[automerger skipped] Merge "Import translations. DO NOT MERGE" into qt-qpr1-dev am: 6730679c31 -s ours

am skip reason: subject contains skip directive

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

Change-Id: If191c041525ccbccdb56801cde6a74019cc48141
diff --git a/.clang-format b/.clang-format
index fc4eb1b..82e72e7 100644
--- a/.clang-format
+++ b/.clang-format
@@ -1,13 +1,27 @@
+---
+Language: Java
+DisableFormat: true
+SortIncludes: false
+---
+Language: Cpp
 BasedOnStyle: Google
+AlignOperands: false
 AllowShortBlocksOnASingleLine: false
-AllowShortFunctionsOnASingleLine: false
-
-AccessModifierOffset: -2
-ColumnLimit: 100
+AllowShortFunctionsOnASingleLine: Inline
+AlwaysBreakBeforeMultilineStrings: false
 CommentPragmas: NOLINT:.*
-DerivePointerAlignment: false
+ColumnLimit: 100
+AccessModifierOffset: -4
 IndentWidth: 4
-PointerAlignment: Left
 TabWidth: 4
+ContinuationIndentWidth: 8
+ConstructorInitializerIndentWidth: 6
+SpacesBeforeTrailingComments: 2
+IncludeBlocks: Preserve
+DerivePointerAlignment: false
+PointerAlignment: Left
 UseTab: Never
-PenaltyExcessCharacter: 32
+BreakInheritanceList: AfterColon
+BreakConstructorInitializers: AfterColon
+PenaltyBreakBeforeFirstCallParameter: 100000
+---
diff --git a/.gitignore b/.gitignore
index 577e3ca..b61e3aa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@
 *.swp
 __pycache__
 .idea
+/bin/
diff --git a/CPPLINT.cfg b/CPPLINT.cfg
new file mode 100644
index 0000000..6708d34
--- /dev/null
+++ b/CPPLINT.cfg
@@ -0,0 +1,7 @@
+set noparent
+linelength=100
+# Do not enforce including header files in both .h and .cpp.
+filter=-build/include
+# Do not check access modifier indentation.
+# CPPLint enforces +1, but our rule is no indentation.
+filter=-whitespace/indent
diff --git a/EncryptionRunner/Android.bp b/EncryptionRunner/Android.bp
index 7910b73..c82d769 100644
--- a/EncryptionRunner/Android.bp
+++ b/EncryptionRunner/Android.bp
@@ -29,25 +29,3 @@
     installable: true,
 }
 
-android_test {
-    name: "EncryptionRunnerTest",
-    min_sdk_version: "23",
-    srcs: [
-        "test/**/*.java",
-    ],
-    product_variables: {
-        pdk: {
-            enabled: false,
-        },
-    },
-    libs: [
-        "android.test.base",
-        "android.test.runner",
-    ],
-    static_libs: [
-        "androidx.test.rules",
-        "EncryptionRunner",
-        "junit",
-        "truth-prebuilt",
-    ],
-}
diff --git a/EncryptionRunner/AndroidManifest.xml b/EncryptionRunner/AndroidManifest.xml
index 9b76d15..3ebdf42 100644
--- a/EncryptionRunner/AndroidManifest.xml
+++ b/EncryptionRunner/AndroidManifest.xml
@@ -18,5 +18,4 @@
         xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
         package="android.car.encryptionrunner" >
     <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="23" />
-    <application />
 </manifest>
diff --git a/EncryptionRunner/src/android/car/encryptionrunner/DummyEncryptionRunner.java b/EncryptionRunner/src/android/car/encryptionrunner/DummyEncryptionRunner.java
index f38bf65..5b63dbc 100644
--- a/EncryptionRunner/src/android/car/encryptionrunner/DummyEncryptionRunner.java
+++ b/EncryptionRunner/src/android/car/encryptionrunner/DummyEncryptionRunner.java
@@ -31,6 +31,7 @@
 public class DummyEncryptionRunner implements EncryptionRunner {
 
     private static final String KEY = "key";
+    private static final byte[] DUMMY_MESSAGE = "Dummy Message".getBytes();
     @VisibleForTesting
     public static final String INIT = "init";
     @VisibleForTesting
@@ -48,6 +49,9 @@
         int SERVER = 2;
     }
 
+    private boolean mIsReconnect;
+    private boolean mInitReconnectVerification;
+    private Key mCurrentDummyKey;
     @Mode
     private int mMode;
     @HandshakeMessage.HandshakeState
@@ -90,12 +94,16 @@
         if (mState != HandshakeMessage.HandshakeState.IN_PROGRESS) {
             throw new HandshakeException("not waiting for response but got one");
         }
-        switch(mMode) {
+        switch (mMode) {
             case Mode.SERVER:
                 if (!CLIENT_RESPONSE.equals(new String(response))) {
                     throw new HandshakeException("unexpected response: " + new String(response));
                 }
                 mState = HandshakeMessage.HandshakeState.VERIFICATION_NEEDED;
+                if (mIsReconnect) {
+                    verifyPin();
+                    mState = HandshakeMessage.HandshakeState.RESUMING_SESSION;
+                }
                 return HandshakeMessage.newBuilder()
                         .setVerificationCode(VERIFICATION_CODE)
                         .setHandshakeState(mState)
@@ -105,17 +113,44 @@
                     throw new HandshakeException("unexpected response: " + new String(response));
                 }
                 mState = HandshakeMessage.HandshakeState.VERIFICATION_NEEDED;
+                if (mIsReconnect) {
+                    verifyPin();
+                    mState = HandshakeMessage.HandshakeState.RESUMING_SESSION;
+                }
                 return HandshakeMessage.newBuilder()
                         .setHandshakeState(mState)
                         .setNextMessage(CLIENT_RESPONSE.getBytes())
                         .setVerificationCode(VERIFICATION_CODE)
                         .build();
             default:
-                throw new IllegalStateException("unexpected state: "  + mState);
+                throw new IllegalStateException("unexpected role: " + mMode);
         }
     }
 
     @Override
+    public HandshakeMessage authenticateReconnection(byte[] message, byte[] previousKey)
+            throws HandshakeException {
+        mCurrentDummyKey = new DummyKey();
+        // Blindly verify the reconnection because this is a dummy encryption runner.
+        return HandshakeMessage.newBuilder()
+                .setHandshakeState(HandshakeMessage.HandshakeState.FINISHED)
+                .setKey(mCurrentDummyKey)
+                .setNextMessage(mInitReconnectVerification ? null : DUMMY_MESSAGE)
+                .build();
+    }
+
+    @Override
+    public HandshakeMessage initReconnectAuthentication(byte[] previousKey)
+            throws HandshakeException {
+        mInitReconnectVerification = true;
+        mState = HandshakeMessage.HandshakeState.RESUMING_SESSION;
+        return HandshakeMessage.newBuilder()
+                .setHandshakeState(mState)
+                .setNextMessage(DUMMY_MESSAGE)
+                .build();
+    }
+
+    @Override
     public Key keyOf(byte[] serialized) {
         return new DummyKey();
     }
@@ -126,10 +161,8 @@
             throw new IllegalStateException("asking to verify pin, state = " + mState);
         }
         mState = HandshakeMessage.HandshakeState.FINISHED;
-        return HandshakeMessage.newBuilder()
-                .setHandshakeState(mState)
-                .setKey(new DummyKey())
-                .build();
+        return HandshakeMessage.newBuilder().setKey(new DummyKey()).setHandshakeState(
+                mState).build();
     }
 
     @Override
@@ -137,8 +170,12 @@
         mState = HandshakeMessage.HandshakeState.INVALID;
     }
 
-    private class DummyKey implements Key {
+    @Override
+    public void setIsReconnect(boolean isReconnect) {
+        mIsReconnect = isReconnect;
+    }
 
+    private class DummyKey implements Key {
         @Override
         public byte[] asBytes() {
             return KEY.getBytes();
@@ -153,5 +190,10 @@
         public byte[] decryptData(byte[] encryptedData) {
             return encryptedData;
         }
+
+        @Override
+        public byte[] getUniqueSession() {
+            return KEY.getBytes();
+        }
     }
 }
diff --git a/EncryptionRunner/src/android/car/encryptionrunner/EncryptionRunner.java b/EncryptionRunner/src/android/car/encryptionrunner/EncryptionRunner.java
index ad444bc..f0a34b2 100644
--- a/EncryptionRunner/src/android/car/encryptionrunner/EncryptionRunner.java
+++ b/EncryptionRunner/src/android/car/encryptionrunner/EncryptionRunner.java
@@ -23,39 +23,63 @@
  * messages.
  *
  * To use this interface:
- * 1. As a client.
  *
- *  HandshakeMessage initialClientMessage = clientRunner.initHandshake();
- *  sendToServer(initialClientMessage.getNextMessage());
- *  byte message = getServerResponse();
+ * <p>1. As a client.
  *
- *  HandshakeMessage message = clientRunner.continueHandshake(message);
- *  message.getHandshakeState() should be VERIFICATION_NEEDED,
- *  otherwise if IN_PROGRESS just send the result of getNextMessage();
+ * {@code
+ * HandshakeMessage initialClientMessage = clientRunner.initHandshake();
+ * sendToServer(initialClientMessage.getNextMessage());
+ * byte message = getServerResponse();
+ * HandshakeMessage message = clientRunner.continueHandshake(message);
+ * }
  *
- *  Show user the verification code and ask to verify.
- *  message.getVerificationCode()
+ * <p>If it is a first-time connection,
  *
- *  if user agrees
- *  HandshakeMessage lastMessage = clientRunner.verifyPin();
- *  otherwise
- *  clientRunner.invalidPin();
+ * {@code message.getHandshakeState()} should be VERIFICATION_NEEDED, show user the verification
+ * code and ask to verify.
+ * After user confirmed, {@code HandshakeMessage lastMessage = clientRunner.verifyPin();} otherwise
+ * {@code clientRunner.invalidPin(); }
  *
- *  Use lastMessage.getKey() for encryption.
+ * Use {@code lastMessage.getKey()} to get the key for encryption.
  *
- * 2. As a server.
+ * <p>If it is a reconnection,
  *
- *  byte[] initialMessage = getClientMessageBytes();
- *  HandshakeMesssage message = serverRunner.respondToInitRequest(initialMessage);
+ * {@code message.getHandshakeState()} should be RESUMING_SESSION, PIN has been verified blindly,
+ * send the authentication message over to server, then authenticate the message from server.
  *
- *  sendToClient(message.getNextMessage());
+ * {@code
+ * clientMessage = clientRunner.initReconnectAuthentication(previousKey)
+ * sendToServer(clientMessage.getNextMessage());
+ * HandshakeMessage lastMessage = clientRunner.authenticateReconnection(previousKey, message)
+ * }
  *
- *  message.getHandshakeState() should be VERIFICATION_NEEDED,
- *  if so show user code and ask to verify
- *  message.getVerificationCode();
+ * {@code lastMessage.getHandshakeState()} should be FINISHED if reconnection handshake is done.
  *
- *  serverRunner.verifyPin or invalidPin and continue same as client above.
+ * <p>2. As a server.
  *
+ * {@code
+ * byte[] initialMessage = getClientMessageBytes();
+ * HandshakeMessage message = serverRunner.respondToInitRequest(initialMessage);
+ * sendToClient(message.getNextMessage());
+ * byte[] clientMessage = getClientResponse();
+ * HandshakeMessage message = serverRunner.continueHandshake(clientMessage);}
+ *
+ * <p>if it is a first-time connection,
+ *
+ * {@code message.getHandshakeState()} should be VERIFICATION_NEEDED, show user the verification
+ * code and ask to verify.
+ * After PIN is confirmed, {@code HandshakeMessage lastMessage = serverRunner.verifyPin}, otherwise
+ * {@code clientRunner.invalidPin(); }
+ * Use {@code lastMessage.getKey()} to get the key for encryption.
+ *
+ * <p>If it is a reconnection,
+ *
+ * {@code message.getHandshakeState()} should be RESUMING_SESSION,PIN has been verified blindly,
+ * waiting for client message.
+ * After client message been received,
+ * {@code serverMessage = serverRunner.authenticateReconnection(previousKey, message);
+ * sendToClient(serverMessage.getNextMessage());}
+ * {@code serverMessage.getHandshakeState()} should be FINISHED if reconnection handshake is done.
  *
  * Also see {@link EncryptionRunnerTest} for examples.
  */
@@ -68,6 +92,7 @@
      *
      * @return A handshake message with information about the handshake that is started.
      */
+    @NonNull
     HandshakeMessage initHandshake();
 
     /**
@@ -76,9 +101,9 @@
      *
      * @param initializationRequest the bytes that the other device sent over.
      * @return a handshake message with information about the handshake.
-     *
      * @throws HandshakeException if initialization request is invalid.
      */
+    @NonNull
     HandshakeMessage respondToInitRequest(@NonNull byte[] initializationRequest)
             throws HandshakeException;
 
@@ -87,9 +112,9 @@
      *
      * @param response the response from the other device.
      * @return a message that can be used to continue the handshake.
-     *
      * @throws HandshakeException if unexpected bytes in response.
      */
+    @NonNull
     HandshakeMessage continueHandshake(@NonNull byte[] response) throws HandshakeException;
 
     /**
@@ -98,6 +123,7 @@
      *
      * @throws HandshakeException if not in state to verify pin.
      */
+    @NonNull
     HandshakeMessage verifyPin() throws HandshakeException;
 
     /**
@@ -107,11 +133,49 @@
     void invalidPin();
 
     /**
+     * Verifies the reconnection message.
+     *
+     * <p>The message passed to this method should have been generated by
+     * {@link #initReconnectAuthentication(byte[] previousKey)}.
+     *
+     * <p>If the message is valid, then a {@link HandshakeMessage} will be returned that contains
+     * the encryption key and a handshake message which can be used to verify the other side of the
+     * connection.
+     *
+     * @param previousKey previously stored key.
+     * @param message     message from the client
+     * @return a handshake message with an encryption key if verification succeed.
+     * @throws HandshakeException if the message does not match.
+     */
+    @NonNull
+    HandshakeMessage authenticateReconnection(@NonNull byte[] message, @NonNull byte[] previousKey)
+            throws HandshakeException;
+
+    /**
+     * Initiates the reconnection verification by generating a message that should be sent to the
+     * device that is being reconnected to.
+     *
+     * @param previousKey previously stored key.
+     * @return a handshake message with client's message which will be sent to server.
+     * @throws HandshakeException when get encryption key's unique session fail.
+     */
+    @NonNull
+    HandshakeMessage initReconnectAuthentication(@NonNull byte[] previousKey)
+            throws HandshakeException;
+
+    /**
      * De-serializes a previously serialized key generated by an instance of this encryption runner.
      *
      * @param serialized the serialized bytes of the key.
      * @return the Key object used for encryption.
      */
+    @NonNull
     Key keyOf(@NonNull byte[] serialized);
 
+    /**
+     * Set the signal if it is a reconnection process.
+     *
+     * @param isReconnect {@code true} if it is a reconnect.
+     */
+    void setIsReconnect(boolean isReconnect);
 }
diff --git a/EncryptionRunner/src/android/car/encryptionrunner/EncryptionRunnerFactory.java b/EncryptionRunner/src/android/car/encryptionrunner/EncryptionRunnerFactory.java
index 156abd8..5b81c87 100644
--- a/EncryptionRunner/src/android/car/encryptionrunner/EncryptionRunnerFactory.java
+++ b/EncryptionRunner/src/android/car/encryptionrunner/EncryptionRunnerFactory.java
@@ -16,6 +16,8 @@
 
 package android.car.encryptionrunner;
 
+import android.annotation.IntDef;
+
 import com.android.internal.annotations.VisibleForTesting;
 
 /**
@@ -27,11 +29,36 @@
         // prevent instantiation.
     }
 
+    @IntDef({EncryptionRunnerType.UKEY2, EncryptionRunnerType.OOB_UKEY2})
+    public @interface EncryptionRunnerType {
+        /** Use Ukey2 as underlying key exchange. */
+        int UKEY2 = 0;
+        /** Use Ukey2 and an out of band channel as underlying key exchange. */
+        int OOB_UKEY2 = 1;
+    }
+
+    /**
+     * Creates a new {@link EncryptionRunner} based on {@param type}.
+     */
+    public static EncryptionRunner newRunner(@EncryptionRunnerType int type) {
+        switch (type) {
+            case EncryptionRunnerType.UKEY2:
+                return new Ukey2EncryptionRunner();
+            case EncryptionRunnerType.OOB_UKEY2:
+                return new OobUkey2EncryptionRunner();
+            default:
+                throw new IllegalArgumentException("Unknown EncryptionRunnerType: " + type);
+        }
+    }
+
     /**
      * Creates a new {@link EncryptionRunner}.
+     *
+     * @deprecated Use {@link #newRunner(int)} instead.
      */
+    @Deprecated
     public static EncryptionRunner newRunner() {
-        return new Ukey2EncryptionRunner();
+        return newRunner(EncryptionRunnerType.UKEY2);
     }
 
     /**
diff --git a/EncryptionRunner/src/android/car/encryptionrunner/HandshakeMessage.java b/EncryptionRunner/src/android/car/encryptionrunner/HandshakeMessage.java
index 347c9fa..e88d482 100644
--- a/EncryptionRunner/src/android/car/encryptionrunner/HandshakeMessage.java
+++ b/EncryptionRunner/src/android/car/encryptionrunner/HandshakeMessage.java
@@ -17,6 +17,7 @@
 package android.car.encryptionrunner;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.text.TextUtils;
 
@@ -33,12 +34,9 @@
      * States for handshake progress.
      */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({
-            HandshakeState.UNKNOWN,
-            HandshakeState.IN_PROGRESS,
-            HandshakeState.VERIFICATION_NEEDED,
-            HandshakeState.FINISHED,
-            HandshakeState.INVALID})
+    @IntDef({HandshakeState.UNKNOWN, HandshakeState.IN_PROGRESS, HandshakeState.VERIFICATION_NEEDED,
+            HandshakeState.FINISHED, HandshakeState.INVALID, HandshakeState.RESUMING_SESSION,
+            HandshakeState.OOB_VERIFICATION_NEEDED})
     public @interface HandshakeState {
         /**
          * The initial state, this value is not expected to be returned.
@@ -60,12 +58,22 @@
          * The handshake is complete and not successful.
          */
         int INVALID = 4;
+        /**
+         * The handshake is complete, but extra verification is needed.
+         */
+        int RESUMING_SESSION = 5;
+        /**
+         * The handshake is complete, but out of band verification of the code is needed.
+         */
+        int OOB_VERIFICATION_NEEDED = 6;
     }
 
-    @HandshakeState private final int mHandshakeState;
+    @HandshakeState
+    private final int mHandshakeState;
     private final Key mKey;
     private final byte[] mNextMessage;
     private final String mVerificationCode;
+    private final byte[] mOobVerificationCode;
 
     /**
      * @return Returns a builder for {@link HandshakeMessage}.
@@ -81,11 +89,13 @@
             @HandshakeState int handshakeState,
             @Nullable Key key,
             @Nullable byte[] nextMessage,
-            @Nullable String verificationCode) {
+            @Nullable String verificationCode,
+            @Nullable byte[] oobVerificationCode) {
         mHandshakeState = handshakeState;
         mKey = key;
         mNextMessage = nextMessage;
         mVerificationCode = verificationCode;
+        mOobVerificationCode = oobVerificationCode;
     }
 
     /**
@@ -120,11 +130,22 @@
         return mVerificationCode;
     }
 
+    /**
+     * Returns a verification code to be encrypted using an out-of-band key and sent to the remote
+     * device.
+     */
+    @Nullable
+    public byte[] getOobVerificationCode() {
+        return mOobVerificationCode;
+    }
+
     static class Builder {
-        @HandshakeState int mHandshakeState;
+        @HandshakeState
+        int mHandshakeState;
         Key mKey;
         byte[] mNextMessage;
         String mVerificationCode;
+        byte[] mOobVerificationCode;
 
         Builder setHandshakeState(@HandshakeState int handshakeState) {
             mHandshakeState = handshakeState;
@@ -146,6 +167,11 @@
             return this;
         }
 
+        Builder setOobVerificationCode(@NonNull byte[] oobVerificationCode) {
+            mOobVerificationCode = oobVerificationCode;
+            return this;
+        }
+
         HandshakeMessage build() {
             if (mHandshakeState == HandshakeState.UNKNOWN) {
                 throw new IllegalStateException("must set handshake state before calling build");
@@ -153,9 +179,15 @@
             if (mHandshakeState == HandshakeState.VERIFICATION_NEEDED
                     && TextUtils.isEmpty(mVerificationCode)) {
                 throw new IllegalStateException(
-                        "if state is verification needed, must have verification code");
+                        "State is verification needed, but verification code null.");
             }
-            return new HandshakeMessage(mHandshakeState, mKey, mNextMessage, mVerificationCode);
+            if (mHandshakeState == HandshakeState.OOB_VERIFICATION_NEEDED
+                    && (mOobVerificationCode == null || mOobVerificationCode.length == 0)) {
+                throw new IllegalStateException(
+                        "State is OOB verification needed, but OOB verification code null.");
+            }
+            return new HandshakeMessage(mHandshakeState, mKey, mNextMessage, mVerificationCode,
+                    mOobVerificationCode);
         }
 
     }
diff --git a/EncryptionRunner/src/android/car/encryptionrunner/Key.java b/EncryptionRunner/src/android/car/encryptionrunner/Key.java
index ce35e98..2e32858 100644
--- a/EncryptionRunner/src/android/car/encryptionrunner/Key.java
+++ b/EncryptionRunner/src/android/car/encryptionrunner/Key.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 
+import java.security.NoSuchAlgorithmException;
 import java.security.SignatureException;
 
 /**
@@ -27,7 +28,8 @@
     /**
      * Returns a serialized encryption key.
      */
-    @NonNull byte[] asBytes();
+    @NonNull
+    byte[] asBytes();
 
     /**
      * Encrypts data using this key.
@@ -35,6 +37,7 @@
      * @param data the data to be encrypted
      * @return the encrypted data.
      */
+    @NonNull
     byte[] encryptData(@NonNull byte[] data);
 
     /**
@@ -42,8 +45,16 @@
      *
      * @param encryptedData The encrypted data.
      * @return decrypted data.
-     *
      * @throws SignatureException if encrypted data is not properly signed.
      */
+    @NonNull
     byte[] decryptData(@NonNull byte[] encryptedData) throws SignatureException;
+
+    /**
+     * Returns a cryptographic digest of the key.
+     *
+     * @throws NoSuchAlgorithmException when a unique session can not be created.
+     */
+    @NonNull
+    byte[] getUniqueSession() throws NoSuchAlgorithmException;
 }
diff --git a/EncryptionRunner/src/android/car/encryptionrunner/OobUkey2EncryptionRunner.java b/EncryptionRunner/src/android/car/encryptionrunner/OobUkey2EncryptionRunner.java
new file mode 100644
index 0000000..9474bd4
--- /dev/null
+++ b/EncryptionRunner/src/android/car/encryptionrunner/OobUkey2EncryptionRunner.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.encryptionrunner;
+
+import com.google.security.cryptauth.lib.securegcm.Ukey2Handshake;
+
+/**
+ * An {@link EncryptionRunner} that uses Ukey2 as the underlying implementation, and generates a
+ * longer token for the out of band verification step.
+ *
+ * <p>To use this class:
+ *
+ * <p>1. As a client.
+ *
+ * <p>{@code
+ * HandshakeMessage initialClientMessage = clientRunner.initHandshake();
+ * sendToServer(initialClientMessage.getNextMessage());
+ * byte message = getServerResponse();
+ * HandshakeMessage message = clientRunner.continueHandshake(message);
+ * }
+ *
+ * <p>If it is a first-time connection,
+ *
+ * <p>{@code message.getHandshakeState()} should be OOB_VERIFICATION_NEEDED. Wait for an encrypted
+ * message sent from the server, and decrypt that message with an out of band key that was generated
+ * before the start of the handshake.
+ *
+ * <p>After confirming that the decrypted message matches the verification code, send an encrypted
+ * message back to the server, and call {@code HandshakeMessage lastMessage =
+ * clientRunner.verifyPin();} otherwise {@code clientRunner.invalidPin(); }
+ *
+ * <p>Use {@code lastMessage.getKey()} to get the key for encryption.
+ *
+ * <p>If it is a reconnection,
+ *
+ * <p>{@code message.getHandshakeState()} should be RESUMING_SESSION, PIN has been verified blindly,
+ * send the authentication message over to server, then authenticate the message from server.
+ *
+ * <p>{@code
+ * clientMessage = clientRunner.initReconnectAuthentication(previousKey)
+ * sendToServer(clientMessage.getNextMessage());
+ * HandshakeMessage lastMessage = clientRunner.authenticateReconnection(previousKey, message)
+ * }
+ *
+ * <p>{@code lastMessage.getHandshakeState()} should be FINISHED if reconnection handshake is done.
+ *
+ * <p>2. As a server.
+ *
+ * <p>{@code
+ * byte[] initialMessage = getClientMessageBytes();
+ * HandshakeMessage message = serverRunner.respondToInitRequest(initialMessage);
+ * sendToClient(message.getNextMessage());
+ * byte[] clientMessage = getClientResponse();
+ * HandshakeMessage message = serverRunner.continueHandshake(clientMessage);}
+ *
+ * <p>if it is a first-time connection,
+ *
+ * <p>{@code message.getHandshakeState()} should be OOB_VERIFICATION_NEEDED, send the verification
+ * code to the client, encrypted using an out of band key generated before the start of the
+ * handshake, and wait for a response from the client.
+ * If the decrypted message from the client matches the verification code, call {@code
+ * HandshakeMessage lastMessage = serverRunner.verifyPin}, otherwise
+ * {@code clientRunner.invalidPin(); }
+ * Use {@code lastMessage.getKey()} to get the key for encryption.
+ *
+ * <p>If it is a reconnection,
+ *
+ * <p>{@code message.getHandshakeState()} should be RESUMING_SESSION,PIN has been verified blindly,
+ * waiting for client message.
+ * After client message been received,
+ * {@code serverMessage = serverRunner.authenticateReconnection(previousKey, message);
+ * sendToClient(serverMessage.getNextMessage());}
+ * {@code serverMessage.getHandshakeState()} should be FINISHED if reconnection handshake is done.
+ *
+ * <p>Also see {@link EncryptionRunnerTest} for examples.
+ */
+public final class OobUkey2EncryptionRunner extends Ukey2EncryptionRunner {
+    // Choose max verification string length supported by Ukey2
+    private static final int VERIFICATION_STRING_LENGTH = 32;
+
+    @Override
+    public HandshakeMessage continueHandshake(byte[] response) throws HandshakeException {
+        checkInitialized();
+
+        Ukey2Handshake uKey2Client = getUkey2Client();
+
+        try {
+            if (uKey2Client.getHandshakeState() != Ukey2Handshake.State.IN_PROGRESS) {
+                throw new IllegalStateException(
+                        "handshake is not in progress, state =" + uKey2Client.getHandshakeState());
+            }
+            uKey2Client.parseHandshakeMessage(response);
+
+            // Not obvious from ukey2 api, but getting the next message can change the state.
+            // calling getNext message might go from in progress to verification needed, on
+            // the assumption that we already send this message to the peer.
+            byte[] nextMessage = null;
+            if (uKey2Client.getHandshakeState() == Ukey2Handshake.State.IN_PROGRESS) {
+                nextMessage = uKey2Client.getNextHandshakeMessage();
+            }
+
+            byte[] verificationCode = null;
+            if (uKey2Client.getHandshakeState() == Ukey2Handshake.State.VERIFICATION_NEEDED) {
+                // getVerificationString() needs to be called before notifyPinVerified().
+                verificationCode = uKey2Client.getVerificationString(VERIFICATION_STRING_LENGTH);
+                if (isReconnect()) {
+                    HandshakeMessage handshakeMessage = verifyPin();
+                    return HandshakeMessage.newBuilder()
+                            .setHandshakeState(handshakeMessage.getHandshakeState())
+                            .setNextMessage(nextMessage)
+                            .build();
+                }
+            }
+
+            return HandshakeMessage.newBuilder()
+                    .setHandshakeState(HandshakeMessage.HandshakeState.OOB_VERIFICATION_NEEDED)
+                    .setNextMessage(nextMessage)
+                    .setOobVerificationCode(verificationCode)
+                    .build();
+        } catch (com.google.security.cryptauth.lib.securegcm.HandshakeException
+                | Ukey2Handshake.AlertException e) {
+            throw new HandshakeException(e);
+        }
+    }
+}
diff --git a/EncryptionRunner/src/android/car/encryptionrunner/Ukey2EncryptionRunner.java b/EncryptionRunner/src/android/car/encryptionrunner/Ukey2EncryptionRunner.java
index eed7852..454a48b 100644
--- a/EncryptionRunner/src/android/car/encryptionrunner/Ukey2EncryptionRunner.java
+++ b/EncryptionRunner/src/android/car/encryptionrunner/Ukey2EncryptionRunner.java
@@ -16,16 +16,26 @@
 
 package android.car.encryptionrunner;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 
 import com.google.security.cryptauth.lib.securegcm.D2DConnectionContext;
 import com.google.security.cryptauth.lib.securegcm.Ukey2Handshake;
+import com.google.security.cryptauth.lib.securemessage.CryptoOps;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.security.SignatureException;
 
+import javax.crypto.spec.SecretKeySpec;
+
 /**
  * An {@link EncryptionRunner} that uses Ukey2 as the underlying implementation.
  */
@@ -33,15 +43,33 @@
 
     private static final Ukey2Handshake.HandshakeCipher CIPHER =
             Ukey2Handshake.HandshakeCipher.P256_SHA512;
-
+    private static final int RESUME_HMAC_LENGTH = 32;
+    private static final byte[] RESUME = "RESUME".getBytes();
+    private static final byte[] SERVER = "SERVER".getBytes();
+    private static final byte[] CLIENT = "CLIENT".getBytes();
     private static final int AUTH_STRING_LENGTH = 6;
 
+    @IntDef({Mode.UNKNOWN, Mode.CLIENT, Mode.SERVER})
+    private @interface Mode {
+        int UNKNOWN = 0;
+        int CLIENT = 1;
+        int SERVER = 2;
+    }
+
     private Ukey2Handshake mUkey2client;
     private boolean mRunnerIsInvalid;
+    private Key mCurrentKey;
+    private byte[] mCurrentUniqueSesion;
+    private byte[] mPrevUniqueSesion;
+    private boolean mIsReconnect;
+    private boolean mInitReconnectionVerification;
+    @Mode
+    private int mMode = Mode.UNKNOWN;
 
     @Override
     public HandshakeMessage initHandshake() {
         checkRunnerIsNew();
+        mMode = Mode.CLIENT;
         try {
             mUkey2client = Ukey2Handshake.forInitiator(CIPHER);
             return HandshakeMessage.newBuilder()
@@ -56,9 +84,15 @@
     }
 
     @Override
+    public void setIsReconnect(boolean isReconnect) {
+        mIsReconnect = isReconnect;
+    }
+
+    @Override
     public HandshakeMessage respondToInitRequest(byte[] initializationRequest)
             throws HandshakeException {
         checkRunnerIsNew();
+        mMode = Mode.SERVER;
         try {
             if (mUkey2client != null) {
                 throw new IllegalStateException("Cannot reuse encryption runners, "
@@ -101,11 +135,18 @@
             if (mUkey2client.getHandshakeState() == Ukey2Handshake.State.IN_PROGRESS) {
                 nextMessage = mUkey2client.getNextHandshakeMessage();
             }
-
             String verificationCode = null;
             if (mUkey2client.getHandshakeState() == Ukey2Handshake.State.VERIFICATION_NEEDED) {
+                // getVerificationString() needs to be called before verifyPin().
                 verificationCode = generateReadablePairingCode(
                         mUkey2client.getVerificationString(AUTH_STRING_LENGTH));
+                if (mIsReconnect) {
+                    HandshakeMessage handshakeMessage = verifyPin();
+                    return HandshakeMessage.newBuilder()
+                            .setHandshakeState(handshakeMessage.getHandshakeState())
+                            .setNextMessage(nextMessage)
+                            .build();
+                }
             }
             return HandshakeMessage.newBuilder()
                     .setHandshakeState(getHandshakeState())
@@ -158,20 +199,136 @@
         public byte[] decryptData(byte[] encryptedData) throws SignatureException {
             return mConnectionContext.decodeMessageFromPeer(encryptedData);
         }
+
+        @Override
+        public byte[] getUniqueSession() throws NoSuchAlgorithmException {
+            return mConnectionContext.getSessionUnique();
+        }
     }
 
     @Override
     public HandshakeMessage verifyPin() throws HandshakeException {
         checkInitialized();
         mUkey2client.verifyHandshake();
+        int state = getHandshakeState();
         try {
-            return HandshakeMessage.newBuilder()
-                    .setHandshakeState(getHandshakeState())
-                    .setKey(new UKey2Key(mUkey2client.toConnectionContext()))
-                    .build();
+            mCurrentKey = new UKey2Key(mUkey2client.toConnectionContext());
         } catch (com.google.security.cryptauth.lib.securegcm.HandshakeException e) {
             throw new HandshakeException(e);
         }
+        return HandshakeMessage.newBuilder()
+                .setHandshakeState(state)
+                .setKey(mCurrentKey)
+                .build();
+    }
+
+    /**
+     * <p>After getting message from the other device, authenticate the message with the previous
+     * stored key.
+     *
+     * If current device inits the reconnection authentication by calling {@code
+     * initReconnectAuthentication} and sends the message to the other device, the other device
+     * will call {@code authenticateReconnection()} with the received message and send its own
+     * message back to the init device. The init device will call {@code
+     * authenticateReconnection()} on the received message, but do not need to set the next
+     * message.
+     */
+    @Override
+    public HandshakeMessage authenticateReconnection(byte[] message, byte[] previousKey)
+            throws HandshakeException {
+        if (!mIsReconnect) {
+            throw new HandshakeException(
+                    "Reconnection authentication requires setIsReconnect(true)");
+        }
+        if (mCurrentKey == null) {
+            throw new HandshakeException("Current key is null, make sure verifyPin() is called.");
+        }
+        if (message.length != RESUME_HMAC_LENGTH) {
+            mRunnerIsInvalid = true;
+            throw new HandshakeException("Failing because (message.length =" + message.length
+                    + ") is not equal to " + RESUME_HMAC_LENGTH);
+        }
+        try {
+            mCurrentUniqueSesion = mCurrentKey.getUniqueSession();
+            mPrevUniqueSesion = keyOf(previousKey).getUniqueSession();
+        } catch (NoSuchAlgorithmException e) {
+            throw new HandshakeException(e);
+        }
+        switch (mMode) {
+            case Mode.SERVER:
+                if (!MessageDigest.isEqual(
+                        message, computeMAC(mPrevUniqueSesion, mCurrentUniqueSesion, CLIENT))) {
+                    mRunnerIsInvalid = true;
+                    throw new HandshakeException("Reconnection authentication failed.");
+                }
+                return HandshakeMessage.newBuilder()
+                        .setHandshakeState(HandshakeMessage.HandshakeState.FINISHED)
+                        .setKey(mCurrentKey)
+                        .setNextMessage(mInitReconnectionVerification ? null
+                                : computeMAC(mPrevUniqueSesion, mCurrentUniqueSesion, SERVER))
+                        .build();
+            case Mode.CLIENT:
+                if (!MessageDigest.isEqual(
+                        message, computeMAC(mPrevUniqueSesion, mCurrentUniqueSesion, SERVER))) {
+                    mRunnerIsInvalid = true;
+                    throw new HandshakeException("Reconnection authentication failed.");
+                }
+                return HandshakeMessage.newBuilder()
+                        .setHandshakeState(HandshakeMessage.HandshakeState.FINISHED)
+                        .setKey(mCurrentKey)
+                        .setNextMessage(mInitReconnectionVerification ? null
+                                : computeMAC(mPrevUniqueSesion, mCurrentUniqueSesion, CLIENT))
+                        .build();
+            default:
+                throw new IllegalStateException(
+                        "Encountered unexpected role during authenticateReconnection: " + mMode);
+        }
+    }
+
+    /**
+     * Both client and server can call this method to send authentication message to the other
+     * device.
+     */
+    @Override
+    public HandshakeMessage initReconnectAuthentication(byte[] previousKey)
+            throws HandshakeException {
+        if (!mIsReconnect) {
+            throw new HandshakeException(
+                    "Reconnection authentication requires setIsReconnect(true).");
+        }
+        if (mCurrentKey == null) {
+            throw new HandshakeException("Current key is null, make sure verifyPin() is called.");
+        }
+        mInitReconnectionVerification = true;
+        try {
+            mCurrentUniqueSesion = mCurrentKey.getUniqueSession();
+            mPrevUniqueSesion = keyOf(previousKey).getUniqueSession();
+        } catch (NoSuchAlgorithmException e) {
+            throw new HandshakeException(e);
+        }
+        switch (mMode) {
+            case Mode.SERVER:
+                return HandshakeMessage.newBuilder()
+                        .setHandshakeState(HandshakeMessage.HandshakeState.RESUMING_SESSION)
+                        .setNextMessage(computeMAC(mPrevUniqueSesion, mCurrentUniqueSesion, SERVER))
+                        .build();
+            case Mode.CLIENT:
+                return HandshakeMessage.newBuilder()
+                        .setHandshakeState(HandshakeMessage.HandshakeState.RESUMING_SESSION)
+                        .setNextMessage(computeMAC(mPrevUniqueSesion, mCurrentUniqueSesion, CLIENT))
+                        .build();
+            default:
+                throw new IllegalStateException(
+                        "Encountered unexpected role during authenticateReconnection: " + mMode);
+        }
+    }
+
+    protected final Ukey2Handshake getUkey2Client() {
+        return mUkey2client;
+    }
+
+    protected final boolean isReconnect() {
+        return mIsReconnect;
     }
 
     @HandshakeMessage.HandshakeState
@@ -182,6 +339,9 @@
             case ERROR:
                 throw new IllegalStateException("unexpected error state");
             case FINISHED:
+                if (mIsReconnect) {
+                    return HandshakeMessage.HandshakeState.RESUMING_SESSION;
+                }
                 return HandshakeMessage.HandshakeState.FINISHED;
             case IN_PROGRESS:
                 return HandshakeMessage.HandshakeState.IN_PROGRESS;
@@ -210,7 +370,7 @@
         return (UKey2Key) key;
     }
 
-    private void checkInitialized() {
+    protected void checkInitialized() {
         if (mUkey2client == null) {
             throw new IllegalStateException("runner not initialized");
         }
@@ -218,4 +378,28 @@
             throw new IllegalStateException("runner has been invalidated");
         }
     }
+
+    @Nullable
+    private byte[] computeMAC(byte[] previous, byte[] next, byte[] info) {
+        try {
+            SecretKeySpec inputKeyMaterial = new SecretKeySpec(
+                    concatByteArrays(previous, next), "" /* key type is just plain raw bytes */);
+            return CryptoOps.hkdf(inputKeyMaterial, RESUME, info);
+        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
+            // Does not happen in practice
+            Log.e(TAG, "Compute MAC failed");
+            return null;
+        }
+    }
+
+    private static byte[] concatByteArrays(@NonNull byte[] a, @NonNull byte[] b) {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        try {
+            outputStream.write(a);
+            outputStream.write(b);
+        } catch (IOException e) {
+            return new byte[0];
+        }
+        return outputStream.toByteArray();
+    }
 }
diff --git a/EncryptionRunner/test/android/car/encryptionrunner/EncryptionRunnerTest.java b/EncryptionRunner/test/android/car/encryptionrunner/EncryptionRunnerTest.java
deleted file mode 100644
index c7893ad..0000000
--- a/EncryptionRunner/test/android/car/encryptionrunner/EncryptionRunnerTest.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.car.encryptionrunner;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.util.Log;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import junit.framework.Assert;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class EncryptionRunnerTest {
-
-    private static final byte[] sTestData = "test data".getBytes();
-    private interface RunnerFactory {
-        EncryptionRunner newRunner();
-    }
-
-    @Test
-    public void happyFlow_dummyRunner() throws Exception {
-        verifyRunners(EncryptionRunnerFactory::newDummyRunner);
-    }
-
-    @Test
-    public void happyFlow_ukey2Runner() throws Exception {
-        verifyRunners(EncryptionRunnerFactory::newRunner);
-    }
-
-    /**
-     * Runs through a happy flow of encryption runners and verifies that they behave as expected.
-     * Some * of the test is implementation specific because the interface doesn't specify how many
-     * round * trips may be needed but this test makes assumptions( i.e. white box testing).
-     */
-    private void verifyRunners(RunnerFactory runnerFactory) throws Exception {
-        EncryptionRunner clientRunner = runnerFactory.newRunner();
-        EncryptionRunner serverRunner = runnerFactory.newRunner();
-
-        verifyHandshake(clientRunner, serverRunner);
-
-        HandshakeMessage finalServerMessage = serverRunner.verifyPin();
-        assertThat(finalServerMessage.getHandshakeState())
-                .isEqualTo(HandshakeMessage.HandshakeState.FINISHED);
-        assertThat(finalServerMessage.getKey()).isNotNull();
-        assertThat(finalServerMessage.getNextMessage()).isNull();
-
-        HandshakeMessage finalClientMessage = clientRunner.verifyPin();
-        assertThat(finalClientMessage.getHandshakeState())
-                .isEqualTo(HandshakeMessage.HandshakeState.FINISHED);
-        assertThat(finalClientMessage.getKey()).isNotNull();
-        assertThat(finalClientMessage.getNextMessage()).isNull();
-
-        assertThat(finalServerMessage.getKey()
-                .decryptData(finalClientMessage.getKey().encryptData(sTestData)))
-                .isEqualTo(sTestData);
-        assertThat(finalClientMessage.getKey()
-                .decryptData(finalServerMessage.getKey().encryptData(sTestData)))
-                .isEqualTo(sTestData);
-    }
-
-    private void verifyHandshake(EncryptionRunner clientRunner, EncryptionRunner serverRunner)
-            throws Exception {
-        HandshakeMessage initialClientMessage = clientRunner.initHandshake();
-
-        assertThat(initialClientMessage.getHandshakeState())
-                .isEqualTo(HandshakeMessage.HandshakeState.IN_PROGRESS);
-        assertThat(initialClientMessage.getKey()).isNull();
-        assertThat(initialClientMessage.getNextMessage()).isNotNull();
-
-        // This and the following similar log statements are useful when running this test to
-        // find the payload sizes.
-        Log.i(EncryptionRunner.TAG,
-                "initial client size:" + initialClientMessage.getNextMessage().length);
-
-        HandshakeMessage initialServerMessage =
-                serverRunner.respondToInitRequest(initialClientMessage.getNextMessage());
-
-        assertThat(initialServerMessage.getHandshakeState())
-                .isEqualTo(HandshakeMessage.HandshakeState.IN_PROGRESS);
-        assertThat(initialServerMessage.getKey()).isNull();
-        assertThat(initialServerMessage.getNextMessage()).isNotNull();
-
-        Log.i(EncryptionRunner.TAG,
-                "initial server message size:" + initialServerMessage.getNextMessage().length);
-
-        HandshakeMessage clientMessage =
-                clientRunner.continueHandshake(initialServerMessage.getNextMessage());
-
-        assertThat(clientMessage.getHandshakeState())
-                .isEqualTo(HandshakeMessage.HandshakeState.VERIFICATION_NEEDED);
-        assertThat(clientMessage.getKey()).isNull();
-        assertThat(clientMessage.getVerificationCode()).isNotEmpty();
-        assertThat(clientMessage.getNextMessage()).isNotNull();
-
-        Log.i(EncryptionRunner.TAG,
-                "second client message size:" + clientMessage.getNextMessage().length);
-
-        HandshakeMessage serverMessage =
-                serverRunner.continueHandshake(clientMessage.getNextMessage());
-        assertThat(serverMessage.getHandshakeState())
-                .isEqualTo(HandshakeMessage.HandshakeState.VERIFICATION_NEEDED);
-        assertThat(serverMessage.getKey()).isNull();
-        assertThat(serverMessage.getNextMessage()).isNull();
-
-        Log.i(EncryptionRunner.TAG,
-                "last server message size:" + clientMessage.getNextMessage().length);
-    }
-
-    @Test
-    public void invalidPin_ukey2() throws Exception {
-        invalidPinTest(EncryptionRunnerFactory::newRunner);
-    }
-
-    @Test
-    public void invalidPin_dummy() throws Exception {
-        invalidPinTest(EncryptionRunnerFactory::newDummyRunner);
-    }
-
-    private void invalidPinTest(RunnerFactory runnerFactory) throws Exception {
-        EncryptionRunner clientRunner = runnerFactory.newRunner();
-        EncryptionRunner serverRunner = runnerFactory.newRunner();
-
-        verifyHandshake(clientRunner, serverRunner);
-        clientRunner.invalidPin();
-        serverRunner.invalidPin();
-
-        try {
-            clientRunner.verifyPin();
-            Assert.fail();
-        } catch (Exception ignored) {
-            // pass
-        }
-
-        try {
-            serverRunner.verifyPin();
-            Assert.fail();
-        } catch (Exception ignored) {
-            // pass
-        }
-    }
-}
diff --git a/EncryptionRunner/test/android/car/encryptionrunner/Ukey2EncryptionRunnerTest.java b/EncryptionRunner/test/android/car/encryptionrunner/Ukey2EncryptionRunnerTest.java
deleted file mode 100644
index 14ca77d..0000000
--- a/EncryptionRunner/test/android/car/encryptionrunner/Ukey2EncryptionRunnerTest.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.car.encryptionrunner;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class Ukey2EncryptionRunnerTest {
-
-    private Ukey2EncryptionRunner mRunner;
-
-    @Before
-    public void setup() {
-        mRunner = new Ukey2EncryptionRunner();
-    }
-
-    @Test
-    public void generateReadablePairingCode_modsBytesAcrossRange() throws Exception {
-        // 194 is an example of a value that would fail if using signed instead of unsigned ints
-        // 194 -> 11000010
-        // 11000010 -> 194 (unsigned 8-bit int)
-        // 11000010 -> -62 (signed 8-bit int)
-        byte[] bytes = new byte[]{0, 7, (byte) 161, (byte) 194, (byte) 196, (byte) 255};
-        String pairingCode = mRunner.generateReadablePairingCode(bytes);
-
-        assertThat(pairingCode).isEqualTo("071465");
-    }
-}
diff --git a/FrameworkPackageStubs/Android.mk b/FrameworkPackageStubs/Android.mk
index c6a68c8..e24a583 100644
--- a/FrameworkPackageStubs/Android.mk
+++ b/FrameworkPackageStubs/Android.mk
@@ -6,6 +6,8 @@
 LOCAL_PACKAGE_NAME := CarFrameworkPackageStubs
 LOCAL_PRIVATE_PLATFORM_APIS := true
 
+LOCAL_CERTIFICATE := platform
+
 LOCAL_MODULE_TAGS := optional
 
 include $(BUILD_PACKAGE)
diff --git a/FrameworkPackageStubs/AndroidManifest.xml b/FrameworkPackageStubs/AndroidManifest.xml
index 912944c..ac674cb 100644
--- a/FrameworkPackageStubs/AndroidManifest.xml
+++ b/FrameworkPackageStubs/AndroidManifest.xml
@@ -95,6 +95,10 @@
                 <action android:name="android.settings.USER_DICTIONARY_SETTINGS" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
+            <intent-filter android:priority="-1">
+                <action android:name="android.settings.PICTURE_IN_PICTURE_SETTINGS" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
         </activity>
 
         <!-- CDD Core Application Intents Stubs -->
@@ -190,5 +194,30 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
+
+        <!-- Contacts package stubs -->
+        <activity
+            android:name=".Stubs$ContactsStub"
+            android:label="@string/stub_name"
+            android:excludeFromRecents="true">
+            <intent-filter android:priority="-1">
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="vnd.android.cursor.dir/contact"/>
+            </intent-filter>
+
+            <intent-filter android:priority="-1">
+                <action android:name="android.intent.action.GET_CONTENT" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="vnd.android.cursor.dir/contact"/>
+            </intent-filter>
+
+            <intent-filter android:priority="-1">
+                <action android:name="android.intent.action.PICK" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="vnd.android.cursor.dir/contact"/>
+            </intent-filter>
+        </activity>
+
     </application>
 </manifest>
diff --git a/OWNERS b/OWNERS
index b59c421..47f451a 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,2 +1,6 @@
 # Each subdirectory should have its OWNERS.
-# Owned by Android Automotive Embedded (go/aae).
+# Owned by Android Automotive Embedded team.
+felipeal@google.com
+gurunagarajan@google.com
+keunyoung@google.com
+sgurun@google.com
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 38f9800..3da2dc9 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -5,3 +5,5 @@
 [Builtin Hooks]
 commit_msg_changeid_field = true
 commit_msg_test_field = true
+cpplint = true
+clang_format = true
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..6239f78
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "auto-postsubmit": [
+    {
+      "name": "AndroidCarApiTest",
+      "options": [
+        {
+          "include-filter": "android.car.apitest.PreInstalledPackagesTest"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/car-bugreportd/OWNERS b/car-bugreportd/OWNERS
new file mode 100644
index 0000000..335fc46
--- /dev/null
+++ b/car-bugreportd/OWNERS
@@ -0,0 +1,2 @@
+sgurun@google.com
+zhomart@google.com
diff --git a/car-bugreportd/README.md b/car-bugreportd/README.md
new file mode 100644
index 0000000..c6fae4c
--- /dev/null
+++ b/car-bugreportd/README.md
@@ -0,0 +1,9 @@
+# car-bugreportd
+
+Android Automotive OS only service. Please use `CarBugreportManager` API.
+
+It takes bugreport, appends car specific files and then proxies them to
+`CarBugreportManagerService`.
+
+To start, set the value of the system property `ctl.start` to `car-bugreportd`,
+e.g. `SystemProperties.set("ctl.start", "car-bugreportd");`
diff --git a/car-bugreportd/car-bugreportd.rc b/car-bugreportd/car-bugreportd.rc
index 0935a60..e994859 100644
--- a/car-bugreportd/car-bugreportd.rc
+++ b/car-bugreportd/car-bugreportd.rc
@@ -10,8 +10,7 @@
 
 # car-dumpstatez generates a zipped bugreport but also uses a socket to print the file location once
 # it is finished.
-service car-dumpstatez /system/bin/dumpstate -S -d -z \
-        -o /data/user_de/0/com.android.shell/files/bugreports/bugreport
+service car-dumpstatez /system/bin/dumpstate -S -d -z
     socket dumpstate stream 0660 shell log
     class main
     disabled
diff --git a/car-internal-lib/Android.bp b/car-internal-lib/Android.bp
new file mode 100644
index 0000000..cb68c66
--- /dev/null
+++ b/car-internal-lib/Android.bp
@@ -0,0 +1,26 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This project contains libraries that are used internally, mostly by
+// CarService and CarServiceHelperService.
+//
+// They're not meant to be used by other system apps and hence are not
+// supported.
+
+java_library {
+    name: "android.car.internal.event-log-tags",
+    srcs: [
+        "src/com/android/internal/car/EventLogTags.logtags",
+    ],
+}
diff --git a/car-internal-lib/src/com/android/internal/car/EventLogTags.logtags b/car-internal-lib/src/com/android/internal/car/EventLogTags.logtags
new file mode 100644
index 0000000..fcca8ae
--- /dev/null
+++ b/car-internal-lib/src/com/android/internal/car/EventLogTags.logtags
@@ -0,0 +1,118 @@
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# See system/core/logcat/event.logtags for a description of the format of this file.
+
+option java_package com.android.internal.car
+
+####
+#### Tags used by CarServiceHelperService
+####
+#### It uses the 150000 - 160000 range
+####
+
+150000 car_helper_start (uses_hal|1)
+150001 car_helper_boot_phase (phase|1)
+150002 car_helper_user_starting (user_id|1)
+150003 car_helper_user_switching (from_user_id|1),(to_user_id|1)
+150004 car_helper_user_unlocking (user_id|1)
+150005 car_helper_user_unlocked (user_id|1)
+150006 car_helper_user_stopping (user_id|1)
+150007 car_helper_user_stopped (user_id|1)
+150008 car_helper_svc_connected (pending_operations|1)
+150009 car_helper_hal_request (request_type|1)
+150010 car_helper_hal_response (result_code|1)
+150011 car_helper_hal_default_behavior (fallback|1),(user_locales|3)
+150012 car_helper_hal_start_user (user_id|1),(user_locales|3)
+150013 car_helper_hal_create_user (flags|1),(safe_name|3),(user_locales|3)
+150014 car_helper_pre_creation_requested (number_users|1),(number_guests|1)
+150015 car_helper_pre_creation_status (number_existing_users|1),(number_users_to_add|1),(number_users_to_remove|1),(number_existing_guests|1),(number_guests_to_add|1),(number_guests_to_remove|1),(number_invalid_users_to_remove|1)
+
+####
+#### Tags used by ICarImpl / CarService
+####
+
+150050 car_service_init (number_services|1)
+150051 car_service_vhal_reconnected (number_services|1)
+150052 car_service_set_car_service_helper (pid|1)
+150053 car_service_on_user_lifecycle (type|1),(from_user_id|1),(to_user_id|1)
+150054 car_service_set_initial_user (user_id|1)
+150055 car_service_create (has_vhal|1)
+150056 car_service_connected (interface|3)
+150057 car_service_destroy (has_vhal|1)
+150058 car_service_vhal_died (cookie|2)
+
+####
+#### Tags used by CarService subsystems, like user and power management.
+####
+#### They must be prefixed by car_xxx_svc, car_xxx_hal, or car_xxx_mgr, each representing the
+#### respective component associated with the subsystem, and each subsystem should allocate a
+#### 100-tags range.
+####
+
+#### User-related tags (range 150100 - 150199)
+
+150100 car_user_svc_initial_user_info_req (request_type|1),(timeout|1)
+150101 car_user_svc_initial_user_info_resp (status|1),(action|1),(user_id|1),(flags|1),(safe_name|3),(user_locales|3)
+150103 car_user_svc_set_initial_user (user_id|1)
+150104 car_user_svc_set_lifecycle_listener (uid|1)
+150105 car_user_svc_reset_lifecycle_listener (uid|1)
+150106 car_user_svc_switch_user_req (user_id|1),(timeout|1)
+150107 car_user_svc_switch_user_resp (status|1),(result|1),(error_message|3)
+150108 car_user_svc_post_switch_user_req (target_user_id|1),(current_user_id|1)
+150109 car_user_svc_get_user_auth_req (uid|1),(user_id|1),(number_types|1)
+150110 car_user_svc_get_user_auth_resp (number_values|1)
+150111 car_user_svc_switch_user_ui_req (user_id|1)
+150112 car_user_svc_switch_user_from_hal_req (request_id|1),(uid|1)
+150113 car_user_svc_set_user_auth_req (uid|1),(user_id|1),(number_associations|1)
+150114 car_user_svc_set_user_auth_resp (number_values|1),(error_message|3)
+150115 car_user_svc_create_user_req (safe_name|3),(user_type|3),(flags|1),(timeout|1)
+150116 car_user_svc_create_user_resp (status|1),(result|1),(error_message|3)
+150117 car_user_svc_create_user_user_created (user_id|1),(safe_name|3),(user_type|3),(flags|1)
+150118 car_user_svc_create_user_user_removed (user_id|1),(reason|3)
+150119 car_user_svc_remove_user_req (user_id|1)
+150120 car_user_svc_remove_user_resp (user_id|1),(result|1)
+150121 car_user_svc_notify_app_lifecycle_listener (uid|1),(event_type|1),(from_user_id|1),(to_user_id|1)
+150122 car_user_svc_notify_internal_lifecycle_listener (listener_name|3),(event_type|1),(from_user_id|1),(to_user_id|1)
+
+150140 car_user_hal_initial_user_info_req (request_id|1),(request_type|1),(timeout|1)
+150141 car_user_hal_initial_user_info_resp (request_id|1),(status|1),(action|1),(user_id|1),(flags|1),(safe_name|3),(user_locales|3)
+150142 car_user_hal_switch_user_req (request_id|1),(user_id|1),(user_flags|1),(timeout|1)
+150143 car_user_hal_switch_user_resp (request_id|1),(status|1),(result|1),(error_message|3)
+150144 car_user_hal_post_switch_user_req (request_id|1),(target_user_id|1),(current_user_id|1)
+150145 car_user_hal_get_user_auth_req (int32values|4)
+150146 car_user_hal_get_user_auth_resp (int32values|4),(error_message|3)
+150147 car_user_hal_legacy_switch_user_req (request_id|1),(target_user_id|1),(current_user_id|1)
+150148 car_user_hal_set_user_auth_req (int32values|4)
+150149 car_user_hal_set_user_auth_resp (int32values|4),(error_message|3)
+150150 car_user_hal_oem_switch_user_req (request_id|1),(target_user_id|1)
+150151 car_user_hal_create_user_req (request_id|1),(safe_name|3),(flags|1),(timeout|1)
+150152 car_user_hal_create_user_resp (request_id|1),(status|1),(result|1),(error_message|3)
+150153 car_user_hal_remove_user_req (target_user_id|1),(current_user_id|1)
+
+150171 car_user_mgr_add_listener (uid|1)
+150172 car_user_mgr_remove_listener (uid|1)
+150173 car_user_mgr_disconnected (uid|1)
+150174 car_user_mgr_switch_user_req (uid|1),(user_id|1)
+150175 car_user_mgr_switch_user_resp (uid|1),(status|1),(error_message|3)
+150176 car_user_mgr_get_user_auth_req (types|4)
+150177 car_user_mgr_get_user_auth_resp (values|4)
+150178 car_user_mgr_set_user_auth_req (types_and_values_pairs|4)
+150179 car_user_mgr_set_user_auth_resp (values|4)
+150180 car_user_mgr_create_user_req (uid|1),(safe_name|3),(user_type|3),(flags|1)
+150181 car_user_mgr_create_user_resp (uid|1),(status|1),(error_message|3)
+150182 car_user_mgr_remove_user_req (uid|1),(user_id|1)
+150183 car_user_mgr_remove_user_resp (uid|1),(status|1)
+150184 car_user_mgr_notify_lifecycle_listener (number_listeners|1),(event_type|1),(from_user_id|1),(to_user_id|1)
diff --git a/car-lib/Android.bp b/car-lib/Android.bp
index b8d4639..39db28e 100644
--- a/car-lib/Android.bp
+++ b/car-lib/Android.bp
@@ -12,8 +12,19 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+filegroup {
+    name: "libcarpowermanager_aidl",
+    srcs: [
+        "src/android/car/ICar.aidl",
+        "src/android/car/hardware/power/ICarPower.aidl",
+        "src/android/car/hardware/power/ICarPowerStateListener.aidl",
+    ],
+    path: "src",
+}
+
 cc_library {
     name: "libcarpowermanager",
+    vendor_available: true,
 
     aidl: {
         export_aidl_headers: true,
@@ -40,9 +51,7 @@
     ],
 
     srcs: [
-        "src/android/car/ICar.aidl",
-        "src/android/car/hardware/power/ICarPower.aidl",
-        "src/android/car/hardware/power/ICarPowerStateListener.aidl",
+        ":libcarpowermanager_aidl",
         "native/CarPowerManager/CarPowerManager.cpp",
     ],
 }
@@ -56,7 +65,7 @@
     srcs: ["src/android/car/navigation/navigation_state.proto"]
 }
 
-// library to access settings from CarSettings
+// library to access settings from CarSettings 
 java_library {
     name: "android.car.settings",
     srcs: ["src/android/car/settings/CarSettings.java"]
@@ -66,18 +75,22 @@
     name: "android.car",
     srcs: [
         "src/**/*.java",
-        "src_feature_future/**/*.java",
         "src/**/I*.aidl",
     ],
     aidl: {
         include_dirs: [
             "system/bt/binder",
+            "packages/services/Car/watchdog/aidl",
         ],
     },
     exclude_srcs: [
         "src/android/car/storagemonitoring/IoStats.aidl",
         "src/android/car/storagemonitoring/IoStatsEntry.aidl",
     ],
+    static_libs: [
+        "android.car.internal.event-log-tags",
+        "carwatchdog_aidl_interface-java",
+    ],
     product_variables: {
         pdk: {
             enabled: false,
@@ -90,7 +103,6 @@
     name: "android.car-docs-default",
     srcs: [
         "src/**/*.java",
-        "src_feature_future/**/*.java",
     ],
     libs: [
         "android.car",
@@ -127,9 +139,7 @@
 droidstubs {
     name: "android.car-stubs-docs",
     defaults: ["android.car-docs-default"],
-    api_tag_name: "ANDROID_CAR",
-    api_filename: "api.txt",
-    removed_api_filename: "removed.txt",
+    removed_dex_api_filename: "removed-dex.txt",
     args: "--hide UnavailableSymbol --no-docs --stub-packages android.car* ",
     installable: false,
     check_api: {
@@ -137,25 +147,27 @@
             api_file: ":android-car-last-released-api",
             removed_api_file: "api/removed.txt",
             args: " -hide 2 -hide 3 -hide 4 -hide 5 -hide 6 -hide 24 -hide 25 -hide 26 -hide 27 " +
-                  " -warning 7 -warning 8 -warning 9 -warning 10 -warning 11 -warning 12 " +
-                  " -warning 13 -warning 14 -warning 15 -warning 16 -warning 17 -warning 18 -hide 113 ",
+                " -warning 7 -warning 8 -warning 9 -warning 10 -warning 11 -warning 12 " +
+                " -warning 13 -warning 14 -warning 15 -warning 16 -warning 17 -warning 18 -hide 113 ",
         },
         current: {
             api_file: "api/current.txt",
             removed_api_file: "api/removed.txt",
             args: " -error 2 -error 3 -error 4 -error 5 -error 6 -error 7 -error 8 -error 9 -error 10 -error 11 " +
-                  " -error 12 -error 13 -error 14 -error 15 -error 16 -error 17 -error 18 -error 19 -error 20 " +
-                  " -error 21 -error 23 -error 24 -error 25 -hide 113 ",
+                " -error 12 -error 13 -error 14 -error 15 -error 16 -error 17 -error 18 -error 19 -error 20 " +
+                " -error 21 -error 23 -error 24 -error 25 -hide 113 ",
         },
+        api_lint: {
+            enabled: true,
+            baseline_file: "api/lint-baseline.txt",
+        }
     },
 }
 
 droidstubs {
     name: "android.car-system-stubs-docs",
     defaults: ["android.car-docs-default"],
-    api_tag_name: "ANDROID_CAR_SYSTEM",
-    api_filename: "api.txt",
-    removed_api_filename: "removed.txt",
+    removed_dex_api_filename: "system-removed-dex.txt",
     args: "--hide UnavailableSymbol --no-docs --stub-packages android.car* " +
         "--show-annotation android.annotation.SystemApi ",
     installable: false,
@@ -164,26 +176,27 @@
             api_file: ":android-car-last-released-system-api",
             removed_api_file: "api/system-removed.txt",
             args: " -hide 2 -hide 3 -hide 4 -hide 5 -hide 6 -hide 24 -hide 25 -hide 26 -hide 27 " +
-                  " -warning 7 -warning 8 -warning 9 -warning 10 -warning 11 -warning 12 " +
-                  " -warning 13 -warning 14 -warning 15 -warning 16 -warning 17 -warning 18 -hide 113 ",
+                " -warning 7 -warning 8 -warning 9 -warning 10 -warning 11 -warning 12 " +
+                " -warning 13 -warning 14 -warning 15 -warning 16 -warning 17 -warning 18 -hide 113 ",
         },
         current: {
             api_file: "api/system-current.txt",
             removed_api_file: "api/system-removed.txt",
             args: " -error 2 -error 3 -error 4 -error 5 -error 6 -error 7 -error 8 -error 9 -error 10 -error 11 " +
-                  " -error 12 -error 13 -error 14 -error 15 -error 16 -error 17 -error 18 -error 19 -error 20 " +
-                  " -error 21 -error 23 -error 24 -error 25 -hide 113 ",
+                " -error 12 -error 13 -error 14 -error 15 -error 16 -error 17 -error 18 -error 19 -error 20 " +
+                " -error 21 -error 23 -error 24 -error 25 -hide 113 ",
         },
+        api_lint: {
+            enabled: true,
+            baseline_file: "api/system-lint-baseline.txt",
+        }
     },
 }
 
 droidstubs {
     name: "android.car-test-stubs-docs",
     defaults: ["android.car-docs-default"],
-    api_tag_name: "ANDROID_CAR_SYSTEM",
-    api_filename: "api.txt",
-    removed_api_filename: "removed.txt",
-    args: "--hide UnavailableSymbol --no-docs --stub-packages android.car* " +
+    args: "--hide HiddenSuperclass --hide UnavailableSymbol --no-docs --stub-packages android.car* " +
         "--show-annotation android.annotation.TestApi ",
     installable: false,
     check_api: {
@@ -205,9 +218,8 @@
     libs: [
         "android.car",
     ],
-    api_tag_name: "ANDROID_CAR_STUB",
     api_filename: "api.txt",
-    args: "--hide UnavailableSymbol --no-docs --stub-packages android.car* ",
+    args: "--hide HiddenSuperclass --hide UnavailableSymbol --no-docs --stub-packages android.car* ",
     installable: false,
     product_variables: {
         pdk: {
@@ -227,17 +239,28 @@
             enabled: false,
         },
     },
-    compile_dex: true,
+    installable: false,
     dist: {
         targets: ["dist_files"],
     }
 }
 
 java_library {
+    name: "android.car-stubs-dex",
+    static_libs: ["android.car-stubs"],
+    sdk_version: "current",
+    product_variables: {
+        pdk: {
+            enabled: false,
+        },
+    },
+    compile_dex: true,
+}
+
+java_library {
     name: "android.car-system-stubs",
     srcs: [
         ":android.car-system-stubs-docs",
-        "src_stub/**/*.java",
     ],
     sdk_version: "system_current",
     product_variables: {
@@ -245,13 +268,25 @@
             enabled: false,
         },
     },
-    compile_dex: true,
+    installable: false,
     dist: {
         targets: ["dist_files"],
     }
 }
 
 java_library {
+    name: "android.car-system-stubs-dex",
+    static_libs: ["android.car-system-stubs"],
+    sdk_version: "system_current",
+    product_variables: {
+        pdk: {
+            enabled: false,
+        },
+    },
+    compile_dex: true,
+}
+
+java_library {
     name: "android.car-test-stubs",
     srcs: [
         ":android.car-test-stubs-docs",
@@ -262,8 +297,42 @@
             enabled: false,
         },
     },
+    installable: false,
+}
+
+java_library {
+    name: "android.car-test-stubs-dex",
+    static_libs: ["android.car-test-stubs"],
+    sdk_version: "test_current",
+    product_variables: {
+        pdk: {
+            enabled: false,
+        },
+    },
     compile_dex: true,
     dist: {
         targets: ["dist_files"],
     }
 }
+
+// Export the api/system-current.txt file.
+filegroup {
+    name: "car-api-system-current.txt",
+    visibility: [
+        "//cts/tests/signature/api",
+    ],
+    srcs: [
+        "api/system-current.txt",
+    ],
+}
+
+// Export the api/system-removed.txt file.
+filegroup {
+    name: "car-api-system-removed.txt",
+    visibility: [
+        "//cts/tests/signature/api",
+    ],
+    srcs: [
+        "api/system-removed.txt",
+    ],
+}
diff --git a/car-lib/api/baseline.txt b/car-lib/api/baseline.txt
index 16e4b7b..e274b0a 100644
--- a/car-lib/api/baseline.txt
+++ b/car-lib/api/baseline.txt
@@ -1,41 +1,173 @@
 // Baseline format: 1.0
-HiddenTypeParameter: android.car.hardware.CarSensorManager#getPropertyList():
-    Method android.car.hardware.CarSensorManager.getPropertyList() references hidden type class android.car.hardware.CarPropertyConfig.
-HiddenTypeParameter: android.car.navigation.CarNavigationStatusManager#getInstrumentClusterInfo():
-    Method android.car.navigation.CarNavigationStatusManager.getInstrumentClusterInfo() references hidden type android.car.navigation.CarNavigationInstrumentCluster.
-
-
-HiddenTypedefConstant: android.car.CarInfoManager#getEvConnectorTypes():
-    Typedef references constant which isn't part of the API, skipping in documentation: android.car.EvConnectorType#UNKNOWN
-HiddenTypedefConstant: android.car.CarInfoManager#getFuelTypes():
-    Typedef references constant which isn't part of the API, skipping in documentation: android.car.FuelType#UNKNOWN
-HiddenTypedefConstant: android.car.hardware.CarSensorManager#getLatestSensorEvent(int) parameter #0:
-    Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
-HiddenTypedefConstant: android.car.hardware.CarSensorManager#isSensorSupported(int) parameter #0:
-    Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
-HiddenTypedefConstant: android.car.hardware.CarSensorManager#isSensorSupported(int[], int) parameter #1:
-    Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
-HiddenTypedefConstant: android.car.hardware.CarSensorManager#registerListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int, int) parameter #1:
-    Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
-HiddenTypedefConstant: android.car.hardware.CarSensorManager#unregisterListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int) parameter #1:
-    Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
-
-
-ReferencesHidden: android.car.hardware.CarSensorManager#getPropertyList():
-    Class android.car.hardware.CarPropertyConfig is hidden but was referenced (as return type parameter) from public method android.car.hardware.CarSensorManager.getPropertyList()
-ReferencesHidden: android.car.navigation.CarNavigationStatusManager#getInstrumentClusterInfo():
-    Class android.car.navigation.CarNavigationInstrumentCluster is hidden but was referenced (as return type) from public method android.car.navigation.CarNavigationStatusManager.getInstrumentClusterInfo()
-
-
-RequiresPermission: android.car.hardware.CarSensorManager#registerListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int, int):
-    Method 'registerListener' documentation mentions permissions already declared by @RequiresPermission
-
-
-SdkConstant: android.car.Car#CAR_INTENT_ACTION_MEDIA_TEMPLATE:
-    Field 'CAR_INTENT_ACTION_MEDIA_TEMPLATE' is missing @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-
-
-Todo: android.car.CarInfoManager#getVehicleId():
-    Documentation mentions 'TODO'
-
-
+MissingPermission: android.car.VehiclePropertyIds#ABS_ACTIVE:
+    Permission Car.PERMISSION_CAR_DYNAMICS_STATE required by field VehiclePropertyIds.ABS_ACTIVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#AP_POWER_BOOTUP_REASON:
+    Permission Car.PERMISSION_CAR_POWER required by field VehiclePropertyIds.AP_POWER_BOOTUP_REASON is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#AP_POWER_STATE_REPORT:
+    Permission Car.PERMISSION_CAR_POWER required by field VehiclePropertyIds.AP_POWER_STATE_REPORT is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#AP_POWER_STATE_REQ:
+    Permission Car.PERMISSION_CAR_POWER required by field VehiclePropertyIds.AP_POWER_STATE_REQ is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#DISPLAY_BRIGHTNESS:
+    Permission Car.PERMISSION_CAR_POWER required by field VehiclePropertyIds.DISPLAY_BRIGHTNESS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#DOOR_LOCK:
+    Permission Car.PERMISSION_CONTROL_CAR_DOORS required by field VehiclePropertyIds.DOOR_LOCK is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#DOOR_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_DOORS required by field VehiclePropertyIds.DOOR_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#DOOR_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_DOORS required by field VehiclePropertyIds.DOOR_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#ENGINE_COOLANT_TEMP:
+    Permission Car.PERMISSION_CAR_ENGINE_DETAILED required by field VehiclePropertyIds.ENGINE_COOLANT_TEMP is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#ENGINE_OIL_LEVEL:
+    Permission Car.PERMISSION_CAR_ENGINE_DETAILED required by field VehiclePropertyIds.ENGINE_OIL_LEVEL is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#ENGINE_OIL_TEMP:
+    Permission Car.PERMISSION_CAR_ENGINE_DETAILED required by field VehiclePropertyIds.ENGINE_OIL_TEMP is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#ENGINE_RPM:
+    Permission Car.PERMISSION_CAR_ENGINE_DETAILED required by field VehiclePropertyIds.ENGINE_RPM is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#FOG_LIGHTS_STATE:
+    Permission Car.PERMISSION_EXTERIOR_LIGHTS required by field VehiclePropertyIds.FOG_LIGHTS_STATE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#FOG_LIGHTS_SWITCH:
+    Permission Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS required by field VehiclePropertyIds.FOG_LIGHTS_SWITCH is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HAZARD_LIGHTS_STATE:
+    Permission Car.PERMISSION_EXTERIOR_LIGHTS required by field VehiclePropertyIds.HAZARD_LIGHTS_STATE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HAZARD_LIGHTS_SWITCH:
+    Permission Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS required by field VehiclePropertyIds.HAZARD_LIGHTS_SWITCH is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HEADLIGHTS_STATE:
+    Permission Car.PERMISSION_EXTERIOR_LIGHTS required by field VehiclePropertyIds.HEADLIGHTS_STATE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HEADLIGHTS_SWITCH:
+    Permission Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS required by field VehiclePropertyIds.HEADLIGHTS_SWITCH is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HIGH_BEAM_LIGHTS_STATE:
+    Permission Car.PERMISSION_EXTERIOR_LIGHTS required by field VehiclePropertyIds.HIGH_BEAM_LIGHTS_STATE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HIGH_BEAM_LIGHTS_SWITCH:
+    Permission Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS required by field VehiclePropertyIds.HIGH_BEAM_LIGHTS_SWITCH is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_ACTUAL_FAN_SPEED_RPM:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_ACTUAL_FAN_SPEED_RPM is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_AC_ON:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_AC_ON is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_AUTO_ON:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_AUTO_ON is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_AUTO_RECIRC_ON:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_AUTO_RECIRC_ON is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_DEFROSTER:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_DEFROSTER is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_DUAL_ON:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_DUAL_ON is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_FAN_DIRECTION:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_FAN_DIRECTION is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_FAN_DIRECTION_AVAILABLE:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_FAN_DIRECTION_AVAILABLE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_FAN_SPEED:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_FAN_SPEED is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_MAX_AC_ON:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_MAX_AC_ON is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_MAX_DEFROST_ON:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_MAX_DEFROST_ON is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_POWER_ON:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_POWER_ON is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_RECIRC_ON:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_RECIRC_ON is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_SEAT_TEMPERATURE:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_SEAT_TEMPERATURE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_SEAT_VENTILATION:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_SEAT_VENTILATION is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_SIDE_MIRROR_HEAT:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_SIDE_MIRROR_HEAT is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_STEERING_WHEEL_HEAT:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_STEERING_WHEEL_HEAT is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_TEMPERATURE_CURRENT:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_TEMPERATURE_CURRENT is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_TEMPERATURE_DISPLAY_UNITS:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_TEMPERATURE_SET:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_TEMPERATURE_SET is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#MIRROR_FOLD:
+    Permission Car.PERMISSION_CONTROL_CAR_MIRRORS required by field VehiclePropertyIds.MIRROR_FOLD is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#MIRROR_LOCK:
+    Permission Car.PERMISSION_CONTROL_CAR_MIRRORS required by field VehiclePropertyIds.MIRROR_LOCK is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#MIRROR_Y_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_MIRRORS required by field VehiclePropertyIds.MIRROR_Y_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#MIRROR_Y_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_MIRRORS required by field VehiclePropertyIds.MIRROR_Y_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#MIRROR_Z_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_MIRRORS required by field VehiclePropertyIds.MIRROR_Z_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#MIRROR_Z_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_MIRRORS required by field VehiclePropertyIds.MIRROR_Z_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#OBD2_FREEZE_FRAME:
+    Permission Car.PERMISSION_CAR_DIAGNOSTIC_READ_ALL required by field VehiclePropertyIds.OBD2_FREEZE_FRAME is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#OBD2_FREEZE_FRAME_CLEAR:
+    Permission Car.PERMISSION_CAR_DIAGNOSTIC_CLEAR required by field VehiclePropertyIds.OBD2_FREEZE_FRAME_CLEAR is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#OBD2_FREEZE_FRAME_INFO:
+    Permission Car.PERMISSION_CAR_DIAGNOSTIC_READ_ALL required by field VehiclePropertyIds.OBD2_FREEZE_FRAME_INFO is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#OBD2_LIVE_FRAME:
+    Permission Car.PERMISSION_CAR_DIAGNOSTIC_READ_ALL required by field VehiclePropertyIds.OBD2_LIVE_FRAME is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#PERF_ODOMETER:
+    Permission Car.PERMISSION_MILEAGE required by field VehiclePropertyIds.PERF_ODOMETER is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_BACKREST_ANGLE_1_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_BACKREST_ANGLE_1_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_BACKREST_ANGLE_1_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_BACKREST_ANGLE_1_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_BACKREST_ANGLE_2_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_BACKREST_ANGLE_2_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_BACKREST_ANGLE_2_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_BACKREST_ANGLE_2_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_BELT_BUCKLED:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_BELT_BUCKLED is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_BELT_HEIGHT_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_BELT_HEIGHT_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_BELT_HEIGHT_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_BELT_HEIGHT_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_DEPTH_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_DEPTH_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_DEPTH_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_DEPTH_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_FORE_AFT_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_FORE_AFT_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_FORE_AFT_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_FORE_AFT_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_HEADREST_ANGLE_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_HEADREST_ANGLE_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_HEADREST_ANGLE_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_HEADREST_ANGLE_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_HEADREST_FORE_AFT_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_HEADREST_FORE_AFT_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_HEADREST_FORE_AFT_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_HEADREST_FORE_AFT_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_HEADREST_HEIGHT_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_HEADREST_HEIGHT_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_HEADREST_HEIGHT_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_HEADREST_HEIGHT_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_HEIGHT_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_HEIGHT_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_HEIGHT_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_HEIGHT_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_LUMBAR_FORE_AFT_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_LUMBAR_FORE_AFT_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_LUMBAR_FORE_AFT_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_LUMBAR_FORE_AFT_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_LUMBAR_SIDE_SUPPORT_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_LUMBAR_SIDE_SUPPORT_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_LUMBAR_SIDE_SUPPORT_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_LUMBAR_SIDE_SUPPORT_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_MEMORY_SELECT:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_MEMORY_SELECT is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_MEMORY_SET:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_MEMORY_SET is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_OCCUPANCY:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_OCCUPANCY is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_TILT_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_TILT_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_TILT_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_TILT_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#TIRE_PRESSURE:
+    Permission Car.PERMISSION_TIRES required by field VehiclePropertyIds.TIRE_PRESSURE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#TRACTION_CONTROL_ACTIVE:
+    Permission Car.PERMISSION_CAR_DYNAMICS_STATE required by field VehiclePropertyIds.TRACTION_CONTROL_ACTIVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#TURN_SIGNAL_STATE:
+    Permission Car.PERMISSION_EXTERIOR_LIGHTS required by field VehiclePropertyIds.TURN_SIGNAL_STATE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#VEHICLE_MAP_SERVICE:
+    Permission Car.PERMISSION_VMS_PUBLISHER required by field VehiclePropertyIds.VEHICLE_MAP_SERVICE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#WINDOW_LOCK:
+    Permission Car.PERMISSION_CONTROL_CAR_WINDOWS required by field VehiclePropertyIds.WINDOW_LOCK is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#WINDOW_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_WINDOWS required by field VehiclePropertyIds.WINDOW_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#WINDOW_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_WINDOWS required by field VehiclePropertyIds.WINDOW_POS is hidden or removed
diff --git a/car-lib/api/current.txt b/car-lib/api/current.txt
index 404350c..40b8e57 100644
--- a/car-lib/api/current.txt
+++ b/car-lib/api/current.txt
@@ -7,20 +7,28 @@
     method @Deprecated public static android.car.Car createCar(android.content.Context, android.content.ServiceConnection);
     method @Nullable public static android.car.Car createCar(android.content.Context);
     method @Nullable public static android.car.Car createCar(android.content.Context, @Nullable android.os.Handler);
+    method @NonNull public static android.car.Car createCar(@NonNull android.content.Context, @Nullable android.os.Handler, long, @NonNull android.car.Car.CarServiceLifecycleListener);
     method public void disconnect();
     method public int getCarConnectionType();
     method @Nullable public Object getCarManager(String);
     method public boolean isConnected();
     method public boolean isConnecting();
+    method public boolean isFeatureEnabled(@NonNull String);
     field public static final String APP_FOCUS_SERVICE = "app_focus";
     field public static final String AUDIO_SERVICE = "audio";
     field public static final String CAR_CONFIGURATION_SERVICE = "configuration";
-    field public static final String CAR_EXTRA_MEDIA_PACKAGE = "android.car.intent.extra.MEDIA_PACKAGE";
+    field public static final String CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION = "android.media.session.BROWSE_SERVICE";
+    field public static final String CAR_EXTRA_MEDIA_COMPONENT = "android.car.intent.extra.MEDIA_COMPONENT";
     field public static final String CAR_INTENT_ACTION_MEDIA_TEMPLATE = "android.car.intent.action.MEDIA_TEMPLATE";
     field public static final String CAR_NAVIGATION_SERVICE = "car_navigation_service";
+    field public static final String CAR_OCCUPANT_ZONE_SERVICE = "car_occupant_zone_service";
     field public static final String CAR_UX_RESTRICTION_SERVICE = "uxrestriction";
+    field public static final long CAR_WAIT_TIMEOUT_DO_NOT_WAIT = 0L; // 0x0L
+    field public static final long CAR_WAIT_TIMEOUT_WAIT_FOREVER = -1L; // 0xffffffffffffffffL
     field public static final int CONNECTION_TYPE_EMBEDDED = 5; // 0x5
     field public static final String INFO_SERVICE = "info";
+    field public static final String META_DATA_DISTRACTION_OPTIMIZED = "distractionOptimized";
+    field public static final String META_DATA_REQUIRES_CAR_FEATURE = "requires-car-feature";
     field public static final String PACKAGE_SERVICE = "package";
     field public static final String PERMISSION_CAR_CONTROL_AUDIO_SETTINGS = "android.car.permission.CAR_CONTROL_AUDIO_SETTINGS";
     field public static final String PERMISSION_CAR_CONTROL_AUDIO_VOLUME = "android.car.permission.CAR_CONTROL_AUDIO_VOLUME";
@@ -41,6 +49,10 @@
     field @Deprecated public static final String SENSOR_SERVICE = "sensor";
   }
 
+  public static interface Car.CarServiceLifecycleListener {
+    method public void onLifecycleChanged(@NonNull android.car.Car, boolean);
+  }
+
   public final class CarAppFocusManager {
     method public void abandonAppFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback, int);
     method public void abandonAppFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback);
@@ -86,14 +98,51 @@
     ctor @Deprecated public CarNotConnectedException(Exception);
   }
 
+  public class CarOccupantZoneManager {
+    method @NonNull public java.util.List<android.view.Display> getAllDisplaysForOccupant(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+    method @NonNull public java.util.List<android.car.CarOccupantZoneManager.OccupantZoneInfo> getAllOccupantZones();
+    method @Nullable public android.view.Display getDisplayForOccupant(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo, int);
+    method public int getDisplayType(@NonNull android.view.Display);
+    method public int getUserForOccupant(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+    method public void registerOccupantZoneConfigChangeListener(@NonNull android.car.CarOccupantZoneManager.OccupantZoneConfigChangeListener);
+    method public void unregisterOccupantZoneConfigChangeListener(@NonNull android.car.CarOccupantZoneManager.OccupantZoneConfigChangeListener);
+    field public static final int DISPLAY_TYPE_AUXILIARY = 5; // 0x5
+    field public static final int DISPLAY_TYPE_HUD = 3; // 0x3
+    field public static final int DISPLAY_TYPE_INPUT = 4; // 0x4
+    field public static final int DISPLAY_TYPE_INSTRUMENT_CLUSTER = 2; // 0x2
+    field public static final int DISPLAY_TYPE_MAIN = 1; // 0x1
+    field public static final int DISPLAY_TYPE_UNKNOWN = 0; // 0x0
+    field public static final int OCCUPANT_TYPE_DRIVER = 0; // 0x0
+    field public static final int OCCUPANT_TYPE_FRONT_PASSENGER = 1; // 0x1
+    field public static final int OCCUPANT_TYPE_REAR_PASSENGER = 2; // 0x2
+    field public static final int ZONE_CONFIG_CHANGE_FLAG_AUDIO = 4; // 0x4
+    field public static final int ZONE_CONFIG_CHANGE_FLAG_DISPLAY = 1; // 0x1
+    field public static final int ZONE_CONFIG_CHANGE_FLAG_USER = 2; // 0x2
+  }
+
+  public static interface CarOccupantZoneManager.OccupantZoneConfigChangeListener {
+    method public void onOccupantZoneConfigChanged(int);
+  }
+
+  public static final class CarOccupantZoneManager.OccupantZoneInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.car.CarOccupantZoneManager.OccupantZoneInfo> CREATOR;
+    field public final int occupantType;
+    field public final int seat;
+    field public int zoneId;
+  }
+
   public final class EvConnectorType {
     field public static final int CHADEMO = 3; // 0x3
     field public static final int COMBO_1 = 4; // 0x4
     field public static final int COMBO_2 = 5; // 0x5
     field public static final int GBT = 9; // 0x9
+    field public static final int GBT_DC = 10; // 0xa
     field public static final int J1772 = 1; // 0x1
     field public static final int MENNEKES = 2; // 0x2
     field public static final int OTHER = 101; // 0x65
+    field public static final int SCAME = 11; // 0xb
     field public static final int TESLA_HPWC = 7; // 0x7
     field public static final int TESLA_ROADSTER = 6; // 0x6
     field public static final int TESLA_SUPERCHARGER = 8; // 0x8
@@ -148,136 +197,165 @@
     field public static final int VEHICLE_AREA_TYPE_WINDOW = 2; // 0x2
   }
 
+  public final class VehicleAreaWheel {
+    field public static final int WHEEL_LEFT_FRONT = 1; // 0x1
+    field public static final int WHEEL_LEFT_REAR = 4; // 0x4
+    field public static final int WHEEL_RIGHT_FRONT = 2; // 0x2
+    field public static final int WHEEL_RIGHT_REAR = 8; // 0x8
+    field public static final int WHEEL_UNKNOWN = 0; // 0x0
+  }
+
+  public final class VehicleGear {
+    method public static String toString(int);
+    field public static final int GEAR_DRIVE = 8; // 0x8
+    field public static final int GEAR_EIGHTH = 2048; // 0x800
+    field public static final int GEAR_FIFTH = 256; // 0x100
+    field public static final int GEAR_FIRST = 16; // 0x10
+    field public static final int GEAR_FOURTH = 128; // 0x80
+    field public static final int GEAR_NEUTRAL = 1; // 0x1
+    field public static final int GEAR_NINTH = 4096; // 0x1000
+    field public static final int GEAR_PARK = 4; // 0x4
+    field public static final int GEAR_REVERSE = 2; // 0x2
+    field public static final int GEAR_SECOND = 32; // 0x20
+    field public static final int GEAR_SEVENTH = 1024; // 0x400
+    field public static final int GEAR_SIXTH = 512; // 0x200
+    field public static final int GEAR_THIRD = 64; // 0x40
+    field public static final int GEAR_UNKNOWN = 0; // 0x0
+  }
+
   public final class VehiclePropertyIds {
     ctor public VehiclePropertyIds();
     method public static String toString(int);
-    field public static final int ABS_ACTIVE = 287310858; // 0x1120040a
-    field public static final int AP_POWER_BOOTUP_REASON = 289409538; // 0x11400a02
-    field public static final int AP_POWER_STATE_REPORT = 289475073; // 0x11410a01
-    field public static final int AP_POWER_STATE_REQ = 289475072; // 0x11410a00
-    field public static final int CABIN_LIGHTS_STATE = 289410817; // 0x11400f01
-    field public static final int CABIN_LIGHTS_SWITCH = 289410818; // 0x11400f02
-    field public static final int CURRENT_GEAR = 289408001; // 0x11400401
-    field public static final int DISPLAY_BRIGHTNESS = 289409539; // 0x11400a03
-    field public static final int DISTANCE_DISPLAY_UNITS = 289408512; // 0x11400600
-    field public static final int DOOR_LOCK = 371198722; // 0x16200b02
-    field public static final int DOOR_MOVE = 373295873; // 0x16400b01
-    field public static final int DOOR_POS = 373295872; // 0x16400b00
-    field public static final int ENGINE_COOLANT_TEMP = 291504897; // 0x11600301
-    field public static final int ENGINE_OIL_LEVEL = 289407747; // 0x11400303
-    field public static final int ENGINE_OIL_TEMP = 291504900; // 0x11600304
-    field public static final int ENGINE_RPM = 291504901; // 0x11600305
-    field public static final int ENV_OUTSIDE_TEMPERATURE = 291505923; // 0x11600703
-    field public static final int EV_BATTERY_DISPLAY_UNITS = 289408515; // 0x11400603
-    field public static final int EV_BATTERY_INSTANTANEOUS_CHARGE_RATE = 291504908; // 0x1160030c
-    field public static final int EV_BATTERY_LEVEL = 291504905; // 0x11600309
-    field public static final int EV_CHARGE_PORT_CONNECTED = 287310603; // 0x1120030b
-    field public static final int EV_CHARGE_PORT_OPEN = 287310602; // 0x1120030a
-    field public static final int FOG_LIGHTS_STATE = 289410562; // 0x11400e02
-    field public static final int FOG_LIGHTS_SWITCH = 289410578; // 0x11400e12
-    field public static final int FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME = 287311364; // 0x11200604
-    field public static final int FUEL_DOOR_OPEN = 287310600; // 0x11200308
-    field public static final int FUEL_LEVEL = 291504903; // 0x11600307
-    field public static final int FUEL_LEVEL_LOW = 287310853; // 0x11200405
-    field public static final int FUEL_VOLUME_DISPLAY_UNITS = 289408513; // 0x11400601
-    field public static final int GEAR_SELECTION = 289408000; // 0x11400400
-    field public static final int HAZARD_LIGHTS_STATE = 289410563; // 0x11400e03
-    field public static final int HAZARD_LIGHTS_SWITCH = 289410579; // 0x11400e13
-    field public static final int HEADLIGHTS_STATE = 289410560; // 0x11400e00
-    field public static final int HEADLIGHTS_SWITCH = 289410576; // 0x11400e10
-    field public static final int HIGH_BEAM_LIGHTS_STATE = 289410561; // 0x11400e01
-    field public static final int HIGH_BEAM_LIGHTS_SWITCH = 289410577; // 0x11400e11
-    field public static final int HVAC_ACTUAL_FAN_SPEED_RPM = 356517135; // 0x1540050f
-    field public static final int HVAC_AC_ON = 354419973; // 0x15200505
-    field public static final int HVAC_AUTO_ON = 354419978; // 0x1520050a
-    field public static final int HVAC_AUTO_RECIRC_ON = 354419986; // 0x15200512
-    field public static final int HVAC_DEFROSTER = 320865540; // 0x13200504
-    field public static final int HVAC_DUAL_ON = 354419977; // 0x15200509
-    field public static final int HVAC_FAN_DIRECTION = 356517121; // 0x15400501
-    field public static final int HVAC_FAN_DIRECTION_AVAILABLE = 356582673; // 0x15410511
-    field public static final int HVAC_FAN_SPEED = 356517120; // 0x15400500
-    field public static final int HVAC_MAX_AC_ON = 354419974; // 0x15200506
-    field public static final int HVAC_MAX_DEFROST_ON = 354419975; // 0x15200507
-    field public static final int HVAC_POWER_ON = 354419984; // 0x15200510
-    field public static final int HVAC_RECIRC_ON = 354419976; // 0x15200508
-    field public static final int HVAC_SEAT_TEMPERATURE = 356517131; // 0x1540050b
-    field public static final int HVAC_SEAT_VENTILATION = 356517139; // 0x15400513
-    field public static final int HVAC_SIDE_MIRROR_HEAT = 339739916; // 0x1440050c
-    field public static final int HVAC_STEERING_WHEEL_HEAT = 289408269; // 0x1140050d
-    field public static final int HVAC_TEMPERATURE_CURRENT = 358614274; // 0x15600502
-    field public static final int HVAC_TEMPERATURE_DISPLAY_UNITS = 289408270; // 0x1140050e
-    field public static final int HVAC_TEMPERATURE_SET = 358614275; // 0x15600503
+    field @RequiresPermission("android.car.permission.CAR_DYNAMICS_STATE") public static final int ABS_ACTIVE = 287310858; // 0x1120040a
+    field @RequiresPermission("android.car.permission.CAR_POWER") public static final int AP_POWER_BOOTUP_REASON = 289409538; // 0x11400a02
+    field @RequiresPermission("android.car.permission.CAR_POWER") public static final int AP_POWER_STATE_REPORT = 289475073; // 0x11410a01
+    field @RequiresPermission("android.car.permission.CAR_POWER") public static final int AP_POWER_STATE_REQ = 289475072; // 0x11410a00
+    field @RequiresPermission(android.car.Car.PERMISSION_READ_INTERIOR_LIGHTS) public static final int CABIN_LIGHTS_STATE = 289410817; // 0x11400f01
+    field @RequiresPermission(android.car.Car.PERMISSION_CONTROL_INTERIOR_LIGHTS) public static final int CABIN_LIGHTS_SWITCH = 289410818; // 0x11400f02
+    field @RequiresPermission(android.car.Car.PERMISSION_POWERTRAIN) public static final int CURRENT_GEAR = 289408001; // 0x11400401
+    field @RequiresPermission("android.car.permission.CAR_POWER") public static final int DISPLAY_BRIGHTNESS = 289409539; // 0x11400a03
+    field @RequiresPermission.Read(@androidx.annotation.RequiresPermission(android.car.Car.PERMISSION_READ_DISPLAY_UNITS)) @RequiresPermission.Write(@androidx.annotation.RequiresPermission(allOf={android.car.Car.PERMISSION_CONTROL_DISPLAY_UNITS, "android.car.permission.CAR_VENDOR_EXTENSION"})) public static final int DISTANCE_DISPLAY_UNITS = 289408512; // 0x11400600
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_DOORS") public static final int DOOR_LOCK = 371198722; // 0x16200b02
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_DOORS") public static final int DOOR_MOVE = 373295873; // 0x16400b01
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_DOORS") public static final int DOOR_POS = 373295872; // 0x16400b00
+    field @RequiresPermission("android.car.permission.CAR_ENGINE_DETAILED") public static final int ENGINE_COOLANT_TEMP = 291504897; // 0x11600301
+    field @RequiresPermission("android.car.permission.CAR_ENGINE_DETAILED") public static final int ENGINE_OIL_LEVEL = 289407747; // 0x11400303
+    field @RequiresPermission("android.car.permission.CAR_ENGINE_DETAILED") public static final int ENGINE_OIL_TEMP = 291504900; // 0x11600304
+    field @RequiresPermission("android.car.permission.CAR_ENGINE_DETAILED") public static final int ENGINE_RPM = 291504901; // 0x11600305
+    field @RequiresPermission(android.car.Car.PERMISSION_EXTERIOR_ENVIRONMENT) public static final int ENV_OUTSIDE_TEMPERATURE = 291505923; // 0x11600703
+    field @RequiresPermission.Read(@androidx.annotation.RequiresPermission(android.car.Car.PERMISSION_READ_DISPLAY_UNITS)) @RequiresPermission.Write(@androidx.annotation.RequiresPermission(allOf={android.car.Car.PERMISSION_CONTROL_DISPLAY_UNITS, "android.car.permission.CAR_VENDOR_EXTENSION"})) public static final int EV_BATTERY_DISPLAY_UNITS = 289408515; // 0x11400603
+    field @RequiresPermission(android.car.Car.PERMISSION_ENERGY) public static final int EV_BATTERY_INSTANTANEOUS_CHARGE_RATE = 291504908; // 0x1160030c
+    field @RequiresPermission(android.car.Car.PERMISSION_ENERGY) public static final int EV_BATTERY_LEVEL = 291504905; // 0x11600309
+    field @RequiresPermission(android.car.Car.PERMISSION_ENERGY_PORTS) public static final int EV_CHARGE_PORT_CONNECTED = 287310603; // 0x1120030b
+    field @RequiresPermission.Read(@androidx.annotation.RequiresPermission(android.car.Car.PERMISSION_ENERGY_PORTS)) @RequiresPermission.Write(@androidx.annotation.RequiresPermission("android.car.permission.CONTROL_CAR_ENERGY_PORTS")) public static final int EV_CHARGE_PORT_OPEN = 287310602; // 0x1120030a
+    field @RequiresPermission("android.car.permission.CAR_EXTERIOR_LIGHTS") public static final int FOG_LIGHTS_STATE = 289410562; // 0x11400e02
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS") public static final int FOG_LIGHTS_SWITCH = 289410578; // 0x11400e12
+    field @RequiresPermission.Read(@androidx.annotation.RequiresPermission(android.car.Car.PERMISSION_READ_DISPLAY_UNITS)) @RequiresPermission.Write(@androidx.annotation.RequiresPermission(allOf={android.car.Car.PERMISSION_CONTROL_DISPLAY_UNITS, "android.car.permission.CAR_VENDOR_EXTENSION"})) public static final int FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME = 287311364; // 0x11200604
+    field @RequiresPermission.Read(@androidx.annotation.RequiresPermission(android.car.Car.PERMISSION_ENERGY_PORTS)) @RequiresPermission.Write(@androidx.annotation.RequiresPermission("android.car.permission.CONTROL_CAR_ENERGY_PORTS")) public static final int FUEL_DOOR_OPEN = 287310600; // 0x11200308
+    field @RequiresPermission(android.car.Car.PERMISSION_ENERGY) public static final int FUEL_LEVEL = 291504903; // 0x11600307
+    field @RequiresPermission(android.car.Car.PERMISSION_ENERGY) public static final int FUEL_LEVEL_LOW = 287310853; // 0x11200405
+    field @RequiresPermission.Read(@androidx.annotation.RequiresPermission(android.car.Car.PERMISSION_READ_DISPLAY_UNITS)) @RequiresPermission.Write(@androidx.annotation.RequiresPermission(allOf={android.car.Car.PERMISSION_CONTROL_DISPLAY_UNITS, "android.car.permission.CAR_VENDOR_EXTENSION"})) public static final int FUEL_VOLUME_DISPLAY_UNITS = 289408513; // 0x11400601
+    field @RequiresPermission(android.car.Car.PERMISSION_POWERTRAIN) public static final int GEAR_SELECTION = 289408000; // 0x11400400
+    field @RequiresPermission("android.car.permission.CAR_EXTERIOR_LIGHTS") public static final int HAZARD_LIGHTS_STATE = 289410563; // 0x11400e03
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS") public static final int HAZARD_LIGHTS_SWITCH = 289410579; // 0x11400e13
+    field @RequiresPermission("android.car.permission.CAR_EXTERIOR_LIGHTS") public static final int HEADLIGHTS_STATE = 289410560; // 0x11400e00
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS") public static final int HEADLIGHTS_SWITCH = 289410576; // 0x11400e10
+    field @RequiresPermission("android.car.permission.CAR_EXTERIOR_LIGHTS") public static final int HIGH_BEAM_LIGHTS_STATE = 289410561; // 0x11400e01
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS") public static final int HIGH_BEAM_LIGHTS_SWITCH = 289410577; // 0x11400e11
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_CLIMATE") public static final int HVAC_ACTUAL_FAN_SPEED_RPM = 356517135; // 0x1540050f
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_CLIMATE") public static final int HVAC_AC_ON = 354419973; // 0x15200505
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_CLIMATE") public static final int HVAC_AUTO_ON = 354419978; // 0x1520050a
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_CLIMATE") public static final int HVAC_AUTO_RECIRC_ON = 354419986; // 0x15200512
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_CLIMATE") public static final int HVAC_DEFROSTER = 320865540; // 0x13200504
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_CLIMATE") public static final int HVAC_DUAL_ON = 354419977; // 0x15200509
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_CLIMATE") public static final int HVAC_FAN_DIRECTION = 356517121; // 0x15400501
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_CLIMATE") public static final int HVAC_FAN_DIRECTION_AVAILABLE = 356582673; // 0x15410511
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_CLIMATE") public static final int HVAC_FAN_SPEED = 356517120; // 0x15400500
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_CLIMATE") public static final int HVAC_MAX_AC_ON = 354419974; // 0x15200506
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_CLIMATE") public static final int HVAC_MAX_DEFROST_ON = 354419975; // 0x15200507
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_CLIMATE") public static final int HVAC_POWER_ON = 354419984; // 0x15200510
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_CLIMATE") public static final int HVAC_RECIRC_ON = 354419976; // 0x15200508
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_CLIMATE") public static final int HVAC_SEAT_TEMPERATURE = 356517131; // 0x1540050b
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_CLIMATE") public static final int HVAC_SEAT_VENTILATION = 356517139; // 0x15400513
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_CLIMATE") public static final int HVAC_SIDE_MIRROR_HEAT = 339739916; // 0x1440050c
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_CLIMATE") public static final int HVAC_STEERING_WHEEL_HEAT = 289408269; // 0x1140050d
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_CLIMATE") public static final int HVAC_TEMPERATURE_CURRENT = 358614274; // 0x15600502
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_CLIMATE") public static final int HVAC_TEMPERATURE_DISPLAY_UNITS = 289408270; // 0x1140050e
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_CLIMATE") public static final int HVAC_TEMPERATURE_SET = 358614275; // 0x15600503
     field public static final int HW_KEY_INPUT = 289475088; // 0x11410a10
-    field public static final int IGNITION_STATE = 289408009; // 0x11400409
-    field public static final int INFO_DRIVER_SEAT = 356516106; // 0x1540010a
-    field public static final int INFO_EV_BATTERY_CAPACITY = 291504390; // 0x11600106
-    field public static final int INFO_EV_CONNECTOR_TYPE = 289472775; // 0x11410107
-    field public static final int INFO_EV_PORT_LOCATION = 289407241; // 0x11400109
-    field public static final int INFO_FUEL_CAPACITY = 291504388; // 0x11600104
-    field public static final int INFO_FUEL_DOOR_LOCATION = 289407240; // 0x11400108
-    field public static final int INFO_FUEL_TYPE = 289472773; // 0x11410105
-    field public static final int INFO_MAKE = 286261505; // 0x11100101
-    field public static final int INFO_MODEL = 286261506; // 0x11100102
-    field public static final int INFO_MODEL_YEAR = 289407235; // 0x11400103
-    field public static final int INFO_VIN = 286261504; // 0x11100100
+    field @RequiresPermission(android.car.Car.PERMISSION_POWERTRAIN) public static final int IGNITION_STATE = 289408009; // 0x11400409
+    field @RequiresPermission(android.car.Car.PERMISSION_CAR_INFO) public static final int INFO_DRIVER_SEAT = 356516106; // 0x1540010a
+    field @RequiresPermission(android.car.Car.PERMISSION_CAR_INFO) public static final int INFO_EV_BATTERY_CAPACITY = 291504390; // 0x11600106
+    field @RequiresPermission(android.car.Car.PERMISSION_CAR_INFO) public static final int INFO_EV_CONNECTOR_TYPE = 289472775; // 0x11410107
+    field @RequiresPermission(android.car.Car.PERMISSION_CAR_INFO) public static final int INFO_EV_PORT_LOCATION = 289407241; // 0x11400109
+    field @RequiresPermission(android.car.Car.PERMISSION_CAR_INFO) public static final int INFO_EXTERIOR_DIMENSIONS = 289472779; // 0x1141010b
+    field @RequiresPermission(android.car.Car.PERMISSION_CAR_INFO) public static final int INFO_FUEL_CAPACITY = 291504388; // 0x11600104
+    field @RequiresPermission(android.car.Car.PERMISSION_CAR_INFO) public static final int INFO_FUEL_DOOR_LOCATION = 289407240; // 0x11400108
+    field @RequiresPermission(android.car.Car.PERMISSION_CAR_INFO) public static final int INFO_FUEL_TYPE = 289472773; // 0x11410105
+    field @RequiresPermission(android.car.Car.PERMISSION_CAR_INFO) public static final int INFO_MAKE = 286261505; // 0x11100101
+    field @RequiresPermission(android.car.Car.PERMISSION_CAR_INFO) public static final int INFO_MODEL = 286261506; // 0x11100102
+    field @RequiresPermission(android.car.Car.PERMISSION_CAR_INFO) public static final int INFO_MODEL_YEAR = 289407235; // 0x11400103
+    field @RequiresPermission(android.car.Car.PERMISSION_CAR_INFO) public static final int INFO_MULTI_EV_PORT_LOCATIONS = 289472780; // 0x1141010c
+    field @RequiresPermission(android.car.Car.PERMISSION_IDENTIFICATION) public static final int INFO_VIN = 286261504; // 0x11100100
     field public static final int INVALID = 0; // 0x0
-    field public static final int MIRROR_FOLD = 287312709; // 0x11200b45
-    field public static final int MIRROR_LOCK = 287312708; // 0x11200b44
-    field public static final int MIRROR_Y_MOVE = 339741507; // 0x14400b43
-    field public static final int MIRROR_Y_POS = 339741506; // 0x14400b42
-    field public static final int MIRROR_Z_MOVE = 339741505; // 0x14400b41
-    field public static final int MIRROR_Z_POS = 339741504; // 0x14400b40
-    field public static final int NIGHT_MODE = 287310855; // 0x11200407
-    field public static final int OBD2_FREEZE_FRAME = 299896065; // 0x11e00d01
-    field public static final int OBD2_FREEZE_FRAME_CLEAR = 299896067; // 0x11e00d03
-    field public static final int OBD2_FREEZE_FRAME_INFO = 299896066; // 0x11e00d02
-    field public static final int OBD2_LIVE_FRAME = 299896064; // 0x11e00d00
-    field public static final int PARKING_BRAKE_AUTO_APPLY = 287310851; // 0x11200403
-    field public static final int PARKING_BRAKE_ON = 287310850; // 0x11200402
-    field public static final int PERF_ODOMETER = 291504644; // 0x11600204
-    field public static final int PERF_STEERING_ANGLE = 291504649; // 0x11600209
-    field public static final int PERF_VEHICLE_SPEED = 291504647; // 0x11600207
-    field public static final int PERF_VEHICLE_SPEED_DISPLAY = 291504648; // 0x11600208
-    field public static final int RANGE_REMAINING = 291504904; // 0x11600308
-    field public static final int READING_LIGHTS_STATE = 356519683; // 0x15400f03
-    field public static final int READING_LIGHTS_SWITCH = 356519684; // 0x15400f04
-    field public static final int SEAT_BACKREST_ANGLE_1_MOVE = 356518792; // 0x15400b88
-    field public static final int SEAT_BACKREST_ANGLE_1_POS = 356518791; // 0x15400b87
-    field public static final int SEAT_BACKREST_ANGLE_2_MOVE = 356518794; // 0x15400b8a
-    field public static final int SEAT_BACKREST_ANGLE_2_POS = 356518793; // 0x15400b89
-    field public static final int SEAT_BELT_BUCKLED = 354421634; // 0x15200b82
-    field public static final int SEAT_BELT_HEIGHT_MOVE = 356518788; // 0x15400b84
-    field public static final int SEAT_BELT_HEIGHT_POS = 356518787; // 0x15400b83
-    field public static final int SEAT_DEPTH_MOVE = 356518798; // 0x15400b8e
-    field public static final int SEAT_DEPTH_POS = 356518797; // 0x15400b8d
-    field public static final int SEAT_FORE_AFT_MOVE = 356518790; // 0x15400b86
-    field public static final int SEAT_FORE_AFT_POS = 356518789; // 0x15400b85
-    field public static final int SEAT_HEADREST_ANGLE_MOVE = 356518808; // 0x15400b98
-    field public static final int SEAT_HEADREST_ANGLE_POS = 356518807; // 0x15400b97
-    field public static final int SEAT_HEADREST_FORE_AFT_MOVE = 356518810; // 0x15400b9a
-    field public static final int SEAT_HEADREST_FORE_AFT_POS = 356518809; // 0x15400b99
-    field public static final int SEAT_HEADREST_HEIGHT_MOVE = 356518806; // 0x15400b96
-    field public static final int SEAT_HEADREST_HEIGHT_POS = 289409941; // 0x11400b95
-    field public static final int SEAT_HEIGHT_MOVE = 356518796; // 0x15400b8c
-    field public static final int SEAT_HEIGHT_POS = 356518795; // 0x15400b8b
-    field public static final int SEAT_LUMBAR_FORE_AFT_MOVE = 356518802; // 0x15400b92
-    field public static final int SEAT_LUMBAR_FORE_AFT_POS = 356518801; // 0x15400b91
-    field public static final int SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 356518804; // 0x15400b94
-    field public static final int SEAT_LUMBAR_SIDE_SUPPORT_POS = 356518803; // 0x15400b93
-    field public static final int SEAT_MEMORY_SELECT = 356518784; // 0x15400b80
-    field public static final int SEAT_MEMORY_SET = 356518785; // 0x15400b81
-    field public static final int SEAT_OCCUPANCY = 356518832; // 0x15400bb0
-    field public static final int SEAT_TILT_MOVE = 356518800; // 0x15400b90
-    field public static final int SEAT_TILT_POS = 356518799; // 0x15400b8f
-    field public static final int TIRE_PRESSURE = 392168201; // 0x17600309
-    field public static final int TIRE_PRESSURE_DISPLAY_UNITS = 289408514; // 0x11400602
-    field public static final int TRACTION_CONTROL_ACTIVE = 287310859; // 0x1120040b
-    field public static final int TURN_SIGNAL_STATE = 289408008; // 0x11400408
-    field public static final int VEHICLE_MAP_SERVICE = 299895808; // 0x11e00c00
-    field public static final int WHEEL_TICK = 290521862; // 0x11510306
-    field public static final int WINDOW_LOCK = 320867268; // 0x13200bc4
-    field public static final int WINDOW_MOVE = 322964417; // 0x13400bc1
-    field public static final int WINDOW_POS = 322964416; // 0x13400bc0
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_MIRRORS") public static final int MIRROR_FOLD = 287312709; // 0x11200b45
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_MIRRORS") public static final int MIRROR_LOCK = 287312708; // 0x11200b44
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_MIRRORS") public static final int MIRROR_Y_MOVE = 339741507; // 0x14400b43
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_MIRRORS") public static final int MIRROR_Y_POS = 339741506; // 0x14400b42
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_MIRRORS") public static final int MIRROR_Z_MOVE = 339741505; // 0x14400b41
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_MIRRORS") public static final int MIRROR_Z_POS = 339741504; // 0x14400b40
+    field @RequiresPermission(android.car.Car.PERMISSION_EXTERIOR_ENVIRONMENT) public static final int NIGHT_MODE = 287310855; // 0x11200407
+    field @RequiresPermission("android.car.permission.CAR_DIAGNOSTICS") public static final int OBD2_FREEZE_FRAME = 299896065; // 0x11e00d01
+    field @RequiresPermission("android.car.permission.CLEAR_CAR_DIAGNOSTICS") public static final int OBD2_FREEZE_FRAME_CLEAR = 299896067; // 0x11e00d03
+    field @RequiresPermission("android.car.permission.CAR_DIAGNOSTICS") public static final int OBD2_FREEZE_FRAME_INFO = 299896066; // 0x11e00d02
+    field @RequiresPermission("android.car.permission.CAR_DIAGNOSTICS") public static final int OBD2_LIVE_FRAME = 299896064; // 0x11e00d00
+    field @RequiresPermission(android.car.Car.PERMISSION_POWERTRAIN) public static final int PARKING_BRAKE_AUTO_APPLY = 287310851; // 0x11200403
+    field @RequiresPermission(android.car.Car.PERMISSION_POWERTRAIN) public static final int PARKING_BRAKE_ON = 287310850; // 0x11200402
+    field @RequiresPermission("android.car.permission.CAR_MILEAGE") public static final int PERF_ODOMETER = 291504644; // 0x11600204
+    field @RequiresPermission(android.car.Car.PERMISSION_READ_STEERING_STATE) public static final int PERF_REAR_STEERING_ANGLE = 291504656; // 0x11600210
+    field @RequiresPermission(android.car.Car.PERMISSION_READ_STEERING_STATE) public static final int PERF_STEERING_ANGLE = 291504649; // 0x11600209
+    field @RequiresPermission(android.car.Car.PERMISSION_SPEED) public static final int PERF_VEHICLE_SPEED = 291504647; // 0x11600207
+    field @RequiresPermission(android.car.Car.PERMISSION_SPEED) public static final int PERF_VEHICLE_SPEED_DISPLAY = 291504648; // 0x11600208
+    field @RequiresPermission.Read(@androidx.annotation.RequiresPermission(android.car.Car.PERMISSION_ENERGY)) @RequiresPermission.Write(@androidx.annotation.RequiresPermission("android.car.permission.ADJUST_RANGE_REMAINING")) public static final int RANGE_REMAINING = 291504904; // 0x11600308
+    field @RequiresPermission(android.car.Car.PERMISSION_READ_INTERIOR_LIGHTS) public static final int READING_LIGHTS_STATE = 356519683; // 0x15400f03
+    field @RequiresPermission(android.car.Car.PERMISSION_CONTROL_INTERIOR_LIGHTS) public static final int READING_LIGHTS_SWITCH = 356519684; // 0x15400f04
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_BACKREST_ANGLE_1_MOVE = 356518792; // 0x15400b88
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_BACKREST_ANGLE_1_POS = 356518791; // 0x15400b87
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_BACKREST_ANGLE_2_MOVE = 356518794; // 0x15400b8a
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_BACKREST_ANGLE_2_POS = 356518793; // 0x15400b89
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_BELT_BUCKLED = 354421634; // 0x15200b82
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_BELT_HEIGHT_MOVE = 356518788; // 0x15400b84
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_BELT_HEIGHT_POS = 356518787; // 0x15400b83
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_DEPTH_MOVE = 356518798; // 0x15400b8e
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_DEPTH_POS = 356518797; // 0x15400b8d
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_FORE_AFT_MOVE = 356518790; // 0x15400b86
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_FORE_AFT_POS = 356518789; // 0x15400b85
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_HEADREST_ANGLE_MOVE = 356518808; // 0x15400b98
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_HEADREST_ANGLE_POS = 356518807; // 0x15400b97
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_HEADREST_FORE_AFT_MOVE = 356518810; // 0x15400b9a
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_HEADREST_FORE_AFT_POS = 356518809; // 0x15400b99
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_HEADREST_HEIGHT_MOVE = 356518806; // 0x15400b96
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_HEADREST_HEIGHT_POS = 289409941; // 0x11400b95
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_HEIGHT_MOVE = 356518796; // 0x15400b8c
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_HEIGHT_POS = 356518795; // 0x15400b8b
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_LUMBAR_FORE_AFT_MOVE = 356518802; // 0x15400b92
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_LUMBAR_FORE_AFT_POS = 356518801; // 0x15400b91
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 356518804; // 0x15400b94
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_LUMBAR_SIDE_SUPPORT_POS = 356518803; // 0x15400b93
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_MEMORY_SELECT = 356518784; // 0x15400b80
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_MEMORY_SET = 356518785; // 0x15400b81
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_OCCUPANCY = 356518832; // 0x15400bb0
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_TILT_MOVE = 356518800; // 0x15400b90
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_SEATS") public static final int SEAT_TILT_POS = 356518799; // 0x15400b8f
+    field @RequiresPermission("android.car.permission.CAR_TIRES") public static final int TIRE_PRESSURE = 392168201; // 0x17600309
+    field @RequiresPermission.Read(@androidx.annotation.RequiresPermission(android.car.Car.PERMISSION_READ_DISPLAY_UNITS)) @RequiresPermission.Write(@androidx.annotation.RequiresPermission(allOf={android.car.Car.PERMISSION_CONTROL_DISPLAY_UNITS, "android.car.permission.CAR_VENDOR_EXTENSION"})) public static final int TIRE_PRESSURE_DISPLAY_UNITS = 289408514; // 0x11400602
+    field @RequiresPermission("android.car.permission.CAR_DYNAMICS_STATE") public static final int TRACTION_CONTROL_ACTIVE = 287310859; // 0x1120040b
+    field @RequiresPermission("android.car.permission.CAR_EXTERIOR_LIGHTS") public static final int TURN_SIGNAL_STATE = 289408008; // 0x11400408
+    field @RequiresPermission(anyOf={"android.car.permission.VMS_PUBLISHER", "android.car.permission.VMS_SUBSCRIBER"}) public static final int VEHICLE_MAP_SERVICE = 299895808; // 0x11e00c00
+    field @RequiresPermission(android.car.Car.PERMISSION_SPEED) public static final int WHEEL_TICK = 290521862; // 0x11510306
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_WINDOWS") public static final int WINDOW_LOCK = 320867268; // 0x13200bc4
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_WINDOWS") public static final int WINDOW_MOVE = 322964417; // 0x13400bc1
+    field @RequiresPermission("android.car.permission.CONTROL_CAR_WINDOWS") public static final int WINDOW_POS = 322964416; // 0x13400bc0
   }
 
 }
@@ -286,6 +364,7 @@
 
   public final class CarPackageManager {
     method public boolean isActivityDistractionOptimized(String, String);
+    method public boolean isPendingIntentDistractionOptimized(@NonNull android.app.PendingIntent);
     method public boolean isServiceDistractionOptimized(String, String);
   }
 
@@ -356,6 +435,7 @@
     method @Nullable public T getMinValue(int);
     method @Nullable public T getMinValue();
     method public int getPropertyId();
+    method @NonNull public Class<T> getPropertyType();
     method public boolean isGlobalProperty();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.car.hardware.CarPropertyConfig> CREATOR;
@@ -468,8 +548,13 @@
 
 package android.car.hardware.property {
 
+  public class CarInternalErrorException extends java.lang.RuntimeException {
+  }
+
   public class CarPropertyManager {
+    method public int getAreaId(int, int);
     method public boolean getBooleanProperty(int, int);
+    method @Nullable public android.car.hardware.CarPropertyConfig<?> getCarPropertyConfig(int);
     method public float getFloatProperty(int, int);
     method @NonNull public int[] getIntArrayProperty(int, int);
     method public int getIntProperty(int, int);
@@ -485,6 +570,11 @@
     method public <E> void setProperty(@NonNull Class<E>, int, int, @NonNull E);
     method public void unregisterCallback(@NonNull android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback);
     method public void unregisterCallback(@NonNull android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback, int);
+    field public static final int CAR_SET_PROPERTY_ERROR_CODE_ACCESS_DENIED = 4; // 0x4
+    field public static final int CAR_SET_PROPERTY_ERROR_CODE_INVALID_ARG = 2; // 0x2
+    field public static final int CAR_SET_PROPERTY_ERROR_CODE_PROPERTY_NOT_AVAILABLE = 3; // 0x3
+    field public static final int CAR_SET_PROPERTY_ERROR_CODE_TRY_AGAIN = 1; // 0x1
+    field public static final int CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN = 5; // 0x5
     field public static final float SENSOR_RATE_FAST = 10.0f;
     field public static final float SENSOR_RATE_FASTEST = 100.0f;
     field public static final float SENSOR_RATE_NORMAL = 1.0f;
@@ -495,6 +585,16 @@
   public static interface CarPropertyManager.CarPropertyEventCallback {
     method public void onChangeEvent(android.car.hardware.CarPropertyValue);
     method public void onErrorEvent(int, int);
+    method public default void onErrorEvent(int, int, int);
+  }
+
+  public class PropertyAccessDeniedSecurityException extends java.lang.SecurityException {
+  }
+
+  public class PropertyNotAvailableAndRetryException extends java.lang.IllegalStateException {
+  }
+
+  public class PropertyNotAvailableException extends java.lang.IllegalStateException {
   }
 
 }
@@ -516,29 +616,18 @@
 
 package android.car.settings {
 
-  public class CarConfigurationManager {
-    method public android.car.settings.SpeedBumpConfiguration getSpeedBumpConfiguration();
+  @Deprecated public class CarConfigurationManager {
+    method @Deprecated public android.car.settings.SpeedBumpConfiguration getSpeedBumpConfiguration();
   }
 
-  public class CarSettings {
-    ctor public CarSettings();
-  }
-
-  public static final class CarSettings.Global {
-    ctor public CarSettings.Global();
-    field @Deprecated public static final String KEY_GARAGE_MODE_ENABLED = "android.car.GARAGE_MODE_ENABLED";
-    field @Deprecated public static final String KEY_GARAGE_MODE_MAINTENANCE_WINDOW = "android.car.GARAGE_MODE_MAINTENANCE_WINDOW";
-    field @Deprecated public static final String KEY_GARAGE_MODE_WAKE_UP_TIME = "android.car.GARAGE_MODE_WAKE_UP_TIME";
-  }
-
-  public final class SpeedBumpConfiguration implements android.os.Parcelable {
-    ctor public SpeedBumpConfiguration(double, double, long);
-    method public int describeContents();
-    method public double getAcquiredPermitsPerSecond();
-    method public double getMaxPermitPool();
-    method public long getPermitFillDelay();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.settings.SpeedBumpConfiguration> CREATOR;
+  @Deprecated public final class SpeedBumpConfiguration implements android.os.Parcelable {
+    ctor @Deprecated public SpeedBumpConfiguration(double, double, long);
+    method @Deprecated public int describeContents();
+    method @Deprecated public double getAcquiredPermitsPerSecond();
+    method @Deprecated public double getMaxPermitPool();
+    method @Deprecated public long getPermitFillDelay();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final android.os.Parcelable.Creator<android.car.settings.SpeedBumpConfiguration> CREATOR;
   }
 
 }
diff --git a/car-lib/api/lint-baseline.txt b/car-lib/api/lint-baseline.txt
new file mode 100644
index 0000000..c1216f2
--- /dev/null
+++ b/car-lib/api/lint-baseline.txt
@@ -0,0 +1,253 @@
+// Baseline format: 1.0
+CallbackInterface: android.car.CarAppFocusManager.OnAppFocusOwnershipCallback:
+    Callbacks must be abstract class instead of interface to enable extension in future API levels: OnAppFocusOwnershipCallback
+CallbackInterface: android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback:
+    Callbacks must be abstract class instead of interface to enable extension in future API levels: CarPropertyEventCallback
+
+
+ConcreteCollection: android.car.hardware.property.CarPropertyManager#getPropertyList(android.util.ArraySet<java.lang.Integer>) parameter #0:
+    Parameter type is concrete collection (`android.util.ArraySet`); must be higher-level interface
+
+
+ExecutorRegistration: android.car.Car#createCar(android.content.Context, android.os.Handler, long, android.car.Car.CarServiceLifecycleListener):
+    Registration methods should have overload that accepts delivery Executor: `createCar`
+ExecutorRegistration: android.car.CarAppFocusManager#abandonAppFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback):
+    Registration methods should have overload that accepts delivery Executor: `abandonAppFocus`
+ExecutorRegistration: android.car.CarAppFocusManager#addFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener, int):
+    Registration methods should have overload that accepts delivery Executor: `addFocusListener`
+ExecutorRegistration: android.car.CarAppFocusManager#isOwningFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback, int):
+    Registration methods should have overload that accepts delivery Executor: `isOwningFocus`
+ExecutorRegistration: android.car.CarAppFocusManager#requestAppFocus(int, android.car.CarAppFocusManager.OnAppFocusOwnershipCallback):
+    Registration methods should have overload that accepts delivery Executor: `requestAppFocus`
+ExecutorRegistration: android.car.CarOccupantZoneManager#registerOccupantZoneConfigChangeListener(android.car.CarOccupantZoneManager.OccupantZoneConfigChangeListener):
+    Registration methods should have overload that accepts delivery Executor: `registerOccupantZoneConfigChangeListener`
+ExecutorRegistration: android.car.drivingstate.CarUxRestrictionsManager#registerListener(android.car.drivingstate.CarUxRestrictionsManager.OnUxRestrictionsChangedListener):
+    Registration methods should have overload that accepts delivery Executor: `registerListener`
+ExecutorRegistration: android.car.hardware.CarSensorManager#registerListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int, int):
+    Registration methods should have overload that accepts delivery Executor: `registerListener`
+ExecutorRegistration: android.car.hardware.property.CarPropertyManager#registerCallback(android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback, int, float):
+    Registration methods should have overload that accepts delivery Executor: `registerCallback`
+ExecutorRegistration: android.car.media.CarAudioManager#registerCarVolumeCallback(android.car.media.CarAudioManager.CarVolumeCallback):
+    Registration methods should have overload that accepts delivery Executor: `registerCarVolumeCallback`
+
+
+HiddenSuperclass: android.car.CarAppFocusManager:
+    Public class android.car.CarAppFocusManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.CarInfoManager:
+    Public class android.car.CarInfoManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.CarOccupantZoneManager:
+    Public class android.car.CarOccupantZoneManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.content.pm.CarPackageManager:
+    Public class android.car.content.pm.CarPackageManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.drivingstate.CarUxRestrictionsManager:
+    Public class android.car.drivingstate.CarUxRestrictionsManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.hardware.CarSensorManager:
+    Public class android.car.hardware.CarSensorManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.hardware.property.CarPropertyManager:
+    Public class android.car.hardware.property.CarPropertyManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.media.CarAudioManager:
+    Public class android.car.media.CarAudioManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.settings.CarConfigurationManager:
+    Public class android.car.settings.CarConfigurationManager stripped of unavailable superclass android.car.CarManagerBase
+
+
+IntentName: android.car.Car#CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION:
+    Intent extra constant name must be EXTRA_FOO: CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION
+IntentName: android.car.Car#CAR_EXTRA_MEDIA_COMPONENT:
+    Intent extra constant name must be EXTRA_FOO: CAR_EXTRA_MEDIA_COMPONENT
+IntentName: android.car.Car#CAR_INTENT_ACTION_MEDIA_TEMPLATE:
+    Intent action constant name must be ACTION_FOO: CAR_INTENT_ACTION_MEDIA_TEMPLATE
+
+
+ListenerLast: android.car.CarAppFocusManager#abandonAppFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback, int) parameter #1:
+    Listeners should always be at end of argument list (method `abandonAppFocus`)
+ListenerLast: android.car.CarAppFocusManager#isOwningFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback, int) parameter #1:
+    Listeners should always be at end of argument list (method `isOwningFocus`)
+
+
+MissingNullability: android.car.Car#createCar(android.content.Context) parameter #0:
+    Missing nullability on parameter `context` in method `createCar`
+MissingNullability: android.car.Car#createCar(android.content.Context, android.content.ServiceConnection) parameter #0:
+    Missing nullability on parameter `context` in method `createCar`
+MissingNullability: android.car.Car#createCar(android.content.Context, android.content.ServiceConnection) parameter #1:
+    Missing nullability on parameter `serviceConnectionListener` in method `createCar`
+MissingNullability: android.car.Car#createCar(android.content.Context, android.content.ServiceConnection, android.os.Handler) parameter #0:
+    Missing nullability on parameter `context` in method `createCar`
+MissingNullability: android.car.Car#createCar(android.content.Context, android.content.ServiceConnection, android.os.Handler) parameter #1:
+    Missing nullability on parameter `serviceConnectionListener` in method `createCar`
+MissingNullability: android.car.Car#createCar(android.content.Context, android.os.Handler) parameter #0:
+    Missing nullability on parameter `context` in method `createCar`
+MissingNullability: android.car.Car#getCarManager(String) parameter #0:
+    Missing nullability on parameter `serviceName` in method `getCarManager`
+MissingNullability: android.car.CarAppFocusManager#abandonAppFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback) parameter #0:
+    Missing nullability on parameter `ownershipCallback` in method `abandonAppFocus`
+MissingNullability: android.car.CarAppFocusManager#abandonAppFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback, int) parameter #0:
+    Missing nullability on parameter `ownershipCallback` in method `abandonAppFocus`
+MissingNullability: android.car.CarAppFocusManager#addFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener, int) parameter #0:
+    Missing nullability on parameter `listener` in method `addFocusListener`
+MissingNullability: android.car.CarAppFocusManager#isOwningFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback, int) parameter #0:
+    Missing nullability on parameter `callback` in method `isOwningFocus`
+MissingNullability: android.car.CarAppFocusManager#removeFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener) parameter #0:
+    Missing nullability on parameter `listener` in method `removeFocusListener`
+MissingNullability: android.car.CarAppFocusManager#removeFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener, int) parameter #0:
+    Missing nullability on parameter `listener` in method `removeFocusListener`
+MissingNullability: android.car.CarAppFocusManager#requestAppFocus(int, android.car.CarAppFocusManager.OnAppFocusOwnershipCallback) parameter #1:
+    Missing nullability on parameter `ownershipCallback` in method `requestAppFocus`
+MissingNullability: android.car.CarInfoManager#getEvConnectorTypes():
+    Missing nullability on method `getEvConnectorTypes` return
+MissingNullability: android.car.CarInfoManager#getFuelTypes():
+    Missing nullability on method `getFuelTypes` return
+MissingNullability: android.car.CarNotConnectedException#CarNotConnectedException(Exception) parameter #0:
+    Missing nullability on parameter `cause` in method `CarNotConnectedException`
+MissingNullability: android.car.CarNotConnectedException#CarNotConnectedException(String) parameter #0:
+    Missing nullability on parameter `name` in method `CarNotConnectedException`
+MissingNullability: android.car.CarNotConnectedException#CarNotConnectedException(String, Throwable) parameter #0:
+    Missing nullability on parameter `name` in method `CarNotConnectedException`
+MissingNullability: android.car.CarNotConnectedException#CarNotConnectedException(String, Throwable) parameter #1:
+    Missing nullability on parameter `cause` in method `CarNotConnectedException`
+MissingNullability: android.car.CarOccupantZoneManager.OccupantZoneInfo#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.CarOccupantZoneManager.OccupantZoneInfo`
+MissingNullability: android.car.CarOccupantZoneManager.OccupantZoneInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
+MissingNullability: android.car.VehicleGear#toString(int):
+    Missing nullability on method `toString` return
+MissingNullability: android.car.VehiclePropertyIds#toString(int):
+    Missing nullability on method `toString` return
+MissingNullability: android.car.content.pm.CarPackageManager#isActivityDistractionOptimized(String, String) parameter #0:
+    Missing nullability on parameter `packageName` in method `isActivityDistractionOptimized`
+MissingNullability: android.car.content.pm.CarPackageManager#isActivityDistractionOptimized(String, String) parameter #1:
+    Missing nullability on parameter `className` in method `isActivityDistractionOptimized`
+MissingNullability: android.car.content.pm.CarPackageManager#isServiceDistractionOptimized(String, String) parameter #0:
+    Missing nullability on parameter `packageName` in method `isServiceDistractionOptimized`
+MissingNullability: android.car.content.pm.CarPackageManager#isServiceDistractionOptimized(String, String) parameter #1:
+    Missing nullability on parameter `className` in method `isServiceDistractionOptimized`
+MissingNullability: android.car.drivingstate.CarUxRestrictions#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.drivingstate.CarUxRestrictions`
+MissingNullability: android.car.drivingstate.CarUxRestrictions#CarUxRestrictions(android.car.drivingstate.CarUxRestrictions) parameter #0:
+    Missing nullability on parameter `uxRestrictions` in method `CarUxRestrictions`
+MissingNullability: android.car.drivingstate.CarUxRestrictions#isSameRestrictions(android.car.drivingstate.CarUxRestrictions) parameter #0:
+    Missing nullability on parameter `other` in method `isSameRestrictions`
+MissingNullability: android.car.drivingstate.CarUxRestrictions#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
+MissingNullability: android.car.drivingstate.CarUxRestrictions.Builder#build():
+    Missing nullability on method `build` return
+MissingNullability: android.car.drivingstate.CarUxRestrictions.Builder#setMaxContentDepth(int):
+    Missing nullability on method `setMaxContentDepth` return
+MissingNullability: android.car.drivingstate.CarUxRestrictions.Builder#setMaxCumulativeContentItems(int):
+    Missing nullability on method `setMaxCumulativeContentItems` return
+MissingNullability: android.car.drivingstate.CarUxRestrictions.Builder#setMaxStringLength(int):
+    Missing nullability on method `setMaxStringLength` return
+MissingNullability: android.car.drivingstate.CarUxRestrictionsManager.OnUxRestrictionsChangedListener#onUxRestrictionsChanged(android.car.drivingstate.CarUxRestrictions) parameter #0:
+    Missing nullability on parameter `restrictionInfo` in method `onUxRestrictionsChanged`
+MissingNullability: android.car.hardware.CarPropertyConfig#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.hardware.CarPropertyConfig`
+MissingNullability: android.car.hardware.CarPropertyConfig#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
+MissingNullability: android.car.hardware.CarPropertyValue#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.hardware.CarPropertyValue`
+MissingNullability: android.car.hardware.CarPropertyValue#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
+MissingNullability: android.car.hardware.CarSensorEvent#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.hardware.CarSensorEvent`
+MissingNullability: android.car.hardware.CarSensorEvent#floatValues:
+    Missing nullability on field `floatValues` in class `class android.car.hardware.CarSensorEvent`
+MissingNullability: android.car.hardware.CarSensorEvent#intValues:
+    Missing nullability on field `intValues` in class `class android.car.hardware.CarSensorEvent`
+MissingNullability: android.car.hardware.CarSensorEvent#longValues:
+    Missing nullability on field `longValues` in class `class android.car.hardware.CarSensorEvent`
+MissingNullability: android.car.hardware.CarSensorEvent#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
+MissingNullability: android.car.hardware.CarSensorManager.OnSensorChangedListener#onSensorChanged(android.car.hardware.CarSensorEvent) parameter #0:
+    Missing nullability on parameter `event` in method `onSensorChanged`
+MissingNullability: android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback#onChangeEvent(android.car.hardware.CarPropertyValue) parameter #0:
+    Missing nullability on parameter `value` in method `onChangeEvent`
+MissingNullability: android.car.settings.CarConfigurationManager#getSpeedBumpConfiguration():
+    Missing nullability on method `getSpeedBumpConfiguration` return
+MissingNullability: android.car.settings.SpeedBumpConfiguration#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.settings.SpeedBumpConfiguration`
+MissingNullability: android.car.settings.SpeedBumpConfiguration#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `desk` in method `writeToParcel`
+
+
+MutableBareField: android.car.CarOccupantZoneManager.OccupantZoneInfo#zoneId:
+    Bare field zoneId must be marked final, or moved behind accessors if mutable
+MutableBareField: android.car.hardware.CarSensorEvent#sensorType:
+    Bare field sensorType must be marked final, or moved behind accessors if mutable
+MutableBareField: android.car.hardware.CarSensorEvent#timestamp:
+    Bare field timestamp must be marked final, or moved behind accessors if mutable
+MutableBareField: android.car.hardware.CarSensorEvent.EnvironmentData#temperature:
+    Bare field temperature must be marked final, or moved behind accessors if mutable
+MutableBareField: android.car.hardware.CarSensorEvent.EnvironmentData#timestamp:
+    Bare field timestamp must be marked final, or moved behind accessors if mutable
+
+
+NotCloseable: android.car.Car:
+    Classes that release resources (disconnect()) should implement AutoClosable and CloseGuard: class android.car.Car
+
+
+PublicTypedef: android.car.drivingstate.CarUxRestrictions.CarUxRestrictionsInfo:
+    Don't expose @IntDef: CarUxRestrictionsInfo must be hidden.
+PublicTypedef: android.car.hardware.CarPropertyValue.PropertyStatus:
+    Don't expose @IntDef: PropertyStatus must be hidden.
+
+
+RegistrationName: android.car.CarOccupantZoneManager#registerOccupantZoneConfigChangeListener(android.car.CarOccupantZoneManager.OccupantZoneConfigChangeListener):
+    Listener methods should be named add/remove; was registerOccupantZoneConfigChangeListener
+RegistrationName: android.car.CarOccupantZoneManager#unregisterOccupantZoneConfigChangeListener(android.car.CarOccupantZoneManager.OccupantZoneConfigChangeListener):
+    Listener methods should be named add/remove; was unregisterOccupantZoneConfigChangeListener
+RegistrationName: android.car.drivingstate.CarUxRestrictionsManager#registerListener(android.car.drivingstate.CarUxRestrictionsManager.OnUxRestrictionsChangedListener):
+    Listener methods should be named add/remove; was registerListener
+RegistrationName: android.car.drivingstate.CarUxRestrictionsManager#unregisterListener():
+    Listener methods should be named add/remove; was unregisterListener
+RegistrationName: android.car.hardware.CarSensorManager#registerListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int, int):
+    Listener methods should be named add/remove; was registerListener
+RegistrationName: android.car.hardware.CarSensorManager#unregisterListener(android.car.hardware.CarSensorManager.OnSensorChangedListener):
+    Listener methods should be named add/remove; was unregisterListener
+RegistrationName: android.car.hardware.CarSensorManager#unregisterListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int):
+    Listener methods should be named add/remove; was unregisterListener
+
+
+SamShouldBeLast: android.car.CarAppFocusManager#addFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener, int):
+    SAM-compatible parameters (such as parameter 1, "listener", in android.car.CarAppFocusManager.addFocusListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.car.CarAppFocusManager#removeFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener, int):
+    SAM-compatible parameters (such as parameter 1, "listener", in android.car.CarAppFocusManager.removeFocusListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.car.hardware.CarSensorManager#registerListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int, int):
+    SAM-compatible parameters (such as parameter 1, "listener", in android.car.hardware.CarSensorManager.registerListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.car.hardware.CarSensorManager#unregisterListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int):
+    SAM-compatible parameters (such as parameter 1, "listener", in android.car.hardware.CarSensorManager.unregisterListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+
+
+ServiceName: android.car.Car#CAR_CONFIGURATION_SERVICE:
+    Inconsistent service value; expected `CAR_CONFIGURATION`, was `configuration`
+ServiceName: android.car.Car#CAR_NAVIGATION_SERVICE:
+    Inconsistent service value; expected `CAR_NAVIGATION`, was `car_navigation_service`
+ServiceName: android.car.Car#CAR_OCCUPANT_ZONE_SERVICE:
+    Inconsistent service value; expected `CAR_OCCUPANT_ZONE`, was `car_occupant_zone_service`
+ServiceName: android.car.Car#CAR_UX_RESTRICTION_SERVICE:
+    Inconsistent service value; expected `CAR_UX_RESTRICTION`, was `uxrestriction`
+
+
+StaticUtils: android.car.VehiclePropertyIds:
+    Fully-static utility classes must not have constructor
+StaticUtils: android.car.settings.CarSettings.Global:
+    Fully-static utility classes must not have constructor
+
+
+VisiblySynchronized: PsiThisExpression:this:
+    Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.car.CarAppFocusManager.addFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener,int)
+VisiblySynchronized: android.car.CarAppFocusManager#abandonAppFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback):
+    Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.car.CarAppFocusManager.abandonAppFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback)
+VisiblySynchronized: android.car.CarAppFocusManager#abandonAppFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback, int):
+    Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.car.CarAppFocusManager.abandonAppFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback,int)
+VisiblySynchronized: android.car.CarAppFocusManager#addFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener, int):
+    Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.car.CarAppFocusManager.addFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener,int)
+VisiblySynchronized: android.car.CarAppFocusManager#isOwningFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback, int):
+    Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.car.CarAppFocusManager.isOwningFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback,int)
+VisiblySynchronized: android.car.CarAppFocusManager#removeFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener):
+    Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.car.CarAppFocusManager.removeFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener)
+VisiblySynchronized: android.car.CarAppFocusManager#removeFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener, int):
+    Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.car.CarAppFocusManager.removeFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener,int)
+VisiblySynchronized: android.car.CarAppFocusManager#requestAppFocus(int, android.car.CarAppFocusManager.OnAppFocusOwnershipCallback):
+    Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.car.CarAppFocusManager.requestAppFocus(int,android.car.CarAppFocusManager.OnAppFocusOwnershipCallback)
+VisiblySynchronized: android.car.drivingstate.CarUxRestrictionsManager#unregisterListener():
+    Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.car.drivingstate.CarUxRestrictionsManager.unregisterListener()
diff --git a/car-lib/api/removed.txt b/car-lib/api/removed.txt
index d802177..b14f0a6 100644
--- a/car-lib/api/removed.txt
+++ b/car-lib/api/removed.txt
@@ -1 +1,9 @@
 // Signature format: 2.0
+package android.car {
+
+  public final class Car {
+    field @Deprecated public static final String CAR_EXTRA_MEDIA_PACKAGE = "android.car.intent.extra.MEDIA_PACKAGE";
+  }
+
+}
+
diff --git a/car-lib/api/system-current.txt b/car-lib/api/system-current.txt
index a32ffba..c404acd 100644
--- a/car-lib/api/system-current.txt
+++ b/car-lib/api/system-current.txt
@@ -12,12 +12,26 @@
   }
 
   public final class Car {
+    method @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_FEATURES) public int disableFeature(@NonNull String);
+    method @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_FEATURES) public int enableFeature(@NonNull String);
+    method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_FEATURES) public java.util.List<java.lang.String> getAllEnabledFeatures();
+    method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_FEATURES) public java.util.List<java.lang.String> getAllPendingDisabledFeatures();
+    method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_FEATURES) public java.util.List<java.lang.String> getAllPendingEnabledFeatures();
     field @Deprecated public static final String CABIN_SERVICE = "cabin";
     field public static final String CAR_DRIVING_STATE_SERVICE = "drivingstate";
     field public static final String CAR_EXTRA_CLUSTER_ACTIVITY_STATE = "android.car.cluster.ClusterActivityState";
+    field public static final String CAR_MEDIA_SERVICE = "car_media";
     field public static final String CAR_TRUST_AGENT_ENROLLMENT_SERVICE = "trust_enroll";
+    field public static final String CAR_USER_SERVICE = "car_user_service";
+    field public static final String CAR_WATCHDOG_SERVICE = "car_watchdog";
     field public static final String DIAGNOSTIC_SERVICE = "diagnostic";
+    field public static final int FEATURE_REQUEST_ALREADY_IN_THE_STATE = 1; // 0x1
+    field public static final int FEATURE_REQUEST_MANDATORY = 2; // 0x2
+    field public static final int FEATURE_REQUEST_NOT_EXISTING = 3; // 0x3
+    field public static final int FEATURE_REQUEST_SUCCESS = 0; // 0x0
     field @Deprecated public static final String HVAC_SERVICE = "hvac";
+    field public static final String OCCUPANT_AWARENESS_SERVICE = "occupant_awareness";
+    field public static final String PERMISSION_ADJUST_RANGE_REMAINING = "android.car.permission.ADJUST_RANGE_REMAINING";
     field public static final String PERMISSION_CAR_DIAGNOSTIC_CLEAR = "android.car.permission.CLEAR_CAR_DIAGNOSTICS";
     field public static final String PERMISSION_CAR_DIAGNOSTIC_READ_ALL = "android.car.permission.CAR_DIAGNOSTICS";
     field public static final String PERMISSION_CAR_DRIVING_STATE = "android.car.permission.CAR_DRIVING_STATE";
@@ -32,16 +46,22 @@
     field public static final String PERMISSION_CONTROL_APP_BLOCKING = "android.car.permission.CONTROL_APP_BLOCKING";
     field public static final String PERMISSION_CONTROL_CAR_CLIMATE = "android.car.permission.CONTROL_CAR_CLIMATE";
     field public static final String PERMISSION_CONTROL_CAR_DOORS = "android.car.permission.CONTROL_CAR_DOORS";
+    field public static final String PERMISSION_CONTROL_CAR_FEATURES = "android.car.permission.CONTROL_CAR_FEATURES";
     field public static final String PERMISSION_CONTROL_CAR_MIRRORS = "android.car.permission.CONTROL_CAR_MIRRORS";
+    field public static final String PERMISSION_CONTROL_CAR_OCCUPANT_AWARENESS_SYSTEM = "android.car.permission.CONTROL_CAR_OCCUPANT_AWARENESS_SYSTEM";
     field public static final String PERMISSION_CONTROL_CAR_SEATS = "android.car.permission.CONTROL_CAR_SEATS";
     field public static final String PERMISSION_CONTROL_CAR_WINDOWS = "android.car.permission.CONTROL_CAR_WINDOWS";
+    field public static final String PERMISSION_CONTROL_ENERGY_PORTS = "android.car.permission.CONTROL_CAR_ENERGY_PORTS";
     field public static final String PERMISSION_CONTROL_EXTERIOR_LIGHTS = "android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS";
     field public static final String PERMISSION_EXTERIOR_LIGHTS = "android.car.permission.CAR_EXTERIOR_LIGHTS";
     field public static final String PERMISSION_MILEAGE = "android.car.permission.CAR_MILEAGE";
     field @Deprecated public static final String PERMISSION_MOCK_VEHICLE_HAL = "android.car.permission.CAR_MOCK_VEHICLE_HAL";
+    field public static final String PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE = "android.car.permission.READ_CAR_OCCUPANT_AWARENESS_STATE";
+    field public static final String PERMISSION_READ_CAR_VENDOR_PERMISSION_INFO = "android.car.permission.READ_CAR_VENDOR_PERMISSION_INFO";
     field public static final String PERMISSION_RECEIVE_CAR_AUDIO_DUCKING_EVENTS = "android.car.permission.RECEIVE_CAR_AUDIO_DUCKING_EVENTS";
     field public static final String PERMISSION_STORAGE_MONITORING = "android.car.permission.STORAGE_MONITORING";
     field public static final String PERMISSION_TIRES = "android.car.permission.CAR_TIRES";
+    field public static final String PERMISSION_USE_CAR_WATCHDOG = "android.car.permission.USE_CAR_WATCHDOG";
     field public static final String PERMISSION_VENDOR_EXTENSION = "android.car.permission.CAR_VENDOR_EXTENSION";
     field public static final String PERMISSION_VMS_PUBLISHER = "android.car.permission.VMS_PUBLISHER";
     field public static final String PERMISSION_VMS_SUBSCRIBER = "android.car.permission.VMS_SUBSCRIBER";
@@ -49,15 +69,21 @@
     field public static final String PROJECTION_SERVICE = "projection";
     field public static final String STORAGE_MONITORING_SERVICE = "storage_monitoring";
     field public static final String TEST_SERVICE = "car-service-test";
+    field public static final String VEHICLE_MAP_SERVICE = "vehicle_map_service";
     field @Deprecated public static final String VENDOR_EXTENSION_SERVICE = "vendor_extension";
-    field public static final String VMS_SUBSCRIBER_SERVICE = "vehicle_map_subscriber_service";
+    field @Deprecated public static final String VMS_SUBSCRIBER_SERVICE = "vehicle_map_subscriber_service";
+  }
+
+  public class CarOccupantZoneManager {
+    method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public int getAudioZoneIdForOccupant(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+    method @Nullable @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public android.car.CarOccupantZoneManager.OccupantZoneInfo getOccupantForAudioZoneId(int);
   }
 
   public final class CarProjectionManager {
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public void addKeyEventHandler(@NonNull java.util.Set<java.lang.Integer>, @NonNull android.car.CarProjectionManager.ProjectionKeyEventHandler);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public void addKeyEventHandler(@NonNull java.util.Set<java.lang.Integer>, @Nullable java.util.concurrent.Executor, @NonNull android.car.CarProjectionManager.ProjectionKeyEventHandler);
-    method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) @NonNull public java.util.List<java.lang.Integer> getAvailableWifiChannels(int);
-    method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) @NonNull public android.os.Bundle getProjectionOptions();
+    method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public java.util.List<java.lang.Integer> getAvailableWifiChannels(int);
+    method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public android.os.Bundle getProjectionOptions();
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public void registerProjectionListener(@NonNull android.car.CarProjectionManager.CarProjectionListener, int);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public void registerProjectionRunner(@NonNull android.content.Intent);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION_STATUS) public void registerProjectionStatusListener(@NonNull android.car.CarProjectionManager.ProjectionStatusListener);
@@ -89,7 +115,8 @@
   public abstract static class CarProjectionManager.ProjectionAccessPointCallback {
     ctor public CarProjectionManager.ProjectionAccessPointCallback();
     method public void onFailed(int);
-    method public void onStarted(android.net.wifi.WifiConfiguration);
+    method @Deprecated public void onStarted(@Nullable android.net.wifi.WifiConfiguration);
+    method public void onStarted(@NonNull android.net.wifi.SoftApConfiguration);
     method public void onStopped();
     field public static final int ERROR_GENERIC = 2; // 0x2
     field public static final int ERROR_INCOMPATIBLE_MODE = 3; // 0x3
@@ -122,14 +149,6 @@
     field public static final int MIRROR_DRIVER_RIGHT = 2; // 0x2
   }
 
-  public final class VehicleAreaWheel {
-    field public static final int WHEEL_LEFT_FRONT = 1; // 0x1
-    field public static final int WHEEL_LEFT_REAR = 4; // 0x4
-    field public static final int WHEEL_RIGHT_FRONT = 2; // 0x2
-    field public static final int WHEEL_RIGHT_REAR = 8; // 0x8
-    field public static final int WHEEL_UNKNOWN = 0; // 0x0
-  }
-
   public final class VehicleAreaWindow {
     field public static final int WINDOW_FRONT_WINDSHIELD = 1; // 0x1
     field public static final int WINDOW_REAR_WINDSHIELD = 2; // 0x2
@@ -214,19 +233,22 @@
 
   public abstract class InstrumentClusterRenderingService extends android.app.Service {
     ctor public InstrumentClusterRenderingService();
-    method @Nullable public android.graphics.Bitmap getBitmap(android.net.Uri);
+    method @Deprecated @Nullable public android.graphics.Bitmap getBitmap(android.net.Uri);
+    method @Nullable public android.graphics.Bitmap getBitmap(@NonNull android.net.Uri, int, int);
+    method @Nullable public android.graphics.Bitmap getBitmap(@NonNull android.net.Uri, int, int, float);
     method @MainThread @Nullable public abstract android.car.cluster.renderer.NavigationRenderer getNavigationRenderer();
     method @CallSuper public android.os.IBinder onBind(android.content.Intent);
     method @MainThread public void onKeyEvent(@NonNull android.view.KeyEvent);
     method @MainThread public void onNavigationComponentLaunched();
     method @MainThread public void onNavigationComponentReleased();
+    method public boolean startFixedActivityModeForDisplayAndUser(@NonNull android.content.Intent, @NonNull android.app.ActivityOptions, int);
     method protected boolean startNavigationActivity(@NonNull android.content.ComponentName);
+    method public void stopFixedActivityMode(int);
   }
 
   @UiThread public abstract class NavigationRenderer {
     ctor public NavigationRenderer();
     method public abstract android.car.navigation.CarNavigationInstrumentCluster getNavigationProperties();
-    method @Deprecated public void onEvent(int, android.os.Bundle);
     method public void onNavigationStateChanged(@Nullable android.os.Bundle);
   }
 
@@ -282,10 +304,10 @@
   public final class CarDiagnosticEvent implements android.os.Parcelable {
     ctor public CarDiagnosticEvent(android.os.Parcel);
     method public int describeContents();
-    method @Nullable @android.car.diagnostic.CarDiagnosticEvent.FuelSystemStatus.Status public Integer getFuelSystemStatus();
-    method @Nullable @android.car.diagnostic.CarDiagnosticEvent.FuelType.Type public Integer getFuelType();
+    method @android.car.diagnostic.CarDiagnosticEvent.FuelSystemStatus.Status @Nullable public Integer getFuelSystemStatus();
+    method @android.car.diagnostic.CarDiagnosticEvent.FuelType.Type @Nullable public Integer getFuelType();
     method @Nullable public android.car.diagnostic.CarDiagnosticEvent.CommonIgnitionMonitors getIgnitionMonitors();
-    method @Nullable @android.car.diagnostic.CarDiagnosticEvent.SecondaryAirStatus.Status public Integer getSecondaryAirStatus();
+    method @android.car.diagnostic.CarDiagnosticEvent.SecondaryAirStatus.Status @Nullable public Integer getSecondaryAirStatus();
     method public float getSystemFloatSensor(int, float);
     method @Nullable public Float getSystemFloatSensor(int);
     method public int getSystemIntegerSensor(int, int);
@@ -343,7 +365,7 @@
     field public static final int OPEN_SYSTEM_FAILURE = 8; // 0x8
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.car.diagnostic.CarDiagnosticEvent.FuelSystemStatus.OPEN_INSUFFICIENT_ENGINE_TEMPERATURE, android.car.diagnostic.CarDiagnosticEvent.FuelSystemStatus.CLOSED_LOOP, android.car.diagnostic.CarDiagnosticEvent.FuelSystemStatus.OPEN_ENGINE_LOAD_OR_DECELERATION, android.car.diagnostic.CarDiagnosticEvent.FuelSystemStatus.OPEN_SYSTEM_FAILURE, android.car.diagnostic.CarDiagnosticEvent.FuelSystemStatus.CLOSED_LOOP_BUT_FEEDBACK_FAULT}) public static @interface CarDiagnosticEvent.FuelSystemStatus.Status {
+  @IntDef({android.car.diagnostic.CarDiagnosticEvent.FuelSystemStatus.OPEN_INSUFFICIENT_ENGINE_TEMPERATURE, android.car.diagnostic.CarDiagnosticEvent.FuelSystemStatus.CLOSED_LOOP, android.car.diagnostic.CarDiagnosticEvent.FuelSystemStatus.OPEN_ENGINE_LOAD_OR_DECELERATION, android.car.diagnostic.CarDiagnosticEvent.FuelSystemStatus.OPEN_SYSTEM_FAILURE, android.car.diagnostic.CarDiagnosticEvent.FuelSystemStatus.CLOSED_LOOP_BUT_FEEDBACK_FAULT}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface CarDiagnosticEvent.FuelSystemStatus.Status {
   }
 
   public static final class CarDiagnosticEvent.FuelType {
@@ -373,7 +395,7 @@
     field public static final int PROPANE = 7; // 0x7
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.car.diagnostic.CarDiagnosticEvent.FuelType.NOT_AVAILABLE, android.car.diagnostic.CarDiagnosticEvent.FuelType.GASOLINE, android.car.diagnostic.CarDiagnosticEvent.FuelType.METHANOL, android.car.diagnostic.CarDiagnosticEvent.FuelType.ETHANOL, android.car.diagnostic.CarDiagnosticEvent.FuelType.DIESEL, android.car.diagnostic.CarDiagnosticEvent.FuelType.LPG, android.car.diagnostic.CarDiagnosticEvent.FuelType.CNG, android.car.diagnostic.CarDiagnosticEvent.FuelType.PROPANE, android.car.diagnostic.CarDiagnosticEvent.FuelType.ELECTRIC, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_GASOLINE, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_METHANOL, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_ETHANOL, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_LPG, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_CNG, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_PROPANE, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_ELECTRIC, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_ELECTRIC_AND_COMBUSTION, android.car.diagnostic.CarDiagnosticEvent.FuelType.HYBRID_GASOLINE, android.car.diagnostic.CarDiagnosticEvent.FuelType.HYBRID_ETHANOL, android.car.diagnostic.CarDiagnosticEvent.FuelType.HYBRID_DIESEL, android.car.diagnostic.CarDiagnosticEvent.FuelType.HYBRID_ELECTRIC, android.car.diagnostic.CarDiagnosticEvent.FuelType.HYBRID_RUNNING_ELECTRIC_AND_COMBUSTION, android.car.diagnostic.CarDiagnosticEvent.FuelType.HYBRID_REGENERATIVE, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_DIESEL}) public static @interface CarDiagnosticEvent.FuelType.Type {
+  @IntDef({android.car.diagnostic.CarDiagnosticEvent.FuelType.NOT_AVAILABLE, android.car.diagnostic.CarDiagnosticEvent.FuelType.GASOLINE, android.car.diagnostic.CarDiagnosticEvent.FuelType.METHANOL, android.car.diagnostic.CarDiagnosticEvent.FuelType.ETHANOL, android.car.diagnostic.CarDiagnosticEvent.FuelType.DIESEL, android.car.diagnostic.CarDiagnosticEvent.FuelType.LPG, android.car.diagnostic.CarDiagnosticEvent.FuelType.CNG, android.car.diagnostic.CarDiagnosticEvent.FuelType.PROPANE, android.car.diagnostic.CarDiagnosticEvent.FuelType.ELECTRIC, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_GASOLINE, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_METHANOL, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_ETHANOL, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_LPG, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_CNG, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_PROPANE, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_ELECTRIC, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_ELECTRIC_AND_COMBUSTION, android.car.diagnostic.CarDiagnosticEvent.FuelType.HYBRID_GASOLINE, android.car.diagnostic.CarDiagnosticEvent.FuelType.HYBRID_ETHANOL, android.car.diagnostic.CarDiagnosticEvent.FuelType.HYBRID_DIESEL, android.car.diagnostic.CarDiagnosticEvent.FuelType.HYBRID_ELECTRIC, android.car.diagnostic.CarDiagnosticEvent.FuelType.HYBRID_RUNNING_ELECTRIC_AND_COMBUSTION, android.car.diagnostic.CarDiagnosticEvent.FuelType.HYBRID_REGENERATIVE, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_DIESEL}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface CarDiagnosticEvent.FuelType.Type {
   }
 
   public static final class CarDiagnosticEvent.IgnitionMonitor {
@@ -388,7 +410,7 @@
     field public static final int UPSTREAM = 1; // 0x1
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.car.diagnostic.CarDiagnosticEvent.SecondaryAirStatus.UPSTREAM, android.car.diagnostic.CarDiagnosticEvent.SecondaryAirStatus.DOWNSTREAM_OF_CATALYCIC_CONVERTER, android.car.diagnostic.CarDiagnosticEvent.SecondaryAirStatus.FROM_OUTSIDE_OR_OFF, android.car.diagnostic.CarDiagnosticEvent.SecondaryAirStatus.PUMP_ON_FOR_DIAGNOSTICS}) public static @interface CarDiagnosticEvent.SecondaryAirStatus.Status {
+  @IntDef({android.car.diagnostic.CarDiagnosticEvent.SecondaryAirStatus.UPSTREAM, android.car.diagnostic.CarDiagnosticEvent.SecondaryAirStatus.DOWNSTREAM_OF_CATALYCIC_CONVERTER, android.car.diagnostic.CarDiagnosticEvent.SecondaryAirStatus.FROM_OUTSIDE_OR_OFF, android.car.diagnostic.CarDiagnosticEvent.SecondaryAirStatus.PUMP_ON_FOR_DIAGNOSTICS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface CarDiagnosticEvent.SecondaryAirStatus.Status {
   }
 
   public static final class CarDiagnosticEvent.SparkIgnitionMonitors extends android.car.diagnostic.CarDiagnosticEvent.CommonIgnitionMonitors {
@@ -419,7 +441,7 @@
     field public static final int FRAME_TYPE_LIVE = 0; // 0x0
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.car.diagnostic.CarDiagnosticManager.FRAME_TYPE_LIVE, android.car.diagnostic.CarDiagnosticManager.FRAME_TYPE_FREEZE}) public static @interface CarDiagnosticManager.FrameType {
+  @IntDef({android.car.diagnostic.CarDiagnosticManager.FRAME_TYPE_LIVE, android.car.diagnostic.CarDiagnosticManager.FRAME_TYPE_FREEZE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface CarDiagnosticManager.FrameType {
   }
 
   public static interface CarDiagnosticManager.OnDiagnosticEventListener {
@@ -570,8 +592,16 @@
 
 package android.car.hardware {
 
+  public final class CarHvacFanDirection {
+    field public static final int DEFROST = 4; // 0x4
+    field public static final int DEFROST_AND_FLOOR = 6; // 0x6
+    field public static final int FACE = 1; // 0x1
+    field public static final int FACE_AND_FLOOR = 3; // 0x3
+    field public static final int FLOOR = 2; // 0x2
+    field public static final int UNKNOWN = 0; // 0x0
+  }
+
   public final class CarPropertyConfig<T> implements android.os.Parcelable {
-    method @NonNull public Class<T> getPropertyType();
     method public static <T> android.car.hardware.CarPropertyConfig.Builder<T> newBuilder(Class<T>, int, int, int);
   }
 
@@ -722,6 +752,49 @@
 
 }
 
+package android.car.hardware.property {
+
+  public final class VehicleVendorPermission {
+    field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_1 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_1";
+    field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_10 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_10";
+    field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_2 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_2";
+    field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_3 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_3";
+    field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_4 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_4";
+    field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_5 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_5";
+    field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_6 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_6";
+    field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_7 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_7";
+    field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_8 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_8";
+    field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_9 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_9";
+    field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_DOOR = "android.car.permission.GET_CAR_VENDOR_CATEGORY_DOOR";
+    field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_ENGINE = "android.car.permission.GET_CAR_VENDOR_CATEGORY_ENGINE";
+    field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_HVAC = "android.car.permission.GET_CAR_VENDOR_CATEGORY_HVAC";
+    field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_INFO = "android.car.permission.GET_CAR_VENDOR_CATEGORY_INFO";
+    field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_LIGHT = "android.car.permission.GET_CAR_VENDOR_CATEGORY_LIGHT";
+    field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_MIRROR = "android.car.permission.GET_CAR_VENDOR_CATEGORY_MIRROR";
+    field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_SEAT = "android.car.permission.GET_CAR_VENDOR_CATEGORY_SEAT";
+    field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_WINDOW = "android.car.permission.GET_CAR_VENDOR_CATEGORY_WINDOW";
+    field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_1 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_1";
+    field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_10 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_10";
+    field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_2 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_2";
+    field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_3 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_3";
+    field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_4 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_4";
+    field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_5 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_5";
+    field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_6 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_6";
+    field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_7 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_7";
+    field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_8 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_8";
+    field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_9 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_9";
+    field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_DOOR = "android.car.permission.SET_CAR_VENDOR_CATEGORY_DOOR";
+    field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_ENGINE = "android.car.permission.SET_CAR_VENDOR_CATEGORY_ENGINE";
+    field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_HVAC = "android.car.permission.SET_CAR_VENDOR_CATEGORY_HVAC";
+    field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_INFO = "android.car.permission.SET_CAR_VENDOR_CATEGORY_INFO";
+    field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_LIGHT = "android.car.permission.SET_CAR_VENDOR_CATEGORY_LIGHT";
+    field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_MIRROR = "android.car.permission.SET_CAR_VENDOR_CATEGORY_MIRROR";
+    field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_SEAT = "android.car.permission.SET_CAR_VENDOR_CATEGORY_SEAT";
+    field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_WINDOW = "android.car.permission.SET_CAR_VENDOR_CATEGORY_WINDOW";
+  }
+
+}
+
 package android.car.input {
 
   public abstract class CarInputHandlingService extends android.app.Service {
@@ -747,6 +820,7 @@
 
   public final class CarAudioManager {
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public android.car.media.CarAudioPatchHandle createAudioPatch(String, int, int);
+    method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public java.util.List<java.lang.Integer> getAudioZoneIds();
     method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public String[] getExternalSources();
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getGroupMaxVolume(int);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getGroupMaxVolume(int, int);
@@ -754,6 +828,8 @@
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getGroupMinVolume(int, int);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getGroupVolume(int);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getGroupVolume(int, int);
+    method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public java.util.List<android.media.AudioDeviceInfo> getInputDevicesForZoneId(int);
+    method @Nullable @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public android.media.AudioDeviceInfo getOutputDeviceForUsage(int, int);
     method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int[] getUsagesForVolumeGroupId(int);
     method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int[] getUsagesForVolumeGroupId(int, int);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getVolumeGroupCount();
@@ -766,16 +842,30 @@
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public void setGroupVolume(int, int, int);
     method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public void setGroupVolume(int, int, int, int);
     field public static final String AUDIOFOCUS_EXTRA_RECEIVE_DUCKING_EVENTS = "android.car.media.AUDIOFOCUS_EXTRA_RECEIVE_DUCKING_EVENTS";
+    field public static final int INVALID_AUDIO_ZONE = -1; // 0xffffffff
     field public static final int PRIMARY_AUDIO_ZONE = 0; // 0x0
   }
 
   public final class CarAudioPatchHandle implements android.os.Parcelable {
-    ctor public CarAudioPatchHandle(android.media.AudioPatch);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.car.media.CarAudioPatchHandle> CREATOR;
   }
 
+  public final class CarMediaManager {
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void addMediaSourceListener(@NonNull android.car.media.CarMediaManager.MediaSourceChangedListener, int);
+    method @NonNull @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public java.util.List<android.content.ComponentName> getLastMediaSources(int);
+    method @NonNull @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public android.content.ComponentName getMediaSource(int);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void removeMediaSourceListener(@NonNull android.car.media.CarMediaManager.MediaSourceChangedListener, int);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void setMediaSource(@NonNull android.content.ComponentName, int);
+    field public static final int MEDIA_SOURCE_MODE_BROWSE = 1; // 0x1
+    field public static final int MEDIA_SOURCE_MODE_PLAYBACK = 0; // 0x0
+  }
+
+  public static interface CarMediaManager.MediaSourceChangedListener {
+    method public void onMediaSourceChanged(@NonNull android.content.ComponentName);
+  }
+
 }
 
 package android.car.navigation {
@@ -865,6 +955,17 @@
 
 }
 
+package android.car.settings {
+
+  public class CarSettings {
+  }
+
+  public static final class CarSettings.Secure {
+    field public static final String KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL = "android.car.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL";
+  }
+
+}
+
 package android.car.storagemonitoring {
 
   public final class CarStorageMonitoringManager {
@@ -983,50 +1084,75 @@
 
 package android.car.trust {
 
-  public final class CarTrustAgentEnrollmentManager {
-    method @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public void enrollmentHandshakeAccepted(android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) @NonNull public java.util.List<android.car.trust.TrustedDeviceInfo> getEnrolledDeviceInfoForUser(int);
-    method @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public boolean isEscrowTokenActive(long, int);
-    method @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public void removeAllTrustedDevices(int);
-    method @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public void removeEscrowToken(long, int);
-    method @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public void setBleCallback(@Nullable android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentBleCallback);
-    method @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public void setEnrollmentCallback(@Nullable android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentEnrollmentCallback);
-    method @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public void setTrustedDeviceEnrollmentEnabled(boolean);
-    method @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public void setTrustedDeviceUnlockEnabled(boolean);
-    method @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public void startEnrollmentAdvertising();
-    method @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public void stopEnrollmentAdvertising();
-    method @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public void terminateEnrollmentHandshake();
-    field public static final int ENROLLMENT_HANDSHAKE_FAILURE = 1; // 0x1
-    field public static final int ENROLLMENT_NOT_ALLOWED = 2; // 0x2
+  @Deprecated public final class CarTrustAgentEnrollmentManager {
+    method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public void enrollmentHandshakeAccepted(android.bluetooth.BluetoothDevice);
+    method @Deprecated @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public java.util.List<android.car.trust.TrustedDeviceInfo> getEnrolledDeviceInfoForUser(int);
+    method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public boolean isEscrowTokenActive(long, int);
+    method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public void removeAllTrustedDevices(int);
+    method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public void removeEscrowToken(long, int);
+    method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public void setBleCallback(@Nullable android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentBleCallback);
+    method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public void setEnrollmentCallback(@Nullable android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentEnrollmentCallback);
+    method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public void setTrustedDeviceEnrollmentEnabled(boolean);
+    method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public void setTrustedDeviceUnlockEnabled(boolean);
+    method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public void startEnrollmentAdvertising();
+    method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public void stopEnrollmentAdvertising();
+    method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_CAR_ENROLL_TRUST) public void terminateEnrollmentHandshake();
+    field @Deprecated public static final int ENROLLMENT_HANDSHAKE_FAILURE = 1; // 0x1
+    field @Deprecated public static final int ENROLLMENT_NOT_ALLOWED = 2; // 0x2
   }
 
-  public static interface CarTrustAgentEnrollmentManager.CarTrustAgentBleCallback {
-    method public void onBleEnrollmentDeviceConnected(android.bluetooth.BluetoothDevice);
-    method public void onBleEnrollmentDeviceDisconnected(android.bluetooth.BluetoothDevice);
-    method public void onEnrollmentAdvertisingFailed();
-    method public void onEnrollmentAdvertisingStarted();
+  @Deprecated public static interface CarTrustAgentEnrollmentManager.CarTrustAgentBleCallback {
+    method @Deprecated public void onBleEnrollmentDeviceConnected(android.bluetooth.BluetoothDevice);
+    method @Deprecated public void onBleEnrollmentDeviceDisconnected(android.bluetooth.BluetoothDevice);
+    method @Deprecated public void onEnrollmentAdvertisingFailed();
+    method @Deprecated public void onEnrollmentAdvertisingStarted();
   }
 
-  public static interface CarTrustAgentEnrollmentManager.CarTrustAgentEnrollmentCallback {
-    method public void onAuthStringAvailable(android.bluetooth.BluetoothDevice, String);
-    method public void onEnrollmentHandshakeFailure(@Nullable android.bluetooth.BluetoothDevice, int);
-    method public void onEscrowTokenActiveStateChanged(long, boolean);
-    method public void onEscrowTokenAdded(long);
-    method public void onEscrowTokenRemoved(long);
+  @Deprecated public static interface CarTrustAgentEnrollmentManager.CarTrustAgentEnrollmentCallback {
+    method @Deprecated public void onAuthStringAvailable(android.bluetooth.BluetoothDevice, String);
+    method @Deprecated public void onEnrollmentHandshakeFailure(@Nullable android.bluetooth.BluetoothDevice, int);
+    method @Deprecated public void onEscrowTokenActiveStateChanged(long, boolean);
+    method @Deprecated public void onEscrowTokenAdded(long);
+    method @Deprecated public void onEscrowTokenRemoved(long);
   }
 
-  public final class TrustedDeviceInfo implements android.os.Parcelable {
-    ctor public TrustedDeviceInfo(long, @NonNull String, @NonNull String);
-    ctor public TrustedDeviceInfo(android.os.Parcel);
-    method public int describeContents();
-    method public static android.car.trust.TrustedDeviceInfo deserialize(String);
-    method @NonNull public String getAddress();
-    method public long getHandle();
-    method @NonNull public String getName();
-    method public String serialize();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-    field public static final String DEFAULT_NAME = "Default";
+  @Deprecated public final class TrustedDeviceInfo implements android.os.Parcelable {
+    ctor @Deprecated public TrustedDeviceInfo(long, @NonNull String, @NonNull String);
+    ctor @Deprecated public TrustedDeviceInfo(android.os.Parcel);
+    method @Deprecated public int describeContents();
+    method @Deprecated public static android.car.trust.TrustedDeviceInfo deserialize(String);
+    method @Deprecated @NonNull public String getAddress();
+    method @Deprecated public long getHandle();
+    method @Deprecated @NonNull public String getName();
+    method @Deprecated public String serialize();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final android.os.Parcelable.Creator CREATOR;
+    field @Deprecated public static final String DEFAULT_NAME = "Default";
+  }
+
+}
+
+package android.car.user {
+
+  public final class CarUserManager {
+    method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void addListener(@NonNull java.util.concurrent.Executor, @NonNull android.car.user.CarUserManager.UserLifecycleListener);
+    method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void removeListener(@NonNull android.car.user.CarUserManager.UserLifecycleListener);
+    field public static final int USER_LIFECYCLE_EVENT_TYPE_STARTING = 1; // 0x1
+    field public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPED = 6; // 0x6
+    field public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPING = 5; // 0x5
+    field public static final int USER_LIFECYCLE_EVENT_TYPE_SWITCHING = 2; // 0x2
+    field public static final int USER_LIFECYCLE_EVENT_TYPE_UNLOCKED = 4; // 0x4
+    field public static final int USER_LIFECYCLE_EVENT_TYPE_UNLOCKING = 3; // 0x3
+  }
+
+  public static final class CarUserManager.UserLifecycleEvent {
+    method public int getEventType();
+    method @Nullable public android.os.UserHandle getPreviousUserHandle();
+    method @NonNull public android.os.UserHandle getUserHandle();
+  }
+
+  public static interface CarUserManager.UserLifecycleListener {
+    method public void onEvent(@NonNull android.car.user.CarUserManager.UserLifecycleEvent);
   }
 
 }
@@ -1036,97 +1162,126 @@
   public final class VmsAssociatedLayer implements android.os.Parcelable {
     ctor public VmsAssociatedLayer(@NonNull android.car.vms.VmsLayer, @NonNull java.util.Set<java.lang.Integer>);
     method public int describeContents();
-    method @NonNull public java.util.Set<java.lang.Integer> getPublisherIds();
+    method @NonNull public java.util.Set<java.lang.Integer> getProviderIds();
+    method @Deprecated @NonNull public java.util.Set<java.lang.Integer> getPublisherIds();
     method @NonNull public android.car.vms.VmsLayer getVmsLayer();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.vms.VmsAssociatedLayer> CREATOR;
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.car.vms.VmsAssociatedLayer> CREATOR;
   }
 
   public final class VmsAvailableLayers implements android.os.Parcelable {
-    ctor public VmsAvailableLayers(@NonNull java.util.Set<android.car.vms.VmsAssociatedLayer>, int);
+    ctor @Deprecated public VmsAvailableLayers(@NonNull java.util.Set<android.car.vms.VmsAssociatedLayer>, int);
+    ctor public VmsAvailableLayers(int, @NonNull java.util.Set<android.car.vms.VmsAssociatedLayer>);
     method public int describeContents();
     method @NonNull public java.util.Set<android.car.vms.VmsAssociatedLayer> getAssociatedLayers();
-    method public int getSequence();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.vms.VmsAvailableLayers> CREATOR;
+    method @Deprecated public int getSequence();
+    method public int getSequenceNumber();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.car.vms.VmsAvailableLayers> CREATOR;
+  }
+
+  public final class VmsClient {
+    method @NonNull @RequiresPermission(anyOf={android.car.Car.PERMISSION_VMS_PUBLISHER, android.car.Car.PERMISSION_VMS_SUBSCRIBER}) public android.car.vms.VmsAvailableLayers getAvailableLayers();
+    method @Nullable @RequiresPermission(anyOf={android.car.Car.PERMISSION_VMS_PUBLISHER, android.car.Car.PERMISSION_VMS_SUBSCRIBER}) public byte[] getProviderDescription(int);
+    method @NonNull @RequiresPermission(anyOf={android.car.Car.PERMISSION_VMS_PUBLISHER, android.car.Car.PERMISSION_VMS_SUBSCRIBER}) public android.car.vms.VmsSubscriptionState getSubscriptionState();
+    method @RequiresPermission(android.car.Car.PERMISSION_VMS_SUBSCRIBER) public boolean isMonitoringEnabled();
+    method @RequiresPermission(android.car.Car.PERMISSION_VMS_PUBLISHER) public void publishPacket(int, @NonNull android.car.vms.VmsLayer, @NonNull byte[]);
+    method @RequiresPermission(android.car.Car.PERMISSION_VMS_PUBLISHER) public int registerProvider(@NonNull byte[]);
+    method @RequiresPermission(android.car.Car.PERMISSION_VMS_SUBSCRIBER) public void setMonitoringEnabled(boolean);
+    method @RequiresPermission(android.car.Car.PERMISSION_VMS_PUBLISHER) public void setProviderOfferings(int, @NonNull java.util.Set<android.car.vms.VmsLayerDependency>);
+    method @RequiresPermission(android.car.Car.PERMISSION_VMS_SUBSCRIBER) public void setSubscriptions(@NonNull java.util.Set<android.car.vms.VmsAssociatedLayer>);
+    method @RequiresPermission(android.car.Car.PERMISSION_VMS_PUBLISHER) public void unregisterProvider(int);
+  }
+
+  public final class VmsClientManager {
+    method @RequiresPermission(anyOf={android.car.Car.PERMISSION_VMS_PUBLISHER, android.car.Car.PERMISSION_VMS_SUBSCRIBER}) public void registerVmsClientCallback(@NonNull java.util.concurrent.Executor, @NonNull android.car.vms.VmsClientManager.VmsClientCallback);
+    method @RequiresPermission(anyOf={android.car.Car.PERMISSION_VMS_PUBLISHER, android.car.Car.PERMISSION_VMS_SUBSCRIBER}) public void unregisterVmsClientCallback(@NonNull android.car.vms.VmsClientManager.VmsClientCallback);
+  }
+
+  public static interface VmsClientManager.VmsClientCallback {
+    method public void onClientConnected(@NonNull android.car.vms.VmsClient);
+    method public void onLayerAvailabilityChanged(@NonNull android.car.vms.VmsAvailableLayers);
+    method public void onPacketReceived(int, @NonNull android.car.vms.VmsLayer, @NonNull byte[]);
+    method public void onSubscriptionStateChanged(@NonNull android.car.vms.VmsSubscriptionState);
   }
 
   public final class VmsLayer implements android.os.Parcelable {
     ctor public VmsLayer(int, int, int);
     method public int describeContents();
-    method public int getSubtype();
+    method public int getChannel();
+    method @Deprecated public int getSubtype();
     method public int getType();
     method public int getVersion();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.vms.VmsLayer> CREATOR;
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.car.vms.VmsLayer> CREATOR;
   }
 
   public final class VmsLayerDependency implements android.os.Parcelable {
-    ctor public VmsLayerDependency(@NonNull android.car.vms.VmsLayer, @NonNull java.util.Set<android.car.vms.VmsLayer>);
     ctor public VmsLayerDependency(@NonNull android.car.vms.VmsLayer);
+    ctor public VmsLayerDependency(@NonNull android.car.vms.VmsLayer, @NonNull java.util.Set<android.car.vms.VmsLayer>);
     method public int describeContents();
     method @NonNull public java.util.Set<android.car.vms.VmsLayer> getDependencies();
     method @NonNull public android.car.vms.VmsLayer getLayer();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.vms.VmsLayerDependency> CREATOR;
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.car.vms.VmsLayerDependency> CREATOR;
   }
 
-  public final class VmsLayersOffering implements android.os.Parcelable {
-    ctor public VmsLayersOffering(@NonNull java.util.Set<android.car.vms.VmsLayerDependency>, int);
-    method public int describeContents();
-    method public java.util.Set<android.car.vms.VmsLayerDependency> getDependencies();
-    method public int getPublisherId();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.vms.VmsLayersOffering> CREATOR;
+  @Deprecated public final class VmsLayersOffering implements android.os.Parcelable {
+    ctor @Deprecated public VmsLayersOffering(@NonNull java.util.Set<android.car.vms.VmsLayerDependency>, int);
+    method @Deprecated public int describeContents();
+    method @Deprecated @NonNull public java.util.Set<android.car.vms.VmsLayerDependency> getDependencies();
+    method @Deprecated public int getPublisherId();
+    method @Deprecated public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.car.vms.VmsLayersOffering> CREATOR;
   }
 
-  public final class VmsOperationRecorder {
-    method public void addHalSubscription(int, android.car.vms.VmsLayer);
-    method public void addPromiscuousSubscription(int);
-    method public void addSubscription(int, android.car.vms.VmsLayer);
-    method public static android.car.vms.VmsOperationRecorder get();
-    method public void getPublisherId(int);
-    method public void removeHalSubscription(int, android.car.vms.VmsLayer);
-    method public void removePromiscuousSubscription(int);
-    method public void removeSubscription(int, android.car.vms.VmsLayer);
-    method public void setHalPublisherLayersOffering(android.car.vms.VmsLayersOffering);
-    method public void setLayersOffering(android.car.vms.VmsLayersOffering);
-    method public void setPublisherLayersOffering(android.car.vms.VmsLayersOffering);
-    method public void startMonitoring();
-    method public void stopMonitoring();
-    method public void subscribe(android.car.vms.VmsLayer);
-    method public void subscribe(android.car.vms.VmsLayer, int);
-    method public void unsubscribe(android.car.vms.VmsLayer);
-    method public void unsubscribe(android.car.vms.VmsLayer, int);
+  @Deprecated public final class VmsOperationRecorder {
+    method @Deprecated public void addHalSubscription(int, android.car.vms.VmsLayer);
+    method @Deprecated public void addPromiscuousSubscription(int);
+    method @Deprecated public void addSubscription(int, android.car.vms.VmsLayer);
+    method @Deprecated public static android.car.vms.VmsOperationRecorder get();
+    method @Deprecated public void getPublisherId(int);
+    method @Deprecated public void removeHalSubscription(int, android.car.vms.VmsLayer);
+    method @Deprecated public void removePromiscuousSubscription(int);
+    method @Deprecated public void removeSubscription(int, android.car.vms.VmsLayer);
+    method @Deprecated public void setHalPublisherLayersOffering(android.car.vms.VmsLayersOffering);
+    method @Deprecated public void setLayersOffering(android.car.vms.VmsLayersOffering);
+    method @Deprecated public void setPublisherLayersOffering(android.car.vms.VmsLayersOffering);
+    method @Deprecated public void startMonitoring();
+    method @Deprecated public void stopMonitoring();
+    method @Deprecated public void subscribe(android.car.vms.VmsLayer);
+    method @Deprecated public void subscribe(android.car.vms.VmsLayer, int);
+    method @Deprecated public void unsubscribe(android.car.vms.VmsLayer);
+    method @Deprecated public void unsubscribe(android.car.vms.VmsLayer, int);
   }
 
-  public abstract class VmsPublisherClientService extends android.app.Service {
-    ctor public VmsPublisherClientService();
-    method public final int getPublisherId(byte[]);
-    method public final android.car.vms.VmsSubscriptionState getSubscriptions();
-    method public android.os.IBinder onBind(android.content.Intent);
-    method protected abstract void onVmsPublisherServiceReady();
-    method public abstract void onVmsSubscriptionChange(@NonNull android.car.vms.VmsSubscriptionState);
-    method public final void publish(@NonNull android.car.vms.VmsLayer, int, byte[]);
-    method public final void setLayersOffering(@NonNull android.car.vms.VmsLayersOffering);
+  @Deprecated public abstract class VmsPublisherClientService extends android.app.Service {
+    ctor @Deprecated public VmsPublisherClientService();
+    method @Deprecated public final int getPublisherId(byte[]);
+    method @Deprecated public final android.car.vms.VmsSubscriptionState getSubscriptions();
+    method @Deprecated public android.os.IBinder onBind(android.content.Intent);
+    method @Deprecated protected abstract void onVmsPublisherServiceReady();
+    method @Deprecated public abstract void onVmsSubscriptionChange(@NonNull android.car.vms.VmsSubscriptionState);
+    method @Deprecated public final void publish(@NonNull android.car.vms.VmsLayer, int, byte[]);
+    method @Deprecated public final void setLayersOffering(@NonNull android.car.vms.VmsLayersOffering);
   }
 
-  public final class VmsSubscriberManager {
-    method public void clearVmsSubscriberClientCallback();
-    method @NonNull public android.car.vms.VmsAvailableLayers getAvailableLayers();
-    method @NonNull public byte[] getPublisherInfo(int);
-    method public void setVmsSubscriberClientCallback(@NonNull java.util.concurrent.Executor, @NonNull android.car.vms.VmsSubscriberManager.VmsSubscriberClientCallback);
-    method public void startMonitoring();
-    method public void stopMonitoring();
-    method public void subscribe(@NonNull android.car.vms.VmsLayer);
-    method public void subscribe(@NonNull android.car.vms.VmsLayer, int);
-    method public void unsubscribe(@NonNull android.car.vms.VmsLayer);
-    method public void unsubscribe(@NonNull android.car.vms.VmsLayer, int);
+  @Deprecated public final class VmsSubscriberManager {
+    method @Deprecated public void clearVmsSubscriberClientCallback();
+    method @Deprecated @NonNull public android.car.vms.VmsAvailableLayers getAvailableLayers();
+    method @Deprecated @NonNull public byte[] getPublisherInfo(int);
+    method @Deprecated public void setVmsSubscriberClientCallback(@NonNull java.util.concurrent.Executor, @NonNull android.car.vms.VmsSubscriberManager.VmsSubscriberClientCallback);
+    method @Deprecated public void startMonitoring();
+    method @Deprecated public void stopMonitoring();
+    method @Deprecated public void subscribe(@NonNull android.car.vms.VmsLayer);
+    method @Deprecated public void subscribe(@NonNull android.car.vms.VmsLayer, int);
+    method @Deprecated public void unsubscribe(@NonNull android.car.vms.VmsLayer);
+    method @Deprecated public void unsubscribe(@NonNull android.car.vms.VmsLayer, int);
   }
 
-  public static interface VmsSubscriberManager.VmsSubscriberClientCallback {
-    method public void onLayersAvailabilityChanged(@NonNull android.car.vms.VmsAvailableLayers);
-    method public void onVmsMessageReceived(@NonNull android.car.vms.VmsLayer, byte[]);
+  @Deprecated public static interface VmsSubscriberManager.VmsSubscriberClientCallback {
+    method @Deprecated public void onLayersAvailabilityChanged(@NonNull android.car.vms.VmsAvailableLayers);
+    method @Deprecated public void onVmsMessageReceived(@NonNull android.car.vms.VmsLayer, byte[]);
   }
 
   public final class VmsSubscriptionState implements android.os.Parcelable {
@@ -1135,8 +1290,27 @@
     method @NonNull public java.util.Set<android.car.vms.VmsAssociatedLayer> getAssociatedLayers();
     method @NonNull public java.util.Set<android.car.vms.VmsLayer> getLayers();
     method public int getSequenceNumber();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.vms.VmsSubscriptionState> CREATOR;
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.car.vms.VmsSubscriptionState> CREATOR;
+  }
+
+}
+
+package android.car.watchdog {
+
+  public final class CarWatchdogManager {
+    method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_WATCHDOG) public void registerClient(@NonNull java.util.concurrent.Executor, @NonNull android.car.watchdog.CarWatchdogManager.CarWatchdogClientCallback, int);
+    method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_WATCHDOG) public void tellClientAlive(@NonNull android.car.watchdog.CarWatchdogManager.CarWatchdogClientCallback, int);
+    method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_WATCHDOG) public void unregisterClient(@NonNull android.car.watchdog.CarWatchdogManager.CarWatchdogClientCallback);
+    field public static final int TIMEOUT_CRITICAL = 0; // 0x0
+    field public static final int TIMEOUT_MODERATE = 1; // 0x1
+    field public static final int TIMEOUT_NORMAL = 2; // 0x2
+  }
+
+  public abstract static class CarWatchdogManager.CarWatchdogClientCallback {
+    ctor public CarWatchdogManager.CarWatchdogClientCallback();
+    method public boolean onCheckHealthStatus(int, int);
+    method public void onPrepareProcessTermination();
   }
 
 }
diff --git a/car-lib/api/system-lint-baseline.txt b/car-lib/api/system-lint-baseline.txt
new file mode 100644
index 0000000..0f151f2
--- /dev/null
+++ b/car-lib/api/system-lint-baseline.txt
@@ -0,0 +1,773 @@
+// Baseline format: 1.0
+AllUpper: android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors#EGR:
+    Constant EGR must be marked static final
+
+
+ArrayReturn: android.car.content.pm.AppBlockingPackageInfo#AppBlockingPackageInfo(String, int, int, int, android.content.pm.Signature[], String[]) parameter #4:
+    Method parameter should be Collection<Signature> (or subclass) instead of raw array; was `android.content.pm.Signature[]`
+ArrayReturn: android.car.content.pm.AppBlockingPackageInfo#signatures:
+    Field should be Collection<Signature> (or subclass) instead of raw array; was `android.content.pm.Signature[]`
+ArrayReturn: android.car.content.pm.CarAppBlockingPolicy#CarAppBlockingPolicy(android.car.content.pm.AppBlockingPackageInfo[], android.car.content.pm.AppBlockingPackageInfo[]) parameter #0:
+    Method parameter should be Collection<AppBlockingPackageInfo> (or subclass) instead of raw array; was `android.car.content.pm.AppBlockingPackageInfo[]`
+ArrayReturn: android.car.content.pm.CarAppBlockingPolicy#CarAppBlockingPolicy(android.car.content.pm.AppBlockingPackageInfo[], android.car.content.pm.AppBlockingPackageInfo[]) parameter #1:
+    Method parameter should be Collection<AppBlockingPackageInfo> (or subclass) instead of raw array; was `android.car.content.pm.AppBlockingPackageInfo[]`
+ArrayReturn: android.car.content.pm.CarAppBlockingPolicy#blacklists:
+    Field should be Collection<AppBlockingPackageInfo> (or subclass) instead of raw array; was `android.car.content.pm.AppBlockingPackageInfo[]`
+ArrayReturn: android.car.content.pm.CarAppBlockingPolicy#whitelists:
+    Field should be Collection<AppBlockingPackageInfo> (or subclass) instead of raw array; was `android.car.content.pm.AppBlockingPackageInfo[]`
+ArrayReturn: android.car.input.CarInputHandlingService#CarInputHandlingService(android.car.input.CarInputHandlingService.InputFilter[]) parameter #0:
+    Method parameter should be Collection<InputFilter> (or subclass) instead of raw array; was `android.car.input.CarInputHandlingService.InputFilter[]`
+
+
+AutoBoxing: android.car.diagnostic.CarDiagnosticEvent#getFuelSystemStatus():
+    Must avoid boxed primitives (`java.lang.Integer`)
+AutoBoxing: android.car.diagnostic.CarDiagnosticEvent#getFuelType():
+    Must avoid boxed primitives (`java.lang.Integer`)
+AutoBoxing: android.car.diagnostic.CarDiagnosticEvent#getSecondaryAirStatus():
+    Must avoid boxed primitives (`java.lang.Integer`)
+AutoBoxing: android.car.diagnostic.CarDiagnosticEvent#getSystemFloatSensor(int):
+    Must avoid boxed primitives (`java.lang.Float`)
+AutoBoxing: android.car.diagnostic.CarDiagnosticEvent#getSystemIntegerSensor(int):
+    Must avoid boxed primitives (`java.lang.Integer`)
+AutoBoxing: android.car.diagnostic.CarDiagnosticEvent#getVendorFloatSensor(int):
+    Must avoid boxed primitives (`java.lang.Float`)
+AutoBoxing: android.car.diagnostic.CarDiagnosticEvent#getVendorIntegerSensor(int):
+    Must avoid boxed primitives (`java.lang.Integer`)
+
+
+CallbackInterface: android.car.hardware.CarVendorExtensionManager.CarVendorExtensionCallback:
+    Callbacks must be abstract class instead of interface to enable extension in future API levels: CarVendorExtensionCallback
+CallbackInterface: android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback:
+    Callbacks must be abstract class instead of interface to enable extension in future API levels: CarCabinEventCallback
+CallbackInterface: android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback:
+    Callbacks must be abstract class instead of interface to enable extension in future API levels: CarHvacEventCallback
+CallbackInterface: android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentBleCallback:
+    Callbacks must be abstract class instead of interface to enable extension in future API levels: CarTrustAgentBleCallback
+CallbackInterface: android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentEnrollmentCallback:
+    Callbacks must be abstract class instead of interface to enable extension in future API levels: CarTrustAgentEnrollmentCallback
+CallbackInterface: android.car.vms.VmsClientManager.VmsClientCallback:
+    Callbacks must be abstract class instead of interface to enable extension in future API levels: VmsClientCallback
+CallbackInterface: android.car.vms.VmsSubscriberManager.VmsSubscriberClientCallback:
+    Callbacks must be abstract class instead of interface to enable extension in future API levels: VmsSubscriberClientCallback
+
+
+ConcreteCollection: android.car.hardware.CarPropertyConfig.Builder#setConfigArray(java.util.ArrayList<java.lang.Integer>) parameter #0:
+    Parameter type is concrete collection (`java.util.ArrayList`); must be higher-level interface
+
+
+EqualsAndHashCode: android.car.storagemonitoring.LifetimeWriteInfo#equals(Object):
+    Must override both equals and hashCode; missing one in android.car.storagemonitoring.LifetimeWriteInfo
+EqualsAndHashCode: android.car.vms.VmsAvailableLayers#equals(Object):
+    Must override both equals and hashCode; missing one in android.car.vms.VmsAvailableLayers
+
+
+ExecutorRegistration: android.car.CarProjectionManager#registerProjectionListener(android.car.CarProjectionManager.CarProjectionListener, int):
+    Registration methods should have overload that accepts delivery Executor: `registerProjectionListener`
+ExecutorRegistration: android.car.CarProjectionManager#registerProjectionStatusListener(android.car.CarProjectionManager.ProjectionStatusListener):
+    Registration methods should have overload that accepts delivery Executor: `registerProjectionStatusListener`
+ExecutorRegistration: android.car.CarProjectionManager#startProjectionAccessPoint(android.car.CarProjectionManager.ProjectionAccessPointCallback):
+    Registration methods should have overload that accepts delivery Executor: `startProjectionAccessPoint`
+ExecutorRegistration: android.car.diagnostic.CarDiagnosticManager#registerListener(android.car.diagnostic.CarDiagnosticManager.OnDiagnosticEventListener, int, int):
+    Registration methods should have overload that accepts delivery Executor: `registerListener`
+ExecutorRegistration: android.car.drivingstate.CarDrivingStateManager#registerListener(android.car.drivingstate.CarDrivingStateManager.CarDrivingStateEventListener):
+    Registration methods should have overload that accepts delivery Executor: `registerListener`
+ExecutorRegistration: android.car.hardware.CarVendorExtensionManager#registerCallback(android.car.hardware.CarVendorExtensionManager.CarVendorExtensionCallback):
+    Registration methods should have overload that accepts delivery Executor: `registerCallback`
+ExecutorRegistration: android.car.hardware.cabin.CarCabinManager#registerCallback(android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback):
+    Registration methods should have overload that accepts delivery Executor: `registerCallback`
+ExecutorRegistration: android.car.hardware.hvac.CarHvacManager#registerCallback(android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback):
+    Registration methods should have overload that accepts delivery Executor: `registerCallback`
+ExecutorRegistration: android.car.storagemonitoring.CarStorageMonitoringManager#registerListener(android.car.storagemonitoring.CarStorageMonitoringManager.IoStatsListener):
+    Registration methods should have overload that accepts delivery Executor: `registerListener`
+ExecutorRegistration: android.car.trust.CarTrustAgentEnrollmentManager#setBleCallback(android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentBleCallback):
+    Registration methods should have overload that accepts delivery Executor: `setBleCallback`
+ExecutorRegistration: android.car.trust.CarTrustAgentEnrollmentManager#setEnrollmentCallback(android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentEnrollmentCallback):
+    Registration methods should have overload that accepts delivery Executor: `setEnrollmentCallback`
+
+
+HiddenSuperclass: android.car.CarAppFocusManager:
+    Public class android.car.CarAppFocusManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.CarInfoManager:
+    Public class android.car.CarInfoManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.CarOccupantZoneManager:
+    Public class android.car.CarOccupantZoneManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.CarProjectionManager:
+    Public class android.car.CarProjectionManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.cluster.CarInstrumentClusterManager:
+    Public class android.car.cluster.CarInstrumentClusterManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.content.pm.CarPackageManager:
+    Public class android.car.content.pm.CarPackageManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.diagnostic.CarDiagnosticManager:
+    Public class android.car.diagnostic.CarDiagnosticManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.drivingstate.CarDrivingStateManager:
+    Public class android.car.drivingstate.CarDrivingStateManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.drivingstate.CarUxRestrictionsManager:
+    Public class android.car.drivingstate.CarUxRestrictionsManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.hardware.CarSensorManager:
+    Public class android.car.hardware.CarSensorManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.hardware.CarVendorExtensionManager:
+    Public class android.car.hardware.CarVendorExtensionManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.hardware.cabin.CarCabinManager:
+    Public class android.car.hardware.cabin.CarCabinManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.hardware.hvac.CarHvacManager:
+    Public class android.car.hardware.hvac.CarHvacManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.hardware.power.CarPowerManager:
+    Public class android.car.hardware.power.CarPowerManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.hardware.property.CarPropertyManager:
+    Public class android.car.hardware.property.CarPropertyManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.media.CarAudioManager:
+    Public class android.car.media.CarAudioManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.navigation.CarNavigationStatusManager:
+    Public class android.car.navigation.CarNavigationStatusManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.settings.CarConfigurationManager:
+    Public class android.car.settings.CarConfigurationManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.storagemonitoring.CarStorageMonitoringManager:
+    Public class android.car.storagemonitoring.CarStorageMonitoringManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.trust.CarTrustAgentEnrollmentManager:
+    Public class android.car.trust.CarTrustAgentEnrollmentManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.user.CarUserManager:
+    Public class android.car.user.CarUserManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.vms.VmsClientManager:
+    Public class android.car.vms.VmsClientManager stripped of unavailable superclass android.car.CarManagerBase
+HiddenSuperclass: android.car.vms.VmsSubscriberManager:
+    Public class android.car.vms.VmsSubscriberManager stripped of unavailable superclass android.car.CarManagerBase
+
+
+IntentName: android.car.Car#CAR_EXTRA_CLUSTER_ACTIVITY_STATE:
+    Intent extra constant name must be EXTRA_FOO: CAR_EXTRA_CLUSTER_ACTIVITY_STATE
+IntentName: android.car.media.CarAudioManager#AUDIOFOCUS_EXTRA_RECEIVE_DUCKING_EVENTS:
+    Intent extra constant name must be EXTRA_FOO: AUDIOFOCUS_EXTRA_RECEIVE_DUCKING_EVENTS
+
+
+InternalField: android.car.input.CarInputHandlingService.InputFilter#mKeyCode:
+    Internal field mKeyCode must not be exposed
+InternalField: android.car.input.CarInputHandlingService.InputFilter#mTargetDisplay:
+    Internal field mTargetDisplay must not be exposed
+
+
+MinMaxConstant: android.car.diagnostic.IntegerSensorIndex#MAX_AIR_FLOW_RATE_FROM_MASS_AIR_FLOW_SENSOR:
+    If min/max could change in future, make them dynamic methods: android.car.diagnostic.IntegerSensorIndex#MAX_AIR_FLOW_RATE_FROM_MASS_AIR_FLOW_SENSOR
+MinMaxConstant: android.car.diagnostic.IntegerSensorIndex#MAX_FUEL_AIR_EQUIVALENCE_RATIO:
+    If min/max could change in future, make them dynamic methods: android.car.diagnostic.IntegerSensorIndex#MAX_FUEL_AIR_EQUIVALENCE_RATIO
+MinMaxConstant: android.car.diagnostic.IntegerSensorIndex#MAX_INTAKE_MANIFOLD_ABSOLUTE_PRESSURE:
+    If min/max could change in future, make them dynamic methods: android.car.diagnostic.IntegerSensorIndex#MAX_INTAKE_MANIFOLD_ABSOLUTE_PRESSURE
+MinMaxConstant: android.car.diagnostic.IntegerSensorIndex#MAX_OXYGEN_SENSOR_CURRENT:
+    If min/max could change in future, make them dynamic methods: android.car.diagnostic.IntegerSensorIndex#MAX_OXYGEN_SENSOR_CURRENT
+MinMaxConstant: android.car.diagnostic.IntegerSensorIndex#MAX_OXYGEN_SENSOR_VOLTAGE:
+    If min/max could change in future, make them dynamic methods: android.car.diagnostic.IntegerSensorIndex#MAX_OXYGEN_SENSOR_VOLTAGE
+
+
+MissingNullability: android.car.AoapService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
+    Missing nullability on parameter `fd` in method `dump`
+MissingNullability: android.car.AoapService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #1:
+    Missing nullability on parameter `writer` in method `dump`
+MissingNullability: android.car.AoapService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #2:
+    Missing nullability on parameter `args` in method `dump`
+MissingNullability: android.car.AoapService#onBind(android.content.Intent):
+    Missing nullability on method `onBind` return
+MissingNullability: android.car.AoapService#onBind(android.content.Intent) parameter #0:
+    Missing nullability on parameter `intent` in method `onBind`
+MissingNullability: android.car.AoapService#onUnbind(android.content.Intent) parameter #0:
+    Missing nullability on parameter `intent` in method `onUnbind`
+MissingNullability: android.car.CarProjectionManager.ProjectionAccessPointCallback#onStarted(android.net.wifi.WifiConfiguration) parameter #0:
+    Missing nullability on parameter `wifiConfiguration` in method `onStarted`
+MissingNullability: android.car.cluster.CarInstrumentClusterManager#registerCallback(String, android.car.cluster.CarInstrumentClusterManager.Callback) parameter #0:
+    Missing nullability on parameter `category` in method `registerCallback`
+MissingNullability: android.car.cluster.CarInstrumentClusterManager#registerCallback(String, android.car.cluster.CarInstrumentClusterManager.Callback) parameter #1:
+    Missing nullability on parameter `callback` in method `registerCallback`
+MissingNullability: android.car.cluster.CarInstrumentClusterManager#startActivity(android.content.Intent) parameter #0:
+    Missing nullability on parameter `intent` in method `startActivity`
+MissingNullability: android.car.cluster.CarInstrumentClusterManager#unregisterCallback(android.car.cluster.CarInstrumentClusterManager.Callback) parameter #0:
+    Missing nullability on parameter `callback` in method `unregisterCallback`
+MissingNullability: android.car.cluster.CarInstrumentClusterManager.Callback#onClusterActivityStateChanged(String, android.os.Bundle) parameter #0:
+    Missing nullability on parameter `category` in method `onClusterActivityStateChanged`
+MissingNullability: android.car.cluster.CarInstrumentClusterManager.Callback#onClusterActivityStateChanged(String, android.os.Bundle) parameter #1:
+    Missing nullability on parameter `clusterActivityState` in method `onClusterActivityStateChanged`
+MissingNullability: android.car.cluster.renderer.InstrumentClusterRenderer#createNavigationRenderer():
+    Missing nullability on method `createNavigationRenderer` return
+MissingNullability: android.car.cluster.renderer.InstrumentClusterRenderer#onCreate(android.content.Context) parameter #0:
+    Missing nullability on parameter `context` in method `onCreate`
+MissingNullability: android.car.cluster.renderer.InstrumentClusterRenderingService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
+    Missing nullability on parameter `fd` in method `dump`
+MissingNullability: android.car.cluster.renderer.InstrumentClusterRenderingService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #1:
+    Missing nullability on parameter `writer` in method `dump`
+MissingNullability: android.car.cluster.renderer.InstrumentClusterRenderingService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #2:
+    Missing nullability on parameter `args` in method `dump`
+MissingNullability: android.car.cluster.renderer.InstrumentClusterRenderingService#getBitmap(android.net.Uri) parameter #0:
+    Missing nullability on parameter `uri` in method `getBitmap`
+MissingNullability: android.car.cluster.renderer.InstrumentClusterRenderingService#getBitmap(android.net.Uri, int, int) parameter #0:
+    Missing nullability on parameter `uri` in method `getBitmap`
+MissingNullability: android.car.cluster.renderer.InstrumentClusterRenderingService#onBind(android.content.Intent):
+    Missing nullability on method `onBind` return
+MissingNullability: android.car.cluster.renderer.InstrumentClusterRenderingService#onBind(android.content.Intent) parameter #0:
+    Missing nullability on parameter `intent` in method `onBind`
+MissingNullability: android.car.cluster.renderer.NavigationRenderer#getNavigationProperties():
+    Missing nullability on method `getNavigationProperties` return
+MissingNullability: android.car.content.pm.AppBlockingPackageInfo#AppBlockingPackageInfo(String, int, int, int, android.content.pm.Signature[], String[]) parameter #0:
+    Missing nullability on parameter `packageName` in method `AppBlockingPackageInfo`
+MissingNullability: android.car.content.pm.AppBlockingPackageInfo#AppBlockingPackageInfo(android.os.Parcel) parameter #0:
+    Missing nullability on parameter `in` in method `AppBlockingPackageInfo`
+MissingNullability: android.car.content.pm.AppBlockingPackageInfo#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.content.pm.AppBlockingPackageInfo`
+MissingNullability: android.car.content.pm.AppBlockingPackageInfo#activities:
+    Missing nullability on field `activities` in class `class android.car.content.pm.AppBlockingPackageInfo`
+MissingNullability: android.car.content.pm.AppBlockingPackageInfo#packageName:
+    Missing nullability on field `packageName` in class `class android.car.content.pm.AppBlockingPackageInfo`
+MissingNullability: android.car.content.pm.AppBlockingPackageInfo#signatures:
+    Missing nullability on field `signatures` in class `class android.car.content.pm.AppBlockingPackageInfo`
+MissingNullability: android.car.content.pm.AppBlockingPackageInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
+MissingNullability: android.car.content.pm.CarAppBlockingPolicy#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.content.pm.CarAppBlockingPolicy`
+MissingNullability: android.car.content.pm.CarAppBlockingPolicy#CarAppBlockingPolicy(android.car.content.pm.AppBlockingPackageInfo[], android.car.content.pm.AppBlockingPackageInfo[]) parameter #0:
+    Missing nullability on parameter `whitelists` in method `CarAppBlockingPolicy`
+MissingNullability: android.car.content.pm.CarAppBlockingPolicy#CarAppBlockingPolicy(android.car.content.pm.AppBlockingPackageInfo[], android.car.content.pm.AppBlockingPackageInfo[]) parameter #1:
+    Missing nullability on parameter `blacklists` in method `CarAppBlockingPolicy`
+MissingNullability: android.car.content.pm.CarAppBlockingPolicy#CarAppBlockingPolicy(android.os.Parcel) parameter #0:
+    Missing nullability on parameter `in` in method `CarAppBlockingPolicy`
+MissingNullability: android.car.content.pm.CarAppBlockingPolicy#blacklists:
+    Missing nullability on field `blacklists` in class `class android.car.content.pm.CarAppBlockingPolicy`
+MissingNullability: android.car.content.pm.CarAppBlockingPolicy#whitelists:
+    Missing nullability on field `whitelists` in class `class android.car.content.pm.CarAppBlockingPolicy`
+MissingNullability: android.car.content.pm.CarAppBlockingPolicy#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
+MissingNullability: android.car.content.pm.CarAppBlockingPolicyService#getAppBlockingPolicy():
+    Missing nullability on method `getAppBlockingPolicy` return
+MissingNullability: android.car.content.pm.CarAppBlockingPolicyService#onBind(android.content.Intent):
+    Missing nullability on method `onBind` return
+MissingNullability: android.car.content.pm.CarAppBlockingPolicyService#onBind(android.content.Intent) parameter #0:
+    Missing nullability on parameter `intent` in method `onBind`
+MissingNullability: android.car.content.pm.CarAppBlockingPolicyService#onStartCommand(android.content.Intent, int, int) parameter #0:
+    Missing nullability on parameter `intent` in method `onStartCommand`
+MissingNullability: android.car.content.pm.CarAppBlockingPolicyService#onUnbind(android.content.Intent) parameter #0:
+    Missing nullability on parameter `intent` in method `onUnbind`
+MissingNullability: android.car.content.pm.CarPackageManager#isActivityBackedBySafeActivity(android.content.ComponentName) parameter #0:
+    Missing nullability on parameter `activityName` in method `isActivityBackedBySafeActivity`
+MissingNullability: android.car.content.pm.CarPackageManager#setAppBlockingPolicy(String, android.car.content.pm.CarAppBlockingPolicy, int) parameter #0:
+    Missing nullability on parameter `packageName` in method `setAppBlockingPolicy`
+MissingNullability: android.car.content.pm.CarPackageManager#setAppBlockingPolicy(String, android.car.content.pm.CarAppBlockingPolicy, int) parameter #1:
+    Missing nullability on parameter `policy` in method `setAppBlockingPolicy`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.diagnostic.CarDiagnosticEvent`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent#CarDiagnosticEvent(android.os.Parcel) parameter #0:
+    Missing nullability on parameter `in` in method `CarDiagnosticEvent`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent#dtc:
+    Missing nullability on field `dtc` in class `class android.car.diagnostic.CarDiagnosticEvent`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent#writeToJson(android.util.JsonWriter) parameter #0:
+    Missing nullability on parameter `jsonWriter` in method `writeToJson`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.Builder#build():
+    Missing nullability on method `build` return
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.Builder#newFreezeFrameBuilder():
+    Missing nullability on method `newFreezeFrameBuilder` return
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.Builder#newLiveFrameBuilder():
+    Missing nullability on method `newLiveFrameBuilder` return
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.Builder#setDtc(String):
+    Missing nullability on method `setDtc` return
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.Builder#setDtc(String) parameter #0:
+    Missing nullability on parameter `dtc` in method `setDtc`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.Builder#setFloatValue(int, float):
+    Missing nullability on method `setFloatValue` return
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.Builder#setIntValue(int, int):
+    Missing nullability on method `setIntValue` return
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.Builder#setTimeStamp(long):
+    Missing nullability on method `setTimeStamp` return
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.Builder#withDtc(String) parameter #0:
+    Missing nullability on parameter `dtc` in method `withDtc`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.CommonIgnitionMonitors#components:
+    Missing nullability on field `components` in class `class android.car.diagnostic.CarDiagnosticEvent.CommonIgnitionMonitors`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.CommonIgnitionMonitors#fuelSystem:
+    Missing nullability on field `fuelSystem` in class `class android.car.diagnostic.CarDiagnosticEvent.CommonIgnitionMonitors`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.CommonIgnitionMonitors#misfire:
+    Missing nullability on field `misfire` in class `class android.car.diagnostic.CarDiagnosticEvent.CommonIgnitionMonitors`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.CompressionIgnitionMonitors#EGROrVVT:
+    Missing nullability on field `EGROrVVT` in class `class android.car.diagnostic.CarDiagnosticEvent.CompressionIgnitionMonitors`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.CompressionIgnitionMonitors#NMHCCatalyst:
+    Missing nullability on field `NMHCCatalyst` in class `class android.car.diagnostic.CarDiagnosticEvent.CompressionIgnitionMonitors`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.CompressionIgnitionMonitors#NOxSCR:
+    Missing nullability on field `NOxSCR` in class `class android.car.diagnostic.CarDiagnosticEvent.CompressionIgnitionMonitors`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.CompressionIgnitionMonitors#PMFilter:
+    Missing nullability on field `PMFilter` in class `class android.car.diagnostic.CarDiagnosticEvent.CompressionIgnitionMonitors`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.CompressionIgnitionMonitors#boostPressure:
+    Missing nullability on field `boostPressure` in class `class android.car.diagnostic.CarDiagnosticEvent.CompressionIgnitionMonitors`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.CompressionIgnitionMonitors#exhaustGasSensor:
+    Missing nullability on field `exhaustGasSensor` in class `class android.car.diagnostic.CarDiagnosticEvent.CompressionIgnitionMonitors`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors#ACRefrigerant:
+    Missing nullability on field `ACRefrigerant` in class `class android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors#EGR:
+    Missing nullability on field `EGR` in class `class android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors#catalyst:
+    Missing nullability on field `catalyst` in class `class android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors#evaporativeSystem:
+    Missing nullability on field `evaporativeSystem` in class `class android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors#heatedCatalyst:
+    Missing nullability on field `heatedCatalyst` in class `class android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors#oxygenSensor:
+    Missing nullability on field `oxygenSensor` in class `class android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors#oxygenSensorHeater:
+    Missing nullability on field `oxygenSensorHeater` in class `class android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors`
+MissingNullability: android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors#secondaryAirSystem:
+    Missing nullability on field `secondaryAirSystem` in class `class android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors`
+MissingNullability: android.car.diagnostic.CarDiagnosticManager#clearFreezeFrames(long...) parameter #0:
+    Missing nullability on parameter `timestamps` in method `clearFreezeFrames`
+MissingNullability: android.car.diagnostic.CarDiagnosticManager#getFreezeFrameTimestamps():
+    Missing nullability on method `getFreezeFrameTimestamps` return
+MissingNullability: android.car.diagnostic.CarDiagnosticManager#registerListener(android.car.diagnostic.CarDiagnosticManager.OnDiagnosticEventListener, int, int) parameter #0:
+    Missing nullability on parameter `listener` in method `registerListener`
+MissingNullability: android.car.diagnostic.CarDiagnosticManager#unregisterListener(android.car.diagnostic.CarDiagnosticManager.OnDiagnosticEventListener) parameter #0:
+    Missing nullability on parameter `listener` in method `unregisterListener`
+MissingNullability: android.car.diagnostic.CarDiagnosticManager.OnDiagnosticEventListener#onDiagnosticEvent(android.car.diagnostic.CarDiagnosticEvent) parameter #0:
+    Missing nullability on parameter `carDiagnosticEvent` in method `onDiagnosticEvent`
+MissingNullability: android.car.drivingstate.CarDrivingStateEvent#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.drivingstate.CarDrivingStateEvent`
+MissingNullability: android.car.drivingstate.CarDrivingStateEvent#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
+MissingNullability: android.car.drivingstate.CarDrivingStateManager.CarDrivingStateEventListener#onDrivingStateChanged(android.car.drivingstate.CarDrivingStateEvent) parameter #0:
+    Missing nullability on parameter `event` in method `onDrivingStateChanged`
+MissingNullability: android.car.hardware.CarPropertyConfig#newBuilder(Class<T>, int, int, int):
+    Missing nullability on method `newBuilder` return
+MissingNullability: android.car.hardware.CarPropertyConfig#newBuilder(Class<T>, int, int, int) parameter #0:
+    Missing nullability on parameter `type` in method `newBuilder`
+MissingNullability: android.car.hardware.CarPropertyConfig.Builder#addArea(int):
+    Missing nullability on method `addArea` return
+MissingNullability: android.car.hardware.CarPropertyConfig.Builder#addAreaConfig(int, T, T):
+    Missing nullability on method `addAreaConfig` return
+MissingNullability: android.car.hardware.CarPropertyConfig.Builder#addAreas(int[]):
+    Missing nullability on method `addAreas` return
+MissingNullability: android.car.hardware.CarPropertyConfig.Builder#addAreas(int[]) parameter #0:
+    Missing nullability on parameter `areaIds` in method `addAreas`
+MissingNullability: android.car.hardware.CarPropertyConfig.Builder#build():
+    Missing nullability on method `build` return
+MissingNullability: android.car.hardware.CarPropertyConfig.Builder#setAccess(int):
+    Missing nullability on method `setAccess` return
+MissingNullability: android.car.hardware.CarPropertyConfig.Builder#setChangeMode(int):
+    Missing nullability on method `setChangeMode` return
+MissingNullability: android.car.hardware.CarPropertyConfig.Builder#setConfigArray(java.util.ArrayList<java.lang.Integer>):
+    Missing nullability on method `setConfigArray` return
+MissingNullability: android.car.hardware.CarPropertyConfig.Builder#setConfigArray(java.util.ArrayList<java.lang.Integer>) parameter #0:
+    Missing nullability on parameter `configArray` in method `setConfigArray`
+MissingNullability: android.car.hardware.CarPropertyConfig.Builder#setConfigString(String):
+    Missing nullability on method `setConfigString` return
+MissingNullability: android.car.hardware.CarPropertyConfig.Builder#setConfigString(String) parameter #0:
+    Missing nullability on parameter `configString` in method `setConfigString`
+MissingNullability: android.car.hardware.CarPropertyConfig.Builder#setMaxSampleRate(float):
+    Missing nullability on method `setMaxSampleRate` return
+MissingNullability: android.car.hardware.CarPropertyConfig.Builder#setMinSampleRate(float):
+    Missing nullability on method `setMinSampleRate` return
+MissingNullability: android.car.hardware.CarVendorExtensionManager#getGlobalProperty(Class<E>, int) parameter #0:
+    Missing nullability on parameter `propertyClass` in method `getGlobalProperty`
+MissingNullability: android.car.hardware.CarVendorExtensionManager#getProperties():
+    Missing nullability on method `getProperties` return
+MissingNullability: android.car.hardware.CarVendorExtensionManager#getProperty(Class<E>, int, int) parameter #0:
+    Missing nullability on parameter `propertyClass` in method `getProperty`
+MissingNullability: android.car.hardware.CarVendorExtensionManager#registerCallback(android.car.hardware.CarVendorExtensionManager.CarVendorExtensionCallback) parameter #0:
+    Missing nullability on parameter `callback` in method `registerCallback`
+MissingNullability: android.car.hardware.CarVendorExtensionManager#setGlobalProperty(Class<E>, int, E) parameter #0:
+    Missing nullability on parameter `propertyClass` in method `setGlobalProperty`
+MissingNullability: android.car.hardware.CarVendorExtensionManager#setProperty(Class<E>, int, int, E) parameter #0:
+    Missing nullability on parameter `propertyClass` in method `setProperty`
+MissingNullability: android.car.hardware.CarVendorExtensionManager#unregisterCallback(android.car.hardware.CarVendorExtensionManager.CarVendorExtensionCallback) parameter #0:
+    Missing nullability on parameter `callback` in method `unregisterCallback`
+MissingNullability: android.car.hardware.CarVendorExtensionManager.CarVendorExtensionCallback#onChangeEvent(android.car.hardware.CarPropertyValue) parameter #0:
+    Missing nullability on parameter `value` in method `onChangeEvent`
+MissingNullability: android.car.hardware.cabin.CarCabinManager#getPropertyList():
+    Missing nullability on method `getPropertyList` return
+MissingNullability: android.car.hardware.cabin.CarCabinManager#registerCallback(android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback) parameter #0:
+    Missing nullability on parameter `callback` in method `registerCallback`
+MissingNullability: android.car.hardware.cabin.CarCabinManager#unregisterCallback(android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback) parameter #0:
+    Missing nullability on parameter `callback` in method `unregisterCallback`
+MissingNullability: android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback#onChangeEvent(android.car.hardware.CarPropertyValue) parameter #0:
+    Missing nullability on parameter `value` in method `onChangeEvent`
+MissingNullability: android.car.hardware.hvac.CarHvacManager#getPropertyList():
+    Missing nullability on method `getPropertyList` return
+MissingNullability: android.car.hardware.hvac.CarHvacManager#registerCallback(android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback) parameter #0:
+    Missing nullability on parameter `callback` in method `registerCallback`
+MissingNullability: android.car.hardware.hvac.CarHvacManager#unregisterCallback(android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback) parameter #0:
+    Missing nullability on parameter `callback` in method `unregisterCallback`
+MissingNullability: android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback#onChangeEvent(android.car.hardware.CarPropertyValue) parameter #0:
+    Missing nullability on parameter `value` in method `onChangeEvent`
+MissingNullability: android.car.input.CarInputHandlingService#CarInputHandlingService(android.car.input.CarInputHandlingService.InputFilter[]) parameter #0:
+    Missing nullability on parameter `handledKeys` in method `CarInputHandlingService`
+MissingNullability: android.car.input.CarInputHandlingService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
+    Missing nullability on parameter `fd` in method `dump`
+MissingNullability: android.car.input.CarInputHandlingService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #1:
+    Missing nullability on parameter `writer` in method `dump`
+MissingNullability: android.car.input.CarInputHandlingService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #2:
+    Missing nullability on parameter `args` in method `dump`
+MissingNullability: android.car.input.CarInputHandlingService#onBind(android.content.Intent):
+    Missing nullability on method `onBind` return
+MissingNullability: android.car.input.CarInputHandlingService#onBind(android.content.Intent) parameter #0:
+    Missing nullability on parameter `intent` in method `onBind`
+MissingNullability: android.car.input.CarInputHandlingService#onKeyEvent(android.view.KeyEvent, int) parameter #0:
+    Missing nullability on parameter `keyEvent` in method `onKeyEvent`
+MissingNullability: android.car.input.CarInputHandlingService.InputFilter#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.input.CarInputHandlingService.InputFilter`
+MissingNullability: android.car.input.CarInputHandlingService.InputFilter#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
+MissingNullability: android.car.media.CarAudioManager#createAudioPatch(String, int, int):
+    Missing nullability on method `createAudioPatch` return
+MissingNullability: android.car.media.CarAudioManager#createAudioPatch(String, int, int) parameter #0:
+    Missing nullability on parameter `sourceAddress` in method `createAudioPatch`
+MissingNullability: android.car.media.CarAudioManager#releaseAudioPatch(android.car.media.CarAudioPatchHandle) parameter #0:
+    Missing nullability on parameter `patch` in method `releaseAudioPatch`
+MissingNullability: android.car.media.CarAudioPatchHandle#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.media.CarAudioPatchHandle`
+MissingNullability: android.car.media.CarAudioPatchHandle#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `out` in method `writeToParcel`
+MissingNullability: android.car.navigation.CarNavigationInstrumentCluster#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.navigation.CarNavigationInstrumentCluster`
+MissingNullability: android.car.navigation.CarNavigationInstrumentCluster#CarNavigationInstrumentCluster(android.car.navigation.CarNavigationInstrumentCluster) parameter #0:
+    Missing nullability on parameter `that` in method `CarNavigationInstrumentCluster`
+MissingNullability: android.car.navigation.CarNavigationInstrumentCluster#createCluster(int):
+    Missing nullability on method `createCluster` return
+MissingNullability: android.car.navigation.CarNavigationInstrumentCluster#createCustomImageCluster(int, int, int, int):
+    Missing nullability on method `createCustomImageCluster` return
+MissingNullability: android.car.navigation.CarNavigationInstrumentCluster#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
+MissingNullability: android.car.navigation.CarNavigationStatusManager#getInstrumentClusterInfo():
+    Missing nullability on method `getInstrumentClusterInfo` return
+MissingNullability: android.car.navigation.CarNavigationStatusManager#sendEvent(int, android.os.Bundle) parameter #1:
+    Missing nullability on parameter `bundle` in method `sendEvent`
+MissingNullability: android.car.navigation.CarNavigationStatusManager#sendNavigationStateChange(android.os.Bundle) parameter #0:
+    Missing nullability on parameter `bundle` in method `sendNavigationStateChange`
+MissingNullability: android.car.projection.ProjectionOptions#ProjectionOptions(android.os.Bundle) parameter #0:
+    Missing nullability on parameter `bundle` in method `ProjectionOptions`
+MissingNullability: android.car.projection.ProjectionStatus#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.projection.ProjectionStatus`
+MissingNullability: android.car.projection.ProjectionStatus#builder(String, int) parameter #0:
+    Missing nullability on parameter `packageName` in method `builder`
+MissingNullability: android.car.projection.ProjectionStatus#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
+MissingNullability: android.car.projection.ProjectionStatus.Builder#addMobileDevice(android.car.projection.ProjectionStatus.MobileDevice) parameter #0:
+    Missing nullability on parameter `mobileDevice` in method `addMobileDevice`
+MissingNullability: android.car.projection.ProjectionStatus.Builder#build():
+    Missing nullability on method `build` return
+MissingNullability: android.car.projection.ProjectionStatus.Builder#setExtras(android.os.Bundle) parameter #0:
+    Missing nullability on parameter `extras` in method `setExtras`
+MissingNullability: android.car.projection.ProjectionStatus.MobileDevice#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.projection.ProjectionStatus.MobileDevice`
+MissingNullability: android.car.projection.ProjectionStatus.MobileDevice#builder(int, String) parameter #1:
+    Missing nullability on parameter `name` in method `builder`
+MissingNullability: android.car.projection.ProjectionStatus.MobileDevice#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
+MissingNullability: android.car.projection.ProjectionStatus.MobileDevice.Builder#setExtras(android.os.Bundle) parameter #0:
+    Missing nullability on parameter `extras` in method `setExtras`
+MissingNullability: android.car.storagemonitoring.CarStorageMonitoringManager#getAggregateIoStats():
+    Missing nullability on method `getAggregateIoStats` return
+MissingNullability: android.car.storagemonitoring.CarStorageMonitoringManager#getBootIoStats():
+    Missing nullability on method `getBootIoStats` return
+MissingNullability: android.car.storagemonitoring.CarStorageMonitoringManager#getIoStatsDeltas():
+    Missing nullability on method `getIoStatsDeltas` return
+MissingNullability: android.car.storagemonitoring.CarStorageMonitoringManager#getWearEstimate():
+    Missing nullability on method `getWearEstimate` return
+MissingNullability: android.car.storagemonitoring.CarStorageMonitoringManager#getWearEstimateHistory():
+    Missing nullability on method `getWearEstimateHistory` return
+MissingNullability: android.car.storagemonitoring.CarStorageMonitoringManager#registerListener(android.car.storagemonitoring.CarStorageMonitoringManager.IoStatsListener) parameter #0:
+    Missing nullability on parameter `listener` in method `registerListener`
+MissingNullability: android.car.storagemonitoring.CarStorageMonitoringManager#unregisterListener(android.car.storagemonitoring.CarStorageMonitoringManager.IoStatsListener) parameter #0:
+    Missing nullability on parameter `listener` in method `unregisterListener`
+MissingNullability: android.car.storagemonitoring.CarStorageMonitoringManager.IoStatsListener#onSnapshot(android.car.storagemonitoring.IoStats) parameter #0:
+    Missing nullability on parameter `snapshot` in method `onSnapshot`
+MissingNullability: android.car.storagemonitoring.IoStats#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.storagemonitoring.IoStats`
+MissingNullability: android.car.storagemonitoring.IoStats#IoStats(android.os.Parcel) parameter #0:
+    Missing nullability on parameter `in` in method `IoStats`
+MissingNullability: android.car.storagemonitoring.IoStats#IoStats(java.util.List<android.car.storagemonitoring.IoStatsEntry>, long) parameter #0:
+    Missing nullability on parameter `stats` in method `IoStats`
+MissingNullability: android.car.storagemonitoring.IoStats#getBackgroundTotals():
+    Missing nullability on method `getBackgroundTotals` return
+MissingNullability: android.car.storagemonitoring.IoStats#getForegroundTotals():
+    Missing nullability on method `getForegroundTotals` return
+MissingNullability: android.car.storagemonitoring.IoStats#getStats():
+    Missing nullability on method `getStats` return
+MissingNullability: android.car.storagemonitoring.IoStats#getTotals():
+    Missing nullability on method `getTotals` return
+MissingNullability: android.car.storagemonitoring.IoStats#getUserIdStats(int):
+    Missing nullability on method `getUserIdStats` return
+MissingNullability: android.car.storagemonitoring.IoStats#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
+MissingNullability: android.car.storagemonitoring.IoStatsEntry#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.storagemonitoring.IoStatsEntry`
+MissingNullability: android.car.storagemonitoring.IoStatsEntry#IoStatsEntry(android.car.storagemonitoring.UidIoRecord, long) parameter #0:
+    Missing nullability on parameter `record` in method `IoStatsEntry`
+MissingNullability: android.car.storagemonitoring.IoStatsEntry#IoStatsEntry(android.os.Parcel) parameter #0:
+    Missing nullability on parameter `in` in method `IoStatsEntry`
+MissingNullability: android.car.storagemonitoring.IoStatsEntry#IoStatsEntry(int, long, android.car.storagemonitoring.IoStatsEntry.Metrics, android.car.storagemonitoring.IoStatsEntry.Metrics) parameter #2:
+    Missing nullability on parameter `foreground` in method `IoStatsEntry`
+MissingNullability: android.car.storagemonitoring.IoStatsEntry#IoStatsEntry(int, long, android.car.storagemonitoring.IoStatsEntry.Metrics, android.car.storagemonitoring.IoStatsEntry.Metrics) parameter #3:
+    Missing nullability on parameter `background` in method `IoStatsEntry`
+MissingNullability: android.car.storagemonitoring.IoStatsEntry#background:
+    Missing nullability on field `background` in class `class android.car.storagemonitoring.IoStatsEntry`
+MissingNullability: android.car.storagemonitoring.IoStatsEntry#foreground:
+    Missing nullability on field `foreground` in class `class android.car.storagemonitoring.IoStatsEntry`
+MissingNullability: android.car.storagemonitoring.IoStatsEntry#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
+MissingNullability: android.car.storagemonitoring.IoStatsEntry.Metrics#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.storagemonitoring.IoStatsEntry.Metrics`
+MissingNullability: android.car.storagemonitoring.IoStatsEntry.Metrics#Metrics(android.os.Parcel) parameter #0:
+    Missing nullability on parameter `in` in method `Metrics`
+MissingNullability: android.car.storagemonitoring.IoStatsEntry.Metrics#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
+MissingNullability: android.car.storagemonitoring.LifetimeWriteInfo#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.storagemonitoring.LifetimeWriteInfo`
+MissingNullability: android.car.storagemonitoring.LifetimeWriteInfo#LifetimeWriteInfo(String, String, long) parameter #0:
+    Missing nullability on parameter `partition` in method `LifetimeWriteInfo`
+MissingNullability: android.car.storagemonitoring.LifetimeWriteInfo#LifetimeWriteInfo(String, String, long) parameter #1:
+    Missing nullability on parameter `fstype` in method `LifetimeWriteInfo`
+MissingNullability: android.car.storagemonitoring.LifetimeWriteInfo#LifetimeWriteInfo(android.os.Parcel) parameter #0:
+    Missing nullability on parameter `in` in method `LifetimeWriteInfo`
+MissingNullability: android.car.storagemonitoring.LifetimeWriteInfo#fstype:
+    Missing nullability on field `fstype` in class `class android.car.storagemonitoring.LifetimeWriteInfo`
+MissingNullability: android.car.storagemonitoring.LifetimeWriteInfo#partition:
+    Missing nullability on field `partition` in class `class android.car.storagemonitoring.LifetimeWriteInfo`
+MissingNullability: android.car.storagemonitoring.LifetimeWriteInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
+MissingNullability: android.car.storagemonitoring.WearEstimate#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.storagemonitoring.WearEstimate`
+MissingNullability: android.car.storagemonitoring.WearEstimate#WearEstimate(android.os.Parcel) parameter #0:
+    Missing nullability on parameter `in` in method `WearEstimate`
+MissingNullability: android.car.storagemonitoring.WearEstimate#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
+MissingNullability: android.car.storagemonitoring.WearEstimateChange#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.storagemonitoring.WearEstimateChange`
+MissingNullability: android.car.storagemonitoring.WearEstimateChange#WearEstimateChange(android.car.storagemonitoring.WearEstimate, android.car.storagemonitoring.WearEstimate, long, java.time.Instant, boolean) parameter #0:
+    Missing nullability on parameter `oldEstimate` in method `WearEstimateChange`
+MissingNullability: android.car.storagemonitoring.WearEstimateChange#WearEstimateChange(android.car.storagemonitoring.WearEstimate, android.car.storagemonitoring.WearEstimate, long, java.time.Instant, boolean) parameter #1:
+    Missing nullability on parameter `newEstimate` in method `WearEstimateChange`
+MissingNullability: android.car.storagemonitoring.WearEstimateChange#WearEstimateChange(android.car.storagemonitoring.WearEstimate, android.car.storagemonitoring.WearEstimate, long, java.time.Instant, boolean) parameter #3:
+    Missing nullability on parameter `dateAtChange` in method `WearEstimateChange`
+MissingNullability: android.car.storagemonitoring.WearEstimateChange#WearEstimateChange(android.os.Parcel) parameter #0:
+    Missing nullability on parameter `in` in method `WearEstimateChange`
+MissingNullability: android.car.storagemonitoring.WearEstimateChange#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
+MissingNullability: android.car.trust.CarTrustAgentEnrollmentManager#enrollmentHandshakeAccepted(android.bluetooth.BluetoothDevice) parameter #0:
+    Missing nullability on parameter `device` in method `enrollmentHandshakeAccepted`
+MissingNullability: android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentBleCallback#onBleEnrollmentDeviceConnected(android.bluetooth.BluetoothDevice) parameter #0:
+    Missing nullability on parameter `device` in method `onBleEnrollmentDeviceConnected`
+MissingNullability: android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentBleCallback#onBleEnrollmentDeviceDisconnected(android.bluetooth.BluetoothDevice) parameter #0:
+    Missing nullability on parameter `device` in method `onBleEnrollmentDeviceDisconnected`
+MissingNullability: android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentEnrollmentCallback#onAuthStringAvailable(android.bluetooth.BluetoothDevice, String) parameter #0:
+    Missing nullability on parameter `device` in method `onAuthStringAvailable`
+MissingNullability: android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentEnrollmentCallback#onAuthStringAvailable(android.bluetooth.BluetoothDevice, String) parameter #1:
+    Missing nullability on parameter `authString` in method `onAuthStringAvailable`
+MissingNullability: android.car.trust.TrustedDeviceInfo#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.trust.TrustedDeviceInfo`
+MissingNullability: android.car.trust.TrustedDeviceInfo#TrustedDeviceInfo(android.os.Parcel) parameter #0:
+    Missing nullability on parameter `in` in method `TrustedDeviceInfo`
+MissingNullability: android.car.trust.TrustedDeviceInfo#deserialize(String):
+    Missing nullability on method `deserialize` return
+MissingNullability: android.car.trust.TrustedDeviceInfo#deserialize(String) parameter #0:
+    Missing nullability on parameter `deviceInfo` in method `deserialize`
+MissingNullability: android.car.trust.TrustedDeviceInfo#serialize():
+    Missing nullability on method `serialize` return
+MissingNullability: android.car.trust.TrustedDeviceInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
+MissingNullability: android.car.vms.VmsAssociatedLayer#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.vms.VmsAssociatedLayer`
+MissingNullability: android.car.vms.VmsAssociatedLayer#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `out` in method `writeToParcel`
+MissingNullability: android.car.vms.VmsAvailableLayers#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.vms.VmsAvailableLayers`
+MissingNullability: android.car.vms.VmsAvailableLayers#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `out` in method `writeToParcel`
+MissingNullability: android.car.vms.VmsLayer#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.vms.VmsLayer`
+MissingNullability: android.car.vms.VmsLayer#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `out` in method `writeToParcel`
+MissingNullability: android.car.vms.VmsLayerDependency#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.vms.VmsLayerDependency`
+MissingNullability: android.car.vms.VmsLayerDependency#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `out` in method `writeToParcel`
+MissingNullability: android.car.vms.VmsLayersOffering#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.vms.VmsLayersOffering`
+MissingNullability: android.car.vms.VmsLayersOffering#getDependencies():
+    Missing nullability on method `getDependencies` return
+MissingNullability: android.car.vms.VmsLayersOffering#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `out` in method `writeToParcel`
+MissingNullability: android.car.vms.VmsOperationRecorder#addHalSubscription(int, android.car.vms.VmsLayer) parameter #1:
+    Missing nullability on parameter `layer` in method `addHalSubscription`
+MissingNullability: android.car.vms.VmsOperationRecorder#addSubscription(int, android.car.vms.VmsLayer) parameter #1:
+    Missing nullability on parameter `layer` in method `addSubscription`
+MissingNullability: android.car.vms.VmsOperationRecorder#get():
+    Missing nullability on method `get` return
+MissingNullability: android.car.vms.VmsOperationRecorder#removeHalSubscription(int, android.car.vms.VmsLayer) parameter #1:
+    Missing nullability on parameter `layer` in method `removeHalSubscription`
+MissingNullability: android.car.vms.VmsOperationRecorder#removeSubscription(int, android.car.vms.VmsLayer) parameter #1:
+    Missing nullability on parameter `layer` in method `removeSubscription`
+MissingNullability: android.car.vms.VmsOperationRecorder#setHalPublisherLayersOffering(android.car.vms.VmsLayersOffering) parameter #0:
+    Missing nullability on parameter `layersOffering` in method `setHalPublisherLayersOffering`
+MissingNullability: android.car.vms.VmsOperationRecorder#setLayersOffering(android.car.vms.VmsLayersOffering) parameter #0:
+    Missing nullability on parameter `layersOffering` in method `setLayersOffering`
+MissingNullability: android.car.vms.VmsOperationRecorder#setPublisherLayersOffering(android.car.vms.VmsLayersOffering) parameter #0:
+    Missing nullability on parameter `layersOffering` in method `setPublisherLayersOffering`
+MissingNullability: android.car.vms.VmsOperationRecorder#subscribe(android.car.vms.VmsLayer) parameter #0:
+    Missing nullability on parameter `layer` in method `subscribe`
+MissingNullability: android.car.vms.VmsOperationRecorder#subscribe(android.car.vms.VmsLayer, int) parameter #0:
+    Missing nullability on parameter `layer` in method `subscribe`
+MissingNullability: android.car.vms.VmsOperationRecorder#unsubscribe(android.car.vms.VmsLayer) parameter #0:
+    Missing nullability on parameter `layer` in method `unsubscribe`
+MissingNullability: android.car.vms.VmsOperationRecorder#unsubscribe(android.car.vms.VmsLayer, int) parameter #0:
+    Missing nullability on parameter `layer` in method `unsubscribe`
+MissingNullability: android.car.vms.VmsPublisherClientService#getPublisherId(byte[]) parameter #0:
+    Missing nullability on parameter `publisherInfo` in method `getPublisherId`
+MissingNullability: android.car.vms.VmsPublisherClientService#getSubscriptions():
+    Missing nullability on method `getSubscriptions` return
+MissingNullability: android.car.vms.VmsPublisherClientService#onBind(android.content.Intent):
+    Missing nullability on method `onBind` return
+MissingNullability: android.car.vms.VmsPublisherClientService#onBind(android.content.Intent) parameter #0:
+    Missing nullability on parameter `intent` in method `onBind`
+MissingNullability: android.car.vms.VmsPublisherClientService#onUnbind(android.content.Intent) parameter #0:
+    Missing nullability on parameter `intent` in method `onUnbind`
+MissingNullability: android.car.vms.VmsPublisherClientService#publish(android.car.vms.VmsLayer, int, byte[]) parameter #2:
+    Missing nullability on parameter `payload` in method `publish`
+MissingNullability: android.car.vms.VmsSubscriberManager.VmsSubscriberClientCallback#onVmsMessageReceived(android.car.vms.VmsLayer, byte[]) parameter #1:
+    Missing nullability on parameter `payload` in method `onVmsMessageReceived`
+MissingNullability: android.car.vms.VmsSubscriptionState#CREATOR:
+    Missing nullability on field `CREATOR` in class `class android.car.vms.VmsSubscriptionState`
+MissingNullability: android.car.vms.VmsSubscriptionState#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `out` in method `writeToParcel`
+
+
+OnNameExpected: android.car.AoapService#canSwitchToAoap(android.hardware.usb.UsbDevice):
+    If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+OnNameExpected: android.car.AoapService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
+    If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+OnNameExpected: android.car.AoapService#isDeviceSupported(android.hardware.usb.UsbDevice):
+    Methods implemented by developers should follow the on<Something> style, was `isDeviceSupported`
+OnNameExpected: android.car.cluster.renderer.InstrumentClusterRenderingService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
+    If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+OnNameExpected: android.car.cluster.renderer.InstrumentClusterRenderingService#getBitmap(android.net.Uri, int, int):
+    If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+OnNameExpected: android.car.cluster.renderer.InstrumentClusterRenderingService#getNavigationRenderer():
+    Methods implemented by developers should follow the on<Something> style, was `getNavigationRenderer`
+OnNameExpected: android.car.cluster.renderer.InstrumentClusterRenderingService#startNavigationActivity(android.content.ComponentName):
+    If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+OnNameExpected: android.car.content.pm.CarAppBlockingPolicyService#getAppBlockingPolicy():
+    Methods implemented by developers should follow the on<Something> style, was `getAppBlockingPolicy`
+OnNameExpected: android.car.input.CarInputHandlingService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
+    If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+
+
+ParcelConstructor: android.car.content.pm.AppBlockingPackageInfo#AppBlockingPackageInfo(android.os.Parcel):
+    Parcelable inflation is exposed through CREATOR, not raw constructors, in android.car.content.pm.AppBlockingPackageInfo
+ParcelConstructor: android.car.content.pm.CarAppBlockingPolicy#CarAppBlockingPolicy(android.os.Parcel):
+    Parcelable inflation is exposed through CREATOR, not raw constructors, in android.car.content.pm.CarAppBlockingPolicy
+ParcelConstructor: android.car.diagnostic.CarDiagnosticEvent#CarDiagnosticEvent(android.os.Parcel):
+    Parcelable inflation is exposed through CREATOR, not raw constructors, in android.car.diagnostic.CarDiagnosticEvent
+ParcelConstructor: android.car.storagemonitoring.IoStats#IoStats(android.os.Parcel):
+    Parcelable inflation is exposed through CREATOR, not raw constructors, in android.car.storagemonitoring.IoStats
+ParcelConstructor: android.car.storagemonitoring.IoStatsEntry#IoStatsEntry(android.os.Parcel):
+    Parcelable inflation is exposed through CREATOR, not raw constructors, in android.car.storagemonitoring.IoStatsEntry
+ParcelConstructor: android.car.storagemonitoring.IoStatsEntry.Metrics#Metrics(android.os.Parcel):
+    Parcelable inflation is exposed through CREATOR, not raw constructors, in android.car.storagemonitoring.IoStatsEntry.Metrics
+ParcelConstructor: android.car.storagemonitoring.LifetimeWriteInfo#LifetimeWriteInfo(android.os.Parcel):
+    Parcelable inflation is exposed through CREATOR, not raw constructors, in android.car.storagemonitoring.LifetimeWriteInfo
+ParcelConstructor: android.car.storagemonitoring.WearEstimate#WearEstimate(android.os.Parcel):
+    Parcelable inflation is exposed through CREATOR, not raw constructors, in android.car.storagemonitoring.WearEstimate
+ParcelConstructor: android.car.storagemonitoring.WearEstimateChange#WearEstimateChange(android.os.Parcel):
+    Parcelable inflation is exposed through CREATOR, not raw constructors, in android.car.storagemonitoring.WearEstimateChange
+ParcelConstructor: android.car.trust.TrustedDeviceInfo#TrustedDeviceInfo(android.os.Parcel):
+    Parcelable inflation is exposed through CREATOR, not raw constructors, in android.car.trust.TrustedDeviceInfo
+
+
+ProtectedMember: android.car.AoapService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
+    Protected methods not allowed; must be public: method android.car.AoapService.dump(java.io.FileDescriptor,java.io.PrintWriter,String[])}
+ProtectedMember: android.car.cluster.renderer.InstrumentClusterRenderer#createNavigationRenderer():
+    Protected methods not allowed; must be public: method android.car.cluster.renderer.InstrumentClusterRenderer.createNavigationRenderer()}
+ProtectedMember: android.car.cluster.renderer.InstrumentClusterRenderingService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
+    Protected methods not allowed; must be public: method android.car.cluster.renderer.InstrumentClusterRenderingService.dump(java.io.FileDescriptor,java.io.PrintWriter,String[])}
+ProtectedMember: android.car.cluster.renderer.InstrumentClusterRenderingService#startNavigationActivity(android.content.ComponentName):
+    Protected methods not allowed; must be public: method android.car.cluster.renderer.InstrumentClusterRenderingService.startNavigationActivity(android.content.ComponentName)}
+ProtectedMember: android.car.content.pm.CarAppBlockingPolicyService#getAppBlockingPolicy():
+    Protected methods not allowed; must be public: method android.car.content.pm.CarAppBlockingPolicyService.getAppBlockingPolicy()}
+ProtectedMember: android.car.input.CarInputHandlingService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
+    Protected methods not allowed; must be public: method android.car.input.CarInputHandlingService.dump(java.io.FileDescriptor,java.io.PrintWriter,String[])}
+ProtectedMember: android.car.input.CarInputHandlingService#onKeyEvent(android.view.KeyEvent, int):
+    Protected methods not allowed; must be public: method android.car.input.CarInputHandlingService.onKeyEvent(android.view.KeyEvent,int)}
+ProtectedMember: android.car.vms.VmsPublisherClientService#onVmsPublisherServiceReady():
+    Protected methods not allowed; must be public: method android.car.vms.VmsPublisherClientService.onVmsPublisherServiceReady()}
+
+
+PublicTypedef: android.car.diagnostic.CarDiagnosticEvent.FuelSystemStatus.Status:
+    Don't expose @IntDef: Status must be hidden.
+PublicTypedef: android.car.diagnostic.CarDiagnosticEvent.FuelType.Type:
+    Don't expose @IntDef: Type must be hidden.
+PublicTypedef: android.car.diagnostic.CarDiagnosticEvent.SecondaryAirStatus.Status:
+    Don't expose @IntDef: Status must be hidden.
+PublicTypedef: android.car.diagnostic.CarDiagnosticManager.FrameType:
+    Don't expose @IntDef: FrameType must be hidden.
+
+
+RegistrationName: android.car.CarProjectionManager#registerProjectionListener(android.car.CarProjectionManager.CarProjectionListener, int):
+    Listener methods should be named add/remove; was registerProjectionListener
+RegistrationName: android.car.CarProjectionManager#registerProjectionStatusListener(android.car.CarProjectionManager.ProjectionStatusListener):
+    Listener methods should be named add/remove; was registerProjectionStatusListener
+RegistrationName: android.car.CarProjectionManager#unregisterProjectionListener():
+    Listener methods should be named add/remove; was unregisterProjectionListener
+RegistrationName: android.car.CarProjectionManager#unregisterProjectionStatusListener(android.car.CarProjectionManager.ProjectionStatusListener):
+    Listener methods should be named add/remove; was unregisterProjectionStatusListener
+RegistrationName: android.car.diagnostic.CarDiagnosticManager#registerListener(android.car.diagnostic.CarDiagnosticManager.OnDiagnosticEventListener, int, int):
+    Listener methods should be named add/remove; was registerListener
+RegistrationName: android.car.diagnostic.CarDiagnosticManager#unregisterListener(android.car.diagnostic.CarDiagnosticManager.OnDiagnosticEventListener):
+    Listener methods should be named add/remove; was unregisterListener
+RegistrationName: android.car.drivingstate.CarDrivingStateManager#registerListener(android.car.drivingstate.CarDrivingStateManager.CarDrivingStateEventListener):
+    Listener methods should be named add/remove; was registerListener
+RegistrationName: android.car.drivingstate.CarDrivingStateManager#unregisterListener():
+    Listener methods should be named add/remove; was unregisterListener
+RegistrationName: android.car.storagemonitoring.CarStorageMonitoringManager#registerListener(android.car.storagemonitoring.CarStorageMonitoringManager.IoStatsListener):
+    Listener methods should be named add/remove; was registerListener
+RegistrationName: android.car.storagemonitoring.CarStorageMonitoringManager#unregisterListener(android.car.storagemonitoring.CarStorageMonitoringManager.IoStatsListener):
+    Listener methods should be named add/remove; was unregisterListener
+
+
+SamShouldBeLast: android.car.CarProjectionManager#registerProjectionListener(android.car.CarProjectionManager.CarProjectionListener, int):
+    SAM-compatible parameters (such as parameter 1, "listener", in android.car.CarProjectionManager.registerProjectionListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.car.diagnostic.CarDiagnosticManager#registerListener(android.car.diagnostic.CarDiagnosticManager.OnDiagnosticEventListener, int, int):
+    SAM-compatible parameters (such as parameter 1, "listener", in android.car.diagnostic.CarDiagnosticManager.registerListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+
+
+ServiceName: android.car.Car#CAR_DRIVING_STATE_SERVICE:
+    Inconsistent service value; expected `CAR_DRIVING_STATE`, was `drivingstate`
+ServiceName: android.car.Car#CAR_TRUST_AGENT_ENROLLMENT_SERVICE:
+    Inconsistent service value; expected `CAR_TRUST_AGENT_ENROLLMENT`, was `trust_enroll`
+ServiceName: android.car.Car#CAR_USER_SERVICE:
+    Inconsistent service value; expected `CAR_USER`, was `car_user_service`
+ServiceName: android.car.Car#PERMISSION_CAR_TEST_SERVICE:
+    Inconsistent service value; expected `PERMISSION_CAR_TEST`, was `android.car.permission.CAR_TEST_SERVICE`
+ServiceName: android.car.Car#TEST_SERVICE:
+    Inconsistent service value; expected `TEST`, was `car-service-test`
+ServiceName: android.car.Car#VMS_SUBSCRIBER_SERVICE:
+    Inconsistent service value; expected `VMS_SUBSCRIBER`, was `vehicle_map_subscriber_service`
+
+
+StartWithLower: android.car.diagnostic.CarDiagnosticEvent.CompressionIgnitionMonitors#EGROrVVT:
+    Non-static field EGROrVVT must be named using fooBar style
+StartWithLower: android.car.diagnostic.CarDiagnosticEvent.CompressionIgnitionMonitors#NMHCCatalyst:
+    Non-static field NMHCCatalyst must be named using fooBar style
+StartWithLower: android.car.diagnostic.CarDiagnosticEvent.CompressionIgnitionMonitors#NOxSCR:
+    Non-static field NOxSCR must be named using fooBar style
+StartWithLower: android.car.diagnostic.CarDiagnosticEvent.CompressionIgnitionMonitors#PMFilter:
+    Non-static field PMFilter must be named using fooBar style
+StartWithLower: android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors#ACRefrigerant:
+    Non-static field ACRefrigerant must be named using fooBar style
+StartWithLower: android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors#EGR:
+    Non-static field EGR must be named using fooBar style
+
+
+UserHandleName: android.car.projection.ProjectionOptions:
+    Classes holding a set of parameters should be called `FooParams`, was `ProjectionOptions`
+
+
+VisiblySynchronized: android.car.drivingstate.CarDrivingStateManager#registerListener(android.car.drivingstate.CarDrivingStateManager.CarDrivingStateEventListener):
+    Internal locks must not be exposed: method android.car.drivingstate.CarDrivingStateManager.registerListener(android.car.drivingstate.CarDrivingStateManager.CarDrivingStateEventListener)
+VisiblySynchronized: android.car.drivingstate.CarDrivingStateManager#unregisterListener():
+    Internal locks must not be exposed: method android.car.drivingstate.CarDrivingStateManager.unregisterListener()
+VisiblySynchronized: android.car.hardware.cabin.CarCabinManager#registerCallback(android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback):
+    Internal locks must not be exposed: method android.car.hardware.cabin.CarCabinManager.registerCallback(android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback)
+VisiblySynchronized: android.car.hardware.cabin.CarCabinManager#unregisterCallback(android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback):
+    Internal locks must not be exposed: method android.car.hardware.cabin.CarCabinManager.unregisterCallback(android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback)
+VisiblySynchronized: android.car.hardware.hvac.CarHvacManager#registerCallback(android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback):
+    Internal locks must not be exposed: method android.car.hardware.hvac.CarHvacManager.registerCallback(android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback)
+VisiblySynchronized: android.car.hardware.hvac.CarHvacManager#unregisterCallback(android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback):
+    Internal locks must not be exposed: method android.car.hardware.hvac.CarHvacManager.unregisterCallback(android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback)
diff --git a/car-lib/api/system-released/system-1.txt b/car-lib/api/system-released/system-1.txt
deleted file mode 100644
index e58b9be..0000000
--- a/car-lib/api/system-released/system-1.txt
+++ /dev/null
@@ -1,787 +0,0 @@
-package android.car {
-
-  public final class Car {
-    method public void connect() throws java.lang.IllegalStateException;
-    method public static android.car.Car createCar(android.content.Context, android.content.ServiceConnection, android.os.Handler);
-    method public static android.car.Car createCar(android.content.Context, android.content.ServiceConnection);
-    method public void disconnect();
-    method public int getCarConnectionType();
-    method public java.lang.Object getCarManager(java.lang.String) throws android.car.CarNotConnectedException;
-    method public boolean isConnected();
-    method public boolean isConnecting();
-    field public static final java.lang.String APP_FOCUS_SERVICE = "app_focus";
-    field public static final java.lang.String AUDIO_SERVICE = "audio";
-    field public static final java.lang.String CABIN_SERVICE = "cabin";
-    field public static final java.lang.String CAMERA_SERVICE = "camera";
-    field public static final int CONNECTION_TYPE_EMBEDDED = 5; // 0x5
-    field public static final java.lang.String HVAC_SERVICE = "hvac";
-    field public static final java.lang.String INFO_SERVICE = "info";
-    field public static final java.lang.String PACKAGE_SERVICE = "package";
-    field public static final java.lang.String PERMISSION_CAR_CABIN = "android.car.permission.CAR_CABIN";
-    field public static final java.lang.String PERMISSION_CAR_CAMERA = "android.car.permission.CAR_CAMERA";
-    field public static final java.lang.String PERMISSION_CAR_CONTROL_AUDIO_VOLUME = "android.car.permission.CAR_CONTROL_AUDIO_VOLUME";
-    field public static final java.lang.String PERMISSION_CAR_HVAC = "android.car.permission.CAR_HVAC";
-    field public static final java.lang.String PERMISSION_CAR_PROJECTION = "android.car.permission.CAR_PROJECTION";
-    field public static final java.lang.String PERMISSION_CAR_RADIO = "android.car.permission.CAR_RADIO";
-    field public static final java.lang.String PERMISSION_CONTROL_APP_BLOCKING = "android.car.permission.CONTROL_APP_BLOCKING";
-    field public static final java.lang.String PERMISSION_FUEL = "android.car.permission.CAR_FUEL";
-    field public static final java.lang.String PERMISSION_MILEAGE = "android.car.permission.CAR_MILEAGE";
-    field public static final java.lang.String PERMISSION_MOCK_VEHICLE_HAL = "android.car.permission.CAR_MOCK_VEHICLE_HAL";
-    field public static final java.lang.String PERMISSION_SPEED = "android.car.permission.CAR_SPEED";
-    field public static final java.lang.String PERMISSION_VENDOR_EXTENSION = "android.car.permission.CAR_VENDOR_EXTENSION";
-    field public static final java.lang.String PROJECTION_SERVICE = "projection";
-    field public static final java.lang.String RADIO_SERVICE = "radio";
-    field public static final java.lang.String SENSOR_SERVICE = "sensor";
-    field public static final java.lang.String TEST_SERVICE = "car-service-test";
-    field public static final java.lang.String VENDOR_EXTENSION_SERVICE = "vendor_extension";
-    field public static final int VERSION = 1; // 0x1
-  }
-
-  public final class CarAppFocusManager {
-    method public void abandonAppFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback, int);
-    method public void abandonAppFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback);
-    method public void addFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener, int) throws android.car.CarNotConnectedException;
-    method public boolean isOwningFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback, int) throws android.car.CarNotConnectedException;
-    method public void removeFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener, int);
-    method public void removeFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener);
-    method public int requestAppFocus(int, android.car.CarAppFocusManager.OnAppFocusOwnershipCallback) throws android.car.CarNotConnectedException, java.lang.SecurityException;
-    field public static final int APP_FOCUS_REQUEST_FAILED = 0; // 0x0
-    field public static final int APP_FOCUS_REQUEST_SUCCEEDED = 1; // 0x1
-    field public static final int APP_FOCUS_TYPE_NAVIGATION = 1; // 0x1
-    field public static final int APP_FOCUS_TYPE_VOICE_COMMAND = 2; // 0x2
-  }
-
-  public static abstract interface CarAppFocusManager.OnAppFocusChangedListener {
-    method public abstract void onAppFocusChanged(int, boolean);
-  }
-
-  public static abstract interface CarAppFocusManager.OnAppFocusOwnershipCallback {
-    method public abstract void onAppFocusOwnershipGranted(int);
-    method public abstract void onAppFocusOwnershipLost(int);
-  }
-
-  public final class CarInfoManager {
-    method public java.lang.String getManufacturer() throws android.car.CarNotConnectedException;
-    method public java.lang.String getModel() throws android.car.CarNotConnectedException;
-    method public java.lang.String getModelYear() throws android.car.CarNotConnectedException;
-    method public java.lang.String getVehicleId() throws android.car.CarNotConnectedException;
-  }
-
-  public class CarNotConnectedException extends java.lang.Exception {
-    ctor public CarNotConnectedException();
-    ctor public CarNotConnectedException(java.lang.String);
-    ctor public CarNotConnectedException(java.lang.String, java.lang.Throwable);
-    ctor public CarNotConnectedException(java.lang.Exception);
-  }
-
-  public final class CarProjectionManager {
-    method public void onCarDisconnected();
-    method public void registerProjectionRunner(android.content.Intent) throws android.car.CarNotConnectedException;
-    method public void registerProjectionListener(android.car.CarProjectionManager.CarProjectionListener, int) throws android.car.CarNotConnectedException;
-    method public void unregisterProjectionRunner(android.content.Intent);
-    method public void unregisterProjectionListener();
-    field public static final int PROJECTION_LONG_PRESS_VOICE_SEARCH = 2; // 0x2
-    field public static final int PROJECTION_VOICE_SEARCH = 1; // 0x1
-  }
-
-  public static abstract interface CarProjectionManager.CarProjectionListener {
-    method public abstract void onVoiceAssistantRequest(boolean);
-  }
-
-  public final class VehicleAreaType {
-    field public static final int VEHICLE_AREA_TYPE_DOOR = 4; // 0x4
-    field public static final int VEHICLE_AREA_TYPE_MIRROR = 5; // 0x5
-    field public static final int VEHICLE_AREA_TYPE_NONE = 0; // 0x0
-    field public static final int VEHICLE_AREA_TYPE_SEAT = 3; // 0x3
-    field public static final int VEHICLE_AREA_TYPE_WINDOW = 2; // 0x2
-    field public static final int VEHICLE_AREA_TYPE_ZONE = 1; // 0x1
-  }
-
-  public final class VehicleDoor {
-    field public static final int DOOR_HOOD = 268435456; // 0x10000000
-    field public static final int DOOR_REAR = 536870912; // 0x20000000
-    field public static final int DOOR_ROW_1_LEFT = 1; // 0x1
-    field public static final int DOOR_ROW_1_RIGHT = 4; // 0x4
-    field public static final int DOOR_ROW_2_LEFT = 16; // 0x10
-    field public static final int DOOR_ROW_2_RIGHT = 64; // 0x40
-    field public static final int DOOR_ROW_3_LEFT = 256; // 0x100
-    field public static final int DOOR_ROW_3_RIGHT = 1024; // 0x400
-  }
-
-  public final class VehicleMirror {
-    field public static final int MIRROR_DRIVER_CENTER = 4; // 0x4
-    field public static final int MIRROR_DRIVER_LEFT = 1; // 0x1
-    field public static final int MIRROR_DRIVER_RIGHT = 2; // 0x2
-  }
-
-  public final class VehicleSeat {
-    field public static final int SEAT_ROW_1_CENTER = 2; // 0x2
-    field public static final int SEAT_ROW_1_LEFT = 1; // 0x1
-    field public static final int SEAT_ROW_1_RIGHT = 4; // 0x4
-    field public static final int SEAT_ROW_2_CENTER = 32; // 0x20
-    field public static final int SEAT_ROW_2_LEFT = 16; // 0x10
-    field public static final int SEAT_ROW_2_RIGHT = 64; // 0x40
-    field public static final int SEAT_ROW_3_CENTER = 512; // 0x200
-    field public static final int SEAT_ROW_3_LEFT = 256; // 0x100
-    field public static final int SEAT_ROW_3_RIGHT = 1024; // 0x400
-  }
-
-  public final class VehicleWindow {
-    field public static final int WINDOW_FRONT_WINDSHIELD = 1; // 0x1
-    field public static final int WINDOW_REAR_WINDSHIELD = 2; // 0x2
-    field public static final int WINDOW_ROOF_TOP = 4; // 0x4
-    field public static final int WINDOW_ROW_1_LEFT = 16; // 0x10
-    field public static final int WINDOW_ROW_1_RIGHT = 32; // 0x20
-    field public static final int WINDOW_ROW_2_LEFT = 256; // 0x100
-    field public static final int WINDOW_ROW_2_RIGHT = 512; // 0x200
-    field public static final int WINDOW_ROW_3_LEFT = 4096; // 0x1000
-    field public static final int WINDOW_ROW_3_RIGHT = 8192; // 0x2000
-  }
-
-  public final class VehicleZone {
-    field public static final int ZONE_ALL = -2147483648; // 0x80000000
-    field public static final int ZONE_ROW_1_ALL = 8; // 0x8
-    field public static final int ZONE_ROW_1_CENTER = 2; // 0x2
-    field public static final int ZONE_ROW_1_LEFT = 1; // 0x1
-    field public static final int ZONE_ROW_1_RIGHT = 4; // 0x4
-    field public static final int ZONE_ROW_2_ALL = 128; // 0x80
-    field public static final int ZONE_ROW_2_CENTER = 32; // 0x20
-    field public static final int ZONE_ROW_2_LEFT = 16; // 0x10
-    field public static final int ZONE_ROW_2_RIGHT = 64; // 0x40
-    field public static final int ZONE_ROW_3_ALL = 2048; // 0x800
-    field public static final int ZONE_ROW_3_CENTER = 512; // 0x200
-    field public static final int ZONE_ROW_3_LEFT = 256; // 0x100
-    field public static final int ZONE_ROW_3_RIGHT = 1024; // 0x400
-    field public static final int ZONE_ROW_4_ALL = 32768; // 0x8000
-    field public static final int ZONE_ROW_4_CENTER = 8192; // 0x2000
-    field public static final int ZONE_ROW_4_LEFT = 4096; // 0x1000
-    field public static final int ZONE_ROW_4_RIGHT = 16384; // 0x4000
-  }
-
-  public final class VehicleZoneUtil {
-    method public static int getFirstZone(int);
-    method public static int getNextZone(int, int) throws java.lang.IllegalArgumentException;
-    method public static int getNumberOfZones(int);
-    method public static int[] listAllZones(int);
-    method public static int zoneToIndex(int, int) throws java.lang.IllegalArgumentException;
-  }
-
-}
-
-package android.car.app.menu {
-
-  public abstract class CarMenuCallbacks {
-    ctor public CarMenuCallbacks();
-    method public abstract android.car.app.menu.RootMenu getRootMenu(android.os.Bundle);
-    method public abstract void onCarMenuClosed();
-    method public abstract void onCarMenuClosing();
-    method public abstract void onCarMenuOpened();
-    method public abstract void onCarMenuOpening();
-    method public abstract void onItemClicked(java.lang.String);
-    method public abstract boolean onItemLongClicked(java.lang.String);
-    method public abstract boolean onMenuClicked();
-    method public abstract void subscribe(java.lang.String, android.car.app.menu.SubscriptionCallbacks);
-    method public abstract void unsubscribe(java.lang.String, android.car.app.menu.SubscriptionCallbacks);
-  }
-
-  public class CarMenuConstants {
-    ctor public CarMenuConstants();
-  }
-
-  public static class CarMenuConstants.MenuItemConstants {
-    ctor public CarMenuConstants.MenuItemConstants();
-    field public static final int FLAG_BROWSABLE = 1; // 0x1
-    field public static final int FLAG_FIRSTITEM = 2; // 0x2
-    field public static final java.lang.String KEY_EMPTY_PLACEHOLDER = "android.car.app.menu.empty_placeholder";
-    field public static final java.lang.String KEY_FLAGS = "android.car.app.menu.flags";
-    field public static final java.lang.String KEY_ID = "android.car.app.menu.id";
-    field public static final java.lang.String KEY_LEFTICON = "android.car.app.menu.leftIcon";
-    field public static final java.lang.String KEY_REMOTEVIEWS = "android.car.app.menu.remoteViews";
-    field public static final java.lang.String KEY_RIGHTICON = "android.car.app.menu.rightIcon";
-    field public static final java.lang.String KEY_RIGHTTEXT = "android.car.app.menu.rightText";
-    field public static final java.lang.String KEY_TEXT = "android.car.app.menu.text";
-    field public static final java.lang.String KEY_TITLE = "android.car.app.menu.title";
-    field public static final java.lang.String KEY_WIDGET = "android.car.app.menu.widget";
-    field public static final java.lang.String KEY_WIDGET_STATE = "android.car.app.menu.widget_state";
-    field public static final int WIDGET_CHECKBOX = 1; // 0x1
-    field public static final int WIDGET_TEXT_VIEW = 2; // 0x2
-  }
-
-  public static abstract class CarMenuConstants.MenuItemConstants.MenuItemFlags implements java.lang.annotation.Annotation {
-  }
-
-  public static abstract class CarMenuConstants.MenuItemConstants.WidgetTypes implements java.lang.annotation.Annotation {
-  }
-
-  public abstract class CarUiEntry {
-    ctor public CarUiEntry(android.content.Context, android.content.Context);
-    method public abstract void closeDrawer();
-    method public abstract android.view.View getContentView();
-    method public abstract int getFragmentContainerId();
-    method public abstract java.lang.CharSequence getSearchBoxText();
-    method public abstract void hideMenuButton();
-    method public abstract void hideTitle();
-    method public abstract void onPause();
-    method public abstract void onRestoreInstanceState(android.os.Bundle);
-    method public abstract void onResume();
-    method public abstract void onSaveInstanceState(android.os.Bundle);
-    method public abstract void onStart();
-    method public abstract void onStop();
-    method public abstract void openDrawer();
-    method public abstract void restoreMenuDrawable();
-    method public abstract void setAutoLightDarkMode();
-    method public abstract void setBackground(android.graphics.Bitmap);
-    method public abstract void setCarMenuCallbacks(android.car.app.menu.CarMenuCallbacks);
-    method public abstract void setDarkMode();
-    method public abstract void setLightMode();
-    method public abstract void setMenuButtonBitmap(android.graphics.Bitmap);
-    method public abstract void setMenuButtonColor(int);
-    method public abstract void setScrimColor(int);
-    method public abstract void setSearchBoxColors(int, int, int, int);
-    method public abstract void setSearchBoxEditListener(android.car.app.menu.SearchBoxEditListener);
-    method public abstract void setSearchBoxEndView(android.view.View);
-    method public abstract void setTitle(java.lang.CharSequence);
-    method public abstract void showMenu(java.lang.String, java.lang.String);
-    method public abstract void showSearchBox(android.view.View.OnClickListener);
-    method public abstract void showTitle();
-    method public abstract void showToast(java.lang.String, long);
-    method public abstract android.widget.EditText startInput(java.lang.String, android.view.View.OnClickListener);
-    method public abstract void stopInput();
-    field protected final android.content.Context mAppContext;
-    field protected final android.content.Context mUiLibContext;
-  }
-
-  public class RootMenu {
-    ctor public RootMenu(java.lang.String);
-    ctor public RootMenu(java.lang.String, android.os.Bundle);
-    method public android.os.Bundle getBundle();
-    method public java.lang.String getId();
-  }
-
-  public abstract class SearchBoxEditListener {
-    ctor public SearchBoxEditListener();
-    method public abstract void onEdit(java.lang.String);
-    method public abstract void onSearch(java.lang.String);
-  }
-
-  public abstract class SubscriptionCallbacks {
-    ctor public SubscriptionCallbacks();
-    method public abstract void onChildChanged(java.lang.String, android.os.Bundle);
-    method public abstract void onChildrenLoaded(java.lang.String, java.util.List<android.os.Bundle>);
-    method public abstract void onError(java.lang.String);
-  }
-
-}
-
-package android.car.cluster.renderer {
-
-  public class DisplayConfiguration implements android.os.Parcelable {
-    ctor public DisplayConfiguration(android.os.Parcel);
-    ctor public DisplayConfiguration(android.graphics.Rect);
-    ctor public DisplayConfiguration(android.graphics.Rect, android.graphics.Rect);
-    method public int describeContents();
-    method public android.graphics.Rect getPrimaryRegion();
-    method public android.graphics.Rect getSecondaryRegion();
-    method public boolean hasSecondaryRegion();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.cluster.renderer.DisplayConfiguration> CREATOR;
-  }
-
-  public abstract class InstrumentClusterRenderer {
-    ctor public InstrumentClusterRenderer();
-    method protected abstract android.car.cluster.renderer.NavigationRenderer createNavigationRenderer();
-    method public synchronized android.car.cluster.renderer.NavigationRenderer getNavigationRenderer();
-    method public final synchronized void initialize();
-    method public abstract void onCreate(android.content.Context);
-    method public abstract void onStart();
-    method public abstract void onStop();
-  }
-
-  public abstract class InstrumentClusterRenderingService extends android.app.Service {
-    ctor public InstrumentClusterRenderingService();
-    method protected abstract android.car.cluster.renderer.NavigationRenderer getNavigationRenderer();
-    method public android.os.IBinder onBind(android.content.Intent);
-    method protected void onKeyEvent(android.view.KeyEvent);
-  }
-
-  public abstract class NavigationRenderer {
-    ctor public NavigationRenderer();
-    method public abstract android.car.navigation.CarNavigationInstrumentCluster getNavigationProperties();
-    method public abstract void onNextTurnChanged(int, java.lang.CharSequence, int, int, android.graphics.Bitmap, int);
-    method public abstract void onNextTurnDistanceChanged(int, int, int, int);
-    method public abstract void onStartNavigation();
-    method public abstract void onStopNavigation();
-  }
-
-}
-
-package android.car.content.pm {
-
-  public class AppBlockingPackageInfo implements android.os.Parcelable {
-    ctor public AppBlockingPackageInfo(java.lang.String, int, int, int, android.content.pm.Signature[], java.lang.String[]);
-    ctor public AppBlockingPackageInfo(android.os.Parcel);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.content.pm.AppBlockingPackageInfo> CREATOR;
-    field public static final int FLAG_SYSTEM_APP = 1; // 0x1
-    field public static final int FLAG_WHOLE_ACTIVITY = 2; // 0x2
-    field public final java.lang.String[] activities;
-    field public final int flags;
-    field public final int maxRevisionCode;
-    field public final int minRevisionCode;
-    field public final java.lang.String packageName;
-    field public final android.content.pm.Signature[] signatures;
-  }
-
-  public class CarAppBlockingPolicy implements android.os.Parcelable {
-    ctor public CarAppBlockingPolicy(android.car.content.pm.AppBlockingPackageInfo[], android.car.content.pm.AppBlockingPackageInfo[]);
-    ctor public CarAppBlockingPolicy(android.os.Parcel);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.content.pm.CarAppBlockingPolicy> CREATOR;
-    field public final android.car.content.pm.AppBlockingPackageInfo[] blacklists;
-    field public final android.car.content.pm.AppBlockingPackageInfo[] whitelists;
-  }
-
-  public abstract class CarAppBlockingPolicyService extends android.app.Service {
-    ctor public CarAppBlockingPolicyService();
-    method protected abstract android.car.content.pm.CarAppBlockingPolicy getAppBlockingPolicy();
-    method public android.os.IBinder onBind(android.content.Intent);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.car.content.pm.CarAppBlockingPolicyService";
-  }
-
-  public final class CarPackageManager {
-    method public boolean isActivityAllowedWhileDriving(java.lang.String, java.lang.String) throws android.car.CarNotConnectedException;
-    method public boolean isActivityBackedBySafeActivity(android.content.ComponentName) throws android.car.CarNotConnectedException;
-    method public boolean isServiceAllowedWhileDriving(java.lang.String, java.lang.String) throws android.car.CarNotConnectedException;
-    method public void setAppBlockingPolicy(java.lang.String, android.car.content.pm.CarAppBlockingPolicy, int) throws android.car.CarNotConnectedException, java.lang.IllegalArgumentException, java.lang.SecurityException;
-    field public static final int FLAG_SET_POLICY_ADD = 2; // 0x2
-    field public static final int FLAG_SET_POLICY_REMOVE = 4; // 0x4
-    field public static final int FLAG_SET_POLICY_WAIT_FOR_CHANGE = 1; // 0x1
-  }
-
-}
-
-package android.car.hardware {
-
-  public class CarPropertyConfig<T> implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getAreaCount();
-    method public int[] getAreaIds();
-    method public int getAreaType();
-    method public int getFirstAndOnlyAreaId();
-    method public T getMaxValue(int);
-    method public T getMaxValue();
-    method public T getMinValue(int);
-    method public T getMinValue();
-    method public int getPropertyId();
-    method public java.lang.Class<T> getPropertyType();
-    method public boolean hasArea(int);
-    method public boolean isGlobalProperty();
-    method public static <T> android.car.hardware.CarPropertyConfig.Builder<T> newBuilder(java.lang.Class<T>, int, int, int);
-    method public static <T> android.car.hardware.CarPropertyConfig.Builder<T> newBuilder(java.lang.Class<T>, int, int);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.hardware.CarPropertyConfig> CREATOR;
-  }
-
-  public static class CarPropertyConfig.AreaConfig<T> implements android.os.Parcelable {
-    method public int describeContents();
-    method public T getMaxValue();
-    method public T getMinValue();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.hardware.CarPropertyConfig.AreaConfig<java.lang.Object>> CREATOR;
-  }
-
-  public static class CarPropertyConfig.Builder<T> {
-    method public android.car.hardware.CarPropertyConfig.Builder<T> addArea(int);
-    method public android.car.hardware.CarPropertyConfig.Builder<T> addAreaConfig(int, T, T);
-    method public android.car.hardware.CarPropertyConfig.Builder<T> addAreas(int[]);
-    method public android.car.hardware.CarPropertyConfig<T> build();
-  }
-
-  public class CarPropertyValue<T> implements android.os.Parcelable {
-    ctor public CarPropertyValue(int, T);
-    ctor public CarPropertyValue(int, int, T);
-    ctor public CarPropertyValue(android.os.Parcel);
-    method public int describeContents();
-    method public int getAreaId();
-    method public int getPropertyId();
-    method public T getValue();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.hardware.CarPropertyValue> CREATOR;
-  }
-
-  public class CarSensorEvent implements android.os.Parcelable {
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.hardware.CarSensorEvent> CREATOR;
-    field public static final int DRIVE_STATUS_FULLY_RESTRICTED = 31; // 0x1f
-    field public static final int DRIVE_STATUS_LIMIT_MESSAGE_LEN = 16; // 0x10
-    field public static final int DRIVE_STATUS_NO_CONFIG = 8; // 0x8
-    field public static final int DRIVE_STATUS_NO_KEYBOARD_INPUT = 2; // 0x2
-    field public static final int DRIVE_STATUS_NO_VIDEO = 1; // 0x1
-    field public static final int DRIVE_STATUS_NO_VOICE_INPUT = 4; // 0x4
-    field public static final int DRIVE_STATUS_UNRESTRICTED = 0; // 0x0
-    field public static final int GEAR_DRIVE = 100; // 0x64
-    field public static final int GEAR_EIGHTH = 8; // 0x8
-    field public static final int GEAR_FIFTH = 5; // 0x5
-    field public static final int GEAR_FIRST = 1; // 0x1
-    field public static final int GEAR_FOURTH = 4; // 0x4
-    field public static final int GEAR_NEUTRAL = 0; // 0x0
-    field public static final int GEAR_NINTH = 9; // 0x9
-    field public static final int GEAR_PARK = 101; // 0x65
-    field public static final int GEAR_REVERSE = 102; // 0x66
-    field public static final int GEAR_SECOND = 2; // 0x2
-    field public static final int GEAR_SEVENTH = 7; // 0x7
-    field public static final int GEAR_SIXTH = 6; // 0x6
-    field public static final int GEAR_TENTH = 10; // 0xa
-    field public static final int GEAR_THIRD = 3; // 0x3
-    field public static final int INDEX_ENVIRONMENT_PRESSURE = 1; // 0x1
-    field public static final int INDEX_ENVIRONMENT_TEMPERATURE = 0; // 0x0
-    field public static final int INDEX_FUEL_LEVEL_IN_DISTANCE = 1; // 0x1
-    field public static final int INDEX_FUEL_LEVEL_IN_PERCENTILE = 0; // 0x0
-    field public static final int INDEX_FUEL_LOW_WARNING = 0; // 0x0
-    field public final float[] floatValues;
-    field public final int[] intValues;
-    field public int sensorType;
-    field public long timestamp;
-  }
-
-  public static class CarSensorEvent.EnvironmentData {
-    field public float pressure;
-    field public float temperature;
-    field public long timestamp;
-  }
-
-  public final class CarSensorManager {
-    method public android.car.hardware.CarSensorEvent getLatestSensorEvent(int) throws android.car.CarNotConnectedException;
-    method public int[] getSupportedSensors() throws android.car.CarNotConnectedException;
-    method public boolean isSensorSupported(int) throws android.car.CarNotConnectedException;
-    method public static boolean isSensorSupported(int[], int);
-    method public boolean registerListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int, int) throws android.car.CarNotConnectedException, java.lang.IllegalArgumentException;
-    method public void unregisterListener(android.car.hardware.CarSensorManager.OnSensorChangedListener);
-    method public void unregisterListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int);
-    field public static final int SENSOR_RATE_FAST = 1; // 0x1
-    field public static final int SENSOR_RATE_FASTEST = 0; // 0x0
-    field public static final int SENSOR_RATE_NORMAL = 3; // 0x3
-    field public static final int SENSOR_RATE_UI = 2; // 0x2
-    field public static final int SENSOR_TYPE_CAR_SPEED = 2; // 0x2
-    field public static final int SENSOR_TYPE_DRIVING_STATUS = 11; // 0xb
-    field public static final int SENSOR_TYPE_ENVIRONMENT = 12; // 0xc
-    field public static final int SENSOR_TYPE_FUEL_LEVEL = 5; // 0x5
-    field public static final int SENSOR_TYPE_GEAR = 7; // 0x7
-    field public static final int SENSOR_TYPE_NIGHT = 9; // 0x9
-    field public static final int SENSOR_TYPE_ODOMETER = 4; // 0x4
-    field public static final int SENSOR_TYPE_PARKING_BRAKE = 6; // 0x6
-    field public static final int SENSOR_TYPE_RPM = 3; // 0x3
-    field public static final int SENSOR_TYPE_VENDOR_EXTENSION_END = 1879048191; // 0x6fffffff
-  }
-
-  public static abstract interface CarSensorManager.OnSensorChangedListener {
-    method public abstract void onSensorChanged(android.car.hardware.CarSensorEvent);
-  }
-
-  public final class CarVendorExtensionManager {
-    method public <E> E getGlobalProperty(java.lang.Class<E>, int) throws android.car.CarNotConnectedException;
-    method public java.util.List<android.car.hardware.CarPropertyConfig> getProperties() throws android.car.CarNotConnectedException;
-    method public <E> E getProperty(java.lang.Class<E>, int, int) throws android.car.CarNotConnectedException;
-    method public void registerCallback(android.car.hardware.CarVendorExtensionManager.CarVendorExtensionCallback) throws android.car.CarNotConnectedException;
-    method public <E> void setGlobalProperty(java.lang.Class<E>, int, E) throws android.car.CarNotConnectedException;
-    method public <E> void setProperty(java.lang.Class<E>, int, int, E) throws android.car.CarNotConnectedException;
-    method public void unregisterCallback(android.car.hardware.CarVendorExtensionManager.CarVendorExtensionCallback);
-  }
-
-  public static abstract interface CarVendorExtensionManager.CarVendorExtensionCallback {
-    method public abstract void onChangeEvent(android.car.hardware.CarPropertyValue);
-    method public abstract void onErrorEvent(int, int);
-  }
-
-}
-
-package android.car.hardware.cabin {
-
-  public final class CarCabinManager {
-    method public boolean getBooleanProperty(int, int) throws android.car.CarNotConnectedException;
-    method public float getFloatProperty(int, int) throws android.car.CarNotConnectedException;
-    method public int getIntProperty(int, int) throws android.car.CarNotConnectedException;
-    method public java.util.List<android.car.hardware.CarPropertyConfig> getPropertyList() throws android.car.CarNotConnectedException;
-    method public static boolean isZonedProperty(int);
-    method public synchronized void registerCallback(android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback) throws android.car.CarNotConnectedException;
-    method public void setBooleanProperty(int, int, boolean) throws android.car.CarNotConnectedException;
-    method public void setFloatProperty(int, int, float) throws android.car.CarNotConnectedException;
-    method public void setIntProperty(int, int, int) throws android.car.CarNotConnectedException;
-    method public synchronized void unregisterCallback(android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback);
-    field public static final int ID_DOOR_LOCK = 3; // 0x3
-    field public static final int ID_DOOR_MOVE = 2; // 0x2
-    field public static final int ID_DOOR_POS = 1; // 0x1
-    field public static final int ID_MIRROR_FOLD = 4102; // 0x1006
-    field public static final int ID_MIRROR_LOCK = 4101; // 0x1005
-    field public static final int ID_MIRROR_Y_MOVE = 4100; // 0x1004
-    field public static final int ID_MIRROR_Y_POS = 4099; // 0x1003
-    field public static final int ID_MIRROR_Z_MOVE = 4098; // 0x1002
-    field public static final int ID_MIRROR_Z_POS = 4097; // 0x1001
-    field public static final int ID_SEAT_BACKREST_ANGLE_1_MOVE = 8201; // 0x2009
-    field public static final int ID_SEAT_BACKREST_ANGLE_1_POS = 8200; // 0x2008
-    field public static final int ID_SEAT_BACKREST_ANGLE_2_MOVE = 8203; // 0x200b
-    field public static final int ID_SEAT_BACKREST_ANGLE_2_POS = 8202; // 0x200a
-    field public static final int ID_SEAT_BELT_BUCKLED = 8195; // 0x2003
-    field public static final int ID_SEAT_BELT_HEIGHT_MOVE = 8197; // 0x2005
-    field public static final int ID_SEAT_BELT_HEIGHT_POS = 8196; // 0x2004
-    field public static final int ID_SEAT_DEPTH_MOVE = 8207; // 0x200f
-    field public static final int ID_SEAT_DEPTH_POS = 8206; // 0x200e
-    field public static final int ID_SEAT_FORE_AFT_MOVE = 8199; // 0x2007
-    field public static final int ID_SEAT_FORE_AFT_POS = 8198; // 0x2006
-    field public static final int ID_SEAT_HEADREST_ANGLE_MOVE = 8217; // 0x2019
-    field public static final int ID_SEAT_HEADREST_ANGLE_POS = 8216; // 0x2018
-    field public static final int ID_SEAT_HEADREST_FORE_AFT_MOVE = 8219; // 0x201b
-    field public static final int ID_SEAT_HEADREST_FORE_AFT_POS = 8218; // 0x201a
-    field public static final int ID_SEAT_HEADREST_HEIGHT_MOVE = 8215; // 0x2017
-    field public static final int ID_SEAT_HEADREST_HEIGHT_POS = 8214; // 0x2016
-    field public static final int ID_SEAT_HEIGHT_MOVE = 8205; // 0x200d
-    field public static final int ID_SEAT_HEIGHT_POS = 8204; // 0x200c
-    field public static final int ID_SEAT_LUMBAR_FORE_AFT_MOVE = 8211; // 0x2013
-    field public static final int ID_SEAT_LUMBAR_FORE_AFT_POS = 8210; // 0x2012
-    field public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 8213; // 0x2015
-    field public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_POS = 8212; // 0x2014
-    field public static final int ID_SEAT_MEMORY_SELECT = 8193; // 0x2001
-    field public static final int ID_SEAT_MEMORY_SET = 8194; // 0x2002
-    field public static final int ID_SEAT_TILT_MOVE = 8209; // 0x2011
-    field public static final int ID_SEAT_TILT_POS = 8208; // 0x2010
-    field public static final int ID_WINDOW_LOCK = 12293; // 0x3005
-    field public static final int ID_WINDOW_MOVE = 12290; // 0x3002
-    field public static final int ID_WINDOW_POS = 12289; // 0x3001
-    field public static final int ID_WINDOW_VENT_MOVE = 12292; // 0x3004
-    field public static final int ID_WINDOW_VENT_POS = 12291; // 0x3003
-  }
-
-  public static abstract interface CarCabinManager.CarCabinEventCallback {
-    method public abstract void onChangeEvent(android.car.hardware.CarPropertyValue);
-    method public abstract void onErrorEvent(int, int);
-  }
-
-}
-
-package android.car.hardware.camera {
-
-  public class CarCamera {
-    ctor public CarCamera(android.car.hardware.camera.ICarCamera, int);
-    method public android.graphics.Rect getCameraCrop() throws android.car.CarNotConnectedException;
-    method public android.graphics.Rect getCameraPosition() throws android.car.CarNotConnectedException;
-    method public android.car.hardware.camera.CarCameraState getCameraState() throws android.car.CarNotConnectedException;
-    method public int getCapabilities() throws android.car.CarNotConnectedException;
-    method public void setCameraCrop(android.graphics.Rect) throws android.car.CarNotConnectedException;
-    method public void setCameraPosition(android.graphics.Rect) throws android.car.CarNotConnectedException;
-    method public void setCameraState(android.car.hardware.camera.CarCameraState) throws android.car.CarNotConnectedException;
-    field public static final java.lang.String TAG;
-    field public final int mCameraType;
-  }
-
-  public final class CarCameraManager {
-    method public void closeCamera(android.car.hardware.camera.CarCamera);
-    method public int getCameraCapabilities(int) throws android.car.CarNotConnectedException;
-    method public int[] getCameraList() throws android.car.CarNotConnectedException;
-    method public android.car.hardware.camera.CarCamera openCamera(int) throws android.car.CarNotConnectedException;
-    field public static final int ANDROID_OVERLAY_SUPPORT_FLAG = 1; // 0x1
-    field public static final int CAMERA_CROP_SUPPORT_FLAG = 2; // 0x2
-    field public static final int CAMERA_POSITIONING_SUPPORT_FLAG = 4; // 0x4
-    field public static final int CAR_CAMERA_TYPE_NONE = 0; // 0x0
-    field public static final int CAR_CAMERA_TYPE_RVC = 1; // 0x1
-  }
-
-  public class CarCameraState implements android.os.Parcelable {
-    ctor public CarCameraState(android.car.hardware.camera.CarCameraState);
-    ctor public CarCameraState(boolean, boolean);
-    method public int describeContents();
-    method public boolean getCameraIsOn();
-    method public boolean getOverlayIsOn();
-    method public void setCameraIsOn(boolean);
-    method public void setOverlayIsOn(boolean);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.hardware.camera.CarCameraState> CREATOR;
-  }
-
-  public abstract interface ICarCamera implements android.os.IInterface {
-    method public abstract android.graphics.Rect getCameraCrop(int) throws android.os.RemoteException;
-    method public abstract int[] getCameraList() throws android.os.RemoteException;
-    method public abstract android.graphics.Rect getCameraPosition(int) throws android.os.RemoteException;
-    method public abstract android.car.hardware.camera.CarCameraState getCameraState(int) throws android.os.RemoteException;
-    method public abstract int getCapabilities(int) throws android.os.RemoteException;
-    method public abstract void setCameraCrop(int, android.graphics.Rect) throws android.os.RemoteException;
-    method public abstract void setCameraPosition(int, android.graphics.Rect) throws android.os.RemoteException;
-    method public abstract void setCameraState(int, android.car.hardware.camera.CarCameraState) throws android.os.RemoteException;
-  }
-
-}
-
-package android.car.hardware.hvac {
-
-  public final class CarHvacManager {
-    method public boolean getBooleanProperty(int, int) throws android.car.CarNotConnectedException;
-    method public float getFloatProperty(int, int) throws android.car.CarNotConnectedException;
-    method public int getIntProperty(int, int) throws android.car.CarNotConnectedException;
-    method public java.util.List<android.car.hardware.CarPropertyConfig> getPropertyList() throws android.car.CarNotConnectedException;
-    method public static boolean isZonedProperty(int);
-    method public synchronized void registerCallback(android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback) throws android.car.CarNotConnectedException;
-    method public void setBooleanProperty(int, int, boolean) throws android.car.CarNotConnectedException;
-    method public void setFloatProperty(int, int, float) throws android.car.CarNotConnectedException;
-    method public void setIntProperty(int, int, int) throws android.car.CarNotConnectedException;
-    method public synchronized void unregisterCallback(android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback);
-    field public static final int ID_MIRROR_DEFROSTER_ON = 1; // 0x1
-    field public static final int ID_OUTSIDE_AIR_TEMP = 3; // 0x3
-    field public static final int ID_STEERING_WHEEL_TEMP = 2; // 0x2
-    field public static final int ID_TEMPERATURE_UNITS = 4; // 0x4
-    field public static final int ID_WINDOW_DEFROSTER_ON = 20481; // 0x5001
-    field public static final int ID_ZONED_AC_ON = 16393; // 0x4009
-    field public static final int ID_ZONED_AIR_RECIRCULATION_ON = 16395; // 0x400b
-    field public static final int ID_ZONED_AUTOMATIC_MODE_ON = 16394; // 0x400a
-    field public static final int ID_ZONED_DUAL_ZONE_ON = 16397; // 0x400d
-    field public static final int ID_ZONED_FAN_DIRECTION = 16391; // 0x4007
-    field public static final int ID_ZONED_FAN_DIRECTION_AVAILABLE = 16390; // 0x4006
-    field public static final int ID_ZONED_FAN_SPEED_RPM = 16389; // 0x4005
-    field public static final int ID_ZONED_FAN_SPEED_SETPOINT = 16388; // 0x4004
-    field public static final int ID_ZONED_HVAC_POWER_ON = 16387; // 0x4003
-    field public static final int ID_ZONED_MAX_AC_ON = 16396; // 0x400c
-    field public static final int ID_ZONED_MAX_DEFROST_ON = 16398; // 0x400e
-    field public static final int ID_ZONED_SEAT_TEMP = 16392; // 0x4008
-    field public static final int ID_ZONED_TEMP_ACTUAL = 16386; // 0x4002
-    field public static final int ID_ZONED_TEMP_SETPOINT = 16385; // 0x4001
-  }
-
-  public static abstract interface CarHvacManager.CarHvacEventCallback {
-    method public abstract void onChangeEvent(android.car.hardware.CarPropertyValue);
-    method public abstract void onErrorEvent(int, int);
-  }
-
-}
-
-package android.car.hardware.radio {
-
-  public class CarRadioEvent implements android.os.Parcelable {
-    ctor public CarRadioEvent(int, android.car.hardware.radio.CarRadioPreset);
-    method public int describeContents();
-    method public int getEventType();
-    method public android.car.hardware.radio.CarRadioPreset getPreset();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.hardware.radio.CarRadioEvent> CREATOR;
-    field public static final int RADIO_PRESET = 0; // 0x0
-  }
-
-  public final class CarRadioManager {
-    method public android.car.hardware.radio.CarRadioPreset getPreset(int) throws android.car.CarNotConnectedException;
-    method public int getPresetCount() throws android.car.CarNotConnectedException;
-    method public synchronized void registerListener(android.car.hardware.radio.CarRadioManager.CarRadioEventListener) throws android.car.CarNotConnectedException;
-    method public boolean setPreset(android.car.hardware.radio.CarRadioPreset) throws android.car.CarNotConnectedException, java.lang.IllegalArgumentException;
-    method public synchronized void unregisterListener();
-  }
-
-  public static abstract interface CarRadioManager.CarRadioEventListener {
-    method public abstract void onEvent(android.car.hardware.radio.CarRadioEvent);
-  }
-
-  public class CarRadioPreset implements android.os.Parcelable {
-    ctor public CarRadioPreset(int, int, int, int);
-    method public int describeContents();
-    method public int getBand();
-    method public int getChannel();
-    method public int getPresetNumber();
-    method public int getSubChannel();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.hardware.radio.CarRadioPreset> CREATOR;
-  }
-
-}
-
-package android.car.input {
-
-  public abstract class CarInputHandlingService extends android.app.Service {
-    ctor protected CarInputHandlingService(android.car.input.CarInputHandlingService.InputFilter[]);
-    method public android.os.IBinder onBind(android.content.Intent);
-    method protected abstract void onKeyEvent(android.view.KeyEvent, int);
-    field public static final int INPUT_CALLBACK_BINDER_CODE = 1; // 0x1
-    field public static final java.lang.String INPUT_CALLBACK_BINDER_KEY = "callback_binder";
-  }
-
-  public static class CarInputHandlingService.InputFilter implements android.os.Parcelable {
-    ctor public CarInputHandlingService.InputFilter(int, int);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-    field public final int mKeyCode;
-    field public final int mTargetDisplay;
-  }
-
-}
-
-package android.car.media {
-
-  public final class CarAudioManager {
-    method public void abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes);
-    method public android.media.AudioAttributes getAudioAttributesForCarUsage(int) throws android.car.CarNotConnectedException;
-    method public int getStreamMaxVolume(int) throws android.car.CarNotConnectedException;
-    method public int getStreamMinVolume(int) throws android.car.CarNotConnectedException;
-    method public int getStreamVolume(int) throws android.car.CarNotConnectedException;
-    method public boolean isMediaMuted() throws android.car.CarNotConnectedException;
-    method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int) throws android.car.CarNotConnectedException, java.lang.IllegalArgumentException;
-    method public boolean setMediaMute(boolean) throws android.car.CarNotConnectedException;
-    method public void setStreamVolume(int, int, int) throws android.car.CarNotConnectedException;
-    method public void setVolumeController(android.media.IVolumeController) throws android.car.CarNotConnectedException;
-    field public static final int CAR_AUDIO_USAGE_ALARM = 6; // 0x6
-    field public static final int CAR_AUDIO_USAGE_DEFAULT = 0; // 0x0
-    field public static final int CAR_AUDIO_USAGE_MUSIC = 1; // 0x1
-    field public static final int CAR_AUDIO_USAGE_NAVIGATION_GUIDANCE = 3; // 0x3
-    field public static final int CAR_AUDIO_USAGE_NOTIFICATION = 7; // 0x7
-    field public static final int CAR_AUDIO_USAGE_RADIO = 2; // 0x2
-    field public static final int CAR_AUDIO_USAGE_SYSTEM_SAFETY_ALERT = 9; // 0x9
-    field public static final int CAR_AUDIO_USAGE_SYSTEM_SOUND = 8; // 0x8
-    field public static final int CAR_AUDIO_USAGE_VOICE_CALL = 4; // 0x4
-    field public static final int CAR_AUDIO_USAGE_VOICE_COMMAND = 5; // 0x5
-  }
-
-}
-
-package android.car.navigation {
-
-  public class CarNavigationInstrumentCluster implements android.os.Parcelable {
-    ctor public CarNavigationInstrumentCluster(android.car.navigation.CarNavigationInstrumentCluster);
-    method public static android.car.navigation.CarNavigationInstrumentCluster createCluster(int);
-    method public static android.car.navigation.CarNavigationInstrumentCluster createCustomImageCluster(int, int, int, int);
-    method public int describeContents();
-    method public int getImageColorDepthBits();
-    method public int getImageHeight();
-    method public int getImageWidth();
-    method public int getMinIntervalMillis();
-    method public int getType();
-    method public boolean supportsCustomImages();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final int CLUSTER_TYPE_CUSTOM_IMAGES_SUPPORTED = 1; // 0x1
-    field public static final int CLUSTER_TYPE_IMAGE_CODES_ONLY = 2; // 0x2
-    field public static final android.os.Parcelable.Creator<android.car.navigation.CarNavigationInstrumentCluster> CREATOR;
-  }
-
-}
-
-package android.car.settings {
-
-  public class CarSettings {
-    ctor public CarSettings();
-  }
-
-  public static final class CarSettings.Global {
-    ctor public CarSettings.Global();
-    field public static final java.lang.String KEY_GARAGE_MODE_ENABLED = "android.car.GARAGE_MODE_ENABLED";
-    field public static final java.lang.String KEY_GARAGE_MODE_MAINTENANCE_WINDOW = "android.car.GARAGE_MODE_MAINTENANCE_WINDOW";
-    field public static final java.lang.String KEY_GARAGE_MODE_WAKE_UP_TIME = "android.car.GARAGE_MODE_WAKE_UP_TIME";
-  }
-
-}
-
-package android.car.test {
-
-  public class CarTestManagerBinderWrapper {
-    ctor public CarTestManagerBinderWrapper(android.os.IBinder);
-    method public void onCarDisconnected();
-    field public final android.os.IBinder binder;
-  }
-
-}
-
diff --git a/car-lib/api/system-released/system-2.txt b/car-lib/api/system-released/system-2.txt
index 3a2f2de..e69de29 100644
--- a/car-lib/api/system-released/system-2.txt
+++ b/car-lib/api/system-released/system-2.txt
@@ -1,752 +0,0 @@
-package android.car {
-
-  public final class Car {
-    method public void connect() throws java.lang.IllegalStateException;
-    method public static android.car.Car createCar(android.content.Context, android.content.ServiceConnection, android.os.Handler);
-    method public static android.car.Car createCar(android.content.Context, android.content.ServiceConnection);
-    method public void disconnect();
-    method public int getCarConnectionType();
-    method public java.lang.Object getCarManager(java.lang.String) throws android.car.CarNotConnectedException;
-    method public boolean isConnected();
-    method public boolean isConnecting();
-    field public static final java.lang.String APP_FOCUS_SERVICE = "app_focus";
-    field public static final java.lang.String AUDIO_SERVICE = "audio";
-    field public static final java.lang.String CABIN_SERVICE = "cabin";
-    field public static final int CONNECTION_TYPE_EMBEDDED = 5; // 0x5
-    field public static final java.lang.String DIAGNOSTIC_SERVICE = "diagnostic";
-    field public static final java.lang.String HVAC_SERVICE = "hvac";
-    field public static final java.lang.String INFO_SERVICE = "info";
-    field public static final java.lang.String PACKAGE_SERVICE = "package";
-    field public static final java.lang.String PERMISSION_CAR_CABIN = "android.car.permission.CAR_CABIN";
-    field public static final java.lang.String PERMISSION_CAR_CONTROL_AUDIO_VOLUME = "android.car.permission.CAR_CONTROL_AUDIO_VOLUME";
-    field public static final java.lang.String PERMISSION_CAR_DIAGNOSTIC_CLEAR = "android.car.permission.DIAGNOSTIC_CLEAR";
-    field public static final java.lang.String PERMISSION_CAR_DIAGNOSTIC_READ = "android.car.permission.DIAGNOSTIC_READ";
-    field public static final java.lang.String PERMISSION_CAR_HVAC = "android.car.permission.CAR_HVAC";
-    field public static final java.lang.String PERMISSION_CAR_PROJECTION = "android.car.permission.CAR_PROJECTION";
-    field public static final java.lang.String PERMISSION_CAR_RADIO = "android.car.permission.CAR_RADIO";
-    field public static final java.lang.String PERMISSION_CAR_TEST_SERVICE = "android.car.permission.CAR_TEST_SERVICE";
-    field public static final java.lang.String PERMISSION_CONTROL_APP_BLOCKING = "android.car.permission.CONTROL_APP_BLOCKING";
-    field public static final java.lang.String PERMISSION_FUEL = "android.car.permission.CAR_FUEL";
-    field public static final java.lang.String PERMISSION_MILEAGE = "android.car.permission.CAR_MILEAGE";
-    field public static final deprecated java.lang.String PERMISSION_MOCK_VEHICLE_HAL = "android.car.permission.CAR_MOCK_VEHICLE_HAL";
-    field public static final java.lang.String PERMISSION_SPEED = "android.car.permission.CAR_SPEED";
-    field public static final java.lang.String PERMISSION_VENDOR_EXTENSION = "android.car.permission.CAR_VENDOR_EXTENSION";
-    field public static final java.lang.String PERMISSION_VMS_PUBLISHER = "android.car.permission.VMS_PUBLISHER";
-    field public static final java.lang.String PERMISSION_VMS_SUBSCRIBER = "android.car.permission.VMS_SUBSCRIBER";
-    field public static final java.lang.String PROJECTION_SERVICE = "projection";
-    field public static final java.lang.String RADIO_SERVICE = "radio";
-    field public static final java.lang.String SENSOR_SERVICE = "sensor";
-    field public static final java.lang.String TEST_SERVICE = "car-service-test";
-    field public static final java.lang.String VENDOR_EXTENSION_SERVICE = "vendor_extension";
-    field public static final int VERSION = 2; // 0x2
-    field public static final java.lang.String VMS_SUBSCRIBER_SERVICE = "vehicle_map_subscriber_service";
-  }
-
-  public final class CarAppFocusManager {
-    method public void abandonAppFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback, int);
-    method public void abandonAppFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback);
-    method public void addFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener, int) throws android.car.CarNotConnectedException;
-    method public boolean isOwningFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback, int) throws android.car.CarNotConnectedException;
-    method public void removeFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener, int);
-    method public void removeFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener);
-    method public int requestAppFocus(int, android.car.CarAppFocusManager.OnAppFocusOwnershipCallback) throws android.car.CarNotConnectedException, java.lang.SecurityException;
-    field public static final int APP_FOCUS_REQUEST_FAILED = 0; // 0x0
-    field public static final int APP_FOCUS_REQUEST_SUCCEEDED = 1; // 0x1
-    field public static final int APP_FOCUS_TYPE_NAVIGATION = 1; // 0x1
-    field public static final int APP_FOCUS_TYPE_VOICE_COMMAND = 2; // 0x2
-  }
-
-  public static abstract interface CarAppFocusManager.OnAppFocusChangedListener {
-    method public abstract void onAppFocusChanged(int, boolean);
-  }
-
-  public static abstract interface CarAppFocusManager.OnAppFocusOwnershipCallback {
-    method public abstract void onAppFocusOwnershipGranted(int);
-    method public abstract void onAppFocusOwnershipLost(int);
-  }
-
-  public final class CarInfoManager {
-    method public java.lang.String getManufacturer() throws android.car.CarNotConnectedException;
-    method public java.lang.String getModel() throws android.car.CarNotConnectedException;
-    method public java.lang.String getModelYear() throws android.car.CarNotConnectedException;
-    method public java.lang.String getVehicleId() throws android.car.CarNotConnectedException;
-  }
-
-  public class CarNotConnectedException extends java.lang.Exception {
-    ctor public CarNotConnectedException();
-    ctor public CarNotConnectedException(java.lang.String);
-    ctor public CarNotConnectedException(java.lang.String, java.lang.Throwable);
-    ctor public CarNotConnectedException(java.lang.Exception);
-  }
-
-  public final class CarProjectionManager {
-    method public void onCarDisconnected();
-    method public void registerProjectionRunner(android.content.Intent) throws android.car.CarNotConnectedException;
-    method public void regsiterProjectionListener(android.car.CarProjectionManager.CarProjectionListener, int) throws android.car.CarNotConnectedException;
-    method public void unregisterProjectionRunner(android.content.Intent);
-    method public void unregsiterProjectionListener();
-    field public static final int PROJECTION_LONG_PRESS_VOICE_SEARCH = 2; // 0x2
-    field public static final int PROJECTION_VOICE_SEARCH = 1; // 0x1
-  }
-
-  public static abstract interface CarProjectionManager.CarProjectionListener {
-    method public abstract void onVoiceAssistantRequest(boolean);
-  }
-
-  public final class VehicleAreaType {
-    field public static final int VEHICLE_AREA_TYPE_DOOR = 4; // 0x4
-    field public static final int VEHICLE_AREA_TYPE_MIRROR = 5; // 0x5
-    field public static final int VEHICLE_AREA_TYPE_NONE = 0; // 0x0
-    field public static final int VEHICLE_AREA_TYPE_SEAT = 3; // 0x3
-    field public static final int VEHICLE_AREA_TYPE_WINDOW = 2; // 0x2
-    field public static final int VEHICLE_AREA_TYPE_ZONE = 1; // 0x1
-  }
-
-  public final class VehicleDoor {
-    field public static final int DOOR_HOOD = 268435456; // 0x10000000
-    field public static final int DOOR_REAR = 536870912; // 0x20000000
-    field public static final int DOOR_ROW_1_LEFT = 1; // 0x1
-    field public static final int DOOR_ROW_1_RIGHT = 4; // 0x4
-    field public static final int DOOR_ROW_2_LEFT = 16; // 0x10
-    field public static final int DOOR_ROW_2_RIGHT = 64; // 0x40
-    field public static final int DOOR_ROW_3_LEFT = 256; // 0x100
-    field public static final int DOOR_ROW_3_RIGHT = 1024; // 0x400
-  }
-
-  public final class VehicleMirror {
-    field public static final int MIRROR_DRIVER_CENTER = 4; // 0x4
-    field public static final int MIRROR_DRIVER_LEFT = 1; // 0x1
-    field public static final int MIRROR_DRIVER_RIGHT = 2; // 0x2
-  }
-
-  public final class VehicleSeat {
-    field public static final int SEAT_ROW_1_CENTER = 2; // 0x2
-    field public static final int SEAT_ROW_1_LEFT = 1; // 0x1
-    field public static final int SEAT_ROW_1_RIGHT = 4; // 0x4
-    field public static final int SEAT_ROW_2_CENTER = 32; // 0x20
-    field public static final int SEAT_ROW_2_LEFT = 16; // 0x10
-    field public static final int SEAT_ROW_2_RIGHT = 64; // 0x40
-    field public static final int SEAT_ROW_3_CENTER = 512; // 0x200
-    field public static final int SEAT_ROW_3_LEFT = 256; // 0x100
-    field public static final int SEAT_ROW_3_RIGHT = 1024; // 0x400
-  }
-
-  public final class VehicleWindow {
-    field public static final int WINDOW_FRONT_WINDSHIELD = 1; // 0x1
-    field public static final int WINDOW_REAR_WINDSHIELD = 2; // 0x2
-    field public static final int WINDOW_ROOF_TOP = 4; // 0x4
-    field public static final int WINDOW_ROW_1_LEFT = 16; // 0x10
-    field public static final int WINDOW_ROW_1_RIGHT = 32; // 0x20
-    field public static final int WINDOW_ROW_2_LEFT = 256; // 0x100
-    field public static final int WINDOW_ROW_2_RIGHT = 512; // 0x200
-    field public static final int WINDOW_ROW_3_LEFT = 4096; // 0x1000
-    field public static final int WINDOW_ROW_3_RIGHT = 8192; // 0x2000
-  }
-
-  public final class VehicleZone {
-    field public static final int ZONE_ALL = -2147483648; // 0x80000000
-    field public static final int ZONE_ROW_1_ALL = 8; // 0x8
-    field public static final int ZONE_ROW_1_CENTER = 2; // 0x2
-    field public static final int ZONE_ROW_1_LEFT = 1; // 0x1
-    field public static final int ZONE_ROW_1_RIGHT = 4; // 0x4
-    field public static final int ZONE_ROW_2_ALL = 128; // 0x80
-    field public static final int ZONE_ROW_2_CENTER = 32; // 0x20
-    field public static final int ZONE_ROW_2_LEFT = 16; // 0x10
-    field public static final int ZONE_ROW_2_RIGHT = 64; // 0x40
-    field public static final int ZONE_ROW_3_ALL = 2048; // 0x800
-    field public static final int ZONE_ROW_3_CENTER = 512; // 0x200
-    field public static final int ZONE_ROW_3_LEFT = 256; // 0x100
-    field public static final int ZONE_ROW_3_RIGHT = 1024; // 0x400
-    field public static final int ZONE_ROW_4_ALL = 32768; // 0x8000
-    field public static final int ZONE_ROW_4_CENTER = 8192; // 0x2000
-    field public static final int ZONE_ROW_4_LEFT = 4096; // 0x1000
-    field public static final int ZONE_ROW_4_RIGHT = 16384; // 0x4000
-  }
-
-  public final class VehicleZoneUtil {
-    method public static int getFirstZone(int);
-    method public static int getNextZone(int, int) throws java.lang.IllegalArgumentException;
-    method public static int getNumberOfZones(int);
-    method public static int[] listAllZones(int);
-    method public static int zoneToIndex(int, int) throws java.lang.IllegalArgumentException;
-  }
-
-}
-
-package android.car.app.menu {
-
-  public abstract class CarMenuCallbacks {
-    ctor public CarMenuCallbacks();
-    method public abstract android.car.app.menu.RootMenu getRootMenu(android.os.Bundle);
-    method public abstract void onCarMenuClosed();
-    method public abstract void onCarMenuClosing();
-    method public abstract void onCarMenuOpened();
-    method public abstract void onCarMenuOpening();
-    method public abstract void onItemClicked(java.lang.String);
-    method public abstract boolean onItemLongClicked(java.lang.String);
-    method public abstract boolean onMenuClicked();
-    method public abstract void subscribe(java.lang.String, android.car.app.menu.SubscriptionCallbacks);
-    method public abstract void unsubscribe(java.lang.String, android.car.app.menu.SubscriptionCallbacks);
-  }
-
-  public class CarMenuConstants {
-    ctor public CarMenuConstants();
-  }
-
-  public static class CarMenuConstants.MenuItemConstants {
-    ctor public CarMenuConstants.MenuItemConstants();
-    field public static final int FLAG_BROWSABLE = 1; // 0x1
-    field public static final int FLAG_FIRSTITEM = 2; // 0x2
-    field public static final java.lang.String KEY_EMPTY_PLACEHOLDER = "android.car.app.menu.empty_placeholder";
-    field public static final java.lang.String KEY_FLAGS = "android.car.app.menu.flags";
-    field public static final java.lang.String KEY_ID = "android.car.app.menu.id";
-    field public static final java.lang.String KEY_LEFTICON = "android.car.app.menu.leftIcon";
-    field public static final java.lang.String KEY_REMOTEVIEWS = "android.car.app.menu.remoteViews";
-    field public static final java.lang.String KEY_RIGHTICON = "android.car.app.menu.rightIcon";
-    field public static final java.lang.String KEY_RIGHTTEXT = "android.car.app.menu.rightText";
-    field public static final java.lang.String KEY_TEXT = "android.car.app.menu.text";
-    field public static final java.lang.String KEY_TITLE = "android.car.app.menu.title";
-    field public static final java.lang.String KEY_WIDGET = "android.car.app.menu.widget";
-    field public static final java.lang.String KEY_WIDGET_STATE = "android.car.app.menu.widget_state";
-    field public static final int WIDGET_CHECKBOX = 1; // 0x1
-    field public static final int WIDGET_TEXT_VIEW = 2; // 0x2
-  }
-
-  public static abstract class CarMenuConstants.MenuItemConstants.MenuItemFlags implements java.lang.annotation.Annotation {
-  }
-
-  public static abstract class CarMenuConstants.MenuItemConstants.WidgetTypes implements java.lang.annotation.Annotation {
-  }
-
-  public abstract class CarUiEntry {
-    ctor public CarUiEntry(android.content.Context, android.content.Context);
-    method public abstract void closeDrawer();
-    method public abstract android.view.View getContentView();
-    method public abstract int getFragmentContainerId();
-    method public abstract java.lang.CharSequence getSearchBoxText();
-    method public abstract void hideMenuButton();
-    method public abstract void hideTitle();
-    method public abstract void onPause();
-    method public abstract void onRestoreInstanceState(android.os.Bundle);
-    method public abstract void onResume();
-    method public abstract void onSaveInstanceState(android.os.Bundle);
-    method public abstract void onStart();
-    method public abstract void onStop();
-    method public abstract void openDrawer();
-    method public abstract void restoreMenuDrawable();
-    method public abstract void setAutoLightDarkMode();
-    method public abstract void setBackground(android.graphics.Bitmap);
-    method public abstract void setCarMenuCallbacks(android.car.app.menu.CarMenuCallbacks);
-    method public abstract void setDarkMode();
-    method public abstract void setLightMode();
-    method public abstract void setMenuButtonBitmap(android.graphics.Bitmap);
-    method public abstract void setMenuButtonColor(int);
-    method public abstract void setScrimColor(int);
-    method public abstract void setSearchBoxColors(int, int, int, int);
-    method public abstract void setSearchBoxEditListener(android.car.app.menu.SearchBoxEditListener);
-    method public abstract void setSearchBoxEndView(android.view.View);
-    method public abstract void setTitle(java.lang.CharSequence);
-    method public abstract void showMenu(java.lang.String, java.lang.String);
-    method public abstract void showSearchBox(android.view.View.OnClickListener);
-    method public abstract void showTitle();
-    method public abstract void showToast(java.lang.String, long);
-    method public abstract android.widget.EditText startInput(java.lang.String, android.view.View.OnClickListener);
-    method public abstract void stopInput();
-    field protected final android.content.Context mAppContext;
-    field protected final android.content.Context mUiLibContext;
-  }
-
-  public class RootMenu {
-    ctor public RootMenu(java.lang.String);
-    ctor public RootMenu(java.lang.String, android.os.Bundle);
-    method public android.os.Bundle getBundle();
-    method public java.lang.String getId();
-  }
-
-  public abstract class SearchBoxEditListener {
-    ctor public SearchBoxEditListener();
-    method public abstract void onEdit(java.lang.String);
-    method public abstract void onSearch(java.lang.String);
-  }
-
-  public abstract class SubscriptionCallbacks {
-    ctor public SubscriptionCallbacks();
-    method public abstract void onChildChanged(java.lang.String, android.os.Bundle);
-    method public abstract void onChildrenLoaded(java.lang.String, java.util.List<android.os.Bundle>);
-    method public abstract void onError(java.lang.String);
-  }
-
-}
-
-package android.car.cluster.renderer {
-
-  public class DisplayConfiguration implements android.os.Parcelable {
-    ctor public DisplayConfiguration(android.os.Parcel);
-    ctor public DisplayConfiguration(android.graphics.Rect);
-    ctor public DisplayConfiguration(android.graphics.Rect, android.graphics.Rect);
-    method public int describeContents();
-    method public android.graphics.Rect getPrimaryRegion();
-    method public android.graphics.Rect getSecondaryRegion();
-    method public boolean hasSecondaryRegion();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.cluster.renderer.DisplayConfiguration> CREATOR;
-  }
-
-  public abstract class InstrumentClusterRenderer {
-    ctor public InstrumentClusterRenderer();
-    method protected abstract android.car.cluster.renderer.NavigationRenderer createNavigationRenderer();
-    method public synchronized android.car.cluster.renderer.NavigationRenderer getNavigationRenderer();
-    method public final synchronized void initialize();
-    method public abstract void onCreate(android.content.Context);
-    method public abstract void onStart();
-    method public abstract void onStop();
-  }
-
-  public abstract class InstrumentClusterRenderingService extends android.app.Service {
-    ctor public InstrumentClusterRenderingService();
-    method protected abstract android.car.cluster.renderer.NavigationRenderer getNavigationRenderer();
-    method public android.os.IBinder onBind(android.content.Intent);
-    method protected void onKeyEvent(android.view.KeyEvent);
-  }
-
-  public abstract class NavigationRenderer {
-    ctor public NavigationRenderer();
-    method public abstract android.car.navigation.CarNavigationInstrumentCluster getNavigationProperties();
-    method public abstract void onNextTurnChanged(int, java.lang.CharSequence, int, int, android.graphics.Bitmap, int);
-    method public abstract void onNextTurnDistanceChanged(int, int, int, int);
-    method public abstract void onStartNavigation();
-    method public abstract void onStopNavigation();
-  }
-
-}
-
-package android.car.content.pm {
-
-  public class AppBlockingPackageInfo implements android.os.Parcelable {
-    ctor public AppBlockingPackageInfo(java.lang.String, int, int, int, android.content.pm.Signature[], java.lang.String[]);
-    ctor public AppBlockingPackageInfo(android.os.Parcel);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.content.pm.AppBlockingPackageInfo> CREATOR;
-    field public static final int FLAG_SYSTEM_APP = 1; // 0x1
-    field public static final int FLAG_WHOLE_ACTIVITY = 2; // 0x2
-    field public final java.lang.String[] activities;
-    field public final int flags;
-    field public final int maxRevisionCode;
-    field public final int minRevisionCode;
-    field public final java.lang.String packageName;
-    field public final android.content.pm.Signature[] signatures;
-  }
-
-  public class CarAppBlockingPolicy implements android.os.Parcelable {
-    ctor public CarAppBlockingPolicy(android.car.content.pm.AppBlockingPackageInfo[], android.car.content.pm.AppBlockingPackageInfo[]);
-    ctor public CarAppBlockingPolicy(android.os.Parcel);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.content.pm.CarAppBlockingPolicy> CREATOR;
-    field public final android.car.content.pm.AppBlockingPackageInfo[] blacklists;
-    field public final android.car.content.pm.AppBlockingPackageInfo[] whitelists;
-  }
-
-  public abstract class CarAppBlockingPolicyService extends android.app.Service {
-    ctor public CarAppBlockingPolicyService();
-    method protected abstract android.car.content.pm.CarAppBlockingPolicy getAppBlockingPolicy();
-    method public android.os.IBinder onBind(android.content.Intent);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.car.content.pm.CarAppBlockingPolicyService";
-  }
-
-  public final class CarPackageManager {
-    method public boolean isActivityAllowedWhileDriving(java.lang.String, java.lang.String) throws android.car.CarNotConnectedException;
-    method public boolean isActivityBackedBySafeActivity(android.content.ComponentName) throws android.car.CarNotConnectedException;
-    method public boolean isServiceAllowedWhileDriving(java.lang.String, java.lang.String) throws android.car.CarNotConnectedException;
-    method public void setAppBlockingPolicy(java.lang.String, android.car.content.pm.CarAppBlockingPolicy, int) throws android.car.CarNotConnectedException, java.lang.IllegalArgumentException, java.lang.SecurityException;
-    field public static final int FLAG_SET_POLICY_ADD = 2; // 0x2
-    field public static final int FLAG_SET_POLICY_REMOVE = 4; // 0x4
-    field public static final int FLAG_SET_POLICY_WAIT_FOR_CHANGE = 1; // 0x1
-  }
-
-}
-
-package android.car.hardware {
-
-  public class CarPropertyConfig<T> implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getAreaCount();
-    method public int[] getAreaIds();
-    method public int getAreaType();
-    method public int getFirstAndOnlyAreaId();
-    method public T getMaxValue(int);
-    method public T getMaxValue();
-    method public T getMinValue(int);
-    method public T getMinValue();
-    method public int getPropertyId();
-    method public java.lang.Class<T> getPropertyType();
-    method public boolean hasArea(int);
-    method public boolean isGlobalProperty();
-    method public static <T> android.car.hardware.CarPropertyConfig.Builder<T> newBuilder(java.lang.Class<T>, int, int, int);
-    method public static <T> android.car.hardware.CarPropertyConfig.Builder<T> newBuilder(java.lang.Class<T>, int, int);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.hardware.CarPropertyConfig> CREATOR;
-  }
-
-  public static class CarPropertyConfig.AreaConfig<T> implements android.os.Parcelable {
-    method public int describeContents();
-    method public T getMaxValue();
-    method public T getMinValue();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.hardware.CarPropertyConfig.AreaConfig<java.lang.Object>> CREATOR;
-  }
-
-  public static class CarPropertyConfig.Builder<T> {
-    method public android.car.hardware.CarPropertyConfig.Builder<T> addArea(int);
-    method public android.car.hardware.CarPropertyConfig.Builder<T> addAreaConfig(int, T, T);
-    method public android.car.hardware.CarPropertyConfig.Builder<T> addAreas(int[]);
-    method public android.car.hardware.CarPropertyConfig<T> build();
-  }
-
-  public class CarPropertyValue<T> implements android.os.Parcelable {
-    ctor public CarPropertyValue(int, T);
-    ctor public CarPropertyValue(int, int, T);
-    ctor public CarPropertyValue(android.os.Parcel);
-    method public int describeContents();
-    method public int getAreaId();
-    method public int getPropertyId();
-    method public T getValue();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.hardware.CarPropertyValue> CREATOR;
-  }
-
-  public class CarSensorEvent implements android.os.Parcelable {
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.hardware.CarSensorEvent> CREATOR;
-    field public static final int DRIVE_STATUS_FULLY_RESTRICTED = 31; // 0x1f
-    field public static final int DRIVE_STATUS_LIMIT_MESSAGE_LEN = 16; // 0x10
-    field public static final int DRIVE_STATUS_NO_CONFIG = 8; // 0x8
-    field public static final int DRIVE_STATUS_NO_KEYBOARD_INPUT = 2; // 0x2
-    field public static final int DRIVE_STATUS_NO_VIDEO = 1; // 0x1
-    field public static final int DRIVE_STATUS_NO_VOICE_INPUT = 4; // 0x4
-    field public static final int DRIVE_STATUS_UNRESTRICTED = 0; // 0x0
-    field public static final int GEAR_DRIVE = 100; // 0x64
-    field public static final int GEAR_EIGHTH = 8; // 0x8
-    field public static final int GEAR_FIFTH = 5; // 0x5
-    field public static final int GEAR_FIRST = 1; // 0x1
-    field public static final int GEAR_FOURTH = 4; // 0x4
-    field public static final int GEAR_NEUTRAL = 0; // 0x0
-    field public static final int GEAR_NINTH = 9; // 0x9
-    field public static final int GEAR_PARK = 101; // 0x65
-    field public static final int GEAR_REVERSE = 102; // 0x66
-    field public static final int GEAR_SECOND = 2; // 0x2
-    field public static final int GEAR_SEVENTH = 7; // 0x7
-    field public static final int GEAR_SIXTH = 6; // 0x6
-    field public static final int GEAR_TENTH = 10; // 0xa
-    field public static final int GEAR_THIRD = 3; // 0x3
-    field public static final int IGNITION_STATE_ACC = 3; // 0x3
-    field public static final int IGNITION_STATE_LOCK = 1; // 0x1
-    field public static final int IGNITION_STATE_OFF = 2; // 0x2
-    field public static final int IGNITION_STATE_ON = 4; // 0x4
-    field public static final int IGNITION_STATE_START = 5; // 0x5
-    field public static final int IGNITION_STATE_UNDEFINED = 0; // 0x0
-    field public static final int INDEX_ENVIRONMENT_PRESSURE = 1; // 0x1
-    field public static final int INDEX_ENVIRONMENT_TEMPERATURE = 0; // 0x0
-    field public static final int INDEX_FUEL_LEVEL_IN_DISTANCE = 1; // 0x1
-    field public static final int INDEX_FUEL_LEVEL_IN_PERCENTILE = 0; // 0x0
-    field public static final int INDEX_FUEL_LOW_WARNING = 0; // 0x0
-    field public final float[] floatValues;
-    field public final int[] intValues;
-    field public int sensorType;
-    field public long timestamp;
-  }
-
-  public static class CarSensorEvent.EnvironmentData {
-    field public float pressure;
-    field public float temperature;
-    field public long timestamp;
-  }
-
-  public final class CarSensorManager {
-    method public android.car.hardware.CarSensorEvent getLatestSensorEvent(int) throws android.car.CarNotConnectedException;
-    method public int[] getSupportedSensors() throws android.car.CarNotConnectedException;
-    method public boolean isSensorSupported(int) throws android.car.CarNotConnectedException;
-    method public static boolean isSensorSupported(int[], int);
-    method public boolean registerListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int, int) throws android.car.CarNotConnectedException, java.lang.IllegalArgumentException;
-    method public void unregisterListener(android.car.hardware.CarSensorManager.OnSensorChangedListener);
-    method public void unregisterListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int);
-    field public static final int SENSOR_RATE_FAST = 1; // 0x1
-    field public static final int SENSOR_RATE_FASTEST = 0; // 0x0
-    field public static final int SENSOR_RATE_NORMAL = 3; // 0x3
-    field public static final int SENSOR_RATE_UI = 2; // 0x2
-    field public static final int SENSOR_TYPE_CAR_SPEED = 2; // 0x2
-    field public static final int SENSOR_TYPE_DRIVING_STATUS = 11; // 0xb
-    field public static final int SENSOR_TYPE_ENVIRONMENT = 12; // 0xc
-    field public static final int SENSOR_TYPE_FUEL_LEVEL = 5; // 0x5
-    field public static final int SENSOR_TYPE_GEAR = 7; // 0x7
-    field public static final int SENSOR_TYPE_IGNITION_STATE = 22; // 0x16
-    field public static final int SENSOR_TYPE_NIGHT = 9; // 0x9
-    field public static final int SENSOR_TYPE_ODOMETER = 4; // 0x4
-    field public static final int SENSOR_TYPE_PARKING_BRAKE = 6; // 0x6
-    field public static final int SENSOR_TYPE_RPM = 3; // 0x3
-    field public static final int SENSOR_TYPE_VENDOR_EXTENSION_END = 1879048191; // 0x6fffffff
-  }
-
-  public static abstract interface CarSensorManager.OnSensorChangedListener {
-    method public abstract void onSensorChanged(android.car.hardware.CarSensorEvent);
-  }
-
-  public final class CarVendorExtensionManager {
-    method public <E> E getGlobalProperty(java.lang.Class<E>, int) throws android.car.CarNotConnectedException;
-    method public java.util.List<android.car.hardware.CarPropertyConfig> getProperties() throws android.car.CarNotConnectedException;
-    method public <E> E getProperty(java.lang.Class<E>, int, int) throws android.car.CarNotConnectedException;
-    method public void registerCallback(android.car.hardware.CarVendorExtensionManager.CarVendorExtensionCallback) throws android.car.CarNotConnectedException;
-    method public <E> void setGlobalProperty(java.lang.Class<E>, int, E) throws android.car.CarNotConnectedException;
-    method public <E> void setProperty(java.lang.Class<E>, int, int, E) throws android.car.CarNotConnectedException;
-    method public void unregisterCallback(android.car.hardware.CarVendorExtensionManager.CarVendorExtensionCallback);
-  }
-
-  public static abstract interface CarVendorExtensionManager.CarVendorExtensionCallback {
-    method public abstract void onChangeEvent(android.car.hardware.CarPropertyValue);
-    method public abstract void onErrorEvent(int, int);
-  }
-
-}
-
-package android.car.hardware.cabin {
-
-  public final class CarCabinManager {
-    method public boolean getBooleanProperty(int, int) throws android.car.CarNotConnectedException;
-    method public float getFloatProperty(int, int) throws android.car.CarNotConnectedException;
-    method public int getIntProperty(int, int) throws android.car.CarNotConnectedException;
-    method public java.util.List<android.car.hardware.CarPropertyConfig> getPropertyList() throws android.car.CarNotConnectedException;
-    method public static boolean isZonedProperty(int);
-    method public synchronized void registerCallback(android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback) throws android.car.CarNotConnectedException;
-    method public void setBooleanProperty(int, int, boolean) throws android.car.CarNotConnectedException;
-    method public void setFloatProperty(int, int, float) throws android.car.CarNotConnectedException;
-    method public void setIntProperty(int, int, int) throws android.car.CarNotConnectedException;
-    method public synchronized void unregisterCallback(android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback);
-    field public static final int ID_DOOR_LOCK = 3; // 0x3
-    field public static final int ID_DOOR_MOVE = 2; // 0x2
-    field public static final int ID_DOOR_POS = 1; // 0x1
-    field public static final int ID_MIRROR_FOLD = 4102; // 0x1006
-    field public static final int ID_MIRROR_LOCK = 4101; // 0x1005
-    field public static final int ID_MIRROR_Y_MOVE = 4100; // 0x1004
-    field public static final int ID_MIRROR_Y_POS = 4099; // 0x1003
-    field public static final int ID_MIRROR_Z_MOVE = 4098; // 0x1002
-    field public static final int ID_MIRROR_Z_POS = 4097; // 0x1001
-    field public static final int ID_SEAT_BACKREST_ANGLE_1_MOVE = 8201; // 0x2009
-    field public static final int ID_SEAT_BACKREST_ANGLE_1_POS = 8200; // 0x2008
-    field public static final int ID_SEAT_BACKREST_ANGLE_2_MOVE = 8203; // 0x200b
-    field public static final int ID_SEAT_BACKREST_ANGLE_2_POS = 8202; // 0x200a
-    field public static final int ID_SEAT_BELT_BUCKLED = 8195; // 0x2003
-    field public static final int ID_SEAT_BELT_HEIGHT_MOVE = 8197; // 0x2005
-    field public static final int ID_SEAT_BELT_HEIGHT_POS = 8196; // 0x2004
-    field public static final int ID_SEAT_DEPTH_MOVE = 8207; // 0x200f
-    field public static final int ID_SEAT_DEPTH_POS = 8206; // 0x200e
-    field public static final int ID_SEAT_FORE_AFT_MOVE = 8199; // 0x2007
-    field public static final int ID_SEAT_FORE_AFT_POS = 8198; // 0x2006
-    field public static final int ID_SEAT_HEADREST_ANGLE_MOVE = 8217; // 0x2019
-    field public static final int ID_SEAT_HEADREST_ANGLE_POS = 8216; // 0x2018
-    field public static final int ID_SEAT_HEADREST_FORE_AFT_MOVE = 8219; // 0x201b
-    field public static final int ID_SEAT_HEADREST_FORE_AFT_POS = 8218; // 0x201a
-    field public static final int ID_SEAT_HEADREST_HEIGHT_MOVE = 8215; // 0x2017
-    field public static final int ID_SEAT_HEADREST_HEIGHT_POS = 8214; // 0x2016
-    field public static final int ID_SEAT_HEIGHT_MOVE = 8205; // 0x200d
-    field public static final int ID_SEAT_HEIGHT_POS = 8204; // 0x200c
-    field public static final int ID_SEAT_LUMBAR_FORE_AFT_MOVE = 8211; // 0x2013
-    field public static final int ID_SEAT_LUMBAR_FORE_AFT_POS = 8210; // 0x2012
-    field public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 8213; // 0x2015
-    field public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_POS = 8212; // 0x2014
-    field public static final int ID_SEAT_MEMORY_SELECT = 8193; // 0x2001
-    field public static final int ID_SEAT_MEMORY_SET = 8194; // 0x2002
-    field public static final int ID_SEAT_TILT_MOVE = 8209; // 0x2011
-    field public static final int ID_SEAT_TILT_POS = 8208; // 0x2010
-    field public static final int ID_WINDOW_LOCK = 12293; // 0x3005
-    field public static final int ID_WINDOW_MOVE = 12290; // 0x3002
-    field public static final int ID_WINDOW_POS = 12289; // 0x3001
-    field public static final int ID_WINDOW_VENT_MOVE = 12292; // 0x3004
-    field public static final int ID_WINDOW_VENT_POS = 12291; // 0x3003
-  }
-
-  public static abstract interface CarCabinManager.CarCabinEventCallback {
-    method public abstract void onChangeEvent(android.car.hardware.CarPropertyValue);
-    method public abstract void onErrorEvent(int, int);
-  }
-
-}
-
-package android.car.hardware.hvac {
-
-  public final class CarHvacManager {
-    method public boolean getBooleanProperty(int, int) throws android.car.CarNotConnectedException;
-    method public float getFloatProperty(int, int) throws android.car.CarNotConnectedException;
-    method public int getIntProperty(int, int) throws android.car.CarNotConnectedException;
-    method public java.util.List<android.car.hardware.CarPropertyConfig> getPropertyList() throws android.car.CarNotConnectedException;
-    method public static boolean isZonedProperty(int);
-    method public synchronized void registerCallback(android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback) throws android.car.CarNotConnectedException;
-    method public void setBooleanProperty(int, int, boolean) throws android.car.CarNotConnectedException;
-    method public void setFloatProperty(int, int, float) throws android.car.CarNotConnectedException;
-    method public void setIntProperty(int, int, int) throws android.car.CarNotConnectedException;
-    method public synchronized void unregisterCallback(android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback);
-    field public static final int FAN_DIRECTION_DEFROST = 4; // 0x4
-    field public static final int FAN_DIRECTION_DEFROST_AND_FLOOR = 5; // 0x5
-    field public static final int FAN_DIRECTION_FACE = 1; // 0x1
-    field public static final int FAN_DIRECTION_FACE_AND_FLOOR = 3; // 0x3
-    field public static final int FAN_DIRECTION_FLOOR = 2; // 0x2
-    field public static final int ID_MIRROR_DEFROSTER_ON = 1; // 0x1
-    field public static final int ID_OUTSIDE_AIR_TEMP = 3; // 0x3
-    field public static final int ID_STEERING_WHEEL_TEMP = 2; // 0x2
-    field public static final int ID_TEMPERATURE_UNITS = 4; // 0x4
-    field public static final int ID_WINDOW_DEFROSTER_ON = 20481; // 0x5001
-    field public static final int ID_ZONED_AC_ON = 16393; // 0x4009
-    field public static final int ID_ZONED_AIR_RECIRCULATION_ON = 16395; // 0x400b
-    field public static final int ID_ZONED_AUTOMATIC_MODE_ON = 16394; // 0x400a
-    field public static final int ID_ZONED_DUAL_ZONE_ON = 16397; // 0x400d
-    field public static final int ID_ZONED_FAN_DIRECTION = 16391; // 0x4007
-    field public static final int ID_ZONED_FAN_DIRECTION_AVAILABLE = 16390; // 0x4006
-    field public static final int ID_ZONED_FAN_SPEED_RPM = 16389; // 0x4005
-    field public static final int ID_ZONED_FAN_SPEED_SETPOINT = 16388; // 0x4004
-    field public static final int ID_ZONED_HVAC_POWER_ON = 16387; // 0x4003
-    field public static final int ID_ZONED_MAX_AC_ON = 16396; // 0x400c
-    field public static final int ID_ZONED_MAX_DEFROST_ON = 16398; // 0x400e
-    field public static final int ID_ZONED_SEAT_TEMP = 16392; // 0x4008
-    field public static final int ID_ZONED_TEMP_ACTUAL = 16386; // 0x4002
-    field public static final int ID_ZONED_TEMP_SETPOINT = 16385; // 0x4001
-  }
-
-  public static abstract interface CarHvacManager.CarHvacEventCallback {
-    method public abstract void onChangeEvent(android.car.hardware.CarPropertyValue);
-    method public abstract void onErrorEvent(int, int);
-  }
-
-}
-
-package android.car.hardware.radio {
-
-  public class CarRadioEvent implements android.os.Parcelable {
-    ctor public CarRadioEvent(int, android.car.hardware.radio.CarRadioPreset);
-    method public int describeContents();
-    method public int getEventType();
-    method public android.car.hardware.radio.CarRadioPreset getPreset();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.hardware.radio.CarRadioEvent> CREATOR;
-    field public static final int RADIO_PRESET = 0; // 0x0
-  }
-
-  public final class CarRadioManager {
-    method public android.car.hardware.radio.CarRadioPreset getPreset(int) throws android.car.CarNotConnectedException;
-    method public int getPresetCount() throws android.car.CarNotConnectedException;
-    method public synchronized void registerListener(android.car.hardware.radio.CarRadioManager.CarRadioEventListener) throws android.car.CarNotConnectedException;
-    method public boolean setPreset(android.car.hardware.radio.CarRadioPreset) throws android.car.CarNotConnectedException, java.lang.IllegalArgumentException;
-    method public synchronized void unregisterListener();
-  }
-
-  public static abstract interface CarRadioManager.CarRadioEventListener {
-    method public abstract void onEvent(android.car.hardware.radio.CarRadioEvent);
-  }
-
-  public class CarRadioPreset implements android.os.Parcelable {
-    ctor public CarRadioPreset(int, int, int, int);
-    method public int describeContents();
-    method public int getBand();
-    method public int getChannel();
-    method public int getPresetNumber();
-    method public int getSubChannel();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.hardware.radio.CarRadioPreset> CREATOR;
-  }
-
-}
-
-package android.car.input {
-
-  public abstract class CarInputHandlingService extends android.app.Service {
-    ctor protected CarInputHandlingService(android.car.input.CarInputHandlingService.InputFilter[]);
-    method public android.os.IBinder onBind(android.content.Intent);
-    method protected abstract void onKeyEvent(android.view.KeyEvent, int);
-    field public static final int INPUT_CALLBACK_BINDER_CODE = 1; // 0x1
-    field public static final java.lang.String INPUT_CALLBACK_BINDER_KEY = "callback_binder";
-  }
-
-  public static class CarInputHandlingService.InputFilter implements android.os.Parcelable {
-    ctor public CarInputHandlingService.InputFilter(int, int);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-    field public final int mKeyCode;
-    field public final int mTargetDisplay;
-  }
-
-}
-
-package android.car.media {
-
-  public final class CarAudioManager {
-    method public void abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes);
-    method public android.media.AudioAttributes getAudioAttributesForCarUsage(int) throws android.car.CarNotConnectedException;
-    method public int getStreamMaxVolume(int) throws android.car.CarNotConnectedException;
-    method public int getStreamMinVolume(int) throws android.car.CarNotConnectedException;
-    method public int getStreamVolume(int) throws android.car.CarNotConnectedException;
-    method public boolean isMediaMuted() throws android.car.CarNotConnectedException;
-    method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int) throws android.car.CarNotConnectedException, java.lang.IllegalArgumentException;
-    method public boolean setMediaMute(boolean) throws android.car.CarNotConnectedException;
-    method public void setStreamVolume(int, int, int) throws android.car.CarNotConnectedException;
-    method public void setVolumeController(android.media.IVolumeController) throws android.car.CarNotConnectedException;
-    field public static final int CAR_AUDIO_USAGE_ALARM = 6; // 0x6
-    field public static final int CAR_AUDIO_USAGE_DEFAULT = 0; // 0x0
-    field public static final int CAR_AUDIO_USAGE_MUSIC = 1; // 0x1
-    field public static final int CAR_AUDIO_USAGE_NAVIGATION_GUIDANCE = 3; // 0x3
-    field public static final int CAR_AUDIO_USAGE_NOTIFICATION = 7; // 0x7
-    field public static final int CAR_AUDIO_USAGE_RADIO = 2; // 0x2
-    field public static final int CAR_AUDIO_USAGE_SYSTEM_SAFETY_ALERT = 9; // 0x9
-    field public static final int CAR_AUDIO_USAGE_SYSTEM_SOUND = 8; // 0x8
-    field public static final int CAR_AUDIO_USAGE_VOICE_CALL = 4; // 0x4
-    field public static final int CAR_AUDIO_USAGE_VOICE_COMMAND = 5; // 0x5
-  }
-
-}
-
-package android.car.navigation {
-
-  public class CarNavigationInstrumentCluster implements android.os.Parcelable {
-    ctor public CarNavigationInstrumentCluster(android.car.navigation.CarNavigationInstrumentCluster);
-    method public static android.car.navigation.CarNavigationInstrumentCluster createCluster(int);
-    method public static android.car.navigation.CarNavigationInstrumentCluster createCustomImageCluster(int, int, int, int);
-    method public int describeContents();
-    method public int getImageColorDepthBits();
-    method public int getImageHeight();
-    method public int getImageWidth();
-    method public int getMinIntervalMillis();
-    method public int getType();
-    method public boolean supportsCustomImages();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final int CLUSTER_TYPE_CUSTOM_IMAGES_SUPPORTED = 1; // 0x1
-    field public static final int CLUSTER_TYPE_IMAGE_CODES_ONLY = 2; // 0x2
-    field public static final android.os.Parcelable.Creator<android.car.navigation.CarNavigationInstrumentCluster> CREATOR;
-  }
-
-}
-
-package android.car.settings {
-
-  public class CarSettings {
-    ctor public CarSettings();
-  }
-
-  public static final class CarSettings.Global {
-    ctor public CarSettings.Global();
-    field public static final java.lang.String KEY_GARAGE_MODE_ENABLED = "android.car.GARAGE_MODE_ENABLED";
-    field public static final java.lang.String KEY_GARAGE_MODE_MAINTENANCE_WINDOW = "android.car.GARAGE_MODE_MAINTENANCE_WINDOW";
-    field public static final java.lang.String KEY_GARAGE_MODE_WAKE_UP_TIME = "android.car.GARAGE_MODE_WAKE_UP_TIME";
-  }
-
-}
-
-package android.car.test {
-
-  public class CarTestManagerBinderWrapper {
-    ctor public CarTestManagerBinderWrapper(android.os.IBinder);
-    method public void onCarDisconnected();
-    field public final android.os.IBinder binder;
-  }
-
-}
-
diff --git a/car-lib/api/system-removed.txt b/car-lib/api/system-removed.txt
index d802177..b8614e7 100644
--- a/car-lib/api/system-removed.txt
+++ b/car-lib/api/system-removed.txt
@@ -1 +1,9 @@
 // Signature format: 2.0
+package android.car.cluster.renderer {
+
+  @UiThread public abstract class NavigationRenderer {
+    method public void onEvent(int, android.os.Bundle);
+  }
+
+}
+
diff --git a/car-lib/api/test-baseline.txt b/car-lib/api/test-baseline.txt
index 6cb7b91..e274b0a 100644
--- a/car-lib/api/test-baseline.txt
+++ b/car-lib/api/test-baseline.txt
@@ -1,42 +1,173 @@
 // Baseline format: 1.0
-HiddenTypeParameter: android.car.hardware.CarSensorManager#getPropertyList():
-    Method android.car.hardware.CarSensorManager.getPropertyList() references hidden type class android.car.hardware.CarPropertyConfig.
-HiddenTypeParameter: android.car.navigation.CarNavigationStatusManager#getInstrumentClusterInfo():
-    Method android.car.navigation.CarNavigationStatusManager.getInstrumentClusterInfo() references hidden type android.car.navigation.CarNavigationInstrumentCluster.
-
-
-HiddenTypedefConstant: android.car.CarInfoManager#getEvConnectorTypes():
-    Typedef references constant which isn't part of the API, skipping in documentation: android.car.EvConnectorType#UNKNOWN
-HiddenTypedefConstant: android.car.CarInfoManager#getFuelTypes():
-    Typedef references constant which isn't part of the API, skipping in documentation: android.car.FuelType#UNKNOWN
-HiddenTypedefConstant: android.car.hardware.CarSensorManager#getLatestSensorEvent(int) parameter #0:
-    Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
-HiddenTypedefConstant: android.car.hardware.CarSensorManager#isSensorSupported(int) parameter #0:
-    Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
-HiddenTypedefConstant: android.car.hardware.CarSensorManager#isSensorSupported(int[], int) parameter #1:
-    Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
-HiddenTypedefConstant: android.car.hardware.CarSensorManager#registerListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int, int) parameter #1:
-    Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
-HiddenTypedefConstant: android.car.hardware.CarSensorManager#unregisterListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int) parameter #1:
-    Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
-
-
-
-ReferencesHidden: android.car.hardware.CarSensorManager#getPropertyList():
-    Class android.car.hardware.CarPropertyConfig is hidden but was referenced (as return type parameter) from public method android.car.hardware.CarSensorManager.getPropertyList()
-ReferencesHidden: android.car.navigation.CarNavigationStatusManager#getInstrumentClusterInfo():
-    Class android.car.navigation.CarNavigationInstrumentCluster is hidden but was referenced (as return type) from public method android.car.navigation.CarNavigationStatusManager.getInstrumentClusterInfo()
-
-
-RequiresPermission: android.car.hardware.CarSensorManager#registerListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int, int):
-    Method 'registerListener' documentation mentions permissions already declared by @RequiresPermission
-
-
-SdkConstant: android.car.Car#CAR_INTENT_ACTION_MEDIA_TEMPLATE:
-    Field 'CAR_INTENT_ACTION_MEDIA_TEMPLATE' is missing @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-
-
-Todo: android.car.CarInfoManager#getVehicleId():
-    Documentation mentions 'TODO'
-
-
+MissingPermission: android.car.VehiclePropertyIds#ABS_ACTIVE:
+    Permission Car.PERMISSION_CAR_DYNAMICS_STATE required by field VehiclePropertyIds.ABS_ACTIVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#AP_POWER_BOOTUP_REASON:
+    Permission Car.PERMISSION_CAR_POWER required by field VehiclePropertyIds.AP_POWER_BOOTUP_REASON is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#AP_POWER_STATE_REPORT:
+    Permission Car.PERMISSION_CAR_POWER required by field VehiclePropertyIds.AP_POWER_STATE_REPORT is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#AP_POWER_STATE_REQ:
+    Permission Car.PERMISSION_CAR_POWER required by field VehiclePropertyIds.AP_POWER_STATE_REQ is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#DISPLAY_BRIGHTNESS:
+    Permission Car.PERMISSION_CAR_POWER required by field VehiclePropertyIds.DISPLAY_BRIGHTNESS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#DOOR_LOCK:
+    Permission Car.PERMISSION_CONTROL_CAR_DOORS required by field VehiclePropertyIds.DOOR_LOCK is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#DOOR_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_DOORS required by field VehiclePropertyIds.DOOR_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#DOOR_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_DOORS required by field VehiclePropertyIds.DOOR_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#ENGINE_COOLANT_TEMP:
+    Permission Car.PERMISSION_CAR_ENGINE_DETAILED required by field VehiclePropertyIds.ENGINE_COOLANT_TEMP is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#ENGINE_OIL_LEVEL:
+    Permission Car.PERMISSION_CAR_ENGINE_DETAILED required by field VehiclePropertyIds.ENGINE_OIL_LEVEL is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#ENGINE_OIL_TEMP:
+    Permission Car.PERMISSION_CAR_ENGINE_DETAILED required by field VehiclePropertyIds.ENGINE_OIL_TEMP is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#ENGINE_RPM:
+    Permission Car.PERMISSION_CAR_ENGINE_DETAILED required by field VehiclePropertyIds.ENGINE_RPM is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#FOG_LIGHTS_STATE:
+    Permission Car.PERMISSION_EXTERIOR_LIGHTS required by field VehiclePropertyIds.FOG_LIGHTS_STATE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#FOG_LIGHTS_SWITCH:
+    Permission Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS required by field VehiclePropertyIds.FOG_LIGHTS_SWITCH is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HAZARD_LIGHTS_STATE:
+    Permission Car.PERMISSION_EXTERIOR_LIGHTS required by field VehiclePropertyIds.HAZARD_LIGHTS_STATE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HAZARD_LIGHTS_SWITCH:
+    Permission Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS required by field VehiclePropertyIds.HAZARD_LIGHTS_SWITCH is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HEADLIGHTS_STATE:
+    Permission Car.PERMISSION_EXTERIOR_LIGHTS required by field VehiclePropertyIds.HEADLIGHTS_STATE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HEADLIGHTS_SWITCH:
+    Permission Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS required by field VehiclePropertyIds.HEADLIGHTS_SWITCH is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HIGH_BEAM_LIGHTS_STATE:
+    Permission Car.PERMISSION_EXTERIOR_LIGHTS required by field VehiclePropertyIds.HIGH_BEAM_LIGHTS_STATE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HIGH_BEAM_LIGHTS_SWITCH:
+    Permission Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS required by field VehiclePropertyIds.HIGH_BEAM_LIGHTS_SWITCH is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_ACTUAL_FAN_SPEED_RPM:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_ACTUAL_FAN_SPEED_RPM is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_AC_ON:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_AC_ON is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_AUTO_ON:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_AUTO_ON is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_AUTO_RECIRC_ON:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_AUTO_RECIRC_ON is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_DEFROSTER:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_DEFROSTER is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_DUAL_ON:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_DUAL_ON is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_FAN_DIRECTION:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_FAN_DIRECTION is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_FAN_DIRECTION_AVAILABLE:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_FAN_DIRECTION_AVAILABLE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_FAN_SPEED:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_FAN_SPEED is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_MAX_AC_ON:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_MAX_AC_ON is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_MAX_DEFROST_ON:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_MAX_DEFROST_ON is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_POWER_ON:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_POWER_ON is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_RECIRC_ON:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_RECIRC_ON is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_SEAT_TEMPERATURE:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_SEAT_TEMPERATURE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_SEAT_VENTILATION:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_SEAT_VENTILATION is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_SIDE_MIRROR_HEAT:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_SIDE_MIRROR_HEAT is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_STEERING_WHEEL_HEAT:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_STEERING_WHEEL_HEAT is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_TEMPERATURE_CURRENT:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_TEMPERATURE_CURRENT is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_TEMPERATURE_DISPLAY_UNITS:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#HVAC_TEMPERATURE_SET:
+    Permission Car.PERMISSION_CONTROL_CAR_CLIMATE required by field VehiclePropertyIds.HVAC_TEMPERATURE_SET is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#MIRROR_FOLD:
+    Permission Car.PERMISSION_CONTROL_CAR_MIRRORS required by field VehiclePropertyIds.MIRROR_FOLD is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#MIRROR_LOCK:
+    Permission Car.PERMISSION_CONTROL_CAR_MIRRORS required by field VehiclePropertyIds.MIRROR_LOCK is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#MIRROR_Y_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_MIRRORS required by field VehiclePropertyIds.MIRROR_Y_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#MIRROR_Y_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_MIRRORS required by field VehiclePropertyIds.MIRROR_Y_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#MIRROR_Z_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_MIRRORS required by field VehiclePropertyIds.MIRROR_Z_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#MIRROR_Z_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_MIRRORS required by field VehiclePropertyIds.MIRROR_Z_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#OBD2_FREEZE_FRAME:
+    Permission Car.PERMISSION_CAR_DIAGNOSTIC_READ_ALL required by field VehiclePropertyIds.OBD2_FREEZE_FRAME is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#OBD2_FREEZE_FRAME_CLEAR:
+    Permission Car.PERMISSION_CAR_DIAGNOSTIC_CLEAR required by field VehiclePropertyIds.OBD2_FREEZE_FRAME_CLEAR is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#OBD2_FREEZE_FRAME_INFO:
+    Permission Car.PERMISSION_CAR_DIAGNOSTIC_READ_ALL required by field VehiclePropertyIds.OBD2_FREEZE_FRAME_INFO is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#OBD2_LIVE_FRAME:
+    Permission Car.PERMISSION_CAR_DIAGNOSTIC_READ_ALL required by field VehiclePropertyIds.OBD2_LIVE_FRAME is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#PERF_ODOMETER:
+    Permission Car.PERMISSION_MILEAGE required by field VehiclePropertyIds.PERF_ODOMETER is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_BACKREST_ANGLE_1_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_BACKREST_ANGLE_1_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_BACKREST_ANGLE_1_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_BACKREST_ANGLE_1_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_BACKREST_ANGLE_2_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_BACKREST_ANGLE_2_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_BACKREST_ANGLE_2_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_BACKREST_ANGLE_2_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_BELT_BUCKLED:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_BELT_BUCKLED is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_BELT_HEIGHT_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_BELT_HEIGHT_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_BELT_HEIGHT_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_BELT_HEIGHT_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_DEPTH_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_DEPTH_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_DEPTH_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_DEPTH_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_FORE_AFT_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_FORE_AFT_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_FORE_AFT_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_FORE_AFT_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_HEADREST_ANGLE_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_HEADREST_ANGLE_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_HEADREST_ANGLE_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_HEADREST_ANGLE_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_HEADREST_FORE_AFT_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_HEADREST_FORE_AFT_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_HEADREST_FORE_AFT_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_HEADREST_FORE_AFT_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_HEADREST_HEIGHT_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_HEADREST_HEIGHT_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_HEADREST_HEIGHT_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_HEADREST_HEIGHT_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_HEIGHT_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_HEIGHT_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_HEIGHT_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_HEIGHT_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_LUMBAR_FORE_AFT_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_LUMBAR_FORE_AFT_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_LUMBAR_FORE_AFT_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_LUMBAR_FORE_AFT_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_LUMBAR_SIDE_SUPPORT_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_LUMBAR_SIDE_SUPPORT_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_LUMBAR_SIDE_SUPPORT_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_LUMBAR_SIDE_SUPPORT_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_MEMORY_SELECT:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_MEMORY_SELECT is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_MEMORY_SET:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_MEMORY_SET is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_OCCUPANCY:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_OCCUPANCY is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_TILT_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_TILT_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#SEAT_TILT_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_SEATS required by field VehiclePropertyIds.SEAT_TILT_POS is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#TIRE_PRESSURE:
+    Permission Car.PERMISSION_TIRES required by field VehiclePropertyIds.TIRE_PRESSURE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#TRACTION_CONTROL_ACTIVE:
+    Permission Car.PERMISSION_CAR_DYNAMICS_STATE required by field VehiclePropertyIds.TRACTION_CONTROL_ACTIVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#TURN_SIGNAL_STATE:
+    Permission Car.PERMISSION_EXTERIOR_LIGHTS required by field VehiclePropertyIds.TURN_SIGNAL_STATE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#VEHICLE_MAP_SERVICE:
+    Permission Car.PERMISSION_VMS_PUBLISHER required by field VehiclePropertyIds.VEHICLE_MAP_SERVICE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#WINDOW_LOCK:
+    Permission Car.PERMISSION_CONTROL_CAR_WINDOWS required by field VehiclePropertyIds.WINDOW_LOCK is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#WINDOW_MOVE:
+    Permission Car.PERMISSION_CONTROL_CAR_WINDOWS required by field VehiclePropertyIds.WINDOW_MOVE is hidden or removed
+MissingPermission: android.car.VehiclePropertyIds#WINDOW_POS:
+    Permission Car.PERMISSION_CONTROL_CAR_WINDOWS required by field VehiclePropertyIds.WINDOW_POS is hidden or removed
diff --git a/car-lib/api/test-current.txt b/car-lib/api/test-current.txt
index 515bd93..49d4bb5 100644
--- a/car-lib/api/test-current.txt
+++ b/car-lib/api/test-current.txt
@@ -1,4 +1,30 @@
 // Signature format: 2.0
+package android.car {
+
+  public final class Car {
+    field public static final String CAR_USER_SERVICE = "car_user_service";
+  }
+
+  public final class CarAppFocusManager {
+    method public int[] getActiveAppTypes();
+  }
+
+  public class VehiclePropertyType {
+    field public static final int BOOLEAN = 2097152; // 0x200000
+    field public static final int BYTES = 7340032; // 0x700000
+    field public static final int FLOAT = 6291456; // 0x600000
+    field public static final int FLOAT_VEC = 6356992; // 0x610000
+    field public static final int INT32 = 4194304; // 0x400000
+    field public static final int INT32_VEC = 4259840; // 0x410000
+    field public static final int INT64 = 5242880; // 0x500000
+    field public static final int INT64_VEC = 5308416; // 0x510000
+    field public static final int MASK = 16711680; // 0xff0000
+    field public static final int MIXED = 14680064; // 0xe00000
+    field public static final int STRING = 1048576; // 0x100000
+  }
+
+}
+
 package android.car.content.pm {
 
   public final class CarPackageManager {
@@ -23,3 +49,29 @@
 
 }
 
+package android.car.user {
+
+  public final class CarUserManager {
+    method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void addListener(@NonNull java.util.concurrent.Executor, @NonNull android.car.user.CarUserManager.UserLifecycleListener);
+    method public static String lifecycleEventTypeToString(int);
+    method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void removeListener(@NonNull android.car.user.CarUserManager.UserLifecycleListener);
+    field public static final int USER_LIFECYCLE_EVENT_TYPE_STARTING = 1; // 0x1
+    field public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPED = 6; // 0x6
+    field public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPING = 5; // 0x5
+    field public static final int USER_LIFECYCLE_EVENT_TYPE_SWITCHING = 2; // 0x2
+    field public static final int USER_LIFECYCLE_EVENT_TYPE_UNLOCKED = 4; // 0x4
+    field public static final int USER_LIFECYCLE_EVENT_TYPE_UNLOCKING = 3; // 0x3
+  }
+
+  public static final class CarUserManager.UserLifecycleEvent {
+    method public int getEventType();
+    method @Nullable public android.os.UserHandle getPreviousUserHandle();
+    method @NonNull public android.os.UserHandle getUserHandle();
+  }
+
+  public static interface CarUserManager.UserLifecycleListener {
+    method public void onEvent(@NonNull android.car.user.CarUserManager.UserLifecycleEvent);
+  }
+
+}
+
diff --git a/car-lib/native/include/CarPowerManager.h b/car-lib/native/include/CarPowerManager.h
index 57bbd50..b02c886 100644
--- a/car-lib/native/include/CarPowerManager.h
+++ b/car-lib/native/include/CarPowerManager.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef CAR_POWER_MANAGER
-#define CAR_POWER_MANAGER
+#ifndef CAR_LIB_NATIVE_INCLUDE_CARPOWERMANAGER_H_
+#define CAR_LIB_NATIVE_INCLUDE_CARPOWERMANAGER_H_
 
 #include <binder/Status.h>
 #include <utils/RefBase.h>
@@ -38,6 +38,7 @@
     //  NOTE:  The entries in this enum must match the ones in CarPowerStateListener located in
     //      packages/services/Car/car-lib/src/android/car/hardware/power/CarPowerManager.java
     enum class State {
+        kInvalid = 0,
         kWaitForVhal = 1,
         kSuspendEnter = 2,
         kSuspendExit = 3,
@@ -46,8 +47,7 @@
         kShutdownPrepare = 7,
         kShutdownCancelled = 8,
 
-
-        kFirst = kWaitForVhal,
+        kFirst = kInvalid,
         kLast = kShutdownCancelled,
     };
 
@@ -74,7 +74,7 @@
 private:
     class CarPowerStateListener final : public BnCarPowerStateListener {
     public:
-        explicit CarPowerStateListener(CarPowerManager* parent) : mParent(parent) {};
+        explicit CarPowerStateListener(CarPowerManager* parent) : mParent(parent) {}
 
         Status onStateChanged(int state) override {
             sp<CarPowerManager> parent = mParent;
@@ -102,9 +102,9 @@
     sp<CarPowerStateListener> mListenerToService;
 };
 
-} // namespace power
-} // namespace hardware
-} // namespace car
-} // namespace android
+}  // namespace power
+}  // namespace hardware
+}  // namespace car
+}  // namespace android
 
-#endif // CAR_POWER_MANAGER
+#endif  // CAR_LIB_NATIVE_INCLUDE_CARPOWERMANAGER_H_
diff --git a/car-lib/src/android/car/AoapService.java b/car-lib/src/android/car/AoapService.java
index 0637e75..de21621 100644
--- a/car-lib/src/android/car/AoapService.java
+++ b/car-lib/src/android/car/AoapService.java
@@ -16,8 +16,6 @@
 
 package android.car;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 import android.annotation.IntDef;
 import android.annotation.MainThread;
 import android.annotation.NonNull;
@@ -39,6 +37,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
+import java.util.Objects;
 
 /**
  * The service that must be implemented by USB AOAP handler system apps. The app must hold the
@@ -203,7 +202,7 @@
             switch (msg.what) {
                 case MSG_NEW_DEVICE_ATTACHED: {
                     int res = service.isDeviceSupported(
-                            checkNotNull(data.getParcelable(KEY_DEVICE)));
+                            Objects.requireNonNull(data.getParcelable(KEY_DEVICE)));
                     if (res != RESULT_OK && res != RESULT_DEVICE_NOT_SUPPORTED) {
                         throw new IllegalArgumentException("Result can not be " + res);
                     }
@@ -213,7 +212,7 @@
 
                 case MSG_CAN_SWITCH_TO_AOAP: {
                     int res = service.canSwitchToAoap(
-                            checkNotNull(data.getParcelable(KEY_DEVICE)));
+                            Objects.requireNonNull(data.getParcelable(KEY_DEVICE)));
                     if (res != RESULT_OK && res != RESULT_DEVICE_NOT_SUPPORTED
                             && res != RESULT_DO_NOT_SWITCH_TO_AOAP) {
                         throw new IllegalArgumentException("Result can not be " + res);
diff --git a/car-lib/src/android/car/Car.java b/car-lib/src/android/car/Car.java
index 086e5c8..099d56a 100644
--- a/car-lib/src/android/car/Car.java
+++ b/car-lib/src/android/car/Car.java
@@ -21,11 +21,16 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.Activity;
 import android.app.Service;
+import android.car.annotation.MandatoryFeature;
+import android.car.annotation.OptionalFeature;
 import android.car.cluster.CarInstrumentClusterManager;
 import android.car.cluster.ClusterActivityState;
 import android.car.content.pm.CarPackageManager;
@@ -39,14 +44,19 @@
 import android.car.hardware.power.CarPowerManager;
 import android.car.hardware.property.CarPropertyManager;
 import android.car.hardware.property.ICarProperty;
+import android.car.input.CarInputManager;
 import android.car.media.CarAudioManager;
 import android.car.media.CarMediaManager;
 import android.car.navigation.CarNavigationStatusManager;
+import android.car.occupantawareness.OccupantAwarenessManager;
 import android.car.settings.CarConfigurationManager;
 import android.car.storagemonitoring.CarStorageMonitoringManager;
 import android.car.test.CarTestManagerBinderWrapper;
 import android.car.trust.CarTrustAgentEnrollmentManager;
+import android.car.user.CarUserManager;
+import android.car.vms.VmsClientManager;
 import android.car.vms.VmsSubscriberManager;
+import android.car.watchdog.CarWatchdogManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -65,13 +75,17 @@
 
 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.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
 
 /**
  *   Top level car API for embedded Android Auto deployments.
@@ -86,35 +100,91 @@
      * @hide
      */
     public static final String CAR_SERVICE_BINDER_SERVICE_NAME = "car_service";
+
+    /**
+     * This represents AndroidManifest meta-data to tell that {@code Activity} is optimized for
+     * driving distraction.
+     *
+     * <p>Activities without this meta-data can be blocked while car is in moving / driving state.
+     *
+     * <p>Note that having this flag does not guarantee that the {@code Activity} will be always
+     * allowed for all driving states.
+     *
+     * <p>For this meta-data, android:value can be {@code true} (=optimized) or {@code false}.
+     *
+     * <p>Example usage:
+     * <xml><meta-data android:name="distractionOptimized" android:value="true"/></xml>
+     */
+    @SuppressLint("IntentName")
+    public static final String META_DATA_DISTRACTION_OPTIMIZED = "distractionOptimized";
+
+    /**
+     * This represents AndroidManifest meta-data to tell that {@code Application} requires specific
+     * car features to work.
+     *
+     * <p>Apps like launcher or installer app can use this information to filter out apps
+     * not usable in a specific car. This meta-data is not necessary for mandatory features.
+     *
+     * <p>For this meta-data, android:value should contain the feature name string defined by
+     * (@link android.car.annotation.OptionalFeature} or
+     * {@link android.car.annotation.ExperimentalFeature} annotations.
+     *
+     * <p>Example usage:
+     * <xml><meta-data android:name="requires-car-feature" android:value="diagnostic"/></xml>
+     */
+    @SuppressLint("IntentName")
+    public static final String META_DATA_REQUIRES_CAR_FEATURE = "requires-car-feature";
+
     /**
      * Service name for {@link CarSensorManager}, to be used in {@link #getCarManager(String)}.
      *
      * @deprecated  {@link CarSensorManager} is deprecated. Use {@link CarPropertyManager} instead.
      */
+    @MandatoryFeature
     @Deprecated
     public static final String SENSOR_SERVICE = "sensor";
 
     /** Service name for {@link CarInfoManager}, to be used in {@link #getCarManager(String)}. */
+    @MandatoryFeature
     public static final String INFO_SERVICE = "info";
 
     /** Service name for {@link CarAppFocusManager}. */
+    @MandatoryFeature
     public static final String APP_FOCUS_SERVICE = "app_focus";
 
     /** Service name for {@link CarPackageManager} */
+    @MandatoryFeature
     public static final String PACKAGE_SERVICE = "package";
 
     /** Service name for {@link CarAudioManager} */
+    @MandatoryFeature
     public static final String AUDIO_SERVICE = "audio";
 
     /** Service name for {@link CarNavigationStatusManager} */
+    @OptionalFeature
     public static final String CAR_NAVIGATION_SERVICE = "car_navigation_service";
 
+    /** Service name for {@link CarOccupantZoneManager} */
+    @MandatoryFeature
+    public static final String CAR_OCCUPANT_ZONE_SERVICE = "car_occupant_zone_service";
+
+    /**
+     * Service name for {@link CarUserManager}
+     *
+     * @hide
+     */
+    @MandatoryFeature
+    @SystemApi
+    @TestApi
+    public static final String CAR_USER_SERVICE = "car_user_service";
+
     /**
      * Service name for {@link CarInstrumentClusterManager}
      *
      * @deprecated CarInstrumentClusterManager is being deprecated
      * @hide
      */
+    @MandatoryFeature
     @Deprecated
     public static final String CAR_INSTRUMENT_CLUSTER_SERVICE = "cluster_service";
 
@@ -124,6 +194,7 @@
      * @deprecated {@link CarCabinManager} is deprecated. Use {@link CarPropertyManager} instead.
      * @hide
      */
+    @MandatoryFeature
     @Deprecated
     @SystemApi
     public static final String CABIN_SERVICE = "cabin";
@@ -131,6 +202,7 @@
     /**
      * @hide
      */
+    @OptionalFeature
     @SystemApi
     public static final String DIAGNOSTIC_SERVICE = "diagnostic";
 
@@ -139,6 +211,7 @@
      * @deprecated {@link CarHvacManager} is deprecated. Use {@link CarPropertyManager} instead.
      * @hide
      */
+    @MandatoryFeature
     @Deprecated
     @SystemApi
     public static final String HVAC_SERVICE = "hvac";
@@ -146,18 +219,21 @@
     /**
      * @hide
      */
+    @MandatoryFeature
     @SystemApi
     public static final String POWER_SERVICE = "power";
 
     /**
      * @hide
      */
+    @MandatoryFeature
     @SystemApi
     public static final String PROJECTION_SERVICE = "projection";
 
     /**
      * Service name for {@link CarPropertyManager}
      */
+    @MandatoryFeature
     public static final String PROPERTY_SERVICE = "property";
 
     /**
@@ -167,6 +243,7 @@
      * Use {@link CarPropertyManager} instead.
      * @hide
      */
+    @MandatoryFeature
     @Deprecated
     @SystemApi
     public static final String VENDOR_EXTENSION_SERVICE = "vendor_extension";
@@ -174,11 +251,26 @@
     /**
      * @hide
      */
+    @MandatoryFeature
     public static final String BLUETOOTH_SERVICE = "car_bluetooth";
 
     /**
+     * Service name for {@link VmsClientManager}
+     *
      * @hide
      */
+    @OptionalFeature
+    @SystemApi
+    public static final String VEHICLE_MAP_SERVICE = "vehicle_map_service";
+
+    /**
+     * Service name for {@link VmsSubscriberManager}
+     *
+     * @deprecated {@link VmsSubscriberManager} is deprecated. Use {@link VmsClientManager} instead.
+     * @hide
+     */
+    @OptionalFeature
+    @Deprecated
     @SystemApi
     public static final String VMS_SUBSCRIBER_SERVICE = "vehicle_map_subscriber_service";
 
@@ -186,6 +278,7 @@
      * Service name for {@link CarDrivingStateManager}
      * @hide
      */
+    @MandatoryFeature
     @SystemApi
     public static final String CAR_DRIVING_STATE_SERVICE = "drivingstate";
 
@@ -194,6 +287,11 @@
      */
     public static final String CAR_UX_RESTRICTION_SERVICE = "uxrestriction";
 
+    /** @hide */
+    @OptionalFeature
+    @SystemApi
+    public static final String OCCUPANT_AWARENESS_SERVICE = "occupant_awareness";
+
     /**
      * Service name for {@link android.car.settings.CarConfigurationManager}
      */
@@ -203,6 +301,8 @@
      * Service name for {@link android.car.media.CarMediaManager}
      * @hide
      */
+    @MandatoryFeature
+    @SystemApi
     public static final String CAR_MEDIA_SERVICE = "car_media";
 
     /**
@@ -210,11 +310,13 @@
      * Service name for {@link android.car.CarBugreportManager}
      * @hide
      */
+    @MandatoryFeature
     public static final String CAR_BUGREPORT_SERVICE = "car_bugreport";
 
     /**
      * @hide
      */
+    @OptionalFeature
     @SystemApi
     public static final String STORAGE_MONITORING_SERVICE = "storage_monitoring";
 
@@ -226,10 +328,24 @@
     public static final String CAR_TRUST_AGENT_ENROLLMENT_SERVICE = "trust_enroll";
 
     /**
+     * Service name for {@link android.car.watchdog.CarWatchdogManager}
+     * @hide
+     */
+    @MandatoryFeature
+    @SystemApi
+    public static final String CAR_WATCHDOG_SERVICE = "car_watchdog";
+
+    /**
+     * @hide
+     */
+    public static final String CAR_INPUT_SERVICE = "android.car.input";
+
+    /**
      * Service for testing. This is system app only feature.
      * Service name for {@link CarTestManager}, to be used in {@link #getCarManager(String)}.
      * @hide
      */
+    @MandatoryFeature
     @SystemApi
     public static final String TEST_SERVICE = "car-service-test";
 
@@ -242,6 +358,14 @@
     /** Permission necessary to access car's energy information. */
     public static final String PERMISSION_ENERGY = "android.car.permission.CAR_ENERGY";
 
+    /**
+     * Permission necessary to change value of car's range remaining.
+     * @hide
+     */
+    @SystemApi
+    public static final String PERMISSION_ADJUST_RANGE_REMAINING =
+            "android.car.permission.ADJUST_RANGE_REMAINING";
+
     /** Permission necessary to access car's VIN information */
     public static final String PERMISSION_IDENTIFICATION =
             "android.car.permission.CAR_IDENTIFICATION";
@@ -259,7 +383,15 @@
     /** Permission necessary to access car's fuel door and ev charge port. */
     public static final String PERMISSION_ENERGY_PORTS = "android.car.permission.CAR_ENERGY_PORTS";
 
-    /** Permission necessary to read car's exterior lights information.
+    /**
+     * Permission necessary to control car's fuel door and ev charge port.
+     * @hide
+     */
+    @SystemApi
+    public static final String PERMISSION_CONTROL_ENERGY_PORTS =
+            "android.car.permission.CONTROL_CAR_ENERGY_PORTS";
+    /**
+     * Permission necessary to read car's exterior lights information.
      *  @hide
      */
     @SystemApi
@@ -337,6 +469,14 @@
     /** Permission necessary to use {@link CarInfoManager}. */
     public static final String PERMISSION_CAR_INFO = "android.car.permission.CAR_INFO";
 
+    /**
+     * Permission necessary to read information of vendor properties' permissions.
+     * @hide
+     */
+    @SystemApi
+    public static final String PERMISSION_READ_CAR_VENDOR_PERMISSION_INFO =
+            "android.car.permission.READ_CAR_VENDOR_PERMISSION_INFO";
+
     /** Permission necessary to read temperature of car's exterior environment. */
     public static final String PERMISSION_EXTERIOR_ENVIRONMENT =
             "android.car.permission.CAR_EXTERIOR_ENVIRONMENT";
@@ -457,6 +597,7 @@
      * @hide
      * @deprecated mocking vehicle HAL in car service is no longer supported.
      */
+    @Deprecated
     @SystemApi
     public static final String PERMISSION_MOCK_VEHICLE_HAL =
             "android.car.permission.CAR_MOCK_VEHICLE_HAL";
@@ -508,7 +649,7 @@
      */
     @SystemApi
     public static final String PERMISSION_CAR_DIAGNOSTIC_READ_ALL =
-        "android.car.permission.CAR_DIAGNOSTICS";
+            "android.car.permission.CAR_DIAGNOSTICS";
 
     /**
      * Permissions necessary to clear diagnostic information.
@@ -528,6 +669,24 @@
             "android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION";
 
     /**
+     * Permission necessary to listen to occupant awareness state {@link OccupantAwarenessManager}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE =
+            "android.car.permission.READ_CAR_OCCUPANT_AWARENESS_STATE";
+
+    /**
+     * Permission necessary to modify occupant awareness graph.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String PERMISSION_CONTROL_CAR_OCCUPANT_AWARENESS_SYSTEM =
+            "android.car.permission.CONTROL_CAR_OCCUPANT_AWARENESS_SYSTEM";
+
+    /**
      * Permissions necessary to clear diagnostic information.
      *
      * @hide
@@ -545,6 +704,24 @@
     public static final String PERMISSION_CAR_ENROLL_TRUST =
             "android.car.permission.CAR_ENROLL_TRUST";
 
+    /**
+     * Permission necessary to dynamically enable / disable optional car features.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String PERMISSION_CONTROL_CAR_FEATURES =
+            "android.car.permission.CONTROL_CAR_FEATURES";
+
+    /**
+     * Permission necessary to be car watchdog clients.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String PERMISSION_USE_CAR_WATCHDOG =
+            "android.car.permission.USE_CAR_WATCHDOG";
+
     /** Type of car connection: platform runs directly in car. */
     public static final int CONNECTION_TYPE_EMBEDDED = 5;
 
@@ -568,25 +745,22 @@
     /**
      * Used as a string extra field with {@link #CAR_INTENT_ACTION_MEDIA_TEMPLATE} to specify the
      * MediaBrowserService that user wants to start the media on.
-     *
-     * @hide
      */
     public static final String CAR_EXTRA_MEDIA_COMPONENT =
             "android.car.intent.extra.MEDIA_COMPONENT";
 
     /**
-     * Used as a string extra field with {@link #CAR_INTENT_ACTION_MEDIA_TEMPLATE} to specify the
-     * media app that user wants to start the media on. Note: this is not the templated media app.
      *
-     * This is being deprecated. Use {@link #CAR_EXTRA_MEDIA_COMPONENT} instead.
+     * @deprecated Use{@link #CAR_EXTRA_MEDIA_COMPONENT} instead.
+     * @removed Using this for specifying MediaBrowserService was not supported since API level 29
+     * and above. Apps must use {@link #CAR_EXTRA_MEDIA_COMPONENT} instead.
      */
+    @Deprecated
     public static final String CAR_EXTRA_MEDIA_PACKAGE = "android.car.intent.extra.MEDIA_PACKAGE";
 
     /**
      * Used as a string extra field of media session to specify the service corresponding to the
      * session.
-     *
-     * @hide
      */
     public static final String CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION =
             "android.media.session.BROWSE_SERVICE";
@@ -630,7 +804,6 @@
      * 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 {
         /**
@@ -650,14 +823,12 @@
     /**
      * {@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;
 
@@ -681,6 +852,43 @@
     @Target({ElementType.TYPE_USE})
     public @interface StateTypeEnum {}
 
+    /**
+     * The enabling request was successful and requires reboot to take effect.
+     * @hide
+     */
+    @SystemApi
+    public static final int FEATURE_REQUEST_SUCCESS = 0;
+    /**
+     * The requested feature is already enabled or disabled as requested. No need to reboot the
+     * system.
+     * @hide
+     */
+    @SystemApi
+    public static final int FEATURE_REQUEST_ALREADY_IN_THE_STATE = 1;
+    /**
+     * The requested feature is mandatory cannot be enabled or disabled. It is always enabled.
+     * @hide
+     */
+    @SystemApi
+    public static final int FEATURE_REQUEST_MANDATORY = 2;
+    /**
+     * The requested feature is not available and cannot be enabled or disabled.
+     * @hide
+     */
+    @SystemApi
+    public static final int FEATURE_REQUEST_NOT_EXISTING = 3;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "FEATURE_REQUEST_", value = {
+            FEATURE_REQUEST_SUCCESS,
+            FEATURE_REQUEST_ALREADY_IN_THE_STATE,
+            FEATURE_REQUEST_MANDATORY,
+            FEATURE_REQUEST_NOT_EXISTING,
+    })
+    @Target({ElementType.TYPE_USE})
+    public @interface FeaturerRequestEnum {}
+
     private static final boolean DBG = false;
 
     private final Context mContext;
@@ -716,7 +924,7 @@
     };
 
     private final ServiceConnection mServiceConnectionListener =
-            new ServiceConnection () {
+            new ServiceConnection() {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
             synchronized (mLock) {
@@ -741,6 +949,8 @@
 
         @Override
         public void onServiceDisconnected(ComponentName name) {
+            // Car service can pick up feature changes after restart.
+            mFeatures.resetCache();
             synchronized (mLock) {
                 if (mConnectionState  == STATE_DISCONNECTED) {
                     // can happen when client calls disconnect before onServiceDisconnected call.
@@ -774,8 +984,14 @@
 
     private final Handler mMainThreadEventHandler;
 
+    private final CarFeatures mFeatures = new CarFeatures();
+
     /**
      * A factory method that creates Car instance for all Car API access.
+     *
+     * <p>Instance created with this should be disconnected from car service by calling
+     * {@link #disconnect()} before the passed {code Context} is released.
+     *
      * @param context App's Context. This should not be null. If you are passing
      *                {@link ContextWrapper}, make sure that its base Context is non-null as well.
      *                Otherwise it will throw {@link java.lang.NullPointerException}.
@@ -808,18 +1024,24 @@
      * A factory method that creates Car instance for all Car API access using main thread {@code
      * Looper}.
      *
+     * <p>Instance created with this should be disconnected from car service by calling
+     * {@link #disconnect()} before the passed {code Context} is released.
+     *
      * @see #createCar(Context, ServiceConnection, Handler)
      *
      * @deprecated use {@link #createCar(Context, Handler)} instead.
      */
     @Deprecated
     public static Car createCar(Context context, ServiceConnection serviceConnectionListener) {
-      return createCar(context, serviceConnectionListener, null);
+        return createCar(context, serviceConnectionListener, null);
     }
 
     /**
      * Creates new {@link Car} object which connected synchronously to Car Service and ready to use.
      *
+     * <p>Instance created with this should be disconnected from car service by calling
+     * {@link #disconnect()} before the passed {code Context} is released.
+     *
      * @param context application's context
      *
      * @return Car object if operation succeeded, otherwise null.
@@ -832,6 +1054,9 @@
     /**
      * Creates new {@link Car} object which connected synchronously to Car Service and ready to use.
      *
+     * <p>Instance created with this should be disconnected from car service by calling
+     * {@link #disconnect()} before the passed {code Context} is released.
+     *
      * @param context App's Context. This should not be null. If you are passing
      *                {@link ContextWrapper}, make sure that its base Context is non-null as well.
      *                Otherwise it will throw {@link java.lang.NullPointerException}.
@@ -899,6 +1124,9 @@
     /**
      * Creates new {@link Car} object with {@link CarServiceLifecycleListener}.
      *
+     * <p>Instance created with this should be disconnected from car service by calling
+     * {@link #disconnect()} before the passed {code Context} is released.
+     *
      * <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,
@@ -932,15 +1160,13 @@
      *                      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
      */
     @NonNull
     public static Car createCar(@NonNull Context context,
             @Nullable Handler handler, long waitTimeoutMs,
             @NonNull CarServiceLifecycleListener statusChangeListener) {
         assertNonNullContext(context);
-        Preconditions.checkNotNull(statusChangeListener);
+        Objects.requireNonNull(statusChangeListener);
         Car car = null;
         IBinder service = null;
         boolean started = false;
@@ -1021,7 +1247,7 @@
     }
 
     private static void assertNonNullContext(Context context) {
-        Preconditions.checkNotNull(context);
+        Objects.requireNonNull(context);
         if (context instanceof ContextWrapper
                 && ((ContextWrapper) context).getBaseContext() == null) {
             throw new NullPointerException(
@@ -1185,7 +1411,7 @@
                                 + serviceName);
                         return null;
                     }
-                    manager = createCarManager(serviceName, binder);
+                    manager = createCarManagerLocked(serviceName, binder);
                     if (manager == null) {
                         Log.w(TAG_CAR, "getCarManager could not create manager for service:"
                                         + serviceName);
@@ -1209,18 +1435,160 @@
         return CONNECTION_TYPE_EMBEDDED;
     }
 
+    /**
+     * Checks if {code featureName} is enabled in this car.
+     *
+     * <p>For optional features, this can return false if the car cannot support it. Optional
+     * features should be used only when they are supported.</p>
+     *
+     * <p>For mandatory features, this will always return true.
+     */
+    public boolean isFeatureEnabled(@NonNull String featureName) {
+        ICar service;
+        synchronized (mLock) {
+            if (mService == null) {
+                return false;
+            }
+            service = mService;
+        }
+        return mFeatures.isFeatureEnabled(service, featureName);
+    }
+
+    /**
+     * Enables the requested car feature. It becomes no-op if the feature is already enabled. The
+     * change take effects after reboot.
+     *
+     * @return true if the feature is enabled or was enabled before.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(PERMISSION_CONTROL_CAR_FEATURES)
+    @FeaturerRequestEnum
+    public int enableFeature(@NonNull String featureName) {
+        ICar service;
+        synchronized (mLock) {
+            if (mService == null) {
+                return FEATURE_REQUEST_NOT_EXISTING;
+            }
+            service = mService;
+        }
+        try {
+            return service.enableFeature(featureName);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, FEATURE_REQUEST_NOT_EXISTING);
+        }
+    }
+
+    /**
+     * Disables the requested car feature. It becomes no-op if the feature is already disabled. The
+     * change take effects after reboot.
+     *
+     * @return true if the request succeeds or if it was already disabled.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(PERMISSION_CONTROL_CAR_FEATURES)
+    @FeaturerRequestEnum
+    public int disableFeature(@NonNull String featureName) {
+        ICar service;
+        synchronized (mLock) {
+            if (mService == null) {
+                return FEATURE_REQUEST_NOT_EXISTING;
+            }
+            service = mService;
+        }
+        try {
+            return service.disableFeature(featureName);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, FEATURE_REQUEST_NOT_EXISTING);
+        }
+    }
+
+    /**
+     * Returns all =enabled features at the moment including mandatory, optional, and
+     * experimental features.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(PERMISSION_CONTROL_CAR_FEATURES)
+    @NonNull public List<String> getAllEnabledFeatures() {
+        ICar service;
+        synchronized (mLock) {
+            if (mService == null) {
+                return Collections.EMPTY_LIST;
+            }
+            service = mService;
+        }
+        try {
+            return service.getAllEnabledFeatures();
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, Collections.EMPTY_LIST);
+        }
+    }
+
+    /**
+     * Returns the list of disabled features which are not effective yet. Those features will be
+     * disabled when system restarts later.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(PERMISSION_CONTROL_CAR_FEATURES)
+    @NonNull public List<String> getAllPendingDisabledFeatures() {
+        ICar service;
+        synchronized (mLock) {
+            if (mService == null) {
+                return Collections.EMPTY_LIST;
+            }
+            service = mService;
+        }
+        try {
+            return service.getAllPendingDisabledFeatures();
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, Collections.EMPTY_LIST);
+        }
+    }
+
+    /**
+     * Returns the list of enabled features which are not effective yet. Those features will be
+     * enabled when system restarts later.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(PERMISSION_CONTROL_CAR_FEATURES)
+    @NonNull public List<String> getAllPendingEnabledFeatures() {
+        ICar service;
+        synchronized (mLock) {
+            if (mService == null) {
+                return Collections.EMPTY_LIST;
+            }
+            service = mService;
+        }
+        try {
+            return service.getAllPendingEnabledFeatures();
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, Collections.EMPTY_LIST);
+        }
+    }
+
     /** @hide */
-    Context getContext() {
+    public Context getContext() {
         return mContext;
     }
 
     /** @hide */
-    Handler getEventHandler() {
+    @VisibleForTesting
+    public Handler getEventHandler() {
         return mEventHandler;
     }
 
     /** @hide */
-    <T> T handleRemoteExceptionFromCarService(RemoteException e, T returnValue) {
+    @VisibleForTesting
+    public <T> T handleRemoteExceptionFromCarService(RemoteException e, T returnValue) {
         handleRemoteExceptionFromCarService(e);
         return returnValue;
     }
@@ -1290,7 +1658,7 @@
     }
 
     @Nullable
-    private CarManagerBase createCarManager(String serviceName, IBinder binder) {
+    private CarManagerBase createCarManagerLocked(String serviceName, IBinder binder) {
         CarManagerBase manager = null;
         switch (serviceName) {
             case AUDIO_SERVICE:
@@ -1308,6 +1676,9 @@
             case PACKAGE_SERVICE:
                 manager = new CarPackageManager(this, binder);
                 break;
+            case CAR_OCCUPANT_ZONE_SERVICE:
+                manager = new CarOccupantZoneManager(this, binder);
+                break;
             case CAR_NAVIGATION_SERVICE:
                 manager = new CarNavigationStatusManager(this, binder);
                 break;
@@ -1340,8 +1711,12 @@
                  * only pass binder wrapper so that CarTestManager can be constructed outside. */
                 manager = new CarTestManagerBinderWrapper(this, binder);
                 break;
+            case VEHICLE_MAP_SERVICE:
+                manager = new VmsClientManager(this, binder);
+                break;
             case VMS_SUBSCRIBER_SERVICE:
-                manager = new VmsSubscriberManager(this, binder);
+                manager = VmsSubscriberManager.wrap(this,
+                        (VmsClientManager) getCarManager(VEHICLE_MAP_SERVICE));
                 break;
             case BLUETOOTH_SERVICE:
                 manager = new CarBluetoothManager(this, binder);
@@ -1355,6 +1730,9 @@
             case CAR_UX_RESTRICTION_SERVICE:
                 manager = new CarUxRestrictionsManager(this, binder);
                 break;
+            case OCCUPANT_AWARENESS_SERVICE:
+                manager = new OccupantAwarenessManager(this, binder);
+                break;
             case CAR_CONFIGURATION_SERVICE:
                 manager = new CarConfigurationManager(this, binder);
                 break;
@@ -1367,12 +1745,51 @@
             case CAR_BUGREPORT_SERVICE:
                 manager = new CarBugreportManager(this, binder);
                 break;
+            case CAR_USER_SERVICE:
+                manager = new CarUserManager(this, binder);
+                break;
+            case CAR_WATCHDOG_SERVICE:
+                manager = new CarWatchdogManager(this, binder);
+                break;
+            case CAR_INPUT_SERVICE:
+                manager = new CarInputManager(this, binder);
+                break;
             default:
+                // Experimental or non-existing
+                String className = null;
+                try {
+                    className = mService.getCarManagerClassForFeature(serviceName);
+                } catch (RemoteException e) {
+                    handleRemoteExceptionFromCarService(e);
+                    return null;
+                }
+                if (className == null) {
+                    Log.e(TAG_CAR, "Cannot construct CarManager for service:" + serviceName
+                            + " : no class defined");
+                    return null;
+                }
+                manager = constructCarManager(className, binder);
                 break;
         }
         return manager;
     }
 
+    private CarManagerBase constructCarManager(String className, IBinder binder) {
+        try {
+            // Should use class loader for the Context as class loader for car api does not
+            // see the class.
+            ClassLoader loader = mContext.getClassLoader();
+            Class managerClass = loader.loadClass(className);
+            Constructor constructor = managerClass.getConstructor(Car.class, IBinder.class);
+            CarManagerBase manager = (CarManagerBase) constructor.newInstance(this, binder);
+            return manager;
+        } catch (ClassNotFoundException | IllegalAccessException | NoSuchMethodException
+                | InstantiationException | InvocationTargetException e) {
+            Log.e(TAG_CAR, "Cannot construct CarManager, class:" + className, e);
+            return null;
+        }
+    }
+
     private void startCarService() {
         Intent intent = new Intent();
         intent.setPackage(CAR_SERVICE_PACKAGE);
diff --git a/car-lib/src/android/car/CarAppFocusManager.java b/car-lib/src/android/car/CarAppFocusManager.java
index b8936af..cc0d10b 100644
--- a/car-lib/src/android/car/CarAppFocusManager.java
+++ b/car-lib/src/android/car/CarAppFocusManager.java
@@ -17,9 +17,12 @@
 package android.car;
 
 import android.annotation.IntDef;
+import android.annotation.TestApi;
 import android.os.IBinder;
 import android.os.RemoteException;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
@@ -42,8 +45,11 @@
         /**
          * Application focus has changed. Note that {@link CarAppFocusManager} instance
          * causing the change will not get this notification.
-         * @param appType
-         * @param active
+         *
+         * <p>Note that this call can happen for app focus grant, release, and ownership change.
+         *
+         * @param appType appType where the focus change has happened.
+         * @param active {@code true} if there is an active owner for the focus.
          */
         void onAppFocusChanged(@AppFocusType int appType, boolean active);
     }
@@ -121,7 +127,8 @@
     /**
      * @hide
      */
-    CarAppFocusManager(Car car, IBinder service) {
+    @VisibleForTesting
+    public CarAppFocusManager(Car car, IBinder service) {
         super(car);
         mService = IAppFocus.Stub.asInterface(service);
     }
@@ -204,6 +211,7 @@
      * Returns application types currently active in the system.
      * @hide
      */
+    @TestApi
     public int[] getActiveAppTypes() {
         try {
             return mService.getActiveAppTypes();
diff --git a/car-lib/src/android/car/CarBugreportManager.java b/car-lib/src/android/car/CarBugreportManager.java
index 99f2c7c..1d7f862 100644
--- a/car-lib/src/android/car/CarBugreportManager.java
+++ b/car-lib/src/android/car/CarBugreportManager.java
@@ -25,13 +25,12 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 
-import com.android.internal.util.Preconditions;
-
 import libcore.io.IoUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
+import java.util.Objects;
 
 /**
  * Car specific bugreport manager. Only available for userdebug and eng builds.
@@ -162,25 +161,25 @@
      * bugreport and makes them available through a extra output file. Currently the extra
      * output contains the screenshots for all the physical displays.
      *
-     * <p>The file descriptor is closed when bugreport is written or if an exception happens.
+     * <p>It closes provided file descriptors. The callback runs on a background thread.
      *
      * <p>This method is enabled only for one bug reporting app. It can be configured using
      * {@code config_car_bugreport_application} string that is defined in
      * {@code packages/services/Car/service/res/values/config.xml}. To learn more please
      * see {@code packages/services/Car/tests/BugReportApp/README.md}.
      *
-     * @param output the zipped bugreport file
+     * @param output the zipped bugreport file.
      * @param extraOutput a zip file that contains extra files generated for automotive.
-     * @param callback  the callback for reporting dump status
+     * @param callback the callback for reporting dump status.
      */
     @RequiresPermission(android.Manifest.permission.DUMP)
     public void requestBugreport(
             @NonNull ParcelFileDescriptor output,
             @NonNull ParcelFileDescriptor extraOutput,
             @NonNull CarBugreportManagerCallback callback) {
-        Preconditions.checkNotNull(output);
-        Preconditions.checkNotNull(extraOutput);
-        Preconditions.checkNotNull(callback);
+        Objects.requireNonNull(output);
+        Objects.requireNonNull(extraOutput);
+        Objects.requireNonNull(callback);
         try {
             CarBugreportManagerCallbackWrapper wrapper =
                     new CarBugreportManagerCallbackWrapper(callback, getEventHandler());
@@ -188,11 +187,27 @@
         } catch (RemoteException e) {
             handleRemoteExceptionFromCarService(e);
         } finally {
+            // Safely close the FDs on this side, because binder dups them.
             IoUtils.closeQuietly(output);
             IoUtils.closeQuietly(extraOutput);
         }
     }
 
+    /**
+     * Cancels the running bugreport. It doesn't guarantee immediate cancellation and after
+     * calling this method, callbacks provided in {@link #requestBugreport} might still get fired.
+     * The next {@link startBugreport} should be called after a delay to allow the system to fully
+     * complete the cancellation.
+     */
+    @RequiresPermission(android.Manifest.permission.DUMP)
+    public void cancelBugreport() {
+        try {
+            mService.cancelBugreport();
+        } catch (RemoteException e) {
+            handleRemoteExceptionFromCarService(e);
+        }
+    }
+
     @Override
     public void onCarDisconnected() {
     }
diff --git a/car-lib/src/android/car/CarFeatures.java b/car-lib/src/android/car/CarFeatures.java
new file mode 100644
index 0000000..3fe0f1b
--- /dev/null
+++ b/car-lib/src/android/car/CarFeatures.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car;
+
+import android.annotation.NonNull;
+import android.car.annotation.OptionalFeature;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * This class declares all car features which does not have API as {@code String}.
+ *
+ * <p>Note that all {@code Car*Managers'} feature string is their service name
+ * {@code Car.*_SERVICE.}
+ * For features with APIs, subfeature {@code String} will be also defined inside the API.
+ *
+ * <p>To prevent potential conflict in feature / subfeature name, all feature name should use
+ * implementation package name space like {@code com.android.car.user.FeatureA} unless it is
+ * {@code Car.*_SERVICE}.
+ *
+ * <p>To define a subfeature, main feature should be already declared and sub feature name should
+ * have the format of "main_feature/sub_feature_name". Note that feature name cannot use '/' and
+ * should use only alphabet, digit, '_', '-' and '.'.
+ *
+ * @hide
+ */
+public final class CarFeatures {
+    /**
+     * Service to show initial user notice screen. This feature has no API and thus defined here.
+     * @hide */
+    @OptionalFeature
+    public static String FEATURE_CAR_USER_NOTICE_SERVICE =
+            "com.android.car.user.CarUserNoticeService";
+
+    // Local cache for making feature query fast.
+    // Key: feature name, value: supported or not.
+    @GuardedBy("mCachedFeatures")
+    private final ArrayMap<String, Boolean> mCachedFeatures = new ArrayMap<>();
+
+    /** @hide */
+    boolean isFeatureEnabled(@NonNull ICar service, @NonNull String featureName) {
+        synchronized (mCachedFeatures) {
+            Boolean supported = mCachedFeatures.get(featureName);
+            if (supported != null) {
+                return supported;
+            }
+        }
+        // Need to fetch from car service. This should happen only once
+        try {
+            boolean supported = service.isFeatureEnabled(featureName);
+            synchronized (mCachedFeatures) {
+                mCachedFeatures.put(featureName, Boolean.valueOf(supported));
+            }
+            return supported;
+        } catch (RemoteException e) {
+            // car service has crashed. return false.
+        }
+        return false;
+    }
+
+    /** @hide */
+    void resetCache() {
+        synchronized (mCachedFeatures) {
+            mCachedFeatures.clear();
+        }
+    }
+}
diff --git a/car-lib/src/android/car/CarInfoManager.java b/car-lib/src/android/car/CarInfoManager.java
index e9a170d..6b2ddd7 100644
--- a/car-lib/src/android/car/CarInfoManager.java
+++ b/car-lib/src/android/car/CarInfoManager.java
@@ -61,7 +61,6 @@
     public static final String BASIC_INFO_KEY_VEHICLE_ID = "android.car.vehicle-id";
     /**
      * Key for product configuration info.
-     * @FutureFeature Cannot drop due to usage in non-flag protected place.
      * @hide
      */
     @ValueTypeDef(type = String.class)
@@ -203,7 +202,7 @@
                     connectorTypes[i] = EvConnectorType.MENNEKES;
                     break;
                 case 3: // IEC_TYPE_3_AC
-                    connectorTypes[i] = 11;
+                    connectorTypes[i] = EvConnectorType.SCAME;
                     break;
                 case 4: // IEC_TYPE_4_DC
                     connectorTypes[i] = EvConnectorType.CHADEMO;
@@ -227,7 +226,7 @@
                     connectorTypes[i] = EvConnectorType.GBT;
                     break;
                 case 11: // GBT_DC
-                    connectorTypes[i] = 10;
+                    connectorTypes[i] = EvConnectorType.GBT_DC;
                     break;
                 case 101: // OTHER
                     connectorTypes[i] = EvConnectorType.OTHER;
@@ -261,7 +260,7 @@
     }
 
     /** @hide */
-    CarInfoManager(Car car, IBinder service) {
+    public CarInfoManager(Car car, IBinder service) {
         super(car);
         ICarProperty mCarPropertyService = ICarProperty.Stub.asInterface(service);
         mCarPropertyMgr = new CarPropertyManager(car, mCarPropertyService);
@@ -271,6 +270,4 @@
     public void onCarDisconnected() {
         mCarPropertyMgr.onCarDisconnected();
     }
-
-
 }
diff --git a/car-lib/src/android/car/CarOccupantZoneManager.aidl b/car-lib/src/android/car/CarOccupantZoneManager.aidl
new file mode 100644
index 0000000..a03c9af
--- /dev/null
+++ b/car-lib/src/android/car/CarOccupantZoneManager.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car;
+
+parcelable CarOccupantZoneManager.OccupantZoneInfo;
diff --git a/car-lib/src/android/car/CarOccupantZoneManager.java b/car-lib/src/android/car/CarOccupantZoneManager.java
new file mode 100644
index 0000000..7a00029
--- /dev/null
+++ b/car-lib/src/android/car/CarOccupantZoneManager.java
@@ -0,0 +1,527 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.UserIdInt;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.Display;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * API to get information on displays and users in the car.
+ */
+public class CarOccupantZoneManager extends CarManagerBase {
+
+    private static final String TAG = CarOccupantZoneManager.class.getSimpleName();
+
+    /** Display type is not known. In some system, some displays may be just public display without
+     *  any additional information and such displays will be treated as unknown.
+     */
+    public static final int DISPLAY_TYPE_UNKNOWN = 0;
+
+    /** Main display users are interacting with. UI for the user will be launched to this display by
+     *  default. {@link Display#DEFAULT_DISPLAY} will be always have this type. But there can be
+     *  multiple of this type as each passenger can have their own main display.
+     */
+    public static final int DISPLAY_TYPE_MAIN = 1;
+
+    /** Instrument cluster display. This may exist only for driver. */
+    public static final int DISPLAY_TYPE_INSTRUMENT_CLUSTER = 2;
+
+    /** Head Up Display. This may exist only for driver. */
+    public static final int DISPLAY_TYPE_HUD = 3;
+
+    /** Dedicated display for showing IME for {@link #DISPLAY_TYPE_MAIN} */
+    public static final int DISPLAY_TYPE_INPUT = 4;
+
+    /** Auxiliary display which can provide additional screen for {@link #DISPLAY_TYPE_MAIN}.
+     *  Activity running in {@link #DISPLAY_TYPE_MAIN} may use {@link android.app.Presentation} to
+     *  show additional information.
+     */
+    public static final int DISPLAY_TYPE_AUXILIARY = 5;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "DISPLAY_TYPE_", value = {
+            DISPLAY_TYPE_UNKNOWN,
+            DISPLAY_TYPE_MAIN,
+            DISPLAY_TYPE_INSTRUMENT_CLUSTER,
+            DISPLAY_TYPE_HUD,
+            DISPLAY_TYPE_INPUT,
+            DISPLAY_TYPE_AUXILIARY,
+    })
+    @Target({ElementType.TYPE_USE})
+    public @interface DisplayTypeEnum {}
+
+    /** @hide */
+    public static final int OCCUPANT_TYPE_INVALID = -1;
+
+    /** Represents driver. There can be only one driver for the system. */
+    public static final int OCCUPANT_TYPE_DRIVER = 0;
+
+    /** Represents front passengers who sits in front side of car. Most cars will have only
+     *  one passenger of this type but this can be multiple. */
+    public static final int OCCUPANT_TYPE_FRONT_PASSENGER = 1;
+
+    /** Represents passengers in rear seats. There can be multiple passengers of this type. */
+    public static final int OCCUPANT_TYPE_REAR_PASSENGER = 2;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "OCCUPANT_TYPE_", value = {
+            OCCUPANT_TYPE_DRIVER,
+            OCCUPANT_TYPE_FRONT_PASSENGER,
+            OCCUPANT_TYPE_REAR_PASSENGER,
+    })
+    @Target({ElementType.TYPE_USE})
+    public @interface OccupantTypeEnum {}
+
+    /**
+     * Represents an occupant zone in a car.
+     *
+     * <p>Each occupant does not necessarily represent single person but it is for mapping to one
+     * set of displays. For example, for display located in center rear seat, both left and right
+     * side passengers may use it but it is abstracted as a single occupant zone.</p>
+     */
+    public static final class OccupantZoneInfo implements Parcelable {
+        /** @hide */
+        public static final int INVALID_ZONE_ID = -1;
+        /**
+         * This is an unique id to distinguish each occupant zone.
+         *
+         * <p>This can be helpful to distinguish different zones when {@link #occupantType} and
+         * {@link #seat} are the same for multiple occupant / passenger zones.</p>
+         *
+         * <p>This id will remain the same for the same zone across configuration changes like
+         * user switching or display changes</p>
+         */
+        public int zoneId;
+        /** Represents type of passenger */
+        @OccupantTypeEnum
+        public final int occupantType;
+        /**
+         * Represents seat assigned for the occupant. In some system, this can have value of
+         * {@link VehicleAreaSeat#SEAT_UNKNOWN}.
+         */
+        @VehicleAreaSeat.Enum
+        public final int seat;
+
+        /** @hide */
+        public OccupantZoneInfo(int zoneId, @OccupantTypeEnum int occupantType,
+                @VehicleAreaSeat.Enum int seat) {
+            this.zoneId = zoneId;
+            this.occupantType = occupantType;
+            this.seat = seat;
+        }
+
+        /** @hide */
+        public OccupantZoneInfo(Parcel in) {
+            zoneId = in.readInt();
+            occupantType = in.readInt();
+            seat = in.readInt();
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(zoneId);
+            dest.writeInt(occupantType);
+            dest.writeInt(seat);
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (this == other) {
+                return true;
+            }
+            if (!(other instanceof OccupantZoneInfo)) {
+                return false;
+            }
+            OccupantZoneInfo that = (OccupantZoneInfo) other;
+            return zoneId == that.zoneId && occupantType == that.occupantType
+                    && seat == that.seat;
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 23;
+            hash = hash * 17 + zoneId;
+            hash = hash * 17 + occupantType;
+            hash = hash * 17 + seat;
+            return hash;
+        }
+
+        public static final Parcelable.Creator<OccupantZoneInfo> CREATOR =
+                new Parcelable.Creator<OccupantZoneInfo>() {
+            public OccupantZoneInfo createFromParcel(Parcel in) {
+                return new OccupantZoneInfo(in);
+            }
+
+            public OccupantZoneInfo[] newArray(int size) {
+                return new OccupantZoneInfo[size];
+            }
+        };
+
+        @Override
+        public String toString() {
+            StringBuilder b = new StringBuilder(64);
+            b.append("OccupantZoneInfo{zoneId=");
+            b.append(zoneId);
+            b.append(" type=");
+            b.append(occupantType);
+            b.append(" seat=");
+            b.append(Integer.toHexString(seat));
+            b.append("}");
+            return b.toString();
+        }
+    }
+
+    /** Zone config change caused by display changes. A display could have been added / removed.
+     *  Besides change in display itself. this can lead into removal / addition of passenger zones.
+     */
+    public static final int ZONE_CONFIG_CHANGE_FLAG_DISPLAY = 0x1;
+
+    /** Zone config change caused by user change. Assigned user for passenger zones have changed. */
+    public static final int ZONE_CONFIG_CHANGE_FLAG_USER = 0x2;
+
+    /** Zone config change caused by audio zone change.
+     * Assigned audio zone for passenger zones have changed.
+     **/
+    public static final int ZONE_CONFIG_CHANGE_FLAG_AUDIO = 0x4;
+
+    /** @hide */
+    @IntDef(flag = true, prefix = { "ZONE_CONFIG_CHANGE_FLAG_" }, value = {
+            ZONE_CONFIG_CHANGE_FLAG_DISPLAY,
+            ZONE_CONFIG_CHANGE_FLAG_USER,
+            ZONE_CONFIG_CHANGE_FLAG_AUDIO,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface ZoneConfigChangeFlags {}
+
+    /**
+     * Listener to monitor any Occupant Zone configuration change. The configuration change can
+     * involve some displays removed or new displays added. Also it can happen when assigned user
+     * for any zone changes.
+     */
+    public interface OccupantZoneConfigChangeListener {
+
+        /**
+         * Configuration for occupant zones has changed. Apps should re-check all
+         * occupant zone configs. This can be caused by events like user switching and
+         * display addition / removal.
+         *
+         * @param changeFlags Reason for the zone change.
+         */
+        void onOccupantZoneConfigChanged(@ZoneConfigChangeFlags int changeFlags);
+    }
+
+    private final DisplayManager mDisplayManager;
+    private final EventHandler mEventHandler;
+
+    private final ICarOccupantZone mService;
+
+    private final ICarOccupantZoneCallbackImpl mBinderCallback;
+
+    private final CopyOnWriteArrayList<OccupantZoneConfigChangeListener> mListeners =
+            new CopyOnWriteArrayList<>();
+
+    /** @hide */
+    @VisibleForTesting
+    public CarOccupantZoneManager(Car car, IBinder service) {
+        super(car);
+        mService = ICarOccupantZone.Stub.asInterface(service);
+        mBinderCallback = new ICarOccupantZoneCallbackImpl(this);
+        mDisplayManager = getContext().getSystemService(DisplayManager.class);
+        mEventHandler = new EventHandler(getEventHandler().getLooper());
+    }
+
+    /**
+     * Returns all available occupants in the system. If no occupant zone is defined in the system
+     * or none is available at the moment, it will return empty list.
+     */
+    @NonNull
+    public List<OccupantZoneInfo> getAllOccupantZones() {
+        try {
+            return mService.getAllOccupantZones();
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, Collections.emptyList());
+        }
+    }
+
+    /**
+     * Returns all displays assigned for the given occupant zone. If no display is available for
+     * the passenger, it will return empty list.
+     */
+    @NonNull
+    public List<Display> getAllDisplaysForOccupant(@NonNull OccupantZoneInfo occupantZone) {
+        assertNonNullOccupant(occupantZone);
+        try {
+            int[] displayIds = mService.getAllDisplaysForOccupantZone(occupantZone.zoneId);
+            ArrayList<Display> displays = new ArrayList<>(displayIds.length);
+            for (int i = 0; i < displayIds.length; i++) {
+                // quick sanity check while getDisplay can still handle invalid display
+                if (displayIds[i] == Display.INVALID_DISPLAY) {
+                    continue;
+                }
+                Display display = mDisplayManager.getDisplay(displayIds[i]);
+                if (display != null) { // necessary as display list could have changed.
+                    displays.add(display);
+                }
+            }
+            return displays;
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, Collections.emptyList());
+        }
+    }
+
+    /**
+     * Gets the display for the occupant for the specified display type, or returns {@code null}
+     * if no display matches the requirements.
+     *
+     * @param displayType This should be a valid display type and passing
+     *                    {@link #DISPLAY_TYPE_UNKNOWN} will always lead into {@link null} return.
+     */
+    @Nullable
+    public Display getDisplayForOccupant(@NonNull OccupantZoneInfo occupantZone,
+            @DisplayTypeEnum int displayType) {
+        assertNonNullOccupant(occupantZone);
+        try {
+            int displayId = mService.getDisplayForOccupant(occupantZone.zoneId, displayType);
+            // quick sanity check while getDisplay can still handle invalid display
+            if (displayId == Display.INVALID_DISPLAY) {
+                return null;
+            }
+            return mDisplayManager.getDisplay(displayId);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, null);
+        }
+    }
+
+    /**
+     * Gets the audio zone id for the occupant, or returns
+     * {@code CarAudioManager.INVALID_AUDIO_ZONE} if no audio zone matches the requirements.
+     * throws InvalidArgumentException if occupantZone does not exist.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS)
+    public int getAudioZoneIdForOccupant(@NonNull OccupantZoneInfo occupantZone) {
+        assertNonNullOccupant(occupantZone);
+        try {
+            return mService.getAudioZoneIdForOccupant(occupantZone.zoneId);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, null);
+        }
+    }
+
+    /**
+     * Gets occupant for the audio zone id, or returns {@code null}
+     * if no audio zone matches the requirements.
+     *
+     * @hide
+     */
+    @Nullable
+    @SystemApi
+    @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS)
+    public OccupantZoneInfo getOccupantForAudioZoneId(int audioZoneId) {
+        try {
+            return mService.getOccupantForAudioZoneId(audioZoneId);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, null);
+        }
+    }
+
+    /**
+     * Returns assigned display type for the display. It will return {@link #DISPLAY_TYPE_UNKNOWN}
+     * if type is not specified or if display is no longer available.
+     */
+    @DisplayTypeEnum
+    public int getDisplayType(@NonNull Display display) {
+        assertNonNullDisplay(display);
+        try {
+            return mService.getDisplayType(display.getDisplayId());
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, DISPLAY_TYPE_UNKNOWN);
+        }
+    }
+
+    /**
+     * Returns android user id assigned for the given zone. It will return
+     * {@link UserHandle#USER_NULL} if user is not assigned or if zone is not available.
+     */
+    @UserIdInt
+    public int getUserForOccupant(@NonNull OccupantZoneInfo occupantZone) {
+        assertNonNullOccupant(occupantZone);
+        try {
+            return mService.getUserForOccupant(occupantZone.zoneId);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, UserHandle.USER_NULL);
+        }
+    }
+
+    /**
+     * Assigns the given profile {@code userId} to the {@code occupantZone}. Returns true when the
+     * request succeeds.
+     *
+     * <p>Note that only non-driver zone can be assigned with this call. Calling this for driver
+     * zone will lead into {@code IllegalArgumentException}.
+     *
+     * @param occupantZone Zone to assign user.
+     * @param userId profile user id to assign. Passing {@link UserHandle#USER_NULL} leads into
+     *               removing the current user assignment.
+     * @return true if the request succeeds or if the user is already assigned to the zone.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public boolean assignProfileUserToOccupantZone(@NonNull OccupantZoneInfo occupantZone,
+            @UserIdInt int userId) {
+        assertNonNullOccupant(occupantZone);
+        try {
+            return mService.assignProfileUserToOccupantZone(occupantZone.zoneId, userId);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, false);
+        }
+    }
+
+    private void assertNonNullOccupant(OccupantZoneInfo occupantZone) {
+        if (occupantZone == null) {
+            throw new IllegalArgumentException("null OccupantZoneInfo");
+        }
+    }
+
+    private void assertNonNullDisplay(Display display) {
+        if (display == null) {
+            throw new IllegalArgumentException("null Display");
+        }
+    }
+
+    /**
+     * Registers the listener for occupant zone config change. Registering multiple listeners are
+     * allowed.
+     */
+    public void registerOccupantZoneConfigChangeListener(
+            @NonNull OccupantZoneConfigChangeListener listener) {
+        if (mListeners.addIfAbsent(listener)) {
+            if (mListeners.size() == 1) {
+                try {
+                    mService.registerCallback(mBinderCallback);
+                } catch (RemoteException e) {
+                    handleRemoteExceptionFromCarService(e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Unregisters the listener. Listeners not registered before will be ignored.
+     */
+    public void unregisterOccupantZoneConfigChangeListener(
+            @NonNull OccupantZoneConfigChangeListener listener) {
+        if (mListeners.remove(listener)) {
+            if (mListeners.size() == 0) {
+                try {
+                    mService.unregisterCallback(mBinderCallback);
+                } catch (RemoteException ignored) {
+                    // ignore for unregistering
+                }
+            }
+        }
+    }
+
+    private void handleOnOccupantZoneConfigChanged(int flags) {
+        for (OccupantZoneConfigChangeListener listener : mListeners) {
+            listener.onOccupantZoneConfigChanged(flags);
+        }
+    }
+
+    private final class EventHandler extends Handler {
+        private static final int MSG_ZONE_CHANGE = 1;
+
+        private EventHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_ZONE_CHANGE:
+                    handleOnOccupantZoneConfigChanged(msg.arg1);
+                    break;
+                default:
+                    Log.e(TAG, "Unknown msg not handdled:" + msg.what);
+                    break;
+            }
+        }
+
+        private void dispatchOnOccupantZoneConfigChanged(int flags) {
+            sendMessage(obtainMessage(MSG_ZONE_CHANGE, flags, 0));
+        }
+    }
+
+    private static class ICarOccupantZoneCallbackImpl extends ICarOccupantZoneCallback.Stub {
+        private final WeakReference<CarOccupantZoneManager> mManager;
+
+        private ICarOccupantZoneCallbackImpl(CarOccupantZoneManager manager) {
+            mManager = new WeakReference<>(manager);
+        }
+
+        @Override
+        public void onOccupantZoneConfigChanged(int flags) {
+            CarOccupantZoneManager manager = mManager.get();
+            if (manager != null) {
+                manager.mEventHandler.dispatchOnOccupantZoneConfigChanged(flags);
+            }
+        }
+    }
+
+    /** @hide */
+    @Override
+    public void onCarDisconnected() {
+        // nothing to do
+    }
+}
diff --git a/car-lib/src/android/car/CarProjectionManager.java b/car-lib/src/android/car/CarProjectionManager.java
index bc4107f..66590a5 100644
--- a/car-lib/src/android/car/CarProjectionManager.java
+++ b/car-lib/src/android/car/CarProjectionManager.java
@@ -27,6 +27,7 @@
 import android.car.projection.ProjectionStatus;
 import android.car.projection.ProjectionStatus.ProjectionState;
 import android.content.Intent;
+import android.net.wifi.SoftApConfiguration;
 import android.net.wifi.WifiConfiguration;
 import android.os.Binder;
 import android.os.Bundle;
@@ -56,6 +57,7 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.Executor;
 
@@ -264,7 +266,7 @@
     @RequiresPermission(Car.PERMISSION_CAR_PROJECTION)
     public void registerProjectionListener(@NonNull CarProjectionListener listener,
             int voiceSearchFilter) {
-        Preconditions.checkNotNull(listener, "listener cannot be null");
+        Objects.requireNonNull(listener, "listener cannot be null");
         synchronized (mLock) {
             if (mListener == null || mVoiceSearchFilter != voiceSearchFilter) {
                 addKeyEventHandler(
@@ -281,7 +283,7 @@
      * @hide
      */
     public void unregsiterProjectionListener() {
-       unregisterProjectionListener();
+        unregisterProjectionListener();
     }
 
     /**
@@ -462,7 +464,7 @@
      */
     @RequiresPermission(Car.PERMISSION_CAR_PROJECTION)
     public void registerProjectionRunner(@NonNull Intent serviceIntent) {
-        Preconditions.checkNotNull("serviceIntent cannot be null");
+        Objects.requireNonNull("serviceIntent cannot be null");
         synchronized (mLock) {
             try {
                 mService.registerProjectionRunner(serviceIntent);
@@ -479,7 +481,7 @@
      */
     @RequiresPermission(Car.PERMISSION_CAR_PROJECTION)
     public void unregisterProjectionRunner(@NonNull Intent serviceIntent) {
-        Preconditions.checkNotNull("serviceIntent cannot be null");
+        Objects.requireNonNull("serviceIntent cannot be null");
         synchronized (mLock) {
             try {
                 mService.unregisterProjectionRunner(serviceIntent);
@@ -506,7 +508,7 @@
      */
     @RequiresPermission(Car.PERMISSION_CAR_PROJECTION)
     public void startProjectionAccessPoint(@NonNull ProjectionAccessPointCallback callback) {
-        Preconditions.checkNotNull(callback, "callback cannot be null");
+        Objects.requireNonNull(callback, "callback cannot be null");
         synchronized (mLock) {
             Looper looper = getEventHandler().getLooper();
             ProjectionAccessPointCallbackProxy proxy =
@@ -572,7 +574,7 @@
     @RequiresPermission(Car.PERMISSION_CAR_PROJECTION)
     public boolean requestBluetoothProfileInhibit(
             @NonNull BluetoothDevice device, int profile) {
-        Preconditions.checkNotNull(device, "device cannot be null");
+        Objects.requireNonNull(device, "device cannot be null");
         try {
             return mService.requestBluetoothProfileInhibit(device, profile, mToken);
         } catch (RemoteException e) {
@@ -590,7 +592,7 @@
      */
     @RequiresPermission(Car.PERMISSION_CAR_PROJECTION)
     public boolean releaseBluetoothProfileInhibit(@NonNull BluetoothDevice device, int profile) {
-        Preconditions.checkNotNull(device, "device cannot be null");
+        Objects.requireNonNull(device, "device cannot be null");
         try {
             return mService.releaseBluetoothProfileInhibit(device, profile, mToken);
         } catch (RemoteException e) {
@@ -608,7 +610,7 @@
      */
     @RequiresPermission(Car.PERMISSION_CAR_PROJECTION)
     public void updateProjectionStatus(@NonNull ProjectionStatus status) {
-        Preconditions.checkNotNull(status, "status cannot be null");
+        Objects.requireNonNull(status, "status cannot be null");
         try {
             mService.updateProjectionStatus(status, mToken);
         } catch (RemoteException e) {
@@ -626,7 +628,7 @@
      */
     @RequiresPermission(Car.PERMISSION_CAR_PROJECTION_STATUS)
     public void registerProjectionStatusListener(@NonNull ProjectionStatusListener listener) {
-        Preconditions.checkNotNull(listener, "listener cannot be null");
+        Objects.requireNonNull(listener, "listener cannot be null");
         synchronized (mLock) {
             mProjectionStatusListeners.add(listener);
 
@@ -657,7 +659,7 @@
      */
     @RequiresPermission(Car.PERMISSION_CAR_PROJECTION_STATUS)
     public void unregisterProjectionStatusListener(@NonNull ProjectionStatusListener listener) {
-        Preconditions.checkNotNull(listener, "listener cannot be null");
+        Objects.requireNonNull(listener, "listener cannot be null");
         synchronized (mLock) {
             if (!mProjectionStatusListeners.remove(listener)
                     || !mProjectionStatusListeners.isEmpty()) {
@@ -709,8 +711,33 @@
         public static final int ERROR_INCOMPATIBLE_MODE = 3;
         public static final int ERROR_TETHERING_DISALLOWED = 4;
 
-        /** Called when access point started successfully. */
-        public void onStarted(WifiConfiguration wifiConfiguration) {}
+        /**
+         * Called when access point started successfully.
+         * <p>
+         * Note that AP detail may contain configuration which is cannot be represented
+         * by the legacy WifiConfiguration, in such cases a null will be returned.
+         * For example:
+         * <li> SoftAp band in {@link WifiConfiguration.apBand} only supports
+         * 2GHz, 5GHz, 2GHz+5GHz bands, so conversion is limited to these bands. </li>
+         * <li> SoftAp security type in {@link WifiConfiguration.KeyMgmt} only supports
+         * NONE, WPA2_PSK, so conversion is limited to these security type.</li>
+         *
+         * @param wifiConfiguration  the {@link WifiConfiguration} of the current hotspot.
+         * @deprecated This callback is deprecated. Use {@link #onStarted(SoftApConfiguration))}
+         * instead.
+         */
+        @Deprecated
+        public void onStarted(@Nullable WifiConfiguration wifiConfiguration) {}
+
+        /**
+         * Called when access point started successfully.
+         *
+         * @param softApConfiguration the {@link SoftApConfiguration} of the current hotspot.
+         */
+        public void onStarted(@NonNull SoftApConfiguration softApConfiguration) {
+            onStarted(softApConfiguration.toWifiConfiguration());
+        }
+
         /** Called when access point is stopped. No events will be sent after that. */
         public void onStopped() {}
         /** Called when access point failed to start. No events will be sent after that. */
@@ -745,7 +772,7 @@
 
                     switch (msg.what) {
                         case PROJECTION_AP_STARTED:
-                            WifiConfiguration config = (WifiConfiguration) msg.obj;
+                            SoftApConfiguration config = (SoftApConfiguration) msg.obj;
                             if (config == null) {
                                 Log.e(TAG, LOG_PREFIX + "config cannot be null.");
                                 callback.onFailed(ProjectionAccessPointCallback.ERROR_GENERIC);
diff --git a/car-lib/src/android/car/EvConnectorType.java b/car-lib/src/android/car/EvConnectorType.java
index 81b9e1f..a3f2c3a 100644
--- a/car-lib/src/android/car/EvConnectorType.java
+++ b/car-lib/src/android/car/EvConnectorType.java
@@ -26,9 +26,6 @@
 public final class EvConnectorType {
     /**
      * List of EV Connector Types used in {@link CarInfoManager#getEvConnectorTypes()}.
-     * Beside connector types are listed here, there are two more EvConnectorTypes.
-     * The value of GBT_DC faster charging standard is 10.
-     * The value of IEC_TYPE_3_AC standard is 11.
      * If a vehicle does not know the type, it will return UNKNOWN.
      * The vehicle returns OTHER when no other types apply.
      * <b>Note:</b> The connector types in Java API have different values than the ones in VHAL.
@@ -52,15 +49,9 @@
     public static final int TESLA_SUPERCHARGER = 8;
     /** GBT_AC Fast Charging Standard */
     public static final int GBT = 9;
-    /**
-     * Map to GBT_DC in VHAL
-     * @hide
-     */
+    /** GBT_DC Fast Charging Standard */
     public static final int GBT_DC = 10;
-    /**
-     * Map to IEC_TYPE_3_AC in VHAL
-     * @hide
-     */
+    /** IEC_TYPE_3_AC connector */
     public static final int SCAME = 11;
 
     /**
@@ -80,6 +71,8 @@
         TESLA_HPWC,
         TESLA_SUPERCHARGER,
         GBT,
+        GBT_DC,
+        SCAME,
         OTHER
     })
     @Retention(RetentionPolicy.SOURCE)
diff --git a/car-lib/src/android/car/ICar.aidl b/car-lib/src/android/car/ICar.aidl
index 811034f..5f548a6 100644
--- a/car-lib/src/android/car/ICar.aidl
+++ b/car-lib/src/android/car/ICar.aidl
@@ -19,34 +19,66 @@
 /** @hide */
 interface ICar {
     // All oneway methods are called from system server and should be placed in top positions.
-    // Do not change the order of oneway methods as system server make binder call based on this
-    // order.
+    // Do not change the number of oneway methods as system server make binder calls based on these
+    // numbers - if you change them, you need to change the constants on CarServiceHelperService.
 
     /**
      * IBinder is ICarServiceHelper but passed as IBinder due to aidl hidden.
-     *
-     * This should be the 1st method. Do not change the order.
      */
     oneway void setCarServiceHelper(in IBinder helper) = 0;
-    /**
-     * Notify lock / unlock of user id to car service.
-     * unlocked: 1 if unlocked 0 otherwise.
-     *
-     * This should be the 2nd method. Do not change the order.
-     */
-    oneway void setUserLockStatus(in int userHandle, in int unlocked) = 1;
 
     /**
-     * Notify of user switching.  This is called only for foreground users when the user is starting
-     * to boot.
+     * Notify of user lifecycle events.
      *
-     * @param userHandle -  user handle of new user.
-     *
-     * This should be the 3rd method. Do not change the order.
+     * @param eventType - type as defined by CarUserManager.UserLifecycleEventType
+     * @param timestampMs - when the event happened
+     * @param fromUserId - user id of previous user when type is SWITCHING (or UserHandle.USER_NULL)
+     * @param toUserId - user id of new user.
      */
-    oneway void onSwitchUser(in int userHandle) = 2;
+    oneway void onUserLifecycleEvent(int eventType, long timestampMs, int fromUserId,
+            int toUserId) = 1;
 
-    IBinder getCarService(in String serviceName) = 3;
-    int getCarConnectionType() = 4;
+    /**
+     * Notify when first user was unlocked, for metrics (and lifecycle) purposes.
+     *
+     * @param userId - id of first non-system user locked
+     * @param timestampMs - when the user was unlocked
+     * @param duration - how long it took to unlock (from SystemServer start)
+     * @param halResponseTime - see CarServiceHelperService.mHalResponseTime
+     */
+    oneway void onFirstUserUnlocked(int userId, long timestampMs, long duration,
+            int halResponseTime) = 2;
 
+    /**
+     * Calls User HAL to get the initial user info.
+     *
+     * @param requestType - as defined by InitialUserInfoRequestType.
+     * @param timeoutMs - how long to wait for HAL's response.
+     * @param receiver - a com.android.internal.os.IResultReceiver callback.
+     */
+    oneway void getInitialUserInfo(int requestType, int timeoutMs, in IBinder receiver) = 3;
+
+    /**
+     * Sets the initial user after boot.
+     *
+     * @param userId - the id of the initial user
+     */
+    // TODO(b/150413515): should pass UserInfo instead, but for some reason passing the whole
+    // UserInfo through a raw binder transaction on CarServiceHelper is not working.
+    oneway void setInitialUser(int userId) = 4;
+
+    // Methods below start on 11 to make it easier to add more oneway methods above
+    IBinder getCarService(in String serviceName) = 11;
+    int getCarConnectionType() = 12;
+    boolean isFeatureEnabled(in String featureName) = 13;
+    int enableFeature(in String featureName) = 14;
+    int disableFeature(in String featureName) = 15;
+    List<String> getAllEnabledFeatures() = 16;
+    List<String> getAllPendingDisabledFeatures() = 17;
+    List<String> getAllPendingEnabledFeatures() = 18;
+    /**
+     * Get class name for experimental feature. Class should have constructor taking (Car, IBinder)
+     * and should inherit CarManagerBase.
+     */
+    String getCarManagerClassForFeature(in String featureName) = 19;
 }
diff --git a/car-lib/src/android/car/ICarBugreportService.aidl b/car-lib/src/android/car/ICarBugreportService.aidl
index 2673c80..54ae4eb 100644
--- a/car-lib/src/android/car/ICarBugreportService.aidl
+++ b/car-lib/src/android/car/ICarBugreportService.aidl
@@ -23,7 +23,7 @@
  *
  * @hide
  */
- interface ICarBugreportService {
+interface ICarBugreportService {
 
     /**
      * Starts bugreport service to capture a zipped bugreport. The caller needs to provide
@@ -34,4 +34,9 @@
      */
     void requestBugreport(in ParcelFileDescriptor output,
             in ParcelFileDescriptor extraOutput, ICarBugreportCallback callback) = 1;
- }
+
+    /**
+     * Cancels the running bugreport.
+     */
+    void cancelBugreport() = 2;
+}
diff --git a/car-lib/src/android/car/ICarOccupantZone.aidl b/car-lib/src/android/car/ICarOccupantZone.aidl
new file mode 100644
index 0000000..463517e
--- /dev/null
+++ b/car-lib/src/android/car/ICarOccupantZone.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car;
+
+import android.car.CarOccupantZoneManager;
+import android.car.ICarOccupantZoneCallback;
+import android.view.DisplayInfo;
+
+/** @hide */
+interface ICarOccupantZone {
+    List<CarOccupantZoneManager.OccupantZoneInfo> getAllOccupantZones();
+    int getAudioZoneIdForOccupant(in int occupantZoneId);
+    int[] getAllDisplaysForOccupantZone(in int occupantZoneId);
+    int getDisplayForOccupant(in int occupantZoneId, in int displayType);
+    CarOccupantZoneManager.OccupantZoneInfo getOccupantForAudioZoneId(in int audioZoneId);
+    int getDisplayType(in int displayId);
+    int getUserForOccupant(in int occupantZoneId);
+    int getOccupantZoneIdForUserId(in int userId);
+    void registerCallback(in ICarOccupantZoneCallback callback);
+    void unregisterCallback(in ICarOccupantZoneCallback callback);
+    boolean assignProfileUserToOccupantZone(in int occupantZoneId, in int userId);
+}
diff --git a/car-lib/src/android/car/ICarOccupantZoneCallback.aidl b/car-lib/src/android/car/ICarOccupantZoneCallback.aidl
new file mode 100644
index 0000000..c87c48b
--- /dev/null
+++ b/car-lib/src/android/car/ICarOccupantZoneCallback.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car;
+
+/** @hide */
+oneway interface ICarOccupantZoneCallback {
+    void onOccupantZoneConfigChanged(in int flags);
+}
\ No newline at end of file
diff --git a/car-lib/src/android/car/ICarUserService.aidl b/car-lib/src/android/car/ICarUserService.aidl
index 82eab72..5b58b54 100644
--- a/car-lib/src/android/car/ICarUserService.aidl
+++ b/car-lib/src/android/car/ICarUserService.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,11 +15,34 @@
  */
 
 package android.car;
-import android.car.ICarBluetoothUserService;
-import android.car.ILocationManagerProxy;
+
+import android.content.pm.UserInfo;
+import android.car.user.UserCreationResult;
+import android.car.user.UserRemovalResult;
+import android.car.user.UserIdentificationAssociationResponse;
+import android.car.user.UserSwitchResult;
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.os.IResultReceiver;
 
 /** @hide */
 interface ICarUserService {
-    ICarBluetoothUserService getBluetoothUserService();
-    ILocationManagerProxy getLocationManagerProxy();
+    AndroidFuture<UserCreationResult> createDriver(@nullable String name, boolean admin);
+    UserInfo createPassenger(@nullable String name, int driverId);
+    void switchDriver(int driverId, in AndroidFuture<UserSwitchResult> receiver);
+    void switchUser(int tagerUserId, int timeoutMs, in AndroidFuture<UserSwitchResult> receiver);
+    void setUserSwitchUiCallback(in IResultReceiver callback);
+    void createUser(@nullable String name, String userType, int flags, int timeoutMs,
+      in AndroidFuture<UserCreationResult> receiver);
+    UserRemovalResult removeUser(int userId);
+    List<UserInfo> getAllDrivers();
+    List<UserInfo> getPassengers(int driverId);
+    boolean startPassenger(int passengerId, int zoneId);
+    boolean stopPassenger(int passengerId);
+    void setLifecycleListenerForUid(in IResultReceiver listener);
+    void resetLifecycleListenerForUid();
+    void getInitialUserInfo(int requestType, int timeoutMs, in IResultReceiver receiver);
+    UserIdentificationAssociationResponse getUserIdentificationAssociation(in int[] types);
+    void setUserIdentificationAssociation(int timeoutMs, in int[] types, in int[] values,
+      in AndroidFuture<UserIdentificationAssociationResponse> result);
+    boolean isUserHalUserAssociationSupported();
 }
diff --git a/car-lib/src/android/car/IExperimentalCar.aidl b/car-lib/src/android/car/IExperimentalCar.aidl
new file mode 100644
index 0000000..18cbb0d
--- /dev/null
+++ b/car-lib/src/android/car/IExperimentalCar.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car;
+
+import android.car.IExperimentalCarHelper;
+
+/** @hide */
+oneway interface IExperimentalCar {
+    /**
+     * Initialize the experimental car service.
+     * @param helper After init, experimental car service should return binder, class names for
+     *               enabled features with all features available through helper.onInitComplete().
+     * @param enabledFeatures Currently enabled features. If this feature is not available any more,
+     *                        helper.onInitComplete should drop it from started features.
+     */
+    void init(in IExperimentalCarHelper helper, in List<String> enabledFeatures);
+}
diff --git a/car-lib/src/android/car/IExperimentalCarHelper.aidl b/car-lib/src/android/car/IExperimentalCarHelper.aidl
new file mode 100644
index 0000000..4275c51
--- /dev/null
+++ b/car-lib/src/android/car/IExperimentalCarHelper.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car;
+
+/** @hide */
+interface IExperimentalCarHelper {
+    /**
+     * Notify the completion of init to car service.
+     * @param allAvailableFeatures All features available in the package.
+     * @param startedFeatures Started features. This is a subset of enabledFeatures passed through
+     *        IExperimentalCar.init(..). Only available features should be started.
+     * @param classNames Car*Manager class names for all started experimental features. Class name
+     *        can be null if the feature does not have Car*Manager (=internal feature).
+     * @param binders Car*Manager binders for all started experimental features. Binder can be null
+     *        if the feature does not have Car*Manager.
+     */
+    void onInitComplete(in List<String> allAvailableFeatures, in List<String> startedFeatures,
+            in List<String> classNames, in List<IBinder> binders);
+}
diff --git a/car-lib/src/android/car/IPerUserCarService.aidl b/car-lib/src/android/car/IPerUserCarService.aidl
new file mode 100644
index 0000000..fa66173
--- /dev/null
+++ b/car-lib/src/android/car/IPerUserCarService.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car;
+
+import android.car.ICarBluetoothUserService;
+import android.car.ILocationManagerProxy;
+
+/** @hide */
+interface IPerUserCarService {
+    ICarBluetoothUserService getBluetoothUserService();
+    ILocationManagerProxy getLocationManagerProxy();
+}
diff --git a/car-lib/src/android/car/VehicleAreaSeat.java b/car-lib/src/android/car/VehicleAreaSeat.java
index e1c6720..611827d 100644
--- a/car-lib/src/android/car/VehicleAreaSeat.java
+++ b/car-lib/src/android/car/VehicleAreaSeat.java
@@ -16,16 +16,26 @@
 package android.car;
 
 import android.annotation.IntDef;
-import android.car.hardware.CarPropertyValue;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * VehicleAreaSeat is an abstraction for a seat in a car. Some car APIs like
- * {@link CarPropertyValue} may provide control per seat and
- * values defined here should be used to distinguish different seats.
+ * Object used to indicate the area value for car properties which have area type
+ * {@link VehicleAreaType#VEHICLE_AREA_TYPE_SEAT}.
+ * <p>
+ * The constants defined by {@link VehicleAreaSeat} indicate the position for area type
+ * {@link VehicleAreaType#VEHICLE_AREA_TYPE_SEAT}. A property can have a single or a combination of
+ * positions. Developers can query the position using
+ * {@link android.car.hardware.property.CarPropertyManager#getAreaId(int, int)}.
+ * </p><p>
+ * Refer to {@link android.car.hardware.CarPropertyConfig#getAreaIds()} for more information about
+ * areaId.
+ * </p>
  */
+
+// This class is only designed to provide constants for VehicleAreaSeat. The constants should
+// be same as VehicleAreaSeat in /hardware/interfaces/automotive/vehicle/2.0/types.hal.
 public final class VehicleAreaSeat {
     /** List of vehicle's seats. */
     public static final int SEAT_UNKNOWN = 0;
@@ -66,4 +76,31 @@
     public @interface Enum {}
     private VehicleAreaSeat() {}
 
+    /** @hide */
+    public static final int SIDE_LEFT = -1;
+    /** @hide */
+    public static final int SIDE_CENTER = 0;
+    /** @hide */
+    public static final int SIDE_RIGHT = 1;
+    /**
+     * Convert row number and side into {@link Enum}.
+     *
+     * @param rowNumber should be 1, 2 or 3
+     * @param side {@link #SIDE_LEFT}. {@link #SIDE_CENTER}, {@link #SIDE_RIGHT}.
+     *
+     * @hide */
+    @Enum
+    public static int fromRowAndSide(int rowNumber, int side) {
+        if (rowNumber < 1 || rowNumber > 3) {
+            return SEAT_UNKNOWN;
+        }
+        if (side < -1 || side > 1) {
+            return SEAT_UNKNOWN;
+        }
+        int seat = 0x1;
+        seat = seat << ((rowNumber - 1) * 4);
+        seat = seat << (side + 1);
+        return seat;
+    }
+
 }
diff --git a/car-lib/src/android/car/VehicleAreaType.java b/car-lib/src/android/car/VehicleAreaType.java
index 826ffe3..5cd5c7a 100644
--- a/car-lib/src/android/car/VehicleAreaType.java
+++ b/car-lib/src/android/car/VehicleAreaType.java
@@ -16,15 +16,24 @@
 package android.car;
 
 import android.annotation.IntDef;
+import android.car.hardware.CarPropertyConfig;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * Represents vehicle area such as window, door, seat, etc.
- * See also {@link VehicleAreaDoor}, {@link VehicleAreaSeat},
- * {@link VehicleAreaWindow},
+ * Object used to indicate area types for car properties.
+ * <p>
+ * The constants defined by {@link VehicleAreaType} indicate the area types for properties.  A
+ * property only has one area type. Developers can query the area type using
+ * {@link CarPropertyConfig#getPropertyType()}.
+ * </p><p>
+ * Refer to {@link VehicleAreaSeat} and {@link VehicleAreaWheel} for more information about areaId.
+ * </p>
  */
+
+// This class is only designed to provide constants for VehicleAreaType. The constants should
+// exactly be same as VehicleAreaType in /hardware/interfaces/automotive/vehicle/2.0/types.hal.
 public final class VehicleAreaType {
     /** Used for global properties */
     public static final int VEHICLE_AREA_TYPE_GLOBAL = 0;
diff --git a/car-lib/src/android/car/VehicleAreaWheel.java b/car-lib/src/android/car/VehicleAreaWheel.java
index 9e66ed5..d58381d 100644
--- a/car-lib/src/android/car/VehicleAreaWheel.java
+++ b/car-lib/src/android/car/VehicleAreaWheel.java
@@ -15,21 +15,50 @@
  */
 package android.car;
 
-import android.annotation.SystemApi;
+import android.annotation.IntDef;
+import android.car.hardware.CarPropertyConfig;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 /**
- * VehicleAreaWheel is an abstraction for the wheels on a car.  It exists to isolate the java APIs
- * from the VHAL definitions.
- * @hide
+ * Object used to indicate area value for car properties which have area type
+ * {@link VehicleAreaType#VEHICLE_AREA_TYPE_WHEEL}.
+ * <p>
+ * The constants defined by {@link VehicleAreaWheel} indicate the position for area type
+ * {@link VehicleAreaType#VEHICLE_AREA_TYPE_WHEEL}. A property can have a single or a combination of
+ * positions. Developers can query the position using
+ * {@link android.car.hardware.property.CarPropertyManager#getAreaId(int, int)}.
+ * </p><p>
+ * Refer to {@link CarPropertyConfig#getAreaIds()} for more information about areaId.
+ * </p>
  */
-@SystemApi
+
+// This class is only designed to provide constants for VehicleAreaWheel. The constants should
+// exactly be same as VehicleAreaWheel in /hardware/interfaces/automotive/vehicle/2.0/types.hal.
 public final class VehicleAreaWheel {
+    /** Unknown wheel*/
     public static final int WHEEL_UNKNOWN = 0x00;
+    /** Constant for left front wheel.*/
     public static final int WHEEL_LEFT_FRONT = 0x01;
+    /** Constant for right front wheel.*/
     public static final int WHEEL_RIGHT_FRONT = 0x02;
+    /** Constant for left rear wheel.*/
     public static final int WHEEL_LEFT_REAR = 0x04;
+    /** Constant for right rear wheel.*/
     public static final int WHEEL_RIGHT_REAR = 0x08;
 
+    /** @hide */
+    @IntDef(prefix = {"WHEEL_"}, value = {
+            WHEEL_UNKNOWN,
+            WHEEL_LEFT_FRONT,
+            WHEEL_RIGHT_FRONT,
+            WHEEL_LEFT_REAR,
+            WHEEL_RIGHT_REAR
+    })
+    @Retention(RetentionPolicy.SOURCE)
+
+    public  @interface Enum {}
     private VehicleAreaWheel() {}
 }
 
diff --git a/car-lib/src/android/car/VehicleGear.java b/car-lib/src/android/car/VehicleGear.java
new file mode 100644
index 0000000..8634aac
--- /dev/null
+++ b/car-lib/src/android/car/VehicleGear.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * List of enums for vehicle gears.
+ */
+public final class VehicleGear {
+
+    /**
+     *  GEAR_* represents meaning of value for {@link VehiclePropertyIds#GEAR_SELECTION} and
+     *  {@link VehiclePropertyIds#CURRENT_GEAR}. {@link VehicleGear#GEAR_PARK} and
+     *  {@link VehicleGear#GEAR_DRIVE} only apply to the {@link VehiclePropertyIds#GEAR_SELECTION}
+     *  property for a vehicle with an automatic transmission.
+     */
+    public static final int GEAR_UNKNOWN    = 0x0000;
+    public static final int GEAR_NEUTRAL    = 0x0001;
+    public static final int GEAR_REVERSE    = 0x0002;
+    public static final int GEAR_PARK       = 0x0004;
+    public static final int GEAR_DRIVE      = 0x0008;
+    public static final int GEAR_FIRST      = 0x0010;
+    public static final int GEAR_SECOND     = 0x0020;
+    public static final int GEAR_THIRD      = 0x0040;
+    public static final int GEAR_FOURTH     = 0x0080;
+    public static final int GEAR_FIFTH      = 0x0100;
+    public static final int GEAR_SIXTH      = 0x0200;
+    public static final int GEAR_SEVENTH    = 0x0400;
+    public static final int GEAR_EIGHTH     = 0x0800;
+    public static final int GEAR_NINTH      = 0x1000;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+        GEAR_UNKNOWN,
+        GEAR_NEUTRAL,
+        GEAR_REVERSE,
+        GEAR_PARK,
+        GEAR_DRIVE,
+        GEAR_FIRST,
+        GEAR_SECOND,
+        GEAR_THIRD,
+        GEAR_FOURTH,
+        GEAR_FIFTH,
+        GEAR_SIXTH,
+        GEAR_SEVENTH,
+        GEAR_EIGHTH,
+        GEAR_NINTH,
+    })
+    public @interface Enum {}
+    private VehicleGear() {}
+
+    /**
+     * @param o Integer
+     * @return String
+     */
+    public static  String toString(int o) {
+        if (o == GEAR_UNKNOWN) {
+            return "GEAR_UNKNOWN";
+        }
+        if (o == GEAR_NEUTRAL) {
+            return "GEAR_NEUTRAL";
+        }
+        if (o == GEAR_REVERSE) {
+            return "GEAR_REVERSE";
+        }
+        if (o == GEAR_PARK) {
+            return "GEAR_PARK";
+        }
+        if (o == GEAR_DRIVE) {
+            return "GEAR_DRIVE";
+        }
+        if (o == GEAR_FIRST) {
+            return "GEAR_FIRST";
+        }
+        if (o == GEAR_SECOND) {
+            return "GEAR_SECOND";
+        }
+        if (o == GEAR_THIRD) {
+            return "GEAR_THIRD";
+        }
+        if (o == GEAR_FOURTH) {
+            return "GEAR_FOURTH";
+        }
+        if (o == GEAR_FIFTH) {
+            return "GEAR_FIFTH";
+        }
+        if (o == GEAR_SIXTH) {
+            return "GEAR_SIXTH";
+        }
+        if (o == GEAR_SEVENTH) {
+            return "GEAR_SEVENTH";
+        }
+        if (o == GEAR_EIGHTH) {
+            return "GEAR_EIGHTH";
+        }
+        if (o == GEAR_NINTH) {
+            return "GEAR_NINTH";
+        }
+        return "0x" + Integer.toHexString(o);
+    }
+}
diff --git a/car-lib/src/android/car/VehicleOilLevel.java b/car-lib/src/android/car/VehicleOilLevel.java
index 5a21a2d..75fd1da 100644
--- a/car-lib/src/android/car/VehicleOilLevel.java
+++ b/car-lib/src/android/car/VehicleOilLevel.java
@@ -16,7 +16,7 @@
 package android.car;
 
 import android.annotation.IntDef;
-import android.annotation.SystemApi;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
diff --git a/car-lib/src/android/car/VehiclePropertyIds.java b/car-lib/src/android/car/VehiclePropertyIds.java
index ada2b2d..a9945da 100644
--- a/car-lib/src/android/car/VehiclePropertyIds.java
+++ b/car-lib/src/android/car/VehiclePropertyIds.java
@@ -16,6 +16,8 @@
 
 package android.car;
 
+import android.annotation.RequiresPermission;
+
 /**
  * Copy from android.hardware.automotive.vehicle-V2.0-java_gen_java/gen/android/hardware/automotive
  * /vehicle/V2_0. Need to update this file when vehicle propertyId is changed in VHAL.
@@ -30,67 +32,112 @@
      * VIN of vehicle
      * Requires permission: {@link Car#PERMISSION_IDENTIFICATION}.
      */
+    @RequiresPermission(Car.PERMISSION_IDENTIFICATION)
     public static final int INFO_VIN = 286261504;
     /**
      * Manufacturer of vehicle
      * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_MAKE = 286261505;
     /**
      * Model of vehicle
      * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_MODEL = 286261506;
     /**
      * Model year of vehicle.
      * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_MODEL_YEAR = 289407235;
     /**
      * Fuel capacity of the vehicle in milliliters
      * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_FUEL_CAPACITY = 291504388;
     /**
      * List of fuels the vehicle may use
      * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_FUEL_TYPE = 289472773;
     /**
      * Battery capacity of the vehicle, if EV or hybrid.  This is the nominal
      * battery capacity when the vehicle is new.
      * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_EV_BATTERY_CAPACITY = 291504390;
     /**
-     * List of connectors this EV may use
+     * List of connectors this vehicle may use
+     *
+     * <p>Applications can query the property value by
+     * {@link android.car.hardware.property.CarPropertyManager#getIntArrayProperty(int, int)}. The
+     * return value is an integer array containing enums in {@link EvConnectorType}
+     *
      * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_EV_CONNECTOR_TYPE = 289472775;
     /**
      * Fuel door location
+     *
+     * <p> Applications can query the property value by
+     * {@link android.car.hardware.property.CarPropertyManager#getIntProperty(int, int)}. The return
+     * value is one of enums in {@link PortLocationType}.
+     *
      * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_FUEL_DOOR_LOCATION = 289407240;
     /**
      * EV port location
+     *
+     * <p> Applications can query the property value by
+     * {@link android.car.hardware.property.CarPropertyManager#getIntProperty(int, int)}. The return
+     * value is one of enums in {@link PortLocationType}.
+     *
      * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_EV_PORT_LOCATION = 289407241;
     /**
+     * Multiple EV port locations
+     *
+     * <p> Applications can query the property value by
+     * {@link android.car.hardware.property.CarPropertyManager#getIntArrayProperty(int, int)}. The
+     * return value is an integer array containing enums in {@link PortLocationType}.
+     *
+     * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
+     */
+    @RequiresPermission(Car.PERMISSION_CAR_INFO)
+    public static final int INFO_MULTI_EV_PORT_LOCATIONS = 289472780;
+    /**
      * Driver's seat location
      * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_DRIVER_SEAT = 356516106;
     /**
+     * Vehicle's exterior dimensions.
+     * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
+     */
+    @RequiresPermission(Car.PERMISSION_CAR_INFO)
+    public static final int INFO_EXTERIOR_DIMENSIONS = 289472779;
+    /**
      * Current odometer value of the vehicle
      * Requires permission: {@link Car#PERMISSION_MILEAGE}.
      */
+    @RequiresPermission(Car.PERMISSION_MILEAGE)
     public static final int PERF_ODOMETER = 291504644;
     /**
      * Speed of the vehicle
      * Requires permission: {@link Car#PERMISSION_SPEED}.
      */
+    @RequiresPermission(Car.PERMISSION_SPEED)
     public static final int PERF_VEHICLE_SPEED = 291504647;
     /**
      * Speed of the vehicle for displays
@@ -99,73 +146,105 @@
      * usually displayed on the speedometer.
      * Requires permission: {@link Car#PERMISSION_SPEED}.
      */
+    @RequiresPermission(Car.PERMISSION_SPEED)
     public static final int PERF_VEHICLE_SPEED_DISPLAY = 291504648;
     /**
-     * Steering angle of the vehicle
+     * Front bicycle model steering angle for vehicle
      *
      * Angle is in degrees. Left is negative.
      * Requires permission: {@link Car#PERMISSION_READ_STEERING_STATE}.
      */
+    @RequiresPermission(Car.PERMISSION_READ_STEERING_STATE)
     public static final int PERF_STEERING_ANGLE = 291504649;
     /**
+     * Rear bicycle model steering angle for vehicle
+     *
+     * Angle is in degrees. Left is negative.
+     * Requires permission: {@link Car#PERMISSION_READ_STEERING_STATE}.
+     */
+    @RequiresPermission(Car.PERMISSION_READ_STEERING_STATE)
+    public static final int PERF_REAR_STEERING_ANGLE = 291504656;
+    /**
      * Temperature of engine coolant
      * Requires permission: {@link Car#PERMISSION_CAR_ENGINE_DETAILED}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_ENGINE_DETAILED)
     public static final int ENGINE_COOLANT_TEMP = 291504897;
     /**
      * Engine oil level
      * Requires permission: {@link Car#PERMISSION_CAR_ENGINE_DETAILED}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_ENGINE_DETAILED)
     public static final int ENGINE_OIL_LEVEL = 289407747;
     /**
      * Temperature of engine oil
      * Requires permission: {@link Car#PERMISSION_CAR_ENGINE_DETAILED}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_ENGINE_DETAILED)
     public static final int ENGINE_OIL_TEMP = 291504900;
     /**
      * Engine rpm
      * Requires permission: {@link Car#PERMISSION_CAR_ENGINE_DETAILED}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_ENGINE_DETAILED)
     public static final int ENGINE_RPM = 291504901;
     /**
      * Reports wheel ticks
      * Requires permission: {@link Car#PERMISSION_SPEED}.
      */
+    @RequiresPermission(Car.PERMISSION_SPEED)
     public static final int WHEEL_TICK = 290521862;
     /**
      * Fuel remaining in the the vehicle, in milliliters
      * Requires permission: {@link Car#PERMISSION_ENERGY}.
      */
+    @RequiresPermission(Car.PERMISSION_ENERGY)
     public static final int FUEL_LEVEL = 291504903;
     /**
      * Fuel door open
-     * Requires permission: {@link Car#PERMISSION_ENERGY_PORTS}.
+     * Requires permission: {@link Car#PERMISSION_ENERGY_PORTS} to read the property.
+     * Requires permission: {@link Car#PERMISSION_CONTROL_ENERGY_PORTS} to control the property.
      */
+    @RequiresPermission.Read(@RequiresPermission(Car.PERMISSION_ENERGY_PORTS))
+    @RequiresPermission.Write(@RequiresPermission(Car.PERMISSION_CONTROL_ENERGY_PORTS))
     public static final int FUEL_DOOR_OPEN = 287310600;
     /**
      * EV battery level in WH, if EV or hybrid
      * Requires permission: {@link Car#PERMISSION_ENERGY}.
      */
+    @RequiresPermission(Car.PERMISSION_ENERGY)
     public static final int EV_BATTERY_LEVEL = 291504905;
     /**
      * EV charge port open
-     * Requires permission: {@link Car#PERMISSION_ENERGY_PORTS}.
+     * Requires permission: {@link Car#PERMISSION_ENERGY_PORTS} to read the property.
+     * Requires permission: {@link Car#PERMISSION_CONTROL_ENERGY_PORTS} to control the property.
      */
+    @RequiresPermission.Read(@RequiresPermission(Car.PERMISSION_ENERGY_PORTS))
+    @RequiresPermission.Write(@RequiresPermission(Car.PERMISSION_CONTROL_ENERGY_PORTS))
     public static final int EV_CHARGE_PORT_OPEN = 287310602;
     /**
      * EV charge port connected
      * Requires permission: {@link Car#PERMISSION_ENERGY_PORTS}.
      */
+    @RequiresPermission(Car.PERMISSION_ENERGY_PORTS)
     public static final int EV_CHARGE_PORT_CONNECTED = 287310603;
     /**
      * EV instantaneous charge rate in milliwatts
      * Requires permission: {@link Car#PERMISSION_ENERGY}.
      */
+    @RequiresPermission(Car.PERMISSION_ENERGY)
     public static final int EV_BATTERY_INSTANTANEOUS_CHARGE_RATE = 291504908;
     /**
      * Range remaining
-     * Requires permission: {@link Car#PERMISSION_ENERGY}.
+     *
+     * Meters remaining of fuel and charge.  Range remaining shall account for
+     * all energy sources in a vehicle.  For example, a hybrid car's range will
+     * be the sum of the ranges based on fuel and battery.
+     * Requires permission: {@link Car#PERMISSION_ENERGY} to read the property.
+     * Requires permission: {@link Car#PERMISSION_ADJUST_RANGE_REMAINING} to write the property.
      */
+    @RequiresPermission.Read(@RequiresPermission(Car.PERMISSION_ENERGY))
+    @RequiresPermission.Write(@RequiresPermission(Car.PERMISSION_ADJUST_RANGE_REMAINING))
     public static final int RANGE_REMAINING = 291504904;
     /**
      * Tire pressure
@@ -174,6 +253,7 @@
      * value denoted by its areaConfig.areaId.
      * Requires permission: {@link Car#PERMISSION_TIRES}.
      */
+    @RequiresPermission(Car.PERMISSION_TIRES)
     public static final int TIRE_PRESSURE = 392168201;
     /**
      * Currently selected gear
@@ -181,6 +261,7 @@
      * This is the gear selected by the user.
      * Requires permission: {@link Car#PERMISSION_POWERTRAIN}.
      */
+    @RequiresPermission(Car.PERMISSION_POWERTRAIN)
     public static final int GEAR_SELECTION = 289408000;
     /**
      * Current gear. In non-manual case, selected gear may not
@@ -189,126 +270,151 @@
      * the actual gear the transmission is currently running in.
      * Requires permission: {@link Car#PERMISSION_POWERTRAIN}.
      */
+    @RequiresPermission(Car.PERMISSION_POWERTRAIN)
     public static final int CURRENT_GEAR = 289408001;
     /**
      * Parking brake state.
      * Requires permission: {@link Car#PERMISSION_POWERTRAIN}.
      */
+    @RequiresPermission(Car.PERMISSION_POWERTRAIN)
     public static final int PARKING_BRAKE_ON = 287310850;
     /**
      * Auto-apply parking brake.
      * Requires permission: {@link Car#PERMISSION_POWERTRAIN}.
      */
+    @RequiresPermission(Car.PERMISSION_POWERTRAIN)
     public static final int PARKING_BRAKE_AUTO_APPLY = 287310851;
     /**
      * Warning for fuel low level.
      * Requires permission: {@link Car#PERMISSION_ENERGY}.
      */
+    @RequiresPermission(Car.PERMISSION_ENERGY)
     public static final int FUEL_LEVEL_LOW = 287310853;
     /**
      * Night mode
      * Requires permission: {@link Car#PERMISSION_EXTERIOR_ENVIRONMENT}.
      */
+    @RequiresPermission(Car.PERMISSION_EXTERIOR_ENVIRONMENT)
     public static final int NIGHT_MODE = 287310855;
     /**
      * State of the vehicles turn signals
      * Requires permission: {@link Car#PERMISSION_EXTERIOR_LIGHTS}.
      */
+    @RequiresPermission(Car.PERMISSION_EXTERIOR_LIGHTS)
     public static final int TURN_SIGNAL_STATE = 289408008;
     /**
      * Represents ignition state
      * Requires permission: {@link Car#PERMISSION_POWERTRAIN}.
      */
+    @RequiresPermission(Car.PERMISSION_POWERTRAIN)
     public static final int IGNITION_STATE = 289408009;
     /**
      * ABS is active
      * Requires permission: {@link Car#PERMISSION_CAR_DYNAMICS_STATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_DYNAMICS_STATE)
     public static final int ABS_ACTIVE = 287310858;
     /**
      * Traction Control is active
      * Requires permission: {@link Car#PERMISSION_CAR_DYNAMICS_STATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_DYNAMICS_STATE)
     public static final int TRACTION_CONTROL_ACTIVE = 287310859;
     /**
      * Fan speed setting
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_FAN_SPEED = 356517120;
     /**
      * Fan direction setting
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_FAN_DIRECTION = 356517121;
     /**
      * HVAC current temperature.
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_TEMPERATURE_CURRENT = 358614274;
     /**
      * HVAC, target temperature set.
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_TEMPERATURE_SET = 358614275;
     /**
      * On/off defrost for designated window
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_DEFROSTER = 320865540;
     /**
      * On/off AC for designated areaId
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_AC_ON = 354419973;
     /**
      * On/off max AC
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_MAX_AC_ON = 354419974;
     /**
      * On/off max defrost
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_MAX_DEFROST_ON = 354419975;
     /**
      * Recirculation on/off
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_RECIRC_ON = 354419976;
     /**
      * Enable temperature coupling between areas.
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_DUAL_ON = 354419977;
     /**
      * On/off automatic mode
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_AUTO_ON = 354419978;
     /**
      * Seat heating/cooling
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_SEAT_TEMPERATURE = 356517131;
     /**
      * Side Mirror Heat
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_SIDE_MIRROR_HEAT = 339739916;
     /**
      * Steering Wheel Heating/Cooling
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_STEERING_WHEEL_HEAT = 289408269;
     /**
      * Temperature units for display
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_TEMPERATURE_DISPLAY_UNITS = 289408270;
     /**
      * Actual fan speed
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_ACTUAL_FAN_SPEED_RPM = 356517135;
     /**
      * Represents global power state for HVAC. Setting this property to false
@@ -319,35 +425,52 @@
      * merits).
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_POWER_ON = 354419984;
     /**
      * Fan Positions Available
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_FAN_DIRECTION_AVAILABLE = 356582673;
     /**
      * Automatic recirculation on/off
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_AUTO_RECIRC_ON = 354419986;
     /**
      * Seat ventilation
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
     public static final int HVAC_SEAT_VENTILATION = 356517139;
     /**
+     * ELECTRIC DEFROSTER
+     * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_CLIMATE}.
+     * @hide
+     */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
+    public static final int HVAC_ELECTRIC_DEFROSTER_ON = 320865556;
+    /**
      * Distance units for display
      * Requires permission {@link Car#PERMISSION_READ_DISPLAY_UNITS} to read the property.
      * Requires permission {@link Car#PERMISSION_CONTROL_DISPLAY_UNITS} and
      * {@link Car#PERMISSION_VENDOR_EXTENSION}to write the property.
      */
+    @RequiresPermission.Read(@RequiresPermission(Car.PERMISSION_READ_DISPLAY_UNITS))
+    @RequiresPermission.Write(@RequiresPermission(allOf = {Car.PERMISSION_CONTROL_DISPLAY_UNITS,
+            Car.PERMISSION_VENDOR_EXTENSION}))
     public static final int DISTANCE_DISPLAY_UNITS = 289408512;
     /**
      * Fuel volume units for display
      * Requires permission {@link Car#PERMISSION_READ_DISPLAY_UNITS} to read the property.
-     * Requires permission {@link Car#PERMISSION_CONTROL_DISPLAY_UNITS} and
-     * {@link Car#PERMISSION_VENDOR_EXTENSION}to write the property.
+     * Requires permission {@link Car#PERMISSION_CONTROL_DISPLAY_UNITS}
+     * and {@link Car#PERMISSION_VENDOR_EXTENSION}to write the property.
      */
+    @RequiresPermission.Read(@RequiresPermission(Car.PERMISSION_READ_DISPLAY_UNITS))
+    @RequiresPermission.Write(@RequiresPermission(allOf = {Car.PERMISSION_CONTROL_DISPLAY_UNITS,
+            Car.PERMISSION_VENDOR_EXTENSION}))
     public static final int FUEL_VOLUME_DISPLAY_UNITS = 289408513;
     /**
      * Tire pressure units for display
@@ -355,6 +478,9 @@
      * Requires permission {@link Car#PERMISSION_CONTROL_DISPLAY_UNITS} and
      * {@link Car#PERMISSION_VENDOR_EXTENSION}to write the property.
      */
+    @RequiresPermission.Read(@RequiresPermission(Car.PERMISSION_READ_DISPLAY_UNITS))
+    @RequiresPermission.Write(@RequiresPermission(allOf = {Car.PERMISSION_CONTROL_DISPLAY_UNITS,
+            Car.PERMISSION_VENDOR_EXTENSION}))
     public static final int TIRE_PRESSURE_DISPLAY_UNITS = 289408514;
     /**
      * EV battery units for display
@@ -362,6 +488,9 @@
      * Requires permission {@link Car#PERMISSION_CONTROL_DISPLAY_UNITS} and
      * {@link Car#PERMISSION_VENDOR_EXTENSION}to write the property.
      */
+    @RequiresPermission.Read(@RequiresPermission(Car.PERMISSION_READ_DISPLAY_UNITS))
+    @RequiresPermission.Write(@RequiresPermission(allOf = {Car.PERMISSION_CONTROL_DISPLAY_UNITS,
+            Car.PERMISSION_VENDOR_EXTENSION}))
     public static final int EV_BATTERY_DISPLAY_UNITS = 289408515;
     /**
      * Speed Units for display
@@ -370,6 +499,9 @@
      * {@link Car#PERMISSION_VENDOR_EXTENSION}to write the property.
      * @hide
      */
+    @RequiresPermission.Read(@RequiresPermission(Car.PERMISSION_READ_DISPLAY_UNITS))
+    @RequiresPermission.Write(@RequiresPermission(allOf = {Car.PERMISSION_CONTROL_DISPLAY_UNITS,
+            Car.PERMISSION_VENDOR_EXTENSION}))
     public static final int VEHICLE_SPEED_DISPLAY_UNITS = 289408516;
     /**
      * Fuel consumption units for display
@@ -377,11 +509,15 @@
      * Requires permission {@link Car#PERMISSION_CONTROL_DISPLAY_UNITS} and
      * {@link Car#PERMISSION_VENDOR_EXTENSION}to write the property.
      */
+    @RequiresPermission.Read(@RequiresPermission(Car.PERMISSION_READ_DISPLAY_UNITS))
+    @RequiresPermission.Write(@RequiresPermission(allOf = {Car.PERMISSION_CONTROL_DISPLAY_UNITS,
+            Car.PERMISSION_VENDOR_EXTENSION}))
     public static final int FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME = 287311364;
     /**
      * Outside temperature
      * Requires permission: {@link Car#PERMISSION_EXTERIOR_ENVIRONMENT}.
      */
+    @RequiresPermission(Car.PERMISSION_EXTERIOR_ENVIRONMENT)
     public static final int ENV_OUTSIDE_TEMPERATURE = 291505923;
     /**
      * Property to control power state of application processor
@@ -390,6 +526,7 @@
      * controller.
      * Requires permission: {@link Car#PERMISSION_CAR_POWER}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_POWER)
     public static final int AP_POWER_STATE_REQ = 289475072;
     /**
      * Property to report power state of application processor
@@ -398,6 +535,7 @@
      * controller.
      * Requires permission: {@link Car#PERMISSION_CAR_POWER}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_POWER)
     public static final int AP_POWER_STATE_REPORT = 289475073;
     /**
      * Property to report bootup reason for the current power on. This is a
@@ -407,6 +545,7 @@
      * VehicleApPowerBootupReason#USER_UNLOCK.
      * Requires permission: {@link Car#PERMISSION_CAR_POWER}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_POWER)
     public static final int AP_POWER_BOOTUP_REASON = 289409538;
     /**
      * Property to represent brightness of the display. Some cars have single
@@ -414,6 +553,7 @@
      * change in that control.
      * Requires permission: {@link Car#PERMISSION_CAR_POWER}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_POWER)
     public static final int DISPLAY_BRIGHTNESS = 289409539;
     /**
      * Property to feed H/W input events to android
@@ -426,46 +566,55 @@
      * Max value indicates fully open, min value (0) indicates fully closed.
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_DOORS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_DOORS)
     public static final int DOOR_POS = 373295872;
     /**
      * Door move
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_DOORS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_DOORS)
     public static final int DOOR_MOVE = 373295873;
     /**
      * Door lock
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_DOORS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_DOORS)
     public static final int DOOR_LOCK = 371198722;
     /**
      * Mirror Z Position
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_MIRRORS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_MIRRORS)
     public static final int MIRROR_Z_POS = 339741504;
     /**
      * Mirror Z Move
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_MIRRORS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_MIRRORS)
     public static final int MIRROR_Z_MOVE = 339741505;
     /**
      * Mirror Y Position
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_MIRRORS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_MIRRORS)
     public static final int MIRROR_Y_POS = 339741506;
     /**
      * Mirror Y Move
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_MIRRORS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_MIRRORS)
     public static final int MIRROR_Y_MOVE = 339741507;
     /**
      * Mirror Lock
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_MIRRORS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_MIRRORS)
     public static final int MIRROR_LOCK = 287312708;
     /**
      * Mirror Fold
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_MIRRORS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_MIRRORS)
     public static final int MIRROR_FOLD = 287312709;
     /**
      * Seat memory select
@@ -475,6 +624,7 @@
      * number of seat positions available.
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_MEMORY_SELECT = 356518784;
     /**
      * Seat memory set
@@ -484,6 +634,7 @@
      * must match the maxValue for SEAT_MEMORY_SELECT.
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_MEMORY_SET = 356518785;
     /**
      * Seatbelt buckled
@@ -491,31 +642,37 @@
      * True indicates belt is buckled.
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_BELT_BUCKLED = 354421634;
     /**
      * Seatbelt height position
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_BELT_HEIGHT_POS = 356518787;
     /**
      * Seatbelt height move
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_BELT_HEIGHT_MOVE = 356518788;
     /**
      * Seat fore/aft position
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_FORE_AFT_POS = 356518789;
     /**
      * Seat fore/aft move
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_FORE_AFT_MOVE = 356518790;
     /**
      * Seat backrest angle 1 position
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_BACKREST_ANGLE_1_POS = 356518791;
     /**
      * Seat backrest angle 1 move
@@ -523,122 +680,146 @@
      * Moves the backrest forward or recline.
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_BACKREST_ANGLE_1_MOVE = 356518792;
     /**
      * Seat backrest angle 2 position
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_BACKREST_ANGLE_2_POS = 356518793;
     /**
      * Seat backrest angle 2 move
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_BACKREST_ANGLE_2_MOVE = 356518794;
     /**
      * Seat height position
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_HEIGHT_POS = 356518795;
     /**
      * Seat height move
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_HEIGHT_MOVE = 356518796;
     /**
      * Seat depth position
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_DEPTH_POS = 356518797;
     /**
      * Seat depth move
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_DEPTH_MOVE = 356518798;
     /**
      * Seat tilt position
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_TILT_POS = 356518799;
     /**
      * Seat tilt move
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_TILT_MOVE = 356518800;
     /**
      * Lumber fore/aft position
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_LUMBAR_FORE_AFT_POS = 356518801;
     /**
      * Lumbar fore/aft move
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_LUMBAR_FORE_AFT_MOVE = 356518802;
     /**
      * Lumbar side support position
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_LUMBAR_SIDE_SUPPORT_POS = 356518803;
     /**
      * Lumbar side support move
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 356518804;
     /**
      * Headrest height position
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_HEADREST_HEIGHT_POS = 289409941;
     /**
      * Headrest height move
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_HEADREST_HEIGHT_MOVE = 356518806;
     /**
      * Headrest angle position
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_HEADREST_ANGLE_POS = 356518807;
     /**
      * Headrest angle move
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_HEADREST_ANGLE_MOVE = 356518808;
     /**
      * Headrest fore/aft position
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_HEADREST_FORE_AFT_POS = 356518809;
     /**
      * Headrest fore/aft move
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_HEADREST_FORE_AFT_MOVE = 356518810;
     /**
      * Seat Occupancy
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_SEATS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_SEATS)
     public static final int SEAT_OCCUPANCY = 356518832;
     /**
      * Window Position
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_WINDOWS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_WINDOWS)
     public static final int WINDOW_POS = 322964416;
     /**
      * Window Move
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_WINDOWS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_WINDOWS)
     public static final int WINDOW_MOVE = 322964417;
     /**
      * Window Lock
      * Requires permission: {@link Car#PERMISSION_CONTROL_CAR_WINDOWS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_CAR_WINDOWS)
     public static final int WINDOW_LOCK = 320867268;
     /**
      * Vehicle Maps Service (VMS) message
      * Requires one of permissions in {@link Car#PERMISSION_VMS_PUBLISHER},
      * {@link Car#PERMISSION_VMS_SUBSCRIBER}.
      */
+    @RequiresPermission(anyOf = {Car.PERMISSION_VMS_PUBLISHER, Car.PERMISSION_VMS_SUBSCRIBER})
     public static final int VEHICLE_MAP_SERVICE = 299895808;
     /**
      * OBD2 Live Sensor Data
@@ -646,6 +827,7 @@
      * Reports a snapshot of the current (live) values of the OBD2 sensors available.
      * Requires permission: {@link Car#PERMISSION_CAR_DIAGNOSTIC_READ_ALL}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_DIAGNOSTIC_READ_ALL)
     public static final int OBD2_LIVE_FRAME = 299896064;
     /**
      * OBD2 Freeze Frame Sensor Data
@@ -654,11 +836,13 @@
      * occurred and was detected.
      * Requires permission: {@link Car#PERMISSION_CAR_DIAGNOSTIC_READ_ALL}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_DIAGNOSTIC_READ_ALL)
     public static final int OBD2_FREEZE_FRAME = 299896065;
     /**
      * OBD2 Freeze Frame Information
      * Requires permission: {@link Car#PERMISSION_CAR_DIAGNOSTIC_READ_ALL}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_DIAGNOSTIC_READ_ALL)
     public static final int OBD2_FREEZE_FRAME_INFO = 299896066;
     /**
      * OBD2 Freeze Frame Clear
@@ -667,457 +851,412 @@
      * vehicle memory, as described by OBD2_FREEZE_FRAME_INFO.
      * Requires permission: {@link Car#PERMISSION_CAR_DIAGNOSTIC_CLEAR}.
      */
+    @RequiresPermission(Car.PERMISSION_CAR_DIAGNOSTIC_CLEAR)
     public static final int OBD2_FREEZE_FRAME_CLEAR = 299896067;
     /**
      * Headlights State
      * Requires permission: {@link Car#PERMISSION_EXTERIOR_LIGHTS}.
      */
+    @RequiresPermission(Car.PERMISSION_EXTERIOR_LIGHTS)
     public static final int HEADLIGHTS_STATE = 289410560;
     /**
      * High beam lights state
      * Requires permission: {@link Car#PERMISSION_EXTERIOR_LIGHTS}.
      */
+    @RequiresPermission(Car.PERMISSION_EXTERIOR_LIGHTS)
     public static final int HIGH_BEAM_LIGHTS_STATE = 289410561;
     /**
      * Fog light state
      * Requires permission: {@link Car#PERMISSION_EXTERIOR_LIGHTS}.
      */
+    @RequiresPermission(Car.PERMISSION_EXTERIOR_LIGHTS)
     public static final int FOG_LIGHTS_STATE = 289410562;
     /**
      * Hazard light status
      * Requires permission: {@link Car#PERMISSION_EXTERIOR_LIGHTS}.
      */
+    @RequiresPermission(Car.PERMISSION_EXTERIOR_LIGHTS)
     public static final int HAZARD_LIGHTS_STATE = 289410563;
     /**
      * Headlight switch
      * Requires permission: {@link Car#PERMISSION_CONTROL_EXTERIOR_LIGHTS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS)
     public static final int HEADLIGHTS_SWITCH = 289410576;
     /**
      * High beam light switch
      * Requires permission: {@link Car#PERMISSION_CONTROL_EXTERIOR_LIGHTS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS)
     public static final int HIGH_BEAM_LIGHTS_SWITCH = 289410577;
     /**
      * Fog light switch
      * Requires permission: {@link Car#PERMISSION_CONTROL_EXTERIOR_LIGHTS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS)
     public static final int FOG_LIGHTS_SWITCH = 289410578;
     /**
      * Hazard light switch
      * Requires permission: {@link Car#PERMISSION_CONTROL_EXTERIOR_LIGHTS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS)
     public static final int HAZARD_LIGHTS_SWITCH = 289410579;
     /**
      * Cabin lights
      * Requires permission: {@link Car#PERMISSION_READ_INTERIOR_LIGHTS}.
      */
+    @RequiresPermission(Car.PERMISSION_READ_INTERIOR_LIGHTS)
     public static final int CABIN_LIGHTS_STATE = 289410817;
     /**
      * Cabin lights switch
      * Requires permission: {@link Car#PERMISSION_CONTROL_INTERIOR_LIGHTS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_INTERIOR_LIGHTS)
     public static final int CABIN_LIGHTS_SWITCH = 289410818;
     /**
      * Reading lights
      * Requires permission: {@link Car#PERMISSION_READ_INTERIOR_LIGHTS}.
      */
+    @RequiresPermission(Car.PERMISSION_READ_INTERIOR_LIGHTS)
     public static final int READING_LIGHTS_STATE = 356519683;
     /**
      * Reading lights switch
      * Requires permission: {@link Car#PERMISSION_CONTROL_INTERIOR_LIGHTS}.
      */
+    @RequiresPermission(Car.PERMISSION_CONTROL_INTERIOR_LIGHTS)
     public static final int READING_LIGHTS_SWITCH = 356519684;
 
     /**
-     * @param o Integer
-     * @return String
+     * Property to get the initial settings for multi-user management (such as initial user).
+     *
+     * <p>Doesn't require permission because it's not exposed through
+     * {@link android.car.hardware.property.CarPropertyManager}.
+     *
+     * @hide
      */
-    public static  String toString(int o) {
-        if (o == INVALID) {
-            return "INVALID";
-        }
-        if (o == INFO_VIN) {
-            return "INFO_VIN";
-        }
-        if (o == INFO_MAKE) {
-            return "INFO_MAKE";
-        }
-        if (o == INFO_MODEL) {
-            return "INFO_MODEL";
-        }
-        if (o == INFO_MODEL_YEAR) {
-            return "INFO_MODEL_YEAR";
-        }
-        if (o == INFO_FUEL_CAPACITY) {
-            return "INFO_FUEL_CAPACITY";
-        }
-        if (o == INFO_FUEL_TYPE) {
-            return "INFO_FUEL_TYPE";
-        }
-        if (o == INFO_EV_BATTERY_CAPACITY) {
-            return "INFO_EV_BATTERY_CAPACITY";
-        }
-        if (o == INFO_EV_CONNECTOR_TYPE) {
-            return "INFO_EV_CONNECTOR_TYPE";
-        }
-        if (o == INFO_FUEL_DOOR_LOCATION) {
-            return "INFO_FUEL_DOOR_LOCATION";
-        }
-        if (o == INFO_EV_PORT_LOCATION) {
-            return "INFO_EV_PORT_LOCATION";
-        }
-        if (o == INFO_DRIVER_SEAT) {
-            return "INFO_DRIVER_SEAT";
-        }
-        if (o == PERF_ODOMETER) {
-            return "PERF_ODOMETER";
-        }
-        if (o == PERF_VEHICLE_SPEED) {
-            return "PERF_VEHICLE_SPEED";
-        }
-        if (o == PERF_VEHICLE_SPEED_DISPLAY) {
-            return "PERF_VEHICLE_SPEED_DISPLAY";
-        }
-        if (o == PERF_STEERING_ANGLE) {
-            return "PERF__STEERING_ANGLE";
-        }
-        if (o == ENGINE_COOLANT_TEMP) {
-            return "ENGINE_COOLANT_TEMP";
-        }
-        if (o == ENGINE_OIL_LEVEL) {
-            return "ENGINE_OIL_LEVEL";
-        }
-        if (o == ENGINE_OIL_TEMP) {
-            return "ENGINE_OIL_TEMP";
-        }
-        if (o == ENGINE_RPM) {
-            return "ENGINE_RPM";
-        }
-        if (o == WHEEL_TICK) {
-            return "WHEEL_TICK";
-        }
-        if (o == FUEL_LEVEL) {
-            return "FUEL_LEVEL";
-        }
-        if (o == FUEL_DOOR_OPEN) {
-            return "FUEL_DOOR_OPEN";
-        }
-        if (o == EV_BATTERY_LEVEL) {
-            return "EV_BATTERY_LEVEL";
-        }
-        if (o == EV_CHARGE_PORT_OPEN) {
-            return "EV_CHARGE_PORT_OPEN";
-        }
-        if (o == EV_CHARGE_PORT_CONNECTED) {
-            return "EV_CHARGE_PORT_CONNECTED";
-        }
-        if (o == EV_BATTERY_INSTANTANEOUS_CHARGE_RATE) {
-            return "EV_BATTERY_INSTANTANEOUS_CHARGE_RATE";
-        }
-        if (o == RANGE_REMAINING) {
-            return "RANGE_REMAINING";
-        }
-        if (o == TIRE_PRESSURE) {
-            return "TIRE_PRESSURE";
-        }
-        if (o == GEAR_SELECTION) {
-            return "GEAR_SELECTION";
-        }
-        if (o == CURRENT_GEAR) {
-            return "CURRENT_GEAR";
-        }
-        if (o == PARKING_BRAKE_ON) {
-            return "PARKING_BRAKE_ON";
-        }
-        if (o == PARKING_BRAKE_AUTO_APPLY) {
-            return "PARKING_BRAKE_AUTO_APPLY";
-        }
-        if (o == FUEL_LEVEL_LOW) {
-            return "FUEL_LEVEL_LOW";
-        }
-        if (o == NIGHT_MODE) {
-            return "NIGHT_MODE";
-        }
-        if (o == TURN_SIGNAL_STATE) {
-            return "TURN_SIGNAL_STATE";
-        }
-        if (o == IGNITION_STATE) {
-            return "IGNITION_STATE";
-        }
-        if (o == ABS_ACTIVE) {
-            return "ABS_ACTIVE";
-        }
-        if (o == TRACTION_CONTROL_ACTIVE) {
-            return "TRACTION_CONTROL_ACTIVE";
-        }
-        if (o == HVAC_FAN_SPEED) {
-            return "HVAC_FAN_SPEED";
-        }
-        if (o == HVAC_FAN_DIRECTION) {
-            return "HVAC_FAN_DIRECTION";
-        }
-        if (o == HVAC_TEMPERATURE_CURRENT) {
-            return "HVAC_TEMPERATURE_CURRENT";
-        }
-        if (o == HVAC_TEMPERATURE_SET) {
-            return "HVAC_TEMPERATURE_SET";
-        }
-        if (o == HVAC_DEFROSTER) {
-            return "HVAC_DEFROSTER";
-        }
-        if (o == HVAC_AC_ON) {
-            return "HVAC_AC_ON";
-        }
-        if (o == HVAC_MAX_AC_ON) {
-            return "HVAC_MAX_AC_ON";
-        }
-        if (o == HVAC_MAX_DEFROST_ON) {
-            return "HVAC_MAX_DEFROST_ON";
-        }
-        if (o == HVAC_RECIRC_ON) {
-            return "HVAC_RECIRC_ON";
-        }
-        if (o == HVAC_DUAL_ON) {
-            return "HVAC_DUAL_ON";
-        }
-        if (o == HVAC_AUTO_ON) {
-            return "HVAC_AUTO_ON";
-        }
-        if (o == HVAC_SEAT_TEMPERATURE) {
-            return "HVAC_SEAT_TEMPERATURE";
-        }
-        if (o == HVAC_SIDE_MIRROR_HEAT) {
-            return "HVAC_SIDE_MIRROR_HEAT";
-        }
-        if (o == HVAC_STEERING_WHEEL_HEAT) {
-            return "HVAC_STEERING_WHEEL_HEAT";
-        }
-        if (o == HVAC_TEMPERATURE_DISPLAY_UNITS) {
-            return "HVAC_TEMPERATURE_DISPLAY_UNITS";
-        }
-        if (o == HVAC_ACTUAL_FAN_SPEED_RPM) {
-            return "HVAC_ACTUAL_FAN_SPEED_RPM";
-        }
-        if (o == HVAC_POWER_ON) {
-            return "HVAC_POWER_ON";
-        }
-        if (o == HVAC_FAN_DIRECTION_AVAILABLE) {
-            return "HVAC_FAN_DIRECTION_AVAILABLE";
-        }
-        if (o == HVAC_AUTO_RECIRC_ON) {
-            return "HVAC_AUTO_RECIRC_ON";
-        }
-        if (o == HVAC_SEAT_VENTILATION) {
-            return "HVAC_SEAT_VENTILATION";
-        }
-        if (o == DISTANCE_DISPLAY_UNITS) {
-            return "DISTANCE_DISPLAY_UNITS";
-        }
-        if (o == FUEL_VOLUME_DISPLAY_UNITS) {
-            return "FUEL_VOLUME_DISPLAY_UNITS";
-        }
-        if (o == TIRE_PRESSURE_DISPLAY_UNITS) {
-            return "TIRE_PRESSURE_DISPLAY_UNITS";
-        }
-        if (o == EV_BATTERY_DISPLAY_UNITS) {
-            return "EV_BATTERY_DISPLAY_UNITS";
-        }
-        if (o == FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME) {
-            return "FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME";
-        }
-        if (o == ENV_OUTSIDE_TEMPERATURE) {
-            return "ENV_OUTSIDE_TEMPERATURE";
-        }
-        if (o == AP_POWER_STATE_REQ) {
-            return "AP_POWER_STATE_REQ";
-        }
-        if (o == AP_POWER_STATE_REPORT) {
-            return "AP_POWER_STATE_REPORT";
-        }
-        if (o == AP_POWER_BOOTUP_REASON) {
-            return "AP_POWER_BOOTUP_REASON";
-        }
-        if (o == DISPLAY_BRIGHTNESS) {
-            return "DISPLAY_BRIGHTNESS";
-        }
-        if (o == HW_KEY_INPUT) {
-            return "HW_KEY_INPUT";
-        }
-        if (o == DOOR_POS) {
-            return "DOOR_POS";
-        }
-        if (o == DOOR_MOVE) {
-            return "DOOR_MOVE";
-        }
-        if (o == DOOR_LOCK) {
-            return "DOOR_LOCK";
-        }
-        if (o == MIRROR_Z_POS) {
-            return "MIRROR_Z_POS";
-        }
-        if (o == MIRROR_Z_MOVE) {
-            return "MIRROR_Z_MOVE";
-        }
-        if (o == MIRROR_Y_POS) {
-            return "MIRROR_Y_POS";
-        }
-        if (o == MIRROR_Y_MOVE) {
-            return "MIRROR_Y_MOVE";
-        }
-        if (o == MIRROR_LOCK) {
-            return "MIRROR_LOCK";
-        }
-        if (o == MIRROR_FOLD) {
-            return "MIRROR_FOLD";
-        }
-        if (o == SEAT_MEMORY_SELECT) {
-            return "SEAT_MEMORY_SELECT";
-        }
-        if (o == SEAT_MEMORY_SET) {
-            return "SEAT_MEMORY_SET";
-        }
-        if (o == SEAT_BELT_BUCKLED) {
-            return "SEAT_BELT_BUCKLED";
-        }
-        if (o == SEAT_BELT_HEIGHT_POS) {
-            return "SEAT_BELT_HEIGHT_POS";
-        }
-        if (o == SEAT_BELT_HEIGHT_MOVE) {
-            return "SEAT_BELT_HEIGHT_MOVE";
-        }
-        if (o == SEAT_FORE_AFT_POS) {
-            return "SEAT_FORE_AFT_POS";
-        }
-        if (o == SEAT_FORE_AFT_MOVE) {
-            return "SEAT_FORE_AFT_MOVE";
-        }
-        if (o == SEAT_BACKREST_ANGLE_1_POS) {
-            return "SEAT_BACKREST_ANGLE_1_POS";
-        }
-        if (o == SEAT_BACKREST_ANGLE_1_MOVE) {
-            return "SEAT_BACKREST_ANGLE_1_MOVE";
-        }
-        if (o == SEAT_BACKREST_ANGLE_2_POS) {
-            return "SEAT_BACKREST_ANGLE_2_POS";
-        }
-        if (o == SEAT_BACKREST_ANGLE_2_MOVE) {
-            return "SEAT_BACKREST_ANGLE_2_MOVE";
-        }
-        if (o == SEAT_HEIGHT_POS) {
-            return "SEAT_HEIGHT_POS";
-        }
-        if (o == SEAT_HEIGHT_MOVE) {
-            return "SEAT_HEIGHT_MOVE";
-        }
-        if (o == SEAT_DEPTH_POS) {
-            return "SEAT_DEPTH_POS";
-        }
-        if (o == SEAT_DEPTH_MOVE) {
-            return "SEAT_DEPTH_MOVE";
-        }
-        if (o == SEAT_TILT_POS) {
-            return "SEAT_TILT_POS";
-        }
-        if (o == SEAT_TILT_MOVE) {
-            return "SEAT_TILT_MOVE";
-        }
-        if (o == SEAT_LUMBAR_FORE_AFT_POS) {
-            return "SEAT_LUMBAR_FORE_AFT_POS";
-        }
-        if (o == SEAT_LUMBAR_FORE_AFT_MOVE) {
-            return "SEAT_LUMBAR_FORE_AFT_MOVE";
-        }
-        if (o == SEAT_LUMBAR_SIDE_SUPPORT_POS) {
-            return "SEAT_LUMBAR_SIDE_SUPPORT_POS";
-        }
-        if (o == SEAT_LUMBAR_SIDE_SUPPORT_MOVE) {
-            return "SEAT_LUMBAR_SIDE_SUPPORT_MOVE";
-        }
-        if (o == SEAT_HEADREST_HEIGHT_POS) {
-            return "SEAT_HEADREST_HEIGHT_POS";
-        }
-        if (o == SEAT_HEADREST_HEIGHT_MOVE) {
-            return "SEAT_HEADREST_HEIGHT_MOVE";
-        }
-        if (o == SEAT_HEADREST_ANGLE_POS) {
-            return "SEAT_HEADREST_ANGLE_POS";
-        }
-        if (o == SEAT_HEADREST_ANGLE_MOVE) {
-            return "SEAT_HEADREST_ANGLE_MOVE";
-        }
-        if (o == SEAT_HEADREST_FORE_AFT_POS) {
-            return "SEAT_HEADREST_FORE_AFT_POS";
-        }
-        if (o == SEAT_HEADREST_FORE_AFT_MOVE) {
-            return "SEAT_HEADREST_FORE_AFT_MOVE";
-        }
-        if (o == SEAT_OCCUPANCY) {
-            return "SEAT_OCCUPANCY";
-        }
-        if (o == WINDOW_POS) {
-            return "WINDOW_POS";
-        }
-        if (o == WINDOW_MOVE) {
-            return "WINDOW_MOVE";
-        }
-        if (o == WINDOW_LOCK) {
-            return "WINDOW_LOCK";
-        }
-        if (o == VEHICLE_MAP_SERVICE) {
-            return "VEHICLE_MAP_SERVICE";
-        }
-        if (o == OBD2_LIVE_FRAME) {
-            return "OBD2_LIVE_FRAME";
-        }
-        if (o == OBD2_FREEZE_FRAME) {
-            return "OBD2_FREEZE_FRAME";
-        }
-        if (o == OBD2_FREEZE_FRAME_INFO) {
-            return "OBD2_FREEZE_FRAME_INFO";
-        }
-        if (o == OBD2_FREEZE_FRAME_CLEAR) {
-            return "OBD2_FREEZE_FRAME_CLEAR";
-        }
-        if (o == HEADLIGHTS_STATE) {
-            return "HEADLIGHTS_STATE";
-        }
-        if (o == HIGH_BEAM_LIGHTS_STATE) {
-            return "HIGH_BEAM_LIGHTS_STATE";
-        }
-        if (o == FOG_LIGHTS_STATE) {
-            return "FOG_LIGHTS_STATE";
-        }
-        if (o == HAZARD_LIGHTS_STATE) {
-            return "HAZARD_LIGHTS_STATE";
-        }
-        if (o == HEADLIGHTS_SWITCH) {
-            return "HEADLIGHTS_SWITCH";
-        }
-        if (o == HIGH_BEAM_LIGHTS_SWITCH) {
-            return "HIGH_BEAM_LIGHTS_SWITCH";
-        }
-        if (o == FOG_LIGHTS_SWITCH) {
-            return "FOG_LIGHTS_SWITCH";
-        }
-        if (o == HAZARD_LIGHTS_SWITCH) {
-            return "HAZARD_LIGHTS_SWITCH";
-        }
-        if (o == CABIN_LIGHTS_STATE) {
-            return "CABIN_LIGHTS_STATE";
-        }
-        if (o == CABIN_LIGHTS_SWITCH) {
-            return "CABIN_LIGHTS_SWITCH";
-        }
-        if (o == READING_LIGHTS_STATE) {
-            return "READING_LIGHTS_STATE";
-        }
-        if (o == READING_LIGHTS_SWITCH) {
-            return "READING_LIGHTS_SWITCH";
-        }
-        if (o == VEHICLE_SPEED_DISPLAY_UNITS) {
-            return "VEHICLE_SPEED_DISPLAY_UNITS";
+    public static final int INITIAL_USER_INFO = 299896583;
+
+    /**
+     * Property to switch user for multi-user management.
+     *
+     * <p>Doesn't require permission because it's not exposed through
+     * {@link android.car.hardware.property.CarPropertyManager}.
+     *
+     * @hide
+     */
+    public static final int SWITCH_USER = 299896584;
+
+    /**
+     * Property to create a new user for multi-user management.
+     *
+     * <p>Doesn't require permission because it's not exposed through
+     * {@link android.car.hardware.property.CarPropertyManager}.
+     *
+     * @hide
+     */
+    public static final int CREATE_USER = 299896585;
+
+    /**
+     * Property to remove a new user for multi-user management.
+     *
+     * <p>Doesn't require permission because it's not exposed through
+     * {@link android.car.hardware.property.CarPropertyManager}.
+     *
+     * @hide
+     */
+    public static final int REMOVE_USER = 299896586;
+
+    /**
+     * Property to get / set the user authentication types associated with an Android user.
+     *
+     * <p>Doesn't require permission because it's not exposed through
+     * {@link android.car.hardware.property.CarPropertyManager}.
+     *
+     * @hide
+     */
+    public static final int USER_IDENTIFICATION_ASSOCIATION = 299896587;
+
+    /**
+     * Gets a user-friendly representation of a property.
+     */
+    public static String toString(int property) {
+        switch (property) {
+            case INVALID:
+                return "INVALID";
+            case INFO_VIN:
+                return "INFO_VIN";
+            case INFO_MAKE:
+                return "INFO_MAKE";
+            case INFO_MODEL:
+                return "INFO_MODEL";
+            case INFO_MODEL_YEAR:
+                return "INFO_MODEL_YEAR";
+            case INFO_FUEL_CAPACITY:
+                return "INFO_FUEL_CAPACITY";
+            case INFO_FUEL_TYPE:
+                return "INFO_FUEL_TYPE";
+            case INFO_EV_BATTERY_CAPACITY:
+                return "INFO_EV_BATTERY_CAPACITY";
+            case INFO_MULTI_EV_PORT_LOCATIONS:
+                return "INFO_MULTI_EV_PORT_LOCATIONS";
+            case INFO_EV_CONNECTOR_TYPE:
+                return "INFO_EV_CONNECTOR_TYPE";
+            case INFO_FUEL_DOOR_LOCATION:
+                return "INFO_FUEL_DOOR_LOCATION";
+            case INFO_EV_PORT_LOCATION:
+                return "INFO_EV_PORT_LOCATION";
+            case INFO_DRIVER_SEAT:
+                return "INFO_DRIVER_SEAT";
+            case INFO_EXTERIOR_DIMENSIONS:
+                return "INFO_EXTERIOR_DIMENSIONS";
+            case PERF_ODOMETER:
+                return "PERF_ODOMETER";
+            case PERF_VEHICLE_SPEED:
+                return "PERF_VEHICLE_SPEED";
+            case PERF_VEHICLE_SPEED_DISPLAY:
+                return "PERF_VEHICLE_SPEED_DISPLAY";
+            case PERF_STEERING_ANGLE:
+                return "PERF_STEERING_ANGLE";
+            case PERF_REAR_STEERING_ANGLE:
+                return "PERF_REAR_STEERING_ANGLE";
+            case ENGINE_COOLANT_TEMP:
+                return "ENGINE_COOLANT_TEMP";
+            case ENGINE_OIL_LEVEL:
+                return "ENGINE_OIL_LEVEL";
+            case ENGINE_OIL_TEMP:
+                return "ENGINE_OIL_TEMP";
+            case ENGINE_RPM:
+                return "ENGINE_RPM";
+            case WHEEL_TICK:
+                return "WHEEL_TICK";
+            case FUEL_LEVEL:
+                return "FUEL_LEVEL";
+            case FUEL_DOOR_OPEN:
+                return "FUEL_DOOR_OPEN";
+            case EV_BATTERY_LEVEL:
+                return "EV_BATTERY_LEVEL";
+            case EV_CHARGE_PORT_OPEN:
+                return "EV_CHARGE_PORT_OPEN";
+            case EV_CHARGE_PORT_CONNECTED:
+                return "EV_CHARGE_PORT_CONNECTED";
+            case EV_BATTERY_INSTANTANEOUS_CHARGE_RATE:
+                return "EV_BATTERY_INSTANTANEOUS_CHARGE_RATE";
+            case RANGE_REMAINING:
+                return "RANGE_REMAINING";
+            case TIRE_PRESSURE:
+                return "TIRE_PRESSURE";
+            case GEAR_SELECTION:
+                return "GEAR_SELECTION";
+            case CURRENT_GEAR:
+                return "CURRENT_GEAR";
+            case PARKING_BRAKE_ON:
+                return "PARKING_BRAKE_ON";
+            case PARKING_BRAKE_AUTO_APPLY:
+                return "PARKING_BRAKE_AUTO_APPLY";
+            case FUEL_LEVEL_LOW:
+                return "FUEL_LEVEL_LOW";
+            case NIGHT_MODE:
+                return "NIGHT_MODE";
+            case TURN_SIGNAL_STATE:
+                return "TURN_SIGNAL_STATE";
+            case IGNITION_STATE:
+                return "IGNITION_STATE";
+            case ABS_ACTIVE:
+                return "ABS_ACTIVE";
+            case TRACTION_CONTROL_ACTIVE:
+                return "TRACTION_CONTROL_ACTIVE";
+            case HVAC_FAN_SPEED:
+                return "HVAC_FAN_SPEED";
+            case HVAC_FAN_DIRECTION:
+                return "HVAC_FAN_DIRECTION";
+            case HVAC_TEMPERATURE_CURRENT:
+                return "HVAC_TEMPERATURE_CURRENT";
+            case HVAC_TEMPERATURE_SET:
+                return "HVAC_TEMPERATURE_SET";
+            case HVAC_DEFROSTER:
+                return "HVAC_DEFROSTER";
+            case HVAC_AC_ON:
+                return "HVAC_AC_ON";
+            case HVAC_MAX_AC_ON:
+                return "HVAC_MAX_AC_ON";
+            case HVAC_MAX_DEFROST_ON:
+                return "HVAC_MAX_DEFROST_ON";
+            case HVAC_RECIRC_ON:
+                return "HVAC_RECIRC_ON";
+            case HVAC_DUAL_ON:
+                return "HVAC_DUAL_ON";
+            case HVAC_AUTO_ON:
+                return "HVAC_AUTO_ON";
+            case HVAC_SEAT_TEMPERATURE:
+                return "HVAC_SEAT_TEMPERATURE";
+            case HVAC_SIDE_MIRROR_HEAT:
+                return "HVAC_SIDE_MIRROR_HEAT";
+            case HVAC_STEERING_WHEEL_HEAT:
+                return "HVAC_STEERING_WHEEL_HEAT";
+            case HVAC_TEMPERATURE_DISPLAY_UNITS:
+                return "HVAC_TEMPERATURE_DISPLAY_UNITS";
+            case HVAC_ACTUAL_FAN_SPEED_RPM:
+                return "HVAC_ACTUAL_FAN_SPEED_RPM";
+            case HVAC_POWER_ON:
+                return "HVAC_POWER_ON";
+            case HVAC_FAN_DIRECTION_AVAILABLE:
+                return "HVAC_FAN_DIRECTION_AVAILABLE";
+            case HVAC_AUTO_RECIRC_ON:
+                return "HVAC_AUTO_RECIRC_ON";
+            case HVAC_SEAT_VENTILATION:
+                return "HVAC_SEAT_VENTILATION";
+            case HVAC_ELECTRIC_DEFROSTER_ON:
+                return "HVAC_ELECTRIC_DEFROSTER_ON";
+            case DISTANCE_DISPLAY_UNITS:
+                return "DISTANCE_DISPLAY_UNITS";
+            case FUEL_VOLUME_DISPLAY_UNITS:
+                return "FUEL_VOLUME_DISPLAY_UNITS";
+            case TIRE_PRESSURE_DISPLAY_UNITS:
+                return "TIRE_PRESSURE_DISPLAY_UNITS";
+            case EV_BATTERY_DISPLAY_UNITS:
+                return "EV_BATTERY_DISPLAY_UNITS";
+            case FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME:
+                return "FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME";
+            case ENV_OUTSIDE_TEMPERATURE:
+                return "ENV_OUTSIDE_TEMPERATURE";
+            case AP_POWER_STATE_REQ:
+                return "AP_POWER_STATE_REQ";
+            case AP_POWER_STATE_REPORT:
+                return "AP_POWER_STATE_REPORT";
+            case AP_POWER_BOOTUP_REASON:
+                return "AP_POWER_BOOTUP_REASON";
+            case DISPLAY_BRIGHTNESS:
+                return "DISPLAY_BRIGHTNESS";
+            case HW_KEY_INPUT:
+                return "HW_KEY_INPUT";
+            case DOOR_POS:
+                return "DOOR_POS";
+            case DOOR_MOVE:
+                return "DOOR_MOVE";
+            case DOOR_LOCK:
+                return "DOOR_LOCK";
+            case MIRROR_Z_POS:
+                return "MIRROR_Z_POS";
+            case MIRROR_Z_MOVE:
+                return "MIRROR_Z_MOVE";
+            case MIRROR_Y_POS:
+                return "MIRROR_Y_POS";
+            case MIRROR_Y_MOVE:
+                return "MIRROR_Y_MOVE";
+            case MIRROR_LOCK:
+                return "MIRROR_LOCK";
+            case MIRROR_FOLD:
+                return "MIRROR_FOLD";
+            case SEAT_MEMORY_SELECT:
+                return "SEAT_MEMORY_SELECT";
+            case SEAT_MEMORY_SET:
+                return "SEAT_MEMORY_SET";
+            case SEAT_BELT_BUCKLED:
+                return "SEAT_BELT_BUCKLED";
+            case SEAT_BELT_HEIGHT_POS:
+                return "SEAT_BELT_HEIGHT_POS";
+            case SEAT_BELT_HEIGHT_MOVE:
+                return "SEAT_BELT_HEIGHT_MOVE";
+            case SEAT_FORE_AFT_POS:
+                return "SEAT_FORE_AFT_POS";
+            case SEAT_FORE_AFT_MOVE:
+                return "SEAT_FORE_AFT_MOVE";
+            case SEAT_BACKREST_ANGLE_1_POS:
+                return "SEAT_BACKREST_ANGLE_1_POS";
+            case SEAT_BACKREST_ANGLE_1_MOVE:
+                return "SEAT_BACKREST_ANGLE_1_MOVE";
+            case SEAT_BACKREST_ANGLE_2_POS:
+                return "SEAT_BACKREST_ANGLE_2_POS";
+            case SEAT_BACKREST_ANGLE_2_MOVE:
+                return "SEAT_BACKREST_ANGLE_2_MOVE";
+            case SEAT_HEIGHT_POS:
+                return "SEAT_HEIGHT_POS";
+            case SEAT_HEIGHT_MOVE:
+                return "SEAT_HEIGHT_MOVE";
+            case SEAT_DEPTH_POS:
+                return "SEAT_DEPTH_POS";
+            case SEAT_DEPTH_MOVE:
+                return "SEAT_DEPTH_MOVE";
+            case SEAT_TILT_POS:
+                return "SEAT_TILT_POS";
+            case SEAT_TILT_MOVE:
+                return "SEAT_TILT_MOVE";
+            case SEAT_LUMBAR_FORE_AFT_POS:
+                return "SEAT_LUMBAR_FORE_AFT_POS";
+            case SEAT_LUMBAR_FORE_AFT_MOVE:
+                return "SEAT_LUMBAR_FORE_AFT_MOVE";
+            case SEAT_LUMBAR_SIDE_SUPPORT_POS:
+                return "SEAT_LUMBAR_SIDE_SUPPORT_POS";
+            case SEAT_LUMBAR_SIDE_SUPPORT_MOVE:
+                return "SEAT_LUMBAR_SIDE_SUPPORT_MOVE";
+            case SEAT_HEADREST_HEIGHT_POS:
+                return "SEAT_HEADREST_HEIGHT_POS";
+            case SEAT_HEADREST_HEIGHT_MOVE:
+                return "SEAT_HEADREST_HEIGHT_MOVE";
+            case SEAT_HEADREST_ANGLE_POS:
+                return "SEAT_HEADREST_ANGLE_POS";
+            case SEAT_HEADREST_ANGLE_MOVE:
+                return "SEAT_HEADREST_ANGLE_MOVE";
+            case SEAT_HEADREST_FORE_AFT_POS:
+                return "SEAT_HEADREST_FORE_AFT_POS";
+            case SEAT_HEADREST_FORE_AFT_MOVE:
+                return "SEAT_HEADREST_FORE_AFT_MOVE";
+            case SEAT_OCCUPANCY:
+                return "SEAT_OCCUPANCY";
+            case WINDOW_POS:
+                return "WINDOW_POS";
+            case WINDOW_MOVE:
+                return "WINDOW_MOVE";
+            case WINDOW_LOCK:
+                return "WINDOW_LOCK";
+            case VEHICLE_MAP_SERVICE:
+                return "VEHICLE_MAP_SERVICE";
+            case OBD2_LIVE_FRAME:
+                return "OBD2_LIVE_FRAME";
+            case OBD2_FREEZE_FRAME:
+                return "OBD2_FREEZE_FRAME";
+            case OBD2_FREEZE_FRAME_INFO:
+                return "OBD2_FREEZE_FRAME_INFO";
+            case OBD2_FREEZE_FRAME_CLEAR:
+                return "OBD2_FREEZE_FRAME_CLEAR";
+            case HEADLIGHTS_STATE:
+                return "HEADLIGHTS_STATE";
+            case HIGH_BEAM_LIGHTS_STATE:
+                return "HIGH_BEAM_LIGHTS_STATE";
+            case FOG_LIGHTS_STATE:
+                return "FOG_LIGHTS_STATE";
+            case HAZARD_LIGHTS_STATE:
+                return "HAZARD_LIGHTS_STATE";
+            case HEADLIGHTS_SWITCH:
+                return "HEADLIGHTS_SWITCH";
+            case HIGH_BEAM_LIGHTS_SWITCH:
+                return "HIGH_BEAM_LIGHTS_SWITCH";
+            case FOG_LIGHTS_SWITCH:
+                return "FOG_LIGHTS_SWITCH";
+            case HAZARD_LIGHTS_SWITCH:
+                return "HAZARD_LIGHTS_SWITCH";
+            case CABIN_LIGHTS_STATE:
+                return "CABIN_LIGHTS_STATE";
+            case CABIN_LIGHTS_SWITCH:
+                return "CABIN_LIGHTS_SWITCH";
+            case READING_LIGHTS_STATE:
+                return "READING_LIGHTS_STATE";
+            case READING_LIGHTS_SWITCH:
+                return "READING_LIGHTS_SWITCH";
+            case VEHICLE_SPEED_DISPLAY_UNITS:
+                return "VEHICLE_SPEED_DISPLAY_UNITS";
+            case INITIAL_USER_INFO:
+                return "INITIAL_USER_INFO";
+            case SWITCH_USER:
+                return "SWITCH_USER";
+            case CREATE_USER:
+                return "CREATE_USER";
+            case REMOVE_USER:
+                return "REMOVE_USER";
+            case USER_IDENTIFICATION_ASSOCIATION:
+                return "USER_IDENTIFICATION_ASSOCIATION";
+            default:
+                return "0x" + Integer.toHexString(property);
         }
-        return "0x" + Integer.toHexString(o);
     }
 }
diff --git a/car-lib/src/android/car/VehiclePropertyType.java b/car-lib/src/android/car/VehiclePropertyType.java
index b236d2d..80fb575 100644
--- a/car-lib/src/android/car/VehiclePropertyType.java
+++ b/car-lib/src/android/car/VehiclePropertyType.java
@@ -17,6 +17,7 @@
 package android.car;
 
 import android.annotation.IntDef;
+import android.annotation.TestApi;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -26,6 +27,7 @@
  * Value type of VehicleProperty
  * @hide
  */
+@TestApi
 public class VehiclePropertyType {
     public static final int STRING          = 0x00100000;
     public static final int BOOLEAN         = 0x00200000;
@@ -50,10 +52,10 @@
             FLOAT,
             FLOAT_VEC,
             BYTES,
-            /**
+            /*
              * Any combination of scalar or vector types. The exact format must be
              * provided in the description of the property.
-            */
+             */
             MIXED,
             MASK
     })
diff --git a/car-lib/src/android/car/annotation/ExperimentalFeature.java b/car-lib/src/android/car/annotation/ExperimentalFeature.java
new file mode 100644
index 0000000..dbaa7cb
--- /dev/null
+++ b/car-lib/src/android/car/annotation/ExperimentalFeature.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.annotation;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * This is for experimental features. Note that experimental feature will not be allowed for user
+ * build and experimental features will not be part of car API. But this annotation is provided
+ * to mark it in separate library, which will be typically static library.
+ *
+ * <p>Note that experimental feature can become official feature later.
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({ANNOTATION_TYPE, FIELD, TYPE})
+public @interface ExperimentalFeature {
+}
diff --git a/car-lib/src/android/car/annotation/FutureFeature.java b/car-lib/src/android/car/annotation/FutureFeature.java
deleted file mode 100644
index 1854771..0000000
--- a/car-lib/src/android/car/annotation/FutureFeature.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.annotation;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Annotation to represent future feature which is not ready for the current platform release.
- * Any API marked with this is for future development and should not be used for product.
- *
- * @hide
- */
-@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR,
-        ElementType.LOCAL_VARIABLE})
-@Retention(RetentionPolicy.CLASS)
-public @interface FutureFeature {
-    Class type() default Object.class;
-}
diff --git a/car-lib/src/android/car/annotation/MandatoryFeature.java b/car-lib/src/android/car/annotation/MandatoryFeature.java
new file mode 100644
index 0000000..3aca13d
--- /dev/null
+++ b/car-lib/src/android/car/annotation/MandatoryFeature.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.annotation;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * This is for mandatory features. Features marked with this will be always available in all car
+ * products.
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({ANNOTATION_TYPE, FIELD})
+public @interface MandatoryFeature {
+}
diff --git a/car-lib/src/android/car/annotation/OptionalFeature.java b/car-lib/src/android/car/annotation/OptionalFeature.java
new file mode 100644
index 0000000..342f696
--- /dev/null
+++ b/car-lib/src/android/car/annotation/OptionalFeature.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.annotation;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * This is for optional features. Features marked with this should be first checked if it is
+ * supported using {@link android.car.Car#isFeatureSupported(featureName)}.
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({ANNOTATION_TYPE, FIELD})
+public @interface OptionalFeature {
+}
diff --git a/car-lib/src/android/car/annotation/RequiredFeature.java b/car-lib/src/android/car/annotation/RequiredFeature.java
new file mode 100644
index 0000000..a5a3d14
--- /dev/null
+++ b/car-lib/src/android/car/annotation/RequiredFeature.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.annotation;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to represent a feature required to use the specified method.
+ * Ex: @RequiredFeature(Car.STORAGE_MONITORING_SERVICE)
+ *
+ * @hide
+ */
+@Target({ANNOTATION_TYPE, CONSTRUCTOR, METHOD, TYPE})
+@Retention(SOURCE)
+public @interface RequiredFeature {
+    String value();
+}
diff --git a/car-lib/src/android/car/app/CarActivityView.java b/car-lib/src/android/car/app/CarActivityView.java
new file mode 100644
index 0000000..a73cf45
--- /dev/null
+++ b/car-lib/src/android/car/app/CarActivityView.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.app;
+
+import android.annotation.Nullable;
+import android.app.ActivityView;
+import android.car.Car;
+import android.car.drivingstate.CarUxRestrictionsManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Display;
+
+/**
+ * CarActivityView is a special kind of ActivityView that can track which display the ActivityView
+ * is placed.  This information can be used to enforce the driving safety.
+ *
+ * @hide
+ */
+public final class CarActivityView extends ActivityView {
+
+    private static final String TAG = CarActivityView.class.getSimpleName();
+
+    // volatile, since mUserActivityViewCallback can be accessed from Main and Binder thread.
+    @Nullable private volatile StateCallback mUserActivityViewCallback;
+
+    @Nullable private Car mCar;
+    @Nullable private CarUxRestrictionsManager mUxRestrictionsManager;
+
+    private int mVirtualDisplayId = Display.INVALID_DISPLAY;
+
+    public CarActivityView(Context context) {
+        this(context, /*attrs=*/ null);
+    }
+
+    public CarActivityView(Context context, AttributeSet attrs) {
+        this(context, attrs, /*defStyle=*/ 0);
+    }
+
+    public CarActivityView(Context context, AttributeSet attrs, int defStyle) {
+        this(context, attrs, defStyle,  /*singleTaskInstance=*/ false);
+    }
+
+    public CarActivityView(
+            Context context, AttributeSet attrs, int defStyle, boolean singleTaskInstance) {
+        super(context, attrs, defStyle, singleTaskInstance, /*usePublicVirtualDisplay=*/ true);
+        super.setCallback(new CarActivityViewCallback());
+    }
+
+    @Override
+    public void setCallback(StateCallback callback) {
+        mUserActivityViewCallback = callback;
+        if (getVirtualDisplayId() != Display.INVALID_DISPLAY && callback != null) {
+            callback.onActivityViewReady(this);
+        }
+    }
+
+    private static void reportPhysicalDisplayId(CarUxRestrictionsManager manager,
+            int virtualDisplayId, int physicalDisplayId) {
+        Log.d(TAG, "reportPhysicalDisplayId: virtualDisplayId=" + virtualDisplayId
+                + ", physicalDisplayId=" + physicalDisplayId);
+        if (virtualDisplayId == Display.INVALID_DISPLAY) {
+            Log.w(TAG, "No virtual display to report");
+            return;
+        }
+        if (manager == null) {
+            Log.w(TAG, "CarUxRestrictionsManager is not ready yet");
+            return;
+        }
+        manager.reportVirtualDisplayToPhysicalDisplay(virtualDisplayId, physicalDisplayId);
+    }
+
+    // Intercepts ActivityViewCallback and reports it's display-id changes.
+    private class CarActivityViewCallback extends StateCallback {
+        // onActivityViewReady() and onActivityViewDestroyed() are called in the main thread.
+        @Override
+        public void onActivityViewReady(ActivityView activityView) {
+            // Stores the virtual display id to use it onActivityViewDestroyed().
+            mVirtualDisplayId = getVirtualDisplayId();
+            reportPhysicalDisplayId(
+                    mUxRestrictionsManager, mVirtualDisplayId, mContext.getDisplayId());
+
+            StateCallback stateCallback = mUserActivityViewCallback;
+            if (stateCallback != null) {
+                stateCallback.onActivityViewReady(activityView);
+            }
+        }
+
+        @Override
+        public void onActivityViewDestroyed(ActivityView activityView) {
+            // getVirtualDisplayId() will return INVALID_DISPLAY inside onActivityViewDestroyed(),
+            // because AV.mVirtualDisplay was already released during AV.performRelease().
+            int virtualDisplayId = mVirtualDisplayId;
+            mVirtualDisplayId = Display.INVALID_DISPLAY;
+            reportPhysicalDisplayId(
+                    mUxRestrictionsManager, virtualDisplayId, Display.INVALID_DISPLAY);
+
+            StateCallback stateCallback = mUserActivityViewCallback;
+            if (stateCallback != null) {
+                stateCallback.onActivityViewDestroyed(activityView);
+            }
+        }
+
+        @Override
+        public void onTaskCreated(int taskId, ComponentName componentName) {
+            StateCallback stateCallback = mUserActivityViewCallback;
+            if (stateCallback != null) {
+                stateCallback.onTaskCreated(taskId, componentName);
+            }
+        }
+
+        @Override
+        public void onTaskMovedToFront(int taskId) {
+            StateCallback stateCallback = mUserActivityViewCallback;
+            if (stateCallback != null) {
+                stateCallback.onTaskMovedToFront(taskId);
+            }
+        }
+
+        @Override
+        public void onTaskRemovalStarted(int taskId) {
+            StateCallback stateCallback = mUserActivityViewCallback;
+            if (stateCallback != null) {
+                stateCallback.onTaskRemovalStarted(taskId);
+            }
+        }
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mCar = Car.createCar(mContext, /*handler=*/ null,
+                Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
+                (car, ready) -> {
+                    // Expect to be called in the main thread, since passed a 'null' handler
+                    // in Car.createCar().
+                    if (!ready) return;
+                    mUxRestrictionsManager = (CarUxRestrictionsManager) car.getCarManager(
+                            Car.CAR_UX_RESTRICTION_SERVICE);
+                    if (mVirtualDisplayId != Display.INVALID_DISPLAY) {
+                        // When the CarService is reconnected, we'd like to report the physical
+                        // display id again, since the previously reported mapping could be gone.
+                        reportPhysicalDisplayId(
+                                mUxRestrictionsManager, mVirtualDisplayId, mContext.getDisplayId());
+                    }
+                });
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        if (mCar != null) mCar.disconnect();
+    }
+}
diff --git a/car-lib/src/android/car/cluster/CarInstrumentClusterManager.java b/car-lib/src/android/car/cluster/CarInstrumentClusterManager.java
index 2b633a0..1167810 100644
--- a/car-lib/src/android/car/cluster/CarInstrumentClusterManager.java
+++ b/car-lib/src/android/car/cluster/CarInstrumentClusterManager.java
@@ -41,6 +41,7 @@
      *
      * @hide
      */
+    @Deprecated
     @SystemApi
     public static final String CATEGORY_NAVIGATION = "android.car.cluster.NAVIGATION";
 
@@ -49,10 +50,11 @@
      * intent's extra thus activity will know information about unobscured area, etc. upon activity
      * creation.
      *
-     * @deprecated use {@link android.car.Car#CATEGORY_NAVIGATION} instead
+     * @deprecated use {@link android.car.Car#CAR_EXTRA_CLUSTER_ACTIVITY_STATE} instead
      *
      * @hide
      */
+    @Deprecated
     @SystemApi
     public static final String KEY_EXTRA_ACTIVITY_STATE =
             "android.car.cluster.ClusterActivityState";
@@ -64,6 +66,7 @@
      *
      * @hide
      */
+    @Deprecated
     @SystemApi
     public void startActivity(Intent intent) {
         // No-op
@@ -81,6 +84,7 @@
      *
      * @hide
      */
+    @Deprecated
     @SystemApi
     public void registerCallback(String category, Callback callback) {
         // No-op
@@ -95,6 +99,7 @@
      *
      * @hide
      */
+    @Deprecated
     @SystemApi
     public void unregisterCallback(Callback callback) {
         // No-op
diff --git a/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderer.java b/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderer.java
index be4cfd4..9687efb 100644
--- a/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderer.java
+++ b/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderer.java
@@ -20,6 +20,8 @@
 import android.annotation.UiThread;
 import android.content.Context;
 
+import com.android.internal.annotations.GuardedBy;
+
 /**
  * @deprecated This class is unused. Refer to {@link InstrumentClusterRenderingService} for
  * documentation on how to build a instrument cluster renderer.
@@ -30,23 +32,34 @@
 @SystemApi
 public abstract class InstrumentClusterRenderer {
 
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
     @Nullable private NavigationRenderer mNavigationRenderer;
 
     /**
-     * Calls once when instrument cluster should be created.
+     * Called when instrument cluster renderer is created.
      */
-    abstract public void onCreate(Context context);
+    public abstract void onCreate(Context context);
 
-    abstract public void onStart();
+    /**
+     * Called when instrument cluster renderer is started.
+     */
+    public abstract void onStart();
 
-    abstract public void onStop();
+    /**
+     * Called when instrument cluster renderer is stopped.
+     */
+    public abstract void onStop();
 
-    abstract protected NavigationRenderer createNavigationRenderer();
+    protected abstract NavigationRenderer createNavigationRenderer();
 
     /** The method is thread-safe, callers should cache returned object. */
     @Nullable
-    public synchronized NavigationRenderer getNavigationRenderer() {
-        return mNavigationRenderer;
+    public NavigationRenderer getNavigationRenderer() {
+        synchronized (mLock) {
+            return mNavigationRenderer;
+        }
     }
 
     /**
@@ -54,7 +67,10 @@
      * method should not be overridden by subclasses.
      */
     @UiThread
-    public synchronized final void initialize() {
-        mNavigationRenderer = createNavigationRenderer();
+    public final void initialize() {
+        synchronized (mLock) {
+            mNavigationRenderer = createNavigationRenderer();
+        }
     }
 }
+
diff --git a/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java b/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
index 3e463d1..cdf0cca 100644
--- a/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
+++ b/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
@@ -52,6 +52,7 @@
 import com.android.internal.annotations.GuardedBy;
 
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.Arrays;
 import java.util.Collection;
@@ -94,13 +95,6 @@
 
     private static final String TAG = CarLibLog.TAG_CLUSTER;
 
-    /**
-     * This constant is kept here for backwards compatibility only.
-     * @deprecated TODO (b/130255007): Remove this along {@link NavigationRenderer#onEvent(int,
-     * Bundle)}
-     */
-    @Deprecated
-    private static final int NAVIGATION_STATE_EVENT_ID = 1;
     private static final String BITMAP_QUERY_WIDTH = "w";
     private static final String BITMAP_QUERY_HEIGHT = "h";
     private static final String BITMAP_QUERY_OFFLANESALPHA = "offLanesAlpha";
@@ -262,15 +256,18 @@
      *         target Activity is in normal state and client should retry when it fails. Once it is
      *         successfully launched, car service will guarantee that it is running across crash or
      *         other events.
-     *
-     * @hide
      */
-    protected boolean startFixedActivityModeForDisplayAndUser(@NonNull Intent intent,
+    public boolean startFixedActivityModeForDisplayAndUser(@NonNull Intent intent,
             @NonNull ActivityOptions options, @UserIdInt int userId) {
         IInstrumentClusterHelper helper = getClusterHelper();
         if (helper == null) {
             return false;
         }
+        if (mActivityState != null
+                && intent.getBundleExtra(Car.CAR_EXTRA_CLUSTER_ACTIVITY_STATE) == null) {
+            intent = new Intent(intent).putExtra(Car.CAR_EXTRA_CLUSTER_ACTIVITY_STATE,
+                    mActivityState.toBundle());
+        }
         try {
             return helper.startFixedActivityModeForDisplayAndUser(intent, options.toBundle(),
                     userId);
@@ -285,10 +282,8 @@
     /**
      * Stop fixed mode for top Activity in the display. Crashing or launching other Activity
      * will not re-launch the top Activity any more.
-     *
-     * @hide
      */
-    protected void stopFixedActivityMode(int displayId) {
+    public void stopFixedActivityMode(int displayId) {
         IInstrumentClusterHelper helper = getClusterHelper();
         if (helper == null) {
             return;
@@ -417,22 +412,21 @@
             startActivityAsUser(intent, mActivityOptions.toBundle(), UserHandle.CURRENT);
             Log.i(TAG, String.format("Activity launched: %s (options: %s, displayId: %d)",
                     mActivityOptions, intent, mActivityOptions.getLaunchDisplayId()));
-        } catch (ActivityNotFoundException ex) {
+        } catch (ActivityNotFoundException e) {
             Log.w(TAG, "Unable to find activity for intent: " + intent);
             return false;
-        } catch (Exception ex) {
+        } catch (RuntimeException e) {
             // Catch all other possible exception to prevent service disruption by misbehaving
             // applications.
-            Log.e(TAG, "Error trying to launch intent: " + intent + ". Ignored", ex);
+            Log.e(TAG, "Error trying to launch intent: " + intent + ". Ignored", e);
             return false;
         }
         return true;
     }
 
     /**
-     * @deprecated Use {@link #setClusterActivityLaunchOptions(ActivityOptions)} instead.
-     *
      * @hide
+     * @deprecated Use {@link #setClusterActivityLaunchOptions(ActivityOptions)} instead.
      */
     @Deprecated
     public void setClusterActivityLaunchOptions(String category, ActivityOptions activityOptions) {
@@ -453,9 +447,8 @@
     }
 
     /**
-     * @deprecated Use {@link #setClusterActivityState(ClusterActivityState)} instead.
-     *
      * @hide
+     * @deprecated Use {@link #setClusterActivityState(ClusterActivityState)} instead.
      */
     @Deprecated
     public void setClusterActivityState(String category, Bundle state) {
@@ -532,11 +525,8 @@
         @SuppressWarnings("deprecation")
         public void onNavigationStateChanged(@Nullable Bundle bundle) throws RemoteException {
             assertClusterManagerPermission();
-            assertContextOwnership();
             mUiHandler.post(() -> {
                 if (mNavigationRenderer != null) {
-                    // Invoking deprecated method to maintain backwards compatibility
-                    mNavigationRenderer.onEvent(NAVIGATION_STATE_EVENT_ID, bundle);
                     mNavigationRenderer.onNavigationStateChanged(bundle);
                 }
             });
@@ -547,18 +537,6 @@
             assertClusterManagerPermission();
             return runAndWaitResult(() -> mNavigationRenderer.getNavigationProperties());
         }
-
-        private void assertContextOwnership() {
-            int uid = getCallingUid();
-            int pid = getCallingPid();
-
-            synchronized (mLock) {
-                if (mNavContextOwner.mUid != uid || mNavContextOwner.mPid != pid) {
-                    throw new IllegalStateException("Client {uid:" + uid + ", pid: " + pid + "} is"
-                            + " not an owner of APP_FOCUS_TYPE_NAVIGATION " + mNavContextOwner);
-                }
-            }
-        }
     }
 
     private void assertClusterManagerPermission() {
@@ -596,16 +574,21 @@
      * This is a costly operation. Returned bitmaps should be cached and fetching should be done on
      * a secondary thread.
      *
-     * Will be deprecated. Replaced by {@link #getBitmap(Uri, int, int)}.
+     * @param uri The URI of the bitmap
+     *
+     * @throws IllegalArgumentException if {@code uri} does not have width and height query params.
+     *
+     * @deprecated Replaced by {@link #getBitmap(Uri, int, int)}.
      */
+    @Deprecated
     @Nullable
     public Bitmap getBitmap(Uri uri) {
         try {
             if (uri.getQueryParameter(BITMAP_QUERY_WIDTH).isEmpty() || uri.getQueryParameter(
                     BITMAP_QUERY_HEIGHT).isEmpty()) {
                 throw new IllegalArgumentException(
-                        "Uri must have '" + BITMAP_QUERY_WIDTH + "' and '" + BITMAP_QUERY_HEIGHT
-                                + "' query parameters");
+                    "Uri must have '" + BITMAP_QUERY_WIDTH + "' and '" + BITMAP_QUERY_HEIGHT
+                            + "' query parameters");
             }
 
             ContextOwner contextOwner = getNavigationContextOwner();
@@ -615,7 +598,6 @@
             }
 
             String host = uri.getHost();
-
             if (!contextOwner.mAuthorities.contains(host)) {
                 Log.e(TAG, "Uri points to an authority not handled by the current context owner: "
                         + uri + " (valid authorities: " + contextOwner.mAuthorities + ")");
@@ -631,29 +613,27 @@
             if (Log.isLoggable(TAG, Log.DEBUG)) {
                 Log.d(TAG, "Requesting bitmap: " + uri);
             }
-            ParcelFileDescriptor fileDesc = getContentResolver()
-                    .openFileDescriptor(filteredUid, "r");
-            if (fileDesc != null) {
-                Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fileDesc.getFileDescriptor());
-                fileDesc.close();
-                return bitmap;
-            } else {
-                Log.e(TAG, "Failed to create pipe for uri string: " + uri);
+            try (ParcelFileDescriptor fileDesc = getContentResolver()
+                    .openFileDescriptor(filteredUid, "r")) {
+                if (fileDesc != null) {
+                    Bitmap bitmap = BitmapFactory.decodeFileDescriptor(
+                            fileDesc.getFileDescriptor());
+                    return bitmap;
+                } else {
+                    Log.e(TAG, "Failed to create pipe for uri string: " + uri);
+                }
             }
-        } catch (Throwable e) {
+        } catch (IOException e) {
             Log.e(TAG, "Unable to fetch uri: " + uri, e);
         }
-
         return null;
     }
 
     /**
      * See {@link #getBitmap(Uri, int, int, float)}
-     *
-     * @hide
      */
     @Nullable
-    public Bitmap getBitmap(Uri uri, int width, int height) {
+    public Bitmap getBitmap(@NonNull Uri uri, int width, int height) {
         return getBitmap(uri, width, height, 1f);
     }
 
@@ -668,11 +648,14 @@
      * </ul>
      * This is a costly operation. Returned bitmaps should be fetched on a secondary thread.
      *
+     * @param uri           The URI of the bitmap
+     * @param width         Requested width
+     * @param height        Requested height
+     * @param offLanesAlpha Opacity value of the off-lane images. Only used for lane guidance images
      * @throws IllegalArgumentException if width, height <= 0, or 0 > offLanesAlpha > 1
-     * @hide
      */
     @Nullable
-    public Bitmap getBitmap(Uri uri, int width, int height, float offLanesAlpha) {
+    public Bitmap getBitmap(@NonNull Uri uri, int width, int height, float offLanesAlpha) {
         if (width <= 0 || height <= 0) {
             throw new IllegalArgumentException("Width and height must be > 0");
         }
@@ -712,27 +695,24 @@
                 if (Log.isLoggable(TAG, Log.DEBUG)) {
                     Log.d(TAG, "Requesting bitmap: " + uri);
                 }
-                ParcelFileDescriptor fileDesc = getContentResolver()
-                        .openFileDescriptor(filteredUid, "r");
-                if (fileDesc != null) {
-                    bitmap = BitmapFactory.decodeFileDescriptor(fileDesc.getFileDescriptor());
-                    fileDesc.close();
-                    return bitmap;
-                } else {
-                    Log.e(TAG, "Failed to create pipe for uri string: " + uri);
+                try (ParcelFileDescriptor fileDesc = getContentResolver()
+                        .openFileDescriptor(filteredUid, "r")) {
+                    if (fileDesc != null) {
+                        bitmap = BitmapFactory.decodeFileDescriptor(fileDesc.getFileDescriptor());
+                        return bitmap;
+                    } else {
+                        Log.e(TAG, "Failed to create pipe for uri string: " + uri);
+                    }
                 }
-
                 if (bitmap.getWidth() != width || bitmap.getHeight() != height) {
                     bitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);
                 }
                 mCache.put(uri.toString(), bitmap);
             }
-
             return bitmap;
-        } catch (Throwable e) {
+        } catch (IOException e) {
             Log.e(TAG, "Unable to fetch uri: " + uri, e);
         }
-
         return null;
     }
 }
diff --git a/car-lib/src/android/car/cluster/renderer/NavigationRenderer.java b/car-lib/src/android/car/cluster/renderer/NavigationRenderer.java
index 429dada..afced45 100644
--- a/car-lib/src/android/car/cluster/renderer/NavigationRenderer.java
+++ b/car-lib/src/android/car/cluster/renderer/NavigationRenderer.java
@@ -37,18 +37,19 @@
     /**
      * Called when a navigation state change is received.
      *
-     * @deprecated use {@link #onNavigationStateChanged(Bundle)} instead.
+     * @removed Replaced by {@link #onNavigationStateChanged(Bundle)}
      */
-    @Deprecated
-    public void onEvent(int eventType, Bundle bundle) {}
+    public void onEvent(int eventType, Bundle bundle) {
+    }
 
     /**
      * Called when a navigation state change is received.
      *
      * @param bundle {@link android.os.Bundle} containing the description of the navigation state
-     *               change. This information can be parsed using
-     *               <a href="https://developer.android.com/reference/androidx/car/cluster/navigation/NavigationState.html#toParcelable()">
-     *               androidx.car.cluster.navigation.NavigationState#fromParcelable(Parcelable)</a>
+     *               change as an array of bytes. This information can be parsed using
+     *               {@link android.car.cluster.navigation.NavigationState.NavigationStateProto
+     *                                        #parseFrom(protoBytes)}.
      */
-    public void onNavigationStateChanged(@Nullable Bundle bundle) {}
+    public void onNavigationStateChanged(@Nullable Bundle bundle) {
+    }
 }
diff --git a/car-lib/src/android/car/content/pm/AppBlockingPackageInfo.java b/car-lib/src/android/car/content/pm/AppBlockingPackageInfo.java
index 02610ab..001c1d2 100644
--- a/car-lib/src/android/car/content/pm/AppBlockingPackageInfo.java
+++ b/car-lib/src/android/car/content/pm/AppBlockingPackageInfo.java
@@ -99,7 +99,7 @@
     public AppBlockingPackageInfo(Parcel in) {
         packageName = in.readString();
         flags = in.readInt();
-        minRevisionCode= in.readInt();
+        minRevisionCode = in.readInt();
         maxRevisionCode = in.readInt();
         signatures = in.createTypedArray(Signature.CREATOR);
         activities = in.createStringArray();
@@ -121,15 +121,18 @@
         dest.writeStringArray(activities);
     }
 
-    public static final Parcelable.Creator<AppBlockingPackageInfo> CREATOR
-            = new Parcelable.Creator<AppBlockingPackageInfo>() {
-        public AppBlockingPackageInfo createFromParcel(Parcel in) {
-            return new AppBlockingPackageInfo(in);
-        }
+    public static final Parcelable.Creator<AppBlockingPackageInfo> CREATOR =
+            new Parcelable.Creator<AppBlockingPackageInfo>() {
 
-        public AppBlockingPackageInfo[] newArray(int size) {
-            return new AppBlockingPackageInfo[size];
-        }
+                @Override
+                public AppBlockingPackageInfo createFromParcel(Parcel in) {
+                    return new AppBlockingPackageInfo(in);
+                }
+
+                @Override
+                public AppBlockingPackageInfo[] newArray(int size) {
+                    return new AppBlockingPackageInfo[size];
+                }
     };
 
     /** @hide */
@@ -194,10 +197,12 @@
             return false;
         }
         if (packageName == null) {
-            if (other.packageName != null)
+            if (other.packageName != null) {
                 return false;
-        } else if (!packageName.equals(other.packageName))
+            }
+        } else if (!packageName.equals(other.packageName)) {
             return false;
+        }
         if (!Arrays.equals(signatures, other.signatures)) {
             return false;
         }
diff --git a/car-lib/src/android/car/content/pm/CarAppBlockingPolicy.java b/car-lib/src/android/car/content/pm/CarAppBlockingPolicy.java
index 3ada352..3027d02 100644
--- a/car-lib/src/android/car/content/pm/CarAppBlockingPolicy.java
+++ b/car-lib/src/android/car/content/pm/CarAppBlockingPolicy.java
@@ -85,16 +85,19 @@
         payloadParcel.recycle();
     }
 
-    public static final Parcelable.Creator<CarAppBlockingPolicy> CREATOR
-            = new Parcelable.Creator<CarAppBlockingPolicy>() {
-        public CarAppBlockingPolicy createFromParcel(Parcel in) {
-            return new CarAppBlockingPolicy(in);
-        }
+    public static final Parcelable.Creator<CarAppBlockingPolicy> CREATOR =
+            new Parcelable.Creator<CarAppBlockingPolicy>() {
 
-        public CarAppBlockingPolicy[] newArray(int size) {
-            return new CarAppBlockingPolicy[size];
-        }
-    };
+                @Override
+                public CarAppBlockingPolicy createFromParcel(Parcel in) {
+                    return new CarAppBlockingPolicy(in);
+                }
+
+                @Override
+                public CarAppBlockingPolicy[] newArray(int size) {
+                    return new CarAppBlockingPolicy[size];
+                }
+            };
 
     @Override
     public int hashCode() {
diff --git a/car-lib/src/android/car/content/pm/CarPackageManager.java b/car-lib/src/android/car/content/pm/CarPackageManager.java
index 7498c65..6a8c7fb 100644
--- a/car-lib/src/android/car/content/pm/CarPackageManager.java
+++ b/car-lib/src/android/car/content/pm/CarPackageManager.java
@@ -17,8 +17,10 @@
 package android.car.content.pm;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.app.PendingIntent;
 import android.car.Car;
 import android.car.CarManagerBase;
 import android.content.ComponentName;
@@ -106,8 +108,8 @@
     @SystemApi
     public void setAppBlockingPolicy(
             String packageName, CarAppBlockingPolicy policy, @SetPolicyFlags int flags) {
-        if ((flags & FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0 &&
-                Looper.getMainLooper().isCurrentThread()) {
+        if ((flags & FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0
+                && Looper.getMainLooper().isCurrentThread()) {
             throw new IllegalStateException(
                     "FLAG_SET_POLICY_WAIT_FOR_CHANGE cannot be used in main thread");
         }
@@ -121,6 +123,8 @@
     /**
      * Restarts the requested task. If task with {@code taskId} does not exist, do nothing.
      *
+     * <p>This requires {@code android.permission.REAL_GET_TASKS} permission.
+     *
      * @hide
      */
     public void restartTask(int taskId) {
@@ -169,12 +173,13 @@
     }
 
     /**
-     * Check if given activity is distraction optimized, i.e, allowed in a
-     * restricted driving state
+     * Returns whether an activity is distraction optimized, i.e, allowed in a restricted
+     * driving state.
      *
-     * @param packageName
-     * @param className
-     * @return
+     * @param packageName the activity's {@link android.content.pm.ActivityInfo#packageName}.
+     * @param className the activity's {@link android.content.pm.ActivityInfo#name}.
+     * @return true if the activity is distraction optimized, false if it isn't or if the value
+     *         could not be determined.
      */
     public boolean isActivityDistractionOptimized(String packageName, String className) {
         try {
@@ -185,6 +190,22 @@
     }
 
     /**
+     * Returns whether the given {@link PendingIntent} represents an activity that is distraction
+     * optimized, i.e, allowed in a restricted driving state.
+     *
+     * @param pendingIntent the {@link PendingIntent} to check.
+     * @return true if the pending intent represents an activity that is distraction optimized,
+     *         false if it isn't or if the value could not be determined.
+     */
+    public boolean isPendingIntentDistractionOptimized(@NonNull PendingIntent pendingIntent) {
+        try {
+            return mService.isPendingIntentDistractionOptimized(pendingIntent);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, false);
+        }
+    }
+
+    /**
      * Check if given service is distraction optimized, i.e, allowed in a restricted
      * driving state.
      *
diff --git a/car-lib/src/android/car/content/pm/ICarPackageManager.aidl b/car-lib/src/android/car/content/pm/ICarPackageManager.aidl
index 7210f90..b8261f2 100644
--- a/car-lib/src/android/car/content/pm/ICarPackageManager.aidl
+++ b/car-lib/src/android/car/content/pm/ICarPackageManager.aidl
@@ -16,6 +16,7 @@
 
 package android.car.content.pm;
 
+import android.app.PendingIntent;
 import android.car.content.pm.CarAppBlockingPolicy;
 import android.content.ComponentName;
 
@@ -27,4 +28,5 @@
     boolean isActivityBackedBySafeActivity(in ComponentName activityName) = 3;
     void setEnableActivityBlocking(boolean enable) = 4;
     void restartTask(int taskId) = 5;
+    boolean isPendingIntentDistractionOptimized(in PendingIntent pendingIntent) = 6;
 }
diff --git a/car-lib/src/android/car/diagnostic/CarDiagnosticEvent.java b/car-lib/src/android/car/diagnostic/CarDiagnosticEvent.java
index 27e1f45..901d14e 100644
--- a/car-lib/src/android/car/diagnostic/CarDiagnosticEvent.java
+++ b/car-lib/src/android/car/diagnostic/CarDiagnosticEvent.java
@@ -50,13 +50,13 @@
      * Sparse array that contains the mapping of OBD2 diagnostic properties to their values for
      * integer valued properties
      */
-    private final SparseIntArray intValues;
+    private final SparseIntArray mIntValues;
 
     /**
      * Sparse array that contains the mapping of OBD2 diagnostic properties to their values for
      * float valued properties
      */
-    private final SparseArray<Float> floatValues;
+    private final SparseArray<Float> mFloatValues;
 
     /**
      * Diagnostic Troubleshooting Code (DTC) that was detected and caused this frame to be stored
@@ -68,18 +68,18 @@
         frameType = in.readInt();
         timestamp = in.readLong();
         int len = in.readInt();
-        floatValues = new SparseArray<>(len);
+        mFloatValues = new SparseArray<>(len);
         for (int i = 0; i < len; ++i) {
             int key = in.readInt();
             float value = in.readFloat();
-            floatValues.put(key, value);
+            mFloatValues.put(key, value);
         }
         len = in.readInt();
-        intValues = new SparseIntArray(len);
+        mIntValues = new SparseIntArray(len);
         for (int i = 0; i < len; ++i) {
             int key = in.readInt();
             int value = in.readInt();
-            intValues.put(key, value);
+            mIntValues.put(key, value);
         }
         dtc = (String) in.readValue(String.class.getClassLoader());
         // version 1 up to here
@@ -94,17 +94,17 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(frameType);
         dest.writeLong(timestamp);
-        dest.writeInt(floatValues.size());
-        for (int i = 0; i < floatValues.size(); ++i) {
-            int key = floatValues.keyAt(i);
+        dest.writeInt(mFloatValues.size());
+        for (int i = 0; i < mFloatValues.size(); ++i) {
+            int key = mFloatValues.keyAt(i);
             dest.writeInt(key);
-            dest.writeFloat(floatValues.get(key));
+            dest.writeFloat(mFloatValues.get(key));
         }
-        dest.writeInt(intValues.size());
-        for (int i = 0; i < intValues.size(); ++i) {
-            int key = intValues.keyAt(i);
+        dest.writeInt(mIntValues.size());
+        for (int i = 0; i < mIntValues.size(); ++i) {
+            int key = mIntValues.keyAt(i);
             dest.writeInt(key);
-            dest.writeInt(intValues.get(key));
+            dest.writeInt(mIntValues.get(key));
         }
         dest.writeValue(dtc);
     }
@@ -141,19 +141,19 @@
         jsonWriter.name("timestamp").value(timestamp);
 
         jsonWriter.name("intValues").beginArray();
-        for (int i = 0; i < intValues.size(); ++i) {
+        for (int i = 0; i < mIntValues.size(); ++i) {
             jsonWriter.beginObject();
-            jsonWriter.name("id").value(intValues.keyAt(i));
-            jsonWriter.name("value").value(intValues.valueAt(i));
+            jsonWriter.name("id").value(mIntValues.keyAt(i));
+            jsonWriter.name("value").value(mIntValues.valueAt(i));
             jsonWriter.endObject();
         }
         jsonWriter.endArray();
 
         jsonWriter.name("floatValues").beginArray();
-        for (int i = 0; i < floatValues.size(); ++i) {
+        for (int i = 0; i < mFloatValues.size(); ++i) {
             jsonWriter.beginObject();
-            jsonWriter.name("id").value(floatValues.keyAt(i));
-            jsonWriter.name("value").value(floatValues.valueAt(i));
+            jsonWriter.name("id").value(mFloatValues.keyAt(i));
+            jsonWriter.name("value").value(mFloatValues.valueAt(i));
             jsonWriter.endObject();
         }
         jsonWriter.endArray();
@@ -184,8 +184,8 @@
             String dtc) {
         this.frameType = frameType;
         this.timestamp = timestamp;
-        this.floatValues = floatValues;
-        this.intValues = intValues;
+        mFloatValues = floatValues;
+        mIntValues = intValues;
         this.dtc = dtc;
     }
 
@@ -308,16 +308,16 @@
      * @hide
      */
     public CarDiagnosticEvent withVendorSensorsRemoved() {
-        SparseIntArray newIntValues = intValues.clone();
-        SparseArray<Float> newFloatValues = floatValues.clone();
-        for (int i = 0; i < intValues.size(); ++i) {
-            int key = intValues.keyAt(i);
+        SparseIntArray newIntValues = mIntValues.clone();
+        SparseArray<Float> newFloatValues = mFloatValues.clone();
+        for (int i = 0; i < mIntValues.size(); ++i) {
+            int key = mIntValues.keyAt(i);
             if (key >= android.car.diagnostic.IntegerSensorIndex.LAST_SYSTEM) {
                 newIntValues.delete(key);
             }
         }
-        for (int i = 0; i < floatValues.size(); ++i) {
-            int key = floatValues.keyAt(i);
+        for (int i = 0; i < mFloatValues.size(); ++i) {
+            int key = mFloatValues.keyAt(i);
             if (key >= android.car.diagnostic.FloatSensorIndex.LAST_SYSTEM) {
                 newFloatValues.delete(key);
             }
@@ -337,8 +337,8 @@
 
     /** @hide */
     public boolean isEmptyFrame() {
-        boolean empty = (0 == intValues.size());
-        empty &= (0 == floatValues.size());
+        boolean empty = (0 == mIntValues.size());
+        empty &= (0 == mFloatValues.size());
         if (isFreezeFrame()) empty &= dtc.isEmpty();
         return empty;
     }
@@ -372,37 +372,42 @@
         if (!(otherObject instanceof CarDiagnosticEvent)) {
             return false;
         }
-        CarDiagnosticEvent otherEvent = (CarDiagnosticEvent)otherObject;
-        if (otherEvent.frameType != frameType)
+        CarDiagnosticEvent otherEvent = (CarDiagnosticEvent) otherObject;
+        if (otherEvent.frameType != frameType) {
             return false;
-        if (otherEvent.timestamp != timestamp)
+        }
+        if (otherEvent.timestamp != timestamp) {
             return false;
-        if (otherEvent.intValues.size() != intValues.size())
+        }
+        if (otherEvent.mIntValues.size() != mIntValues.size()) {
             return false;
-        if (otherEvent.floatValues.size() != floatValues.size())
+        }
+        if (otherEvent.mFloatValues.size() != mFloatValues.size()) {
             return false;
-        if (!Objects.equals(dtc, otherEvent.dtc))
+        }
+        if (!Objects.equals(dtc, otherEvent.dtc)) {
             return false;
-        for (int i = 0; i < intValues.size(); ++i) {
-            int key = intValues.keyAt(i);
-            int otherKey = otherEvent.intValues.keyAt(i);
+        }
+        for (int i = 0; i < mIntValues.size(); ++i) {
+            int key = mIntValues.keyAt(i);
+            int otherKey = otherEvent.mIntValues.keyAt(i);
             if (key != otherKey) {
                 return false;
             }
-            int value = intValues.valueAt(i);
-            int otherValue = otherEvent.intValues.valueAt(i);
+            int value = mIntValues.valueAt(i);
+            int otherValue = otherEvent.mIntValues.valueAt(i);
             if (value != otherValue) {
                 return false;
             }
         }
-        for (int i = 0; i < floatValues.size(); ++i) {
-            int key = floatValues.keyAt(i);
-            int otherKey = otherEvent.floatValues.keyAt(i);
+        for (int i = 0; i < mFloatValues.size(); ++i) {
+            int key = mFloatValues.keyAt(i);
+            int otherKey = otherEvent.mFloatValues.keyAt(i);
             if (key != otherKey) {
                 return false;
             }
-            float value = floatValues.valueAt(i);
-            float otherValue = otherEvent.floatValues.valueAt(i);
+            float value = mFloatValues.valueAt(i);
+            float otherValue = otherEvent.mFloatValues.valueAt(i);
             if (value != otherValue) {
                 return false;
             }
@@ -412,22 +417,22 @@
 
     @Override
     public int hashCode() {
-        Integer[] intKeys = new Integer[intValues.size()];
-        Integer[] floatKeys = new Integer[floatValues.size()];
+        Integer[] intKeys = new Integer[mIntValues.size()];
+        Integer[] floatKeys = new Integer[mFloatValues.size()];
         Integer[] intValues = new Integer[intKeys.length];
         Float[] floatValues = new Float[floatKeys.length];
         for (int i = 0; i < intKeys.length; ++i) {
-            intKeys[i] = this.intValues.keyAt(i);
-            intValues[i] = this.intValues.valueAt(i);
+            intKeys[i] = mIntValues.keyAt(i);
+            intValues[i] = mIntValues.valueAt(i);
         }
         for (int i = 0; i < floatKeys.length; ++i) {
-            floatKeys[i] = this.floatValues.keyAt(i);
-            floatValues[i] = this.floatValues.valueAt(i);
+            floatKeys[i] = mFloatValues.keyAt(i);
+            floatValues[i] = mFloatValues.valueAt(i);
         }
-        int intKeysHash = Objects.hash((Object[])intKeys);
-        int intValuesHash = Objects.hash((Object[])intValues);
-        int floatKeysHash = Objects.hash((Object[])floatKeys);
-        int floatValuesHash = Objects.hash((Object[])floatValues);
+        int intKeysHash = Objects.hash((Object[]) intKeys);
+        int intValuesHash = Objects.hash((Object[]) intValues);
+        int floatKeysHash = Objects.hash((Object[]) floatKeys);
+        int floatValuesHash = Objects.hash((Object[]) floatValues);
         return Objects.hash(frameType,
                 timestamp,
                 dtc,
@@ -443,13 +448,13 @@
                 "%s diagnostic frame {\n"
                         + "\ttimestamp: %d, "
                         + "DTC: %s\n"
-                        + "\tintValues: %s\n"
-                        + "\tfloatValues: %s\n}",
+                        + "\tmIntValues: %s\n"
+                        + "\tmFloatValues: %s\n}",
                 isLiveFrame() ? "live" : "freeze",
                 timestamp,
                 dtc,
-                intValues.toString(),
-                floatValues.toString());
+                mIntValues.toString(),
+                mFloatValues.toString());
     }
 
     /**
@@ -458,7 +463,7 @@
      */
     public int getSystemIntegerSensor(
             @android.car.diagnostic.IntegerSensorIndex.SensorIndex int sensor, int defaultValue) {
-        return intValues.get(sensor, defaultValue);
+        return mIntValues.get(sensor, defaultValue);
     }
 
     /**
@@ -467,7 +472,7 @@
      */
     public float getSystemFloatSensor(
             @android.car.diagnostic.FloatSensorIndex.SensorIndex int sensor, float defaultValue) {
-        return floatValues.get(sensor, defaultValue);
+        return mFloatValues.get(sensor, defaultValue);
     }
 
     /**
@@ -475,7 +480,7 @@
      * Returns defaultValue otherwise.
      */
     public int getVendorIntegerSensor(int sensor, int defaultValue) {
-        return intValues.get(sensor, defaultValue);
+        return mIntValues.get(sensor, defaultValue);
     }
 
     /**
@@ -483,7 +488,7 @@
      * Returns defaultValue otherwise.
      */
     public float getVendorFloatSensor(int sensor, float defaultValue) {
-        return floatValues.get(sensor, defaultValue);
+        return mFloatValues.get(sensor, defaultValue);
     }
 
     /**
@@ -492,9 +497,9 @@
      */
     public @Nullable Integer getSystemIntegerSensor(
             @android.car.diagnostic.IntegerSensorIndex.SensorIndex int sensor) {
-        int index = intValues.indexOfKey(sensor);
+        int index = mIntValues.indexOfKey(sensor);
         if (index < 0) return null;
-        return intValues.valueAt(index);
+        return mIntValues.valueAt(index);
     }
 
     /**
@@ -503,9 +508,9 @@
      */
     public @Nullable Float getSystemFloatSensor(
             @android.car.diagnostic.FloatSensorIndex.SensorIndex int sensor) {
-        int index = floatValues.indexOfKey(sensor);
+        int index = mFloatValues.indexOfKey(sensor);
         if (index < 0) return null;
-        return floatValues.valueAt(index);
+        return mFloatValues.valueAt(index);
     }
 
     /**
@@ -513,9 +518,9 @@
      * Returns null otherwise.
      */
     public @Nullable Integer getVendorIntegerSensor(int sensor) {
-        int index = intValues.indexOfKey(sensor);
+        int index = mIntValues.indexOfKey(sensor);
         if (index < 0) return null;
-        return intValues.valueAt(index);
+        return mIntValues.valueAt(index);
     }
 
     /**
@@ -523,9 +528,9 @@
      * Returns null otherwise.
      */
     public @Nullable Float getVendorFloatSensor(int sensor) {
-        int index = floatValues.indexOfKey(sensor);
+        int index = mFloatValues.indexOfKey(sensor);
         if (index < 0) return null;
-        return floatValues.valueAt(index);
+        return mFloatValues.valueAt(index);
     }
 
     /**
@@ -542,7 +547,6 @@
         public static final int CLOSED_LOOP_BUT_FEEDBACK_FAULT = 16;
 
         @Retention(RetentionPolicy.SOURCE)
-        /** @hide */
         @IntDef({
             OPEN_INSUFFICIENT_ENGINE_TEMPERATURE,
             CLOSED_LOOP,
@@ -550,7 +554,6 @@
             OPEN_SYSTEM_FAILURE,
             CLOSED_LOOP_BUT_FEEDBACK_FAULT
         })
-        /** @hide */
         public @interface Status {}
     }
 
@@ -567,14 +570,12 @@
         public static final int PUMP_ON_FOR_DIAGNOSTICS = 8;
 
         @Retention(RetentionPolicy.SOURCE)
-        /** @hide */
         @IntDef({
             UPSTREAM,
             DOWNSTREAM_OF_CATALYCIC_CONVERTER,
             FROM_OUTSIDE_OR_OFF,
             PUMP_ON_FOR_DIAGNOSTICS
         })
-        /** @hide */
         public @interface Status {}
     }
 
@@ -611,7 +612,6 @@
         public static final int BIFUEL_RUNNING_DIESEL = 23;
 
         @Retention(RetentionPolicy.SOURCE)
-        /** @hide */
         @IntDef({
             NOT_AVAILABLE,
             GASOLINE,
@@ -638,7 +638,6 @@
             HYBRID_REGENERATIVE,
             BIFUEL_RUNNING_DIESEL
         })
-        /** @hide */
         public @interface Type {}
     }
 
@@ -664,6 +663,9 @@
                 mIncompleteBitmask = incompleteBitmask;
             }
 
+            /**
+             * Returns the {@link IgnitionMonitor} associated with the value passed as parameter.
+             */
             public IgnitionMonitor fromValue(int value) {
                 boolean available = (0 != (value & mAvailableBitmask));
                 boolean incomplete = (0 != (value & mIncompleteBitmask));
@@ -727,8 +729,9 @@
          * Returns null otherwise.
          */
         public @Nullable CompressionIgnitionMonitors asCompressionIgnitionMonitors() {
-            if (this instanceof CompressionIgnitionMonitors)
+            if (this instanceof CompressionIgnitionMonitors) {
                 return (CompressionIgnitionMonitors) this;
+            }
             return null;
         }
     }
@@ -913,7 +916,8 @@
      * Returns null otherwise.
      */
     public @Nullable @SecondaryAirStatus.Status Integer getSecondaryAirStatus() {
-        return getSystemIntegerSensor(android.car.diagnostic.IntegerSensorIndex.COMMANDED_SECONDARY_AIR_STATUS);
+        return getSystemIntegerSensor(
+            android.car.diagnostic.IntegerSensorIndex.COMMANDED_SECONDARY_AIR_STATUS);
     }
 
     /**
@@ -922,9 +926,11 @@
      */
     public @Nullable CommonIgnitionMonitors getIgnitionMonitors() {
         Integer ignitionMonitorsType =
-                getSystemIntegerSensor(android.car.diagnostic.IntegerSensorIndex.IGNITION_MONITORS_SUPPORTED);
+                getSystemIntegerSensor(
+                    android.car.diagnostic.IntegerSensorIndex.IGNITION_MONITORS_SUPPORTED);
         Integer ignitionMonitorsBitmask =
-                getSystemIntegerSensor(android.car.diagnostic.IntegerSensorIndex.IGNITION_SPECIFIC_MONITORS);
+                getSystemIntegerSensor(
+                    android.car.diagnostic.IntegerSensorIndex.IGNITION_SPECIFIC_MONITORS);
         if (null == ignitionMonitorsType) return null;
         if (null == ignitionMonitorsBitmask) return null;
         switch (ignitionMonitorsType) {
diff --git a/car-lib/src/android/car/diagnostic/CarDiagnosticManager.java b/car-lib/src/android/car/diagnostic/CarDiagnosticManager.java
index c9c8b6f..9799707 100644
--- a/car-lib/src/android/car/diagnostic/CarDiagnosticManager.java
+++ b/car-lib/src/android/car/diagnostic/CarDiagnosticManager.java
@@ -51,11 +51,10 @@
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({FRAME_TYPE_LIVE, FRAME_TYPE_FREEZE})
-    /** @hide */
     public @interface FrameType {}
 
     /** @hide */
-    public static final @FrameType int FRAME_TYPES[] = {
+    public static final @FrameType int[] FRAME_TYPES = {
         FRAME_TYPE_LIVE,
         FRAME_TYPE_FREEZE
     };
@@ -95,9 +94,8 @@
     }
 
     @Override
-    /** @hide */
     public void onCarDisconnected() {
-        synchronized(mActiveListeners) {
+        synchronized (mActiveListeners) {
             mActiveListeners.clear();
         }
     }
@@ -109,7 +107,7 @@
          *
          * @param carDiagnosticEvent
          */
-        void onDiagnosticEvent(final CarDiagnosticEvent carDiagnosticEvent);
+        void onDiagnosticEvent(CarDiagnosticEvent carDiagnosticEvent);
     }
 
     // OnDiagnosticEventListener registration
@@ -136,7 +134,7 @@
     public boolean registerListener(
             OnDiagnosticEventListener listener, @FrameType int frameType, int rate) {
         assertFrameType(frameType);
-        synchronized(mActiveListeners) {
+        synchronized (mActiveListeners) {
             boolean needsServerUpdate = false;
             CarDiagnosticListeners listeners = mActiveListeners.get(frameType);
             if (listeners == null) {
@@ -161,8 +159,8 @@
      * @param listener
      */
     public void unregisterListener(OnDiagnosticEventListener listener) {
-        synchronized(mActiveListeners) {
-            for(@FrameType int frameType : FRAME_TYPES) {
+        synchronized (mActiveListeners) {
+            for (@FrameType int frameType : FRAME_TYPES) {
                 doUnregisterListenerLocked(listener, frameType);
             }
         }
@@ -179,7 +177,7 @@
             if (listeners.isEmpty()) {
                 try {
                     mService.unregisterDiagnosticListener(frameType,
-                        mListenerToService);
+                            mListenerToService);
                 } catch (RemoteException e) {
                     handleRemoteExceptionFromCarService(e);
                     // continue for local clean-up
@@ -342,12 +340,12 @@
             extends Stub {
         private final WeakReference<CarDiagnosticManager> mManager;
 
-        public CarDiagnosticEventListenerToService(CarDiagnosticManager manager) {
+        CarDiagnosticEventListenerToService(CarDiagnosticManager manager) {
             mManager = new WeakReference<>(manager);
         }
 
         private void handleOnDiagnosticEvents(CarDiagnosticManager manager,
-            List<CarDiagnosticEvent> events) {
+                List<CarDiagnosticEvent> events) {
             manager.mHandlerCallback.sendEvents(events);
         }
 
@@ -374,8 +372,8 @@
             }
             mLastUpdateTime = updateTime;
             final boolean hasVendorExtensionPermission = mVendorExtensionPermission.checkGranted();
-            final CarDiagnosticEvent eventToDispatch = hasVendorExtensionPermission ?
-                    event :
+            final CarDiagnosticEvent eventToDispatch = hasVendorExtensionPermission
+                    ? event :
                     event.withVendorSensorsRemoved();
             List<OnDiagnosticEventListener> listeners;
             synchronized (mActiveListeners) {
diff --git a/car-lib/src/android/car/diagnostic/FloatSensorIndex.java b/car-lib/src/android/car/diagnostic/FloatSensorIndex.java
index 6ec7e8c..790d43f 100644
--- a/car-lib/src/android/car/diagnostic/FloatSensorIndex.java
+++ b/car-lib/src/android/car/diagnostic/FloatSensorIndex.java
@@ -12,12 +12,13 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-*/
+ */
 
 package android.car.diagnostic;
 
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
diff --git a/car-lib/src/android/car/diagnostic/IntegerSensorIndex.java b/car-lib/src/android/car/diagnostic/IntegerSensorIndex.java
index 15291f7..83fd303 100644
--- a/car-lib/src/android/car/diagnostic/IntegerSensorIndex.java
+++ b/car-lib/src/android/car/diagnostic/IntegerSensorIndex.java
@@ -12,12 +12,13 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-*/
+ */
 
 package android.car.diagnostic;
 
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
diff --git a/car-lib/src/android/car/drivingstate/CarDrivingStateEvent.java b/car-lib/src/android/car/drivingstate/CarDrivingStateEvent.java
index bd553ce..db2cf55 100644
--- a/car-lib/src/android/car/drivingstate/CarDrivingStateEvent.java
+++ b/car-lib/src/android/car/drivingstate/CarDrivingStateEvent.java
@@ -84,16 +84,19 @@
         dest.writeLong(timeStamp);
     }
 
-    public static final Parcelable.Creator<CarDrivingStateEvent> CREATOR
-            = new Parcelable.Creator<CarDrivingStateEvent>() {
-        public CarDrivingStateEvent createFromParcel(Parcel in) {
-            return new CarDrivingStateEvent(in);
-        }
+    public static final Parcelable.Creator<CarDrivingStateEvent> CREATOR =
+            new Parcelable.Creator<CarDrivingStateEvent>() {
 
-        public CarDrivingStateEvent[] newArray(int size) {
-            return new CarDrivingStateEvent[size];
-        }
-    };
+                @Override
+                public CarDrivingStateEvent createFromParcel(Parcel in) {
+                    return new CarDrivingStateEvent(in);
+                }
+
+                @Override
+                public CarDrivingStateEvent[] newArray(int size) {
+                    return new CarDrivingStateEvent[size];
+                }
+            };
 
     public CarDrivingStateEvent(int value, long time) {
         eventValue = value;
diff --git a/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java b/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java
index 4053c5c..0998e7d 100644
--- a/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java
+++ b/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java
@@ -61,8 +61,8 @@
     /** @hide */
     @Override
     public synchronized void onCarDisconnected() {
-            mListenerToService = null;
-            mDrvStateEventListener = null;
+        mListenerToService = null;
+        mDrvStateEventListener = null;
     }
 
     /**
@@ -182,7 +182,7 @@
             ICarDrivingStateChangeListener.Stub {
         private final WeakReference<CarDrivingStateManager> mDrvStateMgr;
 
-        public CarDrivingStateChangeListenerToService(CarDrivingStateManager manager) {
+        CarDrivingStateChangeListenerToService(CarDrivingStateManager manager) {
             mDrvStateMgr = new WeakReference<>(manager);
         }
 
@@ -216,7 +216,7 @@
     private static final class EventCallbackHandler extends Handler {
         private final WeakReference<CarDrivingStateManager> mDrvStateMgr;
 
-        public EventCallbackHandler(CarDrivingStateManager manager, Looper looper) {
+        EventCallbackHandler(CarDrivingStateManager manager, Looper looper) {
             super(looper);
             mDrvStateMgr = new WeakReference<>(manager);
         }
diff --git a/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java b/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java
index 1557e6e..735e0e3 100644
--- a/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java
+++ b/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java
@@ -21,8 +21,10 @@
 import android.annotation.RequiresPermission;
 import android.car.Car;
 import android.car.CarManagerBase;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.IRemoteCallback;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
@@ -302,7 +304,7 @@
             ICarUxRestrictionsChangeListener.Stub {
         private final WeakReference<CarUxRestrictionsManager> mUxRestrictionsManager;
 
-        public CarUxRestrictionsChangeListenerToService(CarUxRestrictionsManager manager) {
+        CarUxRestrictionsChangeListenerToService(CarUxRestrictionsManager manager) {
             mUxRestrictionsManager = new WeakReference<>(manager);
         }
 
@@ -335,7 +337,7 @@
     private static final class EventCallbackHandler extends Handler {
         private final WeakReference<CarUxRestrictionsManager> mUxRestrictionsManager;
 
-        public EventCallbackHandler(CarUxRestrictionsManager manager, Looper looper) {
+        EventCallbackHandler(CarUxRestrictionsManager manager, Looper looper) {
             super(looper);
             mUxRestrictionsManager = new WeakReference<>(manager);
         }
@@ -381,4 +383,47 @@
 
         return mDisplayId;
     }
+
+    // Dummy Callback to identify the requester of reportVirtualDisplayToPhysicalDisplay() and
+    // to clean up the internal data when the requester is crashed.
+    private final IRemoteCallback mRequester = new IRemoteCallback.Stub() {
+        @Override
+        public void sendResult(Bundle data) {
+            // Unused
+        }
+    };
+
+    /**
+     * Reports the mapping the virtual display to the physical display.
+     *
+     * @param virtualDisplayId the display id of the embedded virtual display.
+     * @parom physicalDisplayId the display id where the ActivityView is placed in.
+     * @hide
+     */
+    public void reportVirtualDisplayToPhysicalDisplay(int virtualDisplayId, int physicalDisplayId) {
+        try {
+            mUxRService.reportVirtualDisplayToPhysicalDisplay(mRequester,
+                    virtualDisplayId, physicalDisplayId);
+        } catch (RemoteException e) {
+            handleRemoteExceptionFromCarService(e);
+        }
+    }
+
+    /**
+     * Finds out the physical display id where ActivityView is actually located in.
+     * If the given ActivityView is placed inside of another ActivityView, then it will return
+     * the display id where the parent ActivityView is located in.
+     *
+     * @param displayId the display id of the embedded virtual display of ActivityView.
+     * @return the physical display id where ActivityView is actually located in.
+     * @hide
+     */
+    public int getMappedPhysicalDisplayOfVirtualDisplay(int displayId) {
+        try {
+            return mUxRService.getMappedPhysicalDisplayOfVirtualDisplay(displayId);
+        } catch (RemoteException e) {
+            // When CarService isn't ready, we'll return DEFAULT_DISPLAY defensively.
+            return handleRemoteExceptionFromCarService(e, Display.DEFAULT_DISPLAY);
+        }
+    }
 }
diff --git a/car-lib/src/android/car/drivingstate/ICarUxRestrictionsManager.aidl b/car-lib/src/android/car/drivingstate/ICarUxRestrictionsManager.aidl
index 8c9afd7..dd4dc72 100644
--- a/car-lib/src/android/car/drivingstate/ICarUxRestrictionsManager.aidl
+++ b/car-lib/src/android/car/drivingstate/ICarUxRestrictionsManager.aidl
@@ -19,6 +19,7 @@
 import android.car.drivingstate.CarUxRestrictions;
 import android.car.drivingstate.CarUxRestrictionsConfiguration;
 import android.car.drivingstate.ICarUxRestrictionsChangeListener;
+import android.os.IRemoteCallback;
 
 /**
  * Binder interface for {@link android.car.drivingstate.CarUxRestrictionsManager}.
@@ -36,6 +37,8 @@
     List<CarUxRestrictionsConfiguration> getConfigs() = 5;
     // 6 removed. Do not use - boolean setRestrictionMode(int mode) = 6;
     // 7 removed. Do not use - int getRestrictionMode() = 7;
+    void reportVirtualDisplayToPhysicalDisplay(in IRemoteCallback binder, int virtualDisplayId, int physicalDisplayId) = 8;
+    int getMappedPhysicalDisplayOfVirtualDisplay(int displayId) = 9;
     boolean setRestrictionMode(String mode) = 10;
     String getRestrictionMode() = 11;
 }
diff --git a/car-lib/src/android/car/hardware/CarHvacFanDirection.java b/car-lib/src/android/car/hardware/CarHvacFanDirection.java
new file mode 100644
index 0000000..c55dd13
--- /dev/null
+++ b/car-lib/src/android/car/hardware/CarHvacFanDirection.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.hardware;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * CarHvacFanDirection is an abstraction for car's fan directions.
+ * <p>
+ * {@link android.car.VehiclePropertyIds#HVAC_FAN_DIRECTION} and
+ * {@link android.car.VehiclePropertyIds#HVAC_FAN_DIRECTION_AVAILABLE} use constants in
+ * {@link CarHvacFanDirection} as their property value.
+ * Developers can compare the property value with constants in this class to know which fan
+ * direction is used in cars.
+ * </p>
+ * @hide
+ */
+// This class is only designed to provide constants for car's fan direction. The constants should
+// exactly be same as VehicleHvacFanDirection in file
+// hardware/interfaces/automotive/vehicle/2.0/types.hal.
+@SystemApi
+public final class CarHvacFanDirection {
+    /** Constant for unknown fan direction. */
+    public static final int UNKNOWN = 0x0;
+    /** Constant for face direction. */
+    public static final int FACE = 0x01;
+    /** Constant for floor direction. */
+    public static final int FLOOR = 0x02;
+    /** Constant for face and floor direction. */
+    public static final int FACE_AND_FLOOR = 0x03; // FACE_AND_FLOOR = FACE | FLOOR
+    /** Constant for defrost direction. */
+    public static final int DEFROST = 0x04;
+    /** Constant for defrost and floor direction.*/
+    public static final int DEFROST_AND_FLOOR = 0x06; // DEFROST_AND_FLOOR = DEFROST | FLOOR
+
+    /**@hide*/
+    @IntDef(value = {
+            UNKNOWN,
+            FACE,
+            FLOOR,
+            FACE_AND_FLOOR,
+            DEFROST,
+            DEFROST_AND_FLOOR
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Enum {}
+    private CarHvacFanDirection() {}
+}
diff --git a/car-lib/src/android/car/hardware/CarPropertyConfig.java b/car-lib/src/android/car/hardware/CarPropertyConfig.java
index 87c4b46..df7ac5f 100644
--- a/car-lib/src/android/car/hardware/CarPropertyConfig.java
+++ b/car-lib/src/android/car/hardware/CarPropertyConfig.java
@@ -203,10 +203,23 @@
     }
 
     /**
-     * @return Value type of VehicleProperty.
-     * @hide
+     * Returns the value type of the vehicle property.
+     * <p>The value type could be one of the following:
+     * <ul>
+     *   <li>Boolean</li>
+     *   <li>Float</li>
+     *   <li>Float[]</li>
+     *   <li>Integer</li>
+     *   <li>Integer[]</li>
+     *   <li>Long</li>
+     *   <li>Long[]</li>
+     *   <li>String</li>
+     *   <li>byte[]</li>
+     *   <li>Object[]</li>
+     * </ul>
+     *
+     * @return the value type of the vehicle property.
      */
-    @SystemApi
     @NonNull
     public Class<T> getPropertyType() {
         return mType;
@@ -421,8 +434,8 @@
             mMaxValue = maxValue;
         }
 
-        public static final Parcelable.Creator<AreaConfig<Object>> CREATOR
-                = getCreator(Object.class);
+        public static final Parcelable.Creator<AreaConfig<Object>> CREATOR =
+                getCreator(Object.class);
 
         private static <E> Parcelable.Creator<AreaConfig<E>> getCreator(final Class<E> clazz) {
             return new Creator<AreaConfig<E>>() {
@@ -444,8 +457,13 @@
             mMaxValue = (T) in.readValue(getClass().getClassLoader());
         }
 
-        @Nullable public T getMinValue() { return mMinValue; }
-        @Nullable public T getMaxValue() { return mMaxValue; }
+        @Nullable public T getMinValue() {
+            return mMinValue;
+        }
+
+        @Nullable public T getMaxValue() {
+            return mMaxValue;
+        }
 
         @Override
         public int describeContents() {
@@ -460,10 +478,10 @@
 
         @Override
         public String toString() {
-            return "CarAreaConfig{" +
-                    "mMinValue=" + mMinValue +
-                    ", mMaxValue=" + mMaxValue +
-                    '}';
+            return "CarAreaConfig{"
+                    + "mMinValue=" + mMinValue
+                    + ", mMaxValue=" + mMaxValue
+                    + '}';
         }
     }
 
@@ -616,6 +634,9 @@
             return this;
         }
 
+        /**
+         * Builds a new {@link CarPropertyConfig}.
+         */
         public CarPropertyConfig<T> build() {
             return new CarPropertyConfig<>(mAccess, mAreaType, mChangeMode, mConfigArray,
                                            mConfigString, mMaxSampleRate, mMinSampleRate,
diff --git a/car-lib/src/android/car/hardware/CarPropertyValue.java b/car-lib/src/android/car/hardware/CarPropertyValue.java
index 38af395..b946af9 100644
--- a/car-lib/src/android/car/hardware/CarPropertyValue.java
+++ b/car-lib/src/android/car/hardware/CarPropertyValue.java
@@ -26,6 +26,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 
 /**
  * Stores values broken down by area for a vehicle property.
@@ -35,7 +36,7 @@
  *
  */
 public final class CarPropertyValue<T> implements Parcelable {
-    private final static Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
+    private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
 
     private final int mPropertyId;
     private final int mAreaId;
@@ -152,7 +153,7 @@
 
         // Special handling for String and byte[] to mitigate transaction buffer limitations.
         if (String.class.equals(valueClass)) {
-            dest.writeBlob(((String)mValue).getBytes(DEFAULT_CHARSET));
+            dest.writeBlob(((String) mValue).getBytes(DEFAULT_CHARSET));
         } else if (byte[].class.equals(valueClass)) {
             dest.writeBlob((byte[]) mValue);
         } else {
@@ -199,12 +200,12 @@
     /** @hide */
     @Override
     public String toString() {
-        return "CarPropertyValue{" +
-                "mPropertyId=0x" + toHexString(mPropertyId) +
-                ", mAreaId=0x" + toHexString(mAreaId) +
-                ", mStatus=" + mStatus +
-                ", mTimestamp=" + mTimestamp +
-                ", mValue=" + mValue +
-                '}';
+        return "CarPropertyValue{"
+                + "mPropertyId=0x" + toHexString(mPropertyId)
+                + ", mAreaId=0x" + toHexString(mAreaId)
+                + ", mStatus=" + mStatus
+                + ", mTimestamp=" + mTimestamp
+                + ", mValue=" + mValue
+                + '}';
     }
 }
diff --git a/car-lib/src/android/car/hardware/CarSensorConfig.java b/car-lib/src/android/car/hardware/CarSensorConfig.java
index 77f8dc5..4910def 100644
--- a/car-lib/src/android/car/hardware/CarSensorConfig.java
+++ b/car-lib/src/android/car/hardware/CarSensorConfig.java
@@ -19,7 +19,6 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
-import java.util.ArrayList;
 
 /**
  * A CarSensorConfig object corresponds to a single sensor type coming from the car.
@@ -28,20 +27,20 @@
 public class CarSensorConfig implements Parcelable {
     /** List of property specific mapped elements in bundle for WHEEL_TICK_DISTANCE sensor*/
     /** @hide */
-    public final static String WHEEL_TICK_DISTANCE_SUPPORTED_WHEELS =
-        "android.car.wheelTickDistanceSupportedWheels";
+    public static final String WHEEL_TICK_DISTANCE_SUPPORTED_WHEELS =
+            "android.car.wheelTickDistanceSupportedWheels";
     /** @hide */
-    public final static String WHEEL_TICK_DISTANCE_FRONT_LEFT_UM_PER_TICK =
-        "android.car.wheelTickDistanceFrontLeftUmPerTick";
+    public static final String WHEEL_TICK_DISTANCE_FRONT_LEFT_UM_PER_TICK =
+            "android.car.wheelTickDistanceFrontLeftUmPerTick";
     /** @hide */
-    public final static String WHEEL_TICK_DISTANCE_FRONT_RIGHT_UM_PER_TICK =
-        "android.car.wheelTickDistanceFrontRightUmPerTick";
+    public static final String WHEEL_TICK_DISTANCE_FRONT_RIGHT_UM_PER_TICK =
+            "android.car.wheelTickDistanceFrontRightUmPerTick";
     /** @hide */
-    public final static String WHEEL_TICK_DISTANCE_REAR_RIGHT_UM_PER_TICK =
-        "android.car.wheelTickDistanceRearRightUmPerTick";
+    public static final String WHEEL_TICK_DISTANCE_REAR_RIGHT_UM_PER_TICK =
+            "android.car.wheelTickDistanceRearRightUmPerTick";
     /** @hide */
-    public final static String WHEEL_TICK_DISTANCE_REAR_LEFT_UM_PER_TICK =
-        "android.car.wheelTickDistanceRearLeftUmPerTick";
+    public static final String WHEEL_TICK_DISTANCE_REAR_LEFT_UM_PER_TICK =
+            "android.car.wheelTickDistanceRearLeftUmPerTick";
 
     /** Config data stored in Bundle */
     private final Bundle mConfig;
@@ -67,16 +66,19 @@
     }
 
     /** @hide */
-    public static final Parcelable.Creator<CarSensorConfig> CREATOR
-    = new Parcelable.Creator<CarSensorConfig>() {
-        public CarSensorConfig createFromParcel(Parcel in) {
-            return new CarSensorConfig(in);
-        }
+    public static final Parcelable.Creator<CarSensorConfig> CREATOR =
+            new Parcelable.Creator<CarSensorConfig>() {
 
-        public CarSensorConfig[] newArray(int size) {
-            return new CarSensorConfig[size];
-        }
-    };
+            @Override
+            public CarSensorConfig createFromParcel(Parcel in) {
+                return new CarSensorConfig(in);
+            }
+
+            @Override
+            public CarSensorConfig[] newArray(int size) {
+                return new CarSensorConfig[size];
+            }
+        };
 
     /** @hide */
     public CarSensorConfig(int type, Bundle b) {
@@ -101,10 +103,9 @@
     public int getInt(String key) {
         if (mConfig.containsKey(key)) {
             return mConfig.getInt(key);
-        } else {
-            throw new IllegalArgumentException("SensorType " + mType +
-                " does not contain key: " + key);
         }
+        throw new IllegalArgumentException("SensorType " + mType
+            + " does not contain key: " + key);
     }
 
     /** @hide */
diff --git a/car-lib/src/android/car/hardware/CarSensorEvent.java b/car-lib/src/android/car/hardware/CarSensorEvent.java
index b92a789..3f33a8d 100644
--- a/car-lib/src/android/car/hardware/CarSensorEvent.java
+++ b/car-lib/src/android/car/hardware/CarSensorEvent.java
@@ -164,8 +164,8 @@
         dest.writeLongArray(longValues);
     }
 
-    public static final Parcelable.Creator<CarSensorEvent> CREATOR
-    = new Parcelable.Creator<CarSensorEvent>() {
+    public static final Parcelable.Creator<CarSensorEvent> CREATOR =
+            new Parcelable.Creator<CarSensorEvent>() {
         public CarSensorEvent createFromParcel(Parcel in) {
             return new CarSensorEvent(in);
         }
@@ -203,6 +203,9 @@
                 "Invalid sensor type: expected %d, got %d", type, sensorType));
     }
 
+    /**
+     * Environment data with timestamp and temperature.
+     */
     public static class EnvironmentData {
         public long timestamp;
         /** If unsupported by the car, this value is NaN. */
@@ -577,8 +580,7 @@
      *     CarSensorEvent.
      * @hide
      */
-    public CarFuelDoorOpenData getCarFuelDoorOpenData(
-        CarFuelDoorOpenData data) {
+    public CarFuelDoorOpenData getCarFuelDoorOpenData(CarFuelDoorOpenData data) {
         checkType(CarSensorManager.SENSOR_TYPE_FUEL_DOOR_OPEN);
         if (data == null) {
             data = new CarFuelDoorOpenData();
@@ -608,8 +610,7 @@
      *     CarSensorEvent.
      * @hide
      */
-    public CarEvBatteryLevelData getCarEvBatteryLevelData(
-        CarEvBatteryLevelData data) {
+    public CarEvBatteryLevelData getCarEvBatteryLevelData(CarEvBatteryLevelData data) {
         checkType(CarSensorManager.SENSOR_TYPE_EV_BATTERY_LEVEL);
         if (data == null) {
             data = new CarEvBatteryLevelData();
@@ -646,8 +647,7 @@
      *     CarSensorEvent.
      * @hide
      */
-    public CarEvChargePortOpenData getCarEvChargePortOpenData(
-        CarEvChargePortOpenData data) {
+    public CarEvChargePortOpenData getCarEvChargePortOpenData(CarEvChargePortOpenData data) {
         checkType(CarSensorManager.SENSOR_TYPE_EV_CHARGE_PORT_OPEN);
         if (data == null) {
             data = new CarEvChargePortOpenData();
@@ -668,7 +668,7 @@
 
     /**
      * Convenience method for obtaining a {@link CarEvChargePortConnectedData} object from a
-     * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED}.
+     * CarSensorEvent with type {@link CarSensorManager#SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED}.
      *
      * @param data an optional output parameter which, if non-null, will be used by this method
      *     instead of a newly created object.
@@ -677,7 +677,7 @@
      * @hide
      */
     public CarEvChargePortConnectedData getCarEvChargePortConnectedData(
-        CarEvChargePortConnectedData data) {
+            CarEvChargePortConnectedData data) {
         checkType(CarSensorManager.SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED);
         if (data == null) {
             data = new CarEvChargePortConnectedData();
@@ -709,7 +709,7 @@
      * @hide
      */
     public CarEvBatteryChargeRateData getCarEvBatteryChargeRateData(
-        CarEvBatteryChargeRateData data) {
+            CarEvBatteryChargeRateData data) {
         checkType(CarSensorManager.SENSOR_TYPE_EV_BATTERY_CHARGE_RATE);
         if (data == null) {
             data = new CarEvBatteryChargeRateData();
diff --git a/car-lib/src/android/car/hardware/CarSensorManager.java b/car-lib/src/android/car/hardware/CarSensorManager.java
index 082c8eb..d047aa1 100644
--- a/car-lib/src/android/car/hardware/CarSensorManager.java
+++ b/car-lib/src/android/car/hardware/CarSensorManager.java
@@ -496,7 +496,7 @@
      * A CarSensorConfig object is returned for every sensor type.  However, if there is no
      * config, the data will be empty.
      *
-     * @param sensor type to request
+     * @param type sensor type to request
      * @return CarSensorConfig object
      * @hide
      */
diff --git a/car-lib/src/android/car/hardware/CarVendorExtensionManager.java b/car-lib/src/android/car/hardware/CarVendorExtensionManager.java
index b796156..639eab1 100644
--- a/car-lib/src/android/car/hardware/CarVendorExtensionManager.java
+++ b/car-lib/src/android/car/hardware/CarVendorExtensionManager.java
@@ -45,8 +45,8 @@
 @SystemApi
 public final class CarVendorExtensionManager extends CarManagerBase {
 
-    private final static boolean DBG = false;
-    private final static String TAG = CarVendorExtensionManager.class.getSimpleName();
+    private static final boolean DBG = false;
+    private static final String TAG = CarVendorExtensionManager.class.getSimpleName();
     private final CarPropertyManager mPropertyManager;
 
     @GuardedBy("mLock")
diff --git a/car-lib/src/android/car/hardware/cabin/CarCabinManager.java b/car-lib/src/android/car/hardware/cabin/CarCabinManager.java
index 7318176..1ebf390 100644
--- a/car-lib/src/android/car/hardware/cabin/CarCabinManager.java
+++ b/car-lib/src/android/car/hardware/cabin/CarCabinManager.java
@@ -28,6 +28,8 @@
 import android.os.IBinder;
 import android.util.ArraySet;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
@@ -57,10 +59,11 @@
 @Deprecated
 @SystemApi
 public final class CarCabinManager extends CarManagerBase {
-    private final static boolean DBG = false;
-    private final static String TAG = "CarCabinManager";
+    private final Object mLock = new Object();
     private final CarPropertyManager mCarPropertyMgr;
+    @GuardedBy("mLock")
     private final ArraySet<CarCabinEventCallback> mCallbacks = new ArraySet<>();
+    @GuardedBy("mLock")
     private CarPropertyEventListenerToBase mListenerToBase = null;
 
     /** Door properties are zoned by VehicleAreaDoor */
@@ -416,7 +419,7 @@
     private static class CarPropertyEventListenerToBase implements CarPropertyEventCallback {
         private final WeakReference<CarCabinManager> mManager;
 
-        public CarPropertyEventListenerToBase(CarCabinManager manager) {
+        CarPropertyEventListenerToBase(CarCabinManager manager) {
             mManager = new WeakReference<>(manager);
         }
 
@@ -439,7 +442,7 @@
 
     private void handleOnChangeEvent(CarPropertyValue value) {
         Collection<CarCabinEventCallback> callbacks;
-        synchronized (this) {
+        synchronized (mLock) {
             callbacks = new ArraySet<>(mCallbacks);
         }
         for (CarCabinEventCallback l: callbacks) {
@@ -449,7 +452,7 @@
 
     private void handleOnErrorEvent(int propertyId, int zone) {
         Collection<CarCabinEventCallback> listeners;
-        synchronized (this) {
+        synchronized (mLock) {
             listeners = new ArraySet<>(mCallbacks);
         }
         if (!listeners.isEmpty()) {
@@ -487,16 +490,18 @@
      * Implement wrappers for contained CarPropertyManagerBase object
      * @param callback
      */
-    public synchronized void registerCallback(CarCabinEventCallback callback) {
-        if (mCallbacks.isEmpty()) {
-            mListenerToBase = new CarPropertyEventListenerToBase(this);
-        }
+    public void registerCallback(CarCabinEventCallback callback) {
         List<CarPropertyConfig> configs = getPropertyList();
-        for (CarPropertyConfig c : configs) {
-            // Register each individual propertyId
-            mCarPropertyMgr.registerCallback(mListenerToBase, c.getPropertyId(), 0);
+        synchronized (mLock) {
+            if (mListenerToBase == null) {
+                mListenerToBase = new CarPropertyEventListenerToBase(this);
+            }
+            for (CarPropertyConfig c : configs) {
+                // Register each individual propertyId
+                mCarPropertyMgr.registerCallback(mListenerToBase, c.getPropertyId(), 0);
+            }
+            mCallbacks.add(callback);
         }
-        mCallbacks.add(callback);
     }
 
     /**
@@ -504,15 +509,17 @@
      * this listener, all listening will be stopped.
      * @param callback
      */
-    public synchronized void unregisterCallback(CarCabinEventCallback callback) {
-        mCallbacks.remove(callback);
-        List<CarPropertyConfig> configs = getPropertyList();
-        for (CarPropertyConfig c : configs) {
-                // Register each individual propertyId
-            mCarPropertyMgr.unregisterCallback(mListenerToBase, c.getPropertyId());
-        }
-        if (mCallbacks.isEmpty()) {
-            mListenerToBase = null;
+    public void unregisterCallback(CarCabinEventCallback callback) {
+        synchronized (mLock) {
+            mCallbacks.remove(callback);
+            List<CarPropertyConfig> configs = getPropertyList();
+            for (CarPropertyConfig c : configs) {
+                    // Register each individual propertyId
+                mCarPropertyMgr.unregisterCallback(mListenerToBase, c.getPropertyId());
+            }
+            if (mCallbacks.isEmpty()) {
+                mListenerToBase = null;
+            }
         }
     }
 
@@ -593,8 +600,7 @@
     /** @hide */
     @Override
     public void onCarDisconnected() {
-        // TODO(b/142730969) Fix synchronization to use separate mLock
-        synchronized (this) {
+        synchronized (mLock) {
             mCallbacks.clear();
         }
         mCarPropertyMgr.onCarDisconnected();
diff --git a/car-lib/src/android/car/hardware/hvac/CarHvacManager.java b/car-lib/src/android/car/hardware/hvac/CarHvacManager.java
index 3ab7631..42cba76 100644
--- a/car-lib/src/android/car/hardware/hvac/CarHvacManager.java
+++ b/car-lib/src/android/car/hardware/hvac/CarHvacManager.java
@@ -29,6 +29,8 @@
 import android.util.ArraySet;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
@@ -45,12 +47,15 @@
 @Deprecated
 @SystemApi
 public final class CarHvacManager extends CarManagerBase {
-    private final static boolean DBG = false;
-    private final static String TAG = "CarHvacManager";
+    private static final String TAG = "CarHvacManager";
     private final CarPropertyManager mCarPropertyMgr;
-    private final ArraySet<CarHvacEventCallback> mCallbacks = new ArraySet<>();
+    @GuardedBy("mLock")
     private CarPropertyEventListenerToBase mListenerToBase = null;
 
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private final ArraySet<CarHvacEventCallback> mCallbacks = new ArraySet<>();
 
     /**
      * HVAC property IDs for get/set methods
@@ -212,16 +217,19 @@
 
 
     /**
+     * Use {@link android.car.hardware.CarHvacFanDirection#FACE} instead.
      * Represents fan direction when air flows through face directed vents.
      * This constant must be used with {@link #ID_ZONED_FAN_DIRECTION} property.
      */
     public static final int FAN_DIRECTION_FACE = 0x1;
     /**
+     * Use {@link android.car.hardware.CarHvacFanDirection#FLOOR} instead.
      * Represents fan direction when air flows through floor directed vents.
      * This constant must be used with {@link #ID_ZONED_FAN_DIRECTION} property.
      */
     public static final int FAN_DIRECTION_FLOOR = 0x2;
     /**
+     * Use {@link android.car.hardware.CarHvacFanDirection#DEFROST} instead.
      * Represents fan direction when air flows through defrost vents.
      * This constant must be used with {@link #ID_ZONED_FAN_DIRECTION} property.
      */
@@ -249,7 +257,7 @@
     private static class CarPropertyEventListenerToBase implements CarPropertyEventCallback {
         private final WeakReference<CarHvacManager> mManager;
 
-        public CarPropertyEventListenerToBase(CarHvacManager manager) {
+        CarPropertyEventListenerToBase(CarHvacManager manager) {
             mManager = new WeakReference<>(manager);
         }
 
@@ -272,7 +280,7 @@
 
     private void handleOnChangeEvent(CarPropertyValue value) {
         Collection<CarHvacEventCallback> callbacks;
-        synchronized (this) {
+        synchronized (mLock) {
             callbacks = new ArraySet<>(mCallbacks);
         }
         if (!callbacks.isEmpty()) {
@@ -284,7 +292,7 @@
 
     private void handleOnErrorEvent(int propertyId, int zone) {
         Collection<CarHvacEventCallback> callbacks;
-        synchronized (this) {
+        synchronized (mLock) {
             callbacks = new ArraySet<>(mCallbacks);
         }
         if (!callbacks.isEmpty()) {
@@ -312,16 +320,18 @@
      * Implement wrappers for contained CarPropertyManager object
      * @param callback
      */
-    public synchronized void registerCallback(CarHvacEventCallback callback) {
-        if (mCallbacks.isEmpty()) {
-            mListenerToBase = new CarPropertyEventListenerToBase(this);
-        }
-        List<CarPropertyConfig> configs = getPropertyList();
-        for (CarPropertyConfig c : configs) {
+    public void registerCallback(CarHvacEventCallback callback) {
+        synchronized (mLock) {
+            if (mCallbacks.isEmpty()) {
+                mListenerToBase = new CarPropertyEventListenerToBase(this);
+            }
+            List<CarPropertyConfig> configs = getPropertyList();
+            for (CarPropertyConfig c : configs) {
                 // Register each individual propertyId
-            mCarPropertyMgr.registerCallback(mListenerToBase, c.getPropertyId(), 0);
+                mCarPropertyMgr.registerCallback(mListenerToBase, c.getPropertyId(), 0);
+            }
+            mCallbacks.add(callback);
         }
-        mCallbacks.add(callback);
     }
 
     /**
@@ -329,21 +339,23 @@
      * this listener, all listening will be stopped.
      * @param callback
      */
-    public synchronized void unregisterCallback(CarHvacEventCallback callback) {
-        mCallbacks.remove(callback);
-        try {
-            List<CarPropertyConfig> configs = getPropertyList();
-            for (CarPropertyConfig c : configs) {
-                // Register each individual propertyId
-                mCarPropertyMgr.unregisterCallback(mListenerToBase, c.getPropertyId());
+    public void unregisterCallback(CarHvacEventCallback callback) {
+        synchronized (mLock) {
+            mCallbacks.remove(callback);
+            try {
+                List<CarPropertyConfig> configs = getPropertyList();
+                for (CarPropertyConfig c : configs) {
+                    // Register each individual propertyId
+                    mCarPropertyMgr.unregisterCallback(mListenerToBase, c.getPropertyId());
 
+                }
+            } catch (RuntimeException e) {
+                Log.e(TAG, "getPropertyList exception ", e);
             }
-        } catch (Exception e) {
-            Log.e(TAG, "getPropertyList exception ", e);
-        }
-        if (mCallbacks.isEmpty()) {
-            mCarPropertyMgr.unregisterCallback(mListenerToBase);
-            mListenerToBase = null;
+            if (mCallbacks.isEmpty()) {
+                mCarPropertyMgr.unregisterCallback(mListenerToBase);
+                mListenerToBase = null;
+            }
         }
     }
 
@@ -431,8 +443,7 @@
 
     /** @hide */
     public void onCarDisconnected() {
-        // TODO(b/142730482) Fix synchronization to use separate mLock
-        synchronized (this) {
+        synchronized (mLock) {
             mCallbacks.clear();
         }
         mCarPropertyMgr.onCarDisconnected();
diff --git a/car-lib/src/android/car/hardware/power/CarPowerManager.java b/car-lib/src/android/car/hardware/power/CarPowerManager.java
index 4b0e8cf..54d7b28 100644
--- a/car-lib/src/android/car/hardware/power/CarPowerManager.java
+++ b/car-lib/src/android/car/hardware/power/CarPowerManager.java
@@ -16,6 +16,7 @@
 
 package android.car.hardware.power;
 
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.car.Car;
 import android.car.CarManagerBase;
@@ -34,8 +35,8 @@
  */
 @SystemApi
 public class CarPowerManager extends CarManagerBase {
-    private final static boolean DBG = false;
-    private final static String TAG = "CarPowerManager";
+    private static final boolean DBG = false;
+    private static final String TAG = CarPowerManager.class.getSimpleName();
 
     private final Object mLock = new Object();
     private final ICarPower mService;
@@ -56,10 +57,15 @@
     public interface CarPowerStateListener {
         /**
          * onStateChanged() states.  These definitions must match the ones located in the native
-         * CarPowerManager:  packages/services/Car/car-lib/native/CarPowerManager/CarPowerManager.h
+         * CarPowerManager:  packages/services/Car/car-lib/native/include/CarPowerManager.h
          */
 
         /**
+         * The current power state is unavailable, unknown, or invalid
+         * @hide
+         */
+        int INVALID = 0;
+        /**
          * Android is up, but vendor is controlling the audio / display
          * @hide
          */
@@ -162,6 +168,20 @@
     }
 
     /**
+     * Returns the current power state
+     * @return One of the values defined in {@link CarPowerStateListener}
+     * @hide
+     */
+    @RequiresPermission(Car.PERMISSION_CAR_POWER)
+    public int getPowerState() {
+        try {
+            return mService.getPowerState();
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, CarPowerStateListener.INVALID);
+        }
+    }
+
+    /**
      * Sets a listener to receive power state changes. Only one listener may be set at a
      * time for an instance of CarPowerManager.
      * The listener is assumed to completely handle the 'onStateChanged' before returning.
@@ -195,7 +215,7 @@
      * @hide
      */
     public void setListenerWithCompletion(CarPowerStateListenerWithCompletion listener) {
-        synchronized(mLock) {
+        synchronized (mLock) {
             if (mListener != null || mListenerWithCompletion != null) {
                 throw new IllegalStateException("Listener must be cleared first");
             }
@@ -220,14 +240,18 @@
                             future = mFuture;
                         }
                         // Notify user that the state has changed and supply a future
-                        listenerWithCompletion.onStateChanged(state, future);
+                        if (listenerWithCompletion != null) {
+                            listenerWithCompletion.onStateChanged(state, future);
+                        }
                     } else {
                         CarPowerStateListener listener;
                         synchronized (mLock) {
                             listener = mListener;
                         }
                         // Notify the user without supplying a future
-                        listener.onStateChanged(state);
+                        if (listener != null) {
+                            listener.onStateChanged(state);
+                        }
                     }
                 }
             };
diff --git a/car-lib/src/android/car/hardware/power/ICarPower.aidl b/car-lib/src/android/car/hardware/power/ICarPower.aidl
index 581e736..505b075 100644
--- a/car-lib/src/android/car/hardware/power/ICarPower.aidl
+++ b/car-lib/src/android/car/hardware/power/ICarPower.aidl
@@ -31,4 +31,6 @@
     void scheduleNextWakeupTime(int seconds) = 4;
 
     void registerListenerWithCompletion(in ICarPowerStateListener listener) = 5;
+
+    int getPowerState() = 6;
 }
diff --git a/car-lib/src/android/car/hardware/property/CarInternalErrorException.java b/car-lib/src/android/car/hardware/property/CarInternalErrorException.java
new file mode 100644
index 0000000..7fc3f52
--- /dev/null
+++ b/car-lib/src/android/car/hardware/property/CarInternalErrorException.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.hardware.property;
+
+import static java.lang.Integer.toHexString;
+
+/**
+ * Exception thrown when something unexpected happened in cars.
+ */
+public class CarInternalErrorException extends RuntimeException {
+    CarInternalErrorException(int property, int areaId) {
+        super("Property 0x" + toHexString(property) + " with area: " + toHexString(areaId)
+                + " raised an internal error in cars.");
+    }
+}
diff --git a/car-lib/src/android/car/hardware/property/CarPropertyEvent.java b/car-lib/src/android/car/hardware/property/CarPropertyEvent.java
index 4cb7e92..4d5498d 100644
--- a/car-lib/src/android/car/hardware/property/CarPropertyEvent.java
+++ b/car-lib/src/android/car/hardware/property/CarPropertyEvent.java
@@ -25,11 +25,15 @@
 public class CarPropertyEvent implements Parcelable {
     public static final int PROPERTY_EVENT_PROPERTY_CHANGE = 0;
     public static final int PROPERTY_EVENT_ERROR = 1;
-
     /**
      * EventType of this message
      */
     private final int mEventType;
+
+    /**
+     * ErrorCode of this message.
+     */
+    private final @CarPropertyManager.CarSetPropertyErrorCode int mErrorCode;
     private final CarPropertyValue<?> mCarPropertyValue;
 
     // Use it as default value for error events.
@@ -38,12 +42,16 @@
     /**
      * @return EventType field
      */
-    public int getEventType() { return mEventType; }
+    public int getEventType() {
+        return mEventType;
+    }
 
     /**
      * Returns {@link CarPropertyValue} associated with this event.
      */
-    public CarPropertyValue<?> getCarPropertyValue() { return mCarPropertyValue; }
+    public CarPropertyValue<?> getCarPropertyValue() {
+        return mCarPropertyValue;
+    }
 
     @Override
     public int describeContents() {
@@ -53,51 +61,75 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mEventType);
+        dest.writeInt(mErrorCode);
         dest.writeParcelable(mCarPropertyValue, flags);
     }
 
-    public static final Parcelable.Creator<CarPropertyEvent> CREATOR
-            = new Parcelable.Creator<CarPropertyEvent>() {
+    public static final Parcelable.Creator<CarPropertyEvent> CREATOR =
+            new Parcelable.Creator<CarPropertyEvent>() {
+
+        @Override
         public CarPropertyEvent createFromParcel(Parcel in) {
             return new CarPropertyEvent(in);
         }
 
+        @Override
         public CarPropertyEvent[] newArray(int size) {
             return new CarPropertyEvent[size];
         }
-    };
+        };
 
     /**
      * Constructor for {@link CarPropertyEvent}.
      */
     public CarPropertyEvent(int eventType, @NonNull CarPropertyValue<?> carPropertyValue) {
         mEventType  = eventType;
+        mErrorCode = CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN;
         mCarPropertyValue = carPropertyValue;
     }
 
     /**
+     * Constructor for {@link CarPropertyEvent} with an error code.
+     */
+    public CarPropertyEvent(int eventType, @NonNull CarPropertyValue<?> carPropertyValue,
+            @CarPropertyManager.CarSetPropertyErrorCode int errorCode) {
+        mEventType  = eventType;
+        mErrorCode = errorCode;
+        mCarPropertyValue = carPropertyValue;
+    }
+
+
+    /**
      * Constructor for {@link CarPropertyEvent} when it is an error event.
      *
      * The status of {@link CarPropertyValue} should be {@link CarPropertyValue#STATUS_ERROR}.
      * In {@link CarPropertyManager}, the value of {@link CarPropertyValue} will be dropped.
      */
-    public static CarPropertyEvent createErrorEvent(int propertyId, int areaId) {
-        // valueWithErrorCode will not be propagated to listeners
+    public static CarPropertyEvent createErrorEventWithErrorCode(int propertyId, int areaId,
+            @CarPropertyManager.CarSetPropertyErrorCode int errorCode) {
         CarPropertyValue<Integer> valueWithErrorCode = new CarPropertyValue<>(propertyId, areaId,
-                    CarPropertyValue.STATUS_ERROR, 0, ERROR_EVENT_VALUE);
-        return new CarPropertyEvent(PROPERTY_EVENT_ERROR, valueWithErrorCode);
+                CarPropertyValue.STATUS_ERROR, 0, ERROR_EVENT_VALUE);
+        CarPropertyEvent event = new CarPropertyEvent(PROPERTY_EVENT_ERROR, valueWithErrorCode,
+                errorCode);
+        return event;
+    }
+
+    public @CarPropertyManager.CarSetPropertyErrorCode int getErrorCode() {
+        return mErrorCode;
     }
 
     private CarPropertyEvent(Parcel in) {
         mEventType  = in.readInt();
+        mErrorCode = in.readInt();
         mCarPropertyValue = in.readParcelable(CarPropertyValue.class.getClassLoader());
     }
 
     @Override
     public String toString() {
-        return "CarPropertyEvent{" +
-                "mEventType=" + mEventType +
-                ", mCarPropertyValue=" + mCarPropertyValue +
-                '}';
+        return "CarPropertyEvent{"
+                + "mEventType=" + mEventType
+                + ", mErrorCode=" + mErrorCode
+                + ", mCarPropertyValue=" + mCarPropertyValue
+                + '}';
     }
 }
diff --git a/car-lib/src/android/car/hardware/property/CarPropertyManager.java b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
index be4766b..ce51701 100644
--- a/car-lib/src/android/car/hardware/property/CarPropertyManager.java
+++ b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
@@ -19,14 +19,19 @@
 import static java.lang.Integer.toHexString;
 
 import android.annotation.FloatRange;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.car.Car;
 import android.car.CarManagerBase;
+import android.car.VehicleAreaType;
+import android.car.VehiclePropertyIds;
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.CarPropertyValue;
+import android.os.Build;
 import android.os.Handler;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -34,6 +39,8 @@
 import com.android.car.internal.CarRatedFloatListeners;
 import com.android.car.internal.SingleMessageHandler;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
@@ -51,6 +58,7 @@
     private static final int MSG_GENERIC_EVENT = 0;
     private final SingleMessageHandler<CarPropertyEvent> mHandler;
     private final ICarProperty mService;
+    private final int mAppTargetSdk;
 
     private CarPropertyEventListenerToService mCarPropertyEventToService;
 
@@ -72,11 +80,35 @@
         void onChangeEvent(CarPropertyValue value);
 
         /**
-         * Called when an error is detected with a property
+         * Called when an error is detected when setting a property.
+         *
          * @param propId Property ID which is detected an error.
          * @param zone Zone which is detected an error.
+         *
+         * @see CarPropertyEventCallback#onErrorEvent(int, int, int)
          */
         void onErrorEvent(int propId, int zone);
+
+        /**
+         * Called when an error is detected when setting a property.
+         *
+         * <p>Clients which changed the property value in the areaId most recently will receive
+         * this callback. If multiple clients set a property for the same area id simultaneously,
+         * which one takes precedence is undefined. Typically, the last set operation
+         * (in the order that they are issued to car's ECU) overrides the previous set operations.
+         * The delivered error reflects the error happened in the last set operation.
+         *
+         * @param propId Property ID which is detected an error.
+         * @param areaId AreaId which is detected an error.
+         * @param errorCode Error code is raised in the car.
+         */
+        default void onErrorEvent(int propId, int areaId, @CarSetPropertyErrorCode int errorCode) {
+            if (DBG) {
+                Log.d(TAG, "onErrorEvent propertyId: 0x" + toHexString(propId) + " areaId:0x"
+                        + toHexString(areaId) + " ErrorCode: " + errorCode);
+            }
+            onErrorEvent(propId, areaId);
+        }
     }
 
     /** Read ON_CHANGE sensors */
@@ -90,6 +122,44 @@
     /** Read sensors at the rate of 100 hertz */
     public static final float SENSOR_RATE_FASTEST = 100f;
 
+
+
+    /**
+     * Status to indicate that set operation failed. Try it again.
+     */
+    public static final int CAR_SET_PROPERTY_ERROR_CODE_TRY_AGAIN = 1;
+
+    /**
+     * Status to indicate that set operation failed because of an invalid argument.
+     */
+    public static final int CAR_SET_PROPERTY_ERROR_CODE_INVALID_ARG = 2;
+
+    /**
+     * Status to indicate that set operation failed because the property is not available.
+     */
+    public static final int CAR_SET_PROPERTY_ERROR_CODE_PROPERTY_NOT_AVAILABLE = 3;
+
+    /**
+     * Status to indicate that set operation failed because car denied access to the property.
+     */
+    public static final int CAR_SET_PROPERTY_ERROR_CODE_ACCESS_DENIED = 4;
+
+    /**
+     * Status to indicate that set operation failed because of an general error in cars.
+     */
+    public static final int CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN = 5;
+
+    /** @hide */
+    @IntDef(prefix = {"CAR_SET_PROPERTY_ERROR_CODE_"}, value = {
+            CAR_SET_PROPERTY_ERROR_CODE_TRY_AGAIN,
+            CAR_SET_PROPERTY_ERROR_CODE_INVALID_ARG,
+            CAR_SET_PROPERTY_ERROR_CODE_PROPERTY_NOT_AVAILABLE,
+            CAR_SET_PROPERTY_ERROR_CODE_ACCESS_DENIED,
+            CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CarSetPropertyErrorCode {}
+
     /**
      * Get an instance of the CarPropertyManager.
      *
@@ -101,15 +171,17 @@
     public CarPropertyManager(Car car, @NonNull ICarProperty service) {
         super(car);
         mService = service;
+        mAppTargetSdk = getContext().getApplicationInfo().targetSdkVersion;
         try {
             List<CarPropertyConfig> configs = mService.getPropertyList();
             for (CarPropertyConfig carPropertyConfig : configs) {
                 mConfigMap.put(carPropertyConfig.getPropertyId(), carPropertyConfig);
             }
-        } catch (Exception e) {
+        } catch (RemoteException e) {
             Log.e(TAG, "getPropertyList exception ", e);
             throw new RuntimeException(e);
         }
+
         Handler eventHandler = getEventHandler();
         if (eventHandler == null) {
             mHandler = null;
@@ -308,6 +380,7 @@
     public List<CarPropertyConfig> getPropertyList(@NonNull ArraySet<Integer> propertyIds) {
         List<CarPropertyConfig> configs = new ArrayList<>();
         for (int propId : propertyIds) {
+            checkSupportedProperty(propId);
             CarPropertyConfig config = mConfigMap.get(propId);
             if (config != null) {
                 configs.add(config);
@@ -317,6 +390,51 @@
     }
 
     /**
+     * Get CarPropertyConfig by property Id.
+     *
+     * @param propId Property ID
+     * @return {@link CarPropertyConfig} for the selected property.
+     * Null if the property is not available.
+     */
+    @Nullable
+    public CarPropertyConfig<?> getCarPropertyConfig(int propId) {
+        checkSupportedProperty(propId);
+
+        return  mConfigMap.get(propId);
+    }
+
+    /**
+     * Returns areaId contains the seletcted area for the property.
+     *
+     * @param propId Property ID
+     * @param area Area enum such as Enums in {@link android.car.VehicleAreaSeat}.
+     * @throws IllegalArgumentException if the property is not available in the vehicle for
+     * the selected area.
+     * @return AreaId contains the selected area for the property.
+     */
+    public int getAreaId(int propId, int area) {
+        checkSupportedProperty(propId);
+
+        CarPropertyConfig<?> propConfig = getCarPropertyConfig(propId);
+        if (propConfig == null) {
+            throw new IllegalArgumentException("The property propId: 0x" + toHexString(propId)
+                    + " is not available");
+        }
+        // For the global property, areaId is 0
+        if (propConfig.isGlobalProperty()) {
+            return VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
+        }
+        for (int areaId : propConfig.getAreaIds()) {
+            if ((area & areaId) == area) {
+                return areaId;
+            }
+        }
+
+        throw new IllegalArgumentException("The property propId: 0x" + toHexString(propId)
+                + " is not available at the area: 0x" + toHexString(area));
+    }
+
+    /**
      * Return read permission string for given property ID.
      *
      * @param propId Property ID to query
@@ -328,6 +446,7 @@
         if (DBG) {
             Log.d(TAG, "getReadPermission, propId: 0x" + toHexString(propId));
         }
+        checkSupportedProperty(propId);
         try {
             return mService.getReadPermission(propId);
         } catch (RemoteException e) {
@@ -347,6 +466,7 @@
         if (DBG) {
             Log.d(TAG, "getWritePermission, propId: 0x" + toHexString(propId));
         }
+        checkSupportedProperty(propId);
         try {
             return mService.getWritePermission(propId);
         } catch (RemoteException e) {
@@ -362,6 +482,7 @@
      * @return true if STATUS_AVAILABLE, false otherwise (eg STATUS_UNAVAILABLE)
      */
     public boolean isPropertyAvailable(int propId, int area) {
+        checkSupportedProperty(propId);
         try {
             CarPropertyValue propValue = mService.getProperty(propId, area);
             return (propValue != null)
@@ -373,12 +494,15 @@
 
     /**
      * Returns value of a bool property
+     * <p> This method may take couple seconds to complete, so it needs to be called from an
+     * non-main thread.
      *
      * @param prop Property ID to get
      * @param area Area of the property to get
      * @return value of a bool property.
      */
     public boolean getBooleanProperty(int prop, int area) {
+        checkSupportedProperty(prop);
         CarPropertyValue<Boolean> carProp = getProperty(Boolean.class, prop, area);
         return carProp != null ? carProp.getValue() : false;
     }
@@ -386,10 +510,14 @@
     /**
      * Returns value of a float property
      *
+     * <p> This method may take couple seconds to complete, so it needs to be called from an
+     * non-main thread.
+     *
      * @param prop Property ID to get
      * @param area Area of the property to get
      */
     public float getFloatProperty(int prop, int area) {
+        checkSupportedProperty(prop);
         CarPropertyValue<Float> carProp = getProperty(Float.class, prop, area);
         return carProp != null ? carProp.getValue() : 0f;
     }
@@ -397,10 +525,13 @@
     /**
      * Returns value of a integer property
      *
+     * <p> This method may take couple seconds to complete, so it needs to be called form an
+     * non-main thread.
      * @param prop Property ID to get
      * @param area Zone of the property to get
      */
     public int getIntProperty(int prop, int area) {
+        checkSupportedProperty(prop);
         CarPropertyValue<Integer> carProp = getProperty(Integer.class, prop, area);
         return carProp != null ? carProp.getValue() : 0;
     }
@@ -408,11 +539,15 @@
     /**
      * Returns value of a integer array property
      *
+     * <p> This method may take couple seconds to complete, so it needs to be called from an
+     * non-main thread.
+     *
      * @param prop Property ID to get
      * @param area Zone of the property to get
      */
     @NonNull
     public int[] getIntArrayProperty(int prop, int area) {
+        checkSupportedProperty(prop);
         CarPropertyValue<Integer[]> carProp = getProperty(Integer[].class, prop, area);
         return carProp != null ? toIntArray(carProp.getValue()) : new int[0];
     }
@@ -429,10 +564,39 @@
     /**
      * Return CarPropertyValue
      *
+     * <p> This method may take couple seconds to complete, so it needs to be called from an
+     * non-main thread.
+     *
+     * <p> Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} equal
+     * or later than {@link Build.VERSION_CODES#R} will receive the following exceptions when
+     * request is failed.
+     * <ul>
+     *     <li>{@link CarInternalErrorException}
+     *     <li>{@link PropertyAccessDeniedSecurityException}
+     *     <li>{@link PropertyNotAvailableAndRetryException}
+     *     <li>{@link PropertyNotAvailableException}
+     *     <li>{@link IllegalArgumentException}
+     * </ul>
+     * <p> Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion}
+     * earlier than {@link Build.VERSION_CODES#R} will receive the following exceptions when request
+     * is failed.
+     * <ul>
+     *     <li>{@link IllegalStateException} when there is an error detected in cars.
+     *     <li>{@link IllegalArgumentException} when the property in the areaId is not supplied.
+     * </ul>
+     *
      * @param clazz The class object for the CarPropertyValue
      * @param propId Property ID to get
      * @param areaId Zone of the property to get
-     * @throws IllegalArgumentException if there is invalid property type.
+     *
+     * @throws {@link CarInternalErrorException} when there is an error detected in cars.
+     * @throws {@link PropertyAccessDeniedSecurityException} when cars denied the access of the
+     * property.
+     * @throws {@link PropertyNotAvailableAndRetryException} when the property is temporarily
+     * not available and likely that retrying will be successful.
+     * @throws {@link PropertyNotAvailableException} when the property is temporarily not available.
+     * @throws {@link IllegalArgumentException} when the property in the areaId is not supplied.
+     *
      * @return CarPropertyValue. Null if property's id is invalid.
      */
     @SuppressWarnings("unchecked")
@@ -442,6 +606,9 @@
             Log.d(TAG, "getProperty, propId: 0x" + toHexString(propId)
                     + ", areaId: 0x" + toHexString(areaId) + ", class: " + clazz);
         }
+
+        checkSupportedProperty(propId);
+
         try {
             CarPropertyValue<E> propVal = mService.getProperty(propId, areaId);
             if (propVal != null && propVal.getValue() != null) {
@@ -454,45 +621,151 @@
             return propVal;
         } catch (RemoteException e) {
             return handleRemoteExceptionFromCarService(e, null);
+        } catch (ServiceSpecificException e) {
+            // For pre R apps, throws the old exceptions.
+            if (mAppTargetSdk < Build.VERSION_CODES.R) {
+                if (e.errorCode == VehicleHalStatusCode.STATUS_TRY_AGAIN) {
+                    return null;
+                } else {
+                    throw new IllegalStateException(String.format("Failed to get property: 0x%x, "
+                            + "areaId: 0x%x", propId, areaId));
+                }
+            }
+            return handleCarServiceSpecificException(e.errorCode, propId, areaId, null);
         }
     }
 
     /**
      * Query CarPropertyValue with property id and areaId.
+     *
+     * <p> This method may take couple seconds to complete, so it needs to be called from an
+     * non-main thread.
+     *
+     * <p> Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} equal
+     * or later than {@link Build.VERSION_CODES#R} will receive the following exceptions when
+     * request is failed.
+     * <ul>
+     *     <li>{@link CarInternalErrorException}
+     *     <li>{@link PropertyAccessDeniedSecurityException}
+     *     <li>{@link PropertyNotAvailableAndRetryException}
+     *     <li>{@link PropertyNotAvailableException}
+     *     <li>{@link IllegalArgumentException}
+     * </ul>
+     * <p> Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion}
+     * earlier than {@link Build.VERSION_CODES#R} will receive the following exceptions when request
+     * is failed.
+     * <ul>
+     *     <li>{@link IllegalStateException} when there is an error detected in cars.
+     *     <li>{@link IllegalArgumentException} when the property in the areaId is not supplied.
+     * </ul>
+     *
      * @param propId Property Id
      * @param areaId areaId
-     * @param <E>
+     * @param <E> Value type of the property
+     *
+     * @throws {@link CarInternalErrorException} when there is an error detected in cars.
+     * @throws {@link PropertyAccessDeniedSecurityException} when cars denied the access of the
+     * property.
+     * @throws {@link PropertyNotAvailableAndRetryException} when the property is temporarily
+     * not available and likely that retrying will be successful.
+     * @throws {@link PropertyNotAvailableException} when the property is temporarily not available.
+     * @throws {@link IllegalArgumentException} when the property in the areaId is not supplied.
+     *
      * @return CarPropertyValue. Null if property's id is invalid.
      */
     @Nullable
     public <E> CarPropertyValue<E> getProperty(int propId, int areaId) {
+        checkSupportedProperty(propId);
+
         try {
             CarPropertyValue<E> propVal = mService.getProperty(propId, areaId);
             return propVal;
         } catch (RemoteException e) {
             return handleRemoteExceptionFromCarService(e, null);
+        } catch (ServiceSpecificException e) {
+            if (mAppTargetSdk < Build.VERSION_CODES.R) {
+                if (e.errorCode == VehicleHalStatusCode.STATUS_TRY_AGAIN) {
+                    return null;
+                } else {
+                    throw new IllegalStateException(String.format("Failed to get property: 0x%x, "
+                            + "areaId: 0x%x", propId, areaId));
+                }
+            }
+            return handleCarServiceSpecificException(e.errorCode, propId, areaId, null);
         }
     }
 
     /**
      * Set value of car property by areaId.
+     *
+     * <p>If multiple clients set a property for the same area id simultaneously, which one takes
+     * precedence is undefined. Typically, the last set operation (in the order that they are issued
+     * to the car's ECU) overrides the previous set operations.
+     *
+     * <p> This method may take couple seconds to complete, so it needs to be called form an
+     * non-main thread.
+     *
+     * <p> Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} equal
+     * or later than {@link Build.VERSION_CODES#R} will receive the following exceptions when
+     * request is failed.
+     * <ul>
+     *     <li>{@link CarInternalErrorException}
+     *     <li>{@link PropertyAccessDeniedSecurityException}
+     *     <li>{@link PropertyNotAvailableAndRetryException}
+     *     <li>{@link PropertyNotAvailableException}
+     *     <li>{@link IllegalArgumentException}
+     * </ul>
+     * <p> Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion}
+     * earlier than {@link Build.VERSION_CODES#R} will receive the following exceptions when request
+     * is failed.
+     * <ul>
+     *     <li>{@link RuntimeException} when the property is temporarily not available.
+     *     <li>{@link IllegalStateException} when there is an error detected in cars.
+     *     <li>{@link IllegalArgumentException} when the property in the areaId is not supplied
+     * </ul>
+     *
      * @param clazz The class object for the CarPropertyValue
      * @param propId Property ID
      * @param areaId areaId
      * @param val Value of CarPropertyValue
      * @param <E> data type of the given property, for example property that was
      * defined as {@code VEHICLE_VALUE_TYPE_INT32} in vehicle HAL could be accessed using
-     * {@code Integer.class}
+     * {@code Integer.class}.
+     *
+     * @throws {@link CarInternalErrorException} when there is an error detected in cars.
+     * @throws {@link PropertyAccessDeniedSecurityException} when cars denied the access of the
+     * property.
+     * @throws {@link PropertyNotAvailableException} when the property is temporarily not available.
+     * @throws {@link PropertyNotAvailableAndRetryException} when the property is temporarily
+     * not available and likely that retrying will be successful.
+     * @throws {@link IllegalStateException} when get an unexpected error code.
+     * @throws {@link IllegalArgumentException} when the property in the areaId is not supplied.
      */
     public <E> void setProperty(@NonNull Class<E> clazz, int propId, int areaId, @NonNull E val) {
         if (DBG) {
             Log.d(TAG, "setProperty, propId: 0x" + toHexString(propId)
                     + ", areaId: 0x" + toHexString(areaId) + ", class: " + clazz + ", val: " + val);
         }
+        checkSupportedProperty(propId);
         try {
-            mService.setProperty(new CarPropertyValue<>(propId, areaId, val));
+            if (mCarPropertyEventToService == null) {
+                mCarPropertyEventToService = new CarPropertyEventListenerToService(this);
+            }
+            mService.setProperty(new CarPropertyValue<>(propId, areaId, val),
+                    mCarPropertyEventToService);
         } catch (RemoteException e) {
             handleRemoteExceptionFromCarService(e);
+        } catch (ServiceSpecificException e) {
+            if (mAppTargetSdk < Build.VERSION_CODES.R) {
+                if (e.errorCode == VehicleHalStatusCode.STATUS_TRY_AGAIN) {
+                    throw new RuntimeException(String.format("Failed to set property: 0x%x, "
+                            + "areaId: 0x%x", propId, areaId));
+                } else {
+                    throw new IllegalStateException(String.format("Failed to set property: 0x%x, "
+                            + "areaId: 0x%x", propId, areaId));
+                }
+            }
+            handleCarServiceSpecificException(e.errorCode, propId, areaId, null);
         }
     }
 
@@ -500,6 +773,9 @@
      * Modifies a property.  If the property modification doesn't occur, an error event shall be
      * generated and propagated back to the application.
      *
+     * <p> This method may take couple seconds to complete, so it needs to be called from an
+     * non-main thread.
+     *
      * @param prop Property ID to modify
      * @param areaId AreaId to apply the modification.
      * @param val Value to set
@@ -511,6 +787,9 @@
     /**
      * Set float value of property
      *
+     * <p> This method may take couple seconds to complete, so it needs to be called from an
+     * non-main thread.
+     *
      * @param prop Property ID to modify
      * @param areaId AreaId to apply the modification
      * @param val Value to set
@@ -522,6 +801,9 @@
     /**
      * Set int value of property
      *
+     * <p> This method may take couple seconds to complete, so it needs to be called from an
+     * non-main thread.
+     *
      * @param prop Property ID to modify
      * @param areaId AreaId to apply the modification
      * @param val Value to set
@@ -530,8 +812,48 @@
         setProperty(Integer.class, prop, areaId, val);
     }
 
+    // Handles ServiceSpecificException in CarService for R and later version.
+    private <T> T handleCarServiceSpecificException(int errorCode, int propId, int areaId,
+            T returnValue) {
+        switch (errorCode) {
+            case VehicleHalStatusCode.STATUS_NOT_AVAILABLE:
+                throw new PropertyNotAvailableException(propId, areaId);
+            case VehicleHalStatusCode.STATUS_TRY_AGAIN:
+                throw new PropertyNotAvailableAndRetryException(propId, areaId);
+            case VehicleHalStatusCode.STATUS_ACCESS_DENIED:
+                throw new PropertyAccessDeniedSecurityException(propId, areaId);
+            case VehicleHalStatusCode.STATUS_INTERNAL_ERROR:
+                throw new CarInternalErrorException(propId, areaId);
+            default:
+                Log.e(TAG, "Invalid errorCode: " + errorCode + " in CarService");
+        }
+        return returnValue;
+    }
 
-    private class CarPropertyListeners extends CarRatedFloatListeners<CarPropertyEventCallback> {
+    /**
+     * Checks if the given property can be exposed to by this manager.
+     *
+     * <p>For example, properties related to user management should only be manipulated by
+     * {@code UserHalService}.
+     *
+     * @param propId property to be checked
+     *
+     * @throws IllegalArgumentException if the property is not supported.
+     */
+    private void checkSupportedProperty(int propId) {
+        switch (propId) {
+            case VehiclePropertyIds.INITIAL_USER_INFO:
+            case VehiclePropertyIds.SWITCH_USER:
+            case VehiclePropertyIds.CREATE_USER:
+            case VehiclePropertyIds.REMOVE_USER:
+            case VehiclePropertyIds.USER_IDENTIFICATION_ASSOCIATION:
+                throw new IllegalArgumentException("Unsupported property: "
+                        + VehiclePropertyIds.toString(propId) + " (" + propId + ")");
+        }
+    }
+
+    private final class CarPropertyListeners
+            extends CarRatedFloatListeners<CarPropertyEventCallback> {
         CarPropertyListeners(float rate) {
             super(rate);
         }
@@ -540,7 +862,9 @@
             long updateTime = event.getCarPropertyValue().getTimestamp();
             int areaId = event.getCarPropertyValue().getAreaId();
             if (!needUpdateForAreaId(areaId, updateTime)) {
-                Log.w(TAG, "dropping old property data");
+                if (DBG) {
+                    Log.w(TAG, "Dropping a stale event: " + event.toString());
+                }
                 return;
             }
             List<CarPropertyEventCallback> listeners;
@@ -570,9 +894,13 @@
                         Log.d(TAG, new StringBuilder().append("onErrorEvent for ")
                                         .append("property: ").append(value.getPropertyId())
                                         .append(" areaId: ").append(value.getAreaId())
+                                        .append(" errorCode: ").append(event.getErrorCode())
                                         .toString());
                     }
-                    listener.onErrorEvent(value.getPropertyId(), value.getAreaId());
+
+                    listener.onErrorEvent(value.getPropertyId(), value.getAreaId(),
+                            event.getErrorCode());
+
                 }
             });
         }
diff --git a/car-lib/src/android/car/hardware/property/ICarProperty.aidl b/car-lib/src/android/car/hardware/property/ICarProperty.aidl
index ab5ad7e..f2496a2 100644
--- a/car-lib/src/android/car/hardware/property/ICarProperty.aidl
+++ b/car-lib/src/android/car/hardware/property/ICarProperty.aidl
@@ -33,7 +33,7 @@
 
     CarPropertyValue getProperty(int prop, int zone) = 3;
 
-    void setProperty(in CarPropertyValue prop) = 4;
+    void setProperty(in CarPropertyValue prop, in ICarPropertyEventListener callback) = 4;
 
     String getReadPermission(int propId) = 5;
 
diff --git a/car-lib/src/android/car/hardware/property/PropertyAccessDeniedSecurityException.java b/car-lib/src/android/car/hardware/property/PropertyAccessDeniedSecurityException.java
new file mode 100644
index 0000000..dcfb284
--- /dev/null
+++ b/car-lib/src/android/car/hardware/property/PropertyAccessDeniedSecurityException.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.hardware.property;
+
+import static java.lang.Integer.toHexString;
+
+/**
+ * Exception thrown when cars denied the access of properties.
+ */
+public class PropertyAccessDeniedSecurityException extends SecurityException {
+    PropertyAccessDeniedSecurityException(int property, int areaId) {
+        super("Cars denied the access of property 0x"
+                + toHexString(property) + " in area: " + toHexString(areaId));
+    }
+}
diff --git a/car-lib/src/android/car/hardware/property/PropertyNotAvailableAndRetryException.java b/car-lib/src/android/car/hardware/property/PropertyNotAvailableAndRetryException.java
new file mode 100644
index 0000000..a04b9b2
--- /dev/null
+++ b/car-lib/src/android/car/hardware/property/PropertyNotAvailableAndRetryException.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.hardware.property;
+
+import static java.lang.Integer.toHexString;
+
+/**
+ * Exception thrown when device that associated with the vehicle property is temporarily
+ * not available. It's likely that retrying will be successful.
+ */
+public class PropertyNotAvailableAndRetryException extends IllegalStateException {
+    PropertyNotAvailableAndRetryException(int property, int areaId) {
+        super("Property 0x" + toHexString(property) + " with area: " + toHexString(areaId)
+                + " is temporarily not available. Try the operation later.");
+    }
+}
diff --git a/car-lib/src/android/car/hardware/property/PropertyNotAvailableException.java b/car-lib/src/android/car/hardware/property/PropertyNotAvailableException.java
new file mode 100644
index 0000000..1edfd67
--- /dev/null
+++ b/car-lib/src/android/car/hardware/property/PropertyNotAvailableException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.hardware.property;
+
+import static java.lang.Integer.toHexString;
+
+/**
+ * Exception thrown when device that associated with the vehicle property is temporarily
+ * not available because of the current state of cars. For example, applications try to change
+ * HVAC fan speed when the HVAC system is power off.
+ */
+public class PropertyNotAvailableException extends IllegalStateException {
+    PropertyNotAvailableException(int property, int areaId) {
+        super("Property 0x" + toHexString(property) + " with area: " + toHexString(areaId)
+                + " is temporarily not available because the current state of cars.");
+    }
+}
diff --git a/car-lib/src/android/car/hardware/property/VehicleHalStatusCode.java b/car-lib/src/android/car/hardware/property/VehicleHalStatusCode.java
new file mode 100644
index 0000000..983c2ad
--- /dev/null
+++ b/car-lib/src/android/car/hardware/property/VehicleHalStatusCode.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.hardware.property;
+
+/**
+ * Error codes used in vehicle HAL interface.
+ * @hide
+ */
+public final class VehicleHalStatusCode {
+
+    /** No error detected in HAL.*/
+    public static final int STATUS_OK = 0;
+    /** Try again. */
+    public static final int STATUS_TRY_AGAIN = 1;
+    /** Invalid argument provide. */
+    public static final int STATUS_INVALID_ARG = 2;
+    /**
+     * This code must be returned when device that associated with the vehicle
+     * property is not available. For example, when client tries to set HVAC
+     * temperature when the whole HVAC unit is turned OFF.
+     */
+    public static final int STATUS_NOT_AVAILABLE = 3;
+    /** Access denied */
+    public static final int STATUS_ACCESS_DENIED = 4;
+    /** Something unexpected has happened in Vehicle HAL */
+    public static final int STATUS_INTERNAL_ERROR = 5;
+
+    private VehicleHalStatusCode() {}
+}
diff --git a/car-lib/src/android/car/hardware/property/VehicleVendorPermission.java b/car-lib/src/android/car/hardware/property/VehicleVendorPermission.java
new file mode 100644
index 0000000..3ad6b9c
--- /dev/null
+++ b/car-lib/src/android/car/hardware/property/VehicleVendorPermission.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.hardware.property;
+
+import android.annotation.SystemApi;
+
+/**
+ * VehicleVendorPermission list all vendor permissions for vehicle. Vendors can map the vendor
+ * properties with any vendor permission.
+ * @hide
+ */
+@SystemApi
+public final class VehicleVendorPermission {
+
+    // permissions for the property related with window
+    public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_WINDOW =
+            "android.car.permission.GET_CAR_VENDOR_CATEGORY_WINDOW";
+    public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_WINDOW =
+            "android.car.permission.SET_CAR_VENDOR_CATEGORY_WINDOW";
+
+    // permissions for the property related with door
+    public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_DOOR =
+            "android.car.permission.GET_CAR_VENDOR_CATEGORY_DOOR";
+    public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_DOOR =
+            "android.car.permission.SET_CAR_VENDOR_CATEGORY_DOOR";
+
+    // permissions for the property related with seat
+    public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_SEAT =
+            "android.car.permission.GET_CAR_VENDOR_CATEGORY_SEAT";
+    public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_SEAT =
+            "android.car.permission.SET_CAR_VENDOR_CATEGORY_SEAT";
+
+    // permissions for the property related with mirror
+    public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_MIRROR =
+            "android.car.permission.GET_CAR_VENDOR_CATEGORY_MIRROR";
+    public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_MIRROR =
+            "android.car.permission.SET_CAR_VENDOR_CATEGORY_MIRROR";
+
+    // permissions for the property related with car's information
+    public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_INFO =
+            "android.car.permission.GET_CAR_VENDOR_CATEGORY_INFO";
+    public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_INFO =
+            "android.car.permission.SET_CAR_VENDOR_CATEGORY_INFO";
+
+    // permissions for the property related with car's engine
+    public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_ENGINE =
+            "android.car.permission.GET_CAR_VENDOR_CATEGORY_ENGINE";
+    public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_ENGINE =
+            "android.car.permission.SET_CAR_VENDOR_CATEGORY_ENGINE";
+
+    // permissions for the property related with car's HVAC
+    public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_HVAC =
+            "android.car.permission.GET_CAR_VENDOR_CATEGORY_HVAC";
+    public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_HVAC =
+            "android.car.permission.SET_CAR_VENDOR_CATEGORY_HVAC";
+
+    // permissions for the property related with car's light
+    public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_LIGHT =
+            "android.car.permission.GET_CAR_VENDOR_CATEGORY_LIGHT";
+    public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_LIGHT =
+            "android.car.permission.SET_CAR_VENDOR_CATEGORY_LIGHT";
+
+
+    // permissions reserved for other vendor permission
+    public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_1 =
+            "android.car.permission.GET_CAR_VENDOR_CATEGORY_1";
+    public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_1 =
+            "android.car.permission.SET_CAR_VENDOR_CATEGORY_1";
+    public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_2 =
+            "android.car.permission.GET_CAR_VENDOR_CATEGORY_2";
+    public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_2 =
+            "android.car.permission.SET_CAR_VENDOR_CATEGORY_2";
+    public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_3 =
+            "android.car.permission.GET_CAR_VENDOR_CATEGORY_3";
+    public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_3 =
+            "android.car.permission.SET_CAR_VENDOR_CATEGORY_3";
+    public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_4 =
+            "android.car.permission.GET_CAR_VENDOR_CATEGORY_4";
+    public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_4 =
+            "android.car.permission.SET_CAR_VENDOR_CATEGORY_4";
+    public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_5 =
+            "android.car.permission.GET_CAR_VENDOR_CATEGORY_5";
+    public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_5 =
+            "android.car.permission.SET_CAR_VENDOR_CATEGORY_5";
+    public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_6 =
+            "android.car.permission.GET_CAR_VENDOR_CATEGORY_6";
+    public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_6 =
+            "android.car.permission.SET_CAR_VENDOR_CATEGORY_6";
+    public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_7 =
+            "android.car.permission.GET_CAR_VENDOR_CATEGORY_7";
+    public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_7 =
+            "android.car.permission.SET_CAR_VENDOR_CATEGORY_7";
+    public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_8 =
+            "android.car.permission.GET_CAR_VENDOR_CATEGORY_8";
+    public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_8 =
+            "android.car.permission.SET_CAR_VENDOR_CATEGORY_8";
+    public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_9 =
+            "android.car.permission.GET_CAR_VENDOR_CATEGORY_9";
+    public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_9 =
+            "android.car.permission.SET_CAR_VENDOR_CATEGORY_9";
+    public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_10 =
+            "android.car.permission.GET_CAR_VENDOR_CATEGORY_10";
+    public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_10 =
+            "android.car.permission.SET_CAR_VENDOR_CATEGORY_10";
+
+    private VehicleVendorPermission() {}
+
+}
diff --git a/car-lib/src/android/car/input/CarInputManager.java b/car-lib/src/android/car/input/CarInputManager.java
new file mode 100644
index 0000000..dbbf18c
--- /dev/null
+++ b/car-lib/src/android/car/input/CarInputManager.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.input;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.car.Car;
+import android.car.CarManagerBase;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.SparseArray;
+import android.view.KeyEvent;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.ref.WeakReference;
+import java.util.List;
+
+/**
+ * This API allows capturing selected input events.
+ *
+ * @hide
+ */
+public final class CarInputManager extends CarManagerBase {
+
+    /**
+     * Callback for capturing input events.
+     */
+    public interface CarInputCaptureCallback {
+        /**
+         * Key events were captured.
+         */
+        void onKeyEvents(int targetDisplayId, @NonNull List<KeyEvent> keyEvents);
+
+        /**
+         * Rotary events were captured.
+         */
+        void onRotaryEvents(int targetDisplayId, @NonNull List<RotaryEvent> events);
+
+        /**
+         * Capture state for the display has changed due to other client making requests or
+         * releasing capture. Client should check {@code activeInputTypes} for which input types
+         * are currently captured.
+         */
+        void onCaptureStateChanged(int targetDisplayId,
+                @NonNull @InputTypeEnum int[] activeInputTypes);
+    }
+
+    /**
+     * Represents main display for the system.
+     */
+    public static final int TARGET_DISPLAY_TYPE_MAIN = 0;
+
+    /**
+     * Represents cluster display.
+     */
+    public static final int TARGET_DISPLAY_TYPE_CLUSTER = 1;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "TARGET_DISPLAY_TYPE_", value = {
+            TARGET_DISPLAY_TYPE_MAIN,
+            TARGET_DISPLAY_TYPE_CLUSTER,
+    })
+    @Target({ElementType.TYPE_USE})
+    public @interface TargetDisplayTypeEnum {}
+
+    /**
+     * Client will wait for grant if the request is failing due to higher priority client.
+     */
+    public static final int CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT = 0x1;
+
+    /**
+     * Client wants to capture the keys for the whole display. This is only allowed to system
+     * process.
+     *
+     * @hide
+     */
+    public static final int CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY = 0x2;
+
+    /** @hide */
+    @IntDef(flag = true, prefix = { "CAPTURE_REQ_FLAGS_" }, value = {
+            CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT,
+            CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface CaptureRequestFlags {}
+
+    /**
+     * This is special type to cover all INPUT_TYPE_*. This is used for clients using
+     * {@link #CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY} flag.
+     *
+     * @hide
+     */
+    public static final int INPUT_TYPE_ALL_INPUTS = 1;
+
+    /**
+     * This covers rotary input device for navigation.
+     */
+    public static final int INPUT_TYPE_ROTARY_NAVIGATION = 10;
+
+    /**
+     * Volume knob.
+     * TODO (b/151666020): This will be only allowed to system apps later.
+     *
+     * @hide
+     */
+    public static final int INPUT_TYPE_ROTARY_VOLUME = 11;
+
+    /**
+     * This is the group of keys for DPAD.
+     * Included key events are: {@link KeyEvent#KEYCODE_DPAD_UP},
+     * {@link KeyEvent#KEYCODE_DPAD_DOWN}, {@link KeyEvent#KEYCODE_DPAD_LEFT},
+     * {@link KeyEvent#KEYCODE_DPAD_RIGHT}, {@link KeyEvent#KEYCODE_DPAD_CENTER},
+     * {@link KeyEvent#KEYCODE_DPAD_DOWN_LEFT}, {@link KeyEvent#KEYCODE_DPAD_DOWN_RIGHT},
+     * {@link KeyEvent#KEYCODE_DPAD_UP_LEFT}, {@link KeyEvent#KEYCODE_DPAD_UP_RIGHT}
+     */
+    public static final int INPUT_TYPE_DPAD_KEYS = 100;
+
+    /**
+     * This is for all KEYCODE_NAVIGATE_* keys.
+     */
+    public static final int INPUT_TYPE_NAVIGATE_KEYS = 101;
+
+    /**
+     * This is for all KEYCODE_SYSTEM_NAVIGATE_* keys.
+     */
+    public static final int INPUT_TYPE_SYSTEM_NAVIGATE_KEYS = 102;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "INPUT_TYPE_", value = {
+            INPUT_TYPE_ALL_INPUTS,
+            INPUT_TYPE_ROTARY_NAVIGATION,
+            INPUT_TYPE_ROTARY_VOLUME,
+            INPUT_TYPE_DPAD_KEYS,
+            INPUT_TYPE_NAVIGATE_KEYS,
+            INPUT_TYPE_SYSTEM_NAVIGATE_KEYS
+    })
+    @Target({ElementType.TYPE_USE})
+    public @interface InputTypeEnum {}
+
+    /**
+     * The client's request has succeeded and capture will start.
+     */
+    public static final int INPUT_CAPTURE_RESPONSE_SUCCEEDED = 0;
+
+    /**
+     * The client's request has failed due to higher priority client already capturing. If priority
+     * for the clients are the same, last client making request will be allowed to capture.
+     */
+    public static final int INPUT_CAPTURE_RESPONSE_FAILED = 1;
+
+    /**
+     * This is used when client has set {@link #CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT} in
+     * {@code requestFlags} and capturing is blocked due to existing higher priority client.
+     * When the higher priority client stops capturing, this client can capture events after
+     * getting @link CarInputCaptureCallback#onCaptureStateChanged(int, int[])} call.
+     */
+    public static final int INPUT_CAPTURE_RESPONSE_DELAYED = 2;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "INPUT_CAPTURE_RESPONSE_", value = {
+            INPUT_CAPTURE_RESPONSE_SUCCEEDED,
+            INPUT_CAPTURE_RESPONSE_FAILED,
+            INPUT_CAPTURE_RESPONSE_DELAYED
+    })
+    @Target({ElementType.TYPE_USE})
+    public @interface InputCaptureResponseEnum {}
+
+    private final ICarInput mService;
+    private final ICarInputCallback mServiceCallback = new ICarInputCallbackImpl(this);
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private final SparseArray<CarInputCaptureCallback> mCarInputCaptureCallbacks =
+            new SparseArray<>(1);
+
+    /**
+     * @hide
+     */
+    public CarInputManager(Car car, IBinder service) {
+        super(car);
+        mService = ICarInput.Stub.asInterface(service);
+    }
+
+    /**
+     * Requests capturing of input event for the specified display for all requested input types.
+     *
+     * <p>The request can fail if a high priority client is holding it. The client can set
+     * {@link #CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT} in {@code requestFlags} to wait for the
+     * current high priority client to release it.
+     *
+     * <p>If only some of the input types specified are available, the request will either:
+     * <ul>
+     * <li>fail, returning {@link #INPUT_CAPTURE_RESPONSE_FAILED}, or
+     * <li>be deferred, returning {@link #INPUT_CAPTURE_RESPONSE_DELAYED}, if the
+     * {@link #CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT} flag is used.
+     * </ul>
+     *
+     * <p> After {@link #INPUT_CAPTURE_RESPONSE_DELAYED} is returned, no input types are captured
+     * until the client receives a {@link CarInputCaptureCallback#onCaptureStateChanged(int, int[])}
+     * call with valid input types.
+     */
+    @RequiresPermission(android.Manifest.permission.MONITOR_INPUT)
+    @InputCaptureResponseEnum
+    public int requestInputEventCapture(@NonNull CarInputCaptureCallback callback,
+            @TargetDisplayTypeEnum int targetDisplayType,
+            @NonNull @InputTypeEnum int[] inputTypes,
+            @CaptureRequestFlags int requestFlags) {
+        synchronized (mLock) {
+            mCarInputCaptureCallbacks.put(targetDisplayType, callback);
+        }
+        try {
+            return mService.requestInputEventCapture(mServiceCallback, targetDisplayType,
+                    inputTypes, requestFlags);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, INPUT_CAPTURE_RESPONSE_FAILED);
+        }
+    }
+
+    /**
+     * Stops capturing of given display.
+     */
+    public void releaseInputEventCapture(@TargetDisplayTypeEnum int targetDisplayType) {
+        CarInputCaptureCallback callback;
+        synchronized (mLock) {
+            callback = mCarInputCaptureCallbacks.removeReturnOld(targetDisplayType);
+        }
+        if (callback == null) {
+            return;
+        }
+        try {
+            mService.releaseInputEventCapture(mServiceCallback, targetDisplayType);
+        } catch (RemoteException e) {
+            // ignore
+        }
+    }
+
+    @Override
+    protected void onCarDisconnected() {
+        synchronized (mLock) {
+            mCarInputCaptureCallbacks.clear();
+        }
+    }
+
+    private CarInputCaptureCallback getCallback(int targetDisplayType) {
+        synchronized (mLock) {
+            return mCarInputCaptureCallbacks.get(targetDisplayType);
+        }
+    }
+
+    private void dispatchKeyEvents(int targetDisplayType, List<KeyEvent> keyEvents) {
+        getEventHandler().post(() -> {
+            CarInputCaptureCallback callback = getCallback(targetDisplayType);
+            if (callback != null) {
+                callback.onKeyEvents(targetDisplayType, keyEvents);
+            }
+        });
+
+    }
+
+    private void dispatchRotaryEvents(int targetDisplayType, List<RotaryEvent> events) {
+        getEventHandler().post(() -> {
+            CarInputCaptureCallback callback = getCallback(targetDisplayType);
+            if (callback != null) {
+                callback.onRotaryEvents(targetDisplayType, events);
+            }
+        });
+    }
+
+    private void dispatchOnCaptureStateChanged(int targetDisplayType, int[] activeInputTypes) {
+        getEventHandler().post(() -> {
+            CarInputCaptureCallback callback = getCallback(targetDisplayType);
+            if (callback != null) {
+                callback.onCaptureStateChanged(targetDisplayType, activeInputTypes);
+            }
+        });
+    }
+
+    private static final class ICarInputCallbackImpl extends ICarInputCallback.Stub {
+
+        private final WeakReference<CarInputManager> mManager;
+
+        private ICarInputCallbackImpl(CarInputManager manager) {
+            mManager = new WeakReference<>(manager);
+        }
+
+        @Override
+        public void onKeyEvents(int targetDisplayType, List<KeyEvent> keyEvents) {
+            CarInputManager manager = mManager.get();
+            if (manager == null) {
+                return;
+            }
+            manager.dispatchKeyEvents(targetDisplayType, keyEvents);
+        }
+
+        @Override
+        public void onRotaryEvents(int targetDisplayType, List<RotaryEvent> events) {
+            CarInputManager manager = mManager.get();
+            if (manager == null) {
+                return;
+            }
+            manager.dispatchRotaryEvents(targetDisplayType, events);
+        }
+
+        @Override
+        public void onCaptureStateChanged(int targetDisplayType, int[] activeInputTypes) {
+            CarInputManager manager = mManager.get();
+            if (manager == null) {
+                return;
+            }
+            manager.dispatchOnCaptureStateChanged(targetDisplayType, activeInputTypes);
+        }
+    }
+}
diff --git a/car-lib/src/android/car/input/ICarInput.aidl b/car-lib/src/android/car/input/ICarInput.aidl
new file mode 100644
index 0000000..94c7022
--- /dev/null
+++ b/car-lib/src/android/car/input/ICarInput.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.input;
+
+import android.car.input.ICarInputCallback;
+import android.view.KeyEvent;
+
+/**
+ * Binder API for CarInputManager
+ *
+ * @hide
+ */
+interface ICarInput {
+    /** See {@code CarInputManager.requestInputEventCapture(...)} */
+    int requestInputEventCapture(in ICarInputCallback callback, int targetDisplayType,
+        in int[] inputTypes, int requestFlags) = 1;
+    /** See {@code CarInputManager.requestInputEventCapture(...)} */
+    void releaseInputEventCapture(in ICarInputCallback callback, int targetDisplayType) = 2;
+}
diff --git a/car-lib/src/android/car/input/ICarInputCallback.aidl b/car-lib/src/android/car/input/ICarInputCallback.aidl
new file mode 100644
index 0000000..218ff2c
--- /dev/null
+++ b/car-lib/src/android/car/input/ICarInputCallback.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.input;
+
+import android.car.input.RotaryEvent;
+import android.view.KeyEvent;
+
+/**
+ * Binder API for Input Service.
+ *
+ * @hide
+ */
+oneway interface ICarInputCallback {
+    void onKeyEvents(int targetDisplayType, in List<KeyEvent> keyEvents) = 1;
+    void onRotaryEvents(int targetDisplayType, in List<RotaryEvent> events) = 2;
+    void onCaptureStateChanged(int targetDisplayType, in int[] activeInputTypes) = 3;
+}
diff --git a/car-lib/src/android/car/input/RotaryEvent.aidl b/car-lib/src/android/car/input/RotaryEvent.aidl
new file mode 100644
index 0000000..88906e2
--- /dev/null
+++ b/car-lib/src/android/car/input/RotaryEvent.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.input;
+
+parcelable RotaryEvent;
diff --git a/car-lib/src/android/car/input/RotaryEvent.java b/car-lib/src/android/car/input/RotaryEvent.java
new file mode 100644
index 0000000..a43e1e2
--- /dev/null
+++ b/car-lib/src/android/car/input/RotaryEvent.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.input;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.util.Arrays;
+
+/**
+ * {@code Parcelable} containing rotary input event.
+ *
+ * <p>A rotary input event can be either clockwise or counterclockwise and can contain more than 1
+ * click. Each click has its own event time.
+ *
+ * @hide
+ */
+@DataClass(
+        genEqualsHashCode = true,
+        genAidl = true)
+public final class RotaryEvent implements Parcelable {
+    /**
+     * Represents the type of rotary event. This indicates which knob was rotated. For example, it
+     * can be {@link CarInputManager#INPUT_TYPE_ROTARY_NAVIGATION}.
+     */
+    @CarInputManager.InputTypeEnum
+    private final int mInputType;
+
+    /**
+     * Indicates if the event is clockwise (={@code true}) or counterclockwise (={@code false}).
+     */
+    private final boolean mClockwise;
+
+    /**
+     * Stores the event times of all clicks. Time used is uptime in milliseconds.
+     * See {@link android.os.SystemClock#uptimeMillis()} for the definition of the time.
+     *
+     * <p>Timestamps are guaranteed to be monotonically increasing. If the input device cannot
+     * capture timestamps for each click, all the timestamps will be the same.
+     */
+    @NonNull
+    private final long[] mUptimeMillisForClicks;
+
+    /**
+     * Returns the number of clicks contained in this event.
+     */
+    public int getNumberOfClicks() {
+        return mUptimeMillisForClicks.length;
+    }
+
+    /**
+     * Returns the event time for the requested {@code clickIndex}. The time is recorded as
+     * {@link android.os.SystemClock#uptimeMillis()}.
+     *
+     * @param clickIndex Index of click to check the time. It should be  in the range of 0 to
+     * {@code getNumberOfClicks() - 1}.
+     *
+     * @return Event time
+     */
+    public long getUptimeMillisForClick(int clickIndex) {
+        return mUptimeMillisForClicks[clickIndex];
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder(128)
+                .append("RotaryEvent{")
+                .append("mInputType:")
+                .append(mInputType)
+                .append(",mClockwise:")
+                .append(mClockwise)
+                .append(",mUptimeMillisForClicks:")
+                .append(Arrays.toString(mUptimeMillisForClicks))
+                .append("}")
+                .toString();
+    }
+
+
+
+    // Code below generated by codegen v1.0.15.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/input/RotaryEvent.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new RotaryEvent.
+     *
+     * @param inputType
+     *   Represents the type of rotary event. This indicates which knob was rotated. For example, it
+     *   can be {@link CarInputManager#INPUT_TYPE_ROTARY_NAVIGATION}.
+     * @param clockwise
+     *   Indicates if the event is clockwise (={@code true}) or counterclockwise (={@code false}).
+     * @param uptimeMillisForClicks
+     *   Stores the event times of all clicks. Time used is uptime in milliseconds.
+     *   See {@link android.os.SystemClock#uptimeMillis()} for the definition of the time.
+     *
+     * <p>Timestamps are guaranteed to be monotonically increasing. If the input device cannot
+     *   capture timestamps for each click, all the timestamps will be the same.
+     */
+    @DataClass.Generated.Member
+    public RotaryEvent(
+            @CarInputManager.InputTypeEnum int inputType,
+            boolean clockwise,
+            @NonNull long[] uptimeMillisForClicks) {
+        this.mInputType = inputType;
+        com.android.internal.util.AnnotationValidations.validate(
+                CarInputManager.InputTypeEnum.class, null, mInputType);
+        this.mClockwise = clockwise;
+        this.mUptimeMillisForClicks = uptimeMillisForClicks;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mUptimeMillisForClicks);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * Represents the type of rotary event. This indicates which knob was rotated. For example, it
+     * can be {@link CarInputManager#INPUT_TYPE_ROTARY_NAVIGATION}.
+     */
+    @DataClass.Generated.Member
+    public @CarInputManager.InputTypeEnum int getInputType() {
+        return mInputType;
+    }
+
+    /**
+     * Indicates if the event is clockwise (={@code true}) or counterclockwise (={@code false}).
+     */
+    @DataClass.Generated.Member
+    public boolean isClockwise() {
+        return mClockwise;
+    }
+
+    /**
+     * Stores the event times of all clicks. Time used is uptime in milliseconds.
+     * See {@link android.os.SystemClock#uptimeMillis()} for the definition of the time.
+     *
+     * <p>Timestamps are guaranteed to be monotonically increasing. If the input device cannot
+     * capture timestamps for each click, all the timestamps will be the same.
+     */
+    @DataClass.Generated.Member
+    public @NonNull long[] getUptimeMillisForClicks() {
+        return mUptimeMillisForClicks;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@android.annotation.Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(RotaryEvent other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        RotaryEvent that = (RotaryEvent) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && mInputType == that.mInputType
+                && mClockwise == that.mClockwise
+                && Arrays.equals(mUptimeMillisForClicks, that.mUptimeMillisForClicks);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + mInputType;
+        _hash = 31 * _hash + Boolean.hashCode(mClockwise);
+        _hash = 31 * _hash + Arrays.hashCode(mUptimeMillisForClicks);
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        byte flg = 0;
+        if (mClockwise) flg |= 0x2;
+        dest.writeByte(flg);
+        dest.writeInt(mInputType);
+        dest.writeLongArray(mUptimeMillisForClicks);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ RotaryEvent(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        boolean clockwise = (flg & 0x2) != 0;
+        int inputType = in.readInt();
+        long[] uptimeMillisForClicks = in.createLongArray();
+
+        this.mInputType = inputType;
+        com.android.internal.util.AnnotationValidations.validate(
+                CarInputManager.InputTypeEnum.class, null, mInputType);
+        this.mClockwise = clockwise;
+        this.mUptimeMillisForClicks = uptimeMillisForClicks;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mUptimeMillisForClicks);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<RotaryEvent> CREATOR
+            = new Parcelable.Creator<RotaryEvent>() {
+        @Override
+        public RotaryEvent[] newArray(int size) {
+            return new RotaryEvent[size];
+        }
+
+        @Override
+        public RotaryEvent createFromParcel(@NonNull Parcel in) {
+            return new RotaryEvent(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1584120905236L,
+            codegenVersion = "1.0.15",
+            sourceFile = "packages/services/Car/car-lib/src/android/car/input/RotaryEvent.java",
+            inputSignatures = "private final @android.car.input.CarInputManager.InputTypeEnum int mInputType\nprivate final  boolean mClockwise\nprivate final @android.annotation.NonNull long[] mUptimeMillisForClicks\npublic  int getNumberOfClicks()\npublic  long getUptimeMillisForClick(int)\npublic @java.lang.Override java.lang.String toString()\nclass RotaryEvent extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/car-lib/src/android/car/media/CarAudioManager.java b/car-lib/src/android/car/media/CarAudioManager.java
index 2bc8fd7..9f57617 100644
--- a/car-lib/src/android/car/media/CarAudioManager.java
+++ b/car-lib/src/android/car/media/CarAudioManager.java
@@ -16,6 +16,7 @@
 package android.car.media;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
@@ -23,15 +24,22 @@
 import android.car.CarLibLog;
 import android.car.CarManagerBase;
 import android.media.AudioAttributes;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.media.AudioManager.AudioDeviceRole;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
-import android.view.Display;
-import android.view.DisplayAddress;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * APIs for handling audio in a car.
@@ -60,6 +68,19 @@
     public static final int PRIMARY_AUDIO_ZONE = 0x0;
 
     /**
+     * Zone id of the invalid audio zone.
+     * @hide
+     */
+    @SystemApi
+    public static final int INVALID_AUDIO_ZONE = 0xffffffff;
+
+    /**
+     * Volume Group ID when volume group not found.
+     * @hide
+     */
+    public static final int INVALID_VOLUME_GROUP_ID = -1;
+
+    /**
      * Extra for {@link android.media.AudioAttributes.Builder#addBundle(Bundle)}: when used in an
      * {@link android.media.AudioFocusRequest}, the requester should receive all audio focus events,
      * including {@link android.media.AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}.
@@ -85,7 +106,8 @@
             "android.car.media.AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID";
 
     private final ICarAudio mService;
-    private final List<CarVolumeCallback> mCarVolumeCallbacks;
+    private final CopyOnWriteArrayList<CarVolumeCallback> mCarVolumeCallbacks;
+    private final AudioManager mAudioManager;
 
     private final ICarVolumeCallback mCarVolumeCallbackImpl = new ICarVolumeCallback.Stub() {
         @Override
@@ -425,17 +447,41 @@
     }
 
     /**
+     * Gets array of {@link AudioAttributes} usages for a volume group in a zone.
+     *
+     * @param zoneId The zone id whose volume group is queried.
+     * @param groupId The volume group id whose associated audio usages is returned.
+     * @return Array of {@link AudioAttributes} usages for a given volume group id
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME)
+    public @NonNull int[] getUsagesForVolumeGroupId(int zoneId, int groupId) {
+        try {
+            return mService.getUsagesForVolumeGroupId(zoneId, groupId);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, new int[0]);
+        }
+    }
+
+    /**
      * Gets the audio zones currently available
      *
      * @return audio zone ids
      * @hide
      */
+    @SystemApi
     @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS)
-    public @NonNull int[] getAudioZoneIds() {
+    public @NonNull List<Integer> getAudioZoneIds() {
         try {
-            return mService.getAudioZoneIds();
+            int[] zoneIdArray = mService.getAudioZoneIds();
+            List<Integer> zoneIdList = new ArrayList<Integer>(zoneIdArray.length);
+            for (int zoneIdValue : zoneIdArray) {
+                zoneIdList.add(zoneIdValue);
+            }
+            return zoneIdList;
         } catch (RemoteException e) {
-            return handleRemoteExceptionFromCarService(e, new int[0]);
+            return handleRemoteExceptionFromCarService(e, Collections.emptyList());
         }
     }
 
@@ -490,57 +536,59 @@
     }
 
     /**
-     * Get the zone id for the display
+     * Gets the output device for a given {@link AudioAttributes} usage in zoneId.
      *
-     * @param  display display to query
-     * @return zone id for display or
-     * CarAudioManager.PRIMARY_AUDIO_ZONE if no match is found.
-     * @hide
-     */
-    @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS)
-    public int getZoneIdForDisplay(Display display) {
-        DisplayAddress address = display.getAddress();
-        if (address instanceof DisplayAddress.Physical) {
-            DisplayAddress.Physical physicalAddress = (DisplayAddress.Physical) address;
-            if (physicalAddress != null) {
-                return getZoneIdForDisplayPortId(physicalAddress.getPort());
-            }
-        }
-        return PRIMARY_AUDIO_ZONE;
-    }
-
-    /**
-     * Get the zone id for the display port id passed in
+     * <p><b>Note:</b> To be used for routing to a specific device. Most applications should
+     * use the regular routing mechanism, which is to set audio attribute usage to
+     * an audio track.
      *
-     * @param  displayPortId display port id to query
-     * @return zone id for display port id or
-     * CarAudioManager.PRIMARY_AUDIO_ZONE if no match is found.
-     * @hide
-     */
-    @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS)
-    public int getZoneIdForDisplayPortId(byte displayPortId) {
-        try {
-            return mService.getZoneIdForDisplayPortId(displayPortId);
-        } catch (RemoteException e) {
-            return handleRemoteExceptionFromCarService(e, 0);
-        }
-    }
-
-    /**
-     * Gets array of {@link AudioAttributes} usages for a volume group in a zone.
+     * @param zoneId zone id to query for device
+     * @param usage usage where audio is routed
+     * @return Audio device info, returns {@code null} if audio device usage fails to map to
+     * an active audio device. This is different from the using an invalid value for
+     * {@link AudioAttributes} usage. In the latter case the query will fail with a
+     * RuntimeException indicating the issue.
      *
-     * @param zoneId The zone id whose volume group is queried.
-     * @param groupId The volume group id whose associated audio usages is returned.
-     * @return Array of {@link AudioAttributes} usages for a given volume group id
      * @hide
      */
     @SystemApi
-    @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME)
-    public @NonNull int[] getUsagesForVolumeGroupId(int zoneId, int groupId) {
+    @Nullable
+    @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS)
+    public AudioDeviceInfo getOutputDeviceForUsage(int zoneId,
+            @AudioAttributes.AttributeUsage int usage) {
         try {
-            return mService.getUsagesForVolumeGroupId(zoneId, groupId);
+            String deviceAddress = mService.getOutputDeviceAddressForUsage(zoneId, usage);
+            if (deviceAddress == null) {
+                return null;
+            }
+            AudioDeviceInfo[] outputDevices =
+                    mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
+            for (AudioDeviceInfo info : outputDevices) {
+                if (info.getAddress().equals(deviceAddress)) {
+                    return info;
+                }
+            }
+            return null;
         } catch (RemoteException e) {
-            return handleRemoteExceptionFromCarService(e, new int[0]);
+            return handleRemoteExceptionFromCarService(e, null);
+        }
+    }
+
+    /**
+     * Gets the input devices for an audio zone
+     *
+     * @return list of input devices
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS)
+    public @NonNull List<AudioDeviceInfo> getInputDevicesForZoneId(int zoneId) {
+        try {
+            return convertInputDevicesToDeviceInfos(
+                    mService.getInputDevicesForZoneId(zoneId),
+                    AudioManager.GET_DEVICES_INPUTS);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, new ArrayList<>());
         }
     }
 
@@ -548,11 +596,7 @@
     @Override
     public void onCarDisconnected() {
         if (mService != null) {
-            try {
-                mService.unregisterVolumeCallback(mCarVolumeCallbackImpl.asBinder());
-            } catch (RemoteException e) {
-                handleRemoteExceptionFromCarService(e);
-            }
+            unregisterVolumeCallback();
         }
     }
 
@@ -560,7 +604,40 @@
     public CarAudioManager(Car car, IBinder service) {
         super(car);
         mService = ICarAudio.Stub.asInterface(service);
-        mCarVolumeCallbacks = new ArrayList<>();
+        mAudioManager = getContext().getSystemService(AudioManager.class);
+        mCarVolumeCallbacks = new CopyOnWriteArrayList<>();
+    }
+
+    /**
+     * Registers a {@link CarVolumeCallback} to receive volume change callbacks
+     * @param callback {@link CarVolumeCallback} instance, can not be null
+     * <p>
+     * Requires permission Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME
+     */
+    public void registerCarVolumeCallback(@NonNull CarVolumeCallback callback) {
+        Objects.requireNonNull(callback);
+
+        if (mCarVolumeCallbacks.isEmpty()) {
+            registerVolumeCallback();
+        }
+
+        mCarVolumeCallbacks.add(callback);
+    }
+
+    /**
+     * Unregisters a {@link CarVolumeCallback} from receiving volume change callbacks
+     * @param callback {@link CarVolumeCallback} instance previously registered, can not be null
+     * <p>
+     * Requires permission Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME
+     */
+    public void unregisterCarVolumeCallback(@NonNull CarVolumeCallback callback) {
+        Objects.requireNonNull(callback);
+        if (mCarVolumeCallbacks.remove(callback) && mCarVolumeCallbacks.isEmpty()) {
+            unregisterVolumeCallback();
+        }
+    }
+
+    private void registerVolumeCallback() {
         try {
             mService.registerVolumeCallback(mCarVolumeCallbackImpl.asBinder());
         } catch (RemoteException e) {
@@ -568,20 +645,31 @@
         }
     }
 
-    /**
-     * Registers a {@link CarVolumeCallback} to receive volume change callbacks
-     * @param callback {@link CarVolumeCallback} instance, can not be null
-     */
-    public void registerCarVolumeCallback(@NonNull CarVolumeCallback callback) {
-        mCarVolumeCallbacks.add(callback);
+    private void unregisterVolumeCallback() {
+        try {
+            mService.unregisterVolumeCallback(mCarVolumeCallbackImpl.asBinder());
+        } catch (RemoteException e) {
+            handleRemoteExceptionFromCarService(e);
+        }
     }
 
-    /**
-     * Unregisters a {@link CarVolumeCallback} from receiving volume change callbacks
-     * @param callback {@link CarVolumeCallback} instance previously registered, can not be null
-     */
-    public void unregisterCarVolumeCallback(@NonNull CarVolumeCallback callback) {
-        mCarVolumeCallbacks.remove(callback);
+    private List<AudioDeviceInfo> convertInputDevicesToDeviceInfos(
+            List<AudioDeviceAttributes> devices, @AudioDeviceRole int flag) {
+        int addressesSize = devices.size();
+        Set<String> deviceAddressMap = new HashSet<>(addressesSize);
+        for (int i = 0; i < addressesSize; ++i) {
+            AudioDeviceAttributes device = devices.get(i);
+            deviceAddressMap.add(device.getAddress());
+        }
+        List<AudioDeviceInfo> deviceInfoList = new ArrayList<>(devices.size());
+        AudioDeviceInfo[] inputDevices = mAudioManager.getDevices(flag);
+        for (int i = 0; i < inputDevices.length; ++i) {
+            AudioDeviceInfo info = inputDevices[i];
+            if (info.isSource() && deviceAddressMap.contains(info.getAddress())) {
+                deviceInfoList.add(info);
+            }
+        }
+        return deviceInfoList;
     }
 
     /**
diff --git a/car-lib/src/android/car/media/CarAudioPatchHandle.java b/car-lib/src/android/car/media/CarAudioPatchHandle.java
index 77dfc23..8bc4cfe 100644
--- a/car-lib/src/android/car/media/CarAudioPatchHandle.java
+++ b/car-lib/src/android/car/media/CarAudioPatchHandle.java
@@ -42,6 +42,8 @@
      * Construct a audio patch handle container given the system level handle
      * NOTE: Assumes (as it true today), that there is exactly one device port in the source
      * and sink arrays.
+     *
+     * @hide
      */
     public CarAudioPatchHandle(AudioPatch patch) {
         Preconditions.checkArgument(patch.sources().length == 1
@@ -68,9 +70,7 @@
      * @hide
      */
     public boolean represents(AudioPatch patch) {
-        return patch.sources().length == 1
-                && patch.sinks().length == 1
-                && patch.id() == mHandleId;
+        return patch.id() == mHandleId;
     }
 
     @Override
@@ -98,16 +98,16 @@
         out.writeString(mSinkAddress);
     }
 
-    public static final Parcelable.Creator<CarAudioPatchHandle> CREATOR
-            = new Parcelable.Creator<CarAudioPatchHandle>() {
-        public CarAudioPatchHandle createFromParcel(Parcel in) {
-            return new CarAudioPatchHandle(in);
-        }
+    public static final Parcelable.Creator<CarAudioPatchHandle> CREATOR =
+                new Parcelable.Creator<CarAudioPatchHandle>() {
+            public CarAudioPatchHandle createFromParcel(Parcel in) {
+                return new CarAudioPatchHandle(in);
+            }
 
-        public CarAudioPatchHandle[] newArray(int size) {
-            return new CarAudioPatchHandle[size];
-        }
-    };
+            public CarAudioPatchHandle[] newArray(int size) {
+                return new CarAudioPatchHandle[size];
+            }
+        };
 
     @Override
     public int describeContents() {
diff --git a/car-lib/src/android/car/media/CarMediaManager.java b/car-lib/src/android/car/media/CarMediaManager.java
index 8537ed6..8e45dfc 100644
--- a/car-lib/src/android/car/media/CarMediaManager.java
+++ b/car-lib/src/android/car/media/CarMediaManager.java
@@ -15,27 +15,51 @@
  */
 package android.car.media;
 
+import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.car.Car;
 import android.car.CarManagerBase;
 import android.content.ComponentName;
 import android.os.IBinder;
 import android.os.RemoteException;
 
+import com.android.internal.annotations.GuardedBy;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
  * API for updating and receiving updates to the primary media source in the car.
  * @hide
  */
+@SystemApi
 public final class CarMediaManager extends CarManagerBase {
 
+    public static final int MEDIA_SOURCE_MODE_PLAYBACK = 0;
+    public static final int MEDIA_SOURCE_MODE_BROWSE = 1;
+
+    /** @hide */
+    @IntDef(prefix = { "MEDIA_SOURCE_MODE_" }, value = {
+            MEDIA_SOURCE_MODE_PLAYBACK,
+            MEDIA_SOURCE_MODE_BROWSE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface MediaSourceMode {}
+
+    private final Object mLock = new Object();
+
     private final ICarMedia mService;
+    @GuardedBy("mLock")
     private Map<MediaSourceChangedListener, ICarMediaSourceListener> mCallbackMap = new HashMap();
 
     /**
-     * Get an instance of the CarPowerManager.
+     * Get an instance of the CarMediaManager.
      *
      * Should not be obtained directly by clients, use {@link Car#getCarManager(String)} instead.
      * @hide
@@ -47,40 +71,39 @@
 
     /**
      * Listener for updates to the primary media source
-     * @hide
      */
     public interface MediaSourceChangedListener {
 
         /**
          * Called when the primary media source is changed
-         * @hide
          */
-        void onMediaSourceChanged(ComponentName componentName);
+        void onMediaSourceChanged(@NonNull ComponentName componentName);
     }
 
     /**
-     * Gets the currently active media source, or null if none exists
-     * Requires android.Manifest.permission.MEDIA_CONTENT_CONTROL permission
-     * @hide
+     * Gets the currently active media source for the provided mode
+     *
+     * @param mode the mode (playback or browse) for which the media source is active in.
+     * @return the active media source in the provided mode, will be non-{@code null}.
      */
     @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
-    public synchronized ComponentName getMediaSource() {
+    public @NonNull ComponentName getMediaSource(@MediaSourceMode int mode) {
         try {
-            return mService.getMediaSource();
+            return mService.getMediaSource(mode);
         } catch (RemoteException e) {
             return handleRemoteExceptionFromCarService(e, null);
         }
     }
 
     /**
-     * Sets the currently active media source
-     * Requires android.Manifest.permission.MEDIA_CONTENT_CONTROL permission
-     * @hide
+     * Sets the currently active media source for the provided mode
+     *
+     * @param mode the mode (playback or browse) for which the media source is active in.
      */
     @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
-    public synchronized void setMediaSource(ComponentName componentName) {
+    public void setMediaSource(@NonNull ComponentName componentName, @MediaSourceMode int mode) {
         try {
-            mService.setMediaSource(componentName);
+            mService.setMediaSource(componentName, mode);
         } catch (RemoteException e) {
             handleRemoteExceptionFromCarService(e);
         }
@@ -88,11 +111,13 @@
 
     /**
      * Register a callback that receives updates to the active media source.
-     * Requires android.Manifest.permission.MEDIA_CONTENT_CONTROL permission
-     * @hide
+     *
+     * @param callback the callback to receive active media source updates.
+     * @param mode the mode to receive updates for.
      */
     @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
-    public synchronized void registerMediaSourceListener(MediaSourceChangedListener callback) {
+    public void addMediaSourceListener(@NonNull MediaSourceChangedListener callback,
+            @MediaSourceMode int mode) {
         try {
             ICarMediaSourceListener binderCallback = new ICarMediaSourceListener.Stub() {
                 @Override
@@ -100,8 +125,10 @@
                     callback.onMediaSourceChanged(componentName);
                 }
             };
-            mCallbackMap.put(callback, binderCallback);
-            mService.registerMediaSourceListener(binderCallback);
+            synchronized (mLock) {
+                mCallbackMap.put(callback, binderCallback);
+            }
+            mService.registerMediaSourceListener(binderCallback, mode);
         } catch (RemoteException e) {
             handleRemoteExceptionFromCarService(e);
         }
@@ -109,23 +136,74 @@
 
     /**
      * Unregister a callback that receives updates to the active media source.
-     * Requires android.Manifest.permission.MEDIA_CONTENT_CONTROL permission
-     * @hide
+     *
+     * @param callback the callback to be unregistered.
+     * @param mode the mode that the callback was registered to receive updates for.
      */
     @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
-    public synchronized void unregisterMediaSourceListener(MediaSourceChangedListener callback) {
+    public void removeMediaSourceListener(@NonNull MediaSourceChangedListener callback,
+            @MediaSourceMode int mode) {
         try {
-            ICarMediaSourceListener binderCallback = mCallbackMap.remove(callback);
-            mService.unregisterMediaSourceListener(binderCallback);
+            synchronized (mLock) {
+                ICarMediaSourceListener binderCallback = mCallbackMap.remove(callback);
+                mService.unregisterMediaSourceListener(binderCallback, mode);
+            }
         } catch (RemoteException e) {
             handleRemoteExceptionFromCarService(e);
         }
     }
 
+    /**
+     * Retrieve a list of media sources, ordered by most recently used.
+     *
+     * @param mode the mode (playback or browse) for which to retrieve media sources from.
+     * @return non-{@code null} list of media sources, ordered by most recently used
+     */
+    @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public @NonNull List<ComponentName> getLastMediaSources(@MediaSourceMode int mode) {
+        try {
+            return mService.getLastMediaSources(mode);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, null);
+        }
+    }
+
     /** @hide */
     @Override
-    public synchronized void onCarDisconnected() {
-        // TODO(b/142733057) Fix synchronization to use separate mLock
-        mCallbackMap.clear();
+    public void onCarDisconnected() {
+        synchronized (mLock) {
+            mCallbackMap.clear();
+        }
+    }
+
+    /**
+     * Returns whether the browse and playback sources can be changed independently.
+     * @return true if the browse and playback sources can be changed independently, false if it
+     * isn't or if the value could not be determined.
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public boolean isIndependentPlaybackConfig() {
+        try {
+            return mService.isIndependentPlaybackConfig();
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, null);
+        }
+    }
+
+    /**
+     * Sets whether the browse and playback sources can be changed independently.
+     * @param independent whether the browse and playback sources can be changed independently.
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void setIndependentPlaybackConfig(boolean independent) {
+        try {
+            mService.setIndependentPlaybackConfig(independent);
+        } catch (RemoteException e) {
+            handleRemoteExceptionFromCarService(e);
+        }
     }
 }
diff --git a/car-lib/src/android/car/media/ICarAudio.aidl b/car-lib/src/android/car/media/ICarAudio.aidl
index 2614a2e..a8997ce 100644
--- a/car-lib/src/android/car/media/ICarAudio.aidl
+++ b/car-lib/src/android/car/media/ICarAudio.aidl
@@ -17,6 +17,7 @@
 package android.car.media;
 
 import android.car.media.CarAudioPatchHandle;
+import android.media.AudioDeviceAttributes;
 /**
  * Binder interface for {@link android.car.media.CarAudioManager}.
  * Check {@link android.car.media.CarAudioManager} APIs for expected behavior of each call.
@@ -47,8 +48,9 @@
     boolean setZoneIdForUid(int zoneId, int uid);
     boolean clearZoneIdForUid(int uid);
 
-    int getZoneIdForDisplayPortId(byte displayPortId);
+    String getOutputDeviceAddressForUsage(int zoneId, int usage);
 
+    List<AudioDeviceAttributes> getInputDevicesForZoneId(int zoneId);
     /**
      * IBinder is ICarVolumeCallback but passed as IBinder due to aidl hidden.
      */
diff --git a/car-lib/src/android/car/media/ICarMedia.aidl b/car-lib/src/android/car/media/ICarMedia.aidl
index c2881cd..ab73536 100644
--- a/car-lib/src/android/car/media/ICarMedia.aidl
+++ b/car-lib/src/android/car/media/ICarMedia.aidl
@@ -26,8 +26,18 @@
  * @hide
  */
 interface ICarMedia {
-    ComponentName getMediaSource();
-    void setMediaSource(in ComponentName mediaSource);
-    void registerMediaSourceListener(in ICarMediaSourceListener callback);
-    void unregisterMediaSourceListener(in ICarMediaSourceListener callback);
+    /** Gets the currently active media source for the provided mode */
+    ComponentName getMediaSource(int mode);
+    /** Sets the currently active media source for the provided mode */
+    void setMediaSource(in ComponentName mediaSource, int mode);
+    /** Register a callback that receives updates to the active media source */
+    void registerMediaSourceListener(in ICarMediaSourceListener callback, int mode);
+    /** Unregister a callback that receives updates to the active media source */
+    void unregisterMediaSourceListener(in ICarMediaSourceListener callback, int mode);
+    /** Retrieve a list of media sources, ordered by most recently used */
+    List<ComponentName> getLastMediaSources(int mode);
+    /** Returns whether the browse and playback sources can be changed independently. */
+    boolean isIndependentPlaybackConfig();
+    /** Sets whether the browse and playback sources can be changed independently. */
+    void setIndependentPlaybackConfig(boolean independent);
 }
diff --git a/car-lib/src/android/car/navigation/CarNavigationInstrumentCluster.java b/car-lib/src/android/car/navigation/CarNavigationInstrumentCluster.java
index b41c7de..444f82a 100644
--- a/car-lib/src/android/car/navigation/CarNavigationInstrumentCluster.java
+++ b/car-lib/src/android/car/navigation/CarNavigationInstrumentCluster.java
@@ -57,25 +57,31 @@
 
     private final Bundle mExtra;
 
-    public static final Parcelable.Creator<CarNavigationInstrumentCluster> CREATOR
-            = new Parcelable.Creator<CarNavigationInstrumentCluster>() {
-        public CarNavigationInstrumentCluster createFromParcel(Parcel in) {
-            return new CarNavigationInstrumentCluster(in);
-        }
+    public static final Parcelable.Creator<CarNavigationInstrumentCluster> CREATOR =
+                new Parcelable.Creator<CarNavigationInstrumentCluster>() {
+            public CarNavigationInstrumentCluster createFromParcel(Parcel in) {
+                return new CarNavigationInstrumentCluster(in);
+            }
 
-        public CarNavigationInstrumentCluster[] newArray(int size) {
-            return new CarNavigationInstrumentCluster[size];
-        }
-    };
+            public CarNavigationInstrumentCluster[] newArray(int size) {
+                return new CarNavigationInstrumentCluster[size];
+            }
+        };
 
+    /**
+     * Creates a new {@link CarNavigationInstrumentCluster}.
+     */
     public static CarNavigationInstrumentCluster createCluster(int minIntervalMillis) {
         return new CarNavigationInstrumentCluster(minIntervalMillis, CLUSTER_TYPE_IMAGE_CODES_ONLY,
                 0, 0, 0);
     }
 
-    public static CarNavigationInstrumentCluster createCustomImageCluster(int minIntervalMs,
+    /**
+     * Creates a new {@link CarNavigationInstrumentCluster}.
+     */
+    public static CarNavigationInstrumentCluster createCustomImageCluster(int minIntervalMillis,
             int imageWidth, int imageHeight, int imageColorDepthBits) {
-        return new CarNavigationInstrumentCluster(minIntervalMs,
+        return new CarNavigationInstrumentCluster(minIntervalMillis,
                 CLUSTER_TYPE_CUSTOM_IMAGES_SUPPORTED,
                 imageWidth, imageHeight, imageColorDepthBits);
     }
@@ -108,7 +114,9 @@
      * Contains extra information about instrument cluster.
      * @hide
      */
-    public Bundle getExtra() { return mExtra; }
+    public Bundle getExtra() {
+        return mExtra;
+    }
 
     /**
      * If instrument cluster is image, number of bits of colour depth it supports (8, 16, or 32).
@@ -127,10 +135,9 @@
 
     /**
      * Whether cluster support custom image or not.
-     * @return
      */
     public boolean supportsCustomImages() {
-      return mType == CLUSTER_TYPE_CUSTOM_IMAGES_SUPPORTED;
+        return mType == CLUSTER_TYPE_CUSTOM_IMAGES_SUPPORTED;
     }
 
     private CarNavigationInstrumentCluster(
@@ -174,12 +181,12 @@
     /** Converts to string for debug purpose */
     @Override
     public String toString() {
-        return CarNavigationInstrumentCluster.class.getSimpleName() + "{ " +
-                "minIntervalMillis: " + mMinIntervalMillis + ", " +
-                "type: " + mType + ", " +
-                "imageWidth: " + mImageWidth + ", " +
-                "imageHeight: " + mImageHeight + ", " +
-                "imageColourDepthBits: " + mImageColorDepthBits +
-                "extra: " + mExtra + " }";
+        return CarNavigationInstrumentCluster.class.getSimpleName() + "{ "
+                + "minIntervalMillis: " + mMinIntervalMillis + ", "
+                + "type: " + mType + ", "
+                + "imageWidth: " + mImageWidth + ", "
+                + "imageHeight: " + mImageHeight + ", "
+                + "imageColourDepthBits: " + mImageColorDepthBits
+                + "extra: " + mExtra + " }";
     }
 }
diff --git a/car-lib/src/android/car/navigation/CarNavigationStatusManager.java b/car-lib/src/android/car/navigation/CarNavigationStatusManager.java
index 2aa2f10..e94a188 100644
--- a/car-lib/src/android/car/navigation/CarNavigationStatusManager.java
+++ b/car-lib/src/android/car/navigation/CarNavigationStatusManager.java
@@ -61,6 +61,9 @@
      * @param bundle object holding data about the navigation event. This information is
      *               generated using <a href="https://developer.android.com/reference/androidx/car/cluster/navigation/NavigationState.html#toParcelable()">
      *               androidx.car.cluster.navigation.NavigationState#toParcelable()</a>
+     *
+     * @throws IllegalStateException if the client is not holding
+     *                 {@link android.car.CarAppFocusManager#APP_FOCUS_TYPE_NAVIGATION} focus.
      */
     @RequiresPermission(Car.PERMISSION_CAR_NAVIGATION_MANAGER)
     public void sendNavigationStateChange(Bundle bundle) {
diff --git a/car-lib/src/android/car/navigation/navigation_state.proto b/car-lib/src/android/car/navigation/navigation_state.proto
index f6161e0..6c4f2bd 100644
--- a/car-lib/src/android/car/navigation/navigation_state.proto
+++ b/car-lib/src/android/car/navigation/navigation_state.proto
@@ -32,7 +32,8 @@
 // Margins: The referenced image does not have internal margins.
 // Format: Content URI must reference a file with MIME type
 //         'image/png', 'image/jpeg' or 'image/bmp'.
-// Color: Images can be either "tintable" or not. A "tintable" image is such that
+// Color: Images can be either "tintable" or not. A "tintable" image is such
+// that
 //        all its content is defined in its alpha channel, while its color
 //        (all other channels) can be altered without losing information
 //        (e.g. icons). A non "tintable" images contains information in all its
@@ -40,8 +41,8 @@
 // Caching: Given the same image reference and the same requested size,
 //          it is assumed that the exact same image will always be returned.
 //          This means that it should be safe to cache an image once requested
-//          the first time, using this image reference plus requested size as key,
-//          for as long as needed.
+//          the first time, using this image reference plus requested size as
+//          key, for as long as needed.
 message ImageReference {
   // A URI defining the location that the image can be retrieved from.
   //
@@ -95,7 +96,8 @@
   // in the vehicle.
   //
   // For example, a distance of 1200 meters in ES_es locale could be
-  // represented with `display_value` of "1,2" and `display_units` of KILOMETERS.
+  // represented with `display_value` of "1,2" and `display_units` of
+  // KILOMETERS.
   string display_value = 2;
 
   // The distance unit that should be used to display the distance value
@@ -106,7 +108,6 @@
 
 // Information about a maneuver that the driver will be required to perform.
 message Maneuver {
-
   // Next ID: 57
   enum Type {
     // Maneuver type is unknown, no maneuver information should be displayed.
@@ -119,57 +120,92 @@
     NAME_CHANGE = 2;
 
     // No turn, from 0 (included) to 10 (excluded) degrees. Used when we just
-    // wish to say "Keep left" or "Keep right". Note that this is used in
-    // contrast to STRAIGHT for disambiguating cases where there is more than
-    // one option to go into the same general direction.
+    // wish to say "Keep left". Note that this is used in contrast to STRAIGHT
+    // for disambiguating cases where there is more than one option to go into
+    // the same general direction.
     KEEP_LEFT = 3;
+    // No turn, from 0 (included) to 10 (excluded) degrees. Used when we just
+    // wish to say "Keep right". Note that this is used in contrast to STRAIGHT
+    // for disambiguating cases where there is more than one option to go into
+    // the same general direction.
     KEEP_RIGHT = 4;
 
-    // Slight turn at an intersection, from 10 (included) to 45 (excluded)
+    // Slight left turn at an intersection, from 10 (included) to 45 (excluded)
     // degrees.
     TURN_SLIGHT_LEFT = 5;
+    // Slight right turn at an intersection, from 10 (included) to 45 (excluded)
+    // degrees.
     TURN_SLIGHT_RIGHT = 6;
 
-    // Regular turn at an intersection, from 45 (included) to 135 (excluded)
-    // degrees.
+    // Regular left turn at an intersection, from 45 (included) to 135
+    // (excluded) degrees.
     TURN_NORMAL_LEFT = 7;
+    // Regular right turn at an intersection, from 45 (included) to 135
+    // (excluded) degrees.
     TURN_NORMAL_RIGHT = 8;
 
-    // Sharp turn at an intersection, from 135 (included) to 175 (excluded)
-    // degrees
+    // Sharp left turn at an intersection, from 135 (included) to 175 (excluded)
+    // degrees.
     TURN_SHARP_LEFT = 9;
+    // Sharp right turn at an intersection, from 135 (included) to 175
+    // (excluded) degrees.
     TURN_SHARP_RIGHT = 10;
 
-    // A turn onto the opposite side of the same street, from 175 (included) to
-    // 180 (included) degrees.
+    // A left turn onto the opposite side of the same street, from 175
+    // (included) to 180 (included) degrees.
     U_TURN_LEFT = 11;
+    // A right turn onto the opposite side of the same street, from 175
+    // (included) to 180 (included) degrees.
     U_TURN_RIGHT = 12;
 
-    // A turn to enter a turnpike or freeway. See TURN_NORMAL_LEFT,
-    // TURN_SLIGHT_RIGHT, etc., for the difference between slight, sharp, etc.
+    // A slight left turn to enter a turnpike or freeway. See TURN_SLIGHT_LEFT
+    // for the definition of slight.
     ON_RAMP_SLIGHT_LEFT = 13;
+    // A slight right turn to enter a turnpike or freeway. See TURN_SLIGHT_RIGHT
+    // for the definition of slight.
     ON_RAMP_SLIGHT_RIGHT = 14;
+    // A normal left turn to enter a turnpike or freeway. See TURN_NORMAL_LEFT
+    // for the definition of normal.
     ON_RAMP_NORMAL_LEFT = 15;
+    // A normal right turn to enter a turnpike or freeway. See TURN_NORMAL_RIGHT
+    // for the definition of normal.
     ON_RAMP_NORMAL_RIGHT = 16;
+    // A sharp left turn to enter a turnpike or freeway. See TURN_SHARP_LEFT
+    // for the definition of sharp.
     ON_RAMP_SHARP_LEFT = 17;
+    // A sharp right turn to enter a turnpike or freeway. See TURN_SHARP_RIGHT
+    // for the definition of sharp.
     ON_RAMP_SHARP_RIGHT = 18;
+    // A left u-turn to enter a turnpike or freeway. See U_TURN_LEFT for the
+    // definition of u-turn.
     ON_RAMP_U_TURN_LEFT = 19;
+    // A right u-turn to enter a turnpike or freeway. See U_TURN_RIGHT for the
+    // definition of u-turn.
     ON_RAMP_U_TURN_RIGHT = 20;
 
-    // A turn to exit a turnpike or freeway. See TURN_NORMAL_LEFT,
-    // TURN_SLIGHT_RIGHT, etc., for the difference between slight, sharp, etc.
+    // A slight left turn to exit a turnpike or freeway. See TURN_SLIGHT_LEFT
+    // for the definition of slight.
     OFF_RAMP_SLIGHT_LEFT = 21;
+    // A slight right turn to exit a turnpike or freeway. See TURN_SLIGHT_RIGHT
+    // for the definition of slight.
     OFF_RAMP_SLIGHT_RIGHT = 22;
+    // A left turn to exit a turnpike or freeway. See TURN_NORMAL_LEFT
+    // for the definition of normal.
     OFF_RAMP_NORMAL_LEFT = 23;
+    // A right turn to exit a turnpike or freeway. See TURN_NORMAL_RIGHT
+    // for the definition of normal.
     OFF_RAMP_NORMAL_RIGHT = 24;
 
-    // Road diverges (e.g. "Keep left/right at the fork").
+    // Road diverges (e.g. "Keep left at the fork").
     FORK_LEFT = 25;
+    // Road diverges (e.g. "Keep right at the fork").
     FORK_RIGHT = 26;
 
-    // Current road joins another (e.g. "Merge left/right onto Main St.").
+    // Current road joins another (e.g. "Merge right onto Main St.").
     MERGE_LEFT = 27;
+    // Current road joins another (e.g. "Merge left onto Main St.").
     MERGE_RIGHT = 28;
+    // Current road joins another (e.g. "Merge onto Main St.").
     MERGE_SIDE_UNSPECIFIED = 54;
 
     // Roundabout entrance on which the current road ends (e.g. "Enter the
@@ -180,36 +216,90 @@
     // the roundabout").
     ROUNDABOUT_EXIT = 30;
 
-    // The following are entrance and exit (e.g. "At the roundabout, take Nth
-    // exit") on a clockwise roundabout (as seen from above, typical for
-    // left-hand drive countries) where the exit is a particular turn amount
-    // (sharp right, vs. normal left, etc. - see the definitions for
-    // TURN_SHARP_LEFT, TURN_SLIGHT_RIGHT, etc., for a definition of what "sharp"
-    // vs. "normal" vs. "slight" is.
+    // Entrance and exit (e.g. "At the roundabout, take Nth exit") on a
+    // clockwise roundabout (as seen from above, typical for left-hand drive
+    // countries).
     ROUNDABOUT_ENTER_AND_EXIT_CW = 55;
+    // Entrance and sharp right turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a clockwise roundabout (as seen from above, typical for
+    // left-hand drive countries). See TURN_SHARP_RIGHT for the definition of
+    // sharp.
     ROUNDABOUT_ENTER_AND_EXIT_CW_SHARP_RIGHT = 31;
+    // Entrance and regular right turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a clockwise roundabout (as seen from above, typical for
+    // left-hand drive countries). See TURN_NORMAL_RIGHT for the definition of
+    // normal.
     ROUNDABOUT_ENTER_AND_EXIT_CW_NORMAL_RIGHT = 32;
+    // Entrance and slight right turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a clockwise roundabout (as seen from above, typical for
+    // left-hand drive countries). See TURN_SLIGHT_RIGHT for the definition of
+    // slight.
     ROUNDABOUT_ENTER_AND_EXIT_CW_SLIGHT_RIGHT = 33;
+    // Entrance and straight exit (e.g. "At the roundabout, take Nth exit") on a
+    // clockwise roundabout (as seen from above, typical for left-hand drive
+    // countries).
     ROUNDABOUT_ENTER_AND_EXIT_CW_STRAIGHT = 34;
+    // Entrance and sharp left turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a clockwise roundabout (as seen from above, typical for
+    // left-hand drive countries). See TURN_SHARP_LEFT for the definition of
+    // sharp.
     ROUNDABOUT_ENTER_AND_EXIT_CW_SHARP_LEFT = 35;
+    // Entrance and regular left turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a clockwise roundabout (as seen from above, typical for
+    // left-hand drive countries). See TURN_NORMAL_LEFT for the definition of
+    // normal.
     ROUNDABOUT_ENTER_AND_EXIT_CW_NORMAL_LEFT = 36;
+    // Entrance and slight left turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a clockwise roundabout (as seen from above, typical for
+    // left-hand drive countries). See TURN_SLIGHT_LEFT for the definition of
+    // slight.
     ROUNDABOUT_ENTER_AND_EXIT_CW_SLIGHT_LEFT = 37;
+    // Entrance and u-turn exit (e.g. "At the roundabout, take Nth exit") on a
+    // clockwise roundabout (as seen from above, typical for left-hand drive
+    // countries).
     ROUNDABOUT_ENTER_AND_EXIT_CW_U_TURN = 38;
 
-    // The following are entrance and exit (e.g. "At the roundabout, take Nth
-    // exit") on a counter-clockwise roundabout (as seen from above, typical
-    // for right-hand drive countries) where the exit is a particular turn
-    // amount (sharp right, vs. normal left, etc. - see the definitions for
-    // TURN_SHARP_LEFT, TURN_SLIGHT_RIGHT, etc., for a definition of what "sharp"
-    // vs. "normal" vs. "slight" is.
+    // Entrance and exit (e.g. "At the roundabout, take Nth exit") on a
+    // counter-clockwise roundabout (as seen from above, typical for right-hand
+    // drive countries).
     ROUNDABOUT_ENTER_AND_EXIT_CCW = 56;
+    // Entrance and sharp right turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a counter-clockwise roundabout (as seen from above, typical for
+    // right-hand drive countries). See TURN_SHARP_RIGHT for the definition of
+    // sharp.
     ROUNDABOUT_ENTER_AND_EXIT_CCW_SHARP_RIGHT = 39;
+    // Entrance and regular right turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a counter-clockwise roundabout (as seen from above, typical for
+    // right-hand drive countries). See TURN_NORMAL_RIGHT for the definition of
+    // normal.
     ROUNDABOUT_ENTER_AND_EXIT_CCW_NORMAL_RIGHT = 40;
+    // Entrance and slight right turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a counter-clockwise roundabout (as seen from above, typical for
+    // right-hand drive countries). See TURN_SLIGHT_RIGHT for the definition of
+    // slight.
     ROUNDABOUT_ENTER_AND_EXIT_CCW_SLIGHT_RIGHT = 41;
+    // Entrance and straight exit (e.g. "At the roundabout, take Nth exit") on a
+    // counter-clockwise roundabout (as seen from above, typical for right-hand
+    // drive countries).
     ROUNDABOUT_ENTER_AND_EXIT_CCW_STRAIGHT = 42;
+    // Entrance and sharp left turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a counter-clockwise roundabout (as seen from above, typical for
+    // right-hand drive countries). See TURN_SHARP_LEFT for the definition of
+    // sharp.
     ROUNDABOUT_ENTER_AND_EXIT_CCW_SHARP_LEFT = 43;
+    // Entrance and regular left turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a counter-clockwise roundabout (as seen from above, typical for
+    // right-hand drive countries). See TURN_NORMAL_LEFT for the definition of
+    // normal.
     ROUNDABOUT_ENTER_AND_EXIT_CCW_NORMAL_LEFT = 44;
+    // Entrance and slight left turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a counter-clockwise roundabout (as seen from above, typical for
+    // right-hand drive countries). See TURN_SLIGHT_LEFT for the definition of
+    // slight.
     ROUNDABOUT_ENTER_AND_EXIT_CCW_SLIGHT_LEFT = 45;
+    // Entrance and u-turn exit (e.g. "At the roundabout, take Nth exit") on a
+    // counter-clockwise roundabout (as seen from above, typical for right-hand
+    // drive countries).
     ROUNDABOUT_ENTER_AND_EXIT_CCW_U_TURN = 46;
 
     // Driver should steer straight.
@@ -224,10 +314,11 @@
     // Arrival to a destination where the direction is unknown.
     DESTINATION = 50;
 
-    // Arrival to a destination located in a particular direction (straight
-    // ahead, left side of the road, right side of the road).
+    // Arrival to a destination located straight ahead.
     DESTINATION_STRAIGHT = 51;
+    // Arrival to a destination located on the left side of the road.
     DESTINATION_LEFT = 52;
+    // Arrival to a destination located on the right side of the road.
     DESTINATION_RIGHT = 53;
   }
 
@@ -427,7 +518,8 @@
 // 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
 // By restricting to that range, we ensure that we can convert to
 // and from  RFC 3339 date strings.
-// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
+// See
+// [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
 //
 // This is a subset of
 // https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/timestamp.proto
@@ -534,3 +626,4 @@
   // Current status of the navigation.
   ServiceStatus service_status = 4;
 }
+
diff --git a/car-lib/src/android/car/occupantawareness/DriverMonitoringDetection.aidl b/car-lib/src/android/car/occupantawareness/DriverMonitoringDetection.aidl
new file mode 100644
index 0000000..61779a3
--- /dev/null
+++ b/car-lib/src/android/car/occupantawareness/DriverMonitoringDetection.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.occupantawareness;
+
+parcelable DriverMonitoringDetection;
diff --git a/car-lib/src/android/car/occupantawareness/DriverMonitoringDetection.java b/car-lib/src/android/car/occupantawareness/DriverMonitoringDetection.java
new file mode 100644
index 0000000..bbac2cb
--- /dev/null
+++ b/car-lib/src/android/car/occupantawareness/DriverMonitoringDetection.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.occupantawareness;
+
+import android.annotation.NonNull;
+import android.car.occupantawareness.OccupantAwarenessDetection.ConfidenceLevel;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Detection state data for monitoring driver attention.
+ *
+ * @hide
+ */
+public final class DriverMonitoringDetection implements Parcelable {
+
+    /** {@link OccupantAwarenessDetection.ConfidenceLevel} for the driver monitoring detection. */
+    public final @ConfidenceLevel int confidenceLevel;
+
+    /** Indicates whether the driver is looking on-road. */
+    public final boolean isLookingOnRoad;
+
+    /**
+     * Duration that the driver has been looking on or off-road, in milliseconds.
+     *
+     * <p>If 'isLookingOnRoad' is true, this indicates the continuous duration of time that the
+     * driver has been looking on-road (in milliseconds). Otherwise, this indicates the continuous
+     * duration of time that the driver is looking off-road (in milliseconds).
+     */
+    public final long gazeDurationMillis;
+
+    public DriverMonitoringDetection() {
+        confidenceLevel = OccupantAwarenessDetection.CONFIDENCE_LEVEL_NONE;
+        isLookingOnRoad = false;
+        gazeDurationMillis = 0;
+    }
+
+    public DriverMonitoringDetection(
+            @ConfidenceLevel int confidenceLevel,
+            boolean isLookingOnRoad,
+            long gazeDurationMillis) {
+        this.confidenceLevel = confidenceLevel;
+        this.isLookingOnRoad = isLookingOnRoad;
+        this.gazeDurationMillis = gazeDurationMillis;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return "DriverMonitoringDetection{"
+                + "confidenceLevel="
+                + confidenceLevel
+                + ", isLookingOnRoad="
+                + isLookingOnRoad
+                + ", gazeDurationMillis="
+                + gazeDurationMillis;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(confidenceLevel);
+        dest.writeBoolean(isLookingOnRoad);
+        dest.writeLong(gazeDurationMillis);
+    }
+
+    public static final @NonNull Parcelable.Creator<DriverMonitoringDetection> CREATOR =
+            new Parcelable.Creator<DriverMonitoringDetection>() {
+                public DriverMonitoringDetection createFromParcel(Parcel in) {
+                    return new DriverMonitoringDetection(in);
+                }
+
+                public DriverMonitoringDetection[] newArray(int size) {
+                    return new DriverMonitoringDetection[size];
+                }
+            };
+
+    private DriverMonitoringDetection(Parcel in) {
+        confidenceLevel = in.readInt();
+        isLookingOnRoad = in.readBoolean();
+        gazeDurationMillis = in.readLong();
+    }
+}
diff --git a/car-lib/src/android/car/occupantawareness/GazeDetection.aidl b/car-lib/src/android/car/occupantawareness/GazeDetection.aidl
new file mode 100644
index 0000000..3ef6b9c
--- /dev/null
+++ b/car-lib/src/android/car/occupantawareness/GazeDetection.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.occupantawareness;
+
+parcelable GazeDetection;
diff --git a/car-lib/src/android/car/occupantawareness/GazeDetection.java b/car-lib/src/android/car/occupantawareness/GazeDetection.java
new file mode 100644
index 0000000..54494a4
--- /dev/null
+++ b/car-lib/src/android/car/occupantawareness/GazeDetection.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.occupantawareness;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+
+/**
+ * Detection result for gaze detection for the respective {@link VehicleOccupantRole}.
+ *
+ * @hide
+ */
+public final class GazeDetection implements Parcelable {
+
+    /** A unknown gaze region, not otherwise specified. */
+    public static final int VEHICLE_REGION_UNKNOWN = 0;
+
+    /** Center instrument cluster in front of the driver. */
+    public static final int VEHICLE_REGION_CENTER_INSTRUMENT_CLUSTER = 1;
+
+    /** The rear-view mirror. */
+    public static final int VEHICLE_REGION_REAR_VIEW_MIRROR = 2;
+
+    /** The left side mirror. */
+    public static final int VEHICLE_REGION_LEFT_SIDE_MIRROR = 3;
+
+    /** The right side mirror. */
+    public static final int VEHICLE_REGION_RIGHT_SIDE_MIRROR = 4;
+
+    /** The forward roadway. */
+    public static final int VEHICLE_REGION_FORWARD_ROADWAY = 5;
+
+    /** Out-the-window to the right. */
+    public static final int VEHICLE_REGION_LEFT_ROADWAY = 6;
+
+    /** Out-the-window to the right. */
+    public static final int VEHICLE_REGION_RIGHT_ROADWAY = 7;
+
+    /** Center head-unit display. */
+    public static final int VEHICLE_REGION_HEAD_UNIT_DISPLAY = 8;
+
+    /**
+     * Vehicle regions
+     *
+     * @hide
+     */
+    @Retention(SOURCE)
+    @IntDef({
+        VEHICLE_REGION_UNKNOWN,
+        VEHICLE_REGION_CENTER_INSTRUMENT_CLUSTER,
+        VEHICLE_REGION_REAR_VIEW_MIRROR,
+        VEHICLE_REGION_LEFT_SIDE_MIRROR,
+        VEHICLE_REGION_RIGHT_SIDE_MIRROR,
+        VEHICLE_REGION_FORWARD_ROADWAY,
+        VEHICLE_REGION_LEFT_ROADWAY,
+        VEHICLE_REGION_RIGHT_ROADWAY,
+        VEHICLE_REGION_HEAD_UNIT_DISPLAY
+    })
+    public @interface VehicleRegion {}
+
+    /** {@link OccupantAwarenessDetection.ConfidenceLevel} for the gaze detection. */
+    @OccupantAwarenessDetection.ConfidenceLevel public final int confidenceLevel;
+
+    /**
+     * Location of the subject's left eye, in millimeters.
+     *
+     * <p>Vehicle origin is defined as part of the Cabin Space API. All units in millimeters. +x is
+     * right (from driver perspective), +y is up, -z is forward.
+     *
+     * <p>May be {@code null} if the underlying detection system does not export eye position data.
+     */
+    public final @Nullable Point3D leftEyePosition;
+
+    /**
+     * Location of the subject's right eye, in millimeters.
+     *
+     * <p>Vehicle origin is defined as part of the Cabin Space API. All units in millimeters. +x is
+     * right (from driver perspective), +y is up, -z is forward.
+     *
+     * <p>May be {@code null} if the underlying detection system does not export eye position data.
+     */
+    public final @Nullable Point3D rightEyePosition;
+
+    /**
+     * Direction of the subject's head orientation, as a <a
+     * href="https://en.wikipedia.org/wiki/Unit_vector">unit-vector</a>.
+     *
+     * <p>May be {@code null} if the underlying system does not support head orientation vectors.
+     */
+    public final @Nullable Point3D headAngleUnitVector;
+
+    /**
+     * Direction of the gaze angle, as a <a
+     * href="https://en.wikipedia.org/wiki/Unit_vector">unit-vector</a>.
+     *
+     * <p>May be {@code null} if the underlying system does not support vectors.
+     */
+    public final @Nullable Point3D gazeAngleUnitVector;
+
+    /** {@link VehicleRegion} where the subject is currently looking. */
+    @VehicleRegion public final int gazeTarget;
+
+    /** Duration on the current gaze target, in milliseconds. */
+    public final long durationOnTargetMillis;
+
+    public GazeDetection(
+            @OccupantAwarenessDetection.ConfidenceLevel int confidenceLevel,
+            @Nullable Point3D leftEyePosition,
+            @Nullable Point3D rightEyePosition,
+            @Nullable Point3D headAngleUnitVector,
+            @Nullable Point3D gazeAngleUnitVector,
+            @VehicleRegion int gazeTarget,
+            long durationOnTargetMillis) {
+
+        this.confidenceLevel = confidenceLevel;
+        this.leftEyePosition = leftEyePosition;
+        this.rightEyePosition = rightEyePosition;
+        this.headAngleUnitVector = headAngleUnitVector;
+        this.gazeAngleUnitVector = gazeAngleUnitVector;
+        this.gazeTarget = gazeTarget;
+        this.durationOnTargetMillis = durationOnTargetMillis;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(confidenceLevel);
+        dest.writeParcelable(leftEyePosition, flags);
+        dest.writeParcelable(rightEyePosition, flags);
+        dest.writeParcelable(headAngleUnitVector, flags);
+        dest.writeParcelable(gazeAngleUnitVector, flags);
+        dest.writeInt(gazeTarget);
+        dest.writeLong(durationOnTargetMillis);
+    }
+
+    @Override
+    public String toString() {
+        return "GazeDetection{"
+                + "confidenceLevel=" + confidenceLevel
+                + ", leftEyePosition=" + (leftEyePosition == null ? "(null)" : leftEyePosition)
+                + ", rightEyePosition=" + (rightEyePosition == null ? "(null)" : rightEyePosition)
+                + ", headAngleUnitVector="
+                + (headAngleUnitVector == null ? "(null)" : headAngleUnitVector)
+                + ", gazeAngleUnitVector="
+                + (gazeAngleUnitVector == null ? "(null)" : gazeAngleUnitVector)
+                + ", gazeTarget=" + gazeTarget
+                + ", durationOnTargetMillis=" + durationOnTargetMillis
+                + "}";
+    }
+
+    public static final @NonNull Parcelable.Creator<GazeDetection> CREATOR =
+            new Parcelable.Creator<GazeDetection>() {
+                public GazeDetection createFromParcel(Parcel in) {
+                    return new GazeDetection(in);
+                }
+
+                public GazeDetection[] newArray(int size) {
+                    return new GazeDetection[size];
+                }
+            };
+
+    private GazeDetection(Parcel in) {
+        confidenceLevel = in.readInt();
+        leftEyePosition = in.readParcelable(Point3D.class.getClassLoader());
+        rightEyePosition = in.readParcelable(Point3D.class.getClassLoader());
+        headAngleUnitVector = in.readParcelable(Point3D.class.getClassLoader());
+        gazeAngleUnitVector = in.readParcelable(Point3D.class.getClassLoader());
+        gazeTarget = in.readInt();
+        durationOnTargetMillis = in.readLong();
+    }
+}
diff --git a/car-lib/src/android/car/occupantawareness/IOccupantAwarenessEventCallback.aidl b/car-lib/src/android/car/occupantawareness/IOccupantAwarenessEventCallback.aidl
new file mode 100644
index 0000000..ad582d2
--- /dev/null
+++ b/car-lib/src/android/car/occupantawareness/IOccupantAwarenessEventCallback.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.occupantawareness;
+
+import android.car.occupantawareness.OccupantAwarenessDetection;
+import android.car.occupantawareness.SystemStatusEvent;
+
+/**
+ * Binder callbacks for events.
+   @hide
+ */
+oneway interface IOccupantAwarenessEventCallback {
+    void onStatusChanged(in SystemStatusEvent event) = 0;
+    void onDetectionEvent(in OccupantAwarenessDetection detectionEvent) = 1;
+}
diff --git a/car-lib/src/android/car/occupantawareness/IOccupantAwarenessManager.aidl b/car-lib/src/android/car/occupantawareness/IOccupantAwarenessManager.aidl
new file mode 100644
index 0000000..0994a09
--- /dev/null
+++ b/car-lib/src/android/car/occupantawareness/IOccupantAwarenessManager.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.occupantawareness;
+
+import android.car.occupantawareness.IOccupantAwarenessEventCallback;
+
+/**
+ * Binder interface for {@link android.car.occupantawareness.OccupantAwarenessManager}.
+ * Check {@link android.car.occupantawareness.OccupantAwarenessManager} APIs for expected behavior of
+ * each call.
+ *
+ * @hide
+ */
+interface IOccupantAwarenessManager {
+    int getCapabilityForRole(int role) = 0;
+    void registerEventListener(IOccupantAwarenessEventCallback listener) = 1;
+    void unregisterEventListener(IOccupantAwarenessEventCallback listener) = 2;
+}
diff --git a/car-lib/src/android/car/occupantawareness/OccupantAwarenessDetection.aidl b/car-lib/src/android/car/occupantawareness/OccupantAwarenessDetection.aidl
new file mode 100644
index 0000000..5e806a6
--- /dev/null
+++ b/car-lib/src/android/car/occupantawareness/OccupantAwarenessDetection.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.occupantawareness;
+
+parcelable OccupantAwarenessDetection;
diff --git a/car-lib/src/android/car/occupantawareness/OccupantAwarenessDetection.java b/car-lib/src/android/car/occupantawareness/OccupantAwarenessDetection.java
new file mode 100644
index 0000000..19009a8
--- /dev/null
+++ b/car-lib/src/android/car/occupantawareness/OccupantAwarenessDetection.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.occupantawareness;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.car.Car;
+import android.car.annotation.RequiredFeature;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+
+/**
+ * Complete detection result for a single detected person. Includes presence detection, {@link
+ * GazeDetection} and {@link DriverMonitoringDetection}.
+ *
+ * <p>Register to listen to events via {@link OccupantAwarenessManager}.
+ *
+ * @hide
+ */
+@RequiredFeature(Car.OCCUPANT_AWARENESS_SERVICE)
+public final class OccupantAwarenessDetection implements Parcelable {
+    /** Empty occupant flag. */
+    public static final int VEHICLE_OCCUPANT_NONE = 0;
+
+    /** Occupants that the system detects as the driver. */
+    public static final int VEHICLE_OCCUPANT_DRIVER = 1 << 2;
+
+    /** Occupants that the system detects as front seat passengers. */
+    public static final int VEHICLE_OCCUPANT_FRONT_PASSENGER = 1 << 1;
+
+    /** Occupants that the system detects in the second vehicle row, on the left. */
+    public static final int VEHICLE_OCCUPANT_ROW_2_PASSENGER_LEFT = 1 << 3;
+
+    /** Occupants that the system detects in the second vehicle row, in the center. */
+    public static final int VEHICLE_OCCUPANT_ROW_2_PASSENGER_CENTER = 1 << 4;
+
+    /** Occupants that the system detects in the second vehicle row, on the right. */
+    public static final int VEHICLE_OCCUPANT_ROW_2_PASSENGER_RIGHT = 1 << 5;
+
+    /** Occupants that the system detects in the third vehicle row, on the left. */
+    public static final int VEHICLE_OCCUPANT_ROW_3_PASSENGER_LEFT = 1 << 6;
+
+    /** Occupants that the system detects in the third vehicle row, in the middle. */
+    public static final int VEHICLE_OCCUPANT_ROW_3_PASSENGER_CENTER = 1 << 7;
+
+    /** Occupants that the system detects in the third vehicle row, on the right. */
+    public static final int VEHICLE_OCCUPANT_ROW_3_PASSENGER_RIGHT = 1 << 8;
+
+    /** All occupants that the system detects in the front row of the vehicle. */
+    public static final int VEHICLE_OCCUPANT_ALL_FRONT_OCCUPANTS =
+            VEHICLE_OCCUPANT_DRIVER | VEHICLE_OCCUPANT_FRONT_PASSENGER;
+
+    /** All occupants that the system detects in the second row of the vehicle. */
+    public static final int VEHICLE_OCCUPANT_ALL_ROW_2_OCCUPANTS =
+            VEHICLE_OCCUPANT_ROW_2_PASSENGER_LEFT
+                    | VEHICLE_OCCUPANT_ROW_2_PASSENGER_RIGHT
+                    | VEHICLE_OCCUPANT_ROW_2_PASSENGER_CENTER;
+
+    /** All occupants that the system detects in the third row of the vehicle. */
+    public static final int VEHICLE_OCCUPANT_ALL_ROW_3_OCCUPANTS =
+            VEHICLE_OCCUPANT_ROW_3_PASSENGER_LEFT
+                    | VEHICLE_OCCUPANT_ROW_3_PASSENGER_RIGHT
+                    | VEHICLE_OCCUPANT_ROW_3_PASSENGER_CENTER;
+
+    /** All occupants that the system detects in the vehicle. */
+    public static final int VEHICLE_OCCUPANT_ALL_OCCUPANTS =
+            VEHICLE_OCCUPANT_ALL_FRONT_OCCUPANTS
+                    | VEHICLE_OCCUPANT_ALL_ROW_2_OCCUPANTS
+                    | VEHICLE_OCCUPANT_ALL_ROW_3_OCCUPANTS;
+
+    /**
+     * Vehicle occupant roles based on their location in the vehicle.
+     *
+     * @hide
+     */
+    @Retention(SOURCE)
+    @IntDef(
+            flag = true,
+            value = {
+                VEHICLE_OCCUPANT_NONE,
+                VEHICLE_OCCUPANT_DRIVER,
+                VEHICLE_OCCUPANT_FRONT_PASSENGER,
+                VEHICLE_OCCUPANT_ROW_2_PASSENGER_LEFT,
+                VEHICLE_OCCUPANT_ROW_2_PASSENGER_CENTER,
+                VEHICLE_OCCUPANT_ROW_2_PASSENGER_RIGHT,
+                VEHICLE_OCCUPANT_ROW_3_PASSENGER_LEFT,
+                VEHICLE_OCCUPANT_ROW_3_PASSENGER_CENTER,
+                VEHICLE_OCCUPANT_ROW_3_PASSENGER_RIGHT,
+                VEHICLE_OCCUPANT_ALL_FRONT_OCCUPANTS,
+                VEHICLE_OCCUPANT_ALL_ROW_2_OCCUPANTS,
+                VEHICLE_OCCUPANT_ALL_ROW_3_OCCUPANTS
+            })
+    public @interface VehicleOccupantRole {}
+
+    /** No prediction could be made. */
+    public static final int CONFIDENCE_LEVEL_NONE = 0;
+
+    /**
+     * Best-guess, low-confidence prediction. Predictions exceeding this threshold are adequate for
+     * non-critical applications.
+     */
+    public static final int CONFIDENCE_LEVEL_LOW = 1;
+
+    /**
+     * High-confidence prediction. Predictions exceeding this threshold are adequate for
+     * applications that require reliable predictions.
+     */
+    public static final int CONFIDENCE_LEVEL_HIGH = 2;
+
+    /** Highest confidence rate achievable. */
+    public static final int CONFIDENCE_LEVEL_MAX = 3;
+
+    /**
+     * Confidence scores for predictions.
+     *
+     * @hide
+     */
+    @Retention(SOURCE)
+    @IntDef(
+            value = {
+                CONFIDENCE_LEVEL_NONE,
+                CONFIDENCE_LEVEL_LOW,
+                CONFIDENCE_LEVEL_HIGH,
+                CONFIDENCE_LEVEL_MAX
+            })
+    public @interface ConfidenceLevel {}
+
+    /** The {@link VehicleOccupantRole} of the face associated with this event. */
+    public final @VehicleOccupantRole int role;
+
+    /** Timestamp when the underlying detection data was detected, in milliseconds since boot. */
+    public final long timestampMillis;
+
+    /** Indicates whether any person was detected for the given role. */
+    public final boolean isPresent;
+
+    /**
+     * {@link GazeDetection} data for the requested role, or {@code null} if no person was found.
+     */
+    public final @Nullable GazeDetection gazeDetection;
+
+    /**
+     * {@link DriverMonitoringDetection} data for the driver, or {@code null} if the role was
+     * non-driver or if the detection could not be computed.
+     */
+    public final @Nullable DriverMonitoringDetection driverMonitoringDetection;
+
+    public OccupantAwarenessDetection(
+            @VehicleOccupantRole int role,
+            long timestampMillis,
+            boolean isPresent,
+            @Nullable GazeDetection gazeDetection,
+            @Nullable DriverMonitoringDetection driverMonitoringDetection) {
+        this.role = role;
+        this.timestampMillis = timestampMillis;
+        this.isPresent = isPresent;
+        this.gazeDetection = gazeDetection;
+        this.driverMonitoringDetection = driverMonitoringDetection;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(role);
+        dest.writeLong(timestampMillis);
+        dest.writeBoolean(isPresent);
+        dest.writeParcelable(gazeDetection, flags);
+        dest.writeParcelable(driverMonitoringDetection, flags);
+    }
+
+    @Override
+    public String toString() {
+        return "OccupantAwarenessDetection{"
+                + "role="  + role
+                + ", timestampMillis=" + timestampMillis
+                + ", isPresent=" + isPresent
+                + ", gazeDetection="
+                + (gazeDetection == null ? "(null)" : gazeDetection.toString())
+                + ", driverMonitoringDetection="
+                + (driverMonitoringDetection == null
+                        ? "(null)" : driverMonitoringDetection.toString())
+                + "}";
+    }
+
+    public static final @NonNull Parcelable.Creator<OccupantAwarenessDetection> CREATOR =
+            new Parcelable.Creator<OccupantAwarenessDetection>() {
+                public OccupantAwarenessDetection createFromParcel(Parcel in) {
+                    return new OccupantAwarenessDetection(in);
+                }
+
+                public OccupantAwarenessDetection[] newArray(int size) {
+                    return new OccupantAwarenessDetection[size];
+                }
+            };
+
+    private OccupantAwarenessDetection(Parcel in) {
+        role = in.readInt();
+        timestampMillis = in.readLong();
+        isPresent = in.readBoolean();
+        gazeDetection = in.readParcelable(GazeDetection.class.getClassLoader());
+        driverMonitoringDetection =
+                in.readParcelable(DriverMonitoringDetection.class.getClassLoader());
+    }
+}
diff --git a/car-lib/src/android/car/occupantawareness/OccupantAwarenessManager.java b/car-lib/src/android/car/occupantawareness/OccupantAwarenessManager.java
new file mode 100644
index 0000000..671bf0e
--- /dev/null
+++ b/car-lib/src/android/car/occupantawareness/OccupantAwarenessManager.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.occupantawareness;
+
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.car.Car;
+import android.car.CarManagerBase;
+import android.car.annotation.RequiredFeature;
+import android.car.occupantawareness.OccupantAwarenessDetection.VehicleOccupantRole;
+import android.car.occupantawareness.SystemStatusEvent.DetectionTypeFlags;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * API exposing Occupant Awareness System data.
+ *
+ * <p>Supported detections include: presence detection, {@link GazeDetection} and {@link
+ * DriverMonitoringDetection}.
+ *
+ * @hide
+ */
+@RequiredFeature(Car.OCCUPANT_AWARENESS_SERVICE)
+public class OccupantAwarenessManager extends CarManagerBase {
+    private static final String TAG = "OAS.Manager";
+    private static final boolean DBG = false;
+
+    private static final int MSG_HANDLE_SYSTEM_STATUS_CHANGE = 0;
+    private static final int MSG_HANDLE_DETECTION_EVENT = 1;
+
+    private final android.car.occupantawareness.IOccupantAwarenessManager mOccupantAwarenessService;
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private ChangeCallback mChangeCallback;
+
+    private final EventCallbackHandler mEventCallbackHandler;
+
+    @GuardedBy("mLock")
+    private ChangeListenerToService mListenerToService;
+
+    /** @hide */
+    public OccupantAwarenessManager(Car car, IBinder service) {
+        super(car);
+        mOccupantAwarenessService =
+                android.car.occupantawareness.IOccupantAwarenessManager.Stub.asInterface(service);
+
+        mEventCallbackHandler = new EventCallbackHandler(this, getEventHandler().getLooper());
+    }
+
+    /** @hide */
+    @Override
+    public void onCarDisconnected() {
+        synchronized (mLock) {
+            mChangeCallback = null;
+            mListenerToService = null;
+        }
+    }
+
+    /**
+     * Gets the detection capabilities for a given {@link VehicleOccupantRole} in this vehicle.
+     *
+     * <p>There may be different detection capabilities for different {@link VehicleOccupantRole}.
+     * Each role should be queried independently.
+     *
+     * <p>Capabilities are static for a given vehicle configuration and need only be queried once
+     * per vehicle. Once capability is determined, clients should query system status via {@link
+     * SystemStatusEvent} to see if the subsystem is currently online and ready to serve.
+     *
+     * @param role {@link VehicleOccupantRole} to query for.
+     * @return {@link SystemStatusEvent.DetectionTypeFlags} indicating supported capabilities for
+     *     the role.
+     */
+    @RequiresPermission(value = Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE)
+    public @DetectionTypeFlags int getCapabilityForRole(@VehicleOccupantRole int role) {
+        try {
+            return mOccupantAwarenessService.getCapabilityForRole(role);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, 0);
+        }
+    }
+
+    /**
+     * Callbacks for listening to changes to {@link SystemStatusEvent} and {@link
+     * OccupantAwarenessDetection}.
+     */
+    public abstract static class ChangeCallback {
+        /**
+         * Called when the system state changes changes.
+         *
+         * @param systemStatus The new system state as a {@link SystemStatusEvent}.
+         */
+        public abstract void onSystemStateChanged(@NonNull SystemStatusEvent systemStatus);
+
+        /**
+         * Called when a detection event is generated.
+         *
+         * @param event The new detection state as a {@link OccupantAwarenessDetection}.
+         */
+        public abstract void onDetectionEvent(@NonNull OccupantAwarenessDetection event);
+    }
+
+    /**
+     * Registers a {@link ChangeCallback} for listening for events.
+     *
+     * <p>If a listener has already been registered, it has to be unregistered before registering
+     * the new one.
+     *
+     * @param callback {@link ChangeCallback} to register.
+     * @throws IllegalStateException if an existing callback is already registered.
+     */
+    @RequiresPermission(value = Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE)
+    public void registerChangeCallback(@NonNull ChangeCallback callback) {
+        if (DBG) {
+            Log.d(TAG, "Registering change listener");
+        }
+
+        synchronized (mLock) {
+            // Check if the listener has been already registered.
+            if (mChangeCallback != null) {
+                throw new IllegalStateException(
+                        "Attempting to register a new listener when an existing listener has"
+                                + " already been registered.");
+            }
+
+            mChangeCallback = callback;
+
+            try {
+                if (mListenerToService == null) {
+                    mListenerToService = new ChangeListenerToService(this);
+                }
+
+                mOccupantAwarenessService.registerEventListener(mListenerToService);
+            } catch (RemoteException e) {
+                handleRemoteExceptionFromCarService(e);
+            }
+        }
+    }
+
+    /** Unregisters a previously registered {@link ChangeCallback}. */
+    @RequiresPermission(value = Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE)
+    public void unregisterChangeCallback() {
+        if (DBG) {
+            Log.d(TAG, "Unregistering change listener");
+        }
+
+        synchronized (mLock) {
+            if (mChangeCallback == null) {
+                Log.e(TAG, "No listener exists to unregister.");
+                return;
+            }
+            mChangeCallback = null;
+        }
+
+        synchronized (mLock) {
+            try {
+                mOccupantAwarenessService.unregisterEventListener(mListenerToService);
+            } catch (RemoteException e) {
+                handleRemoteExceptionFromCarService(e);
+            }
+
+            mListenerToService = null;
+        }
+    }
+
+    /**
+     * Class that implements the listener interface and gets called back from the {@link
+     * com.android.car.IOccupantAwarenessEventCallback} across the binder interface.
+     */
+    private static class ChangeListenerToService extends IOccupantAwarenessEventCallback.Stub {
+        private final WeakReference<OccupantAwarenessManager> mOccupantAwarenessManager;
+
+        ChangeListenerToService(OccupantAwarenessManager manager) {
+            mOccupantAwarenessManager = new WeakReference<>(manager);
+        }
+
+        @Override
+        public void onStatusChanged(SystemStatusEvent systemStatus) {
+            OccupantAwarenessManager manager = mOccupantAwarenessManager.get();
+            if (manager != null) {
+                manager.handleSystemStatusChanged(systemStatus);
+            }
+        }
+
+        @Override
+        public void onDetectionEvent(OccupantAwarenessDetection event) {
+            OccupantAwarenessManager manager = mOccupantAwarenessManager.get();
+            if (manager != null) {
+                manager.handleDetectionEvent(event);
+            }
+        }
+    }
+
+    /**
+     * Gets the {@link SystemStatusEvent} from the service listener {@link
+     * SystemStateChangeListenerToService} and dispatches it to a handler provided to the manager.
+     *
+     * @param systemStatus {@link SystemStatusEvent} that has been registered to listen on
+     */
+    private void handleSystemStatusChanged(SystemStatusEvent systemStatus) {
+        // Send a message via the handler.
+        mEventCallbackHandler.sendMessage(
+                mEventCallbackHandler.obtainMessage(MSG_HANDLE_SYSTEM_STATUS_CHANGE, systemStatus));
+    }
+
+    /**
+     * Checks for the listeners to list of {@link SystemStatusEvent} and calls them back in the
+     * callback handler thread.
+     *
+     * @param systemStatus {@link SystemStatusEvent}
+     */
+    private void dispatchSystemStatusToClient(SystemStatusEvent systemStatus) {
+        if (systemStatus == null) {
+            return;
+        }
+
+        synchronized (mLock) {
+            if (mChangeCallback != null) {
+                mChangeCallback.onSystemStateChanged(systemStatus);
+            }
+        }
+    }
+
+    /**
+     * Gets the {@link OccupantAwarenessDetection} from the service listener {@link
+     * DetectionEventListenerToService} and dispatches it to a handler provided to the manager.
+     *
+     * @param detectionEvent {@link OccupantAwarenessDetection} that has been registered to listen
+     *     on
+     */
+    private void handleDetectionEvent(OccupantAwarenessDetection detectionEvent) {
+        // Send a message via the handler.
+        mEventCallbackHandler.sendMessage(
+                mEventCallbackHandler.obtainMessage(MSG_HANDLE_DETECTION_EVENT, detectionEvent));
+    }
+
+    /**
+     * Checks for the listeners to list of {@link
+     * android.car.occupantawareness.OccupantAwarenessDetection} and calls them back in the callback
+     * handler thread.
+     *
+     * @param detectionEvent {@link OccupantAwarenessDetection}
+     */
+    private void dispatchDetectionEventToClient(OccupantAwarenessDetection detectionEvent) {
+        if (detectionEvent == null) {
+            return;
+        }
+
+        ChangeCallback callback;
+
+        synchronized (mLock) {
+            callback = mChangeCallback;
+        }
+
+        if (callback != null) {
+
+            callback.onDetectionEvent(detectionEvent);
+        }
+    }
+
+    /** Callback handler to dispatch system status changes to the corresponding listeners. */
+    private static final class EventCallbackHandler extends Handler {
+        private final WeakReference<OccupantAwarenessManager> mOccupantAwarenessManager;
+
+        EventCallbackHandler(OccupantAwarenessManager manager, Looper looper) {
+            super(looper);
+            mOccupantAwarenessManager = new WeakReference<>(manager);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            OccupantAwarenessManager mgr = mOccupantAwarenessManager.get();
+            if (mgr != null) {
+
+                switch (msg.what) {
+                    case MSG_HANDLE_SYSTEM_STATUS_CHANGE:
+                        mgr.dispatchSystemStatusToClient((SystemStatusEvent) msg.obj);
+                        break;
+
+                    case MSG_HANDLE_DETECTION_EVENT:
+                        mgr.dispatchDetectionEventToClient((OccupantAwarenessDetection) msg.obj);
+                        break;
+
+                    default:
+                        throw new RuntimeException("Unknown message " + msg.what);
+                }
+            }
+        }
+    }
+}
diff --git a/car-lib/src/android/car/occupantawareness/Point3D.aidl b/car-lib/src/android/car/occupantawareness/Point3D.aidl
new file mode 100644
index 0000000..b9ee912
--- /dev/null
+++ b/car-lib/src/android/car/occupantawareness/Point3D.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.occupantawareness;
+
+parcelable Point3D;
diff --git a/car-lib/src/android/car/occupantawareness/Point3D.java b/car-lib/src/android/car/occupantawareness/Point3D.java
new file mode 100644
index 0000000..b3f026d
--- /dev/null
+++ b/car-lib/src/android/car/occupantawareness/Point3D.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.occupantawareness;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A point in 3D space, in millimeters.
+ *
+ * @hide
+ */
+public final class Point3D implements Parcelable {
+    /** The x-component of the point. */
+    public final double x;
+
+    /** The y-component of the point. */
+    public final double y;
+
+    /** The z-component of the point. */
+    public final double z;
+
+    public Point3D(double valueX, double valueY, double valueZ) {
+        x = valueX;
+        y = valueY;
+        z = valueZ;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeDouble(x);
+        dest.writeDouble(y);
+        dest.writeDouble(z);
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%f, %f, %f", x, y, z);
+    }
+
+    public static final @NonNull Parcelable.Creator<Point3D> CREATOR =
+            new Parcelable.Creator<Point3D>() {
+                public Point3D createFromParcel(Parcel in) {
+                    return new Point3D(in);
+                }
+
+                public Point3D[] newArray(int size) {
+                    return new Point3D[size];
+                }
+            };
+
+    private Point3D(Parcel in) {
+        x = in.readDouble();
+        y = in.readDouble();
+        z = in.readDouble();
+    }
+}
diff --git a/car-lib/src/android/car/occupantawareness/SystemStatusEvent.aidl b/car-lib/src/android/car/occupantawareness/SystemStatusEvent.aidl
new file mode 100644
index 0000000..62ca13c
--- /dev/null
+++ b/car-lib/src/android/car/occupantawareness/SystemStatusEvent.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.occupantawareness;
+
+parcelable SystemStatusEvent;
diff --git a/car-lib/src/android/car/occupantawareness/SystemStatusEvent.java b/car-lib/src/android/car/occupantawareness/SystemStatusEvent.java
new file mode 100644
index 0000000..64fffcd
--- /dev/null
+++ b/car-lib/src/android/car/occupantawareness/SystemStatusEvent.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.occupantawareness;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+
+/**
+ * Current system status.
+ *
+ * <p>Detection system may be ready, not-supported, in a failure mode or not-yet-ready.
+ *
+ * @hide
+ */
+public final class SystemStatusEvent implements Parcelable {
+    /** The system is ready to provide data. */
+    public static final int SYSTEM_STATUS_READY = 0;
+
+    /**
+     * Detection is not supported in this vehicle due to a permanent lack of capabilities. Clients
+     * need not retry.
+     */
+    public static final int SYSTEM_STATUS_NOT_SUPPORTED = 1;
+
+    /** The system is not yet ready to serve requests. Clients should check back again later. */
+    public static final int SYSTEM_STATUS_NOT_READY = 2;
+
+    /**
+     * A permanent hardware failure has occurred. Clients need not retry until the underlying
+     * hardware has been fixed.
+     */
+    public static final int SYSTEM_STATUS_SYSTEM_FAILURE = 3;
+
+    /**
+     * System state status values.
+     *
+     * @hide
+     */
+    @Retention(SOURCE)
+    @IntDef({
+        SYSTEM_STATUS_READY,
+        SYSTEM_STATUS_NOT_SUPPORTED,
+        SYSTEM_STATUS_SYSTEM_FAILURE,
+        SYSTEM_STATUS_NOT_READY
+    })
+    public @interface SystemStatus {}
+
+    /** No detection types are supported. */
+    public static final int DETECTION_TYPE_NONE = 0;
+
+    /** Presence detection for occupants in the vehicle. */
+    public static final int DETECTION_TYPE_PRESENCE = 1 << 0;
+
+    /** Gaze data for occupant in the vehicle. */
+    public static final int DETECTION_TYPE_GAZE = 1 << 1;
+
+    /** Driver monitoring state for the driver in the vehicle. */
+    public static final int DETECTION_TYPE_DRIVER_MONITORING = 1 << 2;
+
+    /**
+     * Detection types.
+     *
+     * @hide
+     */
+    @Retention(SOURCE)
+    @IntDef(
+            flag = true,
+            value = {
+                DETECTION_TYPE_PRESENCE,
+                DETECTION_TYPE_GAZE,
+                DETECTION_TYPE_DRIVER_MONITORING
+            })
+    public @interface DetectionTypeFlags {}
+
+    public final @SystemStatus int systemStatus;
+    public final @DetectionTypeFlags int detectionType;
+
+    public SystemStatusEvent(@SystemStatus int status, @DetectionTypeFlags int type) {
+        systemStatus = status;
+        detectionType = type;
+    }
+
+    public SystemStatusEvent() {
+        systemStatus = SYSTEM_STATUS_NOT_READY;
+        detectionType = DETECTION_TYPE_NONE;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(systemStatus);
+        dest.writeInt(detectionType);
+    }
+
+    @Override
+    public String toString() {
+        return "SystemStatusEvent{"
+                + "systemStatus="
+                + systemStatus
+                + ", detectionType="
+                + detectionType
+                + "}";
+    }
+
+    public static final @NonNull Parcelable.Creator<SystemStatusEvent> CREATOR =
+            new Parcelable.Creator<SystemStatusEvent>() {
+                public SystemStatusEvent createFromParcel(Parcel in) {
+                    return new SystemStatusEvent(in);
+                }
+
+                public SystemStatusEvent[] newArray(int size) {
+                    return new SystemStatusEvent[size];
+                }
+            };
+
+    private SystemStatusEvent(Parcel in) {
+        systemStatus = in.readInt();
+        detectionType = in.readInt();
+    }
+}
diff --git a/car-lib/src/android/car/settings/CarConfigurationManager.java b/car-lib/src/android/car/settings/CarConfigurationManager.java
index 626ad39..45b8767 100644
--- a/car-lib/src/android/car/settings/CarConfigurationManager.java
+++ b/car-lib/src/android/car/settings/CarConfigurationManager.java
@@ -23,7 +23,10 @@
 
 /**
  * Manager that exposes car configuration values that are stored on the system.
+ *
+ * @deprecated The {@code CarConfigurationManager} is no longer supported and will be removed.
  */
+@Deprecated
 public class CarConfigurationManager extends CarManagerBase {
     private static final String TAG = "CarConfigurationManager";
 
diff --git a/car-lib/src/android/car/settings/CarSettings.java b/car-lib/src/android/car/settings/CarSettings.java
index 3294071..3f5a6c3 100644
--- a/car-lib/src/android/car/settings/CarSettings.java
+++ b/car-lib/src/android/car/settings/CarSettings.java
@@ -1,73 +1,51 @@
 /*
  * Copyright (C) 2016 The Android Open Source Project
  *
- *   Licensed under the Apache License, Version 2.0 (the "License");
- *   you may not use this file except in compliance with the License.
- *   You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *        http://www.apache.org/licenses/LICENSE-2.0
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
- *   Unless required by applicable law or agreed to in writing, software
- *   distributed under the License is distributed on an "AS IS" BASIS,
- *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *   See the License for the specific language governing permissions and
- *   limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 package android.car.settings;
 
+import android.annotation.SystemApi;
+
 /**
- * System level car related settings.
+ * System-level, car-related settings.
+ *
+ * @hide
  */
+@SystemApi
 public class CarSettings {
 
+    private CarSettings() {
+        throw new UnsupportedOperationException("this class only provide constants");
+    }
+
     /**
      * Global car settings, containing preferences that always apply identically
      * to all defined users.  Applications can read these but are not allowed to write;
      * like the "Secure" settings, these are for preferences that the user must
      * explicitly modify through the system UI or specialized APIs for those values.
      *
-     * To read/write the global car settings, use {@link android.provider.Settings.Global}
+     * <p>To read/write the global car settings, use {@link android.provider.Settings.Global}
      * with the keys defined here.
+     *
+     * @hide
      */
     public static final class Global {
-        /**
-         * DEPRECATED. Will be removed in Q. Key for when to wake up to run garage mode.
-         * @deprecated not used by GarageMode anymore. Will be removed in Q.
-         */
-        @Deprecated
-        public static final String KEY_GARAGE_MODE_WAKE_UP_TIME =
-                "android.car.GARAGE_MODE_WAKE_UP_TIME";
-        /**
-         * DEPRECATED. Will be removed in Q. Key for whether garage mode is enabled.
-         * @deprecated not used by GarageMode anymore. Will be removed in Q.
-         */
-        @Deprecated
-        public static final String KEY_GARAGE_MODE_ENABLED = "android.car.GARAGE_MODE_ENABLED";
 
-        /**
-         * DEPRECATED. Will be removed in Q. Key for garage mode maintenance window.
-         * @deprecated not used by GarageMode anymore. Will be removed in Q.
-         */
-        @Deprecated
-        public static final String KEY_GARAGE_MODE_MAINTENANCE_WINDOW =
-                "android.car.GARAGE_MODE_MAINTENANCE_WINDOW";
-
-        /**
-         * Key for default user id to boot into.
-         *
-         * @hide
-         */
-        public static final String DEFAULT_USER_ID_TO_BOOT_INTO =
-                "android.car.DEFAULT_BOOT_INTO_USER_ID";
-
-        /**
-         * Key for user id that is last logged in to.
-         *
-         * @hide
-         */
-        public static final String LAST_ACTIVE_USER_ID =
-                "android.car.LAST_ACTIVE_USER_ID";
+        private Global() {
+            throw new UnsupportedOperationException("this class only provide constants");
+        }
 
         /**
          * Whether default restrictions for users have been set.
@@ -78,6 +56,15 @@
                 "android.car.DEFAULT_USER_RESTRICTIONS_SET";
 
         /**
+         * Developer settings String used to explicitly disable the instrumentation service (when
+         * set to {@code "true"}.
+         *
+         * @hide
+         */
+        public static final String DISABLE_INSTRUMENTATION_SERVICE =
+                "android.car.DISABLE_INSTRUMENTATION_SERVICE";
+
+        /**
          * Developer settings String used to explicitly enable the user switch message when
          * set to {@code "true"}.
          *
@@ -85,6 +72,32 @@
          */
         public static final String ENABLE_USER_SWITCH_DEVELOPER_MESSAGE =
                 "android.car.ENABLE_USER_SWITCH_DEVELOPER_MESSAGE";
+
+        /**
+         * User id of the last foreground user
+         *
+         * @hide
+         */
+        public static final String LAST_ACTIVE_USER_ID =
+                        "android.car.LAST_ACTIVE_USER_ID";
+
+        /**
+         * User id of the last persistent (i.e, not counting ephemeral guests) foreground user
+         *
+         * @hide
+         */
+        public static final String LAST_ACTIVE_PERSISTENT_USER_ID =
+                        "android.car.LAST_ACTIVE_PERSISTENT_USER_ID";
+
+        /**
+         * Defines global runtime overrides to system bar policy.
+         *
+         * See {@link com.android.systemui.wm.BarControlPolicy} for value format.
+         *
+         * @hide
+         */
+        public static final String SYSTEM_BAR_VISIBILITY_OVERRIDE =
+                "android.car.SYSTEM_BAR_VISIBILITY_OVERRIDE";
     }
 
     /**
@@ -104,8 +117,33 @@
     /**
      * @hide
      */
+    @SystemApi
     public static final class Secure {
 
+        private Secure() {
+            throw new UnsupportedOperationException("this class only provide constants");
+        }
+
+        /**
+         * Key to indicate whether audio focus requests for
+         * {@link android.hardware.automotive.audiocontrol.V1_0.ContextNumber.NAVIGATION} should
+         * be rejected if focus is currently held by
+         * {@link android.hardware.automotive.audiocontrol.V1_0.ContextNumber.CALL}.
+         * <p>The value is a boolean (1 or 0) where:
+         * <ul>
+         * <li>1 indicates {@code NAVIGATION} should be rejected when a {@code CALL} is in progress.
+         * <li>0 indicates {@code NAVIGATION} and {@code CALL} should be allowed to hold focus
+         * concurrently.
+         * </ul>
+         *
+         * <p>Recommended {@code false} as default value.
+         *
+         * @hide
+         */
+        @SystemApi
+        public static final String KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL =
+                "android.car.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL";
+
         /**
          * Key for a list of devices to automatically connect on Bluetooth A2DP Sink profile
          * Written to and read by {@link com.android.car.BluetoothDeviceConnectionPolicy}
diff --git a/car-lib/src/android/car/settings/ICarConfigurationManager.aidl b/car-lib/src/android/car/settings/ICarConfigurationManager.aidl
index 5fe4088..ea53998 100644
--- a/car-lib/src/android/car/settings/ICarConfigurationManager.aidl
+++ b/car-lib/src/android/car/settings/ICarConfigurationManager.aidl
@@ -22,6 +22,7 @@
  * Binder interface for {@link android.car.settings.CarConfigurationManager}.
  *
  * @hide
+ * @deprecated Configuration of speed bump is no longer a supported feature.
  */
 interface ICarConfigurationManager {
     /**
diff --git a/car-lib/src/android/car/settings/SpeedBumpConfiguration.java b/car-lib/src/android/car/settings/SpeedBumpConfiguration.java
index 39a1eab..ee090f5 100644
--- a/car-lib/src/android/car/settings/SpeedBumpConfiguration.java
+++ b/car-lib/src/android/car/settings/SpeedBumpConfiguration.java
@@ -25,7 +25,9 @@
  * A configuration struct that holds information for tweaking SpeedBump settings.
  *
  * @see androidx.car.moderator.SpeedBumpView
+ * @deprecated Speed bump configuration is no longer a support feature.
  */
+@Deprecated
 public final class SpeedBumpConfiguration implements Parcelable {
     private final double mAcquiredPermitsPerSecond;
     private final double mMaxPermitPool;
diff --git a/car-lib/src/android/car/storagemonitoring/CarStorageMonitoringManager.java b/car-lib/src/android/car/storagemonitoring/CarStorageMonitoringManager.java
index 69c092b..6f993e3 100644
--- a/car-lib/src/android/car/storagemonitoring/CarStorageMonitoringManager.java
+++ b/car-lib/src/android/car/storagemonitoring/CarStorageMonitoringManager.java
@@ -19,6 +19,7 @@
 import android.annotation.SystemApi;
 import android.car.Car;
 import android.car.CarManagerBase;
+import android.car.annotation.RequiredFeature;
 import android.os.IBinder;
 import android.os.RemoteException;
 
@@ -36,6 +37,7 @@
  * @hide
  */
 @SystemApi
+@RequiredFeature(Car.STORAGE_MONITORING_SERVICE)
 public final class CarStorageMonitoringManager extends CarManagerBase {
     private static final String TAG = CarStorageMonitoringManager.class.getSimpleName();
     private static final int MSG_IO_STATS_EVENT = 0;
@@ -45,9 +47,17 @@
     private final SingleMessageHandler<IoStats> mMessageHandler;
     private final Set<IoStatsListener> mListeners = new HashSet<>();
 
+    /**
+     * Implementers will be notified on every new I/O activity calculated stats.
+     */
     public interface IoStatsListener {
+
+        /**
+         * Invoked when a new periodic snapshot delta of I/O activities is calculated.
+         */
         void onSnapshot(IoStats snapshot);
     }
+
     private static final class ListenerToService extends IIoStatsListener.Stub {
         private final WeakReference<CarStorageMonitoringManager> mManager;
 
@@ -107,7 +117,7 @@
      * It will return either PRE_EOL_INFO_UNKNOWN if the value can't be determined,
      * or one of PRE_EOL_INFO_{NORMAL|WARNING|URGENT} depending on the device state.
      */
-    @RequiresPermission(value=Car.PERMISSION_STORAGE_MONITORING)
+    @RequiresPermission(value = Car.PERMISSION_STORAGE_MONITORING)
     public int getPreEolIndicatorStatus() {
         try {
             return mService.getPreEolIndicatorStatus();
@@ -125,7 +135,7 @@
      *
      * If either or both indicators are not available, they will be reported as UNKNOWN.
      */
-    @RequiresPermission(value=Car.PERMISSION_STORAGE_MONITORING)
+    @RequiresPermission(value = Car.PERMISSION_STORAGE_MONITORING)
     public WearEstimate getWearEstimate() {
         try {
             return mService.getWearEstimate();
@@ -145,7 +155,7 @@
      *
      * If no indicators are available, an empty list will be returned.
      */
-    @RequiresPermission(value=Car.PERMISSION_STORAGE_MONITORING)
+    @RequiresPermission(value = Car.PERMISSION_STORAGE_MONITORING)
     public List<WearEstimateChange> getWearEstimateHistory() {
         try {
             return mService.getWearEstimateHistory();
@@ -164,7 +174,7 @@
      *
      * If the information is not available, an empty list will be returned.
      */
-    @RequiresPermission(value=Car.PERMISSION_STORAGE_MONITORING)
+    @RequiresPermission(value = Car.PERMISSION_STORAGE_MONITORING)
     public List<IoStatsEntry> getBootIoStats() {
         try {
             return mService.getBootIoStats();
@@ -194,7 +204,7 @@
      *
      * <p>If the information is not available, SHUTDOWN_COST_INFO_MISSING will be returned.</p>s
      */
-    @RequiresPermission(value=Car.PERMISSION_STORAGE_MONITORING)
+    @RequiresPermission(value = Car.PERMISSION_STORAGE_MONITORING)
     public long getShutdownDiskWriteAmount() {
         try {
             return mService.getShutdownDiskWriteAmount();
@@ -211,7 +221,7 @@
      *
      * If the information is not available, an empty list will be returned.
      */
-    @RequiresPermission(value=Car.PERMISSION_STORAGE_MONITORING)
+    @RequiresPermission(value = Car.PERMISSION_STORAGE_MONITORING)
     public List<IoStatsEntry> getAggregateIoStats() {
         try {
             return mService.getAggregateIoStats();
@@ -231,7 +241,7 @@
      *
      * If the information is not available, an empty list will be returned.
      */
-    @RequiresPermission(value=Car.PERMISSION_STORAGE_MONITORING)
+    @RequiresPermission(value = Car.PERMISSION_STORAGE_MONITORING)
     public List<IoStats> getIoStatsDeltas() {
         try {
             return mService.getIoStatsDeltas();
@@ -248,7 +258,7 @@
      *
      * The timing of availability of the deltas is configurable by the OEM.
      */
-    @RequiresPermission(value=Car.PERMISSION_STORAGE_MONITORING)
+    @RequiresPermission(value = Car.PERMISSION_STORAGE_MONITORING)
     public void registerListener(IoStatsListener listener) {
         try {
             if (mListeners.isEmpty()) {
@@ -266,7 +276,7 @@
     /**
      * This method removes a registered listener of I/O stats deltas.
      */
-    @RequiresPermission(value=Car.PERMISSION_STORAGE_MONITORING)
+    @RequiresPermission(value = Car.PERMISSION_STORAGE_MONITORING)
     public void unregisterListener(IoStatsListener listener) {
         try {
             if (!mListeners.remove(listener)) {
diff --git a/car-lib/src/android/car/storagemonitoring/IoStats.java b/car-lib/src/android/car/storagemonitoring/IoStats.java
index d620169..5154196 100644
--- a/car-lib/src/android/car/storagemonitoring/IoStats.java
+++ b/car-lib/src/android/car/storagemonitoring/IoStats.java
@@ -70,7 +70,7 @@
         mUptimeTimestamp = in.getInt("uptime");
         JSONArray statsArray = in.getJSONArray("stats");
         mStats = new ArrayList<>();
-        for(int i = 0; i < statsArray.length(); ++i) {
+        for (int i = 0; i < statsArray.length(); ++i) {
             mStats.add(new IoStatsEntry(statsArray.getJSONObject(i)));
         }
     }
@@ -113,6 +113,11 @@
         return Objects.hash(mStats, mUptimeTimestamp);
     }
 
+    /**
+     * Returns user's stats ({@link IoStatsEntry}).
+     *
+     * @param uid Android's user id
+     */
     public IoStatsEntry getUserIdStats(int uid) {
         for (IoStatsEntry stats : getStats()) {
             if (stats.uid == uid) {
@@ -123,6 +128,10 @@
         return null;
     }
 
+    /**
+     * Returns the following foreground total metrics: bytes written and read, bytes read from and
+     * written to storage, and number of sync calls.
+     */
     public IoStatsEntry.Metrics getForegroundTotals() {
         long bytesRead = 0;
         long bytesWritten = 0;
@@ -145,6 +154,10 @@
                 fsyncCalls);
     }
 
+    /**
+     * Returns the following background total metrics: bytes written and read, bytes read from and
+     * written to storage, and number of sync calls.
+     */
     public IoStatsEntry.Metrics getBackgroundTotals() {
         long bytesRead = 0;
         long bytesWritten = 0;
@@ -167,6 +180,10 @@
             fsyncCalls);
     }
 
+    /**
+     * Returns the sum of all foreground and background metrics (bytes written, bytes read from
+     * storage, bytes written to storage and number of sync calls).
+     */
     public IoStatsEntry.Metrics getTotals() {
         IoStatsEntry.Metrics foreground = getForegroundTotals();
         IoStatsEntry.Metrics background = getBackgroundTotals();
@@ -181,9 +198,9 @@
     @Override
     public boolean equals(Object other) {
         if (other instanceof IoStats) {
-            IoStats delta = (IoStats)other;
-            return delta.getTimestamp() == getTimestamp() &&
-                delta.getStats().equals(getStats());
+            IoStats delta = (IoStats) other;
+            return delta.getTimestamp() == getTimestamp()
+                && delta.getStats().equals(getStats());
         }
         return false;
     }
diff --git a/car-lib/src/android/car/storagemonitoring/IoStatsEntry.java b/car-lib/src/android/car/storagemonitoring/IoStatsEntry.java
index b187139..bcee900 100644
--- a/car-lib/src/android/car/storagemonitoring/IoStatsEntry.java
+++ b/car-lib/src/android/car/storagemonitoring/IoStatsEntry.java
@@ -38,15 +38,16 @@
 public final class IoStatsEntry implements Parcelable {
 
     public static final Parcelable.Creator<IoStatsEntry> CREATOR =
-        new Parcelable.Creator<IoStatsEntry>() {
-            public IoStatsEntry createFromParcel(Parcel in) {
-                return new IoStatsEntry(in);
-            }
+            new Parcelable.Creator<IoStatsEntry>() {
 
-            public IoStatsEntry[] newArray(int size) {
-                return new IoStatsEntry[size];
-            }
-        };
+        public IoStatsEntry createFromParcel(Parcel in) {
+            return new IoStatsEntry(in);
+        }
+
+        public IoStatsEntry[] newArray(int size) {
+            return new IoStatsEntry[size];
+        }
+    };
 
     /**
      * The user id that this object contains metrics for.
@@ -161,14 +162,13 @@
     @Override
     public boolean equals(Object other) {
         if (other instanceof IoStatsEntry) {
-            IoStatsEntry uidIoStatEntry = (IoStatsEntry)other;
+            IoStatsEntry uidIoStatEntry = (IoStatsEntry) other;
 
-            return uid == uidIoStatEntry.uid &&
-                    runtimeMillis == uidIoStatEntry.runtimeMillis &&
-                    foreground.equals(uidIoStatEntry.foreground) &&
-                    background.equals(uidIoStatEntry.background);
+            return uid == uidIoStatEntry.uid
+                    && runtimeMillis == uidIoStatEntry.runtimeMillis
+                    && foreground.equals(uidIoStatEntry.foreground)
+                    && background.equals(uidIoStatEntry.background);
         }
-
         return false;
     }
 
@@ -190,17 +190,17 @@
      * @hide
      */
     public boolean representsSameMetrics(UidIoRecord record) {
-        return record.uid == uid &&
-               record.foreground_rchar == foreground.bytesRead &&
-               record.foreground_wchar == foreground.bytesWritten &&
-               record.foreground_read_bytes == foreground.bytesReadFromStorage &&
-               record.foreground_write_bytes == foreground.bytesWrittenToStorage &&
-               record.foreground_fsync == foreground.fsyncCalls &&
-               record.background_rchar == background.bytesRead &&
-               record.background_wchar == background.bytesWritten &&
-               record.background_read_bytes == background.bytesReadFromStorage &&
-               record.background_write_bytes == background.bytesWrittenToStorage &&
-               record.background_fsync == background.fsyncCalls;
+        return record.uid == uid
+                && record.foreground_rchar == foreground.bytesRead
+                && record.foreground_wchar == foreground.bytesWritten
+                && record.foreground_read_bytes == foreground.bytesReadFromStorage
+                && record.foreground_write_bytes == foreground.bytesWrittenToStorage
+                && record.foreground_fsync == foreground.fsyncCalls
+                && record.background_rchar == background.bytesRead
+                && record.background_wchar == background.bytesWritten
+                && record.background_read_bytes == background.bytesReadFromStorage
+                && record.background_write_bytes == background.bytesWrittenToStorage
+                && record.background_fsync == background.fsyncCalls;
     }
 
     /**
@@ -209,15 +209,15 @@
     public static final class Metrics implements Parcelable {
 
         public static final Parcelable.Creator<IoStatsEntry.Metrics> CREATOR =
-            new Parcelable.Creator<IoStatsEntry.Metrics>() {
-                public IoStatsEntry.Metrics createFromParcel(Parcel in) {
-                    return new IoStatsEntry.Metrics(in);
-                }
+                new Parcelable.Creator<IoStatsEntry.Metrics>() {
+            public IoStatsEntry.Metrics createFromParcel(Parcel in) {
+                return new IoStatsEntry.Metrics(in);
+            }
 
-                public IoStatsEntry.Metrics[] newArray(int size) {
-                    return new IoStatsEntry.Metrics[size];
-                }
-            };
+            public IoStatsEntry.Metrics[] newArray(int size) {
+                return new IoStatsEntry.Metrics[size];
+            }
+        };
 
         /**
          * Total bytes that processes running on behalf of this user obtained
@@ -249,7 +249,7 @@
         public final long fsyncCalls;
 
         public Metrics(long bytesRead, long bytesWritten, long bytesReadFromStorage,
-            long bytesWrittenToStorage, long fsyncCalls) {
+                long bytesWrittenToStorage, long fsyncCalls) {
             this.bytesRead = bytesRead;
             this.bytesWritten = bytesWritten;
             this.bytesReadFromStorage = bytesReadFromStorage;
@@ -313,23 +313,23 @@
          * @hide
          */
         public Metrics delta(Metrics other) {
-            return new Metrics(bytesRead-other.bytesRead,
-                bytesWritten-other.bytesWritten,
-                bytesReadFromStorage-other.bytesReadFromStorage,
-                bytesWrittenToStorage-other.bytesWrittenToStorage,
-                fsyncCalls-other.fsyncCalls);
+            return new Metrics(bytesRead - other.bytesRead,
+                bytesWritten - other.bytesWritten,
+                bytesReadFromStorage - other.bytesReadFromStorage,
+                bytesWrittenToStorage - other.bytesWrittenToStorage,
+                fsyncCalls - other.fsyncCalls);
         }
 
         @Override
         public boolean equals(Object other) {
             if (other instanceof Metrics) {
-                Metrics metrics = (Metrics)other;
+                Metrics metrics = (Metrics) other;
 
-                return (bytesRead == metrics.bytesRead) &&
-                    (bytesWritten == metrics.bytesWritten) &&
-                    (bytesReadFromStorage == metrics.bytesReadFromStorage) &&
-                    (bytesWrittenToStorage == metrics.bytesWrittenToStorage) &&
-                    (fsyncCalls == metrics.fsyncCalls);
+                return (bytesRead == metrics.bytesRead)
+                    && (bytesWritten == metrics.bytesWritten)
+                    && (bytesReadFromStorage == metrics.bytesReadFromStorage)
+                    && (bytesWrittenToStorage == metrics.bytesWrittenToStorage)
+                    && (fsyncCalls == metrics.fsyncCalls);
             }
             return false;
         }
@@ -342,8 +342,9 @@
 
         @Override
         public String toString() {
-            return String.format("bytesRead=%d, bytesWritten=%d, bytesReadFromStorage=%d, bytesWrittenToStorage=%d, fsyncCalls=%d",
-                bytesRead, bytesWritten, bytesReadFromStorage, bytesWrittenToStorage, fsyncCalls);
+            return String.format("bytesRead=%d, bytesWritten=%d, bytesReadFromStorage=%d, "
+                    + "bytesWrittenToStorage=%d, fsyncCalls=%d", bytesRead, bytesWritten,
+                    bytesReadFromStorage, bytesWrittenToStorage, fsyncCalls);
         }
     }
 }
diff --git a/car-lib/src/android/car/storagemonitoring/LifetimeWriteInfo.java b/car-lib/src/android/car/storagemonitoring/LifetimeWriteInfo.java
index b835950..7f811c8 100644
--- a/car-lib/src/android/car/storagemonitoring/LifetimeWriteInfo.java
+++ b/car-lib/src/android/car/storagemonitoring/LifetimeWriteInfo.java
@@ -101,10 +101,10 @@
     @Override
     public boolean equals(Object other) {
         if (other instanceof LifetimeWriteInfo) {
-            LifetimeWriteInfo lifetime = (LifetimeWriteInfo)other;
-            return partition.equals(lifetime.partition) &&
-                    fstype.equals(lifetime.fstype) &&
-                    writtenBytes == lifetime.writtenBytes;
+            LifetimeWriteInfo lifetime = (LifetimeWriteInfo) other;
+            return partition.equals(lifetime.partition)
+                    && fstype.equals(lifetime.fstype)
+                    && writtenBytes == lifetime.writtenBytes;
         }
 
         return false;
diff --git a/car-lib/src/android/car/storagemonitoring/WearEstimate.java b/car-lib/src/android/car/storagemonitoring/WearEstimate.java
index ee6aa31..07ef4c7 100644
--- a/car-lib/src/android/car/storagemonitoring/WearEstimate.java
+++ b/car-lib/src/android/car/storagemonitoring/WearEstimate.java
@@ -47,11 +47,10 @@
     public static final WearEstimate UNKNOWN_ESTIMATE = new WearEstimate(UNKNOWN, UNKNOWN);
 
     public static final Parcelable.Creator<WearEstimate> CREATOR =
-        new Parcelable.Creator<WearEstimate>() {
-            public WearEstimate createFromParcel(Parcel in) {
+            new Parcelable.Creator<WearEstimate>() {
+        public WearEstimate createFromParcel(Parcel in) {
                 return new WearEstimate(in);
             }
-
             public WearEstimate[] newArray(int size) {
                 return new WearEstimate[size];
             }
@@ -60,16 +59,16 @@
     /**
      * Wear estimate data for "type A" storage.
      */
-    @IntRange(from=-1, to=100)
+    @IntRange(from = -1, to = 100)
     public final int typeA;
 
     /**
      * Wear estimate data for "type B" storage.
      */
-    @IntRange(from=-1, to=100)
+    @IntRange(from = -1, to = 100)
     public final int typeB;
 
-    private static final int validateWearValue(int value) {
+    private static int validateWearValue(int value) {
         if (value == UNKNOWN) return value;
         if ((value >= 0) && (value <= 100)) return value;
         throw new IllegalArgumentException(value + " is not a valid wear estimate");
@@ -137,7 +136,7 @@
     @Override
     public boolean equals(Object other) {
         if (other instanceof WearEstimate) {
-            WearEstimate wo = (WearEstimate)other;
+            WearEstimate wo = (WearEstimate) other;
             return wo.typeA == typeA && wo.typeB == typeB;
         }
         return false;
@@ -148,7 +147,7 @@
         return Objects.hash(typeA, typeB);
     }
 
-    private static final String wearValueToString(int value) {
+    private static String wearValueToString(int value) {
         if (value == UNKNOWN) return "unknown";
         return value + "%";
     }
diff --git a/car-lib/src/android/car/storagemonitoring/WearEstimateChange.java b/car-lib/src/android/car/storagemonitoring/WearEstimateChange.java
index 2d454b4..a2839d5 100644
--- a/car-lib/src/android/car/storagemonitoring/WearEstimateChange.java
+++ b/car-lib/src/android/car/storagemonitoring/WearEstimateChange.java
@@ -15,15 +15,16 @@
  */
 package android.car.storagemonitoring;
 
+import static java.util.Objects.requireNonNull;
+
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
+
 import java.time.Instant;
 import java.util.Objects;
 
-import static java.util.Objects.requireNonNull;
-
 /**
  * Change in wear-out information.
  *
@@ -35,15 +36,15 @@
 @SystemApi
 public final class WearEstimateChange implements Parcelable {
     public static final Parcelable.Creator<WearEstimateChange> CREATOR =
-        new Parcelable.Creator<WearEstimateChange>() {
-            public WearEstimateChange createFromParcel(Parcel in) {
-                return new WearEstimateChange(in);
-            }
+            new Parcelable.Creator<WearEstimateChange>() {
+        public WearEstimateChange createFromParcel(Parcel in) {
+            return new WearEstimateChange(in);
+        }
 
-            public WearEstimateChange[] newArray(int size) {
+        public WearEstimateChange[] newArray(int size) {
                 return new WearEstimateChange[size];
             }
-        };
+    };
 
     /**
      * The previous wear estimate.
@@ -110,12 +111,12 @@
     @Override
     public boolean equals(Object other) {
         if (other instanceof WearEstimateChange) {
-            WearEstimateChange wo = (WearEstimateChange)other;
-            return wo.isAcceptableDegradation == isAcceptableDegradation &&
-                wo.uptimeAtChange == uptimeAtChange &&
-                wo.dateAtChange.equals(dateAtChange) &&
-                wo.oldEstimate.equals(oldEstimate) &&
-                wo.newEstimate.equals(newEstimate);
+            WearEstimateChange wo = (WearEstimateChange) other;
+            return wo.isAcceptableDegradation == isAcceptableDegradation
+                    && wo.uptimeAtChange == uptimeAtChange
+                    && wo.dateAtChange.equals(dateAtChange)
+                    && wo.oldEstimate.equals(oldEstimate)
+                    && wo.newEstimate.equals(newEstimate);
         }
         return false;
     }
diff --git a/car-lib/src/android/car/trust/CarTrustAgentEnrollmentManager.java b/car-lib/src/android/car/trust/CarTrustAgentEnrollmentManager.java
index 9881420..c4e1989 100644
--- a/car-lib/src/android/car/trust/CarTrustAgentEnrollmentManager.java
+++ b/car-lib/src/android/car/trust/CarTrustAgentEnrollmentManager.java
@@ -66,7 +66,11 @@
  * </ol>
  *
  * @hide
+ *
+ * @deprecated Enrollment of a trusted device is no longer a supported feature and these APIs will
+ * be removed in the next Android release.
  */
+@Deprecated
 @SystemApi
 public final class CarTrustAgentEnrollmentManager extends CarManagerBase {
     private static final String TAG = "CarTrustEnrollMgr";
diff --git a/car-lib/src/android/car/trust/ICarTrustAgentBleCallback.aidl b/car-lib/src/android/car/trust/ICarTrustAgentBleCallback.aidl
index f83cd23..0678db8 100644
--- a/car-lib/src/android/car/trust/ICarTrustAgentBleCallback.aidl
+++ b/car-lib/src/android/car/trust/ICarTrustAgentBleCallback.aidl
@@ -22,6 +22,8 @@
  * Callback interface for BLE connection state changes during trusted device enrollment.
  *
  * @hide
+ * @deprecated Adding a trust agent is no longer a supported feature and these APIs will be removed
+ * in the next Android release.
  */
 oneway interface ICarTrustAgentBleCallback {
     /**
diff --git a/car-lib/src/android/car/trust/ICarTrustAgentEnrollment.aidl b/car-lib/src/android/car/trust/ICarTrustAgentEnrollment.aidl
index 27b8a3f..485b77e 100644
--- a/car-lib/src/android/car/trust/ICarTrustAgentEnrollment.aidl
+++ b/car-lib/src/android/car/trust/ICarTrustAgentEnrollment.aidl
@@ -26,6 +26,8 @@
  * to communicate with the remote device securely to enroll the remote device as a trusted device.
  *
  * @hide
+ * @deprecated Enrolling a trusted device is no longer a supported feature and these APIs will be
+ * removed in the next Android release.
  */
 interface ICarTrustAgentEnrollment {
     void startEnrollmentAdvertising();
diff --git a/car-lib/src/android/car/trust/ICarTrustAgentEnrollmentCallback.aidl b/car-lib/src/android/car/trust/ICarTrustAgentEnrollmentCallback.aidl
index 8cfc983..b151958 100644
--- a/car-lib/src/android/car/trust/ICarTrustAgentEnrollmentCallback.aidl
+++ b/car-lib/src/android/car/trust/ICarTrustAgentEnrollmentCallback.aidl
@@ -22,6 +22,8 @@
  * Callback interface for state changes during Trusted device enrollment.
  *
  * @hide
+ * @deprecated Enrolling a trusted device is no longer a supported feature and these APIs will be
+ * removed in the next Android release.
  */
 oneway interface ICarTrustAgentEnrollmentCallback {
     /**
diff --git a/car-lib/src/android/car/trust/TrustedDeviceInfo.aidl b/car-lib/src/android/car/trust/TrustedDeviceInfo.aidl
index 510dbc9..8dc558c 100644
--- a/car-lib/src/android/car/trust/TrustedDeviceInfo.aidl
+++ b/car-lib/src/android/car/trust/TrustedDeviceInfo.aidl
@@ -1,3 +1,3 @@
 package android.car.trust;
 
-parcelable TrustedDeviceInfo;
\ No newline at end of file
+parcelable TrustedDeviceInfo;
diff --git a/car-lib/src/android/car/trust/TrustedDeviceInfo.java b/car-lib/src/android/car/trust/TrustedDeviceInfo.java
index 418bede..1f44a83 100644
--- a/car-lib/src/android/car/trust/TrustedDeviceInfo.java
+++ b/car-lib/src/android/car/trust/TrustedDeviceInfo.java
@@ -28,7 +28,10 @@
  * Contains basic info of a trusted device.
  *
  * @hide
+ * @deprecated Adding a trusted device is no longer a supported feature and these APIs will be
+ * removed in the next Android release.
  */
+@Deprecated
 @SystemApi
 public final class TrustedDeviceInfo implements Parcelable {
 
diff --git a/car-lib/src/android/car/user/CarUserManager.java b/car-lib/src/android/car/user/CarUserManager.java
new file mode 100644
index 0000000..62ae7e0
--- /dev/null
+++ b/car-lib/src/android/car/user/CarUserManager.java
@@ -0,0 +1,796 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.user;
+
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.os.Process.myUid;
+
+import static com.android.internal.util.FunctionalUtils.getLambdaName;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.annotation.UserIdInt;
+import android.car.Car;
+import android.car.CarManagerBase;
+import android.car.ICarUserService;
+import android.content.pm.UserInfo;
+import android.content.pm.UserInfo.UserInfoFlag;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.sysprop.CarProperties;
+import android.util.ArrayMap;
+import android.util.EventLog;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.car.EventLogTags;
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.stream.Collectors;
+
+/**
+ * API to manage users related to car.
+ *
+ * @hide
+ */
+@SystemApi
+@TestApi
+public final class CarUserManager extends CarManagerBase {
+
+    private static final String TAG = CarUserManager.class.getSimpleName();
+    private static final int HAL_TIMEOUT_MS = CarProperties.user_hal_timeout().orElse(5_000);
+
+    private static final boolean DBG = false;
+
+    /**
+     * {@link UserLifecycleEvent} called when the user is starting, for components to initialize
+     * any per-user state they maintain for running users.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final int USER_LIFECYCLE_EVENT_TYPE_STARTING = 1;
+
+    /**
+     * {@link UserLifecycleEvent} called when switching to a different foreground user, for
+     * components that have special behavior for whichever user is currently in the foreground.
+     *
+     * <p>This is called before any application processes are aware of the new user.
+     *
+     * <p>Notice that internal system services might not have handled user switching yet, so be
+     * careful with interaction with them.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final int USER_LIFECYCLE_EVENT_TYPE_SWITCHING = 2;
+
+    /**
+     * {@link UserLifecycleEvent} called when an existing user is in the process of being unlocked.
+     *
+     * <p>This means the credential-encrypted storage for that user is now available, and
+     * encryption-aware component filtering is no longer in effect.
+     *
+     * <p>Notice that internal system services might not have handled unlock yet, so most components
+     * should ignore this callback and rely on {@link #USER_LIFECYCLE_EVENT_TYPE_UNLOCKED} instead.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final int USER_LIFECYCLE_EVENT_TYPE_UNLOCKING = 3;
+
+    /**
+     * {@link UserLifecycleEvent} called after an existing user is unlocked.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final int USER_LIFECYCLE_EVENT_TYPE_UNLOCKED = 4;
+
+    /**
+     * {@link UserLifecycleEvent} called when an existing user is stopping, for components to
+     * finalize any per-user state they maintain for running users.
+     *
+     * <p>This is called prior to sending the {@code SHUTDOWN} broadcast to the user; it is a good
+     * place to stop making use of any resources of that user (such as binding to a service running
+     * in the user).
+     *
+     * <p><b>Note:</b> this is the last callback where the callee may access the target user's CE
+     * storage.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPING = 5;
+
+    /**
+     * {@link UserLifecycleEvent} called after an existing user is stopped.
+     *
+     * <p>This is called after all application process teardown of the user is complete.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPED = 6;
+
+    /** @hide */
+    @IntDef(prefix = { "USER_LIFECYCLE_EVENT_TYPE_" }, value = {
+            USER_LIFECYCLE_EVENT_TYPE_STARTING,
+            USER_LIFECYCLE_EVENT_TYPE_SWITCHING,
+            USER_LIFECYCLE_EVENT_TYPE_UNLOCKING,
+            USER_LIFECYCLE_EVENT_TYPE_UNLOCKED,
+            USER_LIFECYCLE_EVENT_TYPE_STOPPING,
+            USER_LIFECYCLE_EVENT_TYPE_STOPPED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface UserLifecycleEventType{}
+
+    /** @hide */
+    public static final String BUNDLE_PARAM_ACTION = "action";
+    /** @hide */
+    public static final String BUNDLE_PARAM_PREVIOUS_USER_ID = "previous_user";
+
+    private final Object mLock = new Object();
+    private final ICarUserService mService;
+    private final UserManager mUserManager;
+
+    @Nullable
+    @GuardedBy("mLock")
+    private ArrayMap<UserLifecycleListener, Executor> mListeners;
+
+    @Nullable
+    @GuardedBy("mLock")
+    private LifecycleResultReceiver mReceiver;
+
+    /**
+     * @hide
+     */
+    public CarUserManager(@NonNull Car car, @NonNull IBinder service) {
+        this(car, ICarUserService.Stub.asInterface(service), UserManager.get(car.getContext()));
+    }
+
+    /**
+     * @hide
+     */
+    @VisibleForTesting
+    public CarUserManager(@NonNull Car car, @NonNull ICarUserService service,
+            @NonNull UserManager userManager) {
+        super(car);
+        mService = service;
+        mUserManager = userManager;
+    }
+
+    /**
+     * Switches the foreground user to the given target user.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public AndroidFuture<UserSwitchResult> switchUser(@UserIdInt int targetUserId) {
+        int uid = myUid();
+
+        if (mUserManager.getUserSwitchability() != UserManager.SWITCHABILITY_STATUS_OK) {
+            return newSwitchResuiltForFailure(UserSwitchResult.STATUS_NOT_SWITCHABLE);
+        }
+
+        try {
+            AndroidFuture<UserSwitchResult> future = new AndroidFuture<UserSwitchResult>() {
+                @Override
+                protected void onCompleted(UserSwitchResult result, Throwable err) {
+                    if (result != null) {
+                        EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SWITCH_USER_RESP, uid,
+                                result.getStatus(), result.getErrorMessage());
+                    } else {
+                        Log.w(TAG, "switchUser(" + targetUserId + ") failed: " + err);
+                    }
+                    super.onCompleted(result, err);
+                }
+            };
+            EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SWITCH_USER_REQ, uid, targetUserId);
+            mService.switchUser(targetUserId, HAL_TIMEOUT_MS, future);
+            return future;
+        } catch (RemoteException e) {
+            AndroidFuture<UserSwitchResult> future =
+                    newSwitchResuiltForFailure(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
+            return handleRemoteExceptionFromCarService(e, future);
+        }
+    }
+
+    private AndroidFuture<UserSwitchResult> newSwitchResuiltForFailure(
+            @UserSwitchResult.Status int status) {
+        AndroidFuture<UserSwitchResult> future = new AndroidFuture<>();
+        future.complete(new UserSwitchResult(status, null));
+        return future;
+    }
+
+    /**
+     * Creates a new Android user.
+     *
+     * @hide
+     */
+    @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.CREATE_USERS})
+    public AndroidFuture<UserCreationResult> createUser(@Nullable String name,
+            @NonNull String userType, @UserInfoFlag int flags) {
+        int uid = myUid();
+        try {
+            AndroidFuture<UserCreationResult> future = new AndroidFuture<UserCreationResult>() {
+                @Override
+                protected void onCompleted(UserCreationResult result, Throwable err) {
+                    if (result != null) {
+                        EventLog.writeEvent(EventLogTags.CAR_USER_MGR_CREATE_USER_RESP, uid,
+                                result.getStatus(), result.getErrorMessage());
+                        UserInfo user = result.getUser();
+                        if (result.isSuccess() && user != null && user.isGuest()) {
+                            onGuestCreated(user);
+                        }
+                    } else {
+                        Log.w(TAG, "createUser(" + userType + "," + UserInfo.flagsToString(flags)
+                                + ") failed: " + err);
+                    }
+                    super.onCompleted(result, err);
+                };
+            };
+            EventLog.writeEvent(EventLogTags.CAR_USER_MGR_CREATE_USER_REQ, uid,
+                    safeName(name), userType, flags);
+            mService.createUser(name, userType, flags, HAL_TIMEOUT_MS, future);
+            return future;
+        } catch (RemoteException e) {
+            AndroidFuture<UserCreationResult> future = new AndroidFuture<>();
+            future.complete(new UserCreationResult(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE,
+                    null, null));
+            return handleRemoteExceptionFromCarService(e, future);
+        }
+    }
+
+    /**
+     * Creates a new guest Android user.
+     *
+     * @hide
+     */
+    @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.CREATE_USERS})
+    public AndroidFuture<UserCreationResult> createGuest(@Nullable String name) {
+        return createUser(name, UserManager.USER_TYPE_FULL_GUEST, /* flags= */ 0);
+    }
+
+    /**
+     * Creates a new Android user.
+     *
+     * @hide
+     */
+    @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.CREATE_USERS})
+    public AndroidFuture<UserCreationResult> createUser(@Nullable String name,
+            @UserInfoFlag int flags) {
+        return createUser(name, UserManager.USER_TYPE_FULL_SECONDARY, flags);
+    }
+
+    // TODO(b/159283854): move to UserManager
+    private void onGuestCreated(UserInfo user) {
+        Settings.Secure.putStringForUser(getContext().getContentResolver(),
+                Settings.Secure.SKIP_FIRST_USE_HINTS, "1", user.id);
+    }
+
+     /**
+     * Removes a user.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public UserRemovalResult removeUser(@UserIdInt int userId) {
+        int uid = myUid();
+        EventLog.writeEvent(EventLogTags.CAR_USER_MGR_REMOVE_USER_REQ, uid, userId);
+        int status = UserRemovalResult.STATUS_HAL_INTERNAL_FAILURE;
+        try {
+            UserRemovalResult result = mService.removeUser(userId);
+            status = result.getStatus();
+            return result;
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e,
+                    new UserRemovalResult(UserRemovalResult.STATUS_HAL_INTERNAL_FAILURE));
+        } finally {
+            EventLog.writeEvent(EventLogTags.CAR_USER_MGR_REMOVE_USER_RESP, uid, status);
+        }
+    }
+
+    /**
+     * Adds a listener for {@link UserLifecycleEvent user lifecycle events}.
+     *
+     * @throws IllegalStateException if the listener was already added.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    @RequiresPermission(anyOf = {INTERACT_ACROSS_USERS, INTERACT_ACROSS_USERS_FULL})
+    public void addListener(@NonNull @CallbackExecutor Executor executor,
+            @NonNull UserLifecycleListener listener) {
+        Objects.requireNonNull(executor, "executor cannot be null");
+        Objects.requireNonNull(listener, "listener cannot be null");
+
+        int uid = myUid();
+        synchronized (mLock) {
+            Preconditions.checkState(mListeners == null || !mListeners.containsKey(listener),
+                    "already called for this listener");
+            if (mReceiver == null) {
+                mReceiver = new LifecycleResultReceiver();
+                try {
+                    EventLog.writeEvent(EventLogTags.CAR_USER_MGR_ADD_LISTENER, uid);
+                    if (DBG) Log.d(TAG, "Setting lifecycle receiver for uid " + uid);
+                    mService.setLifecycleListenerForUid(mReceiver);
+                } catch (RemoteException e) {
+                    handleRemoteExceptionFromCarService(e);
+                }
+            } else {
+                if (DBG) Log.d(TAG, "Already set receiver for uid " + uid);
+            }
+
+            if (mListeners == null) {
+                mListeners = new ArrayMap<>(1); // Most likely app will have just one listener
+            } else if (DBG) {
+                Log.d(TAG, "addListener(" + getLambdaName(listener) + "): context " + getContext()
+                        + " already has " + mListeners.size() + " listeners: "
+                        + mListeners.keySet().stream()
+                                .map((l) -> getLambdaName(l))
+                                .collect(Collectors.toList()), new Exception());
+            }
+            if (DBG) Log.d(TAG, "Adding listener: " + listener);
+            mListeners.put(listener, executor);
+        }
+    }
+
+    /**
+     * Removes a listener for {@link UserLifecycleEvent user lifecycle events}.
+     *
+     * @throws IllegalStateException if the listener was not added beforehand.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    @RequiresPermission(anyOf = {INTERACT_ACROSS_USERS, INTERACT_ACROSS_USERS_FULL})
+    public void removeListener(@NonNull UserLifecycleListener listener) {
+        Objects.requireNonNull(listener, "listener cannot be null");
+
+        int uid = myUid();
+        synchronized (mLock) {
+            Preconditions.checkState(mListeners != null && mListeners.containsKey(listener),
+                    "not called for this listener yet");
+            mListeners.remove(listener);
+
+            if (!mListeners.isEmpty()) {
+                if (DBG) Log.d(TAG, "removeListeners(): still " + mListeners.size() + " left");
+                return;
+            }
+            mListeners = null;
+
+            if (mReceiver == null) {
+                Log.wtf(TAG, "removeListener(): receiver already null");
+                return;
+            }
+
+            EventLog.writeEvent(EventLogTags.CAR_USER_MGR_REMOVE_LISTENER, uid);
+            if (DBG) Log.d(TAG, "Removing lifecycle receiver for uid=" + uid);
+            try {
+                mService.resetLifecycleListenerForUid();
+                mReceiver = null;
+            } catch (RemoteException e) {
+                handleRemoteExceptionFromCarService(e);
+            }
+        }
+    }
+
+    /**
+     * Check if user hal supports user association.
+     *
+     * @hide
+     */
+    public boolean isUserHalUserAssociationSupported() {
+        try {
+            return mService.isUserHalUserAssociationSupported();
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, false);
+        }
+    }
+
+    /**
+     * Gets the user authentication types associated with this manager's user.
+     *
+     * @hide
+     */
+    @NonNull
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public UserIdentificationAssociationResponse getUserIdentificationAssociation(
+            @NonNull int... types) {
+        Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
+        EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_REQ, types.length);
+        try {
+            UserIdentificationAssociationResponse response =
+                    mService.getUserIdentificationAssociation(types);
+            if (response != null) {
+                int[] values = response.getValues();
+                EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_RESP,
+                        values != null ? values.length : 0);
+            }
+            return response;
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, null);
+        }
+    }
+
+    /**
+     * Sets the user authentication types associated with this manager's user.
+     *
+     * @hide
+     */
+    @NonNull
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public AndroidFuture<UserIdentificationAssociationResponse> setUserIdentificationAssociation(
+            @NonNull int[] types, @NonNull int[] values) {
+        Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
+        Preconditions.checkArgument(!ArrayUtils.isEmpty(values), "must have at least one value");
+        if (types.length != values.length) {
+            throw new IllegalArgumentException("types (" + Arrays.toString(types) + ") and values ("
+                    + Arrays.toString(values) + ") should have the same length");
+        }
+        // TODO(b/153900032): move this logic to a common helper
+        Object[] loggedValues = new Integer[types.length * 2];
+        for (int i = 0; i < types.length; i++) {
+            loggedValues[i * 2] = types[i];
+            loggedValues[i * 2 + 1 ] = values[i];
+        }
+        EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_REQ, loggedValues);
+
+        try {
+            AndroidFuture<UserIdentificationAssociationResponse> future =
+                    new AndroidFuture<UserIdentificationAssociationResponse>() {
+                @Override
+                protected void onCompleted(UserIdentificationAssociationResponse result,
+                        Throwable err) {
+                    if (result != null) {
+                        int[] rawValues = result.getValues();
+                        // TODO(b/153900032): move this logic to a common helper
+                        if (rawValues != null) {
+                            Object[] loggedValues = new Object[rawValues.length];
+                            for (int i = 0; i < rawValues.length; i++) {
+                                loggedValues[i] = rawValues[i];
+                            }
+                            EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP,
+                                    loggedValues);
+                        }
+                    } else {
+                        Log.w(TAG, "setUserIdentificationAssociation(" + Arrays.toString(types)
+                                + ", " + Arrays.toString(values) + ") failed: " + err);
+                    }
+                    super.onCompleted(result, err);
+                };
+            };
+            mService.setUserIdentificationAssociation(HAL_TIMEOUT_MS, types, values, future);
+            return future;
+        } catch (RemoteException e) {
+            AndroidFuture<UserIdentificationAssociationResponse> future = new AndroidFuture<>();
+            future.complete(UserIdentificationAssociationResponse.forFailure());
+            return handleRemoteExceptionFromCarService(e, future);
+        }
+    }
+
+    /**
+     * Sets a callback to be notified before user switch. It should only be used by Car System UI.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public void setUserSwitchUiCallback(@NonNull UserSwitchUiCallback callback) {
+        Preconditions.checkArgument(callback != null, "Null callback");
+        UserSwitchUiCallbackReceiver userSwitchUiCallbackReceiver =
+                new UserSwitchUiCallbackReceiver(callback);
+        try {
+            mService.setUserSwitchUiCallback(userSwitchUiCallbackReceiver);
+        } catch (RemoteException e) {
+            handleRemoteExceptionFromCarService(e);
+        }
+    }
+
+    /**
+     * {@code IResultReceiver} used to receive user switch UI Callback.
+     */
+    // TODO(b/154958003): use mReceiver instead as now there are two binder objects
+    private final class UserSwitchUiCallbackReceiver extends IResultReceiver.Stub {
+
+        private final UserSwitchUiCallback mUserSwitchUiCallback;
+
+        UserSwitchUiCallbackReceiver(UserSwitchUiCallback callback) {
+            mUserSwitchUiCallback = callback;
+        }
+
+        @Override
+        public void send(int userId, Bundle unused) throws RemoteException {
+            mUserSwitchUiCallback.showUserSwitchDialog(userId);
+        }
+    }
+
+    /**
+     * {@code IResultReceiver} used to receive lifecycle events and dispatch to the proper listener.
+     */
+    private class LifecycleResultReceiver extends IResultReceiver.Stub {
+        @Override
+        public void send(int resultCode, Bundle resultData) {
+            if (resultData == null) {
+                Log.w(TAG, "Received result (" + resultCode + ") without data");
+                return;
+            }
+            int from = resultData.getInt(BUNDLE_PARAM_PREVIOUS_USER_ID, UserHandle.USER_NULL);
+            int to = resultCode;
+            int eventType = resultData.getInt(BUNDLE_PARAM_ACTION);
+            UserLifecycleEvent event = new UserLifecycleEvent(eventType, from, to);
+            ArrayMap<UserLifecycleListener, Executor> listeners;
+            synchronized (mLock) {
+                listeners = mListeners;
+            }
+            if (listeners == null) {
+                Log.w(TAG, "No listeners for event " + event);
+                return;
+            }
+            int size = listeners.size();
+            EventLog.writeEvent(EventLogTags.CAR_USER_MGR_NOTIFY_LIFECYCLE_LISTENER,
+                    size, eventType, from, to);
+            for (int i = 0; i < size; i++) {
+                UserLifecycleListener listener = listeners.keyAt(i);
+                Executor executor = listeners.valueAt(i);
+                if (DBG) {
+                    Log.d(TAG, "Calling " + getLambdaName(listener) + " for event " + event);
+                }
+                executor.execute(() -> listener.onEvent(event));
+            }
+        }
+    }
+
+    /** @hide */
+    @Override
+    public void onCarDisconnected() {
+        // nothing to do
+    }
+
+    /**
+     * @hide
+     */
+    @TestApi
+    public static String lifecycleEventTypeToString(@UserLifecycleEventType int type) {
+        switch (type) {
+            case USER_LIFECYCLE_EVENT_TYPE_STARTING:
+                return "STARTING";
+            case USER_LIFECYCLE_EVENT_TYPE_SWITCHING:
+                return "SWITCHING";
+            case USER_LIFECYCLE_EVENT_TYPE_UNLOCKING:
+                return "UNLOCKING";
+            case USER_LIFECYCLE_EVENT_TYPE_UNLOCKED:
+                return "UNLOCKED";
+            case USER_LIFECYCLE_EVENT_TYPE_STOPPING:
+                return "STOPPING";
+            case USER_LIFECYCLE_EVENT_TYPE_STOPPED:
+                return "STOPPED";
+            default:
+                return "UNKNOWN-" + type;
+        }
+    }
+
+    // NOTE: this method is called by ExperimentalCarUserManager, so it can get the mService.
+    // "Real" ExperimentalCarUserManager instances should be obtained through
+    //    ExperimentalCarUserManager.from(mCarUserManager)
+    // instead.
+    ExperimentalCarUserManager newExperimentalCarUserManager() {
+        return new ExperimentalCarUserManager(mCar, mService);
+    }
+
+    /**
+     * Checks if the given {@code userId} represents a valid user.
+     *
+     * <p>A "valid" user:
+     *
+     * <ul>
+     *   <li>Must exist in the device.
+     *   <li>Is not in the process of being deleted.
+     *   <li>Cannot be the {@link UserHandle#isSystem() system} user on devices that use
+     *   {@link UserManager#isHeadlessSystemUserMode() headless system mode}.
+     * </ul>
+     *
+     * @hide
+     */
+    public boolean isValidUser(@UserIdInt int userId) {
+        List<UserInfo> allUsers = mUserManager.getUsers(/* excludeDying= */ true);
+        for (int i = 0; i < allUsers.size(); i++) {
+            UserInfo user = allUsers.get(i);
+            if (user.id == userId && (userId != UserHandle.USER_SYSTEM
+                    || !UserManager.isHeadlessSystemUserMode())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // TODO(b/150413515): use from UserHelper instead (would require a new make target, otherwise it
+    // would include the whole car-user-lib)
+    private boolean isHeadlessSystemUser(int targetUserId) {
+        return targetUserId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode();
+    }
+
+    // TODO(b/150413515): use from UserHelper instead (would require a new make target, otherwise it
+    // would include the whole car-user-lib)
+    @Nullable
+    private static String safeName(@Nullable String name) {
+        return name == null ? name : name.length() + "_chars";
+    }
+
+    /**
+     * Defines a lifecycle event for an Android user.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final class UserLifecycleEvent {
+        private final @UserLifecycleEventType int mEventType;
+        private final @UserIdInt int mUserId;
+        private final @UserIdInt int mPreviousUserId;
+
+        /** @hide */
+        public UserLifecycleEvent(@UserLifecycleEventType int eventType,
+                @UserIdInt int from, @UserIdInt int to) {
+            mEventType = eventType;
+            mPreviousUserId = from;
+            mUserId = to;
+        }
+
+        /** @hide */
+        public UserLifecycleEvent(@UserLifecycleEventType int eventType, @UserIdInt int to) {
+            this(eventType, UserHandle.USER_NULL, to);
+        }
+
+        /**
+         * Gets the event type.
+         *
+         * @return either {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_STARTING},
+         * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_SWITCHING},
+         * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_UNLOCKING},
+         * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_UNLOCKED},
+         * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_STOPPING}, or
+         * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_STOPPED}.
+         */
+        @UserLifecycleEventType
+        public int getEventType() {
+            return mEventType;
+        }
+
+        /**
+         * Gets the id of the user whose event is being reported.
+         *
+         * @hide
+         */
+        @UserIdInt
+        public int getUserId() {
+            return mUserId;
+        }
+
+        /**
+         * Gets the handle of the user whose event is being reported.
+         */
+        @NonNull
+        public UserHandle getUserHandle() {
+            return UserHandle.of(mUserId);
+        }
+
+        /**
+         * Gets the id of the user being switched from.
+         *
+         * <p>This method returns {@link UserHandle#USER_NULL} for all event types but
+         * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_SWITCHING}.
+         *
+         * @hide
+         */
+        @UserIdInt
+        public int getPreviousUserId() {
+            return mPreviousUserId;
+        }
+
+        /**
+         * Gets the handle of the user being switched from.
+         *
+         * <p>This method returns {@code null} for all event types but
+         * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_SWITCHING}.
+         */
+        @Nullable
+        public UserHandle getPreviousUserHandle() {
+            return mPreviousUserId == UserHandle.USER_NULL ? null : UserHandle.of(mPreviousUserId);
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder("Event[type=")
+                    .append(lifecycleEventTypeToString(mEventType));
+            if (mPreviousUserId != UserHandle.USER_NULL) {
+                builder
+                    .append(",from=").append(mPreviousUserId)
+                    .append(",to=").append(mUserId);
+            } else {
+                builder.append(",user=").append(mUserId);
+            }
+
+            return builder.append(']').toString();
+        }
+    }
+
+    /**
+     * Listener for Android User lifecycle events.
+     *
+     * <p>Must be registered using {@link CarUserManager#addListener(UserLifecycleListener)} and
+     * unregistered through {@link CarUserManager#removeListener(UserLifecycleListener)}.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public interface UserLifecycleListener {
+
+        /**
+         * Called to notify the given {@code event}.
+         */
+        void onEvent(@NonNull UserLifecycleEvent event);
+    }
+
+    /**
+     * Callback for notifying user switch before switch started.
+     *
+     * <p> It should only be user by Car System UI. The purpose of this callback is notify the
+     * Car System UI to display the user switch UI.
+     *
+     * @hide
+     */
+    public interface UserSwitchUiCallback {
+
+        /**
+         * Called to notify that user switch dialog should be shown now.
+         */
+        void showUserSwitchDialog(@UserIdInt int userId);
+    }
+}
diff --git a/car-lib/src/android/car/user/CommonResults.java b/car-lib/src/android/car/user/CommonResults.java
new file mode 100644
index 0000000..9238a0b
--- /dev/null
+++ b/car-lib/src/android/car/user/CommonResults.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.user;
+
+/**
+ * Defines status for common result objects.
+ */
+final class CommonResults {
+
+    /**
+     * Operation was is successful for both HAL and Android.
+     */
+    public static final int STATUS_SUCCESSFUL = 1;
+
+    /**
+     * Operation failed on Android.
+     */
+    public static final int STATUS_ANDROID_FAILURE = 2;
+
+    /**
+     * Operation failed on HAL.
+     */
+    public static final int STATUS_HAL_FAILURE = 3;
+
+    /**
+     * Operation failed due to an error communication with HAL (like timeout).
+     */
+    public static final int STATUS_HAL_INTERNAL_FAILURE = 4;
+
+    /**
+     * Operation failed due to invalid request.
+     */
+    public static final int STATUS_INVALID_REQUEST = 5;
+
+    /**
+     * Reference for common status - anything higher than this can be used for custom status
+     */
+    static final int LAST_COMMON_STATUS = 100;
+
+    private CommonResults() {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/car-lib/src/android/car/user/ExperimentalCarUserManager.java b/car-lib/src/android/car/user/ExperimentalCarUserManager.java
new file mode 100644
index 0000000..fa7eb72
--- /dev/null
+++ b/car-lib/src/android/car/user/ExperimentalCarUserManager.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.user;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.UserIdInt;
+import android.car.Car;
+import android.car.CarManagerBase;
+import android.car.ICarUserService;
+import android.car.annotation.ExperimentalFeature;
+import android.content.pm.UserInfo;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+import com.android.internal.infra.AndroidFuture;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Temporary class containing {@link CarUserManager} features that are not ready yet.
+ *
+ * <p>New instances are created through {@link #from(CarUserManager)}.
+ *
+ * @hide
+ */
+@ExperimentalFeature
+public final class ExperimentalCarUserManager extends CarManagerBase {
+
+    private static final String TAG = ExperimentalCarUserManager.class.getSimpleName();
+
+    /**
+     *  User id representing invalid user.
+     */
+    private static final int INVALID_USER_ID = UserHandle.USER_NULL;
+
+    private final ICarUserService mService;
+
+    /**
+     * Factory method to create a new instance.
+     */
+    public static ExperimentalCarUserManager from(@NonNull CarUserManager carUserManager) {
+        return carUserManager.newExperimentalCarUserManager();
+    }
+
+    ExperimentalCarUserManager(@NonNull Car car, @NonNull ICarUserService service) {
+        super(car);
+
+        mService = service;
+    }
+
+    /**
+     * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
+     *
+     * @param name The name of the driver to be created.
+     * @param admin Whether the created driver will be an admin.
+     * @return an {@link AndroidFuture} that can be used to track operation's completion and
+     *         retrieve its result (if any).
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public AndroidFuture<UserCreationResult> createDriver(@NonNull String name, boolean admin) {
+        try {
+            return mService.createDriver(name, admin);
+        } catch (RemoteException e) {
+            AndroidFuture<UserCreationResult> future = new AndroidFuture<>();
+            future.complete(new UserCreationResult(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE,
+                    null, null));
+            handleRemoteExceptionFromCarService(e);
+            return future;
+        }
+    }
+
+    /**
+     * Creates a passenger who is a profile of the given driver.
+     *
+     * @param name The name of the passenger to be created.
+     * @param driverId User id of the driver under whom a passenger is created.
+     * @return user id of the created passenger, or {@code INVALID_USER_ID} if the passenger
+     *         could not be created.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @Nullable
+    public int createPassenger(@NonNull String name, @UserIdInt int driverId) {
+        try {
+            UserInfo ui = mService.createPassenger(name, driverId);
+            return ui != null ? ui.id : INVALID_USER_ID;
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, null);
+        }
+    }
+
+    /**
+     * Switches a driver to the given user.
+     *
+     * @param driverId User id of the driver to switch to.
+     * @return an {@link AndroidFuture} that can be used to track operation's completion and
+     *         retrieve its result (if any).
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public AndroidFuture<UserSwitchResult> switchDriver(@UserIdInt int driverId) {
+        try {
+            AndroidFuture<UserSwitchResult> future = new AndroidFuture<>() {
+                @Override
+                protected void onCompleted(UserSwitchResult result, Throwable err) {
+                    if (result == null) {
+                        Log.w(TAG, "switchDriver(" + driverId + ") failed: " + err);
+                    }
+                    super.onCompleted(result, err);
+                }
+            };
+            mService.switchDriver(driverId, future);
+            return future;
+        } catch (RemoteException e) {
+            AndroidFuture<UserSwitchResult> future = new AndroidFuture<>();
+            future.complete(
+                    new UserSwitchResult(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE, null));
+            handleRemoteExceptionFromCarService(e);
+            return future;
+        }
+    }
+
+    /**
+     * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
+     *
+     * @return the list of user ids who can be a driver on the device.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @NonNull
+    public List<Integer> getAllDrivers() {
+        try {
+            return getUserIdsFromUserInfos(mService.getAllDrivers());
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, Collections.emptyList());
+        }
+    }
+
+    /**
+     * Returns all passengers under the given driver.
+     *
+     * @param driverId User id of a driver.
+     * @return the list of user ids who are passengers under the given driver.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @NonNull
+    public List<Integer> getPassengers(@UserIdInt int driverId) {
+        try {
+            return getUserIdsFromUserInfos(mService.getPassengers(driverId));
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, Collections.emptyList());
+        }
+    }
+
+    /**
+     * Assigns the passenger to the zone and starts the user if it is not started yet.
+     *
+     * @param passengerId User id of the passenger to be started.
+     * @param zoneId Zone id to which the passenger is assigned.
+     * @return {@code true} if the user is successfully started or the user is already running.
+     *         Otherwise, {@code false}.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
+        try {
+            return mService.startPassenger(passengerId, zoneId);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, false);
+        }
+    }
+
+    /**
+     * Stops the given passenger.
+     *
+     * @param passengerId User id of the passenger to be stopped.
+     * @return {@code true} if successfully stopped, or {@code false} if failed.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public boolean stopPassenger(@UserIdInt int passengerId) {
+        try {
+            return mService.stopPassenger(passengerId);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, false);
+        }
+    }
+
+    /** @hide */
+    @Override
+    public void onCarDisconnected() {
+        // nothing to do
+    }
+
+    private List<Integer> getUserIdsFromUserInfos(List<UserInfo> infos) {
+        List<Integer> ids = new ArrayList<>(infos.size());
+        for (UserInfo ui : infos) {
+            ids.add(ui.id);
+        }
+        return ids;
+    }
+}
diff --git a/car-lib/src/android/car/user/UserCreationResult.aidl b/car-lib/src/android/car/user/UserCreationResult.aidl
new file mode 100644
index 0000000..a735202
--- /dev/null
+++ b/car-lib/src/android/car/user/UserCreationResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.user;
+
+parcelable UserCreationResult;
diff --git a/car-lib/src/android/car/user/UserCreationResult.java b/car-lib/src/android/car/user/UserCreationResult.java
new file mode 100644
index 0000000..328908f
--- /dev/null
+++ b/car-lib/src/android/car/user/UserCreationResult.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.user;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.content.pm.UserInfo;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * User creation results.
+ *
+ * @hide
+ */
+@DataClass(
+        genToString = true,
+        genHiddenConstructor = true,
+        genHiddenConstDefs = true)
+public final class UserCreationResult implements Parcelable {
+
+    /**
+     * {@link Status} called when user creation is successful for both HAL and Android.
+     *
+     * @hide
+     */
+    public static final int STATUS_SUCCESSFUL = CommonResults.STATUS_SUCCESSFUL;
+
+    /**
+     * {@link Status} called when user creation failed on Android - HAL is not even called in this
+     * case.
+     *
+     * @hide
+     */
+    public static final int STATUS_ANDROID_FAILURE = CommonResults.STATUS_ANDROID_FAILURE;
+
+    /**
+     * {@link Status} called when user was created on Android but HAL returned a failure - the
+     * Android user is automatically removed.
+     *
+     * @hide
+     */
+    public static final int STATUS_HAL_FAILURE = CommonResults.STATUS_HAL_FAILURE;
+
+    /**
+     * {@link Status} called when user creation is failed for HAL for some internal error - the
+     * Android user is not automatically removed.
+     *
+     * @hide
+     */
+    public static final int STATUS_HAL_INTERNAL_FAILURE = CommonResults.STATUS_HAL_INTERNAL_FAILURE;
+
+    /**
+     * {@link Status} called when given parameters or environment states are invalid for creating
+     * user - HAL or Android user creation is not requested.
+     */
+    public static final int STATUS_INVALID_REQUEST = CommonResults.STATUS_INVALID_REQUEST;
+
+    /**
+     * Gets the user creation result status.
+     *
+     * @return either {@link UserCreationResult#STATUS_SUCCESSFUL},
+     *         {@link UserCreationResult#STATUS_ANDROID_FAILURE},
+     *         {@link UserCreationResult#STATUS_HAL_FAILURE},
+     *         {@link UserCreationResult#STATUS_HAL_INTERNAL_FAILURE}, or
+     *         {@link UserCreationResult#STATUS_INVALID_REQUEST}.
+     */
+    private final @Status int mStatus;
+
+    /**
+     * Gets the created user.
+     */
+    @Nullable
+    private final UserInfo mUser;
+
+    /**
+     * Gets the error message sent by HAL, if any.
+     */
+    @Nullable
+    private final String mErrorMessage;
+
+    /**
+     * Checks if this result is successful.
+     */
+    public boolean isSuccess() {
+        return mStatus == STATUS_SUCCESSFUL;
+    }
+
+    // TODO(b/158195639): if you change any status constant, you need to manually assign its values
+
+
+
+    // Code below generated by codegen v1.0.15.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/user/UserCreationResult.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /** @hide */
+    @IntDef(prefix = "STATUS_", value = {
+        STATUS_SUCCESSFUL,
+        STATUS_ANDROID_FAILURE,
+        STATUS_HAL_FAILURE,
+        STATUS_HAL_INTERNAL_FAILURE,
+        STATUS_INVALID_REQUEST
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @DataClass.Generated.Member
+    public @interface Status {}
+
+    /** @hide */
+    @DataClass.Generated.Member
+    public static String statusToString(@Status int value) {
+        switch (value) {
+            case STATUS_SUCCESSFUL:
+                    return "STATUS_SUCCESSFUL";
+            case STATUS_ANDROID_FAILURE:
+                    return "STATUS_ANDROID_FAILURE";
+            case STATUS_HAL_FAILURE:
+                    return "STATUS_HAL_FAILURE";
+            case STATUS_HAL_INTERNAL_FAILURE:
+                    return "STATUS_HAL_INTERNAL_FAILURE";
+            case STATUS_INVALID_REQUEST:
+                    return "STATUS_INVALID_REQUEST";
+            default: return Integer.toHexString(value);
+        }
+    }
+
+    /**
+     * Creates a new UserCreationResult.
+     *
+     * @param status
+     *   Gets the user creation result status.
+     *
+     *   @return either {@link UserCreationResult#STATUS_SUCCESSFUL},
+     *           {@link UserCreationResult#STATUS_ANDROID_FAILURE},
+     *           {@link UserCreationResult#STATUS_HAL_FAILURE},
+     *           {@link UserCreationResult#STATUS_HAL_INTERNAL_FAILURE}, or
+     *           {@link UserCreationResult#STATUS_INVALID_REQUEST}.
+     * @param user
+     *   Gets the created user.
+     * @param errorMessage
+     *   Gets the error message sent by HAL, if any.
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public UserCreationResult(
+            @Status int status,
+            @Nullable UserInfo user,
+            @Nullable String errorMessage) {
+        this.mStatus = status;
+
+        if (!(mStatus == STATUS_SUCCESSFUL)
+                && !(mStatus == STATUS_ANDROID_FAILURE)
+                && !(mStatus == STATUS_HAL_FAILURE)
+                && !(mStatus == STATUS_HAL_INTERNAL_FAILURE)
+                && !(mStatus == STATUS_INVALID_REQUEST)) {
+            throw new java.lang.IllegalArgumentException(
+                    "status was " + mStatus + " but must be one of: "
+                            + "STATUS_SUCCESSFUL(" + STATUS_SUCCESSFUL + "), "
+                            + "STATUS_ANDROID_FAILURE(" + STATUS_ANDROID_FAILURE + "), "
+                            + "STATUS_HAL_FAILURE(" + STATUS_HAL_FAILURE + "), "
+                            + "STATUS_HAL_INTERNAL_FAILURE(" + STATUS_HAL_INTERNAL_FAILURE + "), "
+                            + "STATUS_INVALID_REQUEST(" + STATUS_INVALID_REQUEST + ")");
+        }
+
+        this.mUser = user;
+        this.mErrorMessage = errorMessage;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * Gets the user creation result status.
+     *
+     * @return either {@link UserCreationResult#STATUS_SUCCESSFUL},
+     *         {@link UserCreationResult#STATUS_ANDROID_FAILURE},
+     *         {@link UserCreationResult#STATUS_HAL_FAILURE},
+     *         {@link UserCreationResult#STATUS_HAL_INTERNAL_FAILURE}, or
+     *         {@link UserCreationResult#STATUS_INVALID_REQUEST}.
+     */
+    @DataClass.Generated.Member
+    public @Status int getStatus() {
+        return mStatus;
+    }
+
+    /**
+     * Gets the created user.
+     */
+    @DataClass.Generated.Member
+    public @Nullable UserInfo getUser() {
+        return mUser;
+    }
+
+    /**
+     * Gets the error message sent by HAL, if any.
+     */
+    @DataClass.Generated.Member
+    public @Nullable String getErrorMessage() {
+        return mErrorMessage;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "UserCreationResult { " +
+                "status = " + statusToString(mStatus) + ", " +
+                "user = " + mUser + ", " +
+                "errorMessage = " + mErrorMessage +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@android.annotation.NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        byte flg = 0;
+        if (mUser != null) flg |= 0x2;
+        if (mErrorMessage != null) flg |= 0x4;
+        dest.writeByte(flg);
+        dest.writeInt(mStatus);
+        if (mUser != null) dest.writeTypedObject(mUser, flags);
+        if (mErrorMessage != null) dest.writeString(mErrorMessage);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ UserCreationResult(@android.annotation.NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        int status = in.readInt();
+        UserInfo user = (flg & 0x2) == 0 ? null : (UserInfo) in.readTypedObject(UserInfo.CREATOR);
+        String errorMessage = (flg & 0x4) == 0 ? null : in.readString();
+
+        this.mStatus = status;
+
+        if (!(mStatus == STATUS_SUCCESSFUL)
+                && !(mStatus == STATUS_ANDROID_FAILURE)
+                && !(mStatus == STATUS_HAL_FAILURE)
+                && !(mStatus == STATUS_HAL_INTERNAL_FAILURE)
+                && !(mStatus == STATUS_INVALID_REQUEST)) {
+            throw new java.lang.IllegalArgumentException(
+                    "status was " + mStatus + " but must be one of: "
+                            + "STATUS_SUCCESSFUL(" + STATUS_SUCCESSFUL + "), "
+                            + "STATUS_ANDROID_FAILURE(" + STATUS_ANDROID_FAILURE + "), "
+                            + "STATUS_HAL_FAILURE(" + STATUS_HAL_FAILURE + "), "
+                            + "STATUS_HAL_INTERNAL_FAILURE(" + STATUS_HAL_INTERNAL_FAILURE + "), "
+                            + "STATUS_INVALID_REQUEST(" + STATUS_INVALID_REQUEST + ")");
+        }
+
+        this.mUser = user;
+        this.mErrorMessage = errorMessage;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @android.annotation.NonNull Parcelable.Creator<UserCreationResult> CREATOR
+            = new Parcelable.Creator<UserCreationResult>() {
+        @Override
+        public UserCreationResult[] newArray(int size) {
+            return new UserCreationResult[size];
+        }
+
+        @Override
+        public UserCreationResult createFromParcel(@android.annotation.NonNull android.os.Parcel in) {
+            return new UserCreationResult(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1591401523007L,
+            codegenVersion = "1.0.15",
+            sourceFile = "packages/services/Car/car-lib/src/android/car/user/UserCreationResult.java",
+            inputSignatures = "public static final  int STATUS_SUCCESSFUL\npublic static final  int STATUS_ANDROID_FAILURE\npublic static final  int STATUS_HAL_FAILURE\npublic static final  int STATUS_HAL_INTERNAL_FAILURE\npublic static final  int STATUS_INVALID_REQUEST\nprivate final @android.car.user.UserCreationResult.Status int mStatus\nprivate final @android.annotation.Nullable android.content.pm.UserInfo mUser\nprivate final @android.annotation.Nullable java.lang.String mErrorMessage\npublic  boolean isSuccess()\nclass UserCreationResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/car-lib/src/android/car/user/UserIdentificationAssociationResponse.aidl b/car-lib/src/android/car/user/UserIdentificationAssociationResponse.aidl
new file mode 100644
index 0000000..9e292d4
--- /dev/null
+++ b/car-lib/src/android/car/user/UserIdentificationAssociationResponse.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.user;
+
+parcelable UserIdentificationAssociationResponse;
diff --git a/car-lib/src/android/car/user/UserIdentificationAssociationResponse.java b/car-lib/src/android/car/user/UserIdentificationAssociationResponse.java
new file mode 100644
index 0000000..d2cdb44
--- /dev/null
+++ b/car-lib/src/android/car/user/UserIdentificationAssociationResponse.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.user;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcelable;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.DataClass;
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+
+/**
+ * Results of a {@link CarUserManager#getUserIdentificationAssociation(int[]) request.
+ *
+ * @hide
+ */
+@DataClass(
+        genToString = true,
+        genHiddenConstructor = false,
+        genHiddenConstDefs = true)
+public final class UserIdentificationAssociationResponse implements Parcelable {
+
+    /**
+     * Whether the request was successful.
+     *
+     * <p>A successful option has non-null {@link #getValues()}
+     */
+    private final boolean mSuccess;
+
+    /**
+     * Gets the error message returned by the HAL.
+     */
+    @Nullable
+    private final String mErrorMessage;
+
+    /**
+     * Gets the list of values associated with the request.
+     *
+     * <p><b>NOTE: </b>It's only set when the response is {@link #isSuccess() successful}.
+     *
+     * <p>For {@link CarUserManager#getUserIdentificationAssociation(int...)}, the values are
+     * defined on
+     * {@link android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationValue}.
+     *
+     * <p>For {@link CarUserManager#setUserIdentificationAssociation(int...)}, the values are
+     * defined on
+     * {@link android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue}.
+     */
+    @Nullable
+    private final int[] mValues;
+
+    private UserIdentificationAssociationResponse(
+            boolean success,
+            @Nullable String errorMessage,
+            @Nullable int[] values) {
+        this.mSuccess = success;
+        this.mErrorMessage = errorMessage;
+        this.mValues = values;
+    }
+
+    /**
+     * Factory method for failed UserIdentificationAssociationResponse requests.
+     */
+    @NonNull
+    public static UserIdentificationAssociationResponse forFailure() {
+        return forFailure(/* errorMessage= */ null);
+    }
+
+    /**
+     * Factory method for failed UserIdentificationAssociationResponse requests.
+     */
+    @NonNull
+    public static UserIdentificationAssociationResponse forFailure(@Nullable String errorMessage) {
+        return new UserIdentificationAssociationResponse(/* success= */ false,
+                errorMessage, /* values= */ null);
+    }
+
+    /**
+     * Factory method for successful UserIdentificationAssociationResponse requests.
+     */
+    @NonNull
+    public static UserIdentificationAssociationResponse forSuccess(@NonNull int[] values) {
+        Preconditions.checkArgument(!ArrayUtils.isEmpty(values), "must have at least one value");
+        return new UserIdentificationAssociationResponse(/* success= */ true,
+                /* errorMessage= */ null, Objects.requireNonNull(values));
+    }
+
+    /**
+     * Factory method for successful UserIdentificationAssociationResponse requests.
+     */
+    @NonNull
+    public static UserIdentificationAssociationResponse forSuccess(@NonNull int[] values,
+            @Nullable String errorMessage) {
+        Preconditions.checkArgument(!ArrayUtils.isEmpty(values), "must have at least one value");
+        return new UserIdentificationAssociationResponse(/* success= */ true,
+                errorMessage, Objects.requireNonNull(values));
+    }
+
+
+
+    // Code below generated by codegen v1.0.15.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/user/UserIdentificationAssociationResponse.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Whether the request was successful.
+     *
+     * <p>A successful option has non-null {@link #getValues()}
+     */
+    @DataClass.Generated.Member
+    public boolean isSuccess() {
+        return mSuccess;
+    }
+
+    /**
+     * Gets the error message returned by the HAL.
+     */
+    @DataClass.Generated.Member
+    public @Nullable String getErrorMessage() {
+        return mErrorMessage;
+    }
+
+    /**
+     * Gets the list of values associated with the request.
+     *
+     * <p><b>NOTE: </b>It's only set when the response is {@link #isSuccess() successful}.
+     *
+     * <p>For {@link CarUserManager#getUserIdentificationAssociation(int...)}, the values are
+     * defined on
+     * {@link android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationValue}.
+     *
+     * <p>For {@link CarUserManager#setUserIdentificationAssociation(int...)}, the values are
+     * defined on
+     * {@link android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue}.
+     */
+    @DataClass.Generated.Member
+    public @Nullable int[] getValues() {
+        return mValues;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "UserIdentificationAssociationResponse { " +
+                "success = " + mSuccess + ", " +
+                "errorMessage = " + mErrorMessage + ", " +
+                "values = " + java.util.Arrays.toString(mValues) +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        byte flg = 0;
+        if (mSuccess) flg |= 0x1;
+        if (mErrorMessage != null) flg |= 0x2;
+        if (mValues != null) flg |= 0x4;
+        dest.writeByte(flg);
+        if (mErrorMessage != null) dest.writeString(mErrorMessage);
+        if (mValues != null) dest.writeIntArray(mValues);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ UserIdentificationAssociationResponse(@NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        boolean success = (flg & 0x1) != 0;
+        String errorMessage = (flg & 0x2) == 0 ? null : in.readString();
+        int[] values = (flg & 0x4) == 0 ? null : in.createIntArray();
+
+        this.mSuccess = success;
+        this.mErrorMessage = errorMessage;
+        this.mValues = values;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<UserIdentificationAssociationResponse> CREATOR
+            = new Parcelable.Creator<UserIdentificationAssociationResponse>() {
+        @Override
+        public UserIdentificationAssociationResponse[] newArray(int size) {
+            return new UserIdentificationAssociationResponse[size];
+        }
+
+        @Override
+        public UserIdentificationAssociationResponse createFromParcel(@NonNull android.os.Parcel in) {
+            return new UserIdentificationAssociationResponse(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1588982917194L,
+            codegenVersion = "1.0.15",
+            sourceFile = "packages/services/Car/car-lib/src/android/car/user/UserIdentificationAssociationResponse.java",
+            inputSignatures = "private final  boolean mSuccess\nprivate final @android.annotation.Nullable java.lang.String mErrorMessage\nprivate final @android.annotation.Nullable int[] mValues\npublic static @android.annotation.NonNull android.car.user.UserIdentificationAssociationResponse forFailure()\npublic static @android.annotation.NonNull android.car.user.UserIdentificationAssociationResponse forFailure(java.lang.String)\npublic static @android.annotation.NonNull android.car.user.UserIdentificationAssociationResponse forSuccess(int[])\npublic static @android.annotation.NonNull android.car.user.UserIdentificationAssociationResponse forSuccess(int[],java.lang.String)\nclass UserIdentificationAssociationResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=false, genHiddenConstDefs=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/car-lib/src/android/car/user/UserRemovalResult.aidl b/car-lib/src/android/car/user/UserRemovalResult.aidl
new file mode 100644
index 0000000..00a0eba
--- /dev/null
+++ b/car-lib/src/android/car/user/UserRemovalResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.user;
+
+parcelable UserRemovalResult;
diff --git a/car-lib/src/android/car/user/UserRemovalResult.java b/car-lib/src/android/car/user/UserRemovalResult.java
new file mode 100644
index 0000000..dbfd8a6
--- /dev/null
+++ b/car-lib/src/android/car/user/UserRemovalResult.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.user;
+
+import android.annotation.IntDef;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * User remove result.
+ *
+ * @hide
+ */
+@DataClass(
+        genToString = true,
+        genHiddenConstructor = true,
+        genHiddenConstDefs = true)
+public final class UserRemovalResult implements Parcelable {
+
+    /**
+     * When user remove is successful.
+     *
+     * @hide
+     */
+    public static final int STATUS_SUCCESSFUL = CommonResults.STATUS_SUCCESSFUL;
+
+    /**
+     * When user remove fails for android. Hal user is not removed.
+     *
+     * @hide
+     */
+    public static final int STATUS_ANDROID_FAILURE = CommonResults.STATUS_ANDROID_FAILURE;
+
+    /**
+     * When remove user fails for unknown error.
+     *
+     * @hide
+     */
+    public static final int STATUS_HAL_INTERNAL_FAILURE = CommonResults.STATUS_HAL_INTERNAL_FAILURE;
+
+     /**
+     * When user to remove is same as current user.
+     *
+     * @hide
+     */
+    public static final int STATUS_TARGET_USER_IS_CURRENT_USER =
+            CommonResults.LAST_COMMON_STATUS + 1;
+
+    /**
+     * When user to remove doesn't exits.
+     *
+     * @hide
+     */
+    public static final int STATUS_USER_DOES_NOT_EXIST = CommonResults.LAST_COMMON_STATUS + 2;
+
+    /**
+     * When user to remove is last admin user.
+     *
+     * @hide
+     */
+    public static final int STATUS_TARGET_USER_IS_LAST_ADMIN_USER =
+            CommonResults.LAST_COMMON_STATUS + 3;
+
+    /**
+     * Gets the user switch result status.
+     *
+     * @return either {@link UserRemovalResult#STATUS_SUCCESSFUL},
+     *         {@link UserRemovalResult#STATUS_ANDROID_FAILURE},
+     *         {@link UserRemovalResult#STATUS_HAL_INTERNAL_FAILURE},
+     *         {@link UserRemovalResult#STATUS_TARGET_USER_IS_CURRENT_USER},
+     *         {@link UserRemovalResult#STATUS_USER_DOES_NOT_EXIST}, or
+     *         {@link UserRemovalResult#STATUS_TARGET_USER_IS_LAST_ADMIN_USER}.
+     */
+    private final @Status int mStatus;
+
+    public boolean isSuccess() {
+        return mStatus == STATUS_SUCCESSFUL;
+    }
+
+    // TODO(b/158195639): if you change any status constant, you need to manually assign its values
+    // (rather than using CommonResults) before running codegen to regenerate the class
+
+
+    // Code below generated by codegen v1.0.15.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/user/UserRemovalResult.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /** @hide */
+    @IntDef(prefix = "STATUS_", value = {
+        STATUS_SUCCESSFUL,
+        STATUS_ANDROID_FAILURE,
+        STATUS_HAL_INTERNAL_FAILURE,
+        STATUS_TARGET_USER_IS_CURRENT_USER,
+        STATUS_USER_DOES_NOT_EXIST,
+        STATUS_TARGET_USER_IS_LAST_ADMIN_USER
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @DataClass.Generated.Member
+    public @interface Status {}
+
+    /** @hide */
+    @DataClass.Generated.Member
+    public static String statusToString(@Status int value) {
+        switch (value) {
+            case STATUS_SUCCESSFUL:
+                    return "STATUS_SUCCESSFUL";
+            case STATUS_ANDROID_FAILURE:
+                    return "STATUS_ANDROID_FAILURE";
+            case STATUS_HAL_INTERNAL_FAILURE:
+                    return "STATUS_HAL_INTERNAL_FAILURE";
+            case STATUS_TARGET_USER_IS_CURRENT_USER:
+                    return "STATUS_TARGET_USER_IS_CURRENT_USER";
+            case STATUS_USER_DOES_NOT_EXIST:
+                    return "STATUS_USER_DOES_NOT_EXIST";
+            case STATUS_TARGET_USER_IS_LAST_ADMIN_USER:
+                    return "STATUS_TARGET_USER_IS_LAST_ADMIN_USER";
+            default: return Integer.toHexString(value);
+        }
+    }
+
+    /**
+     * Creates a new UserRemovalResult.
+     *
+     * @param status
+     *   Gets the user switch result status.
+     *
+     *   @return either {@link UserRemovalResult#STATUS_SUCCESSFUL},
+     *           {@link UserRemovalResult#STATUS_ANDROID_FAILURE},
+     *           {@link UserRemovalResult#STATUS_HAL_INTERNAL_FAILURE},
+     *           {@link UserRemovalResult#STATUS_TARGET_USER_IS_CURRENT_USER},
+     *           {@link UserRemovalResult#STATUS_USER_DOES_NOT_EXIST}, or
+     *           {@link UserRemovalResult#STATUS_TARGET_USER_IS_LAST_ADMIN_USER}.
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public UserRemovalResult(
+            int status) {
+        this.mStatus = status;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * Gets the user switch result status.
+     *
+     * @return either {@link UserRemovalResult#STATUS_SUCCESSFUL},
+     *         {@link UserRemovalResult#STATUS_ANDROID_FAILURE},
+     *         {@link UserRemovalResult#STATUS_HAL_INTERNAL_FAILURE},
+     *         {@link UserRemovalResult#STATUS_TARGET_USER_IS_CURRENT_USER},
+     *         {@link UserRemovalResult#STATUS_USER_DOES_NOT_EXIST}, or
+     *         {@link UserRemovalResult#STATUS_TARGET_USER_IS_LAST_ADMIN_USER}.
+     */
+    @DataClass.Generated.Member
+    public int getStatus() {
+        return mStatus;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "UserRemovalResult { " +
+                "status = " + mStatus +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@android.annotation.NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeInt(mStatus);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ UserRemovalResult(@android.annotation.NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        int status = in.readInt();
+
+        this.mStatus = status;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @android.annotation.NonNull Parcelable.Creator<UserRemovalResult> CREATOR
+            = new Parcelable.Creator<UserRemovalResult>() {
+        @Override
+        public UserRemovalResult[] newArray(int size) {
+            return new UserRemovalResult[size];
+        }
+
+        @Override
+        public UserRemovalResult createFromParcel(@android.annotation.NonNull android.os.Parcel in) {
+            return new UserRemovalResult(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1591259644931L,
+            codegenVersion = "1.0.15",
+            sourceFile = "packages/services/Car/car-lib/src/android/car/user/UserRemovalResult.java",
+            inputSignatures = "public static final  int STATUS_SUCCESSFUL\npublic static final  int STATUS_ANDROID_FAILURE\npublic static final  int STATUS_HAL_INTERNAL_FAILURE\npublic static final  int STATUS_TARGET_USER_IS_CURRENT_USER\npublic static final  int STATUS_USER_DOES_NOT_EXIST\npublic static final  int STATUS_TARGET_USER_IS_LAST_ADMIN_USER\nprivate final  int mStatus\npublic  boolean isSuccess()\nclass UserRemovalResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/car-lib/src/android/car/user/UserSwitchResult.aidl b/car-lib/src/android/car/user/UserSwitchResult.aidl
new file mode 100644
index 0000000..10241c1
--- /dev/null
+++ b/car-lib/src/android/car/user/UserSwitchResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.user;
+
+parcelable UserSwitchResult;
diff --git a/car-lib/src/android/car/user/UserSwitchResult.java b/car-lib/src/android/car/user/UserSwitchResult.java
new file mode 100644
index 0000000..5c1ca23
--- /dev/null
+++ b/car-lib/src/android/car/user/UserSwitchResult.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.user;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * User switch results.
+ *
+ * @hide
+ */
+@DataClass(
+        genToString = true,
+        genHiddenConstructor = true,
+        genHiddenConstDefs = true)
+public final class UserSwitchResult implements Parcelable {
+
+    /**
+     * When user switch is successful for both HAL and Android.
+     */
+    public static final int STATUS_SUCCESSFUL = CommonResults.STATUS_SUCCESSFUL;
+
+    /**
+     * When user switch is only successful for Hal but not for Android. Hal user switch rollover
+     * message have been sent.
+     */
+    public static final int STATUS_ANDROID_FAILURE = CommonResults.STATUS_ANDROID_FAILURE;
+
+    /**
+     * When user switch fails for HAL. User switch for Android is not called.
+     */
+    public static final int STATUS_HAL_FAILURE = CommonResults.STATUS_HAL_FAILURE;
+
+    /**
+     * When user switch fails for HAL for some internal error. User switch for Android is not
+     * called.
+     */
+    public static final int STATUS_HAL_INTERNAL_FAILURE = CommonResults.STATUS_HAL_INTERNAL_FAILURE;
+
+    /**
+     * When given parameters or environment states are invalid for switching user. HAL or Android
+     * user switch is not requested.
+     */
+    public static final int STATUS_INVALID_REQUEST = CommonResults.STATUS_INVALID_REQUEST;
+
+    /**
+     * When target user is same as current user.
+     */
+    public static final int STATUS_OK_USER_ALREADY_IN_FOREGROUND =
+            CommonResults.LAST_COMMON_STATUS + 1;
+
+    /**
+     * When another user switch request for the same target user is in process.
+     */
+    public static final int STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO =
+            CommonResults.LAST_COMMON_STATUS + 2;
+
+    /**
+     * When another user switch request for a new different target user is received. Previous
+     * request is abandoned.
+     */
+    public static final int STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST =
+            CommonResults.LAST_COMMON_STATUS + 3;
+
+    /**
+     * When switching users is currently not allowed for the user this process is running under.
+     */
+    public static final int STATUS_NOT_SWITCHABLE =
+            CommonResults.LAST_COMMON_STATUS + 4;
+
+    /**
+     * Gets the user switch result status.
+     *
+     * @return either {@link UserSwitchResult#STATUS_SUCCESSFUL},
+     *         {@link UserSwitchResult#STATUS_ANDROID_FAILURE},
+     *         {@link UserSwitchResult#STATUS_HAL_FAILURE},
+     *         {@link UserSwitchResult#STATUS_HAL_INTERNAL_FAILURE},
+     *         {@link UserSwitchResult#STATUS_INVALID_REQUEST},
+     *         {@link UserSwitchResult#STATUS_OK_USER_ALREADY_IN_FOREGROUND},
+     *         {@link UserSwitchResult#STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO},
+     *         {@link UserSwitchResult#STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST}, or
+     *         {@link UserSwitchResult#STATUS_NOT_SWITCHABLE}.
+     */
+    private final @Status int mStatus;
+
+    /**
+     * Gets the error message, if any.
+     */
+    @Nullable
+    private final String mErrorMessage;
+
+    /**
+     * Check if {@link UserSwitchResult} is successful.
+     */
+    public boolean isSuccess() {
+        return mStatus == STATUS_SUCCESSFUL || mStatus == STATUS_OK_USER_ALREADY_IN_FOREGROUND;
+    }
+
+    // TODO(b/158195639): if you change any status constant, you need to manually assign its values
+    // (rather than using CommonResults) before running codegen to regenerate the class
+
+
+    // Code below generated by codegen v1.0.15.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/user/UserSwitchResult.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /** @hide */
+    @IntDef(prefix = "STATUS_", value = {
+        STATUS_SUCCESSFUL,
+        STATUS_ANDROID_FAILURE,
+        STATUS_HAL_FAILURE,
+        STATUS_HAL_INTERNAL_FAILURE,
+        STATUS_INVALID_REQUEST,
+        STATUS_OK_USER_ALREADY_IN_FOREGROUND,
+        STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO,
+        STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST,
+        STATUS_NOT_SWITCHABLE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @DataClass.Generated.Member
+    public @interface Status {}
+
+    /** @hide */
+    @DataClass.Generated.Member
+    public static String statusToString(@Status int value) {
+        switch (value) {
+            case STATUS_SUCCESSFUL:
+                    return "STATUS_SUCCESSFUL";
+            case STATUS_ANDROID_FAILURE:
+                    return "STATUS_ANDROID_FAILURE";
+            case STATUS_HAL_FAILURE:
+                    return "STATUS_HAL_FAILURE";
+            case STATUS_HAL_INTERNAL_FAILURE:
+                    return "STATUS_HAL_INTERNAL_FAILURE";
+            case STATUS_INVALID_REQUEST:
+                    return "STATUS_INVALID_REQUEST";
+            case STATUS_OK_USER_ALREADY_IN_FOREGROUND:
+                    return "STATUS_OK_USER_ALREADY_IN_FOREGROUND";
+            case STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO:
+                    return "STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO";
+            case STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST:
+                    return "STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST";
+            case STATUS_NOT_SWITCHABLE:
+                    return "STATUS_NOT_SWITCHABLE";
+            default: return Integer.toHexString(value);
+        }
+    }
+
+    /**
+     * Creates a new UserSwitchResult.
+     *
+     * @param status
+     *   Gets the user switch result status.
+     *
+     *   @return either {@link UserSwitchResult#STATUS_SUCCESSFUL},
+     *           {@link UserSwitchResult#STATUS_ANDROID_FAILURE},
+     *           {@link UserSwitchResult#STATUS_HAL_FAILURE},
+     *           {@link UserSwitchResult#STATUS_HAL_INTERNAL_FAILURE},
+     *           {@link UserSwitchResult#STATUS_INVALID_REQUEST},
+     *           {@link UserSwitchResult#STATUS_OK_USER_ALREADY_IN_FOREGROUND},
+     *           {@link UserSwitchResult#STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO},
+     *           {@link UserSwitchResult#STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST}, or
+     *           {@link UserSwitchResult#STATUS_NOT_SWITCHABLE}.
+     * @param errorMessage
+     *   Gets the error message, if any.
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public UserSwitchResult(
+            @Status int status,
+            @Nullable String errorMessage) {
+        this.mStatus = status;
+
+        if (!(mStatus == STATUS_SUCCESSFUL)
+                && !(mStatus == STATUS_ANDROID_FAILURE)
+                && !(mStatus == STATUS_HAL_FAILURE)
+                && !(mStatus == STATUS_HAL_INTERNAL_FAILURE)
+                && !(mStatus == STATUS_INVALID_REQUEST)
+                && !(mStatus == STATUS_OK_USER_ALREADY_IN_FOREGROUND)
+                && !(mStatus == STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO)
+                && !(mStatus == STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST)
+                && !(mStatus == STATUS_NOT_SWITCHABLE)) {
+            throw new java.lang.IllegalArgumentException(
+                    "status was " + mStatus + " but must be one of: "
+                            + "STATUS_SUCCESSFUL(" + STATUS_SUCCESSFUL + "), "
+                            + "STATUS_ANDROID_FAILURE(" + STATUS_ANDROID_FAILURE + "), "
+                            + "STATUS_HAL_FAILURE(" + STATUS_HAL_FAILURE + "), "
+                            + "STATUS_HAL_INTERNAL_FAILURE(" + STATUS_HAL_INTERNAL_FAILURE + "), "
+                            + "STATUS_INVALID_REQUEST(" + STATUS_INVALID_REQUEST + "), "
+                            + "STATUS_OK_USER_ALREADY_IN_FOREGROUND(" + STATUS_OK_USER_ALREADY_IN_FOREGROUND + "), "
+                            + "STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO(" + STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO + "), "
+                            + "STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST(" + STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST + "), "
+                            + "STATUS_NOT_SWITCHABLE(" + STATUS_NOT_SWITCHABLE + ")");
+        }
+
+        this.mErrorMessage = errorMessage;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * Gets the user switch result status.
+     *
+     * @return either {@link UserSwitchResult#STATUS_SUCCESSFUL},
+     *         {@link UserSwitchResult#STATUS_ANDROID_FAILURE},
+     *         {@link UserSwitchResult#STATUS_HAL_FAILURE},
+     *         {@link UserSwitchResult#STATUS_HAL_INTERNAL_FAILURE},
+     *         {@link UserSwitchResult#STATUS_INVALID_REQUEST},
+     *         {@link UserSwitchResult#STATUS_OK_USER_ALREADY_IN_FOREGROUND},
+     *         {@link UserSwitchResult#STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO},
+     *         {@link UserSwitchResult#STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST}, or
+     *         {@link UserSwitchResult#STATUS_NOT_SWITCHABLE}.
+     */
+    @DataClass.Generated.Member
+    public @Status int getStatus() {
+        return mStatus;
+    }
+
+    /**
+     * Gets the error message, if any.
+     */
+    @DataClass.Generated.Member
+    public @Nullable String getErrorMessage() {
+        return mErrorMessage;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "UserSwitchResult { " +
+                "status = " + statusToString(mStatus) + ", " +
+                "errorMessage = " + mErrorMessage +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@android.annotation.NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        byte flg = 0;
+        if (mErrorMessage != null) flg |= 0x2;
+        dest.writeByte(flg);
+        dest.writeInt(mStatus);
+        if (mErrorMessage != null) dest.writeString(mErrorMessage);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ UserSwitchResult(@android.annotation.NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        int status = in.readInt();
+        String errorMessage = (flg & 0x2) == 0 ? null : in.readString();
+
+        this.mStatus = status;
+
+        if (!(mStatus == STATUS_SUCCESSFUL)
+                && !(mStatus == STATUS_ANDROID_FAILURE)
+                && !(mStatus == STATUS_HAL_FAILURE)
+                && !(mStatus == STATUS_HAL_INTERNAL_FAILURE)
+                && !(mStatus == STATUS_INVALID_REQUEST)
+                && !(mStatus == STATUS_OK_USER_ALREADY_IN_FOREGROUND)
+                && !(mStatus == STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO)
+                && !(mStatus == STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST)
+                && !(mStatus == STATUS_NOT_SWITCHABLE)) {
+            throw new java.lang.IllegalArgumentException(
+                    "status was " + mStatus + " but must be one of: "
+                            + "STATUS_SUCCESSFUL(" + STATUS_SUCCESSFUL + "), "
+                            + "STATUS_ANDROID_FAILURE(" + STATUS_ANDROID_FAILURE + "), "
+                            + "STATUS_HAL_FAILURE(" + STATUS_HAL_FAILURE + "), "
+                            + "STATUS_HAL_INTERNAL_FAILURE(" + STATUS_HAL_INTERNAL_FAILURE + "), "
+                            + "STATUS_INVALID_REQUEST(" + STATUS_INVALID_REQUEST + "), "
+                            + "STATUS_OK_USER_ALREADY_IN_FOREGROUND(" + STATUS_OK_USER_ALREADY_IN_FOREGROUND + "), "
+                            + "STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO(" + STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO + "), "
+                            + "STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST(" + STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST + "), "
+                            + "STATUS_NOT_SWITCHABLE(" + STATUS_NOT_SWITCHABLE + ")");
+        }
+
+        this.mErrorMessage = errorMessage;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @android.annotation.NonNull Parcelable.Creator<UserSwitchResult> CREATOR
+            = new Parcelable.Creator<UserSwitchResult>() {
+        @Override
+        public UserSwitchResult[] newArray(int size) {
+            return new UserSwitchResult[size];
+        }
+
+        @Override
+        public UserSwitchResult createFromParcel(@android.annotation.NonNull android.os.Parcel in) {
+            return new UserSwitchResult(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1592422606349L,
+            codegenVersion = "1.0.15",
+            sourceFile = "packages/services/Car/car-lib/src/android/car/user/UserSwitchResult.java",
+            inputSignatures = "public static final  int STATUS_SUCCESSFUL\npublic static final  int STATUS_ANDROID_FAILURE\npublic static final  int STATUS_HAL_FAILURE\npublic static final  int STATUS_HAL_INTERNAL_FAILURE\npublic static final  int STATUS_INVALID_REQUEST\npublic static final  int STATUS_OK_USER_ALREADY_IN_FOREGROUND\npublic static final  int STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO\npublic static final  int STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST\npublic static final  int STATUS_NOT_SWITCHABLE\nprivate final @android.car.user.UserSwitchResult.Status int mStatus\nprivate final @android.annotation.Nullable java.lang.String mErrorMessage\npublic  boolean isSuccess()\nclass UserSwitchResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+}
diff --git a/car-lib/src/android/car/vms/IVmsBrokerService.aidl b/car-lib/src/android/car/vms/IVmsBrokerService.aidl
new file mode 100644
index 0000000..28b50a6
--- /dev/null
+++ b/car-lib/src/android/car/vms/IVmsBrokerService.aidl
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.vms;
+
+import android.car.vms.IVmsClientCallback;
+import android.car.vms.VmsAssociatedLayer;
+import android.car.vms.VmsLayer;
+import android.car.vms.VmsLayerDependency;
+import android.car.vms.VmsProviderInfo;
+import android.car.vms.VmsRegistrationInfo;
+import android.os.SharedMemory;
+
+/**
+ * Hidden API for communicating with the Vehicle Map Service message broker.
+ *
+ * @hide
+ */
+interface IVmsBrokerService {
+    // Client operations
+    // Restricted to callers with android.car.permission.VMS_SUBSCRIBER
+    // or android.car.permission.VMS_PUBLISHER
+
+    VmsRegistrationInfo registerClient(
+    in IBinder token,
+    in IVmsClientCallback callback,
+    boolean legacyClient) = 0;
+
+    void unregisterClient(in IBinder token) = 1;
+
+    VmsProviderInfo getProviderInfo(in IBinder token, int providerId) = 2;
+
+    // Subscriber operations
+    // Restricted to callers with android.car.permission.VMS_SUBSCRIBER
+
+    void setSubscriptions(
+        in IBinder token,
+        in List<VmsAssociatedLayer> layers) = 3;
+
+    void setMonitoringEnabled(in IBinder token, boolean enabled) = 4;
+
+    // Publisher operations
+    // Restricted to callers with android.car.permission.VMS_PUBLISHER
+
+    int registerProvider(
+        in IBinder token,
+        in VmsProviderInfo providerInfo) = 5;
+
+    void setProviderOfferings(
+        in IBinder token,
+        int providerId,
+        in List<VmsLayerDependency> offerings) = 6;
+
+    void publishPacket(
+        in IBinder token,
+        int providerId,
+        in VmsLayer layer,
+        in byte[] packet) = 7;
+
+    void publishLargePacket(
+        in IBinder token,
+        int providerId,
+        in VmsLayer layer,
+        in SharedMemory packet) = 8;
+}
diff --git a/car-lib/src/android/car/vms/IVmsClientCallback.aidl b/car-lib/src/android/car/vms/IVmsClientCallback.aidl
new file mode 100644
index 0000000..c9b2f96
--- /dev/null
+++ b/car-lib/src/android/car/vms/IVmsClientCallback.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.vms;
+
+import android.car.vms.VmsAvailableLayers;
+import android.car.vms.VmsLayer;
+import android.car.vms.VmsSubscriptionState;
+import android.os.SharedMemory;
+
+/**
+ * Hidden API for sending notifications to Vehicle Map Service clients.
+ *
+ * @hide
+ */
+oneway interface IVmsClientCallback {
+    void onLayerAvailabilityChanged(
+        in VmsAvailableLayers availableLayers) = 0;
+
+    void onSubscriptionStateChanged(
+        in VmsSubscriptionState subscriptionState) = 1;
+
+    void onPacketReceived(
+        int providerId,
+        in VmsLayer layer,
+        in byte[] packet) = 2;
+
+    void onLargePacketReceived(
+        int providerId,
+        in VmsLayer layer,
+        in SharedMemory packet) = 3;
+}
diff --git a/car-lib/src/android/car/vms/IVmsPublisherClient.aidl b/car-lib/src/android/car/vms/IVmsPublisherClient.aidl
deleted file mode 100644
index 96b993b..0000000
--- a/car-lib/src/android/car/vms/IVmsPublisherClient.aidl
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.car.vms;
-
-import android.car.vms.IVmsPublisherService;
-import android.car.vms.VmsSubscriptionState;
-
-/**
- * @hide
- */
-interface IVmsPublisherClient {
-    /**
-    * Once the VmsPublisherService is bound to the client, this callback is used to set the
-    * binder that the client can use to invoke publisher services. This also gives the client
-    * the token it should use when calling the service.
-    */
-    oneway void setVmsPublisherService(in IBinder token, IVmsPublisherService service) = 0;
-
-    /**
-     * The VmsPublisherService uses this callback to notify about subscription changes.
-     * @param subscriptionState all the layers that have subscribers and a sequence number,
-     *                          clients should ignore any packet with a sequence number that is less
-     *                          than the highest sequence number they have seen thus far.
-     */
-    oneway void onVmsSubscriptionChange(in VmsSubscriptionState subscriptionState) = 1;
-}
diff --git a/car-lib/src/android/car/vms/IVmsPublisherService.aidl b/car-lib/src/android/car/vms/IVmsPublisherService.aidl
deleted file mode 100644
index 3c26a1b..0000000
--- a/car-lib/src/android/car/vms/IVmsPublisherService.aidl
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.car.vms;
-
-import android.car.vms.VmsLayer;
-import android.car.vms.VmsLayersOffering;
-import android.car.vms.VmsSubscriptionState;
-
-/**
- * Exposes publisher services to VMS clients.
- *
- * @hide
- */
-interface IVmsPublisherService {
-    /**
-     * Client call to publish a message.
-     */
-    oneway void publish(in IBinder token, in VmsLayer layer, int publisherId, in byte[] message) = 0;
-
-    /**
-     * Returns the list of VmsLayers that has any clients subscribed to it.
-     */
-    VmsSubscriptionState getSubscriptions() = 1;
-
-    /**
-     * Sets which layers the publisher can publish under which dependencties.
-     */
-    oneway void setLayersOffering(in IBinder token, in VmsLayersOffering offering) = 2;
-
-    /**
-     * The first time a publisher calls this API it will store the publisher info and assigns the
-     * publisher an ID. Between reboots, subsequent calls with the same publisher info will
-     * return the same ID so that a restarting process can obtain the same ID as it had before.
-     */
-    int getPublisherId(in byte[] publisherInfo) = 3;
-}
diff --git a/car-lib/src/android/car/vms/IVmsSubscriberClient.aidl b/car-lib/src/android/car/vms/IVmsSubscriberClient.aidl
deleted file mode 100644
index 8f67cd5..0000000
--- a/car-lib/src/android/car/vms/IVmsSubscriberClient.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.car.vms;
-
-import android.car.vms.VmsAvailableLayers;
-import android.car.vms.VmsLayer;
-
-/**
- * @hide
- */
-oneway interface IVmsSubscriberClient {
-    /**
-     * A VmsService uses this callback to pass messages to subscribers.
-     */
-    void onVmsMessageReceived(in VmsLayer layer, in byte[] payload) = 0;
-
-    void onLayersAvailabilityChanged(in VmsAvailableLayers availableLayers) = 1;
-}
diff --git a/car-lib/src/android/car/vms/IVmsSubscriberService.aidl b/car-lib/src/android/car/vms/IVmsSubscriberService.aidl
deleted file mode 100644
index 661065a..0000000
--- a/car-lib/src/android/car/vms/IVmsSubscriberService.aidl
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.car.vms;
-
-import android.car.vms.IVmsSubscriberClient;
-import android.car.vms.VmsLayer;
-import android.car.vms.VmsAvailableLayers;
-
-/**
- * @hide
- */
-interface IVmsSubscriberService {
-    /**
-     * Adds a subscriber to notifications only.
-     * Should be called when a subscriber registers its callback, and before any subscription to a
-     * layer is made.
-     */
-    void addVmsSubscriberToNotifications(
-            in IVmsSubscriberClient subscriber) = 0;
-
-    /**
-     * Adds a subscriber to a VMS layer.
-     */
-    void addVmsSubscriber(
-            in IVmsSubscriberClient subscriber,
-            in VmsLayer layer) = 1;
-
-    /**
-     * Adds a subscriber to all actively broadcasted layers.
-     * Publishers will not be notified regarding this request so the state of the service will not
-     * change.
-     */
-    void addVmsSubscriberPassive(in IVmsSubscriberClient subscriber) = 2;
-
-    /**
-     * Adds a subscriber to a VMS layer from a specific publisher.
-     */
-    void addVmsSubscriberToPublisher(
-            in IVmsSubscriberClient subscriber,
-            in VmsLayer layer,
-            int publisherId) = 3;
-
-    /**
-     * Removes a subscriber to notifications only.
-     * Should be called when a subscriber unregisters its callback, and after all subscriptions to
-     * layers are removed.
-     */
-    void removeVmsSubscriberToNotifications(
-            in IVmsSubscriberClient subscriber) = 4;
-
-    /**
-     * Removes a subscriber to a VMS layer.
-     */
-    void removeVmsSubscriber(
-            in IVmsSubscriberClient subscriber,
-            in VmsLayer layer) = 5;
-
-    /**
-     * Removes a subscriber to all actively broadcasted layers.
-     * Publishers will not be notified regarding this request so the state of the service will not
-     * change.
-     */
-    void removeVmsSubscriberPassive(
-            in IVmsSubscriberClient subscriber) = 6;
-
-    /**
-     * Removes a subscriber to a VMS layer from a specific publisher.
-     */
-    void removeVmsSubscriberToPublisher(
-            in IVmsSubscriberClient subscriber,
-            in VmsLayer layer,
-            int publisherId) = 7;
-
-    /**
-     * Returns a list of available layers from the closure of the publishers offerings.
-     */
-    VmsAvailableLayers getAvailableLayers() = 8;
-
-    /**
-     *  Returns a the publisher information for a publisher ID.
-     */
-    byte[] getPublisherInfo(in int publisherId) = 9;
-}
diff --git a/car-lib/src/android/car/vms/VmsAssociatedLayer.java b/car-lib/src/android/car/vms/VmsAssociatedLayer.java
index e522faa..7443857 100644
--- a/car-lib/src/android/car/vms/VmsAssociatedLayer.java
+++ b/car-lib/src/android/car/vms/VmsAssociatedLayer.java
@@ -20,10 +20,13 @@
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.ArraySet;
 
-import com.android.internal.util.Preconditions;
+import com.android.internal.util.DataClass;
 
-import java.util.*;
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Set;
 
 /**
  * A Vehicle Map Service layer with a list of publisher IDs it is associated with.
@@ -31,85 +34,194 @@
  * @hide
  */
 @SystemApi
+@DataClass(genAidl = true, genEqualsHashCode = true, genToString = true)
 public final class VmsAssociatedLayer implements Parcelable {
-    private final VmsLayer mLayer;
-    private final Set<Integer> mPublisherIds;
+    /**
+     * Layer being offered
+     */
+    private final @NonNull VmsLayer mVmsLayer;
 
     /**
-     * Constructs a new layer offering.
+     * IDs of providers that publish the layer
+     */
+    private @NonNull Set<Integer> mProviderIds;
+
+    private void onConstructed() {
+        mProviderIds = Collections.unmodifiableSet(mProviderIds);
+    }
+
+    private void parcelProviderIds(Parcel dest, int flags) {
+        dest.writeArraySet(new ArraySet<>(mProviderIds));
+    }
+
+    @SuppressWarnings("unchecked")
+    private Set<Integer> unparcelProviderIds(Parcel in) {
+        return (Set<Integer>) in.readArraySet(Integer.class.getClassLoader());
+    }
+
+    /**
+     * IDs of publishers that publish the layer
      *
-     * @param layer layer being offered
-     * @param publisherIds IDs of publishers associated with the layer
+     * @deprecated Use {@link #getProviderIds()} instead
      */
-    public VmsAssociatedLayer(@NonNull VmsLayer layer, @NonNull Set<Integer> publisherIds) {
-        mLayer = Preconditions.checkNotNull(layer, "layer cannot be null");
-        mPublisherIds = Collections.unmodifiableSet(publisherIds);
-    }
-
-    /**
-     * @return layer being offered
-     */
-    @NonNull
-    public VmsLayer getVmsLayer() {
-        return mLayer;
-    }
-
-    /**
-     * @return IDs of publishers associated with the layer
-     */
+    @Deprecated
     @NonNull
     public Set<Integer> getPublisherIds() {
-        return mPublisherIds;
+        return mProviderIds;
+    }
+
+
+
+    // Code below generated by codegen v1.0.14.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/vms/VmsAssociatedLayer.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new VmsAssociatedLayer.
+     *
+     * @param vmsLayer
+     *   Layer being offered
+     * @param providerIds
+     *   IDs of providers that publish the layer
+     */
+    @DataClass.Generated.Member
+    public VmsAssociatedLayer(
+            @NonNull VmsLayer vmsLayer,
+            @NonNull Set<Integer> providerIds) {
+        this.mVmsLayer = vmsLayer;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mVmsLayer);
+        this.mProviderIds = providerIds;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mProviderIds);
+
+        onConstructed();
+    }
+
+    /**
+     * Layer being offered
+     */
+    @DataClass.Generated.Member
+    public @NonNull VmsLayer getVmsLayer() {
+        return mVmsLayer;
+    }
+
+    /**
+     * IDs of providers that publish the layer
+     */
+    @DataClass.Generated.Member
+    public @NonNull Set<Integer> getProviderIds() {
+        return mProviderIds;
     }
 
     @Override
+    @DataClass.Generated.Member
     public String toString() {
-        return "VmsAssociatedLayer{ VmsLayer: " + mLayer + ", Publishers: " + mPublisherIds + "}";
-    }
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
 
-    public static final Parcelable.Creator<VmsAssociatedLayer> CREATOR =
-            new Parcelable.Creator<VmsAssociatedLayer>() {
-                public VmsAssociatedLayer createFromParcel(Parcel in) {
-                    return new VmsAssociatedLayer(in);
-                }
-
-                public VmsAssociatedLayer[] newArray(int size) {
-                    return new VmsAssociatedLayer[size];
-                }
-            };
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeParcelable(mLayer, flags);
-        out.writeArray(mPublisherIds.toArray());
+        return "VmsAssociatedLayer { " +
+                "vmsLayer = " + mVmsLayer + ", " +
+                "providerIds = " + mProviderIds +
+        " }";
     }
 
     @Override
-    public boolean equals(Object o) {
-        if (!(o instanceof VmsAssociatedLayer)) {
-            return false;
-        }
-        VmsAssociatedLayer p = (VmsAssociatedLayer) o;
-        return Objects.equals(p.mLayer, mLayer) && p.mPublisherIds.equals(mPublisherIds);
+    @DataClass.Generated.Member
+    public boolean equals(@android.annotation.Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(VmsAssociatedLayer other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        VmsAssociatedLayer that = (VmsAssociatedLayer) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && Objects.equals(mVmsLayer, that.mVmsLayer)
+                && Objects.equals(mProviderIds, that.mProviderIds);
     }
 
     @Override
+    @DataClass.Generated.Member
     public int hashCode() {
-        return Objects.hash(mLayer, mPublisherIds);
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + Objects.hashCode(mVmsLayer);
+        _hash = 31 * _hash + Objects.hashCode(mProviderIds);
+        return _hash;
     }
 
     @Override
-    public int describeContents() {
-        return 0;
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeTypedObject(mVmsLayer, flags);
+        parcelProviderIds(dest, flags);
     }
 
-    private VmsAssociatedLayer(Parcel in) {
-        mLayer = in.readParcelable(VmsLayer.class.getClassLoader());
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
 
-        Object[] objects = in.readArray(Integer.class.getClassLoader());
-        Integer[] integers = Arrays.copyOf(objects, objects.length, Integer[].class);
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ VmsAssociatedLayer(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
 
-        mPublisherIds = Collections.unmodifiableSet(
-                new HashSet<>(Arrays.asList(integers)));
+        VmsLayer vmsLayer = (VmsLayer) in.readTypedObject(VmsLayer.CREATOR);
+        Set<Integer> providerIds = unparcelProviderIds(in);
+
+        this.mVmsLayer = vmsLayer;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mVmsLayer);
+        this.mProviderIds = providerIds;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mProviderIds);
+
+        onConstructed();
     }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<VmsAssociatedLayer> CREATOR
+            = new Parcelable.Creator<VmsAssociatedLayer>() {
+        @Override
+        public VmsAssociatedLayer[] newArray(int size) {
+            return new VmsAssociatedLayer[size];
+        }
+
+        @Override
+        public VmsAssociatedLayer createFromParcel(@NonNull Parcel in) {
+            return new VmsAssociatedLayer(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1582065953302L,
+            codegenVersion = "1.0.14",
+            sourceFile = "packages/services/Car/car-lib/src/android/car/vms/VmsAssociatedLayer.java",
+            inputSignatures = "private final @android.annotation.NonNull android.car.vms.VmsLayer mVmsLayer\nprivate @android.annotation.NonNull android.car.vms.Set<java.lang.Integer> mProviderIds\nprivate  void onConstructed()\nprivate  void parcelProviderIds(android.os.Parcel,int)\nprivate @java.lang.SuppressWarnings(\"unchecked\") android.car.vms.Set<java.lang.Integer> unparcelProviderIds(android.os.Parcel)\npublic @java.lang.Deprecated @android.annotation.NonNull android.car.vms.Set<java.lang.Integer> getPublisherIds()\nclass VmsAssociatedLayer extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genEqualsHashCode=true, genToString=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
 }
diff --git a/car-lib/src/android/car/vms/VmsAvailableLayers.java b/car-lib/src/android/car/vms/VmsAvailableLayers.java
index 3852a7f..cfd55bc 100644
--- a/car-lib/src/android/car/vms/VmsAvailableLayers.java
+++ b/car-lib/src/android/car/vms/VmsAvailableLayers.java
@@ -20,12 +20,11 @@
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.ArraySet;
 
-import java.util.ArrayList;
+import com.android.internal.util.DataClass;
+
 import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -42,88 +41,204 @@
  * @hide
  */
 @SystemApi
+@DataClass(genAidl = true, genEqualsHashCode = true, genToString = true)
 public final class VmsAvailableLayers implements Parcelable {
-
-    // A sequence number.
-    private final int mSeq;
-
-    // The list of AssociatedLayers
-    private final Set<VmsAssociatedLayer> mAssociatedLayers;
+    /**
+     * Sequence number of the availability state
+     */
+    private final int mSequenceNumber;
 
     /**
-     * Constructs a new layer availability.
+     * Set of layers available for subscription
+     */
+    private @NonNull Set<VmsAssociatedLayer> mAssociatedLayers;
+
+    private void onConstructed() {
+        mAssociatedLayers = Collections.unmodifiableSet(mAssociatedLayers);
+    }
+
+    private void parcelAssociatedLayers(Parcel dest, int flags) {
+        dest.writeArraySet(new ArraySet<>(mAssociatedLayers));
+    }
+
+    @SuppressWarnings("unchecked")
+    private Set<VmsAssociatedLayer> unparcelAssociatedLayers(Parcel in) {
+        return (Set<VmsAssociatedLayer>) in.readArraySet(VmsAssociatedLayer.class.getClassLoader());
+    }
+
+    /**
+     * Creates a new VmsAvailableLayers.
      *
-     * @param associatedLayers set of layers available for subscription
-     * @param sequence         sequence number of the availability state
+     * @param associatedLayers
+     *   Set of layers available for subscription
+     * @param sequenceNumber
+     *   Sequence number of the availability state
+     * @deprecated Use {@link #VmsAvailableLayers(int, Set)} instead
      */
-    public VmsAvailableLayers(@NonNull Set<VmsAssociatedLayer> associatedLayers, int sequence) {
-        mSeq = sequence;
-        mAssociatedLayers = Collections.unmodifiableSet(associatedLayers);
+    @Deprecated
+    public VmsAvailableLayers(@NonNull Set<VmsAssociatedLayer> associatedLayers,
+            int sequenceNumber) {
+        this(sequenceNumber, associatedLayers);
     }
 
     /**
-     * @return sequence number of the availability state
+     * Sequence number of the availability state
+     *
+     * @deprecated Use {@link #getSequenceNumber()} instead
      */
+    @Deprecated
     public int getSequence() {
-        return mSeq;
+        return mSequenceNumber;
+    }
+
+
+
+    // Code below generated by codegen v1.0.14.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/vms/VmsAvailableLayers.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new VmsAvailableLayers.
+     *
+     * @param sequenceNumber
+     *   Sequence number of the availability state
+     * @param associatedLayers
+     *   Set of layers available for subscription
+     */
+    @DataClass.Generated.Member
+    public VmsAvailableLayers(
+            int sequenceNumber,
+            @NonNull Set<VmsAssociatedLayer> associatedLayers) {
+        this.mSequenceNumber = sequenceNumber;
+        this.mAssociatedLayers = associatedLayers;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mAssociatedLayers);
+
+        onConstructed();
     }
 
     /**
-     * @return set of layers available for subscription
+     * Sequence number of the availability state
      */
-    @NonNull
-    public Set<VmsAssociatedLayer> getAssociatedLayers() {
+    @DataClass.Generated.Member
+    public int getSequenceNumber() {
+        return mSequenceNumber;
+    }
+
+    /**
+     * Set of layers available for subscription
+     */
+    @DataClass.Generated.Member
+    public @NonNull Set<VmsAssociatedLayer> getAssociatedLayers() {
         return mAssociatedLayers;
     }
 
     @Override
+    @DataClass.Generated.Member
     public String toString() {
-        return "VmsAvailableLayers{ seq: " +
-                mSeq +
-                ", AssociatedLayers: " +
-                mAssociatedLayers +
-                "}";
-    }
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
 
-
-    // Parcelable related methods.
-    public static final Parcelable.Creator<VmsAvailableLayers> CREATOR = new
-            Parcelable.Creator<VmsAvailableLayers>() {
-                public VmsAvailableLayers createFromParcel(Parcel in) {
-                    return new VmsAvailableLayers(in);
-                }
-
-                public VmsAvailableLayers[] newArray(int size) {
-                    return new VmsAvailableLayers[size];
-                }
-            };
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(mSeq);
-        out.writeParcelableList(new ArrayList(mAssociatedLayers), flags);
+        return "VmsAvailableLayers { " +
+                "sequenceNumber = " + mSequenceNumber + ", " +
+                "associatedLayers = " + mAssociatedLayers +
+        " }";
     }
 
     @Override
-    public boolean equals(Object o) {
-        if (!(o instanceof VmsAvailableLayers)) {
-            return false;
+    @DataClass.Generated.Member
+    public boolean equals(@android.annotation.Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(VmsAvailableLayers other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        VmsAvailableLayers that = (VmsAvailableLayers) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && mSequenceNumber == that.mSequenceNumber
+                && java.util.Objects.equals(mAssociatedLayers, that.mAssociatedLayers);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + mSequenceNumber;
+        _hash = 31 * _hash + java.util.Objects.hashCode(mAssociatedLayers);
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeInt(mSequenceNumber);
+        parcelAssociatedLayers(dest, flags);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ VmsAvailableLayers(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        int sequenceNumber = in.readInt();
+        Set<VmsAssociatedLayer> associatedLayers = unparcelAssociatedLayers(in);
+
+        this.mSequenceNumber = sequenceNumber;
+        this.mAssociatedLayers = associatedLayers;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mAssociatedLayers);
+
+        onConstructed();
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<VmsAvailableLayers> CREATOR
+            = new Parcelable.Creator<VmsAvailableLayers>() {
+        @Override
+        public VmsAvailableLayers[] newArray(int size) {
+            return new VmsAvailableLayers[size];
         }
-        VmsAvailableLayers p = (VmsAvailableLayers) o;
-        return Objects.equals(p.mAssociatedLayers, mAssociatedLayers) &&
-                p.mSeq == mSeq;
-    }
 
-    @Override
-    public int describeContents() {
-        return 0;
-    }
+        @Override
+        public VmsAvailableLayers createFromParcel(@NonNull Parcel in) {
+            return new VmsAvailableLayers(in);
+        }
+    };
 
-    private VmsAvailableLayers(Parcel in) {
-        mSeq = in.readInt();
+    @DataClass.Generated(
+            time = 1582066089314L,
+            codegenVersion = "1.0.14",
+            sourceFile = "packages/services/Car/car-lib/src/android/car/vms/VmsAvailableLayers.java",
+            inputSignatures = "private final  int mSequenceNumber\nprivate @android.annotation.NonNull java.util.Set<android.car.vms.VmsAssociatedLayer> mAssociatedLayers\nprivate  void onConstructed()\nprivate  void parcelAssociatedLayers(android.os.Parcel,int)\nprivate @java.lang.SuppressWarnings(\"unchecked\") java.util.Set<android.car.vms.VmsAssociatedLayer> unparcelAssociatedLayers(android.os.Parcel)\npublic @java.lang.Deprecated int getSequence()\nclass VmsAvailableLayers extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genEqualsHashCode=true, genToString=true)")
+    @Deprecated
+    private void __metadata() {}
 
-        List<VmsAssociatedLayer> associatedLayers = new ArrayList<>();
-        in.readParcelableList(associatedLayers, VmsAssociatedLayer.class.getClassLoader());
-        mAssociatedLayers = Collections.unmodifiableSet(new HashSet(associatedLayers));
-    }
-}
\ No newline at end of file
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/car-lib/src/android/car/vms/VmsClient.java b/car-lib/src/android/car/vms/VmsClient.java
new file mode 100644
index 0000000..a941909
--- /dev/null
+++ b/car-lib/src/android/car/vms/VmsClient.java
@@ -0,0 +1,423 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.vms;
+
+import static android.system.OsConstants.PROT_READ;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.car.Car;
+import android.car.vms.VmsClientManager.VmsClientCallback;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SharedMemory;
+import android.system.ErrnoException;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.lang.ref.WeakReference;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+/**
+ * API implementation for use by Vehicle Map Service clients.
+ *
+ * This API can be obtained by registering a callback with {@link VmsClientManager}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class VmsClient {
+    private static final boolean DBG = false;
+    private static final String TAG = VmsClient.class.getSimpleName();
+
+    private static final VmsAvailableLayers DEFAULT_AVAILABLE_LAYERS =
+            new VmsAvailableLayers(Collections.emptySet(), 0);
+    private static final VmsSubscriptionState DEFAULT_SUBSCRIPTIONS =
+            new VmsSubscriptionState(0, Collections.emptySet(), Collections.emptySet());
+    private static final int LARGE_PACKET_THRESHOLD = 16 * 1024; // 16 KB
+
+    private final IVmsBrokerService mService;
+    private final Executor mExecutor;
+    private final VmsClientCallback mCallback;
+    private final boolean mLegacyClient;
+    private final IVmsClientCallback mClientCallback;
+    private final Consumer<RemoteException> mExceptionHandler;
+    private final IBinder mClientToken;
+
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private VmsAvailableLayers mAvailableLayers = DEFAULT_AVAILABLE_LAYERS;
+    @GuardedBy("mLock")
+    private VmsSubscriptionState mSubscriptionState = DEFAULT_SUBSCRIPTIONS;
+    @GuardedBy("mLock")
+    private boolean mMonitoringEnabled;
+
+    /**
+     * @hide
+     */
+    public VmsClient(IVmsBrokerService service, Executor executor, VmsClientCallback callback,
+            boolean legacyClient, boolean autoCloseMemory,
+            Consumer<RemoteException> exceptionHandler) {
+        mService = service;
+        mExecutor = executor;
+        mCallback = callback;
+        mLegacyClient = legacyClient;
+        mClientCallback = new IVmsClientCallbackImpl(this, autoCloseMemory);
+        mExceptionHandler = exceptionHandler;
+        mClientToken = new Binder();
+    }
+
+    /**
+     * Retrieves registered information about a Vehicle Map Service data provider.
+     *
+     * <p>Data layers may be associated with multiple providers in updates received via
+     * {@link VmsClientCallback#onLayerAvailabilityChanged(VmsAvailableLayers)}, and clients can use
+     * this query to determine a provider or subset of providers to subscribe to.
+     *
+     * @param providerId Provider ID
+     * @return Provider's registration information, or null if unavailable
+     */
+    @Nullable
+    @RequiresPermission(anyOf = {Car.PERMISSION_VMS_PUBLISHER, Car.PERMISSION_VMS_SUBSCRIBER})
+    public byte[] getProviderDescription(int providerId) {
+        if (DBG) Log.d(TAG, "Getting provider information for " + providerId);
+        try {
+            return mService.getProviderInfo(mClientToken, providerId).getDescription();
+        } catch (RemoteException e) {
+            Log.e(TAG, "While getting publisher information for " + providerId, e);
+            mExceptionHandler.accept(e);
+            return null;
+        }
+    }
+
+    /**
+     * Sets this client's data layer subscriptions
+     *
+     * <p>Existing subscriptions for the client will be replaced.
+     *
+     * @param layers Data layers to be subscribed
+     */
+    @RequiresPermission(Car.PERMISSION_VMS_SUBSCRIBER)
+    public void setSubscriptions(@NonNull Set<VmsAssociatedLayer> layers) {
+        if (DBG) Log.d(TAG, "Setting subscriptions to " + layers);
+        try {
+            mService.setSubscriptions(mClientToken, new ArrayList<>(layers));
+        } catch (RemoteException e) {
+            Log.e(TAG, "While setting subscriptions", e);
+            mExceptionHandler.accept(e);
+        }
+    }
+
+    /**
+     * Enables the monitoring of Vehicle Map Service packets by this client.
+     *
+     * <p>If monitoring is enabled, the client will receive all packets, regardless of any
+     * subscriptions. Enabling monitoring does not affect the client's existing subscriptions.
+     */
+    @RequiresPermission(Car.PERMISSION_VMS_SUBSCRIBER)
+    public void setMonitoringEnabled(boolean enabled) {
+        if (DBG) Log.d(TAG, "Setting monitoring state to " + enabled);
+        try {
+            mService.setMonitoringEnabled(mClientToken, enabled);
+            synchronized (mLock) {
+                mMonitoringEnabled = enabled;
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "While setting monitoring state to " + enabled, e);
+            mExceptionHandler.accept(e);
+        }
+    }
+
+    /**
+     * Disables the monitoring of Vehicle Map Service packets by this client.
+     *
+     * <p>If monitoring is disabled, this client will receive only packets for its subscriptions.
+     * Disabling monitoring does not affect the client's existing subscriptions.
+     */
+    @RequiresPermission(Car.PERMISSION_VMS_SUBSCRIBER)
+    public boolean isMonitoringEnabled() {
+        synchronized (mLock) {
+            return mMonitoringEnabled;
+        }
+    }
+
+    /**
+     * Returns the most recently received data layer availability.
+     */
+    @NonNull
+    @RequiresPermission(anyOf = {Car.PERMISSION_VMS_PUBLISHER, Car.PERMISSION_VMS_SUBSCRIBER})
+    public VmsAvailableLayers getAvailableLayers() {
+        synchronized (mLock) {
+            return mAvailableLayers;
+        }
+    }
+
+    /**
+     * Registers a data provider with the Vehicle Map Service.
+     *
+     * @param providerDescription Identifying information about the data provider
+     * @return Provider ID to use for setting offerings and publishing packets, or -1 on
+     * connection error
+     */
+    @RequiresPermission(Car.PERMISSION_VMS_PUBLISHER)
+    public int registerProvider(@NonNull byte[] providerDescription) {
+        if (DBG) Log.d(TAG, "Registering provider");
+        Objects.requireNonNull(providerDescription, "providerDescription cannot be null");
+        try {
+            return mService.registerProvider(mClientToken,
+                    new VmsProviderInfo(providerDescription));
+        } catch (RemoteException e) {
+            Log.e(TAG, "While registering provider", e);
+            mExceptionHandler.accept(e);
+            return -1;
+        }
+    }
+
+    /**
+     * Unregisters a data provider with the Vehicle Map Service.
+     *
+     * @param providerId Provider ID
+     */
+    @RequiresPermission(Car.PERMISSION_VMS_PUBLISHER)
+    public void unregisterProvider(int providerId) {
+        if (DBG) Log.d(TAG, "Unregistering provider");
+        try {
+            setProviderOfferings(providerId, Collections.emptySet());
+        } catch (IllegalArgumentException e) {
+            Log.e(TAG, "While unregistering provider " + providerId, e);
+        }
+    }
+
+    /**
+     * Sets the data layer offerings for a provider registered through
+     * {@link #registerProvider(byte[])}.
+     *
+     * <p>Existing offerings for the provider ID will be replaced.
+     *
+     * @param providerId Provider ID
+     * @param offerings  Data layer offerings
+     * @throws IllegalArgumentException if the client has not registered the provider
+     */
+    @RequiresPermission(Car.PERMISSION_VMS_PUBLISHER)
+    public void setProviderOfferings(int providerId, @NonNull Set<VmsLayerDependency> offerings) {
+        if (DBG) Log.d(TAG, "Setting provider offerings for " + providerId);
+        Objects.requireNonNull(offerings, "offerings cannot be null");
+        try {
+            mService.setProviderOfferings(mClientToken, providerId, new ArrayList<>(offerings));
+        } catch (RemoteException e) {
+            Log.e(TAG, "While setting provider offerings for " + providerId, e);
+            mExceptionHandler.accept(e);
+        }
+    }
+
+    /**
+     * Publishes a Vehicle Maps Service packet.
+     *
+     * @param providerId Packet provider
+     * @param layer      Packet layer
+     * @param packet     Packet data
+     * @throws IllegalArgumentException if the client does not offer the layer as the provider
+     */
+    @RequiresPermission(Car.PERMISSION_VMS_PUBLISHER)
+    public void publishPacket(int providerId, @NonNull VmsLayer layer, @NonNull byte[] packet) {
+        Objects.requireNonNull(layer, "layer cannot be null");
+        Objects.requireNonNull(packet, "packet cannot be null");
+        if (DBG) {
+            Log.d(TAG, "Publishing packet as " + providerId + " (" + packet.length + " bytes)");
+        }
+        try {
+            if (packet.length < LARGE_PACKET_THRESHOLD) {
+                mService.publishPacket(mClientToken, providerId, layer, packet);
+            } else {
+                try (SharedMemory largePacket = packetToSharedMemory(packet)) {
+                    mService.publishLargePacket(mClientToken, providerId, layer,
+                            largePacket);
+                }
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "While publishing packet as " + providerId);
+            mExceptionHandler.accept(e);
+        }
+    }
+
+    /**
+     * Returns the most recently received data layer subscription state.
+     */
+    @NonNull
+    @RequiresPermission(anyOf = {Car.PERMISSION_VMS_PUBLISHER, Car.PERMISSION_VMS_SUBSCRIBER})
+    public VmsSubscriptionState getSubscriptionState() {
+        synchronized (mLock) {
+            return mSubscriptionState;
+        }
+    }
+
+    /**
+     * Registers this client with the Vehicle Map Service.
+     *
+     * @hide
+     */
+    public void register() throws RemoteException {
+        VmsRegistrationInfo registrationInfo = mService.registerClient(
+                mClientToken, mClientCallback, mLegacyClient);
+        synchronized (mLock) {
+            mAvailableLayers = registrationInfo.getAvailableLayers();
+            mSubscriptionState = registrationInfo.getSubscriptionState();
+        }
+    }
+
+    /**
+     * Unregisters this client from the Vehicle Map Service.
+     *
+     * @hide
+     */
+    public void unregister() throws RemoteException {
+        mService.unregisterClient(mClientToken);
+    }
+
+    private static class IVmsClientCallbackImpl extends IVmsClientCallback.Stub {
+        private final WeakReference<VmsClient> mClient;
+        private final boolean mAutoCloseMemory;
+
+        private IVmsClientCallbackImpl(VmsClient client, boolean autoCloseMemory) {
+            mClient = new WeakReference<>(client);
+            mAutoCloseMemory = autoCloseMemory;
+        }
+
+        @Override
+        public void onLayerAvailabilityChanged(VmsAvailableLayers availableLayers) {
+            if (DBG) Log.d(TAG, "Received new layer availability: " + availableLayers);
+            executeCallback((client, callback) -> {
+                synchronized (client.mLock) {
+                    client.mAvailableLayers = availableLayers;
+                }
+                callback.onLayerAvailabilityChanged(availableLayers);
+            });
+        }
+
+        @Override
+        public void onSubscriptionStateChanged(VmsSubscriptionState subscriptionState) {
+            if (DBG) Log.d(TAG, "Received new subscription state: " + subscriptionState);
+            executeCallback((client, callback) -> {
+                synchronized (client.mLock) {
+                    client.mSubscriptionState = subscriptionState;
+                }
+                callback.onSubscriptionStateChanged(subscriptionState);
+            });
+        }
+
+        @Override
+        public void onPacketReceived(int providerId, VmsLayer layer, byte[] packet) {
+            if (DBG) {
+                Log.d(TAG, "Received packet from " + providerId + " for: " + layer
+                        + " (" + packet.length + " bytes)");
+            }
+            executeCallback((client, callback) ->
+                    callback.onPacketReceived(providerId, layer, packet));
+        }
+
+        @Override
+        public void onLargePacketReceived(int providerId, VmsLayer layer, SharedMemory packet) {
+            if (DBG) {
+                Log.d(TAG, "Received large packet from " + providerId + " for: " + layer
+                        + " (" + packet.getSize() + " bytes)");
+            }
+            byte[] largePacket;
+            if (mAutoCloseMemory) {
+                try (SharedMemory autoClosedPacket = packet) {
+                    largePacket = sharedMemoryToPacket(autoClosedPacket);
+                }
+            } else {
+                largePacket = sharedMemoryToPacket(packet);
+            }
+            executeCallback((client, callback) ->
+                    callback.onPacketReceived(providerId, layer, largePacket));
+        }
+
+        private void executeCallback(BiConsumer<VmsClient, VmsClientCallback> callbackOperation) {
+            final VmsClient client = mClient.get();
+            if (client == null) {
+                Log.w(TAG, "VmsClient unavailable");
+                return;
+            }
+
+            long token = Binder.clearCallingIdentity();
+            try {
+                client.mExecutor.execute(() -> callbackOperation.accept(client, client.mCallback));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+    }
+
+    private static SharedMemory packetToSharedMemory(byte[] packet) {
+        SharedMemory shm;
+        try {
+            shm = SharedMemory.create("VmsClient", packet.length);
+        } catch (ErrnoException e) {
+            throw new IllegalStateException("Failed to allocate shared memory", e);
+        }
+
+        ByteBuffer buffer = null;
+        try {
+            buffer = shm.mapReadWrite();
+            buffer.put(packet);
+        } catch (ErrnoException e) {
+            shm.close();
+            throw new IllegalStateException("Failed to create write buffer", e);
+        } finally {
+            if (buffer != null) {
+                SharedMemory.unmap(buffer);
+            }
+        }
+
+        if (!shm.setProtect(PROT_READ)) {
+            shm.close();
+            throw new SecurityException("Failed to set read-only protection on shared memory");
+        }
+
+        return shm;
+    }
+
+    private static byte[] sharedMemoryToPacket(SharedMemory shm) {
+        ByteBuffer buffer;
+        try {
+            buffer = shm.mapReadOnly();
+        } catch (ErrnoException e) {
+            throw new IllegalStateException("Failed to create read buffer", e);
+        }
+
+        byte[] packet;
+        try {
+            packet = new byte[buffer.capacity()];
+            buffer.get(packet);
+        } finally {
+            SharedMemory.unmap(buffer);
+        }
+        return packet;
+    }
+}
diff --git a/car-lib/src/android/car/vms/VmsClientManager.java b/car-lib/src/android/car/vms/VmsClientManager.java
new file mode 100644
index 0000000..db43342
--- /dev/null
+++ b/car-lib/src/android/car/vms/VmsClientManager.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.vms;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.car.Car;
+import android.car.CarManagerBase;
+import android.car.annotation.RequiredFeature;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * Car Service manager for connecting clients to the Vehicle Map Service.
+ *
+ * @hide
+ */
+@RequiredFeature(Car.VEHICLE_MAP_SERVICE)
+@SystemApi
+public final class VmsClientManager extends CarManagerBase {
+    private static final boolean DBG = false;
+    private static final String TAG = VmsClientManager.class.getSimpleName();
+
+    /**
+     * Callback interface for Vehicle Map Service clients.
+     */
+    public interface VmsClientCallback {
+        /**
+         * Invoked when a Vehicle Map Service connection has been established for the callback.
+         *
+         * @param client API client
+         */
+        void onClientConnected(@NonNull VmsClient client);
+
+        /**
+         * Invoked when the availability of data layers has changed.
+         *
+         * @param availableLayers Current layer availability
+         */
+        void onLayerAvailabilityChanged(@NonNull VmsAvailableLayers availableLayers);
+
+        /**
+         * Invoked when any subscriptions to data layers have changed.
+         *
+         * @param subscriptionState Current subscription state
+         */
+        void onSubscriptionStateChanged(@NonNull VmsSubscriptionState subscriptionState);
+
+        /**
+         * Invoked whenever a packet is received for this client's subscriptions.
+         *
+         * @param providerId  Packet provider
+         * @param layer       Packet layer
+         * @param packet      Packet data
+         */
+        void onPacketReceived(int providerId, @NonNull VmsLayer layer, @NonNull byte[] packet);
+    }
+
+    private final IVmsBrokerService mBrokerService;
+
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private final Map<VmsClientCallback, VmsClient> mClients = new ArrayMap<>();
+
+    /**
+     * @hide
+     */
+    public VmsClientManager(Car car, IBinder service) {
+        super(car);
+        mBrokerService = IVmsBrokerService.Stub.asInterface(service);
+    }
+
+    /**
+     * Registers new Vehicle Map Service client for the given callback.
+     *
+     * If the callback is already registered, no action is taken.
+     *
+     * @param executor Executor to run callback operations
+     * @param callback Callback to register for new client
+     */
+    @RequiresPermission(anyOf = {Car.PERMISSION_VMS_PUBLISHER, Car.PERMISSION_VMS_SUBSCRIBER})
+    public void registerVmsClientCallback(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull VmsClientCallback callback) {
+        registerVmsClientCallback(executor, callback, false);
+    }
+
+    /**
+     * @hide
+     */
+    @RequiresPermission(anyOf = {Car.PERMISSION_VMS_PUBLISHER, Car.PERMISSION_VMS_SUBSCRIBER})
+    void registerVmsClientCallback(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull VmsClientCallback callback,
+            boolean legacyClient) {
+        Objects.requireNonNull(executor, "executor cannot be null");
+        Objects.requireNonNull(callback, "callback cannot be null");
+        VmsClient client;
+        synchronized (mLock) {
+            if (mClients.containsKey(callback)) {
+                Log.w(TAG, "VmsClient already registered");
+                return;
+            }
+
+            client = new VmsClient(mBrokerService, executor, callback, legacyClient,
+                    /* autoCloseMemory */ true,
+                    this::handleRemoteExceptionFromCarService);
+            mClients.put(callback, client);
+            if (DBG) Log.d(TAG, "Client count: " + mClients.size());
+        }
+
+        try {
+            if (DBG) Log.d(TAG, "Registering VmsClient");
+            client.register();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error while registering", e);
+            synchronized (mLock) {
+                mClients.remove(callback);
+            }
+            handleRemoteExceptionFromCarService(e);
+            return;
+        }
+
+        if (DBG) Log.d(TAG, "Triggering callbacks for new VmsClient");
+        executor.execute(() -> {
+            callback.onClientConnected(client);
+            if (!legacyClient) {
+                callback.onLayerAvailabilityChanged(client.getAvailableLayers());
+                callback.onSubscriptionStateChanged(client.getSubscriptionState());
+            }
+        });
+    }
+
+    /**
+     * Unregisters the Vehicle Map Service client associated with the given callback.
+     *
+     * If the callback is not registered, no action is taken.
+     *
+     * @param callback
+     */
+    @RequiresPermission(anyOf = {Car.PERMISSION_VMS_PUBLISHER, Car.PERMISSION_VMS_SUBSCRIBER})
+    public void unregisterVmsClientCallback(@NonNull VmsClientCallback callback) {
+        VmsClient client;
+        synchronized (mLock) {
+            client = mClients.remove(callback);
+        }
+        if (client == null) {
+            Log.w(TAG, "Unregister called for unknown callback");
+            return;
+        }
+
+        if (DBG) Log.d(TAG, "Unregistering VmsClient");
+        try {
+            client.unregister();
+        } catch (RemoteException e) {
+            handleRemoteExceptionFromCarService(e);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    protected void onCarDisconnected() {
+        synchronized (mLock) {
+            Log.w(TAG, "Car disconnected with " + mClients.size() + " active clients");
+            mClients.clear();
+        }
+    }
+}
diff --git a/car-lib/src/android/car/vms/VmsLayer.java b/car-lib/src/android/car/vms/VmsLayer.java
index fb811fa..ebb068f 100644
--- a/car-lib/src/android/car/vms/VmsLayer.java
+++ b/car-lib/src/android/car/vms/VmsLayer.java
@@ -20,7 +20,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.util.Objects;
+import com.android.internal.util.DataClass;
 
 /**
  * A Vehicle Map Service layer, which can be offered or subscribed to by clients.
@@ -40,97 +40,195 @@
  * @hide
  */
 @SystemApi
+@DataClass(genAidl = true, genEqualsHashCode = true, genToString = true)
 public final class VmsLayer implements Parcelable {
+    /**
+     * Type of data published on the layer
+     **/
     private int mType;
-    private int mSubtype;
+
+    /**
+     * Type of packet published on the layer
+     */
+    private int mChannel;
+
+    /**
+     * Major version of layer packet format
+     */
     private int mVersion;
 
     /**
-     * Constructs a new layer definition.
+     * Type of packet published on the layer
      *
-     * @param type    type of data published on the layer
-     * @param subtype type of packet published on the layer
-     * @param version major version of layer packet format
+     * @deprecated Use {@link #getChannel()} instead
      */
-    public VmsLayer(int type, int subtype, int version) {
-        mType = type;
-        mSubtype = subtype;
-        mVersion = version;
+    @Deprecated
+    public int getSubtype() {
+        return mChannel;
+    }
+
+
+
+    // Code below generated by codegen v1.0.14.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/vms/VmsLayer.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new VmsLayer.
+     *
+     * @param type
+     *   Type of data published on the layer
+     * @param channel
+     *   Type of packet published on the layer
+     * @param version
+     *   Major version of layer packet format
+     */
+    @DataClass.Generated.Member
+    public VmsLayer(
+            int type,
+            int channel,
+            int version) {
+        this.mType = type;
+        this.mChannel = channel;
+        this.mVersion = version;
+
+        // onConstructed(); // You can define this method to get a callback
     }
 
     /**
-     * @return type of data published on the layer
+     * Type of data published on the layer
      */
+    @DataClass.Generated.Member
     public int getType() {
         return mType;
     }
 
     /**
-     * @return type of packet published on the layer
+     * Type of packet published on the layer
      */
-    public int getSubtype() {
-        return mSubtype;
+    @DataClass.Generated.Member
+    public int getChannel() {
+        return mChannel;
     }
 
     /**
-     * @return major version of layer packet format
+     * Major version of layer packet format
      */
+    @DataClass.Generated.Member
     public int getVersion() {
         return mVersion;
     }
 
     @Override
-    public boolean equals(Object o) {
-        if (!(o instanceof VmsLayer)) {
-            return false;
-        }
-        VmsLayer p = (VmsLayer) o;
-        return Objects.equals(p.mType, mType)
-                && Objects.equals(p.mSubtype, mSubtype)
-                && Objects.equals(p.mVersion, mVersion);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mType, mSubtype, mVersion);
-    }
-
-    @Override
+    @DataClass.Generated.Member
     public String toString() {
-        return "VmsLayer{ Type: " + mType + ", Sub type: " + mSubtype + ", Version: " + mVersion
-                + "}";
-    }
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
 
-    public static final Parcelable.Creator<VmsLayer> CREATOR = new
-            Parcelable.Creator<VmsLayer>() {
-                public VmsLayer createFromParcel(Parcel in) {
-                    return new VmsLayer(in);
-                }
-
-                public VmsLayer[] newArray(int size) {
-                    return new VmsLayer[size];
-                }
-            };
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(mType);
-        out.writeInt(mSubtype);
-        out.writeInt(mVersion);
+        return "VmsLayer { " +
+                "type = " + mType + ", " +
+                "channel = " + mChannel + ", " +
+                "version = " + mVersion +
+        " }";
     }
 
     @Override
-    public int describeContents() {
-        return 0;
+    @DataClass.Generated.Member
+    public boolean equals(@android.annotation.Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(VmsLayer other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        VmsLayer that = (VmsLayer) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && mType == that.mType
+                && mChannel == that.mChannel
+                && mVersion == that.mVersion;
     }
 
-    private VmsLayer(Parcel in) {
-        readFromParcel(in);
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + mType;
+        _hash = 31 * _hash + mChannel;
+        _hash = 31 * _hash + mVersion;
+        return _hash;
     }
 
-    private void readFromParcel(Parcel in) {
-        mType = in.readInt();
-        mSubtype = in.readInt();
-        mVersion = in.readInt();
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@android.annotation.NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeInt(mType);
+        dest.writeInt(mChannel);
+        dest.writeInt(mVersion);
     }
-}
\ No newline at end of file
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ VmsLayer(@android.annotation.NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        int type = in.readInt();
+        int channel = in.readInt();
+        int version = in.readInt();
+
+        this.mType = type;
+        this.mChannel = channel;
+        this.mVersion = version;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @android.annotation.NonNull Parcelable.Creator<VmsLayer> CREATOR
+            = new Parcelable.Creator<VmsLayer>() {
+        @Override
+        public VmsLayer[] newArray(int size) {
+            return new VmsLayer[size];
+        }
+
+        @Override
+        public VmsLayer createFromParcel(@android.annotation.NonNull Parcel in) {
+            return new VmsLayer(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1582065881190L,
+            codegenVersion = "1.0.14",
+            sourceFile = "packages/services/Car/car-lib/src/android/car/vms/VmsLayer.java",
+            inputSignatures = "private  int mType\nprivate  int mChannel\nprivate  int mVersion\npublic @java.lang.Deprecated int getSubtype()\nclass VmsLayer extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genEqualsHashCode=true, genToString=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/car-lib/src/android/car/vms/VmsLayerDependency.java b/car-lib/src/android/car/vms/VmsLayerDependency.java
index 8cf8722..06d2617 100644
--- a/car-lib/src/android/car/vms/VmsLayerDependency.java
+++ b/car-lib/src/android/car/vms/VmsLayerDependency.java
@@ -20,13 +20,11 @@
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.ArraySet;
 
-import com.android.internal.util.Preconditions;
+import com.android.internal.util.DataClass;
 
-import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 
@@ -39,91 +37,193 @@
  * @hide
  */
 @SystemApi
+@DataClass(genAidl = true, genEqualsHashCode = true, genToString = true)
 public final class VmsLayerDependency implements Parcelable {
-    private final VmsLayer mLayer;
-    private final Set<VmsLayer> mDependency;
+    /**
+     * Layer that has dependencies
+     */
+    private final @NonNull VmsLayer mLayer;
 
     /**
-     * Constructs a layer with a dependency on other layers.
-     *
-     * @param layer layer that has dependencies
-     * @param dependencies layers that the given layer depends on
+     * Layers that the given layer depends on
      */
-    public VmsLayerDependency(@NonNull VmsLayer layer, @NonNull Set<VmsLayer> dependencies) {
-        mLayer = Preconditions.checkNotNull(layer, "layer cannot be null");
-        mDependency = Collections.unmodifiableSet(dependencies);
+    private @NonNull Set<VmsLayer> mDependencies;
+
+    private void onConstructed() {
+        mDependencies = Collections.unmodifiableSet(mDependencies);
+    }
+
+    private void parcelDependencies(Parcel dest, int flags) {
+        dest.writeArraySet(new ArraySet<>(mDependencies));
+    }
+
+    @SuppressWarnings("unchecked")
+    private Set<VmsLayer> unparcelDependencies(Parcel in) {
+        return (Set<VmsLayer>) in.readArraySet(VmsLayer.class.getClassLoader());
     }
 
     /**
-     * Constructs a layer without dependencies.
+     * Creates a new VmsLayerDependency without dependencies.
      *
-     * @param layer layer that has no dependencies
+     * @param layer
+     *   Layer that has no dependencies
      */
     public VmsLayerDependency(@NonNull VmsLayer layer) {
         this(layer, Collections.emptySet());
     }
 
+
+
+    // Code below generated by codegen v1.0.14.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/vms/VmsLayerDependency.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
     /**
-     * @return layer that has zero or more dependencies
+     * Creates a new VmsLayerDependency.
+     *
+     * @param layer
+     *   Layer that has dependencies
+     * @param dependencies
+     *   Layers that the given layer depends on
      */
-    @NonNull
-    public VmsLayer getLayer() {
+    @DataClass.Generated.Member
+    public VmsLayerDependency(
+            @NonNull VmsLayer layer,
+            @NonNull Set<VmsLayer> dependencies) {
+        this.mLayer = layer;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mLayer);
+        this.mDependencies = dependencies;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mDependencies);
+
+        onConstructed();
+    }
+
+    /**
+     * Layer that has dependencies
+     */
+    @DataClass.Generated.Member
+    public @NonNull VmsLayer getLayer() {
         return mLayer;
     }
 
     /**
-     * @return all layers that the layer depends on
+     * Layers that the given layer depends on
      */
-    @NonNull
-    public Set<VmsLayer> getDependencies() {
-        return mDependency;
+    @DataClass.Generated.Member
+    public @NonNull Set<VmsLayer> getDependencies() {
+        return mDependencies;
     }
 
-    public static final Parcelable.Creator<VmsLayerDependency> CREATOR = new
-            Parcelable.Creator<VmsLayerDependency>() {
-                public VmsLayerDependency createFromParcel(Parcel in) {
-                    return new VmsLayerDependency(in);
-                }
-
-                public VmsLayerDependency[] newArray(int size) {
-                    return new VmsLayerDependency[size];
-                }
-            };
-
     @Override
+    @DataClass.Generated.Member
     public String toString() {
-        return "VmsLayerDependency{ Layer: " + mLayer + " Dependency: " + mDependency + "}";
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "VmsLayerDependency { " +
+                "layer = " + mLayer + ", " +
+                "dependencies = " + mDependencies +
+        " }";
     }
 
     @Override
-    public boolean equals(Object o) {
-        if (!(o instanceof VmsLayerDependency)) {
-            return false;
-        }
-        VmsLayerDependency p = (VmsLayerDependency) o;
-        return Objects.equals(p.mLayer, mLayer) && p.mDependency.equals(mDependency);
+    @DataClass.Generated.Member
+    public boolean equals(@android.annotation.Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(VmsLayerDependency other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        VmsLayerDependency that = (VmsLayerDependency) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && Objects.equals(mLayer, that.mLayer)
+                && Objects.equals(mDependencies, that.mDependencies);
     }
 
     @Override
+    @DataClass.Generated.Member
     public int hashCode() {
-        return Objects.hash(mLayer, mDependency);
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + Objects.hashCode(mLayer);
+        _hash = 31 * _hash + Objects.hashCode(mDependencies);
+        return _hash;
     }
 
     @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeParcelable(mLayer, flags);
-        out.writeParcelableList(new ArrayList<VmsLayer>(mDependency), flags);
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeTypedObject(mLayer, flags);
+        parcelDependencies(dest, flags);
     }
 
     @Override
-    public int describeContents() {
-        return 0;
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ VmsLayerDependency(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        VmsLayer layer = (VmsLayer) in.readTypedObject(VmsLayer.CREATOR);
+        Set<VmsLayer> dependencies = unparcelDependencies(in);
+
+        this.mLayer = layer;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mLayer);
+        this.mDependencies = dependencies;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mDependencies);
+
+        onConstructed();
     }
 
-    private VmsLayerDependency(Parcel in) {
-        mLayer = in.readParcelable(VmsLayer.class.getClassLoader());
-        List<VmsLayer> dependency = new ArrayList<>();
-        in.readParcelableList(dependency, VmsLayer.class.getClassLoader());
-        mDependency = Collections.unmodifiableSet(new HashSet<VmsLayer>(dependency));
-    }
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<VmsLayerDependency> CREATOR
+            = new Parcelable.Creator<VmsLayerDependency>() {
+        @Override
+        public VmsLayerDependency[] newArray(int size) {
+            return new VmsLayerDependency[size];
+        }
+
+        @Override
+        public VmsLayerDependency createFromParcel(@NonNull Parcel in) {
+            return new VmsLayerDependency(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1582065875835L,
+            codegenVersion = "1.0.14",
+            sourceFile = "packages/services/Car/car-lib/src/android/car/vms/VmsLayerDependency.java",
+            inputSignatures = "private final @android.annotation.NonNull android.car.vms.VmsLayer mLayer\nprivate @android.annotation.NonNull java.util.Set<android.car.vms.VmsLayer> mDependencies\nprivate  void onConstructed()\nprivate  void parcelDependencies(android.os.Parcel,int)\nprivate @java.lang.SuppressWarnings(\"unchecked\") java.util.Set<android.car.vms.VmsLayer> unparcelDependencies(android.os.Parcel)\nclass VmsLayerDependency extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genEqualsHashCode=true, genToString=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
 }
diff --git a/car-lib/src/android/car/vms/VmsLayersOffering.java b/car-lib/src/android/car/vms/VmsLayersOffering.java
index 9a79cdb..f201e39 100644
--- a/car-lib/src/android/car/vms/VmsLayersOffering.java
+++ b/car-lib/src/android/car/vms/VmsLayersOffering.java
@@ -20,12 +20,11 @@
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.ArraySet;
 
-import java.util.ArrayList;
+import com.android.internal.util.DataClass;
+
 import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -35,89 +34,185 @@
  *
  * A layer will not be advertised to subscribers unless all of its dependencies are met.
  *
+ * @deprecated Use {@link VmsClient#setProviderOfferings(int, Set)} instead
+ *
  * @hide
  */
+@Deprecated
 @SystemApi
+@DataClass(genAidl = true, genEqualsHashCode = true, genToString = true)
 public final class VmsLayersOffering implements Parcelable {
-
-    private final Set<VmsLayerDependency> mDependencies;
-
-    private final int mPublisherId;
+    /**
+     * Layers and dependencies in the offering
+     */
+    private @NonNull Set<VmsLayerDependency> mDependencies;
 
     /**
+     * ID of the publisher making the offering
+     */
+    private final int mPublisherId;
+
+    private void onConstructed() {
+        mDependencies = Collections.unmodifiableSet(mDependencies);
+    }
+
+    private void parcelDependencies(Parcel dest, int flags) {
+        dest.writeArraySet(new ArraySet<>(mDependencies));
+    }
+
+    @SuppressWarnings("unchecked")
+    private Set<VmsLayerDependency> unparcelDependencies(Parcel in) {
+        return (Set<VmsLayerDependency>) in.readArraySet(VmsLayerDependency.class.getClassLoader());
+    }
+
+
+
+    // Code below generated by codegen v1.0.14.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/vms/VmsLayersOffering.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new VmsLayersOffering.
      *
      * @param dependencies
+     *   Layers and dependencies in the offering
      * @param publisherId
+     *   ID of the publisher making the offering
      */
-    public VmsLayersOffering(@NonNull Set<VmsLayerDependency> dependencies, int publisherId) {
-        mDependencies = Collections.unmodifiableSet(dependencies);
-        mPublisherId = publisherId;
+    @DataClass.Generated.Member
+    public VmsLayersOffering(
+            @NonNull Set<VmsLayerDependency> dependencies,
+            int publisherId) {
+        this.mDependencies = dependencies;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mDependencies);
+        this.mPublisherId = publisherId;
+
+        onConstructed();
     }
 
     /**
-     * @return set of layer and dependencies in the offering
+     * Layers and dependencies in the offering
      */
-    public Set<VmsLayerDependency> getDependencies() {
+    @DataClass.Generated.Member
+    public @NonNull Set<VmsLayerDependency> getDependencies() {
         return mDependencies;
     }
 
     /**
-     * @return ID of the publisher making the offering
+     * ID of the publisher making the offering
      */
+    @DataClass.Generated.Member
     public int getPublisherId() {
         return mPublisherId;
     }
 
-    public static final Parcelable.Creator<VmsLayersOffering> CREATOR = new
-            Parcelable.Creator<VmsLayersOffering>() {
-                public VmsLayersOffering createFromParcel(Parcel in) {
-                    return new VmsLayersOffering(in);
-                }
-
-                public VmsLayersOffering[] newArray(int size) {
-                    return new VmsLayersOffering[size];
-                }
-            };
-
     @Override
+    @DataClass.Generated.Member
     public String toString() {
-        return "VmsLayersOffering{ Publisher: " +
-                mPublisherId +
-                " Dependencies: " +
-                mDependencies +
-                "}";
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "VmsLayersOffering { " +
+                "dependencies = " + mDependencies + ", " +
+                "publisherId = " + mPublisherId +
+        " }";
     }
 
     @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeParcelableList(new ArrayList<>(mDependencies), flags);
-        out.writeInt(mPublisherId);
+    @DataClass.Generated.Member
+    public boolean equals(@android.annotation.Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(VmsLayersOffering other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        VmsLayersOffering that = (VmsLayersOffering) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && java.util.Objects.equals(mDependencies, that.mDependencies)
+                && mPublisherId == that.mPublisherId;
     }
 
     @Override
-    public boolean equals(Object o) {
-        if (!(o instanceof VmsLayersOffering)) {
-            return false;
-        }
-        VmsLayersOffering p = (VmsLayersOffering) o;
-        return Objects.equals(p.mPublisherId, mPublisherId)
-                && p.mDependencies.equals(mDependencies);
-    }
-
-    @Override
+    @DataClass.Generated.Member
     public int hashCode() {
-        return Objects.hash(mPublisherId, mDependencies);
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + java.util.Objects.hashCode(mDependencies);
+        _hash = 31 * _hash + mPublisherId;
+        return _hash;
     }
 
     @Override
-    public int describeContents() {
-        return 0;
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        parcelDependencies(dest, flags);
+        dest.writeInt(mPublisherId);
     }
 
-    private VmsLayersOffering(Parcel in) {
-        List<VmsLayerDependency> dependencies = new ArrayList<>();
-        in.readParcelableList(dependencies, VmsLayerDependency.class.getClassLoader());
-        mDependencies = Collections.unmodifiableSet(new HashSet<>(dependencies));
-        mPublisherId = in.readInt();
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ VmsLayersOffering(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        Set<VmsLayerDependency> dependencies = unparcelDependencies(in);
+        int publisherId = in.readInt();
+
+        this.mDependencies = dependencies;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mDependencies);
+        this.mPublisherId = publisherId;
+
+        onConstructed();
     }
-}
\ No newline at end of file
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<VmsLayersOffering> CREATOR
+            = new Parcelable.Creator<VmsLayersOffering>() {
+        @Override
+        public VmsLayersOffering[] newArray(int size) {
+            return new VmsLayersOffering[size];
+        }
+
+        @Override
+        public VmsLayersOffering createFromParcel(@NonNull Parcel in) {
+            return new VmsLayersOffering(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1582065871728L,
+            codegenVersion = "1.0.14",
+            sourceFile = "packages/services/Car/car-lib/src/android/car/vms/VmsLayersOffering.java",
+            inputSignatures = "private @android.annotation.NonNull java.util.Set<android.car.vms.VmsLayerDependency> mDependencies\nprivate final  int mPublisherId\nprivate  void onConstructed()\nprivate  void parcelDependencies(android.os.Parcel,int)\nprivate @java.lang.SuppressWarnings(\"unchecked\") java.util.Set<android.car.vms.VmsLayerDependency> unparcelDependencies(android.os.Parcel)\nclass VmsLayersOffering extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genEqualsHashCode=true, genToString=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/car-lib/src/android/car/vms/VmsOperationRecorder.java b/car-lib/src/android/car/vms/VmsOperationRecorder.java
index 50a47c2..aa3f09d 100644
--- a/car-lib/src/android/car/vms/VmsOperationRecorder.java
+++ b/car-lib/src/android/car/vms/VmsOperationRecorder.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.car.vms;
 
 import android.annotation.SystemApi;
@@ -22,8 +38,10 @@
  *   VmsOperationRecorder.get().subscribe(layer);
  * }</pre>
  *
+ * @deprecated VmsOperationRecorder is no longer used by VMS and will produce no output
  * @hide
  */
+@Deprecated
 @SystemApi
 public final class VmsOperationRecorder {
     private static final String TAG = "VmsOperationRecorder";
@@ -43,68 +61,127 @@
 
     // VMS Client operations.
 
+    /**
+     * Records {@code subscribe} operation with the {@link VmsLayer} layer passed as parameter.
+     */
     public void subscribe(VmsLayer layer) {
         recordOp("subscribe", layer);
     }
 
+    /**
+     * Records {@code unsubscribe} operation with the {@link VmsLayer} layer passed as parameter.
+     */
     public void unsubscribe(VmsLayer layer) {
         recordOp("unsubscribe", layer);
     }
 
+    /**
+     * Records {@code subscribe} operation with the {@link VmsLayer} layer and publisher id passed
+     * both as parameter.
+     */
     public void subscribe(VmsLayer layer, int publisherId) {
         recordOp("subscribe", "publisherId", publisherId, layer);
     }
 
+    /**
+     * Record {@code unsubscribe} operation with the {@link VmsLayer} layer and publisher id passed
+     * both as parameter.
+     */
     public void unsubscribe(VmsLayer layer, int publisherId) {
         recordOp("unsubscribe", "publisherId", publisherId, layer);
     }
 
+    /**
+     * Records {@code startMonitoring} operation.
+     */
     public void startMonitoring() {
         recordOp("startMonitoring");
     }
 
+    /**
+     * Records {@code stopMonitoring} operation.
+     */
     public void stopMonitoring() {
         recordOp("stopMonitoring");
     }
 
+    /**
+     * Records {@code setLayerOffering} operation with the {@link VmsLayerOffering} offering
+     * passed as parameter.
+     */
     public void setLayersOffering(VmsLayersOffering layersOffering) {
         recordOp("setLayersOffering", layersOffering);
     }
 
+    /**
+     * Records {@code getPublisherId} operation with the publisher id passed as parameter.
+     */
     public void getPublisherId(int publisherId) {
         recordOp("getPublisherId", "publisherId", publisherId);
     }
 
     // VMS Service operations.
 
+    /**
+     * Records {@code addSubscription} operation with the {@link VmsLayer} and the sequenceNumber
+     * passed as parameter.
+     */
     public void addSubscription(int sequenceNumber, VmsLayer layer) {
         recordOp("addSubscription", "sequenceNumber", sequenceNumber, layer);
     }
 
+    /**
+     * Records {@code addPromiscuousSubscription} operation with the {@link VmsLayer} and the
+     * sequenceNumber passed as parameter.
+     */
     public void removeSubscription(int sequenceNumber, VmsLayer layer) {
         recordOp("removeSubscription", "sequenceNumber", sequenceNumber, layer);
     }
 
+    /**
+     * Records {@code addPromiscuousSubscription} operation with the sequenceNumber passed as
+     * parameter.
+     */
     public void addPromiscuousSubscription(int sequenceNumber) {
         recordOp("addPromiscuousSubscription", "sequenceNumber", sequenceNumber);
     }
 
+    /**
+     * Records {@code removePromiscuousSubscription} operation with the sequenceNumber passed as
+     * parameter.
+     */
     public void removePromiscuousSubscription(int sequenceNumber) {
         recordOp("removePromiscuousSubscription", "sequenceNumber", sequenceNumber);
     }
 
+    /**
+     * Records {@code addHalSubscription} operation with the {@link VmsLayer} layer and
+     * sequenceNumber both passed as parameter.
+     */
     public void addHalSubscription(int sequenceNumber, VmsLayer layer) {
         recordOp("addHalSubscription", "sequenceNumber", sequenceNumber, layer);
     }
 
+    /**
+     * Records {@code removeHalSubscription} operation with the {@link VmsLayer} layer and
+     * sequenceNumber both passed as parameter.
+     */
     public void removeHalSubscription(int sequenceNumber, VmsLayer layer) {
         recordOp("removeHalSubscription", "sequenceNumber", sequenceNumber, layer);
     }
 
+    /**
+     * Records {@code setPublisherLayersOffering} operation with the {@link VmsLayersOffering}
+     * layersOffering passed as parameter.
+     */
     public void setPublisherLayersOffering(VmsLayersOffering layersOffering) {
         recordOp("setPublisherLayersOffering", layersOffering);
     }
 
+    /**
+     * Records {@code setHalPublisherLayersOffering} operation with the {@link VmsLayersOffering}
+     * layersOffering passed as parameter.
+     */
     public void setHalPublisherLayersOffering(VmsLayersOffering layersOffering) {
         recordOp("setHalPublisherLayersOffering", layersOffering);
     }
@@ -222,6 +299,7 @@
             return Log.isLoggable(TAG, LEVEL);
         }
 
+        /** Logs the message passed as parameter. */
         public void write(String msg) {
             Log.println(LEVEL, TAG, msg);
         }
diff --git a/car-lib/src/android/car/vms/VmsProviderInfo.aidl b/car-lib/src/android/car/vms/VmsProviderInfo.aidl
new file mode 100644
index 0000000..6122834
--- /dev/null
+++ b/car-lib/src/android/car/vms/VmsProviderInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.vms;
+
+parcelable VmsProviderInfo;
diff --git a/car-lib/src/android/car/vms/VmsProviderInfo.java b/car-lib/src/android/car/vms/VmsProviderInfo.java
new file mode 100644
index 0000000..db4f873
--- /dev/null
+++ b/car-lib/src/android/car/vms/VmsProviderInfo.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.vms;
+
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.util.Arrays;
+
+/**
+ * Hidden data object used to communicate Vehicle Map Service publisher information on registration.
+ *
+ * @hide
+ */
+@DataClass(
+        genEqualsHashCode = true,
+        genAidl = true)
+public class VmsProviderInfo implements Parcelable {
+    private @Nullable final byte[] mDescription;
+
+
+
+    // Code below generated by codegen v1.0.14.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/vms/VmsProviderInfo.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    @DataClass.Generated.Member
+    public VmsProviderInfo(
+            @Nullable byte[] description) {
+        this.mDescription = description;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public @Nullable byte[] getDescription() {
+        return mDescription;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(VmsProviderInfo other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        VmsProviderInfo that = (VmsProviderInfo) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && Arrays.equals(mDescription, that.mDescription);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + Arrays.hashCode(mDescription);
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@android.annotation.NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        byte flg = 0;
+        if (mDescription != null) flg |= 0x1;
+        dest.writeByte(flg);
+        if (mDescription != null) dest.writeByteArray(mDescription);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    protected VmsProviderInfo(@android.annotation.NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        byte[] description = (flg & 0x1) == 0 ? null : in.createByteArray();
+
+        this.mDescription = description;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @android.annotation.NonNull Parcelable.Creator<VmsProviderInfo> CREATOR
+            = new Parcelable.Creator<VmsProviderInfo>() {
+        @Override
+        public VmsProviderInfo[] newArray(int size) {
+            return new VmsProviderInfo[size];
+        }
+
+        @Override
+        public VmsProviderInfo createFromParcel(@android.annotation.NonNull Parcel in) {
+            return new VmsProviderInfo(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1581406319319L,
+            codegenVersion = "1.0.14",
+            sourceFile = "packages/services/Car/car-lib/src/android/car/vms/VmsProviderInfo.java",
+            inputSignatures = "private final @android.annotation.Nullable byte[] mDescription\nclass VmsProviderInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/car-lib/src/android/car/vms/VmsPublisherClientService.java b/car-lib/src/android/car/vms/VmsPublisherClientService.java
index 70e0592..c603609 100644
--- a/car-lib/src/android/car/vms/VmsPublisherClientService.java
+++ b/car-lib/src/android/car/vms/VmsPublisherClientService.java
@@ -18,25 +18,22 @@
 
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.Service;
 import android.car.Car;
+import android.car.annotation.RequiredFeature;
+import android.car.vms.VmsClientManager.VmsClientCallback;
 import android.content.Intent;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.IBinder;
 import android.os.Looper;
-import android.os.Message;
-import android.os.Process;
-import android.os.RemoteException;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
-
-import java.lang.ref.WeakReference;
-import java.util.Collections;
+import com.android.internal.annotations.VisibleForTesting;
 
 /**
  * API implementation of a Vehicle Map Service publisher client.
@@ -51,41 +48,68 @@
  *
  * Publishers must also register a publisher ID by calling {@link #getPublisherId(byte[])}.
  *
+ * @deprecated Use {@link VmsClientManager} instead
  * @hide
  */
+@RequiredFeature(Car.VEHICLE_MAP_SERVICE)
+@Deprecated
 @SystemApi
 public abstract class VmsPublisherClientService extends Service {
     private static final boolean DBG = false;
     private static final String TAG = "VmsPublisherClientService";
 
-    private static final VmsSubscriptionState DEFAULT_SUBSCRIPTIONS =
-            new VmsSubscriptionState(0, Collections.emptySet(),
-                    Collections.emptySet());
+
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+    private final VmsClientCallback mClientCallback = new PublisherClientCallback();
 
     private final Object mLock = new Object();
-
-    private Handler mHandler = new VmsEventHandler(this);
-    private final VmsPublisherClientBinder mVmsPublisherClient = new VmsPublisherClientBinder(this);
-    private volatile IVmsPublisherService mVmsPublisherService = null;
     @GuardedBy("mLock")
-    private IBinder mToken = null;
+    private @Nullable Car mCar;
+    @GuardedBy("mLock")
+    private @Nullable VmsClient mClient;
+
+    @Override
+    public void onCreate() {
+        if (DBG) Log.d(TAG, "Connecting to Car service");
+        synchronized (mLock) {
+            mCar = Car.createCar(this, mHandler, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
+                    this::onCarLifecycleChanged);
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        if (DBG) Log.d(TAG, "Disconnecting from Car service");
+        synchronized (mLock) {
+            if (mCar != null) {
+                mCar.disconnect();
+                mCar = null;
+            }
+        }
+    }
 
     @Override
     public IBinder onBind(Intent intent) {
         if (DBG) Log.d(TAG, "onBind, intent: " + intent);
-        return mVmsPublisherClient.asBinder();
+        return new Binder();
     }
 
-    @Override
-    public boolean onUnbind(Intent intent) {
-        if (DBG) Log.d(TAG, "onUnbind, intent: " + intent);
-        stopSelf();
-        return super.onUnbind(intent);
-    }
-
-    private void setToken(IBinder token) {
-        synchronized (mLock) {
-            mToken = token;
+    /**
+     * @hide
+     */
+    @VisibleForTesting
+    protected void onCarLifecycleChanged(Car car, boolean ready) {
+        if (DBG) Log.d(TAG, "Car service ready: " + ready);
+        if (ready) {
+            VmsClientManager clientManager =
+                    (VmsClientManager) car.getCarManager(Car.VEHICLE_MAP_SERVICE);
+            if (DBG) Log.d(TAG, "VmsClientManager: " + clientManager);
+            if (clientManager == null) {
+                Log.e(TAG, "VmsClientManager is not available");
+                return;
+            }
+            clientManager.registerVmsClientCallback(new HandlerExecutor(mHandler), mClientCallback,
+                    /* legacyClient= */ true);
         }
     }
 
@@ -112,16 +136,7 @@
      * @throws IllegalStateException if publisher services are not available
      */
     public final void publish(@NonNull VmsLayer layer, int publisherId, byte[] payload) {
-        Preconditions.checkNotNull(layer, "layer cannot be null");
-        if (DBG) Log.d(TAG, "Publishing for layer : " + layer);
-
-        IBinder token = getTokenForPublisherServiceThreadSafe();
-
-        try {
-            mVmsPublisherService.publish(token, layer, publisherId, payload);
-        } catch (RemoteException e) {
-            Car.handleRemoteExceptionFromCarService(this, e);
-        }
+        getVmsClient().publishPacket(publisherId, layer, payload);
     }
 
     /**
@@ -131,32 +146,7 @@
      * @throws IllegalStateException if publisher services are not available
      */
     public final void setLayersOffering(@NonNull VmsLayersOffering offering) {
-        Preconditions.checkNotNull(offering, "offering cannot be null");
-        if (DBG) Log.d(TAG, "Setting layers offering : " + offering);
-
-        IBinder token = getTokenForPublisherServiceThreadSafe();
-
-        try {
-            mVmsPublisherService.setLayersOffering(token, offering);
-            VmsOperationRecorder.get().setLayersOffering(offering);
-        } catch (RemoteException e) {
-            Car.handleRemoteExceptionFromCarService(this, e);
-        }
-    }
-
-    private IBinder getTokenForPublisherServiceThreadSafe() {
-        if (mVmsPublisherService == null) {
-            throw new IllegalStateException("VmsPublisherService not set.");
-        }
-
-        IBinder token;
-        synchronized (mLock) {
-            token = mToken;
-        }
-        if (token == null) {
-            throw new IllegalStateException("VmsPublisherService does not have a valid token.");
-        }
-        return token;
+        getVmsClient().setProviderOfferings(offering.getPublisherId(), offering.getDependencies());
     }
 
     /**
@@ -170,19 +160,7 @@
      * @throws IllegalStateException if publisher services are not available
      */
     public final int getPublisherId(byte[] publisherInfo) {
-        if (mVmsPublisherService == null) {
-            throw new IllegalStateException("VmsPublisherService not set.");
-        }
-        int publisherId;
-        try {
-            publisherId = mVmsPublisherService.getPublisherId(publisherInfo);
-            Log.i(TAG, "Assigned publisher ID: " + publisherId);
-        } catch (RemoteException e) {
-            // This will crash. To prevent crash, safer invalid return value should be defined.
-            throw e.rethrowFromSystemServer();
-        }
-        VmsOperationRecorder.get().getPublisherId(publisherId);
-        return publisherId;
+        return getVmsClient().registerProvider(publisherInfo);
     }
 
     /**
@@ -192,114 +170,40 @@
      * @throws IllegalStateException if publisher services are not available
      */
     public final VmsSubscriptionState getSubscriptions() {
-        if (mVmsPublisherService == null) {
-            throw new IllegalStateException("VmsPublisherService not set.");
-        }
-        try {
-            return mVmsPublisherService.getSubscriptions();
-        } catch (RemoteException e) {
-            return Car.handleRemoteExceptionFromCarService(this, e, DEFAULT_SUBSCRIPTIONS);
+        return getVmsClient().getSubscriptionState();
+    }
+
+    private VmsClient getVmsClient() {
+        synchronized (mLock) {
+            if (mClient == null) {
+                throw new IllegalStateException("VMS client connection is not ready");
+            }
+            return mClient;
         }
     }
 
-    private void setVmsPublisherService(IVmsPublisherService service) {
-        mVmsPublisherService = service;
-        onVmsPublisherServiceReady();
-    }
-
-    /**
-     * Implements the interface that the VMS service uses to communicate with this client.
-     */
-    private static class VmsPublisherClientBinder extends IVmsPublisherClient.Stub {
-        private final WeakReference<VmsPublisherClientService> mVmsPublisherClientService;
-        @GuardedBy("mSequenceLock")
-        private long mSequence = -1;
-        private final Object mSequenceLock = new Object();
-
-        VmsPublisherClientBinder(VmsPublisherClientService vmsPublisherClientService) {
-            mVmsPublisherClientService = new WeakReference<>(vmsPublisherClientService);
+    private class PublisherClientCallback implements VmsClientCallback {
+        @Override
+        public void onClientConnected(VmsClient client) {
+            synchronized (mLock) {
+                mClient = client;
+            }
+            onVmsPublisherServiceReady();
         }
 
         @Override
-        public void setVmsPublisherService(IBinder token, IVmsPublisherService service) {
-            assertSystemOrSelf();
-
-            VmsPublisherClientService vmsPublisherClientService = mVmsPublisherClientService.get();
-            if (vmsPublisherClientService == null) return;
-            if (DBG) Log.d(TAG, "setting VmsPublisherService.");
-            Handler handler = vmsPublisherClientService.mHandler;
-            handler.sendMessage(
-                    handler.obtainMessage(VmsEventHandler.SET_SERVICE_CALLBACK, service));
-            vmsPublisherClientService.setToken(token);
+        public void onSubscriptionStateChanged(VmsSubscriptionState subscriptionState) {
+            onVmsSubscriptionChange(subscriptionState);
         }
 
         @Override
-        public void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState) {
-            assertSystemOrSelf();
-
-            VmsPublisherClientService vmsPublisherClientService = mVmsPublisherClientService.get();
-            if (vmsPublisherClientService == null) return;
-            if (DBG) Log.d(TAG, "subscription event: " + subscriptionState);
-            synchronized (mSequenceLock) {
-                if (subscriptionState.getSequenceNumber() <= mSequence) {
-                    Log.w(TAG, "Sequence out of order. Current sequence = " + mSequence
-                            + "; expected new sequence = " + subscriptionState.getSequenceNumber());
-                    // Do not propagate old notifications.
-                    return;
-                } else {
-                    mSequence = subscriptionState.getSequenceNumber();
-                }
-            }
-            Handler handler = vmsPublisherClientService.mHandler;
-            handler.sendMessage(
-                    handler.obtainMessage(VmsEventHandler.ON_SUBSCRIPTION_CHANGE_EVENT,
-                            subscriptionState));
-        }
-
-        private void assertSystemOrSelf() {
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
-                if (DBG) Log.d(TAG, "Skipping system user check");
-                return;
-            }
-
-            if (!(Binder.getCallingUid() == Process.SYSTEM_UID
-                    || Binder.getCallingPid() == Process.myPid())) {
-                throw new SecurityException("Caller must be system user or same process");
-            }
-        }
-    }
-
-    /**
-     * Receives events from the binder thread and dispatches them.
-     */
-    private final static class VmsEventHandler extends Handler {
-        /** Constants handled in the handler */
-        private static final int ON_SUBSCRIPTION_CHANGE_EVENT = 0;
-        private static final int SET_SERVICE_CALLBACK = 1;
-
-        private final WeakReference<VmsPublisherClientService> mVmsPublisherClientService;
-
-        VmsEventHandler(VmsPublisherClientService service) {
-            super(Looper.getMainLooper());
-            mVmsPublisherClientService = new WeakReference<>(service);
+        public void onLayerAvailabilityChanged(VmsAvailableLayers availableLayers) {
+            // Ignored
         }
 
         @Override
-        public void handleMessage(Message msg) {
-            VmsPublisherClientService service = mVmsPublisherClientService.get();
-            if (service == null) return;
-            switch (msg.what) {
-                case ON_SUBSCRIPTION_CHANGE_EVENT:
-                    VmsSubscriptionState subscriptionState = (VmsSubscriptionState) msg.obj;
-                    service.onVmsSubscriptionChange(subscriptionState);
-                    break;
-                case SET_SERVICE_CALLBACK:
-                    service.setVmsPublisherService((IVmsPublisherService) msg.obj);
-                    break;
-                default:
-                    Log.e(TAG, "Event type not handled:  " + msg.what);
-                    break;
-            }
+        public void onPacketReceived(int providerId, VmsLayer layer, byte[] packet) {
+            // Does not subscribe to packets
         }
     }
 }
diff --git a/car-lib/src/android/car/vms/VmsRegistrationInfo.aidl b/car-lib/src/android/car/vms/VmsRegistrationInfo.aidl
new file mode 100644
index 0000000..eff5dc2
--- /dev/null
+++ b/car-lib/src/android/car/vms/VmsRegistrationInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.vms;
+
+parcelable VmsRegistrationInfo;
diff --git a/car-lib/src/android/car/vms/VmsRegistrationInfo.java b/car-lib/src/android/car/vms/VmsRegistrationInfo.java
new file mode 100644
index 0000000..78c8273
--- /dev/null
+++ b/car-lib/src/android/car/vms/VmsRegistrationInfo.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.vms;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.util.Objects;
+
+/**
+ * Hidden data object used to communicate Vehicle Map Service client tokens and system state on
+ * client registration.
+ *
+ * @hide
+ */
+@DataClass(
+        genEqualsHashCode = true,
+        genAidl = true)
+public class VmsRegistrationInfo implements Parcelable {
+    private @NonNull VmsAvailableLayers mAvailableLayers;
+    private @NonNull VmsSubscriptionState mSubscriptionState;
+
+
+
+    // Code below generated by codegen v1.0.14.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/vms/VmsRegistrationInfo.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    @DataClass.Generated.Member
+    public VmsRegistrationInfo(
+            @NonNull VmsAvailableLayers availableLayers,
+            @NonNull VmsSubscriptionState subscriptionState) {
+        this.mAvailableLayers = availableLayers;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mAvailableLayers);
+        this.mSubscriptionState = subscriptionState;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mSubscriptionState);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull VmsAvailableLayers getAvailableLayers() {
+        return mAvailableLayers;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull VmsSubscriptionState getSubscriptionState() {
+        return mSubscriptionState;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@android.annotation.Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(VmsRegistrationInfo other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        VmsRegistrationInfo that = (VmsRegistrationInfo) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && Objects.equals(mAvailableLayers, that.mAvailableLayers)
+                && Objects.equals(mSubscriptionState, that.mSubscriptionState);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + Objects.hashCode(mAvailableLayers);
+        _hash = 31 * _hash + Objects.hashCode(mSubscriptionState);
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeTypedObject(mAvailableLayers, flags);
+        dest.writeTypedObject(mSubscriptionState, flags);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    protected VmsRegistrationInfo(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        VmsAvailableLayers availableLayers = (VmsAvailableLayers) in.readTypedObject(VmsAvailableLayers.CREATOR);
+        VmsSubscriptionState subscriptionState = (VmsSubscriptionState) in.readTypedObject(VmsSubscriptionState.CREATOR);
+
+        this.mAvailableLayers = availableLayers;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mAvailableLayers);
+        this.mSubscriptionState = subscriptionState;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mSubscriptionState);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<VmsRegistrationInfo> CREATOR
+            = new Parcelable.Creator<VmsRegistrationInfo>() {
+        @Override
+        public VmsRegistrationInfo[] newArray(int size) {
+            return new VmsRegistrationInfo[size];
+        }
+
+        @Override
+        public VmsRegistrationInfo createFromParcel(@NonNull Parcel in) {
+            return new VmsRegistrationInfo(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1581406323727L,
+            codegenVersion = "1.0.14",
+            sourceFile = "packages/services/Car/car-lib/src/android/car/vms/VmsRegistrationInfo.java",
+            inputSignatures = "private @android.annotation.NonNull android.car.vms.VmsAvailableLayers mAvailableLayers\nprivate @android.annotation.NonNull android.car.vms.VmsSubscriptionState mSubscriptionState\nclass VmsRegistrationInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/car-lib/src/android/car/vms/VmsSubscriberManager.java b/car-lib/src/android/car/vms/VmsSubscriberManager.java
index ce10b13..c077bcd 100644
--- a/car-lib/src/android/car/vms/VmsSubscriberManager.java
+++ b/car-lib/src/android/car/vms/VmsSubscriberManager.java
@@ -18,19 +18,20 @@
 
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.car.Car;
 import android.car.CarManagerBase;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
+import android.car.annotation.RequiredFeature;
+import android.car.vms.VmsClientManager.VmsClientCallback;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
 
-import java.util.Collections;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
 
 /**
  * API implementation for use by Vehicle Map Service subscribers.
@@ -38,23 +39,15 @@
  * Supports a single client callback that can subscribe and unsubscribe to different data layers.
  * {@link #setVmsSubscriberClientCallback} must be called before any subscription operations.
  *
+ * @deprecated Use {@link VmsClientManager} instead
  * @hide
  */
+@RequiredFeature(Car.VMS_SUBSCRIBER_SERVICE)
+@Deprecated
 @SystemApi
 public final class VmsSubscriberManager extends CarManagerBase {
-    private static final String TAG = "VmsSubscriberManager";
-
+    private static final long CLIENT_READY_TIMEOUT_MS = 500;
     private static final byte[] DEFAULT_PUBLISHER_INFO = new byte[0];
-    private static final VmsAvailableLayers DEFAULT_AVAILABLE_LAYERS =
-            new VmsAvailableLayers(Collections.emptySet(), 0);
-
-    private final IVmsSubscriberService mVmsSubscriberService;
-    private final IVmsSubscriberClient mSubscriberManagerClient;
-    private final Object mClientCallbackLock = new Object();
-    @GuardedBy("mClientCallbackLock")
-    private VmsSubscriberClientCallback mClientCallback;
-    @GuardedBy("mClientCallbackLock")
-    private Executor mExecutor;
 
     /**
      * Callback interface for Vehicle Map Service subscribers.
@@ -76,47 +69,32 @@
         void onLayersAvailabilityChanged(@NonNull VmsAvailableLayers availableLayers);
     }
 
+    private final VmsClientManager mClientManager;
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private @Nullable VmsClient mClient;
+
+    @GuardedBy("mLock")
+    private @Nullable VmsClientCallback mClientCallback;
+
+    private final VmsSubscriptionHelper mSubscriptionHelper =
+            new VmsSubscriptionHelper(this::setSubscriptions);
+
     /**
-     * Hidden constructor - can only be used internally.
-     *
      * @hide
      */
-    public VmsSubscriberManager(Car car, IBinder service) {
-        super(car);
-        mVmsSubscriberService = IVmsSubscriberService.Stub.asInterface(service);
-        mSubscriberManagerClient = new IVmsSubscriberClient.Stub() {
-            @Override
-            public void onVmsMessageReceived(VmsLayer layer, byte[] payload) {
-                Executor executor;
-                synchronized (mClientCallbackLock) {
-                    executor = mExecutor;
-                }
-                if (executor == null) {
-                    Log.w(TAG, "Executor is unset in onVmsMessageReceived");
-                    return;
-                }
-                Binder.clearCallingIdentity();
-                executor.execute(() -> {
-                    dispatchOnReceiveMessage(layer, payload);
-                });
-            }
+    public static VmsSubscriberManager wrap(Car car, @Nullable VmsClientManager clientManager) {
+        if (clientManager == null) {
+            return null;
+        }
+        return new VmsSubscriberManager(car, clientManager);
+    }
 
-            @Override
-            public void onLayersAvailabilityChanged(VmsAvailableLayers availableLayers) {
-                Executor executor;
-                synchronized (mClientCallbackLock) {
-                    executor = mExecutor;
-                }
-                if (executor == null) {
-                    Log.w(TAG, "Executor is unset in onLayersAvailabilityChanged");
-                    return;
-                }
-                Binder.clearCallingIdentity();
-                executor.execute(() -> {
-                    dispatchOnAvailabilityChangeMessage(availableLayers);
-                });
-            }
-        };
+    private VmsSubscriberManager(Car car, VmsClientManager clientManager) {
+        super(car);
+        mClientManager = clientManager;
     }
 
     /**
@@ -129,38 +107,41 @@
     public void setVmsSubscriberClientCallback(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull VmsSubscriberClientCallback clientCallback) {
-        synchronized (mClientCallbackLock) {
+        Objects.requireNonNull(clientCallback, "clientCallback cannot be null");
+        Objects.requireNonNull(executor, "executor cannot be null");
+        CountDownLatch clientReady;
+        synchronized (mLock) {
             if (mClientCallback != null) {
                 throw new IllegalStateException("Client callback is already configured.");
             }
-            mClientCallback = Preconditions.checkNotNull(clientCallback,
-                    "clientCallback cannot be null");
-            mExecutor = Preconditions.checkNotNull(executor, "executor cannot be null");
+            clientReady = new CountDownLatch(1);
+            mClientCallback = new SubscriberCallbackWrapper(clientCallback, clientReady);
+            // Register callback with broker service
+            mClientManager.registerVmsClientCallback(executor, mClientCallback,
+                    /* legacyClient= */ true);
         }
+
         try {
-            mVmsSubscriberService.addVmsSubscriberToNotifications(mSubscriberManagerClient);
-        } catch (RemoteException e) {
-            handleRemoteExceptionFromCarService(e);
+            // Wait for VmsClient to be available
+            if (!clientReady.await(CLIENT_READY_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                clearVmsSubscriberClientCallback();
+                throw new IllegalStateException("Subscriber client is not ready");
+            }
+        } catch (InterruptedException e) {
+            clearVmsSubscriberClientCallback();
+            Thread.currentThread().interrupt();
+            throw new IllegalStateException("Interrupted while waiting for subscriber client", e);
         }
     }
 
-
     /**
      * Clears the subscriber client's callback.
      */
     public void clearVmsSubscriberClientCallback() {
-        synchronized (mClientCallbackLock) {
-            if (mExecutor == null) return;
-        }
-        try {
-            mVmsSubscriberService.removeVmsSubscriberToNotifications(mSubscriberManagerClient);
-        } catch (RemoteException e) {
-            handleRemoteExceptionFromCarService(e);
-        } finally {
-            synchronized (mClientCallbackLock) {
-                mClientCallback = null;
-                mExecutor = null;
-            }
+        synchronized (mLock) {
+            mClientManager.unregisterVmsClientCallback(mClientCallback);
+            mClient = null;
+            mClientCallback = null;
         }
     }
 
@@ -172,11 +153,8 @@
      */
     @NonNull
     public byte[] getPublisherInfo(int publisherId) {
-        try {
-            return mVmsSubscriberService.getPublisherInfo(publisherId);
-        } catch (RemoteException e) {
-            return handleRemoteExceptionFromCarService(e, DEFAULT_PUBLISHER_INFO);
-        }
+        byte[] publisherInfo = getVmsClient().getProviderDescription(publisherId);
+        return publisherInfo != null ? publisherInfo : DEFAULT_PUBLISHER_INFO;
     }
 
     /**
@@ -186,11 +164,7 @@
      */
     @NonNull
     public VmsAvailableLayers getAvailableLayers() {
-        try {
-            return mVmsSubscriberService.getAvailableLayers();
-        } catch (RemoteException e) {
-            return handleRemoteExceptionFromCarService(e, DEFAULT_AVAILABLE_LAYERS);
-        }
+        return getVmsClient().getAvailableLayers();
     }
 
     /**
@@ -201,13 +175,7 @@
      *                               {@link #setVmsSubscriberClientCallback}.
      */
     public void subscribe(@NonNull VmsLayer layer) {
-        verifySubscriptionIsAllowed();
-        try {
-            mVmsSubscriberService.addVmsSubscriber(mSubscriberManagerClient, layer);
-            VmsOperationRecorder.get().subscribe(layer);
-        } catch (RemoteException e) {
-            handleRemoteExceptionFromCarService(e);
-        }
+        mSubscriptionHelper.subscribe(layer);
     }
 
     /**
@@ -219,27 +187,14 @@
      *                               {@link #setVmsSubscriberClientCallback}.
      */
     public void subscribe(@NonNull VmsLayer layer, int publisherId) {
-        verifySubscriptionIsAllowed();
-        try {
-            mVmsSubscriberService.addVmsSubscriberToPublisher(
-                    mSubscriberManagerClient, layer, publisherId);
-            VmsOperationRecorder.get().subscribe(layer, publisherId);
-        } catch (RemoteException e) {
-            handleRemoteExceptionFromCarService(e);
-        }
+        mSubscriptionHelper.subscribe(layer, publisherId);
     }
 
     /**
      * Start monitoring all messages for all layers, regardless of subscriptions.
      */
     public void startMonitoring() {
-        verifySubscriptionIsAllowed();
-        try {
-            mVmsSubscriberService.addVmsSubscriberPassive(mSubscriberManagerClient);
-            VmsOperationRecorder.get().startMonitoring();
-        } catch (RemoteException e) {
-            handleRemoteExceptionFromCarService(e);
-        }
+        getVmsClient().setMonitoringEnabled(true);
     }
 
     /**
@@ -250,13 +205,7 @@
      *                               {@link #setVmsSubscriberClientCallback}.
      */
     public void unsubscribe(@NonNull VmsLayer layer) {
-        verifySubscriptionIsAllowed();
-        try {
-            mVmsSubscriberService.removeVmsSubscriber(mSubscriberManagerClient, layer);
-            VmsOperationRecorder.get().unsubscribe(layer);
-        } catch (RemoteException e) {
-            handleRemoteExceptionFromCarService(e);
-        }
+        mSubscriptionHelper.unsubscribe(layer);
     }
 
     /**
@@ -268,74 +217,66 @@
      *                               {@link #setVmsSubscriberClientCallback}.
      */
     public void unsubscribe(@NonNull VmsLayer layer, int publisherId) {
-        try {
-            mVmsSubscriberService.removeVmsSubscriberToPublisher(
-                    mSubscriberManagerClient, layer, publisherId);
-            VmsOperationRecorder.get().unsubscribe(layer, publisherId);
-        } catch (RemoteException e) {
-            handleRemoteExceptionFromCarService(e);
-        }
+        mSubscriptionHelper.unsubscribe(layer, publisherId);
     }
 
     /**
      * Stop monitoring. Only receive messages for layers which have been subscribed to."
      */
     public void stopMonitoring() {
-        try {
-            mVmsSubscriberService.removeVmsSubscriberPassive(mSubscriberManagerClient);
-            VmsOperationRecorder.get().stopMonitoring();
-        } catch (RemoteException e) {
-            handleRemoteExceptionFromCarService(e);
-        }
-    }
-
-    private void dispatchOnReceiveMessage(VmsLayer layer, byte[] payload) {
-        VmsSubscriberClientCallback clientCallback = getClientCallbackThreadSafe();
-        if (clientCallback == null) {
-            Log.e(TAG, "Cannot dispatch received message.");
-            return;
-        }
-        clientCallback.onVmsMessageReceived(layer, payload);
-    }
-
-    private void dispatchOnAvailabilityChangeMessage(VmsAvailableLayers availableLayers) {
-        VmsSubscriberClientCallback clientCallback = getClientCallbackThreadSafe();
-        if (clientCallback == null) {
-            Log.e(TAG, "Cannot dispatch availability change message.");
-            return;
-        }
-        clientCallback.onLayersAvailabilityChanged(availableLayers);
-    }
-
-    private VmsSubscriberClientCallback getClientCallbackThreadSafe() {
-        VmsSubscriberClientCallback clientCallback;
-        synchronized (mClientCallbackLock) {
-            clientCallback = mClientCallback;
-        }
-        if (clientCallback == null) {
-            Log.e(TAG, "client callback not set.");
-        }
-        return clientCallback;
-    }
-
-    /*
-     * Verifies that the subscriber is in a state where it is allowed to subscribe.
-     */
-    private void verifySubscriptionIsAllowed() {
-        VmsSubscriberClientCallback clientCallback = getClientCallbackThreadSafe();
-        if (clientCallback == null) {
-            throw new IllegalStateException("Cannot subscribe.");
-        }
+        getVmsClient().setMonitoringEnabled(false);
     }
 
     /**
      * @hide
      */
     @Override
-    public void onCarDisconnected() {
-        synchronized (mClientCallbackLock) {
-            mClientCallback = null;
-            mExecutor = null;
+    public void onCarDisconnected() {}
+
+    private void setSubscriptions(Set<VmsAssociatedLayer> subscriptions) {
+        getVmsClient().setSubscriptions(subscriptions);
+    }
+
+    private VmsClient getVmsClient() {
+        synchronized (mLock) {
+            if (mClient == null) {
+                throw new IllegalStateException("VMS client connection is not ready");
+            }
+            return mClient;
+        }
+    }
+
+    private final class SubscriberCallbackWrapper implements VmsClientCallback {
+        private final VmsSubscriberClientCallback mCallback;
+        private final CountDownLatch mClientReady;
+
+        SubscriberCallbackWrapper(VmsSubscriberClientCallback callback,
+                CountDownLatch clientReady) {
+            mCallback = callback;
+            mClientReady = clientReady;
+        }
+
+        @Override
+        public void onClientConnected(VmsClient client) {
+            synchronized (mLock) {
+                mClient = client;
+            }
+            mClientReady.countDown();
+        }
+
+        @Override
+        public void onSubscriptionStateChanged(VmsSubscriptionState subscriptionState) {
+            // Ignored
+        }
+
+        @Override
+        public void onLayerAvailabilityChanged(VmsAvailableLayers availableLayers) {
+            mCallback.onLayersAvailabilityChanged(availableLayers);
+        }
+
+        @Override
+        public void onPacketReceived(int providerId, VmsLayer layer, byte[] packet) {
+            mCallback.onVmsMessageReceived(layer, packet);
         }
     }
 }
diff --git a/car-lib/src/android/car/vms/VmsSubscriptionHelper.java b/car-lib/src/android/car/vms/VmsSubscriptionHelper.java
new file mode 100644
index 0000000..500d8f9
--- /dev/null
+++ b/car-lib/src/android/car/vms/VmsSubscriptionHelper.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.vms;
+
+import android.annotation.NonNull;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.SparseBooleanArray;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Internal utility for computing subscription updates.
+ *
+ * @hide
+ */
+public final class VmsSubscriptionHelper {
+    private final Consumer<Set<VmsAssociatedLayer>> mUpdateHandler;
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private final Set<VmsLayer> mLayerSubscriptions = new ArraySet<>();
+
+    @GuardedBy("mLock")
+    private final Map<VmsLayer, SparseBooleanArray> mPublisherSubscriptions = new ArrayMap<>();
+
+    @GuardedBy("mLock")
+    private boolean mPendingUpdate;
+
+    /**
+     * Constructor for subscription helper.
+     *
+     * @param updateHandler Consumer of subscription updates.
+     */
+    public VmsSubscriptionHelper(@NonNull Consumer<Set<VmsAssociatedLayer>> updateHandler) {
+        mUpdateHandler = Objects.requireNonNull(updateHandler, "updateHandler cannot be null");
+    }
+
+    /**
+     * Adds a subscription to a layer.
+     */
+    public void subscribe(@NonNull VmsLayer layer) {
+        Objects.requireNonNull(layer, "layer cannot be null");
+        synchronized (mLock) {
+            if (mLayerSubscriptions.add(layer)) {
+                mPendingUpdate = true;
+            }
+            publishSubscriptionUpdate();
+        }
+    }
+
+    /**
+     * Adds a subscription to a specific provider of a layer.
+     */
+    public void subscribe(@NonNull VmsLayer layer, int providerId) {
+        Objects.requireNonNull(layer, "layer cannot be null");
+        synchronized (mLock) {
+            SparseBooleanArray providerIds = mPublisherSubscriptions.computeIfAbsent(layer,
+                    ignored -> new SparseBooleanArray());
+            if (!providerIds.get(providerId)) {
+                providerIds.put(providerId, true);
+                mPendingUpdate = true;
+            }
+            publishSubscriptionUpdate();
+        }
+    }
+
+    /**
+     * Removes a subscription to a layer.
+     */
+    public void unsubscribe(@NonNull VmsLayer layer) {
+        Objects.requireNonNull(layer, "layer cannot be null");
+        synchronized (mLock) {
+            if (mLayerSubscriptions.remove(layer)) {
+                mPendingUpdate = true;
+            }
+            publishSubscriptionUpdate();
+        }
+    }
+
+    /**
+     * Removes a subscription to the specific provider of a layer.
+     */
+    public void unsubscribe(@NonNull VmsLayer layer, int providerId) {
+        Objects.requireNonNull(layer, "layer cannot be null");
+        synchronized (mLock) {
+            SparseBooleanArray providerIds = mPublisherSubscriptions.get(layer);
+            if (providerIds != null && providerIds.get(providerId)) {
+                providerIds.delete(providerId);
+                if (providerIds.size() == 0) {
+                    mPublisherSubscriptions.remove(layer);
+                }
+                mPendingUpdate = true;
+            }
+            publishSubscriptionUpdate();
+        }
+    }
+
+    /**
+     * Gets the current set of subscriptions.
+     */
+    @NonNull
+    public Set<VmsAssociatedLayer> getSubscriptions() {
+        return Stream.concat(
+                mLayerSubscriptions.stream().map(
+                        layer -> new VmsAssociatedLayer(layer, Collections.emptySet())),
+                mPublisherSubscriptions.entrySet().stream()
+                        .filter(entry -> !mLayerSubscriptions.contains(entry.getKey()))
+                        .map(VmsSubscriptionHelper::toAssociatedLayer))
+                .collect(Collectors.toSet());
+    }
+
+    private void publishSubscriptionUpdate() {
+        synchronized (mLock) {
+            if (mPendingUpdate) {
+                mUpdateHandler.accept(getSubscriptions());
+            }
+            mPendingUpdate = false;
+        }
+    }
+
+    private static VmsAssociatedLayer toAssociatedLayer(
+            Map.Entry<VmsLayer, SparseBooleanArray> entry) {
+        SparseBooleanArray providerIdArray = entry.getValue();
+        Set<Integer> providerIds = new ArraySet<>(providerIdArray.size());
+        for (int i = 0; i < providerIdArray.size(); i++) {
+            providerIds.add(providerIdArray.keyAt(i));
+        }
+        return new VmsAssociatedLayer(entry.getKey(), providerIds);
+    }
+}
diff --git a/car-lib/src/android/car/vms/VmsSubscriptionState.java b/car-lib/src/android/car/vms/VmsSubscriptionState.java
index 08e72ba..436744f 100644
--- a/car-lib/src/android/car/vms/VmsSubscriptionState.java
+++ b/car-lib/src/android/car/vms/VmsSubscriptionState.java
@@ -20,11 +20,11 @@
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.ArraySet;
 
-import java.util.ArrayList;
+import com.android.internal.util.DataClass;
+
 import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 
@@ -41,112 +41,216 @@
  * @hide
  */
 @SystemApi
+@DataClass(genAidl = true, genEqualsHashCode = true, genToString = true)
 public final class VmsSubscriptionState implements Parcelable {
+    /**
+     * Sequence number of the subscription state
+     */
     private final int mSequenceNumber;
-    private final Set<VmsLayer> mLayers;
-    private final Set<VmsAssociatedLayer> mSubscribedLayersFromPublishers;
 
     /**
-     * Constructs a summary of the state of the current subscriptions for publishers to consume
-     * and adjust which layers that the are publishing.
+     * Layers with subscriptions to all publishers
      */
-    public VmsSubscriptionState(int sequenceNumber,
-            @NonNull Set<VmsLayer> subscribedLayers,
-            @NonNull Set<VmsAssociatedLayer> layersFromPublishers) {
-        mSequenceNumber = sequenceNumber;
-        mLayers = Collections.unmodifiableSet(subscribedLayers);
-        mSubscribedLayersFromPublishers = Collections.unmodifiableSet(layersFromPublishers);
+    private @NonNull Set<VmsLayer> mLayers;
+
+    /**
+     * Layers with subscriptions to a subset of publishers
+     */
+    private @NonNull Set<VmsAssociatedLayer> mAssociatedLayers;
+
+    private void onConstructed() {
+        mLayers = Collections.unmodifiableSet(mLayers);
+        mAssociatedLayers = Collections.unmodifiableSet(mAssociatedLayers);
+    }
+
+    private void parcelLayers(Parcel dest, int flags) {
+        dest.writeArraySet(new ArraySet<>(mLayers));
+    }
+
+    @SuppressWarnings("unchecked")
+    private Set<VmsLayer> unparcelLayers(Parcel in) {
+        return (Set<VmsLayer>) in.readArraySet(VmsLayer.class.getClassLoader());
+    }
+
+    private void parcelAssociatedLayers(Parcel dest, int flags) {
+        dest.writeArraySet(new ArraySet<>(mAssociatedLayers));
+    }
+
+    @SuppressWarnings("unchecked")
+    private Set<VmsAssociatedLayer> unparcelAssociatedLayers(Parcel in) {
+        return (Set<VmsAssociatedLayer>) in.readArraySet(VmsAssociatedLayer.class.getClassLoader());
+    }
+
+
+
+    // Code below generated by codegen v1.0.14.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/vms/VmsSubscriptionState.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new VmsSubscriptionState.
+     *
+     * @param sequenceNumber
+     *   Sequence number of the subscription state
+     * @param layers
+     *   Layers with subscriptions to all publishers
+     * @param associatedLayers
+     *   Layers with subscriptions to a subset of publishers
+     */
+    @DataClass.Generated.Member
+    public VmsSubscriptionState(
+            int sequenceNumber,
+            @NonNull Set<VmsLayer> layers,
+            @NonNull Set<VmsAssociatedLayer> associatedLayers) {
+        this.mSequenceNumber = sequenceNumber;
+        this.mLayers = layers;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mLayers);
+        this.mAssociatedLayers = associatedLayers;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mAssociatedLayers);
+
+        onConstructed();
     }
 
     /**
-     * @return sequence number of the subscription state
+     * Sequence number of the subscription state
      */
+    @DataClass.Generated.Member
     public int getSequenceNumber() {
         return mSequenceNumber;
     }
 
     /**
-     * @return set of layers with subscriptions to all publishers
+     * Layers with subscriptions to all publishers
      */
-    @NonNull
-    public Set<VmsLayer> getLayers() {
+    @DataClass.Generated.Member
+    public @NonNull Set<VmsLayer> getLayers() {
         return mLayers;
     }
 
     /**
-     * @return set of layers with subscriptions to a subset of publishers
+     * Layers with subscriptions to a subset of publishers
      */
-    @NonNull
-    public Set<VmsAssociatedLayer> getAssociatedLayers() {
-        return mSubscribedLayersFromPublishers;
+    @DataClass.Generated.Member
+    public @NonNull Set<VmsAssociatedLayer> getAssociatedLayers() {
+        return mAssociatedLayers;
     }
 
     @Override
+    @DataClass.Generated.Member
     public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("sequence number=").append(mSequenceNumber);
-        sb.append("; layers={");
-        for (VmsLayer layer : mLayers) {
-            sb.append(layer).append(",");
-        }
-        sb.append("}");
-        sb.append("; associatedLayers={");
-        for (VmsAssociatedLayer layer : mSubscribedLayersFromPublishers) {
-            sb.append(layer).append(",");
-        }
-        sb.append("}");
-        return sb.toString();
-    }
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
 
-    public static final Parcelable.Creator<VmsSubscriptionState> CREATOR = new
-            Parcelable.Creator<VmsSubscriptionState>() {
-                public VmsSubscriptionState createFromParcel(Parcel in) {
-                    return new VmsSubscriptionState(in);
-                }
-
-                public VmsSubscriptionState[] newArray(int size) {
-                    return new VmsSubscriptionState[size];
-                }
-            };
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(mSequenceNumber);
-        out.writeParcelableList(new ArrayList(mLayers), flags);
-        out.writeParcelableList(new ArrayList(mSubscribedLayersFromPublishers), flags);
+        return "VmsSubscriptionState { " +
+                "sequenceNumber = " + mSequenceNumber + ", " +
+                "layers = " + mLayers + ", " +
+                "associatedLayers = " + mAssociatedLayers +
+        " }";
     }
 
     @Override
-    public boolean equals(Object o) {
-        if (!(o instanceof VmsSubscriptionState)) {
-            return false;
-        }
-        VmsSubscriptionState p = (VmsSubscriptionState) o;
-        return Objects.equals(p.mSequenceNumber, mSequenceNumber) &&
-                p.mLayers.equals(mLayers) &&
-                p.mSubscribedLayersFromPublishers.equals(mSubscribedLayersFromPublishers);
+    @DataClass.Generated.Member
+    public boolean equals(@android.annotation.Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(VmsSubscriptionState other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        VmsSubscriptionState that = (VmsSubscriptionState) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && mSequenceNumber == that.mSequenceNumber
+                && Objects.equals(mLayers, that.mLayers)
+                && Objects.equals(mAssociatedLayers, that.mAssociatedLayers);
     }
 
     @Override
+    @DataClass.Generated.Member
     public int hashCode() {
-        return Objects.hash(mSequenceNumber, mLayers, mSubscribedLayersFromPublishers);
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + mSequenceNumber;
+        _hash = 31 * _hash + Objects.hashCode(mLayers);
+        _hash = 31 * _hash + Objects.hashCode(mAssociatedLayers);
+        return _hash;
     }
 
     @Override
-    public int describeContents() {
-        return 0;
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeInt(mSequenceNumber);
+        parcelLayers(dest, flags);
+        parcelAssociatedLayers(dest, flags);
     }
 
-    private VmsSubscriptionState(Parcel in) {
-        mSequenceNumber = in.readInt();
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
 
-        List<VmsLayer> layers = new ArrayList<>();
-        in.readParcelableList(layers, VmsLayer.class.getClassLoader());
-        mLayers = Collections.unmodifiableSet(new HashSet(layers));
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ VmsSubscriptionState(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
 
-        List<VmsAssociatedLayer> associatedLayers = new ArrayList<>();
-        in.readParcelableList(associatedLayers, VmsAssociatedLayer.class.getClassLoader());
-        mSubscribedLayersFromPublishers =
-                Collections.unmodifiableSet(new HashSet(associatedLayers));
+        int sequenceNumber = in.readInt();
+        Set<VmsLayer> layers = unparcelLayers(in);
+        Set<VmsAssociatedLayer> associatedLayers = unparcelAssociatedLayers(in);
+
+        this.mSequenceNumber = sequenceNumber;
+        this.mLayers = layers;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mLayers);
+        this.mAssociatedLayers = associatedLayers;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mAssociatedLayers);
+
+        onConstructed();
     }
-}
\ No newline at end of file
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<VmsSubscriptionState> CREATOR
+            = new Parcelable.Creator<VmsSubscriptionState>() {
+        @Override
+        public VmsSubscriptionState[] newArray(int size) {
+            return new VmsSubscriptionState[size];
+        }
+
+        @Override
+        public VmsSubscriptionState createFromParcel(@NonNull Parcel in) {
+            return new VmsSubscriptionState(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1582061018243L,
+            codegenVersion = "1.0.14",
+            sourceFile = "packages/services/Car/car-lib/src/android/car/vms/VmsSubscriptionState.java",
+            inputSignatures = "private final  int mSequenceNumber\nprivate @android.annotation.NonNull java.util.Set<android.car.vms.VmsLayer> mLayers\nprivate @android.annotation.NonNull java.util.Set<android.car.vms.VmsAssociatedLayer> mAssociatedLayers\nprivate  void onConstructed()\nprivate  void parcelLayers(android.os.Parcel,int)\nprivate @java.lang.SuppressWarnings(\"unchecked\") java.util.Set<android.car.vms.VmsLayer> unparcelLayers(android.os.Parcel)\nprivate  void parcelAssociatedLayers(android.os.Parcel,int)\nprivate @java.lang.SuppressWarnings(\"unchecked\") java.util.Set<android.car.vms.VmsAssociatedLayer> unparcelAssociatedLayers(android.os.Parcel)\nclass VmsSubscriptionState extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genEqualsHashCode=true, genToString=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/car-lib/src/android/car/watchdog/CarWatchdogManager.java b/car-lib/src/android/car/watchdog/CarWatchdogManager.java
new file mode 100644
index 0000000..d8fb7d9
--- /dev/null
+++ b/car-lib/src/android/car/watchdog/CarWatchdogManager.java
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.watchdog;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.automotive.watchdog.ICarWatchdogClient;
+import android.car.Car;
+import android.car.CarManagerBase;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.ref.WeakReference;
+import java.util.concurrent.Executor;
+
+/**
+ * Provides APIs and interfaces for client health checking.
+ *
+ * @hide
+ */
+@SystemApi
+public final class CarWatchdogManager extends CarManagerBase {
+
+    private static final String TAG = CarWatchdogManager.class.getSimpleName();
+    private static final boolean DEBUG = false; // STOPSHIP if true
+    private static final int INVALID_SESSION_ID = -1;
+    private static final int NUMBER_OF_CONDITIONS_TO_BE_MET = 2;
+    // Message ID representing main thread activeness checking.
+    private static final int WHAT_CHECK_MAIN_THREAD = 1;
+
+    /** Timeout for services which should be responsive. The length is 3,000 milliseconds. */
+    public static final int TIMEOUT_CRITICAL = 0;
+
+    /** Timeout for services which are relatively responsive. The length is 5,000 milliseconds. */
+    public static final int TIMEOUT_MODERATE = 1;
+
+    /** Timeout for all other services. The length is 10,000 milliseconds. */
+    public static final int TIMEOUT_NORMAL = 2;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "TIMEOUT_", value = {
+            TIMEOUT_CRITICAL,
+            TIMEOUT_MODERATE,
+            TIMEOUT_NORMAL,
+    })
+    @Target({ElementType.TYPE_USE})
+    public @interface TimeoutLengthEnum {}
+
+    private final ICarWatchdogService mService;
+    private final ICarWatchdogClientImpl mClientImpl;
+    private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private CarWatchdogClientCallback mRegisteredClient;
+    @GuardedBy("mLock")
+    private Executor mCallbackExecutor;
+    @GuardedBy("mLock")
+    private SessionInfo mSession = new SessionInfo(INVALID_SESSION_ID, INVALID_SESSION_ID);
+    @GuardedBy("mLock")
+    private int mRemainingConditions;
+
+    /**
+     * CarWatchdogClientCallback is implemented by the clients which want to be health-checked by
+     * car watchdog server. Every time onCheckHealthStatus is called, they are expected to
+     * respond by calling {@link CarWatchdogManager.tellClientAlive} within timeout. If they don't
+     * respond, car watchdog server reports the current state and kills them.
+     *
+     * <p>Before car watchdog server kills the client, it calls onPrepareProcessTermination to allow
+     * them to prepare the termination. They will be killed in 1 second.
+     */
+    public abstract static class CarWatchdogClientCallback {
+        /**
+         * Car watchdog server pings the client to check if it is alive.
+         *
+         * <p>The callback method is called at the Executor which is specifed in {@link
+         * #registerClient}.
+         *
+         * @param sessionId Unique id to distinguish each health checking.
+         * @param timeout Time duration within which the client should respond.
+         *
+         * @return whether the response is immediately acknowledged. If {@code true}, car watchdog
+         *         server considers that the response is acknowledged already. If {@code false},
+         *         the client should call {@link CarWatchdogManager.tellClientAlive} later to tell
+         *         that it is alive.
+         */
+        public boolean onCheckHealthStatus(int sessionId, @TimeoutLengthEnum int timeout) {
+            return false;
+        }
+
+        /**
+         * Car watchdog server notifies the client that it will be terminated in 1 second.
+         *
+         * <p>The callback method is called at the Executor which is specifed in {@link
+         * #registerClient}.
+         */
+        public void onPrepareProcessTermination() {}
+    }
+
+    /** @hide */
+    public CarWatchdogManager(Car car, IBinder service) {
+        super(car);
+        mService = ICarWatchdogService.Stub.asInterface(service);
+        mClientImpl = new ICarWatchdogClientImpl(this);
+    }
+
+    /**
+     * Registers the car watchdog clients to {@link CarWatchdogManager}.
+     *
+     * <p>It is allowed to register a client from any thread, but only one client can be
+     * registered. If two or more clients are needed, create a new {@link Car} and register a client
+     * to it.
+     *
+     * @param client Watchdog client implementing {@link CarWatchdogClientCallback} interface.
+     * @param timeout The time duration within which the client desires to respond. The actual
+     *        timeout is decided by watchdog server.
+     * @throws IllegalStateException if at least one client is already registered.
+     */
+    @RequiresPermission(Car.PERMISSION_USE_CAR_WATCHDOG)
+    public void registerClient(@NonNull @CallbackExecutor Executor executor,
+            @NonNull CarWatchdogClientCallback client, @TimeoutLengthEnum int timeout) {
+        synchronized (mLock) {
+            if (mRegisteredClient == client) {
+                return;
+            }
+            if (mRegisteredClient != null) {
+                throw new IllegalStateException(
+                        "Cannot register the client. Only one client can be registered.");
+            }
+            mRegisteredClient = client;
+            mCallbackExecutor = executor;
+        }
+        try {
+            mService.registerClient(mClientImpl, timeout);
+            if (DEBUG) {
+                Log.d(TAG, "Car watchdog client is successfully registered");
+            }
+        } catch (RemoteException e) {
+            synchronized (mLock) {
+                mRegisteredClient = null;
+            }
+            handleRemoteExceptionFromCarService(e);
+        }
+    }
+
+    /**
+     * Unregisters the car watchdog client from {@link CarWatchdogManager}.
+     *
+     * @param client Watchdog client implementing {@link CarWatchdogClientCallback} interface.
+     */
+    @RequiresPermission(Car.PERMISSION_USE_CAR_WATCHDOG)
+    public void unregisterClient(@NonNull CarWatchdogClientCallback client) {
+        synchronized (mLock) {
+            if (mRegisteredClient != client) {
+                Log.w(TAG, "Cannot unregister the client. It has not been registered.");
+                return;
+            }
+            mRegisteredClient = null;
+            mCallbackExecutor = null;
+        }
+        try {
+            mService.unregisterClient(mClientImpl);
+            if (DEBUG) {
+                Log.d(TAG, "Car watchdog client is successfully unregistered");
+            }
+        } catch (RemoteException e) {
+            handleRemoteExceptionFromCarService(e);
+        }
+    }
+
+    /**
+     * Tells {@link CarWatchdogManager} that the client is alive.
+     *
+     * @param client Watchdog client implementing {@link CarWatchdogClientCallback} interface.
+     * @param sessionId Session id given by {@link CarWatchdogManager}.
+     * @throws IllegalStateException if {@code client} is not registered.
+     * @throws IllegalArgumentException if {@code session Id} is not correct.
+     */
+    @RequiresPermission(Car.PERMISSION_USE_CAR_WATCHDOG)
+    public void tellClientAlive(@NonNull CarWatchdogClientCallback client, int sessionId) {
+        boolean shouldReport;
+        synchronized (mLock) {
+            if (mRegisteredClient != client) {
+                throw new IllegalStateException(
+                        "Cannot report client status. The client has not been registered.");
+            }
+            Preconditions.checkArgument(sessionId != -1 && mSession.currentId == sessionId,
+                    "Cannot report client status. "
+                    + "The given session id doesn't match the current one.");
+            if (mSession.lastReportedId == sessionId) {
+                Log.w(TAG, "The given session id is already reported.");
+                return;
+            }
+            mSession.lastReportedId = sessionId;
+            mRemainingConditions--;
+            shouldReport = checkConditionLocked();
+        }
+        if (shouldReport) {
+            reportToService(sessionId);
+        }
+    }
+
+    /** @hide */
+    @Override
+    public void onCarDisconnected() {
+        // nothing to do
+    }
+
+    private void checkClientStatus(int sessionId, int timeout) {
+        CarWatchdogClientCallback client;
+        Executor executor;
+        mMainHandler.removeMessages(WHAT_CHECK_MAIN_THREAD);
+        synchronized (mLock) {
+            if (mRegisteredClient == null) {
+                Log.w(TAG, "Cannot check client status. The client has not been registered.");
+                return;
+            }
+            mSession.currentId = sessionId;
+            client = mRegisteredClient;
+            executor = mCallbackExecutor;
+            mRemainingConditions = NUMBER_OF_CONDITIONS_TO_BE_MET;
+        }
+        // For a car watchdog client to be active, 1) its main thread is active and 2) the client
+        // responds within timeout. When each condition is met, the remaining task counter is
+        // decreased. If the remaining task counter is zero, the client is considered active.
+        mMainHandler.sendMessage(obtainMessage(CarWatchdogManager::checkMainThread, this)
+                .setWhat(WHAT_CHECK_MAIN_THREAD));
+        // Call the client callback to check if the client is active.
+        executor.execute(() -> {
+            boolean checkDone = client.onCheckHealthStatus(sessionId, timeout);
+            if (checkDone) {
+                boolean shouldReport;
+                synchronized (mLock) {
+                    if (mSession.lastReportedId == sessionId) {
+                        return;
+                    }
+                    mSession.lastReportedId = sessionId;
+                    mRemainingConditions--;
+                    shouldReport = checkConditionLocked();
+                }
+                if (shouldReport) {
+                    reportToService(sessionId);
+                }
+            }
+        });
+    }
+
+    private void checkMainThread() {
+        int sessionId;
+        boolean shouldReport;
+        synchronized (mLock) {
+            mRemainingConditions--;
+            sessionId = mSession.currentId;
+            shouldReport = checkConditionLocked();
+        }
+        if (shouldReport) {
+            reportToService(sessionId);
+        }
+    }
+
+    private boolean checkConditionLocked() {
+        if (mRemainingConditions < 0) {
+            Log.wtf(TAG, "Remaining condition is less than zero: should not happen");
+        }
+        return mRemainingConditions == 0;
+    }
+
+    private void reportToService(int sessionId) {
+        try {
+            mService.tellClientAlive(mClientImpl, sessionId);
+        } catch (RemoteException e) {
+            handleRemoteExceptionFromCarService(e);
+        }
+    }
+
+    private void notifyProcessTermination() {
+        CarWatchdogClientCallback client;
+        Executor executor;
+        synchronized (mLock) {
+            if (mRegisteredClient == null) {
+                Log.w(TAG, "Cannot notify the client. The client has not been registered.");
+                return;
+            }
+            client = mRegisteredClient;
+            executor = mCallbackExecutor;
+        }
+        executor.execute(() -> client.onPrepareProcessTermination());
+    }
+
+    /** @hide */
+    private static final class ICarWatchdogClientImpl extends ICarWatchdogClient.Stub {
+        private final WeakReference<CarWatchdogManager> mManager;
+
+        private ICarWatchdogClientImpl(CarWatchdogManager manager) {
+            mManager = new WeakReference<>(manager);
+        }
+
+        @Override
+        public void checkIfAlive(int sessionId, int timeout) {
+            CarWatchdogManager manager = mManager.get();
+            if (manager != null) {
+                manager.checkClientStatus(sessionId, timeout);
+            }
+        }
+
+        @Override
+        public void prepareProcessTermination() {
+            CarWatchdogManager manager = mManager.get();
+            if (manager != null) {
+                manager.notifyProcessTermination();
+            }
+        }
+
+        @Override
+        public int getInterfaceVersion() {
+            return this.VERSION;
+        }
+
+        @Override
+        public String getInterfaceHash() {
+            return this.HASH;
+        }
+    }
+
+    private final class SessionInfo {
+        public int currentId;
+        public int lastReportedId;
+
+        SessionInfo(int currentId, int lastReportedId) {
+            this.currentId = currentId;
+            this.lastReportedId = lastReportedId;
+        }
+    }
+}
diff --git a/car-lib/src/android/car/watchdog/ICarWatchdogService.aidl b/car-lib/src/android/car/watchdog/ICarWatchdogService.aidl
new file mode 100644
index 0000000..017e0e1
--- /dev/null
+++ b/car-lib/src/android/car/watchdog/ICarWatchdogService.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.watchdog;
+
+import android.automotive.watchdog.ICarWatchdogClient;
+import android.automotive.watchdog.TimeoutLength;
+
+/** @hide */
+interface ICarWatchdogService {
+    // registerClient needs to get callingPid, so cannot be oneway.
+    void registerClient(in ICarWatchdogClient client, in TimeoutLength timeout);
+    void unregisterClient(in ICarWatchdogClient client);
+    void tellClientAlive(in ICarWatchdogClient client, in int sessionId);
+}
diff --git a/car-lib/src/com/android/car/internal/CarPermission.java b/car-lib/src/com/android/car/internal/CarPermission.java
index 6439c00..6b775d7 100644
--- a/car-lib/src/com/android/car/internal/CarPermission.java
+++ b/car-lib/src/com/android/car/internal/CarPermission.java
@@ -40,8 +40,8 @@
     public boolean checkGranted() {
         if (mName != null) {
             if (Binder.getCallingUid() != Process.myUid()) {
-                return PackageManager.PERMISSION_GRANTED ==
-                        mContext.checkCallingOrSelfPermission(mName);
+                return PackageManager.PERMISSION_GRANTED
+                        == mContext.checkCallingOrSelfPermission(mName);
             }
         }
         return true;
diff --git a/car-lib/src/com/android/car/internal/CarRatedListeners.java b/car-lib/src/com/android/car/internal/CarRatedListeners.java
index 6b26e61..5284a5b 100644
--- a/car-lib/src/com/android/car/internal/CarRatedListeners.java
+++ b/car-lib/src/com/android/car/internal/CarRatedListeners.java
@@ -23,6 +23,8 @@
 
 /**
  * Represent listeners for a sensor grouped by their rate.
+ *
+ * @param <EventListenerType> type of event listener
  * @hide
  */
 public class CarRatedListeners<EventListenerType> {
@@ -36,6 +38,7 @@
         mUpdateRate = rate;
     }
 
+    /** Returns true if it contains the listener passed as parameter. */
     public boolean contains(EventListenerType listener) {
         return mListenersToRate.containsKey(listener);
     }
diff --git a/car-lib/src/com/android/car/internal/FeatureUtil.java b/car-lib/src/com/android/car/internal/FeatureUtil.java
index ad33eb9..c601a9d 100644
--- a/car-lib/src/com/android/car/internal/FeatureUtil.java
+++ b/car-lib/src/com/android/car/internal/FeatureUtil.java
@@ -21,6 +21,9 @@
  */
 public class FeatureUtil {
 
+    /**
+     * Ensures the flag passes as parameter is enabled.
+     */
     public static void assertFeature(boolean featureFlag) {
         if (!featureFlag) {
             throw new IllegalStateException("Feature not enabled");
diff --git a/car-lib/src/com/android/car/internal/SingleMessageHandler.java b/car-lib/src/com/android/car/internal/SingleMessageHandler.java
index 57788a7..de09250 100644
--- a/car-lib/src/com/android/car/internal/SingleMessageHandler.java
+++ b/car-lib/src/com/android/car/internal/SingleMessageHandler.java
@@ -26,6 +26,8 @@
 
 /**
  * Handles call back into clients for Car managers.
+ *
+ * @param <EventType> type of event to be handled
  * @hide
  */
 public abstract class SingleMessageHandler<EventType> implements Callback {
@@ -58,6 +60,7 @@
         return true;
     }
 
+    /** Send the events passsed as parameter */
     public void sendEvents(List<EventType> events) {
         mHandler.sendMessage(mHandler.obtainMessage(mHandledMessageWhat, events));
     }
diff --git a/car-lib/src_feature_future/com/android/car/internal/FeatureConfiguration.java b/car-lib/src_feature_future/com/android/car/internal/FeatureConfiguration.java
deleted file mode 100644
index 66cff60..0000000
--- a/car-lib/src_feature_future/com/android/car/internal/FeatureConfiguration.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.car.internal;
-
-/**
- * Class to hold static boolean flag for enabling / disabling features.
- *
- * @hide
- */
-public class FeatureConfiguration {
-    /** Enable future feature by default. */
-    public static final boolean DEFAULT = true;
-    /** product configuration in CarInfoManager */
-    public static final boolean ENABLE_PRODUCT_CONFIGURATION_INFO = DEFAULT;
-    public static final boolean ENABLE_VEHICLE_MAP_SERVICE = DEFAULT;
-}
diff --git a/car-lib/src_stub/android/media/AudioPatch.java b/car-lib/src_stub/android/media/AudioPatch.java
deleted file mode 100644
index f50481b..0000000
--- a/car-lib/src_stub/android/media/AudioPatch.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media;
-
-/**
- * This is added to build system-stub library as hidden API, AudioPatch was used by mistake in
- * CarAudioManager for system API. This should not be used by apps using system API as the real
- * API from framework is really hidden API.
- *
- * @hide
- */
-public class AudioPatch {
-}
diff --git a/car-maps-placeholder/res/values-ne/strings.xml b/car-maps-placeholder/res/values-ne/strings.xml
index a2aef6c..03412e9 100644
--- a/car-maps-placeholder/res/values-ne/strings.xml
+++ b/car-maps-placeholder/res/values-ne/strings.xml
@@ -17,5 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="6575346965016311017">"नक्सा"</string>
-    <string name="error_text" msgid="5575174711944349180">"नक्सासम्बन्धी कुनै पनि अनुप्रयोगहरू स्थापना गरिएको छैन। कृपया आफ्नो कार निर्मातालाई सम्पर्क गर्नुहोस्‌।"</string>
+    <string name="error_text" msgid="5575174711944349180">"नक्सासम्बन्धी कुनै पनि एपहरू स्थापना गरिएको छैन। कृपया आफ्नो कार निर्मातालाई सम्पर्क गर्नुहोस्‌।"</string>
 </resources>
diff --git a/car-systemtest-lib/Android.bp b/car-systemtest-lib/Android.bp
new file mode 100644
index 0000000..aee61a3
--- /dev/null
+++ b/car-systemtest-lib/Android.bp
@@ -0,0 +1,28 @@
+// 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.
+//
+//
+
+java_library {
+
+    name: "car-systemtest",
+
+    srcs: [
+        "src/**/*.java",
+        "src/**/I*.aidl",
+    ],
+
+    libs: ["android.car"],
+
+}
diff --git a/car-systemtest-lib/Android.mk b/car-systemtest-lib/Android.mk
deleted file mode 100644
index 6e4def5..0000000
--- a/car-systemtest-lib/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := car-systemtest
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
-
-LOCAL_AIDL_INCLUDES += packages/services/Car/libvehiclenetwork/java/src/
-
-LOCAL_JAVA_LIBRARIES += android.car
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/car-test-lib/Android.bp b/car-test-lib/Android.bp
index 3d913a0..4522982 100644
--- a/car-test-lib/Android.bp
+++ b/car-test-lib/Android.bp
@@ -15,7 +15,7 @@
 java_library {
     name: "android.car.testapi",
     srcs: [
-        "src/**/*.java",
+        "src/android/car/testapi/*.java",
     ],
     product_variables: {
         pdk: {
@@ -24,7 +24,25 @@
     },
     static_libs: [
         "android.car",
+        "car-service-test-lib",
+    ],
+    libs: [
         "mockito",
     ],
     installable: false,
+    dist: {
+        targets: ["dist_files"],
+    }
+}
+
+java_library {
+    name: "android.car.test.utils",
+    srcs: [
+        "src/android/car/test/**/*.java",
+    ],
+    libs: [
+        "android.hardware.automotive.vehicle-V2.0-java",
+        "mockito-target-extended",
+        "compatibility-device-util-axt",
+    ],
 }
diff --git a/car-test-lib/Android.mk b/car-test-lib/Android.mk
deleted file mode 100644
index 6ece515..0000000
--- a/car-test-lib/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2019 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-#
-
-#disble build in PDK, missing aidl import breaks build
-ifneq ($(TARGET_BUILD_PDK),true)
-
-include $(CLEAR_VARS)
-
-ifeq ($(BOARD_IS_AUTOMOTIVE), true)
-full_classes_jar := $(call intermediates-dir-for,JAVA_LIBRARIES,android.car.testapi,,COMMON)/classes.jar
-$(call dist-for-goals,dist_files,$(full_classes_jar):android.car.testapi.jar)
-endif
-
-endif #TARGET_BUILD_PDK
diff --git a/car-test-lib/src/android/car/test/mocks/AbstractExtendedMockitoTestCase.java b/car-test-lib/src/android/car/test/mocks/AbstractExtendedMockitoTestCase.java
new file mode 100644
index 0000000..09d2670
--- /dev/null
+++ b/car-test-lib/src/android/car/test/mocks/AbstractExtendedMockitoTestCase.java
@@ -0,0 +1,580 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.test.mocks;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.Mockito.when;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Trace;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.util.Log;
+import android.util.Slog;
+import android.util.TimingsTraceLog;
+
+import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
+import com.android.internal.util.Preconditions;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import org.mockito.MockitoSession;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.quality.Strictness;
+import org.mockito.session.MockitoSessionBuilder;
+import org.mockito.stubbing.Answer;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Base class for tests that must use {@link com.android.dx.mockito.inline.extended.ExtendedMockito}
+ * to mock static classes and final methods.
+ *
+ * <p><b>Note: </b> this class automatically spy on {@link Log} and {@link Slog} and fail tests that
+ * all any of their {@code wtf()} methods. If a test is expect to call {@code wtf()}, it should be
+ * annotated with {@link ExpectWtf}.
+ *
+ * <p><b>Note: </b>when using this class, you must include the following
+ * dependencies on {@code Android.bp} (or {@code Android.mk}:
+ * <pre><code>
+    jni_libs: [
+        "libdexmakerjvmtiagent",
+        "libstaticjvmtiagent",
+    ],
+
+   LOCAL_JNI_SHARED_LIBRARIES := \
+      libdexmakerjvmtiagent \
+      libstaticjvmtiagent \
+ *  </code></pre>
+ */
+public abstract class AbstractExtendedMockitoTestCase {
+
+    private static final String TAG = AbstractExtendedMockitoTestCase.class.getSimpleName();
+
+    private static final boolean TRACE = false;
+    private static final boolean VERBOSE = false;
+
+    private final List<Class<?>> mStaticSpiedClasses = new ArrayList<>();
+
+    // Tracks (S)Log.wtf() calls made during code execution, then used on verifyWtfNeverLogged()
+    private final List<RuntimeException> mWtfs = new ArrayList<>();
+
+    private MockitoSession mSession;
+    private MockSettings mSettings;
+
+    @Nullable
+    private final TimingsTraceLog mTracer;
+
+    @Rule
+    public final WtfCheckerRule mWtfCheckerRule = new WtfCheckerRule();
+
+    protected AbstractExtendedMockitoTestCase() {
+        mTracer = TRACE ? new TimingsTraceLog(TAG, Trace.TRACE_TAG_APP) : null;
+    }
+
+    @Before
+    public final void startSession() {
+        beginTrace("startSession()");
+
+        beginTrace("startMocking()");
+        mSession = newSessionBuilder().startMocking();
+        endTrace();
+
+        beginTrace("MockSettings()");
+        mSettings = new MockSettings();
+        endTrace();
+
+        beginTrace("interceptWtfCalls()");
+        interceptWtfCalls();
+        endTrace();
+
+        endTrace(); // startSession
+    }
+
+    @After
+    public final void finishSession() {
+        beginTrace("finishSession()");
+        completeAllHandlerThreadTasks();
+        if (mSession != null) {
+            beginTrace("finishMocking()");
+            mSession.finishMocking();
+            endTrace();
+        } else {
+            Log.w(TAG, getClass().getSimpleName() + ".finishSession(): no session");
+        }
+        endTrace();
+    }
+
+    /**
+     * Waits for completion of all pending Handler tasks for all HandlerThread in the process.
+     *
+     * <p>This can prevent pending Handler tasks of one test from affecting another. This does not
+     * work if the message is posted with delay.
+     */
+    protected void completeAllHandlerThreadTasks() {
+        beginTrace("completeAllHandlerThreadTasks");
+        Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
+        ArrayList<HandlerThread> handlerThreads = new ArrayList<>(threadSet.size());
+        Thread currentThread = Thread.currentThread();
+        for (Thread t : threadSet) {
+            if (t != currentThread && t instanceof HandlerThread) {
+                handlerThreads.add((HandlerThread) t);
+            }
+        }
+        ArrayList<SyncRunnable> syncs = new ArrayList<>(handlerThreads.size());
+        Log.i(TAG, "will wait for " + handlerThreads.size() + " HandlerThreads");
+        for (int i = 0; i < handlerThreads.size(); i++) {
+            Handler handler = new Handler(handlerThreads.get(i).getLooper());
+            SyncRunnable sr = new SyncRunnable(() -> { });
+            handler.post(sr);
+            syncs.add(sr);
+        }
+        beginTrace("waitForComplete");
+        for (int i = 0; i < syncs.size(); i++) {
+            syncs.get(i).waitForComplete();
+        }
+        endTrace(); // waitForComplete
+        endTrace(); // completeAllHandlerThreadTasks
+    }
+
+    /**
+     * Adds key-value(int) pair in mocked Settings.Global and Settings.Secure
+     */
+    protected void putSettingsInt(@NonNull String key, int value) {
+        mSettings.insertObject(key, value);
+    }
+
+    /**
+     * Gets value(int) from mocked Settings.Global and Settings.Secure
+     */
+    protected int getSettingsInt(@NonNull String key) {
+        return mSettings.getInt(key);
+    }
+
+    /**
+     * Adds key-value(String) pair in mocked Settings.Global and Settings.Secure
+     */
+    protected void putSettingsString(@NonNull String key, @NonNull String value) {
+        mSettings.insertObject(key, value);
+    }
+
+    /**
+     * Gets value(String) from mocked Settings.Global and Settings.Secure
+     */
+    protected String getSettingsString(@NonNull String key) {
+        return mSettings.getString(key);
+    }
+
+    /**
+     * Asserts that the giving settings was not set.
+     */
+    protected void assertSettingsNotSet(String key) {
+        mSettings.assertDoesNotContainsKey(key);
+    }
+
+    /**
+     * Subclasses can use this method to initialize the Mockito session that's started before every
+     * test on {@link #startSession()}.
+     *
+     * <p>Typically, it should be overridden when mocking static methods.
+     */
+    protected void onSessionBuilder(@NonNull CustomMockitoSessionBuilder session) {
+        if (VERBOSE) Log.v(TAG, getLogPrefix() + "onSessionBuilder()");
+    }
+
+    /**
+     * Changes the value of the session created by
+     * {@link #onSessionBuilder(CustomMockitoSessionBuilder)}.
+     *
+     * <p>By default it's set to {@link Strictness.LENIENT}, but subclasses can overwrite this
+     * method to change the behavior.
+     */
+    @NonNull
+    protected Strictness getSessionStrictness() {
+        return Strictness.LENIENT;
+    }
+
+    /**
+     * Mocks a call to {@link ActivityManager#getCurrentUser()}.
+     *
+     * @param userId result of such call
+     *
+     * @throws IllegalStateException if class didn't override {@link #newSessionBuilder()} and
+     * called {@code spyStatic(ActivityManager.class)} on the session passed to it.
+     */
+    protected final void mockGetCurrentUser(@UserIdInt int userId) {
+        if (VERBOSE) Log.v(TAG, getLogPrefix() + "mockGetCurrentUser(" + userId + ")");
+        assertSpied(ActivityManager.class);
+
+        beginTrace("mockAmGetCurrentUser-" + userId);
+        AndroidMockitoHelper.mockAmGetCurrentUser(userId);
+        endTrace();
+    }
+
+    /**
+     * Mocks a call to {@link UserManager#isHeadlessSystemUserMode()}.
+     *
+     * @param mode result of such call
+     *
+     * @throws IllegalStateException if class didn't override {@link #newSessionBuilder()} and
+     * called {@code spyStatic(UserManager.class)} on the session passed to it.
+     */
+    protected final void mockIsHeadlessSystemUserMode(boolean mode) {
+        if (VERBOSE) Log.v(TAG, getLogPrefix() + "mockIsHeadlessSystemUserMode(" + mode + ")");
+        assertSpied(UserManager.class);
+
+        beginTrace("mockUmIsHeadlessSystemUserMode");
+        AndroidMockitoHelper.mockUmIsHeadlessSystemUserMode(mode);
+        endTrace();
+    }
+
+    /**
+     * Starts a tracing message.
+     *
+     * <p>MUST be followed by a {@link #endTrace()} calls.
+     *
+     * <p>Ignored if {@value #VERBOSE} is {@code false}.
+     */
+    protected final void beginTrace(@NonNull String message) {
+        if (mTracer == null) return;
+
+        Log.d(TAG, getLogPrefix() + message);
+        mTracer.traceBegin(message);
+    }
+
+    /**
+     * Ends a tracing call.
+     *
+     * <p>MUST be called after {@link #beginTrace(String)}.
+     *
+     * <p>Ignored if {@value #VERBOSE} is {@code false}.
+     */
+    protected final void endTrace() {
+        if (mTracer == null) return;
+
+        mTracer.traceEnd();
+    }
+
+    private void interceptWtfCalls() {
+        doAnswer((invocation) -> {
+            return addWtf(invocation);
+        }).when(() -> Log.wtf(anyString(), anyString()));
+        doAnswer((invocation) -> {
+            return addWtf(invocation);
+        }).when(() -> Log.wtf(anyString(), anyString(), notNull()));
+        doAnswer((invocation) -> {
+            return addWtf(invocation);
+        }).when(() -> Slog.wtf(anyString(), anyString()));
+        doAnswer((invocation) -> {
+            return addWtf(invocation);
+        }).when(() -> Slog.wtf(anyString(), anyString(), notNull()));
+    }
+
+    private Object addWtf(InvocationOnMock invocation) {
+        String message = "Called " + invocation;
+        Log.d(TAG, message); // Log always, as some test expect it
+        mWtfs.add(new IllegalStateException(message));
+        return null;
+    }
+
+    private void verifyWtfLogged() {
+        Preconditions.checkState(!mWtfs.isEmpty(), "no wtf() called");
+    }
+
+    private void verifyWtfNeverLogged() {
+        int size = mWtfs.size();
+
+        switch (size) {
+            case 0:
+                return;
+            case 1:
+                throw mWtfs.get(0);
+            default:
+                StringBuilder msg = new StringBuilder("wtf called ").append(size).append(" times")
+                        .append(": ").append(mWtfs);
+                throw new AssertionError(msg.toString());
+        }
+    }
+
+    @NonNull
+    private MockitoSessionBuilder newSessionBuilder() {
+        // TODO (b/155523104): change from mock to spy
+        StaticMockitoSessionBuilder builder = mockitoSession()
+                .strictness(getSessionStrictness())
+                .mockStatic(Settings.Global.class)
+                .mockStatic(Settings.System.class)
+                .mockStatic(Settings.Secure.class);
+
+        CustomMockitoSessionBuilder customBuilder =
+                new CustomMockitoSessionBuilder(builder, mStaticSpiedClasses)
+                    .spyStatic(Log.class)
+                    .spyStatic(Slog.class);
+
+        onSessionBuilder(customBuilder);
+
+        if (VERBOSE) Log.v(TAG, "spied classes" + customBuilder.mStaticSpiedClasses);
+
+        return builder.initMocks(this);
+    }
+
+    /**
+     * Gets a prefix for {@link Log} calls
+     */
+    protected String getLogPrefix() {
+        return getClass().getSimpleName() + ".";
+    }
+
+    /**
+     * Asserts the given class is being spied in the Mockito session.
+     */
+    protected void assertSpied(Class<?> clazz) {
+        Preconditions.checkArgument(mStaticSpiedClasses.contains(clazz),
+                "did not call spyStatic() on %s", clazz.getName());
+    }
+
+    /**
+     * Custom {@code MockitoSessionBuilder} used to make sure some pre-defined mock stations
+     * (like {@link AbstractExtendedMockitoTestCase#mockGetCurrentUser(int)} fail if the test case
+     * didn't explicitly set it to spy / mock the required classes.
+     *
+     * <p><b>NOTE: </b>for now it only provides simple {@link #spyStatic(Class)}, but more methods
+     * (as provided by {@link StaticMockitoSessionBuilder}) could be provided as needed.
+     */
+    public static final class CustomMockitoSessionBuilder {
+        private final StaticMockitoSessionBuilder mBuilder;
+        private final List<Class<?>> mStaticSpiedClasses;
+
+        private CustomMockitoSessionBuilder(StaticMockitoSessionBuilder builder,
+                List<Class<?>> staticSpiedClasses) {
+            mBuilder = builder;
+            mStaticSpiedClasses = staticSpiedClasses;
+        }
+
+        /**
+         * Same as {@link StaticMockitoSessionBuilder#spyStatic(Class)}.
+         */
+        public <T> CustomMockitoSessionBuilder spyStatic(Class<T> clazz) {
+            Preconditions.checkState(!mStaticSpiedClasses.contains(clazz),
+                    "already called spyStatic() on " + clazz);
+            mStaticSpiedClasses.add(clazz);
+            mBuilder.spyStatic(clazz);
+            return this;
+        }
+    }
+
+    private final class WtfCheckerRule implements TestRule {
+
+        @Override
+        public Statement apply(Statement base, Description description) {
+            return new Statement() {
+                @Override
+                public void evaluate() throws Throwable {
+                    String testName = description.getMethodName();
+                    if (VERBOSE) Log.v(TAG, "running " + testName);
+                    beginTrace("evaluate-" + testName);
+                    base.evaluate();
+                    endTrace();
+
+                    Method testMethod = AbstractExtendedMockitoTestCase.this.getClass()
+                            .getMethod(testName);
+                    ExpectWtf expectWtfAnnotation = testMethod.getAnnotation(ExpectWtf.class);
+
+                    beginTrace("verify-wtfs");
+                    try {
+                        if (expectWtfAnnotation != null) {
+                            if (VERBOSE) Log.v(TAG, "expecting wtf()");
+                            verifyWtfLogged();
+                        } else {
+                            if (VERBOSE) Log.v(TAG, "NOT expecting wtf()");
+                            verifyWtfNeverLogged();
+                        }
+                    } finally {
+                        endTrace();
+                    }
+                }
+            };
+        }
+    }
+
+    // TODO (b/155523104): Add log
+    // TODO (b/156033195): Clean settings API
+    private static final class MockSettings {
+        private static final int INVALID_DEFAULT_INDEX = -1;
+        private HashMap<String, Object> mSettingsMapping = new HashMap<>();
+
+        MockSettings() {
+
+            Answer<Object> insertObjectAnswer =
+                    invocation -> insertObjectFromInvocation(invocation, 1, 2);
+            Answer<Integer> getIntAnswer = invocation ->
+                    getAnswer(invocation, Integer.class, 1, 2);
+            Answer<String> getStringAnswer = invocation ->
+                    getAnswer(invocation, String.class, 1, INVALID_DEFAULT_INDEX);
+
+            when(Settings.Global.putInt(any(), any(), anyInt())).thenAnswer(insertObjectAnswer);
+
+            when(Settings.Global.getInt(any(), any(), anyInt())).thenAnswer(getIntAnswer);
+
+            when(Settings.Secure.putIntForUser(any(), any(), anyInt(), anyInt()))
+                    .thenAnswer(insertObjectAnswer);
+
+            when(Settings.Secure.getIntForUser(any(), any(), anyInt(), anyInt()))
+                    .thenAnswer(getIntAnswer);
+
+            when(Settings.Secure.putStringForUser(any(), anyString(), anyString(), anyInt()))
+                    .thenAnswer(insertObjectAnswer);
+
+            when(Settings.Global.putString(any(), any(), any()))
+                    .thenAnswer(insertObjectAnswer);
+
+            when(Settings.Global.getString(any(), any())).thenAnswer(getStringAnswer);
+
+            when(Settings.System.putIntForUser(any(), any(), anyInt(), anyInt()))
+                    .thenAnswer(insertObjectAnswer);
+
+            when(Settings.System.getIntForUser(any(), any(), anyInt(), anyInt()))
+                    .thenAnswer(getIntAnswer);
+
+            when(Settings.System.putStringForUser(any(), any(), anyString(), anyInt()))
+                    .thenAnswer(insertObjectAnswer);
+        }
+
+        private Object insertObjectFromInvocation(InvocationOnMock invocation,
+                int keyIndex, int valueIndex) {
+            String key = (String) invocation.getArguments()[keyIndex];
+            Object value = invocation.getArguments()[valueIndex];
+            insertObject(key, value);
+            return null;
+        }
+
+        private void insertObject(String key, Object value) {
+            if (VERBOSE) Log.v(TAG, "Inserting Setting " + key + ": " + value);
+            mSettingsMapping.put(key, value);
+        }
+
+        private <T> T getAnswer(InvocationOnMock invocation, Class<T> clazz,
+                int keyIndex, int defaultValueIndex) {
+            String key = (String) invocation.getArguments()[keyIndex];
+            T defaultValue = null;
+            if (defaultValueIndex > INVALID_DEFAULT_INDEX) {
+                defaultValue = safeCast(invocation.getArguments()[defaultValueIndex], clazz);
+            }
+            return get(key, defaultValue, clazz);
+        }
+
+        @Nullable
+        private <T> T get(String key, T defaultValue, Class<T> clazz) {
+            if (VERBOSE) {
+                Log.v(TAG, "get(): key=" + key + ", default=" + defaultValue + ", class=" + clazz);
+            }
+            Object value = mSettingsMapping.get(key);
+            if (value == null) {
+                if (VERBOSE) Log.v(TAG, "not found");
+                return defaultValue;
+            }
+
+            if (VERBOSE) Log.v(TAG, "returning " + value);
+            return safeCast(value, clazz);
+        }
+
+        private static <T> T safeCast(Object value, Class<T> clazz) {
+            if (value == null) {
+                return null;
+            }
+            Preconditions.checkArgument(value.getClass() == clazz,
+                    "Setting value has class %s but requires class %s",
+                    value.getClass(), clazz);
+            return clazz.cast(value);
+        }
+
+        private String getString(String key) {
+            return get(key, null, String.class);
+        }
+
+        public int getInt(String key) {
+            return get(key, null, Integer.class);
+        }
+
+        public void assertDoesNotContainsKey(String key) {
+            if (mSettingsMapping.containsKey(key)) {
+                throw new AssertionError("Should not have key " + key + ", but has: "
+                        + mSettingsMapping.get(key));
+            }
+        }
+    }
+
+    /**
+     * Annotation used on test methods that are expect to call {@code wtf()} methods on {@link Log}
+     * or {@link Slog} - if such methods are not annotated with this annotation, they will fail.
+     */
+    @Retention(RUNTIME)
+    @Target({METHOD})
+    public static @interface ExpectWtf {
+    }
+
+    private static final class SyncRunnable implements Runnable {
+        private final Runnable mTarget;
+        private volatile boolean mComplete = false;
+
+        private SyncRunnable(Runnable target) {
+            mTarget = target;
+        }
+
+        @Override
+        public void run() {
+            mTarget.run();
+            synchronized (this) {
+                mComplete = true;
+                notifyAll();
+            }
+        }
+
+        private void waitForComplete() {
+            synchronized (this) {
+                while (!mComplete) {
+                    try {
+                        wait();
+                    } catch (InterruptedException e) {
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/car-test-lib/src/android/car/test/mocks/AndroidMockitoHelper.java b/car-test-lib/src/android/car/test/mocks/AndroidMockitoHelper.java
new file mode 100644
index 0000000..f6b15f2
--- /dev/null
+++ b/car-test-lib/src/android/car/test/mocks/AndroidMockitoHelper.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.test.mocks;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.car.test.util.UserTestingHelper;
+import android.car.test.util.UserTestingHelper.UserInfoBuilder;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.content.pm.UserInfo.UserInfoFlag;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import com.android.internal.infra.AndroidFuture;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.stream.Collectors;
+
+/**
+ * Provides common Mockito calls for core Android classes.
+ */
+public final class AndroidMockitoHelper {
+
+    private static final long ASYNC_TIMEOUT_MS = 500;
+
+    /**
+     * Mocks a call to {@link ActivityManager#getCurrentUser()}.
+     *
+     * <p><b>Note: </b>it must be made inside a
+     * {@link com.android.dx.mockito.inline.extended.StaticMockitoSession} built with
+     * {@code spyStatic(ActivityManager.class)}.
+     *
+     * @param userId result of such call
+     */
+    public static void mockAmGetCurrentUser(@UserIdInt int userId) {
+        doReturn(userId).when(() -> ActivityManager.getCurrentUser());
+    }
+
+    /**
+     * Mocks a call to {@link UserManager#isHeadlessSystemUserMode()}.
+     *
+     * <p><b>Note: </b>it must be made inside a
+     * {@linkcom.android.dx.mockito.inline.extended.StaticMockitoSession} built with
+     * {@code spyStatic(UserManager.class)}.
+     *
+     * @param mode result of such call
+     */
+    public static void mockUmIsHeadlessSystemUserMode(boolean mode) {
+        doReturn(mode).when(() -> UserManager.isHeadlessSystemUserMode());
+    }
+
+    /**
+     * Mocks {@code UserManager#getUserInfo(userId)} to return a {@link UserInfo} with the given
+     * {@code flags}.
+     */
+    @NonNull
+    public static UserInfo mockUmGetUserInfo(@NonNull UserManager um, @UserIdInt int userId,
+            @UserInfoFlag int flags) {
+        Objects.requireNonNull(um);
+        UserInfo user = new UserTestingHelper.UserInfoBuilder(userId).setFlags(flags).build();
+        mockUmGetUserInfo(um, user);
+        return user;
+    }
+
+    /**
+     * Mocks {@code UserManager.getUserInfo(userId)} to return the given {@link UserInfo}.
+     */
+    @NonNull
+    public static void mockUmGetUserInfo(@NonNull UserManager um, @NonNull UserInfo user) {
+        when(um.getUserInfo(user.id)).thenReturn(user);
+    }
+
+    /**
+     * Mocks {@code UserManager#getUserInfo(userId)} when the {@code userId} is the system user's.
+     */
+    @NonNull
+    public static void mockUmGetSystemUser(@NonNull UserManager um) {
+        UserInfo user = new UserTestingHelper.UserInfoBuilder(UserHandle.USER_SYSTEM)
+                .setFlags(UserInfo.FLAG_SYSTEM).build();
+        when(um.getUserInfo(UserHandle.USER_SYSTEM)).thenReturn(user);
+    }
+
+    /**
+     * Mocks {@code UserManager#getUsers()}, {@code UserManager#getUsers(excludeDying)}, and
+     * {@code UserManager#getUsers(excludePartial, excludeDying, excludeDying)} to return the given
+     * users.
+     */
+    public static void mockUmGetUsers(@NonNull UserManager um, @NonNull UserInfo... users) {
+        Objects.requireNonNull(um);
+        List<UserInfo> testUsers = Arrays.stream(users).collect(Collectors.toList());
+        when(um.getUsers()).thenReturn(testUsers);
+        when(um.getUsers(anyBoolean())).thenReturn(testUsers);
+        when(um.getUsers(anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(testUsers);
+    }
+
+    /**
+     * Mocks {@code UserManager#getUsers()}, {@code UserManager#getUsers(excludeDying)}, and
+     * {@code UserManager#getUsers(excludePartial, excludeDying, excludeDying)} to return simple
+     * users with the given ids.
+     */
+    public static void mockUmGetUsers(@NonNull UserManager um, @NonNull @UserIdInt int... userIds) {
+        List<UserInfo> users = UserTestingHelper.newUsers(userIds);
+        when(um.getUsers()).thenReturn(users);
+        when(um.getUsers(anyBoolean())).thenReturn(users);
+        when(um.getUsers(anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(users);
+    }
+
+    /**
+     * Mocks a call to {@code UserManager#getUsers()}, which includes dying users.
+     */
+    public static void mockUmGetAllUsers(@NonNull UserManager um,
+            @NonNull List<UserInfo> userInfos) {
+        when(um.getUsers()).thenReturn(userInfos);
+    }
+
+    /**
+     * Mocks {@code UserManager#getUsers()}, {@code UserManager#getUsers(excludeDying)}, and
+     * {@code UserManager#getUsers(excludePartial, excludeDying, excludeDying)} to return given
+     * userInfos.
+     */
+    public static void mockUmGetUsers(@NonNull UserManager um, @NonNull List<UserInfo> userInfos) {
+        when(um.getUsers()).thenReturn(userInfos);
+        when(um.getUsers(anyBoolean())).thenReturn(userInfos);
+        when(um.getUsers(anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(userInfos);
+    }
+
+    /**
+     * Mocks a call to {@code UserManager#isUserRunning(userId)}.
+     */
+    public static void mockUmIsUserRunning(@NonNull UserManager um, @UserIdInt int userId,
+            boolean isRunning) {
+        when(um.isUserRunning(userId)).thenReturn(isRunning);
+    }
+
+    /**
+     * Mocks a successful call to {@code UserManager#createUser(String, String, int)}, returning
+     * a user with the passed arguments.
+     */
+    @NonNull
+    public static UserInfo mockUmCreateUser(@NonNull UserManager um, @Nullable String name,
+            @NonNull String userType, @UserInfoFlag int flags, @UserIdInt int userId) {
+        UserInfo userInfo = new UserInfoBuilder(userId)
+                        .setName(name)
+                        .setType(userType)
+                        .setFlags(flags)
+                        .build();
+        when(um.createUser(name, userType, flags)).thenReturn(userInfo);
+        return userInfo;
+    }
+
+    /**
+     * Mocks a call to {@code UserManager#createUser(String, String, int)} that throws the given
+     * runtime exception.
+     */
+    @NonNull
+    public static void mockUmCreateUser(@NonNull UserManager um, @Nullable String name,
+            @NonNull String userType, @UserInfoFlag int flags, @NonNull RuntimeException e) {
+        when(um.createUser(name, userType, flags)).thenThrow(e);
+    }
+
+    /**
+     * Mocks a call to {@link ServiceManager#getService(name)}.
+     *
+     * <p><b>Note: </b>it must be made inside a
+     * {@link com.android.dx.mockito.inline.extended.StaticMockitoSession} built with
+     * {@code spyStatic(ServiceManager.class)}.
+     *
+     * @param name interface name of the service
+     * @param binder result of such call
+     */
+    public static void mockSmGetService(@NonNull String name, @NonNull IBinder binder) {
+        doReturn(binder).when(() -> ServiceManager.getService(name));
+    }
+
+    /**
+     * Returns mocked binder implementation from the given interface name.
+     *
+     * <p><b>Note: </b>it must be made inside a
+     * {@link com.android.dx.mockito.inline.extended.StaticMockitoSession} built with
+     * {@code spyStatic(ServiceManager.class)}.
+     *
+     * @param name interface name of the service
+     * @param binder mocked return of ServiceManager.getService
+     * @param service binder implementation
+     */
+    public static <T extends IInterface> void mockQueryService(@NonNull String name,
+            @NonNull IBinder binder, @NonNull T service) {
+        doReturn(binder).when(() -> ServiceManager.getService(name));
+        when(binder.queryLocalInterface(anyString())).thenReturn(service);
+    }
+
+    /**
+     * Mocks a call to {@link Context#getSystemService(Class)}.
+     */
+    public static <T> void mockContextGetService(@NonNull Context context,
+            @NonNull Class<T> serviceClass, @NonNull T service) {
+        when(context.getSystemService(serviceClass)).thenReturn(service);
+        if (serviceClass.equals(PackageManager.class)) {
+            when(context.getPackageManager()).thenReturn(PackageManager.class.cast(service));
+        }
+    }
+
+    /**
+     * Gets the result of a future, or throw a {@link IllegalStateException} if it times out after
+     * {@value #ASYNC_TIMEOUT_MS} ms.
+     */
+    @NonNull
+    public static <T> T getResult(@NonNull AndroidFuture<T> future)
+            throws InterruptedException, ExecutionException {
+        return getResult(future, ASYNC_TIMEOUT_MS);
+    }
+
+    /**
+     * Gets the result of a future, or throw a {@link IllegalStateException} if it times out.
+     */
+    @NonNull
+    public static <T> T getResult(@NonNull AndroidFuture<T> future, long timeoutMs)
+            throws InterruptedException, ExecutionException {
+        try {
+            return future.get(timeoutMs, TimeUnit.MILLISECONDS);
+        } catch (TimeoutException e) {
+            throw new IllegalStateException("not called in " + ASYNC_TIMEOUT_MS + "ms", e);
+        }
+    }
+
+    private AndroidMockitoHelper() {
+        throw new UnsupportedOperationException("contains only static methods");
+    }
+}
diff --git a/car-test-lib/src/android/car/test/mocks/BlockingAnswer.java b/car-test-lib/src/android/car/test/mocks/BlockingAnswer.java
new file mode 100644
index 0000000..c0594cc
--- /dev/null
+++ b/car-test-lib/src/android/car/test/mocks/BlockingAnswer.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.test.mocks;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.car.test.util.Visitor;
+import android.util.Log;
+
+import com.android.internal.util.FunctionalUtils;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * Custom Mockito {@link Answer} that blocks until a condition is unblocked by the test case.
+ *
+ * <p>Example:
+ *
+ * <pre><code>
+ *
+ *  BlockingAnswer<Void> blockingAnswer = BlockingAnswer.forVoidReturn(10_000, (invocation) -> {
+ *     MyObject obj = (MyObject) invocation.getArguments()[0];
+ *     obj.doSomething();
+ *  });
+ *  doAnswer(blockingAnswer).when(mMock).mockSomething();
+ *  doSomethingOnTest();
+ *  blockingAnswer.unblock();
+ *
+ * </code></pre>
+ */
+public final class BlockingAnswer<T> implements Answer<T> {
+
+    private static final String TAG = BlockingAnswer.class.getSimpleName();
+
+    private final CountDownLatch mLatch = new CountDownLatch(1);
+
+    private final long mTimeoutMs;
+
+    @NonNull
+    private final Visitor<InvocationOnMock> mInvocator;
+
+    @Nullable
+    private final T mValue;
+
+    private BlockingAnswer(long timeoutMs, @NonNull Visitor<InvocationOnMock> invocator,
+            @Nullable T value) {
+        mTimeoutMs = timeoutMs;
+        mInvocator = invocator;
+        mValue = value;
+    }
+
+    /**
+     * Unblocks the answer so the test case can continue.
+     */
+    public void unblock() {
+        Log.v(TAG, "Unblocking " + mLatch);
+        mLatch.countDown();
+    }
+
+    /**
+     * Creates a {@link BlockingAnswer} for a {@code void} method.
+     *
+     * @param timeoutMs maximum time the answer would block.
+     *
+     * @param invocator code executed after the answer is unblocked.
+     */
+    public static BlockingAnswer<Void> forVoidReturn(long timeoutMs,
+            @NonNull Visitor<InvocationOnMock> invocator) {
+        return new BlockingAnswer<Void>(timeoutMs, invocator, /* value= */ null);
+    }
+
+    /**
+     * Creates a {@link BlockingAnswer} for a method that returns type {@code T}
+     *
+     * @param timeoutMs maximum time the answer would block.
+     * @param invocator code executed after the answer is unblocked.
+     *
+     * @return what the answer should return
+     */
+    public static <T> BlockingAnswer<T> forReturn(long timeoutMs,
+            @NonNull Visitor<InvocationOnMock> invocator, @Nullable T value) {
+        return new BlockingAnswer<T>(timeoutMs, invocator, value);
+    }
+
+    @Override
+    public T answer(InvocationOnMock invocation) throws Throwable {
+        String threadName = "BlockingAnswerThread";
+        Log.d(TAG, "Starting thread " + threadName);
+
+        new Thread(() -> {
+            JavaMockitoHelper.silentAwait(mLatch, mTimeoutMs);
+            Log.d(TAG, "Invocating " + FunctionalUtils.getLambdaName(mInvocator));
+            mInvocator.visit(invocation);
+        }, threadName).start();
+        Log.d(TAG, "Returning " + mValue);
+        return mValue;
+    }
+}
diff --git a/car-test-lib/src/android/car/test/mocks/CarArgumentMatchers.java b/car-test-lib/src/android/car/test/mocks/CarArgumentMatchers.java
new file mode 100644
index 0000000..1d1c399
--- /dev/null
+++ b/car-test-lib/src/android/car/test/mocks/CarArgumentMatchers.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.test.mocks;
+
+import static org.mockito.ArgumentMatchers.argThat;
+
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.pm.UserInfo;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
+import android.os.UserHandle;
+import android.util.Log;
+
+import org.mockito.ArgumentMatcher;
+
+import java.util.Arrays;
+
+/**
+ * Provides custom mockito matcher for Android / Car objects.
+ *
+ */
+public final class CarArgumentMatchers {
+
+    private static final String TAG = CarArgumentMatchers.class.getSimpleName();
+
+    /**
+     * Matches if a {@link UserInfo} has the given {@code userId}.
+     */
+    public static UserInfo isUserInfo(@UserIdInt int userId) {
+        return argThat(new UserInfoMatcher(userId));
+    }
+
+    /**
+     * Matches if a {@link UserHandle} has the given {@code userId}.
+     */
+    public static UserHandle isUserHandle(@UserIdInt int userId) {
+        return argThat(new UserHandleMatcher(userId));
+    }
+
+    /**
+     * Matches if a {@link VehiclePropValue} has the given {@code prop}.
+     */
+    public static VehiclePropValue isProperty(int prop) {
+        return argThat(new PropertyIdMatcher(prop));
+    }
+
+    /**
+     * Matches if a {@link VehiclePropValue} has the given {@code prop} and {@code int32} values.
+     */
+    public static VehiclePropValue isPropertyWithValues(int prop, int...values) {
+        return argThat(new PropertyIdMatcher(prop, values));
+    }
+
+    private static class UserInfoMatcher implements ArgumentMatcher<UserInfo> {
+
+        public final @UserIdInt int userId;
+
+        private UserInfoMatcher(@UserIdInt int userId) {
+            this.userId = userId;
+        }
+
+        @Override
+        public boolean matches(@Nullable UserInfo argument) {
+            if (argument == null) {
+                Log.w(TAG, "isUserInfo(): null argument");
+                return false;
+            }
+            if (argument.id != userId) {
+                Log.w(TAG, "isUserInfo(): argument mismatch (expected " + userId
+                        + ", got " + argument.id);
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return "isUserInfo(userId=" + userId + ")";
+        }
+    }
+
+    private static class UserHandleMatcher implements ArgumentMatcher<UserHandle> {
+
+        public final @UserIdInt int userId;
+
+        private UserHandleMatcher(@UserIdInt int userId) {
+            this.userId = userId;
+        }
+
+        @Override
+        public boolean matches(UserHandle argument) {
+            if (argument == null) {
+                Log.w(TAG, "isUserHandle(): null argument");
+                return false;
+            }
+            if (argument.getIdentifier() != userId) {
+                Log.w(TAG, "isUserHandle(): argument mismatch (expected " + userId
+                        + ", got " + argument.getIdentifier());
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return "isUserHandle(userId=" + userId + ")";
+        }
+    }
+
+    private static class PropertyIdMatcher implements ArgumentMatcher<VehiclePropValue> {
+
+        final int mProp;
+        private final int[] mValues;
+
+        private PropertyIdMatcher(int prop) {
+            this(prop, null);
+        }
+
+        private PropertyIdMatcher(int prop, int[] values) {
+            mProp = prop;
+            mValues = values;
+        }
+
+        @Override
+        public boolean matches(VehiclePropValue argument) {
+            Log.v(TAG, "PropertyIdMatcher: argument=" + argument);
+            if (argument.prop != mProp) {
+                Log.w(TAG, "PropertyIdMatcher: Invalid prop on " + argument);
+                return false;
+            }
+            if (mValues == null) return true;
+            // Make sure values match
+            if (mValues.length != argument.value.int32Values.size()) {
+                Log.w(TAG, "PropertyIdMatcher: number of values (expected " + mValues.length
+                        + ") mismatch on " + argument);
+                return false;
+            }
+
+            for (int i = 0; i < mValues.length; i++) {
+                if (mValues[i] != argument.value.int32Values.get(i)) {
+                    Log.w(TAG, "PropertyIdMatcher: value mismatch at index " + i + " on " + argument
+                            + ": expected " + Arrays.toString(mValues));
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return "prop: " + mProp + " values: " + Arrays.toString(mValues);
+        }
+    }
+
+    private CarArgumentMatchers() {
+        throw new UnsupportedOperationException("contains only static methods");
+    }
+}
diff --git a/car-test-lib/src/android/car/test/mocks/JavaMockitoHelper.java b/car-test-lib/src/android/car/test/mocks/JavaMockitoHelper.java
new file mode 100644
index 0000000..ab772a9
--- /dev/null
+++ b/car-test-lib/src/android/car/test/mocks/JavaMockitoHelper.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.test.mocks;
+
+import android.annotation.NonNull;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Provides common Mockito calls for core Java classes.
+ */
+public final class JavaMockitoHelper {
+
+    private static final String TAG = JavaMockitoHelper.class.getSimpleName();
+
+    /**
+     * Waits for a latch to be counted down.
+     *
+     * @param timeoutMs how long to wait for
+     *
+     * @throws {@link IllegalStateException} if it times out.
+     */
+    public static void await(@NonNull CountDownLatch latch, long timeoutMs)
+            throws InterruptedException {
+        if (!latch.await(timeoutMs, TimeUnit.MILLISECONDS)) {
+            throw new IllegalStateException(latch + " not called in " + timeoutMs + " ms");
+        }
+    }
+
+    /**
+     * Waits for a semaphore.
+     *
+     * @param timeoutMs how long to wait for
+     *
+     * @throws {@link IllegalStateException} if it times out.
+     */
+    public static void await(@NonNull Semaphore semaphore, long timeoutMs)
+            throws InterruptedException {
+        if (!semaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
+            throw new IllegalStateException(semaphore + " not released in " + timeoutMs + " ms");
+        }
+    }
+
+    /**
+     * Silently waits for a latch to be counted down, without throwing any exception if it isn't.
+     *
+     * @param timeoutMs how long to wait for
+     *
+     * @return whether the latch was counted down.
+     */
+    public static boolean silentAwait(@NonNull CountDownLatch latch, long timeoutMs) {
+        boolean called;
+        try {
+            called = latch.await(timeoutMs, TimeUnit.MILLISECONDS);
+            if (!called) {
+                Log.w(TAG, latch + " not called in " + timeoutMs + " ms");
+            }
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            Log.w(TAG, latch + " interrupted", e);
+            return false;
+        }
+        return called;
+    }
+
+    private JavaMockitoHelper() {
+        throw new UnsupportedOperationException("contains only static methods");
+    }
+}
diff --git a/car-test-lib/src/android/car/test/mocks/SyncAnswer.java b/car-test-lib/src/android/car/test/mocks/SyncAnswer.java
new file mode 100644
index 0000000..3e885b3
--- /dev/null
+++ b/car-test-lib/src/android/car/test/mocks/SyncAnswer.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.test.mocks;
+
+import android.annotation.NonNull;
+import android.util.Log;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * Custom Mockito {@link Answer} used to block the test until it's invoked.
+ *
+ * <p>Example:
+ *
+ * <pre><code>
+ *
+ * SyncAnswer<UserInfo> syncUserInfo = SyncAnswer.forReturn(user);
+ * when(mMock.preCreateUser(userType)).thenAnswer(syncUserInfo);
+ * objectUnderTest.preCreate();
+ * syncUserInfo.await(100);
+ *
+ * </code></pre>
+ */
+public final class SyncAnswer<T> implements Answer<T> {
+
+    private static final String TAG = SyncAnswer.class.getSimpleName();
+
+    private final CountDownLatch mLatch = new CountDownLatch(1);
+    private final T mAnswer;
+    private final Throwable mException;
+
+    private SyncAnswer(T answer, Throwable exception) {
+        mAnswer = answer;
+        mException = exception;
+    }
+
+    /**
+     * Creates an answer that returns a value.
+     */
+    @NonNull
+    public static <T> SyncAnswer<T> forReturn(@NonNull T value) {
+        return new SyncAnswer<T>(value, /* exception= */ null);
+    }
+
+    /**
+     * Creates an answer that throws an exception.
+     */
+    @NonNull
+    public static <T> SyncAnswer<T> forException(@NonNull Throwable t) {
+        return new SyncAnswer<T>(/* value= */ null, t);
+    }
+
+    /**
+     * Wait until the answer is invoked, or times out.
+     */
+    public void await(long timeoutMs) throws InterruptedException {
+        JavaMockitoHelper.await(mLatch, timeoutMs);
+    }
+
+    @Override
+    public T answer(InvocationOnMock invocation) throws Throwable {
+        Log.v(TAG, "answering " + invocation);
+        mLatch.countDown();
+        if (mException != null) {
+            throw mException;
+        }
+        return mAnswer;
+    }
+
+}
diff --git a/car-test-lib/src/android/car/test/util/BlockingResultReceiver.java b/car-test-lib/src/android/car/test/util/BlockingResultReceiver.java
new file mode 100644
index 0000000..cdf01fb
--- /dev/null
+++ b/car-test-lib/src/android/car/test/util/BlockingResultReceiver.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.test.util;
+
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.Preconditions;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Implementation of {@link IResultReceiver} that blocks waiting for the result.
+ */
+public final class BlockingResultReceiver extends IResultReceiver.Stub {
+
+    private static final String TAG = BlockingResultReceiver.class.getSimpleName();
+
+    private final CountDownLatch mLatch = new CountDownLatch(1);
+    private final long mTimeoutMs;
+
+    private int mResultCode;
+    @Nullable private Bundle mResultData;
+
+    /**
+     * Default constructor.
+     *
+     * @param timeoutMs how long to wait for before failing.
+     */
+    public BlockingResultReceiver(long timeoutMs) {
+        mTimeoutMs = timeoutMs;
+    }
+
+    @Override
+    public void send(int resultCode, Bundle resultData) {
+        Log.d(TAG, "send() received: code=" + resultCode + ", data=" + resultData + ", count="
+                + mLatch.getCount());
+        Preconditions.checkState(mLatch.getCount() == 1,
+                "send() already called (code=" + mResultCode + ", data=" + mResultData);
+        mResultCode = resultCode;
+        mResultData = resultData;
+        mLatch.countDown();
+    }
+
+    private void assertCalled() throws InterruptedException {
+        boolean called = mLatch.await(mTimeoutMs, TimeUnit.MILLISECONDS);
+        Log.d(TAG, "assertCalled(): " + called);
+        Preconditions.checkState(called, "receiver not called in " + mTimeoutMs + " ms");
+    }
+
+    /**
+     * Gets the {@code resultCode} or fails if it times out before {@code send()} is called.
+     */
+    public int getResultCode() throws InterruptedException {
+        assertCalled();
+        return mResultCode;
+    }
+
+    /**
+     * Gets the {@code resultData} or fails if it times out before {@code send()} is called.
+     */
+    @Nullable
+    public Bundle getResultData() throws InterruptedException {
+        assertCalled();
+        return mResultData;
+    }
+}
diff --git a/car-test-lib/src/android/car/test/util/UserTestingHelper.java b/car-test-lib/src/android/car/test/util/UserTestingHelper.java
new file mode 100644
index 0000000..d1c2f13
--- /dev/null
+++ b/car-test-lib/src/android/car/test/util/UserTestingHelper.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.test.util;
+
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.pm.UserInfo;
+import android.content.pm.UserInfo.UserInfoFlag;
+import android.os.UserManager;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Provides utilities for Android User related tasks.
+ */
+public final class UserTestingHelper {
+
+    /**
+     * Creates a simple {@link UserInfo}, containing just the given {@code userId}.
+     */
+    @NonNull
+    public static UserInfo newUser(@UserIdInt int userId) {
+        return new UserInfoBuilder(userId).build();
+    }
+
+    /**
+     * Creates a list of {@link UserInfo UserInfos}, each containing just the given user ids.
+     */
+    @NonNull
+    public static List<UserInfo> newUsers(@UserIdInt int... userIds) {
+        return Arrays.stream(userIds)
+                .mapToObj(id -> newUser(id))
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * Creates a {@link UserInfo} with the type explicitly set and with the given {@code userId}.
+     */
+    @NonNull
+    public static UserInfo newSecondaryUser(@UserIdInt int userId) {
+        return new UserInfoBuilder(userId).setType(UserManager.USER_TYPE_FULL_SECONDARY).build();
+    }
+
+    /**
+     * Creates a new guest with the given {@code userId} and proper flags and types set.
+     */
+    @NonNull
+    public static UserInfo newGuestUser(@UserIdInt int userId, boolean ephemeral) {
+        return new UserInfoBuilder(userId).setGuest(true).setEphemeral(ephemeral).build();
+    }
+
+    /**
+     * Creates a new guest with the given {@code userId} and without any flag..
+     */
+    @NonNull
+    public static UserInfo newGuestUser(@UserIdInt int userId) {
+        return new UserInfoBuilder(userId).setGuest(true).build();
+    }
+
+    /**
+     * Gets the default {@link UserInfo#userType} for a guest / regular user.
+     */
+    @NonNull
+    public static String getDefaultUserType(boolean isGuest) {
+        return isGuest ? UserManager.USER_TYPE_FULL_GUEST : UserManager.USER_TYPE_FULL_SECONDARY;
+    }
+
+    /**
+     * Sets the property that defines the maximum number of uses allowed in the device.
+     */
+    public static void setMaxSupportedUsers(int max) {
+        runShellCommand("setprop fw.max_users %d", max);
+    }
+
+    /**
+     * Configures the user to use PIN credentials.
+     */
+    public static void setUserLockCredentials(@UserIdInt int userId, int pin) {
+        runShellCommand("locksettings set-pin %s --user %d ", pin, userId);
+    }
+
+    /**
+     * Clears the user credentials using current PIN.
+     */
+    public static void clearUserLockCredentials(@UserIdInt int userId, int pin) {
+        runShellCommand("locksettings clear --old %d --user %d ", pin, userId);
+    }
+
+    /**
+     * Builder for {@link UserInfo} objects.
+     */
+    public static final class UserInfoBuilder {
+
+        @UserIdInt
+        private final int mUserId;
+
+        @UserInfoFlag
+        private int mFlags;
+
+        @Nullable
+        private String mName;
+
+        @Nullable
+        private String mType;
+
+        private boolean mGuest;
+        private boolean mEphemeral;
+        private boolean mAdmin;
+        private boolean mPreCreated;
+        private boolean mInitialized;
+
+        /**
+         * Default constructor.
+         */
+        public UserInfoBuilder(@UserIdInt int userId) {
+            mUserId = userId;
+        }
+
+        /**
+         * Sets the user name.
+         */
+        @NonNull
+        public UserInfoBuilder setName(@Nullable String name) {
+            mName = name;
+            return this;
+        }
+
+        /**
+         * Sets the user type.
+         */
+        @NonNull
+        public UserInfoBuilder setType(@Nullable String type) {
+            Preconditions.checkState(!mGuest, "cannot set type (" + mType + ") after setting it as "
+                    + "guest");
+            mType = type;
+            return this;
+        }
+
+        /**
+         * Sets whether the user is a guest.
+         */
+        @NonNull
+        public UserInfoBuilder setGuest(boolean guest) {
+            Preconditions.checkState(mType == null, "cannot set guest after setting type (" + mType
+                    + ")");
+            mGuest = guest;
+            return this;
+        }
+
+        /**
+         * Sets the user flags
+         */
+        @NonNull
+        public UserInfoBuilder setFlags(@UserInfoFlag int flags) {
+            mFlags = flags;
+            return this;
+        }
+
+        /**
+         * Sets whether the user is ephemeral.
+         */
+        @NonNull
+        public UserInfoBuilder setEphemeral(boolean ephemeral) {
+            mEphemeral = ephemeral;
+            return this;
+        }
+
+        /**
+         * Sets whether the user is an admin.
+         */
+        @NonNull
+        public UserInfoBuilder setAdmin(boolean admin) {
+            mAdmin = admin;
+            return this;
+        }
+
+        /**
+         * Sets whether the user is an pre-created.
+         */
+        @NonNull
+        public UserInfoBuilder setPreCreated(boolean preCreated) {
+            mPreCreated = preCreated;
+            return this;
+        }
+
+        /**
+         * Sets whether the user is initialized.
+         */
+        @NonNull
+        public UserInfoBuilder setInitialized(boolean initialized) {
+            mInitialized = initialized;
+            return this;
+        }
+
+        /**
+         * Creates a new {@link UserInfo}.
+         */
+        @NonNull
+        public UserInfo build() {
+            int flags = mFlags;
+            if (mEphemeral) {
+                flags |= UserInfo.FLAG_EPHEMERAL;
+            }
+            if (mAdmin) {
+                flags |= UserInfo.FLAG_ADMIN;
+            }
+            if (mInitialized) {
+                flags |= UserInfo.FLAG_INITIALIZED;
+            }
+            if (mGuest) {
+                mType = UserManager.USER_TYPE_FULL_GUEST;
+            }
+            UserInfo info = new UserInfo(mUserId, mName, /* iconPath= */ null, flags, mType);
+            info.preCreated = mPreCreated;
+            return info;
+        }
+    }
+
+    private UserTestingHelper() {
+        throw new UnsupportedOperationException("contains only static methods");
+    }
+}
diff --git a/car-test-lib/src/android/car/test/util/VehicleHalTestingHelper.java b/car-test-lib/src/android/car/test/util/VehicleHalTestingHelper.java
new file mode 100644
index 0000000..5971da8
--- /dev/null
+++ b/car-test-lib/src/android/car/test/util/VehicleHalTestingHelper.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.test.util;
+
+import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropertyChangeMode;
+
+/**
+ * Provides utilities for Vehicle HAL related tasks.
+ */
+public final class VehicleHalTestingHelper {
+
+    /**
+     * Creates an empty config for the given property.
+     */
+    public static VehiclePropConfig newConfig(int prop) {
+        VehiclePropConfig config = new VehiclePropConfig();
+        config.prop = prop;
+        return config;
+    }
+
+    /**
+     * Creates a config for the given property that passes the
+     * {@link com.android.car.hal.VehicleHal.VehicleHal#isPropertySubscribable(VehiclePropConfig)}
+     * criteria.
+     */
+    public static VehiclePropConfig newSubscribableConfig(int prop) {
+        VehiclePropConfig config = newConfig(prop);
+        config.access = VehiclePropertyAccess.READ_WRITE;
+        config.changeMode = VehiclePropertyChangeMode.ON_CHANGE;
+        return config;
+    }
+
+    private VehicleHalTestingHelper() {
+        throw new UnsupportedOperationException("contains only static methods");
+    }
+}
diff --git a/car-test-lib/src/android/car/test/util/Visitor.java b/car-test-lib/src/android/car/test/util/Visitor.java
new file mode 100644
index 0000000..8faf5d0
--- /dev/null
+++ b/car-test-lib/src/android/car/test/util/Visitor.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.test.util;
+
+/**
+ * Visitor design pattern.
+ *
+ * @param <T> type of visited object
+ */
+public interface Visitor<T> {
+
+    /**
+     * Visits an object.
+     */
+    void visit(T t);
+}
diff --git a/car-test-lib/src/android/car/testapi/BlockingUserLifecycleListener.java b/car-test-lib/src/android/car/testapi/BlockingUserLifecycleListener.java
new file mode 100644
index 0000000..5ed572f
--- /dev/null
+++ b/car-test-lib/src/android/car/testapi/BlockingUserLifecycleListener.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.testapi;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.car.user.CarUserManager;
+import android.car.user.CarUserManager.UserLifecycleEvent;
+import android.car.user.CarUserManager.UserLifecycleEventType;
+import android.car.user.CarUserManager.UserLifecycleListener;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * {@link UserLifecycleListener} that blocks until the proper events are received.
+ *
+ * <p>It can be used in 2 "modes":
+ *
+ * <ul>
+ *   <li>{@link #forAnyEvent()}: it blocks (through the {@link #waitForAnyEvent()} call) until any
+ *   any event is received. It doesn't allow any customization (other than
+ *   {@link Builder#setTimeout(long)}).
+ *   <li>{@link #forSpecificEvents()}: it blocks (through the {@link #waitForEvents()} call) until
+ *   all events specified by the {@link Builder} are received.
+ * </ul>
+ */
+public final class BlockingUserLifecycleListener implements UserLifecycleListener {
+
+    private static final String TAG = BlockingUserLifecycleListener.class.getSimpleName();
+
+    private static final long DEFAULT_TIMEOUT_MS = 2_000;
+
+    private final Object mLock = new Object();
+
+    private final CountDownLatch mLatch = new CountDownLatch(1);
+
+    @GuardedBy("mLock")
+    private final List<UserLifecycleEvent> mAllReceivedEvents = new ArrayList<>();
+    @GuardedBy("mLock")
+    private final List<UserLifecycleEvent> mExpectedEventsReceived = new ArrayList<>();
+
+    @UserLifecycleEventType
+    private final List<Integer> mExpectedEventTypes;
+
+    @UserLifecycleEventType
+    private final List<Integer> mExpectedEventTypesLeft;
+
+    @UserIdInt
+    @Nullable
+    private final Integer mForUserId;
+
+    @UserIdInt
+    @Nullable
+    private final Integer mForPreviousUserId;
+
+    private final long mTimeoutMs;
+
+    private BlockingUserLifecycleListener(Builder builder) {
+        mExpectedEventTypes = Collections
+                .unmodifiableList(new ArrayList<>(builder.mExpectedEventTypes));
+        mExpectedEventTypesLeft = builder.mExpectedEventTypes;
+        mTimeoutMs = builder.mTimeoutMs;
+        mForUserId = builder.mForUserId;
+        mForPreviousUserId = builder.mForPreviousUserId;
+        Log.d(TAG, "constructor: " + this);
+    }
+
+    /**
+     * Creates a builder for tests that need to wait for an arbitrary event.
+     */
+    @NonNull
+    public static Builder forAnyEvent() {
+        return new Builder(/* forAnyEvent= */ true);
+    }
+
+    /**
+     * Creates a builder for tests that need to wait for specific events.
+     */
+    @NonNull
+    public static Builder forSpecificEvents() {
+        return new Builder(/* forAnyEvent= */ false);
+    }
+
+    /**
+     * Builder for a customized {@link BlockingUserLifecycleListener} instance.
+     */
+    public static final class Builder {
+        private long mTimeoutMs = DEFAULT_TIMEOUT_MS;
+        private final boolean mForAnyEvent;
+
+        private Builder(boolean forAnyEvent) {
+            mForAnyEvent = forAnyEvent;
+        }
+
+        @UserLifecycleEventType
+        private final List<Integer> mExpectedEventTypes = new ArrayList<>();
+
+        @UserIdInt
+        @Nullable
+        private Integer mForUserId;
+
+        @UserIdInt
+        @Nullable
+        private Integer mForPreviousUserId;
+
+        /**
+         * Sets the timeout.
+         */
+        public Builder setTimeout(long timeoutMs) {
+            mTimeoutMs = timeoutMs;
+            return this;
+        }
+
+        /**
+         * Sets the expected type - once the given event is received, the listener will unblock.
+         *
+         * @throws IllegalStateException if builder is {@link #forAnyEvent}.
+         * @throws IllegalArgumentException if the expected type was already added.
+         */
+        public Builder addExpectedEvent(@UserLifecycleEventType int eventType) {
+            assertNotForAnyEvent();
+            mExpectedEventTypes.add(eventType);
+            return this;
+        }
+
+        /**
+         * Filters received events just for the given user.
+         */
+        public Builder forUser(@UserIdInt int userId) {
+            assertNotForAnyEvent();
+            mForUserId = userId;
+            return this;
+        }
+
+        /**
+         * Filters received events just for the given previous user.
+         */
+        public Builder forPreviousUser(@UserIdInt int userId) {
+            assertNotForAnyEvent();
+            mForPreviousUserId = userId;
+            return this;
+        }
+
+        /**
+         * Builds a new instance.
+         */
+        @NonNull
+        public BlockingUserLifecycleListener build() {
+            return new BlockingUserLifecycleListener(Builder.this);
+        }
+
+        private void assertNotForAnyEvent() {
+            Preconditions.checkState(!mForAnyEvent, "not allowed forAnyEvent()");
+        }
+    }
+
+    @Override
+    public void onEvent(UserLifecycleEvent event) {
+        synchronized (mLock) {
+            Log.d(TAG, "onEvent(): expecting=" + mExpectedEventTypesLeft + ", received=" + event);
+
+            mAllReceivedEvents.add(event);
+
+            if (expectingSpecificUser() && event.getUserId() != mForUserId) {
+                Log.w(TAG, "ignoring event for different user (expecting " + mForUserId + ")");
+                return;
+            }
+
+            if (expectingSpecificPreviousUser()
+                    && event.getPreviousUserId() != mForPreviousUserId) {
+                Log.w(TAG, "ignoring event for different previous user (expecting "
+                        + mForPreviousUserId + ")");
+                return;
+            }
+
+            Integer actualType = event.getEventType();
+            boolean removed = mExpectedEventTypesLeft.remove(actualType);
+            if (removed) {
+                Log.v(TAG, "event removed; still expecting for "
+                        + toString(mExpectedEventTypesLeft));
+                mExpectedEventsReceived.add(event);
+            } else {
+                Log.v(TAG, "event not removed");
+            }
+
+            if (mExpectedEventTypesLeft.isEmpty() && mLatch.getCount() == 1) {
+                Log.d(TAG, "all expected events received, counting down " + mLatch);
+                mLatch.countDown();
+            }
+        }
+    }
+
+    /**
+     * Blocks until any event is received, and returns it.
+     *
+     * @throws IllegalStateException if listener was built using {@link #forSpecificEvents()}.
+     * @throws IllegalStateException if it times out before any event is received.
+     * @throws InterruptedException if interrupted before any event is received.
+     */
+    @Nullable
+    public UserLifecycleEvent waitForAnyEvent() throws InterruptedException {
+        Preconditions.checkState(isForAnyEvent(),
+                "cannot call waitForEvent() when built with expected events");
+        waitForExpectedEvents();
+
+        UserLifecycleEvent event;
+        synchronized (mLock) {
+            event = mAllReceivedEvents.isEmpty() ? null : mAllReceivedEvents.get(0);
+            Log.v(TAG, "waitForAnyEvent(): returning " + event);
+        }
+        return event;
+    }
+
+    /**
+     * Blocks until the events specified in the {@link Builder} are received, and returns them.
+     *
+     * @throws IllegalStateException if listener was built without any call to
+     * {@link Builder#addExpectedEvent(int)} or using {@link #forAnyEvent().
+     * @throws IllegalStateException if it times out before all specified events are received.
+     * @throws InterruptedException if interrupted before all specified events are received.
+     */
+    @NonNull
+    public List<UserLifecycleEvent> waitForEvents() throws InterruptedException {
+        Preconditions.checkState(!isForAnyEvent(),
+                "cannot call waitForEvents() when built without specific expected events");
+        waitForExpectedEvents();
+        List<UserLifecycleEvent> events;
+        synchronized (mLock) {
+            events = mExpectedEventsReceived;
+        }
+        Log.v(TAG, "waitForEvents(): returning " + events);
+        return events;
+    }
+
+    /**
+     * Gets a list with all received events until now.
+     */
+    @NonNull
+    public List<UserLifecycleEvent> getAllReceivedEvents() {
+        Preconditions.checkState(!isForAnyEvent(),
+                "cannot call getAllReceivedEvents() when built without specific expected events");
+        synchronized (mLock) {
+            return Collections.unmodifiableList(new ArrayList<>(mAllReceivedEvents));
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "[" + getClass().getSimpleName() + ": " + stateToString() + "]";
+    }
+
+    @NonNull
+    private String stateToString() {
+        synchronized (mLock) {
+            return "timeout=" + mTimeoutMs + "ms"
+                    + ",expectedEventTypes=" + toString(mExpectedEventTypes)
+                    + ",expectedEventTypesLeft=" + toString(mExpectedEventTypesLeft)
+                    + (expectingSpecificUser() ? ",forUser=" + mForUserId : "")
+                    + (expectingSpecificPreviousUser() ? ",forPrevUser=" + mForPreviousUserId : "")
+                    + ",received=" + mAllReceivedEvents
+                    + ",waiting=" + mExpectedEventTypesLeft;
+        }
+    }
+
+    private void waitForExpectedEvents() throws InterruptedException {
+        if (!mLatch.await(mTimeoutMs, TimeUnit.MILLISECONDS)) {
+            String errorMessage = "did not receive all expected events (" + stateToString() + ")";
+            Log.e(TAG, errorMessage);
+            throw new IllegalStateException(errorMessage);
+        }
+    }
+
+    @NonNull
+    private static String toString(@NonNull List<Integer> eventTypes) {
+        return eventTypes.stream()
+                .map((i) -> CarUserManager.lifecycleEventTypeToString(i))
+                .collect(Collectors.toList())
+                .toString();
+    }
+
+    private boolean isForAnyEvent() {
+        return mExpectedEventTypes.isEmpty();
+    }
+
+    private boolean expectingSpecificUser() {
+        return mForUserId != null;
+    }
+
+    private boolean expectingSpecificPreviousUser() {
+        return mForPreviousUserId != null;
+    }
+}
diff --git a/car-test-lib/src/android/car/testapi/CarAppFocusController.java b/car-test-lib/src/android/car/testapi/CarAppFocusController.java
new file mode 100644
index 0000000..9aafc65
--- /dev/null
+++ b/car-test-lib/src/android/car/testapi/CarAppFocusController.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.testapi;
+
+import android.os.Looper;
+
+/** Used to manipulate properties of the CarAppFocusManager in unit tests. */
+public interface CarAppFocusController {
+    /** Set what the UID of the "foreground" app is */
+    void setForegroundUid(int uid);
+
+    /** Set what the PID of the "foreground" app is */
+    void setForegroundPid(int pid);
+
+    /** Resets the foreground UID such that all UIDs are considered to be foreground */
+    void resetForegroundUid();
+
+    /** Resets the foreground PID such that all PIDs are considered to be foreground */
+    void resetForegroundPid();
+
+    /** Gets the {@link android.os.Looper} for the internal handler for the service */
+    Looper getLooper();
+}
diff --git a/car-test-lib/src/android/car/testapi/CarMockitoHelper.java b/car-test-lib/src/android/car/testapi/CarMockitoHelper.java
new file mode 100644
index 0000000..13c5361
--- /dev/null
+++ b/car-test-lib/src/android/car/testapi/CarMockitoHelper.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.testapi;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.isA;
+import static org.mockito.Mockito.doAnswer;
+
+import android.annotation.NonNull;
+import android.car.Car;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * Provides common Mockito calls for Car-specific classes.
+ */
+public final class CarMockitoHelper {
+
+    private static final String TAG = CarMockitoHelper.class.getSimpleName();
+
+    /**
+     * Mocks a call to {@link Car#handleRemoteExceptionFromCarService(RemoteException, Object)} so
+     * it returns the passed as 2nd argument.
+     */
+    public static void mockHandleRemoteExceptionFromCarServiceWithDefaultValue(
+            @NonNull Car car) {
+        doAnswer((invocation) -> {
+            Object returnValue = invocation.getArguments()[1];
+            Log.v(TAG, "mocking handleRemoteExceptionFromCarService(): " + returnValue);
+            return returnValue;
+        }).when(car).handleRemoteExceptionFromCarService(isA(RemoteException.class), any());
+    }
+
+    private CarMockitoHelper() {
+        throw new UnsupportedOperationException("contains only static methods");
+    }
+}
diff --git a/car-test-lib/src/android/car/testapi/CarNavigationStatusController.java b/car-test-lib/src/android/car/testapi/CarNavigationStatusController.java
new file mode 100644
index 0000000..bb8324f
--- /dev/null
+++ b/car-test-lib/src/android/car/testapi/CarNavigationStatusController.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.testapi;
+
+import android.os.Bundle;
+
+/**
+ * Controller to manipulate and verify {@link android.car.navigation.CarNavigationStatusManager} in
+ * unit tests.
+ */
+public interface CarNavigationStatusController {
+    /** Returns the last state sent to the manager. */
+    Bundle getCurrentNavState();
+
+    /** Sets the current internal cluster state to use a cluster that can accept custom images. */
+    void setCustomImageClusterInfo(
+            int minIntervalMillis,
+            int imageWidth,
+            int imageHeight,
+            int imageColorDepthBits);
+
+    /** Sets the current internal cluster state to use a cluster that can accept image codes. */
+    void setImageCodeClusterInfo(int minIntervalMillis);
+}
diff --git a/car-test-lib/src/android/car/testapi/CarProjectionController.java b/car-test-lib/src/android/car/testapi/CarProjectionController.java
index 19d8aeb..45cd155 100644
--- a/car-test-lib/src/android/car/testapi/CarProjectionController.java
+++ b/car-test-lib/src/android/car/testapi/CarProjectionController.java
@@ -18,12 +18,12 @@
 
 import android.car.CarProjectionManager;
 import android.car.projection.ProjectionOptions;
-import android.net.wifi.WifiConfiguration;
+import android.net.wifi.SoftApConfiguration;
 
 /** Controller to change behavior of {@link CarProjectionManager} */
 public interface CarProjectionController {
-    /** Set WifiConfiguration for wireless projection or null to simulate failure to start AP */
-    void setWifiConfiguration(WifiConfiguration wifiConfiguration);
+    /** Set SoftApConfiguration for wireless projection or null to simulate failure to start AP */
+    void setSoftApConfiguration(SoftApConfiguration softApConfiguration);
 
     /**
      * Sets {@link ProjectionOptions} object returns by
diff --git a/car-test-lib/src/android/car/testapi/CarUxRestrictionsController.java b/car-test-lib/src/android/car/testapi/CarUxRestrictionsController.java
new file mode 100644
index 0000000..0881f11
--- /dev/null
+++ b/car-test-lib/src/android/car/testapi/CarUxRestrictionsController.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.testapi;
+
+import android.os.RemoteException;
+
+/**
+ * Used to set the current set of UX restrictions being enforced in the test.
+ */
+public interface CarUxRestrictionsController {
+    /**
+     * Sets the current set of UX restrictions.
+     *
+     * @param restrictions is a bitmask of UX restrictions as defined in {@link
+     * android.car.drivingstate.CarUxRestrictions}
+     * @throws RemoteException when the underlying service fails to set the given restrictions.
+     */
+    void setUxRestrictions(int restrictions) throws RemoteException;
+
+    /**
+     * Clears all UX restrictions.
+     *
+     * @throws RemoteException when the underlying service fails to clear the restrictions.
+     */
+    void clearUxRestrictions() throws RemoteException;
+
+    /**
+     * Returns {@code true} if a {@link
+     * android.car.drivingstate.CarUxRestrictionsManager.OnUxRestrictionsChangedListener} is
+     * registered with the manager, otherwise returns {@code false}.
+     */
+    boolean isListenerRegistered();
+}
diff --git a/car-test-lib/src/android/car/testapi/FakeAppFocusService.java b/car-test-lib/src/android/car/testapi/FakeAppFocusService.java
new file mode 100644
index 0000000..df97525
--- /dev/null
+++ b/car-test-lib/src/android/car/testapi/FakeAppFocusService.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.testapi;
+
+import android.car.CarAppFocusManager;
+import android.car.IAppFocus;
+import android.content.Context;
+import android.os.Looper;
+
+import com.android.car.AppFocusService;
+
+/**
+ * Fake service that is used by {@link FakeCar} to provide an implementation of {@link IAppFocus}
+ * to allow the use of {@link CarAppFocusManager} in unit tests.
+ */
+public class FakeAppFocusService extends AppFocusService implements CarAppFocusController {
+    FakeSystemActivityMonitoringService mSystemActivityMonitoringService;
+
+    private FakeAppFocusService(
+            Context context,
+            FakeSystemActivityMonitoringService fakeSystemActivityMonitoringService) {
+        super(context, fakeSystemActivityMonitoringService);
+        mSystemActivityMonitoringService = fakeSystemActivityMonitoringService;
+    }
+
+    public FakeAppFocusService(Context context) {
+        this(context, new FakeSystemActivityMonitoringService(context));
+        super.init();
+    }
+
+    //************************* CarAppFocusController implementation ******************************/
+
+    @Override
+    public synchronized void setForegroundUid(int uid) {
+        mSystemActivityMonitoringService.setForegroundUid(uid);
+    }
+
+    @Override
+    public synchronized void setForegroundPid(int pid) {
+        mSystemActivityMonitoringService.setForegroundPid(pid);
+    }
+
+    @Override
+    public synchronized void resetForegroundUid() {
+        mSystemActivityMonitoringService.resetForegroundUid();
+    }
+
+    @Override
+    public synchronized void resetForegroundPid() {
+        mSystemActivityMonitoringService.resetForegroundPid();
+    }
+
+    @Override
+    public Looper getLooper() {
+        return super.getLooper();
+    }
+}
diff --git a/car-test-lib/src/android/car/testapi/FakeCar.java b/car-test-lib/src/android/car/testapi/FakeCar.java
index 47757be..1bb4d57 100644
--- a/car-test-lib/src/android/car/testapi/FakeCar.java
+++ b/car-test-lib/src/android/car/testapi/FakeCar.java
@@ -17,20 +17,16 @@
 package android.car.testapi;
 
 import android.car.Car;
-import android.car.IAppFocus;
 import android.car.ICar;
 import android.car.ICarBluetooth;
 import android.car.cluster.IInstrumentClusterManagerService;
-import android.car.cluster.renderer.IInstrumentClusterNavigation;
 import android.car.content.pm.ICarPackageManager;
 import android.car.diagnostic.ICarDiagnostic;
 import android.car.drivingstate.ICarDrivingState;
-import android.car.drivingstate.ICarUxRestrictionsManager;
 import android.car.hardware.power.ICarPower;
 import android.car.media.ICarAudio;
 import android.car.settings.ICarConfigurationManager;
 import android.car.storagemonitoring.ICarStorageMonitoring;
-import android.car.vms.IVmsSubscriberService;
 import android.content.Context;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -39,6 +35,9 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Collections;
+import java.util.List;
+
 /*
     The idea behind this class is that we can fake-out interfaces between Car*Manager and
     Car Service.  Effectively creating a fake version of Car Service that can run under Robolectric
@@ -106,28 +105,54 @@
         return mService.mCarProjection;
     }
 
+    /**
+     * Returns the test controller to change the behavior of the underlying
+     * {@link android.car.CarAppFocusManager}
+     */
+    public CarAppFocusController getAppFocusController() {
+        return mService.mAppFocus;
+    }
+
+    /**
+     * Returns the test controller to change the behavior of as well as query the underlying {@link
+     * android.car.navigation.CarNavigationStatusManager}.
+     */
+    public CarNavigationStatusController getCarNavigationStatusController() {
+        return mService.mInstrumentClusterNavigation;
+    }
+
+    /**
+     * Returns a test controller that can modify and query the underlying service for the {@link
+     * android.car.drivingstate.CarUxRestrictionsManager}.
+     */
+    public CarUxRestrictionsController getCarUxRestrictionController() {
+        return mService.mCarUxRestrictionService;
+    }
+
     private static class FakeCarService extends ICar.Stub {
         @Mock ICarAudio.Stub mCarAudio;
-        @Mock IAppFocus.Stub mAppFocus;
         @Mock ICarPackageManager.Stub mCarPackageManager;
         @Mock ICarDiagnostic.Stub mCarDiagnostic;
         @Mock ICarPower.Stub mCarPower;
-        @Mock IInstrumentClusterNavigation.Stub mClusterNavigation;
         @Mock IInstrumentClusterManagerService.Stub mClusterService;
-        @Mock IVmsSubscriberService.Stub mVmsSubscriberService;
         @Mock ICarBluetooth.Stub mCarBluetooth;
         @Mock ICarStorageMonitoring.Stub mCarStorageMonitoring;
         @Mock ICarDrivingState.Stub mCarDrivingState;
-        @Mock ICarUxRestrictionsManager.Stub mCarUxRestriction;
         @Mock ICarConfigurationManager.Stub mCarConfigurationManager;
 
+        private final FakeAppFocusService mAppFocus;
         private final FakeCarPropertyService mCarProperty;
         private final FakeCarProjectionService mCarProjection;
+        private final FakeInstrumentClusterNavigation mInstrumentClusterNavigation;
+        private final FakeCarUxRestrictionsService mCarUxRestrictionService;
 
         FakeCarService(Context context) {
             MockitoAnnotations.initMocks(this);
+            mAppFocus = new FakeAppFocusService(context);
             mCarProperty = new FakeCarPropertyService();
             mCarProjection = new FakeCarProjectionService(context);
+            mInstrumentClusterNavigation = new FakeInstrumentClusterNavigation();
+            mCarUxRestrictionService = new FakeCarUxRestrictionsService();
         }
 
         @Override
@@ -136,12 +161,24 @@
         }
 
         @Override
-        public void setUserLockStatus(int userHandle, int unlocked) throws RemoteException {
+        public void onUserLifecycleEvent(int eventType, long timestampMs, int fromUserId,
+                int toUserId) {
             // Nothing to do yet.
         }
 
         @Override
-        public void onSwitchUser(int userHandle) throws RemoteException {
+        public void onFirstUserUnlocked(int userId, long timestampMs, long duration,
+                int halResponseTime) {
+            // Nothing to do yet.
+        }
+
+        @Override
+        public void getInitialUserInfo(int requestType, int timeoutMs, IBinder binder) {
+            // Nothing to do yet.
+        }
+
+        @Override
+        public void setInitialUser(int userId) {
             // Nothing to do yet.
         }
 
@@ -166,13 +203,11 @@
                 case Car.VENDOR_EXTENSION_SERVICE:
                     return mCarProperty;
                 case Car.CAR_NAVIGATION_SERVICE:
-                    return mClusterNavigation;
+                    return mInstrumentClusterNavigation;
                 case Car.CAR_INSTRUMENT_CLUSTER_SERVICE:
                     return mClusterService;
                 case Car.PROJECTION_SERVICE:
                     return mCarProjection;
-                case Car.VMS_SUBSCRIBER_SERVICE:
-                    return mVmsSubscriberService;
                 case Car.BLUETOOTH_SERVICE:
                     return mCarBluetooth;
                 case Car.STORAGE_MONITORING_SERVICE:
@@ -180,7 +215,7 @@
                 case Car.CAR_DRIVING_STATE_SERVICE:
                     return mCarDrivingState;
                 case Car.CAR_UX_RESTRICTION_SERVICE:
-                    return mCarUxRestriction;
+                    return mCarUxRestrictionService;
                 case Car.CAR_CONFIGURATION_SERVICE:
                     return mCarConfigurationManager;
                 default:
@@ -193,6 +228,41 @@
         public int getCarConnectionType() throws RemoteException {
             return Car.CONNECTION_TYPE_EMBEDDED;
         }
+
+        @Override
+        public boolean isFeatureEnabled(String featureName) {
+            return false;
+        }
+
+        @Override
+        public int enableFeature(String featureName) {
+            return Car.FEATURE_REQUEST_SUCCESS;
+        }
+
+        @Override
+        public int disableFeature(String featureName) {
+            return Car.FEATURE_REQUEST_SUCCESS;
+        }
+
+        @Override
+        public List<String> getAllEnabledFeatures() {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public List<String> getAllPendingDisabledFeatures() {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public List<String> getAllPendingEnabledFeatures() {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public String getCarManagerClassForFeature(String featureName) {
+            return null;
+        }
     }
 
 }
diff --git a/car-test-lib/src/android/car/testapi/FakeCarProjectionService.java b/car-test-lib/src/android/car/testapi/FakeCarProjectionService.java
index 0408f5d..275ae1c 100644
--- a/car-test-lib/src/android/car/testapi/FakeCarProjectionService.java
+++ b/car-test-lib/src/android/car/testapi/FakeCarProjectionService.java
@@ -28,7 +28,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
-import android.net.wifi.WifiConfiguration;
+import android.net.wifi.SoftApConfiguration;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Message;
@@ -51,7 +51,7 @@
 
     private final Context mContext;
 
-    private WifiConfiguration mWifiConfiguration;
+    private SoftApConfiguration mSoftApConfiguration;
     private Messenger mApMessenger;
     private IBinder mApBinder;
     private List<ICarProjectionStatusListener> mStatusListeners = new ArrayList<>();
@@ -115,9 +115,9 @@
         mApBinder = binder;
 
         Message message = Message.obtain();
-        if (mWifiConfiguration != null) {
+        if (mSoftApConfiguration != null) {
             message.what = CarProjectionManager.PROJECTION_AP_STARTED;
-            message.obj = mWifiConfiguration;
+            message.obj = mSoftApConfiguration;
         } else {
             message.what = CarProjectionManager.PROJECTION_AP_FAILED;
             message.arg1 = ProjectionAccessPointCallback.ERROR_GENERIC;
@@ -179,8 +179,8 @@
     }
 
     @Override
-    public void setWifiConfiguration(WifiConfiguration wifiConfiguration) {
-        mWifiConfiguration = wifiConfiguration;
+    public void setSoftApConfiguration(SoftApConfiguration softApConfiguration) {
+        mSoftApConfiguration = softApConfiguration;
     }
 
     @Override
diff --git a/car-test-lib/src/android/car/testapi/FakeCarPropertyService.java b/car-test-lib/src/android/car/testapi/FakeCarPropertyService.java
index a1c8bb3..0060302 100644
--- a/car-test-lib/src/android/car/testapi/FakeCarPropertyService.java
+++ b/car-test-lib/src/android/car/testapi/FakeCarPropertyService.java
@@ -92,7 +92,8 @@
     }
 
     @Override
-    public void setProperty(CarPropertyValue prop) throws RemoteException {
+    public void setProperty(CarPropertyValue prop, ICarPropertyEventListener listener)
+            throws RemoteException {
         mValues.put(PropKey.of(prop), prop);
         mValuesSet.add(prop);
         sendEvent(prop);
diff --git a/car-test-lib/src/android/car/testapi/FakeCarUxRestrictionsService.java b/car-test-lib/src/android/car/testapi/FakeCarUxRestrictionsService.java
new file mode 100644
index 0000000..6100e93
--- /dev/null
+++ b/car-test-lib/src/android/car/testapi/FakeCarUxRestrictionsService.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.testapi;
+
+import static android.car.drivingstate.CarUxRestrictions.UX_RESTRICTIONS_BASELINE;
+
+import android.car.drivingstate.CarUxRestrictions;
+import android.car.drivingstate.CarUxRestrictionsConfiguration;
+import android.car.drivingstate.ICarUxRestrictionsChangeListener;
+import android.car.drivingstate.ICarUxRestrictionsManager;
+import android.os.IRemoteCallback;
+import android.os.RemoteException;
+import android.os.SystemClock;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A fake implementation of {@link ICarUxRestrictionsManager.Stub} to facilitate the use of {@link
+ * android.car.drivingstate.CarUxRestrictionsManager} in external unit tests.
+ *
+ * @hide
+ */
+public class FakeCarUxRestrictionsService extends ICarUxRestrictionsManager.Stub implements
+        CarUxRestrictionsController {
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private CarUxRestrictions mCarUxRestrictions;
+    @GuardedBy("mLock")
+    private ICarUxRestrictionsChangeListener mListener;
+
+    @GuardedBy("mLock")
+    private String mMode = "baseline";
+
+    private static CarUxRestrictions createCarUxRestrictions(int activeRestrictions) {
+        return new CarUxRestrictions.Builder(
+                false, /* requires driving distraction optimization */
+                activeRestrictions,
+                SystemClock.elapsedRealtimeNanos())
+                .build();
+    }
+
+    FakeCarUxRestrictionsService() {
+        synchronized (mLock) {
+            mCarUxRestrictions = createCarUxRestrictions(UX_RESTRICTIONS_BASELINE);
+        }
+    }
+
+    @Override
+    public void registerUxRestrictionsChangeListener(
+            ICarUxRestrictionsChangeListener listener, int displayId) {
+        synchronized (mLock) {
+            this.mListener = listener;
+        }
+    }
+
+    @Override
+    public void unregisterUxRestrictionsChangeListener(ICarUxRestrictionsChangeListener listener) {
+        synchronized (mLock) {
+            this.mListener = null;
+        }
+    }
+
+    @Override
+    public CarUxRestrictions getCurrentUxRestrictions(int displayId) {
+        synchronized (mLock) {
+            return mCarUxRestrictions;
+        }
+    }
+
+    @Override
+    public List<CarUxRestrictionsConfiguration> getStagedConfigs() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public List<CarUxRestrictionsConfiguration> getConfigs() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public boolean setRestrictionMode(String mode) throws RemoteException {
+        synchronized (mLock) {
+            mMode = mode;
+        }
+        return true;
+    }
+
+    @Override
+    public String getRestrictionMode() throws RemoteException {
+        synchronized (mLock) {
+            return mMode;
+        }
+    }
+
+    @Override
+    public void reportVirtualDisplayToPhysicalDisplay(IRemoteCallback binder, int virtualDisplayId,
+            int physicalDisplayId) throws RemoteException {
+
+    }
+
+    @Override
+    public int getMappedPhysicalDisplayOfVirtualDisplay(int displayId) throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public boolean saveUxRestrictionsConfigurationForNextBoot(
+            List<CarUxRestrictionsConfiguration> config) {
+        return true;
+    }
+
+    /**************************** CarUxRestrictionsController impl ********************************/
+
+    @Override
+    public void setUxRestrictions(int restrictions) throws RemoteException {
+        synchronized (mLock) {
+            mCarUxRestrictions = createCarUxRestrictions(restrictions);
+            if (isListenerRegistered()) {
+                mListener.onUxRestrictionsChanged(mCarUxRestrictions);
+            }
+        }
+    }
+
+    @Override
+    public void clearUxRestrictions() throws RemoteException {
+        setUxRestrictions(0);
+    }
+
+    @Override
+    public boolean isListenerRegistered() {
+        synchronized (mLock) {
+            return mListener != null;
+        }
+    }
+
+}
diff --git a/car-test-lib/src/android/car/testapi/FakeInstrumentClusterNavigation.java b/car-test-lib/src/android/car/testapi/FakeInstrumentClusterNavigation.java
new file mode 100644
index 0000000..d427028
--- /dev/null
+++ b/car-test-lib/src/android/car/testapi/FakeInstrumentClusterNavigation.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.testapi;
+
+import android.car.cluster.renderer.IInstrumentClusterNavigation;
+import android.car.navigation.CarNavigationInstrumentCluster;
+import android.os.Bundle;
+
+/**
+ * Fake implementation of {@link IInstrumentClusterNavigation} used by FakeCar.
+ *
+ * @hide
+ */
+public class FakeInstrumentClusterNavigation extends IInstrumentClusterNavigation.Stub
+        implements CarNavigationStatusController {
+    private static final int DEFAULT_MIN_UPDATE_INTERVAL_MILLIS = 1000;
+
+    private Bundle mCurrentNavigationState;
+    private CarNavigationInstrumentCluster mCarNavigationInstrumentCluster =
+            CarNavigationInstrumentCluster.createCluster(DEFAULT_MIN_UPDATE_INTERVAL_MILLIS);
+
+    @Override
+    public void onNavigationStateChanged(Bundle bundle) {
+        mCurrentNavigationState = bundle;
+    }
+
+    @Override
+    public CarNavigationInstrumentCluster getInstrumentClusterInfo() {
+        return mCarNavigationInstrumentCluster;
+    }
+
+
+    //********************** CarNavigationStatusController implementation *************************/
+    @Override
+    public Bundle getCurrentNavState() {
+        return mCurrentNavigationState;
+    }
+
+    @Override
+    public void setImageCodeClusterInfo(int minIntervalMillis) {
+        mCarNavigationInstrumentCluster =
+                CarNavigationInstrumentCluster.createCluster(minIntervalMillis);
+    }
+
+    @Override
+    public void setCustomImageClusterInfo(
+            int minIntervalMillis,
+            int imageWidth,
+            int imageHeight,
+            int imageColorDepthBits) {
+        mCarNavigationInstrumentCluster =
+                CarNavigationInstrumentCluster
+                        .createCustomImageCluster(
+                                minIntervalMillis, imageWidth, imageHeight, imageColorDepthBits);
+    }
+}
diff --git a/car-test-lib/src/android/car/testapi/FakeSystemActivityMonitoringService.java b/car-test-lib/src/android/car/testapi/FakeSystemActivityMonitoringService.java
new file mode 100644
index 0000000..045ec4e
--- /dev/null
+++ b/car-test-lib/src/android/car/testapi/FakeSystemActivityMonitoringService.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.testapi;
+
+import android.content.Context;
+
+import com.android.car.SystemActivityMonitoringService;
+
+/**
+ * This is fake implementation of the SystemActivityMonitoringService which is used by the
+ * {@link com.android.car.AppFocusService}. A faked version is needed for offline unit tests so that
+ * the foreground app ID can be changed manually.
+ *
+ * @hide
+ */
+public class FakeSystemActivityMonitoringService extends SystemActivityMonitoringService {
+    private static final int DEFAULT_FOREGROUND_ID = -1;
+
+    private int mForegroundPid = DEFAULT_FOREGROUND_ID;
+    private int mForegroundUid = DEFAULT_FOREGROUND_ID;
+
+    FakeSystemActivityMonitoringService(Context context) {
+         super(context);
+    }
+
+    @Override
+    public boolean isInForeground(int pid, int uid) {
+        return (mForegroundPid == DEFAULT_FOREGROUND_ID || mForegroundPid == pid)
+                && (mForegroundUid == DEFAULT_FOREGROUND_ID || mForegroundUid == uid);
+    }
+
+    void setForegroundPid(int pid) {
+        mForegroundPid = pid;
+    }
+
+    void setForegroundUid(int uid) {
+        mForegroundUid = uid;
+    }
+
+    void resetForegroundPid() {
+        mForegroundPid = DEFAULT_FOREGROUND_ID;
+    }
+
+    void resetForegroundUid() {
+        mForegroundUid = DEFAULT_FOREGROUND_ID;
+    }
+}
diff --git a/car-usb-handler/AndroidManifest.xml b/car-usb-handler/AndroidManifest.xml
index caa93bd..8eac7a0 100644
--- a/car-usb-handler/AndroidManifest.xml
+++ b/car-usb-handler/AndroidManifest.xml
@@ -14,22 +14,39 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-        package="android.car.usb.handler">
-    <uses-sdk android:minSdkVersion="25" />
-    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
-    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
-    <uses-permission android:name="android.permission.MANAGE_USB" />
-    <uses-permission android:name="android.permission.MANAGE_USERS" />
-    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
-    <application android:label="@string/app_name" android:icon="@drawable/ic_launcher"
-                 android:directBootAware="true">
+          xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+          package="android.car.usb.handler">
+    <uses-sdk
+        android:minSdkVersion="25"
+        android:targetSdkVersion="29"/>
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+    <uses-permission android:name="android.permission.MANAGE_USB"/>
+    <!-- Needed for Build.getSerial(), which is used to send a unique number for serial, per HUIG. -->
+    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+    <uses-permission android:name="android.permission.MANAGE_USERS"/>
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
+
+    <!-- "queries" to specify what car-usb-handler will query for due to  Android 11's
+         package visibility update. -->
+    <queries>
+        <intent>
+            <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
+        </intent>
+    </queries>
+
+    <application
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:directBootAware="true">
         <activity android:name=".UsbHostManagementActivity"
                   android:theme="@android:style/Theme.DeviceDefault.Dialog"
                   android:launchMode="standard">
             <meta-data
                 android:name="distractionOptimized"
-                android:value="true" />
+                android:value="true"/>
         </activity>
         <service android:name=".BootUsbService"
                  android:exported="false"
@@ -38,7 +55,7 @@
         <receiver android:name=".BootUsbScanner"
                   android:directBootAware="true">
             <intent-filter>
-                <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
+                <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED"/>
             </intent-filter>
         </receiver>
     </application>
diff --git a/car-usb-handler/res/values-ne/strings.xml b/car-usb-handler/res/values-ne/strings.xml
index a181597..806be7c 100644
--- a/car-usb-handler/res/values-ne/strings.xml
+++ b/car-usb-handler/res/values-ne/strings.xml
@@ -18,8 +18,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="6963366455471441257">"USB ह्यान्ड्लर"</string>
     <string name="usb_saved_devices" msgid="2829442070749964872">"सुरक्षित गरिएका यन्त्रहरू"</string>
-    <string name="usb_pref_delete_title" msgid="3885061814853467483">"USB यन्त्रको व्यवस्थापन गर्ने अनुप्रयोग हटाउनुहोस्‌"</string>
-    <string name="usb_pref_delete_message" msgid="5849493572520646218">"तपाईंले %1$s को व्यवस्थापन गर्ने पूर्वनिर्धारित अनुप्रयोग मेट्न खोज्नुभएकै हो?"</string>
+    <string name="usb_pref_delete_title" msgid="3885061814853467483">"USB यन्त्रको व्यवस्थापन गर्ने एप हटाउनुहोस्‌"</string>
+    <string name="usb_pref_delete_message" msgid="5849493572520646218">"तपाईंले %1$s को व्यवस्थापन गर्ने पूर्वनिर्धारित एप मेट्न खोज्नुभएकै हो?"</string>
     <string name="usb_pref_delete_yes" msgid="7803356145103146036">"हो"</string>
     <string name="usb_pref_delete_cancel" msgid="5999791462730255929">"रद्द गर्नुहोस्"</string>
     <string name="usb_resolving_handlers" msgid="1943100136172948686">"समर्थित ह्यान्ड्लरहरू प्राप्त गर्दै"</string>
diff --git a/car-usb-handler/res/values-te/strings.xml b/car-usb-handler/res/values-te/strings.xml
index a8dd520..25cd088 100644
--- a/car-usb-handler/res/values-te/strings.xml
+++ b/car-usb-handler/res/values-te/strings.xml
@@ -19,9 +19,7 @@
     <string name="app_name" msgid="6963366455471441257">"USB హ్యాండ్లర్‌"</string>
     <string name="usb_saved_devices" msgid="2829442070749964872">"సేవ్ చేసిన పరికరాలు"</string>
     <string name="usb_pref_delete_title" msgid="3885061814853467483">"USB పరికర కొరకు హాండీలింగ్ యాప్‌ని తొలగించండి"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for usb_pref_delete_message (5849493572520646218) -->
-    <skip />
+    <string name="usb_pref_delete_message" msgid="5849493572520646218">"%1$s‌ను ఆటోమేటిక్‌గా హ్యాండిల్ చేసే యాప్‌ను ఖచ్చితంగా తొలగించాలని మీరు అనుకుంటున్నారా?"</string>
     <string name="usb_pref_delete_yes" msgid="7803356145103146036">"అవును"</string>
     <string name="usb_pref_delete_cancel" msgid="5999791462730255929">"రద్దు చేయి"</string>
     <string name="usb_resolving_handlers" msgid="1943100136172948686">"మద్దతుగల హ్యాండ్లర్‌లను పొందడం"</string>
diff --git a/car-usb-handler/res/values-ur/strings.xml b/car-usb-handler/res/values-ur/strings.xml
index 0fe5553..109dd4c 100644
--- a/car-usb-handler/res/values-ur/strings.xml
+++ b/car-usb-handler/res/values-ur/strings.xml
@@ -19,9 +19,7 @@
     <string name="app_name" msgid="6963366455471441257">"USB ہینڈلر"</string>
     <string name="usb_saved_devices" msgid="2829442070749964872">"محفوظ کردہ آلات"</string>
     <string name="usb_pref_delete_title" msgid="3885061814853467483">"USB آلہ کو ہینڈل کرنے والی اپپ کو ہٹائیں"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for usb_pref_delete_message (5849493572520646218) -->
-    <skip />
+    <string name="usb_pref_delete_message" msgid="5849493572520646218">"کیا آپ واقعی %1$s اپپ کی ڈیفالٹ ہینڈلنگ کو حذف کرنا چاہتے ہیں؟"</string>
     <string name="usb_pref_delete_yes" msgid="7803356145103146036">"ہاں"</string>
     <string name="usb_pref_delete_cancel" msgid="5999791462730255929">"منسوخ کریں"</string>
     <string name="usb_resolving_handlers" msgid="1943100136172948686">"تعاون یافتہ ہینڈلرز حاصل کر رہے ہیں"</string>
diff --git a/car-usb-handler/src/android/car/usb/handler/AoapInterface.java b/car-usb-handler/src/android/car/usb/handler/AoapInterface.java
index 21aa64e..3b7fbfe 100644
--- a/car-usb-handler/src/android/car/usb/handler/AoapInterface.java
+++ b/car-usb-handler/src/android/car/usb/handler/AoapInterface.java
@@ -22,6 +22,10 @@
 import android.util.Pair;
 
 import java.io.IOException;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -97,7 +101,7 @@
     /**
      * Accessory write timeout.
      */
-    public static final int AOAP_TIMEOUT_MS = 2000;
+    public static final int AOAP_TIMEOUT_MS = 50;
 
     /**
      * Set of VID:PID pairs blacklisted through config_AoapIncompatibleDeviceIds. Only
@@ -107,14 +111,30 @@
 
     private static final String TAG = AoapInterface.class.getSimpleName();
 
+    @Retention(RetentionPolicy.SOURCE)
+    @Target({ ElementType.FIELD, ElementType.PARAMETER })
+    public @interface Direction {}
+
+    @Direction
+    public static final int WRITE = 1;
+    @Direction
+    public static final int READ = 2;
+
+
     public static int getProtocol(UsbDeviceConnection conn) {
         byte[] buffer = new byte[2];
-        int len = conn.controlTransfer(
-                UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_VENDOR,
-                ACCESSORY_GET_PROTOCOL, 0, 0, buffer, 2, AOAP_TIMEOUT_MS);
-        if (len != 2) {
+
+        int len = transfer(conn, READ, ACCESSORY_GET_PROTOCOL, 0, buffer, buffer.length);
+        if (len == 0) {
             return -1;
         }
+        if (len < 0) {
+            Log.w(TAG, "getProtocol() failed. Retrying...");
+            len = transfer(conn, READ, ACCESSORY_GET_PROTOCOL, 0, buffer, buffer.length);
+            if (len != buffer.length) {
+                return -1;
+            }
+        }
         return (buffer[1] << 8) | buffer[0];
     }
 
@@ -125,21 +145,22 @@
     public static void sendString(UsbDeviceConnection conn, int index, String string)
             throws IOException {
         byte[] buffer = (string + "\0").getBytes();
-        int len = conn.controlTransfer(
-                UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
-                ACCESSORY_SEND_STRING, 0, index,
-                buffer, buffer.length, AOAP_TIMEOUT_MS);
+        int len = transfer(conn, WRITE, ACCESSORY_SEND_STRING, index, buffer,
+                buffer.length);
         if (len != buffer.length) {
-            throw new IOException("Failed to send string " + index + ": \"" + string + "\"");
+            Log.w(TAG, "sendString for " + index + ":" + string + " failed. Retrying...");
+            len = transfer(conn, WRITE, ACCESSORY_SEND_STRING, index, buffer,
+                buffer.length);
+            if (len != buffer.length) {
+                throw new IOException("Failed to send string " + index + ": \"" + string + "\"");
+            }
         } else {
             Log.i(TAG, "Sent string " + index + ": \"" + string + "\"");
         }
     }
 
     public static void sendAoapStart(UsbDeviceConnection conn) throws IOException {
-        int len = conn.controlTransfer(
-                UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
-                ACCESSORY_START, 0, 0, null, 0, AOAP_TIMEOUT_MS);
+        int len = transfer(conn, WRITE, ACCESSORY_START, 0, null, 0);
         if (len < 0) {
             throw new IOException("Control transfer for accessory start failed: " + len);
         }
@@ -181,4 +202,22 @@
         return vid == USB_ACCESSORY_VENDOR_ID
                 && USB_ACCESSORY_MODE_PRODUCT_ID.contains(pid);
     }
+
+    private static int transfer(UsbDeviceConnection conn, @Direction int direction, int string,
+            int index, byte[] buffer, int length) {
+        int directionConstant;
+        switch (direction) {
+            case READ:
+                directionConstant = UsbConstants.USB_DIR_IN;
+                break;
+            case WRITE:
+                directionConstant = UsbConstants.USB_DIR_OUT;
+                break;
+            default:
+                Log.w(TAG, "Unknown direction for transfer: " + direction);
+                return -1;
+        }
+        return conn.controlTransfer(directionConstant | UsbConstants.USB_TYPE_VENDOR, string, 0,
+            index, buffer, length, AOAP_TIMEOUT_MS);
+    }
 }
diff --git a/car-usb-handler/src/android/car/usb/handler/BootUsbScanner.java b/car-usb-handler/src/android/car/usb/handler/BootUsbScanner.java
index ac7a6a5..9f2cd2a 100644
--- a/car-usb-handler/src/android/car/usb/handler/BootUsbScanner.java
+++ b/car-usb-handler/src/android/car/usb/handler/BootUsbScanner.java
@@ -6,6 +6,7 @@
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbManager;
 import android.os.UserHandle;
+import android.os.UserManager;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -15,10 +16,11 @@
 
     @Override
     public void onReceive(Context context, Intent intent) {
-        // Only start the service if we are the system user. We cannot use the singleUser tag in the
-        // manifest for <receiver>s, so there is no way to avoid us registering this receiver as the
-        // non system user. Just return immediately if we are not.
-        if (context.getUserId() != UserHandle.USER_SYSTEM) {
+        // Only start the service for the non-system user, or for the system user if it is running
+        // as a "real" user. This ensures the service is started only once and is started even on a
+        // foreground user switch.
+        if (context.getUserId() == UserHandle.USER_SYSTEM
+                && !UserManager.isHeadlessSystemUserMode()) {
             return;
         }
         // we defer this processing to BootUsbService so that we are very quick to process
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 5d29f54..c98b902 100644
--- a/car-usb-handler/src/android/car/usb/handler/BootUsbService.java
+++ b/car-usb-handler/src/android/car/usb/handler/BootUsbService.java
@@ -15,17 +15,12 @@
  */
 package android.car.usb.handler;
 
-import static android.content.Intent.ACTION_USER_SWITCHED;
-
-import android.app.ActivityManager;
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.Service;
-import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbManager;
 import android.os.Binder;
@@ -46,14 +41,6 @@
     static final String USB_DEVICE_LIST_KEY = "usb_device_list";
 
     private ArrayList<UsbDevice> mDeviceList;
-    private boolean mReceiverRegistered = false;
-    private final BroadcastReceiver mUserSwitchBroadcastReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            processDevices();
-            unregisterUserSwitchReceiver();
-        }
-    };
 
     @Override
     public Binder onBind(Intent intent) {
@@ -81,27 +68,13 @@
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
         mDeviceList = intent.getParcelableArrayListExtra(USB_DEVICE_LIST_KEY);
-        // If the current user is still the system user, wait until the non system user becomes the
-        // current/foreground user. Otherwise, we can go ahead and start processing the USB devices
-        // immediately.
-        if (ActivityManager.getCurrentUser() == UserHandle.USER_SYSTEM) {
-            Log.d(TAG, "Current user is still the system user, waiting for user switch");
-            registerUserSwitchReceiver();
-        } else {
-            processDevices();
-        }
-
+        processDevices();
         return START_NOT_STICKY;
     }
 
-    @Override
-    public void onDestroy() {
-        unregisterUserSwitchReceiver();
-    }
-
     private void processDevices() {
-        Log.d(TAG, "Processing connected USB devices and starting handlers");
         for (UsbDevice device : mDeviceList) {
+            Log.d(TAG, "Processing device: " + device.getProductName());
             handle(this, device);
         }
         stopSelf();
@@ -114,18 +87,4 @@
         manageDevice.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
         context.startActivityAsUser(manageDevice, UserHandle.CURRENT);
     }
-
-    private void registerUserSwitchReceiver() {
-        if (!mReceiverRegistered) {
-            registerReceiver(mUserSwitchBroadcastReceiver, new IntentFilter(ACTION_USER_SWITCHED));
-            mReceiverRegistered = true;
-        }
-    }
-
-    private void unregisterUserSwitchReceiver() {
-        if (mReceiverRegistered) {
-            unregisterReceiver(mUserSwitchBroadcastReceiver);
-            mReceiverRegistered = false;
-        }
-    }
 }
diff --git a/car-usb-handler/src/android/car/usb/handler/UsbDeviceHandlerResolver.java b/car-usb-handler/src/android/car/usb/handler/UsbDeviceHandlerResolver.java
index c562c72..a1be7dd 100644
--- a/car-usb-handler/src/android/car/usb/handler/UsbDeviceHandlerResolver.java
+++ b/car-usb-handler/src/android/car/usb/handler/UsbDeviceHandlerResolver.java
@@ -30,6 +30,7 @@
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbDeviceConnection;
 import android.hardware.usb.UsbManager;
+import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
@@ -41,6 +42,8 @@
 import org.xmlpull.v1.XmlPullParser;
 
 import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -68,18 +71,16 @@
     private final PackageManager mPackageManager;
     private final UsbDeviceHandlerResolverCallback mDeviceCallback;
     private final Context mContext;
-    private final HandlerThread mHandlerThread;
-    private final UsbDeviceResolverHandler mHandler;
     private final AoapServiceManager mAoapServiceManager;
+    private HandlerThread mHandlerThread;
+    private UsbDeviceResolverHandler mHandler;
 
     public UsbDeviceHandlerResolver(UsbManager manager, Context context,
             UsbDeviceHandlerResolverCallback deviceListener) {
         mUsbManager = manager;
         mContext = context;
         mDeviceCallback = deviceListener;
-        mHandlerThread = new HandlerThread(TAG);
-        mHandlerThread.start();
-        mHandler = new UsbDeviceResolverHandler(mHandlerThread.getLooper());
+        createHandlerThread();
         mPackageManager = context.getPackageManager();
         mAoapServiceManager = new AoapServiceManager(mContext.getApplicationContext());
     }
@@ -101,9 +102,22 @@
     }
 
     /**
+     * Listener for failed {@code startAosp} command.
+     *
+     * <p>If {@code startAosp} fails, the device could be left in a inconsistent state, that's why
+     * we go back to USB enumeration, instead of just repeating the command.
+     */
+    public interface StartAoapFailureListener {
+
+        /** Called if startAoap fails. */
+        void onFailure();
+    }
+
+    /**
      * Dispatches device to component.
      */
-    public boolean dispatch(UsbDevice device, ComponentName component, boolean inAoap) {
+    public boolean dispatch(UsbDevice device, ComponentName component, boolean inAoap,
+            StartAoapFailureListener failureListener) {
         if (LOCAL_LOGD) {
             Log.d(TAG, "dispatch: " + device + " component: " + component + " inAoap: " + inAoap);
         }
@@ -125,10 +139,20 @@
                         packageMatches(activityInfo, intent.getAction(), device, true);
 
                 if (filter != null) {
+                    if (!mHandlerThread.isAlive()) {
+                        // Start a new thread. Used only when startAoap fails, and we need to
+                        // re-enumerate device in order to try again.
+                        createHandlerThread();
+                    }
                     mHandlerThread.getThreadHandler().post(() -> {
                         if (mAoapServiceManager.canSwitchDeviceToAoap(device,
                                 ComponentName.unflattenFromString(filter.mAoapService))) {
-                            requestAoapSwitch(device, filter);
+                            try {
+                                requestAoapSwitch(device, filter);
+                            } catch (IOException e) {
+                                Log.w(TAG, "Start AOAP command failed:" + e);
+                                failureListener.onFailure();
+                            }
                         } else {
                             Log.i(TAG, "Ignore AOAP switch for device " + device
                                     + " handled by " + filter.mAoapService);
@@ -148,6 +172,12 @@
         return true;
     }
 
+    private void createHandlerThread() {
+        mHandlerThread = new HandlerThread(TAG);
+        mHandlerThread.start();
+        mHandler = new UsbDeviceResolverHandler(mHandlerThread.getLooper());
+    }
+
     private static Intent createDeviceAttachedIntent(UsbDevice device) {
         Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
         intent.putExtra(UsbManager.EXTRA_DEVICE, device);
@@ -189,13 +219,15 @@
         return settings;
     }
 
-    private void requestAoapSwitch(UsbDevice device, UsbDeviceFilter filter) {
+    private void requestAoapSwitch(UsbDevice device, UsbDeviceFilter filter) throws IOException {
         UsbDeviceConnection connection = UsbUtil.openConnection(mUsbManager, device);
         if (connection == null) {
             Log.e(TAG, "Failed to connect to usb device.");
             return;
         }
+
         try {
+            String hashedSerial =  getHashed(Build.getSerial());
             UsbUtil.sendAoapAccessoryStart(
                     connection,
                     filter.mAoapManufacturer,
@@ -203,11 +235,19 @@
                     filter.mAoapDescription,
                     filter.mAoapVersion,
                     filter.mAoapUri,
-                    filter.mAoapSerial);
-        } catch (IOException e) {
-            Log.w(TAG, "Failed to switch device into AOAP mode", e);
+                    hashedSerial);
+        } finally {
+            connection.close();
         }
-        connection.close();
+    }
+
+    private String getHashed(String serial) {
+        try {
+            return MessageDigest.getInstance("MD5").digest(serial.getBytes()).toString();
+        } catch (NoSuchAlgorithmException e) {
+            Log.w(TAG, "could not create MD5 for serial number: " + serial);
+            return Integer.toString(serial.hashCode());
+        }
     }
 
     private void deviceProbingComplete(UsbDevice device, List<UsbDeviceSettings> settings) {
diff --git a/car-usb-handler/src/android/car/usb/handler/UsbHostController.java b/car-usb-handler/src/android/car/usb/handler/UsbHostController.java
index 3fcb67b..0da71ac 100644
--- a/car-usb-handler/src/android/car/usb/handler/UsbHostController.java
+++ b/car-usb-handler/src/android/car/usb/handler/UsbHostController.java
@@ -30,6 +30,7 @@
 import com.android.internal.annotations.GuardedBy;
 
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 
 /**
@@ -300,6 +301,12 @@
 
         private static final int DEVICE_REMOVE_TIMEOUT_MS = 500;
 
+        // Used to get the device that we are trying to connect to, if mActiveDevice is removed and
+        // startAoap fails afterwards. Used during USB enumeration when retrying to startAoap when
+        // there are multiple devices attached.
+        private int mLastDeviceId = 0;
+        private int mStartAoapRetries = 1;
+
         private UsbHostControllerHandler(Looper looper) {
             super(looper);
         }
@@ -308,6 +315,24 @@
             sendEmptyMessageDelayed(MSG_DEVICE_REMOVED, DEVICE_REMOVE_TIMEOUT_MS);
         }
 
+        private void onFailure() {
+            if (mStartAoapRetries == 0) {
+                Log.w(TAG, "Reached maximum retry count for startAoap. Giving up Aoa handshake.");
+                return;
+            }
+            mStartAoapRetries--;
+
+            Log.d(TAG, "Restarting USB enumeration.");
+            Iterator<UsbDevice> deviceIterator = mUsbManager.getDeviceList().values().iterator();
+            while (deviceIterator.hasNext()) {
+                UsbDevice device = deviceIterator.next();
+                if (mLastDeviceId == device.getDeviceId()) {
+                    processDevice(device);
+                    return;
+                }
+            }
+        }
+
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
@@ -318,8 +343,10 @@
                     UsbHostControllerHandlerDispatchData data =
                             (UsbHostControllerHandlerDispatchData) msg.obj;
                     UsbDevice device = data.getUsbDevice();
+                    mLastDeviceId = device.getDeviceId();
                     UsbDeviceSettings settings = data.getUsbDeviceSettings();
-                    if (!mUsbResolver.dispatch(device, settings.getHandler(), settings.getAoap())) {
+                    if (!mUsbResolver.dispatch(device, settings.getHandler(), settings.getAoap(),
+                            this::onFailure)) {
                         if (data.mRetries > 0) {
                             --data.mRetries;
                             Message nextMessage = Message.obtain(msg);
diff --git a/car_product/build/car.mk b/car_product/build/car.mk
index 7c03328..f602d3a 100644
--- a/car_product/build/car.mk
+++ b/car_product/build/car.mk
@@ -16,16 +16,19 @@
 
 # Common make file for all car builds
 
-BOARD_PLAT_PUBLIC_SEPOLICY_DIR += packages/services/Car/car_product/sepolicy/public
-BOARD_PLAT_PRIVATE_SEPOLICY_DIR += packages/services/Car/car_product/sepolicy/private
+PRODUCT_PUBLIC_SEPOLICY_DIRS += packages/services/Car/car_product/sepolicy/public
+PRODUCT_PRIVATE_SEPOLICY_DIRS += packages/services/Car/car_product/sepolicy/private
 
 PRODUCT_PACKAGES += \
     Bluetooth \
     CarDeveloperOptions \
+    CompanionDeviceSupport \
     OneTimeInitializer \
     Provision \
+    StatementService \
     SystemUpdater
 
+
 PRODUCT_PACKAGES += \
     clatd \
     clatd.conf \
@@ -37,10 +40,11 @@
 PRODUCT_PACKAGES += \
     DefaultStorageMonitoringCompanionApp \
     EmbeddedKitchenSinkApp \
-    VmsPublisherClientSample \
-    VmsSubscriberClientSample \
     DirectRenderingCluster \
     GarageModeTestApp \
+    ExperimentalCarService \
+    RotaryPlayground \
+
 
 # SEPolicy for test apps / services
 BOARD_SEPOLICY_DIRS += packages/services/Car/car_product/sepolicy/test
@@ -59,15 +63,6 @@
 
 # Overlay for Google network and fused location providers
 $(call inherit-product, device/sample/products/location_overlay.mk)
-$(call inherit-product-if-exists, frameworks/base/data/fonts/fonts.mk)
-$(call inherit-product-if-exists, external/google-fonts/dancing-script/fonts.mk)
-$(call inherit-product-if-exists, external/google-fonts/carrois-gothic-sc/fonts.mk)
-$(call inherit-product-if-exists, external/google-fonts/coming-soon/fonts.mk)
-$(call inherit-product-if-exists, external/google-fonts/cutive-mono/fonts.mk)
-$(call inherit-product-if-exists, external/noto-fonts/fonts.mk)
-$(call inherit-product-if-exists, external/roboto-fonts/fonts.mk)
-$(call inherit-product-if-exists, external/hyphenation-patterns/patterns.mk)
-$(call inherit-product-if-exists, frameworks/base/data/keyboards/keyboards.mk)
 $(call inherit-product-if-exists, frameworks/webview/chromium/chromium.mk)
 $(call inherit-product, packages/services/Car/car_product/build/car_base.mk)
 
@@ -76,6 +71,8 @@
 PRODUCT_DEVICE := generic
 PRODUCT_NAME := generic_car_no_telephony
 
+PRODUCT_IS_AUTOMOTIVE := true
+
 PRODUCT_PROPERTY_OVERRIDES := \
     ro.config.ringtone=Girtab.ogg \
     ro.config.notification_sound=Tethys.ogg \
@@ -108,30 +105,102 @@
     libcar-framework-service-jni \
 
 # System Server components
+# Order is important: if X depends on Y, then Y should precede X on the list.
 PRODUCT_SYSTEM_SERVER_JARS += car-frameworks-service
 
 # Boot animation
 PRODUCT_COPY_FILES += \
     packages/services/Car/car_product/bootanimations/bootanimation-832.zip:system/media/bootanimation.zip
 
-PRODUCT_COPY_FILES += \
-    packages/services/Car/car_product/init/init.car.rc:system/etc/init/init.car.rc
+PRODUCT_LOCALES := \
+    en_US \
+    af_ZA \
+    am_ET \
+    ar_EG ar_XB \
+    as_IN \
+    az_AZ \
+    be_BY \
+    bg_BG \
+    bn_BD \
+    bs_BA \
+    ca_ES \
+    cs_CZ \
+    da_DK \
+    de_DE \
+    el_GR \
+    en_AU en_CA en_GB en_IN en_XA \
+    es_ES es_US \
+    et_EE \
+    eu_ES \
+    fa_IR \
+    fi_FI \
+    fil_PH \
+    fr_CA fr_FR \
+    gl_ES \
+    gu_IN \
+    hi_IN \
+    hr_HR \
+    hu_HU \
+    hy_AM \
+    id_ID \
+    is_IS \
+    it_IT \
+    iw_IL \
+    ja_JP \
+    ka_GE \
+    kk_KZ \
+    km_KH km_MH \
+    kn_IN \
+    ko_KR \
+    ky_KG \
+    lo_LA \
+    lv_LV \
+    lt_LT \
+    mk_MK \
+    ml_IN \
+    mn_MN \
+    mr_IN \
+    ms_MY \
+    my_MM \
+    ne_NP \
+    nl_NL \
+    no_NO \
+    or_IN \
+    pa_IN \
+    pl_PL \
+    pt_BR pt_PT \
+    ro_RO \
+    ru_RU \
+    si_LK \
+    sk_SK \
+    sl_SI \
+    sq_AL \
+    sr_RS \
+    sv_SE \
+    sw_TZ \
+    ta_IN \
+    te_IN \
+    th_TH \
+    tr_TR \
+    uk_UA \
+    ur_PK \
+    uz_UZ \
+    vi_VN \
+    zh_CN zh_HK zh_TW \
+    zu_ZA
 
-PRODUCT_LOCALES := en_US af_ZA am_ET ar_EG bg_BG bn_BD ca_ES cs_CZ da_DK de_DE el_GR en_AU en_GB en_IN es_ES es_US et_EE eu_ES fa_IR fi_FI fr_CA fr_FR gl_ES hi_IN hr_HR hu_HU hy_AM in_ID is_IS it_IT iw_IL ja_JP ka_GE km_KH ko_KR ky_KG lo_LA lt_LT lv_LV km_MH kn_IN mn_MN ml_IN mk_MK mr_IN ms_MY my_MM ne_NP nb_NO nl_NL pl_PL pt_BR pt_PT ro_RO ru_RU si_LK sk_SK sl_SI sr_RS sv_SE sw_TZ ta_IN te_IN th_TH tl_PH tr_TR uk_UA vi_VN zh_CN zh_HK zh_TW zu_ZA en_XA ar_XB
-
-# should add to BOOT_JARS only once
-ifeq (,$(INCLUDED_ANDROID_CAR_TO_PRODUCT_BOOT_JARS))
 PRODUCT_BOOT_JARS += \
     android.car
 
 PRODUCT_HIDDENAPI_STUBS := \
-    android.car-stubs
+    android.car-stubs-dex
 
 PRODUCT_HIDDENAPI_STUBS_SYSTEM := \
-    android.car-system-stubs
+    android.car-system-stubs-dex
 
 PRODUCT_HIDDENAPI_STUBS_TEST := \
-    android.car-test-stubs
+    android.car-test-stubs-dex
 
-INCLUDED_ANDROID_CAR_TO_PRODUCT_BOOT_JARS := yes
-endif
+# Disable Prime Shader Cache in SurfaceFlinger to make it available faster
+PRODUCT_PROPERTY_OVERRIDES += \
+    service.sf.prime_shader_cache=0
diff --git a/car_product/build/car_base.mk b/car_product/build/car_base.mk
index 72feacf..a1b6534 100644
--- a/car_product/build/car_base.mk
+++ b/car_product/build/car_base.mk
@@ -20,6 +20,7 @@
 PRODUCT_PACKAGE_OVERLAYS += packages/services/Car/car_product/overlay
 
 PRODUCT_PACKAGES += \
+    com.android.wifi \
     Home \
     BasicDreams \
     CaptivePortalLogin \
@@ -51,7 +52,6 @@
     libspeexresampler \
     libvariablespeed \
     libwebrtc_audio_preprocessing \
-    wifi-service \
     A2dpSinkService \
     PackageInstaller \
     car-bugreportd \
@@ -69,10 +69,19 @@
 
 # Default permission grant exceptions
 PRODUCT_COPY_FILES += \
-    packages/services/Car/car_product/build/default-car-permissions.xml:system/etc/default-permissions/default-car-permissions.xml
+    packages/services/Car/car_product/build/default-car-permissions.xml:system/etc/default-permissions/default-car-permissions.xml \
+    packages/services/Car/car_product/build/preinstalled-packages-product-car-base.xml:system/etc/sysconfig/preinstalled-packages-product-car-base.xml
 
 $(call inherit-product, $(SRC_TARGET_DIR)/product/core_minimal.mk)
 
 # Default dex optimization configurations
 PRODUCT_PROPERTY_OVERRIDES += \
      pm.dexopt.disable_bg_dexopt=true
+
+# Required init rc files for car
+PRODUCT_COPY_FILES += \
+    packages/services/Car/car_product/init/init.bootstat.rc:system/etc/init/init.bootstat.car.rc \
+    packages/services/Car/car_product/init/init.car.rc:system/etc/init/init.car.rc
+
+# Enable car watchdog
+include packages/services/Car/watchdog/product/carwatchdog.mk
diff --git a/car_product/build/preinstalled-packages-product-car-base.xml b/car_product/build/preinstalled-packages-product-car-base.xml
new file mode 100644
index 0000000..0ed7b7f
--- /dev/null
+++ b/car_product/build/preinstalled-packages-product-car-base.xml
@@ -0,0 +1,311 @@
+<?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
+  -->
+<!-- System packages to preinstall on all automotive devices, per user type.
+     OEMs must provide they own as well, listing their specific apps (like launcher, settings, etc...)
+     Documentation at frameworks/base/data/etc/preinstalled-packages-platform.xml
+-->
+<config>
+<!--
+  Here the apps will have SYSTEM only.
+-->
+    <install-in-user-type package="com.android.experimentalcar">
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+<!--
+  Apps that need to run on SYSTEM and evaluated by package owner.
+  Here the apps will have FULL and SYSTEM.
+-->
+    <install-in-user-type package="android">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+    <install-in-user-type package="android.car.cluster">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.car">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.car.frameworkpackagestubs">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!-- Needed for Projected on Embedded so it receives LOCKED_BOOT_COMPLETED immediately,
+      otherwise projection wouldn't launch on startup -->
+    <install-in-user-type package="android.car.usb.handler">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!-- Need to upload collected bugreports even if full user was deleted or changed -->
+    <install-in-user-type package="com.android.car.bugreport">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!-- Not sure, leave for security purpose -->
+    <install-in-user-type package="com.android.keychain">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!-- Provides Settings. Secure for SYSTEM, which are used in places such as SUW -->
+    <install-in-user-type package="com.android.providers.settings">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!--
+      CompanionDeviceSupport app needs to run on SYSTEM for the Trusted Device feature to work.
+      It needs to run in the foreground user for other companion app features like calendar sync
+      and notifications bridging
+    -->
+    <install-in-user-type package="com.android.car.companiondevicesupport">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!-- Not sure, leave for security purpose -->
+    <install-in-user-type package="com.android.se">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!-- Needed by the Location service during system bootup -->
+    <install-in-user-type package="com.android.location.fused">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!-- Resides on a device's /system partition to verify certain upgrade scenarios -->
+    <install-in-user-type package="com.android.cts.ctsshim">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!-- Resides on a device's /system partition to verify certain upgrade scenarios -->
+    <install-in-user-type package="com.android.cts.priv.ctsshim">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!-- Contains exported and single user service -->
+    <install-in-user-type package="com.android.ons">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!-- Needs this packages during bootup, otherwise system won't boot -->
+    <install-in-user-type package="com.android.wifi.resources">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!-- Required StorageManagerService to bind to the ExternalStorageService -->
+    <install-in-user-type package="com.android.providers.media.module">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!-- Needs to run on system user otherwise cannot find available device -->
+    <install-in-user-type package="com.android.bluetooth">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!-- Required to create application com.android.phone.PhoneApp -->
+    <install-in-user-type package="com.android.telephony.resources">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!-- Required to find provider info for telephony for com.android.phone.PhoneApp -->
+    <install-in-user-type package="com.android.providers.telephony">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!-- Required to use adb -->
+    <install-in-user-type package="com.android.shell">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!-- Required to get current location; check map -->
+    <install-in-user-type package="com.android.server.telecom">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!-- Required for compatibility -->
+    <install-in-user-type package="com.android.statementservice">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!-- Failed to find provider info for downloads error if not installed for system user -->
+    <install-in-user-type package="com.android.providers.downloads">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!-- Failed to find provider info for calendar error if not installed for system user -->
+    <install-in-user-type package="com.android.providers.calendar">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+    <!-- Failed to pass CTS if not installed for system user -->
+    <install-in-user-type package="com.android.car.ui.sharedlibrary">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
+<!--
+  Apps that do need to run on SYSTEM and evaluated by package owner.
+  Here the apps will have FULL only.
+-->
+    <install-in-user-type package="com.android.htmlviewer">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.inputdevices">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.soundpicker">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.captiveportallogin">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.google.android.car.hideapps">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.stk">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.dreams.phototable">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.carrierdefaultapp">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.soundrecorder">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.bips">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.settings.intelligence">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.egg">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.simappdialog">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.dreams.basic">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.companiondevicemanager">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.bluetoothmidiservice">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.statementservice">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.backupconfirm">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+   <install-in-user-type package="com.android.calllogbackup">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.providers.blockednumber">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.providers.contacts">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.providers.downloads.ui">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.providers.media">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.providers.userdictionary">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.voicetrigger">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.internal.display.cutout.emulation.hole">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.internal.display.cutout.emulation.waterfall">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="android.auto_generated_rro_product__">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="android.auto_generated_rro_vendor__">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.car.calendar">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.wifi.inprocess.overlay.car">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.cellbroadcastreceiver">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.networkstack.permissionconfig">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.storagemanager">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.carrierconfig">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.certinstaller">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.pacprocessor">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.proxyhandler">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.vpndialogs">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.sharedstoragebackup">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.externalstorage">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+    <install-in-user-type package="com.android.hotspot2.osulogin">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+</config>
diff --git a/car_product/init/init.car.rc b/car_product/init/init.car.rc
index 0bcfe96..d255942 100644
--- a/car_product/init/init.car.rc
+++ b/car_product/init/init.car.rc
@@ -1,3 +1,16 @@
 # Insert car-specific startup services here
 on post-fs-data
     mkdir /data/system/car 0700 system system
+
+# A property to enable EVS services conditionally
+on property:persist.automotive.evs.mode=0
+    # stop EVS and automotive display services
+    stop automotive_display
+    stop evs_driver
+    stop evs_manager
+
+on property:persist.automotive.evs.mode=1
+    # start EVS and automotive display services
+    start automotive_display
+    start evs_driver
+    start evs_manager
diff --git a/car_product/occupant_awareness/OccupantAwareness.mk b/car_product/occupant_awareness/OccupantAwareness.mk
new file mode 100644
index 0000000..75f5fb2
--- /dev/null
+++ b/car_product/occupant_awareness/OccupantAwareness.mk
@@ -0,0 +1,3 @@
+# Occupant Awareness SELinux policy variable definitions
+PRODUCT_PUBLIC_SEPOLICY_DIRS += packages/services/Car/car_product/occupant_awareness/sepolicy/public
+PRODUCT_PRIVATE_SEPOLICY_DIRS += packages/services/Car/car_product/occupant_awareness/sepolicy/private
diff --git a/car_product/occupant_awareness/sepolicy/file_contexts b/car_product/occupant_awareness/sepolicy/file_contexts
new file mode 100644
index 0000000..09a2859
--- /dev/null
+++ b/car_product/occupant_awareness/sepolicy/file_contexts
@@ -0,0 +1 @@
+/vendor/bin/hw/android\.hardware\.automotive\.occupant_awareness@1\.0-service u:object_r:hal_occupant_awareness_default_exec:s0
diff --git a/car_product/occupant_awareness/sepolicy/hal_occupant_awareness_default.te b/car_product/occupant_awareness/sepolicy/hal_occupant_awareness_default.te
new file mode 100644
index 0000000..ca4cf7d
--- /dev/null
+++ b/car_product/occupant_awareness/sepolicy/hal_occupant_awareness_default.te
@@ -0,0 +1,5 @@
+type hal_occupant_awareness_default, domain;
+hal_server_domain(hal_occupant_awareness_default, hal_occupant_awareness)
+
+type hal_occupant_awareness_default_exec, exec_type, vendor_file_type, file_type;
+init_daemon_domain(hal_occupant_awareness_default)
diff --git a/car_product/occupant_awareness/sepolicy/private/service_contexts b/car_product/occupant_awareness/sepolicy/private/service_contexts
new file mode 100644
index 0000000..3796d53
--- /dev/null
+++ b/car_product/occupant_awareness/sepolicy/private/service_contexts
@@ -0,0 +1 @@
+android.hardware.automotive.occupant_awareness.IOccupantAwareness/default u:object_r:hal_occupant_awareness_service:s0
diff --git a/car_product/occupant_awareness/sepolicy/public/attributes b/car_product/occupant_awareness/sepolicy/public/attributes
new file mode 100644
index 0000000..64373ba
--- /dev/null
+++ b/car_product/occupant_awareness/sepolicy/public/attributes
@@ -0,0 +1,7 @@
+# hal_attribute(occupant_awareness);
+attribute hal_occupant_awareness;
+expandattribute hal_occupant_awareness true;
+attribute hal_occupant_awareness_client;
+expandattribute hal_occupant_awareness_client true;
+attribute hal_occupant_awareness_server;
+expandattribute hal_occupant_awareness_server false;
diff --git a/car_product/occupant_awareness/sepolicy/public/hal_occupant_awareness.te b/car_product/occupant_awareness/sepolicy/public/hal_occupant_awareness.te
new file mode 100644
index 0000000..bcc522f
--- /dev/null
+++ b/car_product/occupant_awareness/sepolicy/public/hal_occupant_awareness.te
@@ -0,0 +1,8 @@
+# HwBinder IPC from client to server, and callbacks
+binder_call(hal_occupant_awareness_client, hal_occupant_awareness_server)
+binder_call(hal_occupant_awareness_server, hal_occupant_awareness_client)
+add_service(hal_occupant_awareness_server, hal_occupant_awareness_service)
+
+binder_use(hal_occupant_awareness_server)
+
+allow hal_occupant_awareness_client hal_occupant_awareness_service:service_manager find;
diff --git a/car_product/occupant_awareness/sepolicy/public/service.te b/car_product/occupant_awareness/sepolicy/public/service.te
new file mode 100644
index 0000000..a2ff448
--- /dev/null
+++ b/car_product/occupant_awareness/sepolicy/public/service.te
@@ -0,0 +1 @@
+type hal_occupant_awareness_service, vendor_service, service_manager_type;
diff --git a/car_product/overlay/frameworks/base/core/res/res/drawable-night/item_background.xml b/car_product/overlay/frameworks/base/core/res/res/drawable-night/item_background.xml
new file mode 100644
index 0000000..cfab8bd
--- /dev/null
+++ b/car_product/overlay/frameworks/base/core/res/res/drawable-night/item_background.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_focused="true">
+        <ripple android:color="#2371cd">
+            <item android:id="@android:id/mask">
+                <color android:color="@android:color/white" />
+            </item>
+        </ripple>
+    </item>
+    <item>
+        <ripple android:color="?android:attr/colorControlHighlight">
+            <item android:id="@android:id/mask">
+                <color android:color="@android:color/white" />
+            </item>
+        </ripple>
+    </item>
+</selector>
diff --git a/car_product/overlay/frameworks/base/core/res/res/drawable/item_background.xml b/car_product/overlay/frameworks/base/core/res/res/drawable/item_background.xml
new file mode 100644
index 0000000..b95802f
--- /dev/null
+++ b/car_product/overlay/frameworks/base/core/res/res/drawable/item_background.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_focused="true">
+        <ripple android:color="#4b9eff">
+            <item android:id="@android:id/mask">
+                <color android:color="@android:color/white" />
+            </item>
+        </ripple>
+    </item>
+    <item>
+        <ripple android:color="?android:attr/colorControlHighlight">
+            <item android:id="@android:id/mask">
+                <color android:color="@android:color/white" />
+            </item>
+        </ripple>
+    </item>
+</selector>
diff --git a/car_product/overlay/frameworks/base/core/res/res/layout/alert_dialog_button_bar_material.xml b/car_product/overlay/frameworks/base/core/res/res/layout/alert_dialog_button_bar_material.xml
deleted file mode 100644
index 0df7215..0000000
--- a/car_product/overlay/frameworks/base/core/res/res/layout/alert_dialog_button_bar_material.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-            android:id="@*android:id/buttonPanel"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:scrollbarAlwaysDrawVerticalTrack="true"
-            android:scrollIndicators="top|bottom"
-            android:fillViewport="true"
-            style="?android:attr/buttonBarStyle">
-    <com.android.internal.widget.ButtonBarLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:paddingStart="@*android:dimen/button_bar_layout_start_padding"
-        android:paddingEnd="@*android:dimen/button_bar_layout_end_padding"
-        android:paddingTop="@*android:dimen/button_bar_layout_top_padding"
-        android:layoutDirection="locale"
-        android:orientation="horizontal"
-        android:gravity="center_vertical">
-
-        <Button
-            android:id="@*android:id/button3"
-            style="@*android:style/CarAction1"
-            android:background="@*android:drawable/car_dialog_button_background"
-            android:layout_marginEnd="@*android:dimen/button_end_margin"
-            android:layout_width="wrap_content"
-            android:layout_height="@*android:dimen/button_layout_height" />
-
-        <Button
-            android:id="@*android:id/button2"
-            style="@*android:style/CarAction1"
-            android:background="@*android:drawable/car_dialog_button_background"
-            android:layout_marginEnd="@*android:dimen/button_end_margin"
-            android:layout_width="wrap_content"
-            android:layout_height="@*android:dimen/button_layout_height" />
-
-        <Button
-            android:id="@*android:id/button1"
-            style="@*android:style/CarAction1"
-            android:background="@*android:drawable/car_dialog_button_background"
-            android:layout_width="wrap_content"
-            android:layout_height="@*android:dimen/button_layout_height" />
-        <Space
-            android:id="@*android:id/spacer"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:visibility="invisible" />
-    </com.android.internal.widget.ButtonBarLayout>
-</ScrollView>
diff --git a/car_product/overlay/frameworks/base/core/res/res/layout/alert_dialog_material.xml b/car_product/overlay/frameworks/base/core/res/res/layout/alert_dialog_material.xml
deleted file mode 100644
index 7452026..0000000
--- a/car_product/overlay/frameworks/base/core/res/res/layout/alert_dialog_material.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<com.android.internal.widget.AlertDialogLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@*android:id/parentPanel"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:gravity="start|top"
-    android:orientation="vertical">
-
-    <include layout="@*android:layout/alert_dialog_title_material" />
-
-    <FrameLayout
-        android:id="@*android:id/contentPanel"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:minHeight="48dp">
-
-        <ScrollView
-            android:id="@*android:id/scrollView"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:clipToPadding="false">
-
-            <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="vertical">
-
-                <Space
-                    android:id="@*android:id/textSpacerNoTitle"
-                    android:visibility="gone"
-                    android:layout_width="match_parent"
-                    android:layout_height="@*android:dimen/dialog_no_title_padding_top" />
-
-                <TextView
-                    android:id="@*android:id/message"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_marginStart="@*android:dimen/text_view_start_margin"
-                    android:layout_marginEnd="@*android:dimen/text_view_end_margin"
-                    style="@*android:style/CarBody2"/>
-
-                <!-- we don't need this spacer, but the id needs to be here for compatibility -->
-                <Space
-                    android:id="@*android:id/textSpacerNoButtons"
-                    android:visibility="gone"
-                    android:layout_width="match_parent"
-                    android:layout_height="0dp" />
-            </LinearLayout>
-        </ScrollView>
-    </FrameLayout>
-
-    <FrameLayout
-        android:id="@*android:id/customPanel"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:minHeight="48dp">
-
-        <FrameLayout
-            android:id="@*android:id/custom"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
-    </FrameLayout>
-
-    <include
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        layout="@*android:layout/alert_dialog_button_bar_material" />
-</com.android.internal.widget.AlertDialogLayout>
diff --git a/car_product/overlay/frameworks/base/core/res/res/layout/alert_dialog_title_material.xml b/car_product/overlay/frameworks/base/core/res/res/layout/alert_dialog_title_material.xml
deleted file mode 100644
index 92bd7d0..0000000
--- a/car_product/overlay/frameworks/base/core/res/res/layout/alert_dialog_title_material.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:id="@*android:id/topPanel"
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content"
-              android:gravity="center_vertical"
-              android:orientation="vertical">
-
-    <!-- If the client uses a customTitle, it will be added here. -->
-
-    <RelativeLayout
-        android:id="@*android:id/title_template"
-        android:layout_width="match_parent"
-        android:layout_height="@*android:dimen/car_card_header_height"
-        android:orientation="horizontal">
-
-        <ImageView
-            android:id="@*android:id/icon"
-            android:layout_width="@*android:dimen/image_size"
-            android:layout_height="@*android:dimen/image_size"
-            android:layout_marginStart="@*android:dimen/image_margin_start"
-            android:layout_alignParentStart="true"
-            android:layout_centerVertical="true"
-            android:scaleType="fitCenter"
-            android:src="@null" />
-
-        <com.android.internal.widget.DialogTitle
-            android:id="@*android:id/alertTitle"
-            android:maxLines="1"
-            android:ellipsize="none"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_toEndOf="@*android:id/icon"
-            android:textAlignment="viewStart"
-            android:layout_centerVertical="true"
-            android:layout_marginStart="@*android:dimen/text_view_start_margin"
-            android:layout_marginEnd="@*android:dimen/text_view_end_margin"
-            style="?android:attr/windowTitleStyle" />
-    </RelativeLayout>
-
-    <Space
-        android:id="@*android:id/titleDividerNoCustom"
-        android:visibility="gone"
-        android:layout_width="match_parent"
-        android:layout_height="0dp" />
-</LinearLayout>
diff --git a/car_product/overlay/frameworks/base/core/res/res/layout/notification_material_action.xml b/car_product/overlay/frameworks/base/core/res/res/layout/notification_material_action.xml
deleted file mode 100644
index 5604049..0000000
--- a/car_product/overlay/frameworks/base/core/res/res/layout/notification_material_action.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2017 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-<Button
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@android:style/Widget.Material.Light.Button.Borderless.Small"
-    android:id="@*android:id/action0"
-    android:layout_width="wrap_content"
-    android:layout_height="match_parent"
-    android:layout_gravity="center"
-    android:fontFamily="sans-serif"
-    android:gravity="start|center_vertical"
-    android:layout_marginStart="0dp"
-    android:textColor="@*android:color/notification_default_color"
-    android:textSize="@*android:dimen/notification_text_size"
-    android:textStyle="normal"
-    android:singleLine="true"
-    android:ellipsize="end"
-    android:paddingStart="@*android:dimen/notification_content_margin_start"
-    android:paddingEnd="@*android:dimen/notification_content_margin_start"
-    android:background="@*android:drawable/notification_material_action_background" />
diff --git a/car_product/overlay/frameworks/base/core/res/res/layout/notification_material_media_action.xml b/car_product/overlay/frameworks/base/core/res/res/layout/notification_material_media_action.xml
deleted file mode 100644
index b6468df..0000000
--- a/car_product/overlay/frameworks/base/core/res/res/layout/notification_material_media_action.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<ImageButton
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@android:style/Widget.Material.Button.Borderless.Small"
-    android:id="@*android:id/action0"
-    android:background="@*android:drawable/notification_material_media_action_background"
-    android:layout_width="0dp"
-    android:layout_height="@*android:dimen/media_notification_action_button_size"
-    android:layout_weight="1"
-    android:padding="0dp"
-    android:gravity="center"
-    android:scaleType="fitCenter" />
diff --git a/car_product/overlay/frameworks/base/core/res/res/layout/resolver_different_item_header.xml b/car_product/overlay/frameworks/base/core/res/res/layout/resolver_different_item_header.xml
index 535ea3f..f4bedb2 100644
--- a/car_product/overlay/frameworks/base/core/res/res/layout/resolver_different_item_header.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/layout/resolver_different_item_header.xml
@@ -16,9 +16,18 @@
  * limitations under the License.
  */
 -->
-<FrameLayout
+<TextView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content">
-    <include layout="@*android:layout/car_resolver_different_item_header"/>
-</FrameLayout>
+    android:layout_height="wrap_content"
+    android:text="@*android:string/use_a_different_app"
+    android:minHeight="56dp"
+    android:textAppearance="?android:attr/textAppearanceLarge"
+    android:textSize="@*android:dimen/car_body2_size"
+    android:gravity="start|center_vertical"
+    android:paddingStart="16dp"
+    android:paddingEnd="16dp"
+    android:paddingTop="8dp"
+    android:paddingBottom="8dp"
+    android:elevation="8dp"
+/>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values/colors.xml b/car_product/overlay/frameworks/base/core/res/res/values/colors.xml
index e2717e5..94a0478 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values/colors.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values/colors.xml
@@ -33,9 +33,6 @@
     <!-- The secondary text color if the text is on top of a dark background. -->
     <color name="notification_secondary_text_color_dark">@*android:color/car_body2</color>
 
-    <!-- The background color of a notification card. -->
-    <color name="notification_material_background_color">@*android:color/car_colorPrimary</color>
-
     <!-- The default color for text in a notification. This color is also the default color for
          icons. -->
     <color name="notification_default_color">@*android:color/car_accent</color>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values/config.xml b/car_product/overlay/frameworks/base/core/res/res/values/config.xml
index 56dbf19..4538e60 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values/config.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values/config.xml
@@ -27,7 +27,13 @@
          up to this many users can be running in garage mode.
          3 = headless user 0 + two primary users or 1 primary + 1 guest -->
     <integer name="config_multiuserMaxRunningUsers">3</integer>
-    <!-- Use delay loccking mode always for automotive -->
+    <!-- Show multiuser switcher by default, unless the user specifically disables it. -->
+    <bool name="config_showUserSwitcherByDefault">true</bool>
+    <!-- Flag specifying whether user-switch operations have custom UI. When false, user-switch
+         UI is handled by ActivityManagerService. On AAOS, this value should be true since the
+         UserSwitchUi is implemented by Car SystemUI.-->
+    <bool name="config_customUserSwitchUi">true</bool>
+    <!-- Use delay locking mode always for automotive -->
     <bool name="config_multiuserDelayUserDataLocking">true</bool>
     <!-- If true, all guest users created on the device will be ephemeral. -->
     <bool name="config_guestUserEphemeral">true</bool>
@@ -91,11 +97,33 @@
 
     <string name="config_dataUsageSummaryComponent">com.android.car.settings/com.android.car.settings.datausage.DataWarningAndLimitActivity</string>
 
+    <string name="config_defaultTrustAgent" translatable="false">com.android.car.companiondevicesupport/.feature.trust.TrustedDeviceAgentService</string>
+
+    <!-- Controls whether system buttons use all caps for text -->
+    <bool name="config_buttonTextAllCaps">false</bool>
+
     <bool name="config_automotiveHideNavBarForKeyboard">true</bool>
 
     <!-- Turn off Wallpaper service -->
     <bool name="config_enableWallpaperService">false</bool>
 
-    <!-- Automotive explicitly controls when the system suspends. Do not use autoSuspend. -->
-    <bool name="config_enableAutoSuspend" translatable="false">false</bool>
+    <!-- Whether to only install system packages on a user if they're whitelisted for that user
+         type. Override the default value in framework config file.
+         0  - disable whitelist (install all system packages; no logging)
+         1  - enforce (only install system packages if they are whitelisted)
+         2  - log (log when a non-whitelisted package is run)
+         4  - any package not mentioned in the whitelist file is implicitly whitelisted on all users
+         8  - same as 4, but just for the SYSTEM user
+         16 - ignore OTAs (don't install system packages during OTAs)
+
+         Common scenarios for auto:
+          - to enable feature (fully enforced) for a complete whitelist: 1
+          - to enable feature for an incomplete whitelist (so use implicit whitelist mode): 5 -->
+    <integer name="config_userTypePackageWhitelistMode">5</integer> <!-- 1+4 -->
+
+    <!-- Default user restrictions for system user 0. -->
+    <string-array translatable="false" name="config_defaultFirstUserRestrictions">
+        <item>"no_modify_accounts"</item>
+    </string-array>
+
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values/styles_device_default.xml b/car_product/overlay/frameworks/base/core/res/res/values/styles_device_default.xml
index 37139d3..08ea8dc 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values/styles_device_default.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values/styles_device_default.xml
@@ -87,6 +87,10 @@
     </style>
 
     <style name="Widget.DeviceDefault.Button" parent="android:Widget.Material.Button">
+        <item name="android:singleLine">true</item>
+        <item name="android:ellipsize">none</item>
+        <item name="android:requiresFadingEdge">horizontal</item>
+        <item name="android:fadingEdgeLength">@*android:dimen/car_textview_fading_edge_length</item>
         <item name="android:background">@*android:drawable/car_button_background</item>
         <item name="android:layout_height">@*android:dimen/car_button_height</item>
         <item name="android:minWidth">@*android:dimen/car_button_min_width</item>
@@ -137,4 +141,9 @@
         <item name="android:layout">@*android:layout/car_preference</item>
     </style>
 
+    <!-- AlertDialog Style -->
+    <style name="AlertDialog.DeviceDefault" parent="*android:AlertDialog.Material">
+        <item name="android:layout">@*android:layout/car_alert_dialog</item>
+    </style>
+
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values/themes_device_defaults.xml b/car_product/overlay/frameworks/base/core/res/res/values/themes_device_defaults.xml
index c36e925..5796cff 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values/themes_device_defaults.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values/themes_device_defaults.xml
@@ -34,6 +34,7 @@
         <item name="android:colorForeground">@*android:color/car_card_light</item>
         <item name="android:editTextColor">@*android:color/car_body1</item>
         <item name="android:listPreferredItemHeightSmall">@*android:dimen/car_single_line_list_item_height</item>
+        <item name="android:selectableItemBackground">@*android:drawable/item_background</item>
         <item name="android:textColorHint">@*android:color/car_body2</item>
         <item name="android:textColorPrimary">@*android:color/text_color_primary</item>
         <item name="android:textColorSecondary">@*android:color/car_body2</item>
@@ -53,6 +54,7 @@
         <item name="android:textAppearanceListItem">@*android:style/TextAppearance.DeviceDefault.Large</item>
         <item name="android:textAppearanceListItemSmall">@*android:style/TextAppearance.DeviceDefault.Large</item>
         <item name="android:textAppearanceListItemSecondary">@*android:style/TextAppearance.DeviceDefault.Small</item>
+        <item name="android:textAppearanceButton">@*android:style/Widget.DeviceDefault.Button</item>
         <item name="android:borderlessButtonStyle">@*android:style/Widget.DeviceDefault.Button.Borderless.Colored</item>
         <item name="android:buttonBarButtonStyle">@*android:style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
         <item name="android:buttonStyle">@*android:style/Widget.DeviceDefault.Button</item>
@@ -65,9 +67,11 @@
         <item name="android:colorPrimaryDark">@*android:color/primary_device_default_dark</item>
         <item name="android:colorForeground">@*android:color/car_card_light</item>
         <item name="android:editTextColor">@*android:color/car_body1</item>
+        <item name="android:selectableItemBackground">@*android:drawable/item_background</item>
         <item name="android:textColorHint">@*android:color/car_body2</item>
         <item name="android:textColorPrimary">@*android:color/text_color_primary</item>
         <item name="android:textColorSecondary">@*android:color/car_body2</item>
+        <item name="android:windowTitleStyle">?android:attr/textAppearanceLarge</item>
     </style>
 
     <style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="android:Theme.DeviceDefault.Dialog">
@@ -76,6 +80,11 @@
     </style>
 
     <style name="Theme.DeviceDefault.Dialog.Alert" parent="android:Theme.Material.Dialog.Alert">
+        <item name="android:textAppearanceLarge">@*android:style/TextAppearance.DeviceDefault.Large</item>
+        <item name="android:textAppearanceMedium">@*android:style/TextAppearance.DeviceDefault.Medium</item>
+        <item name="android:textAppearanceSmall">@*android:style/TextAppearance.DeviceDefault.Small</item>
+        <item name="android:textAppearanceButton">@*android:style/Widget.DeviceDefault.Button</item>
+        <item name="android:alertDialogStyle">@*android:style/AlertDialog.DeviceDefault</item>
         <item name="android:borderlessButtonStyle">@*android:style/Widget.DeviceDefault.Button.Borderless.Colored</item>
         <item name="android:buttonBarButtonStyle">@*android:style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
         <item name="android:buttonStyle">@*android:style/Widget.DeviceDefault.Button</item>
@@ -88,12 +97,14 @@
         <item name="android:colorPrimaryDark">@*android:color/primary_device_default_dark</item>
         <item name="android:colorForeground">@*android:color/car_card_light</item>
         <item name="android:editTextColor">@*android:color/car_body1</item>
+        <item name="android:selectableItemBackground">@*android:drawable/item_background</item>
         <item name="android:textColorHint">@*android:color/car_body2</item>
         <item name="android:textColorPrimary">@*android:color/text_color_primary</item>
         <item name="android:textColorSecondary">@*android:color/car_body2</item>
         <item name="android:textAppearanceListItem">@*android:style/TextAppearance.DeviceDefault.Large</item>
         <item name="android:textAppearanceListItemSmall">@*android:style/TextAppearance.DeviceDefault.Large</item>
         <item name="android:textAppearanceListItemSecondary">@*android:style/TextAppearance.DeviceDefault.Small</item>
+        <item name="android:windowTitleStyle">?android:attr/textAppearanceLarge</item>
     </style>
 
     <style name="Theme.DeviceDefault.Settings.Dialog" parent="android:Theme.DeviceDefault.Dialog.Alert">
@@ -120,6 +131,7 @@
         <item name="android:colorAccent">@*android:color/accent_device_default_light</item>
         <item name="android:colorBackground">@*android:color/primary_device_default_light</item>
         <item name="android:listDivider">@*android:color/car_keyboard_divider_line</item>
+        <item name="android:selectableItemBackground">@*android:drawable/item_background</item>
         <item name="android:textColorPrimary">@*android:color/car_keyboard_text_primary_color</item>
         <item name="android:textColorSecondary">@*android:color/car_keyboard_text_secondary_color</item>
     </style>
@@ -181,6 +193,10 @@
         <item name="android:textAppearanceListItem">@android:style/TextAppearance.DeviceDefault.Large</item>
         <item name="android:textAppearanceListItemSmall">@android:style/TextAppearance.DeviceDefault.Large</item>
         <item name="android:textAppearanceListItemSecondary">@android:style/TextAppearance.DeviceDefault.Small</item>
+
+        <!-- Icon sizes -->
+        <item name="*android:iconfactoryIconSize">@*android:dimen/resolver_icon_size</item>
+        <item name="*android:iconfactoryBadgeSize">@*android:dimen/resolver_badge_size</item>
     </style>
 
 
@@ -278,6 +294,8 @@
         <!-- Hide action bar -->
         <item name="android:windowActionBar">false</item>
         <item name="android:windowNoTitle">true</item>
+
+        <item name="android:selectableItemBackground">@*android:drawable/item_background</item>
     </style>
 
     <style name="Theme.DeviceDefault.Light.Panel" parent="android:Theme.DeviceDefault.Panel"/>
diff --git a/car_product/overlay/frameworks/base/core/res/res/xml/config_user_types.xml b/car_product/overlay/frameworks/base/core/res/res/xml/config_user_types.xml
new file mode 100644
index 0000000..1baae68
--- /dev/null
+++ b/car_product/overlay/frameworks/base/core/res/res/xml/config_user_types.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+
+<user-types>
+    <full-type name="android.os.usertype.full.SECONDARY" >
+        <default-restrictions />
+    </full-type>
+
+    <full-type name="android.os.usertype.full.GUEST" >
+        <default-restrictions no_factory_reset="true" no_remove_user="true"
+                  no_modify_accounts="true" no_install_apps="true" no_install_unknown_sources="true"
+                  no_uninstall_apps="true"/>
+    </full-type>
+</user-types>
diff --git a/car_product/overlay/frameworks/base/packages/CarSystemUI/res/values/config.xml b/car_product/overlay/frameworks/base/packages/CarSystemUI/res/values/config.xml
index e30a197..d8d8516 100644
--- a/car_product/overlay/frameworks/base/packages/CarSystemUI/res/values/config.xml
+++ b/car_product/overlay/frameworks/base/packages/CarSystemUI/res/values/config.xml
@@ -80,42 +80,4 @@
     <!-- Keep the notification background when the container has been expanded. The children will
          expand inline within the container, so it can keep its original background. -->
     <bool name="config_showGroupNotificationBgWhenExpanded">true</bool>
-
-    <!--
-      Service components below were copied verbatim from frameworks/base/packages/SystemUI/res/values/config.xml,
-      then the services that are not needed by automotive were commented out (to improve boot and user switch time).
-    -->
-    <string-array name="config_systemUIServiceComponents" translatable="false">
-        <item>com.android.systemui.util.NotificationChannels</item>
-        <item>com.android.systemui.statusbar.CommandQueue$CommandQueueStart</item>
-        <item>com.android.systemui.keyguard.KeyguardViewMediator</item>
-<!--
-        <item>com.android.systemui.recents.Recents</item>
--->
-<!--
-        <item>com.android.systemui.volume.VolumeUI</item>
--->
-        <item>com.android.systemui.stackdivider.Divider</item>
-        <item>com.android.systemui.SystemBars</item>
-        <item>com.android.systemui.usb.StorageNotification</item>
-        <item>com.android.systemui.power.PowerUI</item>
-        <item>com.android.systemui.media.RingtonePlayer</item>
-        <item>com.android.systemui.keyboard.KeyboardUI</item>
-<!--
-        <item>com.android.systemui.pip.PipUI</item>
--->
-        <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
-        <item>@string/config_systemUIVendorServiceComponent</item>
-        <item>com.android.systemui.util.leak.GarbageMonitor$Service</item>
-        <item>com.android.systemui.LatencyTester</item>
-        <item>com.android.systemui.globalactions.GlobalActionsComponent</item>
-        <item>com.android.systemui.ScreenDecorations</item>
-        <item>com.android.systemui.biometrics.BiometricDialogImpl</item>
-        <item>com.android.systemui.SliceBroadcastRelayHandler</item>
-        <item>com.android.systemui.SizeCompatModeActivityController</item>
-        <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
-        <item>com.android.systemui.theme.ThemeOverlayController</item>
-        <item>com.android.systemui.voicerecognition.car.ConnectedDeviceVoiceRecognitionNotifier</item>
-    </string-array>
-
 </resources>
diff --git a/car_product/overlay/frameworks/base/packages/CarSystemUI/res/values/dimens.xml b/car_product/overlay/frameworks/base/packages/CarSystemUI/res/values/dimens.xml
deleted file mode 100644
index b57fcb9..0000000
--- a/car_product/overlay/frameworks/base/packages/CarSystemUI/res/values/dimens.xml
+++ /dev/null
@@ -1,94 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2016, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<resources>
-    <!-- The alpha for the scrim behind the notification shade. This value is 1 so that the
-         scrim has no transparency. -->
-    <item name="scrim_behind_alpha" format="float" type="dimen">1.0</item>
-
-    <!-- Largest size an avatar might need to be drawn in the user picker, status bar, or
-         quick settings header -->
-    <dimen name="max_avatar_size">128dp</dimen>
-
-    <!-- The width of panel holding the notification card. -->
-    <dimen name="notification_panel_width">522dp</dimen>
-
-    <!-- The width of the quick settings panel. -1 for match_parent. -->
-    <dimen name="qs_panel_width">-1px</dimen>
-
-    <!-- Height of a small notification in the status bar-->
-    <dimen name="notification_min_height">192dp</dimen>
-
-    <!-- Height of a small notification in the status bar which was used before android N -->
-    <dimen name="notification_min_height_legacy">192dp</dimen>
-
-    <!-- Height of a large notification in the status bar -->
-    <dimen name="notification_max_height">400dp</dimen>
-
-    <!-- Height of a heads up notification in the status bar for legacy custom views -->
-    <dimen name="notification_max_heads_up_height_legacy">400dp</dimen>
-
-    <!-- Height of a heads up notification in the status bar -->
-    <dimen name="notification_max_heads_up_height">400dp</dimen>
-
-    <!-- Height of the status bar header bar -->
-    <dimen name="status_bar_header_height">54dp</dimen>
-
-    <!-- The height of the divider between the individual notifications. -->
-    <dimen name="notification_divider_height">16dp</dimen>
-
-    <!-- The height of the divider between the individual notifications when the notification
-         wants it to be increased. This value is the same as notification_divider_height so that
-         the spacing between all notifications will always be the same. -->
-    <dimen name="notification_divider_height_increased">@dimen/notification_divider_height</dimen>
-
-    <!-- The alpha of the dividing line between child notifications of a notification group. -->
-    <item name="notification_divider_alpha" format="float" type="dimen">1.0</item>
-
-    <!-- The width of each individual notification card. -->
-    <dimen name="notification_child_width">522dp</dimen>
-
-    <!-- The top margin of the notification panel. -->
-    <dimen name="notification_panel_margin_top">32dp</dimen>
-
-    <!-- The bottom margin of the panel that holds the list of notifications. -->
-    <dimen name="notification_panel_margin_bottom">@dimen/notification_divider_height</dimen>
-
-    <!-- The corner radius of the shadow behind the notification. -->
-    <dimen name="notification_shadow_radius">16dp</dimen>
-
-    <!-- The amount of space below the notification list. This value is 0 so the list scrolls
-         all the way to the bottom. -->
-    <dimen name="close_handle_underlap">0dp</dimen>
-
-    <!-- The height of the divider between the individual notifications in a notification group. -->
-    <dimen name="notification_children_container_divider_height">1dp</dimen>
-
-    <!-- The height of the header for a container containing child notifications. -->
-    <dimen name="notification_children_container_header_height">76dp</dimen>
-
-    <!-- The top margin for the notification children container in its non-expanded form. This
-         value is smaller than notification_children_container_header_height to bring the first
-         child closer so there is less wasted space. -->
-    <dimen name="notification_children_container_margin_top">68dp</dimen>
-
-    <!-- The height of the quick settings footer that holds the user switcher, settings icon,
-         etc. in the car setting.-->
-    <dimen name="qs_footer_height">74dp</dimen>
-
-</resources>
diff --git a/car_product/overlay/frameworks/base/packages/SettingsProvider/res/values/default.xml b/car_product/overlay/frameworks/base/packages/SettingsProvider/res/values/default.xml
deleted file mode 100644
index 6009626..0000000
--- a/car_product/overlay/frameworks/base/packages/SettingsProvider/res/values/default.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/**
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<resources>
-    <!-- There is no frx in the emulator so default to being fully set up. -->
-    <bool name="def_device_provisioned">true</bool>
-    <bool name="def_user_setup_complete">true</bool>
-    <bool name="def_bluetooth_on">true</bool>
-    <bool name="def_wifi_on">false</bool>
-    <!-- Disable system heads-up notifications -->
-    <integer name="def_heads_up_enabled">0</integer>
-</resources>
diff --git a/car_product/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults.xml b/car_product/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults.xml
index cb44830..81a9a3d 100644
--- a/car_product/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults.xml
+++ b/car_product/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults.xml
@@ -20,4 +20,10 @@
     <bool name="def_device_provisioned">false</bool>
     <!--  default setting for Settings.System.END_BUTTON_BEHAVIOR: 0 for car -->
     <integer name="def_end_button_behavior">0</integer>
+
+    <bool name="def_bluetooth_on">true</bool>
+    <bool name="def_wifi_on">false</bool>
+
+    <!-- Disable system heads-up notifications -->
+    <integer name="def_heads_up_enabled">0</integer>
 </resources>
diff --git a/car_product/overlay/packages/apps/Bluetooth/res/values/config.xml b/car_product/overlay/packages/apps/Bluetooth/res/values/config.xml
index 810549a..36bd90c 100644
--- a/car_product/overlay/packages/apps/Bluetooth/res/values/config.xml
+++ b/car_product/overlay/packages/apps/Bluetooth/res/values/config.xml
@@ -32,18 +32,22 @@
 <resources>
     <!-- Disable source profiles (typically used in phone) -->
     <bool name="profile_supported_a2dp">false</bool>
+    <bool name="profile_supported_avrcp_target">false</bool>
     <bool name="profile_supported_hs_hfp">false</bool>
+    <bool name="profile_supported_hid_device">false</bool>
     <bool name="profile_supported_hid_host">false</bool>
     <bool name="profile_supported_pbap">false</bool>
     <bool name="profile_supported_map">false</bool>
     <bool name="profile_supported_hdp">false</bool>
     <bool name="profile_supported_opp">false</bool>
+    <bool name="profile_supported_sap">false</bool>
     <bool name="enable_phone_policy">false</bool>
 
     <!-- Enable sink profiles (typically used on a CarKitt) -->
     <bool name="profile_supported_hfpclient">true</bool>
     <bool name="hfp_client_connection_service_enabled">true</bool>
     <bool name="profile_supported_avrcp_controller">true</bool>
+    <bool name="avrcp_controller_enable_cover_art">true</bool>
     <bool name="profile_supported_a2dp_sink">true</bool>
     <bool name="profile_supported_pbapclient">true</bool>
     <bool name="profile_supported_pan">true</bool>
diff --git a/car_product/overlay/packages/apps/SettingsIntelligence/res/values/configs.xml b/car_product/overlay/packages/apps/SettingsIntelligence/res/values/configs.xml
new file mode 100644
index 0000000..4e8539a
--- /dev/null
+++ b/car_product/overlay/packages/apps/SettingsIntelligence/res/values/configs.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<resources>
+    <!-- Fully-qualified class name for the implementation of the FeatureFactory to be instantiated in SettingsIntelligence. -->
+    <string name="config_featureFactory" translatable="false">
+        com.android.settings.intelligence.search.car.CarFeatureFactoryImpl
+    </string>
+</resources>
\ No newline at end of file
diff --git a/car_product/sepolicy/OWNERS b/car_product/sepolicy/OWNERS
new file mode 100644
index 0000000..307b9d5
--- /dev/null
+++ b/car_product/sepolicy/OWNERS
@@ -0,0 +1,5 @@
+# Project owners
+danharms@google.com
+keunyoung@google.com
+sgurun@google.com
+gurunagarajan@google.com
diff --git a/car_product/sepolicy/private/carservice_app.te b/car_product/sepolicy/private/carservice_app.te
index 05c7b3f..49a3c6f 100644
--- a/car_product/sepolicy/private/carservice_app.te
+++ b/car_product/sepolicy/private/carservice_app.te
@@ -12,9 +12,6 @@
 # Allow Car Service to register/access itself with ServiceManager
 add_service(carservice_app, carservice_service)
 
-# Allow Car Service to register its stats service with ServiceManager
-add_service(carservice_app, carstats_service)
-
 # Allow Car Service to access certain system services.
 # Keep alphabetically sorted.
 allow carservice_app {
@@ -33,13 +30,16 @@
     input_method_service
     input_service
     location_service
+    lock_settings_service
     media_session_service
     network_management_service
     power_service
     procfsinspector_service
     sensorservice_service
+    statsmanager_service
     surfaceflinger_service
     telecom_service
+    thermal_service
     uimode_service
     voiceinteraction_service
     wifi_service
@@ -62,8 +62,24 @@
 
 allow carservice_app procfsinspector:binder call;
 
+# Allow binder calls with statsd
+allow carservice_app statsd:binder call;
+
 # To access /sys/fs/<type>/<partition>/lifetime_write_kbytes
-allow carservice_app sysfs_fs_lifetime_write:file { getattr open read };
+r_dir_file(carservice_app, sysfs_fs_ext4)
+r_dir_file(carservice_app, sysfs_fs_f2fs)
 
 set_prop(carservice_app, ctl_start_prop)
+set_prop(carservice_app, ctl_stop_prop)
 unix_socket_connect(carservice_app, dumpstate, dumpstate)
+
+# Allow reading vehicle-specific configuration
+get_prop(carservice_app, vehicle_hal_prop)
+
+carwatchdog_client_domain(carservice_app)
+
+# For ActivityBlockingActiviy
+allow carservice_app gpu_device:chr_file rw_file_perms;
+allow carservice_app gpu_device:dir r_dir_perms;
+allow carservice_app gpu_service:service_manager find;
+binder_call(carservice_app, gpuservice)
diff --git a/car_product/sepolicy/private/genfs_contexts b/car_product/sepolicy/private/genfs_contexts
new file mode 100644
index 0000000..e8e6e9f
--- /dev/null
+++ b/car_product/sepolicy/private/genfs_contexts
@@ -0,0 +1 @@
+genfscon sysfs /fs/ext4 u:object_r:sysfs_fs_ext4:s0
diff --git a/car_product/sepolicy/private/service_contexts b/car_product/sepolicy/private/service_contexts
index 38d994c..7ac544c 100644
--- a/car_product/sepolicy/private/service_contexts
+++ b/car_product/sepolicy/private/service_contexts
@@ -1,3 +1,2 @@
 car_service  u:object_r:carservice_service:s0
-car_stats u:object_r:carstats_service:s0
 com.android.car.procfsinspector u:object_r:procfsinspector_service:s0
diff --git a/car_product/sepolicy/private/statsd.te b/car_product/sepolicy/private/statsd.te
deleted file mode 100644
index 1a17418..0000000
--- a/car_product/sepolicy/private/statsd.te
+++ /dev/null
@@ -1,2 +0,0 @@
-# Allow statsd to pull atoms from car_stats service
-allow statsd carstats_service:service_manager find;
diff --git a/car_product/sepolicy/public/file.te b/car_product/sepolicy/public/file.te
index 11bf839..8703f35 100644
--- a/car_product/sepolicy/public/file.te
+++ b/car_product/sepolicy/public/file.te
@@ -1,8 +1,4 @@
-# This type for lifetime_write_kbytes files which resides in
-# /sys/fs/<filesystem>/<partition>/lifetime_writes_kbytes
-# Vendors are supposed to extend genfs_contexts with the
-# partition names for their devices.
-type sysfs_fs_lifetime_write, sysfs_type, fs_type;
-
 # /data/system/car
 type system_car_data_file, file_type, data_file_type, core_data_file_type;
+# /sys/fs/ext4
+type sysfs_fs_ext4, sysfs_type, fs_type;
diff --git a/car_product/sepolicy/public/service.te b/car_product/sepolicy/public/service.te
index c6a2e30..87426f4 100644
--- a/car_product/sepolicy/public/service.te
+++ b/car_product/sepolicy/public/service.te
@@ -1,3 +1,2 @@
 type carservice_service, app_api_service, service_manager_type;
-type carstats_service, service_manager_type;
 type procfsinspector_service, service_manager_type;
diff --git a/car_product/sepolicy/test/experimentalcarservice_app.te b/car_product/sepolicy/test/experimentalcarservice_app.te
new file mode 100644
index 0000000..6bfe3b3
--- /dev/null
+++ b/car_product/sepolicy/test/experimentalcarservice_app.te
@@ -0,0 +1,47 @@
+# Domain to run ExperimentalCarService (com.android.experimentalcar)
+type experimentalcarservice_app, domain, coredomain;
+app_domain(experimentalcarservice_app);
+
+allow experimentalcarservice_app wifi_service:service_manager find;
+
+# Allow access certain to system services.
+# Keep alphabetically sorted.
+allow experimentalcarservice_app {
+    accessibility_service
+    activity_service
+    activity_task_service
+    audio_service
+    audioserver_service
+    autofill_service
+    bluetooth_manager_service
+    carservice_service
+    connectivity_service
+    content_service
+    deviceidle_service
+    display_service
+    graphicsstats_service
+    input_method_service
+    input_service
+    location_service
+    lock_settings_service
+    media_session_service
+    network_management_service
+    power_service
+    procfsinspector_service
+    sensorservice_service
+    surfaceflinger_service
+    telecom_service
+    uimode_service
+    voiceinteraction_service
+}:service_manager find;
+
+# Read and write /data/data subdirectory.
+allow experimentalcarservice_app system_app_data_file:dir create_dir_perms;
+allow experimentalcarservice_app system_app_data_file:{ file lnk_file } create_file_perms;
+# R/W /data/system/car
+allow experimentalcarservice_app system_car_data_file:dir create_dir_perms;
+allow experimentalcarservice_app system_car_data_file:{ file lnk_file } create_file_perms;
+
+net_domain(experimentalcarservice_app)
+
+allow experimentalcarservice_app cgroup:file rw_file_perms;
diff --git a/car_product/sepolicy/test/kitchensink_app.te b/car_product/sepolicy/test/kitchensink_app.te
deleted file mode 100644
index dcdb1e4..0000000
--- a/car_product/sepolicy/test/kitchensink_app.te
+++ /dev/null
@@ -1,37 +0,0 @@
-# Domain to run EmbeddedKitchenSink app (for test-purpose)
-type kitchensink_app, domain;
-app_domain(kitchensink_app);
-
-# Allow Car Service to be the client of Vehicle HAL
-hal_client_domain(kitchensink_app, hal_vehicle)
-
-# Keep alphabetically sorted.
-allow kitchensink_app {
-    accessibility_service
-    activity_service
-    activity_task_service
-    audio_service
-    audioserver_service
-    autofill_service
-    carservice_service
-    connectivity_service
-    content_service
-    deviceidle_service
-    display_service
-    graphicsstats_service
-    input_method_service
-    input_service
-    location_service
-    mediaserver_service
-    network_management_service
-    power_service
-    sensorservice_service
-    surfaceflinger_service
-    telecom_service
-    uimode_service
-    wifi_service
-}:service_manager find;
-
-# Read and write /data/data subdirectory.
-allow kitchensink_app system_app_data_file:dir { create_dir_perms getattr };
-allow kitchensink_app system_app_data_file:{ file lnk_file } create_file_perms;
diff --git a/car_product/sepolicy/test/seapp_contexts b/car_product/sepolicy/test/seapp_contexts
index 530e60e..a818d73 100644
--- a/car_product/sepolicy/test/seapp_contexts
+++ b/car_product/sepolicy/test/seapp_contexts
@@ -1 +1 @@
-user=system seinfo=platform name=com.google.android.car.kitchensink domain=kitchensink_app type=system_app_data_file
+user=system seinfo=platform name=com.android.experimentalcar domain=experimentalcarservice_app type=system_app_data_file
diff --git a/computepipe/Android.mk b/computepipe/Android.mk
new file mode 100644
index 0000000..319852c
--- /dev/null
+++ b/computepipe/Android.mk
@@ -0,0 +1,18 @@
+# Copyright (C) 2018 The Android Open Source Project
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
+
diff --git a/computepipe/OWNERS b/computepipe/OWNERS
new file mode 100644
index 0000000..284dba0
--- /dev/null
+++ b/computepipe/OWNERS
@@ -0,0 +1,5 @@
+hanumantsingh@google.com
+ankitarora@google.com
+kathan@google.com
+nyogeshwar@google.com
+michaelkeller@google.com
diff --git a/computepipe/aidl/Android.bp b/computepipe/aidl/Android.bp
new file mode 100644
index 0000000..749fd5b
--- /dev/null
+++ b/computepipe/aidl/Android.bp
@@ -0,0 +1,41 @@
+aidl_interface {
+    name: "android.automotive.computepipe.runner",
+    vendor_available: true,
+    srcs: [
+        "android/automotive/computepipe/runner/*.aidl",
+        "android/automotive/computepipe/*.aidl",
+    ],
+    imports: [
+        "android.hardware.graphics.common",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            enabled: false,
+        },
+        cpp: {
+            enabled: false,
+        },
+    },
+    versions: ["1"],
+}
+
+aidl_interface {
+    name: "android.automotive.computepipe.registry",
+    vendor_available: true,
+    imports: ["android.automotive.computepipe.runner"],
+    srcs: [
+        "android/automotive/computepipe/registry/*.aidl",
+        "android/automotive/computepipe/*.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            enabled: false,
+        },
+        cpp: {
+            enabled: false,
+        },
+    },
+    versions: ["1"],
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/1/.hash b/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/1/.hash
new file mode 100644
index 0000000..d5b2102
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/1/.hash
@@ -0,0 +1 @@
+9d1bf5f9568165514a5f8777ce77155ba87dc3f0
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/1/android/automotive/computepipe/registry/IClientInfo.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/1/android/automotive/computepipe/registry/IClientInfo.aidl
new file mode 100644
index 0000000..c37657e
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/1/android/automotive/computepipe/registry/IClientInfo.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.registry;
+@VintfStability
+interface IClientInfo {
+  @utf8InCpp String getClientName();
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/1/android/automotive/computepipe/registry/IPipeQuery.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/1/android/automotive/computepipe/registry/IPipeQuery.aidl
new file mode 100644
index 0000000..06f7fd6
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/1/android/automotive/computepipe/registry/IPipeQuery.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.registry;
+@VintfStability
+interface IPipeQuery {
+  @utf8InCpp String[] getGraphList();
+  android.automotive.computepipe.runner.IPipeRunner getPipeRunner(in @utf8InCpp String graphName, in android.automotive.computepipe.registry.IClientInfo info);
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/1/android/automotive/computepipe/registry/IPipeRegistration.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/1/android/automotive/computepipe/registry/IPipeRegistration.aidl
new file mode 100644
index 0000000..b16da98
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/1/android/automotive/computepipe/registry/IPipeRegistration.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.registry;
+@VintfStability
+interface IPipeRegistration {
+  void registerPipeRunner(in @utf8InCpp String graphName, android.automotive.computepipe.runner.IPipeRunner graphRunner);
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/current/android/automotive/computepipe/registry/IClientInfo.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/current/android/automotive/computepipe/registry/IClientInfo.aidl
new file mode 100644
index 0000000..c37657e
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/current/android/automotive/computepipe/registry/IClientInfo.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.registry;
+@VintfStability
+interface IClientInfo {
+  @utf8InCpp String getClientName();
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/current/android/automotive/computepipe/registry/IPipeQuery.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/current/android/automotive/computepipe/registry/IPipeQuery.aidl
new file mode 100644
index 0000000..06f7fd6
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/current/android/automotive/computepipe/registry/IPipeQuery.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.registry;
+@VintfStability
+interface IPipeQuery {
+  @utf8InCpp String[] getGraphList();
+  android.automotive.computepipe.runner.IPipeRunner getPipeRunner(in @utf8InCpp String graphName, in android.automotive.computepipe.registry.IClientInfo info);
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/current/android/automotive/computepipe/registry/IPipeRegistration.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/current/android/automotive/computepipe/registry/IPipeRegistration.aidl
new file mode 100644
index 0000000..b16da98
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.registry/current/android/automotive/computepipe/registry/IPipeRegistration.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.registry;
+@VintfStability
+interface IPipeRegistration {
+  void registerPipeRunner(in @utf8InCpp String graphName, android.automotive.computepipe.runner.IPipeRunner graphRunner);
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/.hash b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/.hash
new file mode 100644
index 0000000..18c726e
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/.hash
@@ -0,0 +1 @@
+693de9d1b1839f3c90076d78c8f2380b93bafe41
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/IPipeDebugger.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/IPipeDebugger.aidl
new file mode 100644
index 0000000..80a4581
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/IPipeDebugger.aidl
@@ -0,0 +1,26 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+interface IPipeDebugger {
+  void setPipeProfileOptions(in android.automotive.computepipe.runner.PipeProfilingType type);
+  void startPipeProfiling();
+  void stopPipeProfiling();
+  android.automotive.computepipe.runner.ProfilingData getPipeProfilingInfo();
+  void releaseDebugger();
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/IPipeRunner.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/IPipeRunner.aidl
new file mode 100644
index 0000000..827d220
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/IPipeRunner.aidl
@@ -0,0 +1,34 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+interface IPipeRunner {
+  void init(in android.automotive.computepipe.runner.IPipeStateCallback statecb);
+  android.automotive.computepipe.runner.PipeDescriptor getPipeDescriptor();
+  void setPipeInputSource(in int configId);
+  void setPipeOffloadOptions(in int configId);
+  void setPipeTermination(in int configId);
+  void setPipeOutputConfig(in int configId, in int maxInFlightCount, in android.automotive.computepipe.runner.IPipeStream handler);
+  void applyPipeConfigs();
+  void resetPipeConfigs();
+  void startPipe();
+  void stopPipe();
+  void doneWithPacket(in int bufferId, in int streamId);
+  android.automotive.computepipe.runner.IPipeDebugger getPipeDebugger();
+  void releaseRunner();
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/IPipeStateCallback.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/IPipeStateCallback.aidl
new file mode 100644
index 0000000..54dba9b
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/IPipeStateCallback.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+interface IPipeStateCallback {
+  oneway void handleState(in android.automotive.computepipe.runner.PipeState state);
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/IPipeStream.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/IPipeStream.aidl
new file mode 100644
index 0000000..6fc01f8
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/IPipeStream.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+interface IPipeStream {
+  oneway void deliverPacket(in android.automotive.computepipe.runner.PacketDescriptor packet);
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PacketDescriptor.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PacketDescriptor.aidl
new file mode 100644
index 0000000..581a0c7
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PacketDescriptor.aidl
@@ -0,0 +1,28 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PacketDescriptor {
+  int bufId;
+  android.automotive.computepipe.runner.PacketDescriptorPacketType type;
+  int size;
+  android.hardware.graphics.common.HardwareBuffer handle;
+  ParcelFileDescriptor[] dataFds;
+  long sourceTimeStampMillis;
+  byte[] data;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PacketDescriptorPacketType.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PacketDescriptorPacketType.aidl
new file mode 100644
index 0000000..4070d78
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PacketDescriptorPacketType.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PacketDescriptorPacketType {
+  SEMANTIC_DATA = 0,
+  PIXEL_DATA = 1,
+  SEMANTIC_ZERO_COPY_DATA = 2,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeDescriptor.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeDescriptor.aidl
new file mode 100644
index 0000000..679d315
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeDescriptor.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeDescriptor {
+  android.automotive.computepipe.runner.PipeInputConfig[] inputConfig;
+  android.automotive.computepipe.runner.PipeOffloadConfig[] offloadConfig;
+  android.automotive.computepipe.runner.PipeTerminationConfig[] terminationConfig;
+  android.automotive.computepipe.runner.PipeOutputConfig[] outputConfig;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfig.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfig.aidl
new file mode 100644
index 0000000..6d59d47
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfig.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeInputConfig {
+  android.automotive.computepipe.runner.PipeInputConfigInputSourceDesc[] inputSources;
+  int configId;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigCameraDesc.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigCameraDesc.aidl
new file mode 100644
index 0000000..7bd5309
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigCameraDesc.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeInputConfigCameraDesc {
+  android.automotive.computepipe.runner.PipeInputConfigCameraType type;
+  @utf8InCpp String camId;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigCameraType.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigCameraType.aidl
new file mode 100644
index 0000000..604ba77
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigCameraType.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PipeInputConfigCameraType {
+  DRIVER_VIEW_CAMERA = 0,
+  OCCUPANT_VIEW_CAMERA = 1,
+  EXTERNAL_CAMERA = 2,
+  SURROUND_VIEW_CAMERA = 3,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigFormatType.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigFormatType.aidl
new file mode 100644
index 0000000..509c31a
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigFormatType.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PipeInputConfigFormatType {
+  RGB = 0,
+  NIR = 1,
+  NIR_DEPTH = 2,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigImageFileDesc.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigImageFileDesc.aidl
new file mode 100644
index 0000000..e8f258e
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigImageFileDesc.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeInputConfigImageFileDesc {
+  android.automotive.computepipe.runner.PipeInputConfigImageFileType fileType;
+  @utf8InCpp String filePath;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigImageFileType.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigImageFileType.aidl
new file mode 100644
index 0000000..966c2ad
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigImageFileType.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PipeInputConfigImageFileType {
+  JPEG = 0,
+  PNG = 1,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigInputSourceDesc.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigInputSourceDesc.aidl
new file mode 100644
index 0000000..7caee90
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigInputSourceDesc.aidl
@@ -0,0 +1,29 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeInputConfigInputSourceDesc {
+  android.automotive.computepipe.runner.PipeInputConfigInputType type;
+  android.automotive.computepipe.runner.PipeInputConfigFormatType format;
+  int width;
+  int height;
+  int stride;
+  android.automotive.computepipe.runner.PipeInputConfigCameraDesc camDesc;
+  android.automotive.computepipe.runner.PipeInputConfigVideoFileDesc videoDesc;
+  android.automotive.computepipe.runner.PipeInputConfigImageFileDesc imageDesc;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigInputType.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigInputType.aidl
new file mode 100644
index 0000000..a67f6e5
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigInputType.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PipeInputConfigInputType {
+  CAMERA = 0,
+  VIDEO_FILE = 1,
+  IMAGE_FILES = 2,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigVideoFileDesc.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigVideoFileDesc.aidl
new file mode 100644
index 0000000..fa79a8b
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigVideoFileDesc.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeInputConfigVideoFileDesc {
+  android.automotive.computepipe.runner.PipeInputConfigVideoFileType fileType;
+  @utf8InCpp String filePath;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigVideoFileType.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigVideoFileType.aidl
new file mode 100644
index 0000000..29a1b55
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeInputConfigVideoFileType.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PipeInputConfigVideoFileType {
+  MPEG = 0,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeOffloadConfig.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeOffloadConfig.aidl
new file mode 100644
index 0000000..7e9f29c
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeOffloadConfig.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeOffloadConfig {
+  android.automotive.computepipe.runner.PipeOffloadConfigOffloadDesc desc;
+  String configId;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeOffloadConfigOffloadDesc.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeOffloadConfigOffloadDesc.aidl
new file mode 100644
index 0000000..6a99bec
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeOffloadConfigOffloadDesc.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeOffloadConfigOffloadDesc {
+  android.automotive.computepipe.runner.PipeOffloadConfigOffloadType[] type;
+  boolean[] isVirtual;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeOffloadConfigOffloadType.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeOffloadConfigOffloadType.aidl
new file mode 100644
index 0000000..40f3a7d
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeOffloadConfigOffloadType.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PipeOffloadConfigOffloadType {
+  CPU = 0,
+  GPU = 1,
+  NEURAL_ENGINE = 2,
+  CV_ENGINE = 3,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeOutputConfig.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeOutputConfig.aidl
new file mode 100644
index 0000000..8f2b27f
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeOutputConfig.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeOutputConfig {
+  android.automotive.computepipe.runner.PipeOutputConfigOutputDesc output;
+  int outputId;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeOutputConfigOutputDesc.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeOutputConfigOutputDesc.aidl
new file mode 100644
index 0000000..a396dc7
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeOutputConfigOutputDesc.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeOutputConfigOutputDesc {
+  String name;
+  android.automotive.computepipe.runner.PipeOutputConfigPacketType type;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeOutputConfigPacketType.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeOutputConfigPacketType.aidl
new file mode 100644
index 0000000..df206bc
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeOutputConfigPacketType.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PipeOutputConfigPacketType {
+  SEMANTIC_DATA = 0,
+  PIXEL_DATA = 1,
+  PIXEL_ZERO_COPY_DATA = 2,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeProfilingType.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeProfilingType.aidl
new file mode 100644
index 0000000..43b4146
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeProfilingType.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PipeProfilingType {
+  LATENCY = 0,
+  TRACE_EVENTS = 1,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeState.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeState.aidl
new file mode 100644
index 0000000..67793e9
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeState.aidl
@@ -0,0 +1,26 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PipeState {
+  RESET = 0,
+  CONFIG_DONE = 1,
+  RUNNING = 2,
+  DONE = 3,
+  ERR_HALT = 4,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeTerminationConfig.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeTerminationConfig.aidl
new file mode 100644
index 0000000..e93c2f9
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeTerminationConfig.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeTerminationConfig {
+  android.automotive.computepipe.runner.PipeTerminationConfigTerminationDesc desc;
+  int configId;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeTerminationConfigTerminationDesc.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeTerminationConfigTerminationDesc.aidl
new file mode 100644
index 0000000..3a3f7f5
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeTerminationConfigTerminationDesc.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeTerminationConfigTerminationDesc {
+  android.automotive.computepipe.runner.PipeTerminationConfigTerminationType type;
+  int qualifier;
+  android.automotive.computepipe.runner.PipeOutputConfig streamConfig;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeTerminationConfigTerminationType.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeTerminationConfigTerminationType.aidl
new file mode 100644
index 0000000..4c4dafc
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/PipeTerminationConfigTerminationType.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PipeTerminationConfigTerminationType {
+  CLIENT_STOP = 0,
+  MIN_PACKET_COUNT = 1,
+  MAX_RUN_TIME = 2,
+  EVENT = 3,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/ProfilingData.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/ProfilingData.aidl
new file mode 100644
index 0000000..1cc898f
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/1/android/automotive/computepipe/runner/ProfilingData.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable ProfilingData {
+  android.automotive.computepipe.runner.PipeProfilingType type;
+  int size;
+  ParcelFileDescriptor[] dataFds;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/IPipeDebugger.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/IPipeDebugger.aidl
new file mode 100644
index 0000000..80a4581
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/IPipeDebugger.aidl
@@ -0,0 +1,26 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+interface IPipeDebugger {
+  void setPipeProfileOptions(in android.automotive.computepipe.runner.PipeProfilingType type);
+  void startPipeProfiling();
+  void stopPipeProfiling();
+  android.automotive.computepipe.runner.ProfilingData getPipeProfilingInfo();
+  void releaseDebugger();
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/IPipeRunner.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/IPipeRunner.aidl
new file mode 100644
index 0000000..827d220
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/IPipeRunner.aidl
@@ -0,0 +1,34 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+interface IPipeRunner {
+  void init(in android.automotive.computepipe.runner.IPipeStateCallback statecb);
+  android.automotive.computepipe.runner.PipeDescriptor getPipeDescriptor();
+  void setPipeInputSource(in int configId);
+  void setPipeOffloadOptions(in int configId);
+  void setPipeTermination(in int configId);
+  void setPipeOutputConfig(in int configId, in int maxInFlightCount, in android.automotive.computepipe.runner.IPipeStream handler);
+  void applyPipeConfigs();
+  void resetPipeConfigs();
+  void startPipe();
+  void stopPipe();
+  void doneWithPacket(in int bufferId, in int streamId);
+  android.automotive.computepipe.runner.IPipeDebugger getPipeDebugger();
+  void releaseRunner();
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/IPipeStateCallback.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/IPipeStateCallback.aidl
new file mode 100644
index 0000000..54dba9b
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/IPipeStateCallback.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+interface IPipeStateCallback {
+  oneway void handleState(in android.automotive.computepipe.runner.PipeState state);
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/IPipeStream.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/IPipeStream.aidl
new file mode 100644
index 0000000..6fc01f8
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/IPipeStream.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+interface IPipeStream {
+  oneway void deliverPacket(in android.automotive.computepipe.runner.PacketDescriptor packet);
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PacketDescriptor.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PacketDescriptor.aidl
new file mode 100644
index 0000000..581a0c7
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PacketDescriptor.aidl
@@ -0,0 +1,28 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PacketDescriptor {
+  int bufId;
+  android.automotive.computepipe.runner.PacketDescriptorPacketType type;
+  int size;
+  android.hardware.graphics.common.HardwareBuffer handle;
+  ParcelFileDescriptor[] dataFds;
+  long sourceTimeStampMillis;
+  byte[] data;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PacketDescriptorPacketType.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PacketDescriptorPacketType.aidl
new file mode 100644
index 0000000..4070d78
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PacketDescriptorPacketType.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PacketDescriptorPacketType {
+  SEMANTIC_DATA = 0,
+  PIXEL_DATA = 1,
+  SEMANTIC_ZERO_COPY_DATA = 2,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeDescriptor.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeDescriptor.aidl
new file mode 100644
index 0000000..679d315
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeDescriptor.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeDescriptor {
+  android.automotive.computepipe.runner.PipeInputConfig[] inputConfig;
+  android.automotive.computepipe.runner.PipeOffloadConfig[] offloadConfig;
+  android.automotive.computepipe.runner.PipeTerminationConfig[] terminationConfig;
+  android.automotive.computepipe.runner.PipeOutputConfig[] outputConfig;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfig.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfig.aidl
new file mode 100644
index 0000000..6d59d47
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfig.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeInputConfig {
+  android.automotive.computepipe.runner.PipeInputConfigInputSourceDesc[] inputSources;
+  int configId;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigCameraDesc.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigCameraDesc.aidl
new file mode 100644
index 0000000..7bd5309
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigCameraDesc.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeInputConfigCameraDesc {
+  android.automotive.computepipe.runner.PipeInputConfigCameraType type;
+  @utf8InCpp String camId;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigCameraType.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigCameraType.aidl
new file mode 100644
index 0000000..604ba77
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigCameraType.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PipeInputConfigCameraType {
+  DRIVER_VIEW_CAMERA = 0,
+  OCCUPANT_VIEW_CAMERA = 1,
+  EXTERNAL_CAMERA = 2,
+  SURROUND_VIEW_CAMERA = 3,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigFormatType.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigFormatType.aidl
new file mode 100644
index 0000000..509c31a
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigFormatType.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PipeInputConfigFormatType {
+  RGB = 0,
+  NIR = 1,
+  NIR_DEPTH = 2,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigImageFileDesc.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigImageFileDesc.aidl
new file mode 100644
index 0000000..e8f258e
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigImageFileDesc.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeInputConfigImageFileDesc {
+  android.automotive.computepipe.runner.PipeInputConfigImageFileType fileType;
+  @utf8InCpp String filePath;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigImageFileType.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigImageFileType.aidl
new file mode 100644
index 0000000..966c2ad
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigImageFileType.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PipeInputConfigImageFileType {
+  JPEG = 0,
+  PNG = 1,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigInputSourceDesc.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigInputSourceDesc.aidl
new file mode 100644
index 0000000..7caee90
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigInputSourceDesc.aidl
@@ -0,0 +1,29 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeInputConfigInputSourceDesc {
+  android.automotive.computepipe.runner.PipeInputConfigInputType type;
+  android.automotive.computepipe.runner.PipeInputConfigFormatType format;
+  int width;
+  int height;
+  int stride;
+  android.automotive.computepipe.runner.PipeInputConfigCameraDesc camDesc;
+  android.automotive.computepipe.runner.PipeInputConfigVideoFileDesc videoDesc;
+  android.automotive.computepipe.runner.PipeInputConfigImageFileDesc imageDesc;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigInputType.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigInputType.aidl
new file mode 100644
index 0000000..a67f6e5
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigInputType.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PipeInputConfigInputType {
+  CAMERA = 0,
+  VIDEO_FILE = 1,
+  IMAGE_FILES = 2,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigVideoFileDesc.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigVideoFileDesc.aidl
new file mode 100644
index 0000000..fa79a8b
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigVideoFileDesc.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeInputConfigVideoFileDesc {
+  android.automotive.computepipe.runner.PipeInputConfigVideoFileType fileType;
+  @utf8InCpp String filePath;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigVideoFileType.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigVideoFileType.aidl
new file mode 100644
index 0000000..29a1b55
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeInputConfigVideoFileType.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PipeInputConfigVideoFileType {
+  MPEG = 0,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeOffloadConfig.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeOffloadConfig.aidl
new file mode 100644
index 0000000..7e9f29c
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeOffloadConfig.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeOffloadConfig {
+  android.automotive.computepipe.runner.PipeOffloadConfigOffloadDesc desc;
+  String configId;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeOffloadConfigOffloadDesc.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeOffloadConfigOffloadDesc.aidl
new file mode 100644
index 0000000..6a99bec
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeOffloadConfigOffloadDesc.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeOffloadConfigOffloadDesc {
+  android.automotive.computepipe.runner.PipeOffloadConfigOffloadType[] type;
+  boolean[] isVirtual;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeOffloadConfigOffloadType.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeOffloadConfigOffloadType.aidl
new file mode 100644
index 0000000..40f3a7d
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeOffloadConfigOffloadType.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PipeOffloadConfigOffloadType {
+  CPU = 0,
+  GPU = 1,
+  NEURAL_ENGINE = 2,
+  CV_ENGINE = 3,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeOutputConfig.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeOutputConfig.aidl
new file mode 100644
index 0000000..8f2b27f
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeOutputConfig.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeOutputConfig {
+  android.automotive.computepipe.runner.PipeOutputConfigOutputDesc output;
+  int outputId;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeOutputConfigOutputDesc.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeOutputConfigOutputDesc.aidl
new file mode 100644
index 0000000..a396dc7
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeOutputConfigOutputDesc.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeOutputConfigOutputDesc {
+  String name;
+  android.automotive.computepipe.runner.PipeOutputConfigPacketType type;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeOutputConfigPacketType.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeOutputConfigPacketType.aidl
new file mode 100644
index 0000000..df206bc
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeOutputConfigPacketType.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PipeOutputConfigPacketType {
+  SEMANTIC_DATA = 0,
+  PIXEL_DATA = 1,
+  PIXEL_ZERO_COPY_DATA = 2,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeProfilingType.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeProfilingType.aidl
new file mode 100644
index 0000000..43b4146
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeProfilingType.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PipeProfilingType {
+  LATENCY = 0,
+  TRACE_EVENTS = 1,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeState.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeState.aidl
new file mode 100644
index 0000000..67793e9
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeState.aidl
@@ -0,0 +1,26 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PipeState {
+  RESET = 0,
+  CONFIG_DONE = 1,
+  RUNNING = 2,
+  DONE = 3,
+  ERR_HALT = 4,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeTerminationConfig.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeTerminationConfig.aidl
new file mode 100644
index 0000000..e93c2f9
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeTerminationConfig.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeTerminationConfig {
+  android.automotive.computepipe.runner.PipeTerminationConfigTerminationDesc desc;
+  int configId;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeTerminationConfigTerminationDesc.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeTerminationConfigTerminationDesc.aidl
new file mode 100644
index 0000000..3a3f7f5
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeTerminationConfigTerminationDesc.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable PipeTerminationConfigTerminationDesc {
+  android.automotive.computepipe.runner.PipeTerminationConfigTerminationType type;
+  int qualifier;
+  android.automotive.computepipe.runner.PipeOutputConfig streamConfig;
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeTerminationConfigTerminationType.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeTerminationConfigTerminationType.aidl
new file mode 100644
index 0000000..4c4dafc
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/PipeTerminationConfigTerminationType.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@Backing(type="int") @VintfStability
+enum PipeTerminationConfigTerminationType {
+  CLIENT_STOP = 0,
+  MIN_PACKET_COUNT = 1,
+  MAX_RUN_TIME = 2,
+  EVENT = 3,
+}
diff --git a/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/ProfilingData.aidl b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/ProfilingData.aidl
new file mode 100644
index 0000000..1cc898f
--- /dev/null
+++ b/computepipe/aidl/aidl_api/android.automotive.computepipe.runner/current/android/automotive/computepipe/runner/ProfilingData.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.computepipe.runner;
+@VintfStability
+parcelable ProfilingData {
+  android.automotive.computepipe.runner.PipeProfilingType type;
+  int size;
+  ParcelFileDescriptor[] dataFds;
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/registry/IClientInfo.aidl b/computepipe/aidl/android/automotive/computepipe/registry/IClientInfo.aidl
new file mode 100644
index 0000000..1dd2010
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/registry/IClientInfo.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.registry;
+
+@VintfStability
+interface IClientInfo {
+    /**
+     * Retrieve the name of the client.
+     */
+     @utf8InCpp String getClientName();
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/registry/IPipeQuery.aidl b/computepipe/aidl/android/automotive/computepipe/registry/IPipeQuery.aidl
new file mode 100644
index 0000000..0602971
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/registry/IPipeQuery.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.registry;
+
+import android.automotive.computepipe.registry.IClientInfo;
+import android.automotive.computepipe.runner.IPipeRunner;
+
+/**
+ * Provides mechanism for pipe/graph runner discovery
+ */
+@VintfStability
+interface IPipeQuery {
+    /**
+     * A client will lookup the registered graphs using this method
+     * The registry implementation will return all the graphs registered.
+     * The registration is a one time event.
+     *
+     * @param out get supported graphs by name
+     */
+    @utf8InCpp String[] getGraphList();
+
+    /**
+     * Returns the graph runner for a specific graph
+     *
+     * Once the client has found the graph it is interested in using
+     * getGraphList(), it will use this to retrieve the runner for that graph.
+     * It is possible that between the GraphList retrieval and the invocation of
+     * this method the runner for this graph has gone down. In which case appropriate binder
+     * status will be used to report such an event.
+     *
+     * @param: graphId graph name for which corresponding runner is sought.
+     * @param: info retrieve client information for match purposes when needed
+     * @return handle to interact with specific graph
+     */
+    IPipeRunner getPipeRunner(in @utf8InCpp String graphName, in IClientInfo info);
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/registry/IPipeRegistration.aidl b/computepipe/aidl/android/automotive/computepipe/registry/IPipeRegistration.aidl
new file mode 100644
index 0000000..23039da
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/registry/IPipeRegistration.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.registry;
+
+import android.automotive.computepipe.runner.IPipeRunner;
+
+/**
+ * Provides mechanism for graph/pipe runner to register with router.
+ */
+@VintfStability
+interface IPipeRegistration {
+    /**
+     * Returns a successful registration
+     * A runner will register itself as supporting a graph only once.
+     *
+     * @param graphName: Graph id for which runner and debugger are registered
+     * @param runner: Graph runner for associated graph.
+     * @return: returns ok if successful
+     */
+    void registerPipeRunner(in @utf8InCpp String graphName, IPipeRunner graphRunner);
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/IPipeDebugger.aidl b/computepipe/aidl/android/automotive/computepipe/runner/IPipeDebugger.aidl
new file mode 100644
index 0000000..58e69e5
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/IPipeDebugger.aidl
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.computepipe.runner;
+
+import android.automotive.computepipe.runner.PipeProfilingType;
+import android.automotive.computepipe.runner.ProfilingData;
+
+/**
+ * interface to debug and profile a graph
+ */
+@VintfStability
+interface IPipeDebugger {
+    /**
+     * Set the debug options for a pipe. The profiling options can be an
+     * externsion of the options mentioned here.
+     * https://mediapipe.readthedocs.io/en/latest/measure_performance.html
+     * This should be done prior to the applyPipeConfigs() call.
+     *
+     * @param type: The type of profiling a client wants to enable
+     */
+    void setPipeProfileOptions(in PipeProfilingType type);
+
+    /**
+     * Start the profiling for the mediapipe graph.
+     * This should be issued after the pipe has transitioned to the PipeState::RUNNING
+     *
+     * @param out if starting profiling was successful it returns binder::Status::OK
+     */
+    void startPipeProfiling();
+
+    /**
+     * Stop the profiling for the mediapipe graph.
+     * This can be done at any point of after a pipe is in RUNNING state.
+     *
+     * @param out if stoping profiling was successful, it returns binder::Status::OK
+     */
+    void stopPipeProfiling();
+
+    /**
+     * Retrieve the profiling information
+     * This can be done after a stopPipeProfiling() call or if a PipeState::DONE
+     * notification has been received.
+     *
+     * This is a polling api, If the pipe crashes, any calls to this api will fail.
+     * It blocks until profiling information is available.
+     * It returns the profiling data associated with the profiling options
+     * chosen by setPipe*().
+     * The profiling data is not retained after a call to resetPipeConfigs().
+     */
+    ProfilingData getPipeProfilingInfo();
+
+    /**
+     * Clear up all client specific resources.
+     *
+     * This clears out any gathered profiling data.
+     * This also resets the profiling configuration chosen by the client.
+     * After this method is invoked, client will be responsible for
+     * reconfiguring the profiling steps.
+     *
+     * @param out OK if release was configured successfully.
+     */
+    void releaseDebugger();
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/IPipeRunner.aidl b/computepipe/aidl/android/automotive/computepipe/runner/IPipeRunner.aidl
new file mode 100644
index 0000000..7e80dbc
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/IPipeRunner.aidl
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+import android.automotive.computepipe.runner.PipeDescriptor;
+import android.automotive.computepipe.runner.IPipeStateCallback;
+import android.automotive.computepipe.runner.IPipeStream;
+import android.automotive.computepipe.runner.IPipeDebugger;
+
+@VintfStability
+interface IPipeRunner {
+    /**
+     * Init the runner
+     *
+     * @param statecb state handler to notify client of different state
+     * transitions in the runner. The runner deletes this callback after release
+     * is invoked. This is the first call that should be invoked by the client
+     */
+    void init(in IPipeStateCallback statecb);
+
+    /**
+     * Returns the descriptor for the associated mediapipe
+     *
+     * @param out A descriptor that describes the input options, offload options
+     * and the outputstreams of a computepipe instance.
+     */
+    PipeDescriptor getPipeDescriptor();
+
+    /**
+     * Set the input source for the computepipe graph.
+     * This should be done prior to invoking startPipe.
+     *
+     * @param configId id selected from the available input options.
+     * @param out if selection of input source was supported returns OK
+     */
+    void setPipeInputSource(in int configId);
+
+    /**
+     * Set the offload options for a graph.
+     * This should be a subset of the supported offload options present in the
+     * descriptor. This should be done prior to invoking startPipe
+     *
+     * @param configID offload option id from the advertised offload options.
+     * @param out if offload option was set then returns OK.
+     */
+    void setPipeOffloadOptions(in int configId);
+
+    /**
+     * Set the termination options for a graph.
+     * This should be a subset of the supported termination options present in the
+     * descriptor. This should be done prior to invoking startPipe.
+     *
+     * @param terminationId id of the supported termination option as advertized
+     * in the pipe descriptor
+     * @param out if termination criteria was supported then returns OK.
+     */
+    void setPipeTermination(in int configId);
+
+    /**
+     * Enable a output stream and install call back for packets from that
+     * stream. This should be invoked prior to calling startPipe.
+     * Call this for each output stream that a client wants to enable
+     *
+     * @param configId: describes the output stream configuration the client
+     * wants to enable
+     * @param maxInFlightCount: The maximum number of inflight packets the
+     * client can handle.
+     * @param handler: the handler for the output packets to be invoked once
+     * packet is received
+     * @param out OK void if setting callback succeeded
+     */
+    void setPipeOutputConfig(in int configId, in int maxInFlightCount, in IPipeStream handler);
+
+    /**
+     * Apply all configs.
+     * The client has finsihed specifying all the config options.
+     * Now the configs should be applied. Once the configs are applied the
+     * client will get a notification saying PipeState::CONFIG_DONE.
+     * The configuration applied with this step, will be retained for all future runs
+     * unless explicitly reset by calling resetPipeConfigs().
+     * In case of client death as well, the applied configurations are reset.
+     * In case the runner reports a ERR_HALT state, at any time after applyPipeConfigs(),
+     * all configurations are retained, and expected to be reset by the client
+     * explicitly, prior to attempting a new run.
+     * This call is only allowed when pipe is not running.
+     *
+     * @param out void::OK if the runner was notified to apply config.
+     */
+    void applyPipeConfigs();
+
+    /**
+     * Reset all configs.
+     * The runner stores the configuration even after pipe execution has
+     * completed. This call erases the previous configuration, so that client
+     * can modify and set the configuration again. This call is only allowed
+     * when pipe is not running.
+     *
+     * @param out void::OK if the runner was notified to apply config.
+     */
+    void resetPipeConfigs();
+
+    /**
+     * Start pipe execution on the runner. Prior to this step
+     * each of the configuration steps should be completed. Once the
+     * configurations have been applied, the state handler will be invoked with
+     * the PipeState::CONFIG_DONE notification. Wait for this notification before starting the pipe.
+     * Once the Pipe starts execution the client will receive the state
+     * notification PipeState::RUNNING through the state handler.
+     *
+     * @param out OK void if start succeeded.
+     */
+    void startPipe();
+
+    /**
+     * Stop pipe execution on the runner.
+     *
+     * This can invoked only when the pipe is in run state ie PipeState::RUNNING.
+     * If a client has already chosen a termination option, then this
+     * call overrides that termination criteria.
+     *
+     * Client will be notified once the pipe has stopped using PipeState::DONE
+     * notification. Until then, outstanding packets may continue to be received.
+     * These packets must still be returned with doneWithPacket(). (This does not
+     * apply to SEMANTIC_DATA, as they are copied in the stream callback).
+     *
+     * Once the Pipe stops execution (no new packets generated),
+     * the client will receive the state
+     * notification, PipeState::DONE.
+     *
+     * Once the pipe has completely quiesced, it will transition back to
+     * PipeState::CONFIG_DONE and at this point a new startPipe() can be issued or
+     * previously applied configs can be reset using the resetPipeConfigs() call.
+     *
+     * @param out OK void if stop succeeded
+     */
+    void stopPipe();
+
+    /**
+     * Signal completion of a packet having been consumed by the client.
+     * With this signal from client the runner should release buffer corresponding to the packet.
+     *
+     * @param bufferId Buffer id of the packet
+     * @param streamId Stream id of the packet
+     * @param out OK void if successful
+     */
+    void doneWithPacket(in int bufferId, in int streamId);
+
+    /**
+     * Returns the debugger associated with the runner for this graph
+     *
+     * @param out Debugger handle to interact with specific graph
+     */
+    IPipeDebugger getPipeDebugger();
+
+    /**
+     * Immediately frees up all config resources associated with the client.
+     * Client will not receive state notifications after this call is complete.
+     *
+     * This will also free up any in flight packet.
+     * The client may still get in flight IPipeStream::deliverPacket() callbacks.
+     * However the underlying buffer has been freed up from the packets.
+     *
+     * This also resets any configuration that a client may have performed,
+     * ie pipe transitions back to PipeState::RESET state.
+     * So client will have to start next session with
+     * the configuration steps, ie invoke setPipe*() methods.
+     *
+     * If the client had chosen to enable profiling through IPipeDebugger,
+     * the client should first invoke IPipeDebugger::Release() prior to
+     * this method.
+     *
+     * @return status OK if all resources were freed up.
+     */
+    void releaseRunner();
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/IPipeStateCallback.aidl b/computepipe/aidl/android/automotive/computepipe/runner/IPipeStateCallback.aidl
new file mode 100644
index 0000000..b9289f6
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/IPipeStateCallback.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+import android.automotive.computepipe.runner.PipeState;
+
+@VintfStability
+interface IPipeStateCallback {
+    /**
+     * Callback that notifies a client about the state of a pipe
+     *
+     * Client installs IPipeStateHandler with the runner by invoking
+     * setPipeStateNotifier(). The runner invokes the method below to notify the
+     * client of any state changes.
+     *
+     * @param state is the state of the pipe.
+     */
+    oneway void handleState(in PipeState state);
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/IPipeStream.aidl b/computepipe/aidl/android/automotive/computepipe/runner/IPipeStream.aidl
new file mode 100644
index 0000000..8ea6481
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/IPipeStream.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+import android.automotive.computepipe.runner.PacketDescriptor;
+
+@VintfStability
+interface IPipeStream {
+    /**
+     * Receives calls from the AIDL implementation each time a new packet is available.
+     * Semantic data is contaied in the packet descriptor.
+     * Only Zero copy data packets received by this method must be returned via calls to
+     * IPipeRunner::doneWithPacket(), using the bufId field in the descriptor.
+     * After the pipe execution has stopped this callback may continue to happen for sometime.
+     * Those packets must still be returned. Last frame will be indicated with
+     * a null packet. After that there will not be any further packets.
+     *
+     * @param: packet is a descriptor for the packet.
+     */
+    oneway void deliverPacket(in PacketDescriptor packet);
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PacketDescriptor.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PacketDescriptor.aidl
new file mode 100644
index 0000000..02fc82f
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PacketDescriptor.aidl
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+import android.automotive.computepipe.runner.PacketDescriptorPacketType;
+import android.hardware.graphics.common.HardwareBuffer;
+
+/**
+ * Structure that describes the output packet for a specific outputstream
+ * that gets returned to the client.
+ */
+@VintfStability
+parcelable PacketDescriptor {
+    /**
+     * packet id, used in case of zero copy data.
+     * Used to notify the runner of consumption.
+     */
+    int bufId;
+    /**
+     * type of the buffer
+     */
+    PacketDescriptorPacketType type;
+    /**
+     * size of the memory region
+     */
+    int size;
+    /**
+     * Handle to pixel data. This handle can be mapped and data retrieved.
+     * The description field will contain the
+     * graphics buffer description. Must be freed with call to doneWithPacket()
+     * This is populated only if type is PIXEL
+     */
+    HardwareBuffer handle;
+    /**
+     * Zero copy semantic data handle.
+     * Must be freed with call to doneWithPacket().
+     * This is populated only if type is SEMANTIC
+     */
+    ParcelFileDescriptor[] dataFds;
+    /**
+     * Timestamp of event at source. Timestamp value is milliseconds since epoch.
+     */
+    long sourceTimeStampMillis;
+    /**
+     * semantic data. Requires no doneWithPacket() acknowledgement.
+     */
+    byte[] data;
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PacketDescriptorPacketType.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PacketDescriptorPacketType.aidl
new file mode 100644
index 0000000..fd1f5ce
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PacketDescriptorPacketType.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+/**
+ * types of packet
+ */
+@VintfStability
+@Backing(type="int")
+enum PacketDescriptorPacketType {
+    /**
+     * General semantic data derived from input stream
+     */
+    SEMANTIC_DATA = 0,
+    /**
+     * Pixel data generated, for eg annotated frames
+     */
+    PIXEL_DATA,
+    /**
+     * Semantic data with zero copy requirements.
+     */
+    SEMANTIC_ZERO_COPY_DATA,
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeDescriptor.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeDescriptor.aidl
new file mode 100644
index 0000000..128e803
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeDescriptor.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+import android.automotive.computepipe.runner.PipeInputConfig;
+import android.automotive.computepipe.runner.PipeOffloadConfig;
+import android.automotive.computepipe.runner.PipeTerminationConfig;
+import android.automotive.computepipe.runner.PipeOutputConfig;
+
+/**
+ * Pipe Descriptor
+ *
+ * This is the descriptor for use case that describes all the supported
+ * a) input options
+ * b) termination options
+ * c) offload options
+ * d) output streams
+ *
+ * This is returned by the HIDL implementation to the client to describe a given graph.
+ * The client selects the config for a given graph run from the available
+ * choices advertised. Note the output stream that a client wants to subscribes
+ * to, require the client to subscribe to each stream individually.
+ *
+ * This descriptor is returned by the HAL to the client.
+ */
+@VintfStability
+parcelable PipeDescriptor {
+    /**
+     * input configurations supported by the graph.
+     */
+    PipeInputConfig[] inputConfig;
+    /**
+     * Offload options supported by the graph.
+     */
+    PipeOffloadConfig[] offloadConfig;
+    /**
+     * Termination options supported by the graph.
+     */
+    PipeTerminationConfig[] terminationConfig;
+    /**
+     * Output streams supported by the graph.
+     */
+    PipeOutputConfig[] outputConfig;
+}
+
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfig.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfig.aidl
new file mode 100644
index 0000000..e49aba3
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfig.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+import android.automotive.computepipe.runner.PipeInputConfigInputSourceDesc;
+
+/**
+ * Transaction data types
+ *
+ *
+ * Input config descriptor
+ *
+ * Structure that describes the input sources
+ *
+ * This is provided by the AIDL implementation to the client
+ */
+@VintfStability
+parcelable PipeInputConfig {
+    /**
+     * input option.
+     */
+    PipeInputConfigInputSourceDesc[] inputSources;
+    /**
+     * ID for the option.
+     */
+    int configId;
+}
+
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigCameraDesc.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigCameraDesc.aidl
new file mode 100644
index 0000000..9788042
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigCameraDesc.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.computepipe.runner;
+
+import android.automotive.computepipe.runner.PipeInputConfigCameraType;
+
+/**
+ * Camera config descriptor
+ */
+@VintfStability
+parcelable PipeInputConfigCameraDesc {
+    /**
+     * input stream type
+     */
+    PipeInputConfigCameraType type;
+    /**
+     * camera identifier to disambiguate multiple instances
+     * of InputType. If only one of a certain type is present
+     * this should be 0. For VIDEO_FILE this should be 0.
+     */
+    @utf8InCpp String camId;
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigCameraType.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigCameraType.aidl
new file mode 100644
index 0000000..6750eb3
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigCameraType.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+/**
+ * State of the remote graph
+ */
+@VintfStability
+@Backing(type="int")
+enum PipeInputConfigCameraType {
+    /**
+     * Driver focused Camera stream
+     */
+    DRIVER_VIEW_CAMERA = 0,
+    /**
+     * Camera with wider field of view that can capture
+     * occupants in the car.
+     */
+    OCCUPANT_VIEW_CAMERA,
+    /**
+     * External Camera
+     */
+    EXTERNAL_CAMERA,
+    /**
+     * Surround view
+     */
+    SURROUND_VIEW_CAMERA,
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigFormatType.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigFormatType.aidl
new file mode 100644
index 0000000..b25e8b2
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigFormatType.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+@VintfStability
+@Backing(type="int")
+enum PipeInputConfigFormatType {
+    /**
+     * RGB input
+     */
+    RGB,
+    /**
+     * NIR input
+     */
+    NIR,
+    /**
+     * NIR + Depth Frame
+     */
+    NIR_DEPTH,
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigImageFileDesc.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigImageFileDesc.aidl
new file mode 100644
index 0000000..07ea7f8
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigImageFileDesc.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.computepipe.runner;
+
+import android.automotive.computepipe.runner.PipeInputConfigImageFileType;
+
+/**
+ * Image file descriptor
+ */
+@VintfStability
+parcelable PipeInputConfigImageFileDesc {
+    /**
+     * File type
+     */
+    PipeInputConfigImageFileType fileType;
+
+    /**
+     * File path
+     */
+     @utf8InCpp String filePath;
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigImageFileType.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigImageFileType.aidl
new file mode 100644
index 0000000..34e224e
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigImageFileType.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+/**
+ * Image file type
+ */
+@VintfStability
+@Backing(type="int")
+enum PipeInputConfigImageFileType {
+    /**
+     * JPEG
+     */
+    JPEG = 0,
+    /**
+     * Configuration completed
+     */
+    PNG,
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigInputSourceDesc.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigInputSourceDesc.aidl
new file mode 100644
index 0000000..b4b93a7
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigInputSourceDesc.aidl
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.computepipe.runner;
+
+import android.automotive.computepipe.runner.PipeInputConfigCameraDesc;
+import android.automotive.computepipe.runner.PipeInputConfigFormatType;
+import android.automotive.computepipe.runner.PipeInputConfigImageFileDesc;
+import android.automotive.computepipe.runner.PipeInputConfigInputType;
+import android.automotive.computepipe.runner.PipeInputConfigVideoFileDesc;
+
+/**
+ * Input source descriptor
+ */
+@VintfStability
+parcelable PipeInputConfigInputSourceDesc {
+    /**
+     * input stream type
+     */
+    PipeInputConfigInputType type;
+    /**
+     * format of the input stream
+     */
+    PipeInputConfigFormatType format;
+    /**
+     * width resolution of the input stream
+     */
+    int width;
+    /**
+     * height resolution of the input stream
+     */
+    int height;
+    /**
+     * stride for the frame
+     */
+    int stride;
+    /**
+     * Camera config. This should be populated if the type is a camera.
+     */
+    PipeInputConfigCameraDesc camDesc;
+    /**
+     * Video file config. This should be populated if the type set is video file.
+     */
+    PipeInputConfigVideoFileDesc videoDesc;
+    /**
+     * Camera config. This should be populated if the type is a video file
+     */
+    PipeInputConfigImageFileDesc imageDesc;
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigInputType.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigInputType.aidl
new file mode 100644
index 0000000..bf2e739
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigInputType.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+/**
+ * Types of input streams supported by runner
+ */
+@VintfStability
+@Backing(type="int")
+enum PipeInputConfigInputType {
+    /**
+     * Camera type is used
+     */
+    CAMERA = 0,
+    /**
+     * Video file
+     */
+    VIDEO_FILE,
+    /**
+     * Image files
+     */
+    IMAGE_FILES,
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigVideoFileDesc.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigVideoFileDesc.aidl
new file mode 100644
index 0000000..35a59d0
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigVideoFileDesc.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.computepipe.runner;
+
+import android.automotive.computepipe.runner.PipeInputConfigVideoFileType;
+
+/**
+ * Video file descriptor
+ */
+@VintfStability
+parcelable PipeInputConfigVideoFileDesc {
+    /**
+     * File type
+     */
+    PipeInputConfigVideoFileType fileType;
+
+    /**
+     * File path
+     */
+     @utf8InCpp String filePath;
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigVideoFileType.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigVideoFileType.aidl
new file mode 100644
index 0000000..0dba428
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeInputConfigVideoFileType.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+/**
+ *Type of encoding for the video file
+ */
+@VintfStability
+@Backing(type="int")
+enum PipeInputConfigVideoFileType {
+    /**
+     * MPEG
+     */
+    MPEG = 0,
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeOffloadConfig.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeOffloadConfig.aidl
new file mode 100644
index 0000000..2682095
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeOffloadConfig.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+import android.automotive.computepipe.runner.PipeOffloadConfigOffloadType;
+import android.automotive.computepipe.runner.PipeOffloadConfigOffloadDesc;
+
+/**
+ * Offload configs
+ *
+ * Structure that describes the offload options that a graph can use.
+ * This is determined at graph creation time by the developer.
+ * A graph can advertise different combinations of offload options that it
+ * can use. A client can choose amongst the combinations of offload options, for
+ * any given iteration of the graph execution.
+ *
+ * This is provided by the HIDL implementation to the client
+ */
+@VintfStability
+parcelable PipeOffloadConfig {
+    /**
+     * Offload descriptor that the graph can support.
+     */
+    PipeOffloadConfigOffloadDesc desc;
+    /**
+     * identifier for the option.
+     */
+    String configId;
+}
+
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeOffloadConfigOffloadDesc.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeOffloadConfigOffloadDesc.aidl
new file mode 100644
index 0000000..825bb3e
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeOffloadConfigOffloadDesc.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+import android.automotive.computepipe.runner.PipeOffloadConfigOffloadType;
+
+/**
+ * structure that describes the combination of offload options.
+ * This is a per graph specific combination.
+ */
+@VintfStability
+parcelable PipeOffloadConfigOffloadDesc {
+    /**
+     * combination of different offload engines
+     */
+    PipeOffloadConfigOffloadType[] type;
+    /**
+     * 1:1 correspondence for each type above.
+     * Every offload engine has a flag describing if its virtual device
+     */
+    boolean[] isVirtual;
+}
+
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeOffloadConfigOffloadType.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeOffloadConfigOffloadType.aidl
new file mode 100644
index 0000000..3502b1c
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeOffloadConfigOffloadType.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+/**
+ * Types of offload options for graph computations available to the runner
+ * All of the offload options maybe virtualized for different execution
+ * environments.
+ */
+@VintfStability
+@Backing(type="int")
+enum PipeOffloadConfigOffloadType {
+    /**
+     * Default cpu only execution
+     */
+    CPU = 0,
+    /**
+     * GPU, Open GLES based acceleration
+     */
+    GPU,
+    /**
+     * Dedicated neural engine provided by SOC vendor
+     */
+    NEURAL_ENGINE,
+    /**
+     * Computer Vision engine provided by SOC vendor
+     */
+    CV_ENGINE,
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeOutputConfig.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeOutputConfig.aidl
new file mode 100644
index 0000000..e7b0b89
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeOutputConfig.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+import android.automotive.computepipe.runner.PipeOutputConfigOutputDesc;
+
+/**
+ * Output configs
+ *
+ * Structure that describes the output stream packets of a graph
+ *
+ * Provided by AIDL implementation to the client as part of GraphDescriptor
+ */
+@VintfStability
+parcelable PipeOutputConfig {
+    /**
+     * output stream.
+     */
+    PipeOutputConfigOutputDesc output;
+    /**
+     * id for the stream.
+     */
+    int outputId;
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeOutputConfigOutputDesc.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeOutputConfigOutputDesc.aidl
new file mode 100644
index 0000000..7c512df
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeOutputConfigOutputDesc.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+import android.automotive.computepipe.runner.PipeOutputConfigPacketType;
+
+/**
+ * Output descriptor
+ */
+@VintfStability
+parcelable PipeOutputConfigOutputDesc {
+    /**
+     * name of the output stream
+     */
+    String name;
+    /**
+     * type of packets produced
+     */
+    PipeOutputConfigPacketType type;
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeOutputConfigPacketType.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeOutputConfigPacketType.aidl
new file mode 100644
index 0000000..44fffb6
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeOutputConfigPacketType.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+/**
+ * Packet type
+ */
+@VintfStability
+@Backing(type="int")
+enum PipeOutputConfigPacketType {
+    /**
+     * semantic data that can be copied.
+     */
+    SEMANTIC_DATA = 0,
+    /**
+     * pixel data with copy semantics.
+     */
+    PIXEL_DATA,
+    /**
+     * pixel data with zero copy requirement.
+     */
+    PIXEL_ZERO_COPY_DATA,
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeProfilingType.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeProfilingType.aidl
new file mode 100644
index 0000000..1c8a632
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeProfilingType.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+/**
+ * Profiling types
+ */
+@VintfStability
+@Backing(type="int")
+enum PipeProfilingType {
+    /**
+     * Latency profiling
+     */
+    LATENCY = 0,
+    /**
+     * Trace events
+     */
+    TRACE_EVENTS = 1,
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeState.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeState.aidl
new file mode 100644
index 0000000..5e1768f
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeState.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+/**
+ * State of the remote graph
+ */
+@VintfStability
+@Backing(type="int")
+enum PipeState {
+    /**
+     * Reset
+     */
+    RESET = 0,
+    /**
+     * Configuration completed
+     */
+    CONFIG_DONE,
+    /**
+     * Running
+     */
+    RUNNING,
+    /**
+     * Finished
+     */
+    DONE,
+    /**
+     * In halt due to error
+     */
+    ERR_HALT,
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeTerminationConfig.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeTerminationConfig.aidl
new file mode 100644
index 0000000..b462507
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeTerminationConfig.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+import android.automotive.computepipe.runner.PipeTerminationConfigTerminationDesc;
+import android.automotive.computepipe.runner.PipeTerminationConfigTerminationType;
+
+/**
+ * Termination configs
+ *
+ * Structure that describes the termination options a graph can advertise
+ *
+ * Provided by HIDL implementation to the client as part of GraphDescriptor
+ *
+ * The client has the option of choosing one of the provided options supported
+ * by the graph or calling calling stopPipe() explicitly.
+ */
+@VintfStability
+parcelable PipeTerminationConfig {
+    /**
+     * termination option supported by graph.
+     */
+    PipeTerminationConfigTerminationDesc desc;
+    /**
+     * identifiers for the option.
+     */
+    int configId;
+}
+
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeTerminationConfigTerminationDesc.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeTerminationConfigTerminationDesc.aidl
new file mode 100644
index 0000000..cf1434e
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeTerminationConfigTerminationDesc.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+import android.automotive.computepipe.runner.PipeOutputConfig;
+import android.automotive.computepipe.runner.PipeTerminationConfigTerminationType;
+
+/**
+ * structure that describes the different termination options supported
+ * by the graph
+ */
+@VintfStability
+parcelable PipeTerminationConfigTerminationDesc {
+    /**
+     * type of termination criteria
+     */
+    PipeTerminationConfigTerminationType type;
+    /**
+     * type based qualifier, could be run time, packet count, or usecase
+     * specific event identifier.
+     */
+    int qualifier;
+    /**
+     * Output stream config. This will only be used when type is MAX_PACKET_COUNT
+     */
+     PipeOutputConfig streamConfig;
+}
+
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PipeTerminationConfigTerminationType.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PipeTerminationConfigTerminationType.aidl
new file mode 100644
index 0000000..e6ecd9c
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PipeTerminationConfigTerminationType.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */package android.automotive.computepipe.runner;
+
+/**
+ * Types of termination options
+ */
+@VintfStability
+@Backing(type="int")
+enum PipeTerminationConfigTerminationType {
+    /**
+     * run indefinetely until client stop.
+     */
+    CLIENT_STOP = 0,
+    /**
+     * run for minimum number of valid output packets
+     */
+    MIN_PACKET_COUNT,
+    /**
+     * run for fixed maximum duration, graph may still produce some packets
+     * post run time, because of delayed signal.
+     */
+    MAX_RUN_TIME,
+    /**
+     * run until specified event.
+     */
+    EVENT,
+}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/ProfilingData.aidl b/computepipe/aidl/android/automotive/computepipe/runner/ProfilingData.aidl
new file mode 100644
index 0000000..a6973ba
--- /dev/null
+++ b/computepipe/aidl/android/automotive/computepipe/runner/ProfilingData.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.automotive.computepipe.runner;
+
+import android.automotive.computepipe.runner.PipeProfilingType;
+
+/**
+ * Structure that describes the profiling information output from
+ * an executing pipe.
+ */
+@VintfStability
+parcelable ProfilingData {
+    /**
+     * Type of profiling information
+     */
+    PipeProfilingType type;
+    /**
+     * size of the memory region
+     */
+    int size;
+    /**
+     * handle to memory region containing zero copy or semantic data
+     * as described in https://mediapipe.readthedocs.io/en/latest/measure_performance.html
+     */
+    ParcelFileDescriptor[] dataFds;
+}
+
diff --git a/computepipe/example/Android.bp b/computepipe/example/Android.bp
new file mode 100644
index 0000000..cfd979d
--- /dev/null
+++ b/computepipe/example/Android.bp
@@ -0,0 +1,151 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_binary {
+    name: "computepipe_face_runner",
+    srcs: [
+        "Runner.cpp",
+    ],
+    static_libs: [
+        "libcomputepipeprotos",
+        "computepipe_prebuilt_graph",
+        "computepipe_client_interface",
+    ],
+    shared_libs: [
+        "computepipe_runner_engine",
+        "libprotobuf-cpp-lite",
+        "libbase",
+        "libbinder_ndk",
+        "android.automotive.computepipe.runner-ndk_platform",
+        "android.automotive.computepipe.registry-ndk_platform",
+        "liblog",
+        "libutils",
+        "libdl",
+        "libfacegraph",
+	"libnativewindow",
+    ],
+    cflags: ["-DLOG_TAG=\"ComputepipeRunner\""] + [
+        "-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS",
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+        "-Wthread-safety",
+    ],
+    header_libs: [
+        "computepipe_runner_includes",
+    ],
+    include_dirs: [
+        "packages/services/Car/computepipe",
+    ],
+}
+
+cc_prebuilt_library_shared {
+    name: "libfacegraph",
+    strip: {
+        keep_symbols: true,
+    },
+    target: {
+        android_arm64: {
+            srcs: ["lib_arm64/libfacegraph.so"],
+        },
+        android_arm: {
+            srcs: ["lib_arm/libfacegraph.so"],
+        },
+        android_x86_64: {
+            srcs: ["lib_x86_64/libfacegraph.so"],
+        },
+        android_x86: {
+            srcs: ["lib_x86/libfacegraph.so"],
+        },
+    },
+    shared_libs: [
+        "libc",
+        "libdl",
+        "libEGL",
+        "libGLESv2",
+        "liblog",
+        "libm",
+        "libz",
+    ],
+}
+
+cc_binary {
+    name: "computepipe_face_tracker",
+    srcs: [
+        "FaceTracker.cpp",
+	"ClientSvc.cpp",
+    ],
+    vendor: true,
+    static_libs: [
+        "libcomputepipefaceproto",
+    ],
+    shared_libs: [
+        "liblog",
+        "libbase",
+        "libbinder_ndk",
+        "libutils",
+        "android.hardware.automotive.occupant_awareness-ndk_platform",
+        "libprotobuf-cpp-lite",
+        "android.automotive.computepipe.runner-ndk_platform",
+        "android.automotive.computepipe.registry-ndk_platform",
+    ],
+    cflags: ["-DLOG_TAG=\"FaceTrackerClient\""] + [
+        "-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS",
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+        "-Wthread-safety",
+    ],
+}
+
+cc_defaults {
+    name: "libcomputepipeface-defaults",
+
+    proto: {
+        export_proto_headers: true,
+        include_dirs: ["external/protobuf/src"],
+    },
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+    ],
+
+    srcs: [
+        "*.proto",
+    ],
+}
+
+cc_library {
+    name: "libcomputepipefaceproto",
+    defaults: ["libcomputepipeface-defaults"],
+    host_supported: false,
+    vendor_available: true,
+    target: {
+        android: {
+            proto: {
+                type: "lite",
+            },
+            static_libs: [
+                "libprotobuf-cpp-lite",
+            ],
+            shared: {
+                enabled: false,
+            },
+        },
+    },
+}
diff --git a/computepipe/example/ClientSvc.cpp b/computepipe/example/ClientSvc.cpp
new file mode 100644
index 0000000..59af7df
--- /dev/null
+++ b/computepipe/example/ClientSvc.cpp
@@ -0,0 +1,47 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <android-base/logging.h>
+#include <android/binder_process.h>
+#include <utils/Log.h>
+
+#include "FaceTracker.h"
+
+using android::automotive::computepipe::FaceTracker;
+
+namespace {
+
+void terminationCallback(bool error, std::string errorMsg) {
+    if (error) {
+        LOG(ERROR) << errorMsg;
+        exit(2);
+    }
+    LOG(ERROR) << "Test completed";
+    exit(0);
+}
+}  // namespace
+int main(int /* argc */, char** /* argv */) {
+    std::function<void(bool, std::string)> cb = terminationCallback;
+    FaceTracker client;
+
+    ABinderProcess_startThreadPool();
+    ndk::ScopedAStatus status = client.init(std::move(cb));
+    if (!status.isOk()) {
+        LOG(ERROR) << "Unable to init client connection";
+        return -1;
+    }
+    ABinderProcess_joinThreadPool();
+
+    return 0;
+}
diff --git a/computepipe/example/FaceOutput.proto b/computepipe/example/FaceOutput.proto
new file mode 100644
index 0000000..59487b1
--- /dev/null
+++ b/computepipe/example/FaceOutput.proto
@@ -0,0 +1,21 @@
+syntax = "proto2";
+
+package android.automotive.computepipe.example;
+
+message BoundingBox {
+  optional int32 top_x = 1;
+  optional int32 top_y = 2;
+  optional int32 width = 3;
+  optional int32 height = 4;
+};
+
+message Pose {
+  optional float pan  = 1;
+  optional float tilt = 2;
+}
+
+message FaceOutput {
+  optional BoundingBox box = 1;
+
+  optional Pose pose = 2;
+};
diff --git a/computepipe/example/FaceTracker.cpp b/computepipe/example/FaceTracker.cpp
new file mode 100644
index 0000000..47e237b
--- /dev/null
+++ b/computepipe/example/FaceTracker.cpp
@@ -0,0 +1,168 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "FaceTracker.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <utils/Log.h>
+
+#include <memory>
+#include <mutex>
+#include <thread>
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+
+using ::android::automotive::computepipe::example::FaceOutput;
+namespace {
+constexpr char kReigstryInterface[] = "router";
+constexpr char kGraphName[] = "Face Tracker Graph";
+}  // namespace
+
+/**
+ * RemoteState monitor
+ */
+PipeState RemoteState::GetCurrentState() {
+    std::unique_lock<std::mutex> lock(mStateLock);
+    mWait.wait(lock, [this]() { return hasChanged; });
+    hasChanged = false;
+    return mState;
+}
+
+void RemoteState::UpdateCurrentState(const PipeState& state) {
+    std::lock_guard<std::mutex> lock(mStateLock);
+    mState = state;
+    if (mState == PipeState::ERR_HALT) {
+        mTerminationCb(true, "Received error from runner");
+    } else if (mState == PipeState::DONE) {
+        mTerminationCb(false, "");
+    } else {
+        hasChanged = true;
+        mWait.notify_all();
+    }
+}
+
+RemoteState::RemoteState(std::function<void(bool, std::string)>& cb) : mTerminationCb(cb) {
+}
+
+/**
+ * StateCallback methods
+ */
+StateCallback::StateCallback(std::shared_ptr<RemoteState> s) : mStateTracker(s) {
+}
+
+ndk::ScopedAStatus StateCallback::handleState(PipeState state) {
+    mStateTracker->UpdateCurrentState(state);
+    return ndk::ScopedAStatus::ok();
+}
+
+/**
+ * FaceTracker methods
+ */
+ndk::ScopedAStatus FaceTracker::init(std::function<void(bool, std::string)>&& cb) {
+    auto termination = cb;
+    mRemoteState = std::make_shared<RemoteState>(termination);
+    std::string instanceName = std::string() + IPipeQuery::descriptor + "/" + kReigstryInterface;
+
+    ndk::SpAIBinder binder(AServiceManager_getService(instanceName.c_str()));
+    CHECK(binder.get());
+
+    std::shared_ptr<IPipeQuery> queryService = IPipeQuery::fromBinder(binder);
+    mClientInfo = ndk::SharedRefBase::make<ClientInfo>();
+    ndk::ScopedAStatus status = queryService->getPipeRunner(kGraphName, mClientInfo, &mPipeRunner);
+    if (!status.isOk()) {
+        LOG(ERROR) << "Failed to get handle to runner";
+        return status;
+    }
+    mStreamCallback = ndk::SharedRefBase::make<StreamCallback>();
+    mStateCallback = ndk::SharedRefBase::make<StateCallback>(mRemoteState);
+    return setupConfig();
+}
+
+ndk::ScopedAStatus FaceTracker::setupConfig() {
+    ndk::ScopedAStatus status = mPipeRunner->init(mStateCallback);
+    if (!status.isOk()) {
+        LOG(ERROR) << "Failed to init runner";
+        return status;
+    }
+    status = mPipeRunner->setPipeInputSource(0);
+    if (!status.isOk()) {
+        LOG(ERROR) << "Failed to set pipe input config";
+        return status;
+    }
+    status = mPipeRunner->setPipeOutputConfig(0, 10, mStreamCallback);
+    if (!status.isOk()) {
+        LOG(ERROR) << "Failed to set pipe output config";
+        return status;
+    }
+    status = mPipeRunner->applyPipeConfigs();
+    if (!status.isOk()) {
+        LOG(ERROR) << "Failed to set apply configs";
+        return status;
+    }
+    std::thread t(&FaceTracker::start, this);
+    t.detach();
+    return ndk::ScopedAStatus::ok();
+}
+
+void FaceTracker::start() {
+    PipeState state = mRemoteState->GetCurrentState();
+    CHECK(state == PipeState::CONFIG_DONE);
+    ndk::ScopedAStatus status = mPipeRunner->startPipe();
+    CHECK(status.isOk());
+    state = mRemoteState->GetCurrentState();
+    CHECK(state == PipeState::RUNNING);
+}
+
+void FaceTracker::stop() {
+    ndk::ScopedAStatus status = mPipeRunner->startPipe();
+    CHECK(status.isOk());
+}
+
+/**
+ * Stream Callback implementation
+ */
+
+ndk::ScopedAStatus StreamCallback::deliverPacket(const PacketDescriptor& in_packet) {
+    std::string output(in_packet.data.begin(), in_packet.data.end());
+
+    FaceOutput faceData;
+    faceData.ParseFromString(output);
+
+    BoundingBox currentBox = faceData.box();
+
+    if (!faceData.has_box()) {
+        mLastBox = BoundingBox();
+        return ndk::ScopedAStatus::ok();
+    }
+
+    if (!mLastBox.has_top_x()) {
+        mLastBox = currentBox;
+        return ndk::ScopedAStatus::ok();
+    }
+
+    if (currentBox.top_x() > mLastBox.top_x() + 1) {
+        LOG(ERROR) << "Face moving left";
+    } else if (currentBox.top_x() + 1 < mLastBox.top_x()) {
+        LOG(ERROR) << "Face moving right";
+    }
+    mLastBox = currentBox;
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/example/FaceTracker.h b/computepipe/example/FaceTracker.h
new file mode 100644
index 0000000..60fd473
--- /dev/null
+++ b/computepipe/example/FaceTracker.h
@@ -0,0 +1,106 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef COMPUTEPIPE_EXAMPLE_FACE_TRACKER_H
+#define COMPUTEPIPE_EXAMPLE_FACE_TRACKER_H
+
+#include <aidl/android/automotive/computepipe/registry/BnClientInfo.h>
+#include <aidl/android/automotive/computepipe/registry/IPipeQuery.h>
+#include <aidl/android/automotive/computepipe/registry/IPipeRegistration.h>
+#include <aidl/android/automotive/computepipe/runner/BnPipeStateCallback.h>
+#include <aidl/android/automotive/computepipe/runner/BnPipeStream.h>
+#include <aidl/android/automotive/computepipe/runner/PipeState.h>
+
+#include <condition_variable>
+#include <iostream>
+#include <memory>
+
+#include "FaceOutput.pb.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+
+using ::aidl::android::automotive::computepipe::registry::BnClientInfo;
+using ::aidl::android::automotive::computepipe::registry::IPipeQuery;
+using ::aidl::android::automotive::computepipe::runner::BnPipeStateCallback;
+using ::aidl::android::automotive::computepipe::runner::BnPipeStream;
+using ::aidl::android::automotive::computepipe::runner::IPipeRunner;
+using ::aidl::android::automotive::computepipe::runner::IPipeStream;
+using ::aidl::android::automotive::computepipe::runner::PacketDescriptor;
+using ::aidl::android::automotive::computepipe::runner::PipeState;
+using ::android::automotive::computepipe::example::BoundingBox;
+
+class RemoteState {
+  public:
+    explicit RemoteState(std::function<void(bool, std::string)>& cb);
+    PipeState GetCurrentState();
+    void UpdateCurrentState(const PipeState& state);
+
+  private:
+    bool hasChanged = false;
+    PipeState mState = PipeState::RESET;
+    std::mutex mStateLock;
+    std::condition_variable mWait;
+    std::function<void(bool, std::string)> mTerminationCb;
+};
+
+class ClientInfo : public BnClientInfo {
+  public:
+    ndk::ScopedAStatus getClientName(std::string* _aidl_return) override {
+        if (_aidl_return) {
+            *_aidl_return = "FaceTrackerClient";
+            return ndk::ScopedAStatus::ok();
+        }
+        return ndk::ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+    }
+};
+
+class StreamCallback : public BnPipeStream {
+  public:
+    StreamCallback() = default;
+    ndk::ScopedAStatus deliverPacket(const PacketDescriptor& in_packet) override;
+
+  private:
+    BoundingBox mLastBox;
+};
+
+class StateCallback : public BnPipeStateCallback {
+  public:
+    explicit StateCallback(std::shared_ptr<RemoteState> s);
+    ndk::ScopedAStatus handleState(PipeState state) override;
+
+  private:
+    std::shared_ptr<RemoteState> mStateTracker = nullptr;
+};
+
+class FaceTracker {
+  public:
+    FaceTracker() = default;
+    ndk::ScopedAStatus init(std::function<void(bool, std::string)>&& termination);
+    void start();
+    void stop();
+
+  private:
+    ndk::ScopedAStatus setupConfig();
+    std::shared_ptr<IPipeRunner> mPipeRunner = nullptr;
+    std::shared_ptr<ClientInfo> mClientInfo = nullptr;
+    std::shared_ptr<StreamCallback> mStreamCallback = nullptr;
+    std::shared_ptr<StateCallback> mStateCallback = nullptr;
+    std::shared_ptr<RemoteState> mRemoteState = nullptr;
+};
+
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+#endif
diff --git a/computepipe/example/Runner.cpp b/computepipe/example/Runner.cpp
new file mode 100644
index 0000000..bbea0b1
--- /dev/null
+++ b/computepipe/example/Runner.cpp
@@ -0,0 +1,76 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include <android-base/logging.h>
+#include <android/binder_process.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <iostream>
+#include <memory>
+#include <thread>
+
+#include "ClientConfig.pb.h"
+#include "ClientInterface.h"
+#include "MemHandle.h"
+#include "Options.pb.h"
+#include "PrebuiltGraph.h"
+#include "RunnerEngine.h"
+#include "types/Status.h"
+
+using android::automotive::computepipe::Status;
+using android::automotive::computepipe::graph::PrebuiltGraph;
+using android::automotive::computepipe::proto::ClientConfig;
+using android::automotive::computepipe::proto::Options;
+using android::automotive::computepipe::runner::client_interface::ClientInterface;
+using android::automotive::computepipe::runner::client_interface::ClientInterfaceFactory;
+using android::automotive::computepipe::runner::engine::RunnerEngine;
+using android::automotive::computepipe::runner::engine::RunnerEngineFactory;
+
+namespace {
+RunnerEngineFactory sEngineFactory;
+ClientInterfaceFactory sClientFactory;
+}  // namespace
+void terminate(bool isError, std::string msg) {
+    if (isError) {
+        LOG(ERROR) << "Error msg " << msg;
+        exit(2);
+    }
+    LOG(ERROR) << "Test complete";
+    exit(0);
+}
+
+int main(int /* argc */, char** /* argv */) {
+    std::shared_ptr<RunnerEngine> engine =
+            sEngineFactory.createRunnerEngine(RunnerEngineFactory::kDefault, "");
+
+    std::unique_ptr<PrebuiltGraph> graph;
+    graph.reset(android::automotive::computepipe::graph::GetLocalGraphFromLibrary("libfacegraph.so",
+                                                                                  engine));
+
+    Options options = graph->GetSupportedGraphConfigs();
+    engine->setPrebuiltGraph(std::move(graph));
+
+    std::function<void(bool, std::string)> cb = terminate;
+    std::unique_ptr<ClientInterface> client =
+        sClientFactory.createClientInterface("aidl", options, engine);
+    if (!client) {
+        std::cerr << "Unable to allocate client";
+        return -1;
+    }
+    engine->setClientInterface(std::move(client));
+    ABinderProcess_startThreadPool();
+    engine->activate();
+    ABinderProcess_joinThreadPool();
+    return 0;
+}
diff --git a/computepipe/example/lib_arm/libfacegraph.so b/computepipe/example/lib_arm/libfacegraph.so
new file mode 100644
index 0000000..3420932
--- /dev/null
+++ b/computepipe/example/lib_arm/libfacegraph.so
Binary files differ
diff --git a/computepipe/example/lib_arm64/libfacegraph.so b/computepipe/example/lib_arm64/libfacegraph.so
new file mode 100644
index 0000000..9784a5b
--- /dev/null
+++ b/computepipe/example/lib_arm64/libfacegraph.so
Binary files differ
diff --git a/computepipe/example/lib_x86/libfacegraph.so b/computepipe/example/lib_x86/libfacegraph.so
new file mode 100644
index 0000000..2777595
--- /dev/null
+++ b/computepipe/example/lib_x86/libfacegraph.so
Binary files differ
diff --git a/computepipe/example/lib_x86_64/libfacegraph.so b/computepipe/example/lib_x86_64/libfacegraph.so
new file mode 100644
index 0000000..c400257
--- /dev/null
+++ b/computepipe/example/lib_x86_64/libfacegraph.so
Binary files differ
diff --git a/computepipe/products/computepipe.mk b/computepipe/products/computepipe.mk
new file mode 100644
index 0000000..44c93f9
--- /dev/null
+++ b/computepipe/products/computepipe.mk
@@ -0,0 +1,35 @@
+# 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.
+
+# Enable computepipe interface
+PRODUCT_PACKAGES += android.automotive.computepipe.router@1.0-impl
+
+# Enable computepipe router
+PRODUCT_PACKAGES += android.automotive.computepipe.router@1.0
+
+# Enable computepipe runner engine library
+PRODUCT_PACKAGES += computepipe_runner_engine
+
+# Enable computepipe runner engine client interface library
+PRODUCT_PACKAGES += computepipe_client_interface
+
+# Enable computepipe runner engine prebuilt graph library
+PRODUCT_PACKAGES += computepipe_prebuilt_graph
+
+
+# Selinux public policies for computepipe services
+PRODUCT_PUBLIC_SEPOLICY_DIRS += packages/services/Car/computepipe/sepolicy/public
+
+# Selinux private policies for computepipe services
+PRODUCT_PRIVATE_SEPOLICY_DIRS += packages/services/Car/computepipe/sepolicy/private
diff --git a/computepipe/products/init.computepipe.rc b/computepipe/products/init.computepipe.rc
new file mode 100644
index 0000000..2892877
--- /dev/null
+++ b/computepipe/products/init.computepipe.rc
@@ -0,0 +1,8 @@
+service computepipe_router_service /system/bin/android.automotive.computepipe.router@1.0
+   class main
+   user system
+   group system
+   disabled
+
+on boot
+   start computepipe_router_service
diff --git a/computepipe/proto/Android.bp b/computepipe/proto/Android.bp
new file mode 100644
index 0000000..27087b7
--- /dev/null
+++ b/computepipe/proto/Android.bp
@@ -0,0 +1,52 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_defaults {
+    name: "libcomputepipeprotos-defaults",
+
+    proto: {
+        export_proto_headers: true,
+        include_dirs: ["external/protobuf/src"],
+    },
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+    ],
+
+    srcs: [
+        "*.proto",
+    ],
+}
+
+cc_library {
+    name: "libcomputepipeprotos",
+    defaults: ["libcomputepipeprotos-defaults"],
+    host_supported: false,
+    vendor_available: true,
+    target: {
+        android: {
+            proto: {
+                type: "lite",
+            },
+            static_libs: [
+                "libprotobuf-cpp-lite",
+            ],
+            shared_libs: [
+                "liblog",
+            ],
+        },
+    },
+}
diff --git a/computepipe/proto/ClientConfig.proto b/computepipe/proto/ClientConfig.proto
new file mode 100644
index 0000000..9678ac3
--- /dev/null
+++ b/computepipe/proto/ClientConfig.proto
@@ -0,0 +1,13 @@
+syntax = "proto2";
+
+package android.automotive.computepipe.proto;
+
+import "packages/services/Car/computepipe/proto/ProfilingType.proto";
+
+message ClientConfig {
+  optional int32 input_config_id = 1;
+  optional int32 offload_id = 2;
+  map<int32, int32> output_options = 3;
+  optional int32 termination_id = 4;
+  optional ProfilingType profiling_type = 5;
+}
diff --git a/computepipe/proto/ConfigurationCommand.proto b/computepipe/proto/ConfigurationCommand.proto
new file mode 100644
index 0000000..46839d2
--- /dev/null
+++ b/computepipe/proto/ConfigurationCommand.proto
@@ -0,0 +1,34 @@
+syntax = "proto2";
+
+package android.automotive.computepipe.proto;
+
+import "packages/services/Car/computepipe/proto/ProfilingType.proto";
+
+message SetInputSource {
+  optional int32 source_id = 1;
+}
+
+message SetOffloadOptions {
+  optional int32 offload_option_id = 1;
+}
+
+message SetTerminationOptions {
+  optional int32 termination_option_id = 1;
+}
+
+message SetOutputStream {
+  optional int32 stream_id  = 1;
+  optional int32 max_inflight_packets_count = 2;
+}
+
+message SetProfileOptions {
+  optional ProfilingType profile_type = 1;
+}
+
+message ConfigurationCommand {
+  optional SetInputSource set_input_source = 1;
+  optional SetOffloadOptions set_offload_offload = 2;
+  optional SetTerminationOptions set_termination_option = 3;
+  optional SetOutputStream set_output_stream = 4;
+  optional SetProfileOptions set_profile_options = 5;
+}
diff --git a/computepipe/proto/ControlCommand.proto b/computepipe/proto/ControlCommand.proto
new file mode 100644
index 0000000..ac27e32
--- /dev/null
+++ b/computepipe/proto/ControlCommand.proto
@@ -0,0 +1,51 @@
+syntax = "proto2";
+
+package android.automotive.computepipe.proto;
+
+message StartGraph {
+  // No member fields yet, as StartGraph() does not take any arguments.
+}
+
+message StopGraph {
+  // No member fields yet, as StopGraph() does not take any arguments.
+}
+
+message ApplyConfigs {
+  // No member fields yet, as ApplyConfigs() does not take any arguments.
+}
+
+message ResetConfigs {
+  // No member fields yet, as ResetConfigs() does not take any arguments.
+}
+
+message DeathNotification {
+  // No member fields yet.
+}
+
+message StartPipeProfile {
+  // No member fields yet.
+}
+
+message StopPipeProfile {
+  // No member fields yet.
+}
+
+message ReleaseDebugger {
+  // No member fields yet.
+}
+
+message ReadDebugData {
+  // No member fields yet.
+}
+
+message ControlCommand {
+  optional StartGraph start_graph = 1;
+  optional StopGraph stop_graph = 2;
+  optional ApplyConfigs apply_configs = 3;
+  optional DeathNotification death_notification = 4;
+  optional ResetConfigs reset_configs = 5;
+  optional StartPipeProfile start_pipe_profile = 6;
+  optional StopPipeProfile stop_pipe_profile = 7;
+  optional ReleaseDebugger release_debugger = 8;
+  optional ReadDebugData read_debug_data = 9;
+}
diff --git a/computepipe/proto/InputConfig.proto b/computepipe/proto/InputConfig.proto
new file mode 100644
index 0000000..2d82706
--- /dev/null
+++ b/computepipe/proto/InputConfig.proto
@@ -0,0 +1,101 @@
+syntax = "proto2";
+
+package android.automotive.computepipe.proto;
+
+message ImageFileConfig {
+  enum ImageFileType {
+    JPEG = 0;
+    PNG = 1;
+  }
+
+  optional ImageFileType file_type = 1;
+
+  optional string image_dir = 2;
+}
+
+message VideoFileConfig {
+  enum VideoFileType {
+    MPEG = 0;
+  }
+
+  optional VideoFileType file_type = 1;
+
+  optional string file_path = 2;
+}
+
+message CameraConfig {
+  enum CameraType {
+    DRIVER_VIEW_CAMERA = 0;
+    OCCUPANT_VIEW_CAMERA = 1;
+    EXTERNAL_CAMERA = 2;
+    SURROUND_VIEW_CAMERA = 3;
+  };
+
+  optional CameraType camera_type = 1;
+
+  optional string cam_id = 2;
+}
+
+message InputStreamConfig {
+  enum InputType {
+    CAMERA = 1;
+    IMAGE_FILES = 2;
+    VIDEO_FILE = 3;
+  }
+
+  optional InputType type = 1;
+
+  enum FormatType {
+    RGB = 0;
+    NIR = 1;
+    NIR_DEPTH = 2;
+  }
+
+  optional FormatType format = 2;
+
+  optional int32 width = 3;
+
+  optional int32 height = 4;
+
+  optional int32 stride = 5;
+
+  // The camera id string essential to start the camera.
+  optional CameraConfig cam_config = 6;
+
+  // for image file input type the following attributes apply
+  optional ImageFileConfig image_config = 7;
+
+  // Must be present when InputType is ImageFile
+  optional VideoFileConfig video_config = 8;
+
+  optional int32 stream_id = 9;
+
+  enum PixelLayout {
+    UNKNOWN = 0;
+
+    // one byte for R, then one byte for G, then one byte for B for each pixel.
+    RGB24 = 1;
+
+    // one byte for R, one byte for G, one byte for B, one byte for alpha or
+    // unused.
+    RGBA32 = 2;
+
+    // Grayscale, one byte per pixel.
+    GRAY8 = 3;
+
+    // Grayscale, one uint16 per pixel.
+    GRAY16 = 4;
+  }
+
+  // Represent pixel layout of image expected by graph.
+  optional PixelLayout pixel_layout = 10 [default = RGB24];
+}
+
+// A graph could require streams from multiple cameras simultaneously, so each possible input
+// config could specify multiple camera configs.
+message InputConfig {
+    repeated InputStreamConfig input_stream = 1;
+
+    // config id which would be used to set the config rather than passing the entire config proto
+    optional int32 config_id = 2;
+}
diff --git a/computepipe/proto/OffloadConfig.proto b/computepipe/proto/OffloadConfig.proto
new file mode 100644
index 0000000..68ec09e
--- /dev/null
+++ b/computepipe/proto/OffloadConfig.proto
@@ -0,0 +1,26 @@
+syntax = "proto2";
+
+package android.automotive.computepipe.proto;
+
+message OffloadOption {
+  enum OffloadType {
+    CPU = 0;
+    GPU = 1;
+    NEURAL_ENGINE = 2;
+    CV_ENGINE = 3;
+  }
+  repeated OffloadType offload_types = 1;
+
+  /**
+     * 1:1 correspondence for each type above.
+     * Every offload engine has a flag describing if its virtual device
+     */
+  repeated bool is_virtual = 2;
+}
+
+message OffloadConfig {
+
+    optional OffloadOption options = 1;
+
+    optional string config_id = 2;
+}
diff --git a/computepipe/proto/Options.proto b/computepipe/proto/Options.proto
new file mode 100644
index 0000000..14d130d
--- /dev/null
+++ b/computepipe/proto/Options.proto
@@ -0,0 +1,33 @@
+syntax = "proto2";
+
+package android.automotive.computepipe.proto;
+
+import "packages/services/Car/computepipe/proto/InputConfig.proto";
+import "packages/services/Car/computepipe/proto/OffloadConfig.proto";
+import "packages/services/Car/computepipe/proto/OutputConfig.proto";
+import "packages/services/Car/computepipe/proto/TerminationConfig.proto";
+
+message Options {
+  /**
+   * input configurations supported by the graph
+   */
+  repeated InputConfig input_configs = 1;
+
+  /**
+   * Offload options supported by the graph
+   */
+  repeated OffloadConfig offload_configs = 2;
+  /**
+   * Termination options supported by the graph
+   */
+  repeated TerminationConfig termination_configs = 3;
+  /**
+   * Output streams supported by the graph.
+   */
+  repeated OutputConfig output_configs = 4;
+
+  /**
+   * Name of the computer vision graph.
+   */
+  optional string graph_name = 5;
+}
diff --git a/computepipe/proto/OutputConfig.proto b/computepipe/proto/OutputConfig.proto
new file mode 100644
index 0000000..f392b4b
--- /dev/null
+++ b/computepipe/proto/OutputConfig.proto
@@ -0,0 +1,17 @@
+syntax = "proto2";
+
+package android.automotive.computepipe.proto;
+
+enum PacketType {
+  SEMANTIC_DATA = 0;
+  PIXEL_DATA = 1;
+  PIXEL_ZERO_COPY_DATA = 2;
+}
+
+message OutputConfig {
+  optional string stream_name = 1;
+
+  optional PacketType type = 2;
+
+  optional int32 stream_id = 3;
+}
diff --git a/computepipe/proto/PacketDescriptor.proto b/computepipe/proto/PacketDescriptor.proto
new file mode 100644
index 0000000..8014141
--- /dev/null
+++ b/computepipe/proto/PacketDescriptor.proto
@@ -0,0 +1,23 @@
+syntax = "proto2";
+
+package android.automotive.computepipe.proto;
+import "packages/services/Car/computepipe/proto/OutputConfig.proto";
+
+message NativeHandles {
+  // File descriptors
+  repeated int32 fds = 1;
+
+  // Corresponding indexes.
+  repeated int32 ix = 2;
+}
+
+message PacketDescriptor {
+  optional int32 buffer_id = 1;
+
+  optional NativeHandles native_handles = 2;
+
+  //  Timestamp value is milliseconds since epoch.
+  optional int64 timestamp_ms = 3;
+
+  optional PacketType packet_type = 4;
+}
diff --git a/computepipe/proto/ProfilingType.proto b/computepipe/proto/ProfilingType.proto
new file mode 100644
index 0000000..f2215a7
--- /dev/null
+++ b/computepipe/proto/ProfilingType.proto
@@ -0,0 +1,9 @@
+syntax = "proto2";
+
+package android.automotive.computepipe.proto;
+
+enum ProfilingType {
+  DISABLED = 0;
+  LATENCY = 1;
+  TRACE_EVENTS = 2;
+}
diff --git a/computepipe/proto/TerminationConfig.proto b/computepipe/proto/TerminationConfig.proto
new file mode 100644
index 0000000..aea1c4f
--- /dev/null
+++ b/computepipe/proto/TerminationConfig.proto
@@ -0,0 +1,27 @@
+syntax = "proto2";
+
+package android.automotive.computepipe.proto;
+
+import "packages/services/Car/computepipe/proto/OutputConfig.proto";
+
+message TerminationOption {
+  enum TerminationType {
+    CLIENT_STOP = 0;
+    MIN_PACKET_COUNT = 1;
+    MAX_RUN_TIME = 2;
+    EVENT = 3;
+  }
+
+  optional TerminationType type = 1;
+  /**
+    * type based qualifier, could be run time, packet count, or usecase
+    * specific event identifier.
+    */
+  optional int32 qualifier = 2;
+}
+
+message TerminationConfig {
+  optional TerminationOption options = 1;
+  optional int32 config_id = 2;
+  optional OutputConfig output_config = 3;
+}
diff --git a/computepipe/router/1.0/Android.bp b/computepipe/router/1.0/Android.bp
new file mode 100644
index 0000000..dd4b6c0
--- /dev/null
+++ b/computepipe/router/1.0/Android.bp
@@ -0,0 +1,72 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library {
+    name: "android.automotive.computepipe.router@1.0-impl",
+    vendor_available: true,
+    srcs: [
+        "PipeClient.cpp",
+        "PipeRunner.cpp",
+        "PipeRegistration.cpp",
+        "PipeQuery.cpp",
+        "RemoteState.cpp",
+    ],
+    cflags: ["-DLOG_TAG=\"ComputepipeRouter\""] +
+        [
+            "-Wall",
+            "-Werror",
+            "-Wextra",
+            "-Wno-unused-parameter",
+        ],
+    header_libs: [
+        "computepipe_router_headers",
+    ],
+    export_include_dirs: ["include"],
+    shared_libs: [
+        "liblog",
+        "libutils",
+        "libbinder_ndk",
+        "android.automotive.computepipe.registry-ndk_platform",
+        "android.automotive.computepipe.runner-ndk_platform",
+    ],
+}
+
+cc_binary {
+    name: "android.automotive.computepipe.router@1.0",
+    srcs: [
+        "service.cpp",
+        "RouterSvc.cpp",
+    ],
+    shared_libs: [
+        "libcutils",
+        "liblog",
+        "libutils",
+        "libbinder_ndk",
+        "android.automotive.computepipe.router@1.0-impl",
+        "android.automotive.computepipe.registry-ndk_platform",
+    ],
+    header_libs: [
+        "computepipe_router_headers",
+    ],
+    init_rc: ["android.automotive.computepipe.router@1.0.rc"],
+    cflags: ["-DLOG_TAG=\"ComputepipeRouter\""] + [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+    ] + [
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+}
diff --git a/computepipe/router/1.0/PipeClient.cpp b/computepipe/router/1.0/PipeClient.cpp
new file mode 100644
index 0000000..b7e299d
--- /dev/null
+++ b/computepipe/router/1.0/PipeClient.cpp
@@ -0,0 +1,64 @@
+/**
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PipeClient.h"
+
+#include <android/binder_ibinder.h>
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+namespace V1_0 {
+namespace implementation {
+
+using namespace aidl::android::automotive::computepipe::registry;
+using namespace ndk;
+
+PipeClient::PipeClient(const std::shared_ptr<IClientInfo>& info)
+    : mDeathMonitor(AIBinder_DeathRecipient_new(RemoteMonitor::BinderDiedCallback)),
+      mClientInfo(info) {
+}
+
+std::string PipeClient::getClientName() {
+    if (mClientInfo == nullptr) {
+        return 0;
+    }
+    std::string name;
+    auto status = mClientInfo->getClientName(&name);
+    return (status.isOk()) ? name : "";
+}
+
+bool PipeClient::startClientMonitor() {
+    mState = std::make_shared<RemoteState>();
+    auto monitor = new RemoteMonitor(mState);
+    auto status = ScopedAStatus::fromStatus(
+        AIBinder_linkToDeath(mClientInfo->asBinder().get(), mDeathMonitor.get(), monitor));
+    return status.isOk();
+}
+
+bool PipeClient::isAlive() {
+    return mState->isAlive();
+}
+
+PipeClient::~PipeClient() {
+}
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace router
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/router/1.0/PipeQuery.cpp b/computepipe/router/1.0/PipeQuery.cpp
new file mode 100644
index 0000000..42e4f0b
--- /dev/null
+++ b/computepipe/router/1.0/PipeQuery.cpp
@@ -0,0 +1,66 @@
+/**
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "PipeQuery.h"
+
+#include "PipeClient.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+namespace V1_0 {
+namespace implementation {
+
+using namespace android::automotive::computepipe::router;
+using namespace aidl::android::automotive::computepipe::registry;
+using namespace aidl::android::automotive::computepipe::runner;
+using namespace ndk;
+
+ScopedAStatus PipeQuery::getGraphList(std::vector<std::string>* outNames) {
+    if (!mRegistry || !outNames) {
+        return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_STATE));
+    }
+    auto names = mRegistry->getPipeList();
+    std::copy(names.begin(), names.end(), std::back_inserter(*outNames));
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus PipeQuery::getPipeRunner(const std::string& graphName,
+                                       const std::shared_ptr<IClientInfo>& info,
+                                       std::shared_ptr<IPipeRunner>* outRunner) {
+    *outRunner = nullptr;
+    if (!mRegistry) {
+        return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_STATE));
+    }
+    std::unique_ptr<ClientHandle> clientHandle = std::make_unique<PipeClient>(info);
+    auto pipeHandle = mRegistry->getClientPipeHandle(graphName, std::move(clientHandle));
+    if (!pipeHandle) {
+        return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_STATE));
+    }
+    auto pipeRunner = pipeHandle->getInterface();
+    *outRunner = pipeRunner->runner;
+    return ScopedAStatus::ok();
+}
+
+const char* PipeQuery::getIfaceName() {
+    return this->descriptor;
+}
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace router
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/router/1.0/PipeRegistration.cpp b/computepipe/router/1.0/PipeRegistration.cpp
new file mode 100644
index 0000000..cff413c
--- /dev/null
+++ b/computepipe/router/1.0/PipeRegistration.cpp
@@ -0,0 +1,56 @@
+/**
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "PipeRegistration.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+namespace V1_0 {
+namespace implementation {
+
+using namespace android::automotive::computepipe;
+using namespace aidl::android::automotive::computepipe::runner;
+using namespace ndk;
+// Methods from ::android::automotive::computepipe::registry::V1_0::IPipeRegistration follow.
+ScopedAStatus PipeRegistration::registerPipeRunner(const std::string& graphName,
+                                                   const std::shared_ptr<IPipeRunner>& graphRunner) {
+    if (!mRegistry) {
+        return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_STATE));
+    }
+    std::unique_ptr<PipeHandle<PipeRunner>> handle = std::make_unique<RunnerHandle>(graphRunner);
+    auto err = mRegistry->RegisterPipe(std::move(handle), graphName);
+    return convertToBinderStatus(err);
+}
+
+ScopedAStatus PipeRegistration::convertToBinderStatus(Error err) {
+    switch (err) {
+        case OK:
+            return ScopedAStatus::ok();
+        default:
+            return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_STATE));
+    }
+}
+
+const char* PipeRegistration::getIfaceName() {
+    return this->descriptor;
+}
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace router
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/router/1.0/PipeRunner.cpp b/computepipe/router/1.0/PipeRunner.cpp
new file mode 100644
index 0000000..cdf1cb1
--- /dev/null
+++ b/computepipe/router/1.0/PipeRunner.cpp
@@ -0,0 +1,65 @@
+/**
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PipeRunner.h"
+
+#include <android/binder_ibinder.h>
+
+#include <mutex>
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+namespace V1_0 {
+namespace implementation {
+
+using namespace aidl::android::automotive::computepipe::runner;
+using namespace ndk;
+
+PipeRunner::PipeRunner(const std::shared_ptr<IPipeRunner>& graphRunner) : runner(graphRunner) {
+}
+
+RunnerHandle::RunnerHandle(const std::shared_ptr<IPipeRunner>& r)
+    : PipeHandle(std::make_unique<PipeRunner>(r)),
+      mDeathMonitor(AIBinder_DeathRecipient_new(RemoteMonitor::BinderDiedCallback)) {
+}
+
+bool RunnerHandle::startPipeMonitor() {
+    mState = std::make_shared<RemoteState>();
+    auto monitor = new RemoteMonitor(mState);
+    auto status = ScopedAStatus::fromStatus(
+        AIBinder_linkToDeath(mInterface->runner->asBinder().get(), mDeathMonitor.get(), monitor));
+    return status.isOk();
+}
+
+bool RunnerHandle::isAlive() {
+    return mState->isAlive();
+}
+
+PipeHandle<PipeRunner>* RunnerHandle::clone() const {
+    return new RunnerHandle(mInterface->runner);
+}
+
+RunnerHandle::~RunnerHandle() {
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace router
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/router/1.0/RemoteState.cpp b/computepipe/router/1.0/RemoteState.cpp
new file mode 100644
index 0000000..9d81fb6
--- /dev/null
+++ b/computepipe/router/1.0/RemoteState.cpp
@@ -0,0 +1,52 @@
+/**
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RemoteState.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+namespace V1_0 {
+namespace implementation {
+
+void RemoteState::markDead() {
+    std::lock_guard<std::mutex> lock(mStateLock);
+    mAlive = false;
+}
+
+bool RemoteState::isAlive() {
+    std::lock_guard<std::mutex> lock(mStateLock);
+    return mAlive;
+}
+
+void RemoteMonitor::binderDied() {
+    auto state = mState.lock();
+    if (state != nullptr) {
+        state->markDead();
+    }
+}
+
+void RemoteMonitor::BinderDiedCallback(void* cookie) {
+    auto monitor = static_cast<RemoteMonitor*>(cookie);
+    monitor->binderDied();
+}
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace router
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/router/1.0/RouterSvc.cpp b/computepipe/router/1.0/RouterSvc.cpp
new file mode 100644
index 0000000..0b296e6
--- /dev/null
+++ b/computepipe/router/1.0/RouterSvc.cpp
@@ -0,0 +1,88 @@
+/**
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "RouterSvc.h"
+
+#include <android/binder_interface_utils.h>
+#include <android/binder_manager.h>
+#include <binder/IServiceManager.h>
+
+#include "PipeQuery.h"
+#include "PipeRegistration.h"
+#include "Registry.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+namespace V1_0 {
+namespace implementation {
+
+const static char kRouterName[] = "router";
+
+Error RouterSvc::parseArgs(int argc, char** argv) {
+    (void)argc;
+    (void)argv;
+    return OK;
+}
+
+Error RouterSvc::initSvc() {
+    mRegistry = std::make_shared<RouterRegistry>();
+    auto ret = initRegistrationEngine();
+    if (ret != OK) {
+        return ret;
+    }
+    ret = initQueryEngine();
+    if (ret != OK) {
+        return ret;
+    }
+    return OK;
+}
+
+Error RouterSvc::initRegistrationEngine() {
+    mRegisterEngine = ndk::SharedRefBase::make<PipeRegistration>(mRegistry);
+    if (!mRegisterEngine) {
+        ALOGE("unable to allocate registration engine");
+        return NOMEM;
+    }
+    std::string name = std::string() + mRegisterEngine->getIfaceName() + "/" + kRouterName;
+    auto status = AServiceManager_addService(mRegisterEngine->asBinder().get(), name.c_str());
+    if (status != STATUS_OK) {
+        ALOGE("unable to add registration service %s", name.c_str());
+        return INTERNAL_ERR;
+    }
+    return OK;
+}
+
+Error RouterSvc::initQueryEngine() {
+    mQueryEngine = ndk::SharedRefBase::make<PipeQuery>(mRegistry);
+    if (!mQueryEngine) {
+        ALOGE("unable to allocate query service");
+        return NOMEM;
+    }
+    std::string name = std::string() + mQueryEngine->getIfaceName() + "/" + kRouterName;
+    auto status = AServiceManager_addService(mQueryEngine->asBinder().get(), name.c_str());
+    if (status != STATUS_OK) {
+        ALOGE("unable to add query service %s", name.c_str());
+        return INTERNAL_ERR;
+    }
+    return OK;
+}
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace router
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/router/1.0/RouterSvc.h b/computepipe/router/1.0/RouterSvc.h
new file mode 100644
index 0000000..08ea59c
--- /dev/null
+++ b/computepipe/router/1.0/RouterSvc.h
@@ -0,0 +1,63 @@
+/**
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_ROUTERSVC
+#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_ROUTERSVC
+
+#include "PipeQuery.h"
+#include "PipeRegistration.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+namespace V1_0 {
+namespace implementation {
+
+namespace router = android::automotive::computepipe::router;
+
+class RouterRegistry : public router::PipeRegistry<PipeRunner> {
+    std ::unique_ptr<PipeHandle<PipeRunner>> getDebuggerPipeHandle(const std::string& name) {
+        return getPipeHandle(name, nullptr);
+    }
+    Error RemoveEntry(const std::string& name) {
+        return DeletePipeHandle(name);
+    }
+};
+
+class RouterSvc {
+  public:
+    router::Error initSvc();
+    router::Error parseArgs(int argc, char** argv);
+    std::string getSvcName() {
+        return mSvcName;
+    }
+
+  private:
+    router::Error initQueryEngine();
+    router::Error initRegistrationEngine();
+
+    std::string mSvcName = "ComputePipeRouter";
+    std::shared_ptr<PipeQuery> mQueryEngine;
+    std::shared_ptr<PipeRegistration> mRegisterEngine;
+    std::shared_ptr<RouterRegistry> mRegistry;
+};
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace router
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+#endif
diff --git a/computepipe/router/1.0/android.automotive.computepipe.router@1.0.rc b/computepipe/router/1.0/android.automotive.computepipe.router@1.0.rc
new file mode 100644
index 0000000..7cf49b3
--- /dev/null
+++ b/computepipe/router/1.0/android.automotive.computepipe.router@1.0.rc
@@ -0,0 +1,5 @@
+service computepipe_router_service /system/bin/android.automotive.computepipe.router@1.0
+    class main
+    priority -20
+    user system
+    group system
diff --git a/computepipe/router/1.0/include/PipeClient.h b/computepipe/router/1.0/include/PipeClient.h
new file mode 100644
index 0000000..32730f4
--- /dev/null
+++ b/computepipe/router/1.0/include/PipeClient.h
@@ -0,0 +1,63 @@
+/**
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_PIPECLIENT
+#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_PIPECLIENT
+
+#include <aidl/android/automotive/computepipe/registry/IClientInfo.h>
+#include <android/binder_auto_utils.h>
+
+#include <functional>
+#include <memory>
+#include <mutex>
+
+#include "ClientHandle.h"
+#include "RemoteState.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+namespace V1_0 {
+namespace implementation {
+
+/**
+ * PipeClient: Encapsulated the IPC interface to the client.
+ *
+ * Allows for querrying the client state
+ */
+class PipeClient : public ClientHandle {
+  public:
+    explicit PipeClient(
+        const std::shared_ptr<aidl::android::automotive::computepipe::registry::IClientInfo>& info);
+    bool startClientMonitor() override;
+    std::string getClientName() override;
+    bool isAlive() override;
+    ~PipeClient();
+
+  private:
+    ::ndk::ScopedAIBinder_DeathRecipient mDeathMonitor;
+    std::shared_ptr<RemoteState> mState;
+    const std::shared_ptr<aidl::android::automotive::computepipe::registry::IClientInfo> mClientInfo;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace router
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+#endif
diff --git a/computepipe/router/1.0/include/PipeQuery.h b/computepipe/router/1.0/include/PipeQuery.h
new file mode 100644
index 0000000..4cf80ac
--- /dev/null
+++ b/computepipe/router/1.0/include/PipeQuery.h
@@ -0,0 +1,56 @@
+/**
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_PIPEQUERY
+#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_PIPEQUERY
+
+#include <aidl/android/automotive/computepipe/registry/BnPipeQuery.h>
+
+#include <memory>
+
+#include "PipeRunner.h"
+#include "Registry.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+namespace V1_0 {
+namespace implementation {
+
+class PipeQuery : public aidl::android::automotive::computepipe::registry::BnPipeQuery {
+  public:
+    explicit PipeQuery(std::shared_ptr<PipeRegistry<PipeRunner>> r) : mRegistry(r) {
+    }
+    ndk::ScopedAStatus getGraphList(::std::vector<std::string>* outNames) override;
+    ndk::ScopedAStatus getPipeRunner(
+        const std::string& graphName,
+        const std::shared_ptr<aidl::android::automotive::computepipe::registry::IClientInfo>& info,
+        std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeRunner>* outRunner)
+        override;
+    const char* getIfaceName();
+
+  private:
+    std::shared_ptr<PipeRegistry<PipeRunner>> mRegistry;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace router
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+#endif
diff --git a/computepipe/router/1.0/include/PipeRegistration.h b/computepipe/router/1.0/include/PipeRegistration.h
new file mode 100644
index 0000000..abd5a99
--- /dev/null
+++ b/computepipe/router/1.0/include/PipeRegistration.h
@@ -0,0 +1,59 @@
+/**
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_PIPEREGISTRATION
+#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_PIPEREGISTRATION
+#include <aidl/android/automotive/computepipe/registry/BnPipeRegistration.h>
+
+#include <memory>
+#include <utility>
+
+#include "PipeRunner.h"
+#include "Registry.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+namespace V1_0 {
+namespace implementation {
+
+class PipeRegistration
+    : public aidl::android::automotive::computepipe::registry::BnPipeRegistration {
+  public:
+    // Method from ::android::automotive::computepipe::registry::V1_0::IPipeRegistration
+    ndk::ScopedAStatus registerPipeRunner(
+        const std::string& graphName,
+        const std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeRunner>&
+            graphRunner) override;
+
+    explicit PipeRegistration(std::shared_ptr<PipeRegistry<PipeRunner>> r) : mRegistry(r) {
+    }
+    const char* getIfaceName();
+
+  private:
+    // Convert internal registry error codes to PipeStatus
+    ndk::ScopedAStatus convertToBinderStatus(Error err);
+    std::shared_ptr<PipeRegistry<PipeRunner>> mRegistry;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace router
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+#endif
diff --git a/computepipe/router/1.0/include/PipeRunner.h b/computepipe/router/1.0/include/PipeRunner.h
new file mode 100644
index 0000000..d3d0453
--- /dev/null
+++ b/computepipe/router/1.0/include/PipeRunner.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_PIPERUNNER
+#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_PIPERUNNER
+#include <aidl/android/automotive/computepipe/runner/IPipeRunner.h>
+
+#include <functional>
+#include <memory>
+#include <mutex>
+
+#include "PipeHandle.h"
+#include "RemoteState.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+namespace V1_0 {
+namespace implementation {
+
+/**
+ * Wrapper for IPC handle
+ */
+struct PipeRunner {
+    explicit PipeRunner(
+        const std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeRunner>&
+            graphRunner);
+    std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeRunner> runner;
+};
+
+/**
+ * Runner Handle to be stored with registry.
+ *
+ * This is used to represent a runner at the time of registration as well as for
+ * query purposes
+ */
+class RunnerHandle : public android::automotive::computepipe::router::PipeHandle<PipeRunner> {
+  public:
+    explicit RunnerHandle(
+        const std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeRunner>& r);
+    /**
+     * override registry pipehandle methods
+     */
+    bool isAlive() override;
+    bool startPipeMonitor() override;
+    PipeHandle<PipeRunner>* clone() const override;
+    ~RunnerHandle();
+
+  private:
+    std::shared_ptr<RemoteState> mState;
+    ndk::ScopedAIBinder_DeathRecipient mDeathMonitor;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace router
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+#endif
diff --git a/computepipe/router/1.0/include/RemoteState.h b/computepipe/router/1.0/include/RemoteState.h
new file mode 100644
index 0000000..6fa34df
--- /dev/null
+++ b/computepipe/router/1.0/include/RemoteState.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_REMOTESTATE
+#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_REMOTESTATE
+
+#include <utils/RefBase.h>
+
+#include <memory>
+#include <mutex>
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+namespace V1_0 {
+namespace implementation {
+
+/**
+ * Wrapper for the Runner State machine
+ */
+class RemoteState {
+  public:
+    RemoteState() = default;
+    void markDead();
+    bool isAlive();
+
+  private:
+    std::mutex mStateLock;
+    bool mAlive = true;
+};
+
+/**
+ * Monitor for tracking remote state
+ */
+class RemoteMonitor : public RefBase {
+  public:
+    explicit RemoteMonitor(const std::weak_ptr<RemoteState>& s) : mState(s) {
+    }
+    static void BinderDiedCallback(void* cookie);
+    void binderDied();
+
+  private:
+    std::weak_ptr<RemoteState> mState;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace router
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+#endif
diff --git a/computepipe/router/1.0/service.cpp b/computepipe/router/1.0/service.cpp
new file mode 100644
index 0000000..6135836
--- /dev/null
+++ b/computepipe/router/1.0/service.cpp
@@ -0,0 +1,36 @@
+#include <android/binder_process.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <iostream>
+#include <thread>
+
+#include "RouterSvc.h"
+
+using namespace android::automotive::computepipe::router::V1_0::implementation;
+
+static RouterSvc gSvcInstance;
+
+#define SVC_NAME() gSvcInstance.getSvcName().c_str()
+
+static void startService() {
+    auto status = gSvcInstance.initSvc();
+    if (status != router::Error::OK) {
+        ALOGE("Could not register service %s", SVC_NAME());
+        exit(2);
+    }
+    ALOGE("Registration Complete");
+}
+
+int main(int argc, char** argv) {
+    auto status = gSvcInstance.parseArgs(argc - 1, &argv[1]);
+    if (status != router::Error::OK) {
+        ALOGE("Bad Args");
+        exit(2);
+    }
+    ABinderProcess_startThreadPool();
+    std::thread registrationThread(startService);
+    ABinderProcess_joinThreadPool();
+    ALOGE("Router thread joined IPC pool");
+    return 1;
+}
diff --git a/computepipe/router/Android.bp b/computepipe/router/Android.bp
new file mode 100644
index 0000000..901e211
--- /dev/null
+++ b/computepipe/router/Android.bp
@@ -0,0 +1,20 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+cc_library_headers {
+    name: "computepipe_router_headers",
+    vendor_available : true,
+    export_include_dirs: ["include"],
+}
diff --git a/computepipe/router/include/ClientHandle.h b/computepipe/router/include/ClientHandle.h
new file mode 100644
index 0000000..4e2796a
--- /dev/null
+++ b/computepipe/router/include/ClientHandle.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_CLIENT_HANDLE
+#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_CLIENT_HANDLE
+
+#include <cstdint>
+#include <string>
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+
+/**
+ * ClientHandle: Represents client state.
+ *
+ * Allows for querrying client state to determine assignment
+ * of pipe handles. This should be instantiated with the client IPC
+ * capabilities to query clients.
+ */
+class ClientHandle {
+  public:
+    /* Get client identifier as defined by the graph */
+    virtual std::string getClientName() = 0;
+    /* Is client alive */
+    virtual bool isAlive() = 0;
+    /* start client monitor */
+    virtual bool startClientMonitor() = 0;
+    virtual ~ClientHandle() {
+    }
+};
+
+}  // namespace router
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif
diff --git a/computepipe/router/include/PipeContext.h b/computepipe/router/include/PipeContext.h
new file mode 100644
index 0000000..2b442d5
--- /dev/null
+++ b/computepipe/router/include/PipeContext.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_PIPE_CONTEXT
+#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_PIPE_CONTEXT
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "ClientHandle.h"
+#include "PipeHandle.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+
+/**
+ * This is the context of a registered pipe.
+ * It tracks assignments to clients and availability.
+ * It also owns the handle to the runner interface.
+ * This is utilized by the registry to track every registered pipe
+ */
+template <typename T>
+class PipeContext {
+  public:
+    // Check if associated runner is alive
+    bool isAlive() const {
+        return mPipeHandle->isAlive();
+    }
+    // Retrieve the graph name
+    std::string getGraphName() const {
+        return mGraphName;
+    }
+    /**
+     * Check if its available for clients
+     *
+     * If no client is assigned mClientHandle is null.
+     * If a client is assigned use it to determine if its still alive,
+     * If its not then the runner is available
+     */
+    bool isAvailable() {
+        if (!mClientHandle) {
+            return true;
+        }
+        if (!mClientHandle->isAlive()) {
+            mClientHandle = nullptr;
+            return true;
+        }
+        return false;
+    }
+    // Mark availability. True if available
+    void setClient(std::unique_ptr<ClientHandle> clientHandle) {
+        mClientHandle.reset(clientHandle.release());
+    }
+    // Set the name of the graph
+    void setGraphName(std::string name) {
+        mGraphName = name;
+    }
+    // Duplicate the pipehandle for retrieval by clients.
+    std::unique_ptr<PipeHandle<T>> dupPipeHandle() {
+        return std::unique_ptr<PipeHandle<T>>(mPipeHandle->clone());
+    }
+    // Setup pipecontext
+    PipeContext(std::unique_ptr<PipeHandle<T>> h, std::string name)
+        : mGraphName(name), mPipeHandle(std::move(h)) {
+    }
+    ~PipeContext() {
+        if (mPipeHandle) {
+            mPipeHandle = nullptr;
+        }
+        if (mClientHandle) {
+            mClientHandle = nullptr;
+        }
+    }
+
+  private:
+    std::string mGraphName;
+    std::unique_ptr<PipeHandle<T>> mPipeHandle;
+    std::unique_ptr<ClientHandle> mClientHandle;
+    bool hasClient;
+};
+
+}  // namespace router
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+#endif
diff --git a/computepipe/router/include/PipeHandle.h b/computepipe/router/include/PipeHandle.h
new file mode 100644
index 0000000..f40b5ba
--- /dev/null
+++ b/computepipe/router/include/PipeHandle.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_PIPE_HANDLE
+#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_PIPE_HANDLE
+
+#include <memory>
+#include <string>
+#include <utility>
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+
+/**
+ * This abstracts the runner interface object and hides its
+ * details from the inner routing logic.
+ */
+template <typename T>
+class PipeHandle {
+  public:
+    explicit PipeHandle(std::unique_ptr<T> intf) : mInterface(std::move(intf)) {
+    }
+    // Check if runner process is still alive
+    virtual bool isAlive() = 0;
+    // Start the monitor for the pipe
+    virtual bool startPipeMonitor() = 0;
+    // Any successful client lookup, clones this handle
+    // The implementation must handle refcounting of remote objects
+    // accordingly.
+    virtual PipeHandle<T>* clone() const = 0;
+    // Retrieve the underlying remote IPC object
+    std::shared_ptr<T> getInterface() {
+        return mInterface;
+    }
+    virtual ~PipeHandle() = default;
+
+  protected:
+    explicit PipeHandle(std::shared_ptr<T> intf) : mInterface(intf){};
+    // Interface object
+    std::shared_ptr<T> mInterface;
+};
+
+}  // namespace router
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif
diff --git a/computepipe/router/include/Registry.h b/computepipe/router/include/Registry.h
new file mode 100644
index 0000000..a668051
--- /dev/null
+++ b/computepipe/router/include/Registry.h
@@ -0,0 +1,172 @@
+/**
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_REGISTRY
+#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_REGISTRY
+
+#include <list>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <utility>
+
+#include "PipeContext.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+
+enum Error {
+    // Operation successful
+    OK = 0,
+    // Unable to find pipe
+    PIPE_NOT_FOUND = -1,
+    // Duplicate pipe
+    DUPLICATE_PIPE = -2,
+    // Runner unavailable
+    RUNNER_BUSY = -3,
+    // Runner dead
+    RUNNER_DEAD = -4,
+    // Permission error
+    BAD_PERMISSION = -5,
+    // Bad args
+    BAD_ARGUMENTS = -6,
+    // no memory
+    NOMEM = -7,
+    // Internal error
+    INTERNAL_ERR = -8,
+};
+
+/**
+ * PipeRegistry
+ *
+ * Class that represents the current database of graphs and their associated
+ * runners.
+ */
+template <typename T>
+class PipeRegistry {
+  public:
+    /**
+     * Returns the runner for a particular graph
+     * If a runner dies, the discovery is made lazily at the point of
+     * attempted retrieval by a client, and the correct result is returned.
+     */
+    std::unique_ptr<PipeHandle<T>> getClientPipeHandle(const std::string& name,
+                                                       std::unique_ptr<ClientHandle> clientHandle) {
+        if (!clientHandle || !clientHandle->startClientMonitor()) {
+            return nullptr;
+        }
+        return getPipeHandle(name, std::move(clientHandle));
+    }
+    /**
+     * Returns list of registered graphs.
+     */
+    std::list<std::string> getPipeList();
+    /**
+     * Registers a graph and the associated runner
+     * if a restarted runner attempts to reregister, the existing entry is checked
+     * and updated if the old entry is found to be invalid.
+     */
+    Error RegisterPipe(std::unique_ptr<PipeHandle<T>> h, const std::string& name) {
+        std::lock_guard<std::mutex> lock(mPipeDbLock);
+        if (mPipeRunnerDb.find(name) == mPipeRunnerDb.end()) {
+            if (!h->startPipeMonitor()) {
+                return RUNNER_DEAD;
+            }
+            mPipeRunnerDb.emplace(
+                name, std::unique_ptr<PipeContext<T>>(new PipeContext<T>(std::move(h), name)));
+            return OK;
+        }
+        if (!mPipeRunnerDb[name]->isAlive()) {
+            mPipeRunnerDb.erase(name);
+            if (!h->startPipeMonitor()) {
+                return RUNNER_DEAD;
+            }
+            mPipeRunnerDb.emplace(
+                name, std::unique_ptr<PipeContext<T>>(new PipeContext<T>(std::move(h), name)));
+            return OK;
+        }
+        return DUPLICATE_PIPE;
+    }
+
+    PipeRegistry() = default;
+
+    ~PipeRegistry() {
+        mPipeRunnerDb.clear();
+    }
+
+  protected:
+    /**
+     * The retrieval of the pipe handle for debug purposes is controlled by the
+     * instantiator of the pipe registry. This is not exposed to the users of
+     * the pipe registry.
+     */
+    std::unique_ptr<PipeHandle<T>> getPipeHandle(const std::string& name,
+                                                 std::unique_ptr<ClientHandle> clientHandle) {
+        std::lock_guard<std::mutex> lock(mPipeDbLock);
+        if (mPipeRunnerDb.find(name) == mPipeRunnerDb.end()) {
+            return nullptr;
+        }
+
+        if (!clientHandle) {
+            return mPipeRunnerDb[name]->isAlive() ? mPipeRunnerDb[name]->dupPipeHandle() : nullptr;
+        }
+
+        if (mPipeRunnerDb[name]->isAvailable()) {
+            if (mPipeRunnerDb[name]->isAlive()) {
+                mPipeRunnerDb[name]->setClient(std::move(clientHandle));
+                return mPipeRunnerDb[name]->dupPipeHandle();
+            } else {
+                mPipeRunnerDb.erase(name);
+                return nullptr;
+            }
+        }
+        return nullptr;
+    }
+    /**
+     * The deletion of specific entries is protected and can be performed by
+     * only the instantiator
+     */
+    Error DeletePipeHandle(const std::string& name) {
+        std::lock_guard<std::mutex> lock(mPipeDbLock);
+        if (mPipeRunnerDb.find(name) == mPipeRunnerDb.end()) {
+            return PIPE_NOT_FOUND;
+        }
+        mPipeRunnerDb.erase(name);
+        return OK;
+    }
+
+  private:
+    std::mutex mPipeDbLock;
+    std::unordered_map<std::string, std::unique_ptr<PipeContext<T>>> mPipeRunnerDb;
+};  // namespace router
+
+template <typename T>
+std::list<std::string> PipeRegistry<T>::getPipeList() {
+    std::list<std::string> pNames;
+
+    std::lock_guard<std::mutex> lock(mPipeDbLock);
+    for (auto const& kv : mPipeRunnerDb) {
+        pNames.push_back(kv.first);
+    }
+    return pNames;
+}
+}  // namespace router
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+#endif
diff --git a/computepipe/runner/Android.bp b/computepipe/runner/Android.bp
new file mode 100644
index 0000000..1445087
--- /dev/null
+++ b/computepipe/runner/Android.bp
@@ -0,0 +1,44 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_headers {
+    name: "computepipe_runner_includes",
+    export_include_dirs: ["include"],
+    static_libs: [
+        "libcomputepipeprotos",
+    ],
+}
+
+cc_library {
+    name: "computepipe_runner_component",
+    srcs: [
+        "EventGenerator.cpp",
+        "PixelFormatUtils.cpp",
+        "RunnerComponent.cpp",
+    ],
+    header_libs: [
+        "computepipe_runner_includes",
+    ],
+    static_libs: [
+        "libcomputepipeprotos",
+    ],
+    shared_libs: [
+        "libbase",
+        "libnativewindow",
+        "libprotobuf-cpp-lite",
+    ],
+    include_dirs: [
+        "packages/services/Car/computepipe",
+    ],
+}
diff --git a/computepipe/runner/EventGenerator.cpp b/computepipe/runner/EventGenerator.cpp
new file mode 100644
index 0000000..c8e4370
--- /dev/null
+++ b/computepipe/runner/EventGenerator.cpp
@@ -0,0 +1,63 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "EventGenerator.h"
+
+#include "RunnerComponent.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace generator {
+
+bool DefaultEvent::isPhaseEntry() const {
+    return mType == static_cast<int>(PhaseState::ENTRY);
+}
+bool DefaultEvent::isAborted() const {
+    return mType == static_cast<int>(PhaseState::ABORTED);
+}
+bool DefaultEvent::isTransitionComplete() const {
+    return mType == static_cast<int>(PhaseState::TRANSITION_COMPLETE);
+}
+
+Status DefaultEvent::dispatchToComponent(const std::shared_ptr<RunnerComponentInterface>& iface) {
+    switch (mPhase) {
+        case RESET:
+            return iface->handleResetPhase(*this);
+        case RUN:
+            return iface->handleExecutionPhase(*this);
+        case STOP_WITH_FLUSH:
+            return iface->handleStopWithFlushPhase(*this);
+        case STOP_IMMEDIATE:
+            return iface->handleStopImmediatePhase(*this);
+    }
+    return Status::ILLEGAL_STATE;
+}
+
+DefaultEvent DefaultEvent::generateEntryEvent(Phase p) {
+    return DefaultEvent(PhaseState::ENTRY, p);
+}
+DefaultEvent DefaultEvent::generateAbortEvent(Phase p) {
+    return DefaultEvent(PhaseState::ABORTED, p);
+}
+DefaultEvent DefaultEvent::generateTransitionCompleteEvent(Phase p) {
+    return DefaultEvent(PhaseState::TRANSITION_COMPLETE, p);
+}
+
+}  // namespace generator
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/PixelFormatUtils.cpp b/computepipe/runner/PixelFormatUtils.cpp
new file mode 100644
index 0000000..9cbd599
--- /dev/null
+++ b/computepipe/runner/PixelFormatUtils.cpp
@@ -0,0 +1,55 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "PixelFormatUtils.h"
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+
+int numBytesPerPixel(AHardwareBuffer_Format format) {
+    switch (format) {
+        case AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
+            return 4;
+        case AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
+            return 3;
+        case AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_S8_UINT:
+            return 1;
+        default:
+            CHECK(false) << "Unrecognized pixel format seen";
+    }
+    return 0;
+}
+
+AHardwareBuffer_Format PixelFormatToHardwareBufferFormat(PixelFormat pixelFormat) {
+    switch (pixelFormat) {
+        case PixelFormat::RGBA:
+            return AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
+        case PixelFormat::RGB:
+            return AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
+        case PixelFormat::GRAY:
+            return AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_S8_UINT;  // TODO: Check if this works
+        default:
+            CHECK(false) << "Unrecognized pixel format seen";
+    }
+    return AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_BLOB;
+}
+
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/RunnerComponent.cpp b/computepipe/runner/RunnerComponent.cpp
new file mode 100644
index 0000000..d3d1482
--- /dev/null
+++ b/computepipe/runner/RunnerComponent.cpp
@@ -0,0 +1,132 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "RunnerComponent.h"
+
+#include "ClientConfig.pb.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+
+/* Is this a notification to enter the phase */
+bool RunnerEvent::isPhaseEntry() const {
+    return false;
+}
+/* Is this a notification that all components have transitioned to the phase */
+bool RunnerEvent::isTransitionComplete() const {
+    return false;
+}
+
+bool RunnerEvent::isAborted() const {
+    return false;
+}
+
+/**
+ * ClientConfig methods
+ */
+Status ClientConfig::dispatchToComponent(const std::shared_ptr<RunnerComponentInterface>& iface) {
+    return iface->handleConfigPhase(*this);
+}
+
+std::string ClientConfig::getSerializedClientConfig() const {
+    proto::ClientConfig config;
+    std::string output;
+
+    config.set_input_config_id(mInputConfigId);
+    config.set_termination_id(mTerminationId);
+    config.set_offload_id(mOffloadId);
+    config.set_profiling_type(mProfilingType);
+    for (auto it : mOutputConfigs) {
+        (*config.mutable_output_options())[it.first] = it.second;
+    }
+    if (!config.SerializeToString(&output)) {
+        return "";
+    }
+    return output;
+}
+
+Status ClientConfig::getInputConfigId(int* outId) const {
+    if (mInputConfigId == kInvalidId) {
+        return Status::ILLEGAL_STATE;
+    }
+    *outId = mInputConfigId;
+    return Status::SUCCESS;
+}
+
+Status ClientConfig::getOffloadId(int* outId) const {
+    if (mOffloadId == kInvalidId) {
+        return Status::ILLEGAL_STATE;
+    }
+    *outId = mOffloadId;
+    return Status::SUCCESS;
+}
+
+Status ClientConfig::getTerminationId(int* outId) const {
+    if (mTerminationId == kInvalidId) {
+        return Status::ILLEGAL_STATE;
+    }
+    *outId = mTerminationId;
+    return Status::SUCCESS;
+}
+
+Status ClientConfig::getOutputStreamConfigs(std::map<int, int>& outputConfig) const {
+    if (mOutputConfigs.empty()) {
+        return Status::ILLEGAL_STATE;
+    }
+    outputConfig = mOutputConfigs;
+    return Status::SUCCESS;
+}
+
+Status ClientConfig::getOptionalConfigs(std::string& outOptional) const {
+    outOptional = mOptionalConfigs;
+    return Status::SUCCESS;
+}
+
+Status ClientConfig::getProfilingType(proto::ProfilingType* profilingType) const {
+    *profilingType = mProfilingType;
+    return Status::SUCCESS;
+}
+
+/**
+ * Methods for ComponentInterface
+ */
+
+/* handle a ConfigPhase related event notification from Runner Engine */
+Status RunnerComponentInterface::handleConfigPhase(const ClientConfig& /* e*/) {
+    return Status::SUCCESS;
+}
+/* handle execution phase notification from Runner Engine */
+Status RunnerComponentInterface::handleExecutionPhase(const RunnerEvent& /* e*/) {
+    return SUCCESS;
+}
+/* handle a stop with flushing semantics phase notification from the engine */
+Status RunnerComponentInterface::handleStopWithFlushPhase(const RunnerEvent& /* e*/) {
+    return SUCCESS;
+}
+/* handle an immediate stop phase notification from the engine */
+Status RunnerComponentInterface::handleStopImmediatePhase(const RunnerEvent& /* e*/) {
+    return SUCCESS;
+}
+/* handle an engine notification to return to reset state */
+Status RunnerComponentInterface::handleResetPhase(const RunnerEvent& /* e*/) {
+    return SUCCESS;
+}
+
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/client_interface/AidlClient.cpp b/computepipe/runner/client_interface/AidlClient.cpp
new file mode 100644
index 0000000..73543ae
--- /dev/null
+++ b/computepipe/runner/client_interface/AidlClient.cpp
@@ -0,0 +1,200 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string>
+
+#include "AidlClient.h"
+
+#include <aidl/android/automotive/computepipe/registry/IPipeRegistration.h>
+#include <android/binder_manager.h>
+#include <android-base/logging.h>
+
+#include <thread>
+
+#include "types/GraphState.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace client_interface {
+namespace aidl_client {
+
+using ::aidl::android::automotive::computepipe::registry::IPipeRegistration;
+using ::ndk::ScopedAStatus;
+
+namespace {
+constexpr char kRegistryInterfaceName[] = "router";
+constexpr int kMaxRouterConnectionAttempts = 10;
+constexpr int kRouterConnectionAttemptIntervalSeconds = 2;
+
+void deathNotifier(void* cookie) {
+    CHECK(cookie);
+    AidlClient* runnerIface = static_cast<AidlClient*>(cookie);
+    runnerIface->routerDied();
+}
+
+}  // namespace
+
+Status AidlClient::dispatchPacketToClient(int32_t streamId,
+                                          const std::shared_ptr<MemHandle> packet) {
+    if (!mPipeRunner) {
+        return Status::ILLEGAL_STATE;
+    }
+    return mPipeRunner->dispatchPacketToClient(streamId, packet);
+}
+
+Status AidlClient::activate() {
+    if (mPipeRunner) {
+        return Status::ILLEGAL_STATE;
+    }
+
+    mPipeRunner = ndk::SharedRefBase::make<AidlClientImpl>(mGraphOptions, mRunnerEngine);
+    mPipeDebugger = ndk::SharedRefBase::make<DebuggerImpl>(mGraphOptions, mRunnerEngine);
+    mPipeRunner->setPipeDebugger(mPipeDebugger);
+
+    std::thread t(&AidlClient::tryRegisterPipeRunner, this);
+    t.detach();
+    return Status::SUCCESS;
+}
+
+Status AidlClient::deliverGraphDebugInfo(const std::string& debugData) {
+    if (mPipeDebugger) {
+        return mPipeDebugger->deliverGraphDebugInfo(debugData);
+    }
+    return Status::SUCCESS;
+}
+
+void AidlClient::routerDied() {
+    std::thread t(&AidlClient::tryRegisterPipeRunner, this);
+    t.detach();
+}
+
+void AidlClient::tryRegisterPipeRunner() {
+    if (!mPipeRunner) {
+        LOG(ERROR) << "Init must be called before attempting to connect to router.";
+        return;
+    }
+
+    const std::string instanceName =
+        std::string() + IPipeRegistration::descriptor + "/" + kRegistryInterfaceName;
+
+    for (int i =0; i < kMaxRouterConnectionAttempts; i++) {
+        if (i != 0) {
+            sleep(kRouterConnectionAttemptIntervalSeconds);
+        }
+
+        ndk::SpAIBinder binder(AServiceManager_getService(instanceName.c_str()));
+        if (binder.get() == nullptr) {
+            LOG(ERROR) << "Failed to connect to router service";
+            continue;
+        }
+
+        // Connected to router registry, register the runner and dealth callback.
+        std::shared_ptr<IPipeRegistration> registryService = IPipeRegistration::fromBinder(binder);
+        ndk::ScopedAStatus status =
+            registryService->registerPipeRunner(mGraphOptions.graph_name().c_str(), mPipeRunner);
+
+        if (!status.isOk()) {
+            LOG(ERROR) << "Failed to register runner instance at router registy.";
+            continue;
+        }
+
+        AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(&deathNotifier);
+        AIBinder_linkToDeath(registryService->asBinder().get(), recipient, this);
+        LOG(ERROR) << "Runner was registered at router registry.";
+        return;
+    }
+
+    LOG(ERROR) << "Max connection attempts reached, router connection attempts failed.";
+    return;
+}
+
+Status AidlClient::handleResetPhase(const RunnerEvent& e) {
+    if (!mPipeRunner) {
+        return Status::ILLEGAL_STATE;
+    }
+    if (e.isTransitionComplete()) {
+        mPipeRunner->stateUpdateNotification(GraphState::RESET);
+    }
+
+    if (mPipeDebugger) {
+        mPipeDebugger->handleResetPhase(e);
+    }
+    return SUCCESS;
+}
+
+Status AidlClient::handleConfigPhase(const ClientConfig& e) {
+    if (!mPipeRunner) {
+        return Status::ILLEGAL_STATE;
+    }
+    if (e.isTransitionComplete()) {
+        mPipeRunner->stateUpdateNotification(GraphState::CONFIG_DONE);
+    } else if (e.isAborted()) {
+        mPipeRunner->stateUpdateNotification(GraphState::ERR_HALT);
+    }
+    if (mPipeDebugger) {
+        mPipeDebugger->handleConfigPhase(e);
+    }
+
+    return SUCCESS;
+}
+
+Status AidlClient::handleExecutionPhase(const RunnerEvent& e) {
+    if (!mPipeRunner) {
+        return Status::ILLEGAL_STATE;
+    }
+    if (e.isTransitionComplete()) {
+        mPipeRunner->stateUpdateNotification(GraphState::RUNNING);
+    } else if (e.isAborted()) {
+        mPipeRunner->stateUpdateNotification(GraphState::ERR_HALT);
+    }
+    if (mPipeDebugger) {
+        mPipeDebugger->handleExecutionPhase(e);
+    }
+    return SUCCESS;
+}
+
+Status AidlClient::handleStopWithFlushPhase(const RunnerEvent& e) {
+    if (!mPipeRunner) {
+        return Status::ILLEGAL_STATE;
+    }
+    if (e.isTransitionComplete()) {
+        mPipeRunner->stateUpdateNotification(GraphState::DONE);
+    }
+    if (mPipeDebugger) {
+        mPipeDebugger->handleStopWithFlushPhase(e);
+    }
+    return SUCCESS;
+}
+
+Status AidlClient::handleStopImmediatePhase(const RunnerEvent& e) {
+    if (!mPipeRunner) {
+        return Status::ILLEGAL_STATE;
+    }
+    if (e.isTransitionComplete()) {
+        mPipeRunner->stateUpdateNotification(GraphState::ERR_HALT);
+    }
+    if (mPipeDebugger) {
+        mPipeDebugger->handleStopImmediatePhase(e);
+    }
+    return SUCCESS;
+}
+
+}  // namespace aidl_client
+}  // namespace client_interface
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/client_interface/AidlClient.h b/computepipe/runner/client_interface/AidlClient.h
new file mode 100644
index 0000000..7b7d54c
--- /dev/null
+++ b/computepipe/runner/client_interface/AidlClient.h
@@ -0,0 +1,73 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_CLIENT_INTERFACE_AIDLCLIENT_H_
+#define COMPUTEPIPE_RUNNER_CLIENT_INTERFACE_AIDLCLIENT_H_
+
+#include <memory>
+
+#include "ClientInterface.h"
+#include "AidlClientImpl.h"
+#include "DebuggerImpl.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace client_interface {
+namespace aidl_client {
+
+class AidlClient : public ClientInterface {
+  public:
+    explicit AidlClient(const proto::Options graphOptions,
+                        const std::shared_ptr<ClientEngineInterface>& engine)
+            : mGraphOptions(graphOptions), mRunnerEngine(engine) {}
+    /**
+     * Override ClientInterface Functions
+     */
+    Status dispatchPacketToClient(int32_t streamId,
+                                  const std::shared_ptr<MemHandle> packet) override;
+    Status activate() override;
+    Status deliverGraphDebugInfo(const std::string& debugData) override;
+    /**
+     * Override RunnerComponentInterface function
+     */
+    Status handleResetPhase(const RunnerEvent& e) override;
+    Status handleConfigPhase(const ClientConfig& e) override;
+    Status handleExecutionPhase(const RunnerEvent& e) override;
+    Status handleStopWithFlushPhase(const RunnerEvent& e) override;
+    Status handleStopImmediatePhase(const RunnerEvent& e) override;
+
+    void routerDied();
+
+    virtual ~AidlClient() = default;
+
+  private:
+    // Attempt to register pipe runner with router. Returns true on success.
+    // This is a blocking API, calling thread will be blocked until router connection is
+    // established or max attempts are made without success.
+    void tryRegisterPipeRunner();
+    const proto::Options mGraphOptions;
+    std::shared_ptr<AidlClientImpl> mPipeRunner = nullptr;
+    std::shared_ptr<DebuggerImpl> mPipeDebugger = nullptr;
+    std::shared_ptr<ClientEngineInterface> mRunnerEngine;
+};
+
+}  // namespace aidl_client
+}  // namespace client_interface
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+#endif  // COMPUTEPIPE_RUNNER_CLIENT_INTERFACE_AIDLCLIENT_H_
diff --git a/computepipe/runner/client_interface/AidlClientImpl.cpp b/computepipe/runner/client_interface/AidlClientImpl.cpp
new file mode 100644
index 0000000..f8157dc
--- /dev/null
+++ b/computepipe/runner/client_interface/AidlClientImpl.cpp
@@ -0,0 +1,370 @@
+// 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.c
+
+#include "AidlClientImpl.h"
+
+#include <vector>
+
+#include "OutputConfig.pb.h"
+#include "PacketDescriptor.pb.h"
+#include "PipeOptionsConverter.h"
+#include "StatusUtil.h"
+
+#include <aidl/android/automotive/computepipe/runner/PacketDescriptor.h>
+#include <aidl/android/automotive/computepipe/runner/PacketDescriptorPacketType.h>
+#include <android-base/logging.h>
+#include <android/binder_auto_utils.h>
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace client_interface {
+namespace aidl_client {
+namespace {
+
+using ::aidl::android::automotive::computepipe::runner::IPipeStateCallback;
+using ::aidl::android::automotive::computepipe::runner::IPipeStream;
+using ::aidl::android::automotive::computepipe::runner::PacketDescriptor;
+using ::aidl::android::automotive::computepipe::runner::PacketDescriptorPacketType;
+using ::aidl::android::automotive::computepipe::runner::PipeDescriptor;
+using ::aidl::android::automotive::computepipe::runner::PipeState;
+using ::ndk::ScopedAStatus;
+
+PipeState ToAidlState(GraphState state) {
+    switch (state) {
+        case RESET:
+            return PipeState::RESET;
+        case CONFIG_DONE:
+            return PipeState::CONFIG_DONE;
+        case RUNNING:
+            return PipeState::RUNNING;
+        case DONE:
+            return PipeState::DONE;
+        case ERR_HALT:
+        default:
+            return PipeState::ERR_HALT;
+    }
+}
+
+void deathNotifier(void* cookie) {
+    CHECK(cookie);
+    AidlClientImpl* iface = static_cast<AidlClientImpl*>(cookie);
+    iface->clientDied();
+}
+
+Status ToAidlPacketType(proto::PacketType type, PacketDescriptorPacketType* outType) {
+    if (outType == nullptr) {
+        return Status::INTERNAL_ERROR;
+    }
+    switch (type) {
+        case proto::SEMANTIC_DATA:
+            *outType = PacketDescriptorPacketType::SEMANTIC_DATA;
+            return Status::SUCCESS;
+        case proto::PIXEL_DATA:
+            *outType = PacketDescriptorPacketType::PIXEL_DATA;
+            return Status::SUCCESS;
+        default:
+            LOG(ERROR) << "unknown packet type " << type;
+            return Status::INVALID_ARGUMENT;
+    }
+}
+
+}  // namespace
+
+Status AidlClientImpl::DispatchSemanticData(int32_t streamId,
+                                           const std::shared_ptr<MemHandle>& packetHandle) {
+    PacketDescriptor desc;
+
+    if (mPacketHandlers.find(streamId) == mPacketHandlers.end()) {
+        LOG(ERROR) << "Bad streamId";
+        return Status::INVALID_ARGUMENT;
+    }
+    Status status = ToAidlPacketType(packetHandle->getType(), &desc.type);
+    if (status != SUCCESS) {
+        return status;
+    }
+    desc.data = std::vector(reinterpret_cast<const signed char*>(packetHandle->getData()),
+        reinterpret_cast<const signed char*>(packetHandle->getData() + packetHandle->getSize()));
+    desc.size = packetHandle->getSize();
+    if (static_cast<int32_t>(desc.data.size()) != desc.size) {
+        LOG(ERROR) << "mismatch in char data size and reported size";
+        return Status::INVALID_ARGUMENT;
+    }
+    desc.sourceTimeStampMillis = packetHandle->getTimeStamp();
+    desc.bufId = 0;
+    ScopedAStatus ret = mPacketHandlers[streamId]->deliverPacket(desc);
+    if (!ret.isOk()) {
+        LOG(ERROR) << "Dropping Semantic packet due to error ";
+    }
+    return Status::SUCCESS;
+}
+
+Status AidlClientImpl::DispatchPixelData(int32_t streamId,
+                                         const std::shared_ptr<MemHandle>& packetHandle) {
+    PacketDescriptor desc;
+
+    if (mPacketHandlers.find(streamId) == mPacketHandlers.end()) {
+        LOG(ERROR) << "Bad stream id";
+        return Status::INVALID_ARGUMENT;
+    }
+    Status status = ToAidlPacketType(packetHandle->getType(), &desc.type);
+    if (status != Status::SUCCESS) {
+        LOG(ERROR) << "Invalid packet type";
+        return status;
+    }
+
+    // Copies the native handle to the aidl interface.
+    const native_handle_t* nativeHandle =
+        AHardwareBuffer_getNativeHandle(packetHandle->getHardwareBuffer());
+    for (int i = 0; i < nativeHandle->numFds; i++) {
+        desc.handle.handle.fds.push_back(ndk::ScopedFileDescriptor(nativeHandle->data[i]));
+    }
+    for (int i = 0; i < nativeHandle->numInts; i++) {
+        desc.handle.handle.ints.push_back(nativeHandle->data[i + nativeHandle->numFds]);
+    }
+
+    // Copies buffer descriptor to the aidl interface.
+    AHardwareBuffer_Desc bufferDesc;
+    AHardwareBuffer_describe(packetHandle->getHardwareBuffer(), &bufferDesc);
+    desc.handle.description.width = bufferDesc.width;
+    desc.handle.description.height = bufferDesc.height;
+    desc.handle.description.stride = bufferDesc.stride;
+    desc.handle.description.layers = bufferDesc.layers;
+    desc.handle.description.format =
+        static_cast<::aidl::android::hardware::graphics::common::PixelFormat>(bufferDesc.format);
+    desc.handle.description.usage =
+        static_cast<::aidl::android::hardware::graphics::common::BufferUsage>(bufferDesc.usage);
+
+    desc.bufId = packetHandle->getBufferId();
+    desc.sourceTimeStampMillis = packetHandle->getTimeStamp();
+
+    ScopedAStatus ret = mPacketHandlers[streamId]->deliverPacket(desc);
+    if (!ret.isOk()) {
+        LOG(ERROR) << "Unable to deliver packet. Dropping it and returning an error";
+        return Status::INTERNAL_ERROR;
+    }
+    return Status::SUCCESS;
+}
+
+// Thread-safe function to deliver new packets to client.
+Status AidlClientImpl::dispatchPacketToClient(int32_t streamId,
+                                              const std::shared_ptr<MemHandle>& packetHandle) {
+    // TODO(146464279) implement.
+    if (!packetHandle) {
+        LOG(ERROR) << "invalid packetHandle";
+        return Status::INVALID_ARGUMENT;
+    }
+    proto::PacketType packetType = packetHandle->getType();
+    switch (packetType) {
+        case proto::SEMANTIC_DATA:
+            return DispatchSemanticData(streamId, packetHandle);
+        case proto::PIXEL_DATA:
+            return DispatchPixelData(streamId, packetHandle);
+        default:
+            LOG(ERROR) << "Unsupported packet type " << packetHandle->getType();
+            return Status::INVALID_ARGUMENT;
+    }
+    return Status::SUCCESS;
+}
+
+void AidlClientImpl::setPipeDebugger(
+        const std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeDebugger>&
+        pipeDebugger) {
+    mPipeDebugger = pipeDebugger;
+}
+
+Status AidlClientImpl::stateUpdateNotification(const GraphState newState) {
+    if (mClientStateChangeCallback) {
+        (void)mClientStateChangeCallback->handleState(ToAidlState(newState));
+    }
+    return Status::SUCCESS;
+}
+
+ScopedAStatus AidlClientImpl::getPipeDescriptor(PipeDescriptor* _aidl_return) {
+    if (_aidl_return == nullptr) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    *_aidl_return = OptionsToPipeDescriptor(mGraphOptions);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus AidlClientImpl::setPipeInputSource(int32_t configId) {
+    if (!isClientInitDone()) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+
+    proto::ConfigurationCommand configurationCommand;
+    configurationCommand.mutable_set_input_source()->set_source_id(configId);
+
+    Status status = mEngine->processClientConfigUpdate(configurationCommand);
+    return ToNdkStatus(status);
+}
+
+ScopedAStatus AidlClientImpl::setPipeOffloadOptions(int32_t configId) {
+    if (!isClientInitDone()) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+
+    proto::ConfigurationCommand configurationCommand;
+    configurationCommand.mutable_set_offload_offload()->set_offload_option_id(configId);
+
+    Status status = mEngine->processClientConfigUpdate(configurationCommand);
+    return ToNdkStatus(status);
+}
+
+ScopedAStatus AidlClientImpl::setPipeTermination(int32_t configId) {
+    if (!isClientInitDone()) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+
+    proto::ConfigurationCommand configurationCommand;
+    configurationCommand.mutable_set_termination_option()->set_termination_option_id(configId);
+
+    Status status = mEngine->processClientConfigUpdate(configurationCommand);
+    return ToNdkStatus(status);
+}
+
+ScopedAStatus AidlClientImpl::init(const std::shared_ptr<IPipeStateCallback>& stateCb) {
+    if (isClientInitDone()) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+
+    AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(&deathNotifier);
+    AIBinder_linkToDeath(stateCb->asBinder().get(), recipient, this);
+
+    mClientStateChangeCallback = stateCb;
+    return ScopedAStatus::ok();
+}
+
+bool AidlClientImpl::isClientInitDone() {
+    if (mClientStateChangeCallback == nullptr) {
+        return false;
+    }
+    return true;
+}
+
+void AidlClientImpl::clientDied() {
+    LOG(INFO) << "Client has died";
+    releaseRunner();
+}
+
+ScopedAStatus AidlClientImpl::setPipeOutputConfig(int32_t streamId, int32_t maxInFlightCount,
+                                                  const std::shared_ptr<IPipeStream>& handler) {
+    if (!isClientInitDone()) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+
+    if (mPacketHandlers.find(streamId) != mPacketHandlers.end()) {
+        LOG(INFO) << "Handler for stream id " << streamId
+                  << " has already"
+                     " been registered.";
+        return ToNdkStatus(INVALID_ARGUMENT);
+    }
+
+    mPacketHandlers.insert(std::pair<int, std::shared_ptr<IPipeStream>>(streamId, handler));
+
+    proto::ConfigurationCommand configurationCommand;
+    configurationCommand.mutable_set_output_stream()->set_stream_id(streamId);
+    configurationCommand.mutable_set_output_stream()->set_max_inflight_packets_count(
+            maxInFlightCount);
+    Status status = mEngine->processClientConfigUpdate(configurationCommand);
+
+    if (status != SUCCESS) {
+        LOG(INFO) << "Failed to register handler for stream id " << streamId;
+        mPacketHandlers.erase(streamId);
+    }
+    return ToNdkStatus(status);
+}
+
+ScopedAStatus AidlClientImpl::applyPipeConfigs() {
+    if (!isClientInitDone()) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+
+    proto::ControlCommand controlCommand;
+    *controlCommand.mutable_apply_configs() = proto::ApplyConfigs();
+
+    Status status = mEngine->processClientCommand(controlCommand);
+    return ToNdkStatus(status);
+}
+
+ScopedAStatus AidlClientImpl::resetPipeConfigs() {
+    if (!isClientInitDone()) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+
+    proto::ControlCommand controlCommand;
+    *controlCommand.mutable_reset_configs() = proto::ResetConfigs();
+
+    Status status = mEngine->processClientCommand(controlCommand);
+    return ToNdkStatus(status);
+}
+
+ScopedAStatus AidlClientImpl::startPipe() {
+    proto::ControlCommand controlCommand;
+    *controlCommand.mutable_start_graph() = proto::StartGraph();
+
+    Status status = mEngine->processClientCommand(controlCommand);
+    return ToNdkStatus(status);
+}
+
+ScopedAStatus AidlClientImpl::stopPipe() {
+    proto::ControlCommand controlCommand;
+    *controlCommand.mutable_stop_graph() = proto::StopGraph();
+
+    Status status = mEngine->processClientCommand(controlCommand);
+    return ToNdkStatus(status);
+}
+
+ScopedAStatus AidlClientImpl::doneWithPacket(int32_t bufferId, int32_t streamId) {
+    auto it = mPacketHandlers.find(streamId);
+    if (it == mPacketHandlers.end()) {
+        LOG(ERROR) << "Bad stream id provided for doneWithPacket call";
+        return ToNdkStatus(Status::INVALID_ARGUMENT);
+    }
+
+    return ToNdkStatus(mEngine->freePacket(bufferId, streamId));
+}
+
+ScopedAStatus AidlClientImpl::getPipeDebugger(
+    std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeDebugger>*
+    _aidl_return) {
+    if (_aidl_return == nullptr) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    if (mPipeDebugger == nullptr) {
+        return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+    }
+    *_aidl_return = mPipeDebugger;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus AidlClientImpl::releaseRunner() {
+    proto::ControlCommand controlCommand;
+    *controlCommand.mutable_death_notification() = proto::DeathNotification();
+
+    Status status = mEngine->processClientCommand(controlCommand);
+
+    mClientStateChangeCallback = nullptr;
+    mPacketHandlers.clear();
+    return ToNdkStatus(status);
+}
+
+}  // namespace aidl_client
+}  // namespace client_interface
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/client_interface/AidlClientImpl.h b/computepipe/runner/client_interface/AidlClientImpl.h
new file mode 100644
index 0000000..594d2cb
--- /dev/null
+++ b/computepipe/runner/client_interface/AidlClientImpl.h
@@ -0,0 +1,116 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_CLIENT_INTERFACE_AIDLCLIENTIMPL_H_
+#define COMPUTEPIPE_RUNNER_CLIENT_INTERFACE_AIDLCLIENTIMPL_H_
+#include <aidl/android/automotive/computepipe/runner/BnPipeRunner.h>
+#include <aidl/android/automotive/computepipe/runner/BnPipeDebugger.h>
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "ClientEngineInterface.h"
+#include "MemHandle.h"
+#include "Options.pb.h"
+#include "types/GraphState.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace client_interface {
+namespace aidl_client {
+
+// RunnerInterface registers an IPipeRunner interface with computepipe router.
+// RunnerInterface handles binder IPC calls and invokes appropriate callbacks.
+class AidlClientImpl : public aidl::android::automotive::computepipe::runner::BnPipeRunner {
+  public:
+    explicit AidlClientImpl(const proto::Options graphOptions,
+                            const std::shared_ptr<ClientEngineInterface>& engine)
+        : mGraphOptions(graphOptions), mEngine(engine) {
+    }
+
+    ~AidlClientImpl() {
+    }
+
+    Status dispatchPacketToClient(int32_t streamId, const std::shared_ptr<MemHandle>& packetHandle);
+    void setPipeDebugger(
+        const std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeDebugger>&
+        pipeDebugger);
+
+    Status stateUpdateNotification(const GraphState newState);
+
+    // Methods from android::automotive::computepipe::runner::BnPipeRunner
+    ndk::ScopedAStatus init(
+        const std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeStateCallback>&
+            stateCb) override;
+    ndk::ScopedAStatus getPipeDescriptor(
+        aidl::android::automotive::computepipe::runner::PipeDescriptor* _aidl_return) override;
+    ndk::ScopedAStatus setPipeInputSource(int32_t configId) override;
+    ndk::ScopedAStatus setPipeOffloadOptions(int32_t configId) override;
+    ndk::ScopedAStatus setPipeTermination(int32_t configId) override;
+    ndk::ScopedAStatus setPipeOutputConfig(
+        int32_t streamId, int32_t maxInFlightCount,
+        const std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeStream>& handler)
+        override;
+    ndk::ScopedAStatus applyPipeConfigs() override;
+    ndk::ScopedAStatus resetPipeConfigs() override;
+    ndk::ScopedAStatus startPipe() override;
+    ndk::ScopedAStatus stopPipe() override;
+    ndk::ScopedAStatus doneWithPacket(int32_t bufferId, int32_t streamId) override;
+
+    ndk::ScopedAStatus getPipeDebugger(
+        std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeDebugger>*
+        _aidl_return) override;
+
+    ndk::ScopedAStatus releaseRunner() override;
+
+    void clientDied();
+
+  private:
+    // Dispatch semantic data to client. Has copy semantics and does not expect
+    // client to invoke doneWithPacket.
+    Status DispatchSemanticData(int32_t streamId, const std::shared_ptr<MemHandle>& packetHandle);
+
+    // Dispatch pixel data to client. Expects the client to invoke done with
+    // packet.
+    Status DispatchPixelData(int32_t streamId, const std::shared_ptr<MemHandle>& packetHandle);
+
+    bool isClientInitDone();
+
+    const proto::Options mGraphOptions;
+    std::shared_ptr<ClientEngineInterface> mEngine;
+
+    // If value of mClientStateChangeCallback is null pointer, client has not
+    // invoked init.
+    std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeStateCallback>
+        mClientStateChangeCallback = nullptr;
+
+    std::map<int, std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeStream>>
+        mPacketHandlers;
+
+    std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeDebugger> mPipeDebugger =
+        nullptr;
+};
+
+}  // namespace aidl_client
+}  // namespace client_interface
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // COMPUTEPIPE_RUNNER_CLIENT_INTERFACE_AIDLCLIENTIMPL_H_
diff --git a/computepipe/runner/client_interface/Android.bp b/computepipe/runner/client_interface/Android.bp
new file mode 100644
index 0000000..588aa5c
--- /dev/null
+++ b/computepipe/runner/client_interface/Android.bp
@@ -0,0 +1,47 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library {
+    name: "computepipe_client_interface",
+    srcs: [
+        "AidlClient.cpp",
+        "AidlClientImpl.cpp",
+        "DebuggerImpl.cpp",
+        "Factory.cpp",
+        "PipeOptionsConverter.cpp",
+        "StatusUtil.cpp",
+    ],
+    export_include_dirs: ["include"],
+    header_libs: [
+        "computepipe_runner_includes",
+    ],
+    static_libs: [
+        "libcomputepipeprotos",
+    ],
+    shared_libs: [
+        "computepipe_runner_component",
+        "libbase",
+        "libbinder_ndk",
+        "liblog",
+        "libnativewindow",
+        "libutils",
+        "android.automotive.computepipe.runner-ndk_platform",
+        "android.automotive.computepipe.registry-ndk_platform",
+        "libprotobuf-cpp-lite",
+    ],
+    include_dirs: [
+        "packages/services/Car/computepipe",
+    ],
+    cflags: ["-DLOG_TAG=\"RunnerIpcInterface\""],
+}
diff --git a/computepipe/runner/client_interface/DebuggerImpl.cpp b/computepipe/runner/client_interface/DebuggerImpl.cpp
new file mode 100644
index 0000000..67d516a
--- /dev/null
+++ b/computepipe/runner/client_interface/DebuggerImpl.cpp
@@ -0,0 +1,261 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "DebuggerImpl.h"
+#include "ProfilingType.pb.h"
+#include "ConfigurationCommand.pb.h"
+#include "StatusUtil.h"
+
+#include <android-base/logging.h>
+#include <android-base/file.h>
+#include <binder/ParcelFileDescriptor.h>
+
+#include <errno.h>
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace client_interface {
+namespace aidl_client {
+namespace {
+
+using ::std::literals::chrono_literals::operator""ms;
+using ::aidl::android::automotive::computepipe::runner::PipeProfilingType;
+using ::aidl::android::automotive::computepipe::runner::ProfilingData;
+
+using ::ndk::ScopedAStatus;
+
+constexpr std::chrono::milliseconds kProfilingDataReadTimeout = 50ms;
+
+proto::ProfilingType ToProtoProfilingType(PipeProfilingType type) {
+    switch (type) {
+        case PipeProfilingType::LATENCY:
+            return proto::ProfilingType::LATENCY;
+        case PipeProfilingType::TRACE_EVENTS:
+            return proto::ProfilingType::TRACE_EVENTS;
+    }
+}
+
+PipeProfilingType ToAidlProfilingType(proto::ProfilingType type) {
+    switch (type) {
+        case proto::ProfilingType::LATENCY:
+            return PipeProfilingType::LATENCY;
+        case proto::ProfilingType::TRACE_EVENTS:
+            return PipeProfilingType::TRACE_EVENTS;
+        case proto::ProfilingType::DISABLED:
+            LOG(ERROR) << "Attempt to convert invalid profiling type to aidl type.";
+            return PipeProfilingType::LATENCY;
+    }
+}
+
+Status RecursiveCreateDir(const std::string& dirName) {
+    if (dirName == "/") {
+        return Status::SUCCESS;
+    }
+
+    DIR *directory = opendir(dirName.c_str());
+    // Check if directory exists.
+    if (directory) {
+        closedir(directory);
+        return Status::SUCCESS;
+    }
+
+    std::string parentDirName = android::base::Dirname(dirName);
+    if (!parentDirName.empty()) {
+        Status status = RecursiveCreateDir(parentDirName);
+        if (status != Status::SUCCESS) {
+            return status;
+        }
+    }
+
+    // mkdir expects the flag as bits it is essential to send 0777 which is
+    // interpreted in octal rather than 777 which is interpreted in decimal.
+    if (!mkdir(dirName.c_str(), 0777)) {
+        return Status::SUCCESS;
+    } else {
+        LOG(ERROR) << "Failed to create directory - " << errno;
+        return Status::INTERNAL_ERROR;
+    }
+}
+
+}  // namespace
+
+ndk::ScopedAStatus DebuggerImpl::setPipeProfileOptions(PipeProfilingType in_type) {
+    mProfilingType = in_type;
+    proto::ConfigurationCommand command;
+    command.mutable_set_profile_options()->set_profile_type(ToProtoProfilingType(mProfilingType));
+    std::shared_ptr<ClientEngineInterface> engineSp = mEngine.lock();
+    if (!engineSp) {
+        return ToNdkStatus(Status::INTERNAL_ERROR);
+    }
+    Status status = engineSp->processClientConfigUpdate(command);
+    return ToNdkStatus(status);
+}
+
+ScopedAStatus DebuggerImpl::startPipeProfiling() {
+    if (mGraphState != GraphState::RUNNING) {
+        LOG(ERROR) << "Attempting to start profiling when the graph is not in the running state.";
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    proto::ControlCommand controlCommand;
+    *controlCommand.mutable_start_pipe_profile() = proto::StartPipeProfile();
+    std::shared_ptr<ClientEngineInterface> engineSp = mEngine.lock();
+    if (!engineSp) {
+        return ToNdkStatus(Status::INTERNAL_ERROR);
+    }
+    Status status = engineSp->processClientCommand(controlCommand);
+    return ToNdkStatus(status);
+}
+
+ScopedAStatus DebuggerImpl::stopPipeProfiling() {
+    proto::ControlCommand controlCommand;
+    *controlCommand.mutable_stop_pipe_profile() = proto::StopPipeProfile();
+    std::shared_ptr<ClientEngineInterface> engineSp = mEngine.lock();
+    if (!engineSp) {
+        return ToNdkStatus(Status::INTERNAL_ERROR);
+    }
+    Status status = engineSp->processClientCommand(controlCommand);
+    if (status != Status::SUCCESS) {
+        return ToNdkStatus(status);
+    }
+
+    proto::ControlCommand controlCommand2;
+    *controlCommand2.mutable_read_debug_data() = proto::ReadDebugData();
+    status = engineSp->processClientCommand(controlCommand2);
+    if (status != Status::SUCCESS) {
+        return ToNdkStatus(status);
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus DebuggerImpl::getPipeProfilingInfo(ProfilingData* _aidl_return) {
+    if (!_aidl_return) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    std::unique_lock<std::mutex> lk(mLock);
+    if (!mWait.wait_for(lk, kProfilingDataReadTimeout, [this]() {
+                    return mProfilingData.size != 0;
+                })) {
+        LOG(ERROR) << "No profiling data was found.";
+        proto::ProfilingType profilingType = ToProtoProfilingType(mProfilingType);
+        if (profilingType == proto::ProfilingType::DISABLED) {
+            LOG(ERROR) << "Profiling was disabled.";
+            return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+        }
+        _aidl_return->type = ToAidlProfilingType(profilingType);
+        _aidl_return->size = 0;
+        return ScopedAStatus::ok();
+    }
+
+    _aidl_return->type = mProfilingData.type;
+    _aidl_return->size = mProfilingData.size;
+    _aidl_return->dataFds = std::move(mProfilingData.dataFds);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus DebuggerImpl::releaseDebugger() {
+    if (mGraphState == GraphState::RUNNING || mGraphState == GraphState::RESET) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+
+    proto::ControlCommand controlCommand;
+    *controlCommand.mutable_release_debugger() = proto::ReleaseDebugger();
+    std::shared_ptr<ClientEngineInterface> engineSp = mEngine.lock();
+    if (!engineSp) {
+        return ToNdkStatus(Status::INTERNAL_ERROR);
+    }
+    Status status = engineSp->processClientCommand(controlCommand);
+
+    std::lock_guard<std::mutex> lk(mLock);
+    mProfilingData.size = 0;
+    mProfilingData.dataFds.clear();
+    return ToNdkStatus(status);
+}
+
+Status DebuggerImpl::handleConfigPhase(const ClientConfig& e) {
+    if (e.isTransitionComplete()) {
+        mGraphState = GraphState::CONFIG_DONE;
+    }
+    return Status::SUCCESS;
+}
+
+Status DebuggerImpl::handleExecutionPhase(const RunnerEvent& e) {
+    if (e.isTransitionComplete()) {
+        mGraphState = GraphState::RUNNING;
+    }
+    if (e.isAborted()) {
+        mGraphState = GraphState::ERR_HALT;
+    }
+    return Status::SUCCESS;
+}
+
+Status DebuggerImpl::handleStopWithFlushPhase(const RunnerEvent& e) {
+    if (e.isTransitionComplete()) {
+        mGraphState = GraphState::DONE;
+    }
+    if (e.isAborted()) {
+        mGraphState = GraphState::ERR_HALT;
+    }
+    return Status::SUCCESS;
+}
+
+Status DebuggerImpl::handleStopImmediatePhase(const RunnerEvent& e) {
+    if (e.isTransitionComplete() || e.isAborted()) {
+        mGraphState = GraphState::ERR_HALT;
+    }
+    return Status::SUCCESS;
+}
+
+Status DebuggerImpl::handleResetPhase(const RunnerEvent& e) {
+    if (e.isPhaseEntry()) {
+        mGraphState = GraphState::RESET;
+    }
+    return Status::SUCCESS;
+}
+
+Status DebuggerImpl::deliverGraphDebugInfo(const std::string& debugData) {
+    Status status = RecursiveCreateDir(mProfilingDataDirName);
+    if (status != Status::SUCCESS) {
+        return status;
+    }
+
+    std::string profilingDataFilePath = mProfilingDataDirName + "/" + mGraphOptions.graph_name();
+    std::string fileRemoveError;
+    if (!android::base::RemoveFileIfExists(profilingDataFilePath, &fileRemoveError)) {
+        LOG(ERROR) << "Failed to remove file " << profilingDataFilePath << ", error: "
+            << fileRemoveError;
+        return Status::INTERNAL_ERROR;
+    }
+    if (!android::base::WriteStringToFile(debugData, profilingDataFilePath)) {
+        LOG(ERROR) << "Failed to write profiling data to file at path " << profilingDataFilePath;
+        return Status::INTERNAL_ERROR;
+    }
+
+    std::lock_guard<std::mutex> lk(mLock);
+    mProfilingData.type = mProfilingType;
+    mProfilingData.size = debugData.size();
+    mProfilingData.dataFds.emplace_back(
+        ndk::ScopedFileDescriptor(open(profilingDataFilePath.c_str(), O_CREAT, O_RDWR)));
+    mWait.notify_one();
+    return Status::SUCCESS;
+}
+
+}  // namespace aidl_client
+}  // namespace client_interface
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/client_interface/DebuggerImpl.h b/computepipe/runner/client_interface/DebuggerImpl.h
new file mode 100644
index 0000000..d1daf42
--- /dev/null
+++ b/computepipe/runner/client_interface/DebuggerImpl.h
@@ -0,0 +1,84 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_CLIENT_INTERFACE_DEBUGGERIMPL_H_
+#define COMPUTEPIPE_RUNNER_CLIENT_INTERFACE_DEBUGGERIMPL_H_
+#include <aidl/android/automotive/computepipe/runner/BnPipeDebugger.h>
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+
+#include "ClientEngineInterface.h"
+#include "RunnerComponent.h"
+#include "types/GraphState.h"
+#include "types/Status.h"
+#include "Options.pb.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace client_interface {
+namespace aidl_client {
+
+// RunnerInterface registers an IPipeRunner interface with computepipe router.
+// RunnerInterface handles binder IPC calls and invokes appropriate callbacks.
+class DebuggerImpl : public aidl::android::automotive::computepipe::runner::BnPipeDebugger,
+                     public RunnerComponentInterface  {
+  public:
+    explicit DebuggerImpl(const proto::Options graphOptions,
+                          const std::shared_ptr<ClientEngineInterface>& engine)
+            : mEngine(engine), mGraphOptions(graphOptions) {}
+
+    // Methods from android::automotive::computepipe::runner::BnPipeDebugger
+    ndk::ScopedAStatus setPipeProfileOptions(
+        aidl::android::automotive::computepipe::runner::PipeProfilingType in_type) override;
+    ndk::ScopedAStatus startPipeProfiling() override;
+    ndk::ScopedAStatus stopPipeProfiling() override;
+    ndk::ScopedAStatus getPipeProfilingInfo(
+        aidl::android::automotive::computepipe::runner::ProfilingData* _aidl_return) override;
+    ndk::ScopedAStatus releaseDebugger() override;
+
+    // Methods from RunnerComponentInterface
+    Status handleConfigPhase(const ClientConfig& e) override;
+    Status handleExecutionPhase(const RunnerEvent& e) override;
+    Status handleStopWithFlushPhase(const RunnerEvent& e) override;
+    Status handleStopImmediatePhase(const RunnerEvent& e) override;
+    Status handleResetPhase(const RunnerEvent& e) override;
+
+    Status deliverGraphDebugInfo(const std::string& debugData);
+
+  private:
+    std::weak_ptr<ClientEngineInterface> mEngine;
+
+    GraphState mGraphState = GraphState::RESET;
+    aidl::android::automotive::computepipe::runner::PipeProfilingType mProfilingType;
+    proto::Options mGraphOptions;
+    aidl::android::automotive::computepipe::runner::ProfilingData mProfilingData;
+
+    // Lock for mProfilingData.
+    std::mutex mLock;
+    std::condition_variable mWait;
+    const std::string mProfilingDataDirName = "/data/computepipe/profiling";
+};
+
+}  // namespace aidl_client
+}  // namespace client_interface
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // COMPUTEPIPE_RUNNER_CLIENT_INTERFACE_DEBUGGERIMPL_H_
diff --git a/computepipe/runner/client_interface/Factory.cpp b/computepipe/runner/client_interface/Factory.cpp
new file mode 100644
index 0000000..36dd834
--- /dev/null
+++ b/computepipe/runner/client_interface/Factory.cpp
@@ -0,0 +1,48 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "AidlClient.h"
+#include "ClientInterface.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace client_interface {
+
+using aidl_client::AidlClient;
+
+namespace {
+
+std::unique_ptr<AidlClient> buildAidlClient(const proto::Options& options,
+                                            const std::shared_ptr<ClientEngineInterface>& engine) {
+    return std::make_unique<AidlClient>(options, engine);
+}
+
+}  // namespace
+
+std::unique_ptr<ClientInterface> ClientInterfaceFactory::createClientInterface(
+    std::string iface, const proto::Options graphOptions,
+    const std::shared_ptr<ClientEngineInterface>& engine) {
+    if (iface == "aidl") {
+        return buildAidlClient(graphOptions, engine);
+    }
+    return nullptr;
+}
+
+}  // namespace client_interface
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/client_interface/PipeOptionsConverter.cpp b/computepipe/runner/client_interface/PipeOptionsConverter.cpp
new file mode 100644
index 0000000..12b2b3e
--- /dev/null
+++ b/computepipe/runner/client_interface/PipeOptionsConverter.cpp
@@ -0,0 +1,222 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "PipeOptionsConverter.h"
+
+#include "aidl/android/automotive/computepipe/runner/PipeInputConfigInputType.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace client_interface {
+namespace aidl_client {
+
+using ::aidl::android::automotive::computepipe::runner::PipeDescriptor;
+using ::aidl::android::automotive::computepipe::runner::PipeInputConfig;
+using ::aidl::android::automotive::computepipe::runner::PipeInputConfigCameraDesc;
+using ::aidl::android::automotive::computepipe::runner::PipeInputConfigCameraType;
+using ::aidl::android::automotive::computepipe::runner::PipeInputConfigFormatType;
+using ::aidl::android::automotive::computepipe::runner::PipeInputConfigImageFileType;
+using ::aidl::android::automotive::computepipe::runner::PipeInputConfigInputSourceDesc;
+using ::aidl::android::automotive::computepipe::runner::PipeInputConfigInputType;
+using ::aidl::android::automotive::computepipe::runner::PipeInputConfigVideoFileType;
+using ::aidl::android::automotive::computepipe::runner::PipeOffloadConfig;
+using ::aidl::android::automotive::computepipe::runner::PipeOffloadConfigOffloadType;
+using ::aidl::android::automotive::computepipe::runner::PipeOutputConfig;
+using ::aidl::android::automotive::computepipe::runner::PipeOutputConfigPacketType;
+using ::aidl::android::automotive::computepipe::runner::PipeTerminationConfig;
+using ::aidl::android::automotive::computepipe::runner::PipeTerminationConfigTerminationType;
+
+namespace {
+
+PipeInputConfigInputType ConvertInputType(proto::InputStreamConfig::InputType type) {
+    switch (type) {
+        case proto::InputStreamConfig::CAMERA:
+            return PipeInputConfigInputType::CAMERA;
+        case proto::InputStreamConfig::VIDEO_FILE:
+            return PipeInputConfigInputType::VIDEO_FILE;
+        case proto::InputStreamConfig::IMAGE_FILES:
+            return PipeInputConfigInputType::IMAGE_FILES;
+    }
+}
+
+PipeInputConfigCameraType ConvertCameraType(proto::CameraConfig::CameraType type) {
+    switch (type) {
+        case proto::CameraConfig::DRIVER_VIEW_CAMERA:
+            return PipeInputConfigCameraType::DRIVER_VIEW_CAMERA;
+        case proto::CameraConfig::OCCUPANT_VIEW_CAMERA:
+            return PipeInputConfigCameraType::OCCUPANT_VIEW_CAMERA;
+        case proto::CameraConfig::EXTERNAL_CAMERA:
+            return PipeInputConfigCameraType::EXTERNAL_CAMERA;
+        case proto::CameraConfig::SURROUND_VIEW_CAMERA:
+            return PipeInputConfigCameraType::SURROUND_VIEW_CAMERA;
+    }
+}
+
+PipeInputConfigImageFileType ConvertImageFileType(proto::ImageFileConfig::ImageFileType type) {
+    switch (type) {
+        case proto::ImageFileConfig::JPEG:
+            return PipeInputConfigImageFileType::JPEG;
+        case proto::ImageFileConfig::PNG:
+            return PipeInputConfigImageFileType::PNG;
+    }
+}
+
+PipeInputConfigVideoFileType ConvertVideoFileType(proto::VideoFileConfig::VideoFileType type) {
+    switch (type) {
+        case proto::VideoFileConfig::MPEG:
+            return PipeInputConfigVideoFileType::MPEG;
+    }
+}
+
+PipeInputConfigFormatType ConvertInputFormat(proto::InputStreamConfig::FormatType type) {
+    switch (type) {
+        case proto::InputStreamConfig::RGB:
+            return PipeInputConfigFormatType::RGB;
+        case proto::InputStreamConfig::NIR:
+            return PipeInputConfigFormatType::NIR;
+        case proto::InputStreamConfig::NIR_DEPTH:
+            return PipeInputConfigFormatType::NIR_DEPTH;
+    }
+}
+
+PipeOffloadConfigOffloadType ConvertOffloadType(proto::OffloadOption::OffloadType type) {
+    switch (type) {
+        case proto::OffloadOption::CPU:
+            return PipeOffloadConfigOffloadType::CPU;
+        case proto::OffloadOption::GPU:
+            return PipeOffloadConfigOffloadType::GPU;
+        case proto::OffloadOption::NEURAL_ENGINE:
+            return PipeOffloadConfigOffloadType::NEURAL_ENGINE;
+        case proto::OffloadOption::CV_ENGINE:
+            return PipeOffloadConfigOffloadType::CV_ENGINE;
+    }
+}
+
+PipeOutputConfigPacketType ConvertOutputType(proto::PacketType type) {
+    switch (type) {
+        case proto::PacketType::SEMANTIC_DATA:
+            return PipeOutputConfigPacketType::SEMANTIC_DATA;
+        case proto::PacketType::PIXEL_DATA:
+            return PipeOutputConfigPacketType::PIXEL_DATA;
+        case proto::PacketType::PIXEL_ZERO_COPY_DATA:
+            return PipeOutputConfigPacketType::PIXEL_ZERO_COPY_DATA;
+    }
+}
+
+PipeTerminationConfigTerminationType ConvertTerminationType(
+    proto::TerminationOption::TerminationType type) {
+    switch (type) {
+        case proto::TerminationOption::CLIENT_STOP:
+            return PipeTerminationConfigTerminationType::CLIENT_STOP;
+        case proto::TerminationOption::MIN_PACKET_COUNT:
+            return PipeTerminationConfigTerminationType::MIN_PACKET_COUNT;
+        case proto::TerminationOption::MAX_RUN_TIME:
+            return PipeTerminationConfigTerminationType::MAX_RUN_TIME;
+        case proto::TerminationOption::EVENT:
+            return PipeTerminationConfigTerminationType::EVENT;
+    }
+}
+
+PipeInputConfig ConvertInputConfigProto(const proto::InputConfig& proto) {
+    PipeInputConfig aidlConfig;
+
+    for (const auto& inputStreamConfig : proto.input_stream()) {
+        PipeInputConfigInputSourceDesc aidlInputDesc;
+        aidlInputDesc.type = ConvertInputType(inputStreamConfig.type());
+        aidlInputDesc.format = ConvertInputFormat(inputStreamConfig.format());
+        aidlInputDesc.width = inputStreamConfig.width();
+        aidlInputDesc.height = inputStreamConfig.height();
+        aidlInputDesc.stride = inputStreamConfig.stride();
+        aidlInputDesc.camDesc.camId = inputStreamConfig.cam_config().cam_id();
+        aidlInputDesc.camDesc.type =
+                ConvertCameraType(inputStreamConfig.cam_config().camera_type());
+        aidlInputDesc.imageDesc.fileType =
+            ConvertImageFileType(inputStreamConfig.image_config().file_type());
+        aidlInputDesc.imageDesc.filePath = inputStreamConfig.image_config().image_dir();
+        aidlInputDesc.videoDesc.fileType =
+            ConvertVideoFileType(inputStreamConfig.video_config().file_type());
+        aidlInputDesc.videoDesc.filePath = inputStreamConfig.video_config().file_path();
+        aidlConfig.inputSources.emplace_back(aidlInputDesc);
+    }
+    aidlConfig.configId = proto.config_id();
+
+    return aidlConfig;
+}
+
+PipeOffloadConfig ConvertOffloadConfigProto(const proto::OffloadConfig& proto) {
+    PipeOffloadConfig aidlConfig;
+
+    for (int i = 0; i < proto.options().offload_types_size(); i++) {
+        auto offloadType =
+            static_cast<proto::OffloadOption_OffloadType>(proto.options().offload_types()[i]);
+        PipeOffloadConfigOffloadType aidlType = ConvertOffloadType(offloadType);
+        aidlConfig.desc.type.emplace_back(aidlType);
+        aidlConfig.desc.isVirtual.emplace_back(proto.options().is_virtual()[i]);
+    }
+
+    aidlConfig.configId = proto.config_id();
+    return aidlConfig;
+}
+
+PipeOutputConfig ConvertOutputConfigProto(const proto::OutputConfig& proto) {
+    PipeOutputConfig aidlConfig;
+    aidlConfig.output.name = proto.stream_name();
+    aidlConfig.output.type = ConvertOutputType(proto.type());
+    aidlConfig.outputId = proto.stream_id();
+    return aidlConfig;
+}
+
+PipeTerminationConfig ConvertTerminationConfigProto(const proto::TerminationConfig& proto) {
+    PipeTerminationConfig aidlConfig;
+    aidlConfig.desc.type = ConvertTerminationType(proto.options().type());
+    aidlConfig.desc.qualifier = proto.options().qualifier();
+    aidlConfig.configId = proto.config_id();
+    return aidlConfig;
+}
+
+}  // namespace
+
+PipeDescriptor OptionsToPipeDescriptor(const proto::Options& options) {
+    PipeDescriptor desc;
+    for (int i = 0; i < options.input_configs_size(); i++) {
+        PipeInputConfig inputConfig = ConvertInputConfigProto(options.input_configs()[i]);
+        desc.inputConfig.emplace_back(inputConfig);
+    }
+
+    for (int i = 0; i < options.offload_configs_size(); i++) {
+        PipeOffloadConfig offloadConfig = ConvertOffloadConfigProto(options.offload_configs()[i]);
+        desc.offloadConfig.emplace_back(offloadConfig);
+    }
+
+    for (int i = 0; i < options.termination_configs_size(); i++) {
+        PipeTerminationConfig terminationConfig =
+            ConvertTerminationConfigProto(options.termination_configs()[i]);
+        desc.terminationConfig.emplace_back(terminationConfig);
+    }
+
+    for (int i = 0; i < options.output_configs_size(); i++) {
+        PipeOutputConfig outputConfig = ConvertOutputConfigProto(options.output_configs()[i]);
+        desc.outputConfig.emplace_back(outputConfig);
+    }
+    return desc;
+}
+
+}  // namespace aidl_client
+}  // namespace client_interface
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/client_interface/PipeOptionsConverter.h b/computepipe/runner/client_interface/PipeOptionsConverter.h
new file mode 100644
index 0000000..d5d3d75
--- /dev/null
+++ b/computepipe/runner/client_interface/PipeOptionsConverter.h
@@ -0,0 +1,39 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_UTILS_PIPEOPTIONSCONVERTER_H_
+#define COMPUTEPIPE_RUNNER_UTILS_PIPEOPTIONSCONVERTER_H_
+
+#include <aidl/android/automotive/computepipe/runner/BnPipeRunner.h>
+
+#include "Options.pb.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace client_interface {
+namespace aidl_client {
+
+aidl::android::automotive::computepipe::runner::PipeDescriptor OptionsToPipeDescriptor(
+    const proto::Options& options);
+
+}  // namespace aidl_client
+}  // namespace client_interface
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // COMPUTEPIPE_RUNNER_UTILS_PIPEOPTIONSCONVERTER_H_
diff --git a/computepipe/runner/client_interface/StatusUtil.cpp b/computepipe/runner/client_interface/StatusUtil.cpp
new file mode 100644
index 0000000..7cc4fae
--- /dev/null
+++ b/computepipe/runner/client_interface/StatusUtil.cpp
@@ -0,0 +1,47 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "StatusUtil.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace client_interface {
+namespace aidl_client {
+
+using ndk::ScopedAStatus;
+
+ScopedAStatus ToNdkStatus(Status status) {
+    switch (status) {
+        case SUCCESS:
+            return ScopedAStatus::ok();
+        case INTERNAL_ERROR:
+            return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+        case INVALID_ARGUMENT:
+            return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        case FATAL_ERROR:
+        default:
+            return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+    }
+}
+
+
+}  // namespace aidl_client
+}  // namespace client_interface
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
diff --git a/computepipe/runner/client_interface/StatusUtil.h b/computepipe/runner/client_interface/StatusUtil.h
new file mode 100644
index 0000000..4b9b2d1
--- /dev/null
+++ b/computepipe/runner/client_interface/StatusUtil.h
@@ -0,0 +1,36 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_CLIENT_INTERFACE_STATUSUTIL_H_
+#define COMPUTEPIPE_RUNNER_CLIENT_INTERFACE_STATUSUTIL_H_
+#include <android/binder_auto_utils.h>
+
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace client_interface {
+namespace aidl_client {
+
+ndk::ScopedAStatus ToNdkStatus(Status status);
+
+}  // namespace aidl_client
+}  // namespace client_interface
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+#endif  // COMPUTEPIPE_RUNNER_CLIENT_INTERFACE_STATUSUTIL_H_
diff --git a/computepipe/runner/client_interface/include/ClientEngineInterface.h b/computepipe/runner/client_interface/include/ClientEngineInterface.h
new file mode 100644
index 0000000..bc551d8
--- /dev/null
+++ b/computepipe/runner/client_interface/include/ClientEngineInterface.h
@@ -0,0 +1,59 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_CLIENT_INTERFACE_INCLUDE_CLIENTENGINEINTERFACE_H_
+#define COMPUTEPIPE_RUNNER_CLIENT_INTERFACE_INCLUDE_CLIENTENGINEINTERFACE_H_
+
+#include <memory>
+#include <string>
+
+#include "ConfigurationCommand.pb.h"
+#include "ControlCommand.pb.h"
+#include "MemHandle.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace client_interface {
+
+/**
+ * Communications from client component to runner engine
+ */
+class ClientEngineInterface {
+  public:
+    /**
+     * Used by client to provide the engine with incremental client configuration
+     * choices
+     */
+    virtual Status processClientConfigUpdate(const proto::ConfigurationCommand& command) = 0;
+    /**
+     * Used by client to provide the engine, the latest client command
+     */
+    virtual Status processClientCommand(const proto::ControlCommand& command) = 0;
+    /**
+     * Used by client to notify the engine of a consumed packet
+     */
+    virtual Status freePacket(int bufferId, int streamId) = 0;
+    virtual ~ClientEngineInterface() = default;
+};
+
+}  // namespace client_interface
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // COMPUTEPIPE_RUNNER_CLIENT_INTERFACE_INCLUDE_CLIENTENGINEINTERFACE_H_
diff --git a/computepipe/runner/client_interface/include/ClientInterface.h b/computepipe/runner/client_interface/include/ClientInterface.h
new file mode 100644
index 0000000..617b004
--- /dev/null
+++ b/computepipe/runner/client_interface/include/ClientInterface.h
@@ -0,0 +1,72 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_CLIENT_INTERFACE_INCLUDE_CLIENTINTERFACE_H_
+#define COMPUTEPIPE_RUNNER_CLIENT_INTERFACE_INCLUDE_CLIENTINTERFACE_H_
+
+#include <memory>
+
+#include "ClientEngineInterface.h"
+#include "MemHandle.h"
+#include "Options.pb.h"
+#include "RunnerComponent.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace client_interface {
+
+/**
+ * ClientInterface: Is the runner component that represents the client of the
+ * runner. This Component exposes communications from engine to the client.
+ */
+
+class ClientInterface : public RunnerComponentInterface {
+  public:
+    /**
+     * Used by the runner engine to dispatch Graph output packes to the clients
+     */
+    virtual Status dispatchPacketToClient(int32_t streamId,
+                                          const std::shared_ptr<MemHandle> packet) = 0;
+    /**
+     * Used by the runner engine to activate the client interface and open it to
+     * external clients
+     */
+    virtual Status activate() = 0;
+
+    /*
+     *
+     */
+    virtual Status deliverGraphDebugInfo(const std::string& debugData) = 0;
+    virtual ~ClientInterface() = default;
+};
+
+class ClientInterfaceFactory {
+  public:
+    std::unique_ptr<ClientInterface> createClientInterface(
+        std::string ifaceName, const proto::Options graphOptions,
+        const std::shared_ptr<ClientEngineInterface>& engine);
+    ClientInterfaceFactory(const ClientInterfaceFactory&) = delete;
+    ClientInterfaceFactory& operator=(const ClientInterfaceFactory&) = delete;
+    ClientInterfaceFactory() = default;
+};
+
+}  // namespace client_interface
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // COMPUTEPIPE_RUNNER_CLIENT_INTERFACE_INCLUDE_CLIENTINTERFACE_H_
diff --git a/computepipe/runner/debug_display_manager/Android.bp b/computepipe/runner/debug_display_manager/Android.bp
new file mode 100644
index 0000000..43c4994
--- /dev/null
+++ b/computepipe/runner/debug_display_manager/Android.bp
@@ -0,0 +1,48 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library {
+    name: "computepipe_runner_display",
+    srcs: [
+        "EvsDisplayManager.cpp",
+    ],
+    export_include_dirs: ["include"],
+    header_libs: [
+        "computepipe_runner_includes",
+    ],
+    static_libs: [
+        "libcomputepipeprotos",
+    ],
+    cflags: ["-DLOG_TAG=\"Computepipe_runner_display\""],
+    shared_libs: [
+        "android.hardware.automotive.evs@1.0",
+        "android.hardware.automotive.evs@1.1",
+        "computepipe_runner_component",
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libevssupport",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libnativewindow",
+        "libprotobuf-cpp-lite",
+        "libui",
+        "libutils",
+    ],
+    include_dirs: [
+        "packages/services/Car/computepipe",
+        "packages/services/Car/evs/support_library",
+    ],
+}
diff --git a/computepipe/runner/debug_display_manager/EvsDisplayManager.cpp b/computepipe/runner/debug_display_manager/EvsDisplayManager.cpp
new file mode 100644
index 0000000..404f06f
--- /dev/null
+++ b/computepipe/runner/debug_display_manager/EvsDisplayManager.cpp
@@ -0,0 +1,205 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+
+#include <android-base/logging.h>
+#include "EvsDisplayManager.h"
+
+#include "PixelFormatUtils.h"
+#include "RenderDirectView.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace debug_display_manager {
+namespace {
+
+constexpr char kServiceName[] = "default";
+
+using android::hardware::automotive::evs::V1_1::IEvsEnumerator;
+using android::hardware::automotive::evs::V1_1::IEvsDisplay;
+using android::hardware::automotive::evs::V1_0::EvsResult;
+using android::hardware::automotive::evs::V1_0::DisplayState;
+using android::hardware::automotive::evs::V1_0::BufferDesc;
+
+using android::automotive::evs::support::RenderDirectView;
+
+BufferDesc getBufferDesc(const std::shared_ptr<MemHandle>& frame) {
+    AHardwareBuffer_Desc hwDesc;
+    AHardwareBuffer_describe(frame->getHardwareBuffer(), &hwDesc);
+
+    BufferDesc buffer;
+    buffer.width = hwDesc.width;
+    buffer.height = hwDesc.height;
+    buffer.stride = hwDesc.stride;
+    buffer.pixelSize = numBytesPerPixel(static_cast<AHardwareBuffer_Format>(hwDesc.format));
+    buffer.format = hwDesc.format;
+    buffer.usage = hwDesc.usage;
+    buffer.memHandle = AHardwareBuffer_getNativeHandle(frame->getHardwareBuffer());
+    return buffer;
+}
+
+}  // namespace
+
+EvsDisplayManager::~EvsDisplayManager() {
+    stopThread();
+}
+
+Status EvsDisplayManager::setArgs(std::string displayManagerArgs) {
+    auto pos = displayManagerArgs.find(kDisplayId);
+    if (pos == std::string::npos) {
+        return Status::SUCCESS;
+    }
+    mDisplayId = std::stoi(displayManagerArgs.substr(pos + strlen(kDisplayId)));
+    mOverrideDisplayId = true;
+    return Status::SUCCESS;
+}
+
+void EvsDisplayManager::stopThread() {
+    {
+        std::lock_guard<std::mutex> lk(mLock);
+        mStopThread = true;
+        mWait.notify_one();
+    }
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+}
+
+void EvsDisplayManager::threadFn() {
+    sp<IEvsEnumerator> evsEnumerator = IEvsEnumerator::getService(std::string() + kServiceName);
+
+    if (!mOverrideDisplayId) {
+        evsEnumerator->getDisplayIdList([this] (auto ids) {
+                this->mDisplayId = ids[ids.size() - 1];
+        });
+    }
+
+    android::sp <IEvsDisplay> evsDisplay = evsEnumerator->openDisplay_1_1(mDisplayId);
+
+    if (evsDisplay != nullptr) {
+        LOG(INFO) << "Computepipe runner opened debug display.";
+    } else {
+        mStopThread = true;
+        LOG(ERROR) << "EVS Display unavailable.  Exiting thread.";
+        return;
+    }
+
+    RenderDirectView evsRenderer;
+    EvsResult result = evsDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME);
+    if (result != EvsResult::OK) {
+        mStopThread = true;
+        LOG(ERROR) <<  "Set display state returned error - " << static_cast<int>(result);
+        evsEnumerator->closeDisplay(evsDisplay);
+        return;
+    }
+
+    if (!evsRenderer.activate()) {
+        mStopThread = true;
+        LOG(ERROR) <<  "Unable to activate evs renderer.";
+        evsEnumerator->closeDisplay(evsDisplay);
+        return;
+    }
+
+    std::unique_lock<std::mutex> lk(mLock);
+    while (true) {
+        mWait.wait(lk, [this]() { return mNextFrame != nullptr || mStopThread; });
+
+        if (mStopThread) {
+            // Free unused frame.
+            if (mFreePacketCallback && mNextFrame) {
+                mFreePacketCallback(mNextFrame->getBufferId());
+            }
+            break;
+        }
+
+        BufferDesc tgtBuffer = {};
+        evsDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc& buff) {
+                tgtBuffer = buff;
+                }
+            );
+
+        BufferDesc srcBuffer = getBufferDesc(mNextFrame);
+        if (!evsRenderer.drawFrame(tgtBuffer, srcBuffer)) {
+            LOG(ERROR) << "Error in rendering a frame.";
+            mStopThread = true;
+        }
+
+        evsDisplay->returnTargetBufferForDisplay(tgtBuffer);
+        if (mFreePacketCallback) {
+            mFreePacketCallback(mNextFrame->getBufferId());
+        }
+        mNextFrame = nullptr;
+    }
+
+    LOG(INFO) << "Computepipe runner closing debug display.";
+    evsRenderer.deactivate();
+    (void)evsDisplay->setDisplayState(DisplayState::NOT_VISIBLE);
+    evsEnumerator->closeDisplay(evsDisplay);
+}
+
+void EvsDisplayManager::setFreePacketCallback(
+            std::function<Status(int bufferId)> freePacketCallback) {
+    std::lock_guard<std::mutex> lk(mLock);
+    mFreePacketCallback = freePacketCallback;
+}
+
+Status EvsDisplayManager::displayFrame(const std::shared_ptr<MemHandle>& dataHandle) {
+    std::lock_guard<std::mutex> lk(mLock);
+    Status status = Status::SUCCESS;
+    if (mStopThread) {
+        return Status::ILLEGAL_STATE;
+    }
+    if (mNextFrame != nullptr && mFreePacketCallback) {
+        status = mFreePacketCallback(mNextFrame->getBufferId());
+    }
+    mNextFrame = dataHandle;
+    mWait.notify_one();
+    return status;
+}
+
+Status EvsDisplayManager::handleExecutionPhase(const RunnerEvent& e) {
+    if (e.isPhaseEntry()) {
+        std::lock_guard<std::mutex> lk(mLock);
+        mStopThread = false;
+        mThread = std::thread(&EvsDisplayManager::threadFn, this);
+    } else if (e.isAborted()) {
+        stopThread();
+    }
+    return Status::SUCCESS;
+}
+
+Status EvsDisplayManager::handleStopWithFlushPhase(const RunnerEvent& /* e */) {
+    stopThread();
+    return Status::SUCCESS;
+}
+
+Status EvsDisplayManager::handleStopImmediatePhase(const RunnerEvent& /* e */) {
+    stopThread();
+    return Status::SUCCESS;
+}
+
+Status EvsDisplayManager::handleResetPhase(const RunnerEvent& /* e */) {
+    stopThread();
+    return Status::SUCCESS;
+}
+
+}  // namespace debug_display_manager
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/debug_display_manager/include/DebugDisplayManager.h b/computepipe/runner/debug_display_manager/include/DebugDisplayManager.h
new file mode 100644
index 0000000..b48acf1
--- /dev/null
+++ b/computepipe/runner/debug_display_manager/include/DebugDisplayManager.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_DEBUG_DISPLAY_MANAGER
+#define COMPUTEPIPE_RUNNER_DEBUG_DISPLAY_MANAGER
+
+#include "MemHandle.h"
+#include "RunnerComponent.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace debug_display_manager {
+
+class DebugDisplayManager : public RunnerComponentInterface {
+  public:
+    static constexpr char kDisplayId[] = "display_id:";
+
+    /* Any args that a given display manager needs in order to configure itself. */
+    virtual Status setArgs(std::string displayManagerArgs);
+
+    /* Send a frame to debug display.
+     * This is a non-blocking call. When the frame is ready to be freed, setFreePacketCallback()
+     * should be invoked. */
+    virtual Status displayFrame(const std::shared_ptr<MemHandle>& dataHandle) = 0;
+    /* Free the packet (represented by buffer id). */
+    virtual void setFreePacketCallback(std::function<Status (int bufferId)> freePacketCallback) = 0;
+};
+
+}  // namespace debug_display_manager
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // COMPUTEPIPE_RUNNER_DEBUG_DISPLAY_MANAGER
diff --git a/computepipe/runner/debug_display_manager/include/EvsDisplayManager.h b/computepipe/runner/debug_display_manager/include/EvsDisplayManager.h
new file mode 100644
index 0000000..b8a587e
--- /dev/null
+++ b/computepipe/runner/debug_display_manager/include/EvsDisplayManager.h
@@ -0,0 +1,80 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_EVS_DISPLAY_MANAGER
+#define COMPUTEPIPE_RUNNER_EVS_DISPLAY_MANAGER
+
+#include <memory>
+#include <mutex>
+#include <thread>
+
+#include "DebugDisplayManager.h"
+#include "InputFrame.h"
+#include "MemHandle.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace debug_display_manager {
+
+class EvsDisplayManager : public DebugDisplayManager {
+  public:
+    /* Override DebugDisplayManager methods */
+    /* Send a frame to debug display.
+     * This is a non-blocking call. When the frame is ready to be freed, setFreePacketCallback()
+     * should be invoked. */
+    Status setArgs(std::string displayManagerArgs) override;
+    Status displayFrame(const std::shared_ptr<MemHandle>& dataHandle) override;
+    /* Free the packet (represented by buffer id). */
+    void setFreePacketCallback(std::function<Status (int bufferId)> freePacketCallback) override;
+
+    /* handle execution phase notification from Runner Engine */
+    Status handleExecutionPhase(const RunnerEvent& e) override;
+    /* handle a stop with flushing semantics phase notification from the engine */
+    Status handleStopWithFlushPhase(const RunnerEvent& e) override;
+    /* handle an immediate stop phase notification from the engine */
+    Status handleStopImmediatePhase(const RunnerEvent& e) override;
+    /* handle an engine notification to return to reset state */
+    Status handleResetPhase(const RunnerEvent& e) override;
+
+    ~EvsDisplayManager();
+
+  private:
+    void threadFn();
+
+    void stopThread();
+
+    // Variables to remember displayId if set through arguments.
+    bool mOverrideDisplayId = false;
+    int mDisplayId;
+
+    std::thread mThread;
+    bool mStopThread = false;
+
+    // Lock for variables shared with the thread.
+    std::mutex mLock;
+    std::condition_variable mWait;
+    std::shared_ptr<MemHandle> mNextFrame = nullptr;
+    std::function<Status (int bufferId)> mFreePacketCallback = nullptr;
+};
+
+}  // namespace debug_display_manager
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // COMPUTEPIPE_RUNNER_EVS_DISPLAY_MANAGER
diff --git a/computepipe/runner/engine/Android.bp b/computepipe/runner/engine/Android.bp
new file mode 100644
index 0000000..8e5c21a
--- /dev/null
+++ b/computepipe/runner/engine/Android.bp
@@ -0,0 +1,63 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library {
+    name: "computepipe_runner_engine",
+    srcs: [
+        "ConfigBuilder.cpp",
+        "DefaultEngine.cpp",
+        "Factory.cpp",
+    ],
+    export_include_dirs: ["include"],
+    header_libs: [
+        "computepipe_runner_includes",
+    ],
+    static_libs: [
+        "libcomputepipeprotos",
+        "computepipe_runner_component",
+        "computepipe_input_manager",
+        "computepipe_stream_manager",
+    ],
+    shared_libs: [
+        "android.hardware.automotive.evs@1.0",
+        "computepipe_client_interface",
+        "computepipe_prebuilt_graph",
+        "computepipe_runner_display",
+        "libbase",
+        "libcutils",
+        "libdl",
+        "libevssupport",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libnativewindow",
+        "libpng",
+        "libprotobuf-cpp-lite",
+        "libui",
+        "libutils",
+        "libEGL",
+        "libGLESv2",
+    ],
+    cflags: [
+        "-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS",
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+        "-Wthread-safety",
+    ],
+    include_dirs: [
+        "packages/services/Car/computepipe",
+    ],
+}
diff --git a/computepipe/runner/engine/ConfigBuilder.cpp b/computepipe/runner/engine/ConfigBuilder.cpp
new file mode 100644
index 0000000..c4995e2
--- /dev/null
+++ b/computepipe/runner/engine/ConfigBuilder.cpp
@@ -0,0 +1,87 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "ConfigBuilder.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace engine {
+
+void ConfigBuilder::setDebugDisplayStream(int id) {
+    mDisplayStream = id;
+    mOutputConfig.emplace(id, 1);
+}
+
+bool ConfigBuilder::clientConfigEnablesDisplayStream() {
+    return mConfigHasDisplayStream;
+}
+
+ConfigBuilder& ConfigBuilder::updateInputConfigOption(int id) {
+    mInputConfigId = id;
+    return *this;
+}
+
+ConfigBuilder& ConfigBuilder::updateOutputStreamOption(int id, int maxInFlightPackets) {
+    if (id == mDisplayStream) {
+        mConfigHasDisplayStream = true;
+    }
+    mOutputConfig.emplace(id, maxInFlightPackets);
+    return *this;
+}
+
+ConfigBuilder& ConfigBuilder::updateTerminationOption(int id) {
+    mTerminationId = id;
+    return *this;
+}
+
+ConfigBuilder& ConfigBuilder::updateOffloadOption(int id) {
+    mOffloadId = id;
+    return *this;
+}
+
+ConfigBuilder& ConfigBuilder::updateOptionalConfig(std::string options) {
+    mOptionalConfig = options;
+    return *this;
+}
+
+ConfigBuilder& ConfigBuilder::updateProfilingType(proto::ProfilingType profilingType) {
+    mProfilingType = profilingType;
+    return *this;
+}
+
+ClientConfig ConfigBuilder::emitClientOptions() {
+    return ClientConfig(mInputConfigId, mOffloadId, mTerminationId, mOutputConfig, mProfilingType,
+            mOptionalConfig);
+}
+
+ConfigBuilder& ConfigBuilder::reset() {
+    mInputConfigId = ClientConfig::kInvalidId;
+    mTerminationId = ClientConfig::kInvalidId;
+    mOffloadId = ClientConfig::kInvalidId;
+    mOutputConfig.clear();
+    mProfilingType = proto::ProfilingType::DISABLED;
+    if (mDisplayStream != ClientConfig::kInvalidId) {
+        mOutputConfig.emplace(mDisplayStream, 1);
+    }
+    mConfigHasDisplayStream = false;
+    return *this;
+}
+
+}  // namespace engine
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/engine/ConfigBuilder.h b/computepipe/runner/engine/ConfigBuilder.h
new file mode 100644
index 0000000..b45ba8d
--- /dev/null
+++ b/computepipe/runner/engine/ConfigBuilder.h
@@ -0,0 +1,89 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_ENGINE_CONFIGBUILDER_H_
+#define COMPUTEPIPE_RUNNER_ENGINE_CONFIGBUILDER_H_
+
+#include "ProfilingType.pb.h"
+
+#include "RunnerComponent.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace engine {
+
+class ConfigBuilder {
+  public:
+    /**
+     * Set debug display stream in the final client config
+     */
+    void setDebugDisplayStream(int id);
+    /**
+     * Does client explicitly enable display stream
+     */
+    bool clientConfigEnablesDisplayStream();
+    /**
+     * Update current input option
+     */
+    ConfigBuilder& updateInputConfigOption(int id);
+    /**
+     * Update current output options
+     */
+    ConfigBuilder& updateOutputStreamOption(int id, int maxInFlightPackets);
+    /**
+     * Update current termination options
+     */
+    ConfigBuilder& updateTerminationOption(int id);
+    /**
+     * Update current offload options
+     */
+    ConfigBuilder& updateOffloadOption(int id);
+    /**
+     * Update optional Config
+     */
+    ConfigBuilder& updateOptionalConfig(std::string options);
+    /**
+     * Update profiling Config
+     */
+    ConfigBuilder& updateProfilingType(proto::ProfilingType profilingType);
+    /**
+     * Emit Options
+     */
+    ClientConfig emitClientOptions();
+    /**
+     * Clear current options.
+     */
+    ConfigBuilder& reset();
+
+  private:
+    int mDisplayStream = ClientConfig::kInvalidId;
+    int mInputConfigId = ClientConfig::kInvalidId;
+    int mOffloadId = ClientConfig::kInvalidId;
+    int mTerminationId = ClientConfig::kInvalidId;
+    proto::ProfilingType mProfilingType = proto::ProfilingType::DISABLED;
+    bool mConfigHasDisplayStream = false;
+    std::map<int, int> mOutputConfig;
+    std::string mOptionalConfig;
+};
+
+}  // namespace engine
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // COMPUTEPIPE_RUNNER_ENGINE_CONFIGBUILDER_H_
diff --git a/computepipe/runner/engine/DefaultEngine.cpp b/computepipe/runner/engine/DefaultEngine.cpp
new file mode 100644
index 0000000..ab812d2
--- /dev/null
+++ b/computepipe/runner/engine/DefaultEngine.cpp
@@ -0,0 +1,768 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "DefaultEngine.h"
+
+#include <android-base/logging.h>
+
+#include <algorithm>
+#include <cassert>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+#include "ClientInterface.h"
+#include "EventGenerator.h"
+#include "EvsDisplayManager.h"
+#include "InputFrame.h"
+#include "PrebuiltGraph.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace engine {
+
+using android::automotive::computepipe::graph::PrebuiltGraph;
+using android::automotive::computepipe::runner::client_interface::ClientInterface;
+using android::automotive::computepipe::runner::generator::DefaultEvent;
+using android::automotive::computepipe::runner::input_manager::InputEngineInterface;
+using android::automotive::computepipe::runner::stream_manager::StreamEngineInterface;
+using android::automotive::computepipe::runner::stream_manager::StreamManager;
+
+namespace {
+
+int getStreamIdFromSource(std::string source) {
+    auto pos = source.find(":");
+    return std::stoi(source.substr(pos + 1));
+}
+}  // namespace
+
+void DefaultEngine::setClientInterface(std::unique_ptr<ClientInterface>&& client) {
+    mClient = std::move(client);
+}
+
+void DefaultEngine::setPrebuiltGraph(std::unique_ptr<PrebuiltGraph>&& graph) {
+    mGraph = std::move(graph);
+    mGraphDescriptor = mGraph->GetSupportedGraphConfigs();
+    if (mGraph->GetGraphType() == graph::PrebuiltGraphType::REMOTE ||
+        mGraphDescriptor.input_configs_size() == 0) {
+        mIgnoreInputManager = true;
+    }
+}
+
+Status DefaultEngine::setArgs(std::string engine_args) {
+    auto pos = engine_args.find(kNoInputManager);
+    if (pos != std::string::npos) {
+        mIgnoreInputManager = true;
+    }
+    pos = engine_args.find(kDisplayStreamId);
+    if (pos == std::string::npos) {
+        return Status::SUCCESS;
+    }
+    mDisplayStream = std::stoi(engine_args.substr(pos + strlen(kDisplayStreamId)));
+    mConfigBuilder.setDebugDisplayStream(mDisplayStream);
+    mDebugDisplayManager = std::make_unique<debug_display_manager::EvsDisplayManager>();
+    mDebugDisplayManager->setArgs(engine_args);
+    return Status::SUCCESS;
+}
+
+Status DefaultEngine::activate() {
+    mConfigBuilder.reset();
+    mEngineThread = std::make_unique<std::thread>(&DefaultEngine::processCommands, this);
+    return mClient->activate();
+}
+
+Status DefaultEngine::processClientConfigUpdate(const proto::ConfigurationCommand& command) {
+    // TODO check current phase
+    std::lock_guard<std::mutex> lock(mEngineLock);
+    if (mCurrentPhase != kResetPhase) {
+        return Status::ILLEGAL_STATE;
+    }
+    if (command.has_set_input_source()) {
+        mConfigBuilder =
+            mConfigBuilder.updateInputConfigOption(command.set_input_source().source_id());
+    } else if (command.has_set_termination_option()) {
+        mConfigBuilder = mConfigBuilder.updateTerminationOption(
+            command.set_termination_option().termination_option_id());
+    } else if (command.has_set_output_stream()) {
+        mConfigBuilder = mConfigBuilder.updateOutputStreamOption(
+            command.set_output_stream().stream_id(),
+            command.set_output_stream().max_inflight_packets_count());
+    } else if (command.has_set_offload_offload()) {
+        mConfigBuilder =
+            mConfigBuilder.updateOffloadOption(command.set_offload_offload().offload_option_id());
+    } else if (command.has_set_profile_options()) {
+        mConfigBuilder =
+            mConfigBuilder.updateProfilingType(command.set_profile_options().profile_type());
+    } else {
+        return SUCCESS;
+    }
+    return Status::SUCCESS;
+}
+
+Status DefaultEngine::processClientCommand(const proto::ControlCommand& command) {
+    // TODO check current phase
+    std::lock_guard<std::mutex> lock(mEngineLock);
+
+    if (command.has_apply_configs()) {
+        if (mCurrentPhase != kResetPhase) {
+            return Status::ILLEGAL_STATE;
+        }
+        queueCommand("ClientInterface", EngineCommand::Type::BROADCAST_CONFIG);
+        return Status::SUCCESS;
+    }
+    if (command.has_start_graph()) {
+        if (mCurrentPhase != kConfigPhase) {
+            return Status::ILLEGAL_STATE;
+        }
+        queueCommand("ClientInterface", EngineCommand::Type::BROADCAST_START_RUN);
+        return Status::SUCCESS;
+    }
+    if (command.has_stop_graph()) {
+        if (mCurrentPhase != kRunPhase) {
+            return Status::ILLEGAL_STATE;
+        }
+        mStopFromClient = true;
+        queueCommand("ClientInterface", EngineCommand::Type::BROADCAST_INITIATE_STOP);
+        return Status::SUCCESS;
+    }
+    if (command.has_death_notification()) {
+        if (mCurrentPhase == kResetPhase) {
+            /**
+             * The runner is already in reset state, no need to broadcast client death
+             * to components
+             */
+            LOG(INFO) << "client death notification with no configuration";
+            return Status::SUCCESS;
+        }
+        mCurrentPhaseError = std::make_unique<ComponentError>("ClientInterface", "Client death",
+                                                              mCurrentPhase, false);
+        mWakeLooper.notify_all();
+        return Status::SUCCESS;
+    }
+    if (command.has_reset_configs()) {
+        if (mCurrentPhase != kConfigPhase) {
+            return Status::ILLEGAL_STATE;
+        }
+        queueCommand("ClientInterface", EngineCommand::Type::RESET_CONFIG);
+        return Status::SUCCESS;
+    }
+    if (command.has_start_pipe_profile()) {
+        if (mCurrentPhase != kRunPhase) {
+            return Status::ILLEGAL_STATE;
+        }
+        if (mGraph) {
+            return mGraph->StartGraphProfiling();
+        }
+        return Status::SUCCESS;
+    }
+    if (command.has_stop_pipe_profile()) {
+        if (mCurrentPhase != kRunPhase) {
+            return Status::SUCCESS;
+        }
+        if (mGraph) {
+            return mGraph->StopGraphProfiling();
+        }
+        return Status::SUCCESS;
+    }
+    if (command.has_release_debugger()) {
+        if (mCurrentPhase != kConfigPhase && mCurrentPhase != kResetPhase) {
+            return Status::ILLEGAL_STATE;
+        }
+        queueCommand("ClientInterface", EngineCommand::Type::RELEASE_DEBUGGER);
+    }
+    if (command.has_read_debug_data()) {
+        queueCommand("ClientInterface", EngineCommand::Type::READ_PROFILING);
+        return Status::SUCCESS;
+    }
+    return Status::SUCCESS;
+}
+
+Status DefaultEngine::freePacket(int bufferId, int streamId) {
+    if (mStreamManagers.find(streamId) == mStreamManagers.end()) {
+        LOG(ERROR)
+            << "Unable to find the stream manager corresponding to the id for freeing the packet.";
+        return Status::INVALID_ARGUMENT;
+    }
+    return mStreamManagers[streamId]->freePacket(bufferId);
+}
+
+/**
+ * Methods from PrebuiltEngineInterface
+ */
+void DefaultEngine::DispatchPixelData(int streamId, int64_t timestamp, const InputFrame& frame) {
+    LOG(DEBUG) << "Engine::Received data for pixel stream  " << streamId << " with timestamp "
+              << timestamp;
+    if (mStreamManagers.find(streamId) == mStreamManagers.end()) {
+        LOG(ERROR) << "Engine::Received bad stream id from prebuilt graph";
+        return;
+    }
+    mStreamManagers[streamId]->queuePacket(frame, timestamp);
+}
+
+void DefaultEngine::DispatchSerializedData(int streamId, int64_t timestamp, std::string&& output) {
+    LOG(DEBUG) << "Engine::Received data for stream  " << streamId << " with timestamp "
+            << timestamp;
+    if (mStreamManagers.find(streamId) == mStreamManagers.end()) {
+        LOG(ERROR) << "Engine::Received bad stream id from prebuilt graph";
+        return;
+    }
+    std::string data(output);
+    mStreamManagers[streamId]->queuePacket(data.c_str(), data.size(), timestamp);
+}
+
+void DefaultEngine::DispatchGraphTerminationMessage(Status s, std::string&& msg) {
+    std::lock_guard<std::mutex> lock(mEngineLock);
+    if (s == SUCCESS) {
+        if (mCurrentPhase == kRunPhase) {
+            queueCommand("PrebuiltGraph", EngineCommand::Type::BROADCAST_INITIATE_STOP);
+        } else {
+            LOG(WARNING) << "Graph termination when not in run phase";
+        }
+    } else {
+        std::string error = msg;
+        queueError("PrebuiltGraph", error, false);
+    }
+}
+
+Status DefaultEngine::broadcastClientConfig() {
+    ClientConfig config = mConfigBuilder.emitClientOptions();
+
+    LOG(INFO) << "Engine::create stream manager";
+    Status ret = populateStreamManagers(config);
+    if (ret != Status::SUCCESS) {
+        return ret;
+    }
+
+    if (mGraph) {
+        ret = populateInputManagers(config);
+        if (ret != Status::SUCCESS) {
+            abortClientConfig(config);
+            return ret;
+        }
+
+        LOG(INFO) << "Engine::send client config entry to graph";
+        config.setPhaseState(PhaseState::ENTRY);
+        ret = mGraph->handleConfigPhase(config);
+        if (ret != Status::SUCCESS) {
+            abortClientConfig(config);
+            return ret;
+        }
+        LOG(INFO) << "Engine::send client config transition complete to graph";
+        config.setPhaseState(PhaseState::TRANSITION_COMPLETE);
+        ret = mGraph->handleConfigPhase(config);
+        if (ret != Status::SUCCESS) {
+            abortClientConfig(config);
+            return ret;
+        }
+    }
+    LOG(INFO) << "Engine::Graph configured";
+    // TODO add handling for remote graph
+    if (mDebugDisplayManager) {
+        mDebugDisplayManager->setFreePacketCallback(std::bind(
+                &DefaultEngine::freePacket, this, std::placeholders::_1, mDisplayStream));
+
+        ret = mDebugDisplayManager->handleConfigPhase(config);
+        if (ret != Status::SUCCESS) {
+            config.setPhaseState(PhaseState::ABORTED);
+            abortClientConfig(config, true);
+            return ret;
+        }
+    }
+
+    ret = mClient->handleConfigPhase(config);
+    if (ret != Status::SUCCESS) {
+        config.setPhaseState(PhaseState::ABORTED);
+        abortClientConfig(config, true);
+        return ret;
+    }
+
+    mCurrentPhase = kConfigPhase;
+    return Status::SUCCESS;
+}
+
+void DefaultEngine::abortClientConfig(const ClientConfig& config, bool resetGraph) {
+    mStreamManagers.clear();
+    mInputManagers.clear();
+    if (resetGraph && mGraph) {
+        (void)mGraph->handleConfigPhase(config);
+    }
+    (void)mClient->handleConfigPhase(config);
+    // TODO add handling for remote graph
+}
+
+Status DefaultEngine::broadcastStartRun() {
+    DefaultEvent runEvent = DefaultEvent::generateEntryEvent(DefaultEvent::RUN);
+
+    std::vector<int> successfulStreams;
+    std::vector<int> successfulInputs;
+    for (auto& it : mStreamManagers) {
+        if (it.second->handleExecutionPhase(runEvent) != Status::SUCCESS) {
+            LOG(ERROR) << "Engine::failure to enter run phase for stream " << it.first;
+            broadcastAbortRun(successfulStreams, successfulInputs);
+            return Status::INTERNAL_ERROR;
+        }
+        successfulStreams.push_back(it.first);
+    }
+    // TODO: send to remote
+    if (mDebugDisplayManager) {
+        (void)mDebugDisplayManager->handleExecutionPhase(runEvent);
+    }
+
+    Status ret;
+    if (mGraph) {
+        LOG(INFO) << "Engine::sending start run to prebuilt";
+        ret = mGraph->handleExecutionPhase(runEvent);
+        if (ret != Status::SUCCESS) {
+            broadcastAbortRun(successfulStreams, successfulInputs);
+        }
+        for (auto& it : mInputManagers) {
+            if (it.second->handleExecutionPhase(runEvent) != Status::SUCCESS) {
+                LOG(ERROR) << "Engine::failure to enter run phase for input manager " << it.first;
+                broadcastAbortRun(successfulStreams, successfulInputs, true);
+                return Status::INTERNAL_ERROR;
+            }
+            successfulInputs.push_back(it.first);
+        }
+    }
+
+    runEvent = DefaultEvent::generateTransitionCompleteEvent(DefaultEvent::RUN);
+    LOG(INFO) << "Engine::sending run transition complete to client";
+    ret = mClient->handleExecutionPhase(runEvent);
+    if (ret != Status::SUCCESS) {
+        LOG(ERROR) << "Engine::client failure to acknowledge transition to run complete ";
+        broadcastAbortRun(successfulStreams, successfulInputs, true);
+        return ret;
+    }
+    for (auto& it : mStreamManagers) {
+        (void)it.second->handleExecutionPhase(runEvent);
+    }
+    // TODO: send to remote
+    if (mDebugDisplayManager) {
+        (void)mDebugDisplayManager->handleExecutionPhase(runEvent);
+    }
+
+    if (mGraph) {
+        LOG(INFO) << "Engine::sending run transition complete to prebuilt";
+        (void)mGraph->handleExecutionPhase(runEvent);
+        for (auto& it : mInputManagers) {
+            (void)it.second->handleExecutionPhase(runEvent);
+        }
+    }
+
+    LOG(INFO) << "Engine::Running";
+    mCurrentPhase = kRunPhase;
+    return Status::SUCCESS;
+}
+
+void DefaultEngine::broadcastAbortRun(const std::vector<int>& streamIds,
+                                      const std::vector<int>& inputIds, bool abortGraph) {
+    DefaultEvent runEvent = DefaultEvent::generateAbortEvent(DefaultEvent::RUN);
+    if (mDebugDisplayManager) {
+        (void)mDebugDisplayManager->handleExecutionPhase(runEvent);
+    }
+    std::for_each(streamIds.begin(), streamIds.end(), [this, runEvent](int id) {
+        (void)this->mStreamManagers[id]->handleExecutionPhase(runEvent);
+    });
+    std::for_each(inputIds.begin(), inputIds.end(), [this, runEvent](int id) {
+        (void)this->mInputManagers[id]->handleExecutionPhase(runEvent);
+    });
+    if (abortGraph) {
+        if (mGraph) {
+            (void)mGraph->handleExecutionPhase(runEvent);
+        }
+    }
+    (void)mClient->handleExecutionPhase(runEvent);
+}
+
+Status DefaultEngine::broadcastStopWithFlush() {
+    DefaultEvent runEvent = DefaultEvent::generateEntryEvent(DefaultEvent::STOP_WITH_FLUSH);
+    if (mDebugDisplayManager) {
+        (void)mDebugDisplayManager->handleStopWithFlushPhase(runEvent);
+    }
+
+    if (mGraph) {
+        for (auto& it : mInputManagers) {
+            (void)it.second->handleStopWithFlushPhase(runEvent);
+        }
+        if (mStopFromClient) {
+            (void)mGraph->handleStopWithFlushPhase(runEvent);
+        }
+    }
+    // TODO: send to remote.
+    for (auto& it : mStreamManagers) {
+        (void)it.second->handleStopWithFlushPhase(runEvent);
+    }
+    if (!mStopFromClient) {
+        (void)mClient->handleStopWithFlushPhase(runEvent);
+    }
+    mCurrentPhase = kStopPhase;
+    return Status::SUCCESS;
+}
+
+Status DefaultEngine::broadcastStopComplete() {
+    DefaultEvent runEvent =
+        DefaultEvent::generateTransitionCompleteEvent(DefaultEvent::STOP_WITH_FLUSH);
+    if (mGraph) {
+        for (auto& it : mInputManagers) {
+            (void)it.second->handleStopWithFlushPhase(runEvent);
+        }
+        (void)mGraph->handleStopWithFlushPhase(runEvent);
+    }
+    if (mDebugDisplayManager) {
+        (void)mDebugDisplayManager->handleStopWithFlushPhase(runEvent);
+    }
+    // TODO: send to remote.
+    for (auto& it : mStreamManagers) {
+        (void)it.second->handleStopWithFlushPhase(runEvent);
+    }
+    (void)mClient->handleStopWithFlushPhase(runEvent);
+    mCurrentPhase = kConfigPhase;
+    return Status::SUCCESS;
+}
+
+void DefaultEngine::broadcastHalt() {
+    DefaultEvent stopEvent = DefaultEvent::generateEntryEvent(DefaultEvent::STOP_IMMEDIATE);
+
+    if (mGraph) {
+        for (auto& it : mInputManagers) {
+            (void)it.second->handleStopImmediatePhase(stopEvent);
+        }
+
+        if ((mCurrentPhaseError->source.find("PrebuiltGraph") == std::string::npos)) {
+            (void)mGraph->handleStopImmediatePhase(stopEvent);
+        }
+    }
+    if (mDebugDisplayManager) {
+        (void)mDebugDisplayManager->handleStopImmediatePhase(stopEvent);
+    }
+    // TODO: send to remote if client was source.
+    for (auto& it : mStreamManagers) {
+        (void)it.second->handleStopImmediatePhase(stopEvent);
+    }
+    if (mCurrentPhaseError->source.find("ClientInterface") == std::string::npos) {
+        (void)mClient->handleStopImmediatePhase(stopEvent);
+    }
+
+    stopEvent = DefaultEvent::generateTransitionCompleteEvent(DefaultEvent::STOP_IMMEDIATE);
+    if (mGraph) {
+        for (auto& it : mInputManagers) {
+            (void)it.second->handleStopImmediatePhase(stopEvent);
+        }
+        // TODO: send to graph or remote if client was source.
+
+        if ((mCurrentPhaseError->source.find("PrebuiltGraph") == std::string::npos) && mGraph) {
+            (void)mGraph->handleStopImmediatePhase(stopEvent);
+        }
+    }
+    if (mDebugDisplayManager) {
+        (void)mDebugDisplayManager->handleStopImmediatePhase(stopEvent);
+    }
+    for (auto& it : mStreamManagers) {
+        (void)it.second->handleStopImmediatePhase(stopEvent);
+    }
+    if (mCurrentPhaseError->source.find("ClientInterface") == std::string::npos) {
+        (void)mClient->handleStopImmediatePhase(stopEvent);
+    }
+    mCurrentPhase = kConfigPhase;
+}
+
+void DefaultEngine::broadcastReset() {
+    mStreamManagers.clear();
+    mInputManagers.clear();
+    DefaultEvent resetEvent = DefaultEvent::generateEntryEvent(DefaultEvent::RESET);
+    (void)mClient->handleResetPhase(resetEvent);
+    if (mGraph) {
+        (void)mGraph->handleResetPhase(resetEvent);
+    }
+    resetEvent = DefaultEvent::generateTransitionCompleteEvent(DefaultEvent::RESET);
+    (void)mClient->handleResetPhase(resetEvent);
+    if (mGraph) {
+        (void)mGraph->handleResetPhase(resetEvent);
+    }
+    if (mDebugDisplayManager) {
+        (void)mDebugDisplayManager->handleResetPhase(resetEvent);
+    }
+    // TODO: send to remote runner
+    mConfigBuilder.reset();
+    mCurrentPhase = kResetPhase;
+    mStopFromClient = false;
+}
+
+Status DefaultEngine::populateStreamManagers(const ClientConfig& config) {
+    std::map<int, int> outputConfigs;
+    if (config.getOutputStreamConfigs(outputConfigs) != Status::SUCCESS) {
+        return Status::ILLEGAL_STATE;
+    }
+    for (auto& configIt : outputConfigs) {
+        int streamId = configIt.first;
+        int maxInFlightPackets = configIt.second;
+        proto::OutputConfig outputDescriptor;
+        // find the output descriptor for requested stream id
+        bool foundDesc = false;
+        for (auto& optionIt : mGraphDescriptor.output_configs()) {
+            if (optionIt.stream_id() == streamId) {
+                outputDescriptor = optionIt;
+                foundDesc = true;
+                break;
+            }
+        }
+        if (!foundDesc) {
+            LOG(ERROR) << "no matching output config for requested id " << streamId;
+            return Status::INVALID_ARGUMENT;
+        }
+        std::function<Status(std::shared_ptr<MemHandle>)> packetCb =
+            [this, streamId](std::shared_ptr<MemHandle> handle) -> Status {
+            return this->forwardOutputDataToClient(streamId, handle);
+        };
+
+        std::function<void(std::string)> errorCb = [this, streamId](std::string m) {
+            std::string source = "StreamManager:" + std::to_string(streamId) + " : " + m;
+            this->queueError(source, m, false);
+        };
+
+        std::function<void()> eos = [this, streamId]() {
+            std::string source = "StreamManager:" + std::to_string(streamId);
+            std::lock_guard<std::mutex> lock(this->mEngineLock);
+            this->queueCommand(source, EngineCommand::Type::POLL_COMPLETE);
+        };
+
+        std::shared_ptr<StreamEngineInterface> engine = std::make_shared<StreamCallback>(
+            std::move(eos), std::move(errorCb), std::move(packetCb));
+        mStreamManagers.emplace(configIt.first, mStreamFactory.getStreamManager(
+                                                    outputDescriptor, engine, maxInFlightPackets));
+        if (mStreamManagers[streamId] == nullptr) {
+            LOG(ERROR) << "unable to create stream manager for stream " << streamId;
+            return Status::INTERNAL_ERROR;
+        }
+    }
+    return Status::SUCCESS;
+}
+
+Status DefaultEngine::forwardOutputDataToClient(int streamId,
+                                                std::shared_ptr<MemHandle>& dataHandle) {
+    if (streamId != mDisplayStream) {
+        return mClient->dispatchPacketToClient(streamId, dataHandle);
+    }
+
+    auto displayMgrPacket = dataHandle;
+    if (mConfigBuilder.clientConfigEnablesDisplayStream()) {
+        if (mStreamManagers.find(streamId) == mStreamManagers.end()) {
+            displayMgrPacket = nullptr;
+        } else {
+            displayMgrPacket = mStreamManagers[streamId]->clonePacket(dataHandle);
+        }
+        Status status = mClient->dispatchPacketToClient(streamId, dataHandle);
+        if (status != Status::SUCCESS) {
+            return status;
+        }
+    }
+    CHECK(mDebugDisplayManager);
+    return mDebugDisplayManager->displayFrame(dataHandle);
+}
+
+Status DefaultEngine::populateInputManagers(const ClientConfig& config) {
+    if (mIgnoreInputManager) {
+        return Status::SUCCESS;
+    }
+
+    proto::InputConfig inputDescriptor;
+    int selectedId;
+
+    if (config.getInputConfigId(&selectedId) != Status::SUCCESS) {
+        return Status::INVALID_ARGUMENT;
+    }
+
+    for (auto& inputIt : mGraphDescriptor.input_configs()) {
+        if (selectedId == inputIt.config_id()) {
+            inputDescriptor = inputIt;
+            std::shared_ptr<InputCallback> cb = std::make_shared<InputCallback>(
+                selectedId,
+                [this](int id) {
+                    std::string source = "InputManager:" + std::to_string(id);
+                    this->queueError(source, "", false);
+                },
+                [this](int streamId, int64_t timestamp, const InputFrame& frame) {
+                    return this->mGraph->SetInputStreamPixelData(streamId, timestamp, frame);
+                });
+            mInputManagers.emplace(selectedId,
+                                   mInputFactory.createInputManager(inputDescriptor, cb));
+            if (mInputManagers[selectedId] == nullptr) {
+                LOG(ERROR) << "unable to create input manager for stream " << selectedId;
+                // TODO: Add print
+                return Status::INTERNAL_ERROR;
+            }
+            return Status::SUCCESS;
+        }
+    }
+    return Status::INVALID_ARGUMENT;
+}
+
+/**
+ * Engine Command Queue and Error Queue handling
+ */
+void DefaultEngine::processCommands() {
+    std::unique_lock<std::mutex> lock(mEngineLock);
+    while (1) {
+        LOG(INFO) << "Engine::Waiting on commands ";
+        mWakeLooper.wait(lock, [this] {
+            if (this->mCommandQueue.empty() && !mCurrentPhaseError) {
+                return false;
+            } else {
+                return true;
+            }
+        });
+        if (mCurrentPhaseError) {
+            mErrorQueue.push(*mCurrentPhaseError);
+
+            processComponentError(mCurrentPhaseError->source);
+            mCurrentPhaseError = nullptr;
+            std::queue<EngineCommand> empty;
+            std::swap(mCommandQueue, empty);
+            continue;
+        }
+        EngineCommand ec = mCommandQueue.front();
+        mCommandQueue.pop();
+        switch (ec.cmdType) {
+            case EngineCommand::Type::BROADCAST_CONFIG:
+                LOG(INFO) << "Engine::Received broadcast config request";
+                (void)broadcastClientConfig();
+                break;
+            case EngineCommand::Type::BROADCAST_START_RUN:
+                LOG(INFO) << "Engine::Received broadcast run request";
+                (void)broadcastStartRun();
+                break;
+            case EngineCommand::Type::BROADCAST_INITIATE_STOP:
+                if (ec.source.find("ClientInterface") != std::string::npos) {
+                    mStopFromClient = true;
+                }
+                LOG(INFO) << "Engine::Received broadcast stop with flush request";
+                broadcastStopWithFlush();
+                break;
+            case EngineCommand::Type::POLL_COMPLETE:
+                LOG(INFO) << "Engine::Received Poll stream managers for completion request";
+                {
+                    int id = getStreamIdFromSource(ec.source);
+                    bool all_done = true;
+                    for (auto& it : mStreamManagers) {
+                        if (it.first == id) {
+                            continue;
+                        }
+                        if (it.second->getState() != StreamManager::State::STOPPED) {
+                            all_done = false;
+                        }
+                    }
+                    if (all_done) {
+                        broadcastStopComplete();
+                    }
+                }
+                break;
+            case EngineCommand::Type::RESET_CONFIG:
+                (void)broadcastReset();
+                break;
+            case EngineCommand::Type::RELEASE_DEBUGGER:
+                {
+                    // broadcastReset() resets the previous copy, so save a copy of the old config.
+                    ConfigBuilder previousConfig = mConfigBuilder;
+                    (void)broadcastReset();
+                    mConfigBuilder =
+                            previousConfig.updateProfilingType(proto::ProfilingType::DISABLED);
+                    (void)broadcastClientConfig();
+                }
+                break;
+            case EngineCommand::Type::READ_PROFILING:
+                std::string debugData;
+                if (mGraph && (mCurrentPhase == kConfigPhase || mCurrentPhase == kRunPhase
+                                || mCurrentPhase == kStopPhase)) {
+                    debugData = mGraph->GetDebugInfo();
+                }
+                if (mClient) {
+                    Status status = mClient->deliverGraphDebugInfo(debugData);
+                    if (status != Status::SUCCESS) {
+                        LOG(ERROR) << "Failed to deliver graph debug info to client.";
+                    }
+                }
+                break;
+        }
+    }
+}
+
+void DefaultEngine::processComponentError(std::string source) {
+    if (mCurrentPhase == kRunPhase || mCurrentPhase == kStopPhase) {
+        (void)broadcastHalt();
+    }
+    if (source.find("ClientInterface") != std::string::npos) {
+        (void)broadcastReset();
+    }
+}
+
+void DefaultEngine::queueCommand(std::string source, EngineCommand::Type type) {
+    mCommandQueue.push(EngineCommand(source, type));
+    mWakeLooper.notify_all();
+}
+
+void DefaultEngine::queueError(std::string source, std::string msg, bool fatal) {
+    std::lock_guard<std::mutex> lock(mEngineLock);
+    // current phase already has an error report
+    if (!mCurrentPhaseError) {
+        mCurrentPhaseError = std::make_unique<ComponentError>(source, msg, mCurrentPhase, fatal);
+        mWakeLooper.notify_all();
+    }
+}
+
+/**
+ * InputCallback implementation
+ */
+InputCallback::InputCallback(
+    int id, const std::function<void(int)>&& cb,
+    const std::function<Status(int, int64_t timestamp, const InputFrame&)>&& packetCb)
+    : mErrorCallback(cb), mPacketHandler(packetCb), mInputId(id) {
+}
+
+Status InputCallback::dispatchInputFrame(int streamId, int64_t timestamp, const InputFrame& frame) {
+    return mPacketHandler(streamId, timestamp, frame);
+}
+
+void InputCallback::notifyInputError() {
+    mErrorCallback(mInputId);
+}
+
+/**
+ * StreamCallback implementation
+ */
+StreamCallback::StreamCallback(
+    const std::function<void()>&& eos, const std::function<void(std::string)>&& errorCb,
+    const std::function<Status(const std::shared_ptr<MemHandle>&)>&& packetHandler)
+    : mErrorHandler(errorCb), mEndOfStreamHandler(eos), mPacketHandler(packetHandler) {
+}
+
+void StreamCallback::notifyError(std::string msg) {
+    mErrorHandler(msg);
+}
+
+void StreamCallback::notifyEndOfStream() {
+    mEndOfStreamHandler();
+}
+
+Status StreamCallback::dispatchPacket(const std::shared_ptr<MemHandle>& packet) {
+    return mPacketHandler(packet);
+}
+
+}  // namespace engine
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/engine/DefaultEngine.h b/computepipe/runner/engine/DefaultEngine.h
new file mode 100644
index 0000000..d4eaa5e
--- /dev/null
+++ b/computepipe/runner/engine/DefaultEngine.h
@@ -0,0 +1,335 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_ENGINE_DEFAULTENGINE_H_
+#define COMPUTEPIPE_RUNNER_ENGINE_DEFAULTENGINE_H_
+
+#include <condition_variable>
+#include <functional>
+#include <mutex>
+#include <queue>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include "ConfigBuilder.h"
+#include "DebugDisplayManager.h"
+#include "InputManager.h"
+#include "Options.pb.h"
+#include "RunnerEngine.h"
+#include "StreamManager.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace engine {
+
+class InputCallback;
+
+/**
+ * EngineCommand represents client requests or error events.
+ * Each command is queued, and processed by the engine thread.
+ */
+struct EngineCommand {
+  public:
+    enum Type {
+        BROADCAST_CONFIG = 0,
+        BROADCAST_START_RUN,
+        BROADCAST_INITIATE_STOP,
+        POLL_COMPLETE,
+        RESET_CONFIG,
+        RELEASE_DEBUGGER,
+        READ_PROFILING,
+    };
+    std::string source;
+    Type cmdType;
+    explicit EngineCommand(std::string s, Type t) : source(s), cmdType(t) {
+    }
+};
+
+/**
+ * Component Error represents the type of error reported by a component.
+ */
+struct ComponentError {
+  public:
+    bool isFatal;
+    std::string source;
+    std::string message;
+    std::string currentPhase;
+    explicit ComponentError(std::string s, std::string m, std::string p, bool fatal = false)
+        : isFatal(fatal), source(s), message(m), currentPhase(p) {
+    }
+};
+
+/**
+ * Default Engine implementation.
+ * Takes ownership of externally instantiated graph & client interface
+ * instances. Brings the runner online. Manages components.
+ * Responds to client events.
+ */
+class DefaultEngine : public RunnerEngine {
+  public:
+    static constexpr char kDisplayStreamId[] = "display_stream:";
+    static constexpr char kNoInputManager[] = "no_input_manager";
+    static constexpr char kResetPhase[] = "Reset";
+    static constexpr char kConfigPhase[] = "Config";
+    static constexpr char kRunPhase[] = "Running";
+    static constexpr char kStopPhase[] = "Stopping";
+    /**
+     * Methods from Runner Engine to override
+     */
+    Status setArgs(std::string engine_args) override;
+    void setClientInterface(std::unique_ptr<client_interface::ClientInterface>&& client) override;
+    void setPrebuiltGraph(std::unique_ptr<graph::PrebuiltGraph>&& graph) override;
+    Status activate() override;
+    /**
+     * Methods from ClientEngineInterface to override
+     */
+    Status processClientConfigUpdate(const proto::ConfigurationCommand& command) override;
+    Status processClientCommand(const proto::ControlCommand& command) override;
+    Status freePacket(int bufferId, int streamId) override;
+    /**
+     * Methods from PrebuiltEngineInterface to override
+     */
+    void DispatchPixelData(int streamId, int64_t timestamp, const InputFrame& frame) override;
+
+    void DispatchSerializedData(int streamId, int64_t timestamp, std::string&& output) override;
+
+    void DispatchGraphTerminationMessage(Status s, std::string&& msg) override;
+
+  private:
+    // TODO: b/147704051 Add thread analyzer annotations
+    /**
+     * BroadCast Client config to all components. If all components handle the
+     * notification correctly, then broadcast transition complete.
+     * Successful return from this function implies runner has transitioned to
+     * configuration done.
+     * @Lock held mEngineLock
+     */
+    Status broadcastClientConfig();
+    /**
+     * Abort an ongoing attempt to apply client configs.
+     * @Lock held mEngineLock
+     */
+    void abortClientConfig(const ClientConfig& config, bool resetGraph = false);
+    /**
+     * BroadCast start to all components. The order of entry into run phase
+     * notification delivery is downstream components to upstream components.
+     * If all components handle the entry notification correctly then broadcast
+     * transition complete notification again from down stream to upstream.
+     * Successful return from this function implies runner has transitioned to
+     * running.
+     * @Lock held mEngineLock
+     */
+    Status broadcastStartRun();
+    /**
+     * BroadCast abort of started run to given components. This gets called if during
+     * broadcastStartRun(), one of the components failed to set itself up for the run. In that case
+     * the components that had successfully acknowledged broacastStartRun(),
+     * need to be told to abort. We transition back to config phase at the end
+     * of this call.
+     * @Lock held mEngineLock
+     */
+    void broadcastAbortRun(const std::vector<int>& streamIds, const std::vector<int>& inputIds,
+                           bool graph = false);
+
+    /**
+     * Broadcast stop with flush to all components. The stop with flush phase
+     * entry notification is sent from in the order of upstream to downstream.
+     * A successful return can leave the runner in stopping phase.
+     * We transition to stop completely, once all inflight traffic has been drained at a later
+     * point, identified by stream managers.
+     * @Lock held mEngineLock
+     */
+    Status broadcastStopWithFlush();
+    /**
+     * Broadcast transtion to stop complete. This is a confirmation to all
+     * components that stop has finished. At the end of this we transition back
+     * to config phase.
+     * @Lock held mEngineLock
+     */
+    Status broadcastStopComplete();
+    /**
+     * Broadcast halt to all components. All inflight traffic is dropped.
+     * Successful return from this function implies all components have
+     * exited run phase and are back in config phase.
+     * @Lock held mEngineLock
+     */
+    void broadcastHalt();
+    /**
+     * Broadcast reset to all components. All components drop client
+     * specific configuration and transition to reset state. For RAII
+     * components, they are freed at this point. ALso resets the mConfigBuilder
+     * to its original state. Successful return puts the runner in reset phase.
+     * @Lock held mEngineLock
+     */
+    void broadcastReset();
+    /**
+     * Populate stream managers for a given client config. For each client
+     * selected output config, we generate stream managers. During reset phase
+     * we clear out any previously constructed stream managers. This should be
+     * invoked only in response to applyConfigs() issued by client.
+     * @Lock held mEngineLock
+     */
+    Status populateStreamManagers(const ClientConfig& config);
+    /**
+     * Populate input managers for a given client config. For each client
+     * selected output config, we generate input managers. During reset phase
+     * we clear out any previously constructed input managers. This should be
+     * invoked only in response to applyConfigs() issued by client.
+     * @Lock held mEngineLock
+     */
+    Status populateInputManagers(const ClientConfig& config);
+    /**
+     * Helper method to forward packet to client interface for transmission
+     */
+    Status forwardOutputDataToClient(int streamId, std::shared_ptr<MemHandle>& handle);
+    /**
+     * Helper to handle error notification from components, in the errorQueue.
+     * In case the source of the error is client interface, it will
+     * broadcastReset().
+     * This called in the mEngineThread when processing an entry from the
+     * errorQueue,
+     * @Lock acquires mEngineLock.
+     */
+    void processComponentError(std::string source);
+    /**
+     * Method run by the engine thread to process commands.
+     * Uses condition variable. Acquires lock mEngineLock to access
+     * command queues.
+     */
+    void processCommands();
+    /**
+     * Method run by external components to queue commands to the engine.
+     * Must be called with mEngineLock held. Wakes up the looper.
+     */
+    void queueCommand(std::string source, EngineCommand::Type type);
+    /**
+     * Method called by component reporting error.
+     * This will acquire mEngineLock and queue the error.
+     */
+    void queueError(std::string source, std::string msg, bool fatal);
+    /**
+     * client interface handle
+     */
+    std::unique_ptr<client_interface::ClientInterface> mClient = nullptr;
+    /**
+     * builder to build up client config incrementally.
+     */
+    ConfigBuilder mConfigBuilder;
+    /**
+     * Stream management members
+     */
+    std::map<int, std::unique_ptr<stream_manager::StreamManager>> mStreamManagers;
+    stream_manager::StreamManagerFactory mStreamFactory;
+    /**
+     * Input manager members
+     */
+    std::map<int, std::unique_ptr<input_manager::InputManager>> mInputManagers;
+    input_manager::InputManagerFactory mInputFactory;
+    /**
+     * stream to dump to display for debug purposes
+     */
+    int32_t mDisplayStream = ClientConfig::kInvalidId;
+    /**
+     * Debug display manager.
+     */
+    std::unique_ptr<debug_display_manager::DebugDisplayManager> mDebugDisplayManager = nullptr;
+    /**
+     * graph descriptor
+     */
+    proto::Options mGraphDescriptor;
+    std::unique_ptr<graph::PrebuiltGraph> mGraph;
+    /**
+     * stop signal source
+     */
+    bool mStopFromClient = true;
+    /**
+     * Phase management members
+     */
+    std::string mCurrentPhase = kResetPhase;
+    std::mutex mEngineLock;
+    /**
+     * Used to track the first error occurrence for a given phase.
+     */
+    std::unique_ptr<ComponentError> mCurrentPhaseError = nullptr;
+
+    /**
+     * Queue for client commands
+     */
+    std::queue<EngineCommand> mCommandQueue;
+    /**
+     * Queue for error notifications
+     */
+    std::queue<ComponentError> mErrorQueue;
+    /**
+     * Engine looper
+     */
+    std::unique_ptr<std::thread> mEngineThread;
+    /**
+     * Condition variable for looper
+     */
+    std::condition_variable mWakeLooper;
+    /**
+     * ignore input manager allocation
+     */
+    bool mIgnoreInputManager = false;
+};
+
+/**
+ * Handles callbacks from individual stream managers as specified in the
+ * StreamEngineInterface.
+ */
+class StreamCallback : public stream_manager::StreamEngineInterface {
+  public:
+    explicit StreamCallback(
+        const std::function<void()>&& eos, const std::function<void(std::string)>&& errorCb,
+        const std::function<Status(const std::shared_ptr<MemHandle>&)>&& packetHandler);
+    void notifyEndOfStream() override;
+    void notifyError(std::string msg) override;
+    Status dispatchPacket(const std::shared_ptr<MemHandle>& outData) override;
+    ~StreamCallback() = default;
+
+  private:
+    std::function<void(std::string)> mErrorHandler;
+    std::function<void()> mEndOfStreamHandler;
+    std::function<Status(const std::shared_ptr<MemHandle>&)> mPacketHandler;
+};
+
+/**
+ * Handles callbacks from input managers. Forwards frames to the graph.
+ * Only used if graph implementation is local
+ */
+class InputCallback : public input_manager::InputEngineInterface {
+  public:
+    explicit InputCallback(int id, const std::function<void(int)>&& cb,
+                           const std::function<Status(int, int64_t, const InputFrame&)>&& packetCb);
+    Status dispatchInputFrame(int streamId, int64_t timestamp, const InputFrame& frame) override;
+    void notifyInputError() override;
+    ~InputCallback() = default;
+
+  private:
+    std::function<void(int)> mErrorCallback;
+    std::function<Status(int, int64_t, const InputFrame&)> mPacketHandler;
+    int mInputId;
+};
+
+}  // namespace engine
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // COMPUTEPIPE_RUNNER_ENGINE_DEFAULTENGINE_H_
diff --git a/computepipe/runner/engine/Factory.cpp b/computepipe/runner/engine/Factory.cpp
new file mode 100644
index 0000000..67b3cd3
--- /dev/null
+++ b/computepipe/runner/engine/Factory.cpp
@@ -0,0 +1,46 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "DefaultEngine.h"
+#include "RunnerEngine.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace engine {
+
+namespace {
+std::unique_ptr<DefaultEngine> createDefaultEngine(std::string engine_args) {
+    std::unique_ptr<DefaultEngine> engine = std::make_unique<DefaultEngine>();
+    if (engine->setArgs(engine_args) != Status::SUCCESS) {
+        return nullptr;
+    }
+    return engine;
+}
+}  // namespace
+
+std::unique_ptr<RunnerEngine> RunnerEngineFactory::createRunnerEngine(std::string engine,
+                                                                      std::string engine_args) {
+    if (engine == kDefault) {
+        return createDefaultEngine(engine_args);
+    }
+    return nullptr;
+}
+
+}  // namespace engine
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/engine/include/RunnerEngine.h b/computepipe/runner/engine/include/RunnerEngine.h
new file mode 100644
index 0000000..778099d
--- /dev/null
+++ b/computepipe/runner/engine/include/RunnerEngine.h
@@ -0,0 +1,71 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_ENGINE_H
+#define COMPUTEPIPE_RUNNER_ENGINE_H
+
+#include <memory>
+#include <string>
+
+#include "ClientInterface.h"
+#include "PrebuiltGraph.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace engine {
+
+/**
+ * Class that offers an interface into an engine. It derives from the client,
+ * prebuilt -> engine interfaces to enforce that any instantiation of an engine
+ * needs to provide an implementation for those interfaces.
+ */
+class RunnerEngine : public client_interface::ClientEngineInterface,
+                     public graph::PrebuiltEngineInterface {
+  public:
+    /**
+     * Any args that a given engine instance needs in order to configure itself.
+     */
+    virtual Status setArgs(std::string engine_args) = 0;
+    /**
+     * Set the client and the prebuilt graph instances
+     */
+    virtual void setClientInterface(std::unique_ptr<client_interface::ClientInterface>&& client) = 0;
+
+    virtual void setPrebuiltGraph(std::unique_ptr<graph::PrebuiltGraph>&& graph) = 0;
+    /**
+     * Activates the client interface and advertises to the rest of the world
+     * that the runner is online
+     */
+    virtual Status activate() = 0;
+};
+
+class RunnerEngineFactory {
+  public:
+    static constexpr char kDefault[] = "default_engine";
+    std::unique_ptr<RunnerEngine> createRunnerEngine(std::string engine, std::string engine_args);
+    RunnerEngineFactory(const RunnerEngineFactory&) = delete;
+    RunnerEngineFactory& operator=(const RunnerEngineFactory&) = delete;
+    RunnerEngineFactory() = default;
+};
+
+}  // namespace engine
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif
diff --git a/computepipe/runner/graph/Android.bp b/computepipe/runner/graph/Android.bp
new file mode 100644
index 0000000..614eabc
--- /dev/null
+++ b/computepipe/runner/graph/Android.bp
@@ -0,0 +1,85 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library {
+    name: "computepipe_prebuilt_graph",
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+        "-Wno-unused-parameter",
+    ],
+
+    export_include_dirs: ["include"],
+    static_libs: [
+        "computepipe_runner_component",
+    ],
+
+    header_libs: ["computepipe_runner_includes"],
+    include_dirs: [
+          "packages/services/Car/computepipe",
+          "packages/services/Car/computepipe/runner/graph",
+    ],
+
+    shared_libs: [
+        "libcomputepipeprotos",
+        "libbase",
+        "libdl",
+        "liblog",
+        "libutils",
+    ],
+
+    srcs: [
+        "LocalPrebuiltGraph.cpp",
+    ],
+}
+
+cc_library {
+    name: "computepipe_grpc_graph",
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+        "-Wno-unused-parameter",
+    ],
+
+    export_include_dirs: ["include"],
+    static_libs: [
+        "computepipe_runner_component",
+        "computepipe_grpc_graph_proto",
+    ],
+
+    header_libs: ["computepipe_runner_includes"],
+    include_dirs: [
+          "packages/services/Car/computepipe",
+          "packages/services/Car/computepipe/runner/graph",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "libcomputepipeprotos",
+        "libdl",
+        "libgrpc++",
+        "liblog",
+        "libutils",
+        "libprotobuf-cpp-full",
+    ],
+
+    srcs: [
+        "GrpcGraph.cpp",
+        "StreamSetObserver.cpp",
+    ],
+}
diff --git a/computepipe/runner/graph/GrpcGraph.cpp b/computepipe/runner/graph/GrpcGraph.cpp
new file mode 100644
index 0000000..6967230
--- /dev/null
+++ b/computepipe/runner/graph/GrpcGraph.cpp
@@ -0,0 +1,464 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "GrpcGraph.h"
+
+#include <cstdlib>
+
+#include <android-base/logging.h>
+#include <grpcpp/grpcpp.h>
+
+#include "ClientConfig.pb.h"
+#include "GrpcGraph.h"
+#include "InputFrame.h"
+#include "RunnerComponent.h"
+#include "prebuilt_interface.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+namespace {
+constexpr int64_t kRpcDeadlineMilliseconds = 100;
+
+template <class ResponseType, class RpcType>
+std::pair<Status, std::string> FinishRpcAndGetResult(
+        ::grpc::ClientAsyncResponseReader<RpcType>* rpc, ::grpc::CompletionQueue* cq,
+        ResponseType* response) {
+    int random_tag = rand();
+    ::grpc::Status grpcStatus;
+    rpc->Finish(response, &grpcStatus, reinterpret_cast<void*>(random_tag));
+    bool ok = false;
+    void* got_tag;
+    if (!cq->Next(&got_tag, &ok)) {
+        LOG(ERROR) << "Unexpected shutdown of the completion queue";
+        return std::pair(Status::FATAL_ERROR, "Unexpected shutdown of the completion queue");
+    }
+
+    if (!ok) {
+        LOG(ERROR) << "Unable to complete RPC request";
+        return std::pair(Status::FATAL_ERROR, "Unable to complete RPC request");
+    }
+
+    CHECK_EQ(got_tag, reinterpret_cast<void*>(random_tag));
+    if (!grpcStatus.ok()) {
+        std::string error_message =
+                std::string("Grpc failed with error: ") + grpcStatus.error_message();
+        LOG(ERROR) << error_message;
+        return std::pair(Status::FATAL_ERROR, std::move(error_message));
+    }
+
+    return std::pair(Status::SUCCESS, std::string(""));
+}
+
+}  // namespace
+
+PrebuiltGraphState GrpcGraph::GetGraphState() const {
+    std::lock_guard lock(mLock);
+    return mGraphState;
+}
+
+Status GrpcGraph::GetStatus() const {
+    std::lock_guard lock(mLock);
+    return mStatus;
+}
+
+std::string GrpcGraph::GetErrorMessage() const {
+    std::lock_guard lock(mLock);
+    return mErrorMessage;
+}
+
+Status GrpcGraph::initialize(const std::string& address,
+                             std::weak_ptr<PrebuiltEngineInterface> engineInterface) {
+    std::shared_ptr<::grpc::ChannelCredentials> creds = ::grpc::InsecureChannelCredentials();
+    std::shared_ptr<::grpc::Channel> channel = ::grpc::CreateChannel(address, creds);
+    mGraphStub = proto::GrpcGraphService::NewStub(channel);
+    mEngineInterface = engineInterface;
+
+    ::grpc::ClientContext context;
+    context.set_deadline(std::chrono::system_clock::now() +
+                         std::chrono::milliseconds(kRpcDeadlineMilliseconds));
+    ::grpc::CompletionQueue cq;
+
+    proto::GraphOptionsRequest getGraphOptionsRequest;
+    std::unique_ptr<::grpc::ClientAsyncResponseReader<proto::GraphOptionsResponse>> rpc(
+            mGraphStub->AsyncGetGraphOptions(&context, getGraphOptionsRequest, &cq));
+
+    proto::GraphOptionsResponse response;
+    auto [mStatus, mErrorMessage] = FinishRpcAndGetResult(rpc.get(), &cq, &response);
+
+    if (mStatus != Status::SUCCESS) {
+        LOG(ERROR) << "Failed to get graph options: " << mErrorMessage;
+        return Status::FATAL_ERROR;
+    }
+
+    std::string serialized_options = response.serialized_options();
+    if (!mGraphConfig.ParseFromString(serialized_options)) {
+        mErrorMessage = "Failed to parse graph options";
+        LOG(ERROR) << "Failed to parse graph options";
+        return Status::FATAL_ERROR;
+    }
+
+    mGraphState = PrebuiltGraphState::STOPPED;
+    return Status::SUCCESS;
+}
+
+// Function to confirm that there would be no further changes to the graph configuration. This
+// needs to be called before starting the graph.
+Status GrpcGraph::handleConfigPhase(const runner::ClientConfig& e) {
+    std::lock_guard lock(mLock);
+    if (mGraphState == PrebuiltGraphState::UNINITIALIZED) {
+        mStatus = Status::ILLEGAL_STATE;
+        return Status::ILLEGAL_STATE;
+    }
+
+    // handleConfigPhase is a blocking call, so abort call is pointless for this RunnerEvent.
+    if (e.isAborted()) {
+        mStatus = Status::INVALID_ARGUMENT;
+        return mStatus;
+    } else if (e.isTransitionComplete()) {
+        mStatus = Status::SUCCESS;
+        return mStatus;
+    }
+
+    ::grpc::ClientContext context;
+    context.set_deadline(std::chrono::system_clock::now() +
+                         std::chrono::milliseconds(kRpcDeadlineMilliseconds));
+    ::grpc::CompletionQueue cq;
+
+    std::string serializedConfig = e.getSerializedClientConfig();
+    proto::SetGraphConfigRequest setGraphConfigRequest;
+    setGraphConfigRequest.set_serialized_config(std::move(serializedConfig));
+
+    std::unique_ptr<::grpc::ClientAsyncResponseReader<proto::StatusResponse>> rpc(
+            mGraphStub->AsyncSetGraphConfig(&context, setGraphConfigRequest, &cq));
+
+    proto::StatusResponse response;
+    auto [mStatus, mErrorMessage] = FinishRpcAndGetResult(rpc.get(), &cq, &response);
+    if (mStatus != Status::SUCCESS) {
+        LOG(ERROR) << "Rpc failed while trying to set configuration";
+        return mStatus;
+    }
+
+    if (response.code() != proto::RemoteGraphStatusCode::SUCCESS) {
+        LOG(ERROR) << "Failed to cofngure remote graph. " << response.message();
+    }
+
+    mStatus = static_cast<Status>(static_cast<int>(response.code()));
+    mErrorMessage = response.message();
+
+    mStreamSetObserver = std::make_unique<StreamSetObserver>(e, this);
+
+    return mStatus;
+}
+
+// Starts the graph.
+Status GrpcGraph::handleExecutionPhase(const runner::RunnerEvent& e) {
+    std::lock_guard lock(mLock);
+    if (mGraphState != PrebuiltGraphState::STOPPED) {
+        mStatus = Status::ILLEGAL_STATE;
+        return mStatus;
+    }
+
+    if (e.isAborted()) {
+        // Starting the graph is a blocking call and cannot be aborted in between.
+        mStatus = Status::INVALID_ARGUMENT;
+        return mStatus;
+    } else if (e.isTransitionComplete()) {
+        mStatus = Status::SUCCESS;
+        return mStatus;
+    }
+
+    // Start observing the output streams
+    mStatus = mStreamSetObserver->startObservingStreams();
+    if (mStatus != Status::SUCCESS) {
+        mErrorMessage = "Failed to observe output streams";
+        return mStatus;
+    }
+
+    ::grpc::ClientContext context;
+    context.set_deadline(std::chrono::system_clock::now() +
+                         std::chrono::milliseconds(kRpcDeadlineMilliseconds));
+
+    proto::StartGraphExecutionRequest startExecutionRequest;
+    ::grpc::CompletionQueue cq;
+    std::unique_ptr<::grpc::ClientAsyncResponseReader<proto::StatusResponse>> rpc(
+            mGraphStub->AsyncStartGraphExecution(&context, startExecutionRequest, &cq));
+
+    proto::StatusResponse response;
+    auto [mStatus, mErrorMessage] = FinishRpcAndGetResult(rpc.get(), &cq, &response);
+    if (mStatus != Status::SUCCESS) {
+        LOG(ERROR) << "Failed to start graph execution";
+        return mStatus;
+    }
+
+    mStatus = static_cast<Status>(static_cast<int>(response.code()));
+    mErrorMessage = response.message();
+
+    if (mStatus == Status::SUCCESS) {
+        mGraphState = PrebuiltGraphState::RUNNING;
+    }
+
+    return mStatus;
+}
+
+// Stops the graph while letting the graph flush output packets in flight.
+Status GrpcGraph::handleStopWithFlushPhase(const runner::RunnerEvent& e) {
+    std::lock_guard lock(mLock);
+    if (mGraphState != PrebuiltGraphState::RUNNING) {
+        return Status::ILLEGAL_STATE;
+    }
+
+    if (e.isAborted()) {
+        return Status::INVALID_ARGUMENT;
+    } else if (e.isTransitionComplete()) {
+        return Status::SUCCESS;
+    }
+
+    ::grpc::ClientContext context;
+    context.set_deadline(std::chrono::system_clock::now() +
+                         std::chrono::milliseconds(kRpcDeadlineMilliseconds));
+
+    proto::StopGraphExecutionRequest stopExecutionRequest;
+    stopExecutionRequest.set_stop_immediate(false);
+    ::grpc::CompletionQueue cq;
+    std::unique_ptr<::grpc::ClientAsyncResponseReader<proto::StatusResponse>> rpc(
+            mGraphStub->AsyncStopGraphExecution(&context, stopExecutionRequest, &cq));
+
+    proto::StatusResponse response;
+    auto [mStatus, mErrorMessage] = FinishRpcAndGetResult(rpc.get(), &cq, &response);
+    if (mStatus != Status::SUCCESS) {
+        LOG(ERROR) << "Failed to stop graph execution";
+        return Status::FATAL_ERROR;
+    }
+
+    // Stop observing streams immendiately.
+    mStreamSetObserver->stopObservingStreams(false);
+
+    mStatus = static_cast<Status>(static_cast<int>(response.code()));
+    mErrorMessage = response.message();
+
+    if (mStatus == Status::SUCCESS) {
+        mGraphState = PrebuiltGraphState::FLUSHING;
+    }
+
+    return mStatus;
+}
+
+// Stops the graph and cancels all the output packets.
+Status GrpcGraph::handleStopImmediatePhase(const runner::RunnerEvent& e) {
+    std::lock_guard lock(mLock);
+    if (mGraphState != PrebuiltGraphState::RUNNING) {
+        return Status::ILLEGAL_STATE;
+    }
+
+    if (e.isAborted()) {
+        return Status::INVALID_ARGUMENT;
+    } else if (e.isTransitionComplete()) {
+        return Status::SUCCESS;
+    }
+
+    ::grpc::ClientContext context;
+    context.set_deadline(std::chrono::system_clock::now() +
+                         std::chrono::milliseconds(kRpcDeadlineMilliseconds));
+
+    proto::StopGraphExecutionRequest stopExecutionRequest;
+    stopExecutionRequest.set_stop_immediate(true);
+    ::grpc::CompletionQueue cq;
+    std::unique_ptr<::grpc::ClientAsyncResponseReader<proto::StatusResponse>> rpc(
+            mGraphStub->AsyncStopGraphExecution(&context, stopExecutionRequest, &cq));
+
+    proto::StatusResponse response;
+    auto [mStatus, mErrorMessage] = FinishRpcAndGetResult(rpc.get(), &cq, &response);
+    if (mStatus != Status::SUCCESS) {
+        LOG(ERROR) << "Failed to stop graph execution";
+        return Status::FATAL_ERROR;
+    }
+
+    mStatus = static_cast<Status>(static_cast<int>(response.code()));
+    mErrorMessage = response.message();
+
+    // Stop observing streams immendiately.
+    mStreamSetObserver->stopObservingStreams(true);
+
+    if (mStatus == Status::SUCCESS) {
+        mGraphState = PrebuiltGraphState::STOPPED;
+    }
+    return mStatus;
+}
+
+Status GrpcGraph::handleResetPhase(const runner::RunnerEvent& e) {
+    std::lock_guard lock(mLock);
+    if (mGraphState != PrebuiltGraphState::STOPPED) {
+        return Status::ILLEGAL_STATE;
+    }
+
+    if (e.isAborted()) {
+        return Status::INVALID_ARGUMENT;
+    } else if (e.isTransitionComplete()) {
+        return Status::SUCCESS;
+    }
+
+    ::grpc::ClientContext context;
+    context.set_deadline(std::chrono::system_clock::now() +
+                         std::chrono::milliseconds(kRpcDeadlineMilliseconds));
+
+    proto::ResetGraphRequest resetGraphRequest;
+    ::grpc::CompletionQueue cq;
+    std::unique_ptr<::grpc::ClientAsyncResponseReader<proto::StatusResponse>> rpc(
+            mGraphStub->AsyncResetGraph(&context, resetGraphRequest, &cq));
+
+    proto::StatusResponse response;
+    auto [mStatus, mErrorMessage] = FinishRpcAndGetResult(rpc.get(), &cq, &response);
+    if (mStatus != Status::SUCCESS) {
+        LOG(ERROR) << "Failed to stop graph execution";
+        return Status::FATAL_ERROR;
+    }
+
+    mStatus = static_cast<Status>(static_cast<int>(response.code()));
+    mErrorMessage = response.message();
+    mStreamSetObserver.reset();
+
+    return mStatus;
+}
+
+Status GrpcGraph::SetInputStreamData(int /*streamIndex*/, int64_t /*timestamp*/,
+                                     const std::string& /*streamData*/) {
+    LOG(ERROR) << "Cannot set input stream for remote graphs";
+    return Status::FATAL_ERROR;
+}
+
+Status GrpcGraph::SetInputStreamPixelData(int /*streamIndex*/, int64_t /*timestamp*/,
+                                          const runner::InputFrame& /*inputFrame*/) {
+    LOG(ERROR) << "Cannot set input streams for remote graphs";
+    return Status::FATAL_ERROR;
+}
+
+Status GrpcGraph::StartGraphProfiling() {
+    std::lock_guard lock(mLock);
+    if (mGraphState != PrebuiltGraphState::RUNNING) {
+        return Status::ILLEGAL_STATE;
+    }
+
+    ::grpc::ClientContext context;
+    context.set_deadline(std::chrono::system_clock::now() +
+                         std::chrono::milliseconds(kRpcDeadlineMilliseconds));
+
+    proto::StartGraphProfilingRequest startProfilingRequest;
+    ::grpc::CompletionQueue cq;
+    std::unique_ptr<::grpc::ClientAsyncResponseReader<proto::StatusResponse>> rpc(
+            mGraphStub->AsyncStartGraphProfiling(&context, startProfilingRequest, &cq));
+
+    proto::StatusResponse response;
+    auto [mStatus, mErrorMessage] = FinishRpcAndGetResult(rpc.get(), &cq, &response);
+    if (mStatus != Status::SUCCESS) {
+        LOG(ERROR) << "Failed to start graph profiling";
+        return Status::FATAL_ERROR;
+    }
+
+    mStatus = static_cast<Status>(static_cast<int>(response.code()));
+    mErrorMessage = response.message();
+
+    return mStatus;
+}
+
+Status GrpcGraph::StopGraphProfiling() {
+    // Stopping profiling after graph has already stopped can be a no-op
+    ::grpc::ClientContext context;
+    context.set_deadline(std::chrono::system_clock::now() +
+                         std::chrono::milliseconds(kRpcDeadlineMilliseconds));
+
+    proto::StopGraphProfilingRequest stopProfilingRequest;
+    ::grpc::CompletionQueue cq;
+    std::unique_ptr<::grpc::ClientAsyncResponseReader<proto::StatusResponse>> rpc(
+            mGraphStub->AsyncStopGraphProfiling(&context, stopProfilingRequest, &cq));
+
+    proto::StatusResponse response;
+    auto [mStatus, mErrorMessage] = FinishRpcAndGetResult(rpc.get(), &cq, &response);
+    if (mStatus != Status::SUCCESS) {
+        LOG(ERROR) << "Failed to stop graph profiling";
+        return Status::FATAL_ERROR;
+    }
+
+    mStatus = static_cast<Status>(static_cast<int>(response.code()));
+    mErrorMessage = response.message();
+
+    return mStatus;
+}
+
+std::string GrpcGraph::GetDebugInfo() {
+    ::grpc::ClientContext context;
+    context.set_deadline(std::chrono::system_clock::now() +
+                         std::chrono::milliseconds(kRpcDeadlineMilliseconds));
+
+    proto::ProfilingDataRequest profilingDataRequest;
+    ::grpc::CompletionQueue cq;
+    std::unique_ptr<::grpc::ClientAsyncResponseReader<proto::ProfilingDataResponse>> rpc(
+            mGraphStub->AsyncGetProfilingData(&context, profilingDataRequest, &cq));
+
+    proto::ProfilingDataResponse response;
+    auto [mStatus, mErrorMessage] = FinishRpcAndGetResult(rpc.get(), &cq, &response);
+    if (mStatus != Status::SUCCESS) {
+        LOG(ERROR) << "Failed to get profiling info";
+        return "";
+    }
+
+    return response.data();
+}
+
+void GrpcGraph::dispatchPixelData(int streamId, int64_t timestamp_us,
+                                  const runner::InputFrame& frame) {
+    std::shared_ptr<PrebuiltEngineInterface> engineInterface = mEngineInterface.lock();
+    if (engineInterface) {
+        return engineInterface->DispatchPixelData(streamId, timestamp_us, frame);
+    }
+}
+
+void GrpcGraph::dispatchSerializedData(int streamId, int64_t timestamp_us,
+                                       std::string&& serialized_data) {
+    std::shared_ptr<PrebuiltEngineInterface> engineInterface = mEngineInterface.lock();
+    if (engineInterface) {
+        return engineInterface->DispatchSerializedData(streamId, timestamp_us,
+                                                       std::move(serialized_data));
+    }
+}
+
+void GrpcGraph::dispatchGraphTerminationMessage(Status status, std::string&& errorMessage) {
+    std::lock_guard lock(mLock);
+    mErrorMessage = std::move(errorMessage);
+    mStatus = status;
+    mGraphState = PrebuiltGraphState::STOPPED;
+    std::shared_ptr<PrebuiltEngineInterface> engineInterface = mEngineInterface.lock();
+    if (engineInterface) {
+        std::string errorMessageTmp = mErrorMessage;
+        engineInterface->DispatchGraphTerminationMessage(mStatus, std::move(errorMessageTmp));
+    }
+}
+
+std::unique_ptr<PrebuiltGraph> GetRemoteGraphFromAddress(
+        const std::string& address, std::weak_ptr<PrebuiltEngineInterface> engineInterface) {
+    auto prebuiltGraph = std::make_unique<GrpcGraph>();
+    Status status = prebuiltGraph->initialize(address, engineInterface);
+    if (status != Status::SUCCESS) {
+        return nullptr;
+    }
+
+    return prebuiltGraph;
+}
+
+}  // namespace graph
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/graph/GrpcGraph.h b/computepipe/runner/graph/GrpcGraph.h
new file mode 100644
index 0000000..d833dd2
--- /dev/null
+++ b/computepipe/runner/graph/GrpcGraph.h
@@ -0,0 +1,134 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_GRAPH_INCLUDE_LOCALPREBUILTGRAPH_H
+#define COMPUTEPIPE_RUNNER_GRAPH_INCLUDE_LOCALPREBUILTGRAPH_H
+
+#include <condition_variable>
+#include <functional>
+#include <map>
+#include <memory>
+#include <shared_mutex>
+#include <string>
+#include <thread>
+
+#include "ClientConfig.pb.h"
+#include "GrpcPrebuiltGraphService.grpc.pb.h"
+#include "GrpcPrebuiltGraphService.pb.h"
+#include "InputFrame.h"
+#include "Options.pb.h"
+#include "OutputConfig.pb.h"
+#include "PrebuiltEngineInterface.h"
+#include "PrebuiltGraph.h"
+#include "RunnerComponent.h"
+#include "StreamSetObserver.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+
+class GrpcGraph : public PrebuiltGraph, public StreamGraphInterface {
+
+  public:
+    GrpcGraph() {}
+
+    virtual ~GrpcGraph() {}
+
+    Status initialize(const std::string& address,
+                      std::weak_ptr<PrebuiltEngineInterface> engineInterface);
+
+    // No copy or move constructors or operators are available.
+    GrpcGraph(const GrpcGraph&) = delete;
+    GrpcGraph& operator=(const GrpcGraph&) = delete;
+
+    // Override RunnerComponent interface functions for applying configs,
+    // starting the graph and stopping the graph.
+    Status handleConfigPhase(const runner::ClientConfig& e) override;
+    Status handleExecutionPhase(const runner::RunnerEvent& e) override;
+    Status handleStopWithFlushPhase(const runner::RunnerEvent& e) override;
+    Status handleStopImmediatePhase(const runner::RunnerEvent& e) override;
+    Status handleResetPhase(const runner::RunnerEvent& e) override;
+
+    PrebuiltGraphType GetGraphType() const override {
+        return PrebuiltGraphType::REMOTE;
+    }
+
+    PrebuiltGraphState GetGraphState() const override;
+    Status GetStatus() const override;
+    std::string GetErrorMessage() const override;
+
+    // Gets the supported graph config options.
+    const proto::Options& GetSupportedGraphConfigs() const override {
+        return mGraphConfig;
+    }
+
+    // Sets input stream data. The string is expected to be a serialized proto
+    // the definition of which is known to the graph.
+    Status SetInputStreamData(int streamIndex, int64_t timestamp,
+                              const std::string& streamData) override;
+
+    // Sets pixel data to the specified input stream index.
+    Status SetInputStreamPixelData(int streamIndex, int64_t timestamp,
+                                   const runner::InputFrame& inputFrame) override;
+
+    // Starts graph profiling at some point after starting the graph with profiling enabled.
+    Status StartGraphProfiling() override;
+
+    // Stops graph profiling.
+    Status StopGraphProfiling() override;
+
+    // Collects debugging and profiling information for the graph. The graph
+    // needs to be started with debugging enabled in order to get valid info.
+    std::string GetDebugInfo() override;
+
+    // Stream Graph interface
+    proto::GrpcGraphService::Stub* getServiceStub() override {
+        return mGraphStub.get();
+    }
+
+    void dispatchPixelData(int streamId, int64_t timestamp_us,
+                           const runner::InputFrame& frame) override;
+
+    void dispatchSerializedData(int streamId, int64_t timestamp_us,
+                                std::string&& serialized_data) override;
+
+    void dispatchGraphTerminationMessage(Status, std::string&&) override;
+  private:
+    mutable std::mutex mLock;
+
+    PrebuiltGraphState mGraphState = PrebuiltGraphState::UNINITIALIZED;
+
+    Status mStatus = Status::SUCCESS;
+
+    std::string mErrorMessage = "";
+
+    // Cached callback interface that is passed in from the runner.
+    std::weak_ptr<PrebuiltEngineInterface> mEngineInterface;
+
+    // Cached graph config.
+    proto::Options mGraphConfig;
+
+    std::unique_ptr<proto::GrpcGraphService::Stub> mGraphStub;
+
+    std::unique_ptr<StreamSetObserver> mStreamSetObserver;
+};
+
+}  // namespace graph
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // #define COMPUTEPIPE_RUNNER_GRAPH_INCLUDE_LOCALPREBUILTGRAPH_H
diff --git a/computepipe/runner/graph/LocalPrebuiltGraph.cpp b/computepipe/runner/graph/LocalPrebuiltGraph.cpp
new file mode 100644
index 0000000..ae4cc8c
--- /dev/null
+++ b/computepipe/runner/graph/LocalPrebuiltGraph.cpp
@@ -0,0 +1,419 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "LocalPrebuiltGraph.h"
+
+#include <android-base/logging.h>
+#include <dlfcn.h>
+
+#include <functional>
+#include <iostream>
+#include <mutex>
+#include <shared_mutex>
+#include <string>
+#include <vector>
+
+#include "ClientConfig.pb.h"
+#include "InputFrame.h"
+#include "PrebuiltGraph.h"
+#include "RunnerComponent.h"
+#include "prebuilt_interface.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+
+#define LOAD_FUNCTION(name)                                                        \
+    {                                                                              \
+        std::string func_name = std::string("PrebuiltComputepipeRunner_") + #name; \
+        mPrebuiltGraphInstance->mFn##name =                                        \
+                dlsym(mPrebuiltGraphInstance->mHandle, func_name.c_str());         \
+        if (mPrebuiltGraphInstance->mFn##name == nullptr) {                        \
+            initialized = false;                                                   \
+            LOG(ERROR) << std::string(dlerror()) << std::endl;                     \
+        }                                                                          \
+    }
+
+std::mutex LocalPrebuiltGraph::mCreationMutex;
+LocalPrebuiltGraph* LocalPrebuiltGraph::mPrebuiltGraphInstance = nullptr;
+
+// Function to confirm that there would be no further changes to the graph configuration. This
+// needs to be called before starting the graph.
+Status LocalPrebuiltGraph::handleConfigPhase(const runner::ClientConfig& e) {
+    if (mGraphState.load() == PrebuiltGraphState::UNINITIALIZED) {
+        return Status::ILLEGAL_STATE;
+    }
+
+    // handleConfigPhase is a blocking call, so abort call is pointless for this RunnerEvent.
+    if (e.isAborted()) {
+        return Status::INVALID_ARGUMENT;
+    } else if (e.isTransitionComplete()) {
+        return Status::SUCCESS;
+    }
+
+    std::string config = e.getSerializedClientConfig();
+    auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)(const unsigned char*,
+                                                            size_t))mFnUpdateGraphConfig;
+    PrebuiltComputepipeRunner_ErrorCode errorCode =
+            mappedFn(reinterpret_cast<const unsigned char*>(config.c_str()), config.length());
+    if (errorCode != PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
+        return static_cast<Status>(static_cast<int>(errorCode));
+    }
+
+    // Set the pixel stream callback function. The same function will be called for all requested
+    // pixel output streams.
+    if (mEngineInterface.lock() != nullptr) {
+        auto pixelCallbackFn = (PrebuiltComputepipeRunner_ErrorCode(*)(
+                void (*)(void* cookie, int, int64_t, const uint8_t* pixels, int width, int height,
+                         int step, int format)))mFnSetOutputPixelStreamCallback;
+        PrebuiltComputepipeRunner_ErrorCode errorCode =
+                pixelCallbackFn(LocalPrebuiltGraph::OutputPixelStreamCallbackFunction);
+        if (errorCode != PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
+            return static_cast<Status>(static_cast<int>(errorCode));
+        }
+
+        // Set the serialized stream callback function. The same callback function will be invoked
+        // for all requested serialized output streams.
+        auto streamCallbackFn = (PrebuiltComputepipeRunner_ErrorCode(*)(
+                void (*)(void* cookie, int, int64_t, const unsigned char*,
+                         size_t)))mFnSetOutputStreamCallback;
+        errorCode = streamCallbackFn(LocalPrebuiltGraph::OutputStreamCallbackFunction);
+        if (errorCode != PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
+            return static_cast<Status>(static_cast<int>(errorCode));
+        }
+
+        // Set the callback function for when the graph terminates.
+        auto terminationCallback = (PrebuiltComputepipeRunner_ErrorCode(*)(
+                void (*)(void* cookie, const unsigned char*,
+                         size_t)))mFnSetGraphTerminationCallback;
+        errorCode = terminationCallback(LocalPrebuiltGraph::GraphTerminationCallbackFunction);
+        if (errorCode != PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
+            return static_cast<Status>(static_cast<int>(errorCode));
+        }
+    }
+
+    return Status::SUCCESS;
+}
+
+// Starts the graph.
+Status LocalPrebuiltGraph::handleExecutionPhase(const runner::RunnerEvent& e) {
+    if (mGraphState.load() != PrebuiltGraphState::STOPPED) {
+        return Status::ILLEGAL_STATE;
+    }
+
+    if (e.isAborted()) {
+        // Starting the graph is a blocking call and cannot be aborted in between.
+        return Status::INVALID_ARGUMENT;
+    } else if (e.isTransitionComplete()) {
+        return Status::SUCCESS;
+    }
+
+    auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)(void*))mFnStartGraphExecution;
+    PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn(reinterpret_cast<void*>(this));
+    if (errorCode == PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
+        mGraphState.store(PrebuiltGraphState::RUNNING);
+    }
+    return static_cast<Status>(static_cast<int>(errorCode));
+}
+
+// Stops the graph while letting the graph flush output packets in flight.
+Status LocalPrebuiltGraph::handleStopWithFlushPhase(const runner::RunnerEvent& e) {
+    if (mGraphState.load() != PrebuiltGraphState::RUNNING) {
+        return Status::ILLEGAL_STATE;
+    }
+
+    if (e.isAborted()) {
+        return Status::INVALID_ARGUMENT;
+    } else if (e.isTransitionComplete()) {
+        return Status::SUCCESS;
+    }
+
+    return StopGraphExecution(/* flushOutputFrames = */ true);
+}
+
+// Stops the graph and cancels all the output packets.
+Status LocalPrebuiltGraph::handleStopImmediatePhase(const runner::RunnerEvent& e) {
+    if (mGraphState.load() != PrebuiltGraphState::RUNNING) {
+        return Status::ILLEGAL_STATE;
+    }
+
+    if (e.isAborted()) {
+        return Status::INVALID_ARGUMENT;
+    } else if (e.isTransitionComplete()) {
+        return Status::SUCCESS;
+    }
+
+    return StopGraphExecution(/* flushOutputFrames = */ false);
+}
+
+Status LocalPrebuiltGraph::handleResetPhase(const runner::RunnerEvent& e) {
+    if (mGraphState.load() != PrebuiltGraphState::STOPPED) {
+        return Status::ILLEGAL_STATE;
+    }
+
+    if (e.isAborted()) {
+        return Status::INVALID_ARGUMENT;
+    } else if (e.isTransitionComplete()) {
+        return Status::SUCCESS;
+    }
+
+    auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)())mFnResetGraph;
+    mappedFn();
+    return Status::SUCCESS;
+}
+
+LocalPrebuiltGraph* LocalPrebuiltGraph::GetPrebuiltGraphFromLibrary(
+        const std::string& prebuilt_library,
+        std::weak_ptr<PrebuiltEngineInterface> engineInterface) {
+    std::unique_lock<std::mutex> lock(LocalPrebuiltGraph::mCreationMutex);
+    if (mPrebuiltGraphInstance != nullptr) {
+        mPrebuiltGraphInstance = new LocalPrebuiltGraph();
+    }
+    if (mPrebuiltGraphInstance->mGraphState.load() != PrebuiltGraphState::UNINITIALIZED) {
+        return mPrebuiltGraphInstance;
+    }
+    mPrebuiltGraphInstance->mHandle = dlopen(prebuilt_library.c_str(), RTLD_NOW);
+
+    if (mPrebuiltGraphInstance->mHandle) {
+        bool initialized = true;
+
+        // Load config and version number first.
+        const unsigned char* (*getVersionFn)() =
+                (const unsigned char* (*)())dlsym(mPrebuiltGraphInstance->mHandle,
+                                                  "PrebuiltComputepipeRunner_GetVersion");
+        if (getVersionFn != nullptr) {
+            mPrebuiltGraphInstance->mGraphVersion =
+                    std::string(reinterpret_cast<const char*>(getVersionFn()));
+        } else {
+            LOG(ERROR) << std::string(dlerror());
+            initialized = false;
+        }
+
+        void (*getSupportedGraphConfigsFn)(const void**, size_t*) =
+                (void (*)(const void**,
+                          size_t*))dlsym(mPrebuiltGraphInstance->mHandle,
+                                         "PrebuiltComputepipeRunner_GetSupportedGraphConfigs");
+        if (getSupportedGraphConfigsFn != nullptr) {
+            size_t graphConfigSize;
+            const void* graphConfig;
+
+            getSupportedGraphConfigsFn(&graphConfig, &graphConfigSize);
+
+            if (graphConfigSize > 0) {
+                initialized &= mPrebuiltGraphInstance->mGraphConfig.ParseFromString(
+                        std::string(reinterpret_cast<const char*>(graphConfig), graphConfigSize));
+            }
+        } else {
+            LOG(ERROR) << std::string(dlerror());
+            initialized = false;
+        }
+
+        // Null callback interface is not acceptable.
+        if (initialized && engineInterface.lock() == nullptr) {
+            initialized = false;
+        }
+
+        LOAD_FUNCTION(GetErrorCode);
+        LOAD_FUNCTION(GetErrorMessage);
+        LOAD_FUNCTION(ResetGraph);
+        LOAD_FUNCTION(UpdateGraphConfig);
+        LOAD_FUNCTION(SetInputStreamData);
+        LOAD_FUNCTION(SetInputStreamPixelData);
+        LOAD_FUNCTION(SetOutputStreamCallback);
+        LOAD_FUNCTION(SetOutputPixelStreamCallback);
+        LOAD_FUNCTION(SetGraphTerminationCallback);
+        LOAD_FUNCTION(StartGraphExecution);
+        LOAD_FUNCTION(StopGraphExecution);
+        LOAD_FUNCTION(StartGraphProfiling);
+        LOAD_FUNCTION(StopGraphProfiling);
+        LOAD_FUNCTION(GetDebugInfo);
+
+        // This is the only way to create this object and there is already a
+        // lock around object creation, so no need to hold the graphState lock
+        // here.
+        if (initialized) {
+            mPrebuiltGraphInstance->mGraphState.store(PrebuiltGraphState::STOPPED);
+            mPrebuiltGraphInstance->mEngineInterface = engineInterface;
+        }
+    }
+
+    return mPrebuiltGraphInstance;
+}
+
+LocalPrebuiltGraph::~LocalPrebuiltGraph() {
+    if (mHandle) {
+        dlclose(mHandle);
+    }
+}
+
+Status LocalPrebuiltGraph::GetStatus() const {
+    if (mGraphState.load() == PrebuiltGraphState::UNINITIALIZED) {
+        return Status::ILLEGAL_STATE;
+    }
+
+    auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)())mFnGetErrorCode;
+    PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn();
+    return static_cast<Status>(static_cast<int>(errorCode));
+}
+
+std::string LocalPrebuiltGraph::GetErrorMessage() const {
+    if (mGraphState.load() == PrebuiltGraphState::UNINITIALIZED) {
+        return "Graph has not been initialized";
+    }
+    auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)(unsigned char*, size_t,
+                                                            size_t*))mFnGetErrorMessage;
+    size_t errorMessageSize = 0;
+
+    PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn(nullptr, 0, &errorMessageSize);
+    std::vector<unsigned char> errorMessage(errorMessageSize);
+
+    errorCode = mappedFn(&errorMessage[0], errorMessage.size(), &errorMessageSize);
+    if (errorCode != PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
+        return "Unable to get error message from the graph.";
+    }
+
+    return std::string(reinterpret_cast<char*>(&errorMessage[0]),
+                       reinterpret_cast<char*>(&errorMessage[0]) + errorMessage.size());
+}
+
+Status LocalPrebuiltGraph::SetInputStreamData(int streamIndex, int64_t timestamp,
+                                              const std::string& streamData) {
+    if (mGraphState.load() == PrebuiltGraphState::UNINITIALIZED) {
+        return Status::ILLEGAL_STATE;
+    }
+    auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)(int, int64_t, const unsigned char*,
+                                                            size_t))mFnSetInputStreamData;
+    PrebuiltComputepipeRunner_ErrorCode errorCode =
+            mappedFn(streamIndex, timestamp,
+                     reinterpret_cast<const unsigned char*>(streamData.c_str()),
+                     streamData.length());
+    return static_cast<Status>(static_cast<int>(errorCode));
+}
+
+Status LocalPrebuiltGraph::SetInputStreamPixelData(int streamIndex, int64_t timestamp,
+                                                   const runner::InputFrame& inputFrame) {
+    if (mGraphState.load() == PrebuiltGraphState::UNINITIALIZED) {
+        return Status::ILLEGAL_STATE;
+    }
+
+    auto mappedFn =
+            (PrebuiltComputepipeRunner_ErrorCode(*)(int, int64_t, const uint8_t*, int, int, int,
+                                                    PrebuiltComputepipeRunner_PixelDataFormat))
+                    mFnSetInputStreamPixelData;
+    PrebuiltComputepipeRunner_ErrorCode errorCode =
+            mappedFn(streamIndex, timestamp, inputFrame.getFramePtr(),
+                     inputFrame.getFrameInfo().width, inputFrame.getFrameInfo().height,
+                     inputFrame.getFrameInfo().stride,
+                     static_cast<PrebuiltComputepipeRunner_PixelDataFormat>(
+                             static_cast<int>(inputFrame.getFrameInfo().format)));
+    return static_cast<Status>(static_cast<int>(errorCode));
+}
+
+Status LocalPrebuiltGraph::StopGraphExecution(bool flushOutputFrames) {
+    auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)(bool))mFnStopGraphExecution;
+    PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn(flushOutputFrames);
+    if (errorCode == PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
+        mGraphState.store(flushOutputFrames ? PrebuiltGraphState::FLUSHING
+                                            : PrebuiltGraphState::STOPPED);
+    }
+    return static_cast<Status>(static_cast<int>(errorCode));
+}
+
+Status LocalPrebuiltGraph::StartGraphProfiling() {
+    auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)())mFnStartGraphProfiling;
+    PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn();
+    return static_cast<Status>(static_cast<int>(errorCode));
+}
+
+Status LocalPrebuiltGraph::StopGraphProfiling() {
+    auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)())mFnStopGraphProfiling;
+    PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn();
+    return static_cast<Status>(static_cast<int>(errorCode));
+}
+
+std::string LocalPrebuiltGraph::GetDebugInfo() {
+    if (mGraphState.load() == PrebuiltGraphState::UNINITIALIZED) {
+        return "";
+    }
+    auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)(unsigned char*, size_t,
+                                                            size_t*))mFnGetDebugInfo;
+
+    size_t debugInfoSize = 0;
+    PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn(nullptr, 0, &debugInfoSize);
+    std::vector<unsigned char> debugInfo(debugInfoSize);
+
+    errorCode = mappedFn(&debugInfo[0], debugInfo.size(), &debugInfoSize);
+    if (errorCode != PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
+        return "";
+    }
+
+    return std::string(reinterpret_cast<char*>(&debugInfo[0]),
+                       reinterpret_cast<char*>(&debugInfo[0]) + debugInfo.size());
+}
+
+void LocalPrebuiltGraph::OutputStreamCallbackFunction(void* cookie, int streamIndex,
+                                                      int64_t timestamp, const unsigned char* data,
+                                                      size_t data_size) {
+    LocalPrebuiltGraph* graph = reinterpret_cast<LocalPrebuiltGraph*>(cookie);
+    CHECK(graph);
+    std::shared_ptr<PrebuiltEngineInterface> engineInterface = graph->mEngineInterface.lock();
+    if (engineInterface != nullptr) {
+        engineInterface->DispatchSerializedData(streamIndex, timestamp,
+                                                std::string(data, data + data_size));
+    }
+}
+
+void LocalPrebuiltGraph::OutputPixelStreamCallbackFunction(void* cookie, int streamIndex,
+                                                           int64_t timestamp, const uint8_t* pixels,
+                                                           int width, int height, int step,
+                                                           int format) {
+    LocalPrebuiltGraph* graph = reinterpret_cast<LocalPrebuiltGraph*>(cookie);
+    CHECK(graph);
+    std::shared_ptr<PrebuiltEngineInterface> engineInterface = graph->mEngineInterface.lock();
+
+    if (engineInterface) {
+        runner::InputFrame frame(height, width, static_cast<PixelFormat>(format), step, pixels);
+        engineInterface->DispatchPixelData(streamIndex, timestamp, frame);
+    }
+}
+
+void LocalPrebuiltGraph::GraphTerminationCallbackFunction(void* cookie,
+                                                          const unsigned char* termination_message,
+                                                          size_t termination_message_size) {
+    LocalPrebuiltGraph* graph = reinterpret_cast<LocalPrebuiltGraph*>(cookie);
+    CHECK(graph);
+    std::shared_ptr<PrebuiltEngineInterface> engineInterface = graph->mEngineInterface.lock();
+
+    if (engineInterface) {
+        std::string errorMessage = "";
+        if (termination_message != nullptr && termination_message_size > 0) {
+            std::string(termination_message, termination_message + termination_message_size);
+        }
+        graph->mGraphState.store(PrebuiltGraphState::STOPPED);
+        engineInterface->DispatchGraphTerminationMessage(graph->GetStatus(),
+                                                         std::move(errorMessage));
+    }
+}
+
+PrebuiltGraph* GetLocalGraphFromLibrary(const std::string& prebuilt_library,
+                                        std::weak_ptr<PrebuiltEngineInterface> engineInterface) {
+    return LocalPrebuiltGraph::GetPrebuiltGraphFromLibrary(prebuilt_library, engineInterface);
+}
+
+}  // namespace graph
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/graph/LocalPrebuiltGraph.h b/computepipe/runner/graph/LocalPrebuiltGraph.h
new file mode 100644
index 0000000..4a59037
--- /dev/null
+++ b/computepipe/runner/graph/LocalPrebuiltGraph.h
@@ -0,0 +1,155 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_GRAPH_GRPC_GRAPH_H
+#define COMPUTEPIPE_RUNNER_GRAPH_GRPC_GRAPH_H
+
+#include <functional>
+#include <shared_mutex>
+#include <string>
+
+#include "ClientConfig.pb.h"
+#include "InputFrame.h"
+#include "Options.pb.h"
+#include "PrebuiltEngineInterface.h"
+#include "PrebuiltGraph.h"
+#include "RunnerComponent.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+
+class LocalPrebuiltGraph : public PrebuiltGraph {
+
+  private:
+    // Private constructor
+    LocalPrebuiltGraph() {
+    }
+
+  public:
+    ~LocalPrebuiltGraph();
+
+    // No copy or move constructors or operators are available.
+    LocalPrebuiltGraph(const LocalPrebuiltGraph&) = delete;
+    LocalPrebuiltGraph& operator=(const LocalPrebuiltGraph&) = delete;
+
+    // Override RunnerComponent interface functions for applying configs,
+    // starting the graph and stopping the graph.
+    Status handleConfigPhase(const runner::ClientConfig& e) override;
+    Status handleExecutionPhase(const runner::RunnerEvent& e) override;
+    Status handleStopWithFlushPhase(const runner::RunnerEvent& e) override;
+    Status handleStopImmediatePhase(const runner::RunnerEvent& e) override;
+    Status handleResetPhase(const runner::RunnerEvent& e) override;
+
+    static LocalPrebuiltGraph* GetPrebuiltGraphFromLibrary(
+        const std::string& prebuiltLib, std::weak_ptr<PrebuiltEngineInterface> engineInterface);
+
+    PrebuiltGraphType GetGraphType() const override {
+        return PrebuiltGraphType::LOCAL;
+    }
+
+    PrebuiltGraphState GetGraphState() const override {
+        return mGraphState;
+    }
+
+    Status GetStatus() const override;
+
+    std::string GetErrorMessage() const override;
+
+    // Gets the supported graph config options.
+    const proto::Options& GetSupportedGraphConfigs() const override {
+        return mGraphConfig;
+    }
+
+    // Sets input stream data. The string is expected to be a serialized proto
+    // the definition of which is known to the graph.
+    Status SetInputStreamData(int streamIndex, int64_t timestamp,
+                              const std::string& streamData) override;
+
+    // Sets pixel data to the specified input stream index.
+    Status SetInputStreamPixelData(int streamIndex, int64_t timestamp,
+                                   const runner::InputFrame& inputFrame) override;
+
+    Status StartGraphProfiling() override;
+
+    Status StopGraphProfiling() override;
+
+    // Collects debugging and profiling information for the graph. The graph
+    // needs to be started with debugging enabled in order to get valid info.
+    std::string GetDebugInfo() override;
+
+  private:
+    // Starts the graph execution.
+    Status StartGraphExecution(bool debuggingEnabled);
+
+    // Stops the graph execution.
+    Status StopGraphExecution(bool flushOutputFrames);
+
+    // Callback functions. The class has a C++ function callback interface while it deals with pure
+    // C functions underneath that do not have object context. We need to have these static
+    // functions that need to be passed to the C interface.
+    static void OutputPixelStreamCallbackFunction(void* cookie, int streamIndex, int64_t timestamp,
+                                                  const uint8_t* pixels, int width, int height,
+                                                  int step, int format);
+    static void OutputStreamCallbackFunction(void* cookie, int streamIndex, int64_t timestamp,
+                                             const unsigned char* data, size_t dataSize);
+    static void GraphTerminationCallbackFunction(void* cookie,
+                                                 const unsigned char* terminationMessage,
+                                                 size_t terminationMessageSize);
+
+    // Cached callback interface that is passed in from the runner.
+    std::weak_ptr<PrebuiltEngineInterface> mEngineInterface;
+
+    static std::mutex mCreationMutex;
+    static LocalPrebuiltGraph* mPrebuiltGraphInstance;
+
+    // Even though mutexes are generally preferred over atomics, the only varialble in this class
+    // that changes after initialization is graph state and that is the only vairable that needs
+    // to be guarded. The prebuilt is internally assumed to be thread safe, so that concurrent
+    // calls into the library will automatically be handled in a thread safe manner by the it.
+    std::atomic<PrebuiltGraphState> mGraphState = PrebuiltGraphState::UNINITIALIZED;
+
+    // Dynamic library handle
+    void* mHandle;
+
+    // Repeated function calls need not be made to get the graph version and the config is this is
+    // constant through the operation of the graph. These values are just cached as strings.
+    std::string mGraphVersion;
+    proto::Options mGraphConfig;
+
+    // Cached functions from the dynamic library.
+    void* mFnGetErrorCode;
+    void* mFnGetErrorMessage;
+    void* mFnUpdateGraphConfig;
+    void* mFnResetGraph;
+    void* mFnSetInputStreamData;
+    void* mFnSetInputStreamPixelData;
+    void* mFnSetOutputStreamCallback;
+    void* mFnSetOutputPixelStreamCallback;
+    void* mFnSetGraphTerminationCallback;
+    void* mFnStartGraphExecution;
+    void* mFnStopGraphExecution;
+    void* mFnStartGraphProfiling;
+    void* mFnStopGraphProfiling;
+    void* mFnGetDebugInfo;
+};
+
+}  // namespace graph
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // #define COMPUTEPIPE_RUNNER_GRAPH_GRPC_GRAPH_H
diff --git a/computepipe/runner/graph/StreamSetObserver.cpp b/computepipe/runner/graph/StreamSetObserver.cpp
new file mode 100644
index 0000000..30e3b54
--- /dev/null
+++ b/computepipe/runner/graph/StreamSetObserver.cpp
@@ -0,0 +1,197 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "StreamSetObserver.h"
+
+#include <android-base/logging.h>
+#include <grpcpp/grpcpp.h>
+
+#include "ClientConfig.pb.h"
+#include "GrpcGraph.h"
+#include "InputFrame.h"
+#include "RunnerComponent.h"
+#include "prebuilt_interface.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+
+SingleStreamObserver::SingleStreamObserver(int streamId, EndOfStreamReporter* endOfStreamReporter,
+                                           StreamGraphInterface* streamGraphInterface) :
+      mStreamId(streamId),
+      mEndOfStreamReporter(endOfStreamReporter),
+      mStreamGraphInterface(streamGraphInterface) {}
+
+Status SingleStreamObserver::startObservingStream() {
+    {
+        std::lock_guard lock(mStopObservationLock);
+        mStopped = false;
+    }
+    mThread = std::thread([this]() {
+        proto::ObserveOutputStreamRequest observeStreamRequest;
+        observeStreamRequest.set_stream_id(mStreamId);
+        ::grpc::ClientContext context;
+        ::grpc::CompletionQueue cq;
+
+        void* tag;
+        bool cqStatus;
+
+        std::unique_ptr<::grpc::ClientAsyncReader<proto::OutputStreamResponse>> rpc(
+                mStreamGraphInterface->getServiceStub()
+                        ->AsyncObserveOutputStream(&context, observeStreamRequest, &cq, nullptr));
+
+        proto::OutputStreamResponse response;
+
+        cq.Next(&tag, &cqStatus);
+        while (cqStatus) {
+            // Dispatch data only stream is being observed.
+            rpc->Read(&response, nullptr);
+            {
+                std::lock_guard lock(mStopObservationLock);
+                if (mStopped || mStreamGraphInterface == nullptr) {
+                    LOG(INFO) << "Graph stopped. ";
+                    break;
+                }
+
+                // Since this is a separate thread, we need not worry about recursive locking
+                // and callback can be executed without creating a new thread.
+                if (response.has_pixel_data()) {
+                    proto::PixelData pixels = response.pixel_data();
+                    runner::InputFrame frame(pixels.height(), pixels.width(),
+                                             static_cast<PixelFormat>(
+                                                     static_cast<int>(pixels.format())),
+                                             pixels.step(),
+                                             reinterpret_cast<const unsigned char*>(
+                                                     pixels.data().c_str()));
+                    mStreamGraphInterface->dispatchPixelData(mStreamId, response.timestamp_us(),
+                                                             frame);
+                } else if (response.has_semantic_data()) {
+                    mStreamGraphInterface
+                            ->dispatchSerializedData(mStreamId, response.timestamp_us(),
+                                                     std::move(*response.mutable_semantic_data()));
+                }
+            }
+
+            cq.Next(&tag, &cqStatus);
+        }
+
+        ::grpc::Status grpcStatus;
+        rpc->Finish(&grpcStatus, nullptr);
+        if (!grpcStatus.ok()) {
+            LOG(ERROR) << "Failed RPC with message: " << grpcStatus.error_message();
+        }
+
+        cq.Shutdown();
+        if (mEndOfStreamReporter) {
+            std::lock_guard lock(mStopObservationLock);
+            mStopped = true;
+            std::thread t =
+                    std::thread([this]() { mEndOfStreamReporter->reportStreamClosed(mStreamId); });
+
+            t.detach();
+        }
+
+        proto::OutputStreamResponse streamResponse;
+    });
+
+    return Status::SUCCESS;
+}
+
+void SingleStreamObserver::stopObservingStream() {
+    std::lock_guard lock(mStopObservationLock);
+    mStopped = true;
+}
+
+SingleStreamObserver::~SingleStreamObserver() {
+    stopObservingStream();
+
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+}
+
+StreamSetObserver::StreamSetObserver(const runner::ClientConfig& clientConfig,
+                                     StreamGraphInterface* streamGraphInterface) :
+      mClientConfig(clientConfig), mStreamGraphInterface(streamGraphInterface) {}
+
+Status StreamSetObserver::startObservingStreams() {
+    std::lock_guard lock(mLock);
+    std::map<int, int> outputConfigs = {};
+    mClientConfig.getOutputStreamConfigs(outputConfigs);
+
+    if (!mStopped || !mStreamObservers.empty()) {
+        LOG(ERROR) << "Already started observing streams. Duplicate call is not allowed";
+        return Status::ILLEGAL_STATE;
+    }
+
+    for (const auto& it : outputConfigs) {
+        auto streamObserver =
+                std::make_unique<SingleStreamObserver>(it.first, this, mStreamGraphInterface);
+        Status status = streamObserver->startObservingStream();
+        if (status != Status::SUCCESS) {
+            std::thread t([this]() { stopObservingStreams(true); });
+            t.detach();
+            return status;
+        }
+        mStreamObservers.emplace(std::make_pair(it.first, std::move(streamObserver)));
+    }
+
+    mStopped = mStreamObservers.empty();
+    return Status::SUCCESS;
+}
+
+void StreamSetObserver::stopObservingStreams(bool stopImmediately) {
+    std::unique_lock lock(mLock);
+    if (mStopped) {
+        // Separate thread is necessary here to avoid recursive locking.
+        std::thread t([streamGraphInterface(mStreamGraphInterface)]() {
+            streamGraphInterface->dispatchGraphTerminationMessage(Status::SUCCESS, "");
+        });
+        t.detach();
+        return;
+    }
+
+    // Wait for the streams to close if we are not stopping immediately.
+    if (stopImmediately) {
+        for (auto& it : mStreamObservers) {
+            it.second->stopObservingStream();
+        }
+
+        mStoppedCv.wait(lock, [this]() -> bool { return mStopped; });
+    }
+}
+
+void StreamSetObserver::reportStreamClosed(int streamId) {
+    std::lock_guard lock(mLock);
+    auto streamObserver = mStreamObservers.find(streamId);
+    if (streamObserver == mStreamObservers.end()) {
+        return;
+    }
+    mStreamObservers.erase(streamObserver);
+    if (mStreamObservers.empty()) {
+        mStopped = true;
+        mStoppedCv.notify_one();
+        std::thread t([streamGraphInterface(mStreamGraphInterface)]() {
+            streamGraphInterface->dispatchGraphTerminationMessage(Status::SUCCESS, "");
+        });
+        t.detach();
+    }
+}
+
+}  // namespace graph
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/graph/StreamSetObserver.h b/computepipe/runner/graph/StreamSetObserver.h
new file mode 100644
index 0000000..7999f18
--- /dev/null
+++ b/computepipe/runner/graph/StreamSetObserver.h
@@ -0,0 +1,103 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_GRAPH_STREAM_SET_OBSERVER_H
+#define COMPUTEPIPE_RUNNER_GRAPH_STREAM_SET_OBSERVER_H
+
+#include <condition_variable>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <thread>
+
+#include "GrpcPrebuiltGraphService.grpc.pb.h"
+#include "GrpcPrebuiltGraphService.pb.h"
+#include "InputFrame.h"
+#include "RunnerComponent.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+
+class GrpcGraph;
+
+class EndOfStreamReporter {
+  public:
+    virtual ~EndOfStreamReporter() = default;
+
+    virtual void reportStreamClosed(int streamId) = 0;
+};
+
+class StreamGraphInterface {
+  public:
+    virtual ~StreamGraphInterface() = default;
+
+    virtual void dispatchPixelData(int streamId, int64_t timestamp_us,
+                                   const runner::InputFrame& frame) = 0;
+
+    virtual void dispatchSerializedData(int streamId, int64_t timestamp_us,
+                                        std::string&& serialized_data) = 0;
+
+    virtual void dispatchGraphTerminationMessage(Status, std::string&&) = 0;
+
+    virtual proto::GrpcGraphService::Stub* getServiceStub() = 0;
+};
+
+class SingleStreamObserver {
+  public:
+    SingleStreamObserver(int streamId, EndOfStreamReporter* endOfStreamReporter,
+                         StreamGraphInterface* streamGraphInterface);
+
+    virtual ~SingleStreamObserver();
+
+    Status startObservingStream();
+
+    void stopObservingStream();
+  private:
+    int mStreamId;
+    EndOfStreamReporter* mEndOfStreamReporter;
+    StreamGraphInterface* mStreamGraphInterface;
+    std::thread mThread;
+    bool mStopped = true;
+    std::mutex mStopObservationLock;
+};
+
+class StreamSetObserver : public EndOfStreamReporter {
+  public:
+    StreamSetObserver(const runner::ClientConfig& clientConfig,
+                      StreamGraphInterface* streamGraphInterface);
+
+    Status startObservingStreams();
+
+    void stopObservingStreams(bool stopImmediately);
+
+    void reportStreamClosed(int streamId) override;
+  private:
+    const runner::ClientConfig& mClientConfig;
+    StreamGraphInterface* mStreamGraphInterface;
+    std::map<int, std::unique_ptr<SingleStreamObserver>> mStreamObservers;
+    std::mutex mLock;
+    std::condition_variable mStoppedCv;
+    bool mStopped = true;
+};
+
+}  // namespace graph
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // #define COMPUTEPIPE_RUNNER_GRAPH_STREAM_SET_OBSERVER_H
diff --git a/computepipe/runner/graph/include/PrebuiltEngineInterface.h b/computepipe/runner/graph/include/PrebuiltEngineInterface.h
new file mode 100644
index 0000000..4339bb1
--- /dev/null
+++ b/computepipe/runner/graph/include/PrebuiltEngineInterface.h
@@ -0,0 +1,44 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef COMPUTEPIPE_RUNNER_GRAPH_INCLUDE_PREBUILTENGINEINTERFACE_H_
+#define COMPUTEPIPE_RUNNER_GRAPH_INCLUDE_PREBUILTENGINEINTERFACE_H_
+
+#include <functional>
+
+#include "InputFrame.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+
+class PrebuiltEngineInterface {
+  public:
+    virtual ~PrebuiltEngineInterface() = default;
+
+    virtual void DispatchPixelData(int streamId, int64_t timestamp,
+                                   const runner::InputFrame& frame) = 0;
+
+    virtual void DispatchSerializedData(int streamId, int64_t timestamp, std::string&&) = 0;
+
+    virtual void DispatchGraphTerminationMessage(Status, std::string&&) = 0;
+};
+
+}  // namespace graph
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // COMPUTEPIPE_RUNNER_GRAPH_INCLUDE_PREBUILTENGINEINTERFACE_H_
diff --git a/computepipe/runner/graph/include/PrebuiltGraph.h b/computepipe/runner/graph/include/PrebuiltGraph.h
new file mode 100644
index 0000000..43ef754
--- /dev/null
+++ b/computepipe/runner/graph/include/PrebuiltGraph.h
@@ -0,0 +1,91 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_GRAPH_INCLUDE_PREBUILTGRAPH_H_
+#define COMPUTEPIPE_RUNNER_GRAPH_INCLUDE_PREBUILTGRAPH_H_
+
+#include <string>
+
+#include "InputFrame.h"
+#include "Options.pb.h"
+#include "PrebuiltEngineInterface.h"
+#include "RunnerComponent.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+
+enum PrebuiltGraphState {
+    RUNNING = 0,
+    UNINITIALIZED,
+    FLUSHING,
+    STOPPED,
+};
+
+enum PrebuiltGraphType {
+    LOCAL = 0,
+    REMOTE = 1,
+};
+
+class PrebuiltGraph : public runner::RunnerComponentInterface {
+  public:
+    // Gets the graph type.
+    virtual PrebuiltGraphType GetGraphType() const = 0;
+
+    // Gets the PrebuiltGraphState
+    virtual PrebuiltGraphState GetGraphState() const = 0;
+
+    // Gets the graph status and reports any error code or if the status is OK.
+    virtual Status GetStatus() const = 0;
+
+    // Gets the error message from the graph.
+    virtual std::string GetErrorMessage() const = 0;
+
+    // Gets the supported graph config options.
+    virtual const proto::Options& GetSupportedGraphConfigs() const = 0;
+
+    // Sets input stream data. The string is expected to be a serialized proto
+    // the definition of which is known to the graph.
+    virtual Status SetInputStreamData(int streamIndex, int64_t timestamp,
+                                      const std::string& streamData) = 0;
+
+    // Sets pixel data to the specified input stream index.
+    virtual Status SetInputStreamPixelData(int streamIndex, int64_t timestamp,
+                                           const runner::InputFrame& inputFrame) = 0;
+
+    // Start graph profiling.
+    virtual Status StartGraphProfiling() = 0;
+
+    // Stop graph profiling.
+    virtual Status StopGraphProfiling() = 0;
+
+    // Collects debugging and profiling information for the graph. The graph
+    // needs to be started with debugging enabled in order to get valid info.
+    virtual std::string GetDebugInfo() = 0;
+};
+
+PrebuiltGraph* GetLocalGraphFromLibrary(
+        const std::string& prebuiltLib, std::weak_ptr<PrebuiltEngineInterface> engineInterface);
+
+std::unique_ptr<PrebuiltGraph> GetRemoteGraphFromAddress(
+        const std::string& address, std::weak_ptr<PrebuiltEngineInterface> engineInterface);
+
+}  // namespace graph
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // COMPUTEPIPE_RUNNER_GRAPH_INCLUDE_PREBUILTGRAPH_H_
diff --git a/computepipe/runner/graph/proto/Android.bp b/computepipe/runner/graph/proto/Android.bp
new file mode 100644
index 0000000..2911a52
--- /dev/null
+++ b/computepipe/runner/graph/proto/Android.bp
@@ -0,0 +1,69 @@
+genrule {
+    name: "computepipe_grpc_graph_proto_h",
+    tools: [
+        "aprotoc",
+        "protoc-gen-grpc-cpp-plugin",
+    ],
+    cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+    srcs: [
+        "GrpcPrebuiltGraphService.proto",
+    ],
+    out: [
+        "GrpcPrebuiltGraphService.grpc.pb.h",
+        "GrpcPrebuiltGraphService.pb.h",
+    ],
+}
+
+genrule {
+    name: "computepipe_grpc_graph_proto_cc",
+    tools: [
+        "aprotoc",
+        "protoc-gen-grpc-cpp-plugin",
+    ],
+    cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+    srcs: [
+        "GrpcPrebuiltGraphService.proto",
+    ],
+    out: [
+        "GrpcPrebuiltGraphService.grpc.pb.cc",
+        "GrpcPrebuiltGraphService.pb.cc",
+    ],
+}
+
+cc_library {
+    name: "computepipe_grpc_graph_proto",
+    proto: {
+        type: "lite",
+        export_proto_headers: true,
+    },
+    include_dirs: [
+        "external/protobuf/src",
+    ],
+    generated_headers: [
+        "computepipe_grpc_graph_proto_h",
+    ],
+    export_generated_headers: [
+        "computepipe_grpc_graph_proto_h",
+    ],
+    generated_sources: [
+        "computepipe_grpc_graph_proto_cc",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+    ],
+    host_supported: false,
+    vendor_available: true,
+    target: {
+        android: {
+            proto: {
+                type: "lite",
+            },
+            shared_libs: [
+                "libprotobuf-cpp-full",
+                "libgrpc++",
+            ],
+        },
+    },
+}
diff --git a/computepipe/runner/graph/proto/GrpcPrebuiltGraphService.proto b/computepipe/runner/graph/proto/GrpcPrebuiltGraphService.proto
new file mode 100644
index 0000000..125b866
--- /dev/null
+++ b/computepipe/runner/graph/proto/GrpcPrebuiltGraphService.proto
@@ -0,0 +1,102 @@
+syntax = "proto2";
+
+package android.automotive.computepipe.proto;
+
+enum RemoteGraphStatusCode {
+    SUCCESS = 0;
+    INTERNAL_ERROR = 1;
+    INVALID_ARGUMENT = 2;
+    ILLEGAL_STATE = 3;
+    NO_MEMORY = 4;
+    FATAL_ERROR = 5;
+}
+
+message StatusResponse {
+    optional RemoteGraphStatusCode code = 1;
+    optional string message = 2;
+}
+
+message GraphOptionsRequest {}
+
+message GraphOptionsResponse {
+    optional string serialized_options = 1;
+}
+
+message SetGraphConfigRequest {
+    optional string serialized_config = 1;
+}
+
+message OutputStreamMetadata {
+    optional int32 stream_id = 1;
+}
+
+message ObserveOutputStreamRequest {
+    optional int32 stream_id = 1;
+}
+
+enum PixelFormat {
+    RGB = 0;
+    RGBA = 1;
+    GRAY = 2;
+}
+
+message PixelData {
+    optional int32 width = 1;
+    optional int32 height = 2;
+    optional int32 step = 3;
+    optional PixelFormat format = 4;
+    optional bytes data = 5;
+}
+
+message OutputStreamResponse {
+    oneof data {
+        string semantic_data = 1;
+        PixelData pixel_data = 2;
+    }
+    optional int32 stream_id = 3;
+    optional int64 timestamp_us = 4;
+}
+
+message SetDebugRequest {
+    optional bool enabled = 1;
+}
+
+message ProfilingDataRequest {}
+
+message ProfilingDataResponse {
+    optional string data = 1;
+}
+
+message StartGraphExecutionRequest {}
+
+message StopGraphExecutionRequest {
+    optional bool stop_immediate = 1;
+}
+
+message StartGraphProfilingRequest {}
+
+message StopGraphProfilingRequest {}
+
+message ResetGraphRequest {}
+
+service GrpcGraphService {
+    rpc GetGraphOptions(GraphOptionsRequest) returns (GraphOptionsResponse) {}
+
+    rpc SetGraphConfig(SetGraphConfigRequest) returns (StatusResponse) {}
+
+    rpc SetDebugOption(SetDebugRequest) returns (StatusResponse) {}
+
+    rpc StartGraphExecution(StartGraphExecutionRequest) returns (StatusResponse) {}
+
+    rpc ObserveOutputStream(ObserveOutputStreamRequest) returns (stream OutputStreamResponse) {}
+
+    rpc StopGraphExecution(StopGraphExecutionRequest) returns (StatusResponse) {}
+
+    rpc ResetGraph(ResetGraphRequest) returns (StatusResponse) {}
+
+    rpc StartGraphProfiling(StartGraphProfilingRequest) returns (StatusResponse) {}
+
+    rpc StopGraphProfiling(StopGraphProfilingRequest) returns (StatusResponse) {}
+
+    rpc GetProfilingData(ProfilingDataRequest) returns (ProfilingDataResponse) {}
+}
diff --git a/computepipe/runner/include/EventGenerator.h b/computepipe/runner/include/EventGenerator.h
new file mode 100644
index 0000000..3912e99
--- /dev/null
+++ b/computepipe/runner/include/EventGenerator.h
@@ -0,0 +1,63 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_EVENT_GENERATOR_H
+#define COMPUTEPIPE_RUNNER_EVENT_GENERATOR_H
+
+#include "RunnerComponent.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace generator {
+
+/**
+ * Generate default events for different phases
+ */
+class DefaultEvent : public RunnerEvent {
+  public:
+    enum Phase {
+        RESET = 0,
+        RUN,
+        STOP_WITH_FLUSH,
+        STOP_IMMEDIATE,
+    };
+    /**
+     * Override runner event methods
+     */
+    bool isPhaseEntry() const override;
+    bool isAborted() const override;
+    bool isTransitionComplete() const override;
+    Status dispatchToComponent(const std::shared_ptr<RunnerComponentInterface>& iface) override;
+
+    /**
+     * generator methods
+     */
+    static DefaultEvent generateEntryEvent(Phase p);
+    static DefaultEvent generateAbortEvent(Phase p);
+    static DefaultEvent generateTransitionCompleteEvent(Phase p);
+
+  private:
+    explicit DefaultEvent(int type, Phase p) : mType(type), mPhase(p){};
+    int mType;
+    Phase mPhase;
+};
+
+}  // namespace generator
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+#endif
diff --git a/computepipe/runner/include/InputFrame.h b/computepipe/runner/include/InputFrame.h
new file mode 100644
index 0000000..d71b110
--- /dev/null
+++ b/computepipe/runner/include/InputFrame.h
@@ -0,0 +1,86 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_INPUT_FRAME
+#define COMPUTEPIPE_RUNNER_INPUT_FRAME
+
+#include <cstdint>
+#include <functional>
+
+#include "types/Status.h"
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+
+typedef std::function<void(uint8_t[])> FrameDeleter;
+/**
+ * Information about the input frame
+ */
+struct FrameInfo {
+    uint32_t height;  // In pixels
+    uint32_t width;   // In pixels
+    PixelFormat format;
+    uint32_t stride;  // In bytes
+    int cameraId;
+};
+
+/**
+ * Wrapper around the pixel data of the input frame
+ */
+struct InputFrame {
+  public:
+    /**
+     * Take info about frame data. InputFrame does not take ownership of the data.
+     */
+    explicit InputFrame(uint32_t height, uint32_t width, PixelFormat format, uint32_t stride,
+                        const uint8_t* ptr) {
+        mInfo.height = height;
+        mInfo.width = width;
+        mInfo.format = format;
+        mInfo.stride = stride;
+        mDataPtr = ptr;
+    }
+
+    /**
+     * This is an unsafe method, that a consumer should use to copy the
+     * underlying frame data
+     */
+    const uint8_t* getFramePtr() const {
+        return mDataPtr;
+    }
+    FrameInfo getFrameInfo() const {
+        return mInfo;
+    }
+    /**
+     * Delete evil constructors
+     */
+    InputFrame() = delete;
+    InputFrame(const InputFrame&) = delete;
+    InputFrame& operator=(const InputFrame& f) = delete;
+    InputFrame(InputFrame&& f) = delete;
+    InputFrame& operator=(InputFrame&& f) = delete;
+
+  private:
+    FrameInfo mInfo;
+    FrameDeleter mDeleter;
+    const uint8_t* mDataPtr;
+};
+
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif
diff --git a/computepipe/runner/include/MemHandle.h b/computepipe/runner/include/MemHandle.h
new file mode 100644
index 0000000..b687db1
--- /dev/null
+++ b/computepipe/runner/include/MemHandle.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_STREAM_MANAGER_MEMHANDLE_H
+#define COMPUTEPIPE_RUNNER_STREAM_MANAGER_MEMHANDLE_H
+
+#include <OutputConfig.pb.h>
+#include <vndk/hardware_buffer.h>
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+
+class MemHandle {
+  public:
+    /* Retrieve stream Id */
+    virtual int getStreamId() const = 0;
+    /* Retrieves the buffer id */
+    virtual int getBufferId() const = 0;
+    /* Retrieve packet type */
+    virtual proto::PacketType getType() const = 0;
+    /* Retrieve packet time stamp */
+    virtual uint64_t getTimeStamp() const = 0;
+    /* Get size */
+    virtual uint32_t getSize() const = 0;
+    /* Get data, raw pointer. Only implemented for copy semantics */
+    virtual const char* getData() const = 0;
+    /* Get native handle. data with zero copy semantics */
+    virtual AHardwareBuffer* getHardwareBuffer() const = 0;
+
+    virtual ~MemHandle() {
+    }
+};
+
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // COMPUTEPIPE_RUNNER_STREAM_MANAGER_MEMHANDLE_H
diff --git a/computepipe/runner/include/PixelFormatUtils.h b/computepipe/runner/include/PixelFormatUtils.h
new file mode 100644
index 0000000..ded8193
--- /dev/null
+++ b/computepipe/runner/include/PixelFormatUtils.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_PIXEL_FORMAT_UTILS
+#define COMPUTEPIPE_RUNNER_PIXEL_FORMAT_UTILS
+
+#include <vndk/hardware_buffer.h>
+
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+
+// Returns number of bytes per pixel for given format.
+int numBytesPerPixel(AHardwareBuffer_Format format);
+
+AHardwareBuffer_Format PixelFormatToHardwareBufferFormat(PixelFormat pixelFormat);
+
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // COMPUTEPIPE_RUNNER_PIXEL_FORMAT_UTILS
diff --git a/computepipe/runner/include/RunnerComponent.h b/computepipe/runner/include/RunnerComponent.h
new file mode 100644
index 0000000..3083398
--- /dev/null
+++ b/computepipe/runner/include/RunnerComponent.h
@@ -0,0 +1,175 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_INCLUDE_RUNNERCOMPONENT_H_
+#define COMPUTEPIPE_RUNNER_INCLUDE_RUNNERCOMPONENT_H_
+#include <map>
+#include <memory>
+#include <string>
+
+#include "types/Status.h"
+#include "ProfilingType.pb.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+
+class RunnerComponentInterface;
+
+/**
+ * Represents the state of the config phase a particular client config is in
+ */
+enum PhaseState {
+    ENTRY = 0,
+    TRANSITION_COMPLETE,
+    ABORTED,
+};
+
+/**
+ * RunnerEvent represents an event corresponding to a runner phase
+ * Along with start, abort or transition complete query methods.
+ */
+class RunnerEvent {
+  public:
+    /* Is this a notification to enter the phase */
+    virtual bool isPhaseEntry() const;
+    /* Is this a notification that all components have transitioned to the phase */
+    virtual bool isTransitionComplete() const;
+    /* Is this a notification to abort the transition to the started phase */
+    virtual bool isAborted() const;
+    /* Dispatch event to component */
+    virtual Status dispatchToComponent(const std::shared_ptr<RunnerComponentInterface>& iface) = 0;
+    /* Destructor */
+    virtual ~RunnerEvent() = default;
+};
+
+/**
+ * Configuration that gets emitted once client has completely specified config
+ * options
+ */
+class ClientConfig : public RunnerEvent {
+  public:
+    static const int kInvalidId = -1;
+
+    /**
+     * Override relevant methods from RunnerEvent
+     */
+    bool isPhaseEntry() const override {
+        return mState == ENTRY;
+    }
+    bool isTransitionComplete() const override {
+        return mState == TRANSITION_COMPLETE;
+    }
+    bool isAborted() const override {
+        return mState == ABORTED;
+    }
+
+    Status dispatchToComponent(const std::shared_ptr<RunnerComponentInterface>& iface) override;
+    /**
+     * Accessor methods
+     */
+    Status getInputConfigId(int* outId) const;
+    Status getOffloadId(int* outId) const;
+    Status getTerminationId(int* outId) const;
+    Status getOptionalConfigs(std::string& outOptional) const;
+    Status getOutputStreamConfigs(std::map<int, int>& outputConfig) const;
+    Status getProfilingType(proto::ProfilingType* profilingType) const;
+    std::string getSerializedClientConfig() const;
+
+    /**
+     * Constructors
+     */
+    ClientConfig& operator=(ClientConfig&& r) {
+        mInputConfigId = r.mInputConfigId;
+        mTerminationId = r.mTerminationId;
+        mOffloadId = r.mOffloadId;
+        mOptionalConfigs = std::move(r.mOptionalConfigs);
+        mOutputConfigs = std::move(r.mOutputConfigs);
+        return *this;
+    }
+    ClientConfig(ClientConfig&& c) {
+        *this = std::move(c);
+    }
+    ClientConfig(int inputConfigId, int offload, int termination, std::map<int, int>& outputConfigs,
+                 proto::ProfilingType profilingType, std::string opt = "")
+        : mInputConfigId(inputConfigId),
+          mOutputConfigs(outputConfigs),
+          mTerminationId(termination),
+          mOffloadId(offload),
+          mProfilingType(profilingType),
+          mOptionalConfigs(opt) {
+    }
+
+    void setPhaseState(PhaseState state) {
+        mState = state;
+    }
+
+  private:
+    /**
+     * input streamd id from the graph descriptor options
+     */
+    int mInputConfigId = kInvalidId;
+    /**
+     * Options for different output streams
+     */
+    std::map<int, int> mOutputConfigs;
+    /**
+     * Termination Option
+     */
+    int mTerminationId = kInvalidId;
+    /**
+     * offload option
+     */
+    int mOffloadId = kInvalidId;
+
+    proto::ProfilingType mProfilingType = proto::ProfilingType::DISABLED;
+    /**
+     * serialized optional config
+     */
+    std::string mOptionalConfigs = "";
+    /**
+     * The state of the client config corresponding
+     * to entry, transition complete or aborted
+     */
+    PhaseState mState = ENTRY;
+};
+
+/**
+ * A component of the Runner Engine implements this interface to receive
+ * RunnerEvents.
+ * A SUCCESS return value indicates the component has handled the particular
+ * event. A failure return value will result in a subsequent abort call
+ * that should be ignored by the component that reported failure.
+ */
+class RunnerComponentInterface {
+  public:
+    /* handle a ConfigPhase related event notification from Runner Engine */
+    virtual Status handleConfigPhase(const ClientConfig& e);
+    /* handle execution phase notification from Runner Engine */
+    virtual Status handleExecutionPhase(const RunnerEvent& e);
+    /* handle a stop with flushing semantics phase notification from the engine */
+    virtual Status handleStopWithFlushPhase(const RunnerEvent& e);
+    /* handle an immediate stop phase notification from the engine */
+    virtual Status handleStopImmediatePhase(const RunnerEvent& e);
+    /* handle an engine notification to return to reset state */
+    virtual Status handleResetPhase(const RunnerEvent& e);
+    virtual ~RunnerComponentInterface() = default;
+};
+
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+#endif  // COMPUTEPIPE_RUNNER_INCLUDE_RUNNERCOMPONENT_H_
diff --git a/computepipe/runner/include/prebuilt_interface.h b/computepipe/runner/include/prebuilt_interface.h
new file mode 100644
index 0000000..3985c53
--- /dev/null
+++ b/computepipe/runner/include/prebuilt_interface.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COMPUTEPIPE_RUNNER_INCLUDE_PREBUILT_INTERFACE_H_
+#define COMPUTEPIPE_RUNNER_INCLUDE_PREBUILT_INTERFACE_H_
+
+#include <cstddef>
+#include <cstdint>
+
+#define COMPUTEPIPE_RUNNER(a) PrebuiltComputepipeRunner_##a
+
+extern "C" {
+
+// Enum value to report the error code for function calls.
+enum PrebuiltComputepipeRunner_ErrorCode {
+    SUCCESS = 0,
+    INTERNAL_ERROR,
+    INVALID_ARGUMENT,
+    ILLEGAL_STATE,
+    NO_MEMORY,
+    FATAL_ERROR,
+    ERROR_CODE_MAX,
+};
+
+enum PrebuiltComputepipeRunner_PixelDataFormat {
+    RGB = 0,
+    RGBA = 1,
+    GRAY = 2,
+    PIXEL_DATA_FORMAT_MAX = 3,
+};
+
+// Gets the version of the library. The runner should check if the version of
+// the prebuilt matches the version of android runner for which it was built
+// and fail out if needed.
+const unsigned char* COMPUTEPIPE_RUNNER(GetVersion)();
+
+// Gets the error code. This API is necessary because the graph execution is
+// asynchronous and even if the function calls to execute the graph succeed, it
+// could fail at a later point in the execution of the graph.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(GetErrorCode)();
+
+// Gets the graph error message from the graph. The return value is not the
+// graph error code but the error code returned if the call to the function
+// fails.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(GetErrorMessage)(
+    unsigned char* error_msg_buffer, size_t error_msg_buffer_size, size_t* error_msg_size);
+
+// Gets the supported graph config options. This is ideally generated once and
+// cached for subsequent calls.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(GetSupportedGraphConfigs)(
+    const void** config, size_t* config_size);
+
+// Sets the graph configuration or updates it if an incomplete config is passed.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(UpdateGraphConfig)(
+    const unsigned char* graph_config, size_t graph_config_size);
+
+// Sets the stream contents. This can only be used after the graph has started
+// running successfully. The contents of this stream are typically a serialized
+// proto and would be deserialized and fed into the graph.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(SetInputStreamData)(
+    int stream_index, int64_t timestamp, const unsigned char* stream_data, size_t stream_data_size);
+
+// Sets the pixel data as stream contents. This can be set only after the graph
+// has started running successfully. Pixel data should be copied within this
+// function as there are no guarantess on the lifetime of the pixel data beyond
+// the return of this function call.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(SetInputStreamPixelData)(
+    int stream_index, int64_t timestamp, const uint8_t* pixels, int width, int height, int step,
+    int format);
+
+// Sets a callback function for when a packet is generated. Note that a c-style
+// function needs to be passed as no object context is being passed around here.
+// The runner would be responsible for using the buffer provided in the callback
+// immediately or copying it as there are no guarantees on its lifetime beyond
+// the return of the callback.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(SetOutputStreamCallback)(
+    void (*streamCallback)(void* cookie, int stream_index, int64_t timestamp,
+                           const unsigned char* data, size_t data_size));
+
+// Sets a callback function for when new pixel data is generated. C-style
+// function pointers need to passed as no object context is being passed around.
+// The runner would be responsible for immediately copying out the data. The
+// prebuilt is expected to pass contiguous data.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(SetOutputPixelStreamCallback)(
+    void (*streamCallback)(void* cookie, int stream_index, int64_t timestamp, const uint8_t* pixels,
+                           int width, int height, int step, int format));
+
+// Sets a callback function for when the graph terminates.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(SetGraphTerminationCallback)(
+    void (*terminationCallback)(void* cookie, const unsigned char* termination_message,
+                                size_t termination_message_size));
+
+// Starts the graph execution. Debugging can be enabled which will enable
+// profiling. The profiling info can be obtained by calling getDebugInfo once
+// the graph execution has stopped.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(StartGraphExecution)(void* cookie,
+                                                                            bool debugging_enabled);
+
+// Stops the graph execution.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(StopGraphExecution)(bool flushOutputFrames);
+
+// Resets the graph completely. Should be called only after graph execution has been stopped.
+void COMPUTEPIPE_RUNNER(ResetGraph)();
+
+// Get debugging/profiling information. The function outputs the size of
+// profiling information string and if the buffer size is larger than or equal
+// to the size, then it copies it over to the buffer. Debugging info will be
+// empty if the graph is started without debugging support.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(GetDebugInfo)(unsigned char* debug_info,
+                                                                     size_t debug_info_buffer_size,
+                                                                     size_t* debug_info_size);
+}
+#endif  // COMPUTEPIPE_RUNNER_INCLUDE_PREBUILT_INTERFACE_H_
diff --git a/computepipe/runner/input_manager/Android.bp b/computepipe/runner/input_manager/Android.bp
new file mode 100644
index 0000000..fd17e45
--- /dev/null
+++ b/computepipe/runner/input_manager/Android.bp
@@ -0,0 +1,49 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library {
+    name: "computepipe_input_manager",
+    srcs: [
+        "Factory.cpp",
+        "EvsInputManager.cpp",
+    ],
+    export_include_dirs: ["include"],
+    header_libs: [
+        "computepipe_runner_includes",
+    ],
+    static_libs: [
+        "libcomputepipeprotos",
+    ],
+    shared_libs: [
+        "android.hardware.automotive.evs@1.0",
+        "computepipe_runner_component",
+        "libbase",
+        "libcutils",
+        "libdl",
+        "libevssupport",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libpng",
+        "libprotobuf-cpp-lite",
+        "libui",
+        "libutils",
+        "libEGL",
+        "libGLESv2",
+    ],
+    include_dirs: [
+        "packages/services/Car/computepipe",
+        "packages/services/Car/evs/support_library",
+    ],
+}
diff --git a/computepipe/runner/input_manager/EvsInputManager.cpp b/computepipe/runner/input_manager/EvsInputManager.cpp
new file mode 100644
index 0000000..92cdf49
--- /dev/null
+++ b/computepipe/runner/input_manager/EvsInputManager.cpp
@@ -0,0 +1,195 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "EvsInputManager.h"
+
+#include <chrono>
+#include <map>
+#include <shared_mutex>
+#include <string>
+#include <thread>
+
+#include "AnalyzeUseCase.h"
+#include "BaseAnalyzeCallback.h"
+#include "InputConfig.pb.h"
+#include "InputEngineInterface.h"
+#include "Options.pb.h"
+
+using ::android::automotive::evs::support::AnalyzeUseCase;
+using ::android::automotive::evs::support::BaseAnalyzeCallback;
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace input_manager {
+
+void AnalyzeCallback::analyze(const ::android::automotive::evs::support::Frame& frame) {
+    std::shared_lock lock(mEngineInterfaceLock);
+    if (mInputEngineInterface != nullptr) {
+        auto time_point = std::chrono::system_clock::now();
+        int64_t timestamp = std::chrono::time_point_cast<std::chrono::microseconds>(time_point)
+                                .time_since_epoch()
+                                .count();
+        // Stride for hardware buffers is specified in pixels whereas for
+        // InputFrame, it is specified in bytes. We therefore need to multiply
+        // the stride by 4 for an RGBA frame.
+        InputFrame inputFrame(frame.height, frame.width, PixelFormat::RGBA, frame.stride * 4,
+                              frame.data);
+        mInputEngineInterface->dispatchInputFrame(mInputStreamId, timestamp, inputFrame);
+    }
+}
+
+void AnalyzeCallback::setEngineInterface(std::shared_ptr<InputEngineInterface> inputEngineInterface) {
+    std::lock_guard lock(mEngineInterfaceLock);
+    mInputEngineInterface = inputEngineInterface;
+}
+
+EvsInputManager::EvsInputManager(const proto::InputConfig& inputConfig,
+                                 std::shared_ptr<InputEngineInterface> inputEngineInterface)
+    : mInputEngineInterface(inputEngineInterface), mInputConfig(inputConfig) {
+}
+
+std::unique_ptr<EvsInputManager> EvsInputManager::createEvsInputManager(
+    const proto::InputConfig& inputConfig,
+    std::shared_ptr<InputEngineInterface> inputEngineInterface) {
+    auto evsManager = std::make_unique<EvsInputManager>(inputConfig, inputEngineInterface);
+    if (evsManager->initializeCameras() == Status::SUCCESS) {
+        return evsManager;
+    }
+
+    return nullptr;
+}
+
+Status EvsInputManager::initializeCameras() {
+    for (int i = 0; i < mInputConfig.input_stream_size(); i++) {
+        // Verify that the stream type specified is a camera stream which is necessary for evs
+        // manager.
+        if (mInputConfig.input_stream(i).type() != proto::InputStreamConfig_InputType_CAMERA) {
+            ALOGE("Evs stream manager expects the input stream type to be camera.");
+            return Status::INVALID_ARGUMENT;
+        }
+        const std::string& cameraId = mInputConfig.input_stream(i).cam_config().cam_id();
+        std::unique_ptr<AnalyzeCallback> analyzeCallback =
+            std::make_unique<AnalyzeCallback>(mInputConfig.input_stream(i).stream_id());
+        AnalyzeUseCase analyzeUseCase =
+            AnalyzeUseCase::createDefaultUseCase(cameraId, analyzeCallback.get());
+        mAnalyzeCallbacks.push_back(std::move(analyzeCallback));
+
+        int streamId = mInputConfig.input_stream(i).stream_id();
+        auto [it, result] = mEvsUseCases.try_emplace(std::move(streamId),
+                                                     std::move(analyzeUseCase));
+        if (!result) {
+            // Multiple camera streams found to have the same camera id.
+            ALOGE("Multiple camera streams have the same stream id.");
+            return Status::INVALID_ARGUMENT;
+        }
+    }
+
+    return Status::SUCCESS;
+}
+
+Status EvsInputManager::handleExecutionPhase(const RunnerEvent& e) {
+    // Starting execution cannot be stopped in between. handleStopImmediate needs to be called.
+    if (e.isAborted()) {
+        return Status::INVALID_ARGUMENT;
+    } else if (e.isTransitionComplete()) {
+        return Status::SUCCESS;
+    }
+
+    if (mEvsUseCases.empty()) {
+        ALOGE("No evs use cases configured. Verify that handleConfigPhase has been called");
+        return Status::ILLEGAL_STATE;
+    }
+
+    // Start all the video streams.
+    bool successfullyStartedAllCameras = true;
+    for (auto& [streamId, evsUseCase] : mEvsUseCases) {
+        if (!evsUseCase.startVideoStream()) {
+            successfullyStartedAllCameras = false;
+            ALOGE("Unable to successfully start all cameras");
+            break;
+        }
+    }
+
+    // If not all video streams have started successfully, stop the streams.
+    if (!successfullyStartedAllCameras) {
+        for (auto& [streamId, evsUseCase] : mEvsUseCases) {
+            evsUseCase.stopVideoStream();
+        }
+        return Status::INTERNAL_ERROR;
+    }
+
+    // Set the input to engine interface for callbacks only when all the streams have successfully
+    // started. This prevents any callback from going out unless all of the streams have started.
+    for (auto& analyzeCallback : mAnalyzeCallbacks) {
+        analyzeCallback->setEngineInterface(mInputEngineInterface);
+    }
+
+    return Status::SUCCESS;
+}
+
+Status EvsInputManager::handleStopImmediatePhase(const RunnerEvent& e) {
+    if (e.isAborted()) {
+        ALOGE(
+            "Unable to abort immediate stopping of EVS cameras. Please start the video streams "
+            "again if "
+            "needed.");
+    } else if (e.isTransitionComplete()) {
+        return Status::SUCCESS;
+    }
+
+    // Reset all input engine interfaces so that callbacks stop going out even if there are evs
+    // frames in flux.
+    for (auto& analyzeCallback : mAnalyzeCallbacks) {
+        analyzeCallback->setEngineInterface(nullptr);
+    }
+
+    for (auto& [streamId, evsUseCase] : mEvsUseCases) {
+        evsUseCase.stopVideoStream();
+    }
+
+    return Status::SUCCESS;
+}
+
+Status EvsInputManager::handleStopWithFlushPhase(const RunnerEvent& e) {
+    if (e.isAborted()) {
+        ALOGE(
+            "Unable to abort stopping and flushing of EVS cameras. Please start the video streams "
+            "again if "
+            "needed.");
+    } else if (e.isTransitionComplete()) {
+        return Status::SUCCESS;
+    }
+
+    for (auto& [streamId, evsUseCase] : mEvsUseCases) {
+        evsUseCase.stopVideoStream();
+    }
+    return Status::SUCCESS;
+}
+
+Status EvsInputManager::handleResetPhase(const RunnerEvent& e) {
+    if (e.isAborted()) {
+        ALOGE("Unable to abort reset.");
+        return Status::INVALID_ARGUMENT;
+    }
+    mEvsUseCases.clear();
+    mAnalyzeCallbacks.clear();
+    return Status::SUCCESS;
+}
+
+}  // namespace input_manager
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/input_manager/Factory.cpp b/computepipe/runner/input_manager/Factory.cpp
new file mode 100644
index 0000000..fe62e60
--- /dev/null
+++ b/computepipe/runner/input_manager/Factory.cpp
@@ -0,0 +1,55 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "EvsInputManager.h"
+#include "InputManager.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace input_manager {
+namespace {
+
+enum InputManagerType {
+    EVS = 0,
+    IMAGES,
+    VIDEO,
+};
+
+// Helper function to determine the type of input manager to be created from the
+// input config.
+// TODO(b/147803315): Implement the actual algorithm to determine the input manager to be
+// used. Right now, only EVS manager is enabled, so that is used.
+InputManagerType getInputManagerType(const proto::InputConfig& /* inputConfig */) {
+    return InputManagerType::EVS;
+}
+
+}  // namespace
+std::unique_ptr<InputManager> InputManagerFactory::createInputManager(
+    const proto::InputConfig& config, std::shared_ptr<InputEngineInterface> inputEngineInterface) {
+    InputManagerType inputManagerType = getInputManagerType(config);
+    switch (inputManagerType) {
+        case InputManagerType::EVS:
+            return EvsInputManager::createEvsInputManager(config, inputEngineInterface);
+        default:
+            return nullptr;
+    }
+}
+
+}  // namespace input_manager
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/input_manager/include/EvsInputManager.h b/computepipe/runner/input_manager/include/EvsInputManager.h
new file mode 100644
index 0000000..899593a
--- /dev/null
+++ b/computepipe/runner/input_manager/include/EvsInputManager.h
@@ -0,0 +1,86 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef COMPUTEPIPE_RUNNER_INPUT_MANAGER_INCLUDE_EVSINPUTMANAGER_H_
+#define COMPUTEPIPE_RUNNER_INPUT_MANAGER_INCLUDE_EVSINPUTMANAGER_H_
+
+#include <memory>
+#include <shared_mutex>
+#include <unordered_map>
+#include <vector>
+
+#include "AnalyzeUseCase.h"
+#include "BaseAnalyzeCallback.h"
+#include "InputConfig.pb.h"
+#include "InputEngineInterface.h"
+#include "InputManager.h"
+#include "RunnerComponent.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace input_manager {
+
+// Class that is used as a callback for EVS camera streams.
+class AnalyzeCallback : public ::android::automotive::evs::support::BaseAnalyzeCallback {
+  public:
+    AnalyzeCallback(int inputStreamId) : mInputStreamId(inputStreamId) {
+    }
+
+    void analyze(const ::android::automotive::evs::support::Frame&) override;
+
+    void setEngineInterface(std::shared_ptr<InputEngineInterface> inputEngineInterface);
+
+    virtual ~AnalyzeCallback(){};
+
+  private:
+    std::shared_ptr<InputEngineInterface> mInputEngineInterface;
+    std::shared_mutex mEngineInterfaceLock;
+    const int mInputStreamId;
+};
+
+class EvsInputManager : public InputManager {
+  public:
+    explicit EvsInputManager(const proto::InputConfig& inputConfig,
+                             std::shared_ptr<InputEngineInterface> inputEngineInterface);
+
+    static std::unique_ptr<EvsInputManager> createEvsInputManager(
+        const proto::InputConfig& inputConfig,
+        std::shared_ptr<InputEngineInterface> inputEngineInterface);
+
+    Status initializeCameras();
+
+    Status handleExecutionPhase(const RunnerEvent& e) override;
+
+    Status handleStopImmediatePhase(const RunnerEvent& e) override;
+
+    Status handleStopWithFlushPhase(const RunnerEvent& e) override;
+
+    Status handleResetPhase(const RunnerEvent& e) override;
+
+  private:
+    std::unordered_map<int, ::android::automotive::evs::support::AnalyzeUseCase> mEvsUseCases;
+    std::vector<std::unique_ptr<AnalyzeCallback>> mAnalyzeCallbacks;
+    std::shared_ptr<InputEngineInterface> mInputEngineInterface;
+    const proto::InputConfig mInputConfig;
+};
+
+}  // namespace input_manager
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // COMPUTEPIPE_RUNNER_INPUT_MANAGER_INCLUDE_EVSINPUTMANAGER_H_
diff --git a/computepipe/runner/input_manager/include/InputEngineInterface.h b/computepipe/runner/input_manager/include/InputEngineInterface.h
new file mode 100644
index 0000000..154bc74
--- /dev/null
+++ b/computepipe/runner/input_manager/include/InputEngineInterface.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_INPUT_ENGINE_INTERFACE_H
+#define COMPUTEPIPE_RUNNER_INPUT_ENGINE_INTERFACE_H
+
+#include "InputFrame.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace input_manager {
+
+class InputEngineInterface {
+  public:
+    /**
+     * Dispatch input frame to engine for consumption by the graph
+     */
+    virtual Status dispatchInputFrame(int streamId, int64_t timestamp, const InputFrame& frame) = 0;
+    /**
+     * Report Error Halt to Engine. Engine should report error to other
+     * components.
+     */
+    virtual void notifyInputError() = 0;
+    /**
+     * Destructor
+     */
+    virtual ~InputEngineInterface() = default;
+};
+
+}  // namespace input_manager
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif
diff --git a/computepipe/runner/input_manager/include/InputManager.h b/computepipe/runner/input_manager/include/InputManager.h
new file mode 100644
index 0000000..9b12414
--- /dev/null
+++ b/computepipe/runner/input_manager/include/InputManager.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_INPUT_MANAGER_H
+#define COMPUTEPIPE_RUNNER_INPUT_MANAGER_H
+
+#include <memory>
+
+#include "InputConfig.pb.h"
+#include "InputEngineInterface.h"
+#include "InputFrame.h"
+#include "RunnerComponent.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace input_manager {
+
+/**
+ * InputManager: Is the runner component repsonsible for managing the input
+ * source for the graph. The Component exposes communications from the engine to
+ * the input source.
+ */
+class InputManager : public RunnerComponentInterface {};
+
+/**
+ * Factory that instantiates the input manager, for a given input option.
+ */
+class InputManagerFactory {
+  public:
+    std::unique_ptr<InputManager> createInputManager(const proto::InputConfig& config,
+                                                     std::shared_ptr<InputEngineInterface> engine);
+    InputManagerFactory() = default;
+    InputManagerFactory(const InputManagerFactory&) = delete;
+    InputManagerFactory& operator=(const InputManagerFactory&) = delete;
+    InputManagerFactory(const InputManagerFactory&&) = delete;
+    InputManagerFactory& operator=(const InputManagerFactory&&) = delete;
+};
+
+}  // namespace input_manager
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+#endif
diff --git a/computepipe/runner/stream_manager/Android.bp b/computepipe/runner/stream_manager/Android.bp
new file mode 100644
index 0000000..7a5cd5a
--- /dev/null
+++ b/computepipe/runner/stream_manager/Android.bp
@@ -0,0 +1,70 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library {
+    name: "computepipe_stream_manager",
+    srcs: [
+        "Factory.cpp",
+        "PixelStreamManager.cpp",
+        "SemanticManager.cpp",
+    ],
+    export_include_dirs: ["include"],
+    visibility: [
+        "//packages/services/Car/computepipe/runner:__subpackages__",
+        "//packages/services/Car/computepipe/tests:__subpackages__",
+    ],
+    header_libs: [
+        "computepipe_runner_includes",
+    ],
+    static_libs: [
+        "libcomputepipeprotos",
+    ],
+    shared_libs: [
+        "libbase",
+        "computepipe_runner_component",
+        "libbase",
+        "libnativewindow",
+    ],
+    include_dirs: [
+        "packages/services/Car/computepipe",
+    ],
+}
+
+cc_library {
+    name: "mock_stream_engine_interface",
+    srcs: [
+        "MockEngine.cpp",
+    ],
+    visibility: [
+        "//packages/services/Car/computepipe/runner:__subpackages__",
+        "//packages/services/Car/computepipe/tests:__subpackages__",
+    ],
+    header_libs: [
+        "computepipe_runner_includes",
+    ],
+    static_libs: [
+        "libbase",
+        "libgtest",
+        "libgmock",
+        "libcomputepipeprotos",
+    ],
+    shared_libs: [
+        "computepipe_runner_component",
+        "computepipe_stream_manager",
+        "libnativewindow",
+    ],
+    include_dirs: [
+        "packages/services/Car/computepipe",
+    ],
+}
diff --git a/computepipe/runner/stream_manager/Factory.cpp b/computepipe/runner/stream_manager/Factory.cpp
new file mode 100644
index 0000000..aee2d1a
--- /dev/null
+++ b/computepipe/runner/stream_manager/Factory.cpp
@@ -0,0 +1,79 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "OutputConfig.pb.h"
+#include "PixelStreamManager.h"
+#include "SemanticManager.h"
+#include "StreamEngineInterface.h"
+#include "StreamManager.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace stream_manager {
+
+namespace {
+
+/**
+ * Build an instance of the Semantic Manager and initialize it
+ */
+std::unique_ptr<SemanticManager> buildSemanticManager(const proto::OutputConfig& config,
+                                                      std::shared_ptr<StreamEngineInterface> engine,
+                                                      uint32_t maxPackets) {
+    std::unique_ptr<SemanticManager> semanticManager =
+        std::make_unique<SemanticManager>(config.stream_name(), config.stream_id(), config.type());
+    semanticManager->setEngineInterface(engine);
+    if (semanticManager->setMaxInFlightPackets(maxPackets) != SUCCESS) {
+        return nullptr;
+    }
+    return semanticManager;
+}
+
+std::unique_ptr<PixelStreamManager> buildPixelStreamManager(
+    const proto::OutputConfig& config, std::shared_ptr<StreamEngineInterface> engine,
+    uint32_t maxPackets) {
+    std::unique_ptr<PixelStreamManager> pixelStreamManager =
+        std::make_unique<PixelStreamManager>(config.stream_name(), config.stream_id());
+    pixelStreamManager->setEngineInterface(engine);
+    if (pixelStreamManager->setMaxInFlightPackets(maxPackets) != Status::SUCCESS) {
+        return nullptr;
+    }
+    return pixelStreamManager;
+}
+
+}  // namespace
+
+std::unique_ptr<StreamManager> StreamManagerFactory::getStreamManager(
+    const proto::OutputConfig& config, std::shared_ptr<StreamEngineInterface> engine,
+    uint32_t maxPackets) {
+    if (!config.has_type()) {
+        return nullptr;
+    }
+    switch (config.type()) {
+        case proto::PacketType::SEMANTIC_DATA:
+            return buildSemanticManager(config, engine, maxPackets);
+        case proto::PacketType::PIXEL_DATA:
+            return buildPixelStreamManager(config, engine, maxPackets);
+        default:
+            return nullptr;
+    }
+    return nullptr;
+}
+
+}  // namespace stream_manager
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/stream_manager/MockEngine.cpp b/computepipe/runner/stream_manager/MockEngine.cpp
new file mode 100644
index 0000000..ac41a98
--- /dev/null
+++ b/computepipe/runner/stream_manager/MockEngine.cpp
@@ -0,0 +1,38 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "MockEngine.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace stream_manager {
+
+using ::testing::_;
+
+void MockEngine::delegateToFake(const std::shared_ptr<StreamEngineInterface>& engine) {
+    mFake = engine;
+    ON_CALL(*this, dispatchPacket).WillByDefault([this](const std::shared_ptr<MemHandle>& handle) {
+        return mFake->dispatchPacket(handle);
+    });
+    ON_CALL(*this, notifyError).WillByDefault([this](std::string msg) { mFake->notifyError(msg); });
+    ON_CALL(*this, notifyEndOfStream).WillByDefault([this]() { mFake->notifyEndOfStream(); });
+}
+
+}  // namespace stream_manager
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/stream_manager/MockEngine.h b/computepipe/runner/stream_manager/MockEngine.h
new file mode 100644
index 0000000..32d318b
--- /dev/null
+++ b/computepipe/runner/stream_manager/MockEngine.h
@@ -0,0 +1,47 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_STREAM_MOCK_ENGINE_H
+#define COMPUTEPIPE_RUNNER_STREAM_MOCK_ENGINE_H
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "StreamEngineInterface.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace stream_manager {
+
+class MockEngine : public StreamEngineInterface {
+  public:
+    MockEngine() = default;
+    MOCK_METHOD(Status, dispatchPacket, (const std::shared_ptr<MemHandle>& data), (override));
+    MOCK_METHOD(void, notifyEndOfStream, (), (override));
+    MOCK_METHOD(void, notifyError, (std::string msg), (override));
+    void delegateToFake(const std::shared_ptr<StreamEngineInterface>& fake);
+
+  private:
+    std::shared_ptr<StreamEngineInterface> mFake;
+};
+
+}  // namespace stream_manager
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif
diff --git a/computepipe/runner/stream_manager/PixelStreamManager.cpp b/computepipe/runner/stream_manager/PixelStreamManager.cpp
new file mode 100644
index 0000000..22e62d6
--- /dev/null
+++ b/computepipe/runner/stream_manager/PixelStreamManager.cpp
@@ -0,0 +1,332 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "PixelStreamManager.h"
+
+#include <android-base/logging.h>
+#include <vndk/hardware_buffer.h>
+
+#include <algorithm>
+#include <mutex>
+#include <thread>
+
+#include "PixelFormatUtils.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace stream_manager {
+
+PixelMemHandle::PixelMemHandle(int bufferId, int streamId, int additionalUsageFlags)
+    : mBufferId(bufferId),
+      mStreamId(streamId),
+      mBuffer(nullptr),
+      mUsage(AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN | additionalUsageFlags) {
+}
+
+PixelMemHandle::~PixelMemHandle() {
+    if (mBuffer) {
+        AHardwareBuffer_release(mBuffer);
+    }
+}
+
+int PixelMemHandle::getStreamId() const {
+    return mStreamId;
+}
+
+proto::PacketType PixelMemHandle::getType() const {
+    return proto::PacketType::PIXEL_DATA;
+}
+uint64_t PixelMemHandle::getTimeStamp() const {
+    return mTimestamp;
+}
+
+uint32_t PixelMemHandle::getSize() const {
+    return 0;
+}
+
+const char* PixelMemHandle::getData() const {
+    return nullptr;
+}
+
+AHardwareBuffer* PixelMemHandle::getHardwareBuffer() const {
+    return mBuffer;
+}
+
+/* Sets frame info */
+Status PixelMemHandle::setFrameData(uint64_t timestamp, const InputFrame& inputFrame) {
+    // Allocate a new buffer if it is currently null.
+    FrameInfo frameInfo = inputFrame.getFrameInfo();
+    if (mBuffer == nullptr) {
+        mDesc.format = PixelFormatToHardwareBufferFormat(frameInfo.format);
+        mDesc.height = frameInfo.height;
+        mDesc.width = frameInfo.width;
+        mDesc.layers = 1;
+        mDesc.rfu0 = 0;
+        mDesc.rfu1 = 0;
+        mDesc.stride = frameInfo.stride;
+        mDesc.usage = mUsage;
+        int err = AHardwareBuffer_allocate(&mDesc, &mBuffer);
+
+        if (err != 0 || mBuffer == nullptr) {
+            LOG(ERROR) << "Failed to allocate hardware buffer with error " << err;
+            return Status::NO_MEMORY;
+        }
+
+        // Update mDesc with the actual descriptor with which the buffer was created. The actual
+        // stride could be different from the specified stride.
+        AHardwareBuffer_describe(mBuffer, &mDesc);
+    }
+
+    // Verifies that the input frame data has the same type as the allocated buffer.
+    if (frameInfo.width != mDesc.width || frameInfo.height != mDesc.height ||
+        PixelFormatToHardwareBufferFormat(frameInfo.format) != mDesc.format) {
+        LOG(ERROR) << "Variable image sizes from the same stream id is not supported.";
+        return Status::INVALID_ARGUMENT;
+    }
+
+    // Locks the frame for copying the input frame data.
+    void* mappedBuffer = nullptr;
+    int err = AHardwareBuffer_lock(mBuffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, -1, nullptr,
+                                   &mappedBuffer);
+    if (err != 0 || mappedBuffer == nullptr) {
+        LOG(ERROR) << "Unable to lock a realased hardware buffer.";
+        return Status::INTERNAL_ERROR;
+    }
+
+    // Copies the input frame data.
+    int bytesPerPixel = numBytesPerPixel(static_cast<AHardwareBuffer_Format>(mDesc.format));
+    // The stride for hardware buffer is specified in pixels while the stride
+    // for InputFrame data structure is specified in bytes.
+    if (mDesc.stride * bytesPerPixel == frameInfo.stride) {
+        memcpy(mappedBuffer, inputFrame.getFramePtr(), mDesc.stride * mDesc.height * bytesPerPixel);
+    } else {
+        for (int y = 0; y < frameInfo.height; y++) {
+            memcpy((uint8_t*)mappedBuffer + mDesc.stride * y * bytesPerPixel,
+                   inputFrame.getFramePtr() + y * frameInfo.stride,
+                   std::min(frameInfo.stride, mDesc.stride * bytesPerPixel));
+        }
+    }
+
+    AHardwareBuffer_unlock(mBuffer, nullptr);
+    mTimestamp = timestamp;
+
+    return Status::SUCCESS;
+}
+
+int PixelMemHandle::getBufferId() const {
+    return mBufferId;
+}
+
+void PixelStreamManager::setEngineInterface(std::shared_ptr<StreamEngineInterface> engine) {
+    std::lock_guard lock(mLock);
+    mEngine = engine;
+}
+
+Status PixelStreamManager::setMaxInFlightPackets(uint32_t maxPackets) {
+    std::lock_guard lock(mLock);
+    if (mBuffersInUse.size() > maxPackets) {
+        LOG(ERROR) << "Cannot set max in flight packets after graph has already started.";
+        return Status::ILLEGAL_STATE;
+    }
+
+    mMaxInFlightPackets = maxPackets;
+    std::lock_guard stateLock(mStateLock);
+    mState = CONFIG_DONE;
+    return Status::SUCCESS;
+}
+
+Status PixelStreamManager::freePacket(int bufferId) {
+    std::lock_guard lock(mLock);
+
+    auto it = mBuffersInUse.find(bufferId);
+
+    if (it == mBuffersInUse.end()) {
+        std::lock_guard stateLock(mStateLock);
+        // If the graph has already been stopped, we free the buffers
+        // asynchronously, so return SUCCESS if freePacket is called later.
+        if (mState == STOPPED) {
+            return Status::SUCCESS;
+        }
+
+        LOG(ERROR) << "Unable to find the mem handle. Duplicate release may possible have been "
+                      "called";
+        return Status::INVALID_ARGUMENT;
+    }
+
+    it->second.outstandingRefCount -= 1;
+    if (it->second.outstandingRefCount == 0) {
+        mBuffersReady.push_back(it->second.handle);
+        mBuffersInUse.erase(it);
+    }
+    return Status::SUCCESS;
+}
+
+void PixelStreamManager::freeAllPackets() {
+    std::lock_guard lock(mLock);
+
+    for (auto [bufferId, buffer] : mBuffersInUse) {
+        mBuffersReady.push_back(buffer.handle);
+    }
+    mBuffersInUse.clear();
+}
+
+Status PixelStreamManager::queuePacket(const char* /*data*/, const uint32_t /*size*/,
+                                       uint64_t /*timestamp*/) {
+    LOG(ERROR) << "Trying to queue a semantic packet to a pixel stream manager";
+    return Status::ILLEGAL_STATE;
+}
+
+Status PixelStreamManager::queuePacket(const InputFrame& frame, uint64_t timestamp) {
+    std::lock_guard lock(mLock);
+
+    // State has to be running for the callback to go back.
+    {
+        std::lock_guard stateLock(mStateLock);
+        if (mState != RUNNING) {
+            LOG(ERROR) << "Packet cannot be queued when state is not RUNNING. Current state is"
+                       << mState;
+            return Status::ILLEGAL_STATE;
+        }
+    }
+
+    if (mEngine == nullptr) {
+        LOG(ERROR) << "Stream to engine interface is not set";
+        return Status::ILLEGAL_STATE;
+    }
+
+    if (mBuffersInUse.size() >= mMaxInFlightPackets) {
+        LOG(INFO) << "Too many frames in flight. Skipping frame at timestamp " << timestamp;
+        return Status::SUCCESS;
+    }
+
+    // A unique id per buffer is maintained by incrementing the unique id from the previously
+    // created buffer. The unique id is therefore the number of buffers already created.
+    if (mBuffersReady.empty()) {
+        mBuffersReady.push_back(std::make_shared<PixelMemHandle>(mBuffersInUse.size(), mStreamId));
+    }
+
+    // The previously used buffer is pushed to the back of the vector. Picking the last used buffer
+    // may be more cache efficient if accessing through CPU, so we use that strategy here.
+    std::shared_ptr<PixelMemHandle> memHandle = mBuffersReady[mBuffersReady.size() - 1];
+    mBuffersReady.resize(mBuffersReady.size() - 1);
+
+    BufferMetadata bufferMetadata;
+    bufferMetadata.outstandingRefCount = 1;
+    bufferMetadata.handle = memHandle;
+
+    mBuffersInUse.emplace(memHandle->getBufferId(), bufferMetadata);
+
+    Status status = memHandle->setFrameData(timestamp, frame);
+    if (status != Status::SUCCESS) {
+        LOG(ERROR) << "Setting frame data failed with error code " << status;
+        return status;
+    }
+
+    // Dispatch packet to the engine asynchronously in order to avoid circularly
+    // waiting for each others' locks.
+    std::thread t([this, memHandle]() {
+        Status status = mEngine->dispatchPacket(memHandle);
+        if (status != Status::SUCCESS) {
+            mEngine->notifyError(std::string(__func__) + ":" + std::to_string(__LINE__) +
+                                 " Failed to dispatch packet");
+        }
+    });
+    t.detach();
+    return Status::SUCCESS;
+}
+
+Status PixelStreamManager::handleExecutionPhase(const RunnerEvent& e) {
+    std::lock_guard<std::mutex> lock(mStateLock);
+    if (mState == CONFIG_DONE && e.isPhaseEntry()) {
+        mState = RUNNING;
+        return Status::SUCCESS;
+    }
+    if (mState == RESET) {
+        // Cannot get to running phase from reset state without config phase
+        return Status::ILLEGAL_STATE;
+    }
+    if (mState == RUNNING && e.isAborted()) {
+        // Transition back to config completed
+        mState = CONFIG_DONE;
+        return Status::SUCCESS;
+    }
+    if (mState == RUNNING) {
+        return Status::ILLEGAL_STATE;
+    }
+    return Status::SUCCESS;
+}
+
+Status PixelStreamManager::handleStopWithFlushPhase(const RunnerEvent& e) {
+    return handleStopImmediatePhase(e);
+}
+
+Status PixelStreamManager::handleStopImmediatePhase(const RunnerEvent& e) {
+    std::lock_guard<std::mutex> lock(mStateLock);
+    if (mState == CONFIG_DONE || mState == RESET) {
+        return ILLEGAL_STATE;
+    }
+    /* Cannot have stop completed if we never entered stop state */
+    if (mState == RUNNING && (e.isAborted() || e.isTransitionComplete())) {
+        return ILLEGAL_STATE;
+    }
+    /* We are being asked to stop */
+    if (mState == RUNNING && e.isPhaseEntry()) {
+        mState = STOPPED;
+        std::thread t([this]() {
+            freeAllPackets();
+            mEngine->notifyEndOfStream();
+        });
+        t.detach();
+        return SUCCESS;
+    }
+    /* Other Components have stopped, we can transition back to CONFIG_DONE */
+    if (mState == STOPPED && e.isTransitionComplete()) {
+        mState = CONFIG_DONE;
+        return SUCCESS;
+    }
+    /* We were stopped, but stop was aborted. */
+    if (mState == STOPPED && e.isAborted()) {
+        mState = RUNNING;
+        return SUCCESS;
+    }
+    return SUCCESS;
+}
+
+std::shared_ptr<MemHandle> PixelStreamManager::clonePacket(std::shared_ptr<MemHandle> handle) {
+    if (!handle) {
+        LOG(ERROR) << "PixelStreamManager - Received null memhandle.";
+        return nullptr;
+    }
+
+    std::lock_guard<std::mutex> lock(mLock);
+    int bufferId = handle->getBufferId();
+    auto it = mBuffersInUse.find(bufferId);
+    if (it == mBuffersInUse.end()) {
+        LOG(ERROR) << "PixelStreamManager - Attempting to clone an already freed packet.";
+        return nullptr;
+    }
+    it->second.outstandingRefCount += 1;
+    return handle;
+}
+
+PixelStreamManager::PixelStreamManager(std::string name, int streamId)
+    : StreamManager(name, proto::PacketType::PIXEL_DATA), mStreamId(streamId) {
+}
+
+}  // namespace stream_manager
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/stream_manager/PixelStreamManager.h b/computepipe/runner/stream_manager/PixelStreamManager.h
new file mode 100644
index 0000000..0e1e7f2
--- /dev/null
+++ b/computepipe/runner/stream_manager/PixelStreamManager.h
@@ -0,0 +1,115 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef COMPUTEPIPE_RUNNER_STREAM_MANAGER_PIXEL_STREAM_MANAGER_H
+#define COMPUTEPIPE_RUNNER_STREAM_MANAGER_PIXEL_STREAM_MANAGER_H
+
+#include <vndk/hardware_buffer.h>
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <vector>
+
+#include "InputFrame.h"
+#include "MemHandle.h"
+#include "RunnerComponent.h"
+#include "StreamManager.h"
+#include "StreamManagerInit.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace stream_manager {
+
+class PixelMemHandle : public MemHandle {
+  public:
+    explicit PixelMemHandle(int bufferId, int streamId, int additionalUsageFlags = 0);
+
+    virtual ~PixelMemHandle();
+
+    // Delete copy and move constructors as well as copy and move assignment operators.
+    PixelMemHandle(const PixelMemHandle&) = delete;
+    PixelMemHandle(PixelMemHandle&&) = delete;
+    PixelMemHandle operator=(const PixelMemHandle&) = delete;
+    PixelMemHandle operator=(PixelMemHandle&&) = delete;
+
+    /**
+     * Overrides mem handle methods
+     */
+    int getStreamId() const override;
+    int getBufferId() const override;
+    proto::PacketType getType() const override;
+    uint64_t getTimeStamp() const override;
+    uint32_t getSize() const override;
+    const char* getData() const override;
+    AHardwareBuffer* getHardwareBuffer() const override;
+
+    /* Sets frame info */
+    Status setFrameData(uint64_t timestamp, const InputFrame& inputFrame);
+
+  private:
+    const int mBufferId;
+    const int mStreamId;
+    AHardwareBuffer_Desc mDesc;
+    AHardwareBuffer* mBuffer;
+    uint64_t mTimestamp;
+    int mUsage;
+};
+
+class PixelStreamManager : public StreamManager, StreamManagerInit {
+  public:
+    void setEngineInterface(std::shared_ptr<StreamEngineInterface> engine) override;
+    // Set Max in flight packets based on client specification
+    Status setMaxInFlightPackets(uint32_t maxPackets) override;
+    // Free previously dispatched packet. Once client has confirmed usage
+    Status freePacket(int bufferId) override;
+    // Queue packet produced by graph stream
+    Status queuePacket(const char* data, const uint32_t size, uint64_t timestamp) override;
+    // Queues pixel packet produced by graph stream
+    Status queuePacket(const InputFrame& frame, uint64_t timestamp) override;
+    /* Make a copy of the packet. */
+    std::shared_ptr<MemHandle> clonePacket(std::shared_ptr<MemHandle> handle) override;
+
+    Status handleExecutionPhase(const RunnerEvent& e) override;
+    Status handleStopWithFlushPhase(const RunnerEvent& e) override;
+    Status handleStopImmediatePhase(const RunnerEvent& e) override;
+
+    explicit PixelStreamManager(std::string name, int streamId);
+    ~PixelStreamManager() = default;
+
+  private:
+    void freeAllPackets();
+    std::mutex mLock;
+    std::mutex mStateLock;
+    int mStreamId;
+    uint32_t mMaxInFlightPackets;
+    std::shared_ptr<StreamEngineInterface> mEngine;
+
+    struct BufferMetadata {
+        int outstandingRefCount;
+        std::shared_ptr<PixelMemHandle> handle;
+    };
+
+    std::map<int, BufferMetadata> mBuffersInUse;
+    std::vector<std::shared_ptr<PixelMemHandle>> mBuffersReady;
+};
+
+}  // namespace stream_manager
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // COMPUTEPIPE_RUNNER_STREAM_MANAGER_PIXEL_STREAM_MANAGER_H
diff --git a/computepipe/runner/stream_manager/SemanticManager.cpp b/computepipe/runner/stream_manager/SemanticManager.cpp
new file mode 100644
index 0000000..2d0d03a
--- /dev/null
+++ b/computepipe/runner/stream_manager/SemanticManager.cpp
@@ -0,0 +1,181 @@
+#include "SemanticManager.h"
+
+#include <android-base/logging.h>
+
+#include <cstdlib>
+#include <thread>
+
+#include "InputFrame.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace stream_manager {
+
+proto::PacketType SemanticHandle::getType() const {
+    return mType;
+}
+
+uint64_t SemanticHandle::getTimeStamp() const {
+    return mTimestamp;
+}
+
+uint32_t SemanticHandle::getSize() const {
+    return mSize;
+}
+
+const char* SemanticHandle::getData() const {
+    return mData;
+}
+
+AHardwareBuffer* SemanticHandle::getHardwareBuffer() const {
+    return nullptr;
+}
+
+int SemanticHandle::getStreamId() const {
+    return mStreamId;
+}
+
+// Buffer id is not tracked for semantic handle as they do not need a
+// doneWithPacket() call.
+int SemanticHandle::getBufferId() const {
+    return -1;
+}
+
+Status SemanticHandle::setMemInfo(int streamId, const char* data, uint32_t size, uint64_t timestamp,
+                                  const proto::PacketType& type) {
+    if (data == nullptr || size == 0 || size > kMaxSemanticDataSize) {
+        return INVALID_ARGUMENT;
+    }
+    mStreamId = streamId;
+    mData = (char*)malloc(size);
+    if (!mData) {
+        return NO_MEMORY;
+    }
+    memcpy(mData, data, size);
+    mType = type;
+    mTimestamp = timestamp;
+    mSize = size;
+    return SUCCESS;
+}
+
+/* Destroy local copy */
+SemanticHandle::~SemanticHandle() {
+    free(mData);
+}
+
+void SemanticManager::setEngineInterface(std::shared_ptr<StreamEngineInterface> engine) {
+    mEngine = engine;
+    std::lock_guard<std::mutex> lock(mStateLock);
+    mState = RESET;
+}
+
+void SemanticManager::notifyEndOfStream() {
+    mEngine->notifyEndOfStream();
+}
+
+// TODO: b/146495240 Add support for batching
+Status SemanticManager::setMaxInFlightPackets(uint32_t /* maxPackets */) {
+    if (!mEngine) {
+        return ILLEGAL_STATE;
+    }
+    mState = CONFIG_DONE;
+    return SUCCESS;
+}
+
+Status SemanticManager::handleExecutionPhase(const RunnerEvent& e) {
+    std::lock_guard<std::mutex> lock(mStateLock);
+    if (mState == CONFIG_DONE && e.isPhaseEntry()) {
+        mState = RUNNING;
+        return SUCCESS;
+    }
+    if (mState == RESET) {
+        /* Cannot get to running phase from reset state without config phase*/
+        return ILLEGAL_STATE;
+    }
+    if (mState == RUNNING && e.isAborted()) {
+        /* Transition back to config completed */
+        mState = CONFIG_DONE;
+        return SUCCESS;
+    }
+    if (mState == RUNNING) {
+        return ILLEGAL_STATE;
+    }
+    return SUCCESS;
+}
+
+Status SemanticManager::handleStopWithFlushPhase(const RunnerEvent& e) {
+    std::lock_guard<std::mutex> lock(mStateLock);
+    if (mState == CONFIG_DONE || mState == RESET) {
+        return ILLEGAL_STATE;
+    }
+    /* Cannot have stop completed if we never entered stop state */
+    if (mState == RUNNING && (e.isAborted() || e.isTransitionComplete())) {
+        return ILLEGAL_STATE;
+    }
+    /* We are being asked to stop */
+    if (mState == RUNNING && e.isPhaseEntry()) {
+        mState = STOPPED;
+        std::thread t(&SemanticManager::notifyEndOfStream, this);
+        t.detach();
+        return SUCCESS;
+    }
+    /* Other Components have stopped, we can transition back to CONFIG_DONE */
+    if (mState == STOPPED && e.isTransitionComplete()) {
+        mState = CONFIG_DONE;
+        return SUCCESS;
+    }
+    /* We were stopped, but stop was aborted. */
+    if (mState == STOPPED && e.isAborted()) {
+        mState = RUNNING;
+        return SUCCESS;
+    }
+    return SUCCESS;
+}
+
+Status SemanticManager::handleStopImmediatePhase(const RunnerEvent& e) {
+    return handleStopWithFlushPhase(e);
+}
+
+Status SemanticManager::freePacket(int /* bufferId */) {
+    return SUCCESS;
+}
+
+Status SemanticManager::queuePacket(const char* data, const uint32_t size, uint64_t timestamp) {
+    std::lock_guard<std::mutex> lock(mStateLock);
+    // We drop the packet since we have received the stop notifications.
+    if (mState != RUNNING) {
+        return SUCCESS;
+    }
+    // Invalid state.
+    if (mEngine == nullptr) {
+        return INTERNAL_ERROR;
+    }
+    auto memHandle = std::make_shared<SemanticHandle>();
+    auto status = memHandle->setMemInfo(mStreamId, data, size, timestamp, mType);
+    if (status != SUCCESS) {
+        return status;
+    }
+    mEngine->dispatchPacket(memHandle);
+    return SUCCESS;
+}
+
+Status SemanticManager::queuePacket(const InputFrame& /*inputData*/, uint64_t /*timestamp*/) {
+    LOG(ERROR) << "Unexpected call to queue a pixel packet from a semantic stream manager.";
+    return Status::ILLEGAL_STATE;
+}
+
+std::shared_ptr<MemHandle> SemanticManager::clonePacket(std::shared_ptr<MemHandle> handle) {
+    return handle;
+}
+
+SemanticManager::SemanticManager(std::string name, int streamId, const proto::PacketType& type)
+    : StreamManager(name, type), mStreamId(streamId) {
+}
+}  // namespace stream_manager
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/runner/stream_manager/SemanticManager.h b/computepipe/runner/stream_manager/SemanticManager.h
new file mode 100644
index 0000000..b5c14cf
--- /dev/null
+++ b/computepipe/runner/stream_manager/SemanticManager.h
@@ -0,0 +1,92 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_STREAM_MANAGER_SEMANTIC_MANAGER_H
+#define COMPUTEPIPE_RUNNER_STREAM_MANAGER_SEMANTIC_MANAGER_H
+
+#include <mutex>
+
+#include "InputFrame.h"
+#include "OutputConfig.pb.h"
+#include "RunnerComponent.h"
+#include "StreamManager.h"
+#include "StreamManagerInit.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace stream_manager {
+
+class SemanticHandle : public MemHandle {
+  public:
+    static constexpr uint32_t kMaxSemanticDataSize = 1024;
+    /**
+     * Override mem handle methods
+     */
+    int getStreamId() const override;
+    int getBufferId() const override;
+    proto::PacketType getType() const override;
+    uint64_t getTimeStamp() const override;
+    uint32_t getSize() const override;
+    const char* getData() const override;
+    AHardwareBuffer* getHardwareBuffer() const override;
+    /* set info for the memory. Make a copy */
+    Status setMemInfo(int streamId, const char* data, uint32_t size, uint64_t timestamp,
+                      const proto::PacketType& type);
+    /* Destroy local copy */
+    ~SemanticHandle();
+
+  private:
+    char* mData = nullptr;
+    uint32_t mSize;
+    uint64_t mTimestamp;
+    proto::PacketType mType;
+    int mStreamId;
+};
+
+class SemanticManager : public StreamManager, StreamManagerInit {
+  public:
+    void setEngineInterface(std::shared_ptr<StreamEngineInterface> engine) override;
+    /* Set Max in flight packets based on client specification */
+    Status setMaxInFlightPackets(uint32_t maxPackets) override;
+    /* Free previously dispatched packet. Once client has confirmed usage */
+    Status freePacket(int bufferId) override;
+    /* Queue packet produced by graph stream */
+    Status queuePacket(const char* data, const uint32_t size, uint64_t timestamp) override;
+    /* Queues an image packet produced by graph stream */
+    Status queuePacket(const InputFrame& inputData, uint64_t timestamp) override;
+    /* Make a copy of the packet. */
+    std::shared_ptr<MemHandle> clonePacket(std::shared_ptr<MemHandle> handle) override;
+    /* Override handling of Runner Engine Events */
+    void notifyEndOfStream();
+
+    Status handleExecutionPhase(const RunnerEvent& e) override;
+    Status handleStopWithFlushPhase(const RunnerEvent& e) override;
+    Status handleStopImmediatePhase(const RunnerEvent& e) override;
+
+    explicit SemanticManager(std::string name, int streamId, const proto::PacketType& type);
+    ~SemanticManager() = default;
+
+  private:
+    std::mutex mStateLock;
+    int mStreamId;
+    std::shared_ptr<StreamEngineInterface> mEngine;
+};
+}  // namespace stream_manager
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+#endif
diff --git a/computepipe/runner/stream_manager/StreamManagerInit.h b/computepipe/runner/stream_manager/StreamManagerInit.h
new file mode 100644
index 0000000..2464ca3
--- /dev/null
+++ b/computepipe/runner/stream_manager/StreamManagerInit.h
@@ -0,0 +1,44 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_STREAM_MANAGER_INIT_H
+#define COMPUTEPIPE_RUNNER_STREAM_MANAGER_INIT_H
+
+#include <functional>
+#include <memory>
+
+#include "MemHandle.h"
+#include "StreamEngineInterface.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace stream_manager {
+
+class StreamManagerInit {
+  public:
+    virtual void setEngineInterface(std::shared_ptr<StreamEngineInterface> engine) = 0;
+    /* Set Max in flight packets based on client specification */
+    virtual Status setMaxInFlightPackets(uint32_t maxPackets) = 0;
+    virtual ~StreamManagerInit() = default;
+};
+
+}  // namespace stream_manager
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+#endif
diff --git a/computepipe/runner/stream_manager/include/StreamEngineInterface.h b/computepipe/runner/stream_manager/include/StreamEngineInterface.h
new file mode 100644
index 0000000..418adeb
--- /dev/null
+++ b/computepipe/runner/stream_manager/include/StreamEngineInterface.h
@@ -0,0 +1,56 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_STREAM_ENGINE_INTERFACE_H
+#define COMPUTEPIPE_RUNNER_STREAM_ENGINE_INTERFACE_H
+
+#include "MemHandle.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace stream_manager {
+
+/**
+ * Stream manager -> Engine interface.
+ */
+class StreamEngineInterface {
+  public:
+    /**
+     * Does not block on the remote client to handle the packet.
+     */
+    virtual Status dispatchPacket(const std::shared_ptr<MemHandle>& outData) = 0;
+    /**
+     * After receiving StopWithFlush, once all outstanding packets have been
+     * freed by the client, notify the engine of end of stream.
+     * Should not be called in the thread that initiates the StopWithFlush, but
+     * rather in a separate thread
+     */
+    virtual void notifyEndOfStream() = 0;
+    /**
+     * Notify engine of error
+     */
+    virtual void notifyError(std::string msg) = 0;
+    virtual ~StreamEngineInterface() = default;
+};
+
+}  // namespace stream_manager
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif
diff --git a/computepipe/runner/stream_manager/include/StreamManager.h b/computepipe/runner/stream_manager/include/StreamManager.h
new file mode 100644
index 0000000..bb3c833
--- /dev/null
+++ b/computepipe/runner/stream_manager/include/StreamManager.h
@@ -0,0 +1,105 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_RUNNER_STREAM_MANAGER_H
+#define COMPUTEPIPE_RUNNER_STREAM_MANAGER_H
+
+#include <functional>
+#include <memory>
+#include <string>
+
+#include "InputFrame.h"
+#include "MemHandle.h"
+#include "OutputConfig.pb.h"
+#include "RunnerComponent.h"
+#include "StreamEngineInterface.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace stream_manager {
+
+/**
+ * Manager the operations of an output stream from the graph.
+ * Should be constructed using the StreamManagerFactory.
+ * The manager instance for a given stream depends on the streams
+ * description specified in OuputConfig.
+ */
+
+class StreamManager : public RunnerComponentInterface {
+  public:
+    enum State {
+        /* State on construction. */
+        RESET = 0,
+        /* State once inflight packets set */
+        CONFIG_DONE = 1,
+        /* State once handleRunPhase() notifies of entry to run phase */
+        RUNNING = 2,
+        /**
+         * State once stop issued
+         * Returns to config done, once all in flight packets handled.
+         */
+        STOPPED = 3,
+    };
+    /* Constructor for StreamManager Base class */
+    explicit StreamManager(std::string streamName, const proto::PacketType& type)
+        : mName(streamName), mType(type) {
+    }
+    /* Retrieves the current state */
+    State getState() {
+        return mState;
+    }
+    /* Make a copy of the packet. */
+    virtual std::shared_ptr<MemHandle> clonePacket(std::shared_ptr<MemHandle> handle) = 0;
+    /* Frees previously dispatched packet based on bufferID. Once client has confirmed usage */
+    virtual Status freePacket(int bufferId) = 0;
+    /* Queue's packet produced by graph stream */
+    virtual Status queuePacket(const char* data, const uint32_t size, uint64_t timestamp) = 0;
+    /* Queues a pixel stream packet produced by graph stream */
+    virtual Status queuePacket(const InputFrame& pixelData, uint64_t timestamp) = 0;
+    /* Destructor */
+    virtual ~StreamManager() = default;
+
+  protected:
+    std::string mName;
+    proto::PacketType mType;
+    State mState = RESET;
+};
+
+/**
+ * Factory for generating stream manager instances
+ * It initializes the instances for a given client configuration prior to
+ * returning. (Follows RAII semantics)
+ */
+class StreamManagerFactory {
+  public:
+    std::unique_ptr<StreamManager> getStreamManager(const proto::OutputConfig& config,
+                                                    std::shared_ptr<StreamEngineInterface> engine,
+                                                    uint32_t maxInFlightPackets);
+    StreamManagerFactory(const StreamManagerFactory&) = delete;
+    StreamManagerFactory(const StreamManagerFactory&&) = delete;
+    StreamManagerFactory& operator=(const StreamManagerFactory&&) = delete;
+    StreamManagerFactory& operator=(const StreamManagerFactory&) = delete;
+    StreamManagerFactory() = default;
+};
+
+}  // namespace stream_manager
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif
diff --git a/computepipe/sepolicy/private/computepipe_router.te b/computepipe/sepolicy/private/computepipe_router.te
new file mode 100644
index 0000000..b28dbc9
--- /dev/null
+++ b/computepipe/sepolicy/private/computepipe_router.te
@@ -0,0 +1,13 @@
+# computepipe router
+type computepipe_router_exec, exec_type, file_type, system_file_type;
+
+# allow init to launch processes in this context
+init_daemon_domain(computepipe_router)
+
+# allow this domain to instantiate query and registration interface
+add_service(computepipe_router, computepipe_router_query_service)
+add_service(computepipe_router, computepipe_router_registration_service)
+
+binder_use(computepipe_router)
+
+binder_service(computepipe_router)
diff --git a/computepipe/sepolicy/private/computepipeclientdomain.te b/computepipe/sepolicy/private/computepipeclientdomain.te
new file mode 100644
index 0000000..cbf0116
--- /dev/null
+++ b/computepipe/sepolicy/private/computepipeclientdomain.te
@@ -0,0 +1,9 @@
+###
+### Rules for all domains which are computepipe clients
+###
+
+# Allow binder use
+binder_use(computepipe_client_domain)
+
+# Allow look up using service manager
+allow computepipe_client_domain computepipe_router_query_service:service_manager find;
diff --git a/computepipe/sepolicy/private/computepiperunnerdomain.te b/computepipe/sepolicy/private/computepiperunnerdomain.te
new file mode 100644
index 0000000..65bafd3
--- /dev/null
+++ b/computepipe/sepolicy/private/computepiperunnerdomain.te
@@ -0,0 +1,9 @@
+###
+### Rules for all domains which are computepipe clients
+###
+
+# Allow binder use
+binder_use(computepipe_runner_domain)
+
+# Allow look up using service manager
+allow computepipe_runner_domain computepipe_router_registration_service:service_manager find;
diff --git a/computepipe/sepolicy/private/file_contexts b/computepipe/sepolicy/private/file_contexts
new file mode 100644
index 0000000..663cc7b
--- /dev/null
+++ b/computepipe/sepolicy/private/file_contexts
@@ -0,0 +1 @@
+/system/bin/android\.automotive\.computepipe\.router@1\.0  u:object_r:computepipe_router_exec:s0
diff --git a/computepipe/sepolicy/private/service_contexts b/computepipe/sepolicy/private/service_contexts
new file mode 100644
index 0000000..3ca3cd7
--- /dev/null
+++ b/computepipe/sepolicy/private/service_contexts
@@ -0,0 +1,2 @@
+android.automotive.computepipe.registry.IPipeQuery/router u:object_r:computepipe_router_query_service:s0
+android.automotive.computepipe.registry.IPipeRegistration/router u:object_r:computepipe_router_registration_service:s0
diff --git a/computepipe/sepolicy/public/attributes b/computepipe/sepolicy/public/attributes
new file mode 100644
index 0000000..6620ef0
--- /dev/null
+++ b/computepipe/sepolicy/public/attributes
@@ -0,0 +1,6 @@
+# All computepipe clients
+attribute computepipe_client_domain;
+expandattribute computepipe_client_domain true;
+
+# All computepipe runners
+attribute computepipe_runner_domain;
diff --git a/computepipe/sepolicy/public/computepipe_router.te b/computepipe/sepolicy/public/computepipe_router.te
new file mode 100644
index 0000000..1079226
--- /dev/null
+++ b/computepipe/sepolicy/public/computepipe_router.te
@@ -0,0 +1 @@
+type computepipe_router, domain, coredomain;
diff --git a/computepipe/sepolicy/public/service.te b/computepipe/sepolicy/public/service.te
new file mode 100644
index 0000000..1b17106
--- /dev/null
+++ b/computepipe/sepolicy/public/service.te
@@ -0,0 +1,3 @@
+type computepipe_router_query_service, service_manager_type;
+type computepipe_router_registration_service, service_manager_type;
+type computepipe_router_service, service_manager_type;
diff --git a/computepipe/tests/Android.bp b/computepipe/tests/Android.bp
new file mode 100644
index 0000000..ec26177
--- /dev/null
+++ b/computepipe/tests/Android.bp
@@ -0,0 +1,61 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "piperegistration_test",
+    test_suites: ["device-tests"],
+    srcs: [
+        "PipeRegistrationTest.cpp",
+        "FakeRunner.cpp",
+    ],
+    static_libs: [
+        "libgtest",
+        "libgmock",
+    ],
+    header_libs: [
+        "computepipe_router_headers",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libbinder",
+        "libutils",
+        "android.automotive.computepipe.router@1.0-impl",
+        "android.automotive.computepipe.runner-ndk_platform",
+        "android.automotive.computepipe.registry-ndk_platform",
+    ],
+}
+
+cc_test {
+    name: "pipequery_test",
+    test_suites: ["device-tests"],
+    srcs: [
+        "PipeQueryTest.cpp",
+	"FakeRunner.cpp",
+    ],
+    static_libs: [
+        "libgtest",
+        "libgmock",
+    ],
+    header_libs: [
+      "computepipe_router_headers",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk",
+        "libutils",
+        "android.automotive.computepipe.router@1.0-impl",
+        "android.automotive.computepipe.runner-ndk_platform",
+        "android.automotive.computepipe.registry-ndk_platform",
+    ],
+}
diff --git a/computepipe/tests/FakeRunner.cpp b/computepipe/tests/FakeRunner.cpp
new file mode 100644
index 0000000..388b7ff
--- /dev/null
+++ b/computepipe/tests/FakeRunner.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "FakeRunner.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace tests {
+
+using namespace aidl::android::automotive::computepipe::runner;
+
+// Methods from ::android::automotive::computepipe::runner::V1_0::IFakeRunnerV1_0 follow.
+
+::ndk::ScopedAStatus FakeRunner::init(
+    const std::shared_ptr<
+        ::aidl::android::automotive::computepipe::runner::IPipeStateCallback>& /* in_statecb */) {
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus FakeRunner::getPipeDescriptor(
+    ::aidl::android::automotive::computepipe::runner::PipeDescriptor* desc) {
+    *desc = mDesc;
+    return ndk::ScopedAStatus::ok();
+}
+::ndk::ScopedAStatus FakeRunner::setPipeInputSource(int32_t /*in_configId*/) {
+    ::ndk::ScopedAStatus _aidl_status;
+    _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+    return _aidl_status;
+}
+::ndk::ScopedAStatus FakeRunner::setPipeOffloadOptions(int32_t /*in_configId*/) {
+    ::ndk::ScopedAStatus _aidl_status;
+    _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+    return _aidl_status;
+}
+::ndk::ScopedAStatus FakeRunner::setPipeTermination(int32_t /*in_configId*/) {
+    ::ndk::ScopedAStatus _aidl_status;
+    _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+    return _aidl_status;
+}
+
+::ndk::ScopedAStatus FakeRunner::setPipeOutputConfig(
+    int32_t /*in_configId*/, int32_t /*in_maxInFlightCount*/,
+    const std::shared_ptr<
+        ::aidl::android::automotive::computepipe::runner::IPipeStream>& /*in_handler*/) {
+    ::ndk::ScopedAStatus _aidl_status;
+    _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+    return _aidl_status;
+}
+::ndk::ScopedAStatus FakeRunner::applyPipeConfigs() {
+    ::ndk::ScopedAStatus _aidl_status;
+    _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+    return _aidl_status;
+}
+
+::ndk::ScopedAStatus FakeRunner::resetPipeConfigs() {
+    ::ndk::ScopedAStatus _aidl_status;
+    _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+    return _aidl_status;
+}
+
+::ndk::ScopedAStatus FakeRunner::startPipe() {
+    ::ndk::ScopedAStatus _aidl_status;
+    _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+    return _aidl_status;
+}
+::ndk::ScopedAStatus FakeRunner::stopPipe() {
+    ::ndk::ScopedAStatus _aidl_status;
+    _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+    return _aidl_status;
+}
+::ndk::ScopedAStatus FakeRunner::doneWithPacket(int32_t /*in_bufferId*/, int32_t /*in_streamId*/) {
+    ::ndk::ScopedAStatus _aidl_status;
+    _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+    return _aidl_status;
+}
+::ndk::ScopedAStatus FakeRunner::getPipeDebugger(
+    std::shared_ptr<::aidl::android::automotive::computepipe::runner::IPipeDebugger>* /*_aidl_return*/) {
+    ::ndk::ScopedAStatus _aidl_status;
+    _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+    return _aidl_status;
+}
+::ndk::ScopedAStatus FakeRunner::releaseRunner() {
+    ::ndk::ScopedAStatus _aidl_status;
+    _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+    return _aidl_status;
+}
+}  // namespace tests
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/tests/FakeRunner.h b/computepipe/tests/FakeRunner.h
new file mode 100644
index 0000000..d87d0c7
--- /dev/null
+++ b/computepipe/tests/FakeRunner.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_TESTS
+#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_TESTS
+
+#include <aidl/android/automotive/computepipe/runner/BnPipeRunner.h>
+#include <aidl/android/automotive/computepipe/runner/IPipeRunner.h>
+
+#include <memory>
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace tests {
+
+// TODO: Wrap under version flag
+
+// This is a fake runner class whose various methods can be mocked in order
+// to test the Runner logic.
+
+class FakeRunner : public aidl::android::automotive::computepipe::runner::BnPipeRunner {
+  public:
+    ::ndk::ScopedAStatus init(
+        const std::shared_ptr<::aidl::android::automotive::computepipe::runner::IPipeStateCallback>&
+            in_statecb) override;
+    ::ndk::ScopedAStatus getPipeDescriptor(
+        ::aidl::android::automotive::computepipe::runner::PipeDescriptor* _aidl_return) override;
+    ::ndk::ScopedAStatus setPipeInputSource(int32_t in_configId) override;
+    ::ndk::ScopedAStatus setPipeOffloadOptions(int32_t in_configId) override;
+    ::ndk::ScopedAStatus setPipeTermination(int32_t in_configId) override;
+    ::ndk::ScopedAStatus setPipeOutputConfig(
+        int32_t in_configId, int32_t in_maxInFlightCount,
+        const std::shared_ptr<::aidl::android::automotive::computepipe::runner::IPipeStream>&
+            in_handler) override;
+    ::ndk::ScopedAStatus applyPipeConfigs() override;
+    ::ndk::ScopedAStatus resetPipeConfigs() override;
+    ::ndk::ScopedAStatus startPipe() override;
+    ::ndk::ScopedAStatus stopPipe() override;
+    ::ndk::ScopedAStatus doneWithPacket(int32_t in_bufferId, int32_t in_streamId) override;
+    ::ndk::ScopedAStatus getPipeDebugger(
+        std::shared_ptr<::aidl::android::automotive::computepipe::runner::IPipeDebugger>*
+            _aidl_return) override;
+    ::ndk::ScopedAStatus releaseRunner() override;
+    ~FakeRunner() {
+        mOutputCallbacks.clear();
+    }
+
+  private:
+    aidl::android::automotive::computepipe::runner::PipeDescriptor mDesc;
+    std::vector<std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeStream>>
+        mOutputCallbacks;
+    std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeStateCallback> mStateCallback;
+};
+
+}  // namespace tests
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+#endif
diff --git a/computepipe/tests/PipeQueryTest.cpp b/computepipe/tests/PipeQueryTest.cpp
new file mode 100644
index 0000000..634ebd0
--- /dev/null
+++ b/computepipe/tests/PipeQueryTest.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/automotive/computepipe/registry/BnClientInfo.h>
+#include <binder/IInterface.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <list>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "FakeRunner.h"
+#include "PipeClient.h"
+#include "PipeQuery.h"
+#include "PipeRunner.h"
+
+using namespace android::automotive::computepipe::router;
+using namespace android::automotive::computepipe::router::V1_0::implementation;
+using namespace android::automotive::computepipe::tests;
+using namespace aidl::android::automotive::computepipe::runner;
+using namespace aidl::android::automotive::computepipe::registry;
+using namespace ::testing;
+
+/**
+ * Fakeclass to instantiate client info for query purposes
+ */
+class FakeClientInfo : public BnClientInfo {
+  public:
+    ndk::ScopedAStatus getClientName(std::string* name) override {
+        *name = "FakeClient";
+        return ndk::ScopedAStatus::ok();
+    }
+};
+
+/**
+ * Class that exposes protected interfaces of PipeRegistry
+ * a) Used to retrieve entries without client ref counts
+ * b) Used to remove entries
+ */
+class FakeRegistry : public PipeRegistry<PipeRunner> {
+  public:
+    std ::unique_ptr<PipeHandle<PipeRunner>> getDebuggerPipeHandle(const std::string& name) {
+        return getPipeHandle(name, nullptr);
+    }
+    Error RemoveEntry(const std::string& name) {
+        return DeletePipeHandle(name);
+    }
+};
+
+/**
+ * Test Fixture class that is responsible for maintaining a registry.
+ * The registry object is used to test the query interfaces
+ */
+class PipeQueryTest : public ::testing::Test {
+  protected:
+    /**
+     * Setup for the test fixture to initialize a registry to be used in all
+     * tests
+     */
+    void SetUp() override {
+        mRegistry = std::make_shared<FakeRegistry>();
+    }
+    /**
+     * Utility to generate fake runners
+     */
+    void addFakeRunner(const std::string& name, const std::shared_ptr<IPipeRunner>& runnerIface) {
+        std::unique_ptr<PipeHandle<PipeRunner>> handle = std::make_unique<RunnerHandle>(runnerIface);
+        Error status = mRegistry->RegisterPipe(std::move(handle), name);
+        ASSERT_THAT(status, testing::Eq(Error::OK));
+    }
+    /**
+     * Utility to remove runners from the registry
+     */
+    void removeRunner(const std::string& name) {
+        ASSERT_THAT(mRegistry->RemoveEntry(name), testing::Eq(Error::OK));
+    }
+    /**
+     * Tear down to cleanup registry resources
+     */
+    void TearDown() override {
+        mRegistry = nullptr;
+    }
+    std::shared_ptr<FakeRegistry> mRegistry;
+};
+
+// Check retrieval of inserted entries
+TEST_F(PipeQueryTest, GetGraphListTest) {
+    std::shared_ptr<IPipeRunner> dummy1 = ndk::SharedRefBase::make<FakeRunner>();
+    addFakeRunner("dummy1", dummy1);
+    std::shared_ptr<IPipeRunner> dummy2 = ndk::SharedRefBase::make<FakeRunner>();
+    addFakeRunner("dummy2", dummy2);
+
+    std::vector<std::string>* outNames = new std::vector<std::string>();
+    std::shared_ptr<PipeQuery> qIface = ndk::SharedRefBase::make<PipeQuery>(mRegistry);
+    ASSERT_TRUE(qIface->getGraphList(outNames).isOk());
+
+    ASSERT_NE(outNames->size(), 0);
+    EXPECT_THAT(std::find(outNames->begin(), outNames->end(), "dummy1"),
+                testing::Ne(outNames->end()));
+    EXPECT_THAT(std::find(outNames->begin(), outNames->end(), "dummy2"),
+                testing::Ne(outNames->end()));
+}
+
+// Check successful retrieval of runner
+TEST_F(PipeQueryTest, GetRunnerTest) {
+    std::shared_ptr<IPipeRunner> dummy1 = ndk::SharedRefBase::make<FakeRunner>();
+    addFakeRunner("dummy1", dummy1);
+
+    std::shared_ptr<PipeQuery> qIface = ndk::SharedRefBase::make<PipeQuery>(mRegistry);
+    std::shared_ptr<IClientInfo> info = ndk::SharedRefBase::make<FakeClientInfo>();
+    std::shared_ptr<IPipeRunner> runner;
+    ASSERT_TRUE(qIface->getPipeRunner("dummy1", info, &runner).isOk());
+    EXPECT_THAT(runner, testing::NotNull());
+}
diff --git a/computepipe/tests/PipeRegistrationTest.cpp b/computepipe/tests/PipeRegistrationTest.cpp
new file mode 100644
index 0000000..1caf07b
--- /dev/null
+++ b/computepipe/tests/PipeRegistrationTest.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+
+#include <list>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "FakeRunner.h"
+#include "PipeRegistration.h"
+#include "PipeRunner.h"
+
+using namespace android::automotive::computepipe::router;
+using namespace android::automotive::computepipe::router::V1_0::implementation;
+using namespace android::automotive::computepipe::tests;
+using namespace aidl::android::automotive::computepipe::runner;
+using namespace aidl::android::automotive::computepipe::registry;
+/**
+ * Test fixture that manages the underlying registry creation and tear down
+ */
+class PipeRegistrationTest : public ::testing::Test {
+  protected:
+    void SetUp() override {
+        mRegistry = std::make_shared<PipeRegistry<PipeRunner>>();
+        ASSERT_THAT(mRegistry, testing::NotNull());
+    }
+
+    void TearDown() override {
+        mRegistry = nullptr;
+    }
+    std::shared_ptr<PipeRegistry<PipeRunner>> mRegistry;
+};
+
+// Valid registration succeeds
+TEST_F(PipeRegistrationTest, RegisterFakeRunner) {
+    std::shared_ptr<IPipeRunner> dummy = ndk::SharedRefBase::make<FakeRunner>();
+    std::shared_ptr<IPipeRegistration> rIface =
+        ndk::SharedRefBase::make<PipeRegistration>(this->mRegistry);
+    EXPECT_TRUE(rIface->registerPipeRunner("dummy", dummy).isOk());
+}
+
+// Duplicate registration fails
+TEST_F(PipeRegistrationTest, RegisterDuplicateRunner) {
+    std::shared_ptr<IPipeRunner> dummy = ndk::SharedRefBase::make<FakeRunner>();
+    std::shared_ptr<IPipeRegistration> rIface =
+        ndk::SharedRefBase::make<PipeRegistration>(this->mRegistry);
+    ASSERT_TRUE(rIface->registerPipeRunner("dummy", dummy).isOk());
+    EXPECT_FALSE(rIface->registerPipeRunner("dummy", dummy).isOk());
+}
diff --git a/computepipe/tests/runner/client_interface/Android.bp b/computepipe/tests/runner/client_interface/Android.bp
new file mode 100644
index 0000000..2ff5d2c
--- /dev/null
+++ b/computepipe/tests/runner/client_interface/Android.bp
@@ -0,0 +1,43 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "clientinterface_test",
+    test_suites: ["device-tests"],
+    srcs: [
+        "ClientInterfaceTest.cc",
+	"PipeOptionsConverterTest.cpp",
+    ],
+    static_libs: [
+        "libgtest",
+        "libgmock",
+        "libcomputepipeprotos",
+    ],
+    header_libs: [
+        "computepipe_router_headers",
+        "computepipe_runner_includes",
+    ],
+    include_dirs: ["packages/services/Car/computepipe"],
+    shared_libs: [
+        "libbinder_ndk",
+        "libutils",
+	"libnativewindow",
+        "computepipe_client_interface",
+        "computepipe_runner_component",
+        "android.automotive.computepipe.registry-ndk_platform",
+        "android.automotive.computepipe.runner-ndk_platform",
+        "android.automotive.computepipe.runner-ndk_platform",
+        "libprotobuf-cpp-lite",
+    ],
+}
diff --git a/computepipe/tests/runner/client_interface/ClientInterfaceTest.cc b/computepipe/tests/runner/client_interface/ClientInterfaceTest.cc
new file mode 100644
index 0000000..524b6a6
--- /dev/null
+++ b/computepipe/tests/runner/client_interface/ClientInterfaceTest.cc
@@ -0,0 +1,406 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <aidl/android/automotive/computepipe/registry/BnClientInfo.h>
+#include <aidl/android/automotive/computepipe/registry/IPipeQuery.h>
+#include <aidl/android/automotive/computepipe/registry/IPipeRegistration.h>
+#include <aidl/android/automotive/computepipe/runner/BnPipeStateCallback.h>
+#include <aidl/android/automotive/computepipe/runner/BnPipeStream.h>
+#include <aidl/android/automotive/computepipe/runner/PipeState.h>
+#include <android/binder_manager.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utility>
+#include <vector>
+
+#include "ConfigurationCommand.pb.h"
+#include "ControlCommand.pb.h"
+#include "MemHandle.h"
+#include "MockEngine.h"
+#include "MockMemHandle.h"
+#include "MockRunnerEvent.h"
+#include "Options.pb.h"
+#include "ProfilingType.pb.h"
+#include "runner/client_interface/AidlClient.h"
+#include "runner/client_interface/include/ClientEngineInterface.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace client_interface {
+namespace aidl_client {
+namespace {
+
+using ::aidl::android::automotive::computepipe::registry::BnClientInfo;
+using ::aidl::android::automotive::computepipe::registry::IPipeQuery;
+using ::aidl::android::automotive::computepipe::runner::BnPipeStateCallback;
+using ::aidl::android::automotive::computepipe::runner::BnPipeStream;
+using ::aidl::android::automotive::computepipe::runner::IPipeRunner;
+using ::aidl::android::automotive::computepipe::runner::IPipeStateCallback;
+using ::aidl::android::automotive::computepipe::runner::PacketDescriptor;
+using ::aidl::android::automotive::computepipe::runner::PipeState;
+using ::android::automotive::computepipe::runner::tests::MockRunnerEvent;
+using ::android::automotive::computepipe::tests::MockMemHandle;
+using ::ndk::ScopedAStatus;
+using ::ndk::SharedRefBase;
+using ::testing::_;
+using ::testing::AnyNumber;
+using ::testing::AtLeast;
+using ::testing::DoAll;
+using ::testing::Return;
+using ::testing::SaveArg;
+
+const char kRegistryInterfaceName[] = "router";
+int testIx = 0;
+
+class StateChangeCallback : public BnPipeStateCallback {
+  public:
+    ScopedAStatus handleState(PipeState state) {
+        mState = state;
+        return ScopedAStatus::ok();
+    }
+    PipeState mState = PipeState::RESET;
+};
+
+class StreamCallback : public BnPipeStream {
+  public:
+    ScopedAStatus deliverPacket(const PacketDescriptor& in_packet) override {
+        data = std::string(in_packet.data.begin(), in_packet.data.end());
+        timestamp = in_packet.sourceTimeStampMillis;
+        return ScopedAStatus::ok();
+    }
+    std::string data;
+    uint64_t timestamp;
+};
+
+class ClientInfo : public BnClientInfo {
+  public:
+    ScopedAStatus getClientName(std::string* _aidl_return) {
+        if (_aidl_return) {
+            *_aidl_return = "ClientInfo";
+            return ScopedAStatus::ok();
+        }
+        return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+    }
+};
+
+class ClientInterface : public ::testing::Test {
+  protected:
+    void SetUp() override {
+        const std::string graphName = "graph " + std::to_string(++testIx);
+        proto::Options options;
+        options.set_graph_name(graphName);
+        mAidlClient = std::make_unique<AidlClient>(options, mEngine);
+
+        // Register the instance with router.
+        EXPECT_EQ(mAidlClient->activate(), Status::SUCCESS);
+
+        // Init is not a blocking call, so sleep for 3 seconds to allow the runner to register with
+        // router.
+        sleep(3);
+
+        // Retrieve router query instance from service manager.
+        std::string instanceName =
+            std::string() + IPipeQuery::descriptor + "/" + kRegistryInterfaceName;
+        ndk::SpAIBinder binder(AServiceManager_getService(instanceName.c_str()));
+        ASSERT_TRUE(binder.get() != nullptr);
+        std::shared_ptr<IPipeQuery> queryService = IPipeQuery::fromBinder(binder);
+
+        // Retrieve pipe runner instance from the router.
+        std::shared_ptr<ClientInfo> clientInfo = ndk::SharedRefBase::make<ClientInfo>();
+        ASSERT_TRUE(queryService->getPipeRunner(graphName, clientInfo, &mPipeRunner).isOk());
+    }
+
+    std::shared_ptr<tests::MockEngine> mEngine = std::make_unique<tests::MockEngine>();
+    std::shared_ptr<AidlClient> mAidlClient = nullptr;
+    std::shared_ptr<IPipeRunner> mPipeRunner = nullptr;
+};
+
+TEST_F(ClientInterface, TestSetConfiguration) {
+    proto::ConfigurationCommand command;
+
+    // Configure runner to return success.
+    EXPECT_CALL(*mEngine, processClientConfigUpdate(_))
+        .Times(AtLeast(4))
+        .WillRepeatedly(DoAll(SaveArg<0>(&command), Return(Status::SUCCESS)));
+
+    // Initialize pipe runner.
+    std::shared_ptr<StateChangeCallback> stateCallback =
+        ndk::SharedRefBase::make<StateChangeCallback>();
+    EXPECT_TRUE(mPipeRunner->init(stateCallback).isOk());
+
+    // Test that set input source returns ok status.
+    EXPECT_TRUE(mPipeRunner->setPipeInputSource(1).isOk());
+    EXPECT_EQ(command.has_set_input_source(), true);
+    EXPECT_EQ(command.set_input_source().source_id(), 1);
+
+    // Test that set offload option returns ok status.
+    EXPECT_TRUE(mPipeRunner->setPipeOffloadOptions(5).isOk());
+    EXPECT_EQ(command.has_set_offload_offload(), true);
+    EXPECT_EQ(command.set_offload_offload().offload_option_id(), 5);
+
+    // Test that set termination option returns ok status.
+    EXPECT_TRUE(mPipeRunner->setPipeTermination(3).isOk());
+    EXPECT_EQ(command.has_set_termination_option(), true);
+    EXPECT_EQ(command.set_termination_option().termination_option_id(), 3);
+
+    // Test that set output callback returns ok status.
+    std::shared_ptr<StreamCallback> streamCb = ndk::SharedRefBase::make<StreamCallback>();
+    EXPECT_TRUE(mPipeRunner->setPipeOutputConfig(0, 10, streamCb).isOk());
+    EXPECT_EQ(command.has_set_output_stream(), true);
+    EXPECT_EQ(command.set_output_stream().stream_id(), 0);
+    EXPECT_EQ(command.set_output_stream().max_inflight_packets_count(), 10);
+
+    // Release runner here. This should remove registry entry from router registry.
+    mAidlClient.reset();
+}
+
+TEST_F(ClientInterface, TestSetConfigurationError) {
+    proto::ConfigurationCommand command;
+
+    // Configure runner to return error.
+    EXPECT_CALL(*mEngine, processClientConfigUpdate(_))
+        .Times(AtLeast(4))
+        .WillRepeatedly(DoAll(SaveArg<0>(&command), Return(Status::INTERNAL_ERROR)));
+
+    ScopedAStatus status;
+
+    // Initialize pipe runner.
+    std::shared_ptr<StateChangeCallback> stateCallback =
+        ndk::SharedRefBase::make<StateChangeCallback>();
+    EXPECT_TRUE(mPipeRunner->init(stateCallback).isOk());
+
+    // Test that set input source returns error status.
+    status = mPipeRunner->setPipeInputSource(1);
+    EXPECT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
+    EXPECT_EQ(command.has_set_input_source(), true);
+    EXPECT_EQ(command.set_input_source().source_id(), 1);
+
+    // Test that set offload option returns error status.
+    status = mPipeRunner->setPipeOffloadOptions(5);
+    EXPECT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
+    EXPECT_EQ(command.has_set_offload_offload(), true);
+    EXPECT_EQ(command.set_offload_offload().offload_option_id(), 5);
+
+    // Test that set termination option returns error status.
+    status = mPipeRunner->setPipeTermination(3);
+    EXPECT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
+    EXPECT_EQ(command.has_set_termination_option(), true);
+    EXPECT_EQ(command.set_termination_option().termination_option_id(), 3);
+
+    // Test that set output callback returns error status.
+    std::shared_ptr<StreamCallback> streamCb = ndk::SharedRefBase::make<StreamCallback>();
+    status = mPipeRunner->setPipeOutputConfig(0, 10, streamCb);
+    EXPECT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
+    EXPECT_EQ(command.has_set_output_stream(), true);
+    EXPECT_EQ(command.set_output_stream().stream_id(), 0);
+    EXPECT_EQ(command.set_output_stream().max_inflight_packets_count(), 10);
+
+    // Release runner here. This should remove registry entry from router registry.
+    mAidlClient.reset();
+}
+
+TEST_F(ClientInterface, TestControlCommands) {
+    proto::ControlCommand command;
+    // Configure runner to return success.
+    EXPECT_CALL(*mEngine, processClientCommand(_))
+        .Times(AtLeast(4))
+        .WillRepeatedly(DoAll(SaveArg<0>(&command), Return(Status::SUCCESS)));
+
+    // Initialize pipe runner.
+    std::shared_ptr<StateChangeCallback> stateCallback =
+        ndk::SharedRefBase::make<StateChangeCallback>();
+    EXPECT_TRUE(mPipeRunner->init(stateCallback).isOk());
+
+    // Test that apply-configs api returns ok status.
+    EXPECT_TRUE(mPipeRunner->applyPipeConfigs().isOk());
+    EXPECT_EQ(command.has_apply_configs(), true);
+
+    // Test that set stop graph api returns ok status.
+    EXPECT_TRUE(mPipeRunner->resetPipeConfigs().isOk());
+    EXPECT_EQ(command.has_reset_configs(), true);
+
+    // Test that set start graph api returns ok status.
+    EXPECT_TRUE(mPipeRunner->startPipe().isOk());
+    EXPECT_EQ(command.has_start_graph(), true);
+
+    // Test that set stop graph api returns ok status.
+    EXPECT_TRUE(mPipeRunner->stopPipe().isOk());
+    EXPECT_EQ(command.has_stop_graph(), true);
+
+    // Release runner here. This should remove registry entry from router registry.
+    mAidlClient.reset();
+}
+
+TEST_F(ClientInterface, TestControlCommandsFailure) {
+    proto::ControlCommand command;
+
+    // Configure runner to return success.
+    EXPECT_CALL(*mEngine, processClientCommand(_))
+        .Times(AtLeast(4))
+        .WillRepeatedly(DoAll(SaveArg<0>(&command), Return(Status::INTERNAL_ERROR)));
+    ScopedAStatus status;
+
+    // Initialize pipe runner.
+    std::shared_ptr<StateChangeCallback> stateCallback =
+        ndk::SharedRefBase::make<StateChangeCallback>();
+    EXPECT_TRUE(mPipeRunner->init(stateCallback).isOk());
+
+    // Test that apply-configs api returns error status.
+    status = mPipeRunner->applyPipeConfigs();
+    EXPECT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
+    EXPECT_EQ(command.has_apply_configs(), true);
+
+    status = mPipeRunner->resetPipeConfigs();
+    EXPECT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
+    EXPECT_EQ(command.has_reset_configs(), true);
+
+    // Test that start graph api returns error status.
+    status = mPipeRunner->startPipe();
+    EXPECT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
+    EXPECT_EQ(command.has_start_graph(), true);
+
+    // Test that stop graph api returns error status.
+    status = mPipeRunner->stopPipe();
+    EXPECT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
+    EXPECT_EQ(command.has_stop_graph(), true);
+
+    // Release runner here. This should remove registry entry from router registry.
+    mAidlClient.reset();
+}
+
+TEST_F(ClientInterface, TestFailureWithoutInit) {
+    EXPECT_CALL(*mEngine, processClientConfigUpdate(_)).Times(0);
+    EXPECT_CALL(*mEngine, processClientCommand(_)).Times(0);
+
+    // Pipe runner is not initalized here, test that a configuration command returns error status.
+    ScopedAStatus status;
+    status = mPipeRunner->setPipeInputSource(1);
+    EXPECT_EQ(status.getExceptionCode(), EX_ILLEGAL_STATE);
+
+    // Test that a control command returns error status.
+    status = mPipeRunner->applyPipeConfigs();
+    EXPECT_EQ(status.getExceptionCode(), EX_ILLEGAL_STATE);
+}
+
+TEST_F(ClientInterface, TestStateChangeNotification) {
+    EXPECT_CALL(*mEngine, processClientConfigUpdate(_)).Times(0);
+    EXPECT_CALL(*mEngine, processClientCommand(_)).Times(0);
+
+    // Initialize pipe runner.
+    std::shared_ptr<StateChangeCallback> stateCallback =
+        ndk::SharedRefBase::make<StateChangeCallback>();
+    EXPECT_TRUE(mPipeRunner->init(stateCallback).isOk());
+
+    // Test that config complete status is conveyed to client.
+    std::map<int, int> m;
+    ClientConfig config(0, 0, 0, m, proto::ProfilingType::DISABLED);
+    config.setPhaseState(TRANSITION_COMPLETE);
+    EXPECT_EQ(mAidlClient->handleConfigPhase(config), Status::SUCCESS);
+    EXPECT_EQ(stateCallback->mState, PipeState::CONFIG_DONE);
+
+    MockRunnerEvent event;
+    EXPECT_CALL(event, isTransitionComplete()).Times(AnyNumber()).WillRepeatedly(Return(true));
+    EXPECT_CALL(event, isPhaseEntry()).Times(AnyNumber()).WillRepeatedly(Return(false));
+
+    // Test that reset status is conveyed to client.
+    EXPECT_EQ(mAidlClient->handleResetPhase(event), Status::SUCCESS);
+    EXPECT_EQ(stateCallback->mState, PipeState::RESET);
+
+    // Test that execution start status is conveyed to client.
+    EXPECT_EQ(mAidlClient->handleExecutionPhase(event), Status::SUCCESS);
+    EXPECT_EQ(stateCallback->mState, PipeState::RUNNING);
+
+    // Test that execution complete status is conveyed to client.
+    EXPECT_EQ(mAidlClient->handleStopWithFlushPhase(event), Status::SUCCESS);
+    EXPECT_EQ(stateCallback->mState, PipeState::DONE);
+
+    // Test that execution error status is conveyed to client.
+    EXPECT_EQ(mAidlClient->handleStopImmediatePhase(event), Status::SUCCESS);
+    EXPECT_EQ(stateCallback->mState, PipeState::ERR_HALT);
+}
+
+TEST_F(ClientInterface, TestStateChangeToError) {
+    EXPECT_CALL(*mEngine, processClientConfigUpdate(_)).Times(0);
+    EXPECT_CALL(*mEngine, processClientCommand(_)).Times(0);
+
+    // Initialize pipe runner.
+    std::shared_ptr<StateChangeCallback> stateCallback =
+        ndk::SharedRefBase::make<StateChangeCallback>();
+    EXPECT_TRUE(mPipeRunner->init(stateCallback).isOk());
+
+    // Test that error while applying config is conveyed to client.
+    std::map<int, int> m;
+    ClientConfig config(0, 0, 0, m, proto::ProfilingType::DISABLED);
+    config.setPhaseState(ABORTED);
+    EXPECT_EQ(mAidlClient->handleConfigPhase(config), Status::SUCCESS);
+    EXPECT_EQ(stateCallback->mState, PipeState::ERR_HALT);
+
+    MockRunnerEvent event;
+    EXPECT_CALL(event, isTransitionComplete()).Times(AnyNumber()).WillRepeatedly(Return(false));
+    EXPECT_CALL(event, isPhaseEntry()).Times(AnyNumber()).WillRepeatedly(Return(false));
+    EXPECT_CALL(event, isAborted()).Times(AnyNumber()).WillRepeatedly(Return(true));
+
+    // Test that error while starting pipe execution is conveyed to client.
+    EXPECT_EQ(mAidlClient->handleExecutionPhase(event), Status::SUCCESS);
+    EXPECT_EQ(stateCallback->mState, PipeState::ERR_HALT);
+}
+
+TEST_F(ClientInterface, TestPacketDelivery) {
+    proto::ConfigurationCommand command;
+
+    // Configure runner to return success.
+    EXPECT_CALL(*mEngine, processClientConfigUpdate(_))
+        .Times(1)
+        .WillOnce(DoAll(SaveArg<0>(&command), Return(Status::SUCCESS)));
+
+    // Initialize pipe runner.
+    std::shared_ptr<StateChangeCallback> stateCallback =
+        ndk::SharedRefBase::make<StateChangeCallback>();
+    EXPECT_TRUE(mPipeRunner->init(stateCallback).isOk());
+
+    // Set callback for stream id 0.
+    std::shared_ptr<StreamCallback> streamCb = ndk::SharedRefBase::make<StreamCallback>();
+    EXPECT_TRUE(mPipeRunner->setPipeOutputConfig(0, 10, streamCb).isOk());
+    EXPECT_EQ(command.has_set_output_stream(), true);
+    EXPECT_EQ(command.set_output_stream().stream_id(), 0);
+    EXPECT_EQ(command.set_output_stream().max_inflight_packets_count(), 10);
+
+    // Send a packet to client and verify the packet.
+    std::shared_ptr<MockMemHandle> packet = std::make_unique<MockMemHandle>();
+    uint64_t timestamp = 100;
+    const std::string testData = "Test String.";
+    EXPECT_CALL(*packet, getType())
+        .Times(AtLeast(1))
+        .WillRepeatedly(Return(proto::PacketType::SEMANTIC_DATA));
+    EXPECT_CALL(*packet, getTimeStamp()).Times(AtLeast(1)).WillRepeatedly(Return(timestamp));
+    EXPECT_CALL(*packet, getSize()).Times(AtLeast(1)).WillRepeatedly(Return(testData.size()));
+    EXPECT_CALL(*packet, getData()).Times(AtLeast(1)).WillRepeatedly(Return(testData.c_str()));
+    EXPECT_EQ(
+        mAidlClient->dispatchPacketToClient(0, static_cast<std::shared_ptr<MemHandle>>(packet)),
+        Status::SUCCESS);
+    EXPECT_EQ(streamCb->data, packet->getData());
+    EXPECT_EQ(streamCb->timestamp, packet->getTimeStamp());
+}
+
+}  // namespace
+}  // namespace aidl_client
+}  // namespace client_interface
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/tests/runner/client_interface/MockEngine.h b/computepipe/tests/runner/client_interface/MockEngine.h
new file mode 100644
index 0000000..07b3484
--- /dev/null
+++ b/computepipe/tests/runner/client_interface/MockEngine.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COMPUTEPIPE_TESTS_RUNNER_CLIENTINTERFACE_MOCKENGINE_H
+#define COMPUTEPIPE_TESTS_RUNNER_CLIENTINTERFACE_MOCKENGINE_H
+
+#include <gmock/gmock.h>
+
+#include "runner/client_interface/include/ClientEngineInterface.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace client_interface {
+namespace tests {
+
+class MockEngine : public ClientEngineInterface {
+  public:
+    MOCK_METHOD1(processClientConfigUpdate, Status(const proto::ConfigurationCommand&));
+    MOCK_METHOD1(processClientCommand, Status(const proto::ControlCommand&));
+    MOCK_METHOD2(freePacket, Status(int bufferId, int streamId));
+};
+
+}  // namespace tests
+}  // namespace client_interface
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // COMPUTEPIPE_TESTS_RUNNER_CLIENTINTERFACE_MOCKENGINE_H
diff --git a/computepipe/tests/runner/client_interface/MockMemHandle.h b/computepipe/tests/runner/client_interface/MockMemHandle.h
new file mode 100644
index 0000000..919cbde
--- /dev/null
+++ b/computepipe/tests/runner/client_interface/MockMemHandle.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COMPUTEPIPE_TESTS_RUNNER_CLIENTINTERFACE_MOCKMEMHANDLE_H
+#define COMPUTEPIPE_TESTS_RUNNER_CLIENTINTERFACE_MOCKMEMHANDLE_H
+
+#include <gmock/gmock.h>
+
+#include "MemHandle.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace tests {
+
+class MockMemHandle : public MemHandle {
+  public:
+    MOCK_CONST_METHOD0(getStreamId, int());
+    MOCK_CONST_METHOD0(getBufferId, int());
+    MOCK_CONST_METHOD0(getType, proto::PacketType());
+    MOCK_CONST_METHOD0(getTimeStamp, uint64_t());
+    MOCK_CONST_METHOD0(getSize, uint32_t());
+    MOCK_CONST_METHOD0(getData, const char*());
+    MOCK_CONST_METHOD0(getHardwareBuffer, AHardwareBuffer*());
+};
+
+}  // namespace tests
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // COMPUTEPIPE_TESTS_RUNNER_CLIENTINTERFACE_MOCKMEMHANDLE_H
diff --git a/computepipe/tests/runner/client_interface/MockRunnerEvent.h b/computepipe/tests/runner/client_interface/MockRunnerEvent.h
new file mode 100644
index 0000000..d6f9039
--- /dev/null
+++ b/computepipe/tests/runner/client_interface/MockRunnerEvent.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COMPUTEPIPE_TESTS_RUNNER_CLIENTINTERFACE_MOCKRUNNEREVENT_H
+#define COMPUTEPIPE_TESTS_RUNNER_CLIENTINTERFACE_MOCKRUNNEREVENT_H
+
+#include <gmock/gmock.h>
+
+#include "RunnerComponent.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace tests {
+
+class MockRunnerEvent : public RunnerEvent {
+  public:
+    MOCK_CONST_METHOD0(isPhaseEntry, bool());
+    MOCK_CONST_METHOD0(isTransitionComplete, bool());
+    MOCK_CONST_METHOD0(isAborted, bool());
+    MOCK_METHOD1(
+        dispatchToComponent, Status(const std::shared_ptr<RunnerComponentInterface>& iface));
+};
+
+}  // namespace tests
+}  // namespce runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // COMPUTEPIPE_TESTS_RUNNER_CLIENTINTERFACE_MOCKRUNNEREVENT_H
diff --git a/computepipe/tests/runner/client_interface/PipeOptionsConverterTest.cpp b/computepipe/tests/runner/client_interface/PipeOptionsConverterTest.cpp
new file mode 100644
index 0000000..5a45dd4
--- /dev/null
+++ b/computepipe/tests/runner/client_interface/PipeOptionsConverterTest.cpp
@@ -0,0 +1,184 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include <string>
+
+#include "InputConfig.pb.h"
+#include "Options.pb.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "runner/client_interface/PipeOptionsConverter.h"
+#include "types/Status.h"
+
+using ::aidl::android::automotive::computepipe::runner::PipeDescriptor;
+using ::aidl::android::automotive::computepipe::runner::PipeInputConfigCameraType;
+using ::aidl::android::automotive::computepipe::runner::PipeInputConfigFormatType;
+using ::aidl::android::automotive::computepipe::runner::PipeInputConfigImageFileType;
+using ::aidl::android::automotive::computepipe::runner::PipeInputConfigInputType;
+using ::aidl::android::automotive::computepipe::runner::PipeInputConfigVideoFileType;
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace client_interface {
+namespace aidl_client {
+namespace {
+
+TEST(OptionsToPipeDescriptorTest, InputTypesConvertAsExpected) {
+    proto::Options options;
+
+    // Add a driver view camera type
+    options.add_input_configs()->add_input_stream()->set_type(
+        proto::InputStreamConfig_InputType_CAMERA);
+    options.mutable_input_configs(0)->mutable_input_stream(0)->mutable_cam_config()->set_camera_type(
+        proto::CameraConfig_CameraType_DRIVER_VIEW_CAMERA);
+    options.mutable_input_configs(0)->set_config_id(0);
+
+    // Add an occupant view camera type
+    options.add_input_configs()->add_input_stream()->set_type(
+        proto::InputStreamConfig_InputType_CAMERA);
+    options.mutable_input_configs(1)->mutable_input_stream(0)->mutable_cam_config()->set_camera_type(
+        proto::CameraConfig_CameraType_OCCUPANT_VIEW_CAMERA);
+    options.mutable_input_configs(1)->set_config_id(1);
+
+    // Add external camera type
+    options.add_input_configs()->add_input_stream()->set_type(
+        proto::InputStreamConfig_InputType_CAMERA);
+    options.mutable_input_configs(2)->mutable_input_stream(0)->mutable_cam_config()->set_camera_type(
+        proto::CameraConfig_CameraType_EXTERNAL_CAMERA);
+    options.mutable_input_configs(2)->set_config_id(2);
+
+    // Add surround camera type
+    options.add_input_configs()->add_input_stream()->set_type(
+        proto::InputStreamConfig_InputType_CAMERA);
+    options.mutable_input_configs(3)->mutable_input_stream(0)->mutable_cam_config()->set_camera_type(
+        proto::CameraConfig_CameraType_SURROUND_VIEW_CAMERA);
+    options.mutable_input_configs(3)->set_config_id(3);
+
+    // Add image file type
+    options.add_input_configs()->add_input_stream()->set_type(
+        proto::InputStreamConfig_InputType_IMAGE_FILES);
+    options.mutable_input_configs(4)->mutable_input_stream(0)->mutable_image_config()->set_file_type(
+        proto::ImageFileConfig_ImageFileType_PNG);
+    options.mutable_input_configs(4)->set_config_id(4);
+
+    // Add video file type
+    options.add_input_configs()->add_input_stream()->set_type(
+        proto::InputStreamConfig_InputType_VIDEO_FILE);
+    options.mutable_input_configs(5)->mutable_input_stream(0)->mutable_video_config()->set_file_type(
+        proto::VideoFileConfig_VideoFileType_MPEG);
+    options.mutable_input_configs(5)->set_config_id(5);
+
+    PipeDescriptor desc = OptionsToPipeDescriptor(options);
+
+    ASSERT_EQ(desc.inputConfig.size(), 6);
+    ASSERT_EQ(desc.inputConfig[0].inputSources.size(), 1);
+    EXPECT_EQ(desc.inputConfig[0].inputSources[0].type, PipeInputConfigInputType::CAMERA);
+    EXPECT_EQ(desc.inputConfig[0].inputSources[0].camDesc.type,
+              PipeInputConfigCameraType::DRIVER_VIEW_CAMERA);
+    EXPECT_EQ(desc.inputConfig[0].configId, 0);
+
+    ASSERT_EQ(desc.inputConfig[1].inputSources.size(), 1);
+    EXPECT_EQ(desc.inputConfig[1].inputSources[0].type, PipeInputConfigInputType::CAMERA);
+    EXPECT_EQ(desc.inputConfig[1].inputSources[0].camDesc.type,
+              PipeInputConfigCameraType::OCCUPANT_VIEW_CAMERA);
+    EXPECT_EQ(desc.inputConfig[1].configId, 1);
+
+    ASSERT_EQ(desc.inputConfig[2].inputSources.size(), 1);
+    EXPECT_EQ(desc.inputConfig[2].inputSources[0].type, PipeInputConfigInputType::CAMERA);
+    EXPECT_EQ(desc.inputConfig[2].inputSources[0].camDesc.type,
+              PipeInputConfigCameraType::EXTERNAL_CAMERA);
+    EXPECT_EQ(desc.inputConfig[2].configId, 2);
+
+    ASSERT_EQ(desc.inputConfig[3].inputSources.size(), 1);
+    EXPECT_EQ(desc.inputConfig[3].inputSources[0].type, PipeInputConfigInputType::CAMERA);
+    EXPECT_EQ(desc.inputConfig[3].inputSources[0].camDesc.type,
+              PipeInputConfigCameraType::SURROUND_VIEW_CAMERA);
+    EXPECT_EQ(desc.inputConfig[3].configId, 3);
+
+    ASSERT_EQ(desc.inputConfig[4].inputSources.size(), 1);
+    EXPECT_EQ(desc.inputConfig[4].inputSources[0].type, PipeInputConfigInputType::IMAGE_FILES);
+    EXPECT_EQ(desc.inputConfig[4].inputSources[0].imageDesc.fileType,
+              PipeInputConfigImageFileType::PNG);
+    EXPECT_EQ(desc.inputConfig[4].configId, 4);
+
+    ASSERT_EQ(desc.inputConfig[5].inputSources.size(), 1);
+    EXPECT_EQ(desc.inputConfig[5].inputSources[0].type, PipeInputConfigInputType::VIDEO_FILE);
+    EXPECT_EQ(desc.inputConfig[5].inputSources[0].videoDesc.fileType,
+              PipeInputConfigVideoFileType::MPEG);
+    EXPECT_EQ(desc.inputConfig[5].configId, 5);
+}
+
+TEST(OptionsToPipeDescriptorTest, FormatTypesConvertAsExpected) {
+    proto::Options options;
+
+    // Add an RGB format
+    options.add_input_configs()->add_input_stream()->set_format(
+        proto::InputStreamConfig_FormatType_RGB);
+
+    options.add_input_configs()->add_input_stream()->set_format(
+        proto::InputStreamConfig_FormatType_NIR);
+
+    options.add_input_configs()->add_input_stream()->set_format(
+        proto::InputStreamConfig_FormatType_NIR_DEPTH);
+
+    PipeDescriptor desc = OptionsToPipeDescriptor(options);
+
+    ASSERT_EQ(desc.inputConfig.size(), 3);
+    ASSERT_EQ(desc.inputConfig[0].inputSources.size(), 1);
+    EXPECT_EQ(desc.inputConfig[0].inputSources[0].format, PipeInputConfigFormatType::RGB);
+
+    ASSERT_EQ(desc.inputConfig[1].inputSources.size(), 1);
+    EXPECT_EQ(desc.inputConfig[1].inputSources[0].format, PipeInputConfigFormatType::NIR);
+
+    ASSERT_EQ(desc.inputConfig[2].inputSources.size(), 1);
+    EXPECT_EQ(desc.inputConfig[2].inputSources[0].format, PipeInputConfigFormatType::NIR_DEPTH);
+}
+
+TEST(OptionsToPipeDescriptorTest, ImageDimensionsAreTranslatedCorrectly) {
+    proto::Options options;
+
+    options.add_input_configs()->add_input_stream()->set_width(640);
+    options.mutable_input_configs(0)->mutable_input_stream(0)->set_height(480);
+    options.mutable_input_configs(0)->mutable_input_stream(0)->set_stride(640 * 3);
+    options.mutable_input_configs(0)->mutable_input_stream(0)->set_stride(640 * 3);
+
+    PipeDescriptor desc = OptionsToPipeDescriptor(options);
+    ASSERT_EQ(desc.inputConfig.size(), 1);
+    ASSERT_EQ(desc.inputConfig[0].inputSources.size(), 1);
+    ASSERT_EQ(desc.inputConfig[0].inputSources[0].width, 640);
+    ASSERT_EQ(desc.inputConfig[0].inputSources[0].height, 480);
+    ASSERT_EQ(desc.inputConfig[0].inputSources[0].stride, 640 * 3);
+}
+
+TEST(OptionsToPipeDescriptorTest, CameraIdIsReflectedCorrectly) {
+    proto::Options options;
+    std::string expectedCameraName = "Camera 1";
+    options.add_input_configs()->add_input_stream()->mutable_cam_config()->set_cam_id(
+        expectedCameraName);
+
+    PipeDescriptor desc = OptionsToPipeDescriptor(options);
+    ASSERT_EQ(desc.inputConfig.size(), 1);
+    ASSERT_EQ(desc.inputConfig[0].inputSources.size(), 1);
+    EXPECT_EQ(desc.inputConfig[0].inputSources[0].camDesc.camId, expectedCameraName);
+}
+
+}  // namespace
+}  // namespace aidl_client
+}  // namespace client_interface
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/tests/runner/graph/Android.bp b/computepipe/tests/runner/graph/Android.bp
new file mode 100644
index 0000000..14271dd
--- /dev/null
+++ b/computepipe/tests/runner/graph/Android.bp
@@ -0,0 +1,79 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "computepipe_prebuilt_graph_test",
+    test_suites: ["device-tests"],
+    srcs: [
+        "EnumConversionTest.cpp",
+        "LocalPrebuiltGraphTest.cpp",
+    ],
+    static_libs: [
+        "computepipe_prebuilt_graph",
+        "computepipe_runner_component",
+        "libgtest",
+        "libgmock",
+	      "libcomputepipeprotos",
+    ],
+    shared_libs: [
+        "libstubgraphimpl",
+        "libprotobuf-cpp-lite",
+        "liblog",
+        "libdl",
+        "libbase",
+    ],
+    header_libs: [
+        "computepipe_runner_includes",
+    ],
+    include_dirs: [
+        "packages/services/Car/computepipe",
+        "packages/services/Car/computepipe/runner/graph",
+    ],
+}
+
+cc_test {
+    name: "computepipe_grpc_graph_test",
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+        "-Wno-unused-parameter",
+    ],
+    test_suites: ["device-tests"],
+    srcs: [
+        "GrpcGraphTest.cpp",
+    ],
+    static_libs: [
+        "computepipe_grpc_graph_proto",
+        "computepipe_runner_component",
+        "libgtest",
+        "libgmock",
+    ],
+    shared_libs: [
+        "computepipe_grpc_graph",
+        "libbase",
+	      "libcomputepipeprotos",
+        "libgrpc++",
+        "libdl",
+        "liblog",
+        "libprotobuf-cpp-full",
+    ],
+    header_libs: [
+        "computepipe_runner_includes",
+    ],
+    include_dirs: [
+        "packages/services/Car/computepipe",
+        "packages/services/Car/computepipe/runner/graph",
+    ],
+}
diff --git a/computepipe/tests/runner/graph/EnumConversionTest.cpp b/computepipe/tests/runner/graph/EnumConversionTest.cpp
new file mode 100644
index 0000000..bbb9408
--- /dev/null
+++ b/computepipe/tests/runner/graph/EnumConversionTest.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "prebuilt_interface.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+namespace {
+
+TEST(EnumConversionTest, StatusToErrorCodeEnums) {
+    EXPECT_EQ(static_cast<int>(PrebuiltComputepipeRunner_ErrorCode::SUCCESS),
+              static_cast<int>(Status::SUCCESS));
+    EXPECT_EQ(static_cast<int>(PrebuiltComputepipeRunner_ErrorCode::INTERNAL_ERROR),
+              static_cast<int>(Status::INTERNAL_ERROR));
+    EXPECT_EQ(PrebuiltComputepipeRunner_ErrorCode::INVALID_ARGUMENT,
+              static_cast<int>(Status::INVALID_ARGUMENT));
+    EXPECT_EQ(PrebuiltComputepipeRunner_ErrorCode::ILLEGAL_STATE,
+              static_cast<int>(Status::ILLEGAL_STATE));
+    EXPECT_EQ(PrebuiltComputepipeRunner_ErrorCode::NO_MEMORY, static_cast<int>(Status::NO_MEMORY));
+    EXPECT_EQ(PrebuiltComputepipeRunner_ErrorCode::FATAL_ERROR,
+              static_cast<int>(Status::FATAL_ERROR));
+    EXPECT_EQ(PrebuiltComputepipeRunner_ErrorCode::ERROR_CODE_MAX,
+              static_cast<int>(Status::STATUS_MAX));
+}
+enum PrebuiltComputepipeRunner_PixelDataFormat {
+    RGB = 0,
+    RGBA = 1,
+    GRAY = 2,
+    PIXEL_DATA_FORMAT_MAX = 3,
+};
+TEST(EnumConversionTest, PixelFormatEnums) {
+    EXPECT_EQ(static_cast<int>(PrebuiltComputepipeRunner_PixelDataFormat::RGB),
+              static_cast<int>(PixelFormat::RGB));
+    EXPECT_EQ(static_cast<int>(PrebuiltComputepipeRunner_PixelDataFormat::RGBA),
+              static_cast<int>(PixelFormat::RGBA));
+    EXPECT_EQ(PrebuiltComputepipeRunner_PixelDataFormat::GRAY, static_cast<int>(PixelFormat::GRAY));
+    EXPECT_EQ(PrebuiltComputepipeRunner_PixelDataFormat::PIXEL_DATA_FORMAT_MAX,
+              static_cast<int>(PixelFormat::PIXELFORMAT_MAX));
+}
+
+}  // namespace
+}  // namespace graph
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/tests/runner/graph/GrpcGraphTest.cpp b/computepipe/tests/runner/graph/GrpcGraphTest.cpp
new file mode 100644
index 0000000..883ef6f
--- /dev/null
+++ b/computepipe/tests/runner/graph/GrpcGraphTest.cpp
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <map>
+#include <memory>
+#include <string>
+#include <thread>
+
+#include <android-base/logging.h>
+#include <grpc++/grpc++.h>
+
+#include "ClientConfig.pb.h"
+#include "GrpcPrebuiltGraphService.grpc.pb.h"
+#include "GrpcPrebuiltGraphService.pb.h"
+#include "Options.pb.h"
+#include "PrebuiltEngineInterface.h"
+#include "PrebuiltGraph.h"
+#include "RunnerComponent.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "types/Status.h"
+
+using ::android::automotive::computepipe::runner::ClientConfig;
+using ::android::automotive::computepipe::runner::RunnerComponentInterface;
+using ::android::automotive::computepipe::runner::RunnerEvent;
+using ::testing::HasSubstr;
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+namespace {
+
+constexpr char kGraphName[] = "Dummy graph name";
+constexpr char kSetGraphConfigMessage[] = "Dummy set config message";
+constexpr char kSetDebugOptionMessage[] = "Dummy set debug option message";
+constexpr char kStartGraphMessage[] = "Dummy start graph message";
+constexpr char kStopGraphMessage[] = "Dummy stop graph message";
+constexpr char kOutputStreamPacket[] = "Dummy output stream packet";
+constexpr char kResetGraphMessage[] = "ResetGraphMessage";
+
+// This is a barebones synchronous server implementation. A better implementation would be an
+// asynchronous implementation and it is upto the graph provider to do that. This implementation
+// is very specific to tests being conducted here.
+class GrpcGraphServerImpl : public proto::GrpcGraphService::Service {
+private:
+    std::string mServerAddress;
+    std::unique_ptr<::grpc::Server> mServer;
+    std::mutex mLock;
+    std::condition_variable mShutdownCv;
+    bool mShutdown = false;
+
+public:
+    explicit GrpcGraphServerImpl(std::string address) : mServerAddress(address) {}
+
+    virtual ~GrpcGraphServerImpl() {
+        if (mServer) {
+            mServer->Shutdown();
+            std::unique_lock lock(mLock);
+            if (!mShutdown) {
+                mShutdownCv.wait_for(lock, std::chrono::seconds(10),
+                                     [this]() { return mShutdown; });
+            }
+        }
+    }
+
+    void startServer() {
+        if (mServer == nullptr) {
+            ::grpc::ServerBuilder builder;
+            builder.RegisterService(this);
+            builder.AddListeningPort(mServerAddress, ::grpc::InsecureServerCredentials());
+            mServer = builder.BuildAndStart();
+            mServer->Wait();
+            std::lock_guard lock(mLock);
+            mShutdown = true;
+            mShutdownCv.notify_one();
+        }
+    }
+
+    ::grpc::Status GetGraphOptions(::grpc::ServerContext* context,
+                                   const proto::GraphOptionsRequest* request,
+                                   proto::GraphOptionsResponse* response) override {
+        proto::Options options;
+        options.set_graph_name(kGraphName);
+        response->set_serialized_options(options.SerializeAsString());
+        return ::grpc::Status::OK;
+    }
+
+    ::grpc::Status SetGraphConfig(::grpc::ServerContext* context,
+                                  const proto::SetGraphConfigRequest* request,
+                                  proto::StatusResponse* response) override {
+        response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
+        response->set_message(kSetGraphConfigMessage);
+        return ::grpc::Status::OK;
+    }
+
+    ::grpc::Status SetDebugOption(::grpc::ServerContext* context,
+                                  const proto::SetDebugRequest* request,
+                                  proto::StatusResponse* response) override {
+        response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
+        response->set_message(kSetDebugOptionMessage);
+        return ::grpc::Status::OK;
+    }
+
+    ::grpc::Status StartGraphExecution(::grpc::ServerContext* context,
+                                       const proto::StartGraphExecutionRequest* request,
+                                       proto::StatusResponse* response) override {
+        response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
+        response->set_message(kStartGraphMessage);
+        return ::grpc::Status::OK;
+    }
+
+    ::grpc::Status ObserveOutputStream(
+            ::grpc::ServerContext* context, const proto::ObserveOutputStreamRequest* request,
+            ::grpc::ServerWriter<proto::OutputStreamResponse>* writer) override {
+        // Write as many output packets as stream id. This is just to test different number of
+        // packets received with each stream. Also write even numbered stream as a pixel packet
+        // and odd numbered stream as a data packet.
+        for (int i = 0; i < request->stream_id(); i++) {
+            proto::OutputStreamResponse response;
+            if (request->stream_id() % 2 == 0) {
+                response.mutable_pixel_data()->set_data(kOutputStreamPacket);
+                response.mutable_pixel_data()->set_height(1);
+                response.mutable_pixel_data()->set_width(sizeof(kOutputStreamPacket));
+                response.mutable_pixel_data()->set_step(sizeof(kOutputStreamPacket));
+                response.mutable_pixel_data()->set_format(proto::PixelFormat::GRAY);
+                EXPECT_TRUE(response.has_pixel_data());
+            } else {
+                response.set_semantic_data(kOutputStreamPacket);
+                EXPECT_TRUE(response.has_semantic_data());
+            }
+            if (!writer->Write(response)) {
+                return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost");
+            }
+        }
+
+        return ::grpc::Status::OK;
+    }
+
+    ::grpc::Status StopGraphExecution(::grpc::ServerContext* context,
+                                      const proto::StopGraphExecutionRequest* request,
+                                      proto::StatusResponse* response) override {
+        response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
+        response->set_message(kStopGraphMessage);
+        return ::grpc::Status::OK;
+    }
+
+    ::grpc::Status ResetGraph(::grpc::ServerContext* context,
+                              const proto::ResetGraphRequest* request,
+                              proto::StatusResponse* response) override {
+        response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
+        response->set_message(kResetGraphMessage);
+        return ::grpc::Status::OK;
+    }
+
+    ::grpc::Status GetProfilingData(::grpc::ServerContext* context,
+                                    const proto::ProfilingDataRequest* request,
+                                    proto::ProfilingDataResponse* response) {
+        response->set_data(kSetGraphConfigMessage);
+        return ::grpc::Status::OK;
+    }
+};
+
+class PrebuiltEngineInterfaceImpl : public PrebuiltEngineInterface {
+private:
+    std::map<int, int> mNumPacketsPerStream;
+    std::mutex mLock;
+    std::condition_variable mCv;
+    bool mGraphTerminated = false;
+
+public:
+    // Prebuilt to engine interface
+    void DispatchPixelData(int streamId, int64_t timestamp,
+                           const runner::InputFrame& frame) override {
+        ASSERT_EQ(streamId % 2, 0);
+        std::lock_guard lock(mLock);
+        if (mNumPacketsPerStream.find(streamId) == mNumPacketsPerStream.end()) {
+            mNumPacketsPerStream[streamId] = 1;
+        } else {
+            mNumPacketsPerStream[streamId]++;
+        }
+    }
+
+    void DispatchSerializedData(int streamId, int64_t timestamp, std::string&& data) override {
+        ASSERT_EQ(streamId % 2, 1);
+        std::lock_guard lock(mLock);
+        if (mNumPacketsPerStream.find(streamId) == mNumPacketsPerStream.end()) {
+            mNumPacketsPerStream[streamId] = 1;
+        } else {
+            mNumPacketsPerStream[streamId]++;
+        }
+    }
+
+    void DispatchGraphTerminationMessage(Status status, std::string&& msg) override {
+        std::lock_guard lock(mLock);
+        mGraphTerminated = true;
+        mCv.notify_one();
+    }
+
+    bool waitForTermination() {
+        std::unique_lock lock(mLock);
+        if (!mGraphTerminated) {
+            mCv.wait_for(lock, std::chrono::seconds(10), [this] { return mGraphTerminated; });
+        }
+        return mGraphTerminated;
+    }
+
+    int numPacketsForStream(int streamId) {
+        std::lock_guard lock(mLock);
+        auto it = mNumPacketsPerStream.find(streamId);
+        if (it == mNumPacketsPerStream.end()) {
+            return 0;
+        }
+        return it->second;
+    }
+};
+
+class GrpcGraphTest : public ::testing::Test {
+private:
+    std::unique_ptr<GrpcGraphServerImpl> mServer;
+    std::shared_ptr<PrebuiltEngineInterfaceImpl> mEngine;
+    std::string mAddress = "[::]:10000";
+
+public:
+    std::unique_ptr<PrebuiltGraph> mGrpcGraph;
+
+    void SetUp() override {
+        mServer = std::make_unique<GrpcGraphServerImpl>(mAddress);
+        std::thread t = std::thread([this]() { mServer->startServer(); });
+        t.detach();
+        std::this_thread::sleep_for(std::chrono::seconds(1));
+
+        mEngine = std::make_shared<PrebuiltEngineInterfaceImpl>();
+        mGrpcGraph = GetRemoteGraphFromAddress(mAddress, mEngine);
+        ASSERT_TRUE(mGrpcGraph != nullptr);
+        EXPECT_EQ(mGrpcGraph->GetSupportedGraphConfigs().graph_name(), kGraphName);
+        EXPECT_EQ(mGrpcGraph->GetGraphType(), PrebuiltGraphType::REMOTE);
+    }
+
+    void TearDown() override { mServer.reset(); }
+
+    bool waitForTermination() { return mEngine->waitForTermination(); }
+
+    int numPacketsForStream(int streamId) { return mEngine->numPacketsForStream(streamId); }
+};
+
+class TestRunnerEvent : public runner::RunnerEvent {
+    bool isPhaseEntry() const override { return true; }
+    bool isTransitionComplete() const override { return false; }
+    bool isAborted() const override { return false; }
+    Status dispatchToComponent(const std::shared_ptr<runner::RunnerComponentInterface>&) override {
+        return Status::SUCCESS;
+    };
+};
+
+// Test to see if stop with flush produces exactly as many packets as expected. The number
+// of packets produced by stopImmediate is variable as the number of packets already dispatched
+// when stop is called is variable.
+TEST_F(GrpcGraphTest, EndToEndTestOnStopWithFlush) {
+    std::map<int, int> outputConfigs = {{5, 1}, {6, 1}};
+    runner::ClientConfig clientConfig(0, 0, 0, outputConfigs, proto::ProfilingType::DISABLED);
+
+    EXPECT_EQ(mGrpcGraph->handleConfigPhase(clientConfig), Status::SUCCESS);
+    EXPECT_EQ(mGrpcGraph->GetGraphState(), PrebuiltGraphState::STOPPED);
+    EXPECT_EQ(mGrpcGraph->GetStatus(), Status::SUCCESS);
+
+    TestRunnerEvent e;
+    EXPECT_EQ(mGrpcGraph->handleExecutionPhase(e), Status::SUCCESS);
+    EXPECT_EQ(mGrpcGraph->GetGraphState(), PrebuiltGraphState::RUNNING);
+    EXPECT_EQ(mGrpcGraph->GetStatus(), Status::SUCCESS);
+
+    EXPECT_EQ(mGrpcGraph->handleStopWithFlushPhase(e), Status::SUCCESS);
+    EXPECT_EQ(mGrpcGraph->GetGraphState(), PrebuiltGraphState::FLUSHING);
+    EXPECT_EQ(mGrpcGraph->GetStatus(), Status::SUCCESS);
+
+    EXPECT_TRUE(waitForTermination());
+    EXPECT_EQ(mGrpcGraph->GetGraphState(), PrebuiltGraphState::STOPPED);
+    EXPECT_EQ(mGrpcGraph->GetStatus(), Status::SUCCESS);
+    EXPECT_EQ(numPacketsForStream(5), 5);
+    EXPECT_EQ(numPacketsForStream(6), 6);
+}
+
+TEST_F(GrpcGraphTest, GraphStopCallbackProducedOnImmediateStop) {
+    std::map<int, int> outputConfigs = {{5, 1}, {6, 1}};
+    runner::ClientConfig clientConfig(0, 0, 0, outputConfigs, proto::ProfilingType::DISABLED);
+
+    EXPECT_EQ(mGrpcGraph->handleConfigPhase(clientConfig), Status::SUCCESS);
+    EXPECT_EQ(mGrpcGraph->GetGraphState(), PrebuiltGraphState::STOPPED);
+    EXPECT_EQ(mGrpcGraph->GetStatus(), Status::SUCCESS);
+
+    TestRunnerEvent e;
+    EXPECT_EQ(mGrpcGraph->handleExecutionPhase(e), Status::SUCCESS);
+    EXPECT_EQ(mGrpcGraph->GetGraphState(), PrebuiltGraphState::RUNNING);
+    EXPECT_EQ(mGrpcGraph->GetStatus(), Status::SUCCESS);
+
+    EXPECT_EQ(mGrpcGraph->handleStopImmediatePhase(e), Status::SUCCESS);
+    EXPECT_EQ(mGrpcGraph->GetGraphState(), PrebuiltGraphState::STOPPED);
+    EXPECT_EQ(mGrpcGraph->GetStatus(), Status::SUCCESS);
+
+    EXPECT_TRUE(waitForTermination());
+}
+
+TEST_F(GrpcGraphTest, GraphStopCallbackProducedOnFlushedStopWithNoOutputStreams) {
+    std::map<int, int> outputConfigs = {};
+    runner::ClientConfig clientConfig(0, 0, 0, outputConfigs, proto::ProfilingType::DISABLED);
+    EXPECT_EQ(mGrpcGraph->handleConfigPhase(clientConfig), Status::SUCCESS);
+    EXPECT_EQ(mGrpcGraph->GetGraphState(), PrebuiltGraphState::STOPPED);
+    EXPECT_EQ(mGrpcGraph->GetStatus(), Status::SUCCESS);
+
+    TestRunnerEvent e;
+    EXPECT_EQ(mGrpcGraph->handleExecutionPhase(e), Status::SUCCESS);
+    EXPECT_EQ(mGrpcGraph->GetGraphState(), PrebuiltGraphState::RUNNING);
+    EXPECT_EQ(mGrpcGraph->GetStatus(), Status::SUCCESS);
+
+    EXPECT_EQ(mGrpcGraph->handleStopWithFlushPhase(e), Status::SUCCESS);
+    EXPECT_EQ(mGrpcGraph->GetStatus(), Status::SUCCESS);
+
+    EXPECT_TRUE(waitForTermination());
+}
+
+TEST_F(GrpcGraphTest, SetInputStreamsFailAsExpected) {
+    runner::InputFrame frame(0, 0, static_cast<PixelFormat>(0), 0, nullptr);
+    EXPECT_EQ(mGrpcGraph->SetInputStreamData(0, 0, ""), Status::FATAL_ERROR);
+    EXPECT_EQ(mGrpcGraph->SetInputStreamPixelData(0, 0, frame), Status::FATAL_ERROR);
+}
+
+}  // namespace
+}  // namespace graph
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/tests/runner/graph/LocalPrebuiltGraphTest.cpp b/computepipe/tests/runner/graph/LocalPrebuiltGraphTest.cpp
new file mode 100644
index 0000000..d63ec51
--- /dev/null
+++ b/computepipe/tests/runner/graph/LocalPrebuiltGraphTest.cpp
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <string>
+
+#include "ClientConfig.pb.h"
+#include "LocalPrebuiltGraph.h"
+#include "PrebuiltEngineInterface.h"
+#include "ProfilingType.pb.h"
+#include "RunnerComponent.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "types/Status.h"
+
+using ::android::automotive::computepipe::runner::ClientConfig;
+using ::android::automotive::computepipe::runner::RunnerComponentInterface;
+using ::android::automotive::computepipe::runner::RunnerEvent;
+using ::testing::HasSubstr;
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+namespace {
+
+// Barebones implementation of the PrebuiltEngineInterface. This implementation should suffice for
+// basic cases. More complicated use cases might need their own implementation of it.
+typedef std::function<void(int, int64_t, const runner::InputFrame&)> PixelCallback;
+typedef std::function<void(int, int64_t, std::string&&)> SerializedStreamCallback;
+typedef std::function<void(Status, std::string&&)> GraphTerminationCallback;
+class PrebuiltEngineInterfaceImpl : public PrebuiltEngineInterface {
+private:
+    PixelCallback mPixelCallbackFn;
+    SerializedStreamCallback mSerializedStreamCallbackFn;
+    GraphTerminationCallback mGraphTerminationCallbackFn;
+
+public:
+    virtual ~PrebuiltEngineInterfaceImpl() = default;
+
+    void DispatchPixelData(int streamId, int64_t timestamp,
+                           const runner::InputFrame& frame) override {
+        mPixelCallbackFn(streamId, timestamp, frame);
+    }
+
+    void DispatchSerializedData(int streamId, int64_t timestamp, std::string&& data) override {
+        mSerializedStreamCallbackFn(streamId, timestamp, std::move(data));
+    }
+
+    void DispatchGraphTerminationMessage(Status status, std::string&& msg) override {
+        mGraphTerminationCallbackFn(status, std::move(msg));
+    }
+
+    void SetPixelCallback(PixelCallback callback) { mPixelCallbackFn = callback; }
+
+    void SetSerializedStreamCallback(SerializedStreamCallback callback) {
+        mSerializedStreamCallbackFn = callback;
+    }
+
+    void SetGraphTerminationCallback(GraphTerminationCallback callback) {
+        mGraphTerminationCallbackFn = callback;
+    }
+};
+
+// The stub graph implementation is a passthrough implementation that does not run
+// any graph and returns success for all implementations. The only useful things that
+// it does for the tests are
+//
+//    1. Stores the name of the function last visited and returns that with GetErrorMessage call
+//    2. When an input stream is set, it immediately returns an output callback with the same input
+//       data and timestamp. Similar callback is issued for when input stream pixel data is set too
+//
+// The above two properties are used to test that the prebuilt graph wrapper calls the correct
+// functions and callbacks are issued as expected. These tests do not test the internals of the
+// graph themselves and such tests must be written along with the graph implementation.
+TEST(LocalPrebuiltGraphTest, FunctionMappingFromLibraryIsSuccessful) {
+    PrebuiltEngineInterfaceImpl callback;
+    std::shared_ptr<PrebuiltEngineInterface> engineInterface =
+            std::static_pointer_cast<PrebuiltEngineInterface, PrebuiltEngineInterfaceImpl>(
+                    std::make_shared<PrebuiltEngineInterfaceImpl>(callback));
+    PrebuiltGraph* graph = GetLocalGraphFromLibrary("libstubgraphimpl.so", engineInterface);
+    ASSERT_TRUE(graph);
+    EXPECT_EQ(graph->GetGraphType(), PrebuiltGraphType::LOCAL);
+    EXPECT_NE(graph->GetGraphState(), PrebuiltGraphState::UNINITIALIZED);
+    EXPECT_EQ(graph->GetSupportedGraphConfigs().graph_name(), "stub_graph");
+}
+
+TEST(LocalPrebuiltGraphTest, GraphConfigurationIssuesCorrectFunctionCalls) {
+    PrebuiltEngineInterfaceImpl callback;
+    std::shared_ptr<PrebuiltEngineInterface> engineInterface =
+            std::static_pointer_cast<PrebuiltEngineInterface, PrebuiltEngineInterfaceImpl>(
+                    std::make_shared<PrebuiltEngineInterfaceImpl>(callback));
+    PrebuiltGraph* graph = GetLocalGraphFromLibrary("libstubgraphimpl.so", engineInterface);
+    ASSERT_TRUE(graph);
+    EXPECT_EQ(graph->GetGraphType(), PrebuiltGraphType::LOCAL);
+    ASSERT_NE(graph->GetGraphState(), PrebuiltGraphState::UNINITIALIZED);
+
+    graph->GetSupportedGraphConfigs();
+    std::string functionVisited = graph->GetErrorMessage();
+    EXPECT_THAT(functionVisited, HasSubstr("GetSupportedGraphConfigs"));
+
+    std::map<int, int> maxOutputPacketsPerStream;
+    ClientConfig e(0, 0, 0, maxOutputPacketsPerStream, proto::ProfilingType::DISABLED);
+    e.setPhaseState(runner::PhaseState::ENTRY);
+    EXPECT_EQ(graph->handleConfigPhase(e), Status::SUCCESS);
+    functionVisited = graph->GetErrorMessage();
+
+    EXPECT_EQ(graph->GetStatus(), Status::SUCCESS);
+    functionVisited = graph->GetErrorMessage();
+    EXPECT_THAT(functionVisited, HasSubstr("GetErrorCode"));
+}
+
+TEST(LocalPrebuiltGraphTest, GraphOperationEndToEndIsSuccessful) {
+    bool graphHasTerminated = false;
+    int numOutputStreamCallbacksReceived[4] = {0, 0, 0, 0};
+
+    PrebuiltEngineInterfaceImpl callback;
+    callback.SetGraphTerminationCallback(
+            [&graphHasTerminated](Status, std::string) { graphHasTerminated = true; });
+
+    // Add multiple pixel stream callback functions to see if all of them register.
+    callback.SetPixelCallback([&numOutputStreamCallbacksReceived](int streamIndex, int64_t,
+                                                                  const runner::InputFrame&) {
+        ASSERT_TRUE(streamIndex == 0 || streamIndex == 1);
+        numOutputStreamCallbacksReceived[streamIndex]++;
+    });
+
+    // Add multiple stream callback functions to see if all of them register.
+    callback.SetSerializedStreamCallback(
+            [&numOutputStreamCallbacksReceived](int streamIndex, int64_t, std::string&&) {
+                ASSERT_TRUE(streamIndex == 2 || streamIndex == 3);
+                numOutputStreamCallbacksReceived[streamIndex]++;
+            });
+
+    std::shared_ptr<PrebuiltEngineInterface> engineInterface =
+            std::static_pointer_cast<PrebuiltEngineInterface, PrebuiltEngineInterfaceImpl>(
+                    std::make_shared<PrebuiltEngineInterfaceImpl>(callback));
+
+    PrebuiltGraph* graph = GetLocalGraphFromLibrary("libstubgraphimpl.so", engineInterface);
+
+    EXPECT_EQ(graph->GetGraphType(), PrebuiltGraphType::LOCAL);
+    ASSERT_NE(graph->GetGraphState(), PrebuiltGraphState::UNINITIALIZED);
+
+    graph->GetSupportedGraphConfigs();
+    std::string functionVisited = graph->GetErrorMessage();
+    EXPECT_THAT(functionVisited, HasSubstr("GetSupportedGraphConfigs"));
+
+    std::map<int, int> maxOutputPacketsPerStream;
+    ClientConfig e(0, 0, 0, maxOutputPacketsPerStream, proto::ProfilingType::DISABLED);
+    e.setPhaseState(runner::PhaseState::ENTRY);
+    EXPECT_EQ(graph->handleConfigPhase(e), Status::SUCCESS);
+    functionVisited = graph->GetErrorMessage();
+
+    EXPECT_EQ(graph->handleExecutionPhase(e), Status::SUCCESS);
+    functionVisited = graph->GetErrorMessage();
+    EXPECT_THAT(functionVisited, HasSubstr("StartGraphExecution"));
+
+    runner::InputFrame inputFrame(0, 0, PixelFormat::RGB, 0, nullptr);
+    EXPECT_EQ(graph->SetInputStreamPixelData(
+                      /*streamIndex =*/0, /*timestamp =*/0, /*inputFrame =*/inputFrame),
+              Status::SUCCESS);
+    EXPECT_EQ(graph->SetInputStreamPixelData(
+                      /*streamIndex =*/0, /*timestamp =*/0, /*inputFrame =*/inputFrame),
+              Status::SUCCESS);
+    EXPECT_EQ(graph->SetInputStreamPixelData(
+                      /*streamIndex =*/0, /*timestamp =*/0, /*inputFrame =*/inputFrame),
+              Status::SUCCESS);
+    EXPECT_EQ(graph->SetInputStreamPixelData(
+                      /*streamIndex =*/1, /*timestamp =*/0, /*inputFrame =*/inputFrame),
+              Status::SUCCESS);
+    EXPECT_EQ(graph->SetInputStreamPixelData(
+                      /*streamIndex =*/1, /*timestamp =*/0, /*inputFrame =*/inputFrame),
+              Status::SUCCESS);
+    functionVisited = graph->GetErrorMessage();
+    EXPECT_THAT(functionVisited, HasSubstr("SetInputStreamPixelData"));
+
+    EXPECT_EQ(graph->SetInputStreamData(/*streamIndex =*/2, /* timestamp =*/0, /* data =*/""),
+              Status::SUCCESS);
+    EXPECT_EQ(graph->SetInputStreamData(/*streamIndex =*/2, /* timestamp =*/0, /* data =*/""),
+              Status::SUCCESS);
+    EXPECT_EQ(graph->SetInputStreamData(/*streamIndex =*/2, /* timestamp =*/0, /* data =*/""),
+              Status::SUCCESS);
+    EXPECT_EQ(graph->SetInputStreamData(/*streamIndex =*/3, /* timestamp =*/0, /* data =*/""),
+              Status::SUCCESS);
+    EXPECT_EQ(graph->SetInputStreamData(/*streamIndex =*/3, /* timestamp =*/0, /* data =*/""),
+              Status::SUCCESS);
+    functionVisited = graph->GetErrorMessage();
+    EXPECT_THAT(functionVisited, HasSubstr("SetInputStreamData"));
+
+    EXPECT_EQ(numOutputStreamCallbacksReceived[0], 3);
+    EXPECT_EQ(numOutputStreamCallbacksReceived[1], 2);
+    EXPECT_EQ(numOutputStreamCallbacksReceived[2], 3);
+    EXPECT_EQ(numOutputStreamCallbacksReceived[3], 2);
+
+    EXPECT_FALSE(graphHasTerminated);
+    EXPECT_EQ(graph->handleStopImmediatePhase(e), Status::SUCCESS);
+
+    EXPECT_EQ(graph->handleResetPhase(e), Status::SUCCESS);
+    functionVisited = graph->GetErrorMessage();
+    EXPECT_THAT(functionVisited, HasSubstr("ResetGraph"));
+
+    EXPECT_TRUE(graphHasTerminated);
+}
+
+}  // namespace
+}  // namespace graph
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/tests/runner/graph/stubgraph/Android.bp b/computepipe/tests/runner/graph/stubgraph/Android.bp
new file mode 100644
index 0000000..d01b69f
--- /dev/null
+++ b/computepipe/tests/runner/graph/stubgraph/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_prebuilt_library_shared {
+    name: "libstubgraphimpl",
+    target: {
+        android_arm64: {
+            srcs: ["arm64/libstubgraphimpl.so"],
+        },
+        android_arm: {
+            srcs: ["arm/libstubgraphimpl.so"],
+        },
+        android_x86: {
+            srcs: ["x86/libstubgraphimpl.so"],
+        },
+        android_x86_64: {
+            srcs: ["x86_64/libstubgraphimpl.so"],
+        },
+    },
+
+    shared_libs: [
+        "libc",
+        "libdl",
+        "liblog",
+        "libm"
+    ],
+    strip: {
+        keep_symbols: true,
+    }
+}
diff --git a/computepipe/tests/runner/graph/stubgraph/arm/libstubgraphimpl.so b/computepipe/tests/runner/graph/stubgraph/arm/libstubgraphimpl.so
new file mode 100755
index 0000000..d15cb8f
--- /dev/null
+++ b/computepipe/tests/runner/graph/stubgraph/arm/libstubgraphimpl.so
Binary files differ
diff --git a/computepipe/tests/runner/graph/stubgraph/arm64/libstubgraphimpl.so b/computepipe/tests/runner/graph/stubgraph/arm64/libstubgraphimpl.so
new file mode 100755
index 0000000..f347de7
--- /dev/null
+++ b/computepipe/tests/runner/graph/stubgraph/arm64/libstubgraphimpl.so
Binary files differ
diff --git a/computepipe/tests/runner/graph/stubgraph/x86/libstubgraphimpl.so b/computepipe/tests/runner/graph/stubgraph/x86/libstubgraphimpl.so
new file mode 100755
index 0000000..55e1355
--- /dev/null
+++ b/computepipe/tests/runner/graph/stubgraph/x86/libstubgraphimpl.so
Binary files differ
diff --git a/computepipe/tests/runner/graph/stubgraph/x86_64/libstubgraphimpl.so b/computepipe/tests/runner/graph/stubgraph/x86_64/libstubgraphimpl.so
new file mode 100755
index 0000000..241c18c
--- /dev/null
+++ b/computepipe/tests/runner/graph/stubgraph/x86_64/libstubgraphimpl.so
Binary files differ
diff --git a/computepipe/tests/runner/stream_manager/Android.bp b/computepipe/tests/runner/stream_manager/Android.bp
new file mode 100644
index 0000000..d5543c6
--- /dev/null
+++ b/computepipe/tests/runner/stream_manager/Android.bp
@@ -0,0 +1,71 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "computepipe_semantic_manager_test",
+    test_suites: ["device-tests"],
+    srcs: [
+        "SemanticManagerTest.cpp",
+    ],
+    static_libs: [
+        "computepipe_stream_manager",
+        "computepipe_runner_component",
+        "mock_stream_engine_interface",
+        "libgtest",
+        "libgmock",
+        "libcomputepipeprotos",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libnativewindow",
+        "libprotobuf-cpp-lite",
+    ],
+    header_libs: [
+        "computepipe_runner_includes",
+    ],
+    include_dirs: [
+        "packages/services/Car/computepipe",
+        "packages/services/Car/computepipe/runner/stream_manager",
+    ],
+}
+
+cc_test {
+    name: "computepipe_pixel_manager_test",
+    test_suites: ["device-tests"],
+    srcs: [
+        "PixelStreamManagerTest.cpp",
+    ],
+    static_libs: [
+        "computepipe_stream_manager",
+        "computepipe_runner_component",
+        "mock_stream_engine_interface",
+        "libgtest",
+        "libgmock",
+        "libcomputepipeprotos",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libnativewindow",
+        "libprotobuf-cpp-lite",
+    ],
+    header_libs: [
+        "computepipe_runner_includes",
+    ],
+    include_dirs: [
+        "packages/services/Car/computepipe",
+        "packages/services/Car/computepipe/runner/stream_manager",
+    ],
+}
diff --git a/computepipe/tests/runner/stream_manager/PixelStreamManagerTest.cpp b/computepipe/tests/runner/stream_manager/PixelStreamManagerTest.cpp
new file mode 100644
index 0000000..118d559
--- /dev/null
+++ b/computepipe/tests/runner/stream_manager/PixelStreamManagerTest.cpp
@@ -0,0 +1,393 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <vndk/hardware_buffer.h>
+#include <android-base/logging.h>
+
+#include "EventGenerator.h"
+#include "InputFrame.h"
+#include "MockEngine.h"
+#include "OutputConfig.pb.h"
+#include "PixelFormatUtils.h"
+#include "PixelStreamManager.h"
+#include "RunnerComponent.h"
+#include "StreamEngineInterface.h"
+#include "StreamManager.h"
+#include "gmock/gmock-matchers.h"
+#include "types/Status.h"
+
+using ::android::automotive::computepipe::runner::RunnerComponentInterface;
+using ::android::automotive::computepipe::runner::RunnerEvent;
+using ::android::automotive::computepipe::runner::generator::DefaultEvent;
+using ::testing::Contains;
+using ::testing::Not;
+using ::testing::Return;
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace stream_manager {
+namespace {
+
+MATCHER_P(ContainsDataFromFrame, data, "") {
+    const uint8_t* dataPtr = data->getFramePtr();
+    FrameInfo info = data->getFrameInfo();
+    AHardwareBuffer_Desc desc;
+    AHardwareBuffer_describe(arg, &desc);
+
+    if (desc.width != info.width) {
+        *result_listener << "Width does not match with values " << desc.width << " and "
+                         << info.width;
+        return false;
+    }
+
+    if (desc.height != info.height) {
+        *result_listener << "Height does not match with values " << desc.height << " and "
+                         << info.height;
+        return false;
+    }
+
+    AHardwareBuffer_Format expectedFormat = PixelFormatToHardwareBufferFormat(info.format);
+    if (expectedFormat != desc.format) {
+        *result_listener << "Format does not match";
+        return false;
+    }
+
+    void* mappedBuffer = nullptr;
+    int err = AHardwareBuffer_lock(arg, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, -1, nullptr,
+                                   &mappedBuffer);
+    if (err != 0 || mappedBuffer == nullptr) {
+        *result_listener << "Unable to lock the buffer for reading and comparing";
+        return false;
+    }
+
+    bool dataMatched = true;
+    int bytesPerPixel = numBytesPerPixel(expectedFormat);
+    for (int y = 0; y < info.height; y++) {
+        uint8_t* mappedRow = (uint8_t*)mappedBuffer + y * desc.stride * bytesPerPixel;
+        if (memcmp(mappedRow, dataPtr + y * info.stride,
+                   std::min(info.stride, desc.stride * bytesPerPixel))) {
+            *result_listener << "Row " << y << " does not match";
+            dataMatched = false;
+            break;
+        }
+    }
+    AHardwareBuffer_unlock(arg, nullptr);
+    return dataMatched;
+}
+
+TEST(PixelMemHandleTest, SuccessfullyCreatesMemHandleOnFirstAttempt) {
+    int bufferId = 10;
+    int streamId = 1;
+    uint64_t timestamp = 100;
+    PixelMemHandle memHandle(bufferId, streamId, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
+
+    EXPECT_EQ(memHandle.getBufferId(), bufferId);
+    EXPECT_EQ(memHandle.getStreamId(), streamId);
+    EXPECT_EQ(memHandle.getHardwareBuffer(), nullptr);
+
+    std::vector<uint8_t> data(16 * 16 * 3, 0);
+    InputFrame frame(16, 16, PixelFormat::RGB, 16 * 3, &data[0]);
+    Status status = memHandle.setFrameData(timestamp, frame);
+    EXPECT_EQ(status, Status::SUCCESS);
+    ASSERT_NE(memHandle.getHardwareBuffer(), nullptr);
+
+    AHardwareBuffer_Desc desc;
+    AHardwareBuffer* buffer = memHandle.getHardwareBuffer();
+    AHardwareBuffer_describe(buffer, &desc);
+    EXPECT_EQ(desc.height, 16);
+    EXPECT_EQ(desc.width, 16);
+    EXPECT_EQ(desc.usage,
+              AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN);
+    EXPECT_EQ(desc.format, AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM);
+
+    EXPECT_THAT(buffer, ContainsDataFromFrame(&frame));
+}
+
+TEST(PixelMemHandleTest, FailsToOverwriteFrameDataWithDifferentImageFormat) {
+    int bufferId = 10;
+    int streamId = 1;
+    uint64_t timestamp = 100;
+    PixelMemHandle memHandle(bufferId, streamId, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
+
+    EXPECT_EQ(memHandle.getBufferId(), bufferId);
+    EXPECT_EQ(memHandle.getStreamId(), streamId);
+    EXPECT_EQ(memHandle.getHardwareBuffer(), nullptr);
+
+    uint8_t data[16 * 16 * 3] = {0};
+    InputFrame frame(16, 16, PixelFormat::RGB, 16 * 3, &data[0]);
+    Status status = memHandle.setFrameData(timestamp, frame);
+    EXPECT_EQ(status, Status::SUCCESS);
+    ASSERT_NE(memHandle.getHardwareBuffer(), nullptr);
+
+    InputFrame frameWithNewFormat(16, 16, PixelFormat::RGBA, 16 * 4, nullptr);
+    status = memHandle.setFrameData(timestamp, frameWithNewFormat);
+    EXPECT_EQ(status, Status::INVALID_ARGUMENT);
+
+    InputFrame frameWithNewDimensions(8, 8, PixelFormat::RGB, 8 * 3, nullptr);
+    status = memHandle.setFrameData(timestamp, frameWithNewDimensions);
+    EXPECT_EQ(status, Status::INVALID_ARGUMENT);
+}
+
+TEST(PixelMemHandleTest, SuccessfullyOverwritesOldData) {
+    int bufferId = 10;
+    int streamId = 1;
+    uint64_t timestamp = 100;
+    PixelMemHandle memHandle(bufferId, streamId, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
+
+    EXPECT_EQ(memHandle.getBufferId(), bufferId);
+    EXPECT_EQ(memHandle.getStreamId(), streamId);
+    EXPECT_EQ(memHandle.getHardwareBuffer(), nullptr);
+
+    std::vector<uint8_t> data(16 * 16 * 3, 0);
+    InputFrame frame(16, 16, PixelFormat::RGB, 16 * 3, &data[0]);
+    Status status = memHandle.setFrameData(timestamp, frame);
+    EXPECT_EQ(status, Status::SUCCESS);
+    ASSERT_NE(memHandle.getHardwareBuffer(), nullptr);
+    EXPECT_THAT(memHandle.getHardwareBuffer(), ContainsDataFromFrame(&frame));
+
+    std::vector<uint8_t> newData(16 * 16 * 3, 1);
+    uint64_t newTimestamp = 200;
+    InputFrame newFrame(16, 16, PixelFormat::RGB, 16 * 3, &newData[0]);
+    memHandle.setFrameData(newTimestamp, newFrame);
+    EXPECT_THAT(memHandle.getHardwareBuffer(), ContainsDataFromFrame(&newFrame));
+    EXPECT_THAT(memHandle.getTimeStamp(), newTimestamp);
+}
+
+TEST(PixelMemHandleTest, CreatesBuffersOfExpectedFormats) {
+    int bufferId = 10;
+    int streamId = 1;
+    uint64_t timestamp = 100;
+
+    std::vector<uint8_t> rgbData(16 * 16 * 3, 10);
+    InputFrame rgbFrame(16, 16, PixelFormat::RGB, 16 * 3, &rgbData[0]);
+    PixelMemHandle rgbHandle(bufferId, streamId, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
+    rgbHandle.setFrameData(timestamp, rgbFrame);
+    EXPECT_THAT(rgbHandle.getHardwareBuffer(), ContainsDataFromFrame(&rgbFrame));
+
+    std::vector<uint8_t> rgbaData(16 * 16 * 4, 20);
+    InputFrame rgbaFrame(16, 16, PixelFormat::RGBA, 16 * 4, &rgbaData[0]);
+    PixelMemHandle rgbaHandle(bufferId, streamId, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
+    rgbaHandle.setFrameData(timestamp, rgbaFrame);
+    EXPECT_THAT(rgbaHandle.getHardwareBuffer(), ContainsDataFromFrame(&rgbaFrame));
+
+    std::vector<uint8_t> yData(16 * 16, 40);
+    InputFrame yFrame(16, 16, PixelFormat::GRAY, 16, &yData[0]);
+    PixelMemHandle yHandle(bufferId, streamId, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
+    yHandle.setFrameData(timestamp, yFrame);
+    EXPECT_THAT(yHandle.getHardwareBuffer(), ContainsDataFromFrame(&yFrame));
+}
+
+std::pair<std::shared_ptr<MockEngine>, std::unique_ptr<StreamManager>> CreateStreamManagerAndEngine(
+    int maxInFlightPackets) {
+    StreamManagerFactory factory;
+    proto::OutputConfig outputConfig;
+    outputConfig.set_type(proto::PacketType::PIXEL_DATA);
+    outputConfig.set_stream_name("pixel_stream");
+    std::shared_ptr<MockEngine> mockEngine = std::make_shared<MockEngine>();
+    std::unique_ptr<StreamManager> manager =
+        factory.getStreamManager(outputConfig, mockEngine, maxInFlightPackets);
+
+    return std::pair(mockEngine, std::move(manager));
+}
+
+TEST(PixelStreamManagerTest, PacketQueueingProducesACallback) {
+    // Create stream manager
+    int maxInFlightPackets = 1;
+    auto [mockEngine, manager] = CreateStreamManagerAndEngine(maxInFlightPackets);
+
+    DefaultEvent e = DefaultEvent::generateEntryEvent(DefaultEvent::Phase::RUN);
+
+    ASSERT_EQ(manager->handleExecutionPhase(e), Status::SUCCESS);
+    std::vector<uint8_t> data(16 * 16 * 3, 100);
+    InputFrame frame(16, 16, PixelFormat::RGB, 16 * 3, &data[0]);
+
+    std::shared_ptr<MemHandle> memHandle;
+    EXPECT_CALL((*mockEngine), dispatchPacket)
+        .WillOnce(testing::DoAll(testing::SaveArg<0>(&memHandle), (Return(Status::SUCCESS))));
+
+    EXPECT_EQ(manager->queuePacket(frame, 0), Status::SUCCESS);
+    sleep(1);
+    ASSERT_NE(memHandle, nullptr);
+    EXPECT_THAT(memHandle->getHardwareBuffer(), ContainsDataFromFrame(&frame));
+    EXPECT_THAT(memHandle->getTimeStamp(), 0);
+    EXPECT_THAT(memHandle->getStreamId(), 0);
+}
+
+TEST(PixelStreamManagerTest, MorePacketsThanMaxInFlightAreNotDispatched) {
+    int maxInFlightPackets = 3;
+    auto [mockEngine, manager] = CreateStreamManagerAndEngine(maxInFlightPackets);
+
+    DefaultEvent e = DefaultEvent::generateEntryEvent(DefaultEvent::Phase::RUN);
+
+    ASSERT_EQ(manager->handleExecutionPhase(e), Status::SUCCESS);
+    std::vector<uint8_t> data(16 * 16 * 3, 100);
+    InputFrame frame(16, 16, PixelFormat::RGB, 16 * 3, &data[0]);
+    std::set<int> activeBufferIds;
+
+    std::shared_ptr<MemHandle> memHandle;
+    EXPECT_CALL((*mockEngine), dispatchPacket)
+        .Times(3)
+        .WillRepeatedly(testing::DoAll(testing::SaveArg<0>(&memHandle), (Return(Status::SUCCESS))));
+
+    EXPECT_EQ(manager->queuePacket(frame, 0), Status::SUCCESS);
+    sleep(1);
+    ASSERT_NE(memHandle, nullptr);
+    EXPECT_THAT(memHandle->getHardwareBuffer(), ContainsDataFromFrame(&frame));
+    EXPECT_THAT(memHandle->getTimeStamp(), 0);
+    EXPECT_THAT(memHandle->getStreamId(), 0);
+    activeBufferIds.insert(memHandle->getBufferId());
+
+    EXPECT_EQ(manager->queuePacket(frame, 10), Status::SUCCESS);
+    sleep(1);
+    ASSERT_NE(memHandle, nullptr);
+    EXPECT_THAT(memHandle->getHardwareBuffer(), ContainsDataFromFrame(&frame));
+    EXPECT_THAT(memHandle->getTimeStamp(), 10);
+    EXPECT_THAT(memHandle->getStreamId(), 0);
+    EXPECT_THAT(activeBufferIds, Not(Contains(memHandle->getBufferId())));
+    activeBufferIds.insert(memHandle->getBufferId());
+
+    EXPECT_EQ(manager->queuePacket(frame, 20), Status::SUCCESS);
+    sleep(1);
+    ASSERT_NE(memHandle, nullptr);
+    EXPECT_THAT(memHandle->getHardwareBuffer(), ContainsDataFromFrame(&frame));
+    EXPECT_THAT(memHandle->getTimeStamp(), 20);
+    EXPECT_THAT(memHandle->getStreamId(), 0);
+    EXPECT_THAT(activeBufferIds, Not(Contains(memHandle->getBufferId())));
+    activeBufferIds.insert(memHandle->getBufferId());
+
+    // No new packet is produced as we have now reached the limit of number of
+    // packets.
+    EXPECT_EQ(manager->queuePacket(frame, 30), Status::SUCCESS);
+    sleep(1);
+    EXPECT_THAT(memHandle->getTimeStamp(), 20);
+    EXPECT_THAT(activeBufferIds, Contains(memHandle->getBufferId()));
+}
+
+TEST(PixelStreamManagerTest, DoneWithPacketCallReleasesAPacket) {
+    int maxInFlightPackets = 1;
+    auto [mockEngine, manager] = CreateStreamManagerAndEngine(maxInFlightPackets);
+    std::set<int> activeBufferIds;
+
+    DefaultEvent e = DefaultEvent::generateEntryEvent(DefaultEvent::Phase::RUN);
+
+    ASSERT_EQ(manager->handleExecutionPhase(e), Status::SUCCESS);
+    std::vector<uint8_t> data(16 * 16 * 3, 100);
+    InputFrame frame(16, 16, PixelFormat::RGB, 16 * 3, &data[0]);
+
+    std::shared_ptr<MemHandle> memHandle;
+    EXPECT_CALL((*mockEngine), dispatchPacket)
+        .Times(2)
+        .WillRepeatedly(testing::DoAll(testing::SaveArg<0>(&memHandle), (Return(Status::SUCCESS))));
+
+    EXPECT_EQ(manager->queuePacket(frame, 10), Status::SUCCESS);
+    sleep(1);
+    ASSERT_NE(memHandle, nullptr);
+    activeBufferIds.insert(memHandle->getBufferId());
+    EXPECT_THAT(memHandle->getHardwareBuffer(), ContainsDataFromFrame(&frame));
+    EXPECT_THAT(memHandle->getTimeStamp(), 10);
+    EXPECT_THAT(memHandle->getStreamId(), 0);
+
+    // Check that new packet has not been dispatched as the old packet has not been released yet.
+    EXPECT_EQ(manager->queuePacket(frame, 20), Status::SUCCESS);
+    sleep(1);
+    ASSERT_NE(memHandle, nullptr);
+    EXPECT_THAT(memHandle->getTimeStamp(), 10);
+
+    EXPECT_THAT(manager->freePacket(memHandle->getBufferId()), Status::SUCCESS);
+    EXPECT_EQ(manager->queuePacket(frame, 30), Status::SUCCESS);
+    sleep(1);
+    ASSERT_NE(memHandle, nullptr);
+    EXPECT_THAT(memHandle->getTimeStamp(), 30);
+}
+
+TEST(PixelStreamManagerTest, EngineReceivesEndOfStreamCallbackOnStoppage) {
+    int maxInFlightPackets = 1;
+    auto [mockEngine, manager] = CreateStreamManagerAndEngine(maxInFlightPackets);
+
+    DefaultEvent e = DefaultEvent::generateEntryEvent(DefaultEvent::Phase::RUN);
+
+    ASSERT_EQ(manager->handleExecutionPhase(e), Status::SUCCESS);
+    std::vector<uint8_t> data(16 * 16 * 3, 100);
+    InputFrame frame(16, 16, PixelFormat::RGB, 16 * 3, &data[0]);
+
+    std::shared_ptr<MemHandle> memHandle;
+    EXPECT_CALL((*mockEngine), dispatchPacket)
+        .WillOnce(testing::DoAll(testing::SaveArg<0>(&memHandle), (Return(Status::SUCCESS))));
+
+    EXPECT_EQ(manager->queuePacket(frame, 10), Status::SUCCESS);
+    sleep(1);
+    ASSERT_NE(memHandle, nullptr);
+    EXPECT_THAT(memHandle->getHardwareBuffer(), ContainsDataFromFrame(&frame));
+    EXPECT_THAT(memHandle->getTimeStamp(), 10);
+    EXPECT_THAT(memHandle->getStreamId(), 0);
+    EXPECT_EQ(manager->handleStopImmediatePhase(e), Status::SUCCESS);
+    // handleStopImmediatePhase is non-blocking call, so wait for manager to finish freeing the
+    // packets.
+    sleep(1);
+}
+
+TEST(PixelStreamManagerTest, MultipleFreePacketReleasesPacketAfterClone) {
+    int maxInFlightPackets = 1;
+    auto [mockEngine, manager] = CreateStreamManagerAndEngine(maxInFlightPackets);
+
+    DefaultEvent e = DefaultEvent::generateEntryEvent(DefaultEvent::Phase::RUN);
+    ASSERT_EQ(manager->handleExecutionPhase(e), Status::SUCCESS);
+    std::vector<uint8_t> data(16 * 16 * 3, 100);
+    InputFrame frame(16, 16, PixelFormat::RGB, 16 * 3, &data[0]);
+
+    std::shared_ptr<MemHandle> memHandle;
+    EXPECT_CALL((*mockEngine), dispatchPacket)
+        .Times(2)
+        .WillRepeatedly(testing::DoAll(testing::SaveArg<0>(&memHandle), (Return(Status::SUCCESS))));
+
+    EXPECT_EQ(manager->queuePacket(frame, 10), Status::SUCCESS);
+    sleep(1);
+    ASSERT_NE(memHandle, nullptr);
+    EXPECT_THAT(memHandle->getHardwareBuffer(), ContainsDataFromFrame(&frame));
+    EXPECT_THAT(memHandle->getTimeStamp(), 10);
+    EXPECT_THAT(memHandle->getStreamId(), 0);
+
+    std::shared_ptr<MemHandle> clonedMemHandle = manager->clonePacket(memHandle);
+    ASSERT_NE(clonedMemHandle, nullptr);
+    EXPECT_THAT(clonedMemHandle->getTimeStamp(), 10);
+
+    // Free packet once.
+    EXPECT_THAT(manager->freePacket(memHandle->getBufferId()), Status::SUCCESS);
+
+    // Check that new packet has not been dispatched as the old packet has not been released yet.
+    EXPECT_EQ(manager->queuePacket(frame, 20), Status::SUCCESS);
+    sleep(1);
+    EXPECT_THAT(memHandle->getTimeStamp(), 10);
+
+    // Free packet second time, this should dispatch new packet.
+    EXPECT_THAT(manager->freePacket(memHandle->getBufferId()), Status::SUCCESS);
+    EXPECT_EQ(manager->queuePacket(frame, 30), Status::SUCCESS);
+    sleep(1);
+    ASSERT_NE(memHandle, nullptr);
+    EXPECT_THAT(memHandle->getTimeStamp(), 30);
+}
+
+
+}  // namespace
+}  // namespace stream_manager
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/tests/runner/stream_manager/SemanticManagerTest.cpp b/computepipe/tests/runner/stream_manager/SemanticManagerTest.cpp
new file mode 100644
index 0000000..9550cc1
--- /dev/null
+++ b/computepipe/tests/runner/stream_manager/SemanticManagerTest.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "EventGenerator.h"
+#include "MockEngine.h"
+#include "OutputConfig.pb.h"
+#include "RunnerComponent.h"
+#include "StreamEngineInterface.h"
+#include "StreamManager.h"
+#include "gmock/gmock-matchers.h"
+#include "types/Status.h"
+
+using namespace android::automotive::computepipe::runner::stream_manager;
+using namespace android::automotive::computepipe;
+using android::automotive::computepipe::runner::RunnerComponentInterface;
+using android::automotive::computepipe::runner::RunnerEvent;
+using android::automotive::computepipe::runner::generator::DefaultEvent;
+using testing::Return;
+
+class SemanticManagerTest : public ::testing::Test {
+  protected:
+    static constexpr uint32_t kMaxSemanticDataSize = 1024;
+    /**
+     * Setup for the test fixture to initialize the semantic manager
+     * After this, the semantic manager should be in RESET state.
+     */
+    void SetUp() override {
+    }
+    void TearDown() override {
+        if (mCurrentPacket) {
+            mCurrentPacket = nullptr;
+            ;
+        }
+    }
+
+    std::unique_ptr<StreamManager> SetupStreamManager(std::shared_ptr<MockEngine>& engine) {
+        proto::OutputConfig config;
+        config.set_type(proto::PacketType::SEMANTIC_DATA);
+        config.set_stream_name("semantic_stream");
+
+        return mFactory.getStreamManager(config, engine, 0);
+    }
+    StreamManagerFactory mFactory;
+    std::shared_ptr<MemHandle> mCurrentPacket;
+};
+
+/**
+ * Checks Packet Queing without start.
+ * Checks Packet Queuing with bad arguments.
+ * Checks successful packet queuing.
+ */
+TEST_F(SemanticManagerTest, PacketQueueTest) {
+    DefaultEvent e = DefaultEvent::generateEntryEvent(DefaultEvent::Phase::RUN);
+    std::shared_ptr<MockEngine> mockEngine = std::make_shared<MockEngine>();
+    std::unique_ptr<StreamManager> manager = SetupStreamManager(mockEngine);
+    ASSERT_EQ(manager->handleExecutionPhase(e), Status::SUCCESS);
+    std::string fakeData("FakeData");
+    uint32_t size = fakeData.size();
+    EXPECT_EQ(manager->queuePacket(nullptr, size, 0), Status::INVALID_ARGUMENT);
+    EXPECT_EQ(manager->queuePacket(fakeData.c_str(), kMaxSemanticDataSize + 1, 0),
+              Status::INVALID_ARGUMENT);
+    EXPECT_CALL((*mockEngine), dispatchPacket)
+        .WillOnce(testing::DoAll(testing::SaveArg<0>(&mCurrentPacket), (Return(Status::SUCCESS))));
+
+    manager->queuePacket(fakeData.c_str(), size, 0);
+    EXPECT_STREQ(mCurrentPacket->getData(), fakeData.c_str());
+}
diff --git a/computepipe/types/GraphState.h b/computepipe/types/GraphState.h
new file mode 100644
index 0000000..a5899b9
--- /dev/null
+++ b/computepipe/types/GraphState.h
@@ -0,0 +1,34 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_TYPES_GRAPHSTATE_H_
+#define COMPUTEPIPE_TYPES_GRAPHSTATE_H_
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+
+enum GraphState {
+    RESET = 0,
+    CONFIG_DONE,
+    RUNNING,
+    DONE,
+    ERR_HALT,
+};
+
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // COMPUTEPIPE_TYPES_GRAPHSTATE_H_
diff --git a/computepipe/types/Status.h b/computepipe/types/Status.h
new file mode 100644
index 0000000..af05c6a
--- /dev/null
+++ b/computepipe/types/Status.h
@@ -0,0 +1,43 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPUTEPIPE_TYPES_STATUS_H_
+#define COMPUTEPIPE_TYPES_STATUS_H_
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+
+enum Status {
+    SUCCESS = 0,
+    INTERNAL_ERROR,
+    INVALID_ARGUMENT,
+    ILLEGAL_STATE,
+    NO_MEMORY,
+    FATAL_ERROR,
+    STATUS_MAX,
+};
+
+enum PixelFormat {
+    RGB = 0,
+    RGBA,
+    GRAY,
+    PIXELFORMAT_MAX,
+};
+
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // COMPUTEPIPE_TYPES_STATUS_H_
diff --git a/evs/Android.bp b/evs/Android.bp
new file mode 100644
index 0000000..fee3461
--- /dev/null
+++ b/evs/Android.bp
@@ -0,0 +1,17 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+
+// Include the sub-makefiles
diff --git a/evs/Android.mk b/evs/Android.mk
deleted file mode 100644
index 01647b0..0000000
--- a/evs/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-# Include the sub-makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/evs/OWNERS b/evs/OWNERS
index a644193..cc4938d 100644
--- a/evs/OWNERS
+++ b/evs/OWNERS
@@ -2,4 +2,3 @@
 changyeon@google.com
 haoxiangl@google.com
 swan@google.com
-randolphs@google.com
diff --git a/evs/app/Android.mk b/evs/app/Android.mk
deleted file mode 100644
index cecbba5..0000000
--- a/evs/app/Android.mk
+++ /dev/null
@@ -1,83 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-##################################
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    evs_app.cpp \
-    EvsStateControl.cpp \
-    RenderBase.cpp \
-    RenderDirectView.cpp \
-    RenderTopView.cpp \
-    ConfigManager.cpp \
-    glError.cpp \
-    shader.cpp \
-    TexWrapper.cpp \
-    VideoTex.cpp \
-    StreamHandler.cpp \
-    WindowSurface.cpp \
-    FormatConvert.cpp \
-    RenderPixelCopy.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libbinder \
-    libcutils \
-    liblog \
-    libutils \
-    libui \
-    libgui \
-    libhidlbase \
-    libhidltransport \
-    libEGL \
-    libGLESv2 \
-    libhardware \
-    libpng \
-    android.hardware.automotive.evs@1.0 \
-    android.hardware.automotive.vehicle@2.0 \
-
-LOCAL_STATIC_LIBRARIES := \
-    libmath \
-    libjsoncpp \
-
-LOCAL_STRIP_MODULE := keep_symbols
-
-LOCAL_INIT_RC := evs_app.rc
-
-LOCAL_MODULE:= evs_app
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS += -DLOG_TAG=\"EvsApp\"
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
-include $(BUILD_EXECUTABLE)
-
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := config.json
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/automotive/evs
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CarFromTop.png
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/automotive/evs
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := LabeledChecker.png
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/automotive/evs
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := evs_app_default_resources
-LOCAL_REQUIRED_MODULES := \
-    config.json \
-    CarFromTop.png \
-    LabeledChecker.png
-include $(BUILD_PHONY_PACKAGE)
\ No newline at end of file
diff --git a/evs/app/ConfigManager.cpp b/evs/app/ConfigManager.cpp
deleted file mode 100644
index 07e570d..0000000
--- a/evs/app/ConfigManager.cpp
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "ConfigManager.h"
-
-#include "json/json.h"
-
-#include <fstream>
-#include <math.h>
-#include <assert.h>
-
-
-static const float kDegreesToRadians = M_PI / 180.0f;
-
-
-static float normalizeToPlusMinus180degrees(float theta) {
-    const float wraps = floor((theta+180.0f) / 360.0f);
-    return theta - wraps*360.0f;
-}
-
-
-static bool readChildNodeAsFloat(const char* groupName,
-                                 const Json::Value& parentNode,
-                                 const char* childName,
-                                 float* value) {
-    // Must have a place to put the value!
-    assert(value);
-
-    Json::Value childNode = parentNode[childName];
-    if (!childNode.isNumeric()) {
-        printf("Missing or invalid field %s in record %s", childName, groupName);
-        return false;
-    }
-
-    *value = childNode.asFloat();
-    return true;
-}
-
-
-bool ConfigManager::initialize(const char* configFileName)
-{
-    bool complete = true;
-
-    // Set up a stream to read in the input file
-    std::ifstream configStream(configFileName);
-
-    // Parse the stream into JSON objects
-    Json::Reader reader;
-    Json::Value rootNode;
-    bool parseOk = reader.parse(configStream, rootNode, false /* don't need comments */);
-    if (!parseOk) {
-        printf("Failed to read configuration file %s\n", configFileName);
-        printf("%s\n", reader.getFormatedErrorMessages().c_str());
-        return false;
-    }
-
-
-    //
-    // Read car information
-    //
-    {
-        Json::Value car = rootNode["car"];
-        if (!car.isObject()) {
-            printf("Invalid configuration format -- we expect a car description\n");
-            return false;
-        }
-        complete &= readChildNodeAsFloat("car", car, "width",       &mCarWidth);
-        complete &= readChildNodeAsFloat("car", car, "wheelBase",   &mWheelBase);
-        complete &= readChildNodeAsFloat("car", car, "frontExtent", &mFrontExtent);
-        complete &= readChildNodeAsFloat("car", car, "rearExtent",  &mRearExtent);
-    }
-
-
-    //
-    // Read display layout information
-    //
-    {
-        Json::Value displayNode = rootNode["display"];
-        if (!displayNode.isObject()) {
-            printf("Invalid configuration format -- we expect a display description\n");
-            return false;
-        }
-        complete &= readChildNodeAsFloat("display", displayNode, "frontRange", &mFrontRangeInCarSpace);
-        complete &= readChildNodeAsFloat("display", displayNode, "rearRange",  &mRearRangeInCarSpace);
-    }
-
-
-    //
-    // Car top view texture properties for top down view
-    //
-    {
-        Json::Value graphicNode = rootNode["graphic"];
-        if (!graphicNode.isObject()) {
-            printf("Invalid configuration format -- we expect a graphic description\n");
-            return false;
-        }
-        complete &= readChildNodeAsFloat("graphic", graphicNode, "frontPixel", &mCarGraphicFrontPixel);
-        complete &= readChildNodeAsFloat("display", graphicNode, "rearPixel",  &mCarGraphicRearPixel);
-    }
-
-
-    //
-    // Read camera information
-    // NOTE:  Missing positions and angles are not reported, but instead default to zero
-    //
-    {
-        Json::Value cameraArray = rootNode["cameras"];
-        if (!cameraArray.isArray()) {
-            printf("Invalid configuration format -- we expect an array of cameras\n");
-            return false;
-        }
-
-        mCameras.reserve(cameraArray.size());
-        for (auto&& node: cameraArray) {
-            // Get data from the configuration file
-            Json::Value nameNode = node.get("cameraId", "MISSING");
-            const char *cameraId = nameNode.asCString();
-
-            Json::Value usageNode = node.get("function", "");
-            const char *function = usageNode.asCString();
-
-            float yaw   = node.get("yaw", 0).asFloat();
-            float pitch = node.get("pitch", 0).asFloat();
-            float hfov  = node.get("hfov", 0).asFloat();
-            float vfov  = node.get("vfov", 0).asFloat();
-
-            // Wrap the direction angles to be in the 180deg to -180deg range
-            // Rotate 180 in yaw if necessary to flip the pitch into the +/-90degree range
-            pitch = normalizeToPlusMinus180degrees(pitch);
-            if (pitch > 90.0f) {
-                yaw += 180.0f;
-                pitch = 180.0f - pitch;
-            }
-            if (pitch < -90.0f) {
-                yaw += 180.0f;
-                pitch = -180.0f + pitch;
-            }
-            yaw = normalizeToPlusMinus180degrees(yaw);
-
-            // Range check the FOV values to ensure they are postive and less than 180degrees
-            if (hfov > 179.0f) {
-                printf("Pathological horizontal field of view %f clamped to 179 degrees\n", hfov);
-                hfov = 179.0f;
-            }
-            if (hfov < 1.0f) {
-                printf("Pathological horizontal field of view %f clamped to 1 degree\n", hfov);
-                hfov = 1.0f;
-            }
-            if (vfov > 179.0f) {
-                printf("Pathological horizontal field of view %f clamped to 179 degrees\n", vfov);
-                vfov = 179.0f;
-            }
-            if (vfov < 1.0f) {
-                printf("Pathological horizontal field of view %f clamped to 1 degree\n", vfov);
-                vfov = 1.0f;
-            }
-
-            // Store the camera info (converting degrees to radians in the process)
-            CameraInfo info;
-            info.position[0] = node.get("x", 0).asFloat();
-            info.position[1] = node.get("y", 0).asFloat();
-            info.position[2] = node.get("z", 0).asFloat();
-            info.yaw         = yaw   * kDegreesToRadians;
-            info.pitch       = pitch * kDegreesToRadians;
-            info.hfov        = hfov  * kDegreesToRadians;
-            info.vfov        = vfov  * kDegreesToRadians;
-            info.cameraId    = cameraId;
-            info.function    = function;
-
-            mCameras.push_back(info);
-        }
-    }
-
-    // If we got this far, we were successful as long as we found all our child fields
-    return complete;
-}
diff --git a/evs/app/ConfigManager.h b/evs/app/ConfigManager.h
deleted file mode 100644
index 0d24919..0000000
--- a/evs/app/ConfigManager.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef CONFIG_MANAGER_H
-#define CONFIG_MANAGER_H
-
-#include <vector>
-#include <string>
-
-
-class ConfigManager {
-public:
-    struct CameraInfo {
-        std::string cameraId = "";  // The name of the camera from the point of view of the HAL
-        std::string function = "";  // The expected use for this camera ("reverse", "left", "right")
-        float position[3] = {0};    // x, y, z -> right, fwd, up in the units of car space
-        float yaw   = 0;    // radians positive to the left (right hand rule about global z axis)
-        float pitch = 0;    // positive upward (ie: right hand rule about local x axis)
-        float hfov  = 0;    // radians
-        float vfov  = 0;    // radians
-    };
-
-    bool initialize(const char* configFileName);
-
-    // World space dimensions of the car
-    float getCarWidth() const   { return mCarWidth; };
-    float getCarLength() const  { return mWheelBase + mFrontExtent + mRearExtent; };
-    float getWheelBase() const  { return mWheelBase; };
-
-    // Car space (world space centered on the rear axel) edges of the car
-    float getFrontLocation() const  { return mWheelBase + mFrontExtent; };
-    float getRearLocation() const   { return -mRearExtent; };
-    float getRightLocation() const  { return mCarWidth*0.5f; };
-    float getLeftLocation() const   { return -mCarWidth*0.5f; };
-
-    // Where are the edges of the top down display in car space?
-    float getDisplayTopLocation() const {
-        // From the rear axel (origin) to the front bumper, and then beyond by the front range
-        return mWheelBase + mFrontExtent + mFrontRangeInCarSpace;
-    };
-    float getDisplayBottomLocation() const {
-        // From the rear axel (origin) to the back bumper, and then beyond by the back range
-        return -mRearExtent - mRearRangeInCarSpace;
-    };
-    float getDisplayRightLocation(float aspectRatio) const   {
-        // Given the display aspect ratio (width over height), how far can we see to the right?
-        return (getDisplayTopLocation() - getDisplayBottomLocation()) * 0.5f * aspectRatio;
-    };
-    float getDisplayLeftLocation(float aspectRatio) const {
-        // Given the display aspect ratio (width over height), how far can we see to the left?
-        return -getDisplayRightLocation(aspectRatio);
-    };
-
-    // At which texel (vertically in the image) are the front and rear bumpers of the car?
-    float carGraphicFrontPixel() const      { return mCarGraphicFrontPixel; };
-    float carGraphicRearPixel() const       { return mCarGraphicRearPixel; };
-
-    const std::vector<CameraInfo>& getCameras() const   { return mCameras; };
-
-private:
-    // Camera information
-    std::vector<CameraInfo> mCameras;
-
-    // Car body information (assumes front wheel steering and origin at center of rear axel)
-    // Note that units aren't specified and don't matter as long as all length units are consistent
-    // within the JSON file from which we parse.  That is, if everything is in meters, that's fine.
-    // Everything in mm?  That's fine too.
-    float mCarWidth;
-    float mWheelBase;
-    float mFrontExtent;
-    float mRearExtent;
-
-    // Display information
-    float    mFrontRangeInCarSpace;     // How far the display extends in front of the car
-    float    mRearRangeInCarSpace;      // How far the display extends behind the car
-
-    // Top view car image information
-    float mCarGraphicFrontPixel;    // How many pixels from the top of the image does the car start
-    float mCarGraphicRearPixel;     // How many pixels from the top of the image does the car end
-};
-
-#endif // CONFIG_MANAGER_H
\ No newline at end of file
diff --git a/evs/app/EvsStateControl.cpp b/evs/app/EvsStateControl.cpp
deleted file mode 100644
index 8922260..0000000
--- a/evs/app/EvsStateControl.cpp
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "EvsStateControl.h"
-#include "RenderDirectView.h"
-#include "RenderTopView.h"
-#include "RenderPixelCopy.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include <log/log.h>
-#include <inttypes.h>
-#include <utils/SystemClock.h>
-#include <binder/IServiceManager.h>
-
-static bool isSfReady() {
-    const android::String16 serviceName("SurfaceFlinger");
-    return android::defaultServiceManager()->checkService(serviceName) != nullptr;
-}
-
-// TODO:  Seems like it'd be nice if the Vehicle HAL provided such helpers (but how & where?)
-inline constexpr VehiclePropertyType getPropType(VehicleProperty prop) {
-    return static_cast<VehiclePropertyType>(
-            static_cast<int32_t>(prop)
-            & static_cast<int32_t>(VehiclePropertyType::MASK));
-}
-
-
-EvsStateControl::EvsStateControl(android::sp <IVehicle>       pVnet,
-                                 android::sp <IEvsEnumerator> pEvs,
-                                 android::sp <IEvsDisplay>    pDisplay,
-                                 const ConfigManager&         config) :
-    mVehicle(pVnet),
-    mEvs(pEvs),
-    mDisplay(pDisplay),
-    mConfig(config),
-    mCurrentState(OFF) {
-
-    // Initialize the property value containers we'll be updating (they'll be zeroed by default)
-    static_assert(getPropType(VehicleProperty::GEAR_SELECTION) == VehiclePropertyType::INT32,
-                  "Unexpected type for GEAR_SELECTION property");
-    static_assert(getPropType(VehicleProperty::TURN_SIGNAL_STATE) == VehiclePropertyType::INT32,
-                  "Unexpected type for TURN_SIGNAL_STATE property");
-
-    mGearValue.prop       = static_cast<int32_t>(VehicleProperty::GEAR_SELECTION);
-    mTurnSignalValue.prop = static_cast<int32_t>(VehicleProperty::TURN_SIGNAL_STATE);
-
-#if 1
-    // This way we only ever deal with cameras which exist in the system
-    // Build our set of cameras for the states we support
-    ALOGD("Requesting camera list");
-    mEvs->getCameraList([this, &config](hidl_vec<CameraDesc> cameraList) {
-                            ALOGI("Camera list callback received %zu cameras",
-                                  cameraList.size());
-                            for (auto&& cam: cameraList) {
-                                ALOGD("Found camera %s", cam.cameraId.c_str());
-                                bool cameraConfigFound = false;
-
-                                // Check our configuration for information about this camera
-                                // Note that a camera can have a compound function string
-                                // such that a camera can be "right/reverse" and be used for both.
-                                // If more than one camera is listed for a given function, we'll
-                                // list all of them and let the UX/rendering logic use one, some
-                                // or all of them as appropriate.
-                                for (auto&& info: config.getCameras()) {
-                                    if (cam.cameraId == info.cameraId) {
-                                        // We found a match!
-                                        if (info.function.find("reverse") != std::string::npos) {
-                                            mCameraList[State::REVERSE].push_back(info);
-                                        }
-                                        if (info.function.find("right") != std::string::npos) {
-                                            mCameraList[State::RIGHT].push_back(info);
-                                        }
-                                        if (info.function.find("left") != std::string::npos) {
-                                            mCameraList[State::LEFT].push_back(info);
-                                        }
-                                        if (info.function.find("park") != std::string::npos) {
-                                            mCameraList[State::PARKING].push_back(info);
-                                        }
-                                        cameraConfigFound = true;
-                                        break;
-                                    }
-                                }
-                                if (!cameraConfigFound) {
-                                    ALOGW("No config information for hardware camera %s",
-                                          cam.cameraId.c_str());
-                                }
-                            }
-                        }
-    );
-#else // This way we use placeholders for cameras in the configuration but not reported by EVS
-    // Build our set of cameras for the states we support
-    ALOGD("Requesting camera list");
-    for (auto&& info: config.getCameras()) {
-        if (info.function.find("reverse") != std::string::npos) {
-            mCameraList[State::REVERSE].push_back(info);
-        }
-        if (info.function.find("right") != std::string::npos) {
-            mCameraList[State::RIGHT].push_back(info);
-        }
-        if (info.function.find("left") != std::string::npos) {
-            mCameraList[State::LEFT].push_back(info);
-        }
-        if (info.function.find("park") != std::string::npos) {
-            mCameraList[State::PARKING].push_back(info);
-        }
-    }
-#endif
-
-    ALOGD("State controller ready");
-}
-
-
-bool EvsStateControl::startUpdateLoop() {
-    // Create the thread and report success if it gets started
-    mRenderThread = std::thread([this](){ updateLoop(); });
-    return mRenderThread.joinable();
-}
-
-
-void EvsStateControl::postCommand(const Command& cmd) {
-    // Push the command onto the queue watched by updateLoop
-    mLock.lock();
-    mCommandQueue.push(cmd);
-    mLock.unlock();
-
-    // Send a signal to wake updateLoop in case it is asleep
-    mWakeSignal.notify_all();
-}
-
-
-void EvsStateControl::updateLoop() {
-    ALOGD("Starting EvsStateControl update loop");
-
-    bool run = true;
-    while (run) {
-        // Process incoming commands
-        {
-            std::lock_guard <std::mutex> lock(mLock);
-            while (!mCommandQueue.empty()) {
-                const Command& cmd = mCommandQueue.front();
-                switch (cmd.operation) {
-                case Op::EXIT:
-                    run = false;
-                    break;
-                case Op::CHECK_VEHICLE_STATE:
-                    // Just running selectStateForCurrentConditions below will take care of this
-                    break;
-                case Op::TOUCH_EVENT:
-                    // Implement this given the x/y location of the touch event
-                    break;
-                }
-                mCommandQueue.pop();
-            }
-        }
-
-        // Review vehicle state and choose an appropriate renderer
-        if (!selectStateForCurrentConditions()) {
-            ALOGE("selectStateForCurrentConditions failed so we're going to die");
-            break;
-        }
-
-        // If we have an active renderer, give it a chance to draw
-        if (mCurrentRenderer) {
-            // Get the output buffer we'll use to display the imagery
-            BufferDesc tgtBuffer = {};
-            mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc& buff) {
-                                          tgtBuffer = buff;
-                                      }
-            );
-
-            if (tgtBuffer.memHandle == nullptr) {
-                ALOGE("Didn't get requested output buffer -- skipping this frame.");
-            } else {
-                // Generate our output image
-                if (!mCurrentRenderer->drawFrame(tgtBuffer)) {
-                    // If drawing failed, we want to exit quickly so an app restart can happen
-                    run = false;
-                }
-
-                // Send the finished image back for display
-                mDisplay->returnTargetBufferForDisplay(tgtBuffer);
-            }
-        } else {
-            // No active renderer, so sleep until somebody wakes us with another command
-            std::unique_lock<std::mutex> lock(mLock);
-            mWakeSignal.wait(lock);
-        }
-    }
-
-    ALOGW("EvsStateControl update loop ending");
-
-    // TODO:  Fix it so we can exit cleanly from the main thread instead
-    printf("Shutting down app due to state control loop ending\n");
-    ALOGE("KILLING THE APP FROM THE EvsStateControl LOOP ON DRAW FAILURE!!!");
-    exit(1);
-}
-
-
-bool EvsStateControl::selectStateForCurrentConditions() {
-    static int32_t sDummyGear   = int32_t(VehicleGear::GEAR_REVERSE);
-    static int32_t sDummySignal = int32_t(VehicleTurnSignal::NONE);
-
-    if (mVehicle != nullptr) {
-        // Query the car state
-        if (invokeGet(&mGearValue) != StatusCode::OK) {
-            ALOGE("GEAR_SELECTION not available from vehicle.  Exiting.");
-            return false;
-        }
-        if ((mTurnSignalValue.prop == 0) || (invokeGet(&mTurnSignalValue) != StatusCode::OK)) {
-            // Silently treat missing turn signal state as no turn signal active
-            mTurnSignalValue.value.int32Values.setToExternal(&sDummySignal, 1);
-            mTurnSignalValue.prop = 0;
-        }
-    } else {
-        // While testing without a vehicle, behave as if we're in reverse for the first 20 seconds
-        static const int kShowTime = 20;    // seconds
-
-        // See if it's time to turn off the default reverse camera
-        static std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
-        std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
-        if (std::chrono::duration_cast<std::chrono::seconds>(now - start).count() > kShowTime) {
-            // Switch to drive (which should turn off the reverse camera)
-            sDummyGear = int32_t(VehicleGear::GEAR_DRIVE);
-        }
-
-        // Build the dummy vehicle state values (treating single values as 1 element vectors)
-        mGearValue.value.int32Values.setToExternal(&sDummyGear, 1);
-        mTurnSignalValue.value.int32Values.setToExternal(&sDummySignal, 1);
-    }
-
-    // Choose our desired EVS state based on the current car state
-    // TODO:  Update this logic, and consider user input when choosing if a view should be presented
-    State desiredState = OFF;
-    if (mGearValue.value.int32Values[0] == int32_t(VehicleGear::GEAR_REVERSE)) {
-        desiredState = REVERSE;
-    } else if (mTurnSignalValue.value.int32Values[0] == int32_t(VehicleTurnSignal::RIGHT)) {
-        desiredState = RIGHT;
-    } else if (mTurnSignalValue.value.int32Values[0] == int32_t(VehicleTurnSignal::LEFT)) {
-        desiredState = LEFT;
-    } else if (mGearValue.value.int32Values[0] == int32_t(VehicleGear::GEAR_PARK)) {
-        desiredState = PARKING;
-    }
-
-    // Apply the desire state
-    return configureEvsPipeline(desiredState);
-}
-
-
-StatusCode EvsStateControl::invokeGet(VehiclePropValue *pRequestedPropValue) {
-    StatusCode status = StatusCode::TRY_AGAIN;
-
-    // Call the Vehicle HAL, which will block until the callback is complete
-    mVehicle->get(*pRequestedPropValue,
-                  [pRequestedPropValue, &status]
-                  (StatusCode s, const VehiclePropValue& v) {
-                       status = s;
-                       if (s == StatusCode::OK) {
-                           *pRequestedPropValue = v;
-                       }
-                  }
-    );
-
-    return status;
-}
-
-
-bool EvsStateControl::configureEvsPipeline(State desiredState) {
-    static bool isGlReady = false;
-
-    if (mCurrentState == desiredState) {
-        // Nothing to do here...
-        return true;
-    }
-
-    ALOGD("Switching to state %d.", desiredState);
-    ALOGD("  Current state %d has %zu cameras", mCurrentState,
-          mCameraList[mCurrentState].size());
-    ALOGD("  Desired state %d has %zu cameras", desiredState,
-          mCameraList[desiredState].size());
-
-    if (!isGlReady && !isSfReady()) {
-        // Graphics is not ready yet; using CPU renderer.
-        if (mCameraList[desiredState].size() >= 1) {
-            mDesiredRenderer = std::make_unique<RenderPixelCopy>(mEvs,
-                                                                 mCameraList[desiredState][0]);
-            if (!mDesiredRenderer) {
-                ALOGE("Failed to construct Pixel Copy renderer.  Skipping state change.");
-                return false;
-            }
-        } else {
-            ALOGD("Unsupported, desiredState %d has %u cameras.",
-                  desiredState, static_cast<unsigned int>(mCameraList[desiredState].size()));
-        }
-    } else {
-        // Assumes that SurfaceFlinger is available always after being launched.
-
-        // Do we need a new direct view renderer?
-        if (mCameraList[desiredState].size() == 1) {
-            // We have a camera assigned to this state for direct view.
-            mDesiredRenderer = std::make_unique<RenderDirectView>(mEvs,
-                                                                  mCameraList[desiredState][0]);
-            if (!mDesiredRenderer) {
-                ALOGE("Failed to construct direct renderer.  Skipping state change.");
-                return false;
-            }
-        } else if (mCameraList[desiredState].size() > 1 || desiredState == PARKING) {
-            mDesiredRenderer = std::make_unique<RenderTopView>(mEvs,
-                                                               mCameraList[desiredState],
-                                                               mConfig);
-            if (!mDesiredRenderer) {
-                ALOGE("Failed to construct top view renderer.  Skipping state change.");
-                return false;
-            }
-        } else {
-            ALOGD("Unsupported, desiredState %d has %u cameras.",
-                  desiredState, static_cast<unsigned int>(mCameraList[desiredState].size()));
-        }
-
-        // GL renderer is now ready.
-        isGlReady = true;
-    }
-
-    // Since we're changing states, shut down the current renderer
-    if (mCurrentRenderer != nullptr) {
-        mCurrentRenderer->deactivate();
-        mCurrentRenderer = nullptr; // It's a smart pointer, so destructs on assignment to null
-    }
-
-    // Now set the display state based on whether we have a video feed to show
-    if (mDesiredRenderer == nullptr) {
-        ALOGD("Turning off the display");
-        mDisplay->setDisplayState(DisplayState::NOT_VISIBLE);
-    } else {
-        mCurrentRenderer = std::move(mDesiredRenderer);
-
-        // Start the camera stream
-        ALOGD("EvsStartCameraStreamTiming start time: %" PRId64 "ms", android::elapsedRealtime());
-        if (!mCurrentRenderer->activate()) {
-            ALOGE("New renderer failed to activate");
-            return false;
-        }
-
-        // Activate the display
-        ALOGD("EvsActivateDisplayTiming start time: %" PRId64 "ms", android::elapsedRealtime());
-        Return<EvsResult> result = mDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME);
-        if (result != EvsResult::OK) {
-            ALOGE("setDisplayState returned an error (%d)", (EvsResult)result);
-            return false;
-        }
-    }
-
-    // Record our current state
-    ALOGI("Activated state %d.", desiredState);
-    mCurrentState = desiredState;
-
-    return true;
-}
diff --git a/evs/app/EvsStateControl.h b/evs/app/EvsStateControl.h
deleted file mode 100644
index 9f7f967..0000000
--- a/evs/app/EvsStateControl.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CAR_EVS_APP_EVSSTATECONTROL_H
-#define CAR_EVS_APP_EVSSTATECONTROL_H
-
-#include "StreamHandler.h"
-#include "ConfigManager.h"
-#include "RenderBase.h"
-
-#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
-#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
-#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
-#include <android/hardware/automotive/evs/1.0/IEvsCamera.h>
-
-#include <thread>
-
-
-using namespace ::android::hardware::automotive::evs::V1_0;
-using namespace ::android::hardware::automotive::vehicle::V2_0;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_handle;
-using ::android::sp;
-
-
-/*
- * This class runs the main update loop for the EVS application.  It will sleep when it has
- * nothing to do.  It provides a thread safe way for other threads to wake it and pass commands
- * to it.
- */
-class EvsStateControl {
-public:
-    EvsStateControl(android::sp <IVehicle>       pVnet,
-                    android::sp <IEvsEnumerator> pEvs,
-                    android::sp <IEvsDisplay>    pDisplay,
-                    const ConfigManager&         config);
-
-    enum State {
-        OFF = 0,
-        REVERSE,
-        LEFT,
-        RIGHT,
-        PARKING,
-        NUM_STATES  // Must come last
-    };
-
-    enum class Op {
-        EXIT,
-        CHECK_VEHICLE_STATE,
-        TOUCH_EVENT,
-    };
-
-    struct Command {
-        Op          operation;
-        uint32_t    arg1;
-        uint32_t    arg2;
-    };
-
-    // This spawns a new thread that is expected to run continuously
-    bool startUpdateLoop();
-
-    // Safe to be called from other threads
-    void postCommand(const Command& cmd);
-
-private:
-    void updateLoop();
-    StatusCode invokeGet(VehiclePropValue *pRequestedPropValue);
-    bool selectStateForCurrentConditions();
-    bool configureEvsPipeline(State desiredState);  // Only call from one thread!
-
-    sp<IVehicle>                mVehicle;
-    sp<IEvsEnumerator>          mEvs;
-    sp<IEvsDisplay>             mDisplay;
-    const ConfigManager&        mConfig;
-
-    VehiclePropValue            mGearValue;
-    VehiclePropValue            mTurnSignalValue;
-
-    State                       mCurrentState = OFF;
-
-    std::vector<ConfigManager::CameraInfo>  mCameraList[NUM_STATES];
-    std::unique_ptr<RenderBase> mCurrentRenderer;
-    std::unique_ptr<RenderBase> mDesiredRenderer;
-
-    std::thread                 mRenderThread;  // The thread that runs the main rendering loop
-
-    // Other threads may want to spur us into action, so we provide a thread safe way to do that
-    std::mutex                  mLock;
-    std::condition_variable     mWakeSignal;
-    std::queue<Command>         mCommandQueue;
-};
-
-
-#endif //CAR_EVS_APP_EVSSTATECONTROL_H
diff --git a/evs/app/FormatConvert.cpp b/evs/app/FormatConvert.cpp
deleted file mode 100644
index bd83ba3..0000000
--- a/evs/app/FormatConvert.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "FormatConvert.h"
-
-
-// Round up to the nearest multiple of the given alignment value
-template<unsigned alignment>
-int align(int value) {
-    static_assert((alignment && !(alignment & (alignment - 1))),
-                  "alignment must be a power of 2");
-
-    unsigned mask = alignment - 1;
-    return (value + mask) & ~mask;
-}
-
-
-// Limit the given value to the provided range.  :)
-static inline float clamp(float v, float min, float max) {
-    if (v < min) return min;
-    if (v > max) return max;
-    return v;
-}
-
-
-static uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const unsigned char Vin) {
-    // Don't use this if you want to see the best performance.  :)
-    // Better to do this in a pixel shader if we really have to, but on actual
-    // embedded hardware we expect to be able to texture directly from the YUV data
-    float U = Uin - 128.0f;
-    float V = Vin - 128.0f;
-
-    float Rf = Y + 1.140f*V;
-    float Gf = Y - 0.395f*U - 0.581f*V;
-    float Bf = Y + 2.032f*U;
-    unsigned char R = (unsigned char)clamp(Rf, 0.0f, 255.0f);
-    unsigned char G = (unsigned char)clamp(Gf, 0.0f, 255.0f);
-    unsigned char B = (unsigned char)clamp(Bf, 0.0f, 255.0f);
-
-    return (R      ) |
-           (G <<  8) |
-           (B << 16) |
-           0xFF000000;  // Fill the alpha channel with ones
-}
-
-
-void copyNV21toRGB32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels)
-{
-    // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
-    // U/V array.  It assumes an even width and height for the overall image, and a horizontal
-    // stride that is an even multiple of 16 bytes for both the Y and UV arrays.
-    unsigned strideLum = align<16>(width);
-    unsigned sizeY = strideLum * height;
-    unsigned strideColor = strideLum;   // 1/2 the samples, but two interleaved channels
-    unsigned offsetUV = sizeY;
-
-    uint8_t* srcY = src;
-    uint8_t* srcUV = src+offsetUV;
-
-    for (unsigned r = 0; r < height; r++) {
-        // Note that we're walking the same UV row twice for even/odd luminance rows
-        uint8_t* rowY  = srcY  + r*strideLum;
-        uint8_t* rowUV = srcUV + (r/2 * strideColor);
-
-        uint32_t* rowDest = dst + r*dstStridePixels;
-
-        for (unsigned c = 0; c < width; c++) {
-            unsigned uCol = (c & ~1);   // uCol is always even and repeats 1:2 with Y values
-            unsigned vCol = uCol | 1;   // vCol is always odd
-            rowDest[c] = yuvToRgbx(rowY[c], rowUV[uCol], rowUV[vCol]);
-        }
-    }
-}
-
-
-void copyYV12toRGB32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels)
-{
-    // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
-    // by another 1/2 x 1/2 V array.  It assumes an even width and height for the overall image,
-    // and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
-    // and V arrays.
-    unsigned strideLum = align<16>(width);
-    unsigned sizeY = strideLum * height;
-    unsigned strideColor = align<16>(strideLum/2);
-    unsigned sizeColor = strideColor * height/2;
-    unsigned offsetU = sizeY;
-    unsigned offsetV = sizeY + sizeColor;
-
-    uint8_t* srcY = src;
-    uint8_t* srcU = src+offsetU;
-    uint8_t* srcV = src+offsetV;
-
-    for (unsigned r = 0; r < height; r++) {
-        // Note that we're walking the same U and V rows twice for even/odd luminance rows
-        uint8_t* rowY = srcY + r*strideLum;
-        uint8_t* rowU = srcU + (r/2 * strideColor);
-        uint8_t* rowV = srcV + (r/2 * strideColor);
-
-        uint32_t* rowDest = dst + r*dstStridePixels;
-
-        for (unsigned c = 0; c < width; c++) {
-            rowDest[c] = yuvToRgbx(rowY[c], rowU[c], rowV[c]);
-        }
-    }
-}
-
-
-void copyYUYVtoRGB32(unsigned width, unsigned height,
-                     uint8_t* src, unsigned srcStridePixels,
-                     uint32_t* dst, unsigned dstStridePixels)
-{
-    uint32_t* srcWords = (uint32_t*)src;
-
-    const int srcRowPadding32 = srcStridePixels/2 - width/2;  // 2 bytes per pixel, 4 bytes per word
-    const int dstRowPadding32 = dstStridePixels   - width;    // 4 bytes per pixel, 4 bytes per word
-
-    for (unsigned r = 0; r < height; r++) {
-        for (unsigned c = 0; c < width/2; c++) {
-            // Note:  we're walking two pixels at a time here (even/odd)
-            uint32_t srcPixel = *srcWords++;
-
-            uint8_t Y1 = (srcPixel)       & 0xFF;
-            uint8_t U  = (srcPixel >> 8)  & 0xFF;
-            uint8_t Y2 = (srcPixel >> 16) & 0xFF;
-            uint8_t V  = (srcPixel >> 24) & 0xFF;
-
-            // On the RGB output, we're writing one pixel at a time
-            *(dst+0) = yuvToRgbx(Y1, U, V);
-            *(dst+1) = yuvToRgbx(Y2, U, V);
-            dst += 2;
-        }
-
-        // Skip over any extra data or end of row alignment padding
-        srcWords += srcRowPadding32;
-        dst += dstRowPadding32;
-    }
-}
-
-
-void copyMatchedInterleavedFormats(unsigned width, unsigned height,
-                                   void* src, unsigned srcStridePixels,
-                                   void* dst, unsigned dstStridePixels,
-                                   unsigned pixelSize) {
-    for (unsigned row = 0; row < height; row++) {
-        // Copy the entire row of pixel data
-        memcpy(dst, src, width * pixelSize);
-
-        // Advance to the next row (keeping in mind that stride here is in units of pixels)
-        src = (uint8_t*)src + srcStridePixels * pixelSize;
-        dst = (uint8_t*)dst + dstStridePixels * pixelSize;
-    }
-}
diff --git a/evs/app/FormatConvert.h b/evs/app/FormatConvert.h
deleted file mode 100644
index 3ff1eec..0000000
--- a/evs/app/FormatConvert.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef EVS_VTS_FORMATCONVERT_H
-#define EVS_VTS_FORMATCONVERT_H
-
-#include <queue>
-#include <stdint.h>
-
-
-// Given an image buffer in NV21 format (HAL_PIXEL_FORMAT_YCRCB_420_SP), output 32bit RGBx values.
-// The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
-// U/V array.  It assumes an even width and height for the overall image, and a horizontal
-// stride that is an even multiple of 16 bytes for both the Y and UV arrays.
-void copyNV21toRGB32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels);
-
-
-// Given an image buffer in YV12 format (HAL_PIXEL_FORMAT_YV12), output 32bit RGBx values.
-// The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
-// by another 1/2 x 1/2 V array.  It assumes an even width and height for the overall image,
-// and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
-// and V arrays.
-void copyYV12toRGB32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels);
-
-
-// Given an image buffer in YUYV format (HAL_PIXEL_FORMAT_YCBCR_422_I), output 32bit RGBx values.
-// The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
-// U/V array.  It assumes an even width and height for the overall image, and a horizontal
-// stride that is an even multiple of 16 bytes for both the Y and UV arrays.
-void copyYUYVtoRGB32(unsigned width, unsigned height,
-                     uint8_t* src, unsigned srcStrideBytes,
-                     uint32_t* dst, unsigned dstStrideBytes);
-
-
-// Given an simple rectangular image buffer with an integer number of bytes per pixel,
-// copy the pixel values into a new rectangular buffer (potentially with a different stride).
-// This is typically used to copy RGBx data into an RGBx output buffer.
-void copyMatchedInterleavedFormats(unsigned width, unsigned height,
-                                   void* src, unsigned srcStridePixels,
-                                   void* dst, unsigned dstStridePixels,
-                                   unsigned pixelSize);
-
-#endif // EVS_VTS_FORMATCONVERT_H
diff --git a/evs/app/RenderBase.cpp b/evs/app/RenderBase.cpp
deleted file mode 100644
index cb6aa93..0000000
--- a/evs/app/RenderBase.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "RenderBase.h"
-#include "glError.h"
-
-#include <log/log.h>
-#include <ui/GraphicBuffer.h>
-
-// Eventually we shouldn't need this dependency, but for now the
-// graphics allocator interface isn't fully supported on all platforms
-// and this is our work around.
-using ::android::GraphicBuffer;
-
-
-// OpenGL state shared among all renderers
-EGLDisplay   RenderBase::sDisplay = EGL_NO_DISPLAY;
-EGLContext   RenderBase::sContext = EGL_NO_CONTEXT;
-EGLSurface   RenderBase::sDummySurface = EGL_NO_SURFACE;
-GLuint       RenderBase::sFrameBuffer = -1;
-GLuint       RenderBase::sColorBuffer = -1;
-GLuint       RenderBase::sDepthBuffer = -1;
-EGLImageKHR  RenderBase::sKHRimage = EGL_NO_IMAGE_KHR;
-unsigned     RenderBase::sWidth  = 0;
-unsigned     RenderBase::sHeight = 0;
-float        RenderBase::sAspectRatio = 0.0f;
-
-
-bool RenderBase::prepareGL() {
-    // Just trivially return success if we're already prepared
-    if (sDisplay != EGL_NO_DISPLAY) {
-        return true;
-    }
-
-    // Hardcoded to RGBx output display
-    const EGLint config_attribs[] = {
-        // Tag                  Value
-        EGL_RENDERABLE_TYPE,    EGL_OPENGL_ES2_BIT,
-        EGL_RED_SIZE,           8,
-        EGL_GREEN_SIZE,         8,
-        EGL_BLUE_SIZE,          8,
-        EGL_NONE
-    };
-
-    // Select OpenGL ES v 3
-    const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
-
-
-    // Set up our OpenGL ES context associated with the default display (though we won't be visible)
-    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    if (display == EGL_NO_DISPLAY) {
-        ALOGE("Failed to get egl display");
-        return false;
-    }
-
-    EGLint major = 0;
-    EGLint minor = 0;
-    if (!eglInitialize(display, &major, &minor)) {
-        ALOGE("Failed to initialize EGL: %s", getEGLError());
-        return false;
-    } else {
-        ALOGI("Intiialized EGL at %d.%d", major, minor);
-    }
-
-
-    // Select the configuration that "best" matches our desired characteristics
-    EGLConfig egl_config;
-    EGLint num_configs;
-    if (!eglChooseConfig(display, config_attribs, &egl_config, 1, &num_configs)) {
-        ALOGE("eglChooseConfig() failed with error: %s", getEGLError());
-        return false;
-    }
-
-
-    // Create a dummy pbuffer so we have a surface to bind -- we never intend to draw to this
-    // because attachRenderTarget will be called first.
-    EGLint surface_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
-    sDummySurface = eglCreatePbufferSurface(display, egl_config, surface_attribs);
-    if (sDummySurface == EGL_NO_SURFACE) {
-        ALOGE("Failed to create OpenGL ES Dummy surface: %s", getEGLError());
-        return false;
-    } else {
-        ALOGI("Dummy surface looks good!  :)");
-    }
-
-
-    //
-    // Create the EGL context
-    //
-    EGLContext context = eglCreateContext(display, egl_config, EGL_NO_CONTEXT, context_attribs);
-    if (context == EGL_NO_CONTEXT) {
-        ALOGE("Failed to create OpenGL ES Context: %s", getEGLError());
-        return false;
-    }
-
-
-    // Activate our render target for drawing
-    if (!eglMakeCurrent(display, sDummySurface, sDummySurface, context)) {
-        ALOGE("Failed to make the OpenGL ES Context current: %s", getEGLError());
-        return false;
-    } else {
-        ALOGI("We made our context current!  :)");
-    }
-
-
-    // Report the extensions available on this implementation
-    const char* gl_extensions = (const char*) glGetString(GL_EXTENSIONS);
-    ALOGI("GL EXTENSIONS:\n  %s", gl_extensions);
-
-
-    // Reserve handles for the color and depth targets we'll be setting up
-    glGenRenderbuffers(1, &sColorBuffer);
-    glGenRenderbuffers(1, &sDepthBuffer);
-
-    // Set up the frame buffer object we can modify and use for off screen rendering
-    glGenFramebuffers(1, &sFrameBuffer);
-    glBindFramebuffer(GL_FRAMEBUFFER, sFrameBuffer);
-
-
-    // Now that we're assured success, store object handles we constructed
-    sDisplay = display;
-    sContext = context;
-
-    return true;
-}
-
-
-bool RenderBase::attachRenderTarget(const BufferDesc& tgtBuffer) {
-    // Hardcoded to RGBx for now
-    if (tgtBuffer.format != HAL_PIXEL_FORMAT_RGBA_8888) {
-        ALOGE("Unsupported target buffer format");
-        return false;
-    }
-
-    // create a GraphicBuffer from the existing handle
-    sp<GraphicBuffer> pGfxBuffer = new GraphicBuffer(tgtBuffer.memHandle,
-                                                     GraphicBuffer::CLONE_HANDLE,
-                                                     tgtBuffer.width, tgtBuffer.height,
-                                                     tgtBuffer.format, 1, // layer count
-                                                     GRALLOC_USAGE_HW_RENDER,
-                                                     tgtBuffer.stride);
-    if (pGfxBuffer.get() == nullptr) {
-        ALOGE("Failed to allocate GraphicBuffer to wrap image handle");
-        return false;
-    }
-
-    // Get a GL compatible reference to the graphics buffer we've been given
-    EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
-    EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(pGfxBuffer->getNativeBuffer());
-    sKHRimage = eglCreateImageKHR(sDisplay, EGL_NO_CONTEXT,
-                                  EGL_NATIVE_BUFFER_ANDROID, clientBuf,
-                                  eglImageAttributes);
-    if (sKHRimage == EGL_NO_IMAGE_KHR) {
-        ALOGE("error creating EGLImage for target buffer: %s", getEGLError());
-        return false;
-    }
-
-    // Construct a render buffer around the external buffer
-    glBindRenderbuffer(GL_RENDERBUFFER, sColorBuffer);
-    glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, static_cast<GLeglImageOES>(sKHRimage));
-    if (eglGetError() != EGL_SUCCESS) {
-        ALOGI("glEGLImageTargetRenderbufferStorageOES => %s", getEGLError());
-        return false;
-    }
-
-    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, sColorBuffer);
-    if (eglGetError() != EGL_SUCCESS) {
-        ALOGE("glFramebufferRenderbuffer => %s", getEGLError());
-        return false;
-    }
-
-    GLenum checkResult = glCheckFramebufferStatus(GL_FRAMEBUFFER);
-    if (checkResult != GL_FRAMEBUFFER_COMPLETE) {
-        ALOGE("Offscreen framebuffer not configured successfully (%d: %s)",
-              checkResult, getGLFramebufferError());
-        return false;
-    }
-
-    // Store the size of our target buffer
-    sWidth = tgtBuffer.width;
-    sHeight = tgtBuffer.height;
-    sAspectRatio = (float)sWidth / sHeight;
-
-    // Set the viewport
-    glViewport(0, 0, sWidth, sHeight);
-
-#if 1   // We don't actually need the clear if we're going to cover the whole screen anyway
-    // Clear the color buffer
-    glClearColor(0.8f, 0.1f, 0.2f, 1.0f);
-    glClear(GL_COLOR_BUFFER_BIT);
-#endif
-
-
-    return true;
-}
-
-
-void RenderBase::detachRenderTarget() {
-    // Drop our external render target
-    if (sKHRimage != EGL_NO_IMAGE_KHR) {
-        eglDestroyImageKHR(sDisplay, sKHRimage);
-        sKHRimage = EGL_NO_IMAGE_KHR;
-    }
-}
\ No newline at end of file
diff --git a/evs/app/RenderBase.h b/evs/app/RenderBase.h
deleted file mode 100644
index 25474d5..0000000
--- a/evs/app/RenderBase.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CAR_EVS_APP_RENDERBASE_H
-#define CAR_EVS_APP_RENDERBASE_H
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#include <GLES3/gl3.h>
-#include <GLES3/gl3ext.h>
-
-#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
-
-using namespace ::android::hardware::automotive::evs::V1_0;
-using ::android::sp;
-
-
-/*
- * Abstract base class for the workhorse classes that handle the user interaction and display for
- * each mode of the EVS application.
- */
-class RenderBase {
-public:
-    virtual ~RenderBase() {};
-
-    virtual bool activate() = 0;
-    virtual void deactivate() = 0;
-
-    virtual bool drawFrame(const BufferDesc& tgtBuffer) = 0;
-
-protected:
-    static bool prepareGL();
-
-    static bool attachRenderTarget(const BufferDesc& tgtBuffer);
-    static void detachRenderTarget();
-
-    // OpenGL state shared among all renderers
-    static EGLDisplay   sDisplay;
-    static EGLContext   sContext;
-    static EGLSurface   sDummySurface;
-    static GLuint       sFrameBuffer;
-    static GLuint       sColorBuffer;
-    static GLuint       sDepthBuffer;
-
-    static EGLImageKHR  sKHRimage;
-
-    static unsigned     sWidth;
-    static unsigned     sHeight;
-    static float        sAspectRatio;
-};
-
-
-#endif //CAR_EVS_APP_RENDERBASE_H
diff --git a/evs/app/RenderDirectView.cpp b/evs/app/RenderDirectView.cpp
deleted file mode 100644
index 5244b26..0000000
--- a/evs/app/RenderDirectView.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "RenderDirectView.h"
-#include "VideoTex.h"
-#include "glError.h"
-#include "shader.h"
-#include "shader_simpleTex.h"
-
-#include <log/log.h>
-#include <math/mat4.h>
-
-
-RenderDirectView::RenderDirectView(sp<IEvsEnumerator> enumerator,
-                                   const ConfigManager::CameraInfo& cam) {
-    mEnumerator = enumerator;
-    mCameraInfo = cam;
-}
-
-
-bool RenderDirectView::activate() {
-    // Ensure GL is ready to go...
-    if (!prepareGL()) {
-        ALOGE("Error initializing GL");
-        return false;
-    }
-
-    // Load our shader program if we don't have it already
-    if (!mShaderProgram) {
-        mShaderProgram = buildShaderProgram(vtxShader_simpleTexture,
-                                            pixShader_simpleTexture,
-                                            "simpleTexture");
-        if (!mShaderProgram) {
-            ALOGE("Error buliding shader program");
-            return false;
-        }
-    }
-
-    // Construct our video texture
-    mTexture.reset(createVideoTexture(mEnumerator, mCameraInfo.cameraId.c_str(), sDisplay));
-    if (!mTexture) {
-        ALOGE("Failed to set up video texture for %s (%s)",
-              mCameraInfo.cameraId.c_str(), mCameraInfo.function.c_str());
-// TODO:  For production use, we may actually want to fail in this case, but not yet...
-//       return false;
-    }
-
-    return true;
-}
-
-
-void RenderDirectView::deactivate() {
-    // Release our video texture
-    // We can't hold onto it because some other Render object might need the same camera
-    // TODO(b/131492626):  investigate whether sharing video textures can save
-    // the time.
-  mTexture = nullptr;
-}
-
-
-bool RenderDirectView::drawFrame(const BufferDesc& tgtBuffer) {
-    // Tell GL to render to the given buffer
-    if (!attachRenderTarget(tgtBuffer)) {
-        ALOGE("Failed to attached render target");
-        return false;
-    }
-
-    // Select our screen space simple texture shader
-    glUseProgram(mShaderProgram);
-
-    // Set up the model to clip space transform (identity matrix if we're modeling in screen space)
-    GLint loc = glGetUniformLocation(mShaderProgram, "cameraMat");
-    if (loc < 0) {
-        ALOGE("Couldn't set shader parameter 'cameraMat'");
-        return false;
-    } else {
-        const android::mat4 identityMatrix;
-        glUniformMatrix4fv(loc, 1, false, identityMatrix.asArray());
-    }
-
-
-    // Bind the texture and assign it to the shader's sampler
-    mTexture->refresh();
-    glActiveTexture(GL_TEXTURE0);
-    glBindTexture(GL_TEXTURE_2D, mTexture->glId());
-
-
-    GLint sampler = glGetUniformLocation(mShaderProgram, "tex");
-    if (sampler < 0) {
-        ALOGE("Couldn't set shader parameter 'tex'");
-        return false;
-    } else {
-        // Tell the sampler we looked up from the shader to use texture slot 0 as its source
-        glUniform1i(sampler, 0);
-    }
-
-    // We want our image to show up opaque regardless of alpha values
-    glDisable(GL_BLEND);
-
-
-    // Draw a rectangle on the screen
-    GLfloat vertsCarPos[] = { -1.0,  1.0, 0.0f,   // left top in window space
-                               1.0,  1.0, 0.0f,   // right top
-                              -1.0, -1.0, 0.0f,   // left bottom
-                               1.0, -1.0, 0.0f    // right bottom
-    };
-    // TODO:  We're flipping horizontally here, but should do it only for specified cameras!
-    GLfloat vertsCarTex[] = { 1.0f, 1.0f,   // left top
-                              0.0f, 1.0f,   // right top
-                              1.0f, 0.0f,   // left bottom
-                              0.0f, 0.0f    // right bottom
-    };
-    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertsCarPos);
-    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, vertsCarTex);
-    glEnableVertexAttribArray(0);
-    glEnableVertexAttribArray(1);
-
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
-    glDisableVertexAttribArray(0);
-    glDisableVertexAttribArray(1);
-
-
-    // Now that everything is submitted, release our hold on the texture resource
-    detachRenderTarget();
-
-    // Wait for the rendering to finish
-    glFinish();
-    detachRenderTarget();
-    return true;
-}
diff --git a/evs/app/RenderDirectView.h b/evs/app/RenderDirectView.h
deleted file mode 100644
index 1543fce..0000000
--- a/evs/app/RenderDirectView.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CAR_EVS_APP_RENDERDIRECTVIEW_H
-#define CAR_EVS_APP_RENDERDIRECTVIEW_H
-
-
-#include "RenderBase.h"
-
-#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
-#include "ConfigManager.h"
-#include "VideoTex.h"
-
-
-using namespace ::android::hardware::automotive::evs::V1_0;
-
-
-/*
- * Renders the view from a single specified camera directly to the full display.
- */
-class RenderDirectView: public RenderBase {
-public:
-    RenderDirectView(sp<IEvsEnumerator> enumerator, const ConfigManager::CameraInfo& cam);
-
-    virtual bool activate() override;
-    virtual void deactivate() override;
-
-    virtual bool drawFrame(const BufferDesc& tgtBuffer);
-
-protected:
-    sp<IEvsEnumerator>              mEnumerator;
-    ConfigManager::CameraInfo       mCameraInfo;
-
-    std::unique_ptr<VideoTex>       mTexture;
-
-    GLuint                          mShaderProgram = 0;
-};
-
-
-#endif //CAR_EVS_APP_RENDERDIRECTVIEW_H
diff --git a/evs/app/RenderPixelCopy.cpp b/evs/app/RenderPixelCopy.cpp
deleted file mode 100644
index 0a586a4..0000000
--- a/evs/app/RenderPixelCopy.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "RenderPixelCopy.h"
-#include "FormatConvert.h"
-
-#include <log/log.h>
-
-
-RenderPixelCopy::RenderPixelCopy(sp<IEvsEnumerator> enumerator,
-                                   const ConfigManager::CameraInfo& cam) {
-    mEnumerator = enumerator;
-    mCameraInfo = cam;
-}
-
-
-bool RenderPixelCopy::activate() {
-    // Set up the camera to feed this texture
-    sp<IEvsCamera> pCamera = mEnumerator->openCamera(mCameraInfo.cameraId.c_str());
-    if (pCamera.get() == nullptr) {
-        ALOGE("Failed to allocate new EVS Camera interface");
-        return false;
-    }
-
-    // Initialize the stream that will help us update this texture's contents
-    sp<StreamHandler> pStreamHandler = new StreamHandler(pCamera);
-    if (pStreamHandler.get() == nullptr) {
-        ALOGE("failed to allocate FrameHandler");
-        return false;
-    }
-
-    // Start the video stream
-    if (!pStreamHandler->startStream()) {
-        ALOGE("start stream failed");
-        return false;
-    }
-
-    mStreamHandler = pStreamHandler;
-
-    return true;
-}
-
-
-void RenderPixelCopy::deactivate() {
-    mStreamHandler = nullptr;
-}
-
-
-bool RenderPixelCopy::drawFrame(const BufferDesc& tgtBuffer) {
-    bool success = true;
-
-    sp<android::GraphicBuffer> tgt = new android::GraphicBuffer(
-            tgtBuffer.memHandle, android::GraphicBuffer::CLONE_HANDLE,
-            tgtBuffer.width, tgtBuffer.height, tgtBuffer.format, 1, tgtBuffer.usage,
-            tgtBuffer.stride);
-
-    // Lock our target buffer for writing (should be RGBA8888 format)
-    uint32_t* tgtPixels = nullptr;
-    tgt->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)&tgtPixels);
-
-    if (tgtPixels) {
-        if (tgtBuffer.format != HAL_PIXEL_FORMAT_RGBA_8888) {
-            // We always expect 32 bit RGB for the display output for now.  Is there a need for 565?
-            ALOGE("Diplay buffer is always expected to be 32bit RGBA");
-            success = false;
-        } else {
-            // Make sure we have the latest frame data
-            if (mStreamHandler->newFrameAvailable()) {
-                const BufferDesc& srcBuffer = mStreamHandler->getNewFrame();
-
-                // Lock our source buffer for reading (current expectation are for this to be NV21 format)
-                sp<android::GraphicBuffer> src = new android::GraphicBuffer(
-                        srcBuffer.memHandle, android::GraphicBuffer::CLONE_HANDLE,
-                        srcBuffer.width, srcBuffer.height, srcBuffer.format, 1, srcBuffer.usage,
-                        srcBuffer.stride);
-                unsigned char* srcPixels = nullptr;
-                src->lock(GRALLOC_USAGE_SW_READ_OFTEN, (void**)&srcPixels);
-                if (!srcPixels) {
-                    ALOGE("Failed to get pointer into src image data");
-                }
-
-                // Make sure we don't run off the end of either buffer
-                const unsigned width     = std::min(tgtBuffer.width,
-                                                    srcBuffer.width);
-                const unsigned height    = std::min(tgtBuffer.height,
-                                                    srcBuffer.height);
-
-                if (srcBuffer.format == HAL_PIXEL_FORMAT_YCRCB_420_SP) {   // 420SP == NV21
-                    copyNV21toRGB32(width, height,
-                                    srcPixels,
-                                    tgtPixels, tgtBuffer.stride);
-                } else if (srcBuffer.format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12
-                    copyYV12toRGB32(width, height,
-                                    srcPixels,
-                                    tgtPixels, tgtBuffer.stride);
-                } else if (srcBuffer.format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV
-                    copyYUYVtoRGB32(width, height,
-                                    srcPixels, srcBuffer.stride,
-                                    tgtPixels, tgtBuffer.stride);
-                } else if (srcBuffer.format == tgtBuffer.format) {  // 32bit RGBA
-                    copyMatchedInterleavedFormats(width, height,
-                                                  srcPixels, srcBuffer.stride,
-                                                  tgtPixels, tgtBuffer.stride,
-                                                  tgtBuffer.pixelSize);
-                }
-
-                mStreamHandler->doneWithFrame(srcBuffer);
-            }
-        }
-    } else {
-        ALOGE("Failed to lock buffer contents for contents transfer");
-        success = false;
-    }
-
-    if (tgtPixels) {
-        tgt->unlock();
-    }
-
-    return success;
-}
diff --git a/evs/app/RenderPixelCopy.h b/evs/app/RenderPixelCopy.h
deleted file mode 100644
index ee6eede..0000000
--- a/evs/app/RenderPixelCopy.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CAR_EVS_APP_RENDERPIXELCOPY_H
-#define CAR_EVS_APP_RENDERPIXELCOPY_H
-
-
-#include "RenderBase.h"
-
-#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
-#include "ConfigManager.h"
-#include "VideoTex.h"
-
-
-using namespace ::android::hardware::automotive::evs::V1_0;
-
-
-/*
- * Renders the view from a single specified camera directly to the full display.
- */
-class RenderPixelCopy: public RenderBase {
-public:
-    RenderPixelCopy(sp<IEvsEnumerator> enumerator, const ConfigManager::CameraInfo& cam);
-
-    virtual bool activate() override;
-    virtual void deactivate() override;
-
-    virtual bool drawFrame(const BufferDesc& tgtBuffer);
-
-protected:
-    sp<IEvsEnumerator>              mEnumerator;
-    ConfigManager::CameraInfo       mCameraInfo;
-
-    sp<StreamHandler>               mStreamHandler;
-};
-
-
-#endif //CAR_EVS_APP_RENDERPIXELCOPY_H
diff --git a/evs/app/RenderTopView.cpp b/evs/app/RenderTopView.cpp
deleted file mode 100644
index 1ffa7cf..0000000
--- a/evs/app/RenderTopView.cpp
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "RenderTopView.h"
-#include "VideoTex.h"
-#include "glError.h"
-#include "shader.h"
-#include "shader_simpleTex.h"
-#include "shader_projectedTex.h"
-
-#include <log/log.h>
-#include <math/mat4.h>
-#include <math/vec3.h>
-
-
-// Simple aliases to make geometric math using vectors more readable
-static const unsigned X = 0;
-static const unsigned Y = 1;
-static const unsigned Z = 2;
-//static const unsigned W = 3;
-
-
-// Since we assume no roll in these views, we can simplify the required math
-static android::vec3 unitVectorFromPitchAndYaw(float pitch, float yaw) {
-    float sinPitch, cosPitch;
-    sincosf(pitch, &sinPitch, &cosPitch);
-    float sinYaw, cosYaw;
-    sincosf(yaw, &sinYaw, &cosYaw);
-    return android::vec3(cosPitch * -sinYaw,
-                         cosPitch * cosYaw,
-                         sinPitch);
-}
-
-
-// Helper function to set up a perspective matrix with independent horizontal and vertical
-// angles of view.
-static android::mat4 perspective(float hfov, float vfov, float near, float far) {
-    const float tanHalfFovX = tanf(hfov * 0.5f);
-    const float tanHalfFovY = tanf(vfov * 0.5f);
-
-    android::mat4 p(0.0f);
-    p[0][0] = 1.0f / tanHalfFovX;
-    p[1][1] = 1.0f / tanHalfFovY;
-    p[2][2] = - (far + near) / (far - near);
-    p[2][3] = -1.0f;
-    p[3][2] = - (2.0f * far * near) / (far - near);
-    return p;
-}
-
-
-// Helper function to set up a view matrix for a camera given it's yaw & pitch & location
-// Yes, with a bit of work, we could use lookAt, but it does a lot of extra work
-// internally that we can short cut.
-static android::mat4 cameraLookMatrix(const ConfigManager::CameraInfo& cam) {
-    float sinYaw, cosYaw;
-    sincosf(cam.yaw, &sinYaw, &cosYaw);
-
-    // Construct principal unit vectors
-    android::vec3 vAt = unitVectorFromPitchAndYaw(cam.pitch, cam.yaw);
-    android::vec3 vRt = android::vec3(cosYaw, sinYaw, 0.0f);
-    android::vec3 vUp = -cross(vAt, vRt);
-    android::vec3 eye = android::vec3(cam.position[X], cam.position[Y], cam.position[Z]);
-
-    android::mat4 Result(1.0f);
-    Result[0][0] = vRt.x;
-    Result[1][0] = vRt.y;
-    Result[2][0] = vRt.z;
-    Result[0][1] = vUp.x;
-    Result[1][1] = vUp.y;
-    Result[2][1] = vUp.z;
-    Result[0][2] =-vAt.x;
-    Result[1][2] =-vAt.y;
-    Result[2][2] =-vAt.z;
-    Result[3][0] =-dot(vRt, eye);
-    Result[3][1] =-dot(vUp, eye);
-    Result[3][2] = dot(vAt, eye);
-    return Result;
-}
-
-
-RenderTopView::RenderTopView(sp<IEvsEnumerator> enumerator,
-                             const std::vector<ConfigManager::CameraInfo>& camList,
-                             const ConfigManager& mConfig) :
-    mEnumerator(enumerator),
-    mConfig(mConfig) {
-
-    // Copy the list of cameras we're to employ into our local storage.  We'll create and
-    // associate a streaming video texture when we are activated.
-    mActiveCameras.reserve(camList.size());
-    for (unsigned i=0; i<camList.size(); i++) {
-        mActiveCameras.emplace_back(camList[i]);
-    }
-}
-
-
-bool RenderTopView::activate() {
-    // Ensure GL is ready to go...
-    if (!prepareGL()) {
-        ALOGE("Error initializing GL");
-        return false;
-    }
-
-    // Load our shader programs
-    mPgmAssets.simpleTexture = buildShaderProgram(vtxShader_simpleTexture,
-                                                 pixShader_simpleTexture,
-                                                 "simpleTexture");
-    if (!mPgmAssets.simpleTexture) {
-        ALOGE("Failed to build shader program");
-        return false;
-    }
-    mPgmAssets.projectedTexture = buildShaderProgram(vtxShader_projectedTexture,
-                                                    pixShader_projectedTexture,
-                                                    "projectedTexture");
-    if (!mPgmAssets.projectedTexture) {
-        ALOGE("Failed to build shader program");
-        return false;
-    }
-
-
-    // Load the checkerboard text image
-    mTexAssets.checkerBoard.reset(createTextureFromPng(
-                                  "/system/etc/automotive/evs/LabeledChecker.png"));
-    if (!mTexAssets.checkerBoard) {
-        ALOGE("Failed to load checkerboard texture");
-        return false;
-    }
-
-    // Load the car image
-    mTexAssets.carTopView.reset(createTextureFromPng(
-                                "/system/etc/automotive/evs/CarFromTop.png"));
-    if (!mTexAssets.carTopView) {
-        ALOGE("Failed to load carTopView texture");
-        return false;
-    }
-
-
-    // Set up streaming video textures for our associated cameras
-    for (auto&& cam: mActiveCameras) {
-        cam.tex.reset(createVideoTexture(mEnumerator, cam.info.cameraId.c_str(), sDisplay));
-        if (!cam.tex) {
-            ALOGE("Failed to set up video texture for %s (%s)",
-                  cam.info.cameraId.c_str(), cam.info.function.c_str());
-// TODO:  For production use, we may actually want to fail in this case, but not yet...
-//            return false;
-        }
-    }
-
-    return true;
-}
-
-
-void RenderTopView::deactivate() {
-    // Release our video textures
-    // We can't hold onto it because some other Render object might need the same camera
-    // TODO(b/131492626):  investigate whether sharing video textures can save
-    // the time.
-    for (auto&& cam: mActiveCameras) {
-        cam.tex = nullptr;
-    }
-}
-
-
-bool RenderTopView::drawFrame(const BufferDesc& tgtBuffer) {
-    // Tell GL to render to the given buffer
-    if (!attachRenderTarget(tgtBuffer)) {
-        ALOGE("Failed to attached render target");
-        return false;
-    }
-
-    // Set up our top down projection matrix from car space (world units, Xfwd, Yright, Zup)
-    // to view space (-1 to 1)
-    const float top    = mConfig.getDisplayTopLocation();
-    const float bottom = mConfig.getDisplayBottomLocation();
-    const float right  = mConfig.getDisplayRightLocation(sAspectRatio);
-    const float left   = mConfig.getDisplayLeftLocation(sAspectRatio);
-
-    const float near = 10.0f;   // arbitrary top of view volume
-    const float far = 0.0f;     // ground plane is at zero
-
-    // We can use a simple, unrotated ortho view since the screen and car space axis are
-    // naturally aligned in the top down view.
-    // TODO:  Not sure if flipping top/bottom here is "correct" or a double reverse...
-//    orthoMatrix = android::mat4::ortho(left, right, bottom, top, near, far);
-    orthoMatrix = android::mat4::ortho(left, right, top, bottom, near, far);
-
-
-    // Refresh our video texture contents.  We do it all at once in hopes of getting
-    // better coherence among images.  This does not guarantee synchronization, of course...
-    for (auto&& cam: mActiveCameras) {
-        if (cam.tex) {
-            cam.tex->refresh();
-        }
-    }
-
-    // Iterate over all the cameras and project their images onto the ground plane
-    for (auto&& cam: mActiveCameras) {
-        renderCameraOntoGroundPlane(cam);
-    }
-
-    // Draw the car image
-    renderCarTopView();
-
-    // Now that everythign is submitted, release our hold on the texture resource
-    detachRenderTarget();
-
-    // Wait for the rendering to finish
-    glFinish();
-    detachRenderTarget();
-    return true;
-}
-
-
-//
-// Responsible for drawing the car's self image in the top down view.
-// Draws in car model space (units of meters with origin at center of rear axel)
-// NOTE:  We probably want to eventually switch to using a VertexArray based model system.
-//
-void RenderTopView::renderCarTopView() {
-    // Compute the corners of our image footprint in car space
-    const float carLengthInTexels = mConfig.carGraphicRearPixel() - mConfig.carGraphicFrontPixel();
-    const float carSpaceUnitsPerTexel = mConfig.getCarLength() / carLengthInTexels;
-    const float textureHeightInCarSpace = mTexAssets.carTopView->height() * carSpaceUnitsPerTexel;
-    const float textureAspectRatio = (float)mTexAssets.carTopView->width() /
-                                            mTexAssets.carTopView->height();
-    const float pixelsBehindCarInImage = mTexAssets.carTopView->height() -
-                                         mConfig.carGraphicRearPixel();
-    const float textureExtentBehindCarInCarSpace = pixelsBehindCarInImage * carSpaceUnitsPerTexel;
-
-    const float btCS = mConfig.getRearLocation() - textureExtentBehindCarInCarSpace;
-    const float tpCS = textureHeightInCarSpace + btCS;
-    const float ltCS = 0.5f * textureHeightInCarSpace * textureAspectRatio;
-    const float rtCS = -ltCS;
-
-    GLfloat vertsCarPos[] = { ltCS, tpCS, 0.0f,   // left top in car space
-                              rtCS, tpCS, 0.0f,   // right top
-                              ltCS, btCS, 0.0f,   // left bottom
-                              rtCS, btCS, 0.0f    // right bottom
-    };
-    // NOTE:  We didn't flip the image in the texture, so V=0 is actually the top of the image
-    GLfloat vertsCarTex[] = { 0.0f, 0.0f,   // left top
-                              1.0f, 0.0f,   // right top
-                              0.0f, 1.0f,   // left bottom
-                              1.0f, 1.0f    // right bottom
-    };
-    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertsCarPos);
-    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, vertsCarTex);
-    glEnableVertexAttribArray(0);
-    glEnableVertexAttribArray(1);
-
-
-    glEnable(GL_BLEND);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-    glUseProgram(mPgmAssets.simpleTexture);
-    GLint loc = glGetUniformLocation(mPgmAssets.simpleTexture, "cameraMat");
-    glUniformMatrix4fv(loc, 1, false, orthoMatrix.asArray());
-    glBindTexture(GL_TEXTURE_2D, mTexAssets.carTopView->glId());
-
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
-
-    glDisable(GL_BLEND);
-
-    glDisableVertexAttribArray(0);
-    glDisableVertexAttribArray(1);
-}
-
-
-// NOTE:  Might be worth reviewing the ideas at
-// http://math.stackexchange.com/questions/1691895/inverse-of-perspective-matrix
-// to see if that simplifies the math, although we'll still want to compute the actual ground
-// interception points taking into account the pitchLimit as below.
-void RenderTopView::renderCameraOntoGroundPlane(const ActiveCamera& cam) {
-    // How far is the farthest any camera should even consider projecting it's image?
-    const float visibleSizeV = mConfig.getDisplayTopLocation() - mConfig.getDisplayBottomLocation();
-    const float visibleSizeH = visibleSizeV * sAspectRatio;
-    const float maxRange = (visibleSizeH > visibleSizeV) ? visibleSizeH : visibleSizeV;
-
-    // Construct the projection matrix (View + Projection) associated with this sensor
-    // TODO:  Consider just hard coding the far plane distance as it likely doesn't matter
-    const android::mat4 V = cameraLookMatrix(cam.info);
-    const android::mat4 P = perspective(cam.info.hfov, cam.info.vfov, cam.info.position[Z], maxRange);
-    const android::mat4 projectionMatix = P*V;
-
-    // Just draw the whole darn ground plane for now -- we're wasting fill rate, but so what?
-    // A 2x optimization would be to draw only the 1/2 space of the window in the direction
-    // the sensor is facing.  A more complex solution would be to construct the intersection
-    // of the sensor volume with the ground plane and render only that geometry.
-    const float top = mConfig.getDisplayTopLocation();
-    const float bottom = mConfig.getDisplayBottomLocation();
-    const float wsHeight = top - bottom;
-    const float wsWidth = wsHeight * sAspectRatio;
-    const float right =  wsWidth * 0.5f;
-    const float left = -right;
-
-    const android::vec3 topLeft(left, top, 0.0f);
-    const android::vec3 topRight(right, top, 0.0f);
-    const android::vec3 botLeft(left, bottom, 0.0f);
-    const android::vec3 botRight(right, bottom, 0.0f);
-
-    GLfloat vertsPos[] = { topLeft[X],  topLeft[Y],  topLeft[Z],
-                           topRight[X], topRight[Y], topRight[Z],
-                           botLeft[X],  botLeft[Y],  botLeft[Z],
-                           botRight[X], botRight[Y], botRight[Z],
-    };
-    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertsPos);
-    glEnableVertexAttribArray(0);
-
-
-    glDisable(GL_BLEND);
-
-    glUseProgram(mPgmAssets.projectedTexture);
-    GLint locCam = glGetUniformLocation(mPgmAssets.projectedTexture, "cameraMat");
-    glUniformMatrix4fv(locCam, 1, false, orthoMatrix.asArray());
-    GLint locProj = glGetUniformLocation(mPgmAssets.projectedTexture, "projectionMat");
-    glUniformMatrix4fv(locProj, 1, false, projectionMatix.asArray());
-
-    GLuint texId;
-    if (cam.tex) {
-        texId = cam.tex->glId();
-    } else {
-        texId = mTexAssets.checkerBoard->glId();
-    }
-    glBindTexture(GL_TEXTURE_2D, texId);
-
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
-
-    glDisableVertexAttribArray(0);
-}
diff --git a/evs/app/RenderTopView.h b/evs/app/RenderTopView.h
deleted file mode 100644
index 570718f..0000000
--- a/evs/app/RenderTopView.h
+++ /dev/null
@@ -1,76 +0,0 @@
-
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CAR_EVS_APP_RENDERTOPVIEW_H
-#define CAR_EVS_APP_RENDERTOPVIEW_H
-
-
-#include "RenderBase.h"
-
-#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
-#include "ConfigManager.h"
-#include "VideoTex.h"
-#include <math/mat4.h>
-
-
-using namespace ::android::hardware::automotive::evs::V1_0;
-
-
-/*
- * Combines the views from all available cameras into one reprojected top down view.
- */
-class RenderTopView: public RenderBase {
-public:
-    RenderTopView(sp<IEvsEnumerator> enumerator,
-                  const std::vector<ConfigManager::CameraInfo>& camList,
-                  const ConfigManager& config);
-
-    virtual bool activate() override;
-    virtual void deactivate() override;
-
-    virtual bool drawFrame(const BufferDesc& tgtBuffer);
-
-protected:
-    struct ActiveCamera {
-        const ConfigManager::CameraInfo&    info;
-        std::unique_ptr<VideoTex>           tex;
-
-        ActiveCamera(const ConfigManager::CameraInfo& c) : info(c) {};
-    };
-
-    void renderCarTopView();
-    void renderCameraOntoGroundPlane(const ActiveCamera& cam);
-
-    sp<IEvsEnumerator>              mEnumerator;
-    const ConfigManager&            mConfig;
-    std::vector<ActiveCamera>       mActiveCameras;
-
-    struct {
-        std::unique_ptr<TexWrapper> checkerBoard;
-        std::unique_ptr<TexWrapper> carTopView;
-    } mTexAssets;
-
-    struct {
-        GLuint simpleTexture;
-        GLuint projectedTexture;
-    } mPgmAssets;
-
-    android::mat4   orthoMatrix;
-};
-
-
-#endif //CAR_EVS_APP_RENDERTOPVIEW_H
diff --git a/evs/app/StreamHandler.cpp b/evs/app/StreamHandler.cpp
deleted file mode 100644
index 28da6df..0000000
--- a/evs/app/StreamHandler.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "StreamHandler.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include <log/log.h>
-#include <cutils/native_handle.h>
-
-
-StreamHandler::StreamHandler(android::sp <IEvsCamera> pCamera) :
-    mCamera(pCamera)
-{
-    // We rely on the camera having at least two buffers available since we'll hold one and
-    // expect the camera to be able to capture a new image in the background.
-    pCamera->setMaxFramesInFlight(2);
-}
-
-
-void StreamHandler::shutdown()
-{
-    // Make sure we're not still streaming
-    blockingStopStream();
-
-    // At this point, the receiver thread is no longer running, so we can safely drop
-    // our remote object references so they can be freed
-    mCamera = nullptr;
-}
-
-
-bool StreamHandler::startStream() {
-    std::unique_lock<std::mutex> lock(mLock);
-
-    if (!mRunning) {
-        // Tell the camera to start streaming
-        Return <EvsResult> result = mCamera->startVideoStream(this);
-        if (result != EvsResult::OK) {
-            return false;
-        }
-
-        // Mark ourselves as running
-        mRunning = true;
-    }
-
-    return true;
-}
-
-
-void StreamHandler::asyncStopStream() {
-    // Tell the camera to stop streaming.
-    // This will result in a null frame being delivered when the stream actually stops.
-    mCamera->stopVideoStream();
-}
-
-
-void StreamHandler::blockingStopStream() {
-    // Tell the stream to stop
-    asyncStopStream();
-
-    // Wait until the stream has actually stopped
-    std::unique_lock<std::mutex> lock(mLock);
-    if (mRunning) {
-        mSignal.wait(lock, [this]() { return !mRunning; });
-    }
-}
-
-
-bool StreamHandler::isRunning() {
-    std::unique_lock<std::mutex> lock(mLock);
-    return mRunning;
-}
-
-
-bool StreamHandler::newFrameAvailable() {
-    std::unique_lock<std::mutex> lock(mLock);
-    return (mReadyBuffer >= 0);
-}
-
-
-const BufferDesc& StreamHandler::getNewFrame() {
-    std::unique_lock<std::mutex> lock(mLock);
-
-    if (mHeldBuffer >= 0) {
-        ALOGE("Ignored call for new frame while still holding the old one.");
-    } else {
-        if (mReadyBuffer < 0) {
-            ALOGE("Returning invalid buffer because we don't have any.  Call newFrameAvailable first?");
-            mReadyBuffer = 0;   // This is a lie!
-        }
-
-        // Move the ready buffer into the held position, and clear the ready position
-        mHeldBuffer = mReadyBuffer;
-        mReadyBuffer = -1;
-    }
-
-    return mBuffers[mHeldBuffer];
-}
-
-
-void StreamHandler::doneWithFrame(const BufferDesc& buffer) {
-    std::unique_lock<std::mutex> lock(mLock);
-
-    // We better be getting back the buffer we original delivered!
-    if ((mHeldBuffer < 0) || (buffer.bufferId != mBuffers[mHeldBuffer].bufferId)) {
-        ALOGE("StreamHandler::doneWithFrame got an unexpected buffer!");
-    }
-
-    // Send the buffer back to the underlying camera
-    mCamera->doneWithFrame(mBuffers[mHeldBuffer]);
-
-    // Clear the held position
-    mHeldBuffer = -1;
-}
-
-
-Return<void> StreamHandler::deliverFrame(const BufferDesc& buffer) {
-    ALOGD("Received a frame from the camera (%p)", buffer.memHandle.getNativeHandle());
-
-    // Take the lock to protect our frame slots and running state variable
-    {
-        std::unique_lock <std::mutex> lock(mLock);
-
-        if (buffer.memHandle.getNativeHandle() == nullptr) {
-            // Signal that the last frame has been received and the stream is stopped
-            mRunning = false;
-        } else {
-            // Do we already have a "ready" frame?
-            if (mReadyBuffer >= 0) {
-                // Send the previously saved buffer back to the camera unused
-                mCamera->doneWithFrame(mBuffers[mReadyBuffer]);
-
-                // We'll reuse the same ready buffer index
-            } else if (mHeldBuffer >= 0) {
-                // The client is holding a buffer, so use the other slot for "on deck"
-                mReadyBuffer = 1 - mHeldBuffer;
-            } else {
-                // This is our first buffer, so just pick a slot
-                mReadyBuffer = 0;
-            }
-
-            // Save this frame until our client is interested in it
-            mBuffers[mReadyBuffer] = buffer;
-        }
-    }
-
-    // Notify anybody who cares that things have changed
-    mSignal.notify_all();
-
-    return Void();
-}
diff --git a/evs/app/StreamHandler.h b/evs/app/StreamHandler.h
deleted file mode 100644
index 9e1d3b7..0000000
--- a/evs/app/StreamHandler.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef EVS_VTS_STREAMHANDLER_H
-#define EVS_VTS_STREAMHANDLER_H
-
-#include <queue>
-
-#include "ui/GraphicBuffer.h"
-
-#include <android/hardware/automotive/evs/1.0/IEvsCameraStream.h>
-#include <android/hardware/automotive/evs/1.0/IEvsCamera.h>
-#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
-
-using namespace ::android::hardware::automotive::evs::V1_0;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_handle;
-using ::android::sp;
-
-
-/*
- * StreamHandler:
- * This class can be used to receive camera imagery from an IEvsCamera implementation.  It will
- * hold onto the most recent image buffer, returning older ones.
- * Note that the video frames are delivered on a background thread, while the control interface
- * is actuated from the applications foreground thread.
- */
-class StreamHandler : public IEvsCameraStream {
-public:
-    virtual ~StreamHandler() { shutdown(); };
-
-    StreamHandler(android::sp <IEvsCamera> pCamera);
-    void shutdown();
-
-    bool startStream();
-    void asyncStopStream();
-    void blockingStopStream();
-
-    bool isRunning();
-
-    bool newFrameAvailable();
-    const BufferDesc& getNewFrame();
-    void doneWithFrame(const BufferDesc& buffer);
-
-private:
-    // Implementation for ::android::hardware::automotive::evs::V1_0::ICarCameraStream
-    Return<void> deliverFrame(const BufferDesc& buffer)  override;
-
-    // Values initialized as startup
-    android::sp <IEvsCamera>    mCamera;
-
-    // Since we get frames delivered to us asnchronously via the ICarCameraStream interface,
-    // we need to protect all member variables that may be modified while we're streaming
-    // (ie: those below)
-    std::mutex                  mLock;
-    std::condition_variable     mSignal;
-
-    bool                        mRunning = false;
-
-    BufferDesc                  mBuffers[2];
-    int                         mHeldBuffer = -1;   // Index of the one currently held by the client
-    int                         mReadyBuffer = -1;  // Index of the newest available buffer
-};
-
-
-#endif //EVS_VTS_STREAMHANDLER_H
diff --git a/evs/app/TexWrapper.cpp b/evs/app/TexWrapper.cpp
deleted file mode 100644
index 7ec2191..0000000
--- a/evs/app/TexWrapper.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "TexWrapper.h"
-#include "glError.h"
-
-#include "log/log.h"
-
-#include <fcntl.h>
-#include <malloc.h>
-#include <png.h>
-
-
-/* Create an new empty GL texture that will be filled later */
-TexWrapper::TexWrapper() {
-    GLuint textureId;
-    glGenTextures(1, &textureId);
-    if (textureId <= 0) {
-        ALOGE("Didn't get a texture handle allocated: %s", getEGLError());
-    } else {
-        // Store the basic texture properties
-        id = textureId;
-        w  = 0;
-        h  = 0;
-    }
-}
-
-
-/* Wrap a texture that already allocated.  The wrapper takes ownership. */
-TexWrapper::TexWrapper(GLuint textureId, unsigned width, unsigned height) {
-    // Store the basic texture properties
-    id = textureId;
-    w  = width;
-    h  = height;
-}
-
-
-TexWrapper::~TexWrapper() {
-    // Give the texture ID back
-    if (id > 0) {
-        glDeleteTextures(1, &id);
-    }
-    id = -1;
-}
-
-
-/* Factory to build TexWrapper objects from a given PNG file */
-TexWrapper* createTextureFromPng(const char * filename)
-{
-    // Open the PNG file
-    FILE *inputFile = fopen(filename, "rb");
-    if (inputFile == 0)
-    {
-        perror(filename);
-        return nullptr;
-    }
-
-    // Read the file header and validate that it is a PNG
-    static const int kSigSize = 8;
-    png_byte header[kSigSize] = {0};
-    fread(header, 1, kSigSize, inputFile);
-    if (png_sig_cmp(header, 0, kSigSize)) {
-        printf("%s is not a PNG.\n", filename);
-        fclose(inputFile);
-        return nullptr;
-    }
-
-    // Set up our control structure
-    png_structp pngControl = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-    if (!pngControl)
-    {
-        printf("png_create_read_struct failed.\n");
-        fclose(inputFile);
-        return nullptr;
-    }
-
-    // Set up our image info structure
-    png_infop pngInfo = png_create_info_struct(pngControl);
-    if (!pngInfo)
-    {
-        printf("error: png_create_info_struct returned 0.\n");
-        png_destroy_read_struct(&pngControl, nullptr, nullptr);
-        fclose(inputFile);
-        return nullptr;
-    }
-
-    // Install an error handler
-    if (setjmp(png_jmpbuf(pngControl))) {
-        printf("libpng reported an error\n");
-        png_destroy_read_struct(&pngControl, &pngInfo, nullptr);
-        fclose(inputFile);
-        return nullptr;
-    }
-
-    // Set up the png reader and fetch the remaining bits of the header
-    png_init_io(pngControl, inputFile);
-    png_set_sig_bytes(pngControl, kSigSize);
-    png_read_info(pngControl, pngInfo);
-
-    // Get basic information about the PNG we're reading
-    int bitDepth;
-    int colorFormat;
-    png_uint_32 width;
-    png_uint_32 height;
-    png_get_IHDR(pngControl, pngInfo,
-                 &width, &height,
-                 &bitDepth, &colorFormat,
-                 NULL, NULL, NULL);
-
-    GLint format;
-    switch(colorFormat)
-    {
-        case PNG_COLOR_TYPE_RGB:
-            format = GL_RGB;
-            break;
-        case PNG_COLOR_TYPE_RGB_ALPHA:
-            format = GL_RGBA;
-            break;
-        default:
-            printf("%s: Unknown libpng color format %d.\n", filename, colorFormat);
-            return nullptr;
-    }
-
-    // Refresh the values in the png info struct in case any transformation shave been applied.
-    png_read_update_info(pngControl, pngInfo);
-    int stride = png_get_rowbytes(pngControl, pngInfo);
-    stride += 3 - ((stride-1) % 4);   // glTexImage2d requires rows to be 4-byte aligned
-
-    // Allocate storage for the pixel data
-    png_byte * buffer = (png_byte*)malloc(stride * height);
-    if (buffer == NULL)
-    {
-        printf("error: could not allocate memory for PNG image data\n");
-        png_destroy_read_struct(&pngControl, &pngInfo, nullptr);
-        fclose(inputFile);
-        return nullptr;
-    }
-
-    // libpng needs an array of pointers into the image data for each row
-    png_byte ** rowPointers = (png_byte**)malloc(height * sizeof(png_byte*));
-    if (rowPointers == NULL)
-    {
-        printf("Failed to allocate temporary row pointers\n");
-        png_destroy_read_struct(&pngControl, &pngInfo, nullptr);
-        free(buffer);
-        fclose(inputFile);
-        return nullptr;
-    }
-    for (unsigned int r = 0; r < height; r++)
-    {
-        rowPointers[r] = buffer + r*stride;
-    }
-
-
-    // Read in the actual image bytes
-    png_read_image(pngControl, rowPointers);
-    png_read_end(pngControl, nullptr);
-
-
-    // Set up the OpenGL texture to contain this image
-    GLuint textureId;
-    glGenTextures(1, &textureId);
-    glBindTexture(GL_TEXTURE_2D, textureId);
-
-    // Send the image data to GL
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
-
-    // Initialize the sampling properties (it seems the sample may not work if this isn't done)
-    // The user of this texture may very well want to set their own filtering, but we're going
-    // to pay the (minor) price of setting this up for them to avoid the dreaded "black image" if
-    // they forget.
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-
-    // clean up
-    png_destroy_read_struct(&pngControl, &pngInfo, nullptr);
-    free(buffer);
-    free(rowPointers);
-    fclose(inputFile);
-
-    glBindTexture(GL_TEXTURE_2D, 0);
-
-
-    // Return the texture
-    return new TexWrapper(textureId, width, height);
-}
diff --git a/evs/app/VideoTex.cpp b/evs/app/VideoTex.cpp
deleted file mode 100644
index 10d54bd..0000000
--- a/evs/app/VideoTex.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-#include <stdio.h>
-#include <fcntl.h>
-#include <alloca.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <malloc.h>
-#include <png.h>
-
-#include "VideoTex.h"
-#include "glError.h"
-
-#include <ui/GraphicBuffer.h>
-
-// Eventually we shouldn't need this dependency, but for now the
-// graphics allocator interface isn't fully supported on all platforms
-// and this is our work around.
-using ::android::GraphicBuffer;
-
-
-VideoTex::VideoTex(sp<IEvsEnumerator> pEnum,
-                   sp<IEvsCamera> pCamera,
-                   sp<StreamHandler> pStreamHandler,
-                   EGLDisplay glDisplay)
-    : TexWrapper()
-    , mEnumerator(pEnum)
-    , mCamera(pCamera)
-    , mStreamHandler(pStreamHandler)
-    , mDisplay(glDisplay) {
-    // Nothing but initialization here...
-}
-
-VideoTex::~VideoTex() {
-    // Tell the stream to stop flowing
-    mStreamHandler->asyncStopStream();
-
-    // Close the camera
-    mEnumerator->closeCamera(mCamera);
-
-    // Drop our device texture image
-    if (mKHRimage != EGL_NO_IMAGE_KHR) {
-        eglDestroyImageKHR(mDisplay, mKHRimage);
-        mKHRimage = EGL_NO_IMAGE_KHR;
-    }
-}
-
-
-// Return true if the texture contents are changed
-bool VideoTex::refresh() {
-    if (!mStreamHandler->newFrameAvailable()) {
-        // No new image has been delivered, so there's nothing to do here
-        return false;
-    }
-
-    // If we already have an image backing us, then it's time to return it
-    if (mImageBuffer.memHandle.getNativeHandle() != nullptr) {
-        // Drop our device texture image
-        if (mKHRimage != EGL_NO_IMAGE_KHR) {
-            eglDestroyImageKHR(mDisplay, mKHRimage);
-            mKHRimage = EGL_NO_IMAGE_KHR;
-        }
-
-        // Return it since we're done with it
-        mStreamHandler->doneWithFrame(mImageBuffer);
-    }
-
-    // Get the new image we want to use as our contents
-    mImageBuffer = mStreamHandler->getNewFrame();
-
-
-    // create a GraphicBuffer from the existing handle
-    sp<GraphicBuffer> pGfxBuffer = new GraphicBuffer(mImageBuffer.memHandle,
-                                                     GraphicBuffer::CLONE_HANDLE,
-                                                     mImageBuffer.width, mImageBuffer.height,
-                                                     mImageBuffer.format, 1, // layer count
-                                                     GRALLOC_USAGE_HW_TEXTURE,
-                                                     mImageBuffer.stride);
-    if (pGfxBuffer.get() == nullptr) {
-        ALOGE("Failed to allocate GraphicBuffer to wrap image handle");
-        // Returning "true" in this error condition because we already released the
-        // previous image (if any) and so the texture may change in unpredictable ways now!
-        return true;
-    }
-
-    // Get a GL compatible reference to the graphics buffer we've been given
-    EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
-    EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(pGfxBuffer->getNativeBuffer());
-    mKHRimage = eglCreateImageKHR(mDisplay, EGL_NO_CONTEXT,
-                                  EGL_NATIVE_BUFFER_ANDROID, clientBuf,
-                                  eglImageAttributes);
-    if (mKHRimage == EGL_NO_IMAGE_KHR) {
-        const char *msg = getEGLError();
-        ALOGE("error creating EGLImage: %s", msg);
-    } else {
-        // Update the texture handle we already created to refer to this gralloc buffer
-        glActiveTexture(GL_TEXTURE0);
-        glBindTexture(GL_TEXTURE_2D, glId());
-        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast<GLeglImageOES>(mKHRimage));
-
-        // Initialize the sampling properties (it seems the sample may not work if this isn't done)
-        // The user of this texture may very well want to set their own filtering, but we're going
-        // to pay the (minor) price of setting this up for them to avoid the dreaded "black image"
-        // if they forget.
-        // TODO:  Can we do this once for the texture ID rather than ever refresh?
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    }
-
-    return true;
-}
-
-
-VideoTex* createVideoTexture(sp<IEvsEnumerator> pEnum,
-                             const char* evsCameraId,
-                             EGLDisplay glDisplay) {
-    // Set up the camera to feed this texture
-    sp<IEvsCamera> pCamera = pEnum->openCamera(evsCameraId);
-    if (pCamera.get() == nullptr) {
-        ALOGE("Failed to allocate new EVS Camera interface for %s", evsCameraId);
-        return nullptr;
-    }
-
-    // Initialize the stream that will help us update this texture's contents
-    sp<StreamHandler> pStreamHandler = new StreamHandler(pCamera);
-    if (pStreamHandler.get() == nullptr) {
-        ALOGE("failed to allocate FrameHandler");
-        return nullptr;
-    }
-
-    // Start the video stream
-    if (!pStreamHandler->startStream()) {
-        printf("Couldn't start the camera stream (%s)\n", evsCameraId);
-        ALOGE("start stream failed for %s", evsCameraId);
-        return nullptr;
-    }
-
-    return new VideoTex(pEnum, pCamera, pStreamHandler, glDisplay);
-}
diff --git a/evs/app/VideoTex.h b/evs/app/VideoTex.h
deleted file mode 100644
index 0b95c1d..0000000
--- a/evs/app/VideoTex.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef VIDEOTEX_H
-#define VIDEOTEX_H
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#include <GLES3/gl3.h>
-#include <GLES3/gl3ext.h>
-
-#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
-
-#include "TexWrapper.h"
-#include "StreamHandler.h"
-
-
-using namespace ::android::hardware::automotive::evs::V1_0;
-
-
-class VideoTex: public TexWrapper {
-    friend VideoTex* createVideoTexture(sp<IEvsEnumerator> pEnum,
-                                        const char * evsCameraId,
-                                        EGLDisplay glDisplay);
-
-public:
-    VideoTex() = delete;
-    virtual ~VideoTex();
-
-    bool refresh();     // returns true if the texture contents were updated
-
-private:
-    VideoTex(sp<IEvsEnumerator> pEnum,
-             sp<IEvsCamera> pCamera,
-             sp<StreamHandler> pStreamHandler,
-             EGLDisplay glDisplay);
-
-    sp<IEvsEnumerator>  mEnumerator;
-    sp<IEvsCamera>      mCamera;
-    sp<StreamHandler>   mStreamHandler;
-    BufferDesc          mImageBuffer;
-
-    EGLDisplay          mDisplay;
-    EGLImageKHR mKHRimage = EGL_NO_IMAGE_KHR;
-};
-
-
-VideoTex* createVideoTexture(sp<IEvsEnumerator> pEnum,
-                             const char * deviceName,
-                             EGLDisplay glDisplay);
-
-#endif // VIDEOTEX_H
\ No newline at end of file
diff --git a/evs/app/WindowSurface.cpp b/evs/app/WindowSurface.cpp
deleted file mode 100644
index dbd245b..0000000
--- a/evs/app/WindowSurface.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "WindowSurface.h"
-
-#include <gui/SurfaceComposerClient.h>
-#include <gui/ISurfaceComposer.h>
-#include <gui/Surface.h>
-#include <ui/DisplayInfo.h>
-
-using namespace android;
-
-WindowSurface::WindowSurface() {
-    status_t err;
-
-    sp<SurfaceComposerClient> surfaceComposerClient = new SurfaceComposerClient;
-    err = surfaceComposerClient->initCheck();
-    if (err != NO_ERROR) {
-        fprintf(stderr, "SurfaceComposerClient::initCheck error: %#x\n", err);
-        return;
-    }
-
-    // Get main display parameters.
-    sp<IBinder> mainDpy = SurfaceComposerClient::getInternalDisplayToken();
-    if (mainDpy == nullptr) {
-        fprintf(stderr, "ERROR: no internal display\n");
-        return;
-    }
-
-    DisplayInfo mainDpyInfo;
-    err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
-    if (err != NO_ERROR) {
-        fprintf(stderr, "ERROR: unable to get display characteristics\n");
-        return;
-    }
-
-    uint32_t width, height;
-    if (mainDpyInfo.orientation != DISPLAY_ORIENTATION_0 &&
-            mainDpyInfo.orientation != DISPLAY_ORIENTATION_180) {
-        // rotated
-        width = mainDpyInfo.h;
-        height = mainDpyInfo.w;
-    } else {
-        width = mainDpyInfo.w;
-        height = mainDpyInfo.h;
-    }
-
-    sp<SurfaceControl> sc = surfaceComposerClient->createSurface(
-            String8("Benchmark"), width, height,
-            PIXEL_FORMAT_RGBX_8888, ISurfaceComposerClient::eOpaque);
-    if (sc == NULL || !sc->isValid()) {
-        fprintf(stderr, "Failed to create SurfaceControl\n");
-        return;
-    }
-
-    SurfaceComposerClient::Transaction{}
-            .setLayer(sc, 0x7FFFFFFF)     // always on top
-            .show(sc)
-            .apply();
-
-    mSurfaceControl = sc;
-}
-
-EGLNativeWindowType WindowSurface::getSurface() const {
-    sp<ANativeWindow> anw = mSurfaceControl->getSurface();
-    return (EGLNativeWindowType) anw.get();
-}
-
diff --git a/evs/app/WindowSurface.h b/evs/app/WindowSurface.h
deleted file mode 100644
index 966ea11..0000000
--- a/evs/app/WindowSurface.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef OPENGL_TESTS_WINDOWSURFACE_H
-#define OPENGL_TESTS_WINDOWSURFACE_H
-
-#include <gui/SurfaceControl.h>
-
-#include <EGL/egl.h>
-
-
-/*
- * A window that covers the entire display surface.
- *
- * The window is destroyed when this object is destroyed, so don't try
- * to use the surface after that point.
- */
-class WindowSurface {
-public:
-    // Creates the window.
-    WindowSurface();
-
-    // Retrieves a handle to the window.
-    EGLNativeWindowType getSurface() const;
-
-private:
-    WindowSurface(const WindowSurface&) = delete;
-    WindowSurface& operator=(const WindowSurface&) = delete;
-
-    android::sp<android::SurfaceControl> mSurfaceControl;
-};
-
-#endif /* OPENGL_TESTS_WINDOWSURFACE_H */
diff --git a/evs/app/config.json.readme b/evs/app/config.json.readme
deleted file mode 100644
index 982e3c9..0000000
--- a/evs/app/config.json.readme
+++ /dev/null
@@ -1,42 +0,0 @@
-// With comments included, this file is no longer legal JSON, but serves to illustrate
-// the format of the configuration file the evs_app expects to read at startup to configure itself
-// for a specific car.
-// In addition to the configuration file, an image to be used to represent the car is expected
-// to be provided in CarFromTop.png.
-// Throughout this file, units of length are arbitrary, but must all be the same units.
-// X is right, Y is forward, Z is up (right handed coordinate system).
-// The origin is at the center of the read axel at ground level.
-// Units for angles are in degrees.
-// Yaw is measured from the front of the car, positive to the left (postive Z rotation).
-// Pitch is measured from the horizon, positive upward (postive X rotation).
-// Roll is always assumed to be zero.
-
-{
-  "car" : {                     // This section describes the geometry of the car
-    "width"  : 76.7,            // The width of the car body
-    "wheelBase" : 117.9,        // The distance between the front and read axel
-    "frontExtent" : 44.7,       // The extent of the car body ahead of the front axel
-    "rearExtent" : 40           // The extent of the car body behind the read axel
-  },
-  "display" : {                 // This configures the dimensions of the surround view display
-    "frontRange" : 100,         // How far to render the view in front of the front bumper
-    "rearRange" : 100           // How far the view extends behind the rear bumper
-  },
-  "graphic" : {                 // This maps the car texture into the projected view space
-    "frontPixel" : 23,          // The pixel row in CarFromTop.png at which the front bumper appears
-    "rearPixel" : 223           // The pixel row in CarFromTop.png at which the back bumper ends
-  },
-  "cameras" : [                 // This describes the cameras potentially available on the car
-    {
-      "cameraId" : "/dev/video32",  // Camera ID exposed by EVS HAL
-      "function" : "reverse,park",  // set of modes to which this camera contributes
-      "x" : 0.0,                    // Optical center distance right of vehicle center
-      "y" : -40.0,                  // Optical center distance forward of rear axel
-      "z" : 48,                     // Optical center distance above ground
-      "yaw" : 180,                  // Optical axis degrees to the left of straight ahead
-      "pitch" : -30,                // Optical axis degrees above the horizon
-      "hfov" : 125,                 // Horizontal field of view in degrees
-      "vfov" :103                   // Vertical field of view in degrees
-    }
-  ]
-}
diff --git a/evs/app/evs_app.cpp b/evs/app/evs_app.cpp
deleted file mode 100644
index 31e5ab6..0000000
--- a/evs/app/evs_app.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-
-#include <hidl/HidlTransportSupport.h>
-#include <utils/Errors.h>
-#include <utils/StrongPointer.h>
-#include <utils/Log.h>
-
-#include "android-base/macros.h"    // arraysize
-
-#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
-#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
-
-#include <hwbinder/ProcessState.h>
-
-#include "EvsStateControl.h"
-#include "EvsVehicleListener.h"
-#include "ConfigManager.h"
-
-
-// libhidl:
-using android::hardware::configureRpcThreadpool;
-using android::hardware::joinRpcThreadpool;
-
-
-// Helper to subscribe to VHal notifications
-static bool subscribeToVHal(sp<IVehicle> pVnet,
-                            sp<IVehicleCallback> listener,
-                            VehicleProperty propertyId) {
-    assert(pVnet != nullptr);
-    assert(listener != nullptr);
-
-    // Register for vehicle state change callbacks we care about
-    // Changes in these values are what will trigger a reconfiguration of the EVS pipeline
-    SubscribeOptions optionsData[] = {
-        {
-            .propId = static_cast<int32_t>(propertyId),
-            .flags  = SubscribeFlags::EVENTS_FROM_CAR
-        },
-    };
-    hidl_vec <SubscribeOptions> options;
-    options.setToExternal(optionsData, arraysize(optionsData));
-    StatusCode status = pVnet->subscribe(listener, options);
-    if (status != StatusCode::OK) {
-        ALOGW("VHAL subscription for property 0x%08X failed with code %d.", propertyId, status);
-        return false;
-    }
-
-    return true;
-}
-
-
-// Main entry point
-int main(int argc, char** argv)
-{
-    ALOGI("EVS app starting\n");
-
-    // Set up default behavior, then check for command line options
-    bool useVehicleHal = true;
-    bool printHelp = false;
-    const char* evsServiceName = "default";
-    for (int i=1; i< argc; i++) {
-        if (strcmp(argv[i], "--test") == 0) {
-            useVehicleHal = false;
-        } else if (strcmp(argv[i], "--hw") == 0) {
-            evsServiceName = "EvsEnumeratorHw";
-        } else if (strcmp(argv[i], "--mock") == 0) {
-            evsServiceName = "EvsEnumeratorHw-Mock";
-        } else if (strcmp(argv[i], "--help") == 0) {
-            printHelp = true;
-        } else {
-            printf("Ignoring unrecognized command line arg '%s'\n", argv[i]);
-            printHelp = true;
-        }
-    }
-    if (printHelp) {
-        printf("Options include:\n");
-        printf("  --test   Do not talk to Vehicle Hal, but simulate 'reverse' instead\n");
-        printf("  --hw     Bypass EvsManager by connecting directly to EvsEnumeratorHw\n");
-        printf("  --mock   Connect directly to EvsEnumeratorHw-Mock\n");
-    }
-
-    // Load our configuration information
-    ConfigManager config;
-    if (!config.initialize("/system/etc/automotive/evs/config.json")) {
-        ALOGE("Missing or improper configuration for the EVS application.  Exiting.");
-        return 1;
-    }
-
-    // Set thread pool size to one to avoid concurrent events from the HAL.
-    // This pool will handle the EvsCameraStream callbacks.
-    // Note:  This _will_ run in parallel with the EvsListener run() loop below which
-    // runs the application logic that reacts to the async events.
-    configureRpcThreadpool(1, false /* callerWillJoin */);
-
-    // Construct our async helper object
-    sp<EvsVehicleListener> pEvsListener = new EvsVehicleListener();
-
-    // Get the EVS manager service
-    ALOGI("Acquiring EVS Enumerator");
-    android::sp<IEvsEnumerator> pEvs = IEvsEnumerator::getService(evsServiceName);
-    if (pEvs.get() == nullptr) {
-        ALOGE("getService(%s) returned NULL.  Exiting.", evsServiceName);
-        return 1;
-    }
-
-    // Request exclusive access to the EVS display
-    ALOGI("Acquiring EVS Display");
-    android::sp <IEvsDisplay> pDisplay;
-    pDisplay = pEvs->openDisplay();
-    if (pDisplay.get() == nullptr) {
-        ALOGE("EVS Display unavailable.  Exiting.");
-        return 1;
-    }
-
-    // Connect to the Vehicle HAL so we can monitor state
-    sp<IVehicle> pVnet;
-    if (useVehicleHal) {
-        ALOGI("Connecting to Vehicle HAL");
-        pVnet = IVehicle::getService();
-        if (pVnet.get() == nullptr) {
-            ALOGE("Vehicle HAL getService returned NULL.  Exiting.");
-            return 1;
-        } else {
-            // Register for vehicle state change callbacks we care about
-            // Changes in these values are what will trigger a reconfiguration of the EVS pipeline
-            if (!subscribeToVHal(pVnet, pEvsListener, VehicleProperty::GEAR_SELECTION)) {
-                ALOGE("Without gear notification, we can't support EVS.  Exiting.");
-                return 1;
-            }
-            if (!subscribeToVHal(pVnet, pEvsListener, VehicleProperty::TURN_SIGNAL_STATE)) {
-                ALOGW("Didn't get turn signal notificaitons, so we'll ignore those.");
-            }
-        }
-    } else {
-        ALOGW("Test mode selected, so not talking to Vehicle HAL");
-    }
-
-    // Configure ourselves for the current vehicle state at startup
-    ALOGI("Constructing state controller");
-    EvsStateControl *pStateController = new EvsStateControl(pVnet, pEvs, pDisplay, config);
-    if (!pStateController->startUpdateLoop()) {
-        ALOGE("Initial configuration failed.  Exiting.");
-        return 1;
-    }
-
-    // Run forever, reacting to events as necessary
-    ALOGI("Entering running state");
-    pEvsListener->run(pStateController);
-
-    // In normal operation, we expect to run forever, but in some error conditions we'll quit.
-    // One known example is if another process preempts our registration for our service name.
-    ALOGE("EVS Listener stopped.  Exiting.");
-
-    return 0;
-}
diff --git a/evs/apps/default/Android.bp b/evs/apps/default/Android.bp
new file mode 100644
index 0000000..df6fd0d
--- /dev/null
+++ b/evs/apps/default/Android.bp
@@ -0,0 +1,102 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+
+//#################################
+cc_binary {
+    name: "evs_app",
+
+    srcs: [
+        "evs_app.cpp",
+        "EvsStateControl.cpp",
+        "RenderBase.cpp",
+        "RenderDirectView.cpp",
+        "RenderTopView.cpp",
+        "ConfigManager.cpp",
+        "glError.cpp",
+        "shader.cpp",
+        "TexWrapper.cpp",
+        "VideoTex.cpp",
+        "StreamHandler.cpp",
+        "FormatConvert.cpp",
+        "RenderPixelCopy.cpp",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libutils",
+        "libui",
+        "libhidlbase",
+        "libEGL",
+        "libGLESv2",
+        "libhardware",
+        "libpng",
+        "libcamera_metadata",
+        "android.hardware.camera.device@3.2",
+        "android.hardware.automotive.evs@1.0",
+        "android.hardware.automotive.evs@1.1",
+        "android.hardware.automotive.vehicle@2.0",
+    ],
+
+    static_libs: [
+        "libmath",
+        "libjsoncpp",
+    ],
+
+    required: [
+        "config.json",
+        "CarFromTop.png",
+        "LabeledChecker.png",
+    ],
+
+    init_rc: ["evs_app.rc"],
+
+    cflags: ["-DLOG_TAG=\"EvsApp\""] + [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+    ] + [
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+
+}
+
+prebuilt_etc {
+    name: "config.json",
+
+    src: "config.json",
+    sub_dir: "automotive/evs",
+
+}
+
+prebuilt_etc {
+    name: "CarFromTop.png",
+
+    src: "CarFromTop.png",
+    sub_dir: "automotive/evs",
+
+}
+
+prebuilt_etc {
+    name: "LabeledChecker.png",
+
+    src: "LabeledChecker.png",
+    sub_dir: "automotive/evs",
+
+}
diff --git a/evs/app/CarFromTop.png b/evs/apps/default/CarFromTop.png
similarity index 100%
rename from evs/app/CarFromTop.png
rename to evs/apps/default/CarFromTop.png
Binary files differ
diff --git a/evs/apps/default/ConfigManager.cpp b/evs/apps/default/ConfigManager.cpp
new file mode 100644
index 0000000..76c142c
--- /dev/null
+++ b/evs/apps/default/ConfigManager.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "ConfigManager.h"
+
+#include "json/json.h"
+
+#include <fstream>
+#include <math.h>
+#include <assert.h>
+
+
+static const float kDegreesToRadians = M_PI / 180.0f;
+
+
+static float normalizeToPlusMinus180degrees(float theta) {
+    const float wraps = floor((theta+180.0f) / 360.0f);
+    return theta - wraps*360.0f;
+}
+
+
+static bool readChildNodeAsFloat(const char* groupName,
+                                 const Json::Value& parentNode,
+                                 const char* childName,
+                                 float* value) {
+    // Must have a place to put the value!
+    assert(value);
+
+    Json::Value childNode = parentNode[childName];
+    if (!childNode.isNumeric()) {
+        printf("Missing or invalid field %s in record %s", childName, groupName);
+        return false;
+    }
+
+    *value = childNode.asFloat();
+    return true;
+}
+
+
+bool ConfigManager::initialize(const char* configFileName)
+{
+    bool complete = true;
+
+    // Set up a stream to read in the input file
+    std::ifstream configStream(configFileName);
+
+    // Parse the stream into JSON objects
+    Json::Reader reader;
+    Json::Value rootNode;
+    bool parseOk = reader.parse(configStream, rootNode, false /* don't need comments */);
+    if (!parseOk) {
+        printf("Failed to read configuration file %s\n", configFileName);
+        printf("%s\n", reader.getFormatedErrorMessages().c_str());
+        return false;
+    }
+
+
+    //
+    // Read car information
+    //
+    {
+        Json::Value car = rootNode["car"];
+        if (!car.isObject()) {
+            printf("Invalid configuration format -- we expect a car description\n");
+            return false;
+        }
+        complete &= readChildNodeAsFloat("car", car, "width",       &mCarWidth);
+        complete &= readChildNodeAsFloat("car", car, "wheelBase",   &mWheelBase);
+        complete &= readChildNodeAsFloat("car", car, "frontExtent", &mFrontExtent);
+        complete &= readChildNodeAsFloat("car", car, "rearExtent",  &mRearExtent);
+    }
+
+
+    //
+    // Read display layout information
+    //
+    {
+        Json::Value displayArray = rootNode["displays"];
+        if (!displayArray.isArray()) {
+            printf("Invalid configuration format -- we expect an array of displays\n");
+            return false;
+        }
+
+        mDisplays.reserve(displayArray.size());
+        for (auto&& node : displayArray) {
+            DisplayInfo info;
+            info.port = node.get("displayPort", 0).asUInt();
+            info.function = node.get("function", "").asCString();
+            info.frontRangeInCarSpace = node.get("frontRange", -1).asFloat();
+            info.rearRangeInCarSpace = node.get("rearRange", -1).asFloat();
+
+            mDisplays.emplace_back(info);
+        }
+    }
+
+
+    //
+    // Car top view texture properties for top down view
+    //
+    {
+        Json::Value graphicNode = rootNode["graphic"];
+        if (!graphicNode.isObject()) {
+            printf("Invalid configuration format -- we expect a graphic description\n");
+            return false;
+        }
+        complete &= readChildNodeAsFloat("graphic", graphicNode, "frontPixel", &mCarGraphicFrontPixel);
+        complete &= readChildNodeAsFloat("display", graphicNode, "rearPixel",  &mCarGraphicRearPixel);
+    }
+
+
+    //
+    // Read camera information
+    // NOTE:  Missing positions and angles are not reported, but instead default to zero
+    //
+    {
+        Json::Value cameraArray = rootNode["cameras"];
+        if (!cameraArray.isArray()) {
+            printf("Invalid configuration format -- we expect an array of cameras\n");
+            return false;
+        }
+
+        mCameras.reserve(cameraArray.size());
+        for (auto&& node: cameraArray) {
+            // Get data from the configuration file
+            Json::Value nameNode = node.get("cameraId", "MISSING");
+            const char *cameraId = nameNode.asCString();
+
+            Json::Value usageNode = node.get("function", "");
+            const char *function = usageNode.asCString();
+
+            float yaw   = node.get("yaw", 0).asFloat();
+            float pitch = node.get("pitch", 0).asFloat();
+            float hfov  = node.get("hfov", 0).asFloat();
+            float vfov  = node.get("vfov", 0).asFloat();
+
+            // Wrap the direction angles to be in the 180deg to -180deg range
+            // Rotate 180 in yaw if necessary to flip the pitch into the +/-90degree range
+            pitch = normalizeToPlusMinus180degrees(pitch);
+            if (pitch > 90.0f) {
+                yaw += 180.0f;
+                pitch = 180.0f - pitch;
+            }
+            if (pitch < -90.0f) {
+                yaw += 180.0f;
+                pitch = -180.0f + pitch;
+            }
+            yaw = normalizeToPlusMinus180degrees(yaw);
+
+            // Range check the FOV values to ensure they are postive and less than 180degrees
+            if (hfov > 179.0f) {
+                printf("Pathological horizontal field of view %f clamped to 179 degrees\n", hfov);
+                hfov = 179.0f;
+            }
+            if (hfov < 1.0f) {
+                printf("Pathological horizontal field of view %f clamped to 1 degree\n", hfov);
+                hfov = 1.0f;
+            }
+            if (vfov > 179.0f) {
+                printf("Pathological horizontal field of view %f clamped to 179 degrees\n", vfov);
+                vfov = 179.0f;
+            }
+            if (vfov < 1.0f) {
+                printf("Pathological horizontal field of view %f clamped to 1 degree\n", vfov);
+                vfov = 1.0f;
+            }
+
+            // Store the camera info (converting degrees to radians in the process)
+            CameraInfo info;
+            info.position[0] = node.get("x", 0).asFloat();
+            info.position[1] = node.get("y", 0).asFloat();
+            info.position[2] = node.get("z", 0).asFloat();
+            info.yaw         = yaw   * kDegreesToRadians;
+            info.pitch       = pitch * kDegreesToRadians;
+            info.hfov        = hfov  * kDegreesToRadians;
+            info.vfov        = vfov  * kDegreesToRadians;
+            info.cameraId    = cameraId;
+            info.function    = function;
+
+            mCameras.emplace_back(info);
+        }
+    }
+
+    // If we got this far, we were successful as long as we found all our child fields
+    return complete;
+}
diff --git a/evs/apps/default/ConfigManager.h b/evs/apps/default/ConfigManager.h
new file mode 100644
index 0000000..7c2186d
--- /dev/null
+++ b/evs/apps/default/ConfigManager.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef CONFIG_MANAGER_H
+#define CONFIG_MANAGER_H
+
+#include <cerrno>
+#include <string>
+#include <vector>
+
+#include <system/graphics-base.h>
+
+
+class ConfigManager {
+public:
+    struct CameraInfo {
+        std::string cameraId = "";  // The name of the camera from the point of view of the HAL
+        std::string function = "";  // The expected use for this camera ("reverse", "left", "right")
+        float position[3] = {0};    // x, y, z -> right, fwd, up in the units of car space
+        float yaw   = 0;    // radians positive to the left (right hand rule about global z axis)
+        float pitch = 0;    // positive upward (ie: right hand rule about local x axis)
+        float hfov  = 0;    // radians
+        float vfov  = 0;    // radians
+    };
+
+    struct DisplayInfo {
+        uint8_t port = 0;           // Display port number to use
+        std::string function = "";  // The expected use for this display.
+        float frontRangeInCarSpace; // How far the display extends in front of the car
+        float rearRangeInCarSpace;  // How far the display extends behind the car
+    };
+
+    bool initialize(const char* configFileName);
+
+    // World space dimensions of the car
+    float getCarWidth() const   { return mCarWidth; };
+    float getCarLength() const  { return mWheelBase + mFrontExtent + mRearExtent; };
+    float getWheelBase() const  { return mWheelBase; };
+
+    // Car space (world space centered on the rear axel) edges of the car
+    float getFrontLocation() const  { return mWheelBase + mFrontExtent; };
+    float getRearLocation() const   { return -mRearExtent; };
+    float getRightLocation() const  { return mCarWidth*0.5f; };
+    float getLeftLocation() const   { return -mCarWidth*0.5f; };
+
+    // Where are the edges of the top down display in car space?
+    float getDisplayTopLocation() const {
+        // From the rear axel (origin) to the front bumper, and then beyond by the front range
+        return mWheelBase + mFrontExtent + mDisplays[mActiveDisplayId].frontRangeInCarSpace;
+    };
+    float getDisplayBottomLocation() const {
+        // From the rear axel (origin) to the back bumper, and then beyond by the back range
+        return -mRearExtent - mDisplays[mActiveDisplayId].rearRangeInCarSpace;
+    };
+    float getDisplayRightLocation(float aspectRatio) const   {
+        // Given the display aspect ratio (width over height), how far can we see to the right?
+        return (getDisplayTopLocation() - getDisplayBottomLocation()) * 0.5f * aspectRatio;
+    };
+    float getDisplayLeftLocation(float aspectRatio) const {
+        // Given the display aspect ratio (width over height), how far can we see to the left?
+        return -getDisplayRightLocation(aspectRatio);
+    };
+
+    // At which texel (vertically in the image) are the front and rear bumpers of the car?
+    float carGraphicFrontPixel() const      { return mCarGraphicFrontPixel; };
+    float carGraphicRearPixel() const       { return mCarGraphicRearPixel; };
+
+    const std::vector<CameraInfo>& getCameras() const   { return mCameras; };
+
+    int  setActiveDisplayId(int displayId) {
+        if (displayId == -1) {
+            // -1 is reserved for the default display, which is the first
+            // display in config.json's display list
+            printf("Uses a display with id %d", mDisplays[0].port);
+            mActiveDisplayId = mDisplays[0].port;
+            return mActiveDisplayId;
+        } else if (displayId < 0) {
+            printf("Display %d is invalid.", displayId);
+            return -ENOENT;
+        } else {
+            for (auto display : mDisplays) {
+                if (display.port == displayId) {
+                    mActiveDisplayId = displayId;
+                    return mActiveDisplayId;
+                }
+            }
+
+            printf("Display %d does not exist.", displayId);
+            return -ENOENT;
+        }
+    }
+    const std::vector<DisplayInfo>& getDisplays() const { return mDisplays; };
+    const DisplayInfo& getActiveDisplay() const { return mDisplays[mActiveDisplayId]; };
+    void  useExternalMemory(bool flag) { mUseExternalMemory = flag; }
+    bool  getUseExternalMemory() const { return mUseExternalMemory; }
+    void  setExternalMemoryFormat(android_pixel_format_t format) {
+        mExternalMemoryFormat = format;
+    }
+    android_pixel_format_t getExternalMemoryFormat() const {
+        return mExternalMemoryFormat;
+    }
+
+private:
+    // Camera information
+    std::vector<CameraInfo> mCameras;
+
+    // Display information
+    std::vector<DisplayInfo> mDisplays;
+    int mActiveDisplayId;
+
+    // Memory management
+    bool mUseExternalMemory;
+
+    // Format of external memory
+    android_pixel_format_t mExternalMemoryFormat;
+
+    // Car body information (assumes front wheel steering and origin at center of rear axel)
+    // Note that units aren't specified and don't matter as long as all length units are consistent
+    // within the JSON file from which we parse.  That is, if everything is in meters, that's fine.
+    // Everything in mm?  That's fine too.
+    float mCarWidth;
+    float mWheelBase;
+    float mFrontExtent;
+    float mRearExtent;
+
+    // Top view car image information
+    float mCarGraphicFrontPixel;    // How many pixels from the top of the image does the car start
+    float mCarGraphicRearPixel;     // How many pixels from the top of the image does the car end
+};
+
+#endif // CONFIG_MANAGER_H
diff --git a/evs/apps/default/EvsStateControl.cpp b/evs/apps/default/EvsStateControl.cpp
new file mode 100644
index 0000000..06af502
--- /dev/null
+++ b/evs/apps/default/EvsStateControl.cpp
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "EvsStateControl.h"
+#include "RenderDirectView.h"
+#include "RenderTopView.h"
+#include "RenderPixelCopy.h"
+#include "FormatConvert.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <android-base/logging.h>
+#include <inttypes.h>
+#include <utils/SystemClock.h>
+#include <binder/IServiceManager.h>
+
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using EvsDisplayState = ::android::hardware::automotive::evs::V1_0::DisplayState;
+using BufferDesc_1_0  = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using BufferDesc_1_1  = ::android::hardware::automotive::evs::V1_1::BufferDesc;
+
+static bool isSfReady() {
+    const android::String16 serviceName("SurfaceFlinger");
+    return android::defaultServiceManager()->checkService(serviceName) != nullptr;
+}
+
+// TODO:  Seems like it'd be nice if the Vehicle HAL provided such helpers (but how & where?)
+inline constexpr VehiclePropertyType getPropType(VehicleProperty prop) {
+    return static_cast<VehiclePropertyType>(
+            static_cast<int32_t>(prop)
+            & static_cast<int32_t>(VehiclePropertyType::MASK));
+}
+
+
+EvsStateControl::EvsStateControl(android::sp <IVehicle>       pVnet,
+                                 android::sp <IEvsEnumerator> pEvs,
+                                 android::sp <IEvsDisplay>    pDisplay,
+                                 const ConfigManager&         config) :
+    mVehicle(pVnet),
+    mEvs(pEvs),
+    mDisplay(pDisplay),
+    mConfig(config),
+    mCurrentState(OFF) {
+
+    // Initialize the property value containers we'll be updating (they'll be zeroed by default)
+    static_assert(getPropType(VehicleProperty::GEAR_SELECTION) == VehiclePropertyType::INT32,
+                  "Unexpected type for GEAR_SELECTION property");
+    static_assert(getPropType(VehicleProperty::TURN_SIGNAL_STATE) == VehiclePropertyType::INT32,
+                  "Unexpected type for TURN_SIGNAL_STATE property");
+
+    mGearValue.prop       = static_cast<int32_t>(VehicleProperty::GEAR_SELECTION);
+    mTurnSignalValue.prop = static_cast<int32_t>(VehicleProperty::TURN_SIGNAL_STATE);
+
+    // This way we only ever deal with cameras which exist in the system
+    // Build our set of cameras for the states we support
+    LOG(DEBUG) << "Requesting camera list";
+    mEvs->getCameraList_1_1(
+        [this, &config](hidl_vec<CameraDesc> cameraList) {
+            LOG(INFO) << "Camera list callback received " << cameraList.size() << "cameras.";
+            for (auto&& cam: cameraList) {
+                LOG(DEBUG) << "Found camera " << cam.v1.cameraId;
+                bool cameraConfigFound = false;
+
+                // Check our configuration for information about this camera
+                // Note that a camera can have a compound function string
+                // such that a camera can be "right/reverse" and be used for both.
+                // If more than one camera is listed for a given function, we'll
+                // list all of them and let the UX/rendering logic use one, some
+                // or all of them as appropriate.
+                for (auto&& info: config.getCameras()) {
+                    if (cam.v1.cameraId == info.cameraId) {
+                        // We found a match!
+                        if (info.function.find("reverse") != std::string::npos) {
+                            mCameraList[State::REVERSE].emplace_back(info);
+                            mCameraDescList[State::REVERSE].emplace_back(cam);
+                        }
+                        if (info.function.find("right") != std::string::npos) {
+                            mCameraList[State::RIGHT].emplace_back(info);
+                            mCameraDescList[State::RIGHT].emplace_back(cam);
+                        }
+                        if (info.function.find("left") != std::string::npos) {
+                            mCameraList[State::LEFT].emplace_back(info);
+                            mCameraDescList[State::LEFT].emplace_back(cam);
+                        }
+                        if (info.function.find("park") != std::string::npos) {
+                            mCameraList[State::PARKING].emplace_back(info);
+                            mCameraDescList[State::PARKING].emplace_back(cam);
+                        }
+                        cameraConfigFound = true;
+                        break;
+                    }
+                }
+                if (!cameraConfigFound) {
+                    LOG(WARNING) << "No config information for hardware camera "
+                                 << cam.v1.cameraId;
+                }
+            }
+        }
+    );
+
+    LOG(DEBUG) << "State controller ready";
+}
+
+
+bool EvsStateControl::startUpdateLoop() {
+    // Create the thread and report success if it gets started
+    mRenderThread = std::thread([this](){ updateLoop(); });
+    return mRenderThread.joinable();
+}
+
+
+void EvsStateControl::terminateUpdateLoop() {
+    // Join a rendering thread
+    if (mRenderThread.joinable()) {
+        mRenderThread.join();
+    }
+}
+
+
+void EvsStateControl::postCommand(const Command& cmd, bool clear) {
+    // Push the command onto the queue watched by updateLoop
+    mLock.lock();
+    if (clear) {
+        std::queue<Command> emptyQueue;
+        std::swap(emptyQueue, mCommandQueue);
+    }
+
+    mCommandQueue.push(cmd);
+    mLock.unlock();
+
+    // Send a signal to wake updateLoop in case it is asleep
+    mWakeSignal.notify_all();
+}
+
+
+void EvsStateControl::updateLoop() {
+    LOG(DEBUG) << "Starting EvsStateControl update loop";
+
+    bool run = true;
+    while (run) {
+        // Process incoming commands
+        {
+            std::lock_guard <std::mutex> lock(mLock);
+            while (!mCommandQueue.empty()) {
+                const Command& cmd = mCommandQueue.front();
+                switch (cmd.operation) {
+                case Op::EXIT:
+                    run = false;
+                    break;
+                case Op::CHECK_VEHICLE_STATE:
+                    // Just running selectStateForCurrentConditions below will take care of this
+                    break;
+                case Op::TOUCH_EVENT:
+                    // Implement this given the x/y location of the touch event
+                    break;
+                }
+                mCommandQueue.pop();
+            }
+        }
+
+        // Review vehicle state and choose an appropriate renderer
+        if (!selectStateForCurrentConditions()) {
+            LOG(ERROR) << "selectStateForCurrentConditions failed so we're going to die";
+            break;
+        }
+
+        // If we have an active renderer, give it a chance to draw
+        if (mCurrentRenderer) {
+            // Get the output buffer we'll use to display the imagery
+            BufferDesc_1_0 tgtBuffer = {};
+            mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) {
+                                          tgtBuffer = buff;
+                                      }
+            );
+
+            if (tgtBuffer.memHandle == nullptr) {
+                LOG(ERROR) << "Didn't get requested output buffer -- skipping this frame.";
+            } else {
+                // Generate our output image
+                if (!mCurrentRenderer->drawFrame(convertBufferDesc(tgtBuffer))) {
+                    // If drawing failed, we want to exit quickly so an app restart can happen
+                    run = false;
+                }
+
+                // Send the finished image back for display
+                mDisplay->returnTargetBufferForDisplay(tgtBuffer);
+            }
+        } else if (run) {
+            // No active renderer, so sleep until somebody wakes us with another command
+            // or exit if we received EXIT command
+            std::unique_lock<std::mutex> lock(mLock);
+            mWakeSignal.wait(lock);
+        }
+    }
+
+    LOG(WARNING) << "EvsStateControl update loop ending";
+
+    if (mCurrentRenderer) {
+        // Deactive the renderer
+        mCurrentRenderer->deactivate();
+    }
+
+    printf("Shutting down app due to state control loop ending\n");
+    LOG(ERROR) << "Shutting down app due to state control loop ending";
+}
+
+
+bool EvsStateControl::selectStateForCurrentConditions() {
+    static int32_t sDummyGear   = int32_t(VehicleGear::GEAR_REVERSE);
+    static int32_t sDummySignal = int32_t(VehicleTurnSignal::NONE);
+
+    if (mVehicle != nullptr) {
+        // Query the car state
+        if (invokeGet(&mGearValue) != StatusCode::OK) {
+            LOG(ERROR) << "GEAR_SELECTION not available from vehicle.  Exiting.";
+            return false;
+        }
+        if ((mTurnSignalValue.prop == 0) || (invokeGet(&mTurnSignalValue) != StatusCode::OK)) {
+            // Silently treat missing turn signal state as no turn signal active
+            mTurnSignalValue.value.int32Values.setToExternal(&sDummySignal, 1);
+            mTurnSignalValue.prop = 0;
+        }
+    } else {
+        // While testing without a vehicle, behave as if we're in reverse for the first 20 seconds
+        static const int kShowTime = 20;    // seconds
+
+        // See if it's time to turn off the default reverse camera
+        static std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
+        std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
+        if (std::chrono::duration_cast<std::chrono::seconds>(now - start).count() > kShowTime) {
+            // Switch to drive (which should turn off the reverse camera)
+            sDummyGear = int32_t(VehicleGear::GEAR_DRIVE);
+        }
+
+        // Build the dummy vehicle state values (treating single values as 1 element vectors)
+        mGearValue.value.int32Values.setToExternal(&sDummyGear, 1);
+        mTurnSignalValue.value.int32Values.setToExternal(&sDummySignal, 1);
+    }
+
+    // Choose our desired EVS state based on the current car state
+    // TODO:  Update this logic, and consider user input when choosing if a view should be presented
+    State desiredState = OFF;
+    if (mGearValue.value.int32Values[0] == int32_t(VehicleGear::GEAR_REVERSE)) {
+        desiredState = REVERSE;
+    } else if (mTurnSignalValue.value.int32Values[0] == int32_t(VehicleTurnSignal::RIGHT)) {
+        desiredState = RIGHT;
+    } else if (mTurnSignalValue.value.int32Values[0] == int32_t(VehicleTurnSignal::LEFT)) {
+        desiredState = LEFT;
+    } else if (mGearValue.value.int32Values[0] == int32_t(VehicleGear::GEAR_PARK)) {
+        desiredState = PARKING;
+    }
+
+    // Apply the desire state
+    return configureEvsPipeline(desiredState);
+}
+
+
+StatusCode EvsStateControl::invokeGet(VehiclePropValue *pRequestedPropValue) {
+    StatusCode status = StatusCode::TRY_AGAIN;
+
+    // Call the Vehicle HAL, which will block until the callback is complete
+    mVehicle->get(*pRequestedPropValue,
+                  [pRequestedPropValue, &status]
+                  (StatusCode s, const VehiclePropValue& v) {
+                       status = s;
+                       if (s == StatusCode::OK) {
+                           *pRequestedPropValue = v;
+                       }
+                  }
+    );
+
+    return status;
+}
+
+
+bool EvsStateControl::configureEvsPipeline(State desiredState) {
+    static bool isGlReady = false;
+
+    if (mCurrentState == desiredState) {
+        // Nothing to do here...
+        return true;
+    }
+
+    LOG(DEBUG) << "Switching to state " << desiredState;
+    LOG(DEBUG) << "  Current state " << mCurrentState
+               << " has " << mCameraList[mCurrentState].size() << " cameras";
+    LOG(DEBUG) << "  Desired state " << desiredState
+               << " has " << mCameraList[desiredState].size() << " cameras";
+
+    if (!isGlReady && !isSfReady()) {
+        // Graphics is not ready yet; using CPU renderer.
+        if (mCameraList[desiredState].size() >= 1) {
+            mDesiredRenderer = std::make_unique<RenderPixelCopy>(mEvs,
+                                                                 mCameraList[desiredState][0]);
+            if (!mDesiredRenderer) {
+                LOG(ERROR) << "Failed to construct Pixel Copy renderer.  Skipping state change.";
+                return false;
+            }
+        } else {
+            LOG(DEBUG) << "Unsupported, desiredState " << desiredState
+                       << " has " << mCameraList[desiredState].size() << " cameras.";
+        }
+    } else {
+        // Assumes that SurfaceFlinger is available always after being launched.
+
+        // Do we need a new direct view renderer?
+        if (mCameraList[desiredState].size() == 1) {
+            // We have a camera assigned to this state for direct view.
+            mDesiredRenderer = std::make_unique<RenderDirectView>(mEvs,
+                                                                  mCameraDescList[desiredState][0],
+                                                                  mConfig);
+            if (!mDesiredRenderer) {
+                LOG(ERROR) << "Failed to construct direct renderer.  Skipping state change.";
+                return false;
+            }
+        } else if (mCameraList[desiredState].size() > 1 || desiredState == PARKING) {
+            //TODO(b/140668179): RenderTopView needs to be updated to use new
+            //                   ConfigManager.
+            mDesiredRenderer = std::make_unique<RenderTopView>(mEvs,
+                                                               mCameraList[desiredState],
+                                                               mConfig);
+            if (!mDesiredRenderer) {
+                LOG(ERROR) << "Failed to construct top view renderer.  Skipping state change.";
+                return false;
+            }
+        } else {
+            LOG(DEBUG) << "Unsupported, desiredState " << desiredState
+                       << " has " << mCameraList[desiredState].size() << " cameras.";
+        }
+
+        // GL renderer is now ready.
+        isGlReady = true;
+    }
+
+    // Since we're changing states, shut down the current renderer
+    if (mCurrentRenderer != nullptr) {
+        mCurrentRenderer->deactivate();
+        mCurrentRenderer = nullptr; // It's a smart pointer, so destructs on assignment to null
+    }
+
+    // Now set the display state based on whether we have a video feed to show
+    if (mDesiredRenderer == nullptr) {
+        LOG(DEBUG) << "Turning off the display";
+        mDisplay->setDisplayState(EvsDisplayState::NOT_VISIBLE);
+    } else {
+        mCurrentRenderer = std::move(mDesiredRenderer);
+
+        // Start the camera stream
+        LOG(DEBUG) << "EvsStartCameraStreamTiming start time: "
+                   << android::elapsedRealtime() << " ms.";
+        if (!mCurrentRenderer->activate()) {
+            LOG(ERROR) << "New renderer failed to activate";
+            return false;
+        }
+
+        // Activate the display
+        LOG(DEBUG) << "EvsActivateDisplayTiming start time: "
+                   << android::elapsedRealtime() << " ms.";
+        Return<EvsResult> result = mDisplay->setDisplayState(EvsDisplayState::VISIBLE_ON_NEXT_FRAME);
+        if (result != EvsResult::OK) {
+            LOG(ERROR) << "setDisplayState returned an error "
+                       << result.description();
+            return false;
+        }
+    }
+
+    // Record our current state
+    LOG(INFO) << "Activated state " << desiredState;
+    mCurrentState = desiredState;
+
+    return true;
+}
diff --git a/evs/apps/default/EvsStateControl.h b/evs/apps/default/EvsStateControl.h
new file mode 100644
index 0000000..1953906
--- /dev/null
+++ b/evs/apps/default/EvsStateControl.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CAR_EVS_APP_EVSSTATECONTROL_H
+#define CAR_EVS_APP_EVSSTATECONTROL_H
+
+#include "StreamHandler.h"
+#include "ConfigManager.h"
+#include "RenderBase.h"
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+
+#include <thread>
+
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+using namespace ::android::hardware::automotive::vehicle::V2_0;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_handle;
+using ::android::sp;
+using ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
+using ::android::hardware::camera::device::V3_2::Stream;
+
+
+/*
+ * This class runs the main update loop for the EVS application.  It will sleep when it has
+ * nothing to do.  It provides a thread safe way for other threads to wake it and pass commands
+ * to it.
+ */
+class EvsStateControl {
+public:
+    EvsStateControl(android::sp <IVehicle>       pVnet,
+                    android::sp <IEvsEnumerator> pEvs,
+                    android::sp <IEvsDisplay>    pDisplay,
+                    const ConfigManager&         config);
+
+    enum State {
+        OFF = 0,
+        REVERSE,
+        LEFT,
+        RIGHT,
+        PARKING,
+        NUM_STATES  // Must come last
+    };
+
+    enum class Op {
+        EXIT,
+        CHECK_VEHICLE_STATE,
+        TOUCH_EVENT,
+    };
+
+    struct Command {
+        Op          operation;
+        uint32_t    arg1;
+        uint32_t    arg2;
+    };
+
+    // This spawns a new thread that is expected to run continuously
+    bool startUpdateLoop();
+
+    // This stops a rendering thread
+    void terminateUpdateLoop();
+
+    // Safe to be called from other threads
+    void postCommand(const Command& cmd, bool clear = false);
+
+private:
+    void updateLoop();
+    StatusCode invokeGet(VehiclePropValue *pRequestedPropValue);
+    bool selectStateForCurrentConditions();
+    bool configureEvsPipeline(State desiredState);  // Only call from one thread!
+
+    sp<IVehicle>                mVehicle;
+    sp<IEvsEnumerator>          mEvs;
+    sp<IEvsDisplay>             mDisplay;
+    const ConfigManager&        mConfig;
+
+    VehiclePropValue            mGearValue;
+    VehiclePropValue            mTurnSignalValue;
+
+    State                       mCurrentState = OFF;
+
+    // mCameraList is a redundant storage for camera device info, which is also
+    // stored in mCameraDescList and, however, not removed for backward
+    // compatibility.
+    std::vector<ConfigManager::CameraInfo>  mCameraList[NUM_STATES];
+    std::unique_ptr<RenderBase> mCurrentRenderer;
+    std::unique_ptr<RenderBase> mDesiredRenderer;
+    std::vector<CameraDesc>     mCameraDescList[NUM_STATES];
+
+    std::thread                 mRenderThread;  // The thread that runs the main rendering loop
+
+    // Other threads may want to spur us into action, so we provide a thread safe way to do that
+    std::mutex                  mLock;
+    std::condition_variable     mWakeSignal;
+    std::queue<Command>         mCommandQueue;
+};
+
+
+#endif //CAR_EVS_APP_EVSSTATECONTROL_H
diff --git a/evs/app/EvsVehicleListener.h b/evs/apps/default/EvsVehicleListener.h
similarity index 100%
rename from evs/app/EvsVehicleListener.h
rename to evs/apps/default/EvsVehicleListener.h
diff --git a/evs/apps/default/FormatConvert.cpp b/evs/apps/default/FormatConvert.cpp
new file mode 100644
index 0000000..c562c79
--- /dev/null
+++ b/evs/apps/default/FormatConvert.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/hardware_buffer.h>
+#include "FormatConvert.h"
+
+
+// Round up to the nearest multiple of the given alignment value
+template<unsigned alignment>
+int align(int value) {
+    static_assert((alignment && !(alignment & (alignment - 1))),
+                  "alignment must be a power of 2");
+
+    unsigned mask = alignment - 1;
+    return (value + mask) & ~mask;
+}
+
+
+// Limit the given value to the provided range.  :)
+static inline float clamp(float v, float min, float max) {
+    if (v < min) return min;
+    if (v > max) return max;
+    return v;
+}
+
+
+static uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const unsigned char Vin) {
+    // Don't use this if you want to see the best performance.  :)
+    // Better to do this in a pixel shader if we really have to, but on actual
+    // embedded hardware we expect to be able to texture directly from the YUV data
+    float U = Uin - 128.0f;
+    float V = Vin - 128.0f;
+
+    float Rf = Y + 1.140f*V;
+    float Gf = Y - 0.395f*U - 0.581f*V;
+    float Bf = Y + 2.032f*U;
+    unsigned char R = (unsigned char)clamp(Rf, 0.0f, 255.0f);
+    unsigned char G = (unsigned char)clamp(Gf, 0.0f, 255.0f);
+    unsigned char B = (unsigned char)clamp(Bf, 0.0f, 255.0f);
+
+    return (R      ) |
+           (G <<  8) |
+           (B << 16) |
+           0xFF000000;  // Fill the alpha channel with ones
+}
+
+
+void copyNV21toRGB32(unsigned width, unsigned height,
+                     uint8_t* src,
+                     uint32_t* dst, unsigned dstStridePixels)
+{
+    // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
+    // U/V array.  It assumes an even width and height for the overall image, and a horizontal
+    // stride that is an even multiple of 16 bytes for both the Y and UV arrays.
+    unsigned strideLum = align<16>(width);
+    unsigned sizeY = strideLum * height;
+    unsigned strideColor = strideLum;   // 1/2 the samples, but two interleaved channels
+    unsigned offsetUV = sizeY;
+
+    uint8_t* srcY = src;
+    uint8_t* srcUV = src+offsetUV;
+
+    for (unsigned r = 0; r < height; r++) {
+        // Note that we're walking the same UV row twice for even/odd luminance rows
+        uint8_t* rowY  = srcY  + r*strideLum;
+        uint8_t* rowUV = srcUV + (r/2 * strideColor);
+
+        uint32_t* rowDest = dst + r*dstStridePixels;
+
+        for (unsigned c = 0; c < width; c++) {
+            unsigned uCol = (c & ~1);   // uCol is always even and repeats 1:2 with Y values
+            unsigned vCol = uCol | 1;   // vCol is always odd
+            rowDest[c] = yuvToRgbx(rowY[c], rowUV[uCol], rowUV[vCol]);
+        }
+    }
+}
+
+
+void copyYV12toRGB32(unsigned width, unsigned height,
+                     uint8_t* src,
+                     uint32_t* dst, unsigned dstStridePixels)
+{
+    // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
+    // by another 1/2 x 1/2 V array.  It assumes an even width and height for the overall image,
+    // and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
+    // and V arrays.
+    unsigned strideLum = align<16>(width);
+    unsigned sizeY = strideLum * height;
+    unsigned strideColor = align<16>(strideLum/2);
+    unsigned sizeColor = strideColor * height/2;
+    unsigned offsetU = sizeY;
+    unsigned offsetV = sizeY + sizeColor;
+
+    uint8_t* srcY = src;
+    uint8_t* srcU = src+offsetU;
+    uint8_t* srcV = src+offsetV;
+
+    for (unsigned r = 0; r < height; r++) {
+        // Note that we're walking the same U and V rows twice for even/odd luminance rows
+        uint8_t* rowY = srcY + r*strideLum;
+        uint8_t* rowU = srcU + (r/2 * strideColor);
+        uint8_t* rowV = srcV + (r/2 * strideColor);
+
+        uint32_t* rowDest = dst + r*dstStridePixels;
+
+        for (unsigned c = 0; c < width; c++) {
+            rowDest[c] = yuvToRgbx(rowY[c], rowU[c], rowV[c]);
+        }
+    }
+}
+
+
+void copyYUYVtoRGB32(unsigned width, unsigned height,
+                     uint8_t* src, unsigned srcStridePixels,
+                     uint32_t* dst, unsigned dstStridePixels)
+{
+    uint32_t* srcWords = (uint32_t*)src;
+
+    const int srcRowPadding32 = srcStridePixels/2 - width/2;  // 2 bytes per pixel, 4 bytes per word
+    const int dstRowPadding32 = dstStridePixels   - width;    // 4 bytes per pixel, 4 bytes per word
+
+    for (unsigned r = 0; r < height; r++) {
+        for (unsigned c = 0; c < width/2; c++) {
+            // Note:  we're walking two pixels at a time here (even/odd)
+            uint32_t srcPixel = *srcWords++;
+
+            uint8_t Y1 = (srcPixel)       & 0xFF;
+            uint8_t U  = (srcPixel >> 8)  & 0xFF;
+            uint8_t Y2 = (srcPixel >> 16) & 0xFF;
+            uint8_t V  = (srcPixel >> 24) & 0xFF;
+
+            // On the RGB output, we're writing one pixel at a time
+            *(dst+0) = yuvToRgbx(Y1, U, V);
+            *(dst+1) = yuvToRgbx(Y2, U, V);
+            dst += 2;
+        }
+
+        // Skip over any extra data or end of row alignment padding
+        srcWords += srcRowPadding32;
+        dst += dstRowPadding32;
+    }
+}
+
+
+void copyMatchedInterleavedFormats(unsigned width, unsigned height,
+                                   void* src, unsigned srcStridePixels,
+                                   void* dst, unsigned dstStridePixels,
+                                   unsigned pixelSize) {
+    for (unsigned row = 0; row < height; row++) {
+        // Copy the entire row of pixel data
+        memcpy(dst, src, width * pixelSize);
+
+        // Advance to the next row (keeping in mind that stride here is in units of pixels)
+        src = (uint8_t*)src + srcStridePixels * pixelSize;
+        dst = (uint8_t*)dst + dstStridePixels * pixelSize;
+    }
+}
+
+
+BufferDesc_1_1 convertBufferDesc(const BufferDesc_1_0& src) {
+    BufferDesc_1_1 dst = {};
+    AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<AHardwareBuffer_Desc *>(&dst.buffer.description);
+    pDesc->width  = src.width;
+    pDesc->height = src.height;
+    pDesc->layers = 1;
+    pDesc->format = src.format;
+    pDesc->usage  = static_cast<uint64_t>(src.usage);
+    pDesc->stride = src.stride;
+
+    dst.buffer.nativeHandle = src.memHandle;
+    dst.pixelSize = src.pixelSize;
+    dst.bufferId = src.bufferId;
+
+    return dst;
+}
diff --git a/evs/apps/default/FormatConvert.h b/evs/apps/default/FormatConvert.h
new file mode 100644
index 0000000..474ce6d
--- /dev/null
+++ b/evs/apps/default/FormatConvert.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef EVS_VTS_FORMATCONVERT_H
+#define EVS_VTS_FORMATCONVERT_H
+
+#include <queue>
+#include <stdint.h>
+
+#include <android/hardware/automotive/evs/1.0/types.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
+
+using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
+
+
+// Given an image buffer in NV21 format (HAL_PIXEL_FORMAT_YCRCB_420_SP), output 32bit RGBx values.
+// The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
+// U/V array.  It assumes an even width and height for the overall image, and a horizontal
+// stride that is an even multiple of 16 bytes for both the Y and UV arrays.
+void copyNV21toRGB32(unsigned width, unsigned height,
+                     uint8_t* src,
+                     uint32_t* dst, unsigned dstStridePixels);
+
+
+// Given an image buffer in YV12 format (HAL_PIXEL_FORMAT_YV12), output 32bit RGBx values.
+// The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
+// by another 1/2 x 1/2 V array.  It assumes an even width and height for the overall image,
+// and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
+// and V arrays.
+void copyYV12toRGB32(unsigned width, unsigned height,
+                     uint8_t* src,
+                     uint32_t* dst, unsigned dstStridePixels);
+
+
+// Given an image buffer in YUYV format (HAL_PIXEL_FORMAT_YCBCR_422_I), output 32bit RGBx values.
+// The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
+// U/V array.  It assumes an even width and height for the overall image, and a horizontal
+// stride that is an even multiple of 16 bytes for both the Y and UV arrays.
+void copyYUYVtoRGB32(unsigned width, unsigned height,
+                     uint8_t* src, unsigned srcStrideBytes,
+                     uint32_t* dst, unsigned dstStrideBytes);
+
+
+// Given an simple rectangular image buffer with an integer number of bytes per pixel,
+// copy the pixel values into a new rectangular buffer (potentially with a different stride).
+// This is typically used to copy RGBx data into an RGBx output buffer.
+void copyMatchedInterleavedFormats(unsigned width, unsigned height,
+                                   void* src, unsigned srcStridePixels,
+                                   void* dst, unsigned dstStridePixels,
+                                   unsigned pixelSize);
+
+// Fill BufferDesc v1.1 with a given BufferDesc v1.0 data.
+BufferDesc_1_1 convertBufferDesc(const BufferDesc_1_0& src);
+
+#endif // EVS_VTS_FORMATCONVERT_H
diff --git a/evs/app/LabeledChecker.png b/evs/apps/default/LabeledChecker.png
similarity index 100%
rename from evs/app/LabeledChecker.png
rename to evs/apps/default/LabeledChecker.png
Binary files differ
diff --git a/evs/apps/default/RenderBase.cpp b/evs/apps/default/RenderBase.cpp
new file mode 100644
index 0000000..0db7c9d
--- /dev/null
+++ b/evs/apps/default/RenderBase.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RenderBase.h"
+#include "glError.h"
+
+#include <android-base/logging.h>
+#include <ui/GraphicBuffer.h>
+
+// Eventually we shouldn't need this dependency, but for now the
+// graphics allocator interface isn't fully supported on all platforms
+// and this is our work around.
+using ::android::GraphicBuffer;
+
+
+// OpenGL state shared among all renderers
+EGLDisplay   RenderBase::sDisplay = EGL_NO_DISPLAY;
+EGLContext   RenderBase::sContext = EGL_NO_CONTEXT;
+EGLSurface   RenderBase::sDummySurface = EGL_NO_SURFACE;
+GLuint       RenderBase::sFrameBuffer = -1;
+GLuint       RenderBase::sColorBuffer = -1;
+GLuint       RenderBase::sDepthBuffer = -1;
+EGLImageKHR  RenderBase::sKHRimage = EGL_NO_IMAGE_KHR;
+unsigned     RenderBase::sWidth  = 0;
+unsigned     RenderBase::sHeight = 0;
+float        RenderBase::sAspectRatio = 0.0f;
+
+
+bool RenderBase::prepareGL() {
+    // Just trivially return success if we're already prepared
+    if (sDisplay != EGL_NO_DISPLAY) {
+        return true;
+    }
+
+    // Hardcoded to RGBx output display
+    const EGLint config_attribs[] = {
+        // Tag                  Value
+        EGL_RENDERABLE_TYPE,    EGL_OPENGL_ES2_BIT,
+        EGL_RED_SIZE,           8,
+        EGL_GREEN_SIZE,         8,
+        EGL_BLUE_SIZE,          8,
+        EGL_NONE
+    };
+
+    // Select OpenGL ES v 3
+    const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
+
+
+    // Set up our OpenGL ES context associated with the default display (though we won't be visible)
+    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    if (display == EGL_NO_DISPLAY) {
+        LOG(ERROR) << "Failed to get egl display";
+        return false;
+    }
+
+    EGLint major = 0;
+    EGLint minor = 0;
+    if (!eglInitialize(display, &major, &minor)) {
+        LOG(ERROR) << "Failed to initialize EGL: " << getEGLError();
+        return false;
+    } else {
+        LOG(INFO) << "Intiialized EGL at " << major << "." << minor;
+    }
+
+
+    // Select the configuration that "best" matches our desired characteristics
+    EGLConfig egl_config;
+    EGLint num_configs;
+    if (!eglChooseConfig(display, config_attribs, &egl_config, 1, &num_configs)) {
+        LOG(ERROR) << "eglChooseConfig() failed with error: " << getEGLError();
+        return false;
+    }
+
+
+    // Create a dummy pbuffer so we have a surface to bind -- we never intend to draw to this
+    // because attachRenderTarget will be called first.
+    EGLint surface_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
+    sDummySurface = eglCreatePbufferSurface(display, egl_config, surface_attribs);
+    if (sDummySurface == EGL_NO_SURFACE) {
+        LOG(ERROR) << "Failed to create OpenGL ES Dummy surface: " << getEGLError();
+        return false;
+    } else {
+        LOG(INFO) << "Dummy surface looks good!  :)";
+    }
+
+
+    //
+    // Create the EGL context
+    //
+    EGLContext context = eglCreateContext(display, egl_config, EGL_NO_CONTEXT, context_attribs);
+    if (context == EGL_NO_CONTEXT) {
+        LOG(ERROR) << "Failed to create OpenGL ES Context: " << getEGLError();
+        return false;
+    }
+
+
+    // Activate our render target for drawing
+    if (!eglMakeCurrent(display, sDummySurface, sDummySurface, context)) {
+        LOG(ERROR) << "Failed to make the OpenGL ES Context current: " << getEGLError();
+        return false;
+    } else {
+        LOG(INFO) << "We made our context current!  :)";
+    }
+
+
+    // Report the extensions available on this implementation
+    const char* gl_extensions = (const char*) glGetString(GL_EXTENSIONS);
+    LOG(INFO) << "GL EXTENSIONS:\n  " << gl_extensions;
+
+
+    // Reserve handles for the color and depth targets we'll be setting up
+    glGenRenderbuffers(1, &sColorBuffer);
+    glGenRenderbuffers(1, &sDepthBuffer);
+
+    // Set up the frame buffer object we can modify and use for off screen rendering
+    glGenFramebuffers(1, &sFrameBuffer);
+    glBindFramebuffer(GL_FRAMEBUFFER, sFrameBuffer);
+
+
+    // Now that we're assured success, store object handles we constructed
+    sDisplay = display;
+    sContext = context;
+
+    return true;
+}
+
+
+bool RenderBase::attachRenderTarget(const BufferDesc& tgtBuffer) {
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&tgtBuffer.buffer.description);
+    // Hardcoded to RGBx for now
+    if (pDesc->format != HAL_PIXEL_FORMAT_RGBA_8888) {
+        LOG(ERROR) << "Unsupported target buffer format";
+        return false;
+    }
+
+    // create a GraphicBuffer from the existing handle
+    sp<GraphicBuffer> pGfxBuffer = new GraphicBuffer(tgtBuffer.buffer.nativeHandle,
+                                                     GraphicBuffer::CLONE_HANDLE,
+                                                     pDesc->width,
+                                                     pDesc->height,
+                                                     pDesc->format,
+                                                     pDesc->layers,
+                                                     GRALLOC_USAGE_HW_RENDER,
+                                                     pDesc->stride);
+    if (pGfxBuffer.get() == nullptr) {
+        LOG(ERROR) << "Failed to allocate GraphicBuffer to wrap image handle";
+        return false;
+    }
+
+    // Get a GL compatible reference to the graphics buffer we've been given
+    EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
+    EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(pGfxBuffer->getNativeBuffer());
+    sKHRimage = eglCreateImageKHR(sDisplay, EGL_NO_CONTEXT,
+                                  EGL_NATIVE_BUFFER_ANDROID, clientBuf,
+                                  eglImageAttributes);
+    if (sKHRimage == EGL_NO_IMAGE_KHR) {
+        LOG(ERROR) << "Error creating EGLImage for target buffer: " << getEGLError();
+        return false;
+    }
+
+    // Construct a render buffer around the external buffer
+    glBindRenderbuffer(GL_RENDERBUFFER, sColorBuffer);
+    glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, static_cast<GLeglImageOES>(sKHRimage));
+    if (eglGetError() != EGL_SUCCESS) {
+        LOG(INFO) << "glEGLImageTargetRenderbufferStorageOES => " << getEGLError();
+        return false;
+    }
+
+    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, sColorBuffer);
+    if (eglGetError() != EGL_SUCCESS) {
+        LOG(ERROR) << "glFramebufferRenderbuffer => " << getEGLError();
+        return false;
+    }
+
+    GLenum checkResult = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+    if (checkResult != GL_FRAMEBUFFER_COMPLETE) {
+        LOG(ERROR) << "Offscreen framebuffer not configured successfully ("
+                   << checkResult << ": " << getGLFramebufferError() << ")";
+        return false;
+    }
+
+    // Store the size of our target buffer
+    sWidth = pDesc->width;
+    sHeight = pDesc->height;
+    sAspectRatio = (float)sWidth / sHeight;
+
+    // Set the viewport
+    glViewport(0, 0, sWidth, sHeight);
+
+    // We don't actually need the clear if we're going to cover the whole screen anyway
+    // Clear the color buffer
+    glClearColor(0.8f, 0.1f, 0.2f, 1.0f);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    return true;
+}
+
+
+void RenderBase::detachRenderTarget() {
+    // Drop our external render target
+    if (sKHRimage != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(sDisplay, sKHRimage);
+        sKHRimage = EGL_NO_IMAGE_KHR;
+    }
+}
diff --git a/evs/apps/default/RenderBase.h b/evs/apps/default/RenderBase.h
new file mode 100644
index 0000000..1226931
--- /dev/null
+++ b/evs/apps/default/RenderBase.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CAR_EVS_APP_RENDERBASE_H
+#define CAR_EVS_APP_RENDERBASE_H
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+using ::android::sp;
+
+
+/*
+ * Abstract base class for the workhorse classes that handle the user interaction and display for
+ * each mode of the EVS application.
+ */
+class RenderBase {
+public:
+    virtual ~RenderBase() {};
+
+    virtual bool activate() = 0;
+    virtual void deactivate() = 0;
+
+    virtual bool drawFrame(const BufferDesc& tgtBuffer) = 0;
+
+protected:
+    static bool prepareGL();
+
+    static bool attachRenderTarget(const BufferDesc& tgtBuffer);
+    static void detachRenderTarget();
+
+    // OpenGL state shared among all renderers
+    static EGLDisplay   sDisplay;
+    static EGLContext   sContext;
+    static EGLSurface   sDummySurface;
+    static GLuint       sFrameBuffer;
+    static GLuint       sColorBuffer;
+    static GLuint       sDepthBuffer;
+
+    static EGLImageKHR  sKHRimage;
+
+    static unsigned     sWidth;
+    static unsigned     sHeight;
+    static float        sAspectRatio;
+};
+
+
+#endif //CAR_EVS_APP_RENDERBASE_H
diff --git a/evs/apps/default/RenderDirectView.cpp b/evs/apps/default/RenderDirectView.cpp
new file mode 100644
index 0000000..68b731e
--- /dev/null
+++ b/evs/apps/default/RenderDirectView.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RenderDirectView.h"
+#include "VideoTex.h"
+#include "glError.h"
+#include "shader.h"
+#include "shader_simpleTex.h"
+
+#include <math/mat4.h>
+#include <system/camera_metadata.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android-base/logging.h>
+
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+
+
+typedef struct {
+    int32_t id;
+    int32_t width;
+    int32_t height;
+    int32_t format;
+    int32_t direction;
+    int32_t framerate;
+} RawStreamConfig;
+
+const size_t kStreamCfgSz = sizeof(RawStreamConfig);
+
+
+RenderDirectView::RenderDirectView(sp<IEvsEnumerator> enumerator,
+                                   const CameraDesc& camDesc,
+                                   const ConfigManager& config) :
+    mEnumerator(enumerator),
+    mCameraDesc(camDesc),
+    mConfig(config) {
+    /* Nothing to do */
+}
+
+
+bool RenderDirectView::activate() {
+    // Ensure GL is ready to go...
+    if (!prepareGL()) {
+        LOG(ERROR) << "Error initializing GL";
+        return false;
+    }
+
+    // Load our shader program if we don't have it already
+    if (!mShaderProgram) {
+        mShaderProgram = buildShaderProgram(vtxShader_simpleTexture,
+                                            pixShader_simpleTexture,
+                                            "simpleTexture");
+        if (!mShaderProgram) {
+            LOG(ERROR) << "Error building shader program";
+            return false;
+        }
+    }
+
+    bool foundCfg = false;
+    std::unique_ptr<Stream> targetCfg(new Stream());
+
+    if (!foundCfg) {
+        // This logic picks the first configuration in the list among them that
+        // support RGBA8888 format and its frame rate is faster than minReqFps.
+        const int32_t minReqFps = 15;
+        int32_t maxArea = 0;
+        camera_metadata_entry_t streamCfgs;
+        if (!find_camera_metadata_entry(
+                 reinterpret_cast<camera_metadata_t *>(mCameraDesc.metadata.data()),
+                 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+                 &streamCfgs)) {
+            // Stream configurations are found in metadata
+            RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
+            for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
+                if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                    ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+
+                    if (ptr->framerate >= minReqFps &&
+                        ptr->width * ptr->height > maxArea) {
+                        targetCfg->id = ptr->id;
+                        targetCfg->width = ptr->width;
+                        targetCfg->height = ptr->height;
+
+                        maxArea = ptr->width * ptr->height;
+
+                        foundCfg = true;
+                    }
+                }
+                ++ptr;
+            }
+        } else {
+            LOG(WARNING) << "No stream configuration data is found; "
+                         << "default parameters will be used.";
+        }
+    }
+
+    // This client always wants below input data format
+    targetCfg->format =
+        static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
+
+    // Construct our video texture
+    mTexture.reset(createVideoTexture(mEnumerator,
+                                      mCameraDesc.v1.cameraId.c_str(),
+                                      foundCfg ? std::move(targetCfg) : nullptr,
+                                      sDisplay,
+                                      mConfig.getUseExternalMemory(),
+                                      mConfig.getExternalMemoryFormat()));
+    if (!mTexture) {
+        LOG(ERROR) << "Failed to set up video texture for " << mCameraDesc.v1.cameraId;
+// TODO:  For production use, we may actually want to fail in this case, but not yet...
+//       return false;
+    }
+
+    return true;
+}
+
+
+void RenderDirectView::deactivate() {
+    // Release our video texture
+    // We can't hold onto it because some other Render object might need the same camera
+    // TODO(b/131492626):  investigate whether sharing video textures can save
+    // the time.
+  mTexture = nullptr;
+}
+
+
+bool RenderDirectView::drawFrame(const BufferDesc& tgtBuffer) {
+    // Tell GL to render to the given buffer
+    if (!attachRenderTarget(tgtBuffer)) {
+        LOG(ERROR) << "Failed to attached render target";
+        return false;
+    }
+
+    // Select our screen space simple texture shader
+    glUseProgram(mShaderProgram);
+
+    // Set up the model to clip space transform (identity matrix if we're modeling in screen space)
+    GLint loc = glGetUniformLocation(mShaderProgram, "cameraMat");
+    if (loc < 0) {
+        LOG(ERROR) << "Couldn't set shader parameter 'cameraMat'";
+        return false;
+    } else {
+        const android::mat4 identityMatrix;
+        glUniformMatrix4fv(loc, 1, false, identityMatrix.asArray());
+    }
+
+
+    // Bind the texture and assign it to the shader's sampler
+    mTexture->refresh();
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, mTexture->glId());
+
+
+    GLint sampler = glGetUniformLocation(mShaderProgram, "tex");
+    if (sampler < 0) {
+        LOG(ERROR) << "Couldn't set shader parameter 'tex'";
+        return false;
+    } else {
+        // Tell the sampler we looked up from the shader to use texture slot 0 as its source
+        glUniform1i(sampler, 0);
+    }
+
+    // We want our image to show up opaque regardless of alpha values
+    glDisable(GL_BLEND);
+
+
+    // Draw a rectangle on the screen
+    GLfloat vertsCarPos[] = { -1.0,  1.0, 0.0f,   // left top in window space
+                               1.0,  1.0, 0.0f,   // right top
+                              -1.0, -1.0, 0.0f,   // left bottom
+                               1.0, -1.0, 0.0f    // right bottom
+    };
+    // TODO:  We're flipping horizontally here, but should do it only for specified cameras!
+    GLfloat vertsCarTex[] = { 1.0f, 1.0f,   // left top
+                              0.0f, 1.0f,   // right top
+                              1.0f, 0.0f,   // left bottom
+                              0.0f, 0.0f    // right bottom
+    };
+    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertsCarPos);
+    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, vertsCarTex);
+    glEnableVertexAttribArray(0);
+    glEnableVertexAttribArray(1);
+
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+    glDisableVertexAttribArray(0);
+    glDisableVertexAttribArray(1);
+
+
+    // Now that everything is submitted, release our hold on the texture resource
+    detachRenderTarget();
+
+    // Wait for the rendering to finish
+    glFinish();
+    detachRenderTarget();
+    return true;
+}
diff --git a/evs/apps/default/RenderDirectView.h b/evs/apps/default/RenderDirectView.h
new file mode 100644
index 0000000..65a94e2
--- /dev/null
+++ b/evs/apps/default/RenderDirectView.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CAR_EVS_APP_RENDERDIRECTVIEW_H
+#define CAR_EVS_APP_RENDERDIRECTVIEW_H
+
+
+#include "RenderBase.h"
+
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include "ConfigManager.h"
+#include "VideoTex.h"
+
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+using ::android::hardware::camera::device::V3_2::Stream;
+
+
+/*
+ * Renders the view from a single specified camera directly to the full display.
+ */
+class RenderDirectView: public RenderBase {
+public:
+    RenderDirectView(sp<IEvsEnumerator> enumerator,
+                     const CameraDesc& camDesc,
+                     const ConfigManager& config);
+
+    virtual bool activate() override;
+    virtual void deactivate() override;
+
+    virtual bool drawFrame(const BufferDesc& tgtBuffer);
+
+protected:
+    sp<IEvsEnumerator>              mEnumerator;
+    ConfigManager::CameraInfo       mCameraInfo;
+    CameraDesc                      mCameraDesc;
+    const ConfigManager&            mConfig;
+
+    std::unique_ptr<VideoTex>       mTexture;
+
+    GLuint                          mShaderProgram = 0;
+};
+
+
+#endif //CAR_EVS_APP_RENDERDIRECTVIEW_H
diff --git a/evs/apps/default/RenderPixelCopy.cpp b/evs/apps/default/RenderPixelCopy.cpp
new file mode 100644
index 0000000..dde2d2f
--- /dev/null
+++ b/evs/apps/default/RenderPixelCopy.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RenderPixelCopy.h"
+#include "FormatConvert.h"
+
+#include <android-base/logging.h>
+
+
+RenderPixelCopy::RenderPixelCopy(sp<IEvsEnumerator> enumerator,
+                                   const ConfigManager::CameraInfo& cam) {
+    mEnumerator = enumerator;
+    mCameraInfo = cam;
+}
+
+
+bool RenderPixelCopy::activate() {
+    // Set up the camera to feed this texture
+    sp<IEvsCamera> pCamera =
+        IEvsCamera::castFrom(mEnumerator->openCamera(mCameraInfo.cameraId.c_str()))
+        .withDefault(nullptr);
+
+    if (pCamera.get() == nullptr) {
+        LOG(ERROR) << "Failed to allocate new EVS Camera interface";
+        return false;
+    }
+
+    // Initialize the stream that will help us update this texture's contents
+    sp<StreamHandler> pStreamHandler = new StreamHandler(pCamera);
+    if (pStreamHandler.get() == nullptr) {
+        LOG(ERROR) << "Failed to allocate FrameHandler";
+        return false;
+    }
+
+    // Start the video stream
+    if (!pStreamHandler->startStream()) {
+        LOG(ERROR) << "Start stream failed";
+        return false;
+    }
+
+    mStreamHandler = pStreamHandler;
+
+    return true;
+}
+
+
+void RenderPixelCopy::deactivate() {
+    mStreamHandler = nullptr;
+}
+
+
+bool RenderPixelCopy::drawFrame(const BufferDesc& tgtBuffer) {
+    bool success = true;
+    const AHardwareBuffer_Desc* pTgtDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&tgtBuffer.buffer.description);
+
+    sp<android::GraphicBuffer> tgt = new android::GraphicBuffer(tgtBuffer.buffer.nativeHandle,
+                                                                android::GraphicBuffer::CLONE_HANDLE,
+                                                                pTgtDesc->width,
+                                                                pTgtDesc->height,
+                                                                pTgtDesc->format,
+                                                                pTgtDesc->layers,
+                                                                pTgtDesc->usage,
+                                                                pTgtDesc->stride);
+
+    // Lock our target buffer for writing (should be RGBA8888 format)
+    uint32_t* tgtPixels = nullptr;
+    tgt->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)&tgtPixels);
+
+    if (tgtPixels) {
+        if (pTgtDesc->format != HAL_PIXEL_FORMAT_RGBA_8888) {
+            // We always expect 32 bit RGB for the display output for now.  Is there a need for 565?
+            LOG(ERROR) << "Diplay buffer is always expected to be 32bit RGBA";
+            success = false;
+        } else {
+            // Make sure we have the latest frame data
+            if (mStreamHandler->newFrameAvailable()) {
+                const BufferDesc& srcBuffer = mStreamHandler->getNewFrame();
+                const AHardwareBuffer_Desc* pSrcDesc =
+                    reinterpret_cast<const AHardwareBuffer_Desc *>(&srcBuffer.buffer.description);
+
+                // Lock our source buffer for reading (current expectation are for this to be NV21 format)
+                sp<android::GraphicBuffer> src = new android::GraphicBuffer(srcBuffer.buffer.nativeHandle,
+                                                                            android::GraphicBuffer::CLONE_HANDLE,
+                                                                            pSrcDesc->width,
+                                                                            pSrcDesc->height,
+                                                                            pSrcDesc->format,
+                                                                            pSrcDesc->layers,
+                                                                            pSrcDesc->usage,
+                                                                            pSrcDesc->stride);
+
+                unsigned char* srcPixels = nullptr;
+                src->lock(GRALLOC_USAGE_SW_READ_OFTEN, (void**)&srcPixels);
+                if (srcPixels != nullptr) {
+                    // Make sure we don't run off the end of either buffer
+                    const unsigned width  = std::min(pTgtDesc->width,
+                                                     pSrcDesc->width);
+                    const unsigned height = std::min(pTgtDesc->height,
+                                                     pSrcDesc->height);
+
+                    if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCRCB_420_SP) {   // 420SP == NV21
+                        copyNV21toRGB32(width, height,
+                                        srcPixels,
+                                        tgtPixels, pTgtDesc->stride);
+                    } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12
+                        copyYV12toRGB32(width, height,
+                                        srcPixels,
+                                        tgtPixels, pTgtDesc->stride);
+                    } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV
+                        copyYUYVtoRGB32(width, height,
+                                        srcPixels, pSrcDesc->stride,
+                                        tgtPixels, pTgtDesc->stride);
+                    } else if (pSrcDesc->format == pTgtDesc->format) {  // 32bit RGBA
+                        copyMatchedInterleavedFormats(width, height,
+                                                      srcPixels, pSrcDesc->stride,
+                                                      tgtPixels, pTgtDesc->stride,
+                                                      tgtBuffer.pixelSize);
+                    }
+                } else {
+                    LOG(ERROR) << "Failed to get pointer into src image data";
+                    success = false;
+                }
+
+                mStreamHandler->doneWithFrame(srcBuffer);
+            }
+        }
+    } else {
+        LOG(ERROR) << "Failed to lock buffer contents for contents transfer";
+        success = false;
+    }
+
+    if (tgtPixels) {
+        tgt->unlock();
+    }
+
+    return success;
+}
diff --git a/evs/apps/default/RenderPixelCopy.h b/evs/apps/default/RenderPixelCopy.h
new file mode 100644
index 0000000..4673a36
--- /dev/null
+++ b/evs/apps/default/RenderPixelCopy.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CAR_EVS_APP_RENDERPIXELCOPY_H
+#define CAR_EVS_APP_RENDERPIXELCOPY_H
+
+
+#include "RenderBase.h"
+
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include "ConfigManager.h"
+#include "VideoTex.h"
+
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+
+
+/*
+ * Renders the view from a single specified camera directly to the full display.
+ */
+class RenderPixelCopy: public RenderBase {
+public:
+    RenderPixelCopy(sp<IEvsEnumerator> enumerator, const ConfigManager::CameraInfo& cam);
+
+    virtual bool activate() override;
+    virtual void deactivate() override;
+
+    virtual bool drawFrame(const BufferDesc& tgtBuffer);
+
+protected:
+    sp<IEvsEnumerator>              mEnumerator;
+    ConfigManager::CameraInfo       mCameraInfo;
+
+    sp<StreamHandler>               mStreamHandler;
+};
+
+
+#endif //CAR_EVS_APP_RENDERPIXELCOPY_H
diff --git a/evs/apps/default/RenderTopView.cpp b/evs/apps/default/RenderTopView.cpp
new file mode 100644
index 0000000..bfec3f2
--- /dev/null
+++ b/evs/apps/default/RenderTopView.cpp
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RenderTopView.h"
+#include "VideoTex.h"
+#include "glError.h"
+#include "shader.h"
+#include "shader_simpleTex.h"
+#include "shader_projectedTex.h"
+
+#include <math/mat4.h>
+#include <math/vec3.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android-base/logging.h>
+
+using ::android::hardware::camera::device::V3_2::Stream;
+
+
+// Simple aliases to make geometric math using vectors more readable
+static const unsigned X = 0;
+static const unsigned Y = 1;
+static const unsigned Z = 2;
+//static const unsigned W = 3;
+
+
+// Since we assume no roll in these views, we can simplify the required math
+static android::vec3 unitVectorFromPitchAndYaw(float pitch, float yaw) {
+    float sinPitch, cosPitch;
+    sincosf(pitch, &sinPitch, &cosPitch);
+    float sinYaw, cosYaw;
+    sincosf(yaw, &sinYaw, &cosYaw);
+    return android::vec3(cosPitch * -sinYaw,
+                         cosPitch * cosYaw,
+                         sinPitch);
+}
+
+
+// Helper function to set up a perspective matrix with independent horizontal and vertical
+// angles of view.
+static android::mat4 perspective(float hfov, float vfov, float near, float far) {
+    const float tanHalfFovX = tanf(hfov * 0.5f);
+    const float tanHalfFovY = tanf(vfov * 0.5f);
+
+    android::mat4 p(0.0f);
+    p[0][0] = 1.0f / tanHalfFovX;
+    p[1][1] = 1.0f / tanHalfFovY;
+    p[2][2] = - (far + near) / (far - near);
+    p[2][3] = -1.0f;
+    p[3][2] = - (2.0f * far * near) / (far - near);
+    return p;
+}
+
+
+// Helper function to set up a view matrix for a camera given it's yaw & pitch & location
+// Yes, with a bit of work, we could use lookAt, but it does a lot of extra work
+// internally that we can short cut.
+static android::mat4 cameraLookMatrix(const ConfigManager::CameraInfo& cam) {
+    float sinYaw, cosYaw;
+    sincosf(cam.yaw, &sinYaw, &cosYaw);
+
+    // Construct principal unit vectors
+    android::vec3 vAt = unitVectorFromPitchAndYaw(cam.pitch, cam.yaw);
+    android::vec3 vRt = android::vec3(cosYaw, sinYaw, 0.0f);
+    android::vec3 vUp = -cross(vAt, vRt);
+    android::vec3 eye = android::vec3(cam.position[X], cam.position[Y], cam.position[Z]);
+
+    android::mat4 Result(1.0f);
+    Result[0][0] = vRt.x;
+    Result[1][0] = vRt.y;
+    Result[2][0] = vRt.z;
+    Result[0][1] = vUp.x;
+    Result[1][1] = vUp.y;
+    Result[2][1] = vUp.z;
+    Result[0][2] =-vAt.x;
+    Result[1][2] =-vAt.y;
+    Result[2][2] =-vAt.z;
+    Result[3][0] =-dot(vRt, eye);
+    Result[3][1] =-dot(vUp, eye);
+    Result[3][2] = dot(vAt, eye);
+    return Result;
+}
+
+
+RenderTopView::RenderTopView(sp<IEvsEnumerator> enumerator,
+                             const std::vector<ConfigManager::CameraInfo>& camList,
+                             const ConfigManager& mConfig) :
+    mEnumerator(enumerator),
+    mConfig(mConfig) {
+
+    // Copy the list of cameras we're to employ into our local storage.  We'll create and
+    // associate a streaming video texture when we are activated.
+    mActiveCameras.reserve(camList.size());
+    for (unsigned i=0; i<camList.size(); i++) {
+        mActiveCameras.emplace_back(camList[i]);
+    }
+}
+
+
+bool RenderTopView::activate() {
+    // Ensure GL is ready to go...
+    if (!prepareGL()) {
+        LOG(ERROR) << "Error initializing GL";
+        return false;
+    }
+
+    // Load our shader programs
+    mPgmAssets.simpleTexture = buildShaderProgram(vtxShader_simpleTexture,
+                                                 pixShader_simpleTexture,
+                                                 "simpleTexture");
+    if (!mPgmAssets.simpleTexture) {
+        LOG(ERROR) << "Failed to build shader program";
+        return false;
+    }
+    mPgmAssets.projectedTexture = buildShaderProgram(vtxShader_projectedTexture,
+                                                    pixShader_projectedTexture,
+                                                    "projectedTexture");
+    if (!mPgmAssets.projectedTexture) {
+        LOG(ERROR) << "Failed to build shader program";
+        return false;
+    }
+
+
+    // Load the checkerboard text image
+    mTexAssets.checkerBoard.reset(createTextureFromPng(
+                                  "/system/etc/automotive/evs/LabeledChecker.png"));
+    if (!mTexAssets.checkerBoard) {
+        LOG(ERROR) << "Failed to load checkerboard texture";
+        return false;
+    }
+
+    // Load the car image
+    mTexAssets.carTopView.reset(createTextureFromPng(
+                                "/system/etc/automotive/evs/CarFromTop.png"));
+    if (!mTexAssets.carTopView) {
+        LOG(ERROR) << "Failed to load carTopView texture";
+        return false;
+    }
+
+
+    // Set up streaming video textures for our associated cameras
+    for (auto&& cam: mActiveCameras) {
+        cam.tex.reset(createVideoTexture(mEnumerator,
+                                         cam.info.cameraId.c_str(),
+                                         nullptr,
+                                         sDisplay));
+        if (!cam.tex) {
+            LOG(ERROR) << "Failed to set up video texture for " << cam.info.cameraId
+                       << " (" << cam.info.function << ")";
+// TODO:  For production use, we may actually want to fail in this case, but not yet...
+//            return false;
+        }
+    }
+
+    return true;
+}
+
+
+void RenderTopView::deactivate() {
+    // Release our video textures
+    // We can't hold onto it because some other Render object might need the same camera
+    // TODO(b/131492626):  investigate whether sharing video textures can save
+    // the time.
+    for (auto&& cam: mActiveCameras) {
+        cam.tex = nullptr;
+    }
+}
+
+
+bool RenderTopView::drawFrame(const BufferDesc& tgtBuffer) {
+    // Tell GL to render to the given buffer
+    if (!attachRenderTarget(tgtBuffer)) {
+        LOG(ERROR) << "Failed to attached render target";
+        return false;
+    }
+
+    // Set up our top down projection matrix from car space (world units, Xfwd, Yright, Zup)
+    // to view space (-1 to 1)
+    const float top    = mConfig.getDisplayTopLocation();
+    const float bottom = mConfig.getDisplayBottomLocation();
+    const float right  = mConfig.getDisplayRightLocation(sAspectRatio);
+    const float left   = mConfig.getDisplayLeftLocation(sAspectRatio);
+
+    const float near = 10.0f;   // arbitrary top of view volume
+    const float far = 0.0f;     // ground plane is at zero
+
+    // We can use a simple, unrotated ortho view since the screen and car space axis are
+    // naturally aligned in the top down view.
+    // TODO:  Not sure if flipping top/bottom here is "correct" or a double reverse...
+//    orthoMatrix = android::mat4::ortho(left, right, bottom, top, near, far);
+    orthoMatrix = android::mat4::ortho(left, right, top, bottom, near, far);
+
+
+    // Refresh our video texture contents.  We do it all at once in hopes of getting
+    // better coherence among images.  This does not guarantee synchronization, of course...
+    for (auto&& cam: mActiveCameras) {
+        if (cam.tex) {
+            cam.tex->refresh();
+        }
+    }
+
+    // Iterate over all the cameras and project their images onto the ground plane
+    for (auto&& cam: mActiveCameras) {
+        renderCameraOntoGroundPlane(cam);
+    }
+
+    // Draw the car image
+    renderCarTopView();
+
+    // Now that everythign is submitted, release our hold on the texture resource
+    detachRenderTarget();
+
+    // Wait for the rendering to finish
+    glFinish();
+    detachRenderTarget();
+    return true;
+}
+
+
+//
+// Responsible for drawing the car's self image in the top down view.
+// Draws in car model space (units of meters with origin at center of rear axel)
+// NOTE:  We probably want to eventually switch to using a VertexArray based model system.
+//
+void RenderTopView::renderCarTopView() {
+    // Compute the corners of our image footprint in car space
+    const float carLengthInTexels = mConfig.carGraphicRearPixel() - mConfig.carGraphicFrontPixel();
+    const float carSpaceUnitsPerTexel = mConfig.getCarLength() / carLengthInTexels;
+    const float textureHeightInCarSpace = mTexAssets.carTopView->height() * carSpaceUnitsPerTexel;
+    const float textureAspectRatio = (float)mTexAssets.carTopView->width() /
+                                            mTexAssets.carTopView->height();
+    const float pixelsBehindCarInImage = mTexAssets.carTopView->height() -
+                                         mConfig.carGraphicRearPixel();
+    const float textureExtentBehindCarInCarSpace = pixelsBehindCarInImage * carSpaceUnitsPerTexel;
+
+    const float btCS = mConfig.getRearLocation() - textureExtentBehindCarInCarSpace;
+    const float tpCS = textureHeightInCarSpace + btCS;
+    const float ltCS = 0.5f * textureHeightInCarSpace * textureAspectRatio;
+    const float rtCS = -ltCS;
+
+    GLfloat vertsCarPos[] = { ltCS, tpCS, 0.0f,   // left top in car space
+                              rtCS, tpCS, 0.0f,   // right top
+                              ltCS, btCS, 0.0f,   // left bottom
+                              rtCS, btCS, 0.0f    // right bottom
+    };
+    // NOTE:  We didn't flip the image in the texture, so V=0 is actually the top of the image
+    GLfloat vertsCarTex[] = { 0.0f, 0.0f,   // left top
+                              1.0f, 0.0f,   // right top
+                              0.0f, 1.0f,   // left bottom
+                              1.0f, 1.0f    // right bottom
+    };
+    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertsCarPos);
+    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, vertsCarTex);
+    glEnableVertexAttribArray(0);
+    glEnableVertexAttribArray(1);
+
+
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+    glUseProgram(mPgmAssets.simpleTexture);
+    GLint loc = glGetUniformLocation(mPgmAssets.simpleTexture, "cameraMat");
+    glUniformMatrix4fv(loc, 1, false, orthoMatrix.asArray());
+    glBindTexture(GL_TEXTURE_2D, mTexAssets.carTopView->glId());
+
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+
+    glDisable(GL_BLEND);
+
+    glDisableVertexAttribArray(0);
+    glDisableVertexAttribArray(1);
+}
+
+
+// NOTE:  Might be worth reviewing the ideas at
+// http://math.stackexchange.com/questions/1691895/inverse-of-perspective-matrix
+// to see if that simplifies the math, although we'll still want to compute the actual ground
+// interception points taking into account the pitchLimit as below.
+void RenderTopView::renderCameraOntoGroundPlane(const ActiveCamera& cam) {
+    // How far is the farthest any camera should even consider projecting it's image?
+    const float visibleSizeV = mConfig.getDisplayTopLocation() - mConfig.getDisplayBottomLocation();
+    const float visibleSizeH = visibleSizeV * sAspectRatio;
+    const float maxRange = (visibleSizeH > visibleSizeV) ? visibleSizeH : visibleSizeV;
+
+    // Construct the projection matrix (View + Projection) associated with this sensor
+    // TODO:  Consider just hard coding the far plane distance as it likely doesn't matter
+    const android::mat4 V = cameraLookMatrix(cam.info);
+    const android::mat4 P = perspective(cam.info.hfov, cam.info.vfov, cam.info.position[Z], maxRange);
+    const android::mat4 projectionMatix = P*V;
+
+    // Just draw the whole darn ground plane for now -- we're wasting fill rate, but so what?
+    // A 2x optimization would be to draw only the 1/2 space of the window in the direction
+    // the sensor is facing.  A more complex solution would be to construct the intersection
+    // of the sensor volume with the ground plane and render only that geometry.
+    const float top = mConfig.getDisplayTopLocation();
+    const float bottom = mConfig.getDisplayBottomLocation();
+    const float wsHeight = top - bottom;
+    const float wsWidth = wsHeight * sAspectRatio;
+    const float right =  wsWidth * 0.5f;
+    const float left = -right;
+
+    const android::vec3 topLeft(left, top, 0.0f);
+    const android::vec3 topRight(right, top, 0.0f);
+    const android::vec3 botLeft(left, bottom, 0.0f);
+    const android::vec3 botRight(right, bottom, 0.0f);
+
+    GLfloat vertsPos[] = { topLeft[X],  topLeft[Y],  topLeft[Z],
+                           topRight[X], topRight[Y], topRight[Z],
+                           botLeft[X],  botLeft[Y],  botLeft[Z],
+                           botRight[X], botRight[Y], botRight[Z],
+    };
+    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertsPos);
+    glEnableVertexAttribArray(0);
+
+
+    glDisable(GL_BLEND);
+
+    glUseProgram(mPgmAssets.projectedTexture);
+    GLint locCam = glGetUniformLocation(mPgmAssets.projectedTexture, "cameraMat");
+    glUniformMatrix4fv(locCam, 1, false, orthoMatrix.asArray());
+    GLint locProj = glGetUniformLocation(mPgmAssets.projectedTexture, "projectionMat");
+    glUniformMatrix4fv(locProj, 1, false, projectionMatix.asArray());
+
+    GLuint texId;
+    if (cam.tex) {
+        texId = cam.tex->glId();
+    } else {
+        texId = mTexAssets.checkerBoard->glId();
+    }
+    glBindTexture(GL_TEXTURE_2D, texId);
+
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+
+    glDisableVertexAttribArray(0);
+}
diff --git a/evs/apps/default/RenderTopView.h b/evs/apps/default/RenderTopView.h
new file mode 100644
index 0000000..4d30a32
--- /dev/null
+++ b/evs/apps/default/RenderTopView.h
@@ -0,0 +1,76 @@
+
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CAR_EVS_APP_RENDERTOPVIEW_H
+#define CAR_EVS_APP_RENDERTOPVIEW_H
+
+
+#include "RenderBase.h"
+
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include "ConfigManager.h"
+#include "VideoTex.h"
+#include <math/mat4.h>
+
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+
+
+/*
+ * Combines the views from all available cameras into one reprojected top down view.
+ */
+class RenderTopView: public RenderBase {
+public:
+    RenderTopView(sp<IEvsEnumerator> enumerator,
+                  const std::vector<ConfigManager::CameraInfo>& camList,
+                  const ConfigManager& config);
+
+    virtual bool activate() override;
+    virtual void deactivate() override;
+
+    virtual bool drawFrame(const BufferDesc& tgtBuffer);
+
+protected:
+    struct ActiveCamera {
+        const ConfigManager::CameraInfo&    info;
+        std::unique_ptr<VideoTex>           tex;
+
+        ActiveCamera(const ConfigManager::CameraInfo& c) : info(c) {};
+    };
+
+    void renderCarTopView();
+    void renderCameraOntoGroundPlane(const ActiveCamera& cam);
+
+    sp<IEvsEnumerator>              mEnumerator;
+    const ConfigManager&            mConfig;
+    std::vector<ActiveCamera>       mActiveCameras;
+
+    struct {
+        std::unique_ptr<TexWrapper> checkerBoard;
+        std::unique_ptr<TexWrapper> carTopView;
+    } mTexAssets;
+
+    struct {
+        GLuint simpleTexture;
+        GLuint projectedTexture;
+    } mPgmAssets;
+
+    android::mat4   orthoMatrix;
+};
+
+
+#endif //CAR_EVS_APP_RENDERTOPVIEW_H
diff --git a/evs/apps/default/StreamHandler.cpp b/evs/apps/default/StreamHandler.cpp
new file mode 100644
index 0000000..d350af1
--- /dev/null
+++ b/evs/apps/default/StreamHandler.cpp
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "StreamHandler.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <android-base/logging.h>
+#include <cutils/native_handle.h>
+#include <ui/GraphicBufferAllocator.h>
+
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+
+
+buffer_handle_t memHandle = nullptr;
+StreamHandler::StreamHandler(android::sp <IEvsCamera> pCamera,
+                             uint32_t numBuffers,
+                             bool useOwnBuffers,
+                             android_pixel_format_t format,
+                             int32_t width,
+                             int32_t height)
+    : mCamera(pCamera),
+      mUseOwnBuffers(useOwnBuffers) {
+    if (!useOwnBuffers) {
+        // We rely on the camera having at least two buffers available since we'll hold one and
+        // expect the camera to be able to capture a new image in the background.
+        pCamera->setMaxFramesInFlight(numBuffers);
+    } else {
+        mOwnBuffers.resize(numBuffers);
+
+        // Acquire the graphics buffer allocator
+        android::GraphicBufferAllocator &alloc(android::GraphicBufferAllocator::get());
+        const auto usage = GRALLOC_USAGE_HW_TEXTURE |
+                           GRALLOC_USAGE_SW_READ_RARELY |
+                           GRALLOC_USAGE_SW_WRITE_OFTEN;
+        for (auto i = 0; i < numBuffers; ++i) {
+            unsigned pixelsPerLine;
+            android::status_t result = alloc.allocate(width,
+                                                      height,
+                                                      format,
+                                                      1,
+                                                      usage,
+                                                      &memHandle,
+                                                      &pixelsPerLine,
+                                                      0,
+                                                      "EvsApp");
+            if (result != android::NO_ERROR) {
+                LOG(ERROR) << __FUNCTION__ << " failed to allocate memory.";
+            } else {
+                BufferDesc_1_1 buf;
+                AHardwareBuffer_Desc* pDesc =
+                    reinterpret_cast<AHardwareBuffer_Desc *>(&buf.buffer.description);
+                pDesc->width = width;
+                pDesc->height = height;
+                pDesc->layers = 1;
+                pDesc->format = format;
+                pDesc->usage = GRALLOC_USAGE_HW_TEXTURE |
+                               GRALLOC_USAGE_SW_READ_RARELY |
+                               GRALLOC_USAGE_SW_WRITE_OFTEN;
+                pDesc->stride = pixelsPerLine;
+                buf.buffer.nativeHandle = memHandle;
+                buf.bufferId = i;   // Unique number to identify this buffer
+                mOwnBuffers[i] = buf;
+            }
+        }
+
+        int delta = 0;
+        EvsResult result = EvsResult::OK;
+        pCamera->importExternalBuffers(mOwnBuffers,
+                                       [&](auto _result, auto _delta) {
+                                           result = _result;
+                                           delta = _delta;
+                                       });
+
+        LOG(INFO) << delta << " buffers are imported by EVS.";
+    }
+}
+
+
+void StreamHandler::shutdown()
+{
+    // Make sure we're not still streaming
+    blockingStopStream();
+
+    // At this point, the receiver thread is no longer running, so we can safely drop
+    // our remote object references so they can be freed
+    mCamera = nullptr;
+
+    if (mUseOwnBuffers) {
+        android::GraphicBufferAllocator &alloc(android::GraphicBufferAllocator::get());
+        for (auto& b : mOwnBuffers) {
+            alloc.free(b.buffer.nativeHandle);
+        }
+
+        mOwnBuffers.resize(0);
+    }
+}
+
+
+bool StreamHandler::startStream() {
+    std::unique_lock<std::mutex> lock(mLock);
+
+    if (!mRunning) {
+        // Tell the camera to start streaming
+        Return <EvsResult> result = mCamera->startVideoStream(this);
+        if (result != EvsResult::OK) {
+            return false;
+        }
+
+        // Mark ourselves as running
+        mRunning = true;
+    }
+
+    return true;
+}
+
+
+void StreamHandler::asyncStopStream() {
+    // Tell the camera to stop streaming.
+    // This will result in a null frame being delivered when the stream actually stops.
+    mCamera->stopVideoStream();
+}
+
+
+void StreamHandler::blockingStopStream() {
+    // Tell the stream to stop
+    asyncStopStream();
+
+    // Wait until the stream has actually stopped
+    std::unique_lock<std::mutex> lock(mLock);
+    if (mRunning) {
+        mSignal.wait(lock, [this]() { return !mRunning; });
+    }
+}
+
+
+bool StreamHandler::isRunning() {
+    std::unique_lock<std::mutex> lock(mLock);
+    return mRunning;
+}
+
+
+bool StreamHandler::newFrameAvailable() {
+    std::unique_lock<std::mutex> lock(mLock);
+    return (mReadyBuffer >= 0);
+}
+
+
+const BufferDesc_1_1& StreamHandler::getNewFrame() {
+    std::unique_lock<std::mutex> lock(mLock);
+
+    if (mHeldBuffer >= 0) {
+        LOG(ERROR) << "Ignored call for new frame while still holding the old one.";
+    } else {
+        if (mReadyBuffer < 0) {
+            LOG(ERROR) << "Returning invalid buffer because we don't have any.  "
+                       << "Call newFrameAvailable first?";
+            mReadyBuffer = 0;   // This is a lie!
+        }
+
+        // Move the ready buffer into the held position, and clear the ready position
+        mHeldBuffer = mReadyBuffer;
+        mReadyBuffer = -1;
+    }
+
+    return mBuffers[mHeldBuffer];
+}
+
+
+void StreamHandler::doneWithFrame(const BufferDesc_1_1& bufDesc_1_1) {
+    std::unique_lock<std::mutex> lock(mLock);
+
+    // We better be getting back the buffer we original delivered!
+    if ((mHeldBuffer < 0) || (bufDesc_1_1.bufferId != mBuffers[mHeldBuffer].bufferId)) {
+        LOG(ERROR) << "StreamHandler::doneWithFrame got an unexpected bufDesc_1_1!";
+    }
+
+    // Send the buffer back to the underlying camera
+    hidl_vec<BufferDesc_1_1> frames;
+    frames.resize(1);
+    frames[0] = mBuffers[mHeldBuffer];
+    mCamera->doneWithFrame_1_1(frames);
+
+    // Clear the held position
+    mHeldBuffer = -1;
+}
+
+
+Return<void> StreamHandler::deliverFrame(const BufferDesc_1_0& bufDesc_1_0) {
+    LOG(INFO) << "Ignores a frame delivered from v1.0 EVS service.";
+    mCamera->doneWithFrame(bufDesc_1_0);
+
+    return Void();
+}
+
+
+Return<void> StreamHandler::deliverFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffers) {
+    LOG(DEBUG) << "Received frames from the camera";
+
+    // Take the lock to protect our frame slots and running state variable
+    std::unique_lock <std::mutex> lock(mLock);
+    BufferDesc_1_1 bufDesc = buffers[0];
+    if (bufDesc.buffer.nativeHandle.getNativeHandle() == nullptr) {
+        // Signal that the last frame has been received and the stream is stopped
+        LOG(WARNING) << "Invalid null frame (id: " << std::hex << bufDesc.bufferId
+                     << ") is ignored";
+    } else {
+        // Do we already have a "ready" frame?
+        if (mReadyBuffer >= 0) {
+            // Send the previously saved buffer back to the camera unused
+            hidl_vec<BufferDesc_1_1> frames;
+            frames.resize(1);
+            frames[0] = mBuffers[mReadyBuffer];
+            mCamera->doneWithFrame_1_1(frames);
+
+            // We'll reuse the same ready buffer index
+        } else if (mHeldBuffer >= 0) {
+            // The client is holding a buffer, so use the other slot for "on deck"
+            mReadyBuffer = 1 - mHeldBuffer;
+        } else {
+            // This is our first buffer, so just pick a slot
+            mReadyBuffer = 0;
+        }
+
+        // Save this frame until our client is interested in it
+        mBuffers[mReadyBuffer] = bufDesc;
+    }
+
+    // Notify anybody who cares that things have changed
+    lock.unlock();
+    mSignal.notify_all();
+
+    return Void();
+}
+
+
+Return<void> StreamHandler::notify(const EvsEventDesc& event) {
+    switch(event.aType) {
+        case EvsEventType::STREAM_STOPPED:
+        {
+            {
+                std::lock_guard<std::mutex> lock(mLock);
+
+                // Signal that the last frame has been received and the stream is stopped
+                mRunning = false;
+            }
+            LOG(INFO) << "Received a STREAM_STOPPED event";
+            break;
+        }
+
+        case EvsEventType::PARAMETER_CHANGED:
+            LOG(INFO) << "Camera parameter " << std::hex << event.payload[0]
+                      << " is set to " << event.payload[1];
+            break;
+
+        // Below events are ignored in reference implementation.
+        case EvsEventType::STREAM_STARTED:
+        [[fallthrough]];
+        case EvsEventType::FRAME_DROPPED:
+        [[fallthrough]];
+        case EvsEventType::TIMEOUT:
+            LOG(INFO) << "Event " << std::hex << static_cast<unsigned>(event.aType)
+                      << "is received but ignored.";
+            break;
+        default:
+            LOG(ERROR) << "Unknown event id: " << static_cast<unsigned>(event.aType);
+            break;
+    }
+
+    return Void();
+}
+
diff --git a/evs/apps/default/StreamHandler.h b/evs/apps/default/StreamHandler.h
new file mode 100644
index 0000000..cb22b36
--- /dev/null
+++ b/evs/apps/default/StreamHandler.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef EVS_VTS_STREAMHANDLER_H
+#define EVS_VTS_STREAMHANDLER_H
+
+#include <queue>
+
+#include "ui/GraphicBuffer.h"
+
+#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_handle;
+using ::android::sp;
+using ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
+using EvsDisplayState = ::android::hardware::automotive::evs::V1_0::DisplayState;
+using BufferDesc_1_0  = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using BufferDesc_1_1  = ::android::hardware::automotive::evs::V1_1::BufferDesc;
+
+
+/*
+ * StreamHandler:
+ * This class can be used to receive camera imagery from an IEvsCamera implementation.  It will
+ * hold onto the most recent image buffer, returning older ones.
+ * Note that the video frames are delivered on a background thread, while the control interface
+ * is actuated from the applications foreground thread.
+ */
+class StreamHandler : public IEvsCameraStream {
+public:
+    virtual ~StreamHandler() { shutdown(); };
+
+    StreamHandler(android::sp <IEvsCamera> pCamera,
+                  uint32_t numBuffers = 2,
+                  bool useOwnBuffers = false,
+                  android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888,
+                  int32_t width = 640,
+                  int32_t height = 360);
+    void shutdown();
+
+    bool startStream();
+    void asyncStopStream();
+    void blockingStopStream();
+
+    bool isRunning();
+
+    bool newFrameAvailable();
+    const BufferDesc_1_1& getNewFrame();
+    void doneWithFrame(const BufferDesc_1_1& buffer);
+
+private:
+    // Implementation for ::android::hardware::automotive::evs::V1_0::IEvsCameraStream
+    Return<void> deliverFrame(const BufferDesc_1_0& buffer)  override;
+
+    // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream
+    Return<void> deliverFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffer)  override;
+    Return<void> notify(const EvsEventDesc& event) override;
+
+    // Values initialized as startup
+    android::sp <IEvsCamera>    mCamera;
+
+    // Since we get frames delivered to us asnchronously via the ICarCameraStream interface,
+    // we need to protect all member variables that may be modified while we're streaming
+    // (ie: those below)
+    std::mutex                  mLock;
+    std::condition_variable     mSignal;
+
+    bool                        mRunning = false;
+
+    BufferDesc                  mBuffers[2];
+    int                         mHeldBuffer = -1;   // Index of the one currently held by the client
+    int                         mReadyBuffer = -1;  // Index of the newest available buffer
+    hidl_vec<BufferDesc_1_1>    mOwnBuffers;
+    bool                        mUseOwnBuffers;
+};
+
+
+#endif //EVS_VTS_STREAMHANDLER_H
diff --git a/evs/apps/default/TexWrapper.cpp b/evs/apps/default/TexWrapper.cpp
new file mode 100644
index 0000000..37cb7a2
--- /dev/null
+++ b/evs/apps/default/TexWrapper.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "TexWrapper.h"
+#include "glError.h"
+
+#include <fcntl.h>
+#include <malloc.h>
+#include <png.h>
+
+#include <android-base/logging.h>
+
+
+/* Create an new empty GL texture that will be filled later */
+TexWrapper::TexWrapper() {
+    GLuint textureId;
+    glGenTextures(1, &textureId);
+    if (textureId <= 0) {
+        LOG(ERROR) << "Didn't get a texture handle allocated: " << getEGLError();
+    } else {
+        // Store the basic texture properties
+        id = textureId;
+        w  = 0;
+        h  = 0;
+    }
+}
+
+
+/* Wrap a texture that already allocated.  The wrapper takes ownership. */
+TexWrapper::TexWrapper(GLuint textureId, unsigned width, unsigned height) {
+    // Store the basic texture properties
+    id = textureId;
+    w  = width;
+    h  = height;
+}
+
+
+TexWrapper::~TexWrapper() {
+    // Give the texture ID back
+    if (id > 0) {
+        glDeleteTextures(1, &id);
+    }
+    id = -1;
+}
+
+
+/* Factory to build TexWrapper objects from a given PNG file */
+TexWrapper* createTextureFromPng(const char * filename)
+{
+    // Open the PNG file
+    FILE *inputFile = fopen(filename, "rb");
+    if (inputFile == 0)
+    {
+        perror(filename);
+        return nullptr;
+    }
+
+    // Read the file header and validate that it is a PNG
+    static const int kSigSize = 8;
+    png_byte header[kSigSize] = {0};
+    fread(header, 1, kSigSize, inputFile);
+    if (png_sig_cmp(header, 0, kSigSize)) {
+        printf("%s is not a PNG.\n", filename);
+        fclose(inputFile);
+        return nullptr;
+    }
+
+    // Set up our control structure
+    png_structp pngControl = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (!pngControl)
+    {
+        printf("png_create_read_struct failed.\n");
+        fclose(inputFile);
+        return nullptr;
+    }
+
+    // Set up our image info structure
+    png_infop pngInfo = png_create_info_struct(pngControl);
+    if (!pngInfo)
+    {
+        printf("error: png_create_info_struct returned 0.\n");
+        png_destroy_read_struct(&pngControl, nullptr, nullptr);
+        fclose(inputFile);
+        return nullptr;
+    }
+
+    // Install an error handler
+    if (setjmp(png_jmpbuf(pngControl))) {
+        printf("libpng reported an error\n");
+        png_destroy_read_struct(&pngControl, &pngInfo, nullptr);
+        fclose(inputFile);
+        return nullptr;
+    }
+
+    // Set up the png reader and fetch the remaining bits of the header
+    png_init_io(pngControl, inputFile);
+    png_set_sig_bytes(pngControl, kSigSize);
+    png_read_info(pngControl, pngInfo);
+
+    // Get basic information about the PNG we're reading
+    int bitDepth;
+    int colorFormat;
+    png_uint_32 width;
+    png_uint_32 height;
+    png_get_IHDR(pngControl, pngInfo,
+                 &width, &height,
+                 &bitDepth, &colorFormat,
+                 NULL, NULL, NULL);
+
+    GLint format;
+    switch(colorFormat)
+    {
+        case PNG_COLOR_TYPE_RGB:
+            format = GL_RGB;
+            break;
+        case PNG_COLOR_TYPE_RGB_ALPHA:
+            format = GL_RGBA;
+            break;
+        default:
+            printf("%s: Unknown libpng color format %d.\n", filename, colorFormat);
+            return nullptr;
+    }
+
+    // Refresh the values in the png info struct in case any transformation shave been applied.
+    png_read_update_info(pngControl, pngInfo);
+    int stride = png_get_rowbytes(pngControl, pngInfo);
+    stride += 3 - ((stride-1) % 4);   // glTexImage2d requires rows to be 4-byte aligned
+
+    // Allocate storage for the pixel data
+    png_byte * buffer = (png_byte*)malloc(stride * height);
+    if (buffer == NULL)
+    {
+        printf("error: could not allocate memory for PNG image data\n");
+        png_destroy_read_struct(&pngControl, &pngInfo, nullptr);
+        fclose(inputFile);
+        return nullptr;
+    }
+
+    // libpng needs an array of pointers into the image data for each row
+    png_byte ** rowPointers = (png_byte**)malloc(height * sizeof(png_byte*));
+    if (rowPointers == NULL)
+    {
+        printf("Failed to allocate temporary row pointers\n");
+        png_destroy_read_struct(&pngControl, &pngInfo, nullptr);
+        free(buffer);
+        fclose(inputFile);
+        return nullptr;
+    }
+    for (unsigned int r = 0; r < height; r++)
+    {
+        rowPointers[r] = buffer + r*stride;
+    }
+
+
+    // Read in the actual image bytes
+    png_read_image(pngControl, rowPointers);
+    png_read_end(pngControl, nullptr);
+
+
+    // Set up the OpenGL texture to contain this image
+    GLuint textureId;
+    glGenTextures(1, &textureId);
+    glBindTexture(GL_TEXTURE_2D, textureId);
+
+    // Send the image data to GL
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+
+    // Initialize the sampling properties (it seems the sample may not work if this isn't done)
+    // The user of this texture may very well want to set their own filtering, but we're going
+    // to pay the (minor) price of setting this up for them to avoid the dreaded "black image" if
+    // they forget.
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+    // clean up
+    png_destroy_read_struct(&pngControl, &pngInfo, nullptr);
+    free(buffer);
+    free(rowPointers);
+    fclose(inputFile);
+
+    glBindTexture(GL_TEXTURE_2D, 0);
+
+
+    // Return the texture
+    return new TexWrapper(textureId, width, height);
+}
diff --git a/evs/app/TexWrapper.h b/evs/apps/default/TexWrapper.h
similarity index 100%
rename from evs/app/TexWrapper.h
rename to evs/apps/default/TexWrapper.h
diff --git a/evs/apps/default/VideoTex.cpp b/evs/apps/default/VideoTex.cpp
new file mode 100644
index 0000000..7491dfe
--- /dev/null
+++ b/evs/apps/default/VideoTex.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vector>
+#include <stdio.h>
+#include <fcntl.h>
+#include <alloca.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <malloc.h>
+#include <png.h>
+
+#include "VideoTex.h"
+#include "glError.h"
+
+#include <ui/GraphicBuffer.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android-base/logging.h>
+
+// Eventually we shouldn't need this dependency, but for now the
+// graphics allocator interface isn't fully supported on all platforms
+// and this is our work around.
+using ::android::GraphicBuffer;
+
+
+VideoTex::VideoTex(sp<IEvsEnumerator> pEnum,
+                   sp<IEvsCamera> pCamera,
+                   sp<StreamHandler> pStreamHandler,
+                   EGLDisplay glDisplay)
+    : TexWrapper()
+    , mEnumerator(pEnum)
+    , mCamera(pCamera)
+    , mStreamHandler(pStreamHandler)
+    , mDisplay(glDisplay) {
+    // Nothing but initialization here...
+}
+
+VideoTex::~VideoTex() {
+    // Tell the stream to stop flowing
+    mStreamHandler->asyncStopStream();
+
+    // Close the camera
+    mEnumerator->closeCamera(mCamera);
+
+    // Drop our device texture image
+    if (mKHRimage != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(mDisplay, mKHRimage);
+        mKHRimage = EGL_NO_IMAGE_KHR;
+    }
+}
+
+
+// Return true if the texture contents are changed
+bool VideoTex::refresh() {
+    if (!mStreamHandler->newFrameAvailable()) {
+        // No new image has been delivered, so there's nothing to do here
+        return false;
+    }
+
+    // If we already have an image backing us, then it's time to return it
+    if (mImageBuffer.buffer.nativeHandle.getNativeHandle() != nullptr) {
+        // Drop our device texture image
+        if (mKHRimage != EGL_NO_IMAGE_KHR) {
+            eglDestroyImageKHR(mDisplay, mKHRimage);
+            mKHRimage = EGL_NO_IMAGE_KHR;
+        }
+
+        // Return it since we're done with it
+        mStreamHandler->doneWithFrame(mImageBuffer);
+    }
+
+    // Get the new image we want to use as our contents
+    mImageBuffer = mStreamHandler->getNewFrame();
+
+
+    // create a GraphicBuffer from the existing handle
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&mImageBuffer.buffer.description);
+    sp<GraphicBuffer> pGfxBuffer = new GraphicBuffer(mImageBuffer.buffer.nativeHandle,
+                                                     GraphicBuffer::CLONE_HANDLE,
+                                                     pDesc->width,
+                                                     pDesc->height,
+                                                     pDesc->format,
+                                                     1,//pDesc->layers,
+                                                     GRALLOC_USAGE_HW_TEXTURE,
+                                                     pDesc->stride);
+    if (pGfxBuffer.get() == nullptr) {
+        LOG(ERROR) << "Failed to allocate GraphicBuffer to wrap image handle";
+        // Returning "true" in this error condition because we already released the
+        // previous image (if any) and so the texture may change in unpredictable ways now!
+        return true;
+    }
+
+    // Get a GL compatible reference to the graphics buffer we've been given
+    EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
+    EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(pGfxBuffer->getNativeBuffer());
+    mKHRimage = eglCreateImageKHR(mDisplay, EGL_NO_CONTEXT,
+                                  EGL_NATIVE_BUFFER_ANDROID, clientBuf,
+                                  eglImageAttributes);
+    if (mKHRimage == EGL_NO_IMAGE_KHR) {
+        const char *msg = getEGLError();
+        LOG(ERROR) << "Error creating EGLImage: " << msg;
+    } else {
+        // Update the texture handle we already created to refer to this gralloc buffer
+        glActiveTexture(GL_TEXTURE0);
+        glBindTexture(GL_TEXTURE_2D, glId());
+        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast<GLeglImageOES>(mKHRimage));
+
+        // Initialize the sampling properties (it seems the sample may not work if this isn't done)
+        // The user of this texture may very well want to set their own filtering, but we're going
+        // to pay the (minor) price of setting this up for them to avoid the dreaded "black image"
+        // if they forget.
+        // TODO:  Can we do this once for the texture ID rather than ever refresh?
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    }
+
+    return true;
+}
+
+
+VideoTex* createVideoTexture(sp<IEvsEnumerator> pEnum,
+                             const char* evsCameraId,
+                             std::unique_ptr<Stream> streamCfg,
+                             EGLDisplay glDisplay,
+                             bool useExternalMemory,
+                             android_pixel_format_t format) {
+    // Set up the camera to feed this texture
+    sp<IEvsCamera> pCamera = nullptr;
+    sp<StreamHandler> pStreamHandler = nullptr;
+    if (streamCfg != nullptr) {
+        pCamera = pEnum->openCamera_1_1(evsCameraId, *streamCfg);
+
+        // Initialize the stream that will help us update this texture's contents
+        pStreamHandler = new StreamHandler(pCamera,
+                                           2,     // number of buffers
+                                           useExternalMemory,
+                                           format,
+                                           streamCfg->width,
+                                           streamCfg->height);
+    } else {
+        pCamera =
+            IEvsCamera::castFrom(pEnum->openCamera(evsCameraId))
+            .withDefault(nullptr);
+
+        // Initialize the stream with the default resolution
+        pStreamHandler = new StreamHandler(pCamera,
+                                           2,     // number of buffers
+                                           useExternalMemory,
+                                           format);
+    }
+
+    if (pCamera == nullptr) {
+        LOG(ERROR) << "Failed to allocate new EVS Camera interface for " << evsCameraId;
+        return nullptr;
+    }
+
+    if (pStreamHandler == nullptr) {
+        LOG(ERROR) << "Failed to allocate FrameHandler";
+        return nullptr;
+    }
+
+    // Start the video stream
+    if (!pStreamHandler->startStream()) {
+        printf("Couldn't start the camera stream (%s)\n", evsCameraId);
+        LOG(ERROR) << "Start stream failed for " << evsCameraId;
+        return nullptr;
+    }
+
+    return new VideoTex(pEnum, pCamera, pStreamHandler, glDisplay);
+}
diff --git a/evs/apps/default/VideoTex.h b/evs/apps/default/VideoTex.h
new file mode 100644
index 0000000..097d086
--- /dev/null
+++ b/evs/apps/default/VideoTex.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef VIDEOTEX_H
+#define VIDEOTEX_H
+
+#include "StreamHandler.h"
+#include "TexWrapper.h"
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <system/graphics-base.h>
+
+using ::android::hardware::camera::device::V3_2::Stream;
+using namespace ::android::hardware::automotive::evs::V1_1;
+
+
+class VideoTex: public TexWrapper {
+    friend VideoTex* createVideoTexture(sp<IEvsEnumerator> pEnum,
+                                        const char *evsCameraId,
+                                        std::unique_ptr<Stream> streamCfg,
+                                        EGLDisplay glDisplay,
+                                        bool useExternalMemory,
+                                        android_pixel_format_t format);
+
+public:
+    VideoTex() = delete;
+    virtual ~VideoTex();
+
+    bool refresh();     // returns true if the texture contents were updated
+
+private:
+    VideoTex(sp<IEvsEnumerator> pEnum,
+             sp<IEvsCamera> pCamera,
+             sp<StreamHandler> pStreamHandler,
+             EGLDisplay glDisplay);
+
+    sp<IEvsEnumerator>  mEnumerator;
+    sp<IEvsCamera>      mCamera;
+    sp<StreamHandler>   mStreamHandler;
+    BufferDesc          mImageBuffer;
+
+    EGLDisplay          mDisplay;
+    EGLImageKHR mKHRimage = EGL_NO_IMAGE_KHR;
+};
+
+
+// Creates a video texture to draw the camera preview.  format is effective only
+// when useExternalMemory is true.
+VideoTex* createVideoTexture(sp<IEvsEnumerator> pEnum,
+                             const char * deviceName,
+                             std::unique_ptr<Stream> streamCfg,
+                             EGLDisplay glDisplay,
+                             bool useExternalMemory = false,
+                             android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888);
+
+#endif // VIDEOTEX_H
diff --git a/evs/apps/default/config.json b/evs/apps/default/config.json
new file mode 100644
index 0000000..1762e86
--- /dev/null
+++ b/evs/apps/default/config.json
@@ -0,0 +1,38 @@
+
+{
+  "car" : {
+    "width"  : 76.7,
+    "wheelBase" : 117.9,
+    "frontExtent" : 44.7,
+    "rearExtent" : 40
+  },
+  "displays" : [
+    {
+      "displayPort" : 1,
+      "frontRange" : 100,
+      "rearRange" : 100
+    },
+    {
+      "displayPort" : 2,
+      "frontRange" : 100,
+      "rearRange" : 100
+    }
+  ],
+  "graphic" : {
+    "frontPixel" : 23,
+    "rearPixel" : 223
+  },
+  "cameras" : [
+    {
+      "cameraId" : "/dev/video3",
+      "function" : "reverse, park",
+      "x" : 0.0,
+      "y" : -40.0,
+      "z" : 48,
+      "yaw" : 180,
+      "pitch" : -30,
+      "hfov" : 125,
+      "vfov" : 103
+    }
+  ]
+}
diff --git a/evs/apps/default/config.json.readme b/evs/apps/default/config.json.readme
new file mode 100644
index 0000000..561adcc
--- /dev/null
+++ b/evs/apps/default/config.json.readme
@@ -0,0 +1,45 @@
+// With comments included, this file is no longer legal JSON, but serves to illustrate
+// the format of the configuration file the evs_app expects to read at startup to configure itself
+// for a specific car.
+// In addition to the configuration file, an image to be used to represent the car is expected
+// to be provided in CarFromTop.png.
+// Throughout this file, units of length are arbitrary, but must all be the same units.
+// X is right, Y is forward, Z is up (right handed coordinate system).
+// The origin is at the center of the read axel at ground level.
+// Units for angles are in degrees.
+// Yaw is measured from the front of the car, positive to the left (postive Z rotation).
+// Pitch is measured from the horizon, positive upward (postive X rotation).
+// Roll is always assumed to be zero.
+
+{
+  "car" : {                     // This section describes the geometry of the car
+    "width"  : 76.7,            // The width of the car body
+    "wheelBase" : 117.9,        // The distance between the front and read axel
+    "frontExtent" : 44.7,       // The extent of the car body ahead of the front axel
+    "rearExtent" : 40           // The extent of the car body behind the read axel
+  },
+  "displays" : [                // This configures the dimensions of the surround view display
+    {                           // The first display will be used as the default display
+      "displayPort" : 1         // Display port number, the target display is connected to.
+      "frontRange" : 100,       // How far to render the view in front of the front bumper
+      "rearRange" : 100         // How far the view extends behind the rear bumper
+    }
+  ],
+  "graphic" : {                 // This maps the car texture into the projected view space
+    "frontPixel" : 23,          // The pixel row in CarFromTop.png at which the front bumper appears
+    "rearPixel" : 223           // The pixel row in CarFromTop.png at which the back bumper ends
+  },
+  "cameras" : [                 // This describes the cameras potentially available on the car
+    {
+      "cameraId" : "/dev/video32",  // Camera ID exposed by EVS HAL
+      "function" : "reverse,park",  // set of modes to which this camera contributes
+      "x" : 0.0,                    // Optical center distance right of vehicle center
+      "y" : -40.0,                  // Optical center distance forward of rear axel
+      "z" : 48,                     // Optical center distance above ground
+      "yaw" : 180,                  // Optical axis degrees to the left of straight ahead
+      "pitch" : -30,                // Optical axis degrees above the horizon
+      "hfov" : 125,                 // Horizontal field of view in degrees
+      "vfov" :103                   // Vertical field of view in degrees
+    }
+  ]
+}
diff --git a/evs/apps/default/evs_app.cpp b/evs/apps/default/evs_app.cpp
new file mode 100644
index 0000000..92d4b7a
--- /dev/null
+++ b/evs/apps/default/evs_app.cpp
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConfigManager.h"
+#include "EvsStateControl.h"
+#include "EvsVehicleListener.h"
+
+#include <signal.h>
+#include <stdio.h>
+
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <android-base/logging.h>
+#include <android-base/macros.h>    // arraysize
+#include <android-base/strings.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/IPCThreadState.h>
+#include <hwbinder/ProcessState.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+#include <utils/Log.h>
+
+
+using android::base::EqualsIgnoreCase;
+
+// libhidl:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+namespace {
+
+android::sp<IEvsEnumerator> pEvs;
+android::sp<IEvsDisplay> pDisplay;
+EvsStateControl *pStateController;
+
+void sigHandler(int sig) {
+    LOG(ERROR) << "evs_app is being terminated on receiving a signal " << sig;
+    if (pEvs != nullptr) {
+        // Attempt to clean up the resources
+        pStateController->postCommand({EvsStateControl::Op::EXIT, 0, 0}, true);
+        pStateController->terminateUpdateLoop();
+        pEvs->closeDisplay(pDisplay);
+    }
+
+    android::hardware::IPCThreadState::self()->stopProcess();
+    exit(EXIT_FAILURE);
+}
+
+void registerSigHandler() {
+    struct sigaction sa;
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = sigHandler;
+    sigaction(SIGABRT, &sa, nullptr);
+    sigaction(SIGTERM, &sa, nullptr);
+    sigaction(SIGINT,  &sa, nullptr);
+}
+
+} // namespace
+
+
+// Helper to subscribe to VHal notifications
+static bool subscribeToVHal(sp<IVehicle> pVnet,
+                            sp<IVehicleCallback> listener,
+                            VehicleProperty propertyId) {
+    assert(pVnet != nullptr);
+    assert(listener != nullptr);
+
+    // Register for vehicle state change callbacks we care about
+    // Changes in these values are what will trigger a reconfiguration of the EVS pipeline
+    SubscribeOptions optionsData[] = {
+        {
+            .propId = static_cast<int32_t>(propertyId),
+            .flags  = SubscribeFlags::EVENTS_FROM_CAR
+        },
+    };
+    hidl_vec <SubscribeOptions> options;
+    options.setToExternal(optionsData, arraysize(optionsData));
+    StatusCode status = pVnet->subscribe(listener, options);
+    if (status != StatusCode::OK) {
+        LOG(WARNING) << "VHAL subscription for property " << static_cast<int32_t>(propertyId)
+                     << " failed with code " << static_cast<int32_t>(status);
+        return false;
+    }
+
+    return true;
+}
+
+
+static bool convertStringToFormat(const char* str, android_pixel_format_t* output) {
+    bool result = true;
+    if (EqualsIgnoreCase(str, "RGBA8888")) {
+        *output = HAL_PIXEL_FORMAT_RGBA_8888;
+    } else if (EqualsIgnoreCase(str, "YV12")) {
+        *output = HAL_PIXEL_FORMAT_YV12;
+    } else if (EqualsIgnoreCase(str, "NV21")) {
+        *output = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+    } else if (EqualsIgnoreCase(str, "YUYV")) {
+        *output = HAL_PIXEL_FORMAT_YCBCR_422_I;
+    } else {
+        result = false;
+    }
+
+    return result;
+}
+
+
+// Main entry point
+int main(int argc, char** argv)
+{
+    LOG(INFO) << "EVS app starting";
+
+    // Register a signal handler
+    registerSigHandler();
+
+    // Set up default behavior, then check for command line options
+    bool useVehicleHal = true;
+    bool printHelp = false;
+    const char* evsServiceName = "default";
+    int displayId = -1;
+    bool useExternalMemory = false;
+    android_pixel_format_t extMemoryFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+    for (int i=1; i< argc; i++) {
+        if (strcmp(argv[i], "--test") == 0) {
+            useVehicleHal = false;
+        } else if (strcmp(argv[i], "--hw") == 0) {
+            evsServiceName = "EvsEnumeratorHw";
+        } else if (strcmp(argv[i], "--mock") == 0) {
+            evsServiceName = "EvsEnumeratorHw-Mock";
+        } else if (strcmp(argv[i], "--help") == 0) {
+            printHelp = true;
+        } else if (strcmp(argv[i], "--display") == 0) {
+            displayId = std::stoi(argv[++i]);
+        } else if (strcmp(argv[i], "--extmem") == 0) {
+            useExternalMemory = true;
+            if (i + 1 >= argc) {
+                // use RGBA8888 by default
+                LOG(INFO) << "External buffer format is not set.  "
+                          << "RGBA8888 will be used.";
+            } else {
+                if (!convertStringToFormat(argv[i + 1], &extMemoryFormat)) {
+                    LOG(WARNING) << "Color format string " << argv[i + 1]
+                                 << " is unknown or not supported.  RGBA8888 will be used.";
+                } else {
+                    // move the index
+                    ++i;
+                }
+            }
+        } else {
+            printf("Ignoring unrecognized command line arg '%s'\n", argv[i]);
+            printHelp = true;
+        }
+    }
+    if (printHelp) {
+        printf("Options include:\n");
+        printf("  --test\n\tDo not talk to Vehicle Hal, but simulate 'reverse' instead\n");
+        printf("  --hw\n\tBypass EvsManager by connecting directly to EvsEnumeratorHw\n");
+        printf("  --mock\n\tConnect directly to EvsEnumeratorHw-Mock\n");
+        printf("  --display\n\tSpecify the display to use.  If this is not set, the first"
+                              "display in config.json's list will be used.\n");
+        printf("  --extmem  <format>\n\t"
+               "Application allocates buffers to capture camera frames.  "
+               "Available format strings are (case insensitive):\n");
+        printf("\t\tRGBA8888: 4x8-bit RGBA format.  This is the default format to be used "
+               "when no format is specified.\n");
+        printf("\t\tYV12: YUV420 planar format with a full resolution Y plane "
+               "followed by a V values, with U values last.\n");
+        printf("\t\tNV21: A biplanar format with a full resolution Y plane "
+               "followed by a single chrome plane with weaved V and U values.\n");
+        printf("\t\tYUYV: Packed format with a half horizontal chrome resolution.  "
+               "Known as YUV4:2:2.\n");
+
+        return EXIT_FAILURE;
+    }
+
+    // Load our configuration information
+    ConfigManager config;
+    if (!config.initialize("/system/etc/automotive/evs/config.json")) {
+        LOG(ERROR) << "Missing or improper configuration for the EVS application.  Exiting.";
+        return EXIT_FAILURE;
+    }
+
+    // Set thread pool size to one to avoid concurrent events from the HAL.
+    // This pool will handle the EvsCameraStream callbacks.
+    // Note:  This _will_ run in parallel with the EvsListener run() loop below which
+    // runs the application logic that reacts to the async events.
+    configureRpcThreadpool(1, false /* callerWillJoin */);
+
+    // Construct our async helper object
+    sp<EvsVehicleListener> pEvsListener = new EvsVehicleListener();
+
+    // Get the EVS manager service
+    LOG(INFO) << "Acquiring EVS Enumerator";
+    pEvs = IEvsEnumerator::getService(evsServiceName);
+    if (pEvs.get() == nullptr) {
+        LOG(ERROR) << "getService(" << evsServiceName
+                   << ") returned NULL.  Exiting.";
+        return EXIT_FAILURE;
+    }
+
+    // Request exclusive access to the EVS display
+    LOG(INFO) << "Acquiring EVS Display";
+
+    // We'll use an available display device.
+    displayId = config.setActiveDisplayId(displayId);
+    if (displayId < 0) {
+        PLOG(ERROR) << "EVS Display is unknown.  Exiting.";
+        return EXIT_FAILURE;
+    }
+
+    pDisplay = pEvs->openDisplay_1_1(displayId);
+    if (pDisplay.get() == nullptr) {
+        LOG(ERROR) << "EVS Display unavailable.  Exiting.";
+        return EXIT_FAILURE;
+    }
+
+    config.useExternalMemory(useExternalMemory);
+    config.setExternalMemoryFormat(extMemoryFormat);
+
+    // Connect to the Vehicle HAL so we can monitor state
+    sp<IVehicle> pVnet;
+    if (useVehicleHal) {
+        LOG(INFO) << "Connecting to Vehicle HAL";
+        pVnet = IVehicle::getService();
+        if (pVnet.get() == nullptr) {
+            LOG(ERROR) << "Vehicle HAL getService returned NULL.  Exiting.";
+            return EXIT_FAILURE;
+        } else {
+            // Register for vehicle state change callbacks we care about
+            // Changes in these values are what will trigger a reconfiguration of the EVS pipeline
+            if (!subscribeToVHal(pVnet, pEvsListener, VehicleProperty::GEAR_SELECTION)) {
+                LOG(ERROR) << "Without gear notification, we can't support EVS.  Exiting.";
+                return EXIT_FAILURE;
+            }
+            if (!subscribeToVHal(pVnet, pEvsListener, VehicleProperty::TURN_SIGNAL_STATE)) {
+                LOG(WARNING) << "Didn't get turn signal notifications, so we'll ignore those.";
+            }
+        }
+    } else {
+        LOG(WARNING) << "Test mode selected, so not talking to Vehicle HAL";
+    }
+
+    // Configure ourselves for the current vehicle state at startup
+    LOG(INFO) << "Constructing state controller";
+    pStateController = new EvsStateControl(pVnet, pEvs, pDisplay, config);
+    if (!pStateController->startUpdateLoop()) {
+        LOG(ERROR) << "Initial configuration failed.  Exiting.";
+        return EXIT_FAILURE;
+    }
+
+    // Run forever, reacting to events as necessary
+    LOG(INFO) << "Entering running state";
+    pEvsListener->run(pStateController);
+
+    // In normal operation, we expect to run forever, but in some error conditions we'll quit.
+    // One known example is if another process preempts our registration for our service name.
+    LOG(ERROR) << "EVS Listener stopped.  Exiting.";
+
+    return EXIT_SUCCESS;
+}
diff --git a/evs/app/evs_app.rc b/evs/apps/default/evs_app.rc
similarity index 100%
rename from evs/app/evs_app.rc
rename to evs/apps/default/evs_app.rc
diff --git a/evs/app/glError.cpp b/evs/apps/default/glError.cpp
similarity index 100%
rename from evs/app/glError.cpp
rename to evs/apps/default/glError.cpp
diff --git a/evs/app/glError.h b/evs/apps/default/glError.h
similarity index 100%
rename from evs/app/glError.h
rename to evs/apps/default/glError.h
diff --git a/evs/app/shader.cpp b/evs/apps/default/shader.cpp
similarity index 100%
rename from evs/app/shader.cpp
rename to evs/apps/default/shader.cpp
diff --git a/evs/app/shader.h b/evs/apps/default/shader.h
similarity index 100%
rename from evs/app/shader.h
rename to evs/apps/default/shader.h
diff --git a/evs/app/shader_projectedTex.h b/evs/apps/default/shader_projectedTex.h
similarity index 100%
rename from evs/app/shader_projectedTex.h
rename to evs/apps/default/shader_projectedTex.h
diff --git a/evs/app/shader_simpleTex.h b/evs/apps/default/shader_simpleTex.h
similarity index 100%
rename from evs/app/shader_simpleTex.h
rename to evs/apps/default/shader_simpleTex.h
diff --git a/evs/apps/demo_app_evs_support_lib/Android.bp b/evs/apps/demo_app_evs_support_lib/Android.bp
new file mode 100644
index 0000000..ae0073a
--- /dev/null
+++ b/evs/apps/demo_app_evs_support_lib/Android.bp
@@ -0,0 +1,45 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+
+//#################################
+cc_binary {
+    name: "evs_app_support_lib",
+
+    srcs: ["evs_app_support_lib.cpp"],
+
+    shared_libs: [
+        "liblog",
+        "libui",
+        "android.hardware.automotive.evs@1.0",
+        "android.hardware.automotive.vehicle@2.0",
+        "libevssupport",
+    ],
+
+    include_dirs: ["packages/services/Car/evs/support_library"],
+
+    init_rc: ["evs_app_support_lib.rc"],
+
+    cflags: ["-DLOG_TAG=\"EvsAppSupportLib\""] + [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+    ] + [
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+
+}
diff --git a/evs/apps/demo_app_evs_support_lib/evs_app_support_lib.cpp b/evs/apps/demo_app_evs_support_lib/evs_app_support_lib.cpp
new file mode 100644
index 0000000..8799bd2
--- /dev/null
+++ b/evs/apps/demo_app_evs_support_lib/evs_app_support_lib.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <utils/SystemClock.h>
+#include <string>
+#include <log/log.h>
+
+#include <DisplayUseCase.h>
+#include <AnalyzeUseCase.h>
+#include <Utils.h>
+
+using namespace ::android::automotive::evs::support;
+
+class SimpleRenderCallback : public BaseRenderCallback {
+    void render(const Frame& inputFrame, const Frame& outputFrame) {
+        ALOGI("SimpleRenderCallback::render");
+
+        if (inputFrame.data == nullptr || outputFrame.data == nullptr) {
+            ALOGE("Invalid frame data was passed to render callback");
+            return;
+        }
+
+        // TODO(b/130246434): Use OpenCV to implement a more meaningful
+        // callback.
+        // Swap the RGB channels.
+        int stride = inputFrame.stride;
+        uint8_t* inDataPtr = inputFrame.data;
+        uint8_t* outDataPtr = outputFrame.data;
+        for (int i = 0; i < inputFrame.width; i++)
+            for (int j = 0; j < inputFrame.height; j++) {
+                outDataPtr[(i + j * stride) * 4 + 0] =
+                    inDataPtr[(i + j * stride) * 4 + 1];
+                outDataPtr[(i + j * stride) * 4 + 1] =
+                    inDataPtr[(i + j * stride) * 4 + 2];
+                outDataPtr[(i + j * stride) * 4 + 2] =
+                    inDataPtr[(i + j * stride) * 4 + 0];
+                outDataPtr[(i + j * stride) * 4 + 3] =
+                    inDataPtr[(i + j * stride) * 4 + 3];
+            }
+    }
+};
+
+class SimpleAnalyzeCallback : public BaseAnalyzeCallback {
+    void analyze(const Frame &frame) {
+        ALOGD("SimpleAnalyzeCallback::analyze");
+        if (frame.data == nullptr) {
+            ALOGE("Invalid frame data was passed to analyze callback");
+            return;
+        }
+
+        // TODO(b/130246434): Now we just put a one second delay as a place
+        // holder. Replace it with an actual complicated enough algorithm.
+
+        ALOGD("SimpleAnalyzerCallback: sleep for one second");
+        std::this_thread::sleep_for(std::chrono::seconds(1));
+    };
+};
+
+// Main entry point
+int main() {
+    ALOGI("EVS app starting\n");
+
+    // Get the default rear view camera from evs support lib
+    std::string cameraId = Utils::getDefaultRearViewCameraId();
+    if (cameraId.empty()) {
+        ALOGE("Cannot find a valid camera");
+        return EXIT_FAILURE;
+    }
+
+    DisplayUseCase displayUseCase =
+        DisplayUseCase::createDefaultUseCase(cameraId, new SimpleRenderCallback());
+
+    AnalyzeUseCase analyzeUseCase =
+        AnalyzeUseCase::createDefaultUseCase(cameraId, new SimpleAnalyzeCallback());
+
+    // Run both DisplayUseCase and AnalyzeUseCase together for 10 seconds.
+    if (displayUseCase.startVideoStream()
+        && analyzeUseCase.startVideoStream()) {
+
+        std::this_thread::sleep_for(std::chrono::seconds(10));
+
+        displayUseCase.stopVideoStream();
+        analyzeUseCase.stopVideoStream();
+    }
+
+    // Run only AnalyzeUseCase for 10 seconds. The display control is back to
+    // Android framework but the camera is still occupied by AnalyzeUseCase in
+    // the background.
+    if (analyzeUseCase.startVideoStream()) {
+        std::this_thread::sleep_for(std::chrono::seconds(10));
+        analyzeUseCase.stopVideoStream();
+    }
+
+    return 0;
+}
diff --git a/evs/apps/demo_app_evs_support_lib/evs_app_support_lib.rc b/evs/apps/demo_app_evs_support_lib/evs_app_support_lib.rc
new file mode 100644
index 0000000..21f5961
--- /dev/null
+++ b/evs/apps/demo_app_evs_support_lib/evs_app_support_lib.rc
@@ -0,0 +1,6 @@
+service evs_app_support_lib /system/bin/evs_app_support_lib
+    class hal
+    priority -20
+    user automotive_evs
+    group automotive_evs
+    disabled # will not automatically start with its class; must be explictly started.
diff --git a/evs/manager/1.0/Android.bp b/evs/manager/1.0/Android.bp
new file mode 100644
index 0000000..82bcdd8
--- /dev/null
+++ b/evs/manager/1.0/Android.bp
@@ -0,0 +1,52 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+
+
+//#################################
+cc_binary {
+    name: "android.automotive.evs.manager@1.0",
+
+    srcs: [
+        "service.cpp",
+        "Enumerator.cpp",
+        "HalCamera.cpp",
+        "VirtualCamera.cpp",
+        "HalDisplay.cpp",
+    ],
+
+    shared_libs: [
+        "libcutils",
+        "liblog",
+        "libutils",
+        "libui",
+        "libhidlbase",
+        "libhardware",
+        "android.hardware.automotive.evs@1.0",
+    ],
+
+    init_rc: ["android.automotive.evs.manager@1.0.rc"],
+
+    cflags: ["-DLOG_TAG=\"EvsManagerV1_0\""] + [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+    ] + [
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+
+}
diff --git a/evs/manager/Enumerator.cpp b/evs/manager/1.0/Enumerator.cpp
similarity index 100%
rename from evs/manager/Enumerator.cpp
rename to evs/manager/1.0/Enumerator.cpp
diff --git a/evs/manager/Enumerator.h b/evs/manager/1.0/Enumerator.h
similarity index 100%
rename from evs/manager/Enumerator.h
rename to evs/manager/1.0/Enumerator.h
diff --git a/evs/manager/HalCamera.cpp b/evs/manager/1.0/HalCamera.cpp
similarity index 100%
rename from evs/manager/HalCamera.cpp
rename to evs/manager/1.0/HalCamera.cpp
diff --git a/evs/manager/HalCamera.h b/evs/manager/1.0/HalCamera.h
similarity index 100%
rename from evs/manager/HalCamera.h
rename to evs/manager/1.0/HalCamera.h
diff --git a/evs/manager/HalDisplay.cpp b/evs/manager/1.0/HalDisplay.cpp
similarity index 100%
rename from evs/manager/HalDisplay.cpp
rename to evs/manager/1.0/HalDisplay.cpp
diff --git a/evs/manager/HalDisplay.h b/evs/manager/1.0/HalDisplay.h
similarity index 100%
rename from evs/manager/HalDisplay.h
rename to evs/manager/1.0/HalDisplay.h
diff --git a/evs/manager/1.0/ServiceNames.h b/evs/manager/1.0/ServiceNames.h
new file mode 100644
index 0000000..bb03298
--- /dev/null
+++ b/evs/manager/1.0/ServiceNames.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// This is the name as which we'll register ourselves
+const static char kManagedEnumeratorName[] = "legacy_sw/0";
+
+// This is the name of the hardware provider to which we'll bind by default
+const static char kHardwareEnumeratorName[]  = "legacy_hw/0";
+
+// This is the name of the mock hardware provider selectable via command line.
+// (should match .../hardware/interfaces/automotive/evs/1.0/default/ServiceNames.h)
+const static char kMockEnumeratorName[]  = "EvsEnumeratorHw-Mock";
+
diff --git a/evs/manager/VirtualCamera.cpp b/evs/manager/1.0/VirtualCamera.cpp
similarity index 100%
rename from evs/manager/VirtualCamera.cpp
rename to evs/manager/1.0/VirtualCamera.cpp
diff --git a/evs/manager/VirtualCamera.h b/evs/manager/1.0/VirtualCamera.h
similarity index 100%
rename from evs/manager/VirtualCamera.h
rename to evs/manager/1.0/VirtualCamera.h
diff --git a/evs/manager/1.0/android.automotive.evs.manager@1.0.rc b/evs/manager/1.0/android.automotive.evs.manager@1.0.rc
new file mode 100644
index 0000000..fac4138
--- /dev/null
+++ b/evs/manager/1.0/android.automotive.evs.manager@1.0.rc
@@ -0,0 +1,7 @@
+service evs_manager_v1_0 /system/bin/android.automotive.evs.manager@1.0
+    class hal
+    priority -20
+    user automotive_evs
+    group automotive_evs
+    onrestart restart evs_app
+    disabled # will not automatically start with its class; must be explictly started.
diff --git a/evs/manager/service.cpp b/evs/manager/1.0/service.cpp
similarity index 100%
rename from evs/manager/service.cpp
rename to evs/manager/1.0/service.cpp
diff --git a/evs/manager/1.1/Android.bp b/evs/manager/1.1/Android.bp
new file mode 100644
index 0000000..891d615
--- /dev/null
+++ b/evs/manager/1.1/Android.bp
@@ -0,0 +1,79 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+
+
+//#################################
+cc_binary {
+    name: "android.automotive.evs.manager@1.1",
+
+    srcs: [
+        "Enumerator.cpp",
+        "HalCamera.cpp",
+        "HalDisplay.cpp",
+        "VirtualCamera.cpp",
+        "service.cpp",
+        "stats/CameraUsageStats.cpp",
+        "stats/LooperWrapper.cpp",
+        "stats/StatsCollector.cpp",
+        "sync/unique_fd.cpp",
+        "sync/unique_fence.cpp",
+        "sync/unique_timeline.cpp",
+    ],
+
+    shared_libs: [
+        "android.hardware.automotive.evs@1.0",
+        "android.hardware.automotive.evs@1.1",
+        "libbase",
+        "libcamera_metadata",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "libprocessgroup",
+        "libstatslog",
+        "libsync",
+        "libui",
+        "libutils",
+    ],
+
+    init_rc: ["android.automotive.evs.manager@1.1.rc"],
+
+    cflags: ["-DLOG_TAG=\"EvsManagerV1_1\""] + [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+        "-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS",
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+        "-Wthread-safety",
+    ],
+
+    include_dirs: [
+        "system/core/libsync",
+    ],
+
+    product_variables: {
+        debuggable: {
+            cflags: [
+                "-DEVS_DEBUG",
+            ]
+        }
+    },
+
+    vintf_fragments: [
+        "manifest_android.automotive.evs.manager@1.1.xml",
+    ],
+}
diff --git a/evs/manager/1.1/Enumerator.cpp b/evs/manager/1.1/Enumerator.cpp
new file mode 100644
index 0000000..fdf3500
--- /dev/null
+++ b/evs/manager/1.1/Enumerator.cpp
@@ -0,0 +1,858 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Enumerator.h"
+#include "HalDisplay.h"
+
+#include <android-base/chrono_utils.h>
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+#include <android-base/stringprintf.h>
+#include <cutils/android_filesystem_config.h>
+#include <hwbinder/IPCThreadState.h>
+
+namespace {
+
+    const char* kSingleIndent = "\t";
+    const char* kDumpOptionAll = "all";
+    const char* kDumpDeviceCamera = "camera";
+    const char* kDumpDeviceDisplay = "display";
+
+    const char* kDumpCameraCommandCurrent = "--current";
+    const char* kDumpCameraCommandCollected = "--collected";
+    const char* kDumpCameraCommandCustom = "--custom";
+    const char* kDumpCameraCommandCustomStart = "start";
+    const char* kDumpCameraCommandCustomStop = "stop";
+
+    const int kDumpCameraMinNumArgs = 4;
+    const int kOptionDumpDeviceTypeIndex = 1;
+    const int kOptionDumpCameraTypeIndex = 2;
+    const int kOptionDumpCameraCommandIndex = 3;
+    const int kOptionDumpCameraArgsStartIndex = 4;
+
+}
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::base::Error;
+using ::android::base::EqualsIgnoreCase;
+using ::android::base::StringAppendF;
+using ::android::base::StringPrintf;
+using ::android::base::WriteStringToFd;
+using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc;
+
+bool Enumerator::init(const char* hardwareServiceName) {
+    LOG(DEBUG) << "init";
+
+    // Connect with the underlying hardware enumerator
+    mHwEnumerator = IEvsEnumerator::getService(hardwareServiceName);
+    bool result = (mHwEnumerator.get() != nullptr);
+    if (result) {
+        // Get an internal display identifier.
+        mHwEnumerator->getDisplayIdList(
+            [this](const auto& displayPorts) {
+                for (auto& port : displayPorts) {
+                    mDisplayPorts.push_back(port);
+                }
+
+                // The first element is the internal display
+                mInternalDisplayPort = mDisplayPorts.front();
+                if (mDisplayPorts.size() < 1) {
+                    LOG(WARNING) << "No display is available to EVS service.";
+                }
+            }
+        );
+    }
+
+    // Starts the statistics collection
+    mMonitorEnabled = false;
+    mClientsMonitor = new StatsCollector();
+    if (mClientsMonitor != nullptr) {
+        auto result = mClientsMonitor->startCollection();
+        if (!result.ok()) {
+            LOG(ERROR) << "Failed to start the usage monitor: "
+                       << result.error();
+        } else {
+            mMonitorEnabled = true;
+        }
+    }
+
+    return result;
+}
+
+
+bool Enumerator::checkPermission() {
+    hardware::IPCThreadState *ipc = hardware::IPCThreadState::self();
+    const auto userId = ipc->getCallingUid() / AID_USER_OFFSET;
+    const auto appId = ipc->getCallingUid() % AID_USER_OFFSET;
+#ifdef EVS_DEBUG
+    if (AID_AUTOMOTIVE_EVS != appId && AID_ROOT != appId && AID_SYSTEM != appId) {
+#else
+    if (AID_AUTOMOTIVE_EVS != appId && AID_SYSTEM != appId) {
+#endif
+        LOG(ERROR) << "EVS access denied? "
+                   << "pid = " << ipc->getCallingPid()
+                   << ", userId = " << userId
+                   << ", appId = " << appId;
+        return false;
+    }
+
+    return true;
+}
+
+
+bool Enumerator::isLogicalCamera(const camera_metadata_t *metadata) {
+    bool found = false;
+
+    if (metadata == nullptr) {
+        LOG(ERROR) << "Metadata is null";
+        return found;
+    }
+
+    camera_metadata_ro_entry_t entry;
+    int rc = find_camera_metadata_ro_entry(metadata,
+                                           ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+                                           &entry);
+    if (0 != rc) {
+        // No capabilities are found in metadata.
+        LOG(DEBUG) << __FUNCTION__ << " does not find a target entry";
+        return found;
+    }
+
+    for (size_t i = 0; i < entry.count; ++i) {
+        uint8_t capability = entry.data.u8[i];
+        if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
+            found = true;
+            break;
+        }
+    }
+
+    if (!found) {
+        LOG(DEBUG) << __FUNCTION__ << " does not find a logical multi camera cap";
+    }
+    return found;
+}
+
+
+std::unordered_set<std::string> Enumerator::getPhysicalCameraIds(const std::string& id) {
+    std::unordered_set<std::string> physicalCameras;
+    if (mCameraDevices.find(id) == mCameraDevices.end()) {
+        LOG(ERROR) << "Queried device " << id << " does not exist!";
+        return physicalCameras;
+    }
+
+    const camera_metadata_t *metadata =
+        reinterpret_cast<camera_metadata_t *>(&mCameraDevices[id].metadata[0]);
+    if (!isLogicalCamera(metadata)) {
+        // EVS assumes that the device w/o a valid metadata is a physical
+        // device.
+        LOG(INFO) << id << " is not a logical camera device.";
+        physicalCameras.emplace(id);
+        return physicalCameras;
+    }
+
+    camera_metadata_ro_entry entry;
+    int rc = find_camera_metadata_ro_entry(metadata,
+                                           ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS,
+                                           &entry);
+    if (0 != rc) {
+        LOG(ERROR) << "No physical camera ID is found for a logical camera device " << id;
+        return physicalCameras;
+    }
+
+    const uint8_t *ids = entry.data.u8;
+    size_t start = 0;
+    for (size_t i = 0; i < entry.count; ++i) {
+        if (ids[i] == '\0') {
+            if (start != i) {
+                std::string id(reinterpret_cast<const char *>(ids + start));
+                physicalCameras.emplace(id);
+            }
+            start = i + 1;
+        }
+    }
+
+    LOG(INFO) << id << " consists of "
+               << physicalCameras.size() << " physical camera devices.";
+    return physicalCameras;
+}
+
+
+// Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
+Return<void> Enumerator::getCameraList(getCameraList_cb list_cb)  {
+    hardware::hidl_vec<CameraDesc_1_0> cameraList;
+    mHwEnumerator->getCameraList_1_1([&cameraList](auto cameraList_1_1) {
+        cameraList.resize(cameraList_1_1.size());
+        unsigned i = 0;
+        for (auto&& cam : cameraList_1_1) {
+            cameraList[i++] = cam.v1;
+        }
+    });
+
+    list_cb(cameraList);
+
+    return Void();
+}
+
+
+Return<sp<IEvsCamera_1_0>> Enumerator::openCamera(const hidl_string& cameraId) {
+    LOG(DEBUG) << __FUNCTION__;
+    if (!checkPermission()) {
+        return nullptr;
+    }
+
+    // Is the underlying hardware camera already open?
+    sp<HalCamera> hwCamera;
+    if (mActiveCameras.find(cameraId) != mActiveCameras.end()) {
+        hwCamera = mActiveCameras[cameraId];
+    } else {
+        // Is the hardware camera available?
+        sp<IEvsCamera_1_1> device =
+            IEvsCamera_1_1::castFrom(mHwEnumerator->openCamera(cameraId))
+            .withDefault(nullptr);
+        if (device == nullptr) {
+            LOG(ERROR) << "Failed to open hardware camera " << cameraId;
+        } else {
+            // Calculates the usage statistics record identifier
+            auto fn = mCameraDevices.hash_function();
+            auto recordId = fn(cameraId) & 0xFF;
+            hwCamera = new HalCamera(device, cameraId, recordId);
+            if (hwCamera == nullptr) {
+                LOG(ERROR) << "Failed to allocate camera wrapper object";
+                mHwEnumerator->closeCamera(device);
+            }
+        }
+    }
+
+    // Construct a virtual camera wrapper for this hardware camera
+    sp<VirtualCamera> clientCamera;
+    if (hwCamera != nullptr) {
+        clientCamera = hwCamera->makeVirtualCamera();
+    }
+
+    // Add the hardware camera to our list, which will keep it alive via ref count
+    if (clientCamera != nullptr) {
+        mActiveCameras.try_emplace(cameraId, hwCamera);
+    } else {
+        LOG(ERROR) << "Requested camera " << cameraId
+                   << " not found or not available";
+    }
+
+    // Send the virtual camera object back to the client by strong pointer which will keep it alive
+    return clientCamera;
+}
+
+
+Return<void> Enumerator::closeCamera(const ::android::sp<IEvsCamera_1_0>& clientCamera) {
+    LOG(DEBUG) << __FUNCTION__;
+
+    if (clientCamera.get() == nullptr) {
+        LOG(ERROR) << "Ignoring call with null camera pointer.";
+        return Void();
+    }
+
+    // All our client cameras are actually VirtualCamera objects
+    sp<VirtualCamera> virtualCamera = reinterpret_cast<VirtualCamera *>(clientCamera.get());
+
+    // Find the parent camera that backs this virtual camera
+    for (auto&& halCamera : virtualCamera->getHalCameras()) {
+        // Tell the virtual camera's parent to clean it up and drop it
+        // NOTE:  The camera objects will only actually destruct when the sp<> ref counts get to
+        //        zero, so it is important to break all cyclic references.
+        halCamera->disownVirtualCamera(virtualCamera);
+
+        // Did we just remove the last client of this camera?
+        if (halCamera->getClientCount() == 0) {
+            // Take this now unused camera out of our list
+            // NOTE:  This should drop our last reference to the camera, resulting in its
+            //        destruction.
+            mActiveCameras.erase(halCamera->getId());
+            if (mMonitorEnabled) {
+                mClientsMonitor->unregisterClientToMonitor(halCamera->getId());
+            }
+        }
+    }
+
+    // Make sure the virtual camera's stream is stopped
+    virtualCamera->stopVideoStream();
+
+    return Void();
+}
+
+
+// Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
+Return<sp<IEvsCamera_1_1>> Enumerator::openCamera_1_1(const hidl_string& cameraId,
+                                                      const Stream& streamCfg) {
+    LOG(DEBUG) << __FUNCTION__;
+    if (!checkPermission()) {
+        return nullptr;
+    }
+
+    // If hwCamera is null, a requested camera device is either a logical camera
+    // device or a hardware camera, which is not being used now.
+    std::unordered_set<std::string> physicalCameras = getPhysicalCameraIds(cameraId);
+    std::vector<sp<HalCamera>> sourceCameras;
+    sp<HalCamera> hwCamera;
+    bool success = true;
+
+    // 1. Try to open inactive camera devices.
+    for (auto&& id : physicalCameras) {
+        auto it = mActiveCameras.find(id);
+        if (it == mActiveCameras.end()) {
+            // Try to open a hardware camera.
+            sp<IEvsCamera_1_1> device =
+                IEvsCamera_1_1::castFrom(mHwEnumerator->openCamera_1_1(id, streamCfg))
+                .withDefault(nullptr);
+            if (device == nullptr) {
+                LOG(ERROR) << "Failed to open hardware camera " << cameraId;
+                success = false;
+                break;
+            } else {
+                // Calculates the usage statistics record identifier
+                auto fn = mCameraDevices.hash_function();
+                auto recordId = fn(id) & 0xFF;
+                hwCamera = new HalCamera(device, id, recordId, streamCfg);
+                if (hwCamera == nullptr) {
+                    LOG(ERROR) << "Failed to allocate camera wrapper object";
+                    mHwEnumerator->closeCamera(device);
+                    success = false;
+                    break;
+                } else if (!hwCamera->isSyncSupported()) {
+                    LOG(INFO) << id << " does not support a sw_sync.";
+                    if (physicalCameras.size() > 1) {
+                        LOG(ERROR) << "sw_sync is required for logical camera devices.";
+                        success = false;
+                        break;
+                    }
+                }
+            }
+
+            // Add the hardware camera to our list, which will keep it alive via ref count
+            mActiveCameras.try_emplace(id, hwCamera);
+            if (mMonitorEnabled) {
+                mClientsMonitor->registerClientToMonitor(hwCamera);
+            }
+
+            sourceCameras.push_back(hwCamera);
+        } else {
+            if (it->second->getStreamConfig().id != streamCfg.id) {
+                LOG(WARNING) << "Requested camera is already active in different configuration.";
+            } else {
+                sourceCameras.push_back(it->second);
+            }
+        }
+    }
+
+    if (!success || sourceCameras.size() < 1) {
+        LOG(ERROR) << "Failed to open any physical camera device";
+        return nullptr;
+    }
+
+    // TODO(b/147170360): Implement a logic to handle a failure.
+    // 3. Create a proxy camera object
+    sp<VirtualCamera> clientCamera = new VirtualCamera(sourceCameras);
+    if (clientCamera == nullptr) {
+        // TODO: Any resource needs to be cleaned up explicitly?
+        LOG(ERROR) << "Failed to create a client camera object";
+    } else {
+        if (physicalCameras.size() > 1) {
+            // VirtualCamera, which represents a logical device, caches its
+            // descriptor.
+            clientCamera->setDescriptor(&mCameraDevices[cameraId]);
+        }
+
+        // 4. Owns created proxy camera object
+        for (auto&& hwCamera : sourceCameras) {
+            if (!hwCamera->ownVirtualCamera(clientCamera)) {
+                // TODO: Remove a referece to this camera from a virtual camera
+                // object.
+                LOG(ERROR) << hwCamera->getId()
+                           << " failed to own a created proxy camera object.";
+            }
+        }
+    }
+
+    // Send the virtual camera object back to the client by strong pointer which will keep it alive
+    return clientCamera;
+}
+
+
+Return<void> Enumerator::getCameraList_1_1(getCameraList_1_1_cb list_cb)  {
+    LOG(DEBUG) << __FUNCTION__;
+    if (!checkPermission()) {
+        return Void();
+    }
+
+    hardware::hidl_vec<CameraDesc_1_1> hidlCameras;
+    mHwEnumerator->getCameraList_1_1(
+        [&hidlCameras](hardware::hidl_vec<CameraDesc_1_1> enumeratedCameras) {
+            hidlCameras.resize(enumeratedCameras.size());
+            unsigned count = 0;
+            for (auto&& camdesc : enumeratedCameras) {
+                hidlCameras[count++] = camdesc;
+            }
+        }
+    );
+
+    // Update the cached device list
+    mCameraDevices.clear();
+    for (auto&& desc : hidlCameras) {
+        mCameraDevices.insert_or_assign(desc.v1.cameraId, desc);
+    }
+
+    list_cb(hidlCameras);
+    return Void();
+}
+
+
+Return<sp<IEvsDisplay_1_0>> Enumerator::openDisplay() {
+    LOG(DEBUG) << __FUNCTION__;
+
+    if (!checkPermission()) {
+        return nullptr;
+    }
+
+    // We simply keep track of the most recently opened display instance.
+    // In the underlying layers we expect that a new open will cause the previous
+    // object to be destroyed.  This avoids any race conditions associated with
+    // create/destroy order and provides a cleaner restart sequence if the previous owner
+    // is non-responsive for some reason.
+    // Request exclusive access to the EVS display
+    sp<IEvsDisplay_1_0> pActiveDisplay = mHwEnumerator->openDisplay();
+    if (pActiveDisplay == nullptr) {
+        LOG(ERROR) << "EVS Display unavailable";
+
+        return nullptr;
+    }
+
+    // Remember (via weak pointer) who we think the most recently opened display is so that
+    // we can proxy state requests from other callers to it.
+    // TODO: Because of b/129284474, an additional class, HalDisplay, has been defined and
+    // wraps the IEvsDisplay object the driver returns.  We may want to remove this
+    // additional class when it is fixed properly.
+    sp<IEvsDisplay_1_0> pHalDisplay = new HalDisplay(pActiveDisplay, mInternalDisplayPort);
+    mActiveDisplay = pHalDisplay;
+
+    return pHalDisplay;
+}
+
+
+Return<void> Enumerator::closeDisplay(const ::android::sp<IEvsDisplay_1_0>& display) {
+    LOG(DEBUG) << __FUNCTION__;
+
+    sp<IEvsDisplay_1_0> pActiveDisplay = mActiveDisplay.promote();
+
+    // Drop the active display
+    if (display.get() != pActiveDisplay.get()) {
+        LOG(WARNING) << "Ignoring call to closeDisplay with unrecognized display object.";
+    } else {
+        // Pass this request through to the hardware layer
+        sp<HalDisplay> halDisplay = reinterpret_cast<HalDisplay *>(pActiveDisplay.get());
+        mHwEnumerator->closeDisplay(halDisplay->getHwDisplay());
+        mActiveDisplay = nullptr;
+    }
+
+    return Void();
+}
+
+
+Return<EvsDisplayState> Enumerator::getDisplayState()  {
+    LOG(DEBUG) << __FUNCTION__;
+    if (!checkPermission()) {
+        return EvsDisplayState::DEAD;
+    }
+
+    // Do we have a display object we think should be active?
+    sp<IEvsDisplay_1_0> pActiveDisplay = mActiveDisplay.promote();
+    if (pActiveDisplay != nullptr) {
+        // Pass this request through to the hardware layer
+        return pActiveDisplay->getDisplayState();
+    } else {
+        // We don't have a live display right now
+        mActiveDisplay = nullptr;
+        return EvsDisplayState::NOT_OPEN;
+    }
+}
+
+
+Return<sp<IEvsDisplay_1_1>> Enumerator::openDisplay_1_1(uint8_t id) {
+    LOG(DEBUG) << __FUNCTION__;
+
+    if (!checkPermission()) {
+        return nullptr;
+    }
+
+    if (std::find(mDisplayPorts.begin(), mDisplayPorts.end(), id) == mDisplayPorts.end()) {
+        LOG(ERROR) << "No display is available on the port " << static_cast<int32_t>(id);
+        return nullptr;
+    }
+
+    // We simply keep track of the most recently opened display instance.
+    // In the underlying layers we expect that a new open will cause the previous
+    // object to be destroyed.  This avoids any race conditions associated with
+    // create/destroy order and provides a cleaner restart sequence if the previous owner
+    // is non-responsive for some reason.
+    // Request exclusive access to the EVS display
+    sp<IEvsDisplay_1_1> pActiveDisplay = mHwEnumerator->openDisplay_1_1(id);
+    if (pActiveDisplay == nullptr) {
+        LOG(ERROR) << "EVS Display unavailable";
+
+        return nullptr;
+    }
+
+    // Remember (via weak pointer) who we think the most recently opened display is so that
+    // we can proxy state requests from other callers to it.
+    // TODO: Because of b/129284474, an additional class, HalDisplay, has been defined and
+    // wraps the IEvsDisplay object the driver returns.  We may want to remove this
+    // additional class when it is fixed properly.
+    sp<IEvsDisplay_1_1> pHalDisplay = new HalDisplay(pActiveDisplay, id);
+    mActiveDisplay = pHalDisplay;
+
+    return pHalDisplay;
+}
+
+
+Return<void> Enumerator::getDisplayIdList(getDisplayIdList_cb _list_cb)  {
+    return mHwEnumerator->getDisplayIdList(_list_cb);
+}
+
+
+// TODO(b/149874793): Add implementation for EVS Manager and Sample driver
+Return<void> Enumerator::getUltrasonicsArrayList(getUltrasonicsArrayList_cb _hidl_cb) {
+    hardware::hidl_vec<UltrasonicsArrayDesc> ultrasonicsArrayDesc;
+    _hidl_cb(ultrasonicsArrayDesc);
+    return Void();
+}
+
+
+// TODO(b/149874793): Add implementation for EVS Manager and Sample driver
+Return<sp<IEvsUltrasonicsArray>> Enumerator::openUltrasonicsArray(
+        const hidl_string& ultrasonicsArrayId) {
+    (void)ultrasonicsArrayId;
+    sp<IEvsUltrasonicsArray> pEvsUltrasonicsArray;
+    return pEvsUltrasonicsArray;
+}
+
+
+// TODO(b/149874793): Add implementation for EVS Manager and Sample driver
+Return<void> Enumerator::closeUltrasonicsArray(
+        const ::android::sp<IEvsUltrasonicsArray>& evsUltrasonicsArray)  {
+    (void)evsUltrasonicsArray;
+    return Void();
+}
+
+
+Return<void> Enumerator::debug(const hidl_handle& fd,
+                               const hidl_vec<hidl_string>& options) {
+    if (fd.getNativeHandle() != nullptr && fd->numFds > 0) {
+        cmdDump(fd->data[0], options);
+    } else {
+        LOG(ERROR) << "Given file descriptor is not valid.";
+    }
+
+    return {};
+}
+
+
+void Enumerator::cmdDump(int fd, const hidl_vec<hidl_string>& options) {
+    if (options.size() == 0) {
+        WriteStringToFd("No option is given.\n", fd);
+        cmdHelp(fd);
+        return;
+    }
+
+    const std::string option = options[0];
+    if (EqualsIgnoreCase(option, "--help")) {
+        cmdHelp(fd);
+    } else if (EqualsIgnoreCase(option, "--list")) {
+        cmdList(fd, options);
+    } else if (EqualsIgnoreCase(option, "--dump")) {
+        cmdDumpDevice(fd, options);
+    } else {
+        WriteStringToFd(StringPrintf("Invalid option: %s\n", option.c_str()),
+                        fd);
+    }
+}
+
+
+void Enumerator::cmdHelp(int fd) {
+    WriteStringToFd("--help: shows this help.\n"
+                    "--list [all|camera|display]: lists camera or display devices or both "
+                    "available to EVS manager.\n"
+                    "--dump camera [all|device_id] --[current|collected|custom] [args]\n"
+                    "\tcurrent: shows the current status\n"
+                    "\tcollected: shows 10 most recent periodically collected camera usage "
+                    "statistics\n"
+                    "\tcustom: starts/stops collecting the camera usage statistics\n"
+                    "\t\tstart [interval] [duration]: starts collecting usage statistics "
+                    "at every [interval] during [duration].  Interval and duration are in "
+                    "milliseconds.\n"
+                    "\t\tstop: stops collecting usage statistics and shows collected records.\n"
+                    "--dump display: shows current status of the display\n", fd);
+}
+
+
+void Enumerator::cmdList(int fd, const hidl_vec<hidl_string>& options) {
+    bool listCameras = true;
+    bool listDisplays = true;
+    if (options.size() > 1) {
+        const std::string option = options[1];
+        const bool listAll = EqualsIgnoreCase(option, kDumpOptionAll);
+        listCameras = listAll || EqualsIgnoreCase(option, kDumpDeviceCamera);
+        listDisplays = listAll || EqualsIgnoreCase(option, kDumpDeviceDisplay);
+        if (!listCameras && !listDisplays) {
+            WriteStringToFd(StringPrintf("Unrecognized option, %s, is ignored.\n",
+                                         option.c_str()),
+                            fd);
+
+            // Nothing to show, return
+            return;
+        }
+    }
+
+    std::string buffer;
+    if (listCameras) {
+        StringAppendF(&buffer,"Camera devices available to EVS service:\n");
+        if (mCameraDevices.size() < 1) {
+            // Camera devices may not be enumerated yet.  This may fail if the
+            // user is not permitted to use EVS service.
+            getCameraList_1_1(
+                [](const auto cameras) {
+                    if (cameras.size() < 1) {
+                        LOG(WARNING) << "No camera device is available to EVS.";
+                    }
+                });
+        }
+
+        for (auto& [id, desc] : mCameraDevices) {
+            StringAppendF(&buffer, "%s%s\n", kSingleIndent, id.c_str());
+        }
+
+        StringAppendF(&buffer, "%sCamera devices currently in use:\n", kSingleIndent);
+        for (auto& [id, ptr] : mActiveCameras) {
+            StringAppendF(&buffer, "%s%s\n", kSingleIndent, id.c_str());
+        }
+        StringAppendF(&buffer, "\n");
+    }
+
+    if (listDisplays) {
+        if (mHwEnumerator != nullptr) {
+            StringAppendF(&buffer, "Display devices available to EVS service:\n");
+            // Get an internal display identifier.
+            mHwEnumerator->getDisplayIdList(
+                [&](const auto& displayPorts) {
+                    for (auto&& port : displayPorts) {
+                        StringAppendF(&buffer, "%sdisplay port %u\n",
+                                               kSingleIndent,
+                                               static_cast<unsigned>(port));
+                    }
+                }
+            );
+        } else {
+            LOG(WARNING) << "EVS HAL implementation is not available.";
+        }
+    }
+
+    WriteStringToFd(buffer, fd);
+}
+
+
+void Enumerator::cmdDumpDevice(int fd, const hidl_vec<hidl_string>& options) {
+    // Dumps both cameras and displays if the target device type is not given
+    bool dumpCameras = false;
+    bool dumpDisplays = false;
+    const auto numOptions = options.size();
+    if (numOptions > kOptionDumpDeviceTypeIndex) {
+        const std::string target = options[kOptionDumpDeviceTypeIndex];
+        dumpCameras = EqualsIgnoreCase(target, kDumpDeviceCamera);
+        dumpDisplays = EqualsIgnoreCase(target, kDumpDeviceDisplay);
+        if (!dumpCameras && !dumpDisplays) {
+            WriteStringToFd(StringPrintf("Unrecognized option, %s, is ignored.\n",
+                                         target.c_str()),
+                            fd);
+            cmdHelp(fd);
+            return;
+        }
+    } else {
+        WriteStringToFd(StringPrintf("Necessary arguments are missing.  "
+                                     "Please check the usages:\n"),
+                        fd);
+        cmdHelp(fd);
+        return;
+    }
+
+    if (dumpCameras) {
+        // --dump camera [all|device_id] --[current|collected|custom] [args]
+        if (numOptions < kDumpCameraMinNumArgs) {
+            WriteStringToFd(StringPrintf("Necessary arguments are missing.  "
+                                         "Please check the usages:\n"),
+                            fd);
+            cmdHelp(fd);
+            return;
+        }
+
+        const std::string deviceId = options[kOptionDumpCameraTypeIndex];
+        auto target = mActiveCameras.find(deviceId);
+        const bool dumpAllCameras = EqualsIgnoreCase(deviceId,
+                                                     kDumpOptionAll);
+        if (!dumpAllCameras && target == mActiveCameras.end()) {
+            // Unknown camera identifier
+            WriteStringToFd(StringPrintf("Given camera ID %s is unknown or not active.\n",
+                                         deviceId.c_str()),
+                            fd);
+            return;
+        }
+
+        const std::string command = options[kOptionDumpCameraCommandIndex];
+        std::string cameraInfo;
+        if (EqualsIgnoreCase(command, kDumpCameraCommandCurrent)) {
+            // Active stream configuration from each active HalCamera objects
+            if (!dumpAllCameras) {
+                StringAppendF(&cameraInfo, "HalCamera: %s\n%s",
+                                           deviceId.c_str(),
+                                           target->second->toString(kSingleIndent).c_str());
+            } else {
+                for (auto&& [id, handle] : mActiveCameras) {
+                    // Appends the current status
+                    cameraInfo += handle->toString(kSingleIndent);
+                }
+            }
+        } else if (EqualsIgnoreCase(command, kDumpCameraCommandCollected)) {
+            // Reads the usage statistics from active HalCamera objects
+            std::unordered_map<std::string, std::string> usageStrings;
+            if (mMonitorEnabled) {
+                auto result = mClientsMonitor->toString(&usageStrings, kSingleIndent);
+                if (!result.ok()) {
+                    LOG(ERROR) << "Failed to get the monitoring result";
+                    return;
+                }
+
+                if (!dumpAllCameras) {
+                    cameraInfo += usageStrings[deviceId];
+                } else {
+                    for (auto&& [id, stats] : usageStrings) {
+                        cameraInfo += stats;
+                    }
+                }
+            } else {
+                WriteStringToFd(StringPrintf("Client monitor is not available.\n"),
+                                fd);
+                return;
+            }
+        } else if (EqualsIgnoreCase(command, kDumpCameraCommandCustom)) {
+            // Additional arguments are expected for this command:
+            // --dump camera device_id --custom start [interval] [duration]
+            // or, --dump camera device_id --custom stop
+            if (numOptions < kDumpCameraMinNumArgs + 1) {
+                WriteStringToFd(StringPrintf("Necessary arguments are missing. "
+                                             "Please check the usages:\n"),
+                                fd);
+                cmdHelp(fd);
+                return;
+            }
+
+            if (!mMonitorEnabled) {
+                WriteStringToFd(StringPrintf("Client monitor is not available."), fd);
+                return;
+            }
+
+            const std::string subcommand = options[kOptionDumpCameraArgsStartIndex];
+            if (EqualsIgnoreCase(subcommand, kDumpCameraCommandCustomStart)) {
+                using std::chrono::nanoseconds;
+                using std::chrono::milliseconds;
+                using std::chrono::duration_cast;
+                nanoseconds interval = 0ns;
+                nanoseconds duration = 0ns;
+                if (numOptions > kOptionDumpCameraArgsStartIndex + 2) {
+                    duration = duration_cast<nanoseconds>(
+                            milliseconds(
+                                    std::stoi(options[kOptionDumpCameraArgsStartIndex + 2])
+                            ));
+                }
+
+                if (numOptions > kOptionDumpCameraArgsStartIndex + 1) {
+                    interval = duration_cast<nanoseconds>(
+                            milliseconds(
+                                    std::stoi(options[kOptionDumpCameraArgsStartIndex + 1])
+                            ));
+                }
+
+                // Starts a custom collection
+                auto result = mClientsMonitor->startCustomCollection(interval, duration);
+                if (!result) {
+                    LOG(ERROR) << "Failed to start a custom collection.  "
+                               << result.error();
+                    StringAppendF(&cameraInfo, "Failed to start a custom collection. %s\n",
+                                               result.error().message().c_str());
+                }
+            } else if (EqualsIgnoreCase(subcommand, kDumpCameraCommandCustomStop)) {
+                if (!mMonitorEnabled) {
+                    WriteStringToFd(StringPrintf("Client monitor is not available."), fd);
+                    return;
+                }
+
+                auto result = mClientsMonitor->stopCustomCollection(deviceId);
+                if (!result) {
+                    LOG(ERROR) << "Failed to stop a custom collection.  "
+                               << result.error();
+                    StringAppendF(&cameraInfo, "Failed to stop a custom collection. %s\n",
+                                               result.error().message().c_str());
+                } else {
+                    // Pull the custom collection
+                    cameraInfo += *result;
+                }
+            } else {
+                WriteStringToFd(StringPrintf("Unknown argument: %s\n",
+                                             subcommand.c_str()),
+                                fd);
+                cmdHelp(fd);
+                return;
+            }
+        } else {
+            WriteStringToFd(StringPrintf("Unknown command: %s\n"
+                                         "Please check the usages:\n", command.c_str()),
+                            fd);
+            cmdHelp(fd);
+            return;
+        }
+
+        // Outputs the report
+        WriteStringToFd(cameraInfo, fd);
+    }
+
+    if (dumpDisplays) {
+        HalDisplay* pDisplay =
+            reinterpret_cast<HalDisplay*>(mActiveDisplay.promote().get());
+        if (!pDisplay) {
+            WriteStringToFd("No active display is found.\n", fd);
+        } else {
+            WriteStringToFd(pDisplay->toString(kSingleIndent), fd);
+        }
+    }
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace android
diff --git a/evs/manager/1.1/Enumerator.h b/evs/manager/1.1/Enumerator.h
new file mode 100644
index 0000000..7708295
--- /dev/null
+++ b/evs/manager/1.1/Enumerator.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
+#define ANDROID_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
+
+#include "HalCamera.h"
+#include "VirtualCamera.h"
+#include "stats/StatsCollector.h"
+
+#include <list>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <system/camera_metadata.h>
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+using ::android::hardware::Return;
+using ::android::hardware::hidl_string;
+using ::android::hardware::camera::device::V3_2::Stream;
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+using IEvsCamera_1_0     = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
+using IEvsCamera_1_1     = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+using IEvsEnumerator_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsEnumerator;
+using IEvsEnumerator_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsEnumerator;
+using IEvsDisplay_1_0    = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using IEvsDisplay_1_1    = ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
+using EvsDisplayState    = ::android::hardware::automotive::evs::V1_0::DisplayState;
+
+class Enumerator : public IEvsEnumerator {
+public:
+    // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
+    Return<void>                getCameraList(getCameraList_cb _hidl_cb)  override;
+    Return<sp<IEvsCamera_1_0>>  openCamera(const hidl_string& cameraId)  override;
+    Return<void>                closeCamera(const ::android::sp<IEvsCamera_1_0>& virtualCamera)  override;
+    Return<sp<IEvsDisplay_1_0>> openDisplay()  override;
+    Return<void>                closeDisplay(const ::android::sp<IEvsDisplay_1_0>& display)  override;
+    Return<EvsDisplayState>     getDisplayState()  override;
+
+    // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
+    Return<void>                getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) override;
+    Return<sp<IEvsCamera_1_1>>  openCamera_1_1(const hidl_string& cameraId,
+                                               const Stream& streamCfg) override;
+    Return<bool>                isHardware() override { return false; }
+    Return<void>                getDisplayIdList(getDisplayIdList_cb _list_cb) override;
+    Return<sp<IEvsDisplay_1_1>> openDisplay_1_1(uint8_t id) override;
+    Return<void> getUltrasonicsArrayList(getUltrasonicsArrayList_cb _hidl_cb) override;
+    Return<sp<IEvsUltrasonicsArray>> openUltrasonicsArray(
+            const hidl_string& ultrasonicsArrayId) override;
+    Return<void> closeUltrasonicsArray(
+            const ::android::sp<IEvsUltrasonicsArray>& evsUltrasonicsArray) override;
+
+    // Methods from ::android.hidl.base::V1_0::IBase follow.
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
+
+    // Implementation details
+    bool init(const char* hardwareServiceName);
+
+private:
+    bool inline                     checkPermission();
+    bool                            isLogicalCamera(const camera_metadata_t *metadata);
+    std::unordered_set<std::string> getPhysicalCameraIds(const std::string& id);
+
+    sp<IEvsEnumerator_1_1>            mHwEnumerator;  // Hardware enumerator
+    wp<IEvsDisplay_1_0>               mActiveDisplay; // Display proxy object warpping hw display
+
+    // List of active camera proxy objects that wrap hw cameras
+    std::unordered_map<std::string,
+                       sp<HalCamera>> mActiveCameras;
+
+    // List of camera descriptors of enumerated hw cameras
+    std::unordered_map<std::string,
+                       CameraDesc>    mCameraDevices;
+
+    // List of available physical display devices
+    std::list<uint8_t>                mDisplayPorts;
+
+    // Display port the internal display is connected to.
+    uint8_t                           mInternalDisplayPort;
+
+    // Collecting camera usage statistics from clients
+    sp<StatsCollector>                mClientsMonitor;
+
+    // Boolean flag to tell whether the camera usages are being monitored or not
+    bool                              mMonitorEnabled;
+
+    // LSHAL dump
+    void cmdDump(int fd, const hidl_vec<hidl_string>& options);
+    void cmdHelp(int fd);
+    void cmdList(int fd, const hidl_vec<hidl_string>& options);
+    void cmdDumpDevice(int fd, const hidl_vec<hidl_string>& options);
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace android
+
+#endif  // ANDROID_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
diff --git a/evs/manager/1.1/HalCamera.cpp b/evs/manager/1.1/HalCamera.cpp
new file mode 100644
index 0000000..38297bb
--- /dev/null
+++ b/evs/manager/1.1/HalCamera.cpp
@@ -0,0 +1,665 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Enumerator.h"
+#include "HalCamera.h"
+#include "VirtualCamera.h"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+// TODO(changyeon):
+// We need to hook up death monitoring to detect stream death so we can attempt a reconnect
+
+using ::android::base::StringAppendF;
+using ::android::base::WriteStringToFd;
+
+HalCamera::~HalCamera() {
+    // Reports the usage statistics before the destruction
+    // EvsUsageStatsReported atom is defined in
+    // frameworks/base/cmds/statsd/src/atoms.proto
+    mUsageStats->writeStats();
+}
+
+sp<VirtualCamera> HalCamera::makeVirtualCamera() {
+
+    // Create the client camera interface object
+    std::vector<sp<HalCamera>> sourceCameras;
+    sourceCameras.reserve(1);
+    sourceCameras.emplace_back(this);
+    sp<VirtualCamera> client = new VirtualCamera(sourceCameras);
+    if (client == nullptr) {
+        LOG(ERROR) << "Failed to create client camera object";
+        return nullptr;
+    }
+
+    if (!ownVirtualCamera(client)) {
+        LOG(ERROR) << "Failed to own a client camera object";
+        client = nullptr;
+    }
+
+    return client;
+}
+
+
+bool HalCamera::ownVirtualCamera(sp<VirtualCamera> virtualCamera) {
+
+    if (virtualCamera == nullptr) {
+        LOG(ERROR) << "Failed to create virtualCamera camera object";
+        return false;
+    }
+
+    // Make sure we have enough buffers available for all our clients
+    if (!changeFramesInFlight(virtualCamera->getAllowedBuffers())) {
+        // Gah!  We couldn't get enough buffers, so we can't support this virtualCamera
+        // Null the pointer, dropping our reference, thus destroying the virtualCamera object
+        return false;
+    }
+
+    if (mSyncSupported) {
+        // Create a timeline
+        std::lock_guard<std::mutex> lock(mFrameMutex);
+        auto timeline = make_unique<UniqueTimeline>(0);
+        if (timeline != nullptr) {
+            mTimelines[(uint64_t)virtualCamera.get()] = std::move(timeline);
+        } else {
+            LOG(WARNING) << "Failed to create a timeline. "
+                         << "Client " << std::hex << virtualCamera.get()
+                         << " will use v1.0 frame delivery mechanism.";
+        }
+    }
+
+    // Add this virtualCamera to our ownership list via weak pointer
+    mClients.emplace_back(virtualCamera);
+
+    // Update statistics
+    mUsageStats->updateNumClients(mClients.size());
+
+    return true;
+}
+
+
+void HalCamera::disownVirtualCamera(sp<VirtualCamera> virtualCamera) {
+    // Ignore calls with null pointers
+    if (virtualCamera.get() == nullptr) {
+        LOG(WARNING) << "Ignoring disownVirtualCamera call with null pointer";
+        return;
+    }
+
+    // Remove the virtual camera from our client list
+    unsigned clientCount = mClients.size();
+    mClients.remove(virtualCamera);
+    if (clientCount != mClients.size() + 1) {
+        LOG(ERROR) << "Couldn't find camera in our client list to remove it";
+    }
+
+    // Recompute the number of buffers required with the target camera removed from the list
+    if (!changeFramesInFlight(0)) {
+        LOG(ERROR) << "Error when trying to reduce the in flight buffer count";
+    }
+
+    // Update statistics
+    mUsageStats->updateNumClients(mClients.size());
+}
+
+
+bool HalCamera::changeFramesInFlight(int delta) {
+    // Walk all our clients and count their currently required frames
+    unsigned bufferCount = 0;
+    for (auto&& client :  mClients) {
+        sp<VirtualCamera> virtCam = client.promote();
+        if (virtCam != nullptr) {
+            bufferCount += virtCam->getAllowedBuffers();
+        }
+    }
+
+    // Add the requested delta
+    bufferCount += delta;
+
+    // Never drop below 1 buffer -- even if all client cameras get closed
+    if (bufferCount < 1) {
+        bufferCount = 1;
+    }
+
+    // Ask the hardware for the resulting buffer count
+    Return<EvsResult> result = mHwCamera->setMaxFramesInFlight(bufferCount);
+    bool success = (result.isOk() && result == EvsResult::OK);
+
+    // Update the size of our array of outstanding frame records
+    if (success) {
+        std::vector<FrameRecord> newRecords;
+        newRecords.reserve(bufferCount);
+
+        // Copy and compact the old records that are still active
+        for (const auto& rec : mFrames) {
+            if (rec.refCount > 0) {
+                newRecords.emplace_back(rec);
+            }
+        }
+        if (newRecords.size() > (unsigned)bufferCount) {
+            LOG(WARNING) << "We found more frames in use than requested.";
+        }
+
+        mFrames.swap(newRecords);
+    }
+
+    return success;
+}
+
+
+bool HalCamera::changeFramesInFlight(const hidl_vec<BufferDesc_1_1>& buffers,
+                                     int* delta) {
+    // Return immediately if a list is empty.
+    if (buffers.size() < 1) {
+        LOG(DEBUG) << "No external buffers to add.";
+        return true;
+    }
+
+    // Walk all our clients and count their currently required frames
+    auto bufferCount = 0;
+    for (auto&& client :  mClients) {
+        sp<VirtualCamera> virtCam = client.promote();
+        if (virtCam != nullptr) {
+            bufferCount += virtCam->getAllowedBuffers();
+        }
+    }
+
+    EvsResult status = EvsResult::OK;
+    // Ask the hardware for the resulting buffer count
+    mHwCamera->importExternalBuffers(buffers,
+                                     [&](auto result, auto added) {
+                                         status = result;
+                                         *delta = added;
+                                     });
+    if (status != EvsResult::OK) {
+        LOG(ERROR) << "Failed to add external capture buffers.";
+        return false;
+    }
+
+    bufferCount += *delta;
+
+    // Update the size of our array of outstanding frame records
+    std::vector<FrameRecord> newRecords;
+    newRecords.reserve(bufferCount);
+
+    // Copy and compact the old records that are still active
+    for (const auto& rec : mFrames) {
+        if (rec.refCount > 0) {
+            newRecords.emplace_back(rec);
+        }
+    }
+
+    if (newRecords.size() > (unsigned)bufferCount) {
+        LOG(WARNING) << "We found more frames in use than requested.";
+    }
+
+    mFrames.swap(newRecords);
+
+    return true;
+}
+
+
+UniqueFence HalCamera::requestNewFrame(sp<VirtualCamera> client,
+                                       const int64_t lastTimestamp) {
+    if (!mSyncSupported) {
+        LOG(ERROR) << "This HalCamera does not support a fence-based "
+                   << "frame delivery.";
+        return {};
+    }
+
+    FrameRequest req;
+    req.client = client;
+    req.timestamp = lastTimestamp;
+
+    const uint64_t id = (uint64_t)client.get();
+
+    std::lock_guard<std::mutex> lock(mFrameMutex);
+
+    mTimelines[id]->BumpFenceEventCounter();
+    UniqueFence fence = mTimelines[id]->CreateFence("FrameFence");
+
+    mNextRequests->push_back(req);
+
+    return fence.Dup();
+}
+
+
+Return<EvsResult> HalCamera::clientStreamStarting() {
+    Return<EvsResult> result = EvsResult::OK;
+
+    if (mStreamState == STOPPED) {
+        mStreamState = RUNNING;
+        result = mHwCamera->startVideoStream(this);
+    }
+
+    return result;
+}
+
+
+void HalCamera::clientStreamEnding(const VirtualCamera* client) {
+    {
+        std::lock_guard<std::mutex> lock(mFrameMutex);
+        auto itReq = mNextRequests->begin();
+        while (itReq != mNextRequests->end()) {
+            if (itReq->client == client) {
+                break;
+            } else {
+                ++itReq;
+            }
+        }
+
+        const uint64_t clientId = reinterpret_cast<const uint64_t>(client);
+        if (itReq != mNextRequests->end()) {
+            mNextRequests->erase(itReq);
+
+            // Signal a pending fence and delete associated timeline.
+            if (mTimelines.find(clientId) != mTimelines.end()) {
+                mTimelines[clientId]->BumpTimelineEventCounter();
+                mTimelines.erase(clientId);
+            }
+        }
+
+        auto itCam = mClients.begin();
+        while (itCam != mClients.end()) {
+            if (itCam->promote() == client) {
+                break;
+            } else {
+                ++itCam;
+            }
+        }
+
+        if (itCam != mClients.end()) {
+            // Remove a client, which requested to stop, from the list.
+            mClients.erase(itCam);
+        }
+    }
+
+    // Do we still have a running client?
+    bool stillRunning = false;
+    for (auto&& client : mClients) {
+        sp<VirtualCamera> virtCam = client.promote();
+        if (virtCam != nullptr) {
+            stillRunning |= virtCam->isStreaming();
+        }
+    }
+
+    // If not, then stop the hardware stream
+    if (!stillRunning) {
+        mStreamState = STOPPING;
+        mHwCamera->stopVideoStream();
+    }
+}
+
+
+Return<void> HalCamera::doneWithFrame(const BufferDesc_1_0& buffer) {
+    // Find this frame in our list of outstanding frames
+    unsigned i;
+    for (i = 0; i < mFrames.size(); i++) {
+        if (mFrames[i].frameId == buffer.bufferId) {
+            break;
+        }
+    }
+    if (i == mFrames.size()) {
+        LOG(ERROR) << "We got a frame back with an ID we don't recognize!";
+    } else {
+        // Are there still clients using this buffer?
+        mFrames[i].refCount--;
+        if (mFrames[i].refCount <= 0) {
+            // Since all our clients are done with this buffer, return it to the device layer
+            mHwCamera->doneWithFrame(buffer);
+
+            // Counts a returned buffer
+            mUsageStats->framesReturned();
+        }
+    }
+
+    return Void();
+}
+
+
+Return<void> HalCamera::doneWithFrame(const BufferDesc_1_1& buffer) {
+    // Find this frame in our list of outstanding frames
+    unsigned i;
+    for (i = 0; i < mFrames.size(); i++) {
+        if (mFrames[i].frameId == buffer.bufferId) {
+            break;
+        }
+    }
+    if (i == mFrames.size()) {
+        LOG(ERROR) << "We got a frame back with an ID we don't recognize!";
+    } else {
+        // Are there still clients using this buffer?
+        mFrames[i].refCount--;
+        if (mFrames[i].refCount <= 0) {
+            // Since all our clients are done with this buffer, return it to the device layer
+            hardware::hidl_vec<BufferDesc_1_1> returnedBuffers;
+            returnedBuffers.resize(1);
+            returnedBuffers[0] = buffer;
+            mHwCamera->doneWithFrame_1_1(returnedBuffers);
+
+            // Counts a returned buffer
+            mUsageStats->framesReturned(returnedBuffers);
+        }
+    }
+
+    return Void();
+}
+
+
+// Methods from ::android::hardware::automotive::evs::V1_0::IEvsCameraStream follow.
+Return<void> HalCamera::deliverFrame(const BufferDesc_1_0& buffer) {
+    /* Frames are delivered via deliverFrame_1_1 callback for clients that implement
+     * IEvsCameraStream v1.1 interfaces and therefore this method must not be
+     * used.
+     */
+    LOG(INFO) << "A delivered frame from EVS v1.0 HW module is rejected.";
+    mHwCamera->doneWithFrame(buffer);
+
+    // Reports a received and returned buffer
+    mUsageStats->framesReceived();
+    mUsageStats->framesReturned();
+
+    return Void();
+}
+
+
+// Methods from ::android::hardware::automotive::evs::V1_1::IEvsCameraStream follow.
+Return<void> HalCamera::deliverFrame_1_1(const hardware::hidl_vec<BufferDesc_1_1>& buffer) {
+    LOG(VERBOSE) << "Received a frame";
+    // Frames are being forwarded to v1.1 clients only who requested new frame.
+    const auto timestamp = buffer[0].timestamp;
+    // TODO(b/145750636): For now, we are using a approximately half of 1 seconds / 30 frames = 33ms
+    //           but this must be derived from current framerate.
+    constexpr int64_t kThreshold = 16 * 1e+3; // ms
+    unsigned frameDeliveriesV1 = 0;
+    if (mSyncSupported) {
+        std::lock_guard<std::mutex> lock(mFrameMutex);
+        std::swap(mCurrentRequests, mNextRequests);
+        while (!mCurrentRequests->empty()) {
+            auto req = mCurrentRequests->front(); mCurrentRequests->pop_front();
+            sp<VirtualCamera> vCam = req.client.promote();
+            if (vCam == nullptr) {
+                // Ignore a client already dead.
+                continue;
+            } else if (timestamp - req.timestamp < kThreshold) {
+                // Skip current frame because it arrives too soon.
+                LOG(DEBUG) << "Skips a frame from " << getId();
+                mNextRequests->push_back(req);
+
+                // Reports a skipped frame
+                mUsageStats->framesSkippedToSync();
+            } else if (vCam != nullptr && vCam->deliverFrame(buffer[0])) {
+                // Forward a frame and move a timeline.
+                LOG(DEBUG) << getId() << " forwarded the buffer #" << buffer[0].bufferId;
+                mTimelines[(uint64_t)vCam.get()]->BumpTimelineEventCounter();
+                ++frameDeliveriesV1;
+            }
+        }
+    }
+
+    // Reports the number of received buffers
+    mUsageStats->framesReceived(buffer);
+
+    // Frames are being forwarded to active v1.0 clients and v1.1 clients if we
+    // failed to create a timeline.
+    unsigned frameDeliveries = 0;
+    for (auto&& client : mClients) {
+        sp<VirtualCamera> vCam = client.promote();
+        if (vCam == nullptr || (mSyncSupported && vCam->getVersion() > 0)) {
+            continue;
+        }
+
+        if (vCam->deliverFrame(buffer[0])) {
+            ++frameDeliveries;
+        }
+    }
+
+    frameDeliveries += frameDeliveriesV1;
+    if (frameDeliveries < 1) {
+        // If none of our clients could accept the frame, then return it
+        // right away.
+        LOG(INFO) << "Trivially rejecting frame (" << buffer[0].bufferId
+                  << ") from " << getId() << " with no acceptance";
+        mHwCamera->doneWithFrame_1_1(buffer);
+
+        // Reports a returned buffer
+        mUsageStats->framesReturned(buffer);
+    } else {
+        // Add an entry for this frame in our tracking list.
+        unsigned i;
+        for (i = 0; i < mFrames.size(); ++i) {
+            if (mFrames[i].refCount == 0) {
+                break;
+            }
+        }
+
+        if (i == mFrames.size()) {
+            mFrames.emplace_back(buffer[0].bufferId);
+        } else {
+            mFrames[i].frameId = buffer[0].bufferId;
+        }
+        mFrames[i].refCount = frameDeliveries;
+    }
+
+    return Void();
+}
+
+
+Return<void> HalCamera::notify(const EvsEventDesc& event) {
+    LOG(DEBUG) << "Received an event id: " << static_cast<int32_t>(event.aType);
+    if(event.aType == EvsEventType::STREAM_STOPPED) {
+        // This event happens only when there is no more active client.
+        if (mStreamState != STOPPING) {
+            LOG(WARNING) << "Stream stopped unexpectedly";
+        }
+
+        mStreamState = STOPPED;
+    }
+
+    // Forward all other events to the clients
+    for (auto&& client : mClients) {
+        sp<VirtualCamera> vCam = client.promote();
+        if (vCam != nullptr) {
+            if (!vCam->notify(event)) {
+                LOG(INFO) << "Failed to forward an event";
+            }
+        }
+    }
+
+    return Void();
+}
+
+
+Return<EvsResult> HalCamera::setMaster(sp<VirtualCamera> virtualCamera) {
+    if (mMaster == nullptr) {
+        LOG(DEBUG) << __FUNCTION__
+                   << ": " << virtualCamera.get() << " becomes a master.";
+        mMaster = virtualCamera;
+        return EvsResult::OK;
+    } else {
+        LOG(INFO) << "This camera already has a master client.";
+        return EvsResult::OWNERSHIP_LOST;
+    }
+}
+
+
+Return<EvsResult> HalCamera::forceMaster(sp<VirtualCamera> virtualCamera) {
+    sp<VirtualCamera> prevMaster = mMaster.promote();
+    if (prevMaster == virtualCamera) {
+        LOG(DEBUG) << "Client " << virtualCamera.get()
+                   << " is already a master client";
+    } else {
+        mMaster = virtualCamera;
+        if (prevMaster != nullptr) {
+            LOG(INFO) << "High priority client " << virtualCamera.get()
+                      << " steals a master role from " << prevMaster.get();
+
+            /* Notify a previous master client the loss of a master role */
+            EvsEventDesc event;
+            event.aType = EvsEventType::MASTER_RELEASED;
+            if (!prevMaster->notify(event)) {
+                LOG(ERROR) << "Fail to deliver a master role lost notification";
+            }
+        }
+    }
+
+    return EvsResult::OK;
+}
+
+
+Return<EvsResult> HalCamera::unsetMaster(sp<VirtualCamera> virtualCamera) {
+    if (mMaster.promote() != virtualCamera) {
+        return EvsResult::INVALID_ARG;
+    } else {
+        LOG(INFO) << "Unset a master camera client";
+        mMaster = nullptr;
+
+        /* Notify other clients that a master role becomes available. */
+        EvsEventDesc event;
+        event.aType = EvsEventType::MASTER_RELEASED;
+        auto cbResult = this->notify(event);
+        if (!cbResult.isOk()) {
+            LOG(ERROR) << "Fail to deliver a parameter change notification";
+        }
+
+        return EvsResult::OK;
+    }
+}
+
+
+Return<EvsResult> HalCamera::setParameter(sp<VirtualCamera> virtualCamera,
+                                          CameraParam id, int32_t& value) {
+    EvsResult result = EvsResult::INVALID_ARG;
+    if (virtualCamera == mMaster.promote()) {
+        mHwCamera->setIntParameter(id, value,
+                                   [&result, &value](auto status, auto readValue) {
+                                       result = status;
+                                       value = readValue[0];
+                                   });
+
+        if (result == EvsResult::OK) {
+            /* Notify a parameter change */
+            EvsEventDesc event;
+            event.aType = EvsEventType::PARAMETER_CHANGED;
+            event.payload[0] = static_cast<uint32_t>(id);
+            event.payload[1] = static_cast<uint32_t>(value);
+            auto cbResult = this->notify(event);
+            if (!cbResult.isOk()) {
+                LOG(ERROR) << "Fail to deliver a parameter change notification";
+            }
+        }
+    } else {
+        LOG(WARNING) << "A parameter change request from a non-master client is declined.";
+
+        /* Read a current value of a requested camera parameter */
+        getParameter(id, value);
+    }
+
+    return result;
+}
+
+
+Return<EvsResult> HalCamera::getParameter(CameraParam id, int32_t& value) {
+    EvsResult result = EvsResult::OK;
+    mHwCamera->getIntParameter(id, [&result, &value](auto status, auto readValue) {
+                                       result = status;
+                                       if (result == EvsResult::OK) {
+                                           value = readValue[0];
+                                       }
+    });
+
+    return result;
+}
+
+
+CameraUsageStatsRecord HalCamera::getStats() const {
+    return mUsageStats->snapshot();
+}
+
+
+Stream HalCamera::getStreamConfiguration() const {
+    return mStreamConfig;
+}
+
+
+std::string HalCamera::toString(const char* indent) const {
+    std::string buffer;
+
+    const auto timeElapsedMs = android::uptimeMillis() - mTimeCreatedMs;
+    StringAppendF(&buffer, "%sCreated: @%" PRId64 " (elapsed %" PRId64 " ms)\n",
+                           indent, mTimeCreatedMs, timeElapsedMs);
+
+    std::string double_indent(indent);
+    double_indent += indent;
+    buffer += CameraUsageStats::toString(getStats(), double_indent.c_str());
+    for (auto&& client : mClients) {
+        auto handle = client.promote();
+        if (!handle) {
+            continue;
+        }
+
+        StringAppendF(&buffer, "%sClient %p\n",
+                               indent, handle.get());
+        buffer += handle->toString(double_indent.c_str());
+    }
+
+    StringAppendF(&buffer, "%sMaster client: %p\n"
+                           "%sSynchronization support: %s\n",
+                           indent, mMaster.promote().get(),
+                           indent, mSyncSupported ? "T":"F");
+
+    buffer += HalCamera::toString(mStreamConfig, indent);
+
+    return buffer;
+}
+
+
+std::string HalCamera::toString(Stream configuration, const char* indent) {
+    std::string streamInfo;
+    std::string double_indent(indent);
+    double_indent += indent;
+    StringAppendF(&streamInfo, "%sActive Stream Configuration\n"
+                               "%sid: %d\n"
+                               "%swidth: %d\n"
+                               "%sheight: %d\n"
+                               "%sformat: 0x%X\n"
+                               "%susage: 0x%" PRIx64 "\n"
+                               "%srotation: 0x%X\n\n",
+                               indent,
+                               double_indent.c_str(), configuration.id,
+                               double_indent.c_str(), configuration.width,
+                               double_indent.c_str(), configuration.height,
+                               double_indent.c_str(), configuration.format,
+                               double_indent.c_str(), configuration.usage,
+                               double_indent.c_str(), configuration.rotation);
+
+    return streamInfo;
+}
+
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace android
diff --git a/evs/manager/1.1/HalCamera.h b/evs/manager/1.1/HalCamera.h
new file mode 100644
index 0000000..efc5c25
--- /dev/null
+++ b/evs/manager/1.1/HalCamera.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUTOMOTIVE_EVS_V1_1_HALCAMERA_H
+#define ANDROID_AUTOMOTIVE_EVS_V1_1_HALCAMERA_H
+
+#include "stats/CameraUsageStats.h"
+#include "sync/unique_fd.h"
+#include "sync/unique_fence.h"
+#include "sync/unique_timeline.h"
+
+#include <deque>
+#include <list>
+#include <thread>
+#include <unordered_map>
+
+#include <android/hardware/automotive/evs/1.1/types.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
+#include <utils/Mutex.h>
+#include <utils/SystemClock.h>
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::Return;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
+using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
+using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream;
+using IEvsCameraStream_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCameraStream;
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+class VirtualCamera;    // From VirtualCamera.h
+
+
+// This class wraps the actual hardware IEvsCamera objects.  There is a one to many
+// relationship between instances of this class and instances of the VirtualCamera class.
+// This class implements the IEvsCameraStream interface so that it can receive the video
+// stream from the hardware camera and distribute it to the associated VirtualCamera objects.
+class HalCamera : public IEvsCameraStream_1_1 {
+public:
+    HalCamera(sp<IEvsCamera_1_1> hwCamera,
+              std::string deviceId = "",
+              int32_t recordId = 0,
+              Stream cfg = {})
+        : mHwCamera(hwCamera),
+          mId(deviceId),
+          mStreamConfig(cfg),
+          mSyncSupported(UniqueTimeline::Supported()),
+          mTimeCreatedMs(android::uptimeMillis()),
+          mUsageStats(new CameraUsageStats(recordId)) {
+        mCurrentRequests = &mFrameRequests[0];
+        mNextRequests    = &mFrameRequests[1];
+    }
+
+    virtual ~HalCamera();
+
+    // Factory methods for client VirtualCameras
+    sp<VirtualCamera>     makeVirtualCamera();
+    bool                  ownVirtualCamera(sp<VirtualCamera> virtualCamera);
+    void                  disownVirtualCamera(sp<VirtualCamera> virtualCamera);
+
+    // Implementation details
+    sp<IEvsCamera_1_0>  getHwCamera()       { return mHwCamera; };
+    unsigned            getClientCount()    { return mClients.size(); };
+    std::string         getId()             { return mId; }
+    Stream&             getStreamConfig()   { return mStreamConfig; }
+    bool                changeFramesInFlight(int delta);
+    bool                changeFramesInFlight(const hardware::hidl_vec<BufferDesc_1_1>& buffers,
+                                             int* delta);
+    UniqueFence         requestNewFrame(sp<VirtualCamera> virtualCamera,
+                                        const int64_t timestamp);
+
+    Return<EvsResult>   clientStreamStarting();
+    void                clientStreamEnding(const VirtualCamera* client);
+    Return<void>        doneWithFrame(const BufferDesc_1_0& buffer);
+    Return<void>        doneWithFrame(const BufferDesc_1_1& buffer);
+    Return<EvsResult>   setMaster(sp<VirtualCamera> virtualCamera);
+    Return<EvsResult>   forceMaster(sp<VirtualCamera> virtualCamera);
+    Return<EvsResult>   unsetMaster(sp<VirtualCamera> virtualCamera);
+    Return<EvsResult>   setParameter(sp<VirtualCamera> virtualCamera,
+                                     CameraParam id, int32_t& value);
+    Return<EvsResult>   getParameter(CameraParam id, int32_t& value);
+    bool                isSyncSupported() const { return mSyncSupported; }
+
+    // Returns a snapshot of collected usage statistics
+    CameraUsageStatsRecord getStats() const;
+
+    // Returns active stream configuration
+    Stream getStreamConfiguration() const;
+
+    // Returns a string showing the current status
+    std::string toString(const char* indent = "") const;
+
+    // Returns a string showing current stream configuration
+    static std::string toString(Stream configuration, const char* indent = "");
+
+    // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCameraStream follow.
+    Return<void> deliverFrame(const BufferDesc_1_0& buffer) override;
+
+    // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCameraStream follow.
+    Return<void> deliverFrame_1_1(const hardware::hidl_vec<BufferDesc_1_1>& buffer) override;
+    Return<void> notify(const EvsEventDesc& event) override;
+
+private:
+    sp<IEvsCamera_1_1>              mHwCamera;
+    std::list<wp<VirtualCamera>>    mClients;   // Weak pointers -> objects destruct if client dies
+
+    enum {
+        STOPPED,
+        RUNNING,
+        STOPPING,
+    }                               mStreamState = STOPPED;
+
+    struct FrameRecord {
+        uint32_t    frameId;
+        uint32_t    refCount;
+        FrameRecord(uint32_t id) : frameId(id), refCount(0) {};
+    };
+    std::vector<FrameRecord>        mFrames;
+    wp<VirtualCamera>               mMaster = nullptr;
+    std::string                     mId;
+    Stream                          mStreamConfig;
+
+    struct FrameRequest {
+        wp<VirtualCamera> client = nullptr;
+        int64_t           timestamp = -1;
+    };
+
+    // synchronization
+    mutable std::mutex        mFrameMutex;
+    std::deque<FrameRequest>  mFrameRequests[2] GUARDED_BY(mFrameMutex);
+    std::deque<FrameRequest>* mCurrentRequests  PT_GUARDED_BY(mFrameMutex);
+    std::deque<FrameRequest>* mNextRequests     PT_GUARDED_BY(mFrameMutex);
+    std::unordered_map<uint64_t,
+                       std::unique_ptr<UniqueTimeline>> mTimelines GUARDED_BY(mFrameMutex);
+    bool                      mSyncSupported;
+
+    // Time this object was created
+    int64_t mTimeCreatedMs;
+
+    // usage statistics to collect
+    android::sp<CameraUsageStats> mUsageStats;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace android
+
+#endif  // ANDROID_AUTOMOTIVE_EVS_V1_1_HALCAMERA_H
diff --git a/evs/manager/1.1/HalDisplay.cpp b/evs/manager/1.1/HalDisplay.cpp
new file mode 100644
index 0000000..b1e1aa6
--- /dev/null
+++ b/evs/manager/1.1/HalDisplay.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "HalDisplay.h"
+
+#include <inttypes.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <ui/DisplayConfig.h>
+#include <ui/DisplayState.h>
+
+using android::base::StringAppendF;
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+HalDisplay::HalDisplay(sp<IEvsDisplay_1_0> display, int32_t id) :
+  mHwDisplay(display),
+  mId(id) {
+    // nothing to do.
+}
+
+HalDisplay::~HalDisplay() {
+    shutdown();
+}
+
+void HalDisplay::shutdown() {
+    // simply release a strong pointer to remote display object.
+    mHwDisplay = nullptr;
+}
+
+/**
+ * Returns a strong pointer to remote display object.
+ */
+sp<IEvsDisplay_1_0> HalDisplay::getHwDisplay() {
+    return mHwDisplay;
+}
+
+/**
+ * Gets basic display information from a hardware display object
+ * and returns.
+ */
+Return<void> HalDisplay::getDisplayInfo(getDisplayInfo_cb _hidl_cb) {
+    if (mHwDisplay) {
+        mHwDisplay->getDisplayInfo(_hidl_cb);
+    }
+
+    return Void();
+}
+
+/**
+ * Sets the display state as what the clients wants.
+ */
+Return<EvsResult> HalDisplay::setDisplayState(EvsDisplayState state) {
+    if (mHwDisplay) {
+        return mHwDisplay->setDisplayState(state);
+    } else {
+        return EvsResult::UNDERLYING_SERVICE_ERROR;
+    }
+}
+
+/**
+ * Gets current display state from a hardware display object and return.
+ */
+Return<EvsDisplayState> HalDisplay::getDisplayState() {
+    if (mHwDisplay) {
+        return mHwDisplay->getDisplayState();
+    } else {
+        return EvsDisplayState::DEAD;
+    }
+}
+
+/**
+ * Returns a handle to a frame buffer associated with the display.
+ */
+Return<void> HalDisplay::getTargetBuffer(getTargetBuffer_cb _hidl_cb) {
+    if (mHwDisplay) {
+        mHwDisplay->getTargetBuffer(_hidl_cb);
+    }
+
+    return Void();
+}
+
+/**
+ * Notifies the display that the buffer is ready to be used.
+ */
+Return<EvsResult> HalDisplay::returnTargetBufferForDisplay(const BufferDesc_1_0& buffer) {
+    if (mHwDisplay) {
+        return mHwDisplay->returnTargetBufferForDisplay(buffer);
+    } else {
+        return EvsResult::OWNERSHIP_LOST;
+    }
+}
+
+/**
+ * Gets basic display information from a hardware display object
+ * and returns.
+ */
+Return<void> HalDisplay::getDisplayInfo_1_1(getDisplayInfo_1_1_cb _info_cb) {
+    sp<IEvsDisplay_1_1> display = IEvsDisplay_1_1::castFrom(mHwDisplay)
+                                  .withDefault(nullptr);
+    if (display != nullptr) {
+        display->getDisplayInfo_1_1(_info_cb);
+    }
+
+    return Void();
+}
+
+
+std::string HalDisplay::toString(const char* indent) {
+    std::string buffer;
+    android::DisplayConfig displayConfig;
+    android::ui::DisplayState displayState;
+
+    if (mId == std::numeric_limits<int32_t>::min()) {
+        // Display identifier has not set
+        StringAppendF(&buffer, "HalDisplay: Display port is unknown.\n");
+    } else {
+        StringAppendF(&buffer, "HalDisplay: Display port %" PRId32 "\n", mId);
+    }
+
+    getDisplayInfo_1_1([&](auto& config, auto& state) {
+        displayConfig =
+            *(reinterpret_cast<const android::DisplayConfig*>(config.data()));
+        displayState =
+            *(reinterpret_cast<const android::ui::DisplayState*>(state.data()));
+    });
+
+    StringAppendF(&buffer, "%sWidth: %" PRId32 "\n",
+                           indent, displayConfig.resolution.getWidth());
+    StringAppendF(&buffer, "%sHeight: %" PRId32 "\n",
+                           indent, displayConfig.resolution.getHeight());
+    StringAppendF(&buffer, "%sRefresh rate: %f\n",
+                           indent, displayConfig.refreshRate);
+    StringAppendF(&buffer, "%sRotation: %" PRId32 "\n",
+                           indent, static_cast<int32_t>(displayState.orientation));
+
+    return buffer;
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace android
diff --git a/evs/manager/1.1/HalDisplay.h b/evs/manager/1.1/HalDisplay.h
new file mode 100644
index 0000000..672ad55
--- /dev/null
+++ b/evs/manager/1.1/HalDisplay.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUTOMOTIVE_EVS_V1_1_DISPLAYPROXY_H
+#define ANDROID_AUTOMOTIVE_EVS_V1_1_DISPLAYPROXY_H
+
+#include <limits>
+
+#include <android/hardware/automotive/evs/1.1/types.h>
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using EvsDisplayState = ::android::hardware::automotive::evs::V1_0::DisplayState;
+using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using IEvsDisplay_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+// TODO(129284474): This class has been defined to wrap the IEvsDisplay object the driver
+// returns because of b/129284474 and represents an EVS display to the client
+// application.  With a proper bug fix, we may remove this class and update the
+// manager directly to use the IEvsDisplay object the driver provides.
+class HalDisplay : public IEvsDisplay_1_1 {
+public:
+    explicit HalDisplay(sp<IEvsDisplay_1_0> display,
+                        int32_t port = std::numeric_limits<int32_t>::min());
+    virtual ~HalDisplay() override;
+
+    inline void         shutdown();
+    sp<IEvsDisplay_1_0> getHwDisplay();
+
+    // Methods from ::android::hardware::automotive::evs::V1_0::IEvsDisplay follow.
+    Return<void>            getDisplayInfo(getDisplayInfo_cb _hidl_cb)  override;
+    Return<EvsResult>       setDisplayState(EvsDisplayState state)  override;
+    Return<EvsDisplayState> getDisplayState()  override;
+    Return<void>            getTargetBuffer(getTargetBuffer_cb _hidl_cb)  override;
+    Return<EvsResult>       returnTargetBufferForDisplay(const BufferDesc_1_0& buffer)  override;
+
+    // Methods from ::android::hardware::automotive::evs::V1_1::IEvsDisplay follow.
+    Return<void>            getDisplayInfo_1_1(getDisplayInfo_1_1_cb _info_cb) override;
+
+    // Returns a string showing the current status
+    std::string toString(const char* indent = "");
+
+private:
+    sp<IEvsDisplay_1_0>     mHwDisplay; // The low level display interface that backs this proxy
+    int32_t                 mId; // Display identifier
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace android
+
+#endif  // ANDROID_AUTOMOTIVE_EVS_V1_1_DISPLAYPROXY_H
diff --git a/evs/manager/1.1/ServiceNames.h b/evs/manager/1.1/ServiceNames.h
new file mode 100644
index 0000000..c2a7a65
--- /dev/null
+++ b/evs/manager/1.1/ServiceNames.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// This is the name as which we'll register ourselves
+const static char kManagedEnumeratorName[] = "default";
+
+// This is the name of the hardware provider to which we'll bind by default
+const static char kHardwareEnumeratorName[]  = "hw/1";
+
+// This is the name of the mock hardware provider selectable via command line.
+// (should match .../hardware/interfaces/automotive/evs/1.1/default/ServiceNames.h)
+const static char kMockEnumeratorName[]  = "EvsEnumeratorHw-Mock";
+
diff --git a/evs/manager/1.1/VirtualCamera.cpp b/evs/manager/1.1/VirtualCamera.cpp
new file mode 100644
index 0000000..6204a78
--- /dev/null
+++ b/evs/manager/1.1/VirtualCamera.cpp
@@ -0,0 +1,929 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "VirtualCamera.h"
+#include "HalCamera.h"
+#include "Enumerator.h"
+
+#include <android/hardware_buffer.h>
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+using ::android::base::StringAppendF;
+using ::android::base::StringPrintf;
+using ::android::base::WriteStringToFd;
+using ::android::hardware::automotive::evs::V1_0::DisplayState;
+
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+VirtualCamera::VirtualCamera(const std::vector<sp<HalCamera>>& halCameras) :
+    mStreamState(STOPPED) {
+    for (auto&& cam : halCameras) {
+        mHalCamera.try_emplace(cam->getId(), cam);
+    }
+}
+
+
+VirtualCamera::~VirtualCamera() {
+    shutdown();
+}
+
+
+void VirtualCamera::shutdown() {
+    // In normal operation, the stream should already be stopped by the time we get here
+    if (mStreamState == RUNNING) {
+        // Note that if we hit this case, no terminating frame will be sent to the client,
+        // but they're probably already dead anyway.
+        LOG(WARNING) << "Virtual camera being shutdown while stream is running";
+
+        // Tell the frame delivery pipeline we don't want any more frames
+        mStreamState = STOPPING;
+
+        for (auto&& [key, hwCamera] : mHalCamera) {
+            auto pHwCamera = hwCamera.promote();
+            if (pHwCamera == nullptr) {
+                LOG(WARNING) << "Camera device " << key << " is not alive.";
+                continue;
+            }
+
+            if (mFramesHeld[key].size() > 0) {
+                LOG(WARNING) << "VirtualCamera destructing with frames in flight.";
+
+                // Return to the underlying hardware camera any buffers the client was holding
+                for (auto&& heldBuffer : mFramesHeld[key]) {
+                    // Tell our parent that we're done with this buffer
+                    pHwCamera->doneWithFrame(heldBuffer);
+                }
+                mFramesHeld[key].clear();
+            }
+
+            // Retire from a master client
+            pHwCamera->unsetMaster(this);
+
+            // Give the underlying hardware camera the heads up that it might be time to stop
+            pHwCamera->clientStreamEnding(this);
+        }
+
+        // Join a capture thread
+        if (mCaptureThread.joinable()) {
+            mCaptureThread.join();
+        }
+
+        mFramesHeld.clear();
+
+        // Drop our reference to our associated hardware camera
+        mHalCamera.clear();
+    }
+}
+
+
+std::vector<sp<HalCamera>> VirtualCamera::getHalCameras() {
+    std::vector<sp<HalCamera>> cameras;
+    for (auto&& [key, cam] : mHalCamera) {
+        auto ptr = cam.promote();
+        if (ptr != nullptr) {
+            cameras.emplace_back(ptr);
+        }
+    }
+
+    return cameras;
+}
+
+
+bool VirtualCamera::deliverFrame(const BufferDesc_1_1& bufDesc) {
+    if (mStreamState == STOPPED) {
+        // A stopped stream gets no frames
+        LOG(ERROR) << "A stopped stream should not get any frames";
+        return false;
+    } else if (mFramesHeld[bufDesc.deviceId].size() >= mFramesAllowed) {
+        // Indicate that we declined to send the frame to the client because they're at quota
+        LOG(INFO) << "Skipping new frame as we hold " << mFramesHeld[bufDesc.deviceId].size()
+                  << " of " << mFramesAllowed;
+
+        if (mStream_1_1 != nullptr) {
+            // Report a frame drop to v1.1 client.
+            EvsEventDesc event;
+            event.deviceId = bufDesc.deviceId;
+            event.aType = EvsEventType::FRAME_DROPPED;
+            auto result = mStream_1_1->notify(event);
+            if (!result.isOk()) {
+                LOG(ERROR) << "Error delivering end of stream event";
+            }
+        }
+
+        return false;
+    } else {
+        // Keep a record of this frame so we can clean up if we have to in case of client death
+        mFramesHeld[bufDesc.deviceId].emplace_back(bufDesc);
+
+        // v1.0 client uses an old frame-delivery mechanism.
+        if (mStream_1_1 == nullptr) {
+            // Forward a frame to v1.0 client
+            BufferDesc_1_0 frame_1_0 = {};
+            const AHardwareBuffer_Desc* pDesc =
+                reinterpret_cast<const AHardwareBuffer_Desc *>(&bufDesc.buffer.description);
+            frame_1_0.width     = pDesc->width;
+            frame_1_0.height    = pDesc->height;
+            frame_1_0.format    = pDesc->format;
+            frame_1_0.usage     = pDesc->usage;
+            frame_1_0.stride    = pDesc->stride;
+            frame_1_0.memHandle = bufDesc.buffer.nativeHandle;
+            frame_1_0.pixelSize = bufDesc.pixelSize;
+            frame_1_0.bufferId  = bufDesc.bufferId;
+
+            mStream->deliverFrame(frame_1_0);
+        } else if (!mCaptureThread.joinable()) {
+            // A capture thread does not run only it failed to create a
+            // timeline.
+            if (mFramesHeld.size() > 0 && mStream_1_1 != nullptr) {
+                // Pass this buffer through to our client
+                hardware::hidl_vec<BufferDesc_1_1> frames;
+                frames.resize(1);
+                auto pHwCamera = mHalCamera.begin()->second.promote();
+                if (pHwCamera != nullptr) {
+                    frames[0] = mFramesHeld[mHalCamera.begin()->first].back();
+                }
+
+                mStream_1_1->deliverFrame_1_1(frames);
+            }
+        }
+
+        return true;
+    }
+}
+
+
+bool VirtualCamera::notify(const EvsEventDesc& event) {
+    switch(event.aType) {
+        case EvsEventType::STREAM_STOPPED:
+            if (mStreamState != STOPPING) {
+                // Warn if we got an unexpected stream termination
+                LOG(WARNING) << "Stream unexpectedly stopped, current status "
+                             << mStreamState;
+            }
+
+            // Mark the stream as stopped.
+            mStreamState = STOPPED;
+
+            if (mStream_1_1 == nullptr) {
+                // Send a null frame instead, for v1.0 client
+                auto result = mStream->deliverFrame({});
+                if (!result.isOk()) {
+                    LOG(ERROR) << "Error delivering end of stream marker";
+                }
+            }
+            break;
+
+        // v1.0 client will ignore all other events.
+        case EvsEventType::PARAMETER_CHANGED:
+            LOG(DEBUG) << "A camera parameter " << event.payload[0]
+                       << " is set to " << event.payload[1];
+            break;
+
+        case EvsEventType::MASTER_RELEASED:
+            LOG(DEBUG) << "The master client has been released";
+            break;
+
+        default:
+            LOG(WARNING) << "Unknown event id " << static_cast<int32_t>(event.aType);
+            break;
+    }
+
+    if (mStream_1_1 != nullptr) {
+        // Forward a received event to the v1.1 client
+        auto result = mStream_1_1->notify(event);
+        if (!result.isOk()) {
+            LOG(ERROR) << "Failed to forward an event";
+            return false;
+        }
+    }
+
+    return true;
+}
+
+
+// Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
+Return<void> VirtualCamera::getCameraInfo(getCameraInfo_cb info_cb) {
+    // Straight pass through to hardware layer
+    if (mHalCamera.size() > 1) {
+        LOG(ERROR) << __FUNCTION__
+                   << " must NOT be called on a logical camera object.";
+        info_cb({});
+        return Void();
+    }
+
+    auto halCamera = mHalCamera.begin()->second.promote();
+    if (halCamera != nullptr) {
+        return halCamera->getHwCamera()->getCameraInfo(info_cb);
+    } else {
+        info_cb({});
+        return Void();
+    }
+}
+
+
+Return<EvsResult> VirtualCamera::setMaxFramesInFlight(uint32_t bufferCount) {
+    // How many buffers are we trying to add (or remove if negative)
+    int bufferCountChange = bufferCount - mFramesAllowed;
+
+    // Ask our parent for more buffers
+    bool result = true;
+    std::vector<sp<HalCamera>> changedCameras;
+    for (auto&& [key, hwCamera] : mHalCamera) {
+        auto pHwCam = hwCamera.promote();
+        if (pHwCam == nullptr) {
+            continue;
+        }
+
+        result = pHwCam->changeFramesInFlight(bufferCountChange);
+        if (!result) {
+            LOG(ERROR) << key
+                       << ": Failed to change buffer count by " << bufferCountChange
+                       << " to " << bufferCount;
+            break;
+        }
+
+        changedCameras.emplace_back(pHwCam);
+    }
+
+    // Update our notion of how many frames we're allowed
+    mFramesAllowed = bufferCount;
+
+    if (!result) {
+        // Rollback changes because we failed to update all cameras
+        for (auto&& hwCamera : changedCameras) {
+            LOG(WARNING) << "Rollback a change on  " << hwCamera->getId();
+            hwCamera->changeFramesInFlight(-bufferCountChange);
+        }
+
+        // Restore the original buffer count
+        mFramesAllowed -= bufferCountChange;
+        return EvsResult::BUFFER_NOT_AVAILABLE;
+    } else {
+        return EvsResult::OK;
+    }
+}
+
+
+Return<EvsResult> VirtualCamera::startVideoStream(const ::android::sp<IEvsCameraStream_1_0>& stream)  {
+    // We only support a single stream at a time
+    if (mStreamState != STOPPED) {
+        LOG(ERROR) << "Ignoring startVideoStream call when a stream is already running.";
+        return EvsResult::STREAM_ALREADY_RUNNING;
+    }
+
+    // Validate our held frame count is starting out at zero as we expect
+    assert(mFramesHeld.size() == 0);
+
+    // Record the user's callback for use when we have a frame ready
+    mStream = stream;
+    mStream_1_1 = IEvsCameraStream_1_1::castFrom(stream).withDefault(nullptr);
+    if (mStream_1_1 == nullptr) {
+        LOG(INFO) << "Start video stream for v1.0 client.";
+    } else {
+        LOG(INFO) << "Start video stream for v1.1 client.";
+    }
+
+    mStreamState = RUNNING;
+
+    // Tell the underlying camera hardware that we want to stream
+    auto iter = mHalCamera.begin();
+    while (iter != mHalCamera.end()) {
+        auto pHwCamera = iter->second.promote();
+        if (pHwCamera == nullptr) {
+            LOG(ERROR) << "Failed to start a video stream on " << iter->first;
+            continue;
+        }
+
+        LOG(INFO) << __FUNCTION__
+                  << " starts a video stream on " << iter->first;
+        Return<EvsResult> result = pHwCamera->clientStreamStarting();
+        if ((!result.isOk()) || (result != EvsResult::OK)) {
+            // If we failed to start the underlying stream, then we're not actually running
+            mStream = mStream_1_1 = nullptr;
+            mStreamState = STOPPED;
+
+            // Request to stop streams started by this client.
+            auto rb = mHalCamera.begin();
+            while (rb != iter) {
+                auto ptr = rb->second.promote();
+                if (ptr != nullptr) {
+                    ptr->clientStreamEnding(this);
+                }
+                ++rb;
+            }
+            return EvsResult::UNDERLYING_SERVICE_ERROR;
+        }
+        ++iter;
+    }
+
+    // Start a thread that waits on the fence and forwards collected frames
+    // to the v1.1 client.
+    // If the system does not support a sw sync, EVS does not support a logical
+    // camera device and, therefore, VirtualCamera will subscribe only to a
+    // single hw camera.
+    auto pHwCamera = mHalCamera.begin()->second.promote();
+    if (mStream_1_1 != nullptr && pHwCamera != nullptr && pHwCamera->isSyncSupported()) {
+        mCaptureThread = std::thread([this]() {
+            // TODO(b/145466570): With a proper camera hang handler, we may want
+            // to reduce an amount of timeout.
+            constexpr int kFrameTimeoutMs = 5000; // timeout in ms.
+            int64_t lastFrameTimestamp = -1;
+            while (mStreamState == RUNNING) {
+                UniqueFence fence;
+                unsigned count = 0;
+                for (auto&& [key, hwCamera] : mHalCamera) {
+                    auto pHwCamera = hwCamera.promote();
+                    if (pHwCamera == nullptr) {
+                        LOG(WARNING) << "Invalid camera " << key << " is ignored.";
+                        continue;
+                    }
+
+                    UniqueFence another = pHwCamera->requestNewFrame(this, lastFrameTimestamp);
+                    if (!another) {
+                        LOG(WARNING) << key << " returned an invalid fence.";
+                        continue;
+                    }
+
+                    fence = UniqueFence::Merge("MergedFrameFence",
+                                               fence,
+                                               another);
+                    ++count;
+                }
+
+                if (fence.Wait(kFrameTimeoutMs) < 0) {
+                    // TODO(b/145466570): Replace this temporarily camera hang
+                    // handler.
+                    PLOG(ERROR) << this << ": Camera hangs?";
+                    break;
+                } else if (mStreamState == RUNNING) {
+                    // Fetch frames and forward to the client
+                    if (mFramesHeld.size() > 0 && mStream_1_1 != nullptr) {
+                        // Pass this buffer through to our client
+                        hardware::hidl_vec<BufferDesc_1_1> frames;
+                        frames.resize(count);
+                        unsigned i = 0;
+                        for (auto&& [key, hwCamera] : mHalCamera) {
+                            auto pHwCamera = hwCamera.promote();
+                            if (pHwCamera == nullptr) {
+                                continue;
+                            }
+
+                            const auto frame = mFramesHeld[key].back();
+                            if (frame.timestamp > lastFrameTimestamp) {
+                                lastFrameTimestamp = frame.timestamp;
+                            }
+                            frames[i++] = frame;
+                        }
+                        mStream_1_1->deliverFrame_1_1(frames);
+                    }
+                }
+            }
+        });
+    }
+
+    // TODO(changyeon):
+    // Detect and exit if we encounter a stalled stream or unresponsive driver?
+    // Consider using a timer and watching for frame arrival?
+
+    return EvsResult::OK;
+}
+
+
+Return<void> VirtualCamera::doneWithFrame(const BufferDesc_1_0& buffer) {
+    if (buffer.memHandle == nullptr) {
+        LOG(ERROR) << "Ignoring doneWithFrame called with invalid handle";
+    } else if (mFramesHeld.size() > 1) {
+        LOG(ERROR) << __FUNCTION__
+                   << " must NOT be called on a logical camera object.";
+    } else {
+        // Find this buffer in our "held" list
+        auto& frameQueue = mFramesHeld.begin()->second;
+        auto it = frameQueue.begin();
+        while (it != frameQueue.end()) {
+            if (it->bufferId == buffer.bufferId) {
+                // found it!
+                break;
+            }
+            ++it;
+        }
+        if (it == frameQueue.end()) {
+            // We should always find the frame in our "held" list
+            LOG(ERROR) << "Ignoring doneWithFrame called with unrecognized frameID "
+                       << buffer.bufferId;
+        } else {
+            // Take this frame out of our "held" list
+            frameQueue.erase(it);
+
+            // Tell our parent that we're done with this buffer
+            auto pHwCamera = mHalCamera.begin()->second.promote();
+            if (pHwCamera != nullptr) {
+                pHwCamera->doneWithFrame(buffer);
+            } else {
+                LOG(WARNING) << "Possible memory leak because a device "
+                             << mHalCamera.begin()->first
+                             << " is not valid.";
+            }
+        }
+    }
+
+    return Void();
+}
+
+
+Return<void> VirtualCamera::stopVideoStream()  {
+    if (mStreamState == RUNNING) {
+        // Tell the frame delivery pipeline we don't want any more frames
+        mStreamState = STOPPING;
+
+        // Deliver an empty frame to close out the frame stream
+        if (mStream_1_1 != nullptr) {
+            // v1.1 client waits for a stream stopped event
+            EvsEventDesc event;
+            event.aType = EvsEventType::STREAM_STOPPED;
+            auto result = mStream_1_1->notify(event);
+            if (!result.isOk()) {
+                LOG(ERROR) << "Error delivering end of stream event";
+            }
+        } else {
+            // v1.0 client expects a null frame at the end of the stream
+            auto result = mStream->deliverFrame({});
+            if (!result.isOk()) {
+                LOG(ERROR) << "Error delivering end of stream marker";
+            }
+        }
+
+        // Since we are single threaded, no frame can be delivered while this function is running,
+        // so we can go directly to the STOPPED state here on the server.
+        // Note, however, that there still might be frames already queued that client will see
+        // after returning from the client side of this call.
+        mStreamState = STOPPED;
+
+        // Give the underlying hardware camera the heads up that it might be time to stop
+        for (auto&& [key, hwCamera] : mHalCamera) {
+            auto pHwCamera = hwCamera.promote();
+            if (pHwCamera != nullptr) {
+                pHwCamera->clientStreamEnding(this);
+            }
+        }
+
+        // Join a thread
+        if (mCaptureThread.joinable()) {
+            mCaptureThread.join();
+        }
+
+    }
+
+    return Void();
+}
+
+
+Return<int32_t> VirtualCamera::getExtendedInfo(uint32_t opaqueIdentifier)  {
+    if (mHalCamera.size() > 1) {
+        LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
+        return 0;
+    }
+
+    // Pass straight through to the hardware device
+    auto pHwCamera = mHalCamera.begin()->second.promote();
+    if (pHwCamera != nullptr) {
+        return pHwCamera->getHwCamera()->getExtendedInfo(opaqueIdentifier);
+    } else {
+        LOG(WARNING) << mHalCamera.begin()->first << " is invalid.";
+        return 0;
+    }
+}
+
+
+Return<EvsResult> VirtualCamera::setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue)  {
+    if (mHalCamera.size() > 1) {
+        LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
+        return EvsResult::INVALID_ARG;
+    }
+
+    // Pass straight through to the hardware device
+    auto pHwCamera = mHalCamera.begin()->second.promote();
+    if (pHwCamera != nullptr) {
+        return pHwCamera->getHwCamera()->setExtendedInfo(opaqueIdentifier, opaqueValue);
+    } else {
+        LOG(WARNING) << mHalCamera.begin()->first << " is invalid.";
+        return EvsResult::INVALID_ARG;
+    }
+}
+
+
+// Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
+Return<void> VirtualCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb info_cb) {
+    if (mHalCamera.size() > 1) {
+        // Logical camera description is stored in VirtualCamera object.
+        info_cb(*mDesc);
+        return Void();
+    }
+
+    // Straight pass through to hardware layer
+    auto pHwCamera = mHalCamera.begin()->second.promote();
+    if (pHwCamera == nullptr) {
+        // Return an empty list
+        info_cb({});
+        return Void();
+    }
+
+    auto hwCamera_1_1 =
+        IEvsCamera_1_1::castFrom(pHwCamera->getHwCamera()).withDefault(nullptr);
+    if (hwCamera_1_1 != nullptr) {
+        return hwCamera_1_1->getCameraInfo_1_1(info_cb);
+    } else {
+        // Return an empty list
+        info_cb({});
+        return Void();
+    }
+}
+
+
+Return<void> VirtualCamera::getPhysicalCameraInfo(const hidl_string& deviceId,
+                                                  getPhysicalCameraInfo_cb info_cb) {
+    auto device = mHalCamera.find(deviceId);
+    if (device != mHalCamera.end()) {
+        // Straight pass through to hardware layer
+        auto pHwCamera = device->second.promote();
+        if (pHwCamera != nullptr) {
+            auto hwCamera_1_1 =
+                IEvsCamera_1_1::castFrom(pHwCamera->getHwCamera()).withDefault(nullptr);
+            if (hwCamera_1_1 != nullptr) {
+                return hwCamera_1_1->getCameraInfo_1_1(info_cb);
+            } else {
+                LOG(WARNING) << "Failed to promote HW camera to v1.1.";
+            }
+        } else {
+            LOG(WARNING) << "Camera device " << deviceId << " is not alive.";
+        }
+    } else {
+        LOG(WARNING) << " Requested device " << deviceId
+                     << " does not back this device.";
+    }
+
+    // Return an empty list
+    info_cb({});
+    return Void();
+}
+
+
+Return<EvsResult> VirtualCamera::doneWithFrame_1_1(
+    const hardware::hidl_vec<BufferDesc_1_1>& buffers) {
+
+    for (auto&& buffer : buffers) {
+        if (buffer.buffer.nativeHandle == nullptr) {
+            LOG(WARNING) << "Ignoring doneWithFrame called with invalid handle";
+        } else {
+            // Find this buffer in our "held" list
+            auto it = mFramesHeld[buffer.deviceId].begin();
+            while (it != mFramesHeld[buffer.deviceId].end()) {
+                if (it->bufferId == buffer.bufferId) {
+                    // found it!
+                    break;
+                }
+                ++it;
+            }
+            if (it == mFramesHeld[buffer.deviceId].end()) {
+                // We should always find the frame in our "held" list
+                LOG(ERROR) << "Ignoring doneWithFrame called with unrecognized frameID "
+                           << buffer.bufferId;
+            } else {
+                // Take this frame out of our "held" list
+                mFramesHeld[buffer.deviceId].erase(it);
+
+                // Tell our parent that we're done with this buffer
+                auto pHwCamera = mHalCamera[buffer.deviceId].promote();
+                if (pHwCamera != nullptr) {
+                    pHwCamera->doneWithFrame(buffer);
+                } else {
+                    LOG(WARNING) << "Possible memory leak; "
+                                 << buffer.deviceId << " is not valid.";
+                }
+            }
+        }
+    }
+
+    return EvsResult::OK;
+}
+
+
+Return<EvsResult> VirtualCamera::setMaster() {
+    if (mHalCamera.size() > 1) {
+        LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
+        return EvsResult::INVALID_ARG;
+    }
+
+    auto pHwCamera = mHalCamera.begin()->second.promote();
+    if (pHwCamera != nullptr) {
+        return pHwCamera->setMaster(this);
+    } else {
+        LOG(WARNING) << "Camera device " << mHalCamera.begin()->first << " is not alive.";
+        return EvsResult::INVALID_ARG;
+    }
+}
+
+
+Return<EvsResult> VirtualCamera::forceMaster(const sp<IEvsDisplay_1_0>& display) {
+    if (mHalCamera.size() > 1) {
+        LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
+        return EvsResult::INVALID_ARG;
+    }
+
+    if (display.get() == nullptr) {
+        LOG(ERROR) << __FUNCTION__
+                   << ": Passed display is invalid";
+        return EvsResult::INVALID_ARG;
+    }
+
+    DisplayState state = display->getDisplayState();
+    if (state == DisplayState::NOT_OPEN ||
+        state == DisplayState::DEAD ||
+        state >= DisplayState::NUM_STATES) {
+        LOG(ERROR) << __FUNCTION__
+                   << ": Passed display is in invalid state";
+        return EvsResult::INVALID_ARG;
+    }
+
+    auto pHwCamera = mHalCamera.begin()->second.promote();
+    if (pHwCamera != nullptr) {
+        return pHwCamera->forceMaster(this);
+    } else {
+        LOG(WARNING) << "Camera device " << mHalCamera.begin()->first << " is not alive.";
+        return EvsResult::INVALID_ARG;
+    }
+}
+
+
+Return<EvsResult> VirtualCamera::unsetMaster() {
+    if (mHalCamera.size() > 1) {
+        LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
+        return EvsResult::INVALID_ARG;
+    }
+
+    auto pHwCamera = mHalCamera.begin()->second.promote();
+    if (pHwCamera != nullptr) {
+        return pHwCamera->unsetMaster(this);
+    } else {
+        LOG(WARNING) << "Camera device " << mHalCamera.begin()->first << " is not alive.";
+        return EvsResult::INVALID_ARG;
+    }
+}
+
+
+Return<void> VirtualCamera::getParameterList(getParameterList_cb _hidl_cb) {
+    if (mHalCamera.size() > 1) {
+        LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
+
+        // Return an empty list
+        _hidl_cb({});
+        return Void();
+    }
+
+    // Straight pass through to hardware layer
+    auto pHwCamera = mHalCamera.begin()->second.promote();
+    if (pHwCamera == nullptr) {
+        LOG(WARNING) << "Camera device " << mHalCamera.begin()->first << " is not alive.";
+
+        // Return an empty list
+        _hidl_cb({});
+        return Void();
+    }
+
+    auto hwCamera_1_1 =
+        IEvsCamera_1_1::castFrom(pHwCamera->getHwCamera()).withDefault(nullptr);
+    if (hwCamera_1_1 != nullptr) {
+        return hwCamera_1_1->getParameterList(_hidl_cb);
+    } else {
+        LOG(WARNING) << "Camera device " << mHalCamera.begin()->first
+                     << " does not support a parameter programming.";
+
+        // Return an empty list
+        _hidl_cb({});
+        return Void();
+    }
+}
+
+
+Return<void> VirtualCamera::getIntParameterRange(CameraParam id,
+                                                 getIntParameterRange_cb _hidl_cb) {
+    if (mHalCamera.size() > 1) {
+        LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
+
+        // Return [0, 0, 0]
+        _hidl_cb(0, 0, 0);
+        return Void();
+    }
+
+    // Straight pass through to hardware layer
+    auto pHwCamera = mHalCamera.begin()->second.promote();
+    if (pHwCamera == nullptr) {
+        LOG(WARNING) << "Camera device " << mHalCamera.begin()->first << " is not alive.";
+
+        // Return [0, 0, 0]
+        _hidl_cb(0, 0, 0);
+        return Void();
+    }
+
+    auto hwCamera_1_1 =
+        IEvsCamera_1_1::castFrom(pHwCamera->getHwCamera()).withDefault(nullptr);
+    if (hwCamera_1_1 != nullptr) {
+        return hwCamera_1_1->getIntParameterRange(id, _hidl_cb);
+    } else {
+        LOG(WARNING) << "Camera device " << mHalCamera.begin()->first
+                     << " does not support a parameter programming.";
+
+        // Return [0, 0, 0]
+        _hidl_cb(0, 0, 0);
+        return Void();
+    }
+    return Void();
+}
+
+
+Return<void> VirtualCamera::setIntParameter(CameraParam id,
+                                            int32_t value,
+                                            setIntParameter_cb _hidl_cb) {
+    hardware::hidl_vec<int32_t> values;
+    EvsResult status = EvsResult::INVALID_ARG;
+    if (mHalCamera.size() > 1) {
+        LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
+        _hidl_cb(status, values);
+        return Void();
+    }
+
+    auto pHwCamera = mHalCamera.begin()->second.promote();
+    if (pHwCamera == nullptr) {
+        LOG(WARNING) << "Camera device " << mHalCamera.begin()->first << " is not alive.";
+        _hidl_cb(status, values);
+        return Void();
+    }
+
+    status = pHwCamera->setParameter(this, id, value);
+
+    values.resize(1);
+    values[0] = value;
+    _hidl_cb(status, values);
+
+    return Void();
+}
+
+
+Return<void> VirtualCamera::getIntParameter(CameraParam id,
+                                            getIntParameter_cb _hidl_cb) {
+    hardware::hidl_vec<int32_t> values;
+    EvsResult status = EvsResult::INVALID_ARG;
+    if (mHalCamera.size() > 1) {
+        LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
+        _hidl_cb(status, values);
+        return Void();
+    }
+
+    auto pHwCamera = mHalCamera.begin()->second.promote();
+    if (pHwCamera == nullptr) {
+        LOG(WARNING) << "Camera device " << mHalCamera.begin()->first << " is not alive.";
+        _hidl_cb(status, values);
+        return Void();
+    }
+
+    int32_t value;
+    status = pHwCamera->getParameter(id, value);
+
+    values.resize(1);
+    values[0] = value;
+    _hidl_cb(status, values);
+
+    return Void();
+}
+
+
+Return<EvsResult> VirtualCamera::setExtendedInfo_1_1(uint32_t opaqueIdentifier,
+                                                     const hidl_vec<uint8_t>& opaqueValue) {
+    hardware::hidl_vec<int32_t> values;
+    if (mHalCamera.size() > 1) {
+        LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
+        return EvsResult::INVALID_ARG;
+    }
+
+    auto pHwCamera = mHalCamera.begin()->second.promote();
+    if (pHwCamera == nullptr) {
+        LOG(WARNING) << "Camera device " << mHalCamera.begin()->first << " is not alive.";
+        return EvsResult::INVALID_ARG;
+    } else {
+        auto hwCamera = IEvsCamera_1_1::castFrom(pHwCamera->getHwCamera()).withDefault(nullptr);
+        if (hwCamera != nullptr) {
+            return hwCamera->setExtendedInfo_1_1(opaqueIdentifier, opaqueValue);
+        } else {
+            LOG(ERROR) << "Underlying hardware camera does not implement v1.1 interfaces.";
+            return EvsResult::INVALID_ARG;
+        }
+    }
+}
+
+
+Return<void> VirtualCamera::getExtendedInfo_1_1(uint32_t opaqueIdentifier,
+                                                getExtendedInfo_1_1_cb _hidl_cb) {
+    hardware::hidl_vec<uint8_t> values;
+    EvsResult status = EvsResult::INVALID_ARG;
+    if (mHalCamera.size() > 1) {
+        LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
+        _hidl_cb(status, values);
+        return Void();
+    }
+
+    auto pHwCamera = mHalCamera.begin()->second.promote();
+    if (pHwCamera == nullptr) {
+        LOG(WARNING) << "Camera device " << mHalCamera.begin()->first << " is not alive.";
+        _hidl_cb(status, values);
+    } else {
+        auto hwCamera = IEvsCamera_1_1::castFrom(pHwCamera->getHwCamera()).withDefault(nullptr);
+        if (hwCamera != nullptr) {
+            hwCamera->getExtendedInfo_1_1(opaqueIdentifier, _hidl_cb);
+        } else {
+            LOG(ERROR) << "Underlying hardware camera does not implement v1.1 interfaces.";
+            _hidl_cb(status, values);
+        }
+    }
+
+    return Void();
+}
+
+
+Return<void>
+VirtualCamera::importExternalBuffers(const hidl_vec<BufferDesc_1_1>& buffers,
+                                     importExternalBuffers_cb _hidl_cb) {
+    if (mHalCamera.size() > 1) {
+        LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
+        _hidl_cb(EvsResult::UNDERLYING_SERVICE_ERROR, 0);
+        return {};
+    }
+
+    auto pHwCamera = mHalCamera.begin()->second.promote();
+    if (pHwCamera == nullptr) {
+        LOG(WARNING) << "Camera device " << mHalCamera.begin()->first << " is not alive.";
+        _hidl_cb(EvsResult::UNDERLYING_SERVICE_ERROR, 0);
+        return {};
+    }
+
+    int delta = 0;
+    if (!pHwCamera->changeFramesInFlight(buffers, &delta)) {
+        LOG(ERROR) << "Failed to add extenral capture buffers.";
+        _hidl_cb(EvsResult::UNDERLYING_SERVICE_ERROR, 0);
+        return {};
+    }
+
+    mFramesAllowed += delta;
+    _hidl_cb(EvsResult::OK, delta);
+    return {};
+}
+
+
+std::string VirtualCamera::toString(const char* indent) const {
+    std::string buffer;
+    StringAppendF(&buffer, "%sLogical camera device: %s\n"
+                           "%sFramesAllowed: %u\n"
+                           "%sFrames in use:\n",
+                           indent, mHalCamera.size() > 1 ? "T" : "F",
+                           indent, mFramesAllowed,
+                           indent);
+
+    std::string next_indent(indent);
+    next_indent += "\t";
+    for (auto&& [id, queue] : mFramesHeld) {
+        StringAppendF(&buffer, "%s%s: %d\n",
+                               next_indent.c_str(),
+                               id.c_str(),
+                               static_cast<int>(queue.size()));
+    }
+    StringAppendF(&buffer, "%sCurrent stream state: %d\n",
+                                 indent, mStreamState);
+
+    return buffer;
+}
+
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace android
diff --git a/evs/manager/1.1/VirtualCamera.h b/evs/manager/1.1/VirtualCamera.h
new file mode 100644
index 0000000..76a8648
--- /dev/null
+++ b/evs/manager/1.1/VirtualCamera.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUTOMOTIVE_EVS_V1_1_CAMERAPROXY_H
+#define ANDROID_AUTOMOTIVE_EVS_V1_1_CAMERAPROXY_H
+
+#include <android/hardware/automotive/evs/1.1/types.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+
+#include <thread>
+#include <deque>
+#include <unordered_map>
+
+
+using namespace std;
+using namespace ::android::hardware::automotive::evs::V1_1;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
+using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
+using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream;
+using IEvsCameraStream_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCameraStream;
+using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using IEvsDisplay_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+class HalCamera;        // From HalCamera.h
+
+
+// This class represents an EVS camera to the client application.  As such it presents
+// the IEvsCamera interface, and also proxies the frame delivery to the client's
+// IEvsCameraStream object.
+class VirtualCamera : public IEvsCamera_1_1 {
+public:
+    explicit          VirtualCamera(const std::vector<sp<HalCamera>>& halCameras);
+    virtual           ~VirtualCamera();
+
+    unsigned          getAllowedBuffers() { return mFramesAllowed; };
+    bool              isStreaming()       { return mStreamState == RUNNING; }
+    bool              getVersion() const  { return (int)(mStream_1_1 != nullptr); }
+    vector<sp<HalCamera>>
+                      getHalCameras();
+    void              setDescriptor(CameraDesc* desc) { mDesc = desc; }
+
+    // Proxy to receive frames and forward them to the client's stream
+    bool              notify(const EvsEventDesc& event);
+    bool              deliverFrame(const BufferDesc& bufDesc);
+
+    // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
+    Return<void>      getCameraInfo(getCameraInfo_cb _hidl_cb)  override;
+    Return<EvsResult> setMaxFramesInFlight(uint32_t bufferCount) override;
+    Return<EvsResult> startVideoStream(const ::android::sp<IEvsCameraStream_1_0>& stream) override;
+    Return<void>      doneWithFrame(const BufferDesc_1_0& buffer) override;
+    Return<void>      stopVideoStream() override;
+    Return<int32_t>   getExtendedInfo(uint32_t opaqueIdentifier) override;
+    Return<EvsResult> setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override;
+
+    // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
+    Return<void>      getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb)  override;
+    Return<void>      getPhysicalCameraInfo(const hidl_string& deviceId,
+                                            getPhysicalCameraInfo_cb _hidl_cb)  override;
+    Return<EvsResult> doneWithFrame_1_1(const hardware::hidl_vec<BufferDesc_1_1>& buffer) override;
+    Return<EvsResult> pauseVideoStream() override { return EvsResult::UNDERLYING_SERVICE_ERROR; }
+    Return<EvsResult> resumeVideoStream() override { return EvsResult::UNDERLYING_SERVICE_ERROR; }
+    Return<EvsResult> setMaster() override;
+    Return<EvsResult> forceMaster(const sp<IEvsDisplay_1_0>& display) override;
+    Return<EvsResult> unsetMaster() override;
+    Return<void>      getParameterList(getParameterList_cb _hidl_cb) override;
+    Return<void>      getIntParameterRange(CameraParam id,
+                                           getIntParameterRange_cb _hidl_cb) override;
+    Return<void>      setIntParameter(CameraParam id, int32_t value,
+                                      setIntParameter_cb _hidl_cb) override;
+    Return<void>      getIntParameter(CameraParam id,
+                                      getIntParameter_cb _hidl_cb) override;
+    Return<EvsResult> setExtendedInfo_1_1(uint32_t opaqueIdentifier,
+                                          const hidl_vec<uint8_t>& opaqueValue) override;
+    Return<void>      getExtendedInfo_1_1(uint32_t opaqueIdentifier,
+                                          getExtendedInfo_1_1_cb _hidl_cb) override;
+    Return<void>      importExternalBuffers(const hidl_vec<BufferDesc_1_1>& buffers,
+                                            importExternalBuffers_cb _hidl_cb) override;
+
+    // Dump current status to a given file descriptor
+    std::string       toString(const char* indent = "") const;
+
+
+private:
+    void shutdown();
+
+    // The low level camera interface that backs this proxy
+    unordered_map<string,
+                 wp<HalCamera>> mHalCamera;
+
+    sp<IEvsCameraStream_1_0>    mStream;
+    sp<IEvsCameraStream_1_1>    mStream_1_1;
+
+    unsigned                    mFramesAllowed  = 1;
+    enum {
+        STOPPED,
+        RUNNING,
+        STOPPING,
+    }                           mStreamState;
+
+    unordered_map<string,
+         deque<BufferDesc_1_1>> mFramesHeld;
+    thread                      mCaptureThread;
+    CameraDesc*                 mDesc;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace android
+
+#endif  // ANDROID_AUTOMOTIVE_EVS_V1_1_CAMERAPROXY_H
diff --git a/evs/manager/1.1/android.automotive.evs.manager@1.1.rc b/evs/manager/1.1/android.automotive.evs.manager@1.1.rc
new file mode 100644
index 0000000..41212e2
--- /dev/null
+++ b/evs/manager/1.1/android.automotive.evs.manager@1.1.rc
@@ -0,0 +1,7 @@
+service evs_manager /system/bin/android.automotive.evs.manager@1.1
+    class hal
+    priority -20
+    user automotive_evs
+    group automotive_evs system
+    onrestart restart evs_app
+    disabled # will not automatically start with its class; must be explictly started.
diff --git a/evs/manager/1.1/manifest_android.automotive.evs.manager@1.1.xml b/evs/manager/1.1/manifest_android.automotive.evs.manager@1.1.xml
new file mode 100644
index 0000000..617e325
--- /dev/null
+++ b/evs/manager/1.1/manifest_android.automotive.evs.manager@1.1.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest version="1.0" type="framework" >
+    <hal format="hidl">
+        <name>android.hardware.automotive.evs</name>
+        <transport>hwbinder</transport>
+        <version>1.1</version>
+        <interface>
+            <name>IEvsEnumerator</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/evs/manager/1.1/service.cpp b/evs/manager/1.1/service.cpp
new file mode 100644
index 0000000..2210ab9
--- /dev/null
+++ b/evs/manager/1.1/service.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+#include <utils/Log.h>
+
+#include "ServiceNames.h"
+#include "Enumerator.h"
+
+
+// libhidl:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::automotive::evs::V1_1::IEvsEnumerator;
+using android::hardware::automotive::evs::V1_0::IEvsDisplay;
+
+// The namespace in which all our implementation code lives
+using namespace android::automotive::evs::V1_1::implementation;
+using namespace android;
+
+
+static void startService(const char *hardwareServiceName, const char * managerServiceName) {
+    LOG(INFO) << "EVS managed service connecting to hardware service at " << hardwareServiceName;
+    android::sp<Enumerator> service = new Enumerator();
+    if (!service->init(hardwareServiceName)) {
+        LOG(ERROR) << "Failed to connect to hardware service - quitting from registrationThread";
+        exit(1);
+    }
+
+    // Register our service -- if somebody is already registered by our name,
+    // they will be killed (their thread pool will throw an exception).
+    LOG(INFO) << "EVS managed service is starting as " << managerServiceName;
+    status_t status = service->registerAsService(managerServiceName);
+    if (status != OK) {
+        LOG(ERROR) << "Could not register service " << managerServiceName
+                   << " status = " << status << " - quitting from registrationThread";
+        exit(2);
+    }
+
+    LOG(INFO) << "Registration complete";
+}
+
+
+int main(int argc, char** argv) {
+    LOG(INFO) << "EVS manager starting";
+
+#ifdef EVS_DEBUG
+    SetMinimumLogSeverity(android::base::DEBUG);
+#endif
+
+    // Set up default behavior, then check for command line options
+    bool printHelp = false;
+    const char* evsHardwareServiceName = kHardwareEnumeratorName;
+    for (int i=1; i< argc; i++) {
+        if (strcmp(argv[i], "--mock") == 0) {
+            evsHardwareServiceName = kMockEnumeratorName;
+        } else if (strcmp(argv[i], "--target") == 0) {
+            i++;
+            if (i >= argc) {
+                LOG(ERROR) << "--target <service> was not provided with a service name";
+            } else {
+                evsHardwareServiceName = argv[i];
+            }
+        } else if (strcmp(argv[i], "--help") == 0) {
+            printHelp = true;
+        } else {
+            printf("Ignoring unrecognized command line arg '%s'\n", argv[i]);
+            printHelp = true;
+        }
+    }
+    if (printHelp) {
+        printf("Options include:\n");
+        printf("  --mock                   Connect to the mock driver at EvsEnumeratorHw-Mock\n");
+        printf("  --target <service_name>  Connect to the named IEvsEnumerator service");
+    }
+
+
+    // Prepare the RPC serving thread pool.  We're configuring it with no additional
+    // threads beyond the main thread which will "join" the pool below.
+    configureRpcThreadpool(1, true /* callerWillJoin */);
+
+    // The connection to the underlying hardware service must happen on a dedicated thread to ensure
+    // that the hwbinder response can be processed by the thread pool without blocking.
+    std::thread registrationThread(startService, evsHardwareServiceName, kManagedEnumeratorName);
+
+    // Send this main thread to become a permanent part of the thread pool.
+    // This is not expected to return.
+    LOG(INFO) << "Main thread entering thread pool";
+    joinRpcThreadpool();
+
+    // In normal operation, we don't expect the thread pool to exit
+    LOG(ERROR) << "EVS Hardware Enumerator is shutting down";
+    return 1;
+}
diff --git a/evs/manager/1.1/stats/CameraUsageStats.cpp b/evs/manager/1.1/stats/CameraUsageStats.cpp
new file mode 100644
index 0000000..593577e
--- /dev/null
+++ b/evs/manager/1.1/stats/CameraUsageStats.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CameraUsageStats.h"
+
+#include <statslog.h>
+
+#include <android-base/logging.h>
+
+namespace {
+
+    // Length of frame roundtrip history
+    const int kMaxHistoryLength = 100;
+
+}
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::base::Result;
+using ::android::base::StringAppendF;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::automotive::evs::V1_1::BufferDesc;
+
+void CameraUsageStats::updateFrameStatsOnArrival(
+        const hidl_vec<BufferDesc>& bufs) {
+    const auto now = android::uptimeMillis();
+    for (const auto& b : bufs) {
+        auto it = mBufferHistory.find(b.bufferId);
+        if (it == mBufferHistory.end()) {
+            mBufferHistory.emplace(b.bufferId, now);
+        } else {
+            it->second.timestamp = now;
+        }
+    }
+}
+
+
+void CameraUsageStats::updateFrameStatsOnReturn(
+        const hidl_vec<BufferDesc>& bufs) {
+    const auto now = android::uptimeMillis();
+    for (auto& b : bufs) {
+        auto it = mBufferHistory.find(b.bufferId);
+        if (it == mBufferHistory.end()) {
+            LOG(WARNING) << "Buffer " << b.bufferId << " from "
+                         << b.deviceId << " is unknown.";
+        } else {
+            const auto roundtrip = now - it->second.timestamp;
+            it->second.history.emplace(roundtrip);
+            it->second.sum += roundtrip;
+            if (it->second.history.size() > kMaxHistoryLength) {
+                it->second.sum -= it->second.history.front();
+                it->second.history.pop();
+            }
+
+            if (roundtrip > it->second.peak) {
+                it->second.peak = roundtrip;
+            }
+
+            if (mStats.framesFirstRoundtripLatency == 0) {
+                mStats.framesFirstRoundtripLatency = roundtrip;
+            }
+        }
+    }
+}
+
+
+void CameraUsageStats::framesReceived(int n) {
+    AutoMutex lock(mMutex);
+    mStats.framesReceived += n;
+}
+
+
+void CameraUsageStats::framesReceived(
+        const hidl_vec<BufferDesc>& bufs) {
+    AutoMutex lock(mMutex);
+    mStats.framesReceived += bufs.size();
+
+    updateFrameStatsOnArrival(bufs);
+}
+
+
+void CameraUsageStats::framesReturned(int n) {
+    AutoMutex lock(mMutex);
+    mStats.framesReturned += n;
+}
+
+
+void CameraUsageStats::framesReturned(
+        const hidl_vec<BufferDesc>& bufs) {
+    AutoMutex lock(mMutex);
+    mStats.framesReturned += bufs.size();
+
+    updateFrameStatsOnReturn(bufs);
+}
+
+
+void CameraUsageStats::framesIgnored(int n) {
+    AutoMutex lock(mMutex);
+    mStats.framesIgnored += n;
+}
+
+
+void CameraUsageStats::framesSkippedToSync(int n) {
+    AutoMutex lock(mMutex);
+    mStats.framesSkippedToSync += n;
+}
+
+
+void CameraUsageStats::eventsReceived() {
+    AutoMutex lock(mMutex);
+    ++mStats.erroneousEventsCount;
+}
+
+
+void CameraUsageStats::updateNumClients(size_t n) {
+    AutoMutex lock(mMutex);
+    if (n > mStats.peakClientsCount) {
+        mStats.peakClientsCount = n;
+    }
+}
+
+
+int64_t CameraUsageStats::getTimeCreated() const {
+    AutoMutex lock(mMutex);
+    return mTimeCreatedMs;
+}
+
+
+int64_t CameraUsageStats::getFramesReceived() const {
+    AutoMutex lock(mMutex);
+    return mStats.framesReceived;
+}
+
+
+int64_t CameraUsageStats::getFramesReturned() const {
+    AutoMutex lock(mMutex);
+    return mStats.framesReturned;
+}
+
+
+CameraUsageStatsRecord CameraUsageStats::snapshot() {
+    AutoMutex lock(mMutex);
+
+    int32_t sum = 0;
+    int32_t peak = 0;
+    int32_t len = 0;
+    for (auto& [id, rec] : mBufferHistory) {
+        sum += rec.sum;
+        len += rec.history.size();
+        if (peak < rec.peak) {
+            peak = rec.peak;
+        }
+    }
+
+    mStats.framesPeakRoundtripLatency = peak;
+    mStats.framesAvgRoundtripLatency = (double)sum / len;
+    return mStats;
+}
+
+
+Result<void> CameraUsageStats::writeStats() const {
+    AutoMutex lock(mMutex);
+
+    // Reports the usage statistics before the destruction
+    // EvsUsageStatsReported atom is defined in
+    // frameworks/base/cmds/statsd/src/atoms.proto
+    const auto duration = android::uptimeMillis() - mTimeCreatedMs;
+    android::util::stats_write(android::util::EVS_USAGE_STATS_REPORTED,
+                               mId,
+                               mStats.peakClientsCount,
+                               mStats.erroneousEventsCount,
+                               mStats.framesFirstRoundtripLatency,
+                               mStats.framesAvgRoundtripLatency,
+                               mStats.framesPeakRoundtripLatency,
+                               mStats.framesReceived,
+                               mStats.framesIgnored,
+                               mStats.framesSkippedToSync,
+                               duration);
+    return {};
+}
+
+
+std::string CameraUsageStats::toString(const CameraUsageStatsRecord& record, const char* indent) {
+    return record.toString(indent);
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace android
+
diff --git a/evs/manager/1.1/stats/CameraUsageStats.h b/evs/manager/1.1/stats/CameraUsageStats.h
new file mode 100644
index 0000000..7a7224d
--- /dev/null
+++ b/evs/manager/1.1/stats/CameraUsageStats.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUTOMOTIVE_EVS_V1_1_CAMERAUSAGESTATS_H
+#define ANDROID_AUTOMOTIVE_EVS_V1_1_CAMERAUSAGESTATS_H
+
+#include <queue>
+#include <unordered_map>
+
+#include <inttypes.h>
+
+#include <android/hardware/automotive/evs/1.1/types.h>
+#include <android-base/result.h>
+#include <android-base/stringprintf.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+#include <utils/SystemClock.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+struct CameraUsageStatsRecord {
+public:
+    // Time a snapshot is generated
+    nsecs_t timestamp;
+
+    // Total number of frames received
+    int64_t framesReceived;
+
+    // Total number of frames returned to EVS HAL
+    int64_t framesReturned;
+
+    // Number of frames ignored because no clients are listening
+    int64_t framesIgnored;
+
+    // Number of frames skipped to synchronize camera frames
+    int64_t framesSkippedToSync;
+
+    // Roundtrip latency of the very first frame after the stream started.
+    int64_t framesFirstRoundtripLatency;
+
+    // Peak mFrame roundtrip latency
+    int64_t framesPeakRoundtripLatency;
+
+    // Average mFrame roundtrip latency
+    double  framesAvgRoundtripLatency;
+
+    // Number of the erroneous streaming events
+    int32_t erroneousEventsCount;
+
+    // Peak number of active clients
+    int32_t peakClientsCount;
+
+    // Calculates a delta between two records
+    CameraUsageStatsRecord& operator-=(const CameraUsageStatsRecord& rhs) {
+        // Only calculates differences in the frame statistics
+        framesReceived = framesReceived - rhs.framesReceived;
+        framesReturned = framesReturned - rhs.framesReturned;
+        framesIgnored = framesIgnored - rhs.framesIgnored;
+        framesSkippedToSync = framesSkippedToSync - rhs.framesSkippedToSync;
+        erroneousEventsCount = erroneousEventsCount - rhs.erroneousEventsCount;
+
+        return *this;
+    }
+
+    friend CameraUsageStatsRecord operator-(CameraUsageStatsRecord lhs,
+                                      const CameraUsageStatsRecord& rhs) noexcept {
+        lhs -= rhs; // reuse compound assignment
+        return lhs;
+    }
+
+    // Constructs a string that shows collected statistics
+    std::string toString(const char* indent = "") const {
+        std::string buffer;
+        android::base::StringAppendF(&buffer,
+                "%sTime Collected: @%" PRId64 "ms\n"
+                "%sFrames Received: %" PRId64 "\n"
+                "%sFrames Returned: %" PRId64 "\n"
+                "%sFrames Ignored : %" PRId64 "\n"
+                "%sFrames Skipped To Sync: %" PRId64 "\n"
+                "%sFrames First Roundtrip: %" PRId64 "\n"
+                "%sFrames Peak Roundtrip: %" PRId64 "\n"
+                "%sFrames Average Roundtrip: %f\n"
+                "%sPeak Number of Clients: %" PRId32 "\n\n",
+                indent, ns2ms(timestamp),
+                indent, framesReceived,
+                indent, framesReturned,
+                indent, framesIgnored,
+                indent, framesSkippedToSync,
+                indent, framesFirstRoundtripLatency,
+                indent, framesPeakRoundtripLatency,
+                indent, framesAvgRoundtripLatency,
+                indent, peakClientsCount);
+
+        return buffer;
+    }
+};
+
+
+struct BufferRecord {
+    BufferRecord(int64_t timestamp) :
+        timestamp(timestamp),
+        sum(0),
+        peak(0) {}
+
+    // Recent processing time
+    std::queue<int32_t> history;
+
+    // Timestamp on the buffer arrival
+    int64_t timestamp;
+
+    // Sum of processing times
+    int64_t sum;
+
+    // Peak processing time
+    int64_t peak;
+};
+
+
+class CameraUsageStats : public RefBase {
+public:
+    CameraUsageStats(int32_t id)
+        : mMutex(Mutex()),
+          mId(id),
+          mTimeCreatedMs(android::uptimeMillis()),
+          mStats({}) {}
+
+private:
+    // Mutex to protect a collection record
+    mutable Mutex mMutex;
+
+    // Unique identifier
+    int32_t mId;
+
+    // Time this object was created
+    int64_t mTimeCreatedMs;
+
+    // Usage statistics to collect
+    CameraUsageStatsRecord mStats GUARDED_BY(mMutex);
+
+    // Frame buffer histories
+    std::unordered_map<int, BufferRecord> mBufferHistory GUARDED_BY(mMutex);
+
+public:
+    void framesReceived(int n = 1) EXCLUDES(mMutex);
+    void framesReturned(int n = 1) EXCLUDES(mMutex);
+    void framesReceived(
+            const hardware::hidl_vec<::android::hardware::automotive::evs::V1_1::BufferDesc>& bufs
+        ) EXCLUDES(mMutex);
+    void framesReturned(
+            const hardware::hidl_vec<::android::hardware::automotive::evs::V1_1::BufferDesc>& bufs
+        ) EXCLUDES(mMutex);
+    void framesIgnored(int n = 1) EXCLUDES(mMutex);
+    void framesSkippedToSync(int n = 1) EXCLUDES(mMutex);
+    void eventsReceived() EXCLUDES(mMutex);
+    int64_t getTimeCreated() const EXCLUDES(mMutex);
+    int64_t getFramesReceived() const EXCLUDES(mMutex);
+    int64_t getFramesReturned() const EXCLUDES(mMutex);
+    void updateNumClients(size_t n) EXCLUDES(mMutex);
+    void updateFrameStatsOnArrival(
+            const hardware::hidl_vec<::android::hardware::automotive::evs::V1_1::BufferDesc>& bufs
+        ) REQUIRES(mMutex);
+    void updateFrameStatsOnReturn(
+            const hardware::hidl_vec<::android::hardware::automotive::evs::V1_1::BufferDesc>& bufs
+        ) REQUIRES(mMutex);
+
+    // Returns the statistics collected so far
+    CameraUsageStatsRecord snapshot() EXCLUDES(mMutex);
+
+    // Reports the usage statistics
+    android::base::Result<void> writeStats() const EXCLUDES(mMutex);
+
+    // Generates a string with current statistics
+    static std::string toString(const CameraUsageStatsRecord& record, const char* indent = "");
+};
+
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace android
+
+#endif // ANDROID_AUTOMOTIVE_EVS_V1_1_CAMERAUSAGESTATS_H
diff --git a/evs/manager/1.1/stats/LooperWrapper.cpp b/evs/manager/1.1/stats/LooperWrapper.cpp
new file mode 100644
index 0000000..041a723
--- /dev/null
+++ b/evs/manager/1.1/stats/LooperWrapper.cpp
@@ -0,0 +1,82 @@
+/**
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LooperWrapper.h"
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+using android::sp;
+
+void LooperWrapper::wake() {
+    if (mLooper == nullptr) {
+        LOG(WARNING) << __FUNCTION__ << ": Looper is invalid.";
+        return;
+    }
+
+    return mLooper->wake();
+}
+
+int LooperWrapper::pollAll(int timeoutMillis) {
+    if (mLooper == nullptr) {
+        LOG(WARNING) << __FUNCTION__ << ": Looper is invalid.";
+        return 0;
+    }
+
+    return mLooper->pollAll(timeoutMillis);
+}
+
+void LooperWrapper::sendMessage(const sp<MessageHandler>& handler,
+                                   const Message& message) {
+    if (mLooper == nullptr) {
+        LOG(WARNING) << __FUNCTION__ << ": Looper is invalid.";
+        return;
+    }
+
+    return mLooper->sendMessage(handler, message);
+}
+
+void LooperWrapper::sendMessageAtTime(nsecs_t uptime,
+                                         const sp<MessageHandler>& handler,
+                                         const Message& message) {
+    if (mLooper == nullptr) {
+        LOG(WARNING) << __FUNCTION__ << ": Looper is invalid.";
+        return;
+    }
+
+    return mLooper->sendMessageAtTime(uptime, handler, message);
+}
+
+void LooperWrapper::removeMessages(const sp<MessageHandler>& handler) {
+    if (mLooper == nullptr) {
+        LOG(WARNING) << __FUNCTION__ << ": Looper is invalid.";
+        return;
+    }
+
+    return mLooper->removeMessages(handler);
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace android
+
diff --git a/evs/manager/1.1/stats/LooperWrapper.h b/evs/manager/1.1/stats/LooperWrapper.h
new file mode 100644
index 0000000..fb9ec12
--- /dev/null
+++ b/evs/manager/1.1/stats/LooperWrapper.h
@@ -0,0 +1,57 @@
+/**
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUTMOTIVE_EVS_V1_1_EVSLOOPERWRAPPER_H_
+#define ANDROID_AUTMOTIVE_EVS_V1_1_EVSLOOPERWRAPPER_H_
+
+#include <utils/Looper.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+// This class wraps around android::Looper methods.  Please refer to
+// utils/Looper.h for the details.
+class LooperWrapper : public RefBase {
+public:
+    LooperWrapper() : mLooper(nullptr) {}
+    virtual ~LooperWrapper() {}
+
+    void setLooper(android::sp<Looper> looper) { mLooper = looper; }
+    void wake();
+    virtual nsecs_t now() { return systemTime(SYSTEM_TIME_MONOTONIC); }
+    virtual int pollAll(int timeoutMillis);
+    virtual void sendMessage(const android::sp<MessageHandler>& handler, const Message& message);
+    virtual void sendMessageAtTime(nsecs_t uptime, const android::sp<MessageHandler>& handler,
+                                   const Message& message);
+    virtual void removeMessages(const android::sp<MessageHandler>& handler);
+
+protected:
+    android::sp<Looper> mLooper;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace android
+
+#endif  // ANDROID_AUTMOTIVE_EVS_V1_1_EVSLOOPERWRAPPER_H_
+
diff --git a/evs/manager/1.1/stats/StatsCollector.cpp b/evs/manager/1.1/stats/StatsCollector.cpp
new file mode 100644
index 0000000..b57f928
--- /dev/null
+++ b/evs/manager/1.1/stats/StatsCollector.cpp
@@ -0,0 +1,468 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "HalCamera.h"
+#include "StatsCollector.h"
+#include "VirtualCamera.h"
+
+#include <processgroup/sched_policy.h>
+#include <pthread.h>
+
+#include <android-base/file.h>
+#include <android-base/strings.h>
+#include <android-base/stringprintf.h>
+#include <utils/SystemClock.h>
+
+namespace {
+
+    const char* kSingleIndent = "\t";
+    const char* kDoubleIndent = "\t\t";
+    const char* kDumpAllDevices = "all";
+
+}
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+using android::base::Error;
+using android::base::EqualsIgnoreCase;
+using android::base::Result;
+using android::base::StringAppendF;
+using android::base::StringPrintf;
+using android::base::WriteStringToFd;
+using android::hardware::automotive::evs::V1_1::BufferDesc;
+
+namespace {
+
+const auto kPeriodicCollectionInterval = 10s;
+const auto kPeriodicCollectionCacheSize = 180;
+const auto kMinCollectionInterval = 1s;
+const auto kCustomCollectionMaxDuration = 30min;
+const auto kMaxDumpHistory = 10;
+
+}
+
+void StatsCollector::handleMessage(const Message& message) {
+    const auto received = static_cast<CollectionEvent>(message.what);
+    Result<void> ret;
+    switch (received) {
+        case CollectionEvent::PERIODIC:
+            ret = handleCollectionEvent(received, &mPeriodicCollectionInfo);
+            break;
+
+        case CollectionEvent::CUSTOM_START:
+            ret = handleCollectionEvent(received, &mCustomCollectionInfo);
+            break;
+
+        case CollectionEvent::CUSTOM_END: {
+            AutoMutex lock(mMutex);
+            if (mCurrentCollectionEvent != CollectionEvent::CUSTOM_START) {
+                LOG(WARNING) << "Ignoring a message to end custom collection "
+                             << "as current collection is " << toString(mCurrentCollectionEvent);
+                return;
+            }
+
+            // Starts a periodic collection
+            mLooper->removeMessages(this);
+            mCurrentCollectionEvent = CollectionEvent::PERIODIC;
+            mPeriodicCollectionInfo.lastCollectionTime = mLooper->now();
+            mLooper->sendMessage(this, CollectionEvent::PERIODIC);
+            return;
+        }
+
+        default:
+            LOG(WARNING) << "Unknown event is received: " << received;
+            break;
+    }
+
+    if (!ret.ok()) {
+        Mutex::Autolock lock(mMutex);
+        LOG(ERROR) << "Terminating data collection: "
+                   << ret.error();
+
+        mCurrentCollectionEvent = CollectionEvent::TERMINATED;
+        mLooper->removeMessages(this);
+        mLooper->wake();
+    }
+}
+
+
+Result<void> StatsCollector::handleCollectionEvent(CollectionEvent event,
+                                                   CollectionInfo* info) {
+    AutoMutex lock(mMutex);
+    if (mCurrentCollectionEvent != event) {
+        LOG(WARNING) << "Skipping " << toString(event) << " collection event "
+                     << "on collection event " << toString(mCurrentCollectionEvent);
+        return {};
+    }
+
+    if (info->maxCacheSize < 1) {
+        return Error() << "Maximum cache size must be greater than 0";
+    }
+
+    using std::chrono::duration_cast;
+    using std::chrono::seconds;
+    if (info->interval < kMinCollectionInterval) {
+        LOG(WARNING) << "Collection interval of "
+                     << duration_cast<seconds>(info->interval).count()
+                     << " seconds for " << toString(event)
+                     << " collection cannot be shorter than "
+                     << duration_cast<seconds>(kMinCollectionInterval).count()
+                     << " seconds.";
+        info->interval = kMinCollectionInterval;
+    }
+
+    auto ret = collectLocked(info);
+    if (!ret) {
+        return Error() << toString(event) << " collection failed: "
+                       << ret.error();
+    }
+
+    // Arms a message for next periodic collection
+    info->lastCollectionTime += info->interval.count();
+    mLooper->sendMessageAtTime(info->lastCollectionTime, this, event);
+    return {};
+}
+
+
+Result<void> StatsCollector::collectLocked(CollectionInfo* info) REQUIRES(mMutex) {
+    for (auto&& [id, ptr] : mClientsToMonitor) {
+        auto pClient = ptr.promote();
+        if (!pClient) {
+            LOG(DEBUG) << id << " seems not alive.";
+            continue;
+        }
+
+        // Pulls a snapshot and puts a timestamp
+        auto snapshot = pClient->getStats();
+        snapshot.timestamp = mLooper->now();
+
+        // Removes the oldest record if cache is full
+        if (info->records[id].history.size() > info->maxCacheSize) {
+            info->records[id].history.pop_front();
+        }
+
+        // Stores the latest record and the deltas
+        auto delta = snapshot - info->records[id].latest;
+        info->records[id].history.emplace_back(delta);
+        info->records[id].latest = snapshot;
+    }
+
+    return {};
+}
+
+
+Result<void> StatsCollector::startCollection() {
+    {
+        AutoMutex lock(mMutex);
+        if (mCurrentCollectionEvent != CollectionEvent::INIT ||
+            mCollectionThread.joinable()) {
+            return Error(INVALID_OPERATION)
+                   << "Camera usages collection is already running.";
+        }
+
+        // Create the collection info w/ the default values
+        mPeriodicCollectionInfo = {
+            .interval = kPeriodicCollectionInterval,
+            .maxCacheSize = kPeriodicCollectionCacheSize,
+            .lastCollectionTime = 0,
+        };
+
+    }
+
+    // Starts a background worker thread
+    mCollectionThread = std::thread([&]() {
+        {
+            AutoMutex lock(mMutex);
+            if (mCurrentCollectionEvent != CollectionEvent::INIT) {
+                LOG(ERROR) << "Skipping the statistics collection because "
+                           << "the current collection event is "
+                           << toString(mCurrentCollectionEvent);
+                return;
+            }
+
+            // Staring with a periodic collection
+            mCurrentCollectionEvent = CollectionEvent::PERIODIC;
+        }
+
+        if (set_sched_policy(0, SP_BACKGROUND) != 0) {
+            PLOG(WARNING) << "Failed to set background scheduling prioirty";
+        }
+
+        // Sets a looper for the communication
+        mLooper->setLooper(Looper::prepare(/*opts=*/0));
+
+        // Starts collecting the usage statistics periodically
+        mLooper->sendMessage(this, CollectionEvent::PERIODIC);
+
+        // Polls the messages until the collection is stopped.
+        bool isActive = true;
+        while (isActive) {
+            mLooper->pollAll(/*timeoutMillis=*/-1);
+            {
+                AutoMutex lock(mMutex);
+                isActive = mCurrentCollectionEvent != CollectionEvent::TERMINATED;
+            }
+        }
+    });
+
+    auto ret = pthread_setname_np(mCollectionThread.native_handle(), "EvsUsageCollect");
+    if (ret != 0) {
+        PLOG(WARNING) << "Failed to name a collection thread";
+    }
+
+    return {};
+}
+
+
+Result<void> StatsCollector::stopCollection() {
+    {
+        AutoMutex lock(mMutex);
+        if (mCurrentCollectionEvent == CollectionEvent::TERMINATED) {
+            LOG(WARNING) << "Camera usage data collection was stopped already.";
+            return {};
+        }
+
+        LOG(INFO) << "Stopping a camera usage data collection";
+        mCurrentCollectionEvent = CollectionEvent::TERMINATED;
+    }
+
+    // Join a background thread
+    if (mCollectionThread.joinable()) {
+        mLooper->removeMessages(this);
+        mLooper->wake();
+        mCollectionThread.join();
+    }
+
+    return {};
+}
+
+
+Result<void> StatsCollector::startCustomCollection(
+        std::chrono::nanoseconds interval,
+        std::chrono::nanoseconds maxDuration) {
+    using std::chrono::duration_cast;
+    using std::chrono::milliseconds;
+    if (interval < kMinCollectionInterval || maxDuration < kMinCollectionInterval) {
+        return Error(INVALID_OPERATION)
+                << "Collection interval and maximum maxDuration must be >= "
+                << duration_cast<milliseconds>(kMinCollectionInterval).count()
+                << " milliseconds.";
+    }
+
+    if (maxDuration > kCustomCollectionMaxDuration) {
+        return Error(INVALID_OPERATION)
+                << "Collection maximum maxDuration must be less than "
+                << duration_cast<milliseconds>(kCustomCollectionMaxDuration).count()
+                << " milliseconds.";
+    }
+
+    {
+        AutoMutex lock(mMutex);
+        if (mCurrentCollectionEvent != CollectionEvent::PERIODIC) {
+            return Error(INVALID_OPERATION)
+                    << "Cannot start a custom collection when "
+                    << "the current collection event " << toString(mCurrentCollectionEvent)
+                    << " != " << toString(CollectionEvent::PERIODIC) << " collection event";
+        }
+
+        // Notifies the user if a preview custom collection result is
+        // not used yet.
+        if (mCustomCollectionInfo.records.size() > 0) {
+            LOG(WARNING) << "Previous custom collection result, which was done at "
+                         << mCustomCollectionInfo.lastCollectionTime
+                         << " has not pulled yet will be overwritten.";
+        }
+
+        // Programs custom collection configurations
+        mCustomCollectionInfo = {
+                .interval = interval,
+                .maxCacheSize = std::numeric_limits<std::size_t>::max(),
+                .lastCollectionTime = mLooper->now(),
+                .records = {},
+        };
+
+        mLooper->removeMessages(this);
+        nsecs_t uptime = mLooper->now() + maxDuration.count();
+        mLooper->sendMessageAtTime(uptime, this, CollectionEvent::CUSTOM_END);
+        mCurrentCollectionEvent = CollectionEvent::CUSTOM_START;
+        mLooper->sendMessage(this, CollectionEvent::CUSTOM_START);
+    }
+
+    return {};
+}
+
+
+Result<std::string> StatsCollector::stopCustomCollection(std::string targetId) {
+    Mutex::Autolock lock(mMutex);
+    if (mCurrentCollectionEvent == CollectionEvent::CUSTOM_START) {
+        // Stops a running custom collection
+        mLooper->removeMessages(this);
+        mLooper->sendMessage(this, CollectionEvent::CUSTOM_END);
+    }
+
+    auto ret = collectLocked(&mCustomCollectionInfo);
+    if (!ret) {
+        return Error() << toString(mCurrentCollectionEvent) << " collection failed: "
+                       << ret.error();
+    }
+
+    // Prints out the all collected statistics
+    std::string buffer;
+    using std::chrono::duration_cast;
+    using std::chrono::seconds;
+    const intmax_t interval =
+        duration_cast<seconds>(mCustomCollectionInfo.interval).count();
+    if (EqualsIgnoreCase(targetId, kDumpAllDevices)) {
+        for (auto& [id, records] : mCustomCollectionInfo.records) {
+
+            StringAppendF(&buffer, "%s\n"
+                                   "%sNumber of collections: %zu\n"
+                                   "%sCollection interval: %" PRIdMAX " secs\n",
+                                   id.c_str(),
+                                   kSingleIndent, records.history.size(),
+                                   kSingleIndent, interval);
+            auto it = records.history.rbegin();
+            while (it != records.history.rend()) {
+                buffer += it++->toString(kDoubleIndent);
+            }
+        }
+
+        // Clears the collection
+        mCustomCollectionInfo = {};
+    } else {
+        auto it = mCustomCollectionInfo.records.find(targetId);
+        if (it != mCustomCollectionInfo.records.end()) {
+            StringAppendF(&buffer, "%s\n"
+                                   "%sNumber of collections: %zu\n"
+                                   "%sCollection interval: %" PRIdMAX " secs\n",
+                                   targetId.c_str(),
+                                   kSingleIndent, it->second.history.size(),
+                                   kSingleIndent, interval);
+            auto recordIter = it->second.history.rbegin();
+            while (recordIter != it->second.history.rend()) {
+                buffer += recordIter++->toString(kDoubleIndent);
+            }
+
+            // Clears the collection
+            mCustomCollectionInfo = {};
+        } else {
+            // Keeps the collection as the users may want to execute a command
+            // again with a right device id
+            StringAppendF(&buffer, "%s has not been monitored.", targetId.c_str());
+        }
+    }
+
+    return buffer;
+}
+
+
+Result<void> StatsCollector::registerClientToMonitor(android::sp<HalCamera>& camera) {
+    if (!camera) {
+        return Error(BAD_VALUE) << "Given camera client is invalid";
+    }
+
+    AutoMutex lock(mMutex);
+    const auto id = camera->getId();
+    if (mClientsToMonitor.find(id) != mClientsToMonitor.end()) {
+        LOG(WARNING) << id << " is already registered.";
+    } else {
+        mClientsToMonitor.insert_or_assign(id, camera);
+    }
+
+    return {};
+}
+
+
+Result<void> StatsCollector::unregisterClientToMonitor(const std::string& id) {
+    AutoMutex lock(mMutex);
+    auto entry = mClientsToMonitor.find(id);
+    if (entry != mClientsToMonitor.end()) {
+        mClientsToMonitor.erase(entry);
+    } else {
+        LOG(WARNING) << id << " has not been registerd.";
+    }
+
+    return {};
+}
+
+
+std::string StatsCollector::toString(const CollectionEvent& event) const {
+    switch(event) {
+        case CollectionEvent::INIT:
+            return "CollectionEvent::INIT";
+        case CollectionEvent::PERIODIC:
+            return "CollectionEvent::PERIODIC";
+        case CollectionEvent::CUSTOM_START:
+            return "CollectionEvent::CUSTOM_START";
+        case CollectionEvent::CUSTOM_END:
+            return "CollectionEvent::CUSTOM_END";
+        case CollectionEvent::TERMINATED:
+            return "CollectionEvent::TERMINATED";
+
+        default:
+            return "Unknown";
+    }
+}
+
+
+Result<void> StatsCollector::toString(std::unordered_map<std::string, std::string>* usages,
+                                      const char* indent) EXCLUDES(mMutex) {
+    std::string double_indent(indent);
+    double_indent += indent;
+
+    {
+        AutoMutex lock(mMutex);
+        using std::chrono::duration_cast;
+        using std::chrono::seconds;
+        const intmax_t interval =
+            duration_cast<seconds>(mPeriodicCollectionInfo.interval).count();
+
+        for (auto&& [id, records] : mPeriodicCollectionInfo.records) {
+            std::string buffer;
+            StringAppendF(&buffer, "%s\n"
+                                   "%sNumber of collections: %zu\n"
+                                   "%sCollection interval: %" PRIdMAX "secs\n",
+                                   id.c_str(),
+                                   indent, records.history.size(),
+                                   indent, interval);
+
+            // Adding up to kMaxDumpHistory records
+            auto it = records.history.rbegin();
+            auto count = 0;
+            while (it != records.history.rend() && count < kMaxDumpHistory) {
+                buffer += it->toString(double_indent.c_str());
+                ++it;
+                ++count;
+            }
+
+            usages->insert_or_assign(id, std::move(buffer));
+        }
+    }
+
+    return {};
+}
+
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace android
+
diff --git a/evs/manager/1.1/stats/StatsCollector.h b/evs/manager/1.1/stats/StatsCollector.h
new file mode 100644
index 0000000..031b342
--- /dev/null
+++ b/evs/manager/1.1/stats/StatsCollector.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUTOMOTIVE_EVS_V1_1_EVSSTATSCOLLECTOR_H
+#define ANDROID_AUTOMOTIVE_EVS_V1_1_EVSSTATSCOLLECTOR_H
+
+#include "CameraUsageStats.h"
+#include "LooperWrapper.h"
+
+#include <deque>
+#include <thread>
+#include <unordered_map>
+#include <vector>
+
+#include <android/hardware/automotive/evs/1.1/types.h>
+#include <android-base/chrono_utils.h>
+#include <android-base/logging.h>
+#include <android-base/result.h>
+#include <utils/Mutex.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+class HalCamera;    // From VirtualCamera.h
+
+enum CollectionEvent {
+    INIT = 0,
+    PERIODIC,
+    CUSTOM_START,
+    CUSTOM_END,
+    TERMINATED,
+
+    LAST_EVENT,
+};
+
+
+struct CollectionRecord {
+    // Latest statistics collection
+    CameraUsageStatsRecord latest = {};
+
+    // History of collected statistics records
+    std::deque<CameraUsageStatsRecord> history;
+};
+
+
+struct CollectionInfo {
+    // Collection interval between two subsequent collections
+    std::chrono::nanoseconds interval = 0ns;
+
+    // The maximum number of records this collection stores
+    size_t maxCacheSize = 0;
+
+    // Time when the latest collection was done
+    nsecs_t lastCollectionTime = 0;
+
+    // Collected statistics records per instances
+    std::unordered_map<std::string, CollectionRecord> records;
+};
+
+
+class StatsCollector : public MessageHandler {
+public:
+    explicit StatsCollector() :
+        mLooper(new LooperWrapper()),
+        mCurrentCollectionEvent(CollectionEvent::INIT),
+        mPeriodicCollectionInfo({}),
+        mCustomCollectionInfo({}) {}
+
+    virtual ~StatsCollector() { stopCollection(); }
+
+    // Starts collecting CameraUsageStats
+    android::base::Result<void> startCollection();
+
+    // Stops collecting the statistics
+    android::base::Result<void> stopCollection();
+
+    // Starts collecting CameraUsageStarts during a given duration at a given
+    // interval.
+    android::base::Result<void> startCustomCollection(
+            std::chrono::nanoseconds interval,
+            std::chrono::nanoseconds duration) EXCLUDES(mMutex);
+
+    // Stops current custom collection and shows the result from the device with
+    // a given unique id.  If this is "all",all results
+    // will be returned.
+    android::base::Result<std::string> stopCustomCollection(
+            std::string id = "") EXCLUDES(mMutex);
+
+    // Registers HalCamera object to monitor
+    android::base::Result<void> registerClientToMonitor(
+            android::sp<HalCamera>& camera) EXCLUDES(mMutex);
+
+    // Unregister HalCamera object
+    android::base::Result<void> unregisterClientToMonitor(
+            const std::string& id) EXCLUDES(mMutex);
+
+    // Returns a string that contains the latest statistics pulled from
+    // currently active clients
+    android::base::Result<void> toString(
+            std::unordered_map<std::string, std::string>* usages,
+            const char* indent = "") EXCLUDES(mMutex);
+
+private:
+    // Mutex to protect records
+    mutable Mutex mMutex;
+
+    // Looper to message the collection thread
+    android::sp<LooperWrapper> mLooper;
+
+    // Background thread to pull stats from the clients
+    std::thread mCollectionThread;
+
+    // Current state of the monitor
+    CollectionEvent mCurrentCollectionEvent GUARDED_BY(mMutex);
+
+    // Periodic collection information
+    CollectionInfo  mPeriodicCollectionInfo GUARDED_BY(mMutex);
+
+    // A collection during the custom period the user sets
+    CollectionInfo  mCustomCollectionInfo GUARDED_BY(mMutex);
+
+    // A list of HalCamera objects to monitor
+    std::unordered_map<std::string,
+                       android::wp<HalCamera>> mClientsToMonitor GUARDED_BY(mMutex);
+
+    // Handles the messages from the looper
+    void handleMessage(const Message& message) override;
+
+    // Handles each CollectionEvent
+    android::base::Result<void> handleCollectionEvent(
+            CollectionEvent event, CollectionInfo* info) EXCLUDES(mMutex);
+
+    // Pulls the statistics from each active HalCamera objects and generates the
+    // records
+    android::base::Result<void> collectLocked(CollectionInfo* info) REQUIRES(mMutex);
+
+    // Returns a string corresponding to a given collection event
+    std::string toString(const CollectionEvent& event) const;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace android
+
+#endif // ANDROID_AUTOMOTIVE_EVS_V1_1_EVSSTATSCOLLECTOR_H
diff --git a/evs/manager/1.1/sync/unique_fd.cpp b/evs/manager/1.1/sync/unique_fd.cpp
new file mode 100644
index 0000000..eb5bb63
--- /dev/null
+++ b/evs/manager/1.1/sync/unique_fd.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "unique_fd.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+UniqueFd::UniqueFd() : fd_(-1) {}
+
+UniqueFd::UniqueFd(int fd) : fd_(fd) {
+}
+
+UniqueFd::~UniqueFd() {
+    InternalClose();
+}
+
+UniqueFd::UniqueFd(UniqueFd&& other) : fd_(other.fd_) {
+    other.fd_ = -1;
+}
+
+UniqueFd& UniqueFd::operator=(UniqueFd&& other) {
+    InternalClose();
+    fd_ = other.fd_;
+    other.fd_ = -1;
+    return *this;
+}
+
+void UniqueFd::Reset(int new_fd) {
+    InternalClose();
+    fd_ = new_fd;
+}
+
+UniqueFd UniqueFd::Dup() const {
+    return (fd_ >= 0) ? UniqueFd(InternalDup()) : UniqueFd(fd_);
+}
+
+UniqueFd::operator bool() const {
+    return fd_ >= 0;
+}
+
+int UniqueFd::Get() const {
+    return fd_;
+}
+
+int UniqueFd::GetUnowned() const {
+    return InternalDup();
+}
+
+int UniqueFd::Release() {
+    int ret = fd_;
+    fd_ = -1;
+    return ret;
+}
+
+void UniqueFd::InternalClose() {
+    if (fd_ >= 0) {
+        int err = close(fd_);
+        if (err < 0) {
+            PLOG(FATAL) << "Error closing UniqueFd";
+        }
+    }
+    fd_ = -1;
+}
+
+int UniqueFd::InternalDup() const {
+    int new_fd = fd_ >= 0 ? dup(fd_) : fd_;
+    if (new_fd < 0 && fd_ >= 0) {
+        PLOG(FATAL) << "Error duplicating UniqueFd";
+    }
+    return new_fd;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/evs/manager/1.1/sync/unique_fd.h b/evs/manager/1.1/sync/unique_fd.h
new file mode 100644
index 0000000..204a5fc
--- /dev/null
+++ b/evs/manager/1.1/sync/unique_fd.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+// This is a simple C++ wrapper around a POSIX file descriptor. It is meant to
+// enforce ownership just like unique_ptr<T>
+//
+// Instances of this type cannot be copied, but they can be moved.
+class UniqueFd {
+public:
+    UniqueFd();
+    explicit UniqueFd(int fd);
+    ~UniqueFd();
+    UniqueFd(UniqueFd&&);
+    UniqueFd& operator=(UniqueFd&&);
+
+    // Destroy the current descriptor, and take ownership of a new one.
+    void Reset(int new_fd = -1);
+
+    // Duplicate the current descriptor.
+    UniqueFd Dup() const;
+
+    // Returns true if the descriptor is valid. False otherwise.
+    explicit operator bool() const;
+
+    // Gets the descriptor
+    int Get() const;
+
+    // Gets a unowned duplicate of the descriptor. The caller is responsible for
+    // closing it.
+    int GetUnowned() const;
+
+    // Gets the descriptor and releases ownership. The caller is responsible for
+    // closing it.
+    int Release();
+
+private:
+    UniqueFd(const UniqueFd&) = delete;
+    UniqueFd& operator=(const UniqueFd&) = delete;
+
+    void InternalClose();
+    int InternalDup() const;
+
+    int fd_;
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
diff --git a/evs/manager/1.1/sync/unique_fence.cpp b/evs/manager/1.1/sync/unique_fence.cpp
new file mode 100644
index 0000000..7aaa9f4
--- /dev/null
+++ b/evs/manager/1.1/sync/unique_fence.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "unique_fence.h"
+
+#include <errno.h>
+#include <cinttypes>
+#include <cstring>
+#include <memory>
+#include <string>
+
+#include <android-base/logging.h>
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wzero-length-array"
+#endif  // __clang__
+#include <sync/sync.h>
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif  // __clang__
+#include <utils/String8.h>
+
+
+constexpr int kWarningTimeout = 2000;
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+namespace {
+
+const char* GetStatusString(int status) {
+    if (status == 0) {
+        return "active";
+    } else if (status == 1) {
+        return "signaled";
+    } else {
+        return "error";
+    }
+}
+
+}  // namespace
+
+UniqueFence::UniqueFence() {}
+
+UniqueFence::UniqueFence(int fd) : fd_(fd) {}
+
+UniqueFence::UniqueFence(UniqueFence&& other) = default;
+UniqueFence& UniqueFence::operator=(UniqueFence&& other) = default;
+
+void UniqueFence::Reset() {
+    fd_.Reset();
+}
+
+UniqueFence UniqueFence::Dup() const {
+    return UniqueFence(fd_.GetUnowned());
+}
+
+int UniqueFence::Get() const {
+    return fd_.Get();
+}
+
+int UniqueFence::GetUnowned() const {
+    return fd_.GetUnowned();
+}
+
+UniqueFence::operator bool() const {
+    return static_cast<bool>(fd_);
+}
+
+void UniqueFence::GetDebugStateDump(String8& result) const {
+    constexpr int INDENT = 8;
+    struct sync_file_info* finfo = sync_file_info(fd_.Get());
+    if (finfo == nullptr) {
+        result.append("no debug info available");
+        return;
+    }
+    result.appendFormat("name: %s status: %d (%s)", finfo->name, finfo->status,
+                        GetStatusString(finfo->status));
+
+    struct sync_fence_info* pinfo = sync_get_fence_info(finfo);
+    for (uint32_t i = 0; i < finfo->num_fences; i++) {
+        result.appendFormat("\n%*spt %u driver: %s obj: %s: status: %d(%s) timestamp: %llu", INDENT,
+                            "", i, pinfo[i].driver_name, pinfo[i].obj_name, pinfo[i].status,
+                            GetStatusString(pinfo[i].status), pinfo[i].timestamp_ns);
+    }
+    sync_file_info_free(finfo);
+}
+
+int UniqueFence::Wait(int wait_time_ms) {
+    if (wait_time_ms == -1) {
+        int err = sync_wait(fd_.Get(), kWarningTimeout);
+        if (err >= 0 || errno != ETIME) return err;
+
+        String8 dump;
+        GetDebugStateDump(dump);
+        LOG(WARNING) << "Waited on fence " << fd_.Get()
+                     << " for " << kWarningTimeout << " ms. " << dump.string();
+    }
+    return sync_wait(fd_.Get(), wait_time_ms);
+}
+
+UniqueFence UniqueFence::Merge(const char* name, const UniqueFence& fence1,
+                               const UniqueFence& fence2) {
+    UniqueFence merged_fence;
+    if (fence1.fd_ || fence2.fd_) {
+        if (fence1.fd_ && fence2.fd_) {
+            merged_fence.fd_.Reset(sync_merge(name, fence1.fd_.Get(), fence2.fd_.Get()));
+        } else if (fence1.fd_) {
+            // We merge the fence with itself so that we always generate a fence with
+            // a new name.
+            merged_fence.fd_.Reset(sync_merge(name, fence1.fd_.Get(), fence1.fd_.Get()));
+        } else if (fence2.fd_) {
+            // We merge the fence with itself so that we always generate a fence with
+            // a new name.
+            merged_fence.fd_.Reset(sync_merge(name, fence2.fd_.Get(), fence2.fd_.Get()));
+        }
+
+        if (!merged_fence.fd_) {
+            PLOG(ERROR) << "Failed to merge fences";
+        }
+    }
+    return merged_fence;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/evs/manager/1.1/sync/unique_fence.h b/evs/manager/1.1/sync/unique_fence.h
new file mode 100644
index 0000000..7dd9f91
--- /dev/null
+++ b/evs/manager/1.1/sync/unique_fence.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <utils/String8.h>
+
+#include "unique_fd.h"
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+// This is a simple C++ wrapper around the sw_sync interface. It is used to
+// create and maintain sync fences created from a timeline.
+class UniqueFence {
+public:
+    UniqueFence();
+    explicit UniqueFence(int fd);
+
+    UniqueFence(UniqueFence&&);
+    UniqueFence& operator=(UniqueFence&&);
+
+    // Destroy the current fence.
+    void Reset();
+
+    // Duplicate the fence.
+    UniqueFence Dup() const;
+
+    // Gets the descriptor
+    int Get() const;
+
+    // Gets an unowned duplicate of the fence descriptor.
+    int GetUnowned() const;
+
+    // Returns true if the fence is set to a valid descriptor. False otherwise.
+    explicit operator bool() const;
+
+    // Waits on the fence for the indicated amount of time in milliseconds. The
+    // default value of -1 means to wait forever.
+    int Wait(int wait_time_ms = -1);
+
+    // Gets a string containing debug information for the fence.
+    void GetDebugStateDump(String8& result) const;
+
+    // Creates a new fence that signals when both input fences are signaled. Note
+    // that it is possible to merge multiple fences this way.
+    static UniqueFence Merge(const char* name, const UniqueFence& fence1,
+                             const UniqueFence& fence2);
+
+private:
+    // The fence file descriptor
+    UniqueFd fd_;
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
diff --git a/evs/manager/1.1/sync/unique_timeline.cpp b/evs/manager/1.1/sync/unique_timeline.cpp
new file mode 100644
index 0000000..b9556b8
--- /dev/null
+++ b/evs/manager/1.1/sync/unique_timeline.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "unique_timeline.h"
+
+#include <errno.h>
+#include <limits>
+#include <string.h>
+#include <sw_sync.h>
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+UniqueTimeline::UniqueTimeline(unsigned offset)
+      : fd_(sw_sync_timeline_create()), fence_counter_(offset) {
+    if (!fd_) {
+        LOG(FATAL) << "Failed to create a timeline.";
+    }
+}
+
+UniqueTimeline::~UniqueTimeline() {
+    // Force any fences waiting on the timeline to be released by incrementing
+    // by the difference between the two counters. The sw_sync driver has
+    // changed behavior several times, and no longer releases fences when the
+    // timeline fd is closed. While at one point adding MAX_UINT worked (by
+    // adding MAX_INT with two separate calls), even that stopped working.
+    // (See b/35115489 for background)
+    BumpTimelineEventCounter(fence_counter_ - timeline_counter_);
+}
+
+bool UniqueTimeline::Supported() {
+    UniqueFd fd{sw_sync_timeline_create()};
+    return !!fd;
+}
+
+UniqueFence UniqueTimeline::CreateFence(const char* name) {
+    UniqueFence fence(sw_sync_fence_create(fd_.Get(), name, fence_counter_));
+    if (!fence) {
+        PLOG(FATAL) << "Cannot create fence";
+    }
+    return fence;
+}
+
+void UniqueTimeline::BumpTimelineEventCounter() {
+    BumpTimelineEventCounter(1);
+}
+
+void UniqueTimeline::BumpTimelineEventCounter(unsigned count) {
+    timeline_counter_ += count;
+    int err = sw_sync_timeline_inc(fd_.Get(), count);
+    if (err < 0) {
+        PLOG(FATAL) << "Cannot bump timeline counter";
+    }
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/evs/manager/1.1/sync/unique_timeline.h b/evs/manager/1.1/sync/unique_timeline.h
new file mode 100644
index 0000000..17c2703
--- /dev/null
+++ b/evs/manager/1.1/sync/unique_timeline.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "unique_fd.h"
+#include "unique_fence.h"
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+// This is a simple C++ wrapper around the sw_sync interface. It is used to
+// create sync fences using timeline semantics.
+//
+// The timeline has two counters, a fence event counter maintained here in this
+// class, and the timeline counter hidden in the driver. The one in the driver
+// is initialized to zero when creating the timeline, and the one here is
+// initialized to one. The counters are meant to be independently incremented.
+//
+// When the driver counter is incremented, all fences that were created with
+// counts after the previous value of the timeline counter, and before (and
+// including) the new value are signaled by the driver.
+//
+// All fences are signaled if the timeline is also destroyed.
+//
+// The typical uses of these fences is to acquire a fence for some future point
+// on the timeline, and incrementing the local fence event counter to
+// distinguish between separate events. Then later when the event actually
+// occurs you increment the drivers count.
+//
+// Since the fences are file descriptors, they can be easily sent to another
+// process, which can wait for them to signal without needing to define some
+// other IPC mechanism to communicate the event. If the fence is sent well in
+// advance, there should be minimal latency too.
+//
+// Instances of this class cannot be copied, but can be moved.
+class UniqueTimeline {
+public:
+    // Initializes the timeline, using the given initial_fence_couter value.
+    explicit UniqueTimeline(unsigned initial_fence_counter);
+
+    ~UniqueTimeline();
+
+    // Returns true if it is possible to create timelines.
+    static bool Supported();
+
+    // Creates a fence fd using the current value of the fence counter.
+    // A negative value is returned on error.
+    UniqueFence CreateFence(const char* name);
+
+    // Increments the counter used when creating fences
+    void BumpFenceEventCounter() { fence_counter_ += 1; }
+
+    // Increments the drivers version of the counter, signaling any fences in the
+    // range.
+    void BumpTimelineEventCounter();
+
+private:
+    void BumpTimelineEventCounter(unsigned);
+
+    // The timeline file descriptor.
+    UniqueFd fd_{-1};
+
+    // The counter used when creating fences on the timeline.
+    unsigned fence_counter_{0};
+
+    // The effective count for the timeline. The kernel driver has the actual
+    // value, we just track what it should be. If it ever becomes out of sync,
+    // it could be a problem for releasing fences on destruction.
+    unsigned timeline_counter_{0};
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
diff --git a/evs/manager/Android.mk b/evs/manager/Android.mk
deleted file mode 100644
index 3924562..0000000
--- a/evs/manager/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-##################################
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    service.cpp \
-    Enumerator.cpp \
-    HalCamera.cpp \
-    VirtualCamera.cpp \
-    HalDisplay.cpp
-
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    liblog \
-    libutils \
-    libui \
-    libhidlbase \
-    libhidltransport \
-    libhardware \
-    android.hardware.automotive.evs@1.0 \
-    libhwbinder
-
-
-LOCAL_INIT_RC := android.automotive.evs.manager@1.0.rc
-
-LOCAL_MODULE := android.automotive.evs.manager@1.0
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_STRIP_MODULE := keep_symbols
-
-LOCAL_CFLAGS += -DLOG_TAG=\"EvsManager\"
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
-include $(BUILD_EXECUTABLE)
diff --git a/evs/manager/ServiceNames.h b/evs/manager/ServiceNames.h
deleted file mode 100644
index fb87536..0000000
--- a/evs/manager/ServiceNames.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-// This is the name as which we'll register ourselves
-const static char kManagedEnumeratorName[] = "default";
-
-// This is the name of the hardware provider to which we'll bind by default
-const static char kHardwareEnumeratorName[]  = "EvsEnumeratorHw";
-
-// This is the name of the mock hardware provider selectable via command line.
-// (should match .../hardware/interfaces/automotive/evs/1.0/default/ServiceNames.h)
-const static char kMockEnumeratorName[]  = "EvsEnumeratorHw-Mock";
-
diff --git a/evs/manager/android.automotive.evs.manager@1.0.rc b/evs/manager/android.automotive.evs.manager@1.0.rc
deleted file mode 100644
index f1b58ed..0000000
--- a/evs/manager/android.automotive.evs.manager@1.0.rc
+++ /dev/null
@@ -1,7 +0,0 @@
-service evs_manager /system/bin/android.automotive.evs.manager@1.0
-    class hal
-    priority -20
-    user automotive_evs
-    group automotive_evs
-    onrestart restart evs_app
-    disabled # will not automatically start with its class; must be explictly started.
diff --git a/evs/sampleDriver/Android.bp b/evs/sampleDriver/Android.bp
new file mode 100644
index 0000000..0ae0b2a
--- /dev/null
+++ b/evs/sampleDriver/Android.bp
@@ -0,0 +1,125 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+
+
+//#################################
+cc_binary {
+    name: "android.hardware.automotive.evs@1.1-sample",
+
+    vendor: true,
+
+    srcs: [
+        "service.cpp",
+        "EvsEnumerator.cpp",
+        "EvsV4lCamera.cpp",
+        "EvsGlDisplay.cpp",
+        "GlWrapper.cpp",
+        "VideoCapture.cpp",
+        "bufferCopy.cpp",
+        "ConfigManager.cpp",
+        "ConfigManagerUtil.cpp",
+    ],
+
+    shared_libs: [
+        "android.hardware.automotive.evs@1.0",
+        "android.hardware.automotive.evs@1.1",
+        "android.hardware.camera.device@3.2",
+        "libui",
+        "libEGL",
+        "libGLESv2",
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "libutils",
+        "libhardware_legacy",
+        "libcamera_metadata",
+        "libtinyxml2",
+        "libbufferqueueconverter",
+        "android.hidl.token@1.0-utils",
+        "android.frameworks.automotive.display@1.0",
+        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.bufferqueue@2.0",
+    ],
+
+    init_rc: ["android.hardware.automotive.evs@1.1-sample.rc"],
+
+    cflags: ["-DLOG_TAG=\"EvsSampleDriver\""] + [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+    ] + [
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+
+    required: [
+        "evs_configuration.dtd",
+        "evs_sample_configuration.xml",
+    ],
+
+    include_dirs: [
+        "frameworks/native/include/",
+    ],
+
+    product_variables: {
+        debuggable: {
+            cflags: [
+                "-DEVS_DEBUG",
+            ]
+        }
+    },
+
+    vintf_fragments: [
+        "manifest_android.hardware.automotive.evs@1.1.xml",
+    ],
+}
+
+cc_library{
+    name : "libevsconfigmanager",
+    vendor : true,
+    srcs : [
+        "ConfigManager.cpp",
+        "ConfigManagerUtil.cpp",
+    ],
+    shared_libs : [
+        "android.hardware.automotive.evs@1.0",
+        "android.hardware.automotive.evs@1.1",
+        "android.hardware.camera.device@3.2",
+        "libbase",
+        "libcamera_metadata",
+        "libcutils",
+        "libhardware",
+        "libtinyxml2",
+        "libutils",
+    ],
+}
+
+prebuilt_etc {
+    name: "evs_configuration.dtd",
+    soc_specific: true,
+    src: "resources/evs_configuration.dtd",
+    sub_dir: "automotive/evs",
+}
+
+prebuilt_etc {
+    name: "evs_sample_configuration.xml",
+    soc_specific: true,
+    src: "resources/evs_sample_configuration.xml",
+    sub_dir: "automotive/evs",
+}
diff --git a/evs/sampleDriver/Android.mk b/evs/sampleDriver/Android.mk
deleted file mode 100644
index 734feea..0000000
--- a/evs/sampleDriver/Android.mk
+++ /dev/null
@@ -1,47 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-##################################
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    service.cpp \
-    EvsEnumerator.cpp \
-    EvsV4lCamera.cpp \
-    EvsGlDisplay.cpp \
-    GlWrapper.cpp \
-    VideoCapture.cpp \
-    bufferCopy.cpp \
-
-
-LOCAL_SHARED_LIBRARIES := \
-    android.hardware.automotive.evs@1.0 \
-    libui \
-    libgui \
-    libEGL \
-    libGLESv2 \
-    libbase \
-    libbinder \
-    libcutils \
-    libhardware \
-    libhidlbase \
-    libhidltransport \
-    liblog \
-    libutils \
-    libhardware_legacy\
-    libhwbinder
-
-LOCAL_INIT_RC := android.hardware.automotive.evs@1.0-sample.rc
-
-LOCAL_MODULE := android.hardware.automotive.evs@1.0-sample
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_STRIP_MODULE := keep_symbols
-
-LOCAL_CFLAGS += -DLOG_TAG=\"EvsSampleDriver\"
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
-# NOTE:  It can be helpful, while debugging, to disable optimizations
-#LOCAL_CFLAGS += -O0 -g
-
-include $(BUILD_EXECUTABLE)
diff --git a/evs/sampleDriver/ConfigManager.cpp b/evs/sampleDriver/ConfigManager.cpp
new file mode 100644
index 0000000..b027bbb
--- /dev/null
+++ b/evs/sampleDriver/ConfigManager.cpp
@@ -0,0 +1,1086 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sstream>
+#include <fstream>
+#include <thread>
+
+#include <hardware/gralloc.h>
+#include <utils/SystemClock.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+
+#include "ConfigManager.h"
+
+using ::android::hardware::camera::device::V3_2::StreamRotation;
+
+
+ConfigManager::~ConfigManager() {
+    /* Nothing to do */
+}
+
+
+void ConfigManager::printElementNames(const XMLElement *rootElem,
+                                      string prefix) const {
+    const XMLElement *curElem = rootElem;
+
+    while (curElem != nullptr) {
+        LOG(VERBOSE) << "[ELEM] " << prefix << curElem->Name();
+        const XMLAttribute *curAttr = curElem->FirstAttribute();
+        while (curAttr) {
+            LOG(VERBOSE) << "[ATTR] " << prefix << curAttr->Name() << ": " << curAttr->Value();
+            curAttr = curAttr->Next();
+        }
+
+        /* recursively go down to descendants */
+        printElementNames(curElem->FirstChildElement(), prefix + "\t");
+
+        curElem = curElem->NextSiblingElement();
+    }
+}
+
+
+void ConfigManager::readCameraInfo(const XMLElement * const aCameraElem) {
+    if (aCameraElem == nullptr) {
+        LOG(WARNING) << "XML file does not have required camera element";
+        return;
+    }
+
+    const XMLElement *curElem = aCameraElem->FirstChildElement();
+    while (curElem != nullptr) {
+        if (!strcmp(curElem->Name(), "group")) {
+            /* camera group identifier */
+            const char *id = curElem->FindAttribute("id")->Value();
+
+            /* create a camera group to be filled */
+            CameraGroupInfo *aCamera = new CameraGroupInfo();
+
+            /* read camera device information */
+            if (!readCameraDeviceInfo(aCamera, curElem)) {
+                LOG(WARNING) << "Failed to read a camera information of " << id;
+                delete aCamera;
+                continue;
+            }
+
+            /* camera group synchronization */
+            const char *sync = curElem->FindAttribute("synchronized")->Value();
+            if (!strcmp(sync, "CALIBRATED")) {
+                aCamera->synchronized =
+                    ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED;
+            } else if (!strcmp(sync, "APPROXIMATE")) {
+                aCamera->synchronized =
+                    ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE;
+            } else {
+                aCamera->synchronized = 0; // Not synchronized
+            }
+
+            /* add a group to hash map */
+            mCameraGroups.insert_or_assign(id, unique_ptr<CameraGroupInfo>(aCamera));
+        } else if (!strcmp(curElem->Name(), "device")) {
+            /* camera unique identifier */
+            const char *id = curElem->FindAttribute("id")->Value();
+
+            /* camera mount location */
+            const char *pos = curElem->FindAttribute("position")->Value();
+
+            /* create a camera device to be filled */
+            CameraInfo *aCamera = new CameraInfo();
+
+            /* read camera device information */
+            if (!readCameraDeviceInfo(aCamera, curElem)) {
+                LOG(WARNING) << "Failed to read a camera information of " << id;
+                delete aCamera;
+                continue;
+            }
+
+            /* store read camera module information */
+            mCameraInfo.insert_or_assign(id, unique_ptr<CameraInfo>(aCamera));
+
+            /* assign a camera device to a position group */
+            mCameraPosition[pos].emplace(id);
+        } else {
+            /* ignore other device types */
+            LOG(DEBUG) << "Unknown element " << curElem->Name() << " is ignored";
+        }
+
+        curElem = curElem->NextSiblingElement();
+    }
+}
+
+
+bool
+ConfigManager::readCameraDeviceInfo(CameraInfo *aCamera,
+                                    const XMLElement *aDeviceElem) {
+    if (aCamera == nullptr || aDeviceElem == nullptr) {
+        return false;
+    }
+
+    /* size information to allocate camera_metadata_t */
+    size_t totalEntries = 0;
+    size_t totalDataSize = 0;
+
+    /* read device capabilities */
+    totalEntries +=
+        readCameraCapabilities(aDeviceElem->FirstChildElement("caps"),
+                               aCamera,
+                               totalDataSize);
+
+
+    /* read camera metadata */
+    totalEntries +=
+        readCameraMetadata(aDeviceElem->FirstChildElement("characteristics"),
+                           aCamera,
+                           totalDataSize);
+
+    /* construct camera_metadata_t */
+    if (!constructCameraMetadata(aCamera, totalEntries, totalDataSize)) {
+        LOG(WARNING) << "Either failed to allocate memory or "
+                     << "allocated memory was not large enough";
+    }
+
+    return true;
+}
+
+
+size_t
+ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem,
+                                      CameraInfo *aCamera,
+                                      size_t &dataSize) {
+    if (aCapElem == nullptr || aCamera == nullptr) {
+        return 0;
+    }
+
+    string token;
+    const XMLElement *curElem = nullptr;
+
+    /* a list of supported camera parameters/controls */
+    curElem = aCapElem->FirstChildElement("supported_controls");
+    if (curElem != nullptr) {
+        const XMLElement *ctrlElem = curElem->FirstChildElement("control");
+        while (ctrlElem != nullptr) {
+            const char *nameAttr = ctrlElem->FindAttribute("name")->Value();;
+            const int32_t minVal = stoi(ctrlElem->FindAttribute("min")->Value());
+            const int32_t maxVal = stoi(ctrlElem->FindAttribute("max")->Value());
+
+            int32_t stepVal = 1;
+            const XMLAttribute *stepAttr = ctrlElem->FindAttribute("step");
+            if (stepAttr != nullptr) {
+                stepVal = stoi(stepAttr->Value());
+            }
+
+            CameraParam aParam;
+            if (ConfigManagerUtil::convertToEvsCameraParam(nameAttr,
+                                                           aParam)) {
+                aCamera->controls.emplace(
+                    aParam,
+                    make_tuple(minVal, maxVal, stepVal)
+                );
+            }
+
+            ctrlElem = ctrlElem->NextSiblingElement("control");
+        }
+    }
+
+    /* a list of camera stream configurations */
+    curElem = aCapElem->FirstChildElement("stream");
+    while (curElem != nullptr) {
+        /* read 5 attributes */
+        const XMLAttribute *idAttr     = curElem->FindAttribute("id");
+        const XMLAttribute *widthAttr  = curElem->FindAttribute("width");
+        const XMLAttribute *heightAttr = curElem->FindAttribute("height");
+        const XMLAttribute *fmtAttr    = curElem->FindAttribute("format");
+        const XMLAttribute *fpsAttr    = curElem->FindAttribute("framerate");
+
+        const int32_t id = stoi(idAttr->Value());
+        int32_t framerate = 0;
+        if (fpsAttr != nullptr) {
+            framerate = stoi(fpsAttr->Value());
+        }
+
+        int32_t pixFormat;
+        if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
+                                                    pixFormat)) {
+            RawStreamConfiguration cfg = {
+                id,
+                stoi(widthAttr->Value()),
+                stoi(heightAttr->Value()),
+                pixFormat,
+                ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
+                framerate
+            };
+            aCamera->streamConfigurations.insert_or_assign(id, cfg);
+        }
+
+        curElem = curElem->NextSiblingElement("stream");
+    }
+
+    dataSize = calculate_camera_metadata_entry_data_size(
+                   get_camera_metadata_tag_type(
+                       ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+                   ),
+                   aCamera->streamConfigurations.size() * kStreamCfgSz
+               );
+
+    /* a single camera metadata entry contains multiple stream configurations */
+    return dataSize > 0 ? 1 : 0;
+}
+
+
+size_t
+ConfigManager::readCameraMetadata(const XMLElement * const aParamElem,
+                                  CameraInfo *aCamera,
+                                  size_t &dataSize) {
+    if (aParamElem == nullptr || aCamera == nullptr) {
+        return 0;
+    }
+
+    const XMLElement *curElem = aParamElem->FirstChildElement("parameter");
+    size_t numEntries = 0;
+    camera_metadata_tag_t tag;
+    while (curElem != nullptr) {
+        if (ConfigManagerUtil::convertToMetadataTag(curElem->FindAttribute("name")->Value(),
+                                                    tag)) {
+            switch(tag) {
+                case ANDROID_LENS_DISTORTION:
+                case ANDROID_LENS_POSE_ROTATION:
+                case ANDROID_LENS_POSE_TRANSLATION:
+                case ANDROID_LENS_INTRINSIC_CALIBRATION: {
+                    /* float[] */
+                    size_t count = 0;
+                    void   *data = ConfigManagerUtil::convertFloatArray(
+                                        curElem->FindAttribute("size")->Value(),
+                                        curElem->FindAttribute("value")->Value(),
+                                        count
+                                   );
+
+                    aCamera->cameraMetadata.insert_or_assign(
+                        tag, make_pair(data, count)
+                    );
+
+                    ++numEntries;
+                    dataSize += calculate_camera_metadata_entry_data_size(
+                                    get_camera_metadata_tag_type(tag), count
+                                );
+
+                    break;
+                }
+
+                case ANDROID_REQUEST_AVAILABLE_CAPABILITIES: {
+                    camera_metadata_enum_android_request_available_capabilities_t *data =
+                        new camera_metadata_enum_android_request_available_capabilities_t[1];
+                    if (ConfigManagerUtil::convertToCameraCapability(
+                           curElem->FindAttribute("value")->Value(),
+                           *data)
+                       ) {
+                        aCamera->cameraMetadata.insert_or_assign(
+                            tag, make_pair((void *)data, 1)
+                        );
+
+                        ++numEntries;
+                        dataSize += calculate_camera_metadata_entry_data_size(
+                                        get_camera_metadata_tag_type(tag), 1
+                                    );
+                    }
+                    break;
+                }
+
+                case ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS: {
+                    /* a comma-separated list of physical camera devices */
+                    size_t len = strlen(curElem->FindAttribute("value")->Value());
+                    char *data = new char[len + 1];
+                    memcpy(data,
+                           curElem->FindAttribute("value")->Value(),
+                           len * sizeof(char));
+
+                    /* replace commas with null char */
+                    char *p = data;
+                    while (*p != '\0') {
+                        if (*p == ',') {
+                            *p = '\0';
+                        }
+                        ++p;
+                    }
+
+                    aCamera->cameraMetadata.insert_or_assign(
+                        tag, make_pair((void *)data, len + 1)
+                    );
+
+                    ++numEntries;
+                    dataSize += calculate_camera_metadata_entry_data_size(
+                                    get_camera_metadata_tag_type(tag), len
+                                );
+                    break;
+                }
+
+
+                /* TODO(b/140416878): add vendor-defined/custom tag support */
+
+                default:
+                    LOG(WARNING) << "Parameter "
+                                 << curElem->FindAttribute("name")->Value()
+                                 << " is not supported";
+                    break;
+            }
+        } else {
+            LOG(WARNING) << "Unsupported metadata tag "
+                         << curElem->FindAttribute("name")->Value()
+                         << " is found.";
+        }
+
+        curElem = curElem->NextSiblingElement("parameter");
+    }
+
+    return numEntries;
+}
+
+
+bool
+ConfigManager::constructCameraMetadata(CameraInfo *aCamera,
+                                       const size_t totalEntries,
+                                       const size_t totalDataSize) {
+    if (aCamera == nullptr || !aCamera->allocate(totalEntries, totalDataSize)) {
+        LOG(ERROR) << "Failed to allocate memory for camera metadata";
+        return false;
+    }
+
+    const size_t numStreamConfigs = aCamera->streamConfigurations.size();
+    unique_ptr<int32_t[]> data(new int32_t[kStreamCfgSz * numStreamConfigs]);
+    int32_t *ptr = data.get();
+    for (auto &cfg : aCamera->streamConfigurations) {
+        for (auto i = 0; i < kStreamCfgSz; ++i) {
+          *ptr++ = cfg.second[i];
+        }
+    }
+    int32_t err = add_camera_metadata_entry(aCamera->characteristics,
+                                            ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+                                            data.get(),
+                                            numStreamConfigs * kStreamCfgSz);
+
+    if (err) {
+        LOG(ERROR) << "Failed to add stream configurations to metadata, ignored";
+        return false;
+    }
+
+    bool success = true;
+    for (auto &[tag, entry] : aCamera->cameraMetadata) {
+        /* try to add new camera metadata entry */
+        int32_t err = add_camera_metadata_entry(aCamera->characteristics,
+                                                tag,
+                                                entry.first,
+                                                entry.second);
+        if (err) {
+            LOG(ERROR) << "Failed to add an entry with a tag, " << std::hex << tag;
+
+            /* may exceed preallocated capacity */
+            LOG(ERROR) << "Camera metadata has "
+                       << get_camera_metadata_entry_count(aCamera->characteristics)
+                       << " / "
+                       << get_camera_metadata_entry_capacity(aCamera->characteristics)
+                       << " entries and "
+                       << get_camera_metadata_data_count(aCamera->characteristics)
+                       << " / "
+                       << get_camera_metadata_data_capacity(aCamera->characteristics)
+                       << " bytes are filled.";
+            LOG(ERROR) << "\tCurrent metadata entry requires "
+                       << calculate_camera_metadata_entry_data_size(tag, entry.second)
+                       << " bytes.";
+
+            success = false;
+        }
+    }
+
+    LOG(VERBOSE) << "Camera metadata has "
+                 << get_camera_metadata_entry_count(aCamera->characteristics)
+                 << " / "
+                 << get_camera_metadata_entry_capacity(aCamera->characteristics)
+                 << " entries and "
+                 << get_camera_metadata_data_count(aCamera->characteristics)
+                 << " / "
+                 << get_camera_metadata_data_capacity(aCamera->characteristics)
+                 << " bytes are filled.";
+    return success;
+}
+
+
+void ConfigManager::readSystemInfo(const XMLElement * const aSysElem) {
+    if (aSysElem == nullptr) {
+        return;
+    }
+
+    /*
+     * Please note that this function assumes that a given system XML element
+     * and its child elements follow DTD.  If it does not, it will cause a
+     * segmentation fault due to the failure of finding expected attributes.
+     */
+
+    /* read number of cameras available in the system */
+    const XMLElement *xmlElem = aSysElem->FirstChildElement("num_cameras");
+    if (xmlElem != nullptr) {
+        mSystemInfo.numCameras =
+            stoi(xmlElem->FindAttribute("value")->Value());
+    }
+}
+
+
+void ConfigManager::readDisplayInfo(const XMLElement * const aDisplayElem) {
+    if (aDisplayElem == nullptr) {
+        LOG(WARNING) << "XML file does not have required camera element";
+        return;
+    }
+
+    const XMLElement *curDev = aDisplayElem->FirstChildElement("device");
+    while (curDev != nullptr) {
+        const char *id = curDev->FindAttribute("id")->Value();
+        //const char *pos = curDev->FirstAttribute("position")->Value();
+
+        unique_ptr<DisplayInfo> dpy(new DisplayInfo());
+        if (dpy == nullptr) {
+            LOG(ERROR) << "Failed to allocate memory for DisplayInfo";
+            return;
+        }
+
+        const XMLElement *cap = curDev->FirstChildElement("caps");
+        if (cap != nullptr) {
+            const XMLElement *curStream = cap->FirstChildElement("stream");
+            while (curStream != nullptr) {
+                /* read 4 attributes */
+                const XMLAttribute *idAttr     = curStream->FindAttribute("id");
+                const XMLAttribute *widthAttr  = curStream->FindAttribute("width");
+                const XMLAttribute *heightAttr = curStream->FindAttribute("height");
+                const XMLAttribute *fmtAttr    = curStream->FindAttribute("format");
+
+                const int32_t id = stoi(idAttr->Value());
+                int32_t pixFormat;
+                if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
+                                                            pixFormat)) {
+                    RawStreamConfiguration cfg = {
+                        id,
+                        stoi(widthAttr->Value()),
+                        stoi(heightAttr->Value()),
+                        pixFormat,
+                        ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT,
+                        0   // unused
+                    };
+                    dpy->streamConfigurations.insert_or_assign(id, cfg);
+                }
+
+                curStream = curStream->NextSiblingElement("stream");
+            }
+        }
+
+        mDisplayInfo.insert_or_assign(id, std::move(dpy));
+        curDev = curDev->NextSiblingElement("device");
+    }
+
+    return;
+}
+
+
+bool ConfigManager::readConfigDataFromXML() noexcept {
+    XMLDocument xmlDoc;
+
+    const int64_t parsingStart = android::elapsedRealtimeNano();
+
+    /* load and parse a configuration file */
+    xmlDoc.LoadFile(mConfigFilePath);
+    if (xmlDoc.ErrorID() != XML_SUCCESS) {
+        LOG(ERROR) << "Failed to load and/or parse a configuration file, " << xmlDoc.ErrorStr();
+        return false;
+    }
+
+    /* retrieve the root element */
+    const XMLElement *rootElem = xmlDoc.RootElement();
+    if (strcmp(rootElem->Name(), "configuration")) {
+        LOG(ERROR) << "A configuration file is not in the required format.  "
+                   << "See /etc/automotive/evs/evs_configuration.dtd";
+        return false;
+    }
+
+    unique_lock<mutex> lock(mConfigLock);
+
+    /*
+     * parse camera information; this needs to be done before reading system
+     * information
+     */
+    readCameraInfo(rootElem->FirstChildElement("camera"));
+
+    /* parse system information */
+    readSystemInfo(rootElem->FirstChildElement("system"));
+
+    /* parse display information */
+    readDisplayInfo(rootElem->FirstChildElement("display"));
+
+    /* configuration data is ready to be consumed */
+    mIsReady = true;
+
+    /* notify that configuration data is ready */
+    lock.unlock();
+    mConfigCond.notify_all();
+
+    const int64_t parsingEnd = android::elapsedRealtimeNano();
+    LOG(INFO) << "Parsing configuration file takes "
+              << std::scientific << (double)(parsingEnd - parsingStart) / 1000000.0
+              << " ms.";
+
+    return true;
+}
+
+
+bool ConfigManager::readConfigDataFromBinary() {
+    /* Temporary buffer to hold configuration data read from a binary file */
+    char mBuffer[1024];
+
+    fstream srcFile;
+    const int64_t readStart = android::elapsedRealtimeNano();
+
+    srcFile.open(mBinaryFilePath, fstream::in | fstream::binary);
+    if (!srcFile) {
+        LOG(ERROR) << "Failed to open a source binary file, " << mBinaryFilePath;
+        return false;
+    }
+
+    unique_lock<mutex> lock(mConfigLock);
+    mIsReady = false;
+
+    /* read configuration data into the internal buffer */
+    srcFile.read(mBuffer, sizeof(mBuffer));
+    LOG(VERBOSE) << __FUNCTION__ << ": " << srcFile.gcount() << " bytes are read.";
+    char *p = mBuffer;
+    size_t sz = 0;
+
+    /* read number of camera group information entries */
+    size_t ngrps = *(reinterpret_cast<size_t *>(p)); p += sizeof(size_t);
+
+    /* read each camera information entry */
+    for (auto cidx = 0; cidx < ngrps; ++cidx) {
+        /* read camera identifier */
+        string cameraId = *(reinterpret_cast<string *>(p)); p += sizeof(string);
+
+        /* size of camera_metadata_t */
+        size_t num_entry = *(reinterpret_cast<size_t *>(p)); p += sizeof(size_t);
+        size_t num_data  = *(reinterpret_cast<size_t *>(p)); p += sizeof(size_t);
+
+        /* create CameraInfo and add it to hash map */
+        unique_ptr<ConfigManager::CameraGroupInfo> aCamera;
+        if (aCamera == nullptr ||
+            !aCamera->allocate(num_entry, num_data))  {
+            LOG(ERROR) << "Failed to create new CameraInfo object";
+            mCameraInfo.clear();
+            return false;
+        }
+
+        /* controls */
+        typedef struct {
+            CameraParam cid;
+            int32_t min;
+            int32_t max;
+            int32_t step;
+        } CameraCtrl;
+        sz = *(reinterpret_cast<size_t *>(p)); p += sizeof(size_t);
+        CameraCtrl *ptr = reinterpret_cast<CameraCtrl *>(p);
+        for (auto idx = 0; idx < sz; ++idx) {
+            CameraCtrl temp = *ptr++;
+            aCamera->controls.emplace(temp.cid,
+                                      make_tuple(temp.min, temp.max, temp.step));
+        }
+        p = reinterpret_cast<char *>(ptr);
+
+        /* stream configurations */
+        sz = *(reinterpret_cast<size_t *>(p)); p += sizeof(size_t);
+        int32_t *i32_ptr = reinterpret_cast<int32_t *>(p);
+        for (auto idx = 0; idx < sz; ++idx) {
+            const int32_t id = *i32_ptr++;
+
+            std::array<int32_t, kStreamCfgSz> temp;
+            for (auto i = 0; i < kStreamCfgSz; ++i) {
+                temp[i] = *i32_ptr++;
+            }
+            aCamera->streamConfigurations.insert_or_assign(id, temp);
+        }
+        p = reinterpret_cast<char *>(i32_ptr);
+
+        /* synchronization */
+        aCamera->synchronized =
+            *(reinterpret_cast<int32_t *>(p)); p += sizeof(int32_t);
+
+        for (auto idx = 0; idx < num_entry; ++idx) {
+            /* Read camera metadata entries */
+            camera_metadata_tag_t tag =
+                *reinterpret_cast<camera_metadata_tag_t *>(p);
+            p += sizeof(camera_metadata_tag_t);
+            size_t count = *reinterpret_cast<size_t *>(p); p += sizeof(size_t);
+
+            int32_t type = get_camera_metadata_tag_type(tag);
+            switch (type) {
+                case TYPE_BYTE: {
+                    add_camera_metadata_entry(aCamera->characteristics,
+                                              tag,
+                                              p,
+                                              count);
+                    p += count * sizeof(uint8_t);
+                    break;
+                }
+                case TYPE_INT32: {
+                    add_camera_metadata_entry(aCamera->characteristics,
+                                              tag,
+                                              p,
+                                              count);
+                    p += count * sizeof(int32_t);
+                    break;
+                }
+                case TYPE_FLOAT: {
+                    add_camera_metadata_entry(aCamera->characteristics,
+                                              tag,
+                                              p,
+                                              count);
+                    p += count * sizeof(float);
+                    break;
+                }
+                case TYPE_INT64: {
+                    add_camera_metadata_entry(aCamera->characteristics,
+                                              tag,
+                                              p,
+                                              count);
+                    p += count * sizeof(int64_t);
+                    break;
+                }
+                case TYPE_DOUBLE: {
+                    add_camera_metadata_entry(aCamera->characteristics,
+                                              tag,
+                                              p,
+                                              count);
+                    p += count * sizeof(double);
+                    break;
+                }
+                case TYPE_RATIONAL:
+                    p += count * sizeof(camera_metadata_rational_t);
+                    break;
+                default:
+                    LOG(WARNING) << "Type " << type << " is unknown; "
+                                 << "data may be corrupted.";
+                    break;
+            }
+        }
+
+        mCameraInfo.insert_or_assign(cameraId, std::move(aCamera));
+    }
+
+
+
+    /* read number of camera information entries */
+    size_t ncams = *(reinterpret_cast<size_t *>(p)); p += sizeof(size_t);
+
+    /* read each camera information entry */
+    for (auto cidx = 0; cidx < ncams; ++cidx) {
+        /* read camera identifier */
+        string cameraId = *(reinterpret_cast<string *>(p)); p += sizeof(string);
+
+        /* size of camera_metadata_t */
+        size_t num_entry = *(reinterpret_cast<size_t *>(p)); p += sizeof(size_t);
+        size_t num_data  = *(reinterpret_cast<size_t *>(p)); p += sizeof(size_t);
+
+        /* create CameraInfo and add it to hash map */
+        unique_ptr<ConfigManager::CameraInfo> aCamera;
+        if (aCamera == nullptr ||
+            !aCamera->allocate(num_entry, num_data))  {
+            LOG(ERROR) << "Failed to create new CameraInfo object";
+            mCameraInfo.clear();
+            return false;
+        }
+
+        /* controls */
+        typedef struct {
+            CameraParam cid;
+            int32_t min;
+            int32_t max;
+            int32_t step;
+        } CameraCtrl;
+        sz = *(reinterpret_cast<size_t *>(p)); p += sizeof(size_t);
+        CameraCtrl *ptr = reinterpret_cast<CameraCtrl *>(p);
+        for (auto idx = 0; idx < sz; ++idx) {
+            CameraCtrl temp = *ptr++;
+            aCamera->controls.emplace(temp.cid,
+                                      make_tuple(temp.min, temp.max, temp.step));
+        }
+        p = reinterpret_cast<char *>(ptr);
+
+        /* stream configurations */
+        sz = *(reinterpret_cast<size_t *>(p)); p += sizeof(size_t);
+        int32_t *i32_ptr = reinterpret_cast<int32_t *>(p);
+        for (auto idx = 0; idx < sz; ++idx) {
+            const int32_t id = *i32_ptr++;
+
+            std::array<int32_t, kStreamCfgSz> temp;
+            for (auto i = 0; i < kStreamCfgSz; ++i) {
+                temp[i] = *i32_ptr++;
+            }
+            aCamera->streamConfigurations.insert_or_assign(id, temp);
+        }
+        p = reinterpret_cast<char *>(i32_ptr);
+
+        for (auto idx = 0; idx < num_entry; ++idx) {
+            /* Read camera metadata entries */
+            camera_metadata_tag_t tag =
+                *reinterpret_cast<camera_metadata_tag_t *>(p);
+            p += sizeof(camera_metadata_tag_t);
+            size_t count = *reinterpret_cast<size_t *>(p); p += sizeof(size_t);
+
+            int32_t type = get_camera_metadata_tag_type(tag);
+            switch (type) {
+                case TYPE_BYTE: {
+                    add_camera_metadata_entry(aCamera->characteristics,
+                                              tag,
+                                              p,
+                                              count);
+                    p += count * sizeof(uint8_t);
+                    break;
+                }
+                case TYPE_INT32: {
+                    add_camera_metadata_entry(aCamera->characteristics,
+                                              tag,
+                                              p,
+                                              count);
+                    p += count * sizeof(int32_t);
+                    break;
+                }
+                case TYPE_FLOAT: {
+                    add_camera_metadata_entry(aCamera->characteristics,
+                                              tag,
+                                              p,
+                                              count);
+                    p += count * sizeof(float);
+                    break;
+                }
+                case TYPE_INT64: {
+                    add_camera_metadata_entry(aCamera->characteristics,
+                                              tag,
+                                              p,
+                                              count);
+                    p += count * sizeof(int64_t);
+                    break;
+                }
+                case TYPE_DOUBLE: {
+                    add_camera_metadata_entry(aCamera->characteristics,
+                                              tag,
+                                              p,
+                                              count);
+                    p += count * sizeof(double);
+                    break;
+                }
+                case TYPE_RATIONAL:
+                    p += count * sizeof(camera_metadata_rational_t);
+                    break;
+                default:
+                    LOG(WARNING) << "Type " << type << " is unknown; "
+                                 << "data may be corrupted.";
+                    break;
+            }
+        }
+
+        mCameraInfo.insert_or_assign(cameraId, std::move(aCamera));
+    }
+
+    mIsReady = true;
+
+    /* notify that configuration data is ready */
+    lock.unlock();
+    mConfigCond.notify_all();
+
+    int64_t readEnd = android::elapsedRealtimeNano();
+    LOG(INFO) << __FUNCTION__ << " takes "
+              << std::scientific << (double)(readEnd - readStart) / 1000000.0
+              << " ms.";
+
+    return true;
+}
+
+
+bool ConfigManager::writeConfigDataToBinary() {
+    fstream outFile;
+
+    int64_t writeStart = android::elapsedRealtimeNano();
+
+    outFile.open(mBinaryFilePath, fstream::out | fstream::binary);
+    if (!outFile) {
+        LOG(ERROR) << "Failed to open a destination binary file, " << mBinaryFilePath;
+        return false;
+    }
+
+    /* lock a configuration data while it's being written to the filesystem */
+    lock_guard<mutex> lock(mConfigLock);
+
+    /* write camera group information */
+    size_t sz = mCameraGroups.size();
+    outFile.write(reinterpret_cast<const char *>(&sz),
+                  sizeof(size_t));
+    for (auto&& [camId, camInfo] : mCameraGroups) {
+        LOG(INFO) << "Storing camera group " << camId;
+
+        /* write a camera identifier string */
+        outFile.write(reinterpret_cast<const char *>(&camId),
+                      sizeof(string));
+
+        /* controls */
+        sz = camInfo->controls.size();
+        outFile.write(reinterpret_cast<const char *>(&sz),
+                      sizeof(size_t));
+        for (auto&& [ctrl, range] : camInfo->controls) {
+            outFile.write(reinterpret_cast<const char *>(&ctrl),
+                          sizeof(CameraParam));
+            outFile.write(reinterpret_cast<const char *>(&get<0>(range)),
+                          sizeof(int32_t));
+            outFile.write(reinterpret_cast<const char *>(&get<1>(range)),
+                          sizeof(int32_t));
+            outFile.write(reinterpret_cast<const char *>(&get<2>(range)),
+                          sizeof(int32_t));
+        }
+
+        /* stream configurations */
+        sz = camInfo->streamConfigurations.size();
+        outFile.write(reinterpret_cast<const char *>(&sz),
+                      sizeof(size_t));
+        for (auto&& [sid, cfg] : camInfo->streamConfigurations) {
+            outFile.write(reinterpret_cast<const char *>(sid),
+                          sizeof(int32_t));
+            for (int idx = 0; idx < kStreamCfgSz; ++idx) {
+                outFile.write(reinterpret_cast<const char *>(&cfg[idx]),
+                              sizeof(int32_t));
+            }
+        }
+
+        /* synchronization */
+        outFile.write(reinterpret_cast<const char *>(&camInfo->synchronized),
+                      sizeof(int32_t));
+
+        /* size of camera_metadata_t */
+        size_t num_entry = 0;
+        size_t num_data  = 0;
+        if (camInfo->characteristics != nullptr) {
+            num_entry = get_camera_metadata_entry_count(camInfo->characteristics);
+            num_data  = get_camera_metadata_data_count(camInfo->characteristics);
+        }
+        outFile.write(reinterpret_cast<const char *>(&num_entry),
+                      sizeof(size_t));
+        outFile.write(reinterpret_cast<const char *>(&num_data),
+                      sizeof(size_t));
+
+        /* write each camera metadata entry */
+        if (num_entry > 0) {
+            camera_metadata_entry_t entry;
+            for (auto idx = 0; idx < num_entry; ++idx) {
+                if (get_camera_metadata_entry(camInfo->characteristics, idx, &entry)) {
+                    LOG(ERROR) << "Failed to retrieve camera metadata entry " << idx;
+                    outFile.close();
+                    return false;
+                }
+
+                outFile.write(reinterpret_cast<const char *>(&entry.tag),
+                              sizeof(entry.tag));
+                outFile.write(reinterpret_cast<const char *>(&entry.count),
+                              sizeof(entry.count));
+
+                int32_t type = get_camera_metadata_tag_type(entry.tag);
+                switch (type) {
+                    case TYPE_BYTE:
+                        outFile.write(reinterpret_cast<const char *>(entry.data.u8),
+                                      sizeof(uint8_t) * entry.count);
+                        break;
+                    case TYPE_INT32:
+                        outFile.write(reinterpret_cast<const char *>(entry.data.i32),
+                                      sizeof(int32_t) * entry.count);
+                        break;
+                    case TYPE_FLOAT:
+                        outFile.write(reinterpret_cast<const char *>(entry.data.f),
+                                      sizeof(float) * entry.count);
+                        break;
+                    case TYPE_INT64:
+                        outFile.write(reinterpret_cast<const char *>(entry.data.i64),
+                                      sizeof(int64_t) * entry.count);
+                        break;
+                    case TYPE_DOUBLE:
+                        outFile.write(reinterpret_cast<const char *>(entry.data.d),
+                                      sizeof(double) * entry.count);
+                        break;
+                    case TYPE_RATIONAL:
+                        [[fallthrough]];
+                    default:
+                        LOG(WARNING) << "Type " << type << " is not supported.";
+                        break;
+                }
+            }
+        }
+    }
+
+    /* write camera device information */
+    sz = mCameraInfo.size();
+    outFile.write(reinterpret_cast<const char *>(&sz),
+                  sizeof(size_t));
+    for (auto&& [camId, camInfo] : mCameraInfo) {
+        LOG(INFO) << "Storing camera " << camId;
+
+        /* write a camera identifier string */
+        outFile.write(reinterpret_cast<const char *>(&camId),
+                      sizeof(string));
+
+        /* controls */
+        sz = camInfo->controls.size();
+        outFile.write(reinterpret_cast<const char *>(&sz),
+                      sizeof(size_t));
+        for (auto& [ctrl, range] : camInfo->controls) {
+            outFile.write(reinterpret_cast<const char *>(&ctrl),
+                          sizeof(CameraParam));
+            outFile.write(reinterpret_cast<const char *>(&get<0>(range)),
+                          sizeof(int32_t));
+            outFile.write(reinterpret_cast<const char *>(&get<1>(range)),
+                          sizeof(int32_t));
+            outFile.write(reinterpret_cast<const char *>(&get<2>(range)),
+                          sizeof(int32_t));
+        }
+
+        /* stream configurations */
+        sz = camInfo->streamConfigurations.size();
+        outFile.write(reinterpret_cast<const char *>(&sz),
+                      sizeof(size_t));
+        for (auto&& [sid, cfg] : camInfo->streamConfigurations) {
+            outFile.write(reinterpret_cast<const char *>(sid),
+                          sizeof(int32_t));
+            for (int idx = 0; idx < kStreamCfgSz; ++idx) {
+                outFile.write(reinterpret_cast<const char *>(&cfg[idx]),
+                              sizeof(int32_t));
+            }
+        }
+
+        /* size of camera_metadata_t */
+        size_t num_entry = 0;
+        size_t num_data  = 0;
+        if (camInfo->characteristics != nullptr) {
+            num_entry = get_camera_metadata_entry_count(camInfo->characteristics);
+            num_data  = get_camera_metadata_data_count(camInfo->characteristics);
+        }
+        outFile.write(reinterpret_cast<const char *>(&num_entry),
+                      sizeof(size_t));
+        outFile.write(reinterpret_cast<const char *>(&num_data),
+                      sizeof(size_t));
+
+        /* write each camera metadata entry */
+        if (num_entry > 0) {
+            camera_metadata_entry_t entry;
+            for (auto idx = 0; idx < num_entry; ++idx) {
+                if (get_camera_metadata_entry(camInfo->characteristics, idx, &entry)) {
+                    LOG(ERROR) << "Failed to retrieve camera metadata entry " << idx;
+                    outFile.close();
+                    return false;
+                }
+
+                outFile.write(reinterpret_cast<const char *>(&entry.tag),
+                              sizeof(entry.tag));
+                outFile.write(reinterpret_cast<const char *>(&entry.count),
+                              sizeof(entry.count));
+
+                int32_t type = get_camera_metadata_tag_type(entry.tag);
+                switch (type) {
+                    case TYPE_BYTE:
+                        outFile.write(reinterpret_cast<const char *>(entry.data.u8),
+                                      sizeof(uint8_t) * entry.count);
+                        break;
+                    case TYPE_INT32:
+                        outFile.write(reinterpret_cast<const char *>(entry.data.i32),
+                                      sizeof(int32_t) * entry.count);
+                        break;
+                    case TYPE_FLOAT:
+                        outFile.write(reinterpret_cast<const char *>(entry.data.f),
+                                      sizeof(float) * entry.count);
+                        break;
+                    case TYPE_INT64:
+                        outFile.write(reinterpret_cast<const char *>(entry.data.i64),
+                                      sizeof(int64_t) * entry.count);
+                        break;
+                    case TYPE_DOUBLE:
+                        outFile.write(reinterpret_cast<const char *>(entry.data.d),
+                                      sizeof(double) * entry.count);
+                        break;
+                    case TYPE_RATIONAL:
+                        [[fallthrough]];
+                    default:
+                        LOG(WARNING) << "Type " << type << " is not supported.";
+                        break;
+                }
+            }
+        }
+    }
+
+    outFile.close();
+    int64_t writeEnd = android::elapsedRealtimeNano();
+    LOG(INFO) << __FUNCTION__ << " takes "
+              << std::scientific << (double)(writeEnd - writeStart) / 1000000.0
+              << " ms.";
+
+
+    return true;
+}
+
+
+std::unique_ptr<ConfigManager> ConfigManager::Create(const char *path) {
+    unique_ptr<ConfigManager> cfgMgr(new ConfigManager(path));
+
+    /*
+     * Read a configuration from XML file
+     *
+     * If this is too slow, ConfigManager::readConfigDataFromBinary() and
+     * ConfigManager::writeConfigDataToBinary()can serialize CameraInfo object
+     * to the filesystem and construct CameraInfo instead; this was
+     * evaluated as 10x faster.
+     */
+    if (!cfgMgr->readConfigDataFromXML()) {
+        return nullptr;
+    } else {
+        return cfgMgr;
+    }
+}
+
+ConfigManager::CameraInfo::~CameraInfo() {
+    free_camera_metadata(characteristics);
+
+    for (auto&& [tag, val] : cameraMetadata) {
+        switch(tag) {
+            case ANDROID_LENS_DISTORTION:
+            case ANDROID_LENS_POSE_ROTATION:
+            case ANDROID_LENS_POSE_TRANSLATION:
+            case ANDROID_LENS_INTRINSIC_CALIBRATION: {
+                delete[] reinterpret_cast<float *>(val.first);
+                break;
+            }
+
+            case ANDROID_REQUEST_AVAILABLE_CAPABILITIES: {
+                delete[] \
+                    reinterpret_cast<
+                        camera_metadata_enum_android_request_available_capabilities_t *
+                    >(val.first);
+                break;
+            }
+
+            case ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS: {
+                delete[] reinterpret_cast<char *>(val.first);
+                break;
+            }
+
+            default:
+                LOG(WARNING) << "Tag " << std::hex << tag << " is not supported.  "
+                             << "Data may be corrupted?";
+                break;
+        }
+    }
+}
+
diff --git a/evs/sampleDriver/ConfigManager.h b/evs/sampleDriver/ConfigManager.h
new file mode 100644
index 0000000..97e609a
--- /dev/null
+++ b/evs/sampleDriver/ConfigManager.h
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef CONFIG_MANAGER_H
+#define CONFIG_MANAGER_H
+
+#include <vector>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <tinyxml2.h>
+
+#include <system/camera_metadata.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
+#include <android-base/logging.h>
+
+#include "ConfigManagerUtil.h"
+
+using namespace std;
+using namespace tinyxml2;
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::automotive::evs::V1_1::CameraParam;
+
+/*
+ * Plese note that this is different from what is defined in
+ * libhardware/modules/camera/3_4/metadata/types.h; this has one additional
+ * field to store a framerate.
+ */
+const size_t kStreamCfgSz = 6;
+typedef std::array<int32_t, kStreamCfgSz> RawStreamConfiguration;
+
+class ConfigManager {
+public:
+    static std::unique_ptr<ConfigManager> Create(const char *path = "");
+    ConfigManager(const ConfigManager&) = delete;
+    ConfigManager& operator=(const ConfigManager&) = delete;
+
+    virtual ~ConfigManager();
+
+    /* Camera device's capabilities and metadata */
+    class CameraInfo {
+    public:
+        CameraInfo() :
+            characteristics(nullptr) {
+            /* Nothing to do */
+        }
+
+        virtual ~CameraInfo();
+
+        /* Allocate memory for camera_metadata_t */
+        bool allocate(size_t entry_cap, size_t data_cap) {
+            if (characteristics != nullptr) {
+                LOG(ERROR) << "Camera metadata is already allocated";
+                return false;
+            }
+
+            characteristics = allocate_camera_metadata(entry_cap, data_cap);
+            return characteristics != nullptr;
+        }
+
+        /*
+         * List of supported controls that the master client can program.
+         * Paraemters are stored with its valid range
+         */
+        unordered_map<CameraParam,
+                      tuple<int32_t, int32_t, int32_t>> controls;
+
+        /*
+         * List of supported output stream configurations; each array stores
+         * format, width, height, and direction values in the order.
+         */
+        unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
+
+        /*
+         * Internal storage for camera metadata.  Each entry holds a pointer to
+         * data and number of elements
+         */
+        unordered_map<camera_metadata_tag_t,
+                      pair<void *, size_t>> cameraMetadata;
+
+        /* Camera module characteristics */
+        camera_metadata_t *characteristics;
+    };
+
+    class CameraGroupInfo : public CameraInfo {
+    public:
+        CameraGroupInfo() {}
+
+        /* ID of member camera devices */
+        unordered_set<string> devices;
+
+        /* The capture operation of member camera devices are synchronized */
+        int32_t synchronized = 0;
+    };
+
+    class SystemInfo {
+    public:
+        /* number of available cameras */
+        int32_t numCameras = 0;
+    };
+
+    class DisplayInfo {
+    public:
+        /*
+         * List of supported input stream configurations; each array stores
+         * format, width, height, and direction values in the order.
+         */
+        unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
+    };
+
+    /*
+     * Return system information
+     *
+     * @return SystemInfo
+     *         Constant reference of SystemInfo.
+     */
+    const SystemInfo &getSystemInfo() {
+        unique_lock<mutex> lock(mConfigLock);
+        mConfigCond.wait(lock, [this] { return mIsReady; });
+        return mSystemInfo;
+    }
+
+    /*
+     * Return a list of camera identifiers
+     *
+     * This function assumes that it is not being called frequently.
+     *
+     * @return vector<string>
+     *         A vector that contains unique camera device identifiers.
+     */
+    vector<string> getCameraIdList() {
+        unique_lock<mutex> lock(mConfigLock);
+        mConfigCond.wait(lock, [this] { return mIsReady; });
+
+        vector<string> aList;
+        for (auto&& v : mCameraInfo) {
+            aList.emplace_back(v.first);
+        }
+
+        return aList;
+    }
+
+    /*
+     * Return a list of camera group identifiers
+     *
+     * This function assumes that it is not being called frequently.
+     *
+     * @return vector<string>
+     *         A vector that contains unique camera device identifiers.
+     */
+    vector<string> getCameraGroupIdList() {
+        unique_lock<mutex> lock(mConfigLock);
+        mConfigCond.wait(lock, [this] { return mIsReady; });
+
+        vector<string> aList;
+        for (auto&& v : mCameraGroups) {
+            aList.emplace_back(v.first);
+        }
+
+        return aList;
+    }
+
+    /*
+     * Return a pointer to the camera group
+     *
+     * @return CameraGroup
+     *         A pointer to a camera group identified by a given id.
+     */
+    unique_ptr<CameraGroupInfo>& getCameraGroupInfo(const string& gid) {
+        unique_lock<mutex> lock(mConfigLock);
+        mConfigCond.wait(lock, [this] { return mIsReady; });
+
+        return mCameraGroups[gid];
+    }
+
+    /*
+     * Return a camera metadata
+     *
+     * @param  cameraId
+     *         Unique camera node identifier in string
+     *
+     * @return unique_ptr<CameraInfo>
+     *         A pointer to CameraInfo that is associated with a given camera
+     *         ID.  This returns a null pointer if this does not recognize a
+     *         given camera identifier.
+     */
+    unique_ptr<CameraInfo>& getCameraInfo(const string cameraId) noexcept {
+        unique_lock<mutex> lock(mConfigLock);
+        mConfigCond.wait(lock, [this] { return mIsReady; });
+
+        return mCameraInfo[cameraId];
+    }
+
+    /*
+     * Tell whether the configuration data is ready to be used
+     *
+     * @return bool
+     *         True if configuration data is ready to be consumed.
+     */
+    bool isReady() const {
+        return mIsReady;
+    }
+
+private:
+    /* Constructors */
+    ConfigManager(const char *xmlPath) :
+        mConfigFilePath(xmlPath),
+        mBinaryFilePath("") {
+    }
+
+    /* System configuration */
+    SystemInfo mSystemInfo;
+
+    /* Internal data structure for camera device information */
+    unordered_map<string, unique_ptr<CameraInfo>> mCameraInfo;
+
+    /* Internal data structure for camera device information */
+    unordered_map<string, unique_ptr<DisplayInfo>> mDisplayInfo;
+
+    /* Camera groups are stored in <groud id, CameraGroup> hash map */
+    unordered_map<string, unique_ptr<CameraGroupInfo>> mCameraGroups;
+
+    /*
+     * Camera positions are stored in <position, camera id set> hash map.
+     * The position must be one of front, rear, left, and right.
+     */
+    unordered_map<string, unordered_set<string>>  mCameraPosition;
+
+    /* Configuration data lock */
+    mutex mConfigLock;
+
+    /*
+     * This condition is signalled when it completes a configuration data
+     * preparation.
+     */
+    condition_variable mConfigCond;
+
+    /* A path to XML configuration file */
+    const char *mConfigFilePath;
+
+    /* A path to a binary configuration file */
+    const char *mBinaryFilePath;
+
+    /* Configuration data readiness */
+    bool mIsReady = false;
+
+    /*
+     * Parse a given EVS configuration file and store the information
+     * internally.
+     *
+     * @return bool
+     *         True if it completes parsing a file successfully.
+     */
+    bool readConfigDataFromXML() noexcept;
+
+    /*
+     * read the information of the vehicle
+     *
+     * @param  aSysElem
+     *         A pointer to "system" XML element.
+     */
+    void readSystemInfo(const XMLElement * const aSysElem);
+
+    /*
+     * read the information of camera devices
+     *
+     * @param  aCameraElem
+     *         A pointer to "camera" XML element that may contain multiple
+     *         "device" elements.
+     */
+    void readCameraInfo(const XMLElement * const aCameraElem);
+
+    /*
+     * read display device information
+     *
+     * @param  aDisplayElem
+     *         A pointer to "display" XML element that may contain multiple
+     *         "device" elements.
+     */
+    void readDisplayInfo(const XMLElement * const aDisplayElem);
+
+    /*
+     * read camera device information
+     *
+     * @param  aCamera
+     *         A pointer to CameraInfo that will be completed by this
+     *         method.
+     *         aDeviceElem
+     *         A pointer to "device" XML element that contains camera module
+     *         capability info and its characteristics.
+     *
+     * @return bool
+     *         Return false upon any failure in reading and processing camera
+     *         device information.
+     */
+    bool readCameraDeviceInfo(CameraInfo *aCamera,
+                              const XMLElement *aDeviceElem);
+
+    /*
+     * read camera metadata
+     *
+     * @param  aCapElem
+     *         A pointer to "cap" XML element.
+     * @param  aCamera
+     *         A pointer to CameraInfo that is being filled by this method.
+     * @param  dataSize
+     *         Required size of memory to store camera metadata found in this
+     *         method.  This is calculated in this method and returned to the
+     *         caller for camera_metadata allocation.
+     *
+     * @return size_t
+     *         Number of camera metadata entries
+     */
+    size_t readCameraCapabilities(const XMLElement * const aCapElem,
+                                  CameraInfo *aCamera,
+                                  size_t &dataSize);
+
+    /*
+     * read camera metadata
+     *
+     * @param  aParamElem
+     *         A pointer to "characteristics" XML element.
+     * @param  aCamera
+     *         A pointer to CameraInfo that is being filled by this method.
+     * @param  dataSize
+     *         Required size of memory to store camera metadata found in this
+     *         method.
+     *
+     * @return size_t
+     *         Number of camera metadata entries
+     */
+    size_t readCameraMetadata(const XMLElement * const aParamElem,
+                              CameraInfo *aCamera,
+                              size_t &dataSize);
+
+    /*
+     * construct camera_metadata_t from camera capabilities and metadata
+     *
+     * @param  aCamera
+     *         A pointer to CameraInfo that is being filled by this method.
+     * @param  totalEntries
+     *         Number of camera metadata entries to be added.
+     * @param  totalDataSize
+     *         Sum of sizes of camera metadata entries to be added.
+     *
+     * @return bool
+     *         False if either it fails to allocate memory for camera metadata
+     *         or its size is not large enough to add all found camera metadata
+     *         entries.
+     */
+    bool constructCameraMetadata(CameraInfo *aCamera,
+                                 const size_t totalEntries,
+                                 const size_t totalDataSize);
+
+    /*
+     * Read configuration data from the binary file
+     *
+     * @return bool
+     *         True if it succeeds to read configuration data from a binary
+     *         file.
+     */
+    bool readConfigDataFromBinary();
+
+    /*
+     * Store configuration data to the file
+     *
+     * @return bool
+     *         True if it succeeds to serialize mCameraInfo to the file.
+     */
+    bool writeConfigDataToBinary();
+
+    /*
+     * debugging method to print out all XML elements and their attributes in
+     * logcat message.
+     *
+     * @param  aNode
+     *         A pointer to the root XML element to navigate.
+     * @param  prefix
+     *         A prefix to XML string.
+     */
+    void printElementNames(const XMLElement *aNode, string prefix = "") const;
+};
+#endif // CONFIG_MANAGER_H
+
diff --git a/evs/sampleDriver/ConfigManagerUtil.cpp b/evs/sampleDriver/ConfigManagerUtil.cpp
new file mode 100644
index 0000000..5105f19
--- /dev/null
+++ b/evs/sampleDriver/ConfigManagerUtil.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConfigManagerUtil.h"
+
+#include <string>
+#include <sstream>
+#include <linux/videodev2.h>
+#include <system/graphics-base-v1.0.h>
+
+#include <android-base/logging.h>
+
+
+bool ConfigManagerUtil::convertToEvsCameraParam(const string &id,
+                                                CameraParam &camParam) {
+    string trimmed = ConfigManagerUtil::trimString(id);
+    bool success = true;
+
+    if (!trimmed.compare("BRIGHTNESS")) {
+        camParam =  CameraParam::BRIGHTNESS;
+    } else if (!trimmed.compare("CONTRAST")) {
+        camParam =  CameraParam::CONTRAST;
+    } else if (!trimmed.compare("AUTOGAIN")) {
+        camParam =  CameraParam::AUTOGAIN;
+    } else if (!trimmed.compare("GAIN")) {
+        camParam =  CameraParam::GAIN;
+    } else if (!trimmed.compare("AUTO_WHITE_BALANCE")) {
+        camParam =  CameraParam::AUTO_WHITE_BALANCE;
+    } else if (!trimmed.compare("WHITE_BALANCE_TEMPERATURE")) {
+        camParam =  CameraParam::WHITE_BALANCE_TEMPERATURE;
+    } else if (!trimmed.compare("SHARPNESS")) {
+        camParam =  CameraParam::SHARPNESS;
+    } else if (!trimmed.compare("AUTO_EXPOSURE")) {
+        camParam =  CameraParam::AUTO_EXPOSURE;
+    } else if (!trimmed.compare("ABSOLUTE_EXPOSURE")) {
+        camParam =  CameraParam::ABSOLUTE_EXPOSURE;
+    } else if (!trimmed.compare("ABSOLUTE_FOCUS")) {
+        camParam =  CameraParam::ABSOLUTE_FOCUS;
+    } else if (!trimmed.compare("AUTO_FOCUS")) {
+        camParam =  CameraParam::AUTO_FOCUS;
+    } else if (!trimmed.compare("ABSOLUTE_ZOOM")) {
+        camParam =  CameraParam::ABSOLUTE_ZOOM;
+    } else {
+        success = false;
+    }
+
+    return success;
+}
+
+
+bool ConfigManagerUtil::convertToPixelFormat(const string &format,
+                                             int32_t &pixFormat) {
+    string trimmed = ConfigManagerUtil::trimString(format);
+    bool success = true;
+
+    if (!trimmed.compare("RGBA_8888")) {
+        pixFormat =  HAL_PIXEL_FORMAT_RGBA_8888;
+    } else if (!trimmed.compare("YCRCB_420_SP")) {
+        pixFormat =  HAL_PIXEL_FORMAT_YCRCB_420_SP;
+    } else if (!trimmed.compare("YCBCR_422_I")) {
+        pixFormat =  HAL_PIXEL_FORMAT_YCBCR_422_I;
+    } else {
+        success = false;
+    }
+
+    return success;
+}
+
+
+bool ConfigManagerUtil::convertToMetadataTag(const char *name,
+                                             camera_metadata_tag &aTag) {
+    if (!strcmp(name, "LENS_DISTORTION")) {
+        aTag =  ANDROID_LENS_DISTORTION;
+    } else if (!strcmp(name, "LENS_INTRINSIC_CALIBRATION")) {
+        aTag =  ANDROID_LENS_INTRINSIC_CALIBRATION;
+    } else if (!strcmp(name, "LENS_POSE_ROTATION")) {
+        aTag =  ANDROID_LENS_POSE_ROTATION;
+    } else if (!strcmp(name, "LENS_POSE_TRANSLATION")) {
+        aTag =  ANDROID_LENS_POSE_TRANSLATION;
+    } else if (!strcmp(name, "REQUEST_AVAILABLE_CAPABILITIES")) {
+        aTag =  ANDROID_REQUEST_AVAILABLE_CAPABILITIES;
+    } else if (!strcmp(name, "LOGICAL_MULTI_CAMERA_PHYSICAL_IDS")) {
+        aTag =  ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS;
+    } else {
+        return false;
+    }
+
+    return true;
+}
+
+
+bool ConfigManagerUtil::convertToCameraCapability(
+    const char *name,
+    camera_metadata_enum_android_request_available_capabilities_t &cap) {
+
+    if (!strcmp(name, "DEPTH_OUTPUT")) {
+        cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT;
+    } else if (!strcmp(name, "LOGICAL_MULTI_CAMERA")) {
+        cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA;
+    } else if (!strcmp(name, "MONOCHROME")) {
+        cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME;
+    } else if (!strcmp(name, "SECURE_IMAGE_DATA")) {
+        cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA;
+    } else {
+        return false;
+    }
+
+    return true;
+}
+
+
+float *ConfigManagerUtil::convertFloatArray(const char *sz, const char *vals,
+                                            size_t &count, const char delimiter) {
+    string size_string(sz);
+    string value_string(vals);
+
+    count = stoi(size_string);
+    float *result = new float[count];
+    stringstream values(value_string);
+
+    int32_t idx = 0;
+    string token;
+    while (getline(values, token, delimiter)) {
+        result[idx++] = stof(token);
+    }
+
+    return result;
+}
+
+
+string ConfigManagerUtil::trimString(const string &src, const string &ws) {
+    const auto s = src.find_first_not_of(ws);
+    if (s == string::npos) {
+        return "";
+    }
+
+    const auto e = src.find_last_not_of(ws);
+    const auto r = e - s + 1;
+
+    return src.substr(s, r);
+}
+
diff --git a/evs/sampleDriver/ConfigManagerUtil.h b/evs/sampleDriver/ConfigManagerUtil.h
new file mode 100644
index 0000000..1710cac
--- /dev/null
+++ b/evs/sampleDriver/ConfigManagerUtil.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef CONFIG_MANAGER_UTIL_H
+#define CONFIG_MANAGER_UTIL_H
+
+#include <utility>
+#include <string>
+#include <system/camera_metadata.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
+
+using namespace std;
+using ::android::hardware::automotive::evs::V1_1::CameraParam;
+
+
+class ConfigManagerUtil {
+public:
+    /**
+     * Convert a given string into V4L2_CID_*
+     */
+    static bool convertToEvsCameraParam(const string &id,
+                                        CameraParam &camParam);
+    /**
+     * Convert a given string into android.hardware.graphics.common.PixelFormat
+     */
+    static bool convertToPixelFormat(const string &format,
+                                     int32_t &pixelFormat);
+    /**
+     * Convert a given string into corresponding camera metadata data tag defined in
+     * system/media/camera/include/system/camera_metadta_tags.h
+     */
+    static bool convertToMetadataTag(const char *name,
+                                     camera_metadata_tag &aTag);
+    /**
+     * Convert a given string into a floating value array
+     */
+    static float *convertFloatArray(const char *sz,
+                                    const char *vals,
+                                    size_t &count,
+                                    const char delimiter = ',');
+    /**
+     * Trim a string
+     */
+    static string trimString(const string &src,
+                             const string &ws = " \n\r\t\f\v");
+
+    /**
+     * Convert a given string to corresponding camera capabilities
+     */
+    static bool convertToCameraCapability(
+        const char *name,
+        camera_metadata_enum_android_request_available_capabilities_t &cap);
+
+};
+
+#endif // CONFIG_MANAGER_UTIL_H
+
diff --git a/evs/sampleDriver/EvsEnumerator.cpp b/evs/sampleDriver/EvsEnumerator.cpp
index 4487dab..2dbedb4 100644
--- a/evs/sampleDriver/EvsEnumerator.cpp
+++ b/evs/sampleDriver/EvsEnumerator.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016-2019 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
 #include "EvsEnumerator.h"
 #include "EvsV4lCamera.h"
 #include "EvsGlDisplay.h"
+#include "ConfigManager.h"
 
 #include <dirent.h>
 #include <hardware_legacy/uevent.h>
@@ -25,12 +26,14 @@
 
 
 using namespace std::chrono_literals;
+using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc;
 
 namespace android {
 namespace hardware {
 namespace automotive {
 namespace evs {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 
 
@@ -41,6 +44,11 @@
 wp<EvsGlDisplay>                                             EvsEnumerator::sActiveDisplay;
 std::mutex                                                   EvsEnumerator::sLock;
 std::condition_variable                                      EvsEnumerator::sCameraSignal;
+std::unique_ptr<ConfigManager>                               EvsEnumerator::sConfigManager;
+sp<IAutomotiveDisplayProxyService>                           EvsEnumerator::sDisplayProxy;
+std::unordered_map<uint8_t, uint64_t>                        EvsEnumerator::sDisplayPortList;
+uint64_t                                                     EvsEnumerator::sInternalDisplayId;
+
 
 // Constants
 const auto kEnumerationTimeout = 10s;
@@ -48,8 +56,11 @@
 
 bool EvsEnumerator::checkPermission() {
     hardware::IPCThreadState *ipc = hardware::IPCThreadState::self();
-    if (AID_AUTOMOTIVE_EVS != ipc->getCallingUid()) {
-        ALOGE("EVS access denied: pid = %d, uid = %d", ipc->getCallingPid(), ipc->getCallingUid());
+    if (AID_AUTOMOTIVE_EVS != ipc->getCallingUid() &&
+        AID_ROOT != ipc->getCallingUid()) {
+        LOG(ERROR) << "EVS access denied: "
+                   << "pid = " << ipc->getCallingPid()
+                   << ", uid = " << ipc->getCallingUid();
         return false;
     }
 
@@ -59,7 +70,7 @@
 void EvsEnumerator::EvsUeventThread(std::atomic<bool>& running) {
     int status = uevent_init();
     if (!status) {
-        ALOGE("Failed to initialize uevent handler.");
+        LOG(ERROR) << "Failed to initialize uevent handler.";
         return;
     }
 
@@ -104,12 +115,23 @@
             std::lock_guard<std::mutex> lock(sLock);
             if (cmd_removal) {
                 sCameraList.erase(devpath);
-                ALOGI("%s is removed", devpath.c_str());
+                LOG(INFO) << devpath << " is removed.";
             } else if (cmd_addition) {
                 // NOTE: we are here adding new device without a validation
                 // because it always fails to open, b/132164956.
-                sCameraList.emplace(devpath, devpath.c_str());
-                ALOGI("%s is added", devpath.c_str());
+                CameraRecord cam(devpath.c_str());
+                if (sConfigManager != nullptr) {
+                    unique_ptr<ConfigManager::CameraInfo> &camInfo =
+                        sConfigManager->getCameraInfo(devpath);
+                    if (camInfo != nullptr) {
+                        cam.desc.metadata.setToExternal(
+                            (uint8_t *)camInfo->characteristics,
+                             get_camera_metadata_size(camInfo->characteristics)
+                        );
+                    }
+                }
+                sCameraList.emplace(devpath, cam);
+                LOG(INFO) << devpath << " is added.";
             } else {
                 // Ignore all other actions including "change".
             }
@@ -122,13 +144,25 @@
     return;
 }
 
-EvsEnumerator::EvsEnumerator() {
-    ALOGD("EvsEnumerator created");
+EvsEnumerator::EvsEnumerator(sp<IAutomotiveDisplayProxyService> proxyService) {
+    LOG(DEBUG) << "EvsEnumerator is created.";
 
-    enumerateDevices();
+    if (sConfigManager == nullptr) {
+        /* loads and initializes ConfigManager in a separate thread */
+        sConfigManager =
+            ConfigManager::Create("/vendor/etc/automotive/evs/evs_sample_configuration.xml");
+    }
+
+    if (sDisplayProxy == nullptr) {
+        /* sets a car-window service handle */
+        sDisplayProxy = proxyService;
+    }
+
+    enumerateCameras();
+    enumerateDisplays();
 }
 
-void EvsEnumerator::enumerateDevices() {
+void EvsEnumerator::enumerateCameras() {
     // For every video* entry in the dev folder, see if it reports suitable capabilities
     // WARNING:  Depending on the driver implementations this could be slow, especially if
     //           there are timeouts or round trips to hardware required to collect the needed
@@ -137,7 +171,8 @@
     //           For example, this code might be replaced with nothing more than:
     //                   sCameraList.emplace("/dev/video0");
     //                   sCameraList.emplace("/dev/video1");
-    ALOGI("%s: Starting dev/video* enumeration", __FUNCTION__);
+    LOG(INFO) << __FUNCTION__
+              << ": Starting dev/video* enumeration";
     unsigned videoCount   = 0;
     unsigned captureCount = 0;
     DIR* dir = opendir("/dev");
@@ -155,7 +190,7 @@
                 deviceName += entry->d_name;
                 videoCount++;
                 if (sCameraList.find(deviceName) != sCameraList.end()) {
-                    ALOGI("%s has been added already.", deviceName.c_str());
+                    LOG(INFO) << deviceName << " has been added already.";
                     captureCount++;
                 } else if(qualifyCaptureDevice(deviceName.c_str())) {
                     sCameraList.emplace(deviceName, deviceName.c_str());
@@ -165,12 +200,42 @@
         }
     }
 
-    ALOGI("Found %d qualified video capture devices of %d checked\n", captureCount, videoCount);
+    LOG(INFO) << "Found " << captureCount << " qualified video capture devices "
+              << "of " << videoCount << " checked.";
 }
 
+
+void EvsEnumerator::enumerateDisplays() {
+    LOG(INFO) << __FUNCTION__
+              << ": Starting display enumeration";
+    if (!sDisplayProxy) {
+        LOG(ERROR) << "AutomotiveDisplayProxyService is not available!";
+        return;
+    }
+
+    sDisplayProxy->getDisplayIdList(
+        [](const auto& displayIds) {
+            // The first entry of the list is the internal display.  See
+            // SurfaceFlinger::getPhysicalDisplayIds() implementation.
+            if (displayIds.size() > 0) {
+                sInternalDisplayId = displayIds[0];
+                for (const auto& id : displayIds) {
+                    const auto port = id & 0xF;
+                    LOG(INFO) << "Display " << std::hex << id
+                              << " is detected on the port, " << port;
+                    sDisplayPortList.insert_or_assign(port, id);
+                }
+            }
+        }
+    );
+
+    LOG(INFO) << "Found " << sDisplayPortList.size() << " displays";
+}
+
+
 // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
 Return<void> EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb)  {
-    ALOGD("getCameraList");
+    LOG(DEBUG) << __FUNCTION__;
     if (!checkPermission()) {
         return Void();
     }
@@ -183,7 +248,7 @@
             if (!sCameraSignal.wait_for(lock,
                                         kEnumerationTimeout,
                                         []{ return sCameraList.size() > 0; })) {
-                ALOGD("Timer expired.  No new device has been added.");
+                LOG(DEBUG) << "Timer expired.  No new device has been added.";
             }
         }
     }
@@ -191,15 +256,15 @@
     const unsigned numCameras = sCameraList.size();
 
     // Build up a packed array of CameraDesc for return
-    hidl_vec<CameraDesc> hidlCameras;
+    hidl_vec<CameraDesc_1_0> hidlCameras;
     hidlCameras.resize(numCameras);
     unsigned i = 0;
     for (const auto& [key, cam] : sCameraList) {
-        hidlCameras[i++] = cam.desc;
+        hidlCameras[i++] = cam.desc.v1;
     }
 
     // Send back the results
-    ALOGD("reporting %zu cameras available", hidlCameras.size());
+    LOG(DEBUG) << "Reporting " << hidlCameras.size() << " cameras available";
     _hidl_cb(hidlCameras);
 
     // HIDL convention says we return Void if we sent our result back via callback
@@ -207,75 +272,66 @@
 }
 
 
-Return<sp<IEvsCamera>> EvsEnumerator::openCamera(const hidl_string& cameraId) {
-    ALOGD("openCamera");
+Return<sp<IEvsCamera_1_0>> EvsEnumerator::openCamera(const hidl_string& cameraId) {
+    LOG(DEBUG) << __FUNCTION__;
     if (!checkPermission()) {
         return nullptr;
     }
 
     // Is this a recognized camera id?
     CameraRecord *pRecord = findCameraById(cameraId);
+    if (pRecord == nullptr) {
+        LOG(ERROR) << cameraId << " does not exist!";
+        return nullptr;
+    }
 
     // Has this camera already been instantiated by another caller?
     sp<EvsV4lCamera> pActiveCamera = pRecord->activeInstance.promote();
     if (pActiveCamera != nullptr) {
-        ALOGW("Killing previous camera because of new caller");
+        LOG(WARNING) << "Killing previous camera because of new caller";
         closeCamera(pActiveCamera);
     }
 
     // Construct a camera instance for the caller
-    pActiveCamera = new EvsV4lCamera(cameraId.c_str());
+    if (sConfigManager == nullptr) {
+        pActiveCamera = EvsV4lCamera::Create(cameraId.c_str());
+    } else {
+        pActiveCamera = EvsV4lCamera::Create(cameraId.c_str(),
+                                             sConfigManager->getCameraInfo(cameraId));
+    }
+
     pRecord->activeInstance = pActiveCamera;
     if (pActiveCamera == nullptr) {
-        ALOGE("Failed to allocate new EvsV4lCamera object for %s\n", cameraId.c_str());
+        LOG(ERROR) << "Failed to create new EvsV4lCamera object for " << cameraId;
     }
 
     return pActiveCamera;
 }
 
 
-Return<void> EvsEnumerator::closeCamera(const ::android::sp<IEvsCamera>& pCamera) {
-    ALOGD("closeCamera");
+Return<void> EvsEnumerator::closeCamera(const ::android::sp<IEvsCamera_1_0>& pCamera) {
+    LOG(DEBUG) << __FUNCTION__;
 
     if (pCamera == nullptr) {
-        ALOGE("Ignoring call to closeCamera with null camera ptr");
+        LOG(ERROR) << "Ignoring call to closeCamera with null camera ptr";
         return Void();
     }
 
     // Get the camera id so we can find it in our list
     std::string cameraId;
-    pCamera->getCameraInfo([&cameraId](CameraDesc desc) {
+    pCamera->getCameraInfo([&cameraId](CameraDesc_1_0 desc) {
                                cameraId = desc.cameraId;
                            }
     );
 
-    // Find the named camera
-    CameraRecord *pRecord = findCameraById(cameraId);
-
-    // Is the display being destroyed actually the one we think is active?
-    if (!pRecord) {
-        ALOGE("Asked to close a camera whose name isn't recognized");
-    } else {
-        sp<EvsV4lCamera> pActiveCamera = pRecord->activeInstance.promote();
-
-        if (pActiveCamera == nullptr) {
-            ALOGE("Somehow a camera is being destroyed when the enumerator didn't know one existed");
-        } else if (pActiveCamera != pCamera) {
-            // This can happen if the camera was aggressively reopened, orphaning this previous instance
-            ALOGW("Ignoring close of previously orphaned camera - why did a client steal?");
-        } else {
-            // Drop the active camera
-            pActiveCamera->shutdown();
-            pRecord->activeInstance = nullptr;
-        }
-    }
+    closeCamera_impl(pCamera, cameraId);
 
     return Void();
 }
 
 
-Return<sp<IEvsDisplay>> EvsEnumerator::openDisplay() {
-    ALOGD("openDisplay");
+Return<sp<IEvsDisplay_1_0>> EvsEnumerator::openDisplay() {
+    LOG(DEBUG) << __FUNCTION__;
     if (!checkPermission()) {
         return nullptr;
     }
@@ -284,28 +340,29 @@
     // give exclusive access to the new caller.
     sp<EvsGlDisplay> pActiveDisplay = sActiveDisplay.promote();
     if (pActiveDisplay != nullptr) {
-        ALOGW("Killing previous display because of new caller");
+        LOG(WARNING) << "Killing previous display because of new caller";
         closeDisplay(pActiveDisplay);
     }
 
-    // Create a new display interface and return it
-    pActiveDisplay = new EvsGlDisplay();
+    // Create a new display interface and return it.
+    pActiveDisplay = new EvsGlDisplay(sDisplayProxy, sInternalDisplayId);
     sActiveDisplay = pActiveDisplay;
 
-    ALOGD("Returning new EvsGlDisplay object %p", pActiveDisplay.get());
+    LOG(DEBUG) << "Returning new EvsGlDisplay object " << pActiveDisplay.get();
     return pActiveDisplay;
 }
 
 
-Return<void> EvsEnumerator::closeDisplay(const ::android::sp<IEvsDisplay>& pDisplay) {
-    ALOGD("closeDisplay");
+Return<void> EvsEnumerator::closeDisplay(const ::android::sp<IEvsDisplay_1_0>& pDisplay) {
+    LOG(DEBUG) << __FUNCTION__;
 
     // Do we still have a display object we think should be active?
     sp<EvsGlDisplay> pActiveDisplay = sActiveDisplay.promote();
     if (pActiveDisplay == nullptr) {
-        ALOGE("Somehow a display is being destroyed when the enumerator didn't know one existed");
+        LOG(ERROR) << "Somehow a display is being destroyed "
+                   << "when the enumerator didn't know one existed";
     } else if (sActiveDisplay != pDisplay) {
-        ALOGW("Ignoring close of previously orphaned display - why did a client steal?");
+        LOG(WARNING) << "Ignoring close of previously orphaned display - why did a client steal?";
     } else {
         // Drop the active display
         pActiveDisplay->forceShutdown();
@@ -316,22 +373,215 @@
 }
 
 
-Return<DisplayState> EvsEnumerator::getDisplayState()  {
-    ALOGD("getDisplayState");
+Return<EvsDisplayState> EvsEnumerator::getDisplayState()  {
+    LOG(DEBUG) << __FUNCTION__;
     if (!checkPermission()) {
-        return DisplayState::DEAD;
+        return EvsDisplayState::DEAD;
     }
 
     // Do we still have a display object we think should be active?
-    sp<IEvsDisplay> pActiveDisplay = sActiveDisplay.promote();
+    sp<IEvsDisplay_1_0> pActiveDisplay = sActiveDisplay.promote();
     if (pActiveDisplay != nullptr) {
         return pActiveDisplay->getDisplayState();
     } else {
-        return DisplayState::NOT_OPEN;
+        return EvsDisplayState::NOT_OPEN;
     }
 }
 
 
+// Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
+Return<void> EvsEnumerator::getCameraList_1_1(getCameraList_1_1_cb _hidl_cb)  {
+    LOG(DEBUG) << __FUNCTION__;
+    if (!checkPermission()) {
+        return Void();
+    }
+
+    {
+        std::unique_lock<std::mutex> lock(sLock);
+        if (sCameraList.size() < 1) {
+            // No qualified device has been found.  Wait until new device is ready,
+            if (!sCameraSignal.wait_for(lock,
+                                        kEnumerationTimeout,
+                                        []{ return sCameraList.size() > 0; })) {
+                LOG(DEBUG) << "Timer expired.  No new device has been added.";
+            }
+        }
+    }
+
+    std::vector<CameraDesc_1_1> hidlCameras;
+    if (sConfigManager == nullptr) {
+        auto numCameras = sCameraList.size();
+
+        // Build up a packed array of CameraDesc for return
+        hidlCameras.resize(numCameras);
+        unsigned i = 0;
+        for (auto&& [key, cam] : sCameraList) {
+            hidlCameras[i++] = cam.desc;
+        }
+    } else {
+        // Build up a packed array of CameraDesc for return
+        for (auto&& [key, cam] : sCameraList) {
+            unique_ptr<ConfigManager::CameraInfo> &tempInfo =
+                sConfigManager->getCameraInfo(key);
+            if (tempInfo != nullptr) {
+                cam.desc.metadata.setToExternal(
+                    (uint8_t *)tempInfo->characteristics,
+                     get_camera_metadata_size(tempInfo->characteristics)
+                );
+            }
+
+            hidlCameras.emplace_back(cam.desc);
+        }
+
+        // Adding camera groups that represent logical camera devices
+        auto camGroups = sConfigManager->getCameraGroupIdList();
+        for (auto&& id : camGroups) {
+            if (sCameraList.find(id) != sCameraList.end()) {
+                // Already exists in the list
+                continue;
+            }
+
+            unique_ptr<ConfigManager::CameraGroupInfo> &tempInfo =
+                sConfigManager->getCameraGroupInfo(id);
+            CameraRecord cam(id.c_str());
+            if (tempInfo != nullptr) {
+                cam.desc.metadata.setToExternal(
+                    (uint8_t *)tempInfo->characteristics,
+                     get_camera_metadata_size(tempInfo->characteristics)
+                );
+            }
+
+            sCameraList.emplace(id, cam);
+            hidlCameras.emplace_back(cam.desc);
+        }
+    }
+
+    // Send back the results
+    _hidl_cb(hidlCameras);
+
+    // HIDL convention says we return Void if we sent our result back via callback
+    return Void();
+}
+
+
+Return<sp<IEvsCamera_1_1>> EvsEnumerator::openCamera_1_1(const hidl_string& cameraId,
+                                                         const Stream& streamCfg) {
+    LOG(DEBUG) << __FUNCTION__;
+    if (!checkPermission()) {
+        return nullptr;
+    }
+
+    // Is this a recognized camera id?
+    CameraRecord *pRecord = findCameraById(cameraId);
+    if (pRecord == nullptr) {
+        LOG(ERROR) << cameraId << " does not exist!";
+        return nullptr;
+    }
+
+    // Has this camera already been instantiated by another caller?
+    sp<EvsV4lCamera> pActiveCamera = pRecord->activeInstance.promote();
+    if (pActiveCamera != nullptr) {
+        LOG(WARNING) << "Killing previous camera because of new caller";
+        closeCamera(pActiveCamera);
+    }
+
+    // Construct a camera instance for the caller
+    if (sConfigManager == nullptr) {
+        LOG(WARNING) << "ConfigManager is not available.  "
+                     << "Given stream configuration is ignored.";
+        pActiveCamera = EvsV4lCamera::Create(cameraId.c_str());
+    } else {
+        pActiveCamera = EvsV4lCamera::Create(cameraId.c_str(),
+                                             sConfigManager->getCameraInfo(cameraId),
+                                             &streamCfg);
+    }
+    pRecord->activeInstance = pActiveCamera;
+    if (pActiveCamera == nullptr) {
+        LOG(ERROR) << "Failed to create new EvsV4lCamera object for " << cameraId;
+    }
+
+    return pActiveCamera;
+}
+
+
+Return<void> EvsEnumerator::getDisplayIdList(getDisplayIdList_cb _list_cb) {
+    hidl_vec<uint8_t> ids;
+
+    if (sDisplayPortList.size() > 0) {
+        ids.resize(sDisplayPortList.size());
+        unsigned i = 0;
+        ids[i++] = sInternalDisplayId & 0xF;
+        for (const auto& [port, id] : sDisplayPortList) {
+            if (sInternalDisplayId != id) {
+                ids[i++] = port;
+            }
+        }
+    }
+
+    _list_cb(ids);
+    return Void();
+}
+
+
+Return<sp<IEvsDisplay_1_1>> EvsEnumerator::openDisplay_1_1(uint8_t port) {
+    LOG(DEBUG) << __FUNCTION__;
+    if (!checkPermission()) {
+        return nullptr;
+    }
+
+    // If we already have a display active, then we need to shut it down so we can
+    // give exclusive access to the new caller.
+    sp<EvsGlDisplay> pActiveDisplay = sActiveDisplay.promote();
+    if (pActiveDisplay != nullptr) {
+        LOG(WARNING) << "Killing previous display because of new caller";
+        closeDisplay(pActiveDisplay);
+    }
+
+    // Create a new display interface and return it
+    if (sDisplayPortList.find(port) == sDisplayPortList.end()) {
+        LOG(ERROR) << "No display is available on the port "
+                   << static_cast<int32_t>(port);
+        return nullptr;
+    }
+
+    pActiveDisplay = new EvsGlDisplay(sDisplayProxy, sDisplayPortList[port]);
+    sActiveDisplay = pActiveDisplay;
+
+    LOG(DEBUG) << "Returning new EvsGlDisplay object " << pActiveDisplay.get();
+    return pActiveDisplay;
+}
+
+
+void EvsEnumerator::closeCamera_impl(const sp<IEvsCamera_1_0>& pCamera,
+                                     const std::string& cameraId) {
+    // Find the named camera
+    CameraRecord *pRecord = findCameraById(cameraId);
+
+    // Is the display being destroyed actually the one we think is active?
+    if (!pRecord) {
+        LOG(ERROR) << "Asked to close a camera whose name isn't recognized";
+    } else {
+        sp<EvsV4lCamera> pActiveCamera = pRecord->activeInstance.promote();
+
+        if (pActiveCamera == nullptr) {
+            LOG(ERROR) << "Somehow a camera is being destroyed "
+                       << "when the enumerator didn't know one existed";
+        } else if (pActiveCamera != pCamera) {
+            // This can happen if the camera was aggressively reopened,
+            // orphaning this previous instance
+            LOG(WARNING) << "Ignoring close of previously orphaned camera "
+                         << "- why did a client steal?";
+        } else {
+            // Drop the active camera
+            pActiveCamera->shutdown();
+            pRecord->activeInstance = nullptr;
+        }
+    }
+
+    return;
+}
+
+
 bool EvsEnumerator::qualifyCaptureDevice(const char* deviceName) {
     class FileHandleWrapper {
     public:
@@ -365,9 +615,10 @@
     for (int i=0; !found; i++) {
         formatDescription.index = i;
         if (ioctl(fd, VIDIOC_ENUM_FMT, &formatDescription) == 0) {
-            ALOGI("FORMAT 0x%X, type 0x%X, desc %s, flags 0x%X",
-                  formatDescription.pixelformat, formatDescription.type,
-                  formatDescription.description, formatDescription.flags);
+            LOG(INFO) << "Format: 0x" << std::hex << formatDescription.pixelformat
+                      << " Type: 0x" << std::hex << formatDescription.type
+                      << " Desc: " << formatDescription.description
+                      << " Flags: 0x" << std::hex << formatDescription.flags;
             switch (formatDescription.pixelformat)
             {
                 case V4L2_PIX_FMT_YUYV:     found = true; break;
@@ -380,7 +631,8 @@
                 case V4L2_PIX_FMT_XRGB32:   found = true; break;
 #endif // V4L2_PIX_FMT_ARGB32
                 default:
-                    ALOGW("Unsupported, 0x%X", formatDescription.pixelformat);
+                    LOG(WARNING) << "Unsupported, "
+                                 << std::hex << formatDescription.pixelformat;
                     break;
             }
         } else {
@@ -406,8 +658,31 @@
 }
 
 
+// TODO(b/149874793): Add implementation for EVS Manager and Sample driver
+Return<void> EvsEnumerator::getUltrasonicsArrayList(getUltrasonicsArrayList_cb _hidl_cb) {
+    hidl_vec<UltrasonicsArrayDesc> ultrasonicsArrayDesc;
+    _hidl_cb(ultrasonicsArrayDesc);
+    return Void();
+}
+
+
+// TODO(b/149874793): Add implementation for EVS Manager and Sample driver
+Return<sp<IEvsUltrasonicsArray>> EvsEnumerator::openUltrasonicsArray(
+        const hidl_string& ultrasonicsArrayId) {
+    (void)ultrasonicsArrayId;
+    return sp<IEvsUltrasonicsArray>();
+}
+
+
+// TODO(b/149874793): Add implementation for EVS Manager and Sample driver
+Return<void> EvsEnumerator::closeUltrasonicsArray(
+        const ::android::sp<IEvsUltrasonicsArray>& evsUltrasonicsArray)  {
+    (void)evsUltrasonicsArray;
+    return Void();
+}
+
 } // namespace implementation
-} // namespace V1_0
+} // namespace V1_1
 } // namespace evs
 } // namespace automotive
 } // namespace hardware
diff --git a/evs/sampleDriver/EvsEnumerator.h b/evs/sampleDriver/EvsEnumerator.h
index 1d36886..33b497e 100644
--- a/evs/sampleDriver/EvsEnumerator.h
+++ b/evs/sampleDriver/EvsEnumerator.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016-2019 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,21 +14,33 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERAENUMERATOR_H
-#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERAENUMERATOR_H
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
 
-#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
-#include <android/hardware/automotive/evs/1.0/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android/frameworks/automotive/display/1.0/IAutomotiveDisplayProxyService.h>
 
 #include <unordered_map>
 #include <thread>
 #include <atomic>
 
+#include "ConfigManager.h"
+
+using ::android::hardware::camera::device::V3_2::Stream;
+using EvsDisplayState = ::android::hardware::automotive::evs::V1_0::DisplayState;
+using IEvsCamera_1_0  = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
+using IEvsCamera_1_1  = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+using IEvsDisplay_1_0  = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using IEvsDisplay_1_1  = ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
+using android::frameworks::automotive::display::V1_0::IAutomotiveDisplayProxyService;
+
 namespace android {
 namespace hardware {
 namespace automotive {
 namespace evs {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 
 
@@ -38,15 +50,28 @@
 class EvsEnumerator : public IEvsEnumerator {
 public:
     // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
-    Return<void> getCameraList(getCameraList_cb _hidl_cb)  override;
-    Return<sp<IEvsCamera>> openCamera(const hidl_string& cameraId) override;
-    Return<void> closeCamera(const ::android::sp<IEvsCamera>& carCamera)  override;
-    Return<sp<IEvsDisplay>> openDisplay()  override;
-    Return<void> closeDisplay(const ::android::sp<IEvsDisplay>& display)  override;
-    Return<DisplayState> getDisplayState()  override;
+    Return<void>                getCameraList(getCameraList_cb _hidl_cb)  override;
+    Return<sp<IEvsCamera_1_0>>  openCamera(const hidl_string& cameraId) override;
+    Return<void>                closeCamera(const ::android::sp<IEvsCamera_1_0>& pCamera)  override;
+    Return<sp<IEvsDisplay_1_0>> openDisplay()  override;
+    Return<void>                closeDisplay(const ::android::sp<IEvsDisplay_1_0>& display)  override;
+    Return<EvsDisplayState>     getDisplayState()  override;
+
+    // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
+    Return<void>                getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) override;
+    Return<sp<IEvsCamera_1_1>>  openCamera_1_1(const hidl_string& cameraId,
+                                               const Stream& streamCfg) override;
+    Return<bool>                isHardware() override { return true; }
+    Return<void>                getDisplayIdList(getDisplayIdList_cb _list_cb) override;
+    Return<sp<IEvsDisplay_1_1>> openDisplay_1_1(uint8_t port) override;
+    Return<void> getUltrasonicsArrayList(getUltrasonicsArrayList_cb _hidl_cb) override;
+    Return<sp<IEvsUltrasonicsArray>> openUltrasonicsArray(
+            const hidl_string& ultrasonicsArrayId) override;
+    Return<void> closeUltrasonicsArray(
+            const ::android::sp<IEvsUltrasonicsArray>& evsUltrasonicsArray) override;
 
     // Implementation details
-    EvsEnumerator();
+    EvsEnumerator(sp<IAutomotiveDisplayProxyService> proxyService = nullptr);
 
     // Listen to video device uevents
     static void EvsUeventThread(std::atomic<bool>& running);
@@ -56,14 +81,17 @@
         CameraDesc          desc;
         wp<EvsV4lCamera>    activeInstance;
 
-        CameraRecord(const char *cameraId) : desc() { desc.cameraId = cameraId; }
+        CameraRecord(const char *cameraId) : desc() { desc.v1.cameraId = cameraId; }
     };
 
     bool checkPermission();
 
     static bool qualifyCaptureDevice(const char* deviceName);
     static CameraRecord* findCameraById(const std::string& cameraId);
-    static void enumerateDevices();
+    static void enumerateCameras();
+    static void enumerateDisplays();
+
+    void closeCamera_impl(const sp<IEvsCamera_1_0>& pCamera, const std::string& cameraId);
 
     // NOTE:  All members values are static so that all clients operate on the same state
     //        That is to say, this is effectively a singleton despite the fact that HIDL
@@ -79,13 +107,20 @@
 
     static std::mutex                       sLock;          // Mutex on shared camera device list.
     static std::condition_variable          sCameraSignal;  // Signal on camera device addition.
+
+    static std::unique_ptr<ConfigManager>   sConfigManager; // ConfigManager
+
+    static sp<IAutomotiveDisplayProxyService> sDisplayProxy;
+    static std::unordered_map<uint8_t,
+                              uint64_t>       sDisplayPortList;
+    static uint64_t                           sInternalDisplayId;
 };
 
 } // namespace implementation
-} // namespace V1_0
+} // namespace V1_1
 } // namespace evs
 } // namespace automotive
 } // namespace hardware
 } // namespace android
 
-#endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERAENUMERATOR_H
+#endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
diff --git a/evs/sampleDriver/EvsGlDisplay.cpp b/evs/sampleDriver/EvsGlDisplay.cpp
index 89bfcf9..949860c 100644
--- a/evs/sampleDriver/EvsGlDisplay.cpp
+++ b/evs/sampleDriver/EvsGlDisplay.cpp
@@ -20,18 +20,25 @@
 #include <ui/GraphicBufferMapper.h>
 #include <utils/SystemClock.h>
 
+using ::android::frameworks::automotive::display::V1_0::HwDisplayConfig;
+using ::android::frameworks::automotive::display::V1_0::HwDisplayState;
 
 namespace android {
 namespace hardware {
 namespace automotive {
 namespace evs {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 
+#ifdef EVS_DEBUG
 static bool sDebugFirstFrameDisplayed = false;
+#endif
 
-EvsGlDisplay::EvsGlDisplay() {
-    ALOGD("EvsGlDisplay instantiated");
+
+EvsGlDisplay::EvsGlDisplay(sp<IAutomotiveDisplayProxyService> pDisplayProxy, uint64_t displayId)
+    : mDisplayProxy(pDisplayProxy),
+      mDisplayId(displayId) {
+    LOG(DEBUG) << "EvsGlDisplay instantiated";
 
     // Set up our self description
     // NOTE:  These are arbitrary values chosen for testing
@@ -41,8 +48,8 @@
 
 
 EvsGlDisplay::~EvsGlDisplay() {
-    ALOGD("EvsGlDisplay being destroyed");
-	forceShutdown();
+    LOG(DEBUG) << "EvsGlDisplay being destroyed";
+    forceShutdown();
 }
 
 
@@ -51,7 +58,7 @@
  */
 void EvsGlDisplay::forceShutdown()
 {
-    ALOGD("EvsGlDisplay forceShutdown");
+    LOG(DEBUG) << "EvsGlDisplay forceShutdown";
     std::lock_guard<std::mutex> lock(mAccessLock);
 
     // If the buffer isn't being held by a remote client, release it now as an
@@ -60,7 +67,7 @@
     if (mBuffer.memHandle) {
         // Report if we're going away while a buffer is outstanding
         if (mFrameBusy) {
-            ALOGE("EvsGlDisplay going down while client is holding a buffer");
+            LOG(ERROR) << "EvsGlDisplay going down while client is holding a buffer";
         }
 
         // Drop the graphics buffer we've been using
@@ -68,12 +75,13 @@
         alloc.free(mBuffer.memHandle);
         mBuffer.memHandle = nullptr;
 
+        mGlWrapper.hideWindow(mDisplayProxy, mDisplayId);
         mGlWrapper.shutdown();
     }
 
     // Put this object into an unrecoverable error state since somebody else
     // is going to own the display now.
-    mRequestedState = DisplayState::DEAD;
+    mRequestedState = EvsDisplayState::DEAD;
 }
 
 
@@ -82,7 +90,7 @@
  * See the description of the DisplayDesc structure for details.
  */
 Return<void> EvsGlDisplay::getDisplayInfo(getDisplayInfo_cb _hidl_cb)  {
-    ALOGD("getDisplayInfo");
+    LOG(DEBUG) << __FUNCTION__;
 
     // Send back our self description
     _hidl_cb(mInfo);
@@ -99,26 +107,26 @@
  * then begin providing video.  When the display is no longer required, the client
  * is expected to request the NOT_VISIBLE state after passing the last video frame.
  */
-Return<EvsResult> EvsGlDisplay::setDisplayState(DisplayState state) {
-    ALOGD("setDisplayState");
+Return<EvsResult> EvsGlDisplay::setDisplayState(EvsDisplayState state) {
+    LOG(DEBUG) << __FUNCTION__;
     std::lock_guard<std::mutex> lock(mAccessLock);
 
-    if (mRequestedState == DisplayState::DEAD) {
+    if (mRequestedState == EvsDisplayState::DEAD) {
         // This object no longer owns the display -- it's been superceeded!
         return EvsResult::OWNERSHIP_LOST;
     }
 
     // Ensure we recognize the requested state so we don't go off the rails
-    if (state >= DisplayState::NUM_STATES) {
+    if (state >= EvsDisplayState::NUM_STATES) {
         return EvsResult::INVALID_ARG;
     }
 
     switch (state) {
-    case DisplayState::NOT_VISIBLE:
-        mGlWrapper.hideWindow();
+    case EvsDisplayState::NOT_VISIBLE:
+        mGlWrapper.hideWindow(mDisplayProxy, mDisplayId);
         break;
-    case DisplayState::VISIBLE:
-        mGlWrapper.showWindow();
+    case EvsDisplayState::VISIBLE:
+        mGlWrapper.showWindow(mDisplayProxy, mDisplayId);
         break;
     default:
         break;
@@ -138,8 +146,8 @@
  * the device layer, making it undesirable for the HAL implementation to
  * spontaneously change display states.
  */
-Return<DisplayState> EvsGlDisplay::getDisplayState()  {
-    ALOGD("getDisplayState");
+Return<EvsDisplayState> EvsGlDisplay::getDisplayState()  {
+    LOG(DEBUG) << __FUNCTION__;
     std::lock_guard<std::mutex> lock(mAccessLock);
 
     return mRequestedState;
@@ -153,13 +161,12 @@
  * display is no longer visible.
  */
 Return<void> EvsGlDisplay::getTargetBuffer(getTargetBuffer_cb _hidl_cb)  {
-    ALOGV("getTargetBuffer");
+    LOG(DEBUG) << __FUNCTION__;
     std::lock_guard<std::mutex> lock(mAccessLock);
 
-    if (mRequestedState == DisplayState::DEAD) {
-        ALOGE("Rejecting buffer request from object that lost ownership of the display.");
-        BufferDesc nullBuff = {};
-        _hidl_cb(nullBuff);
+    if (mRequestedState == EvsDisplayState::DEAD) {
+        LOG(ERROR) << "Rejecting buffer request from object that lost ownership of the display.";
+        _hidl_cb({});
         return Void();
     }
 
@@ -169,11 +176,10 @@
         // NOTE:  This will cause the display to become "VISIBLE" before a frame is actually
         // returned, which is contrary to the spec and will likely result in a black frame being
         // (briefly) shown.
-        if (!mGlWrapper.initialize()) {
+        if (!mGlWrapper.initialize(mDisplayProxy, mDisplayId)) {
             // Report the failure
-            ALOGE("Failed to initialize GL display");
-            BufferDesc nullBuff = {};
-            _hidl_cb(nullBuff);
+            LOG(ERROR) << "Failed to initialize GL display";
+            _hidl_cb({});
             return Void();
         }
 
@@ -194,24 +200,23 @@
                                          &mBuffer.stride,
                                          0, "EvsGlDisplay");
         if (result != NO_ERROR) {
-            ALOGE("Error %d allocating %d x %d graphics buffer",
-                  result, mBuffer.width, mBuffer.height);
-            BufferDesc nullBuff = {};
-            _hidl_cb(nullBuff);
+            LOG(ERROR) << "Error " << result
+                       << " allocating " << mBuffer.width << " x " << mBuffer.height
+                       << " graphics buffer.";
+            _hidl_cb({});
             mGlWrapper.shutdown();
             return Void();
         }
         if (!handle) {
-            ALOGE("We didn't get a buffer handle back from the allocator");
-            BufferDesc nullBuff = {};
-            _hidl_cb(nullBuff);
+            LOG(ERROR) << "We didn't get a buffer handle back from the allocator";
+            _hidl_cb({});
             mGlWrapper.shutdown();
             return Void();
         }
 
         mBuffer.memHandle = handle;
-        ALOGD("Allocated new buffer %p with stride %u",
-              mBuffer.memHandle.getNativeHandle(), mBuffer.stride);
+        LOG(DEBUG) << "Allocated new buffer " << mBuffer.memHandle.getNativeHandle()
+                   << " with stride " <<  mBuffer.stride;
         mFrameBusy = false;
     }
 
@@ -221,17 +226,16 @@
         // (an unsupported mode of operation) or else the client hasn't returned
         // a previously issued buffer yet (they're behaving badly).
         // NOTE:  We have to make the callback even if we have nothing to provide
-        ALOGE("getTargetBuffer called while no buffers available.");
-        BufferDesc nullBuff = {};
-        _hidl_cb(nullBuff);
+        LOG(ERROR) << "getTargetBuffer called while no buffers available.";
+        _hidl_cb({});
         return Void();
     } else {
         // Mark our buffer as busy
         mFrameBusy = true;
 
         // Send the buffer to the client
-        ALOGV("Providing display buffer handle %p as id %d",
-              mBuffer.memHandle.getNativeHandle(), mBuffer.bufferId);
+        LOG(VERBOSE) << "Providing display buffer handle " << mBuffer.memHandle.getNativeHandle()
+                     << " as id " << mBuffer.bufferId;
         _hidl_cb(mBuffer);
         return Void();
     }
@@ -242,41 +246,42 @@
  * This call tells the display that the buffer is ready for display.
  * The buffer is no longer valid for use by the client after this call.
  */
-Return<EvsResult> EvsGlDisplay::returnTargetBufferForDisplay(const BufferDesc& buffer)  {
-    ALOGV("returnTargetBufferForDisplay %p", buffer.memHandle.getNativeHandle());
+Return<EvsResult> EvsGlDisplay::returnTargetBufferForDisplay(const BufferDesc_1_0& buffer)  {
+    LOG(VERBOSE) << __FUNCTION__ << " " << buffer.memHandle.getNativeHandle();
     std::lock_guard<std::mutex> lock(mAccessLock);
 
     // Nobody should call us with a null handle
     if (!buffer.memHandle.getNativeHandle()) {
-        ALOGE ("returnTargetBufferForDisplay called without a valid buffer handle.\n");
+        LOG(ERROR) << __FUNCTION__
+                   << " called without a valid buffer handle.";
         return EvsResult::INVALID_ARG;
     }
     if (buffer.bufferId != mBuffer.bufferId) {
-        ALOGE ("Got an unrecognized frame returned.\n");
+        LOG(ERROR) << "Got an unrecognized frame returned.";
         return EvsResult::INVALID_ARG;
     }
     if (!mFrameBusy) {
-        ALOGE ("A frame was returned with no outstanding frames.\n");
+        LOG(ERROR) << "A frame was returned with no outstanding frames.";
         return EvsResult::BUFFER_NOT_AVAILABLE;
     }
 
     mFrameBusy = false;
 
     // If we've been displaced by another owner of the display, then we can't do anything else
-    if (mRequestedState == DisplayState::DEAD) {
+    if (mRequestedState == EvsDisplayState::DEAD) {
         return EvsResult::OWNERSHIP_LOST;
     }
 
     // If we were waiting for a new frame, this is it!
-    if (mRequestedState == DisplayState::VISIBLE_ON_NEXT_FRAME) {
-        mRequestedState = DisplayState::VISIBLE;
-        mGlWrapper.showWindow();
+    if (mRequestedState == EvsDisplayState::VISIBLE_ON_NEXT_FRAME) {
+        mRequestedState = EvsDisplayState::VISIBLE;
+        mGlWrapper.showWindow(mDisplayProxy, mDisplayId);
     }
 
     // Validate we're in an expected state
-    if (mRequestedState != DisplayState::VISIBLE) {
+    if (mRequestedState != EvsDisplayState::VISIBLE) {
         // Not sure why a client would send frames back when we're not visible.
-        ALOGW ("Got a frame returned while not visible - ignoring.\n");
+        LOG(WARNING) << "Got a frame returned while not visible - ignoring.";
     } else {
         // Update the texture contents with the provided data
 // TODO:  Why doesn't it work to pass in the buffer handle we got from HIDL?
@@ -287,18 +292,32 @@
 
         // Put the image on the screen
         mGlWrapper.renderImageToScreen();
+#ifdef EVS_DEBUG
         if (!sDebugFirstFrameDisplayed) {
-            ALOGD("EvsFirstFrameDisplayTiming start time: %" PRId64 "ms", elapsedRealtime());
+            LOG(DEBUG) << "EvsFirstFrameDisplayTiming start time: "
+                       << elapsedRealtime() << " ms.";
             sDebugFirstFrameDisplayed = true;
         }
+#endif
 
     }
 
     return EvsResult::OK;
 }
 
+
+Return<void> EvsGlDisplay::getDisplayInfo_1_1(getDisplayInfo_1_1_cb _info_cb) {
+    if (mDisplayProxy != nullptr) {
+        return mDisplayProxy->getDisplayInfo(mDisplayId, _info_cb);
+    } else {
+        _info_cb({}, {});
+        return Void();
+    }
+}
+
+
 } // namespace implementation
-} // namespace V1_0
+} // namespace V1_1
 } // namespace evs
 } // namespace automotive
 } // namespace hardware
diff --git a/evs/sampleDriver/EvsGlDisplay.h b/evs/sampleDriver/EvsGlDisplay.h
index 7adbac9..af6dd72 100644
--- a/evs/sampleDriver/EvsGlDisplay.h
+++ b/evs/sampleDriver/EvsGlDisplay.h
@@ -14,48 +14,63 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSGLDISPLAY_H
-#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSGLDISPLAY_H
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSGLDISPLAY_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSGLDISPLAY_H
 
-#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+#include <android/frameworks/automotive/display/1.0/IAutomotiveDisplayProxyService.h>
 #include <ui/GraphicBuffer.h>
 
 #include "GlWrapper.h"
 
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using ::android::hardware::automotive::evs::V1_0::DisplayDesc;
+using ::android::hardware::automotive::evs::V1_0::DisplayState;
+using ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
+using EvsResult   = ::android::hardware::automotive::evs::V1_0::EvsResult;
+using BufferDesc_1_0  = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using EvsDisplayState = ::android::hardware::automotive::evs::V1_0::DisplayState;
+using android::frameworks::automotive::display::V1_0::IAutomotiveDisplayProxyService;
 
 namespace android {
 namespace hardware {
 namespace automotive {
 namespace evs {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 
 
 class EvsGlDisplay : public IEvsDisplay {
 public:
     // Methods from ::android::hardware::automotive::evs::V1_0::IEvsDisplay follow.
-    Return<void> getDisplayInfo(getDisplayInfo_cb _hidl_cb)  override;
-    Return<EvsResult> setDisplayState(DisplayState state)  override;
-    Return<DisplayState> getDisplayState()  override;
-    Return<void> getTargetBuffer(getTargetBuffer_cb _hidl_cb)  override;
-    Return<EvsResult> returnTargetBufferForDisplay(const BufferDesc& buffer)  override;
+    Return<void>            getDisplayInfo(getDisplayInfo_cb _hidl_cb)  override;
+    Return<EvsResult>       setDisplayState(EvsDisplayState state)  override;
+    Return<EvsDisplayState> getDisplayState()  override;
+    Return<void>            getTargetBuffer(getTargetBuffer_cb _hidl_cb)  override;
+    Return<EvsResult>       returnTargetBufferForDisplay(const BufferDesc_1_0& buffer)  override;
+
+    // Methods from ::android::hardware::automotive::evs::V1_1::IEvsDisplay follow.
+    Return<void>            getDisplayInfo_1_1(getDisplayInfo_1_1_cb _info_cb) override;
 
     // Implementation details
-    EvsGlDisplay();
+    EvsGlDisplay(sp<IAutomotiveDisplayProxyService> pWindowService, uint64_t displayId);
     virtual ~EvsGlDisplay() override;
 
     void forceShutdown();   // This gets called if another caller "steals" ownership of the display
 
 private:
     DisplayDesc     mInfo           = {};
-    BufferDesc      mBuffer         = {};       // A graphics buffer into which we'll store images
+    BufferDesc_1_0  mBuffer         = {};       // A graphics buffer into which we'll store images
 
     bool            mFrameBusy      = false;    // A flag telling us our buffer is in use
-    DisplayState    mRequestedState = DisplayState::NOT_VISIBLE;
+    EvsDisplayState mRequestedState = EvsDisplayState::NOT_VISIBLE;
 
     GlWrapper       mGlWrapper;
 
     std::mutex      mAccessLock;
+
+    sp<IAutomotiveDisplayProxyService> mDisplayProxy;
+    uint64_t                           mDisplayId;
 };
 
 } // namespace implementation
diff --git a/evs/sampleDriver/EvsV4lCamera.cpp b/evs/sampleDriver/EvsV4lCamera.cpp
index 79a0b2e..cd2a3a4 100644
--- a/evs/sampleDriver/EvsV4lCamera.cpp
+++ b/evs/sampleDriver/EvsV4lCamera.cpp
@@ -18,37 +18,41 @@
 #include "EvsEnumerator.h"
 #include "bufferCopy.h"
 
+#include <android/hardware_buffer.h>
+#include <android-base/logging.h>
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/GraphicBufferMapper.h>
+#include <utils/SystemClock.h>
 
 
 namespace android {
 namespace hardware {
 namespace automotive {
 namespace evs {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 
+// Default camera output image resolution
+const std::array<int32_t, 2> kDefaultResolution = {640, 480};
 
 // Arbitrary limit on number of graphics buffers allowed to be allocated
 // Safeguards against unreasonable resource consumption and provides a testable limit
 static const unsigned MAX_BUFFERS_IN_FLIGHT = 100;
 
-
-EvsV4lCamera::EvsV4lCamera(const char *deviceName) :
+EvsV4lCamera::EvsV4lCamera(const char *deviceName,
+                           unique_ptr<ConfigManager::CameraInfo> &camInfo) :
         mFramesAllowed(0),
-        mFramesInUse(0) {
-    ALOGD("EvsV4lCamera instantiated");
+        mFramesInUse(0),
+        mCameraInfo(camInfo) {
+    LOG(DEBUG) << "EvsV4lCamera instantiated";
 
-    mDescription.cameraId = deviceName;
-
-    // Initialize the video device
-    if (!mVideo.open(deviceName)) {
-        ALOGE("Failed to open v4l device %s\n", deviceName);
+    mDescription.v1.cameraId = deviceName;
+    if (camInfo != nullptr) {
+        mDescription.metadata.setToExternal((uint8_t *)camInfo->characteristics,
+                                            get_camera_metadata_size(camInfo->characteristics));
     }
 
-    // Output buffer format.
-    // TODO: Does this need to be configurable?
+    // Default output buffer format.
     mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
 
     // How we expect to use the gralloc buffers we'll exchange with our client
@@ -59,7 +63,7 @@
 
 
 EvsV4lCamera::~EvsV4lCamera() {
-    ALOGD("EvsV4lCamera being destroyed");
+    LOG(DEBUG) << "EvsV4lCamera being destroyed";
     shutdown();
 }
 
@@ -69,7 +73,7 @@
 //
 void EvsV4lCamera::shutdown()
 {
-    ALOGD("EvsV4lCamera shutdown");
+    LOG(DEBUG) << "EvsV4lCamera shutdown";
 
     // Make sure our output stream is cleaned up
     // (It really should be already)
@@ -85,7 +89,7 @@
         GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
         for (auto&& rec : mBuffers) {
             if (rec.inUse) {
-                ALOGW("Error - releasing buffer despite remote ownership");
+                LOG(WARNING) << "Releasing buffer despite remote ownership";
             }
             alloc.free(rec.handle);
             rec.handle = nullptr;
@@ -97,27 +101,27 @@
 
 // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
 Return<void> EvsV4lCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) {
-    ALOGD("getCameraInfo");
+    LOG(DEBUG) << __FUNCTION__;
 
     // Send back our self description
-    _hidl_cb(mDescription);
+    _hidl_cb(mDescription.v1);
     return Void();
 }
 
 
 Return<EvsResult> EvsV4lCamera::setMaxFramesInFlight(uint32_t bufferCount) {
-    ALOGD("setMaxFramesInFlight");
+    LOG(DEBUG) << __FUNCTION__;
     std::lock_guard<std::mutex> lock(mAccessLock);
 
     // If we've been displaced by another owner of the camera, then we can't do anything else
     if (!mVideo.isOpen()) {
-        ALOGW("ignoring setMaxFramesInFlight call when camera has been lost.");
+        LOG(WARNING) << "Ignoring setMaxFramesInFlight call when camera has been lost.";
         return EvsResult::OWNERSHIP_LOST;
     }
 
     // We cannot function without at least one video buffer to send data
     if (bufferCount < 1) {
-        ALOGE("Ignoring setMaxFramesInFlight with less than one buffer requested");
+        LOG(ERROR) << "Ignoring setMaxFramesInFlight with less than one buffer requested";
         return EvsResult::INVALID_ARG;
     }
 
@@ -130,24 +134,24 @@
 }
 
 
-Return<EvsResult> EvsV4lCamera::startVideoStream(const ::android::sp<IEvsCameraStream>& stream)  {
-    ALOGD("startVideoStream");
+Return<EvsResult> EvsV4lCamera::startVideoStream(const sp<IEvsCameraStream_1_0>& stream)  {
+    LOG(DEBUG) << __FUNCTION__;
     std::lock_guard<std::mutex> lock(mAccessLock);
 
     // If we've been displaced by another owner of the camera, then we can't do anything else
     if (!mVideo.isOpen()) {
-        ALOGW("ignoring startVideoStream call when camera has been lost.");
+        LOG(WARNING) << "Ignoring startVideoStream call when camera has been lost.";
         return EvsResult::OWNERSHIP_LOST;
     }
     if (mStream.get() != nullptr) {
-        ALOGE("ignoring startVideoStream call when a stream is already running.");
+        LOG(ERROR) << "Ignoring startVideoStream call when a stream is already running.";
         return EvsResult::STREAM_ALREADY_RUNNING;
     }
 
     // If the client never indicated otherwise, configure ourselves for a single streaming buffer
     if (mFramesAllowed < 1) {
         if (!setAvailableFrames_Locked(1)) {
-            ALOGE("Failed to start stream because we couldn't get a graphics buffer");
+            LOG(ERROR) << "Failed to start stream because we couldn't get a graphics buffer";
             return EvsResult::BUFFER_NOT_AVAILABLE;
         }
     }
@@ -155,8 +159,8 @@
     // Choose which image transfer function we need
     // Map from V4L2 to Android graphic buffer format
     const uint32_t videoSrcFormat = mVideo.getV4LFormat();
-    ALOGI("Configuring to accept %4.4s camera data and convert to 0x%X",
-          (char*)&videoSrcFormat, mFormat);
+    LOG(INFO) << "Configuring to accept " << (char*)&videoSrcFormat
+              << " camera data and convert to " << std::hex << mFormat;
 
     switch (mFormat) {
     case HAL_PIXEL_FORMAT_YCRCB_420_SP:
@@ -164,19 +168,19 @@
         case V4L2_PIX_FMT_NV21:     mFillBufferFromVideo = fillNV21FromNV21;    break;
         case V4L2_PIX_FMT_YUYV:     mFillBufferFromVideo = fillNV21FromYUYV;    break;
         default:
-            ALOGE("Unhandled camera output format %c%c%c%c (0x%8X)\n",
-                  ((char*)&videoSrcFormat)[0],
-                  ((char*)&videoSrcFormat)[1],
-                  ((char*)&videoSrcFormat)[2],
-                  ((char*)&videoSrcFormat)[3],
-                  videoSrcFormat);
+            LOG(ERROR) << "Unhandled camera output format: "
+                       << ((char*)&videoSrcFormat)[0]
+                       << ((char*)&videoSrcFormat)[1]
+                       << ((char*)&videoSrcFormat)[2]
+                       << ((char*)&videoSrcFormat)[3]
+                       << std::hex << videoSrcFormat;
         }
         break;
     case HAL_PIXEL_FORMAT_RGBA_8888:
         switch (videoSrcFormat) {
         case V4L2_PIX_FMT_YUYV:     mFillBufferFromVideo = fillRGBAFromYUYV;    break;
         default:
-            ALOGE("Unhandled camera format %4.4s", (char*)&videoSrcFormat);
+            LOG(ERROR) << "Unhandled camera format " << (char*)&videoSrcFormat;
         }
         break;
     case HAL_PIXEL_FORMAT_YCBCR_422_I:
@@ -184,24 +188,27 @@
         case V4L2_PIX_FMT_YUYV:     mFillBufferFromVideo = fillYUYVFromYUYV;    break;
         case V4L2_PIX_FMT_UYVY:     mFillBufferFromVideo = fillYUYVFromUYVY;    break;
         default:
-            ALOGE("Unhandled camera format %4.4s", (char*)&videoSrcFormat);
+            LOG(ERROR) << "Unhandled camera format " << (char*)&videoSrcFormat;
         }
         break;
     default:
-        ALOGE("Unhandled output format %4.4s", (char*)&mFormat);
+        LOG(ERROR) << "Unhandled camera format " << (char*)&mFormat;
     }
 
 
     // Record the user's callback for use when we have a frame ready
     mStream = stream;
+    mStream_1_1 = IEvsCameraStream_1_1::castFrom(mStream).withDefault(nullptr);
 
     // Set up the video stream with a callback to our member function forwardFrame()
     if (!mVideo.startStream([this](VideoCapture*, imageBuffer* tgt, void* data) {
                                 this->forwardFrame(tgt, data);
                             })
     ) {
-        mStream = nullptr;  // No need to hold onto this if we failed to start
-        ALOGE("underlying camera start stream failed");
+        // No need to hold onto this if we failed to start
+        mStream = nullptr;
+        mStream_1_1 = nullptr;
+        LOG(ERROR) << "Underlying camera start stream failed";
         return EvsResult::UNDERLYING_SERVICE_ERROR;
     }
 
@@ -209,60 +216,42 @@
 }
 
 
-Return<void> EvsV4lCamera::doneWithFrame(const BufferDesc& buffer)  {
-    ALOGD("doneWithFrame");
-    std::lock_guard <std::mutex> lock(mAccessLock);
-
-    // If we've been displaced by another owner of the camera, then we can't do anything else
-    if (!mVideo.isOpen()) {
-        ALOGW("ignoring doneWithFrame call when camera has been lost.");
-    } else {
-        if (buffer.memHandle == nullptr) {
-            ALOGE("ignoring doneWithFrame called with null handle");
-        } else if (buffer.bufferId >= mBuffers.size()) {
-            ALOGE("ignoring doneWithFrame called with invalid bufferId %d (max is %zu)",
-                  buffer.bufferId, mBuffers.size()-1);
-        } else if (!mBuffers[buffer.bufferId].inUse) {
-            ALOGE("ignoring doneWithFrame called on frame %d which is already free",
-                  buffer.bufferId);
-        } else {
-            // Mark the frame as available
-            mBuffers[buffer.bufferId].inUse = false;
-            mFramesInUse--;
-
-            // If this frame's index is high in the array, try to move it down
-            // to improve locality after mFramesAllowed has been reduced.
-            if (buffer.bufferId >= mFramesAllowed) {
-                // Find an empty slot lower in the array (which should always exist in this case)
-                for (auto&& rec : mBuffers) {
-                    if (rec.handle == nullptr) {
-                        rec.handle = mBuffers[buffer.bufferId].handle;
-                        mBuffers[buffer.bufferId].handle = nullptr;
-                        break;
-                    }
-                }
-            }
-        }
-    }
+Return<void> EvsV4lCamera::doneWithFrame(const BufferDesc_1_0& buffer)  {
+    LOG(DEBUG) << __FUNCTION__;
+    doneWithFrame_impl(buffer.bufferId, buffer.memHandle);
 
     return Void();
 }
 
 
 Return<void> EvsV4lCamera::stopVideoStream()  {
-    ALOGD("stopVideoStream");
+    LOG(DEBUG) << __FUNCTION__;
 
     // Tell the capture device to stop (and block until it does)
     mVideo.stopStream();
 
-    if (mStream != nullptr) {
+    if (mStream_1_1 != nullptr) {
+        // V1.1 client is waiting on STREAM_STOPPED event.
+        std::unique_lock <std::mutex> lock(mAccessLock);
+
+        EvsEventDesc event;
+        event.aType = EvsEventType::STREAM_STOPPED;
+        auto result = mStream_1_1->notify(event);
+        if (!result.isOk()) {
+            LOG(ERROR) << "Error delivering end of stream event";
+        }
+
+        // Drop our reference to the client's stream receiver
+        mStream_1_1 = nullptr;
+        mStream     = nullptr;
+    } else if (mStream != nullptr) {
         std::unique_lock <std::mutex> lock(mAccessLock);
 
         // Send one last NULL frame to signal the actual end of stream
-        BufferDesc nullBuff = {};
+        BufferDesc_1_0 nullBuff = {};
         auto result = mStream->deliverFrame(nullBuff);
         if (!result.isOk()) {
-            ALOGE("Error delivering end of stream marker");
+            LOG(ERROR) << "Error delivering end of stream marker";
         }
 
         // Drop our reference to the client's stream receiver
@@ -274,20 +263,20 @@
 
 
 Return<int32_t> EvsV4lCamera::getExtendedInfo(uint32_t /*opaqueIdentifier*/)  {
-    ALOGD("getExtendedInfo");
+    LOG(DEBUG) << __FUNCTION__;
     // Return zero by default as required by the spec
     return 0;
 }
 
 
 Return<EvsResult> EvsV4lCamera::setExtendedInfo(uint32_t /*opaqueIdentifier*/,
-                                                int32_t /*opaqueValue*/)  {
-    ALOGD("setExtendedInfo");
+                                                int32_t  /*opaqueValue*/)  {
+    LOG(DEBUG) << __FUNCTION__;
     std::lock_guard<std::mutex> lock(mAccessLock);
 
     // If we've been displaced by another owner of the camera, then we can't do anything else
     if (!mVideo.isOpen()) {
-        ALOGW("ignoring setExtendedInfo call when camera has been lost.");
+        LOG(WARNING) << "Ignoring setExtendedInfo call when camera has been lost.";
         return EvsResult::OWNERSHIP_LOST;
     }
 
@@ -296,13 +285,295 @@
 }
 
 
+// Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
+Return<void> EvsV4lCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) {
+    LOG(DEBUG) << __FUNCTION__;
+
+    // Send back our self description
+    _hidl_cb(mDescription);
+    return Void();
+}
+
+
+Return<void> EvsV4lCamera::getPhysicalCameraInfo(const hidl_string& id,
+                                                 getPhysicalCameraInfo_cb _hidl_cb) {
+    LOG(DEBUG) << __FUNCTION__;
+
+    // This method works exactly same as getCameraInfo_1_1() in EVS HW module.
+    (void)id;
+    _hidl_cb(mDescription);
+    return Void();
+}
+
+
+Return<EvsResult> EvsV4lCamera::doneWithFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffers)  {
+    LOG(DEBUG) << __FUNCTION__;
+
+    for (auto&& buffer : buffers) {
+        doneWithFrame_impl(buffer.bufferId, buffer.buffer.nativeHandle);
+    }
+
+    return EvsResult::OK;
+}
+
+
+Return<EvsResult> EvsV4lCamera::pauseVideoStream() {
+    return EvsResult::UNDERLYING_SERVICE_ERROR;
+}
+
+
+Return<EvsResult> EvsV4lCamera::resumeVideoStream() {
+    return EvsResult::UNDERLYING_SERVICE_ERROR;
+}
+
+
+Return<EvsResult> EvsV4lCamera::setMaster() {
+    /* Because EVS HW module reference implementation expects a single client at
+     * a time, this returns a success code always.
+     */
+    return EvsResult::OK;
+}
+
+
+Return<EvsResult> EvsV4lCamera::forceMaster(const sp<IEvsDisplay_1_0>&) {
+    /* Because EVS HW module reference implementation expects a single client at
+     * a time, this returns a success code always.
+     */
+    return EvsResult::OK;
+}
+
+
+Return<EvsResult> EvsV4lCamera::unsetMaster() {
+    /* Because EVS HW module reference implementation expects a single client at
+     * a time, there is no chance that this is called by a non-master client and
+     * therefore returns a success code always.
+     */
+    return EvsResult::OK;
+}
+
+
+Return<void> EvsV4lCamera::getParameterList(getParameterList_cb _hidl_cb) {
+    hidl_vec<CameraParam> hidlCtrls;
+    if (mCameraInfo != nullptr) {
+        hidlCtrls.resize(mCameraInfo->controls.size());
+        unsigned idx = 0;
+        for (auto& [cid, range]: mCameraInfo->controls) {
+            hidlCtrls[idx++] = cid;
+        }
+    }
+
+    _hidl_cb(hidlCtrls);
+    return Void();
+}
+
+
+Return<void> EvsV4lCamera::getIntParameterRange(CameraParam id,
+                                                getIntParameterRange_cb _hidl_cb) {
+    if (mCameraInfo != nullptr) {
+        auto range = mCameraInfo->controls[id];
+        _hidl_cb(get<0>(range), get<1>(range), get<2>(range));
+    } else {
+        _hidl_cb(0, 0, 0);
+    }
+
+    return Void();
+}
+
+
+Return<void> EvsV4lCamera::setIntParameter(CameraParam id, int32_t value,
+                                           setIntParameter_cb _hidl_cb) {
+    uint32_t v4l2cid = V4L2_CID_BASE;
+    hidl_vec<int32_t> values;
+    values.resize(1);
+    if (!convertToV4l2CID(id, v4l2cid)) {
+        _hidl_cb(EvsResult::INVALID_ARG, values);
+    } else {
+        EvsResult result = EvsResult::OK;
+        v4l2_control control = {v4l2cid, value};
+        if (mVideo.setParameter(control) < 0 ||
+            mVideo.getParameter(control) < 0) {
+            result = EvsResult::UNDERLYING_SERVICE_ERROR;
+        }
+
+        values[0] = control.value;
+        _hidl_cb(result, values);
+    }
+
+    return Void();
+}
+
+
+Return<void> EvsV4lCamera::getIntParameter(CameraParam id,
+                                           getIntParameter_cb _hidl_cb) {
+    uint32_t v4l2cid = V4L2_CID_BASE;
+    hidl_vec<int32_t> values;
+    values.resize(1);
+    if (!convertToV4l2CID(id, v4l2cid)) {
+        _hidl_cb(EvsResult::INVALID_ARG, values);
+    } else {
+        EvsResult result = EvsResult::OK;
+        v4l2_control control = {v4l2cid, 0};
+        if (mVideo.getParameter(control) < 0) {
+            result = EvsResult::INVALID_ARG;
+        }
+
+        // Report a result
+        values[0] = control.value;
+        _hidl_cb(result, values);
+    }
+
+    return Void();
+}
+
+
+Return<EvsResult> EvsV4lCamera::setExtendedInfo_1_1(uint32_t opaqueIdentifier,
+                                                    const hidl_vec<uint8_t>& opaqueValue) {
+    mExtInfo.insert_or_assign(opaqueIdentifier, opaqueValue);
+    return EvsResult::OK;
+}
+
+
+Return<void> EvsV4lCamera::getExtendedInfo_1_1(uint32_t opaqueIdentifier,
+                                               getExtendedInfo_1_1_cb _hidl_cb) {
+    const auto it = mExtInfo.find(opaqueIdentifier);
+    hidl_vec<uint8_t> value;
+    auto status = EvsResult::OK;
+    if (it == mExtInfo.end()) {
+        status = EvsResult::INVALID_ARG;
+    } else {
+        value = mExtInfo[opaqueIdentifier];
+    }
+
+    _hidl_cb(status, value);
+    return Void();
+}
+
+
+Return<void>
+EvsV4lCamera::importExternalBuffers(const hidl_vec<BufferDesc_1_1>& buffers,
+                                    importExternalBuffers_cb _hidl_cb) {
+    LOG(DEBUG) << __FUNCTION__;
+
+    // If we've been displaced by another owner of the camera, then we can't do anything else
+    if (!mVideo.isOpen()) {
+        LOG(WARNING) << "Ignoring a request add external buffers "
+                     << "when camera has been lost.";
+        _hidl_cb(EvsResult::UNDERLYING_SERVICE_ERROR, mFramesAllowed);
+        return {};
+    }
+
+    auto numBuffersToAdd = buffers.size();
+    if (numBuffersToAdd < 1) {
+        LOG(DEBUG) << "No buffers to add.";
+        _hidl_cb(EvsResult::OK, mFramesAllowed);
+        return {};
+    }
+
+    {
+        std::scoped_lock<std::mutex> lock(mAccessLock);
+
+        if (numBuffersToAdd > (MAX_BUFFERS_IN_FLIGHT - mFramesAllowed)) {
+            numBuffersToAdd -= (MAX_BUFFERS_IN_FLIGHT - mFramesAllowed);
+            LOG(WARNING) << "Exceed the limit on number of buffers.  "
+                         << numBuffersToAdd << " buffers will be added only.";
+        }
+
+        GraphicBufferMapper& mapper = GraphicBufferMapper::get();
+        const auto before = mFramesAllowed;
+        for (auto i = 0; i < numBuffersToAdd; ++i) {
+            // TODO: reject if external buffer is configured differently.
+            auto& b = buffers[i];
+            const AHardwareBuffer_Desc* pDesc =
+                reinterpret_cast<const AHardwareBuffer_Desc *>(&b.buffer.description);
+
+            // Import a buffer to add
+            buffer_handle_t memHandle = nullptr;
+            status_t result = mapper.importBuffer(b.buffer.nativeHandle,
+                                                  pDesc->width,
+                                                  pDesc->height,
+                                                  1,
+                                                  pDesc->format,
+                                                  pDesc->usage,
+                                                  pDesc->stride,
+                                                  &memHandle);
+            if (result != android::NO_ERROR || !memHandle) {
+                LOG(WARNING) << "Failed to import a buffer " << b.bufferId;
+                continue;
+            }
+
+            auto stored = false;
+            for (auto&& rec : mBuffers) {
+                if (rec.handle == nullptr) {
+                    // Use this existing entry
+                    rec.handle = memHandle;
+                    rec.inUse = false;
+
+                    stored = true;
+                    break;
+                }
+            }
+
+            if (!stored) {
+                // Add a BufferRecord wrapping this handle to our set of available buffers
+                mBuffers.emplace_back(memHandle);
+            }
+
+            ++mFramesAllowed;
+        }
+
+        _hidl_cb(EvsResult::OK, mFramesAllowed - before);
+        return {};
+    }
+}
+
+
+EvsResult EvsV4lCamera::doneWithFrame_impl(const uint32_t bufferId,
+                                           const buffer_handle_t memHandle) {
+    std::lock_guard <std::mutex> lock(mAccessLock);
+
+    // If we've been displaced by another owner of the camera, then we can't do anything else
+    if (!mVideo.isOpen()) {
+        LOG(WARNING) << "Ignoring doneWithFrame call when camera has been lost.";
+    } else {
+        if (memHandle == nullptr) {
+            LOG(ERROR) << "Ignoring doneWithFrame called with null handle";
+        } else if (bufferId >= mBuffers.size()) {
+            LOG(ERROR) << "Ignoring doneWithFrame called with invalid bufferId " << bufferId
+                       << " (max is " << mBuffers.size() - 1 << ")";
+        } else if (!mBuffers[bufferId].inUse) {
+            LOG(ERROR) << "Ignoring doneWithFrame called on frame " << bufferId
+                       << " which is already free";
+        } else {
+            // Mark the frame as available
+            mBuffers[bufferId].inUse = false;
+            mFramesInUse--;
+
+            // If this frame's index is high in the array, try to move it down
+            // to improve locality after mFramesAllowed has been reduced.
+            if (bufferId >= mFramesAllowed) {
+                // Find an empty slot lower in the array (which should always exist in this case)
+                for (auto&& rec : mBuffers) {
+                    if (rec.handle == nullptr) {
+                        rec.handle = mBuffers[bufferId].handle;
+                        mBuffers[bufferId].handle = nullptr;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    return EvsResult::OK;
+}
+
+
 bool EvsV4lCamera::setAvailableFrames_Locked(unsigned bufferCount) {
     if (bufferCount < 1) {
-        ALOGE("Ignoring request to set buffer count to zero");
+        LOG(ERROR) << "Ignoring request to set buffer count to zero";
         return false;
     }
     if (bufferCount > MAX_BUFFERS_IN_FLIGHT) {
-        ALOGE("Rejecting buffer request in excess of internal limit");
+        LOG(ERROR) << "Rejecting buffer request in excess of internal limit";
         return false;
     }
 
@@ -310,26 +581,26 @@
     if (mFramesAllowed < bufferCount) {
         // An increase is required
         unsigned needed = bufferCount - mFramesAllowed;
-        ALOGI("Allocating %d buffers for camera frames", needed);
+        LOG(INFO) << "Allocating " << needed << " buffers for camera frames";
 
         unsigned added = increaseAvailableFrames_Locked(needed);
         if (added != needed) {
             // If we didn't add all the frames we needed, then roll back to the previous state
-            ALOGE("Rolling back to previous frame queue size");
+            LOG(ERROR) << "Rolling back to previous frame queue size";
             decreaseAvailableFrames_Locked(added);
             return false;
         }
     } else if (mFramesAllowed > bufferCount) {
         // A decrease is required
         unsigned framesToRelease = mFramesAllowed - bufferCount;
-        ALOGI("Returning %d camera frame buffers", framesToRelease);
+        LOG(INFO) << "Returning " << framesToRelease << " camera frame buffers";
 
         unsigned released = decreaseAvailableFrames_Locked(framesToRelease);
         if (released != framesToRelease) {
             // This shouldn't happen with a properly behaving client because the client
             // should only make this call after returning sufficient outstanding buffers
             // to allow a clean resize.
-            ALOGE("Buffer queue shrink failed -- too many buffers currently in use?");
+            LOG(ERROR) << "Buffer queue shrink failed -- too many buffers currently in use?";
         }
     }
 
@@ -352,19 +623,18 @@
                                          mUsage,
                                          &memHandle, &pixelsPerLine, 0, "EvsV4lCamera");
         if (result != NO_ERROR) {
-            ALOGE("Error %d allocating %d x %d graphics buffer",
-                  result,
-                  mVideo.getWidth(),
-                  mVideo.getHeight());
+            LOG(ERROR) << "Error " << result << " allocating "
+                       << mVideo.getWidth() << " x " << mVideo.getHeight()
+                       << " graphics buffer";
             break;
         }
         if (!memHandle) {
-            ALOGE("We didn't get a buffer handle back from the allocator");
+            LOG(ERROR) << "We didn't get a buffer handle back from the allocator";
             break;
         }
         if (mStride) {
             if (mStride != pixelsPerLine) {
-                ALOGE("We did not expect to get buffers with different strides!");
+                LOG(ERROR) << "We did not expect to get buffers with different strides!";
             }
         } else {
             // Gralloc defines stride in terms of pixels per line
@@ -422,7 +692,7 @@
 
 
 // This is the async callback from the video camera that tells us a frame is ready
-void EvsV4lCamera::forwardFrame(imageBuffer* /*pV4lBuff*/, void* pData) {
+void EvsV4lCamera::forwardFrame(imageBuffer* pV4lBuff, void* pData) {
     bool readyForFrame = false;
     size_t idx = 0;
 
@@ -433,7 +703,7 @@
         // Are we allowed to issue another buffer?
         if (mFramesInUse >= mFramesAllowed) {
             // Can't do anything right now -- skip this frame
-            ALOGW("Skipped a frame because too many are in flight\n");
+            LOG(WARNING) << "Skipped a frame because too many are in flight";
         } else {
             // Identify an available buffer to fill
             for (idx = 0; idx < mBuffers.size(); idx++) {
@@ -446,7 +716,7 @@
             }
             if (idx >= mBuffers.size()) {
                 // This shouldn't happen since we already checked mFramesInUse vs mFramesAllowed
-                ALOGE("Failed to find an available buffer slot\n");
+                LOG(ERROR) << "Failed to find an available buffer slot";
             } else {
                 // We're going to make the frame busy
                 mBuffers[idx].inUse = true;
@@ -457,66 +727,229 @@
     }
 
     if (!readyForFrame) {
-        // We need to return the vide buffer so it can capture a new frame
+        // We need to return the video buffer so it can capture a new frame
         mVideo.markFrameConsumed();
     } else {
         // Assemble the buffer description we'll transmit below
-        BufferDesc buff = {};
-        buff.width      = mVideo.getWidth();
-        buff.height     = mVideo.getHeight();
-        buff.stride     = mStride;
-        buff.format     = mFormat;
-        buff.usage      = mUsage;
-        buff.bufferId   = idx;
-        buff.memHandle  = mBuffers[idx].handle;
+        BufferDesc_1_1 bufDesc_1_1 = {};
+        AHardwareBuffer_Desc* pDesc =
+            reinterpret_cast<AHardwareBuffer_Desc *>(&bufDesc_1_1.buffer.description);
+        pDesc->width  = mVideo.getWidth();
+        pDesc->height = mVideo.getHeight();
+        pDesc->layers = 1;
+        pDesc->format = mFormat;
+        pDesc->usage  = mUsage;
+        pDesc->stride = mStride;
+        bufDesc_1_1.buffer.nativeHandle = mBuffers[idx].handle;
+        bufDesc_1_1.bufferId = idx;
+        bufDesc_1_1.deviceId = mDescription.v1.cameraId;
+        // timestamp in microseconds.
+        bufDesc_1_1.timestamp =
+            pV4lBuff->timestamp.tv_sec * 1e+6 + pV4lBuff->timestamp.tv_usec;
 
         // Lock our output buffer for writing
+        // TODO(b/145459970): Sometimes, physical camera device maps a buffer
+        // into the address that is about to be unmapped by another device; this
+        // causes SEGV_MAPPER.
         void *targetPixels = nullptr;
         GraphicBufferMapper &mapper = GraphicBufferMapper::get();
-        mapper.lock(buff.memHandle,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
-                    android::Rect(buff.width, buff.height),
-                    (void **) &targetPixels);
+        status_t result =
+            mapper.lock(bufDesc_1_1.buffer.nativeHandle,
+                        GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
+                        android::Rect(pDesc->width, pDesc->height),
+                        (void **)&targetPixels);
 
         // If we failed to lock the pixel buffer, we're about to crash, but log it first
         if (!targetPixels) {
-            ALOGE("Camera failed to gain access to image buffer for writing");
+            // TODO(b/145457727): When EvsHidlTest::CameraToDisplayRoundTrip
+            // test case was repeatedly executed, EVS occasionally fails to map
+            // a buffer.
+            LOG(ERROR) << "Camera failed to gain access to image buffer for writing - "
+                       << " status: " << statusToString(result)
+                       << " , error: " << strerror(errno);
         }
 
         // Transfer the video image into the output buffer, making any needed
         // format conversion along the way
-        mFillBufferFromVideo(buff, (uint8_t*)targetPixels, pData, mVideo.getStride());
+        mFillBufferFromVideo(bufDesc_1_1, (uint8_t *)targetPixels, pData, mVideo.getStride());
 
         // Unlock the output buffer
-        mapper.unlock(buff.memHandle);
-
+        mapper.unlock(bufDesc_1_1.buffer.nativeHandle);
 
         // Give the video frame back to the underlying device for reuse
-        // Note that we do this before making the client callback to give the underlying
-        // camera more time to capture the next frame.
+        // Note that we do this before making the client callback to give the
+        // underlying camera more time to capture the next frame
         mVideo.markFrameConsumed();
 
-        // Issue the (asynchronous) callback to the client -- can't be holding the lock
-        auto result = mStream->deliverFrame(buff);
-        if (result.isOk()) {
-            ALOGD("Delivered %p as id %d", buff.memHandle.getNativeHandle(), buff.bufferId);
+        // Issue the (asynchronous) callback to the client -- can't be holding
+        // the lock
+        bool flag = false;
+        if (mStream_1_1 != nullptr) {
+            hidl_vec<BufferDesc_1_1> frames;
+            frames.resize(1);
+            frames[0] = bufDesc_1_1;
+            auto result = mStream_1_1->deliverFrame_1_1(frames);
+            flag = result.isOk();
+        } else {
+            BufferDesc_1_0 bufDesc_1_0 = {
+                pDesc->width,
+                pDesc->height,
+                pDesc->stride,
+                bufDesc_1_1.pixelSize,
+                static_cast<uint32_t>(pDesc->format),
+                static_cast<uint32_t>(pDesc->usage),
+                bufDesc_1_1.bufferId,
+                bufDesc_1_1.buffer.nativeHandle
+            };
+
+            auto result = mStream->deliverFrame(bufDesc_1_0);
+            flag = result.isOk();
+        }
+
+        if (flag) {
+            LOG(DEBUG) << "Delivered " << bufDesc_1_1.buffer.nativeHandle.getNativeHandle()
+                       << " as id " << bufDesc_1_1.bufferId;
         } else {
             // This can happen if the client dies and is likely unrecoverable.
             // To avoid consuming resources generating failing calls, we stop sending
             // frames.  Note, however, that the stream remains in the "STREAMING" state
             // until cleaned up on the main thread.
-            ALOGE("Frame delivery call failed in the transport layer.");
+            LOG(ERROR) << "Frame delivery call failed in the transport layer.";
 
             // Since we didn't actually deliver it, mark the frame as available
             std::lock_guard<std::mutex> lock(mAccessLock);
             mBuffers[idx].inUse = false;
+
             mFramesInUse--;
         }
     }
 }
 
+
+bool EvsV4lCamera::convertToV4l2CID(CameraParam id, uint32_t& v4l2cid) {
+    switch (id) {
+        case CameraParam::BRIGHTNESS:
+            v4l2cid = V4L2_CID_BRIGHTNESS;
+            break;
+        case CameraParam::CONTRAST:
+            v4l2cid = V4L2_CID_CONTRAST;
+            break;
+        case CameraParam::AUTO_WHITE_BALANCE:
+            v4l2cid = V4L2_CID_AUTO_WHITE_BALANCE;
+            break;
+        case CameraParam::WHITE_BALANCE_TEMPERATURE:
+            v4l2cid = V4L2_CID_WHITE_BALANCE_TEMPERATURE;
+            break;
+        case CameraParam::SHARPNESS:
+            v4l2cid = V4L2_CID_SHARPNESS;
+            break;
+        case CameraParam::AUTO_EXPOSURE:
+            v4l2cid = V4L2_CID_EXPOSURE_AUTO;
+            break;
+        case CameraParam::ABSOLUTE_EXPOSURE:
+            v4l2cid = V4L2_CID_EXPOSURE_ABSOLUTE;
+            break;
+        case CameraParam::AUTO_FOCUS:
+            v4l2cid = V4L2_CID_FOCUS_AUTO;
+            break;
+        case CameraParam::ABSOLUTE_FOCUS:
+            v4l2cid = V4L2_CID_FOCUS_ABSOLUTE;
+            break;
+        case CameraParam::ABSOLUTE_ZOOM:
+            v4l2cid = V4L2_CID_ZOOM_ABSOLUTE;
+            break;
+        default:
+            LOG(ERROR) << "Camera parameter " << static_cast<unsigned>(id) << " is unknown.";
+            return false;
+    }
+
+    return mCameraControls.find(v4l2cid) != mCameraControls.end();
+}
+
+
+sp<EvsV4lCamera> EvsV4lCamera::Create(const char *deviceName) {
+    unique_ptr<ConfigManager::CameraInfo> nullCamInfo = nullptr;
+
+    return Create(deviceName, nullCamInfo);
+}
+
+
+sp<EvsV4lCamera> EvsV4lCamera::Create(const char *deviceName,
+                                      unique_ptr<ConfigManager::CameraInfo> &camInfo,
+                                      const Stream *requestedStreamCfg) {
+    LOG(INFO) << "Create " << deviceName;
+    sp<EvsV4lCamera> evsCamera = new EvsV4lCamera(deviceName, camInfo);
+    if (evsCamera == nullptr) {
+        return nullptr;
+    }
+
+    // Initialize the video device
+    bool success = false;
+    if (camInfo != nullptr && requestedStreamCfg != nullptr) {
+        // Validate a given stream configuration.  If there is no exact match,
+        // this will try to find the best match based on:
+        // 1) same output format
+        // 2) the largest resolution that is smaller that a given configuration.
+        int32_t streamId = -1, area = INT_MIN;
+        for (auto& [id, cfg] : camInfo->streamConfigurations) {
+            // RawConfiguration has id, width, height, format, direction, and
+            // fps.
+            if (cfg[3] == static_cast<uint32_t>(requestedStreamCfg->format)) {
+                if (cfg[1] == requestedStreamCfg->width &&
+                    cfg[2] == requestedStreamCfg->height) {
+                    // Find exact match.
+                    streamId = id;
+                    break;
+                } else if (requestedStreamCfg->width  > cfg[1] &&
+                           requestedStreamCfg->height > cfg[2] &&
+                           cfg[1] * cfg[2] > area) {
+                    streamId = id;
+                    area = cfg[1] * cfg[2];
+                }
+            }
+
+        }
+
+        if (streamId >= 0) {
+            LOG(INFO) << "Try to open a video with "
+                      << "width: " << camInfo->streamConfigurations[streamId][1]
+                      << ", height: " << camInfo->streamConfigurations[streamId][2]
+                      << ", format: " << camInfo->streamConfigurations[streamId][3];
+            success =
+                evsCamera->mVideo.open(deviceName,
+                                       camInfo->streamConfigurations[streamId][1],
+                                       camInfo->streamConfigurations[streamId][2]);
+            evsCamera->mFormat = static_cast<uint32_t>(camInfo->streamConfigurations[streamId][3]);
+        }
+    }
+
+    if (!success) {
+        // Create a camera object with the default resolution and format
+        // , HAL_PIXEL_FORMAT_RGBA_8888.
+        LOG(INFO) << "Open a video with default parameters";
+        success =
+            evsCamera->mVideo.open(deviceName, kDefaultResolution[0], kDefaultResolution[1]);
+        if (!success) {
+            LOG(ERROR) << "Failed to open a video stream";
+            return nullptr;
+        }
+    }
+
+    // List available camera parameters
+    evsCamera->mCameraControls = evsCamera->mVideo.enumerateCameraControls();
+
+    // Please note that the buffer usage flag does not come from a given stream
+    // configuration.
+    evsCamera->mUsage  = GRALLOC_USAGE_HW_TEXTURE     |
+                         GRALLOC_USAGE_SW_READ_RARELY |
+                         GRALLOC_USAGE_SW_WRITE_OFTEN;
+
+    return evsCamera;
+}
+
+
 } // namespace implementation
-} // namespace V1_0
+} // namespace V1_1
 } // namespace evs
 } // namespace automotive
 } // namespace hardware
diff --git a/evs/sampleDriver/EvsV4lCamera.h b/evs/sampleDriver/EvsV4lCamera.h
index 3d351b9..90cde57 100644
--- a/evs/sampleDriver/EvsV4lCamera.h
+++ b/evs/sampleDriver/EvsV4lCamera.h
@@ -14,24 +14,39 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSV4LCAMERA_H
-#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSV4LCAMERA_H
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSV4LCAMERA_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSV4LCAMERA_H
 
-#include <android/hardware/automotive/evs/1.0/types.h>
-#include <android/hardware/automotive/evs/1.0/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
 #include <ui/GraphicBuffer.h>
 
-#include <thread>
 #include <functional>
+#include <thread>
+#include <set>
 
 #include "VideoCapture.h"
+#include "ConfigManager.h"
 
+using ::android::hardware::hidl_string;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using IEvsDisplay_1_0      = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using IEvsDisplay_1_1      = ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
+using BufferDesc_1_0       = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using BufferDesc_1_1       = ::android::hardware::automotive::evs::V1_1::BufferDesc;
+using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream;
+using IEvsCameraStream_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCameraStream;
 
 namespace android {
 namespace hardware {
 namespace automotive {
 namespace evs {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 
 
@@ -42,34 +57,69 @@
 class EvsV4lCamera : public IEvsCamera {
 public:
     // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
-    Return<void> getCameraInfo(getCameraInfo_cb _hidl_cb)  override;
-    Return <EvsResult> setMaxFramesInFlight(uint32_t bufferCount) override;
-    Return <EvsResult> startVideoStream(const ::android::sp<IEvsCameraStream>& stream) override;
-    Return<void> doneWithFrame(const BufferDesc& buffer) override;
-    Return<void> stopVideoStream() override;
-    Return <int32_t> getExtendedInfo(uint32_t opaqueIdentifier) override;
-    Return <EvsResult> setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override;
+    Return<void>      getCameraInfo(getCameraInfo_cb _hidl_cb)  override;
+    Return<EvsResult> setMaxFramesInFlight(uint32_t bufferCount) override;
+    Return<EvsResult> startVideoStream(const ::android::sp<IEvsCameraStream_1_0>& stream) override;
+    Return<void>      doneWithFrame(const BufferDesc_1_0& buffer) override;
+    Return<void>      stopVideoStream() override;
+    Return<int32_t>   getExtendedInfo(uint32_t opaqueIdentifier) override;
+    Return<EvsResult> setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override;
 
-    // Implementation details
-    EvsV4lCamera(const char *deviceName);
+    // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
+    Return<void>      getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb)  override;
+    Return<void>      getPhysicalCameraInfo(const hidl_string& deviceId,
+                                            getPhysicalCameraInfo_cb _hidl_cb)  override;
+    Return<EvsResult> pauseVideoStream() override;
+    Return<EvsResult> resumeVideoStream() override;
+    Return<EvsResult> doneWithFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffer) override;
+    Return<EvsResult> setMaster() override;
+    Return<EvsResult> forceMaster(const sp<IEvsDisplay_1_0>&) override;
+    Return<EvsResult> unsetMaster() override;
+    Return<void>      getParameterList(getParameterList_cb _hidl_cb) override;
+    Return<void>      getIntParameterRange(CameraParam id,
+                                           getIntParameterRange_cb _hidl_cb) override;
+    Return<void>      setIntParameter(CameraParam id, int32_t value,
+                                      setIntParameter_cb _hidl_cb) override;
+    Return<void>      getIntParameter(CameraParam id,
+                                      getIntParameter_cb _hidl_cb) override;
+    Return<EvsResult> setExtendedInfo_1_1(uint32_t opaqueIdentifier,
+                                          const hidl_vec<uint8_t>& opaqueValue) override;
+    Return<void>      getExtendedInfo_1_1(uint32_t opaqueIdentifier,
+                                          getExtendedInfo_1_1_cb _hidl_cb) override;
+    Return<void>      importExternalBuffers(const hidl_vec<BufferDesc_1_1>& buffers,
+                                            importExternalBuffers_cb _hidl_cb) override;
+
+    static sp<EvsV4lCamera> Create(const char *deviceName);
+    static sp<EvsV4lCamera> Create(const char *deviceName,
+                                   unique_ptr<ConfigManager::CameraInfo> &camInfo,
+                                   const Stream *streamCfg = nullptr);
+    EvsV4lCamera(const EvsV4lCamera&) = delete;
+    EvsV4lCamera& operator=(const EvsV4lCamera&) = delete;
+
     virtual ~EvsV4lCamera() override;
     void shutdown();
 
     const CameraDesc& getDesc() { return mDescription; };
 
 private:
+    // Constructors
+    EvsV4lCamera(const char *deviceName,
+                 unique_ptr<ConfigManager::CameraInfo> &camInfo);
+
     // These three functions are expected to be called while mAccessLock is held
     bool setAvailableFrames_Locked(unsigned bufferCount);
     unsigned increaseAvailableFrames_Locked(unsigned numToAdd);
     unsigned decreaseAvailableFrames_Locked(unsigned numToRemove);
 
     void forwardFrame(imageBuffer* tgt, void* data);
+    inline bool convertToV4l2CID(CameraParam id, uint32_t& v4l2cid);
 
-    sp <IEvsCameraStream> mStream = nullptr;  // The callback used to deliver each frame
+    sp <IEvsCameraStream_1_0> mStream     = nullptr;  // The callback used to deliver each frame
+    sp <IEvsCameraStream_1_1> mStream_1_1 = nullptr;  // The callback used to deliver each frame
 
-    VideoCapture          mVideo;   // Interface to the v4l device
+    VideoCapture              mVideo;                 // Interface to the v4l device
+    CameraDesc                mDescription = {};      // The properties of this camera
 
-    CameraDesc mDescription = {};   // The properties of this camera
     uint32_t mFormat = 0;           // Values from android_pixel_format_t
     uint32_t mUsage  = 0;           // Values from from Gralloc.h
     uint32_t mStride = 0;           // Pixels per row (may be greater than image width)
@@ -85,20 +135,31 @@
     unsigned mFramesAllowed;                // How many buffers are we currently using
     unsigned mFramesInUse;                  // How many buffers are currently outstanding
 
+    std::set<uint32_t> mCameraControls;     // Available camera controls
+
     // Which format specific function we need to use to move camera imagery into our output buffers
     void(*mFillBufferFromVideo)(const BufferDesc& tgtBuff, uint8_t* tgt,
                                 void* imgData, unsigned imgStride);
 
+
+    EvsResult doneWithFrame_impl(const uint32_t id, const buffer_handle_t handle);
+
     // Synchronization necessary to deconflict the capture thread from the main service thread
     // Note that the service interface remains single threaded (ie: not reentrant)
     std::mutex mAccessLock;
+
+    // Static camera module information
+    unique_ptr<ConfigManager::CameraInfo> &mCameraInfo;
+
+    // Extended information
+    std::unordered_map<uint32_t, std::vector<uint8_t>> mExtInfo;
 };
 
 } // namespace implementation
-} // namespace V1_0
+} // namespace V1_1
 } // namespace evs
 } // namespace automotive
 } // namespace hardware
 } // namespace android
 
-#endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSV4LCAMERA_H
+#endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSV4LCAMERA_H
diff --git a/evs/sampleDriver/GlWrapper.cpp b/evs/sampleDriver/GlWrapper.cpp
index cb55a5e..59d677d 100644
--- a/evs/sampleDriver/GlWrapper.cpp
+++ b/evs/sampleDriver/GlWrapper.cpp
@@ -20,7 +20,10 @@
 #include <fcntl.h>
 #include <sys/ioctl.h>
 
-#include <ui/DisplayInfo.h>
+#include <utility>
+
+#include <ui/DisplayConfig.h>
+#include <ui/DisplayState.h>
 #include <ui/GraphicBuffer.h>
 
 
@@ -109,7 +112,7 @@
     GLint compiled = 0;
     glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
     if (!compiled) {
-        ALOGE("Error compiling shader\n");
+        LOG(ERROR) << "Error compiling shader";
 
         GLint size = 0;
         glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &size);
@@ -118,7 +121,7 @@
             // Get and report the error message
             char *infoLog = (char*)malloc(size);
             glGetShaderInfoLog(shader, size, nullptr, infoLog);
-            ALOGE("  msg:\n%s\n", infoLog);
+            LOG(ERROR) << "  msg:" << std::endl << infoLog;
             free(infoLog);
         }
 
@@ -134,20 +137,20 @@
 static GLuint buildShaderProgram(const char* vtxSrc, const char* pxlSrc) {
     GLuint program = glCreateProgram();
     if (program == 0) {
-        ALOGE("Failed to allocate program object\n");
+        LOG(ERROR) << "Failed to allocate program object";
         return 0;
     }
 
     // Compile the shaders and bind them to this program
     GLuint vertexShader = loadShader(GL_VERTEX_SHADER, vtxSrc);
     if (vertexShader == 0) {
-        ALOGE("Failed to load vertex shader\n");
+        LOG(ERROR) << "Failed to load vertex shader";
         glDeleteProgram(program);
         return 0;
     }
     GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pxlSrc);
     if (pixelShader == 0) {
-        ALOGE("Failed to load pixel shader\n");
+        LOG(ERROR) << "Failed to load pixel shader";
         glDeleteProgram(program);
         glDeleteShader(vertexShader);
         return 0;
@@ -161,7 +164,7 @@
     glGetProgramiv(program, GL_LINK_STATUS, &linked);
     if (!linked)
     {
-        ALOGE("Error linking program.\n");
+        LOG(ERROR) << "Error linking program";
         GLint size = 0;
         glGetProgramiv(program, GL_INFO_LOG_LENGTH, &size);
         if (size > 0)
@@ -169,7 +172,7 @@
             // Get and report the error message
             char *infoLog = (char*)malloc(size);
             glGetProgramInfoLog(program, size, nullptr, infoLog);
-            ALOGE("  msg:  %s\n", infoLog);
+            LOG(ERROR) << "  msg:  " << infoLog;
             free(infoLog);
         }
 
@@ -184,68 +187,61 @@
 
 
 // Main entry point
-bool GlWrapper::initialize() {
-    //
-    //  Create the native full screen window and get a suitable configuration to match it
-    //
-    status_t err;
+bool GlWrapper::initialize(sp<IAutomotiveDisplayProxyService> pWindowProxy,
+                           uint64_t displayId) {
+    LOG(DEBUG) << __FUNCTION__;
 
-    mFlinger = new SurfaceComposerClient();
-    if (mFlinger == nullptr) {
-        ALOGE("SurfaceComposerClient couldn't be allocated");
-        return false;
-    }
-    err = mFlinger->initCheck();
-    if (err != NO_ERROR) {
-        ALOGE("SurfaceComposerClient::initCheck error: %#x", err);
+    if (pWindowProxy == nullptr) {
+        LOG(ERROR) << "Could not get IAutomotiveDisplayProxyService.";
         return false;
     }
 
-    // Get main display parameters.
-    sp<IBinder> mainDpy = SurfaceComposerClient::getInternalDisplayToken();
-    if (mainDpy == nullptr) {
-        ALOGE("ERROR: no internal display");
+    // We will use the first display in the list as the primary.
+    pWindowProxy->getDisplayInfo(displayId, [this](auto dpyConfig, auto dpyState) {
+        DisplayConfig *pConfig = (DisplayConfig*)dpyConfig.data();
+        mWidth = pConfig->resolution.getWidth();
+        mHeight = pConfig->resolution.getHeight();
+
+        ui::DisplayState* pState = (ui::DisplayState*)dpyState.data();
+        if (pState->orientation != ui::ROTATION_0 &&
+            pState->orientation != ui::ROTATION_180) {
+            // rotate
+            std::swap(mWidth, mHeight);
+        }
+
+        LOG(DEBUG) << "Display resolution is " << mWidth << " x " << mHeight;
+    });
+
+    mGfxBufferProducer = pWindowProxy->getIGraphicBufferProducer(displayId);
+    if (mGfxBufferProducer == nullptr) {
+        LOG(ERROR) << "Failed to get IGraphicBufferProducer from IAutomotiveDisplayProxyService.";
         return false;
     }
 
-    DisplayInfo mainDpyInfo;
-    err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
-    if (err != NO_ERROR) {
-        ALOGE("ERROR: unable to get display characteristics");
+    mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer);
+    if (mSurfaceHolder == nullptr) {
+        LOG(ERROR) << "Failed to get a Surface from HGBP.";
         return false;
     }
 
-    if (mainDpyInfo.orientation != DISPLAY_ORIENTATION_0 &&
-        mainDpyInfo.orientation != DISPLAY_ORIENTATION_180) {
-        // rotated
-        mWidth = mainDpyInfo.h;
-        mHeight = mainDpyInfo.w;
-    } else {
-        mWidth = mainDpyInfo.w;
-        mHeight = mainDpyInfo.h;
-    }
-
-    mFlingerSurfaceControl = mFlinger->createSurface(
-            String8("Evs Display"), mWidth, mHeight,
-            PIXEL_FORMAT_RGBX_8888, ISurfaceComposerClient::eOpaque);
-    if (mFlingerSurfaceControl == nullptr || !mFlingerSurfaceControl->isValid()) {
-        ALOGE("Failed to create SurfaceControl");
+    mWindow = getNativeWindow(mSurfaceHolder.get());
+    if (mWindow == nullptr) {
+        LOG(ERROR) << "Failed to get a native window from Surface.";
         return false;
     }
-    mFlingerSurface = mFlingerSurfaceControl->getSurface();
 
 
     // Set up our OpenGL ES context associated with the default display
     mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     if (mDisplay == EGL_NO_DISPLAY) {
-        ALOGE("Failed to get egl display");
+        LOG(ERROR) << "Failed to get egl display";
         return false;
     }
 
     EGLint major = 3;
     EGLint minor = 0;
     if (!eglInitialize(mDisplay, &major, &minor)) {
-        ALOGE("Failed to initialize EGL: %s", getEGLError());
+        LOG(ERROR) << "Failed to initialize EGL: " << getEGLError();
         return false;
     }
 
@@ -264,14 +260,14 @@
     EGLint numConfigs = -1;
     eglChooseConfig(mDisplay, config_attribs, &egl_config, 1, &numConfigs);
     if (numConfigs != 1) {
-        ALOGE("Didn't find a suitable format for our display window");
+        LOG(ERROR) << "Didn't find a suitable format for our display window";
         return false;
     }
 
     // Create the EGL render target surface
-    mSurface = eglCreateWindowSurface(mDisplay, egl_config, mFlingerSurface.get(), nullptr);
+    mSurface = eglCreateWindowSurface(mDisplay, egl_config, mWindow, nullptr);
     if (mSurface == EGL_NO_SURFACE) {
-        ALOGE("gelCreateWindowSurface failed.");
+        LOG(ERROR) << "eglCreateWindowSurface failed.";
         return false;
     }
 
@@ -281,14 +277,14 @@
     const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
     mContext = eglCreateContext(mDisplay, egl_config, EGL_NO_CONTEXT, context_attribs);
     if (mContext == EGL_NO_CONTEXT) {
-        ALOGE("Failed to create OpenGL ES Context: %s", getEGLError());
+        LOG(ERROR) << "Failed to create OpenGL ES Context: " << getEGLError();
         return false;
     }
 
 
     // Activate our render target for drawing
     if (!eglMakeCurrent(mDisplay, mSurface, mSurface, mContext)) {
-        ALOGE("Failed to make the OpenGL ES Context current: %s", getEGLError());
+        LOG(ERROR) << "Failed to make the OpenGL ES Context current: " << getEGLError();
         return false;
     }
 
@@ -296,14 +292,14 @@
     // Create the shader program for our simple pipeline
     mShaderProgram = buildShaderProgram(vertexShaderSource, pixelShaderSource);
     if (!mShaderProgram) {
-        ALOGE("Failed to build shader program: %s", getEGLError());
+        LOG(ERROR) << "Failed to build shader program: " << getEGLError();
         return false;
     }
 
     // Create a GL texture that will eventually wrap our externally created texture surface(s)
     glGenTextures(1, &mTextureMap);
     if (mTextureMap <= 0) {
-        ALOGE("Didn't get a texture handle allocated: %s", getEGLError());
+        LOG(ERROR) << "Didn't get a texture handle allocated: " << getEGLError();
         return false;
     }
 
@@ -334,68 +330,79 @@
     mContext = EGL_NO_CONTEXT;
     mDisplay = EGL_NO_DISPLAY;
 
-    // Let go of our SurfaceComposer resources
-    mFlingerSurface.clear();
-    mFlingerSurfaceControl.clear();
-    mFlinger.clear();
+    // Release the window
+    mSurfaceHolder = nullptr;
 }
 
 
-void GlWrapper::showWindow() {
-    if (mFlingerSurfaceControl != nullptr) {
-        SurfaceComposerClient::Transaction{}
-                .setLayer(mFlingerSurfaceControl, 0x7FFFFFFF)     // always on top
-                .show(mFlingerSurfaceControl)
-                .apply();
+void GlWrapper::showWindow(sp<IAutomotiveDisplayProxyService>& pWindowProxy, uint64_t id) {
+    if (pWindowProxy != nullptr) {
+        pWindowProxy->showWindow(id);
+    } else {
+        LOG(ERROR) << "IAutomotiveDisplayProxyService is not available.";
     }
 }
 
 
-void GlWrapper::hideWindow() {
-    if (mFlingerSurfaceControl != nullptr) {
-        SurfaceComposerClient::Transaction{}
-                .hide(mFlingerSurfaceControl)
-                .apply();
+void GlWrapper::hideWindow(sp<IAutomotiveDisplayProxyService>& pWindowProxy, uint64_t id) {
+    if (pWindowProxy != nullptr) {
+        pWindowProxy->hideWindow(id);
+    } else {
+        LOG(ERROR) << "IAutomotiveDisplayProxyService is not available.";
     }
 }
 
 
-bool GlWrapper::updateImageTexture(const BufferDesc& buffer) {
+bool GlWrapper::updateImageTexture(const BufferDesc_1_0& buffer) {
+    BufferDesc_1_1 newBuffer = {};
+    AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<AHardwareBuffer_Desc *>(&newBuffer.buffer.description);
+    pDesc->width = buffer.width;
+    pDesc->height = buffer.height;
+    pDesc->layers = 1;
+    pDesc->format = buffer.format;
+    pDesc->usage = buffer.usage;
+    pDesc->stride = buffer.stride;
+    newBuffer.buffer.nativeHandle = buffer.memHandle;
+    newBuffer.pixelSize = buffer.pixelSize;
+    newBuffer.bufferId = buffer.bufferId;
+
+    return updateImageTexture(newBuffer);
+}
+
+
+bool GlWrapper::updateImageTexture(const BufferDesc_1_1& aFrame) {
 
     // If we haven't done it yet, create an "image" object to wrap the gralloc buffer
     if (mKHRimage == EGL_NO_IMAGE_KHR) {
         // create a temporary GraphicBuffer to wrap the provided handle
+        const AHardwareBuffer_Desc* pDesc =
+            reinterpret_cast<const AHardwareBuffer_Desc *>(&aFrame.buffer.description);
         sp<GraphicBuffer> pGfxBuffer = new GraphicBuffer(
-                buffer.width,
-                buffer.height,
-                buffer.format,
-                1,      /* layer count */
-                buffer.usage,
-                buffer.stride,
-                const_cast<native_handle_t*>(buffer.memHandle.getNativeHandle()),
+                pDesc->width,
+                pDesc->height,
+                pDesc->format,
+                pDesc->layers,
+                pDesc->usage,
+                pDesc->stride,
+                const_cast<native_handle_t*>(aFrame.buffer.nativeHandle.getNativeHandle()),
                 false   /* keep ownership */
         );
         if (pGfxBuffer.get() == nullptr) {
-            ALOGE("Failed to allocate GraphicsBuffer to wrap our native handle");
+            LOG(ERROR) << "Failed to allocate GraphicBuffer to wrap our native handle";
             return false;
         }
 
-
         // Get a GL compatible reference to the graphics buffer we've been given
         EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
         EGLClientBuffer cbuf = static_cast<EGLClientBuffer>(pGfxBuffer->getNativeBuffer());
-// TODO:  If we pass in a context, we get "bad context" back
-#if 0
-        mKHRimage = eglCreateImageKHR(mDisplay, mContext,
-                                      EGL_NATIVE_BUFFER_ANDROID, cbuf,
+        mKHRimage = eglCreateImageKHR(mDisplay,
+                                      EGL_NO_CONTEXT,
+                                      EGL_NATIVE_BUFFER_ANDROID,
+                                      cbuf,
                                       eglImageAttributes);
-#else
-        mKHRimage = eglCreateImageKHR(mDisplay, EGL_NO_CONTEXT,
-                                      EGL_NATIVE_BUFFER_ANDROID, cbuf,
-                                      eglImageAttributes);
-#endif
         if (mKHRimage == EGL_NO_IMAGE_KHR) {
-            ALOGE("error creating EGLImage: %s", getEGLError());
+            LOG(ERROR) << "Error creating EGLImage: " << getEGLError();
             return false;
         }
 
diff --git a/evs/sampleDriver/GlWrapper.h b/evs/sampleDriver/GlWrapper.h
index 07b5525..68505bc 100644
--- a/evs/sampleDriver/GlWrapper.h
+++ b/evs/sampleDriver/GlWrapper.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_DISPLAY_GLWRAPPER_H
-#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_DISPLAY_GLWRAPPER_H
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_DISPLAY_GLWRAPPER_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_DISPLAY_GLWRAPPER_H
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
@@ -24,38 +24,40 @@
 #include <GLES3/gl3.h>
 #include <GLES3/gl3ext.h>
 
-#include <gui/ISurfaceComposer.h>
-#include <gui/Surface.h>
-#include <gui/SurfaceComposerClient.h>
-
-#include <android/hardware/automotive/evs/1.0/types.h>
+#include <android/frameworks/automotive/display/1.0/IAutomotiveDisplayProxyService.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
+#include <android-base/logging.h>
+#include <bufferqueueconverter/BufferQueueConverter.h>
 
 
 using ::android::sp;
-using ::android::SurfaceComposerClient;
-using ::android::SurfaceControl;
-using ::android::Surface;
-using ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using ::android::SurfaceHolder;
+using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
+using ::android::frameworks::automotive::display::V1_0::IAutomotiveDisplayProxyService;
+using ::android::hardware::graphics::bufferqueue::V2_0::IGraphicBufferProducer;
 
 
 class GlWrapper {
 public:
-    bool initialize();
+    GlWrapper()
+        : mSurfaceHolder(android::SurfaceHolderUniquePtr(nullptr, nullptr)) {}
+    bool initialize(sp<IAutomotiveDisplayProxyService> pWindowService, uint64_t displayId);
     void shutdown();
 
-    bool updateImageTexture(const BufferDesc& buffer);
+    bool updateImageTexture(const BufferDesc_1_0& buffer);
+    bool updateImageTexture(const BufferDesc_1_1& buffer);
     void renderImageToScreen();
 
-    void showWindow();
-    void hideWindow();
+    void showWindow(sp<IAutomotiveDisplayProxyService>& pWindowService, uint64_t id);
+    void hideWindow(sp<IAutomotiveDisplayProxyService>& pWindowService, uint64_t id);
 
     unsigned getWidth()     { return mWidth; };
     unsigned getHeight()    { return mHeight; };
 
 private:
-    sp<SurfaceComposerClient>   mFlinger;
-    sp<SurfaceControl>          mFlingerSurfaceControl;
-    sp<Surface>                 mFlingerSurface;
+    sp<IGraphicBufferProducer>  mGfxBufferProducer;
+
     EGLDisplay                  mDisplay;
     EGLSurface                  mSurface;
     EGLContext                  mContext;
@@ -67,6 +69,13 @@
 
     GLuint mTextureMap    = 0;
     GLuint mShaderProgram = 0;
+
+    // Opaque handle for a native hardware buffer defined in
+    // frameworks/native/opengl/include/EGL/eglplatform.h
+    ANativeWindow*                  mWindow;
+
+    // Pointer to a Surface wrapper.
+    android::SurfaceHolderUniquePtr mSurfaceHolder;
 };
 
-#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_DISPLAY_GLWRAPPER_H
+#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_DISPLAY_GLWRAPPER_H
diff --git a/evs/sampleDriver/ServiceNames.h b/evs/sampleDriver/ServiceNames.h
index 6458b1b..4fb7225 100644
--- a/evs/sampleDriver/ServiceNames.h
+++ b/evs/sampleDriver/ServiceNames.h
@@ -13,9 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_SERVICENAMES_H
-#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_SERVICENAMES_H
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_SERVICENAMES_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_SERVICENAMES_H
 
-const static char kEnumeratorServiceName[] = "EvsEnumeratorHw";
+const static char kEnumeratorServiceName[] = "hw/1";
 
-#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_SERVICENAMES_H
+#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_SERVICENAMES_H
diff --git a/evs/sampleDriver/VideoCapture.cpp b/evs/sampleDriver/VideoCapture.cpp
index 5ef996d..9663bf6 100644
--- a/evs/sampleDriver/VideoCapture.cpp
+++ b/evs/sampleDriver/VideoCapture.cpp
@@ -17,12 +17,14 @@
 #include <stdlib.h>
 #include <error.h>
 #include <errno.h>
+#include <iomanip>
 #include <memory.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
-#include <cutils/log.h>
+
+#include <android-base/logging.h>
 
 #include "assert.h"
 
@@ -33,12 +35,12 @@
 //        during the resource setup phase.  Of particular note is the potential to leak
 //        the file descriptor.  This must be fixed before using this code for anything but
 //        experimentation.
-bool VideoCapture::open(const char* deviceName) {
+bool VideoCapture::open(const char* deviceName, const int32_t width, const int32_t height) {
     // If we want a polling interface for getting frames, we would use O_NONBLOCK
 //    int mDeviceFd = open(deviceName, O_RDWR | O_NONBLOCK, 0);
     mDeviceFd = ::open(deviceName, O_RDWR, 0);
     if (mDeviceFd < 0) {
-        ALOGE("failed to open device %s (%d = %s)", deviceName, errno, strerror(errno));
+        PLOG(ERROR) << "failed to open device " << deviceName;
         return false;
     }
 
@@ -46,35 +48,32 @@
     {
         int result = ioctl(mDeviceFd, VIDIOC_QUERYCAP, &caps);
         if (result  < 0) {
-            ALOGE("failed to get device caps for %s (%d = %s)", deviceName, errno, strerror(errno));
+            PLOG(ERROR) << "failed to get device caps for " << deviceName;
             return false;
         }
     }
 
     // Report device properties
-    ALOGI("Open Device: %s (fd=%d)", deviceName, mDeviceFd);
-    ALOGI("  Driver: %s", caps.driver);
-    ALOGI("  Card: %s", caps.card);
-    ALOGI("  Version: %u.%u.%u",
-            (caps.version >> 16) & 0xFF,
-            (caps.version >> 8)  & 0xFF,
-            (caps.version)       & 0xFF);
-    ALOGI("  All Caps: %08X", caps.capabilities);
-    ALOGI("  Dev Caps: %08X", caps.device_caps);
+    LOG(INFO) << "Open Device: " << deviceName << " (fd = " << mDeviceFd << ")";
+    LOG(INFO) << "  Driver: " << caps.driver;
+    LOG(INFO) << "  Card: " << caps.card;
+    LOG(INFO) << "  Version: " << ((caps.version >> 16) & 0xFF)
+                               << "." << ((caps.version >> 8) & 0xFF)
+                               << "." << (caps.version & 0xFF);
+    LOG(INFO) << "  All Caps: " << std::hex << std::setw(8) << caps.capabilities;
+    LOG(INFO) << "  Dev Caps: " << std::hex << caps.device_caps;
 
     // Enumerate the available capture formats (if any)
-    ALOGI("Supported capture formats:");
+    LOG(INFO) << "Supported capture formats:";
     v4l2_fmtdesc formatDescriptions;
     formatDescriptions.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
     for (int i=0; true; i++) {
         formatDescriptions.index = i;
         if (ioctl(mDeviceFd, VIDIOC_ENUM_FMT, &formatDescriptions) == 0) {
-            ALOGI("  %2d: %s 0x%08X 0x%X",
-                   i,
-                   formatDescriptions.description,
-                   formatDescriptions.pixelformat,
-                   formatDescriptions.flags
-            );
+            LOG(INFO) << "  " << std::setw(2) << i
+                      << ": " << formatDescriptions.description
+                      << " " << std::hex << std::setw(8) << formatDescriptions.pixelformat
+                      << " " << std::hex << formatDescriptions.flags;
         } else {
             // No more formats available
             break;
@@ -85,7 +84,7 @@
     if (!(caps.capabilities & V4L2_CAP_VIDEO_CAPTURE) ||
         !(caps.capabilities & V4L2_CAP_STREAMING)) {
         // Can't do streaming capture.
-        ALOGE("Streaming capture not supported by %s.", deviceName);
+        LOG(ERROR) << "Streaming capture not supported by " << deviceName;
         return false;
     }
 
@@ -93,16 +92,17 @@
     v4l2_format format;
     format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
     format.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
-    format.fmt.pix.width = 720;
-    format.fmt.pix.height = 240;
-    ALOGI("Requesting format %c%c%c%c (0x%08X)",
-          ((char*)&format.fmt.pix.pixelformat)[0],
-          ((char*)&format.fmt.pix.pixelformat)[1],
-          ((char*)&format.fmt.pix.pixelformat)[2],
-          ((char*)&format.fmt.pix.pixelformat)[3],
-          format.fmt.pix.pixelformat);
+    format.fmt.pix.width = width;
+    format.fmt.pix.height = height;
+    LOG(INFO) << "Requesting format: "
+              << ((char*)&format.fmt.pix.pixelformat)[0]
+              << ((char*)&format.fmt.pix.pixelformat)[1]
+              << ((char*)&format.fmt.pix.pixelformat)[2]
+              << ((char*)&format.fmt.pix.pixelformat)[3]
+              << "(" << std::hex << std::setw(8) << format.fmt.pix.pixelformat << ")";
+
     if (ioctl(mDeviceFd, VIDIOC_S_FMT, &format) < 0) {
-        ALOGE("VIDIOC_S_FMT: %s", strerror(errno));
+        PLOG(ERROR) << "VIDIOC_S_FMT failed";
     }
 
     // Report the current output format
@@ -114,14 +114,12 @@
         mHeight = format.fmt.pix.height;
         mStride = format.fmt.pix.bytesperline;
 
-        ALOGI("Current output format:  fmt=0x%X, %dx%d, pitch=%d",
-               format.fmt.pix.pixelformat,
-               format.fmt.pix.width,
-               format.fmt.pix.height,
-               format.fmt.pix.bytesperline
-        );
+        LOG(INFO) << "Current output format:  "
+                  << "fmt=0x" << std::hex << format.fmt.pix.pixelformat
+                  << ", " << std::dec << format.fmt.pix.width << " x " << format.fmt.pix.height
+                  << ", pitch=" << format.fmt.pix.bytesperline;
     } else {
-        ALOGE("VIDIOC_G_FMT: %s", strerror(errno));
+        PLOG(ERROR) << "VIDIOC_G_FMT failed";
         return false;
     }
 
@@ -135,12 +133,12 @@
 
 
 void VideoCapture::close() {
-    ALOGD("VideoCapture::close");
+    LOG(DEBUG) << __FUNCTION__;
     // Stream should be stopped first!
     assert(mRunMode == STOPPED);
 
     if (isOpen()) {
-        ALOGD("closing video device file handled %d", mDeviceFd);
+        LOG(DEBUG) << "closing video device file handle " << mDeviceFd;
         ::close(mDeviceFd);
         mDeviceFd = -1;
     }
@@ -152,7 +150,7 @@
     int prevRunMode = mRunMode.fetch_or(RUN);
     if (prevRunMode & RUN) {
         // The background thread is already running, so we can't start a new stream
-        ALOGE("Already in RUN state, so we can't start a new streaming thread");
+        LOG(ERROR) << "Already in RUN state, so we can't start a new streaming thread";
         return false;
     }
 
@@ -162,7 +160,7 @@
     bufrequest.memory = V4L2_MEMORY_MMAP;
     bufrequest.count = 1;
     if (ioctl(mDeviceFd, VIDIOC_REQBUFS, &bufrequest) < 0) {
-        ALOGE("VIDIOC_REQBUFS: %s", strerror(errno));
+        PLOG(ERROR) << "VIDIOC_REQBUFS failed";
         return false;
     }
 
@@ -172,13 +170,14 @@
     mBufferInfo.memory   = V4L2_MEMORY_MMAP;
     mBufferInfo.index    = 0;
     if (ioctl(mDeviceFd, VIDIOC_QUERYBUF, &mBufferInfo) < 0) {
-        ALOGE("VIDIOC_QUERYBUF: %s", strerror(errno));
+        PLOG(ERROR) << "VIDIOC_QUERYBUF failed";
         return false;
     }
 
-    ALOGI("Buffer description:");
-    ALOGI("  offset: %d", mBufferInfo.m.offset);
-    ALOGI("  length: %d", mBufferInfo.length);
+    LOG(INFO) << "Buffer description:";
+    LOG(INFO) << "  offset: " << mBufferInfo.m.offset;
+    LOG(INFO) << "  length: " << mBufferInfo.length;
+    LOG(INFO) << "  flags : " << std::hex << mBufferInfo.flags;
 
     // Get a pointer to the buffer contents by mapping into our address space
     mPixelBuffer = mmap(
@@ -190,22 +189,22 @@
             mBufferInfo.m.offset
     );
     if( mPixelBuffer == MAP_FAILED) {
-        ALOGE("mmap: %s", strerror(errno));
+        PLOG(ERROR) << "mmap() failed";
         return false;
     }
     memset(mPixelBuffer, 0, mBufferInfo.length);
-    ALOGI("Buffer mapped at %p", mPixelBuffer);
+    LOG(INFO) << "Buffer mapped at " << mPixelBuffer;
 
     // Queue the first capture buffer
     if (ioctl(mDeviceFd, VIDIOC_QBUF, &mBufferInfo) < 0) {
-        ALOGE("VIDIOC_QBUF: %s", strerror(errno));
+        PLOG(ERROR) << "VIDIOC_QBUF failed";
         return false;
     }
 
     // Start the video stream
     int type = mBufferInfo.type;
     if (ioctl(mDeviceFd, VIDIOC_STREAMON, &type) < 0) {
-        ALOGE("VIDIOC_STREAMON: %s", strerror(errno));
+        PLOG(ERROR) << "VIDIOC_STREAMON failed";
         return false;
     }
 
@@ -215,7 +214,7 @@
     // Fire up a thread to receive and dispatch the video frames
     mCaptureThread = std::thread([this](){ collectFrames(); });
 
-    ALOGD("Stream started.");
+    LOG(DEBUG) << "Stream started.";
     return true;
 }
 
@@ -227,7 +226,8 @@
         // The background thread wasn't running, so set the flag back to STOPPED
         mRunMode = STOPPED;
     } else if (prevRunMode & STOPPING) {
-        ALOGE("stopStream called while stream is already stopping.  Reentrancy is not supported!");
+        LOG(ERROR) << "stopStream called while stream is already stopping.  "
+                   << "Reentrancy is not supported!";
         return;
     } else {
         // Block until the background thread is stopped
@@ -238,10 +238,10 @@
         // Stop the underlying video stream (automatically empties the buffer queue)
         int type = mBufferInfo.type;
         if (ioctl(mDeviceFd, VIDIOC_STREAMOFF, &type) < 0) {
-            ALOGE("VIDIOC_STREAMOFF: %s", strerror(errno));
+            PLOG(ERROR) << "VIDIOC_STREAMOFF failed";
         }
 
-        ALOGD("Capture thread stopped.");
+        LOG(DEBUG) << "Capture thread stopped.";
     }
 
     // Unmap the buffers we allocated
@@ -270,7 +270,7 @@
 
     // Requeue the buffer to capture the next available frame
     if (ioctl(mDeviceFd, VIDIOC_QBUF, &mBufferInfo) < 0) {
-        ALOGE("VIDIOC_QBUF: %s", strerror(errno));
+        PLOG(ERROR) << "VIDIOC_QBUF failed";
         return false;
     }
 
@@ -284,7 +284,7 @@
     while (mRunMode == RUN) {
         // Wait for a buffer to be ready
         if (ioctl(mDeviceFd, VIDIOC_DQBUF, &mBufferInfo) < 0) {
-            ALOGE("VIDIOC_DQBUF: %s", strerror(errno));
+            PLOG(ERROR) << "VIDIOC_DQBUF failed";
             break;
         }
 
@@ -297,6 +297,52 @@
     }
 
     // Mark ourselves stopped
-    ALOGD("VideoCapture thread ending");
+    LOG(DEBUG) << "VideoCapture thread ending";
     mRunMode = STOPPED;
 }
+
+
+int VideoCapture::setParameter(v4l2_control& control) {
+    int status = ioctl(mDeviceFd, VIDIOC_S_CTRL, &control);
+    if (status < 0) {
+        PLOG(ERROR) << "Failed to program a parameter value "
+                    << "id = " << std::hex << control.id;
+    }
+
+    return status;
+}
+
+
+int VideoCapture::getParameter(v4l2_control& control) {
+    int status = ioctl(mDeviceFd, VIDIOC_G_CTRL, &control);
+    if (status < 0) {
+        PLOG(ERROR) << "Failed to read a parameter value"
+                    << " fd = " << std::hex << mDeviceFd
+                    << " id = " << control.id;
+    }
+
+    return status;
+}
+
+
+std::set<uint32_t> VideoCapture::enumerateCameraControls() {
+    // Retrieve available camera controls
+    struct v4l2_queryctrl ctrl = {
+        .id = V4L2_CTRL_FLAG_NEXT_CTRL
+    };
+
+    std::set<uint32_t> ctrlIDs;
+    while (0 == ioctl(mDeviceFd, VIDIOC_QUERYCTRL, &ctrl)) {
+        if (!(ctrl.flags & V4L2_CTRL_FLAG_DISABLED)) {
+            ctrlIDs.emplace(ctrl.id);
+        }
+
+        ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+    }
+
+    if (errno != EINVAL) {
+        PLOG(WARNING) << "Failed to run VIDIOC_QUERYCTRL";
+    }
+
+    return std::move(ctrlIDs);
+}
diff --git a/evs/sampleDriver/VideoCapture.h b/evs/sampleDriver/VideoCapture.h
index 63305b9..42a5ef4 100644
--- a/evs/sampleDriver/VideoCapture.h
+++ b/evs/sampleDriver/VideoCapture.h
@@ -13,21 +13,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_VIDEOCAPTURE_H
-#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_VIDEOCAPTURE_H
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_VIDEOCAPTURE_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_VIDEOCAPTURE_H
 
 #include <atomic>
-#include <thread>
 #include <functional>
-#include <linux/videodev2.h>
+#include <set>
+#include <thread>
 
+#include <linux/videodev2.h>
 
 typedef v4l2_buffer imageBuffer;
 
 
 class VideoCapture {
 public:
-    bool open(const char* deviceName);
+    bool open(const char* deviceName, const int32_t width = 0, const int32_t height = 0);
     void close();
 
     bool startStream(std::function<void(VideoCapture*, imageBuffer*, void*)> callback = nullptr);
@@ -47,6 +48,10 @@
 
     bool isOpen()               { return mDeviceFd >= 0; };
 
+    int setParameter(struct v4l2_control& control);
+    int getParameter(struct v4l2_control& control);
+    std::set<uint32_t> enumerateCameraControls();
+
 private:
     void collectFrames();
     void markFrameReady();
diff --git a/evs/sampleDriver/android.hardware.automotive.evs@1.0-sample.rc b/evs/sampleDriver/android.hardware.automotive.evs@1.0-sample.rc
deleted file mode 100644
index 445a3a0..0000000
--- a/evs/sampleDriver/android.hardware.automotive.evs@1.0-sample.rc
+++ /dev/null
@@ -1,7 +0,0 @@
-service evs_driver /system/bin/android.hardware.automotive.evs@1.0-sample
-    class hal
-    priority -20
-    user graphics
-    group automotive_evs camera
-    onrestart restart evs_manager
-    disabled # will not automatically start with its class; must be explictly started.
diff --git a/evs/sampleDriver/android.hardware.automotive.evs@1.1-sample.rc b/evs/sampleDriver/android.hardware.automotive.evs@1.1-sample.rc
new file mode 100644
index 0000000..324a949
--- /dev/null
+++ b/evs/sampleDriver/android.hardware.automotive.evs@1.1-sample.rc
@@ -0,0 +1,7 @@
+service evs_driver /vendor/bin/android.hardware.automotive.evs@1.1-sample
+    class hal
+    priority -20
+    user graphics
+    group automotive_evs camera
+    onrestart restart evs_manager
+    disabled # will not automatically start with its class; must be explictly started.
diff --git a/evs/sampleDriver/bufferCopy.cpp b/evs/sampleDriver/bufferCopy.cpp
index 6c8c3ef..1c07478 100644
--- a/evs/sampleDriver/bufferCopy.cpp
+++ b/evs/sampleDriver/bufferCopy.cpp
@@ -21,7 +21,7 @@
 namespace hardware {
 namespace automotive {
 namespace evs {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 
 
@@ -71,10 +71,12 @@
     // an even multiple of 16 bytes for both the Y and UV arrays.
 
     // Target  and source image layout properties (They match since the formats match!)
-    const unsigned strideLum = align<16>(tgtBuff.width);
-    const unsigned sizeY = strideLum * tgtBuff.height;
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
+    const unsigned strideLum = align<16>(pDesc->width);
+    const unsigned sizeY = strideLum * pDesc->height;
     const unsigned strideColor = strideLum;   // 1/2 the samples, but two interleaved channels
-    const unsigned sizeColor = strideColor * tgtBuff.height/2;
+    const unsigned sizeColor = strideColor * pDesc->height/2;
     const unsigned totalBytes = sizeY + sizeColor;
 
     // Simply copy the data byte for byte
@@ -100,8 +102,10 @@
     };
 
     // Target image layout properties
-    const unsigned strideLum = align<16>(tgtBuff.width);
-    const unsigned sizeY = strideLum * tgtBuff.height;
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
+    const unsigned strideLum = align<16>(pDesc->width);
+    const unsigned sizeY = strideLum * pDesc->height;
     const unsigned strideColor = strideLum;   // 1/2 the samples, but two interleaved channels
 
     // Source image layout properties
@@ -111,14 +115,14 @@
     uint32_t* botSrcRow =  srcDataYUYV + srcRowPixels;
 
     // We're going to work on one 2x2 cell in the output image at at time
-    for (unsigned cellRow = 0; cellRow < tgtBuff.height/2; cellRow++) {
+    for (unsigned cellRow = 0; cellRow < pDesc->height/2; cellRow++) {
 
         // Set up the output pointers
         uint8_t* yTopRow = tgt + (cellRow*2) * strideLum;
         uint8_t* yBotRow = yTopRow + strideLum;
         uint8_t* uvRow   = (tgt + sizeY) + cellRow * strideColor;
 
-        for (unsigned cellCol = 0; cellCol < tgtBuff.width/2; cellCol++) {
+        for (unsigned cellCol = 0; cellCol < pDesc->width/2; cellCol++) {
             // Collect the values from the YUYV interleaved data
             const YUYVpixel* pTopMacroPixel = (YUYVpixel*)&topSrcRow[cellCol];
             const YUYVpixel* pBotMacroPixel = (YUYVpixel*)&botSrcRow[cellCol];
@@ -144,12 +148,14 @@
 
 
 void fillRGBAFromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, unsigned imgStride) {
-    unsigned width = tgtBuff.width;
-    unsigned height = tgtBuff.height;
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
+    unsigned width = pDesc->width;
+    unsigned height = pDesc->height;
     uint32_t* src = (uint32_t*)imgData;
     uint32_t* dst = (uint32_t*)tgt;
     unsigned srcStridePixels = imgStride / 2;
-    unsigned dstStridePixels = tgtBuff.stride;
+    unsigned dstStridePixels = pDesc->stride;
 
     const int srcRowPadding32 = srcStridePixels/2 - width/2;  // 2 bytes per pixel, 4 bytes per word
     const int dstRowPadding32 = dstStridePixels   - width;    // 4 bytes per pixel, 4 bytes per word
@@ -178,12 +184,14 @@
 
 
 void fillYUYVFromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, unsigned imgStride) {
-    unsigned width = tgtBuff.width;
-    unsigned height = tgtBuff.height;
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
+    unsigned width = pDesc->width;
+    unsigned height = pDesc->height;
     uint8_t* src = (uint8_t*)imgData;
     uint8_t* dst = (uint8_t*)tgt;
     unsigned srcStrideBytes = imgStride;
-    unsigned dstStrideBytes = tgtBuff.stride * 2;
+    unsigned dstStrideBytes = pDesc->stride * 2;
 
     for (unsigned r=0; r<height; r++) {
         // Copy a pixel row at a time (2 bytes per pixel, averaged over a YUYV macro pixel)
@@ -193,12 +201,14 @@
 
 
 void fillYUYVFromUYVY(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, unsigned imgStride) {
-    unsigned width = tgtBuff.width;
-    unsigned height = tgtBuff.height;
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
+    unsigned width = pDesc->width;
+    unsigned height = pDesc->height;
     uint32_t* src = (uint32_t*)imgData;
     uint32_t* dst = (uint32_t*)tgt;
     unsigned srcStridePixels = imgStride / 2;
-    unsigned dstStridePixels = tgtBuff.stride;
+    unsigned dstStridePixels = pDesc->stride;
 
     const int srcRowPadding32 = srcStridePixels/2 - width/2;  // 2 bytes per pixel, 4 bytes per word
     const int dstRowPadding32 = dstStridePixels/2 - width/2;  // 2 bytes per pixel, 4 bytes per word
@@ -228,7 +238,7 @@
 
 
 } // namespace implementation
-} // namespace V1_0
+} // namespace V1_1
 } // namespace evs
 } // namespace automotive
 } // namespace hardware
diff --git a/evs/sampleDriver/bufferCopy.h b/evs/sampleDriver/bufferCopy.h
index 9f68f2b..b07a619 100644
--- a/evs/sampleDriver/bufferCopy.h
+++ b/evs/sampleDriver/bufferCopy.h
@@ -14,17 +14,18 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_BUFFERCOPY_H
-#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_BUFFERCOPY_H
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_BUFFERCOPY_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_BUFFERCOPY_H
 
-#include <android/hardware/automotive/evs/1.0/types.h>
+#include <android/hardware_buffer.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
 
 
 namespace android {
 namespace hardware {
 namespace automotive {
 namespace evs {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 
 
@@ -44,10 +45,10 @@
                       void* imgData, unsigned imgStride);
 
 } // namespace implementation
-} // namespace V1_0
+} // namespace V1_1
 } // namespace evs
 } // namespace automotive
 } // namespace hardware
 } // namespace android
 
-#endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_BUFFERCOPY_H
+#endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_BUFFERCOPY_H
diff --git a/evs/sampleDriver/manifest_android.hardware.automotive.evs@1.1.xml b/evs/sampleDriver/manifest_android.hardware.automotive.evs@1.1.xml
new file mode 100644
index 0000000..c36edb6
--- /dev/null
+++ b/evs/sampleDriver/manifest_android.hardware.automotive.evs@1.1.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest version="1.0" type="device" >
+    <hal format="hidl">
+        <name>android.hardware.automotive.evs</name>
+        <transport>hwbinder</transport>
+        <version>1.1</version>
+        <interface>
+            <name>IEvsEnumerator</name>
+            <instance>hw/1</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/evs/sampleDriver/resources/evs_configuration.dtd b/evs/sampleDriver/resources/evs_configuration.dtd
new file mode 100644
index 0000000..d6be018
--- /dev/null
+++ b/evs/sampleDriver/resources/evs_configuration.dtd
@@ -0,0 +1,108 @@
+<?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.
+-->
+
+<!-- Author : changyeon@google.com
+     Version: 1.0
+-->
+
+<!ELEMENT configuration (system,camera,display)>
+
+<!-- System Configuration that contains below informations:
+     - Number of cameras available to EVS.
+-->
+<!ELEMENT system (num_cameras)>
+    <!-- The number of cameras that are available to EVS on the vehicle.
+         This must be equal to number of camera elements of device element.
+    -->
+    <!ELEMENT num_cameras EMPTY>
+    <!ATTLIST num_cameras
+        value CDATA #REQUIRED
+    >
+
+<!-- Device descriptions -->
+<!ELEMENT camera (group|device)+>
+    <!-- Camera group descriptor
+         @attr group_id    : Unique logical camera group identifier.  Camera device use this to be
+                             a member of the group.
+         @attr device_id   : Comma-separated list of unique camera identifiers of member camera
+                             devices.
+         @attr synchronized: NONE if cameras are not synchronized.
+                             CALIBRATED if cameras are synchronized by hardware.
+                             APPROXIMATE if cameras are synchronized by other means.
+    -->
+    <!ELEMENT group (caps)>
+    <!ATTLIST group
+        group_id        CDATA #REQUIRED
+        device_id       CDATA #REQUIRED
+        synchronized    CDATA #REQUIRED
+    >
+    <!-- Please note that a camera group may have stream configurations.  If it has, all stream
+         configurations must be supported by each camera device in the group.
+    -->
+
+    <!-- Camera device descriptor
+         @attr id          : Unique camera identifier.
+         @attr position    : Must be one of front, rear, left, or right.
+    -->
+    <!ELEMENT device (caps,characteristics*)>
+    <!ATTLIST device
+        id              CDATA #REQUIRED
+        position        CDATA #REQUIRED
+    >
+        <!-- Camera metadata that contains:
+             - A list of supported controls.
+             - A list of supported stream configurations.
+        -->
+        <!ELEMENT caps (supported_controls|stream)*>
+            <!-- A list of supported controls.
+                 This must be a subset of android.hardware.automotive.evs@1.1::CameraParam.
+            -->
+            <!ELEMENT supported_controls (control)+>
+                <!-- A camera control parameter with its valid value range -->
+                <!ELEMENT control EMPTY>
+                <!ATTLIST control
+                    name    CDATA #REQUIRED
+                    min     CDATA #REQUIRED
+                    max     CDATA #REQUIRED
+                    step    CDATA '1'
+                >
+
+            <!-- A list of supported output sizes. -->
+            <!ELEMENT stream EMPTY>
+            <!ATTLIST stream
+                id        CDATA #REQUIRED
+                width     CDATA #REQUIRED
+                height    CDATA #REQUIRED
+                format    CDATA #REQUIRED
+                framerate CDATA #REQUIRED
+            >
+
+        <!-- Camera module characteristics including its optics and imaging sensor. -->
+        <!ELEMENT characteristics (parameter)*>
+                <!ELEMENT parameter EMPTY>
+                <!-- A name of camera characteristic.  This must be a subset of
+                     android.hardware.automotive.evs@1.1::CameraCharacteristics.
+                -->
+                <!ATTLIST parameter
+                    name  CDATA #REQUIRED
+                    type  CDATA #REQUIRED
+                    size  CDATA #REQUIRED
+                    value CDATA #REQUIRED
+                >
+
+<!-- Available display devices -->
+<!ELEMENT display (device)+>
+
diff --git a/evs/sampleDriver/resources/evs_sample_configuration.xml b/evs/sampleDriver/resources/evs_sample_configuration.xml
new file mode 100644
index 0000000..f81b922
--- /dev/null
+++ b/evs/sampleDriver/resources/evs_sample_configuration.xml
@@ -0,0 +1,425 @@
+<?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.
+-->
+
+<!-- Exterior View System Example Configuration
+
+     Android Automotive axes are used to define coordinates.
+     See https://source.android.com/devices/sensors/sensor-types#auto_axes
+
+     Use evs_configuration.dtd with xmllint tool, to validate XML configuration file
+-->
+
+<configuration>
+    <!-- system configuration -->
+    <system>
+        <!-- number of cameras available to EVS -->
+        <num_cameras value='2'/>
+    </system>
+
+    <!-- camera device information -->
+    <camera>
+        <!-- camera group 0 -->
+        <group id='group0' synchronized='CALIBRATED'>
+            <caps>
+                <!-- list of supported controls supported by all physical devices -->
+                <supported_controls>
+                    <control name='BRIGHTNESS' min='0' max='255'/>
+                    <control name='CONTRAST' min='0' max='255'/>
+                </supported_controls>
+
+                <!-- list of stream configuration supported by all physical devices -->
+                <stream id='0' width='640' height='480' format='RGBA_8888' framerate='30'/>
+            </caps>
+
+            <!-- list of parameters -->
+            <characteristics>
+                <parameter
+                    name='REQUEST_AVAILABLE_CAPABILITIES'
+                    type='enum'
+                    size='1'
+                    value='LOGICAL_MULTI_CAMERA'
+                />
+                <parameter
+                    name='LOGICAL_MULTI_CAMERA_PHYSICAL_IDS'
+                    type='byte[]'
+                    size='2'
+                    value='/dev/video3,/dev/video4'
+                />
+            </characteristics>
+        </group>
+
+        <!-- camera device starts -->
+        <device id='/dev/video3' position='rear'>
+            <caps>
+                <!-- list of supported controls -->
+                <supported_controls>
+                    <control name='BRIGHTNESS' min='0' max='255'/>
+                    <control name='CONTRAST' min='0' max='255'/>
+                    <control name='AUTO_WHITE_BALANCE' min='0' max='1'/>
+                    <control name='WHITE_BALANCE_TEMPERATURE' min='2000' max='7500'/>
+                    <control name='SHARPNESS' min='0' max='255'/>
+                    <control name='AUTO_FOCUS' min='0' max='1'/>
+                    <control name='ABSOLUTE_FOCUS' min='0' max='255' step='5'/>
+                    <control name='ABSOLUTE_ZOOM' min='100' max='400'/>
+                </supported_controls>
+
+                <!-- list of supported stream configurations -->
+                <!-- below configurations were taken from v4l2-ctrl query on Logitech Webcam C930e device -->
+                <stream id='0' width='1920' height='1080' format='RGBA_8888' framerate='5'/>
+                <stream id='1' width='2304' height='1296' format='RGBA_8888' framerate='2'/>
+                <stream id='2' width='2304' height='1536' format='RGBA_8888' framerate='2'/>
+                <stream id='4' width='1280' height='720'  format='RGBA_8888' framerate='10'/>
+                <stream id='4' width='1024' height='576'  format='RGBA_8888' framerate='15'/>
+                <stream id='5' width='960'  height='540'  format='RGBA_8888' framerate='15'/>
+                <stream id='6' width='848'  height='480'  format='RGBA_8888' framerate='30'/>
+                <stream id='7' width='640'  height='360'  format='RGBA_8888' framerate='30'/>
+                <stream id='8' width='480'  height='270'  format='RGBA_8888' framerate='30'/>
+                <stream id='9' width='160'  height='120'  format='RGBA_8888' framerate='30'/>
+            </caps>
+
+            <!-- list of parameters -->
+            <characteristics>
+                <!-- Lens distortion information. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_DISTORTION
+                -->
+                <parameter
+                    name='LENS_DISTORTION'
+                    type='float'
+                    size='5'
+                    value='0.0,0.0,0.0,0.0,0.0'
+                />
+
+                <!-- Camera intrinsic calibration matrix. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_INTRINSIC_CALIBRATION
+                -->
+                <parameter
+                    name='LENS_INTRINSIC_CALIBRATION'
+                    type='float'
+                    size='5'
+                    value='0.0,0.0,0.0,0.0,0.0'
+                />
+
+                <!-- Camera pose translation and rotation.  See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_POSE_TRANSLATION
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_POSE_ROTATION
+                -->
+                <parameter
+                    name='LENS_POSE_TRANSLATION'
+                    type='float'
+                    size='3'
+                    value='0.0,0.0,0.0'
+                />
+                <parameter
+                    name='LENS_POSE_ROTATION'
+                    type='float'
+                    size='4'
+                    value='0.0,0.0,0.0,0.0'
+                />
+            </characteristics>
+        </device>
+        <device id='/dev/video4' position='front'>
+            <caps>
+                <!-- list of supported controls -->
+                <supported_controls>
+                    <control name='BRIGHTNESS' min='0' max='255'/>
+                    <control name='CONTRAST' min='0' max='255'/>
+                    <control name='AUTO_WHITE_BALANCE' min='0' max='1'/>
+                    <control name='WHITE_BALANCE_TEMPERATURE' min='2000' max='7500'/>
+                    <control name='SHARPNESS' min='0' max='255'/>
+                    <control name='AUTO_FOCUS' min='0' max='1'/>
+                    <control name='ABSOLUTE_FOCUS' min='0' max='255' step='5'/>
+                    <control name='ABSOLUTE_ZOOM' min='100' max='400'/>
+                </supported_controls>
+
+                <!-- list of supported stream configurations -->
+                <!-- below configurations were taken from v4l2-ctrl query on Logitech Webcam C930e device -->
+                <stream id='0' width='1920' height='1080' format='RGBA_8888' framerate='5'/>
+                <stream id='1' width='2304' height='1296' format='RGBA_8888' framerate='2'/>
+                <stream id='2' width='2304' height='1536' format='RGBA_8888' framerate='2'/>
+                <stream id='4' width='1280' height='720'  format='RGBA_8888' framerate='10'/>
+                <stream id='4' width='1024' height='576'  format='RGBA_8888' framerate='15'/>
+                <stream id='5' width='960'  height='540'  format='RGBA_8888' framerate='15'/>
+                <stream id='6' width='848'  height='480'  format='RGBA_8888' framerate='30'/>
+                <stream id='7' width='640'  height='360'  format='RGBA_8888' framerate='30'/>
+                <stream id='8' width='480'  height='270'  format='RGBA_8888' framerate='30'/>
+                <stream id='9' width='160'  height='120'  format='RGBA_8888' framerate='30'/>
+            </caps>
+
+            <!-- list of parameters -->
+            <characteristics>
+                <!-- Lens distortion information. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_DISTORTION
+                -->
+                <parameter
+                    name='LENS_DISTORTION'
+                    type='float'
+                    size='5'
+                    value='0.0,0.0,0.0,0.0,0.0'
+                />
+
+                <!-- Camera intrinsic calibration matrix. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_INTRINSIC_CALIBRATION
+                -->
+                <parameter
+                    name='LENS_INTRINSIC_CALIBRATION'
+                    type='float'
+                    size='5'
+                    value='0.0,0.0,0.0,0.0,0.0'
+                />
+
+                <!-- Camera pose translation and rotation.  See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_POSE_TRANSLATION
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_POSE_ROTATION
+                -->
+                <parameter
+                    name='LENS_POSE_TRANSLATION'
+                    type='float'
+                    size='3'
+                    value='0.0,0.0,0.0'
+                />
+                <parameter
+                    name='LENS_POSE_ROTATION'
+                    type='float'
+                    size='4'
+                    value='0.0,0.0,0.0,0.0'
+                />
+            </characteristics>
+        </device>
+
+    <!-- camera device information for v4l2loopback devices -->
+        <!-- camera group v4l2loopback_group0 -->
+        <group id='v4l2loopback_group0' synchronized='CALIBRATED'>
+            <caps>
+                <!-- list of stream configuration supported by all physical devices -->
+                <stream id='0' width='1920' height='1024' format='RGBA_8888' framerate='30'/>
+            </caps>
+
+            <!-- list of parameters -->
+            <characteristics>
+                <parameter
+                    name='REQUEST_AVAILABLE_CAPABILITIES'
+                    type='enum'
+                    size='1'
+                    value='LOGICAL_MULTI_CAMERA'
+                />
+                <parameter
+                    name='LOGICAL_MULTI_CAMERA_PHYSICAL_IDS'
+                    type='byte[]'
+                    size='4'
+                    value='/dev/video60,/dev/video61,/dev/video62,/dev/video63'
+                />
+            </characteristics>
+        </group>
+
+        <!-- camera device starts  -->
+        <!-- /dev/video6[0-3]$ were reserved for experimental purposes with v4l2loopback devices -->
+        <!-- The following calibration parameters are for the sample camera images in packages/services/Car/surround_view/service-impl/test_data/ -->
+        <device id='/dev/video60' position='front'>
+            <caps>
+                <!-- list of supported stream configurations -->
+                <stream id='0' width='1920' height='1024' format='RGBA_8888' framerate='30'/>
+            </caps>
+
+            <!-- list of parameters -->
+            <characteristics>
+                <!-- Lens distortion information. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_DISTORTION
+                -->
+                <parameter
+                    name='LENS_DISTORTION'
+                    type='float'
+                    size='5'
+                    value='-0.03711481733589263,-0.0014805627895442888,-0.00030212056866592464,-0.00020149538570397933,0.0'
+                />
+
+                <!-- Camera intrinsic calibration matrix. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_INTRINSIC_CALIBRATION
+                -->
+                <parameter
+                    name='LENS_INTRINSIC_CALIBRATION'
+                    type='float'
+                    size='5'
+                    value='608.0026093794693,608.205469489769,968.699544102168,476.38843298898996,0.0'
+                />
+
+                <!-- Camera pose translation and rotation.  See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_POSE_TRANSLATION
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_POSE_ROTATION
+                -->
+                <parameter
+                    name='LENS_POSE_TRANSLATION'
+                    type='float'
+                    size='3'
+                    value='-7.8028875403817685e-02,1.4537396465103221e+00,-8.4197165554645001e-02'
+                />
+                <parameter
+                    name='LENS_POSE_ROTATION'
+                    type='float'
+                    size='4'
+                    value='0.9049874,0.0153074,-0.0088196,0.4250714'
+                />
+            </characteristics>
+        </device>
+        <device id='/dev/video61' position='right'>
+            <caps>
+                <!-- list of supported stream configurations -->
+                <stream id='0' width='1920' height='1024' format='RGBA_8888' framerate='30'/>
+            </caps>
+
+            <!-- list of parameters -->
+            <characteristics>
+                <!-- Lens distortion information. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_DISTORTION
+                -->
+                <parameter
+                    name='LENS_DISTORTION'
+                    type='float'
+                    size='5'
+                    value='-0.040116809827977926,0.0028769489398543014,-0.002651039958977229,0.00024260630476736675,0.0'
+                />
+
+                <!-- Camera intrinsic calibration matrix. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_INTRINSIC_CALIBRATION
+                -->
+                <parameter
+                    name='LENS_INTRINSIC_CALIBRATION'
+                    type='float'
+                    size='5'
+                    value='607.8691721095306,608.0112887189435,975.5686146375716,481.1938786570715,0.0'
+                />
+
+                <!-- Camera pose translation and rotation.  See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_POSE_TRANSLATION
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_POSE_ROTATION
+                -->
+                <parameter
+                    name='LENS_POSE_TRANSLATION'
+                    type='float'
+                    size='3'
+                    value='2.9715052384687407e-01,1.1407102692699396e+00,3.0074545273489206e-01'
+                />
+                <parameter
+                    name='LENS_POSE_ROTATION'
+                    type='float'
+                    size='4'
+                    value='0.6293863,-0.6544242,0.2967697,0.2958542'
+                />
+            </characteristics>
+        </device>
+        <device id='/dev/video62' position='rear'>
+            <caps>
+                <!-- list of supported stream configurations -->
+                <stream id='0' width='1920' height='1024' format='RGBA_8888' framerate='30'/>
+            </caps>
+
+            <!-- list of parameters -->
+            <characteristics>
+                <!-- Lens distortion information. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_DISTORTION
+                -->
+                <parameter
+                    name='LENS_DISTORTION'
+                    type='float'
+                    size='5'
+                    value='-0.03998488563470043,0.0024786686909103388,-0.002354736769480817,0.00018369619088506146,0.0'
+                />
+
+                <!-- Camera intrinsic calibration matrix. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_INTRINSIC_CALIBRATION
+                -->
+                <parameter
+                    name='LENS_INTRINSIC_CALIBRATION'
+                    type='float'
+                    size='5'
+                    value='608.557299289448,608.8093878512448,960.1949354417656,474.74744054048256,0.0'
+                />
+
+                <!-- Camera pose translation and rotation.  See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_POSE_TRANSLATION
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_POSE_ROTATION
+                -->
+                <parameter
+                    name='LENS_POSE_TRANSLATION'
+                    type='float'
+                    size='3'
+                    value='1.7115269161259747e-01,1.4376160762596599e+00,-1.9028844233159006e-02'
+                />
+                <parameter
+                    name='LENS_POSE_ROTATION'
+                    type='float'
+                    size='4'
+                    value='-0.0341381,-0.9101571,0.4126677,0.0124103'
+                />
+            </characteristics>
+        </device>
+        <device id='/dev/video63' position='left'>
+            <caps>
+                <!-- list of supported stream configurations -->
+                <stream id='0' width='1920' height='1024' format='RGBA_8888' framerate='30'/>
+            </caps>
+
+            <!-- list of parameters -->
+            <characteristics>
+                <!-- Lens distortion information. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_DISTORTION
+                -->
+                <parameter
+                    name='LENS_DISTORTION'
+                    type='float'
+                    size='5'
+                    value='-0.038096507459563965,0.0004008114278766646,-0.0013549275607082035,-5.9961182248325556e-06,0.0'
+                />
+
+                <!-- Camera intrinsic calibration matrix. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_INTRINSIC_CALIBRATION
+                -->
+                <parameter
+                    name='LENS_INTRINSIC_CALIBRATION'
+                    type='float'
+                    size='5'
+                    value='608.1221963545495,608.0523818661524,943.6280444638576,474.8564698210861,0.0'
+                />
+
+                <!-- Camera pose translation and rotation.  See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_POSE_TRANSLATION
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_POSE_ROTATION
+                -->
+                <parameter
+                    name='LENS_POSE_TRANSLATION'
+                    type='float'
+                    size='3'
+                    value='-3.0842691427126512e-01,1.0884122033556984e+00,3.4419058255954926e-01'
+                />
+                <parameter
+                    name='LENS_POSE_ROTATION'
+                    type='float'
+                    size='4'
+                    value='0.612825,0.6634091,-0.3112416,0.2957406'
+                />
+            </characteristics>
+        </device>
+    </camera>
+
+    <!-- display device starts -->
+    <display>
+        <device id='display0' position='driver'>
+            <caps>
+                <!-- list of supported inpu stream configurations -->
+                <stream id='0' width='1280' height='720' format='RGBA_8888' framerate='30'/>
+            </caps>
+        </device>
+    </display>
+</configuration>
+
diff --git a/evs/sampleDriver/service.cpp b/evs/sampleDriver/service.cpp
index d8fb316..d4b7617 100644
--- a/evs/sampleDriver/service.cpp
+++ b/evs/sampleDriver/service.cpp
@@ -32,22 +32,34 @@
 using android::hardware::joinRpcThreadpool;
 
 // Generated HIDL files
-using android::hardware::automotive::evs::V1_0::IEvsEnumerator;
-using android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using android::hardware::automotive::evs::V1_1::IEvsEnumerator;
+using android::hardware::automotive::evs::V1_1::IEvsDisplay;
+using android::frameworks::automotive::display::V1_0::IAutomotiveDisplayProxyService;
 
 // The namespace in which all our implementation code lives
-using namespace android::hardware::automotive::evs::V1_0::implementation;
+using namespace android::hardware::automotive::evs::V1_1::implementation;
 using namespace android;
 
 
 int main() {
-    ALOGI("EVS Hardware Enumerator service is starting");
+    LOG(INFO) << "EVS Hardware Enumerator service is starting";
+
+    android::sp<IAutomotiveDisplayProxyService> carWindowService =
+        IAutomotiveDisplayProxyService::getService("default");
+    if (carWindowService == nullptr) {
+        LOG(ERROR) << "Cannot use AutomotiveDisplayProxyService.  Exiting.";
+        return 1;
+    }
+
+#ifdef EVS_DEBUG
+    SetMinimumLogSeverity(android::base::DEBUG);
+#endif
 
     // Start a thread to listen video device addition events.
     std::atomic<bool> running { true };
     std::thread ueventHandler(EvsEnumerator::EvsUeventThread, std::ref(running));
 
-    android::sp<IEvsEnumerator> service = new EvsEnumerator();
+    android::sp<IEvsEnumerator> service = new EvsEnumerator(carWindowService);
 
     configureRpcThreadpool(1, true /* callerWillJoin */);
 
@@ -55,10 +67,11 @@
     // they will be killed (their thread pool will throw an exception).
     status_t status = service->registerAsService(kEnumeratorServiceName);
     if (status == OK) {
-        ALOGD("%s is ready.", kEnumeratorServiceName);
+        LOG(DEBUG) << kEnumeratorServiceName << " is ready.";
         joinRpcThreadpool();
     } else {
-        ALOGE("Could not register service %s (%d).", kEnumeratorServiceName, status);
+        LOG(ERROR) << "Could not register service " << kEnumeratorServiceName
+                   << " (" << status << ").";
     }
 
     // Exit a uevent handler thread.
@@ -68,6 +81,6 @@
     }
 
     // In normal operation, we don't expect the thread pool to exit
-    ALOGE("EVS Hardware Enumerator is shutting down");
+    LOG(ERROR) << "EVS Hardware Enumerator is shutting down";
     return 1;
 }
diff --git a/evs/sepolicy/evs_driver.te b/evs/sepolicy/evs_driver.te
index f1f31e9..9bb7b97 100644
--- a/evs/sepolicy/evs_driver.te
+++ b/evs/sepolicy/evs_driver.te
@@ -1,10 +1,10 @@
 # evs_mock mock hardware driver service
-type hal_evs_driver, domain, coredomain;
+type hal_evs_driver, domain;
 hal_server_domain(hal_evs_driver, hal_evs)
 hal_client_domain(hal_evs_driver, hal_evs)
 
 # allow init to launch processes in this context
-type hal_evs_driver_exec, exec_type, file_type, system_file_type;
+type hal_evs_driver_exec, exec_type, file_type, vendor_file_type;
 init_daemon_domain(hal_evs_driver)
 binder_use(hal_evs_driver)
 
@@ -22,3 +22,8 @@
 
 # Allow the driver to access kobject uevents
 allow hal_evs_driver self:netlink_kobject_uevent_socket create_socket_perms_no_ioctl;
+
+# Allow the driver to use automotive display proxy service
+allow hal_evs_driver automotive_display_service_server:binder call;
+allow hal_evs_driver fwk_automotive_display_hwservice:hwservice_manager find;
+
diff --git a/evs/sepolicy/evs_manager.te b/evs/sepolicy/evs_manager.te
index 51acac1..cf649bb 100644
--- a/evs/sepolicy/evs_manager.te
+++ b/evs/sepolicy/evs_manager.te
@@ -9,3 +9,10 @@
 
 # allow use of hwservices
 allow evs_manager hal_graphics_allocator_default:fd use;
+
+# allow write to fd
+allow evs_manager shell:fd use;
+allow evs_manager shell:fifo_file write;
+
+# allow evs_manager to send information to statsd socket
+unix_socket_send(evs_manager, statsdw, statsd)
diff --git a/evs/sepolicy/file_contexts b/evs/sepolicy/file_contexts
index 0358e16..7b8ec19 100644
--- a/evs/sepolicy/file_contexts
+++ b/evs/sepolicy/file_contexts
@@ -3,9 +3,10 @@
 # Binaries associated with the default EVS stack, plus
 # the directory which contains the configuration for the evs_app
 #
-/system/bin/android\.hardware\.automotive\.evs@1\.0-sample   u:object_r:hal_evs_driver_exec:s0
-/system/bin/android\.automotive\.evs\.manager@1\.0           u:object_r:evs_manager_exec:s0
-/system/bin/evs_app                                          u:object_r:evs_app_exec:s0
-/system/etc/automotive/evs(/.*)?                             u:object_r:evs_app_files:s0
+/system/bin/android\.automotive\.evs\.manager@1\.[0-9]+         u:object_r:evs_manager_exec:s0
+/system/bin/evs_app                                             u:object_r:evs_app_exec:s0
+/system/bin/evs_app_support_lib                                 u:object_r:evs_app_exec:s0
+/system/etc/automotive/evs(/.*)?                                u:object_r:evs_app_files:s0
+/vendor/bin/android\.hardware\.automotive\.evs@1\.[0-9]+-sample u:object_r:hal_evs_driver_exec:s0
 
 ###################################
diff --git a/evs/sepolicy/servicemanager.te b/evs/sepolicy/servicemanager.te
new file mode 100644
index 0000000..006e3e3
--- /dev/null
+++ b/evs/sepolicy/servicemanager.te
@@ -0,0 +1,3 @@
+allow servicemanager evs_app:dir search;
+allow servicemanager evs_app:file r_file_perms;
+allow servicemanager evs_app:process getattr;
diff --git a/evs/support_library/AnalyzeUseCase.cpp b/evs/support_library/AnalyzeUseCase.cpp
new file mode 100644
index 0000000..d79f93e
--- /dev/null
+++ b/evs/support_library/AnalyzeUseCase.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <utils/SystemClock.h>
+
+#include "AnalyzeUseCase.h"
+#include "ConfigManager.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+AnalyzeUseCase::AnalyzeUseCase(string cameraId, BaseAnalyzeCallback* callback)
+              : BaseUseCase(vector<string>(1, cameraId)),
+                mAnalyzeCallback(callback) {}
+
+AnalyzeUseCase::~AnalyzeUseCase() {}
+
+bool AnalyzeUseCase::initialize() {
+    // TODO(b/130246434): Move the following ConfigManager and thread pool
+    // logic into ResourceManager, for both display and analyze use case.
+
+    ConfigManager config;
+    if (!config.initialize("/system/etc/automotive/evs_support_lib/camera_config.json")) {
+        ALOGE("Missing or improper configuration for the EVS application.  Exiting.");
+        return false;
+    }
+
+    // Set thread pool size to one to avoid concurrent events from the HAL.
+    // This pool will handle the EvsCameraStream callbacks.
+    // Note:  This _will_ run in parallel with the EvsListener run() loop below which
+    // runs the application logic that reacts to the async events.
+    configureRpcThreadpool(1, false /* callerWillJoin */);
+
+    mResourceManager = ResourceManager::getInstance();
+
+    ALOGD("Requesting camera list");
+    for (auto&& info : config.getCameras()) {
+        // This use case is currently a single camera use case.
+        // Only one element is available in the camera id list.
+        string cameraId = mCameraIds[0];
+        if (cameraId == info.cameraId) {
+            mStreamHandler =
+                mResourceManager->obtainStreamHandler(cameraId);
+            if (mStreamHandler.get() == nullptr) {
+                ALOGE("Failed to get a valid StreamHandler for %s",
+                      cameraId.c_str());
+                return false;
+            }
+
+            mIsInitialized = true;
+            return true;
+        }
+    }
+
+    ALOGE("Cannot find a match camera. Exiting");
+    return false;
+}
+
+bool AnalyzeUseCase::startVideoStream() {
+    ALOGD("AnalyzeUseCase::startVideoStream");
+
+    // Initialize the use case.
+    if (!mIsInitialized && !initialize()) {
+        ALOGE("There is an error while initializing the use case. Exiting");
+        return false;
+    }
+
+    ALOGD("Attach callback to StreamHandler");
+    if (mAnalyzeCallback != nullptr) {
+        mStreamHandler->attachAnalyzeCallback(mAnalyzeCallback);
+    }
+
+    mStreamHandler->startStream();
+
+    return true;
+}
+
+void AnalyzeUseCase::stopVideoStream() {
+    ALOGD("AnalyzeUseCase::stopVideoStream");
+
+    if (mStreamHandler == nullptr) {
+        ALOGE("Failed to detach render callback since stream handler is null");
+
+        // Something may go wrong. Instead of to return this method right away,
+        // we want to finish the remaining logic of this method to try to
+        // release other resources.
+    } else {
+        mStreamHandler->detachAnalyzeCallback();
+    }
+
+    if (mResourceManager == nullptr) {
+        ALOGE("Failed to release resources since resource manager is null");
+    } else {
+        mResourceManager->releaseStreamHandler(mCameraIds[0]);
+    }
+
+    mStreamHandler = nullptr;
+
+    // TODO(b/130246434): with the current logic, the initialize method will
+    // be triggered every time when a pair of
+    // stopVideoStream/startVideoStream is called. We might want to move
+    // some heavy work away from initialize method so increase the
+    // performance.
+
+    // Sets mIsInitialzed to false so the initialize method will be
+    // triggered when startVideoStream is called again.
+    mIsInitialized = false;
+}
+
+// TODO(b/130246434): For both Analyze use case and Display use case, return a
+// pointer instead of an object.
+AnalyzeUseCase AnalyzeUseCase::createDefaultUseCase(
+    string cameraId, BaseAnalyzeCallback* callback) {
+    return AnalyzeUseCase(cameraId, callback);
+}
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
diff --git a/evs/support_library/AnalyzeUseCase.h b/evs/support_library/AnalyzeUseCase.h
new file mode 100644
index 0000000..837aaf1
--- /dev/null
+++ b/evs/support_library/AnalyzeUseCase.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef CAR_LIB_EVS_SUPPORT_ANALYZE_USECASE_H
+#define CAR_LIB_EVS_SUPPORT_ANALYZE_USECASE_H
+
+#include <thread>
+
+#include "BaseUseCase.h"
+#include "StreamHandler.h"
+#include "BaseAnalyzeCallback.h"
+#include "ResourceManager.h"
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::std::string;
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+class AnalyzeUseCase : public BaseUseCase {
+public:
+    AnalyzeUseCase(string cameraId, BaseAnalyzeCallback* analyzeCallback);
+    virtual ~AnalyzeUseCase();
+    virtual bool startVideoStream() override;
+    virtual void stopVideoStream() override;
+
+    static AnalyzeUseCase createDefaultUseCase(string cameraId,
+                                               BaseAnalyzeCallback* cb = nullptr);
+
+private:
+    bool initialize();
+
+    bool mIsInitialized = false;
+    BaseAnalyzeCallback* mAnalyzeCallback = nullptr;
+
+    sp<StreamHandler>           mStreamHandler;
+    sp<ResourceManager>         mResourceManager;
+};
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
+#endif // CAR_LIB_EVS_SUPPORT_ANALYZE_USECASE_H
diff --git a/evs/support_library/Android.bp b/evs/support_library/Android.bp
new file mode 100644
index 0000000..8b77a5d
--- /dev/null
+++ b/evs/support_library/Android.bp
@@ -0,0 +1,76 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+
+//#################################
+cc_library_shared {
+    name: "libevssupport",
+
+    srcs: [
+        "RenderBase.cpp",
+        "RenderDirectView.cpp",
+        "ConfigManager.cpp",
+        "glError.cpp",
+        "shader.cpp",
+        "TexWrapper.cpp",
+        "VideoTex.cpp",
+        "StreamHandler.cpp",
+        "ResourceManager.cpp",
+        "FormatConvert.cpp",
+        "DisplayUseCase.cpp",
+        "AnalyzeUseCase.cpp",
+        "Utils.cpp",
+    ],
+
+    shared_libs: [
+        "libcutils",
+        "liblog",
+        "libutils",
+        "libui",
+        "libhidlbase",
+        "libEGL",
+        "libGLESv2",
+        "libhardware",
+        "libpng",
+        "android.hardware.automotive.evs@1.0",
+    ],
+
+    static_libs: [
+        "libmath",
+        "libjsoncpp",
+    ],
+
+    required: [
+        "camera_config.json",
+    ],
+
+    cflags: ["-DLOG_TAG=\"libevssupport\""] + [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+    ] + [
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+}
+
+prebuilt_etc {
+    name: "camera_config.json",
+
+    src: "config.json",
+    sub_dir: "automotive/evs_support_lib",
+}
+
diff --git a/evs/support_library/BaseAnalyzeCallback.h b/evs/support_library/BaseAnalyzeCallback.h
new file mode 100644
index 0000000..e67c791
--- /dev/null
+++ b/evs/support_library/BaseAnalyzeCallback.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CAR_LIB_EVS_SUPPORT_BASE_ANALYZE_CALLBACK_H
+#define CAR_LIB_EVS_SUPPORT_BASE_ANALYZE_CALLBACK_H
+
+#include "Frame.h"
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+class BaseAnalyzeCallback{
+    public:
+        virtual void analyze(const Frame&) = 0;
+        virtual ~BaseAnalyzeCallback() {};
+};
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
+#endif // CAR_LIB_EVS_SUPPORT_BASE_ANALYZE_CALLBACK_H
diff --git a/evs/support_library/BaseRenderCallback.h b/evs/support_library/BaseRenderCallback.h
new file mode 100644
index 0000000..cdcf6a4
--- /dev/null
+++ b/evs/support_library/BaseRenderCallback.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef EVS_SUPPORT_LIBRARY_BASERENDERCALLBACK_H_
+#define EVS_SUPPORT_LIBRARY_BASERENDERCALLBACK_H_
+
+#include "Frame.h"
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+class BaseRenderCallback {
+  public:
+    // TODO(b/130246434): Rename the callback to a more accurate name since
+    // the callback itself is about image inline processing. Also avoid
+    // passing in two frames, since the two frames are almost identical except
+    // for the data pointer. Instead, pass in one input frame and one output
+    // data pointer.
+    virtual void render(const Frame& in, const Frame& out) = 0;
+    virtual ~BaseRenderCallback() {
+    }
+};
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
+#endif  // EVS_SUPPORT_LIBRARY_BASERENDERCALLBACK_H_
diff --git a/evs/support_library/BaseUseCase.h b/evs/support_library/BaseUseCase.h
new file mode 100644
index 0000000..a76174d
--- /dev/null
+++ b/evs/support_library/BaseUseCase.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef EVS_SUPPORT_LIBRARY_BASEUSECASE_H_
+#define EVS_SUPPORT_LIBRARY_BASEUSECASE_H_
+
+#include <string>
+#include <vector>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+using ::std::string;
+using ::std::vector;
+
+/**
+ * Base class for all the use cases in the EVS support library.
+ */
+class BaseUseCase {
+public:
+    /**
+     * Requests delivery of camera frames from the desired EVS camera(s). The
+     * use case begins receiving periodic calls from EVS camera with new image
+     * frames until stopVideoStream is called.
+     *
+     * If the same EVS camera has already been started by other use cases,
+     * the frame delivery to this use case starts without affecting the status
+     * of the EVS camera.
+     *
+     * @return Returns true if the video stream is started successfully.
+     * Otherwise returns false.
+     *
+     * @see stopVideoStream()
+     */
+    virtual bool startVideoStream() = 0;
+
+    /**
+     * Stops the delivery of EVS camera frames, and tries to close the EVS
+     * camera. Because delivery is asynchronous, frames may continue to
+     * arrive for some time after this call returns.
+     *
+     * If other use cases are using the camera at the same time, the EVS
+     * camera will not be closed, until all the other use cases using the
+     * camera are stopped.
+     *
+     * @see startVideoStream()
+     */
+    virtual void stopVideoStream() = 0;
+
+    /**
+     * Default constructor for BaseUseCase.
+     *
+     * @param The ids for the desired EVS cameras.
+     */
+    BaseUseCase(vector<string> cameraIds) : mCameraIds(cameraIds) {};
+
+    virtual ~BaseUseCase() {}
+
+protected:
+    vector<string> mCameraIds;
+};
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
+#endif  // EVS_SUPPORT_LIBRARY_BASEUSECASE_H_
diff --git a/evs/support_library/ConfigManager.cpp b/evs/support_library/ConfigManager.cpp
new file mode 100644
index 0000000..f686526
--- /dev/null
+++ b/evs/support_library/ConfigManager.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "ConfigManager.h"
+
+#include "json/json.h"
+
+#include <fstream>
+#include <math.h>
+#include <assert.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+static const float kDegreesToRadians = M_PI / 180.0f;
+
+
+static float normalizeToPlusMinus180degrees(float theta) {
+    const float wraps = floor((theta+180.0f) / 360.0f);
+    return theta - wraps*360.0f;
+}
+
+
+static bool readChildNodeAsFloat(const char* groupName,
+                                 const Json::Value& parentNode,
+                                 const char* childName,
+                                 float* value) {
+    // Must have a place to put the value!
+    assert(value);
+
+    Json::Value childNode = parentNode[childName];
+    if (!childNode.isNumeric()) {
+        printf("Missing or invalid field %s in record %s", childName, groupName);
+        return false;
+    }
+
+    *value = childNode.asFloat();
+    return true;
+}
+
+
+bool ConfigManager::initialize(const char* configFileName)
+{
+    bool complete = true;
+
+    // Set up a stream to read in the input file
+    std::ifstream configStream(configFileName);
+
+    // Parse the stream into JSON objects
+    Json::Reader reader;
+    Json::Value rootNode;
+    bool parseOk = reader.parse(configStream, rootNode, false /* don't need comments */);
+    if (!parseOk) {
+        printf("Failed to read configuration file %s\n", configFileName);
+        printf("%s\n", reader.getFormatedErrorMessages().c_str());
+        return false;
+    }
+
+
+    //
+    // Read car information
+    //
+    {
+        Json::Value car = rootNode["car"];
+        if (!car.isObject()) {
+            printf("Invalid configuration format -- we expect a car description\n");
+            return false;
+        }
+        complete &= readChildNodeAsFloat("car", car, "width",       &mCarWidth);
+        complete &= readChildNodeAsFloat("car", car, "wheelBase",   &mWheelBase);
+        complete &= readChildNodeAsFloat("car", car, "frontExtent", &mFrontExtent);
+        complete &= readChildNodeAsFloat("car", car, "rearExtent",  &mRearExtent);
+    }
+
+
+    //
+    // Read display layout information
+    //
+    {
+        Json::Value displayNode = rootNode["display"];
+        if (!displayNode.isObject()) {
+            printf("Invalid configuration format -- we expect a display description\n");
+            return false;
+        }
+        complete &= readChildNodeAsFloat("display", displayNode, "frontRange", &mFrontRangeInCarSpace);
+        complete &= readChildNodeAsFloat("display", displayNode, "rearRange",  &mRearRangeInCarSpace);
+    }
+
+
+    //
+    // Car top view texture properties for top down view
+    //
+    {
+        Json::Value graphicNode = rootNode["graphic"];
+        if (!graphicNode.isObject()) {
+            printf("Invalid configuration format -- we expect a graphic description\n");
+            return false;
+        }
+        complete &= readChildNodeAsFloat("graphic", graphicNode, "frontPixel", &mCarGraphicFrontPixel);
+        complete &= readChildNodeAsFloat("display", graphicNode, "rearPixel",  &mCarGraphicRearPixel);
+    }
+
+
+    //
+    // Read camera information
+    // NOTE:  Missing positions and angles are not reported, but instead default to zero
+    //
+    {
+        Json::Value cameraArray = rootNode["cameras"];
+        if (!cameraArray.isArray()) {
+            printf("Invalid configuration format -- we expect an array of cameras\n");
+            return false;
+        }
+
+        mCameras.reserve(cameraArray.size());
+        for (auto&& node: cameraArray) {
+            // Get data from the configuration file
+            Json::Value nameNode = node.get("cameraId", "MISSING");
+            const char *cameraId = nameNode.asCString();
+
+            Json::Value usageNode = node.get("function", "");
+            const char *function = usageNode.asCString();
+
+            float yaw   = node.get("yaw", 0).asFloat();
+            float pitch = node.get("pitch", 0).asFloat();
+            float hfov  = node.get("hfov", 0).asFloat();
+            float vfov  = node.get("vfov", 0).asFloat();
+
+            // Wrap the direction angles to be in the 180deg to -180deg range
+            // Rotate 180 in yaw if necessary to flip the pitch into the +/-90degree range
+            pitch = normalizeToPlusMinus180degrees(pitch);
+            if (pitch > 90.0f) {
+                yaw += 180.0f;
+                pitch = 180.0f - pitch;
+            }
+            if (pitch < -90.0f) {
+                yaw += 180.0f;
+                pitch = -180.0f + pitch;
+            }
+            yaw = normalizeToPlusMinus180degrees(yaw);
+
+            // Range check the FOV values to ensure they are positive and less than 180degrees
+            if (hfov > 179.0f) {
+                printf("Pathological horizontal field of view %f clamped to 179 degrees\n", hfov);
+                hfov = 179.0f;
+            }
+            if (hfov < 1.0f) {
+                printf("Pathological horizontal field of view %f clamped to 1 degree\n", hfov);
+                hfov = 1.0f;
+            }
+            if (vfov > 179.0f) {
+                printf("Pathological horizontal field of view %f clamped to 179 degrees\n", vfov);
+                vfov = 179.0f;
+            }
+            if (vfov < 1.0f) {
+                printf("Pathological horizontal field of view %f clamped to 1 degree\n", vfov);
+                vfov = 1.0f;
+            }
+
+            // Store the camera info (converting degrees to radians in the process)
+            CameraInfo info;
+            info.position[0] = node.get("x", 0).asFloat();
+            info.position[1] = node.get("y", 0).asFloat();
+            info.position[2] = node.get("z", 0).asFloat();
+            info.yaw         = yaw   * kDegreesToRadians;
+            info.pitch       = pitch * kDegreesToRadians;
+            info.hfov        = hfov  * kDegreesToRadians;
+            info.vfov        = vfov  * kDegreesToRadians;
+            info.cameraId    = cameraId;
+            info.function    = function;
+
+            mCameras.push_back(info);
+        }
+    }
+
+    // If we got this far, we were successful as long as we found all our child fields
+    return complete;
+}
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/evs/support_library/ConfigManager.h b/evs/support_library/ConfigManager.h
new file mode 100644
index 0000000..6777938
--- /dev/null
+++ b/evs/support_library/ConfigManager.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef CONFIG_MANAGER_H
+#define CONFIG_MANAGER_H
+
+#include <vector>
+#include <string>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+class ConfigManager {
+public:
+    struct CameraInfo {
+        std::string cameraId = "";  // The name of the camera from the point of view of the HAL
+        std::string function = "";  // The expected use for this camera ("reverse", "left", "right")
+        float position[3] = {0};    // x, y, z -> right, fwd, up in the units of car space
+        float yaw   = 0;    // radians positive to the left (right hand rule about global z axis)
+        float pitch = 0;    // positive upward (ie: right hand rule about local x axis)
+        float hfov  = 0;    // radians
+        float vfov  = 0;    // radians
+    };
+
+    bool initialize(const char* configFileName);
+
+    // World space dimensions of the car
+    float getCarWidth() const   { return mCarWidth; };
+    float getCarLength() const  { return mWheelBase + mFrontExtent + mRearExtent; };
+    float getWheelBase() const  { return mWheelBase; };
+
+    // Car space (world space centered on the rear axel) edges of the car
+    float getFrontLocation() const  { return mWheelBase + mFrontExtent; };
+    float getRearLocation() const   { return -mRearExtent; };
+    float getRightLocation() const  { return mCarWidth*0.5f; };
+    float getLeftLocation() const   { return -mCarWidth*0.5f; };
+
+    // Where are the edges of the top down display in car space?
+    float getDisplayTopLocation() const {
+        // From the rear axel (origin) to the front bumper, and then beyond by the front range
+        return mWheelBase + mFrontExtent + mFrontRangeInCarSpace;
+    };
+    float getDisplayBottomLocation() const {
+        // From the rear axel (origin) to the back bumper, and then beyond by the back range
+        return -mRearExtent - mRearRangeInCarSpace;
+    };
+    float getDisplayRightLocation(float aspectRatio) const   {
+        // Given the display aspect ratio (width over height), how far can we see to the right?
+        return (getDisplayTopLocation() - getDisplayBottomLocation()) * 0.5f * aspectRatio;
+    };
+    float getDisplayLeftLocation(float aspectRatio) const {
+        // Given the display aspect ratio (width over height), how far can we see to the left?
+        return -getDisplayRightLocation(aspectRatio);
+    };
+
+    // At which texel (vertically in the image) are the front and rear bumpers of the car?
+    float carGraphicFrontPixel() const      { return mCarGraphicFrontPixel; };
+    float carGraphicRearPixel() const       { return mCarGraphicRearPixel; };
+
+    const std::vector<CameraInfo>& getCameras() const   { return mCameras; };
+
+private:
+    // Camera information
+    std::vector<CameraInfo> mCameras;
+
+    // Car body information (assumes front wheel steering and origin at center of rear axel)
+    // Note that units aren't specified and don't matter as long as all length units are consistent
+    // within the JSON file from which we parse.  That is, if everything is in meters, that's fine.
+    // Everything in mm?  That's fine too.
+    float mCarWidth;
+    float mWheelBase;
+    float mFrontExtent;
+    float mRearExtent;
+
+    // Display information
+    float    mFrontRangeInCarSpace;     // How far the display extends in front of the car
+    float    mRearRangeInCarSpace;      // How far the display extends behind the car
+
+    // Top view car image information
+    float mCarGraphicFrontPixel;    // How many pixels from the top of the image does the car start
+    float mCarGraphicRearPixel;     // How many pixels from the top of the image does the car end
+};
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
+#endif  // CONFIG_MANAGER_H
diff --git a/evs/support_library/DisplayUseCase.cpp b/evs/support_library/DisplayUseCase.cpp
new file mode 100644
index 0000000..cf50387
--- /dev/null
+++ b/evs/support_library/DisplayUseCase.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <utils/SystemClock.h>
+
+#include "DisplayUseCase.h"
+#include "RenderDirectView.h"
+#include "Utils.h"
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// TODO(b/130246434): since we don't support multi-display use case, there
+// should only be one DisplayUseCase. Add the logic to prevent more than
+// one DisplayUseCases running at the same time.
+DisplayUseCase::DisplayUseCase(string cameraId, BaseRenderCallback* callback)
+              : BaseUseCase(vector<string>(1, cameraId)) {
+    mRenderCallback = callback;
+}
+
+DisplayUseCase::~DisplayUseCase() {
+    if (mCurrentRenderer != nullptr) {
+        mCurrentRenderer->deactivate();
+        mCurrentRenderer = nullptr;  // It's a smart pointer, so destructs on assignment to null
+    }
+
+    mIsReadyToRun = false;
+    if (mWorkerThread.joinable()) {
+        mWorkerThread.join();
+    }
+}
+
+bool DisplayUseCase::initialize() {
+    // Load our configuration information
+    ConfigManager config;
+    if (!config.initialize("/system/etc/automotive/evs_support_lib/camera_config.json")) {
+        ALOGE("Missing or improper configuration for the EVS application.  Exiting.");
+        return false;
+    }
+
+    // Set thread pool size to one to avoid concurrent events from the HAL.
+    // This pool will handle the EvsCameraStream callbacks.
+    // Note:  This _will_ run in parallel with the EvsListener run() loop below which
+    // runs the application logic that reacts to the async events.
+    configureRpcThreadpool(1, false /* callerWillJoin */);
+
+    mResourceManager = ResourceManager::getInstance();
+    if (mResourceManager == nullptr) {
+        ALOGE("Failed to get resource manager instance. Initialization failed.");
+        return false;
+    }
+
+    // Request exclusive access to the EVS display
+    ALOGI("Acquiring EVS Display");
+
+    mDisplay = mResourceManager->openDisplay();
+    if (mDisplay.get() == nullptr) {
+        ALOGE("EVS Display unavailable.  Exiting.");
+        return false;
+    }
+
+    ALOGD("Requesting camera list");
+    for (auto&& info : config.getCameras()) {
+        // This use case is currently a single camera use case.
+        // Only one element is available in the camera id list.
+        string cameraId = mCameraIds[0];
+        if (cameraId == info.cameraId) {
+            mStreamHandler = mResourceManager->obtainStreamHandler(cameraId);
+            if (mStreamHandler.get() == nullptr) {
+                ALOGE("Failed to get a valid StreamHandler for %s",
+                      cameraId.c_str());
+                return false;
+            }
+
+            mIsInitialized = true;
+            return true;
+        }
+    }
+
+    ALOGE("Cannot find a match camera. Exiting");
+    return false;
+}
+
+// TODO(b/130246434): if user accidentally call this function twice, there is
+// no logic to handle that and it will causes issues. For example, the
+// mWorkerThread will be assigned twice and cause unexpected behavior.
+// We need to fix this issue.
+bool DisplayUseCase::startVideoStream() {
+    // Initialize the use case.
+    if (!mIsInitialized && !initialize()) {
+        ALOGE("There is an error while initializing the use case. Exiting");
+        return false;
+    }
+
+    ALOGD("Attach use case to StreamHandler");
+    if (mRenderCallback != nullptr) {
+        mStreamHandler->attachRenderCallback(mRenderCallback);
+    }
+
+    ALOGD("Start video streaming using worker thread");
+    mIsReadyToRun = true;
+    mWorkerThread = std::thread([this]() {
+        // We have a camera assigned to this state for direct view
+        mCurrentRenderer = std::make_unique<RenderDirectView>();
+        if (!mCurrentRenderer) {
+            ALOGE("Failed to construct direct renderer. Exiting.");
+            mIsReadyToRun = false;
+            return;
+        }
+
+        // Now set the display state based on whether we have a video feed to show
+        // Start the camera stream
+        ALOGD("EvsStartCameraStreamTiming start time: %" PRId64 "ms", android::elapsedRealtime());
+        if (!mCurrentRenderer->activate()) {
+            ALOGE("New renderer failed to activate. Exiting");
+            mIsReadyToRun = false;
+            return;
+        }
+
+        // Activate the display
+        ALOGD("EvsActivateDisplayTiming start time: %" PRId64 "ms", android::elapsedRealtime());
+        Return<EvsResult> result = mDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME);
+        if (result != EvsResult::OK) {
+            ALOGE("setDisplayState returned an error (%d). Exiting.", (EvsResult)result);
+            mIsReadyToRun = false;
+            return;
+        }
+
+        if (!mStreamHandler->startStream()) {
+            ALOGE("failed to start stream handler");
+            mIsReadyToRun = false;
+            return;
+        }
+
+        while (mIsReadyToRun && streamFrame());
+
+        ALOGD("Worker thread stops.");
+    });
+
+    return true;
+}
+
+void DisplayUseCase::stopVideoStream() {
+    ALOGD("Stop video streaming in worker thread.");
+    mIsReadyToRun = false;
+
+    if (mStreamHandler == nullptr) {
+        ALOGE("Failed to detach render callback since stream handler is null");
+
+        // Something may go wrong. Instead of to return this method right away,
+        // we want to finish the remaining logic of this method to try to
+        // release other resources.
+    } else {
+        mStreamHandler->detachRenderCallback();
+    }
+
+    if (mResourceManager == nullptr) {
+        ALOGE("Failed to release resources since resource manager is null");
+    } else {
+        mResourceManager->releaseStreamHandler(mCameraIds[0]);
+        mStreamHandler = nullptr;
+
+        mResourceManager->closeDisplay(mDisplay);
+        mDisplay = nullptr;
+
+        // TODO(b/130246434): with the current logic, the initialize method will
+        // be triggered every time when a pair of
+        // stopVideoStream/startVideoStream is called. We might want to move
+        // some heavy work away from initialize method so increase the
+        // performance.
+
+        // Sets mIsInitialzed to false so the initialize method will be
+        // triggered when startVideoStream is called again.
+        mIsInitialized = false;
+    }
+    return;
+}
+
+bool DisplayUseCase::streamFrame() {
+    // Get the output buffer we'll use to display the imagery
+    BufferDesc tgtBuffer = {};
+    mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc& buff) { tgtBuffer = buff; });
+
+    // TODO(b/130246434): if there is no new display frame available, shall we
+    // still get display buffer? Shall we just skip and keep the display
+    // un-refreshed?
+    // We should explore this option.
+
+    // If there is no display buffer available, skip it.
+    if (tgtBuffer.memHandle == nullptr) {
+        ALOGW("Didn't get requested output buffer -- skipping this frame.");
+
+        // Return true since it won't affect next call.
+        return true;
+    } else {
+        // If there is no new display frame available, re-use the old (held)
+        // frame for display.
+        // Otherwise, return the old (held) frame, fetch the newly available
+        // frame from stream handler, and use the new frame for display
+        // purposes.
+        if (!mStreamHandler->newDisplayFrameAvailable()) {
+            ALOGD("No new display frame is available. Re-use the old frame.");
+        } else {
+            ALOGD("Get new display frame, refreshing");
+
+            // If we already hold a camera image for display purposes, it's
+            // time to return it to evs camera driver.
+            if (mImageBuffer.memHandle.getNativeHandle() != nullptr) {
+                mStreamHandler->doneWithFrame(mImageBuffer);
+            }
+
+            // Get the new image we want to use as our display content
+            mImageBuffer = mStreamHandler->getNewDisplayFrame();
+        }
+
+        // Render the image buffer to the display buffer
+        bool result = mCurrentRenderer->drawFrame(tgtBuffer, mImageBuffer);
+
+        // Send the finished display buffer back to display driver
+        // Even if the rendering fails, we still want to return the display
+        // buffer.
+        mDisplay->returnTargetBufferForDisplay(tgtBuffer);
+
+        return result;
+    }
+}
+
+DisplayUseCase DisplayUseCase::createDefaultUseCase(string cameraId, BaseRenderCallback* callback) {
+    return DisplayUseCase(cameraId, callback);
+}
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/evs/support_library/DisplayUseCase.h b/evs/support_library/DisplayUseCase.h
new file mode 100644
index 0000000..0eeac64
--- /dev/null
+++ b/evs/support_library/DisplayUseCase.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef CAR_LIB_EVS_SUPPORT_DISPLAY_USECASE_H
+#define CAR_LIB_EVS_SUPPORT_DISPLAY_USECASE_H
+
+#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+
+#include <string>
+#include <thread>
+
+#include "BaseRenderCallback.h"
+#include "BaseUseCase.h"
+#include "ConfigManager.h"
+#include "RenderBase.h"
+#include "StreamHandler.h"
+#include "ResourceManager.h"
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+using namespace ::android::hardware::automotive::evs::V1_0;
+using ::android::sp;
+using ::android::hardware::Return;
+using ::std::string;
+
+// TODO(b/130246434): Think about multi-camera situation.
+class DisplayUseCase : public BaseUseCase {
+  public:
+    ~DisplayUseCase();
+    bool startVideoStream() override;
+    void stopVideoStream() override;
+
+    // TODO(b/130246434): Add configuration class to create more use case.
+    static DisplayUseCase createDefaultUseCase(string cameraId,
+                                               BaseRenderCallback* cb = nullptr);
+
+  private:
+    DisplayUseCase(string cameraId, BaseRenderCallback* renderCallback);
+
+    // TODO(b/130246434): Think about whether we should make init public so
+    // users can call it.
+    bool initialize();
+    bool streamFrame();
+
+    bool mIsInitialized = false;
+    BaseRenderCallback* mRenderCallback = nullptr;
+    std::unique_ptr<RenderBase> mCurrentRenderer;
+
+    sp<IEvsDisplay> mDisplay;
+    sp<StreamHandler> mStreamHandler;
+    sp<ResourceManager> mResourceManager;
+    bool mIsReadyToRun;
+    std::thread mWorkerThread;
+    BufferDesc mImageBuffer;
+};
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
+#endif  // CAR_LIB_EVS_SUPPORT_DISPLAY_USECASE_H
diff --git a/evs/support_library/FormatConvert.cpp b/evs/support_library/FormatConvert.cpp
new file mode 100644
index 0000000..f823179
--- /dev/null
+++ b/evs/support_library/FormatConvert.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "FormatConvert.h"
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+// Round up to the nearest multiple of the given alignment value
+template<unsigned alignment>
+int align(int value) {
+    static_assert((alignment && !(alignment & (alignment - 1))),
+                  "alignment must be a power of 2");
+
+    unsigned mask = alignment - 1;
+    return (value + mask) & ~mask;
+}
+
+
+// Limit the given value to the provided range.  :)
+static inline float clamp(float v, float min, float max) {
+    if (v < min) return min;
+    if (v > max) return max;
+    return v;
+}
+
+
+static uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const unsigned char Vin) {
+    // Don't use this if you want to see the best performance.  :)
+    // Better to do this in a pixel shader if we really have to, but on actual
+    // embedded hardware we expect to be able to texture directly from the YUV data
+    float U = Uin - 128.0f;
+    float V = Vin - 128.0f;
+
+    float Rf = Y + 1.140f*V;
+    float Gf = Y - 0.395f*U - 0.581f*V;
+    float Bf = Y + 2.032f*U;
+    unsigned char R = (unsigned char)clamp(Rf, 0.0f, 255.0f);
+    unsigned char G = (unsigned char)clamp(Gf, 0.0f, 255.0f);
+    unsigned char B = (unsigned char)clamp(Bf, 0.0f, 255.0f);
+
+    return (R      ) |
+           (G <<  8) |
+           (B << 16) |
+           0xFF000000;  // Fill the alpha channel with ones
+}
+
+
+void copyNV21toRGB32(unsigned width, unsigned height,
+                     uint8_t* src,
+                     uint32_t* dst, unsigned dstStridePixels)
+{
+    // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
+    // U/V array.  It assumes an even width and height for the overall image, and a horizontal
+    // stride that is an even multiple of 16 bytes for both the Y and UV arrays.
+    unsigned strideLum = align<16>(width);
+    unsigned sizeY = strideLum * height;
+    unsigned strideColor = strideLum;   // 1/2 the samples, but two interleaved channels
+    unsigned offsetUV = sizeY;
+
+    uint8_t* srcY = src;
+    uint8_t* srcUV = src+offsetUV;
+
+    for (unsigned r = 0; r < height; r++) {
+        // Note that we're walking the same UV row twice for even/odd luminance rows
+        uint8_t* rowY  = srcY  + r*strideLum;
+        uint8_t* rowUV = srcUV + (r/2 * strideColor);
+
+        uint32_t* rowDest = dst + r*dstStridePixels;
+
+        for (unsigned c = 0; c < width; c++) {
+            unsigned uCol = (c & ~1);   // uCol is always even and repeats 1:2 with Y values
+            unsigned vCol = uCol | 1;   // vCol is always odd
+            rowDest[c] = yuvToRgbx(rowY[c], rowUV[uCol], rowUV[vCol]);
+        }
+    }
+}
+
+
+void copyYV12toRGB32(unsigned width, unsigned height,
+                     uint8_t* src,
+                     uint32_t* dst, unsigned dstStridePixels)
+{
+    // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
+    // by another 1/2 x 1/2 V array.  It assumes an even width and height for the overall image,
+    // and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
+    // and V arrays.
+    unsigned strideLum = align<16>(width);
+    unsigned sizeY = strideLum * height;
+    unsigned strideColor = align<16>(strideLum/2);
+    unsigned sizeColor = strideColor * height/2;
+    unsigned offsetU = sizeY;
+    unsigned offsetV = sizeY + sizeColor;
+
+    uint8_t* srcY = src;
+    uint8_t* srcU = src+offsetU;
+    uint8_t* srcV = src+offsetV;
+
+    for (unsigned r = 0; r < height; r++) {
+        // Note that we're walking the same U and V rows twice for even/odd luminance rows
+        uint8_t* rowY = srcY + r*strideLum;
+        uint8_t* rowU = srcU + (r/2 * strideColor);
+        uint8_t* rowV = srcV + (r/2 * strideColor);
+
+        uint32_t* rowDest = dst + r*dstStridePixels;
+
+        for (unsigned c = 0; c < width; c++) {
+            rowDest[c] = yuvToRgbx(rowY[c], rowU[c], rowV[c]);
+        }
+    }
+}
+
+
+void copyYUYVtoRGB32(unsigned width, unsigned height,
+                     uint8_t* src, unsigned srcStridePixels,
+                     uint32_t* dst, unsigned dstStridePixels)
+{
+    uint32_t* srcWords = (uint32_t*)src;
+
+    const int srcRowPadding32 = srcStridePixels/2 - width/2;  // 2 bytes per pixel, 4 bytes per word
+    const int dstRowPadding32 = dstStridePixels   - width;    // 4 bytes per pixel, 4 bytes per word
+
+    for (unsigned r = 0; r < height; r++) {
+        for (unsigned c = 0; c < width/2; c++) {
+            // Note:  we're walking two pixels at a time here (even/odd)
+            uint32_t srcPixel = *srcWords++;
+
+            uint8_t Y1 = (srcPixel)       & 0xFF;
+            uint8_t U  = (srcPixel >> 8)  & 0xFF;
+            uint8_t Y2 = (srcPixel >> 16) & 0xFF;
+            uint8_t V  = (srcPixel >> 24) & 0xFF;
+
+            // On the RGB output, we're writing one pixel at a time
+            *(dst+0) = yuvToRgbx(Y1, U, V);
+            *(dst+1) = yuvToRgbx(Y2, U, V);
+            dst += 2;
+        }
+
+        // Skip over any extra data or end of row alignment padding
+        srcWords += srcRowPadding32;
+        dst += dstRowPadding32;
+    }
+}
+
+
+void copyMatchedInterleavedFormats(unsigned width, unsigned height,
+                                   void* src, unsigned srcStridePixels,
+                                   void* dst, unsigned dstStridePixels,
+                                   unsigned pixelSize) {
+    for (unsigned row = 0; row < height; row++) {
+        // Copy the entire row of pixel data
+        memcpy(dst, src, width * pixelSize);
+
+        // Advance to the next row (keeping in mind that stride here is in units of pixels)
+        src = (uint8_t*)src + srcStridePixels * pixelSize;
+        dst = (uint8_t*)dst + dstStridePixels * pixelSize;
+    }
+}
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/evs/support_library/FormatConvert.h b/evs/support_library/FormatConvert.h
new file mode 100644
index 0000000..2513dfe
--- /dev/null
+++ b/evs/support_library/FormatConvert.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef EVS_VTS_FORMATCONVERT_H
+#define EVS_VTS_FORMATCONVERT_H
+
+#include <queue>
+#include <stdint.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+// Given an image buffer in NV21 format (HAL_PIXEL_FORMAT_YCRCB_420_SP), output 32bit RGBx values.
+// The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
+// U/V array.  It assumes an even width and height for the overall image, and a horizontal
+// stride that is an even multiple of 16 bytes for both the Y and UV arrays.
+void copyNV21toRGB32(unsigned width, unsigned height,
+                     uint8_t* src,
+                     uint32_t* dst, unsigned dstStridePixels);
+
+
+// Given an image buffer in YV12 format (HAL_PIXEL_FORMAT_YV12), output 32bit RGBx values.
+// The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
+// by another 1/2 x 1/2 V array.  It assumes an even width and height for the overall image,
+// and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
+// and V arrays.
+void copyYV12toRGB32(unsigned width, unsigned height,
+                     uint8_t* src,
+                     uint32_t* dst, unsigned dstStridePixels);
+
+
+// Given an image buffer in YUYV format (HAL_PIXEL_FORMAT_YCBCR_422_I), output 32bit RGBx values.
+// The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
+// U/V array.  It assumes an even width and height for the overall image, and a horizontal
+// stride that is an even multiple of 16 bytes for both the Y and UV arrays.
+void copyYUYVtoRGB32(unsigned width, unsigned height,
+                     uint8_t* src, unsigned srcStrideBytes,
+                     uint32_t* dst, unsigned dstStrideBytes);
+
+
+// Given an simple rectangular image buffer with an integer number of bytes per pixel,
+// copy the pixel values into a new rectangular buffer (potentially with a different stride).
+// This is typically used to copy RGBx data into an RGBx output buffer.
+void copyMatchedInterleavedFormats(unsigned width, unsigned height,
+                                   void* src, unsigned srcStridePixels,
+                                   void* dst, unsigned dstStridePixels,
+                                   unsigned pixelSize);
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
+#endif // EVS_VTS_FORMATCONVERT_H
diff --git a/evs/support_library/Frame.h b/evs/support_library/Frame.h
new file mode 100644
index 0000000..92af203
--- /dev/null
+++ b/evs/support_library/Frame.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef CAR_LIB_EVS_SUPPORT_FRAME_H
+#define CAR_LIB_EVS_SUPPORT_FRAME_H
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+struct Frame {
+    unsigned width;
+    unsigned height;
+    unsigned stride;
+    uint8_t* data;
+};
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
+#endif  // CAR_LIB_EVS_SUPPORT_FRAME_H
diff --git a/evs/support_library/RenderBase.cpp b/evs/support_library/RenderBase.cpp
new file mode 100644
index 0000000..3dab978
--- /dev/null
+++ b/evs/support_library/RenderBase.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RenderBase.h"
+#include "glError.h"
+
+#include <log/log.h>
+#include <ui/GraphicBuffer.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+// Eventually we shouldn't need this dependency, but for now the
+// graphics allocator interface isn't fully supported on all platforms
+// and this is our work around.
+using ::android::GraphicBuffer;
+
+
+// OpenGL state shared among all renderers
+EGLDisplay   RenderBase::sDisplay = EGL_NO_DISPLAY;
+EGLContext   RenderBase::sContext = EGL_NO_CONTEXT;
+EGLSurface   RenderBase::sDummySurface = EGL_NO_SURFACE;
+GLuint       RenderBase::sFrameBuffer = -1;
+GLuint       RenderBase::sColorBuffer = -1;
+GLuint       RenderBase::sDepthBuffer = -1;
+EGLImageKHR  RenderBase::sKHRimage = EGL_NO_IMAGE_KHR;
+unsigned     RenderBase::sWidth  = 0;
+unsigned     RenderBase::sHeight = 0;
+float        RenderBase::sAspectRatio = 0.0f;
+
+
+bool RenderBase::prepareGL() {
+    // Just trivially return success if we're already prepared
+    if (sDisplay != EGL_NO_DISPLAY) {
+        return true;
+    }
+
+    // Hardcoded to RGBx output display
+    const EGLint config_attribs[] = {
+        // Tag                  Value
+        EGL_RENDERABLE_TYPE,    EGL_OPENGL_ES2_BIT,
+        EGL_RED_SIZE,           8,
+        EGL_GREEN_SIZE,         8,
+        EGL_BLUE_SIZE,          8,
+        EGL_NONE
+    };
+
+    // Select OpenGL ES v 3
+    const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
+
+
+    // Set up our OpenGL ES context associated with the default display (though we won't be visible)
+    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    if (display == EGL_NO_DISPLAY) {
+        ALOGE("Failed to get egl display");
+        return false;
+    }
+
+    EGLint major = 0;
+    EGLint minor = 0;
+    if (!eglInitialize(display, &major, &minor)) {
+        ALOGE("Failed to initialize EGL: %s", getEGLError());
+        return false;
+    } else {
+        ALOGI("Intiialized EGL at %d.%d", major, minor);
+    }
+
+
+    // Select the configuration that "best" matches our desired characteristics
+    EGLConfig egl_config;
+    EGLint num_configs;
+    if (!eglChooseConfig(display, config_attribs, &egl_config, 1, &num_configs)) {
+        ALOGE("eglChooseConfig() failed with error: %s", getEGLError());
+        return false;
+    }
+
+
+    // Create a dummy pbuffer so we have a surface to bind -- we never intend to draw to this
+    // because attachRenderTarget will be called first.
+    EGLint surface_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
+    sDummySurface = eglCreatePbufferSurface(display, egl_config, surface_attribs);
+    if (sDummySurface == EGL_NO_SURFACE) {
+        ALOGE("Failed to create OpenGL ES Dummy surface: %s", getEGLError());
+        return false;
+    } else {
+        ALOGI("Dummy surface looks good!  :)");
+    }
+
+
+    //
+    // Create the EGL context
+    //
+    EGLContext context = eglCreateContext(display, egl_config, EGL_NO_CONTEXT, context_attribs);
+    if (context == EGL_NO_CONTEXT) {
+        ALOGE("Failed to create OpenGL ES Context: %s", getEGLError());
+        return false;
+    }
+
+
+    // Activate our render target for drawing
+    if (!eglMakeCurrent(display, sDummySurface, sDummySurface, context)) {
+        ALOGE("Failed to make the OpenGL ES Context current: %s", getEGLError());
+        return false;
+    } else {
+        ALOGI("We made our context current!  :)");
+    }
+
+
+    // Report the extensions available on this implementation
+    const char* gl_extensions = (const char*) glGetString(GL_EXTENSIONS);
+    ALOGI("GL EXTENSIONS:\n  %s", gl_extensions);
+
+
+    // Reserve handles for the color and depth targets we'll be setting up
+    glGenRenderbuffers(1, &sColorBuffer);
+    glGenRenderbuffers(1, &sDepthBuffer);
+
+    // Set up the frame buffer object we can modify and use for off screen rendering
+    glGenFramebuffers(1, &sFrameBuffer);
+    glBindFramebuffer(GL_FRAMEBUFFER, sFrameBuffer);
+
+
+    // Now that we're assured success, store object handles we constructed
+    sDisplay = display;
+    sContext = context;
+
+    return true;
+}
+
+
+bool RenderBase::attachRenderTarget(const BufferDesc& tgtBuffer) {
+    // Hardcoded to RGBx for now
+    if (tgtBuffer.format != HAL_PIXEL_FORMAT_RGBA_8888) {
+        ALOGE("Unsupported target buffer format");
+        return false;
+    }
+
+    // create a GraphicBuffer from the existing handle
+    sp<GraphicBuffer> pGfxBuffer = new GraphicBuffer(tgtBuffer.memHandle,
+                                                     GraphicBuffer::CLONE_HANDLE,
+                                                     tgtBuffer.width, tgtBuffer.height,
+                                                     tgtBuffer.format, 1, // layer count
+                                                     GRALLOC_USAGE_HW_RENDER,
+                                                     tgtBuffer.stride);
+    if (pGfxBuffer.get() == nullptr) {
+        ALOGE("Failed to allocate GraphicBuffer to wrap image handle");
+        return false;
+    }
+
+    // Get a GL compatible reference to the graphics buffer we've been given
+    EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
+    EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(pGfxBuffer->getNativeBuffer());
+    sKHRimage = eglCreateImageKHR(sDisplay, EGL_NO_CONTEXT,
+                                  EGL_NATIVE_BUFFER_ANDROID, clientBuf,
+                                  eglImageAttributes);
+    if (sKHRimage == EGL_NO_IMAGE_KHR) {
+        ALOGE("error creating EGLImage for target buffer: %s", getEGLError());
+        return false;
+    }
+
+    // Construct a render buffer around the external buffer
+    glBindRenderbuffer(GL_RENDERBUFFER, sColorBuffer);
+    glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, static_cast<GLeglImageOES>(sKHRimage));
+    if (eglGetError() != EGL_SUCCESS) {
+        ALOGI("glEGLImageTargetRenderbufferStorageOES => %s", getEGLError());
+        return false;
+    }
+
+    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, sColorBuffer);
+    if (eglGetError() != EGL_SUCCESS) {
+        ALOGE("glFramebufferRenderbuffer => %s", getEGLError());
+        return false;
+    }
+
+    GLenum checkResult = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+    if (checkResult != GL_FRAMEBUFFER_COMPLETE) {
+        ALOGE("Offscreen framebuffer not configured successfully (%d: %s)",
+              checkResult, getGLFramebufferError());
+        return false;
+    }
+
+    // Store the size of our target buffer
+    sWidth = tgtBuffer.width;
+    sHeight = tgtBuffer.height;
+    sAspectRatio = (float)sWidth / sHeight;
+
+    // Set the viewport
+    glViewport(0, 0, sWidth, sHeight);
+
+#if 1   // We don't actually need the clear if we're going to cover the whole screen anyway
+    // Clear the color buffer
+    glClearColor(0.8f, 0.1f, 0.2f, 1.0f);
+    glClear(GL_COLOR_BUFFER_BIT);
+#endif
+
+
+    return true;
+}
+
+
+void RenderBase::detachRenderTarget() {
+    // Drop our external render target
+    if (sKHRimage != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(sDisplay, sKHRimage);
+        sKHRimage = EGL_NO_IMAGE_KHR;
+    }
+}
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/evs/support_library/RenderBase.h b/evs/support_library/RenderBase.h
new file mode 100644
index 0000000..0a9be51
--- /dev/null
+++ b/evs/support_library/RenderBase.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CAR_EVS_APP_RENDERBASE_H
+#define CAR_EVS_APP_RENDERBASE_H
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+
+#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
+
+#include <BaseRenderCallback.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+using namespace ::android::hardware::automotive::evs::V1_0;
+using ::android::sp;
+
+
+/*
+ * Abstract base class for the workhorse classes that handle the user interaction and display for
+ * each mode of the EVS application.
+ */
+class RenderBase {
+public:
+    virtual ~RenderBase() {};
+
+    virtual bool activate() = 0;
+    virtual void deactivate() = 0;
+
+    virtual bool drawFrame(const BufferDesc& tgtBuffer, const BufferDesc& imageBuffer) = 0;
+
+protected:
+    static bool prepareGL();
+
+    static bool attachRenderTarget(const BufferDesc& tgtBuffer);
+    static void detachRenderTarget();
+
+    // OpenGL state shared among all renderers
+    static EGLDisplay   sDisplay;
+    static EGLContext   sContext;
+    static EGLSurface   sDummySurface;
+    static GLuint       sFrameBuffer;
+    static GLuint       sColorBuffer;
+    static GLuint       sDepthBuffer;
+
+    static EGLImageKHR  sKHRimage;
+
+    static unsigned     sWidth;
+    static unsigned     sHeight;
+    static float        sAspectRatio;
+};
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
+#endif //CAR_EVS_APP_RENDERBASE_H
diff --git a/evs/support_library/RenderDirectView.cpp b/evs/support_library/RenderDirectView.cpp
new file mode 100644
index 0000000..f727002
--- /dev/null
+++ b/evs/support_library/RenderDirectView.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RenderDirectView.h"
+#include "VideoTex.h"
+#include "glError.h"
+#include "shader.h"
+#include "shader_simpleTex.h"
+
+#include <log/log.h>
+#include <math/mat4.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+bool RenderDirectView::activate() {
+    // Ensure GL is ready to go...
+    if (!prepareGL()) {
+        ALOGE("Error initializing GL");
+        return false;
+    }
+
+    // Load our shader program if we don't have it already
+    if (!mShaderProgram) {
+        mShaderProgram = buildShaderProgram(vtxShader_simpleTexture,
+                                            pixShader_simpleTexture,
+                                            "simpleTexture");
+        if (!mShaderProgram) {
+            ALOGE("Error building shader program");
+            return false;
+        }
+    }
+
+    // Construct our video texture
+    mTexture.reset(new VideoTex(sDisplay));
+    if (!mTexture) {
+        ALOGE("Failed to set up video texture");
+// TODO:  For production use, we may actually want to fail in this case, but not yet...
+//       return false;
+    }
+
+    return true;
+}
+
+
+void RenderDirectView::deactivate() {
+    // Release our video texture
+    // We can't hold onto it because some other Render object might need the same camera
+    // TODO:  If start/stop costs become a problem, we could share video textures
+    mTexture = nullptr;
+}
+
+
+bool RenderDirectView::drawFrame(const BufferDesc& tgtBuffer,
+                                 const BufferDesc& imageBuffer) {
+    // Tell GL to render to the given buffer
+    if (!attachRenderTarget(tgtBuffer)) {
+        ALOGE("Failed to attached render target");
+        return false;
+    }
+
+    // Select our screen space simple texture shader
+    glUseProgram(mShaderProgram);
+
+    // Set up the model to clip space transform (identity matrix if we're modeling in screen space)
+    GLint loc = glGetUniformLocation(mShaderProgram, "cameraMat");
+    if (loc < 0) {
+        ALOGE("Couldn't set shader parameter 'cameraMat'");
+        return false;
+    } else {
+        const android::mat4 identityMatrix;
+        glUniformMatrix4fv(loc, 1, false, identityMatrix.asArray());
+    }
+
+
+    // Bind the texture and assign it to the shader's sampler
+    mTexture->refresh(imageBuffer);
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, mTexture->glId());
+
+
+    GLint sampler = glGetUniformLocation(mShaderProgram, "tex");
+    if (sampler < 0) {
+        ALOGE("Couldn't set shader parameter 'tex'");
+        return false;
+    } else {
+        // Tell the sampler we looked up from the shader to use texture slot 0 as its source
+        glUniform1i(sampler, 0);
+    }
+
+    // We want our image to show up opaque regardless of alpha values
+    glDisable(GL_BLEND);
+
+
+    // Draw a rectangle on the screen
+    GLfloat vertsCarPos[] = { -1.0,  1.0, 0.0f,   // left top in window space
+                               1.0,  1.0, 0.0f,   // right top
+                              -1.0, -1.0, 0.0f,   // left bottom
+                               1.0, -1.0, 0.0f    // right bottom
+    };
+    // TODO:  We're flipping horizontally here, but should do it only for specified cameras!
+    GLfloat vertsCarTex[] = { 1.0f, 1.0f,   // left top
+                              0.0f, 1.0f,   // right top
+                              1.0f, 0.0f,   // left bottom
+                              0.0f, 0.0f    // right bottom
+    };
+    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertsCarPos);
+    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, vertsCarTex);
+    glEnableVertexAttribArray(0);
+    glEnableVertexAttribArray(1);
+
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+    glDisableVertexAttribArray(0);
+    glDisableVertexAttribArray(1);
+
+
+    // Now that everything is submitted, release our hold on the texture resource
+    detachRenderTarget();
+
+    // Wait for the rendering to finish
+    glFinish();
+    detachRenderTarget();
+    return true;
+}
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/evs/support_library/RenderDirectView.h b/evs/support_library/RenderDirectView.h
new file mode 100644
index 0000000..25bf990
--- /dev/null
+++ b/evs/support_library/RenderDirectView.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CAR_EVS_APP_RENDERDIRECTVIEW_H
+#define CAR_EVS_APP_RENDERDIRECTVIEW_H
+
+
+#include "RenderBase.h"
+
+#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
+#include "ConfigManager.h"
+#include "VideoTex.h"
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+using namespace ::android::hardware::automotive::evs::V1_0;
+
+
+/*
+ * Renders the view from a single specified camera directly to the full display.
+ */
+class RenderDirectView: public RenderBase {
+public:
+    virtual bool activate() override;
+    virtual void deactivate() override;
+
+    virtual bool drawFrame(const BufferDesc& tgtBuffer,
+                           const BufferDesc& imageBuffer) override;
+
+protected:
+    std::unique_ptr<VideoTex>       mTexture;
+
+    GLuint                          mShaderProgram = 0;
+};
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
+#endif //CAR_EVS_APP_RENDERDIRECTVIEW_H
diff --git a/evs/support_library/ResourceManager.cpp b/evs/support_library/ResourceManager.cpp
new file mode 100644
index 0000000..aebd15a
--- /dev/null
+++ b/evs/support_library/ResourceManager.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ResourceManager.h"
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+using ::std::lock_guard;
+
+const string ResourceManager::kDefaultServiceName = "default";
+sp<ResourceManager> ResourceManager::sInstance;
+mutex ResourceManager::sLockSingleton;
+mutex ResourceManager::sLockEvs;
+sp<IEvsEnumerator> ResourceManager::sEvs;
+
+sp<IEvsEnumerator> ResourceManager::getEvsEnumerator(string serviceName) {
+    lock_guard<mutex> lock(sLockEvs);
+    if (sEvs.get() == nullptr) {
+        sEvs = IEvsEnumerator::getService(serviceName);
+    }
+    return sEvs;
+}
+
+sp<ResourceManager> ResourceManager::getInstance() {
+    lock_guard<mutex> lock(sLockSingleton);
+    if (sInstance == nullptr) {
+        ALOGD("Creating new ResourceManager instance");
+        sInstance = new ResourceManager();
+    }
+    return sInstance;
+}
+
+sp<StreamHandler> ResourceManager::obtainStreamHandler(string pCameraId) {
+    ALOGD("ResourceManager::obtainStreamHandler");
+
+    // Lock for stream handler related methods.
+    lock_guard<mutex> lock(mLockStreamHandler);
+
+    auto result = mCameraInstances.find(pCameraId);
+    if (result == mCameraInstances.end()) {
+        sp<CameraInstance> instance = new CameraInstance();
+
+        // CameraInstance::useCaseCount
+        instance->useCaseCount++;
+
+        // CameraInstance::cameraId
+        instance->cameraId = pCameraId;
+
+        // CameraInstance::camera
+        instance->camera = getEvsEnumerator()->openCamera(pCameraId);
+        if (instance->camera.get() == nullptr) {
+            ALOGE("Failed to allocate new EVS Camera interface for %s",
+                  pCameraId.c_str());
+            return nullptr;
+        }
+
+        // CameraInstance::handler
+        instance->handler = new StreamHandler(instance->camera);
+        if (instance->handler == nullptr) {
+            ALOGE("Failed to create stream handler for %s",
+                  pCameraId.c_str());
+        }
+
+        // Move the newly-created instance into vector, and the vector takes
+        // ownership of the instance.
+        mCameraInstances.emplace(pCameraId, instance);
+
+        return instance->handler;
+    } else {
+        auto instance = result->second;
+        instance->useCaseCount++;
+
+        return instance->handler;
+    }
+}
+
+void ResourceManager::releaseStreamHandler(string pCameraId) {
+    ALOGD("ResourceManager::releaseStreamHandler");
+
+    // Lock for stream handler related methods.
+    lock_guard<mutex> lock(mLockStreamHandler);
+
+    auto result = mCameraInstances.find(pCameraId);
+    if (result == mCameraInstances.end()) {
+        ALOGW("No stream handler is active with camera id %s", pCameraId.c_str());
+    } else {
+        auto instance = result->second;
+        instance->useCaseCount--;
+
+        if (instance->useCaseCount <= 0) {
+            // The vector keeps the only strong reference to the camera
+            // instance. Once the instance is erased from the vector, the
+            // override onLastStrongRef method for CameraInstance class will
+            // be called and clean up the resources.
+            mCameraInstances.erase(result);
+        }
+    }
+}
+
+// TODO(b/130246434): have further discussion about how the display resource
+// should be managed.
+sp<IEvsDisplay> ResourceManager::openDisplay() {
+    // Lock for display related methods.
+    lock_guard<mutex> lock(mLockDisplay);
+
+    if (mDisplay.get() == nullptr) {
+        mDisplay = getEvsEnumerator()->openDisplay();
+        if (mDisplay.get() != nullptr) {
+            ALOGD("Evs display is opened");
+        } else {
+            ALOGE("Failed to open evs display.");
+        }
+    }
+
+    return mDisplay;
+}
+
+void ResourceManager::closeDisplay(sp<IEvsDisplay> pDisplay) {
+    // Lock for display related methods.
+    lock_guard<mutex> lock(mLockDisplay);
+
+    // Even though there are logics in evs manager to prevent errors from
+    // unrecognized IEvsDisplay object, we still want to check whether the
+    // incoming pDisplay is the one we opened earlier in resource manager. So
+    // when developer make mistakes by passing in incorrect IEvsDisplay object,
+    // we know that we should not proceed and the active display is still
+    // opened.
+    if (mDisplay.get() == pDisplay.get()) {
+        getEvsEnumerator()->closeDisplay(mDisplay);
+        mDisplay = nullptr;
+        ALOGD("Evs display is closed");
+    } else {
+        ALOGW("Ignored! Unrecognized display object for closeDisplay method");
+    }
+}
+
+bool ResourceManager::isDisplayOpened() {
+    // Lock for display related methods.
+    lock_guard<mutex> lock(mLockDisplay);
+
+    return mDisplay.get() != nullptr;
+}
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/evs/support_library/ResourceManager.h b/evs/support_library/ResourceManager.h
new file mode 100644
index 0000000..2bf2e27
--- /dev/null
+++ b/evs/support_library/ResourceManager.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CAR_LIB_EVS_SUPPORT_RESOURCEMANAGER_H
+#define CAR_LIB_EVS_SUPPORT_RESOURCEMANAGER_H
+
+#include <utils/RefBase.h>
+#include <unordered_map>
+#include <mutex>
+
+#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
+
+#include "StreamHandler.h"
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+using ::android::sp;
+using ::std::string;
+using ::std::mutex;
+using ::std::unordered_map;
+
+/*
+ * Manages EVS related resources. E.g. evs camera, stream handler, and display.
+ *
+ * The methods in the class are guaranteed to be thread-safe.
+ */
+class ResourceManager : public android::RefBase {
+public:
+    /*
+     * Gets the singleton instance of the class.
+     */
+    static sp<ResourceManager> getInstance();
+
+    /*
+     * Obtains a StreamHandler instance to receive evs camera imagery from the
+     * given camera.
+     *
+     * When this function is called with a new camera id the first time, an evs
+     * camera instance will be opened. An internal reference count will be
+     * incremented by one every time when this method is called with the same
+     * camera id. The count will be decreased by one when releaseStreamHandler
+     * method is called, and when the reference count for the camera is
+     * decreased to zero, the stream handler will be shut down and the evs
+     * camera instance will be closed.
+     *
+     * The method will block other stream handler related calls. For example,
+     * method releaseStreamHandler.
+     *
+     * @see releaseStreamHandler()
+     */
+    sp<StreamHandler> obtainStreamHandler(string pCameraId);
+
+    /*
+     * Releases the StreamHandler associated with the given camera.
+     *
+     * An internal reference count will be decreased when this method is
+     * called. When the count is down to zero, the stream handler will be shut
+     * down and the evs camera instance will be closed.
+     *
+     * The method will block other stream handler related calls. For example,
+     * method obtainStreamHandler.
+     *
+     * @see obtainStreamHandler()
+     */
+    void releaseStreamHandler(string pCameraId);
+
+    /*
+     * Obtains an interface object used to exclusively interact with the
+     * system's evs display.
+     *
+     * @see closeDisplay()
+     */
+    sp<IEvsDisplay> openDisplay();
+
+    /*
+     * Releases the evs display interface.
+     *
+     * @see openDisplay()
+     */
+    void closeDisplay(sp<IEvsDisplay>);
+
+    /**
+     * Returns true if display is opened by openDisplay method; returns false
+     * if display is never opened, or closed by closeDisplay method.
+     *
+     * @see openDisplay()
+     * @see closeDisplay()
+     */
+    bool isDisplayOpened();
+
+private:
+    static sp<IEvsEnumerator> getEvsEnumerator(string serviceName = kDefaultServiceName);
+
+    static const string kDefaultServiceName;
+
+    static sp<ResourceManager> sInstance;
+    static sp<IEvsEnumerator> sEvs;
+    static mutex sLockSingleton, sLockEvs;
+
+    class CameraInstance : public RefBase {
+    public:
+        int useCaseCount = 0;
+        string cameraId;
+        sp<IEvsCamera> camera;
+        sp<StreamHandler> handler;
+
+    private:
+        void onLastStrongRef(const void* /*id*/) {
+            ALOGD("StreamHandler::onLastStrongRef");
+
+            handler->shutdown();
+            ALOGD("Stream handler for camera id (%s) has been shutdown",
+                  cameraId.c_str());
+
+            getEvsEnumerator()->closeCamera(camera);
+            ALOGD("Camera with id (%s) has been closed", cameraId.c_str());
+        }
+    };
+
+    sp<IEvsDisplay> mDisplay;
+    unordered_map<string, sp<CameraInstance>> mCameraInstances;
+    mutex mLockStreamHandler, mLockDisplay;
+};
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
+#endif //CAR_LIB_EVS_SUPPORT_RESOURCEMANAGER_H
diff --git a/evs/support_library/StreamHandler.cpp b/evs/support_library/StreamHandler.cpp
new file mode 100644
index 0000000..4e557b8
--- /dev/null
+++ b/evs/support_library/StreamHandler.cpp
@@ -0,0 +1,483 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "StreamHandler.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <log/log.h>
+#include <cutils/native_handle.h>
+
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
+
+#include "Frame.h"
+#include "ResourceManager.h"
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+using ::std::lock_guard;
+using ::std::unique_lock;
+
+StreamHandler::StreamHandler(android::sp <IEvsCamera> pCamera) :
+    mCamera(pCamera),
+    mAnalyzeCallback(nullptr),
+    mAnalyzerRunning(false)
+{
+    // We rely on the camera having at least two buffers available since we'll hold one and
+    // expect the camera to be able to capture a new image in the background.
+    pCamera->setMaxFramesInFlight(2);
+}
+
+// TODO(b/130246343): investigate further to make sure the resources are cleaned
+// up properly in the shutdown logic.
+void StreamHandler::shutdown()
+{
+    // Tell the camera to stop streaming.
+    // This will result in a null frame being delivered when the stream actually stops.
+    mCamera->stopVideoStream();
+
+    // Wait until the stream has actually stopped
+    unique_lock<mutex> lock(mLock);
+    if (mRunning) {
+        mSignal.wait(lock, [this]() { return !mRunning; });
+    }
+
+    // At this point, the receiver thread is no longer running, so we can safely drop
+    // our remote object references so they can be freed
+    mCamera = nullptr;
+}
+
+
+bool StreamHandler::startStream() {
+    lock_guard<mutex> lock(mLock);
+
+    if (!mRunning) {
+        // Tell the camera to start streaming
+        Return <EvsResult> result = mCamera->startVideoStream(this);
+        if (result != EvsResult::OK) {
+            return false;
+        }
+
+        // Mark ourselves as running
+        mRunning = true;
+    }
+
+    return true;
+}
+
+
+bool StreamHandler::newDisplayFrameAvailable() {
+    lock_guard<mutex> lock(mLock);
+    return (mReadyBuffer >= 0);
+}
+
+
+const BufferDesc& StreamHandler::getNewDisplayFrame() {
+    lock_guard<mutex> lock(mLock);
+
+    if (mHeldBuffer >= 0) {
+        ALOGE("Ignored call for new frame while still holding the old one.");
+    } else {
+        if (mReadyBuffer < 0) {
+            ALOGE("Returning invalid buffer because we don't have any. "
+                  " Call newDisplayFrameAvailable first?");
+            mReadyBuffer = 0;   // This is a lie!
+        }
+
+        // Move the ready buffer into the held position, and clear the ready position
+        mHeldBuffer = mReadyBuffer;
+        mReadyBuffer = -1;
+    }
+
+    if (mRenderCallback == nullptr) {
+        return mOriginalBuffers[mHeldBuffer];
+    } else {
+        return mProcessedBuffers[mHeldBuffer];
+    }
+}
+
+
+void StreamHandler::doneWithFrame(const BufferDesc& buffer) {
+    lock_guard<mutex> lock(mLock);
+
+    // We better be getting back the buffer we original delivered!
+    if ((mHeldBuffer < 0)
+        || (buffer.bufferId != mOriginalBuffers[mHeldBuffer].bufferId)) {
+        ALOGE("StreamHandler::doneWithFrame got an unexpected buffer!");
+        ALOGD("Held buffer id: %d, input buffer id: %d",
+              mOriginalBuffers[mHeldBuffer].bufferId, buffer.bufferId);
+        return;
+    }
+
+    // Send the buffer back to the underlying camera
+    mCamera->doneWithFrame(mOriginalBuffers[mHeldBuffer]);
+
+    // Clear the held position
+    mHeldBuffer = -1;
+}
+
+
+Return<void> StreamHandler::deliverFrame(const BufferDesc& buffer) {
+    ALOGD("Received a frame from the camera. NativeHandle:%p, buffer id:%d",
+          buffer.memHandle.getNativeHandle(), buffer.bufferId);
+
+    // Take the lock to protect our frame slots and running state variable
+    {
+        lock_guard <mutex> lock(mLock);
+
+        if (buffer.memHandle.getNativeHandle() == nullptr) {
+            // Signal that the last frame has been received and the stream is stopped
+            mRunning = false;
+        } else {
+            // Do we already have a "ready" frame?
+            if (mReadyBuffer >= 0) {
+                // Send the previously saved buffer back to the camera unused
+                mCamera->doneWithFrame(mOriginalBuffers[mReadyBuffer]);
+
+                // We'll reuse the same ready buffer index
+            } else if (mHeldBuffer >= 0) {
+                // The client is holding a buffer, so use the other slot for "on deck"
+                mReadyBuffer = 1 - mHeldBuffer;
+            } else {
+                // This is our first buffer, so just pick a slot
+                mReadyBuffer = 0;
+            }
+
+            // Save this frame until our client is interested in it
+            mOriginalBuffers[mReadyBuffer] = buffer;
+
+            // If render callback is not null, process the frame with render
+            // callback.
+            if (mRenderCallback != nullptr) {
+                processFrame(mOriginalBuffers[mReadyBuffer],
+                             mProcessedBuffers[mReadyBuffer]);
+            } else {
+                ALOGI("Render callback is null in deliverFrame.");
+            }
+
+            // If analyze callback is not null and the analyze thread is
+            // available, copy the frame and run the analyze callback in
+            // analyze thread.
+            {
+                std::shared_lock<std::shared_mutex> analyzerLock(mAnalyzerLock);
+                if (mAnalyzeCallback != nullptr && !mAnalyzerRunning) {
+                    copyAndAnalyzeFrame(mOriginalBuffers[mReadyBuffer]);
+                }
+            }
+        }
+    }
+
+    // Notify anybody who cares that things have changed
+    mSignal.notify_all();
+
+    return Void();
+}
+
+void StreamHandler::attachRenderCallback(BaseRenderCallback* callback) {
+    ALOGD("StreamHandler::attachRenderCallback");
+
+    lock_guard<mutex> lock(mLock);
+
+    if (mRenderCallback != nullptr) {
+        ALOGW("Ignored! There should only be one render callback");
+        return;
+    }
+    mRenderCallback = callback;
+}
+
+void StreamHandler::detachRenderCallback() {
+    ALOGD("StreamHandler::detachRenderCallback");
+
+    lock_guard<mutex> lock(mLock);
+
+    mRenderCallback = nullptr;
+}
+
+void StreamHandler::attachAnalyzeCallback(BaseAnalyzeCallback* callback) {
+    ALOGD("StreamHandler::attachAnalyzeCallback");
+
+    if (mAnalyzeCallback != nullptr) {
+        ALOGW("Ignored! There should only be one analyze callcack");
+        return;
+    }
+
+    {
+        lock_guard<std::shared_mutex> lock(mAnalyzerLock);
+        mAnalyzeCallback = callback;
+    }
+}
+
+void StreamHandler::detachAnalyzeCallback() {
+    ALOGD("StreamHandler::detachAnalyzeCallback");
+
+    {
+        std::unique_lock<std::shared_mutex> lock(mAnalyzerLock);
+
+        // Wait until current running analyzer ends
+        mAnalyzerSignal.wait(lock, [this] { return !mAnalyzerRunning; });
+        mAnalyzeCallback = nullptr;
+    }
+}
+
+bool isSameFormat(const BufferDesc& input, const BufferDesc& output) {
+    return input.width == output.width
+        && input.height == output.height
+        && input.format == output.format
+        && input.usage == output.usage
+        && input.stride == output.stride
+        && input.pixelSize == output.pixelSize;
+}
+
+bool allocate(BufferDesc& buffer) {
+    ALOGD("StreamHandler::allocate");
+    buffer_handle_t handle;
+    android::GraphicBufferAllocator& alloc(android::GraphicBufferAllocator::get());
+    android::status_t result = alloc.allocate(
+        buffer.width, buffer.height, buffer.format, 1, buffer.usage,
+        &handle, &buffer.stride, 0, "EvsDisplay");
+    if (result != android::NO_ERROR) {
+        ALOGE("Error %d allocating %d x %d graphics buffer", result, buffer.width,
+              buffer.height);
+        return false;
+    }
+
+    // The reason that we have to check null for "handle" is because that the
+    // above "result" might not cover all the failure scenarios.
+    // By looking into Gralloc4.cpp (and 3, 2, as well), it turned out that if
+    // there is anything that goes wrong in the process of buffer importing (see
+    // Ln 385 in Gralloc4.cpp), the error won't be covered by the above "result"
+    // we got from "allocate" method. In other words, it means that there is
+    // still a chance that the "result" is "NO_ERROR" but the handle is nullptr
+    // (that means buffer importing failed).
+    if (!handle) {
+        ALOGE("We didn't get a buffer handle back from the allocator");
+        return false;
+    }
+
+    buffer.memHandle = hidl_handle(handle);
+    return true;
+}
+
+bool StreamHandler::processFrame(const BufferDesc& input,
+                                 BufferDesc& output) {
+    ALOGD("StreamHandler::processFrame");
+    if (!isSameFormat(input, output)
+        || output.memHandle.getNativeHandle() == nullptr) {
+        output.width = input.width;
+        output.height = input.height;
+        output.format = input.format;
+        output.usage = input.usage;
+        output.stride = input.stride;
+        output.pixelSize = input.pixelSize;
+
+        // free the allocated output frame handle if it is not null
+        if (output.memHandle.getNativeHandle() != nullptr) {
+            GraphicBufferAllocator::get().free(output.memHandle);
+        }
+
+        if (!allocate(output)) {
+            ALOGE("Error allocating buffer");
+            return false;
+        }
+    }
+    output.bufferId = input.bufferId;
+
+    // Create a GraphicBuffer from the existing handle
+    sp<GraphicBuffer> inputBuffer = new GraphicBuffer(
+        input.memHandle, GraphicBuffer::CLONE_HANDLE, input.width,
+        input.height, input.format, 1,  // layer count
+        GRALLOC_USAGE_HW_TEXTURE, input.stride);
+
+    if (inputBuffer.get() == nullptr) {
+        ALOGE("Failed to allocate GraphicBuffer to wrap image handle");
+        // Returning "true" in this error condition because we already released
+        // the previous image (if any) and so the texture may change in
+        // unpredictable ways now!
+        return false;
+    }
+
+    // Lock the input GraphicBuffer and map it to a pointer. If we failed to
+    // lock, return false.
+    void* inputDataPtr;
+    inputBuffer->lock(
+        GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
+        &inputDataPtr);
+
+    // Unlock the buffer and return if lock did not succeed.
+    if (!inputDataPtr) {
+        ALOGE("Failed to gain read access to image buffer");
+
+        // The program reaches at here when it fails to lock the buffer. But
+        // it is still safer to unlock it. The reason is as described in "lock"
+        // method in  Gralloc.h: "The ownership of acquireFence is always
+        // transferred to the callee, even on errors."
+        // And even if the buffer was not locked, it does not harm anything
+        // given the comment for "unlock" method in IMapper.hal:
+        // "`BAD_BUFFER` if the buffer is invalid or not locked."
+        inputBuffer->unlock();
+        return false;
+    }
+
+    // Lock the allocated buffer in output BufferDesc and map it to a pointer
+    void* outputDataPtr = nullptr;
+    android::GraphicBufferMapper& mapper = android::GraphicBufferMapper::get();
+    mapper.lock(output.memHandle,
+                GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
+                android::Rect(output.width, output.height),
+                (void**)&outputDataPtr);
+
+    // If we failed to lock the pixel buffer, return false, and unlock both
+    // input and output buffers.
+    if (!outputDataPtr) {
+        ALOGE("Failed to gain write access to image buffer");
+
+        // Please refer to the previous "if" block for why we want to unlock
+        // the buffers even if the buffer locking fails.
+        inputBuffer->unlock();
+        mapper.unlock(output.memHandle);
+        return false;
+    }
+
+    // Wrap the raw data and copied data, and pass them to the callback.
+    Frame inputFrame = {
+        .width = input.width,
+        .height = input.height,
+        .stride = input.stride,
+        .data = (uint8_t*)inputDataPtr
+    };
+
+    Frame outputFrame = {
+        .width = output.width,
+        .height = output.height,
+        .stride = output.stride,
+        .data = (uint8_t*)outputDataPtr
+    };
+
+    mRenderCallback->render(inputFrame, outputFrame);
+
+    // Unlock the buffers after all changes to the buffer are completed.
+    inputBuffer->unlock();
+    mapper.unlock(output.memHandle);
+
+    return true;
+}
+
+bool StreamHandler::copyAndAnalyzeFrame(const BufferDesc& input) {
+    ALOGD("StreamHandler::copyAndAnalyzeFrame");
+
+    // TODO(b/130246434): make the following into a method. Some lines are
+    // duplicated with processFrame, move them into new methods as well.
+    if (!isSameFormat(input, mAnalyzeBuffer)
+        || mAnalyzeBuffer.memHandle.getNativeHandle() == nullptr) {
+        mAnalyzeBuffer.width = input.width;
+        mAnalyzeBuffer.height = input.height;
+        mAnalyzeBuffer.format = input.format;
+        mAnalyzeBuffer.usage = input.usage;
+        mAnalyzeBuffer.stride = input.stride;
+        mAnalyzeBuffer.pixelSize = input.pixelSize;
+        mAnalyzeBuffer.bufferId = input.bufferId;
+
+        // free the allocated output frame handle if it is not null
+        if (mAnalyzeBuffer.memHandle.getNativeHandle() != nullptr) {
+            GraphicBufferAllocator::get().free(mAnalyzeBuffer.memHandle);
+        }
+
+        if (!allocate(mAnalyzeBuffer)) {
+            ALOGE("Error allocating buffer");
+            return false;
+        }
+    }
+
+    // create a GraphicBuffer from the existing handle
+    sp<GraphicBuffer> inputBuffer = new GraphicBuffer(
+        input.memHandle, GraphicBuffer::CLONE_HANDLE, input.width,
+        input.height, input.format, 1,  // layer count
+        GRALLOC_USAGE_HW_TEXTURE, input.stride);
+
+    if (inputBuffer.get() == nullptr) {
+        ALOGE("Failed to allocate GraphicBuffer to wrap image handle");
+        // Returning "true" in this error condition because we already released the
+        // previous image (if any) and so the texture may change in unpredictable
+        // ways now!
+        return false;
+    }
+
+    // Lock the input GraphicBuffer and map it to a pointer.  If we failed to
+    // lock, return false.
+    void* inputDataPtr;
+    inputBuffer->lock(
+        GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
+        &inputDataPtr);
+    if (!inputDataPtr) {
+        ALOGE("Failed to gain read access to imageGraphicBuffer");
+        inputBuffer->unlock();
+        return false;
+    }
+
+    // Lock the allocated buffer in output BufferDesc and map it to a pointer
+    void* analyzeDataPtr = nullptr;
+    android::GraphicBufferMapper::get().lock(
+        mAnalyzeBuffer.memHandle,
+        GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
+        android::Rect(mAnalyzeBuffer.width, mAnalyzeBuffer.height),
+        (void**)&analyzeDataPtr);
+
+    // If we failed to lock the pixel buffer, return false, and unlock both
+    // input and output buffers.
+    if (!analyzeDataPtr) {
+        ALOGE("Camera failed to gain access to image buffer for analyzing");
+        return false;
+    }
+
+    // Wrap the raw data and copied data, and pass them to the callback.
+    Frame analyzeFrame = {
+        .width = mAnalyzeBuffer.width,
+        .height = mAnalyzeBuffer.height,
+        .stride = mAnalyzeBuffer.stride,
+        .data = (uint8_t*)analyzeDataPtr,
+    };
+
+    memcpy(analyzeDataPtr, inputDataPtr, mAnalyzeBuffer.stride * mAnalyzeBuffer.height * 4);
+
+    // Unlock the buffers after all changes to the buffer are completed.
+    inputBuffer->unlock();
+
+    mAnalyzerRunning = true;
+    std::thread([this, analyzeFrame]() {
+        ALOGD("StreamHandler: Analyze Thread starts");
+
+        std::shared_lock<std::shared_mutex> lock(mAnalyzerLock);
+        if (this->mAnalyzeCallback != nullptr) {
+            this->mAnalyzeCallback->analyze(analyzeFrame);
+            android::GraphicBufferMapper::get().unlock(this->mAnalyzeBuffer.memHandle);
+        }
+        this->mAnalyzerRunning = false;
+        mAnalyzerSignal.notify_one();
+        ALOGD("StreamHandler: Analyze Thread ends");
+    }).detach();
+
+    return true;
+}
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/evs/support_library/StreamHandler.h b/evs/support_library/StreamHandler.h
new file mode 100644
index 0000000..f0e9fed
--- /dev/null
+++ b/evs/support_library/StreamHandler.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef EVS_VTS_STREAMHANDLER_H
+#define EVS_VTS_STREAMHANDLER_H
+
+#include <condition_variable>
+#include <queue>
+#include <thread>
+#include <shared_mutex>
+#include <ui/GraphicBuffer.h>
+#include <android/hardware/automotive/evs/1.0/IEvsCameraStream.h>
+#include <android/hardware/automotive/evs/1.0/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+
+#include "BaseRenderCallback.h"
+#include "BaseAnalyzeCallback.h"
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+using namespace ::android::hardware::automotive::evs::V1_0;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_handle;
+using ::android::sp;
+
+
+/*
+ * StreamHandler:
+ * This class can be used to receive camera imagery from an IEvsCamera implementation.  It will
+ * hold onto the most recent image buffer, returning older ones.
+ * Note that the video frames are delivered on a background thread, while the control interface
+ * is actuated from the applications foreground thread.
+ */
+class StreamHandler : public IEvsCameraStream {
+public:
+    virtual ~StreamHandler() {
+        // The shutdown logic is supposed to be handled by ResourceManager
+        // class. But if something goes wrong, we want to make sure that the
+        // related resources are still released properly.
+        if (mCamera != nullptr) {
+            shutdown();
+        }
+    };
+
+    StreamHandler(android::sp <IEvsCamera> pCamera);
+    void shutdown();
+
+    bool startStream();
+
+    bool newDisplayFrameAvailable();
+    const BufferDesc& getNewDisplayFrame();
+    void doneWithFrame(const BufferDesc& buffer);
+
+    /*
+     * Attaches a render callback to the StreamHandler.
+     *
+     * Every frame will be processed by the attached render callback before it
+     * is delivered to the client by method getNewDisplayFrame().
+     *
+     * Since there is only one DisplayUseCase allowed at the same time, at most
+     * only one render callback can be attached. The current render callback
+     * needs to be detached first (by method detachRenderCallback()), before a
+     * new callback can be attached. In other words, the call will be ignored
+     * if the current render callback is not null.
+     *
+     * @see detachRenderCallback()
+     * @see getNewDisplayFrame()
+     */
+    void attachRenderCallback(BaseRenderCallback*);
+
+    /*
+     * Detaches the current render callback.
+     *
+     * If no render callback is attached, this call will be ignored.
+     *
+     * @see attachRenderCallback(BaseRenderCallback*)
+     */
+    void detachRenderCallback();
+
+    /*
+     * Attaches an analyze callback to the StreamHandler.
+     *
+     * When there is a valid analyze callback attached, a thread dedicated for
+     * the analyze callback will be allocated. When the thread is not busy, the
+     * next available evs frame will be copied (now happens in binder thread).
+     * And the copy will be passed into the analyze thread, and be processed by
+     * the analyze callback.
+     *
+     * Since there is only one AnalyzeUseCase allowed at the same time, at most
+     * only one analyze callback can be attached. The current analyze callback
+     * needs to be detached first (by method detachAnalyzeCallback()), before a
+     * new callback can be attached. In other words, the call will be ignored
+     * if the current analyze callback is not null.
+     *
+     * @see detachAnalyzeCallback()
+     */
+    // TODO(b/130246434): now only one analyze use case is supported, so one
+    // analyze thread id good enough. But we should be able to support several
+    // analyze use cases running at the same time, so we should probably use a
+    // thread pool to handle the cases.
+    void attachAnalyzeCallback(BaseAnalyzeCallback*);
+
+    /*
+     * Detaches the current analyze callback.
+     *
+     * If no analyze callback is attached, this call will be ignored.
+     *
+     * @see attachAnalyzeCallback(BaseAnalyzeCallback*)
+     */
+    void detachAnalyzeCallback();
+
+private:
+    // Implementation for ::android::hardware::automotive::evs::V1_0::ICarCameraStream
+    Return<void> deliverFrame(const BufferDesc& buffer)  override;
+
+    bool processFrame(const BufferDesc&, BufferDesc&);
+    bool copyAndAnalyzeFrame(const BufferDesc&);
+
+    // Values initialized as startup
+    android::sp <IEvsCamera>    mCamera;
+
+    // Since we get frames delivered to us asnchronously via the ICarCameraStream interface,
+    // we need to protect all member variables that may be modified while we're streaming
+    // (ie: those below)
+    std::mutex                  mLock;
+    std::condition_variable     mSignal;
+
+    bool                        mRunning = false;
+
+    BufferDesc                  mOriginalBuffers[2];
+    int                         mHeldBuffer = -1;   // Index of the one currently held by the client
+    int                         mReadyBuffer = -1;  // Index of the newest available buffer
+
+    BufferDesc                  mProcessedBuffers[2];
+    BufferDesc                  mAnalyzeBuffer GUARDED_BY(mAnalyzerLock);
+
+    BaseRenderCallback*         mRenderCallback = nullptr;
+
+    BaseAnalyzeCallback*        mAnalyzeCallback GUARDED_BY(mAnalyzerLock);
+    std::atomic<bool>           mAnalyzerRunning;
+    std::shared_mutex           mAnalyzerLock;
+    std::condition_variable_any mAnalyzerSignal;
+};
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
+#endif //EVS_VTS_STREAMHANDLER_H
+
diff --git a/evs/support_library/TexWrapper.cpp b/evs/support_library/TexWrapper.cpp
new file mode 100644
index 0000000..eb29a24
--- /dev/null
+++ b/evs/support_library/TexWrapper.cpp
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "TexWrapper.h"
+#include "glError.h"
+
+#include "log/log.h"
+
+#include <fcntl.h>
+#include <malloc.h>
+#include <png.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+/* Create an new empty GL texture that will be filled later */
+TexWrapper::TexWrapper() {
+    GLuint textureId;
+    glGenTextures(1, &textureId);
+    if (textureId <= 0) {
+        ALOGE("Didn't get a texture handle allocated: %s", getEGLError());
+    } else {
+        // Store the basic texture properties
+        id = textureId;
+        w  = 0;
+        h  = 0;
+    }
+}
+
+
+/* Wrap a texture that already allocated.  The wrapper takes ownership. */
+TexWrapper::TexWrapper(GLuint textureId, unsigned width, unsigned height) {
+    // Store the basic texture properties
+    id = textureId;
+    w  = width;
+    h  = height;
+}
+
+
+TexWrapper::~TexWrapper() {
+    // Give the texture ID back
+    if (id > 0) {
+        glDeleteTextures(1, &id);
+    }
+    id = -1;
+}
+
+
+/* Factory to build TexWrapper objects from a given PNG file */
+TexWrapper* createTextureFromPng(const char * filename)
+{
+    // Open the PNG file
+    FILE *inputFile = fopen(filename, "rb");
+    if (inputFile == 0)
+    {
+        perror(filename);
+        return nullptr;
+    }
+
+    // Read the file header and validate that it is a PNG
+    static const int kSigSize = 8;
+    png_byte header[kSigSize] = {0};
+    fread(header, 1, kSigSize, inputFile);
+    if (png_sig_cmp(header, 0, kSigSize)) {
+        printf("%s is not a PNG.\n", filename);
+        fclose(inputFile);
+        return nullptr;
+    }
+
+    // Set up our control structure
+    png_structp pngControl = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (!pngControl)
+    {
+        printf("png_create_read_struct failed.\n");
+        fclose(inputFile);
+        return nullptr;
+    }
+
+    // Set up our image info structure
+    png_infop pngInfo = png_create_info_struct(pngControl);
+    if (!pngInfo)
+    {
+        printf("error: png_create_info_struct returned 0.\n");
+        png_destroy_read_struct(&pngControl, nullptr, nullptr);
+        fclose(inputFile);
+        return nullptr;
+    }
+
+    // Install an error handler
+    if (setjmp(png_jmpbuf(pngControl))) {
+        printf("libpng reported an error\n");
+        png_destroy_read_struct(&pngControl, &pngInfo, nullptr);
+        fclose(inputFile);
+        return nullptr;
+    }
+
+    // Set up the png reader and fetch the remaining bits of the header
+    png_init_io(pngControl, inputFile);
+    png_set_sig_bytes(pngControl, kSigSize);
+    png_read_info(pngControl, pngInfo);
+
+    // Get basic information about the PNG we're reading
+    int bitDepth;
+    int colorFormat;
+    png_uint_32 width;
+    png_uint_32 height;
+    png_get_IHDR(pngControl, pngInfo,
+                 &width, &height,
+                 &bitDepth, &colorFormat,
+                 NULL, NULL, NULL);
+
+    GLint format;
+    switch(colorFormat)
+    {
+        case PNG_COLOR_TYPE_RGB:
+            format = GL_RGB;
+            break;
+        case PNG_COLOR_TYPE_RGB_ALPHA:
+            format = GL_RGBA;
+            break;
+        default:
+            printf("%s: Unknown libpng color format %d.\n", filename, colorFormat);
+            return nullptr;
+    }
+
+    // Refresh the values in the png info struct in case any transformation shave been applied.
+    png_read_update_info(pngControl, pngInfo);
+    int stride = png_get_rowbytes(pngControl, pngInfo);
+    stride += 3 - ((stride-1) % 4);   // glTexImage2d requires rows to be 4-byte aligned
+
+    // Allocate storage for the pixel data
+    png_byte * buffer = (png_byte*)malloc(stride * height);
+    if (buffer == NULL)
+    {
+        printf("error: could not allocate memory for PNG image data\n");
+        png_destroy_read_struct(&pngControl, &pngInfo, nullptr);
+        fclose(inputFile);
+        return nullptr;
+    }
+
+    // libpng needs an array of pointers into the image data for each row
+    png_byte ** rowPointers = (png_byte**)malloc(height * sizeof(png_byte*));
+    if (rowPointers == NULL)
+    {
+        printf("Failed to allocate temporary row pointers\n");
+        png_destroy_read_struct(&pngControl, &pngInfo, nullptr);
+        free(buffer);
+        fclose(inputFile);
+        return nullptr;
+    }
+    for (unsigned int r = 0; r < height; r++)
+    {
+        rowPointers[r] = buffer + r*stride;
+    }
+
+
+    // Read in the actual image bytes
+    png_read_image(pngControl, rowPointers);
+    png_read_end(pngControl, nullptr);
+
+
+    // Set up the OpenGL texture to contain this image
+    GLuint textureId;
+    glGenTextures(1, &textureId);
+    glBindTexture(GL_TEXTURE_2D, textureId);
+
+    // Send the image data to GL
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+
+    // Initialize the sampling properties (it seems the sample may not work if this isn't done)
+    // The user of this texture may very well want to set their own filtering, but we're going
+    // to pay the (minor) price of setting this up for them to avoid the dreaded "black image" if
+    // they forget.
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+    // clean up
+    png_destroy_read_struct(&pngControl, &pngInfo, nullptr);
+    free(buffer);
+    free(rowPointers);
+    fclose(inputFile);
+
+    glBindTexture(GL_TEXTURE_2D, 0);
+
+
+    // Return the texture
+    return new TexWrapper(textureId, width, height);
+}
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/evs/support_library/TexWrapper.h b/evs/support_library/TexWrapper.h
new file mode 100644
index 0000000..b26f443
--- /dev/null
+++ b/evs/support_library/TexWrapper.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef TEXWRAPPER_H
+#define TEXWRAPPER_H
+
+#include <GLES2/gl2.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+class TexWrapper {
+public:
+    TexWrapper(GLuint textureId, unsigned width, unsigned height);
+    virtual ~TexWrapper();
+
+    GLuint glId()       { return id; };
+    unsigned width()    { return w; };
+    unsigned height()   { return h; };
+
+protected:
+    TexWrapper();
+
+    GLuint id;
+    unsigned w;
+    unsigned h;
+};
+
+
+TexWrapper* createTextureFromPng(const char* filename);
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
+#endif  // TEXWRAPPER_H
diff --git a/evs/support_library/Utils.cpp b/evs/support_library/Utils.cpp
new file mode 100644
index 0000000..ae6e792
--- /dev/null
+++ b/evs/support_library/Utils.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+
+#include "ConfigManager.h"
+#include "Utils.h"
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+using namespace ::android::hardware::automotive::evs::V1_0;
+using ::android::hardware::hidl_vec;
+
+vector<string> Utils::sCameraIds;
+
+vector<string> Utils::getRearViewCameraIds() {
+    // If we already get the camera list, re-use it.
+    if (!sCameraIds.empty()) {
+        return sCameraIds;
+    }
+
+    const char* evsServiceName = "default";
+
+    // Load our configuration information
+    ConfigManager config;
+    if (!config.initialize("/system/etc/automotive/evs_support_lib/camera_config.json")) {
+        ALOGE("Missing or improper configuration for the EVS application.  Exiting.");
+        return vector<string>();
+    }
+
+    ALOGI("Acquiring EVS Enumerator");
+    sp<IEvsEnumerator> evs = IEvsEnumerator::getService(evsServiceName);
+    if (evs.get() == nullptr) {
+        ALOGE("getService(%s) returned NULL.  Exiting.", evsServiceName);
+        return vector<string>();
+    }
+
+    // static variable cannot be passed into capture, so we create a local
+    // variable instead.
+    vector<string> cameraIds;
+    ALOGD("Requesting camera list");
+    evs->getCameraList([&config, &cameraIds](hidl_vec<CameraDesc> cameraList) {
+        ALOGI("Camera list callback received %zu cameras", cameraList.size());
+        for (auto&& cam : cameraList) {
+            ALOGD("Found camera %s", cam.cameraId.c_str());
+
+            // If there are more than one rear-view cameras, return the first
+            // one.
+            for (auto&& info : config.getCameras()) {
+                if (cam.cameraId == info.cameraId) {
+                    // We found a match!
+                    if (info.function.find("reverse") != std::string::npos) {
+                        ALOGD("Camera %s is matched with reverse state",
+                              cam.cameraId.c_str());
+                        cameraIds.emplace_back(cam.cameraId);
+                    }
+                }
+            }
+        }
+    });
+    sCameraIds = cameraIds;
+    return sCameraIds;
+}
+
+string Utils::getDefaultRearViewCameraId() {
+    auto list = getRearViewCameraIds();
+    if (!list.empty()) {
+        return list[0];
+    } else {
+        return string();
+    }
+}
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/evs/support_library/Utils.h b/evs/support_library/Utils.h
new file mode 100644
index 0000000..a059175
--- /dev/null
+++ b/evs/support_library/Utils.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef CAR_LIB_EVS_SUPPORT_UTILS_H
+#define CAR_LIB_EVS_SUPPORT_UTILS_H
+
+#include <string>
+#include <vector>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+using std::vector;
+using std::string;
+
+class Utils {
+public:
+    /**
+     * Gets camera ids for all the available rear view cameras. For
+     * now, we don't support dynamically adding/removing camera. In
+     * other words, the camera list won't be updated after the first
+     * time the camera list is obtained.
+     *
+     * An empty vector is returned if no rear view camera is found.
+     */
+    static vector<string> getRearViewCameraIds();
+
+    /**
+     * Gets camera id for the default rear view camera. For now, we
+     * always assume that the first element in rear view camera list
+     * is the default one.
+     *
+     * An empty string is returned if no rear view camera is found.
+     */
+    static string getDefaultRearViewCameraId();
+
+private:
+    static vector<string> sCameraIds;
+};
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
+#endif  // CAR_LIB_EVS_SUPPORT_UTILS_H
diff --git a/evs/support_library/VideoTex.cpp b/evs/support_library/VideoTex.cpp
new file mode 100644
index 0000000..0f0397a
--- /dev/null
+++ b/evs/support_library/VideoTex.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vector>
+#include <stdio.h>
+#include <fcntl.h>
+#include <alloca.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <malloc.h>
+#include <png.h>
+
+#include "VideoTex.h"
+#include "glError.h"
+
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+// Eventually we shouldn't need this dependency, but for now the
+// graphics allocator interface isn't fully supported on all platforms
+// and this is our work around.
+using ::android::GraphicBuffer;
+
+
+VideoTex::VideoTex(EGLDisplay glDisplay)
+    : TexWrapper()
+    , mDisplay(glDisplay) {
+    // Nothing but initialization here...
+}
+
+VideoTex::~VideoTex() {
+    // Drop our device texture image
+    if (mKHRimage != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(mDisplay, mKHRimage);
+        mKHRimage = EGL_NO_IMAGE_KHR;
+    }
+}
+
+
+// Return true if the texture contents are changed
+bool VideoTex::refresh(const BufferDesc& imageBuffer) {
+    // No new image has been delivered, so there's nothing to do here
+    if (imageBuffer.memHandle.getNativeHandle() == nullptr) {
+        return false;
+    }
+
+    // Drop our device texture image
+    if (mKHRimage != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(mDisplay, mKHRimage);
+        mKHRimage = EGL_NO_IMAGE_KHR;
+    }
+
+    // create a GraphicBuffer from the existing handle
+    sp<GraphicBuffer> imageGraphicBuffer = new GraphicBuffer(
+        imageBuffer.memHandle, GraphicBuffer::CLONE_HANDLE, imageBuffer.width,
+        imageBuffer.height, imageBuffer.format, 1, // layer count
+        GRALLOC_USAGE_HW_TEXTURE, imageBuffer.stride);
+
+    if (imageGraphicBuffer.get() == nullptr) {
+        ALOGE("Failed to allocate GraphicBuffer to wrap image handle");
+        // Returning "true" in this error condition because we already released the
+        // previous image (if any) and so the texture may change in unpredictable ways now!
+        return true;
+    }
+
+
+    // Get a GL compatible reference to the graphics buffer we've been given
+    EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
+    EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(imageGraphicBuffer->getNativeBuffer());
+    mKHRimage = eglCreateImageKHR(mDisplay, EGL_NO_CONTEXT,
+                                  EGL_NATIVE_BUFFER_ANDROID, clientBuf,
+                                  eglImageAttributes);
+    if (mKHRimage == EGL_NO_IMAGE_KHR) {
+        const char *msg = getEGLError();
+        ALOGE("error creating EGLImage: %s", msg);
+        return false;
+    } else {
+        // Update the texture handle we already created to refer to this gralloc buffer
+        glActiveTexture(GL_TEXTURE0);
+        glBindTexture(GL_TEXTURE_2D, glId());
+        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast<GLeglImageOES>(mKHRimage));
+
+        // Initialize the sampling properties (it seems the sample may not work if this isn't done)
+        // The user of this texture may very well want to set their own filtering, but we're going
+        // to pay the (minor) price of setting this up for them to avoid the dreaded "black image"
+        // if they forget.
+        // TODO:  Can we do this once for the texture ID rather than ever refresh?
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    }
+
+    return true;
+}
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/evs/support_library/VideoTex.h b/evs/support_library/VideoTex.h
new file mode 100644
index 0000000..58a1882
--- /dev/null
+++ b/evs/support_library/VideoTex.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef VIDEOTEX_H
+#define VIDEOTEX_H
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+
+#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
+
+#include "BaseRenderCallback.h"
+#include "StreamHandler.h"
+#include "TexWrapper.h"
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+using namespace ::android::hardware::automotive::evs::V1_0;
+
+
+class VideoTex: public TexWrapper {
+public:
+    VideoTex() = delete;
+    VideoTex(EGLDisplay glDisplay);
+    virtual ~VideoTex();
+
+    // returns true if the texture contents were updated
+    bool refresh(const BufferDesc& imageBuffer);
+
+private:
+    EGLDisplay          mDisplay;
+    EGLImageKHR mKHRimage = EGL_NO_IMAGE_KHR;
+};
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
+#endif  // VIDEOTEX_H
diff --git a/evs/app/config.json b/evs/support_library/config.json
similarity index 100%
rename from evs/app/config.json
rename to evs/support_library/config.json
diff --git a/evs/support_library/glError.cpp b/evs/support_library/glError.cpp
new file mode 100644
index 0000000..6c96455
--- /dev/null
+++ b/evs/support_library/glError.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <EGL/egl.h>
+#include <GLES3/gl3.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+const char *getEGLError(void) {
+    switch (eglGetError()) {
+        case EGL_SUCCESS:
+            return "EGL_SUCCESS";
+        case EGL_NOT_INITIALIZED:
+            return "EGL_NOT_INITIALIZED";
+        case EGL_BAD_ACCESS:
+            return "EGL_BAD_ACCESS";
+        case EGL_BAD_ALLOC:
+            return "EGL_BAD_ALLOC";
+        case EGL_BAD_ATTRIBUTE:
+            return "EGL_BAD_ATTRIBUTE";
+        case EGL_BAD_CONTEXT:
+            return "EGL_BAD_CONTEXT";
+        case EGL_BAD_CONFIG:
+            return "EGL_BAD_CONFIG";
+        case EGL_BAD_CURRENT_SURFACE:
+            return "EGL_BAD_CURRENT_SURFACE";
+        case EGL_BAD_DISPLAY:
+            return "EGL_BAD_DISPLAY";
+        case EGL_BAD_SURFACE:
+            return "EGL_BAD_SURFACE";
+        case EGL_BAD_MATCH:
+            return "EGL_BAD_MATCH";
+        case EGL_BAD_PARAMETER:
+            return "EGL_BAD_PARAMETER";
+        case EGL_BAD_NATIVE_PIXMAP:
+            return "EGL_BAD_NATIVE_PIXMAP";
+        case EGL_BAD_NATIVE_WINDOW:
+            return "EGL_BAD_NATIVE_WINDOW";
+        case EGL_CONTEXT_LOST:
+            return "EGL_CONTEXT_LOST";
+        default:
+            return "Unknown error";
+    }
+}
+
+
+const char *getGLFramebufferError(void) {
+    switch (glCheckFramebufferStatus(GL_FRAMEBUFFER)) {
+    case GL_FRAMEBUFFER_COMPLETE:
+        return "GL_FRAMEBUFFER_COMPLETE";
+    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
+        return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
+    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
+        return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
+    case GL_FRAMEBUFFER_UNSUPPORTED:
+        return "GL_FRAMEBUFFER_UNSUPPORTED";
+    case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
+        return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
+    default:
+        return "Unknown error";
+    }
+}
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
diff --git a/evs/support_library/glError.h b/evs/support_library/glError.h
new file mode 100644
index 0000000..636860a
--- /dev/null
+++ b/evs/support_library/glError.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GLERROR_H
+#define GLERROR_H
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace support {
+
+const char *getEGLError(void);
+
+const char *getGLFramebufferError(void);
+
+}  // namespace support
+}  // namespace evs
+}  // namespace automotive
+}  // namespace android
+
+#endif  // GLERROR_H
diff --git a/evs/app/shader.cpp b/evs/support_library/shader.cpp
similarity index 100%
copy from evs/app/shader.cpp
copy to evs/support_library/shader.cpp
diff --git a/evs/app/shader.h b/evs/support_library/shader.h
similarity index 100%
copy from evs/app/shader.h
copy to evs/support_library/shader.h
diff --git a/evs/app/shader_projectedTex.h b/evs/support_library/shader_projectedTex.h
similarity index 100%
copy from evs/app/shader_projectedTex.h
copy to evs/support_library/shader_projectedTex.h
diff --git a/evs/app/shader_simpleTex.h b/evs/support_library/shader_simpleTex.h
similarity index 100%
copy from evs/app/shader_simpleTex.h
copy to evs/support_library/shader_simpleTex.h
diff --git a/experimental/experimental_api/Android.bp b/experimental/experimental_api/Android.bp
new file mode 100644
index 0000000..24e9b99
--- /dev/null
+++ b/experimental/experimental_api/Android.bp
@@ -0,0 +1,37 @@
+// 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.
+//
+//
+
+// Experimental API backed by Experimental Car service.
+
+java_library {
+
+    name: "car-experimental-api-static-lib",
+
+    srcs: [
+            "src/**/*.java",
+            "src/**/*.aidl"
+        ],
+
+    libs: ["android.car"],
+
+    platform_apis: true,
+
+    product_variables: {
+            pdk: {
+                enabled: false,
+            },
+    },
+}
diff --git a/experimental/experimental_api/src/android/car/experimental/CarDriverDistractionManager.java b/experimental/experimental_api/src/android/car/experimental/CarDriverDistractionManager.java
new file mode 100644
index 0000000..1a1e1cc
--- /dev/null
+++ b/experimental/experimental_api/src/android/car/experimental/CarDriverDistractionManager.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.experimental;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.car.Car;
+import android.car.CarManagerBase;
+import android.car.annotation.RequiredFeature;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Experimental APIs that allow clients to consume information about a driver's current distraction
+ * level.
+ *
+ * @hide
+ */
+@RequiredFeature(ExperimentalCar.TEST_EXPERIMENTAL_FEATURE_SERVICE)
+public final class CarDriverDistractionManager extends CarManagerBase {
+
+    private static final String TAG = "CarDriverDistractionManager";
+    private static final int MSG_HANDLE_DISTRACTION_CHANGE = 0;
+
+    private final IDriverDistractionManager mService;
+    private final EventHandler mEventHandler;
+
+    private final IDriverDistractionChangeListenerImpl mBinderCallback;
+
+    /**
+     * Listener to monitor any changes to the driver's distraction level.
+     */
+    public interface OnDriverDistractionChangeListener {
+        /**
+         * Called when the driver's distraction level has changed.
+         *
+         * @param event the new driver distraction information.
+         */
+        void onDriverDistractionChange(DriverDistractionChangeEvent event);
+    }
+
+    private final CopyOnWriteArrayList<OnDriverDistractionChangeListener> mListeners =
+            new CopyOnWriteArrayList<>();
+
+    /**
+     * Constructor parameters should remain this way for Car library to construct this.
+     */
+    public CarDriverDistractionManager(Car car, IBinder service) {
+        super(car);
+        mService = IDriverDistractionManager.Stub.asInterface(service);
+        mEventHandler = new EventHandler(this, getEventHandler().getLooper());
+        mBinderCallback = new IDriverDistractionChangeListenerImpl(this);
+    }
+
+    /**
+     * Gets the current driver distraction level based on the last change event that is not stale.
+     *
+     * Return {@code null} if there is an internal error.
+     */
+    @RequiresPermission(value = ExperimentalCar.PERMISSION_READ_CAR_DRIVER_DISTRACTION)
+    @Nullable
+    public DriverDistractionChangeEvent getLastDistractionEvent() {
+        try {
+            return mService.getLastDistractionEvent();
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, null);
+        }
+    }
+
+    /**
+     * Adds a {@link OnDriverDistractionChangeListener} to be notified for changes to the driver's
+     * distraction level.
+     *
+     * <p>The provided listener will immediately receive a callback for the most recent distraction
+     * event.
+     *
+     * @param listener to be added
+     */
+    @RequiresPermission(value = ExperimentalCar.PERMISSION_READ_CAR_DRIVER_DISTRACTION)
+    public void addDriverDistractionChangeListener(
+            @NonNull OnDriverDistractionChangeListener listener) {
+        if (mListeners.addIfAbsent(listener)) {
+            if (mListeners.size() == 1) {
+                try {
+                    mService.addDriverDistractionChangeListener(mBinderCallback);
+                } catch (RemoteException e) {
+                    handleRemoteExceptionFromCarService(e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Removes the listener. Listeners not added before will be ignored.
+     */
+    @RequiresPermission(value = ExperimentalCar.PERMISSION_READ_CAR_DRIVER_DISTRACTION)
+    public void removeDriverDistractionChangeListener(
+            @NonNull OnDriverDistractionChangeListener listener) {
+        if (mListeners.remove(listener)) {
+            if (mListeners.size() == 0) {
+                try {
+                    mService.removeDriverDistractionChangeListener(mBinderCallback);
+                } catch (RemoteException ignored) {
+                    // ignore for unregistering
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void onCarDisconnected() {
+        // nothing to do
+    }
+
+    private void dispatchDistractionChangeToClient(
+            DriverDistractionChangeEvent distractionChangeEvent) {
+        if (distractionChangeEvent == null) {
+            return;
+        }
+        for (OnDriverDistractionChangeListener listener : mListeners) {
+            listener.onDriverDistractionChange(distractionChangeEvent);
+        }
+    }
+
+    private static final class EventHandler extends Handler {
+        private final WeakReference<CarDriverDistractionManager> mDistractionManager;
+
+        EventHandler(CarDriverDistractionManager manager, Looper looper) {
+            super(looper);
+            mDistractionManager = new WeakReference<>(manager);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            CarDriverDistractionManager mgr = mDistractionManager.get();
+            if (mgr == null) {
+                Log.e(TAG,
+                        "handleMessage: null reference to distraction manager when handling "
+                                + "message for " + msg.what);
+                return;
+            }
+            switch (msg.what) {
+                case MSG_HANDLE_DISTRACTION_CHANGE:
+                    mgr.dispatchDistractionChangeToClient((DriverDistractionChangeEvent) msg.obj);
+                    break;
+                default:
+                    Log.e(TAG, "Unknown msg not handled:" + msg.what);
+            }
+        }
+
+        private void dispatchOnDistractionChangedEvent(DriverDistractionChangeEvent event) {
+            sendMessage(obtainMessage(MSG_HANDLE_DISTRACTION_CHANGE, event));
+        }
+    }
+
+    private static class IDriverDistractionChangeListenerImpl extends
+            IDriverDistractionChangeListener.Stub {
+        private final WeakReference<CarDriverDistractionManager> mDistractionManager;
+
+        IDriverDistractionChangeListenerImpl(CarDriverDistractionManager manager) {
+            mDistractionManager = new WeakReference<>(manager);
+        }
+
+        @Override
+        public void onDriverDistractionChange(DriverDistractionChangeEvent event) {
+            CarDriverDistractionManager manager = mDistractionManager.get();
+            if (manager != null) {
+                manager.mEventHandler.dispatchOnDistractionChangedEvent(event);
+            }
+        }
+    }
+}
diff --git a/experimental/experimental_api/src/android/car/experimental/CarTestDemoExperimentalFeatureManager.java b/experimental/experimental_api/src/android/car/experimental/CarTestDemoExperimentalFeatureManager.java
new file mode 100644
index 0000000..517165e
--- /dev/null
+++ b/experimental/experimental_api/src/android/car/experimental/CarTestDemoExperimentalFeatureManager.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.experimental;
+
+import android.car.Car;
+import android.car.CarManagerBase;
+import android.car.annotation.RequiredFeature;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+/**
+ * Demo CarManager API for demonstrating experimental feature / API usage. This will never go to
+ * production.
+ *
+ * @hide
+ */
+@RequiredFeature(ExperimentalCar.TEST_EXPERIMENTAL_FEATURE_SERVICE)
+public final class CarTestDemoExperimentalFeatureManager extends CarManagerBase {
+
+    private final ITestDemoExperimental mService;
+
+    /**
+     * Constructor parameters should remain this way for Car library to construct this.
+     */
+    public CarTestDemoExperimentalFeatureManager(Car car, IBinder service) {
+        super(car);
+        mService = ITestDemoExperimental.Stub.asInterface(service);
+    }
+
+    /**
+     * Send ping msg service. It will replay back with the same message.
+     */
+    public String ping(String msg) {
+        try {
+            return mService.ping(msg);
+        } catch (RemoteException e) {
+            // For experimental API, we just crash client.
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    protected void onCarDisconnected() {
+        // Nothing to do
+    }
+}
diff --git a/experimental/experimental_api/src/android/car/experimental/DriverAwarenessEvent.aidl b/experimental/experimental_api/src/android/car/experimental/DriverAwarenessEvent.aidl
new file mode 100644
index 0000000..e9f38b5
--- /dev/null
+++ b/experimental/experimental_api/src/android/car/experimental/DriverAwarenessEvent.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.experimental;
+
+parcelable DriverAwarenessEvent;
\ No newline at end of file
diff --git a/experimental/experimental_api/src/android/car/experimental/DriverAwarenessEvent.java b/experimental/experimental_api/src/android/car/experimental/DriverAwarenessEvent.java
new file mode 100644
index 0000000..19134ed
--- /dev/null
+++ b/experimental/experimental_api/src/android/car/experimental/DriverAwarenessEvent.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.experimental;
+
+import android.annotation.FloatRange;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Event about a driver's awareness level at a certain point in time.
+ *
+ * <p>Driver Awareness is an abstract concept based on a driver's cognitive situational awareness
+ * of the environment around them. This metric can be approximated based on signals about the
+ * driver's behavior, such as where they are looking or how much their interact with the headunit
+ * in the car.
+ *
+ * <p>Furthermore, what constitutes the boundaries of no awareness and full awareness must be based
+ * on the UX Research through real-world studies and driving simulation. It is the responsibility
+ * of {@link DriverAwarenessSupplier}s to understand how their sensor input fits with current
+ * research in order to determine the appropriate awareness value.
+ *
+ * @hide
+ */
+public final class DriverAwarenessEvent implements Parcelable {
+
+    private final long mTimeStamp;
+
+    @FloatRange(from = 0.0f, to = 1.0f)
+    private final float mAwarenessValue;
+
+    /**
+     * Creator for {@link Parcelable}.
+     */
+    public static final Parcelable.Creator<DriverAwarenessEvent> CREATOR =
+            new Parcelable.Creator<DriverAwarenessEvent>() {
+                public DriverAwarenessEvent createFromParcel(Parcel in) {
+                    return new DriverAwarenessEvent(in);
+                }
+
+                public DriverAwarenessEvent[] newArray(int size) {
+                    return new DriverAwarenessEvent[size];
+                }
+            };
+
+    /**
+     * Creates an instance of a {@link DriverAwarenessEvent}.
+     *
+     * @param timeStamp      the time that the awareness value was sampled, in milliseconds elapsed
+     *                       since system boot
+     * @param awarenessValue the driver's awareness level at this point in time, ranging from 0, no
+     *                       awareness, to 1, full awareness
+     */
+    public DriverAwarenessEvent(long timeStamp,
+            @FloatRange(from = 0.0f, to = 1.0f) float awarenessValue) {
+        mTimeStamp = timeStamp;
+        mAwarenessValue = awarenessValue;
+    }
+
+    /**
+     * Parcelable constructor.
+     */
+    private DriverAwarenessEvent(Parcel in) {
+        mTimeStamp = in.readLong();
+        mAwarenessValue = in.readFloat();
+    }
+
+    /**
+     * Returns the time at which this driver awareness value was inferred based on the car's
+     * sensors. It is the elapsed time in milliseconds since system boot.
+     */
+    public long getTimeStamp() {
+        return mTimeStamp;
+    }
+
+    /**
+     * The current driver awareness value, where 0 is no awareness and 1 is full awareness.
+     */
+    @FloatRange(from = 0.0f, to = 1.0f)
+    public float getAwarenessValue() {
+        return mAwarenessValue;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(mTimeStamp);
+        dest.writeFloat(mAwarenessValue);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof DriverAwarenessEvent)) {
+            return false;
+        }
+        DriverAwarenessEvent that = (DriverAwarenessEvent) o;
+        return mTimeStamp == that.mTimeStamp
+                && Float.compare(that.mAwarenessValue, mAwarenessValue) == 0;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mTimeStamp, mAwarenessValue);
+    }
+
+    @Override
+    public String toString() {
+        return String.format("DriverAwarenessEvent{timeStamp=%s, awarenessValue=%s}",
+                mTimeStamp, mAwarenessValue);
+    }
+}
diff --git a/experimental/experimental_api/src/android/car/experimental/DriverAwarenessSupplierConfig.aidl b/experimental/experimental_api/src/android/car/experimental/DriverAwarenessSupplierConfig.aidl
new file mode 100644
index 0000000..f7b1398
--- /dev/null
+++ b/experimental/experimental_api/src/android/car/experimental/DriverAwarenessSupplierConfig.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.experimental;
+
+parcelable DriverAwarenessSupplierConfig;
\ No newline at end of file
diff --git a/experimental/experimental_api/src/android/car/experimental/DriverAwarenessSupplierConfig.java b/experimental/experimental_api/src/android/car/experimental/DriverAwarenessSupplierConfig.java
new file mode 100644
index 0000000..1fd867a
--- /dev/null
+++ b/experimental/experimental_api/src/android/car/experimental/DriverAwarenessSupplierConfig.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.experimental;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Configuration for an instance of {@link android.car.experimental.IDriverAwarenessSupplier}.
+ */
+public class DriverAwarenessSupplierConfig implements Parcelable {
+
+    private final long mMaxStalenessMillis;
+
+    /**
+     * Creator for {@link Parcelable}.
+     */
+    public static final Parcelable.Creator<DriverAwarenessSupplierConfig> CREATOR =
+            new Parcelable.Creator<DriverAwarenessSupplierConfig>() {
+                public DriverAwarenessSupplierConfig createFromParcel(Parcel in) {
+                    return new DriverAwarenessSupplierConfig(in);
+                }
+
+                public DriverAwarenessSupplierConfig[] newArray(int size) {
+                    return new DriverAwarenessSupplierConfig[size];
+                }
+            };
+
+    /**
+     * Creates an instance of a {@link DriverAwarenessSupplierConfig}.
+     */
+    public DriverAwarenessSupplierConfig(long maxStalenessMillis) {
+        mMaxStalenessMillis = maxStalenessMillis;
+    }
+
+    /**
+     * Parcelable constructor.
+     */
+    private DriverAwarenessSupplierConfig(Parcel in) {
+        mMaxStalenessMillis = in.readLong();
+    }
+
+    /**
+     * Returns the duration in milliseconds after which the input from this supplier should be
+     * considered stale.
+     *
+     * <p>Data should be sent more frequently than the staleness rate defined here.
+     */
+    public long getMaxStalenessMillis() {
+        return mMaxStalenessMillis;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(mMaxStalenessMillis);
+    }
+
+
+    @Override
+    public String toString() {
+        return String.format("DriverAwarenessEvent{mMaxStalenessMillis=%s}", mMaxStalenessMillis);
+    }
+}
diff --git a/experimental/experimental_api/src/android/car/experimental/DriverAwarenessSupplierService.java b/experimental/experimental_api/src/android/car/experimental/DriverAwarenessSupplierService.java
new file mode 100644
index 0000000..c904428
--- /dev/null
+++ b/experimental/experimental_api/src/android/car/experimental/DriverAwarenessSupplierService.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.experimental;
+
+
+import android.annotation.CallSuper;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * The supplier for providing a stream of the driver's current situational awareness.
+ *
+ * <p>A perfect understanding of driver awareness requires years of extensive research and signals
+ * that suggest the cognitive situational awareness of the driver. Implementations of this class
+ * attempt to approximate driver awareness using concrete, but less accurate signals, such as gaze
+ * or touch.
+ *
+ * <p>Suppliers should notify of updates to the driver awareness level through {@link
+ * #onDriverAwarenessUpdated(DriverAwarenessEvent)}.
+ *
+ * <p>Suppliers define the amount of time until their data should be considered stale through
+ * {@link #getMaxStalenessMillis()}. After that amount of time data from this supplier will no
+ * longer be considered fresh. {@link #NO_STALENESS} is meant to be used by change-based suppliers
+ * such as a touch supplier - it is not appropriate for data signals that change continuous over
+ * time.
+ *
+ * <p>If this supplier has its own internal configuration, that configuration must be configurable
+ * by locale.
+ *
+ * <p>It is the attention supplier's responsibility to make sure that it only sends high-quality
+ * data events.
+ */
+public abstract class DriverAwarenessSupplierService extends Service {
+    private static final String TAG = "DriverAwarenessSupplierService";
+
+    /**
+     * Value that can be returned by {@link #getMaxStalenessMillis()} to indicate that an attention
+     * supplier sends change-events instead of push events on a regular interval. Should only be
+     * used for a supplier that is guaranteed to always be running (e.g. it won't crash or have
+     * periods of poor data).
+     */
+    public static final long NO_STALENESS = -1;
+
+    private final Object mLock = new Object();
+
+    private SupplierBinder mSupplierBinder;
+
+    @GuardedBy("mLock")
+    private IDriverAwarenessSupplierCallback mDriverAwarenessSupplierCallback;
+
+    /**
+     * Returns the duration in milliseconds after which the input from this supplier should be
+     * considered stale. This method should return a positive value greater than 0. There is no
+     * technical limit on the value returned here, but a value of 1000ms (1 second) would likely be
+     * considered too high since the driving environment can change drastically in that amount of
+     * time.
+     *
+     * <p>This can also return {@link #NO_STALENESS} if the supplier only emits change events and
+     * has no risk of failing to emit those change events within a reasonable amount of time.
+     *
+     * <p>Data should be sent more frequently than the staleness period defined here.
+     */
+    public abstract long getMaxStalenessMillis();
+
+    /**
+     * The distraction service is ready to start receiving events via {@link
+     * #onDriverAwarenessUpdated(DriverAwarenessEvent)}.
+     */
+    protected abstract void onReady();
+
+    @Override
+    @CallSuper
+    public IBinder onBind(Intent intent) {
+        logd("onBind, intent: " + intent);
+        if (mSupplierBinder == null) {
+            mSupplierBinder = new SupplierBinder();
+        }
+        return mSupplierBinder;
+    }
+
+    /**
+     * The driver awareness has changed - emit that update to the {@link
+     * com.android.experimentalcar.DriverDistractionExperimentalFeatureService}.
+     */
+    protected void onDriverAwarenessUpdated(DriverAwarenessEvent event) {
+        logd("onDriverAwarenessUpdated: " + event);
+        synchronized (mLock) {
+            if (mDriverAwarenessSupplierCallback != null) {
+                try {
+                    mDriverAwarenessSupplierCallback.onDriverAwarenessUpdated(event);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Remote exception", e);
+                }
+            }
+        }
+    }
+
+    private void handleReady() {
+        synchronized (mLock) {
+            try {
+                mDriverAwarenessSupplierCallback.onConfigLoaded(
+                        new DriverAwarenessSupplierConfig(getMaxStalenessMillis()));
+            } catch (RemoteException e) {
+                Log.e(TAG, "Unable to send config - abandoning ready process", e);
+                return;
+            }
+        }
+        onReady();
+    }
+
+    /**
+     * The binder between this service and
+     * {@link com.android.experimentalcar.DriverDistractionExperimentalFeatureService}.
+     */
+    @VisibleForTesting
+    public class SupplierBinder extends IDriverAwarenessSupplier.Stub {
+
+        @Override
+        public void onReady() {
+            handleReady();
+        }
+
+        @Override
+        public void setCallback(IDriverAwarenessSupplierCallback callback) {
+            synchronized (mLock) {
+                mDriverAwarenessSupplierCallback = callback;
+            }
+        }
+    }
+
+    private static void logd(String message) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, message);
+        }
+    }
+}
diff --git a/experimental/experimental_api/src/android/car/experimental/DriverDistractionChangeEvent.aidl b/experimental/experimental_api/src/android/car/experimental/DriverDistractionChangeEvent.aidl
new file mode 100644
index 0000000..dfd44ac
--- /dev/null
+++ b/experimental/experimental_api/src/android/car/experimental/DriverDistractionChangeEvent.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.experimental;
+
+parcelable DriverDistractionChangeEvent;
diff --git a/experimental/experimental_api/src/android/car/experimental/DriverDistractionChangeEvent.java b/experimental/experimental_api/src/android/car/experimental/DriverDistractionChangeEvent.java
new file mode 100644
index 0000000..0f619bd
--- /dev/null
+++ b/experimental/experimental_api/src/android/car/experimental/DriverDistractionChangeEvent.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.experimental;
+
+import android.annotation.FloatRange;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+
+/**
+ * Event about a change in the driver's distraction.
+ *
+ * @hide
+ */
+public class DriverDistractionChangeEvent implements Parcelable {
+
+    private final long mElapsedRealtimeTimestamp;
+
+    @FloatRange(from = 0.0f, to = 1.0f)
+    private final float mAwarenessPercentage;
+
+    /**
+     * Creator for {@link Parcelable}.
+     */
+    public static final Parcelable.Creator<DriverDistractionChangeEvent> CREATOR =
+            new Parcelable.Creator<DriverDistractionChangeEvent>() {
+                public DriverDistractionChangeEvent createFromParcel(Parcel in) {
+                    return new DriverDistractionChangeEvent(in);
+                }
+
+                public DriverDistractionChangeEvent[] newArray(int size) {
+                    return new DriverDistractionChangeEvent[size];
+                }
+            };
+
+
+    private DriverDistractionChangeEvent(Builder builder) {
+        mElapsedRealtimeTimestamp = builder.mElapsedRealtimeTimestamp;
+        mAwarenessPercentage = builder.mAwarenessPercentage;
+    }
+
+    /**
+     * Parcelable constructor.
+     */
+    private DriverDistractionChangeEvent(Parcel in) {
+        mElapsedRealtimeTimestamp = in.readLong();
+        mAwarenessPercentage = in.readFloat();
+    }
+
+    /**
+     * Returns the timestamp for the change event, in milliseconds since boot, including time spent
+     * in sleep.
+     */
+    public long getElapsedRealtimeTimestamp() {
+        return mElapsedRealtimeTimestamp;
+    }
+
+    /**
+     * Returns the current driver driver awareness value as a percentage of the required awareness
+     * of the situation.
+     * <ul>
+     * <li>0% indicates that the driver has no situational awareness of the surrounding environment.
+     * <li>100% indicates that the driver has the target amount of situational awareness
+     * necessary for the current driving environment.
+     * </ul>
+     *
+     * <p>If the required awareness of the current driving environment is 0, such as when the car
+     * is in park, then the awareness percentage will be 100%.
+     *
+     * <p>Since this is a percentage, 0% will always correspond with a 0.0 driver awareness level.
+     * However, the rest of the range will get squeezed or compressed in time depending on the
+     * required awareness of the situation.
+     *
+     * <p>For example, suppose that driver awareness can go from 1.0 to 0.0 with 6 seconds of
+     * eyes-off-road time and that the driver has just started looking off-road. Now consider
+     * these two scenarios:
+     * <ol>
+     * <li>Scenario 1: The required awareness of the driving environment is 1.0:
+     * After 0 seconds: 100% awareness
+     * After 3 seconds: 50% awareness
+     * After 4.5 seconds: 25% awareness
+     * After 6 seconds: 0% awareness
+     * <li>Scenario 2: The required awareness of the driving environment is 0.5:
+     * After 0 seconds: 100% awareness
+     * After 3 seconds: 100% awareness
+     * After 4.5 seconds: 50% awareness
+     * After 6 seconds: 0% awareness
+     * </ol>
+     */
+    @FloatRange(from = 0.0f, to = 1.0f)
+    public float getAwarenessPercentage() {
+        return mAwarenessPercentage;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(mElapsedRealtimeTimestamp);
+        dest.writeFloat(mAwarenessPercentage);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof DriverDistractionChangeEvent)) {
+            return false;
+        }
+        DriverDistractionChangeEvent that = (DriverDistractionChangeEvent) o;
+        return mElapsedRealtimeTimestamp == that.mElapsedRealtimeTimestamp
+                && Float.compare(that.mAwarenessPercentage, mAwarenessPercentage) == 0;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mElapsedRealtimeTimestamp, mAwarenessPercentage);
+    }
+
+    @Override
+    public String toString() {
+        return String.format(
+                "DriverDistractionChangeEvent{mElapsedRealtimeTimestamp=%s, "
+                        + "mAwarenessPercentage=%s}",
+                mElapsedRealtimeTimestamp, mAwarenessPercentage);
+    }
+
+
+    /**
+     * Builder for {@link DriverDistractionChangeEvent}.
+     */
+    public static class Builder {
+        private long mElapsedRealtimeTimestamp;
+
+        @FloatRange(from = 0.0f, to = 1.0f)
+        private float mAwarenessPercentage;
+
+        /**
+         * Set the timestamp for the change event, in milliseconds since boot, including time spent
+         * in sleep.
+         */
+        public Builder setElapsedRealtimeTimestamp(long timestamp) {
+            mElapsedRealtimeTimestamp = timestamp;
+            return this;
+        }
+
+        /**
+         * Set the current driver driver awareness value as a percentage of the required awareness
+         * of the situation.
+         */
+        public Builder setAwarenessPercentage(
+                @FloatRange(from = 0.0f, to = 1.0f) float awarenessPercentage) {
+            Preconditions.checkArgument(
+                    awarenessPercentage >= 0 && awarenessPercentage <= 1,
+                    "awarenessPercentage must be between 0 and 1");
+            mAwarenessPercentage = awarenessPercentage;
+            return this;
+        }
+
+        /**
+         * Build and return the {@link DriverDistractionChangeEvent} object.
+         */
+        public DriverDistractionChangeEvent build() {
+            return new DriverDistractionChangeEvent(this);
+        }
+
+    }
+
+}
diff --git a/experimental/experimental_api/src/android/car/experimental/ExperimentalCar.java b/experimental/experimental_api/src/android/car/experimental/ExperimentalCar.java
new file mode 100644
index 0000000..0f4c43f
--- /dev/null
+++ b/experimental/experimental_api/src/android/car/experimental/ExperimentalCar.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.experimental;
+
+import android.car.annotation.ExperimentalFeature;
+
+/**
+ * Top level class for experimental Car features
+ *
+ * @hide
+ */
+public final class ExperimentalCar {
+    /**
+     * Service for testing experimental feature
+     *
+     * @hide
+     */
+    @ExperimentalFeature
+    public static final String TEST_EXPERIMENTAL_FEATURE_SERVICE =
+            "android.car.experimental.test_demo_experimental_feature_service";
+
+    /**
+     * Service for monitoring the driver distraction level.
+     *
+     * @hide
+     */
+    @ExperimentalFeature
+    public static final String DRIVER_DISTRACTION_EXPERIMENTAL_FEATURE_SERVICE =
+            "android.car.experimental.driver_distraction_experimental_feature_service";
+
+
+    /**
+     * Permission necessary to observe the driver distraction level through {@link
+     * CarDriverDistractionManager}.
+     *
+     * @hide
+     */
+    public static final String PERMISSION_READ_CAR_DRIVER_DISTRACTION =
+            "android.car.permission.CAR_DRIVER_DISTRACTION";
+}
diff --git a/experimental/experimental_api/src/android/car/experimental/IDriverAwarenessSupplier.aidl b/experimental/experimental_api/src/android/car/experimental/IDriverAwarenessSupplier.aidl
new file mode 100644
index 0000000..6eaadeb
--- /dev/null
+++ b/experimental/experimental_api/src/android/car/experimental/IDriverAwarenessSupplier.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.experimental;
+
+import android.car.experimental.IDriverAwarenessSupplierCallback;
+
+/**
+ * Binder API for a driver awareness supplier.
+ *
+ * @hide
+ */
+oneway interface IDriverAwarenessSupplier {
+
+    /** Called once the distraction service is ready to receive events */
+    void onReady() = 0;
+
+    /** Set the callback to be used for this supplier */
+    void setCallback(IDriverAwarenessSupplierCallback callback) = 1;
+}
\ No newline at end of file
diff --git a/experimental/experimental_api/src/android/car/experimental/IDriverAwarenessSupplierCallback.aidl b/experimental/experimental_api/src/android/car/experimental/IDriverAwarenessSupplierCallback.aidl
new file mode 100644
index 0000000..7b6ec1f
--- /dev/null
+++ b/experimental/experimental_api/src/android/car/experimental/IDriverAwarenessSupplierCallback.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.experimental;
+
+import android.car.experimental.DriverAwarenessEvent;
+import android.car.experimental.DriverAwarenessSupplierConfig;
+
+/**
+ * Binder callback for IDriverAwarenessSupplier.
+ *
+ * @hide
+ */
+interface IDriverAwarenessSupplierCallback {
+   /**
+    * Sets the awareness level for the driver. Determining sufficient data quality is the
+    * responsibility of the AwarenessSupplier and events with insufficient data quality should not
+    * be sent.
+    *
+    * <p>Suppliers could crash in the background or fail to send continuously high data and
+    * therefore should push events, even if the Awareness level hasn't changed, with a frequency
+    * greater than their specified AwarenessSupplier#getMaxStalenessMillis().
+    *
+    * <p>Should be called once when first registered.
+    *
+    * @param event a snapshot of the driver's awareness at a certain point in time.
+    */
+   void onDriverAwarenessUpdated(in DriverAwarenessEvent event) = 0;
+
+   /**
+    * Sends the configuration for IDriverAwarenessSupplier configuration that this is a callback
+    * for.
+    *
+    * @param config for the IDriverAwarenessSupplier
+    */
+   void onConfigLoaded(in DriverAwarenessSupplierConfig config) = 1;
+}
diff --git a/experimental/experimental_api/src/android/car/experimental/IDriverDistractionChangeListener.aidl b/experimental/experimental_api/src/android/car/experimental/IDriverDistractionChangeListener.aidl
new file mode 100644
index 0000000..10fbb7a
--- /dev/null
+++ b/experimental/experimental_api/src/android/car/experimental/IDriverDistractionChangeListener.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.experimental;
+
+import android.car.experimental.DriverDistractionChangeEvent;
+
+/**
+ * Binder callback for changes to the driver's distraction level.
+ * @hide
+ */
+oneway interface IDriverDistractionChangeListener {
+   /**
+    * Called when the driver's distraction level has changed.
+    *
+    * Should be called once when first registered.
+    */
+   void onDriverDistractionChange(in DriverDistractionChangeEvent event) = 0;
+}
\ No newline at end of file
diff --git a/experimental/experimental_api/src/android/car/experimental/IDriverDistractionManager.aidl b/experimental/experimental_api/src/android/car/experimental/IDriverDistractionManager.aidl
new file mode 100644
index 0000000..00d5268
--- /dev/null
+++ b/experimental/experimental_api/src/android/car/experimental/IDriverDistractionManager.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.experimental;
+
+import android.car.experimental.DriverDistractionChangeEvent;
+import android.car.experimental.IDriverDistractionChangeListener;
+
+/** @hide */
+interface IDriverDistractionManager {
+    /**
+     * Gets the current driver distraction level based on the last change event that is not stale.
+     */
+    DriverDistractionChangeEvent getLastDistractionEvent() = 0;
+   /**
+    * Registers a listener to be called when the driver's distraction level has changed.
+    *
+    * Listener immediately receives a callback.
+    */
+    void addDriverDistractionChangeListener(in IDriverDistractionChangeListener listener) = 1;
+    /**
+     * Removes the provided listener from receiving callbacks.
+     */
+    void removeDriverDistractionChangeListener(in IDriverDistractionChangeListener listener) = 2;
+}
\ No newline at end of file
diff --git a/experimental/experimental_api/src/android/car/experimental/ITestDemoExperimental.aidl b/experimental/experimental_api/src/android/car/experimental/ITestDemoExperimental.aidl
new file mode 100644
index 0000000..b5ce7e1
--- /dev/null
+++ b/experimental/experimental_api/src/android/car/experimental/ITestDemoExperimental.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.experimental;
+
+/** @hide */
+interface ITestDemoExperimental {
+    String ping(in String msg);
+}
\ No newline at end of file
diff --git a/experimental/service/Android.bp b/experimental/service/Android.bp
new file mode 100644
index 0000000..b0c59c4
--- /dev/null
+++ b/experimental/service/Android.bp
@@ -0,0 +1,83 @@
+// 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.
+//
+//
+
+// Build the Experimental Car service.
+
+experimentalcar_service_sources = ["src/**/*.java"]
+
+android_app {
+    name: "ExperimentalCarService",
+
+    srcs: experimentalcar_service_sources,
+
+    resource_dirs: ["res"],
+
+    platform_apis: true,
+
+    // Each update should be signed by OEMs
+    certificate: "platform",
+    privileged: true,
+
+    optimize: {
+        proguard_flags_files: ["proguard.flags"],
+        enabled: false,
+    },
+
+    libs: ["android.car"],
+
+    static_libs: [
+      "car-service-common-util-static-lib",
+      "car-experimental-api-static-lib",
+    ],
+
+    required: ["privapp_whitelist_com.android.experimentalcar"],
+
+    // Disable build in PDK, missing aidl import breaks build
+    product_variables: {
+        pdk: {
+            enabled: false,
+        },
+    },
+}
+
+//####################################################################################
+// Build a static library to help mocking various car services in testing. This is meant to be used
+// for internal unit tests around the car service.
+//####################################################################################
+android_library {
+    name: "experimentalcar-service-test-static-lib",
+
+    srcs: experimentalcar_service_sources,
+
+    resource_dirs: ["res"],
+
+    libs: [
+        "android.car",
+    ],
+
+    static_libs: [
+      "car-service-common-util-static-lib",
+      "car-experimental-api-static-lib",
+    ],
+
+    min_sdk_version: "25",
+
+    product_variables: {
+        pdk: {
+            enabled: false,
+        },
+    },
+}
diff --git a/experimental/service/AndroidManifest.xml b/experimental/service/AndroidManifest.xml
new file mode 100644
index 0000000..09e50b1
--- /dev/null
+++ b/experimental/service/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.experimentalcar"
+          coreApp="true"
+          android:sharedUserId="android.uid.system">
+
+    <original-package android:name="com.android.experimentalcar"/>
+
+    <!-- Allows an application to get the driver's current distraction level.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.CAR_DRIVER_DISTRACTION"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_driver_distraction"
+        android:description="@string/car_permission_desc_driver_distraction"/>
+
+    <application android:label="@string/app_title"
+                 android:directBootAware="true"
+                 android:allowBackup="false"
+                 android:persistent="false">
+        <service android:name=".ExperimentalCarService"
+                 android:singleUser="true">
+        </service>
+        <service android:name=".TouchDriverAwarenessSupplier" android:exported="false"/>
+        <service android:name=".GazeDriverAwarenessSupplier" android:exported="false"/>
+        <service android:name=".SampleExternalDriverAwarenessSupplier" android:exported="false"/>
+    </application>
+</manifest>
diff --git a/experimental/service/proguard.flags b/experimental/service/proguard.flags
new file mode 100644
index 0000000..22cc22d
--- /dev/null
+++ b/experimental/service/proguard.flags
@@ -0,0 +1,3 @@
+-verbose
+-keep @com.android.internal.annotations.VisibleForTesting class *
+
diff --git a/experimental/service/res/values-af/strings.xml b/experimental/service/res/values-af/strings.xml
new file mode 100644
index 0000000..8b74368
--- /dev/null
+++ b/experimental/service/res/values-af/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"lees bestuurder se afleidingsvlak"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Lees bestuurder se afleidingsvlak."</string>
+</resources>
diff --git a/experimental/service/res/values-am/strings.xml b/experimental/service/res/values-am/strings.xml
new file mode 100644
index 0000000..47887d8
--- /dev/null
+++ b/experimental/service/res/values-am/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"የነጂ መዘናጋት ደረጃ ያንብቡ"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"የነጂ መዘናጋት ደረጃን ያንብቡ።"</string>
+</resources>
diff --git a/experimental/service/res/values-ar/strings.xml b/experimental/service/res/values-ar/strings.xml
new file mode 100644
index 0000000..08391f5
--- /dev/null
+++ b/experimental/service/res/values-ar/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"قراءة مستوى تشتت السائق"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"قراءة مستوى تشتت السائق"</string>
+</resources>
diff --git a/experimental/service/res/values-as/strings.xml b/experimental/service/res/values-as/strings.xml
new file mode 100644
index 0000000..a3a1185
--- /dev/null
+++ b/experimental/service/res/values-as/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"চালকৰ অন্যমনস্কতাৰ স্তৰ পঢ়িব পাৰে"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"চালকৰ অন্যমনস্কতাৰ স্তৰ পঢ়ক।"</string>
+</resources>
diff --git a/experimental/service/res/values-az/strings.xml b/experimental/service/res/values-az/strings.xml
new file mode 100644
index 0000000..aa67fdb
--- /dev/null
+++ b/experimental/service/res/values-az/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"sürücünün yayınma səviyyəsini oxumaq"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Sürücünün yayınma səviyyəsini oxuyun."</string>
+</resources>
diff --git a/experimental/service/res/values-b+sr+Latn/strings.xml b/experimental/service/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..b4957fd
--- /dev/null
+++ b/experimental/service/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"čitanje nivoa ometanja vozača"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Očitavaju nivo ometanja vozača."</string>
+</resources>
diff --git a/experimental/service/res/values-be/strings.xml b/experimental/service/res/values-be/strings.xml
new file mode 100644
index 0000000..f8df9fd
--- /dev/null
+++ b/experimental/service/res/values-be/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"вызначаць узровень рассеянасці вадзіцеля"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Вызначаць узровень рассеянасці вадзіцеля."</string>
+</resources>
diff --git a/experimental/service/res/values-bg/strings.xml b/experimental/service/res/values-bg/strings.xml
new file mode 100644
index 0000000..dbfe9a4
--- /dev/null
+++ b/experimental/service/res/values-bg/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"четене на нивото на разсейване на шофьора"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Четене на нивото на разсейване на шофьора."</string>
+</resources>
diff --git a/experimental/service/res/values-bn/strings.xml b/experimental/service/res/values-bn/strings.xml
new file mode 100644
index 0000000..a94c53a
--- /dev/null
+++ b/experimental/service/res/values-bn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"ড্রাইভারের মনোযোগে ব্যাঘাত ঘটার লেভেল সম্পর্কে জানুন"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"ড্রাইভারের মনোযোগে ব্যাঘাত ঘটার লেভেল সম্পর্কে জানুন।"</string>
+</resources>
diff --git a/experimental/service/res/values-bs/strings.xml b/experimental/service/res/values-bs/strings.xml
new file mode 100644
index 0000000..bb6e2c3
--- /dev/null
+++ b/experimental/service/res/values-bs/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"očitavanje nivoa ometanja vozača"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Očitavanje nivoa ometanja vozača."</string>
+</resources>
diff --git a/experimental/service/res/values-ca/strings.xml b/experimental/service/res/values-ca/strings.xml
new file mode 100644
index 0000000..df98dda
--- /dev/null
+++ b/experimental/service/res/values-ca/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"consultar el nivell de distracció del conductor"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Consultar el nivell de distracció del conductor."</string>
+</resources>
diff --git a/experimental/service/res/values-cs/strings.xml b/experimental/service/res/values-cs/strings.xml
new file mode 100644
index 0000000..d2b9e62
--- /dev/null
+++ b/experimental/service/res/values-cs/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"čtení míry vyrušení pozornosti řidiče"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Čtení míry vyrušení pozornosti řidiče."</string>
+</resources>
diff --git a/experimental/service/res/values-da/strings.xml b/experimental/service/res/values-da/strings.xml
new file mode 100644
index 0000000..0de5c2b
--- /dev/null
+++ b/experimental/service/res/values-da/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"aflæs, hvor distraheret føreren er"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Tjek, hvor distraheret føreren er."</string>
+</resources>
diff --git a/experimental/service/res/values-de/strings.xml b/experimental/service/res/values-de/strings.xml
new file mode 100644
index 0000000..14953b7
--- /dev/null
+++ b/experimental/service/res/values-de/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"Ablenkungsgrad des Fahrers erkennen"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Ablenkungsgrad des Fahrers erkennen."</string>
+</resources>
diff --git a/experimental/service/res/values-el/strings.xml b/experimental/service/res/values-el/strings.xml
new file mode 100644
index 0000000..a136eb1
--- /dev/null
+++ b/experimental/service/res/values-el/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"ανάγνωση επιπέδου απόσπασης προσοχής οδηγού"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Ανάγνωση επιπέδου απόσπασης προσοχής οδηγού."</string>
+</resources>
diff --git a/experimental/service/res/values-en-rAU/strings.xml b/experimental/service/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..4162250
--- /dev/null
+++ b/experimental/service/res/values-en-rAU/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"read driver’s distraction level"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Read driver distraction level."</string>
+</resources>
diff --git a/experimental/service/res/values-en-rCA/strings.xml b/experimental/service/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..4162250
--- /dev/null
+++ b/experimental/service/res/values-en-rCA/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"read driver’s distraction level"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Read driver distraction level."</string>
+</resources>
diff --git a/experimental/service/res/values-en-rGB/strings.xml b/experimental/service/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..4162250
--- /dev/null
+++ b/experimental/service/res/values-en-rGB/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"read driver’s distraction level"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Read driver distraction level."</string>
+</resources>
diff --git a/experimental/service/res/values-en-rIN/strings.xml b/experimental/service/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..4162250
--- /dev/null
+++ b/experimental/service/res/values-en-rIN/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"read driver’s distraction level"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Read driver distraction level."</string>
+</resources>
diff --git a/experimental/service/res/values-en-rXC/strings.xml b/experimental/service/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..39ca1ae
--- /dev/null
+++ b/experimental/service/res/values-en-rXC/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‏‏‎‎‎‏‏‎‏‏‎‏‎‎‎‏‎‏‏‎‏‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‎‏‏‏‏‏‎‎‎‎‏‏‎‎‏‏‎read driver’s distraction level‎‏‎‎‏‎"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‏‏‎‏‏‏‎‏‎‎‎‏‏‏‎‏‎‏‏‎‎‎‏‏‎‏‏‏‏‏‎‎‎‎‎‎‎‎‎‎‎‎Read driver distraction level.‎‏‎‎‏‎"</string>
+</resources>
diff --git a/experimental/service/res/values-es-rUS/strings.xml b/experimental/service/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..0e93b4f
--- /dev/null
+++ b/experimental/service/res/values-es-rUS/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"leer nivel de distracción del conductor"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Leer el nivel de distracción del conductor."</string>
+</resources>
diff --git a/experimental/service/res/values-es/strings.xml b/experimental/service/res/values-es/strings.xml
new file mode 100644
index 0000000..826ace2
--- /dev/null
+++ b/experimental/service/res/values-es/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"consultar el nivel de distracción de quien conduce"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Leer el nivel de distracción del conductor."</string>
+</resources>
diff --git a/experimental/service/res/values-et/strings.xml b/experimental/service/res/values-et/strings.xml
new file mode 100644
index 0000000..0fa6482
--- /dev/null
+++ b/experimental/service/res/values-et/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"juhi häirituse taseme lugemine"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Juhi häirituse taseme lugemine."</string>
+</resources>
diff --git a/experimental/service/res/values-eu/strings.xml b/experimental/service/res/values-eu/strings.xml
new file mode 100644
index 0000000..408e4d7
--- /dev/null
+++ b/experimental/service/res/values-eu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"irakurri gidariaren distrakzio-maila"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Irakurri gidariaren distrakzio-maila."</string>
+</resources>
diff --git a/experimental/service/res/values-fa/strings.xml b/experimental/service/res/values-fa/strings.xml
new file mode 100644
index 0000000..29068bc
--- /dev/null
+++ b/experimental/service/res/values-fa/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"خواندن سطح حواس‌پرتی راننده"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"خواندن سطح حواس‌پرتی راننده."</string>
+</resources>
diff --git a/experimental/service/res/values-fi/strings.xml b/experimental/service/res/values-fi/strings.xml
new file mode 100644
index 0000000..ee5cf5c
--- /dev/null
+++ b/experimental/service/res/values-fi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"lue kuljettajan keskittymisen taso"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Lue kuljettajan keskittymisen taso."</string>
+</resources>
diff --git a/experimental/service/res/values-fr-rCA/strings.xml b/experimental/service/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..f013f3a
--- /dev/null
+++ b/experimental/service/res/values-fr-rCA/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"accéder au niveau de distraction du conducteur"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Accédez au niveau de distraction du conducteur."</string>
+</resources>
diff --git a/experimental/service/res/values-fr/strings.xml b/experimental/service/res/values-fr/strings.xml
new file mode 100644
index 0000000..42e60a6
--- /dev/null
+++ b/experimental/service/res/values-fr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"accéder au niveau de distraction du conducteur"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Accéder au niveau de distraction du conducteur."</string>
+</resources>
diff --git a/experimental/service/res/values-gl/strings.xml b/experimental/service/res/values-gl/strings.xml
new file mode 100644
index 0000000..7fe78ad
--- /dev/null
+++ b/experimental/service/res/values-gl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"ler o nivel de distracción do condutor"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Ler o nivel de distracción do condutor."</string>
+</resources>
diff --git a/experimental/service/res/values-gu/strings.xml b/experimental/service/res/values-gu/strings.xml
new file mode 100644
index 0000000..64f97f2
--- /dev/null
+++ b/experimental/service/res/values-gu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"ડ્રાઇવરનું ધ્યાન ભટકવાના સ્તર વિશે જાણો"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"ડ્રાઇવરનું ધ્યાન ભટકવાના સ્તર વિશે જાણો."</string>
+</resources>
diff --git a/experimental/service/res/values-hi/strings.xml b/experimental/service/res/values-hi/strings.xml
new file mode 100644
index 0000000..ee2faf5
--- /dev/null
+++ b/experimental/service/res/values-hi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"ड्राइवर का ध्यान भटकने के लेवल के बारे में जानें"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"ड्राइवर का ध्यान भटकने के लेवल के बारे में जानें."</string>
+</resources>
diff --git a/experimental/service/res/values-hr/strings.xml b/experimental/service/res/values-hr/strings.xml
new file mode 100644
index 0000000..271625b
--- /dev/null
+++ b/experimental/service/res/values-hr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"čitaju razinu ometanja vozača"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Čitaju razinu ometanja vozača."</string>
+</resources>
diff --git a/experimental/service/res/values-hu/strings.xml b/experimental/service/res/values-hu/strings.xml
new file mode 100644
index 0000000..21ca04c
--- /dev/null
+++ b/experimental/service/res/values-hu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"sofőr figyelmetlenségi szintjének olvasása"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"A sofőr figyelmetlenségi szintjének olvasása."</string>
+</resources>
diff --git a/experimental/service/res/values-hy/strings.xml b/experimental/service/res/values-hy/strings.xml
new file mode 100644
index 0000000..407f2dd
--- /dev/null
+++ b/experimental/service/res/values-hy/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"հաշվարկել շեղող գործոնների մակարդակը"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Տեսնել շեղող գործոնների մակարդակը։"</string>
+</resources>
diff --git a/experimental/service/res/values-in/strings.xml b/experimental/service/res/values-in/strings.xml
new file mode 100644
index 0000000..f1ffbac
--- /dev/null
+++ b/experimental/service/res/values-in/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"baca tingkat gangguan bagi pengemudi"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Baca tingkat gangguan bagi pengemudi."</string>
+</resources>
diff --git a/experimental/service/res/values-is/strings.xml b/experimental/service/res/values-is/strings.xml
new file mode 100644
index 0000000..99f6547
--- /dev/null
+++ b/experimental/service/res/values-is/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"athuga hversu miklum truflunum ökumaður verður fyrir"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Athuga hversu miklum truflunum ökumaður verður fyrir."</string>
+</resources>
diff --git a/experimental/service/res/values-it/strings.xml b/experimental/service/res/values-it/strings.xml
new file mode 100644
index 0000000..a48bb0f
--- /dev/null
+++ b/experimental/service/res/values-it/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"Lettura del livello di distrazione dell\'autista"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Leggi il livello di distrazione dell\'autista"</string>
+</resources>
diff --git a/experimental/service/res/values-iw/strings.xml b/experimental/service/res/values-iw/strings.xml
new file mode 100644
index 0000000..8e38a45
--- /dev/null
+++ b/experimental/service/res/values-iw/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"קריאה של רמת הסחת הדעת של הנהג"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"אישור קריאה של רמת הסחת הדעת של הנהג."</string>
+</resources>
diff --git a/experimental/service/res/values-ja/strings.xml b/experimental/service/res/values-ja/strings.xml
new file mode 100644
index 0000000..07dbea4
--- /dev/null
+++ b/experimental/service/res/values-ja/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"ドライバーの注意散漫レベルの読み取り"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"ドライバーの注意散漫レベルの読み取り。"</string>
+</resources>
diff --git a/experimental/service/res/values-ka/strings.xml b/experimental/service/res/values-ka/strings.xml
new file mode 100644
index 0000000..3f28b4b
--- /dev/null
+++ b/experimental/service/res/values-ka/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"მძღოლის გაფანტულობის დონის წაკითხვა"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"მძღოლის გაფანტულობის დონის წაკითხვა."</string>
+</resources>
diff --git a/experimental/service/res/values-kk/strings.xml b/experimental/service/res/values-kk/strings.xml
new file mode 100644
index 0000000..0941757
--- /dev/null
+++ b/experimental/service/res/values-kk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"жүргізушіні алаңдату деңгейін көру"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Жүргізушіні алаңдату деңгейін көру."</string>
+</resources>
diff --git a/experimental/service/res/values-km/strings.xml b/experimental/service/res/values-km/strings.xml
new file mode 100644
index 0000000..c25b605
--- /dev/null
+++ b/experimental/service/res/values-km/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"អានកម្រិត​នៃការរំខាន​របស់អ្នកបើកបរ"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"អានកម្រិត​នៃការរំខាន​របស់អ្នកបើកបរ។"</string>
+</resources>
diff --git a/experimental/service/res/values-kn/strings.xml b/experimental/service/res/values-kn/strings.xml
new file mode 100644
index 0000000..c58906b
--- /dev/null
+++ b/experimental/service/res/values-kn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"ಚಾಲಕರ ವ್ಯಾಕುಲತೆಯ ಮಟ್ಟವನ್ನು ಓದಿ"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"ಚಾಲಕನ ವ್ಯಾಕುಲತೆಯ ಮಟ್ಟವನ್ನು ಓದಿ."</string>
+</resources>
diff --git a/experimental/service/res/values-ko/strings.xml b/experimental/service/res/values-ko/strings.xml
new file mode 100644
index 0000000..62b78fc
--- /dev/null
+++ b/experimental/service/res/values-ko/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"운전자의 주의 분산 수준을 읽습니다."</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"운전자의 주의 분산 수준을 읽습니다."</string>
+</resources>
diff --git a/experimental/service/res/values-ky/strings.xml b/experimental/service/res/values-ky/strings.xml
new file mode 100644
index 0000000..f4f2750
--- /dev/null
+++ b/experimental/service/res/values-ky/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"айдоочуну алаксыткан колдонмолордун деңгээлин окуу"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Айдоочуну алаксыткан колдонмолордун деңгээлин окуу."</string>
+</resources>
diff --git a/experimental/service/res/values-lo/strings.xml b/experimental/service/res/values-lo/strings.xml
new file mode 100644
index 0000000..3065fb6
--- /dev/null
+++ b/experimental/service/res/values-lo/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"ລະດັບການເສຍສະມາທິຂອງຜູ້ຂັບ"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"ອ່ານລະດັບການເສຍສະມາທິຂອງຜູ້ຂັບ."</string>
+</resources>
diff --git a/experimental/service/res/values-lt/strings.xml b/experimental/service/res/values-lt/strings.xml
new file mode 100644
index 0000000..7bbbf97
--- /dev/null
+++ b/experimental/service/res/values-lt/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"skaityti vairuotojo dėmesio atitraukimo lygio informaciją"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Skaityti vairuotojo dėmesio atitraukimo lygio informaciją."</string>
+</resources>
diff --git a/experimental/service/res/values-lv/strings.xml b/experimental/service/res/values-lv/strings.xml
new file mode 100644
index 0000000..755614c
--- /dev/null
+++ b/experimental/service/res/values-lv/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"lasīt autovadītāja uzmanības novēršanas līmeni"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Lasīt autovadītāja uzmanības novēršanas līmeni."</string>
+</resources>
diff --git a/experimental/service/res/values-mk/strings.xml b/experimental/service/res/values-mk/strings.xml
new file mode 100644
index 0000000..fe75ef8
--- /dev/null
+++ b/experimental/service/res/values-mk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"да го чита нивото на одвлекување на вниманието на возачот"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Го читаат нивото на одвлекување на вниманието на возачот."</string>
+</resources>
diff --git a/experimental/service/res/values-ml/strings.xml b/experimental/service/res/values-ml/strings.xml
new file mode 100644
index 0000000..a1fb16f
--- /dev/null
+++ b/experimental/service/res/values-ml/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"ഡ്രൈവറുടെ ശ്രദ്ധ വ്യതിചലിച്ചതിന്റെ ലെവൽ റീഡ് ചെയ്യുക"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"ഡ്രൈവറുടെ ശ്രദ്ധ വ്യതിചലിച്ചതിന്റെ ലെവൽ റീഡ് ചെയ്യുക."</string>
+</resources>
diff --git a/experimental/service/res/values-mn/strings.xml b/experimental/service/res/values-mn/strings.xml
new file mode 100644
index 0000000..c4c1c78
--- /dev/null
+++ b/experimental/service/res/values-mn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"жолоочийн анхаарал сарних түвшнийг унших"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Жолоочийн анхаарал сарниулах зүйлсийн түвшнийг уншина уу."</string>
+</resources>
diff --git a/experimental/service/res/values-mr/strings.xml b/experimental/service/res/values-mr/strings.xml
new file mode 100644
index 0000000..96328bb
--- /dev/null
+++ b/experimental/service/res/values-mr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"ड्रायव्हर डिस्ट्रॅक्शनची पातळी वाचा"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"ड्रायव्हर डिस्ट्रॅक्शनची पातळी रीड करा."</string>
+</resources>
diff --git a/experimental/service/res/values-ms/strings.xml b/experimental/service/res/values-ms/strings.xml
new file mode 100644
index 0000000..5b7cb61
--- /dev/null
+++ b/experimental/service/res/values-ms/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"baca tahap gangguan pemandu"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Baca tahap gangguan pemandu."</string>
+</resources>
diff --git a/experimental/service/res/values-my/strings.xml b/experimental/service/res/values-my/strings.xml
new file mode 100644
index 0000000..7f6ec58
--- /dev/null
+++ b/experimental/service/res/values-my/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"ယာဉ်မောင်းသူ၏ စိတ်အနှောင့်အယှက်ဖြစ်မှု အဆင့်ကို ကြည့်ရန်"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"ယာဉ်မောင်းသူ အနှောင့်အယှက်ဖြစ်မှုအဆင့်ကို ဖတ်ရန်။"</string>
+</resources>
diff --git a/experimental/service/res/values-nb/strings.xml b/experimental/service/res/values-nb/strings.xml
new file mode 100644
index 0000000..ac03d56
--- /dev/null
+++ b/experimental/service/res/values-nb/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"registrer sjåførens distraksjonsnivå"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Registrer sjåførens distraksjonsnivå."</string>
+</resources>
diff --git a/experimental/service/res/values-ne/strings.xml b/experimental/service/res/values-ne/strings.xml
new file mode 100644
index 0000000..fac2957
--- /dev/null
+++ b/experimental/service/res/values-ne/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"ड्राइभरको ध्यान भङ्ग गराउने कुराको स्तर पढ्नुहोस्"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"ड्राइभरको ध्यान भङ्ग गराउने कुराको स्तर पढ्नुहोस्।"</string>
+</resources>
diff --git a/experimental/service/res/values-nl/strings.xml b/experimental/service/res/values-nl/strings.xml
new file mode 100644
index 0000000..70cb99a
--- /dev/null
+++ b/experimental/service/res/values-nl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"afleidingsniveau van chauffeur lezen"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Afleidingsniveau van chauffeur lezen"</string>
+</resources>
diff --git a/experimental/service/res/values-or/strings.xml b/experimental/service/res/values-or/strings.xml
new file mode 100644
index 0000000..f896f66
--- /dev/null
+++ b/experimental/service/res/values-or/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"ଡ୍ରାଇଭରର ଡିସଟ୍ରାକସନ୍ ସ୍ତର ପଢ଼ନ୍ତୁ"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"ଡ୍ରାଇଭର୍ ଡିସଟ୍ରାକସନ୍ ସ୍ତର ପଢ଼ନ୍ତୁ"</string>
+</resources>
diff --git a/experimental/service/res/values-pa/strings.xml b/experimental/service/res/values-pa/strings.xml
new file mode 100644
index 0000000..01788ed
--- /dev/null
+++ b/experimental/service/res/values-pa/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"ਡਰਾਈਵਰ ਦੇ ਧਿਆਨ ਹਟਣ ਦੇ ਪੱਧਰ ਬਾਰੇ ਜਾਣੋ"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"ਡਰਾਈਵਰ ਦੇ ਧਿਆਨ ਹਟਣ ਦੇ ਪੱਧਰ ਬਾਰੇ ਜਾਣੋ।"</string>
+</resources>
diff --git a/experimental/service/res/values-pl/strings.xml b/experimental/service/res/values-pl/strings.xml
new file mode 100644
index 0000000..5e4db5d
--- /dev/null
+++ b/experimental/service/res/values-pl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"odczytywanie informacji o poziomie rozproszenia uwagi kierowcy"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Odczytywanie informacji o poziomie rozproszenia uwagi kierowcy."</string>
+</resources>
diff --git a/experimental/service/res/values-pt-rPT/strings.xml b/experimental/service/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..7c3fb42
--- /dev/null
+++ b/experimental/service/res/values-pt-rPT/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"avaliar o nível de distração do condutor"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Avaliar o nível de distração do condutor"</string>
+</resources>
diff --git a/experimental/service/res/values-pt/strings.xml b/experimental/service/res/values-pt/strings.xml
new file mode 100644
index 0000000..c697875
--- /dev/null
+++ b/experimental/service/res/values-pt/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"ler o nível de distração do motorista"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Ler o nível de distração do motorista."</string>
+</resources>
diff --git a/experimental/service/res/values-ro/strings.xml b/experimental/service/res/values-ro/strings.xml
new file mode 100644
index 0000000..7b6f4be
--- /dev/null
+++ b/experimental/service/res/values-ro/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"poate citi nivelul de distragere al șoferului"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Poate citi nivelul de distragere al șoferului."</string>
+</resources>
diff --git a/experimental/service/res/values-ru/strings.xml b/experimental/service/res/values-ru/strings.xml
new file mode 100644
index 0000000..c2176d6
--- /dev/null
+++ b/experimental/service/res/values-ru/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"считывание уровня отвлекающих факторов"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Считывание уровня отвлекающих факторов."</string>
+</resources>
diff --git a/experimental/service/res/values-si/strings.xml b/experimental/service/res/values-si/strings.xml
new file mode 100644
index 0000000..0a793ea
--- /dev/null
+++ b/experimental/service/res/values-si/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"රියදුරු වික්ෂිප්ත මට්ටම කියවන්න"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"රියදුරු වික්ෂිප්ත මට්ටම කියවන්න."</string>
+</resources>
diff --git a/experimental/service/res/values-sk/strings.xml b/experimental/service/res/values-sk/strings.xml
new file mode 100644
index 0000000..567acf0
--- /dev/null
+++ b/experimental/service/res/values-sk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"čítanie miery vyrušenia pozornosti vodiča"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Čítanie miery vyrušenia pozornosti vodiča."</string>
+</resources>
diff --git a/experimental/service/res/values-sl/strings.xml b/experimental/service/res/values-sl/strings.xml
new file mode 100644
index 0000000..e8243ff
--- /dev/null
+++ b/experimental/service/res/values-sl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"branje stopnje nepozornosti voznika"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Branje stopnje nepozornosti voznika."</string>
+</resources>
diff --git a/experimental/service/res/values-sq/strings.xml b/experimental/service/res/values-sq/strings.xml
new file mode 100644
index 0000000..6ec188b
--- /dev/null
+++ b/experimental/service/res/values-sq/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"të lexojnë nivelin e shpërqendrimit të drejtuesit të makinës"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Lexo nivelin e shpërqendrimit të drejtuesit të makinës."</string>
+</resources>
diff --git a/experimental/service/res/values-sr/strings.xml b/experimental/service/res/values-sr/strings.xml
new file mode 100644
index 0000000..a1db45b
--- /dev/null
+++ b/experimental/service/res/values-sr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"читање нивоа ометања возача"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Очитавају ниво ометања возача."</string>
+</resources>
diff --git a/experimental/service/res/values-sv/strings.xml b/experimental/service/res/values-sv/strings.xml
new file mode 100644
index 0000000..c7f35a6
--- /dev/null
+++ b/experimental/service/res/values-sv/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"läsa graden av förardistraktion"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Läsa graden av förardistraktion."</string>
+</resources>
diff --git a/experimental/service/res/values-sw/strings.xml b/experimental/service/res/values-sw/strings.xml
new file mode 100644
index 0000000..7ef4c6f
--- /dev/null
+++ b/experimental/service/res/values-sw/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"kusoma kiwango cha usumbufu kwa dereva"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Soma kiwango cha usumbufu kwa dereva."</string>
+</resources>
diff --git a/experimental/service/res/values-ta/strings.xml b/experimental/service/res/values-ta/strings.xml
new file mode 100644
index 0000000..b3f6833
--- /dev/null
+++ b/experimental/service/res/values-ta/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"ஓட்டுநரின் கவனச்சிதறல் நிலையைக் கண்டறி"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"ஓட்டுநரின் கவனச்சிதறல் நிலையைக் கண்டறி."</string>
+</resources>
diff --git a/experimental/service/res/values-te/strings.xml b/experimental/service/res/values-te/strings.xml
new file mode 100644
index 0000000..ca50681
--- /dev/null
+++ b/experimental/service/res/values-te/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"డ్రైవర్ పరధ్యాన స్థాయిని చదువు"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"డ్రైవర్ పరధ్యాన స్థాయిని చదువు."</string>
+</resources>
diff --git a/experimental/service/res/values-th/strings.xml b/experimental/service/res/values-th/strings.xml
new file mode 100644
index 0000000..3a2c851
--- /dev/null
+++ b/experimental/service/res/values-th/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"อ่านระดับการเสียสมาธิของผู้ขับ"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"อ่านระดับการเสียสมาธิของผู้ขับ"</string>
+</resources>
diff --git a/experimental/service/res/values-tl/strings.xml b/experimental/service/res/values-tl/strings.xml
new file mode 100644
index 0000000..19052c8
--- /dev/null
+++ b/experimental/service/res/values-tl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"basahin ang antas ng gambala sa nagmamaneho"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Basahin ang antas ng gambala sa nagmamaneho."</string>
+</resources>
diff --git a/experimental/service/res/values-tr/strings.xml b/experimental/service/res/values-tr/strings.xml
new file mode 100644
index 0000000..cccb1a4
--- /dev/null
+++ b/experimental/service/res/values-tr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"sürücünün dikkatinin dağılma seviyesini oku"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Sürücünün dikkatinin dağılma seviyesini oku."</string>
+</resources>
diff --git a/experimental/service/res/values-uk/strings.xml b/experimental/service/res/values-uk/strings.xml
new file mode 100644
index 0000000..54c0bd4
--- /dev/null
+++ b/experimental/service/res/values-uk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"переглядати рівень відволікання водія"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Переглядати рівень відволікання водія."</string>
+</resources>
diff --git a/experimental/service/res/values-ur/strings.xml b/experimental/service/res/values-ur/strings.xml
new file mode 100644
index 0000000..871fb80
--- /dev/null
+++ b/experimental/service/res/values-ur/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"ڈرائیور کے ذہنی انتشار کا لیول پڑھیں"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"ڈرائیور کے ذہنی انتشار کا لیول پڑھیں۔"</string>
+</resources>
diff --git a/experimental/service/res/values-uz/strings.xml b/experimental/service/res/values-uz/strings.xml
new file mode 100644
index 0000000..3e30601
--- /dev/null
+++ b/experimental/service/res/values-uz/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"haydovchi diqqatini olish darajasi haqida batafsil"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Haydovchi diqqatini olish darajasi haqida batafsil."</string>
+</resources>
diff --git a/experimental/service/res/values-vi/strings.xml b/experimental/service/res/values-vi/strings.xml
new file mode 100644
index 0000000..1af7c52
--- /dev/null
+++ b/experimental/service/res/values-vi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"đọc thông tin về mức mất tập trung của người lái xe"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Đọc thông tin về mức mất tập trung của người lái xe."</string>
+</resources>
diff --git a/experimental/service/res/values-zh-rCN/strings.xml b/experimental/service/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..cfecc42
--- /dev/null
+++ b/experimental/service/res/values-zh-rCN/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"读取驾驶员分散注意力等级"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"读取驾驶员分散注意力等级。"</string>
+</resources>
diff --git a/experimental/service/res/values-zh-rHK/strings.xml b/experimental/service/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..2aa6176
--- /dev/null
+++ b/experimental/service/res/values-zh-rHK/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"讀取司機分心程度"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"讀取司機分心程度。"</string>
+</resources>
diff --git a/experimental/service/res/values-zh-rTW/strings.xml b/experimental/service/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..86512f5
--- /dev/null
+++ b/experimental/service/res/values-zh-rTW/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"讀取駕駛人的分心等級"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"讀取駕駛人分心等級。"</string>
+</resources>
diff --git a/experimental/service/res/values-zu/strings.xml b/experimental/service/res/values-zu/strings.xml
new file mode 100644
index 0000000..6d1c25a
--- /dev/null
+++ b/experimental/service/res/values-zu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="car_permission_label_driver_distraction" msgid="4362982084385602611">"funda ileveli yokuphazamisa yomshayeli"</string>
+    <string name="car_permission_desc_driver_distraction" msgid="2506435411900299264">"Funda ileveli yokuphazamisa yomshayeli."</string>
+</resources>
diff --git a/experimental/service/res/values/config.xml b/experimental/service/res/values/config.xml
new file mode 100644
index 0000000..2a8db9b
--- /dev/null
+++ b/experimental/service/res/values/config.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Resources to configure experimental car service based on each OEM's preference. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- The preferred driver awareness suppliers for dispatching the current driver awareness
+         level to DriverDistractionExperimentalFeatureService. Each component must be service that
+         extends DriverAwarenessSupplierService. The ordering of this list matters - items should
+         be ordered from lowest to highest priority. That is to say, the first index is the lowest
+         priority supplier and the index of items after that are higher. Data from higher priority
+         suppliers is always preferred unless that data is stale. -->
+    <string-array translatable="false" name="preferredDriverAwarenessSuppliers">
+        <item>
+            com.android.experimentalcar/.SampleExternalDriverAwarenessSupplier
+        </item>
+        <item>
+            com.android.experimentalcar/.GazeDriverAwarenessSupplier
+        </item>
+    </string-array>
+
+    <!-- The maximum, and default, number of permits a driver has. Each unthrottled tap will
+         decrement the current permit count, down to a minimum value of 0. Permits will meanwhile be
+         refreshed at a rate of 1 permit every
+         @integer/driverAwarenessTouchModelPermitRefreshIntervalMs milliseconds, up to this maximum
+         value. -->
+    <integer name="driverAwarenessTouchModelMaxPermits">6</integer>
+
+    <!-- Number of milliseconds for the interval that permits should be refreshed. -->
+    <integer name="driverAwarenessTouchModelPermitRefreshIntervalMs">2000</integer>
+
+    <!-- Number of milliseconds that taps should be ignored following a first tap. -->
+    <integer name="driverAwarenessTouchModelThrottleMs">600</integer>
+
+    <!-- Initial value for the gaze based attention buffer [0, 1]. -->
+    <item name="driverAwarenessGazeModelInitialValue" format="float" type="fraction">1</item>
+
+    <!-- Rate at which the attention buffer decreases when the driver is looking off-road, in attention units/second-->
+    <item name="driverAwarenessGazeModelDecayRate" format="float" type="fraction">0.167</item>
+
+     <!-- Rate at which the attention buffer increases when the driver is looking on-road, in attention units/second-->
+    <item name="driverAwarenessGazeModelGrowthRate" format="float" type="fraction">0.167</item>
+
+</resources>
diff --git a/experimental/service/res/values/strings.xml b/experimental/service/res/values/strings.xml
new file mode 100644
index 0000000..97231b4
--- /dev/null
+++ b/experimental/service/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_title" translatable="false">Experimental Car service</string>
+    <!-- Permission text: apps can access the driver's distraction level [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_driver_distraction">read driver\u2019s distraction level</string>
+    <!-- Permission text: apps can access the driver's distraction level [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_driver_distraction">Read driver distraction level.</string>
+
+</resources>
diff --git a/experimental/service/src/com/android/experimentalcar/DriverDistractionExperimentalFeatureService.java b/experimental/service/src/com/android/experimentalcar/DriverDistractionExperimentalFeatureService.java
new file mode 100644
index 0000000..6b6a05c
--- /dev/null
+++ b/experimental/service/src/com/android/experimentalcar/DriverDistractionExperimentalFeatureService.java
@@ -0,0 +1,863 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.experimentalcar;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.car.Car;
+import android.car.VehiclePropertyIds;
+import android.car.experimental.DriverAwarenessEvent;
+import android.car.experimental.DriverAwarenessSupplierConfig;
+import android.car.experimental.DriverAwarenessSupplierService;
+import android.car.experimental.DriverDistractionChangeEvent;
+import android.car.experimental.ExperimentalCar;
+import android.car.experimental.IDriverAwarenessSupplier;
+import android.car.experimental.IDriverAwarenessSupplierCallback;
+import android.car.experimental.IDriverDistractionChangeListener;
+import android.car.experimental.IDriverDistractionManager;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarPropertyEvent;
+import android.car.hardware.property.CarPropertyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.car.CarServiceBase;
+import com.android.car.Utils;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.PrintWriter;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TimerTask;
+
+/**
+ * Driver Distraction Service for using the driver's awareness, the required awareness of the
+ * driving environment to expose APIs for the driver's current distraction level.
+ *
+ * <p>Allows the registration of multiple {@link IDriverAwarenessSupplier} so that higher accuracy
+ * signals can be used when possible, with a fallback to less accurate signals. The {@link
+ * TouchDriverAwarenessSupplier} is always set to the fallback implementation - it is configured
+ * to send change-events, so its data will not become stale.
+ */
+public final class DriverDistractionExperimentalFeatureService extends
+        IDriverDistractionManager.Stub implements CarServiceBase {
+
+    private static final String TAG = "CAR.DriverDistractionService";
+
+    /**
+     * The minimum delay between dispatched distraction events, in milliseconds.
+     */
+    @VisibleForTesting
+    static final long DISPATCH_THROTTLE_MS = 50L;
+    private static final float DEFAULT_AWARENESS_VALUE_FOR_LOG = 1.0f;
+    private static final float MOVING_REQUIRED_AWARENESS = 1.0f;
+    private static final float STATIONARY_REQUIRED_AWARENESS = 0.0f;
+    private static final int MAX_EVENT_LOG_COUNT = 50;
+    private static final int PROPERTY_UPDATE_RATE_HZ = 5;
+    @VisibleForTesting
+    static final float DEFAULT_AWARENESS_PERCENTAGE = 1.0f;
+
+    private final HandlerThread mClientDispatchHandlerThread;
+    private final Handler mClientDispatchHandler;
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private final ArrayDeque<Utils.TransitionLog> mTransitionLogs = new ArrayDeque<>();
+
+    /**
+     * All the active service connections.
+     */
+    @GuardedBy("mLock")
+    private final List<ServiceConnection> mServiceConnections = new ArrayList<>();
+
+    /**
+     * The binder for each supplier.
+     */
+    @GuardedBy("mLock")
+    private final Map<ComponentName, IDriverAwarenessSupplier> mSupplierBinders = new HashMap<>();
+
+    /**
+     * The configuration for each supplier.
+     */
+    @GuardedBy("mLock")
+    private final Map<IDriverAwarenessSupplier, DriverAwarenessSupplierConfig> mSupplierConfigs =
+            new HashMap<>();
+
+    /**
+     * List of driver awareness suppliers that can be used to understand the current driver
+     * awareness level. Ordered from highest to lowest priority.
+     */
+    @GuardedBy("mLock")
+    private final List<IDriverAwarenessSupplier> mPrioritizedDriverAwarenessSuppliers =
+            new ArrayList<>();
+
+    /**
+     * Helper map for looking up the priority rank of a supplier by name. A higher integer value
+     * represents a higher priority.
+     */
+    @GuardedBy("mLock")
+    private final Map<IDriverAwarenessSupplier, Integer> mDriverAwarenessSupplierPriorities =
+            new HashMap<>();
+
+    /**
+     * List of clients listening to UX restriction events.
+     */
+    private final RemoteCallbackList<IDriverDistractionChangeListener> mDistractionClients =
+            new RemoteCallbackList<>();
+
+    /**
+     * Comparator used to sort {@link #mDriverAwarenessSupplierPriorities}.
+     */
+    private final Comparator<IDriverAwarenessSupplier> mPrioritizedSuppliersComparator =
+            (left, right) -> {
+                int leftPri = mDriverAwarenessSupplierPriorities.get(left);
+                int rightPri = mDriverAwarenessSupplierPriorities.get(right);
+                // sort descending
+                return rightPri - leftPri;
+            };
+
+    /**
+     * Keep track of the most recent awareness event for each supplier for use when the data from
+     * higher priority suppliers becomes stale. This is necessary in order to seamlessly handle
+     * fallback scenarios when data from preferred providers becomes stale.
+     */
+    @GuardedBy("mLock")
+    private final Map<IDriverAwarenessSupplier, DriverAwarenessEventWrapper>
+            mCurrentAwarenessEventsMap =
+            new HashMap<>();
+
+    /**
+     * The awareness event that is currently being used to determine the driver awareness level.
+     *
+     * <p>This is null until it is set by the first awareness supplier to send an event
+     */
+    @GuardedBy("mLock")
+    @Nullable
+    private DriverAwarenessEventWrapper mCurrentDriverAwareness;
+
+    /**
+     * Timer to alert when the current driver awareness event has become stale.
+     */
+    @GuardedBy("mLock")
+    private ITimer mExpiredDriverAwarenessTimer;
+
+    /**
+     * The current, non-stale, driver distraction event. Defaults to 100% awareness.
+     */
+    @GuardedBy("mLock")
+    private DriverDistractionChangeEvent mCurrentDistractionEvent;
+
+    /**
+     * The required driver awareness based on the current driving environment, where 1.0 means that
+     * full awareness is required and 0.0 means than no awareness is required.
+     */
+    @FloatRange(from = 0.0f, to = 1.0f)
+    @GuardedBy("mLock")
+    private float mRequiredAwareness = STATIONARY_REQUIRED_AWARENESS;
+
+    @GuardedBy("mLock")
+    private Car mCar;
+
+    @GuardedBy("mLock")
+    private CarPropertyManager mPropertyManager;
+
+    /**
+     * The time that last event was emitted, measured in milliseconds since boot using the {@link
+     * android.os.SystemClock#uptimeMillis()} time-base.
+     */
+    @GuardedBy("mLock")
+    private long mLastDispatchUptimeMillis;
+
+    /**
+     * Whether there is currently a pending dispatch to clients.
+     */
+    @GuardedBy("mLock")
+    private boolean mIsDispatchQueued;
+
+    private final Context mContext;
+    private final ITimeSource mTimeSource;
+    private final Looper mLooper;
+
+    private final Runnable mDispatchCurrentDistractionRunnable = () -> {
+        synchronized (mLock) {
+            // dispatch whatever the current value is at this time in the future
+            dispatchCurrentDistractionEventToClientsLocked(
+                    mCurrentDistractionEvent);
+            mIsDispatchQueued = false;
+        }
+    };
+
+    /**
+     * Create an instance of {@link DriverDistractionExperimentalFeatureService}.
+     *
+     * @param context the context
+     */
+    DriverDistractionExperimentalFeatureService(Context context) {
+        this(context, new SystemTimeSource(), new SystemTimer(), Looper.myLooper(), null);
+    }
+
+    @VisibleForTesting
+    DriverDistractionExperimentalFeatureService(
+            Context context,
+            ITimeSource timeSource,
+            ITimer timer,
+            Looper looper,
+            Handler clientDispatchHandler) {
+        mContext = context;
+        mTimeSource = timeSource;
+        mExpiredDriverAwarenessTimer = timer;
+        mCurrentDistractionEvent = new DriverDistractionChangeEvent.Builder()
+                .setElapsedRealtimeTimestamp(mTimeSource.elapsedRealtime())
+                .setAwarenessPercentage(DEFAULT_AWARENESS_PERCENTAGE)
+                .build();
+        mClientDispatchHandlerThread = new HandlerThread(TAG);
+        mClientDispatchHandlerThread.start();
+        if (clientDispatchHandler == null) {
+            mClientDispatchHandler = new Handler(mClientDispatchHandlerThread.getLooper());
+        } else {
+            mClientDispatchHandler = clientDispatchHandler;
+        }
+        mLooper = looper;
+    }
+
+    @Override
+    public void init() {
+        // The touch supplier is an internal implementation, so it can be started initiated by its
+        // constructor, unlike other suppliers
+        ComponentName touchComponent = new ComponentName(mContext,
+                TouchDriverAwarenessSupplier.class);
+        TouchDriverAwarenessSupplier touchSupplier = new TouchDriverAwarenessSupplier(mContext,
+                new DriverAwarenessSupplierCallback(touchComponent), mLooper);
+        addDriverAwarenessSupplier(touchComponent, touchSupplier, /* priority= */ 0);
+        touchSupplier.onReady();
+
+        String[] preferredDriverAwarenessSuppliers = mContext.getResources().getStringArray(
+                R.array.preferredDriverAwarenessSuppliers);
+        for (int i = 0; i < preferredDriverAwarenessSuppliers.length; i++) {
+            String supplierStringName = preferredDriverAwarenessSuppliers[i];
+            ComponentName externalComponent = ComponentName.unflattenFromString(supplierStringName);
+            // the touch supplier has priority 0 and preferred suppliers are higher based on order
+            int priority = i + 1;
+            bindDriverAwarenessSupplierService(externalComponent, priority);
+        }
+
+        synchronized (mLock) {
+            mCar = Car.createCar(mContext);
+            if (mCar != null) {
+                mPropertyManager = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
+            } else {
+                Log.e(TAG, "Unable to connect to car in init");
+            }
+        }
+
+        if (mPropertyManager != null) {
+            mPropertyManager.registerCallback(mSpeedPropertyEventCallback,
+                    VehiclePropertyIds.PERF_VEHICLE_SPEED,
+                    PROPERTY_UPDATE_RATE_HZ);
+        } else {
+            Log.e(TAG, "Unable to get car property service.");
+        }
+    }
+
+    @Override
+    public void release() {
+        logd("release");
+        mDistractionClients.kill();
+        synchronized (mLock) {
+            mExpiredDriverAwarenessTimer.cancel();
+            mClientDispatchHandler.removeCallbacksAndMessages(null);
+            for (ServiceConnection serviceConnection : mServiceConnections) {
+                mContext.unbindService(serviceConnection);
+            }
+            if (mPropertyManager != null) {
+                mPropertyManager.unregisterCallback(mSpeedPropertyEventCallback);
+            }
+            if (mCar != null) {
+                mCar.disconnect();
+            }
+        }
+    }
+
+    @Override
+    public void dump(PrintWriter writer) {
+        writer.println("*DriverDistractionExperimentalFeatureService*");
+        mDistractionClients.dump(writer, "Distraction Clients ");
+        writer.println("Prioritized Driver Awareness Suppliers (highest to lowest priority):");
+        synchronized (mLock) {
+            for (int i = 0; i < mPrioritizedDriverAwarenessSuppliers.size(); i++) {
+                writer.println(
+                        String.format("  %d: %s", i, mPrioritizedDriverAwarenessSuppliers.get(
+                                i).getClass().getName()));
+            }
+            writer.println("Current Driver Awareness:");
+            writer.println("  Value: "
+                    + (mCurrentDriverAwareness == null ? "unknown"
+                    : mCurrentDriverAwareness.mAwarenessEvent.getAwarenessValue()));
+            writer.println("  Supplier: " + (mCurrentDriverAwareness == null ? "unknown"
+                    : mCurrentDriverAwareness.mSupplier.getClass().getSimpleName()));
+            writer.println("  Timestamp (ms since boot): "
+                    + (mCurrentDriverAwareness == null ? "unknown"
+                    : mCurrentDriverAwareness.mAwarenessEvent.getTimeStamp()));
+            writer.println("Current Required Awareness: " + mRequiredAwareness);
+            writer.println("Last Distraction Event:");
+            writer.println("  Value: "
+                    + (mCurrentDistractionEvent == null ? "unknown"
+                    : mCurrentDistractionEvent.getAwarenessPercentage()));
+            writer.println("  Timestamp (ms since boot): "
+                    + (mCurrentDistractionEvent == null ? "unknown"
+                    : mCurrentDistractionEvent.getElapsedRealtimeTimestamp()));
+            writer.println("Dispatch Status:");
+            writer.println("  mLastDispatchUptimeMillis: " + mLastDispatchUptimeMillis);
+            writer.println("  mIsDispatchQueued: " + mIsDispatchQueued);
+            writer.println("Change log:");
+            for (Utils.TransitionLog log : mTransitionLogs) {
+                writer.println(log);
+            }
+        }
+    }
+
+    /**
+     * Bind to a {@link DriverAwarenessSupplierService} by its component name.
+     *
+     * @param componentName the name of the {@link DriverAwarenessSupplierService} to bind to.
+     * @param priority      the priority rank of this supplier
+     */
+    private void bindDriverAwarenessSupplierService(ComponentName componentName, int priority) {
+        Intent intent = new Intent();
+        intent.setComponent(componentName);
+        ServiceConnection connection = new DriverAwarenessServiceConnection(priority);
+        synchronized (mLock) {
+            mServiceConnections.add(connection);
+        }
+        if (!mContext.bindServiceAsUser(intent, connection,
+                Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
+            Log.e(TAG, "Unable to bind with intent: " + intent);
+            // TODO(b/146471650) attempt to rebind
+        }
+    }
+
+    @VisibleForTesting
+    void handleDriverAwarenessEvent(DriverAwarenessEventWrapper awarenessEventWrapper) {
+        synchronized (mLock) {
+            handleDriverAwarenessEventLocked(awarenessEventWrapper);
+        }
+    }
+
+    /**
+     * Handle the driver awareness event by:
+     * <ul>
+     *     <li>Cache the driver awareness event for its supplier</li>
+     *     <li>Update the current awareness value</li>
+     *     <li>Register to refresh the awareness value again when the new current expires</li>
+     * </ul>
+     *
+     * @param awarenessEventWrapper the driver awareness event that has occurred
+     */
+    @GuardedBy("mLock")
+    private void handleDriverAwarenessEventLocked(
+            DriverAwarenessEventWrapper awarenessEventWrapper) {
+        // update the current awareness event for the supplier, checking that it is the newest event
+        IDriverAwarenessSupplier supplier = awarenessEventWrapper.mSupplier;
+        long timestamp = awarenessEventWrapper.mAwarenessEvent.getTimeStamp();
+        if (!mCurrentAwarenessEventsMap.containsKey(supplier)
+                || mCurrentAwarenessEventsMap.get(supplier).mAwarenessEvent.getTimeStamp()
+                < timestamp) {
+            mCurrentAwarenessEventsMap.put(awarenessEventWrapper.mSupplier, awarenessEventWrapper);
+        }
+
+        int oldSupplierPriority = mDriverAwarenessSupplierPriorities.get(supplier);
+        float oldAwarenessValue = DEFAULT_AWARENESS_VALUE_FOR_LOG;
+        if (mCurrentDriverAwareness != null) {
+            oldAwarenessValue = mCurrentDriverAwareness.mAwarenessEvent.getAwarenessValue();
+        }
+
+        updateCurrentAwarenessValueLocked();
+
+        int newSupplierPriority = mDriverAwarenessSupplierPriorities.get(
+                mCurrentDriverAwareness.mSupplier);
+        if (mSupplierConfigs.get(mCurrentDriverAwareness.mSupplier).getMaxStalenessMillis()
+                != DriverAwarenessSupplierService.NO_STALENESS
+                && newSupplierPriority >= oldSupplierPriority) {
+            // only reschedule an expiration if this is for a supplier that is the same or higher
+            // priority than the old value. If there is a higher priority supplier with non-stale
+            // data, then mCurrentDriverAwareness won't change even though we received a new event.
+            scheduleExpirationTimerLocked();
+        }
+
+        if (oldAwarenessValue != mCurrentDriverAwareness.mAwarenessEvent.getAwarenessValue()) {
+            logd("Driver awareness updated: "
+                    + mCurrentDriverAwareness.mAwarenessEvent.getAwarenessValue());
+            addTransitionLogLocked(oldAwarenessValue,
+                    awarenessEventWrapper.mAwarenessEvent.getAwarenessValue(),
+                    "Driver awareness updated by "
+                            + awarenessEventWrapper.mSupplier.getClass().getSimpleName());
+        }
+
+        updateCurrentDistractionEventLocked();
+    }
+
+    /**
+     * Get the current awareness value.
+     */
+    @VisibleForTesting
+    DriverAwarenessEventWrapper getCurrentDriverAwareness() {
+        return mCurrentDriverAwareness;
+    }
+
+    /**
+     * Set the drier awareness suppliers. Allows circumventing the {@link #init()} logic.
+     */
+    @VisibleForTesting
+    void setDriverAwarenessSuppliers(
+            List<Pair<IDriverAwarenessSupplier, DriverAwarenessSupplierConfig>> suppliers) {
+        mPrioritizedDriverAwarenessSuppliers.clear();
+        mDriverAwarenessSupplierPriorities.clear();
+        for (int i = 0; i < suppliers.size(); i++) {
+            Pair<IDriverAwarenessSupplier, DriverAwarenessSupplierConfig> pair = suppliers.get(i);
+            mSupplierConfigs.put(pair.first, pair.second);
+            mDriverAwarenessSupplierPriorities.put(pair.first, i);
+            mPrioritizedDriverAwarenessSuppliers.add(pair.first);
+        }
+        mPrioritizedDriverAwarenessSuppliers.sort(mPrioritizedSuppliersComparator);
+    }
+
+    /**
+     * {@link CarPropertyEvent} listener registered with the {@link CarPropertyManager} for getting
+     * speed change notifications.
+     */
+    private final CarPropertyManager.CarPropertyEventCallback mSpeedPropertyEventCallback =
+            new CarPropertyManager.CarPropertyEventCallback() {
+                @Override
+                public void onChangeEvent(CarPropertyValue value) {
+                    synchronized (mLock) {
+                        handleSpeedEventLocked(value);
+                    }
+                }
+
+                @Override
+                public void onErrorEvent(int propId, int zone) {
+                    Log.e(TAG, "Error in callback for vehicle speed");
+                }
+            };
+
+
+    @VisibleForTesting
+    @GuardedBy("mLock")
+    void handleSpeedEventLocked(@NonNull CarPropertyValue value) {
+        if (value.getPropertyId() != VehiclePropertyIds.PERF_VEHICLE_SPEED) {
+            Log.e(TAG, "Unexpected property id: " + value.getPropertyId());
+            return;
+        }
+
+        float oldValue = mRequiredAwareness;
+        if ((Float) value.getValue() > 0) {
+            mRequiredAwareness = MOVING_REQUIRED_AWARENESS;
+        } else {
+            mRequiredAwareness = STATIONARY_REQUIRED_AWARENESS;
+        }
+
+        if (Float.compare(oldValue, mRequiredAwareness) != 0) {
+            logd("Required awareness updated: " + mRequiredAwareness);
+            addTransitionLogLocked(oldValue, mRequiredAwareness, "Required awareness");
+            updateCurrentDistractionEventLocked();
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void updateCurrentDistractionEventLocked() {
+        if (mCurrentDriverAwareness == null) {
+            logd("Driver awareness level is not yet known");
+            return;
+        }
+        float awarenessPercentage;
+        if (mRequiredAwareness == 0) {
+            // avoid divide by 0 error - awareness percentage should be 100% when required
+            // awareness is 0
+            awarenessPercentage = 1.0f;
+        } else {
+            // Cap awareness percentage at 100%
+            awarenessPercentage = Math.min(
+                    mCurrentDriverAwareness.mAwarenessEvent.getAwarenessValue()
+                            / mRequiredAwareness, 1.0f);
+        }
+        if (Float.compare(mCurrentDistractionEvent.getAwarenessPercentage(), awarenessPercentage)
+                == 0) {
+            // no need to dispatch unless there's a change
+            return;
+        }
+
+        addTransitionLogLocked(mCurrentDistractionEvent.getAwarenessPercentage(),
+                awarenessPercentage, "Awareness percentage");
+
+        mCurrentDistractionEvent = new DriverDistractionChangeEvent.Builder()
+                .setElapsedRealtimeTimestamp(mTimeSource.elapsedRealtime())
+                .setAwarenessPercentage(awarenessPercentage)
+                .build();
+
+        long nowUptimeMillis = mTimeSource.uptimeMillis();
+        if (shouldThrottleDispatchEventLocked(nowUptimeMillis)) {
+            scheduleAwarenessDispatchLocked(nowUptimeMillis);
+        } else {
+            // if event doesn't need to be throttled, emit immediately
+            DriverDistractionChangeEvent changeEvent = mCurrentDistractionEvent;
+            mClientDispatchHandler.post(
+                    () -> dispatchCurrentDistractionEventToClientsLocked(changeEvent));
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void scheduleAwarenessDispatchLocked(long uptimeMillis) {
+        if (mIsDispatchQueued) {
+            logd("Dispatch event is throttled and already scheduled.");
+            return;
+        }
+
+        // schedule a dispatch for when throttle window has passed
+        long delayMs = mLastDispatchUptimeMillis + DISPATCH_THROTTLE_MS - uptimeMillis;
+        if (delayMs < 0) {
+            Log.e(TAG, String.format(
+                    "Delay for (%s) calculated to be negative (%s), so dispatching immediately",
+                    mCurrentDistractionEvent, delayMs));
+            delayMs = 0;
+        }
+        logd(String.format("Dispatch event (%s) is throttled. Scheduled to emit in %sms",
+                mCurrentDistractionEvent, delayMs));
+        mIsDispatchQueued = true;
+        mClientDispatchHandler.postDelayed(mDispatchCurrentDistractionRunnable, delayMs);
+    }
+
+    @GuardedBy("mLock")
+    private boolean shouldThrottleDispatchEventLocked(long uptimeMillis) {
+        return uptimeMillis < mLastDispatchUptimeMillis + DISPATCH_THROTTLE_MS;
+    }
+
+    @GuardedBy("mLock")
+    private void dispatchCurrentDistractionEventToClientsLocked(
+            DriverDistractionChangeEvent changeEvent) {
+        mLastDispatchUptimeMillis = mTimeSource.uptimeMillis();
+        logd("Dispatching event to clients: " + changeEvent);
+        int numClients = mDistractionClients.beginBroadcast();
+        for (int i = 0; i < numClients; i++) {
+            IDriverDistractionChangeListener callback = mDistractionClients.getBroadcastItem(i);
+            try {
+                callback.onDriverDistractionChange(changeEvent);
+            } catch (RemoteException ignores) {
+                // ignore
+            }
+        }
+        mDistractionClients.finishBroadcast();
+    }
+
+    /**
+     * Internally register the supplier with the specified priority.
+     */
+    private void addDriverAwarenessSupplier(
+            ComponentName componentName,
+            IDriverAwarenessSupplier awarenessSupplier,
+            int priority) {
+        synchronized (mLock) {
+            mSupplierBinders.put(componentName, awarenessSupplier);
+            mDriverAwarenessSupplierPriorities.put(awarenessSupplier, priority);
+            mPrioritizedDriverAwarenessSuppliers.add(awarenessSupplier);
+            mPrioritizedDriverAwarenessSuppliers.sort(mPrioritizedSuppliersComparator);
+        }
+    }
+
+    /**
+     * Remove references to a supplier.
+     */
+    private void removeDriverAwarenessSupplier(ComponentName componentName) {
+        synchronized (mLock) {
+            IDriverAwarenessSupplier supplier = mSupplierBinders.get(componentName);
+            mSupplierBinders.remove(componentName);
+            mDriverAwarenessSupplierPriorities.remove(supplier);
+            mPrioritizedDriverAwarenessSuppliers.remove(supplier);
+        }
+    }
+
+    /**
+     * Update {@link #mCurrentDriverAwareness} based on the current driver awareness events for each
+     * supplier.
+     */
+    @GuardedBy("mLock")
+    private void updateCurrentAwarenessValueLocked() {
+        for (IDriverAwarenessSupplier supplier : mPrioritizedDriverAwarenessSuppliers) {
+            long supplierMaxStaleness = mSupplierConfigs.get(supplier).getMaxStalenessMillis();
+            DriverAwarenessEventWrapper eventForSupplier = mCurrentAwarenessEventsMap.get(supplier);
+            if (eventForSupplier == null) {
+                continue;
+            }
+            if (supplierMaxStaleness == DriverAwarenessSupplierService.NO_STALENESS) {
+                // this supplier can't be stale, so use its information
+                mCurrentDriverAwareness = eventForSupplier;
+                return;
+            }
+
+            long oldestFreshTimestamp = mTimeSource.elapsedRealtime() - supplierMaxStaleness;
+            if (eventForSupplier.mAwarenessEvent.getTimeStamp() > oldestFreshTimestamp) {
+                // value is still fresh, so use it
+                mCurrentDriverAwareness = eventForSupplier;
+                return;
+            }
+        }
+
+        if (mCurrentDriverAwareness == null) {
+            // There must always at least be a fallback supplier with NO_STALENESS configuration.
+            // Since we control this configuration, getting this exception represents a developer
+            // error in initialization.
+            throw new IllegalStateException(
+                    "Unable to determine the current driver awareness value");
+        }
+    }
+
+    /**
+     * Sets a timer to update the refresh the awareness value once the current value has become
+     * stale.
+     */
+    @GuardedBy("mLock")
+    private void scheduleExpirationTimerLocked() {
+        // reschedule the current awareness expiration task
+        mExpiredDriverAwarenessTimer.reset();
+        long delay = mCurrentDriverAwareness.mAwarenessEvent.getTimeStamp()
+                - mTimeSource.elapsedRealtime()
+                + mCurrentDriverAwareness.mMaxStaleness;
+        if (delay < 0) {
+            // somehow the event is already stale
+            synchronized (mLock) {
+                updateCurrentAwarenessValueLocked();
+            }
+            return;
+        }
+        mExpiredDriverAwarenessTimer.schedule(new TimerTask() {
+            @Override
+            public void run() {
+                logd("Driver awareness has become stale. Selecting new awareness level.");
+                synchronized (mLock) {
+                    updateCurrentAwarenessValueLocked();
+                    updateCurrentDistractionEventLocked();
+                }
+            }
+        }, delay);
+
+        logd(String.format(
+                "Current awareness value is stale after %sms and is scheduled to expire in %sms",
+                mCurrentDriverAwareness.mMaxStaleness, delay));
+    }
+
+    /**
+     * Add the state change to the transition log.
+     *
+     * @param oldValue the old value
+     * @param newValue the new value
+     * @param extra    name of the value being changed
+     */
+    @GuardedBy("mLock")
+    private void addTransitionLogLocked(float oldValue, float newValue, String extra) {
+        if (mTransitionLogs.size() >= MAX_EVENT_LOG_COUNT) {
+            mTransitionLogs.remove();
+        }
+
+        Utils.TransitionLog tLog = new Utils.TransitionLog(TAG, oldValue, newValue,
+                System.currentTimeMillis(), extra);
+        mTransitionLogs.add(tLog);
+    }
+
+    private static void logd(String message) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, message);
+        }
+    }
+
+    @Override
+    public DriverDistractionChangeEvent getLastDistractionEvent() throws RemoteException {
+        IExperimentalCarImpl.assertPermission(mContext,
+                ExperimentalCar.PERMISSION_READ_CAR_DRIVER_DISTRACTION);
+        synchronized (mLock) {
+            return mCurrentDistractionEvent;
+        }
+    }
+
+    @Override
+    public void addDriverDistractionChangeListener(IDriverDistractionChangeListener listener)
+            throws RemoteException {
+        IExperimentalCarImpl.assertPermission(mContext,
+                ExperimentalCar.PERMISSION_READ_CAR_DRIVER_DISTRACTION);
+        if (listener == null) {
+            throw new IllegalArgumentException("IDriverDistractionChangeListener is null");
+        }
+        mDistractionClients.register(listener);
+
+        DriverDistractionChangeEvent changeEvent = mCurrentDistractionEvent;
+        mClientDispatchHandler.post(() -> {
+            try {
+                listener.onDriverDistractionChange(changeEvent);
+            } catch (RemoteException ignores) {
+                // ignore
+            }
+        });
+    }
+
+
+    @Override
+    public void removeDriverDistractionChangeListener(IDriverDistractionChangeListener listener)
+            throws RemoteException {
+        IExperimentalCarImpl.assertPermission(mContext,
+                ExperimentalCar.PERMISSION_READ_CAR_DRIVER_DISTRACTION);
+        if (listener == null) {
+            Log.e(TAG, "unregisterUxRestrictionsChangeListener(): listener null");
+            throw new IllegalArgumentException("Listener is null");
+        }
+        mDistractionClients.unregister(listener);
+    }
+
+    /**
+     * The service connection between this distraction service and a {@link
+     * DriverAwarenessSupplierService}, communicated through {@link IDriverAwarenessSupplier}.
+     */
+    private class DriverAwarenessServiceConnection implements ServiceConnection {
+
+        final int mPriority;
+
+        /**
+         * Create an instance of {@link DriverAwarenessServiceConnection}.
+         *
+         * @param priority the priority of the {@link DriverAwarenessSupplierService} that this
+         *                 connection is for
+         */
+        DriverAwarenessServiceConnection(int priority) {
+            mPriority = priority;
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder binder) {
+            logd("onServiceConnected, name: " + name + ", binder: " + binder);
+            IDriverAwarenessSupplier service = IDriverAwarenessSupplier.Stub.asInterface(
+                    binder);
+            addDriverAwarenessSupplier(name, service, mPriority);
+            try {
+                service.setCallback(new DriverAwarenessSupplierCallback(name));
+                service.onReady();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Unable to call onReady on supplier", e);
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            logd("onServiceDisconnected, name: " + name);
+            removeDriverAwarenessSupplier(name);
+            // TODO(b/146471650) rebind to driver awareness suppliers on service disconnect
+        }
+    }
+
+    /**
+     * Driver awareness listener that keeps a references to some attributes of the supplier.
+     */
+    private class DriverAwarenessSupplierCallback extends IDriverAwarenessSupplierCallback.Stub {
+
+        private final ComponentName mComponentName;
+
+        /**
+         * Construct an instance  of {@link DriverAwarenessSupplierCallback}.
+         *
+         * @param componentName the driver awareness supplier for this listener
+         */
+        DriverAwarenessSupplierCallback(ComponentName componentName) {
+            mComponentName = componentName;
+        }
+
+        @Override
+        public void onDriverAwarenessUpdated(DriverAwarenessEvent event) {
+            IDriverAwarenessSupplier supplier;
+            long maxStaleness;
+            synchronized (mLock) {
+                supplier = mSupplierBinders.get(mComponentName);
+                maxStaleness = mSupplierConfigs.get(supplier).getMaxStalenessMillis();
+            }
+            if (supplier == null) {
+                // this should never happen. Initialization process would not be correct.
+                throw new IllegalStateException(
+                        "No supplier registered for component " + mComponentName);
+            }
+            logd(String.format("Driver awareness updated for %s: %s",
+                    supplier.getClass().getSimpleName(), event));
+            handleDriverAwarenessEvent(
+                    new DriverAwarenessEventWrapper(event, supplier, maxStaleness));
+        }
+
+        @Override
+        public void onConfigLoaded(DriverAwarenessSupplierConfig config) throws RemoteException {
+            synchronized (mLock) {
+                mSupplierConfigs.put(mSupplierBinders.get(mComponentName), config);
+            }
+        }
+    }
+
+    /**
+     * Wrapper for {@link DriverAwarenessEvent} that includes some information from the supplier
+     * that emitted the event.
+     */
+    @VisibleForTesting
+    static class DriverAwarenessEventWrapper {
+        final DriverAwarenessEvent mAwarenessEvent;
+        final IDriverAwarenessSupplier mSupplier;
+        final long mMaxStaleness;
+
+        /**
+         * Construct an instance of {@link DriverAwarenessEventWrapper}.
+         *
+         * @param awarenessEvent the driver awareness event being wrapped
+         * @param supplier       the driver awareness supplier for this listener
+         * @param maxStaleness   the max staleness of the supplier that emitted this event (included
+         *                       to avoid making a binder call)
+         */
+        DriverAwarenessEventWrapper(
+                DriverAwarenessEvent awarenessEvent,
+                IDriverAwarenessSupplier supplier,
+                long maxStaleness) {
+            mAwarenessEvent = awarenessEvent;
+            mSupplier = supplier;
+            mMaxStaleness = maxStaleness;
+        }
+
+        @Override
+        public String toString() {
+            return String.format(
+                    "DriverAwarenessEventWrapper{mAwarenessChangeEvent=%s, mSupplier=%s, "
+                            + "mMaxStaleness=%s}",
+                    mAwarenessEvent, mSupplier, mMaxStaleness);
+        }
+    }
+}
diff --git a/experimental/service/src/com/android/experimentalcar/ExperimentalCarService.java b/experimental/service/src/com/android/experimentalcar/ExperimentalCarService.java
new file mode 100644
index 0000000..065f8e9
--- /dev/null
+++ b/experimental/service/src/com/android/experimentalcar/ExperimentalCarService.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.experimentalcar;
+
+import android.app.Service;
+import android.car.Car;
+import android.content.Intent;
+import android.os.IBinder;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Top class to keep all experimental features.
+ */
+public class ExperimentalCarService extends Service {
+
+    private Car mCar;
+    private final IExperimentalCarImpl mIExperimentalCarImpl = new IExperimentalCarImpl(this);
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        // This is for crashing this service when car service crashes.
+        mCar = Car.createCar(this);
+    }
+
+    @Override
+    public void onDestroy() {
+        mIExperimentalCarImpl.release();
+        if (mCar != null && mCar.isConnected()) {
+            mCar.disconnect();
+            mCar = null;
+        }
+        super.onDestroy();
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        // keep it alive.
+        return START_STICKY;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mIExperimentalCarImpl;
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        mIExperimentalCarImpl.dump(fd, writer, args);
+    }
+}
diff --git a/experimental/service/src/com/android/experimentalcar/GazeAttentionProcessor.java b/experimental/service/src/com/android/experimentalcar/GazeAttentionProcessor.java
new file mode 100644
index 0000000..66e3a48
--- /dev/null
+++ b/experimental/service/src/com/android/experimentalcar/GazeAttentionProcessor.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.experimentalcar;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.car.occupantawareness.GazeDetection;
+import android.util.Log;
+
+/** {@link GazeAttentionProcessor} estimates driver attention based on a gaze history. */
+class GazeAttentionProcessor {
+    private static final String TAG = "Car.OAS.GazeAttentionProcessor";
+    private static final int NOT_SET = -1;
+
+    private final Configuration mConfig;
+
+    /** Current attention value. */
+    @FloatRange(from = 0.0f, to = 1.0f)
+    private float mAttention;
+
+    /** Timestamp of last frame received, in milliseconds since boot. */
+    private long mLastTimestamp = NOT_SET;
+
+    GazeAttentionProcessor(Configuration configuration) {
+        mConfig = configuration;
+        mAttention = mConfig.initialValue;
+    }
+
+    /** Gets the current attention awareness value. */
+    @FloatRange(from = 0.0f, to = 1.0f)
+    public float getAttention() {
+        return mAttention;
+    }
+
+    /**
+     * Updates the current attention with a new gaze detection.
+     *
+     * @param detection New {@link android.car.occupantawareness.GazeDetection} data.
+     * @param timestamp Timestamp that the detection was detected, in milliseconds since boot.
+     * @return Attention value [0, 1].
+     */
+    @FloatRange(from = 0.0f, to = 1.0f)
+    public float updateAttention(@NonNull GazeDetection detection, long timestamp) {
+        // When the first frame of data is received, no duration can be computed. Just capture the
+        // timestamp for the next pass and return the initial buffer value.
+        if (mLastTimestamp == NOT_SET) {
+            logd("First pass, returning 'initialValue=" + mConfig.initialValue);
+            mLastTimestamp = timestamp;
+            return mConfig.initialValue;
+        }
+
+        float startingAttention = mAttention;
+
+        // Compute the time since the last detection, in seconds.
+        float dtSeconds = (float) (timestamp - mLastTimestamp) / 1000.0f;
+
+        if (isOnRoadGaze(detection.gazeTarget)) {
+            logd("Handling on-road gaze");
+            mAttention += dtSeconds * mConfig.growthRate;
+            mAttention = Math.min(mAttention, 1.0f); // Cap value to max of 1.
+        } else {
+            logd("Handling off-road gaze");
+            mAttention -= dtSeconds * mConfig.decayRate;
+            mAttention = Math.max(mAttention, 0.0f); // Cap value to min of 0.
+        }
+
+        // Save current timestamp for next pass.
+        mLastTimestamp = timestamp;
+
+        logd(String.format("updateAttention(): Time=%1.2f. Attention [%f]->[%f]. ",
+                dtSeconds, startingAttention, mAttention));
+
+        return mAttention;
+    }
+
+    /** Gets whether the gaze target is on-road. */
+    private boolean isOnRoadGaze(@GazeDetection.VehicleRegion int gazeTarget) {
+        switch (gazeTarget) {
+            case GazeDetection.VEHICLE_REGION_FORWARD_ROADWAY:
+            case GazeDetection.VEHICLE_REGION_LEFT_ROADWAY:
+            case GazeDetection.VEHICLE_REGION_RIGHT_ROADWAY:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    private static void logd(String message) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, message);
+        }
+    }
+
+    /** Configuration settings for {@link GazeAttentionProcessor}. */
+    public static class Configuration {
+        /** Initial value for the attention buffer, [0, 1]. */
+        @FloatRange(from = 0.0f, to = 1.0f)
+        public final float initialValue;
+
+        /**
+         * Rate at which the attention decays when the driver is looking off-road (per second of
+         * off-road looks)
+         */
+        public final float decayRate;
+
+        /**
+         * Rate at which the attention grows when the driver is looking on-road (per second of
+         * on-road looks).
+         */
+        public final float growthRate;
+
+        /**
+         * Creates an instance of {@link Configuration}.
+         *
+         * @param initialValue the initial value that the attention buffer starts at.
+         * @param decayRate the rate at which the attention buffer decreases when the driver is
+         *     looking off-road.
+         * @param growthRate the rate at which the attention buffer increases when the driver is
+         *     looking on-road.
+         */
+        Configuration(float initialValue, float decayRate, float growthRate) {
+            this.initialValue = initialValue;
+            this.decayRate = decayRate;
+            this.growthRate = growthRate;
+        }
+
+        @Override
+        public String toString() {
+            return String.format(
+                    "Configuration{initialValue=%s, decayRate=%s, growthRate=%s}",
+                    initialValue, decayRate, growthRate);
+        }
+    }
+}
diff --git a/experimental/service/src/com/android/experimentalcar/GazeDriverAwarenessSupplier.java b/experimental/service/src/com/android/experimentalcar/GazeDriverAwarenessSupplier.java
new file mode 100644
index 0000000..bd980bd
--- /dev/null
+++ b/experimental/service/src/com/android/experimentalcar/GazeDriverAwarenessSupplier.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.experimentalcar;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.car.Car;
+import android.car.experimental.DriverAwarenessEvent;
+import android.car.experimental.DriverAwarenessSupplierService;
+import android.car.occupantawareness.OccupantAwarenessDetection;
+import android.car.occupantawareness.OccupantAwarenessManager;
+import android.car.occupantawareness.SystemStatusEvent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.IBinder;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * A Driver Awareness Supplier that estimates the driver's current level of awareness based on gaze
+ * history.
+ *
+ * <p>Attention is facilitated via {@link OccupantAwarenessManager}, which is an optional component
+ * and may not be available on every platform.
+ */
+public class GazeDriverAwarenessSupplier extends DriverAwarenessSupplierService {
+    private static final String TAG = "Car.OAS.GazeAwarenessSupplier";
+
+    /* Maximum allowable staleness before gaze data should be considered unreliable for attention
+     * monitoring, in milliseconds. */
+    @VisibleForTesting
+    static final long MAX_STALENESS_MILLIS = 500;
+
+    private final Object mLock = new Object();
+    private final ITimeSource mTimeSource;
+
+    @GuardedBy("mLock")
+    private GazeAttentionProcessor.Configuration mConfiguration;
+
+    @Nullable
+    private Context mContext;
+
+    @GuardedBy("mLock")
+    private Car mCar;
+
+    @GuardedBy("mLock")
+    private OccupantAwarenessManager mOasManager;
+
+    @GuardedBy("mLock")
+    private GazeAttentionProcessor mProcessor;
+
+    /**
+     * Empty constructor allows system service creation.
+     */
+    public GazeDriverAwarenessSupplier() {
+        this(/* context= */ null, new SystemTimeSource());
+    }
+
+    @VisibleForTesting
+    GazeDriverAwarenessSupplier(Context context, ITimeSource timeSource) {
+        mContext = context;
+        mTimeSource = timeSource;
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        if (mContext == null) {
+            mContext = this;
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        synchronized (mLock) {
+            if (mCar != null && mCar.isConnected()) {
+                mCar.disconnect();
+            }
+        }
+        super.onDestroy();
+    }
+
+    /**
+     * Gets the self-reported maximum allowable staleness before the supplier should be considered
+     * failed, in milliseconds.
+     */
+    @Override
+    public long getMaxStalenessMillis() {
+        return MAX_STALENESS_MILLIS;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        logd("onBind with intent: " + intent);
+        return super.onBind(intent);
+    }
+
+    @Override
+    public void onReady() {
+        synchronized (mLock) {
+            mConfiguration = loadConfiguration();
+            mProcessor = new GazeAttentionProcessor(mConfiguration);
+            mCar = Car.createCar(mContext);
+            if (mCar != null) {
+                if (mOasManager == null && mCar.isFeatureEnabled(Car.OCCUPANT_AWARENESS_SERVICE)) {
+                    mOasManager =
+                            (OccupantAwarenessManager)
+                                    mCar.getCarManager(Car.OCCUPANT_AWARENESS_SERVICE);
+
+                    if (mOasManager == null) {
+                        Log.e(TAG, "Failed to get OccupantAwarenessManager.");
+                    }
+                }
+
+                if (mOasManager != null) {
+                    logd("Registering callback with OAS manager");
+                    mOasManager.registerChangeCallback(new ChangeCallback());
+                }
+            }
+        }
+
+        // Send an initial value once the provider is ready, as required by {link
+        // IDriverAwarenessSupplierCallback}.
+        emitAwarenessEvent(
+                new DriverAwarenessEvent(
+                        mTimeSource.elapsedRealtime(), mConfiguration.initialValue));
+    }
+
+    /**
+     * Returns whether this car supports gaze based awareness.
+     *
+     * <p>The underlying Occupant Awareness System is optional and may not be supported on every
+     * vehicle. This method must be called *after* onReady().
+     */
+    public boolean supportsGaze() throws IllegalStateException {
+        synchronized (mLock) {
+            if (mCar == null) {
+                throw new IllegalStateException(
+                        "Must call onReady() before querying for gaze support");
+            }
+
+            // Occupant Awareness is optional and may not be available on this machine. If not
+            // available, the returned manager will be null.
+            if (mOasManager == null) {
+                logd("Occupant Awareness System is not available on this machine");
+                return false;
+            }
+
+            int driver_capability =
+                    mOasManager.getCapabilityForRole(
+                            OccupantAwarenessDetection.VEHICLE_OCCUPANT_DRIVER);
+
+            logd("Driver capabilities flags: " + driver_capability);
+
+            return (driver_capability & SystemStatusEvent.DETECTION_TYPE_DRIVER_MONITORING) > 0;
+        }
+    }
+
+    /** Builds {@link GazeAttentionProcessor.Configuration} using context resources. */
+    private GazeAttentionProcessor.Configuration loadConfiguration() {
+        Resources resources = mContext.getResources();
+
+        return new GazeAttentionProcessor.Configuration(
+                resources.getFloat(R.fraction.driverAwarenessGazeModelInitialValue),
+                resources.getFloat(R.fraction.driverAwarenessGazeModelDecayRate),
+                resources.getFloat(R.fraction.driverAwarenessGazeModelGrowthRate));
+    }
+
+    /** Processes a new detection event, updating the current attention value. */
+    @VisibleForTesting
+    void processDetectionEvent(@NonNull OccupantAwarenessDetection event) {
+        if (event.role == OccupantAwarenessDetection.VEHICLE_OCCUPANT_DRIVER
+                && event.gazeDetection != null) {
+            float awarenessValue;
+            synchronized (mLock) {
+                awarenessValue =
+                        mProcessor.updateAttention(event.gazeDetection, event.timestampMillis);
+            }
+
+            emitAwarenessEvent(new DriverAwarenessEvent(event.timestampMillis, awarenessValue));
+        }
+    }
+
+    @VisibleForTesting
+    void emitAwarenessEvent(@NonNull DriverAwarenessEvent event) {
+        logd("Emitting new event: " + event);
+        onDriverAwarenessUpdated(event);
+    }
+
+    private static void logd(String message) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, message);
+        }
+    }
+
+    /** Callback when the system status changes or a new detection is made. */
+    private class ChangeCallback extends OccupantAwarenessManager.ChangeCallback {
+        /** Called when the system state changes changes. */
+        @Override
+        public void onSystemStateChanged(@NonNull SystemStatusEvent status) {
+            logd("New status: " + status);
+        }
+
+        /** Called when a detection event is generated. */
+        @Override
+        public void onDetectionEvent(@NonNull OccupantAwarenessDetection event) {
+            logd("New detection: " + event);
+            processDetectionEvent(event);
+        }
+    }
+}
diff --git a/experimental/service/src/com/android/experimentalcar/IExperimentalCarImpl.java b/experimental/service/src/com/android/experimentalcar/IExperimentalCarImpl.java
new file mode 100644
index 0000000..905b268
--- /dev/null
+++ b/experimental/service/src/com/android/experimentalcar/IExperimentalCarImpl.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.experimentalcar;
+
+import android.annotation.MainThread;
+import android.annotation.Nullable;
+import android.car.IExperimentalCar;
+import android.car.IExperimentalCarHelper;
+import android.car.experimental.CarDriverDistractionManager;
+import android.car.experimental.CarTestDemoExperimentalFeatureManager;
+import android.car.experimental.ExperimentalCar;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.car.CarServiceBase;
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Implements IExperimentalCar for experimental features.
+ */
+public final class IExperimentalCarImpl extends IExperimentalCar.Stub {
+
+    private static final String TAG = "CAR.EXPIMPL";
+
+    private static final List<String> ALL_AVAILABLE_FEATURES = Arrays.asList(
+            ExperimentalCar.TEST_EXPERIMENTAL_FEATURE_SERVICE,
+            ExperimentalCar.DRIVER_DISTRACTION_EXPERIMENTAL_FEATURE_SERVICE
+    );
+
+    private final Context mContext;
+
+    private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private boolean mReleased;
+
+    @GuardedBy("mLock")
+    private IExperimentalCarHelper mHelper;
+
+    @GuardedBy("mLock")
+    private ArrayList<CarServiceBase> mRunningServices = new ArrayList<>();
+
+    public IExperimentalCarImpl(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public void init(IExperimentalCarHelper helper, List<String> enabledFeatures) {
+        // From car service or unit testing only
+        assertCallingFromSystemProcessOrSelf();
+
+        // dispatch to main thread as release is always done in main.
+        mMainThreadHandler.post(() -> {
+            synchronized (mLock) {
+                if (mReleased) {
+                    Log.w(TAG, "init binder call after onDestroy, will ignore");
+                    return;
+                }
+            }
+            ArrayList<CarServiceBase> services = new ArrayList<>();
+            ArrayList<String> startedFeatures = new ArrayList<>();
+            ArrayList<String> classNames = new ArrayList<>();
+            ArrayList<IBinder> binders = new ArrayList<>();
+
+            // This cannot address inter-dependency. That requires re-ordering this in dependency
+            // order.
+            // That should be done when we find such needs. For now, each feature inside here should
+            // not have inter-dependency as they are all optional.
+            for (String feature : enabledFeatures) {
+                CarServiceBase service = constructServiceForFeature(feature);
+                if (service == null) {
+                    Log.e(TAG, "Failed to construct requested feature:" + feature);
+                    continue;
+                }
+                service.init();
+                services.add(service);
+                startedFeatures.add(feature);
+                // If it is not IBinder, then it is internal feature.
+                if (service instanceof IBinder) {
+                    binders.add((IBinder) service);
+                } else {
+                    binders.add(null);
+                }
+                classNames.add(getClassNameForFeature(feature));
+            }
+            try {
+                helper.onInitComplete(ALL_AVAILABLE_FEATURES, startedFeatures, classNames, binders);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Car service crashed?", e);
+                // will be destroyed soon. Just continue and register services for possible cleanup.
+            }
+            synchronized (mLock) {
+                mHelper = helper;
+                mRunningServices.addAll(services);
+            }
+        });
+    }
+
+    // should be called in Service.onDestroy
+    @MainThread
+    void release() {
+        // Copy to handle call release without lock
+        ArrayList<CarServiceBase> services;
+        synchronized (mLock) {
+            if (mReleased) {
+                return;
+            }
+            mReleased = true;
+            services = new ArrayList<>(mRunningServices);
+            mRunningServices.clear();
+        }
+        for (CarServiceBase service : services) {
+            service.release();
+        }
+    }
+
+    /** dump */
+    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        ArrayList<CarServiceBase> services;
+        synchronized (mLock) {
+            writer.println("mReleased:" + mReleased);
+            writer.println("ALL_AVAILABLE_FEATURES:" + ALL_AVAILABLE_FEATURES);
+            services = new ArrayList<>(mRunningServices);
+        }
+        writer.println(" Number of running services:" + services.size());
+        int i = 0;
+        for (CarServiceBase service : services) {
+            writer.print(i + ":");
+            service.dump(writer);
+            i++;
+        }
+    }
+
+    @Nullable
+    private String getClassNameForFeature(String featureName) {
+        switch (featureName) {
+            case ExperimentalCar.TEST_EXPERIMENTAL_FEATURE_SERVICE:
+                return CarTestDemoExperimentalFeatureManager.class.getName();
+            case ExperimentalCar.DRIVER_DISTRACTION_EXPERIMENTAL_FEATURE_SERVICE:
+                return CarDriverDistractionManager.class.getName();
+            default:
+                return null;
+        }
+    }
+
+    @Nullable
+    private CarServiceBase constructServiceForFeature(String featureName) {
+        switch (featureName) {
+            case ExperimentalCar.TEST_EXPERIMENTAL_FEATURE_SERVICE:
+                return new TestDemoExperimentalFeatureService();
+            case ExperimentalCar.DRIVER_DISTRACTION_EXPERIMENTAL_FEATURE_SERVICE:
+                return new DriverDistractionExperimentalFeatureService(mContext);
+            default:
+                return null;
+        }
+    }
+
+    private static void assertCallingFromSystemProcessOrSelf() {
+        int uid = Binder.getCallingUid();
+        int pid = Binder.getCallingPid();
+        if (uid != Process.SYSTEM_UID && pid != Process.myPid()) {
+            throw new SecurityException("Only allowed from system or self, uid:" + uid
+                    + " pid:" + pid);
+        }
+    }
+
+    /**
+     * Assert that a permission has been granted for the current context.
+     */
+    public static void assertPermission(Context context, String permission) {
+        if (context.checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("requires " + permission);
+        }
+    }
+}
diff --git a/experimental/service/src/com/android/experimentalcar/ITimeSource.java b/experimental/service/src/com/android/experimentalcar/ITimeSource.java
new file mode 100644
index 0000000..4dc26d3
--- /dev/null
+++ b/experimental/service/src/com/android/experimentalcar/ITimeSource.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.experimentalcar;
+
+import android.os.SystemClock;
+
+/**
+ * Interface to abstract dependency on {@link android.os.SystemClock}.
+ */
+public interface ITimeSource {
+
+    /**
+     * See {@link SystemClock#elapsedRealtime()}.
+     */
+    long elapsedRealtime();
+
+    /**
+     * See {@link SystemClock#uptimeMillis()}.
+     */
+    long uptimeMillis();
+}
diff --git a/experimental/service/src/com/android/experimentalcar/ITimer.java b/experimental/service/src/com/android/experimentalcar/ITimer.java
new file mode 100644
index 0000000..104a1d1
--- /dev/null
+++ b/experimental/service/src/com/android/experimentalcar/ITimer.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.experimentalcar;
+
+import java.util.TimerTask;
+
+/**
+ * Interface to abstract dependency on {@link java.util.Timer}.
+ */
+public interface ITimer {
+
+    /**
+     * Cancel the timer and prepare for new events.
+     */
+    void reset();
+
+    /**
+     * See {@link java.util.Timer#schedule(TimerTask, long)}.
+     */
+    void schedule(TimerTask task, long delay);
+
+    /**
+     * See {@link java.util.Timer#cancel()}.
+     */
+    void cancel();
+}
diff --git a/experimental/service/src/com/android/experimentalcar/SampleExternalDriverAwarenessSupplier.java b/experimental/service/src/com/android/experimentalcar/SampleExternalDriverAwarenessSupplier.java
new file mode 100644
index 0000000..917ac20
--- /dev/null
+++ b/experimental/service/src/com/android/experimentalcar/SampleExternalDriverAwarenessSupplier.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.experimentalcar;
+
+import android.car.experimental.DriverAwarenessEvent;
+import android.car.experimental.DriverAwarenessSupplierService;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.SystemClock;
+import android.util.Log;
+
+/**
+ * Simple example of how an external driver awareness supplier service could be implemented.
+ */
+public class SampleExternalDriverAwarenessSupplier extends DriverAwarenessSupplierService {
+
+    private static final String TAG = "SampleExternalDriverAwarenessSupplier";
+    private static final float INITIAL_DRIVER_AWARENESS_VALUE = 1.0f;
+    private static final long MAX_STALENESS_MILLIS = 100L;
+
+    @Override
+    public long getMaxStalenessMillis() {
+        return MAX_STALENESS_MILLIS;
+    }
+
+    @Override
+    public void onReady() {
+        // send an initial event, as required by the IDriverAwarenessSupplierCallback spec
+        onDriverAwarenessUpdated(new DriverAwarenessEvent(SystemClock.elapsedRealtime(),
+                INITIAL_DRIVER_AWARENESS_VALUE));
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        logd("onBind, intent: " + intent);
+        return super.onBind(intent);
+    }
+
+    private static void logd(String message) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, message);
+        }
+    }
+}
diff --git a/experimental/service/src/com/android/experimentalcar/SystemTimeSource.java b/experimental/service/src/com/android/experimentalcar/SystemTimeSource.java
new file mode 100644
index 0000000..2af05e7
--- /dev/null
+++ b/experimental/service/src/com/android/experimentalcar/SystemTimeSource.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.experimentalcar;
+
+import android.os.SystemClock;
+
+/**
+ * Time source implementation using {@link SystemClock}.
+ */
+public class SystemTimeSource implements ITimeSource {
+
+    @Override
+    public long elapsedRealtime() {
+        return SystemClock.elapsedRealtime();
+    }
+
+    @Override
+    public long uptimeMillis() {
+        return SystemClock.uptimeMillis();
+    }
+}
diff --git a/experimental/service/src/com/android/experimentalcar/SystemTimer.java b/experimental/service/src/com/android/experimentalcar/SystemTimer.java
new file mode 100644
index 0000000..18f9c5e
--- /dev/null
+++ b/experimental/service/src/com/android/experimentalcar/SystemTimer.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.experimentalcar;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * Implementation of {@link ITimer} that uses {@link Timer}.
+ */
+public class SystemTimer implements ITimer {
+
+    private Timer mTimer = new Timer();
+
+    @Override
+    public void reset() {
+        mTimer.cancel();
+        mTimer = new Timer();
+    }
+
+    @Override
+    public void schedule(TimerTask task, long delay) {
+        mTimer.schedule(task, delay);
+    }
+
+    @Override
+    public void cancel() {
+        mTimer.cancel();
+    }
+}
diff --git a/experimental/service/src/com/android/experimentalcar/TestDemoExperimentalFeatureService.java b/experimental/service/src/com/android/experimentalcar/TestDemoExperimentalFeatureService.java
new file mode 100644
index 0000000..1309dd2
--- /dev/null
+++ b/experimental/service/src/com/android/experimentalcar/TestDemoExperimentalFeatureService.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.experimentalcar;
+
+import android.car.experimental.ITestDemoExperimental;
+
+import com.android.car.CarServiceBase;
+
+import java.io.PrintWriter;
+
+/**
+ * Demo service for testing experimental feature.
+ */
+public final class TestDemoExperimentalFeatureService extends ITestDemoExperimental.Stub
+        implements CarServiceBase {
+
+    @Override
+    public void init() {
+        // Nothing to do
+    }
+
+    @Override
+    public void release() {
+        // Nothing to do
+    }
+
+    @Override
+    public void dump(PrintWriter writer) {
+        writer.println("*TestExperimentalFeatureService*");
+    }
+
+    @Override
+    public String ping(String msg) {
+        return msg;
+    }
+}
diff --git a/experimental/service/src/com/android/experimentalcar/TouchDriverAwarenessSupplier.java b/experimental/service/src/com/android/experimentalcar/TouchDriverAwarenessSupplier.java
new file mode 100644
index 0000000..fa8bc34
--- /dev/null
+++ b/experimental/service/src/com/android/experimentalcar/TouchDriverAwarenessSupplier.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.experimentalcar;
+
+import android.car.experimental.DriverAwarenessEvent;
+import android.car.experimental.DriverAwarenessSupplierConfig;
+import android.car.experimental.DriverAwarenessSupplierService;
+import android.car.experimental.IDriverAwarenessSupplier;
+import android.car.experimental.IDriverAwarenessSupplierCallback;
+import android.content.Context;
+import android.hardware.input.InputManager;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.Display;
+import android.view.InputChannel;
+import android.view.InputEvent;
+import android.view.InputEventReceiver;
+import android.view.InputMonitor;
+import android.view.MotionEvent;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+
+/**
+ * A driver awareness supplier that estimates the driver's current awareness level based on touches
+ * on the headunit.
+ */
+public class TouchDriverAwarenessSupplier extends IDriverAwarenessSupplier.Stub {
+
+    private static final String TAG = "Car.TouchAwarenessSupplier";
+    private static final String TOUCH_INPUT_CHANNEL_NAME = "TouchDriverAwarenessInputChannel";
+
+    private static final long MAX_STALENESS = DriverAwarenessSupplierService.NO_STALENESS;
+
+    @VisibleForTesting
+    static final float INITIAL_DRIVER_AWARENESS_VALUE = 1.0f;
+
+    private final AtomicInteger mCurrentPermits = new AtomicInteger();
+    private final ScheduledExecutorService mRefreshScheduler;
+    private final Looper mLooper;
+    private final Context mContext;
+    private final ITimeSource mTimeSource;
+    private final Runnable mRefreshPermitRunnable;
+    private final IDriverAwarenessSupplierCallback mDriverAwarenessSupplierCallback;
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private long mLastEventMillis;
+
+    @GuardedBy("mLock")
+    private ScheduledFuture<?> mRefreshScheduleHandle;
+
+    @GuardedBy("mLock")
+    private Config mConfig;
+
+    // Main thread only. Hold onto reference to avoid garbage collection
+    private InputMonitor mInputMonitor;
+
+    // Main thread only. Hold onto reference to avoid garbage collection
+    private InputEventReceiver mInputEventReceiver;
+
+    TouchDriverAwarenessSupplier(Context context,
+            IDriverAwarenessSupplierCallback driverAwarenessSupplierCallback, Looper looper) {
+        this(context, driverAwarenessSupplierCallback, Executors.newScheduledThreadPool(1),
+                looper, new SystemTimeSource());
+    }
+
+    @VisibleForTesting
+    TouchDriverAwarenessSupplier(
+            Context context,
+            IDriverAwarenessSupplierCallback driverAwarenessSupplierCallback,
+            ScheduledExecutorService refreshScheduler,
+            Looper looper,
+            ITimeSource timeSource) {
+        mContext = context;
+        mDriverAwarenessSupplierCallback = driverAwarenessSupplierCallback;
+        mRefreshScheduler = refreshScheduler;
+        mLooper = looper;
+        mTimeSource = timeSource;
+        mRefreshPermitRunnable =
+                () -> {
+                    synchronized (mLock) {
+                        handlePermitRefreshLocked(mTimeSource.elapsedRealtime());
+                    }
+                };
+    }
+
+
+    @Override
+    public void onReady() {
+        try {
+            mDriverAwarenessSupplierCallback.onConfigLoaded(
+                    new DriverAwarenessSupplierConfig(MAX_STALENESS));
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to send config - abandoning ready process", e);
+            return;
+        }
+        // send an initial event, as required by the IDriverAwarenessSupplierCallback spec
+        try {
+            mDriverAwarenessSupplierCallback.onDriverAwarenessUpdated(
+                    new DriverAwarenessEvent(mTimeSource.elapsedRealtime(),
+                            INITIAL_DRIVER_AWARENESS_VALUE));
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to emit initial awareness event", e);
+        }
+        synchronized (mLock) {
+            mConfig = loadConfig();
+            logd("Config loaded: " + mConfig);
+            mCurrentPermits.set(mConfig.getMaxPermits());
+        }
+        startTouchMonitoring();
+    }
+
+    @Override
+    public void setCallback(IDriverAwarenessSupplierCallback callback) {
+        // no-op - the callback is initialized in the constructor
+    }
+
+    private Config loadConfig() {
+        int maxPermits = mContext.getResources().getInteger(
+                R.integer.driverAwarenessTouchModelMaxPermits);
+        if (maxPermits <= 0) {
+            throw new IllegalArgumentException("driverAwarenessTouchModelMaxPermits must be >0");
+        }
+        int refreshIntervalMillis = mContext.getResources().getInteger(
+                R.integer.driverAwarenessTouchModelPermitRefreshIntervalMs);
+        if (refreshIntervalMillis <= 0) {
+            throw new IllegalArgumentException(
+                    "driverAwarenessTouchModelPermitRefreshIntervalMs must be >0");
+        }
+        int throttleDurationMillis = mContext.getResources().getInteger(
+                R.integer.driverAwarenessTouchModelThrottleMs);
+        if (throttleDurationMillis <= 0) {
+            throw new IllegalArgumentException("driverAwarenessTouchModelThrottleMs must be >0");
+        }
+        return new Config(maxPermits, refreshIntervalMillis, throttleDurationMillis);
+    }
+
+    /**
+     * Starts monitoring touches.
+     */
+    @VisibleForTesting
+    // TODO(b/146802952) handle touch monitoring on multiple displays
+    void startTouchMonitoring() {
+        InputManager inputManager = (InputManager) mContext.getSystemService(Context.INPUT_SERVICE);
+        mInputMonitor = inputManager.monitorGestureInput(
+                TOUCH_INPUT_CHANNEL_NAME,
+                Display.DEFAULT_DISPLAY);
+        mInputEventReceiver = new TouchReceiver(
+                mInputMonitor.getInputChannel(),
+                mLooper);
+    }
+
+    /**
+     * Refreshes permits on the interval specified by {@code R.integer
+     * .driverAwarenessTouchModelPermitRefreshIntervalMs}.
+     */
+    @GuardedBy("mLock")
+    private void schedulePermitRefreshLocked() {
+        logd("Scheduling permit refresh interval (ms): "
+                + mConfig.getPermitRefreshIntervalMillis());
+        mRefreshScheduleHandle = mRefreshScheduler.scheduleAtFixedRate(
+                mRefreshPermitRunnable,
+                mConfig.getPermitRefreshIntervalMillis(),
+                mConfig.getPermitRefreshIntervalMillis(),
+                TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Stops the scheduler for refreshing the number of permits.
+     */
+    @GuardedBy("mLock")
+    private void stopPermitRefreshLocked() {
+        logd("Stopping permit refresh");
+        if (mRefreshScheduleHandle != null) {
+            mRefreshScheduleHandle.cancel(true);
+            mRefreshScheduleHandle = null;
+        }
+    }
+
+    /**
+     * Consume a single permit if the event should not be throttled.
+     */
+    @VisibleForTesting
+    @GuardedBy("mLock")
+    void consumePermitLocked(long timestamp) {
+        long timeSinceLastEvent = timestamp - mLastEventMillis;
+        boolean isEventAccepted = timeSinceLastEvent >= mConfig.getThrottleDurationMillis();
+        if (!isEventAccepted) {
+            logd("Ignoring consumePermit request: event throttled");
+            return;
+        }
+        mLastEventMillis = timestamp;
+        int curPermits = mCurrentPermits.updateAndGet(cur -> Math.max(0, cur - 1));
+        logd("Permit consumed to: " + curPermits);
+
+        if (mRefreshScheduleHandle == null) {
+            schedulePermitRefreshLocked();
+        }
+
+        try {
+            mDriverAwarenessSupplierCallback.onDriverAwarenessUpdated(
+                    new DriverAwarenessEvent(timestamp,
+                            (float) curPermits / mConfig.getMaxPermits()));
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to emit awareness event", e);
+        }
+    }
+
+    @VisibleForTesting
+    @GuardedBy("mLock")
+    void handlePermitRefreshLocked(long timestamp) {
+        int curPermits = mCurrentPermits.updateAndGet(
+                cur -> Math.min(cur + 1, mConfig.getMaxPermits()));
+        logd("Permit refreshed to: " + curPermits);
+        if (curPermits == mConfig.getMaxPermits()) {
+            stopPermitRefreshLocked();
+        }
+        try {
+            mDriverAwarenessSupplierCallback.onDriverAwarenessUpdated(
+                    new DriverAwarenessEvent(timestamp,
+                            (float) curPermits / mConfig.getMaxPermits()));
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to emit awareness event", e);
+        }
+    }
+
+    private static void logd(String message) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, message);
+        }
+    }
+
+    /**
+     * Receiver of all touch events. This receiver filters out all events except {@link
+     * MotionEvent#ACTION_UP} events.
+     */
+    private class TouchReceiver extends InputEventReceiver {
+
+        /**
+         * Creates an input event receiver bound to the specified input channel.
+         *
+         * @param inputChannel The input channel.
+         * @param looper       The looper to use when invoking callbacks.
+         */
+        TouchReceiver(InputChannel inputChannel, Looper looper) {
+            super(inputChannel, looper);
+        }
+
+        @Override
+        public void onInputEvent(InputEvent event) {
+            if (!(event instanceof MotionEvent)) {
+                return;
+            }
+
+            MotionEvent motionEvent = (MotionEvent) event;
+            if (motionEvent.getActionMasked() == MotionEvent.ACTION_UP) {
+                logd("ACTION_UP touch received");
+                synchronized (mLock) {
+                    consumePermitLocked(SystemClock.elapsedRealtime());
+                }
+            }
+        }
+    }
+
+    /**
+     * Configuration for a {@link TouchDriverAwarenessSupplier}.
+     */
+    private static class Config {
+
+        private final int mMaxPermits;
+        private final int mPermitRefreshIntervalMillis;
+        private final int mThrottleDurationMillis;
+
+        /**
+         * Creates an instance of {@link Config}.
+         *
+         * @param maxPermits                  the maximum number of permits in the user's
+         *                                    attention buffer. A user's number of permits will
+         *                                    never refresh to a value higher than this.
+         * @param permitRefreshIntervalMillis the refresh interval in milliseconds for refreshing
+         *                                    permits
+         * @param throttleDurationMillis      the duration in milliseconds representing the window
+         *                                    that permit consumption is ignored after an event.
+         */
+        private Config(
+                int maxPermits,
+                int permitRefreshIntervalMillis,
+                int throttleDurationMillis) {
+            mMaxPermits = maxPermits;
+            mPermitRefreshIntervalMillis = permitRefreshIntervalMillis;
+            mThrottleDurationMillis = throttleDurationMillis;
+        }
+
+        int getMaxPermits() {
+            return mMaxPermits;
+        }
+
+        int getPermitRefreshIntervalMillis() {
+            return mPermitRefreshIntervalMillis;
+        }
+
+        int getThrottleDurationMillis() {
+            return mThrottleDurationMillis;
+        }
+
+        @Override
+        public String toString() {
+            return String.format(
+                    "Config{mMaxPermits=%s, mPermitRefreshIntervalMillis=%s, "
+                            + "mThrottleDurationMillis=%s}",
+                    mMaxPermits,
+                    mPermitRefreshIntervalMillis,
+                    mThrottleDurationMillis);
+        }
+    }
+}
diff --git a/experimental/tests/Android.bp b/experimental/tests/Android.bp
new file mode 100644
index 0000000..7996a89
--- /dev/null
+++ b/experimental/tests/Android.bp
@@ -0,0 +1,17 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+
+// Include the sub-makefiles
\ No newline at end of file
diff --git a/experimental/tests/experimentalcarservice_unit_test/Android.bp b/experimental/tests/experimentalcarservice_unit_test/Android.bp
new file mode 100644
index 0000000..891a151
--- /dev/null
+++ b/experimental/tests/experimentalcarservice_unit_test/Android.bp
@@ -0,0 +1,48 @@
+// 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.
+
+// Unit tests for the experimental car service
+android_test {
+
+    name: "ExperimentalCarServiceTests",
+
+    srcs: ["src/**/*.java"],
+
+    platform_apis: true,
+    certificate: "platform",
+
+    libs: [
+        "android.car",
+        "android.test.runner",
+        "android.test.base",
+        "android.test.mock",
+    ],
+
+    static_libs: [
+        "androidx.test.core",
+        "androidx.test.ext.junit",
+        "androidx.test.rules",
+        "car-frameworks-service",
+        "mockito-target-extended",
+        "truth-prebuilt",
+        "experimentalcar-service-test-static-lib"
+    ],
+
+    jni_libs: [
+        "libdexmakerjvmtiagent",
+        "libstaticjvmtiagent",
+    ],
+
+    instrumentation_for: "ExperimentalCarService",
+}
diff --git a/experimental/tests/experimentalcarservice_unit_test/AndroidManifest.xml b/experimental/tests/experimentalcarservice_unit_test/AndroidManifest.xml
new file mode 100644
index 0000000..e2cff85
--- /dev/null
+++ b/experimental/tests/experimentalcarservice_unit_test/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          android:sharedUserId="com.google.android.car.uid.kitchensink"
+          package="com.android.experimentalcar.experimentalcarservice_unittest">
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.experimentalcar.experimentalcarservice_unittest"
+                     android:label="Unit Tests for Experimental Car APIs"/>
+
+    <application android:label="ExperimentalCarServiceUnitTest"
+                 tools:replace="android:label"
+                 android:debuggable="true">
+        <uses-library android:name="android.test.runner"/>
+    </application>
+</manifest>
diff --git a/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/DriverDistractionExperimentalFeatureServiceTest.java b/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/DriverDistractionExperimentalFeatureServiceTest.java
new file mode 100644
index 0000000..6d4707d
--- /dev/null
+++ b/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/DriverDistractionExperimentalFeatureServiceTest.java
@@ -0,0 +1,778 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.experimentalcar;
+
+import static com.android.experimentalcar.DriverDistractionExperimentalFeatureService.DEFAULT_AWARENESS_PERCENTAGE;
+import static com.android.experimentalcar.DriverDistractionExperimentalFeatureService.DISPATCH_THROTTLE_MS;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.car.Car;
+import android.car.VehiclePropertyIds;
+import android.car.experimental.CarDriverDistractionManager;
+import android.car.experimental.DriverAwarenessEvent;
+import android.car.experimental.DriverAwarenessSupplierConfig;
+import android.car.experimental.DriverAwarenessSupplierService;
+import android.car.experimental.DriverDistractionChangeEvent;
+import android.car.experimental.IDriverAwarenessSupplier;
+import android.car.experimental.IDriverAwarenessSupplierCallback;
+import android.car.hardware.CarPropertyValue;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.hardware.input.InputManager;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Pair;
+import android.view.InputChannel;
+import android.view.InputMonitor;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.rule.ServiceTestRule;
+
+import com.android.internal.annotations.GuardedBy;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DriverDistractionExperimentalFeatureServiceTest {
+
+    private static final String TAG = "Car.DriverDistractionServiceTest";
+
+    private static final String SERVICE_BIND_GAZE_SUPPLIER =
+            "com.android.experimentalcar/.GazeDriverAwarenessSupplier";
+
+    private static final long INITIAL_TIME = 1000L;
+    private static final long PREFERRED_SUPPLIER_STALENESS = 10L;
+
+    private final IDriverAwarenessSupplier mFallbackSupplier =
+            new IDriverAwarenessSupplier.Stub() {
+                @Override
+                public void onReady() throws RemoteException {
+                }
+
+                @Override
+                public void setCallback(IDriverAwarenessSupplierCallback callback)
+                        throws RemoteException {
+                }
+            };
+    private final DriverAwarenessSupplierConfig mFallbackConfig = new DriverAwarenessSupplierConfig(
+            DriverAwarenessSupplierService.NO_STALENESS);
+
+    private final IDriverAwarenessSupplier mPreferredSupplier =
+            new IDriverAwarenessSupplier.Stub() {
+                @Override
+                public void onReady() throws RemoteException {
+                }
+
+                @Override
+                public void setCallback(IDriverAwarenessSupplierCallback callback)
+                        throws RemoteException {
+                }
+            };
+    private final DriverAwarenessSupplierConfig mPreferredSupplierConfig =
+            new DriverAwarenessSupplierConfig(PREFERRED_SUPPLIER_STALENESS);
+
+    // stores the last change event from OnDriverDistractionChange call
+    private DriverDistractionChangeEvent mLastDistractionEvent;
+    private List<DriverDistractionChangeEvent> mDistractionEventHistory = new ArrayList<>();
+    private final Semaphore mChangeEventSignal = new Semaphore(0);
+
+    private final CarDriverDistractionManager.OnDriverDistractionChangeListener mChangeListener =
+            new CarDriverDistractionManager.OnDriverDistractionChangeListener() {
+                @Override
+                public void onDriverDistractionChange(DriverDistractionChangeEvent event) {
+                    // should be dispatched to main thread.
+                    assertThat(Looper.getMainLooper()).isEqualTo(Looper.myLooper());
+                    mLastDistractionEvent = event;
+                    mDistractionEventHistory.add(event);
+                    mChangeEventSignal.release();
+                }
+            };
+
+    @Mock
+    private InputManager mInputManager;
+
+    @Mock
+    private InputMonitor mInputMonitor;
+
+    @Mock
+    private IBinder mIBinder;
+
+    @Mock
+    private Handler mHandler;
+
+    @Rule
+    public final ServiceTestRule serviceRule = new ServiceTestRule();
+
+    private final Context mSpyContext = spy(
+            InstrumentationRegistry.getInstrumentation().getContext());
+
+    private DriverDistractionExperimentalFeatureService mService;
+    private CarDriverDistractionManager mManager;
+    private FakeTimeSource mTimeSource;
+    private FakeTimer mExpiredAwarenessTimer;
+    private List<Runnable> mQueuedRunnables;
+
+    @Before
+    public void setUp() throws Exception {
+        mTimeSource = new FakeTimeSource(INITIAL_TIME);
+        mExpiredAwarenessTimer = new FakeTimer();
+        // execute all handler posts immediately
+        when(mHandler.post(any())).thenAnswer(i -> {
+            ((Runnable) i.getArguments()[0]).run();
+            return true;
+        });
+        // keep track of runnables with delayed posts
+        mQueuedRunnables = new ArrayList<>();
+        when(mHandler.postDelayed(any(), anyLong())).thenAnswer(i -> {
+            mQueuedRunnables.add(((Runnable) i.getArguments()[0]));
+            return true;
+        });
+        mDistractionEventHistory = new ArrayList<>();
+        doReturn(PackageManager.PERMISSION_GRANTED)
+                .when(mSpyContext).checkCallingOrSelfPermission(any());
+        mService = new DriverDistractionExperimentalFeatureService(mSpyContext, mTimeSource,
+                mExpiredAwarenessTimer, Looper.myLooper(), mHandler);
+        // Car must not be created with a mock context (otherwise CarService may crash)
+        mManager = new CarDriverDistractionManager(Car.createCar(mSpyContext), mService);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (mService != null) {
+            mService.release();
+        }
+        resetChangeEventWait();
+    }
+
+    @Test
+    public void testConfig_servicesCanBeBound() throws Exception {
+        Context realContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+        // Get the actual suppliers defined in the config
+        String[] preferredDriverAwarenessSuppliers = realContext.getResources().getStringArray(
+                R.array.preferredDriverAwarenessSuppliers);
+
+        for (String supplierStringName : preferredDriverAwarenessSuppliers) {
+            ComponentName supplierComponent = ComponentName.unflattenFromString(supplierStringName);
+            Class<?> supplerClass = Class.forName(supplierComponent.getClassName());
+            Intent serviceIntent =
+                    new Intent(ApplicationProvider.getApplicationContext(), supplerClass);
+
+            // Bind the service and grab a reference to the binder.
+            IBinder binder = serviceRule.bindService(serviceIntent);
+
+            assertThat(binder instanceof DriverAwarenessSupplierService.SupplierBinder).isTrue();
+        }
+    }
+
+    @Test
+    public void testInit_bindsToServicesInXmlConfig() throws Exception {
+        Context spyContext = spy(InstrumentationRegistry.getInstrumentation().getTargetContext());
+
+        // Mock the config to load a gaze supplier
+        Resources spyResources = spy(spyContext.getResources());
+        doReturn(spyResources).when(spyContext).getResources();
+        doReturn(new String[]{SERVICE_BIND_GAZE_SUPPLIER}).when(spyResources).getStringArray(
+                anyInt());
+
+        // Mock the InputManager that will be used by TouchDriverAwarenessSupplier
+        doReturn(mInputManager).when(spyContext).getSystemService(Context.INPUT_SERVICE);
+        when(mInputManager.monitorGestureInput(any(), anyInt())).thenReturn(mInputMonitor);
+        // InputChannel cannot be mocked because it passes to InputEventReceiver.
+        final InputChannel[] inputChannels = InputChannel.openInputChannelPair(TAG);
+        inputChannels[0].dispose();
+        when(mInputMonitor.getInputChannel()).thenReturn(inputChannels[1]);
+
+        // Create a special context that allows binders to succeed and keeps track of them. Doesn't
+        // actually start the intents / services.
+        ServiceLauncherContext serviceLauncherContext = new ServiceLauncherContext(spyContext);
+        mService = new DriverDistractionExperimentalFeatureService(serviceLauncherContext,
+                mTimeSource, mExpiredAwarenessTimer,
+                spyContext.getMainLooper(), mHandler);
+        mService.init();
+
+        serviceLauncherContext.assertBoundService(SERVICE_BIND_GAZE_SUPPLIER);
+
+        serviceLauncherContext.reset();
+        inputChannels[0].dispose();
+    }
+
+    @Test
+    public void testHandleDriverAwarenessEvent_updatesCurrentValue_withLatestEvent()
+            throws Exception {
+        mService.setDriverAwarenessSuppliers(Arrays.asList(
+                new Pair<>(mFallbackSupplier, mFallbackConfig)));
+
+        float firstAwarenessValue = 0.7f;
+        emitDriverAwarenessEvent(mFallbackSupplier, INITIAL_TIME + 1, firstAwarenessValue);
+
+        assertThat(getCurrentAwarenessValue()).isEqualTo(firstAwarenessValue);
+    }
+
+    @Test
+    public void testHandleDriverAwarenessEvent_hasPreferredEvent_ignoresFallbackEvent()
+            throws Exception {
+        mService.setDriverAwarenessSuppliers(Arrays.asList(
+                new Pair<>(mFallbackSupplier, mFallbackConfig),
+                new Pair<>(mPreferredSupplier, mPreferredSupplierConfig)));
+
+        // emit an event from the preferred supplier before the fallback supplier
+        float preferredValue = 0.6f;
+        emitDriverAwarenessEvent(mPreferredSupplier, INITIAL_TIME + 1, preferredValue);
+        float fallbackValue = 0.7f;
+        emitDriverAwarenessEvent(mFallbackSupplier, INITIAL_TIME + 2, fallbackValue);
+
+        // even though the fallback supplier has a more recent timestamp, it is not the current
+        // since the event from the preferred supplier is still fresh
+        assertThat(getCurrentAwarenessValue()).isEqualTo(preferredValue);
+    }
+
+    @Test
+    public void testHandleDriverAwarenessEvent_ignoresOldEvents() throws Exception {
+        mService.setDriverAwarenessSuppliers(Arrays.asList(
+                new Pair<>(mFallbackSupplier, mFallbackConfig)));
+
+        float firstAwarenessValue = 0.7f;
+        emitDriverAwarenessEvent(mFallbackSupplier, INITIAL_TIME + 1, firstAwarenessValue);
+        long oldTime = INITIAL_TIME - 100;
+        emitDriverAwarenessEvent(mFallbackSupplier, oldTime, 0.6f);
+
+        // the event with the old timestamp shouldn't overwrite the value with a more recent
+        // timestamp
+        assertThat(getCurrentAwarenessValue()).isEqualTo(firstAwarenessValue);
+    }
+
+    @Test
+    public void testPreferredAwarenessEvent_becomesStale_fallsBackToFallbackEvent()
+            throws Exception {
+        setVehicleMoving();
+        mService.setDriverAwarenessSuppliers(Arrays.asList(
+                new Pair<>(mFallbackSupplier, mFallbackConfig),
+                new Pair<>(mPreferredSupplier, mPreferredSupplierConfig)));
+
+        // emit an event from the preferred supplier before the fallback supplier
+        float preferredSupplierAwarenessValue = 0.6f;
+        long preferredSupplierEventTime = INITIAL_TIME + 1;
+        mTimeSource.setTimeMillis(preferredSupplierEventTime);
+        emitDriverAwarenessEvent(mPreferredSupplier, preferredSupplierEventTime,
+                preferredSupplierAwarenessValue);
+        float fallbackSuppplierAwarenessValue = 0.7f;
+        long fallbackSupplierEventTime = INITIAL_TIME + 2;
+        mTimeSource.setTimeMillis(fallbackSupplierEventTime);
+        emitDriverAwarenessEvent(mFallbackSupplier, fallbackSupplierEventTime,
+                fallbackSuppplierAwarenessValue);
+
+        // the preferred supplier still has a fresh event
+        assertThat(getCurrentAwarenessValue()).isEqualTo(preferredSupplierAwarenessValue);
+
+        // go into the future
+        mTimeSource.setTimeMillis(
+                preferredSupplierEventTime + PREFERRED_SUPPLIER_STALENESS + 1);
+        mExpiredAwarenessTimer.executePendingTask();
+
+        // the preferred supplier's data has become stale
+        assertThat(getCurrentAwarenessValue()).isEqualTo(fallbackSuppplierAwarenessValue);
+        assertThat(mService.getLastDistractionEvent()).isEqualTo(
+                new DriverDistractionChangeEvent.Builder()
+                        // time is when the event expired
+                        .setElapsedRealtimeTimestamp(mTimeSource.elapsedRealtime())
+                        .setAwarenessPercentage(fallbackSuppplierAwarenessValue)
+                        .build());
+    }
+
+
+    @Test
+    public void testGetLastDistractionEvent_noEvents_returnsDefault() throws Exception {
+        assertThat(mService.getLastDistractionEvent()).isEqualTo(
+                new DriverDistractionChangeEvent.Builder()
+                        .setElapsedRealtimeTimestamp(INITIAL_TIME)
+                        .setAwarenessPercentage(DEFAULT_AWARENESS_PERCENTAGE)
+                        .build());
+    }
+
+    @Test
+    public void testGetLastDistractionEvent_afterEventEmit_returnsLastEvent() throws Exception {
+        setVehicleMoving();
+        mService.setDriverAwarenessSuppliers(Arrays.asList(
+                new Pair<>(mFallbackSupplier, mFallbackConfig)));
+
+        float firstAwarenessValue = 0.7f;
+        mTimeSource.setTimeMillis(INITIAL_TIME + 1);
+        emitDriverAwarenessEvent(mFallbackSupplier, mTimeSource.elapsedRealtime(),
+                firstAwarenessValue);
+
+        assertThat(mService.getLastDistractionEvent()).isEqualTo(
+                new DriverDistractionChangeEvent.Builder()
+                        .setElapsedRealtimeTimestamp(INITIAL_TIME + 1)
+                        .setAwarenessPercentage(0.7f)
+                        .build());
+    }
+
+    @Test
+    public void testManagerRegister_returnsInitialEvent() throws Exception {
+        long eventWaitTimeMs = 300;
+
+        mService.setDriverAwarenessSuppliers(Arrays.asList(
+                new Pair<>(mFallbackSupplier, mFallbackConfig)));
+        resetChangeEventWait();
+        mManager.addDriverDistractionChangeListener(mChangeListener);
+
+        assertThat(waitForCallbackEvent(eventWaitTimeMs)).isTrue();
+        assertThat(mLastDistractionEvent).isEqualTo(
+                new DriverDistractionChangeEvent.Builder()
+                        .setElapsedRealtimeTimestamp(mTimeSource.elapsedRealtime())
+                        .setAwarenessPercentage(DEFAULT_AWARENESS_PERCENTAGE)
+                        .build());
+    }
+
+    @Test
+    public void testManagerRegister_distractionValueUnchanged_doesNotEmitEvent() throws Exception {
+        setVehicleMoving();
+        long eventWaitTimeMs = 300;
+
+        mService.setDriverAwarenessSuppliers(Arrays.asList(
+                new Pair<>(mFallbackSupplier, mFallbackConfig)));
+        resetChangeEventWait();
+        mManager.addDriverDistractionChangeListener(mChangeListener);
+
+        assertThat(waitForCallbackEvent(eventWaitTimeMs)).isTrue();
+        assertThat(mLastDistractionEvent).isEqualTo(
+                new DriverDistractionChangeEvent.Builder()
+                        .setElapsedRealtimeTimestamp(mTimeSource.elapsedRealtime())
+                        .setAwarenessPercentage(DEFAULT_AWARENESS_PERCENTAGE)
+                        .build());
+
+        float firstAwarenessValue = 1.0f;
+        mTimeSource.setTimeMillis(INITIAL_TIME + 1);
+        resetChangeEventWait();
+        emitDriverAwarenessEvent(mFallbackSupplier, mTimeSource.elapsedRealtime(),
+                firstAwarenessValue);
+
+        assertThat(waitForCallbackEvent(eventWaitTimeMs)).isFalse();
+    }
+
+    @Test
+    public void testManagerRegister_eventInThrottleWindow_isQueued()
+            throws Exception {
+        setVehicleMoving();
+        long eventWaitTimeMs = 300;
+
+        mService.setDriverAwarenessSuppliers(Collections.singletonList(
+                new Pair<>(mFallbackSupplier, mFallbackConfig)));
+        resetChangeEventWait();
+        mManager.addDriverDistractionChangeListener(mChangeListener);
+        // 0th event: event from registering
+        assertThat(waitForCallbackEvent(eventWaitTimeMs)).isTrue();
+
+        // 1st event: driver awareness changes, and first event is emitted
+        resetChangeEventWait();
+        float firstAwarenessValue = 0.9f;
+        long firstEventTime = INITIAL_TIME + 1;
+        mTimeSource.setTimeMillis(firstEventTime);
+        emitDriverAwarenessEvent(mFallbackSupplier, mTimeSource.elapsedRealtime(),
+                firstAwarenessValue);
+        assertThat(waitForCallbackEvent(eventWaitTimeMs)).isTrue();
+
+        // 2nd event: driver awareness changes within throttle window, so dispatch is scheduled
+        resetChangeEventWait();
+        float secondAwarenessValue = 0.8f;
+        long secondEventTime = INITIAL_TIME + 2;
+        mTimeSource.setTimeMillis(secondEventTime);
+        emitDriverAwarenessEvent(mFallbackSupplier, mTimeSource.elapsedRealtime(),
+                secondAwarenessValue);
+
+        // delayed runnable should be posted to handler in 1 second less than the throttle delay
+        // (since there was 1 second between the two events). No event should have been emitted.
+        verify(mHandler).postDelayed(any(), eq(DISPATCH_THROTTLE_MS - 1));
+        assertThat(waitForCallbackEvent(eventWaitTimeMs)).isFalse();
+
+        // event is emitted once the pending task is run
+        mQueuedRunnables.get(0).run();
+        assertThat(waitForCallbackEvent(eventWaitTimeMs)).isTrue();
+        assertThat(mLastDistractionEvent).isEqualTo(
+                new DriverDistractionChangeEvent.Builder()
+                        .setElapsedRealtimeTimestamp(secondEventTime)
+                        .setAwarenessPercentage(secondAwarenessValue)
+                        .build());
+    }
+
+    @Test
+    public void testManagerRegister_multipleEventsInThrottleWindow_dropsExtraEvents()
+            throws Exception {
+        setVehicleMoving();
+        long eventWaitTimeMs = 300;
+
+        mService.setDriverAwarenessSuppliers(Collections.singletonList(
+                new Pair<>(mFallbackSupplier, mFallbackConfig)));
+        resetChangeEventWait();
+        mManager.addDriverDistractionChangeListener(mChangeListener);
+        // 0th event: event from registering
+        assertThat(waitForCallbackEvent(eventWaitTimeMs)).isTrue();
+
+        // 1st event: driver awareness changes, and first event is emitted
+        resetChangeEventWait();
+        float firstAwarenessValue = 0.9f;
+        long firstEventTime = INITIAL_TIME + 1;
+        mTimeSource.setTimeMillis(firstEventTime);
+        emitDriverAwarenessEvent(mFallbackSupplier, mTimeSource.elapsedRealtime(),
+                firstAwarenessValue);
+        assertThat(waitForCallbackEvent(eventWaitTimeMs)).isTrue();
+
+        // 2nd event: driver awareness changes within throttle window, so dispatch is scheduled
+        resetChangeEventWait();
+        float secondAwarenessValue = 0.8f;
+        long secondEventTime = INITIAL_TIME + 2;
+        mTimeSource.setTimeMillis(secondEventTime);
+        emitDriverAwarenessEvent(mFallbackSupplier, mTimeSource.elapsedRealtime(),
+                secondAwarenessValue);
+        // runnable will be posted in 1 second less than the throttle delay
+        verify(mHandler).postDelayed(any(), eq(DISPATCH_THROTTLE_MS - 1));
+
+        // 3rd event: driver awareness changes within throttle window again, no new schedule
+        float thirdAwarenessValue = 0.7f;
+        long thirdEventTime = INITIAL_TIME + 3;
+        mTimeSource.setTimeMillis(thirdEventTime);
+        emitDriverAwarenessEvent(mFallbackSupplier, mTimeSource.elapsedRealtime(),
+                thirdAwarenessValue);
+        // verify that this was still only called once
+        verify(mHandler).postDelayed(any(), eq(DISPATCH_THROTTLE_MS - 1));
+
+        // neither 2nd or 3rd events should trigger a callback
+        assertThat(waitForCallbackEvent(eventWaitTimeMs)).isFalse();
+    }
+
+    @Test
+    public void testManagerRegister_multipleEventsOutsideThrottleWindow_emitsAllEvents()
+            throws Exception {
+        setVehicleMoving();
+        long eventWaitTimeMs = 300;
+
+        mService.setDriverAwarenessSuppliers(Collections.singletonList(
+                new Pair<>(mFallbackSupplier, mFallbackConfig)));
+        resetChangeEventWait();
+        mManager.addDriverDistractionChangeListener(mChangeListener);
+        // 0th event: event from registering
+        assertThat(waitForCallbackEvent(eventWaitTimeMs)).isTrue();
+
+        // 1st event: driver awareness changes, and first event is emitted
+        resetChangeEventWait();
+        float firstAwarenessValue = 0.9f;
+        long firstEventTime = INITIAL_TIME + DISPATCH_THROTTLE_MS;
+        mTimeSource.setTimeMillis(firstEventTime);
+        emitDriverAwarenessEvent(mFallbackSupplier, mTimeSource.elapsedRealtime(),
+                firstAwarenessValue);
+        assertThat(waitForCallbackEvent(eventWaitTimeMs)).isTrue();
+
+        // 2nd event: outside throttle window, so dispatched
+        resetChangeEventWait();
+        float secondAwarenessValue = 0.8f;
+        long secondEventTime = INITIAL_TIME + DISPATCH_THROTTLE_MS * 2;
+        mTimeSource.setTimeMillis(secondEventTime);
+        emitDriverAwarenessEvent(mFallbackSupplier, mTimeSource.elapsedRealtime(),
+                secondAwarenessValue);
+        assertThat(waitForCallbackEvent(eventWaitTimeMs)).isTrue();
+
+        // 3rd event: outside throttle window, so dispatched
+        resetChangeEventWait();
+        float thirdAwarenessValue = 0.7f;
+        long thirdEventTime = INITIAL_TIME + DISPATCH_THROTTLE_MS * 3;
+        mTimeSource.setTimeMillis(thirdEventTime);
+        emitDriverAwarenessEvent(mFallbackSupplier, mTimeSource.elapsedRealtime(),
+                thirdAwarenessValue);
+        assertThat(waitForCallbackEvent(eventWaitTimeMs)).isTrue();
+
+        // all events should be in history
+        assertThat(mDistractionEventHistory).containsExactly(
+                new DriverDistractionChangeEvent.Builder()
+                        .setElapsedRealtimeTimestamp(INITIAL_TIME)
+                        .setAwarenessPercentage(DEFAULT_AWARENESS_PERCENTAGE)
+                        .build(),
+                new DriverDistractionChangeEvent.Builder()
+                        .setElapsedRealtimeTimestamp(firstEventTime)
+                        .setAwarenessPercentage(firstAwarenessValue)
+                        .build(),
+                new DriverDistractionChangeEvent.Builder()
+                        .setElapsedRealtimeTimestamp(secondEventTime)
+                        .setAwarenessPercentage(secondAwarenessValue)
+                        .build(),
+                new DriverDistractionChangeEvent.Builder()
+                        .setElapsedRealtimeTimestamp(thirdEventTime)
+                        .setAwarenessPercentage(thirdAwarenessValue)
+                        .build());
+    }
+
+    @Test
+    public void testManagerRegister_receivesChangeEvents() throws Exception {
+        setVehicleMoving();
+        long eventWaitTimeMs = 300;
+
+        mService.setDriverAwarenessSuppliers(Arrays.asList(
+                new Pair<>(mFallbackSupplier, mFallbackConfig)));
+        resetChangeEventWait();
+        mManager.addDriverDistractionChangeListener(mChangeListener);
+
+        assertThat(waitForCallbackEvent(eventWaitTimeMs)).isTrue();
+        assertThat(mLastDistractionEvent).isEqualTo(
+                new DriverDistractionChangeEvent.Builder()
+                        .setElapsedRealtimeTimestamp(mTimeSource.elapsedRealtime())
+                        .setAwarenessPercentage(DEFAULT_AWARENESS_PERCENTAGE)
+                        .build());
+
+        float firstAwarenessValue = 0.7f;
+        mTimeSource.setTimeMillis(INITIAL_TIME + 1);
+        resetChangeEventWait();
+        emitDriverAwarenessEvent(mFallbackSupplier, mTimeSource.elapsedRealtime(),
+                firstAwarenessValue);
+
+        assertThat(waitForCallbackEvent(eventWaitTimeMs)).isTrue();
+        assertThat(mLastDistractionEvent).isEqualTo(
+                new DriverDistractionChangeEvent.Builder()
+                        .setElapsedRealtimeTimestamp(mTimeSource.elapsedRealtime())
+                        .setAwarenessPercentage(firstAwarenessValue)
+                        .build());
+    }
+
+    @Test
+    public void testManagerRegisterUnregister_stopsReceivingEvents() throws Exception {
+        long eventWaitTimeMs = 300;
+
+        mService.setDriverAwarenessSuppliers(Arrays.asList(
+                new Pair<>(mFallbackSupplier, mFallbackConfig)));
+        resetChangeEventWait();
+        mManager.addDriverDistractionChangeListener(mChangeListener);
+        mManager.removeDriverDistractionChangeListener(mChangeListener);
+
+        float firstAwarenessValue = 0.8f;
+        mTimeSource.setTimeMillis(INITIAL_TIME + 1);
+        resetChangeEventWait();
+        emitDriverAwarenessEvent(mFallbackSupplier, mTimeSource.elapsedRealtime(),
+                firstAwarenessValue);
+
+        assertThat(waitForCallbackEvent(eventWaitTimeMs)).isFalse();
+    }
+
+    @Test
+    public void testManagerUnregister_beforeRegister_doesNothing() throws Exception {
+        mManager.removeDriverDistractionChangeListener(mChangeListener);
+    }
+
+    @Test
+    public void testDistractionEvent_noSpeedEventsReceived_awarenessPercentageRemainsFull()
+            throws Exception {
+        mService.setDriverAwarenessSuppliers(Arrays.asList(
+                new Pair<>(mFallbackSupplier, mFallbackConfig)));
+
+        float firstAwarenessValue = 0.7f;
+        mTimeSource.setTimeMillis(INITIAL_TIME + 1);
+        emitDriverAwarenessEvent(mFallbackSupplier, mTimeSource.elapsedRealtime(),
+                firstAwarenessValue);
+
+        // No new distraction event since required awareness is 0 until a speed change occurs
+        assertThat(mService.getLastDistractionEvent()).isEqualTo(
+                new DriverDistractionChangeEvent.Builder()
+                        .setElapsedRealtimeTimestamp(INITIAL_TIME)
+                        .setAwarenessPercentage(1.0f)
+                        .build());
+    }
+
+    @Test
+    public void testRequiredAwareness_multipleSpeedChanges_emitsSingleEvent()
+            throws Exception {
+        setVehicleStopped();
+        mService.setDriverAwarenessSuppliers(Arrays.asList(
+                new Pair<>(mFallbackSupplier, mFallbackConfig)));
+
+        float firstAwarenessValue = 0.7f;
+        mTimeSource.setTimeMillis(INITIAL_TIME + 1);
+        emitDriverAwarenessEvent(mFallbackSupplier, mTimeSource.elapsedRealtime(),
+                firstAwarenessValue);
+        mService.handleSpeedEventLocked(
+                new CarPropertyValue<>(VehiclePropertyIds.PERF_VEHICLE_SPEED, 0, 30.0f));
+
+        // Receive the first speed change event
+        assertThat(mService.getLastDistractionEvent()).isEqualTo(
+                new DriverDistractionChangeEvent.Builder()
+                        .setElapsedRealtimeTimestamp(INITIAL_TIME + 1)
+                        .setAwarenessPercentage(0.7f)
+                        .build());
+
+        mTimeSource.setTimeMillis(INITIAL_TIME + 2);
+        mService.handleSpeedEventLocked(
+                new CarPropertyValue<>(VehiclePropertyIds.PERF_VEHICLE_SPEED, 0, 20.0f));
+        mTimeSource.setTimeMillis(INITIAL_TIME + 3);
+        mService.handleSpeedEventLocked(
+                new CarPropertyValue<>(VehiclePropertyIds.PERF_VEHICLE_SPEED, 0, 40.0f));
+
+        // Speed changes when already in a moving state don't trigger a new distraction event
+        assertThat(mService.getLastDistractionEvent()).isEqualTo(
+                new DriverDistractionChangeEvent.Builder()
+                        .setElapsedRealtimeTimestamp(INITIAL_TIME + 1)
+                        .setAwarenessPercentage(0.7f)
+                        .build());
+    }
+
+    @Test
+    public void testDistractionEvent_vehicleBecomesStopped_emitsFullAwareness() throws Exception {
+        mService.setDriverAwarenessSuppliers(Arrays.asList(
+                new Pair<>(mFallbackSupplier, mFallbackConfig)));
+
+        setVehicleMoving();
+        float firstAwarenessValue = 0.7f;
+        mTimeSource.setTimeMillis(INITIAL_TIME + 1);
+        emitDriverAwarenessEvent(mFallbackSupplier, mTimeSource.elapsedRealtime(),
+                firstAwarenessValue);
+
+        mTimeSource.setTimeMillis(INITIAL_TIME + 2);
+        setVehicleStopped();
+
+        // Awareness percentage is 1.0 since the vehicle is stopped, even though driver awareness
+        // is 0.7
+        assertThat(mService.getLastDistractionEvent()).isEqualTo(
+                new DriverDistractionChangeEvent.Builder()
+                        .setElapsedRealtimeTimestamp(INITIAL_TIME + 2)
+                        .setAwarenessPercentage(1.0f)
+                        .build());
+    }
+
+    private void setVehicleMoving() {
+        mService.handleSpeedEventLocked(
+                new CarPropertyValue<>(VehiclePropertyIds.PERF_VEHICLE_SPEED, 0, 30.0f));
+    }
+
+    private void setVehicleStopped() {
+        mService.handleSpeedEventLocked(
+                new CarPropertyValue<>(VehiclePropertyIds.PERF_VEHICLE_SPEED, 0, 0.0f));
+    }
+
+    private void resetChangeEventWait() {
+        mLastDistractionEvent = null;
+        mChangeEventSignal.drainPermits();
+    }
+
+    private boolean waitForCallbackEvent(long timeoutMs) {
+        boolean acquired = false;
+        try {
+            acquired = mChangeEventSignal.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
+        } catch (Exception ignored) {
+
+        }
+        return acquired;
+    }
+
+    private float getCurrentAwarenessValue() {
+        return mService.getCurrentDriverAwareness().mAwarenessEvent.getAwarenessValue();
+    }
+
+    /**
+     * Handle an event as if it were emitted from the specified supplier with the specified time and
+     * value.
+     */
+    private void emitDriverAwarenessEvent(IDriverAwarenessSupplier supplier, long time, float value)
+            throws RemoteException {
+        long maxStaleness;
+        if (supplier == mFallbackSupplier) {
+            maxStaleness = DriverAwarenessSupplierService.NO_STALENESS;
+        } else {
+            maxStaleness = PREFERRED_SUPPLIER_STALENESS;
+        }
+        mService.handleDriverAwarenessEvent(
+                new DriverDistractionExperimentalFeatureService.DriverAwarenessEventWrapper(
+                        new DriverAwarenessEvent(time, value),
+                        supplier,
+                        maxStaleness));
+    }
+
+
+    /** Overrides framework behavior to succeed on binding/starting processes. */
+    public class ServiceLauncherContext extends ContextWrapper {
+        private final Object mLock = new Object();
+
+        @GuardedBy("mLock")
+        private List<Intent> mBoundIntents = new ArrayList<>();
+
+        ServiceLauncherContext(Context base) {
+            super(base);
+        }
+
+        @Override
+        public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
+                Handler handler, UserHandle user) {
+            synchronized (mLock) {
+                mBoundIntents.add(service);
+            }
+            conn.onServiceConnected(service.getComponent(), mIBinder);
+            return true;
+        }
+
+        @Override
+        public boolean bindServiceAsUser(Intent service, ServiceConnection conn,
+                int flags, UserHandle user) {
+            return bindServiceAsUser(service, conn, flags, null, user);
+        }
+
+        @Override
+        public void unbindService(ServiceConnection conn) {
+            // do nothing
+        }
+
+        void assertBoundService(String service) {
+            synchronized (mLock) {
+                assertThat(mBoundIntents.stream().map(Intent::getComponent).collect(
+                        Collectors.toList())).contains(ComponentName.unflattenFromString(service));
+            }
+        }
+
+        void reset() {
+            synchronized (mLock) {
+                mBoundIntents.clear();
+            }
+        }
+    }
+}
diff --git a/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/FakeTimeSource.java b/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/FakeTimeSource.java
new file mode 100644
index 0000000..34807c2
--- /dev/null
+++ b/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/FakeTimeSource.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.experimentalcar;
+
+/**
+ * Fake implementation of {@link ITimeSource}.
+ */
+public class FakeTimeSource implements ITimeSource {
+
+    private long mTimeMillis;
+
+    /**
+     * Create an instance of {@link FakeTimeSource} with an initial time.
+     */
+    FakeTimeSource(long timeMillis) {
+        mTimeMillis = timeMillis;
+    }
+
+    /**
+     * Set the value that will be returned for time getters.
+     */
+    void setTimeMillis(long elapsedRealtime) {
+        mTimeMillis = elapsedRealtime;
+    }
+
+    @Override
+    public long elapsedRealtime() {
+        return mTimeMillis;
+    }
+
+    @Override
+    public long uptimeMillis() {
+        return mTimeMillis;
+    }
+}
diff --git a/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/FakeTimer.java b/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/FakeTimer.java
new file mode 100644
index 0000000..1884fe9
--- /dev/null
+++ b/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/FakeTimer.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.experimentalcar;
+
+import java.util.TimerTask;
+
+/**
+ * Fake implementation for {@link ITimer}.
+ */
+public class FakeTimer implements ITimer {
+
+    private TimerTask mPendingTask;
+
+    @Override
+    public void reset() {
+        mPendingTask = null;
+    }
+
+    @Override
+    public void schedule(TimerTask task, long delay) {
+        mPendingTask = task;
+    }
+
+    @Override
+    public void cancel() {
+        // no-op
+    }
+
+    TimerTask getPendingTask() {
+        return mPendingTask;
+    }
+
+    /**
+     * Immediately execute the scheduled task.
+     */
+    void executePendingTask() {
+        mPendingTask.run();
+    }
+}
diff --git a/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/GazeAttentionProcessorTest.java b/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/GazeAttentionProcessorTest.java
new file mode 100644
index 0000000..82d60bb
--- /dev/null
+++ b/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/GazeAttentionProcessorTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.experimentalcar;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertTrue;
+
+import android.car.occupantawareness.GazeDetection;
+import android.car.occupantawareness.OccupantAwarenessDetection;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class GazeAttentionProcessorTest {
+
+    private static final long FRAME_TIME_MILLIS = 1000; // Milliseconds
+    private static final float INITIAL_VALUE = 1.0f;
+    private static final float GROWTH_RATE = 0.4f;
+    private static final float DECAY_RATE = 0.6f;
+
+    private GazeAttentionProcessor mAttentionProcessor;
+
+    @Before
+    public void setUp() {
+        mAttentionProcessor =
+                new GazeAttentionProcessor(
+                        new GazeAttentionProcessor.Configuration(
+                                INITIAL_VALUE, DECAY_RATE, GROWTH_RATE));
+    }
+
+    @Test
+    public void test_initialValue() {
+        // Initial attention value should match input configuration.
+        assertThat(mAttentionProcessor.getAttention()).isEqualTo(INITIAL_VALUE);
+    }
+
+    @Test
+    public void testUpdateAttention_neverExceedsOne() {
+        // Maximum awareness should never exceed '1'.
+        long timestamp = 1234;
+        final GazeDetection onRoadDetection =
+                buildGazeDetection(GazeDetection.VEHICLE_REGION_FORWARD_ROADWAY);
+
+        // First pass should return initial value.
+        assertThat(mAttentionProcessor.updateAttention(onRoadDetection, timestamp))
+                .isEqualTo(INITIAL_VALUE);
+        timestamp += FRAME_TIME_MILLIS;
+
+        for (int i = 0; i < 100; i++) {
+            // Running on-road again with maxed out attention should max out at '1'.
+            assertTrue(mAttentionProcessor.updateAttention(onRoadDetection, timestamp) <= 1.0f);
+            timestamp += FRAME_TIME_MILLIS;
+        }
+    }
+
+    @Test
+    public void testUpdateAttention_neverBelowZero() {
+        // Minimum awareness should never fall below '0'.
+        long timestamp = 1234;
+        final GazeDetection offRoadDetection =
+                buildGazeDetection(GazeDetection.VEHICLE_REGION_HEAD_UNIT_DISPLAY);
+
+        // First pass should return initial value.
+        assertThat(mAttentionProcessor.updateAttention(offRoadDetection, timestamp))
+                .isEqualTo(INITIAL_VALUE);
+        timestamp += FRAME_TIME_MILLIS;
+
+        for (int i = 0; i < 100; i++) {
+            // Running on-road again with maxed out attention should max out at '1'.
+            assertTrue(mAttentionProcessor.updateAttention(offRoadDetection, timestamp) >= 0);
+            timestamp += FRAME_TIME_MILLIS;
+        }
+    }
+
+    @Test
+    public void testUpdateAttention_offRoadAndOnRoad() {
+
+        final GazeDetection onRoadDetection =
+                buildGazeDetection(GazeDetection.VEHICLE_REGION_FORWARD_ROADWAY);
+
+        final GazeDetection offRoadDetection =
+                buildGazeDetection(GazeDetection.VEHICLE_REGION_HEAD_UNIT_DISPLAY);
+
+        long timestamp = 1234;
+
+        // First pass should return initial value.
+        assertThat(mAttentionProcessor.updateAttention(onRoadDetection, timestamp))
+                .isEqualTo(INITIAL_VALUE);
+        timestamp += FRAME_TIME_MILLIS;
+
+        // Looking off-road should decay the attention.
+        assertThat(mAttentionProcessor.updateAttention(offRoadDetection, timestamp))
+                .isEqualTo(1.0f - DECAY_RATE);
+        timestamp += FRAME_TIME_MILLIS;
+
+        // Looking back up at the roadway should increase the buffer.
+        assertThat(mAttentionProcessor.updateAttention(onRoadDetection, timestamp))
+                .isEqualTo(1.0f - DECAY_RATE + GROWTH_RATE);
+        timestamp += FRAME_TIME_MILLIS;
+    }
+
+    /** Builds a {link GazeDetection} with the specified target for testing. */
+    private GazeDetection buildGazeDetection(@GazeDetection.VehicleRegion int gazeTarget) {
+        return new GazeDetection(
+                OccupantAwarenessDetection.CONFIDENCE_LEVEL_HIGH,
+                null /*leftEyePosition*/,
+                null /*rightEyePosition*/,
+                null /*headAngleUnitVector*/,
+                null /*gazeAngleUnitVector*/,
+                gazeTarget,
+                FRAME_TIME_MILLIS);
+    }
+}
diff --git a/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/GazeDriverAwarenessSupplierTest.java b/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/GazeDriverAwarenessSupplierTest.java
new file mode 100644
index 0000000..042c40d
--- /dev/null
+++ b/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/GazeDriverAwarenessSupplierTest.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.experimentalcar;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.car.experimental.DriverAwarenessEvent;
+import android.car.occupantawareness.GazeDetection;
+import android.car.occupantawareness.OccupantAwarenessDetection;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ServiceTestRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class GazeDriverAwarenessSupplierTest {
+
+    private static final long START_TIME_MILLIS = 1234L;
+    private static final long FRAME_TIME_MILLIS = 1000L;
+
+    private Context mSpyContext;
+    private GazeDriverAwarenessSupplier mGazeSupplier;
+    private float mInitialValue;
+    private float mGrowthRate;
+    private float mDecayRate;
+    private FakeTimeSource mTimeSource;
+
+    @Rule
+    public final ServiceTestRule serviceRule = new ServiceTestRule();
+
+    @Before
+    public void setUp() throws Exception {
+        mSpyContext = spy(InstrumentationRegistry.getInstrumentation().getTargetContext());
+
+        mInitialValue =
+                mSpyContext
+                        .getResources()
+                        .getFloat(R.fraction.driverAwarenessGazeModelInitialValue);
+        mGrowthRate =
+                mSpyContext.getResources().getFloat(R.fraction.driverAwarenessGazeModelGrowthRate);
+        mDecayRate =
+                mSpyContext.getResources().getFloat(R.fraction.driverAwarenessGazeModelDecayRate);
+
+        mTimeSource = new FakeTimeSource(START_TIME_MILLIS);
+        mGazeSupplier = spy(new GazeDriverAwarenessSupplier(mSpyContext, mTimeSource));
+    }
+
+    @Test
+    public void testWithBoundService() throws Exception {
+        Intent serviceIntent =
+                new Intent(ApplicationProvider.getApplicationContext(),
+                        GazeDriverAwarenessSupplier.class);
+
+        // Bind the service and grab a reference to the binder.
+        IBinder binder = serviceRule.bindService(serviceIntent);
+        assertThat(binder instanceof GazeDriverAwarenessSupplier.SupplierBinder).isTrue();
+    }
+
+    @Test
+    public void testonReady_initialCallbackIsGenerated() throws Exception {
+        // Supplier should return an initial callback after onReady().
+        mGazeSupplier.onReady();
+
+        verify(mGazeSupplier)
+                .emitAwarenessEvent(new DriverAwarenessEvent(START_TIME_MILLIS, mInitialValue));
+    }
+
+    @Test
+    public void testprocessDetectionEvent_noGazeDataProvided() throws Exception {
+        // If detection events happen with *no gaze*, no further events should be generated by the
+        // attention supplier.
+        mGazeSupplier.onReady();
+
+        mGazeSupplier.processDetectionEvent(buildEmptyDetection(START_TIME_MILLIS));
+
+        // Should have exactly one call from the initial onReady(), but no further events.
+        verify(mGazeSupplier, times(1))
+                .emitAwarenessEvent(new DriverAwarenessEvent(START_TIME_MILLIS, mInitialValue));
+    }
+
+    @Test
+    public void testprocessDetectionEvent_neverExceedsOne() throws Exception {
+        // Attention value should never exceed '1' no matter how long the driver looks on-road.
+        mGazeSupplier.onReady();
+
+        // Should have initial callback from onReady().
+        verify(mGazeSupplier)
+                .emitAwarenessEvent(new DriverAwarenessEvent(START_TIME_MILLIS, mInitialValue));
+
+        long timestamp = START_TIME_MILLIS + FRAME_TIME_MILLIS;
+        float attention = mInitialValue;
+
+        for (int i = 0; i < 100; i++) {
+            OccupantAwarenessDetection detection =
+                    buildGazeDetection(timestamp, GazeDetection.VEHICLE_REGION_FORWARD_ROADWAY);
+            mGazeSupplier.processDetectionEvent(detection);
+
+            verify(mGazeSupplier)
+                    .emitAwarenessEvent(new DriverAwarenessEvent(timestamp, attention));
+
+            // Increase attention, but not past 1.
+            attention = Math.min(attention + mGrowthRate, 1.0f);
+            timestamp += FRAME_TIME_MILLIS;
+        }
+    }
+
+    @Test
+    public void testprocessDetectionEvent_neverFallsBelowZero() throws Exception {
+        // Attention value should never fall below '0' no matter how long the driver looks off-road.
+        mGazeSupplier.onReady();
+
+        // Should have initial callback from onReady().
+        verify(mGazeSupplier)
+                .emitAwarenessEvent(new DriverAwarenessEvent(START_TIME_MILLIS, mInitialValue));
+
+        long timestamp = START_TIME_MILLIS + FRAME_TIME_MILLIS;
+        float attention = mInitialValue;
+
+        for (int i = 0; i < 100; i++) {
+            OccupantAwarenessDetection detection =
+                    buildGazeDetection(timestamp, GazeDetection.VEHICLE_REGION_HEAD_UNIT_DISPLAY);
+            mGazeSupplier.processDetectionEvent(detection);
+
+            verify(mGazeSupplier)
+                    .emitAwarenessEvent(new DriverAwarenessEvent(timestamp, attention));
+
+            // Decrement the attention, but not past 0.
+            attention = Math.max(attention - mDecayRate, 0);
+            timestamp += FRAME_TIME_MILLIS;
+        }
+    }
+
+    /** Builds a {link OccupantAwarenessDetection} with the specified target for testing. */
+    private OccupantAwarenessDetection buildGazeDetection(
+            long timestamp, @GazeDetection.VehicleRegion int gazeTarget) {
+        GazeDetection gaze =
+                new GazeDetection(
+                        OccupantAwarenessDetection.CONFIDENCE_LEVEL_HIGH,
+                        null /*leftEyePosition*/,
+                        null /*rightEyePosition*/,
+                        null /*headAngleUnitVector*/,
+                        null /*gazeAngleUnitVector*/,
+                        gazeTarget,
+                        FRAME_TIME_MILLIS);
+
+        return new OccupantAwarenessDetection(
+                OccupantAwarenessDetection.VEHICLE_OCCUPANT_DRIVER, timestamp, true, gaze, null);
+    }
+
+    /** Builds a {link OccupantAwarenessDetection} with the specified target for testing. */
+    private OccupantAwarenessDetection buildEmptyDetection(long timestamp) {
+        return new OccupantAwarenessDetection(
+                OccupantAwarenessDetection.VEHICLE_OCCUPANT_DRIVER, timestamp, true, null, null);
+    }
+}
diff --git a/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/TouchDriverAwarenessSupplierTest.java b/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/TouchDriverAwarenessSupplierTest.java
new file mode 100644
index 0000000..5ca40eb
--- /dev/null
+++ b/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/TouchDriverAwarenessSupplierTest.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.experimentalcar;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.car.experimental.DriverAwarenessEvent;
+import android.car.experimental.IDriverAwarenessSupplierCallback;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Looper;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.concurrent.ScheduledExecutorService;
+
+@RunWith(MockitoJUnitRunner.class)
+public class TouchDriverAwarenessSupplierTest {
+
+    private static final long INITIAL_TIME = 1000L;
+
+    @Mock
+    private ScheduledExecutorService mScheduledExecutorService;
+
+    @Mock
+    private Looper mLooper;
+
+    @Mock
+    private IDriverAwarenessSupplierCallback mSupplierCallback;
+
+    private TouchDriverAwarenessSupplier mTouchSupplier;
+    private int mMaxPermitsConfig;
+    private int mPermitThrottleMs;
+    private FakeTimeSource mTimeSource;
+    private Context mSpyContext;
+
+    @Before
+    public void setUp() throws Exception {
+        mSpyContext = spy(InstrumentationRegistry.getInstrumentation().getTargetContext());
+        mMaxPermitsConfig = mSpyContext.getResources().getInteger(
+                R.integer.driverAwarenessTouchModelMaxPermits);
+        mPermitThrottleMs = mSpyContext.getResources().getInteger(
+                R.integer.driverAwarenessTouchModelThrottleMs);
+        mTimeSource = new FakeTimeSource(INITIAL_TIME);
+        mTouchSupplier = spy(
+                new TouchDriverAwarenessSupplier(mSpyContext, mSupplierCallback,
+                        mScheduledExecutorService, mLooper,
+                        mTimeSource));
+        doNothing().when(mTouchSupplier).startTouchMonitoring();
+    }
+
+    @Test
+    public void testReady_initializesPermitsToMaxFromConfig() throws Exception {
+        mTouchSupplier.onReady();
+
+        verify(mSupplierCallback).onDriverAwarenessUpdated(
+                new DriverAwarenessEvent(INITIAL_TIME,
+                        TouchDriverAwarenessSupplier.INITIAL_DRIVER_AWARENESS_VALUE));
+    }
+
+    @Test
+    public void testconsumePermitLocked_decrementsPermitCount() throws Exception {
+        mTouchSupplier.onReady();
+
+        mTouchSupplier.consumePermitLocked(INITIAL_TIME);
+
+        verify(mSupplierCallback).onDriverAwarenessUpdated(
+                new DriverAwarenessEvent(INITIAL_TIME,
+                        awarenessValueForPermitCount(mMaxPermitsConfig)));
+    }
+
+    @Test
+    public void testconsumePermitLocked_decrementIgnoredInThrottleWindow() throws Exception {
+        mTouchSupplier.onReady();
+
+        mTouchSupplier.consumePermitLocked(INITIAL_TIME);
+        mTouchSupplier.consumePermitLocked(INITIAL_TIME + 1);
+
+        verify(mSupplierCallback).onDriverAwarenessUpdated(
+                new DriverAwarenessEvent(INITIAL_TIME,
+                        awarenessValueForPermitCount(mMaxPermitsConfig)));
+    }
+
+    @Test
+    public void testconsumePermitLocked_decrementsToMinOf0() throws Exception {
+        int lowMaxPermits = 1;
+
+        Resources spyResources = spy(mSpyContext.getResources());
+        doReturn(spyResources).when(mSpyContext).getResources();
+        doReturn(lowMaxPermits).when(spyResources).getInteger(
+                eq(R.integer.driverAwarenessTouchModelMaxPermits));
+        mTouchSupplier.onReady();
+
+        verify(mSupplierCallback).onDriverAwarenessUpdated(
+                new DriverAwarenessEvent(INITIAL_TIME, 1f));
+        long firstEventTimestamp = INITIAL_TIME + 1 + mPermitThrottleMs;
+        mTouchSupplier.consumePermitLocked(firstEventTimestamp);
+        verify(mSupplierCallback).onDriverAwarenessUpdated(
+                new DriverAwarenessEvent(firstEventTimestamp, 0f));
+        long secondEventTimestamp = INITIAL_TIME + 1 + mPermitThrottleMs;
+        mTouchSupplier.consumePermitLocked(secondEventTimestamp);
+
+        verify(mSupplierCallback).onDriverAwarenessUpdated(
+                new DriverAwarenessEvent(secondEventTimestamp, 0f));
+    }
+
+    @Test
+    public void testhandlePermitRefreshLocked_incrementsPermitCount() throws Exception {
+        mTouchSupplier.onReady();
+
+        mTouchSupplier.consumePermitLocked(INITIAL_TIME);
+        verify(mSupplierCallback).onDriverAwarenessUpdated(
+                new DriverAwarenessEvent(INITIAL_TIME,
+                        awarenessValueForPermitCount(mMaxPermitsConfig - 1)));
+
+        long refreshTimestamp = INITIAL_TIME + 1;
+        mTouchSupplier.handlePermitRefreshLocked(refreshTimestamp);
+        verify(mSupplierCallback).onDriverAwarenessUpdated(
+                new DriverAwarenessEvent(refreshTimestamp,
+                        awarenessValueForPermitCount(mMaxPermitsConfig)));
+    }
+
+    @Test
+    public void testhandlePermitRefreshLocked_incrementsToMaxOfConfig() throws Exception {
+        mTouchSupplier.onReady();
+
+        verify(mSupplierCallback).onDriverAwarenessUpdated(
+                new DriverAwarenessEvent(INITIAL_TIME,
+                        TouchDriverAwarenessSupplier.INITIAL_DRIVER_AWARENESS_VALUE));
+
+        long refreshTimestamp = INITIAL_TIME + 1;
+        mTouchSupplier.handlePermitRefreshLocked(refreshTimestamp);
+        verify(mSupplierCallback).onDriverAwarenessUpdated(
+                new DriverAwarenessEvent(refreshTimestamp,
+                        awarenessValueForPermitCount(mMaxPermitsConfig)));
+    }
+
+    private float awarenessValueForPermitCount(int count) {
+        return count / (float) mMaxPermitsConfig;
+    }
+}
diff --git a/procfs-inspector/client/Android.bp b/procfs-inspector/client/Android.bp
new file mode 100644
index 0000000..91b5e98
--- /dev/null
+++ b/procfs-inspector/client/Android.bp
@@ -0,0 +1,26 @@
+// 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.
+//
+//
+
+java_library {
+
+    name: "com.android.car.procfsinspector-client",
+
+    srcs: [
+        "src/**/*.java",
+        "src/**/I*.aidl",
+    ],
+
+}
diff --git a/procfs-inspector/client/Android.mk b/procfs-inspector/client/Android.mk
deleted file mode 100644
index d9713de..0000000
--- a/procfs-inspector/client/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := com.android.car.procfsinspector-client
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/procfs-inspector/server/Android.mk b/procfs-inspector/server/Android.mk
index fab1cf8..6924ef5 100644
--- a/procfs-inspector/server/Android.mk
+++ b/procfs-inspector/server/Android.mk
@@ -25,9 +25,6 @@
     process.cpp \
     directory.cpp
 
-LOCAL_C_INCLUDES += \
-    frameworks/base/include
-
 LOCAL_SHARED_LIBRARIES := \
     libbinder \
     liblog \
diff --git a/service/Android.bp b/service/Android.bp
new file mode 100644
index 0000000..50f0f41
--- /dev/null
+++ b/service/Android.bp
@@ -0,0 +1,155 @@
+// 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.
+//
+//
+
+// Build the Car service.
+
+genrule {
+    name: "statslog-Car-java-gen",
+    tools: ["stats-log-api-gen"],
+    cmd: "$(location stats-log-api-gen) --java $(out) --module car --javaPackage com.android.car"
+        + " --javaClass CarStatsLog",
+    out: ["com/android/car/CarStatsLog.java"],
+}
+
+car_service_sources = [
+    "src/**/*.java",
+    ":statslog-Car-java-gen",
+]
+
+common_lib_deps = [
+    "android.car.userlib",
+    "android.car.watchdoglib",
+    "android.hidl.base-V1.0-java",
+    "android.hardware.automotive.audiocontrol-V1.0-java",
+    "android.hardware.automotive.audiocontrol-V2.0-java",
+    "android.hardware.automotive.vehicle-V2.0-java",
+    "android.hardware.health-V1.0-java",
+    "android.hardware.health-V2.0-java",
+    "android.hardware.automotive.occupant_awareness-java",
+    "vehicle-hal-support-lib",
+    "car-systemtest",
+    "com.android.car.procfsinspector-client",
+    "blestream-protos",
+    "SettingsLib",
+    "androidx.preference_preference",
+    "EncryptionRunner",
+]
+
+android_app {
+    name: "CarService",
+
+    srcs: car_service_sources,
+
+    resource_dirs: ["res"],
+
+    platform_apis: true,
+
+    // Each update should be signed by OEMs
+    certificate: "platform",
+    privileged: true,
+
+    optimize: {
+        proguard_flags_files: ["proguard.flags"],
+        enabled: false,
+    },
+
+    libs: ["android.car"],
+
+    static_libs: common_lib_deps + [
+        "car-frameworks-service",
+    ],
+
+    required: ["privapp_whitelist_com.android.car"],
+
+    // Disable build in PDK, missing aidl import breaks build
+    product_variables: {
+        pdk: {
+            enabled: false,
+        },
+    },
+}
+
+java_library {
+
+    name: "car-service-common-util-static-lib",
+
+    srcs: [
+        "src/com/android/car/CarServiceBase.java",
+        "src/com/android/car/CarServiceUtils.java",
+        "src/com/android/car/CarLog.java",
+        "src/com/android/car/Utils.java",
+    ],
+
+    product_variables: {
+            pdk: {
+                enabled: false,
+            },
+    },
+}
+
+//####################################################################################
+// Build a static library to help mocking various car services in testing. This is meant to be used
+// for internal unit tests around the car service.
+//####################################################################################
+android_library {
+    name: "car-service-test-static-lib",
+
+    srcs: car_service_sources,
+
+    resource_dirs: ["res"],
+
+    libs: [
+        "android.car",
+        "car-frameworks-service",
+    ],
+
+    static_libs: common_lib_deps,
+
+    min_sdk_version: "25",
+
+    product_variables: {
+        pdk: {
+            enabled: false,
+        },
+    },
+}
+
+//####################################################################################
+// Build a library to help generate a testing library for external apps.
+// We do not want to use statically linked libraries, as this will bloat the output jar with classes
+// that can conflict with the user's environment.
+//####################################################################################
+android_library {
+    name: "car-service-test-lib",
+
+    srcs: car_service_sources,
+
+    resource_dirs: ["res"],
+
+    libs: common_lib_deps + [
+        "android.car",
+        "car-frameworks-service",
+    ],
+
+    min_sdk_version: "25",
+
+    product_variables: {
+        pdk: {
+            enabled: false,
+        },
+    },
+}
+
diff --git a/service/Android.mk b/service/Android.mk
deleted file mode 100644
index f9d6032..0000000
--- a/service/Android.mk
+++ /dev/null
@@ -1,107 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-#
-
-# Build the Car service.
-
-#disble build in PDK, missing aidl import breaks build
-ifneq ($(TARGET_BUILD_PDK),true)
-
-LOCAL_PATH:= $(call my-dir)
-
-car_service_sources := $(call all-java-files-under, src)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(car_service_sources)
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_PACKAGE_NAME := CarService
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-# Each update should be signed by OEMs
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_JAVA_LIBRARIES += \
-    android.car \
-
-LOCAL_STATIC_JAVA_LIBRARIES += \
-    android.car.userlib \
-    android.hidl.base-V1.0-java \
-    android.hardware.automotive.audiocontrol-V1.0-java \
-    android.hardware.automotive.vehicle-V2.0-java \
-    android.hardware.health-V1.0-java \
-    android.hardware.health-V2.0-java \
-    vehicle-hal-support-lib \
-    car-frameworks-service \
-    car-systemtest \
-    com.android.car.procfsinspector-client \
-    blestream-protos \
-
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-    SettingsLib \
-    androidx.preference_preference \
-    EncryptionRunner
-
-LOCAL_REQUIRED_MODULES := privapp_whitelist_com.android.car
-
-include $(BUILD_PACKAGE)
-
-#####################################################################################
-# Build a static library to help mocking various car services in testing
-#####################################################################################
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(car_service_sources)
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_MODULE := car-service-lib-for-test
-
-LOCAL_JAVA_LIBRARIES += \
-    android.car \
-    car-frameworks-service \
-
-LOCAL_STATIC_JAVA_LIBRARIES += \
-    android.car.userlib \
-    android.hidl.base-V1.0-java \
-    android.hardware.automotive.audiocontrol-V1.0-java \
-    android.hardware.automotive.vehicle-V2.0-java \
-    android.hardware.health-V1.0-java \
-    android.hardware.health-V2.0-java \
-    vehicle-hal-support-lib \
-    car-systemtest \
-    com.android.car.procfsinspector-client \
-    blestream-protos \
-
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-    SettingsLib \
-    androidx.preference_preference \
-    EncryptionRunner
-
-LOCAL_MIN_SDK_VERSION := 25
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
-
-endif #TARGET_BUILD_PDK
diff --git a/service/AndroidManifest.xml b/service/AndroidManifest.xml
index 59ce65d..f15978c 100644
--- a/service/AndroidManifest.xml
+++ b/service/AndroidManifest.xml
@@ -39,6 +39,15 @@
         android:label="@string/car_permission_label_energy"
         android:description="@string/car_permission_desc_energy" />
 
+    <!-- Allows an application to adjust the vehicle's range remaining information.
+         <p>Protection level: signature|privileged
+     -->
+    <permission
+        android:name="android.car.permission.ADJUST_RANGE_REMAINING"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_adjust_range_remaining"
+        android:description="@string/car_permission_desc_adjust_range_remaining" />
+
     <!-- Allows an application to read the VIN information.
          <p>Protection level: signature|privileged
     -->
@@ -159,6 +168,15 @@
         android:label="@string/car_permission_label_car_energy_ports"
         android:description="@string/car_permission_desc_car_energy_ports" />
 
+    <!-- Allows an application to control the vehicle fuel and charge port status.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.CONTROL_CAR_ENERGY_PORTS"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_control_car_energy_ports"
+        android:description="@string/car_permission_desc_control_car_energy_ports" />
+
     <!-- Allows an application to read the vehicle engine information. For example, it allows an
          application to read the engine oil level, oil temperature, coolant temperature and RPM.
          <p>Protection level: signature|privileged
@@ -236,6 +254,15 @@
         android:label="@string/car_permission_label_car_info"
         android:description="@string/car_permission_desc_car_info" />
 
+    <!-- Allows an application to read information of car's vendor permission.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.READ_CAR_VENDOR_PERMISSION_INFO"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_vendor_permission_info"
+        android:description="@string/car_permission_desc_vendor_permission_info" />
+
     <!-- Allows an application to read the vehicle exterior environment information. For example,
          it allows an application to read the vehicle exterior temperature and night mode status.
          <p>Protection level: normal
@@ -457,6 +484,24 @@
         android:label="@string/car_permission_label_car_ux_restrictions_configuration"
         android:description="@string/car_permission_desc_car_ux_restrictions_configuration" />
 
+    <!-- Allows an application to read state data from the 'Occupant Awareness System'.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.READ_CAR_OCCUPANT_AWARENESS_STATE"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_read_car_occupant_awareness_state"
+        android:description="@string/car_permission_desc_read_car_occupant_awareness_state" />
+
+    <!-- Allows an application to control the detection graph for the 'Occupant Awareness System'.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.CONTROL_CAR_OCCUPANT_AWARENESS_SYSTEM"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_control_car_occupant_awareness_system"
+        android:description="@string/car_permission_desc_control_car_occupant_awareness_system" />
+
     <!-- Allows an application to monitor flash storage usage.
          <p>Protection level: signature|privileged
     -->
@@ -485,6 +530,350 @@
         android:label="@string/car_permission_label_car_test_service"
         android:description="@string/car_permission_desc_car_test_service" />
 
+    <!-- Allows system app to enable / disable / query features in the system.
+     <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.CONTROL_CAR_FEATURES"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_control_car_features"
+        android:description="@string/car_permission_desc_control_car_features" />
+
+    <!-- Allows an application to use car watchdog service.
+        <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.USE_CAR_WATCHDOG"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_use_car_watchdog"
+        android:description="@string/car_permission_desc_use_car_watchdog" />
+
+    <!-- Allows an application to read vendor properties related with windows.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_WINDOW"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_get_car_vendor_category_window"
+        android:description="@string/car_permission_desc_get_car_vendor_category_window" />
+
+    <!-- Allows an application to control vendor properties related with windows.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_WINDOW"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_set_car_vendor_category_window"
+        android:description="@string/car_permission_desc_set_car_vendor_category_window" />
+
+    <!-- Allows an application to read vendor properties related with doors.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_DOOR"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_get_car_vendor_category_door"
+        android:description="@string/car_permission_desc_get_car_vendor_category_door" />
+
+    <!-- Allows an application to control vendor properties related with doors.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_DOOR"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_set_car_vendor_category_door"
+        android:description="@string/car_permission_desc_set_car_vendor_category_door" />
+
+
+    <!-- Allows an application to read vendor properties related with seats.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_SEAT"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_get_car_vendor_category_seat"
+        android:description="@string/car_permission_desc_get_car_vendor_category_seat" />
+
+    <!-- Allows an application to control vendor properties related with seats.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_SEAT"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_set_car_vendor_category_seat"
+        android:description="@string/car_permission_desc_set_car_vendor_category_seat" />
+
+    <!-- Allows an application to read vendor properties related with mirrors.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_MIRROR"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_get_car_vendor_category_mirror"
+        android:description="@string/car_permission_desc_get_car_vendor_category_mirror" />
+
+    <!-- Allows an application to control vendor properties related with mirrors.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_MIRROR"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_set_car_vendor_category_mirror"
+        android:description="@string/car_permission_desc_set_car_vendor_category_mirror" />
+
+    <!-- Allows an application to read vendor properties related with car information.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_INFO"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_get_car_vendor_category_info"
+        android:description="@string/car_permission_desc_get_car_vendor_category_info" />
+
+    <!-- Allows an application to control vendor properties related with car information.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_INFO"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_set_car_vendor_category_info"
+        android:description="@string/car_permission_desc_set_car_vendor_category_info" />
+
+    <!-- Allows an application to read vendor properties related with engine.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_ENGINE"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_get_car_vendor_category_engine"
+        android:description="@string/car_permission_desc_get_car_vendor_category_engine" />
+
+    <!-- Allows an application to control vendor properties related with engine.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_ENGINE"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_set_car_vendor_category_engine"
+        android:description="@string/car_permission_desc_set_car_vendor_category_engine" />
+
+    <!-- Allows an application to read vendor properties related with HVAC.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_HVAC"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_get_car_vendor_category_hvac"
+        android:description="@string/car_permission_desc_get_car_vendor_category_hvac" />
+
+    <!-- Allows an application to control vendor properties related with hvac.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_HVAC"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_set_car_vendor_category_hvac"
+        android:description="@string/car_permission_desc_set_car_vendor_category_hvac" />
+
+    <!-- Allows an application to read vendor properties related with light.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_LIGHT"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_get_car_vendor_category_light"
+        android:description="@string/car_permission_desc_get_car_vendor_category_light" />
+
+    <!-- Allows an application to control vendor properties related with light.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_LIGHT"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_set_car_vendor_category_light"
+        android:description="@string/car_permission_desc_set_car_vendor_category_light" />
+
+    <!-- Allows an application to access vendor properties in category 1.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_1"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_get_car_vendor_category_1"
+        android:description="@string/car_permission_desc_get_car_vendor_category_1" />
+
+    <!-- Allows an application to control vendor properties in category 1.
+        <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_1"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_set_car_vendor_category_1"
+        android:description="@string/car_permission_desc_set_car_vendor_category_1" />
+
+    <!-- Allows an application to access vendor properties in category 2.
+        <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_2"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_get_car_vendor_category_2"
+        android:description="@string/car_permission_desc_get_car_vendor_category_2" />
+
+    <!-- Allows an application to control vendor properties in category 2.
+        <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_2"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_set_car_vendor_category_2"
+        android:description="@string/car_permission_desc_set_car_vendor_category_2" />
+
+    <!-- Allows an application to access vendor properties in category 3.
+        <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_3"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_get_car_vendor_category_3"
+        android:description="@string/car_permission_desc_get_car_vendor_category_3" />
+
+    <!-- Allows an application to control vendor properties in category 3.
+        <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_3"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_set_car_vendor_category_3"
+        android:description="@string/car_permission_desc_set_car_vendor_category_3" />
+
+    <!-- Allows an application to access vendor properties in category 4.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_4"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_get_car_vendor_category_4"
+        android:description="@string/car_permission_desc_get_car_vendor_category_4" />
+
+    <!-- Allows an application to control vendor properties in category 4.
+        <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_4"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_set_car_vendor_category_4"
+        android:description="@string/car_permission_desc_set_car_vendor_category_4" />
+
+    <!-- Allows an application to access vendor properties in category 5.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_5"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_get_car_vendor_category_5"
+        android:description="@string/car_permission_desc_get_car_vendor_category_5" />
+
+    <!-- Allows an application to control vendor properties in category 5.
+        <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_5"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_set_car_vendor_category_5"
+        android:description="@string/car_permission_desc_set_car_vendor_category_5" />
+
+    <!-- Allows an application to access vendor properties in category 6.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_6"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_get_car_vendor_category_6"
+        android:description="@string/car_permission_desc_get_car_vendor_category_6" />
+
+    <!-- Allows an application to control vendor properties in category 6.
+        <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_6"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_set_car_vendor_category_6"
+        android:description="@string/car_permission_desc_set_car_vendor_category_6" />
+
+    <!-- Allows an application to access vendor properties in category 7.
+        <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_7"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_get_car_vendor_category_7"
+        android:description="@string/car_permission_desc_get_car_vendor_category_7" />
+
+    <!-- Allows an application to control vendor properties in category 7.
+        <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_7"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_set_car_vendor_category_7"
+        android:description="@string/car_permission_desc_set_car_vendor_category_7" />
+
+    <!-- Allows an application to access vendor properties in category 8.
+        <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_8"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_get_car_vendor_category_8"
+        android:description="@string/car_permission_desc_get_car_vendor_category_8" />
+
+    <!-- Allows an application to control vendor properties in category 8.
+        <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_8"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_set_car_vendor_category_8"
+        android:description="@string/car_permission_desc_set_car_vendor_category_8" />
+
+    <!-- Allows an application to access vendor properties in category 9.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_9"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_get_car_vendor_category_9"
+        android:description="@string/car_permission_desc_get_car_vendor_category_9" />
+
+    <!-- Allows an application to control vendor properties in category 9.
+        <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_9"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_set_car_vendor_category_9"
+        android:description="@string/car_permission_desc_set_car_vendor_category_9" />
+
+    <!-- Allows an application to access vendor properties in category 10.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_10"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_get_car_vendor_category_10"
+        android:description="@string/car_permission_desc_get_car_vendor_category_10" />
+
+    <!-- Allows an application to control vendor properties in category 10.
+        <p>Protection level: signature|privileged
+    -->
+    <permission
+        android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_10"
+        android:protectionLevel="signature|privileged"
+        android:label="@string/car_permission_label_set_car_vendor_category_10"
+        android:description="@string/car_permission_desc_set_car_vendor_category_10" />
+
+
     <uses-permission android:name="android.permission.CALL_PHONE" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
     <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS" />
@@ -514,7 +903,6 @@
                  android:allowBackup="false"
                  android:persistent="true">
 
-        <uses-library android:name="android.test.runner" />
         <service android:name=".CarService"
                 android:singleUser="true">
             <intent-filter>
diff --git a/service/OWNERS b/service/OWNERS
new file mode 100644
index 0000000..4b56e5e
--- /dev/null
+++ b/service/OWNERS
@@ -0,0 +1,11 @@
+# Project owners
+keunyoung@google.com
+sgurun@google.com
+gurunagarajan@google.com
+pfg@google.com
+kevinme@google.com
+ankitarora@google.com
+swan@google.com
+pirozzoj@google.com
+twasilczyk@google.com
+felipeal@google.com
diff --git a/service/proto/Android.bp b/service/proto/Android.bp
index 8d500ea..92a73f4 100644
--- a/service/proto/Android.bp
+++ b/service/proto/Android.bp
@@ -5,7 +5,6 @@
         type: "lite",
     },
     srcs: ["*.proto"],
-    no_framework_libs: true,
     jarjar_rules: "jarjar-rules.txt",
     sdk_version: "28",
 }
diff --git a/service/proto/ble_device_message.proto b/service/proto/ble_device_message.proto
new file mode 100644
index 0000000..70896e8
--- /dev/null
+++ b/service/proto/ble_device_message.proto
@@ -0,0 +1,23 @@
+syntax = "proto3";
+
+package aae.blemessagestream;
+
+import "packages/services/Car/service/proto/operation_type.proto";
+
+option java_package = "com.android.car.BleStreamProtos";
+option java_outer_classname = "BleDeviceMessageProto";
+
+// A message between devices.
+message BleDeviceMessage {
+  // The operation that this message represents.
+  OperationType operation = 1;
+
+  // Whether the payload field is encrypted.
+  bool is_payload_encrypted = 2;
+
+  // Identifier of the intended recipient.
+  bytes recipient = 3;
+
+  // The bytes that represent the content for this message.
+  bytes payload = 4;
+}
diff --git a/service/proto/ble_packet.proto b/service/proto/ble_packet.proto
new file mode 100644
index 0000000..109365e
--- /dev/null
+++ b/service/proto/ble_packet.proto
@@ -0,0 +1,22 @@
+syntax = "proto3";
+
+package aae.blemessagestream;
+
+option java_package = "com.android.car.BleStreamProtos";
+option java_outer_classname = "BlePacketProto";
+
+// A packet across a BLE channel.
+message BlePacket {
+  // A 1-based packet number. The first message will have a value of "1" rather
+  // than "0".
+  fixed32 packet_number = 1;
+
+  // The total number of packets in the message stream.
+  int32 total_packets = 2;
+
+  // Id of message for reassembly on other side
+  int32 message_id = 3;
+
+  // The bytes that represent the message content for this packet.
+  bytes payload = 4;
+}
diff --git a/service/res/layout/activity_blocking.xml b/service/res/layout/activity_blocking.xml
index f79406d..911c658 100644
--- a/service/res/layout/activity_blocking.xml
+++ b/service/res/layout/activity_blocking.xml
@@ -12,58 +12,67 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="@color/activity_blocking_activity_background"
-    android:gravity="center"
-    android:orientation="vertical">
+    android:layout_height="match_parent">
 
-  <ImageView
-      android:id="@+id/ux_restricted_icon"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_marginBottom="@dimen/common_margin"
-      android:src="@drawable/car_ic_ux_restricted_48dp" />
+    <android.opengl.GLSurfaceView
+        android:id="@+id/blurred_surface_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
 
-  <TextView
-      android:id="@+id/blocking_text"
-      android:layout_width="@dimen/blocking_text_width"
-      android:layout_height="wrap_content"
-      android:gravity="center"
-      android:text="@string/activity_blocked_text"
-      android:textAppearance="@style/ActivityBlockingActivityText" />
+    <LinearLayout
+        android:id="@+id/activity_blocking_content"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@color/activity_blocking_activity_background"
+        android:gravity="center"
+        android:orientation="vertical">
 
-  <LinearLayout
-      android:id="@+id/action_button_container"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_marginTop="48dp"
-      android:layout_gravity="center"
-      android:gravity="center_horizontal"
-      android:orientation="horizontal">
-    <Button
-        android:id="@+id/exit_button"
-        style="@style/ButtonStyle" />
+        <ImageView
+            android:id="@+id/ux_restricted_icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="@dimen/common_margin"
+            android:src="@drawable/car_ic_ux_restricted_48dp" />
 
-    <Button
-        android:id="@+id/toggle_debug_info"
-        style="@style/ButtonStyle"
-        android:text="@string/debug_button_text"
-        android:visibility="gone"
-        android:layout_marginStart="@dimen/action_button_padding_horizontal"/>
+        <TextView
+            android:id="@+id/blocking_text"
+            android:layout_width="@dimen/blocking_text_width"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:text="@string/activity_blocked_text"
+            android:textAppearance="@style/ActivityBlockingActivityText" />
 
-  </LinearLayout>
+        <LinearLayout
+            android:id="@+id/action_button_container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="48dp"
+            android:layout_gravity="center"
+            android:gravity="center_horizontal"
+            android:orientation="horizontal">
+            <Button
+                android:id="@+id/exit_button"
+                style="@style/ButtonStyle" />
 
-  <TextView
-      android:id="@+id/debug_info"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:textAppearance="@style/ActivityBlockingActivityText"
-      android:visibility="gone" />
+            <Button
+                android:id="@+id/toggle_debug_info"
+                style="@style/ButtonStyle"
+                android:text="@string/debug_button_text"
+                android:visibility="gone"
+                android:layout_marginStart="@dimen/action_button_padding_horizontal"/>
 
-</LinearLayout>
+        </LinearLayout>
 
+        <TextView
+            android:id="@+id/debug_info"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="@style/ActivityBlockingActivityText"
+            android:visibility="gone" />
+
+    </LinearLayout>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/service/res/raw/horizontal_blur_fragment_shader.glsl b/service/res/raw/horizontal_blur_fragment_shader.glsl
new file mode 100644
index 0000000..b0b935f
--- /dev/null
+++ b/service/res/raw/horizontal_blur_fragment_shader.glsl
@@ -0,0 +1,36 @@
+#extension GL_OES_EGL_image_external : require
+precision mediump float;
+
+uniform vec3                uResolution;
+uniform samplerExternalOES  sTexture;
+uniform float               uRadius;
+varying vec2                vTextureCoord;
+
+float computeWeight(float x) {
+    return -((x * x) / (uRadius * uRadius)) + 1.0;
+}
+
+/**
+* This shader sets the colour of each fragment to be the weighted average of the uRadius fragments
+* horizontally adjacent to it to produce a blur effect along the x-axis of the texture
+*
+* The weights come from the following curve: f(x) = 1 - (x^2)/(r^2)
+* where r is the radius of the blur
+*/
+void main() {
+    vec4 sampledColor = vec4(0.0);
+    vec4 weightedColor = vec4(0.0);
+
+    float divisor = 0.0;
+    float weight = 0.0;
+
+    for (float x = -uRadius; x <= uRadius; x++)
+    {
+        sampledColor = texture2D(sTexture, vTextureCoord + vec2(x / uResolution.x, 0.0));
+        weight = computeWeight(x);
+        weightedColor += sampledColor * weight;
+        divisor += weight;
+    }
+
+    gl_FragColor = vec4(weightedColor.r / divisor, weightedColor.g / divisor, weightedColor.b / divisor, 1.0);
+}
diff --git a/service/res/raw/vertex_shader.glsl b/service/res/raw/vertex_shader.glsl
new file mode 100644
index 0000000..69e7c2e
--- /dev/null
+++ b/service/res/raw/vertex_shader.glsl
@@ -0,0 +1,15 @@
+uniform mat4 uMVPMatrix;
+uniform mat4 uTexMatrix;
+attribute vec4 aPosition;
+attribute vec4 aTextureCoord;
+varying vec2 vTextureCoord;
+
+/**
+* This vertex shader maps the projection matrix to the
+* position of the frame and then forwards
+* the coordinates of the texture to a vertex shader
+*/
+void main() {
+    gl_Position = uMVPMatrix * aPosition;
+    vTextureCoord = (uTexMatrix * aTextureCoord).xy;
+}
diff --git a/service/res/raw/vertical_blur_fragment_shader.glsl b/service/res/raw/vertical_blur_fragment_shader.glsl
new file mode 100644
index 0000000..abe6436
--- /dev/null
+++ b/service/res/raw/vertical_blur_fragment_shader.glsl
@@ -0,0 +1,36 @@
+#extension GL_OES_EGL_image_external : require
+precision mediump float;
+
+uniform vec3                uResolution;
+uniform sampler2D           sTexture;
+uniform float               uRadius;
+varying vec2                vTextureCoord;
+
+float computeWeight(float x) {
+    return -((x * x) / (uRadius * uRadius)) + 1.0;
+}
+
+/**
+* This shader sets the colour of each fragment to be the weighted average of the uRadius fragments
+* vertically adjacent to it to produce a blur effect along the y-axis of the texture
+*
+* The weights come from the following curve: f(x) = 1 - (x^2)/(r^2)
+* where r is the radius of the blur
+*/
+void main() {
+    vec4 sampledColor = vec4(0.0);
+    vec4 weightedColor = vec4(0.0);
+
+    float divisor = 0.0;
+    float weight = 0.0;
+
+    for (float y = -uRadius; y <= uRadius; y++)
+    {
+        sampledColor = texture2D(sTexture, vTextureCoord + vec2(0.0, y / uResolution.y));
+        weight = computeWeight(y);
+        weightedColor += sampledColor * weight;
+        divisor += weight;
+    }
+
+    gl_FragColor = vec4(weightedColor.r / divisor, weightedColor.g / divisor, weightedColor.b / divisor, 1.0);
+}
diff --git a/service/res/values-af/strings.xml b/service/res/values-af/strings.xml
index 212959c..6c1a292 100644
--- a/service/res/values-af/strings.xml
+++ b/service/res/values-af/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Toegang tot motor se kamera(s)."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"toegang tot motor se dryfkraginligting"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Toegang tot jou motor se energie-inligting."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"verstel motor se oorblywende ritafstand"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Verstel waarde van motor se oorblywende ritafstand."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"toegang tot motor se HVAC- (verhitting, ventilasie, lugversorging) stelsel"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Toegang tot jou motor se HVAC (verhitting, venitalise en lugversorging)."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"toegang tot motor se ryafstandinligting"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Stel UX-beperkings op"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Kommunikeer met USB-toestel in AOAP-modus"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Laat \'n program toe om in AOAP-modus met \'n toestel te kommunikeer"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Leestoegang tot insittendebewustheidstelsel"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Laat toe dat status- en bespeuringsdata vir die insittendebewustheidstelsel gelees word"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Beheer insittendebewustheidstelsel se grafiek"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Laat toe dat die begin en einde van die insittendebewustheidstelsel se bespeuringsgrafiek beheer word"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Motorinvoerdiens"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Hanteer invoergebeurtenisse"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-bus het misluk"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Toegang tot jou motor se gedetailleerde enjininligting."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"toegang tot motor se brandstofdeur en laaipoort"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Toegang tot motor se brandstofdeur en laaipoort."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"beheer motor se brandstofdeur en laaipoort"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Beheer motor se brandstofdeur en laaipoort."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"lees motor se identifikasie"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Toegang tot motor se identifikasie."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"beheer motor se deure"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Beheer motor se sitplekke."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"toegang tot motor se basiese inligting"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Toegang tot motor se basiese inligting."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"gaan in by motorverkoper se toestemmingsinligting"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Gaan in by motorverkoper se toestemmingsinligting."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"lees motor se buiteligtestaat"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Toegang tot motor se buiteligtestaat."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"lees motor se buiteligte"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Laat inskrywing van vertroude toestelle toe"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Beheer motor se toetsmodus"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Beheer motor se toetsmodus"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Aktiveer of deaktiveer motor se kenmerke"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Aktiveer of deaktiveer motor se kenmerke."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"gebruik motorwaghond"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Gebruik motorwaghond."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"My Toestel"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Gas"</string>
 </resources>
diff --git a/service/res/values-am/strings.xml b/service/res/values-am/strings.xml
index 62857d5..3899911 100644
--- a/service/res/values-am/strings.xml
+++ b/service/res/values-am/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"የእርስዎን ካሜራ(ዎች) ይደርሱበት(ባቸው)።"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"የመኪናውን የኃይል መረጃ ድረስበት"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"የእርስዎን መኪና ኃይል መረጃ ይድረሱበት።"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"የመኪና ክልልን ቀሪ አስተካክል"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"የመኪና ክልልን ቀሪ ዋጋ አስተካክል።"</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"የመኪናውን hvac ድረስበት"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"የእርስዎን መኪና hvac ይድረሱበት።"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"የመኪናውን የሄደበት ርቀት ብዛት መረጃ ድረስበት"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"የUX ገደቦችን ያዋቅሩ"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"ከዩኤስቢ መሣሪያ ጋር በ AOAP ሁነታ ውስጥ መልዕክት ይለዋወጡ"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"አንድ መተግበሪያ ከመሣሪያ ጋር በ AOAP ሁነታ ውስጥ መልዕክት እንዲለዋወጥ ይፈቅዳል"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"የተሳፋሪ ማስገንዘቢያ ሥርዓት የንባብ መዳረሻ"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"የተሳፋሪ ማስገንዘቢያ ሥርዓት ሁኔታን እና ፈልጎ ማግኛን ውሂብ ማንበብን ያስችላል"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"የተሳፋሪ ማስገንዘቢያ ሥርዓት ፈልጎ ማወቂያ ግራፍን ይቆጣጠሩ"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"የተሳፋሪ ማስገንዘቢያ ሥርዓት ፈልጎ ማወቂያ ግራፍ ማስጀመርን እና ማስቆምን መቆጣጠርን ያስችላል"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"የመኪና ግቤት አገልግሎት"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"የግቤት ክስተቶችን ያስተናግዱ"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN አውቶብስ አልተሳካም"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"የእርስዎን መኪና በዝርዝር የቀረበ የሞተር መረጃ ይድረሱበት።"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"የመኪናውን የነዳጅ በር እና የኃይል መሙያ በር ድረስበት"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"የመኪና ነዳጅን በር እና የኃይል መሙያ ወደብ ይድረሱባቸው።"</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"የመኪናውን የነዳጅ በር እና የኃይል መሙያ በር መድረስ"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"የመኪናውን የነዳጅ በር እና የኃይል መሙያ በር መድረስ።"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"የመኪናውን መለያ መታወቂያ አንብብ"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"የመኪና ለይቶ ማወቂያን ይድረሱበት።"</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"የመኪና በሮችን ተቆጣጠር"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"የመኪና ወንበሮችን ይቆጣጠሩ።"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"የመኪናን መሠረታዊ መረጃ ድረስበት"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"የመኪና መሠረታዊ መረጃን ይድረሱበት።"</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"የመኪና አቅራቢ ፈቃድ መረጃን መድረስ"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"የመኪና አቅራቢ ፈቃድ መረጃን መድረስ።"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"የመኪናውን የውጭ መብራቶች ሁኔታ ድረስበት"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"የመኪናውን የውጭ መብራቶች ሁነታ ይድረሱባቸው።"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"የመኪናውን የውጭ መብራቶች አንብብ"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"የታመነ መሣሪያ ምዝገባ ይፍቀዱ"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"የመኪና ሙከራ ሁነታን ተቆጣጠር"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"የመኪና ሙከራ ሁነታን ተቆጣጠር"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"የመኪና ባህሪዎችን አንቃ ወይም አሰናክል"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"የመኪና ባህሪዎችን አንቃ ወይም አሰናክል"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"የመኪና ጠባቂን መጠቀም"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"የመኪና ጠባቂን መጠቀም።"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"የእኔ መሣሪያ"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"እንግዳ"</string>
 </resources>
diff --git a/service/res/values-ar/strings.xml b/service/res/values-ar/strings.xml
index a79636f..3b3015e 100644
--- a/service/res/values-ar/strings.xml
+++ b/service/res/values-ar/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"الوصول إلى الكاميرات في السيارة"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"الحصول على معلومات عن طاقة السيارة"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"الحصول على معلومات الطاقة في السيارة"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"ضبط القيمة المتبقية لنطاق السيارة"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"يمكنك ضبط القيمة المتبقية لنطاق السيارة."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"الحصول على معلومات التدفئة والتهوية وتكييف الهواء في السيارة"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"الحصول على معلومات التدفئة والتهوية وتكييف الهواء في السيارة"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"الحصول على معلومات المسافة المقطوعة بالأميال في سيارتك"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"ضبط قيود تجربة المُستخدِم"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"التواصل مع جهاز USB في وضع AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"يتيح للتطبيق التواصل مع جهاز في وضع AOAP."</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"الوصول لقراءة Occupant Awareness System"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"السماح بقراءة حالة Occupant Awareness System وبيانات التعرف عليه"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"التحكّم في الرسم البياني لنظام Occupant Awareness System"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"السماح بالتحكّم في بدء وإيقاف الرسم البياني للتعرف على Occupant Awareness System"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"خدمة إدخال السيارة"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"التعامل مع أحداث الإدخال"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"حدث خطأ في موصّل CAN"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"يمكنك الحصول على معلومات تفصيلية عن محرّك السيارة."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"الحصول على معلومات عن .باب خزان الوقود ومنفذ الشحن"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"يمكنك الحصول على معلومات عن باب خزان الوقود ومنفذ الشحن."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"التحكّم في باب خزان الوقود ومنفذ الشحن في السيارة"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"التحكّم في باب خزان الوقود ومنفذ الشحن"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"قراءة معلومات عن تحديد هوية السيارة"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"يمكنك الحصول على معلومات عن تحديد هوية السيارة."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"التحكم في أبواب السيارة"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"يمكنك التحكم في مقاعد السيارة."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"الحصول على المعلومات الأساسية للسيارة"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"يمكنك الحصول على المعلومات الأساسية عن السيارة."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"الوصول إلى معلومات إذن المورّد للسيارة"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"الوصول إلى معلومات إذن المورّد للسيارة"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"قراءة معلومات عن حالة الإضاءة الخارجية للسيارة"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"يمكنك الحصول على معلومات عن حالة الإضاءة الخارجية للسيارة."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"قراءة معلومات عن الإضاءة الخارجية للسيارة"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"السماح بتسجيل الأجهزة الموثوق بها"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"وضع اختبار التحكم في السيارة"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"وضع اختبار التحكم في السيارة"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"تفعيل ميزات السيارة أو إيقافها"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"تفعيل ميزات السيارة أو إيقافها"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"استخدام مراقب نظام السيارة"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"استخدام مراقب نظام السيارة"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"جهازي"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"ضيف"</string>
 </resources>
diff --git a/service/res/values-as/strings.xml b/service/res/values-as/strings.xml
index 49fc913..811d8f7 100644
--- a/service/res/values-as/strings.xml
+++ b/service/res/values-as/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"আপোনাৰ গাড়ীৰ কেমেৰা এক্সেছ কৰিব।"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"গাড়ীৰ শক্তিৰ তথ্য এক্সেছ কৰিব"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"আপোনাৰ গাড়ীৰ শক্তি সম্পৰ্কীয় তথ্য এক্সেছ কৰিব।"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"গাড়ীখন আৰু কিমান সময়লৈ চলিব সেয়া মিলাওক"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"গাড়ীখন আৰু কিমান সময়লৈ চলিব তাৰ মানটো মিলাওক।"</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"গাড়ীৰ এইছভিএচি এক্সেছ কৰিব"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"আপোনাৰ গাড়ীৰ hvac এক্সেছ কৰিব।"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"গাড়ীৰ মাইলেজৰ তথ্য এক্সেছ কৰিব"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UXৰ সীমাবদ্ধতা কনফিগাৰ কৰক"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"AOAP ম’ডত থকা ইউএছবি ডিভাইচৰ লগত যোগাযোগ কৰিব পাৰে"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"কোনো এপক AOAP ম’ডত থকা ডিভাইচৰ লগত যোগাযোগ কৰাৰ অনুমতি দিয়ে"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant Awareness System পঢ়াৰ এক্সেছ"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Occupant Awareness Systemৰ স্থিতি পঢ়া আৰু ডেটা চিনাক্ত কৰাৰ অনুমতি দিয়ে"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Occupant Awareness Systemৰ লেখ নিয়ন্ত্ৰণ কৰক"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Occupant Awareness System চিনাক্তকৰণৰ লেখৰ আৰম্ভ কৰা আৰু বন্ধ কৰা কার্য নিয়ন্ত্ৰণ কৰাটোৰ অনুমতি দিয়ে"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"গাড়ীৰ ইনপুট সেৱা"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ইনপুট ইভেণ্ট নিয়ন্ত্ৰণ কৰিব"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN বাছ বিফল হৈছে"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"আপোনাৰ গাড়ীৰ ইঞ্জিনৰ সবিশেষ তথ্য এক্সেছ কৰিব।"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"গাড়ীৰ ইন্ধনৰ দৰ্জা আৰু চাৰ্জ প’ৰ্ট এক্সেছ কৰিব"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"গাড়ীৰ ইন্ধনৰ দৰ্জা আৰু চাৰ্জ প’ৰ্ট এক্সেছ কৰিব।"</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"গাড়ীৰ ইন্ধনৰ দৰ্জা আৰু চাৰ্জ প’ৰ্ট নিয়ন্ত্ৰণ কৰা"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"গাড়ীৰ ইন্ধনৰ দৰ্জা আৰু চাৰ্জ প’ৰ্ট নিয়ন্ত্ৰণ কৰা।"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"গাড়ী চিনাক্তকৰণৰ তথ্য পঢ়িব"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"গাড়ী চিনাক্তকৰণৰ তথ্য এক্সেছ কৰিব।"</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"গাড়ীৰ দৰ্জা নিয়ন্ত্ৰণ কৰিব"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"গাড়ীৰ আসন নিয়ন্ত্ৰণ কৰিব।"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"গাড়ীৰ মৌলিক তথ্যবোৰ এক্সেছ কৰিব"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"গাড়ীৰ মৌলিক তথ্যবোৰ এক্সেছ কৰিব।"</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"গাড়ীৰ বিক্ৰেতাৰ অনুমতি সম্পৰ্কীয় তথ্য এক্সেছ কৰক"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"গাড়ীৰ বিক্ৰেতাৰ অনুমতি সম্পৰ্কীয় তথ্য এক্সেছ কৰক।"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"গাড়ীৰ বাহ্যিক লাইটৰ স্থিতি পঢ়িব"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"গাড়ীৰ বাহ্যিক লাইটৰ স্থিতি এক্সেছ কৰিব।"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"গাড়ীৰ বাহ্যিক লাইট পঢ়িব"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"বিশ্বাসী ডিভাইচ পঞ্জীয়নৰ অনুমতি দিয়ক"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"বাহনৰ পৰীক্ষণ ম’ড নিয়ন্ত্ৰণ কৰক"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"বাহনৰ পৰীক্ষণ ম’ড নিয়ন্ত্ৰণ কৰক"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"গাড়ীৰ সুবিধাসমূহ সক্ষম অথবা অক্ষম কৰক"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"গাড়ীৰ সুবিধাসমূহ সক্ষম অথবা অক্ষম কৰক।"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"গাড়ীৰ ৱাচ্‌ডগ ব্যৱহাৰ কৰক"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"গাড়ীৰ ৱাচ্‌ডগ ব্যৱহাৰ কৰক।"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"মোৰ ডিভাইচ"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"অতিথি"</string>
 </resources>
diff --git a/service/res/values-az/strings.xml b/service/res/values-az/strings.xml
index 415a7a8..fbdd24c 100644
--- a/service/res/values-az/strings.xml
+++ b/service/res/values-az/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Avtomobilin kameralarına giriş."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"avtomobilin enerji məlumatlarına giriş"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Avtomobilin enerji məlumatlarına giriş."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"avtomobilin yürüş məsafəsi qalığını nizamlamaq"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Avtomobilin yürüş məsafəsi qalıq dəyərini nizamlamaq."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"avtomobilin HVAC məlumatlarına giriş"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Avtomobilin HVAC mexanizminə giriş."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"avtomobilin kilometraj məlumatlarına giriş"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX Məhdudiyyətlərinin Konfiqurasiyası"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"AOAP rejimində USB cihazı ilə əlaqə qurmaq"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"AOAP rejimində tətbiqin cihazla əlaqə qurmasına icazə verir"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Sərnişin Məlumatlılıq Sistemini Oxumaq üçün Giriş"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Sərnişin Məlumatlılıq Sisteminin vəziyyət və aşkarlama datasını oxumağa icazə verir"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Sərnişin Məlumatlılıq Sistemi Qrafikinə nəzarət"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Sərnişin Məlumatlılıq Sisteminin aşkarlama qrafikinin başladılması və dayandırılmasına nəzarətə icazə verir"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Avtomobil Daxiletmə Xidməti"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Daxiletmələri idarə etmək"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN idarəetmə mexanizmi uğursuz oldu"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Avtomobilin ətraflı mühərrik məlumatlarına giriş."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"avtomobilin yanacaq bölməsinin qapağı və enerji doldurma portuna giriş"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Avtomobilin yanacaq bölməsinin qapağı və enerji doldurma portuna giriş."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"avtomobilin yanacaq bölməsinin qapağı və enerji doldurma portuna nəzarət"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Avtomobilin yanacaq bölməsinin qapağı və enerji doldurma portuna nəzarət"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"avtomobilin identifikasiyasını oxumaq"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Avtomobilin identifikasiyasına giriş."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"avtomobilin qapılarını idarə etmək"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Avtomobilin oturacaqlarını idarə etmək."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"avtomobilin əsas məlumatlarına giriş"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Avtomobilin əsas məlumatlarına giriş."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"avtomobilin təchizatçı icazə məlumatına giriş"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Avtomobilin təchizatçı icazə məlumatına giriş."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"avtomobilin eksteryer işıqlarının vəziyyətini oxumaq"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Avtomobilin eksteryer işıqlarının vəziyyətinə giriş."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"avtomobilin eksteryer işıqları məlumatlarını oxumaq"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Güvənli cihaz qeydiyyatına icazə verin"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"avtomobilin sınaq rejimini idarə etmək"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"avtomobilin sınaq rejimini idarə etmək"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Avtomobilin xüsusiyyətlərini aktiv və ya deaktiv etmək"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Avtomobilin xüsusiyyətlərini aktiv və ya deaktiv etmək."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"avtomobil keşikçisindən istifadə edin"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Avtomobil keşikçisindən istifadə edin."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Cihazım"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Qonaq"</string>
 </resources>
diff --git a/service/res/values-b+sr+Latn/strings.xml b/service/res/values-b+sr+Latn/strings.xml
index 7656784..25bffaa 100644
--- a/service/res/values-b+sr+Latn/strings.xml
+++ b/service/res/values-b+sr+Latn/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Pristupi kamerama automobila."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"pristup podacima o energiji automobila"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Pristupi informacijama o energiji automobila."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"prilagođavanje preostalog dometa automobila"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Prilagođavanje vrednosti preostalog dometa automobila."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"pristup grejanju, ventilaciji i klimatizaciji automobila"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Pristupi grejanju, ventilaciji i klimatizaciji automobila"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"pristup podacima o kilometraži automobila"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfiguriše ograničenja KD-a"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Komunicira sa USB uređajem u režimu AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Dozvoljava aplikaciji komunikaciju sa uređajem u režimu AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Pristup za čitanje za Occupant Awareness System"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Omogućava čitanje podataka o statusu i otkrivanju za Occupant Awareness System"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Upravljanje grafikonom za Occupant Awareness System"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Omogućava pokretanje i zaustavljanje grafikona otkrivanja za Occupant Awareness System"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Usluga automobilskog unosa"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Upravlja događajima unosa"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Greška CAN magistrale"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Pristup detaljnim podacima o motoru automobila."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"pristup poklopcu rezervoara za gorivo i portu za punjenje"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Pristup poklopcu rezervoara za gorivo i portu za punjenje."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"upravljanje poklopcem rezervoara za gorivo i portom za punjenje"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Upravljanje poklopcem rezervoara za gorivo i portom za punjenje."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"čitanje podataka za identifikaciju automobila"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Pristup podacima za identifikaciju automobila."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"Kontrolisanje vrata automobila"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kontrolisanje sedišta u automobilu."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"pristup osnovnim podacima o automobilu"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Pristup osnovnim podacima o automobilu."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"pristup informacijama o dozvolama prodavca automobila"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Pristupa informacijama o dozvolama prodavca automobila."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"čitanje stanja spoljnih svetla automobila"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Pristup stanju spoljnih svetla automobila."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"čitanje statusa spoljnih svetla automobila"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Omogući registrovanje pouzdanih uređaja"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Kontrola režima za testiranje automobila"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Kontrola režima za testiranje automobila"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Omogućavanje ili onemogućavanje funkcija automobila"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Omogućavanje ili onemogućavanje funkcija automobila."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"koristi nadzorni tajmer automobila"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Koristi nadzorni tajmer automobila."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moj uređaj"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Gost"</string>
 </resources>
diff --git a/service/res/values-be/strings.xml b/service/res/values-be/strings.xml
index 60bc3a6..9df2dc5 100644
--- a/service/res/values-be/strings.xml
+++ b/service/res/values-be/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Доступ да камер аўтамабіля."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"дазволіць доступ да інфармацыі пра энергарэсурсы аўтамабіля"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Доступ да інфармацыі пра энергарэсурсы аўтамабіля."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"карэктаваць аўтамабільны прабег без дазапраўкі, які застаўся"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Карэктаваць значэнне аўтамабільнага прабегу без дазапраўкі, які застаўся."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"дазволіць доступ да сістэмы АВіК аўтамабіля"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Доступ да сістэмы АВіК аўтамабіля."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"дазволіць доступ да інфармацыі пра прабег аўтамабіля"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Наладжванне абмежаванняў UX"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Абменьвацца данымі з USB-прыладай у рэжыме AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Дазваляе праграме абменьвацца данымі з прыладай у рэжыме AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Доступ да счытвання даных сістэмы інфармавання пра пасажыра"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Дазваляе счытваць стан і даныя выяўлення для сістэмы інфармавання пра пасажыра"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Правяраць графік сістэмы інфармавання пра пасажыра"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Дазваляе кантраляваць запуск і прыпыненне графіка выяўлення для сістэмы інфармавання пра пасажыра"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Сэрвіс уводу аўтамабіля"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Магчымасць апрацоўваць падзеі ўводу"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-шына парушана"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Доступ да падрабязнай інфармацыі пра рухавік аўтамабіля."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"дазволіць доступ да лючка паліўнага бака і порта зарадкі аўтамабіля"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Доступ да лючка паліўнага бака і порта зарадкі аўтамабіля."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"правяраць лючок паліўнага бака і порт зарадкі аўтамабіля"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Правяраць лючок паліўнага бака і порт зарадкі аўтамабіля."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"счытваць ідэнтыфікацыйны нумар аўтамабіля"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Доступ да ідэнтыфікацыйнага нумара аўтамабіля."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"кіраваць дзвярыма аўтамабіля"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Рэгуляванне сядзенняў аўтамабіля."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"дазволіць доступ да асноўнай інфармацыі пра аўтамабіль"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Доступ да асноўнай інфармацыі пра аўтамабіль."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"доступ да інфармацыі пра дазволы пастаўшчыка аўтамабіля"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Доступ да інфармацыі пра дазволы пастаўшчыка аўтамабіля."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"атрымліваць інфармацыю пра стан знешніх асвятляльных прыбораў аўтамабіля"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Доступ да інфармацыі пра стан знешніх асвятляльных прыбораў аўтамабіля."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"атрымліваць інфармацыю са знешніх асвятляльных прыбораў аўтамабіля"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Дазволіць рэгістрацыю даверанай прылады"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Тэставы рэжым кіравання аўтамабілем"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Тэставы рэжым кіравання аўтамабілем"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Уключыць або выключыць функцыі аўтамабіля"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Уключыць або выключыць функцыі аўтамабіля."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"выкарыстанне вартавога таймера аўтамабіля"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Выкарыстанне вартавога таймера аўтамабіля."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Мая прылада"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Госць"</string>
 </resources>
diff --git a/service/res/values-bg/strings.xml b/service/res/values-bg/strings.xml
index afa35f3..e8be5e2 100644
--- a/service/res/values-bg/strings.xml
+++ b/service/res/values-bg/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Достъп до камерата или съответно камерите на автомобила ви."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"достъп до информацията за енергията на автомобила"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Достъп до информацията за енергията на автомобила."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"корекция на отсечката, която трябва да измине автомобилът"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Коригирайте стойността за отсечката, която трябва да измине автомобилът."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"достъп до ОВК системата на автомобила"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Достъп до ОВК системата на автомобила."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"достъп до информацията за километража на автомобила"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Конфигуриране на ограничения за ПРП"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Комуникиране с USB устройство в режим AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Разрешава на приложението да комуникира с устройство в режим AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Достъп за четене на системата за информираност на пътниците"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Разрешава четенето на състоянието и данните за установяване на системата за информираност на пътниците"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Управление на графиката за системата за информираност на пътниците"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Разрешава управлението на стартирането и спирането на графиката за установяване на системата за информираност на пътниците"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Автомобилна услуга за входящи данни"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Обработване на входящи събития"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Грешка в CAN шината"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Достъп до подробна информация за двигателя на автомобила."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"достъп до капака за резервоара и порта за зареждане на автомобила"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Достъп до капака за резервоара и порта за зареждане на автомобила."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"управление на капака за резервоара и порта за зареждане на автомобила"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Управление на капака за резервоара и порта за зареждане на автомобила."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"четене на идентификационните данни на автомобила"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Достъп до идентификационните данни на автомобила."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"контролиране на вратите на автомобила"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Контролиране на седалките на автомобила."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"достъп до основна информация за автомобила"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Достъп до основна информация за автомобила."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"достъп до информацията за разрешенията на автомобилния производител"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Достъп до информацията за разрешенията на автомобилния производител"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"четене на състоянието на външните светлини на автомобила"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Достъп до състоянието на външните светлини на автомобила."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"четене на външните светлини на автомобила"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Разрешаване на регистрирането на надеждно устройство"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Управление на тестовия режим на автомобила"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Управление на тестовия режим на автомобила"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Активиране или деактивиране на функциите на автомобила"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Активиране или деактивиране на функциите на автомобила."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"използване на защитения таймер на автомобила"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Използване на защитения таймер на автомобила."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Моето устройство"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Гост"</string>
 </resources>
diff --git a/service/res/values-bn/strings.xml b/service/res/values-bn/strings.xml
index 32f6df9..2a2dd4f 100644
--- a/service/res/values-bn/strings.xml
+++ b/service/res/values-bn/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"আপনার গাড়ির ক্যামেরা(গুলি) অ্যাক্সেস করা।"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"আপনার গাড়ির এনার্জির তথ্য অ্যাক্সেস করা"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"আপনার গাড়ির এনার্জি তথ্য অ্যাক্সেস করা।"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"গাড়ি আর কত সময় চলবে তা অ্যাডজাস্ট করতে পারবে"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"গাড়ি আর কত সময় চলবে তার মান অ্যাডজাস্ট করতে পারবে।"</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"গাড়ির HVAC অ্যাক্সেস করা"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"আপনার গাড়ির HVAC অ্যাক্সেস করা।"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"গাড়ির মাইলেজ সংক্রান্ত তথ্য অ্যাক্সেস করা"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX বিধিনিষেধ কনফিগার করা"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"AOAP মোডে ইউএসবি ডিভাইসের সাথে কানেক্ট করুন"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"AOAP মোডে ডিভাইসের সাথে অ্যাপকে কানেক্ট করতে অনুমতি দিন"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"অকুপেন্ট সচেতনতা সিস্টেম পড়ার অ্যাক্সেস করা"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"অকুপেন্ট সচেতনতা সিস্টেমের জন্য পড়ার স্ট্যাটাস এবং ডিটেকশন ডেটার অনুমতি দেওয়া"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"অকুপেন্ট সচেতনতা সিস্টেম গ্রাফ কন্ট্রোল করা"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"অকুপেন্ট সচেতনতা সিস্টেম ডিটেকশন গ্রাফের চালু এবং বন্ধ করার ফিচার নিয়ন্ত্রণে অনুমতি দেওয়া"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"গাড়ির ইনপুট সার্ভিস"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ইনপুট ইভেন্ট হ্যান্ডেল করা"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN বাস কাজ করছে না"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"আপনার গাড়ির ইঞ্জিনের বিশদ তথ্য অ্যাক্সেস করা।"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"গাড়ির জ্বালানীর চেম্বারের ঢাকনা ও চার্জ পোর্ট অ্যাক্সেস করা"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"গাড়ির জ্বালানীর চেম্বারের ঢাকনা ও চার্জ পোর্ট অ্যাক্সেস করা।"</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"গাড়ির জ্বালানীর চেম্বারের ঢাকনা ও চার্জ পোর্ট নিয়ন্ত্রণ করা"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"গাড়ির জ্বালানীর চেম্বারের ঢাকনা ও চার্জ পোর্ট নিয়ন্ত্রণ করা।"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"গাড়ির শনাক্তকরণ সংক্রান্ত তথ্য দেখা"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"গাড়ির শনাক্তকরণ সংক্রান্ত তথ্য অ্যাক্সেস করা।"</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"গাড়ির দরজা নিয়ন্ত্রণ করা"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"গাড়ির সিট নিয়ন্ত্রণ করা।"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"গাড়ির সাধারণ তথ্য অ্যাক্সেস করা"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"গাড়ির সাধারণ তথ্য অ্যাক্সেস করা।"</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"গাড়ির ভেন্ডরের অনুমতি সম্পর্কে তথ্য অ্যাক্সেস করুন"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"গাড়ির ভেন্ডরের অনুমতি সম্পর্কে তথ্য অ্যাক্সেস করুন।"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"গাড়ির এক্সটিরিয়র বা বাইরের দিকের লাইটের স্ট্যাটাস দেখা"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"গাড়ির এক্সটিরিয়র বা বাইরের দিকের লাইটের স্ট্যাটাস অ্যাক্সেস করা।"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"গাড়ির এক্সটিরিয়র বা বাইরের দিকের লাইট দেখা"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"বিশ্বস্ত ডিভাইস নথিভুক্ত করার অনুমতি দিন"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"গাড়ির টেস্ট মোড নিয়ন্ত্রণ করুন"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"গাড়ির টেস্ট মোড নিয়ন্ত্রণ করুন"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"গাড়ির ফিচার চালু বা বন্ধ করুন"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"গাড়ির ফিচার চালু বা বন্ধ করুন।"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"গাড়ির ওয়াচডগ ফিচারটি ব্যবহার করুন"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"গাড়ির ওয়াচডগ ফিচারটি ব্যবহার করুন।"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"আমার ডিভাইস"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"অতিথি"</string>
 </resources>
diff --git a/service/res/values-bs/strings.xml b/service/res/values-bs/strings.xml
index d21a8aa..a8779ca 100644
--- a/service/res/values-bs/strings.xml
+++ b/service/res/values-bs/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Pristupiti kameri(ama) automobila."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"pristupiti informacijama o energiji automobila"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Pristupiti informacijama o energiji automobila."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"podesi preostali domet automobila"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Podesi vrijednost preostalog dometa automobila."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"pristupiti grijanju, ventilaciji i klimatizaciji automobila"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Pristupiti grijanju, ventilaciji i klimatizaciji automobila."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"pristupiti informacijama o pređenim kilometrima automobila"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfigurirajte ograničenja IK-a"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Komunicirati s USB uređajem u AOAP načinu"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Omogućava aplikaciji da komunicira s uređajem u AOAP načinu"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Pristup očitavanju za Sistem informiranosti o broju prisutnih"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Omogućava očitavanje statusa i otkrivanje podataka za Sistem informiranosti o broju prisutnih"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontroliranje grafikona Sistema informiranosti o broju prisutnih"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Omogućava kontroliranje početka i zaustavljanja grafikona otkrivanja Sistema informiranosti o broju prisutnih"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Usluga unosa za automobil"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Rukovati događajima unosa"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Greška CAN busa"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Pristupiti detaljnim informacijama o motoru automobila."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"pristupiti poklopcu rezervoara za gorivo i priključku za punjenje"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Pristupiti poklopcu rezervoara za gorivo i priključku za punjenje."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"kontrolirati poklopac rezervoara za gorivo i priključak za punjenje"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Kontroliranje poklopca rezervoara za gorivo i priključka za punjenje."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"očitati identifikaciju automobila"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Pristupiti identifikaciji automobila."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"kontrolirati vrata automobila"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kontrolirati sjedala automobila."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"pristupiti osnovnim podacima automobila"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Pristupiti osnovnim informacijama automobila."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"pristup informacijama o odobrenjima trgovca automobilima"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Pristup informacijama o odobrenjima trgovca automobilima"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"očitati stanje vanjskih svjetala automobila"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Pristupiti podacima o stanju vanjskih svjetala automobila."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"očitati informacije o vanjskim svjetlima automobila"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Dozvoli prijavu pouzdanih uređaja"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Kontroliranje testnim načinom automobila"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Kontroliranje testnim načinom automobila"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Omogućavanje ili onemogućavanje funkcija automobila"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Omogućavanje ili onemogućavanje funkcija automobila."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"koristi čuvara automobila"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Koristi čuvara automobila."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moj uređaj"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Gost"</string>
 </resources>
diff --git a/service/res/values-ca/strings.xml b/service/res/values-ca/strings.xml
index 209e8f5..6bf7504 100644
--- a/service/res/values-ca/strings.xml
+++ b/service/res/values-ca/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Accedir a la càmera del cotxe"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"accedeix a la informació sobre l\'energia del cotxe"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Accedir a la informació sobre l\'energia del cotxe"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"ajustar l\'autonomia restant del cotxe"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Ajustar el valor de l\'autonomia restant del cotxe."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"accedir al sistema de calefacció, ventilació i aire condicionat del cotxe"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Accedir al sistema de calefacció, ventilació i aire condicionat del cotxe"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"accedeix a la informació sobre el quilometratge del cotxe"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurar les restriccions de l\'experiència d\'usuari"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Comunica amb un dispositiu USB al mode AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Permet que una aplicació es comuniqui amb un dispositiu amb el mode AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Accés de lectura al Sistema de detecció d\'ocupants"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Permet llegir les dades de detecció i d\'estat del Sistema de detecció d\'ocupants"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Controlar el gràfic del Sistema de detecció d\'ocupants"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Permet controlar l\'inici i la pausa del gràfic de detecció del Sistema de detecció d\'ocupants"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Servei d\'entrada del cotxe"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gestionar els esdeveniments d\'entrada"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Ha fallat el bus CAN"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Accedeix a la informació detallada sobre el motor del cotxe."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"accedeix a la porta del combustible i al port de càrrega del cotxe"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Accedeix a la porta del combustible i al port de càrrega del cotxe."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"controlar la tapa del dipòsit de combustible i el port de càrrega del cotxe"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Controlar la tapa del dipòsit de combustible i el port de càrrega del cotxe."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"llegeix la identificació del cotxe"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Accedeix a la identificació del cotxe."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"controla les portes del cotxe"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Controla els seients del cotxe."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"accedeix a la informació bàsica del cotxe"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Accedeix a la informació bàsica del cotxe."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"accedeix a la informació sobre permisos del fabricant del cotxe"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Accedeix a la informació sobre permisos del fabricant del cotxe."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"llegeix l\'estat dels llums exteriors del cotxe"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Accedeix a l\'estat dels llums exteriors del cotxe."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"llegeix els llums exteriors del cotxe"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Permet el registre de dispositius de confiança"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Controla el mode de proves del cotxe"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Controla el mode de proves del cotxe"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Activa o desactiva les funcions del cotxe"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Activa o desactiva les funcions del cotxe."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"utilitza el temporitzador de vigilància del cotxe"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Utilitza el temporitzador de vigilància del cotxe."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"El meu dispositiu"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Convidat"</string>
 </resources>
diff --git a/service/res/values-cs/strings.xml b/service/res/values-cs/strings.xml
index 432b1e2..4db0481 100644
--- a/service/res/values-cs/strings.xml
+++ b/service/res/values-cs/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Přístup ke kamerám auta."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"přístup k údajům o energii auta"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Přístup k údajům o energii auta."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"úprava dojezdu auta – zbytek"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Úprava zbývající hodnoty dojezdu auta."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"přístup k topení, větrání a klimatizaci auta"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Přístup k systému HVAC auta."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"přístup k ujetým kilometrům auta"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfigurace omezení uživatelského prostředí"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Komunikace se zařízením USB v režimu AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Umožňuje aplikaci komunikovat se zařízením v režimu AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Systému detekce uživatele – přístup ke čtení"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Umožňuje čtení stavu a dat ze systému detekce uživatele"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Systému detekce uživatele – ovládání grafu"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Umožňuje ovládat zahájení a ukončení grafu systému detekce uživatele"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Služba vstupu auta"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Zpracování vstupních událostí"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Sběrnice CAN selhala"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Přístup k podrobným údajům o motoru auta."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"přístup ke vstupu do nádrže a nabíjecímu portu auta"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Přístup ke vstupu do nádrže a nabíjecímu portu auta."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"přístup ke vstupu do nádrže a nabíjecímu portu auta"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Přístup ke vstupu do nádrže a nabíjecímu portu auta."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"čtení identifikace auta"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Přístup k identifikaci auta."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"ovládání dveří auta"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Ovládání autosedaček."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"přístup k základním informacím o autu"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Přístup k základním informacím o autu."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"přístup k informacím o oprávněních dodavatele auta"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Přístup k informacím o oprávněních dodavatele auta."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"zjištění stavu vnějších světel auta"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Přístup ke stavu vnějších světel auta."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ovládání vnějších světel auta"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Povolit registraci důvěryhodného zařízení"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Ovládání testovacího režimu auta"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Ovládání testovacího režimu auta"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Zapnout nebo vypnout funkce auta"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Zapnout nebo vypnout funkce auta."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"používat sledování auta"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Používat sledování auta."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moje zařízení"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Host"</string>
 </resources>
diff --git a/service/res/values-da/strings.xml b/service/res/values-da/strings.xml
index 045fb09..40b134c 100644
--- a/service/res/values-da/strings.xml
+++ b/service/res/values-da/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Få adgang til bilens kameraer."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"få adgang til oplysninger om bilens energiforbrug"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Få adgang til oplysninger om bilens energiforbrug"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"juster bilens resterende afstand."</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Juster værdien for bilens resterende afstand."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"få adgang til bilens ventilation"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Få adgang til bilens ventilationssystem."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"få adgang til oplysninger om bilens kilometertal"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfigurer UX-begrænsninger"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Kommunikere med en USB-enhed i AOAP-tilstand"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Tillader, at en app kan kommunikere med en enhed i AOAP-tilstand"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Adgang til aflæsning af Occupant Awareness System"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Giver mulighed for at aflæse status og registreringsdata for Occupant Awareness System"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Styr grafen for Occupant Awareness System"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Giver mulighed for at starte og stoppe registreringsgrafen for Occupant Awareness System"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Bilens inputservice"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Håndter input"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-bus (Controller Area Network) mislykkedes"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Få adgang til detaljerede oplysninger om bilens motor."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"få adgang til bilens tankdæksel og opladningsport"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Få adgang til bilens tankdæksel og opladningsport."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"styr bilens tankdæksel og opladningsport"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Styr bilens tankdæksel og opladningsport."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"tjekke bilens identifikation"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Få adgang til bilens identifikation."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"styre bilens døre"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Styr bilens sæder."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"få adgang til grundlæggende oplysninger om bilen"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Få adgang til grundlæggende oplysninger om bilen."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"få adgang til oplysninger om tilladelser for bilens producent"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Få adgang til oplysninger om tilladelser for bilens producent."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"tjekke status for bilens lygter"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Se status for bilens lygter."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"tjekke bilens lygter"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Tillad tilmelding af godkendt enhed"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Styr bilens testtilstand"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Styr bilens testtilstand"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Aktivér eller deaktiver bilens funktioner"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Aktivér eller deaktiver bilens funktioner."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"brug bilens watchdog"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Brug bilens watchdog."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Min enhed"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Gæst"</string>
 </resources>
diff --git a/service/res/values-de/strings.xml b/service/res/values-de/strings.xml
index 7fa9aad..6eade76 100644
--- a/service/res/values-de/strings.xml
+++ b/service/res/values-de/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Auf Autokamera(s) zugreifen."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"auf Energieinformationen des Autos zuzugreifen"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Auf Energieinformationen des Autos zugreifen."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"Strecke anpassen, die das Auto noch fahren kann"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Wert für die Strecke anpassen, die das Auto noch fahren kann."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"auf die Klimaanlage zuzugreifen"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Auf Klimaanlage des Autos zugreifen."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"auf den Kilometerstand zuzugreifen"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX-Einschränkungen konfigurieren"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Mit USB-Gerät im AOAP-Modus kommunizieren"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Ermöglicht einer App, mit einem Gerät im AOAP-Modus zu kommunizieren"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant Awareness System – Lesezugriff"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Berechtigung, die Status- und Erkennungsdaten des Occupant Awareness System zu lesen"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Occupant Awareness System Graph steuern"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Berechtigung, den Start- und Stoppvorgang des Occupant Awareness System-Erkennungsgraphen zu steuern"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Eingabedienst für das Auto"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Eingabe-Ereignisse verwalten"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-Bus ausgefallen"</string>
@@ -71,10 +77,10 @@
     <string name="exit_button" msgid="5829638404777671253">"Zurück"</string>
     <string name="exit_button_close_application" msgid="8824289547809332460">"App schließen"</string>
     <string name="exit_button_go_back" msgid="3469083862100560326">"Zurück"</string>
-    <string name="car_permission_label_diag_read" msgid="7248894224877702604">"Fehlerberichte zu lesen"</string>
-    <string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Fehlerberichte des Autos lesen."</string>
-    <string name="car_permission_label_diag_clear" msgid="4783070510879698157">"Fehlerberichte zu löschen"</string>
-    <string name="car_permission_desc_diag_clear" msgid="7453222114866042786">"Fehlerberichte des Autos löschen."</string>
+    <string name="car_permission_label_diag_read" msgid="7248894224877702604">"Diagnosedaten zu lesen"</string>
+    <string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Diagnosedaten des Autos lesen."</string>
+    <string name="car_permission_label_diag_clear" msgid="4783070510879698157">"Diagnosedaten zu löschen"</string>
+    <string name="car_permission_desc_diag_clear" msgid="7453222114866042786">"Diagnosedaten des Autos löschen."</string>
     <string name="car_permission_label_vms_publisher" msgid="3049934078926106641">"VMS-Herausgeber"</string>
     <string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS-Meldungen senden"</string>
     <string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS-Abonnent"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Auf detaillierte Motorinformationen zugreifen."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"auf die Tankklappe und die Ladebuchse zuzugreifen"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Auf Tankklappe und Ladebuchse zugreifen."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"Tankklappe und Ladebuchse steuern"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Tankklappe und Ladebuchse steuern."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"die Fahrzeug-Identifizierungsnummer zu lesen"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Auf Fahrzeug-Identifizierungsnummer zugreifen."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"die Autotüren zu steuern"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Autositze steuern."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"auf grundlegende Fahrzeuginformationen zuzugreifen"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Auf grundlegende Fahrzeuginformationen zugreifen."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"Auf Informationen zu Berechtigungen des Herstellers zugreifen"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Auf Informationen zu Berechtigungen des Herstellers zugreifen."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"Informationen zum Zustand der Außenbeleuchtung zu lesen"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Auf Informationen zum Zustand der Außenbeleuchtung zugreifen."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"Informationen zur Außenbeleuchtung zu lesen"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Registrieren eines vertrauenswürdigen Geräts erlauben"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Testmodus des Autos steuern"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Testmodus des Autos steuern"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Funktionen des Autos aktivieren oder deaktivieren"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Funktionen des Autos aktivieren oder deaktivieren."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"Watchdog im Auto verwenden"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Watchdog im Auto verwenden."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mein Gerät"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Gast"</string>
 </resources>
diff --git a/service/res/values-el/strings.xml b/service/res/values-el/strings.xml
index 0a61aff..3d4fc20 100644
--- a/service/res/values-el/strings.xml
+++ b/service/res/values-el/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Πρόσβαση στις κάμερες του αυτοκινήτου σας."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"πρόσβαση στις πληροφορίες ενέργειας του αυτοκινήτου"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Πρόσβαση σε πληροφορίες ενέργειας του αυτοκινήτου σας."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"προσαρμόστε το εύρος αυτοκινήτου που απομένει"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Προσαρμόστε την τιμή του εύρους αυτοκινήτου που απομένει."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"πρόσβαση στο σύστημα θέρμανσης-αερισμού-κλιματισμού του αυτοκινήτου"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Πρόσβαση στο σύστημα θέρμανσης, αερισμού, και κλιματισμού του αυτοκινήτου σας."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"πρόσβαση στις πληροφορίες διανυθείσας απόστασης του αυτοκινήτου"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Διαμόρφωση περιορισμών εμπειρίας χρήστη"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Επικοινωνία με συσκευή USB σε λειτουργία AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Επιτρέπει σε μια εφαρμογή να επικοινωνεί με μια συσκευή σε λειτουργία AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Πρόσβαση ανάγνωσης συστήματος ελέγχου συμπεριφοράς οδηγού"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Επιτρέπει την ανάγνωση των δεδομένων κατάστασης και ανίχνευσης του συστήματος ελέγχου συμπεριφοράς οδηγού."</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Έλεγχος γραφήματος συστήματος ελέγχου συμπεριφοράς οδηγού"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Επιτρέπει τον έλεγχο της έναρξης και της διακοπής του γραφήματος ανίχνευσης του συστήματος ελέγχου συμπεριφοράς οδηγού."</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Υπηρεσία εισόδου αυτοκινήτου"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Χειρισμός συμβάντων εισόδου"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Αποτυχία διαύλου CAN"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Πρόσβαση σε λεπτομερείς πληροφορίες του κινητήρα του αυτοκινήτου."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"πρόσβαση στο πορτάκι του ρεζερβουάρ και της θύρας φόρτισης"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Πρόσβαση στη θύρα καυσίμου και το πορτάκι του ρεζερβουάρ."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"έλεγχος για τη θύρα καυσίμου και το πορτάκι του ρεζερβουάρ."</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Έλεγχος για τη θύρα καυσίμου και το πορτάκι του ρεζερβουάρ."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"παρακολούθηση στοιχείων αυτοκινήτου"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Πρόσβαση στα στοιχεία του αυτοκινήτου."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"έλεγχος θυρών αυτοκινήτου"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Έλεγχος καθισμάτων αυτοκινήτου."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"πρόσβαση στις βασικές πληροφορίες του αυτοκινήτου"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Πρόσβαση σε βασικές πληροφορίες του αυτοκινήτου."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"πρόσβαση στις πληροφορίες άδειας πωλητή του αυτοκινήτου"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Πρόσβαση στις πληροφορίες άδειας πωλητή του αυτοκινήτου."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"παρακολούθηση κατάστασης εξωτερικών φώτων του αυτοκινήτου"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Πρόσβαση στην κατάσταση εξωτερικών φώτων του αυτοκινήτου."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"παρακολούθηση εξωτερικών φώτων του αυτοκινήτου"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Να επιτρέπεται η εγγραφή αξιόπιστης συσκευής"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Έλεγχος της λειτουργίας δοκιμής του αυτοκινήτου"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Έλεγχος της λειτουργίας δοκιμής του αυτοκινήτου"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Ενεργοποίηση ή απενεργοποίηση των λειτουργιών του αυτοκινήτου."</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Ενεργοποίηση ή απενεργοποίηση των λειτουργιών του αυτοκινήτου."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"χρήση watchdog αυτοκινήτου"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Χρήση watchdog αυτοκινήτου."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Η συσκευή μου"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Επισκέπτης"</string>
 </resources>
diff --git a/service/res/values-en-rAU/strings.xml b/service/res/values-en-rAU/strings.xml
index cbd442d..cae8100 100644
--- a/service/res/values-en-rAU/strings.xml
+++ b/service/res/values-en-rAU/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Access your car’s camera(s)."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"access car’s energy information"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Access your car’s energy information."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"adjust car’s range remaining"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Adjust car’s range remaining value."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"access car’s hvac"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Access your car’s HVAC."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"access car’s mileage information"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configure UX restrictions"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Communicate with USB device in AOAP mode"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Allows an app to communicate with a device in AOAP mode"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant awareness system read access"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Allows reading status and detection data for occupant awareness system"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Control occupant awareness system graph"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Allows controlling the start and stop of the occupant awareness system detection graph"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Car input service"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Handle input events"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus failed"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Access your car’s detailed engine information."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"access car’s fuel door and charge port"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Access car’s fuel door and charge port."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"control car’s fuel door and charge port"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Control car’s fuel door and charge port."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"read car’s identification"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Access car’s identification."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"control car’s doors"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Control car’s seats."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"access car’s basic information"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Access car’s basic information."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"access car’s vendor permission information"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Access car’s vendor permission information."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"read car’s exterior lights state"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Access car’s exterior lights state."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"read car’s exterior lights"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Allow Trusted Device Enrollment"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Control car’s test mode"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Control car’s test mode"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Enable or disable car’s features"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Enable or disable car’s features."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"use car watchdog"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Use car watchdog."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Guest"</string>
 </resources>
diff --git a/service/res/values-en-rCA/strings.xml b/service/res/values-en-rCA/strings.xml
index cbd442d..cae8100 100644
--- a/service/res/values-en-rCA/strings.xml
+++ b/service/res/values-en-rCA/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Access your car’s camera(s)."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"access car’s energy information"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Access your car’s energy information."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"adjust car’s range remaining"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Adjust car’s range remaining value."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"access car’s hvac"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Access your car’s HVAC."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"access car’s mileage information"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configure UX restrictions"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Communicate with USB device in AOAP mode"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Allows an app to communicate with a device in AOAP mode"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant awareness system read access"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Allows reading status and detection data for occupant awareness system"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Control occupant awareness system graph"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Allows controlling the start and stop of the occupant awareness system detection graph"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Car input service"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Handle input events"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus failed"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Access your car’s detailed engine information."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"access car’s fuel door and charge port"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Access car’s fuel door and charge port."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"control car’s fuel door and charge port"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Control car’s fuel door and charge port."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"read car’s identification"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Access car’s identification."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"control car’s doors"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Control car’s seats."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"access car’s basic information"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Access car’s basic information."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"access car’s vendor permission information"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Access car’s vendor permission information."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"read car’s exterior lights state"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Access car’s exterior lights state."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"read car’s exterior lights"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Allow Trusted Device Enrollment"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Control car’s test mode"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Control car’s test mode"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Enable or disable car’s features"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Enable or disable car’s features."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"use car watchdog"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Use car watchdog."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Guest"</string>
 </resources>
diff --git a/service/res/values-en-rGB/strings.xml b/service/res/values-en-rGB/strings.xml
index cbd442d..cae8100 100644
--- a/service/res/values-en-rGB/strings.xml
+++ b/service/res/values-en-rGB/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Access your car’s camera(s)."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"access car’s energy information"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Access your car’s energy information."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"adjust car’s range remaining"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Adjust car’s range remaining value."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"access car’s hvac"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Access your car’s HVAC."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"access car’s mileage information"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configure UX restrictions"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Communicate with USB device in AOAP mode"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Allows an app to communicate with a device in AOAP mode"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant awareness system read access"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Allows reading status and detection data for occupant awareness system"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Control occupant awareness system graph"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Allows controlling the start and stop of the occupant awareness system detection graph"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Car input service"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Handle input events"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus failed"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Access your car’s detailed engine information."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"access car’s fuel door and charge port"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Access car’s fuel door and charge port."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"control car’s fuel door and charge port"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Control car’s fuel door and charge port."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"read car’s identification"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Access car’s identification."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"control car’s doors"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Control car’s seats."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"access car’s basic information"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Access car’s basic information."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"access car’s vendor permission information"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Access car’s vendor permission information."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"read car’s exterior lights state"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Access car’s exterior lights state."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"read car’s exterior lights"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Allow Trusted Device Enrollment"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Control car’s test mode"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Control car’s test mode"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Enable or disable car’s features"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Enable or disable car’s features."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"use car watchdog"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Use car watchdog."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Guest"</string>
 </resources>
diff --git a/service/res/values-en-rIN/strings.xml b/service/res/values-en-rIN/strings.xml
index cbd442d..cae8100 100644
--- a/service/res/values-en-rIN/strings.xml
+++ b/service/res/values-en-rIN/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Access your car’s camera(s)."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"access car’s energy information"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Access your car’s energy information."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"adjust car’s range remaining"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Adjust car’s range remaining value."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"access car’s hvac"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Access your car’s HVAC."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"access car’s mileage information"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configure UX restrictions"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Communicate with USB device in AOAP mode"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Allows an app to communicate with a device in AOAP mode"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant awareness system read access"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Allows reading status and detection data for occupant awareness system"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Control occupant awareness system graph"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Allows controlling the start and stop of the occupant awareness system detection graph"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Car input service"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Handle input events"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus failed"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Access your car’s detailed engine information."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"access car’s fuel door and charge port"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Access car’s fuel door and charge port."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"control car’s fuel door and charge port"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Control car’s fuel door and charge port."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"read car’s identification"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Access car’s identification."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"control car’s doors"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Control car’s seats."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"access car’s basic information"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Access car’s basic information."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"access car’s vendor permission information"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Access car’s vendor permission information."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"read car’s exterior lights state"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Access car’s exterior lights state."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"read car’s exterior lights"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Allow Trusted Device Enrollment"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Control car’s test mode"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Control car’s test mode"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Enable or disable car’s features"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Enable or disable car’s features."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"use car watchdog"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Use car watchdog."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Guest"</string>
 </resources>
diff --git a/service/res/values-en-rXC/strings.xml b/service/res/values-en-rXC/strings.xml
index 38dea76..840f717 100644
--- a/service/res/values-en-rXC/strings.xml
+++ b/service/res/values-en-rXC/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‎‏‏‏‎‎‏‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‏‏‎‎‏‏‏‏‎‏‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎Access your car’s camera(s).‎‏‎‎‏‎"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎‎‏‏‎‎‎‎‎‎‏‏‏‎‎‎‏‎‏‎‏‏‏‏‎‏‎‎‏‎‎‏‎‎‎‏‏‏‏‎‏‏‎‎access car’s energy information‎‏‎‎‏‎"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‎‏‎‏‎‎‏‏‎‏‏‏‏‎‎‏‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‏‎‎‏‏‏‏‎Access your car’s energy information.‎‏‎‎‏‎"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‎‏‎‎‏‏‎‏‏‎‎‎‏‎‎‏‎‎‏‎‎‏‏‎‏‏‎‎‏‏‎‎‏‏‎‎‎‏‏‏‏‏‎‎‎‎‎‎‏‎‏‎‎adjust car’s range remaining‎‏‎‎‏‎"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‎‎‎‎‏‏‎‎‎‎‏‎‏‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‏‏‎‏‏‎‎‎‏‏‎‎‏‏‎‎‏‏‎‎‎‏‎Adjust car’s range remaining value.‎‏‎‎‏‎"</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‎‏‏‏‏‎‎‏‎‎‎‎‏‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‎‎‏‏‎‏‏‏‎‏‏‏‎‎‎‏‎‏‎‏‎‎‎‏‏‎access car’s hvac‎‏‎‎‏‎"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‏‏‎‎‏‏‎‏‏‎‏‎‎‎‎‎‎‎‏‎‎‎‏‏‏‎‎‏‎‏‏‎‏‏‎‎‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‏‎Access your car’s hvac.‎‏‎‎‏‎"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‎‎‏‎‏‏‏‎‏‏‎‎‎‎‏‎‏‏‎‏‏‎‏‎‎‏‎‎‏‎‏‏‏‏‎‏‎‏‏‏‎access car’s mileage information‎‏‎‎‏‎"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‎‎‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‎‎‎‏‏‏‎‏‎‎‎‏‎Configure UX Restrictions‎‏‎‎‏‎"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‎‎‏‎‏‎‎‏‎‏‎‎‏‎‏‎‎‏‏‏‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎‏‏‎‏‎‎‎Communicate with USB device in AOAP mode‎‏‎‎‏‎"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‏‎‏‏‏‎‏‏‎‎‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‏‎‎‏‎‏‎‏‏‎‏‏‎‎‏‎‏‎‏‎‎Allows an app to communicate with a device in AOAP mode‎‏‎‎‏‎"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‏‏‎‏‏‏‏‎‏‏‎‏‏‏‏‎‏‎‎‏‏‏‏‎‏‎‏‏‏‏‎‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‏‎‏‏‎‎Occupant Awareness System Read Access‎‏‎‎‏‎"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‏‎‎‎‎‏‎‏‎‎‎‎‎‎‏‎‎‏‏‏‏‎‎‎‎‎‎‏‏‎‏‎‏‎‎‎‏‎‏‎‎Allows reading status and detection data for Occupant Awareness System‎‏‎‎‏‎"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‎‏‎‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‎‏‏‏‎‏‏‎‏‎‏‎‎‏‎‎‎‎‎‎‎‏‏‏‎‎Control Occupant Awareness System Graph‎‏‎‎‏‎"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‏‎‏‏‏‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‏‎‎‎‏‎‎‎‏‏‎‏‏‎‎‎‏‏‏‎Allows controlling the start and stopping of the Occupant Awareness System detection graph‎‏‎‎‏‎"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‎‎‏‎‎‏‎‏‎‎‏‏‎‎‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‏‎‏‎‏‎‏‏‎‎Car Input Service‎‏‎‎‏‎"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‎‏‏‏‎‎‎‏‎‏‏‏‎‎‏‎‎‏‏‎‎‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎Handle input events‎‏‎‎‏‎"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‎‏‎‎‎‎‏‎‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‏‎‎‏‏‏‎‎‏‎‏‏‎‏‎‏‎‏‎‏‎‎‎‎‎‏‎‏‎‎CAN bus failed‎‏‎‎‏‎"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‏‏‏‎‎‎‎‏‏‎‏‎‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‏‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‎‎Access your car’s detailed engine information.‎‏‎‎‏‎"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‎‎‎‎‏‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‎‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‏‏‎‏‏‏‏‏‏‎‎access car’s fuel door and charge port‎‏‎‎‏‎"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‏‎‎‎‏‏‎‎‏‏‎‎‎‏‏‏‏‏‏‎‎‏‎‎‏‎‏‏‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‎‏‎‎‎‏‎‏‎Access car’s fuel door and charge port.‎‏‎‎‏‎"</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‎‎‎‏‏‎‏‎‎‎‎‏‏‎‎‏‏‎‏‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‏‏‎control car’s fuel door and charge port‎‏‎‎‏‎"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‏‎‏‎‎‎‏‏‎‏‏‏‏‎‏‎‏‎‏‏‏‎‎‎‏‎‏‏‎‏‏‎‎‎‏‏‎‎‎‏‎‎‎‏‏‎‏‎‎‏‎‏‏‎Control car’s fuel door and charge port.‎‏‎‎‏‎"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‎‏‎‏‎‏‎‏‎‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‏‏‏‎‏‏‏‎‏‏‎‏‏‎‏‎‏‏‎‎‏‏‏‏‏‏‏‎‎read car’s identification‎‏‎‎‏‎"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‏‎‏‎‏‏‎‏‎‏‎‎‏‎‎‏‎‎‎‎‎‏‎‎‎‏‎‎‏‏‎‎‏‏‎Access car’s identification.‎‏‎‎‏‎"</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‏‎‏‎‎‎‎‎‎‏‎‎‏‎‏‏‎‏‏‏‎‎‏‏‏‏‎‏‏‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‏‏‎‏‎‎‎control car’s doors‎‏‎‎‏‎"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‏‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‏‎‎‎‏‏‎Control car’s seats.‎‏‎‎‏‎"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‏‎‏‎‎‎‏‏‏‎‎‏‎‏‎‏‎‎‏‏‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‎‎‎‎‎‎‏‏‎‏‏‎access car’s basic information‎‏‎‎‏‎"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‎‏‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‏‎‏‏‏‏‏‎‏‎‏‎Access car’s basic information.‎‏‎‎‏‎"</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‎‏‏‎‏‏‏‎‏‏‎‎‏‎‏‏‏‏‏‎‎‎‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‎access car’s vendor permission information‎‏‎‎‏‎"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‏‎‎‎‏‎‎‎‎‎‎‏‎‏‏‎‏‏‏‎‏‎‏‎‎‎‎‎‎‏‏‎‏‏‎‎‏‏‏‎‎‏‏‏‎‎‏‏‏‎‎Access car’s vendor permission information.‎‏‎‎‏‎"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‏‏‎‎‏‏‎‎‎‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‎‏‎‎‏‎‎‏‏‎‏‏‏‏‎‎read car’s exterior lights state‎‏‎‎‏‎"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‏‎‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‏‏‏‎‎‏‏‏‎‎‎‎‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎Access car’s exterior lights state.‎‏‎‎‏‎"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‎‎‎‎‏‎‎‎‏‏‎‏‎‎‎‏‎‏‏‎‎‏‎‏‏‎‎‎‏‏‏‏‎‏‎‏‎‎‏‏‎‏‎read car’s exterior lights‎‏‎‎‏‎"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‎‎‏‎‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‎‏‎‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‎‎‎‎‎‏‏‎‏‎‏‎‏‎‎Allow Trusted Device Enrollment‎‏‎‎‏‎"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‏‏‏‏‎‎‏‎‎‏‎‎‎‏‎‎‏‎‏‎‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎‏‎‏‎‏‏‎‎‎‏‎‎‎Control car’s test mode‎‏‎‎‏‎"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‏‎‎‎‏‎‏‏‏‎‎‏‏‏‏‎‎‎‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‏‎‎‏‏‎Control car’s test mode‎‏‎‎‏‎"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‎‎‏‎‏‎‎‎‏‎‏‏‏‎‏‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‎‏‏‏‏‎‎Enable or disable car’s features‎‏‎‎‏‎"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‏‏‏‏‎‎‎‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎‏‏‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎Enable or disable car’s features.‎‏‎‎‏‎"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‏‎‎‎‎‏‏‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‎‎‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‎use car watchdog‎‏‎‎‏‎"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‏‎‏‎‏‎‏‏‎‏‎‏‎‎‏‎‏‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‏‎‎‏‏‎‏‏‎‏‎‎‏‏‎‏‏‎‎Use car watchdog.‎‏‎‎‏‎"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‏‎‎‏‏‏‎‎‏‏‏‎‎‏‏‏‎‏‎‎‎‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‏‏‎‎‎‎‎‎‏‎‏‎My Device‎‏‎‎‏‎"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‎‏‏‎‎‎‏‏‎‎‎‏‏‏‏‎‎‏‏‏‎‏‏‏‎‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‎‎‎Guest‎‏‎‎‏‎"</string>
 </resources>
diff --git a/service/res/values-es-rUS/strings.xml b/service/res/values-es-rUS/strings.xml
index 607ccb0..85ccfab 100644
--- a/service/res/values-es-rUS/strings.xml
+++ b/service/res/values-es-rUS/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Acceder a las cámaras del auto"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"acceder a información de la potencia del vehículo"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Acceder a la información de energía del auto"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"ajustar el valor restante de alcance del vehículo"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Ajustar el valor restante de alcance del vehículo"</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"acceder al sistema HVAC del vehículo"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Acceder al sistema HVAC del auto."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"acceder a información sobre el kilometraje del vehículo"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurar restricciones de UX"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Comunicarse con un dispositivo USB en modo AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Permite que una app se comunique con un dispositivo en modo AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Acceso de lectura al Sistema de detección de ocupantes"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Permite leer el estado y los datos de detección del Sistema de detección de ocupantes"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Control del gráfico del Sistema de detección de ocupantes"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Permite controlar el inicio y la detención del gráfico de detección del Sistema de detección de ocupantes"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Servicio de entrada del auto"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Controlar eventos de entrada"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Error de bus CAN"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Acceder a información detallada del motor del vehículo."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"acceder a la puerta de combustible del vehículo y al puerto de carga"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Acceder a la puerta de combustible del vehículo y al puerto de carga."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"controlar la puerta de combustible del vehículo y el puerto de carga"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Control de la puerta de combustible del vehículo y el puerto de carga"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"leer información sobre la identificación del vehículo"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Acceder a la identificación del vehículo."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"controlar las puertas del vehículo"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Controlar los asientos del vehículo."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"acceder a información básica del vehículo"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Acceder a información básica del vehículo."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"acceder a la información de permisos del fabricante del vehículo"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Acceder a la información de permisos del fabricante del vehículo"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"leer el estado de luces del exterior del vehículo"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Acceder al estado de las luces exteriores del vehículo."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"leer información sobre luces del exterior del vehículo"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Permitir inscripción de dispositivos de confianza"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Controlar el modo de prueba del vehículo"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Controlar el modo de prueba del vehículo"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Habilitar o inhabilitar las funciones del vehículo"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Habilitar o inhabilitar las funciones del vehículo"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"usar perro guardián del vehículo"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Usar perro guardián del vehículo"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mi dispositivo"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Invitado"</string>
 </resources>
diff --git a/service/res/values-es/strings.xml b/service/res/values-es/strings.xml
index 9072c1e..97d252b 100644
--- a/service/res/values-es/strings.xml
+++ b/service/res/values-es/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Acceder a las cámaras del coche."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"acceder a la información sobre el nivel de energía del coche"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Acceder a la información sobre el nivel de energía del coche."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"Ajuste de la distancia que se puede recorrer con el combustible actual"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Valor del ajuste de la distancia que se puede recorrer con el combustible actual."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"acceder al sistema de CVAA del coche"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Acceder al sistema de CVAA del coche."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"acceder a la información del kilometraje del coche"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurar restricciones de la experiencia de usuario"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Comunicarse con un dispositivo USB en modo AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Permite que una aplicación se comunique con un dispositivo en modo AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Consultar el sistema de detección de ocupantes"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Permite leer el estado y los datos de detección del sistema de detección de ocupantes"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Controlar el gráfico del sistema de detección de ocupantes"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Permite configurar el inicio y las pausas del gráfico de detección del sistema de detección de ocupantes"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Servicio de entrada del coche"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gestionar eventos de entrada"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Fallo de bus CAN"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Acceder a información detallada sobre el motor del coche."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"acceder al puerto de carga y al depósito de combustible"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Acceder al puerto de carga y al depósito de combustible."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"controlar el puerto de carga y el depósito de combustible"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Controlar el puerto de carga y el depósito de combustible."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"consultar la identificación del coche"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Acceder a la identificación del coche."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"controlar las puertas del coche"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Controlar los asientos del coche."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"acceder a la información básica del coche"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Acceder a la información básica del coche."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"acceder a la información de permisos del proveedor del coche"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Acceder a la información de permisos del proveedor del coche."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"consultar el estado de las luces exteriores del coche"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Acceder al estado de las luces exteriores del coche."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"controlar las luces exteriores del coche"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Permitir registro de dispositivos de confianza"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Controlar modo de prueba del coche"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Controlar modo de prueba del coche"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Habilitar o inhabilitar las funciones de un coche"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Habilitar o inhabilitar las funciones de un coche."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"usar watchdog del coche"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Usar watchdog del coche."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mi dispositivo"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Invitado"</string>
 </resources>
diff --git a/service/res/values-et/strings.xml b/service/res/values-et/strings.xml
index 5ae4443..982d219 100644
--- a/service/res/values-et/strings.xml
+++ b/service/res/values-et/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Juurdepääs auto kaameratele."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"juurdepääs auto energiateabele"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Juurdepääs auto energiateabele."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"kohandage auto järelejäänud kütusega kaetavat vahemaad"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Kohandage auto järelejäänud kütusega kaetava vahemaa väärtust."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"juurdepääs auto kliimaseadmele"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Juurdepääs auto kliimatehnikale."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"juurdepääs auto läbisõiduteabele"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Kasutuskogemuse piirangute seadistamine"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"AOAP-režiimis USB-seadmega suhtlemine"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Lubab rakendusel seadmega AOAP-režiimis suhelda"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Lugemisega juurdepääs süsteemile Occupant Awareness System"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Võimaldab lugeda süsteemi Occupant Awareness System oleku- ja tuvastamisandmeid"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Süsteemi Occupant Awareness System graafiku juhtimine"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Võimaldab juhtida süsteemi Occupant Awareness System tuvastamisgraafiku käivitamist ja peatamist"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Auto sisendteenus"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Sisestussündmuste töötlemine"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-siin ebaõnnestus"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Juurdepääs auto üksikasjalikule mootoriteabele."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"juurdepääs auto kütusepaagi luugile ja avale"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Juurdepääs auto kütusepaagi luugile ja avale."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"auto kütusepaagi luugi ja ava juhtimine"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Auto kütusepaagi luugi ja ava juhtimine."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"auto tuvastamisteabe lugemine"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Juurdepääs auto tuvastamisteabele."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"autouste juhtimine"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Autoistmete juhtimine."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"juurdepääs auto põhiteabele"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Juurdepääs auto põhiteabele."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"juurdepääs auto edasimüüja lubade teabele"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Juurdepääs auto edasimüüja lubade teabele."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"auto salongitulede oleku lugemine"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Juurdepääs auto välistulede olekule."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"auto välistulede lugemine"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Usaldusväärse seadme registreerimise lubamine"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Auto testrežiimi haldamine"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Auto testrežiimi haldamine"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Auto funktsioonide lubamine ja keelamine"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Võimalik on lubada ja keelata auto funktsioone."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"kasuta auto valvesüsteemi"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Kasuta auto valvesüsteemi."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Minu seade"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Külaline"</string>
 </resources>
diff --git a/service/res/values-eu/strings.xml b/service/res/values-eu/strings.xml
index 6b4990c..5a97151 100644
--- a/service/res/values-eu/strings.xml
+++ b/service/res/values-eu/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Atzitu autoaren kamerak."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"atzitu autoaren energiari buruzko informazioa"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Atzitu autoaren energiari buruzko informazioa"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"doitu autoari gelditzen zaion gaitasuna"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Doitu autoari gelditzen zaion gaitasunaren balioa."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"atzitu autoaren berogailua, haizagailua eta aire-girogailua"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Atzitu autoaren berogailua, haizagailua eta aire-girogailua."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"atzitu autoaren kilometro kopuruari buruzko informazioa"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfiguratu erabiltzeko moduaren murriztapenak"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Komunikatu AOAP moduan USB bidezko gailuekin"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Gailuekin AOAP moduan komunikatzeko baimena ematen dio aplikazioari."</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Bidaiariak hautemateko sistema irakurtzeko sarbidea"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Bidaiariak hautemateko sistemaren egoerei eta detekzioei buruzko datuak irakurtzeko aukera ematen du"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontrolatu Bidaiariak hautemateko sistemaren grafikoa"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Bidaiariak hautemateko sistemaren detekzioen grafikoa noiz hasi eta noiz bukatu kontrolatzeko aukera ematen du"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Autoaren sarrerako zerbitzua"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Kudeatu sarrerako gertaerak"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN autobusak huts egin du"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Atzitu autoaren motorrari buruzko informazio xehatua."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"atzitu autoaren erregai-deposituaren ataka eta korrontera konektatzeko ataka"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Atzitu autoaren erregai-deposituaren ataka eta korrontera konektatzeko ataka."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"kontrolatu autoaren erregai-deposituaren ataka eta korrontera konektatzeko ataka"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Kontrolatu autoaren erregai-deposituaren ataka eta korrontera konektatzeko ataka."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"irakurri autoaren identifikazioa"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Atzitu autoaren identifikazioa."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"kontrolatu autoaren ateak"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kontrolatu autoaren eserlekuak."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"atzitu autoaren oinarrizko informazioa"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Atzitu autoaren oinarrizko informazioa."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"atzitu autoaren saltzailearen baimenari buruzko informazioa"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Atzitu autoaren saltzailearen baimenari buruzko informazioa"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"irakurri autoaren kanpoaldeko argien egoera"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Atzitu autoaren kanpoaldeko argien egoera."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"irakurri autoaren kanpoaldeko argiak"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Eman gailu fidagarriak erregistratzeko baimena"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Kontrolatu autoaren proba modua"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Kontrolatu autoaren proba modua"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Gaitu edo desgaitu autoaren eginbideak"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Gaitu edo desgaitu autoaren eginbideak."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"erabili autoaren softwarea zaintzeko sistema"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Erabili autoaren softwarea zaintzeko sistema."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Nire gailua"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Gonbidatua"</string>
 </resources>
diff --git a/service/res/values-fa/strings.xml b/service/res/values-fa/strings.xml
index 93f4c27..cc05861 100644
--- a/service/res/values-fa/strings.xml
+++ b/service/res/values-fa/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"دسترسی به دوربین(های) خودرو."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"دسترسی به اطلاعات انرژی خودرو"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"دسترسی اطلاعات انرژی خودرو."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"تنظیم مقدار مسافت باقی‌مانده که می‌توان با خودرو سفر کرد"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"تنظیم مقدار مسافت باقی‌مانده که می‌توان با خودرو سفر کرد."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"دسترسی به اچ‌وی‌ای‌سی خودرو"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"دسترسی به اچ‌وی‌ای‌سی خودرو."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"دسترسی به اطلاعات مسافت طی‌شده خودرو"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"پیکربندی محدودیت‌های UX"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"برقراری ارتباط با دستگاه USB در حالت AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"به برنامه‌ای اجازه می‌دهید با دستگاهی در حالت AOAP ارتباط برقرار کند"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"دسترسی خواندن «سیستم هوشیاری سرنشین»"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"اجازه می‌دهد وضعیت و داده‌های تشخیص «سیستم هوشیاری سرنشین» خوانده شود"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"کنترل نمودار «سیستم هوشیاری سرنشین»"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"اجازه می‌دهد شروع و توقف نمودار تشخیص «سیستم هوشیاری سرنشین» کنترل شود"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"سرویس ورودی خودرو"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"مدیریت رویدادهای ورودی"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"گذرگاه CAN ناموفق بود"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"به اطلاعات کامل موتور خودرو دسترسی پیدا کنید."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"دسترسی به درب باک و درگاه شارژ خودرو"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"به درب باک و درگاه شارژ دسترسی پیدا کنید."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"درب باک و درگاه شارژ خودرو کنترل شود"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"درب باک و درگاه شارژ خودرو کنترل شود."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"خواندن شناسه خودرو"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"به شناسه خودرو دسترسی پیدا کنید."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"کنترل درهای خودرو"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"صندلی‌های خودرو را کنترل کنید."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"دسترسی به اطلاعات اصلی خودرو"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"به اطلاعات اصلی خودرو دسترسی پیدا کنید."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"دسترسی به اطلاعات مجوز فروشنده خودرو"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"به اطلاعات مجوز فروشنده خودرو دسترسی پیدا کنید."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"خواندن وضعیت چراغ‌های خارجی خودرو"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"به وضعیت چراغ‌های خارجی خودرو دسترسی پیدا کنید."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"خواندن چراغ‌های خارجی خودرو"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"مجاز کردن ثبت‌نام دستگاه مطمئن"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"کنترل حالت آزمایش خودرو"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"کنترل حالت آزمایش خودرو"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"فعال کردن یا غیرفعال کردن ویژگی‌های خودرو"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"ویژگی‌های خودرو را فعال یا غیرفعال کنید."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"استفاده از زمان‌سنج مراقب خودرو"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"استفاده از زمان‌سنج مراقب خودرو"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"دستگاه من"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"مهمان"</string>
 </resources>
diff --git a/service/res/values-fi/strings.xml b/service/res/values-fi/strings.xml
index de6b0cb..e03f38c 100644
--- a/service/res/values-fi/strings.xml
+++ b/service/res/values-fi/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"käyttää auton kameroita"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"käyttää auton energiatietoja"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"nähdä auton energiatiedot"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"säädä auton jäljellä olevaa toimintamatkaa"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Säädä auton jäljellä olevan toimintamatkan arvoa."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"käyttää auton ilmastointia ja lämmitystä"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"käyttää auton lämmitys-,ilmanvaihto- ja ilmastointijärjestelmää"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"käyttää tietoja ajetuista kilometreistä"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Määritä UX-rajoitukset"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"kommunikoida USB-laitteen kanssa AOAP-tilassa"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Sallii sovelluksen kommunikoida laitteen kanssa AOAP-tilassa"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant Awareness Systemin lukemisoikeudet"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Sallii Occupant Awareness Systemin tilan ja tunnistusdatan lukemisen"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Ohjata Occupant Awareness System Graphia"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Sallii Occupant Awareness Systemin käynnistyksen ja pysäytyksen ohjaamisen"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Auton syötepalvelu"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"käsitellä syötteitä"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-väylä hylättiin"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"käyttää auton moottorin yksityiskohtaisia tietoja"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"käyttää auton polttoaineluukkua ja latausliitäntää"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"käyttää auton polttoaineluukkua ja latausliitäntää"</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"ohjata auton polttoaineluukkua ja latausliitäntää"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Ohjata auton polttoaineluukkua ja latausliitäntää."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"nähdä auton tunnistetiedot"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"käyttää auton tunnistetietoja"</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"ohjata auton ovia"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"ohjata auton istuimia"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"käyttää auton perustietoja"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"käyttää auton perustietoja"</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"tarkistaa auton myyjän lupatiedot"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"tarkistaa auton myyjän lupatiedot"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"nähdä auton ulkovalojen tilan"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"käyttää auton ulkovalojen tilaa"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"nähdä auton ulkovalot"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Salli luotetun laitteen rekisteröinti"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Ohjaa auton testaustilaa"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Ohjaa auton testaustilaa"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Ota auton ominaisuuksia käyttöön tai poista niitä käytöstä"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Ota auton ominaisuuksia käyttöön tai poista niitä käytöstä."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"käytä auton vauhtiajastinta"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Käytä auton vauhtiajastinta."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Oma laite"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Vieras"</string>
 </resources>
diff --git a/service/res/values-fr-rCA/strings.xml b/service/res/values-fr-rCA/strings.xml
index 23e8d6a..4bfbde2 100644
--- a/service/res/values-fr-rCA/strings.xml
+++ b/service/res/values-fr-rCA/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Accéder aux caméras de la voiture."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"accéder aux renseignements énergétiques de la voiture"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Accéder aux renseignements énergétiques de la voiture."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"réglez l\'autonomie restante du véhicule"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Réglez la valeur de l\'autonomie restante du véhicule."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"accéder à l\'élément CVC de la voiture"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Accéder à l\'élément CVC de la voiture."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"accéder au kilométrage de la voiture"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurer les restrictions relatives à l\'expérience utilisateur"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Communiquer avec les appareils USB en mode AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Permet à une application de communiquer avec un appareil en mode AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Accès en lecture au système de détection des occupants"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Permet de lire les données liées à l\'état et à la détection du système de détection des occupants"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Contrôler le graphique du système de détection des occupants"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Permet de contrôler le démarrage et l\'arrêt du graphique de détection du système de détection des occupants"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Service d\'entrée de la voiture"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gérer les événements d\'entrée"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Défaillance du bus de données CAN"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Accéder aux renseignements détaillés sur le moteur de votre voiture."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"accéder à la porte du réservoir de carburant et au port de recharge de la voiture"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Accéder à la porte du réservoir de carburant et au port de recharge de la voiture."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"contrôler la porte du réservoir de carburant et le port de recharge du véhicule"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Contrôler la porte du réservoir de carburant et le port de recharge du véhicule."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"lire l\'identification de la voiture"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Accéder à l\'identification de la voiture."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"contrôler les portières de la voiture"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Contrôler les sièges de la voiture."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"accéder aux renseignements de base de la voiture"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Accéder aux renseignements de base de la voiture."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"accéder aux renseignements d\'autorisation du fournisseur du véhicule"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Accédez aux renseignements d\'autorisation du fournisseur du véhicule."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"lire l\'état des feux extérieurs de la voiture"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Accéder à l\'état des feux extérieurs de la voiture."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"lire les feux extérieurs de la voiture"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Autoriser l\'inscription d\'un appareil de confiance"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Contrôler le mode test du véhicule"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Contrôler le mode test du véhicule"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Activez ou désactivez les fonctionnalités du véhicule"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Activez ou désactivez les fonctionnalités du véhicule."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"utilisez le service de surveillance automobile"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Utilisez le service de surveillance automobile."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mon appareil"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Invité"</string>
 </resources>
diff --git a/service/res/values-fr/strings.xml b/service/res/values-fr/strings.xml
index 22a3be3..b1e67e4 100644
--- a/service/res/values-fr/strings.xml
+++ b/service/res/values-fr/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Accéder aux caméras de la voiture."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"Accéder aux informations relatives à l\'énergie de la voiture"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Accéder aux informations énergétiques de la voiture."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"ajuster l\'autonomie restante de la voiture"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Ajustez la valeur de l\'autonomie restante de la voiture."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"Accéder aux éléments CVC de la voiture"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Accéder aux éléments CVC de la voiture"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"Accéder aux informations sur le kilométrage de la voiture"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurer les restrictions relatives à l\'expérience utilisateur"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Communiquer avec un appareil USB en mode AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Autorise une application à communiquer avec un appareil en mode AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Accès en lecture au système de perception de l\'occupant"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Permet la lecture des données liées à l\'état et à la détection du système de perception de l\'occupant"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Contrôler le graphique du système de perception de l\'occupant"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Permet de contrôler le lancement et l\'arrêt du graphique de détection du système de perception de l\'occupant"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Service d\'entrée de la voiture"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gérer les événements d\'entrée"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Échec du bus de données CAN"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Accéder à des informations détaillées sur le moteur de la voiture."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"Accéder à la trappe à carburant et au port de recharge de la voiture"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Accéder à la trappe à carburant et au port de recharge de la voiture."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"contrôler la trappe à carburant et le port de recharge de la voiture"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Contrôler la trappe à carburant et le port de recharge de la voiture."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"Lire l\'identification de la voiture"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Accéder à l\'identification de la voiture."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"Contrôler les portes de la voiture"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Contrôler les sièges de la voiture."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"Accéder aux informations de base de la voiture"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Accéder aux informations de base relatives à la voiture."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"accéder aux informations sur les autorisations des fournisseurs pour la voiture"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Accéder aux informations sur les autorisations des fournisseurs pour la voiture."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"Lire l\'état des phares de la voiture"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Accéder à l\'état des phares de la voiture."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"Lire l\'état des phares de la voiture"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Autoriser l\'enregistrement de l\'appareil vérifié"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Contrôler le mode de test de la voiture"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Contrôler le mode de test de la voiture"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Activer ou désactiver les fonctionnalités de la voiture"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Activez ou désactivez les fonctionnalités de la voiture."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"utiliser le watchdog de la voiture"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Utiliser le watchdog de la voiture."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mon appareil"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Invité"</string>
 </resources>
diff --git a/service/res/values-gl/strings.xml b/service/res/values-gl/strings.xml
index f0b343e..7a6eaa9 100644
--- a/service/res/values-gl/strings.xml
+++ b/service/res/values-gl/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Acceder ás cámaras do coche."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"acceder a información sobre o nivel de enerxía do coche"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Acceder a información de enerxía do coche."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"axustar autonomía restante do coche"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Axusta o valor de autonomía restante do coche."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"acceder ao sistema de climatización do coche"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Acceder ao sistema de HVAC coche."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"acceder a información da quilometraxe do coche"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurar restricións da experiencia de usuario"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Comunicarse con dispositivos USB no modo AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Permite que unha aplicación se comunique cun dispositivo no modo AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Acceso de lectura ao sistema de detección de ocupantes"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Permite ler os datos da detección e do estado do sistema de detección de ocupantes"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Controlar o gráfico do sistema de detección de ocupantes"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Permite controlar o inicio e a parada do gráfico de detección do sistema de detección de ocupantes"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Servizo de entrada do coche"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Controlar os eventos de entrada"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Produciuse un erro no bus CAN"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Acceder a información detallada do motor do coche."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"acceder ao depósito de combustible e ao porto de carga do coche"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Acceder ao depósito de combustible e ao porto de carga do coche."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"controlar o depósito de combustible e o porto de carga do coche"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Controlar o depósito de combustible e o porto de carga do coche."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"ler a identificación do coche"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Acceder á identificación do coche."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"controlar as portas do coche"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Controlar os asentos do coche."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"acceder a información básica do coche"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Acceder a información básica do coche."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"acceder á información sobre os permisos do vendedor do coche"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Acceder á información sobre os permisos do vendedor do coche."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"ler o estado das luces exteriores do dispositivo"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Acceder ao estado das luces exteriores do coche."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ler as luces exteriores do coche"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Permitir inscrición de dispositivos de confianza"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Controlar o modo de proba do coche"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Controlar o modo de proba do coche"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Activar ou desactivar funcións do coche"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Activa ou desactiva as funcións do coche."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"utilizar sistema de vixilancia do coche"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Utiliza o sistema de vixilancia do coche."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Dispositivo"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Convidado"</string>
 </resources>
diff --git a/service/res/values-gu/strings.xml b/service/res/values-gu/strings.xml
index 78e94b3..3303fce 100644
--- a/service/res/values-gu/strings.xml
+++ b/service/res/values-gu/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"તમારી કારના કૅમેરાને ઍક્સેસ કરવાની મંજૂરી આપો."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"કારની ઊર્જાની માહિતીને ઍક્સેસ કરો"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"તમારી કારની ઊર્જાની માહિતી ઍક્સેસ કરવાની મંજૂરી આપો."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"કારની રેંજનું બાકીનું મૂલ્ય ગોઠવો"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"કારની રેંજનું બાકીનું મૂલ્ય ગોઠવો."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"કારના HVACને ઍક્સેસ કરો"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"તમારી કારની hvac ઍક્સેસ કરો."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"કારના માઇલેજની માહિતીને ઍક્સેસ કરો"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX પ્રતિબંધોને ગોઠવણી કરો"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"USB ડિવાઇસ સાથે AOAP મોડમાં સંવાદ સાધો"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"કોઈ ઍપને અન્ય ડિવાઇસ સાથે AOAP મોડમાં સંવાદ સાધવાની મંજૂરી આપે છે"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"\'કારમાં સવાર લોકોની જાગરૂકતા સંબંધિત સિસ્ટમ\'ને વાંચવા માટેનો ઍક્સેસ"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"\'કારમાં સવાર લોકોની જાગરૂકતા સંબંધિત સિસ્ટમ\'ના સ્ટેટસ અને તેની જાણકારીના ડેટાને વાંચવાની મંજૂરી આપે છે"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"\'કારમાં સવાર લોકોની જાગરૂકતા સંબંધિત સિસ્ટમ\'ના ગ્રાફને નિયંત્રિત કરો"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"\'કારમાં સવાર લોકોની જાગરૂકતા સંબંધિત સિસ્ટમ\'ની જાણકારીના ગ્રાફનું નિયંત્રણ શરૂ કરવાની અને રોકવાની મંજૂરી આપે છે"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"કારની ઇનપુટ સેવા"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ઇનપુટ ઇવેન્ટ્સને હૅન્ડલ કરો"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN બસ નિષ્ફળ રહી"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"તમારી કારના એન્જિનની વિગતવાર માહિતીને ઍક્સેસ કરો."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"કારના ઇંધણના દરવાજા અને ચાર્જ પોર્ટને ઍક્સેસ કરો"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"કારના ઇંધણના દરવાજા અને ચાર્જ પોર્ટને ઍક્સેસ કરો."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"કારની \'ઈંધણની ટાંકી\'ના દરવાજા અને ચાર્જ પોર્ટનું નિયંત્રણ કરો"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"કારની \'ઈંધણની ટાંકી\'ના દરવાજા અને ચાર્જ પોર્ટનું નિયંત્રણ કરો."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"કારની ઓળખ વાંચો"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"કારની ઓળખને ઍક્સેસ કરો."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"કારના દરવાજાને નિયંત્રિત કરો"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"કારની સીટને નિયંત્રિત કરો."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"કારની પ્રાથમિક માહિતીને ઍક્સેસ કરો"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"કારની મૂળભૂત માહિતીને ઍક્સેસ કરો."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"કારના વિક્રેતાની પરવાનગી વિશેની માહિતીને ઍક્સેસ કરો"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"કારના વિક્રેતાની પરવાનગી વિશેની માહિતીને ઍક્સેસ કરો."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"કારની બહારની લાઇટની સ્થિતિને વાંચો"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"કારની બહારની લાઇટની સ્થિતિને ઍક્સેસ કરો."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"કારની બહારની લાઇટ વિશે વાંચો"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"વિશ્વસનીય ડિવાઇસના નોંધણીની મંજૂરી આપો"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"કારના પરીક્ષણ મોડને નિયંત્રિત કરો"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"કારના પરીક્ષણ મોડને નિયંત્રિત કરો"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"કારની સુવિધા ચાલુ અથવા બંધ કરો"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"કારની સુવિધા ચાલુ અથવા બંધ કરો."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"કાર વૉચડોગ સુવિધાનો ઉપયોગ કરો"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"કાર વૉચડોગ સુવિધાનો ઉપયોગ કરો."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"મારું ડિવાઇસ"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"અતિથિ"</string>
 </resources>
diff --git a/service/res/values-hi/strings.xml b/service/res/values-hi/strings.xml
index 4352d7d..a70c77d 100644
--- a/service/res/values-hi/strings.xml
+++ b/service/res/values-hi/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"आपकी कार के कैमरे ऐक्सेस कर सकता है."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"कार की ऊर्जा की जानकारी ऐक्सेस कर सकता है"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"आपकी कार की ऊर्जा से जुड़ी जानकारी ऐक्सेस कर सकता है."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"मौजूदा बैटरी या फ़्यूल में कार कितनी दूरी तय कर सकती है, इस मान में बदलाव करें."</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"मौजूदा बैटरी या फ़्यूल में कार कितनी दूरी तय कर सकती है, इस मान में बदलाव करें."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"कार का एचवीएसी ऐक्सेस कर सकता है"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"आपकी कार का एचवीएसी ऐक्सेस कर सकता है."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"कार के माइलेज की जानकारी ऐक्सेस कर सकता है"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX की पाबंदियां कॉन्फ़िगर करें"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"एओएपी मोड में यूएसबी डिवाइस से कनेक्ट करें"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"ऐप्लिकेशन एओएपी मोड में किसी डिवाइस से कनेक्ट हो सकता है"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant Awareness System से मिले डेटा को सिर्फ़ पढ़ने की अनुमति"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"इससे Occupant Awareness System की स्थिति और डिटेक्शन सिस्टम के नतीजों को पढ़ने की अनुमति मिलती है. डिटेक्शन सिस्टम यह बताता है कि ड्राइवर कहां देख रहा है."</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"इससे ऐप्लिकेशन को Occupant Awareness System Graph कंट्रोल करने की अनुमति मिलती है"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"इससे Occupant Awareness System के डिटेक्शन ग्राफ़ को शुरू करने या रोकने की अनुमति मिलती है"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"कार की इनपुट सेवा"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"इनपुट से जुड़े इवेंट प्रबंधित कर सकता है"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"\'CAN बस\' काम नहीं कर पा रहा है"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"आपकी कार के इंजन की पूरी जानकारी ऐक्सेस कर सकता है."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"कार की ईंधन टंकी का ढक्कन और चार्जिंग पोर्ट ऐक्सेस कर सकता है"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"कार की ईंधन टंकी का ढक्कन और चार्जिंग पोर्ट ऐक्सेस कर सकता है."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"इससे ऐप्लिकेशन को कार की ईंधन टंकी का ढक्कन और चार्जिंग पोर्ट कंट्रोल करने की अनुमति मिलती है"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"इससे ऐप्लिकेशन को कार की ईंधन टंकी का ढक्कन और चार्जिंग पोर्ट कंट्रोल करने की अनुमति मिलती है."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"कार की पहचान देख सकता है"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"कार की पहचान ऐक्सेस कर सकता है."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"कार के दरवाज़े नियंत्रित कर सकता है"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"कार की सीटें नियंत्रित कर सकता है."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"कार की बुनियादी जानकारी ऐक्सेस कर सकता है"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"कार की बुनियादी जानकारी ऐक्सेस कर सकता है."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"कार के वेंडर की अनुमति संबंधित जानकारी ऐक्सेस करें"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"कार के वेंडर की अनुमति संबंधित जानकारी ऐक्सेस करें."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"कार के बाहरी हिस्से में लगी लाइटों की स्थिति देख सकता है"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"कार के बाहरी हिस्से में लगी लाइटों की स्थिति ऐक्सेस कर सकता है."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"कार के बाहरी हिस्से में लगी लाइटें नियंत्रित कर सकता है"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"भरोसेमंद डिवाइस का नाम दर्ज करने की अनुमति दें"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"कार के जांच मोड को नियंत्रित करें"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"कार के जांच मोड को नियंत्रित करें"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"कार की सुविधाएं चालू या बंद करें"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"कार की सुविधाएं चालू या बंद करें."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"कार के वॉचडॉग का इस्तेमाल करें"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"कार के वॉचडॉग का इस्तेमाल करें."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"मेरा डिवाइस"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"मेहमान"</string>
 </resources>
diff --git a/service/res/values-hr/strings.xml b/service/res/values-hr/strings.xml
index feb4108..2f9c2b0 100644
--- a/service/res/values-hr/strings.xml
+++ b/service/res/values-hr/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"pristupiti kamerama automobila"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"pristupiti podacima o energiji automobila"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"pristupiti informacijama o energiji automobila"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"korekcija preostalog dometa automobila"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Korekcija vrijednosti preostalog dometa automobila."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"pristupiti grijanju, ventilaciji i klimatizaciji automobila"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"pristupiti grijanju, ventilaciji i klimatizaciji vašeg automobila"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"pristupiti podacima o kilometraži automobila"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"konfigurirati ograničenja UX-a"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"komunicirati s USB uređajem u AOAP načinu"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Aplikaciji omogućuje da komunicira s uređajem u AOAP načinu"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Pristup za čitanje za Sustav detektiranja prisutnosti"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Omogućuje očitavanje statusa i podataka o detektiranju za Sustav detektiranja prisutnosti"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontrola grafikona Sustava detektiranja prisutnosti"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Omogućuje kontroliranje početka i završetka grafikona detektiranja za Sustav detektiranja prisutnosti"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"usluga automobilskog unosa"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"rukovati događajima unosa"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Pogreška CAN busa"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"pristupiti detaljnim podacima o motoru automobila"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"pristupiti poklopcu spremnika za gorivo i priključku za punjenje na automobilu"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"pristupiti poklopcu spremnika za gorivo i priključku za punjenje na automobilu"</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"kontrolirati poklopac spremnika za gorivo i priključak za punjenje na automobilu"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"kontrolirati poklopac spremnika za gorivo i priključak za punjenje na automobilu."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"čitati identifikaciju automobila"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"pristupiti identifikaciji automobila"</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"upravljati automobilskim vratima"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"upravljati automobilskim sjedalima"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"pristupiti osnovnim podacima automobila"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"pristupiti osnovnim podacima automobila"</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"pristupanje informacijama o dopuštenju dobavljača automobila"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Pristupanje informacijama o dopuštenju dobavljača automobila."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"čitati stanje vanjskih svjetala automobila"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"pristupiti stanju vanjskih svjetala automobila"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"čitati podatke o vanjskim svjetlima automobila"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Dopusti prijavu pouzdanih uređaja"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Upravljajte probnim načinom automobila"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Upravljajte probnim načinom automobila"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Omogućivanje ili onemogućivanje značajki automobila"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Omogućivanje ili onemogućivanje značajki automobila."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"koristi čuvara automobila."</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Koristi čuvara automobila."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moj uređaj"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Gost"</string>
 </resources>
diff --git a/service/res/values-hu/strings.xml b/service/res/values-hu/strings.xml
index 68657a8..0a3950f 100644
--- a/service/res/values-hu/strings.xml
+++ b/service/res/values-hu/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Hozzáférhet az autó kameráihoz."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"hozzáférhet az autó energiafelhasználására vonatkozó adatokhoz"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Hozzáférhet az autó energiafelhasználására vonatkozó adatokhoz."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"az autó fennmaradó hatótávolságának módosítása"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Az autó fennmaradó hatótávolságának módosítása."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"hozzáférhet az autó HVAC-adataihoz"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Hozzáférhet az autó HVAC-adataihoz."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"hozzáférhet az autó kilométeradataihoz"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Felhasználói élményre vonatkozó korlátozások beállítása"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"USB-eszközzel való kommunikáció AOAP módban"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Lehetővé teszi az alkalmazás számára, hogy AOAP módban kommunikáljon az adott eszközzel"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant Awareness System olvasási hozzáférés"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Engedélyezi a státusz- és észlelési adatok olvasását az Occupant Awareness System számára"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Az Occupant Awareness System grafikonjának irányítása"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Engedélyezi az Occupant Awareness System észlelési grafikonjának indítását és leállítását"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Az autó beviteli szolgáltatása"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Kezelheti a beviteli eseményeket"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"A CAN-busz hibát észlelt"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Hozzáférhet az autó motorjának részletes adataihoz."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"hozzáférhet az autó tanksapkájához és töltőnyílásához"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Hozzáférhet az autó tanksapkájához és töltőnyílásához."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"vezérelheti az autó tanksapkáját és töltőnyílását"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Vezérelheti az autó tanksapkáját és töltőnyílását."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"olvashatja a jármű-azonosító számot"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Hozzáférhet a jármű-azonosító számhoz."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"vezérelheti az autó ajtóit"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Vezérelheti az autó üléseit."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"hozzáférhet az autó alapvető adataihoz"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Hozzáférhet az autó alapvető adataihoz."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"hozzáférhet az autó gyártóengedélyeivel kapcsolatos adataihoz"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Hozzáférhet az autó gyártóengedélyeivel kapcsolatos adataihoz."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"olvashatja az autó külső világításának állapotáról szóló adatokat"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Hozzáférhet az autó külső világításának állapotához."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"olvashatja az autó külső világítására vonatkozó adatokat"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Megbízható eszköz regisztrálásának engedélyezése"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Vezérelheti az autó tesztüzemmódját"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Vezérelheti az autó tesztüzemmódját"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Az autó funkcióinak engedélyezése vagy tiltása"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Az autó funkcióinak engedélyezése vagy tiltása."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"autófigyelő használata"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Autófigyelő használata."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Saját eszköz"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Vendég"</string>
 </resources>
diff --git a/service/res/values-hy/strings.xml b/service/res/values-hy/strings.xml
index 23f5812..80f3c91 100644
--- a/service/res/values-hy/strings.xml
+++ b/service/res/values-hy/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Կառավարել մեքենայի տեսախցիկ(ներ)ը"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"օգտագործել մեքենայի լիցքի մասին տվյալները"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Ընթերցել մեքենայի էներգառեսուրսների մասին տվյալները"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"փոխել տարածությունը, որը մեքենան կանցնի մինչև հաջորդ լցակայանը"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Փոխել տարածությունը, որը մեքենան կանցնի մինչև հաջորդ լցակայանը"</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"օգտագործել մեքենայի HVAC համակարգի տվյալները"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Կառավարել HVAC համակարգը"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"օգտագործել մեքենայի վազքի տվյալները"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Սահմանափակել գործառույթների օգտագործումը"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Հաղորդակցվել USB սարքի հետ AOAP ռեժիմում"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Հավելվածին թույլ է տալիս հաղորդակցվել սարքի հետ AOAP ռեժիմում"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Ուղևորի ներկայության որոշման համակարգի կարգավիճակի ընթերցման թույլտվություն"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Թույլ է տալիս կարդալ ուղևորի ներկայության որոշման համակարգի կարգավիճակը և տվյալները"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Կառավարել ուղևորի ներկայության որոշման համակարգի տրամագիրը"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Թույլ է տալիս կառավարել ուղևորի ներկայության որոշման համակարգի աշխատանքի տրամագրի գործարկումը և դադարեցումը"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Ներածման ծառայություն"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Մշակել ներածման իրադարձությունները"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN անվադողի սխալ"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Օգտագործել շարժիչի մանրամասն տվյալները։"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"օգտագործել մեքենայի վառելիքի բաքի կափարիչի և լիցքավորման վարդակի տվյալները"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Օգտագործել մեքենայի վառելիքի բաքի կափարիչի և լիցքավորման վարդակի տվյալները։"</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"Կառավարել մեքենայի վառելիքի բաքի կափարիչի և լիցքավորման վարդակի տվյալները"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Կառավարել մեքենայի վառելիքի բաքի կափարիչի և լիցքավորման վարդակի տվյալները։"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"կարդալ մեքենայի նույնականացման տվյալները"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Օգտագործել մեքենայի նույնականացման տվյալները։"</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"կառավարել մեքենայի դռները"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Կառավարել մեքենայի նստատեղերը։"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"օգտագործել մեքենայի հիմնական տվյալները"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Օգտագործել մեքենայի հիմնական տվյալները։"</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"օգտագործել մեքենայի վաճառողի մասին տվյալները"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Օգտագործել մեքենայի վաճառողի մասին տվյալները։"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"կարդալ մեքենայի արտաքին լուսավորության կարգավիճակի տվյալները"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Օգտագործել մեքենայի արտաքին լուսավորության կարգավիճակի մասին տվյալները։"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"կարդալ մեքենայի արտաքին լուսավորության կարգավիճակի մասին տվյալները"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Թույլատրել վստահելի սարքի գրանցումը"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Կառավարել ավտոմեքենայի փորձարկման ռեժիմը"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Կառավարել ավտոմեքենայի փորձարկման ռեժիմը"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Միացնել կամ անջատել մեքենայի գործառույթները"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Միացնել կամ անջատել մեքենայի գործառույթները"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"oգտագործել մեքենայի պահապանին"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Օգտագործել մեքենայի պահապանին"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Իմ սարքը"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Հյուր"</string>
 </resources>
diff --git a/service/res/values-in/strings.xml b/service/res/values-in/strings.xml
index 3eef766..3f35edd 100644
--- a/service/res/values-in/strings.xml
+++ b/service/res/values-in/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Mengakses kamera mobil Anda."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"mengakses informasi energi mobil"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Mengakses informasi energi mobil Anda."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"sesuaikan jangkauan mobil yang tersisa"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Sesuaikan nilai jangkauan mobil yang tersisa."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"mengakses hvac mobil"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Mengakses hvac mobil Anda."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"mengakses informasi jarak tempuh mobil"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Mengonfigurasi Batasan UX"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Berkomunikasi dengan perangkat USB dalam mode AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Mengizinkan aplikasi untuk berkomunikasi dengan perangkat dalam mode AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Akses Baca Sistem Awareness Penumpang"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Mengizinkan pembacaan status dan data deteksi untuk Sistem Awareness Penumpang"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontrol Grafik Sistem Awareness Penumpang"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Mengizinkan pengontrolan mulai dan berhentinya grafik deteksi Sistem Awareness Penumpang"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Layanan Masukan Mobil"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Menangani aktivitas masukan"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus gagal"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Mengakses informasi mendetail tentang mesin mobil Anda."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"mengakses tutup tangki bahan bakar dan lubang colokan pengisi daya mobil"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Mengakses tutup tangki bahan bakar dan lubang colokan pengisi daya mobil."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"mengontrol tutup tangki bahan bakar dan port pengisian daya di mobil"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Mengontrol tutup tangki bahan bakar dan port pengisian daya di mobil."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"membaca identifikasi mobil"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Mengakses identifikasi mobil."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"mengontrol pintu mobil"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Mengontrol tempat duduk mobil."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"mengakses informasi dasar mobil"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Mengakses informasi dasar mobil."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"mengakses informasi izin vendor mobil"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Mengakses informasi izin vendor mobil."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"membaca status lampu eksterior mobil"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Mengakses status lampu eksterior mobil."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"membaca lampu eksterior mobil"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Izinkan Pendaftaran Perangkat Dipercaya"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Mode uji untuk mengontrol mobil"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Mode uji untuk mengontrol mobil"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Aktifkan atau nonaktifkan fitur mobil"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Aktifkan atau nonaktifkan fitur mobil."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"gunakan watchdog mobil"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Gunakan watchdog mobil."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Perangkat Saya"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Tamu"</string>
 </resources>
diff --git a/service/res/values-is/strings.xml b/service/res/values-is/strings.xml
index 301e4bd..5a10627 100644
--- a/service/res/values-is/strings.xml
+++ b/service/res/values-is/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Fá aðgang að myndavél(um) bílsins."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"fá aðgang að upplýsingum um orkunotkun bílsins"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Aðgangur að upplýsingum um orkunotkun bílsins."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"stilla gildi fyrir eftirstandandi drægi bílsins"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Stilla gildi fyrir eftirstandandi drægi bílsins."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"fá aðgang að hitun og loftræstingu bílsins"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Fá aðgang að hitun og loftræstingu bílsins."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"fá aðgang að upplýsingum um ekna vegalengd bílsins"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Stilla takmarkanir á upplifun notanda"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Eiga samskipti við USB-tæki í AOAP-stillingu"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Gerir forriti kleift að eiga í samskiptum við tæki í AOAP-stillingu"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Lesaðgangur að Occupant Awareness System"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Leyfir lestur á stöðu og kennslagögnum fyrir Occupant Awareness System"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Stjórna riti fyrir Occupant Awareness System"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Leyfir stjórnun á kennslariti fyrir Occupant Awareness System"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Inntaksþjónusta bíls"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Stjórna inntakstilvikum"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Bilun í CAN-gagnabraut"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Fá aðgang að ítarlegum upplýsingum um vél bílsins."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"fá aðgang að bensínloki og hleðslutengi bílsins"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Fá aðgang að bensínloki og hleðslutengi bílsins."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"stjórna bensínloki og hleðslutengi bílsins"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Stjórna bensínloki og hleðslutengi bílsins."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"lesa auðkenni bílsins"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Fá aðgang að auðkenni bílsins."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"stjórna hurðum bílsins"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Stjórna bílsætum."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"fá aðgang að grunnupplýsingum bílsins"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Fá aðgang að grunnupplýsingum bílsins."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"fá aðgang að heimildarupplýsingum bílasala"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Fá aðgang að heimildarupplýsingum bílasala."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"lesa stöðu ljósa bíls að utanverðu"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Fá aðgang að stöðu ljósa bíls að utanverðu."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"lesa ljós bíls að utanverðu"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Heimila skráningu sem traust tæki"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Stjórna prófunarstillingu bíls"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Stjórna prófunarstillingu bíls"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Kveikja eða slökkva á bíleiginleikum"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Kveikja eða slökkva á bíleiginleikum."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"nota bílaeftirlitsaðila"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Nota bílaeftirlitsaðila."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Tækið mitt"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Gestur"</string>
 </resources>
diff --git a/service/res/values-it/strings.xml b/service/res/values-it/strings.xml
index be4af19..da6720a 100644
--- a/service/res/values-it/strings.xml
+++ b/service/res/values-it/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Consente di accedere alle videocamere dell\'automobile."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"Accesso alle informazioni sulla carica dell\'automobile"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Consente di accedere alle informazioni sulla carica dell\'automobile."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"regolazione dell\'autonomia rimanente dell\'auto"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Consente di regolare il valore dell\'autonomia rimanente dell\'auto."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"Accesso al sistema HVAC dell\'automobile"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Consente di accedere al sistema HVAC dell\'automobile."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"Accesso alle informazioni sul consumo di carburante dell\'automobile"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Consente di configurare le limitazioni dell\'esperienza utente."</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Comunicazione con dispositivo USB in modalità AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Consente a un\'app di comunicare con un dispositivo in modalità AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Accesso in lettura all\'Occupant Awareness System"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Consente di leggere lo stato e i dati di rilevamento dell\'Occupant Awareness System."</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Controllo del grafico dell\'Occupant Awareness System"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Consente di controllare l\'avvio e l\'interruzione del grafico di rilevamento dell\'Occupant Awareness System."</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Servizio di input dell\'auto"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Consente di gestire gli eventi di input."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Comunicazione tramite bus CAN non riuscita"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Consente di accedere a informazioni dettagliate sul motore dell\'automobile."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"Accesso al coperchio del serbatoio e allo sportello di ricarica dell\'automobile"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Consente di accedere al coperchio del serbatoio e allo sportello di ricarica dell\'automobile."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"Controllo del coperchio del serbatoio e dello sportello di ricarica dell\'automobile"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Consente di controllare il coperchio del serbatoio e lo sportello di ricarica dell\'automobile."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"Lettura dell\'identificazione dell\'automobile"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Consente di accedere all\'identificazione dell\'automobile."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"Controllo delle portiere dell\'automobile"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Consente di regolare i sedili dell\'automobile."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"Accesso alle informazioni di base dell\'automobile"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Consente di accedere alle informazioni di base dell\'automobile."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"Accesso alle informazioni sulle autorizzazioni del produttore dell\'automobile"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Consente di accedere alle informazioni sulle autorizzazioni del produttore dell\'automobile."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"Lettura dello stato delle luci esterne dell\'automobile"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Consente di accedere allo stato delle luci esterne dell\'automobile."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"Lettura delle luci esterne dell\'automobile"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Consenti la registrazione di dispositivi attendibili"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Controllo della modalità di test dell\'auto"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Controllo della modalità di test dell\'auto"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Attiva o disattiva le funzionalità dell\'auto"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Attiva o disattiva le funzionalità dell\'auto."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"Uso del watchdog dell\'auto"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Consente di usare il watchdog dell\'auto."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mio dispositivo"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Ospite"</string>
 </resources>
diff --git a/service/res/values-iw/strings.xml b/service/res/values-iw/strings.xml
index f4e9edb..8c93a62 100644
--- a/service/res/values-iw/strings.xml
+++ b/service/res/values-iw/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"גישה למצלמות הרכב."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"גישה למידע על נתוני צריכת האנרגיה של הרכב"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"גישה למידע על אנרגיית הרכב"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"התאמה של הטווח הנותר של הרכב"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"התאמת הערך של הטווח הנותר של הרכב."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"גישה למערכת החימום, הקירור והאוורור של הרכב"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"גישה למערכת החימום, האוורור ומיזוג האוויר (HVAC) של הרכב."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"גישה לנתוני הקילומטראז\' של הרכב"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"הגדרת הגבלות של חוויית משתמש (UX)"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"תקשורת באמצעות מכשיר USB במצב AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"מאפשרת לאפליקציה לתקשר עם מכשיר במצב AOAP ‏(Android Open Accessory Protocol)"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"גישת קריאה אל מערכת המודעות לתפוסה (Occupant Awareness)"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"הרשאה לסטטוס קריאה ונתוני זיהוי למערכת המודעות לתפוסה (Occupant Awareness)"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"שליטה בתרשים של מערכת המודעות לתפוסה (Occupant Awareness)"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"הרשאה לשליטה בהתחלה ובסיום של תרשים הזיהוי של מערכת המודעות לתפוסה (Occupant Awareness)"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"שירות הקלט של הרכב"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ניהול אירועי קלט"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"פרוטוקול CAN bus נכשל"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"גישה למידע מפורט על מנוע הרכב."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"גישה לפתח מכל הדלק וליציאת הטעינה של הרכב"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"גישה לפתח מכל הדלק וליציאת הטעינה של הרכב."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"שליטה בפתח מכל הדלק וביציאת הטעינה של המכונית"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"שליטה בפתח מכל הדלק וביציאת הטעינה של המכונית."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"קריאת פרטי הזיהוי של הרכב"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"גישה לפרטי הזיהוי של הרכב."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"שליטה בדלתות הרכב"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"שליטה במושבי הרכב."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"גישה לנתונים הבסיסיים של הרכב"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"גישה לנתונים הבסיסיים של הרכב."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"מתן גישה למידע לגבי הרשאת הספק של המכונית"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"מתן גישה למידע לגבי הרשאת הספק של המכונית."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"קריאה של מצב הפנסים החיצוניים של הרכב"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"גישה למצב הפנסים החיצוניים של הרכב."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"קריאת נתונים על הפנסים החיצוניים של הרכב"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"הפעלת רישום של מכשירים מהימנים"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"שליטה במצב הבדיקה של הרכב"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"שליטה במצב הבדיקה של הרכב"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"הפעלה או השבתה של תכונות המכונית"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"הפעלה או השבתה של תכונות המכונית."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"שימוש בטיימר המפקח (watchdog) של המכונית"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"שימוש בטיימר המפקח (watchdog) של המכונית."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"המכשיר שלי"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"אורח"</string>
 </resources>
diff --git a/service/res/values-ja/strings.xml b/service/res/values-ja/strings.xml
index 5c92e38..10db486 100644
--- a/service/res/values-ja/strings.xml
+++ b/service/res/values-ja/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"車載カメラにアクセスします。"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"車のエネルギー情報へのアクセス"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"車のエネルギー情報にアクセスします。"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"車の航続可能距離の調整"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"車の航続可能距離の値を調整します。"</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"車のエアコン ユニットへのアクセス"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"車のエアコン ユニットにアクセスします。"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"車の走行距離情報へのアクセス"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX 制限を設定します"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"AOAP モードでの USB デバイスとの通信"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"AOAP モードでのデバイスとの通信をアプリに許可"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"乗員検知システムの読み取りアクセス"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"乗員検知システムのステータスと検知データの読み取りを許可します"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"乗員検知システムグラフの操作"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"乗員検知システムの検知グラフの開始および終了操作を許可します"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"車の入力サービス"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"入力イベントを処理します"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN バスでエラーが発生しました"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"車の詳細なエンジン情報にアクセスします。"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"車の給油口と充電ポートへのアクセス"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"車の給油口と充電ポートにアクセスします。"</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"車の給油口と充電ポートの制御"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"車の給油口と充電ポートの制御"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"車の ID の読み取り"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"車の ID にアクセスします。"</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"車のドアの操作"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"カーシートを調節します。"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"車の基本情報へのアクセス"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"車の基本情報にアクセスします。"</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"車のベンダー権限情報へのアクセス"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"車のベンダー権限情報にアクセスします。"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"車のエクステリア ライトの状態の読み取り"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"車のエクステリア ライトの状態にアクセスします。"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"車のエクステリア ライトの読み取り"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"信頼できるデバイスの登録を許可"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"車のテストモードの制御"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"車のテストモードの制御"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"車の機能を有効または無効にします"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"車の機能を有効または無効にします。"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"車のウォッチドッグの使用"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"車のウォッチドッグの使用。"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"自分のデバイス"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"ゲスト"</string>
 </resources>
diff --git a/service/res/values-ka/strings.xml b/service/res/values-ka/strings.xml
index 9fb70b1..b4cd61a 100644
--- a/service/res/values-ka/strings.xml
+++ b/service/res/values-ka/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"თქვენი მანქანის კამერებზე წვდომა."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"მანქანის ენერგორესურსების ინფორმაციაზე წვდომა"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"თქვენი მანქანის ენერგორესურსების ინფორმაციაზე წვდომა."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"მანქანის დიაპაზონის ნარჩენის კორექტირება"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"მანქანის დიაპაზონის დარჩენილი მნიშვნელობის კორექტირება."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"მანქანის HVAC (გათბობა, ვენტილაცია და ჰაერის კონდიცირება) სისტემაზე წვდომა"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"თქვენი მანქანის HVAC (გათბობა, ვენტილაცია და ჰაერის კონდიცირება) სისტემაზე წვდომა."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"მანქანის გარბენის შესახებ ინფორმაციაზე წვდომა"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX შეზღუდვების კონფიგურაცია"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"USB მოწყობილობასთან AOAP რეჟიმში კომუნიკაცია"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"აპს აძლევს მოწყობილობასთან AOAP რეჟიმში კომუნიკაციის საშუალებას"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"წვდომა მძღოლის ინფორმირების სისტემის წასაკითხად"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"იძლევა მძღოლის ინფორმირების სისტემის სტატუსისა და ამოცნობის მონაცემების წაკითხვის საშუალებას"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"მძღოლის ინფორმირების სისტემის დიაგრამის მართვა"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"იძლევა მძღოლის ინფორმირების სისტემის გაშვების მართვისა და ამოცნობის დიაგრამის შეწყვეტის საშუალებას"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"მანქანის შეყვანის სერვისი"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"შეტანის მოვლენების დამუშავება"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"წარმოიშვა CAN-სალტის შეცდომა"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"მანქანის ძრავის დეტალურ ინფორმაციაზე წვდომა."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"მანქანის საწვავის ავზის ხუფზე და დამტენ პორტზე წვდომა"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"მანქანის საწვავის ავზის ხუფზე და დამტენ პორტზე წვდომა."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"მანქანის საწვავის ავზის კარის და დამტენი პორტის მართვა"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"მანქანის საწვავის ავზის კარის და დამტენი პორტის მართვა."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"მანქანის საიდენტიფიკაციო მონაცემების წაკითხვა"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"მანქანის საიდენტიფიკაციო მონაცემებზე წვდომა."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"მანქანის კარების გაკონტროლება"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"მანქანის სავარძლების გაკონტროლება."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"მანქანის ძირითად ინფორმაციაზე წვდომა"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"მანქანის ძირითად ინფორმაციაზე წვდომა."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"მანქანის მწარმოებლის ნებართვასთან დაკავშირებულ ინფორმაციაზე წვდომა"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"მანქანის მწარმოებლის ნებართვასთან დაკავშირებულ ინფორმაციაზე წვდომა."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"მანქანის გარე განათების მდგომარეობის წაკითხვა"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"მანქანის გარე განათების მდგომარეობაზე წვდომა."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"მანქანის გარე განათების წაკითხვა"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"სანდო მოწყობილობის რეგისტრაციის დაშვება"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"მანქანის სატესტო რეჟიმის გაკონტროლება"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"მანქანის სატესტო რეჟიმის გაკონტროლება"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"მანქანის ფუნქციების ჩართვა ან გათიშვა"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"მანქანის ფუნქციების ჩართვა ან გათიშვა."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"მანქანის დაცვის მოწყობილობის გამოყენება"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"მანქანის დაცვის მოწყობილობის გამოყენება."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ჩემი მოწყობილობა"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"სტუმარი"</string>
 </resources>
diff --git a/service/res/values-kk/strings.xml b/service/res/values-kk/strings.xml
index c3d0aea..14e925e 100644
--- a/service/res/values-kk/strings.xml
+++ b/service/res/values-kk/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Көліктің камераларын пайдалануға болады."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"көлік қуаты туралы ақпаратты пайдалану"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Көліктің қуаты туралы ақпаратты көруге болады."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"көліктің қалған жүріп өтетін жолын өзгерту"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Көліктің қалған жүріп өтетін жолының мәнін өзгерту"</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"көліктің климат басқару жүйесін пайдалану"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Көліктің кондиционерін пайдалануға болады."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"көліктің километражы туралы ақпаратты пайдалану"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX шектеулерін конфигурациялау"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"USB құрылғысымен AOAP режимінде байланыс орнату"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Қолданбаға AOAP режиміндегі құрылғымен байланыс орнатуға мүмкіндік береді."</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Жолаушыларды бақылау жүйесін оқуға рұқсат ету"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Жолаушыларды бақылау жүйесінің күйін оқуға және деректерді анықтауға мүмкіндік береді."</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Жолаушыларды бақылау жүйесі графигі"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Жолаушыларды бақылау жүйесі графигінің басталуы мен аяқталуын басқаруға мүмкіндік береді."</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Көліктің дерек енгізу қызметі"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Деректерді енгізу оқиғаларын басқаруға болады"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN шинасы істен шықты"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Көліктің қозғалтқышы туралы толық ақпаратты пайдалану."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"көліктің жанармай құю саңылауын және зарядтау портын пайдалану"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Көліктің жанармай құю саңылауын және зарядтау портын пайдалану."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"көліктің жанармай құю саңылауын және зарядтау портын пайдалану"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Көліктің жанармай құю саңылауын және зарядтау портын пайдалану."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"көліктің идентификациялық нөмірін көру"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Көліктің идентификациялық нөмірін пайдалану."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"көлік есіктерін басқару"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Көлік орындықтарын басқару."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"көліктің негізгі ақпаратын пайдалану"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Көлік туралы негізгі ақпаратты пайдалану."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"автокөлік өндірушісінің рұқсаты туралы ақпаратты пайдалану"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Автокөлік өндірушісінің рұқсаты туралы ақпаратты пайдалану."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"көліктің сыртқы шамдарының күйін көру"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Көліктің сыртқы шамдарының күйін көру."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"көліктің сыртқы шамдарын көру"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Сенімді құрылғыларды тіркеуге рұқсат ету"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Көліктің сынақ режимін бақылау"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Көліктің сынақ режимін бақылау"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Көлік функцияларын қосыңыз немесе өшіріңіз."</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Көлік функцияларын қосыңыз немесе өшіріңіз."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"көлік бақылау жүйесін пайдалану"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Көлік бақылау жүйесін пайдалану."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Құрылғым"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Қонақ"</string>
 </resources>
diff --git a/service/res/values-km/strings.xml b/service/res/values-km/strings.xml
index 7648697..cec9d5d 100644
--- a/service/res/values-km/strings.xml
+++ b/service/res/values-km/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"ចូលប្រើ​កាមេរ៉ារបស់​រថយន្តអ្នក។"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"ចូលប្រើ​ព័ត៌មាន​អំពីថាមពលរបស់​រថយន្ត"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"ចូលប្រើ​ព័ត៌មាន​ថាមពលរបស់​រថយន្តអ្នក។"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"កែតម្រូវ​រយៈចម្ងាយ​ដែលរថយន្តអាចបន្ត​ដំណើរការបាន"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"កែតម្រូវ​តម្លៃ​នៃរយៈចម្ងាយ​ដែលរថយន្តអាចបន្ត​ដំណើរការបាន។"</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"ចូលប្រើ​ប្រព័ន្ធកម្តៅ ខ្យល់ និងម៉ាស៊ីនត្រជាក់​របស់​រថយន្ត"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"ចូលប្រើ​ប្រព័ន្ធកម្តៅ ខ្យល់ និងម៉ាស៊ីនត្រជាក់​របស់រថយន្តអ្នក។"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"ចូលប្រើព័ត៌មាន​អំពីរយៈចម្ងាយរត់​របស់រថយន្ត"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"កំណត់រចនាសម្ព័ន្ធ​ការរឹតបន្តឹង UX"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"ទាក់ទងជាមួយ​ឧបករណ៍ USB តាមរយៈមុខងារ AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"អនុញ្ញាតឱ្យ​កម្មវិធី​ទាក់ទង​ជាមួយឧបករណ៍តាមរយៈមុខងារ AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"សិទ្ធិ​ចូលអាន​ប្រព័ន្ធ​នៃ​ការយល់ដឹង​អំពី​អ្នកជិះ​ក្នុងរថយន្ត"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"អនុញ្ញាត​ការអាន​ស្ថានភាព និង​ទិន្នន័យ​អំពី​ការចាប់​ប្រព័ន្ធ​នៃ​ការយល់ដឹង​អំពី​អ្នកជិះ​ក្នុងរថយន្ត"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"គ្រប់គ្រង​ក្រាហ្វ​អំពី​ប្រព័ន្ធ​នៃ​ការយល់ដឹង​អំពី​អ្នកជិះ​ក្នុងរថយន្ត"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"អនុញ្ញាត​ការគ្រប់គ្រង​ការចាប់ផ្ដើម និង​ការបញ្ឈប់​ក្រាហ្វ​អំពីការចាប់​ប្រព័ន្ធ​នៃ​ការយល់ដឹង​អំពី​អ្នកជិះ​ក្នុងរថយន្ត"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"សេវាកម្ម​បញ្ចូលរបស់​រថយន្ត"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"គ្រប់គ្រង​ព្រឹត្តិការណ៍​បញ្ចូល"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"មិនអាច​ដំណើរការ CAN bus បានទេ"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"ចូលប្រើ​ព័ត៌មាន​លម្អិត​អំពីម៉ាស៊ីនរថយន្តរបស់អ្នក។"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"ចូលប្រើ​គម្របសាំង និងរន្ធសាក​អាគុយរថយន្ត។"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"ចូលប្រើ​គម្របសាំង និងរន្ធសាក​អាគុយរថយន្ត។"</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"គ្រប់គ្រង​គម្រប​សាំង និង​រន្ធ​សាក​អាគុយ​រថយន្ត"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"គ្រប់គ្រង​គម្របសាំង និង​រន្ធ​សាក​អាគុយ​រថយន្ត​។"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"អាន​អត្តសញ្ញាណរថយន្ត"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"ចូលប្រើ​អត្តសញ្ញាណរថយន្ត។"</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"គ្រប់គ្រង​ទ្វាររថយន្ត"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"គ្រប់គ្រង​កៅអី​រថយន្ត។"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"ចូលប្រើ​ព័ត៌មាន​មូលដ្ឋាន​របស់រថយន្ត"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"ចូលប្រើ​ព័ត៌មាន​មូលដ្ឋាន​របស់រថយន្ត។"</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"ចូលប្រើ​ព័ត៌មាន​អំពី​ការអនុញ្ញាត​ពី​អ្នកលក់​របស់​រថយន្ត"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"ចូលប្រើ​ព័ត៌មាន​អំពី​ការអនុញ្ញាត​ពី​អ្នកលក់​របស់​រថយន្ត​។"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"អានស្ថានភាពភ្លើងផ្នែក​ខាងក្រៅ​រថយន្ត"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"ចូលប្រើ​ស្ថានភាពភ្លើង​ផ្នែកខាងក្រៅ​រថយន្ត។"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"អានភ្លើងផ្នែកខាងក្រៅ​រថយន្ត"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"អនុញ្ញាតឱ្យចុះ​ឈ្មោះឧបករណ៍​ដែល​ទុក​ចិត្ត"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"គ្រប់គ្រង​មុខងារ​ធ្វើតេស្តរបស់​រថយន្ត"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"គ្រប់គ្រង​មុខងារ​ធ្វើតេស្តរបស់​រថយន្ត"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"បើក ឬ​បិទ​មុខងារ​របស់​រថយន្ត"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"បើក ឬ​បិទ​មុខងារ​របស់​រថយន្ត​។"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"ប្រើប្រាស់សេវា​មើល​ការ​ខុស​ត្រូវ​ស្ថានភាព​កម្មវិធី​របស់​ឡាន"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"ប្រើប្រាស់​សេវា​មើល​ការ​ខុស​ត្រូវ​ស្ថានភាព​កម្មវិធី​របស់​ឡាន។"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ឧបករណ៍របស់ខ្ញុំ"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"ភ្ញៀវ"</string>
 </resources>
diff --git a/service/res/values-kn/strings.xml b/service/res/values-kn/strings.xml
index 36f565e..1ee0f44 100644
--- a/service/res/values-kn/strings.xml
+++ b/service/res/values-kn/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"ನಿಮ್ಮ ಕಾರಿನ ಕ್ಯಾಮರವನ್ನು(ಗಳನ್ನು) ಪ್ರವೇಶಿಸಿ."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"ಕಾರಿನ ಶಕ್ತಿಯ ಬಳಕೆಯ ಮಾಹಿತಿ ಕುರಿತು ಪ್ರವೇಶಿಸಿ"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"ನಿಮ್ಮ ಕಾರಿನ ಶಕ್ತಿ ಮಾಹಿತಿಯನ್ನು ಪಡೆಯಿರಿ."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"ಬಾಕಿ ಉಳಿದ ಕಾರ್‌ನ ಶ್ರೇಣಿಯನ್ನು ಸರಿಹೊಂದಿಸಿ"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"ಕಾರ್‌ನ ಶ್ರೇಣಿಯ ಬಾಕಿ ಉಳಿದ ಮೌಲ್ಯವನ್ನು ಸರಿಹೊಂದಿಸಿ."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"ಕಾರಿನ ಹವಾನಿಯಂತ್ರಕದ ಮಾಹಿತಿ ಪಡೆಯಿರಿ"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"ಕಾರಿನ ಎಚ್‌ವಿಎಸಿಯ ಮಾಹಿತಿನ್ನು ಪಡೆಯಿರಿ."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"ಕಾರಿನ ಮೈಲೇಜ್ ಮಾಹಿತಿಯನ್ನು ಪಡೆಯಿರಿ"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"ಯುಎಕ್ಸ್ ನಿರ್ಬಂಧಗಳನ್ನು ಸಂರಚಿಸು"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"AOAP ಮೋಡ್‌ನಲ್ಲಿ USB ಸಾಧನದ ಜೊತೆಗೆ ಸಂವಹನ ನಡೆಸಿ"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"AOAP ಮೋಡ್‌ನಲ್ಲಿ ಸಾಧನದ ಜೊತೆಗೆ ಸಂವಹನ ನಡೆಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant Awareness System ರೀಡ್ ಆ್ಯಕ್ಸೆಸ್"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Occupant Awareness System ಗಾಗಿ ಓದುವ ಸ್ಥಿತಿ ಮತ್ತು ಪತ್ತೆಹಚ್ಚುವಿಕೆ ಡೇಟಾವನ್ನು ಅನುಮತಿಸುತ್ತದೆ"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Occupant Awareness System Graph ಅನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Occupant Awareness System ಪತ್ತೆಹಚ್ಚುವಿಕೆ ಗ್ರಾಫ್‌ನ ಪ್ರಾರಂಭಿಸಲು ಮತ್ತು ನಿಲ್ಲಿಸುವುದನ್ನು ನಿಯಂತ್ರಿಸಲು ನಿಮಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"ಕಾರಿನ ಇನ್‌ಪುಟ್ ಸೇವೆ"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ಊಡಿಕೆ ಘಟನೆಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"ಸಿಎಎನ್ ಬಸ್ ಕೆಟ್ಟಿದೆ"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"ಕಾರಿನ ಇಂಜಿನ್‌ನ ವಿವರಣೆಯ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಿ."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"ಕಾರಿನ ಇಂಧನ ಪಂಪ್‌ನ ಮುಚ್ಚಳ ಮತ್ತು ಚಾರ್ಜ್ ಪೋರ್ಟ್ ಮಾಹಿತಿ ಪಡೆಯಿರಿ"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"ಕಾರಿನ ಇಂಧನ ಪಂಪ್‌ನ ಮುಚ್ಚಳ ಮತ್ತು ಚಾರ್ಜ್ ಪೋರ್ಟ್ ಅನ್ನು ಪ್ರವೇಶಿಸಿ."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"ಕಾರ್‌ನ ಇಂಧನ ಪಂಪ್‌ನ ಮುಚ್ಚಳ ಮತ್ತು ಚಾರ್ಜ್ ಪೋರ್ಟ್ ಅನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"ಕಾರ್‌ನ ಇಂಧನ ಪಂಪ್‌ನ ಮುಚ್ಚಳ ಮತ್ತು ಚಾರ್ಜ್ ಪೋರ್ಟ್ ಅನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"ಕಾರಿನ ಗುರುತನ್ನು ಓದಿ"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"ಕಾರಿನ ಗುರುತನ್ನು ಪಡೆಯಿರಿ."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"ಕಾರಿನ ಬಾಗಿಲುಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"ಕಾರಿನ ಆಸನಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"ಕಾರಿನ ಮೂಲ ಮಾಹಿತಿಯನ್ನು ಪಡೆಯಿರಿ"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"ಕಾರಿನ ಮೂಲ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಿ."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"ಕಾರಿನ ಮಾರಾಟಗಾರರ ಅನುಮತಿ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"ಕಾರಿನ ಮಾರಾಟಗಾರರ ಅನುಮತಿ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಿ."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"ಕಾರಿನ ಹೊರಾಂಗಣ ಲೈಟ್‌ಗಳ ಸ್ಥಿತಿಯ ಮಾಹಿತಿಯನ್ನು ಓದಿ"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"ಕಾರಿನ ಹೊರಾಂಗಣ ಲೈಟ್‌ಗಳ ಸ್ಥಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಿ."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ಕಾರಿನ ಹೊರಾಂಗಣ ಲೈಟ್‌ಗಳ ಮಾಹಿತಿಯನ್ನು ಓದಿ"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"ವಿಶ್ವಾಸಾರ್ಹ ಸಾಧನಗಳ ನೋಂದಣಿಯನ್ನು ಅನುಮತಿಸಿ"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"ಕಾರ್‌ನ ಪರೀಕ್ಷಾ ಮೋಡ್ ಅನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"ಕಾರ್‌ನ ಪರೀಕ್ಷಾ ಮೋಡ್ ಅನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"ಕಾರ್ ಫೀಚರ್‌ಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ ಅಥವಾ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"ಕಾರ್ ಫೀಚರ್‌ಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ ಅಥವಾ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"ಕಾರ್ ಮಾನಿಟರಿಂಗ್ ಟೈಮರ್ ಬಳಸಿ"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"ಕಾರ್ ಮಾನಿಟರಿಂಗ್ ಟೈಮರ್ ಬಳಸಿ."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ನನ್ನ ಸಾಧನ"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"ಅತಿಥಿ"</string>
 </resources>
diff --git a/service/res/values-ko/strings.xml b/service/res/values-ko/strings.xml
index 2f67908..2e1e845 100644
--- a/service/res/values-ko/strings.xml
+++ b/service/res/values-ko/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"차량 카메라에 액세스"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"차량 에너지 정보 액세스"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"차량 에너지 정보에 액세스"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"차량의 잔여 주행거리 조정"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"차량의 잔여 주행거리를 조정하세요."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"차량 공조기에 액세스"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"차량 공조기에 액세스합니다."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"차량 주행 거리 정보에 액세스"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX 제한사항 설정"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"AOAP 모드의 USB 기기와 통신"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"AOAP 모드의 기기와 통신하도록 앱을 허용하세요."</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant Awareness System 읽기 액세스"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Occupant Awareness System의 상태 및 감지 데이터를 읽는 것을 허용합니다."</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Occupant Awareness System 그래프 제어"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Occupant Awareness System 감지 그래프의 시작 및 중지를 제어하는 것을 허용합니다."</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"차량 입력 서비스"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"입력 이벤트 처리"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN 버스 실패"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"차량의 상세한 엔진 정보에 액세스합니다."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"차량 주유구 캡 및 충전 포트 액세스"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"차량의 주유구 캡 및 충전 포트에 액세스합니다."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"차량 주유구 캡 및 충전 포트 액세스 제어"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"차량 주유구 캡 및 충전 포트 액세스를 제어합니다."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"차량 ID 읽기"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"차량 ID에 액세스합니다."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"차량 도어 제어"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"차량 시트를 제어합니다."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"차량의 기본 정보에 액세스"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"차량의 기본 정보에 액세스합니다."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"차량 공급업체 권한 정보에 액세스합니다."</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"차량 공급업체 권한 정보에 액세스합니다."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"차량 외부 조명 상태 읽기"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"차량의 외부 조명 상태에 액세스합니다."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"차량 외부 조명 읽기"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"신뢰할 수 있는 기기 등록 허용"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"차량 테스트 모드 제어"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"차량 테스트 모드 제어"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"차량 기능 사용 설정 또는 사용 중지"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"차량 기능 사용 설정 또는 사용 중지"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"차량 워치독을 사용합니다."</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"차량 워치독을 사용합니다."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"내 기기"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"게스트"</string>
 </resources>
diff --git a/service/res/values-ky/strings.xml b/service/res/values-ky/strings.xml
index a239eb7..294da79 100644
--- a/service/res/values-ky/strings.xml
+++ b/service/res/values-ky/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Унааңыздын камераларын колдонуу."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"унаанын кубаты тууралуу маалыматты көрүү"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Унааңыздын кубаты тууралуу маалыматты көрүү."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"унаа дагы канча аралыкты басып өтөрүн тууралоо"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Унаа дагы канча аралыкты басып өтөрүн тууралоо."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"унаанын жылыткыч жана вентилиция тутумдарын көрүү"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Унааңыздын жылыткыч жана вентилиция тутумдарын көрүү."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"унаанын километраж маалыматын көрүү"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"КТ чектөөлөрүн конфигурациялоо"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"USB түзмөгү менен AOAP режиминде байланышуу"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Колдономого түзмөк менен AOAP режиминде байланышууга мүмкүнчүлүк берет"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Тургундарды көзөмөлдөө тутумунун абалын окууга мүмкүнчүлүк алуу"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Тургундарды көзөмөлдөө тутумундагы статусту окуп, маалыматты аныктоого мүмкүнчүлүк берет"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Тургундарды көзөмөлдөө тутумунун диаграммасы"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Тургундарды көзөмөлдөө тутумун аныктоо диаграммасын иштетүүнү жана токтотууну көзөмөлдөөгө мүмкүнчүлүк берет"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Унаанын киргизүү кызматы"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Киргизүү аракеттерин башкаруу"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN иштебей калды"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Унааңыздын кыймылдаткычы тууралуу толук маалыматты көрүү."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"унаанын май куюучу тешигине жана кубаттоо оюкчасына мүмкүнчүлүк алуу"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Унаанын май куюучу тешигине жана кубаттоо оюкчасына мүмкүнчүлүк алуу."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"унаанын май куюучу тешигин жана кубаттоо оюкчасын көзөмөлдөө"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Унаанын май куюучу тешигин жана кубаттоо оюкчасын көзөмөлдөө."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"унаанын идентификаторун көрүү"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Унаанын идентификаторун көрүү."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"унаанын эшиктерин көзөмөлдөө"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Унаадагы орундуктарды көзөмөлдөө."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"унаанын негизги маалыматына мүмкүнчүлүк алуу"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Унаанын негизги маалыматына мүмкүнчүлүк алуу."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"унааны сатуучунун уруксатына тиешелүү маалымат"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Унааны сатуучунун уруксатына тиешелүү маалыматты көрүү."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"унаанын сыртындагы жарыктарынын абалын көрүү"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Унаанын сыртындагы жарыктарынын абалына мүмкүнчүлүк алуу."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"унаанын сыртындагы жарыктарын көзөмөлдөө"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Ишенимдүү түзмөктү каттоого уруксат берүү"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Унаанын сыноо режимин көзөмөлдөө"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Унаанын сыноо режимин көзөмөлдөө"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Унаанын функцияларын иштетүү же өчүрүү"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Унаанын функцияларын иштетүү же өчүрүү."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"унаанын кароолун колдонуу"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Унаанын кароолун колдонуу."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Түзмөгүм"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Конок"</string>
 </resources>
diff --git a/service/res/values-lo/strings.xml b/service/res/values-lo/strings.xml
index 37bc6f6..8691783 100644
--- a/service/res/values-lo/strings.xml
+++ b/service/res/values-lo/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"ເຂົ້າເຖິງກ້ອງຂອງລົດທ່ານ."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"ເຂົ້າເຖິງຂໍ້ມູນພະລັງງານຂອງລົດ"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"ເຂົ້າເຖິງຂໍ້ມູນພະລັງງານຂອງລົດທ່ານ."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"ປັບໄລຍະແລ່ນທີ່ເຫຼືອຢູ່ຂອງລົດ"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"ປັບຄ່າໄລຍະແລ່ນທີ່ເຫຼືອຢູ່ຂອງລົດ"</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"ເຂົ້າເຖິງ HVAC ຂອງລົດ"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"ເຂົ້າເຖິງ HVAC ຂອງລົດທ່ານ."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"ເຂົ້າເຖິງຂໍ້ມູນໄລຍະໄມລ໌ຂອງລົດ"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"ກຳນົດຄ່າຂໍ້ຈຳກັດ UX"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"ສື່ສານກັບອຸປະກອນ USB ໃນໂໝດ AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"ອະນຸຍາດໃຫ້ແອັບສື່ສານກັບອຸປະກອນໃນໂໝດ AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"ສິດເຂົ້າເຖິງການອ່ານຂອງລະບົບການຮັບຮູ້ວ່າມີຄົນຢູ່"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"ອະນຸຍາດການອ່ານຂໍ້ມູນສະຖານະ ແລະ ການກວດຫາສຳລັບລະບົບການຮັບຮູ້ວ່າມີຄົນຢູ່"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"ຄວບຄຸມກຣາຟຂອງລະບົບການຮັບຮູ້ວ່າມີຄົນຢູ່"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"ອະນຸຍາດການຄວບຄຸມການເລີ່ມ ແລະ ການຢຸດສຳລັບກຣາຟການກວດຫາຂອງລະບົບການຮັບຮູ້ວ່າມີຄົນຢູ່"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"ການບໍລິການປ້ອນຂໍ້ມູນຂອງລົດ"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ຈັດການເຫດການປ້ອນຂໍ້ມູນ"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus ບໍ່ສຳເລັດ"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"ເຂົ້າເຖິງຂໍ້ມູນເຄື່ອງຈັກລະອຽດຂອງລົດທ່ານ."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"ເຂົ້າເຖິງຂໍ້ມູນຝານໍ້າມັນ ແລະ ຮູສາກໄຟຂອງລົດ"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"ເຂົ້າເຖິງຂໍ້ມູນຝານໍ້າມັນ ແລະ ຮູສາກໄຟຂອງລົດ."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"ຄວບຄຸມຂໍ້ມູນຝານໍ້າມັນ ແລະ ຮູສາກຂອງລົດ"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"ຄວບຄຸມຂໍ້ມູນຝານໍ້າມັນ ແລະ ຮູສາກຂອງລົດ."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"ອ່ານການລະບຸຕົວລົດ"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"ເຂົ້າເຖິງການລະບຸຕົວລົດ."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"ຄວບຄຸມປະຕູລົດ"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"ຄວບຄຸມບ່ອນນັ່ງໃນລົດ."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"ເຂົ້າເຖິງຂໍ້ມູນພື້ນຖານຂອງລົດ"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"ເຂົ້າເຖິງຂໍ້ມູນພື້ນຖານຂອງລົດ."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"ເຂົ້າເຖິງຂໍ້ມູນການອະນຸຍາດຂອງຜູ້ຂາຍລົດ"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"ເຂົ້າເຖິງຂໍ້ມູນການອະນຸຍາດຂອງຜູ້ຂາຍລົດ."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"ອ່ານສະຖານະໄຟພາຍນອກຂອງລົດ"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"ເຂົ້າເຖິງສະຖານະໄພພາຍນອກຂອງລົດ."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ອ່ານສະຖານໄຟພາຍນອກລົດ"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"ອະນຸຍາດການລົງທະບຽນອຸປະກອນທີ່ເຊື່ອຖືໄດ້"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"ຄວບຄຸມໂໝດທົດສອບຂອງລົດ"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"ຄວບຄຸມໂໝດທົດສອບຂອງລົດ"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"ເປີດນຳໃຊ້ ຫຼື ປິດການນຳໃຊ້ຄຸນສົມບັດຂອງລົດ"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"ເປີດນຳໃຊ້ ຫຼື ປິດການນຳໃຊ້ຄຸນສົມບັດຂອງລົດ."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"ໃຊ້ Watchdog ໃນລົດ"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"ໃຊ້ Watchdog ໃນລົດ."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ອຸປະກອນຂອງຂ້ອຍ"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"ແຂກ"</string>
 </resources>
diff --git a/service/res/values-lt/strings.xml b/service/res/values-lt/strings.xml
index ba49a7f..3cc8d44 100644
--- a/service/res/values-lt/strings.xml
+++ b/service/res/values-lt/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Pasiekti automobilio fotoaparatą (-us)."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"pasiekti automobilio energijos informaciją"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Pasiekti automobilio energijos informaciją."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"koreguoti automobilio likusį atstumą"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Koreguokite automobilio likusio atstumo vertę."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"pasiekti automobilio HVAC"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Pasiekti automobilio HVAC."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"pasiekti automobilio ridos informaciją"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfigūruoti NP apribojimus"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Užmegzti ryšį su USB įrenginiu AOAP režimu"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Programai leidžiama užmegzti ryšį su įrenginiu AOAP režimu"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Keleivių stebėjimo sistemos skaitymo prieiga"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Leidžiama skaityti duomenis apie keleivių stebėjimo sistemos skaitymo būseną ir aptikimą"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Valdyti keleivių stebėjimo sistemos diagramą"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Leidžiama įjungti ir sustabdyti keleivių stebėjimo sistemos aptikimo diagramą"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Automobilio įvesties paslauga"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Apdoroti įvesties įvykius."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN BUS klaida"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Pasiekti išsamią automobilio variklio informaciją."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"pasiekti automobilio degalų bako dureles ir įkrovimo prievadą"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Pasiekti automobilio degalų bako dureles ir įkrovimo prievadą."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"valdyti automobilio degalų bako dureles ir įkrovimo prievadą"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Valdyti automobilio degalų bako dureles ir įkrovimo prievadą."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"nuskaityti automobilio identifikavimo duomenis"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Pasiekti automobilio identifikavimo duomenis."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"valdyti automobilio dureles"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Valdyti automobilio sėdynes."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"pasiekti pagrindinę automobilio informaciją"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Pasiekti pagrindinę automobilio informaciją."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"pasiekti automobilio paslaugų teikėjo leidimo informaciją"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Pasiekti automobilio paslaugų teikėjo leidimo informaciją."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"nuskaityti automobilio išorinių žibintų būseną"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Pasiekti automobilio išorinių žibintų būseną."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"nuskaityti automobilio išorinių žibintų būseną"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Leisti užregistruoti patikimą įrenginį"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Valdyti automobilio bandomąjį režimą"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Valdyti automobilio bandomąjį režimą"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Įgalinti arba išjungti automobilio funkcijas"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Įgalinkite arba išjunkite automobilio funkcijas."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"naudoti automobilio apsauginį laikmatį"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Naudoti automobilio apsauginį laikmatį."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mano įrenginys"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Svečias"</string>
 </resources>
diff --git a/service/res/values-lv/strings.xml b/service/res/values-lv/strings.xml
index de2ce2d..aecbeb4 100644
--- a/service/res/values-lv/strings.xml
+++ b/service/res/values-lv/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Piekļūt automašīnas kamerai(-ām)."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"piekļūt informācijai par automašīnas degvielas/uzlādes līmeni"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Piekļūt informācijai par automašīnas enerģiju."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"pielāgot automašīnas atlikušo attālumu"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Pielāgojiet automašīnas atlikušā attāluma vērtību."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"piekļūt automašīnas gaisa kondicionētājam"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Piekļūt automašīnas gaisa kondicionēšanas sistēmai."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"piekļūt informācijai par automašīnas nobraukumu"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfigurēt lietotāja pieredzes ierobežojumus."</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Sazināties ar USB ierīci AOAP režīmā"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Ļauj lietotnei sazināties ar ierīci AOAP režīmā"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Lasīšanas piekļuve pasažieru uzraudzības sistēmai"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Ļauj lasīt pasažieru uzraudzības sistēmas statusu un noteikšanas datus."</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontrolēt pasažieru uzraudzības sistēmas diagrammu"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Ļauj kontrolēt pasažieru uzraudzības sistēmas noteikšanas diagrammas palaišanu un apturēšanu."</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Automašīnas ievades pakalpojums"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Apstrādāt ievades notikumus."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Radās atteice datu maģistrālē"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Piekļūt detalizētai informācijai par automašīnas dzinēju."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"piekļūt automašīnas degvielas tvertnes vāciņam un uzlādes pieslēgvietai"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Piekļūt automašīnas degvielas tvertnes vāciņam un uzlādes pieslēgvietai."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"kontrolēt automašīnas degvielas tvertnes vāciņu un uzlādes pieslēgvietu"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Kontrolēt automašīnas degvielas tvertnes vāciņu un uzlādes pieslēgvietu."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"nolasīt automašīnas identifikācijas numuru"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Piekļūt automašīnas identifikācijas numuram."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"kontrolēt automašīnas durvis"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kontrolēt automašīnas sēdekļus."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"piekļūt pamatinformācijai par automašīnu"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Piekļūt pamatinformācijai par automašīnu."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"piekļuve informācijai par automašīnas ražotāja atļaujām"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Piekļūt informācijai par automašīnas ražotāja atļaujām."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"nolasīt automašīnas lukturu stāvokli"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Piekļūt automašīnas lukturu stāvoklim."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"nolasīt automašīnas lukturus"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Atļaut uzticamu ierīču reģistrāciju"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"kontrolēt automašīnas testa režīmu"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Kontrolēt automašīnas testa režīmu"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Iespējot vai atspējot automašīnas funkcijas"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Iespējojiet vai atspējojiet automašīnas funkcijas."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"izmantot automašīnas sargierīci"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Izmantot automašīnas sargierīci."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mana ierīce"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Viesis"</string>
 </resources>
diff --git a/service/res/values-mk/strings.xml b/service/res/values-mk/strings.xml
index f554d96..8945ff6 100644
--- a/service/res/values-mk/strings.xml
+++ b/service/res/values-mk/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Пристапува до камерите на автомобилот."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"пристапува до информациите за енергијата на автомобилот"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Пристапува до информациите за енергијата на автомобилот."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"приспособете ја преостанатата вредност на опсегот на автомобилот"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Приспособете ја преостанатата вредност на опсегот на автомобилот."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"пристапува до клима-уредот на автомобилот"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Пристапува до клима-уредот на автомобилот."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"пристапува до информациите за километража на автомобилот"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Конфигурирајте ги ограничувањата на корисничкото искуство"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Комуницирајте со USB-уред во режим на AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Дозволува апликацијата да комуницира со уред во режим на AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Пристап за читање на „Системот за откривање патници“"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Овозможува читање на статусот и податоците на откривање за „Системот за откривање патници“"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Го контролира графиконот на „Системот за откривање патници“"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Овозможува контролирање на стартувањето и сопирањето на графиконот за откривање на „Системот за откривање патници“"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Влезна услуга на автомобилот"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Ракува со влезните настани"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-магистралата не успеа"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Пристапува до деталните информации за моторот на автомобилот."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"пристапува до вратата за гориво и портата за полнење на автомобилот"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Пристапува до вратата за гориво и портата за полнење на автомобилот."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"ја контролира вратата за гориво и портата за полнење на автомобилот"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Ја контролира вратата за гориво и портата за полнење на автомобилот."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"ја чита идентификацијата на автомобилот"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Пристапува до идентификацијата на автомобилот."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"ги контролира вратите на автомобилот"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Ги контролира седиштата на автомобилот."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"пристапува до основните информации за автомобилот"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Пристапува до основните информации за автомобилот."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"пристап до информациите за дозволи на продавачот"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Пристап до информациите за дозволи на продавачот."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"ја чита состојбата на надворешните светла на автомобилот"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Пристапува до состојбата на надворешните светла на автомобилот."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ги чита надворешните светла на автомобилот"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Дозволете регистрација на доверлив уред"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Контролирање на режимот за тестирање на автомобилот"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Контролирање на режимот за тестирање на автомобилот"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Овозможување или оневозможување функции на автомобилот"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Овозможување или оневозможување функции на автомобилот."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"ја користат „Заштитник за автомобилот“"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Ја користат „Заштитник за автомобилот“."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Мојот уред"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Гостин"</string>
 </resources>
diff --git a/service/res/values-ml/strings.xml b/service/res/values-ml/strings.xml
index e7463cd..4e8cf7e 100644
--- a/service/res/values-ml/strings.xml
+++ b/service/res/values-ml/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"നിങ്ങളുടെ കാറിന്റെ ക്യാമറ(കൾ) ആക്‌സസ് ചെയ്യുക."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"കാറിൻ്റെ എനർജി വിവരങ്ങൾ ആക്‌സസ് ചെയ്യുക"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"നിങ്ങളുടെ കാറിന്റെ എനർജി വിവരങ്ങൾ ആക്‌സസ് ചെയ്യുക."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"കാറിൽ ശേഷിക്കുന്ന ഇന്ധനം ക്രമീകരിക്കുക"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"കാറിൽ ശേഷിക്കുന്ന ഇന്ധനത്തിന്റെ മൂല്യം ക്രമീകരിക്കുക."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"കാറിൻ്റെ hvac ആക്‌സസ് ചെയ്യുക"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"നിങ്ങളുടെ കാറിന്റെ hvac ആക്‌സസ് ചെയ്യുക."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"കാറിൻ്റെ മൈലേജ് വിവരങ്ങൾ ആക്‌സസ് ചെയ്യുക"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX നിയന്ത്രണങ്ങൾ കോൺഫിഗർ ചെയ്യുക"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"AOAP മോഡിൽ USB ഉപകരണം ഉപയോഗിച്ച് ആശയവിനിമയം നടത്തുക"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"AOAP മോഡിലുള്ള ഉപകരണവുമായി ബന്ധപ്പെടാൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"ഒക്യുപന്റ് അവയർനെസ് സിസ്റ്റം വായനാ ആക്‌സസ്"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"ഒക്യുപന്റ് അവയർനെസ് സിസ്റ്റത്തിനുള്ള വായനാ നിലയും കണ്ടെത്തൽ ഡാറ്റയും അനുവദിക്കുന്നു"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"ഒക്യുപന്റ് അവയർനെസ് സിസ്റ്റം ഗ്രാഫ് നിയന്ത്രിക്കുക"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"ഒക്യുപന്റ് അവയർനെസ് സിസ്റ്റം കണ്ടെത്തൽ ഗ്രാഫിന്റെ ആരംഭവും നിർത്തലും നിയന്ത്രിക്കാൻ അനുവദിക്കുന്നു"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"കാറിന്റെ ഇൻപുട്ട് സേവനം"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ഇൻപുട്ട് ഇവന്റുകൾ കൈകാര്യം ചെയ്യുക"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN ബസ് പരാജയപ്പെട്ടു"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"നിങ്ങളുടെ കാറിൻ്റെ വിശദമായ എഞ്ചിൻ വിവരങ്ങൾ ആക്‌സസ് ചെയ്യുക."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"കാറിൻ്റെ ഇന്ധന വാതിലും ചാർജ് പോർട്ടും ആക്‌സസ് ചെയ്യുക"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"കാറിൻ്റെ ഇന്ധന വാതിലും ചാർജ് പോർട്ടും ആക്‌സസ് ചെയ്യുക."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"കാറിന്റെ ഇന്ധന വാതിലും ചാർജ് പോർട്ടും ആക്‌സസ് ചെയ്യുക"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"കാറിന്റെ ഇന്ധന വാതിലും ചാർജ് പോർട്ടും ആക്‌സസ് ചെയ്യുക."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"കാറിൻ്റെ ഐഡൻ്റിഫിക്കേഷൻ വായിക്കുക"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"കാറിൻ്റെ ഐഡൻ്റിഫിക്കേഷൻ ആക്‌സസ് ചെയ്യുക."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"കാറിൻ്റെ ഡോറുകൾ നിയന്ത്രിക്കുക"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"കാറിൻ്റെ സീറ്റുകൾ നിയന്ത്രിക്കുക."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"കാറിൻ്റെ അടിസ്ഥാന വിവരങ്ങൾ ആക്‌സസ് ചെയ്യുക"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"കാറിൻ്റെ അടിസ്ഥാന വിവരങ്ങൾ ആക്‌സസ് ചെയ്യുക."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"കാറിന്റെ വെൻഡർ അനുമതി വിവരങ്ങൾ ആക്‌സസ് ചെയ്യുക"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"കാറിന്റെ വെൻഡർ അനുമതി വിവരങ്ങൾ ആക്‌സസ് ചെയ്യുക."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"കാറിൻ്റെ പുറംഭാഗത്തെ ലൈറ്റുകളുടെ നില വായിക്കുക"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"കാറിൻ്റെ പുറംഭാഗത്തെ ലൈറ്റുകളുടെ നില ആക്‌സസ് ചെയ്യുക."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"കാറിൻ്റെ പുറംഭാഗത്തെ ലൈറ്റുകളുടെ നില വായിക്കുക"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"വിശ്വസ്‌ത ഉപകരണ എൻറോൾമെന്റ് അനുവദിക്കുക"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"കാറിന്റെ ടെസ്റ്റ് മോഡ് നിയന്ത്രിക്കുക"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"കാറിന്റെ ടെസ്റ്റ് മോഡ് നിയന്ത്രിക്കുക"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"കാറിന്റെ ഫീച്ചറുകൾ പ്രവർത്തനക്ഷമമോ പ്രവർത്തനരഹിതമോ ആക്കുക"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"കാറിന്റെ ഫീച്ചറുകൾ പ്രവർത്തനക്ഷമമോ പ്രവർത്തനരഹിതമോ ആക്കുക."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"കാർ പരിശോധനാ സിസ്‌റ്റം ഉപയോഗിക്കുക"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"കാർ പരിശോധനാ സിസ്‌റ്റം ഉപയോഗിക്കുക."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"എന്റെ ഉപകരണം"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"അതിഥി"</string>
 </resources>
diff --git a/service/res/values-mn/strings.xml b/service/res/values-mn/strings.xml
index b5f57dc..19d64b6 100644
--- a/service/res/values-mn/strings.xml
+++ b/service/res/values-mn/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Машиныхаа камерт хандана уу."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"машины эрчим хүчний мэдээлэлд хандах"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Машиныхаа эрчим хүчний мэдээлэлд хандана уу."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"автомашины туулах замын үлдсэн утгыг тохируулах"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Автомашины туулах замын үлдсэн утгыг тохируулна."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"машины халаалт, агааржуулалт болон aгаар цэвэршүүлэгчид хандах"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Машиныхаа халаалт, агааржуулалт болон aгаар цэвэршүүлэгчид хандана уу."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"машины милийн мэдээлэлд хандах"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX хязгаарлалтыг тохируулах"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"AOAP горимд байгаа USB төхөөрөмжтэй холбогдох"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Аппыг AOAP горимд байгаа төхөөрөмжтэй холбогдохыг зөвшөөрдөг"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Оршин суугчийн дохионы мэдээллийн системийг уншихад хандах"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Оршин суугчийн дохионы мэдээллийн системийн статус болон илрүүлэлтийн өгөгдлийг унших боломж олгодог"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Оршин суугчийн дохионы мэдээллийн системийн графикийг хянах"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Оршин суугчийн дохионы мэдээллийн системийн илрүүлэлтийн графикийг эхлүүлэх, зогсоохыг хянах боломж олгодог"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Машины оролтын үйлчилгээ"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Оролтын арга хэмжээг боловсруулах"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus амжилтгүй болсон"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Таны машины хөдөлгүүрийн дэлгэрэнгүй мэдээлэлд хандах."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"машины шатахууны савны таг болон цэнэглэх оролтод хандах"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Машины шатахууны савны таг болон цэнэглэх оролтод хандах."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"машины шатахууны савны таг болон цэнэглэх оролтыг хянах"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Машины шатахууны савны таг болон цэнэглэх оролтыг хянаарай."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"машины тодорхойлолтыг унших"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Машины тодорхойлолтод хандах."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"машины хаалгыг хянах"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Машины суудлыг хянах."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"машины ерөнхий мэдээлэлд хандах"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Машины ерөнхий мэдээлэлд хандах."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"машин нийлүүлэгчийн зөвшөөрлийн мэдээлэлд хандах"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Машин нийлүүлэгчийн зөвшөөрлийн мэдээлэлд хандана уу."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"машины гадна талын гэрлийн төлөвийг унших"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Машины гадна талын гэрлийн төлөвт хандах."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"машины гадна талын гэрлийн төлөвийг унших"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Итгэмжлэгдсэн төхөөрөмж бүртгэхийг зөвшөөрөх"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Машины тест горимыг хянах"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Машины тест горимыг хянах"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Автомашины онцлогуудыг идэвхжүүлэх эсвэл идэвхгүй болгох"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Автомашины онцлогуудыг идэвхжүүлж эсвэл идэвхгүй болгоно уу."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"машины watchdog-г ашиглана уу"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Машины watchdog-г ашиглана уу."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Миний төхөөрөмж"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Зочин"</string>
 </resources>
diff --git a/service/res/values-mr/strings.xml b/service/res/values-mr/strings.xml
index b04502c..4bd5aaf 100644
--- a/service/res/values-mr/strings.xml
+++ b/service/res/values-mr/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"तुमच्या कारचा(चे) कॅमेरा(रे) अ‍ॅक्सेस करा."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"कारच्या ऊर्जेची माहिती अ‍ॅक्सेस करा"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"तुमच्या कारची ऊर्जा माहिती अ‍ॅक्सेस करा."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"कारची शिल्लक रेंज अ‍ॅडजस्ट करा"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"कारच्या शिल्लक रेंजचे मूल्य अ‍ॅडजस्ट करा."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"कारचे hvac अ‍ॅक्सेस करा"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"तुमच्या कारचे hvac अ‍ॅक्सेस करा."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"कारच्या मायलेजची माहिती अ‍ॅक्सेस करा"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX निर्बंध कॉन्फिगर करा"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"USB डिव्हाइसशी AOAP मोडमध्ये कनेक्ट करा"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"अ‍ॅपला डिव्हाइसशी AOAP मोडमध्ये कनेक्ट करण्याची अनुमती देते"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"ऑक्युपंट अवेअरनेस सिस्टम वाचन अ‍ॅक्सेस"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"ऑक्युपंट अवेअरनेस सिस्टम यासाठी वाचन स्थिती आणि डिटेक्‍शन डेटाला अनुमती देते"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"ऑक्युपंट अवेअरनेस सिस्टम आलेख नियंत्रित करा"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"ऑक्युपंट अवेअरनेस सिस्टम डिटेक्शन आलेख सुरू करणे आणि थांबवणे नियंत्रित करण्यासाठी अनुमती देते"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"कार इनपुट सेवा"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"इनपुट इव्हेंट हाताळा"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN बस अयशस्वी"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"तुमच्या कारच्या इंजिनची तपशीलवार माहिती अ‍ॅक्सेस करा."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"कारचा इंधन भरण्याचा दरवाजा आणि चार्ज पोर्ट अ‍ॅक्सेस करा"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"कारचा इंधन भरण्याचा दरवाजा आणि चार्ज पोर्ट अ‍ॅक्सेस करा."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"कारचा इंधन भरण्याचा दरवाजा आणि चार्ज पोर्ट नियंत्रित करा"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"कारचा इंधन भरण्याचा दरवाजा आणि चार्ज पोर्ट नियंत्रित करा"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"कारची ओळख वाचा"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"कारची ओळख अ‍ॅक्सेस करा."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"कारचे दरवाजे नियंत्रित करा"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"कारची आसने नियंत्रित करा."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"कारची प्राथमिक माहिती अ‍ॅक्सेस करा"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"कारची प्राथमिक माहिती अ‍ॅक्सेस करा."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"कारच्या विक्रेता परवानगी माहिती ॲक्सेस करा"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"कारच्या विक्रेता परवानगी माहिती ॲक्सेस करा."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"कारच्या बाहेरील लाइटची स्थिती वाचा"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"कारच्या बाहेरील लाइटची स्थिती अ‍ॅक्सेस करा."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"कारच्या बाहेरच्या लाइटची स्थिती वाचा"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"विश्वसनीय डिव्हाइसच्या नोंदणीला अनुमती द्या"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"कारचा चाचणी मोड नियंत्रित करा"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"कारचा चाचणी मोड नियंत्रित करा"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"कारची वैशिष्ट्ये सुरू किंवा बंद करा"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"कारची वैशिष्ट्ये सुरू किंवा बंद करा."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"कार वॉचडॉग वापरा"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"कार वॉचडॉग वापरा."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"माझे डिव्हाइस"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"अतिथी"</string>
 </resources>
diff --git a/service/res/values-ms/strings.xml b/service/res/values-ms/strings.xml
index ad4927b..e5d4a9c 100644
--- a/service/res/values-ms/strings.xml
+++ b/service/res/values-ms/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Akses kamera kereta anda."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"akses maklumat tenaga kereta"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Akses maklumat tenaga kereta anda."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"laraskan baki julat kereta"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Laraskan baki nilai julat kereta."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"akses hvac kereta"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Akses hvac kereta anda."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"akses maklumat perbatuan kereta"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfigurasikan Sekatan UX"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Berkomunikasi dengan peranti USB dalam mod AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Membenarkan apl berkomunikasi dengan peranti dalam mod AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Akses Baca Sistem Kesedaran Penumpang"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Membenarkan pembacaan status dan data pengesanan untuk Sistem Kesedaran Penumpang"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kawal Graf Sistem Kesedaran Penumpang"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Membenarkan pengawalan permulaan dan penamatan graf pengesanan Sistem Kesedaran Penumpang"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Perkhidmatan Input Kereta"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Kendalikan peristiwa input"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Bas CAN gagal"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Akses maklumat terperinci enjin kereta anda."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"akses penutup tangki bahan api dan port pengecasan kereta"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Akses penutup tangki bahan api dan port pengecasan kereta."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"kawal penutup tangki bahan api dan port pengecasan kereta"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Kawal penutup tangki bahan api dan port pengecasan kereta."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"baca pengenalan kereta"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Akses pengenalan kereta."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"kawal pintu kereta"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kawal tempat duduk kereta."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"akses maklumat asas kereta"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Akses maklumat asas kereta."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"akses maklumat kebenaran vendor kereta"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Akses maklumat kebenaran vendor kereta"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"baca keadaan lampu luar kereta"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Akses keadaan lampu luar kereta."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"baca lampu luar kereta"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Benarkan Pendaftaran Peranti yang Dipercayai"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Mod ujian kereta kawalan"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Mod ujian kereta kawalan"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Dayakan atau lumpuhkan ciri kereta"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Dayakan atau lumpuhkan ciri kereta."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"gunakan pengawas kereta"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Gunakan pengawas kereta."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Peranti Saya"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Tetamu"</string>
 </resources>
diff --git a/service/res/values-my/strings.xml b/service/res/values-my/strings.xml
index 6c6637d..fb1aebf 100644
--- a/service/res/values-my/strings.xml
+++ b/service/res/values-my/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"သင့်ကား၏ ကင်မရာ(များ)ကို ဝင်ရောက်အသုံးပြုပါမည်။"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"ကား၏ စွမ်းအင်အချက်အလက်များကို ရယူပါမည်"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"ကား၏ စွမ်းအင်ဆိုင်ရာ အချက်အလက်ကို အသုံးပြုပါမည်။"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"ကား၏ အတိုင်းအတာ လက်ကျန်ကို ချိန်ညှိရန်"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"ကား၏ အတိုင်းအတာ လက်ကျန်တန်ဖိုးကို ချိန်ညှိရန်"</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"ကား၏ hvac ကို အသုံးပြုပါမည်"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"သင့်ကား၏ \"havc စနစ်\" ကို အသုံးပြုပါမည်။"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"ကား၏ ခရီးမိုင်အချက်အလက်များကို ရယူပါမည်"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX ကန့်သတ်ချက်များကို စီစဉ်သတ်မှတ်ရန်"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"AOAP မုဒ်တွင် USB ကိရိယာတစ်ခုနှင့် ဆက်သွယ်ခြင်း"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"အက်ပ်တစ်ခုကို AOAP မုဒ်တွင် စက်တစ်ခုနှင့် ဆက်သွယ်ခွင့်ပြုသည်"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"\'စီးနင်းသူ သတိရှိမှု စနစ်\' ဖတ်ရှုခွင့်"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"\'စီးနင်းသူ သတိရှိမှု စနစ်\' အတွက် အခြေအနေဖတ်ခြင်းနှင့် ဒေတာရှာဖွေခြင်းတို့ကို ခွင့်ပြုသည်"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"\'စီးနင်းသူ သတိရှိမှု စနစ် ဂရပ်ဖ်\' ကို ထိန်းချုပ်ရန်"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"\'စီးနင်းသူ သတိရှိမှု စနစ်\' သိရှိသည့်ဂရပ်ဖ် စတင်ခြင်းနှင့် ရပ်တန့်ခြင်းကို ထိန်းချုပ်ရန် ခွင့်ပြုသည်"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"ကား၏ အချက်အလက်ထည့်သွင်းခြင်း ဝန်ဆောင်မှု"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"အချက်အလက်ထည့်သွင်းခြင်း အစီအစဉ်များကို စီမံပါမည်"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"\"CAN bus\" စနစ် အသုံးပြုမှု မအောင်မြင်ပါ"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"သင့်ကား၏ အသေးစိတ် အင်ဂျင်အချက်အလက်ကို ရယူပါမည်။"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"ကား၏ ဆီတိုင်ကီတံခါးပေါက်နှင့် အားသွင်းသည့်အပေါက်ကို အသုံးပြုပါမည်"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"ကား၏ ဆီတိုင်ကီတံခါးပေါက်နှင့် အားသွင်းသည့်အပေါက်ကို အသုံးပြုပါမည်။"</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"ကား၏ ဆီတိုင်ကီတံခါးပေါက်နှင့် အားသွင်းသည့်အပေါက်ကို ထိန်းချုပ်ရန်"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"ကား၏ ဆီတိုင်ကီတံခါးပေါက်နှင့် အားသွင်းသည့်အပေါက်ကို ထိန်းချုပ်ပါမည်။"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"ကား၏ အထောက်အထားကို ကြည့်ပါမည်"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"ကား၏ အထောက်အထားကို ရယူပါမည်။"</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"ကားတံခါးများကို ထိန်းချုပ်သည်"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"ကားတွင်းထိုင်ခုံများကို ထိန်းချုပ်ပါမည်။"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"ကား၏ အခြေခံအချက်အလက်များကို ရယူပါမည်"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"ကား၏ အခြေခံအချက်အလက်များကို ရယူပါမည်။"</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"ကားရောင်းချသူ ခွင့်ပြုချက်ဆိုင်ရာ အချက်အလက်များကို ကြည့်ရန်"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"ကားရောင်းချသူ ခွင့်ပြုချက်ဆိုင်ရာ အချက်အလက်များကို ကြည့်ရန်။"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"ကားအပြင်ဘက်ရှိ မီးလုံးများ၏ အခြေအနေကို ကြည့်ပါမည်"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"ကား၏အပြင်ဘက်ရှိ မီးလုံးများ၏ အခြေအနေကို ကြည့်ပါမည်။"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ကားအပြင်ဘက်ရှိ မီးလုံးများကို ကြည့်ပါမည်"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"ယုံကြည်ရသည့် ကိရိယာအား စာရင်းသွင်းခြင်းကို ခွင့်ပြုရန်"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"ကား၏ စမ်းသပ်မုဒ်ကို ထိန်းချုပ်ရန်"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"ကား၏ စမ်းသပ်မုဒ်ကို ထိန်းချုပ်ရန်"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"ကား၏ ဝန်ဆောင်မှုများကို ပိတ်ရန် သို့မဟုတ် ပိတ်ရန်"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"ကား၏ ဝန်ဆောင်မှုများကို ဖွင့်ရန် သို့မဟုတ် ပိတ်ရန်။"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"ကားကင်းစောင့်ကို အသုံးပြုခွင့်"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"ကားကင်းစောင့်ကို အသုံးပြုခွင့်။"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ကျွန်ုပ်၏စက်"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"ဧည့်သည်"</string>
 </resources>
diff --git a/service/res/values-nb/strings.xml b/service/res/values-nb/strings.xml
index 16e2fa9..5d1fbe6 100644
--- a/service/res/values-nb/strings.xml
+++ b/service/res/values-nb/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Tilgang til bilens kamera(er)."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"få tilgang til bilens energiinformasjon"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Tilgang til informasjon om bilens energibruk."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"juster bilens gjenværende rekkevidde"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Juster verdien for bilens gjenværende rekkevidde."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"få tilgang til bilens klimaanlegg"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Tilgang til bilens klimaanlegg."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"få informasjon om bilens kjørelengde"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfigurering av begrensninger tilknyttet brukeropplevelsen"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Kommuniser med USB-enhet i AOAP-modus"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Tillater at en app kommuniserer med en enhet i AOAP-modus"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Lesetilgang til Occupant Awareness System"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Lar deg lese av status og registreringsdata for Occupant Awareness System"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontrollér diagrammet for Occupant Awareness System"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Lar deg kontrollere start og stopp av registreringsdiagrammet for Occupant Awareness System"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Bilens inndatatjeneste"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Behandling av inndatahendelser"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-bus mislyktes"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Tilgang til detaljert informasjon om bilmotoren."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"få tilgang til tanklokket og ladeporten på bilen"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Tilgang til tanklokket og ladeporten på bilen."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"kontrollere tanklokket og ladeporten på bilen"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Kontrollér tanklokket og ladeporten på bilen."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"lese bilens identifikator"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Tilgang til bilens identifikasjon."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"kontrollére bildørene"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kontrollér bilsetene."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"få tilgang til grunnleggende informasjon om bilen"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Tilgang til grunnleggende informasjon om bilen."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"få tilgang til bilens informasjon om leverandørtillatelser"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Få tilgang til bilens informasjon om leverandørtillatelser."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"lese tilstanden til bilens utvendige lys"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Tilgang til tilstanden til bilens utvendige lys."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"lese bilens utvendige lys"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Tillat registrering av godkjente enheter"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Kontrollér bilens testmodus"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Kontrollér bilens testmodus"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Slå bilens funksjoner på eller av"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Slå bilens funksjoner på eller av."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"bruk vakthund for bil"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Bruk vakthund for bil."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Enheten min"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Gjest"</string>
 </resources>
diff --git a/service/res/values-ne/strings.xml b/service/res/values-ne/strings.xml
index 7e86076..df9f269 100644
--- a/service/res/values-ne/strings.xml
+++ b/service/res/values-ne/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"तपाईंको कारका क्यामेरा(हरू) माथि पहुँच राख्ने।"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"कारको ऊर्जासम्बन्धी जानकारीमाथि पहुँच राख्ने"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"तपाईंको कारको ऊर्जासम्बन्धी जानकारीमाथि पहुँच राख्ने।"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"कारको दायराको बाँकी मान समायोजन गर्नुहोस्"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"कारको दायराको बाँकी मान समायोजन गर्नुहोस्।"</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"कारको hvac प्रणालीमाथि पहुँच राख्ने"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"तपाईंको कारको hvac माथि पहुँच राख्ने।"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"कारको माइलेजसम्बन्धी जानकारीमाथि पहुँच राख्ने"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX सम्बन्धी प्रतिबन्धहरू कन्फिगर गर्नुहोस्‌"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"AOAP मोडमा USB यन्त्रसँग सञ्चार गर्नुहोस्"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"AOAP मोडमा एपलाई कुनै यन्त्रसँग सञ्चार गर्न दिन्छ"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant Awareness System रिड गर्ने पहुँच"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Occupant Awareness System को स्थिति र पत्ता लगाउनेसम्बन्धी डेटा रिड गर्न दिन्छ"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Occupant Awareness System सम्बन्धी ग्राफको नियन्त्रण गर्नुहोस्"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Occupant Awareness System पत्ता लगाउनेसम्बन्धी ग्राफको सुरु र समाप्त हुने कार्य नियन्त्रण गर्न अनुमति दिनुहोस्"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"कारको इनपुट सेवा"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"इनपुट गरिएका कार्यक्रमहरू व्यवस्थापन गर्ने"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus असफल भयो"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"तपाईंको कारको इन्जिनको विस्तृत जानकारीमाथि पहुँच राख्ने।"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"कारको इन्धन हाल्ने ट्याङ्कीको बिर्को तथा चार्ज गर्ने पोर्टमाथि पहुँच राख्ने"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"कारको इन्धन हाल्ने ट्याङ्कीको बिर्को तथा चार्ज गर्ने पोर्टमाथि पहुँच राख्ने।"</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"कारको इन्धन हाल्ने ट्याङ्कीको बिर्को तथा चार्ज गर्ने पोर्टमाथि नियन्त्रण राख्नुहोस्"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"कारको इन्धन हाल्ने ट्याङ्कीको बिर्को तथा चार्ज गर्ने पोर्ट नियन्त्रण गर्नुहोस्।"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"कारको पहिचानसम्बन्धी जानकारी पढ्ने"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"कारको पहिचानसम्बन्धी जानकारीमाथि पहुँच राख्ने।"</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"कारका ढोकाहरू नियन्त्रण गर्ने"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"कारका सिटहरू नियन्त्रण गर्ने।"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"कारको आधारभूत जानकारीमाथि पहुँच राख्ने"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"कारको आधारभूत जानकारीमाथि पहुँच राख्ने।"</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"कारको विक्रेतासम्बन्धी अनुमतिको जानकारीमाथि पहुँच राख्नुहोस्"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"कारको विक्रेतासम्बन्धी अनुमतिको जानकारीमाथि पहुँच राख्नुहोस्।"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"कारका बाहिरी बत्तीहरूको स्थिति पढ्ने"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"कारका बाहिरी बत्तीहरूको स्थितिमाथि पहुँच राख्ने।"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"कारका बाहिरी बत्तीहरूको अवस्थाबारे जानकारी प्राप्त गर्ने"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"विश्वसनीय यन्त्र दर्ता गर्ने अनुमति दिनुहोस्"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"कारको परीक्षण मोड नियन्त्रण गर्नुहोस्"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"कारको परीक्षण मोड नियन्त्रण गर्नुहोस्"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"कारका सुविधाहरू सक्षम वा असक्षम पार्नुहोस्"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"कारका सुविधाहरू सक्षम वा असक्षम पार्नुहोस्।"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"कारको प्रणालीको निगरानी गर्ने सुविधा प्रयोग गर्नुहोस्"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"कारको प्रणालीको निगरानी गर्ने सुविधा प्रयोग गर्नुहोस्"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"मेरो यन्त्र"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"अतिथि"</string>
 </resources>
diff --git a/service/res/values-night/colors.xml b/service/res/values-night/colors.xml
index 6f30b68..108de11 100644
--- a/service/res/values-night/colors.xml
+++ b/service/res/values-night/colors.xml
@@ -18,8 +18,7 @@
 -->
 <resources>
     <!-- Semi-transparent background color of blocking activity. -->
-    <!-- In Call background scrim: black -->
-    <color name="activity_blocking_activity_background">@android:color/black</color>
+    <color name="activity_blocking_activity_background">#c7000000</color>
 
     <!-- Color of text in blocking activity. -->
     <color name="blocking_text">#fff5f5f5</color>
diff --git a/service/res/values-nl/strings.xml b/service/res/values-nl/strings.xml
index 785fd9b..da7bc47 100644
--- a/service/res/values-nl/strings.xml
+++ b/service/res/values-nl/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Toegang tot de camera(\'s) van je auto."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"toegang tot informatie over energieniveau van auto"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Toegang tot informatie over het energieniveau van je auto."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"resterende actieradius van auto aanpassen"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Waarde voor resterende actieradius van auto aanpassen."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"toegang tot HVAC van auto"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Toegang tot de HVAC van je auto."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"toegang tot informatie over kilometerstand van auto"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Beperkingen voor gebruikerservaring configureren"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Communiceren met USB-apparaat in AOAP-modus"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Hiermee kan een app communiceren met een apparaat in AOAP-modus"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Leestoegang voor Occupant Awareness System"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Hiermee kunnen status- en detectiegegevens van het Occupant Awareness System worden gelezen"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Occupant Awareness System-diagram bedienen"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Hiermee kan het starten en stoppen van het Occupant Awareness System-detectiediagram worden bediend"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Invoerservice van auto"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Invoergebeurtenissen verwerken"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-bus is mislukt"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Toegang tot gedetailleerde informatie over motor van auto."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"toegang tot tankklep en oplaadpoort van auto"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Toegang tot tankklep en oplaadpoort van auto."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"tankklep en oplaadpoort van auto bedienen"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Tankklep en oplaadpoort van auto bedienen."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"identificatie van auto lezen"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Toegang tot identificatie van auto."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"autoportieren bedienen"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Autostoelen bedienen."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"toegang tot basisgegevens van auto"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Toegang tot basisgegevens van auto."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"toegang tot informatie over de leveranciersrechten van de auto"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Toegang tot informatie over de leveranciersrechten van de auto."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"status van buitenverlichting van auto lezen"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Toegang tot status van buitenverlichting van auto."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"buitenverlichting van auto lezen"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Inschrijving van vertrouwd apparaat toestaan"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Testmodus van auto bedienen"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Testmodus van auto bedienen"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Functies van de auto in- of uitschakelen"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Functies van de auto in- of uitschakelen."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"auto-watchdog gebruiken"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Auto-watchdog gebruiken."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Mijn apparaat"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Gast"</string>
 </resources>
diff --git a/service/res/values-or/strings.xml b/service/res/values-or/strings.xml
index b02e150..9851358 100644
--- a/service/res/values-or/strings.xml
+++ b/service/res/values-or/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"ଆପଣଙ୍କ କାର୍‍ର କ୍ୟାମେରା(ଗୁଡ଼ିକ) ଆକ୍ସେସ୍ କରିପାରେ।"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"କାର୍\'ର ଏନାର୍ଜି ସୂଚନାକୁ ଆକ୍‍‍ସେସ୍ କରନ୍ତୁ"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"ଆପଣଙ୍କ କାର୍‍ର ଶକ୍ତି ସୂଚନା ଆକ୍ସେସ୍ କରିପାରେ।"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"କାର୍‌ର ରେଞ୍ଜ୍ ପାଇଁ ଅବଶିଷ୍ଟ ମୂଲ୍ୟ ଆଡ୍‌ଜଷ୍ଟ୍ କରନ୍ତୁ"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"କାର୍‌ର ରେଞ୍ଜ୍ ପାଇଁ ଅବଶିଷ୍ଟ ମୂଲ୍ୟ ଆଡ୍‌ଜଷ୍ଟ୍ କରନ୍ତୁ।"</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"କାର୍\'ର hvac ଆକ୍‍‍ସେସ୍ କରନ୍ତୁ"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"ଆପଣଙ୍କ କାର୍‍ର hvac ଆକ୍ସେସ୍ କରିପାରେ।"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"କାର୍\'ର ମାଇଲେଜ୍ ସୂଚନାକୁ ଆକ୍‍‍ସେସ୍ କରନ୍ତୁ"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX ପ୍ରତିବନ୍ଧତା କନ୍‌ଫିଗର୍ କରନ୍ତୁ"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"AOAP ମୋଡ୍‌ରେ USB ଡିଭାଇସ୍ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"AOAP ମୋଡ୍‌ରେ ଏକ ଡିଭାଇସ୍ ସହ ଯୋଗାଯୋଗ କରିବା ପାଇଁ ଆପ୍‍କୁ ଅନୁମତି ଦେଇଥାଏ"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"ଅକ୍ୟୁପେଣ୍ଟ ଆୱାରନେସ୍ ସିଷ୍ଟମ୍ ପଢ଼ିବା ଆକ୍ସେସ୍"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"ଏହା ଅକ୍ୟୁପେଣ୍ଟ ଆୱାରନେସ୍ ସିଷ୍ଟମ୍ ପାଇଁ ସ୍ଥିତି ଏବଂ ଚିହ୍ନଟକରଣ ଡାଟା ପଢ଼ିବାକୁ ଅନୁମତି ଦେଇଥାଏ"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"ଅକ୍ୟୁପେଣ୍ଟ ଆୱାରନେସ୍ ସିଷ୍ଟମ୍ ଗ୍ରାଫ୍ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"ଏହା ଅକ୍ୟୁପେଣ୍ଟ ଆୱାରନେସ୍ ସିଷ୍ଟମ୍ ଡିଟେକ୍ସନ୍ ଗ୍ରାଫକୁ ଚାଲୁ ଏବଂ ବନ୍ଦ କରିବା ନିୟନ୍ତ୍ରଣ ପାଇଁ ଅନୁମତି ଦେଇଥାଏ"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"କାର୍‍ର ଇନ୍‍ପୁଟ୍ ସେବା"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ଇନ୍‍ପୁଟ୍ ଇଭେଣ୍ଟଗୁଡ଼ିକ ପରିଚାଳନା କରିପାରେ"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN ବସ୍ ବିଫଳ ହେଲା"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"ଆପଣଙ୍କ କାର୍\'ର ବିସ୍ତୃତ ଇଞ୍ଜିନ୍ ସୂଚନାକୁ ଆକ୍‍‍ସେସ୍ କରନ୍ତୁ।"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"କାର୍\'ର ଫୁଏଲ୍ ଡୋର୍ ଏବଂ ଚାର୍ଜ ପୋର୍ଟକୁ ଆକ୍‍‍ସେସ୍ କରନ୍ତୁ।"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"କାର୍\'ର ଫୁଏଲ୍‍ ଡୋର୍ ଏବଂ ଚାର୍ଜ ପୋର୍ଟକୁ ଆକ୍‍‍ସେସ୍ କରନ୍ତୁ।"</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"କାରର ଫୁଏଲ୍ ଡୋର୍ ଏବଂ ଚାର୍ଜ ପୋର୍ଟକୁ ନିୟନ୍ତ୍ରଣ କରିପାରିବ"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"କାରର ଫୁଏଲ୍ ଡୋର୍ ଏବଂ ଚାର୍ଜ ପୋର୍ଟକୁ ନିୟନ୍ତ୍ରଣ କରିପାରିବ।"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"କାର୍\'ର ଚିହ୍ନଟକରଣକୁ ପଢ଼ିବ"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"କାର୍\'ର ଚିହ୍ନଟକରଣ ଆକ୍‍‍ସେସ୍ କରନ୍ତୁ।"</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"କାର୍\'ର ଡୋର୍‌ଗୁଡ଼ିକୁ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"କାର୍\'ର ସିଟ୍‌ଗୁଡ଼ିକୁ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ।"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"କାର୍\'ର ମୌଳିକ ସୂଚନା ଆକ୍‍‍ସେସ୍ କରନ୍ତୁ"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"କାର୍\'ର ମୌଳିକ ସୂଚନା ଆକ୍‍‍ସେସ୍‍ କରନ୍ତୁ।"</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"କାର୍\'ର ଭେଣ୍ଡର୍ ଅନୁମତି ସୂୂଚନା ଆକ୍‍‍ସେସ୍ କରନ୍ତୁ"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"କାର୍\'ର ଭେଣ୍ଡର୍ ଅନୁମତି ସୂୂଚନା ଆକ୍‍‍ସେସ୍ କରନ୍ତୁ।"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"କାର୍\'ର ବାହାର ଲାଇଟ୍‌ଗୁଡ଼ିକର ଷ୍ଟେଟ୍‌କୁ ପଢ଼ିବ"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"କାର୍\'ର ବାହାର ଲାଇଟ୍‌ଗୁଡ଼ିକର ଷ୍ଟେଟ୍‌କୁ ଆକ୍‍‍ସେସ୍ କରନ୍ତୁ।"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"କାର୍\'ର ବାହାର ଲାଇଟ୍‌ଗୁଡ଼ିକର ସ୍ଥିତିକୁ ପଢ଼ିବ"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"ଚିହ୍ନା ଡିଭାଇସ୍‌ ନାମାଙ୍କନକୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"କାର୍‍ର ପରୀକ୍ଷଣ ମୋଡ୍ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"କାର୍‍ର ପରୀକ୍ଷଣ ମୋଡ୍ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"କାରର ଫିଚର୍‌ଗୁଡ଼ିକୁ ସକ୍ଷମ କିମ୍ବା ଅକ୍ଷମ କରନ୍ତୁ"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"କାରର ଫିଚର୍‌ଗୁଡ଼ିକୁ ସକ୍ଷମ କିମ୍ବା ଅକ୍ଷମ କରନ୍ତୁ।"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"କାର ୱାଚଡଗ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"କାର ୱାଚଡଗ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ମୋ ଡିଭାଇସ୍"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"ଅତିଥି"</string>
 </resources>
diff --git a/service/res/values-pa/strings.xml b/service/res/values-pa/strings.xml
index 1205efd..d0e0ee5 100644
--- a/service/res/values-pa/strings.xml
+++ b/service/res/values-pa/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"ਤੁਹਾਡੀ ਕਾਰ ਦੇ ਕੈਮਰੇ ਤੱਕ ਪਹੁੰਚ।"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"ਕਾਰ ਦੀ ਊਰਜਾ ਸੰਬੰਧੀ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"ਤੁਹਾਡੀ ਕਾਰ ਦੀ ਊਰਜਾ ਸੰਬੰਧੀ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ।"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"ਕਾਰ ਦੀ ਬਾਕੀ ਰੇਂਜ ਨੂੰ ਵਿਵਸਥਿਤ ਕਰੋ"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"ਕਾਰ ਦੀ ਬਾਕੀ ਰੇਂਜ ਦੇ ਮੁੱਲ ਨੂੰ ਵਿਵਸਥਿਤ ਕਰੋ।"</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"ਕਾਰ ਦੇ hvac ਤੱਕ ਪਹੁੰਚ"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"ਤੁਹਾਡੀ ਕਾਰ ਦੇ hvac ਸਿਸਟਮ ਤੱਕ ਪਹੁੰਚ।"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"ਕਾਰ ਦੀ ਮਾਈਲੇਜ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX ਪਾਬੰਦੀਆਂ ਦਾ ਸੰਰੂਪਣ ਕਰੋ"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"AOAP ਮੋਡ ਵਿੱਚ USB ਡੀਵਾਈਸ ਨਾਲ ਸੰਚਾਰ ਕਰੋ"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"ਕਿਸੇ ਐਪ ਨੂੰ AOAP ਮੋਡ ਵਿੱਚ ਡੀਵਾਈਸ ਨਾਲ ਸੰਚਾਰ ਕਰਨ ਦਿਓ"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"ਕਾਰ ਚਲਾਉਣ ਵਾਲੇ ਲਈ ਜਾਗਰੂਕਤਾ ਸਿਸਟਮ ਨੂੰ ਪੜ੍ਹਨ ਦੀ ਪਹੁੰਚ"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"ਕਾਰ ਚਲਾਉਣ ਵਾਲੇ ਲਈ ਜਾਗਰੂਕਤਾ ਸਿਸਟਮ ਦੀ ਸਥਿਤੀ ਨੂੰ ਪੜ੍ਹਨ ਅਤੇ ਇਸਦੇ ਡਾਟੇ ਦਾ ਪਤਾ ਲਗਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"ਕਾਰ ਚਲਾਉਣ ਵਾਲੇ ਲਈ ਜਾਗਰੂਕਤਾ ਸਿਸਟਮ ਦੇ ਗ੍ਰਾਫ਼ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"ਕਾਰ ਚਲਾਉਣ ਵਾਲੇ ਲਈ ਜਾਗਰੂਕਤਾ ਸਿਸਟਮ ਦੇ ਪਤਾ ਲਗਾਉਣ ਵਾਲੇ ਗ੍ਰਾਫ਼ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਅਤੇ ਰੋਕਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"ਕਾਰ ਇਨਪੁੱਟ ਸਰਵਿਸ"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ਇਨਪੁੱਟ ਇਵੈਂਟਾਂ ਦੀ ਸੰਭਾਲ"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN ਬੱਸ ਅਸਫਲ ਰਹੀ"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"ਤੁਹਾਡੀ ਕਾਰ ਦੇ ਇੰਜਣ ਦੀ ਵੇਰਵੇ ਸਹਿਤ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ।"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"ਕਾਰ ਦੀ ਈਂਧਣ ਵਾਲੀ ਜਗ੍ਹਾ ਅਤੇ ਚਾਰਜ ਪੋਰਟ ਤੱਕ ਪਹੁੰਚ"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"ਕਾਰ ਦੀ ਈਂਧਣ ਵਾਲੀ ਜਗ੍ਹਾ ਅਤੇ ਚਾਰਜ ਪੋਰਟ ਤੱਕ ਪਹੁੰਚ।"</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"ਕਾਰ ਦੀ ਈਂਧਣ ਭਰਨ ਵਾਲੀ ਜਗ੍ਹਾ ਦੇ ਢੱਕਣ ਅਤੇ ਚਾਰਜ ਪੋਰਟ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"ਕਾਰ ਦੀ ਈਂਧਣ ਭਰਨ ਵਾਲੀ ਜਗ੍ਹਾ ਦੇ ਢੱਕਣ ਅਤੇ ਚਾਰਜ ਪੋਰਟ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ।"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"ਕਾਰ ਦੀ ਪਛਾਣ ਤੱਕ ਪਹੁੰਚ"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"ਕਾਰ ਦੀ ਪਛਾਣ ਤੱਕ ਪਹੁੰਚ।"</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"ਕਾਰ ਦੀਆਂ ਤਾਕੀਆਂ \'ਤੇ ਕੰਟਰੋਲ"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"ਕਾਰ ਦੀਆਂ ਸੀਟਾਂ \'ਤੇ ਕੰਟਰੋਲ।"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"ਕਾਰ ਦੀ ਮੂਲ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"ਕਾਰ ਦੀ ਮੂਲ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ।"</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"ਕਾਰ ਵਿਕਰੇਤਾ ਦੀ ਇਜਾਜ਼ਤ ਸੰਬੰਧੀ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"ਕਾਰ ਵਿਕਰੇਤਾ ਦੀ ਇਜਾਜ਼ਤ ਸੰਬੰਧੀ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ।"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"ਕਾਰ ਦੀਆਂ ਬਾਹਰੀ ਲਾਈਟਾਂ ਦੀ ਸਥਿਤੀ ਨੂੰ ਪੜ੍ਹਨਾ"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"ਕਾਰ ਦੀਆਂ ਬਾਹਰੀ ਲਾਈਟਾਂ ਦੀ ਸਥਿਤੀ ਤੱਕ ਪਹੁੰਚ।"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ਕਾਰ ਦੀਆਂ ਬਾਹਰੀ ਲਾਈਟਾਂ \'ਤੇ ਕੰਟਰੋਲ"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"ਭਰੋਸੇਯੋਗ ਡੀਵਾਈਸਾਂ ਨੂੰ ਦਰਜਾਬੰਦੀ ਕਰਨ ਦਿਓ"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"ਕਾਰ ਦੇ ਜਾਂਚ ਮੋਡ \'ਤੇ ਕੰਟਰੋਲ"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"ਕਾਰ ਦੇ ਜਾਂਚ ਮੋਡ \'ਤੇ ਕੰਟਰੋਲ"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"ਕਾਰ ਦੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਚਾਲੂ ਜਾਂ ਬੰਦ ਕਰੋ"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"ਕਾਰ ਦੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਚਾਲੂ ਜਾਂ ਬੰਦ ਕਰੋ।"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"ਕਾਰ ਵਾਚਡੌਗ ਵਰਤੋ"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"ਕਾਰ ਵਾਚਡੌਗ ਵਰਤੋ।"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"ਮੇਰਾ ਡੀਵਾਈਸ"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"ਮਹਿਮਾਨ"</string>
 </resources>
diff --git a/service/res/values-pl/strings.xml b/service/res/values-pl/strings.xml
index 733cda3..fa33cd3 100644
--- a/service/res/values-pl/strings.xml
+++ b/service/res/values-pl/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Dostęp do kamer samochodu."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"dostęp do informacji o zasilaniu w samochodzie"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Dostęp do informacji o zasilaniu w samochodzie."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"korekta pozostałego zasięgu samochodu"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Korekta wartości pozostałego zasięgu samochodu."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"dostęp do systemu sterowania temperaturą w samochodzie"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Dostęp do systemu sterowania temperaturą w samochodzie."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"dostęp do informacji o przebiegu samochodu"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfigurowanie ograniczeń UX"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Komunikowanie się z urządzeniem USB w trybie AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Zezwala aplikacji na komunikowanie się z urządzeniem w trybie AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Odczytywanie danych z systemu wykrywania osób"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Umożliwia odczytywanie danych o stanie i działaniu systemu wykrywania osób"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Sterowanie wykresem z systemu wykrywania osób"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Umożliwia włączanie i wyłączanie wykresu z systemu wykrywania osób"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Usługa wprowadzania danych w samochodzie"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Obsługa zdarzeń wprowadzania danych"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Błąd magistrali CAN"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Dostęp do szczegółowych informacji o silniku."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"dostęp do drzwiczek wlewu paliwa i portu ładowania samochodu"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Dostęp do drzwiczek wlewu paliwa i portu ładowania samochodu."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"sterowanie drzwiczkami wlewu paliwa i portu ładowania samochodu"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Sterowanie drzwiczkami wlewu paliwa i portu ładowania samochodu."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"odczytywanie danych identyfikacyjnych samochodu"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Dostęp do danych identyfikacyjnych samochodu."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"sterowanie drzwiami samochodu"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Sterowanie fotelami samochodowymi."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"dostęp do podstawowych informacji o samochodzie"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Dostęp do podstawowych informacji o samochodzie."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"dostęp do informacji o uprawnieniach producenta samochodu"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Dostęp do informacji o uprawnieniach producenta samochodu."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"odczytywanie stanu zewnętrznych świateł samochodu"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Dostęp do stanu zewnętrznych świateł samochodu."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"odczytywanie informacji o zewnętrznych światłach samochodu"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Zezwalaj na rejestrowanie zaufanych urządzeń"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Sterowanie trybem testowym w samochodzie"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Sterowanie trybem testowym w samochodzie"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Włączanie i wyłączanie funkcji samochodu"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Włączanie i wyłączanie funkcji samochodu."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"używaj watchdoga w samochodzie"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Używaj watchdoga w samochodzie."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moje urządzenie"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Gość"</string>
 </resources>
diff --git a/service/res/values-pt-rPT/strings.xml b/service/res/values-pt-rPT/strings.xml
index dfcc04a..9d7ae8f 100644
--- a/service/res/values-pt-rPT/strings.xml
+++ b/service/res/values-pt-rPT/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Aceda à(s) câmara(s) do automóvel."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"aceder às informações de energia do automóvel"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Aceda às informações de energia do automóvel."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"ajustar o funcionamento restante do automóvel"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Ajuste o valor restante do funcionamento do automóvel."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"aceder ao AVAC do automóvel"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Aceda ao AVAC do automóvel."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"aceder às informações de quilometragem do automóvel"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configure restrições da experiência do utilizador."</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Comunicar com o dispositivo USB no modo AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Permite que uma aplicação comunique com um dispositivo no modo AOAP."</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Acesso de leitura do Sistema de deteção de ocupantes"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Permite a leitura do estado e dos dados de deteção do Sistema de deteção de ocupantes."</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Controlar o gráfico do Sistema de deteção de ocupantes"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Permite controlar o início e a interrupção do gráfico de deteção do Sistema de deteção de ocupantes."</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Serviço de entrada do automóvel"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Processe eventos de entrada."</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Falha no CAN bus."</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Aceder às informações detalhadas do motor do automóvel."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"aceder à porta de carregamento e à tampa do depósito de combustível do automóvel"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Aceder à porta de carregamento e à tampa do depósito de combustível do automóvel."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"controlar a porta de carregamento e a tampa do depósito de combustível do automóvel."</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Controlar a porta de carregamento e a tampa do depósito de combustível do automóvel."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"ler a identificação do automóvel"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Aceder à identificação do automóvel."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"controlar as portas do automóvel"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Controlar os assentos do automóvel."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"aceder às informações básicas acerca do automóvel"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Aceder às informações básicas acerca do automóvel."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"aceda às informações de autorização do fornecedor do automóvel."</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Aceda às informações de autorização do fornecedor do automóvel."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"ler o estado das luzes exteriores do automóvel"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Aceder ao estado das luzes exteriores do automóvel."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ler as luzes exteriores do automóvel"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Permitir a inscrição de dispositivos fidedignos"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Controlar o modo de teste do automóvel"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Controlar o modo de teste do automóvel"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Ativar ou desativar as funcionalidades do automóvel"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Ative ou desative as funcionalidades do automóvel."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"utilizar o watchdog do automóvel"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Utilize o watchdog do automóvel."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Dispositivo"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Convidado"</string>
 </resources>
diff --git a/service/res/values-pt/strings.xml b/service/res/values-pt/strings.xml
index 5688116..3cc6b05 100644
--- a/service/res/values-pt/strings.xml
+++ b/service/res/values-pt/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Acessar câmeras do carro."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"acessar as informações de energia do carro"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Acessar informações de abastecimento do carro."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"ajustar a autonomia restante do carro"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Ajustar o valor restante de autonomia do carro."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"acessar o HVAC (Aquecimento, ventilação e ar-condicionado) do carro"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Acessar o HVAC (Aquecimento, ventilação e ar-condicionado) do carro."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"acessar informações de quilometragem do carro"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurar restrições de UX"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Comunicar com um dispositivo USB no modo AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Permite que um app se comunique com um dispositivo no modo AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Acesso de leitura ao sistema de detecção de ocupantes"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Permite ler o status e os dados de detecção do sistema de detecção de ocupantes"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Controlar o gráfico do sistema de detecção de ocupantes"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Permite controlar o início e fim do gráfico do sistema de detecção de ocupantes"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Serviço de entrada do carro"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gerenciar eventos de entrada"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Falha no barramento CAN"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Acessar informações detalhadas do motor do carro."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"acessar as entradas de combustível e carregamento do carro"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Acessar as entradas de combustível e carregamento do carro."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"controlar as entradas de combustível e carregamento do carro"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Controlar as entradas de combustível e carregamento do carro."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"ler identificação do carro"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Acessar identificação do carro."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"controlar portas do carro"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Controlar bancos do carro."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"acessar informações básicas do carro"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Acessar informações básicas do carro."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"acessar informações de permissão do fornecedor do carro"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Acessar informações de permissão do fornecedor do carro."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"ler o estado das luzes externas do carro"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Acessar o estado das luzes externas do carro."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ler informações sobre as luzes externas do carro"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Permitir inscrição de dispositivo confiável"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Controlar modo de teste do carro"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Controlar modo de teste do carro"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Ativar ou desativar os recursos do carro"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Ativar ou desativar os recursos do carro."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"usar watchdog do carro"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Usar watchdog do carro."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Meu dispositivo"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Visitante"</string>
 </resources>
diff --git a/service/res/values-ro/strings.xml b/service/res/values-ro/strings.xml
index 470f90d..cae9576 100644
--- a/service/res/values-ro/strings.xml
+++ b/service/res/values-ro/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Accesează camerele mașinii."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"Accesează informațiile despre nivelul de energie al mașinii"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Accesează informațiile despre energie ale mașinii."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"ajustați restul distanței parcurse de mașină"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Ajustați restul distanței parcurse de mașină."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"Accesează sistemul hvac al mașinii"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Accesează sistemul hvac al mașinii."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"Accesează informațiile despre kilometrajul mașinii"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurați restricțiile UX"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Comunică cu dispozitivul USB în modul AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Permite unei aplicații să comunice cu un dispozitiv în modul AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Acces de citire la Sistemul de avertizare privind ocupanții"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Permite citirea stării și a datelor de detectare pentru Sistemul de avertizare privind ocupanții"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Controlează graficul Sistemului de avertizare privind ocupanții"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Permite controlarea începerii și opririi graficului de detectare a Sistemului de avertizare privind ocupanții"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Gestionează serviciul de intrare pentru mașină"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gestionează evenimentele de intrare"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Magistrala CAN nu a reușit"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Accesează informațiile detaliate despre motorul mașinii"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"Accesează ușa de alimentare a mașinii și portul de încărcare"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Accesează ușa de alimentare a mașinii și portul de încărcare."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"controlează ușa de alimentare a mașinii și portul de încărcare"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Controlează ușa de alimentare a mașinii și portul de încărcare."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"Citește informațiile de identificare a mașinii"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Accesează informațiile de identificare a mașinii."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"Controlează portierele mașinii"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Controlează locurile din mașină."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"Accesează informațiile de bază despre mașină"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Accesează informațiile de bază despre mașină."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"accesați informațiile despre permisiuni ale furnizorului mașinii"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Accesați informațiile despre permisiuni ale furnizorului mașinii."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"Citește starea luminilor exterioare ale mașinii"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Accesează starea luminilor exterioare ale mașinii."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"Citește starea luminilor exterioare ale mașinii"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Permiteți înscrierea unui dispozitiv de încredere"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Controlați modul de testare a mașinii"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Controlați modul de testare a mașinii"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Activați sau dezactivați funcțiile mașinii"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Activați sau dezactivați funcțiile mașinii."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"folosiți ceasul de gardă al mașinii"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Folosiți ceasul de gardă al mașinii."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Dispozitivul meu"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Invitat"</string>
 </resources>
diff --git a/service/res/values-ru/strings.xml b/service/res/values-ru/strings.xml
index 2362d73..c9f7231 100644
--- a/service/res/values-ru/strings.xml
+++ b/service/res/values-ru/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Доступ к камерам автомобиля"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"доступ к данным об энергоресурсах автомобиля"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Доступ к данным об энергоресурсах автомобиля"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"Изменение расстояния, которое проедет автомобиль без дозаправки"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Изменение расстояния, которое проедет автомобиль без дозаправки"</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"доступ к системе ОВиК"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Доступ к системе ОВиК"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"доступ к данным о пробеге"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Возможность ограничивать использование функций"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Обмен данными с USB-устройством в режиме AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Приложение сможет обмениваться данными с устройством в режиме AOAP."</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Доступ к считыванию состояния функции Occupant Awareness System"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Считывание статуса и данных функции Occupant Awareness System"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Управление графиком функции Occupant Awareness System"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Управление началом и окончанием работы графика функции Occupant Awareness System"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Автомобильная служба ввода"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Возможность обрабатывать события ввода"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Произошла ошибка шины CAN."</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Доступ к подробным данным о двигателе."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"доступ к лючку топливного бака и порту зарядки"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Доступ к лючку топливного бака и порту зарядки."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"управление лючком топливного бака и портом зарядки"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Управление лючком топливного бака и портом зарядки."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"чтение идентификационных данных автомобиля"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Доступ к идентификационным данным автомобиля."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"управление дверями"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Управление сиденьями."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"Доступ к общим данным об автомобиле"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Доступ к общим данным об автомобиле."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"доступ к информации о фирменных разрешениях"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Доступ к информации о фирменных разрешениях."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"чтение данных о состоянии внешних осветительных приборов"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Доступ к данным о состоянии внешних осветительных приборов."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"чтение данных о состоянии внешних осветительных приборов"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Разрешить регистрацию надежных устройств."</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Управление тестовым режимом"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Управление тестовым режимом"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Включение и отключение функций автомобиля"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Включение и отключение функций автомобиля."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"использование системы мониторинга автомобиля"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Использование системы мониторинга автомобиля."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Мое устройство"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Гость"</string>
 </resources>
diff --git a/service/res/values-si/strings.xml b/service/res/values-si/strings.xml
index 490d677..653e7fd 100644
--- a/service/res/values-si/strings.xml
+++ b/service/res/values-si/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"ඔබේ මෝටර් රථයේ කැමරා(ව) වෙත ප්‍රවේශ වන්න."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"මෝටර් රථයේ බලශක්ති තොරතුරුවලට ප්‍රවේශ වන්න"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"ඔබේ මෝටර් රථයේ බල ශක්ති තොරතුරු වෙත ප්‍රවේශ වන්න."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"මෝටර් රථ පරාසයේ ඉතිරිය ගළපන්න"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"මෝටර් රථ පරාසයේ ඉතිරිව ඇති අගය ගළපන්න."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"මෝටර් රථයේ hvac වෙත ප්‍රවේශ වන්න"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"ඔබේ මෝටර් රථයේ hvac වෙත ප්‍රවේශ වන්න."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"මෝටර් රථයේ ධාවන දුර තොරතුරුවලට ප්‍රවේශ වන්න"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX සීමා කිරීම් වින්‍යාස කරන්න"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"AOAP ප්‍රකාරයේ USB උපාංගය සමඟ සන්නිවේදනය කරන්න"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"යෙදුමකට AOAP ප්‍රකාරය තුළ උපාංගයක් සමඟ සන්නිවේදනය කිරීමට ඉඩ දෙයි"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"පදිංචිකරුවන් දැනුවත් කිරීමේ පද්ධති කියවීම් ප්‍රවේශය"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"පදිංචිකරුවන් දැනුවත් කිරීමේ පද්ධතිය සඳහා තත්ත්වය සහ අනාවරණ දත්ත කියවීමට ඉඩ දෙයි"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"පදිංචිකරුවන් දැනුවත් කිරීමේ පද්ධති ප්‍රස්ථාරය"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"පදිංචිකරුවන් දැනුවත් කිරීමේ පද්ධති අනාවරණ ප්‍රස්ථාරයෙහි ආරම්භය සහ නැවැත්වීම පාලනයට ඉඩ දෙයි"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"මෝටර් රථ ආදාන සේවය"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ආදාන සිදුවීම් පරිහරණ කරන්න"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN බස් අසාර්ථකයි"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"ඔබේ මෝටර් රථයේ විස්තරාත්මක එන්ජින් තොරතුරුවලට ප්‍රවේශ වන්න."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"මෝටර් රථයේ ඉන්ධන දොර සහ ආරෝපණ කවුළුවට ප්‍රවේශ වන්න"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"මෝටර් රථයේ ඉන්ධන දොර සහ ආරෝපණ කවුළුවට ප්‍රවේශ වන්න."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"මෝටර් රථයේ ඉන්ධන දොර සහ ආරෝපණ කවුළුව පාලනය"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"මෝටර් රථයේ ඉන්ධන දොර සහ ආරෝපණ කවුළුව පාලනය කරන්න."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"මෝටර් රථයේ අනන්‍යතාවය කියවන්න"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"මෝටර් රථයේ අනන්‍යතාවයට ප්‍රවේශ වන්න."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"මෝටර් රථයේ දොරවල් පාලනය කරන්න"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"මෝටර් රථයේ ආසන පාලනය කරන්න."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"මෝටර් රථයේ මූලික තොරතුරුවලට ප්‍රවේශ වන්න"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"මෝටර් රථයේ මූලික තොරතුරුවලට ප්‍රවේශ වන්න."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"මෝටර් රථයේ විකුණුම්කරුගේ අවසර තොරතුරු වෙත ප්‍රවේශ වන්න"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"මෝටර් රථයේ විකුණුම්කරුගේ අවසර තොරතුරු වෙත ප්‍රවේශ වන්න."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"මෝටර් රථයේ බාහිර ආලෝක තත්ත්වය කියවන්න"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"මෝටර් රථයේ බාහිර ආලෝක තත්ත්වයට ප්‍රවේශ වන්න."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"මෝටර් රථයේ බාහිර ආලෝකයන් කියවන්න"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"විශ්වාසී උපාංග ඇතුළත් කිරීමට ඉඩ දෙන්න"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"මෝටර් රථයේ පරීක්ෂණ ප්‍රකාරය පාලනය"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"මෝටර් රථයේ පරීක්ෂණ ප්‍රකාරය පාලනය"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"මෝටර් රථයේ විශේෂාංග සබල හෝ අබල කරන්න"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"මෝටර් රථයේ විශේෂාංග සබල හෝ අබල කරන්න."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"රිය මුරබල්ලා භාවිතා කරන්න"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"රිය මුරබල්ලා භාවිතා කරන්න."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"මගේ උපාංගය"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"අමුත්තා"</string>
 </resources>
diff --git a/service/res/values-sk/strings.xml b/service/res/values-sk/strings.xml
index 46dfc59..3154c8b 100644
--- a/service/res/values-sk/strings.xml
+++ b/service/res/values-sk/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Získajte prístup ku kamerám auta."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"získať prístup k informáciám o energii auta"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Získajte prístup k informáciám o palive a energii auta."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"úprava dojazdu auta – zostatok"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Úprava zostávajúcej hodnoty dojazdu auta."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"získať prístup ku kúreniu, vzduchotechnike a klimatizácii auta"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Získajte prístup k vykurovaniu, ventilácii a klimatizácii auta."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"získať prístup k informáciám o spotrebe auta"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfigurovať obmedzenia dojmu používateľa"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Komunikovať so zariadením USB v režime AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Umožňuje aplikácii komunikovať so zariadením v režime AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Prístup na čítanie do systému detekcie posádky"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Umožňuje čítať stav a údaje o detekcii zo systému detekcie posádky"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Ovládanie grafu systému detekcie posádky"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Umožňuje ovládať spustenie a zastavenie grafu detekcie systému detekcie posádky"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Služba vstupov auta"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Spravovať udalosti vstupu"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Zbernica CAN zlyhala"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Získajte prístup k podrobným informáciám o motore auta."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"získať prístup k dvierkam palivovej nádrže a nabíjaciemu portu"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Prístup k dvierkam palivovej nádrže a nabíjaciemu portu."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"ovládať dvierka palivovej nádrže a nabíjací port"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Ovládanie dvierok palivovej nádrže a nabíjacieho portu"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"čítať identifikačné číslo auta"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Prístup k identifikačnému číslu auta."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"ovládať dvere auta"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Ovládanie sedadiel auta."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"získať prístup k základným informáciám o aute"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Prístup k základným informáciám o aute."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"prístup k informáciám o povoleniach dodávateľa auta"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Prístup k informáciám o povoleniach dodávateľa auta."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"čítať stav vonkajších svetiel auta"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Prístup k stavu vonkajších svetiel auta."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"čítať vonkajšie svetlá auta"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Povoliť registráciu dôveryhodného zariadenia"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Ovládanie testovacieho režimu auta"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Ovládanie testovacieho režimu auta"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Povoliť alebo zakázať funkcie auta"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Povoľte alebo zakážte funkcie auta."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"používať strážcu prevádzky auta"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Používať strážcu prevádzky auta."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moje zariadenie"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Hosť"</string>
 </resources>
diff --git a/service/res/values-sl/strings.xml b/service/res/values-sl/strings.xml
index 54bab6d..0e37f92 100644
--- a/service/res/values-sl/strings.xml
+++ b/service/res/values-sl/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Dostop do kamer avtomobila."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"dostop do podatkov o energiji avtomobila"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Dostop do podatkov o energiji avtomobila."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"prilagajanje preostalega dosega avtomobila"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Prilagajanje preostale vrednosti dosega avtomobila."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"dostop do sistema za ogrevanje, hlajenje in prezračevanje avtomobila"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Dostop do sistema za ogrevanje, hlajenje in prezračevanje avtomobila."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"dostop o podatkov o prevoženih kilometrih avtomobila"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfiguriranje omejitev uporabniške izkušnje"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Komuniciranje z napravo USB v načinu AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Aplikaciji omogoča komuniciranje z napravo v načinu AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Dostop za branje za sistem za zavedanje potnikov"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Omogoča branje stanja in podatkov o zaznavanju sistema za zavedanje potnikov"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Upravljanje grafikona sistema za zavedanje potnikov"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Omogoča upravljanje grafikona začetka in ustavitve zaznavanja sistema za zavedanje potnikov"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Storitev za vhode avtomobila"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Obravnava dogodkov vnosa"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Napaka vodila CAN"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Dostop do podrobnih podatkov o motorju avtomobila."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"dostop do pokrova rezervoarja in polnilnih vrat avtomobila"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Dostop do pokrova rezervoarja in polnilnih vrat avtomobila."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"upravljanje pokrova rezervoarja in polnilnih vrat avtomobila"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Upravljanje pokrova rezervoarja in polnilnih vrat avtomobila."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"branje identifikacijskih podatkov avtomobila"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Dostop do identifikacijskih podatkov avtomobila."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"nadziranje vrat avtomobila"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Nadziranje sedežev avtomobila."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"dostop do osnovnih podatkov avtomobila"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Dostop do osnovnih podatkov avtomobila."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"dostop do podatkov o dovoljenjih prodajalca avtomobila"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Dostop do podatkov o dovoljenjih prodajalca avtomobila."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"branje stanja zunanjih luči avtomobila"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Dostop do stanja zunanjih luči avtomobila."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"branje zunanjih luči avtomobila"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Omogočanje včlanitve zaupanja vredne naprave"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Nadziranje preizkusnega načina avtomobila"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Nadziranje preizkusnega načina avtomobila"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Omogočanje ali onemogočanje funkcij avtomobila."</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Omogočanje ali onemogočanje funkcij avtomobila."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"uporaba avtomobilskega nadzornika"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Uporaba avtomobilskega nadzornika."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Moja naprava"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Gost"</string>
 </resources>
diff --git a/service/res/values-sq/strings.xml b/service/res/values-sq/strings.xml
index dc82e47..89b6944 100644
--- a/service/res/values-sq/strings.xml
+++ b/service/res/values-sq/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Qasu te kamera(t) e makinës."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"qasu tek informacionet e energjisë së makinës"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Qasu tek informacionet e energjisë së makinës."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"rregullo vlerën e mbetur të gamës së makinës"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Rregullo vlerën e mbetur të gamës së makinës."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"qasu në sistemin HVAC të makinës"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Qasu në sistemin HVAC të makinës."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"qasu tek informacionet e kilometrazhit të makinës"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfiguro kufizimet për eksperiencën e përdoruesit"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Komuniko me pajisjen USB në modalitetin AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Lejon që një aplikacion të komunikojë me një pajisje në modalitetin AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Qasja për leximin e Occupant Awareness System"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Lejon leximin e të dhënave për statusin dhe zbulimin për Occupant Awareness System"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontrollo Occupant Awareness System Graph"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Lejon kontrollin e nisjes dhe ndalimit të grafikut të zbulimit të Occupant Awareness System"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Shërbimi i hyrjes së makinës"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Menaxho ngjarjet e hyrjes"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Kanali i komunikimit CAN dështoi"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Qasu tek informacionet e detajuara të motorit të makinës."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"qasu te porta e karburantit të makinës dhe te porta e karikimit"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Qasu te porta e karburantit të makinës dhe te porta e karikimit."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"kontrollo kapakun e karburantit të makinës dhe portën e karikimit"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Kontrollo kapakun e karburantit të makinës dhe portën e karikimit."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"lexo identifikimin e makinës"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Qasu tek identifikimi i makinës."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"kontrollo dyert e makinës"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kontrollo ndenjëset e makinës."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"qasu tek informacionet bazë të makinës"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Qasu tek informacionet bazë të makinës."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"qasu tek informacionet për lejet e shitësit të makinës"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Qasu tek informacionet për lejet e shitësit të makinës."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"lexo gjendjen e dritave të jashtme të makinës"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Qasu te gjendja e dritave të jashtme të makinës."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"lexo dritat e jashtme të makinës"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Lejo regjistrimin e pajisjes së besuar"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Kontrollo modalitetin e testimit të makinës"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Kontrollo modalitetin e testimit të makinës"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Aktivizo ose çaktivizo veçoritë e makinës"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Aktivizo ose çaktivizo veçoritë e makinës."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"përdor monitoruesin e makinës"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Përdor monitoruesin e makinës."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Pajisja ime"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"I ftuar"</string>
 </resources>
diff --git a/service/res/values-sr/strings.xml b/service/res/values-sr/strings.xml
index 0d05a02..c8505b4 100644
--- a/service/res/values-sr/strings.xml
+++ b/service/res/values-sr/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Приступи камерама аутомобила."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"приступ подацима о енергији аутомобила"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Приступи информацијама о енергији аутомобила."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"прилагођавање преосталог домета аутомобила"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Прилагођавање вредности преосталог домета аутомобила."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"приступ грејању, вентилацији и климатизацији аутомобила"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Приступи грејању, вентилацији и климатизацији аутомобила"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"приступ подацима о километражи аутомобила"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Конфигурише ограничења КД-а"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Комуницира са USB уређајем у режиму AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Дозвољава апликацији комуникацију са уређајем у режиму AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Приступ за читање за Occupant Awareness System"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Омогућава читање података о статусу и откривању за Occupant Awareness System"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Управљање графиконом за Occupant Awareness System"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Омогућава покретање и заустављање графикона откривања за Occupant Awareness System"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Услуга аутомобилског уноса"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Управља догађајима уноса"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Грешка CAN магистрале"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Приступ детаљним подацима о мотору аутомобила."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"приступ поклопцу резервоара за гориво и порту за пуњење"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Приступ поклопцу резервоара за гориво и порту за пуњење."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"управљање поклопцем резервоара за гориво и портом за пуњење"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Управљање поклопцем резервоара за гориво и портом за пуњење."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"читање података за идентификацију аутомобила"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Приступ подацима за идентификацију аутомобила."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"Контролисање врата аутомобила"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Контролисање седишта у аутомобилу."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"приступ основним подацима о аутомобилу"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Приступ основним подацима о аутомобилу."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"приступ информацијама о дозволама продавца аутомобила"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Приступа информацијама о дозволама продавца аутомобила."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"читање стања спољних светла аутомобила"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Приступ стању спољних светла аутомобила."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"читање статуса спољних светла аутомобила"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Омогући регистровање поузданих уређаја"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Контрола режима за тестирање аутомобила"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Контрола режима за тестирање аутомобила"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Омогућавање или онемогућавање функција аутомобила"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Омогућавање или онемогућавање функција аутомобила."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"користи надзорни тајмер аутомобила"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Користи надзорни тајмер аутомобила."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Мој уређај"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Гост"</string>
 </resources>
diff --git a/service/res/values-sv/strings.xml b/service/res/values-sv/strings.xml
index 05f586c..a7320db 100644
--- a/service/res/values-sv/strings.xml
+++ b/service/res/values-sv/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Åtkomst till bilens kamera eller kameror."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"åtkomst till information om bilens drivmedel"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Åtkomst till information om bilens drivmedel."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"justera värdet på bilens återstående körsträcka"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Får justera värdet på bilens återstående körsträcka."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"åtkomst till bilens värme, ventilation och luftkonditionering"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Åtkomst till bilens värme-, ventilations- och AC-system."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"åtkomst till information om bilens bränsleförbrukning"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfigurera användningsbegränsningar"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Kommunicera med en USB-enhet i AOAP-läge"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Tillåt att en app kommunicerar med en enhet i AOAP-läge"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Läsbehörighet för Occupant Awareness System"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Tillåter läsning av status och detektionsdata för Occupant Awareness System"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Styra diagrammet för Occupant Awareness System"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Tillåter styrning av start och stopp av detektionsdiagrammet för Occupant Awareness System"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Indatatjänst för bilen"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Hantera indatahändelser"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Fel i CAN-bussen"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Åtkomst till detaljerad information om bilens motor."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"åtkomst till bilens tanklucka och laddningsport"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Åtkomst till bilens tanklucka och laddningsport."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"styra bilens tanklucka och laddningsport"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Styra bilens tanklucka och laddningsport."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"läsa av bilens id-information"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Åtkomst till bilens id-information."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"styra bilens dörrar och luckor"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Styra bilens säten."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"åtkomst till grundläggande uppgifter om bilen"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Åtkomst till grundläggande uppgifter om bilen."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"åtkomst till information om behörighet från bilens tillverkare"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Åtkomst till information om behörighet från bilens tillverkare."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"läsa av status för bilens exteriörbelysning"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Åtkomst till status för bilens exteriörbelysning."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"läsa av bilens exteriörbelysning"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Tillåt registrering av betrodda enheter"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Styra bilens testläge"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Styra bilens testläge"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Aktivera eller inaktivera funktioner i bilen"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Aktivera eller inaktivera funktioner i bilen."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"använd vakthund för bilen"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Använd vakthund för bilen."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Min enhet"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Gäst"</string>
 </resources>
diff --git a/service/res/values-sw/strings.xml b/service/res/values-sw/strings.xml
index 132e340..85eadfd 100644
--- a/service/res/values-sw/strings.xml
+++ b/service/res/values-sw/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Kufikia kamera ya gari lako."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"kufikia maelezo ya nishati ya gari"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Kufikia maelezo ya nishati ya gari lako."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"kurekebisha umbali unaosalia wa kusafiri wa gari"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Kurekebisha thamani inayosalia ya umbali wa kusafiri wa gari."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"kufikia hali ya joto, hewa na kiyoyozi (hvac) katika gari"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Kufikia hali ya joto, hewa na kiyoyozi (hvac) ya gari lako."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"kufikia maelezo ya maili za gari"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Weka Mipangilio ya Masharti ya UX"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Iwasiliane na kifaa cha USB katika hali ya AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Inaruhusu programu iwasiliane na kifaa katika hali ya AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Ufikiaji wa Kusoma wa Mfumo wa Kutambua Waliomo"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Huruhusu kusoma data ya hali na ya utambuzi ya Mfumo wa Kutambua Waliomo"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kudhibiti Grafu ya Mfumo wa Kutambua Waliomo"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Huruhusu udhibiti wa kuanzisha na kusimamisha grafu ya utambuzi ya Mfumo wa Kutambua Waliomo"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Huduma ya Kuweka Data ya Gari"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Kudhibiti matukio ya kuweka data"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Imeshindwa kuleta maelezo ya kebo CAN"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Kufikia maelezo ya kina ya injini ya gari lako."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"kufikia kifuniko cha sehemu ya kuwekea mafuta ya gari na mlango wa kuchaji"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Kufikia maelezo ya kifuniko cha sehemu ya kuwekea mafuta ya gari na mlango wa kuchaji."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"kudhibiti kifuniko cha sehemu ya kuwekea mafuta ya gari na mlango wa kuchaji"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Kudhibiti kifuniko cha sehemu ya kuwekea mafuta ya gari na mlango wa kuchaji."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"kusoma maelezo ya utambulisho wa gari"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Kufikia maelezo ya utambulisho wa gari."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"kudhibiti milango ya gari"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kudhibiti viti vya gari."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"kufikia maelezo ya msingi ya gari"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Kufikia maelezo ya msingi ya gari."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"kufikia maelezo ya ruhusa ya muuzaji wa gari"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Kufikia maelezo ya ruhusa ya muuzaji wa gari"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"kusoma hali ya taa za nje ya gari"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Kufikia hali ya taa za nje ya gari."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"kusoma taa za nje ya gari"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Ruhusu Usajili wa Vifaa Unavyoviamini"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Kudhibiti hali ya jaribio la gari"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Kudhibiti hali ya jaribio la gari"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Washa au uzime vipengele vya gari"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Washa au uzime vipengele vya gari."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"tumia kipengele cha kulinda gari"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Tumia kipengele cha kulinda gari."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Kifaa Changu"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Mgeni"</string>
 </resources>
diff --git a/service/res/values-ta/strings.xml b/service/res/values-ta/strings.xml
index 51bf2ab..63c4493 100644
--- a/service/res/values-ta/strings.xml
+++ b/service/res/values-ta/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"காரின் கேமராவை அணுகுதல்."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"காரின் எரிபொருள் விவரத்தை அணுக வேண்டும்"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"காரின் எரிபொருள் தகவலை அணுகுதல்."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"கார் சென்றடைய மீதமுள்ள மைலேஜின் மதிப்பை மாற்றும்"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"கார் சென்றடைய மீதமுள்ள மைலேஜின் மதிப்பை மாற்றும்."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"காரின் hvac சிஸ்டத்தை அணுக வேண்டும்"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"காரில் வெப்பம், காற்றோட்டம், குளிர்சாதன வசதி ஆகியவற்றை உள்ளடக்கிய அமைப்பை (hvac) அணுகுதல்."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"காரின் மைலேஜ் பற்றிய தகவலை அணுக வேண்டும்"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX கட்டுப்பாடுகளை உள்ளமைத்தல்"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"AOAP பயன்முறையில் USB சாதனத்தை தொடர்புகொள்ளும்"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"AOAP பயன்முறையில் சாதனத்துடன் ஆப்ஸைத் தொடர்புகொள்ள அனுமதிக்கிறது"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"உள்ளிருப்போருக்கான விழிப்புணர்வு சிஸ்டத்தின் வாசிக்கும் அணுகல்"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"உள்ளிருப்போருக்கான விழிப்புணர்வு சிஸ்டத்திற்கு வாசிக்கும் நிலையையும் கண்டறிதல் தரவையும் அனுமதிக்கிறது"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"உள்ளிருப்போருக்கான விழிப்புணர்வு சிஸ்டத்தின் வரைபடத்தைக் கட்டுப்படுத்த வேண்டும்"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"உள்ளிருப்போருக்கான விழிப்புணர்வு சிஸ்டத்தின் கண்டறிதல் வரைபடத்தை தொடங்குவதற்கும் நிறுத்துவதற்கும் கட்டுப்படுத்த அனுமதிக்கிறது"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"காருக்கு உற்பத்தியாளர் வழங்கும் சேவை"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"உற்பத்தியாளர் வழங்கும் சேவைகளைக் கையாளுதல்"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus அமைப்பு தோல்வியடைந்தது"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"காரின் இன்ஜின் குறித்த முழுமையான தகவலை அணுக வேண்டும்."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"காரின் எரிபொருள் மூடியையும் சார்ஜ் போர்ட்டையும் அணுக வேண்டும்"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"காரின் எரிபொருள் மூடியையும் சார்ஜ் போர்ட்டையும் அணுக வேண்டும்."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"காரின் எரிபொருள் மூடியையும் சார்ஜ் போர்ட்டையும் கட்டுப்படுத்த வேண்டும்"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"காரின் எரிபொருள் மூடியையும் சார்ஜ் போர்ட்டையும் கட்டுப்படுத்த வேண்டும்."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"காரின் VIN தகவலை அறிய வேண்டும்"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"காரின் VIN தகவலை அணுக வேண்டும்."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"காரின் கதவுகளை நிர்வகிக்க வேண்டும்"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"காரின் இருக்கைகளை நிர்வகிக்க வேண்டும்."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"காரின் அடிப்படைத் தகவலை அணுக வேண்டும்"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"காரின் அடிப்படைத் தகவலை அணுக வேண்டும்."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"காரின் தயாரிப்பாளர் அனுமதி குறித்த விவரங்களை அணுகுதல்"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"காரின் தயாரிப்பாளர் அனுமதி குறித்த விவரங்களை அணுகுதல்."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"காரின் வெளிப்புற விளக்குகளின் நிலையை அறிய வேண்டும்"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"காரின் வெளிப்புற விளக்குகளின் நிலையை அணுக வேண்டும்."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"காரின் வெளிப்புற விளக்குகளை அறிய வேண்டும்"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"’நம்பகமான சாதனம்’ என்று பதிவு செய்வதை அனுமதிக்கும்"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"காரின் சோதனைப் பயன்முறையைக் கட்டுப்படுத்த வேண்டும்"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"காரின் சோதனைப் பயன்முறையைக் கட்டுப்படுத்த வேண்டும்"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"காரின் அம்சங்களை இயக்கும் அல்லது முடக்கும்"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"காரின் அம்சங்களை இயக்கும் அல்லது முடக்கும்."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"பயன்படுத்திய காருக்கான ஒழுங்குமுறை ஆணையம்"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"பயன்படுத்திய காருக்கான ஒழுங்குமுறை ஆணையம்."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"எனது சாதனம்"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"விருந்தினர்"</string>
 </resources>
diff --git a/service/res/values-te/strings.xml b/service/res/values-te/strings.xml
index fb11edf..d886359 100644
--- a/service/res/values-te/strings.xml
+++ b/service/res/values-te/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"మీ కారు యొక్క కామెరా(లు)ని యాక్సెస్ చేయండి."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"కారు శక్తి సమాచారాన్ని యాక్సెస్ చేయగలవు"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"మీ కారు శక్తి సమాచారాన్ని యాక్సెస్ చేయండి."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"కారు యొక్క మిగిలిన ప్రయాణ దూరాన్ని సర్దుబాటు చేయండి"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"కారు యొక్క మిగిలిన ప్రయాణ దూర విలువను సర్దుబాటు చేయండి."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"కారు hvacని యాక్సెస్ చేయగలవు"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"మీ కారు యొక్క hvacని యాక్సెస్ చేయండి"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"కారు మైలేజీ సమాచారాన్ని యాక్సెస్ చేయగలవు"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX పరిమితులను కాన్ఫిగర్ చెయ్యండి"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"AOAP మోడ్‌లో USB పరికరాన్ని కమ్యూనికేట్ చేయండి"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"AOAP మోడ్‌లో పరికరంతో కమ్యూనికేట్ చేయడానికి యాప్‌ను అనుమతిస్తుంది"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant Awareness Systemను చదవే యాక్సెస్"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Occupant Awareness Systemకు చదివే స్థితిని, డేటాను గుర్తించడాన్ని అనుమతిస్తుంది"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Occupant Awareness System గ్రాఫ్‌ను నియంత్రించు"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Occupant Awareness Systemను గుర్తించే గ్రాఫ్‌ను ప్రారంభించడాన్ని, ఆపివేయడాన్ని నియంత్రించడానికి అనుమతిస్తుంది"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"కారు ఇన్‌పుట్ సేవ"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ఇన్‌పుట్ ఈవెంట్‌లను హ్యాండిల్ చేయండి"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN బస్సు విఫలమైంది"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"మీ కారు యొక్క సమగ్ర ఇంజిన్ సమాచారాన్ని యాక్సెస్ చేయగలవు."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"కారు ఇంధన డోర్ మరియు ఛార్జ్ పోర్ట్‌ను యాక్సెస్ చేయగలవు"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"కారు ఇంధన తలుపు మరియు ఛార్జ్ పోర్ట్‌ను యాక్సెస్ చేయగలవు."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"కారు ఇంధన డోర్, ఛార్జ్ పోర్ట్‌ను నియంత్రించు"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"కారు ఇంధన డోర్, ఛార్జ్ పోర్ట్‌ను నియంత్రించు"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"కారు గుర్తింపును చూడగలవు"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"కారు గుర్తింపును యాక్సెస్ చేయగలవు."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"కారు డోర్‌లను నియంత్రించగలవు"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"కారు సీట్లను నియంత్రించగలవు."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"కారు ప్రాథమిక సమాచారాన్ని యాక్సెస్ చేయగలవు"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"కారు యొక్క ప్రాథమిక సమాచారాన్ని యాక్సెస్ చేయగలవు."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"కారు విక్రేత అనుమతి సమాచారాన్ని యాక్సెస్ చేయగలవు"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"కారు విక్రేత అనుమతి సమాచారాన్ని యాక్సెస్ చేయగలవు."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"కారు బయటి లైట్‌ల స్థితిని తెలుసుకోగలవు"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"కారు బయటి లైట్‌ల స్థితిని యాక్సెస్ చేయగలవు."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"కారు బయటి లైట్‌ల స్థితిని తెలుసుకోగలవు"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"విశ్వసనీయ పరికర నమోదును అనుమతించండి"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"కారు యొక్క పరీక్ష మోడ్‌ను నియంత్రించండి"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"కారు యొక్క పరీక్ష మోడ్‌ను నియంత్రించండి"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"కార్ ఫీచర్‌లను ఎనేబుల్ లేదా డిజేబుల్ చేయడం"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"కార్ ఫీచర్‌లను ఎనేబుల్ లేదా డిజేబుల్ చేయడం."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"కార్ వాచ్‌డాగ్‌ను ఉపయోగించండి"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"కార్ వాచ్‌డాగ్‌ను ఉపయోగించండి."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"నా పరికరం"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"అతిథి"</string>
 </resources>
diff --git a/service/res/values-th/strings.xml b/service/res/values-th/strings.xml
index 22786e2..62b454a 100644
--- a/service/res/values-th/strings.xml
+++ b/service/res/values-th/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"เข้าถึงกล้องของรถ"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"เข้าถึงข้อมูลพลังงานของรถ"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"เข้าถึงข้อมูลพลังงานของรถ"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"ปรับระยะวิ่งที่เหลืออยู่ของรถ"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"ปรับค่าระยะวิ่งที่เหลืออยู่ของรถ"</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"เข้าถึง HVAC ของรถ"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"เข้าถึง HVAC ของรถ"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"เข้าถึงข้อมูลระยะไมล์ของรถ"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"กำหนดค่าข้อจำกัด UX"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"สื่อสารกับอุปกรณ์ USB ในโหมด AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"อนุญาตให้แอปสื่อสารกับอุปกรณ์ในโหมด AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"การเข้าถึงการอ่านระบบการรับรู้ว่ามีคนอยู่"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"อนุญาตการอ่านข้อมูลสถานะและการตรวจจับของระบบการรับรู้ว่ามีคนอยู่"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"ควบคุมกราฟระบบการรับรู้ว่ามีคนอยู่"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"อนุญาตการเริ่มต้นและหยุดกราฟการตรวจจับของระบบการรับรู้ว่ามีคนอยู่"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"บริการป้อนข้อมูลของรถ"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"จัดการเหตุการณ์การป้อนข้อมูล"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN Bus ล้มเหลว"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"เข้าถึงข้อมูลเครื่องยนต์ของรถโดยละเอียด"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"เข้าถึงฝาถังน้ำมันและพอร์ตชาร์จ"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"เข้าถึงฝาถังน้ำมันและพอร์ตชาร์จ"</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"ควบคุมฝาถังน้ำมันและพอร์ตชาร์จของรถ"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"ควบคุมฝาถังน้ำมันและพอร์ตชาร์จของรถ"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"อ่านการระบุตัวรถ"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"เข้าถึงการระบุตัวรถ"</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"ควบคุมประตูรถ"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"ควบคุมที่นั่งในรถ"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"เข้าถึงข้อมูลเบื้องต้นของรถ"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"เข้าถึงข้อมูลเบื้องต้นของรถ"</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"เข้าถึงข้อมูลสิทธิ์ผู้จำหน่ายของรถ"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"เข้าถึงข้อมูลสิทธิ์ผู้จำหน่ายของรถ"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"อ่านสถานะไฟภายนอกรถ"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"เข้าถึงสถานะไฟภายนอกรถ"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"อ่านไฟภายนอกรถ"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"อนุญาตการลงทะเบียนอุปกรณ์ที่เชื่อถือได้"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"ควบคุมโหมดการทดสอบของรถยนต์"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"ควบคุมโหมดการทดสอบของรถยนต์"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"เปิดหรือปิดใช้ฟีเจอร์ของรถยนต์"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"เปิดหรือปิดใช้ฟีเจอร์ของรถยนต์"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"ใช้ Watchdog ในรถ"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"ใช้ Watchdog ในรถ"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"อุปกรณ์ของฉัน"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"ผู้มาเยือน"</string>
 </resources>
diff --git a/service/res/values-tl/strings.xml b/service/res/values-tl/strings.xml
index 3f49db7..47f4172 100644
--- a/service/res/values-tl/strings.xml
+++ b/service/res/values-tl/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"I-access ang (mga) camera ng iyong sasakyan."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"i-access ang impormasyon ng enerhiya ng sasakyan"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"I-access ang impormasyon sa enerhiya ng iyong sasakyan."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"isaayos ang natitirang range ng sasakyan"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Isaayos ang value ng natitirang range ng sasakyan."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"i-access ang hvac ng sasakyan"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"I-access ang hvac ng iyong sasakyan."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"i-access ang impormasyon ng mileage ng sasakyan"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"I-configure ang Mga Paghihigpit sa UX"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Makipag-ugnayan sa pamamagitan ng USB device sa AOAP mode"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Binibigyang-daan ang isang app na makipag-ugnayan sa isang device sa AOAP mode"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Access sa Pagbasa sa Occupant Awareness System"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Pinapayagan ang pagbasa sa status at data ng pag-detect para sa Occupant Awareness System"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontrolin ang Graph ng Occupant Awareness System"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Pinapayagan ang pagkontrol sa pagsimula at paghinto sa detection graph ng Occupant Awareness System"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Serbisyo sa Input ng Sasakyan"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Pangasiwaan ang mga event ng input"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Hindi gumana ang CAN bus"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"I-access ang detalyadong impormasyon sa makina ng iyong sasakyan."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"i-access ang takip ng gasolina at charge port ng sasakyan"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"I-access ang takip ng gasolina at charge port ng sasakyan."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"kontrolin ang takip ng gasolina at charge port ng sasakyan"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Kontrolin ang takip ng gasolina at charge port ng sasakyan."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"basahin ang pagkakakilanlan ng sasakyan"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"I-access ang pagkakakilanlan ng sasakyan."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"kontrolin ang mga pintuan ng sasakyan"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kontrolin ang mga upuan ng sasakyan."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"i-access ang pangunahing impormasyon ng sasakyan"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"I-access ang pangunahing impormasyon ng sasakyan."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"i-access ang impormasyon ng pahintulot ng vendor ng sasakyan"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"I-access ang impormasyon ng pahintulot ng vendor ng sasakyan."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"basahin ang status ng mga ilaw sa labas ng sasakyan"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"I-access ang status ng mga ilaw sa labas ng sasakyan."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"basahin ang mga ilaw sa labas ng sasakyan"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Payagan ang Pag-enroll ng Pinagkakatiwalaang Device"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Kontrolin ang test mode ng kotse"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Kontrolin ang test mode ng kotse"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"I-enable o i-disable ang mga feature ng kotse."</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"I-enable o i-disable ang mga feature ng kotse."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"gamitin ang watchdog ng sasakyan"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Gamitin ang watchdog ng sasakyan."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Aking Device"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Bisita"</string>
 </resources>
diff --git a/service/res/values-tr/strings.xml b/service/res/values-tr/strings.xml
index 6ab1526..4419f98 100644
--- a/service/res/values-tr/strings.xml
+++ b/service/res/values-tr/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Aracınızın kameralarına erişim."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"aracın enerji bilgilerine erişim"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Aracınızın enerji bilgilerine erişim."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"aracın kalan menzil değerini düzenleme"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Aracın kalan menzil değerini düzenler."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"aracın HVAC\'sine erişim"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Aracınızın HVAC\'sine erişim."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"aracın kilometre bilgilerine erişim"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Kullanıcı Deneyimi Kısıtlamalarını Yapılandırma"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"AOAP modunda USB cihazıyla iletişim kur"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Uygulamaların AOAP modunda cihazlarla iletişim kurmasına izin verir"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Yolcu Algılama Sistemi Okuma Erişimi"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Yolcu Algılama Sistemi için durumun ve tespit verilerinin okunmasına izin verir"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Yolcu Algılama Sistemi Grafiğini kontrol et"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Yolcu Algılama Sistemi tespit grafiğinin başlatılmasının ve durdurulmasının kontrol edilmesine izin verir"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Araç Giriş Hizmeti"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Giriş olaylarını işleme"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN veri yolu başarısız"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Aracınızın ayrıntılı motor bilgilerine erişim."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"aracın yakıt kapağına ve şarj bağlantı noktasına erişim"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Aracın yakıt kapağına ve şarj bağlantı noktasına erişim."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"aracın yakıt kapağını ve şarj bağlantı noktasını kontrol et"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Aracın yakıt kapağını ve şarj bağlantı noktasını kontrol edin."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"aracın kimliğini okuma"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Aracın kimliğine erişim."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"aracın kapılarını kontrol etme"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Aracın koltuklarını kontrol etme."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"aracın temel bilgilerine erişim"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Aracın temel bilgilerine erişim."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"aracın tedarikçi firma izin bilgilerine erişin"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Aracın tedarikçi firma izin bilgilerine erişin."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"aracın dış ışıklarının durumunu okuma"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Aracın dış ışıklarının durumuna erişim."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"aracın dış ışıklarını okuma"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Güvenilen Cihaz Kaydına İzin Ver"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Aracın test modunu kontrol etme"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Aracın test modunu kontrol etme"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Arabanın özelliklerini etkinleştirin veya devre dışı bırakın"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Arabanın özelliklerini etkinleştirin veya devre dışı bırakın."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"araç güvenlik zamanlayıcısını kullan"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Araç güvenlik zamanlayıcısını kullan."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Cihazım"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Misafir"</string>
 </resources>
diff --git a/service/res/values-uk/strings.xml b/service/res/values-uk/strings.xml
index d8dd8e7..a7f6ef4 100644
--- a/service/res/values-uk/strings.xml
+++ b/service/res/values-uk/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Доступ до камер автомобіля."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"доступ до інформації про енергоспоживання автомобіля"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Доступ до інформації про енергоспоживання автомобіля."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"коригувати залишок пробігу автомобіля"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Коригувати значення залишку пробігу автомобіля."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"доступ до системи клімат-контролю автомобіля"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Доступ до системи клімат-контролю автомобіля."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"доступ до інформації про пробіг автомобіля"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Налаштувати обмеження щодо використання функцій"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Зв’язуватися з USB-пристроєм в режимі AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Дозволяє додатку зв’язуватися з пристроєм у режимі AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Перегляд даних системи визначення присутності пасажира"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Дозволяє переглядати статус і дані системи визначення присутності пасажира"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Керування графіком визначення присутності пасажира"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Дозволяє керувати графіком визначення присутності пасажира"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Сервіс даних про вхідні події автомобіля"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Обробка вхідних подій"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Помилка CAN-шини"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Доступ до детальної інформації про двигун автомобіля."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"доступ до даних про кришку паливного бака чи порт заряджання автомобіля"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Доступ до даних про кришку паливного бака чи порт заряджання автомобіля."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"керування кришкою паливного бака й портом заряджання автомобіля"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Керування кришкою паливного бака й портом заряджання автомобіля."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"перегляд ідентифікаційного номера автомобіля"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Доступ до ідентифікаційного номера автомобіля."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"керування дверима автомобіля"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Керування сидіннями автомобіля."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"доступ до основної інформації про автомобіль"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Доступ до основної інформації про автомобіль."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"мають доступ до інформації про дозволи виробника автомобіля"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Мають доступ до інформації про дозволи виробника автомобіля."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"перегляд стану зовнішніх світлових приладів автомобіля"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Керування зовнішніми світловими приладами автомобіля."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"перегляд зовнішніх світлових приладів автомобіля"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Дозволити реєстрацію надійних пристроїв"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Керувати режимом тестування автомобіля"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Керувати режимом тестування автомобіля"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Вмикати чи вимикати функції автомобіля"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Вмикати чи вимикати функції автомобіля"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"використовувати сторожовий таймер автомобіля"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Використовувати сторожовий таймер автомобіля."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Мій пристрій"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Гість"</string>
 </resources>
diff --git a/service/res/values-ur/strings.xml b/service/res/values-ur/strings.xml
index dca6e36..01b7626 100644
--- a/service/res/values-ur/strings.xml
+++ b/service/res/values-ur/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"اپنی کار کے کیمرے (کیمروں) تک رسائی حاصل کریں۔"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"کار کی انرجی کی معلومات تک رسائی حاصل کریں"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"اپنی کار کی انرجی کی معلومات تک رسائی حاصل کریں۔"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"کار کی باقی حد ایڈجسٹ کریں"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"کار کی باقی حد قدر کو ایڈجسٹ کریں۔"</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"کار کی hvac تک رسائی حاصل کریں"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"اپنی کار کی hvac تک رسائی حاصل کریں۔"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"کار کی مائلیج کی معلومات تک رسائی حاصل کریں"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX کی پابندیاں ترتیب دیں"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"USB آلہ کے ساتھ AOAP وضع میں مواصلت کریں"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"آلہ کے ساتھ AOAP وضع میں ایپ مواصلت کر سکتی ہے"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"کار میں بیٹھنے والے فرد کے لیے بنے آگاہی کے سسٹم کی رسائی کو پڑھیں"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"کار میں بیٹھنے والے فرد کے لیے بنے آگاہی کے سسٹم کیلئے پڑھنے کی حیثیت اور ڈیٹا کا پتہ لگانے کی اجازت دیتا ہے"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"کار میں بیٹھنے والے فرد کے لیے بنے آگاہی کے سسٹم کے گراف کو کنٹرول کریں"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"کار میں بیٹھنے والے فرد کے لیے بنا آگاہی کا سسٹم پتہ لگانے کے گراف کو شروع کرنے اور روکنے کی اجازت دیتا ہے"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"کار کی ان پٹ سروس"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ایونٹس کے ان پٹ کو ہینڈل کریں"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"کین بس ناکام ہو گئی"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"اپنی کار کے انجن کی تفصیلی معلومات تک رسائی حاصل کریں۔"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"کار کے ایندھن کے دروازے اور چارج پورٹ تک رسائی حاصل کریں"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"کار کے ایندھن کے دروازے اور چارج پورٹ تک رسائی حاصل کریں۔"</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"کار کے ایندھن کے دروازے اور چارج پورٹ کنٹرول کریں"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"کار کے ایندھن کے دروازے اور چارج پورٹ کنٹرول کریں۔"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"کار کی شناخت کے بارے میں پڑھیں"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"کار کی شناخت تک رسائی حاصل کریں۔"</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"کار کے دروازوں کو کنٹرول کریں"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"کار کی سیٹوں کو کنٹرول کریں۔"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"کار کی بنیادی معلومات تک رسائی حاصل کریں"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"کار کی بنیادی معلومات حاصل کریں۔"</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"کار کے وینڈر کے اجازت کی معلومات تک رسائی حاصل کریں"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"کار کے وینڈر کے اجازت کی معلومات تک رسائی حاصل کریں۔"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"کار کی بیرونی روشنیوں کی صورتحال کے بارے میں پڑھیں"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"کار کی بیرونی روشنیوں کی صورتحال تک رسائی حاصل کریں۔"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"کار کی بیرونی روشنیوں کے بارے میں پڑھیں"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"بھروسہ مند آلات کے اندراج کی اجازت دیں"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"کار کے ٹیسٹ وضع کو کنٹرول کریں"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"کار کے ٹیسٹ وضع کو کنٹرول کریں"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"کار کی خصوصیات کو فعال یا غیر فعال کریں"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"کار کی خصوصیات کو فعال یا غیر فعال کریں۔"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"کار کے واچ ڈاگ کا ستعمال کریں"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"کار کے واچ ڈاگ کا ستعمال کریں۔"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"میرا آلہ"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"مہمان"</string>
 </resources>
diff --git a/service/res/values-uz/strings.xml b/service/res/values-uz/strings.xml
index 80b2c71..7f9e006 100644
--- a/service/res/values-uz/strings.xml
+++ b/service/res/values-uz/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Avtomobil kamerasidan foydalanish"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"avtomobilning energiya manbalari haqidagi axborotga kirish"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Avtomobilning energiya axborotlariga kirish"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"avtomobil mavjud yonilgʻi bilan bosib oʻtadigan masofani tuzatish"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Avtomobil mavjud yonilgʻi bilan bosib oʻtadigan masofani tuzatish."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"avtomobilning HVAC tizimiga kirish"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Avtomobilning HVAC tizimiga kirish."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"avtomobil yonilgʻisi qancha masofaga yetishi haqidagi axborotga kirish"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Funksiyalardan foydalanishni cheklash"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"USB qurilma bilan AOAP rejimida axborot almashish"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Ilova AOAP rejimida qurilma bilan axborot almasha oladi"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Yoʻlovchilarni aniqlash tizimini oʻqishga ruxsat"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Yoʻlovchilarni aniqlash tizimi uchun holat va aniqlash maʼlumotlarini oʻqishga ruxsat beradi"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Yoʻlovchilarni aniqlash tizimi chizmasini boshqarish"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Yoʻlovchilarni aniqlash tizimining aniqlash chizmasini boshlash va toʻxtatishni boshqarishga ruxsat beradi"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Avtomobilda matn kiritish xizmati"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Matn kiritish hodisalari bilan ishlash imkoniyati"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN shinalarida xatolik yuz berdi"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Avtomobilning motori haqidagi batafsil axborotga kirish."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"avtomobilning yonilgʻi darajasi va quvvatlash porti haqidagi axborotga kirish"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Avtomobilingizning yonilgʻi darajasi va quvvatlash porti haqidagi axborotga kirish."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"avtomobilning yonilgʻi darajasi va quvvatlash porti haqidagi axborotni boshqarish."</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Avtomobilning yonilgʻi darajasi va quvvatlash porti haqidagi axborotni boshqarish."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"avtomobilning identifikatsiya axborotini ochish"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Avtomobilning identifikatsiya axborotiga kirish"</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"avtomobilning eshiklarini boshqarish"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Avtomobil oʻrindiqlarini boshqarish"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"avtomobil haqidagi batafsil axborotga kirish"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Avtomobil haqidagi batafsil axborotga kirish."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"avtomobilning taʼminotchi ruxsatlari axborotiga kirish"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Avtomobilning taʼminotchi ruxsatlari axborotiga kirish."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"avtomobilning tashqi chiroqlari holati haqidagi axborotni ochish"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Avtomobilning tashqi chiroqlari holati haqidagi axborotiga kirish."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"avtomobilning tashqi chiroqlari holati haqidagi axborotni ochish"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Ishonchli qurilma registratsiyasiga ruxsat berish"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Avtomobilning sinov rejimini boshqarish"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Avtomobilning sinov rejimini boshqarish"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Avtomobil funksiyalarini yoqish yoki faolsizlantirish"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Avtomobil funksiyalarini yoqish yoki faolsizlantirish"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"avtomobilni kuzatish tizimidan foydalanish."</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Avtomobilni kuzatish tizimidan foydalanish."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Qurilmam"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Mehmon"</string>
 </resources>
diff --git a/service/res/values-vi/strings.xml b/service/res/values-vi/strings.xml
index 8712694..7426314 100644
--- a/service/res/values-vi/strings.xml
+++ b/service/res/values-vi/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Truy cập vào (các) camera trên ô tô."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"truy cập vào thông tin về năng lượng của ô tô"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Truy cập vào thông tin về mức năng lượng trên ô tô của bạn."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"điều chỉnh quãng đường còn đi được của ô tô"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Điều chỉnh giá trị quãng đường còn đi được của ô tô."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"truy cập vào hệ thống điều hòa không khí (hvac) của ô tô"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Truy cập vào hvac của ô tô."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"truy cập vào thông tin về quãng đường đi được của ô tô"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Định cấu hình các hạn chế trải nghiệm người dùng"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Kết nối với thiết bị USB ở chế độ AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Cho phép ứng dụng kết nối với một thiết bị ở chế độ AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Quyền truy cập đọc Occupant Awareness System"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Cho phép đọc trạng thái và dữ liệu phát hiện của Occupant Awareness System"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Biểu đồ kiểm soát Occupant Awareness System"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Cho phép kiểm soát việc bắt đầu và dừng biểu đồ phát hiện Occupant Awareness System"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Dịch vụ nhập dành cho ô tô"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Xử lý sự kiện nhập"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Đường dẫn chính CAN không hoạt động"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Truy cập vào thông tin chi tiết về động cơ trên ô tô của bạn."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"truy cập vào cổng sạc và cổng nhiên liệu của ô tô"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Truy cập vào cổng sạc và cổng nhiên liệu trên ô tô."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"kiểm soát cổng sạc và cổng nhiên liệu của ô tô"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Kiểm soát cổng sạc và cổng nhiên liệu của ô tô."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"đọc thông tin nhận dạng ô tô"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Truy cập vào thông tin nhận dạng ô tô."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"kiểm soát cửa ô tô"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kiểm soát ghế ngồi trên ô tô."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"truy cập vào thông tin cơ bản của ô tô"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Truy cập vào thông tin cơ bản của ô tô."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"truy cập vào thông tin về quyền của nhà sản xuất ô tô"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Truy cập vào thông tin về quyền của nhà sản xuất ô tô."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"đọc trạng thái đèn bên ngoài ô tô"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Truy cập vào trạng thái đèn bên ngoài ô tô."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"đọc đèn bên ngoài ô tô"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Cho phép đăng ký thiết bị tin cậy"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Kiểm soát chế độ kiểm tra của ô tô"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Kiểm soát chế độ kiểm tra của ô tô"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Bật hoặc tắt các tính năng của ô tô"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Bật hoặc tắt các tính năng của ô tô."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"dùng dịch vụ theo dõi tình trạng xe"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Dùng dịch vụ theo dõi tình trạng xe."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Thiết bị của tôi"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Khách"</string>
 </resources>
diff --git a/service/res/values-zh-rCN/strings.xml b/service/res/values-zh-rCN/strings.xml
index 9484694..8357acc 100644
--- a/service/res/values-zh-rCN/strings.xml
+++ b/service/res/values-zh-rCN/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"访问汽车摄像头。"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"访问汽车的能耗信息"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"访问汽车的能耗信息。"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"调整汽车的剩余可行驶距离"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"调整汽车的剩余可行驶距离值。"</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"访问汽车的暖通空调"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"访问汽车的 HVAC。"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"访问汽车的行驶里程信息"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"配置用户体验限制条件"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"在 AOAP 模式下与 USB 设备通信"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"允许应用在 AOAP 模式下与设备通信"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant Awareness System 读取权限"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"允许读取 Occupant Awareness System 的状态和检测数据"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"控制 Occupant Awareness System 图表"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"允许控制 Occupant Awareness System 检测图表的启动和停止"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"汽车输入服务"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"处理输入事件"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN 总线故障"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"访问汽车的详细引擎信息。"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"访问汽车的油箱盖和充电端口信息"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"访问汽车的油箱盖和充电端口信息。"</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"控制汽车的油箱盖和充电端口"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"控制汽车的油箱盖和充电端口。"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"读取汽车的识别信息"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"访问汽车的标识信息。"</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"控制车门"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"控制车座。"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"访问汽车的基本信息"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"访问汽车的基本信息。"</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"访问汽车的供应商权限信息"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"访问汽车的供应商权限信息。"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"读取汽车的外部灯具状态信息"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"访问汽车的外部灯具状态信息。"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"读取汽车的外部灯具信息"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"允许注册可信设备"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"控制汽车的测试模式"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"控制汽车的测试模式"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"启用或停用汽车的功能"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"启用或停用汽车的功能。"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"使用汽车监控定时器"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"使用汽车监控定时器。"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"我的设备"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"访客"</string>
 </resources>
diff --git a/service/res/values-zh-rHK/strings.xml b/service/res/values-zh-rHK/strings.xml
index 98397b0..1510099 100644
--- a/service/res/values-zh-rHK/strings.xml
+++ b/service/res/values-zh-rHK/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"存取汽車攝錄機。"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"存取汽車的能源資訊"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"存取汽車的電量資訊。"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"調整汽車油量餘額"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"調整汽車油量餘額。"</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"存取汽車的暖通空調"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"存取汽車的暖通空調。"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"存取汽車里數資訊"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"設定使用者體驗限制"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"與啟用 AOAP 模式的 USB 裝置通訊"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"允許應用程式與啟用 AOAP 模式的裝置通訊"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant Awareness System 的讀取權限"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"允許讀取 Occupant Awareness System 的狀態和偵測數據"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"控制 Occupant Awareness System 圖表"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"允許控制何時開始和停止 Occupant Awareness System 的偵測圖表"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"汽車輸入服務"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"處理輸入活動"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"控制器區域網路操作失敗"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"存取汽車引擎詳情。"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"存取汽車油箱蓋及充電埠"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"存取汽車油箱蓋及充電埠。"</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"控制汽車油箱蓋及充電埠"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"控制汽車油箱蓋及充電埠。"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"讀取汽車識別資訊"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"存取汽車識別資訊。"</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"控制車門"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"控制汽車座位。"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"存取汽車基本資訊"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"存取汽車基本資訊。"</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"存取汽車供應商權限資訊"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"存取汽車供應商權限資訊。"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"讀取汽車外部燈光狀態"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"存取汽車外部燈光狀態。"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"讀取汽車外部燈光"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"允許註冊信任的裝置"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"控制汽車的測試模式"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"控制汽車的測試模式"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"啟用或停用汽車的功能"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"啟用或停用汽車的功能。"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"使用汽車監控服務"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"使用汽車監控服務。"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"我的裝置"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"訪客"</string>
 </resources>
diff --git a/service/res/values-zh-rTW/strings.xml b/service/res/values-zh-rTW/strings.xml
index 62239ae..0de37a5 100644
--- a/service/res/values-zh-rTW/strings.xml
+++ b/service/res/values-zh-rTW/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"存取車輛攝影機。"</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"存取車輛的能源資訊"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"存取車輛的能源資訊。"</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"調整汽車的剩餘可行駛距離"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"調整汽車的剩餘可行駛距離值。"</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"存取車輛空調"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"存取車輛空調。"</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"存取車輛的行駛里程資訊"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"設定使用者體驗限制"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"使用 AOAP 模式與 USB 裝置通訊"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"允許應用程式使用 AOAP 模式與裝置通訊"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant Awareness System 讀取權限"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"允許讀取 Occupant Awareness System 的狀態和偵測資料"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"控管 Occupant Awareness System 圖表"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"允許控管 Occupant Awareness System 偵測圖表的啟用和停用狀況"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"車輛輸入服務"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"處理輸入事件"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"控制器區域網路發生問題"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"存取車輛的詳細引擎資訊。"</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"存取車輛的油孔蓋和充電口"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"存取車輛的油孔蓋和充電口。"</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"控管車輛的油孔蓋和充電口"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"控管車輛的油孔蓋和充電口。"</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"讀取車輛識別號碼"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"存取車輛識別號碼。"</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"控制車門"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"控制車輛座椅。"</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"存取車輛的基本資訊"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"存取車輛的基本資訊。"</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"存取車商權限資訊"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"存取車商權限資訊。"</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"讀取車輛外部燈光狀態"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"存取車輛外部燈光狀態。"</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"讀取車輛外部燈光"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"允許註冊信任的裝置"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"控制車輛的測試模式"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"控制車輛的測試模式"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"啟用或停用車輛的功能"</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"啟用或停用車輛的功能。"</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"使用車輛監控計時器"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"使用車輛監控計時器。"</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"我的裝置"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"訪客"</string>
 </resources>
diff --git a/service/res/values-zu/strings.xml b/service/res/values-zu/strings.xml
index 515dc06..ede8f50 100644
--- a/service/res/values-zu/strings.xml
+++ b/service/res/values-zu/strings.xml
@@ -22,6 +22,8 @@
     <string name="car_permission_desc_camera" msgid="917024932164501426">"Finyelela ikhamera yemoto yakho."</string>
     <string name="car_permission_label_energy" msgid="7409144323527821558">"finyelela ulwazi lamandla lemoto"</string>
     <string name="car_permission_desc_energy" msgid="3392963810053235407">"Finyelela ulwazi lwamandla lwemoto yakho."</string>
+    <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"lungisa ivelu elisele lebanga lemoto"</string>
+    <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Lungisa ivelu elisele lebanga lemoto."</string>
     <string name="car_permission_label_hvac" msgid="1499454192558727843">"i-hvac yemoto"</string>
     <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Finyelela i-hvac yemoto yakho."</string>
     <string name="car_permission_label_mileage" msgid="4661317074631150551">"finyelela ulwazi lwe-mileage lemoto"</string>
@@ -62,6 +64,10 @@
     <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Lungisa imikhawulo ye-UX"</string>
     <string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Xhumana nedivayisi ye-USB kumodi ye-AOAP"</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Ivumela uhlelo lokusebenza ukuthi luxhumane nedivayisi kumodi ye-AOAP"</string>
+    <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Ukufinyelela Ekufundeni Kwesistimu Yokwazisa Yomgibeli"</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Ivumela isimo sokufundwa nokutholakala kwedatha Yesistimu Yokwazisa Yomgibeli"</string>
+    <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Lawula Igrafu Yesistimu Yokwazisa Yomgibeli"</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Ivumela ukulawula ukuqalwa nokumiswa kwegrafu yokutholakala Kwesistimu Yokwazisa Yomgibeli"</string>
     <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Isevisi yokufaka yemoto"</string>
     <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Phatha imicimbi yokungena"</string>
     <string name="car_can_bus_failure" msgid="2334035748788283914">"Ibhasi ye-CAN yehlulekile"</string>
@@ -89,6 +95,8 @@
     <string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Finyelela ulwazi lwenjini olunemininingwane lwemoto yakho."</string>
     <string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"iinyelela umnyango kaphethiloli nembobo yokushaja"</string>
     <string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Finyelela umnyango kaphethiloli nembobo yokushaja."</string>
+    <string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"lawula umnyango wesibaseli semoto kanye nembobo yokushaja"</string>
+    <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Lawula umnyango wesibaseli semoto kanye nembobo yokushaja."</string>
     <string name="car_permission_label_car_identification" msgid="5896712510164020478">"funda ubunikazi bemoto"</string>
     <string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Finyelela isihlonzi semoto."</string>
     <string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"lawula iminyango yemoto"</string>
@@ -101,6 +109,8 @@
     <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Lawula izihlalo zemoto."</string>
     <string name="car_permission_label_car_info" msgid="4707513570676492315">"finyelela ulwazi oluyisisekelo lwemoto"</string>
     <string name="car_permission_desc_car_info" msgid="2118081474543537653">"Finyelela ulwazi oluyisisekelo."</string>
+    <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"finyelela ulwazi lwemvume lomthengisi wemoto"</string>
+    <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Finyelela ulwazi lwemvume lomthengisi wemoto."</string>
     <string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"funda isimo somkhanyo wemoto sangaphakathi"</string>
     <string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Finyelela isimo sezibani sangaphandle semoto."</string>
     <string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"Funda isimo sezibani zangaphandle zemoto"</string>
@@ -127,6 +137,10 @@
     <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Vumela ukubhaliswa kwamadivayisi athenjwayo"</string>
     <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Lawula imodi yokuhlola yemoto"</string>
     <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Lawula imodi yokuhlola yemoto"</string>
+    <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Nika amandla noma khubaza izici zemoto."</string>
+    <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Nika amandla noma khubaza izici zemoto."</string>
+    <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"sebenzisa unogada wemoto"</string>
+    <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Sebenzisa unogada wemoto."</string>
     <string name="trust_device_default_name" msgid="4213625926070261253">"Idivayisi yami"</string>
     <string name="default_guest_name" msgid="2912812799433131476">"Isihambeli"</string>
 </resources>
diff --git a/service/res/values/attrs.xml b/service/res/values/attrs.xml
index e026cae..8db7406 100644
--- a/service/res/values/attrs.xml
+++ b/service/res/values/attrs.xml
@@ -24,7 +24,7 @@
     </declare-styleable>
     <declare-styleable name="volumeGroups_group"/>
     <declare-styleable name="volumeGroups_context">
-        <!-- Align with hardware/interfaces/automotive/audiocontrol/1.0/types.hal:ContextNumber -->
+        <!-- Align with CarAudioContext -->
         <attr name="context">
             <enum name="music" value="1"/>
             <enum name="navigation" value="2"/>
@@ -34,6 +34,10 @@
             <enum name="alarm" value="6"/>
             <enum name="notification" value="7"/>
             <enum name="system_sound" value="8"/>
+            <enum name="emergency" value="9"/>
+            <enum name="safety" value="10"/>
+            <enum name="vehicle_status" value="11"/>
+            <enum name="announcement" value="12"/>
         </attr>
     </declare-styleable>
 
diff --git a/service/res/values/config.xml b/service/res/values/config.xml
index c55c7a6..d40dea9 100644
--- a/service/res/values/config.xml
+++ b/service/res/values/config.xml
@@ -44,6 +44,11 @@
     <!--  Service responsible for displaying information on the car instrument cluster. -->
     <string name="instrumentClusterRendererService" translatable="false">android.car.cluster/.ClusterRenderingService</string>
 
+    <!--  Service responsible for handling the rotary controller input. This service will start
+          on boot or on user switch. Set this string to empty if you don't want to start this
+          service. -->
+    <string name="rotaryService" translatable="false">com.android.car.rotary/com.android.car.rotary.RotaryService</string>
+
     <!--  Whether to enable Activity blocking for safety. When Activity blocking is enabled,
           only whitelisted safe Activities will be allowed while car is not parked. -->
     <bool name="enableActivityBlockingForSafety">true</bool>
@@ -64,7 +69,7 @@
           The current implementations expects the following system packages/activities to be
           whitelisted. For general guidelines to design distraction optimized apps, please refer
           to Android Auto Driver Distraction Guidelines. -->
-    <string name="systemActivityWhitelist" translatable="false">com.android.systemui,com.google.android.permissioncontroller/com.android.packageinstaller.permission.ui.GrantPermissionsActivity,com.android.permissioncontroller/com.android.packageinstaller.permission.ui.GrantPermissionsActivity,android/com.android.internal.app.ResolverActivity,com.android.mtp/com.android.mtp.ReceiverActivity,com.android.server.telecom/com.android.server.telecom.components.UserCallActivity</string>
+    <string name="systemActivityWhitelist" translatable="false">com.android.systemui,com.google.android.permissioncontroller/com.android.permissioncontroller.permission.ui.GrantPermissionsActivity,com.android.permissioncontroller/com.android.permissioncontroller.permission.ui.GrantPermissionsActivity,android/com.android.internal.app.ResolverActivity,com.android.mtp/com.android.mtp.ReceiverActivity,com.android.server.telecom/com.android.server.telecom.components.UserCallActivity</string>
     <!--  Comma separated list of activities that will be blocked during restricted state.
           Format of each entry is either to specify package name to whitelist the whole package
           or use format of "packagename/activity_classname" for tagging each activities.-->
@@ -225,6 +230,63 @@
          There is no default bugreporting app.-->
     <string name="config_car_bugreport_application" translatable="false"></string>
 
+    <!--
+        Lists all occupant (= driver + passenger) zones available in the car.
+        Some examples are:
+        <item>occupantZoneId=0,occupantType=DRIVER,seatRow=1,seatSide=driver</item>
+        <item>occupantZoneId=1,occupantType=FRONT_PASSENGER,seatRow=1,seatSide=oppositeDriver</item>
+        <item>occupantZoneId=2,occupantType=REAR_PASSENGER,seatRow=2,seatSide=left</item>
+        <item>occupantZoneId=3,occupantType=REAR_PASSENGER,seatRow=2,seatSide=right</item>
+
+        occupantZoneId: Unique unsigned integer id to represent each passenger zone. Each zone
+                        should have different id.
+        occupantType: Occupant type for the display. Use * part from
+                       CarOccupantZoneManager.OCCUPANT_TYPE_* like DRIVER, FRONT_PASSENGER,
+                       REAR_PASSENGER and etc.
+        seatRow: Integer telling which row the seat is located. Row 1 is for front seats.
+        seatSide: left/center/right for known side. Or can use driver/center/oppositeDriver to
+                  handle both right-hand driving and left-hand driving in one place.
+                  If car's RHD / LHD is not specified, LHD will be assumed and driver side becomes
+                  left.
+    -->
+    <string-array translatable="false" name="config_occupant_zones">
+        <item>occupantZoneId=0,occupantType=DRIVER,seatRow=1,seatSide=driver</item>
+    </string-array>
+    <!--
+        Specifies configuration of displays in system telling its usage / type and assigned
+        occupant. DEFAULT_DISPLAY, if assigned here, should be always assigned to the DRIVER zone.
+
+        Some examples are:
+        <item>displayPort=0,displayType=MAIN,occupantZoneId=0</item>
+        <item>displayPort=1,displayType=INSTRUMENT_CLUSTER,occupantZoneId=0</item>
+        <item>displayPort=2,displayType=MAIN,occupantZoneId=1</item>
+        <item>displayPort=3,displayType=MAIN,occupantZoneId=2</item>
+        <item>displayPort=4,displayType=MAIN,occupantZoneId=3</item>
+
+        displayPort: Unique port id for the display.
+        displayType: Display type for the display. Use * part from
+                       CarOccupantZoneManager.DISPLAY_TYPE_* like MAIN, INSTRUMENT_CLUSTER and
+                       etc.
+        occupantZoneId: occupantZoneId specified from config_occupant_zones.
+
+    -->
+    <string-array translatable="false" name="config_occupant_display_mapping">
+    </string-array>
+
+    <!--
+        Specifies whether CarLaunchParamControl prefers source. If prefer-source is enabled,
+        CarLaunchParamControl tries to launch Activities without any desiganted display to
+        the display where the source is located.
+
+        This can be configured 3 ways:
+        A. No items - don't prefer source for any components.
+        B. 1 items with "*" - prefer source for all components.
+        C. enumerate items of "packageName/activityName" - prefer source for the specified ones.
+    -->
+    <string-array translatable="false" name="config_sourcePreferredComponents">
+        <item>com.google.android.apps.maps/com.google.android.maps.MapsActivity</item>
+    </string-array>
+
     <!-- Specifies notice UI that will be launched when user starts a car or do user
          switching. It is recommended to use dialog with at least TYPE_APPLICATION_OVERLAY window
          type to show the UI regardless of activity launches. Target package will be auto-granted
@@ -242,11 +304,43 @@
     <integer name="config_mediaSourceChangedAutoplay">2</integer>
     <!-- Configuration to enable media center to autoplay on boot -->
     <integer name="config_mediaBootAutoplay">2</integer>
+    <!-- Setting this flag to true allows for browsing a different source than the
+         one that is currently playing audio. By default, there is only one active
+         source in the car, for both playback and browse. -->
+    <bool name="config_mediaSourceIndependentPlayback">false</bool>
+
 
     <!-- Disable switching the user while the system is resuming from Suspend to RAM.
          This default says to prevent changing the user during Resume. -->
     <bool name="config_disableUserSwitchDuringResume" translatable="false">true</bool>
 
+    <!--
+        Specifies optional features that can be enabled by this image. Note that vhal can disable
+        them depending on product variation.
+        Feature name can be either service name defined in Car.*_SERVICE for Car*Manager or any
+        optional feature defined under @OptionalFeature annotation.
+        Note that '/' is used to have subfeature under main feature like "MAIN_FEATURE/SUB_FEATURE".
+
+        Some examples are:
+        <item>storage_monitoring</item>
+        <item>com.android.car.user.CarUserNoticeService</item>
+        <item>com.example.Feature/SubFeature</item>
+
+        The default list defined below will enable all optional features defined.
+    -->
+    <string-array translatable="false" name="config_allowed_optional_car_features">
+        <item>car_navigation_service</item>
+        <item>com.android.car.user.CarUserNoticeService</item>
+        <item>diagnostic</item>
+        <item>storage_monitoring</item>
+        <item>vehicle_map_service</item>
+    </string-array>
+
+    <!-- Configuration to enable passenger support.
+         If this is set to true and there is a passenger display, a user can login to the passenger
+         display and use it as a normal Android user. -->
+    <bool name="enablePassengerSupport">false</bool>
+
     <!-- Class name of the custom country detector to be used. Override the default value in the
          device specific config file.  -->
     <string name="config_customCountryDetector" translatable="false">com.android.server.location.ComprehensiveCountryDetector</string>
@@ -259,4 +353,11 @@
          be done after waking up from sleep. This only affects if the current user is a guest user.
          -->
     <bool name="config_switchGuestUserBeforeGoingSleep" translate="false">true</bool>
+
+    <!-- Enable profile user assignment per each CarOccupantZone for per display android user
+         assignments. This feature is still experimental. -->
+    <bool name="enableProfileUserAssignmentForMultiDisplay" translatable="false">false</bool>
+
+    <!-- The ComponentName of the media source that will be selected as the default -->
+    <string name="config_defaultMediaSource">com.android.bluetooth/com.android.bluetooth.avrcpcontroller.BluetoothMediaBrowserService</string>
 </resources>
diff --git a/service/res/values/strings.xml b/service/res/values/strings.xml
index 3884450..0b1c265 100644
--- a/service/res/values/strings.xml
+++ b/service/res/values/strings.xml
@@ -28,6 +28,10 @@
     <string name="car_permission_label_energy">access car\u2019s energy information</string>
     <!-- Permission text: can access your car's energy information [CHAR LIMIT=NONE] -->
     <string name="car_permission_desc_energy">Access your car\u2019s energy information.</string>
+    <!-- Permission text: can adjust value of your car's range remaining [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_adjust_range_remaining">adjust car\u2019s range remaining</string>
+    <!-- Permission text: can adjust value of your car's range remaining [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_adjust_range_remaining">Adjust car\u2019s range remaining value.</string>
     <!-- Permission text: apps can control car hvac [CHAR LIMIT=NONE] -->
     <string name="car_permission_label_hvac">access car\u2019s hvac</string>
     <!-- Permission text: apps can control car hvac [CHAR LIMIT=NONE] -->
@@ -102,6 +106,12 @@
     <string name="car_permission_label_car_handle_usb_aoap_device">Communicate with USB device in AOAP mode</string>
     <string name="car_permission_desc_car_handle_usb_aoap_device">Allows an app to communicate with a device in AOAP mode</string>
 
+    <string name="car_permission_label_read_car_occupant_awareness_state">Occupant Awareness System Read Access</string>
+    <string name="car_permission_desc_read_car_occupant_awareness_state">Allows reading status and detection data for Occupant Awareness System</string>
+
+    <string name="car_permission_label_control_car_occupant_awareness_system">Control Occupant Awareness System Graph</string>
+    <string name="car_permission_desc_control_car_occupant_awareness_system">Allows controlling the start and stopping of the Occupant Awareness System detection graph</string>
+
     <!-- Permission text: apps can handle input events [CHAR LIMIT=NONE] -->
     <string name="car_permission_label_bind_input_service">Car Input Service</string>
     <!-- Permission text: apps can handle input events [CHAR LIMIT=NONE] -->
@@ -172,6 +182,11 @@
     <!-- Permission text: apps can access car's fuel door and ev charge port [CHAR LIMIT=NONE] -->
     <string name="car_permission_desc_car_energy_ports">Access car\u2019s fuel door and charge port.</string>
 
+    <!-- Permission text: apps can control car's fuel door and ev charge port [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_control_car_energy_ports">control car\u2019s fuel door and charge port</string>
+    <!-- Permission text: apps can control car's fuel door and ev charge port [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_control_car_energy_ports">Control car\u2019s fuel door and charge port.</string>
+
     <!-- Permission text: apps can access car's VIN information [CHAR LIMIT=NONE] -->
     <string name="car_permission_label_car_identification">read car\u2019s identification</string>
     <!-- Permission text: apps can access car's VIN information [CHAR LIMIT=NONE] -->
@@ -202,6 +217,11 @@
     <!-- Permission text: apps read car's basic information [CHAR LIMIT=NONE] -->
     <string name="car_permission_desc_car_info">Access car\u2019s basic information.</string>
 
+    <!-- Permission text: apps read car's vendor permissions information [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_vendor_permission_info">access car\u2019s vendor permission information</string>
+    <!-- Permission text: apps read car's vendor permissions information [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_vendor_permission_info">Access car\u2019s vendor permission information.</string>
+
     <!-- Permission text: apps access car's exterior lights state [CHAR LIMIT=NONE] -->
     <string name="car_permission_label_car_exterior_lights">read car\u2019s exterior lights state</string>
     <!-- Permission text: apps access car's exterior lights state [CHAR LIMIT=NONE] -->
@@ -265,13 +285,199 @@
     <!-- Permission text: Control car's test mode [CHAR LIMIT=NONE] -->
     <string name="car_permission_desc_car_test_service">Control car\u2019s test mode</string>
 
+    <!-- Permission text: apps control vendor properties related with window [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_set_car_vendor_category_window" translatable="false">control vendor specific window properties</string>
+    <!-- Permission text: apps control vendor properties related with window [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_set_car_vendor_category_window" translatable="false">Control vendor specific window properties.</string>
+
+    <!-- Permission text: apps access vendor properties related with window [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_get_car_vendor_category_window" translatable="false">access vendor specific window properties</string>
+    <!-- Permission text: apps access vendor properties related with window [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_get_car_vendor_category_window" translatable="false">Access vendor specific window properties.</string>
+
+    <!-- Permission text: apps control vendor properties related with door [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_set_car_vendor_category_door" translatable="false">control vendor specific door properties</string>
+    <!-- Permission text: apps control vendor properties related with door [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_set_car_vendor_category_door" translatable="false">Control vendor specific door properties.</string>
+
+    <!-- Permission text: apps access vendor properties related with door [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_get_car_vendor_category_door" translatable="false">access vendor specific door properties</string>
+    <!-- Permission text: apps access vendor properties related with door [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_get_car_vendor_category_door" translatable="false">Access vendor specific door properties.</string>
+
+    <!-- Permission text: apps control vendor properties related with seat [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_set_car_vendor_category_seat" translatable="false">control vendor specific seat properties</string>
+    <!-- Permission text: apps control vendor properties related with seat [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_set_car_vendor_category_seat" translatable="false">Control vendor specific seat properties.</string>
+
+    <!-- Permission text: apps access vendor properties related with seat [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_get_car_vendor_category_seat" translatable="false">access vendor specific seat properties</string>
+    <!-- Permission text: apps access vendor properties related with seat [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_get_car_vendor_category_seat" translatable="false">Access vendor specific seat properties.</string>
+
+    <!-- Permission text: apps control vendor properties related with mirror [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_set_car_vendor_category_mirror" translatable="false">control vendor specific mirror properties</string>
+    <!-- Permission text: apps control vendor properties related with mirror [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_set_car_vendor_category_mirror" translatable="false">Control vendor specific mirror properties.</string>
+
+    <!-- Permission text: apps access vendor properties related with mirror [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_get_car_vendor_category_mirror" translatable="false">access vendor specific mirror properties</string>
+    <!-- Permission text: apps access vendor properties related with mirror [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_get_car_vendor_category_mirror" translatable="false">Access vendor specific mirror properties.</string>
+
+    <!-- Permission text: apps control vendor properties related with info [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_set_car_vendor_category_info" translatable="false">control vendor specific information properties</string>
+    <!-- Permission text: apps control vendor properties related with info [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_set_car_vendor_category_info" translatable="false">Control vendor specific information properties.</string>
+
+    <!-- Permission text: apps access vendor properties related with info [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_get_car_vendor_category_info" translatable="false">access vendor specific information properties</string>
+    <!-- Permission text: apps access vendor properties related with info [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_get_car_vendor_category_info" translatable="false">Access vendor specific information properties.</string>
+
+    <!-- Permission text: apps control vendor properties related with engine [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_set_car_vendor_category_engine" translatable="false">control vendor specific engine properties</string>
+    <!-- Permission text: apps control vendor properties related with engine [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_set_car_vendor_category_engine" translatable="false">Control vendor specific engine properties.</string>
+
+    <!-- Permission text: apps access vendor properties related with engine [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_get_car_vendor_category_engine" translatable="false">access vendor specific engine properties</string>
+    <!-- Permission text: apps access vendor properties related with engine [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_get_car_vendor_category_engine" translatable="false">Access vendor specific engine properties.</string>
+
+    <!-- Permission text: apps control vendor properties related with hvac [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_set_car_vendor_category_hvac" translatable="false">control vendor specific hvac properties</string>
+    <!-- Permission text: apps control vendor properties related with hvac [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_set_car_vendor_category_hvac" translatable="false">Control vendor specific hvac properties.</string>
+
+    <!-- Permission text: apps access vendor properties related with hvac [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_get_car_vendor_category_hvac" translatable="false">access vendor specific hvac properties</string>
+    <!-- Permission text: apps access vendor properties related with hvac [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_get_car_vendor_category_hvac" translatable="false">Access vendor specific hvac properties.</string>
+
+    <!-- Permission text: apps control vendor properties related with light [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_set_car_vendor_category_light" translatable="false">control vendor specific light properties</string>
+    <!-- Permission text: apps control vendor properties related with light [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_set_car_vendor_category_light" translatable="false">Control vendor specific light properties.</string>
+
+    <!-- Permission text: apps access vendor properties related with light [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_get_car_vendor_category_light" translatable="false">access vendor specific light properties</string>
+    <!-- Permission text: apps access vendor properties related with light [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_get_car_vendor_category_light" translatable="false">Access vendor specific light properties.</string>
+
+    <!-- Permission text: apps access properties in category 1 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_get_car_vendor_category_1" translatable="false">access vendor specific properties in category 1</string>
+    <!-- Permission text: apps access vendor properties in category 1 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_get_car_vendor_category_1" translatable="false">Access vendor specific properties in category 1.</string>
+
+    <!-- Permission text: apps access vendor properties in category 2 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_get_car_vendor_category_2" translatable="false">access vendor specific properties in category 2</string>
+    <!-- Permission text: apps access vendor properties in category 2 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_get_car_vendor_category_2" translatable="false">Access vendor specific properties in category 2.</string>
+
+    <!-- Permission text: apps access properties in category 3 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_get_car_vendor_category_3" translatable="false">access vendor specific properties in category 3</string>
+    <!-- Permission text: apps access  properties in category 3 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_get_car_vendor_category_3" translatable="false">Access vendor specific properties in category 3.</string>
+
+    <!-- Permission text: apps access vendor properties in category 4 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_get_car_vendor_category_4" translatable="false">access vendor specific properties in category 4</string>
+    <!-- Permission text: apps access vendor properties in category 4 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_get_car_vendor_category_4" translatable="false">Access vendor specific properties in category 4.</string>
+
+    <!-- Permission text: apps access vendor properties in category 5 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_get_car_vendor_category_5" translatable="false">access vendor specific properties in category 5</string>
+    <!-- Permission text: apps access vendor properties in category 5 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_get_car_vendor_category_5" translatable="false">Access vendor specific properties in category 5.</string>
+
+    <!-- Permission text: apps access vendor properties in category 6 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_get_car_vendor_category_6" translatable="false">access vendor specific properties in category 6</string>
+    <!-- Permission text: apps access and control vendor properties in category 6 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_get_car_vendor_category_6" translatable="false">Access vendor specific properties in category 6.</string>
+
+    <!-- Permission text: apps access vendor properties in category 7 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_get_car_vendor_category_7" translatable="false">access vendor specific properties in category 7</string>
+    <!-- Permission text: apps access vendor properties in category 7 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_get_car_vendor_category_7" translatable="false">Access vendor specific properties in category 7.</string>
+
+    <!-- Permission text: apps access vendor properties in category 8 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_get_car_vendor_category_8" translatable="false">access vendor specific properties in category 8</string>
+    <!-- Permission text: apps access vendor properties in category 8 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_get_car_vendor_category_8" translatable="false">Access vendor specific properties in category 8.</string>
+
+    <!-- Permission text: apps access vendor properties in category 9 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_get_car_vendor_category_9" translatable="false">access vendor specific properties in category 9</string>
+    <!-- Permission text: apps access vendor properties in category 9 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_get_car_vendor_category_9" translatable="false">Access vendor specific properties in category 9.</string>
+
+    <!-- Permission text: apps access vendor properties in category 10 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_get_car_vendor_category_10" translatable="false">access vendor specific properties in category 10</string>
+    <!-- Permission text: apps access vendor properties in category 10 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_get_car_vendor_category_10" translatable="false">Access vendor specific properties in category 10.</string>
+
+    <!-- Permission text: apps control vendor properties in category 1 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_set_car_vendor_category_1" translatable="false">control vendor specific properties in category 1</string>
+    <!-- Permission text: apps control vendor properties in category 1 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_set_car_vendor_category_1" translatable="false">Control vendor specific properties in category 1.</string>
+
+    <!-- Permission text: apps control vendor properties in category 2 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_set_car_vendor_category_2" translatable="false">control vendor specific properties in category 2</string>
+    <!-- Permission text: apps control vendor properties in category 2 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_set_car_vendor_category_2" translatable="false">Control vendor specific properties in category 2.</string>
+
+    <!-- Permission text: apps control vendor properties in category 3 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_set_car_vendor_category_3" translatable="false">control vendor specific properties in category 3</string>
+    <!-- Permission text: apps control vendor properties in category 3 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_set_car_vendor_category_3" translatable="false">Control vendor specific properties in category 3.</string>
+
+    <!-- Permission text: apps control vendor properties in category 4 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_set_car_vendor_category_4" translatable="false">control vendor specific properties in category 4</string>
+    <!-- Permission text: apps control vendor properties in category 4 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_set_car_vendor_category_4" translatable="false">Control vendor specific properties in category 4.</string>
+
+    <!-- Permission text: apps control vendor properties in category 5 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_set_car_vendor_category_5" translatable="false">control vendor specific properties in category 5</string>
+    <!-- Permission text: apps control vendor properties in category 5 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_set_car_vendor_category_5" translatable="false">Control vendor specific properties in category 5.</string>
+
+    <!-- Permission text: apps control vendor properties in category 6 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_set_car_vendor_category_6" translatable="false">control vendor specific properties in category 6</string>
+    <!-- Permission text: apps control vendor properties in category 6 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_set_car_vendor_category_6" translatable="false">Control vendor specific properties in category 6.</string>
+
+    <!-- Permission text: apps control vendor properties in category 7 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_set_car_vendor_category_7" translatable="false">control vendor specific properties in category 7</string>
+    <!-- Permission text: apps control vendor properties in category 7 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_set_car_vendor_category_7" translatable="false">Control vendor specific properties in category 7.</string>
+
+    <!-- Permission text: apps control vendor properties in category 8 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_set_car_vendor_category_8" translatable="false">control vendor specific properties in category 8</string>
+    <!-- Permission text: apps control vendor properties in category 8 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_set_car_vendor_category_8" translatable="false">Control vendor specific properties in category 8.</string>
+
+    <!-- Permission text: apps control vendor properties in category 9 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_set_car_vendor_category_9" translatable="false">control vendor specific properties in category 9</string>
+    <!-- Permission text: apps control vendor properties in category 9 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_set_car_vendor_category_9" translatable="false">Control vendor specific properties in category 9.</string>
+
+    <!-- Permission text: apps control vendor properties in category 10 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_set_car_vendor_category_10" translatable="false">control vendor specific properties in category 10</string>
+    <!-- Permission text: apps control vendor properties in category 10 [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_set_car_vendor_category_10" translatable="false">Control vendor specific properties in category 10.</string>
+
+    <!-- Permission text: enable or disable car's features [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_control_car_features">Enable or disable car\u2019s features</string>
+    <!-- Permission text: enable or disable car's features [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_control_car_features">Enable or disable car\u2019s features.</string>
+
+    <!-- Permission text: apps use car watchdog [CHAR LIMIT=NONE] -->
+    <string name="car_permission_label_use_car_watchdog">use car watchdog</string>
+    <!-- Permission text: apps use car watchdog [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_use_car_watchdog">Use car watchdog.</string>
+
     <!-- The default name of device enrolled as trust device [CHAR LIMIT=NONE] -->
     <string name="trust_device_default_name">My Device</string>
 
-    <!-- The ComponentName of the media source that will be selected as the default [CHAR LIMIT=NONE] -->
-    <string name="default_media_source" translatable="false">com.android.bluetooth/com.android.bluetooth.avrcpcontroller.BluetoothMediaBrowserService</string>
-
     <!-- Default name for new guest users [CHAR LIMIT=20] -->
     <string name="default_guest_name">Guest</string>
-
 </resources>
diff --git a/service/res/xml/car_ux_restrictions_map.xml b/service/res/xml/car_ux_restrictions_map.xml
index 813796b..771aa19 100644
--- a/service/res/xml/car_ux_restrictions_map.xml
+++ b/service/res/xml/car_ux_restrictions_map.xml
@@ -8,7 +8,7 @@
    <restrictionParameters> tag.
 
 Note:
-   1. The tags and attributes are declared in packages/services/Car/service/res/attrs.xml.
+   1. The tags and attributes are declared in packages/services/Car/service/res/values/attrs.xml.
    2. The driving states defined there should align with driving states (@CarDrivingState) defined in
    packages/services/Car/car-lib/src/android/car/drivingstate/CarDrivingStateEvent.java
    3. Similarly the UX restrictions should align with
@@ -48,13 +48,14 @@
         4. If the above conditions are not met, mapping behavior is undefined. -->
         <!-- This is restrictions for moving and speed [0,5m/s) -->
         <DrivingState car:state="moving" car:minSpeed="0" car:maxSpeed="5.0">
-            <Restrictions car:requiresDistractionOptimization="true" car:uxr="fully_restricted"/>
+            <Restrictions car:requiresDistractionOptimization="true" car:uxr="no_dialpad|no_filtering|limit_string_length|no_keyboard|no_video|limit_content|no_setup|no_text_message"/>
         </DrivingState>
 
         <!-- Restrictions for speed >=5 -->
         <DrivingState car:state="moving" car:minSpeed="5.0">
-            <Restrictions car:requiresDistractionOptimization="true" car:uxr="fully_restricted"/>
+            <Restrictions car:requiresDistractionOptimization="true" car:uxr="no_dialpad|no_filtering|limit_string_length|no_keyboard|no_video|limit_content|no_setup|no_text_message"/>
         </DrivingState>
+
     </RestrictionMapping>
 
     <!-- Configure restriction parameters here-->
diff --git a/service/res/xml/car_volume_groups.xml b/service/res/xml/car_volume_groups.xml
index c900329..2fdd61f 100644
--- a/service/res/xml/car_volume_groups.xml
+++ b/service/res/xml/car_volume_groups.xml
@@ -17,17 +17,14 @@
 <!--
   This configuration is replaced by car_audio_configuration.xml
 
-  Notes on backward compatibility
-  - A new audioUseUnifiedConfiguration flag is added, and the default value
-  is false
-  - If OEM does not explicitly set audioUseUnifiedConfiguration to be true,
-  car_volume_groups.xml will be used, CarAudioService also queries
-  IAudioControl HAL (getBusForContext)
-  - Otherwise, CarAudioService loads the new car_audio_configuration.xml
+  Notes on backward compatibility:
+  If audioUseDynamicRouting is true and no car_audio_configuration.xml file
+  is found in either /vendor/etc or /system/etc, then car_volume_groups.xml will
+  be used and IAudioControl.getBusForContext will be queried
 
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-  Defines the all available volume groups for volume control in a car.
+  Defines all of the available volume groups for volume control in a car.
   One can overlay this configuration to customize the groups.
 
   This configuration will be populated by CarAudioService and
@@ -40,7 +37,7 @@
     - All gain controllers (set on each bus) in one group have same step value
 
   It is fine that there are buses that do not appear in any group, those buses
-  may be reserved for other usages.
+  may be reserved for other purposes.
 
   Important note: when overlaying this configuration,
   make sure the resources are in the same package as CarAudioService.
diff --git a/service/src/com/android/car/AppFocusService.java b/service/src/com/android/car/AppFocusService.java
index 9d46dad..cc1a530 100644
--- a/service/src/com/android/car/AppFocusService.java
+++ b/service/src/com/android/car/AppFocusService.java
@@ -26,14 +26,19 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
+import android.util.ArraySet;
 import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.PrintWriter;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.Set;
-import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * App focus service ensures only one instance of application type is active at a time.
@@ -44,18 +49,34 @@
     private static final boolean DBG_EVENT = false;
 
     private final SystemActivityMonitoringService mSystemActivityMonitoringService;
-    private final ClientHolder mAllChangeClients;
-    private final OwnershipClientHolder mAllOwnershipClients;
+
+    private final Object mLock = new Object();
+
+    @VisibleForTesting
+    @GuardedBy("mLock")
+    final ClientHolder mAllChangeClients;
+
+    @VisibleForTesting
+    @GuardedBy("mLock")
+    final OwnershipClientHolder mAllOwnershipClients;
+
     /** K: appType, V: client owning it */
-    private final HashMap<Integer, OwnershipClientInfo> mFocusOwners = new HashMap<>();
-    private final Set<Integer> mActiveAppTypes = new HashSet<>();
-    private final CopyOnWriteArrayList<FocusOwnershipCallback> mFocusOwnershipCallbacks =
-            new CopyOnWriteArrayList<>();
+    @GuardedBy("mLock")
+    private final SparseArray<OwnershipClientInfo> mFocusOwners = new SparseArray<>();
+
+    @GuardedBy("mLock")
+    private final Set<Integer> mActiveAppTypes = new ArraySet<>();
+
+    @GuardedBy("mLock")
+    private final List<FocusOwnershipCallback> mFocusOwnershipCallbacks = new ArrayList<>();
+
     private final BinderInterfaceContainer.BinderEventHandler<IAppFocusListener>
             mAllBinderEventHandler = bInterface -> { /* nothing to do.*/ };
 
-    private DispatchHandler mDispatchHandler;
-    private HandlerThread mHandlerThread;
+    private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
+            getClass().getSimpleName());
+    private final DispatchHandler mDispatchHandler = new DispatchHandler(mHandlerThread.getLooper(),
+            this);
 
     public AppFocusService(Context context,
             SystemActivityMonitoringService systemActivityMonitoringService) {
@@ -66,7 +87,7 @@
 
     @Override
     public void registerFocusListener(IAppFocusListener listener, int appType) {
-        synchronized (this) {
+        synchronized (mLock) {
             ClientInfo info = (ClientInfo) mAllChangeClients.getBinderInterface(listener);
             if (info == null) {
                 info = new ClientInfo(mAllChangeClients, listener, Binder.getCallingUid(),
@@ -80,7 +101,7 @@
 
     @Override
     public void unregisterFocusListener(IAppFocusListener listener, int appType) {
-        synchronized (this) {
+        synchronized (mLock) {
             ClientInfo info = (ClientInfo) mAllChangeClients.getBinderInterface(listener);
             if (info == null) {
                 return;
@@ -94,26 +115,26 @@
 
     @Override
     public int[] getActiveAppTypes() {
-        synchronized (this) {
-            return toIntArray(mActiveAppTypes);
+        synchronized (mLock) {
+            return mActiveAppTypes.stream().mapToInt(Integer::intValue).toArray();
         }
     }
 
     @Override
     public boolean isOwningFocus(IAppFocusOwnershipCallback callback, int appType) {
-        synchronized (this) {
-            OwnershipClientInfo info =
-                    (OwnershipClientInfo) mAllOwnershipClients.getBinderInterface(callback);
-            if (info == null) {
-                return false;
-            }
-            return info.getOwnedAppTypes().contains(appType);
+        OwnershipClientInfo info;
+        synchronized (mLock) {
+            info = (OwnershipClientInfo) mAllOwnershipClients.getBinderInterface(callback);
         }
+        if (info == null) {
+            return false;
+        }
+        return info.getOwnedAppTypes().contains(appType);
     }
 
     @Override
     public int requestAppFocus(IAppFocusOwnershipCallback callback, int appType) {
-        synchronized (this) {
+        synchronized (mLock) {
             OwnershipClientInfo info =
                     (OwnershipClientInfo) mAllOwnershipClients.getBinderInterface(callback);
             if (info == null) {
@@ -126,13 +147,13 @@
                 OwnershipClientInfo ownerInfo = mFocusOwners.get(appType);
                 if (ownerInfo != null && ownerInfo != info) {
                     if (mSystemActivityMonitoringService.isInForeground(
-                                ownerInfo.getPid(), ownerInfo.getUid()) &&
-                        !mSystemActivityMonitoringService.isInForeground(
-                                info.getPid(), info.getUid())) {
+                            ownerInfo.getPid(), ownerInfo.getUid())
+                            && !mSystemActivityMonitoringService.isInForeground(
+                            info.getPid(), info.getUid())) {
                         Log.w(CarLog.TAG_APP_FOCUS, "Focus request failed for non-foreground app("
-                              + "pid=" + info.getPid() + ", uid=" + info.getUid() + ")."
-                              + "Foreground app (pid=" + ownerInfo.getPid() + ", uid="
-                              + ownerInfo.getUid() + ") owns it.");
+                                + "pid=" + info.getPid() + ", uid=" + info.getUid() + ")."
+                                + "Foreground app (pid=" + ownerInfo.getPid() + ", uid="
+                                + ownerInfo.getUid() + ") owns it.");
                         return CarAppFocusManager.APP_FOCUS_REQUEST_FAILED;
                     }
                     ownerInfo.removeOwnedAppType(appType);
@@ -140,7 +161,7 @@
                             ownerInfo.binderInterface, appType);
                     if (DBG) {
                         Log.i(CarLog.TAG_APP_FOCUS, "losing app type "
-                                + appType + "," + ownerInfo.toString());
+                                + appType + "," + ownerInfo);
                     }
                 }
                 updateFocusOwner(appType, info);
@@ -148,20 +169,20 @@
             info.addOwnedAppType(appType);
             mDispatchHandler.requestAppFocusOwnershipGrantDispatch(
                     info.binderInterface, appType);
-            if (mActiveAppTypes.add(appType)) {
-                if (DBG) {
-                    Log.i(CarLog.TAG_APP_FOCUS, "adding active app type " + appType + ","
-                            + info.toString());
-                }
-                for (BinderInterfaceContainer.BinderInterface<IAppFocusListener> client :
-                        mAllChangeClients.getInterfaces()) {
-                    ClientInfo clientInfo = (ClientInfo) client;
-                    // dispatch events only when there is change after filter and the listener
-                    // is not coming from the current caller.
-                    if (clientInfo.getAppTypes().contains(appType)) {
-                        mDispatchHandler.requestAppFocusChangeDispatch(clientInfo.binderInterface,
-                                appType, true);
-                    }
+            mActiveAppTypes.add(appType);
+            if (DBG) {
+                Log.i(CarLog.TAG_APP_FOCUS, "updating active app type " + appType + ","
+                        + info);
+            }
+            // Always dispatch.
+            for (BinderInterfaceContainer.BinderInterface<IAppFocusListener> client :
+                    mAllChangeClients.getInterfaces()) {
+                ClientInfo clientInfo = (ClientInfo) client;
+                // dispatch events only when there is change after filter and the listener
+                // is not coming from the current caller.
+                if (clientInfo.getAppTypes().contains(appType)) {
+                    mDispatchHandler.requestAppFocusChangeDispatch(clientInfo.binderInterface,
+                            appType, true);
                 }
             }
         }
@@ -170,7 +191,7 @@
 
     @Override
     public void abandonAppFocus(IAppFocusOwnershipCallback callback, int appType) {
-        synchronized (this) {
+        synchronized (mLock) {
             OwnershipClientInfo info =
                     (OwnershipClientInfo) mAllOwnershipClients.getBinderInterface(callback);
             if (info == null) {
@@ -186,12 +207,12 @@
                 // ignore as listener doesn't own focus.
                 return;
             }
-            if (mFocusOwners.remove(appType) != null) {
+            if (mFocusOwners.contains(appType)) {
+                mFocusOwners.remove(appType);
                 mActiveAppTypes.remove(appType);
                 info.removeOwnedAppType(appType);
                 if (DBG) {
-                    Log.i(CarLog.TAG_APP_FOCUS, "abandoning focus " + appType
-                            + "," + info.toString());
+                    Log.i(CarLog.TAG_APP_FOCUS, "abandoning focus " + appType + "," + info);
                 }
                 for (FocusOwnershipCallback ownershipCallback : mFocusOwnershipCallbacks) {
                     ownershipCallback.onFocusAbandoned(appType, info.mUid, info.mPid);
@@ -210,23 +231,18 @@
 
     @Override
     public void init() {
-        synchronized (this) {
-            mHandlerThread = new HandlerThread(AppFocusService.class.getSimpleName());
-            mHandlerThread.start();
-            mDispatchHandler = new DispatchHandler(mHandlerThread.getLooper());
-        }
+        // nothing to do
+    }
+
+    @VisibleForTesting
+    public Looper getLooper() {
+        return mHandlerThread.getLooper();
+
     }
 
     @Override
     public void release() {
-        synchronized (this) {
-            mHandlerThread.quitSafely();
-            try {
-                mHandlerThread.join(1000);
-            } catch (InterruptedException e) {
-                Log.e(CarLog.TAG_APP_FOCUS, "Timeout while waiting for handler thread to join.");
-            }
-            mDispatchHandler = null;
+        synchronized (mLock) {
             mAllChangeClients.clear();
             mAllOwnershipClients.clear();
             mFocusOwners.clear();
@@ -238,20 +254,22 @@
     public void onBinderDeath(
             BinderInterfaceContainer.BinderInterface<IAppFocusOwnershipCallback> bInterface) {
         OwnershipClientInfo info = (OwnershipClientInfo) bInterface;
-        for (Integer appType : info.getOwnedAppTypes()) {
-            abandonAppFocus(bInterface.binderInterface, appType);
+        synchronized (mLock) {
+            for (Integer appType : info.getOwnedAppTypes()) {
+                abandonAppFocus(bInterface.binderInterface, appType);
+            }
         }
     }
 
     @Override
     public void dump(PrintWriter writer) {
         writer.println("**AppFocusService**");
-        synchronized (this) {
+        synchronized (mLock) {
             writer.println("mActiveAppTypes:" + mActiveAppTypes);
             for (BinderInterfaceContainer.BinderInterface<IAppFocusOwnershipCallback> client :
                     mAllOwnershipClients.getInterfaces()) {
                 OwnershipClientInfo clientInfo = (OwnershipClientInfo) client;
-                writer.println(clientInfo.toString());
+                writer.println(clientInfo);
             }
         }
     }
@@ -260,8 +278,8 @@
      * Returns true if process with given uid and pid owns provided focus.
      */
     public boolean isFocusOwner(int uid, int pid, int appType) {
-        synchronized (this) {
-            if (mFocusOwners.containsKey(appType)) {
+        synchronized (mLock) {
+            if (mFocusOwners.contains(appType)) {
                 OwnershipClientInfo clientInfo = mFocusOwners.get(appType);
                 return clientInfo.getUid() == uid && clientInfo.getPid() == pid;
             }
@@ -284,16 +302,15 @@
      * {@link FocusOwnershipCallback#onFocusAcquired} call immediately in the same thread.
      */
     public void registerContextOwnerChangedCallback(FocusOwnershipCallback callback) {
-        mFocusOwnershipCallbacks.add(callback);
-
-        HashSet<Map.Entry<Integer, OwnershipClientInfo>> owners;
-        synchronized (this) {
-            owners = new HashSet<>(mFocusOwners.entrySet());
+        SparseArray<OwnershipClientInfo> owners;
+        synchronized (mLock) {
+            mFocusOwnershipCallbacks.add(callback);
+            owners = mFocusOwners.clone();
         }
-
-        for (Map.Entry<Integer, OwnershipClientInfo> entry : owners) {
-            OwnershipClientInfo clientInfo = entry.getValue();
-            callback.onFocusAcquired(entry.getKey(), clientInfo.getUid(), clientInfo.getPid());
+        for (int idx = 0; idx < owners.size(); idx++) {
+            int key = owners.keyAt(idx);
+            OwnershipClientInfo clientInfo = owners.valueAt(idx);
+            callback.onFocusAcquired(key, clientInfo.getUid(), clientInfo.getPid());
         }
     }
 
@@ -301,16 +318,19 @@
      * Unregisters provided callback.
      */
     public void unregisterContextOwnerChangedCallback(FocusOwnershipCallback callback) {
-        mFocusOwnershipCallbacks.remove(callback);
+        synchronized (mLock) {
+            mFocusOwnershipCallbacks.remove(callback);
+        }
     }
 
     private void updateFocusOwner(int appType, OwnershipClientInfo owner) {
         CarServiceUtils.runOnMain(() -> {
-            synchronized (this) {
+            List<FocusOwnershipCallback> focusOwnershipCallbacks;
+            synchronized (mLock) {
                 mFocusOwners.put(appType, owner);
+                focusOwnershipCallbacks = new ArrayList<>(mFocusOwnershipCallbacks);
             }
-
-            for (FocusOwnershipCallback callback : mFocusOwnershipCallbacks) {
+            for (FocusOwnershipCallback callback : focusOwnershipCallbacks) {
                 callback.onFocusAcquired(appType, owner.getUid(), owner.getPid());
             }
         });
@@ -337,24 +357,28 @@
         }
     }
 
-    private static class ClientHolder extends BinderInterfaceContainer<IAppFocusListener> {
+    @VisibleForTesting
+    static class ClientHolder extends BinderInterfaceContainer<IAppFocusListener> {
         private ClientHolder(BinderEventHandler<IAppFocusListener> holder) {
             super(holder);
         }
     }
 
-    private static class OwnershipClientHolder extends
+    @VisibleForTesting
+    static class OwnershipClientHolder extends
             BinderInterfaceContainer<IAppFocusOwnershipCallback> {
         private OwnershipClientHolder(AppFocusService service) {
             super(service);
         }
     }
 
-    private static class ClientInfo extends
+    private class ClientInfo extends
             BinderInterfaceContainer.BinderInterface<IAppFocusListener> {
         private final int mUid;
         private final int mPid;
-        private final Set<Integer> mAppTypes = new HashSet<>();
+
+        @GuardedBy("AppFocusService.mLock")
+        private final Set<Integer> mAppTypes = new ArraySet<>();
 
         private ClientInfo(ClientHolder holder, IAppFocusListener binder, int uid, int pid,
                 int appType) {
@@ -364,32 +388,40 @@
             this.mAppTypes.add(appType);
         }
 
-        private synchronized Set<Integer> getAppTypes() {
-            return mAppTypes;
+        private Set<Integer> getAppTypes() {
+            synchronized (mLock) {
+                return Collections.unmodifiableSet(mAppTypes);
+            }
         }
 
-        private synchronized boolean addAppType(Integer appType) {
-            return mAppTypes.add(appType);
+        private boolean addAppType(Integer appType) {
+            synchronized (mLock) {
+                return mAppTypes.add(appType);
+            }
         }
 
-        private synchronized boolean removeAppType(Integer appType) {
-            return mAppTypes.remove(appType);
+        private boolean removeAppType(Integer appType) {
+            synchronized (mLock) {
+                return mAppTypes.remove(appType);
+            }
         }
 
         @Override
         public String toString() {
-            synchronized (this) {
+            synchronized (mLock) {
                 return "ClientInfo{mUid=" + mUid + ",mPid=" + mPid
                         + ",appTypes=" + mAppTypes + "}";
             }
         }
     }
 
-    private static class OwnershipClientInfo extends
+    private class OwnershipClientInfo extends
             BinderInterfaceContainer.BinderInterface<IAppFocusOwnershipCallback> {
         private final int mUid;
         private final int mPid;
-        private final Set<Integer> mOwnedAppTypes = new HashSet<>();
+
+        @GuardedBy("AppFocusService.mLock")
+        private final Set<Integer> mOwnedAppTypes = new ArraySet<>();
 
         private OwnershipClientInfo(OwnershipClientHolder holder, IAppFocusOwnershipCallback binder,
                 int uid, int pid) {
@@ -398,25 +430,31 @@
             this.mPid = pid;
         }
 
-        private synchronized Set<Integer> getOwnedAppTypes() {
+        private Set<Integer> getOwnedAppTypes() {
             if (DBG_EVENT) {
                 Log.i(CarLog.TAG_APP_FOCUS, "getOwnedAppTypes " + mOwnedAppTypes);
             }
-            return mOwnedAppTypes;
+            synchronized (mLock) {
+                return Collections.unmodifiableSet(mOwnedAppTypes);
+            }
         }
 
-        private synchronized boolean addOwnedAppType(Integer appType) {
+        private boolean addOwnedAppType(Integer appType) {
             if (DBG_EVENT) {
                 Log.i(CarLog.TAG_APP_FOCUS, "addOwnedAppType " + appType);
             }
-            return mOwnedAppTypes.add(appType);
+            synchronized (mLock) {
+                return mOwnedAppTypes.add(appType);
+            }
         }
 
-        private synchronized boolean removeOwnedAppType(Integer appType) {
+        private boolean removeOwnedAppType(Integer appType) {
             if (DBG_EVENT) {
                 Log.i(CarLog.TAG_APP_FOCUS, "removeOwnedAppType " + appType);
             }
-            return mOwnedAppTypes.remove(appType);
+            synchronized (mLock) {
+                return mOwnedAppTypes.remove(appType);
+            }
         }
 
         int getUid() {
@@ -429,20 +467,25 @@
 
         @Override
         public String toString() {
-            synchronized (this) {
+            synchronized (mLock) {
                 return "ClientInfo{mUid=" + mUid + ",mPid=" + mPid
                         + ",owned=" + mOwnedAppTypes + "}";
             }
         }
     }
 
-    private class DispatchHandler extends Handler {
+    private static final class DispatchHandler extends Handler {
+        private static final String TAG = DispatchHandler.class.getSimpleName();
+
         private static final int MSG_DISPATCH_OWNERSHIP_LOSS = 0;
         private static final int MSG_DISPATCH_OWNERSHIP_GRANT = 1;
         private static final int MSG_DISPATCH_FOCUS_CHANGE = 2;
 
-        private DispatchHandler(Looper looper) {
+        private final WeakReference<AppFocusService> mService;
+
+        private DispatchHandler(Looper looper, AppFocusService service) {
             super(looper);
+            mService = new WeakReference<AppFocusService>(service);
         }
 
         private void requestAppFocusOwnershipLossDispatch(IAppFocusOwnershipCallback callback,
@@ -466,28 +509,27 @@
 
         @Override
         public void handleMessage(Message msg) {
+            AppFocusService service = mService.get();
+            if (service == null) {
+                Log.i(TAG, "handleMessage null service");
+                return;
+            }
             switch (msg.what) {
                 case MSG_DISPATCH_OWNERSHIP_LOSS:
-                    dispatchAppFocusOwnershipLoss((IAppFocusOwnershipCallback) msg.obj, msg.arg1);
+                    service.dispatchAppFocusOwnershipLoss((IAppFocusOwnershipCallback) msg.obj,
+                            msg.arg1);
                     break;
                 case MSG_DISPATCH_OWNERSHIP_GRANT:
-                    dispatchAppFocusOwnershipGrant((IAppFocusOwnershipCallback) msg.obj, msg.arg1);
+                    service.dispatchAppFocusOwnershipGrant((IAppFocusOwnershipCallback) msg.obj,
+                            msg.arg1);
                     break;
                 case MSG_DISPATCH_FOCUS_CHANGE:
-                    dispatchAppFocusChange((IAppFocusListener) msg.obj, msg.arg1, msg.arg2 == 1);
+                    service.dispatchAppFocusChange((IAppFocusListener) msg.obj, msg.arg1,
+                            msg.arg2 == 1);
                     break;
                 default:
                     Log.e(CarLog.TAG_APP_FOCUS, "Can't dispatch message: " + msg);
             }
         }
     }
-
-    private static int[] toIntArray(Set<Integer> intSet) {
-        int[] intArr = new int[intSet.size()];
-        int index = 0;
-        for (Integer value : intSet) {
-            intArr[index++] = value;
-        }
-        return intArr;
-    }
 }
diff --git a/service/src/com/android/car/BinderInterfaceContainer.java b/service/src/com/android/car/BinderInterfaceContainer.java
index 5d57b16..32f7eb9 100644
--- a/service/src/com/android/car/BinderInterfaceContainer.java
+++ b/service/src/com/android/car/BinderInterfaceContainer.java
@@ -21,16 +21,27 @@
 import android.os.IInterface;
 import android.os.RemoteException;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.Map;
 
 /**
  * Helper class to hold client's binder interface.
+ *
+ * @param <T> type of the value that is wrapped by this class
  */
 public class BinderInterfaceContainer<T extends IInterface> {
 
-    public static class BinderInterface<T extends IInterface>
-            implements IBinder.DeathRecipient {
+    /**
+     * Wrapper class for objects that want to be notified whenever they are unliked from
+     * the container ({@link BinderInterfaceContainer}).
+     *
+     * @param <T> type of the value that is wrapped by this class
+     */
+    public static class BinderInterface<T extends IInterface> implements IBinder.DeathRecipient {
         public final T binderInterface;
         private final BinderInterfaceContainer<T> mContainer;
 
@@ -46,13 +57,25 @@
         }
     }
 
+    /**
+     * Interface to be implemented by object that want to be notified whenever a binder is unliked
+     * (dies).
+     */
     public interface BinderEventHandler<T extends IInterface> {
         void onBinderDeath(BinderInterface<T> bInterface);
     }
 
-    private final BinderEventHandler<T> mEventHandler;
-    private final HashMap<IBinder, BinderInterface<T>> mBinders = new HashMap<>();
+    private final Object mLock = new Object();
 
+    private final BinderEventHandler<T> mEventHandler;
+
+    @GuardedBy("mLock")
+    private final Map<IBinder, BinderInterface<T>> mBinders = new HashMap<>();
+
+    /**
+     * Constructs a new <code>BinderInterfaceContainer</code> passing an event handler to be used to
+     * notify listeners when a registered binder dies (unlinked).
+     */
     public BinderInterfaceContainer(@Nullable BinderEventHandler<T> eventHandler) {
         mEventHandler = eventHandler;
     }
@@ -61,9 +84,14 @@
         mEventHandler = null;
     }
 
+    /**
+     * Add the instance of {@link IInterface} representing the binder interface to this container.
+     *
+     * Internally, this object will be wrapped in an {@link BinderInterface} when added.
+     */
     public void addBinder(T binderInterface) {
         IBinder binder = binderInterface.asBinder();
-        synchronized (this) {
+        synchronized (mLock) {
             BinderInterface<T> bInterface = mBinders.get(binder);
             if (bInterface != null) {
                 return;
@@ -78,9 +106,13 @@
         }
     }
 
+    /**
+     * Removes the {@link BinderInterface} object associated with the passed parameter (if there is
+     * any).
+     */
     public void removeBinder(T binderInterface) {
         IBinder binder = binderInterface.asBinder();
-        synchronized(this) {
+        synchronized (mLock) {
             BinderInterface<T> bInterface = mBinders.get(binder);
             if (bInterface == null) {
                 return;
@@ -90,16 +122,22 @@
         }
     }
 
+    /**
+     * Returns the {@link BinderInterface} object associated with the passed parameter.
+     */
     public BinderInterface<T> getBinderInterface(T binderInterface) {
         IBinder binder = binderInterface.asBinder();
-        synchronized (this) {
+        synchronized (mLock) {
             return mBinders.get(binder);
         }
     }
 
+    /**
+     * Adds a new {@link BinderInterface} in this container.
+     */
     public void addBinderInterface(BinderInterface<T> bInterface) {
         IBinder binder = bInterface.binderInterface.asBinder();
-        synchronized (this) {
+        synchronized (mLock) {
             try {
                 binder.linkToDeath(bInterface, 0);
             } catch (RemoteException e) {
@@ -109,29 +147,43 @@
         }
     }
 
+    /**
+     * Returns an unmodified collection containing all registered {@link BinderInterface} objects
+     * with this container.
+     */
     public Collection<BinderInterface<T>> getInterfaces() {
-        synchronized (this) {
-            return mBinders.values();
+        synchronized (mLock) {
+            return Collections.unmodifiableCollection(mBinders.values());
         }
     }
 
-    public synchronized int size() {
-        return mBinders.size();
+    /**
+     * Returns the number of registered {@link BinderInterface} objects in this container.
+     */
+    public int size() {
+        synchronized (mLock) {
+            return mBinders.size();
+        }
     }
 
-    public synchronized void clear() {
-        Collection<BinderInterface<T>> interfaces = getInterfaces();
-        for (BinderInterface<T> bInterface : interfaces) {
-            IBinder binder = bInterface.binderInterface.asBinder();
-            binder.unlinkToDeath(bInterface, 0);
+    /**
+     * Clears all registered {@link BinderInterface} objects.
+     */
+    public void clear() {
+        synchronized (mLock) {
+            Collection<BinderInterface<T>> interfaces = getInterfaces();
+            for (BinderInterface<T> bInterface : interfaces) {
+                IBinder binder = bInterface.binderInterface.asBinder();
+                binder.unlinkToDeath(bInterface, 0);
+            }
         }
         mBinders.clear();
     }
 
     private void handleBinderDeath(BinderInterface<T> bInterface) {
-        removeBinder(bInterface.binderInterface);
         if (mEventHandler != null) {
             mEventHandler.onBinderDeath(bInterface);
         }
+        removeBinder(bInterface.binderInterface);
     }
 }
diff --git a/service/src/com/android/car/BluetoothProfileDeviceManager.java b/service/src/com/android/car/BluetoothProfileDeviceManager.java
index e73d9ea..2fd17d0 100644
--- a/service/src/com/android/car/BluetoothProfileDeviceManager.java
+++ b/service/src/com/android/car/BluetoothProfileDeviceManager.java
@@ -51,6 +51,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
@@ -65,6 +66,7 @@
     private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
     private final Context mContext;
     private final int mUserId;
+    private Set<String> mBondingDevices = new HashSet<>();
 
     private static final String SETTINGS_DELIMITER = ",";
 
@@ -91,12 +93,12 @@
         sProfileActions.put(BluetoothProfile.A2DP_SINK,
                 new BluetoothProfileInfo(BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED,
                         KEY_BLUETOOTH_A2DP_SINK_DEVICES, new ParcelUuid[] {
-                            BluetoothUuid.AudioSource
+                            BluetoothUuid.A2DP_SOURCE
                         }, new int[] {}));
         sProfileActions.put(BluetoothProfile.HEADSET_CLIENT,
                 new BluetoothProfileInfo(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED,
                         KEY_BLUETOOTH_HFP_CLIENT_DEVICES, new ParcelUuid[] {
-                            BluetoothUuid.Handsfree_AG,
+                            BluetoothUuid.HFP_AG,
                             BluetoothUuid.HSP_AG
                         }, new int[] {BluetoothProfile.MAP_CLIENT, BluetoothProfile.PBAP_CLIENT}));
         sProfileActions.put(BluetoothProfile.MAP_CLIENT,
@@ -217,16 +219,20 @@
         logd("Bond state has changed [device: " + device + ", state: "
                 + Utils.getBondStateName(state) + "]");
         if (state == BluetoothDevice.BOND_NONE) {
+            mBondingDevices.remove(device.getAddress());
             // Note: We have seen cases of unbonding events being sent without actually
             // unbonding the device.
             removeDevice(device);
+        } else if (state == BluetoothDevice.BOND_BONDING) {
+            mBondingDevices.add(device.getAddress());
         } else if (state == BluetoothDevice.BOND_BONDED) {
             addBondedDeviceIfSupported(device);
+            mBondingDevices.remove(device.getAddress());
         }
     }
 
     /**
-     * Handles an incoming device UUID set update event.
+     * Handles an incoming device UUID set update event for bonding devices.
      *
      * On BluetoothDevice.ACTION_UUID:
      *    If the UUID is one this profile cares about, set the profile priority for the device that
@@ -238,6 +244,7 @@
      */
     private void handleDeviceUuidEvent(BluetoothDevice device, Parcelable[] uuids) {
         logd("UUIDs found, device: " + device);
+        if (!mBondingDevices.remove(device.getAddress())) return;
         if (uuids != null) {
             ParcelUuid[] uuidsToSend = new ParcelUuid[uuids.length];
             for (int i = 0; i < uuidsToSend.length; i++) {
diff --git a/service/src/com/android/car/CarBluetoothService.java b/service/src/com/android/car/CarBluetoothService.java
index 92f79ed..b302b7f 100644
--- a/service/src/com/android/car/CarBluetoothService.java
+++ b/service/src/com/android/car/CarBluetoothService.java
@@ -20,11 +20,12 @@
 import android.bluetooth.BluetoothProfile;
 import android.car.ICarBluetooth;
 import android.car.ICarBluetoothUserService;
-import android.car.ICarUserService;
+import android.car.IPerUserCarService;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.Log;
 import android.util.SparseArray;
 
@@ -88,37 +89,41 @@
     @GuardedBy("mPerUserLock")
     private int mUserId;
     @GuardedBy("mPerUserLock")
-    private ICarUserService mCarUserService;
+    private IPerUserCarService mPerUserCarService;
     @GuardedBy("mPerUserLock")
     private ICarBluetoothUserService mCarBluetoothUserService;
     private final PerUserCarServiceHelper mUserServiceHelper;
     private final PerUserCarServiceHelper.ServiceCallback mUserServiceCallback =
             new PerUserCarServiceHelper.ServiceCallback() {
         @Override
-        public void onServiceConnected(ICarUserService carUserService) {
+        public void onServiceConnected(IPerUserCarService perUserCarService) {
             logd("Connected to PerUserCarService");
             synchronized (mPerUserLock) {
                 // Explicitly clear out existing per-user objects since we can't rely on the
                 // onServiceDisconnected and onPreUnbind calls to always be called before this
-                destroyUser();
+                destroyUserLocked();
 
-                mCarUserService = carUserService;
+                mPerUserCarService = perUserCarService;
 
                 // Create new objects with our new set of profile proxies
-                initializeUser();
+                initializeUserLocked();
             }
         }
 
         @Override
         public void onPreUnbind() {
-            logd("Before Unbinding from PerCarUserService");
-            destroyUser();
+            logd("Before Unbinding from PerUserCarService");
+            synchronized (mPerUserLock) {
+                destroyUserLocked();
+            }
         }
 
         @Override
         public void onServiceDisconnected() {
             logd("Disconnected from PerUserCarService");
-            destroyUser();
+            synchronized (mPerUserLock) {
+                destroyUserLocked();
+            }
         }
     };
 
@@ -130,7 +135,7 @@
      *                            to in order to receive user switch events
      */
     public CarBluetoothService(Context context, PerUserCarServiceHelper userSwitchService) {
-        mUserId = -1;
+        mUserId = UserHandle.USER_NULL;
         mContext = context;
         mUserServiceHelper = userSwitchService;
         mUseDefaultPolicy = mContext.getResources().getBoolean(
@@ -157,7 +162,9 @@
     public void release() {
         logd("release()");
         mUserServiceHelper.unregisterServiceCallback(mUserServiceCallback);
-        destroyUser();
+        synchronized (mPerUserLock) {
+            destroyUserLocked();
+        }
     }
 
     /**
@@ -174,37 +181,33 @@
      *
      * Only call this following a known user switch once we've connected to the user service helper.
      */
-    private void initializeUser() {
+    private void initializeUserLocked() {
         logd("Initializing new user");
-        synchronized (mPerUserLock) {
-            mUserId = ActivityManager.getCurrentUser();
-            createBluetoothUserService();
-            createBluetoothProfileDeviceManagers();
-            createBluetoothProfileInhibitManager();
+        mUserId = ActivityManager.getCurrentUser();
+        createBluetoothUserServiceLocked();
+        createBluetoothProfileDeviceManagersLocked();
+        createBluetoothProfileInhibitManagerLocked();
 
-            // Determine if we need to begin the default policy
-            mBluetoothDeviceConnectionPolicy = null;
-            if (mUseDefaultPolicy) {
-                createBluetoothDeviceConnectionPolicy();
-            }
-            logd("Switched to user " + mUserId);
+        // Determine if we need to begin the default policy
+        mBluetoothDeviceConnectionPolicy = null;
+        if (mUseDefaultPolicy) {
+            createBluetoothDeviceConnectionPolicyLocked();
         }
+        logd("Switched to user " + mUserId);
     }
 
     /**
      * Destroy the current user context, defined by the set of profile proxies, profile device
      * managers, inhibit manager and the policy.
      */
-    private void destroyUser() {
+    private void destroyUserLocked() {
         logd("Destroying user " + mUserId);
-        synchronized (mPerUserLock) {
-            destroyBluetoothDeviceConnectionPolicy();
-            destroyBluetoothProfileInhibitManager();
-            destroyBluetoothProfileDeviceManagers();
-            destroyBluetoothUserService();
-            mCarUserService = null;
-            mUserId = -1;
-        }
+        destroyBluetoothDeviceConnectionPolicyLocked();
+        destroyBluetoothProfileInhibitManagerLocked();
+        destroyBluetoothProfileDeviceManagersLocked();
+        destroyBluetoothUserServiceLocked();
+        mPerUserCarService = null;
+        mUserId = UserHandle.USER_NULL;
     }
 
     /**
@@ -213,19 +216,19 @@
      * Also sets up the connection proxy objects required to communicate with the Bluetooth
      * Profile Services.
      */
-    private void createBluetoothUserService() {
-        synchronized (mPerUserLock) {
-            if (mCarUserService != null) {
-                try {
-                    mCarBluetoothUserService = mCarUserService.getBluetoothUserService();
-                    mCarBluetoothUserService.setupBluetoothConnectionProxies();
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Remote Service Exception on ServiceConnection Callback: "
-                            + e.getMessage());
-                } catch (java.lang.NullPointerException e) {
-                    Log.e(TAG, "Initialization Failed: " + e.getMessage());
-                }
+    private void createBluetoothUserServiceLocked() {
+        if (mPerUserCarService != null) {
+            try {
+                mCarBluetoothUserService = mPerUserCarService.getBluetoothUserService();
+                mCarBluetoothUserService.setupBluetoothConnectionProxies();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Remote Service Exception on ServiceConnection Callback: "
+                        + e.getMessage());
+            } catch (java.lang.NullPointerException e) {
+                Log.e(TAG, "Initialization Failed: " + e.getMessage());
             }
+        } else {
+            logd("PerUserCarService not connected. Cannot get bluetooth user proxy objects");
         }
     }
 
@@ -233,130 +236,116 @@
      * Close out the Per User Car Bluetooth profile proxy connections and destroys the Car Bluetooth
      * User Service object.
      */
-    private void destroyBluetoothUserService() {
-        synchronized (mPerUserLock) {
-            if (mCarBluetoothUserService == null) return;
-            try {
-                mCarBluetoothUserService.closeBluetoothConnectionProxies();
-            } catch (RemoteException e) {
-                Log.e(TAG, "Remote Service Exception on ServiceConnection Callback: "
-                        + e.getMessage());
-            }
-            mCarBluetoothUserService = null;
+    private void destroyBluetoothUserServiceLocked() {
+        if (mCarBluetoothUserService == null) return;
+        try {
+            mCarBluetoothUserService.closeBluetoothConnectionProxies();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Remote Service Exception on ServiceConnection Callback: "
+                    + e.getMessage());
         }
+        mCarBluetoothUserService = null;
     }
 
     /**
      * Clears out Profile Device Managers and re-creates them for the current user.
      */
-    private void createBluetoothProfileDeviceManagers() {
-        synchronized (mPerUserLock) {
-            if (mUserId == -1) {
-                logd("No foreground user, cannot create profile device managers");
-                return;
-            }
-            for (int profileId : sManagedProfiles) {
-                BluetoothProfileDeviceManager deviceManager = mProfileDeviceManagers.get(profileId);
-                if (deviceManager != null) {
-                    deviceManager.stop();
-                    mProfileDeviceManagers.remove(profileId);
-                    logd("Existing device manager removed for profile "
-                            + Utils.getProfileName(profileId));
-                }
-
-                deviceManager = BluetoothProfileDeviceManager.create(mContext, mUserId,
-                        mCarBluetoothUserService, profileId);
-                if (deviceManager == null) {
-                    logd("Failed to create profile device manager for "
-                            + Utils.getProfileName(profileId));
-                    continue;
-                }
-                mProfileDeviceManagers.put(profileId, deviceManager);
-                logd("Created profile device manager for " + Utils.getProfileName(profileId));
+    private void createBluetoothProfileDeviceManagersLocked() {
+        if (mUserId == UserHandle.USER_NULL) {
+            logd("No foreground user, cannot create profile device managers");
+            return;
+        }
+        for (int profileId : sManagedProfiles) {
+            BluetoothProfileDeviceManager deviceManager = mProfileDeviceManagers.get(profileId);
+            if (deviceManager != null) {
+                deviceManager.stop();
+                mProfileDeviceManagers.remove(profileId);
+                logd("Existing device manager removed for profile "
+                        + Utils.getProfileName(profileId));
             }
 
-            for (int i = 0; i < mProfileDeviceManagers.size(); i++) {
-                int key = mProfileDeviceManagers.keyAt(i);
-                BluetoothProfileDeviceManager deviceManager =
-                        (BluetoothProfileDeviceManager) mProfileDeviceManagers.get(key);
-                deviceManager.start();
+            deviceManager = BluetoothProfileDeviceManager.create(mContext, mUserId,
+                    mCarBluetoothUserService, profileId);
+            if (deviceManager == null) {
+                logd("Failed to create profile device manager for "
+                        + Utils.getProfileName(profileId));
+                continue;
             }
+            mProfileDeviceManagers.put(profileId, deviceManager);
+            logd("Created profile device manager for " + Utils.getProfileName(profileId));
+        }
+
+        for (int i = 0; i < mProfileDeviceManagers.size(); i++) {
+            int key = mProfileDeviceManagers.keyAt(i);
+            BluetoothProfileDeviceManager deviceManager =
+                    (BluetoothProfileDeviceManager) mProfileDeviceManagers.get(key);
+            deviceManager.start();
         }
     }
 
     /**
      * Stops and clears the entire set of Profile Device Managers.
      */
-    private void destroyBluetoothProfileDeviceManagers() {
-        synchronized (mPerUserLock) {
-            for (int i = 0; i < mProfileDeviceManagers.size(); i++) {
-                int key = mProfileDeviceManagers.keyAt(i);
-                BluetoothProfileDeviceManager deviceManager =
-                        (BluetoothProfileDeviceManager) mProfileDeviceManagers.get(key);
-                deviceManager.stop();
-            }
-            mProfileDeviceManagers.clear();
+    private void destroyBluetoothProfileDeviceManagersLocked() {
+        for (int i = 0; i < mProfileDeviceManagers.size(); i++) {
+            int key = mProfileDeviceManagers.keyAt(i);
+            BluetoothProfileDeviceManager deviceManager =
+                    (BluetoothProfileDeviceManager) mProfileDeviceManagers.get(key);
+            deviceManager.stop();
         }
+        mProfileDeviceManagers.clear();
     }
 
     /**
      * Creates an instance of a BluetoothProfileInhibitManager under the current user
      */
-    private void createBluetoothProfileInhibitManager() {
+    private void createBluetoothProfileInhibitManagerLocked() {
         logd("Creating inhibit manager");
-        synchronized (mPerUserLock) {
-            if (mUserId == -1) {
-                logd("No foreground user, cannot create profile inhibit manager");
-                return;
-            }
-            mInhibitManager = new BluetoothProfileInhibitManager(mContext, mUserId,
-                    mCarBluetoothUserService);
-            mInhibitManager.start();
+        if (mUserId == UserHandle.USER_NULL) {
+            logd("No foreground user, cannot create profile inhibit manager");
+            return;
         }
+        mInhibitManager = new BluetoothProfileInhibitManager(mContext, mUserId,
+                mCarBluetoothUserService);
+        mInhibitManager.start();
     }
 
     /**
      * Destroys the current instance of a BluetoothProfileInhibitManager, if one exists
      */
-    private void destroyBluetoothProfileInhibitManager() {
+    private void destroyBluetoothProfileInhibitManagerLocked() {
         logd("Destroying inhibit manager");
-        synchronized (mPerUserLock) {
-            if (mInhibitManager == null) return;
-            mInhibitManager.stop();
-            mInhibitManager = null;
-        }
+        if (mInhibitManager == null) return;
+        mInhibitManager.stop();
+        mInhibitManager = null;
     }
 
     /**
      * Creates an instance of a BluetoothDeviceConnectionPolicy under the current user
      */
-    private void createBluetoothDeviceConnectionPolicy() {
+    private void createBluetoothDeviceConnectionPolicyLocked() {
         logd("Creating device connection policy");
-        synchronized (mPerUserLock) {
-            if (mUserId == -1) {
-                logd("No foreground user, cannot create device connection policy");
-                return;
-            }
-            mBluetoothDeviceConnectionPolicy = BluetoothDeviceConnectionPolicy.create(mContext,
-                    mUserId, this);
-            if (mBluetoothDeviceConnectionPolicy == null) {
-                logd("Failed to create default Bluetooth device connection policy.");
-                return;
-            }
-            mBluetoothDeviceConnectionPolicy.init();
+        if (mUserId == UserHandle.USER_NULL) {
+            logd("No foreground user, cannot create device connection policy");
+            return;
         }
+        mBluetoothDeviceConnectionPolicy = BluetoothDeviceConnectionPolicy.create(mContext,
+                mUserId, this);
+        if (mBluetoothDeviceConnectionPolicy == null) {
+            logd("Failed to create default Bluetooth device connection policy.");
+            return;
+        }
+        mBluetoothDeviceConnectionPolicy.init();
     }
 
     /**
      * Destroys the current instance of a BluetoothDeviceConnectionPolicy, if one exists
      */
-    private void destroyBluetoothDeviceConnectionPolicy() {
+    private void destroyBluetoothDeviceConnectionPolicyLocked() {
         logd("Destroying device connection policy");
-        synchronized (mPerUserLock) {
-            if (mBluetoothDeviceConnectionPolicy != null) {
-                mBluetoothDeviceConnectionPolicy.release();
-                mBluetoothDeviceConnectionPolicy = null;
-            }
+        if (mBluetoothDeviceConnectionPolicy != null) {
+            mBluetoothDeviceConnectionPolicy.release();
+            mBluetoothDeviceConnectionPolicy = null;
         }
     }
 
@@ -375,6 +364,7 @@
      * Initiate automatated connecting of devices based on the prioritized device lists for each
      * profile.
      */
+    @Override
     public void connectDevices() {
         enforceBluetoothAdminPermission();
         logd("Connect devices for each profile");
diff --git a/service/src/com/android/car/CarBluetoothUserService.java b/service/src/com/android/car/CarBluetoothUserService.java
index 028e66f..566a872 100644
--- a/service/src/com/android/car/CarBluetoothUserService.java
+++ b/service/src/com/android/car/CarBluetoothUserService.java
@@ -27,10 +27,9 @@
 import android.util.Log;
 import android.util.SparseBooleanArray;
 
-import com.android.internal.util.Preconditions;
-
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
@@ -69,7 +68,7 @@
     /**
      * Create a CarBluetoothUserService instance.
      *
-     * @param serice - A reference to a PerUserCarService, so we can use its context to receive
+     * @param service - A reference to a PerUserCarService, so we can use its context to receive
      *                 updates as a particular user.
      */
     public CarBluetoothUserService(PerUserCarService service) {
@@ -82,7 +81,7 @@
         mBluetoothProxyLock = new ReentrantLock();
         mConditionAllProxiesConnected = mBluetoothProxyLock.newCondition();
         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
-        Preconditions.checkNotNull(mBluetoothAdapter, "Bluetooth adapter cannot be null");
+        Objects.requireNonNull(mBluetoothAdapter, "Bluetooth adapter cannot be null");
     }
 
     /**
diff --git a/service/src/com/android/car/CarBugreportManagerService.java b/service/src/com/android/car/CarBugreportManagerService.java
index b63822f..39f4461 100644
--- a/service/src/com/android/car/CarBugreportManagerService.java
+++ b/service/src/com/android/car/CarBugreportManagerService.java
@@ -30,6 +30,7 @@
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.ParcelFileDescriptor;
@@ -50,6 +51,7 @@
 import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.PrintWriter;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Bugreport service for cars.
@@ -69,7 +71,11 @@
     private static final String OK_PREFIX = "OK:";
     private static final String FAIL_PREFIX = "FAIL:";
 
+    /**
+     * The services are defined in {@code packages/services/Car/car-bugreportd/car-bugreportd.rc}.
+     */
     private static final String BUGREPORTD_SERVICE = "car-bugreportd";
+    private static final String DUMPSTATEZ_SERVICE = "car-dumpstatez";
 
     // The socket definitions must match the actual socket names defined in car_bugreportd service
     // definition.
@@ -83,9 +89,10 @@
     private final Context mContext;
     private final Object mLock = new Object();
 
-    private HandlerThread mHandlerThread;
-    private Handler mHandler;
-    private boolean mIsServiceRunning;
+    private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
+            getClass().getSimpleName());
+    private final Handler mHandler = new Handler(mHandlerThread.getLooper());
+    private final AtomicBoolean mIsServiceRunning = new AtomicBoolean(false);
 
     /**
      * Create a CarBugreportManagerService instance.
@@ -98,79 +105,116 @@
 
     @Override
     public void init() {
-        mHandlerThread = new HandlerThread(TAG);
-        mHandlerThread.start();
-        mHandler = new Handler(mHandlerThread.getLooper());
+        // nothing to do
     }
 
     @Override
     public void release() {
-        mHandlerThread.quitSafely();
+        // nothing to do
     }
 
     @Override
     @RequiresPermission(android.Manifest.permission.DUMP)
     public void requestBugreport(ParcelFileDescriptor output, ParcelFileDescriptor extraOutput,
             ICarBugreportCallback callback) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.DUMP, "requestBugreport");
+        ensureTheCallerIsSignedWithPlatformKeys();
+        ensureTheCallerIsDesignatedBugReportApp();
+        synchronized (mLock) {
+            if (mIsServiceRunning.getAndSet(true)) {
+                Slog.w(TAG, "Bugreport Service already running");
+                reportError(callback, CarBugreportManagerCallback.CAR_BUGREPORT_IN_PROGRESS);
+                return;
+            }
+            requestBugReportLocked(output, extraOutput, callback);
+        }
+    }
 
-        // Check the caller has proper permission
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
-                "requestZippedBugreport");
-        // Check the caller is signed with platform keys
+    @Override
+    @RequiresPermission(android.Manifest.permission.DUMP)
+    public void cancelBugreport() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.DUMP, "cancelBugreport");
+        ensureTheCallerIsSignedWithPlatformKeys();
+        ensureTheCallerIsDesignatedBugReportApp();
+        synchronized (mLock) {
+            if (!mIsServiceRunning.getAndSet(false)) {
+                Slog.i(TAG, "Failed to cancel. Service is not running.");
+                return;
+            }
+            Slog.i(TAG, "Cancelling the running bugreport");
+            mHandler.removeCallbacksAndMessages(/* token= */ null);
+            // This tells init to cancel the services. Note that this is achieved through
+            // setting a system property which is not thread-safe. So the lock here offers
+            // thread-safety only among callers of the API.
+            try {
+                SystemProperties.set("ctl.stop", BUGREPORTD_SERVICE);
+            } catch (RuntimeException e) {
+                Slog.e(TAG, "Failed to stop " + BUGREPORTD_SERVICE, e);
+            }
+            try {
+                // Stop DUMPSTATEZ_SERVICE service too, because stopping BUGREPORTD_SERVICE doesn't
+                // guarantee stopping DUMPSTATEZ_SERVICE.
+                SystemProperties.set("ctl.stop", DUMPSTATEZ_SERVICE);
+            } catch (RuntimeException e) {
+                Slog.e(TAG, "Failed to stop " + DUMPSTATEZ_SERVICE, e);
+            }
+        }
+    }
+
+    private void ensureTheCallerIsSignedWithPlatformKeys() {
         PackageManager pm = mContext.getPackageManager();
         int callingUid = Binder.getCallingUid();
         if (pm.checkSignatures(Process.myUid(), callingUid) != PackageManager.SIGNATURE_MATCH) {
             throw new SecurityException("Caller " + pm.getNameForUid(callingUid)
                             + " does not have the right signature");
         }
-        // Check if the caller is the designated bugreport app
+    }
+
+    /** Checks only on user builds. */
+    private void ensureTheCallerIsDesignatedBugReportApp() {
+        if (Build.IS_DEBUGGABLE) {
+            // Per https://source.android.com/setup/develop/new-device, user builds are debuggable=0
+            return;
+        }
         String defaultAppPkgName = mContext.getString(R.string.config_car_bugreport_application);
+        int callingUid = Binder.getCallingUid();
+        PackageManager pm = mContext.getPackageManager();
         String[] packageNamesForCallerUid = pm.getPackagesForUid(callingUid);
-        boolean found = false;
         if (packageNamesForCallerUid != null) {
             for (String packageName : packageNamesForCallerUid) {
                 if (defaultAppPkgName.equals(packageName)) {
-                    found = true;
-                    break;
+                    return;
                 }
             }
         }
-        if (!found) {
-            throw new SecurityException("Caller " +  pm.getNameForUid(callingUid)
-                    + " is not a designated bugreport app");
-        }
-
-        synchronized (mLock) {
-            requestBugReportLocked(output, extraOutput, callback);
-        }
+        throw new SecurityException("Caller " +  pm.getNameForUid(callingUid)
+                + " is not a designated bugreport app");
     }
 
     @GuardedBy("mLock")
     private void requestBugReportLocked(ParcelFileDescriptor output,
             ParcelFileDescriptor extraOutput, ICarBugreportCallback callback) {
-        if (mIsServiceRunning) {
-            Slog.w(TAG, "Bugreport Service already running");
-            reportError(callback, CarBugreportManagerCallback.CAR_BUGREPORT_IN_PROGRESS);
-            return;
-        }
-        mIsServiceRunning = true;
-        mHandler.post(() -> startBugreportd(output, extraOutput, callback));
-    }
-
-    private void startBugreportd(ParcelFileDescriptor output, ParcelFileDescriptor extraOutput,
-            ICarBugreportCallback callback) {
         Slog.i(TAG, "Starting " + BUGREPORTD_SERVICE);
         try {
+            // This tells init to start the service. Note that this is achieved through
+            // setting a system property which is not thread-safe. So the lock here offers
+            // thread-safety only among callers of the API.
             SystemProperties.set("ctl.start", BUGREPORTD_SERVICE);
         } catch (RuntimeException e) {
+            mIsServiceRunning.set(false);
             Slog.e(TAG, "Failed to start " + BUGREPORTD_SERVICE, e);
             reportError(callback, CAR_BUGREPORT_DUMPSTATE_FAILED);
             return;
         }
-        processBugreportSockets(output, extraOutput, callback);
-        synchronized (mLock) {
-            mIsServiceRunning = false;
-        }
+        mHandler.post(() -> {
+            try {
+                processBugreportSockets(output, extraOutput, callback);
+            } finally {
+                mIsServiceRunning.set(false);
+            }
+        });
     }
 
     private void handleProgress(String line, ICarBugreportCallback callback) {
@@ -232,11 +276,10 @@
             reportError(callback, CAR_BUGREPORT_DUMPSTATE_CONNECTION_FAILED);
             return;
         }
-
         try (BufferedReader reader =
                 new BufferedReader(new InputStreamReader(localSocket.getInputStream()))) {
             String line;
-            while ((line = reader.readLine()) != null) {
+            while (mIsServiceRunning.get() && (line = reader.readLine()) != null) {
                 if (line.startsWith(PROGRESS_PREFIX)) {
                     handleProgress(line, callback);
                 } else if (line.startsWith(FAIL_PREFIX)) {
@@ -285,7 +328,7 @@
         try {
             callback.onError(errorCode);
         } catch (RemoteException e) {
-            Slog.e(TAG, "onError() failed: " + e.getMessage());
+            Slog.e(TAG, "onError() failed", e);
         }
     }
 
@@ -310,7 +353,17 @@
             // Therefore we are generous in setting the timeout. Most cases should not even
             // come close to the timeouts, but since bugreports are taken when there is a
             // system issue, it is hard to guess.
-            SystemClock.sleep(SOCKET_CONNECTION_RETRY_DELAY_IN_MS);
+            // The following lines waits for SOCKET_CONNECTION_RETRY_DELAY_IN_MS or until
+            // mIsServiceRunning becomes false.
+            for (int i = 0; i < SOCKET_CONNECTION_RETRY_DELAY_IN_MS / 50; i++) {
+                if (!mIsServiceRunning.get()) {
+                    Slog.i(TAG, "Failed to connect to socket " + socketName
+                            + ". The service is prematurely cancelled.");
+                    return null;
+                }
+                SystemClock.sleep(50);  // Millis.
+            }
+
             try {
                 socket.connect(new LocalSocketAddress(socketName,
                         LocalSocketAddress.Namespace.RESERVED));
@@ -321,7 +374,7 @@
                             + " after " + retryCount + " retries", e);
                     return null;
                 }
-                Log.i(TAG, "Failed to connect to " + socketName + ". Will try again "
+                Log.i(TAG, "Failed to connect to " + socketName + ". Will try again. "
                         + e.getMessage());
             }
         }
diff --git a/service/src/com/android/car/CarDrivingStateService.java b/service/src/com/android/car/CarDrivingStateService.java
index 66a2a7c..0cc3b06 100644
--- a/service/src/com/android/car/CarDrivingStateService.java
+++ b/service/src/com/android/car/CarDrivingStateService.java
@@ -32,17 +32,17 @@
 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
 import android.os.Handler;
 import android.os.HandlerThread;
-import android.os.IBinder;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.PrintWriter;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * A service that infers the current driving state of the vehicle.  It computes the driving state
@@ -55,58 +55,85 @@
     private static final int PROPERTY_UPDATE_RATE = 5; // Update rate in Hz
     private static final int NOT_RECEIVED = -1;
     private final Context mContext;
-    private CarPropertyService mPropertyService;
+    private final CarPropertyService mPropertyService;
     // List of clients listening to driving state events.
-    private final List<DrivingStateClient> mDrivingStateClients = new CopyOnWriteArrayList<>();
+    private final RemoteCallbackList<ICarDrivingStateChangeListener> mDrivingStateClients =
+            new RemoteCallbackList<>();
     // Array of properties that the service needs to listen to from CarPropertyService for deriving
     // the driving state.
     private static final int[] REQUIRED_PROPERTIES = {
             VehicleProperty.PERF_VEHICLE_SPEED,
             VehicleProperty.GEAR_SELECTION,
             VehicleProperty.PARKING_BRAKE_ON};
-    private final HandlerThread mClientDispatchThread;
-    private final Handler mClientDispatchHandler;
-    private CarDrivingStateEvent mCurrentDrivingState;
+    private final HandlerThread mClientDispatchThread = CarServiceUtils.getHandlerThread(
+            getClass().getSimpleName());
+    private final Handler mClientDispatchHandler = new Handler(mClientDispatchThread.getLooper());
+    private final Object mLock = new Object();
+
     // For dumpsys logging
+    @GuardedBy("mLock")
     private final LinkedList<Utils.TransitionLog> mTransitionLogs = new LinkedList<>();
+
+    @GuardedBy("mLock")
     private int mLastGear;
+
+    @GuardedBy("mLock")
     private long mLastGearTimestamp = NOT_RECEIVED;
+
+    @GuardedBy("mLock")
     private float mLastSpeed;
+
+    @GuardedBy("mLock")
     private long mLastSpeedTimestamp = NOT_RECEIVED;
+
+    @GuardedBy("mLock")
     private boolean mLastParkingBrakeState;
+
+    @GuardedBy("mLock")
     private long mLastParkingBrakeTimestamp = NOT_RECEIVED;
+
+    @GuardedBy("mLock")
     private List<Integer> mSupportedGears;
 
+    @GuardedBy("mLock")
+    private CarDrivingStateEvent mCurrentDrivingState;
+
     public CarDrivingStateService(Context context, CarPropertyService propertyService) {
         mContext = context;
         mPropertyService = propertyService;
         mCurrentDrivingState = createDrivingStateEvent(CarDrivingStateEvent.DRIVING_STATE_UNKNOWN);
-        mClientDispatchThread = new HandlerThread("ClientDispatchThread");
-        mClientDispatchThread.start();
-        mClientDispatchHandler = new Handler(mClientDispatchThread.getLooper());
     }
 
     @Override
-    public synchronized void init() {
+    public void init() {
         if (!checkPropertySupport()) {
             Log.e(TAG, "init failure.  Driving state will always be fully restrictive");
             return;
         }
         subscribeToProperties();
-        mCurrentDrivingState = createDrivingStateEvent(inferDrivingStateLocked());
-        addTransitionLog(TAG + " Boot", CarDrivingStateEvent.DRIVING_STATE_UNKNOWN,
-                mCurrentDrivingState.eventValue, mCurrentDrivingState.timeStamp);
+
+        synchronized (mLock) {
+            mCurrentDrivingState = createDrivingStateEvent(inferDrivingStateLocked());
+            addTransitionLogLocked(TAG + " Boot", CarDrivingStateEvent.DRIVING_STATE_UNKNOWN,
+                    mCurrentDrivingState.eventValue, mCurrentDrivingState.timeStamp);
+        }
     }
 
     @Override
-    public synchronized void release() {
+    public void release() {
         for (int property : REQUIRED_PROPERTIES) {
             mPropertyService.unregisterListener(property, mICarPropertyEventListener);
         }
-        for (DrivingStateClient client : mDrivingStateClients) {
-            client.listenerBinder.unlinkToDeath(client, 0);
+        while (mDrivingStateClients.getRegisteredCallbackCount() > 0) {
+            for (int i = mDrivingStateClients.getRegisteredCallbackCount() - 1; i >= 0; i--) {
+                ICarDrivingStateChangeListener client =
+                        mDrivingStateClients.getRegisteredCallbackItem(i);
+                if (client == null) {
+                    continue;
+                }
+                mDrivingStateClients.unregister(client);
+            }
         }
-        mDrivingStateClients.clear();
         mCurrentDrivingState = createDrivingStateEvent(CarDrivingStateEvent.DRIVING_STATE_UNKNOWN);
     }
 
@@ -115,7 +142,7 @@
      *
      * @return {@code true} if supported, {@code false} if not
      */
-    private synchronized boolean checkPropertySupport() {
+    private boolean checkPropertySupport() {
         List<CarPropertyConfig> configs = mPropertyService.getPropertyList();
         for (int propertyId : REQUIRED_PROPERTIES) {
             boolean found = false;
@@ -136,7 +163,7 @@
     /**
      * Subscribe to the {@link CarPropertyService} for required sensors.
      */
-    private synchronized void subscribeToProperties() {
+    private void subscribeToProperties() {
         for (int propertyId : REQUIRED_PROPERTIES) {
             mPropertyService.registerListener(propertyId, PROPERTY_UPDATE_RATE,
                     mICarPropertyEventListener);
@@ -153,46 +180,14 @@
      * @param listener {@link ICarDrivingStateChangeListener}
      */
     @Override
-    public synchronized void registerDrivingStateChangeListener(
-            ICarDrivingStateChangeListener listener) {
+    public void registerDrivingStateChangeListener(ICarDrivingStateChangeListener listener) {
         if (listener == null) {
             if (DBG) {
                 Log.e(TAG, "registerDrivingStateChangeListener(): listener null");
             }
             throw new IllegalArgumentException("Listener is null");
         }
-        // If a new client is registering, create a new DrivingStateClient and add it to the list
-        // of listening clients.
-        DrivingStateClient client = findDrivingStateClient(listener);
-        if (client == null) {
-            client = new DrivingStateClient(listener);
-            try {
-                listener.asBinder().linkToDeath(client, 0);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Cannot link death recipient to binder " + e);
-                return;
-            }
-            mDrivingStateClients.add(client);
-        }
-    }
-
-    /**
-     * Iterates through the list of registered Driving State Change clients -
-     * {@link DrivingStateClient} and finds if the given client is already registered.
-     *
-     * @param listener Listener to look for.
-     * @return the {@link DrivingStateClient} if found, null if not
-     */
-    @Nullable
-    private DrivingStateClient findDrivingStateClient(ICarDrivingStateChangeListener listener) {
-        IBinder binder = listener.asBinder();
-        // Find the listener by comparing the binder object they host.
-        for (DrivingStateClient client : mDrivingStateClients) {
-            if (client.isHoldingBinder(binder)) {
-                return client;
-            }
-        }
-        return null;
+        mDrivingStateClients.register(listener);
     }
 
     /**
@@ -201,21 +196,13 @@
      * @param listener client to unregister
      */
     @Override
-    public synchronized void unregisterDrivingStateChangeListener(
-            ICarDrivingStateChangeListener listener) {
+    public void unregisterDrivingStateChangeListener(ICarDrivingStateChangeListener listener) {
         if (listener == null) {
             Log.e(TAG, "unregisterDrivingStateChangeListener(): listener null");
             throw new IllegalArgumentException("Listener is null");
         }
 
-        DrivingStateClient client = findDrivingStateClient(listener);
-        if (client == null) {
-            Log.e(TAG, "unregisterDrivingStateChangeListener(): listener was not previously "
-                    + "registered");
-            return;
-        }
-        listener.asBinder().unlinkToDeath(client, 0);
-        mDrivingStateClients.remove(client);
+        mDrivingStateClients.unregister(listener);
     }
 
     /**
@@ -225,84 +212,55 @@
      */
     @Override
     @Nullable
-    public synchronized CarDrivingStateEvent getCurrentDrivingState() {
-        return mCurrentDrivingState;
+    public CarDrivingStateEvent getCurrentDrivingState() {
+        synchronized (mLock) {
+            return mCurrentDrivingState;
+        }
     }
 
     @Override
     public void injectDrivingState(CarDrivingStateEvent event) {
         ICarImpl.assertPermission(mContext, Car.PERMISSION_CONTROL_APP_BLOCKING);
 
-        for (DrivingStateClient client : mDrivingStateClients) {
-            client.dispatchEventToClients(event);
-        }
+        dispatchEventToClients(event);
     }
 
-    /**
-     * Class that holds onto client related information - listener interface, process that hosts the
-     * binder object etc.
-     * <p>
-     * It also registers for death notifications of the host.
-     */
-    private class DrivingStateClient implements IBinder.DeathRecipient {
-        private final IBinder listenerBinder;
-        private final ICarDrivingStateChangeListener listener;
-
-        public DrivingStateClient(ICarDrivingStateChangeListener l) {
-            listener = l;
-            listenerBinder = l.asBinder();
-        }
-
-        @Override
-        public void binderDied() {
-            if (DBG) {
-                Log.d(TAG, "Binder died " + listenerBinder);
-            }
-            listenerBinder.unlinkToDeath(this, 0);
-            mDrivingStateClients.remove(this);
-        }
-
-        /**
-         * Returns if the given binder object matches to what this client info holds.
-         * Used to check if the listener asking to be registered is already registered.
-         *
-         * @return true if matches, false if not
-         */
-        public boolean isHoldingBinder(IBinder binder) {
-            return listenerBinder == binder;
-        }
-
-        /**
-         * Dispatch the events to the listener
-         *
-         * @param event {@link CarDrivingStateEvent}.
-         */
-        public void dispatchEventToClients(CarDrivingStateEvent event) {
-            if (event == null) {
-                return;
-            }
-            try {
-                listener.onDrivingStateChanged(event);
-            } catch (RemoteException e) {
-                if (DBG) {
-                    Log.d(TAG, "Dispatch to listener failed");
+    private void dispatchEventToClients(CarDrivingStateEvent event) {
+        boolean success = mClientDispatchHandler.post(() -> {
+            int numClients = mDrivingStateClients.beginBroadcast();
+            for (int i = 0; i < numClients; i++) {
+                ICarDrivingStateChangeListener callback = mDrivingStateClients.getBroadcastItem(i);
+                try {
+                    callback.onDrivingStateChanged(event);
+                } catch (RemoteException e) {
+                    Log.e(TAG,
+                            String.format("Dispatch to listener %s failed for event (%s)", callback,
+                                    event));
                 }
             }
+            mDrivingStateClients.finishBroadcast();
+        });
+
+        if (!success) {
+            Log.e(TAG, String.format("Unable to post (%s) event to dispatch handler", event));
         }
     }
 
     @Override
     public void dump(PrintWriter writer) {
         writer.println("*CarDrivingStateService*");
+        mDrivingStateClients.dump(writer, "Driving State Clients ");
         writer.println("Driving state change log:");
-        for (Utils.TransitionLog tLog : mTransitionLogs) {
-            writer.println(tLog);
-        }
-        writer.println("Current Driving State: " + mCurrentDrivingState.eventValue);
-        if (mSupportedGears != null) {
-            writer.println("Supported gears:");
-            for (Integer gear : mSupportedGears) {
-                writer.print("Gear:" + gear);
+        synchronized (mLock) {
+            for (Utils.TransitionLog tLog : mTransitionLogs) {
+                writer.println(tLog);
+            }
+            writer.println("Current Driving State: " + mCurrentDrivingState.eventValue);
+            if (mSupportedGears != null) {
+                writer.println("Supported gears:");
+                for (Integer gear : mSupportedGears) {
+                    writer.print("Gear:" + gear);
+                }
             }
         }
     }
@@ -315,8 +273,10 @@
             new ICarPropertyEventListener.Stub() {
                 @Override
                 public void onEvent(List<CarPropertyEvent> events) throws RemoteException {
-                    for (CarPropertyEvent event : events) {
-                        handlePropertyEvent(event);
+                    synchronized (mLock) {
+                        for (CarPropertyEvent event : events) {
+                            handlePropertyEventLocked(event);
+                        }
                     }
                 }
             };
@@ -326,7 +286,7 @@
      * the corresponding UX Restrictions and dispatch the events to the registered clients.
      */
     @VisibleForTesting
-    synchronized void handlePropertyEvent(CarPropertyEvent event) {
+    void handlePropertyEventLocked(CarPropertyEvent event) {
         if (event.getEventType() != CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE) {
             return;
         }
@@ -390,20 +350,17 @@
                     + mCurrentDrivingState.eventValue);
         }
         if (drivingState != mCurrentDrivingState.eventValue) {
-            addTransitionLog(TAG, mCurrentDrivingState.eventValue, drivingState,
+            addTransitionLogLocked(TAG, mCurrentDrivingState.eventValue, drivingState,
                     System.currentTimeMillis());
             // Update if there is a change in state.
             mCurrentDrivingState = createDrivingStateEvent(drivingState);
             if (DBG) {
-                Log.d(TAG, "dispatching to " + mDrivingStateClients.size() + " clients");
+                Log.d(TAG, "dispatching to " + mDrivingStateClients.getRegisteredCallbackCount()
+                        + " clients");
             }
             // Dispatch to clients on a separate thread to prevent a deadlock
             final CarDrivingStateEvent currentDrivingStateEvent = mCurrentDrivingState;
-            mClientDispatchHandler.post(() -> {
-                for (DrivingStateClient client : mDrivingStateClients) {
-                    client.dispatchEventToClients(currentDrivingStateEvent);
-                }
-            });
+            dispatchEventToClients(currentDrivingStateEvent);
         }
     }
 
@@ -417,7 +374,8 @@
         return null;
     }
 
-    private void addTransitionLog(String name, int from, int to, long timestamp) {
+    @GuardedBy("mLock")
+    private void addTransitionLogLocked(String name, int from, int to, long timestamp) {
         if (mTransitionLogs.size() >= MAX_TRANSITION_LOG_SIZE) {
             mTransitionLogs.remove();
         }
@@ -432,9 +390,10 @@
      *
      * @return Current driving state
      */
+    @GuardedBy("mLock")
     @CarDrivingState
     private int inferDrivingStateLocked() {
-        updateVehiclePropertiesIfNeeded();
+        updateVehiclePropertiesIfNeededLocked();
         if (DBG) {
             Log.d(TAG, "Last known Gear:" + mLastGear + " Last known speed:" + mLastSpeed);
         }
@@ -452,7 +411,7 @@
                 3c. if speed unavailable, then driving state is unknown
          */
 
-        if (isVehicleKnownToBeParked()) {
+        if (isVehicleKnownToBeParkedLocked()) {
             return CarDrivingStateEvent.DRIVING_STATE_PARKED;
         }
 
@@ -472,14 +431,15 @@
      * @return true if we have enough information to say the vehicle is parked.
      * false, if the vehicle is either not parked or if we don't have any information.
      */
-    private boolean isVehicleKnownToBeParked() {
+    @GuardedBy("mLock")
+    private boolean isVehicleKnownToBeParkedLocked() {
         // If we know the gear is in park, return true
         if (mLastGearTimestamp != NOT_RECEIVED && mLastGear == VehicleGear.GEAR_PARK) {
             return true;
         } else if (mLastParkingBrakeTimestamp != NOT_RECEIVED) {
             // if gear is not in park or unknown, look for status of parking brake if transmission
             // type is manual.
-            if (isCarManualTransmissionType()) {
+            if (isCarManualTransmissionTypeLocked()) {
                 return mLastParkingBrakeState;
             }
         }
@@ -492,7 +452,8 @@
      * If Supported gears information is available and GEAR_PARK is not one of the supported gears,
      * transmission type is considered to be Manual.  Automatic transmission is assumed otherwise.
      */
-    private boolean isCarManualTransmissionType() {
+    @GuardedBy("mLock")
+    private boolean isCarManualTransmissionTypeLocked() {
         if (mSupportedGears != null
                 && !mSupportedGears.isEmpty()
                 && !mSupportedGears.contains(VehicleGear.GEAR_PARK)) {
@@ -508,7 +469,8 @@
      * on-change only properties, we could be in this situation where we will have to query
      * VHAL.
      */
-    private void updateVehiclePropertiesIfNeeded() {
+    @GuardedBy("mLock")
+    private void updateVehiclePropertiesIfNeededLocked() {
         if (mLastGearTimestamp == NOT_RECEIVED) {
             CarPropertyValue propertyValue = mPropertyService.getProperty(
                     VehicleProperty.GEAR_SELECTION,
diff --git a/service/src/com/android/car/CarExperimentalFeatureServiceController.java b/service/src/com/android/car/CarExperimentalFeatureServiceController.java
new file mode 100644
index 0000000..5f9de9c
--- /dev/null
+++ b/service/src/com/android/car/CarExperimentalFeatureServiceController.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car;
+
+import android.car.IExperimentalCar;
+import android.car.IExperimentalCarHelper;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Controls binding to ExperimentalCarService and interfaces for experimental features.
+ */
+public final class CarExperimentalFeatureServiceController implements CarServiceBase {
+
+    private static final String TAG = "CAR.EXPERIMENTAL";
+
+    private final Context mContext;
+
+    private final ServiceConnection mServiceConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            IExperimentalCar experimentalCar;
+            synchronized (mLock) {
+                experimentalCar = IExperimentalCar.Stub.asInterface(service);
+                mExperimentalCar = experimentalCar;
+            }
+            if (experimentalCar == null) {
+                Log.e(TAG, "Experimental car returned null binder");
+                return;
+            }
+            CarFeatureController featureController = CarLocalServices.getService(
+                    CarFeatureController.class);
+            List<String> enabledExperimentalFeatures =
+                    featureController.getEnabledExperimentalFeatures();
+            try {
+                experimentalCar.init(mHelper, enabledExperimentalFeatures);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Experimental car service crashed", e);
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            resetFeatures();
+        }
+    };
+
+    private final IExperimentalCarHelper mHelper = new IExperimentalCarHelper.Stub() {
+        @Override
+        public void onInitComplete(List<String> allAvailableFeatures, List<String> startedFeatures,
+                List<String> classNames, List<IBinder> binders) {
+            if (allAvailableFeatures == null) {
+                Log.e(TAG, "Experimental car passed null allAvailableFeatures");
+                return;
+            }
+            if (startedFeatures == null || classNames == null || binders == null) {
+                Log.i(TAG, "Nothing enabled in Experimental car");
+                return;
+            }
+            int sizeOfStartedFeatures = startedFeatures.size();
+            if (sizeOfStartedFeatures != classNames.size()
+                    || sizeOfStartedFeatures != binders.size()) {
+                Log.e(TAG,
+                        "Experimental car passed wrong lists of enabled features, startedFeatures:"
+                        + startedFeatures + " classNames:" + classNames + " binders:" + binders);
+            }
+            // Do conversion to make indexed accesses
+            ArrayList<String> classNamesInArray = new ArrayList<>(classNames);
+            ArrayList<IBinder> bindersInArray = new ArrayList<>(binders);
+            synchronized (mLock) {
+                for (int i = 0; i < startedFeatures.size(); i++) {
+                    mEnabledFeatures.put(startedFeatures.get(i),
+                            new FeatureInfo(classNamesInArray.get(i),
+                                    bindersInArray.get(i)));
+                }
+            }
+            CarFeatureController featureController = CarLocalServices.getService(
+                    CarFeatureController.class);
+            featureController.setAvailableExperimentalFeatureList(allAvailableFeatures);
+            Log.i(TAG, "Available experimental features:" + allAvailableFeatures);
+            Log.i(TAG, "Started experimental features:" + startedFeatures);
+        }
+    };
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private IExperimentalCar mExperimentalCar;
+
+    @GuardedBy("mLock")
+    private final ArrayMap<String, FeatureInfo> mEnabledFeatures = new ArrayMap<>();
+
+    @GuardedBy("mLock")
+    private boolean mBound;
+
+    private static class FeatureInfo {
+        public final String className;
+        public final IBinder binder;
+
+        FeatureInfo(String className, IBinder binder) {
+            this.className = className;
+            this.binder = binder;
+        }
+    }
+
+    public CarExperimentalFeatureServiceController(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public void init() {
+        // Do binding only for real car servie
+        Intent intent = new Intent();
+        intent.setComponent(new ComponentName("com.android.experimentalcar",
+                "com.android.experimentalcar.ExperimentalCarService"));
+        boolean bound = bindService(intent);
+        if (!bound) {
+            Log.e(TAG, "Cannot bind to experimental car service, intent:" + intent);
+        }
+        synchronized (mLock) {
+            mBound = bound;
+        }
+    }
+
+    /**
+     * Bind service. Separated for testing.
+     * Test will override this. Default behavior will not bind if it is not real run (=system uid).
+     */
+    @VisibleForTesting
+    public boolean bindService(Intent intent) {
+        int myUid = Process.myUid();
+        if (myUid != Process.SYSTEM_UID) {
+            Log.w(TAG, "Binding experimental service skipped as this may be test env, uid:"
+                    + myUid);
+            return false;
+        }
+        try {
+            return mContext.bindServiceAsUser(intent, mServiceConnection,
+                    Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
+        } catch (Exception e) {
+            // Do not crash car service for case like package not found and etc.
+            Log.e(TAG, "Cannot bind to experimental car service", e);
+            return false;
+        }
+    }
+
+    @Override
+    public void release() {
+        synchronized (mLock) {
+            if (mBound) {
+                mContext.unbindService(mServiceConnection);
+            }
+            mBound = false;
+            resetFeatures();
+        }
+    }
+
+    @Override
+    public void dump(PrintWriter writer) {
+        writer.println("*CarExperimentalFeatureServiceController*");
+
+        synchronized (mLock) {
+            writer.println(" mEnabledFeatures, number of features:" + mEnabledFeatures.size()
+                    + ", format: (feature, class)");
+            for (int i = 0; i < mEnabledFeatures.size(); i++) {
+                String feature = mEnabledFeatures.keyAt(i);
+                FeatureInfo info = mEnabledFeatures.valueAt(i);
+                writer.println(feature + "," + info.className);
+            }
+            writer.println("mBound:" + mBound);
+        }
+    }
+
+    /**
+     * Returns class name for experimental feature.
+     */
+    public String getCarManagerClassForFeature(String featureName) {
+        FeatureInfo info;
+        synchronized (mLock) {
+            info = mEnabledFeatures.get(featureName);
+        }
+        if (info == null) {
+            return null;
+        }
+        return info.className;
+    }
+
+    /**
+     * Returns service binder for experimental feature.
+     */
+    public IBinder getCarService(String serviceName) {
+        FeatureInfo info;
+        synchronized (mLock) {
+            info = mEnabledFeatures.get(serviceName);
+        }
+        if (info == null) {
+            return null;
+        }
+        return info.binder;
+    }
+
+    private void resetFeatures() {
+        synchronized (mLock) {
+            mExperimentalCar = null;
+            mEnabledFeatures.clear();
+        }
+    }
+}
diff --git a/service/src/com/android/car/CarFeatureController.java b/service/src/com/android/car/CarFeatureController.java
new file mode 100644
index 0000000..1742e4f
--- /dev/null
+++ b/service/src/com/android/car/CarFeatureController.java
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car;
+
+import android.annotation.NonNull;
+import android.car.Car;
+import android.car.Car.FeaturerRequestEnum;
+import android.car.CarFeatures;
+import android.content.Context;
+import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.AtomicFile;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * Component controlling the feature of car.
+ */
+public final class CarFeatureController implements CarServiceBase {
+
+    private static final String TAG = "CAR.FEATURE";
+
+    // Use HaseSet for better search performance. Memory consumption is fixed and it not an issue.
+    // Should keep alphabetical order under each bucket.
+    // Update CarFeatureTest as well when this is updated.
+    private static final HashSet<String> MANDATORY_FEATURES = new HashSet<>(Arrays.asList(
+            Car.APP_FOCUS_SERVICE,
+            Car.AUDIO_SERVICE,
+            Car.BLUETOOTH_SERVICE,
+            Car.CAR_BUGREPORT_SERVICE,
+            Car.CAR_CONFIGURATION_SERVICE,
+            Car.CAR_DRIVING_STATE_SERVICE,
+            Car.CAR_INPUT_SERVICE,
+            Car.CAR_MEDIA_SERVICE,
+            Car.CAR_OCCUPANT_ZONE_SERVICE,
+            Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE,
+            Car.CAR_USER_SERVICE,
+            Car.CAR_UX_RESTRICTION_SERVICE,
+            Car.INFO_SERVICE,
+            Car.PACKAGE_SERVICE,
+            Car.POWER_SERVICE,
+            Car.PROJECTION_SERVICE,
+            Car.PROPERTY_SERVICE,
+            Car.TEST_SERVICE,
+            Car.CAR_WATCHDOG_SERVICE,
+            // All items below here are deprecated, but still should be supported
+            Car.CAR_INSTRUMENT_CLUSTER_SERVICE,
+            Car.CABIN_SERVICE,
+            Car.HVAC_SERVICE,
+            Car.SENSOR_SERVICE,
+            Car.VENDOR_EXTENSION_SERVICE
+    ));
+
+    private static final HashSet<String> OPTIONAL_FEATURES = new HashSet<>(Arrays.asList(
+            CarFeatures.FEATURE_CAR_USER_NOTICE_SERVICE,
+            Car.CAR_NAVIGATION_SERVICE,
+            Car.DIAGNOSTIC_SERVICE,
+            Car.OCCUPANT_AWARENESS_SERVICE,
+            Car.STORAGE_MONITORING_SERVICE,
+            Car.VEHICLE_MAP_SERVICE
+    ));
+
+    // Features that depend on another feature being enabled (i.e. legacy API support).
+    // For example, VMS_SUBSCRIBER_SERVICE will be enabled if VEHICLE_MAP_SERVICE is enabled
+    // and disabled if VEHICLE_MAP_SERVICE is disabled.
+    private static final List<Pair<String, String>> SUPPORT_FEATURES = Arrays.asList(
+            Pair.create(Car.VEHICLE_MAP_SERVICE, Car.VMS_SUBSCRIBER_SERVICE)
+    );
+
+    private static final String FEATURE_CONFIG_FILE_NAME = "car_feature_config.txt";
+
+    // Last line starts with this with number of features for extra sanity check.
+    private static final String CONFIG_FILE_LAST_LINE_MARKER = ",,";
+
+    // Set once in constructor and not updated. Access it without lock so that it can be accessed
+    // quickly.
+    private final HashSet<String> mEnabledFeatures;
+
+    private final Context mContext;
+
+    private final List<String> mDefaultEnabledFeaturesFromConfig;
+    private final List<String> mDisabledFeaturesFromVhal;
+
+    private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
+            getClass().getSimpleName());
+    private final Handler mHandler = new Handler(mHandlerThread.getLooper());
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private final AtomicFile mFeatureConfigFile;
+
+    @GuardedBy("mLock")
+    private final List<String> mPendingEnabledFeatures = new ArrayList<>();
+
+    @GuardedBy("mLock")
+    private final List<String> mPendingDisabledFeatures = new ArrayList<>();
+
+    @GuardedBy("mLock")
+    private HashSet<String> mAvailableExperimentalFeatures = new HashSet<>();
+
+    public CarFeatureController(@NonNull Context context,
+            @NonNull String[] defaultEnabledFeaturesFromConfig,
+            @NonNull String[] disabledFeaturesFromVhal, @NonNull File dataDir) {
+        mContext = context;
+        mDefaultEnabledFeaturesFromConfig = Arrays.asList(defaultEnabledFeaturesFromConfig);
+        mDisabledFeaturesFromVhal = Arrays.asList(disabledFeaturesFromVhal);
+        Log.i(TAG, "mDefaultEnabledFeaturesFromConfig:" + mDefaultEnabledFeaturesFromConfig
+                + ",mDisabledFeaturesFromVhal:" + mDisabledFeaturesFromVhal);
+        mEnabledFeatures = new HashSet<>(MANDATORY_FEATURES);
+        mFeatureConfigFile = new AtomicFile(new File(dataDir, FEATURE_CONFIG_FILE_NAME), TAG);
+        boolean shouldLoadDefaultConfig = !mFeatureConfigFile.exists();
+        if (!shouldLoadDefaultConfig) {
+            if (!loadFromConfigFileLocked()) {
+                shouldLoadDefaultConfig = true;
+            }
+        }
+        if (!checkMandatoryFeaturesLocked()) { // mandatory feature missing, force default config
+            mEnabledFeatures.clear();
+            mEnabledFeatures.addAll(MANDATORY_FEATURES);
+            shouldLoadDefaultConfig = true;
+        }
+        // Separate if to use this as backup for failure in loadFromConfigFileLocked()
+        if (shouldLoadDefaultConfig) {
+            parseDefaultConfig();
+            dispatchDefaultConfigUpdate();
+        }
+        addSupportFeatures(mEnabledFeatures);
+    }
+
+    @VisibleForTesting
+    List<String> getDisabledFeaturesFromVhal() {
+        return mDisabledFeaturesFromVhal;
+    }
+
+    @Override
+    public void init() {
+        // nothing should be done here. This should work with only constructor.
+    }
+
+    @Override
+    public void release() {
+        // nothing should be done here.
+    }
+
+    @Override
+    public void dump(PrintWriter writer) {
+        writer.println("*CarFeatureController*");
+        writer.println(" mEnabledFeatures:" + mEnabledFeatures);
+        writer.println(" mDefaultEnabledFeaturesFromConfig:" + mDefaultEnabledFeaturesFromConfig);
+        writer.println(" mDisabledFeaturesFromVhal:" + mDisabledFeaturesFromVhal);
+        synchronized (mLock) {
+            writer.println(" mAvailableExperimentalFeatures:" + mAvailableExperimentalFeatures);
+            writer.println(" mPendingEnabledFeatures:" + mPendingEnabledFeatures);
+            writer.println(" mPendingDisabledFeatures:" + mPendingDisabledFeatures);
+        }
+    }
+
+    /** Check {@link Car#isFeatureEnabled(String)} */
+    public boolean isFeatureEnabled(String featureName) {
+        return mEnabledFeatures.contains(featureName);
+    }
+
+    private boolean checkMandatoryFeaturesLocked() {
+        // Ensure that mandatory features are always there
+        for (String feature: MANDATORY_FEATURES) {
+            if (!mEnabledFeatures.contains(feature)) {
+                Log.e(TAG, "Mandatory feature missing in mEnabledFeatures:" + feature);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @FeaturerRequestEnum
+    private int checkFeatureExisting(String featureName) {
+        if (MANDATORY_FEATURES.contains(featureName)) {
+            return Car.FEATURE_REQUEST_MANDATORY;
+        }
+        if (!OPTIONAL_FEATURES.contains(featureName)) {
+            synchronized (mLock) {
+                if (!mAvailableExperimentalFeatures.contains(featureName)) {
+                    Log.e(TAG, "enableFeature requested for non-existing feature:"
+                            + featureName);
+                    return Car.FEATURE_REQUEST_NOT_EXISTING;
+                }
+            }
+        }
+        return Car.FEATURE_REQUEST_SUCCESS;
+    }
+
+    /** Check {@link Car#enableFeature(String)} */
+    public int enableFeature(String featureName) {
+        assertPermission();
+        int checkResult = checkFeatureExisting(featureName);
+        if (checkResult != Car.FEATURE_REQUEST_SUCCESS) {
+            return checkResult;
+        }
+
+        boolean alreadyEnabled = mEnabledFeatures.contains(featureName);
+        boolean shouldUpdateConfigFile = false;
+        synchronized (mLock) {
+            if (mPendingDisabledFeatures.remove(featureName)) {
+                shouldUpdateConfigFile = true;
+            }
+            if (!mPendingEnabledFeatures.contains(featureName) && !alreadyEnabled) {
+                shouldUpdateConfigFile = true;
+                mPendingEnabledFeatures.add(featureName);
+            }
+        }
+        if (shouldUpdateConfigFile) {
+            Log.w(TAG, "Enabling feature in config file:" + featureName);
+            dispatchDefaultConfigUpdate();
+        }
+        if (alreadyEnabled) {
+            return Car.FEATURE_REQUEST_ALREADY_IN_THE_STATE;
+        } else {
+            return Car.FEATURE_REQUEST_SUCCESS;
+        }
+    }
+
+    /** Check {@link Car#disableFeature(String)} */
+    public int disableFeature(String featureName) {
+        assertPermission();
+        int checkResult = checkFeatureExisting(featureName);
+        if (checkResult != Car.FEATURE_REQUEST_SUCCESS) {
+            return checkResult;
+        }
+
+        boolean alreadyDisabled = !mEnabledFeatures.contains(featureName);
+        boolean shouldUpdateConfigFile = false;
+        synchronized (mLock) {
+            if (mPendingEnabledFeatures.remove(featureName)) {
+                shouldUpdateConfigFile = true;
+            }
+            if (!mPendingDisabledFeatures.contains(featureName) && !alreadyDisabled) {
+                shouldUpdateConfigFile = true;
+                mPendingDisabledFeatures.add(featureName);
+            }
+        }
+        if (shouldUpdateConfigFile) {
+            Log.w(TAG, "Disabling feature in config file:" + featureName);
+            dispatchDefaultConfigUpdate();
+        }
+        if (alreadyDisabled) {
+            return Car.FEATURE_REQUEST_ALREADY_IN_THE_STATE;
+        } else {
+            return Car.FEATURE_REQUEST_SUCCESS;
+        }
+    }
+
+    /**
+     * Set available experimental features. Only features set through this call will be allowed to
+     * be enabled for experimental features. Setting this is not allowed for USER build.
+     *
+     * @return True if set is allowed and set. False if experimental feature is not allowed.
+     */
+    public boolean setAvailableExperimentalFeatureList(List<String> experimentalFeatures) {
+        assertPermission();
+        if (Build.IS_USER) {
+            Log.e(TAG, "Experimental feature list set for USER build",
+                    new RuntimeException());
+            return false;
+        }
+        synchronized (mLock) {
+            mAvailableExperimentalFeatures.clear();
+            mAvailableExperimentalFeatures.addAll(experimentalFeatures);
+        }
+        return true;
+    }
+
+    /** Check {@link Car#getAllEnabledFeatures()} */
+    public List<String> getAllEnabledFeatures() {
+        assertPermission();
+        return new ArrayList<>(mEnabledFeatures);
+    }
+
+    /** Check {@link Car#getAllPendingDisabledFeatures()} */
+    public List<String> getAllPendingDisabledFeatures() {
+        assertPermission();
+        synchronized (mLock) {
+            return new ArrayList<>(mPendingDisabledFeatures);
+        }
+    }
+
+    /** Check {@link Car#getAllPendingEnabledFeatures()} */
+    public List<String> getAllPendingEnabledFeatures() {
+        assertPermission();
+        synchronized (mLock) {
+            return new ArrayList<>(mPendingEnabledFeatures);
+        }
+    }
+
+    /** Returns currently enabled experimental features */
+    public @NonNull List<String> getEnabledExperimentalFeatures() {
+        if (Build.IS_USER) {
+            Log.e(TAG, "getEnabledExperimentalFeatures called in USER build",
+                    new RuntimeException());
+            return Collections.emptyList();
+        }
+        ArrayList<String> experimentalFeature = new ArrayList<>();
+        for (String feature: mEnabledFeatures) {
+            if (MANDATORY_FEATURES.contains(feature)) {
+                continue;
+            }
+            if (OPTIONAL_FEATURES.contains(feature)) {
+                continue;
+            }
+            experimentalFeature.add(feature);
+        }
+        return experimentalFeature;
+    }
+
+    void handleCorruptConfigFileLocked(String msg, String line) {
+        Log.e(TAG, msg + ", considered as corrupt, line:" + line);
+        mEnabledFeatures.clear();
+    }
+
+    private boolean loadFromConfigFileLocked() {
+        // done without lock, should be only called from constructor.
+        FileInputStream fis;
+        try {
+            fis = mFeatureConfigFile.openRead();
+        } catch (FileNotFoundException e) {
+            Log.i(TAG, "Feature config file not found, this could be 1st boot");
+            return false;
+        }
+        try (BufferedReader reader = new BufferedReader(
+                new InputStreamReader(fis, StandardCharsets.UTF_8))) {
+            boolean lastLinePassed = false;
+            while (true) {
+                String line = reader.readLine();
+                if (line == null) {
+                    if (!lastLinePassed) {
+                        handleCorruptConfigFileLocked("No last line checksum", "");
+                        return false;
+                    }
+                    break;
+                }
+                if (lastLinePassed && !line.isEmpty()) {
+                    handleCorruptConfigFileLocked(
+                            "Config file has additional line after last line marker", line);
+                    return false;
+                } else {
+                    if (line.startsWith(CONFIG_FILE_LAST_LINE_MARKER)) {
+                        int numberOfFeatures;
+                        try {
+                            numberOfFeatures = Integer.parseInt(line.substring(
+                                    CONFIG_FILE_LAST_LINE_MARKER.length()));
+                        } catch (NumberFormatException e) {
+                            handleCorruptConfigFileLocked(
+                                    "Config file has corrupt last line, not a number",
+                                    line);
+                            return false;
+                        }
+                        int actualNumberOfFeatures = mEnabledFeatures.size();
+                        if (numberOfFeatures != actualNumberOfFeatures) {
+                            handleCorruptConfigFileLocked(
+                                    "Config file has wrong number of features, expected:"
+                                            + numberOfFeatures
+                                            + " actual:" + actualNumberOfFeatures, line);
+                            return false;
+                        }
+                        lastLinePassed = true;
+                    } else {
+                        mEnabledFeatures.add(line);
+                    }
+                }
+            }
+        } catch (IOException e) {
+            Log.w(TAG, "Cannot load config file", e);
+            return false;
+        }
+        Log.i(TAG, "Loaded features:" + mEnabledFeatures);
+        return true;
+    }
+
+    private void persistToFeatureConfigFile(HashSet<String> features) {
+        removeSupportFeatures(features);
+        synchronized (mLock) {
+            features.removeAll(mPendingDisabledFeatures);
+            features.addAll(mPendingEnabledFeatures);
+            FileOutputStream fos;
+            try {
+                fos = mFeatureConfigFile.startWrite();
+            } catch (IOException e) {
+                Log.e(TAG, "Cannot create config file", e);
+                return;
+            }
+            try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos,
+                    StandardCharsets.UTF_8))) {
+                Log.i(TAG, "Updating features:" + features);
+                for (String feature : features) {
+                    writer.write(feature);
+                    writer.newLine();
+                }
+                writer.write(CONFIG_FILE_LAST_LINE_MARKER + features.size());
+                writer.flush();
+                mFeatureConfigFile.finishWrite(fos);
+            } catch (IOException e) {
+                mFeatureConfigFile.failWrite(fos);
+                Log.e(TAG, "Cannot create config file", e);
+            }
+        }
+    }
+
+    private void assertPermission() {
+        ICarImpl.assertPermission(mContext, Car.PERMISSION_CONTROL_CAR_FEATURES);
+    }
+
+    private void dispatchDefaultConfigUpdate() {
+        mHandler.removeCallbacksAndMessages(null);
+        HashSet<String> featuresToPersist = new HashSet<>(mEnabledFeatures);
+        mHandler.post(() -> persistToFeatureConfigFile(featuresToPersist));
+    }
+
+    private void parseDefaultConfig() {
+        for (String feature : mDefaultEnabledFeaturesFromConfig) {
+            if (!OPTIONAL_FEATURES.contains(feature)) {
+                throw new IllegalArgumentException(
+                        "config_default_enabled_optional_car_features include non-optional "
+                                + "features:" + feature);
+            }
+            if (mDisabledFeaturesFromVhal.contains(feature)) {
+                continue;
+            }
+            mEnabledFeatures.add(feature);
+        }
+        Log.i(TAG, "Loaded default features:" + mEnabledFeatures);
+    }
+
+    private static void addSupportFeatures(Collection<String> features) {
+        SUPPORT_FEATURES.stream()
+                .filter(entry -> features.contains(entry.first))
+                .forEach(entry -> features.add(entry.second));
+    }
+
+    private static void removeSupportFeatures(Collection<String> features) {
+        SUPPORT_FEATURES.stream()
+                .filter(entry -> features.contains(entry.first))
+                .forEach(entry -> features.remove(entry.second));
+    }
+}
diff --git a/service/src/com/android/car/CarInputService.java b/service/src/com/android/car/CarInputService.java
index c5ae16d..222e760 100644
--- a/service/src/com/android/car/CarInputService.java
+++ b/service/src/com/android/car/CarInputService.java
@@ -19,6 +19,7 @@
 import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_PUSH_TO_TALK;
 
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
@@ -27,7 +28,13 @@
 import android.car.CarProjectionManager;
 import android.car.input.CarInputHandlingService;
 import android.car.input.CarInputHandlingService.InputFilter;
+import android.car.input.CarInputManager;
+import android.car.input.ICarInput;
+import android.car.input.ICarInputCallback;
 import android.car.input.ICarInputListener;
+import android.car.input.RotaryEvent;
+import android.car.user.CarUserManager;
+import android.car.userlib.UserHelper;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -49,22 +56,30 @@
 import android.telecom.TelecomManager;
 import android.text.TextUtils;
 import android.util.Log;
+import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.ViewConfiguration;
 
 import com.android.car.hal.InputHalService;
+import com.android.car.user.CarUserService;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.AssistUtils;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.BitSet;
+import java.util.Collections;
 import java.util.List;
 import java.util.function.IntSupplier;
 import java.util.function.Supplier;
 
-public class CarInputService implements CarServiceBase, InputHalService.InputListener {
+/**
+ * CarInputService monitors and handles input event through vehicle HAL.
+ */
+public class CarInputService extends ICarInput.Stub
+        implements CarServiceBase, InputHalService.InputListener {
 
     /** An interface to receive {@link KeyEvent}s as they occur. */
     public interface KeyEventListener {
@@ -72,15 +87,16 @@
         void onKeyEvent(KeyEvent event);
     }
 
-    private static final class KeyPressTimer {
-        private final Handler mHandler;
+    private final class KeyPressTimer {
         private final Runnable mLongPressRunnable;
         private final Runnable mCallback = this::onTimerExpired;
         private final IntSupplier mLongPressDelaySupplier;
 
-        @GuardedBy("this")
-        private boolean mDown = false;
-        @GuardedBy("this")
+        @GuardedBy("CarInputService.this.mLock")
+        private final Handler mHandler;
+        @GuardedBy("CarInputService.this.mLock")
+        private boolean mDown;
+        @GuardedBy("CarInputService.this.mLock")
         private boolean mLongPress = false;
 
         KeyPressTimer(
@@ -91,11 +107,13 @@
         }
 
         /** Marks that a key was pressed, and starts the long-press timer. */
-        synchronized void keyDown() {
-            mDown = true;
-            mLongPress = false;
-            mHandler.removeCallbacks(mCallback);
-            mHandler.postDelayed(mCallback, mLongPressDelaySupplier.getAsInt());
+        void keyDown() {
+            synchronized (mLock) {
+                mDown = true;
+                mLongPress = false;
+                mHandler.removeCallbacks(mCallback);
+                mHandler.postDelayed(mCallback, mLongPressDelaySupplier.getAsInt());
+            }
         }
 
         /**
@@ -103,21 +121,22 @@
          *
          * Returns true if the press was a long-press.
          */
-        synchronized boolean keyUp() {
-            mHandler.removeCallbacks(mCallback);
-            mDown = false;
-            return mLongPress;
+        boolean keyUp() {
+            synchronized (mLock) {
+                mHandler.removeCallbacks(mCallback);
+                mDown = false;
+                return mLongPress;
+            }
         }
 
         private void onTimerExpired() {
-            synchronized (this) {
+            synchronized (mLock) {
                 // If the timer expires after key-up, don't retroactively make the press long.
                 if (!mDown) {
                     return;
                 }
                 mLongPress = true;
             }
-
             mLongPressRunnable.run();
         }
     }
@@ -144,6 +163,7 @@
 
     private final Context mContext;
     private final InputHalService mInputHalService;
+    private final CarUserService mUserService;
     private final TelecomManager mTelecomManager;
     private final AssistUtils mAssistUtils;
     // The ComponentName of the CarInputListener service. Can be changed via resource overlay,
@@ -160,29 +180,36 @@
     // from Settings.Secure for the current user, falling back to the system-wide default
     // long-press delay defined in ViewConfiguration. May be overridden for testing.
     private final IntSupplier mLongPressDelaySupplier;
+    // ComponentName of the RotaryService.
+    private final String mRotaryServiceComponentName;
 
-    @GuardedBy("this")
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
     private CarProjectionManager.ProjectionKeyEventHandler mProjectionKeyEventHandler;
-    @GuardedBy("this")
+
+    @GuardedBy("mLock")
     private final BitSet mProjectionKeyEventsSubscribed = new BitSet();
 
     private final KeyPressTimer mVoiceKeyTimer;
     private final KeyPressTimer mCallKeyTimer;
 
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private KeyEventListener mInstrumentClusterKeyListener;
 
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     @VisibleForTesting
     ICarInputListener mCarInputListener;
 
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private boolean mCarInputListenerBound = false;
 
     // Maps display -> keycodes handled.
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private final SetMultimap<Integer, Integer> mHandledKeys = new SetMultimap<>();
 
+    private final InputCaptureClientController mCaptureController;
+
     private final Binder mCallback = new Binder() {
         @Override
         protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
@@ -206,7 +233,7 @@
                 Log.d(CarLog.TAG_INPUT, "onServiceConnected, name: "
                         + name + ", binder: " + binder);
             }
-            synchronized (CarInputService.this) {
+            synchronized (mLock) {
                 mCarInputListener = ICarInputListener.Stub.asInterface(binder);
             }
         }
@@ -214,7 +241,7 @@
         @Override
         public void onServiceDisconnected(ComponentName name) {
             Log.d(CarLog.TAG_INPUT, "onServiceDisconnected, name: " + name);
-            synchronized (CarInputService.this) {
+            synchronized (mLock) {
                 mCarInputListener = null;
             }
         }
@@ -224,7 +251,7 @@
 
     // BluetoothHeadsetClient set through mBluetoothProfileServiceListener, and used by
     // launchBluetoothVoiceRecognition().
-    @GuardedBy("mBluetoothProfileServiceListener")
+    @GuardedBy("mLock")
     private BluetoothHeadsetClient mBluetoothHeadsetClient;
 
     private final BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
@@ -233,7 +260,7 @@
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
             if (profile == BluetoothProfile.HEADSET_CLIENT) {
                 Log.d(CarLog.TAG_INPUT, "Bluetooth proxy connected for HEADSET_CLIENT profile");
-                synchronized (this) {
+                synchronized (mLock) {
                     mBluetoothHeadsetClient = (BluetoothHeadsetClient) proxy;
                 }
             }
@@ -243,21 +270,25 @@
         public void onServiceDisconnected(int profile) {
             if (profile == BluetoothProfile.HEADSET_CLIENT) {
                 Log.d(CarLog.TAG_INPUT, "Bluetooth proxy disconnected for HEADSET_CLIENT profile");
-                synchronized (this) {
+                synchronized (mLock) {
                     mBluetoothHeadsetClient = null;
                 }
             }
         }
     };
 
+    private final CarUserManager.UserLifecycleListener mUserLifecycleListener = event -> {
+        Log.d(CarLog.TAG_INPUT, "CarInputService.onEvent(" + event + ")");
+        if (CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING == event.getEventType()) {
+            updateRotaryServiceSettings(event.getUserId());
+        }
+    };
+
     @Nullable
     private static ComponentName getDefaultInputComponent(Context context) {
         String carInputService = context.getString(R.string.inputService);
-        if (TextUtils.isEmpty(carInputService)) {
-            return null;
-        }
-
-        return ComponentName.unflattenFromString(carInputService);
+        return TextUtils.isEmpty(carInputService)
+                ? null : ComponentName.unflattenFromString(carInputService);
     }
 
     private static int getViewLongPressDelay(ContentResolver cr) {
@@ -268,8 +299,9 @@
                 UserHandle.USER_CURRENT);
     }
 
-    public CarInputService(Context context, InputHalService inputHalService) {
-        this(context, inputHalService, new Handler(Looper.getMainLooper()),
+    public CarInputService(Context context, InputHalService inputHalService,
+            CarUserService userService) {
+        this(context, inputHalService, userService, new Handler(Looper.getMainLooper()),
                 context.getSystemService(TelecomManager.class), new AssistUtils(context),
                 event ->
                         context.getSystemService(InputManager.class)
@@ -280,13 +312,15 @@
     }
 
     @VisibleForTesting
-    CarInputService(Context context, InputHalService inputHalService, Handler handler,
-            TelecomManager telecomManager, AssistUtils assistUtils,
+    CarInputService(Context context, InputHalService inputHalService, CarUserService userService,
+            Handler handler, TelecomManager telecomManager, AssistUtils assistUtils,
             KeyEventListener mainDisplayHandler, Supplier<String> lastCalledNumberSupplier,
             @Nullable ComponentName customInputServiceComponent,
             IntSupplier longPressDelaySupplier) {
         mContext = context;
+        mCaptureController = new InputCaptureClientController(context);
         mInputHalService = inputHalService;
+        mUserService = userService;
         mTelecomManager = telecomManager;
         mAssistUtils = assistUtils;
         mMainDisplayHandler = mainDisplayHandler;
@@ -299,13 +333,17 @@
                         handler, longPressDelaySupplier, this::handleVoiceAssistLongPress);
         mCallKeyTimer =
                 new KeyPressTimer(handler, longPressDelaySupplier, this::handleCallLongPress);
+
+        mRotaryServiceComponentName = mContext.getString(R.string.rotaryService);
     }
 
     @VisibleForTesting
-    synchronized void setHandledKeys(InputFilter[] handledKeys) {
-        mHandledKeys.clear();
-        for (InputFilter handledKey : handledKeys) {
-            mHandledKeys.put(handledKey.mTargetDisplay, handledKey.mKeyCode);
+    void setHandledKeys(InputFilter[] handledKeys) {
+        synchronized (mLock) {
+            mHandledKeys.clear();
+            for (InputFilter handledKey : handledKeys) {
+                mHandledKeys.put(handledKey.mTargetDisplay, handledKey.mKeyCode);
+            }
         }
     }
 
@@ -315,7 +353,7 @@
     public void setProjectionKeyEventHandler(
             @Nullable CarProjectionManager.ProjectionKeyEventHandler listener,
             @Nullable BitSet events) {
-        synchronized (this) {
+        synchronized (mLock) {
             mProjectionKeyEventHandler = listener;
             mProjectionKeyEventsSubscribed.clear();
             if (events != null) {
@@ -325,7 +363,7 @@
     }
 
     public void setInstrumentClusterKeyListener(KeyEventListener listener) {
-        synchronized (this) {
+        synchronized (mLock) {
             mInstrumentClusterKeyListener = listener;
         }
     }
@@ -339,20 +377,22 @@
             Log.d(CarLog.TAG_INPUT, "Hal supports key input.");
         }
 
-
         mInputHalService.setInputListener(this);
-        synchronized (this) {
+        synchronized (mLock) {
             mCarInputListenerBound = bindCarInputService();
         }
         if (mBluetoothAdapter != null) {
             mBluetoothAdapter.getProfileProxy(
                     mContext, mBluetoothProfileServiceListener, BluetoothProfile.HEADSET_CLIENT);
         }
+        if (!TextUtils.isEmpty(mRotaryServiceComponentName)) {
+            mUserService.addUserLifecycleListener(mUserLifecycleListener);
+        }
     }
 
     @Override
     public void release() {
-        synchronized (this) {
+        synchronized (mLock) {
             mProjectionKeyEventHandler = null;
             mProjectionKeyEventsSubscribed.clear();
             mInstrumentClusterKeyListener = null;
@@ -360,21 +400,22 @@
                 mContext.unbindService(mInputServiceConnection);
                 mCarInputListenerBound = false;
             }
-        }
-        synchronized (mBluetoothProfileServiceListener) {
             if (mBluetoothHeadsetClient != null) {
                 mBluetoothAdapter.closeProfileProxy(
                         BluetoothProfile.HEADSET_CLIENT, mBluetoothHeadsetClient);
                 mBluetoothHeadsetClient = null;
             }
         }
+        if (!TextUtils.isEmpty(mRotaryServiceComponentName)) {
+            mUserService.removeUserLifecycleListener(mUserLifecycleListener);
+        }
     }
 
     @Override
     public void onKeyEvent(KeyEvent event, int targetDisplay) {
         // Give a car specific input listener the opportunity to intercept any input from the car
         ICarInputListener carInputListener;
-        synchronized (this) {
+        synchronized (mLock) {
             carInputListener = mCarInputListener;
         }
         if (carInputListener != null && isCustomEventHandler(event, targetDisplay)) {
@@ -403,12 +444,85 @@
         if (targetDisplay == InputHalService.DISPLAY_INSTRUMENT_CLUSTER) {
             handleInstrumentClusterKey(event);
         } else {
+            if (mCaptureController.onKeyEvent(CarInputManager.TARGET_DISPLAY_TYPE_MAIN, event)) {
+                return;
+            }
             mMainDisplayHandler.onKeyEvent(event);
         }
     }
 
-    private synchronized boolean isCustomEventHandler(KeyEvent event, int targetDisplay) {
-        return mHandledKeys.containsEntry(targetDisplay, event.getKeyCode());
+    @Override
+    public void onRotaryEvent(RotaryEvent event, int targetDisplay) {
+        if (!mCaptureController.onRotaryEvent(targetDisplay, event)) {
+            List<KeyEvent> keyEvents = rotaryEventToKeyEvents(event);
+            for (KeyEvent keyEvent : keyEvents) {
+                onKeyEvent(keyEvent, targetDisplay);
+            }
+        }
+    }
+
+    private static List<KeyEvent> rotaryEventToKeyEvents(RotaryEvent event) {
+        int numClicks = event.getNumberOfClicks();
+        int numEvents = numClicks * 2; // up / down per each click
+        boolean clockwise = event.isClockwise();
+        int keyCode;
+        switch (event.getInputType()) {
+            case CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION:
+                keyCode = clockwise
+                        ? KeyEvent.KEYCODE_NAVIGATE_NEXT
+                        : KeyEvent.KEYCODE_NAVIGATE_PREVIOUS;
+                break;
+            case CarInputManager.INPUT_TYPE_ROTARY_VOLUME:
+                keyCode = clockwise
+                        ? KeyEvent.KEYCODE_VOLUME_UP
+                        : KeyEvent.KEYCODE_VOLUME_DOWN;
+                break;
+            default:
+                Log.e(CarLog.TAG_INPUT, "Unknown rotary input type: " + event.getInputType());
+                return Collections.EMPTY_LIST;
+        }
+        ArrayList<KeyEvent> keyEvents = new ArrayList<>(numEvents);
+        for (int i = 0; i < numClicks; i++) {
+            long uptime = event.getUptimeMillisForClick(i);
+            KeyEvent downEvent = createKeyEvent(/* down= */ true, uptime, uptime, keyCode);
+            KeyEvent upEvent = createKeyEvent(/* down= */ false, uptime, uptime, keyCode);
+            keyEvents.add(downEvent);
+            keyEvents.add(upEvent);
+        }
+        return keyEvents;
+    }
+
+    private static KeyEvent createKeyEvent(boolean down, long downTime, long eventTime,
+            int keyCode) {
+        return new KeyEvent(
+                downTime,
+                eventTime,
+                /* action= */ down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
+                keyCode,
+                /* repeat= */ 0,
+                /* metaState= */ 0,
+                /* deviceId= */ 0,
+                /* scancode= */ 0,
+                /* flags= */ 0,
+                InputDevice.SOURCE_CLASS_BUTTON);
+    }
+
+    @Override
+    public int requestInputEventCapture(ICarInputCallback callback, int targetDisplayType,
+            int[] inputTypes, int requestFlags) {
+        return mCaptureController.requestInputEventCapture(callback, targetDisplayType, inputTypes,
+                requestFlags);
+    }
+
+    @Override
+    public void releaseInputEventCapture(ICarInputCallback callback, int targetDisplayType) {
+        mCaptureController.releaseInputEventCapture(callback, targetDisplayType);
+    }
+
+    private boolean isCustomEventHandler(KeyEvent event, int targetDisplay) {
+        synchronized (mLock) {
+            return mHandledKeys.containsEntry(targetDisplay, event.getKeyCode());
+        }
     }
 
     private void handleVoiceAssistKey(KeyEvent event) {
@@ -490,7 +604,7 @@
 
     private boolean dispatchProjectionKeyEvent(@CarProjectionManager.KeyEventNum int event) {
         CarProjectionManager.ProjectionKeyEventHandler projectionKeyEventHandler;
-        synchronized (this) {
+        synchronized (mLock) {
             projectionKeyEventHandler = mProjectionKeyEventHandler;
             if (projectionKeyEventHandler == null || !mProjectionKeyEventsSubscribed.get(event)) {
                 // No event handler, or event handler doesn't want this event - we're done.
@@ -526,7 +640,6 @@
             mTelecomManager.acceptRingingCall();
             return true;
         }
-
         return false;
     }
 
@@ -536,7 +649,7 @@
     }
 
     private boolean launchBluetoothVoiceRecognition() {
-        synchronized (mBluetoothProfileServiceListener) {
+        synchronized (mLock) {
             if (mBluetoothHeadsetClient == null || !isBluetoothVoiceRecognitionEnabled()) {
                 return false;
             }
@@ -580,7 +693,7 @@
 
     private void handleInstrumentClusterKey(KeyEvent event) {
         KeyEventListener listener = null;
-        synchronized (this) {
+        synchronized (mLock) {
             listener = mInstrumentClusterKeyListener;
         }
         if (listener == null) {
@@ -590,12 +703,15 @@
     }
 
     @Override
-    public synchronized void dump(PrintWriter writer) {
+    public void dump(PrintWriter writer) {
         writer.println("*Input Service*");
         writer.println("mCustomInputServiceComponent: " + mCustomInputServiceComponent);
-        writer.println("mCarInputListenerBound: " + mCarInputListenerBound);
-        writer.println("mCarInputListener: " + mCarInputListener);
+        synchronized (mLock) {
+            writer.println("mCarInputListenerBound: " + mCarInputListenerBound);
+            writer.println("mCarInputListener: " + mCarInputListener);
+        }
         writer.println("Long-press delay: " + mLongPressDelaySupplier.getAsInt() + "ms");
+        mCaptureController.dump(writer);
     }
 
     private boolean bindCarInputService() {
@@ -613,4 +729,19 @@
         intent.setComponent(mCustomInputServiceComponent);
         return mContext.bindService(intent, mInputServiceConnection, Context.BIND_AUTO_CREATE);
     }
+
+    private void updateRotaryServiceSettings(@UserIdInt int userId) {
+        if (UserHelper.isHeadlessSystemUser(userId)) {
+            return;
+        }
+        ContentResolver contentResolver = mContext.getContentResolver();
+        Settings.Secure.putStringForUser(contentResolver,
+                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                mRotaryServiceComponentName,
+                userId);
+        Settings.Secure.putStringForUser(contentResolver,
+                Settings.Secure.ACCESSIBILITY_ENABLED,
+                "1",
+                userId);
+    }
 }
diff --git a/service/src/com/android/car/CarLocationService.java b/service/src/com/android/car/CarLocationService.java
index d4daac2..f7cfbc1 100644
--- a/service/src/com/android/car/CarLocationService.java
+++ b/service/src/com/android/car/CarLocationService.java
@@ -17,14 +17,13 @@
 package com.android.car;
 
 import android.app.ActivityManager;
-import android.car.ICarUserService;
 import android.car.ILocationManagerProxy;
+import android.car.IPerUserCarService;
 import android.car.drivingstate.CarDrivingStateEvent;
 import android.car.drivingstate.ICarDrivingStateChangeListener;
 import android.car.hardware.power.CarPowerManager;
 import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
 import android.car.hardware.power.CarPowerManager.CarPowerStateListenerWithCompletion;
-import android.car.userlib.CarUserManagerHelper;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -36,6 +35,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.AtomicFile;
 import android.util.JsonReader;
 import android.util.JsonWriter;
@@ -62,7 +62,6 @@
         CarPowerStateListenerWithCompletion {
     private static final String TAG = "CarLocationService";
     private static final String FILENAME = "location_cache.json";
-    private static final boolean DBG = true;
     // The accuracy for the stored timestamp
     private static final long GRANULARITY_ONE_DAY_MS = 24 * 60 * 60 * 1000L;
     // The time-to-live for the cached location
@@ -70,6 +69,20 @@
     // The maximum number of times to try injecting a location
     private static final int MAX_LOCATION_INJECTION_ATTEMPTS = 10;
 
+    // Constants for location serialization.
+    private static final String PROVIDER = "provider";
+    private static final String LATITUDE = "latitude";
+    private static final String LONGITUDE = "longitude";
+    private static final String ALTITUDE = "altitude";
+    private static final String SPEED = "speed";
+    private static final String BEARING = "bearing";
+    private static final String ACCURACY = "accuracy";
+    private static final String VERTICAL_ACCURACY = "verticalAccuracy";
+    private static final String SPEED_ACCURACY = "speedAccuracy";
+    private static final String BEARING_ACCURACY = "bearingAccuracy";
+    private static final String IS_FROM_MOCK_PROVIDER = "isFromMockProvider";
+    private static final String CAPTURE_TIME = "captureTime";
+
     // Used internally for mHandlerThread synchronization
     private final Object mLock = new Object();
 
@@ -77,10 +90,10 @@
     private final Object mLocationManagerProxyLock = new Object();
 
     private final Context mContext;
-    private final CarUserManagerHelper mCarUserManagerHelper;
-    private int mTaskCount = 0;
-    private HandlerThread mHandlerThread;
-    private Handler mHandler;
+    private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
+            getClass().getSimpleName());
+    private final Handler mHandler = new Handler(mHandlerThread.getLooper());
+
     private CarPowerManager mCarPowerManager;
     private CarDrivingStateService mCarDrivingStateService;
     private PerUserCarServiceHelper mPerUserCarServiceHelper;
@@ -92,23 +105,23 @@
     private final PerUserCarServiceHelper.ServiceCallback mUserServiceCallback =
             new PerUserCarServiceHelper.ServiceCallback() {
                 @Override
-                public void onServiceConnected(ICarUserService carUserService) {
+                public void onServiceConnected(IPerUserCarService perUserCarService) {
                     logd("Connected to PerUserCarService");
-                    if (carUserService == null) {
-                        logd("ICarUserService is null. Cannot get location manager proxy");
+                    if (perUserCarService == null) {
+                        logd("IPerUserCarService is null. Cannot get location manager proxy");
                         return;
                     }
                     synchronized (mLocationManagerProxyLock) {
                         try {
-                            mILocationManagerProxy = carUserService.getLocationManagerProxy();
+                            mILocationManagerProxy = perUserCarService.getLocationManagerProxy();
                         } catch (RemoteException e) {
-                            Log.e(TAG, "RemoteException from ICarUserService", e);
+                            Log.e(TAG, "RemoteException from IPerUserCarService", e);
                             return;
                         }
                     }
                     int currentUser = ActivityManager.getCurrentUser();
-                    logd("Current user: " + currentUser);
-                    if (mCarUserManagerHelper.isHeadlessSystemUser()
+                    logd("Current user: %s", currentUser);
+                    if (UserManager.isHeadlessSystemUserMode()
                             && currentUser > UserHandle.USER_SYSTEM) {
                         asyncOperation(() -> loadLocation());
                     }
@@ -116,7 +129,7 @@
 
                 @Override
                 public void onPreUnbind() {
-                    logd("Before Unbinding from PerCarUserService");
+                    logd("Before Unbinding from PerUserCarService");
                     synchronized (mLocationManagerProxyLock) {
                         mILocationManagerProxy = null;
                     }
@@ -135,7 +148,7 @@
             new ICarDrivingStateChangeListener.Stub() {
                 @Override
                 public void onDrivingStateChanged(CarDrivingStateEvent event) {
-                    logd("onDrivingStateChanged " + event);
+                    logd("onDrivingStateChanged: %s", event);
                     if (event != null
                             && event.eventValue == CarDrivingStateEvent.DRIVING_STATE_MOVING) {
                         deleteCacheFile();
@@ -147,10 +160,9 @@
                 }
             };
 
-    public CarLocationService(Context context, CarUserManagerHelper carUserManagerHelper) {
+    public CarLocationService(Context context) {
         logd("constructed");
         mContext = context;
-        mCarUserManagerHelper = carUserManagerHelper;
     }
 
     @Override
@@ -204,7 +216,7 @@
 
     @Override
     public void onStateChanged(int state, CompletableFuture<Void> future) {
-        logd("onStateChanged: " + state);
+        logd("onStateChanged: %s", state);
         switch (state) {
             case CarPowerStateListener.SHUTDOWN_PREPARE:
                 asyncOperation(() -> {
@@ -242,7 +254,7 @@
 
     @Override
     public void onReceive(Context context, Intent intent) {
-        logd("onReceive " + intent);
+        logd("onReceive %s", intent);
         // If the system user is headless but the current user is still the system user, then we
         // should not delete the location cache file due to missing location permissions.
         if (isCurrentUserHeadlessSystemUser()) {
@@ -258,7 +270,7 @@
             try {
                 if (action == LocationManager.MODE_CHANGED_ACTION) {
                     boolean locationEnabled = mILocationManagerProxy.isLocationEnabled();
-                    logd("isLocationEnabled(): " + locationEnabled);
+                    logd("isLocationEnabled(): %s", locationEnabled);
                     if (!locationEnabled) {
                         deleteCacheFile();
                     }
@@ -274,7 +286,8 @@
     /** Tells whether the current foreground user is the headless system user. */
     private boolean isCurrentUserHeadlessSystemUser() {
         int currentUserId = ActivityManager.getCurrentUser();
-        return mCarUserManagerHelper.isHeadlessSystemUser() && currentUserId == 0;
+        return UserManager.isHeadlessSystemUserMode()
+                && currentUserId == UserHandle.USER_SYSTEM;
     }
 
     /**
@@ -304,39 +317,39 @@
                 fos = atomicFile.startWrite();
                 try (JsonWriter jsonWriter = new JsonWriter(new OutputStreamWriter(fos, "UTF-8"))) {
                     jsonWriter.beginObject();
-                    jsonWriter.name("provider").value(location.getProvider());
-                    jsonWriter.name("latitude").value(location.getLatitude());
-                    jsonWriter.name("longitude").value(location.getLongitude());
+                    jsonWriter.name(PROVIDER).value(location.getProvider());
+                    jsonWriter.name(LATITUDE).value(location.getLatitude());
+                    jsonWriter.name(LONGITUDE).value(location.getLongitude());
                     if (location.hasAltitude()) {
-                        jsonWriter.name("altitude").value(location.getAltitude());
+                        jsonWriter.name(ALTITUDE).value(location.getAltitude());
                     }
                     if (location.hasSpeed()) {
-                        jsonWriter.name("speed").value(location.getSpeed());
+                        jsonWriter.name(SPEED).value(location.getSpeed());
                     }
                     if (location.hasBearing()) {
-                        jsonWriter.name("bearing").value(location.getBearing());
+                        jsonWriter.name(BEARING).value(location.getBearing());
                     }
                     if (location.hasAccuracy()) {
-                        jsonWriter.name("accuracy").value(location.getAccuracy());
+                        jsonWriter.name(ACCURACY).value(location.getAccuracy());
                     }
                     if (location.hasVerticalAccuracy()) {
-                        jsonWriter.name("verticalAccuracy").value(
+                        jsonWriter.name(VERTICAL_ACCURACY).value(
                                 location.getVerticalAccuracyMeters());
                     }
                     if (location.hasSpeedAccuracy()) {
-                        jsonWriter.name("speedAccuracy").value(
+                        jsonWriter.name(SPEED_ACCURACY).value(
                                 location.getSpeedAccuracyMetersPerSecond());
                     }
                     if (location.hasBearingAccuracy()) {
-                        jsonWriter.name("bearingAccuracy").value(
+                        jsonWriter.name(BEARING_ACCURACY).value(
                                 location.getBearingAccuracyDegrees());
                     }
                     if (location.isFromMockProvider()) {
-                        jsonWriter.name("isFromMockProvider").value(true);
+                        jsonWriter.name(IS_FROM_MOCK_PROVIDER).value(true);
                     }
                     long currentTime = location.getTime();
                     // Round the time down to only be accurate within one day.
-                    jsonWriter.name("captureTime").value(
+                    jsonWriter.name(CAPTURE_TIME).value(
                             currentTime - currentTime % GRANULARITY_ONE_DAY_MS);
                     jsonWriter.endObject();
                 }
@@ -353,7 +366,7 @@
      */
     private void loadLocation() {
         Location location = readLocationFromCacheFile();
-        logd("Read location from timestamp " + location.getTime());
+        logd("Read location from timestamp %s", location.getTime());
         long currentTime = System.currentTimeMillis();
         if (location.getTime() + TTL_THIRTY_DAYS_MS < currentTime) {
             logd("Location expired.");
@@ -370,43 +383,58 @@
 
     private Location readLocationFromCacheFile() {
         Location location = new Location((String) null);
-        AtomicFile atomicFile = new AtomicFile(getLocationCacheFile());
+        File file = getLocationCacheFile();
+        AtomicFile atomicFile = new AtomicFile(file);
         try (FileInputStream fis = atomicFile.openRead()) {
             JsonReader reader = new JsonReader(new InputStreamReader(fis, "UTF-8"));
             reader.beginObject();
             while (reader.hasNext()) {
                 String name = reader.nextName();
-                if (name.equals("provider")) {
-                    location.setProvider(reader.nextString());
-                } else if (name.equals("latitude")) {
-                    location.setLatitude(reader.nextDouble());
-                } else if (name.equals("longitude")) {
-                    location.setLongitude(reader.nextDouble());
-                } else if (name.equals("altitude")) {
-                    location.setAltitude(reader.nextDouble());
-                } else if (name.equals("speed")) {
-                    location.setSpeed((float) reader.nextDouble());
-                } else if (name.equals("bearing")) {
-                    location.setBearing((float) reader.nextDouble());
-                } else if (name.equals("accuracy")) {
-                    location.setAccuracy((float) reader.nextDouble());
-                } else if (name.equals("verticalAccuracy")) {
-                    location.setVerticalAccuracyMeters((float) reader.nextDouble());
-                } else if (name.equals("speedAccuracy")) {
-                    location.setSpeedAccuracyMetersPerSecond((float) reader.nextDouble());
-                } else if (name.equals("bearingAccuracy")) {
-                    location.setBearingAccuracyDegrees((float) reader.nextDouble());
-                } else if (name.equals("isFromMockProvider")) {
-                    location.setIsFromMockProvider(reader.nextBoolean());
-                } else if (name.equals("captureTime")) {
-                    location.setTime(reader.nextLong());
-                } else {
-                    reader.skipValue();
+                switch (name) {
+                    case PROVIDER:
+                        location.setProvider(reader.nextString());
+                        break;
+                    case LATITUDE:
+                        location.setLatitude(reader.nextDouble());
+                        break;
+                    case LONGITUDE:
+                        location.setLongitude(reader.nextDouble());
+                        break;
+                    case ALTITUDE:
+                        location.setAltitude(reader.nextDouble());
+                        break;
+                    case SPEED:
+                        location.setSpeed((float) reader.nextDouble());
+                        break;
+                    case BEARING:
+                        location.setBearing((float) reader.nextDouble());
+                        break;
+                    case ACCURACY:
+                        location.setAccuracy((float) reader.nextDouble());
+                        break;
+                    case VERTICAL_ACCURACY:
+                        location.setVerticalAccuracyMeters((float) reader.nextDouble());
+                        break;
+                    case SPEED_ACCURACY:
+                        location.setSpeedAccuracyMetersPerSecond((float) reader.nextDouble());
+                        break;
+                    case BEARING_ACCURACY:
+                        location.setBearingAccuracyDegrees((float) reader.nextDouble());
+                        break;
+                    case IS_FROM_MOCK_PROVIDER:
+                        location.setIsFromMockProvider(reader.nextBoolean());
+                        break;
+                    case CAPTURE_TIME:
+                        location.setTime(reader.nextLong());
+                        break;
+                    default:
+                        Log.w(TAG, String.format("Unrecognized key: %s", name));
+                        reader.skipValue();
                 }
             }
             reader.endObject();
         } catch (FileNotFoundException e) {
-            Log.d(TAG, "Location cache file not found.");
+            logd("Location cache file not found: %s", file);
         } catch (IOException e) {
             Log.e(TAG, "Unable to read from disk", e);
         } catch (NumberFormatException | IllegalStateException e) {
@@ -416,8 +444,13 @@
     }
 
     private void deleteCacheFile() {
-        boolean deleted = getLocationCacheFile().delete();
-        logd("Deleted cache file: " + deleted);
+        File file = getLocationCacheFile();
+        boolean deleted = file.delete();
+        if (deleted) {
+            logd("Successfully deleted cache file at %s", file);
+        } else {
+            logd("Failed to delete cache file at %s", file);
+        }
     }
 
     /**
@@ -437,11 +470,11 @@
                 }
             }
         }
-        logd("Injected location with result " + success + " on attempt "
-                + attemptCount);
         if (success) {
+            logd("Successfully injected stored location on attempt %s.", attemptCount);
             return;
         } else if (attemptCount <= MAX_LOCATION_INJECTION_ATTEMPTS) {
+            logd("Failed to inject stored location on attempt %s.", attemptCount);
             asyncOperation(() -> {
                 injectLocation(location, attemptCount + 1);
             }, 200 * attemptCount);
@@ -452,9 +485,7 @@
 
     private File getLocationCacheFile() {
         SystemInterface systemInterface = CarLocalServices.getService(SystemInterface.class);
-        File file = new File(systemInterface.getSystemCarDir(), FILENAME);
-        logd("File: " + file);
-        return file;
+        return new File(systemInterface.getSystemCarDir(), FILENAME);
     }
 
     @VisibleForTesting
@@ -463,33 +494,11 @@
     }
 
     private void asyncOperation(Runnable operation, long delayMillis) {
-        synchronized (mLock) {
-            // Create a new HandlerThread if this is the first task to queue.
-            if (++mTaskCount == 1) {
-                mHandlerThread = new HandlerThread("CarLocationServiceThread");
-                mHandlerThread.start();
-                mHandler = new Handler(mHandlerThread.getLooper());
-            }
-        }
-        mHandler.postDelayed(() -> {
-            try {
-                operation.run();
-            } finally {
-                synchronized (mLock) {
-                    // Quit the thread when the task queue is empty.
-                    if (--mTaskCount == 0) {
-                        mHandler.getLooper().quit();
-                        mHandler = null;
-                        mHandlerThread = null;
-                    }
-                }
-            }
-        }, delayMillis);
+        mHandler.postDelayed(() -> operation.run(), delayMillis);
     }
 
-    private static void logd(String msg) {
-        if (DBG) {
-            Log.d(TAG, msg);
-        }
+    private static void logd(String msg, Object... vals) {
+        // Disable logs here if they become too spammy.
+        Log.d(TAG, String.format(msg, vals));
     }
 }
diff --git a/service/src/com/android/car/CarLog.java b/service/src/com/android/car/CarLog.java
index a77a549..a9b7dd4 100644
--- a/service/src/com/android/car/CarLog.java
+++ b/service/src/com/android/car/CarLog.java
@@ -34,6 +34,8 @@
     public static final String TAG_MEDIA = "CAR.MEDIA";
     public static final String TAG_MONITORING = "CAR.MONITORING";
     public static final String TAG_NAV = "CAR.NAV";
+    public static final String TAG_OCCUPANT = "CAR.OCCUPANT";
+    public static final String TAG_OAS = "CAR.OAS";
     public static final String TAG_PACKAGE = "CAR.PACKAGE";
     public static final String TAG_POWER = "CAR.POWER";
     public static final String TAG_PROJECTION = "CAR.PROJECTION";
@@ -45,6 +47,7 @@
     public static final String TAG_TEST = "CAR.TEST";
     public static final String TAG_USER = "CAR.USER";
     public static final String TAG_VENDOR_EXT = "CAR.VENDOR_EXT";
+    public static final String TAG_WATCHDOG = "CAR.WATCHDOG";
 
     public static String concatTag(String tagPrefix, Class clazz) {
         String tag = tagPrefix + "." + clazz.getSimpleName();
diff --git a/service/src/com/android/car/CarMediaService.java b/service/src/com/android/car/CarMediaService.java
index 9f57179..9501c89 100644
--- a/service/src/com/android/car/CarMediaService.java
+++ b/service/src/com/android/car/CarMediaService.java
@@ -15,12 +15,19 @@
  */
 package com.android.car;
 
+import static android.car.media.CarMediaManager.MEDIA_SOURCE_MODE_BROWSE;
+import static android.car.media.CarMediaManager.MEDIA_SOURCE_MODE_PLAYBACK;
+
+import android.annotation.TestApi;
 import android.app.ActivityManager;
 import android.car.Car;
 import android.car.media.CarMediaManager;
 import android.car.media.CarMediaManager.MediaSourceChangedListener;
+import android.car.media.CarMediaManager.MediaSourceMode;
 import android.car.media.ICarMedia;
 import android.car.media.ICarMediaSourceListener;
+import android.car.user.CarUserManager;
+import android.car.user.CarUserManager.UserLifecycleListener;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -51,6 +58,10 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.car.user.CarUserService;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.io.PrintWriter;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
@@ -73,12 +84,15 @@
 public class CarMediaService extends ICarMedia.Stub implements CarServiceBase {
 
     private static final String SOURCE_KEY = "media_source_component";
+    private static final String SOURCE_KEY_SEPARATOR = "_";
     private static final String PLAYBACK_STATE_KEY = "playback_state";
     private static final String SHARED_PREF = "com.android.car.media.car_media_service";
     private static final String COMPONENT_NAME_SEPARATOR = ",";
     private static final String MEDIA_CONNECTION_ACTION = "com.android.car.media.MEDIA_CONNECTION";
     private static final String EXTRA_AUTOPLAY = "com.android.car.media.autoplay";
 
+    private static final int MEDIA_SOURCE_MODES = 2;
+
     // XML configuration options for autoplay on media source change.
     private static final int AUTOPLAY_CONFIG_NEVER = 0;
     private static final int AUTOPLAY_CONFIG_ALWAYS = 1;
@@ -88,11 +102,12 @@
     private static final int AUTOPLAY_CONFIG_RETAIN_PREVIOUS = 3;
 
     private final Context mContext;
+    private final CarUserService mUserService;
     private final UserManager mUserManager;
     private final MediaSessionManager mMediaSessionManager;
     private final MediaSessionUpdater mMediaSessionUpdater = new MediaSessionUpdater();
-    private ComponentName mPrimaryMediaComponent;
-    private ComponentName mPreviousMediaComponent;
+    @GuardedBy("mLock")
+    private ComponentName[] mPrimaryMediaComponents = new ComponentName[MEDIA_SOURCE_MODES];
     private SharedPreferences mSharedPrefs;
     // MediaController for the current active user's active media session. This controller can be
     // null if playback has not been started yet.
@@ -100,30 +115,33 @@
     private SessionChangedListener mSessionsListener;
     private int mPlayOnMediaSourceChangedConfig;
     private int mPlayOnBootConfig;
+    private boolean mIndependentPlaybackConfig;
     private int mCurrentPlaybackState;
 
     private boolean mPendingInit;
-    private int mCurrentUser;
 
-    private final RemoteCallbackList<ICarMediaSourceListener> mMediaSourceListeners =
-            new RemoteCallbackList();
+    @GuardedBy("mLock")
+    private final RemoteCallbackList<ICarMediaSourceListener>[] mMediaSourceListeners =
+            new RemoteCallbackList[MEDIA_SOURCE_MODES];
 
     private final Handler mMainHandler = new Handler(Looper.getMainLooper());
 
-    // Handler to receive PlaybackState callbacks from the active media controller.
-    private final Handler mHandler;
-    private final HandlerThread mHandlerThread;
 
-    /** The package name of the last media source that was removed while being primary. */
-    private String mRemovedMediaSourcePackage;
+    private final HandlerThread mHandlerThread  = CarServiceUtils.getHandlerThread(
+            getClass().getSimpleName());
+    // Handler to receive PlaybackState callbacks from the active media controller.
+    private final Handler mHandler = new Handler(mHandlerThread.getLooper());
+    private final Object mLock = new Object();
+
+    /** The component name of the last media source that was removed while being primary. */
+    private ComponentName[] mRemovedMediaSourceComponents = new ComponentName[MEDIA_SOURCE_MODES];
 
     private final IntentFilter mPackageUpdateFilter;
     private boolean mIsPackageUpdateReceiverRegistered;
 
     /**
-     * Listens to {@link Intent#ACTION_PACKAGE_REMOVED}, {@link Intent#ACTION_PACKAGE_REPLACED} and
-     * {@link Intent#ACTION_PACKAGE_ADDED} so we can reset the media source to null when its
-     * application is uninstalled, and restore it when the application is reinstalled.
+     * Listens to {@link Intent#ACTION_PACKAGE_REMOVED}, so we can fall back to a previously used
+     * media source when the active source is uninstalled.
      */
     private final BroadcastReceiver mPackageUpdateReceiver = new BroadcastReceiver() {
         @Override
@@ -133,78 +151,113 @@
             }
             String intentPackage = intent.getData().getSchemeSpecificPart();
             if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
-                if (mPrimaryMediaComponent != null
-                        && mPrimaryMediaComponent.getPackageName().equals(intentPackage)) {
-                    mRemovedMediaSourcePackage = intentPackage;
-                    setPrimaryMediaSource(null);
+                synchronized (mLock) {
+                    for (int i = 0; i < MEDIA_SOURCE_MODES; i++) {
+                        if (mPrimaryMediaComponents[i] != null
+                                && mPrimaryMediaComponents[i].getPackageName().equals(
+                                intentPackage)) {
+                            if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                                // If package is being replaced, it may not be removed from
+                                // PackageManager queries  when we check for available
+                                // MediaBrowseServices, so we iterate to find the next available
+                                // source.
+                                for (ComponentName component : getLastMediaSources(i)) {
+                                    if (!mPrimaryMediaComponents[i].getPackageName()
+                                            .equals(component.getPackageName())) {
+                                        mRemovedMediaSourceComponents[i] =
+                                                mPrimaryMediaComponents[i];
+                                        if (Log.isLoggable(CarLog.TAG_MEDIA, Log.DEBUG)) {
+                                            Log.d(CarLog.TAG_MEDIA,
+                                                    "temporarily replacing updated media source "
+                                                            + mPrimaryMediaComponents[i]
+                                                            + "with backup source: "
+                                                            + component);
+                                        }
+                                        setPrimaryMediaSource(component, i);
+                                        return;
+                                    }
+                                }
+                                Log.e(CarLog.TAG_MEDIA, "No available backup media source");
+                            } else {
+                                if (Log.isLoggable(CarLog.TAG_MEDIA, Log.DEBUG)) {
+                                    Log.d(CarLog.TAG_MEDIA, "replacing removed media source "
+                                            + mPrimaryMediaComponents[i] + "with backup source: "
+                                            + getLastMediaSource(i));
+                                }
+                                mRemovedMediaSourceComponents[i] = null;
+                                setPrimaryMediaSource(getLastMediaSource(i), i);
+                            }
+                        }
+                    }
                 }
             } else if (Intent.ACTION_PACKAGE_REPLACED.equals(intent.getAction())
                     || Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
-                if (mRemovedMediaSourcePackage != null
-                        && mRemovedMediaSourcePackage.equals(intentPackage)) {
-                    ComponentName mediaSource = getMediaSource(intentPackage, "");
-                    if (mediaSource != null) {
-                        setPrimaryMediaSource(mediaSource);
+                for (int i = 0; i < MEDIA_SOURCE_MODES; i++) {
+                    if (mRemovedMediaSourceComponents[i] != null && mRemovedMediaSourceComponents[i]
+                            .getPackageName().equals(intentPackage)) {
+                        if (Log.isLoggable(CarLog.TAG_MEDIA, Log.DEBUG)) {
+                            Log.d(CarLog.TAG_MEDIA, "restoring removed source: "
+                                    + mRemovedMediaSourceComponents[i]);
+                        }
+                        setPrimaryMediaSource(mRemovedMediaSourceComponents[i], i);
                     }
                 }
             }
         }
     };
 
-    private final BroadcastReceiver mUserSwitchReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            mCurrentUser = ActivityManager.getCurrentUser();
-            if (Log.isLoggable(CarLog.TAG_MEDIA, Log.DEBUG)) {
-                Log.d(CarLog.TAG_MEDIA, "Switched to user " + mCurrentUser);
-            }
-            maybeInitUser();
+    private final UserLifecycleListener mUserLifecycleListener = event -> {
+        if (Log.isLoggable(CarLog.TAG_MEDIA, Log.DEBUG)) {
+            Log.d(CarLog.TAG_MEDIA, "CarMediaService.onEvent(" + event + ")");
+        }
+        if (CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING == event.getEventType()) {
+            maybeInitUser(event.getUserId());
+        } else if (CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING == event.getEventType()) {
+            onUserUnlock(event.getUserId());
         }
     };
 
-    public CarMediaService(Context context) {
+    public CarMediaService(Context context, CarUserService userService) {
         mContext = context;
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         mMediaSessionManager = mContext.getSystemService(MediaSessionManager.class);
-
-        mHandlerThread = new HandlerThread(CarLog.TAG_MEDIA);
-        mHandlerThread.start();
-        mHandler = new Handler(mHandlerThread.getLooper());
+        mMediaSourceListeners[MEDIA_SOURCE_MODE_PLAYBACK] = new RemoteCallbackList();
+        mMediaSourceListeners[MEDIA_SOURCE_MODE_BROWSE] = new RemoteCallbackList();
+        mIndependentPlaybackConfig = mContext.getResources().getBoolean(
+                R.bool.config_mediaSourceIndependentPlayback);
 
         mPackageUpdateFilter = new IntentFilter();
         mPackageUpdateFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         mPackageUpdateFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
         mPackageUpdateFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
         mPackageUpdateFilter.addDataScheme("package");
-
-        IntentFilter userSwitchFilter = new IntentFilter();
-        userSwitchFilter.addAction(Intent.ACTION_USER_SWITCHED);
-        mContext.registerReceiver(mUserSwitchReceiver, userSwitchFilter);
+        mUserService = userService;
+        mUserService.addUserLifecycleListener(mUserLifecycleListener);
 
         mPlayOnMediaSourceChangedConfig =
                 mContext.getResources().getInteger(R.integer.config_mediaSourceChangedAutoplay);
         mPlayOnBootConfig = mContext.getResources().getInteger(R.integer.config_mediaBootAutoplay);
-        mCurrentUser = ActivityManager.getCurrentUser();
     }
 
     @Override
     // This method is called from ICarImpl after CarMediaService is created.
     public void init() {
-        maybeInitUser();
+        int currentUser = ActivityManager.getCurrentUser();
+        maybeInitUser(currentUser);
     }
 
-    private void maybeInitUser() {
-        if (mCurrentUser == 0) {
+    private void maybeInitUser(int userId) {
+        if (userId == UserHandle.USER_SYSTEM) {
             return;
         }
-        if (mUserManager.isUserUnlocked(mCurrentUser)) {
-            initUser();
+        if (mUserManager.isUserUnlocked(userId)) {
+            initUser(userId);
         } else {
             mPendingInit = true;
         }
     }
 
-    private void initUser() {
+    private void initUser(int userId) {
         // SharedPreferences are shared among different users thus only need initialized once. And
         // they should be initialized after user 0 is unlocked because SharedPreferences in
         // credential encrypted storage are not available until after user 0 is unlocked.
@@ -217,17 +270,20 @@
         if (mIsPackageUpdateReceiverRegistered) {
             mContext.unregisterReceiver(mPackageUpdateReceiver);
         }
-        UserHandle currentUser = new UserHandle(mCurrentUser);
+        UserHandle currentUser = new UserHandle(userId);
         mContext.registerReceiverAsUser(mPackageUpdateReceiver, currentUser,
                 mPackageUpdateFilter, null, null);
         mIsPackageUpdateReceiverRegistered = true;
 
-        mPrimaryMediaComponent =
-                isCurrentUserEphemeral() ? getDefaultMediaSource() : getLastMediaSource();
+        mPrimaryMediaComponents[MEDIA_SOURCE_MODE_PLAYBACK] = isCurrentUserEphemeral()
+                ? getDefaultMediaSource() : getLastMediaSource(MEDIA_SOURCE_MODE_PLAYBACK);
+        mPrimaryMediaComponents[MEDIA_SOURCE_MODE_BROWSE] = isCurrentUserEphemeral()
+                ? getDefaultMediaSource() : getLastMediaSource(MEDIA_SOURCE_MODE_BROWSE);
         mActiveUserMediaController = null;
 
         updateMediaSessionCallbackForCurrentUser();
-        notifyListeners();
+        notifyListeners(MEDIA_SOURCE_MODE_PLAYBACK);
+        notifyListeners(MEDIA_SOURCE_MODE_BROWSE);
 
         startMediaConnectorService(shouldStartPlayback(mPlayOnBootConfig), currentUser);
     }
@@ -264,98 +320,137 @@
     }
 
     private boolean isCurrentUserEphemeral() {
-        return mUserManager.getUserInfo(mCurrentUser).isEphemeral();
+        return mUserManager.getUserInfo(ActivityManager.getCurrentUser()).isEphemeral();
     }
 
     @Override
     public void release() {
         mMediaSessionUpdater.unregisterCallbacks();
+        mUserService.removeUserLifecycleListener(mUserLifecycleListener);
     }
 
     @Override
     public void dump(PrintWriter writer) {
         writer.println("*CarMediaService*");
-        writer.println("\tCurrent media component: " + (mPrimaryMediaComponent == null ? "-"
-                : mPrimaryMediaComponent.flattenToString()));
-        writer.println("\tPrevious media component: " + (mPreviousMediaComponent == null ? "-"
-                : mPreviousMediaComponent.flattenToString()));
+        writer.println("\tCurrent playback media component: "
+                + (mPrimaryMediaComponents[MEDIA_SOURCE_MODE_PLAYBACK] == null ? "-"
+                : mPrimaryMediaComponents[MEDIA_SOURCE_MODE_PLAYBACK].flattenToString()));
+        writer.println("\tCurrent browse media component: "
+                + (mPrimaryMediaComponents[MEDIA_SOURCE_MODE_BROWSE] == null ? "-"
+                : mPrimaryMediaComponents[MEDIA_SOURCE_MODE_BROWSE].flattenToString()));
         if (mActiveUserMediaController != null) {
             writer.println(
                     "\tCurrent media controller: " + mActiveUserMediaController.getPackageName());
             writer.println(
                     "\tCurrent browse service extra: " + getClassName(mActiveUserMediaController));
         }
-        writer.println("\tNumber of active media sessions: "
-                + mMediaSessionManager.getActiveSessionsForUser(null,
-                ActivityManager.getCurrentUser()).size());
+        writer.println("\tNumber of active media sessions: " + mMediaSessionManager
+                .getActiveSessionsForUser(null, ActivityManager.getCurrentUser()).size());
+
+        writer.println("\tPlayback media source history: ");
+        for (ComponentName name : getLastMediaSources(MEDIA_SOURCE_MODE_PLAYBACK)) {
+            writer.println("\t" + name.flattenToString());
+        }
+        writer.println("\tBrowse media source history: ");
+        for (ComponentName name : getLastMediaSources(MEDIA_SOURCE_MODE_BROWSE)) {
+            writer.println("\t" + name.flattenToString());
+        }
+
     }
 
     /**
      * @see {@link CarMediaManager#setMediaSource(ComponentName)}
      */
     @Override
-    public synchronized void setMediaSource(@NonNull ComponentName componentName) {
+    public void setMediaSource(@NonNull ComponentName componentName,
+            @MediaSourceMode int mode) {
         ICarImpl.assertPermission(mContext, android.Manifest.permission.MEDIA_CONTENT_CONTROL);
         if (Log.isLoggable(CarLog.TAG_MEDIA, Log.DEBUG)) {
             Log.d(CarLog.TAG_MEDIA, "Changing media source to: " + componentName.getPackageName());
         }
-        setPrimaryMediaSource(componentName);
+        setPrimaryMediaSource(componentName, mode);
     }
 
     /**
      * @see {@link CarMediaManager#getMediaSource()}
      */
     @Override
-    public synchronized ComponentName getMediaSource() {
+    public ComponentName getMediaSource(@CarMediaManager.MediaSourceMode int mode) {
         ICarImpl.assertPermission(mContext, android.Manifest.permission.MEDIA_CONTENT_CONTROL);
-        return mPrimaryMediaComponent;
+        synchronized (mLock) {
+            return mPrimaryMediaComponents[mode];
+        }
     }
 
     /**
      * @see {@link CarMediaManager#registerMediaSourceListener(MediaSourceChangedListener)}
      */
     @Override
-    public synchronized void registerMediaSourceListener(ICarMediaSourceListener callback) {
+    public void registerMediaSourceListener(ICarMediaSourceListener callback,
+            @MediaSourceMode int mode) {
         ICarImpl.assertPermission(mContext, android.Manifest.permission.MEDIA_CONTENT_CONTROL);
-        mMediaSourceListeners.register(callback);
+        synchronized (mLock) {
+            mMediaSourceListeners[mode].register(callback);
+        }
     }
 
     /**
      * @see {@link CarMediaManager#unregisterMediaSourceListener(ICarMediaSourceListener)}
      */
     @Override
-    public synchronized void unregisterMediaSourceListener(ICarMediaSourceListener callback) {
+    public void unregisterMediaSourceListener(ICarMediaSourceListener callback,
+            @MediaSourceMode int mode) {
         ICarImpl.assertPermission(mContext, android.Manifest.permission.MEDIA_CONTENT_CONTROL);
-        mMediaSourceListeners.unregister(callback);
+        synchronized (mLock) {
+            mMediaSourceListeners[mode].unregister(callback);
+        }
     }
 
-    /**
-     * Sets user lock / unlocking status on main thread. This is coming from system server through
-     * ICar binder call.
-     *
-     * @param userHandle Handle of user
-     * @param unlocked   unlocked (=true) or locked (=false)
-     */
-    public void setUserLockStatus(int userHandle, boolean unlocked) {
-        mMainHandler.post(new Runnable() {
-            @Override
-            public void run() {
+    @Override
+    public List<ComponentName> getLastMediaSources(@CarMediaManager.MediaSourceMode int mode) {
+        String key = getMediaSourceKey(mode);
+        String serialized = mSharedPrefs.getString(key, null);
+        return getComponentNameList(serialized).stream()
+                .map(name -> ComponentName.unflattenFromString(name)).collect(Collectors.toList());
+    }
+
+    /** See {@link CarMediaManager#isIndependentPlaybackConfig}. */
+    @Override
+    @TestApi
+    public boolean isIndependentPlaybackConfig() {
+        ICarImpl.assertPermission(mContext, android.Manifest.permission.MEDIA_CONTENT_CONTROL);
+        synchronized (mLock) {
+            return mIndependentPlaybackConfig;
+        }
+    }
+
+    /** See {@link CarMediaManager#setIndependentPlaybackConfig}. */
+    @Override
+    @TestApi
+    public void setIndependentPlaybackConfig(boolean independent) {
+        ICarImpl.assertPermission(mContext, android.Manifest.permission.MEDIA_CONTENT_CONTROL);
+        synchronized (mLock) {
+            mIndependentPlaybackConfig = independent;
+        }
+    }
+
+    // TODO(b/153115826): this method was used to be called from the ICar binder thread, but it's
+    // now called by UserCarService. Currently UserCarServie is calling every listener in one
+    // non-main thread, but it's not clear how the final behavior will be. So, for now it's ok
+    // to post it to mMainHandler, but once b/145689885 is fixed, we might not need it.
+    private void onUserUnlock(int userId) {
+        mMainHandler.post(() -> {
+            // No need to handle system user, non current foreground user.
+            if (userId == UserHandle.USER_SYSTEM
+                    || userId != ActivityManager.getCurrentUser()) {
+                return;
+            }
+            if (mPendingInit) {
+                initUser(userId);
+                mPendingInit = false;
                 if (Log.isLoggable(CarLog.TAG_MEDIA, Log.DEBUG)) {
                     Log.d(CarLog.TAG_MEDIA,
-                            "User " + userHandle + " is " + (unlocked ? "unlocked" : "locked"));
-                }
-                // Nothing else to do when it is locked back.
-                if (!unlocked) {
-                    return;
-                }
-                // No need to handle user0, non current foreground user.
-                if (userHandle == UserHandle.USER_SYSTEM
-                        || userHandle != ActivityManager.getCurrentUser()) {
-                    return;
-                }
-                if (mPendingInit) {
-                    initUser();
-                    mPendingInit = false;
+                            "User " + userId + " is now unlocked");
                 }
             }
         });
@@ -373,24 +468,6 @@
     }
 
     /**
-     * Attempts to play the current source using MediaController.TransportControls.play()
-     */
-    private void play() {
-        if (mActiveUserMediaController != null) {
-            if (Log.isLoggable(CarLog.TAG_MEDIA, Log.DEBUG)) {
-                Log.d(CarLog.TAG_MEDIA, "playing " + mActiveUserMediaController.getPackageName());
-            }
-            TransportControls controls = mActiveUserMediaController.getTransportControls();
-            if (controls != null) {
-                controls.play();
-            } else {
-                Log.e(CarLog.TAG_MEDIA, "Can't start playback, transport controls unavailable "
-                        + mActiveUserMediaController.getPackageName());
-            }
-        }
-    }
-
-    /**
      * Attempts to stop the current source using MediaController.TransportControls.stop()
      * This method also unregisters callbacks to the active media controller before calling stop(),
      * to preserve the PlaybackState before stopping.
@@ -453,12 +530,13 @@
                     && state.getState() != mPreviousPlaybackState) {
                 ComponentName mediaSource = getMediaSource(mMediaController.getPackageName(),
                         getClassName(mMediaController));
-                if (mediaSource != null && !mediaSource.equals(mPrimaryMediaComponent)
+                if (mediaSource != null
+                        && !mediaSource.equals(mPrimaryMediaComponents[MEDIA_SOURCE_MODE_PLAYBACK])
                         && Log.isLoggable(CarLog.TAG_MEDIA, Log.INFO)) {
                     Log.i(CarLog.TAG_MEDIA, "Changing media source due to playback state change: "
                             + mediaSource.flattenToString());
                 }
-                setPrimaryMediaSource(mediaSource);
+                setPrimaryMediaSource(mediaSource, MEDIA_SOURCE_MODE_PLAYBACK);
             }
             mPreviousPlaybackState = state.getState();
         }
@@ -519,30 +597,50 @@
 
     /**
      * Updates the primary media source, then notifies content observers of the change
+     * Will update both the playback and browse sources if independent playback is not supported
      */
-    private synchronized void setPrimaryMediaSource(@Nullable ComponentName componentName) {
-        if (mPrimaryMediaComponent != null && mPrimaryMediaComponent.equals((componentName))) {
-            return;
+    private void setPrimaryMediaSource(@NonNull ComponentName componentName,
+            @CarMediaManager.MediaSourceMode int mode) {
+        synchronized (mLock) {
+            if (mPrimaryMediaComponents[mode] != null
+                    && mPrimaryMediaComponents[mode].equals((componentName))) {
+                return;
+            }
         }
 
+        if (!mIndependentPlaybackConfig) {
+            setPlaybackMediaSource(componentName);
+            setBrowseMediaSource(componentName);
+        } else if (mode == MEDIA_SOURCE_MODE_PLAYBACK) {
+            setPlaybackMediaSource(componentName);
+        } else if (mode == MEDIA_SOURCE_MODE_BROWSE) {
+            setBrowseMediaSource(componentName);
+        }
+    }
+
+    private void setPlaybackMediaSource(ComponentName playbackMediaSource) {
         stopAndUnregisterCallback();
 
         mActiveUserMediaController = null;
-        mPreviousMediaComponent = mPrimaryMediaComponent;
-        mPrimaryMediaComponent = componentName;
-
-        if (mPrimaryMediaComponent != null && !TextUtils.isEmpty(
-                mPrimaryMediaComponent.flattenToString())) {
-            if (!isCurrentUserEphemeral()) {
-                saveLastMediaSource(mPrimaryMediaComponent);
-            }
-            mRemovedMediaSourcePackage = null;
+        synchronized (mLock) {
+            mPrimaryMediaComponents[MEDIA_SOURCE_MODE_PLAYBACK] = playbackMediaSource;
         }
 
-        notifyListeners();
+        if (playbackMediaSource != null
+                && !TextUtils.isEmpty(playbackMediaSource.flattenToString())) {
+            if (!isCurrentUserEphemeral()) {
+                saveLastMediaSource(playbackMediaSource, MEDIA_SOURCE_MODE_PLAYBACK);
+            }
+            if (playbackMediaSource
+                    .equals(mRemovedMediaSourceComponents[MEDIA_SOURCE_MODE_PLAYBACK])) {
+                mRemovedMediaSourceComponents[MEDIA_SOURCE_MODE_PLAYBACK] = null;
+            }
+        }
+
+        notifyListeners(MEDIA_SOURCE_MODE_PLAYBACK);
 
         startMediaConnectorService(shouldStartPlayback(mPlayOnMediaSourceChangedConfig),
-                new UserHandle(mCurrentUser));
+                new UserHandle(ActivityManager.getCurrentUser()));
         // Reset current playback state for the new source, in the case that the app is in an error
         // state (e.g. not signed in). This state will be updated from the app callback registered
         // below, to make sure mCurrentPlaybackState reflects the current source only.
@@ -551,17 +649,38 @@
                 .getActiveSessionsForUser(null, ActivityManager.getCurrentUser()));
     }
 
-    private void notifyListeners() {
-        int i = mMediaSourceListeners.beginBroadcast();
-        while (i-- > 0) {
-            try {
-                ICarMediaSourceListener callback = mMediaSourceListeners.getBroadcastItem(i);
-                callback.onMediaSourceChanged(mPrimaryMediaComponent);
-            } catch (RemoteException e) {
-                Log.e(CarLog.TAG_MEDIA, "calling onMediaSourceChanged failed " + e);
+    private void setBrowseMediaSource(ComponentName browseMediaSource) {
+        synchronized (mLock) {
+            mPrimaryMediaComponents[MEDIA_SOURCE_MODE_BROWSE] = browseMediaSource;
+        }
+
+        if (browseMediaSource != null && !TextUtils.isEmpty(browseMediaSource.flattenToString())) {
+            if (!isCurrentUserEphemeral()) {
+                saveLastMediaSource(browseMediaSource, MEDIA_SOURCE_MODE_BROWSE);
+            }
+            if (browseMediaSource
+                    .equals(mRemovedMediaSourceComponents[MEDIA_SOURCE_MODE_BROWSE])) {
+                mRemovedMediaSourceComponents[MEDIA_SOURCE_MODE_BROWSE] = null;
             }
         }
-        mMediaSourceListeners.finishBroadcast();
+
+        notifyListeners(MEDIA_SOURCE_MODE_BROWSE);
+    }
+
+    private void notifyListeners(@CarMediaManager.MediaSourceMode int mode) {
+        synchronized (mLock) {
+            int i = mMediaSourceListeners[mode].beginBroadcast();
+            while (i-- > 0) {
+                try {
+                    ICarMediaSourceListener callback =
+                            mMediaSourceListeners[mode].getBroadcastItem(i);
+                    callback.onMediaSourceChanged(mPrimaryMediaComponents[mode]);
+                } catch (RemoteException e) {
+                    Log.e(CarLog.TAG_MEDIA, "calling onMediaSourceChanged failed " + e);
+                }
+            }
+            mMediaSourceListeners[mode].finishBroadcast();
+        }
     }
 
     private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
@@ -577,14 +696,15 @@
      * Finds the currently playing media source, then updates the active source if the component
      * name is different.
      */
-    private synchronized void updatePrimaryMediaSourceWithCurrentlyPlaying(
+    private void updatePrimaryMediaSourceWithCurrentlyPlaying(
             List<MediaController> controllers) {
         for (MediaController controller : controllers) {
             if (controller.getPlaybackState() != null
                     && controller.getPlaybackState().getState() == PlaybackState.STATE_PLAYING) {
                 String newPackageName = controller.getPackageName();
                 String newClassName = getClassName(controller);
-                if (!matchPrimaryMediaSource(newPackageName, newClassName)) {
+                if (!matchPrimaryMediaSource(newPackageName, newClassName,
+                        MEDIA_SOURCE_MODE_PLAYBACK)) {
                     ComponentName mediaSource = getMediaSource(newPackageName, newClassName);
                     if (Log.isLoggable(CarLog.TAG_MEDIA, Log.INFO)) {
                         if (mediaSource != null) {
@@ -600,7 +720,7 @@
                                             + "in package: " + newPackageName);
                         }
                     }
-                    setPrimaryMediaSource(mediaSource);
+                    setPrimaryMediaSource(mediaSource, MEDIA_SOURCE_MODE_PLAYBACK);
                 }
                 return;
             }
@@ -608,21 +728,27 @@
     }
 
     private boolean matchPrimaryMediaSource(@NonNull String newPackageName,
-            @NonNull String newClassName) {
-        if (mPrimaryMediaComponent != null && mPrimaryMediaComponent.getPackageName().equals(
-                newPackageName)) {
-            // If the class name of currently active source is not specified, only checks package
-            // name; otherwise checks both package name and class name.
-            if (TextUtils.isEmpty(newClassName)) {
-                return true;
-            } else {
-                return newClassName.equals(mPrimaryMediaComponent.getClassName());
+            @NonNull String newClassName, @CarMediaManager.MediaSourceMode int mode) {
+        synchronized (mLock) {
+            if (mPrimaryMediaComponents[mode] != null
+                    && mPrimaryMediaComponents[mode].getPackageName().equals(newPackageName)) {
+                // If the class name of currently active source is not specified, only checks
+                // package name; otherwise checks both package name and class name.
+                if (TextUtils.isEmpty(newClassName)) {
+                    return true;
+                } else {
+                    return newClassName.equals(mPrimaryMediaComponents[mode].getClassName());
+                }
             }
         }
         return false;
     }
 
-    private boolean isMediaService(@NonNull ComponentName componentName) {
+    /**
+     * Returns {@code true} if the provided component has a valid {@link MediaBrowseService}.
+     */
+    @VisibleForTesting
+    public boolean isMediaService(@NonNull ComponentName componentName) {
         return getMediaService(componentName) != null;
     }
 
@@ -668,27 +794,26 @@
         return getMediaService(new ComponentName(packageName, className));
     }
 
-    private void saveLastMediaSource(@NonNull ComponentName component) {
+    private void saveLastMediaSource(@NonNull ComponentName component, int mode) {
         if (!sharedPrefsInitialized()) {
             return;
         }
         String componentName = component.flattenToString();
-        String key = SOURCE_KEY + mCurrentUser;
+        String key = getMediaSourceKey(mode);
         String serialized = mSharedPrefs.getString(key, null);
         if (serialized == null) {
             mSharedPrefs.edit().putString(key, componentName).apply();
         } else {
-            Deque<String> componentNames = getComponentNameList(serialized);
+            Deque<String> componentNames = new ArrayDeque<>(getComponentNameList(serialized));
             componentNames.remove(componentName);
             componentNames.addFirst(componentName);
-            mSharedPrefs.edit().putString(key, serializeComponentNameList(componentNames))
-                    .apply();
+            mSharedPrefs.edit().putString(key, serializeComponentNameList(componentNames)).apply();
         }
     }
 
-    private ComponentName getLastMediaSource() {
+    private @NonNull ComponentName getLastMediaSource(int mode) {
         if (sharedPrefsInitialized()) {
-            String key = SOURCE_KEY + mCurrentUser;
+            String key = getMediaSourceKey(mode);
             String serialized = mSharedPrefs.getString(key, null);
             if (!TextUtils.isEmpty(serialized)) {
                 for (String name : getComponentNameList(serialized)) {
@@ -703,7 +828,7 @@
     }
 
     private ComponentName getDefaultMediaSource() {
-        String defaultMediaSource = mContext.getString(R.string.default_media_source);
+        String defaultMediaSource = mContext.getString(R.string.config_defaultMediaSource);
         ComponentName defaultComponent = ComponentName.unflattenFromString(defaultMediaSource);
         if (isMediaService(defaultComponent)) {
             return defaultComponent;
@@ -715,9 +840,9 @@
         return componentNames.stream().collect(Collectors.joining(COMPONENT_NAME_SEPARATOR));
     }
 
-    private Deque<String> getComponentNameList(String serialized) {
+    private List<String> getComponentNameList(String serialized) {
         String[] componentNames = serialized.split(COMPONENT_NAME_SEPARATOR);
-        return new ArrayDeque(Arrays.asList(componentNames));
+        return (Arrays.asList(componentNames));
     }
 
     private void savePlaybackState(PlaybackState playbackState) {
@@ -734,8 +859,15 @@
      * Builds a string key for saving the playback state for a specific media source (and user)
      */
     private String getPlaybackStateKey() {
-        return PLAYBACK_STATE_KEY + mCurrentUser
-                + (mPrimaryMediaComponent == null ? "" : mPrimaryMediaComponent.flattenToString());
+        synchronized (mLock) {
+            return PLAYBACK_STATE_KEY + ActivityManager.getCurrentUser()
+                    + (mPrimaryMediaComponents[MEDIA_SOURCE_MODE_PLAYBACK] == null ? ""
+                    : mPrimaryMediaComponents[MEDIA_SOURCE_MODE_PLAYBACK].flattenToString());
+        }
+    }
+
+    private String getMediaSourceKey(int mode) {
+        return SOURCE_KEY + mode + SOURCE_KEY_SEPARATOR + ActivityManager.getCurrentUser();
     }
 
     /**
@@ -743,7 +875,7 @@
      * media component. Clears callback and resets media controller to null if not found.
      */
     private void updateActiveMediaController(List<MediaController> mediaControllers) {
-        if (mPrimaryMediaComponent == null) {
+        if (mPrimaryMediaComponents[MEDIA_SOURCE_MODE_PLAYBACK] == null) {
             return;
         }
         if (mActiveUserMediaController != null) {
@@ -751,7 +883,8 @@
             mActiveUserMediaController = null;
         }
         for (MediaController controller : mediaControllers) {
-            if (matchPrimaryMediaSource(controller.getPackageName(), getClassName(controller))) {
+            if (matchPrimaryMediaSource(controller.getPackageName(), getClassName(controller),
+                    MEDIA_SOURCE_MODE_PLAYBACK)) {
                 mActiveUserMediaController = controller;
                 PlaybackState state = mActiveUserMediaController.getPlaybackState();
                 if (!isCurrentUserEphemeral()) {
@@ -788,7 +921,6 @@
                 Log.e(CarLog.TAG_MEDIA, "Unsupported playback configuration: " + config);
                 return false;
         }
-
     }
 
     @NonNull
diff --git a/service/src/com/android/car/CarNightService.java b/service/src/com/android/car/CarNightService.java
index dcf75b5..754c675 100644
--- a/service/src/com/android/car/CarNightService.java
+++ b/service/src/com/android/car/CarNightService.java
@@ -26,11 +26,16 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
 
+/**
+ * Class used to handle events used to set vehicle in night mode.
+ */
 public class CarNightService implements CarServiceBase {
 
     public static final boolean DBG = false;
@@ -43,80 +48,109 @@
     public static final int FORCED_DAY_MODE = 1;
     public static final int FORCED_NIGHT_MODE = 2;
 
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
     private int mNightSetting = UiModeManager.MODE_NIGHT_YES;
+    @GuardedBy("mLock")
     private int mForcedMode = FORCED_SENSOR_MODE;
+    @GuardedBy("mLock")
+    private long mLastSensorEventTime = -1;
     private final Context mContext;
+    @GuardedBy("mLock")
     private final UiModeManager mUiModeManager;
-    private CarPropertyService mCarPropertyService;
+    private final CarPropertyService mCarPropertyService;
 
     private final ICarPropertyEventListener mICarPropertyEventListener =
             new ICarPropertyEventListener.Stub() {
-        @Override
-        public void onEvent(List<CarPropertyEvent> events) throws RemoteException {
-            for (CarPropertyEvent event : events) {
-                handlePropertyEvent(event);
-            }
-        }
-    };
+                @Override
+                public void onEvent(List<CarPropertyEvent> events) throws RemoteException {
+                    synchronized (mLock) {
+                        for (CarPropertyEvent event : events) {
+                            onNightModeCarPropertyEventLocked(event);
+                        }
+                    }
+                }
+            };
 
     /**
-     * Handle CarPropertyEvents
-     * @param event
+     * Acts on {@link CarPropertyEvent} events marked with
+     * {@link CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE} and marked with {@link
+     * VehicleProperty.NIGHT_MODE} by
+     * setting the vehicle in night mode.
+     * <p>
+     * This method does nothing if the event parameter is {@code null}.
+     *
+     * @param event the car property event to be handled
      */
-    public synchronized void handlePropertyEvent(CarPropertyEvent event) {
+    @GuardedBy("mLock")
+    private void onNightModeCarPropertyEventLocked(CarPropertyEvent event) {
         if (event == null) {
             return;
         }
         if (event.getEventType() == CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE) {
             // Only handle onChange events
             CarPropertyValue value = event.getCarPropertyValue();
-            if (value.getPropertyId() == VehicleProperty.NIGHT_MODE) {
+            if (value.getPropertyId() == VehicleProperty.NIGHT_MODE
+                    && value.getTimestamp() > mLastSensorEventTime) {
+                mLastSensorEventTime = value.getTimestamp();
                 boolean nightMode = (Boolean) value.getValue();
-                setNightMode(nightMode);
+                Log.i(CarLog.TAG_SENSOR, "Set dayNight Mode as "
+                        + nightMode + " at timestamp: " + mLastSensorEventTime);
+                setNightModeLocked(nightMode);
             }
         }
     }
 
-    private synchronized void setNightMode(boolean nightMode) {
+    @GuardedBy("mLock")
+    private void setNightModeLocked(boolean nightMode) {
         if (nightMode) {
             mNightSetting = UiModeManager.MODE_NIGHT_YES;
-            if (DBG)  Log.d(CarLog.TAG_SENSOR, "CAR dayNight handleSensorEvent NIGHT");
+            if (DBG) Log.d(CarLog.TAG_SENSOR, "CAR dayNight handleSensorEvent NIGHT");
         } else {
             mNightSetting = UiModeManager.MODE_NIGHT_NO;
-            if (DBG)  Log.d(CarLog.TAG_SENSOR, "CAR dayNight handleSensorEvent DAY");
+            if (DBG) Log.d(CarLog.TAG_SENSOR, "CAR dayNight handleSensorEvent DAY");
         }
         if (mUiModeManager != null && (mForcedMode == FORCED_SENSOR_MODE)) {
             mUiModeManager.setNightMode(mNightSetting);
-            if (DBG)  Log.d(CarLog.TAG_SENSOR, "CAR dayNight handleSensorEvent APPLIED");
+            if (DBG) Log.d(CarLog.TAG_SENSOR, "CAR dayNight handleSensorEvent APPLIED");
         } else {
-            if (DBG)  Log.d(CarLog.TAG_SENSOR, "CAR dayNight handleSensorEvent IGNORED");
+            if (DBG) Log.d(CarLog.TAG_SENSOR, "CAR dayNight handleSensorEvent IGNORED");
         }
     }
 
-    public synchronized int forceDayNightMode(@DayNightSensorMode int mode) {
-        if (mUiModeManager == null) {
-            return -1;
-        }
-        int resultMode;
-        switch (mode) {
-            case FORCED_SENSOR_MODE:
-                resultMode = mNightSetting;
-                mForcedMode = FORCED_SENSOR_MODE;
-                break;
-            case FORCED_DAY_MODE:
-                resultMode = UiModeManager.MODE_NIGHT_NO;
-                mForcedMode = FORCED_DAY_MODE;
-                break;
-            case FORCED_NIGHT_MODE:
-                resultMode = UiModeManager.MODE_NIGHT_YES;
-                mForcedMode = FORCED_NIGHT_MODE;
-                break;
-            default:
-                Log.e(CarLog.TAG_SENSOR, "Unknown forced day/night mode " + mode);
+    /**
+     * Sets {@link UiModeManager} to night mode according to the {@link DayNightSensorMode} passed
+     * as parameter.
+     *
+     * @param mode the sensor mode used to set vehicle in night mode
+     * @return the current night mode, or {@code -1} on error
+     */
+    public int forceDayNightMode(@DayNightSensorMode int mode) {
+        synchronized (mLock) {
+            if (mUiModeManager == null) {
                 return -1;
+            }
+            int resultMode;
+            switch (mode) {
+                case FORCED_SENSOR_MODE:
+                    resultMode = mNightSetting;
+                    mForcedMode = FORCED_SENSOR_MODE;
+                    break;
+                case FORCED_DAY_MODE:
+                    resultMode = UiModeManager.MODE_NIGHT_NO;
+                    mForcedMode = FORCED_DAY_MODE;
+                    break;
+                case FORCED_NIGHT_MODE:
+                    resultMode = UiModeManager.MODE_NIGHT_YES;
+                    mForcedMode = FORCED_NIGHT_MODE;
+                    break;
+                default:
+                    Log.e(CarLog.TAG_SENSOR, "Unknown forced day/night mode " + mode);
+                    return -1;
+            }
+            mUiModeManager.setNightMode(resultMode);
+            return mUiModeManager.getNightMode();
         }
-        mUiModeManager.setNightMode(resultMode);
-        return mUiModeManager.getNightMode();
     }
 
     CarNightService(Context context, CarPropertyService propertyService) {
@@ -129,33 +163,39 @@
     }
 
     @Override
-    public synchronized void init() {
+    public void init() {
         if (DBG) {
-            Log.d(CarLog.TAG_SENSOR,"CAR dayNight init.");
+            Log.d(CarLog.TAG_SENSOR, "CAR dayNight init.");
         }
-        mCarPropertyService.registerListener(VehicleProperty.NIGHT_MODE, 0,
-                mICarPropertyEventListener);
-        CarPropertyValue propertyValue = mCarPropertyService.getProperty(
-                VehicleProperty.NIGHT_MODE, 0);
-        if (propertyValue != null && propertyValue.getTimestamp() != 0) {
-            setNightMode((Boolean) propertyValue.getValue());
-        } else {
-            Log.w(CarLog.TAG_SENSOR, "Failed to get value of NIGHT_MODE");
-            // Initial in Night Mode
-            setNightMode(true);
+        synchronized (mLock) {
+            mCarPropertyService.registerListener(VehicleProperty.NIGHT_MODE, 0,
+                    mICarPropertyEventListener);
+            CarPropertyValue propertyValue = mCarPropertyService.getProperty(
+                    VehicleProperty.NIGHT_MODE, 0);
+            if (propertyValue != null && propertyValue.getTimestamp() != 0) {
+                mLastSensorEventTime = propertyValue.getTimestamp();
+                setNightModeLocked((Boolean) propertyValue.getValue());
+            } else {
+                Log.w(CarLog.TAG_SENSOR, "Failed to get value of NIGHT_MODE");
+                setNightModeLocked(true);
+            }
         }
     }
 
     @Override
-    public synchronized void release() {
+    public void release() {
     }
 
     @Override
-    public synchronized void dump(PrintWriter writer) {
-        writer.println("*DAY NIGHT POLICY*");
-        writer.println("Mode:" +
-                ((mNightSetting == UiModeManager.MODE_NIGHT_YES) ? "night" : "day"));
-        writer.println("Forced Mode? " + (mForcedMode == FORCED_SENSOR_MODE ? "false"
-                : (mForcedMode == FORCED_DAY_MODE ? "day" : "night")));
+    public void dump(PrintWriter writer) {
+        synchronized (mLock) {
+            writer.println("*DAY NIGHT POLICY*");
+            writer.println(
+                    "Mode:" + ((mNightSetting == UiModeManager.MODE_NIGHT_YES) ? "night" : "day"));
+            writer.println("Forced Mode? " + (mForcedMode == FORCED_SENSOR_MODE
+                    ? "false, timestamp of dayNight sensor is: " + mLastSensorEventTime
+                    : (mForcedMode == FORCED_DAY_MODE ? "day" : "night")));
+        }
     }
 }
+
diff --git a/service/src/com/android/car/CarOccupantZoneService.java b/service/src/com/android/car/CarOccupantZoneService.java
new file mode 100644
index 0000000..261235b
--- /dev/null
+++ b/service/src/com/android/car/CarOccupantZoneService.java
@@ -0,0 +1,1165 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.car.Car;
+import android.car.CarInfoManager;
+import android.car.CarOccupantZoneManager;
+import android.car.CarOccupantZoneManager.OccupantTypeEnum;
+import android.car.CarOccupantZoneManager.OccupantZoneInfo;
+import android.car.ICarOccupantZone;
+import android.car.ICarOccupantZoneCallback;
+import android.car.VehicleAreaSeat;
+import android.car.media.CarAudioManager;
+import android.car.user.CarUserManager;
+import android.car.user.CarUserManager.UserLifecycleListener;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.IntArray;
+import android.util.Log;
+import android.util.SparseIntArray;
+import android.view.Display;
+import android.view.DisplayAddress;
+
+import com.android.car.user.CarUserService;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.car.ICarServiceHelper;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Service to implement CarOccupantZoneManager API.
+ */
+public final class CarOccupantZoneService extends ICarOccupantZone.Stub
+        implements CarServiceBase {
+
+    private static final String TAG = CarLog.TAG_OCCUPANT;
+    private static final String ALL_COMPONENTS = "*";
+
+    private final Object mLock = new Object();
+    private final Context mContext;
+    private final DisplayManager mDisplayManager;
+    private final UserManager mUserManager;
+
+    private final boolean mEnableProfileUserAssignmentForMultiDisplay;
+
+    private boolean mEnableSourcePreferred;
+    private ArrayList<ComponentName> mSourcePreferredComponents;
+
+    /**
+     * Stores android user id of profile users for the current user.
+     */
+    @GuardedBy("mLock")
+    private final ArraySet<Integer> mProfileUsers = new ArraySet<>();
+
+    /** key: zone id */
+    @GuardedBy("mLock")
+    private final HashMap<Integer, OccupantZoneInfo> mOccupantsConfig = new HashMap<>();
+
+    @VisibleForTesting
+    static class DisplayConfig {
+        public final int displayType;
+        public final int occupantZoneId;
+
+        DisplayConfig(int displayType, int occupantZoneId) {
+            this.displayType = displayType;
+            this.occupantZoneId = occupantZoneId;
+        }
+
+        @Override
+        public String toString() {
+            // do not include type as this is only used for dump
+            StringBuilder b = new StringBuilder(64);
+            b.append("{displayType=");
+            b.append(Integer.toHexString(displayType));
+            b.append(" occupantZoneId=");
+            b.append(occupantZoneId);
+            b.append("}");
+            return b.toString();
+        }
+    }
+
+    /** key: display port address */
+    @GuardedBy("mLock")
+    private final HashMap<Integer, DisplayConfig> mDisplayConfigs = new HashMap<>();
+
+    /** key: audio zone id */
+    @GuardedBy("mLock")
+    private final SparseIntArray mAudioZoneIdToOccupantZoneIdMapping = new SparseIntArray();
+
+    @VisibleForTesting
+    static class DisplayInfo {
+        public final Display display;
+        public final int displayType;
+
+        DisplayInfo(Display display, int displayType) {
+            this.display = display;
+            this.displayType = displayType;
+        }
+
+        @Override
+        public String toString() {
+            // do not include type as this is only used for dump
+            StringBuilder b = new StringBuilder(64);
+            b.append("{displayId=");
+            b.append(display.getDisplayId());
+            b.append(" displayType=");
+            b.append(displayType);
+            b.append("}");
+            return b.toString();
+        }
+    }
+
+    @VisibleForTesting
+    static class OccupantConfig {
+        public int userId = UserHandle.USER_NULL;
+        public final ArrayList<DisplayInfo> displayInfos = new ArrayList<>();
+        public int audioZoneId = CarAudioManager.INVALID_AUDIO_ZONE;
+
+        @Override
+        public String toString() {
+            // do not include type as this is only used for dump
+            StringBuilder b = new StringBuilder(128);
+            b.append("{userId=");
+            b.append(userId);
+            b.append(" displays=");
+            for (int i = 0; i < displayInfos.size(); i++) {
+                b.append(displayInfos.get(i).toString());
+            }
+            b.append(" audioZoneId=");
+            if (audioZoneId != CarAudioManager.INVALID_AUDIO_ZONE) {
+                b.append(audioZoneId);
+            } else {
+                b.append("none");
+            }
+            b.append("}");
+            return b.toString();
+        }
+    }
+
+    /** key : zoneId */
+    @GuardedBy("mLock")
+    private final HashMap<Integer, OccupantConfig> mActiveOccupantConfigs = new HashMap<>();
+
+    @GuardedBy("mLock")
+    private ICarServiceHelper mICarServiceHelper;
+
+    @GuardedBy("mLock")
+    private int mDriverZoneId = OccupantZoneInfo.INVALID_ZONE_ID;
+
+    @VisibleForTesting
+    final UserLifecycleListener mUserLifecycleListener = event -> {
+        if (Log.isLoggable(CarLog.TAG_MEDIA, Log.DEBUG)) {
+            Log.d(CarLog.TAG_MEDIA, "onEvent(" + event + ")");
+        }
+        if (CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING == event.getEventType()) {
+            handleUserChange();
+        }
+    };
+
+    final CarUserService.PassengerCallback mPassengerCallback =
+            new CarUserService.PassengerCallback() {
+                @Override
+                public void onPassengerStarted(@UserIdInt int passengerId, int zoneId) {
+                    handlePassengerStarted(passengerId, zoneId);
+                }
+
+                @Override
+                public void onPassengerStopped(@UserIdInt int passengerId) {
+                    handlePassengerStopped(passengerId);
+                }
+            };
+
+    @VisibleForTesting
+    final DisplayManager.DisplayListener mDisplayListener =
+            new DisplayManager.DisplayListener() {
+                @Override
+                public void onDisplayAdded(int displayId) {
+                    handleDisplayChange();
+                }
+
+                @Override
+                public void onDisplayRemoved(int displayId) {
+                    handleDisplayChange();
+                }
+
+                @Override
+                public void onDisplayChanged(int displayId) {
+                    // nothing to do
+                }
+            };
+
+    private final RemoteCallbackList<ICarOccupantZoneCallback> mClientCallbacks =
+            new RemoteCallbackList<>();
+
+    @GuardedBy("mLock")
+    private int mDriverSeat = VehicleAreaSeat.SEAT_UNKNOWN;
+
+    public CarOccupantZoneService(Context context) {
+        this(context, context.getSystemService(DisplayManager.class),
+                context.getSystemService(UserManager.class),
+                context.getResources().getBoolean(
+                        R.bool.enableProfileUserAssignmentForMultiDisplay)
+                        && context.getPackageManager().hasSystemFeature(
+                        PackageManager.FEATURE_MANAGED_USERS));
+    }
+
+    @VisibleForTesting
+    public CarOccupantZoneService(Context context, DisplayManager displayManager,
+            UserManager userManager, boolean enableProfileUserAssignmentForMultiDisplay) {
+        mContext = context;
+        mDisplayManager = displayManager;
+        mUserManager = userManager;
+        mEnableProfileUserAssignmentForMultiDisplay = enableProfileUserAssignmentForMultiDisplay;
+    }
+
+    @Override
+    public void init() {
+        // This does not require connection as binder will be passed directly.
+        Car car = new Car(mContext, /* service= */null, /* handler= */ null);
+        CarInfoManager infoManager = new CarInfoManager(car, CarLocalServices.getService(
+                CarPropertyService.class));
+        int driverSeat = infoManager.getDriverSeat();
+        synchronized (mLock) {
+            mDriverSeat = driverSeat;
+            parseOccupantZoneConfigsLocked();
+            parseDisplayConfigsLocked();
+            handleActiveDisplaysLocked();
+            handleAudioZoneChangesLocked();
+            handleUserChangesLocked();
+        }
+        CarUserService userService = CarLocalServices.getService(CarUserService.class);
+        userService.addUserLifecycleListener(mUserLifecycleListener);
+        userService.addPassengerCallback(mPassengerCallback);
+        mDisplayManager.registerDisplayListener(mDisplayListener,
+                new Handler(Looper.getMainLooper()));
+        CarUserService.ZoneUserBindingHelper helper = new CarUserService.ZoneUserBindingHelper() {
+            @Override
+            @NonNull
+            public List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
+                List<OccupantZoneInfo> zones = new ArrayList<OccupantZoneInfo>();
+                for (OccupantZoneInfo ozi : getAllOccupantZones()) {
+                    if (ozi.occupantType == occupantType) {
+                        zones.add(ozi);
+                    }
+                }
+                return zones;
+            }
+
+            @Override
+            public boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
+                // Check if the user is already assigned to the other zone.
+                synchronized (mLock) {
+                    for (Map.Entry<Integer, OccupantConfig> entry :
+                            mActiveOccupantConfigs.entrySet()) {
+                        OccupantConfig config = entry.getValue();
+                        if (config.userId == userId && zoneId != entry.getKey()) {
+                            Log.w(TAG, "cannot assign user to two different zone simultaneously");
+                            return false;
+                        }
+                    }
+                    OccupantConfig zoneConfig = mActiveOccupantConfigs.get(zoneId);
+                    if (zoneConfig == null) {
+                        Log.w(TAG, "cannot find the zone(" + zoneId + ")");
+                        return false;
+                    }
+                    if (zoneConfig.userId != UserHandle.USER_NULL && zoneConfig.userId != userId) {
+                        Log.w(TAG, "other user already occupies the zone(" + zoneId + ")");
+                        return false;
+                    }
+                    zoneConfig.userId = userId;
+                    return true;
+                }
+            }
+
+            @Override
+            public boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
+                synchronized (mLock) {
+                    for (OccupantConfig config : mActiveOccupantConfigs.values()) {
+                        if (config.userId == userId) {
+                            config.userId = UserHandle.USER_NULL;
+                            break;
+                        }
+                    }
+                    return true;
+                }
+            }
+
+            @Override
+            public boolean isPassengerDisplayAvailable() {
+                for (OccupantZoneInfo ozi : getAllOccupantZones()) {
+                    if (getDisplayForOccupant(ozi.zoneId,
+                            CarOccupantZoneManager.DISPLAY_TYPE_MAIN) != Display.INVALID_DISPLAY
+                            && ozi.occupantType != CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+        };
+        userService.setZoneUserBindingHelper(helper);
+    }
+
+    @Override
+    public void release() {
+        mDisplayManager.unregisterDisplayListener(mDisplayListener);
+        CarUserService userService = CarLocalServices.getService(CarUserService.class);
+        userService.removeUserLifecycleListener(mUserLifecycleListener);
+        userService.removePassengerCallback(mPassengerCallback);
+        synchronized (mLock) {
+            mOccupantsConfig.clear();
+            mDisplayConfigs.clear();
+            mAudioZoneIdToOccupantZoneIdMapping.clear();
+            mActiveOccupantConfigs.clear();
+        }
+    }
+
+    /** Return cloned mOccupantsConfig for testing */
+    @VisibleForTesting
+    @NonNull
+    public HashMap<Integer, OccupantZoneInfo> getOccupantsConfig() {
+        synchronized (mLock) {
+            return (HashMap<Integer, OccupantZoneInfo>) mOccupantsConfig.clone();
+        }
+    }
+
+    /** Return cloned mDisplayConfigs for testing */
+    @VisibleForTesting
+    @NonNull
+    public HashMap<Integer, DisplayConfig> getDisplayConfigs() {
+        synchronized (mLock) {
+            return (HashMap<Integer, DisplayConfig>) mDisplayConfigs.clone();
+        }
+    }
+
+    /** Return cloned mAudioConfigs for testing */
+    @VisibleForTesting
+    @NonNull
+    SparseIntArray getAudioConfigs() {
+        synchronized (mLock) {
+            return mAudioZoneIdToOccupantZoneIdMapping.clone();
+        }
+    }
+
+    /** Return cloned mActiveOccupantConfigs for testing */
+    @VisibleForTesting
+    @NonNull
+    public HashMap<Integer, OccupantConfig> getActiveOccupantConfigs() {
+        synchronized (mLock) {
+            return (HashMap<Integer, OccupantConfig>) mActiveOccupantConfigs.clone();
+        }
+    }
+
+    @Override
+    public void dump(PrintWriter writer) {
+        writer.println("*OccupantZoneService*");
+        synchronized (mLock) {
+            writer.println("**mOccupantsConfig**");
+            for (Map.Entry<Integer, OccupantZoneInfo> entry : mOccupantsConfig.entrySet()) {
+                writer.println(" zoneId=" + entry.getKey()
+                        + " info=" + entry.getValue().toString());
+            }
+            writer.println("**mDisplayConfigs**");
+            for (Map.Entry<Integer, DisplayConfig> entry : mDisplayConfigs.entrySet()) {
+                writer.println(" port=" + Integer.toHexString(entry.getKey())
+                        + " config=" + entry.getValue().toString());
+            }
+            writer.println("**mAudioZoneIdToOccupantZoneIdMapping**");
+            for (int index = 0; index < mAudioZoneIdToOccupantZoneIdMapping.size(); index++) {
+                int audioZoneId = mAudioZoneIdToOccupantZoneIdMapping.keyAt(index);
+                writer.println(" audioZoneId=" + Integer.toHexString(audioZoneId)
+                        + " zoneId=" + mAudioZoneIdToOccupantZoneIdMapping.get(audioZoneId));
+            }
+            writer.println("**mActiveOccupantConfigs**");
+            for (Map.Entry<Integer, OccupantConfig> entry : mActiveOccupantConfigs.entrySet()) {
+                writer.println(" zoneId=" + entry.getKey()
+                        + " config=" + entry.getValue().toString());
+            }
+            writer.println("mEnableProfileUserAssignmentForMultiDisplay:"
+                    + mEnableProfileUserAssignmentForMultiDisplay);
+            writer.println("mEnableSourcePreferred:"
+                    + mEnableSourcePreferred);
+            writer.append("mSourcePreferredComponents: [");
+            if (mSourcePreferredComponents != null) {
+                for (int i = 0; i < mSourcePreferredComponents.size(); ++i) {
+                    if (i > 0) writer.append(' ');
+                    writer.append(mSourcePreferredComponents.get(i).toString());
+                }
+            }
+            writer.println(']');
+        }
+    }
+
+    @Override
+    public List<OccupantZoneInfo> getAllOccupantZones() {
+        synchronized (mLock) {
+            List<OccupantZoneInfo> infos = new ArrayList<>();
+            for (Integer zoneId : mActiveOccupantConfigs.keySet()) {
+                // no need for deep copy as OccupantZoneInfo itself is static.
+                infos.add(mOccupantsConfig.get(zoneId));
+            }
+            return infos;
+        }
+    }
+
+    @Override
+    public int[] getAllDisplaysForOccupantZone(int occupantZoneId) {
+        synchronized (mLock) {
+            OccupantConfig config = mActiveOccupantConfigs.get(occupantZoneId);
+            if (config == null) {
+                return new int[0];
+            }
+            int[] displayIds = new int[config.displayInfos.size()];
+            for (int i = 0; i < config.displayInfos.size(); i++) {
+                displayIds[i] = config.displayInfos.get(i).display.getDisplayId();
+            }
+            return displayIds;
+        }
+    }
+
+    @Override
+    public int getDisplayForOccupant(int occupantZoneId, int displayType) {
+        synchronized (mLock) {
+            OccupantConfig config = mActiveOccupantConfigs.get(occupantZoneId);
+            if (config == null) {
+                return Display.INVALID_DISPLAY;
+            }
+            for (int i = 0; i < config.displayInfos.size(); i++) {
+                if (displayType == config.displayInfos.get(i).displayType) {
+                    return config.displayInfos.get(i).display.getDisplayId();
+                }
+            }
+        }
+        return Display.INVALID_DISPLAY;
+    }
+
+    @Override
+    public int getAudioZoneIdForOccupant(int occupantZoneId) {
+        enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
+        synchronized (mLock) {
+            OccupantConfig config = mActiveOccupantConfigs.get(occupantZoneId);
+            if (config != null) {
+                return config.audioZoneId;
+            }
+            // check if the occupant id exist at all
+            if (!mOccupantsConfig.containsKey(occupantZoneId)) {
+                return CarAudioManager.INVALID_AUDIO_ZONE;
+            }
+            // Exist but not active
+            return getAudioZoneIdForOccupantLocked(occupantZoneId);
+        }
+    }
+
+    private int getAudioZoneIdForOccupantLocked(int occupantZoneId) {
+        for (int index = 0; index < mAudioZoneIdToOccupantZoneIdMapping.size(); index++) {
+            int audioZoneId = mAudioZoneIdToOccupantZoneIdMapping.keyAt(index);
+            if (occupantZoneId == mAudioZoneIdToOccupantZoneIdMapping.get(audioZoneId)) {
+                return audioZoneId;
+            }
+        }
+        return CarAudioManager.INVALID_AUDIO_ZONE;
+    }
+
+    @Override
+    public CarOccupantZoneManager.OccupantZoneInfo getOccupantForAudioZoneId(int audioZoneId) {
+        enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
+        synchronized (mLock) {
+            int occupantZoneId = mAudioZoneIdToOccupantZoneIdMapping.get(audioZoneId,
+                    OccupantZoneInfo.INVALID_ZONE_ID);
+            if (occupantZoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
+                return null;
+            }
+            // To support headless zones return the occupant configuration.
+            return mOccupantsConfig.get(occupantZoneId);
+        }
+    }
+
+    @Nullable
+    private DisplayConfig findDisplayConfigForDisplayLocked(int displayId) {
+        for (Map.Entry<Integer, DisplayConfig> entry : mDisplayConfigs.entrySet()) {
+            Display display = mDisplayManager.getDisplay(displayId);
+            if (display == null) {
+                continue;
+            }
+            Byte portAddress = getPortAddress(display);
+            if (portAddress == null) {
+                continue;
+            }
+            DisplayConfig config =
+                    mDisplayConfigs.get(Byte.toUnsignedInt(portAddress));
+            return config;
+        }
+        return null;
+    }
+
+    @Override
+    public int getDisplayType(int displayId) {
+        synchronized (mLock) {
+            DisplayConfig config = findDisplayConfigForDisplayLocked(displayId);
+            if (config != null) {
+                return config.displayType;
+            }
+        }
+        return CarOccupantZoneManager.DISPLAY_TYPE_UNKNOWN;
+    }
+
+    @Override
+    public int getUserForOccupant(int occupantZoneId) {
+        synchronized (mLock) {
+            OccupantConfig config = mActiveOccupantConfigs.get(occupantZoneId);
+            if (config == null) {
+                return UserHandle.USER_NULL;
+            }
+            return config.userId;
+        }
+    }
+
+    @Override
+    public int getOccupantZoneIdForUserId(int userId) {
+        synchronized (mLock) {
+            for (int occupantZoneId : mActiveOccupantConfigs.keySet()) {
+                OccupantConfig config = mActiveOccupantConfigs.get(occupantZoneId);
+                if (config.userId == userId) {
+                    return occupantZoneId;
+                }
+            }
+            Log.w(TAG, "Could not find occupantZoneId for userId" + userId
+                    + " returning invalid occupant zone id " + OccupantZoneInfo.INVALID_ZONE_ID);
+            return OccupantZoneInfo.INVALID_ZONE_ID;
+        }
+    }
+
+    /**
+     * returns the current driver user id.
+     */
+    public @UserIdInt int getDriverUserId() {
+        return getCurrentUser();
+    }
+
+    /**
+     * Sets the mapping for audio zone id to occupant zone id.
+     *
+     * @param audioZoneIdToOccupantZoneMapping map for audio zone id, where key is the audio zone id
+     * and value is the occupant zone id.
+     */
+    public void setAudioZoneIdsForOccupantZoneIds(
+            @NonNull SparseIntArray audioZoneIdToOccupantZoneMapping) {
+        Objects.requireNonNull(audioZoneIdToOccupantZoneMapping,
+                "audioZoneIdToOccupantZoneMapping can not be null");
+        synchronized (mLock) {
+            validateOccupantZoneIdsLocked(audioZoneIdToOccupantZoneMapping);
+            mAudioZoneIdToOccupantZoneIdMapping.clear();
+            for (int index = 0; index < audioZoneIdToOccupantZoneMapping.size(); index++) {
+                int audioZoneId = audioZoneIdToOccupantZoneMapping.keyAt(index);
+                mAudioZoneIdToOccupantZoneIdMapping.put(audioZoneId,
+                        audioZoneIdToOccupantZoneMapping.get(audioZoneId));
+            }
+            //If there are any active displays for the zone send change event
+            handleAudioZoneChangesLocked();
+        }
+        sendConfigChangeEvent(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_AUDIO);
+    }
+
+    private void validateOccupantZoneIdsLocked(SparseIntArray audioZoneIdToOccupantZoneMapping) {
+        for (int i = 0; i < audioZoneIdToOccupantZoneMapping.size(); i++) {
+            int occupantZoneId =
+                    audioZoneIdToOccupantZoneMapping.get(audioZoneIdToOccupantZoneMapping.keyAt(i));
+            if (!mOccupantsConfig.containsKey(occupantZoneId)) {
+                throw new IllegalArgumentException("occupantZoneId " + occupantZoneId
+                        + " does not exist.");
+            }
+        }
+    }
+
+    @Override
+    public void registerCallback(ICarOccupantZoneCallback callback) {
+        mClientCallbacks.register(callback);
+    }
+
+    @Override
+    public void unregisterCallback(ICarOccupantZoneCallback callback) {
+        mClientCallbacks.unregister(callback);
+    }
+
+    @Override
+    public boolean assignProfileUserToOccupantZone(int occupantZoneId, int userId) {
+        enforcePermission(android.Manifest.permission.MANAGE_USERS);
+        if (!mEnableProfileUserAssignmentForMultiDisplay) {
+            throw new IllegalStateException("feature not enabled");
+        }
+        int currentUser = getCurrentUser();
+
+        synchronized (mLock) {
+            if (occupantZoneId == mDriverZoneId) {
+                throw new IllegalArgumentException("Driver zone cannot have profile user");
+            }
+            updateEnabledProfilesLocked(currentUser);
+
+            if (!mProfileUsers.contains(userId) && userId != UserHandle.USER_NULL) {
+                // current user can change while this call is happening, so return false rather
+                // than throwing exception
+                Log.w(TAG, "Invalid profile user id:" + userId);
+                return false;
+            }
+            if (!mUserManager.isUserRunning(userId)) {
+                Log.w(TAG, "User is not running:" + userId);
+                return false;
+            }
+            OccupantConfig config = mActiveOccupantConfigs.get(occupantZoneId);
+            if (config == null) {
+                throw new IllegalArgumentException("Invalid occupantZoneId:" + occupantZoneId);
+            }
+            if (config.userId == userId && userId != UserHandle.USER_NULL) {
+                Log.w(TAG, "assignProfileUserToOccupantZone zone:"
+                        + occupantZoneId + " already set to user:" + userId);
+                return true;
+            }
+            if (userId == UserHandle.USER_NULL) {
+                config.userId = currentUser;
+            } else {
+                config.userId = userId;
+            }
+        }
+        sendConfigChangeEvent(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
+        return true;
+    }
+
+    /**
+     * Sets {@code ICarServiceHelper}.
+     */
+    public void setCarServiceHelper(ICarServiceHelper helper) {
+        doSyncWithCarServiceHelper(helper, /* updateDisplay= */ true, /* updateUser= */ true,
+                /* updateConfig= */ true);
+    }
+
+    private void doSyncWithCarServiceHelper(@Nullable ICarServiceHelper helper,
+            boolean updateDisplay, boolean updateUser, boolean updateConfig) {
+        int[] passengerDisplays = null;
+        ArrayMap<Integer, IntArray> whitelists = null;
+        ICarServiceHelper helperToUse = helper;
+        synchronized (mLock) {
+            if (helper == null) {
+                if (mICarServiceHelper == null) { // helper not set yet.
+                    return;
+                }
+                helperToUse = mICarServiceHelper;
+            } else {
+                mICarServiceHelper = helper;
+            }
+            if (updateDisplay) {
+                passengerDisplays = getAllActivePassengerDisplaysLocked();
+            }
+            if (updateUser) {
+                whitelists = createDisplayWhitelistsLocked();
+            }
+        }
+        if (updateDisplay) {
+            updatePassengerDisplays(helperToUse, passengerDisplays);
+        }
+        if (updateUser) {
+            updateUserAssignmentForDisplays(helperToUse, whitelists);
+        }
+        if (updateConfig) {
+            Resources res = mContext.getResources();
+            String[] components = res.getStringArray(R.array.config_sourcePreferredComponents);
+            updateSourcePreferredComponents(helperToUse, components);
+        }
+    }
+
+    private int[] getAllActivePassengerDisplaysLocked() {
+        IntArray displays = new IntArray();
+        for (Map.Entry<Integer, OccupantConfig> entry : mActiveOccupantConfigs.entrySet()) {
+            Integer zoneId = entry.getKey();
+            if (zoneId == mDriverZoneId) {
+                continue;
+            }
+            OccupantConfig config = entry.getValue();
+            for (int i = 0; i < config.displayInfos.size(); i++) {
+                displays.add(config.displayInfos.get(i).display.getDisplayId());
+            }
+        }
+        return displays.toArray();
+    }
+
+    private void updatePassengerDisplays(ICarServiceHelper helper, int[] passengerDisplayIds) {
+        if (passengerDisplayIds == null) {
+            return;
+        }
+        try {
+            helper.setPassengerDisplays(passengerDisplayIds);
+        } catch (RemoteException e) {
+            Log.e(TAG, "ICarServiceHelper.setPassengerDisplays failed");
+        }
+    }
+
+    private void updateSourcePreferredComponents(ICarServiceHelper helper, String[] components) {
+        boolean enableSourcePreferred;
+        ArrayList<ComponentName> componentNames = null;
+        if (components == null || components.length == 0) {
+            enableSourcePreferred = false;
+            Log.i(TAG, "CarLaunchParamsModifier: disable source-preferred");
+        } else if (components.length == 1 && components[0].equals(ALL_COMPONENTS)) {
+            enableSourcePreferred = true;
+            Log.i(TAG, "CarLaunchParamsModifier: enable source-preferred for all Components");
+        } else {
+            componentNames = new ArrayList<>((components.length));
+            for (String item : components) {
+                ComponentName name = ComponentName.unflattenFromString(item);
+                if (name == null) {
+                    Log.e(TAG, "CarLaunchParamsModifier: Wrong ComponentName=" + item);
+                    return;
+                }
+                componentNames.add(name);
+            }
+            enableSourcePreferred = true;
+        }
+        try {
+            helper.setSourcePreferredComponents(enableSourcePreferred, componentNames);
+            mEnableSourcePreferred = enableSourcePreferred;
+            mSourcePreferredComponents = componentNames;
+        } catch (RemoteException e) {
+            Log.e(TAG, "ICarServiceHelper.setSourcePreferredComponents failed");
+        }
+    }
+
+    private ArrayMap<Integer, IntArray> createDisplayWhitelistsLocked() {
+        ArrayMap<Integer, IntArray> whitelists = new ArrayMap<>();
+        for (Map.Entry<Integer, OccupantConfig> entry : mActiveOccupantConfigs.entrySet()) {
+            Integer zoneId = entry.getKey();
+            if (zoneId == mDriverZoneId) {
+                continue;
+            }
+            OccupantConfig config = entry.getValue();
+            if (config.displayInfos.isEmpty()) {
+                continue;
+            }
+            // user like driver can have multiple zones assigned, so add them all.
+            IntArray displays = whitelists.get(config.userId);
+            if (displays == null) {
+                displays = new IntArray();
+                whitelists.put(config.userId, displays);
+            }
+            for (int i = 0; i < config.displayInfos.size(); i++) {
+                displays.add(config.displayInfos.get(i).display.getDisplayId());
+            }
+        }
+        return whitelists;
+    }
+
+    private void updateUserAssignmentForDisplays(ICarServiceHelper helper,
+            ArrayMap<Integer, IntArray> whitelists) {
+        if (whitelists == null || whitelists.isEmpty()) {
+            return;
+        }
+        try {
+            for (int i = 0; i < whitelists.size(); i++) {
+                int userId = whitelists.keyAt(i);
+                helper.setDisplayWhitelistForUser(userId, whitelists.valueAt(i).toArray());
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "ICarServiceHelper.setDisplayWhitelistForUser failed");
+        }
+    }
+
+    private void throwFormatErrorInOccupantZones(String msg) {
+        throw new RuntimeException("Format error in config_occupant_zones resource:" + msg);
+    }
+
+    // For overriding in test
+    @VisibleForTesting
+    int getDriverSeat() {
+        synchronized (mLock) {
+            return mDriverSeat;
+        }
+    }
+
+    private void parseOccupantZoneConfigsLocked() {
+        final Resources res = mContext.getResources();
+        // examples:
+        // <item>occupantZoneId=0,occupantType=DRIVER,seatRow=1,seatSide=driver</item>
+        // <item>occupantZoneId=1,occupantType=FRONT_PASSENGER,seatRow=1,
+        // searSide=oppositeDriver</item>
+        boolean hasDriver = false;
+        int driverSeat = getDriverSeat();
+        int driverSeatSide = VehicleAreaSeat.SIDE_LEFT; // default LHD : Left Hand Drive
+        if (driverSeat == VehicleAreaSeat.SEAT_ROW_1_RIGHT) {
+            driverSeatSide = VehicleAreaSeat.SIDE_RIGHT;
+        }
+        int maxZoneId = OccupantZoneInfo.INVALID_ZONE_ID;
+        for (String config : res.getStringArray(R.array.config_occupant_zones)) {
+            int zoneId = OccupantZoneInfo.INVALID_ZONE_ID;
+            int type = CarOccupantZoneManager.OCCUPANT_TYPE_INVALID;
+            int seatRow = 0; // invalid row
+            int seatSide = VehicleAreaSeat.SIDE_LEFT;
+            String[] entries = config.split(",");
+            for (String entry : entries) {
+                String[] keyValuePair = entry.split("=");
+                if (keyValuePair.length != 2) {
+                    throwFormatErrorInOccupantZones("No key/value pair:" + entry);
+                }
+                switch (keyValuePair[0]) {
+                    case "occupantZoneId":
+                        zoneId = Integer.parseInt(keyValuePair[1]);
+                        break;
+                    case "occupantType":
+                        switch (keyValuePair[1]) {
+                            case "DRIVER":
+                                type = CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER;
+                                break;
+                            case "FRONT_PASSENGER":
+                                type = CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER;
+                                break;
+                            case "REAR_PASSENGER":
+                                type = CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER;
+                                break;
+                            default:
+                                throwFormatErrorInOccupantZones("Unrecognized type:" + entry);
+                                break;
+                        }
+                        break;
+                    case "seatRow":
+                        seatRow = Integer.parseInt(keyValuePair[1]);
+                        break;
+                    case "seatSide":
+                        switch (keyValuePair[1]) {
+                            case "driver":
+                                seatSide = driverSeatSide;
+                                break;
+                            case "oppositeDriver":
+                                seatSide = -driverSeatSide;
+                                break;
+                            case "left":
+                                seatSide = VehicleAreaSeat.SIDE_LEFT;
+                                break;
+                            case "center":
+                                seatSide = VehicleAreaSeat.SIDE_CENTER;
+                                break;
+                            case "right":
+                                seatSide = VehicleAreaSeat.SIDE_RIGHT;
+                                break;
+                            default:
+                                throwFormatErrorInOccupantZones("Unregognized seatSide:" + entry);
+                                break;
+
+                        }
+                        break;
+                    default:
+                        throwFormatErrorInOccupantZones("Unrecognized key:" + entry);
+                        break;
+                }
+            }
+            if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
+                throwFormatErrorInOccupantZones("Missing zone id:" + config);
+            }
+            if (zoneId > maxZoneId) {
+                maxZoneId = zoneId;
+            }
+            if (type == CarOccupantZoneManager.OCCUPANT_TYPE_INVALID) {
+                throwFormatErrorInOccupantZones("Missing type:" + config);
+            }
+            if (type == CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER) {
+                if (hasDriver) {
+                    throwFormatErrorInOccupantZones("Multiple driver:" + config);
+                } else {
+                    hasDriver = true;
+                    mDriverZoneId = zoneId;
+                }
+            }
+            int seat = VehicleAreaSeat.fromRowAndSide(seatRow, seatSide);
+            if (seat == VehicleAreaSeat.SEAT_UNKNOWN) {
+                throwFormatErrorInOccupantZones("Invalid seat:" + config);
+            }
+            OccupantZoneInfo info = new OccupantZoneInfo(zoneId, type, seat);
+            if (mOccupantsConfig.containsKey(zoneId)) {
+                throwFormatErrorInOccupantZones("Duplicate zone id:" + config);
+            }
+            mOccupantsConfig.put(zoneId, info);
+        }
+        if (!hasDriver) {
+            maxZoneId++;
+            mDriverZoneId = maxZoneId;
+            Log.w(TAG, "No driver zone, add one:" + mDriverZoneId);
+            OccupantZoneInfo info = new OccupantZoneInfo(mDriverZoneId,
+                    CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER, getDriverSeat());
+            mOccupantsConfig.put(mDriverZoneId, info);
+        }
+    }
+
+    private void throwFormatErrorInDisplayMapping(String msg) {
+        throw new RuntimeException(
+                "Format error in config_occupant_display_mapping resource:" + msg);
+    }
+
+    private void parseDisplayConfigsLocked() {
+        final Resources res = mContext.getResources();
+        // examples:
+        // <item>displayPort=0,displayType=MAIN,occupantZoneId=0</item>
+        // <item>displayPort=1,displayType=INSTRUMENT_CLUSTER,occupantZoneId=0</item>
+        final int invalidPort = -1;
+        for (String config : res.getStringArray(R.array.config_occupant_display_mapping)) {
+            int port = invalidPort;
+            int type = CarOccupantZoneManager.DISPLAY_TYPE_UNKNOWN;
+            int zoneId = OccupantZoneInfo.INVALID_ZONE_ID;
+            String[] entries = config.split(",");
+            for (String entry : entries) {
+                String[] keyValuePair = entry.split("=");
+                if (keyValuePair.length != 2) {
+                    throwFormatErrorInDisplayMapping("No key/value pair:" + entry);
+                }
+                switch (keyValuePair[0]) {
+                    case "displayPort":
+                        port = Integer.parseInt(keyValuePair[1]);
+                        break;
+                    case "displayType":
+                        switch (keyValuePair[1]) {
+                            case "MAIN":
+                                type = CarOccupantZoneManager.DISPLAY_TYPE_MAIN;
+                                break;
+                            case "INSTRUMENT_CLUSTER":
+                                type = CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER;
+                                break;
+                            case "HUD":
+                                type = CarOccupantZoneManager.DISPLAY_TYPE_HUD;
+                                break;
+                            case "INPUT":
+                                type = CarOccupantZoneManager.DISPLAY_TYPE_INPUT;
+                                break;
+                            case "AUXILIARY":
+                                type = CarOccupantZoneManager.DISPLAY_TYPE_AUXILIARY;
+                                break;
+                            default:
+                                throwFormatErrorInDisplayMapping(
+                                        "Unrecognized display type:" + entry);
+                                break;
+                        }
+                        break;
+                    case "occupantZoneId":
+                        zoneId = Integer.parseInt(keyValuePair[1]);
+                        break;
+                    default:
+                        throwFormatErrorInDisplayMapping("Unrecognized key:" + entry);
+                        break;
+
+                }
+            }
+            // Now check validity
+            if (port == invalidPort) {
+                throwFormatErrorInDisplayMapping("Missing or invalid displayPort:" + config);
+            }
+
+            if (type == CarOccupantZoneManager.DISPLAY_TYPE_UNKNOWN) {
+                throwFormatErrorInDisplayMapping("Missing or invalid displayType:" + config);
+            }
+            if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
+                throwFormatErrorInDisplayMapping("Missing or invalid occupantZoneId:" + config);
+            }
+            if (!mOccupantsConfig.containsKey(zoneId)) {
+                throwFormatErrorInDisplayMapping(
+                        "Missing or invalid occupantZoneId:" + config);
+            }
+            if (mDisplayConfigs.containsKey(port)) {
+                throwFormatErrorInDisplayMapping("Duplicate displayPort:" + config);
+            }
+            mDisplayConfigs.put(port, new DisplayConfig(type, zoneId));
+        }
+    }
+
+    private Byte getPortAddress(Display display) {
+        DisplayAddress address = display.getAddress();
+        if (address instanceof DisplayAddress.Physical) {
+            DisplayAddress.Physical physicalAddress = (DisplayAddress.Physical) address;
+            if (physicalAddress != null) {
+                return physicalAddress.getPort();
+            }
+        }
+        return null;
+    }
+
+    private void addDisplayInfoToOccupantZoneLocked(int zoneId, DisplayInfo info) {
+        OccupantConfig occupantConfig = mActiveOccupantConfigs.get(zoneId);
+        if (occupantConfig == null) {
+            occupantConfig = new OccupantConfig();
+            mActiveOccupantConfigs.put(zoneId, occupantConfig);
+        }
+        occupantConfig.displayInfos.add(info);
+    }
+
+    private void handleActiveDisplaysLocked() {
+        mActiveOccupantConfigs.clear();
+        boolean hasDefaultDisplayConfig = false;
+        for (Display display : mDisplayManager.getDisplays()) {
+            Byte rawPortAddress = getPortAddress(display);
+            if (rawPortAddress == null) {
+                continue;
+            }
+
+            int portAddress = Byte.toUnsignedInt(rawPortAddress);
+            DisplayConfig displayConfig = mDisplayConfigs.get(portAddress);
+            if (displayConfig == null) {
+                Log.w(TAG,
+                        "Display id:" + display.getDisplayId() + " port:" + portAddress
+                                + " does not have configurations");
+                continue;
+            }
+            if (display.getDisplayId() == Display.DEFAULT_DISPLAY) {
+                if (displayConfig.occupantZoneId != mDriverZoneId) {
+                    throw new IllegalStateException(
+                            "Default display should be only assigned to driver zone");
+                }
+                hasDefaultDisplayConfig = true;
+            }
+            addDisplayInfoToOccupantZoneLocked(displayConfig.occupantZoneId,
+                    new DisplayInfo(display, displayConfig.displayType));
+        }
+        if (!hasDefaultDisplayConfig) {
+            // Can reach here if default display has no port / no config
+            Log.w(TAG, "Default display not assigned, will assign to driver zone");
+            addDisplayInfoToOccupantZoneLocked(mDriverZoneId, new DisplayInfo(
+                    mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY),
+                    CarOccupantZoneManager.DISPLAY_TYPE_MAIN));
+        }
+    }
+
+    @VisibleForTesting
+    int getCurrentUser() {
+        return ActivityManager.getCurrentUser();
+    }
+
+    private void updateEnabledProfilesLocked(int userId) {
+        mProfileUsers.clear();
+        List<UserInfo> profileUsers = mUserManager.getEnabledProfiles(userId);
+        for (UserInfo userInfo : profileUsers) {
+            if (userInfo.id != userId) {
+                mProfileUsers.add(userInfo.id);
+            }
+        }
+    }
+
+    private void handleUserChangesLocked() {
+        int driverUserId = getCurrentUser();
+
+        if (mEnableProfileUserAssignmentForMultiDisplay) {
+            updateEnabledProfilesLocked(driverUserId);
+        }
+
+        for (Map.Entry<Integer, OccupantConfig> entry : mActiveOccupantConfigs.entrySet()) {
+            Integer zoneId = entry.getKey();
+            OccupantConfig config = entry.getValue();
+            // mProfileUsers empty if not supported
+            if (mProfileUsers.contains(config.userId)) {
+                Log.i(TAG, "Profile user:" + config.userId
+                        + " already assigned for occupant zone:" + zoneId);
+            } else {
+                config.userId = driverUserId;
+            }
+        }
+    }
+
+    private void handleAudioZoneChangesLocked() {
+        for (int index = 0; index < mAudioZoneIdToOccupantZoneIdMapping.size(); index++) {
+            int audioZoneId = mAudioZoneIdToOccupantZoneIdMapping.keyAt(index);
+            int occupantZoneId = mAudioZoneIdToOccupantZoneIdMapping.get(audioZoneId);
+            OccupantConfig occupantConfig =
+                    mActiveOccupantConfigs.get(occupantZoneId);
+            if (occupantConfig == null) {
+                //no active display for zone just continue
+                continue;
+            }
+            // Found an active configuration, add audio to it.
+            occupantConfig.audioZoneId = audioZoneId;
+        }
+    }
+
+    private void sendConfigChangeEvent(int changeFlags) {
+        boolean updateDisplay = false;
+        boolean updateUser = false;
+        if ((changeFlags & CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_DISPLAY) != 0) {
+            updateDisplay = true;
+            updateUser = true;
+        } else if ((changeFlags & CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER) != 0) {
+            updateUser = true;
+        }
+        doSyncWithCarServiceHelper(/* helper= */ null, updateDisplay, updateUser,
+                /* updateConfig= */ false);
+
+        final int n = mClientCallbacks.beginBroadcast();
+        for (int i = 0; i < n; i++) {
+            ICarOccupantZoneCallback callback = mClientCallbacks.getBroadcastItem(i);
+            try {
+                callback.onOccupantZoneConfigChanged(changeFlags);
+            } catch (RemoteException ignores) {
+                // ignore
+            }
+        }
+        mClientCallbacks.finishBroadcast();
+    }
+
+    private void handleUserChange() {
+        synchronized (mLock) {
+            handleUserChangesLocked();
+        }
+        sendConfigChangeEvent(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
+    }
+
+    private void handlePassengerStarted(@UserIdInt int passengerId, int zoneId) {
+        sendConfigChangeEvent(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
+    }
+
+    private void handlePassengerStopped(@UserIdInt int passengerId) {
+        sendConfigChangeEvent(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
+    }
+
+    private void handleDisplayChange() {
+        synchronized (mLock) {
+            handleActiveDisplaysLocked();
+            //audio zones should be re-checked for changed display
+            handleAudioZoneChangesLocked();
+            // user should be re-checked for changed displays
+            handleUserChangesLocked();
+        }
+        sendConfigChangeEvent(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_DISPLAY);
+    }
+
+    private void enforcePermission(String permissionName) {
+        if (mContext.checkCallingOrSelfPermission(permissionName)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("requires permission " + permissionName);
+        }
+    }
+}
diff --git a/service/src/com/android/car/CarPowerManagementService.java b/service/src/com/android/car/CarPowerManagementService.java
index 340fd9b..da88468 100644
--- a/service/src/com/android/car/CarPowerManagementService.java
+++ b/service/src/com/android/car/CarPowerManagementService.java
@@ -15,19 +15,25 @@
  */
 package com.android.car;
 
-import android.annotation.Nullable;
+import android.annotation.NonNull;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.car.Car;
 import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
 import android.car.hardware.power.ICarPower;
 import android.car.hardware.power.ICarPowerStateListener;
-import android.car.userlib.CarUserManagerHelper;
+import android.car.userlib.HalCallback;
+import android.car.userlib.InitialUserSetter;
+import android.car.userlib.InitialUserSetter.InitialUserInfoType;
+import android.car.userlib.UserHalHelper;
+import android.car.userlib.UserHelper;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
 import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateReq;
 import android.os.Build;
 import android.os.Handler;
@@ -38,10 +44,12 @@
 import android.os.PowerManager;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.sysprop.CarProperties;
 import android.util.Log;
 
 import com.android.car.am.ContinuousBlankActivity;
@@ -49,13 +57,15 @@
 import com.android.car.hal.PowerHalService.PowerState;
 import com.android.car.systeminterface.SystemInterface;
 import com.android.car.user.CarUserNoticeService;
+import com.android.car.user.CarUserService;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.IVoiceInteractionManagerService;
 
 import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
 import java.util.HashSet;
 import java.util.LinkedList;
-import java.util.List;
 import java.util.Set;
 import java.util.Timer;
 import java.util.TimerTask;
@@ -67,6 +77,9 @@
 public class CarPowerManagementService extends ICarPower.Stub implements
         CarServiceBase, PowerHalService.PowerEventListener {
 
+    // TODO: replace all usage
+    private static final String TAG = CarLog.TAG_POWER;
+
     private final Object mLock = new Object();
     private final Object mSimulationWaitObject = new Object();
 
@@ -96,10 +109,10 @@
     private long mLastSleepEntryTime;
     @GuardedBy("mLock")
     private final LinkedList<CpmsState> mPendingPowerStates = new LinkedList<>();
-    @GuardedBy("mLock")
-    private HandlerThread mHandlerThread;
-    @GuardedBy("mLock")
-    private PowerHandler mHandler;
+    private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
+            getClass().getSimpleName());
+    private final PowerHandler mHandler = new PowerHandler(mHandlerThread.getLooper(), this);
+
     @GuardedBy("mLock")
     private boolean mTimerActive;
     @GuardedBy("mLock")
@@ -113,11 +126,20 @@
     @GuardedBy("mLock")
     private boolean mIsResuming;
     @GuardedBy("mLock")
+    private int mShutdownPrepareTimeMs = MIN_MAX_GARAGE_MODE_DURATION_MS;
+    @GuardedBy("mLock")
+    private int mShutdownPollingIntervalMs = SHUTDOWN_POLLING_INTERVAL_MS;
+    @GuardedBy("mLock")
     private boolean mRebootAfterGarageMode;
+    @GuardedBy("mLock")
+    private boolean mGarageModeShouldExitImmediately;
     private final boolean mDisableUserSwitchDuringResume;
-    private final CarUserManagerHelper mCarUserManagerHelper;
-    private final UserManager mUserManager;    // CarUserManagerHelper is deprecated...
-    private final String mNewGuestName;
+
+    private final UserManager mUserManager;
+    private final CarUserService mUserService;
+    private final InitialUserSetter mInitialUserSetter;
+
+    private final IVoiceInteractionManagerService mVoiceInteractionManagerService;
 
     // TODO:  Make this OEM configurable.
     private static final int SHUTDOWN_POLLING_INTERVAL_MS = 2000;
@@ -126,8 +148,6 @@
     // maxGarageModeRunningDurationInSecs should be equal or greater than this. 15 min for now.
     private static final int MIN_MAX_GARAGE_MODE_DURATION_MS = 15 * 60 * 1000;
 
-    private static int sShutdownPrepareTimeMs = MIN_MAX_GARAGE_MODE_DURATION_MS;
-
     // in secs
     private static final String PROP_MAX_GARAGE_MODE_DURATION_OVERRIDE =
             "android.car.garagemodeduration";
@@ -148,61 +168,61 @@
     }
 
     public CarPowerManagementService(Context context, PowerHalService powerHal,
-            SystemInterface systemInterface, CarUserManagerHelper carUserManagerHelper) {
-        this(context, context.getResources(), powerHal, systemInterface, carUserManagerHelper,
-                UserManager.get(context), context.getString(R.string.default_guest_name));
+            SystemInterface systemInterface, CarUserService carUserService) {
+        this(context, context.getResources(), powerHal, systemInterface, UserManager.get(context),
+                carUserService, new InitialUserSetter(context,
+                        (u) -> carUserService.setInitialUser(u),
+                        context.getString(R.string.default_guest_name)),
+                IVoiceInteractionManagerService.Stub.asInterface(
+                        ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE)));
     }
 
     @VisibleForTesting
-    CarPowerManagementService(Context context, Resources resources, PowerHalService powerHal,
-            SystemInterface systemInterface, CarUserManagerHelper carUserManagerHelper,
-            UserManager userManager, String newGuestName) {
+    public CarPowerManagementService(Context context, Resources resources, PowerHalService powerHal,
+            SystemInterface systemInterface, UserManager userManager, CarUserService carUserService,
+            InitialUserSetter initialUserSetter,
+            IVoiceInteractionManagerService voiceInteractionService) {
         mContext = context;
         mHal = powerHal;
         mSystemInterface = systemInterface;
-        mCarUserManagerHelper = carUserManagerHelper;
         mUserManager = userManager;
         mDisableUserSwitchDuringResume = resources
                 .getBoolean(R.bool.config_disableUserSwitchDuringResume);
-        sShutdownPrepareTimeMs = resources.getInteger(
+        mShutdownPrepareTimeMs = resources.getInteger(
                 R.integer.maxGarageModeRunningDurationInSecs) * 1000;
         mSwitchGuestUserBeforeSleep = resources.getBoolean(
                 R.bool.config_switchGuestUserBeforeGoingSleep);
-        if (sShutdownPrepareTimeMs < MIN_MAX_GARAGE_MODE_DURATION_MS) {
+        if (mShutdownPrepareTimeMs < MIN_MAX_GARAGE_MODE_DURATION_MS) {
             Log.w(CarLog.TAG_POWER,
                     "maxGarageModeRunningDurationInSecs smaller than minimum required, resource:"
-                    + sShutdownPrepareTimeMs + "(ms) while should exceed:"
+                    + mShutdownPrepareTimeMs + "(ms) while should exceed:"
                     +  MIN_MAX_GARAGE_MODE_DURATION_MS + "(ms), Ignore resource.");
-            sShutdownPrepareTimeMs = MIN_MAX_GARAGE_MODE_DURATION_MS;
+            mShutdownPrepareTimeMs = MIN_MAX_GARAGE_MODE_DURATION_MS;
         }
-        mNewGuestName = newGuestName;
+        mUserService = carUserService;
+        mInitialUserSetter = initialUserSetter;
+        mVoiceInteractionManagerService = voiceInteractionService;
     }
 
     @VisibleForTesting
-    protected static void setShutdownPrepareTimeout(int timeoutMs) {
-        // Override the timeout to keep testing time short
-        if (timeoutMs < SHUTDOWN_EXTEND_MAX_MS) {
-            sShutdownPrepareTimeMs = SHUTDOWN_EXTEND_MAX_MS;
-        } else {
-            sShutdownPrepareTimeMs = timeoutMs;
+    public void setShutdownTimersForTest(int pollingIntervalMs, int shutdownTimeoutMs) {
+        // Override timers to keep testing time short
+        // Passing in '0' resets the value to the default
+        synchronized (mLock) {
+            mShutdownPollingIntervalMs =
+                    (pollingIntervalMs == 0) ? SHUTDOWN_POLLING_INTERVAL_MS : pollingIntervalMs;
+            mShutdownPrepareTimeMs =
+                    (shutdownTimeoutMs == 0) ? SHUTDOWN_EXTEND_MAX_MS : shutdownTimeoutMs;
         }
     }
 
     @VisibleForTesting
     protected HandlerThread getHandlerThread() {
-        synchronized (mLock) {
-            return mHandlerThread;
-        }
+        return mHandlerThread;
     }
 
     @Override
     public void init() {
-        synchronized (mLock) {
-            mHandlerThread = new HandlerThread(CarLog.TAG_POWER);
-            mHandlerThread.start();
-            mHandler = new PowerHandler(mHandlerThread.getLooper());
-        }
-
         mHal.setListener(this);
         if (mHal.isPowerStateSupported()) {
             // Initialize CPMS in WAIT_FOR_VHAL state
@@ -216,20 +236,12 @@
 
     @Override
     public void release() {
-        HandlerThread handlerThread;
         synchronized (mLock) {
             releaseTimerLocked();
             mCurrentState = null;
             mHandler.cancelAll();
-            handlerThread = mHandlerThread;
             mListenersWeAreWaitingFor.clear();
         }
-        handlerThread.quitSafely();
-        try {
-            handlerThread.join(1000);
-        } catch (InterruptedException e) {
-            Log.e(CarLog.TAG_POWER, "Timeout while joining for handler thread to join.");
-        }
         mSystemInterface.stopDisplayStateMonitoring();
         mPowerManagerListeners.kill();
         mSystemInterface.releaseAllWakeLocks();
@@ -237,28 +249,31 @@
 
     @Override
     public void dump(PrintWriter writer) {
-        writer.println("*PowerManagementService*");
-        writer.print("mCurrentState:" + mCurrentState);
-        writer.print(",mProcessingStartTime:" + mProcessingStartTime);
-        writer.print(",mLastSleepEntryTime:" + mLastSleepEntryTime);
-        writer.print(",mNextWakeupSec:" + mNextWakeupSec);
-        writer.print(",mShutdownOnNextSuspend:" + mShutdownOnNextSuspend);
-        writer.print(",mShutdownOnFinish:" + mShutdownOnFinish);
-        writer.print(",sShutdownPrepareTimeMs:" + sShutdownPrepareTimeMs);
-        writer.print(",mDisableUserSwitchDuringResume:" + mDisableUserSwitchDuringResume);
-        writer.println(",mRebootAfterGarageMode:" + mRebootAfterGarageMode);
-        writer.print("mNewGuestName: "); writer.println(mNewGuestName);
-        writer.println("mSwitchGuestUserBeforeSleep:" + mSwitchGuestUserBeforeSleep);
+        synchronized (mLock) {
+            writer.println("*PowerManagementService*");
+            // TODO: split it in multiple lines
+            // TODO: lock only what's needed
+            writer.print("mCurrentState:" + mCurrentState);
+            writer.print(",mProcessingStartTime:" + mProcessingStartTime);
+            writer.print(",mLastSleepEntryTime:" + mLastSleepEntryTime);
+            writer.print(",mNextWakeupSec:" + mNextWakeupSec);
+            writer.print(",mShutdownOnNextSuspend:" + mShutdownOnNextSuspend);
+            writer.print(",mShutdownOnFinish:" + mShutdownOnFinish);
+            writer.print(",mShutdownPollingIntervalMs:" + mShutdownPollingIntervalMs);
+            writer.print(",mShutdownPrepareTimeMs:" + mShutdownPrepareTimeMs);
+            writer.print(",mDisableUserSwitchDuringResume:" + mDisableUserSwitchDuringResume);
+            writer.println(",mRebootAfterGarageMode:" + mRebootAfterGarageMode);
+            writer.println("mSwitchGuestUserBeforeSleep:" + mSwitchGuestUserBeforeSleep);
+        }
+        mInitialUserSetter.dump(writer);
     }
 
     @Override
     public void onApPowerStateChange(PowerState state) {
-        PowerHandler handler;
         synchronized (mLock) {
             mPendingPowerStates.addFirst(new CpmsState(state));
-            handler = mHandler;
         }
-        handler.handlePowerStateChange();
+        mHandler.handlePowerStateChange();
     }
 
     @VisibleForTesting
@@ -277,35 +292,31 @@
      */
     private void onApPowerStateChange(int apState, int carPowerStateListenerState) {
         CpmsState newState = new CpmsState(apState, carPowerStateListenerState);
-        PowerHandler handler;
         synchronized (mLock) {
             mPendingPowerStates.addFirst(newState);
-            handler = mHandler;
         }
-        handler.handlePowerStateChange();
+        mHandler.handlePowerStateChange();
     }
 
     private void doHandlePowerStateChange() {
         CpmsState state;
-        PowerHandler handler;
         synchronized (mLock) {
             state = mPendingPowerStates.peekFirst();
             mPendingPowerStates.clear();
             if (state == null) {
+                Log.e(CarLog.TAG_POWER, "Null power state was requested");
                 return;
             }
             Log.i(CarLog.TAG_POWER, "doHandlePowerStateChange: newState=" + state.name());
             if (!needPowerStateChangeLocked(state)) {
-                Log.d(CarLog.TAG_POWER, "doHandlePowerStateChange no change needed");
                 return;
             }
             // now real power change happens. Whatever was queued before should be all cancelled.
             releaseTimerLocked();
-            handler = mHandler;
         }
-        handler.cancelProcessingComplete();
+        mHandler.cancelProcessingComplete();
         Log.i(CarLog.TAG_POWER, "setCurrentState " + state.toString());
-        CarStatsLog.logPowerState(state.mState);
+        CarStatsLogHelper.logPowerState(state.mState);
         mCurrentState = state;
         switch (state.mState) {
             case CpmsState.WAIT_FOR_VHAL:
@@ -405,129 +416,157 @@
 
         mSystemInterface.setDisplayState(true);
         sendPowerManagerEvent(CarPowerStateListener.ON);
+
         mHal.sendOn();
 
         try {
             switchUserOnResumeIfNecessary(allowUserSwitch);
         } catch (Exception e) {
-            Log.e(CarLog.TAG_POWER, "Could not switch user on resume: " + e);
+            Log.e(CarLog.TAG_POWER, "Could not switch user on resume", e);
         }
+
+        setVoiceInteractionDisabled(false);
     }
 
-    private void switchUserIfCurrentUserIsGuest() {
-        int currentUserId = ActivityManager.getCurrentUser();
-        UserInfo currentUserInfo = mUserManager.getUserInfo(currentUserId);
-        boolean isGuest = currentUserInfo.isGuest();
-        if (!isGuest) {
-            return;
-        }
-        Log.d(CarLog.TAG_POWER, "Switching into new guest user before going to sleep");
-        doSwitchFromGuestToNewGuest(currentUserInfo);
-    }
-
-    private void switchUserOnResumeIfNecessary(boolean allowSwitching) {
-        int targetUserId = mCarUserManagerHelper.getInitialUser();
-        if (targetUserId == UserHandle.USER_SYSTEM) {
-            // API explicitly say it doesn't return USER_SYSTEM
-            Log.wtf(CarLog.TAG_POWER, "getInitialUser() returned system user");
-            return;
-        }
-        int currentUserId = ActivityManager.getCurrentUser();
-        UserInfo targetUserInfo = mUserManager.getUserInfo(targetUserId);
-        boolean isTargetPersistent = !targetUserInfo.isEphemeral();
-        boolean isTargetGuest = targetUserInfo.isGuest();
-        Log.d(CarLog.TAG_POWER, "getTargetUserId(): current=" + currentUserId
-                + ", target=" + targetUserInfo.toFullString()
-                + ", isTargetPersistent=" + isTargetPersistent + ", isTargetGuest=" + isTargetGuest
-                + ", allowSwitching: " + allowSwitching);
-
-        if (isTargetPersistent && !isTargetGuest) {
-            if (!allowSwitching) {
-                Log.d(CarLog.TAG_POWER, "Not switching to " + targetUserId
-                        + " because it's not allowed");
+    @VisibleForTesting // Ideally it should not be exposed, but it speeds up the unit tests
+    void switchUserOnResumeIfNecessary(boolean allowSwitching) {
+        Log.d(TAG, "switchUserOnResumeIfNecessary(): allowSwitching=" + allowSwitching
+                + ", mSwitchGuestUserBeforeSleep=" + mSwitchGuestUserBeforeSleep);
+        if (!allowSwitching) {
+            if (mSwitchGuestUserBeforeSleep) { // already handled
                 return;
             }
-            if (currentUserId == targetUserId) {
-                Log.v(CarLog.TAG_POWER, "no need to switch to (same user) " + currentUserId);
-                return;
-            }
-            // All good - switch to the requested user
-            switchToUser(currentUserId, targetUserId, /* reason= */ null);
+            switchToNewGuestIfNecessary();
             return;
         }
 
-        if (!isTargetGuest) {
-            // Shouldn't happen (unless OEM is explicitly creating ephemeral users, which
-            // doesn't make much sense), but it doesn't hurt to log...
-            Log.w(CarLog.TAG_POWER, "target user is ephemeral but not a guest: "
-                    + targetUserInfo.toFullString());
-            if (allowSwitching) {
-                switchToUser(currentUserId, targetUserId, /* reason= */ null);
-            }
-            return;
-        } else if (isTargetPersistent) {
-            // TODO(b/146380030): decide whether we should delete it or not
-            // Shouldn't happen neither, but it's not a big deal (guest will be replaced below
-            // anyway), but it's worth logging as well...
-            Log.w(CarLog.TAG_POWER, "target user is a non-ephemeral guest: "
-                    + targetUserInfo.toFullString());
-        }
-
-        // At this point, target user is a guest - we cannot resume into an ephemeral guest for
-        // privacy reasons, so we need to create a new guest and switch to it (even if the OEM
-        // doesn't allow switching)
-        if (mSwitchGuestUserBeforeSleep) { // already handled
+        if (CarProperties.user_hal_enabled().orElse(false) && mUserService.isUserHalSupported()) {
+            switchUserOnResumeIfNecessaryUsingHal();
             return;
         }
 
-        doSwitchFromGuestToNewGuest(targetUserInfo);
+        executeDefaultInitialUserBehavior(!mSwitchGuestUserBeforeSleep);
     }
 
-    private void doSwitchFromGuestToNewGuest(UserInfo currentGuest) {
-        boolean marked = mUserManager.markGuestForDeletion(currentGuest.id);
-        if (!marked) {
-            Log.w(CarLog.TAG_POWER,
-                    "Could not mark guest user " + currentGuest.id + " for deletion");
+    private void executeDefaultInitialUserBehavior(boolean replaceGuest) {
+        mInitialUserSetter.set(newInitialUserInfoBuilder(InitialUserSetter.TYPE_DEFAULT_BEHAVIOR)
+                .setReplaceGuest(replaceGuest)
+                .build());
+    }
+
+    /**
+     * Replaces the current user if it's a guest.
+     */
+    private void switchToNewGuestIfNecessary() {
+        int currentUserId = ActivityManager.getCurrentUser();
+        UserInfo currentUser = mUserManager.getUserInfo(currentUserId);
+
+        UserInfo newUser = mInitialUserSetter.replaceGuestIfNeeded(currentUser);
+        if (newUser == currentUser) return; // Not a guest
+
+        boolean replaceGuest = !mSwitchGuestUserBeforeSleep;
+        if (newUser == null) {
+            Log.w(TAG, "Failed to replace guest; falling back to default behavior");
+            executeDefaultInitialUserBehavior(replaceGuest);
             return;
         }
+        switchUser(newUser.id, replaceGuest);
+    }
 
-        UserInfo newGuest = mUserManager.createGuest(mContext, mNewGuestName);
+    private void switchUser(@UserIdInt int userId, boolean replaceGuest) {
+        mInitialUserSetter.set(newInitialUserInfoBuilder(InitialUserSetter.TYPE_SWITCH)
+                .setSwitchUserId(userId).setReplaceGuest(replaceGuest).build());
+    }
 
-        if (newGuest != null) {
-            switchToUser(currentGuest.id, newGuest.id, "Created new guest");
-            Log.d(CarLog.TAG_POWER, "Removing previous guest " + currentGuest.id);
-            mUserManager.removeUser(currentGuest.id);
-        } else {
-            Log.wtf(CarLog.TAG_POWER, "Could not create new guest");
-            // TODO(b/146380030): decide whether we should switch to SYSTEM
+    private InitialUserSetter.Builder newInitialUserInfoBuilder(@InitialUserInfoType int type) {
+        return new InitialUserSetter.Builder(type)
+                .setSupportsOverrideUserIdProperty(!mUserService.isUserHalSupported());
+    }
+
+    /**
+     * Tells Garage Mode if it should run normally, or just
+     * exit immediately without indicating 'idle'
+     * @return True if no idle jobs should be run
+     * @hide
+     */
+    public boolean garageModeShouldExitImmediately() {
+        synchronized (mLock) {
+            return mGarageModeShouldExitImmediately;
         }
     }
 
-    private void switchToUser(@UserIdInt int fromUser, @UserIdInt int toUser,
-            @Nullable String reason) {
-        StringBuilder message = new StringBuilder();
-        if (reason == null) {
-            message.append("Desired user changed");
-        } else {
-            message.append(reason);
-        }
-        message.append(", switching from ").append(fromUser).append(" to ").append(toUser);
-        Log.i(CarLog.TAG_POWER, message.toString());
-        mCarUserManagerHelper.switchToUserId(toUser);
+    /**
+     * Switches the initial user by calling the User HAL to define the behavior.
+     */
+    private void switchUserOnResumeIfNecessaryUsingHal() {
+        Log.i(TAG, "Using User HAL to define initial user behavior");
+        mUserService.getInitialUserInfo(InitialUserInfoRequestType.RESUME, (status, response) -> {
+            switch (status) {
+                case HalCallback.STATUS_HAL_RESPONSE_TIMEOUT:
+                case HalCallback.STATUS_HAL_SET_TIMEOUT:
+                    switchUserOnResumeUserHalFallback("timeout");
+                    return;
+                case HalCallback.STATUS_CONCURRENT_OPERATION:
+                    switchUserOnResumeUserHalFallback("concurrent call");
+                    return;
+                case HalCallback.STATUS_WRONG_HAL_RESPONSE:
+                    switchUserOnResumeUserHalFallback("wrong response");
+                    return;
+                case HalCallback.STATUS_HAL_NOT_SUPPORTED:
+                    switchUserOnResumeUserHalFallback("Hal not supported");
+                    return;
+                case HalCallback.STATUS_OK:
+                    if (response == null) {
+                        switchUserOnResumeUserHalFallback("no response");
+                        return;
+                    }
+                    boolean replaceGuest = !mSwitchGuestUserBeforeSleep;
+                    switch (response.action) {
+                        case InitialUserInfoResponseAction.DEFAULT:
+                            Log.i(TAG, "HAL requested default initial user behavior");
+                            executeDefaultInitialUserBehavior(replaceGuest);
+                            return;
+                        case InitialUserInfoResponseAction.SWITCH:
+                            int userId = response.userToSwitchOrCreate.userId;
+                            Log.i(TAG, "HAL requested switch to user " + userId);
+                            // If guest was replaced on shutdown, it doesn't need to be replaced
+                            // again
+                            switchUser(userId, replaceGuest);
+                            return;
+                        case InitialUserInfoResponseAction.CREATE:
+                            int halFlags = response.userToSwitchOrCreate.flags;
+                            String name = response.userNameToCreate;
+                            Log.i(TAG, "HAL requested new user (name="
+                                    + UserHelper.safeName(name) + ", flags="
+                                    + UserHalHelper.userFlagsToString(halFlags) + ")");
+                            mInitialUserSetter
+                                    .set(newInitialUserInfoBuilder(InitialUserSetter.TYPE_CREATE)
+                                            .setNewUserName(name)
+                                            .setNewUserFlags(halFlags)
+                                            .build());
+                            return;
+                        default:
+                            switchUserOnResumeUserHalFallback(
+                                    "invalid response action: " + response.action);
+                            return;
+                    }
+                default:
+                    switchUserOnResumeUserHalFallback("invalid status: " + status);
+            }
+        });
     }
 
-    private int getFirstSwitchableUser() {
-        List<UserInfo> allUsers = mUserManager.getUsers();
-        for (UserInfo user : allUsers) {
-            if (user.id != UserHandle.USER_SYSTEM) {
-                return user.id;
-            }
-        }
-        Log.wtf(CarLog.TAG_POWER, "no switchable user: " + allUsers);
-        return UserHandle.USER_NULL;
+    /**
+     * Switches the initial user directly when the User HAL call failed.
+     */
+    private void switchUserOnResumeUserHalFallback(String reason) {
+        Log.w(TAG, "Failed to set initial user based on User Hal (" + reason
+                + "); falling back to default behavior");
+        executeDefaultInitialUserBehavior(!mSwitchGuestUserBeforeSleep);
     }
 
     private void handleShutdownPrepare(CpmsState newState) {
+        setVoiceInteractionDisabled(true);
         mSystemInterface.setDisplayState(false);
         // Shutdown on finish if the system doesn't support deep sleep or doesn't allow it.
         synchronized (mLock) {
@@ -535,23 +574,15 @@
                     || !mHal.isDeepSleepAllowed()
                     || !mSystemInterface.isSystemSupportingDeepSleep()
                     || !newState.mCanSleep;
+            mGarageModeShouldExitImmediately = !newState.mCanPostpone;
         }
-        if (newState.mCanPostpone) {
-            Log.i(CarLog.TAG_POWER, "starting shutdown prepare");
-            sendPowerManagerEvent(CarPowerStateListener.SHUTDOWN_PREPARE);
-            mHal.sendShutdownPrepare();
-            doHandlePreprocessing();
-        } else {
-            Log.i(CarLog.TAG_POWER, "starting shutdown immediately");
-            synchronized (mLock) {
-                releaseTimerLocked();
-            }
-            // Notify hal that we are shutting down and since it is immediate, don't schedule next
-            // wake up
-            mHal.sendShutdownStart(0);
-            // shutdown HU
-            mSystemInterface.shutdown();
-        }
+        Log.i(CarLog.TAG_POWER,
+                (newState.mCanPostpone
+                ? "starting shutdown prepare with Garage Mode"
+                        : "starting shutdown prepare without Garage Mode"));
+        sendPowerManagerEvent(CarPowerStateListener.SHUTDOWN_PREPARE);
+        mHal.sendShutdownPrepare();
+        doHandlePreprocessing();
     }
 
     // Simulate system shutdown to Deep Sleep
@@ -567,7 +598,9 @@
         sendPowerManagerEvent(state.mCarPowerStateListenerState);
         int wakeupSec;
         synchronized (mLock) {
-            wakeupSec = mNextWakeupSec;
+            // If we're shutting down immediately, don't schedule
+            // a wakeup time.
+            wakeupSec = mGarageModeShouldExitImmediately ? 0 : mNextWakeupSec;
         }
         switch (state.mCarPowerStateListenerState) {
             case CarPowerStateListener.SUSPEND_ENTER:
@@ -601,6 +634,8 @@
                 throw new AssertionError("Should not return from PowerManager.reboot()");
             }
         }
+        setVoiceInteractionDisabled(true);
+
         if (mustShutDown) {
             // shutdown HU
             mSystemInterface.shutdown();
@@ -610,6 +645,14 @@
         mShutdownOnNextSuspend = false;
     }
 
+    private void setVoiceInteractionDisabled(boolean disabled) {
+        try {
+            mVoiceInteractionManagerService.setDisabled(disabled);
+        } catch (RemoteException e) {
+            Log.w(TAG, "setVoiceIntefactionDisabled(" + disabled + ") failed", e);
+        }
+    }
+
     @GuardedBy("mLock")
     private void releaseTimerLocked() {
         if (mTimer != null) {
@@ -620,13 +663,18 @@
     }
 
     private void doHandlePreprocessing() {
-        int pollingCount = (sShutdownPrepareTimeMs / SHUTDOWN_POLLING_INTERVAL_MS) + 1;
+        int intervalMs;
+        int pollingCount;
+        synchronized (mLock) {
+            intervalMs = mShutdownPollingIntervalMs;
+            pollingCount = (mShutdownPrepareTimeMs / mShutdownPollingIntervalMs) + 1;
+        }
         if (Build.IS_USERDEBUG || Build.IS_ENG) {
             int shutdownPrepareTimeOverrideInSecs =
                     SystemProperties.getInt(PROP_MAX_GARAGE_MODE_DURATION_OVERRIDE, -1);
             if (shutdownPrepareTimeOverrideInSecs >= 0) {
                 pollingCount =
-                        (shutdownPrepareTimeOverrideInSecs * 1000 / SHUTDOWN_POLLING_INTERVAL_MS)
+                        (shutdownPrepareTimeOverrideInSecs * 1000 / intervalMs)
                                 + 1;
                 Log.i(CarLog.TAG_POWER,
                         "Garage mode duration overridden secs:"
@@ -634,7 +682,7 @@
             }
         }
         Log.i(CarLog.TAG_POWER, "processing before shutdown expected for: "
-                + sShutdownPrepareTimeMs + " ms, adding polling:" + pollingCount);
+                + mShutdownPrepareTimeMs + " ms, adding polling:" + pollingCount);
         synchronized (mLock) {
             mProcessingStartTime = SystemClock.elapsedRealtime();
             releaseTimerLocked();
@@ -643,10 +691,10 @@
             mTimer.scheduleAtFixedRate(
                     new ShutdownProcessingTimerTask(pollingCount),
                     0 /*delay*/,
-                    SHUTDOWN_POLLING_INTERVAL_MS);
+                    intervalMs);
         }
         if (mSwitchGuestUserBeforeSleep) {
-            switchUserIfCurrentUserIsGuest();
+            switchToNewGuestIfNecessary();
         }
     }
 
@@ -705,11 +753,7 @@
         // keep holding partial wakelock to prevent entering sleep before enterDeepSleep call
         // enterDeepSleep should force sleep entry even if wake lock is kept.
         mSystemInterface.switchToPartialWakeLock();
-        PowerHandler handler;
-        synchronized (mLock) {
-            handler = mHandler;
-        }
-        handler.cancelProcessingComplete();
+        mHandler.cancelProcessingComplete();
         synchronized (mLock) {
             mLastSleepEntryTime = SystemClock.elapsedRealtime();
         }
@@ -718,18 +762,18 @@
             simulateSleepByWaiting();
             nextListenerState = CarPowerStateListener.SHUTDOWN_CANCELLED;
         } else {
-            boolean sleepSucceeded = mSystemInterface.enterDeepSleep();
+            boolean sleepSucceeded = suspendWithRetries();
             if (!sleepSucceeded) {
-                // Suspend failed! VHAL should transition CPMS to shutdown.
-                Log.e(CarLog.TAG_POWER, "Sleep did not succeed. Now attempting to shut down.");
-                mSystemInterface.shutdown();
+                // Suspend failed and we shut down instead.
+                // We either won't get here at all or we will power off very soon.
                 return;
             }
+            // We suspended and have now resumed
             nextListenerState = CarPowerStateListener.SUSPEND_EXIT;
         }
-        // On resume, reset nextWakeup time. If not set again, system will suspend/shutdown forever.
         synchronized (mLock) {
             mIsResuming = true;
+            // Any wakeup time from before is no longer valid.
             mNextWakeupSec = 0;
         }
         Log.i(CarLog.TAG_POWER, "Resuming after suspending");
@@ -737,39 +781,54 @@
         onApPowerStateChange(CpmsState.WAIT_FOR_VHAL, nextListenerState);
     }
 
-    private boolean needPowerStateChangeLocked(CpmsState newState) {
-        if (newState == null) {
-            return false;
-        } else if (mCurrentState == null) {
+    private boolean needPowerStateChangeLocked(@NonNull CpmsState newState) {
+        if (mCurrentState == null) {
             return true;
         } else if (mCurrentState.equals(newState)) {
+            Log.d(CarLog.TAG_POWER, "Requested state is already in effect: "
+                    + newState.name());
             return false;
         }
 
         // The following switch/case enforces the allowed state transitions.
+        boolean transitionAllowed = false;
         switch (mCurrentState.mState) {
             case CpmsState.WAIT_FOR_VHAL:
-                return (newState.mState == CpmsState.ON)
+                transitionAllowed = (newState.mState == CpmsState.ON)
                     || (newState.mState == CpmsState.SHUTDOWN_PREPARE);
+                break;
             case CpmsState.SUSPEND:
-                return newState.mState == CpmsState.WAIT_FOR_VHAL;
+                transitionAllowed =  newState.mState == CpmsState.WAIT_FOR_VHAL;
+                break;
             case CpmsState.ON:
-                return (newState.mState == CpmsState.SHUTDOWN_PREPARE)
+                transitionAllowed = (newState.mState == CpmsState.SHUTDOWN_PREPARE)
                     || (newState.mState == CpmsState.SIMULATE_SLEEP);
+                break;
             case CpmsState.SHUTDOWN_PREPARE:
-                // If VHAL sends SHUTDOWN_IMMEDIATELY while in SHUTDOWN_PREPARE state, do it.
-                return ((newState.mState == CpmsState.SHUTDOWN_PREPARE) && !newState.mCanPostpone)
-                    || (newState.mState == CpmsState.WAIT_FOR_FINISH)
-                    || (newState.mState == CpmsState.WAIT_FOR_VHAL);
+                // If VHAL sends SHUTDOWN_IMMEDIATELY or SLEEP_IMMEDIATELY while in
+                // SHUTDOWN_PREPARE state, do it.
+                transitionAllowed =
+                        ((newState.mState == CpmsState.SHUTDOWN_PREPARE) && !newState.mCanPostpone)
+                                || (newState.mState == CpmsState.WAIT_FOR_FINISH)
+                                || (newState.mState == CpmsState.WAIT_FOR_VHAL);
+                break;
             case CpmsState.SIMULATE_SLEEP:
-                return true;
+                transitionAllowed = true;
+                break;
             case CpmsState.WAIT_FOR_FINISH:
-                return newState.mState == CpmsState.SUSPEND;
+                transitionAllowed = (newState.mState == CpmsState.SUSPEND
+                        || newState.mState == CpmsState.WAIT_FOR_VHAL);
+                break;
             default:
-                Log.e(CarLog.TAG_POWER, "Unhandled state transition:  currentState="
+                Log.e(CarLog.TAG_POWER, "Unexpected current state:  currentState="
                         + mCurrentState.name() + ", newState=" + newState.name());
-                return false;
+                transitionAllowed = true;
         }
+        if (!transitionAllowed) {
+            Log.e(CarLog.TAG_POWER, "Requested power transition is not allowed: "
+                    + mCurrentState.name() + " --> " + newState.name());
+        }
+        return transitionAllowed;
     }
 
     private void doHandleProcessingComplete() {
@@ -784,16 +843,13 @@
             listenerState = mShutdownOnFinish
                     ? CarPowerStateListener.SHUTDOWN_ENTER : CarPowerStateListener.SUSPEND_ENTER;
         }
+
         onApPowerStateChange(CpmsState.WAIT_FOR_FINISH, listenerState);
     }
 
     @Override
     public void onDisplayBrightnessChange(int brightness) {
-        PowerHandler handler;
-        synchronized (mLock) {
-            handler = mHandler;
-        }
-        handler.handleDisplayBrightnessChange(brightness);
+        mHandler.handleDisplayBrightnessChange(brightness);
     }
 
     private void doHandleDisplayBrightnessChange(int brightness) {
@@ -805,11 +861,7 @@
     }
 
     public void handleMainDisplayChanged(boolean on) {
-        PowerHandler handler;
-        synchronized (mLock) {
-            handler = mHandler;
-        }
-        handler.handleMainDisplayStateChange(on);
+        mHandler.handleMainDisplayStateChange(on);
     }
 
     /**
@@ -824,9 +876,8 @@
      * Get the PowerHandler that we use to change power states
      */
     public Handler getHandler() {
-        synchronized (mLock) {
-            return mHandler;
-        }
+        return mHandler;
+
     }
 
     // Binder interface for general use.
@@ -881,6 +932,7 @@
 
     @Override
     public void scheduleNextWakeupTime(int seconds) {
+        ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
         if (seconds < 0) {
             Log.w(CarLog.TAG_POWER, "Next wake up time is negative. Ignoring!");
             return;
@@ -902,11 +954,20 @@
         }
     }
 
-    private void finishedImpl(IBinder binder) {
-        boolean allAreComplete = false;
+    @Override
+    public int getPowerState() {
+        ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
         synchronized (mLock) {
-            boolean oneWasRemoved = mListenersWeAreWaitingFor.remove(binder);
-            allAreComplete = oneWasRemoved && mListenersWeAreWaitingFor.isEmpty();
+            return (mCurrentState == null) ? CarPowerStateListener.INVALID
+                    : mCurrentState.mCarPowerStateListenerState;
+        }
+    }
+
+    private void finishedImpl(IBinder binder) {
+        boolean allAreComplete;
+        synchronized (mLock) {
+            mListenersWeAreWaitingFor.remove(binder);
+            allAreComplete = mListenersWeAreWaitingFor.isEmpty();
         }
         if (allAreComplete) {
             signalComplete();
@@ -933,7 +994,9 @@
         }
     }
 
-    private class PowerHandler extends Handler {
+    private static final class PowerHandler extends Handler {
+        private static final String TAG = PowerHandler.class.getSimpleName();
+
         private final int MSG_POWER_STATE_CHANGE = 0;
         private final int MSG_DISPLAY_BRIGHTNESS_CHANGE = 1;
         private final int MSG_MAIN_DISPLAY_STATE_CHANGE = 2;
@@ -943,8 +1006,11 @@
         // display off due to rear view camera and delivery to here.
         private final long MAIN_DISPLAY_EVENT_DELAY_MS = 500;
 
-        private PowerHandler(Looper looper) {
+        private final WeakReference<CarPowerManagementService> mService;
+
+        private PowerHandler(Looper looper, CarPowerManagementService service) {
             super(looper);
+            mService = new WeakReference<CarPowerManagementService>(service);
         }
 
         private void handlePowerStateChange() {
@@ -982,18 +1048,23 @@
 
         @Override
         public void handleMessage(Message msg) {
+            CarPowerManagementService service = mService.get();
+            if (service == null) {
+                Log.i(TAG, "handleMessage null service");
+                return;
+            }
             switch (msg.what) {
                 case MSG_POWER_STATE_CHANGE:
-                    doHandlePowerStateChange();
+                    service.doHandlePowerStateChange();
                     break;
                 case MSG_DISPLAY_BRIGHTNESS_CHANGE:
-                    doHandleDisplayBrightnessChange(msg.arg1);
+                    service.doHandleDisplayBrightnessChange(msg.arg1);
                     break;
                 case MSG_MAIN_DISPLAY_STATE_CHANGE:
-                    doHandleMainDisplayStateChange((Boolean) msg.obj);
+                    service.doHandleMainDisplayStateChange((Boolean) msg.obj);
                     break;
                 case MSG_PROCESSING_COMPLETE:
-                    doHandleProcessingComplete();
+                    service.doHandleProcessingComplete();
                     break;
             }
         }
@@ -1028,6 +1099,37 @@
         }
     }
 
+    // Send the command to enter Suspend to RAM.
+    // If the command is not successful, try again.
+    // If it fails repeatedly, send the command to shut down.
+    // Returns true if we successfully suspended.
+    private boolean suspendWithRetries() {
+        final int maxTries = 3;
+        final long retryIntervalMs = 10;
+        int tryCount = 0;
+
+        while (true) {
+            Log.i(CarLog.TAG_POWER, "Entering Suspend to RAM");
+            boolean suspendSucceeded = mSystemInterface.enterDeepSleep();
+            if (suspendSucceeded) {
+                return true;
+            }
+            tryCount++;
+            if (tryCount >= maxTries) {
+                break;
+            }
+            // We failed to suspend. Block the thread briefly and try again.
+            Log.w(CarLog.TAG_POWER, "Failed to Suspend; will retry later.");
+            try {
+                Thread.sleep(retryIntervalMs);
+            } catch (InterruptedException ignored) { }
+        }
+        // Too many failures trying to suspend. Shut down.
+        Log.w(CarLog.TAG_POWER, "Could not Suspend to RAM. Shutting down.");
+        mSystemInterface.shutdown();
+        return false;
+    }
+
     private static class CpmsState {
         // NOTE: When modifying states below, make sure to update CarPowerStateChanged.State in
         //   frameworks/base/cmds/statsd/src/atoms.proto also.
@@ -1164,7 +1266,7 @@
      */
     public void forceSimulatedResume() {
         PowerHandler handler;
-        synchronized (this) {
+        synchronized (mLock) {
             // Cancel Garage Mode in case it's running
             mPendingPowerStates.addFirst(new CpmsState(CpmsState.WAIT_FOR_VHAL,
                                                        CarPowerStateListener.SHUTDOWN_CANCELLED));
@@ -1192,6 +1294,7 @@
         synchronized (mSimulationWaitObject) {
             mInSimulatedDeepSleepMode = true;
             mWakeFromSimulatedSleep = false;
+            mGarageModeShouldExitImmediately = false;
         }
         PowerHandler handler;
         synchronized (mLock) {
diff --git a/service/src/com/android/car/CarProjectionService.java b/service/src/com/android/car/CarProjectionService.java
index 5d15d8f..7cac89a 100644
--- a/service/src/com/android/car/CarProjectionService.java
+++ b/service/src/com/android/car/CarProjectionService.java
@@ -26,14 +26,12 @@
 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
-import static android.net.wifi.WifiManager.WIFI_FREQUENCY_BAND_5GHZ;
 
 import android.annotation.Nullable;
 import android.app.ActivityOptions;
 import android.bluetooth.BluetoothDevice;
 import android.car.CarProjectionManager;
 import android.car.CarProjectionManager.ProjectionAccessPointCallback;
-import android.car.CarProjectionManager.ProjectionKeyEventHandler;
 import android.car.ICarProjection;
 import android.car.ICarProjectionKeyEventHandler;
 import android.car.ICarProjectionStatusListener;
@@ -49,15 +47,17 @@
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.graphics.Rect;
-import android.net.wifi.WifiConfiguration;
+import android.net.MacAddress;
+import android.net.wifi.SoftApConfiguration;
+import android.net.wifi.WifiClient;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiManager.LocalOnlyHotspotCallback;
 import android.net.wifi.WifiManager.LocalOnlyHotspotReservation;
-import android.net.wifi.WifiManager.SoftApCallback;
 import android.net.wifi.WifiScanner;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.IBinder;
 import android.os.Message;
 import android.os.Messenger;
@@ -609,14 +609,14 @@
 
         if (mSoftApCallback == null) {
             mSoftApCallback = new ProjectionSoftApCallback();
-            mWifiManager.registerSoftApCallback(mSoftApCallback, mHandler);
+            mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
             ensureApConfiguration();
         }
 
-        if (!mWifiManager.startSoftAp(null /* use existing config*/)) {
+        if (!mWifiManager.startTetheredHotspot(null /* use existing config*/)) {
             // The indicates that AP might be already started.
             if (mWifiManager.getWifiApState() == WIFI_AP_STATE_ENABLED) {
-                sendApStarted(mWifiManager.getWifiApConfiguration());
+                sendApStarted(mWifiManager.getSoftApConfiguration());
             } else {
                 Log.e(TAG, "Failed to start soft AP");
                 sendApFailed(ERROR_GENERIC);
@@ -639,7 +639,7 @@
     private void startLocalOnlyApLocked() {
         if (mLocalOnlyHotspotReservation != null) {
             Log.i(TAG, "Local-only hotspot is already registered.");
-            sendApStarted(mLocalOnlyHotspotReservation.getWifiConfiguration());
+            sendApStarted(mLocalOnlyHotspotReservation.getSoftApConfiguration());
             return;
         }
 
@@ -651,7 +651,7 @@
                 synchronized (mLock) {
                     mLocalOnlyHotspotReservation = reservation;
                 }
-                sendApStarted(reservation.getWifiConfiguration());
+                sendApStarted(reservation.getSoftApConfiguration());
             }
 
             @Override
@@ -707,18 +707,19 @@
         mLocalOnlyHotspotReservation = null;
     }
 
-    private void sendApStarted(WifiConfiguration wifiConfiguration) {
-        WifiConfiguration localWifiConfig = new WifiConfiguration(wifiConfiguration);
-        localWifiConfig.BSSID = mApBssid;
-
+    private void sendApStarted(SoftApConfiguration softApConfiguration) {
+        SoftApConfiguration localSoftApConfig =
+                new SoftApConfiguration.Builder(softApConfiguration)
+                .setBssid(MacAddress.fromString(mApBssid))
+                .build();
         Message message = Message.obtain();
         message.what = CarProjectionManager.PROJECTION_AP_STARTED;
-        message.obj = localWifiConfig;
+        message.obj = localSoftApConfig;
         Log.i(TAG, "Sending PROJECTION_AP_STARTED, ssid: "
-                + localWifiConfig.getPrintableSsid()
-                + ", apBand: " + localWifiConfig.apBand
-                + ", apChannel: " + localWifiConfig.apChannel
-                + ", bssid: " + localWifiConfig.BSSID);
+                + localSoftApConfig.getSsid()
+                + ", apBand: " + localSoftApConfig.getBand()
+                + ", apChannel: " + localSoftApConfig.getChannel()
+                + ", bssid: " + localSoftApConfig.getBssid());
         sendApStatusMessage(message);
     }
 
@@ -937,15 +938,15 @@
 
     private void ensureApConfiguration() {
         // Always prefer 5GHz configuration whenever it is available.
-        WifiConfiguration apConfig = mWifiManager.getWifiApConfiguration();
-        if (apConfig != null && apConfig.apBand != WIFI_FREQUENCY_BAND_5GHZ
+        SoftApConfiguration apConfig = mWifiManager.getSoftApConfiguration();
+        if (apConfig != null && apConfig.getBand() != SoftApConfiguration.BAND_5GHZ
                 && mWifiManager.is5GHzBandSupported()) {
-            apConfig.apBand = WIFI_FREQUENCY_BAND_5GHZ;
-            mWifiManager.setWifiApConfiguration(apConfig);
+            mWifiManager.setSoftApConfiguration(new SoftApConfiguration.Builder(apConfig)
+                    .setBand(SoftApConfiguration.BAND_5GHZ).build());
         }
     }
 
-    private class ProjectionSoftApCallback implements SoftApCallback {
+    private class ProjectionSoftApCallback implements WifiManager.SoftApCallback {
         private boolean mCurrentStateCall = true;
 
         @Override
@@ -963,7 +964,7 @@
 
             switch (state) {
                 case WifiManager.WIFI_AP_STATE_ENABLED: {
-                    sendApStarted(mWifiManager.getWifiApConfiguration());
+                    sendApStarted(mWifiManager.getSoftApConfiguration());
                     break;
                 }
                 case WifiManager.WIFI_AP_STATE_DISABLED: {
@@ -987,8 +988,11 @@
         }
 
         @Override
-        public void onNumClientsChanged(int numClients) {
-            Log.i(TAG, "ProjectionSoftApCallback, onNumClientsChanged: " + numClients);
+        public void onConnectedClientsChanged(List<WifiClient> clients) {
+            if (DBG) {
+                Log.d(TAG, "ProjectionSoftApCallback, onConnectedClientsChanged with "
+                        + clients.size() + " clients");
+            }
         }
     }
 
diff --git a/service/src/com/android/car/CarPropertyService.java b/service/src/com/android/car/CarPropertyService.java
index c9a14c9..00b0d93 100644
--- a/service/src/com/android/car/CarPropertyService.java
+++ b/service/src/com/android/car/CarPropertyService.java
@@ -25,6 +25,8 @@
 import android.car.hardware.property.ICarProperty;
 import android.car.hardware.property.ICarPropertyEventListener;
 import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
@@ -32,21 +34,23 @@
 import android.util.SparseArray;
 
 import com.android.car.hal.PropertyHalService;
+import com.android.internal.annotations.GuardedBy;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * This class implements the binder interface for ICarProperty.aidl to make it easier to create
- * multiple managers that deal with Vehicle Properties. To create a new service, simply extend
- * this class and call the super() constructor with the appropriate arguments for the new service.
- * {@link CarHvacService} shows the basic usage.
+ * multiple managers that deal with Vehicle Properties. The property Ids in this class are IDs in
+ * manager level.
  */
 public class CarPropertyService extends ICarProperty.Stub
         implements CarServiceBase, PropertyHalService.PropertyHalListener {
@@ -54,11 +58,17 @@
     private static final String TAG = "Property.service";
     private final Context mContext;
     private final Map<IBinder, Client> mClientMap = new ConcurrentHashMap<>();
-    private Map<Integer, CarPropertyConfig<?>> mConfigs;
+    @GuardedBy("mLock")
+    private final Map<Integer, CarPropertyConfig<?>> mConfigs = new HashMap<>();
     private final PropertyHalService mHal;
     private boolean mListenerIsSet = false;
     private final Map<Integer, List<Client>> mPropIdClientMap = new ConcurrentHashMap<>();
     private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private final SparseArray<SparseArray<Client>> mSetOperationClientMap = new SparseArray<>();
+    private final HandlerThread mHandlerThread =
+            CarServiceUtils.getHandlerThread(getClass().getSimpleName());
+    private final Handler mHandler = new Handler(mHandlerThread.getLooper());
 
     public CarPropertyService(Context context, PropertyHalService hal) {
         if (DBG) {
@@ -136,12 +146,13 @@
 
     @Override
     public void init() {
-        if (mConfigs == null) {
+        synchronized (mLock) {
             // Cache the configs list to avoid subsequent binder calls
-            mConfigs = mHal.getPropertyList();
-            if (DBG) {
-                Log.d(TAG, "cache CarPropertyConfigs " + mConfigs.size());
-            }
+            mConfigs.clear();
+            mConfigs.putAll(mHal.getPropertyList());
+        }
+        if (DBG) {
+            Log.d(TAG, "cache CarPropertyConfigs " + mConfigs.size());
         }
     }
 
@@ -154,10 +165,36 @@
         mPropIdClientMap.clear();
         mHal.setListener(null);
         mListenerIsSet = false;
+        synchronized (mLock) {
+            mSetOperationClientMap.clear();
+        }
     }
 
     @Override
     public void dump(PrintWriter writer) {
+        writer.println("*CarPropertyService*");
+        synchronized (mLock) {
+            writer.println("    Listener is set for PropertyHalService: " + mListenerIsSet);
+            writer.println("    There are " + mClientMap.size() + " clients "
+                    + "using CarPropertyService.");
+            writer.println("    Properties registered: ");
+            for (int propId : mPropIdClientMap.keySet()) {
+                writer.println("        propId: 0x" + toHexString(propId)
+                        + " is registered by " + mPropIdClientMap.get(propId).size()
+                        + " client(s).");
+            }
+            writer.println("    Properties changed by CarPropertyService: ");
+            for (int i = 0; i < mSetOperationClientMap.size(); i++) {
+                int propId = mSetOperationClientMap.keyAt(i);
+                SparseArray areaIdToClient = mSetOperationClientMap.valueAt(i);
+                for (int j = 0; j < areaIdToClient.size(); j++) {
+                    int areaId = areaIdToClient.keyAt(j);
+                    writer.println("        propId: 0x" + toHexString(propId)
+                            + " areaId: 0x" + toHexString(areaId)
+                            + " by client: " + areaIdToClient.valueAt(j));
+                }
+            }
+        }
     }
 
     @Override
@@ -165,21 +202,24 @@
         if (DBG) {
             Log.d(TAG, "registerListener: propId=0x" + toHexString(propId) + " rate=" + rate);
         }
-        if (mConfigs.get(propId) == null) {
-            // Do not attempt to register an invalid propId
-            Log.e(TAG, "registerListener:  propId is not in config list:  " + propId);
-            return;
-        }
-        ICarImpl.assertPermission(mContext, mHal.getReadPermission(propId));
         if (listener == null) {
             Log.e(TAG, "registerListener: Listener is null.");
             throw new IllegalArgumentException("listener cannot be null.");
         }
 
         IBinder listenerBinder = listener.asBinder();
-
+        CarPropertyConfig propertyConfig;
+        Client finalClient;
         synchronized (mLock) {
-            // Get the client for this listener
+            propertyConfig = mConfigs.get(propId);
+            if (propertyConfig == null) {
+                // Do not attempt to register an invalid propId
+                Log.e(TAG, "registerListener:  propId is not in config list: 0x" + toHexString(
+                        propId));
+                return;
+            }
+            ICarImpl.assertPermission(mContext, mHal.getReadPermission(propId));
+            // Get or create the client for this listener
             Client client = mClientMap.get(listenerBinder);
             if (client == null) {
                 client = new Client(listener);
@@ -202,29 +242,36 @@
             if (rate > mHal.getSampleRate(propId)) {
                 mHal.subscribeProperty(propId, rate);
             }
+            finalClient = client;
         }
-        // Send the latest value(s) to the registering listener only
-        List<CarPropertyEvent> events = new LinkedList<CarPropertyEvent>();
-        if (mConfigs.get(propId).isGlobalProperty()) {
+
+        // propertyConfig and client are NonNull.
+        mHandler.post(() ->
+                getAndDispatchPropertyInitValue(propertyConfig, finalClient));
+    }
+
+    private void getAndDispatchPropertyInitValue(CarPropertyConfig config, Client client) {
+        List<CarPropertyEvent> events = new LinkedList<>();
+        int propId = config.getPropertyId();
+        if (config.isGlobalProperty()) {
             CarPropertyValue value = mHal.getProperty(propId, 0);
-            // CarPropertyEvent without a CarPropertyValue can not be used by any listeners.
             if (value != null) {
                 CarPropertyEvent event = new CarPropertyEvent(
-                    CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, value);
+                        CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, value);
                 events.add(event);
             }
         } else {
-            for (int areaId : mConfigs.get(propId).getAreaIds()) {
+            for (int areaId : config.getAreaIds()) {
                 CarPropertyValue value = mHal.getProperty(propId, areaId);
                 if (value != null) {
                     CarPropertyEvent event = new CarPropertyEvent(
-                        CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, value);
+                            CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, value);
                     events.add(event);
                 }
             }
         }
         try {
-            listener.onEvent(events);
+            client.getListener().onEvent(events);
         } catch (RemoteException ex) {
             // If we cannot send a record, its likely the connection snapped. Let the binder
             // death handle the situation.
@@ -252,16 +299,20 @@
     private void unregisterListenerBinderLocked(int propId, IBinder listenerBinder) {
         Client client = mClientMap.get(listenerBinder);
         List<Client> propertyClients = mPropIdClientMap.get(propId);
-        if (mConfigs.get(propId) == null) {
-            // Do not attempt to register an invalid propId
-            Log.e(TAG, "unregisterListener: propId is not in config list:0x" + toHexString(propId));
-            return;
+        synchronized (mLock) {
+            if (mConfigs.get(propId) == null) {
+                // Do not attempt to register an invalid propId
+                Log.e(TAG, "unregisterListener: propId is not in config list:0x" + toHexString(
+                        propId));
+                return;
+            }
         }
         if ((client == null) || (propertyClients == null)) {
             Log.e(TAG, "unregisterListenerBinderLocked: Listener was not previously registered.");
         } else {
             if (propertyClients.remove(client)) {
                 client.removeProperty(propId);
+                clearSetOperationRecorderLocked(propId, client);
             } else {
                 Log.e(TAG, "unregisterListenerBinderLocked: Listener was not registered for "
                            + "propId=0x" + toHexString(propId));
@@ -271,6 +322,7 @@
                 // Last listener for this property unsubscribed.  Clean up
                 mHal.unsubscribeProperty(propId);
                 mPropIdClientMap.remove(propId);
+                mSetOperationClientMap.remove(propId);
                 if (mPropIdClientMap.isEmpty()) {
                     // No more properties are subscribed.  Turn off the listener.
                     mHal.setListener(null);
@@ -297,7 +349,11 @@
     @Override
     public List<CarPropertyConfig> getPropertyList() {
         List<CarPropertyConfig> returnList = new ArrayList<CarPropertyConfig>();
-        for (CarPropertyConfig c : mConfigs.values()) {
+        Set<CarPropertyConfig> allConfigs;
+        synchronized (mLock) {
+            allConfigs = new HashSet<>(mConfigs.values());
+        }
+        for (CarPropertyConfig c : allConfigs) {
             if (ICarImpl.hasPermission(mContext, mHal.getReadPermission(c.getPropertyId()))) {
                 // Only add properties the list if the process has permissions to read it
                 returnList.add(c);
@@ -311,10 +367,12 @@
 
     @Override
     public CarPropertyValue getProperty(int prop, int zone) {
-        if (mConfigs.get(prop) == null) {
-            // Do not attempt to register an invalid propId
-            Log.e(TAG, "getProperty: propId is not in config list:0x" + toHexString(prop));
-            return null;
+        synchronized (mLock) {
+            if (mConfigs.get(prop) == null) {
+                // Do not attempt to register an invalid propId
+                Log.e(TAG, "getProperty: propId is not in config list:0x" + toHexString(prop));
+                return null;
+            }
         }
         ICarImpl.assertPermission(mContext, mHal.getReadPermission(prop));
         return mHal.getProperty(prop, zone);
@@ -322,38 +380,100 @@
 
     @Override
     public String getReadPermission(int propId) {
-        if (mConfigs.get(propId) == null) {
-            // Property ID does not exist
-            Log.e(TAG, "getReadPermission: propId is not in config list:0x" + toHexString(propId));
-            return null;
+        synchronized (mLock) {
+            if (mConfigs.get(propId) == null) {
+                // Property ID does not exist
+                Log.e(TAG,
+                        "getReadPermission: propId is not in config list:0x" + toHexString(propId));
+                return null;
+            }
         }
         return mHal.getReadPermission(propId);
     }
 
     @Override
     public String getWritePermission(int propId) {
-        if (mConfigs.get(propId) == null) {
-            // Property ID does not exist
-            Log.e(TAG, "getWritePermission: propId is not in config list:0x" + toHexString(propId));
-            return null;
+        synchronized (mLock) {
+            if (mConfigs.get(propId) == null) {
+                // Property ID does not exist
+                Log.e(TAG, "getWritePermission: propId is not in config list:0x" + toHexString(
+                        propId));
+                return null;
+            }
         }
         return mHal.getWritePermission(propId);
     }
 
     @Override
-    public void setProperty(CarPropertyValue prop) {
+    public void setProperty(CarPropertyValue prop, ICarPropertyEventListener listener) {
         int propId = prop.getPropertyId();
-        if (mConfigs.get(propId) == null) {
-            // Do not attempt to register an invalid propId
-            Log.e(TAG, "setProperty:  propId is not in config list:0x" + toHexString(propId));
-            return;
-        }
-        ICarImpl.assertPermission(mContext, mHal.getWritePermission(propId));
+        checkPropertyAccessibility(propId);
         // need an extra permission for writing display units properties.
         if (mHal.isDisplayUnitsProperty(propId)) {
             ICarImpl.assertPermission(mContext, Car.PERMISSION_VENDOR_EXTENSION);
         }
         mHal.setProperty(prop);
+        IBinder listenerBinder = listener.asBinder();
+        synchronized (mLock) {
+            Client client = mClientMap.get(listenerBinder);
+            if (client == null) {
+                client = new Client(listener);
+            }
+            updateSetOperationRecorder(propId, prop.getAreaId(), client);
+        }
+    }
+
+    // The helper method checks if the vehicle has implemented this property and the property
+    // is accessible or not for platform and client.
+    private void checkPropertyAccessibility(int propId) {
+        // Checks if the car implemented the property or not.
+        synchronized (mLock) {
+            if (mConfigs.get(propId) == null) {
+                throw new IllegalArgumentException("Property Id: 0x" + Integer.toHexString(propId)
+                        + " does not exist in the vehicle");
+            }
+        }
+
+        // Checks if android has permission to write property.
+        String propertyWritePermission = mHal.getWritePermission(propId);
+        if (propertyWritePermission == null) {
+            throw new SecurityException("Platform does not have permission to change value for "
+                    + "property Id: 0x" + Integer.toHexString(propId));
+        }
+        // Checks if the client has the permission.
+        ICarImpl.assertPermission(mContext, propertyWritePermission);
+    }
+
+    // Updates recorder for set operation.
+    private void updateSetOperationRecorder(int propId, int areaId, Client client) {
+        if (mSetOperationClientMap.get(propId) != null) {
+            mSetOperationClientMap.get(propId).put(areaId, client);
+        } else {
+            SparseArray<Client> areaIdToClient = new SparseArray<>();
+            areaIdToClient.put(areaId, client);
+            mSetOperationClientMap.put(propId, areaIdToClient);
+        }
+    }
+
+    // Clears map when client unregister for property.
+    private void clearSetOperationRecorderLocked(int propId, Client client) {
+        SparseArray<Client> areaIdToClient = mSetOperationClientMap.get(propId);
+        if (areaIdToClient != null) {
+            List<Integer> indexNeedToRemove = new ArrayList<>();
+            for (int index = 0; index < areaIdToClient.size(); index++) {
+                if (client.equals(areaIdToClient.valueAt(index))) {
+                    indexNeedToRemove.add(index);
+                }
+            }
+
+            for (int index : indexNeedToRemove) {
+                if (DBG) {
+                    Log.d("ErrorEvent", " Clear propId:0x" + toHexString(propId)
+                            + " areaId: 0x" + toHexString(areaIdToClient.keyAt(index)));
+                }
+                areaIdToClient.removeAt(index);
+            }
+        }
     }
 
     // Implement PropertyHalListener interface
@@ -396,23 +516,33 @@
     }
 
     @Override
-    public void onPropertySetError(int property, int area) {
-        List<Client> clients = mPropIdClientMap.get(property);
-        if (clients != null) {
-            List<CarPropertyEvent> eventList = new LinkedList<>();
-            eventList.add(CarPropertyEvent.createErrorEvent(property, area));
-            for (Client c : clients) {
-                try {
-                    c.getListener().onEvent(eventList);
-                } catch (RemoteException ex) {
-                    // If we cannot send a record, its likely the connection snapped. Let the binder
-                    // death handle the situation.
-                    Log.e(TAG, "onEvent calling failed: " + ex);
-                }
+    public void onPropertySetError(int property, int areaId, int errorCode) {
+        Client lastOperatedClient = null;
+        synchronized (mLock) {
+            if (mSetOperationClientMap.get(property) != null
+                    && mSetOperationClientMap.get(property).get(areaId) != null) {
+                lastOperatedClient = mSetOperationClientMap.get(property).get(areaId);
+            } else {
+                Log.e(TAG, "Can not find the client changed propertyId: 0x"
+                        + toHexString(property) + " in areaId: 0x" + toHexString(areaId));
             }
-        } else {
-            Log.e(TAG, "onPropertySetError called with no listener registered for propId=0x"
-                    + toHexString(property));
+
+        }
+        if (lastOperatedClient != null) {
+            dispatchToLastClient(property, areaId, errorCode, lastOperatedClient);
+        }
+    }
+
+    private void dispatchToLastClient(int property, int areaId, int errorCode,
+            Client lastOperatedClient) {
+        try {
+            List<CarPropertyEvent> eventList = new LinkedList<>();
+            eventList.add(
+                    CarPropertyEvent.createErrorEventWithErrorCode(property, areaId,
+                            errorCode));
+            lastOperatedClient.getListener().onEvent(eventList);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "onEvent calling failed: " + ex);
         }
     }
 }
diff --git a/service/src/com/android/car/CarService.java b/service/src/com/android/car/CarService.java
index 044c791..a0db99d 100644
--- a/service/src/com/android/car/CarService.java
+++ b/service/src/com/android/car/CarService.java
@@ -30,10 +30,12 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.util.EventLog;
 import android.util.Log;
 
 import com.android.car.systeminterface.SystemInterface;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.car.EventLogTags;
 import com.android.internal.util.RingBufferIndices;
 
 import java.io.FileDescriptor;
@@ -77,6 +79,7 @@
         Log.i(CarLog.TAG_SERVICE, "Service onCreate");
         mCanBusErrorNotifier = new CanBusErrorNotifier(this /* context */);
         mVehicle = getVehicle();
+        EventLog.writeEvent(EventLogTags.CAR_SERVICE_CREATE, mVehicle == null ? 0 : 1);
 
         if (mVehicle == null) {
             throw new IllegalStateException("Vehicle HAL service is not available.");
@@ -88,6 +91,7 @@
         }
 
         Log.i(CarLog.TAG_SERVICE, "Connected to " + mVehicleInterfaceName);
+        EventLog.writeEvent(EventLogTags.CAR_SERVICE_CONNECTED, mVehicleInterfaceName);
 
         mICarImpl = new ICarImpl(this,
                 mVehicle,
@@ -99,7 +103,6 @@
         linkToDeath(mVehicle, mVehicleDeathRecipient);
 
         ServiceManager.addService("car_service", mICarImpl);
-        ServiceManager.addService("car_stats", mICarImpl.getStatsService());
         SystemProperties.set("boot.car_service_created", "1");
         super.onCreate();
     }
@@ -109,6 +112,7 @@
     // cleanup task that you want to make sure happens on shutdown/reboot, see OnShutdownReboot.
     @Override
     public void onDestroy() {
+        EventLog.writeEvent(EventLogTags.CAR_SERVICE_CREATE, mVehicle == null ? 0 : 1);
         Log.i(CarLog.TAG_SERVICE, "Service onDestroy");
         mICarImpl.release();
         mCanBusErrorNotifier.removeFailureReport(this);
@@ -167,21 +171,23 @@
 
     @Nullable
     private static IVehicle getVehicle() {
+        final String instanceName = SystemProperties.get("ro.vehicle.hal", "default");
+
         try {
-            return android.hardware.automotive.vehicle.V2_0.IVehicle.getService();
+            return android.hardware.automotive.vehicle.V2_0.IVehicle.getService(instanceName);
         } catch (RemoteException e) {
-            Log.e(CarLog.TAG_SERVICE, "Failed to get IVehicle service", e);
+            Log.e(CarLog.TAG_SERVICE, "Failed to get IVehicle/" + instanceName + " service", e);
         } catch (NoSuchElementException e) {
-            Log.e(CarLog.TAG_SERVICE, "IVehicle service not registered yet");
+            Log.e(CarLog.TAG_SERVICE, "IVehicle/" + instanceName + " service not registered yet");
         }
         return null;
     }
 
     private class VehicleDeathRecipient implements DeathRecipient {
-        private int deathCount = 0;
 
         @Override
         public void serviceDied(long cookie) {
+            EventLog.writeEvent(EventLogTags.CAR_SERVICE_VHAL_DIED, cookie);
             if (RESTART_CAR_SERVICE_WHEN_VHAL_CRASH) {
                 Log.wtf(CarLog.TAG_SERVICE, "***Vehicle HAL died. Car service will restart***");
                 Process.killProcess(Process.myPid());
diff --git a/service/src/com/android/car/CarServiceUtils.java b/service/src/com/android/car/CarServiceUtils.java
index be8b0d5..046c059 100644
--- a/service/src/com/android/car/CarServiceUtils.java
+++ b/service/src/com/android/car/CarServiceUtils.java
@@ -21,16 +21,29 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Binder;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.Looper;
+import android.os.SystemClock;
+import android.util.ArrayMap;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
 import java.util.List;
 
 /** Utility class */
 public final class CarServiceUtils {
 
+    private static final String TAG = "CAR.UTIL";
+    /** Empty int array */
+    public  static final int[] EMPTY_INT_ARRAY = new int[0];
+
     private static final String PACKAGE_NOT_FOUND = "Package not found:";
 
+    /** K: class name, V: HandlerThread */
+    private static final ArrayMap<String, HandlerThread> sHandlerThreads = new ArrayMap<>();
+
     /** do not construct. static only */
     private CarServiceUtils() {};
 
@@ -166,4 +179,64 @@
         }
         return array;
     }
+
+    /**
+     * Returns delta between elapsed time to uptime = {@link SystemClock#elapsedRealtime()} -
+     * {@link SystemClock#uptimeMillis()}. Note that this value will be always >= 0.
+     */
+    public static long getUptimeToElapsedTimeDeltaInMillis() {
+        int retry = 0;
+        int max_retry = 2; // try only up to twice
+        while (true) {
+            long elapsed1 = SystemClock.elapsedRealtime();
+            long uptime = SystemClock.uptimeMillis();
+            long elapsed2 = SystemClock.elapsedRealtime();
+            if (elapsed1 == elapsed2) { // avoid possible 1 ms fluctuation.
+                return elapsed1 - uptime;
+            }
+            retry++;
+            if (retry >= max_retry) {
+                return elapsed1 - uptime;
+            }
+        }
+    }
+
+    /**
+     * Gets a static instance of {@code HandlerThread} for the given {@code name}. If the thread
+     * does not exist, create one and start it before returning.
+     */
+    public static HandlerThread getHandlerThread(String name) {
+        synchronized (sHandlerThreads) {
+            HandlerThread thread = sHandlerThreads.get(name);
+            if (thread == null || !thread.isAlive()) {
+                Log.i(TAG, "Starting HandlerThread:" + name);
+                thread = new HandlerThread(name);
+                thread.start();
+                sHandlerThreads.put(name, thread);
+            }
+            return thread;
+        }
+    }
+
+    /**
+     * Finishes all queued {@code Handler} tasks for {@code HandlerThread} created via
+     * {@link #getHandlerThread(String)}. This is useful only for testing.
+     */
+    @VisibleForTesting
+    public static void finishAllHandlerTasks() {
+        ArrayList<HandlerThread> threads;
+        synchronized (sHandlerThreads) {
+            threads = new ArrayList<>(sHandlerThreads.values());
+        }
+        ArrayList<SyncRunnable> syncs = new ArrayList<>(threads.size());
+        for (int i = 0; i < threads.size(); i++) {
+            Handler handler = new Handler(threads.get(i).getLooper());
+            SyncRunnable sr = new SyncRunnable(() -> { });
+            handler.post(sr);
+            syncs.add(sr);
+        }
+        for (int i = 0; i < syncs.size(); i++) {
+            syncs.get(i).waitForComplete();
+        }
+    }
 }
diff --git a/service/src/com/android/car/CarShellCommand.java b/service/src/com/android/car/CarShellCommand.java
new file mode 100644
index 0000000..e1282ab
--- /dev/null
+++ b/service/src/com/android/car/CarShellCommand.java
@@ -0,0 +1,1516 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car;
+
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue.ASSOCIATE_CURRENT_USER;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue.DISASSOCIATE_ALL_USERS;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue.DISASSOCIATE_CURRENT_USER;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.CUSTOM_1;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.CUSTOM_2;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.CUSTOM_3;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.CUSTOM_4;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.KEY_FOB;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.UiModeManager;
+import android.car.Car;
+import android.car.input.CarInputManager;
+import android.car.input.RotaryEvent;
+import android.car.user.CarUserManager;
+import android.car.user.UserCreationResult;
+import android.car.user.UserIdentificationAssociationResponse;
+import android.car.user.UserRemovalResult;
+import android.car.user.UserSwitchResult;
+import android.car.userlib.HalCallback;
+import android.car.userlib.UserHalHelper;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.automotive.vehicle.V2_0.CreateUserRequest;
+import android.hardware.automotive.vehicle.V2_0.CreateUserStatus;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
+import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
+import android.hardware.automotive.vehicle.V2_0.SwitchUserMessageType;
+import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
+import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
+import android.hardware.automotive.vehicle.V2_0.UserFlags;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociation;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationValue;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetAssociation;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
+import android.hardware.automotive.vehicle.V2_0.UserInfo;
+import android.hardware.automotive.vehicle.V2_0.UsersInfo;
+import android.hardware.automotive.vehicle.V2_0.VehicleArea;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Process;
+import android.os.ShellCommand;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.KeyEvent;
+
+import com.android.car.am.FixedActivityService;
+import com.android.car.audio.CarAudioService;
+import com.android.car.garagemode.GarageModeService;
+import com.android.car.hal.InputHalService;
+import com.android.car.hal.UserHalService;
+import com.android.car.hal.VehicleHal;
+import com.android.car.pm.CarPackageManagerService;
+import com.android.car.systeminterface.SystemInterface;
+import com.android.car.trust.CarTrustedDeviceService;
+import com.android.car.user.CarUserService;
+import com.android.internal.infra.AndroidFuture;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+final class CarShellCommand extends ShellCommand {
+
+    private static final String NO_INITIAL_USER = "N/A";
+
+    private static final String TAG = CarShellCommand.class.getSimpleName();
+    private static final boolean VERBOSE = false;
+
+    private static final String COMMAND_HELP = "-h";
+    private static final String COMMAND_DAY_NIGHT_MODE = "day-night-mode";
+    private static final String COMMAND_INJECT_VHAL_EVENT = "inject-vhal-event";
+    private static final String COMMAND_INJECT_ERROR_EVENT = "inject-error-event";
+    private static final String COMMAND_ENABLE_UXR = "enable-uxr";
+    private static final String COMMAND_GARAGE_MODE = "garage-mode";
+    private static final String COMMAND_GET_DO_ACTIVITIES = "get-do-activities";
+    private static final String COMMAND_GET_CARPROPERTYCONFIG = "get-carpropertyconfig";
+    private static final String COMMAND_GET_PROPERTY_VALUE = "get-property-value";
+    private static final String COMMAND_PROJECTION_AP_TETHERING = "projection-tethering";
+    private static final String COMMAND_PROJECTION_UI_MODE = "projection-ui-mode";
+    private static final String COMMAND_RESUME = "resume";
+    private static final String COMMAND_SUSPEND = "suspend";
+    private static final String COMMAND_ENABLE_TRUSTED_DEVICE = "enable-trusted-device";
+    private static final String COMMAND_REMOVE_TRUSTED_DEVICES = "remove-trusted-devices";
+    private static final String COMMAND_SET_UID_TO_ZONE = "set-audio-zone-for-uid";
+    private static final String COMMAND_START_FIXED_ACTIVITY_MODE = "start-fixed-activity-mode";
+    private static final String COMMAND_STOP_FIXED_ACTIVITY_MODE = "stop-fixed-activity-mode";
+    private static final String COMMAND_ENABLE_FEATURE = "enable-feature";
+    private static final String COMMAND_DISABLE_FEATURE = "disable-feature";
+    private static final String COMMAND_INJECT_KEY = "inject-key";
+    private static final String COMMAND_INJECT_ROTARY = "inject-rotary";
+    private static final String COMMAND_GET_INITIAL_USER_INFO = "get-initial-user-info";
+    private static final String COMMAND_SWITCH_USER = "switch-user";
+    private static final String COMMAND_REMOVE_USER = "remove-user";
+    private static final String COMMAND_CREATE_USER = "create-user";
+    private static final String COMMAND_GET_INITIAL_USER = "get-initial-user";
+    private static final String COMMAND_SET_USER_ID_TO_OCCUPANT_ZONE =
+            "set-occupant-zone-for-user";
+    private static final String COMMAND_RESET_USER_ID_IN_OCCUPANT_ZONE =
+            "reset-user-in-occupant-zone";
+    private static final String COMMAND_GET_USER_AUTH_ASSOCIATION =
+            "get-user-auth-association";
+    private static final String COMMAND_SET_USER_AUTH_ASSOCIATION =
+            "set-user-auth-association";
+
+    // Whitelist of commands allowed in user build. All these command should be protected with
+    // a permission. K: command, V: required permission.
+    // Only commands with permission already granted to shell user should be allowed.
+    // Commands that can affect safety should be never allowed in user build.
+    private static final ArrayMap<String, String> USER_BUILD_COMMAND_TO_PERMISSION_MAP;
+    static {
+        USER_BUILD_COMMAND_TO_PERMISSION_MAP = new ArrayMap<>();
+        USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_GARAGE_MODE,
+                android.Manifest.permission.DEVICE_POWER);
+        USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_RESUME,
+                android.Manifest.permission.DEVICE_POWER);
+        USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SUSPEND,
+                android.Manifest.permission.DEVICE_POWER);
+        USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_GET_INITIAL_USER,
+                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+        USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_GET_INITIAL_USER_INFO,
+                android.Manifest.permission.MANAGE_USERS);
+        USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SWITCH_USER,
+                android.Manifest.permission.MANAGE_USERS);
+        USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_REMOVE_USER,
+                android.Manifest.permission.MANAGE_USERS);
+        USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_CREATE_USER,
+                android.Manifest.permission.MANAGE_USERS);
+        USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_GET_USER_AUTH_ASSOCIATION,
+                android.Manifest.permission.MANAGE_USERS);
+        USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SET_USER_AUTH_ASSOCIATION,
+                android.Manifest.permission.MANAGE_USERS);
+    }
+
+    private static final String DEVICE_POWER_PERMISSION = "android.permission.DEVICE_POWER";
+
+    private static final String PARAM_DAY_MODE = "day";
+    private static final String PARAM_NIGHT_MODE = "night";
+    private static final String PARAM_SENSOR_MODE = "sensor";
+    private static final String PARAM_VEHICLE_PROPERTY_AREA_GLOBAL = "0";
+    private static final String PARAM_ON_MODE = "on";
+    private static final String PARAM_OFF_MODE = "off";
+    private static final String PARAM_QUERY_MODE = "query";
+    private static final String PARAM_REBOOT = "reboot";
+
+    private static final int RESULT_OK = 0;
+    private static final int RESULT_ERROR = -1; // Arbitrary value, any non-0 is fine
+
+    private static final int DEFAULT_HAL_TIMEOUT_MS = 1_000;
+
+    private static final int INVALID_USER_AUTH_TYPE_OR_VALUE = -1;
+
+    private static final SparseArray<String> VALID_USER_AUTH_TYPES;
+    private static final String VALID_USER_AUTH_TYPES_HELP;
+
+    private static final SparseArray<String> VALID_USER_AUTH_SET_VALUES;
+    private static final String VALID_USER_AUTH_SET_VALUES_HELP;
+
+    static {
+        VALID_USER_AUTH_TYPES = new SparseArray<String>(5);
+        VALID_USER_AUTH_TYPES.put(KEY_FOB, UserIdentificationAssociationType.toString(KEY_FOB));
+        VALID_USER_AUTH_TYPES.put(CUSTOM_1, UserIdentificationAssociationType.toString(CUSTOM_1));
+        VALID_USER_AUTH_TYPES.put(CUSTOM_2, UserIdentificationAssociationType.toString(CUSTOM_2));
+        VALID_USER_AUTH_TYPES.put(CUSTOM_3, UserIdentificationAssociationType.toString(CUSTOM_3));
+        VALID_USER_AUTH_TYPES.put(CUSTOM_4, UserIdentificationAssociationType.toString(CUSTOM_4));
+        VALID_USER_AUTH_TYPES_HELP = getHelpString("types", VALID_USER_AUTH_TYPES);
+
+        VALID_USER_AUTH_SET_VALUES = new SparseArray<String>(3);
+        VALID_USER_AUTH_SET_VALUES.put(ASSOCIATE_CURRENT_USER,
+                UserIdentificationAssociationSetValue.toString(ASSOCIATE_CURRENT_USER));
+        VALID_USER_AUTH_SET_VALUES.put(DISASSOCIATE_CURRENT_USER,
+                UserIdentificationAssociationSetValue.toString(DISASSOCIATE_CURRENT_USER));
+        VALID_USER_AUTH_SET_VALUES.put(DISASSOCIATE_ALL_USERS,
+                UserIdentificationAssociationSetValue.toString(DISASSOCIATE_ALL_USERS));
+        VALID_USER_AUTH_SET_VALUES_HELP = getHelpString("values", VALID_USER_AUTH_SET_VALUES);
+    }
+
+    @NonNull
+    private static String getHelpString(@NonNull String name, @NonNull SparseArray<String> values) {
+        StringBuilder help = new StringBuilder("Valid ").append(name).append(" are: ");
+        int size = values.size();
+        for (int i = 0; i < size; i++) {
+            help.append(values.valueAt(i));
+            if (i != size - 1) {
+                help.append(", ");
+            }
+        }
+        return help.append('.').toString();
+    }
+
+    private final Context mContext;
+    private final VehicleHal mHal;
+    private final CarAudioService mCarAudioService;
+    private final CarPackageManagerService mCarPackageManagerService;
+    private final CarProjectionService mCarProjectionService;
+    private final CarPowerManagementService mCarPowerManagementService;
+    private final CarTrustedDeviceService mCarTrustedDeviceService;
+    private final FixedActivityService mFixedActivityService;
+    private final CarFeatureController mFeatureController;
+    private final CarInputService mCarInputService;
+    private final CarNightService mCarNightService;
+    private final SystemInterface mSystemInterface;
+    private final GarageModeService mGarageModeService;
+    private final CarUserService mCarUserService;
+    private final CarOccupantZoneService mCarOccupantZoneService;
+
+    CarShellCommand(Context context,
+            VehicleHal hal,
+            CarAudioService carAudioService,
+            CarPackageManagerService carPackageManagerService,
+            CarProjectionService carProjectionService,
+            CarPowerManagementService carPowerManagementService,
+            CarTrustedDeviceService carTrustedDeviceService,
+            FixedActivityService fixedActivityService,
+            CarFeatureController featureController,
+            CarInputService carInputService,
+            CarNightService carNightService,
+            SystemInterface systemInterface,
+            GarageModeService garageModeService,
+            CarUserService carUserService,
+            CarOccupantZoneService carOccupantZoneService) {
+        mContext = context;
+        mHal = hal;
+        mCarAudioService = carAudioService;
+        mCarPackageManagerService = carPackageManagerService;
+        mCarProjectionService = carProjectionService;
+        mCarPowerManagementService = carPowerManagementService;
+        mCarTrustedDeviceService = carTrustedDeviceService;
+        mFixedActivityService = fixedActivityService;
+        mFeatureController = featureController;
+        mCarInputService = carInputService;
+        mCarNightService = carNightService;
+        mSystemInterface = systemInterface;
+        mGarageModeService = garageModeService;
+        mCarUserService = carUserService;
+        mCarOccupantZoneService = carOccupantZoneService;
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            onHelp();
+            return RESULT_ERROR;
+        }
+        ArrayList<String> argsList = new ArrayList<>();
+        argsList.add(cmd);
+        String arg = null;
+        do {
+            arg = getNextArg();
+            if (arg != null) {
+                argsList.add(arg);
+            }
+        } while (arg != null);
+        String[] args = new String[argsList.size()];
+        argsList.toArray(args);
+        return exec(args, getOutPrintWriter());
+    }
+
+    @Override
+    public void onHelp() {
+        showHelp(getOutPrintWriter());
+    }
+
+    private static void showHelp(PrintWriter pw) {
+        pw.println("Car service commands:");
+        pw.println("\t-h");
+        pw.println("\t  Print this help text.");
+        pw.println("\tday-night-mode [day|night|sensor]");
+        pw.println("\t  Force into day/night mode or restore to auto.");
+        pw.println("\tinject-vhal-event property [zone] data(can be comma separated list) "
+                + "[-t delay_time_seconds]");
+        pw.println("\t  Inject a vehicle property for testing.");
+        pw.println("\t  delay_time_seconds: the event timestamp is increased by certain second.");
+        pw.println("\t  If not specified, it will be 0.");
+        pw.println("\tinject-error-event property zone errorCode");
+        pw.println("\t  Inject an error event from VHAL for testing.");
+        pw.println("\tenable-uxr true|false");
+        pw.println("\t  Enable/Disable UX restrictions and App blocking.");
+        pw.println("\tgarage-mode [on|off|query|reboot]");
+        pw.println("\t  Force into or out of garage mode, or check status.");
+        pw.println("\t  With 'reboot', enter garage mode, then reboot when it completes.");
+        pw.println("\tget-do-activities pkgname");
+        pw.println("\t  Get Distraction Optimized activities in given package.");
+        pw.println("\tget-carpropertyconfig [propertyId]");
+        pw.println("\t  Get a CarPropertyConfig by Id in Hex or list all CarPropertyConfigs");
+        pw.println("\tget-property-value [propertyId] [areaId]");
+        pw.println("\t  Get a vehicle property value by property id in Hex and areaId");
+        pw.println("\t  or list all property values for all areaId");
+        pw.println("\tsuspend");
+        pw.println("\t  Suspend the system to Deep Sleep.");
+        pw.println("\tresume");
+        pw.println("\t  Wake the system up after a 'suspend.'");
+        pw.println("\tenable-trusted-device true|false");
+        pw.println("\t  Enable/Disable Trusted device feature.");
+        pw.println("\tremove-trusted-devices");
+        pw.println("\t  Remove all trusted devices for the current foreground user.");
+        pw.println("\tprojection-tethering [true|false]");
+        pw.println("\t  Whether tethering should be used when creating access point for"
+                + " wireless projection");
+        pw.println("\t--metrics");
+        pw.println("\t  When used with dumpsys, only metrics will be in the dumpsys output.");
+        pw.printf("\t%s [zoneid] [uid]\n", COMMAND_SET_UID_TO_ZONE);
+        pw.println("\t  Maps the audio zoneid to uid.");
+        pw.println("\tstart-fixed-activity displayId packageName activityName");
+        pw.println("\t  Start an Activity the specified display as fixed mode");
+        pw.println("\tstop-fixed-mode displayId");
+        pw.println("\t  Stop fixed Activity mode for the given display. "
+                + "The Activity will not be restarted upon crash.");
+        pw.println("\tenable-feature featureName");
+        pw.println("\t  Enable the requested feature. Change will happen after reboot.");
+        pw.println("\t  This requires root/su.");
+        pw.println("\tdisable-feature featureName");
+        pw.println("\t  Disable the requested feature. Change will happen after reboot");
+        pw.println("\t  This requires root/su.");
+        pw.println("\tinject-key [-d display] [-t down_delay_ms] key_code");
+        pw.println("\t  inject key down / up event to car service");
+        pw.println("\t  display: 0 for main, 1 for cluster. If not specified, it will be 0.");
+        pw.println("\t  down_delay_ms: delay from down to up key event. If not specified,");
+        pw.println("\t                 it will be 0");
+        pw.println("\t  key_code: int key code defined in android KeyEvent");
+        pw.println("\tinject-rotary [-d display] [-i input_type] [-c clockwise]");
+        pw.println("\t              [-dt delta_times_ms]");
+        pw.println("\t  inject rotary input event to car service.");
+        pw.println("\t  display: 0 for main, 1 for cluster. If not specified, it will be 0.");
+        pw.println("\t  input_type: 10 for navigation controller input, 11 for volume");
+        pw.println("\t              controller input. If not specified, it will be 10.");
+        pw.println("\t  clockwise: true if the event is clockwise, false if the event is");
+        pw.println("\t             counter-clockwise. If not specified, it will be false.");
+        pw.println("\t  delta_times_ms: a list of delta time (current time minus event time)");
+        pw.println("\t                  in descending order. If not specified, it will be 0.");
+
+        pw.printf("\t%s <REQ_TYPE> [--hal-only] [--timeout TIMEOUT_MS]\n",
+                COMMAND_GET_INITIAL_USER_INFO);
+        pw.println("\t  Calls the Vehicle HAL to get the initial boot info, passing the given");
+        pw.println("\t  REQ_TYPE (which could be either FIRST_BOOT, FIRST_BOOT_AFTER_OTA, ");
+        pw.println("\t  COLD_BOOT, RESUME, or any numeric value that would be passed 'as-is')");
+        pw.println("\t  and an optional TIMEOUT_MS to wait for the HAL response (if not set,");
+        pw.println("\t  it will use a  default value).");
+        pw.println("\t  The --hal-only option only calls HAL, without using CarUserService.");
+
+        pw.printf("\t%s <USER_ID> [--hal-only] [--timeout TIMEOUT_MS]\n", COMMAND_SWITCH_USER);
+        pw.println("\t  Switches to user USER_ID using the HAL integration.");
+        pw.println("\t  The --hal-only option only calls HAL, without switching the user,");
+        pw.println("\t  while the --timeout defines how long to wait for the HAL response.");
+
+        pw.printf("\t%s <USER_ID> [--hal-only]\n", COMMAND_REMOVE_USER);
+        pw.println("\t  Removes user with USER_ID using the HAL integration.");
+        pw.println("\t  The --hal-only option only calls HAL, without removing the user,");
+
+        pw.printf("\t%s [--hal-only] [--timeout TIMEOUT_MS] [--type TYPE] [--flags FLAGS] [NAME]\n",
+                COMMAND_CREATE_USER);
+        pw.println("\t  Creates a new user using the HAL integration.");
+        pw.println("\t  The --hal-only uses UserManager to create the user,");
+        pw.println("\t  while the --timeout defines how long to wait for the HAL response.");
+
+        pw.printf("\t%s\n", COMMAND_GET_INITIAL_USER);
+        pw.printf("\t  Gets the id of the initial user (or %s when it's not available)\n",
+                NO_INITIAL_USER);
+
+        pw.printf("\t%s [occupantZoneId] [userId]\n", COMMAND_SET_USER_ID_TO_OCCUPANT_ZONE);
+        pw.println("\t  Maps the occupant zone id to user id.");
+        pw.printf("\t%s [occupantZoneId]\n", COMMAND_RESET_USER_ID_IN_OCCUPANT_ZONE);
+        pw.println("\t  Unmaps the user assigned to occupant zone id.");
+
+        pw.printf("\t%s [--hal-only] [--user USER_ID] TYPE1 [..TYPE_N]\n",
+                COMMAND_GET_USER_AUTH_ASSOCIATION);
+        pw.println("\t  Gets the N user authentication values for the N types for the given user");
+        pw.println("\t  (or current user when not specified).");
+        pw.println("\t  By defautt it calls CarUserManager, but using --hal-only will call just "
+                + "UserHalService.");
+
+        pw.printf("\t%s [--hal-only] [--user USER_ID] TYPE1 VALUE1 [..TYPE_N VALUE_N]\n",
+                COMMAND_SET_USER_AUTH_ASSOCIATION);
+        pw.println("\t  Sets the N user authentication types with the N values for the given user");
+        pw.println("\t  (or current user when not specified).");
+        pw.println("\t  By defautt it calls CarUserManager, but using --hal-only will call just "
+                + "UserHalService.");
+
+        pw.printf("\t  %s\n", VALID_USER_AUTH_TYPES_HELP);
+        pw.printf("\t  %s\n", VALID_USER_AUTH_SET_VALUES_HELP);
+    }
+
+    private static int showInvalidArguments(PrintWriter pw) {
+        pw.println("Incorrect number of arguments.");
+        showHelp(pw);
+        return RESULT_ERROR;
+    }
+
+    private void runSetZoneIdForUid(String zoneString, String uidString) {
+        int uid = Integer.parseInt(uidString);
+        int zoneId = Integer.parseInt(zoneString);
+        mCarAudioService.setZoneIdForUid(zoneId, uid);
+    }
+
+    private void runSetOccupantZoneIdForUserId(String occupantZoneIdString,
+            String userIdString) {
+        int userId = Integer.parseInt(userIdString);
+        int occupantZoneId = Integer.parseInt(occupantZoneIdString);
+        if (!mCarOccupantZoneService.assignProfileUserToOccupantZone(occupantZoneId, userId)) {
+            throw new IllegalStateException("Failed to set userId " + userId + " to occupantZoneId "
+                    + occupantZoneIdString);
+        }
+    }
+
+    private void runResetOccupantZoneId(String occupantZoneIdString) {
+        int occupantZoneId = Integer.parseInt(occupantZoneIdString);
+        if (!mCarOccupantZoneService
+                .assignProfileUserToOccupantZone(occupantZoneId, UserHandle.USER_NULL)) {
+            throw new IllegalStateException("Failed to reset occupantZoneId "
+                    + occupantZoneIdString);
+        }
+    }
+
+    int exec(String[] args, PrintWriter writer) {
+        String cmd = args[0];
+        String requiredPermission = USER_BUILD_COMMAND_TO_PERMISSION_MAP.get(cmd);
+        if (VERBOSE) {
+            Log.v(TAG, "cmd: " + cmd + ", requiredPermission: " + requiredPermission);
+        }
+        if (Build.IS_USER && requiredPermission == null) {
+            throw new SecurityException("The command " + cmd + "requires non-user build");
+        }
+        if (requiredPermission != null) {
+            if (!ICarImpl.hasPermission(mContext, requiredPermission)) {
+                throw new SecurityException("The command " + cmd + "requires permission:"
+                        + requiredPermission);
+            }
+        }
+        switch (cmd) {
+            case COMMAND_HELP:
+                showHelp(writer);
+                break;
+            case COMMAND_DAY_NIGHT_MODE: {
+                String value = args.length < 2 ? "" : args[1];
+                forceDayNightMode(value, writer);
+                break;
+            }
+            case COMMAND_GARAGE_MODE: {
+                String value = args.length < 2 ? "" : args[1];
+                forceGarageMode(value, writer);
+                break;
+            }
+            case COMMAND_INJECT_VHAL_EVENT:
+                String zone = PARAM_VEHICLE_PROPERTY_AREA_GLOBAL;
+                String data;
+                int argNum = args.length;
+                if (argNum < 3 || argNum > 6) {
+                    return showInvalidArguments(writer);
+                }
+                String delayTime = args[argNum - 2].equals("-t") ?  args[argNum - 1] : "0";
+                if (argNum == 4 || argNum == 6) {
+                    // Zoned
+                    zone = args[2];
+                    data = args[3];
+                } else {
+                    // Global
+                    data = args[2];
+                }
+                injectVhalEvent(args[1], zone, data, false, delayTime, writer);
+                break;
+            case COMMAND_INJECT_ERROR_EVENT:
+                if (args.length != 4) {
+                    return showInvalidArguments(writer);
+                }
+                String errorAreaId = args[2];
+                String errorCode = args[3];
+                injectVhalEvent(args[1], errorAreaId, errorCode, true, "0", writer);
+                break;
+            case COMMAND_ENABLE_UXR:
+                if (args.length != 2) {
+                    return showInvalidArguments(writer);
+                }
+                boolean enableBlocking = Boolean.valueOf(args[1]);
+                if (mCarPackageManagerService != null) {
+                    mCarPackageManagerService.setEnableActivityBlocking(enableBlocking);
+                }
+                break;
+            case COMMAND_GET_DO_ACTIVITIES:
+                if (args.length != 2) {
+                    return showInvalidArguments(writer);
+                }
+                String pkgName = args[1].toLowerCase();
+                if (mCarPackageManagerService != null) {
+                    String[] doActivities =
+                            mCarPackageManagerService.getDistractionOptimizedActivities(
+                                    pkgName);
+                    if (doActivities != null) {
+                        writer.println("DO Activities for " + pkgName);
+                        for (String a : doActivities) {
+                            writer.println(a);
+                        }
+                    } else {
+                        writer.println("No DO Activities for " + pkgName);
+                    }
+                }
+                break;
+            case COMMAND_GET_CARPROPERTYCONFIG:
+                String propertyId = args.length < 2 ? "" : args[1];
+                mHal.dumpPropertyConfigs(writer, propertyId);
+                break;
+            case COMMAND_GET_PROPERTY_VALUE:
+                String propId = args.length < 2 ? "" : args[1];
+                String areaId = args.length < 3 ? "" : args[2];
+                mHal.dumpPropertyValueByCommend(writer, propId, areaId);
+                break;
+            case COMMAND_PROJECTION_UI_MODE:
+                if (args.length != 2) {
+                    return showInvalidArguments(writer);
+                }
+                mCarProjectionService.setUiMode(Integer.valueOf(args[1]));
+                break;
+            case COMMAND_PROJECTION_AP_TETHERING:
+                if (args.length != 2) {
+                    return showInvalidArguments(writer);
+                }
+                mCarProjectionService.setAccessPointTethering(Boolean.valueOf(args[1]));
+                break;
+            case COMMAND_RESUME:
+                mCarPowerManagementService.forceSimulatedResume();
+                writer.println("Resume: Simulating resuming from Deep Sleep");
+                break;
+            case COMMAND_SUSPEND:
+                mCarPowerManagementService.forceSuspendAndMaybeReboot(false);
+                writer.println("Resume: Simulating powering down to Deep Sleep");
+                break;
+            case COMMAND_ENABLE_TRUSTED_DEVICE:
+                if (args.length != 2) {
+                    return showInvalidArguments(writer);
+                }
+                mCarTrustedDeviceService.getCarTrustAgentEnrollmentService()
+                        .setTrustedDeviceEnrollmentEnabled(Boolean.valueOf(args[1]));
+                mCarTrustedDeviceService.getCarTrustAgentUnlockService()
+                        .setTrustedDeviceUnlockEnabled(Boolean.valueOf(args[1]));
+                break;
+            case COMMAND_REMOVE_TRUSTED_DEVICES:
+                mCarTrustedDeviceService.getCarTrustAgentEnrollmentService()
+                        .removeAllTrustedDevices(ActivityManager.getCurrentUser());
+                break;
+            case COMMAND_SET_UID_TO_ZONE:
+                if (args.length != 3) {
+                    return showInvalidArguments(writer);
+                }
+                runSetZoneIdForUid(args[1], args[2]);
+                break;
+            case COMMAND_SET_USER_ID_TO_OCCUPANT_ZONE:
+                if (args.length != 3) {
+                    return showInvalidArguments(writer);
+                }
+                runSetOccupantZoneIdForUserId(args[1], args[2]);
+                break;
+            case COMMAND_RESET_USER_ID_IN_OCCUPANT_ZONE:
+                if (args.length != 2) {
+                    return showInvalidArguments(writer);
+                }
+                runResetOccupantZoneId(args[1]);
+                break;
+            case COMMAND_START_FIXED_ACTIVITY_MODE:
+                startFixedActivity(args, writer);
+                break;
+            case COMMAND_STOP_FIXED_ACTIVITY_MODE:
+                stopFixedMode(args, writer);
+                break;
+            case COMMAND_ENABLE_FEATURE:
+                if (args.length != 2) {
+                    return showInvalidArguments(writer);
+                }
+                enableDisableFeature(args, writer, /* enable= */ true);
+                break;
+            case COMMAND_DISABLE_FEATURE:
+                if (args.length != 2) {
+                    return showInvalidArguments(writer);
+                }
+                enableDisableFeature(args, writer, /* enable= */ false);
+                break;
+            case COMMAND_INJECT_KEY:
+                if (args.length < 2) {
+                    return showInvalidArguments(writer);
+                }
+                injectKey(args, writer);
+                break;
+            case COMMAND_INJECT_ROTARY:
+                if (args.length < 1) {
+                    return showInvalidArguments(writer);
+                }
+                injectRotary(args, writer);
+                break;
+            case COMMAND_GET_INITIAL_USER_INFO:
+                getInitialUserInfo(args, writer);
+                break;
+            case COMMAND_SWITCH_USER:
+                switchUser(args, writer);
+                break;
+            case COMMAND_REMOVE_USER:
+                removeUser(args, writer);
+                break;
+            case COMMAND_CREATE_USER:
+                createUser(args, writer);
+                break;
+            case COMMAND_GET_INITIAL_USER:
+                getInitialUser(writer);
+                break;
+            case COMMAND_GET_USER_AUTH_ASSOCIATION:
+                getUserAuthAssociation(args, writer);
+                break;
+            case COMMAND_SET_USER_AUTH_ASSOCIATION:
+                setUserAuthAssociation(args, writer);
+                break;
+            default:
+                writer.println("Unknown command: \"" + cmd + "\"");
+                showHelp(writer);
+                return RESULT_ERROR;
+        }
+        return RESULT_OK;
+    }
+
+    private void startFixedActivity(String[] args, PrintWriter writer) {
+        if (args.length != 4) {
+            writer.println("Incorrect number of arguments");
+            showHelp(writer);
+            return;
+        }
+        int displayId;
+        try {
+            displayId = Integer.parseInt(args[1]);
+        } catch (NumberFormatException e) {
+            writer.println("Wrong display id:" + args[1]);
+            return;
+        }
+        String packageName = args[2];
+        String activityName = args[3];
+        Intent intent = new Intent();
+        intent.setComponent(new ComponentName(packageName, activityName));
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(displayId);
+        if (!mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent, options,
+                displayId, ActivityManager.getCurrentUser())) {
+            writer.println("Failed to start");
+            return;
+        }
+        writer.println("Succeeded");
+    }
+
+    private void stopFixedMode(String[] args, PrintWriter writer) {
+        if (args.length != 2) {
+            writer.println("Incorrect number of arguments");
+            showHelp(writer);
+            return;
+        }
+        int displayId;
+        try {
+            displayId = Integer.parseInt(args[1]);
+        } catch (NumberFormatException e) {
+            writer.println("Wrong display id:" + args[1]);
+            return;
+        }
+        mFixedActivityService.stopFixedActivityMode(displayId);
+    }
+
+    private void enableDisableFeature(String[] args, PrintWriter writer, boolean enable) {
+        if (Binder.getCallingUid() != Process.ROOT_UID) {
+            writer.println("Only allowed to root/su");
+            return;
+        }
+        String featureName = args[1];
+        long id = Binder.clearCallingIdentity();
+        // no permission check here
+        int r;
+        if (enable) {
+            r = mFeatureController.enableFeature(featureName);
+        } else {
+            r = mFeatureController.disableFeature(featureName);
+        }
+        switch (r) {
+            case Car.FEATURE_REQUEST_SUCCESS:
+                if (enable) {
+                    writer.println("Enabled feature:" + featureName);
+                } else {
+                    writer.println("Disabled feature:" + featureName);
+                }
+                break;
+            case Car.FEATURE_REQUEST_ALREADY_IN_THE_STATE:
+                if (enable) {
+                    writer.println("Already enabled:" + featureName);
+                } else {
+                    writer.println("Already disabled:" + featureName);
+                }
+                break;
+            case Car.FEATURE_REQUEST_MANDATORY:
+                writer.println("Cannot change mandatory feature:" + featureName);
+                break;
+            case Car.FEATURE_REQUEST_NOT_EXISTING:
+                writer.println("Non-existing feature:" + featureName);
+                break;
+            default:
+                writer.println("Unknown error:" + r);
+                break;
+        }
+        Binder.restoreCallingIdentity(id);
+    }
+
+    private void injectKey(String[] args, PrintWriter writer) {
+        int i = 1; // 0 is command itself
+        int display = InputHalService.DISPLAY_MAIN;
+        int delayMs = 0;
+        int keyCode = KeyEvent.KEYCODE_UNKNOWN;
+        try {
+            while (i < args.length) {
+                switch (args[i]) {
+                    case "-d":
+                        i++;
+                        display = Integer.parseInt(args[i]);
+                        break;
+                    case "-t":
+                        i++;
+                        delayMs = Integer.parseInt(args[i]);
+                        break;
+                    default:
+                        if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
+                            throw new IllegalArgumentException("key_code already set:"
+                                    + keyCode);
+                        }
+                        keyCode = Integer.parseInt(args[i]);
+                }
+                i++;
+            }
+        } catch (Exception e) {
+            writer.println("Invalid args:" + e);
+            showHelp(writer);
+            return;
+        }
+        if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
+            writer.println("Missing key code or invalid keycode");
+            showHelp(writer);
+            return;
+        }
+        if (display != InputHalService.DISPLAY_MAIN
+                && display != InputHalService.DISPLAY_INSTRUMENT_CLUSTER) {
+            writer.println("Invalid display:" + display);
+            showHelp(writer);
+            return;
+        }
+        if (delayMs < 0) {
+            writer.println("Invalid delay:" + delayMs);
+            showHelp(writer);
+
+            return;
+        }
+        KeyEvent keyDown = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
+        mCarInputService.onKeyEvent(keyDown, display);
+        SystemClock.sleep(delayMs);
+        KeyEvent keyUp = new KeyEvent(KeyEvent.ACTION_UP, keyCode);
+        mCarInputService.onKeyEvent(keyUp, display);
+        writer.println("Succeeded");
+    }
+
+    private void injectRotary(String[] args, PrintWriter writer) {
+        int i = 1; // 0 is command itself
+        int display = InputHalService.DISPLAY_MAIN;
+        int inputType = CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION;
+        boolean clockwise = false;
+        List<Long> deltaTimeMs = new ArrayList<>();
+        try {
+            while (i < args.length) {
+                switch (args[i]) {
+                    case "-d":
+                        i++;
+                        display = Integer.parseInt(args[i]);
+                        break;
+                    case "-i":
+                        i++;
+                        inputType = Integer.parseInt(args[i]);
+                        break;
+                    case "-c":
+                        i++;
+                        clockwise = Boolean.parseBoolean(args[i]);
+                        break;
+                    case "-dt":
+                        i++;
+                        while (i < args.length) {
+                            deltaTimeMs.add(Long.parseLong(args[i]));
+                            i++;
+                        }
+                        break;
+                    default:
+                        writer.println("Invalid option at index " + i + ": " + args[i]);
+                        return;
+                }
+                i++;
+            }
+        } catch (Exception e) {
+            writer.println("Invalid args:" + e);
+            showHelp(writer);
+            return;
+        }
+        if (deltaTimeMs.isEmpty()) {
+            deltaTimeMs.add(0L);
+        }
+        for (int j = 0; j < deltaTimeMs.size(); j++) {
+            if (deltaTimeMs.get(j) < 0) {
+                writer.println("Delta time shouldn't be negative: " + deltaTimeMs.get(j));
+                showHelp(writer);
+                return;
+            }
+            if (j > 0 && deltaTimeMs.get(j) > deltaTimeMs.get(j - 1)) {
+                writer.println("Delta times should be in descending order");
+                showHelp(writer);
+                return;
+            }
+        }
+        long[] uptimeMs = new long[deltaTimeMs.size()];
+        long currentUptime = SystemClock.uptimeMillis();
+        for (int j = 0; j < deltaTimeMs.size(); j++) {
+            uptimeMs[j] = currentUptime - deltaTimeMs.get(j);
+        }
+        RotaryEvent rotaryEvent = new RotaryEvent(inputType, clockwise, uptimeMs);
+        mCarInputService.onRotaryEvent(rotaryEvent, display);
+        writer.println("Succeeded in injecting: " + rotaryEvent);
+    }
+
+    private void getInitialUserInfo(String[] args, PrintWriter writer) {
+        if (args.length < 2) {
+            writer.println("Insufficient number of args");
+            return;
+        }
+
+        // Gets the request type
+        String typeArg = args[1];
+        int requestType = UserHalHelper.parseInitialUserInfoRequestType(typeArg);
+        boolean halOnly = false;
+
+        int timeout = DEFAULT_HAL_TIMEOUT_MS;
+        for (int i = 2; i < args.length; i++) {
+            String arg = args[i];
+            switch (arg) {
+                case "--timeout":
+                    timeout = Integer.parseInt(args[++i]);
+                    break;
+                case "--hal-only":
+                    halOnly = true;
+                    break;
+                default:
+                    writer.println("Invalid option at index " + i + ": " + arg);
+                    return;
+
+            }
+        }
+
+        Log.d(TAG, "handleGetInitialUserInfo(): type=" + requestType + " (" + typeArg
+                + "), timeout=" + timeout);
+
+        CountDownLatch latch = new CountDownLatch(1);
+        HalCallback<InitialUserInfoResponse> callback = (status, resp) -> {
+            try {
+                Log.d(TAG, "GetUserInfoResponse: status=" + status + ", resp=" + resp);
+                writer.printf("Call status: %s\n",
+                        UserHalHelper.halCallbackStatusToString(status));
+                if (status != HalCallback.STATUS_OK) {
+                    return;
+                }
+                writer.printf("Request id: %d\n", resp.requestId);
+                writer.printf("Action: %s\n",
+                        InitialUserInfoResponseAction.toString(resp.action));
+                if (!TextUtils.isEmpty(resp.userNameToCreate)) {
+                    writer.printf("User name: %s\n", resp.userNameToCreate);
+                }
+                if (resp.userToSwitchOrCreate.userId != UserHandle.USER_NULL) {
+                    writer.printf("User id: %d\n", resp.userToSwitchOrCreate.userId);
+                }
+                if (resp.userToSwitchOrCreate.flags != UserFlags.NONE) {
+                    writer.printf("User flags: %s\n",
+                            UserHalHelper.userFlagsToString(resp.userToSwitchOrCreate.flags));
+                }
+                if (!TextUtils.isEmpty(resp.userLocales)) {
+                    writer.printf("User locales: %s\n", resp.userLocales);
+                }
+            } finally {
+                latch.countDown();
+            }
+        };
+        if (halOnly) {
+            UsersInfo usersInfo = generateUsersInfo();
+            mHal.getUserHal().getInitialUserInfo(requestType, timeout, usersInfo, callback);
+        } else {
+            mCarUserService.getInitialUserInfo(requestType, callback);
+        }
+        waitForHal(writer, latch, timeout);
+    }
+
+    private UsersInfo generateUsersInfo() {
+        return UserHalHelper.newUsersInfo(UserManager.get(mContext));
+    }
+
+    private int getUserHalFlags(@UserIdInt int userId) {
+        return UserHalHelper.getFlags(UserManager.get(mContext), userId);
+    }
+
+    private static void waitForHal(PrintWriter writer, CountDownLatch latch, int timeoutMs) {
+        try {
+            if (!latch.await(timeoutMs, TimeUnit.MILLISECONDS)) {
+                writer.printf("HAL didn't respond in %dms\n", timeoutMs);
+            }
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            writer.println("Interrupted waiting for HAL");
+        }
+        return;
+    }
+
+    private void switchUser(String[] args, PrintWriter writer) {
+        if (args.length < 2) {
+            writer.println("Insufficient number of args");
+            return;
+        }
+
+        int targetUserId = Integer.parseInt(args[1]);
+        int timeout = DEFAULT_HAL_TIMEOUT_MS;
+        boolean halOnly = false;
+
+        for (int i = 2; i < args.length; i++) {
+            String arg = args[i];
+            switch (arg) {
+                case "--timeout":
+                    timeout = Integer.parseInt(args[++i]);
+                    break;
+                case "--hal-only":
+                    halOnly = true;
+                    break;
+                default:
+                    writer.println("Invalid option at index " + i + ": " + arg);
+                    return;
+            }
+        }
+
+        Log.d(TAG, "switchUser(): target=" + targetUserId + ", halOnly=" + halOnly
+                + ", timeout=" + timeout);
+
+        if (halOnly) {
+            CountDownLatch latch = new CountDownLatch(1);
+            UserHalService userHal = mHal.getUserHal();
+            UserInfo targetUserInfo = new UserInfo();
+            targetUserInfo.userId = targetUserId;
+            targetUserInfo.flags = getUserHalFlags(targetUserId);
+
+            SwitchUserRequest request = new SwitchUserRequest();
+            request.targetUser = targetUserInfo;
+            request.usersInfo = generateUsersInfo();
+
+            userHal.switchUser(request, timeout, (status, resp) -> {
+                try {
+                    Log.d(TAG, "SwitchUserResponse: status=" + status + ", resp=" + resp);
+                    writer.printf("Call Status: %s\n",
+                            UserHalHelper.halCallbackStatusToString(status));
+                    if (status != HalCallback.STATUS_OK) {
+                        return;
+                    }
+                    writer.printf("Request id: %d\n", resp.requestId);
+                    writer.printf("Message type: %s\n",
+                            SwitchUserMessageType.toString(resp.messageType));
+                    writer.printf("Switch Status: %s\n", SwitchUserStatus.toString(resp.status));
+                    String errorMessage = resp.errorMessage;
+                    if (!TextUtils.isEmpty(errorMessage)) {
+                        writer.printf("Error message: %s", errorMessage);
+                    }
+                    // If HAL returned OK, make a "post-switch" call to the HAL indicating an
+                    // Android error. This is to "rollback" the HAL switch.
+                    if (status == HalCallback.STATUS_OK
+                            && resp.status == SwitchUserStatus.SUCCESS) {
+                        userHal.postSwitchResponse(request);
+                    }
+                } finally {
+                    latch.countDown();
+                }
+            });
+            waitForHal(writer, latch, timeout);
+            return;
+        }
+        CarUserManager carUserManager = getCarUserManager(mContext);
+        AndroidFuture<UserSwitchResult> future = carUserManager.switchUser(targetUserId);
+        UserSwitchResult result = waitForFuture(writer, future, timeout);
+        if (result == null) return;
+        writer.printf("UserSwitchResult: status=%s",
+                UserSwitchResult.statusToString(result.getStatus()));
+        String msg = result.getErrorMessage();
+        if (!TextUtils.isEmpty(msg)) {
+            writer.printf(", errorMessage=%s", msg);
+        }
+        writer.println();
+    }
+
+    private void createUser(String[] args, PrintWriter writer) {
+        int timeout = DEFAULT_HAL_TIMEOUT_MS;
+        int flags = 0;
+        boolean halOnly = false;
+        String name = null;
+        String userType = null;
+
+        for (int i = 1; i < args.length; i++) {
+            String arg = args[i];
+            switch (arg) {
+                case "--timeout":
+                    timeout = Integer.parseInt(args[++i]);
+                    break;
+                case "--hal-only":
+                    halOnly = true;
+                    break;
+                case "--flags":
+                    flags = Integer.parseInt(args[++i]);
+                    break;
+                case "--type":
+                    userType = args[++i];
+                    break;
+                default:
+                    if (name != null) {
+                        writer.println("Invalid option at index " + i + ": " + arg);
+                        return;
+                    }
+                    name = arg;
+            }
+        }
+
+        if (userType == null) {
+            userType = android.content.pm.UserInfo.getDefaultUserType(flags);
+        }
+
+        Log.d(TAG, "createUser(): name=" + name + ", userType=" + userType
+                + ", flags=" + UserHalHelper.userFlagsToString(flags)
+                + ", halOnly=" + halOnly + ", timeout=" + timeout);
+
+        if (!halOnly) {
+            CarUserManager carUserManager = getCarUserManager(mContext);
+            AndroidFuture<UserCreationResult> future = carUserManager
+                    .createUser(name, userType, flags);
+
+            UserCreationResult result = waitForFuture(writer, future, timeout);
+            if (result == null) return;
+
+            android.content.pm.UserInfo user = result.getUser();
+            writer.printf("UserCreationResult: status=%s, user=%s",
+                    UserCreationResult.statusToString(result.getStatus()),
+                    user == null ? "N/A" : user.toFullString());
+            String msg = result.getErrorMessage();
+            if (!TextUtils.isEmpty(msg)) {
+                writer.printf(", errorMessage=%s", msg);
+            }
+            writer.println();
+            return;
+        }
+
+        CountDownLatch latch = new CountDownLatch(1);
+        UserHalService userHal = mHal.getUserHal();
+
+        CreateUserRequest request = new CreateUserRequest();
+
+        UserManager um = UserManager.get(mContext);
+        android.content.pm.UserInfo newUser = um.createUser(name, userType, flags);
+        if (newUser == null) {
+            writer.printf("Failed to create user");
+            return;
+        }
+        writer.printf("New user: %s\n", newUser.toFullString());
+        Log.i(TAG, "Created new user: " + newUser.toFullString());
+
+        request.newUserInfo.userId = newUser.id;
+        request.newUserInfo.flags = UserHalHelper.convertFlags(newUser);
+
+        request.usersInfo = generateUsersInfo();
+
+        AtomicBoolean halOk = new AtomicBoolean(false);
+        try {
+            userHal.createUser(request, timeout, (status, resp) -> {
+                Log.d(TAG, "CreateUserResponse: status=" + status + ", resp=" + resp);
+                writer.printf("Call Status: %s\n",
+                        UserHalHelper.halCallbackStatusToString(status));
+                if (status == HalCallback.STATUS_OK) {
+                    halOk.set(resp.status == CreateUserStatus.SUCCESS);
+                    writer.printf("Request id: %d\n", resp.requestId);
+                    writer.printf("Create Status: %s\n", CreateUserStatus.toString(resp.status));
+                    String errorMessage = resp.errorMessage;
+                    if (!TextUtils.isEmpty(errorMessage)) {
+                        writer.printf("Error message: %s", errorMessage);
+                    }
+                }
+                latch.countDown();
+            });
+            waitForHal(writer, latch, timeout);
+        } catch (Exception e) {
+            writer.printf("HAL failed: %s\n", e);
+        } finally {
+            if (!halOk.get()) {
+                writer.printf("Removing user %d due to HAL failure\n", newUser.id);
+                boolean removed = um.removeUser(newUser.id);
+                writer.printf("User removed: %b\n", removed);
+            }
+        }
+    }
+
+    private void removeUser(String[] args, PrintWriter writer) {
+        if (args.length < 2) {
+            writer.println("Insufficient number of args");
+            return;
+        }
+
+        int userId = Integer.parseInt(args[1]);
+        boolean halOnly = false;
+
+        for (int i = 2; i < args.length; i++) {
+            String arg = args[i];
+            switch (arg) {
+                case "--hal-only":
+                    halOnly = true;
+                    break;
+                default:
+                    writer.println("Invalid option at index " + i + ": " + arg);
+                    return;
+            }
+        }
+
+        Log.d(TAG, "handleRemoveUser(): User to remove=" + userId + ", halOnly=" + halOnly);
+
+        if (halOnly) {
+            UserHalService userHal = mHal.getUserHal();
+            UsersInfo usersInfo = generateUsersInfo();
+            UserInfo userInfo = new UserInfo();
+            userInfo.userId = userId;
+            userInfo.flags = getUserHalFlags(userId);
+
+            RemoveUserRequest request = new RemoveUserRequest();
+            request.removedUserInfo = userInfo;
+            request.usersInfo = usersInfo;
+
+            userHal.removeUser(request);
+            writer.printf("User removal sent for HAL only.\n");
+            return;
+        }
+
+        CarUserManager carUserManager = getCarUserManager(mContext);
+        UserRemovalResult result = carUserManager.removeUser(userId);
+        if (result == null) return;
+        writer.printf("UserRemovalResult: status = %s\n",
+                UserRemovalResult.statusToString(result.getStatus()));
+    }
+
+    private static <T> T waitForFuture(@NonNull PrintWriter writer,
+            @NonNull AndroidFuture<T> future, int timeoutMs) {
+        T result = null;
+        try {
+            result = future.get(timeoutMs, TimeUnit.MILLISECONDS);
+            if (result == null) {
+                writer.printf("Service didn't respond in %d ms", timeoutMs);
+            }
+        } catch (Exception e) {
+            writer.printf("Exception getting future: %s",  e);
+        }
+        return result;
+    }
+
+    private void getInitialUser(PrintWriter writer) {
+        android.content.pm.UserInfo user = mCarUserService.getInitialUser();
+        writer.println(user == null ? NO_INITIAL_USER : user.id);
+    }
+
+    private void getUserAuthAssociation(String[] args, PrintWriter writer) {
+        if (args.length < 2) {
+            writer.println("invalid usage, must pass at least 1 argument");
+            return;
+        }
+
+        boolean halOnly = false;
+        int userId = UserHandle.USER_CURRENT;
+
+        UserIdentificationGetRequest request = new UserIdentificationGetRequest();
+        for (int i = 1; i < args.length; i++) {
+            String arg = args[i];
+            switch (arg) {
+                case "--user":
+                    try {
+                        userId = Integer.parseInt(args[++i]);
+                    } catch (Exception e) {
+                        writer.printf("Invalid user id at index %d (from %s): %s\n", i + 1,
+                                Arrays.toString(args), arg);
+                    }
+                    break;
+                case "--hal-only":
+                    halOnly = true;
+                    break;
+                default:
+                    int type = parseAuthArg(VALID_USER_AUTH_TYPES, arg);
+                    if (type == INVALID_USER_AUTH_TYPE_OR_VALUE) {
+                        writer.printf("Invalid type at index %d (from %s): %s. %s\n", i + 1,
+                                Arrays.toString(args), arg, VALID_USER_AUTH_TYPES_HELP);
+                        return;
+                    }
+                    request.associationTypes.add(type);
+            }
+
+        }
+        if (userId == UserHandle.USER_CURRENT) {
+            userId = ActivityManager.getCurrentUser();
+        }
+        int requestSize = request.associationTypes.size();
+        if (halOnly) {
+            request.numberAssociationTypes = requestSize;
+            request.userInfo.userId = userId;
+            request.userInfo.flags = getUserHalFlags(userId);
+
+            Log.d(TAG, "getUserAuthAssociation(): user=" + userId + ", halOnly=" + halOnly
+                    + ", request=" + request);
+            UserIdentificationResponse response = mHal.getUserHal().getUserAssociation(request);
+            Log.d(TAG, "getUserAuthAssociation(): response=" + response);
+            showResponse(writer, response);
+            return;
+        }
+
+        CarUserManager carUserManager = getCarUserManager(writer, userId);
+        int[] types = new int[requestSize];
+        for (int i = 0; i < requestSize; i++) {
+            types[i] = request.associationTypes.get(i);
+        }
+        UserIdentificationAssociationResponse response = carUserManager
+                .getUserIdentificationAssociation(types);
+        showResponse(writer, response);
+    }
+
+    private CarUserManager getCarUserManager(@NonNull PrintWriter writer, @UserIdInt int userId) {
+        Context context;
+        if (userId == mContext.getUserId()) {
+            context = mContext;
+        } else {
+            context = mContext.createContextAsUser(UserHandle.of(userId), /* flags= */ 0);
+        }
+        int actualUserId = Binder.getCallingUid();
+        if (actualUserId != userId) {
+            writer.printf("Emulating call for user id %d, but caller's user id is %d, so that's "
+                    + "what CarUserService will use when calling HAL.\n", userId, actualUserId);
+        }
+
+        return getCarUserManager(context);
+    }
+
+    private CarUserManager getCarUserManager(@NonNull Context context) {
+        Car car = Car.createCar(context);
+        CarUserManager carUserManager = (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE);
+        return carUserManager;
+    }
+
+    private void showResponse(@NonNull PrintWriter writer,
+            @NonNull UserIdentificationResponse response) {
+        if (response == null) {
+            writer.println("null response");
+            return;
+        }
+
+        if (!TextUtils.isEmpty(response.errorMessage)) {
+            writer.printf("Error message: %s\n", response.errorMessage);
+        }
+        int numberAssociations = response.associations.size();
+        writer.printf("%d associations:\n", numberAssociations);
+        for (int i = 0; i < numberAssociations; i++) {
+            UserIdentificationAssociation association = response.associations.get(i);
+            writer.printf("  %s\n", association);
+        }
+    }
+
+    private void showResponse(@NonNull PrintWriter writer,
+            @NonNull UserIdentificationAssociationResponse response) {
+        if (response == null) {
+            writer.println("null response");
+            return;
+        }
+        if (!response.isSuccess()) {
+            writer.printf("failed response: %s\n", response);
+            return;
+        }
+        String errorMessage = response.getErrorMessage();
+        if (!TextUtils.isEmpty(errorMessage)) {
+            writer.printf("Error message: %s\n", errorMessage);
+        }
+        int[] values = response.getValues();
+        if (values == null) {
+            writer.printf("no associations on %s\n", response);
+            return;
+        }
+        writer.printf("%d associations:\n", values.length);
+        for (int i = 0; i < values.length; i++) {
+            writer.printf("  %s\n", UserIdentificationAssociationValue.toString(values[i]));
+        }
+    }
+
+    private void setUserAuthAssociation(String[] args, PrintWriter writer) {
+        if (args.length < 3) {
+            writer.println("invalid usage, must pass at least 4 arguments");
+            return;
+        }
+
+        boolean halOnly = false;
+        int timeout = DEFAULT_HAL_TIMEOUT_MS;
+        int userId = UserHandle.USER_CURRENT;
+
+        UserIdentificationSetRequest request = new UserIdentificationSetRequest();
+        for (int i = 1; i < args.length; i++) {
+            String arg = args[i];
+            switch (arg) {
+                case "--user":
+                    try {
+                        userId = Integer.parseInt(args[++i]);
+                    } catch (Exception e) {
+                        writer.printf("Invalid user id at index %d (from %s): %s\n", i + 1,
+                                Arrays.toString(args), arg);
+                    }
+                    break;
+                case "--hal-only":
+                    halOnly = true;
+                    break;
+                case "--timeout":
+                    timeout = Integer.parseInt(args[++i]);
+                    break;
+                default:
+                    UserIdentificationSetAssociation association =
+                            new UserIdentificationSetAssociation();
+                    association.type = parseAuthArg(VALID_USER_AUTH_TYPES, arg);
+                    if (association.type == INVALID_USER_AUTH_TYPE_OR_VALUE) {
+                        writer.printf("Invalid type at index %d (from %s): %s. %s\n", i + 1,
+                                Arrays.toString(args), arg, VALID_USER_AUTH_TYPES_HELP);
+                        return;
+                    }
+                    association.value = parseAuthArg(VALID_USER_AUTH_SET_VALUES, args[++i]);
+                    if (association.value == INVALID_USER_AUTH_TYPE_OR_VALUE) {
+                        writer.printf("Invalid value at index %d (from %s): %s. %s\n", i + 1,
+                                Arrays.toString(args), arg, VALID_USER_AUTH_SET_VALUES_HELP);
+                        return;
+                    }
+                    request.associations.add(association);
+            }
+
+        }
+        if (userId == UserHandle.USER_CURRENT) {
+            userId = ActivityManager.getCurrentUser();
+        }
+        int requestSize = request.associations.size();
+        if (halOnly) {
+            request.numberAssociations = requestSize;
+            request.userInfo.userId = userId;
+            request.userInfo.flags = getUserHalFlags(userId);
+
+            Log.d(TAG, "setUserAuthAssociation(): user=" + userId + ", halOnly=" + halOnly
+                    + ", request=" + request);
+            CountDownLatch latch = new CountDownLatch(1);
+            mHal.getUserHal().setUserAssociation(timeout, request, (status, response) -> {
+                Log.d(TAG, "setUserAuthAssociation(): response=" + response);
+                try {
+                    showResponse(writer, response);
+                } finally {
+                    latch.countDown();
+                }
+            });
+            waitForHal(writer, latch, timeout);
+            return;
+        }
+        CarUserManager carUserManager = getCarUserManager(writer, userId);
+        int[] types = new int[requestSize];
+        int[] values = new int[requestSize];
+        for (int i = 0; i < requestSize; i++) {
+            UserIdentificationSetAssociation association = request.associations.get(i);
+            types[i] = association.type;
+            values[i] = association.value;
+        }
+        AndroidFuture<UserIdentificationAssociationResponse> future = carUserManager
+                .setUserIdentificationAssociation(types, values);
+        UserIdentificationAssociationResponse response = waitForFuture(writer, future, timeout);
+        if (response != null) {
+            showResponse(writer, response);
+        }
+    }
+
+    private static int parseAuthArg(@NonNull SparseArray<String> types, @NonNull String type) {
+        for (int i = 0; i < types.size(); i++) {
+            if (types.valueAt(i).equals(type)) {
+                return types.keyAt(i);
+            }
+        }
+        return INVALID_USER_AUTH_TYPE_OR_VALUE;
+    }
+
+    private void forceDayNightMode(String arg, PrintWriter writer) {
+        int mode;
+        switch (arg) {
+            case PARAM_DAY_MODE:
+                mode = CarNightService.FORCED_DAY_MODE;
+                break;
+            case PARAM_NIGHT_MODE:
+                mode = CarNightService.FORCED_NIGHT_MODE;
+                break;
+            case PARAM_SENSOR_MODE:
+                mode = CarNightService.FORCED_SENSOR_MODE;
+                break;
+            default:
+                writer.println("Unknown value. Valid argument: " + PARAM_DAY_MODE + "|"
+                        + PARAM_NIGHT_MODE + "|" + PARAM_SENSOR_MODE);
+                return;
+        }
+        int current = mCarNightService.forceDayNightMode(mode);
+        String currentMode = null;
+        switch (current) {
+            case UiModeManager.MODE_NIGHT_AUTO:
+                currentMode = PARAM_SENSOR_MODE;
+                break;
+            case UiModeManager.MODE_NIGHT_YES:
+                currentMode = PARAM_NIGHT_MODE;
+                break;
+            case UiModeManager.MODE_NIGHT_NO:
+                currentMode = PARAM_DAY_MODE;
+                break;
+        }
+        writer.println("DayNightMode changed to: " + currentMode);
+    }
+
+    private void forceGarageMode(String arg, PrintWriter writer) {
+        switch (arg) {
+            case PARAM_ON_MODE:
+                mSystemInterface.setDisplayState(false);
+                mGarageModeService.forceStartGarageMode();
+                writer.println("Garage mode: " + mGarageModeService.isGarageModeActive());
+                break;
+            case PARAM_OFF_MODE:
+                mSystemInterface.setDisplayState(true);
+                mGarageModeService.stopAndResetGarageMode();
+                writer.println("Garage mode: " + mGarageModeService.isGarageModeActive());
+                break;
+            case PARAM_QUERY_MODE:
+                mGarageModeService.dump(writer);
+                break;
+            case PARAM_REBOOT:
+                mCarPowerManagementService.forceSuspendAndMaybeReboot(true);
+                writer.println("Entering Garage Mode. Will reboot when it completes.");
+                break;
+            default:
+                writer.println("Unknown value. Valid argument: " + PARAM_ON_MODE + "|"
+                        + PARAM_OFF_MODE + "|" + PARAM_QUERY_MODE + "|" + PARAM_REBOOT);
+        }
+    }
+
+    /**
+     * Inject a fake  VHAL event
+     *
+     * @param property the Vehicle property Id as defined in the HAL
+     * @param zone     Zone that this event services
+     * @param isErrorEvent indicates the type of event
+     * @param value    Data value of the event
+     * @param delayTime the event timestamp is increased by delayTime
+     * @param writer   PrintWriter
+     */
+    private void injectVhalEvent(String property, String zone, String value,
+            boolean isErrorEvent, String delayTime, PrintWriter writer) {
+        if (zone != null && (zone.equalsIgnoreCase(PARAM_VEHICLE_PROPERTY_AREA_GLOBAL))) {
+            if (!isPropertyAreaTypeGlobal(property)) {
+                writer.println("Property area type inconsistent with given zone");
+                return;
+            }
+        }
+        try {
+            if (isErrorEvent) {
+                mHal.injectOnPropertySetError(property, zone, value);
+            } else {
+                mHal.injectVhalEvent(property, zone, value, delayTime);
+            }
+        } catch (NumberFormatException e) {
+            writer.println("Invalid property Id zone Id or value" + e);
+            showHelp(writer);
+        }
+    }
+
+    // Check if the given property is global
+    private static boolean isPropertyAreaTypeGlobal(@Nullable String property) {
+        if (property == null) {
+            return false;
+        }
+        return (Integer.decode(property) & VehicleArea.MASK) == VehicleArea.GLOBAL;
+    }
+}
diff --git a/service/src/com/android/car/CarStatsLog.java b/service/src/com/android/car/CarStatsLog.java
deleted file mode 100644
index a0c9f2b..0000000
--- a/service/src/com/android/car/CarStatsLog.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import android.util.StatsLog;
-
-/**
- * CarStatsLog provides API to send Car events to statd.
- * @hide
- */
-public class CarStatsLog {
-    /**
-     * Logs a power state change event.
-     * @param state an integer defined in CarPowerManagementService.CpmsState
-     */
-    public static void logPowerState(int state) {
-        StatsLog.write(StatsLog.CAR_POWER_STATE_CHANGED, state);
-    }
-
-    /** Logs a GarageMode start event. */
-    public static void logGarageModeStart() {
-        StatsLog.write(StatsLog.GARAGE_MODE_INFO, true);
-    }
-
-    /** Logs a GarageMode stop event. */
-    public static void logGarageModeStop() {
-        StatsLog.write(StatsLog.GARAGE_MODE_INFO, false);
-    }
-}
diff --git a/service/src/com/android/car/CarStatsLogHelper.java b/service/src/com/android/car/CarStatsLogHelper.java
new file mode 100644
index 0000000..d69c8c3
--- /dev/null
+++ b/service/src/com/android/car/CarStatsLogHelper.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car;
+
+/**
+ * CarStatsLogHelper provides API to send Car events to statd.
+ * @hide
+ */
+public class CarStatsLogHelper {
+    /**
+     * Logs a power state change event.
+     * @param state an integer defined in CarPowerManagementService.CpmsState
+     */
+    public static void logPowerState(int state) {
+        CarStatsLog.write(CarStatsLog.CAR_POWER_STATE_CHANGED, state);
+    }
+
+    /** Logs a GarageMode start event. */
+    public static void logGarageModeStart() {
+        CarStatsLog.write(CarStatsLog.GARAGE_MODE_INFO, true);
+    }
+
+    /** Logs a GarageMode stop event. */
+    public static void logGarageModeStop() {
+        CarStatsLog.write(CarStatsLog.GARAGE_MODE_INFO, false);
+    }
+}
diff --git a/service/src/com/android/car/CarStorageMonitoringService.java b/service/src/com/android/car/CarStorageMonitoringService.java
index fb487b4..2d15a3f 100644
--- a/service/src/com/android/car/CarStorageMonitoringService.java
+++ b/service/src/com/android/car/CarStorageMonitoringService.java
@@ -46,6 +46,7 @@
 import com.android.car.storagemonitoring.WearInformation;
 import com.android.car.storagemonitoring.WearInformationProvider;
 import com.android.car.systeminterface.SystemInterface;
+import com.android.internal.annotations.GuardedBy;
 
 import org.json.JSONArray;
 import org.json.JSONException;
@@ -69,6 +70,10 @@
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
+/**
+ * A service to provide storage monitoring data like I/O statistics. In order to receive such data,
+ * users need to implement {@link IIoStatsListener} and register themselves against this service.
+ */
 public class CarStorageMonitoringService extends ICarStorageMonitoring.Stub
         implements CarServiceBase {
     public static final String INTENT_EXCESSIVE_IO =
@@ -93,21 +98,38 @@
     private final OnShutdownReboot mOnShutdownReboot;
     private final SystemInterface mSystemInterface;
     private final UidIoStatsProvider mUidIoStatsProvider;
-    private final SlidingWindow<IoStats> mIoStatsSamples;
-    private final RemoteCallbackList<IIoStatsListener> mListeners;
-    private final Object mIoStatsSamplesLock = new Object();
-    private final Configuration mConfiguration;
 
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private final SlidingWindow<IoStats> mIoStatsSamples;
+
+    private final RemoteCallbackList<IIoStatsListener> mListeners;
+    private final Configuration mConfiguration;
     private final CarPermission mStorageMonitoringPermission;
 
+    @GuardedBy("mLock")
     private UptimeTracker mUptimeTracker = null;
+
+    @GuardedBy("mLock")
     private Optional<WearInformation> mWearInformation = Optional.empty();
-    private List<WearEstimateChange> mWearEstimateChanges = Collections.emptyList();
+
+    @GuardedBy("mLock")
+    private List<WearEstimateChange> mWearEstimateChanges;
+
+    @GuardedBy("mLock")
     private List<IoStatsEntry> mBootIoStats = Collections.emptyList();
+
+    @GuardedBy("mLock")
     private IoStatsTracker mIoStatsTracker = null;
+
+    @GuardedBy("mLock")
     private boolean mInitialized = false;
 
+    @GuardedBy("mLock")
     private long mShutdownCostInfo = SHUTDOWN_COST_INFO_MISSING;
+
+    @GuardedBy("mLock")
     private String mShutdownCostMissingReason;
 
     public CarStorageMonitoringService(Context context, SystemInterface systemInterface) {
@@ -131,8 +153,10 @@
         mWearEstimateChanges = Collections.emptyList();
         mIoStatsSamples = new SlidingWindow<>(mConfiguration.ioStatsNumSamplesToStore);
         mListeners = new RemoteCallbackList<>();
-        systemInterface.scheduleActionForBootCompleted(this::doInitServiceIfNeeded,
-            Duration.ofSeconds(10));
+        systemInterface.scheduleActionForBootCompleted(() -> {
+            synchronized (mLock) {
+                doInitServiceIfNeededLocked();
+            }}, Duration.ofSeconds(10));
     }
 
     private Optional<WearInformation> loadWearInformation() {
@@ -164,7 +188,8 @@
     }
 
     // returns true iff a new event was added (and hence the history needs to be saved)
-    private boolean addEventIfNeeded(WearHistory wearHistory) {
+    @GuardedBy("mLock")
+    private boolean addEventIfNeededLocked(WearHistory wearHistory) {
         if (!mWearInformation.isPresent()) return false;
 
         WearInformation wearInformation = mWearInformation.get();
@@ -180,9 +205,9 @@
         if (currentWearEstimate.equals(lastWearEstimate)) return false;
 
         WearEstimateRecord newRecord = new WearEstimateRecord(lastWearEstimate,
-            currentWearEstimate,
-            mUptimeTracker.getTotalUptime(),
-            Instant.now());
+                currentWearEstimate,
+                mUptimeTracker.getTotalUptime(),
+                Instant.now());
         Log.d(TAG, "new wear record generated " + newRecord);
         wearHistory.add(newRecord);
         return true;
@@ -199,10 +224,11 @@
     @Override
     public void init() {
         Log.d(TAG, "CarStorageMonitoringService init()");
-
-        mUptimeTracker = new UptimeTracker(mUptimeTrackerFile,
-            mConfiguration.uptimeIntervalBetweenUptimeDataWriteMs,
-            mSystemInterface);
+        synchronized (mLock) {
+            mUptimeTracker = new UptimeTracker(mUptimeTrackerFile,
+                    mConfiguration.uptimeIntervalBetweenUptimeDataWriteMs,
+                    mSystemInterface);
+        }
     }
 
     private void launchWearChangeActivity() {
@@ -210,22 +236,21 @@
         if (activityPath.isEmpty()) return;
         try {
             final ComponentName activityComponent =
-                Objects.requireNonNull(ComponentName.unflattenFromString(activityPath));
+                    Objects.requireNonNull(ComponentName.unflattenFromString(activityPath));
             Intent intent = new Intent();
             intent.setComponent(activityComponent);
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             mContext.startActivity(intent);
         } catch (ActivityNotFoundException | NullPointerException e) {
-            Log.e(TAG,
-                "value of activityHandlerForFlashWearChanges invalid non-empty string " +
-                    activityPath, e);
+            Log.e(TAG, "value of activityHandlerForFlashWearChanges invalid non-empty string "
+                    + activityPath, e);
         }
     }
 
     private static void logOnAdverseWearLevel(WearInformation wearInformation) {
         if (wearInformation.preEolInfo > WearInformation.PRE_EOL_INFO_NORMAL ||
-            Math.max(wearInformation.lifetimeEstimateA,
-                wearInformation.lifetimeEstimateB) >= MIN_WEAR_ESTIMATE_OF_CONCERN) {
+                Math.max(wearInformation.lifetimeEstimateA,
+                        wearInformation.lifetimeEstimateB) >= MIN_WEAR_ESTIMATE_OF_CONCERN) {
             Log.w(TAG, "flash storage reached wear a level that requires attention: "
                     + wearInformation);
         }
@@ -237,29 +262,31 @@
     }
 
     private void collectNewIoMetrics() {
+        SparseArray<IoStatsEntry> currentSample;
+        boolean needsExcessiveIoBroadcast;
         IoStats ioStats;
-
-        mIoStatsTracker.update(loadNewIoStats());
-        synchronized (mIoStatsSamplesLock) {
+        synchronized (mLock) {
+            mIoStatsTracker.update(loadNewIoStats());
+            currentSample = mIoStatsTracker.getCurrentSample();
             ioStats = new IoStats(
-                SparseArrayStream.valueStream(mIoStatsTracker.getCurrentSample())
-                    .collect(Collectors.toList()),
-                mSystemInterface.getUptime());
+                    SparseArrayStream.valueStream(currentSample).collect(Collectors.toList()),
+                    mSystemInterface.getUptime());
             mIoStatsSamples.add(ioStats);
+            needsExcessiveIoBroadcast = needsExcessiveIoBroadcastLocked();
         }
 
+        dispatchNewIoEvent(ioStats);
+
         if (DBG) {
-            SparseArray<IoStatsEntry> currentSample = mIoStatsTracker.getCurrentSample();
             if (currentSample.size() == 0) {
                 Log.d(TAG, "no new I/O stat data");
             } else {
                 SparseArrayStream.valueStream(currentSample).forEach(
-                    uidIoStats -> Log.d(TAG, "updated I/O stat data: " + uidIoStats));
+                        uidIoStats -> Log.d(TAG, "updated I/O stat data: " + uidIoStats));
             }
         }
 
-        dispatchNewIoEvent(ioStats);
-        if (needsExcessiveIoBroadcast()) {
+        if (needsExcessiveIoBroadcast) {
             Log.d(TAG, "about to send " + INTENT_EXCESSIVE_IO);
             sendExcessiveIoBroadcast();
         }
@@ -287,33 +314,33 @@
         mContext.sendBroadcast(intent, mStorageMonitoringPermission.toString());
     }
 
-    private boolean needsExcessiveIoBroadcast() {
-        synchronized (mIoStatsSamplesLock) {
-            return mIoStatsSamples.count((IoStats delta) -> {
-                Metrics total = delta.getTotals();
-                final boolean tooManyBytesWritten =
+    @GuardedBy("mLock")
+    private boolean needsExcessiveIoBroadcastLocked() {
+        return mIoStatsSamples.count((IoStats delta) -> {
+            Metrics total = delta.getTotals();
+            final boolean tooManyBytesWritten =
                     (total.bytesWrittenToStorage > mConfiguration.acceptableBytesWrittenPerSample);
-                final boolean tooManyFsyncCalls =
+            final boolean tooManyFsyncCalls =
                     (total.fsyncCalls > mConfiguration.acceptableFsyncCallsPerSample);
-                return tooManyBytesWritten || tooManyFsyncCalls;
-            }) > mConfiguration.maxExcessiveIoSamplesInWindow;
-        }
+            return tooManyBytesWritten || tooManyFsyncCalls;
+        }) > mConfiguration.maxExcessiveIoSamplesInWindow;
     }
 
     private void dispatchNewIoEvent(IoStats delta) {
         final int listenersCount = mListeners.beginBroadcast();
         IntStream.range(0, listenersCount).forEach(
-            i -> {
-                try {
-                    mListeners.getBroadcastItem(i).onSnapshot(delta);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "failed to dispatch snapshot", e);
-                }
-            });
+                i -> {
+                    try {
+                        mListeners.getBroadcastItem(i).onSnapshot(delta);
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "failed to dispatch snapshot", e);
+                    }
+                });
         mListeners.finishBroadcast();
     }
 
-    private synchronized void doInitServiceIfNeeded() {
+    @GuardedBy("mLock")
+    private void doInitServiceIfNeededLocked() {
         if (mInitialized) return;
 
         Log.d(TAG, "initializing CarStorageMonitoringService");
@@ -322,7 +349,7 @@
 
         // TODO(egranata): can this be done lazily?
         final WearHistory wearHistory = loadWearHistory();
-        final boolean didWearChangeHappen = addEventIfNeeded(wearHistory);
+        final boolean didWearChangeHappen = addEventIfNeededLocked(wearHistory);
         if (didWearChangeHappen) {
             storeWearHistory(wearHistory);
         }
@@ -341,15 +368,15 @@
 
         long bootUptime = mSystemInterface.getUptime();
         mBootIoStats = SparseArrayStream.valueStream(loadNewIoStats())
-            .map(record -> {
-                // at boot, assume all UIDs have been running for as long as the system has
-                // been up, since we don't really know any better
-                IoStatsEntry stats = new IoStatsEntry(record, bootUptime);
-                if (DBG) {
-                    Log.d(TAG, "loaded boot I/O stat data: " + stats);
-                }
-                return stats;
-            }).collect(Collectors.toList());
+                .map(record -> {
+                    // at boot, assume all UIDs have been running for as long as the system has
+                    // been up, since we don't really know any better
+                    IoStatsEntry stats = new IoStatsEntry(record, bootUptime);
+                    if (DBG) {
+                        Log.d(TAG, "loaded boot I/O stat data: " + stats);
+                    }
+                    return stats;
+                }).collect(Collectors.toList());
 
         mIoStatsTracker = new IoStatsTracker(mBootIoStats,
                 mConfiguration.ioStatsRefreshRateMs,
@@ -357,12 +384,12 @@
 
         if (mConfiguration.ioStatsNumSamplesToStore > 0) {
             mSystemInterface.scheduleAction(this::collectNewIoMetrics,
-                mConfiguration.ioStatsRefreshRateMs);
+                    mConfiguration.ioStatsRefreshRateMs);
         } else {
             Log.i(TAG, "service configuration disabled I/O sample window. not collecting samples");
         }
 
-        mShutdownCostInfo = computeShutdownCost();
+        mShutdownCostInfo = computeShutdownCostLocked();
         Log.d(TAG, "calculated data written in last shutdown was " +
                 mShutdownCostInfo + " bytes");
         mLifetimeWriteFile.delete();
@@ -372,7 +399,8 @@
         mInitialized = true;
     }
 
-    private long computeShutdownCost() {
+    @GuardedBy("mLock")
+    private long computeShutdownCostLocked() {
         List<LifetimeWriteInfo> shutdownWrites = loadLifetimeWrites();
         if (shutdownWrites.isEmpty()) {
             Log.d(TAG, "lifetime write data from last shutdown missing");
@@ -391,10 +419,10 @@
 
         Map<String, Long> shutdownLifetimeWrites = new HashMap<>();
         shutdownWrites.forEach(li ->
-            shutdownLifetimeWrites.put(li.partition, li.writtenBytes));
+                shutdownLifetimeWrites.put(li.partition, li.writtenBytes));
 
         // for every partition currently available, look for it in the shutdown data
-        for(int i = 0; i < currentWrites.size(); ++i) {
+        for (int i = 0; i < currentWrites.size(); ++i) {
             LifetimeWriteInfo li = currentWrites.get(i);
             // if this partition was not available when we last shutdown the system, then
             // just pretend we had written the same amount of data then as we have now
@@ -402,19 +430,19 @@
                     shutdownLifetimeWrites.getOrDefault(li.partition, li.writtenBytes);
             final long costDelta = li.writtenBytes - writtenAtShutdown;
             if (costDelta >= 0) {
-                Log.d(TAG, "partition " + li.partition + " had " + costDelta +
-                    " bytes written to it during shutdown");
+                Log.d(TAG, "partition " + li.partition + " had " + costDelta
+                        + " bytes written to it during shutdown");
                 shutdownCost += costDelta;
             } else {
                 // the counter of written bytes should be monotonic; a decrease might mean
                 // corrupt data, improper shutdown or that the kernel in use does not
                 // have proper monotonic guarantees on the lifetime write data. If any of these
                 // occur, it's probably safer to just bail out and say we don't know
-                mShutdownCostMissingReason = li.partition + " has a negative write amount (" +
-                        costDelta + " bytes)";
-                Log.e(TAG, "partition " + li.partition + " reported " + costDelta +
-                    " bytes written to it during shutdown. assuming we can't" +
-                    " determine proper shutdown information.");
+                mShutdownCostMissingReason = li.partition + " has a negative write amount ("
+                        + costDelta + " bytes)";
+                Log.e(TAG, "partition " + li.partition + " reported " + costDelta
+                        + " bytes written to it during shutdown. assuming we can't"
+                        + " determine proper shutdown information.");
                 return SHUTDOWN_COST_INFO_MISSING;
             }
         }
@@ -429,7 +457,7 @@
         }
         try {
             JSONObject jsonObject = new JSONObject(
-                new String(Files.readAllBytes(mLifetimeWriteFile.toPath())));
+                    new String(Files.readAllBytes(mLifetimeWriteFile.toPath())));
 
             JSONArray jsonArray = jsonObject.getJSONArray("lifetimeWriteInfo");
 
@@ -447,7 +475,7 @@
     private void logLifetimeWrites() {
         try {
             LifetimeWriteInfo[] lifetimeWriteInfos =
-                mSystemInterface.getLifetimeWriteInfoProvider().load();
+                    mSystemInterface.getLifetimeWriteInfoProvider().load();
             JsonWriter jsonWriter = new JsonWriter(new FileWriter(mLifetimeWriteFile));
             jsonWriter.beginObject();
             jsonWriter.name("lifetimeWriteInfo").beginArray();
@@ -465,8 +493,10 @@
     @Override
     public void release() {
         Log.i(TAG, "tearing down CarStorageMonitoringService");
-        if (mUptimeTracker != null) {
-            mUptimeTracker.onDestroy();
+        synchronized (mLock) {
+            if (mUptimeTracker != null) {
+                mUptimeTracker.onDestroy();
+            }
         }
         mOnShutdownReboot.clearActions();
         mListeners.kill();
@@ -474,39 +504,38 @@
 
     @Override
     public void dump(PrintWriter writer) {
-        doInitServiceIfNeeded();
-
         writer.println("*CarStorageMonitoringService*");
-        writer.println("last wear information retrieved: " +
-            mWearInformation.map(WearInformation::toString).orElse("missing"));
-        writer.println("wear change history: " +
-            mWearEstimateChanges.stream()
-                .map(WearEstimateChange::toString)
-                .collect(Collectors.joining("\n")));
-        writer.println("boot I/O stats: " +
-            mBootIoStats.stream()
-                .map(IoStatsEntry::toString)
-                .collect(Collectors.joining("\n")));
-        writer.println("aggregate I/O stats: " +
-            SparseArrayStream.valueStream(mIoStatsTracker.getTotal())
-                .map(IoStatsEntry::toString)
-                .collect(Collectors.joining("\n")));
-        writer.println("I/O stats snapshots: ");
-        synchronized (mIoStatsSamplesLock) {
+        synchronized (mLock) {
+            doInitServiceIfNeededLocked();
+            writer.println("last wear information retrieved: "
+                    + mWearInformation.map(WearInformation::toString).orElse("missing"));
+            writer.println("wear change history: "
+                    + mWearEstimateChanges.stream()
+                    .map(WearEstimateChange::toString)
+                    .collect(Collectors.joining("\n")));
+            writer.println("boot I/O stats: "
+                    + mBootIoStats.stream()
+                    .map(IoStatsEntry::toString)
+                    .collect(Collectors.joining("\n")));
+            writer.println("aggregate I/O stats: "
+                    + SparseArrayStream.valueStream(mIoStatsTracker.getTotal())
+                    .map(IoStatsEntry::toString)
+                    .collect(Collectors.joining("\n")));
+            writer.println("I/O stats snapshots: ");
             writer.println(
-                mIoStatsSamples.stream().map(
-                    sample -> sample.getStats().stream()
-                        .map(IoStatsEntry::toString)
-                        .collect(Collectors.joining("\n")))
-                    .collect(Collectors.joining("\n------\n")));
-        }
-        if (mShutdownCostInfo < 0) {
-            writer.print("last shutdown cost: missing. ");
-            if (mShutdownCostMissingReason != null && !mShutdownCostMissingReason.isEmpty()) {
-                writer.println("reason: " + mShutdownCostMissingReason);
+                    mIoStatsSamples.stream().map(
+                            sample -> sample.getStats().stream()
+                                    .map(IoStatsEntry::toString)
+                                    .collect(Collectors.joining("\n")))
+                            .collect(Collectors.joining("\n------\n")));
+            if (mShutdownCostInfo < 0) {
+                writer.print("last shutdown cost: missing. ");
+                if (mShutdownCostMissingReason != null && !mShutdownCostMissingReason.isEmpty()) {
+                    writer.println("reason: " + mShutdownCostMissingReason);
+                }
+            } else {
+                writer.println("last shutdown cost: " + mShutdownCostInfo + " bytes, estimated");
             }
-        } else {
-            writer.println("last shutdown cost: " + mShutdownCostInfo + " bytes, estimated");
         }
     }
 
@@ -515,70 +544,82 @@
     @Override
     public int getPreEolIndicatorStatus() {
         mStorageMonitoringPermission.assertGranted();
-        doInitServiceIfNeeded();
+        synchronized (mLock) {
+            doInitServiceIfNeededLocked();
 
-        return mWearInformation.map(wi -> wi.preEolInfo)
-                .orElse(WearInformation.UNKNOWN_PRE_EOL_INFO);
+            return mWearInformation.map(wi -> wi.preEolInfo)
+                    .orElse(WearInformation.UNKNOWN_PRE_EOL_INFO);
+        }
     }
 
     @Override
     public WearEstimate getWearEstimate() {
         mStorageMonitoringPermission.assertGranted();
-        doInitServiceIfNeeded();
+        synchronized (mLock) {
+            doInitServiceIfNeededLocked();
 
-        return mWearInformation.map(wi ->
-                new WearEstimate(wi.lifetimeEstimateA,wi.lifetimeEstimateB)).orElse(
+            return mWearInformation.map(wi ->
+                    new WearEstimate(wi.lifetimeEstimateA, wi.lifetimeEstimateB)).orElse(
                     WearEstimate.UNKNOWN_ESTIMATE);
+        }
     }
 
     @Override
     public List<WearEstimateChange> getWearEstimateHistory() {
         mStorageMonitoringPermission.assertGranted();
-        doInitServiceIfNeeded();
+        synchronized (mLock) {
+            doInitServiceIfNeededLocked();
 
-        return mWearEstimateChanges;
+            return Collections.unmodifiableList(mWearEstimateChanges);
+        }
     }
 
     @Override
     public List<IoStatsEntry> getBootIoStats() {
         mStorageMonitoringPermission.assertGranted();
-        doInitServiceIfNeeded();
+        doInitServiceIfNeededLocked();
 
-        return mBootIoStats;
+        return Collections.unmodifiableList(mBootIoStats);
     }
 
     @Override
     public List<IoStatsEntry> getAggregateIoStats() {
         mStorageMonitoringPermission.assertGranted();
-        doInitServiceIfNeeded();
+        synchronized (mLock) {
+            doInitServiceIfNeededLocked();
 
-        return SparseArrayStream.valueStream(mIoStatsTracker.getTotal())
-                .collect(Collectors.toList());
+            return Collections.unmodifiableList(SparseArrayStream.valueStream(
+                    mIoStatsTracker.getTotal()).collect(Collectors.toList()));
+        }
     }
 
     @Override
     public long getShutdownDiskWriteAmount() {
         mStorageMonitoringPermission.assertGranted();
-        doInitServiceIfNeeded();
+        synchronized (mLock) {
+            doInitServiceIfNeededLocked();
 
-        return mShutdownCostInfo;
+            return mShutdownCostInfo;
+        }
     }
 
     @Override
     public List<IoStats> getIoStatsDeltas() {
         mStorageMonitoringPermission.assertGranted();
-        doInitServiceIfNeeded();
+        synchronized (mLock) {
+            doInitServiceIfNeededLocked();
 
-        synchronized (mIoStatsSamplesLock) {
-            return mIoStatsSamples.stream().collect(Collectors.toList());
+            return Collections.unmodifiableList(
+                    mIoStatsSamples.stream().collect(Collectors.toList()));
         }
     }
 
     @Override
     public void registerListener(IIoStatsListener listener) {
         mStorageMonitoringPermission.assertGranted();
-        doInitServiceIfNeeded();
-
+        synchronized (mLock) {
+            doInitServiceIfNeededLocked();
+        }
         mListeners.register(listener);
     }
 
@@ -609,13 +650,11 @@
                     resources.getInteger(R.integer.acceptableFsyncCallsPerSample);
             maxExcessiveIoSamplesInWindow =
                     resources.getInteger(R.integer.maxExcessiveIoSamplesInWindow);
-            uptimeIntervalBetweenUptimeDataWriteMs =
-                        60 * 60 * 1000 *
-                        resources.getInteger(R.integer.uptimeHoursIntervalBetweenUptimeDataWrite);
+            uptimeIntervalBetweenUptimeDataWriteMs = 60 * 60 * 1000
+                    * resources.getInteger(R.integer.uptimeHoursIntervalBetweenUptimeDataWrite);
             acceptableHoursPerOnePercentFlashWear =
                     resources.getInteger(R.integer.acceptableHoursPerOnePercentFlashWear);
-            ioStatsRefreshRateMs =
-                    1000 * resources.getInteger(R.integer.ioStatsRefreshRateSeconds);
+            ioStatsRefreshRateMs = 1000 * resources.getInteger(R.integer.ioStatsRefreshRateSeconds);
             activityHandlerForFlashWearChanges =
                     resources.getString(R.string.activityHandlerForFlashWearChanges);
             intentReceiverForUnacceptableIoMetrics =
@@ -624,25 +663,24 @@
 
         @Override
         public String toString() {
-            return String.format(
-                "acceptableBytesWrittenPerSample = %d, " +
-                "acceptableFsyncCallsPerSample = %d, " +
-                "acceptableHoursPerOnePercentFlashWear = %d, " +
-                "activityHandlerForFlashWearChanges = %s, " +
-                "intentReceiverForUnacceptableIoMetrics = %s, " +
-                "ioStatsNumSamplesToStore = %d, " +
-                "ioStatsRefreshRateMs = %d, " +
-                "maxExcessiveIoSamplesInWindow = %d, " +
-                "uptimeIntervalBetweenUptimeDataWriteMs = %d",
-                acceptableBytesWrittenPerSample,
-                acceptableFsyncCallsPerSample,
-                acceptableHoursPerOnePercentFlashWear,
-                activityHandlerForFlashWearChanges,
-                intentReceiverForUnacceptableIoMetrics,
-                ioStatsNumSamplesToStore,
-                ioStatsRefreshRateMs,
-                maxExcessiveIoSamplesInWindow,
-                uptimeIntervalBetweenUptimeDataWriteMs);
+            return String.format("acceptableBytesWrittenPerSample = %d, "
+                            + "acceptableFsyncCallsPerSample = %d, "
+                            + "acceptableHoursPerOnePercentFlashWear = %d, "
+                            + "activityHandlerForFlashWearChanges = %s, "
+                            + "intentReceiverForUnacceptableIoMetrics = %s, "
+                            + "ioStatsNumSamplesToStore = %d, "
+                            + "ioStatsRefreshRateMs = %d, "
+                            + "maxExcessiveIoSamplesInWindow = %d, "
+                            + "uptimeIntervalBetweenUptimeDataWriteMs = %d",
+                    acceptableBytesWrittenPerSample,
+                    acceptableFsyncCallsPerSample,
+                    acceptableHoursPerOnePercentFlashWear,
+                    activityHandlerForFlashWearChanges,
+                    intentReceiverForUnacceptableIoMetrics,
+                    ioStatsNumSamplesToStore,
+                    ioStatsRefreshRateMs,
+                    maxExcessiveIoSamplesInWindow,
+                    uptimeIntervalBetweenUptimeDataWriteMs);
         }
     }
 }
diff --git a/service/src/com/android/car/CarUxRestrictionsManagerService.java b/service/src/com/android/car/CarUxRestrictionsManagerService.java
index 0ea757f..88fc920 100644
--- a/service/src/com/android/car/CarUxRestrictionsManagerService.java
+++ b/service/src/com/android/car/CarUxRestrictionsManagerService.java
@@ -45,8 +45,11 @@
 import android.hardware.display.DisplayManager;
 import android.os.Binder;
 import android.os.Build;
-import android.os.IBinder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IRemoteCallback;
 import android.os.Process;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.ArraySet;
@@ -56,13 +59,13 @@
 import android.util.JsonWriter;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayAddress;
 
 import com.android.car.systeminterface.SystemInterface;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -107,7 +110,6 @@
     private static final int MAX_TRANSITION_LOG_SIZE = 20;
     private static final int PROPERTY_UPDATE_RATE = 5; // Update rate in Hz
     private static final float SPEED_NOT_AVAILABLE = -1.0F;
-    private static final byte DEFAULT_PORT = 0;
 
     private static final int UNKNOWN_JSON_SCHEMA_VERSION = -1;
     private static final int JSON_SCHEMA_VERSION_V1 = 1;
@@ -119,6 +121,7 @@
 
     private static final String JSON_NAME_SCHEMA_VERSION = "schema_version";
     private static final String JSON_NAME_RESTRICTIONS = "restrictions";
+    private static final byte DEFAULT_PORT = 0;
 
     @VisibleForTesting
     static final String CONFIG_FILENAME_PRODUCTION = "ux_restrictions_prod_config.json";
@@ -129,26 +132,57 @@
     private final DisplayManager mDisplayManager;
     private final CarDrivingStateService mDrivingStateService;
     private final CarPropertyService mCarPropertyService;
-    // List of clients listening to UX restriction events.
-    private final List<UxRestrictionsClient> mUxRClients = new ArrayList<>();
+    private final HandlerThread mClientDispatchThread  = CarServiceUtils.getHandlerThread(
+            getClass().getSimpleName());
+    private final Handler mClientDispatchHandler  = new Handler(mClientDispatchThread.getLooper());
+    private final RemoteCallbackList<ICarUxRestrictionsChangeListener> mUxRClients =
+            new RemoteCallbackList<>();
 
+    /**
+     * Metadata associated with a binder callback.
+     */
+    private static class RemoteCallbackListCookie {
+        final Byte mPhysicalPort;
+
+        RemoteCallbackListCookie(Byte physicalPort) {
+            mPhysicalPort = physicalPort;
+        }
+    }
+
+    private final Object mLock = new Object();
+
+    /**
+     * This lookup caches the mapping from an int display id to a byte that represents a physical
+     * port. It includes mappings for virtual displays.
+     */
+    @GuardedBy("mLock")
+    private final Map<Integer, Byte> mPortLookup = new HashMap<>();
+
+    @GuardedBy("mLock")
+    private Map<Byte, CarUxRestrictionsConfiguration> mCarUxRestrictionsConfigurations;
+
+    @GuardedBy("mLock")
+    private Map<Byte, CarUxRestrictions> mCurrentUxRestrictions;
+
+    @GuardedBy("mLock")
+    private String mRestrictionMode = UX_RESTRICTION_MODE_BASELINE;
+
+    @GuardedBy("mLock")
     private float mCurrentMovingSpeed;
 
     // Byte represents a physical port for display.
+    @GuardedBy("mLock")
     private byte mDefaultDisplayPhysicalPort;
-    private final List<Byte> mPhysicalPorts = new ArrayList<>();
-    // This lookup caches the mapping from an int display id
-    // to a byte that represents a physical port.
-    private final Map<Integer, Byte> mPortLookup = new HashMap<>();
-    private Map<Byte, CarUxRestrictionsConfiguration> mCarUxRestrictionsConfigurations;
-    private Map<Byte, CarUxRestrictions> mCurrentUxRestrictions;
 
-    private String mRestrictionMode = UX_RESTRICTION_MODE_BASELINE;
+    @GuardedBy("mLock")
+    private final List<Byte> mPhysicalPorts = new ArrayList<>();
 
     // Flag to disable broadcasting UXR changes - for development purposes
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private boolean mUxRChangeBroadcastEnabled = true;
+
     // For dumpsys logging
+    @GuardedBy("mLock")
     private final LinkedList<Utils.TransitionLog> mTransitionLogs = new LinkedList<>();
 
     public CarUxRestrictionsManagerService(Context context, CarDrivingStateService drvService,
@@ -160,23 +194,26 @@
     }
 
     @Override
-    public synchronized void init() {
-        mDefaultDisplayPhysicalPort = getDefaultDisplayPhysicalPort();
+    public void init() {
+        synchronized (mLock) {
+            mDefaultDisplayPhysicalPort = getDefaultDisplayPhysicalPort(mDisplayManager);
+            initPhysicalPort();
 
-        initPhysicalPort();
+            // Unrestricted until driving state information is received. During boot up, we don't
+            // want
+            // everything to be blocked until data is available from CarPropertyManager.  If we
+            // start
+            // driving and we don't get speed or gear information, we have bigger problems.
+            mCurrentUxRestrictions = new HashMap<>();
+            for (byte port : mPhysicalPorts) {
+                mCurrentUxRestrictions.put(port, createUnrestrictedRestrictions());
+            }
 
-        // Unrestricted until driving state information is received. During boot up, we don't want
-        // everything to be blocked until data is available from CarPropertyManager.  If we start
-        // driving and we don't get speed or gear information, we have bigger problems.
-        mCurrentUxRestrictions = new HashMap<>();
-        for (byte port : mPhysicalPorts) {
-            mCurrentUxRestrictions.put(port, createUnrestrictedRestrictions());
+            // Load the prod config, or if there is a staged one, promote that first only if the
+            // current driving state, as provided by the driving state service, is parked.
+            mCarUxRestrictionsConfigurations = convertToMap(loadConfig());
         }
 
-        // Load the prod config, or if there is a staged one, promote that first only if the
-        // current driving state, as provided by the driving state service, is parked.
-        mCarUxRestrictionsConfigurations = convertToMap(loadConfig());
-
         // subscribe to driving state changes
         mDrivingStateService.registerDrivingStateChangeListener(
                 mICarDrivingStateChangeEventListener);
@@ -190,7 +227,9 @@
     @Override
     public List<CarUxRestrictionsConfiguration> getConfigs() {
         ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION);
-        return new ArrayList<>(mCarUxRestrictionsConfigurations.values());
+        synchronized (mLock) {
+            return new ArrayList<>(mCarUxRestrictionsConfigurations.values());
+        }
     }
 
     /**
@@ -207,7 +246,7 @@
      * driving state.
      */
     @VisibleForTesting
-    synchronized List<CarUxRestrictionsConfiguration> loadConfig() {
+    List<CarUxRestrictionsConfiguration> loadConfig() {
         promoteStagedConfig();
         List<CarUxRestrictionsConfiguration> configs;
 
@@ -232,8 +271,10 @@
         Log.w(TAG, "Creating default config");
 
         configs = new ArrayList<>();
-        for (byte port : mPhysicalPorts) {
-            configs.add(createDefaultConfig(port));
+        synchronized (mLock) {
+            for (byte port : mPhysicalPorts) {
+                configs.add(createDefaultConfig(port));
+            }
         }
         return configs;
     }
@@ -297,7 +338,9 @@
         // At this point the underlying CarPropertyService has provided us enough information to
         // compute the UX restrictions that could be potentially different from the initial UX
         // restrictions.
-        handleDispatchUxRestrictions(currentDrivingState, currentSpeed);
+        synchronized (mLock) {
+            handleDispatchUxRestrictionsLocked(currentDrivingState, currentSpeed);
+        }
     }
 
     private Float getCurrentSpeed() {
@@ -310,13 +353,21 @@
     }
 
     @Override
-    public synchronized void release() {
-        for (UxRestrictionsClient client : mUxRClients) {
-            client.listenerBinder.unlinkToDeath(client, 0);
+    public void release() {
+        while (mUxRClients.getRegisteredCallbackCount() > 0) {
+            for (int i = mUxRClients.getRegisteredCallbackCount() - 1; i >= 0; i--) {
+                ICarUxRestrictionsChangeListener client = mUxRClients.getRegisteredCallbackItem(i);
+                if (client == null) {
+                    continue;
+                }
+                mUxRClients.unregister(client);
+            }
         }
-        mUxRClients.clear();
         mDrivingStateService.unregisterDrivingStateChangeListener(
                 mICarDrivingStateChangeEventListener);
+        synchronized (mLock) {
+            mActivityViewDisplayInfoMap.clear();
+        }
     }
 
     // Binder methods
@@ -329,44 +380,20 @@
      * @param displayId UX restrictions on this display will be notified.
      */
     @Override
-    public synchronized void registerUxRestrictionsChangeListener(
+    public void registerUxRestrictionsChangeListener(
             ICarUxRestrictionsChangeListener listener, int displayId) {
         if (listener == null) {
             Log.e(TAG, "registerUxRestrictionsChangeListener(): listener null");
             throw new IllegalArgumentException("Listener is null");
         }
-        // If a new client is registering, create a new DrivingStateClient and add it to the list
-        // of listening clients.
-        UxRestrictionsClient client = findUxRestrictionsClient(listener);
-        if (client == null) {
-            client = new UxRestrictionsClient(listener, displayId);
-            try {
-                listener.asBinder().linkToDeath(client, 0);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Cannot link death recipient to binder " + e);
-            }
-            mUxRClients.add(client);
-        }
-        return;
-    }
-
-    /**
-     * Iterates through the list of registered UX Restrictions clients -
-     * {@link UxRestrictionsClient} and finds if the given client is already registered.
-     *
-     * @param listener Listener to look for.
-     * @return the {@link UxRestrictionsClient} if found, null if not
-     */
-    @Nullable
-    private UxRestrictionsClient findUxRestrictionsClient(
-            ICarUxRestrictionsChangeListener listener) {
-        IBinder binder = listener.asBinder();
-        for (UxRestrictionsClient client : mUxRClients) {
-            if (client.isHoldingBinder(binder)) {
-                return client;
+        Byte physicalPort;
+        synchronized (mLock) {
+            physicalPort = getPhysicalPortLocked(displayId);
+            if (physicalPort == null) {
+                physicalPort = mDefaultDisplayPhysicalPort;
             }
         }
-        return null;
+        mUxRClients.register(listener, new RemoteCallbackListCookie(physicalPort));
     }
 
     /**
@@ -375,21 +402,13 @@
      * @param listener client to unregister
      */
     @Override
-    public synchronized void unregisterUxRestrictionsChangeListener(
-            ICarUxRestrictionsChangeListener listener) {
+    public void unregisterUxRestrictionsChangeListener(ICarUxRestrictionsChangeListener listener) {
         if (listener == null) {
             Log.e(TAG, "unregisterUxRestrictionsChangeListener(): listener null");
             throw new IllegalArgumentException("Listener is null");
         }
 
-        UxRestrictionsClient client = findUxRestrictionsClient(listener);
-        if (client == null) {
-            Log.e(TAG, "unregisterUxRestrictionsChangeListener(): listener was not previously "
-                    + "registered");
-            return;
-        }
-        listener.asBinder().unlinkToDeath(client, 0);
-        mUxRClients.remove(client);
+        mUxRClients.unregister(listener);
     }
 
     /**
@@ -398,8 +417,11 @@
      * @param displayId UX restrictions on this display will be returned.
      */
     @Override
-    public synchronized CarUxRestrictions getCurrentUxRestrictions(int displayId) {
-        CarUxRestrictions restrictions = mCurrentUxRestrictions.get(getPhysicalPort(displayId));
+    public CarUxRestrictions getCurrentUxRestrictions(int displayId) {
+        CarUxRestrictions restrictions;
+        synchronized (mLock) {
+            restrictions = mCurrentUxRestrictions.get(getPhysicalPortLocked(displayId));
+        }
         if (restrictions == null) {
             Log.e(TAG, String.format(
                     "Restrictions are null for displayId:%d. Returning full restrictions.",
@@ -413,12 +435,12 @@
      * Convenience method to retrieve restrictions for default display.
      */
     @Nullable
-    public synchronized CarUxRestrictions getCurrentUxRestrictions() {
+    public CarUxRestrictions getCurrentUxRestrictions() {
         return getCurrentUxRestrictions(Display.DEFAULT_DISPLAY);
     }
 
     @Override
-    public synchronized boolean saveUxRestrictionsConfigurationForNextBoot(
+    public boolean saveUxRestrictionsConfigurationForNextBoot(
             List<CarUxRestrictionsConfiguration> configs) {
         ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION);
 
@@ -454,30 +476,34 @@
      * @see CarUxRestrictionsConfiguration.Builder
      */
     @Override
-    public synchronized boolean setRestrictionMode(@NonNull String mode) {
+    public boolean setRestrictionMode(@NonNull String mode) {
         ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION);
         Objects.requireNonNull(mode, "mode must not be null");
 
-        if (mRestrictionMode.equals(mode)) {
-            return true;
+        synchronized (mLock) {
+            if (mRestrictionMode.equals(mode)) {
+                return true;
+            }
+
+            addTransitionLogLocked(TAG, mRestrictionMode, mode, System.currentTimeMillis(),
+                    "Restriction mode");
+            mRestrictionMode = mode;
+            logd("Set restriction mode to: " + mode);
+
+            handleDispatchUxRestrictionsLocked(
+                    mDrivingStateService.getCurrentDrivingState().eventValue, getCurrentSpeed());
         }
-
-        addTransitionLog(TAG, mRestrictionMode, mode, System.currentTimeMillis(),
-                "Restriction mode");
-        mRestrictionMode = mode;
-        logd("Set restriction mode to: " + mode);
-
-        handleDispatchUxRestrictions(
-                mDrivingStateService.getCurrentDrivingState().eventValue, getCurrentSpeed());
         return true;
     }
 
     @Override
     @NonNull
-    public synchronized String getRestrictionMode() {
+    public String getRestrictionMode() {
         ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION);
 
-        return mRestrictionMode;
+        synchronized (mLock) {
+            return mRestrictionMode;
+        }
     }
 
     /**
@@ -497,15 +523,7 @@
         }
         try (JsonWriter jsonWriter = new JsonWriter(
                 new OutputStreamWriter(fos, StandardCharsets.UTF_8))) {
-            jsonWriter.beginObject();
-            jsonWriter.name(JSON_NAME_SCHEMA_VERSION).value(JSON_SCHEMA_VERSION_V2);
-            jsonWriter.name(JSON_NAME_RESTRICTIONS);
-            jsonWriter.beginArray();
-            for (CarUxRestrictionsConfiguration config : configs) {
-                config.writeJson(jsonWriter);
-            }
-            jsonWriter.endArray();
-            jsonWriter.endObject();
+            writeJson(jsonWriter, configs);
         } catch (IOException e) {
             Log.e(TAG, "Could not persist config", e);
             stagedFile.failWrite(fos);
@@ -515,6 +533,20 @@
         return true;
     }
 
+    @VisibleForTesting
+    void writeJson(JsonWriter jsonWriter, List<CarUxRestrictionsConfiguration> configs)
+            throws IOException {
+        jsonWriter.beginObject();
+        jsonWriter.name(JSON_NAME_SCHEMA_VERSION).value(JSON_SCHEMA_VERSION_V2);
+        jsonWriter.name(JSON_NAME_RESTRICTIONS);
+        jsonWriter.beginArray();
+        for (CarUxRestrictionsConfiguration config : configs) {
+            config.writeJson(jsonWriter);
+        }
+        jsonWriter.endArray();
+        jsonWriter.endObject();
+    }
+
     @Nullable
     private List<CarUxRestrictionsConfiguration> readPersistedConfig(File file) {
         if (!file.exists()) {
@@ -617,7 +649,7 @@
      * This method works only on debug builds and the caller of this method needs to have the same
      * signature of the car service.
      */
-    public synchronized void setUxRChangeBroadcastEnabled(boolean enable) {
+    public void setUxRChangeBroadcastEnabled(boolean enable) {
         if (!isDebugBuild()) {
             Log.e(TAG, "Cannot set UX restriction change broadcast.");
             return;
@@ -629,16 +661,20 @@
                     "Caller " + mContext.getPackageManager().getNameForUid(Binder.getCallingUid())
                             + " does not have the right signature");
         }
-        if (enable) {
-            // if enabling it back, send the current restrictions
-            mUxRChangeBroadcastEnabled = enable;
-            handleDispatchUxRestrictions(mDrivingStateService.getCurrentDrivingState().eventValue,
-                    getCurrentSpeed());
-        } else {
-            // fake parked state, so if the system is currently restricted, the restrictions are
-            // relaxed.
-            handleDispatchUxRestrictions(DRIVING_STATE_PARKED, 0);
-            mUxRChangeBroadcastEnabled = enable;
+
+        synchronized (mLock) {
+            if (enable) {
+                // if enabling it back, send the current restrictions
+                mUxRChangeBroadcastEnabled = enable;
+                handleDispatchUxRestrictionsLocked(
+                        mDrivingStateService.getCurrentDrivingState().eventValue,
+                        getCurrentSpeed());
+            } else {
+                // fake parked state, so if the system is currently restricted, the restrictions are
+                // relaxed.
+                handleDispatchUxRestrictionsLocked(DRIVING_STATE_PARKED, 0);
+                mUxRChangeBroadcastEnabled = enable;
+            }
         }
     }
 
@@ -646,76 +682,33 @@
         return Build.IS_USERDEBUG || Build.IS_ENG;
     }
 
-    /**
-     * Class that holds onto client related information - listener interface, process that hosts the
-     * binder object etc.
-     * It also registers for death notifications of the host.
-     */
-    private class UxRestrictionsClient implements IBinder.DeathRecipient {
-        private final IBinder listenerBinder;
-        private final ICarUxRestrictionsChangeListener listener;
-        private final int mDisplayId;
-
-        UxRestrictionsClient(ICarUxRestrictionsChangeListener l, int displayId) {
-            listener = l;
-            listenerBinder = l.asBinder();
-            mDisplayId = displayId;
-        }
-
-        @Override
-        public void binderDied() {
-            logd("Binder died " + listenerBinder);
-            listenerBinder.unlinkToDeath(this, 0);
-            synchronized (CarUxRestrictionsManagerService.this) {
-                mUxRClients.remove(this);
-            }
-        }
-
-        /**
-         * Returns if the given binder object matches to what this client info holds.
-         * Used to check if the listener asking to be registered is already registered.
-         *
-         * @return true if matches, false if not
-         */
-        public boolean isHoldingBinder(IBinder binder) {
-            return listenerBinder == binder;
-        }
-
-        /**
-         * Dispatch the event to the listener
-         *
-         * @param event {@link CarUxRestrictions}.
-         */
-        public void dispatchEventToClients(CarUxRestrictions event) {
-            if (event == null) {
-                return;
-            }
-            try {
-                listener.onUxRestrictionsChanged(event);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Dispatch to listener failed", e);
-            }
-        }
-    }
-
     @Override
     public void dump(PrintWriter writer) {
-        writer.println("*CarUxRestrictionsManagerService*");
-        for (byte port : mCurrentUxRestrictions.keySet()) {
-            CarUxRestrictions restrictions = mCurrentUxRestrictions.get(port);
-            writer.printf("Port: 0x%02X UXR: %s\n", port, restrictions.toString());
-        }
-        if (isDebugBuild()) {
-            writer.println("mUxRChangeBroadcastEnabled? " + mUxRChangeBroadcastEnabled);
-        }
-
-        writer.println("UX Restriction configurations:");
-        for (CarUxRestrictionsConfiguration config : mCarUxRestrictionsConfigurations.values()) {
-            config.dump(writer);
-        }
-        writer.println("UX Restriction change log:");
-        for (Utils.TransitionLog tlog : mTransitionLogs) {
-            writer.println(tlog);
+        synchronized (mLock) {
+            writer.println("*CarUxRestrictionsManagerService*");
+            mUxRClients.dump(writer, "UX Restrictions Clients ");
+            for (byte port : mCurrentUxRestrictions.keySet()) {
+                CarUxRestrictions restrictions = mCurrentUxRestrictions.get(port);
+                writer.printf("Port: 0x%02X UXR: %s\n", port, restrictions.toString());
+            }
+            if (isDebugBuild()) {
+                writer.println("mUxRChangeBroadcastEnabled? " + mUxRChangeBroadcastEnabled);
+            }
+            writer.println("UX Restriction configurations:");
+            for (CarUxRestrictionsConfiguration config :
+                    mCarUxRestrictionsConfigurations.values()) {
+                config.dump(writer);
+            }
+            writer.println("UX Restriction change log:");
+            for (Utils.TransitionLog tlog : mTransitionLogs) {
+                writer.println(tlog);
+            }
+            writer.println("UX Restriction display info:");
+            for (int i = mActivityViewDisplayInfoMap.size() - 1; i >= 0; --i) {
+                DisplayInfo info = mActivityViewDisplayInfoMap.valueAt(i);
+                writer.printf("Display%d: physicalDisplayId=%d, owner=%s\n",
+                        mActivityViewDisplayInfoMap.keyAt(i), info.mPhysicalDisplayId, info.mOwner);
+            }
         }
     }
 
@@ -728,7 +721,9 @@
                 @Override
                 public void onDrivingStateChanged(CarDrivingStateEvent event) {
                     logd("Driving State Changed:" + event.eventValue);
-                    handleDrivingStateEvent(event);
+                    synchronized (mLock) {
+                        handleDrivingStateEventLocked(event);
+                    }
                 }
             };
 
@@ -737,7 +732,9 @@
      * Map the driving state to the corresponding UX Restrictions and dispatch the
      * UX Restriction change to the registered clients.
      */
-    private synchronized void handleDrivingStateEvent(CarDrivingStateEvent event) {
+    @VisibleForTesting
+    @GuardedBy("mLock")
+    void handleDrivingStateEventLocked(CarDrivingStateEvent event) {
         if (event == null) {
             return;
         }
@@ -759,7 +756,7 @@
             Log.e(TAG, "Unexpected:  Speed null when driving state is: " + drivingState);
             return;
         }
-        handleDispatchUxRestrictions(drivingState, mCurrentMovingSpeed);
+        handleDispatchUxRestrictionsLocked(drivingState, mCurrentMovingSpeed);
     }
 
     /**
@@ -770,18 +767,22 @@
             new ICarPropertyEventListener.Stub() {
                 @Override
                 public void onEvent(List<CarPropertyEvent> events) throws RemoteException {
-                    for (CarPropertyEvent event : events) {
-                        if ((event.getEventType()
-                                == CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE)
-                                && (event.getCarPropertyValue().getPropertyId()
-                                == VehicleProperty.PERF_VEHICLE_SPEED)) {
-                            handleSpeedChange((Float) event.getCarPropertyValue().getValue());
+                    synchronized (mLock) {
+                        for (CarPropertyEvent event : events) {
+                            if ((event.getEventType()
+                                    == CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE)
+                                    && (event.getCarPropertyValue().getPropertyId()
+                                    == VehicleProperty.PERF_VEHICLE_SPEED)) {
+                                handleSpeedChangeLocked(
+                                        (Float) event.getCarPropertyValue().getValue());
+                            }
                         }
                     }
                 }
             };
 
-    private synchronized void handleSpeedChange(float newSpeed) {
+    @GuardedBy("mLock")
+    private void handleSpeedChangeLocked(float newSpeed) {
         if (newSpeed == mCurrentMovingSpeed) {
             // Ignore if speed hasn't changed
             return;
@@ -792,7 +793,7 @@
             return;
         }
         mCurrentMovingSpeed = newSpeed;
-        handleDispatchUxRestrictions(currentDrivingState, newSpeed);
+        handleDispatchUxRestrictionsLocked(currentDrivingState, newSpeed);
     }
 
     /**
@@ -801,11 +802,12 @@
      * @param currentDrivingState driving state of the vehicle
      * @param speed               speed of the vehicle
      */
-    private synchronized void handleDispatchUxRestrictions(@CarDrivingState int currentDrivingState,
+    @GuardedBy("mLock")
+    private void handleDispatchUxRestrictionsLocked(@CarDrivingState int currentDrivingState,
             float speed) {
-        Preconditions.checkNotNull(mCarUxRestrictionsConfigurations,
+        Objects.requireNonNull(mCarUxRestrictionsConfigurations,
                 "mCarUxRestrictionsConfigurations must be initialized");
-        Preconditions.checkNotNull(mCurrentUxRestrictions,
+        Objects.requireNonNull(mCurrentUxRestrictions,
                 "mCurrentUxRestrictions must be initialized");
 
         if (isDebugBuild() && !mUxRChangeBroadcastEnabled) {
@@ -851,30 +853,56 @@
         }
 
         for (byte port : displayToDispatch) {
-            addTransitionLog(
+            addTransitionLogLocked(
                     mCurrentUxRestrictions.get(port), newUxRestrictions.get(port));
         }
 
-        logd("dispatching to clients");
-        for (UxRestrictionsClient client : mUxRClients) {
-            Byte clientDisplayPort = getPhysicalPort(client.mDisplayId);
-            if (clientDisplayPort == null) {
-                clientDisplayPort = mDefaultDisplayPhysicalPort;
-            }
-            if (displayToDispatch.contains(clientDisplayPort)) {
-                client.dispatchEventToClients(newUxRestrictions.get(clientDisplayPort));
-            }
-        }
+        dispatchRestrictionsToClients(newUxRestrictions, displayToDispatch);
 
         mCurrentUxRestrictions = newUxRestrictions;
     }
 
-    private byte getDefaultDisplayPhysicalPort() {
-        Display defaultDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
+    private void dispatchRestrictionsToClients(Map<Byte, CarUxRestrictions> displayRestrictions,
+            Set<Byte> displayToDispatch) {
+        logd("dispatching to clients");
+        boolean success = mClientDispatchHandler.post(() -> {
+            int numClients = mUxRClients.beginBroadcast();
+            for (int i = 0; i < numClients; i++) {
+                ICarUxRestrictionsChangeListener callback = mUxRClients.getBroadcastItem(i);
+                RemoteCallbackListCookie cookie =
+                        (RemoteCallbackListCookie) mUxRClients.getBroadcastCookie(i);
+                if (!displayToDispatch.contains(cookie.mPhysicalPort)) {
+                    continue;
+                }
+                CarUxRestrictions restrictions = displayRestrictions.get(cookie.mPhysicalPort);
+                if (restrictions == null) {
+                    // don't dispatch to displays without configurations
+                    continue;
+                }
+                try {
+                    callback.onUxRestrictionsChanged(restrictions);
+                } catch (RemoteException e) {
+                    Log.e(TAG,
+                            String.format("Dispatch to listener %s failed for restrictions (%s)",
+                                    callback, restrictions));
+                }
+            }
+            mUxRClients.finishBroadcast();
+        });
+
+        if (!success) {
+            Log.e(TAG, String.format("Unable to post (%s) event to dispatch handler",
+                    displayRestrictions));
+        }
+    }
+
+    @VisibleForTesting
+    static byte getDefaultDisplayPhysicalPort(DisplayManager displayManager) {
+        Display defaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
         DisplayAddress.Physical address = (DisplayAddress.Physical) defaultDisplay.getAddress();
 
         if (address == null) {
-            Log.w(TAG, "Default display does not have physical display port.");
+            Log.e(TAG, "Default display does not have physical display port. Using 0 as port.");
             return DEFAULT_PORT;
         }
         return address.getPort();
@@ -892,14 +920,19 @@
                 if (Log.isLoggable(TAG, Log.INFO)) {
                     Log.i(TAG, "Default display does not have display address. Using default.");
                 }
-                mPhysicalPorts.add(mDefaultDisplayPhysicalPort);
+                synchronized (mLock) {
+                    mPhysicalPorts.add(mDefaultDisplayPhysicalPort);
+                }
             } else if (display.getAddress() instanceof DisplayAddress.Physical) {
                 byte port = ((DisplayAddress.Physical) display.getAddress()).getPort();
                 if (Log.isLoggable(TAG, Log.INFO)) {
                     Log.i(TAG, String.format(
-                            "Display %d uses port %d", display.getDisplayId(), port));
+                            "Display %d uses port %d", display.getDisplayId(),
+                            Byte.toUnsignedInt(port)));
                 }
-                mPhysicalPorts.add(port);
+                synchronized (mLock) {
+                    mPhysicalPorts.add(port);
+                }
             } else {
                 Log.w(TAG, "At init non-virtual display has a non-physical display address: "
                         + display);
@@ -914,10 +947,12 @@
         Map<Byte, CarUxRestrictionsConfiguration> result = new HashMap<>();
         if (configs.size() == 1) {
             CarUxRestrictionsConfiguration config = configs.get(0);
-            byte port = config.getPhysicalPort() == null
-                    ? mDefaultDisplayPhysicalPort
-                    : config.getPhysicalPort();
-            result.put(port, config);
+            synchronized (mLock) {
+                byte port = config.getPhysicalPort() == null
+                        ? mDefaultDisplayPhysicalPort
+                        : config.getPhysicalPort();
+                result.put(port, config);
+            }
         } else {
             for (CarUxRestrictionsConfiguration config : configs) {
                 result.put(config.getPhysicalPort(), config);
@@ -972,22 +1007,25 @@
      * DisplayManager#getDisplay(int)} is not aware of the provided id.
      */
     @Nullable
-    private Byte getPhysicalPort(int displayId) {
+    @GuardedBy("mLock")
+    private Byte getPhysicalPortLocked(int displayId) {
         if (!mPortLookup.containsKey(displayId)) {
             Display display = mDisplayManager.getDisplay(displayId);
             if (display == null) {
                 Log.w(TAG, "Could not retrieve display for id: " + displayId);
                 return null;
             }
-            byte port = getPhysicalPort(display);
+            byte port = doGetPhysicalPortLocked(display);
             mPortLookup.put(displayId, port);
         }
         return mPortLookup.get(displayId);
     }
 
-    private byte getPhysicalPort(@NonNull Display display) {
+    @GuardedBy("mLock")
+    private byte doGetPhysicalPortLocked(@NonNull Display display) {
         if (display.getType() == Display.TYPE_VIRTUAL) {
-            // We require all virtual displays to be launched on default display.
+            Log.e(TAG, "Display " + display
+                    + " is a virtual display and does not have a known port.");
             return mDefaultDisplayPhysicalPort;
         }
 
@@ -1031,7 +1069,8 @@
                 .build();
     }
 
-    private void addTransitionLog(String name, String from, String to, long timestamp,
+    @GuardedBy("mLock")
+    private void addTransitionLogLocked(String name, String from, String to, long timestamp,
             String extra) {
         if (mTransitionLogs.size() >= MAX_TRANSITION_LOG_SIZE) {
             mTransitionLogs.remove();
@@ -1041,7 +1080,8 @@
         mTransitionLogs.add(tLog);
     }
 
-    private void addTransitionLog(
+    @GuardedBy("mLock")
+    private void addTransitionLogLocked(
             CarUxRestrictions oldRestrictions, CarUxRestrictions newRestrictions) {
         if (mTransitionLogs.size() >= MAX_TRANSITION_LOG_SIZE) {
             mTransitionLogs.remove();
@@ -1061,4 +1101,101 @@
             Slog.d(TAG, msg);
         }
     }
+
+    private static final class DisplayInfo {
+        final IRemoteCallback mOwner;
+        final int mPhysicalDisplayId;
+
+        DisplayInfo(IRemoteCallback owner, int physicalDisplayId) {
+            mOwner = owner;
+            mPhysicalDisplayId = physicalDisplayId;
+        }
+    }
+
+    @GuardedBy("mLock")
+    private final SparseArray<DisplayInfo> mActivityViewDisplayInfoMap = new SparseArray<>();
+
+    @GuardedBy("mLock")
+    private final RemoteCallbackList<IRemoteCallback> mRemoteCallbackList =
+            new RemoteCallbackList<>() {
+                @Override
+                public void onCallbackDied(IRemoteCallback callback) {
+                    synchronized (mLock) {
+                        // Descending order to delete items safely from SpareArray.gc().
+                        for (int i = mActivityViewDisplayInfoMap.size() - 1; i >= 0; --i) {
+                            DisplayInfo info = mActivityViewDisplayInfoMap.valueAt(i);
+                            if (info.mOwner == callback) {
+                                logd("onCallbackDied: clean up callback=" + callback);
+                                mActivityViewDisplayInfoMap.removeAt(i);
+                                mPortLookup.remove(mActivityViewDisplayInfoMap.keyAt(i));
+                            }
+                        }
+                    }
+                }
+            };
+
+    @Override
+    public void reportVirtualDisplayToPhysicalDisplay(IRemoteCallback callback,
+            int virtualDisplayId, int physicalDisplayId) {
+        logd("reportVirtualDisplayToPhysicalDisplay: callback=" + callback
+                + ", virtualDisplayId=" + virtualDisplayId
+                + ", physicalDisplayId=" + physicalDisplayId);
+        boolean release = physicalDisplayId == Display.INVALID_DISPLAY;
+        checkCallerOwnsDisplay(virtualDisplayId, release);
+        synchronized (mLock) {
+            if (release) {
+                mRemoteCallbackList.unregister(callback);
+                mActivityViewDisplayInfoMap.delete(virtualDisplayId);
+                mPortLookup.remove(virtualDisplayId);
+                return;
+            }
+            mRemoteCallbackList.register(callback);
+            mActivityViewDisplayInfoMap.put(virtualDisplayId,
+                    new DisplayInfo(callback, physicalDisplayId));
+            Byte physicalPort = getPhysicalPortLocked(physicalDisplayId);
+            if (physicalPort == null) {
+                // This should not happen.
+                Log.wtf(TAG, "No known physicalPort for displayId:" + physicalDisplayId);
+                physicalPort = mDefaultDisplayPhysicalPort;
+            }
+            mPortLookup.put(virtualDisplayId, physicalPort);
+        }
+    }
+
+    @Override
+    public int getMappedPhysicalDisplayOfVirtualDisplay(int displayId) {
+        logd("getMappedPhysicalDisplayOfVirtualDisplay: displayId=" + displayId);
+        synchronized (mLock) {
+            DisplayInfo foundInfo = mActivityViewDisplayInfoMap.get(displayId);
+            if (foundInfo == null) {
+                return Display.INVALID_DISPLAY;
+            }
+            // ActivityView can be placed in another ActivityView, so we should repeat the process
+            // until no parent is found (reached to the physical display).
+            while (foundInfo != null) {
+                displayId = foundInfo.mPhysicalDisplayId;
+                foundInfo = mActivityViewDisplayInfoMap.get(displayId);
+            }
+        }
+        return displayId;
+    }
+
+    private void checkCallerOwnsDisplay(int displayId, boolean release) {
+        Display display = mDisplayManager.getDisplay(displayId);
+        if (display == null) {
+            // Bypasses the permission check for non-existing display when releasing it, since
+            // reportVirtualDisplayToPhysicalDisplay() and releasing display happens simultaneously
+            // and it's no harm to release the information on the non-existing display.
+            if (release) return;
+            throw new IllegalArgumentException(
+                    "Cannot find display for non-existent displayId: " + displayId);
+        }
+
+        int callingUid = Binder.getCallingUid();
+        int displayOwnerUid = display.getOwnerUid();
+        if (callingUid != displayOwnerUid) {
+            throw new SecurityException("The caller doesn't own the display: callingUid="
+                    + callingUid + ", displayOwnerUid=" + displayOwnerUid);
+        }
+    }
 }
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index 483dd7f..4d78dad 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -17,38 +17,39 @@
 package com.android.car;
 
 import android.annotation.MainThread;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
-import android.app.ActivityOptions;
-import android.app.UiModeManager;
 import android.car.Car;
+import android.car.CarFeatures;
 import android.car.ICar;
 import android.car.cluster.renderer.IInstrumentClusterNavigation;
+import android.car.user.CarUserManager;
 import android.car.userlib.CarUserManagerHelper;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.hardware.automotive.vehicle.V2_0.IVehicle;
-import android.hardware.automotive.vehicle.V2_0.VehicleArea;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
+import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
 import android.os.Binder;
 import android.os.Build;
 import android.os.IBinder;
 import android.os.Process;
-import android.os.SystemClock;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
 import android.os.Trace;
+import android.os.UserManager;
+import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
 import android.util.TimingsTraceLog;
-import android.view.KeyEvent;
 
 import com.android.car.am.FixedActivityService;
 import com.android.car.audio.CarAudioService;
 import com.android.car.cluster.InstrumentClusterService;
 import com.android.car.garagemode.GarageModeService;
-import com.android.car.hal.InputHalService;
 import com.android.car.hal.VehicleHal;
-import com.android.car.internal.FeatureConfiguration;
 import com.android.car.pm.CarPackageManagerService;
 import com.android.car.stats.CarStatsService;
 import com.android.car.systeminterface.SystemInterface;
@@ -56,9 +57,12 @@
 import com.android.car.user.CarUserNoticeService;
 import com.android.car.user.CarUserService;
 import com.android.car.vms.VmsBrokerService;
-import com.android.car.vms.VmsClientManager;
+import com.android.car.watchdog.CarWatchdogService;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.car.EventLogTags;
 import com.android.internal.car.ICarServiceHelper;
+import com.android.internal.os.IResultReceiver;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -71,11 +75,14 @@
     public static final String INTERNAL_INPUT_SERVICE = "internal_input";
     public static final String INTERNAL_SYSTEM_ACTIVITY_MONITORING_SERVICE =
             "system_activity_monitoring";
-    public static final String INTERNAL_VMS_MANAGER = "vms_manager";
+
+    private static final int INITIAL_VHAL_GET_RETRY = 2;
 
     private final Context mContext;
     private final VehicleHal mHal;
 
+    private final CarFeatureController mFeatureController;
+
     private final SystemInterface mSystemInterface;
 
     private final SystemActivityMonitoringService mSystemActivityMonitoringService;
@@ -84,6 +91,7 @@
     private final CarInputService mCarInputService;
     private final CarDrivingStateService mCarDrivingStateService;
     private final CarUxRestrictionsManagerService mCarUXRestrictionsService;
+    private final OccupantAwarenessService mOccupantAwarenessService;
     private final CarAudioService mCarAudioService;
     private final CarProjectionService mCarProjectionService;
     private final CarPropertyService mCarPropertyService;
@@ -103,57 +111,104 @@
     private final CarMediaService mCarMediaService;
     private final CarUserManagerHelper mUserManagerHelper;
     private final CarUserService mCarUserService;
+    private final CarOccupantZoneService mCarOccupantZoneService;
     private final CarUserNoticeService mCarUserNoticeService;
-    private final VmsClientManager mVmsClientManager;
     private final VmsBrokerService mVmsBrokerService;
-    private final VmsSubscriberService mVmsSubscriberService;
-    private final VmsPublisherService mVmsPublisherService;
     private final CarBugreportManagerService mCarBugreportManagerService;
     private final CarStatsService mCarStatsService;
+    private final CarExperimentalFeatureServiceController mCarExperimentalFeatureServiceController;
+    private final CarWatchdogService mCarWatchdogService;
 
     private final CarServiceBase[] mAllServices;
 
     private static final String TAG = "ICarImpl";
     private static final String VHAL_TIMING_TAG = "VehicleHalTiming";
+    private static final boolean DBG = true; // TODO(b/154033860): STOPSHIP if true
 
     private TimingsTraceLog mBootTiming;
 
+    private final Object mLock = new Object();
+
     /** Test only service. Populate it only when necessary. */
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private CarTestService mCarTestService;
 
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private ICarServiceHelper mICarServiceHelper;
 
     private final String mVehicleInterfaceName;
 
     public ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
             CanBusErrorNotifier errorNotifier, String vehicleInterfaceName) {
+        this(serviceContext, vehicle, systemInterface, errorNotifier, vehicleInterfaceName,
+                /* carUserService= */ null, /* carWatchdogService= */ null);
+    }
+
+    @VisibleForTesting
+    ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
+            CanBusErrorNotifier errorNotifier, String vehicleInterfaceName,
+            @Nullable CarUserService carUserService,
+            @Nullable CarWatchdogService carWatchdogService) {
         mContext = serviceContext;
         mSystemInterface = systemInterface;
         mHal = new VehicleHal(serviceContext, vehicle);
+        // Do this before any other service components to allow feature check. It should work
+        // even without init. For that, vhal get is retried as it can be too early.
+        VehiclePropValue disabledOptionalFeatureValue = mHal.getIfAvailableOrFailForEarlyStage(
+                    VehicleProperty.DISABLED_OPTIONAL_FEATURES, INITIAL_VHAL_GET_RETRY);
+        String[] disabledFeaturesFromVhal = null;
+        if (disabledOptionalFeatureValue != null) {
+            String disabledFeatures = disabledOptionalFeatureValue.value.stringValue;
+            if (disabledFeatures != null && !disabledFeatures.isEmpty()) {
+                disabledFeaturesFromVhal = disabledFeatures.split(",");
+            }
+        }
+        if (disabledFeaturesFromVhal == null) {
+            disabledFeaturesFromVhal = new String[0];
+        }
+        Resources res = mContext.getResources();
+        String[] defaultEnabledFeatures = res.getStringArray(
+                R.array.config_allowed_optional_car_features);
+        mFeatureController = new CarFeatureController(serviceContext, defaultEnabledFeatures,
+                disabledFeaturesFromVhal , mSystemInterface.getSystemCarDir());
+        CarLocalServices.addService(CarFeatureController.class, mFeatureController);
         mVehicleInterfaceName = vehicleInterfaceName;
         mUserManagerHelper = new CarUserManagerHelper(serviceContext);
-        final Resources res = mContext.getResources();
-        final int maxRunningUsers = res.getInteger(
-                com.android.internal.R.integer.config_multiuserMaxRunningUsers);
-        mCarUserService = new CarUserService(serviceContext, mUserManagerHelper,
-                ActivityManager.getService(), maxRunningUsers);
+        if (carUserService != null) {
+            mCarUserService = carUserService;
+        } else {
+            UserManager userManager =
+                    (UserManager) serviceContext.getSystemService(Context.USER_SERVICE);
+            int maxRunningUsers = res.getInteger(
+                    com.android.internal.R.integer.config_multiuserMaxRunningUsers);
+            mCarUserService = new CarUserService(serviceContext, mHal.getUserHal(),
+                    mUserManagerHelper, userManager, ActivityManager.getService(), maxRunningUsers);
+        }
+        mCarOccupantZoneService = new CarOccupantZoneService(serviceContext);
         mSystemActivityMonitoringService = new SystemActivityMonitoringService(serviceContext);
         mCarPowerManagementService = new CarPowerManagementService(mContext, mHal.getPowerHal(),
-                systemInterface, mUserManagerHelper);
-        mCarUserNoticeService = new CarUserNoticeService(serviceContext);
+                systemInterface, mCarUserService);
+        if (mFeatureController.isFeatureEnabled(CarFeatures.FEATURE_CAR_USER_NOTICE_SERVICE)) {
+            mCarUserNoticeService = new CarUserNoticeService(serviceContext);
+        } else {
+            mCarUserNoticeService = null;
+        }
         mCarPropertyService = new CarPropertyService(serviceContext, mHal.getPropertyHal());
         mCarDrivingStateService = new CarDrivingStateService(serviceContext, mCarPropertyService);
         mCarUXRestrictionsService = new CarUxRestrictionsManagerService(serviceContext,
                 mCarDrivingStateService, mCarPropertyService);
+        if (mFeatureController.isFeatureEnabled(Car.OCCUPANT_AWARENESS_SERVICE)) {
+            mOccupantAwarenessService = new OccupantAwarenessService(serviceContext);
+        } else {
+            mOccupantAwarenessService = null;
+        }
         mCarPackageManagerService = new CarPackageManagerService(serviceContext,
                 mCarUXRestrictionsService,
                 mSystemActivityMonitoringService,
-                mUserManagerHelper);
-        mPerUserCarServiceHelper = new PerUserCarServiceHelper(serviceContext);
+                mCarUserService);
+        mPerUserCarServiceHelper = new PerUserCarServiceHelper(serviceContext, mCarUserService);
         mCarBluetoothService = new CarBluetoothService(serviceContext, mPerUserCarServiceHelper);
-        mCarInputService = new CarInputService(serviceContext, mHal.getInputHal());
+        mCarInputService = new CarInputService(serviceContext, mHal.getInputHal(), mCarUserService);
         mCarProjectionService = new CarProjectionService(
                 serviceContext, null /* handler */, mCarInputService, mCarBluetoothService);
         mGarageModeService = new GarageModeService(mContext);
@@ -166,26 +221,44 @@
         mSystemStateControllerService = new SystemStateControllerService(
                 serviceContext, mCarAudioService, this);
         mCarStatsService = new CarStatsService(serviceContext);
-        mVmsBrokerService = new VmsBrokerService();
-        mVmsClientManager = new VmsClientManager(
-                // CarStatsService needs to be passed to the constructor due to HAL init order
-                serviceContext, mCarStatsService, mCarUserService, mVmsBrokerService,
-                mHal.getVmsHal());
-        mVmsSubscriberService = new VmsSubscriberService(
-                serviceContext, mVmsBrokerService, mVmsClientManager, mHal.getVmsHal());
-        mVmsPublisherService = new VmsPublisherService(
-                serviceContext, mCarStatsService, mVmsBrokerService, mVmsClientManager);
-        mCarDiagnosticService = new CarDiagnosticService(serviceContext, mHal.getDiagnosticHal());
-        mCarStorageMonitoringService = new CarStorageMonitoringService(serviceContext,
-                systemInterface);
+        mCarStatsService.init();
+        if (mFeatureController.isFeatureEnabled(Car.VEHICLE_MAP_SERVICE)) {
+            mVmsBrokerService = new VmsBrokerService(mContext, mCarStatsService);
+        } else {
+            mVmsBrokerService = null;
+        }
+        if (mFeatureController.isFeatureEnabled(Car.DIAGNOSTIC_SERVICE)) {
+            mCarDiagnosticService = new CarDiagnosticService(serviceContext,
+                    mHal.getDiagnosticHal());
+        } else {
+            mCarDiagnosticService = null;
+        }
+        if (mFeatureController.isFeatureEnabled(Car.STORAGE_MONITORING_SERVICE)) {
+            mCarStorageMonitoringService = new CarStorageMonitoringService(serviceContext,
+                    systemInterface);
+        } else {
+            mCarStorageMonitoringService = null;
+        }
         mCarConfigurationService =
                 new CarConfigurationService(serviceContext, new JsonReaderImpl());
-        mCarLocationService = new CarLocationService(mContext, mUserManagerHelper);
+        mCarLocationService = new CarLocationService(serviceContext);
         mCarTrustedDeviceService = new CarTrustedDeviceService(serviceContext);
-        mCarMediaService = new CarMediaService(serviceContext);
+        mCarMediaService = new CarMediaService(serviceContext, mCarUserService);
         mCarBugreportManagerService = new CarBugreportManagerService(serviceContext);
+        if (!Build.IS_USER) {
+            mCarExperimentalFeatureServiceController = new CarExperimentalFeatureServiceController(
+                    serviceContext);
+        } else {
+            mCarExperimentalFeatureServiceController = null;
+        }
+        if (carWatchdogService == null) {
+            mCarWatchdogService = new CarWatchdogService(serviceContext);
+        } else {
+            mCarWatchdogService = carWatchdogService;
+        }
 
         CarLocalServices.addService(CarPowerManagementService.class, mCarPowerManagementService);
+        CarLocalServices.addService(CarPropertyService.class, mCarPropertyService);
         CarLocalServices.addService(CarUserService.class, mCarUserService);
         CarLocalServices.addService(CarTrustedDeviceService.class, mCarTrustedDeviceService);
         CarLocalServices.addService(CarUserNoticeService.class, mCarUserNoticeService);
@@ -193,19 +266,25 @@
         CarLocalServices.addService(CarDrivingStateService.class, mCarDrivingStateService);
         CarLocalServices.addService(PerUserCarServiceHelper.class, mPerUserCarServiceHelper);
         CarLocalServices.addService(FixedActivityService.class, mFixedActivityService);
+        CarLocalServices.addService(VmsBrokerService.class, mVmsBrokerService);
+        CarLocalServices.addService(CarOccupantZoneService.class, mCarOccupantZoneService);
+        CarLocalServices.addService(AppFocusService.class, mAppFocusService);
 
         // Be careful with order. Service depending on other service should be inited later.
         List<CarServiceBase> allServices = new ArrayList<>();
+        allServices.add(mFeatureController);
         allServices.add(mCarUserService);
         allServices.add(mSystemActivityMonitoringService);
         allServices.add(mCarPowerManagementService);
         allServices.add(mCarPropertyService);
         allServices.add(mCarDrivingStateService);
+        allServices.add(mCarOccupantZoneService);
         allServices.add(mCarUXRestrictionsService);
+        addServiceIfNonNull(allServices, mOccupantAwarenessService);
         allServices.add(mCarPackageManagerService);
         allServices.add(mCarInputService);
         allServices.add(mGarageModeService);
-        allServices.add(mCarUserNoticeService);
+        addServiceIfNonNull(allServices, mCarUserNoticeService);
         allServices.add(mAppFocusService);
         allServices.add(mCarAudioService);
         allServices.add(mCarNightService);
@@ -215,19 +294,26 @@
         allServices.add(mPerUserCarServiceHelper);
         allServices.add(mCarBluetoothService);
         allServices.add(mCarProjectionService);
-        allServices.add(mCarDiagnosticService);
-        allServices.add(mCarStorageMonitoringService);
+        addServiceIfNonNull(allServices, mCarDiagnosticService);
+        addServiceIfNonNull(allServices, mCarStorageMonitoringService);
         allServices.add(mCarConfigurationService);
-        allServices.add(mVmsClientManager);
-        allServices.add(mVmsSubscriberService);
-        allServices.add(mVmsPublisherService);
+        addServiceIfNonNull(allServices, mVmsBrokerService);
         allServices.add(mCarTrustedDeviceService);
         allServices.add(mCarMediaService);
         allServices.add(mCarLocationService);
         allServices.add(mCarBugreportManagerService);
+        allServices.add(mCarWatchdogService);
+        // Always put mCarExperimentalFeatureServiceController in last.
+        addServiceIfNonNull(allServices, mCarExperimentalFeatureServiceController);
         mAllServices = allServices.toArray(new CarServiceBase[allServices.size()]);
     }
 
+    private void addServiceIfNonNull(List<CarServiceBase> services, CarServiceBase service) {
+        if (service != null) {
+            services.add(service);
+        }
+    }
+
     @MainThread
     void init() {
         mBootTiming = new TimingsTraceLog(VHAL_TIMING_TAG, Trace.TRACE_TAG_HAL);
@@ -239,7 +325,6 @@
             service.init();
         }
         traceEnd();
-        mSystemInterface.reconfigureSecondaryDisplays();
     }
 
     void release() {
@@ -251,6 +336,7 @@
     }
 
     void vehicleHalReconnected(IVehicle vehicle) {
+        EventLog.writeEvent(EventLogTags.CAR_SERVICE_VHAL_RECONNECTED, mAllServices.length);
         mHal.vehicleHalReconnected(vehicle);
         for (CarServiceBase service : mAllServices) {
             service.vehicleHalReconnected();
@@ -259,26 +345,90 @@
 
     @Override
     public void setCarServiceHelper(IBinder helper) {
+        EventLog.writeEvent(EventLogTags.CAR_SERVICE_SET_CAR_SERVICE_HELPER,
+                Binder.getCallingPid());
         assertCallingFromSystemProcess();
-        synchronized (this) {
-            mICarServiceHelper = ICarServiceHelper.Stub.asInterface(helper);
-            mSystemInterface.setCarServiceHelper(mICarServiceHelper);
+        ICarServiceHelper carServiceHelper = ICarServiceHelper.Stub.asInterface(helper);
+        synchronized (mLock) {
+            mICarServiceHelper = carServiceHelper;
         }
+        mSystemInterface.setCarServiceHelper(carServiceHelper);
+        mCarOccupantZoneService.setCarServiceHelper(carServiceHelper);
     }
 
     @Override
-    public void setUserLockStatus(int userHandle, int unlocked) {
+    public void onUserLifecycleEvent(int eventType, long timestampMs, int fromUserId,
+            int toUserId) {
         assertCallingFromSystemProcess();
-        mCarUserService.setUserLockStatus(userHandle, unlocked == 1);
-        mCarMediaService.setUserLockStatus(userHandle, unlocked == 1);
+        EventLog.writeEvent(EventLogTags.CAR_SERVICE_ON_USER_LIFECYCLE, eventType, fromUserId,
+                toUserId);
+        if (DBG) {
+            Log.d(TAG, "onUserLifecycleEvent("
+                    + CarUserManager.lifecycleEventTypeToString(eventType) + ", " + toUserId + ")");
+        }
+        mCarUserService.onUserLifecycleEvent(eventType, timestampMs, fromUserId, toUserId);
     }
 
     @Override
-    public void onSwitchUser(int userHandle) {
-        assertCallingFromSystemProcess();
+    public void onFirstUserUnlocked(int userId, long timestampMs, long duration,
+            int halResponseTime) {
+        mCarUserService.onFirstUserUnlocked(userId, timestampMs, duration, halResponseTime);
+    }
 
-        Log.i(TAG, "Foreground user switched to " + userHandle);
-        mCarUserService.onSwitchUser(userHandle);
+    @Override
+    public void getInitialUserInfo(int requestType, int timeoutMs, IBinder binder) {
+        IResultReceiver receiver = IResultReceiver.Stub.asInterface(binder);
+        mCarUserService.getInitialUserInfo(requestType, timeoutMs, receiver);
+    }
+
+    @Override
+    public void setInitialUser(int userId) {
+        EventLog.writeEvent(EventLogTags.CAR_SERVICE_SET_INITIAL_USER, userId);
+        if (DBG) Log.d(TAG, "setInitialUser(): " + userId);
+        mCarUserService.setInitialUser(userId);
+    }
+
+    @Override
+    public boolean isFeatureEnabled(String featureName) {
+        return mFeatureController.isFeatureEnabled(featureName);
+    }
+
+    @Override
+    public int enableFeature(String featureName) {
+        // permission check inside the controller
+        return mFeatureController.enableFeature(featureName);
+    }
+
+    @Override
+    public int disableFeature(String featureName) {
+        // permission check inside the controller
+        return mFeatureController.disableFeature(featureName);
+    }
+
+    @Override
+    public List<String> getAllEnabledFeatures() {
+        // permission check inside the controller
+        return mFeatureController.getAllEnabledFeatures();
+    }
+
+    @Override
+    public List<String> getAllPendingDisabledFeatures() {
+        // permission check inside the controller
+        return mFeatureController.getAllPendingDisabledFeatures();
+    }
+
+    @Override
+    public List<String> getAllPendingEnabledFeatures() {
+        // permission check inside the controller
+        return mFeatureController.getAllPendingEnabledFeatures();
+    }
+
+    @Override
+    public String getCarManagerClassForFeature(String featureName) {
+        if (mCarExperimentalFeatureServiceController == null) {
+            return null;
+        }
+        return mCarExperimentalFeatureServiceController.getCarManagerClassForFeature(featureName);
     }
 
     static void assertCallingFromSystemProcess() {
@@ -303,6 +453,10 @@
 
     @Override
     public IBinder getCarService(String serviceName) {
+        if (!mFeatureController.isFeatureEnabled(serviceName)) {
+            Log.w(CarLog.TAG_SERVICE, "getCarService for disabled service:" + serviceName);
+            return null;
+        }
         switch (serviceName) {
             case Car.AUDIO_SERVICE:
                 return mCarAudioService;
@@ -333,12 +487,15 @@
                 return mInstrumentClusterService.getManagerService();
             case Car.PROJECTION_SERVICE:
                 return mCarProjectionService;
+            case Car.VEHICLE_MAP_SERVICE:
+                assertAnyVmsPermission(mContext);
+                return mVmsBrokerService;
             case Car.VMS_SUBSCRIBER_SERVICE:
                 assertVmsSubscriberPermission(mContext);
-                return mVmsSubscriberService;
+                return mVmsBrokerService;
             case Car.TEST_SERVICE: {
                 assertPermission(mContext, Car.PERMISSION_CAR_TEST_SERVICE);
-                synchronized (this) {
+                synchronized (mLock) {
                     if (mCarTestService == null) {
                         mCarTestService = new CarTestService(mContext, this);
                     }
@@ -355,6 +512,8 @@
                 return mCarDrivingStateService;
             case Car.CAR_UX_RESTRICTION_SERVICE:
                 return mCarUXRestrictionsService;
+            case Car.OCCUPANT_AWARENESS_SERVICE:
+                return mOccupantAwarenessService;
             case Car.CAR_CONFIGURATION_SERVICE:
                 return mCarConfigurationService;
             case Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE:
@@ -362,11 +521,26 @@
                 return mCarTrustedDeviceService.getCarTrustAgentEnrollmentService();
             case Car.CAR_MEDIA_SERVICE:
                 return mCarMediaService;
+            case Car.CAR_OCCUPANT_ZONE_SERVICE:
+                return mCarOccupantZoneService;
             case Car.CAR_BUGREPORT_SERVICE:
                 return mCarBugreportManagerService;
+            case Car.CAR_USER_SERVICE:
+                return mCarUserService;
+            case Car.CAR_WATCHDOG_SERVICE:
+                return mCarWatchdogService;
+            case Car.CAR_INPUT_SERVICE:
+                return mCarInputService;
             default:
-                Log.w(CarLog.TAG_SERVICE, "getCarService for unknown service:" + serviceName);
-                return null;
+                IBinder service = null;
+                if (mCarExperimentalFeatureServiceController != null) {
+                    service = mCarExperimentalFeatureServiceController.getCarService(serviceName);
+                }
+                if (service == null) {
+                    Log.w(CarLog.TAG_SERVICE, "getCarService for unknown service:"
+                            + serviceName);
+                }
+                return service;
         }
     }
 
@@ -381,8 +555,6 @@
                 return mCarInputService;
             case INTERNAL_SYSTEM_ACTIVITY_MONITORING_SERVICE:
                 return mSystemActivityMonitoringService;
-            case INTERNAL_VMS_MANAGER:
-                return mVmsClientManager;
             default:
                 Log.w(CarLog.TAG_SERVICE, "getCarInternalService for unknown service:" +
                         serviceName);
@@ -390,10 +562,6 @@
         }
     }
 
-    CarStatsService getStatsService() {
-        return mCarStatsService;
-    }
-
     public static void assertVehicleHalMockPermission(Context context) {
         assertPermission(context, Car.PERMISSION_MOCK_VEHICLE_HAL);
     }
@@ -429,6 +597,16 @@
         assertPermission(context, Car.PERMISSION_CAR_DRIVING_STATE);
     }
 
+    /**
+     * Verify the calling context has either {@link Car#PERMISSION_VMS_SUBSCRIBER} or
+     * {@link Car#PERMISSION_VMS_PUBLISHER}
+     */
+    public static void assertAnyVmsPermission(Context context) {
+        assertAnyPermission(context,
+                Car.PERMISSION_VMS_SUBSCRIBER,
+                Car.PERMISSION_VMS_PUBLISHER);
+    }
+
     public static void assertVmsPublisherPermission(Context context) {
         assertPermission(context, Car.PERMISSION_VMS_PUBLISHER);
     }
@@ -462,8 +640,8 @@
 
     public static void assertAnyPermission(Context context, String... permissions) {
         for (String permission : permissions) {
-            if (context.checkCallingOrSelfPermission(permission) ==
-                    PackageManager.PERMISSION_GRANTED) {
+            if (context.checkCallingOrSelfPermission(permission)
+                    == PackageManager.PERMISSION_GRANTED) {
                 return;
             }
         }
@@ -482,34 +660,114 @@
 
         if (args == null || args.length == 0 || (args.length > 0 && "-a".equals(args[0]))) {
             writer.println("*Dump car service*");
-            writer.println("*FutureConfig, DEFAULT:" + FeatureConfiguration.DEFAULT);
-            writer.println("*Dump all services*");
-
             dumpAllServices(writer);
-
-            writer.println("*Dump Vehicle HAL*");
-            writer.println("Vehicle HAL Interface: " + mVehicleInterfaceName);
-            try {
-                // TODO dump all feature flags by creating a dumpable interface
-                mHal.dump(writer);
-            } catch (Exception e) {
-                writer.println("Failed dumping: " + mHal.getClass().getName());
-                e.printStackTrace(writer);
+            dumpAllHals(writer);
+        } else if ("--list".equals(args[0])) {
+            dumpListOfServices(writer);
+            return;
+        } else if ("--services".equals(args[0])) {
+            if (args.length < 2) {
+                writer.println("Must pass services to dump when using --services");
+                return;
             }
+            int length = args.length - 1;
+            String[] services = new String[length];
+            System.arraycopy(args, 1, services, 0, length);
+            dumpIndividualServices(writer, services);
+            return;
         } else if ("--metrics".equals(args[0])) {
             // Strip the --metrics flag when passing dumpsys arguments to CarStatsService
             // allowing for nested flag selection
             mCarStatsService.dump(fd, writer, Arrays.copyOfRange(args, 1, args.length));
         } else if ("--vms-hal".equals(args[0])) {
             mHal.getVmsHal().dumpMetrics(fd);
-        } else if (Build.IS_USERDEBUG || Build.IS_ENG) {
-            execShellCmd(args, writer);
+        } else if ("--hal".equals(args[0])) {
+            if (args.length == 1) {
+                dumpAllHals(writer);
+                return;
+            }
+            int length = args.length - 1;
+            String[] halNames = new String[length];
+            System.arraycopy(args, 1, halNames, 0, length);
+            mHal.dumpSpecificHals(writer, halNames);
+
+        } else if ("--list-hals".equals(args[0])) {
+            mHal.dumpListHals(writer);
+            return;
+        } else if ("--user-metrics".equals(args[0])) {
+            mCarUserService.dumpUserMetrics(writer);
+        } else if ("--first-user-metrics".equals(args[0])) {
+            mCarUserService.dumpFirstUserUnlockDuration(writer);
+        } else if ("--help".equals(args[0])) {
+            showDumpHelp(writer);
         } else {
-            writer.println("Commands not supported in " + Build.TYPE);
+            execShellCmd(args, writer);
+        }
+    }
+
+    private void dumpAllHals(PrintWriter writer) {
+        writer.println("*Dump Vehicle HAL*");
+        writer.println("Vehicle HAL Interface: " + mVehicleInterfaceName);
+        try {
+            // TODO dump all feature flags by creating a dumpable interface
+            mHal.dump(writer);
+        } catch (Exception e) {
+            writer.println("Failed dumping: " + mHal.getClass().getName());
+            e.printStackTrace(writer);
+        }
+    }
+
+    private void showDumpHelp(PrintWriter writer) {
+        writer.println("Car service dump usage:");
+        writer.println("[NO ARG]");
+        writer.println("\t  dumps everything (all services and HALs)");
+        writer.println("--help");
+        writer.println("\t  shows this help");
+        writer.println("--list");
+        writer.println("\t  lists the name of all services");
+        writer.println("--list-hals");
+        writer.println("\t  lists the name of all HALs");
+        writer.println("--services <SVC1> [SVC2] [SVCN]");
+        writer.println("\t  dumps just the specific services, where SVC is just the service class");
+        writer.println("\t  name (like CarUserService)");
+        writer.println("--vms-hal");
+        writer.println("\t  dumps the VMS HAL metrics");
+        writer.println("--hal [HAL1] [HAL2] [HALN]");
+        writer.println("\t  dumps just the specified HALs (or all of them if none specified),");
+        writer.println("\t  where HAL is just the class name (like UserHalService)");
+        writer.println("--user-metrics");
+        writer.println("\t  dumps user switching and stopping metrics ");
+        writer.println("--first-user-metrics");
+        writer.println("\t  dumps how long it took to unlock first user since Android started\n");
+        writer.println("\t  (or -1 if not unlocked)");
+        writer.println("-h");
+        writer.println("\t  shows commands usage (NOTE: commands are not available on USER builds");
+        writer.println("[ANYTHING ELSE]");
+        writer.println("\t  runs the given command (use --h to see the available commands)");
+    }
+
+    @Override
+    public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+            String[] args, ShellCallback callback, ResultReceiver resultReceiver)
+                    throws RemoteException {
+        newCarShellCommand().exec(this, in, out, err, args, callback, resultReceiver);
+    }
+
+    private CarShellCommand newCarShellCommand() {
+        return new CarShellCommand(mContext, mHal, mCarAudioService, mCarPackageManagerService,
+                mCarProjectionService, mCarPowerManagementService, mCarTrustedDeviceService,
+                mFixedActivityService, mFeatureController, mCarInputService, mCarNightService,
+                mSystemInterface, mGarageModeService, mCarUserService, mCarOccupantZoneService);
+    }
+
+    private void dumpListOfServices(PrintWriter writer) {
+        for (CarServiceBase service : mAllServices) {
+            writer.println(service.getClass().getName());
         }
     }
 
     private void dumpAllServices(PrintWriter writer) {
+        writer.println("*Dump all services*");
         for (CarServiceBase service : mAllServices) {
             dumpService(service, writer);
         }
@@ -518,6 +776,26 @@
         }
     }
 
+    private void dumpIndividualServices(PrintWriter writer, String... serviceNames) {
+        for (String serviceName : serviceNames) {
+            writer.println("** Dumping " + serviceName + "\n");
+            CarServiceBase service = getCarServiceBySubstring(serviceName);
+            if (service == null) {
+                writer.println("No such service!");
+            } else {
+                dumpService(service, writer);
+            }
+            writer.println();
+        }
+    }
+
+    @Nullable
+    private CarServiceBase getCarServiceBySubstring(String className) {
+        return Arrays.asList(mAllServices).stream()
+                .filter(s -> s.getClass().getSimpleName().equals(className))
+                .findFirst().orElse(null);
+    }
+
     private void dumpService(CarServiceBase service, PrintWriter writer) {
         try {
             service.dump(writer);
@@ -528,7 +806,7 @@
     }
 
     void execShellCmd(String[] args, PrintWriter writer) {
-        new CarShellCommand().exec(args, writer);
+        newCarShellCommand().exec(args, writer);
     }
 
     @MainThread
@@ -541,419 +819,4 @@
     private void traceEnd() {
         mBootTiming.traceEnd();
     }
-
-    private class CarShellCommand {
-        private static final String COMMAND_HELP = "-h";
-        private static final String COMMAND_DAY_NIGHT_MODE = "day-night-mode";
-        private static final String COMMAND_INJECT_VHAL_EVENT = "inject-vhal-event";
-        private static final String COMMAND_INJECT_ERROR_EVENT = "inject-error-event";
-        private static final String COMMAND_ENABLE_UXR = "enable-uxr";
-        private static final String COMMAND_GARAGE_MODE = "garage-mode";
-        private static final String COMMAND_GET_DO_ACTIVITIES = "get-do-activities";
-        private static final String COMMAND_GET_CARPROPERTYCONFIG = "get-carpropertyconfig";
-        private static final String COMMAND_GET_PROPERTY_VALUE = "get-property-value";
-        private static final String COMMAND_PROJECTION_AP_TETHERING = "projection-tethering";
-        private static final String COMMAND_PROJECTION_UI_MODE = "projection-ui-mode";
-        private static final String COMMAND_RESUME = "resume";
-        private static final String COMMAND_SUSPEND = "suspend";
-        private static final String COMMAND_ENABLE_TRUSTED_DEVICE = "enable-trusted-device";
-        private static final String COMMAND_REMOVE_TRUSTED_DEVICES = "remove-trusted-devices";
-        private static final String COMMAND_START_FIXED_ACTIVITY_MODE = "start-fixed-activity-mode";
-        private static final String COMMAND_STOP_FIXED_ACTIVITY_MODE = "stop-fixed-activity-mode";
-        private static final String COMMAND_INJECT_KEY = "inject-key";
-
-        private static final String PARAM_DAY_MODE = "day";
-        private static final String PARAM_NIGHT_MODE = "night";
-        private static final String PARAM_SENSOR_MODE = "sensor";
-        private static final String PARAM_VEHICLE_PROPERTY_AREA_GLOBAL = "0";
-        private static final String PARAM_ON_MODE = "on";
-        private static final String PARAM_OFF_MODE = "off";
-        private static final String PARAM_QUERY_MODE = "query";
-        private static final String PARAM_REBOOT = "reboot";
-
-
-        private void dumpHelp(PrintWriter pw) {
-            pw.println("Car service commands:");
-            pw.println("\t-h");
-            pw.println("\t  Print this help text.");
-            pw.println("\tday-night-mode [day|night|sensor]");
-            pw.println("\t  Force into day/night mode or restore to auto.");
-            pw.println("\tinject-vhal-event property [zone] data(can be comma separated list)");
-            pw.println("\t  Inject a vehicle property for testing.");
-            pw.println("\tinject-error-event property zone errorCode");
-            pw.println("\t  Inject an error event from VHAL for testing.");
-            pw.println("\tenable-uxr true|false");
-            pw.println("\t  Enable/Disable UX restrictions and App blocking.");
-            pw.println("\tgarage-mode [on|off|query|reboot]");
-            pw.println("\t  Force into or out of garage mode, or check status.");
-            pw.println("\t  With 'reboot', enter garage mode, then reboot when it completes.");
-            pw.println("\tget-do-activities pkgname");
-            pw.println("\t  Get Distraction Optimized activities in given package.");
-            pw.println("\tget-carpropertyconfig [propertyId]");
-            pw.println("\t  Get a CarPropertyConfig by Id in Hex or list all CarPropertyConfigs");
-            pw.println("\tget-property-value [propertyId] [areaId]");
-            pw.println("\t  Get a vehicle property value by property id in Hex and areaId");
-            pw.println("\t  or list all property values for all areaId");
-            pw.println("\tsuspend");
-            pw.println("\t  Suspend the system to Deep Sleep.");
-            pw.println("\tresume");
-            pw.println("\t  Wake the system up after a 'suspend.'");
-            pw.println("\tenable-trusted-device true|false");
-            pw.println("\t  Enable/Disable Trusted device feature.");
-            pw.println("\tremove-trusted-devices");
-            pw.println("\t  Remove all trusted devices for the current foreground user.");
-            pw.println("\tprojection-tethering [true|false]");
-            pw.println("\t  Whether tethering should be used when creating access point for"
-                    + " wireless projection");
-            pw.println("\t--metrics");
-            pw.println("\t  When used with dumpsys, only metrics will be in the dumpsys output.");
-            pw.println("\tstart-fixed-activity displayId packageName activityName");
-            pw.println("\t  Start an Activity the specified display as fixed mode");
-            pw.println("\tstop-fixed-mode displayId");
-            pw.println("\t  Stop fixed Activity mode for the given display. "
-                    + "The Activity will not be restarted upon crash.");
-            pw.println("\tinject-key [-d display] [-t down_delay_ms] key_code");
-            pw.println("\t  inject key down / up event to car service");
-            pw.println("\t  display: 0 for main, 1 for cluster. If not specified, it will be 0.");
-            pw.println("\t  down_delay_ms: delay from down to up key event. If not specified,");
-            pw.println("\t                 it will be 0");
-            pw.println("\t  key_code: int key code defined in android KeyEvent");
-        }
-
-        public void exec(String[] args, PrintWriter writer) {
-            String arg = args[0];
-            switch (arg) {
-                case COMMAND_HELP:
-                    dumpHelp(writer);
-                    break;
-                case COMMAND_DAY_NIGHT_MODE: {
-                    String value = args.length < 2 ? "" : args[1];
-                    forceDayNightMode(value, writer);
-                    break;
-                }
-                case COMMAND_GARAGE_MODE: {
-                    String value = args.length < 2 ? "" : args[1];
-                    forceGarageMode(value, writer);
-                    break;
-                }
-                case COMMAND_INJECT_VHAL_EVENT:
-                    String zone = PARAM_VEHICLE_PROPERTY_AREA_GLOBAL;
-                    String data;
-                    if (args.length != 3 && args.length != 4) {
-                        writer.println("Incorrect number of arguments.");
-                        dumpHelp(writer);
-                        break;
-                    } else if (args.length == 4) {
-                        // Zoned
-                        zone = args[2];
-                        data = args[3];
-                    } else {
-                        // Global
-                        data = args[2];
-                    }
-                    injectVhalEvent(args[1], zone, data, false, writer);
-                    break;
-                case COMMAND_INJECT_ERROR_EVENT:
-                    if (args.length != 4) {
-                        writer.println("Incorrect number of arguments");
-                        dumpHelp(writer);
-                        break;
-                    }
-                    String errorAreaId = args[2];
-                    String errorCode = args[3];
-                    injectVhalEvent(args[1], errorAreaId, errorCode, true, writer);
-                    break;
-                case COMMAND_ENABLE_UXR:
-                    if (args.length != 2) {
-                        writer.println("Incorrect number of arguments");
-                        dumpHelp(writer);
-                        break;
-                    }
-                    boolean enableBlocking = Boolean.valueOf(args[1]);
-                    if (mCarPackageManagerService != null) {
-                        mCarPackageManagerService.setEnableActivityBlocking(enableBlocking);
-                    }
-                    break;
-                case COMMAND_GET_DO_ACTIVITIES:
-                    if (args.length != 2) {
-                        writer.println("Incorrect number of arguments");
-                        dumpHelp(writer);
-                        break;
-                    }
-                    String pkgName = args[1].toLowerCase();
-                    if (mCarPackageManagerService != null) {
-                        String[] doActivities =
-                                mCarPackageManagerService.getDistractionOptimizedActivities(
-                                        pkgName);
-                        if (doActivities != null) {
-                            writer.println("DO Activities for " + pkgName);
-                            for (String a : doActivities) {
-                                writer.println(a);
-                            }
-                        } else {
-                            writer.println("No DO Activities for " + pkgName);
-                        }
-                    }
-                    break;
-                case COMMAND_GET_CARPROPERTYCONFIG:
-                    String propertyId = args.length < 2 ? "" : args[1];
-                    mHal.dumpPropertyConfigs(writer, propertyId);
-                    break;
-                case COMMAND_GET_PROPERTY_VALUE:
-                    String propId = args.length < 2 ? "" : args[1];
-                    String areaId = args.length < 3 ? "" : args[2];
-                    mHal.dumpPropertyValueByCommend(writer, propId, areaId);
-                    break;
-                case COMMAND_PROJECTION_UI_MODE:
-                    if (args.length != 2) {
-                        writer.println("Incorrect number of arguments");
-                        dumpHelp(writer);
-                        break;
-                    }
-                    mCarProjectionService.setUiMode(Integer.valueOf(args[1]));
-                    break;
-                case COMMAND_PROJECTION_AP_TETHERING:
-                    if (args.length != 2) {
-                        writer.println("Incorrect number of arguments");
-                        dumpHelp(writer);
-                        break;
-                    }
-                    mCarProjectionService.setAccessPointTethering(Boolean.valueOf(args[1]));
-                    break;
-                case COMMAND_RESUME:
-                    mCarPowerManagementService.forceSimulatedResume();
-                    writer.println("Resume: Simulating resuming from Deep Sleep");
-                    break;
-                case COMMAND_SUSPEND:
-                    mCarPowerManagementService.forceSuspendAndMaybeReboot(false);
-                    writer.println("Resume: Simulating powering down to Deep Sleep");
-                    break;
-                case COMMAND_ENABLE_TRUSTED_DEVICE:
-                    if (args.length != 2) {
-                        writer.println("Incorrect number of arguments");
-                        dumpHelp(writer);
-                        break;
-                    }
-                    mCarTrustedDeviceService.getCarTrustAgentEnrollmentService()
-                            .setTrustedDeviceEnrollmentEnabled(Boolean.valueOf(args[1]));
-                    mCarTrustedDeviceService.getCarTrustAgentUnlockService()
-                            .setTrustedDeviceUnlockEnabled(Boolean.valueOf(args[1]));
-                    break;
-                case COMMAND_REMOVE_TRUSTED_DEVICES:
-                    mCarTrustedDeviceService.getCarTrustAgentEnrollmentService()
-                            .removeAllTrustedDevices(
-                                    mUserManagerHelper.getCurrentForegroundUserId());
-                    break;
-                case COMMAND_START_FIXED_ACTIVITY_MODE:
-                    handleStartFixedActivity(args, writer);
-                    break;
-                case COMMAND_STOP_FIXED_ACTIVITY_MODE:
-                    handleStopFixedMode(args, writer);
-                    break;
-
-                case COMMAND_INJECT_KEY:
-                    if (args.length < 2) {
-                        writer.println("Incorrect number of arguments");
-                        dumpHelp(writer);
-                        break;
-                    }
-                    handleInjectKey(args, writer);
-                    break;
-                default:
-                    writer.println("Unknown command: \"" + arg + "\"");
-                    dumpHelp(writer);
-            }
-        }
-
-        private void handleStartFixedActivity(String[] args, PrintWriter writer) {
-            if (args.length != 4) {
-                writer.println("Incorrect number of arguments");
-                dumpHelp(writer);
-                return;
-            }
-            int displayId;
-            try {
-                displayId = Integer.parseInt(args[1]);
-            } catch (NumberFormatException e) {
-                writer.println("Wrong display id:" + args[1]);
-                return;
-            }
-            String packageName = args[2];
-            String activityName = args[3];
-            Intent intent = new Intent();
-            intent.setComponent(new ComponentName(packageName, activityName));
-            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-            ActivityOptions options = ActivityOptions.makeBasic();
-            options.setLaunchDisplayId(displayId);
-            if (!mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent, options,
-                    displayId, ActivityManager.getCurrentUser())) {
-                writer.println("Failed to start");
-                return;
-            }
-            writer.println("Succeeded");
-        }
-
-        private void handleStopFixedMode(String[] args, PrintWriter writer) {
-            if (args.length != 2) {
-                writer.println("Incorrect number of arguments");
-                dumpHelp(writer);
-                return;
-            }
-            int displayId;
-            try {
-                displayId = Integer.parseInt(args[1]);
-            } catch (NumberFormatException e) {
-                writer.println("Wrong display id:" + args[1]);
-                return;
-            }
-            mFixedActivityService.stopFixedActivityMode(displayId);
-        }
-
-        private void handleInjectKey(String[] args, PrintWriter writer) {
-            int i = 1; // 0 is command itself
-            int display = InputHalService.DISPLAY_MAIN;
-            int delayMs = 0;
-            int keyCode = KeyEvent.KEYCODE_UNKNOWN;
-            try {
-                while (i < args.length) {
-                    switch (args[i]) {
-                        case "-d":
-                            i++;
-                            display = Integer.parseInt(args[i]);
-                            break;
-                        case "-t":
-                            i++;
-                            delayMs = Integer.parseInt(args[i]);
-                            break;
-                        default:
-                            if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
-                                throw new IllegalArgumentException("key_code already set:"
-                                        + keyCode);
-                            }
-                            keyCode = Integer.parseInt(args[i]);
-                    }
-                    i++;
-                }
-            } catch (Exception e) {
-                writer.println("Invalid args:" + e);
-                dumpHelp(writer);
-                return;
-            }
-            if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
-                writer.println("Missing key code or invalid keycode");
-                dumpHelp(writer);
-                return;
-            }
-            if (display != InputHalService.DISPLAY_MAIN
-                    && display != InputHalService.DISPLAY_INSTRUMENT_CLUSTER) {
-                writer.println("Invalid display:" + display);
-                dumpHelp(writer);
-                return;
-            }
-            if (delayMs < 0) {
-                writer.println("Invalid delay:" + delayMs);
-                dumpHelp(writer);
-                return;
-            }
-            KeyEvent keyDown = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
-            mCarInputService.onKeyEvent(keyDown, display);
-            SystemClock.sleep(delayMs);
-            KeyEvent keyUp = new KeyEvent(KeyEvent.ACTION_UP, keyCode);
-            mCarInputService.onKeyEvent(keyUp, display);
-            writer.println("Succeeded");
-        }
-
-        private void forceDayNightMode(String arg, PrintWriter writer) {
-            int mode;
-            switch (arg) {
-                case PARAM_DAY_MODE:
-                    mode = CarNightService.FORCED_DAY_MODE;
-                    break;
-                case PARAM_NIGHT_MODE:
-                    mode = CarNightService.FORCED_NIGHT_MODE;
-                    break;
-                case PARAM_SENSOR_MODE:
-                    mode = CarNightService.FORCED_SENSOR_MODE;
-                    break;
-                default:
-                    writer.println("Unknown value. Valid argument: " + PARAM_DAY_MODE + "|"
-                            + PARAM_NIGHT_MODE + "|" + PARAM_SENSOR_MODE);
-                    return;
-            }
-            int current = mCarNightService.forceDayNightMode(mode);
-            String currentMode = null;
-            switch (current) {
-                case UiModeManager.MODE_NIGHT_AUTO:
-                    currentMode = PARAM_SENSOR_MODE;
-                    break;
-                case UiModeManager.MODE_NIGHT_YES:
-                    currentMode = PARAM_NIGHT_MODE;
-                    break;
-                case UiModeManager.MODE_NIGHT_NO:
-                    currentMode = PARAM_DAY_MODE;
-                    break;
-            }
-            writer.println("DayNightMode changed to: " + currentMode);
-        }
-
-        private void forceGarageMode(String arg, PrintWriter writer) {
-            switch (arg) {
-                case PARAM_ON_MODE:
-                    mGarageModeService.forceStartGarageMode();
-                    writer.println("Garage mode: " + mGarageModeService.isGarageModeActive());
-                    break;
-                case PARAM_OFF_MODE:
-                    mGarageModeService.stopAndResetGarageMode();
-                    writer.println("Garage mode: " + mGarageModeService.isGarageModeActive());
-                    break;
-                case PARAM_QUERY_MODE:
-                    mGarageModeService.dump(writer);
-                    break;
-                case PARAM_REBOOT:
-                    mCarPowerManagementService.forceSuspendAndMaybeReboot(true);
-                    writer.println("Entering Garage Mode. Will reboot when it completes.");
-                    break;
-                default:
-                    writer.println("Unknown value. Valid argument: " + PARAM_ON_MODE + "|"
-                            + PARAM_OFF_MODE + "|" + PARAM_QUERY_MODE + "|" + PARAM_REBOOT);
-            }
-        }
-
-        /**
-         * Inject a fake  VHAL event
-         *
-         * @param property the Vehicle property Id as defined in the HAL
-         * @param zone     Zone that this event services
-         * @param isErrorEvent indicates the type of event
-         * @param value    Data value of the event
-         * @param writer   PrintWriter
-         */
-        private void injectVhalEvent(String property, String zone, String value,
-                boolean isErrorEvent, PrintWriter writer) {
-            if (zone != null && (zone.equalsIgnoreCase(PARAM_VEHICLE_PROPERTY_AREA_GLOBAL))) {
-                if (!isPropertyAreaTypeGlobal(property)) {
-                    writer.println("Property area type inconsistent with given zone");
-                    return;
-                }
-            }
-            try {
-                if (isErrorEvent) {
-                    mHal.injectOnPropertySetError(property, zone, value);
-                } else {
-                    mHal.injectVhalEvent(property, zone, value);
-                }
-            } catch (NumberFormatException e) {
-                writer.println("Invalid property Id zone Id or value" + e);
-                dumpHelp(writer);
-            }
-        }
-
-        // Check if the given property is global
-        private boolean isPropertyAreaTypeGlobal(String property) {
-            if (property == null) {
-                return false;
-            }
-            return (Integer.decode(property) & VehicleArea.MASK) == VehicleArea.GLOBAL;
-        }
-    }
 }
diff --git a/service/src/com/android/car/InputCaptureClientController.java b/service/src/com/android/car/InputCaptureClientController.java
new file mode 100644
index 0000000..8d140bd
--- /dev/null
+++ b/service/src/com/android/car/InputCaptureClientController.java
@@ -0,0 +1,691 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car;
+
+import static java.util.Map.entry;
+
+import android.annotation.NonNull;
+import android.car.input.CarInputManager;
+import android.car.input.ICarInputCallback;
+import android.car.input.RotaryEvent;
+import android.content.Context;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.KeyEvent;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Preconditions;
+
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Manages input capture request from clients
+ */
+public class InputCaptureClientController {
+    private static final boolean DBG_STACK = false;
+    private static final boolean DBG_DISPATCH = false;
+    private static final boolean DBG_CALLS = false;
+
+    private static final String TAG = CarLog.TAG_INPUT;
+    /**
+     *  This table decides which input key goes into which input type. Not mapped here means it is
+     *  not supported for capturing. Rotary events are treated separately and this is only for
+     *  key events.
+     */
+    private static final Map<Integer, Integer> KEY_EVENT_TO_INPUT_TYPE = Map.ofEntries(
+            entry(KeyEvent.KEYCODE_DPAD_CENTER, CarInputManager.INPUT_TYPE_DPAD_KEYS),
+            entry(KeyEvent.KEYCODE_DPAD_DOWN, CarInputManager.INPUT_TYPE_DPAD_KEYS),
+            entry(KeyEvent.KEYCODE_DPAD_UP, CarInputManager.INPUT_TYPE_DPAD_KEYS),
+            entry(KeyEvent.KEYCODE_DPAD_LEFT, CarInputManager.INPUT_TYPE_DPAD_KEYS),
+            entry(KeyEvent.KEYCODE_DPAD_RIGHT, CarInputManager.INPUT_TYPE_DPAD_KEYS),
+            entry(KeyEvent.KEYCODE_DPAD_DOWN_LEFT, CarInputManager.INPUT_TYPE_DPAD_KEYS),
+            entry(KeyEvent.KEYCODE_DPAD_DOWN_RIGHT, CarInputManager.INPUT_TYPE_DPAD_KEYS),
+            entry(KeyEvent.KEYCODE_DPAD_UP_LEFT, CarInputManager.INPUT_TYPE_DPAD_KEYS),
+            entry(KeyEvent.KEYCODE_DPAD_UP_RIGHT, CarInputManager.INPUT_TYPE_DPAD_KEYS),
+            entry(KeyEvent.KEYCODE_NAVIGATE_IN, CarInputManager.INPUT_TYPE_NAVIGATE_KEYS),
+            entry(KeyEvent.KEYCODE_NAVIGATE_OUT, CarInputManager.INPUT_TYPE_NAVIGATE_KEYS),
+            entry(KeyEvent.KEYCODE_NAVIGATE_NEXT, CarInputManager.INPUT_TYPE_NAVIGATE_KEYS),
+            entry(KeyEvent.KEYCODE_NAVIGATE_PREVIOUS, CarInputManager.INPUT_TYPE_NAVIGATE_KEYS),
+            entry(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN,
+                    CarInputManager.INPUT_TYPE_SYSTEM_NAVIGATE_KEYS),
+            entry(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP,
+                    CarInputManager.INPUT_TYPE_SYSTEM_NAVIGATE_KEYS),
+            entry(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT,
+                    CarInputManager.INPUT_TYPE_SYSTEM_NAVIGATE_KEYS),
+            entry(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT,
+                    CarInputManager.INPUT_TYPE_SYSTEM_NAVIGATE_KEYS)
+    );
+
+    private static final Set<Integer> VALID_INPUT_TYPES = Set.of(
+            CarInputManager.INPUT_TYPE_ALL_INPUTS,
+            CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION,
+            CarInputManager.INPUT_TYPE_DPAD_KEYS,
+            CarInputManager.INPUT_TYPE_NAVIGATE_KEYS,
+            CarInputManager.INPUT_TYPE_SYSTEM_NAVIGATE_KEYS
+    );
+
+    private static final Set<Integer> VALID_ROTARY_TYPES = Set.of(
+            CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION
+    );
+
+    // TODO(b/150818155) Need to migrate cluster code to use this to enable it.
+    private static final List<Integer> SUPPORTED_DISPLAY_TYPES = List.of(
+            CarInputManager.TARGET_DISPLAY_TYPE_MAIN
+    );
+
+    private static final int[] EMPTY_INPUT_TYPES = new int[0];
+
+    private final class ClientInfoForDisplay implements IBinder.DeathRecipient {
+        private final int mUid;
+        private final int mPid;
+        private final ICarInputCallback mCallback;
+        private final int mTargetDisplayType;
+        private final int[] mInputTypes;
+        private final int mFlags;
+        private final ArrayList<Integer> mGrantedTypes;
+
+        private ClientInfoForDisplay(int uid, int pid, @NonNull ICarInputCallback callback,
+                int targetDisplayType, int[] inputTypes, int flags) {
+            mUid = uid;
+            mPid = pid;
+            mCallback = callback;
+            mTargetDisplayType = targetDisplayType;
+            mInputTypes = inputTypes;
+            mFlags = flags;
+            mGrantedTypes = new ArrayList<>(inputTypes.length);
+        }
+
+        private void linkToDeath() throws RemoteException {
+            mCallback.asBinder().linkToDeath(this, 0);
+        }
+
+        private void unlinkToDeath() {
+            mCallback.asBinder().unlinkToDeath(this, 0);
+        }
+
+        @Override
+        public void binderDied() {
+            onClientDeath(this);
+        }
+
+        @Override
+        public String toString() {
+            return new StringBuilder(128)
+                    .append("Client{")
+                    .append("uid:")
+                    .append(mUid)
+                    .append(",pid:")
+                    .append(mPid)
+                    .append(",callback:")
+                    .append(mCallback)
+                    .append(",inputTypes:")
+                    .append(mInputTypes)
+                    .append(",flags:")
+                    .append(Integer.toHexString(mFlags))
+                    .append(",grantedTypes:")
+                    .append(mGrantedTypes)
+                    .append("}")
+                    .toString();
+        }
+    }
+
+    private static final class ClientsToDispatch {
+        // The same client can be added multiple times. Keeping only the last addition is ok.
+        private final ArrayMap<ICarInputCallback, int[]> mClientsToDispatch =
+                new ArrayMap<>();
+        private final int mDisplayType;
+
+        private ClientsToDispatch(int displayType) {
+            mDisplayType = displayType;
+        }
+
+        private void add(ClientInfoForDisplay client) {
+            int[] inputTypesToDispatch;
+            if (client.mGrantedTypes.isEmpty()) {
+                inputTypesToDispatch = EMPTY_INPUT_TYPES;
+            } else {
+                inputTypesToDispatch = ArrayUtils.convertToIntArray(client.mGrantedTypes);
+            }
+            mClientsToDispatch.put(client.mCallback, inputTypesToDispatch);
+        }
+    }
+
+    private final Context mContext;
+
+    private final Object mLock = new Object();
+
+    /**
+     * key: display type, for quick discovery of client
+     * LinkedList is for implementing stack. First entry is the top.
+     */
+    @GuardedBy("mLock")
+    private final SparseArray<LinkedList<ClientInfoForDisplay>> mFullDisplayEventCapturers =
+            new SparseArray<>(2);
+
+    /**
+     * key: display type -> inputType, for quick discovery of client
+     * LinkedList is for implementing stack. First entry is the top.
+     */
+    @GuardedBy("mLock")
+    private final SparseArray<SparseArray<LinkedList<ClientInfoForDisplay>>>
+            mPerInputTypeCapturers = new SparseArray<>(2);
+
+    @GuardedBy("mLock")
+    /** key: display type -> client binder */
+    private final SparseArray<HashMap<IBinder, ClientInfoForDisplay>> mAllClients =
+            new SparseArray<>(1);
+
+    @GuardedBy("mLock")
+    /** Keeps events to dispatch together. FIFO, last one added to last */
+    private final LinkedList<ClientsToDispatch> mClientDispatchQueue =
+            new LinkedList<>();
+
+    /** Accessed from dispatch thread only */
+    private final ArrayList<KeyEvent> mKeyEventDispatchScratchList = new ArrayList<>(1);
+
+    /** Accessed from dispatch thread only */
+    private final ArrayList<RotaryEvent> mRotaryEventDispatchScratchList = new ArrayList<>(1);
+
+    @GuardedBy("mLock")
+    private int mNumKeyEventsDispatched;
+    @GuardedBy("mLock")
+    private int mNumRotaryEventsDispatched;
+
+    public InputCaptureClientController(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * See
+     * {@link CarInputManager#requestInputEventCapture(CarInputManager.CarInputCaptureCallback,
+     * int, int[], int)}.
+     */
+    public int requestInputEventCapture(ICarInputCallback callback, int targetDisplayType,
+            int[] inputTypes, int requestFlags) {
+        ICarImpl.assertPermission(mContext, android.Manifest.permission.MONITOR_INPUT);
+
+        Preconditions.checkArgument(SUPPORTED_DISPLAY_TYPES.contains(targetDisplayType),
+                "Display not supported yet:" + targetDisplayType);
+
+        boolean isRequestingAllEvents =
+                (requestFlags & CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY) != 0;
+        if (isRequestingAllEvents) {
+            ICarImpl.assertCallingFromSystemProcessOrSelf();
+            if (inputTypes.length != 1 || inputTypes[0] != CarInputManager.INPUT_TYPE_ALL_INPUTS) {
+                throw new IllegalArgumentException("Input type should be INPUT_TYPE_ALL_INPUTS"
+                        + " for CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY");
+            }
+        }
+        if (targetDisplayType != CarInputManager.TARGET_DISPLAY_TYPE_CLUSTER
+                && targetDisplayType != CarInputManager.TARGET_DISPLAY_TYPE_MAIN) {
+            throw new IllegalArgumentException("Unrecognized display type:" + targetDisplayType);
+        }
+        if (inputTypes == null) {
+            throw new IllegalArgumentException("inputTypes cannot be null");
+        }
+        assertInputTypeValid(inputTypes);
+        Arrays.sort(inputTypes);
+        IBinder clientBinder = callback.asBinder();
+        boolean allowsDelayedGrant =
+                (requestFlags & CarInputManager.CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT) != 0;
+        int ret = CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED;
+        if (DBG_CALLS) {
+            Log.i(TAG,
+                    "requestInputEventCapture callback:" + callback
+                            + ", display:" + targetDisplayType
+                            + ", inputTypes:" + Arrays.toString(inputTypes)
+                            + ", flags:" + requestFlags);
+        }
+        ClientsToDispatch clientsToDispatch = new ClientsToDispatch(targetDisplayType);
+        synchronized (mLock) {
+            HashMap<IBinder, ClientInfoForDisplay> allClientsForDisplay = mAllClients.get(
+                    targetDisplayType);
+            if (allClientsForDisplay == null) {
+                allClientsForDisplay = new HashMap<IBinder, ClientInfoForDisplay>();
+                mAllClients.put(targetDisplayType, allClientsForDisplay);
+            }
+            ClientInfoForDisplay oldClientInfo = allClientsForDisplay.remove(clientBinder);
+
+            LinkedList<ClientInfoForDisplay> fullCapturersStack = mFullDisplayEventCapturers.get(
+                    targetDisplayType);
+            if (fullCapturersStack == null) {
+                fullCapturersStack = new LinkedList<ClientInfoForDisplay>();
+                mFullDisplayEventCapturers.put(targetDisplayType, fullCapturersStack);
+            }
+
+            if (!isRequestingAllEvents && fullCapturersStack.size() > 0
+                    && fullCapturersStack.getFirst() != oldClientInfo && !allowsDelayedGrant) {
+                // full capturing active. return failed if not delayed granting.
+                return CarInputManager.INPUT_CAPTURE_RESPONSE_FAILED;
+            }
+            // Now we need to register client anyway, so do death monitoring from here.
+            ClientInfoForDisplay newClient = new ClientInfoForDisplay(Binder.getCallingUid(),
+                    Binder.getCallingPid(), callback, targetDisplayType,
+                    inputTypes, requestFlags);
+            try {
+                newClient.linkToDeath();
+            } catch (RemoteException e) {
+                // client died
+                Log.i(TAG, "requestInputEventCapture, cannot linkToDeath to client, pid:"
+                        + Binder.getCallingUid());
+                return CarInputManager.INPUT_CAPTURE_RESPONSE_FAILED;
+            }
+
+            SparseArray<LinkedList<ClientInfoForDisplay>> perInputStacks =
+                    mPerInputTypeCapturers.get(targetDisplayType);
+            if (perInputStacks == null) {
+                perInputStacks = new SparseArray<LinkedList<ClientInfoForDisplay>>();
+                mPerInputTypeCapturers.put(targetDisplayType, perInputStacks);
+            }
+
+            if (isRequestingAllEvents) {
+                if (!fullCapturersStack.isEmpty()) {
+                    ClientInfoForDisplay oldCapturer = fullCapturersStack.getFirst();
+                    if (oldCapturer != oldClientInfo) {
+                        oldCapturer.mGrantedTypes.clear();
+                        clientsToDispatch.add(oldCapturer);
+                    }
+                    fullCapturersStack.remove(oldClientInfo);
+                } else { // All per input type top stack client should be notified.
+                    for (int i = 0; i < perInputStacks.size(); i++) {
+                        LinkedList<ClientInfoForDisplay> perTypeStack = perInputStacks.valueAt(i);
+                        if (!perTypeStack.isEmpty()) {
+                            ClientInfoForDisplay topClient = perTypeStack.getFirst();
+                            if (topClient != oldClientInfo) {
+                                topClient.mGrantedTypes.clear();
+                                clientsToDispatch.add(topClient);
+                            }
+                            // Even if the client was on top, the one in back does not need
+                            // update.
+                            perTypeStack.remove(oldClientInfo);
+                        }
+                    }
+                }
+                fullCapturersStack.addFirst(newClient);
+
+            } else {
+                boolean hadFullCapture = false;
+                boolean fullCaptureActive = false;
+                if (fullCapturersStack.size() > 0) {
+                    if (fullCapturersStack.getFirst() == oldClientInfo) {
+                        fullCapturersStack.remove(oldClientInfo);
+                        // Now we need to check if there is other client in fullCapturersStack
+                        if (fullCapturersStack.size() > 0) {
+                            fullCaptureActive = true;
+                            ret = CarInputManager.INPUT_CAPTURE_RESPONSE_DELAYED;
+                            ClientInfoForDisplay topClient = fullCapturersStack.getFirst();
+                            topClient.mGrantedTypes.clear();
+                            topClient.mGrantedTypes.add(CarInputManager.INPUT_TYPE_ALL_INPUTS);
+                            clientsToDispatch.add(topClient);
+                        } else {
+                            hadFullCapture = true;
+                        }
+                    } else {
+                        // other client doing full capturing and it should have DELAYED_GRANT flag.
+                        fullCaptureActive = true;
+                        ret = CarInputManager.INPUT_CAPTURE_RESPONSE_DELAYED;
+                    }
+                }
+                for (int i = 0; i < perInputStacks.size(); i++) {
+                    LinkedList<ClientInfoForDisplay> perInputStack = perInputStacks.valueAt(i);
+                    perInputStack.remove(oldClientInfo);
+                }
+                // Now go through per input stack
+                for (int inputType : inputTypes) {
+                    LinkedList<ClientInfoForDisplay> perInputStack = perInputStacks.get(
+                            inputType);
+                    if (perInputStack == null) {
+                        perInputStack = new LinkedList<ClientInfoForDisplay>();
+                        perInputStacks.put(inputType, perInputStack);
+                    }
+                    if (perInputStack.size() > 0) {
+                        ClientInfoForDisplay oldTopClient = perInputStack.getFirst();
+                        if (oldTopClient.mGrantedTypes.remove(Integer.valueOf(inputType))) {
+                            clientsToDispatch.add(oldTopClient);
+                        }
+                    }
+                    if (!fullCaptureActive) {
+                        newClient.mGrantedTypes.add(inputType);
+                    }
+                    perInputStack.addFirst(newClient);
+                }
+                if (!fullCaptureActive && hadFullCapture) {
+                    for (int i = 0; i < perInputStacks.size(); i++) {
+                        int inputType = perInputStacks.keyAt(i);
+                        LinkedList<ClientInfoForDisplay> perInputStack = perInputStacks.valueAt(
+                                i);
+                        if (perInputStack.size() > 0) {
+                            ClientInfoForDisplay topStackClient = perInputStack.getFirst();
+                            if (topStackClient == newClient) {
+                                continue;
+                            }
+                            if (!topStackClient.mGrantedTypes.contains(inputType)) {
+                                topStackClient.mGrantedTypes.add(inputType);
+                                clientsToDispatch.add(topStackClient);
+                            }
+                        }
+                    }
+                }
+            }
+            allClientsForDisplay.put(clientBinder, newClient);
+            dispatchClientCallbackLocked(clientsToDispatch);
+        }
+        return ret;
+    }
+
+    /**
+     * See {@link CarInputManager#releaseInputEventCapture(int)}.
+     */
+    public void releaseInputEventCapture(ICarInputCallback callback, int targetDisplayType) {
+        Objects.requireNonNull(callback);
+        Preconditions.checkArgument(SUPPORTED_DISPLAY_TYPES.contains(targetDisplayType),
+                "Display not supported yet:" + targetDisplayType);
+
+        if (DBG_CALLS) {
+            Log.i(TAG, "releaseInputEventCapture callback:" + callback
+                            + ", display:" + targetDisplayType);
+        }
+        ClientsToDispatch clientsToDispatch = new ClientsToDispatch(targetDisplayType);
+        synchronized (mLock) {
+            HashMap<IBinder, ClientInfoForDisplay> allClientsForDisplay = mAllClients.get(
+                    targetDisplayType);
+            ClientInfoForDisplay clientInfo = allClientsForDisplay.remove(callback.asBinder());
+            if (clientInfo == null) {
+                Log.w(TAG, "Cannot find client for releaseInputEventCapture:" + callback);
+                return;
+            }
+            clientInfo.unlinkToDeath();
+            LinkedList<ClientInfoForDisplay> fullCapturersStack = mFullDisplayEventCapturers.get(
+                    targetDisplayType);
+            boolean fullCaptureActive = false;
+            if (fullCapturersStack.size() > 0) {
+                if (fullCapturersStack.getFirst() == clientInfo) {
+                    fullCapturersStack.remove(clientInfo);
+                    if (fullCapturersStack.size() > 0) {
+                        ClientInfoForDisplay newStopStackClient = fullCapturersStack.getFirst();
+                        newStopStackClient.mGrantedTypes.clear();
+                        newStopStackClient.mGrantedTypes.add(CarInputManager.INPUT_TYPE_ALL_INPUTS);
+                        clientsToDispatch.add(newStopStackClient);
+                        fullCaptureActive = true;
+                    }
+                } else { // no notification as other client is in top of the stack
+                    fullCaptureActive = true;
+                }
+                fullCapturersStack.remove(clientInfo);
+            }
+            SparseArray<LinkedList<ClientInfoForDisplay>> perInputStacks =
+                    mPerInputTypeCapturers.get(targetDisplayType);
+            if (DBG_STACK) {
+                Log.i(TAG, "releaseInputEventCapture, fullCaptureActive:"
+                        + fullCaptureActive + ", perInputStacks:" + perInputStacks);
+            }
+            if (perInputStacks != null) {
+                for (int i = 0; i < perInputStacks.size(); i++) {
+                    int inputType = perInputStacks.keyAt(i);
+                    LinkedList<ClientInfoForDisplay> perInputStack = perInputStacks.valueAt(i);
+                    if (perInputStack.size() > 0) {
+                        if (perInputStack.getFirst() == clientInfo) {
+                            perInputStack.removeFirst();
+                            if (perInputStack.size() > 0) {
+                                ClientInfoForDisplay newTopClient = perInputStack.getFirst();
+                                if (!fullCaptureActive) {
+                                    newTopClient.mGrantedTypes.add(inputType);
+                                    clientsToDispatch.add(newTopClient);
+                                }
+                            }
+                        } else { // something else on top.
+                            if (!fullCaptureActive) {
+                                ClientInfoForDisplay topClient = perInputStack.getFirst();
+                                if (!topClient.mGrantedTypes.contains(inputType)) {
+                                    topClient.mGrantedTypes.add(inputType);
+                                    clientsToDispatch.add(topClient);
+                                }
+                            }
+                            perInputStack.remove(clientInfo);
+                        }
+                    }
+                }
+            }
+            dispatchClientCallbackLocked(clientsToDispatch);
+        }
+    }
+
+    /**
+     * Dispatches the given {@code KeyEvent} to a capturing client if there is one.
+     *
+     * @param displayType Should be a display type defined in {@code CarInputManager} such as
+     *                    {@link CarInputManager#TARGET_DISPLAY_TYPE_MAIN}.
+     * @param event
+     * @return true if the event was consumed.
+     */
+    public boolean onKeyEvent(int displayType, KeyEvent event) {
+        if (!SUPPORTED_DISPLAY_TYPES.contains(displayType)) {
+            return false;
+        }
+        Integer inputType = KEY_EVENT_TO_INPUT_TYPE.get(event.getKeyCode());
+        if (inputType == null) { // not supported key
+            return false;
+        }
+        ICarInputCallback callback;
+        synchronized (mLock) {
+            callback = getClientForInputTypeLocked(displayType, inputType);
+            if (callback == null) {
+                return false;
+            }
+            mNumKeyEventsDispatched++;
+        }
+
+        dispatchKeyEvent(displayType, event, callback);
+        return true;
+    }
+
+    /**
+     * Dispatches the given {@code RotaryEvent} to a capturing client if there is one.
+     *
+     * @param displayType Should be a display type defined in {@code CarInputManager} such as
+     *                    {@link CarInputManager#TARGET_DISPLAY_TYPE_MAIN}.
+     * @param event
+     * @return true if the event was consumed.
+     */
+    public boolean onRotaryEvent(int displayType, RotaryEvent event) {
+        if (!SUPPORTED_DISPLAY_TYPES.contains(displayType)) {
+            Log.w(TAG, "onRotaryEvent for not supported display:" + displayType);
+            return false;
+        }
+        int inputType = event.getInputType();
+        if (!VALID_ROTARY_TYPES.contains(inputType)) {
+            Log.w(TAG, "onRotaryEvent for not supported input type:" + inputType);
+            return false;
+        }
+
+        ICarInputCallback callback;
+        synchronized (mLock) {
+            callback = getClientForInputTypeLocked(displayType, inputType);
+            if (callback == null) {
+                if (DBG_DISPATCH) {
+                    Log.i(TAG, "onRotaryEvent no client for input type:" + inputType);
+                }
+                return false;
+            }
+            mNumRotaryEventsDispatched++;
+        }
+
+        dispatchRotaryEvent(displayType, event, callback);
+        return true;
+    }
+
+    ICarInputCallback getClientForInputTypeLocked(int targetDisplayType, int inputType) {
+        LinkedList<ClientInfoForDisplay> fullCapturersStack = mFullDisplayEventCapturers.get(
+                targetDisplayType);
+        if (fullCapturersStack != null && fullCapturersStack.size() > 0) {
+            return fullCapturersStack.getFirst().mCallback;
+        }
+
+        SparseArray<LinkedList<ClientInfoForDisplay>> perInputStacks =
+                mPerInputTypeCapturers.get(targetDisplayType);
+        if (perInputStacks == null) {
+            return null;
+        }
+
+        LinkedList<ClientInfoForDisplay> perInputStack = perInputStacks.get(inputType);
+        if (perInputStack != null && perInputStack.size() > 0) {
+            return perInputStack.getFirst().mCallback;
+        }
+
+        return null;
+    }
+
+    private void onClientDeath(ClientInfoForDisplay client) {
+        releaseInputEventCapture(client.mCallback, client.mTargetDisplayType);
+    }
+
+    /** dump for debugging */
+    public void dump(PrintWriter writer) {
+        writer.println("**InputCaptureClientController**");
+        synchronized (mLock) {
+            for (int display: SUPPORTED_DISPLAY_TYPES) {
+                writer.println("***Display:" + display);
+
+                HashMap<IBinder, ClientInfoForDisplay> allClientsForDisplay = mAllClients.get(
+                        display);
+                if (allClientsForDisplay != null) {
+                    writer.println("****All clients:");
+                    for (ClientInfoForDisplay client: allClientsForDisplay.values()) {
+                        writer.println(client);
+                    }
+                }
+
+                LinkedList<ClientInfoForDisplay> fullCapturersStack =
+                        mFullDisplayEventCapturers.get(display);
+                if (fullCapturersStack != null) {
+                    writer.println("****Full capture stack");
+                    for (ClientInfoForDisplay client: fullCapturersStack) {
+                        writer.println(client);
+                    }
+                }
+                SparseArray<LinkedList<ClientInfoForDisplay>> perInputStacks =
+                        mPerInputTypeCapturers.get(display);
+                if (perInputStacks != null) {
+                    for (int i = 0; i < perInputStacks.size(); i++) {
+                        int inputType = perInputStacks.keyAt(i);
+                        LinkedList<ClientInfoForDisplay> perInputStack = perInputStacks.valueAt(i);
+                        if (perInputStack.size() > 0) {
+                            writer.println("**** Per Input stack, input type:" + inputType);
+                            for (ClientInfoForDisplay client: perInputStack) {
+                                writer.println(client);
+                            }
+                        }
+                    }
+                }
+            }
+            writer.println("mNumKeyEventsDispatched:" + mNumKeyEventsDispatched
+                    + ",mNumRotaryEventsDispatched:" + mNumRotaryEventsDispatched);
+        }
+    }
+
+    private void dispatchClientCallbackLocked(ClientsToDispatch clientsToDispatch) {
+        if (clientsToDispatch.mClientsToDispatch.isEmpty()) {
+            return;
+        }
+        if (DBG_DISPATCH) {
+            Log.i(TAG, "dispatchClientCallbackLocked, number of clients:"
+                    + clientsToDispatch.mClientsToDispatch.size());
+        }
+        mClientDispatchQueue.add(clientsToDispatch);
+        CarServiceUtils.runOnMain(() -> {
+            ClientsToDispatch clients;
+            synchronized (mLock) {
+                if (mClientDispatchQueue.isEmpty()) {
+                    return;
+                }
+                clients = mClientDispatchQueue.pop();
+            }
+
+            if (DBG_DISPATCH) {
+                Log.i(TAG, "dispatching to clients, num of clients:"
+                        + clients.mClientsToDispatch.size()
+                        + ", display:" + clients.mDisplayType);
+            }
+            for (int i = 0; i < clients.mClientsToDispatch.size(); i++) {
+                ICarInputCallback callback = clients.mClientsToDispatch.keyAt(i);
+                int[] inputTypes = clients.mClientsToDispatch.valueAt(i);
+                Arrays.sort(inputTypes);
+                if (DBG_DISPATCH) {
+                    Log.i(TAG, "dispatching to client, callback:"
+                            + callback + ", inputTypes:" + Arrays.toString(inputTypes));
+                }
+                try {
+                    callback.onCaptureStateChanged(clients.mDisplayType, inputTypes);
+                } catch (RemoteException e) {
+                    // Ignore. Let death handler deal with it.
+                }
+            }
+        });
+    }
+
+    private void dispatchKeyEvent(int targetDisplayType, KeyEvent event,
+            ICarInputCallback callback) {
+        CarServiceUtils.runOnMain(() -> {
+            mKeyEventDispatchScratchList.clear();
+            mKeyEventDispatchScratchList.add(event);
+            try {
+                callback.onKeyEvents(targetDisplayType, mKeyEventDispatchScratchList);
+            } catch (RemoteException e) {
+                // Ignore. Let death handler deal with it.
+            }
+        });
+    }
+
+    private void dispatchRotaryEvent(int targetDisplayType, RotaryEvent event,
+            ICarInputCallback callback) {
+        if (DBG_DISPATCH) {
+            Log.i(TAG, "dispatchRotaryEvent:" + event);
+        }
+        CarServiceUtils.runOnMain(() -> {
+            mRotaryEventDispatchScratchList.clear();
+            mRotaryEventDispatchScratchList.add(event);
+            try {
+                callback.onRotaryEvents(targetDisplayType, mRotaryEventDispatchScratchList);
+            } catch (RemoteException e) {
+                // Ignore. Let death handler deal with it.
+            }
+        });
+    }
+
+    private static void assertInputTypeValid(int[] inputTypes) {
+        for (int inputType : inputTypes) {
+            if (!VALID_INPUT_TYPES.contains(inputType)) {
+                throw new IllegalArgumentException("Invalid input type:" + inputType
+                        + ", inputTypes:" + Arrays.toString(inputTypes));
+            }
+        }
+    }
+}
diff --git a/service/src/com/android/car/OccupantAwarenessService.java b/service/src/com/android/car/OccupantAwarenessService.java
new file mode 100644
index 0000000..389fc54
--- /dev/null
+++ b/service/src/com/android/car/OccupantAwarenessService.java
@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car;
+
+import android.annotation.NonNull;
+import android.car.Car;
+import android.car.occupantawareness.IOccupantAwarenessEventCallback;
+import android.car.occupantawareness.OccupantAwarenessDetection;
+import android.car.occupantawareness.OccupantAwarenessDetection.VehicleOccupantRole;
+import android.car.occupantawareness.SystemStatusEvent;
+import android.car.occupantawareness.SystemStatusEvent.DetectionTypeFlags;
+import android.content.Context;
+import android.hardware.automotive.occupant_awareness.IOccupantAwareness;
+import android.hardware.automotive.occupant_awareness.IOccupantAwarenessClientCallback;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+
+/**
+ * A service that listens to an Occupant Awareness Detection system across a HAL boundary and
+ * exposes the data to system clients in Android via a {@link
+ * android.car.occupantawareness.OccupantAwarenessManager}.
+ *
+ * <p>The service exposes the following detections types:
+ *
+ * <h1>Presence Detection</h1>
+ *
+ * Detects whether a person is present for each seat location.
+ *
+ * <h1>Gaze Detection</h1>
+ *
+ * Detects where an occupant is looking and for how long they have been looking at the specified
+ * target.
+ *
+ * <h1>Driver Monitoring</h1>
+ *
+ * Detects whether a driver is looking on or off-road and for how long they have been looking there.
+ */
+public class OccupantAwarenessService
+        extends android.car.occupantawareness.IOccupantAwarenessManager.Stub
+        implements CarServiceBase {
+    private static final String TAG = CarLog.TAG_OAS;
+    private static final boolean DBG = false;
+
+    // HAL service identifier name.
+    @VisibleForTesting
+    static final String OAS_SERVICE_ID =
+            "android.hardware.automotive.occupant_awareness.IOccupantAwareness/default";
+
+    private final Object mLock = new Object();
+    private final Context mContext;
+
+    @GuardedBy("mLock")
+    private IOccupantAwareness mOasHal;
+
+    private final ChangeListenerToHalService mHalListener = new ChangeListenerToHalService(this);
+
+    private class ChangeCallbackList extends RemoteCallbackList<IOccupantAwarenessEventCallback> {
+        private final WeakReference<OccupantAwarenessService> mOasService;
+
+        ChangeCallbackList(OccupantAwarenessService oasService) {
+            mOasService = new WeakReference<>(oasService);
+        }
+
+        /** Handle callback death. */
+        @Override
+        public void onCallbackDied(IOccupantAwarenessEventCallback listener) {
+            Log.i(TAG, "binderDied: " + listener.asBinder());
+
+            OccupantAwarenessService service = mOasService.get();
+            if (service != null) {
+                service.handleClientDisconnected();
+            }
+        }
+    }
+
+    @GuardedBy("mLock")
+    private final ChangeCallbackList mListeners = new ChangeCallbackList(this);
+
+    /** Creates an OccupantAwarenessService instance given a {@link Context}. */
+    public OccupantAwarenessService(Context context) {
+        mContext = context;
+    }
+
+    /** Creates an OccupantAwarenessService instance given a {@link Context}. */
+    @VisibleForTesting
+    OccupantAwarenessService(Context context, IOccupantAwareness oasInterface) {
+        mContext = context;
+        mOasHal = oasInterface;
+    }
+
+    @Override
+    public void init() {
+        logd("Initializing service");
+        connectToHalServiceIfNotConnected();
+    }
+
+    @Override
+    public void release() {
+        logd("Will stop detection and disconnect listeners");
+        stopDetectionGraph();
+        mListeners.kill();
+    }
+
+    @Override
+    public void dump(PrintWriter writer) {
+        writer.println("*OccupantAwarenessService*");
+        writer.println(
+                String.format(
+                        "%s to HAL service", mOasHal == null ? "NOT connected" : "Connected"));
+        writer.println(
+                String.format(
+                        "%d change listeners subscribed.",
+                        mListeners.getRegisteredCallbackCount()));
+    }
+
+    /** Attempts to connect to the HAL service if it is not already connected. */
+    private void connectToHalServiceIfNotConnected() {
+        logd("connectToHalServiceIfNotConnected()");
+
+        synchronized (mLock) {
+            // If already connected, nothing more needs to be done.
+            if (mOasHal != null) {
+                logd("Client is already connected, nothing more to do");
+                return;
+            }
+
+            // Attempt to find the HAL service.
+            logd("Attempting to connect to client at: " + OAS_SERVICE_ID);
+            mOasHal =
+                    android.hardware.automotive.occupant_awareness.IOccupantAwareness.Stub
+                            .asInterface(ServiceManager.getService(OAS_SERVICE_ID));
+
+            if (mOasHal == null) {
+                Log.e(TAG, "Failed to find OAS hal_service at: [" + OAS_SERVICE_ID + "]");
+                return;
+            }
+
+            // Register for callbacks.
+            try {
+                mOasHal.setCallback(mHalListener);
+            } catch (RemoteException e) {
+                mOasHal = null;
+                Log.e(TAG, "Failed to set callback: " + e);
+                return;
+            }
+
+            logd("Successfully connected to hal_service at: [" + OAS_SERVICE_ID + "]");
+        }
+    }
+
+    /** Sends a message via the HAL to start the detection graph. */
+    private void startDetectionGraph() {
+        logd("Attempting to start detection graph");
+
+        // Grab a copy of 'mOasHal' to avoid sitting on the lock longer than is necessary.
+        IOccupantAwareness hal;
+        synchronized (mLock) {
+            hal = mOasHal;
+        }
+
+        if (hal != null) {
+            try {
+                hal.startDetection();
+            } catch (RemoteException e) {
+                Log.e(TAG, "startDetection() HAL invocation failed: " + e, e);
+
+                synchronized (mLock) {
+                    mOasHal = null;
+                }
+            }
+        } else {
+            Log.e(TAG, "No HAL is connected. Cannot request graph start");
+        }
+    }
+
+    /** Sends a message via the HAL to stop the detection graph. */
+    private void stopDetectionGraph() {
+        logd("Attempting to stop detection graph.");
+
+        // Grab a copy of 'mOasHal' to avoid sitting on the lock longer than is necessary.
+        IOccupantAwareness hal;
+        synchronized (mLock) {
+            hal = mOasHal;
+        }
+
+        if (hal != null) {
+            try {
+                hal.stopDetection();
+            } catch (RemoteException e) {
+                Log.e(TAG, "stopDetection() HAL invocation failed: " + e, e);
+
+                synchronized (mLock) {
+                    mOasHal = null;
+                }
+            }
+        } else {
+            Log.e(TAG, "No HAL is connected. Cannot request graph stop");
+        }
+    }
+
+    /**
+     * Gets the vehicle capabilities for a given role.
+     *
+     * <p>Capabilities are static for a given vehicle configuration and need only be queried once
+     * per vehicle. Once capability is determined, clients should query system status to see if the
+     * subsystem is currently ready to serve.
+     *
+     * <p>Requires {@link android.car.Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE} read
+     * permissions to access.
+     *
+     * @param role {@link VehicleOccupantRole} to query for.
+     * @return Flags indicating supported capabilities for the role.
+     */
+    public @DetectionTypeFlags int getCapabilityForRole(@VehicleOccupantRole int role) {
+        ICarImpl.assertPermission(mContext, Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE);
+
+        connectToHalServiceIfNotConnected();
+
+        // Grab a copy of 'mOasHal' to avoid sitting on the lock longer than is necessary.
+        IOccupantAwareness hal;
+        synchronized (mLock) {
+            hal = mOasHal;
+        }
+
+        if (hal != null) {
+            try {
+                return hal.getCapabilityForRole(role);
+            } catch (RemoteException e) {
+
+                Log.e(TAG, "getCapabilityForRole() HAL invocation failed: " + e, e);
+
+                synchronized (mLock) {
+                    mOasHal = null;
+                }
+
+                return SystemStatusEvent.DETECTION_TYPE_NONE;
+            }
+        } else {
+            Log.e(
+                    TAG,
+                    "getCapabilityForRole(): No HAL interface has been provided. Cannot get"
+                            + " capabilities");
+            return SystemStatusEvent.DETECTION_TYPE_NONE;
+        }
+    }
+
+    /**
+     * Registers a {@link IOccupantAwarenessEventCallback} to be notified for changes in the system
+     * state.
+     *
+     * <p>Requires {@link android.car.Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE} read
+     * permissions to access.
+     *
+     * @param listener {@link IOccupantAwarenessEventCallback} listener to register.
+     */
+    @Override
+    public void registerEventListener(@NonNull IOccupantAwarenessEventCallback listener) {
+        ICarImpl.assertPermission(mContext, Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE);
+
+        connectToHalServiceIfNotConnected();
+
+        synchronized (mLock) {
+            if (mOasHal == null) {
+                Log.e(TAG, "Attempting to register a listener, but could not connect to HAL.");
+                return;
+            }
+
+            logd("Registering a new listener");
+            mListeners.register(listener);
+
+            // After the first client connects, request that the detection graph start.
+            if (mListeners.getRegisteredCallbackCount() == 1) {
+                startDetectionGraph();
+            }
+        }
+    }
+
+    /**
+     * Unregister the given {@link IOccupantAwarenessEventCallback} listener from receiving events.
+     *
+     * <p>Requires {@link android.car.Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE} read
+     * permissions to access.
+     *
+     * @param listener {@link IOccupantAwarenessEventCallback} client to unregister.
+     */
+    @Override
+    public void unregisterEventListener(@NonNull IOccupantAwarenessEventCallback listener) {
+        ICarImpl.assertPermission(mContext, Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE);
+
+        connectToHalServiceIfNotConnected();
+
+        synchronized (mLock) {
+            mListeners.unregister(listener);
+        }
+
+        // When the last client disconnects, request that the detection graph stop.
+        handleClientDisconnected();
+    }
+
+    /** Processes a detection event and propagates it to registered clients. */
+    @VisibleForTesting
+    void processStatusEvent(@NonNull SystemStatusEvent statusEvent) {
+        int idx = mListeners.beginBroadcast();
+        while (idx-- > 0) {
+            IOccupantAwarenessEventCallback listener = mListeners.getBroadcastItem(idx);
+            try {
+                listener.onStatusChanged(statusEvent);
+            } catch (RemoteException e) {
+                // It's likely the connection snapped. Let binder death handle the situation.
+                Log.e(TAG, "onStatusChanged() invocation failed: " + e, e);
+            }
+        }
+        mListeners.finishBroadcast();
+    }
+
+    /** Processes a detection event and propagates it to registered clients. */
+    @VisibleForTesting
+    void processDetectionEvent(@NonNull OccupantAwarenessDetection detection) {
+        int idx = mListeners.beginBroadcast();
+        while (idx-- > 0) {
+            IOccupantAwarenessEventCallback listener = mListeners.getBroadcastItem(idx);
+            try {
+                listener.onDetectionEvent(detection);
+            } catch (RemoteException e) {
+                // It's likely the connection snapped. Let binder death handle the situation.
+                Log.e(TAG, "onDetectionEvent() invocation failed: " + e, e);
+            }
+        }
+        mListeners.finishBroadcast();
+    }
+
+    /** Handle client disconnections, possibly stopping the detection graph. */
+    void handleClientDisconnected() {
+        // If the last client disconnects, requests that the graph stops.
+        synchronized (mLock) {
+            if (mListeners.getRegisteredCallbackCount() == 0) {
+                stopDetectionGraph();
+            }
+        }
+    }
+
+    private static void logd(String msg) {
+        if (DBG) {
+            Log.d(TAG, msg);
+        }
+    }
+
+    /**
+     * Class that implements the listener interface and gets called back from the {@link
+     * android.hardware.automotive.occupant_awareness.IOccupantAwarenessClientCallback} across the
+     * binder interface.
+     */
+    private static class ChangeListenerToHalService extends IOccupantAwarenessClientCallback.Stub {
+        private final WeakReference<OccupantAwarenessService> mOasService;
+
+        ChangeListenerToHalService(OccupantAwarenessService oasService) {
+            mOasService = new WeakReference<>(oasService);
+        }
+
+        @Override
+        public void onSystemStatusChanged(int inputDetectionFlags, byte inputStatus) {
+            OccupantAwarenessService service = mOasService.get();
+            if (service != null) {
+                service.processStatusEvent(
+                        OccupantAwarenessUtils.convertToStatusEvent(
+                                inputDetectionFlags, inputStatus));
+            }
+        }
+
+        @Override
+        public void onDetectionEvent(
+                android.hardware.automotive.occupant_awareness.OccupantDetections detections) {
+            OccupantAwarenessService service = mOasService.get();
+            if (service != null) {
+                for (android.hardware.automotive.occupant_awareness.OccupantDetection detection :
+                        detections.detections) {
+                    service.processDetectionEvent(
+                            OccupantAwarenessUtils.convertToDetectionEvent(
+                                    detections.timeStampMillis, detection));
+                }
+            }
+        }
+
+        @Override
+        public int getInterfaceVersion() {
+            return this.VERSION;
+        }
+
+        @Override
+        public String getInterfaceHash() {
+            return this.HASH;
+        }
+    }
+}
diff --git a/service/src/com/android/car/OccupantAwarenessUtils.java b/service/src/com/android/car/OccupantAwarenessUtils.java
new file mode 100644
index 0000000..3ecf008
--- /dev/null
+++ b/service/src/com/android/car/OccupantAwarenessUtils.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car;
+
+import android.annotation.Nullable;
+import android.car.occupantawareness.DriverMonitoringDetection;
+import android.car.occupantawareness.GazeDetection;
+import android.car.occupantawareness.OccupantAwarenessDetection;
+import android.car.occupantawareness.OccupantAwarenessDetection.ConfidenceLevel;
+import android.car.occupantawareness.Point3D;
+import android.car.occupantawareness.SystemStatusEvent;
+import android.car.occupantawareness.SystemStatusEvent.DetectionTypeFlags;
+import android.car.occupantawareness.SystemStatusEvent.SystemStatus;
+import android.hardware.automotive.occupant_awareness.IOccupantAwareness;
+import android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus;
+import android.util.Log;
+
+/*package*/ final class OccupantAwarenessUtils {
+    private static final String TAG = "OccupantAwarenessUtils";
+
+    private OccupantAwarenessUtils() {}
+
+    /** Converts status flags into to a SystemStatusEvent. */
+    static SystemStatusEvent convertToStatusEvent(int inputDetectionFlags, byte inputStatus) {
+        // Parse the system status from the hardware layer.
+        @SystemStatus int outputStatus = SystemStatusEvent.SYSTEM_STATUS_NOT_READY;
+
+        switch (inputStatus) {
+            case OccupantAwarenessStatus.READY:
+                outputStatus = SystemStatusEvent.SYSTEM_STATUS_READY;
+                break;
+
+            case OccupantAwarenessStatus.NOT_SUPPORTED:
+                outputStatus = SystemStatusEvent.SYSTEM_STATUS_NOT_SUPPORTED;
+                break;
+
+            case OccupantAwarenessStatus.NOT_INITIALIZED:
+                outputStatus = SystemStatusEvent.SYSTEM_STATUS_NOT_READY;
+                break;
+
+            case OccupantAwarenessStatus.FAILURE:
+                outputStatus = SystemStatusEvent.SYSTEM_STATUS_SYSTEM_FAILURE;
+                break;
+
+            default:
+                Log.e(TAG, "Invalid status code: " + inputStatus);
+                break;
+        }
+
+        // Parse the detection flags from the hardware layer.
+        @DetectionTypeFlags int outputFlags = SystemStatusEvent.DETECTION_TYPE_NONE;
+
+        switch (inputDetectionFlags) {
+            case IOccupantAwareness.CAP_NONE:
+                outputFlags = SystemStatusEvent.DETECTION_TYPE_NONE;
+                break;
+
+            case IOccupantAwareness.CAP_PRESENCE_DETECTION:
+                outputFlags = SystemStatusEvent.DETECTION_TYPE_PRESENCE;
+                break;
+
+            case IOccupantAwareness.CAP_GAZE_DETECTION:
+                outputFlags = SystemStatusEvent.DETECTION_TYPE_GAZE;
+                break;
+
+            case IOccupantAwareness.CAP_DRIVER_MONITORING_DETECTION:
+                outputFlags = SystemStatusEvent.DETECTION_TYPE_DRIVER_MONITORING;
+                break;
+
+            default:
+                Log.e(TAG, "Invalid status code: " + inputDetectionFlags);
+                break;
+        }
+
+        return new SystemStatusEvent(outputStatus, outputFlags);
+    }
+
+    /** Converts an input confidence to a ConfidenceLevel. */
+    static @ConfidenceLevel int convertToConfidenceScore(
+            @android.hardware.automotive.occupant_awareness.ConfidenceLevel int inputConfidence) {
+        switch (inputConfidence) {
+            case android.hardware.automotive.occupant_awareness.ConfidenceLevel.MAX:
+                return OccupantAwarenessDetection.CONFIDENCE_LEVEL_MAX;
+
+            case android.hardware.automotive.occupant_awareness.ConfidenceLevel.HIGH:
+                return OccupantAwarenessDetection.CONFIDENCE_LEVEL_HIGH;
+
+            case android.hardware.automotive.occupant_awareness.ConfidenceLevel.LOW:
+                return OccupantAwarenessDetection.CONFIDENCE_LEVEL_LOW;
+
+            case android.hardware.automotive.occupant_awareness.ConfidenceLevel.NONE:
+            default:
+                return OccupantAwarenessDetection.CONFIDENCE_LEVEL_NONE;
+        }
+    }
+
+    /**
+     * Converts an input point to a Point3D. Returns null if the source vector was null or empty.
+     */
+    static Point3D convertToPoint3D(@Nullable double[] vector) {
+        if (vector != null && vector.length == 3) {
+            return new Point3D(vector[0], vector[1], vector[2]);
+        } else {
+            return null;
+        }
+    }
+
+    /** Converts an input timestamp to milliseconds since boot. */
+    static long convertTimestamp(long inputTimestamp) {
+        return inputTimestamp;
+    }
+
+    /**
+     * Converts an input @android.hardware.automotive.occupant_awareness.Role to a
+     * VehicleOccupantRole.
+     */
+    static @OccupantAwarenessDetection.VehicleOccupantRole int convertToRole(int inputRole) {
+        if (inputRole == android.hardware.automotive.occupant_awareness.Role.INVALID
+                || inputRole == android.hardware.automotive.occupant_awareness.Role.UNKNOWN) {
+            return OccupantAwarenessDetection.VEHICLE_OCCUPANT_NONE;
+        } else if (inputRole == android.hardware.automotive.occupant_awareness.Role.ALL_OCCUPANTS) {
+            return OccupantAwarenessDetection.VEHICLE_OCCUPANT_ALL_OCCUPANTS;
+        }
+
+        int outputRole = OccupantAwarenessDetection.VEHICLE_OCCUPANT_NONE;
+
+        if ((inputRole & android.hardware.automotive.occupant_awareness.Role.DRIVER) > 0) {
+            outputRole |= OccupantAwarenessDetection.VEHICLE_OCCUPANT_DRIVER;
+        }
+
+        if ((inputRole & android.hardware.automotive.occupant_awareness.Role.FRONT_PASSENGER) > 0) {
+            outputRole |= OccupantAwarenessDetection.VEHICLE_OCCUPANT_FRONT_PASSENGER;
+        }
+
+        if ((inputRole & android.hardware.automotive.occupant_awareness.Role.ROW_2_PASSENGER_LEFT)
+                > 0) {
+            outputRole |= OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_2_PASSENGER_LEFT;
+        }
+
+        if ((inputRole & android.hardware.automotive.occupant_awareness.Role.ROW_2_PASSENGER_CENTER)
+                > 0) {
+            outputRole |= OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_2_PASSENGER_CENTER;
+        }
+
+        if ((inputRole & android.hardware.automotive.occupant_awareness.Role.ROW_2_PASSENGER_RIGHT)
+                > 0) {
+            outputRole |= OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_2_PASSENGER_RIGHT;
+        }
+
+        if ((inputRole & android.hardware.automotive.occupant_awareness.Role.ROW_3_PASSENGER_LEFT)
+                > 0) {
+            outputRole |= OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_3_PASSENGER_LEFT;
+        }
+
+        if ((inputRole & android.hardware.automotive.occupant_awareness.Role.ROW_3_PASSENGER_CENTER)
+                > 0) {
+            outputRole |= OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_3_PASSENGER_CENTER;
+        }
+
+        if ((inputRole & android.hardware.automotive.occupant_awareness.Role.ROW_3_PASSENGER_RIGHT)
+                > 0) {
+            outputRole |= OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_3_PASSENGER_RIGHT;
+        }
+
+        return outputRole;
+    }
+
+    /** Converts an input detection to a GazeDetection. */
+    static GazeDetection convertToGazeDetection(
+            android.hardware.automotive.occupant_awareness.GazeDetection inputDetection) {
+
+        return new GazeDetection(
+                convertToConfidenceScore(inputDetection.gazeConfidence),
+                convertToPoint3D(inputDetection.headPosition),
+                convertToPoint3D(inputDetection.headPosition),
+                convertToPoint3D(inputDetection.headAngleUnitVector),
+                convertToPoint3D(inputDetection.gazeAngleUnitVector),
+                inputDetection.gazeTarget,
+                inputDetection.timeOnTargetMillis);
+    }
+
+    /** Converts an input detection to a DriverMonitoringDetection. */
+    static DriverMonitoringDetection convertToDriverMonitoringDetection(
+            android.hardware.automotive.occupant_awareness.DriverMonitoringDetection
+                    inputDetection) {
+        return new DriverMonitoringDetection(
+                convertToConfidenceScore(inputDetection.confidenceScore),
+                inputDetection.isLookingOnRoad,
+                inputDetection.gazeDurationMillis);
+    }
+
+    /** Converts a PresenceDetection to a boolean indicating if an occupant was present. */
+    static boolean convertToPresence(
+            android.hardware.automotive.occupant_awareness.PresenceDetection inputDetection) {
+        return inputDetection.isOccupantDetected;
+    }
+
+    /** Converts an OccupantDetection to OccupantAwarenessDetection. */
+    static OccupantAwarenessDetection convertToDetectionEvent(
+            long timestamp,
+            android.hardware.automotive.occupant_awareness.OccupantDetection inputDetection) {
+        // Populate presence, if data is available for this frame.
+        boolean isPresent = false;
+        if (inputDetection.presenceData != null && inputDetection.presenceData.length > 0) {
+            isPresent = convertToPresence(inputDetection.presenceData[0]);
+        }
+
+        // Populate gaze, if data is available for this frame.
+        GazeDetection gazeDetection = null;
+        if (inputDetection.gazeData != null && inputDetection.gazeData.length > 0) {
+            gazeDetection = convertToGazeDetection(inputDetection.gazeData[0]);
+        }
+
+        // Populate driver monitoring, if data is available for this frame.
+        DriverMonitoringDetection driverMonitoringDetection = null;
+        if (inputDetection.attentionData != null && inputDetection.attentionData.length > 0) {
+            driverMonitoringDetection =
+                    convertToDriverMonitoringDetection(inputDetection.attentionData[0]);
+        }
+
+        return new OccupantAwarenessDetection(
+                convertToRole(inputDetection.role),
+                timestamp,
+                isPresent,
+                gazeDetection,
+                driverMonitoringDetection);
+    }
+}
diff --git a/service/src/com/android/car/PerUserCarService.java b/service/src/com/android/car/PerUserCarService.java
index dec2b3a..cb13649 100644
--- a/service/src/com/android/car/PerUserCarService.java
+++ b/service/src/com/android/car/PerUserCarService.java
@@ -17,8 +17,8 @@
 
 import android.app.Service;
 import android.car.ICarBluetoothUserService;
-import android.car.ICarUserService;
 import android.car.ILocationManagerProxy;
+import android.car.IPerUserCarService;
 import android.content.Intent;
 import android.os.IBinder;
 import android.util.Log;
@@ -33,20 +33,20 @@
  */
 public class PerUserCarService extends Service {
     private static final boolean DBG = true;
-    private static final String TAG = "CarUserService";
+    private static final String TAG = "PerUserCarService";
     private volatile CarBluetoothUserService mCarBluetoothUserService;
     private volatile LocationManagerProxy mLocationManagerProxy;
-    private CarUserServiceBinder mCarUserServiceBinder;
+    private PerUserCarServiceBinder mPerUserCarServiceBinder;
 
     @Override
     public IBinder onBind(Intent intent) {
         if (DBG) {
             Log.d(TAG, "onBind()");
         }
-        if (mCarUserServiceBinder == null) {
+        if (mPerUserCarServiceBinder == null) {
             Log.e(TAG, "UserSvcBinder null");
         }
-        return mCarUserServiceBinder;
+        return mPerUserCarServiceBinder;
     }
 
     @Override
@@ -62,7 +62,7 @@
         if (DBG) {
             Log.d(TAG, "onCreate()");
         }
-        mCarUserServiceBinder = new CarUserServiceBinder();
+        mPerUserCarServiceBinder = new PerUserCarServiceBinder();
         mCarBluetoothUserService = new CarBluetoothUserService(this);
         mLocationManagerProxy = new LocationManagerProxy(this);
         super.onCreate();
@@ -73,14 +73,14 @@
         if (DBG) {
             Log.d(TAG, "onDestroy()");
         }
-        mCarUserServiceBinder = null;
+        mPerUserCarServiceBinder = null;
     }
 
     /**
      * Other Services in CarService can create their own Binder interface and receive that interface
-     * through this CarUserService binder.
+     * through this PerUserCarService binder.
      */
-    private final class CarUserServiceBinder extends ICarUserService.Stub {
+    private final class PerUserCarServiceBinder extends IPerUserCarService.Stub {
         @Override
         public ICarBluetoothUserService getBluetoothUserService() {
             return mCarBluetoothUserService;
diff --git a/service/src/com/android/car/PerUserCarServiceHelper.java b/service/src/com/android/car/PerUserCarServiceHelper.java
index 73e41cf..1343d92 100644
--- a/service/src/com/android/car/PerUserCarServiceHelper.java
+++ b/service/src/com/android/car/PerUserCarServiceHelper.java
@@ -16,22 +16,23 @@
 
 package com.android.car;
 
-import android.car.ICarUserService;
-import android.content.BroadcastReceiver;
+import android.car.IPerUserCarService;
+import android.car.user.CarUserManager;
+import android.car.user.CarUserManager.UserLifecycleListener;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.os.IBinder;
 import android.os.UserHandle;
 import android.util.Log;
 
+import com.android.car.user.CarUserService;
 import com.android.internal.annotations.GuardedBy;
 
 import java.io.PrintWriter;
-import java.util.List;
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * A Helper class that helps with the following:
@@ -42,68 +43,53 @@
 public class PerUserCarServiceHelper implements CarServiceBase {
     private static final String TAG = "PerUserCarSvcHelper";
     private static boolean DBG = false;
-    private Context mContext;
-    private ICarUserService mCarUserService;
+    private final Context mContext;
+    private final CarUserService mUserService;
+    private IPerUserCarService mPerUserCarService;
     // listener to call on a ServiceConnection to PerUserCarService
     private List<ServiceCallback> mServiceCallbacks;
-    private UserSwitchBroadcastReceiver mReceiver;
-    private IntentFilter mUserSwitchFilter;
     private static final String EXTRA_USER_HANDLE = "android.intent.extra.user_handle";
     private final Object mServiceBindLock = new Object();
     @GuardedBy("mServiceBindLock")
     private boolean mBound = false;
 
-    public PerUserCarServiceHelper(Context context) {
+    public PerUserCarServiceHelper(Context context, CarUserService userService) {
         mContext = context;
         mServiceCallbacks = new ArrayList<>();
-        mReceiver = new UserSwitchBroadcastReceiver();
-        setupUserSwitchListener();
+        mUserService = userService;
+        mUserService.addUserLifecycleListener(mUserLifecycleListener);
     }
 
     @Override
-    public synchronized void init() {
-        bindToPerUserCarService();
-    }
-
-    @Override
-    public synchronized void release() {
-        unbindFromPerUserCarService();
-    }
-
-    /**
-     * Setting up the intent filter for
-     * 2. UserSwitch events
-     */
-    private void setupUserSwitchListener() {
-        mUserSwitchFilter = new IntentFilter();
-        mUserSwitchFilter.addAction(Intent.ACTION_USER_SWITCHED);
-        mContext.registerReceiver(mReceiver, mUserSwitchFilter);
-        if (DBG) {
-            Log.d(TAG, "UserSwitch Listener Registered");
+    public void init() {
+        synchronized (mServiceBindLock) {
+            bindToPerUserCarService();
         }
     }
 
-    /**
-     * UserSwitchBroadcastReceiver receives broadcasts on User account switches.
-     */
-    public class UserSwitchBroadcastReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            List<ServiceCallback> callbacks;
-            if (DBG) {
-                Log.d(TAG, "User Switch Happened");
-                boolean userSwitched = intent.getAction().equals(
-                        Intent.ACTION_USER_SWITCHED);
+    @Override
+    public void release() {
+        synchronized (mServiceBindLock) {
+            unbindFromPerUserCarService();
+            mUserService.removeUserLifecycleListener(mUserLifecycleListener);
+        }
+    }
 
-                int user = intent.getExtras().getInt(EXTRA_USER_HANDLE);
-                if (userSwitched) {
-                    Log.d(TAG, "New User " + user);
-                }
+    private final UserLifecycleListener mUserLifecycleListener = event -> {
+        if (DBG) {
+            Log.d(TAG, "onEvent(" + event + ")");
+        }
+        if (CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING == event.getEventType()) {
+            List<ServiceCallback> callbacks;
+            int userId = event.getUserId();
+            if (DBG) {
+                Log.d(TAG, "User Switch Happened. New User" + userId);
             }
+
             // Before unbinding, notify the callbacks about unbinding from the service
             // so the callbacks can clean up their state through the binder before the service is
             // killed.
-            synchronized (this) {
+            synchronized (mServiceBindLock) {
                 // copy the callbacks
                 callbacks = new ArrayList<>(mServiceCallbacks);
             }
@@ -116,7 +102,7 @@
             // bind to the service running as the new user
             bindToPerUserCarService();
         }
-    }
+    };
 
     /**
      * ServiceConnection to detect connecting/disconnecting to {@link PerUserCarService}
@@ -129,15 +115,15 @@
             if (DBG) {
                 Log.d(TAG, "Connected to User Service");
             }
-            mCarUserService = ICarUserService.Stub.asInterface(service);
-            if (mCarUserService != null) {
-                synchronized (this) {
+            mPerUserCarService = IPerUserCarService.Stub.asInterface(service);
+            if (mPerUserCarService != null) {
+                synchronized (mServiceBindLock) {
                     // copy the callbacks
                     callbacks = new ArrayList<>(mServiceCallbacks);
                 }
                 // call them
                 for (ServiceCallback callback : callbacks) {
-                    callback.onServiceConnected(mCarUserService);
+                    callback.onServiceConnected(mPerUserCarService);
                 }
             }
         }
@@ -148,7 +134,7 @@
             if (DBG) {
                 Log.d(TAG, "Disconnected from User Service");
             }
-            synchronized (this) {
+            synchronized (mServiceBindLock) {
                 // copy the callbacks
                 callbacks = new ArrayList<>(mServiceCallbacks);
             }
@@ -160,9 +146,8 @@
     };
 
     /**
-     * Bind to the CarUserService {@link PerUserCarService} which is created to run as the Current
-     * User.
-     *
+     * Bind to the PerUserCarService {@link PerUserCarService} which is created to run as the
+     * Current User.
      */
     private void bindToPerUserCarService() {
         if (DBG) {
@@ -207,7 +192,7 @@
             if (DBG) {
                 Log.d(TAG, "Registering PerUserCarService Listener");
             }
-            synchronized (this) {
+            synchronized (mServiceBindLock) {
                 mServiceCallbacks.add(listener);
             }
         }
@@ -222,7 +207,7 @@
             Log.d(TAG, "Unregistering PerUserCarService Listener");
         }
         if (listener != null) {
-            synchronized (this) {
+            synchronized (mServiceBindLock) {
                 mServiceCallbacks.remove(listener);
             }
         }
@@ -232,11 +217,21 @@
      * Listener to the PerUserCarService connection status that clients need to implement.
      */
     public interface ServiceCallback {
-        // When Service Connects
-        void onServiceConnected(ICarUserService carUserService);
-        // Before an unbind call is going to be made.
+        /**
+         * Invoked when a service connects.
+         *
+         * @param perUserCarService the instance of IPerUserCarService.
+         */
+        void onServiceConnected(IPerUserCarService perUserCarService);
+
+        /**
+         * Invoked before an unbind call is going to be made.
+         */
         void onPreUnbind();
-        // When Service crashed or disconnected
+
+        /**
+         * Invoked when a service is crashed or disconnected.
+         */
         void onServiceDisconnected();
     }
 
@@ -244,7 +239,4 @@
     public synchronized void dump(PrintWriter writer) {
 
     }
-
-
 }
-
diff --git a/service/src/com/android/car/Standards.kt b/service/src/com/android/car/Standards.kt
new file mode 100644
index 0000000..272b44f
--- /dev/null
+++ b/service/src/com/android/car/Standards.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car
+
+/**
+ * Identical to [also]. Use to communicate intent of guarding against null. Compatible with
+ * `?:` (elvis operator) if else block is needed.
+ *
+ * Example:
+ * ```
+ * array.firstOrNull()?.guard { Log.d(TAG, "$it is guaranteed to not be null here") }
+ * ```
+ *
+ */
+internal inline fun <T> T.guard(block: (T) -> Unit): T {
+    return this.also(block)
+}
\ No newline at end of file
diff --git a/service/src/com/android/car/SystemActivityMonitoringService.java b/service/src/com/android/car/SystemActivityMonitoringService.java
index d192727..418dd3b 100644
--- a/service/src/com/android/car/SystemActivityMonitoringService.java
+++ b/service/src/com/android/car/SystemActivityMonitoringService.java
@@ -39,7 +39,10 @@
 import android.util.SparseArray;
 import android.view.Display;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
@@ -103,24 +106,31 @@
     private final ProcessObserver mProcessObserver;
     private final TaskListener mTaskListener;
 
-    private final HandlerThread mMonitorHandlerThread;
-    private final ActivityMonitorHandler mHandler;
+    private final HandlerThread mMonitorHandlerThread = CarServiceUtils.getHandlerThread(
+            getClass().getSimpleName());
+    private final ActivityMonitorHandler mHandler = new ActivityMonitorHandler(
+            mMonitorHandlerThread.getLooper(), this);
+
+    private final Object mLock = new Object();
 
     /** K: display id, V: top task */
+    @GuardedBy("mLock")
     private final SparseArray<TopTaskInfoContainer> mTopTasks = new SparseArray<>();
     /** K: uid, V : list of pid */
+    @GuardedBy("mLock")
     private final Map<Integer, Set<Integer>> mForegroundUidPids = new ArrayMap<>();
-    private int mFocusedStackId = INVALID_STACK_ID;
+    @GuardedBy("mLock")
     private ActivityLaunchListener mActivityLaunchListener;
 
     public SystemActivityMonitoringService(Context context) {
         mContext = context;
-        mMonitorHandlerThread = new HandlerThread(CarLog.TAG_AM);
-        mMonitorHandlerThread.start();
-        mHandler = new ActivityMonitorHandler(mMonitorHandlerThread.getLooper());
         mProcessObserver = new ProcessObserver();
         mTaskListener = new TaskListener();
         mAm = ActivityManager.getService();
+    }
+
+    @Override
+    public void init() {
         // Monitoring both listeners are necessary as there are cases where one listener cannot
         // monitor activity change.
         try {
@@ -134,18 +144,20 @@
     }
 
     @Override
-    public void init() {
-    }
-
-    @Override
     public void release() {
+        try {
+            mAm.unregisterProcessObserver(mProcessObserver);
+            mAm.unregisterTaskStackListener(mTaskListener);
+        } catch (RemoteException e) {
+            Log.e(CarLog.TAG_AM, "Failed to unregister listeners", e);
+        }
     }
 
     @Override
     public void dump(PrintWriter writer) {
         writer.println("*SystemActivityMonitoringService*");
         writer.println(" Top Tasks per display:");
-        synchronized (this) {
+        synchronized (mLock) {
             for (int i = 0; i < mTopTasks.size(); i++) {
                 int displayId = mTopTasks.keyAt(i);
                 TopTaskInfoContainer info = mTopTasks.valueAt(i);
@@ -161,7 +173,6 @@
                 }
                 writer.println("uid:" + key + ", pids:" + Arrays.toString(pids.toArray()));
             }
-            writer.println(" focused stack:" + mFocusedStackId);
         }
     }
 
@@ -176,7 +187,7 @@
 
     public List<TopTaskInfoContainer> getTopTasks() {
         LinkedList<TopTaskInfoContainer> tasks = new LinkedList<>();
-        synchronized (this) {
+        synchronized (mLock) {
             for (int i = 0; i < mTopTasks.size(); i++) {
                 TopTaskInfoContainer topTask = mTopTasks.valueAt(i);
                 if (topTask == null) {
@@ -191,7 +202,7 @@
     }
 
     public boolean isInForeground(int pid, int uid) {
-        synchronized (this) {
+        synchronized (mLock) {
             Set<Integer> pids = mForegroundUidPids.get(uid);
             if (pids == null) {
                 return false;
@@ -255,7 +266,7 @@
     }
 
     public void registerActivityLaunchListener(ActivityLaunchListener listener) {
-        synchronized (this) {
+        synchronized (mLock) {
             mActivityLaunchListener = listener;
         }
     }
@@ -268,6 +279,11 @@
             Log.e(CarLog.TAG_AM, "cannot getTasks", e);
             return;
         }
+
+        if (infos == null) {
+            return;
+        }
+
         int focusedStackId = INVALID_STACK_ID;
         try {
             // TODO(b/66955160): Someone on the Auto-team should probably re-work the code in the
@@ -283,7 +299,8 @@
 
         SparseArray<TopTaskInfoContainer> topTasks = new SparseArray<>();
         ActivityLaunchListener listener;
-        synchronized (this) {
+        synchronized (mLock) {
+            mTopTasks.clear();
             listener = mActivityLaunchListener;
 
             for (StackInfo info : infos) {
@@ -345,7 +362,7 @@
     }
 
     private void handleForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
-        synchronized (this) {
+        synchronized (mLock) {
             if (foregroundActivities) {
                 Set<Integer> pids = mForegroundUidPids.get(uid);
                 if (pids == null) {
@@ -360,7 +377,7 @@
     }
 
     private void handleProcessDied(int pid, int uid) {
-        synchronized (this) {
+        synchronized (mLock) {
             doHandlePidGoneLocked(pid, uid);
         }
     }
@@ -450,14 +467,19 @@
         }
     }
 
-    private class ActivityMonitorHandler extends Handler {
+    private static final class ActivityMonitorHandler extends Handler {
+        private  static final String TAG = ActivityMonitorHandler.class.getSimpleName();
+
         private static final int MSG_UPDATE_TASKS = 0;
         private static final int MSG_FOREGROUND_ACTIVITIES_CHANGED = 1;
         private static final int MSG_PROCESS_DIED = 2;
         private static final int MSG_BLOCK_ACTIVITY = 3;
 
-        private ActivityMonitorHandler(Looper looper) {
+        private final WeakReference<SystemActivityMonitoringService> mService;
+
+        private ActivityMonitorHandler(Looper looper, SystemActivityMonitoringService service) {
             super(looper);
+            mService = new WeakReference<SystemActivityMonitoringService>(service);
         }
 
         private void requestUpdatingTask() {
@@ -486,21 +508,27 @@
 
         @Override
         public void handleMessage(Message msg) {
+            SystemActivityMonitoringService service = mService.get();
+            if (service == null) {
+                Log.i(TAG, "handleMessage null service");
+                return;
+            }
             switch (msg.what) {
                 case MSG_UPDATE_TASKS:
-                    updateTasks();
+                    service.updateTasks();
                     break;
                 case MSG_FOREGROUND_ACTIVITIES_CHANGED:
-                    handleForegroundActivitiesChanged(msg.arg1, msg.arg2, (Boolean) msg.obj);
-                    updateTasks();
+                    service.handleForegroundActivitiesChanged(msg.arg1, msg.arg2,
+                            (Boolean) msg.obj);
+                    service.updateTasks();
                     break;
                 case MSG_PROCESS_DIED:
-                    handleProcessDied(msg.arg1, msg.arg2);
+                    service.handleProcessDied(msg.arg1, msg.arg2);
                     break;
                 case MSG_BLOCK_ACTIVITY:
                     Pair<TopTaskInfoContainer, Intent> pair =
                         (Pair<TopTaskInfoContainer, Intent>) msg.obj;
-                    handleBlockActivity(pair.first, pair.second);
+                    service.handleBlockActivity(pair.first, pair.second);
                     break;
             }
         }
diff --git a/service/src/com/android/car/VmsLayersAvailability.java b/service/src/com/android/car/VmsLayersAvailability.java
deleted file mode 100644
index a9bbc7a..0000000
--- a/service/src/com/android/car/VmsLayersAvailability.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import android.car.vms.VmsAssociatedLayer;
-import android.car.vms.VmsAvailableLayers;
-import android.car.vms.VmsLayer;
-import android.car.vms.VmsLayerDependency;
-import android.car.vms.VmsLayersOffering;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Manages VMS availability for layers.
- * <p>
- * Each VMS publisher sets its layers offering which are a list of layers the publisher claims
- * it might publish. VmsLayersAvailability calculates from all the offering what are the
- * available layers.
- *
- * @hide
- */
-
-public class VmsLayersAvailability {
-    private static final boolean DBG = false;
-    private static final String TAG = "VmsLayersAvailability";
-
-    private final Object mLock = new Object();
-    @GuardedBy("mLock")
-    private final Map<VmsLayer, Set<Set<VmsLayer>>> mPotentialLayersAndDependencies =
-            new HashMap<>();
-    @GuardedBy("mLock")
-    private Set<VmsAssociatedLayer> mAvailableAssociatedLayers = Collections.EMPTY_SET;
-    @GuardedBy("mLock")
-    private Set<VmsAssociatedLayer> mUnavailableAssociatedLayers = Collections.EMPTY_SET;
-    @GuardedBy("mLock")
-    private Map<VmsLayer, Set<Integer>> mPotentialLayersAndPublishers = new HashMap<>();
-    @GuardedBy("mLock")
-    private int mSeq = 0;
-
-    /**
-     * Setting the current layers offerings as reported by publishers.
-     */
-    public void setPublishersOffering(Collection<VmsLayersOffering> publishersLayersOfferings) {
-        synchronized (mLock) {
-            reset();
-
-            for (VmsLayersOffering offering : publishersLayersOfferings) {
-                for (VmsLayerDependency dependency : offering.getDependencies()) {
-                    VmsLayer layer = dependency.getLayer();
-
-                    // Associate publishers with layers.
-                    Set<Integer> curPotentialLayerAndPublishers =
-                            mPotentialLayersAndPublishers.get(layer);
-                    if (curPotentialLayerAndPublishers == null) {
-                        curPotentialLayerAndPublishers = new HashSet<>();
-                        mPotentialLayersAndPublishers.put(layer, curPotentialLayerAndPublishers);
-                    }
-                    curPotentialLayerAndPublishers.add(offering.getPublisherId());
-
-                    // Add dependencies for availability calculation.
-                    Set<Set<VmsLayer>> curDependencies =
-                            mPotentialLayersAndDependencies.get(layer);
-                    if (curDependencies == null) {
-                        curDependencies = new HashSet<>();
-                        mPotentialLayersAndDependencies.put(layer, curDependencies);
-                    }
-                    curDependencies.add(dependency.getDependencies());
-                }
-            }
-            calculateLayers();
-        }
-    }
-
-    /**
-     * Returns a collection of all the layers which may be published.
-     */
-    public VmsAvailableLayers getAvailableLayers() {
-        synchronized (mLock) {
-            return new VmsAvailableLayers(mAvailableAssociatedLayers, mSeq);
-        }
-    }
-
-    private void reset() {
-        synchronized (mLock) {
-            mPotentialLayersAndDependencies.clear();
-            mPotentialLayersAndPublishers.clear();
-            mAvailableAssociatedLayers = Collections.EMPTY_SET;
-            mUnavailableAssociatedLayers = Collections.EMPTY_SET;
-            mSeq += 1;
-        }
-    }
-
-    private void calculateLayers() {
-        synchronized (mLock) {
-            Set<VmsLayer> availableLayersSet = new HashSet<>();
-            Set<VmsLayer> cyclicAvoidanceAuxiliarySet = new HashSet<>();
-
-            for (VmsLayer layer : mPotentialLayersAndDependencies.keySet()) {
-                addLayerToAvailabilityCalculationLocked(layer,
-                        availableLayersSet,
-                        cyclicAvoidanceAuxiliarySet);
-            }
-
-            mAvailableAssociatedLayers = Collections.unmodifiableSet(
-                    availableLayersSet
-                            .stream()
-                            .map(l -> new VmsAssociatedLayer(l, mPotentialLayersAndPublishers.get(l)))
-                            .collect(Collectors.toSet()));
-
-            mUnavailableAssociatedLayers = Collections.unmodifiableSet(
-                    mPotentialLayersAndDependencies.keySet()
-                            .stream()
-                            .filter(l -> !availableLayersSet.contains(l))
-                            .map(l -> new VmsAssociatedLayer(l, mPotentialLayersAndPublishers.get(l)))
-                            .collect(Collectors.toSet()));
-        }
-    }
-
-    @GuardedBy("mLock")
-    private void addLayerToAvailabilityCalculationLocked(VmsLayer layer,
-                                                         Set<VmsLayer> currentAvailableLayers,
-                                                         Set<VmsLayer> cyclicAvoidanceSet) {
-        if (DBG) {
-            Log.d(TAG, "addLayerToAvailabilityCalculationLocked: checking layer: " + layer);
-        }
-        // If we already know that this layer is supported then we are done.
-        if (currentAvailableLayers.contains(layer)) {
-            return;
-        }
-        // If there is no offering for this layer we're done.
-        if (!mPotentialLayersAndDependencies.containsKey(layer)) {
-            return;
-        }
-        // Avoid cyclic dependency.
-        if (cyclicAvoidanceSet.contains(layer)) {
-            Log.e(TAG, "Detected a cyclic dependency: " + cyclicAvoidanceSet + " -> " + layer);
-            return;
-        }
-        // A layer may have multiple dependency sets. The layer is available if any dependency
-        // set is satisfied
-        for (Set<VmsLayer> dependencies : mPotentialLayersAndDependencies.get(layer)) {
-            // If layer does not have any dependencies then add to supported.
-            if (dependencies == null || dependencies.isEmpty()) {
-                currentAvailableLayers.add(layer);
-                return;
-            }
-            // Add the layer to cyclic avoidance set
-            cyclicAvoidanceSet.add(layer);
-
-            boolean isSupported = true;
-            for (VmsLayer dependency : dependencies) {
-                addLayerToAvailabilityCalculationLocked(dependency,
-                        currentAvailableLayers,
-                        cyclicAvoidanceSet);
-
-                if (!currentAvailableLayers.contains(dependency)) {
-                    isSupported = false;
-                    break;
-                }
-            }
-            cyclicAvoidanceSet.remove(layer);
-
-            if (isSupported) {
-                currentAvailableLayers.add(layer);
-                return;
-            }
-        }
-        return;
-    }
-}
diff --git a/service/src/com/android/car/VmsPublisherService.java b/service/src/com/android/car/VmsPublisherService.java
deleted file mode 100644
index def10dd..0000000
--- a/service/src/com/android/car/VmsPublisherService.java
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import android.car.vms.IVmsPublisherClient;
-import android.car.vms.IVmsPublisherService;
-import android.car.vms.IVmsSubscriberClient;
-import android.car.vms.VmsLayer;
-import android.car.vms.VmsLayersOffering;
-import android.car.vms.VmsSubscriptionState;
-import android.content.Context;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import com.android.car.stats.CarStatsService;
-import com.android.car.vms.VmsBrokerService;
-import com.android.car.vms.VmsClientManager;
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.PrintWriter;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.IntSupplier;
-
-
-/**
- * Receives HAL updates by implementing VmsHalService.VmsHalListener.
- * Binds to publishers and configures them to use this service.
- * Notifies publishers of subscription changes.
- */
-public class VmsPublisherService implements CarServiceBase {
-    private static final boolean DBG = false;
-    private static final String TAG = "VmsPublisherService";
-
-    private final Context mContext;
-    private final CarStatsService mStatsService;
-    private final VmsBrokerService mBrokerService;
-    private final VmsClientManager mClientManager;
-    private final IntSupplier mGetCallingUid;
-    private final Map<String, PublisherProxy> mPublisherProxies = Collections.synchronizedMap(
-            new ArrayMap<>());
-
-    VmsPublisherService(
-            Context context,
-            CarStatsService statsService,
-            VmsBrokerService brokerService,
-            VmsClientManager clientManager) {
-        this(context, statsService, brokerService, clientManager, Binder::getCallingUid);
-    }
-
-    @VisibleForTesting
-    VmsPublisherService(
-            Context context,
-            CarStatsService statsService,
-            VmsBrokerService brokerService,
-            VmsClientManager clientManager,
-            IntSupplier getCallingUid) {
-        mContext = context;
-        mStatsService = statsService;
-        mBrokerService = brokerService;
-        mClientManager = clientManager;
-        mGetCallingUid = getCallingUid;
-
-        mClientManager.setPublisherService(this);
-    }
-
-    @Override
-    public void init() {}
-
-    @Override
-    public void release() {
-        mPublisherProxies.values().forEach(PublisherProxy::unregister);
-        mPublisherProxies.clear();
-    }
-
-    @Override
-    public void dump(PrintWriter writer) {
-        writer.println("*" + getClass().getSimpleName() + "*");
-        writer.println("mPublisherProxies: " + mPublisherProxies.size());
-    }
-
-    /**
-     * Called when a client connection is established or re-established.
-     *
-     * @param publisherName    String that uniquely identifies the service and user.
-     * @param publisherClient The client's communication channel.
-     */
-    public void onClientConnected(String publisherName, IVmsPublisherClient publisherClient) {
-        if (DBG) Log.d(TAG, "onClientConnected: " + publisherName);
-        IBinder publisherToken = new Binder();
-
-        PublisherProxy publisherProxy = new PublisherProxy(publisherName, publisherToken,
-                publisherClient);
-        publisherProxy.register();
-        try {
-            publisherClient.setVmsPublisherService(publisherToken, publisherProxy);
-        } catch (Throwable e) {
-            Log.e(TAG, "unable to configure publisher: " + publisherName, e);
-            return;
-        }
-
-        PublisherProxy existingProxy = mPublisherProxies.put(publisherName, publisherProxy);
-        if (existingProxy != null) {
-            existingProxy.unregister();
-        }
-    }
-
-    /**
-     * Called when a client connection is terminated.
-     *
-     * @param publisherName String that uniquely identifies the service and user.
-     */
-    public void onClientDisconnected(String publisherName) {
-        if (DBG) Log.d(TAG, "onClientDisconnected: " + publisherName);
-        PublisherProxy proxy = mPublisherProxies.remove(publisherName);
-        if (proxy != null) {
-            proxy.unregister();
-        }
-    }
-
-    private class PublisherProxy extends IVmsPublisherService.Stub implements
-            VmsBrokerService.PublisherListener {
-        private final String mName;
-        private final IBinder mToken;
-        private final IVmsPublisherClient mPublisherClient;
-        private boolean mConnected;
-
-        PublisherProxy(String name, IBinder token,
-                IVmsPublisherClient publisherClient) {
-            this.mName = name;
-            this.mToken = token;
-            this.mPublisherClient = publisherClient;
-        }
-
-        void register() {
-            if (DBG) Log.d(TAG, "register: " + mName);
-            mConnected = true;
-            mBrokerService.addPublisherListener(this);
-        }
-
-        void unregister() {
-            if (DBG) Log.d(TAG, "unregister: " + mName);
-            mConnected = false;
-            mBrokerService.removePublisherListener(this);
-            mBrokerService.removeDeadPublisher(mToken);
-        }
-
-        @Override
-        public void setLayersOffering(IBinder token, VmsLayersOffering offering) {
-            assertPermission(token);
-            mBrokerService.setPublisherLayersOffering(token, offering);
-        }
-
-        @Override
-        public void publish(IBinder token, VmsLayer layer, int publisherId, byte[] payload) {
-            assertPermission(token);
-            if (DBG) {
-                Log.d(TAG, String.format("Publishing to %s as %d (%s)", layer, publisherId, mName));
-            }
-
-            if (layer == null) {
-                return;
-            }
-
-            int payloadLength = payload != null ? payload.length : 0;
-            mStatsService.getVmsClientLogger(mGetCallingUid.getAsInt())
-                    .logPacketSent(layer, payloadLength);
-
-            // Send the message to subscribers
-            Set<IVmsSubscriberClient> listeners =
-                    mBrokerService.getSubscribersForLayerFromPublisher(layer, publisherId);
-
-            if (DBG) Log.d(TAG, String.format("Number of subscribers: %d", listeners.size()));
-
-            if (listeners.size() == 0) {
-                // A negative UID signals that the packet had zero subscribers
-                mStatsService.getVmsClientLogger(-1)
-                        .logPacketDropped(layer, payloadLength);
-            }
-
-            for (IVmsSubscriberClient listener : listeners) {
-                int subscriberUid = mClientManager.getSubscriberUid(listener);
-                try {
-                    listener.onVmsMessageReceived(layer, payload);
-                    mStatsService.getVmsClientLogger(subscriberUid)
-                            .logPacketReceived(layer, payloadLength);
-                } catch (RemoteException ex) {
-                    mStatsService.getVmsClientLogger(subscriberUid)
-                            .logPacketDropped(layer, payloadLength);
-                    String subscriberName = mClientManager.getPackageName(listener);
-                    Log.e(TAG, String.format("Unable to publish to listener: %s", subscriberName));
-                }
-            }
-        }
-
-        @Override
-        public VmsSubscriptionState getSubscriptions() {
-            assertPermission();
-            return mBrokerService.getSubscriptionState();
-        }
-
-        @Override
-        public int getPublisherId(byte[] publisherInfo) {
-            assertPermission();
-            return mBrokerService.getPublisherId(publisherInfo);
-        }
-
-        @Override
-        public void onSubscriptionChange(VmsSubscriptionState subscriptionState) {
-            try {
-                mPublisherClient.onVmsSubscriptionChange(subscriptionState);
-            } catch (Throwable e) {
-                Log.e(TAG, String.format("Unable to send subscription state to: %s", mName), e);
-            }
-        }
-
-        private void assertPermission(IBinder publisherToken) {
-            if (mToken != publisherToken) {
-                throw new SecurityException("Invalid publisher token");
-            }
-            assertPermission();
-        }
-
-        private void assertPermission() {
-            if (!mConnected) {
-                throw new SecurityException("Publisher has been disconnected");
-            }
-            ICarImpl.assertVmsPublisherPermission(mContext);
-        }
-    }
-}
diff --git a/service/src/com/android/car/VmsPublishersInfo.java b/service/src/com/android/car/VmsPublishersInfo.java
deleted file mode 100644
index 94bc794..0000000
--- a/service/src/com/android/car/VmsPublishersInfo.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import android.util.ArrayMap;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-
-public class VmsPublishersInfo {
-    private static final byte[] EMPTY_RESPONSE = new byte[0];
-
-    private final Object mLock = new Object();
-    @GuardedBy("mLock")
-    private final ArrayMap<InfoWrapper, Integer> mPublishersIds = new ArrayMap<>();
-    @GuardedBy("mLock")
-    private final ArrayList<InfoWrapper> mPublishersInfo = new ArrayList<>();
-
-    private static class InfoWrapper {
-        private final byte[] mInfo;
-
-        InfoWrapper(byte[] info) {
-            mInfo = info;
-        }
-
-        public byte[] getInfo() {
-            return mInfo.clone();
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (!(o instanceof InfoWrapper)) {
-                return false;
-            }
-            InfoWrapper p = (InfoWrapper) o;
-            return Arrays.equals(this.mInfo, p.mInfo);
-        }
-
-        @Override
-        public int hashCode() {
-            return Arrays.hashCode(mInfo);
-        }
-    }
-
-    /**
-     * Retrieves the publisher ID for the given publisher information. If the publisher information
-     * has not previously been seen, it will be assigned a new publisher ID.
-     *
-     * @param publisherInfo Publisher information to query or register.
-     * @return Publisher ID for the given publisher information.
-     */
-    public int getIdForInfo(byte[] publisherInfo) {
-        Integer publisherId;
-        InfoWrapper wrappedPublisherInfo = new InfoWrapper(publisherInfo);
-        synchronized (mLock) {
-            // Check if publisher is already registered
-            publisherId = mPublishersIds.get(wrappedPublisherInfo);
-            if (publisherId == null) {
-                // Add the new publisher and assign it the next ID
-                mPublishersInfo.add(wrappedPublisherInfo);
-                publisherId = mPublishersInfo.size();
-                mPublishersIds.put(wrappedPublisherInfo, publisherId);
-            }
-        }
-        return publisherId;
-    }
-
-    /**
-     * Returns the publisher info associated with the given publisher ID.
-     * @param publisherId Publisher ID to query.
-     * @return Publisher info associated with the ID, or an empty array if publisher ID is unknown.
-     */
-    public byte[] getPublisherInfo(int publisherId) {
-        synchronized (mLock) {
-            return publisherId < 1 || publisherId > mPublishersInfo.size()
-                    ? EMPTY_RESPONSE
-                    : mPublishersInfo.get(publisherId - 1).getInfo();
-        }
-    }
-}
-
diff --git a/service/src/com/android/car/VmsRouting.java b/service/src/com/android/car/VmsRouting.java
deleted file mode 100644
index 97a928f..0000000
--- a/service/src/com/android/car/VmsRouting.java
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import android.car.vms.IVmsSubscriberClient;
-import android.car.vms.VmsAssociatedLayer;
-import android.car.vms.VmsLayer;
-import android.car.vms.VmsOperationRecorder;
-import android.car.vms.VmsSubscriptionState;
-import android.os.IBinder;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Pair;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Manages all the VMS subscriptions:
- * + Subscriptions to data messages of individual layer + version.
- * + Subscriptions to all data messages.
- * + HAL subscriptions to layer + version.
- */
-
-public class VmsRouting {
-    private final Object mLock = new Object();
-
-    @GuardedBy("mLock")
-    private Map<IBinder, IVmsSubscriberClient> mSubscribers = new ArrayMap<>();
-
-    @GuardedBy("mLock")
-    private Set<IBinder> mPassiveSubscribers = new ArraySet<>();
-
-    @GuardedBy("mLock")
-    private Map<VmsLayer, Set<IBinder>> mLayerSubscriptions = new ArrayMap<>();
-
-    @GuardedBy("mLock")
-    private Map<VmsLayer, Map<Integer, Set<IBinder>>> mLayerSubscriptionsToPublishers =
-            new ArrayMap<>();
-
-    @GuardedBy("mLock")
-    private int mSequenceNumber = 0;
-
-    /**
-     * Add a passive subscription to all data messages.
-     *
-     * Passive subscribers receive all published data messages, but are not reflected in the
-     * subscription state sent to publishers.
-     *
-     * @param subscriber VMS subscriber to add
-     */
-    public void addSubscription(IVmsSubscriberClient subscriber) {
-        int sequenceNumber;
-        synchronized (mLock) {
-            if (!mPassiveSubscribers.add(addSubscriber(subscriber))) {
-                return;
-            }
-            sequenceNumber = mSequenceNumber;
-        }
-        VmsOperationRecorder.get().addPromiscuousSubscription(sequenceNumber);
-    }
-
-    /**
-     * Remove a passive subscription to all data messages.
-     *
-     * @param subscriber VMS subscriber to remove
-     */
-    public void removeSubscription(IVmsSubscriberClient subscriber) {
-        int sequenceNumber;
-        synchronized (mLock) {
-            if (!mPassiveSubscribers.remove(subscriber.asBinder())) {
-                return;
-            }
-            sequenceNumber = mSequenceNumber;
-        }
-        VmsOperationRecorder.get().removePromiscuousSubscription(sequenceNumber);
-    }
-
-    /**
-     * Add a subscription to data messages from a VMS layer.
-     *
-     * @param subscriber VMS subscriber to add
-     * @param layer      the layer to subscribe to
-     */
-    public void addSubscription(IVmsSubscriberClient subscriber, VmsLayer layer) {
-        int sequenceNumber;
-        synchronized (mLock) {
-            Set<IBinder> subscribers =
-                    mLayerSubscriptions.computeIfAbsent(layer, k -> new ArraySet<>());
-            if (!subscribers.add(addSubscriber(subscriber))) {
-                return;
-            }
-            sequenceNumber = ++mSequenceNumber;
-        }
-        VmsOperationRecorder.get().addSubscription(sequenceNumber, layer);
-    }
-
-    /**
-     * Remove a subscription to data messages from a VMS layer.
-     *
-     * @param subscriber VMS subscriber to remove
-     * @param layer      the subscribed layer
-     */
-    public void removeSubscription(IVmsSubscriberClient subscriber, VmsLayer layer) {
-        int sequenceNumber;
-        synchronized (mLock) {
-            Set<IBinder> subscribers =
-                    mLayerSubscriptions.getOrDefault(layer, Collections.emptySet());
-            if (!subscribers.remove(subscriber.asBinder())) {
-                return;
-            }
-            sequenceNumber = ++mSequenceNumber;
-
-            if (subscribers.isEmpty()) {
-                // If a layer has no subscribers, remove it
-                mLayerSubscriptions.remove(layer);
-            }
-        }
-        VmsOperationRecorder.get().removeSubscription(sequenceNumber, layer);
-    }
-
-    /**
-     * Add a subscription to data messages from a VMS layer and a specific publisher.
-     *
-     * @param subscriber  VMS subscriber to add
-     * @param layer       the layer to subscribe to
-     * @param publisherId the publisher ID
-     */
-    public void addSubscription(IVmsSubscriberClient subscriber, VmsLayer layer, int publisherId) {
-        int sequenceNumber;
-        synchronized (mLock) {
-            Set<IBinder> subscribers =
-                    mLayerSubscriptionsToPublishers.computeIfAbsent(layer, k -> new ArrayMap<>())
-                            .computeIfAbsent(publisherId, k -> new ArraySet<>());
-            if (!subscribers.add(addSubscriber(subscriber))) {
-                return;
-            }
-            sequenceNumber = ++mSequenceNumber;
-        }
-        VmsOperationRecorder.get().addSubscription(sequenceNumber, layer);
-    }
-
-    /**
-     * Remove a subscription to data messages from a VMS layer and a specific publisher.
-     *
-     * @param subscriber  VMS subscriber to remove
-     * @param layer       the subscribed layer
-     * @param publisherId the publisher ID
-     */
-    public void removeSubscription(IVmsSubscriberClient subscriber,
-            VmsLayer layer,
-            int publisherId) {
-        int sequenceNumber;
-        synchronized (mLock) {
-            Map<Integer, Set<IBinder>> subscribersToPublishers =
-                    mLayerSubscriptionsToPublishers.getOrDefault(layer, Collections.emptyMap());
-
-            Set<IBinder> subscribers =
-                    subscribersToPublishers.getOrDefault(publisherId, Collections.emptySet());
-            if (!subscribers.remove(subscriber.asBinder())) {
-                return;
-            }
-            sequenceNumber = ++mSequenceNumber;
-
-            // If a publisher has no subscribers, remove it
-            if (subscribers.isEmpty()) {
-                subscribersToPublishers.remove(publisherId);
-            }
-
-            // If a layer has no subscribers, remove it
-            if (subscribersToPublishers.isEmpty()) {
-                mLayerSubscriptionsToPublishers.remove(layer);
-            }
-        }
-        VmsOperationRecorder.get().removeSubscription(sequenceNumber, layer);
-    }
-
-    /**
-     * Remove all of a subscriber's subscriptions.
-     *
-     * @param subscriber VMS subscriber to remove
-     * @return {@code true} if the subscription state was modified
-     */
-    public boolean removeDeadSubscriber(IVmsSubscriberClient subscriber) {
-        IBinder subscriberBinder = subscriber.asBinder();
-        synchronized (mLock) {
-            int startSequenceNumber = mSequenceNumber;
-
-            // Remove the subscriber from the loggers.
-            removeSubscription(subscriber);
-
-            // Remove the subscriber from all layer-based subscriptions.
-            mLayerSubscriptions.entrySet().stream()
-                    .filter(e -> e.getValue().contains(subscriberBinder))
-                    .map(Map.Entry::getKey)
-                    .collect(Collectors.toSet())
-                    .forEach(layer -> removeSubscription(subscriber, layer));
-
-            // Remove the subscriber from all publisher-based subscriptions.
-            mLayerSubscriptionsToPublishers.entrySet().stream()
-                    .flatMap(layer -> layer.getValue().entrySet().stream()
-                            .filter(publisher -> publisher.getValue().contains(subscriberBinder))
-                            .map(publisher -> Pair.create(layer.getKey(), publisher.getKey())))
-                    .collect(Collectors.toSet())
-                    .forEach(layerAndPublisher -> removeSubscription(subscriber,
-                            layerAndPublisher.first, layerAndPublisher.second));
-
-            // Remove the subscriber from the subscriber index
-            mSubscribers.remove(subscriberBinder);
-
-            // If the sequence number was updated, then the subscription state was modified
-            return startSequenceNumber != mSequenceNumber;
-        }
-    }
-
-    /**
-     * Returns a list of all the subscribers a data message should be delivered to. This includes
-     * subscribers that subscribed to this layer from all publishers, subscribed to this layer
-     * from a specific publisher, and passive subscribers.
-     *
-     * @param layer       The layer of the message.
-     * @param publisherId the ID of the client that published the message to be routed.
-     * @return a list of the subscribers.
-     */
-    public Set<IVmsSubscriberClient> getSubscribersForLayerFromPublisher(VmsLayer layer,
-            int publisherId) {
-        Set<IBinder> subscribers = new HashSet<>();
-        synchronized (mLock) {
-            // Add the passive subscribers
-            subscribers.addAll(mPassiveSubscribers);
-
-            // Add the subscribers which explicitly subscribed to this layer
-            subscribers.addAll(mLayerSubscriptions.getOrDefault(layer, Collections.emptySet()));
-
-            // Add the subscribers which explicitly subscribed to this layer and publisher
-            subscribers.addAll(
-                    mLayerSubscriptionsToPublishers.getOrDefault(layer, Collections.emptyMap())
-                            .getOrDefault(publisherId, Collections.emptySet()));
-        }
-        return subscribers.stream()
-                .map(binder -> mSubscribers.get(binder))
-                .filter(Objects::nonNull)
-                .collect(Collectors.toSet());
-    }
-
-    /**
-     * @return {@code true} if there is an explicit subscription to the layer
-     */
-    public boolean hasLayerSubscriptions(VmsLayer layer) {
-        synchronized (mLock) {
-            return mLayerSubscriptions.containsKey(layer);
-        }
-    }
-
-    /**
-     * @return {@code true} if there is an explicit subscription to the layer and publisherId
-     */
-    public boolean hasLayerFromPublisherSubscriptions(VmsLayer layer, int publisherId) {
-        synchronized (mLock) {
-            return mLayerSubscriptionsToPublishers.containsKey(layer)
-                    && mLayerSubscriptionsToPublishers.getOrDefault(layer, Collections.emptyMap())
-                    .containsKey(publisherId);
-        }
-    }
-
-    /**
-     * @return a Set of layers and publishers which VMS clients are subscribed to.
-     */
-    public VmsSubscriptionState getSubscriptionState() {
-        synchronized (mLock) {
-            return new VmsSubscriptionState(mSequenceNumber,
-                    new ArraySet<>(mLayerSubscriptions.keySet()),
-                    mLayerSubscriptionsToPublishers.entrySet()
-                            .stream()
-                            .map(e -> new VmsAssociatedLayer(e.getKey(), e.getValue().keySet()))
-                            .collect(Collectors.toSet()));
-        }
-    }
-
-    private IBinder addSubscriber(IVmsSubscriberClient subscriber) {
-        IBinder subscriberBinder = subscriber.asBinder();
-        synchronized (mLock) {
-            mSubscribers.putIfAbsent(subscriberBinder, subscriber);
-        }
-        return subscriberBinder;
-    }
-}
diff --git a/service/src/com/android/car/VmsSubscriberService.java b/service/src/com/android/car/VmsSubscriberService.java
deleted file mode 100644
index 16cebf3..0000000
--- a/service/src/com/android/car/VmsSubscriberService.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import android.car.vms.IVmsSubscriberClient;
-import android.car.vms.IVmsSubscriberService;
-import android.car.vms.VmsAvailableLayers;
-import android.car.vms.VmsLayer;
-import android.content.Context;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.car.hal.VmsHalService;
-import com.android.car.vms.VmsBrokerService;
-import com.android.car.vms.VmsClientManager;
-
-import java.io.PrintWriter;
-
-/**
- * Offers subscriber services by implementing IVmsSubscriberService.Stub.
- */
-public class VmsSubscriberService extends IVmsSubscriberService.Stub implements CarServiceBase,
-        VmsBrokerService.SubscriberListener {
-    private static final String TAG = "VmsSubscriberService";
-
-    private final Context mContext;
-    private final VmsBrokerService mBrokerService;
-    private final VmsClientManager mClientManager;
-
-    /**
-     * Constructor for client manager.
-     *
-     * @param context           Context to use for registering receivers and binding services.
-     * @param brokerService     Service managing the VMS publisher/subscriber state.
-     * @param clientManager     Service for monitoring VMS subscriber clients.
-     * @param hal               Service providing the HAL client interface
-     */
-    VmsSubscriberService(Context context, VmsBrokerService brokerService,
-            VmsClientManager clientManager, VmsHalService hal) {
-        mContext = context;
-        mBrokerService = brokerService;
-        mClientManager = clientManager;
-        mBrokerService.addSubscriberListener(this);
-        hal.setVmsSubscriberService(this);
-    }
-
-    @Override
-    public void init() {}
-
-    @Override
-    public void release() {}
-
-    @Override
-    public void dump(PrintWriter writer) {
-    }
-
-    @Override
-    public void addVmsSubscriberToNotifications(IVmsSubscriberClient subscriber) {
-        ICarImpl.assertVmsSubscriberPermission(mContext);
-        mClientManager.addSubscriber(subscriber);
-    }
-
-    @Override
-    public void removeVmsSubscriberToNotifications(IVmsSubscriberClient subscriber) {
-        ICarImpl.assertVmsSubscriberPermission(mContext);
-        mClientManager.removeSubscriber(subscriber);
-    }
-
-    @Override
-    public void addVmsSubscriber(IVmsSubscriberClient subscriber, VmsLayer layer) {
-        ICarImpl.assertVmsSubscriberPermission(mContext);
-        mClientManager.addSubscriber(subscriber);
-        mBrokerService.addSubscription(subscriber, layer);
-    }
-
-    @Override
-    public void removeVmsSubscriber(IVmsSubscriberClient subscriber, VmsLayer layer) {
-        ICarImpl.assertVmsSubscriberPermission(mContext);
-        mBrokerService.removeSubscription(subscriber, layer);
-    }
-
-    @Override
-    public void addVmsSubscriberToPublisher(IVmsSubscriberClient subscriber,
-            VmsLayer layer,
-            int publisherId) {
-        ICarImpl.assertVmsSubscriberPermission(mContext);
-        mClientManager.addSubscriber(subscriber);
-        mBrokerService.addSubscription(subscriber, layer, publisherId);
-    }
-
-    @Override
-    public void removeVmsSubscriberToPublisher(IVmsSubscriberClient subscriber,
-            VmsLayer layer,
-            int publisherId) {
-        ICarImpl.assertVmsSubscriberPermission(mContext);
-        mBrokerService.removeSubscription(subscriber, layer, publisherId);
-    }
-
-    @Override
-    public void addVmsSubscriberPassive(IVmsSubscriberClient subscriber) {
-        ICarImpl.assertVmsSubscriberPermission(mContext);
-        mClientManager.addSubscriber(subscriber);
-        mBrokerService.addSubscription(subscriber);
-    }
-
-    @Override
-    public void removeVmsSubscriberPassive(IVmsSubscriberClient subscriber) {
-        ICarImpl.assertVmsSubscriberPermission(mContext);
-        mBrokerService.removeSubscription(subscriber);
-    }
-
-    @Override
-    public byte[] getPublisherInfo(int publisherId) {
-        ICarImpl.assertVmsSubscriberPermission(mContext);
-        return mBrokerService.getPublisherInfo(publisherId);
-    }
-
-    @Override
-    public VmsAvailableLayers getAvailableLayers() {
-        ICarImpl.assertVmsSubscriberPermission(mContext);
-        return mBrokerService.getAvailableLayers();
-    }
-
-    @Override
-    public void onLayersAvailabilityChange(VmsAvailableLayers availableLayers) {
-        for (IVmsSubscriberClient subscriber : mClientManager.getAllSubscribers()) {
-            try {
-                subscriber.onLayersAvailabilityChanged(availableLayers);
-            } catch (RemoteException e) {
-                Log.e(TAG, "onLayersAvailabilityChanged failed: "
-                        + mClientManager.getPackageName(subscriber), e);
-            }
-        }
-    }
-}
diff --git a/service/src/com/android/car/am/FixedActivityService.java b/service/src/com/android/car/am/FixedActivityService.java
index abb1eca..38e31d1 100644
--- a/service/src/com/android/car/am/FixedActivityService.java
+++ b/service/src/com/android/car/am/FixedActivityService.java
@@ -31,6 +31,8 @@
 import android.app.Presentation;
 import android.app.TaskStackListener;
 import android.car.hardware.power.CarPowerManager;
+import android.car.user.CarUserManager;
+import android.car.user.CarUserManager.UserLifecycleListener;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -130,16 +132,13 @@
 
     private final UserManager mUm;
 
-    private final CarUserService.UserCallback mUserCallback = new CarUserService.UserCallback() {
-        @Override
-        public void onUserLockChanged(@UserIdInt int userId, boolean unlocked) {
-            // Nothing to do
+    private final UserLifecycleListener mUserLifecycleListener = event -> {
+        if (Log.isLoggable(TAG_AM, Log.DEBUG)) {
+            Log.d(TAG_AM, "onEvent(" + event + ")");
         }
-
-        @Override
-        public void onSwitchUser(@UserIdInt int userId) {
-            synchronized (mLock) {
-                mRunningActivities.clear();
+        if (CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING == event.getEventType()) {
+            synchronized (FixedActivityService.this.mLock) {
+                clearRunningActivitiesLocked();
             }
         }
     };
@@ -231,8 +230,7 @@
         }
     };
 
-    private final HandlerThread mHandlerThread = new HandlerThread(
-            FixedActivityService.class.getSimpleName());
+    private final HandlerThread mHandlerThread;
 
     private final Runnable mActivityCheckRunnable = () -> {
         launchIfNecessary();
@@ -268,11 +266,18 @@
     };
 
     public FixedActivityService(Context context) {
+        this(context, ActivityManager.getService(), context.getSystemService(UserManager.class),
+                context.getSystemService(DisplayManager.class));
+    }
+
+    FixedActivityService(Context context, IActivityManager activityManager,
+            UserManager userManager, DisplayManager displayManager) {
         mContext = context;
-        mAm = ActivityManager.getService();
-        mUm = context.getSystemService(UserManager.class);
-        mDm = context.getSystemService(DisplayManager.class);
-        mHandlerThread.start();
+        mAm = activityManager;
+        mUm = userManager;
+        mDm = displayManager;
+        mHandlerThread = CarServiceUtils.getHandlerThread(
+                FixedActivityService.class.getSimpleName());
     }
 
     @Override
@@ -291,6 +296,25 @@
         synchronized (mLock) {
             writer.println("mRunningActivities:" + mRunningActivities
                     + " ,mEventMonitoringActive:" + mEventMonitoringActive);
+            writer.println("mBlockingPresentations:");
+            for (int i = 0; i < mBlockingPresentations.size(); i++) {
+                Presentation p = mBlockingPresentations.valueAt(i);
+                if (p == null) {
+                    continue;
+                }
+                writer.println("display:" + mBlockingPresentations.keyAt(i)
+                        + " showing:" + p.isShowing());
+            }
+        }
+    }
+
+    private void clearRunningActivitiesLocked() {
+        int currentUser = ActivityManager.getCurrentUser();
+        for (int i = mRunningActivities.size() - 1; i >= 0; i--) {
+            RunningActivityInfo info = mRunningActivities.valueAt(i);
+            if (info == null || info.userId != currentUser) {
+                mRunningActivities.removeAt(i);
+            }
         }
     }
 
@@ -309,7 +333,7 @@
             mCarPowerManager = carPowerManager;
         }
         CarUserService userService = CarLocalServices.getService(CarUserService.class);
-        userService.addUserCallback(mUserCallback);
+        userService.addUserLifecycleListener(mUserLifecycleListener);
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
@@ -345,7 +369,7 @@
         }
         mHandlerThread.getThreadHandler().removeCallbacks(mActivityCheckRunnable);
         CarUserService userService = CarLocalServices.getService(CarUserService.class);
-        userService.removeUserCallback(mUserCallback);
+        userService.removeUserLifecycleListener(mUserLifecycleListener);
         try {
             mAm.unregisterTaskStackListener(mTaskStackListener);
             mAm.unregisterProcessObserver(mProcessObserver);
@@ -412,10 +436,15 @@
                         Presentation p = new Presentation(mContext, display,
                                 android.R.style.Theme_Black_NoTitleBar_Fullscreen);
                         p.setContentView(R.layout.activity_continuous_blank);
-                        p.show();
                         synchronized (mLock) {
+                            RunningActivityInfo info = mRunningActivities.get(displayIdForActivity);
+                            if (info != null && info.userId == ActivityManager.getCurrentUser()) {
+                                Log.i(TAG_AM, "Do not show Presentation, new req already made");
+                                return;
+                            }
                             mBlockingPresentations.append(displayIdForActivity, p);
                         }
+                        p.show();
                     });
                 }
                 mRunningActivities.removeAt(i);
@@ -548,6 +577,11 @@
             return true;
         }
         int[] profileIds = mUm.getEnabledProfileIds(currentUser);
+        // null can happen in test env when UserManager is mocked. So this check is not necessary
+        // in real env but add it to make test impl easier.
+        if (profileIds == null) {
+            return false;
+        }
         for (int id : profileIds) {
             if (id == userId) {
                 return true;
diff --git a/service/src/com/android/car/audio/CarAudioContext.java b/service/src/com/android/car/audio/CarAudioContext.java
new file mode 100644
index 0000000..f05157b
--- /dev/null
+++ b/service/src/com/android/car/audio/CarAudioContext.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.audio;
+
+import android.media.AudioAttributes;
+import android.media.AudioAttributes.AttributeUsage;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+
+import androidx.annotation.IntDef;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+
+/**
+ * Groupings of {@link AttributeUsage}s to simplify configuration of car audio routing, volume
+ * groups, and focus interactions for similar usages.
+ */
+public final class CarAudioContext {
+    /*
+     * Shouldn't be used
+     * ::android::hardware::automotive::audiocontrol::V1_0::ContextNumber.INVALID
+     */
+    static final int INVALID = 0;
+    /*
+     * Music playback
+     * ::android::hardware::automotive::audiocontrol::V1_0::ContextNumber.INVALID implicitly + 1
+     */
+    static final int MUSIC = 1;
+    /*
+     * Navigation directions
+     * ::android::hardware::automotive::audiocontrol::V1_0::ContextNumber.MUSIC implicitly + 1
+     */
+    static final int NAVIGATION = 2;
+    /*
+     * Voice command session
+     * ::android::hardware::automotive::audiocontrol::V1_0::ContextNumber.NAVIGATION implicitly + 1
+     */
+    static final int VOICE_COMMAND = 3;
+    /*
+     * Voice call ringing
+     * ::android::hardware::automotive::audiocontrol::V1_0::ContextNumber
+     *     .VOICE_COMMAND implicitly + 1
+     */
+    static final int CALL_RING = 4;
+    /*
+     * Voice call
+     * ::android::hardware::automotive::audiocontrol::V1_0::ContextNumber.CALL_RING implicitly + 1
+     */
+    static final int CALL = 5;
+    /*
+     * Alarm sound from Android
+     * ::android::hardware::automotive::audiocontrol::V1_0::ContextNumber.CALL implicitly + 1
+     */
+    static final int ALARM = 6;
+    /*
+     * Notifications
+     * ::android::hardware::automotive::audiocontrol::V1_0::ContextNumber.ALARM implicitly + 1
+     */
+    static final int NOTIFICATION = 7;
+    /*
+     * System sounds
+     * ::android::hardware::automotive::audiocontrol::V1_0::ContextNumber
+     *     .NOTIFICATION implicitly + 1
+     */
+    static final int SYSTEM_SOUND = 8;
+    /*
+     * Emergency related sounds such as collision warnings
+     */
+    static final int EMERGENCY = 9;
+    /*
+     * Safety sounds such as obstacle detection when backing up or when changing lanes
+     */
+    static final int SAFETY = 10;
+    /*
+     * Vehicle Status related sounds such as check engine light or seat belt chimes
+     */
+    static final int VEHICLE_STATUS = 11;
+    /*
+     * Announcement such as traffic announcements
+     */
+    static final int ANNOUNCEMENT = 12;
+
+    static final int[] CONTEXTS = {
+            MUSIC,
+            NAVIGATION,
+            VOICE_COMMAND,
+            CALL_RING,
+            CALL,
+            ALARM,
+            NOTIFICATION,
+            SYSTEM_SOUND,
+            EMERGENCY,
+            SAFETY,
+            VEHICLE_STATUS,
+            ANNOUNCEMENT
+    };
+
+    private static final SparseArray<String> CONTEXT_NAMES = new SparseArray<>(CONTEXTS.length + 1);
+    static {
+        CONTEXT_NAMES.append(INVALID, "INVALID");
+        CONTEXT_NAMES.append(MUSIC, "MUSIC");
+        CONTEXT_NAMES.append(NAVIGATION, "NAVIGATION");
+        CONTEXT_NAMES.append(VOICE_COMMAND, "VOICE_COMMAND");
+        CONTEXT_NAMES.append(CALL_RING, "CALL_RING");
+        CONTEXT_NAMES.append(CALL, "CALL");
+        CONTEXT_NAMES.append(ALARM, "ALARM");
+        CONTEXT_NAMES.append(NOTIFICATION, "NOTIFICATION");
+        CONTEXT_NAMES.append(SYSTEM_SOUND, "SYSTEM_SOUND");
+        CONTEXT_NAMES.append(EMERGENCY, "EMERGENCY");
+        CONTEXT_NAMES.append(SAFETY, "SAFETY");
+        CONTEXT_NAMES.append(VEHICLE_STATUS, "VEHICLE_STATUS");
+        CONTEXT_NAMES.append(ANNOUNCEMENT, "ANNOUNCEMENT");
+    }
+
+    private static final SparseArray<int[]> CONTEXT_TO_USAGES = new SparseArray<>();
+
+    static {
+        CONTEXT_TO_USAGES.put(MUSIC,
+                new int[]{
+                        AudioAttributes.USAGE_UNKNOWN,
+                        AudioAttributes.USAGE_GAME,
+                        AudioAttributes.USAGE_MEDIA
+                });
+
+        CONTEXT_TO_USAGES.put(NAVIGATION,
+                new int[]{
+                        AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE
+                });
+
+        CONTEXT_TO_USAGES.put(VOICE_COMMAND,
+                new int[]{
+                        AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY,
+                        AudioAttributes.USAGE_ASSISTANT
+                });
+
+        CONTEXT_TO_USAGES.put(CALL_RING,
+                new int[]{
+                        AudioAttributes.USAGE_NOTIFICATION_RINGTONE
+                });
+
+        CONTEXT_TO_USAGES.put(CALL,
+                new int[]{
+                        AudioAttributes.USAGE_VOICE_COMMUNICATION,
+                        AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING
+                });
+
+        CONTEXT_TO_USAGES.put(ALARM,
+                new int[]{
+                        AudioAttributes.USAGE_ALARM
+                });
+
+        CONTEXT_TO_USAGES.put(NOTIFICATION,
+                new int[]{
+                        AudioAttributes.USAGE_NOTIFICATION,
+                        AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
+                        AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
+                        AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
+                        AudioAttributes.USAGE_NOTIFICATION_EVENT
+                });
+
+        CONTEXT_TO_USAGES.put(SYSTEM_SOUND,
+                new int[]{
+                        AudioAttributes.USAGE_ASSISTANCE_SONIFICATION
+                });
+
+        CONTEXT_TO_USAGES.put(EMERGENCY,
+                new int[]{
+                        AudioAttributes.USAGE_EMERGENCY
+                });
+
+        CONTEXT_TO_USAGES.put(SAFETY,
+                new int[]{
+                        AudioAttributes.USAGE_SAFETY
+                });
+
+        CONTEXT_TO_USAGES.put(VEHICLE_STATUS,
+                new int[]{
+                        AudioAttributes.USAGE_VEHICLE_STATUS
+                });
+
+        CONTEXT_TO_USAGES.put(ANNOUNCEMENT,
+                new int[]{
+                        AudioAttributes.USAGE_ANNOUNCEMENT
+                });
+
+        CONTEXT_TO_USAGES.put(INVALID,
+                new int[]{
+                        AudioAttributes.USAGE_VIRTUAL_SOURCE
+                });
+    }
+
+    private static final SparseIntArray USAGE_TO_CONTEXT = new SparseIntArray();
+
+    static {
+        for (int i = 0; i < CONTEXT_TO_USAGES.size(); i++) {
+            @AudioContext int audioContext = CONTEXT_TO_USAGES.keyAt(i);
+            @AttributeUsage int[] usages = CONTEXT_TO_USAGES.valueAt(i);
+            for (@AttributeUsage int usage : usages) {
+                USAGE_TO_CONTEXT.put(usage, audioContext);
+            }
+        }
+    }
+
+    /**
+     * Checks if the audio context is within the valid range from MUSIC to SYSTEM_SOUND
+     */
+    static void preconditionCheckAudioContext(@AudioContext int audioContext) {
+        Preconditions.checkArgument(Arrays.binarySearch(CONTEXTS, audioContext) >= 0,
+                "audioContext %d is invalid", audioContext);
+    }
+
+    static @AttributeUsage int[] getUsagesForContext(@AudioContext int carAudioContext) {
+        preconditionCheckAudioContext(carAudioContext);
+        return CONTEXT_TO_USAGES.get(carAudioContext);
+    }
+
+    /**
+     * @return Context number for a given audio usage, {@code INVALID} if the given usage is
+     * unrecognized.
+     */
+    static @AudioContext int getContextForUsage(@AttributeUsage int audioUsage) {
+        return USAGE_TO_CONTEXT.get(audioUsage, INVALID);
+    }
+
+    static String toString(@AudioContext int audioContext) {
+        String name = CONTEXT_NAMES.get(audioContext);
+        if (name != null) {
+            return name;
+        }
+        return "Unsupported Context 0x" + Integer.toHexString(audioContext);
+    }
+
+    @IntDef({
+            INVALID,
+            MUSIC,
+            NAVIGATION,
+            VOICE_COMMAND,
+            CALL_RING,
+            CALL,
+            ALARM,
+            NOTIFICATION,
+            SYSTEM_SOUND,
+            EMERGENCY,
+            SAFETY,
+            VEHICLE_STATUS,
+            ANNOUNCEMENT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AudioContext {
+    }
+};
diff --git a/service/src/com/android/car/audio/CarAudioDeviceInfo.java b/service/src/com/android/car/audio/CarAudioDeviceInfo.java
index f45f48e..cc8788c 100644
--- a/service/src/com/android/car/audio/CarAudioDeviceInfo.java
+++ b/service/src/com/android/car/audio/CarAudioDeviceInfo.java
@@ -28,6 +28,7 @@
 import com.android.internal.util.Preconditions;
 
 import java.io.PrintWriter;
+import java.util.Objects;
 
 /**
  * A helper class wraps {@link AudioDeviceInfo}, and helps get/set the gain on a specific port
@@ -38,34 +39,14 @@
  */
 /* package */ class CarAudioDeviceInfo {
 
-    /**
-     * Parse device address. Expected format is BUS%d_%s, address, usage hint
-     * @return valid address (from 0 to positive) or -1 for invalid address.
-     */
-    static int parseDeviceAddress(String address) {
-        String[] words = address.split("_");
-        int addressParsed = -1;
-        if (words[0].toLowerCase().startsWith("bus")) {
-            try {
-                addressParsed = Integer.parseInt(words[0].substring(3));
-            } catch (NumberFormatException e) {
-                //ignore
-            }
-        }
-        if (addressParsed < 0) {
-            return -1;
-        }
-        return addressParsed;
-    }
-
     private final AudioDeviceInfo mAudioDeviceInfo;
-    private final int mBusNumber;
     private final int mSampleRate;
     private final int mEncodingFormat;
     private final int mChannelCount;
     private final int mDefaultGain;
     private final int mMaxGain;
     private final int mMinGain;
+    private final int mStepValue;
 
     /**
      * We need to store the current gain because it is not accessible from the current
@@ -76,15 +57,15 @@
 
     CarAudioDeviceInfo(AudioDeviceInfo audioDeviceInfo) {
         mAudioDeviceInfo = audioDeviceInfo;
-        mBusNumber = parseDeviceAddress(audioDeviceInfo.getAddress());
         mSampleRate = getMaxSampleRate(audioDeviceInfo);
         mEncodingFormat = getEncodingFormat(audioDeviceInfo);
         mChannelCount = getMaxChannels(audioDeviceInfo);
-        final AudioGain audioGain = Preconditions.checkNotNull(
+        final AudioGain audioGain = Objects.requireNonNull(
                 getAudioGain(), "No audio gain on device port " + audioDeviceInfo);
         mDefaultGain = audioGain.defaultValue();
         mMaxGain = audioGain.maxValue();
         mMinGain = audioGain.minValue();
+        mStepValue = audioGain.stepValue();
 
         mCurrentGain = -1; // Not initialized till explicitly set
     }
@@ -97,8 +78,8 @@
         return mAudioDeviceInfo.getPort();
     }
 
-    int getBusNumber() {
-        return mBusNumber;
+    String getAddress() {
+        return mAudioDeviceInfo.getAddress();
     }
 
     int getDefaultGain() {
@@ -125,6 +106,10 @@
         return mChannelCount;
     }
 
+    int getStepValue() {
+        return mStepValue;
+    }
+
     // Input is in millibels
     void setCurrentGain(int gainInMillibels) {
         // Clamp the incoming value to our valid range.  Out of range values ARE legal input
@@ -237,8 +222,7 @@
 
     @Override
     public String toString() {
-        return "bus number: " + mBusNumber
-                + " address: " + mAudioDeviceInfo.getAddress()
+        return "address: " + mAudioDeviceInfo.getAddress()
                 + " sampleRate: " + getSampleRate()
                 + " encodingFormat: " + getEncodingFormat()
                 + " channelCount: " + getChannelCount()
@@ -248,8 +232,8 @@
     }
 
     void dump(String indent, PrintWriter writer) {
-        writer.printf("%sCarAudioDeviceInfo Bus(%d: %s)\n ",
-                indent, mBusNumber, mAudioDeviceInfo.getAddress());
+        writer.printf("%sCarAudioDeviceInfo Device(%s)\n ",
+                indent, mAudioDeviceInfo.getAddress());
         writer.printf("%s\tsample rate / encoding format / channel count: %d %d %d\n",
                 indent, getSampleRate(), getEncodingFormat(), getChannelCount());
         writer.printf("%s\tGain values (min / max / default/ current): %d %d %d %d\n",
diff --git a/service/src/com/android/car/audio/CarAudioDynamicRouting.java b/service/src/com/android/car/audio/CarAudioDynamicRouting.java
index 73b810c..ea61542 100644
--- a/service/src/com/android/car/audio/CarAudioDynamicRouting.java
+++ b/service/src/com/android/car/audio/CarAudioDynamicRouting.java
@@ -15,42 +15,23 @@
  */
 package com.android.car.audio;
 
-import android.hardware.automotive.audiocontrol.V1_0.ContextNumber;
 import android.media.AudioAttributes;
+import android.media.AudioAttributes.AttributeUsage;
 import android.media.AudioFormat;
 import android.media.AudioManager;
 import android.media.audiopolicy.AudioMix;
 import android.media.audiopolicy.AudioMixingRule;
 import android.media.audiopolicy.AudioPolicy;
 import android.util.Log;
-import android.util.SparseIntArray;
 
 import com.android.car.CarLog;
 
-import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.List;
 
 /**
  * Builds dynamic audio routing in a car from audio zone configuration.
  */
 /* package */ class CarAudioDynamicRouting {
-
-    static final int[] CONTEXT_NUMBERS = new int[] {
-            ContextNumber.MUSIC,
-            ContextNumber.NAVIGATION,
-            ContextNumber.VOICE_COMMAND,
-            ContextNumber.CALL_RING,
-            ContextNumber.CALL,
-            ContextNumber.ALARM,
-            ContextNumber.NOTIFICATION,
-            ContextNumber.SYSTEM_SOUND
-    };
-
-    static final SparseIntArray USAGE_TO_CONTEXT = new SparseIntArray();
-
-    static final int DEFAULT_AUDIO_USAGE = AudioAttributes.USAGE_MEDIA;
-
     // For legacy stream type based volume control.
     // Values in STREAM_TYPES and STREAM_TYPE_USAGES should be aligned.
     static final int[] STREAM_TYPES = new int[] {
@@ -64,33 +45,6 @@
             AudioAttributes.USAGE_NOTIFICATION_RINGTONE
     };
 
-    static {
-        USAGE_TO_CONTEXT.put(AudioAttributes.USAGE_UNKNOWN, ContextNumber.MUSIC);
-        USAGE_TO_CONTEXT.put(AudioAttributes.USAGE_MEDIA, ContextNumber.MUSIC);
-        USAGE_TO_CONTEXT.put(AudioAttributes.USAGE_VOICE_COMMUNICATION, ContextNumber.CALL);
-        USAGE_TO_CONTEXT.put(AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING,
-                ContextNumber.CALL);
-        USAGE_TO_CONTEXT.put(AudioAttributes.USAGE_ALARM, ContextNumber.ALARM);
-        USAGE_TO_CONTEXT.put(AudioAttributes.USAGE_NOTIFICATION, ContextNumber.NOTIFICATION);
-        USAGE_TO_CONTEXT.put(AudioAttributes.USAGE_NOTIFICATION_RINGTONE, ContextNumber.CALL_RING);
-        USAGE_TO_CONTEXT.put(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
-                ContextNumber.NOTIFICATION);
-        USAGE_TO_CONTEXT.put(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
-                ContextNumber.NOTIFICATION);
-        USAGE_TO_CONTEXT.put(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
-                ContextNumber.NOTIFICATION);
-        USAGE_TO_CONTEXT.put(AudioAttributes.USAGE_NOTIFICATION_EVENT, ContextNumber.NOTIFICATION);
-        USAGE_TO_CONTEXT.put(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY,
-                ContextNumber.VOICE_COMMAND);
-        USAGE_TO_CONTEXT.put(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
-                ContextNumber.NAVIGATION);
-        USAGE_TO_CONTEXT.put(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION,
-                ContextNumber.SYSTEM_SOUND);
-        USAGE_TO_CONTEXT.put(AudioAttributes.USAGE_GAME, ContextNumber.MUSIC);
-        USAGE_TO_CONTEXT.put(AudioAttributes.USAGE_VIRTUAL_SOURCE, ContextNumber.INVALID);
-        USAGE_TO_CONTEXT.put(AudioAttributes.USAGE_ASSISTANT, ContextNumber.VOICE_COMMAND);
-    }
-
     private final CarAudioZone[] mCarAudioZones;
 
     CarAudioDynamicRouting(CarAudioZone[] carAudioZones) {
@@ -113,31 +67,32 @@
     private void setupAudioDynamicRoutingForGroup(CarVolumeGroup group,
             AudioPolicy.Builder builder) {
         // Note that one can not register audio mix for same bus more than once.
-        for (int busNumber : group.getBusNumbers()) {
+        for (String address : group.getAddresses()) {
             boolean hasContext = false;
-            CarAudioDeviceInfo info = group.getCarAudioDeviceInfoForBus(busNumber);
+            CarAudioDeviceInfo info = group.getCarAudioDeviceInfoForAddress(address);
             AudioFormat mixFormat = new AudioFormat.Builder()
                     .setSampleRate(info.getSampleRate())
                     .setEncoding(info.getEncodingFormat())
                     .setChannelMask(info.getChannelCount())
                     .build();
             AudioMixingRule.Builder mixingRuleBuilder = new AudioMixingRule.Builder();
-            for (int contextNumber : group.getContextsForBus(busNumber)) {
+            for (int carAudioContext : group.getContextsForAddress(address)) {
                 hasContext = true;
-                int[] usages = getUsagesForContext(contextNumber);
+                int[] usages = CarAudioContext.getUsagesForContext(carAudioContext);
                 for (int usage : usages) {
-                    mixingRuleBuilder.addRule(
-                            new AudioAttributes.Builder().setUsage(usage).build(),
+                    AudioAttributes attributes = buildAttributesWithUsage(usage);
+                    mixingRuleBuilder.addRule(attributes,
                             AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE);
                 }
-                Log.d(CarLog.TAG_AUDIO, "Bus number: " + busNumber
-                        + " contextNumber: " + contextNumber
-                        + " sampleRate: " + info.getSampleRate()
-                        + " channels: " + info.getChannelCount()
-                        + " usages: " + Arrays.toString(usages));
+                if (Log.isLoggable(CarLog.TAG_AUDIO, Log.DEBUG)) {
+                    Log.d(CarLog.TAG_AUDIO, String.format(
+                            "Address: %s AudioContext: %s sampleRate: %d channels: %d usages: %s",
+                            address, carAudioContext, info.getSampleRate(), info.getChannelCount(),
+                            Arrays.toString(usages)));
+                }
             }
             if (hasContext) {
-                // It's a valid case that an audio output bus is defined in
+                // It's a valid case that an audio output address is defined in
                 // audio_policy_configuration and no context is assigned to it.
                 // In such case, do not build a policy mix with zero rules.
                 AudioMix audioMix = new AudioMix.Builder(mixingRuleBuilder.build())
@@ -150,13 +105,13 @@
         }
     }
 
-    private int[] getUsagesForContext(int contextNumber) {
-        final List<Integer> usages = new ArrayList<>();
-        for (int i = 0; i < CarAudioDynamicRouting.USAGE_TO_CONTEXT.size(); i++) {
-            if (CarAudioDynamicRouting.USAGE_TO_CONTEXT.valueAt(i) == contextNumber) {
-                usages.add(CarAudioDynamicRouting.USAGE_TO_CONTEXT.keyAt(i));
-            }
+    private AudioAttributes buildAttributesWithUsage(@AttributeUsage int usage) {
+        AudioAttributes.Builder attributesBuilder = new AudioAttributes.Builder();
+        if (AudioAttributes.isSystemUsage(usage)) {
+            attributesBuilder.setSystemUsage(usage);
+        } else {
+            attributesBuilder.setUsage(usage);
         }
-        return usages.stream().mapToInt(i -> i).toArray();
+        return attributesBuilder.build();
     }
 }
diff --git a/service/src/com/android/car/audio/CarAudioFocus.java b/service/src/com/android/car/audio/CarAudioFocus.java
index 286a045..6c0fdd7 100644
--- a/service/src/com/android/car/audio/CarAudioFocus.java
+++ b/service/src/com/android/car/audio/CarAudioFocus.java
@@ -15,15 +15,12 @@
  */
 package com.android.car.audio;
 
-import android.car.Car;
-import android.car.media.CarAudioManager;
 import android.content.pm.PackageManager;
-import android.hardware.automotive.audiocontrol.V1_0.ContextNumber;
 import android.media.AudioAttributes;
 import android.media.AudioFocusInfo;
 import android.media.AudioManager;
 import android.media.audiopolicy.AudioPolicy;
-import android.os.Bundle;
+import android.util.LocalLog;
 import android.util.Log;
 
 import java.io.PrintWriter;
@@ -36,88 +33,18 @@
 
     private static final String TAG = "CarAudioFocus";
 
+    private static final int FOCUS_EVENT_LOGGER_QUEUE_SIZE = 25;
+
     private final AudioManager mAudioManager;
     private final PackageManager mPackageManager;
-    private CarAudioService mCarAudioService; // Dynamically assigned just after construction
     private AudioPolicy mAudioPolicy; // Dynamically assigned just after construction
 
+    private final LocalLog mFocusEventLogger;
 
-    // Values for the internal interaction matrix we use to make focus decisions
-    static final int INTERACTION_REJECT     = 0;    // Focus not granted
-    static final int INTERACTION_EXCLUSIVE  = 1;    // Focus granted, others loose focus
-    static final int INTERACTION_CONCURRENT = 2;    // Focus granted, others keep focus
+    private final FocusInteraction mFocusInteraction;
 
-
-    // TODO:  Make this an overlayable resource...
-    //  MUSIC           = 1,        // Music playback
-    //  NAVIGATION      = 2,        // Navigation directions
-    //  VOICE_COMMAND   = 3,        // Voice command session
-    //  CALL_RING       = 4,        // Voice call ringing
-    //  CALL            = 5,        // Voice call
-    //  ALARM           = 6,        // Alarm sound from Android
-    //  NOTIFICATION    = 7,        // Notifications
-    //  SYSTEM_SOUND    = 8,        // User interaction sounds (button clicks, etc)
-    private static int sInteractionMatrix[][] = {
-        // Row selected by playing sound (labels along the right)
-        // Column selected by incoming request (labels along the top)
-        // Cell value is one of INTERACTION_REJECT, INTERACTION_EXCLUSIVE, INTERACTION_CONCURRENT
-        // Invalid, Music, Nav, Voice, Ring, Call, Alarm, Notification, System
-        {  0,       0,     0,   0,     0,    0,    0,     0,            0 }, // Invalid
-        {  0,       1,     2,   1,     1,    1,    1,     2,            2 }, // Music
-        {  0,       2,     2,   1,     2,    1,    2,     2,            2 }, // Nav
-        {  0,       2,     0,   2,     1,    1,    0,     0,            0 }, // Voice
-        {  0,       0,     2,   2,     2,    2,    0,     0,            2 }, // Ring
-        {  0,       0,     2,   0,     2,    2,    2,     2,            0 }, // Context
-        {  0,       2,     2,   1,     1,    1,    2,     2,            2 }, // Alarm
-        {  0,       2,     2,   1,     1,    1,    2,     2,            2 }, // Notification
-        {  0,       2,     2,   1,     1,    1,    2,     2,            2 }, // System
-    };
-
-
-    private class FocusEntry {
-        // Requester info
-        final AudioFocusInfo mAfi;                      // never null
-
-        final int mAudioContext;                        // Which HAL level context does this affect
-        final ArrayList<FocusEntry> mBlockers;          // List of requests that block ours
-        boolean mReceivedLossTransientCanDuck;          // Whether holder has lost focus duckably
-
-        FocusEntry(AudioFocusInfo afi,
-                   int context) {
-            mAfi             = afi;
-            mAudioContext    = context;
-            mBlockers        = new ArrayList<FocusEntry>();
-        }
-
-        public String getClientId() {
-            return mAfi.getClientId();
-        }
-
-        public boolean wantsPauseInsteadOfDucking() {
-            return (mAfi.getFlags() & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) != 0;
-        }
-
-        public boolean receivesDuckEvents() {
-            Bundle bundle = mAfi.getAttributes().getBundle();
-
-            if (bundle == null) {
-                return false;
-            }
-
-            if (!bundle.getBoolean(CarAudioManager.AUDIOFOCUS_EXTRA_RECEIVE_DUCKING_EVENTS)) {
-                return false;
-            }
-
-            return (mPackageManager.checkPermission(
-                            Car.PERMISSION_RECEIVE_CAR_AUDIO_DUCKING_EVENTS,
-                            mAfi.getPackageName())
-                    == PackageManager.PERMISSION_GRANTED);
-        }
-
-        String getUsageName() {
-            return mAfi.getAttributes().usageToString();
-        }
-    }
+    private final boolean mEnabledDelayedFocusRequest;
+    private AudioFocusInfo mDelayedRequest;
 
 
     // We keep track of all the focus requesters in this map, with their clientId as the key.
@@ -134,32 +61,40 @@
     private final HashMap<String, FocusEntry> mFocusHolders = new HashMap<>();
     private final HashMap<String, FocusEntry> mFocusLosers = new HashMap<>();
 
+    private final Object mLock = new Object();
 
-    CarAudioFocus(AudioManager audioManager, PackageManager packageManager) {
+
+    CarAudioFocus(AudioManager audioManager, PackageManager packageManager,
+            FocusInteraction focusInteraction, boolean enableDelayedFocusRequest) {
         mAudioManager = audioManager;
         mPackageManager = packageManager;
+        mFocusEventLogger = new LocalLog(FOCUS_EVENT_LOGGER_QUEUE_SIZE);
+        mFocusInteraction = focusInteraction;
+        mEnabledDelayedFocusRequest = enableDelayedFocusRequest;
     }
 
 
     // This has to happen after the construction to avoid a chicken and egg problem when setting up
     // the AudioPolicy which must depend on this object.
-    public void setOwningPolicy(CarAudioService audioService, AudioPolicy parentPolicy) {
-        mCarAudioService = audioService;
-        mAudioPolicy     = parentPolicy;
+    public void setOwningPolicy(AudioPolicy parentPolicy) {
+        mAudioPolicy = parentPolicy;
     }
 
 
     // This sends a focus loss message to the targeted requester.
-    private void sendFocusLoss(FocusEntry loser, int lossType) {
-        Log.i(TAG, "sendFocusLoss (" + focusEventToString(lossType) + ") to "
-                + loser.getClientId());
-        int result = mAudioManager.dispatchAudioFocusChange(loser.mAfi, lossType, mAudioPolicy);
+    private void sendFocusLossLocked(AudioFocusInfo loser, int lossType) {
+        int result = mAudioManager.dispatchAudioFocusChange(loser, lossType,
+                mAudioPolicy);
         if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
             // TODO:  Is this actually an error, or is it okay for an entry in the focus stack
             // to NOT have a listener?  If that's the case, should we even keep it in the focus
             // stack?
             Log.e(TAG, "Failure to signal loss of audio focus with error: " + result);
         }
+
+        logFocusEvent("sendFocusLoss for client " + loser.getClientId()
+                + " with loss type " + focusEventToString(lossType)
+                + " resulted in " + focusRequestResponseToString(result));
     }
 
 
@@ -174,7 +109,7 @@
     // If it is for the same USAGE, we replace the old request with the new one.
     // The default audio framework's behavior is to remove the previous entry in the stack (no-op
     // if the requester is already holding focus).
-    int evaluateFocusRequest(AudioFocusInfo afi) {
+    private int evaluateFocusRequestLocked(AudioFocusInfo afi) {
         Log.i(TAG, "Evaluating " + focusEventToString(afi.getGainRequest())
                 + " request for client " + afi.getClientId()
                 + " with usage " + afi.getAttributes().usageToString());
@@ -190,10 +125,10 @@
         final boolean allowDucking =
                 (afi.getGainRequest() == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
 
+        boolean delayFocusForCurrentRequest = false;
 
-        // Convert from audio attributes "usage" to HAL level "context"
-        final int requestedContext = mCarAudioService.getContextForUsage(
-                afi.getAttributes().getUsage());
+        final int requestedContext = CarAudioContext.getContextForUsage(
+                afi.getAttributes().getSystemUsage());
 
         // If we happen to find entries that this new request should replace, we'll store them here.
         // This happens when a client makes a second AF request on the same listener.
@@ -201,6 +136,26 @@
         FocusEntry replacedCurrentEntry = null;
         FocusEntry replacedBlockedEntry = null;
 
+        boolean allowDelayedFocus = mEnabledDelayedFocusRequest && canReceiveDelayedFocus(afi);
+
+        // We don't allow sharing listeners (client IDs) between two concurrent requests
+        // (because the app would have no way to know to which request a later event applied)
+        if (mDelayedRequest != null && afi.getClientId().equals(mDelayedRequest.getClientId())) {
+            int delayedRequestedContext = CarAudioContext.getContextForUsage(
+                    mDelayedRequest.getAttributes().getSystemUsage());
+            // If it is for a different context then reject
+            if (delayedRequestedContext != requestedContext) {
+                // Trivially reject a request for a different USAGE
+                Log.e(TAG, String.format(
+                        "Client %s has already delayed requested focus for %s "
+                                + "- cannot request focus for %s on same listener.",
+                        mDelayedRequest.getClientId(),
+                        mDelayedRequest.getAttributes().usageToString(),
+                        afi.getAttributes().usageToString()));
+                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+            }
+        }
+
         // Scan all active and pending focus requests.  If any should cause rejection of
         // this new request, then we're done.  Keep a list of those against whom we're exclusive
         // so we can update the relationships if/when we are sure we won't get rejected.
@@ -214,16 +169,16 @@
             // This matches the hardwired behavior in the default audio policy engine which apps
             // might expect (The interaction matrix doesn't have any provision for dealing with
             // override flags like this).
-            if ((requestedContext == ContextNumber.NOTIFICATION) &&
-                    (entry.mAfi.getGainRequest() ==
-                            AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) {
+            if ((requestedContext == CarAudioContext.NOTIFICATION)
+                    && (entry.getAudioFocusInfo().getGainRequest()
+                    == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) {
                 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
             }
 
             // We don't allow sharing listeners (client IDs) between two concurrent requests
             // (because the app would have no way to know to which request a later event applied)
-            if (afi.getClientId().equals(entry.mAfi.getClientId())) {
-                if (entry.mAudioContext == requestedContext) {
+            if (afi.getClientId().equals(entry.getAudioFocusInfo().getClientId())) {
+                if (entry.getAudioContext() == requestedContext) {
                     // This is a request from a current focus holder.
                     // Abandon the previous request (without sending a LOSS notification to it),
                     // and don't check the interaction matrix for it.
@@ -232,58 +187,43 @@
                     continue;
                 } else {
                     // Trivially reject a request for a different USAGE
-                    Log.e(TAG, "Client " + entry.getClientId() + " has already requested focus "
-                            + "for " + entry.mAfi.getAttributes().usageToString() + " - cannot "
-                            + "request focus for " + afi.getAttributes().usageToString() + " on "
-                            + "same listener.");
+                    Log.e(TAG, String.format(
+                            "Client %s has already requested focus for %s - cannot request focus "
+                                    + "for %s on same listener.",
+                            entry.getClientId(),
+                            entry.getAudioFocusInfo().getAttributes().usageToString(),
+                            afi.getAttributes().usageToString()));
                     return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
                 }
             }
 
-            // Check the interaction matrix for the relationship between this entry and the request
-            switch (sInteractionMatrix[entry.mAudioContext][requestedContext]) {
-                case INTERACTION_REJECT:
-                    // This request is rejected, so nothing further to do
-                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
-                case INTERACTION_EXCLUSIVE:
-                    // The new request will cause this existing entry to lose focus
-                    losers.add(entry);
-                    break;
-                case INTERACTION_CONCURRENT:
-                    // If ducking isn't allowed by the focus requestor, then everybody else
-                    // must get a LOSS.
-                    // If a focus holder has set the AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS flag,
-                    // they must get a LOSS message even if ducking would otherwise be allowed.
-                    // If a focus holder holds the RECEIVE_CAR_AUDIO_DUCKING_EVENTS permission,
-                    // they must receive all audio focus losses.
-                    if (!allowDucking
-                            || entry.wantsPauseInsteadOfDucking()
-                            || entry.receivesDuckEvents()) {
-                        losers.add(entry);
-                    }
-                    break;
-                default:
-                    Log.e(TAG, "Bad interaction matrix value - rejecting");
-                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+            @AudioManager.FocusRequestResult int interactionResult = mFocusInteraction
+                    .evaluateRequest(requestedContext, entry, losers, allowDucking,
+                            allowDelayedFocus);
+            if (interactionResult == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
+                return interactionResult;
+            }
+            if (interactionResult == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
+                delayFocusForCurrentRequest = true;
             }
         }
         Log.i(TAG, "Scanning those who've already lost focus...");
         final ArrayList<FocusEntry> blocked = new ArrayList<FocusEntry>();
         for (FocusEntry entry : mFocusLosers.values()) {
-            Log.i(TAG, entry.mAfi.getClientId());
+            Log.i(TAG, entry.getAudioFocusInfo().getClientId());
 
             // If this request is for Notifications and a pending focus holder has specified
             // AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE, then reject the request
-            if ((requestedContext == ContextNumber.NOTIFICATION) &&
-                    (entry.mAfi.getGainRequest() ==
-                            AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) {
+            if ((requestedContext == CarAudioContext.NOTIFICATION)
+                    && (entry.getAudioFocusInfo().getGainRequest()
+                    == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) {
                 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
             }
 
             // We don't allow sharing listeners (client IDs) between two concurrent requests
             // (because the app would have no way to know to which request a later event applied)
-            if (afi.getClientId().equals(entry.mAfi.getClientId())) {
-                if (entry.mAudioContext == requestedContext) {
+            if (afi.getClientId().equals(entry.getAudioFocusInfo().getClientId())) {
+                if (entry.getAudioContext() == requestedContext) {
                     // This is a repeat of a request that is currently blocked.
                     // Evaluate it as if it were a new request, but note that we should remove
                     // the old pending request, and move it.
@@ -293,45 +233,30 @@
                     continue;
                 } else {
                     // Trivially reject a request for a different USAGE
-                    Log.e(TAG, "Client " + entry.getClientId() + " has already requested focus "
-                            + "for " + entry.mAfi.getAttributes().usageToString() + " - cannot "
-                            + "request focus for " + afi.getAttributes().usageToString() + " on "
-                            + "same listener.");
+                    Log.e(TAG, String.format(
+                            "Client %s has already requested focus for %s - cannot request focus "
+                                    + "for %s on same listener.",
+                            entry.getClientId(),
+                            entry.getAudioFocusInfo().getAttributes().usageToString(),
+                            afi.getAttributes().usageToString()));
                     return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
                 }
             }
 
-            // Check the interaction matrix for the relationship between this entry and the request
-            switch (sInteractionMatrix[entry.mAudioContext][requestedContext]) {
-                case INTERACTION_REJECT:
-                    // Even though this entry has currently lost focus, the fact that it is
-                    // waiting to play means we'll reject this new conflicting request.
-                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
-                case INTERACTION_EXCLUSIVE:
-                    // The new request is yet another reason this entry cannot regain focus (yet)
-                    blocked.add(entry);
-                    break;
-                case INTERACTION_CONCURRENT:
-                    // If ducking is not allowed by the requester, or the pending focus holder had
-                    // set the AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS flag, or if the pending
-                    // focus holder has requested to receive all focus events, then the pending
-                    // holder must stay "lost" until this requester goes away.
-                    if (!allowDucking
-                            || entry.wantsPauseInsteadOfDucking()
-                            || entry.receivesDuckEvents()) {
-                        // The new request is yet another reason this entry cannot regain focus yet
-                        blocked.add(entry);
-                    }
-                    break;
-                default:
-                    Log.e(TAG, "Bad interaction matrix value - rejecting");
-                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+            @AudioManager.FocusRequestResult int interactionResult = mFocusInteraction
+                    .evaluateRequest(requestedContext, entry, blocked, allowDucking,
+                            allowDelayedFocus);
+            if (interactionResult == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
+                return interactionResult;
+            }
+            if (interactionResult == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
+                delayFocusForCurrentRequest = true;
             }
         }
 
 
         // Now that we've decided we'll grant focus, construct our new FocusEntry
-        FocusEntry newEntry = new FocusEntry(afi, requestedContext);
+        FocusEntry newEntry = new FocusEntry(afi, requestedContext, mPackageManager);
 
         // These entries have permanently lost focus as a result of this request, so they
         // should be removed from all blocker lists.
@@ -351,54 +276,56 @@
         // block but are already out of focus but waiting to come back
         for (FocusEntry entry : blocked) {
             // If we're out of focus it must be because somebody is blocking us
-            assert !entry.mBlockers.isEmpty();
+            assert !entry.isUnblocked();
 
             if (permanent) {
                 // This entry has now lost focus forever
-                sendFocusLoss(entry, AudioManager.AUDIOFOCUS_LOSS);
-                entry.mReceivedLossTransientCanDuck = false;
-                final FocusEntry deadEntry = mFocusLosers.remove(entry.mAfi.getClientId());
+                sendFocusLossLocked(entry.getAudioFocusInfo(), AudioManager.AUDIOFOCUS_LOSS);
+                entry.setDucked(false);
+                final FocusEntry deadEntry = mFocusLosers.remove(
+                        entry.getAudioFocusInfo().getClientId());
                 assert deadEntry != null;
                 permanentlyLost.add(entry);
             } else {
-                if (!allowDucking && entry.mReceivedLossTransientCanDuck) {
+                if (!allowDucking && entry.isDucked()) {
                     // This entry was previously allowed to duck, but can no longer do so.
                     Log.i(TAG, "Converting duckable loss to non-duckable for "
                             + entry.getClientId());
-                    sendFocusLoss(entry, AudioManager.AUDIOFOCUS_LOSS_TRANSIENT);
-                    entry.mReceivedLossTransientCanDuck = false;
+                    sendFocusLossLocked(entry.getAudioFocusInfo(),
+                            AudioManager.AUDIOFOCUS_LOSS_TRANSIENT);
+                    entry.setDucked(false);
                 }
                 // Note that this new request is yet one more reason we can't (yet) have focus
-                entry.mBlockers.add(newEntry);
+                entry.addBlocker(newEntry);
             }
         }
 
         // Notify and update any requests which are now losing focus as a result of the new request
         for (FocusEntry entry : losers) {
             // If we have focus (but are about to loose it), nobody should be blocking us yet
-            assert entry.mBlockers.isEmpty();
+            assert entry.isUnblocked();
 
             int lossType;
             if (permanent) {
                 lossType = AudioManager.AUDIOFOCUS_LOSS;
             } else if (allowDucking && entry.receivesDuckEvents()) {
                 lossType = AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK;
-                entry.mReceivedLossTransientCanDuck = true;
+                entry.setDucked(true);
             } else {
                 lossType = AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
             }
-            sendFocusLoss(entry, lossType);
+            sendFocusLossLocked(entry.getAudioFocusInfo(), lossType);
 
             // The entry no longer holds focus, so take it out of the holders list
-            mFocusHolders.remove(entry.mAfi.getClientId());
+            mFocusHolders.remove(entry.getAudioFocusInfo().getClientId());
 
             if (permanent) {
                 permanentlyLost.add(entry);
             } else {
                 // Add ourselves to the list of requests waiting to get focus back and
                 // note why we lost focus so we can tell when it's time to get it back
-                mFocusLosers.put(entry.mAfi.getClientId(), entry);
-                entry.mBlockers.add(newEntry);
+                mFocusLosers.put(entry.getAudioFocusInfo().getClientId(), entry);
+                entry.addBlocker(newEntry);
             }
         }
 
@@ -409,27 +336,54 @@
         // GAIN_TRANSIENT request from the same listener.)
         for (FocusEntry entry : permanentlyLost) {
             Log.d(TAG, "Cleaning up entry " + entry.getClientId());
-            removeFocusEntryAndRestoreUnblockedWaiters(entry);
+            removeBlockerAndRestoreUnblockedWaitersLocked(entry);
         }
 
         // Finally, add the request we're granting to the focus holders' list
+        if (delayFocusForCurrentRequest) {
+            swapDelayedAudioFocusRequestLocked(afi);
+            return AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
+        }
+
         mFocusHolders.put(afi.getClientId(), newEntry);
 
         Log.i(TAG, "AUDIOFOCUS_REQUEST_GRANTED");
         return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
     }
 
-
     @Override
-    public synchronized void onAudioFocusRequest(AudioFocusInfo afi, int requestResult) {
-        Log.i(TAG, "onAudioFocusRequest " + afi.getClientId());
-
-        int response = evaluateFocusRequest(afi);
+    public void onAudioFocusRequest(AudioFocusInfo afi, int requestResult) {
+        int response;
+        AudioPolicy policy;
+        AudioFocusInfo replacedDelayedAudioFocusInfo = null;
+        synchronized (mLock) {
+            policy = mAudioPolicy;
+            response = evaluateFocusRequestLocked(afi);
+        }
 
         // Post our reply for delivery to the original focus requester
-        mAudioManager.setFocusRequestResult(afi, response, mAudioPolicy);
+        mAudioManager.setFocusRequestResult(afi, response, policy);
+        logFocusEvent("onAudioFocusRequest for client " + afi.getClientId()
+                + " with gain type " + focusEventToString(afi.getGainRequest())
+                + " resulted in " + focusRequestResponseToString(response));
     }
 
+    private void swapDelayedAudioFocusRequestLocked(AudioFocusInfo afi) {
+        // If we are swapping to a different client then send the focus loss signal
+        if (mDelayedRequest != null
+                && !afi.getClientId().equals(mDelayedRequest.getClientId())) {
+            sendFocusLossLocked(mDelayedRequest, AudioManager.AUDIOFOCUS_LOSS);
+        }
+        mDelayedRequest = afi;
+    }
+
+    private boolean canReceiveDelayedFocus(AudioFocusInfo afi) {
+        if (afi.getGainRequest() != AudioManager.AUDIOFOCUS_GAIN) {
+            return false;
+        }
+        return (afi.getFlags() & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK)
+            == AudioManager.AUDIOFOCUS_FLAG_DELAY_OK;
+    }
 
     /**
      * @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener, AudioAttributes)
@@ -437,13 +391,22 @@
      * we don't need to watch for death notifications directly.
      * */
     @Override
-    public synchronized void onAudioFocusAbandon(AudioFocusInfo afi) {
-        Log.i(TAG, "onAudioFocusAbandon " + afi.getClientId());
+    public void onAudioFocusAbandon(AudioFocusInfo afi) {
+        logFocusEvent("onAudioFocusAbandon for client " + afi.getClientId());
+        synchronized (mLock) {
+            FocusEntry deadEntry = removeFocusEntryLocked(afi);
 
-        FocusEntry deadEntry = removeFocusEntry(afi);
+            if (deadEntry != null) {
+                removeBlockerAndRestoreUnblockedWaitersLocked(deadEntry);
+            } else {
+                removeDelayedAudioFocusRequestLocked(afi);
+            }
+        }
+    }
 
-        if (deadEntry != null) {
-            removeFocusEntryAndRestoreUnblockedWaiters(deadEntry);
+    private void removeDelayedAudioFocusRequestLocked(AudioFocusInfo afi) {
+        if (mDelayedRequest != null && afi.getClientId().equals(mDelayedRequest.getClientId())) {
+            mDelayedRequest = null;
         }
     }
 
@@ -452,7 +415,7 @@
      * @param afi Audio Focus Info to remove
      * @return Removed Focus Entry
      */
-    private FocusEntry removeFocusEntry(AudioFocusInfo afi) {
+    private FocusEntry removeFocusEntryLocked(AudioFocusInfo afi) {
         Log.i(TAG, "removeFocusEntry " + afi.getClientId());
 
         // Remove this entry from our active or pending list
@@ -476,17 +439,61 @@
         return deadEntry;
     }
 
-    private void removeFocusEntryAndRestoreUnblockedWaiters(FocusEntry deadEntry) {
+    private void removeBlockerAndRestoreUnblockedWaitersLocked(FocusEntry deadEntry) {
+        attemptToGainFocusForDelayedAudioFocusRequest();
+        removeBlockerAndRestoreUnblockedFocusLosersLocked(deadEntry);
+    }
+
+    private void attemptToGainFocusForDelayedAudioFocusRequest() {
+        if (!mEnabledDelayedFocusRequest || mDelayedRequest == null) {
+            return;
+        }
+        int delayedFocusRequestResults = evaluateFocusRequestLocked(mDelayedRequest);
+        if (delayedFocusRequestResults == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+            FocusEntry focusEntry = mFocusHolders.get(mDelayedRequest.getClientId());
+            mDelayedRequest = null;
+            if (dispatchFocusGainedLocked(focusEntry.getAudioFocusInfo())
+                    == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
+                Log.e(TAG,
+                        "Failure to signal gain of audio focus gain for "
+                                + "delayed focus clientId " + focusEntry.getClientId());
+                mFocusHolders.remove(focusEntry.getClientId());
+                removeBlockerFromBlockedFocusLosersLocked(focusEntry);
+                sendFocusLossLocked(focusEntry.getAudioFocusInfo(),
+                        AudioManager.AUDIOFOCUS_LOSS);
+                logFocusEvent("Did not gained delayed audio focus for "
+                        + focusEntry.getClientId());
+            }
+        }
+    }
+
+    /**
+     * Removes the dead entry from blocked waiters but does not send focus gain signal
+     */
+    private void removeBlockerFromBlockedFocusLosersLocked(FocusEntry deadEntry) {
+        // Remove this entry from the blocking list of any pending requests
+        Iterator<FocusEntry> it = mFocusLosers.values().iterator();
+        while (it.hasNext()) {
+            FocusEntry entry = it.next();
+            // Remove the retiring entry from all blocker lists
+            entry.removeBlocker(deadEntry);
+        }
+    }
+
+    /**
+     * Removes the dead entry from blocked waiters and sends focus gain signal
+     */
+    private void removeBlockerAndRestoreUnblockedFocusLosersLocked(FocusEntry deadEntry) {
         // Remove this entry from the blocking list of any pending requests
         Iterator<FocusEntry> it = mFocusLosers.values().iterator();
         while (it.hasNext()) {
             FocusEntry entry = it.next();
 
             // Remove the retiring entry from all blocker lists
-            entry.mBlockers.remove(deadEntry);
+            entry.removeBlocker(deadEntry);
 
             // Any entry whose blocking list becomes empty should regain focus
-            if (entry.mBlockers.isEmpty()) {
+            if (entry.isUnblocked()) {
                 Log.i(TAG, "Restoring unblocked entry " + entry.getClientId());
                 // Pull this entry out of the focus losers list
                 it.remove();
@@ -494,8 +501,7 @@
                 // Add it back into the focus holders list
                 mFocusHolders.put(entry.getClientId(), entry);
 
-                dispatchFocusGained(entry.mAfi);
-
+                dispatchFocusGainedLocked(entry.getAudioFocusInfo());
             }
         }
     }
@@ -505,7 +511,7 @@
      * @param afi Audio focus info
      * @return AudioManager.AUDIOFOCUS_REQUEST_GRANTED if focus is dispatched successfully
      */
-    private int dispatchFocusGained(AudioFocusInfo afi) {
+    private int dispatchFocusGainedLocked(AudioFocusInfo afi) {
         // Send the focus (re)gain notification
         int result = mAudioManager.dispatchAudioFocusChange(
                 afi,
@@ -517,10 +523,13 @@
             // it in the focus stack?
             Log.e(TAG, "Failure to signal gain of audio focus with error: " + result);
         }
+
+        logFocusEvent("dispatchFocusGainedLocked for client " + afi.getClientId()
+                        + " with gain type " + focusEventToString(afi.getGainRequest())
+                        + " resulted in " + focusRequestResponseToString(result));
         return result;
     }
 
-
     /**
      * Query the current list of focus loser for uid
      * @param uid uid to query current focus loser
@@ -548,10 +557,12 @@
     private ArrayList<AudioFocusInfo> getAudioFocusListForUid(int uid,
             HashMap<String, FocusEntry> mapToQuery) {
         ArrayList<AudioFocusInfo> matchingInfoList = new ArrayList<>();
-        for (String clientId : mapToQuery.keySet()) {
-            AudioFocusInfo afi = mapToQuery.get(clientId).mAfi;
-            if (afi.getClientUid() == uid) {
-                matchingInfoList.add(afi);
+        synchronized (mLock) {
+            for (String clientId : mapToQuery.keySet()) {
+                AudioFocusInfo afi = mapToQuery.get(clientId).getAudioFocusInfo();
+                if (afi.getClientUid() == uid) {
+                    matchingInfoList.add(afi);
+                }
             }
         }
         return matchingInfoList;
@@ -563,11 +574,13 @@
      * @param afi Audio Focus info to remove
      */
     void removeAudioFocusInfoAndTransientlyLoseFocus(AudioFocusInfo afi) {
-        FocusEntry deadEntry = removeFocusEntry(afi);
-
-        if (deadEntry != null) {
-            sendFocusLoss(deadEntry, AudioManager.AUDIOFOCUS_LOSS_TRANSIENT);
-            removeFocusEntryAndRestoreUnblockedWaiters(deadEntry);
+        synchronized (mLock) {
+            FocusEntry deadEntry = removeFocusEntryLocked(afi);
+            if (deadEntry != null) {
+                sendFocusLossLocked(deadEntry.getAudioFocusInfo(),
+                        AudioManager.AUDIOFOCUS_LOSS_TRANSIENT);
+                removeBlockerAndRestoreUnblockedWaitersLocked(deadEntry);
+            }
         }
     }
 
@@ -577,11 +590,14 @@
      * @return AudioManager.AUDIOFOCUS_REQUEST_GRANTED if focus is granted
      */
     int reevaluateAndRegainAudioFocus(AudioFocusInfo afi) {
-        int results = evaluateFocusRequest(afi);
-
-        if (results == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
-            return dispatchFocusGained(afi);
+        int results;
+        synchronized (mLock) {
+            results = evaluateFocusRequestLocked(afi);
+            if (results == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+                results = dispatchFocusGainedLocked(afi);
+            }
         }
+
         return results;
     }
 
@@ -590,20 +606,28 @@
      * @param indent indent to add to each line in the current stream
      * @param writer stream to write to
      */
-    public synchronized void dump(String indent, PrintWriter writer) {
-        writer.printf("%s*CarAudioFocus*\n", indent);
+    public void dump(String indent, PrintWriter writer) {
+        synchronized (mLock) {
+            writer.printf("%s*CarAudioFocus*\n", indent);
+            String innerIndent = indent + "\t";
+            String focusIndent = innerIndent + "\t";
+            mFocusInteraction.dump(innerIndent, writer);
 
-        String innerIndent = indent + "\t";
-        writer.printf("%sCurrent Focus Holders:\n", innerIndent);
-        for (String clientId : mFocusHolders.keySet()) {
-            writer.printf("%s\t%s - %s\n", innerIndent, clientId,
-                    mFocusHolders.get(clientId).getUsageName());
-        }
+            writer.printf("%sCurrent Focus Holders:\n", innerIndent);
+            for (String clientId : mFocusHolders.keySet()) {
+                mFocusHolders.get(clientId).dump(focusIndent, writer);
+            }
 
-        writer.printf("%sTransient Focus Losers:\n", innerIndent);
-        for (String clientId : mFocusLosers.keySet()) {
-            writer.printf("%s\t%s - %s\n", innerIndent, clientId,
-                    mFocusLosers.get(clientId).getUsageName());
+            writer.printf("%sTransient Focus Losers:\n", innerIndent);
+            for (String clientId : mFocusLosers.keySet()) {
+                mFocusLosers.get(clientId).dump(focusIndent, writer);
+            }
+
+            writer.printf("%sQueued Delayed Focus: %s\n", innerIndent,
+                    mDelayedRequest == null ? "None" : mDelayedRequest.getClientId());
+
+            writer.printf("%sFocus Events:\n", innerIndent);
+            mFocusEventLogger.dump(innerIndent + "\t", writer);
         }
     }
 
@@ -627,4 +651,25 @@
                 return "unknown event " + focusEvent;
         }
     }
+
+    private static String focusRequestResponseToString(int response) {
+        if (response == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+            return "REQUEST_GRANTED";
+        } else if (response == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
+            return "REQUEST_FAILED";
+        }
+        return "REQUEST_DELAYED";
+    }
+
+    private void logFocusEvent(String log) {
+        mFocusEventLogger.log(log);
+        Log.i(TAG, log);
+    }
+
+    /**
+     * Returns the focus interaction for this car focus instance.
+     */
+    public FocusInteraction getFocusInteraction() {
+        return mFocusInteraction;
+    }
 }
diff --git a/service/src/com/android/car/audio/CarAudioService.java b/service/src/com/android/car/audio/CarAudioService.java
index 147cd1e..db081eb 100644
--- a/service/src/com/android/car/audio/CarAudioService.java
+++ b/service/src/com/android/car/audio/CarAudioService.java
@@ -15,9 +15,14 @@
  */
 package com.android.car.audio;
 
+import static android.car.media.CarAudioManager.INVALID_VOLUME_GROUP_ID;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.car.Car;
+import android.car.CarOccupantZoneManager;
+import android.car.CarOccupantZoneManager.OccupantZoneConfigChangeListener;
 import android.car.media.CarAudioManager;
 import android.car.media.CarAudioPatchHandle;
 import android.car.media.ICarAudio;
@@ -27,8 +32,10 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
-import android.hardware.automotive.audiocontrol.V1_0.IAudioControl;
 import android.media.AudioAttributes;
+import android.media.AudioAttributes.AttributeSystemUsage;
+import android.media.AudioAttributes.AttributeUsage;
+import android.media.AudioDeviceAttributes;
 import android.media.AudioDeviceInfo;
 import android.media.AudioDevicePort;
 import android.media.AudioFocusInfo;
@@ -39,23 +46,27 @@
 import android.media.AudioPatch;
 import android.media.AudioPlaybackConfiguration;
 import android.media.AudioPortConfig;
-import android.media.AudioSystem;
 import android.media.audiopolicy.AudioPolicy;
 import android.os.IBinder;
 import android.os.Looper;
-import android.os.RemoteException;
-import android.provider.Settings;
+import android.os.UserHandle;
+import android.telephony.Annotation.CallState;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
-import android.util.SparseArray;
-import android.view.DisplayAddress;
+import android.util.SparseIntArray;
 import android.view.KeyEvent;
 
-import com.android.car.BinderInterfaceContainer;
+import com.android.car.CarLocalServices;
 import com.android.car.CarLog;
+import com.android.car.CarOccupantZoneService;
 import com.android.car.CarServiceBase;
 import com.android.car.R;
+import com.android.car.audio.CarAudioContext.AudioContext;
+import com.android.car.audio.hal.AudioControlFactory;
+import com.android.car.audio.hal.AudioControlWrapper;
+import com.android.car.audio.hal.AudioControlWrapperV1;
+import com.android.car.audio.hal.HalAudioFocus;
 import com.android.internal.util.Preconditions;
 
 import org.xmlpull.v1.XmlPullParserException;
@@ -70,7 +81,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.NoSuchElementException;
+import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -78,7 +89,6 @@
  * Service responsible for interaction with car's audio system.
  */
 public class CarAudioService extends ICarAudio.Stub implements CarServiceBase {
-
     // Turning this off will result in falling back to the default focus policy of Android
     // (which boils down to "grant if not in a phone call, else deny").
     // Aside from the obvious effect of ignoring the logic in CarAudioFocus, this will also
@@ -86,12 +96,12 @@
     // Search for "DUCK_VSHAPE" in PLaybackActivityMonitor.java to see where this happens.
     private static boolean sUseCarAudioFocus = true;
 
-    // Key to persist master mute state in system settings
-    private static final String VOLUME_SETTINGS_KEY_MASTER_MUTE = "android.car.MASTER_MUTE";
+    // Enable to allowed for delayed audio focus in car audio service.
+    private static final boolean ENABLE_DELAYED_AUDIO_FOCUS = true;
 
-    // The trailing slash forms a directory-liked hierarchy and
-    // allows listening for both GROUP/MEDIA and GROUP/NAVIGATION.
-    private static final String VOLUME_SETTINGS_KEY_FOR_GROUP_PREFIX = "android.car.VOLUME_GROUP/";
+    static final @AttributeUsage int DEFAULT_AUDIO_USAGE = AudioAttributes.USAGE_MEDIA;
+    static final @AudioContext int DEFAULT_AUDIO_CONTEXT = CarAudioContext.getContextForUsage(
+            CarAudioService.DEFAULT_AUDIO_USAGE);
 
     // CarAudioService reads configuration from the following paths respectively.
     // If the first one is found, all others are ignored.
@@ -101,17 +111,13 @@
             "/system/etc/car_audio_configuration.xml"
     };
 
-    /**
-     * Gets the key to persist volume for a volume group in settings
-     *
-     * @param zoneId The audio zone id
-     * @param groupId The volume group id
-     * @return Key to persist volume index for volume group in system settings
-     */
-    static String getVolumeSettingsKeyForGroup(int zoneId, int groupId) {
-        final int maskedGroupId = (zoneId << 8) + groupId;
-        return VOLUME_SETTINGS_KEY_FOR_GROUP_PREFIX + maskedGroupId;
-    }
+    private static final @AttributeSystemUsage int[] SYSTEM_USAGES = new int[] {
+            AudioAttributes.USAGE_CALL_ASSISTANT,
+            AudioAttributes.USAGE_EMERGENCY,
+            AudioAttributes.USAGE_SAFETY,
+            AudioAttributes.USAGE_VEHICLE_STATUS,
+            AudioAttributes.USAGE_ANNOUNCEMENT
+    };
 
     private final Object mImplLock = new Object();
 
@@ -120,18 +126,33 @@
     private final AudioManager mAudioManager;
     private final boolean mUseDynamicRouting;
     private final boolean mPersistMasterMuteState;
+    private final CarAudioSettings mCarAudioSettings;
+    private AudioControlWrapper mAudioControlWrapper;
+    private HalAudioFocus mHalAudioFocus;
+
+    private CarOccupantZoneService mOccupantZoneService;
+
+    private CarOccupantZoneManager mOccupantZoneManager;
 
     private final AudioPolicy.AudioPolicyVolumeCallback mAudioPolicyVolumeCallback =
             new AudioPolicy.AudioPolicyVolumeCallback() {
         @Override
         public void onVolumeAdjustment(int adjustment) {
-            final int usage = getSuggestedAudioUsage();
-            Log.v(CarLog.TAG_AUDIO,
-                    "onVolumeAdjustment: " + AudioManager.adjustToString(adjustment)
-                            + " suggested usage: " + AudioAttributes.usageToString(usage));
-            // TODO: Pass zone id into this callback.
-            final int zoneId = CarAudioManager.PRIMARY_AUDIO_ZONE;
-            final int groupId = getVolumeGroupIdForUsage(zoneId, usage);
+            int zoneId = CarAudioManager.PRIMARY_AUDIO_ZONE;
+            @AudioContext int suggestedContext = getSuggestedAudioContext();
+
+            int groupId;
+            synchronized (mImplLock) {
+                groupId = getVolumeGroupIdForAudioContextLocked(zoneId, suggestedContext);
+            }
+
+            if (Log.isLoggable(CarLog.TAG_AUDIO, Log.VERBOSE)) {
+                Log.v(CarLog.TAG_AUDIO, "onVolumeAdjustment: "
+                        + AudioManager.adjustToString(adjustment) + " suggested audio context: "
+                        + CarAudioContext.toString(suggestedContext) + " suggested volume group: "
+                        + groupId);
+            }
+
             final int currentVolume = getGroupVolume(zoneId, groupId);
             final int flags = AudioManager.FLAG_FROM_KEY | AudioManager.FLAG_SHOW_UI;
             switch (adjustment) {
@@ -162,9 +183,6 @@
         }
     };
 
-    private final BinderInterfaceContainer<ICarVolumeCallback> mVolumeCallbackContainer =
-            new BinderInterfaceContainer<>();
-
     /**
      * Simulates {@link ICarVolumeCallback} when it's running in legacy mode.
      * This receiver assumes the intent is sent to {@link CarAudioManager#PRIMARY_AUDIO_ZONE}.
@@ -193,11 +211,17 @@
     private AudioPolicy mAudioPolicy;
     private CarZonesAudioFocus mFocusHandler;
     private String mCarAudioConfigurationPath;
+    private SparseIntArray mAudioZoneIdToOccupantZoneIdMapping;
     private CarAudioZone[] mCarAudioZones;
+    private final CarVolumeCallbackHandler mCarVolumeCallbackHandler;
+    private final SparseIntArray mAudioZoneIdToUserIdMapping;
+
 
     // TODO do not store uid mapping here instead use the uid
     //  device affinity in audio policy when available
     private Map<Integer, Integer> mUidToZoneMap;
+    private OccupantZoneConfigChangeListener
+            mOccupantZoneConfigChangeListener = new CarAudioOccupantConfigChangeListener();
 
     public CarAudioService(Context context) {
         mContext = context;
@@ -207,6 +231,9 @@
         mPersistMasterMuteState = mContext.getResources().getBoolean(
                 R.bool.audioPersistMasterMuteState);
         mUidToZoneMap = new HashMap<>();
+        mCarVolumeCallbackHandler = new CarVolumeCallbackHandler();
+        mCarAudioSettings = new CarAudioSettings(mContext.getContentResolver());
+        mAudioZoneIdToUserIdMapping = new SparseIntArray();
     }
 
     /**
@@ -216,29 +243,12 @@
     @Override
     public void init() {
         synchronized (mImplLock) {
+            mOccupantZoneService = CarLocalServices.getService(CarOccupantZoneService.class);
+            Car car = new Car(mContext, /* service= */null, /* handler= */ null);
+            mOccupantZoneManager = new CarOccupantZoneManager(car, mOccupantZoneService);
             if (mUseDynamicRouting) {
-                // Enumerate all output bus device ports
-                AudioDeviceInfo[] deviceInfos = mAudioManager.getDevices(
-                        AudioManager.GET_DEVICES_OUTPUTS);
-                if (deviceInfos.length == 0) {
-                    Log.e(CarLog.TAG_AUDIO, "No output device available, ignore");
-                    return;
-                }
-                SparseArray<CarAudioDeviceInfo> busToCarAudioDeviceInfo = new SparseArray<>();
-                for (AudioDeviceInfo info : deviceInfos) {
-                    Log.v(CarLog.TAG_AUDIO, String.format("output id=%d address=%s type=%s",
-                            info.getId(), info.getAddress(), info.getType()));
-                    if (info.getType() == AudioDeviceInfo.TYPE_BUS) {
-                        final CarAudioDeviceInfo carInfo = new CarAudioDeviceInfo(info);
-                        // See also the audio_policy_configuration.xml,
-                        // the bus number should be no less than zero.
-                        if (carInfo.getBusNumber() >= 0) {
-                            busToCarAudioDeviceInfo.put(carInfo.getBusNumber(), carInfo);
-                            Log.i(CarLog.TAG_AUDIO, "Valid bus found " + carInfo);
-                        }
-                    }
-                }
-                setupDynamicRouting(busToCarAudioDeviceInfo);
+                setupDynamicRoutingLocked();
+                setupHalAudioFocusListenerLocked();
             } else {
                 Log.i(CarLog.TAG_AUDIO, "Audio dynamic routing not enabled, run in legacy mode");
                 setupLegacyVolumeChangedListener();
@@ -246,10 +256,11 @@
 
             // Restore master mute state if applicable
             if (mPersistMasterMuteState) {
-                boolean storedMasterMute = Settings.Global.getInt(mContext.getContentResolver(),
-                        VOLUME_SETTINGS_KEY_MASTER_MUTE, 0) != 0;
+                boolean storedMasterMute = mCarAudioSettings.getMasterMute();
                 setMasterMute(storedMasterMute, 0);
             }
+
+            mAudioManager.setSupportedSystemUsages(SYSTEM_USAGES);
         }
     }
 
@@ -267,7 +278,16 @@
                 mContext.unregisterReceiver(mLegacyVolumeChangedReceiver);
             }
 
-            mVolumeCallbackContainer.clear();
+            mCarVolumeCallbackHandler.release();
+
+            if (mHalAudioFocus != null) {
+                mHalAudioFocus.unregisterFocusListener();
+            }
+
+            if (mAudioControlWrapper != null) {
+                mAudioControlWrapper.unlinkToDeath();
+                mAudioControlWrapper = null;
+            }
         }
     }
 
@@ -287,15 +307,32 @@
                 zone.dump("\t", writer);
             }
             writer.println();
+            writer.println("\tUserId to Zone Mapping:");
+            for (int index = 0; index < mAudioZoneIdToUserIdMapping.size(); index++) {
+                int audioZoneId = mAudioZoneIdToUserIdMapping.keyAt(index);
+                writer.printf("\t\tUserId %d mapped to zone %d\n",
+                        mAudioZoneIdToUserIdMapping.get(audioZoneId),
+                        audioZoneId);
+            }
             writer.println("\tUID to Zone Mapping:");
             for (int callingId : mUidToZoneMap.keySet()) {
                 writer.printf("\t\tUID %d mapped to zone %d\n",
                         callingId,
                         mUidToZoneMap.get(callingId));
             }
-            //Print focus handler info
+
             writer.println();
             mFocusHandler.dump("\t", writer);
+
+            writer.println();
+            getAudioControlWrapperLocked().dump("\t", writer);
+
+            if (mHalAudioFocus != null) {
+                writer.println();
+                mHalAudioFocus.dump("\t", writer);
+            } else {
+                writer.println("\tNo HalAudioFocus instance\n");
+            }
         }
 
     }
@@ -327,14 +364,7 @@
     }
 
     private void callbackGroupVolumeChange(int zoneId, int groupId, int flags) {
-        for (BinderInterfaceContainer.BinderInterface<ICarVolumeCallback> callback :
-                mVolumeCallbackContainer.getInterfaces()) {
-            try {
-                callback.binderInterface.onGroupVolumeChanged(zoneId, groupId, flags);
-            } catch (RemoteException e) {
-                Log.e(CarLog.TAG_AUDIO, "Failed to callback onGroupVolumeChanged", e);
-            }
-        }
+        mCarVolumeCallbackHandler.onVolumeGroupChange(zoneId, groupId, flags);
     }
 
     private void setMasterMute(boolean mute, int flags) {
@@ -348,20 +378,11 @@
     }
 
     private void callbackMasterMuteChange(int zoneId, int flags) {
-        for (BinderInterfaceContainer.BinderInterface<ICarVolumeCallback> callback :
-                mVolumeCallbackContainer.getInterfaces()) {
-            try {
-                callback.binderInterface.onMasterMuteChanged(zoneId, flags);
-            } catch (RemoteException e) {
-                Log.e(CarLog.TAG_AUDIO, "Failed to callback onMasterMuteChanged", e);
-            }
-        }
+        mCarVolumeCallbackHandler.onMasterMuteChanged(zoneId, flags);
 
         // Persists master mute state if applicable
         if (mPersistMasterMuteState) {
-            Settings.Global.putInt(mContext.getContentResolver(),
-                    VOLUME_SETTINGS_KEY_MASTER_MUTE,
-                    mAudioManager.isMasterMute() ? 1 : 0);
+            mCarAudioSettings.storeMasterMute(mAudioManager.isMasterMute());
         }
     }
 
@@ -423,7 +444,7 @@
     }
 
     private CarVolumeGroup getCarVolumeGroup(int zoneId, int groupId) {
-        Preconditions.checkNotNull(mCarAudioZones);
+        Objects.requireNonNull(mCarAudioZones);
         Preconditions.checkArgumentInRange(zoneId, 0, mCarAudioZones.length - 1,
                 "zoneId out of range: " + zoneId);
         return mCarAudioZones[zoneId].getVolumeGroup(groupId);
@@ -436,34 +457,70 @@
         mContext.registerReceiver(mLegacyVolumeChangedReceiver, intentFilter);
     }
 
-    private void setupDynamicRouting(SparseArray<CarAudioDeviceInfo> busToCarAudioDeviceInfo) {
-        final AudioPolicy.Builder builder = new AudioPolicy.Builder(mContext);
-        builder.setLooper(Looper.getMainLooper());
+    private List<CarAudioDeviceInfo> generateCarAudioDeviceInfos() {
+        AudioDeviceInfo[] deviceInfos = mAudioManager.getDevices(
+                AudioManager.GET_DEVICES_OUTPUTS);
+
+        return Arrays.stream(deviceInfos)
+                .filter(info -> info.getType() == AudioDeviceInfo.TYPE_BUS)
+                .map(CarAudioDeviceInfo::new)
+                .collect(Collectors.toList());
+    }
+
+    private AudioDeviceInfo[] getAllInputDevices() {
+        return mAudioManager.getDevices(
+                AudioManager.GET_DEVICES_INPUTS);
+    }
+
+    private CarAudioZone[] loadCarAudioConfigurationLocked(
+            List<CarAudioDeviceInfo> carAudioDeviceInfos) {
+        AudioDeviceInfo[] inputDevices = getAllInputDevices();
+        try (InputStream inputStream = new FileInputStream(mCarAudioConfigurationPath)) {
+            CarAudioZonesHelper zonesHelper = new CarAudioZonesHelper(mCarAudioSettings,
+                    inputStream, carAudioDeviceInfos, inputDevices);
+            mAudioZoneIdToOccupantZoneIdMapping =
+                    zonesHelper.getCarAudioZoneIdToOccupantZoneIdMapping();
+            return zonesHelper.loadAudioZones();
+        } catch (IOException | XmlPullParserException e) {
+            throw new RuntimeException("Failed to parse audio zone configuration", e);
+        }
+    }
+
+    private CarAudioZone[] loadVolumeGroupConfigurationWithAudioControlLocked(
+            List<CarAudioDeviceInfo> carAudioDeviceInfos) {
+        AudioControlWrapper audioControlWrapper = getAudioControlWrapperLocked();
+        if (!(audioControlWrapper instanceof AudioControlWrapperV1)) {
+            throw new IllegalStateException(
+                    "Updated version of IAudioControl no longer supports CarAudioZonesHelperLegacy."
+                    + " Please provide car_audio_configuration.xml.");
+        }
+        CarAudioZonesHelperLegacy legacyHelper = new CarAudioZonesHelperLegacy(mContext,
+                R.xml.car_volume_groups, carAudioDeviceInfos,
+                (AudioControlWrapperV1) audioControlWrapper, mCarAudioSettings);
+        return legacyHelper.loadAudioZones();
+    }
+
+    private void loadCarAudioZonesLocked() {
+        List<CarAudioDeviceInfo> carAudioDeviceInfos = generateCarAudioDeviceInfos();
 
         mCarAudioConfigurationPath = getAudioConfigurationPath();
         if (mCarAudioConfigurationPath != null) {
-            try (InputStream inputStream = new FileInputStream(mCarAudioConfigurationPath)) {
-                CarAudioZonesHelper zonesHelper = new CarAudioZonesHelper(mContext, inputStream,
-                        busToCarAudioDeviceInfo);
-                mCarAudioZones = zonesHelper.loadAudioZones();
-            } catch (IOException | XmlPullParserException e) {
-                throw new RuntimeException("Failed to parse audio zone configuration", e);
-            }
+            mCarAudioZones = loadCarAudioConfigurationLocked(carAudioDeviceInfos);
         } else {
-            // In legacy mode, context -> bus mapping is done by querying IAudioControl HAL.
-            final IAudioControl audioControl = getAudioControl();
-            if (audioControl == null) {
-                throw new RuntimeException(
-                        "Dynamic routing requested but audioControl HAL not available");
-            }
-            CarAudioZonesHelperLegacy legacyHelper = new CarAudioZonesHelperLegacy(mContext,
-                    R.xml.car_volume_groups, busToCarAudioDeviceInfo, audioControl);
-            mCarAudioZones = legacyHelper.loadAudioZones();
+            mCarAudioZones = loadVolumeGroupConfigurationWithAudioControlLocked(
+                    carAudioDeviceInfos);
         }
+
+        CarAudioZonesValidator.validate(mCarAudioZones);
+    }
+
+    private void setupDynamicRoutingLocked() {
+        final AudioPolicy.Builder builder = new AudioPolicy.Builder(mContext);
+        builder.setLooper(Looper.getMainLooper());
+
+        loadCarAudioZonesLocked();
+
         for (CarAudioZone zone : mCarAudioZones) {
-            if (!zone.validateVolumeGroups()) {
-                throw new RuntimeException("Invalid volume groups configuration");
-            }
             // Ensure HAL gets our initial value
             zone.synchronizeCurrentGainIndex();
             Log.v(CarLog.TAG_AUDIO, "Processed audio zone: " + zone);
@@ -482,7 +539,8 @@
             // the framework ducking logic.
             mFocusHandler = new CarZonesAudioFocus(mAudioManager,
                     mContext.getPackageManager(),
-                    mCarAudioZones);
+                    mCarAudioZones,
+                    mCarAudioSettings, ENABLE_DELAYED_AUDIO_FOCUS);
             builder.setAudioPolicyFocusListener(mFocusHandler);
             builder.setIsAudioFocusPolicy(true);
         }
@@ -497,6 +555,34 @@
         if (r != AudioManager.SUCCESS) {
             throw new RuntimeException("registerAudioPolicy failed " + r);
         }
+
+        setupOccupantZoneInfo();
+    }
+
+    private void setupOccupantZoneInfo() {
+        CarOccupantZoneService occupantZoneService;
+        CarOccupantZoneManager occupantZoneManager;
+        SparseIntArray audioZoneIdToOccupantZoneMapping;
+        OccupantZoneConfigChangeListener listener;
+        synchronized (mImplLock) {
+            audioZoneIdToOccupantZoneMapping = mAudioZoneIdToOccupantZoneIdMapping;
+            occupantZoneService = mOccupantZoneService;
+            occupantZoneManager = mOccupantZoneManager;
+            listener = mOccupantZoneConfigChangeListener;
+        }
+        occupantZoneService.setAudioZoneIdsForOccupantZoneIds(audioZoneIdToOccupantZoneMapping);
+        occupantZoneManager.registerOccupantZoneConfigChangeListener(listener);
+    }
+
+    private void setupHalAudioFocusListenerLocked() {
+        AudioControlWrapper audioControlWrapper = getAudioControlWrapperLocked();
+        if (!audioControlWrapper.supportsHalAudioFocus()) {
+            Log.d(CarLog.TAG_AUDIO, "HalAudioFocus is not supported on this device");
+            return;
+        }
+
+        mHalAudioFocus = new HalAudioFocus(mAudioManager, mAudioControlWrapper, getAudioZoneIds());
+        mHalAudioFocus.registerFocusListener();
     }
 
     /**
@@ -514,25 +600,11 @@
         return null;
     }
 
-    /**
-     * @return Context number for a given audio usage, 0 if the given usage is unrecognized.
-     */
-    int getContextForUsage(int audioUsage) {
-        return CarAudioDynamicRouting.USAGE_TO_CONTEXT.get(audioUsage);
-    }
-
     @Override
     public void setFadeTowardFront(float value) {
         synchronized (mImplLock) {
             enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
-            final IAudioControl audioControlHal = getAudioControl();
-            if (audioControlHal != null) {
-                try {
-                    audioControlHal.setFadeTowardFront(value);
-                } catch (RemoteException e) {
-                    Log.e(CarLog.TAG_AUDIO, "setFadeTowardFront failed", e);
-                }
-            }
+            getAudioControlWrapperLocked().setFadeTowardFront(value);
         }
     }
 
@@ -540,14 +612,7 @@
     public void setBalanceTowardRight(float value) {
         synchronized (mImplLock) {
             enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
-            final IAudioControl audioControlHal = getAudioControl();
-            if (audioControlHal != null) {
-                try {
-                    audioControlHal.setBalanceTowardRight(value);
-                } catch (RemoteException e) {
-                    Log.e(CarLog.TAG_AUDIO, "setBalanceTowardRight failed", e);
-                }
-            }
+            getAudioControlWrapperLocked().setBalanceTowardRight(value);
         }
     }
 
@@ -624,11 +689,11 @@
                 break;
             }
         }
-        Preconditions.checkNotNull(sourcePortInfo,
+        Objects.requireNonNull(sourcePortInfo,
                 "Specified source is not available: " + sourceAddress);
 
         // Find the output port associated with the given carUsage
-        AudioDevicePort sinkPort = Preconditions.checkNotNull(getAudioPort(usage),
+        AudioDevicePort sinkPort = Objects.requireNonNull(getAudioPort(usage),
                 "Sink not available for usage: " + AudioAttributes.usageToString(usage));
 
         // {@link android.media.AudioPort#activeConfig()} is valid for mixer port only,
@@ -641,7 +706,7 @@
 
         // Configure the source port to match the output port except for a gain adjustment
         final CarAudioDeviceInfo helper = new CarAudioDeviceInfo(sourcePortInfo);
-        AudioGain audioGain = Preconditions.checkNotNull(helper.getAudioGain(),
+        AudioGain audioGain = Objects.requireNonNull(helper.getAudioGain(),
                 "Gain controller not available for source port");
 
         // size of gain values is 1 in MODE_JOINT
@@ -662,7 +727,7 @@
             throw new RuntimeException("createAudioPatch failed with code " + result);
         }
 
-        Preconditions.checkNotNull(patch[0],
+        Objects.requireNonNull(patch[0],
                 "createAudioPatch didn't provide expected single handle");
         Log.d(CarLog.TAG_AUDIO, "Audio patch created: " + patch[0]);
 
@@ -675,13 +740,11 @@
     }
 
     private void releaseAudioPatchLocked(CarAudioPatchHandle carPatch) {
+        Objects.requireNonNull(carPatch);
         // NOTE:  AudioPolicyService::removeNotificationClient will take care of this automatically
         //        if the client that created a patch quits.
-
-        // FIXME {@link AudioManager#listAudioPatches(ArrayList)} returns old generation of
-        // audio patches after creation
         ArrayList<AudioPatch> patches = new ArrayList<>();
-        int result = AudioSystem.listAudioPatches(patches, new int[1]);
+        int result = mAudioManager.listAudioPatches(patches);
         if (result != AudioManager.SUCCESS) {
             throw new RuntimeException("listAudioPatches failed with code " + result);
         }
@@ -719,22 +782,38 @@
     public int getVolumeGroupIdForUsage(int zoneId, @AudioAttributes.AttributeUsage int usage) {
         synchronized (mImplLock) {
             enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
-            Preconditions.checkArgumentInRange(zoneId, 0, mCarAudioZones.length - 1,
-                    "zoneId out of range: " + zoneId);
 
-            CarVolumeGroup[] groups = mCarAudioZones[zoneId].getVolumeGroups();
-            for (int i = 0; i < groups.length; i++) {
-                int[] contexts = groups[i].getContexts();
-                for (int context : contexts) {
-                    if (getContextForUsage(usage) == context) {
+            if (!mUseDynamicRouting) {
+                for (int i = 0; i < CarAudioDynamicRouting.STREAM_TYPE_USAGES.length; i++) {
+                    if (usage == CarAudioDynamicRouting.STREAM_TYPE_USAGES[i]) {
                         return i;
                     }
                 }
+
+                return INVALID_VOLUME_GROUP_ID;
             }
-            return -1;
+
+            Preconditions.checkArgumentInRange(zoneId, 0, mCarAudioZones.length - 1,
+                    "zoneId out of range: " + zoneId);
+
+            @AudioContext int audioContext = CarAudioContext.getContextForUsage(usage);
+            return getVolumeGroupIdForAudioContextLocked(zoneId, audioContext);
         }
     }
 
+    private int getVolumeGroupIdForAudioContextLocked(int zoneId, @AudioContext int audioContext) {
+        CarVolumeGroup[] groups = mCarAudioZones[zoneId].getVolumeGroups();
+        for (int i = 0; i < groups.length; i++) {
+            int[] groupAudioContexts = groups[i].getContexts();
+            for (int groupAudioContext : groupAudioContexts) {
+                if (audioContext == groupAudioContext) {
+                    return i;
+                }
+            }
+        }
+        return INVALID_VOLUME_GROUP_ID;
+    }
+
     @Override
     public @NonNull int[] getUsagesForVolumeGroupId(int zoneId, int groupId) {
         synchronized (mImplLock) {
@@ -749,9 +828,10 @@
             Set<Integer> contexts =
                     Arrays.stream(group.getContexts()).boxed().collect(Collectors.toSet());
             final List<Integer> usages = new ArrayList<>();
-            for (int i = 0; i < CarAudioDynamicRouting.USAGE_TO_CONTEXT.size(); i++) {
-                if (contexts.contains(CarAudioDynamicRouting.USAGE_TO_CONTEXT.valueAt(i))) {
-                    usages.add(CarAudioDynamicRouting.USAGE_TO_CONTEXT.keyAt(i));
+            for (@AudioContext int context : contexts) {
+                int[] usagesForContext = CarAudioContext.getUsagesForContext(context);
+                for (@AudioAttributes.AttributeUsage int usage : usagesForContext) {
+                    usages.add(usage);
                 }
             }
             return usages.stream().mapToInt(i -> i).toArray();
@@ -766,6 +846,7 @@
     @Override
     public @NonNull int[] getAudioZoneIds() {
         enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
+        requireDynamicRouting();
         synchronized (mImplLock) {
             return Arrays.stream(mCarAudioZones).mapToInt(CarAudioZone::getId).toArray();
         }
@@ -773,6 +854,8 @@
 
     /**
      * Gets the audio zone id currently mapped to uid,
+     *
+     * <p><b>Note:</b> Will use uid mapping first, followed by uid's {@userId} mapping.
      * defaults to PRIMARY_AUDIO_ZONE if no mapping exist
      *
      * @param uid The uid
@@ -781,21 +864,29 @@
     @Override
     public int getZoneIdForUid(int uid) {
         enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
+        requireDynamicRouting();
         synchronized (mImplLock) {
-            if (!mUidToZoneMap.containsKey(uid)) {
-                Log.i(CarLog.TAG_AUDIO, "getZoneIdForUid uid "
-                        + uid + " does not have a zone. Defaulting to PRIMARY_AUDIO_ZONE: "
-                        + CarAudioManager.PRIMARY_AUDIO_ZONE);
-
-                // Must be added to PRIMARY_AUDIO_ZONE otherwise
-                // audio may be routed to other devices
-                // that match the audio criterion (i.e. usage)
-                setZoneIdForUidNoCheckLocked(CarAudioManager.PRIMARY_AUDIO_ZONE, uid);
+            if (mUidToZoneMap.containsKey(uid)) {
+                return mUidToZoneMap.get(uid);
             }
-
-            return mUidToZoneMap.get(uid);
+            int userId = UserHandle.getUserId(uid);
+            return getZoneIdForUserIdLocked(userId);
         }
     }
+
+    private int getZoneIdForUserIdLocked(@UserIdInt int userId) {
+        int audioZoneId = mOccupantZoneService.getAudioZoneIdForOccupant(
+                mOccupantZoneService.getOccupantZoneIdForUserId(userId));
+        if (audioZoneId != CarAudioManager.INVALID_AUDIO_ZONE) {
+            return audioZoneId;
+        }
+        Log.w(CarLog.TAG_AUDIO,
+                "getZoneIdForUid userId " + userId
+                        + " does not have a zone. Defaulting to PRIMARY_AUDIO_ZONE:"
+                        + CarAudioManager.PRIMARY_AUDIO_ZONE);
+        return CarAudioManager.PRIMARY_AUDIO_ZONE;
+    }
+
     /**
      * Maps the audio zone id to uid
      *
@@ -806,6 +897,9 @@
     @Override
     public boolean setZoneIdForUid(int zoneId, int uid) {
         enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
+        requireDynamicRouting();
+        Preconditions.checkArgument(isAudioZoneIdValid(zoneId),
+                "Invalid audio zone id %d", zoneId);
         synchronized (mImplLock) {
             Log.i(CarLog.TAG_AUDIO, "setZoneIdForUid Calling uid "
                     + uid + " mapped to : "
@@ -857,6 +951,19 @@
         }
     }
 
+    @Override
+    public String getOutputDeviceAddressForUsage(int zoneId,
+            @AudioAttributes.AttributeUsage int usage) {
+        enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
+        requireDynamicRouting();
+        Preconditions.checkArgumentInRange(zoneId, 0, mCarAudioZones.length - 1,
+                "zoneId (" + zoneId + ")");
+        int contextForUsage = CarAudioContext.getContextForUsage(usage);
+        Preconditions.checkArgument(contextForUsage != CarAudioContext.INVALID,
+                "Invalid audio attribute usage %d", usage);
+        return mCarAudioZones[zoneId].getAddressForContext(contextForUsage);
+    }
+
     /**
      * Regain focus for the focus list passed in
      * @param afiList focus info list to regain
@@ -884,6 +991,7 @@
     @Override
     public boolean clearZoneIdForUid(int uid) {
         enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
+        requireDynamicRouting();
         synchronized (mImplLock) {
             return checkAndRemoveUidLocked(uid);
         }
@@ -934,36 +1042,11 @@
         return true;
     }
 
-    /**
-     * Gets the zone id for the display port id.
-     * @param displayPortId display port id to match
-     * @return zone id for the display port id or
-     * CarAudioManager.PRIMARY_AUDIO_ZONE if none are found
-     */
-    @Override
-    public int getZoneIdForDisplayPortId(byte displayPortId) {
-        enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
-        synchronized (mImplLock) {
-            for (int index = 0; index < mCarAudioZones.length; index++) {
-                CarAudioZone zone = mCarAudioZones[index];
-                List<DisplayAddress.Physical> displayAddresses = zone.getPhysicalDisplayAddresses();
-                if (displayAddresses.stream().anyMatch(displayAddress->
-                        displayAddress.getPort() == displayPortId)) {
-                    return index;
-                }
-            }
-
-            // Everything else defaults to primary audio zone
-            return CarAudioManager.PRIMARY_AUDIO_ZONE;
-        }
-    }
-
     @Override
     public void registerVolumeCallback(@NonNull IBinder binder) {
         synchronized (mImplLock) {
             enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
-
-            mVolumeCallbackContainer.addBinder(ICarVolumeCallback.Stub.asInterface(binder));
+            mCarVolumeCallbackHandler.registerCallback(binder);
         }
     }
 
@@ -971,11 +1054,24 @@
     public void unregisterVolumeCallback(@NonNull IBinder binder) {
         synchronized (mImplLock) {
             enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
-
-            mVolumeCallbackContainer.removeBinder(ICarVolumeCallback.Stub.asInterface(binder));
+            mCarVolumeCallbackHandler.unregisterCallback(binder);
         }
     }
 
+    @Override
+    public @NonNull List<AudioDeviceAttributes> getInputDevicesForZoneId(int zoneId) {
+        enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
+        requireDynamicRouting();
+        Preconditions.checkArgumentInRange(zoneId, 0, mCarAudioZones.length - 1,
+                "zoneId out of range: " + zoneId);
+        for (CarAudioZone zone : mCarAudioZones) {
+            if (zone.getId() == zoneId) {
+                return zone.getInputAudioDevices();
+            }
+        }
+        throw new IllegalArgumentException("zoneId does not exist" + zoneId);
+    }
+
     private void enforcePermission(String permissionName) {
         if (mContext.checkCallingOrSelfPermission(permissionName)
                 != PackageManager.PERMISSION_GRANTED) {
@@ -983,6 +1079,10 @@
         }
     }
 
+    private void requireDynamicRouting() {
+        Preconditions.checkState(mUseDynamicRouting, "Dynamic routing is required");
+    }
+
     /**
      * @return {@link AudioDevicePort} that handles the given car audio usage.
      * Multiple usages may share one {@link AudioDevicePort}
@@ -990,36 +1090,18 @@
     private @Nullable AudioDevicePort getAudioPort(@AudioAttributes.AttributeUsage int usage) {
         int zoneId = CarAudioManager.PRIMARY_AUDIO_ZONE;
         final int groupId = getVolumeGroupIdForUsage(zoneId, usage);
-        final CarVolumeGroup group = Preconditions.checkNotNull(
+        final CarVolumeGroup group = Objects.requireNonNull(
                 mCarAudioZones[zoneId].getVolumeGroup(groupId),
                 "Can not find CarVolumeGroup by usage: "
                         + AudioAttributes.usageToString(usage));
-        return group.getAudioDevicePortForContext(getContextForUsage(usage));
+        return group.getAudioDevicePortForContext(CarAudioContext.getContextForUsage(usage));
     }
 
-    /**
-     * @return The suggested {@link AudioAttributes} usage to which the volume key events apply
-     */
-    private @AudioAttributes.AttributeUsage int getSuggestedAudioUsage() {
-        int callState = mTelephonyManager.getCallState();
-        if (callState == TelephonyManager.CALL_STATE_RINGING) {
-            return AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
-        } else if (callState == TelephonyManager.CALL_STATE_OFFHOOK) {
-            return AudioAttributes.USAGE_VOICE_COMMUNICATION;
-        } else {
-            List<AudioPlaybackConfiguration> playbacks = mAudioManager
-                    .getActivePlaybackConfigurations()
-                    .stream()
-                    .filter(AudioPlaybackConfiguration::isActive)
-                    .collect(Collectors.toList());
-            if (!playbacks.isEmpty()) {
-                // Get audio usage from active playbacks if there is any, last one if multiple
-                return playbacks.get(playbacks.size() - 1).getAudioAttributes().getUsage();
-            } else {
-                // TODO(b/72695246): Otherwise, get audio usage from foreground activity/window
-                return CarAudioDynamicRouting.DEFAULT_AUDIO_USAGE;
-            }
-        }
+    private @AudioContext int getSuggestedAudioContext() {
+        @CallState int callState = mTelephonyManager.getCallState();
+        List<AudioPlaybackConfiguration> configurations =
+                mAudioManager.getActivePlaybackConfigurations();
+        return CarVolume.getSuggestedAudioContext(configurations, callState);
     }
 
     /**
@@ -1028,7 +1110,7 @@
      * @return volume group id mapped from stream type
      */
     private int getVolumeGroupIdForStreamType(int streamType) {
-        int groupId = -1;
+        int groupId = INVALID_VOLUME_GROUP_ID;
         for (int i = 0; i < CarAudioDynamicRouting.STREAM_TYPES.length; i++) {
             if (streamType == CarAudioDynamicRouting.STREAM_TYPES[i]) {
                 groupId = i;
@@ -1038,15 +1120,160 @@
         return groupId;
     }
 
-    @Nullable
-    private static IAudioControl getAudioControl() {
-        try {
-            return IAudioControl.getService();
-        } catch (RemoteException e) {
-            Log.e(CarLog.TAG_AUDIO, "Failed to get IAudioControl service", e);
-        } catch (NoSuchElementException e) {
-            Log.e(CarLog.TAG_AUDIO, "IAudioControl service not registered yet");
+    private void handleOccupantZoneUserChanged() {
+        int driverUserId = mOccupantZoneService.getDriverUserId();
+        synchronized (mImplLock) {
+            if (!isOccupantZoneMappingAvailable()) {
+                //No occupant zone to audio zone mapping, re-adjust to settings driver.
+                for (int index = 0; index < mCarAudioZones.length; index++) {
+                    CarAudioZone zone = mCarAudioZones[index];
+                    zone.updateVolumeGroupsForUser(driverUserId);
+                    mFocusHandler.updateUserForZoneId(zone.getId(), driverUserId);
+                }
+                return;
+            }
+            int occupantZoneForDriver =  getOccupantZoneIdForDriver();
+            for (int index = 0; index < mAudioZoneIdToOccupantZoneIdMapping.size(); index++) {
+                int audioZoneId = mAudioZoneIdToOccupantZoneIdMapping.keyAt(index);
+                int occupantZoneId = mAudioZoneIdToOccupantZoneIdMapping.get(audioZoneId);
+                updateUserForOccupantZoneLocked(occupantZoneId, audioZoneId, driverUserId,
+                        occupantZoneForDriver);
+            }
+        }
+    }
+
+    private boolean isOccupantZoneMappingAvailable() {
+        return mAudioZoneIdToOccupantZoneIdMapping.size() > 0;
+    }
+
+    private void updateUserForOccupantZoneLocked(int occupantZoneId, int audioZoneId,
+            @UserIdInt int driverUserId, int occupantZoneForDriver) {
+        CarAudioZone zone = getAudioZoneForZoneIdLocked(audioZoneId);
+        int userId = mOccupantZoneService.getUserForOccupant(occupantZoneId);
+        int prevUserId = getUserIdForZoneLocked(audioZoneId);
+
+        Objects.requireNonNull(zone, () ->
+                "setUserIdDeviceAffinity for userId " + userId
+                        + " in zone " + audioZoneId + " Failed, invalid zone.");
+
+        // user in occupant zone has not changed
+        if (userId == prevUserId) {
+            return;
+        }
+        // If the user has changed, be sure to remove from current routing
+        // This would be true even if the new user is UserHandle.USER_NULL,
+        // as that indicates the user has logged out.
+        removeUserIdDeviceAffinitiesLocked(prevUserId);
+
+        if (userId == UserHandle.USER_NULL) {
+            // Reset zone back to driver user id
+            resetZoneToDefaultUser(zone, driverUserId);
+            return;
+        }
+
+        // Only set user id device affinities for driver when it is the driver's occupant zone
+        if (userId != driverUserId || occupantZoneId == occupantZoneForDriver) {
+            setUserIdDeviceAffinitiesLocked(zone, userId, audioZoneId);
+            mAudioZoneIdToUserIdMapping.put(audioZoneId, userId);
+        }
+        zone.updateVolumeGroupsForUser(userId);
+        mFocusHandler.updateUserForZoneId(audioZoneId, userId);
+    }
+
+    private int getOccupantZoneIdForDriver() {
+        List<CarOccupantZoneManager.OccupantZoneInfo> occupantZoneInfos =
+                mOccupantZoneManager.getAllOccupantZones();
+        for (CarOccupantZoneManager.OccupantZoneInfo info: occupantZoneInfos) {
+            if (info.occupantType == CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER) {
+                return info.zoneId;
+            }
+        }
+        return CarOccupantZoneManager.OccupantZoneInfo.INVALID_ZONE_ID;
+    }
+
+    private void setUserIdDeviceAffinitiesLocked(CarAudioZone zone, @UserIdInt int userId,
+            int audioZoneId) {
+        if (!mAudioPolicy.setUserIdDeviceAffinity(userId, zone.getAudioDeviceInfos())) {
+            throw new IllegalStateException(String.format(
+                    "setUserIdDeviceAffinity for userId %d in zone %d Failed,"
+                            + " could not set audio routing.",
+                    userId, audioZoneId));
+        }
+    }
+
+    private void resetZoneToDefaultUser(CarAudioZone zone, @UserIdInt int driverUserId) {
+        resetCarZonesAudioFocus(zone.getId(), driverUserId);
+        zone.updateVolumeGroupsForUser(driverUserId);
+    }
+
+    private void resetCarZonesAudioFocus(int audioZoneId, @UserIdInt int driverUserId) {
+        mFocusHandler.updateUserForZoneId(audioZoneId, driverUserId);
+    }
+
+    private CarAudioZone getAudioZoneForZoneIdLocked(int audioZoneId) {
+        for (CarAudioZone zone : mCarAudioZones) {
+            if (zone.getId() == audioZoneId) {
+                return zone;
+            }
         }
         return null;
     }
+
+    private void removeUserIdDeviceAffinitiesLocked(@UserIdInt int userId) {
+        if (Log.isLoggable(CarLog.TAG_AUDIO, Log.DEBUG)) {
+            Log.d(CarLog.TAG_AUDIO,
+                    "removeUserIdDeviceAffinities(" + userId + ") Succeeded");
+        }
+        if (userId == UserHandle.USER_NULL) {
+            return;
+        }
+        if (!mAudioPolicy.removeUserIdDeviceAffinity(userId)) {
+            Log.e(CarLog.TAG_AUDIO, "removeUserIdDeviceAffinities(" + userId + ") Failed");
+            return;
+        }
+    }
+
+    private @UserIdInt int getUserIdForZoneLocked(int audioZoneId) {
+        return mAudioZoneIdToUserIdMapping.get(audioZoneId, UserHandle.USER_NULL);
+    }
+
+    private AudioControlWrapper getAudioControlWrapperLocked() {
+        if (mAudioControlWrapper == null) {
+            mAudioControlWrapper = AudioControlFactory.newAudioControl();
+            mAudioControlWrapper.linkToDeath(this::resetHalAudioFocus);
+        }
+        return mAudioControlWrapper;
+    }
+
+    private void resetHalAudioFocus() {
+        if (mHalAudioFocus != null) {
+            mHalAudioFocus.reset();
+            mHalAudioFocus.registerFocusListener();
+        }
+    }
+
+    boolean isAudioZoneIdValid(int zoneId) {
+        for (CarAudioZone zone : mCarAudioZones) {
+            if (zone.getId() == zoneId) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private class CarAudioOccupantConfigChangeListener implements OccupantZoneConfigChangeListener {
+        @Override
+        public void onOccupantZoneConfigChanged(int flags) {
+            if (Log.isLoggable(CarLog.TAG_AUDIO, Log.DEBUG)) {
+                Log.d(CarLog.TAG_AUDIO,
+                        "onOccupantZoneConfigChanged(" + flags + ")");
+            }
+            if (((flags & CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER)
+                    == CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER)
+                    || ((flags & CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_DISPLAY)
+                    == CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_DISPLAY)) {
+                handleOccupantZoneUserChanged();
+            }
+        }
+    }
 }
diff --git a/service/src/com/android/car/audio/CarAudioSettings.java b/service/src/com/android/car/audio/CarAudioSettings.java
new file mode 100644
index 0000000..ef2d5a2
--- /dev/null
+++ b/service/src/com/android/car/audio/CarAudioSettings.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.audio;
+
+import android.annotation.UserIdInt;
+import android.car.settings.CarSettings;
+import android.content.ContentResolver;
+import android.provider.Settings;
+
+import androidx.annotation.NonNull;
+
+import java.util.Objects;
+
+/**
+ * Use to save/load car volume settings
+ */
+public class CarAudioSettings {
+
+    // The trailing slash forms a directory-liked hierarchy and
+    // allows listening for both GROUP/MEDIA and GROUP/NAVIGATION.
+    private static final String VOLUME_SETTINGS_KEY_FOR_GROUP_PREFIX = "android.car.VOLUME_GROUP/";
+
+    // Key to persist master mute state in system settings
+    private static final String VOLUME_SETTINGS_KEY_MASTER_MUTE = "android.car.MASTER_MUTE";
+
+    /**
+     * Gets the key to persist volume for a volume group in settings
+     *
+     * @param zoneId The audio zone id
+     * @param groupId The volume group id
+     * @return Key to persist volume index for volume group in system settings
+     */
+    private static String getVolumeSettingsKeyForGroup(int zoneId, int groupId) {
+        final int maskedGroupId = (zoneId << 8) + groupId;
+        return VOLUME_SETTINGS_KEY_FOR_GROUP_PREFIX + maskedGroupId;
+    }
+
+    private final ContentResolver mContentResolver;
+
+    CarAudioSettings(@NonNull ContentResolver contentResolver) {
+        mContentResolver = Objects.requireNonNull(contentResolver);
+    }
+
+    int getStoredVolumeGainIndexForUser(int userId, int zoneId, int id) {
+        return Settings.System.getIntForUser(mContentResolver,
+                getVolumeSettingsKeyForGroup(zoneId, id), -1, userId);
+    }
+
+    void storeVolumeGainIndexForUser(int userId, int zoneId, int id, int gainIndex) {
+        Settings.System.putIntForUser(mContentResolver,
+                getVolumeSettingsKeyForGroup(zoneId, id),
+                gainIndex, userId);
+    }
+
+    void storeMasterMute(Boolean masterMuteValue) {
+        Settings.Global.putInt(mContentResolver,
+                VOLUME_SETTINGS_KEY_MASTER_MUTE,
+                masterMuteValue ? 1 : 0);
+    }
+
+    boolean getMasterMute() {
+        return Settings.Global.getInt(mContentResolver,
+                VOLUME_SETTINGS_KEY_MASTER_MUTE, 0) != 0;
+    }
+
+    /**
+     * Determines if for a given userId the reject navigation on call setting is enabled
+     */
+    public boolean isRejectNavigationOnCallEnabledInSettings(@UserIdInt int userId) {
+        return Settings.Secure.getIntForUser(mContentResolver,
+                CarSettings.Secure.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL,
+                /*disabled by default*/ 0, userId) == 1;
+    }
+
+    public ContentResolver getContentResolver() {
+        return mContentResolver;
+    }
+}
diff --git a/service/src/com/android/car/audio/CarAudioZone.java b/service/src/com/android/car/audio/CarAudioZone.java
index 4bdf0b7..f4a4a33 100644
--- a/service/src/com/android/car/audio/CarAudioZone.java
+++ b/service/src/com/android/car/audio/CarAudioZone.java
@@ -16,9 +16,9 @@
 package com.android.car.audio;
 
 import android.car.media.CarAudioManager;
+import android.media.AudioDeviceAttributes;
 import android.media.AudioDeviceInfo;
 import android.util.Log;
-import android.view.DisplayAddress;
 
 import com.android.car.CarLog;
 import com.android.internal.util.Preconditions;
@@ -44,13 +44,13 @@
     private final int mId;
     private final String mName;
     private final List<CarVolumeGroup> mVolumeGroups;
-    private final List<DisplayAddress.Physical> mPhysicalDisplayAddresses;
+    private List<AudioDeviceAttributes> mInputAudioDevice;
 
     CarAudioZone(int id, String name) {
         mId = id;
         mName = name;
         mVolumeGroups = new ArrayList<>();
-        mPhysicalDisplayAddresses = new ArrayList<>();
+        mInputAudioDevice = new ArrayList<>();
     }
 
     int getId() {
@@ -81,8 +81,8 @@
     List<AudioDeviceInfo> getAudioDeviceInfos() {
         final List<AudioDeviceInfo> devices = new ArrayList<>();
         for (CarVolumeGroup group : mVolumeGroups) {
-            for (int busNumber : group.getBusNumbers()) {
-                devices.add(group.getCarAudioDeviceInfoForBus(busNumber).getAudioDeviceInfo());
+            for (String address : group.getAddresses()) {
+                devices.add(group.getCarAudioDeviceInfoForAddress(address).getAudioDeviceInfo());
             }
         }
         return devices;
@@ -93,23 +93,6 @@
     }
 
     /**
-     * Associates a new display physical port with this audio zone. This can be used to
-     * identify what zone an activity should produce sound in when launching on a particular display
-     * @param physicalDisplayAddress port to associate with this zone
-     */
-    void addPhysicalDisplayAddress(DisplayAddress.Physical physicalDisplayAddress) {
-        mPhysicalDisplayAddresses.add(physicalDisplayAddress);
-    }
-
-    /**
-     * Gets list of ports for displays associated with this audio zone
-     * @return list of Physical ports for displays associated with this audio zone
-     */
-    List<DisplayAddress.Physical> getPhysicalDisplayAddresses() {
-        return mPhysicalDisplayAddresses;
-    }
-
-    /**
      * @return Snapshot of available {@link CarVolumeGroup}s in array.
      */
     CarVolumeGroup[] getVolumeGroups() {
@@ -121,43 +104,40 @@
      *
      * - One context should not appear in two groups
      * - All contexts are assigned
-     * - One bus should not appear in two groups
+     * - One device should not appear in two groups
      * - All gain controllers in the same group have same step value
      *
-     * Note that it is fine that there are buses not appear in any group, those buses may be
-     * reserved for other usages.
-     * Step value validation is done in {@link CarVolumeGroup#bind(int, int, CarAudioDeviceInfo)}
+     * Note that it is fine that there are devices which do not appear in any group. Those devices
+     * may be reserved for other purposes.
+     * Step value validation is done in {@link CarVolumeGroup#bind(int, CarAudioDeviceInfo)}
      */
     boolean validateVolumeGroups() {
         Set<Integer> contextSet = new HashSet<>();
-        Set<Integer> busNumberSet = new HashSet<>();
+        Set<String> addresses = new HashSet<>();
         for (CarVolumeGroup group : mVolumeGroups) {
             // One context should not appear in two groups
             for (int context : group.getContexts()) {
-                if (contextSet.contains(context)) {
+                if (!contextSet.add(context)) {
                     Log.e(CarLog.TAG_AUDIO, "Context appears in two groups: " + context);
                     return false;
                 }
-                contextSet.add(context);
             }
 
-            // One bus should not appear in two groups
-            for (int busNumber : group.getBusNumbers()) {
-                if (busNumberSet.contains(busNumber)) {
-                    Log.e(CarLog.TAG_AUDIO, "Bus appears in two groups: " + busNumber);
+            // One address should not appear in two groups
+            for (String address : group.getAddresses()) {
+                if (!addresses.add(address)) {
+                    Log.e(CarLog.TAG_AUDIO, "Address appears in two groups: " + address);
                     return false;
                 }
-                busNumberSet.add(busNumber);
             }
         }
 
         // All contexts are assigned
-        if (contextSet.size() != CarAudioDynamicRouting.CONTEXT_NUMBERS.length) {
+        if (contextSet.size() != CarAudioContext.CONTEXTS.length) {
             Log.e(CarLog.TAG_AUDIO, "Some contexts are not assigned to group");
-            Log.e(CarLog.TAG_AUDIO, "Assigned contexts "
-                    + Arrays.toString(contextSet.toArray(new Integer[0])));
+            Log.e(CarLog.TAG_AUDIO, "Assigned contexts " + contextSet);
             Log.e(CarLog.TAG_AUDIO,
-                    "All contexts " + Arrays.toString(CarAudioDynamicRouting.CONTEXT_NUMBERS));
+                    "All contexts " + Arrays.toString(CarAudioContext.CONTEXTS));
             return false;
         }
 
@@ -171,16 +151,52 @@
     }
 
     void dump(String indent, PrintWriter writer) {
+        String internalIndent = indent + "\t";
         writer.printf("%sCarAudioZone(%s:%d) isPrimary? %b\n", indent, mName, mId, isPrimaryZone());
-        for (DisplayAddress.Physical physical: mPhysicalDisplayAddresses) {
-            long port = (long) physical.getPort();
-            writer.printf("%sDisplayAddress.Physical(%d)\n", indent + "\t", port);
-        }
-        writer.println();
 
         for (CarVolumeGroup group : mVolumeGroups) {
-            group.dump(indent + "\t", writer);
+            group.dump(internalIndent, writer);
+        }
+
+        writer.printf("%sInput Audio Device Addresses\n", internalIndent);
+        String devicesIndent = internalIndent + "\t";
+        for (AudioDeviceAttributes audioDevice : mInputAudioDevice) {
+            writer.printf("%sDevice Address(%s)\n", devicesIndent,
+                    audioDevice.getAddress());
         }
         writer.println();
     }
+
+    String getAddressForContext(int audioContext) {
+        CarAudioContext.preconditionCheckAudioContext(audioContext);
+        String deviceAddress = null;
+        for (CarVolumeGroup volumeGroup : getVolumeGroups()) {
+            deviceAddress = volumeGroup.getAddressForContext(audioContext);
+            if (deviceAddress != null) {
+                return deviceAddress;
+            }
+        }
+        // This should not happen unless something went wrong.
+        // Device address are unique per zone and all contexts are assigned in a zone.
+        throw new IllegalStateException("Could not find output device in zone " + mId
+                + " for audio context " + audioContext);
+    }
+
+    /**
+     * Update the volume groups for the new user
+     * @param userId user id to update to
+     */
+    public void updateVolumeGroupsForUser(int userId) {
+        for (CarVolumeGroup group : mVolumeGroups) {
+            group.loadVolumesForUser(userId);
+        }
+    }
+
+    void addInputAudioDevice(AudioDeviceAttributes device) {
+        mInputAudioDevice.add(device);
+    }
+
+    List<AudioDeviceAttributes> getInputAudioDevices() {
+        return mInputAudioDevice;
+    }
 }
diff --git a/service/src/com/android/car/audio/CarAudioZonesHelper.java b/service/src/com/android/car/audio/CarAudioZonesHelper.java
index 17d9393..1a4e0ad 100644
--- a/service/src/com/android/car/audio/CarAudioZonesHelper.java
+++ b/service/src/com/android/car/audio/CarAudioZonesHelper.java
@@ -17,12 +17,13 @@
 
 import android.annotation.NonNull;
 import android.car.media.CarAudioManager;
-import android.content.Context;
-import android.hardware.automotive.audiocontrol.V1_0.ContextNumber;
-import android.util.SparseArray;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
+import android.text.TextUtils;
+import android.util.SparseIntArray;
 import android.util.Xml;
-import android.view.DisplayAddress;
 
+import com.android.car.audio.CarAudioContext.AudioContext;
 import com.android.internal.util.Preconditions;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -31,18 +32,20 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * A helper class loads all audio zones from the configuration XML file.
  */
 /* package */ class CarAudioZonesHelper {
-
     private static final String NAMESPACE = null;
     private static final String TAG_ROOT = "carAudioConfiguration";
     private static final String TAG_AUDIO_ZONES = "zones";
@@ -51,54 +54,141 @@
     private static final String TAG_VOLUME_GROUP = "group";
     private static final String TAG_AUDIO_DEVICE = "device";
     private static final String TAG_CONTEXT = "context";
-    private static final String TAG_DISPLAYS = "displays";
-    private static final String TAG_DISPLAY = "display";
     private static final String ATTR_VERSION = "version";
     private static final String ATTR_IS_PRIMARY = "isPrimary";
     private static final String ATTR_ZONE_NAME = "name";
     private static final String ATTR_DEVICE_ADDRESS = "address";
     private static final String ATTR_CONTEXT_NAME = "context";
-    private static final String ATTR_PHYSICAL_PORT = "port";
-    private static final int SUPPORTED_VERSION = 1;
+    private static final String ATTR_ZONE_ID = "audioZoneId";
+    private static final String ATTR_OCCUPANT_ZONE_ID = "occupantZoneId";
+    private static final String TAG_INPUT_DEVICES = "inputDevices";
+    private static final String TAG_INPUT_DEVICE = "inputDevice";
+    private static final int INVALID_VERSION = -1;
+    private static final int SUPPORTED_VERSION_1 = 1;
+    private static final int SUPPORTED_VERSION_2 = 2;
+    private static final SparseIntArray SUPPORTED_VERSIONS;
+
 
     private static final Map<String, Integer> CONTEXT_NAME_MAP;
 
     static {
-        CONTEXT_NAME_MAP = new HashMap<>();
-        CONTEXT_NAME_MAP.put("music", ContextNumber.MUSIC);
-        CONTEXT_NAME_MAP.put("navigation", ContextNumber.NAVIGATION);
-        CONTEXT_NAME_MAP.put("voice_command", ContextNumber.VOICE_COMMAND);
-        CONTEXT_NAME_MAP.put("call_ring", ContextNumber.CALL_RING);
-        CONTEXT_NAME_MAP.put("call", ContextNumber.CALL);
-        CONTEXT_NAME_MAP.put("alarm", ContextNumber.ALARM);
-        CONTEXT_NAME_MAP.put("notification", ContextNumber.NOTIFICATION);
-        CONTEXT_NAME_MAP.put("system_sound", ContextNumber.SYSTEM_SOUND);
+        CONTEXT_NAME_MAP = new HashMap<>(CarAudioContext.CONTEXTS.length);
+        CONTEXT_NAME_MAP.put("music", CarAudioContext.MUSIC);
+        CONTEXT_NAME_MAP.put("navigation", CarAudioContext.NAVIGATION);
+        CONTEXT_NAME_MAP.put("voice_command", CarAudioContext.VOICE_COMMAND);
+        CONTEXT_NAME_MAP.put("call_ring", CarAudioContext.CALL_RING);
+        CONTEXT_NAME_MAP.put("call", CarAudioContext.CALL);
+        CONTEXT_NAME_MAP.put("alarm", CarAudioContext.ALARM);
+        CONTEXT_NAME_MAP.put("notification", CarAudioContext.NOTIFICATION);
+        CONTEXT_NAME_MAP.put("system_sound", CarAudioContext.SYSTEM_SOUND);
+        CONTEXT_NAME_MAP.put("emergency", CarAudioContext.EMERGENCY);
+        CONTEXT_NAME_MAP.put("safety", CarAudioContext.SAFETY);
+        CONTEXT_NAME_MAP.put("vehicle_status", CarAudioContext.VEHICLE_STATUS);
+        CONTEXT_NAME_MAP.put("announcement", CarAudioContext.ANNOUNCEMENT);
+
+        SUPPORTED_VERSIONS = new SparseIntArray(2);
+        SUPPORTED_VERSIONS.put(SUPPORTED_VERSION_1, SUPPORTED_VERSION_1);
+        SUPPORTED_VERSIONS.put(SUPPORTED_VERSION_2, SUPPORTED_VERSION_2);
     }
 
-    private final Context mContext;
-    private final SparseArray<CarAudioDeviceInfo> mBusToCarAudioDeviceInfo;
+    // Same contexts as defined in android.hardware.automotive.audiocontrol.V1_0.ContextNumber
+    static final int[] LEGACY_CONTEXTS = new int[]{
+            CarAudioContext.MUSIC,
+            CarAudioContext.NAVIGATION,
+            CarAudioContext.VOICE_COMMAND,
+            CarAudioContext.CALL_RING,
+            CarAudioContext.CALL,
+            CarAudioContext.ALARM,
+            CarAudioContext.NOTIFICATION,
+            CarAudioContext.SYSTEM_SOUND
+    };
+
+    private static boolean isLegacyContext(@AudioContext int audioContext) {
+        return Arrays.binarySearch(LEGACY_CONTEXTS, audioContext) >= 0;
+    }
+
+    private static final List<Integer> NON_LEGACY_CONTEXTS = new ArrayList<>(
+            CarAudioContext.CONTEXTS.length - LEGACY_CONTEXTS.length);
+
+    static {
+        for (@AudioContext int audioContext : CarAudioContext.CONTEXTS) {
+            if (!isLegacyContext(audioContext)) {
+                NON_LEGACY_CONTEXTS.add(audioContext);
+            }
+        }
+    }
+
+    static void bindNonLegacyContexts(CarVolumeGroup group, CarAudioDeviceInfo info) {
+        for (@AudioContext int audioContext : NON_LEGACY_CONTEXTS) {
+            group.bind(audioContext, info);
+        }
+    }
+
+    private final CarAudioSettings mCarAudioSettings;
+    private final Map<String, CarAudioDeviceInfo> mAddressToCarAudioDeviceInfo;
+    private final Map<String, AudioDeviceInfo> mAddressToInputAudioDeviceInfo;
     private final InputStream mInputStream;
-    private final Set<Long> mPortIds;
+    private final SparseIntArray mZoneIdToOccupantZoneIdMapping;
+    private final Set<Integer> mAudioZoneIds;
+    private final Set<String> mInputAudioDevices;
 
     private boolean mHasPrimaryZone;
     private int mNextSecondaryZoneId;
+    private int mCurrentVersion;
 
-    CarAudioZonesHelper(Context context, @NonNull InputStream inputStream,
-            @NonNull SparseArray<CarAudioDeviceInfo> busToCarAudioDeviceInfo) {
-        mContext = context;
-        mInputStream = inputStream;
-        mBusToCarAudioDeviceInfo = busToCarAudioDeviceInfo;
-
+    /**
+     * <p><b>Note: <b/> CarAudioZonesHelper is expected to be used from a single thread. This
+     * should be the same thread that originally called new CarAudioZonesHelper.
+     */
+    CarAudioZonesHelper(@NonNull CarAudioSettings carAudioSettings,
+            @NonNull InputStream inputStream,
+            @NonNull List<CarAudioDeviceInfo> carAudioDeviceInfos,
+            @NonNull AudioDeviceInfo[] inputDeviceInfo) {
+        mCarAudioSettings = Objects.requireNonNull(carAudioSettings);
+        mInputStream = Objects.requireNonNull(inputStream);
+        Objects.requireNonNull(carAudioDeviceInfos);
+        Objects.requireNonNull(inputDeviceInfo);
+        mAddressToCarAudioDeviceInfo = CarAudioZonesHelper.generateAddressToInfoMap(
+                carAudioDeviceInfos);
+        mAddressToInputAudioDeviceInfo =
+                CarAudioZonesHelper.generateAddressToInputAudioDeviceInfoMap(inputDeviceInfo);
         mNextSecondaryZoneId = CarAudioManager.PRIMARY_AUDIO_ZONE + 1;
-        mPortIds = new HashSet<>();
+        mZoneIdToOccupantZoneIdMapping = new SparseIntArray();
+        mAudioZoneIds = new HashSet<>();
+        mInputAudioDevices = new HashSet<>();
     }
 
+    SparseIntArray getCarAudioZoneIdToOccupantZoneIdMapping() {
+        return mZoneIdToOccupantZoneIdMapping;
+    }
+
+    // TODO: refactor this method to return List<CarAudioZone>
     CarAudioZone[] loadAudioZones() throws IOException, XmlPullParserException {
         List<CarAudioZone> carAudioZones = new ArrayList<>();
         parseCarAudioZones(carAudioZones, mInputStream);
         return carAudioZones.toArray(new CarAudioZone[0]);
     }
 
+    private static Map<String, CarAudioDeviceInfo> generateAddressToInfoMap(
+            List<CarAudioDeviceInfo> carAudioDeviceInfos) {
+        return carAudioDeviceInfos.stream()
+                .filter(info -> !TextUtils.isEmpty(info.getAddress()))
+                .collect(Collectors.toMap(CarAudioDeviceInfo::getAddress, info -> info));
+    }
+
+    private static Map<String, AudioDeviceInfo> generateAddressToInputAudioDeviceInfoMap(
+            @NonNull AudioDeviceInfo[] inputAudioDeviceInfos) {
+        HashMap<String, AudioDeviceInfo> deviceAddressToInputDeviceMap =
+                new HashMap<>(inputAudioDeviceInfos.length);
+        for (int i = 0; i < inputAudioDeviceInfos.length; ++i) {
+            AudioDeviceInfo device = inputAudioDeviceInfos[i];
+            if (device.isSource()) {
+                deviceAddressToInputDeviceMap.put(device.getAddress(), device);
+            }
+        }
+        return deviceAddressToInputDeviceMap;
+    }
+
     private void parseCarAudioZones(List<CarAudioZone> carAudioZones, InputStream stream)
             throws XmlPullParserException, IOException {
         final XmlPullParser parser = Xml.newPullParser();
@@ -112,11 +202,14 @@
         // Version check
         final int versionNumber = Integer.parseInt(
                 parser.getAttributeValue(NAMESPACE, ATTR_VERSION));
-        if (versionNumber != SUPPORTED_VERSION) {
-            throw new RuntimeException("Support version:"
-                    + SUPPORTED_VERSION + " only, got version:" + versionNumber);
+
+        if (SUPPORTED_VERSIONS.get(versionNumber, INVALID_VERSION) == INVALID_VERSION) {
+            throw new IllegalArgumentException("Latest Supported version:"
+                    + SUPPORTED_VERSION_2 + " , got version:" + versionNumber);
         }
 
+        mCurrentVersion = versionNumber;
+
         // Get all zones configured under <zones> tag
         while (parser.next() != XmlPullParser.END_TAG) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
@@ -151,17 +244,16 @@
             mHasPrimaryZone = true;
         }
         final String zoneName = parser.getAttributeValue(NAMESPACE, ATTR_ZONE_NAME);
-
-        CarAudioZone zone = new CarAudioZone(
-                isPrimary ? CarAudioManager.PRIMARY_AUDIO_ZONE : getNextSecondaryZoneId(),
-                zoneName);
+        final int audioZoneId = getZoneId(isPrimary, parser);
+        parseOccupantZoneId(audioZoneId, parser);
+        final CarAudioZone zone = new CarAudioZone(audioZoneId, zoneName);
         while (parser.next() != XmlPullParser.END_TAG) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             // Expect one <volumeGroups> in one audio zone
             if (TAG_VOLUME_GROUPS.equals(parser.getName())) {
                 parseVolumeGroups(parser, zone);
-            } else if (TAG_DISPLAYS.equals(parser.getName())) {
-                parseDisplays(parser, zone);
+            } else if (TAG_INPUT_DEVICES.equals(parser.getName())) {
+                parseInputAudioDevices(parser, zone);
             } else {
                 skip(parser);
             }
@@ -169,34 +261,114 @@
         return zone;
     }
 
-    private void parseDisplays(XmlPullParser parser, CarAudioZone zone)
+    private int getZoneId(boolean isPrimary, XmlPullParser parser) {
+        String audioZoneIdString = parser.getAttributeValue(NAMESPACE, ATTR_ZONE_ID);
+        if (isVersionOne()) {
+            Preconditions.checkArgument(audioZoneIdString == null,
+                    "Invalid audio attribute %s"
+                            + ", Please update car audio configurations file "
+                            + "to version to 2 to use it.", ATTR_ZONE_ID);
+            return isPrimary ? CarAudioManager.PRIMARY_AUDIO_ZONE
+                    : getNextSecondaryZoneId();
+        }
+        // Primary zone does not need to define it
+        if (isPrimary && audioZoneIdString == null) {
+            return CarAudioManager.PRIMARY_AUDIO_ZONE;
+        }
+        Objects.requireNonNull(audioZoneIdString, () ->
+                "Requires " + ATTR_ZONE_ID + " for all audio zones.");
+        int zoneId = parsePositiveIntAttribute(ATTR_ZONE_ID, audioZoneIdString);
+        //Verify that primary zone id is PRIMARY_AUDIO_ZONE
+        if (isPrimary) {
+            Preconditions.checkArgument(zoneId == CarAudioManager.PRIMARY_AUDIO_ZONE,
+                    "Primary zone %s must be %d or it can be left empty.",
+                    ATTR_ZONE_ID, CarAudioManager.PRIMARY_AUDIO_ZONE);
+        } else {
+            Preconditions.checkArgument(zoneId != CarAudioManager.PRIMARY_AUDIO_ZONE,
+                    "%s can only be %d for primary zone.",
+                    ATTR_ZONE_ID, CarAudioManager.PRIMARY_AUDIO_ZONE);
+        }
+        validateAudioZoneIdIsUnique(zoneId);
+        return zoneId;
+    }
+
+    private void parseOccupantZoneId(int audioZoneId, XmlPullParser parser) {
+        String occupantZoneIdString = parser.getAttributeValue(NAMESPACE, ATTR_OCCUPANT_ZONE_ID);
+        if (isVersionOne()) {
+            Preconditions.checkArgument(occupantZoneIdString == null,
+                    "Invalid audio attribute %s"
+                            + ", Please update car audio configurations file "
+                            + "to version to 2 to use it.", ATTR_OCCUPANT_ZONE_ID);
+            return;
+        }
+        //Occupant id not required for all zones
+        if (occupantZoneIdString == null) {
+            return;
+        }
+        int occupantZoneId = parsePositiveIntAttribute(ATTR_OCCUPANT_ZONE_ID, occupantZoneIdString);
+        validateOccupantZoneIdIsUnique(occupantZoneId);
+        mZoneIdToOccupantZoneIdMapping.put(audioZoneId, occupantZoneId);
+    }
+
+    private int parsePositiveIntAttribute(String attribute, String integerString) {
+        try {
+            return Integer.parseUnsignedInt(integerString);
+        } catch (NumberFormatException | IndexOutOfBoundsException e) {
+            throw new IllegalArgumentException(attribute + " must be a positive integer, but was \""
+                    + integerString + "\" instead.", e);
+        }
+    }
+
+    private void parseInputAudioDevices(XmlPullParser parser, CarAudioZone zone)
             throws IOException, XmlPullParserException {
+        if (isVersionOne()) {
+            throw new IllegalStateException(
+                    TAG_INPUT_DEVICES + " are not supported in car_audio_configuration.xml version "
+                            + SUPPORTED_VERSION_1);
+        }
         while (parser.next() != XmlPullParser.END_TAG) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
-            if (TAG_DISPLAY.equals(parser.getName())) {
-                zone.addPhysicalDisplayAddress(parsePhysicalDisplayAddress(parser));
+            if (TAG_INPUT_DEVICE.equals(parser.getName())) {
+                String audioDeviceAddress =
+                        parser.getAttributeValue(NAMESPACE, ATTR_DEVICE_ADDRESS);
+                validateInputAudioDeviceAddress(audioDeviceAddress);
+                AudioDeviceInfo info = mAddressToInputAudioDeviceInfo.get(audioDeviceAddress);
+                Preconditions.checkArgument(info != null,
+                        "%s %s of %s does not exist, add input device to"
+                                + " audio_policy_configuration.xml.",
+                        ATTR_DEVICE_ADDRESS, audioDeviceAddress, TAG_INPUT_DEVICE);
+                zone.addInputAudioDevice(new AudioDeviceAttributes(info));
             }
             skip(parser);
         }
     }
 
-    private DisplayAddress.Physical parsePhysicalDisplayAddress(XmlPullParser parser) {
-        String port = parser.getAttributeValue(NAMESPACE, ATTR_PHYSICAL_PORT);
-        long portId;
-        try {
-            portId = Long.parseLong(port);
-        } catch (NumberFormatException e) {
-            throw new RuntimeException("Port " +  port + " is not a number", e);
+    private void validateInputAudioDeviceAddress(String audioDeviceAddress) {
+        Objects.requireNonNull(audioDeviceAddress, () ->
+                TAG_INPUT_DEVICE + " " + ATTR_DEVICE_ADDRESS + " attribute must be present.");
+        Preconditions.checkArgument(!audioDeviceAddress.isEmpty(),
+                "%s %s attribute can not be empty.",
+                TAG_INPUT_DEVICE, ATTR_DEVICE_ADDRESS);
+        if (mInputAudioDevices.contains(audioDeviceAddress)) {
+            throw new IllegalArgumentException(TAG_INPUT_DEVICE + " " + audioDeviceAddress
+                    + " repeats, " + TAG_INPUT_DEVICES + " can not repeat.");
         }
-        validatePortIsUnique(portId);
-        return DisplayAddress.fromPhysicalDisplayId(portId);
+        mInputAudioDevices.add(audioDeviceAddress);
     }
 
-    private void validatePortIsUnique(Long portId) {
-        if (mPortIds.contains(portId)) {
-            throw new RuntimeException("Port Id " + portId + " is already associated with a zone");
+    private void validateOccupantZoneIdIsUnique(int occupantZoneId) {
+        if (mZoneIdToOccupantZoneIdMapping.indexOfValue(occupantZoneId) > -1) {
+            throw new IllegalArgumentException(ATTR_OCCUPANT_ZONE_ID + " " + occupantZoneId
+                    + " is already associated with a zone");
         }
-        mPortIds.add(portId);
+    }
+
+    private void validateAudioZoneIdIsUnique(int audioZoneId) {
+        if (mAudioZoneIds.contains(audioZoneId)) {
+            throw new IllegalArgumentException(ATTR_ZONE_ID + " " + audioZoneId
+                    + " is already associated with a zone");
+        }
+        mAudioZoneIds.add(audioZoneId);
     }
 
     private void parseVolumeGroups(XmlPullParser parser, CarAudioZone zone)
@@ -215,13 +387,13 @@
 
     private CarVolumeGroup parseVolumeGroup(XmlPullParser parser, int zoneId, int groupId)
             throws XmlPullParserException, IOException {
-        final CarVolumeGroup group = new CarVolumeGroup(mContext, zoneId, groupId);
+        CarVolumeGroup group = new CarVolumeGroup(mCarAudioSettings, zoneId, groupId);
         while (parser.next() != XmlPullParser.END_TAG) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             if (TAG_AUDIO_DEVICE.equals(parser.getName())) {
                 String address = parser.getAttributeValue(NAMESPACE, ATTR_DEVICE_ADDRESS);
-                parseVolumeGroupContexts(parser, group,
-                        CarAudioDeviceInfo.parseDeviceAddress(address));
+                validateOutputDeviceExist(address);
+                parseVolumeGroupContexts(parser, group, address);
             } else {
                 skip(parser);
             }
@@ -229,21 +401,40 @@
         return group;
     }
 
+    private void validateOutputDeviceExist(String address) {
+        if (!mAddressToCarAudioDeviceInfo.containsKey(address)) {
+            throw new IllegalStateException(String.format(
+                    "Output device address %s does not belong to any configured output device.",
+                    address));
+        }
+    }
+
     private void parseVolumeGroupContexts(
-            XmlPullParser parser, CarVolumeGroup group, int busNumber)
+            XmlPullParser parser, CarVolumeGroup group, String address)
             throws XmlPullParserException, IOException {
         while (parser.next() != XmlPullParser.END_TAG) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             if (TAG_CONTEXT.equals(parser.getName())) {
-                group.bind(
-                        parseContextNumber(parser.getAttributeValue(NAMESPACE, ATTR_CONTEXT_NAME)),
-                        busNumber, mBusToCarAudioDeviceInfo.get(busNumber));
+                @AudioContext int carAudioContext = parseCarAudioContext(
+                        parser.getAttributeValue(NAMESPACE, ATTR_CONTEXT_NAME));
+                validateCarAudioContextSupport(carAudioContext);
+                CarAudioDeviceInfo info = mAddressToCarAudioDeviceInfo.get(address);
+                group.bind(carAudioContext, info);
+
+                // If V1, default new contexts to same device as DEFAULT_AUDIO_USAGE
+                if (isVersionOne() && carAudioContext == CarAudioService.DEFAULT_AUDIO_CONTEXT) {
+                    bindNonLegacyContexts(group, info);
+                }
             }
             // Always skip to upper level since we're at the lowest.
             skip(parser);
         }
     }
 
+    private boolean isVersionOne() {
+        return mCurrentVersion == SUPPORTED_VERSION_1;
+    }
+
     private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
         if (parser.getEventType() != XmlPullParser.START_TAG) {
             throw new IllegalStateException();
@@ -261,8 +452,17 @@
         }
     }
 
-    private int parseContextNumber(String context) {
-        return CONTEXT_NAME_MAP.getOrDefault(context.toLowerCase(), ContextNumber.INVALID);
+    private static @AudioContext int parseCarAudioContext(String context) {
+        return CONTEXT_NAME_MAP.getOrDefault(context.toLowerCase(), CarAudioContext.INVALID);
+    }
+
+    private void validateCarAudioContextSupport(@AudioContext int audioContext) {
+        if (isVersionOne() && NON_LEGACY_CONTEXTS.contains(audioContext)) {
+            throw new IllegalArgumentException(String.format(
+                    "Non-legacy audio contexts such as %s are not supported in "
+                            + "car_audio_configuration.xml version %d",
+                    CarAudioContext.toString(audioContext), SUPPORTED_VERSION_1));
+        }
     }
 
     private int getNextSecondaryZoneId() {
diff --git a/service/src/com/android/car/audio/CarAudioZonesHelperLegacy.java b/service/src/com/android/car/audio/CarAudioZonesHelperLegacy.java
index 7f11275..1b447f3 100644
--- a/service/src/com/android/car/audio/CarAudioZonesHelperLegacy.java
+++ b/service/src/com/android/car/audio/CarAudioZonesHelperLegacy.java
@@ -15,14 +15,14 @@
  */
 package com.android.car.audio;
 
+import static com.android.car.audio.CarAudioZonesHelper.LEGACY_CONTEXTS;
+
 import android.annotation.NonNull;
 import android.annotation.XmlRes;
 import android.car.media.CarAudioManager;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
-import android.hardware.automotive.audiocontrol.V1_0.IAudioControl;
-import android.os.RemoteException;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -31,12 +31,14 @@
 
 import com.android.car.CarLog;
 import com.android.car.R;
+import com.android.car.audio.hal.AudioControlWrapperV1;
 
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * A helper class loads volume groups from car_volume_groups.xml configuration into one zone.
@@ -44,34 +46,83 @@
  * @deprecated This is replaced by {@link CarAudioZonesHelper}.
  */
 @Deprecated
-/* package */ class CarAudioZonesHelperLegacy {
-
+class CarAudioZonesHelperLegacy {
     private static final String TAG_VOLUME_GROUPS = "volumeGroups";
     private static final String TAG_GROUP = "group";
     private static final String TAG_CONTEXT = "context";
 
+    private static final int NO_BUS_FOR_CONTEXT = -1;
+
     private final Context mContext;
     private final @XmlRes int mXmlConfiguration;
-    private final SparseIntArray mContextToBus;
+    private final SparseIntArray mLegacyAudioContextToBus;
     private final SparseArray<CarAudioDeviceInfo> mBusToCarAudioDeviceInfo;
+    private final CarAudioSettings mCarAudioSettings;
 
-    CarAudioZonesHelperLegacy(Context context, @XmlRes int xmlConfiguration,
-            @NonNull SparseArray<CarAudioDeviceInfo> busToCarAudioDeviceInfo,
-            @NonNull IAudioControl audioControl) {
+    CarAudioZonesHelperLegacy(@NonNull  Context context, @XmlRes int xmlConfiguration,
+            @NonNull List<CarAudioDeviceInfo> carAudioDeviceInfos,
+            @NonNull AudioControlWrapperV1 audioControlWrapper,
+            @NonNull CarAudioSettings carAudioSettings) {
+        Objects.requireNonNull(context);
+        Objects.requireNonNull(carAudioDeviceInfos);
+        Objects.requireNonNull(audioControlWrapper);
+        mCarAudioSettings = Objects.requireNonNull(carAudioSettings);
         mContext = context;
         mXmlConfiguration = xmlConfiguration;
-        mBusToCarAudioDeviceInfo = busToCarAudioDeviceInfo;
+        mBusToCarAudioDeviceInfo =
+                generateBusToCarAudioDeviceInfo(carAudioDeviceInfos);
 
-        // Initialize context => bus mapping once.
-        mContextToBus = new SparseIntArray();
-        try {
-            for (int contextNumber : CarAudioDynamicRouting.CONTEXT_NUMBERS) {
-                mContextToBus.put(contextNumber, audioControl.getBusForContext(contextNumber));
-            }
-        } catch (RemoteException e) {
-            Log.e(CarLog.TAG_AUDIO, "Failed to query IAudioControl HAL", e);
-            e.rethrowAsRuntimeException();
+        mLegacyAudioContextToBus =
+                loadBusesForLegacyContexts(audioControlWrapper);
+    }
+
+    /* Loads mapping from {@link CarAudioContext} values to bus numbers
+     * <p>Queries {@code IAudioControl#getBusForContext} for all
+     * {@code CArAudioZoneHelper.LEGACY_CONTEXTS}. Legacy
+     * contexts are those defined as part of
+     * {@code android.hardware.automotive.audiocontrol.V1_0.ContextNumber}
+     *
+     * @param audioControl wrapper for IAudioControl HAL interface.
+     * @return SparseIntArray mapping from {@link CarAudioContext} to bus number.
+     */
+    private static SparseIntArray loadBusesForLegacyContexts(
+            @NonNull AudioControlWrapperV1 audioControlWrapper) {
+        SparseIntArray contextToBus = new SparseIntArray();
+
+        for (int legacyContext : LEGACY_CONTEXTS) {
+            int bus = audioControlWrapper.getBusForContext(legacyContext);
+            validateBusNumber(legacyContext, bus);
+            contextToBus.put(legacyContext, bus);
         }
+        return contextToBus;
+    }
+
+    private static void validateBusNumber(int legacyContext, int bus) {
+        if (bus == NO_BUS_FOR_CONTEXT) {
+            throw new IllegalArgumentException(
+                    String.format("Invalid bus %d was associated with context %s", bus,
+                            CarAudioContext.toString(legacyContext)));
+        }
+    }
+
+    private static SparseArray<CarAudioDeviceInfo> generateBusToCarAudioDeviceInfo(
+            List<CarAudioDeviceInfo> carAudioDeviceInfos) {
+        SparseArray<CarAudioDeviceInfo> busToCarAudioDeviceInfo = new SparseArray<>();
+
+        for (CarAudioDeviceInfo carAudioDeviceInfo : carAudioDeviceInfos) {
+            int busNumber = parseDeviceAddress(carAudioDeviceInfo.getAddress());
+            if (busNumber >= 0) {
+                if (busToCarAudioDeviceInfo.get(busNumber) != null) {
+                    throw new IllegalArgumentException("Two addresses map to same bus number: "
+                            + carAudioDeviceInfo.getAddress()
+                            + " and "
+                            + busToCarAudioDeviceInfo.get(busNumber).getAddress());
+                }
+                busToCarAudioDeviceInfo.put(busNumber, carAudioDeviceInfo);
+            }
+        }
+
+        return busToCarAudioDeviceInfo;
     }
 
     CarAudioZone[] loadAudioZones() {
@@ -79,13 +130,21 @@
                 "Primary zone");
         for (CarVolumeGroup group : loadVolumeGroups()) {
             zone.addVolumeGroup(group);
-            // Binding audio device to volume group.
-            for (int contextNumber : group.getContexts()) {
-                int busNumber = mContextToBus.get(contextNumber);
-                group.bind(contextNumber, busNumber, mBusToCarAudioDeviceInfo.get(busNumber));
+            bindContextsForVolumeGroup(group);
+        }
+        return new CarAudioZone[]{zone};
+    }
+
+    private void bindContextsForVolumeGroup(CarVolumeGroup group) {
+        for (int legacyAudioContext : group.getContexts()) {
+            int busNumber = mLegacyAudioContextToBus.get(legacyAudioContext);
+            CarAudioDeviceInfo info = mBusToCarAudioDeviceInfo.get(busNumber);
+            group.bind(legacyAudioContext, info);
+
+            if (legacyAudioContext == CarAudioService.DEFAULT_AUDIO_CONTEXT) {
+                CarAudioZonesHelper.bindNonLegacyContexts(group, info);
             }
         }
-        return new CarAudioZone[] { zone };
     }
 
     /**
@@ -103,7 +162,8 @@
             }
 
             if (!TAG_VOLUME_GROUPS.equals(parser.getName())) {
-                throw new RuntimeException("Meta-data does not start with volumeGroups tag");
+                throw new IllegalArgumentException(
+                        "Meta-data does not start with volumeGroups tag");
             }
             int outerDepth = parser.getDepth();
             int id = 0;
@@ -141,7 +201,28 @@
             }
         }
 
-        return new CarVolumeGroup(mContext, CarAudioManager.PRIMARY_AUDIO_ZONE, id,
+        return new CarVolumeGroup(mCarAudioSettings, CarAudioManager.PRIMARY_AUDIO_ZONE, id,
                 contexts.stream().mapToInt(i -> i).filter(i -> i >= 0).toArray());
     }
+
+    /**
+     * Parse device address. Expected format is BUS%d_%s, address, usage hint
+     *
+     * @return valid address (from 0 to positive) or -1 for invalid address.
+     */
+    private static int parseDeviceAddress(String address) {
+        String[] words = address.split("_");
+        int addressParsed = -1;
+        if (words[0].toLowerCase().startsWith("bus")) {
+            try {
+                addressParsed = Integer.parseInt(words[0].substring(3));
+            } catch (NumberFormatException e) {
+                //ignore
+            }
+        }
+        if (addressParsed < 0) {
+            return -1;
+        }
+        return addressParsed;
+    }
 }
diff --git a/service/src/com/android/car/audio/CarAudioZonesValidator.java b/service/src/com/android/car/audio/CarAudioZonesValidator.java
new file mode 100644
index 0000000..1bb0234
--- /dev/null
+++ b/service/src/com/android/car/audio/CarAudioZonesValidator.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.audio;
+
+
+import java.util.HashSet;
+import java.util.Set;
+
+class CarAudioZonesValidator {
+    static void validate(CarAudioZone[] carAudioZones) {
+        validateAtLeastOneZoneDefined(carAudioZones);
+        validateVolumeGroupsForEachZone(carAudioZones);
+        validateEachAddressAppearsAtMostOnce(carAudioZones);
+    }
+
+    private static void validateAtLeastOneZoneDefined(CarAudioZone[] carAudioZones) {
+        if (carAudioZones.length == 0) {
+            throw new RuntimeException("At least one zone should be defined");
+        }
+    }
+
+    private static void validateVolumeGroupsForEachZone(CarAudioZone[] carAudioZones) {
+        for (CarAudioZone zone : carAudioZones) {
+            if (!zone.validateVolumeGroups()) {
+                throw new RuntimeException(
+                        "Invalid volume groups configuration for zone " + zone.getId());
+            }
+        }
+    }
+
+    private static void validateEachAddressAppearsAtMostOnce(CarAudioZone[] carAudioZones) {
+        Set<String> addresses = new HashSet<>();
+        for (CarAudioZone zone : carAudioZones) {
+            for (CarVolumeGroup carVolumeGroup : zone.getVolumeGroups()) {
+                for (String address : carVolumeGroup.getAddresses()) {
+                    if (!addresses.add(address)) {
+                        throw new RuntimeException("Device with address "
+                                + address + " appears in multiple volume groups or audio zones");
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/service/src/com/android/car/audio/CarVolume.java b/service/src/com/android/car/audio/CarVolume.java
new file mode 100644
index 0000000..39f2c59
--- /dev/null
+++ b/service/src/com/android/car/audio/CarVolume.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.audio;
+
+import static com.android.car.audio.CarAudioService.DEFAULT_AUDIO_CONTEXT;
+
+import android.media.AudioAttributes;
+import android.media.AudioAttributes.AttributeUsage;
+import android.media.AudioPlaybackConfiguration;
+import android.telephony.Annotation.CallState;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.util.SparseIntArray;
+
+import com.android.car.audio.CarAudioContext.AudioContext;
+
+import java.util.List;
+
+/**
+ * CarVolume is responsible for determining which audio contexts to prioritize when adjusting volume
+ */
+final class CarVolume {
+    private static final String TAG = CarVolume.class.getSimpleName();
+    private static final int CONTEXT_NOT_PRIORITIZED = -1;
+
+    private static final int[] AUDIO_CONTEXT_VOLUME_PRIORITY = {
+            CarAudioContext.NAVIGATION,
+            CarAudioContext.CALL,
+            CarAudioContext.MUSIC,
+            CarAudioContext.ANNOUNCEMENT,
+            CarAudioContext.VOICE_COMMAND,
+            CarAudioContext.CALL_RING,
+            CarAudioContext.SYSTEM_SOUND,
+            CarAudioContext.SAFETY,
+            CarAudioContext.ALARM,
+            CarAudioContext.NOTIFICATION,
+            CarAudioContext.VEHICLE_STATUS,
+            CarAudioContext.EMERGENCY,
+            // CarAudioContext.INVALID is intentionally not prioritized as it is not routed by
+            // CarAudioService and is not expected to be used.
+    };
+
+    private static final SparseIntArray VOLUME_PRIORITY_BY_AUDIO_CONTEXT = new SparseIntArray();
+
+    static {
+        for (int priority = 0; priority < AUDIO_CONTEXT_VOLUME_PRIORITY.length; priority++) {
+            VOLUME_PRIORITY_BY_AUDIO_CONTEXT.append(AUDIO_CONTEXT_VOLUME_PRIORITY[priority],
+                    priority);
+        }
+    }
+
+    /**
+     * Suggests a {@link AudioContext} that should be adjusted based on the current
+     * {@link AudioPlaybackConfiguration}s and {@link CallState}.
+     */
+    static @AudioContext int getSuggestedAudioContext(
+            List<AudioPlaybackConfiguration> configurations, @CallState int callState) {
+        int currentContext = DEFAULT_AUDIO_CONTEXT;
+        int currentPriority = AUDIO_CONTEXT_VOLUME_PRIORITY.length;
+
+        if (callState == TelephonyManager.CALL_STATE_RINGING) {
+            currentContext = CarAudioContext.CALL_RING;
+            currentPriority = VOLUME_PRIORITY_BY_AUDIO_CONTEXT.get(CarAudioContext.CALL_RING);
+        } else if (callState == TelephonyManager.CALL_STATE_OFFHOOK) {
+            currentContext = CarAudioContext.CALL;
+            currentPriority = VOLUME_PRIORITY_BY_AUDIO_CONTEXT.get(CarAudioContext.CALL);
+        }
+
+        for (AudioPlaybackConfiguration configuration : configurations) {
+            if (!configuration.isActive()) {
+                continue;
+            }
+
+            @AttributeUsage int usage = configuration.getAudioAttributes().getSystemUsage();
+            @AudioContext int context = CarAudioContext.getContextForUsage(usage);
+            int priority = VOLUME_PRIORITY_BY_AUDIO_CONTEXT.get(context, CONTEXT_NOT_PRIORITIZED);
+            if (priority == CONTEXT_NOT_PRIORITIZED) {
+                Log.w(TAG, "Usage " + AudioAttributes.usageToString(usage) + " mapped to context "
+                        + CarAudioContext.toString(context) + " which is not prioritized");
+                continue;
+            }
+
+            if (priority < currentPriority) {
+                currentContext = context;
+                currentPriority = priority;
+            }
+        }
+
+        return currentContext;
+    }
+}
diff --git a/service/src/com/android/car/audio/CarVolumeCallbackHandler.java b/service/src/com/android/car/audio/CarVolumeCallbackHandler.java
new file mode 100644
index 0000000..71cb844
--- /dev/null
+++ b/service/src/com/android/car/audio/CarVolumeCallbackHandler.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.audio;
+
+import android.car.media.ICarVolumeCallback;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import com.android.car.BinderInterfaceContainer;
+import com.android.car.CarLog;
+
+/**
+ * Manages callbacks for changes in car volume
+ */
+class CarVolumeCallbackHandler {
+    private final BinderInterfaceContainer<ICarVolumeCallback> mVolumeCallbackContainer =
+            new BinderInterfaceContainer<>();
+
+    void release() {
+        mVolumeCallbackContainer.clear();
+    }
+
+    void onVolumeGroupChange(int zoneId, int groupId, int flags) {
+        for (BinderInterfaceContainer.BinderInterface<ICarVolumeCallback> callback :
+                mVolumeCallbackContainer.getInterfaces()) {
+            try {
+                callback.binderInterface.onGroupVolumeChanged(zoneId, groupId, flags);
+            } catch (RemoteException e) {
+                Log.e(CarLog.TAG_AUDIO, "Failed to callback onGroupVolumeChanged", e);
+            }
+        }
+    }
+
+    void onMasterMuteChanged(int zoneId, int flags) {
+        for (BinderInterfaceContainer.BinderInterface<ICarVolumeCallback> callback :
+                mVolumeCallbackContainer.getInterfaces()) {
+            try {
+                callback.binderInterface.onMasterMuteChanged(zoneId, flags);
+            } catch (RemoteException e) {
+                Log.e(CarLog.TAG_AUDIO, "Failed to callback onMasterMuteChanged", e);
+            }
+        }
+    }
+
+    public void registerCallback(@NonNull IBinder binder) {
+        mVolumeCallbackContainer.addBinder(ICarVolumeCallback.Stub.asInterface(binder));
+    }
+
+    public void unregisterCallback(@NonNull IBinder binder) {
+        mVolumeCallbackContainer.removeBinder(ICarVolumeCallback.Stub.asInterface(binder));
+    }
+}
diff --git a/service/src/com/android/car/audio/CarVolumeGroup.java b/service/src/com/android/car/audio/CarVolumeGroup.java
index eb3cc4f..5244b67 100644
--- a/service/src/com/android/car/audio/CarVolumeGroup.java
+++ b/service/src/com/android/car/audio/CarVolumeGroup.java
@@ -17,21 +17,23 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.car.media.CarAudioManager;
-import android.content.ContentResolver;
 import android.content.Context;
-import android.hardware.automotive.audiocontrol.V1_0.ContextNumber;
 import android.media.AudioDevicePort;
-import android.provider.Settings;
+import android.os.UserHandle;
+import android.util.Log;
 import android.util.SparseArray;
-import android.util.SparseIntArray;
 
+import com.android.car.CarLog;
 import com.android.internal.util.Preconditions;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * A class encapsulates a volume group in car.
@@ -42,11 +44,13 @@
  */
 /* package */ final class CarVolumeGroup {
 
-    private final ContentResolver mContentResolver;
+    private CarAudioSettings mSettingsManager;
     private final int mZoneId;
     private final int mId;
-    private final SparseIntArray mContextToBus = new SparseIntArray();
-    private final SparseArray<CarAudioDeviceInfo> mBusToCarAudioDeviceInfo = new SparseArray<>();
+    private final SparseArray<String> mContextToAddress = new SparseArray<>();
+    private final Map<String, CarAudioDeviceInfo> mAddressToCarAudioDeviceInfo = new HashMap<>();
+
+    private final Object mLock = new Object();
 
     private int mDefaultGain = Integer.MIN_VALUE;
     private int mMaxGain = Integer.MIN_VALUE;
@@ -54,19 +58,19 @@
     private int mStepSize = 0;
     private int mStoredGainIndex;
     private int mCurrentGainIndex = -1;
+    private @UserIdInt int mUserId = UserHandle.USER_CURRENT;
 
     /**
      * Constructs a {@link CarVolumeGroup} instance
-     * @param context {@link Context} instance
+     * @param Settings {@link CarAudioSettings} instance
      * @param zoneId Audio zone this volume group belongs to
      * @param id ID of this volume group
      */
-    CarVolumeGroup(Context context, int zoneId, int id) {
-        mContentResolver = context.getContentResolver();
+    CarVolumeGroup(CarAudioSettings settings, int zoneId, int id) {
+        mSettingsManager = settings;
         mZoneId = zoneId;
         mId = id;
-        mStoredGainIndex = Settings.Global.getInt(mContentResolver,
-                CarAudioService.getVolumeSettingsKeyForGroup(mZoneId, mId), -1);
+        mStoredGainIndex = mSettingsManager.getStoredVolumeGainIndexForUser(mUserId, mZoneId, mId);
     }
 
     /**
@@ -78,155 +82,209 @@
      * @deprecated In favor of {@link #CarVolumeGroup(Context, int, int)}
      */
     @Deprecated
-    CarVolumeGroup(Context context, int zoneId, int id, @NonNull int[] contexts) {
-        this(context, zoneId, id);
+    CarVolumeGroup(CarAudioSettings settings, int zoneId, int id, @NonNull int[] contexts) {
+        this(settings, zoneId, id);
         // Deal with the pre-populated car audio contexts
         for (int audioContext : contexts) {
-            mContextToBus.put(audioContext, -1);
+            mContextToAddress.put(audioContext, null);
         }
     }
 
     /**
-     * @param busNumber Physical bus number for the audio device port
-     * @return {@link CarAudioDeviceInfo} associated with a given bus number
+     * @param address Physical address for the audio device
+     * @return {@link CarAudioDeviceInfo} associated with a given address
      */
-    CarAudioDeviceInfo getCarAudioDeviceInfoForBus(int busNumber) {
-        return mBusToCarAudioDeviceInfo.get(busNumber);
+    CarAudioDeviceInfo getCarAudioDeviceInfoForAddress(String address) {
+        return mAddressToCarAudioDeviceInfo.get(address);
     }
 
     /**
-     * @return Array of context numbers in this {@link CarVolumeGroup}
+     * @return Array of car audio contexts {@link CarAudioContext} in this {@link CarVolumeGroup}
      */
     int[] getContexts() {
-        final int[] contextNumbers = new int[mContextToBus.size()];
-        for (int i = 0; i < contextNumbers.length; i++) {
-            contextNumbers[i] = mContextToBus.keyAt(i);
+        final int[] carAudioContexts = new int[mContextToAddress.size()];
+        for (int i = 0; i < carAudioContexts.length; i++) {
+            carAudioContexts[i] = mContextToAddress.keyAt(i);
         }
-        return contextNumbers;
+        return carAudioContexts;
     }
 
     /**
-     * @param busNumber Physical bus number for the audio device port
-     * @return Array of context numbers assigned to a given bus number
+     * Returns the devices address for the given context
+     * or {@code null} if the context does not exist in the volume group
      */
-    int[] getContextsForBus(int busNumber) {
-        List<Integer> contextNumbers = new ArrayList<>();
-        for (int i = 0; i < mContextToBus.size(); i++) {
-            int value = mContextToBus.valueAt(i);
-            if (value == busNumber) {
-                contextNumbers.add(mContextToBus.keyAt(i));
+    @Nullable
+    String getAddressForContext(int audioContext) {
+        return mContextToAddress.get(audioContext);
+    }
+
+    /**
+     * @param address Physical address for the audio device
+     * @return Array of car audio contexts {@link CarAudioContext} assigned to a given address
+     */
+    int[] getContextsForAddress(@NonNull String address) {
+        List<Integer> carAudioContexts = new ArrayList<>();
+        for (int i = 0; i < mContextToAddress.size(); i++) {
+            String value = mContextToAddress.valueAt(i);
+            if (address.equals(value)) {
+                carAudioContexts.add(mContextToAddress.keyAt(i));
             }
         }
-        return contextNumbers.stream().mapToInt(i -> i).toArray();
+        return carAudioContexts.stream().mapToInt(i -> i).toArray();
     }
 
     /**
-     * @return Array of bus numbers in this {@link CarVolumeGroup}
+     * @return Array of addresses in this {@link CarVolumeGroup}
      */
-    int[] getBusNumbers() {
-        final int[] busNumbers = new int[mBusToCarAudioDeviceInfo.size()];
-        for (int i = 0; i < busNumbers.length; i++) {
-            busNumbers[i] = mBusToCarAudioDeviceInfo.keyAt(i);
-        }
-        return busNumbers;
+    List<String> getAddresses() {
+        return new ArrayList<>(mAddressToCarAudioDeviceInfo.keySet());
     }
 
     /**
-     * Binds the context number to physical bus number and audio device port information.
+     * Binds the context number to physical address and audio device port information.
      * Because this may change the groups min/max values, thus invalidating an index computed from
      * a gain before this call, all calls to this function must happen at startup before any
      * set/getGainIndex calls.
      *
-     * @param contextNumber Context number as defined in audio control HAL
-     * @param busNumber Physical bus number for the audio device port
-     * @param info {@link CarAudioDeviceInfo} instance relates to the physical bus
+     * @param carAudioContext Context to bind audio to {@link CarAudioContext}
+     * @param info {@link CarAudioDeviceInfo} instance relates to the physical address
      */
-    void bind(int contextNumber, int busNumber, CarAudioDeviceInfo info) {
-        if (mBusToCarAudioDeviceInfo.size() == 0) {
-            mStepSize = info.getAudioGain().stepValue();
-        } else {
-            Preconditions.checkArgument(
-                    info.getAudioGain().stepValue() == mStepSize,
-                    "Gain controls within one group must have same step value");
-        }
+    void bind(int carAudioContext, CarAudioDeviceInfo info) {
+        Preconditions.checkArgument(mContextToAddress.get(carAudioContext) == null,
+                String.format("Context %s has already been bound to %s",
+                        CarAudioContext.toString(carAudioContext),
+                        mContextToAddress.get(carAudioContext)));
 
-        mContextToBus.put(contextNumber, busNumber);
-        mBusToCarAudioDeviceInfo.put(busNumber, info);
+        synchronized (mLock) {
+            if (mAddressToCarAudioDeviceInfo.size() == 0) {
+                mStepSize = info.getStepValue();
+            } else {
+                Preconditions.checkArgument(
+                        info.getStepValue() == mStepSize,
+                        "Gain controls within one group must have same step value");
+            }
 
-        if (info.getDefaultGain() > mDefaultGain) {
-            // We're arbitrarily selecting the highest bus default gain as the group's default.
-            mDefaultGain = info.getDefaultGain();
+            mAddressToCarAudioDeviceInfo.put(info.getAddress(), info);
+            mContextToAddress.put(carAudioContext, info.getAddress());
+
+            if (info.getDefaultGain() > mDefaultGain) {
+                // We're arbitrarily selecting the highest
+                // device default gain as the group's default.
+                mDefaultGain = info.getDefaultGain();
+            }
+            if (info.getMaxGain() > mMaxGain) {
+                mMaxGain = info.getMaxGain();
+            }
+            if (info.getMinGain() < mMinGain) {
+                mMinGain = info.getMinGain();
+            }
+            updateCurrentGainIndexLocked();
         }
-        if (info.getMaxGain() > mMaxGain) {
-            mMaxGain = info.getMaxGain();
-        }
-        if (info.getMinGain() < mMinGain) {
-            mMinGain = info.getMinGain();
-        }
-        if (mStoredGainIndex < getMinGainIndex() || mStoredGainIndex > getMaxGainIndex()) {
-            // We expected to load a value from last boot, but if we didn't (perhaps this is the
-            // first boot ever?), then use the highest "default" we've seen to initialize
-            // ourselves.
-            mCurrentGainIndex = getIndexForGain(mDefaultGain);
-        } else {
-            // Just use the gain index we stored last time the gain was set (presumably during our
-            // last boot cycle).
-            mCurrentGainIndex = mStoredGainIndex;
+    }
+
+    /**
+     * Update the user with the a new user
+     * @param userId new user
+     * @note also reloads the store gain index for the user
+     */
+    private void updateUserIdLocked(@UserIdInt int userId) {
+        mUserId = userId;
+        mStoredGainIndex = getCurrentGainIndexForUserLocked();
+    }
+
+    private int getCurrentGainIndexForUserLocked() {
+        int gainIndexForUser = mSettingsManager.getStoredVolumeGainIndexForUser(mUserId, mZoneId,
+                mId);
+        Log.i(CarLog.TAG_AUDIO, "updateUserId userId " + mUserId
+                + " gainIndexForUser " + gainIndexForUser);
+        return gainIndexForUser;
+    }
+
+    /**
+     * Update the current gain index based on the stored gain index
+     */
+    private void updateCurrentGainIndexLocked() {
+        synchronized (mLock) {
+            if (mStoredGainIndex < getIndexForGainLocked(mMinGain)
+                    || mStoredGainIndex > getIndexForGainLocked(mMaxGain)) {
+                // We expected to load a value from last boot, but if we didn't (perhaps this is the
+                // first boot ever?), then use the highest "default" we've seen to initialize
+                // ourselves.
+                mCurrentGainIndex = getIndexForGainLocked(mDefaultGain);
+            } else {
+                // Just use the gain index we stored last time the gain was
+                // set (presumably during our last boot cycle).
+                mCurrentGainIndex = mStoredGainIndex;
+            }
         }
     }
 
     private int getDefaultGainIndex() {
-        return getIndexForGain(mDefaultGain);
+        synchronized (mLock) {
+            return getIndexForGainLocked(mDefaultGain);
+        }
     }
 
     int getMaxGainIndex() {
-        return getIndexForGain(mMaxGain);
+        synchronized (mLock) {
+            return getIndexForGainLocked(mMaxGain);
+        }
     }
 
     int getMinGainIndex() {
-        return getIndexForGain(mMinGain);
+        synchronized (mLock) {
+            return getIndexForGainLocked(mMinGain);
+        }
     }
 
     int getCurrentGainIndex() {
-        return mCurrentGainIndex;
+        synchronized (mLock) {
+            return mCurrentGainIndex;
+        }
     }
 
     /**
-     * Sets the gain on this group, gain will be set on all buses within same bus.
+     * Sets the gain on this group, gain will be set on all devices within volume group.
      * @param gainIndex The gain index
      */
     void setCurrentGainIndex(int gainIndex) {
-        int gainInMillibels = getGainForIndex(gainIndex);
+        synchronized (mLock) {
+            int gainInMillibels = getGainForIndexLocked(gainIndex);
+            Preconditions.checkArgument(
+                    gainInMillibels >= mMinGain && gainInMillibels <= mMaxGain,
+                    "Gain out of range ("
+                            + mMinGain + ":"
+                            + mMaxGain + ") "
+                            + gainInMillibels + "index "
+                            + gainIndex);
 
-        Preconditions.checkArgument(
-                gainInMillibels >= mMinGain && gainInMillibels <= mMaxGain,
-                "Gain out of range ("
-                        + mMinGain + ":"
-                        + mMaxGain + ") "
-                        + gainInMillibels + "index "
-                        + gainIndex);
+            for (String address : mAddressToCarAudioDeviceInfo.keySet()) {
+                CarAudioDeviceInfo info = mAddressToCarAudioDeviceInfo.get(address);
+                info.setCurrentGain(gainInMillibels);
+            }
 
-        for (int i = 0; i < mBusToCarAudioDeviceInfo.size(); i++) {
-            CarAudioDeviceInfo info = mBusToCarAudioDeviceInfo.valueAt(i);
-            info.setCurrentGain(gainInMillibels);
+            mCurrentGainIndex = gainIndex;
+
+            storeGainIndexForUserLocked(mCurrentGainIndex, mUserId);
         }
+    }
 
-        mCurrentGainIndex = gainIndex;
-        Settings.Global.putInt(mContentResolver,
-                CarAudioService.getVolumeSettingsKeyForGroup(mZoneId, mId), gainIndex);
+    private void storeGainIndexForUserLocked(int gainIndex, @UserIdInt int userId) {
+        mSettingsManager.storeVolumeGainIndexForUser(userId,
+                mZoneId, mId, gainIndex);
     }
 
     // Given a group level gain index, return the computed gain in millibells
     // TODO (randolphs) If we ever want to add index to gain curves other than lock-stepped
     // linear, this would be the place to do it.
-    private int getGainForIndex(int gainIndex) {
+    private int getGainForIndexLocked(int gainIndex) {
         return mMinGain + gainIndex * mStepSize;
     }
 
     // TODO (randolphs) if we ever went to a non-linear index to gain curve mapping, we'd need to
     // revisit this as it assumes (at the least) that getGainForIndex is reversible.  Luckily,
     // this is an internal implementation details we could factor out if/when necessary.
-    private int getIndexForGain(int gainInMillibel) {
+    private int getIndexForGainLocked(int gainInMillibel) {
         return (gainInMillibel - mMinGain) / mStepSize;
     }
 
@@ -234,12 +292,13 @@
      * Gets {@link AudioDevicePort} from a context number
      */
     @Nullable
-    AudioDevicePort getAudioDevicePortForContext(int contextNumber) {
-        final int busNumber = mContextToBus.get(contextNumber, -1);
-        if (busNumber < 0 || mBusToCarAudioDeviceInfo.get(busNumber) == null) {
+    AudioDevicePort getAudioDevicePortForContext(int carAudioContext) {
+        final String address = mContextToAddress.get(carAudioContext);
+        if (address == null || mAddressToCarAudioDeviceInfo.get(address) == null) {
             return null;
         }
-        return mBusToCarAudioDeviceInfo.get(busNumber).getAudioDevicePort();
+
+        return mAddressToCarAudioDeviceInfo.get(address).getAudioDevicePort();
     }
 
     @Override
@@ -247,26 +306,46 @@
         return "CarVolumeGroup id: " + mId
                 + " currentGainIndex: " + mCurrentGainIndex
                 + " contexts: " + Arrays.toString(getContexts())
-                + " buses: " + Arrays.toString(getBusNumbers());
+                + " addresses: " + String.join(", ", getAddresses());
     }
 
     /** Writes to dumpsys output */
     void dump(String indent, PrintWriter writer) {
-        writer.printf("%sCarVolumeGroup(%d)\n", indent, mId);
-        writer.printf("%sGain values (min / max / default/ current): %d %d %d %d\n",
-                indent, mMinGain, mMaxGain,
-                mDefaultGain, getGainForIndex(mCurrentGainIndex));
-        writer.printf("%sGain indexes (min / max / default / current): %d %d %d %d\n",
-                indent, getMinGainIndex(), getMaxGainIndex(),
-                getDefaultGainIndex(), mCurrentGainIndex);
-        for (int i = 0; i < mContextToBus.size(); i++) {
-            writer.printf("%sContext: %s -> Bus: %d\n", indent,
-                    ContextNumber.toString(mContextToBus.keyAt(i)), mContextToBus.valueAt(i));
+        synchronized (mLock) {
+            writer.printf("%sCarVolumeGroup(%d)\n", indent, mId);
+            writer.printf("%sUserId(%d)\n", indent, mUserId);
+            writer.printf("%sGain values (min / max / default/ current): %d %d %d %d\n",
+                    indent, mMinGain, mMaxGain,
+                    mDefaultGain, getGainForIndexLocked(mCurrentGainIndex));
+            writer.printf("%sGain indexes (min / max / default / current): %d %d %d %d\n",
+                    indent, getMinGainIndex(), getMaxGainIndex(),
+                    getDefaultGainIndex(), mCurrentGainIndex);
+            for (int i = 0; i < mContextToAddress.size(); i++) {
+                writer.printf("%sContext: %s -> Address: %s\n", indent,
+                        CarAudioContext.toString(mContextToAddress.keyAt(i)),
+                        mContextToAddress.valueAt(i));
+            }
+            mAddressToCarAudioDeviceInfo.keySet().stream()
+                    .map(mAddressToCarAudioDeviceInfo::get)
+                    .forEach((info -> info.dump(indent, writer)));
+
+            // Empty line for comfortable reading
+            writer.println();
         }
-        for (int i = 0; i < mBusToCarAudioDeviceInfo.size(); i++) {
-            mBusToCarAudioDeviceInfo.valueAt(i).dump(indent, writer);
+    }
+
+    /**
+     * Load volumes for new user
+     * @param userId new user to load
+     */
+    void loadVolumesForUser(@UserIdInt int userId) {
+        synchronized (mLock) {
+            //Update the volume for the new user
+            updateUserIdLocked(userId);
+            //Update the current gain index
+            updateCurrentGainIndexLocked();
+            //Reset devices with current gain index
         }
-        // Empty line for comfortable reading
-        writer.println();
+        setCurrentGainIndex(getCurrentGainIndex());
     }
 }
diff --git a/service/src/com/android/car/audio/CarZonesAudioFocus.java b/service/src/com/android/car/audio/CarZonesAudioFocus.java
index a7441ba..ec024be 100644
--- a/service/src/com/android/car/audio/CarZonesAudioFocus.java
+++ b/service/src/com/android/car/audio/CarZonesAudioFocus.java
@@ -17,6 +17,7 @@
 package com.android.car.audio;
 
 import android.annotation.NonNull;
+import android.annotation.UserIdInt;
 import android.car.media.CarAudioManager;
 import android.content.pm.PackageManager;
 import android.media.AudioAttributes;
@@ -33,36 +34,48 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * Implements {@link AudioPolicy.AudioPolicyFocusListener}
  *
- * @note Manages audio focus on a per zone basis.
+ * <p><b>Note:</b> Manages audio focus on a per zone basis.
  */
 class CarZonesAudioFocus extends AudioPolicy.AudioPolicyFocusListener {
 
+    private final boolean mDelayedFocusEnabled;
     private CarAudioService mCarAudioService; // Dynamically assigned just after construction
     private AudioPolicy mAudioPolicy; // Dynamically assigned just after construction
 
     private final Map<Integer, CarAudioFocus> mFocusZones = new HashMap<>();
 
-    CarZonesAudioFocus(AudioManager audioManager,
-            PackageManager packageManager,
-            @NonNull CarAudioZone[] carAudioZones) {
+    CarZonesAudioFocus(@NonNull AudioManager audioManager,
+            @NonNull PackageManager packageManager,
+            @NonNull CarAudioZone[] carAudioZones,
+            @NonNull CarAudioSettings carAudioSettings,
+            boolean enableDelayedAudioFocus) {
         //Create the zones here, the policy will be set setOwningPolicy,
         // which is called right after this constructor.
-
-        Preconditions.checkNotNull(carAudioZones);
+        Objects.requireNonNull(audioManager);
+        Objects.requireNonNull(packageManager);
+        Objects.requireNonNull(carAudioZones);
+        Objects.requireNonNull(carAudioSettings);
         Preconditions.checkArgument(carAudioZones.length != 0,
                 "There must be a minimum of one audio zone");
 
         //Create focus for all the zones
         for (CarAudioZone audioZone : carAudioZones) {
-            Log.d(CarLog.TAG_AUDIO,
-                    "CarZonesAudioFocus adding new zone " + audioZone.getId());
-            CarAudioFocus zoneFocusListener = new CarAudioFocus(audioManager, packageManager);
-            mFocusZones.put(audioZone.getId(), zoneFocusListener);
+            int audioZoneId = audioZone.getId();
+            if (Log.isLoggable(CarLog.TAG_AUDIO, Log.DEBUG)) {
+                Log.d(CarLog.TAG_AUDIO,
+                        "CarZonesAudioFocus adding new zone " + audioZoneId);
+            }
+            CarAudioFocus zoneFocusListener =
+                    new CarAudioFocus(audioManager, packageManager,
+                            new FocusInteraction(carAudioSettings), enableDelayedAudioFocus);
+            mFocusZones.put(audioZoneId, zoneFocusListener);
         }
+        mDelayedFocusEnabled = enableDelayedAudioFocus;
     }
 
 
@@ -111,17 +124,18 @@
     /**
      * Sets the owning policy of the audio focus
      *
-     * @param audioService owning car audio service
-     * @param parentPolicy owning parent car audio policy
-     * @Note This has to happen after the construction to avoid a chicken and egg
+     * <p><b>Note:</b> This has to happen after the construction to avoid a chicken and egg
      * problem when setting up the AudioPolicy which must depend on this object.
+
+     * @param carAudioService owning car audio service
+     * @param parentPolicy owning parent car audio policy
      */
-    void setOwningPolicy(CarAudioService audioService, AudioPolicy parentPolicy) {
-        mCarAudioService = audioService;
+    void setOwningPolicy(CarAudioService carAudioService, AudioPolicy parentPolicy) {
         mAudioPolicy = parentPolicy;
+        mCarAudioService = carAudioService;
 
         for (int zoneId : mFocusZones.keySet()) {
-            mFocusZones.get(zoneId).setOwningPolicy(mCarAudioService, mAudioPolicy);
+            mFocusZones.get(zoneId).setOwningPolicy(mAudioPolicy);
         }
     }
 
@@ -157,9 +171,18 @@
                     bundle.getInt(CarAudioManager.AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID,
                             -1);
             // check if the zone id is within current zones bounds
-            if ((bundleZoneId >= 0)
-                    && (bundleZoneId < mCarAudioService.getAudioZoneIds().length)) {
+            if (mCarAudioService.isAudioZoneIdValid(bundleZoneId)) {
+                if (Log.isLoggable(CarLog.TAG_AUDIO, Log.DEBUG)) {
+                    Log.d(CarLog.TAG_AUDIO,
+                            "getFocusForAudioFocusInfo valid zoneId " + bundleZoneId
+                                    + " with bundle request for client " + afi.getClientId());
+                }
                 zoneId = bundleZoneId;
+            } else {
+                Log.w(CarLog.TAG_AUDIO,
+                        "getFocusForAudioFocusInfo invalid zoneId " + bundleZoneId
+                                + " with bundle request for client " + afi.getClientId()
+                                + ", dispatching focus request to zoneId " + zoneId);
             }
         }
 
@@ -173,14 +196,20 @@
      * @param indent indent to append to each new line
      * @param writer stream to write current state
      */
-    synchronized void dump(String indent, PrintWriter writer) {
+    void dump(String indent, PrintWriter writer) {
         writer.printf("%s*CarZonesAudioFocus*\n", indent);
-
+        writer.printf("%s\tDelayed Focus Enabled: %b\n", indent, mDelayedFocusEnabled);
         writer.printf("%s\tCar Zones Audio Focus Listeners:\n", indent);
         Integer[] keys = mFocusZones.keySet().stream().sorted().toArray(Integer[]::new);
         for (Integer zoneId : keys) {
-            writer.printf("%s\tZone Id: %s", indent, zoneId.toString());
+            writer.printf("%s\tZone Id: %s\n", indent, zoneId.toString());
             mFocusZones.get(zoneId).dump(indent + "\t", writer);
         }
     }
+
+    public void updateUserForZoneId(int audioZoneId, @UserIdInt int userId) {
+        Preconditions.checkArgument(mCarAudioService.isAudioZoneIdValid(audioZoneId),
+                "Invalid zoneId %d", audioZoneId);
+        mFocusZones.get(audioZoneId).getFocusInteraction().setUserIdForSettings(userId);
+    }
 }
diff --git a/service/src/com/android/car/audio/FocusEntry.java b/service/src/com/android/car/audio/FocusEntry.java
new file mode 100644
index 0000000..ec9b8c5
--- /dev/null
+++ b/service/src/com/android/car/audio/FocusEntry.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.audio;
+
+import android.car.Car;
+import android.car.media.CarAudioManager;
+import android.content.pm.PackageManager;
+import android.media.AudioFocusInfo;
+import android.media.AudioManager;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+
+import com.android.car.audio.CarAudioContext.AudioContext;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+final class FocusEntry {
+    private final AudioFocusInfo mAudioFocusInfo;
+    private final int mAudioContext;
+
+    private final List<FocusEntry> mBlockers;
+    private final PackageManager mPackageManager;
+    private boolean mIsDucked;
+
+    FocusEntry(@NonNull AudioFocusInfo audioFocusInfo, @AudioContext int context,
+            @NonNull PackageManager packageManager) {
+        Objects.requireNonNull(audioFocusInfo, "AudioFocusInfo cannot be null");
+        Objects.requireNonNull(packageManager, "PackageManager cannot be null");
+        mAudioFocusInfo = audioFocusInfo;
+        mAudioContext = context;
+        mBlockers = new ArrayList<>();
+        mPackageManager = packageManager;
+    }
+
+    @AudioContext
+    int getAudioContext() {
+        return mAudioContext;
+    }
+
+    AudioFocusInfo getAudioFocusInfo() {
+        return mAudioFocusInfo;
+    }
+
+    boolean isUnblocked() {
+        return mBlockers.isEmpty();
+    }
+
+    void addBlocker(FocusEntry blocker) {
+        mBlockers.add(blocker);
+    }
+
+    void removeBlocker(FocusEntry blocker) {
+        mBlockers.remove(blocker);
+    }
+
+    String getClientId() {
+        return mAudioFocusInfo.getClientId();
+    }
+
+    boolean isDucked() {
+        return mIsDucked;
+    }
+
+    void setDucked(boolean ducked) {
+        mIsDucked = ducked;
+    }
+
+    boolean wantsPauseInsteadOfDucking() {
+        return (mAudioFocusInfo.getFlags() & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
+                != 0;
+    }
+
+    boolean receivesDuckEvents() {
+        Bundle bundle = mAudioFocusInfo.getAttributes().getBundle();
+
+        if (bundle == null) {
+            return false;
+        }
+
+        if (!bundle.getBoolean(CarAudioManager.AUDIOFOCUS_EXTRA_RECEIVE_DUCKING_EVENTS)) {
+            return false;
+        }
+
+        return (mPackageManager.checkPermission(
+                Car.PERMISSION_RECEIVE_CAR_AUDIO_DUCKING_EVENTS,
+                mAudioFocusInfo.getPackageName())
+                == PackageManager.PERMISSION_GRANTED);
+    }
+
+    String getUsageName() {
+        return mAudioFocusInfo.getAttributes().usageToString();
+    }
+
+    public void dump(String indent, PrintWriter writer) {
+        writer.printf("%s%s - %s\n", indent, getClientId(), getUsageName());
+        // Prints in single line
+        writer.printf("%s\tReceives Duck Events: %b, ", indent, receivesDuckEvents());
+        writer.printf("Wants Pause Instead of Ducking: %b, ", wantsPauseInsteadOfDucking());
+        writer.printf("Is Ducked: %b\n", isDucked());
+    }
+}
diff --git a/service/src/com/android/car/audio/FocusInteraction.java b/service/src/com/android/car/audio/FocusInteraction.java
new file mode 100644
index 0000000..eeb8321
--- /dev/null
+++ b/service/src/com/android/car/audio/FocusInteraction.java
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.audio;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.car.settings.CarSettings;
+import android.database.ContentObserver;
+import android.media.AudioManager;
+import android.media.AudioManager.FocusRequestResult;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.car.audio.CarAudioContext.AudioContext;
+import com.android.internal.util.Preconditions;
+
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * FocusInteraction is responsible for evaluating how incoming focus requests should be handled
+ * based on pre-defined interaction behaviors for each incoming {@link AudioContext} in relation to
+ * a {@link AudioContext} that is currently holding focus.
+ */
+final class FocusInteraction {
+
+    private static final String TAG = FocusInteraction.class.getSimpleName();
+
+    @VisibleForTesting
+    static final Uri AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL_URI =
+            Settings.Secure.getUriFor(
+                    CarSettings.Secure.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL);
+
+    // Values for the internal interaction matrix we use to make focus decisions
+    @VisibleForTesting
+    static final int INTERACTION_REJECT = 0; // Focus not granted
+    @VisibleForTesting
+    static final int INTERACTION_EXCLUSIVE = 1; // Focus granted, others loose focus
+    @VisibleForTesting
+    static final int INTERACTION_CONCURRENT = 2; // Focus granted, others keep focus
+
+    private static final int[][] sInteractionMatrix = {
+            // Each Row represents CarAudioContext of current focus holder
+            // Each Column represents CarAudioContext of incoming request (labels along the right)
+            // Cell value is one of INTERACTION_REJECT, INTERACTION_EXCLUSIVE,
+            // or INTERACTION_CONCURRENT
+
+            // Focus holder: INVALID
+            {
+                    INTERACTION_REJECT, // INVALID
+                    INTERACTION_REJECT, // MUSIC
+                    INTERACTION_REJECT, // NAVIGATION
+                    INTERACTION_REJECT, // VOICE_COMMAND
+                    INTERACTION_REJECT, // CALL_RING
+                    INTERACTION_REJECT, // CALL
+                    INTERACTION_REJECT, // ALARM
+                    INTERACTION_REJECT, // NOTIFICATION
+                    INTERACTION_REJECT, // SYSTEM_SOUND,
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_EXCLUSIVE, // SAFETY
+                    INTERACTION_REJECT, // VEHICLE_STATUS
+                    INTERACTION_REJECT, // ANNOUNCEMENT
+            },
+            // Focus holder: MUSIC
+            {
+                    INTERACTION_REJECT, // INVALID
+                    INTERACTION_EXCLUSIVE, // MUSIC
+                    INTERACTION_CONCURRENT, // NAVIGATION
+                    INTERACTION_EXCLUSIVE, // VOICE_COMMAND
+                    INTERACTION_EXCLUSIVE, // CALL_RING
+                    INTERACTION_EXCLUSIVE, // CALL
+                    INTERACTION_EXCLUSIVE, // ALARM
+                    INTERACTION_CONCURRENT, // NOTIFICATION
+                    INTERACTION_CONCURRENT, // SYSTEM_SOUND
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_EXCLUSIVE, // ANNOUNCEMENT
+            },
+            // Focus holder: NAVIGATION
+            {
+                    INTERACTION_REJECT, // INVALID
+                    INTERACTION_CONCURRENT, // MUSIC
+                    INTERACTION_CONCURRENT, // NAVIGATION
+                    INTERACTION_EXCLUSIVE, // VOICE_COMMAND
+                    INTERACTION_CONCURRENT, // CALL_RING
+                    INTERACTION_EXCLUSIVE, // CALL
+                    INTERACTION_CONCURRENT, // ALARM
+                    INTERACTION_CONCURRENT, // NOTIFICATION
+                    INTERACTION_CONCURRENT, // SYSTEM_SOUND
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_CONCURRENT, // ANNOUNCEMENT
+            },
+            // Focus holder: VOICE_COMMAND
+            {
+                    INTERACTION_REJECT, // INVALID
+                    INTERACTION_CONCURRENT, // MUSIC
+                    INTERACTION_REJECT, // NAVIGATION
+                    INTERACTION_CONCURRENT, // VOICE_COMMAND
+                    INTERACTION_EXCLUSIVE, // CALL_RING
+                    INTERACTION_EXCLUSIVE, // CALL
+                    INTERACTION_REJECT, // ALARM
+                    INTERACTION_REJECT, // NOTIFICATION
+                    INTERACTION_REJECT, // SYSTEM_SOUND
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_REJECT, // ANNOUNCEMENT
+            },
+            // Focus holder: CALL_RING
+            {
+                    INTERACTION_REJECT, // INVALID
+                    INTERACTION_REJECT, // MUSIC
+                    INTERACTION_CONCURRENT, // NAVIGATION
+                    INTERACTION_CONCURRENT, // VOICE_COMMAND
+                    INTERACTION_CONCURRENT, // CALL_RING
+                    INTERACTION_CONCURRENT, // CALL
+                    INTERACTION_REJECT, // ALARM
+                    INTERACTION_REJECT, // NOTIFICATION
+                    INTERACTION_CONCURRENT, // SYSTEM_SOUND
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_REJECT, // ANNOUNCEMENT
+            },
+            // Focus holder: CALL
+            {
+                    INTERACTION_REJECT, // INVALID
+                    INTERACTION_REJECT, // MUSIC
+                    INTERACTION_CONCURRENT, // NAVIGATION
+                    INTERACTION_REJECT, // VOICE_COMMAND
+                    INTERACTION_CONCURRENT, // CALL_RING
+                    INTERACTION_CONCURRENT, // CALL
+                    INTERACTION_CONCURRENT, // ALARM
+                    INTERACTION_CONCURRENT, // NOTIFICATION
+                    INTERACTION_REJECT, // SYSTEM_SOUND
+                    INTERACTION_CONCURRENT, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_REJECT, // ANNOUNCEMENT
+            },
+            // Focus holder: ALARM
+            {
+                    INTERACTION_REJECT, // INVALID
+                    INTERACTION_CONCURRENT, // MUSIC
+                    INTERACTION_CONCURRENT, // NAVIGATION
+                    INTERACTION_EXCLUSIVE, // VOICE_COMMAND
+                    INTERACTION_EXCLUSIVE, // CALL_RING
+                    INTERACTION_EXCLUSIVE, // CALL
+                    INTERACTION_CONCURRENT, // ALARM
+                    INTERACTION_CONCURRENT, // NOTIFICATION
+                    INTERACTION_CONCURRENT, // SYSTEM_SOUND
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_REJECT, // ANNOUNCEMENT
+            },
+            // Focus holder: NOTIFICATION
+            {
+                    INTERACTION_REJECT, // INVALID
+                    INTERACTION_CONCURRENT, // MUSIC
+                    INTERACTION_CONCURRENT, // NAVIGATION
+                    INTERACTION_EXCLUSIVE, // VOICE_COMMAND
+                    INTERACTION_EXCLUSIVE, // CALL_RING
+                    INTERACTION_EXCLUSIVE, // CALL
+                    INTERACTION_CONCURRENT, // ALARM
+                    INTERACTION_CONCURRENT, // NOTIFICATION
+                    INTERACTION_CONCURRENT, // SYSTEM_SOUND
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_CONCURRENT, // ANNOUNCEMENT
+            },
+            // Focus holder: SYSTEM_SOUND
+            {
+                    INTERACTION_REJECT, // INVALID
+                    INTERACTION_CONCURRENT, // MUSIC
+                    INTERACTION_CONCURRENT, // NAVIGATION
+                    INTERACTION_EXCLUSIVE, // VOICE_COMMAND
+                    INTERACTION_EXCLUSIVE, // CALL_RING
+                    INTERACTION_EXCLUSIVE, // CALL
+                    INTERACTION_CONCURRENT, // ALARM
+                    INTERACTION_CONCURRENT, // NOTIFICATION
+                    INTERACTION_CONCURRENT, // SYSTEM_SOUND
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_CONCURRENT, // ANNOUNCEMENT
+            },
+            // Focus holder: EMERGENCY
+            {
+                    INTERACTION_REJECT, // INVALID
+                    INTERACTION_REJECT, // MUSIC
+                    INTERACTION_REJECT, // NAVIGATION
+                    INTERACTION_REJECT, // VOICE_COMMAND
+                    INTERACTION_REJECT, // CALL_RING
+                    INTERACTION_CONCURRENT, // CALL
+                    INTERACTION_REJECT, // ALARM
+                    INTERACTION_REJECT, // NOTIFICATION
+                    INTERACTION_REJECT, // SYSTEM_SOUND
+                    INTERACTION_CONCURRENT, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_REJECT, // VEHICLE_STATUS
+                    INTERACTION_REJECT, // ANNOUNCEMENT
+            },
+            // Focus holder: SAFETY
+            {
+                    INTERACTION_REJECT, // INVALID
+                    INTERACTION_CONCURRENT, // MUSIC
+                    INTERACTION_CONCURRENT, // NAVIGATION
+                    INTERACTION_CONCURRENT, // VOICE_COMMAND
+                    INTERACTION_CONCURRENT, // CALL_RING
+                    INTERACTION_CONCURRENT, // CALL
+                    INTERACTION_CONCURRENT, // ALARM
+                    INTERACTION_CONCURRENT, // NOTIFICATION
+                    INTERACTION_CONCURRENT, // SYSTEM_SOUND
+                    INTERACTION_CONCURRENT, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_CONCURRENT, // ANNOUNCEMENT
+            },
+            // Focus holder: VEHICLE_STATUS
+            {
+                    INTERACTION_REJECT, // INVALID
+                    INTERACTION_CONCURRENT, // MUSIC
+                    INTERACTION_CONCURRENT, // NAVIGATION
+                    INTERACTION_CONCURRENT, // VOICE_COMMAND
+                    INTERACTION_CONCURRENT, // CALL_RING
+                    INTERACTION_CONCURRENT, // CALL
+                    INTERACTION_CONCURRENT, // ALARM
+                    INTERACTION_CONCURRENT, // NOTIFICATION
+                    INTERACTION_CONCURRENT, // SYSTEM_SOUND
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_CONCURRENT, // ANNOUNCEMENT
+            },
+            // Focus holder: ANNOUNCEMENT
+            {
+                    INTERACTION_REJECT, // INVALID
+                    INTERACTION_EXCLUSIVE, // MUSIC
+                    INTERACTION_CONCURRENT, // NAVIGATION
+                    INTERACTION_EXCLUSIVE, // VOICE_COMMAND
+                    INTERACTION_EXCLUSIVE, // CALL_RING
+                    INTERACTION_EXCLUSIVE, // CALL
+                    INTERACTION_EXCLUSIVE, // ALARM
+                    INTERACTION_CONCURRENT, // NOTIFICATION
+                    INTERACTION_CONCURRENT, // SYSTEM_SOUND
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_EXCLUSIVE, // ANNOUNCEMENT
+            },
+    };
+
+    private final Object mLock = new Object();
+
+    private final int[][] mInteractionMatrix;
+
+    private ContentObserver mContentObserver;
+
+    private final CarAudioSettings mCarAudioFocusSettings;
+
+    private int mUserId;
+
+    /**
+     * Constructs a focus interaction instance.
+     */
+    FocusInteraction(@NonNull CarAudioSettings carAudioSettings) {
+        mCarAudioFocusSettings = Objects.requireNonNull(carAudioSettings);
+        mInteractionMatrix = cloneInteractionMatrix(sInteractionMatrix);
+    }
+
+    private void navigationOnCallSettingChanged() {
+        synchronized (mLock) {
+            if (mUserId != UserHandle.USER_NULL) {
+                setRejectNavigationOnCallLocked(isRejectNavigationOnCallEnabledInSettings(mUserId));
+            }
+        }
+    }
+
+    public void setRejectNavigationOnCallLocked(boolean navigationRejectedWithCall) {
+        mInteractionMatrix[CarAudioContext.CALL][CarAudioContext.NAVIGATION] =
+                navigationRejectedWithCall ? INTERACTION_REJECT :
+                sInteractionMatrix[CarAudioContext.CALL][CarAudioContext.NAVIGATION];
+    }
+
+    /**
+     * Evaluates interaction between incoming focus {@link AudioContext} and the current focus
+     * request based on interaction matrix.
+     *
+     * <p>Note: In addition to returning the {@link FocusRequestResult}
+     * for the incoming request based on this interaction, this method also adds the current {@code
+     * focusHolder} to the {@code focusLosers} list when appropriate.
+     *
+     * @param requestedContext CarAudioContextType of incoming focus request
+     * @param focusHolder      {@link FocusEntry} for current focus holder
+     * @param focusLosers      Mutable array to add focusHolder to if it should lose focus
+     * @return {@link FocusRequestResult} result of focus interaction
+     */
+    public @FocusRequestResult int evaluateRequest(@AudioContext int requestedContext,
+            FocusEntry focusHolder, List<FocusEntry> focusLosers, boolean allowDucking,
+            boolean allowsDelayedFocus) {
+        @AudioContext int holderContext = focusHolder.getAudioContext();
+        Preconditions.checkArgumentInRange(holderContext, 0, mInteractionMatrix.length - 1,
+                "holderContext");
+        synchronized (mLock) {
+            int[] holderRow = mInteractionMatrix[holderContext];
+            Preconditions.checkArgumentInRange(requestedContext, 0, holderRow.length - 1,
+                    "requestedContext");
+
+            switch (holderRow[requestedContext]) {
+                case INTERACTION_REJECT:
+                    if (allowsDelayedFocus) {
+                        return AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
+                    }
+                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+                case INTERACTION_EXCLUSIVE:
+                    focusLosers.add(focusHolder);
+                    return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+                case INTERACTION_CONCURRENT:
+                    // If ducking isn't allowed by the focus requester, then everybody else
+                    // must get a LOSS.
+                    // If a focus holder has set the AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS flag,
+                    // they must get a LOSS message even if ducking would otherwise be allowed.
+                    // If a focus holder holds the RECEIVE_CAR_AUDIO_DUCKING_EVENTS permission,
+                    // they must receive all audio focus losses.
+                    if (!allowDucking
+                            || focusHolder.wantsPauseInsteadOfDucking()
+                            || focusHolder.receivesDuckEvents()) {
+                        focusLosers.add(focusHolder);
+                    }
+                    return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+                default:
+                    Log.e(TAG, String.format("Unsupported CarAudioContext %d - rejecting request",
+                            holderRow[requestedContext]));
+                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+            }
+        }
+    }
+
+    /**
+     * Sets userId for interaction focus settings
+     */
+    void setUserIdForSettings(@UserIdInt int userId) {
+        synchronized (mLock) {
+            mUserId = userId;
+            if (mContentObserver != null) {
+                mCarAudioFocusSettings.getContentResolver()
+                        .unregisterContentObserver(mContentObserver);
+                mContentObserver = null;
+            }
+            if (mUserId == UserHandle.USER_NULL) {
+                setRejectNavigationOnCallLocked(false);
+                return;
+            }
+            mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
+                @Override
+                public void onChange(boolean selfChange, Uri uri) {
+                    if (uri.equals(AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL_URI)) {
+                        navigationOnCallSettingChanged();
+                    }
+                }
+            };
+            mCarAudioFocusSettings.getContentResolver()
+                    .registerContentObserver(AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL_URI,
+                            false, mContentObserver, userId);
+            setRejectNavigationOnCallLocked(isRejectNavigationOnCallEnabledInSettings(mUserId));
+        }
+    }
+
+    private boolean isRejectNavigationOnCallEnabledInSettings(@UserIdInt int userId) {
+        return mCarAudioFocusSettings.isRejectNavigationOnCallEnabledInSettings(userId);
+    }
+
+    @VisibleForTesting
+    int[][] getInteractionMatrix() {
+        return cloneInteractionMatrix(mInteractionMatrix);
+    }
+
+    private static int[][] cloneInteractionMatrix(int[][] matrixToClone) {
+        int[][] interactionMatrixClone =
+                new int[matrixToClone.length][matrixToClone.length];
+        for (int audioContext = 0; audioContext < matrixToClone.length; audioContext++) {
+            System.arraycopy(matrixToClone[audioContext], 0,
+                    interactionMatrixClone[audioContext], 0, matrixToClone.length);
+        }
+        return interactionMatrixClone;
+    }
+
+    public void dump(String indent, PrintWriter writer) {
+        boolean rejectNavigationOnCall =
+                mInteractionMatrix[CarAudioContext.CALL][CarAudioContext.NAVIGATION]
+                == INTERACTION_REJECT;
+        writer.printf("%sReject Navigation on Call: %b\n", indent, rejectNavigationOnCall);
+    }
+}
diff --git a/service/src/com/android/car/audio/OWNERS b/service/src/com/android/car/audio/OWNERS
new file mode 100644
index 0000000..8d34cdd
--- /dev/null
+++ b/service/src/com/android/car/audio/OWNERS
@@ -0,0 +1,3 @@
+# Audio owners
+haydengomes@google.com
+oscarazu@google.com
\ No newline at end of file
diff --git a/service/src/com/android/car/audio/hal/AudioControlFactory.java b/service/src/com/android/car/audio/hal/AudioControlFactory.java
new file mode 100644
index 0000000..bd599cf
--- /dev/null
+++ b/service/src/com/android/car/audio/hal/AudioControlFactory.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.audio.hal;
+
+import android.util.Log;
+
+/**
+ * Factory for constructing wrappers around IAudioControl HAL instances.
+ */
+public final class AudioControlFactory {
+    private static final String TAG = AudioControlWrapper.class.getSimpleName();
+
+    /**
+     * Generates {@link AudioControlWrapper} for interacting with IAudioControl HAL service. Checks
+     * for V2.0 first, and then falls back to V1.0 if that is not available. Will throw if none is
+     * registered on the manifest.
+     * @return {@link AudioControlWrapper} for registered IAudioControl service.
+     */
+    public static AudioControlWrapper newAudioControl() {
+        android.hardware.automotive.audiocontrol.V2_0.IAudioControl audioControlV2 =
+                AudioControlWrapperV2.getService();
+        if (audioControlV2 != null) {
+            return new AudioControlWrapperV2(audioControlV2);
+        }
+        Log.i(TAG, "IAudioControl@V2.0 not in the manifest");
+
+        android.hardware.automotive.audiocontrol.V1_0.IAudioControl audioControlV1 =
+                AudioControlWrapperV1.getService();
+        if (audioControlV1 != null) {
+            Log.w(TAG, "IAudioControl V1.0 is deprecated. Consider upgrading to V2.0");
+            return new AudioControlWrapperV1(audioControlV1);
+        }
+
+        throw new IllegalStateException("No version of AudioControl HAL in the manifest");
+    }
+}
diff --git a/service/src/com/android/car/audio/hal/AudioControlWrapper.java b/service/src/com/android/car/audio/hal/AudioControlWrapper.java
new file mode 100644
index 0000000..c491056
--- /dev/null
+++ b/service/src/com/android/car/audio/hal/AudioControlWrapper.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.audio.hal;
+
+import android.hardware.automotive.audiocontrol.V2_0.IFocusListener;
+import android.media.AudioAttributes.AttributeUsage;
+
+import androidx.annotation.Nullable;
+
+import java.io.PrintWriter;
+
+/**
+ * AudioControlWrapper wraps IAudioControl HAL interface, handling version specific support so that
+ * the rest of CarAudioService doesn't need to know about it.
+ */
+public interface AudioControlWrapper {
+
+    /**
+     * Closes the focus listener that's registered on the AudioControl HAL
+     */
+    void unregisterFocusListener();
+
+    /**
+     * Indicates if HAL can support making and abandoning audio focus requests.
+     */
+    boolean supportsHalAudioFocus();
+
+    /**
+     * Registers listener for HAL audio focus requests with IAudioControl. Only works if
+     * {@code supportsHalAudioFocus} returns true.
+     *
+     * @param focusListener the listener to register on the IAudioControl HAL.
+     */
+    void registerFocusListener(IFocusListener focusListener);
+
+    /**
+     * Notifies HAL of change in audio focus for a request it has made.
+     *
+     * @param usage that the request is associated with.
+     * @param zoneId for the audio zone that the request is associated with.
+     * @param focusChange the new status of the request.
+     */
+    void onAudioFocusChange(@AttributeUsage int usage, int zoneId, int focusChange);
+
+    /**
+     * dumps the current state of the AudioControlWrapper
+     *
+     * @param indent indent to append to each new line
+     * @param writer stream to write current state
+     */
+    void dump(String indent, PrintWriter writer);
+
+    /**
+     * Sets the fade for the vehicle.
+     *
+     * @param value to set for the fade. Positive is towards front.
+     */
+    void setFadeTowardFront(float value);
+
+    /**
+     * Sets the balance value for the vehicle.
+     *
+     * @param value to set for the balance. Positive is towards the right.
+     */
+    void setBalanceTowardRight(float value);
+
+    /**
+     * Registers recipient to be notified if AudioControl HAL service dies.
+     * @param deathRecipient to be notified upon HAL service death.
+     */
+    void linkToDeath(@Nullable AudioControlDeathRecipient deathRecipient);
+
+    /**
+     * Unregisters recipient for AudioControl HAL service death.
+     */
+    void unlinkToDeath();
+
+    /**
+     * Recipient to be notified upon death of AudioControl HAL.
+     */
+    interface AudioControlDeathRecipient {
+        /**
+         * Called if AudioControl HAL dies.
+         */
+        void serviceDied();
+    }
+}
diff --git a/service/src/com/android/car/audio/hal/AudioControlWrapperV1.java b/service/src/com/android/car/audio/hal/AudioControlWrapperV1.java
new file mode 100644
index 0000000..433b5d5
--- /dev/null
+++ b/service/src/com/android/car/audio/hal/AudioControlWrapperV1.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.audio.hal;
+
+import android.hardware.automotive.audiocontrol.V1_0.IAudioControl;
+import android.hardware.automotive.audiocontrol.V2_0.IFocusListener;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import com.android.car.audio.CarAudioContext;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.PrintWriter;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+
+/**
+ * Wrapper for IAudioControl@1.0.
+ */
+public final class AudioControlWrapperV1 implements AudioControlWrapper {
+    private static final String TAG = AudioControlWrapperV1.class.getSimpleName();
+
+    private IAudioControl mAudioControlV1;
+    private AudioControlDeathRecipient mDeathRecipient;
+
+    /**
+     * Gets IAudioControl@1.0 service if registered.
+     */
+    public static @Nullable IAudioControl getService() {
+        try {
+            return IAudioControl.getService(true);
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Failed to get IAudioControl@1.0 service", e);
+        } catch (NoSuchElementException e) {
+            return null;
+        }
+    }
+
+    @VisibleForTesting
+    AudioControlWrapperV1(IAudioControl audioControlV1) {
+        mAudioControlV1 = Objects.requireNonNull(audioControlV1);
+    }
+
+    @Override
+    public boolean supportsHalAudioFocus() {
+        return false;
+    }
+
+    @Override
+    public void registerFocusListener(IFocusListener focusListener) {
+        throw new UnsupportedOperationException(
+                "Focus listener is unsupported for IAudioControl@1.0");
+    }
+
+    @Override
+    public void unregisterFocusListener() {
+        throw new UnsupportedOperationException(
+                "Focus listener is unsupported for IAudioControl@1.0");
+    }
+
+    @Override
+    public void onAudioFocusChange(int usage, int zoneId, int focusChange) {
+        throw new UnsupportedOperationException(
+                "Focus listener is unsupported for IAudioControl@1.0");
+    }
+
+    @Override
+    public void dump(String indent, PrintWriter writer) {
+        writer.printf("%s*AudioControlWrapperV1*\n", indent);
+    }
+
+    @Override
+    public void setFadeTowardFront(float value) {
+        try {
+            mAudioControlV1.setFadeTowardFront(value);
+        } catch (RemoteException e) {
+            Log.e(TAG, "setFadeTowardFront failed", e);
+        }
+    }
+
+    @Override
+    public void setBalanceTowardRight(float value) {
+        try {
+            mAudioControlV1.setBalanceTowardRight(value);
+        } catch (RemoteException e) {
+            Log.e(TAG, "setBalanceTowardRight failed", e);
+        }
+    }
+
+    /**
+     * Gets the bus associated with CarAudioContext.
+     *
+     * <p>This API is used along with car_volume_groups.xml to configure volume groups and routing.
+     *
+     * @param audioContext {@code CarAudioContext} to get a context for.
+     * @return int bus number. Should be part of the prefix for the device's address. For example,
+     * bus001_media would be bus 1.
+     * @deprecated Volume and routing configuration has been replaced by
+     * car_audio_configuration.xml. Starting with IAudioControl@V2.0, getBusForContext is no longer
+     * supported.
+     */
+    @Deprecated
+    public int getBusForContext(@CarAudioContext.AudioContext int audioContext) {
+        try {
+            return mAudioControlV1.getBusForContext(audioContext);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to query IAudioControl HAL to get bus for context", e);
+            throw new IllegalStateException("Failed to query IAudioControl#getBusForContext", e);
+        }
+    }
+
+    @Override
+    public void linkToDeath(@Nullable AudioControlDeathRecipient deathRecipient) {
+        try {
+            mAudioControlV1.linkToDeath(this::serviceDied, 0);
+            mDeathRecipient = deathRecipient;
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Call to IAudioControl@1.0#linkToDeath failed", e);
+        }
+    }
+
+    @Override
+    public void unlinkToDeath() {
+        try {
+            mAudioControlV1.unlinkToDeath(this::serviceDied);
+            mDeathRecipient = null;
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Call to IAudioControl@1.0#unlinkToDeath failed", e);
+        }
+    }
+
+    private void serviceDied(long cookie) {
+        Log.w(TAG, "IAudioControl@1.0 died. Fetching new handle");
+        mAudioControlV1 = AudioControlWrapperV1.getService();
+        linkToDeath(mDeathRecipient);
+        if (mDeathRecipient != null) {
+            mDeathRecipient.serviceDied();
+        }
+    }
+
+
+}
diff --git a/service/src/com/android/car/audio/hal/AudioControlWrapperV2.java b/service/src/com/android/car/audio/hal/AudioControlWrapperV2.java
new file mode 100644
index 0000000..ff504f4
--- /dev/null
+++ b/service/src/com/android/car/audio/hal/AudioControlWrapperV2.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.audio.hal;
+
+import android.hardware.automotive.audiocontrol.V2_0.IAudioControl;
+import android.hardware.automotive.audiocontrol.V2_0.ICloseHandle;
+import android.hardware.automotive.audiocontrol.V2_0.IFocusListener;
+import android.media.AudioAttributes;
+import android.media.AudioAttributes.AttributeUsage;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import java.io.PrintWriter;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+
+/**
+ * Wrapper for IAudioControl@2.0.
+ */
+public final class AudioControlWrapperV2 implements AudioControlWrapper {
+    private static final String TAG = AudioControlWrapperV2.class.getSimpleName();
+
+    private IAudioControl mAudioControlV2;
+
+    private AudioControlDeathRecipient mDeathRecipient;
+    private ICloseHandle mCloseHandle;
+
+    public static @Nullable IAudioControl getService() {
+        try {
+            return IAudioControl.getService(true);
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Failed to get IAudioControl@2.0 service", e);
+        } catch (NoSuchElementException e) {
+            return null;
+        }
+    }
+
+    AudioControlWrapperV2(IAudioControl audioControlV2) {
+        mAudioControlV2 = Objects.requireNonNull(audioControlV2);
+    }
+
+    @Override
+    public void unregisterFocusListener() {
+        if (mCloseHandle != null) {
+            try {
+                mCloseHandle.close();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to close focus listener", e);
+            } finally {
+                mCloseHandle = null;
+            }
+        }
+    }
+
+    @Override
+    public boolean supportsHalAudioFocus() {
+        return true;
+    }
+
+    @Override
+    public void registerFocusListener(IFocusListener focusListener) {
+        Log.d(TAG, "Registering focus listener on AudioControl HAL");
+        try {
+            mCloseHandle = mAudioControlV2.registerFocusListener(focusListener);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to register focus listener");
+            throw new IllegalStateException("IAudioControl#registerFocusListener failed", e);
+        }
+    }
+
+    @Override
+    public void onAudioFocusChange(@AttributeUsage int usage, int zoneId, int focusChange) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "onAudioFocusChange: usage " + AudioAttributes.usageToString(usage)
+                    + ", zoneId " + zoneId + ", focusChange " + focusChange);
+        }
+        try {
+            mAudioControlV2.onAudioFocusChange(usage, zoneId, focusChange);
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Failed to query IAudioControl#onAudioFocusChange", e);
+        }
+    }
+
+    /**
+     * Dumps the current state of the {@code AudioControlWrapperV2}.
+     *
+     * @param indent indent to append to each new line.
+     * @param writer stream to write current state.
+     */
+    @Override
+    public void dump(String indent, PrintWriter writer) {
+        writer.printf("%s*AudioControlWrapperV2*\n", indent);
+        writer.printf("%s\tFocus listener registered on HAL? %b", indent, (mCloseHandle != null));
+    }
+
+    @Override
+    public void setFadeTowardFront(float value) {
+        try {
+            mAudioControlV2.setFadeTowardFront(value);
+        } catch (RemoteException e) {
+            Log.e(TAG, "setFadeTowardFront failed", e);
+        }
+    }
+
+    @Override
+    public void setBalanceTowardRight(float value) {
+        try {
+            mAudioControlV2.setBalanceTowardRight(value);
+        } catch (RemoteException e) {
+            Log.e(TAG, "setBalanceTowardRight failed", e);
+        }
+    }
+
+    @Override
+    public void linkToDeath(@Nullable AudioControlDeathRecipient deathRecipient) {
+        try {
+            mAudioControlV2.linkToDeath(this::serviceDied, 0);
+            mDeathRecipient = deathRecipient;
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Call to IAudioControl@2.0#linkToDeath failed", e);
+        }
+    }
+
+    @Override
+    public void unlinkToDeath() {
+        try {
+            mAudioControlV2.unlinkToDeath(this::serviceDied);
+            mDeathRecipient = null;
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Call to IAudioControl@2.0#unlinkToDeath failed", e);
+        }
+    }
+
+    private void serviceDied(long cookie) {
+        Log.w(TAG, "IAudioControl@2.0 died. Fetching new handle");
+        mAudioControlV2 = AudioControlWrapperV2.getService();
+        linkToDeath(mDeathRecipient);
+        if (mDeathRecipient != null) {
+            mDeathRecipient.serviceDied();
+        }
+    }
+}
diff --git a/service/src/com/android/car/audio/hal/HalAudioFocus.java b/service/src/com/android/car/audio/hal/HalAudioFocus.java
new file mode 100644
index 0000000..eff0168
--- /dev/null
+++ b/service/src/com/android/car/audio/hal/HalAudioFocus.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.audio.hal;
+
+import static android.media.AudioManager.AUDIOFOCUS_LOSS;
+import static android.media.AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
+import static android.media.AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+import static android.media.AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+
+import android.car.media.CarAudioManager;
+import android.hardware.automotive.audiocontrol.V2_0.IFocusListener;
+import android.media.AudioAttributes;
+import android.media.AudioAttributes.AttributeUsage;
+import android.media.AudioFocusRequest;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.SparseArray;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+
+import java.io.PrintWriter;
+import java.util.Objects;
+
+/**
+ * Manages focus requests from the HAL on a per-zone per-usage basis
+ */
+public final class HalAudioFocus extends IFocusListener.Stub {
+    private static final String TAG = HalAudioFocus.class.getSimpleName();
+
+    private final AudioManager mAudioManager;
+    private final AudioControlWrapper mAudioControlWrapper;
+
+    private final Object mLock = new Object();
+
+    // Map of Maps. Top level keys are ZoneIds. Second level keys are usages.
+    // Values are HalAudioFocusRequests
+    @GuardedBy("mImplLock")
+    private final SparseArray<SparseArray<HalAudioFocusRequest>> mHalFocusRequestsByZoneAndUsage;
+
+    public HalAudioFocus(@NonNull AudioManager audioManager,
+            @NonNull AudioControlWrapper audioControlWrapper,
+            @NonNull int[] audioZoneIds) {
+        mAudioManager = Objects.requireNonNull(audioManager);
+        mAudioControlWrapper = Objects.requireNonNull(audioControlWrapper);
+        Objects.requireNonNull(audioZoneIds);
+
+        mHalFocusRequestsByZoneAndUsage = new SparseArray<>(audioZoneIds.length);
+        for (int zoneId : audioZoneIds) {
+            mHalFocusRequestsByZoneAndUsage.append(zoneId, new SparseArray<>());
+        }
+    }
+
+    /**
+     * Registers {@code IFocusListener} on {@code AudioControlWrapper} to receive HAL audio focus
+     * request and abandon calls.
+     */
+    public void registerFocusListener() {
+        mAudioControlWrapper.registerFocusListener(this);
+    }
+
+    /**
+     * Unregisters {@code IFocusListener} from {@code AudioControlWrapper}.
+     */
+    public void unregisterFocusListener() {
+        mAudioControlWrapper.unregisterFocusListener();
+    }
+
+    @Override
+    public void requestAudioFocus(@AttributeUsage int usage, int zoneId, int focusGain) {
+        Preconditions.checkArgument(mHalFocusRequestsByZoneAndUsage.contains(zoneId),
+                "Invalid zoneId %d provided in requestAudioFocus", zoneId);
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "Requesting focus gain " + focusGain + " with usage "
+                    + AudioAttributes.usageToString(usage) + " and zoneId " + zoneId);
+        }
+        synchronized (mLock) {
+            HalAudioFocusRequest currentRequest = mHalFocusRequestsByZoneAndUsage.get(zoneId).get(
+                    usage);
+            if (currentRequest != null) {
+                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                    Log.d(TAG, "A request already exists for zoneId " + zoneId + " and usage "
+                            + usage);
+                }
+                mAudioControlWrapper.onAudioFocusChange(usage, zoneId, currentRequest.mFocusStatus);
+            } else {
+                makeAudioFocusRequestLocked(usage, zoneId, focusGain);
+            }
+        }
+    }
+
+    @Override
+    public void abandonAudioFocus(int usage, int zoneId) throws RemoteException {
+        Preconditions.checkArgument(mHalFocusRequestsByZoneAndUsage.contains(zoneId),
+                "Invalid zoneId %d provided in abandonAudioFocus", zoneId);
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "Abandoning focus with usage " + AudioAttributes.usageToString(usage)
+                    + " for zoneId " + zoneId);
+        }
+        synchronized (mLock) {
+            abandonAudioFocusLocked(usage, zoneId);
+        }
+    }
+
+    /**
+     * Clear out all existing focus requests. Called when HAL dies.
+     */
+    public void reset() {
+        Log.d(TAG, "Resetting HAL Audio Focus requests");
+        synchronized (mLock) {
+            for (int i = 0; i < mHalFocusRequestsByZoneAndUsage.size(); i++) {
+                int zoneId = mHalFocusRequestsByZoneAndUsage.keyAt(i);
+                SparseArray<HalAudioFocusRequest> requestsByUsage =
+                        mHalFocusRequestsByZoneAndUsage.valueAt(i);
+                int usageCount = requestsByUsage.size();
+                for (int j = 0; j < usageCount; j++) {
+                    int usage = requestsByUsage.keyAt(j);
+                    abandonAudioFocusLocked(usage, zoneId);
+                }
+            }
+        }
+    }
+
+    /**
+     * dumps the current state of the HalAudioFocus
+     *
+     * @param indent indent to append to each new line
+     * @param writer stream to write current state
+     */
+    public void dump(String indent, PrintWriter writer) {
+        writer.printf("%s*HalAudioFocus*\n", indent);
+
+        writer.printf("%s\tCurrent focus requests:\n", indent);
+        for (int i = 0; i < mHalFocusRequestsByZoneAndUsage.size(); i++) {
+            int zoneId = mHalFocusRequestsByZoneAndUsage.keyAt(i);
+            writer.printf("%s\t\tZone %s:\n", indent, zoneId);
+
+            SparseArray<HalAudioFocusRequest> requestsByUsage =
+                    mHalFocusRequestsByZoneAndUsage.valueAt(i);
+            for (int j = 0; j < requestsByUsage.size(); j++) {
+                int usage = requestsByUsage.keyAt(j);
+                HalAudioFocusRequest request = requestsByUsage.valueAt(j);
+                writer.printf("%s\t\t\t%s - focusGain: %s\n", indent,
+                        AudioAttributes.usageToString(usage), request.mFocusStatus);
+            }
+        }
+    }
+
+    private void abandonAudioFocusLocked(int usage, int zoneId) {
+        HalAudioFocusRequest currentRequest = mHalFocusRequestsByZoneAndUsage.get(zoneId)
+                .removeReturnOld(usage);
+
+        if (currentRequest == null) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "No focus to abandon for usage " + AudioAttributes.usageToString(usage)
+                        + " and zoneId " + zoneId);
+            }
+            return;
+        }
+
+        int result = mAudioManager.abandonAudioFocusRequest(currentRequest.mAudioFocusRequest);
+        if (result == AUDIOFOCUS_REQUEST_GRANTED) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "Abandoned focus for usage " + AudioAttributes.usageToString(usage)
+                        + "and zoneId " + zoneId);
+            }
+            mAudioControlWrapper.onAudioFocusChange(usage, zoneId, AUDIOFOCUS_LOSS);
+        } else {
+            Log.w(TAG,
+                    "Failed to abandon focus for usage " + AudioAttributes.usageToString(usage)
+                            + " and zoneId " + zoneId);
+        }
+    }
+
+    private AudioAttributes generateAudioAttributes(int usage, int zoneId) {
+        AudioAttributes.Builder builder = new AudioAttributes.Builder();
+        Bundle bundle = new Bundle();
+        bundle.putInt(CarAudioManager.AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID, zoneId);
+        builder.addBundle(bundle);
+
+        if (AudioAttributes.isSystemUsage(usage)) {
+            builder.setSystemUsage(usage);
+        } else {
+            builder.setUsage(usage);
+        }
+        return builder.build();
+    }
+
+    private AudioFocusRequest generateFocusRequestLocked(int usage, int zoneId, int focusGain) {
+        AudioAttributes attributes = generateAudioAttributes(usage, zoneId);
+        return new AudioFocusRequest.Builder(focusGain)
+                .setAudioAttributes(attributes)
+                .setOnAudioFocusChangeListener((int focusChange) -> {
+                    onAudioFocusChange(usage, zoneId, focusChange);
+                })
+                .build();
+    }
+
+    private void onAudioFocusChange(int usage, int zoneId, int focusChange) {
+        synchronized (mLock) {
+            HalAudioFocusRequest currentRequest = mHalFocusRequestsByZoneAndUsage.get(zoneId).get(
+                    usage);
+            if (currentRequest != null) {
+                if (focusChange == AUDIOFOCUS_LOSS) {
+                    mHalFocusRequestsByZoneAndUsage.get(zoneId).remove(usage);
+                } else {
+                    currentRequest.mFocusStatus = focusChange;
+                }
+                mAudioControlWrapper.onAudioFocusChange(usage, zoneId, focusChange);
+            }
+
+        }
+    }
+
+    private void makeAudioFocusRequestLocked(@AttributeUsage int usage, int zoneId, int focusGain) {
+        AudioFocusRequest audioFocusRequest = generateFocusRequestLocked(usage, zoneId, focusGain);
+
+        int requestResult = mAudioManager.requestAudioFocus(audioFocusRequest);
+
+        int resultingFocusGain = focusGain;
+
+        if (requestResult == AUDIOFOCUS_REQUEST_GRANTED) {
+            HalAudioFocusRequest halAudioFocusRequest = new HalAudioFocusRequest(audioFocusRequest,
+                    focusGain);
+            mHalFocusRequestsByZoneAndUsage.get(zoneId).append(usage, halAudioFocusRequest);
+        } else if (requestResult == AUDIOFOCUS_REQUEST_FAILED) {
+            resultingFocusGain = AUDIOFOCUS_LOSS;
+        } else if (requestResult == AUDIOFOCUS_REQUEST_DELAYED) {
+            Log.w(TAG, "Delayed result for request with usage "
+                    + AudioAttributes.usageToString(usage) + ", zoneId " + zoneId
+                    + ", and focusGain " + focusGain);
+            resultingFocusGain = AUDIOFOCUS_LOSS;
+        }
+
+        mAudioControlWrapper.onAudioFocusChange(usage, zoneId, resultingFocusGain);
+    }
+
+    private final class HalAudioFocusRequest {
+        final AudioFocusRequest mAudioFocusRequest;
+
+        int mFocusStatus;
+
+        HalAudioFocusRequest(AudioFocusRequest audioFocusRequest, int focusStatus) {
+            mAudioFocusRequest = audioFocusRequest;
+            mFocusStatus = focusStatus;
+        }
+    }
+}
diff --git a/service/src/com/android/car/cluster/InstrumentClusterService.java b/service/src/com/android/car/cluster/InstrumentClusterService.java
index cc0a6b7..94f31d2 100644
--- a/service/src/com/android/car/cluster/InstrumentClusterService.java
+++ b/service/src/com/android/car/cluster/InstrumentClusterService.java
@@ -16,16 +16,19 @@
 package com.android.car.cluster;
 
 import static android.car.cluster.renderer.InstrumentClusterRenderingService.EXTRA_BUNDLE_KEY_FOR_INSTRUMENT_CLUSTER_HELPER;
+import static android.car.settings.CarSettings.Global.DISABLE_INSTRUMENTATION_SERVICE;
 
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.ActivityOptions;
+import android.car.Car;
 import android.car.CarAppFocusManager;
 import android.car.cluster.IInstrumentClusterManagerCallback;
 import android.car.cluster.IInstrumentClusterManagerService;
 import android.car.cluster.renderer.IInstrumentCluster;
 import android.car.cluster.renderer.IInstrumentClusterHelper;
 import android.car.cluster.renderer.IInstrumentClusterNavigation;
+import android.car.navigation.CarNavigationInstrumentCluster;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -37,6 +40,7 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -48,12 +52,15 @@
 import com.android.car.CarLocalServices;
 import com.android.car.CarLog;
 import com.android.car.CarServiceBase;
+import com.android.car.ICarImpl;
 import com.android.car.R;
 import com.android.car.am.FixedActivityService;
 import com.android.car.user.CarUserService;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
 import java.util.Objects;
 
 /**
@@ -67,6 +74,9 @@
     private static final String TAG = CarLog.TAG_CLUSTER;
     private static final ContextOwner NO_OWNER = new ContextOwner(0, 0);
 
+    private static final long RENDERER_SERVICE_WAIT_TIMEOUT_MS = 5000;
+    private static final long RENDERER_WAIT_MAX_RETRY = 2;
+
     private final Context mContext;
     private final AppFocusService mAppFocusService;
     private final CarInputService mCarInputService;
@@ -83,17 +93,64 @@
     private IInstrumentCluster mRendererService;
     // If renderer service crashed / stopped and this class fails to rebind with it immediately,
     // we should wait some time before next attempt. This may happen during APK update for example.
-    @GuardedBy("mLock")
-    private DeferredRebinder mDeferredRebinder;
+    private final DeferredRebinder mDeferredRebinder;
     // Whether {@link android.car.cluster.renderer.InstrumentClusterRendererService} is bound
     // (although not necessarily connected)
     @GuardedBy("mLock")
     private boolean mRendererBound = false;
 
+    private final String mRenderingServiceConfig;
+
+    @GuardedBy("mLock")
+    private IInstrumentClusterNavigation mIInstrumentClusterNavigationFromRenderer;
+
+    private final IInstrumentClusterNavigation mIInstrumentClusterNavigationnWrapper =
+            new IInstrumentClusterNavigation.Stub() {
+        @Override
+        public void onNavigationStateChanged(Bundle bundle) {
+            ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_NAVIGATION_MANAGER);
+            assertNavigationFocus();
+            // No retry here as new events will be sent later.
+            IInstrumentClusterNavigation navigationBinder = getNavigationBinder(
+                    /* retryOnFail= */ false);
+            if (navigationBinder == null) {
+                Log.e(TAG, "onNavigationStateChanged failed, renderer not ready, Bundle:"
+                        + bundle);
+                return;
+            }
+            try {
+                navigationBinder.onNavigationStateChanged(bundle);
+            } catch (RemoteException e) {
+                Log.e(TAG, "onNavigationStateChanged failed, bundle:" + bundle, e);
+            }
+        }
+
+        @Override
+        public CarNavigationInstrumentCluster getInstrumentClusterInfo() {
+            ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_NAVIGATION_MANAGER);
+            // Failure in this call leads into an issue in the client, so throw exception
+            // when it cannot be recovered / retried.
+            for (int i = 0; i < RENDERER_WAIT_MAX_RETRY; i++) {
+                IInstrumentClusterNavigation navigationBinder = getNavigationBinder(
+                        /* retryOnFail= */ true);
+                if (navigationBinder == null) {
+                    continue;
+                }
+                try {
+                    return navigationBinder.getInstrumentClusterInfo();
+                } catch (RemoteException e) {
+                    Log.e(TAG, "getInstrumentClusterInfo failed", e);
+                }
+            }
+            throw new IllegalStateException("cannot access renderer service");
+        }
+    };
+
     /**
      * Connection to {@link android.car.cluster.renderer.InstrumentClusterRendererService}
      */
-    private final ServiceConnection mRendererServiceConnection = new ServiceConnection() {
+    @VisibleForTesting
+    final ServiceConnection mRendererServiceConnection = new ServiceConnection() {
         @Override
         public void onServiceConnected(ComponentName name, IBinder binder) {
             if (Log.isLoggable(TAG, Log.DEBUG)) {
@@ -104,6 +161,7 @@
             synchronized (mLock) {
                 mRendererService = service;
                 navContextOwner = mNavContextOwner;
+                mLock.notifyAll();
             }
             if (navContextOwner != null && service != null) {
                 notifyNavContextOwnerChanged(service, navContextOwner);
@@ -116,16 +174,13 @@
                 Log.d(TAG, "onServiceDisconnected, name: " + name);
             }
             mContext.unbindService(this);
-            DeferredRebinder rebinder;
             synchronized (mLock) {
                 mRendererBound = false;
                 mRendererService = null;
-                if (mDeferredRebinder == null) {
-                    mDeferredRebinder = new DeferredRebinder();
-                }
-                rebinder = mDeferredRebinder;
+                mIInstrumentClusterNavigationFromRenderer = null;
+
             }
-            rebinder.rebind();
+            mDeferredRebinder.rebind();
         }
     };
 
@@ -156,6 +211,53 @@
         mContext = context;
         mAppFocusService = appFocusService;
         mCarInputService = carInputService;
+        mRenderingServiceConfig = mContext.getString(R.string.instrumentClusterRendererService);
+        mDeferredRebinder = new DeferredRebinder(this);
+    }
+
+    @GuardedBy("mLock")
+    private IInstrumentCluster waitForRendererLocked() {
+        if (mRendererService == null) {
+            try {
+                mLock.wait(RENDERER_SERVICE_WAIT_TIMEOUT_MS);
+            } catch (InterruptedException e) {
+                Log.d(TAG, "waitForRenderer, interrupted", e);
+                Thread.currentThread().interrupt();
+            }
+        }
+        return mRendererService;
+    }
+
+    private IInstrumentClusterNavigation getNavigationBinder(boolean retryOnFail) {
+        IInstrumentCluster renderer;
+        synchronized (mLock) {
+            if (mIInstrumentClusterNavigationFromRenderer != null) {
+                return mIInstrumentClusterNavigationFromRenderer;
+            }
+            renderer = waitForRendererLocked();
+        }
+        IInstrumentClusterNavigation navigationBinder = null;
+        for (int i = 0; i < RENDERER_WAIT_MAX_RETRY; i++) {
+            if (renderer == null) {
+                synchronized (mLock) {
+                    renderer = waitForRendererLocked();
+                }
+            }
+            try {
+                navigationBinder = renderer.getNavigationService();
+                break;
+            } catch (RemoteException e) {
+                Log.e(TAG, "RemoteException from renderer", e);
+                renderer = null;
+            }
+        }
+        if (navigationBinder == null) {
+            return navigationBinder;
+        }
+        synchronized (mLock) {
+            mIInstrumentClusterNavigationFromRenderer = navigationBinder;
+        }
+        return navigationBinder;
     }
 
     @Override
@@ -168,8 +270,17 @@
         mCarInputService.setInstrumentClusterKeyListener(this /* KeyEventListener */);
         // TODO(b/124246323) Start earlier once data storage for cluster is clarified
         //  for early boot.
+        if (!isRendererServiceEnabled()) {
+            synchronized (mLock) {
+                mRendererBound = false;
+            }
+            return;
+        }
         CarLocalServices.getService(CarUserService.class).runOnUser0Unlock(() -> {
-            mRendererBound = bindInstrumentClusterRendererService();
+            boolean bound = bindInstrumentClusterRendererService();
+            synchronized (mLock) {
+                mRendererBound = bound;
+            }
         });
     }
 
@@ -180,18 +291,25 @@
         }
 
         mAppFocusService.unregisterContextOwnerChangedCallback(this);
-        if (mRendererBound) {
-            mContext.unbindService(mRendererServiceConnection);
-            mRendererBound = false;
+        synchronized (mLock) {
+            if (mRendererBound) {
+                mContext.unbindService(mRendererServiceConnection);
+                mRendererBound = false;
+            }
         }
     }
 
     @Override
     public void dump(PrintWriter writer) {
         writer.println("**" + getClass().getSimpleName() + "**");
-        writer.println("bound with renderer: " + mRendererBound);
-        writer.println("renderer service: " + mRendererService);
-        writer.println("context owner: " + mNavContextOwner);
+        synchronized (mLock) {
+            writer.println("bound with renderer: " + mRendererBound);
+            writer.println("renderer service: " + mRendererService);
+            writer.println("context owner: " + mNavContextOwner);
+            writer.println("mRenderingServiceConfig:" + mRenderingServiceConfig);
+            writer.println("mIInstrumentClusterNavigationFromRenderer:"
+                    + mIInstrumentClusterNavigationFromRenderer);
+        }
     }
 
     @Override
@@ -204,6 +322,23 @@
         changeNavContextOwner(appType, uid, pid, false);
     }
 
+    private void assertNavigationFocus() {
+        int uid = Binder.getCallingUid();
+        int pid = Binder.getCallingPid();
+        synchronized (mLock) {
+            if (uid == mNavContextOwner.uid && pid == mNavContextOwner.pid) {
+                return;
+            }
+        }
+        // Stored one failed. There can be a delay, so check with real one again.
+        AppFocusService afs = CarLocalServices.getService(AppFocusService.class);
+        if (afs != null && afs.isFocusOwner(uid, pid,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION)) {
+            return;
+        }
+        throw new IllegalStateException("Client not owning APP_FOCUS_TYPE_NAVIGATION");
+    }
+
     private void changeNavContextOwner(int appType, int uid, int pid, boolean acquire) {
         if (appType != CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION) {
             return;
@@ -241,17 +376,29 @@
         }
     }
 
+    private boolean isRendererServiceEnabled() {
+        if (TextUtils.isEmpty(mRenderingServiceConfig)) {
+            Log.d(TAG, "Instrument cluster renderer was not configured");
+            return false;
+        }
+        boolean explicitlyDisabled = "true".equals(Settings.Global
+                .getString(mContext.getContentResolver(), DISABLE_INSTRUMENTATION_SERVICE));
+        if (explicitlyDisabled) {
+            Log.i(TAG, "Instrument cluster renderer explicitly disabled by settings");
+            return false;
+        }
+        return true;
+    }
+
     private boolean bindInstrumentClusterRendererService() {
-        String rendererService = mContext.getString(R.string.instrumentClusterRendererService);
-        if (TextUtils.isEmpty(rendererService)) {
-            Log.i(TAG, "Instrument cluster renderer was not configured");
+        if (!isRendererServiceEnabled()) {
             return false;
         }
 
-        Log.d(TAG, "bindInstrumentClusterRendererService, component: " + rendererService);
+        Log.d(TAG, "bindInstrumentClusterRendererService, component: " + mRenderingServiceConfig);
 
         Intent intent = new Intent();
-        intent.setComponent(ComponentName.unflattenFromString(rendererService));
+        intent.setComponent(ComponentName.unflattenFromString(mRenderingServiceConfig));
         // Litle bit inefficiency here as Intent.getIBinderExtra() is a hidden API.
         Bundle bundle = new Bundle();
         bundle.putBinder(EXTRA_BUNDLE_KEY_FOR_INSTRUMENT_CLUSTER_HELPER,
@@ -263,13 +410,11 @@
 
     @Nullable
     public IInstrumentClusterNavigation getNavigationService() {
-        try {
-            IInstrumentCluster service = getInstrumentClusterRendererService();
-            return service == null ? null : service.getNavigationService();
-        } catch (RemoteException e) {
-            Log.e(TAG, "getNavigationServiceBinder" , e);
+        if (!isRendererServiceEnabled()) {
             return null;
+
         }
+        return mIInstrumentClusterNavigationnWrapper;
     }
 
     /**
@@ -297,11 +442,9 @@
     }
 
     private IInstrumentCluster getInstrumentClusterRendererService() {
-        IInstrumentCluster service;
         synchronized (mLock) {
-            service = mRendererService;
+            return mRendererService;
         }
-        return service;
     }
 
     private static class ContextOwner {
@@ -356,14 +499,27 @@
         }
     }
 
-    private class DeferredRebinder extends Handler {
+    private static final class DeferredRebinder extends Handler {
+        private static final String TAG = DeferredRebinder.class.getSimpleName();
+
         private static final long NEXT_REBIND_ATTEMPT_DELAY_MS = 1000L;
         private static final int NUMBER_OF_ATTEMPTS = 10;
 
-        public void rebind() {
-            mRendererBound = bindInstrumentClusterRendererService();
+        private final WeakReference<InstrumentClusterService> mService;
 
-            if (!mRendererBound) {
+        private DeferredRebinder(InstrumentClusterService service) {
+            mService = new WeakReference<InstrumentClusterService>(service);
+        }
+
+        public void rebind() {
+            InstrumentClusterService service = mService.get();
+            if (service == null) {
+                Log.i(TAG, "rebind null service");
+                return;
+            }
+            service.mRendererBound = service.bindInstrumentClusterRendererService();
+
+            if (!service.mRendererBound) {
                 removeMessages(0);
                 sendMessageDelayed(obtainMessage(0, NUMBER_OF_ATTEMPTS, 0),
                         NEXT_REBIND_ATTEMPT_DELAY_MS);
@@ -372,9 +528,14 @@
 
         @Override
         public void handleMessage(Message msg) {
-            mRendererBound = bindInstrumentClusterRendererService();
+            InstrumentClusterService service = mService.get();
+            if (service == null) {
+                Log.i(TAG, "handleMessage null service");
+                return;
+            }
+            service.mRendererBound = service.bindInstrumentClusterRendererService();
 
-            if (mRendererBound) {
+            if (service.mRendererBound) {
                 Log.w(TAG, "Failed to bound to render service, next attempt in "
                         + NEXT_REBIND_ATTEMPT_DELAY_MS + "ms.");
 
diff --git a/service/src/com/android/car/garagemode/Controller.java b/service/src/com/android/car/garagemode/Controller.java
index 9380409..d7cda0a 100644
--- a/service/src/com/android/car/garagemode/Controller.java
+++ b/service/src/com/android/car/garagemode/Controller.java
@@ -24,8 +24,10 @@
 import android.content.Intent;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.UserHandle;
 
 import com.android.car.CarLocalServices;
+import com.android.car.systeminterface.SystemInterface;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.List;
@@ -118,8 +120,9 @@
      * @param i intent that contains broadcast data
      */
     void sendBroadcast(Intent i) {
+        SystemInterface systemInterface = CarLocalServices.getService(SystemInterface.class);
         LOG.d("Sending broadcast with action: " + i.getAction());
-        mContext.sendBroadcast(i);
+        systemInterface.sendBroadcastAsUser(i, UserHandle.ALL);
     }
 
     /**
diff --git a/service/src/com/android/car/garagemode/GarageMode.java b/service/src/com/android/car/garagemode/GarageMode.java
index bdb7a82..5698657 100644
--- a/service/src/com/android/car/garagemode/GarageMode.java
+++ b/service/src/com/android/car/garagemode/GarageMode.java
@@ -25,8 +25,10 @@
 import android.util.ArraySet;
 
 import com.android.car.CarLocalServices;
-import com.android.car.CarStatsLog;
+import com.android.car.CarPowerManagementService;
+import com.android.car.CarStatsLogHelper;
 import com.android.car.user.CarUserService;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.ArrayList;
@@ -64,36 +66,58 @@
     private static final int ADDITIONAL_CHECKS_TO_DO = 1;
 
     private final Controller mController;
+    private final JobScheduler mJobScheduler;
+    private final Object mLock = new Object();
+    private final Handler mHandler;
 
+    private CarPowerManagementService mCarPowerManagementService;
+    @GuardedBy("mLock")
     private boolean mGarageModeActive;
+    @GuardedBy("mLock")
     private int mAdditionalChecksToDo = ADDITIONAL_CHECKS_TO_DO;
-    private JobScheduler mJobScheduler;
-    private Handler mHandler;
-    private Runnable mRunnable = new Runnable() {
+    @GuardedBy("mLock")
+    private boolean mIdleCheckerIsRunning;
+    @GuardedBy("mLock")
+    private List<String> mPendingJobs = new ArrayList<>();
+
+    private final Runnable mRunnable = new Runnable() {
         @Override
         public void run() {
+            if (!mGarageModeActive) {
+                LOG.d("Garage Mode is inactive. Stopping the idle-job checker.");
+                finish();
+                return;
+            }
             int numberRunning = numberOfIdleJobsRunning();
             if (numberRunning > 0) {
                 LOG.d("" + numberRunning + " jobs are still running. Need to wait more ...");
-                mAdditionalChecksToDo = ADDITIONAL_CHECKS_TO_DO;
+                synchronized (mLock) {
+                    mAdditionalChecksToDo = ADDITIONAL_CHECKS_TO_DO;
+                }
             } else {
                 // No idle-mode jobs are running.
                 // Are there any scheduled idle jobs that could run now?
-                int numberReadyToRun = numberOfJobsPending();
+                int numberReadyToRun = numberOfPendingJobs();
                 if (numberReadyToRun == 0) {
                     LOG.d("No jobs are running. No jobs are pending. Exiting Garage Mode.");
                     finish();
                     return;
                 }
-                if (mAdditionalChecksToDo == 0) {
+                int numAdditionalChecks;
+                synchronized (mLock) {
+                    numAdditionalChecks = mAdditionalChecksToDo;
+                    if (mAdditionalChecksToDo > 0) {
+                        mAdditionalChecksToDo--;
+                    }
+                }
+                if (numAdditionalChecks == 0) {
                     LOG.d("No jobs are running. Waited too long for "
                             + numberReadyToRun + " pending jobs. Exiting Garage Mode.");
                     finish();
                     return;
                 }
-                LOG.d("No jobs are running. Waiting " + mAdditionalChecksToDo
+                LOG.d("No jobs are running. Waiting " + numAdditionalChecks
                         + " more cycles for " + numberReadyToRun + " pending jobs.");
-                mAdditionalChecksToDo--;
             }
             mHandler.postDelayed(mRunnable, JOB_SNAPSHOT_UPDATE_FREQUENCY_MS);
         }
@@ -104,13 +128,12 @@
         public void run() {
             int userToStop = UserHandle.USER_SYSTEM; // BG user never becomes system user.
             int remainingUsersToStop = 0;
-            synchronized (this) {
+            synchronized (mLock) {
                 remainingUsersToStop = mStartedBackgroundUsers.size();
-                if (remainingUsersToStop > 0) {
-                    userToStop = mStartedBackgroundUsers.valueAt(0);
-                } else {
+                if (remainingUsersToStop < 1) {
                     return;
                 }
+                userToStop = mStartedBackgroundUsers.valueAt(0);
             }
             if (numberOfIdleJobsRunning() == 0) { // all jobs done or stopped.
                 // Keep user until job scheduling is stopped. Otherwise, it can crash jobs.
@@ -120,10 +143,10 @@
                     LOG.i("Stopping background user:" + userToStop + " remaining users:"
                             + (remainingUsersToStop - 1));
                 }
-                synchronized (this) {
+                synchronized (mLock) {
                     mStartedBackgroundUsers.remove(userToStop);
                     if (mStartedBackgroundUsers.size() == 0) {
-                        LOG.i("all background users stopped");
+                        LOG.i("All background users have stopped");
                         return;
                     }
                 }
@@ -135,8 +158,9 @@
         }
     };
 
-
+    @GuardedBy("mLock")
     private CompletableFuture<Void> mFuture;
+    @GuardedBy("mLock")
     private ArraySet<Integer> mStartedBackgroundUsers = new ArraySet<>();
 
     GarageMode(Controller controller) {
@@ -147,7 +171,9 @@
     }
 
     boolean isGarageModeActive() {
-        return mGarageModeActive;
+        synchronized (mLock) {
+            return mGarageModeActive;
+        }
     }
 
     List<String> dump() {
@@ -155,6 +181,8 @@
         if (!mGarageModeActive) {
             return outString;
         }
+        outString.add("GarageMode idle checker is " + (mIdleCheckerIsRunning ? "" : "not ")
+                + "running");
         List<String> jobList = new ArrayList<>();
         int numJobs = getListOfIdleJobsRunning(jobList);
         if (numJobs > 0) {
@@ -176,95 +204,123 @@
 
     void enterGarageMode(CompletableFuture<Void> future) {
         LOG.d("Entering GarageMode");
-        synchronized (this) {
+        if (mCarPowerManagementService == null) {
+            mCarPowerManagementService = CarLocalServices.getService(
+                    CarPowerManagementService.class);
+        }
+        if (mCarPowerManagementService != null
+                && mCarPowerManagementService.garageModeShouldExitImmediately()) {
+            if (future != null && !future.isDone()) {
+                future.complete(null);
+            }
+            synchronized (mLock) {
+                mGarageModeActive = false;
+            }
+            return;
+        }
+        synchronized (mLock) {
             mGarageModeActive = true;
         }
         updateFuture(future);
-        broadcastSignalToJobSchedulerTo(true);
-        CarStatsLog.logGarageModeStart();
+        broadcastSignalToJobScheduler(true);
+        CarStatsLogHelper.logGarageModeStart();
         startMonitoringThread();
         ArrayList<Integer> startedUsers =
                 CarLocalServices.getService(CarUserService.class).startAllBackgroundUsers();
-        synchronized (this) {
+        synchronized (mLock) {
             mStartedBackgroundUsers.addAll(startedUsers);
         }
     }
 
-    synchronized void cancel() {
-        broadcastSignalToJobSchedulerTo(false);
-        if (mFuture != null && !mFuture.isDone()) {
-            mFuture.cancel(true);
+    void cancel() {
+        broadcastSignalToJobScheduler(false);
+        synchronized (mLock) {
+            if (mFuture == null) {
+                cleanupGarageMode();
+            } else if (!mFuture.isDone()) {
+                mFuture.cancel(true);
+            }
+            mFuture = null;
+            startBackgroundUserStoppingLocked();
         }
-        mFuture = null;
-        startBackgroundUserStopping();
     }
 
-    synchronized void finish() {
-        broadcastSignalToJobSchedulerTo(false);
-        CarStatsLog.logGarageModeStop();
+    void finish() {
+        synchronized (mLock) {
+            if (!mIdleCheckerIsRunning) {
+                LOG.i("Finishing Garage Mode. Idle checker is not running.");
+                return;
+            }
+            mIdleCheckerIsRunning = false;
+        }
+        broadcastSignalToJobScheduler(false);
+        CarStatsLogHelper.logGarageModeStop();
         mController.scheduleNextWakeup();
-        synchronized (this) {
-            if (mFuture != null && !mFuture.isDone()) {
+        synchronized (mLock) {
+            if (mFuture == null) {
+                cleanupGarageMode();
+            } else if (!mFuture.isDone()) {
                 mFuture.complete(null);
             }
             mFuture = null;
+            startBackgroundUserStoppingLocked();
         }
-        startBackgroundUserStopping();
     }
 
     private void cleanupGarageMode() {
         LOG.d("Cleaning up GarageMode");
-        synchronized (this) {
+        synchronized (mLock) {
             mGarageModeActive = false;
+            stopMonitoringThread();
+            if (mIdleCheckerIsRunning) {
+                // The idle checker has not completed.
+                // Schedule it now so it completes promptly.
+                mHandler.post(mRunnable);
+            }
+            startBackgroundUserStoppingLocked();
         }
-        stopMonitoringThread();
-        mHandler.removeCallbacks(mRunnable);
-        startBackgroundUserStopping();
     }
 
-    private void startBackgroundUserStopping() {
-        synchronized (this) {
-            if (mStartedBackgroundUsers.size() > 0) {
-                mHandler.postDelayed(mStopUserCheckRunnable, USER_STOP_CHECK_INTERVAL);
-            }
+    private void startBackgroundUserStoppingLocked() {
+        if (mStartedBackgroundUsers.size() > 0) {
+            mHandler.postDelayed(mStopUserCheckRunnable, USER_STOP_CHECK_INTERVAL);
         }
     }
 
     private void updateFuture(CompletableFuture<Void> future) {
-        synchronized (this) {
+        synchronized (mLock) {
             mFuture = future;
-        }
-        if (mFuture != null) {
-            mFuture.whenComplete((result, exception) -> {
-                if (exception == null) {
-                    LOG.d("GarageMode completed normally");
-                } else if (exception instanceof CancellationException) {
-                    LOG.d("GarageMode was canceled");
-                } else {
-                    LOG.e("GarageMode ended due to exception: ", exception);
-                }
-                cleanupGarageMode();
-            });
+            if (mFuture != null) {
+                mFuture.whenComplete((result, exception) -> {
+                    if (exception == null) {
+                        LOG.d("GarageMode completed normally");
+                    } else if (exception instanceof CancellationException) {
+                        LOG.d("GarageMode was canceled");
+                    } else {
+                        LOG.e("GarageMode ended due to exception: ", exception);
+                    }
+                    cleanupGarageMode();
+                });
+            }
         }
     }
 
-    private void broadcastSignalToJobSchedulerTo(boolean enableGarageMode) {
+    private void broadcastSignalToJobScheduler(boolean enableGarageMode) {
         Intent i = new Intent();
-        if (enableGarageMode) {
-            i.setAction(ACTION_GARAGE_MODE_ON);
-        } else {
-            i.setAction(ACTION_GARAGE_MODE_OFF);
-        }
+        i.setAction(enableGarageMode ? ACTION_GARAGE_MODE_ON : ACTION_GARAGE_MODE_OFF);
         i.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_NO_ABORT);
         mController.sendBroadcast(i);
     }
 
-    private synchronized void startMonitoringThread() {
-        mAdditionalChecksToDo = ADDITIONAL_CHECKS_TO_DO;
+    private void startMonitoringThread() {
+        synchronized (mLock) {
+            mIdleCheckerIsRunning = true;
+            mAdditionalChecksToDo = ADDITIONAL_CHECKS_TO_DO;
+        }
         mHandler.postDelayed(mRunnable, JOB_SNAPSHOT_INITIAL_UPDATE_MS);
     }
 
-    private synchronized void stopMonitoringThread() {
+    private void stopMonitoringThread() {
         mHandler.removeCallbacks(mRunnable);
     }
 
@@ -293,7 +349,7 @@
         return count;
     }
 
-    private int numberOfJobsPending() {
+    private int numberOfPendingJobs() {
         return getListOfPendingJobs(null);
     }
 
diff --git a/service/src/com/android/car/hal/CarPropertyUtils.java b/service/src/com/android/car/hal/CarPropertyUtils.java
index 2d0e6ad..92258c2 100644
--- a/service/src/com/android/car/hal/CarPropertyUtils.java
+++ b/service/src/com/android/car/hal/CarPropertyUtils.java
@@ -28,6 +28,7 @@
 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
@@ -39,6 +40,10 @@
     /* Utility class has no public constructor */
     private CarPropertyUtils() {}
 
+    private static final int[] DEFAULT_AREAIDS = {VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL};
+    // Length of mixed type properties' configArray should always be 9
+    private static final int CONFIG_ARRAY_LENGTH = 9;
+
     /** Converts {@link VehiclePropValue} to {@link CarPropertyValue} */
     static CarPropertyValue<?> toCarPropertyValue(
             VehiclePropValue halValue, int propertyId) {
@@ -84,13 +89,34 @@
         } else if (byte[].class == clazz) {
             byte[] halData = toByteArray(v.bytes);
             return new CarPropertyValue<>(propertyId, areaId, status, timestamp, halData);
-        } else /* Object.class */ {
-            Object[] values = getRawValueList(clazz, v).toArray();
-            return new CarPropertyValue<>(propertyId, areaId, status, timestamp,
-                    values.length == 1 ? values[0] : values);
+        } else {
+            throw new IllegalArgumentException("Unexpected type in: " + propertyId);
         }
     }
 
+    /** Converts {@link VehiclePropValue} to {@link CarPropertyValue} for MIXED type properties*/
+    static CarPropertyValue<?> toMixedCarPropertyValue(
+            VehiclePropValue halValue, int propertyId, boolean containBoolean) {
+        int areaId = halValue.areaId;
+        int status = halValue.status;
+        long timestamp = halValue.timestamp;
+        VehiclePropValue.RawValue value = halValue.value;
+
+        List<Object> valuesList = new ArrayList<>();
+        valuesList.add(value.stringValue);
+        if (containBoolean) {
+            boolean boolValue = value.int32Values.get(0) == 1;
+            valuesList.add(boolValue);
+            valuesList.addAll(value.int32Values.subList(1, value.int32Values.size()));
+        } else {
+            valuesList.addAll(value.int32Values);
+        }
+        valuesList.addAll(value.int64Values);
+        valuesList.addAll(value.floatValues);
+        valuesList.addAll(value.bytes);
+        return new CarPropertyValue<>(propertyId, areaId, status, timestamp, valuesList.toArray());
+    }
+
     /** Converts {@link CarPropertyValue} to {@link VehiclePropValue} */
     static VehiclePropValue toVehiclePropValue(CarPropertyValue carProp, int halPropId) {
         VehiclePropValue vehicleProp = new VehiclePropValue();
@@ -102,10 +128,6 @@
 
         if (o instanceof Boolean) {
             v.int32Values.add(((Boolean) o) ? 1 : 0);
-        } else if (o instanceof Boolean[]) {
-            for (Boolean b : (Boolean[]) o) {
-                v.int32Values.add(b ? 1 : 0);
-            }
         } else if (o instanceof Integer) {
             v.int32Values.add((Integer) o);
         } else if (o instanceof Integer[]) {
@@ -132,21 +154,92 @@
     }
 
     /**
+     * Converts {@link CarPropertyValue} to {@link VehiclePropValue} for MIXED type properties
+     * configArray[0], 1 indicates the property has a String value
+     * configArray[1], 1 indicates the property has a Boolean value .
+     * configArray[2], 1 indicates the property has a Integer value.
+     * configArray[3], the number indicates the size of Integer[]  in the property.
+     * configArray[4], 1 indicates the property has a Long value .
+     * configArray[5], the number indicates the size of Long[]  in the property.
+     * configArray[6], 1 indicates the property has a Float value .
+     * configArray[7], the number indicates the size of Float[] in the property.
+     * configArray[8], the number indicates the size of byte[] in the property.
+     *
+     * For example:
+     * configArray = {1, 1, 1, 3, 0, 0, 0, 0, 0} indicates the property has a String value, a
+     * Boolean value, an Integer value, an Integer array with 3 enums.
+     */
+    static VehiclePropValue toMixedVehiclePropValue(CarPropertyValue carProp,
+            int halPropId, int[] configArray) {
+        if (configArray.length != CONFIG_ARRAY_LENGTH) {
+            throw new IllegalArgumentException("Unexpected configArray in:" + carProp);
+        }
+        VehiclePropValue vehicleProp = new VehiclePropValue();
+        vehicleProp.prop = halPropId;
+        vehicleProp.areaId = carProp.getAreaId();
+        VehiclePropValue.RawValue v = vehicleProp.value;
+
+        Object[] values = (Object[]) carProp.getValue();
+        int indexOfValues = 0;
+        if (configArray[0] != 0) {
+            // Add a string value
+            v.stringValue = (String) values[indexOfValues];
+            indexOfValues++;
+        }
+
+        if (configArray[1] != 0) {
+            // Add a boolean value
+            v.int32Values.add((Boolean) values[indexOfValues] ? 1 : 0); // in HAL, 1 indicates true
+            indexOfValues++;
+        }
+
+        /*
+         * configArray[2], 1 indicates the property has a Integer value.
+         * configArray[3], the number indicates the size of Integer[]  in the property.
+         */
+        int integerSize = configArray[2] + configArray[3];
+        while (integerSize != 0) {
+            v.int32Values.add((Integer) values[indexOfValues]);
+            indexOfValues++;
+            integerSize--;
+        }
+        /* configArray[4], 1 indicates the property has a Long value .
+         * configArray[5], the number indicates the size of Long[]  in the property.
+         */
+        int longSize = configArray[4] + configArray[5];
+        while (longSize != 0) {
+            v.int64Values.add((Long) values[indexOfValues]);
+            indexOfValues++;
+            longSize--;
+        }
+        /* configArray[6], 1 indicates the property has a Float value .
+         * configArray[7], the number indicates the size of Float[] in the property.
+         */
+        int floatSize = configArray[6] + configArray[7];
+        while (floatSize != 0) {
+            v.floatValues.add((Float) values[indexOfValues]);
+            indexOfValues++;
+            floatSize--;
+        }
+
+        /* configArray[8], the number indicates the size of byte[] in the property. */
+        if (configArray[8] != 0) {
+            Collections.addAll(v.bytes, (Byte[]) values[indexOfValues]);
+        }
+        return vehicleProp;
+    }
+
+    /**
      * Converts {@link VehiclePropConfig} to {@link CarPropertyConfig}.
      */
     static CarPropertyConfig<?> toCarPropertyConfig(VehiclePropConfig p, int propertyId) {
         int areaType = getVehicleAreaType(p.prop & VehicleArea.MASK);
-        // Create list of areaIds for this property
-        int[] areas = new int[p.areaConfigs.size()];
-        for (int i=0; i<p.areaConfigs.size(); i++) {
-            areas[i] = p.areaConfigs.get(i).areaId;
-        }
 
         Class<?> clazz = getJavaClass(p.prop & VehiclePropertyType.MASK);
         if (p.areaConfigs.isEmpty()) {
             return CarPropertyConfig
                     .newBuilder(clazz, propertyId, areaType, /* capacity */ 1)
-                    .addAreas(areas)
+                    .addAreas(DEFAULT_AREAIDS)
                     .setAccess(p.access)
                     .setChangeMode(p.changeMode)
                     .setConfigArray(p.configArray)
@@ -177,14 +270,13 @@
                            classMatched(Long[].class, clazz) ||
                            classMatched(String.class, clazz) ||
                            classMatched(byte[].class, clazz) ||
-                           classMatched(Object.class, clazz)) {
+                           classMatched(Object[].class, clazz)) {
                     // These property types do not have min/max values
                     builder.addArea(area.areaId);
                 } else {
                     throw new IllegalArgumentException("Unexpected type: " + clazz);
                 }
             }
-
             return builder.build();
         }
     }
@@ -229,24 +321,12 @@
             case VehiclePropertyType.BYTES:
                 return byte[].class;
             case VehiclePropertyType.MIXED:
-                return Object.class;
+                return Object[].class;
             default:
                 throw new IllegalArgumentException("Unexpected type: " + toHexString(halType));
         }
     }
 
-    private static List getRawValueList(Class<?> clazz, VehiclePropValue.RawValue value) {
-        if (classMatched(Float.class, clazz) || classMatched(Float[].class, clazz)) {
-            return value.floatValues;
-        } else if (classMatched(Integer.class, clazz) || classMatched(Integer[].class, clazz)) {
-            return value.int32Values;
-        } else if (classMatched(Long.class, clazz) || classMatched(Long[].class, clazz)) {
-            return value.int64Values;
-        } else {
-            throw new IllegalArgumentException("Unexpected type: " + clazz);
-        }
-    }
-
     private static boolean classMatched(Class<?> class1, Class<?> class2) {
         return class1 == class2 || class1.getComponentType() == class2;
     }
diff --git a/service/src/com/android/car/hal/DiagnosticHalService.java b/service/src/com/android/car/hal/DiagnosticHalService.java
index d61c88a..fed4eca 100644
--- a/service/src/com/android/car/hal/DiagnosticHalService.java
+++ b/service/src/com/android/car/hal/DiagnosticHalService.java
@@ -28,6 +28,7 @@
 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyChangeMode;
+import android.os.ServiceSpecificException;
 import android.util.Log;
 import android.util.SparseArray;
 
@@ -47,9 +48,17 @@
  * Diagnostic HAL service supporting gathering diagnostic info from VHAL and translating it into
  * higher-level semantic information
  */
-public class DiagnosticHalService extends  HalServiceBase{
+public class DiagnosticHalService extends HalServiceBase {
     static final int OBD2_SELECTIVE_FRAME_CLEAR = 1;
-    static final boolean DEBUG = true;
+    static final boolean DEBUG = false;
+
+    private static final int[] SUPPORTED_PROPERTIES = new int[]{
+            VehicleProperty.OBD2_LIVE_FRAME,
+            VehicleProperty.OBD2_FREEZE_FRAME,
+            VehicleProperty.OBD2_FREEZE_FRAME_INFO,
+            VehicleProperty.OBD2_FREEZE_FRAME_CLEAR
+    };
+
     private final Object mLock = new Object();
     private final VehicleHal mVehicleHal;
 
@@ -110,13 +119,16 @@
     }
 
     @Override
-    public Collection<VehiclePropConfig> takeSupportedProperties(
-            Collection<VehiclePropConfig> allProperties) {
+    public int[] getAllSupportedProperties() {
+        return SUPPORTED_PROPERTIES;
+    }
+
+    @Override
+    public void takeProperties(Collection<VehiclePropConfig> properties) {
         if (DEBUG) {
             Log.d(CarLog.TAG_DIAGNOSTIC, "takeSupportedProperties");
         }
-        LinkedList<VehiclePropConfig> supportedProperties = new LinkedList<VehiclePropConfig>();
-        for (VehiclePropConfig vp : allProperties) {
+        for (VehiclePropConfig vp : properties) {
             int sensorType = getTokenForProperty(vp);
             if (sensorType == NOT_SUPPORTED_PROPERTY) {
                 if (DEBUG) {
@@ -127,20 +139,18 @@
                                 .toString());
                 }
             } else {
-                supportedProperties.add(vp);
                 synchronized (mLock) {
                     mSensorTypeToConfig.append(sensorType, vp);
                 }
             }
         }
-        return supportedProperties;
     }
 
     /**
      * Returns a unique token to be used to map this property to a higher-level sensor
      * This token will be stored in {@link DiagnosticHalService#mSensorTypeToConfig} to allow
      * callers to go from unique sensor identifiers to VehiclePropConfig objects
-     * @param config
+     * @param propConfig
      * @return SENSOR_TYPE_INVALID or a locally unique token
      */
     protected int getTokenForProperty(VehiclePropConfig propConfig) {
@@ -299,7 +309,7 @@
         }
         try {
             return mVehicleHal.get(propConfig.prop);
-        } catch (PropertyTimeoutException e) {
+        } catch (ServiceSpecificException e) {
             Log.e(CarLog.TAG_DIAGNOSTIC,
                     "property not ready 0x" + toHexString(propConfig.prop), e);
             return null;
@@ -396,7 +406,7 @@
     private final LinkedList<CarDiagnosticEvent> mEventsToDispatch = new LinkedList<>();
 
     @Override
-    public void handleHalEvents(List<VehiclePropValue> values) {
+    public void onHalEvents(List<VehiclePropValue> values) {
         for (VehiclePropValue value : values) {
             CarDiagnosticEvent event = createCarDiagnosticEvent(value);
             if (event != null) {
@@ -468,8 +478,8 @@
         try {
             VehiclePropValue value = mVehicleHal.get(VehicleProperty.OBD2_LIVE_FRAME);
             return createCarDiagnosticEvent(value);
-        } catch (PropertyTimeoutException e) {
-            Log.e(CarLog.TAG_DIAGNOSTIC, "timeout trying to read OBD2_LIVE_FRAME");
+        } catch (ServiceSpecificException e) {
+            Log.e(CarLog.TAG_DIAGNOSTIC, "Failed to read OBD2_LIVE_FRAME.", e);
             return null;
         } catch (IllegalArgumentException e) {
             Log.e(CarLog.TAG_DIAGNOSTIC, "illegal argument trying to read OBD2_LIVE_FRAME", e);
@@ -486,8 +496,8 @@
                 timestamps[i] = value.value.int64Values.get(i);
             }
             return timestamps;
-        } catch (PropertyTimeoutException e) {
-            Log.e(CarLog.TAG_DIAGNOSTIC, "timeout trying to read OBD2_FREEZE_FRAME_INFO");
+        } catch (ServiceSpecificException e) {
+            Log.e(CarLog.TAG_DIAGNOSTIC, "Failed to read OBD2_FREEZE_FRAME_INFO.", e);
             return null;
         } catch (IllegalArgumentException e) {
             Log.e(CarLog.TAG_DIAGNOSTIC,
@@ -504,8 +514,8 @@
         try {
             VehiclePropValue value = mVehicleHal.get(builder.build());
             return createCarDiagnosticEvent(value);
-        } catch (PropertyTimeoutException e) {
-            Log.e(CarLog.TAG_DIAGNOSTIC, "timeout trying to read OBD2_FREEZE_FRAME");
+        } catch (ServiceSpecificException e) {
+            Log.e(CarLog.TAG_DIAGNOSTIC, "Failed to read OBD2_FREEZE_FRAME.", e);
             return null;
         } catch (IllegalArgumentException e) {
             Log.e(CarLog.TAG_DIAGNOSTIC,
@@ -520,8 +530,8 @@
         builder.setInt64Value(timestamps);
         try {
             mVehicleHal.set(builder.build());
-        } catch (PropertyTimeoutException e) {
-            Log.e(CarLog.TAG_DIAGNOSTIC, "timeout trying to write OBD2_FREEZE_FRAME_CLEAR");
+        } catch (ServiceSpecificException e) {
+            Log.e(CarLog.TAG_DIAGNOSTIC, "Failed to write OBD2_FREEZE_FRAME_CLEAR.", e);
         } catch (IllegalArgumentException e) {
             Log.e(CarLog.TAG_DIAGNOSTIC,
                 "illegal argument trying to write OBD2_FREEZE_FRAME_CLEAR", e);
diff --git a/service/src/com/android/car/hal/HalClient.java b/service/src/com/android/car/hal/HalClient.java
index 383499f..bb96957 100644
--- a/service/src/com/android/car/hal/HalClient.java
+++ b/service/src/com/android/car/hal/HalClient.java
@@ -28,10 +28,13 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.util.Log;
 
 import com.android.car.CarLog;
+import com.android.internal.annotations.VisibleForTesting;
 
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
 
@@ -39,7 +42,11 @@
  * Vehicle HAL client. Interacts directly with Vehicle HAL interface {@link IVehicle}. Contains
  * some logic for retriable properties, redirects Vehicle notifications into given looper thread.
  */
-class  HalClient {
+final class HalClient {
+
+    private static final String TAG = CarLog.TAG_HAL;
+    private static final boolean DEBUG = false;
+
     /**
      * If call to vehicle HAL returns StatusCode.TRY_AGAIN, than {@link HalClient} will retry to
      * invoke that method again for this amount of milliseconds.
@@ -49,8 +56,9 @@
     private static final int SLEEP_BETWEEN_RETRIABLE_INVOKES_MS = 50;
 
     private final IVehicle mVehicle;
-
     private final IVehicleCallback mInternalCallback;
+    private final int mWaitCapMs;
+    private final int mSleepMs;
 
     /**
      * Create HalClient object
@@ -60,9 +68,18 @@
      * @param callback to propagate notifications from Vehicle HAL in the provided looper thread
      */
     HalClient(IVehicle vehicle, Looper looper, IVehicleCallback callback) {
+        this(vehicle, looper, callback, WAIT_CAP_FOR_RETRIABLE_RESULT_MS,
+                SLEEP_BETWEEN_RETRIABLE_INVOKES_MS);
+    }
+
+    @VisibleForTesting
+    HalClient(IVehicle vehicle, Looper looper, IVehicleCallback callback,
+            int waitCapMs, int sleepMs) {
         mVehicle = vehicle;
         Handler handler = new CallbackHandler(looper, callback);
         mInternalCallback = new VehicleCallback(handler);
+        mWaitCapMs = waitCapMs;
+        mSleepMs = sleepMs;
     }
 
     ArrayList<VehiclePropConfig> getAllPropConfigs() throws RemoteException {
@@ -77,56 +94,61 @@
         mVehicle.unsubscribe(mInternalCallback, prop);
     }
 
-    public void setValue(VehiclePropValue propValue) throws PropertyTimeoutException {
+    public void setValue(VehiclePropValue propValue) {
         int status = invokeRetriable(() -> {
             try {
                 return mVehicle.set(propValue);
             } catch (RemoteException e) {
-                Log.e(CarLog.TAG_HAL, "Failed to set value", e);
+                Log.e(TAG, getValueErrorMessage("set", propValue), e);
                 return StatusCode.TRY_AGAIN;
             }
-        }, WAIT_CAP_FOR_RETRIABLE_RESULT_MS, SLEEP_BETWEEN_RETRIABLE_INVOKES_MS);
+        }, mWaitCapMs, mSleepMs);
 
         if (StatusCode.INVALID_ARG == status) {
-            throw new IllegalArgumentException(
-                    String.format("Failed to set value for: 0x%x, areaId: 0x%x",
-                            propValue.prop, propValue.areaId));
-        }
-
-        if (StatusCode.TRY_AGAIN == status) {
-            throw new PropertyTimeoutException(propValue.prop);
+            throw new IllegalArgumentException(getValueErrorMessage("set", propValue));
         }
 
         if (StatusCode.OK != status) {
-            throw new IllegalStateException(
-                    String.format("Failed to set property: 0x%x, areaId: 0x%x, "
-                            + "code: %d", propValue.prop, propValue.areaId, status));
+            Log.e(TAG, getPropertyErrorMessage("set", propValue, status));
+            throw new ServiceSpecificException(status,
+                    "Failed to set property: 0x" + Integer.toHexString(propValue.prop)
+                            + " in areaId: 0x" + Integer.toHexString(propValue.areaId));
         }
     }
 
-    VehiclePropValue getValue(VehiclePropValue requestedPropValue) throws PropertyTimeoutException {
+    private String getValueErrorMessage(String action, VehiclePropValue propValue) {
+        return String.format("Failed to %s value for: 0x%s, areaId: 0x%s", action,
+                Integer.toHexString(propValue.prop), Integer.toHexString(propValue.areaId));
+    }
+
+    private String getPropertyErrorMessage(String action, VehiclePropValue propValue, int status) {
+        return String.format("Failed to %s property: 0x%s, areaId: 0x%s, code: %d (%s)", action,
+                Integer.toHexString(propValue.prop), Integer.toHexString(propValue.areaId),
+                status, StatusCode.toString(status));
+    }
+
+    VehiclePropValue getValue(VehiclePropValue requestedPropValue) {
         final ObjectWrapper<VehiclePropValue> valueWrapper = new ObjectWrapper<>();
         int status = invokeRetriable(() -> {
             ValueResult res = internalGet(requestedPropValue);
             valueWrapper.object = res.propValue;
             return res.status;
-        }, WAIT_CAP_FOR_RETRIABLE_RESULT_MS, SLEEP_BETWEEN_RETRIABLE_INVOKES_MS);
+        }, mWaitCapMs, mSleepMs);
 
-        int propId = requestedPropValue.prop;
-        int areaId = requestedPropValue.areaId;
         if (StatusCode.INVALID_ARG == status) {
-            throw new IllegalArgumentException(
-                    String.format("Failed to get value for: 0x%x, areaId: 0x%x", propId, areaId));
-        }
-
-        if (StatusCode.TRY_AGAIN == status) {
-            throw new PropertyTimeoutException(propId);
+            throw new IllegalArgumentException(getValueErrorMessage("get", requestedPropValue));
         }
 
         if (StatusCode.OK != status || valueWrapper.object == null) {
-            throw new IllegalStateException(
-                    String.format("Failed to get property: 0x%x, areaId: 0x%x, "
-                            + "code: %d", propId, areaId, status));
+            // If valueWrapper.object is null and status is StatusCode.Ok, change the status to be
+            // NOT_AVAILABLE.
+            if (StatusCode.OK == status) {
+                status = StatusCode.NOT_AVAILABLE;
+            }
+            Log.e(TAG, getPropertyErrorMessage("get", requestedPropValue, status));
+            throw new ServiceSpecificException(status,
+                    "Failed to get property: 0x" + Integer.toHexString(requestedPropValue.prop)
+                            + " in areaId: 0x" + Integer.toHexString(requestedPropValue.areaId));
         }
 
         return valueWrapper.object;
@@ -141,7 +163,7 @@
                         result.propValue = propValue;
                     });
         } catch (RemoteException e) {
-            Log.e(CarLog.TAG_HAL, "Failed to get value from vehicle HAL", e);
+            Log.e(TAG, getValueErrorMessage("get", requestedPropValue), e);
             result.status = StatusCode.TRY_AGAIN;
         }
 
@@ -157,28 +179,35 @@
         int status = callback.action();
         long startTime = elapsedRealtime();
         while (StatusCode.TRY_AGAIN == status && (elapsedRealtime() - startTime) < timeoutMs) {
+            if (DEBUG) {
+                Log.d(TAG, "Status before sleeping " + sleepMs + "ms: "
+                        + StatusCode.toString(status));
+            }
             try {
                 Thread.sleep(sleepMs);
             } catch (InterruptedException e) {
-                Log.e(CarLog.TAG_HAL, "Thread was interrupted while waiting for vehicle HAL.", e);
+                Thread.currentThread().interrupt();
+                Log.e(TAG, "Thread was interrupted while waiting for vehicle HAL.", e);
                 break;
             }
 
             status = callback.action();
+            if (DEBUG) Log.d(TAG, "Status after waking up: " + StatusCode.toString(status));
         }
+        if (DEBUG) Log.d(TAG, "Returning status: " + StatusCode.toString(status));
         return status;
     }
 
-    private static class ObjectWrapper<T> {
+    private static final class ObjectWrapper<T> {
         T object;
     }
 
-    private static class ValueResult {
+    private static final class ValueResult {
         int status;
         VehiclePropValue propValue;
     }
 
-    private static class PropertySetError {
+    private static final class PropertySetError {
         final int errorCode;
         final int propId;
         final int areaId;
@@ -190,45 +219,49 @@
         }
     }
 
-    private static class CallbackHandler extends Handler {
+    private static final class CallbackHandler extends Handler {
         private static final int MSG_ON_PROPERTY_SET = 1;
         private static final int MSG_ON_PROPERTY_EVENT = 2;
         private static final int MSG_ON_SET_ERROR = 3;
 
-        private final IVehicleCallback mCallback;
+        private final WeakReference<IVehicleCallback> mCallback;
 
         CallbackHandler(Looper looper, IVehicleCallback callback) {
             super(looper);
-            mCallback = callback;
+            mCallback = new WeakReference<IVehicleCallback>(callback);
         }
 
         @Override
         public void handleMessage(Message msg) {
-            super.handleMessage(msg);
+            IVehicleCallback callback = mCallback.get();
+            if (callback == null) {
+                Log.i(TAG, "handleMessage null callback");
+                return;
+            }
 
             try {
                 switch (msg.what) {
                     case MSG_ON_PROPERTY_EVENT:
-                        mCallback.onPropertyEvent((ArrayList<VehiclePropValue>) msg.obj);
+                        callback.onPropertyEvent((ArrayList<VehiclePropValue>) msg.obj);
                         break;
                     case MSG_ON_PROPERTY_SET:
-                        mCallback.onPropertySet((VehiclePropValue) msg.obj);
+                        callback.onPropertySet((VehiclePropValue) msg.obj);
                         break;
                     case MSG_ON_SET_ERROR:
                         PropertySetError obj = (PropertySetError) msg.obj;
-                        mCallback.onPropertySetError(obj.errorCode, obj.propId, obj.areaId);
+                        callback.onPropertySetError(obj.errorCode, obj.propId, obj.areaId);
                         break;
                     default:
-                        Log.e(CarLog.TAG_HAL, "Unexpected message: " + msg.what);
+                        Log.e(TAG, "Unexpected message: " + msg.what);
                 }
             } catch (RemoteException e) {
-                Log.e(CarLog.TAG_HAL, "Message failed: " + msg.what);
+                Log.e(TAG, "Message failed: " + msg.what);
             }
         }
     }
 
-    private static class VehicleCallback extends IVehicleCallback.Stub {
-        private Handler mHandler;
+    private static final class VehicleCallback extends IVehicleCallback.Stub {
+        private final Handler mHandler;
 
         VehicleCallback(Handler handler) {
             mHandler = handler;
diff --git a/service/src/com/android/car/hal/HalServiceBase.java b/service/src/com/android/car/hal/HalServiceBase.java
index 40700a9..5e2e5bb 100644
--- a/service/src/com/android/car/hal/HalServiceBase.java
+++ b/service/src/com/android/car/hal/HalServiceBase.java
@@ -17,13 +17,14 @@
 package com.android.car.hal;
 
 
-import android.annotation.Nullable;
+import android.annotation.NonNull;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
+import android.util.Log;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.Collection;
-import java.util.LinkedList;
 import java.util.List;
 
 /**
@@ -32,8 +33,11 @@
  * and will translate HAL data into car api specific format.
  */
 public abstract class HalServiceBase {
+
+    private static final String MY_TAG = HalServiceBase.class.getSimpleName();
+
     /** For dispatching events. Kept here to avoid alloc every time */
-    private final LinkedList<VehiclePropValue> mDispatchList = new LinkedList<VehiclePropValue>();
+    private final ArrayList<VehiclePropValue> mDispatchList = new ArrayList<>(1);
 
     final static int NOT_SUPPORTED_PROPERTY = -1;
 
@@ -48,23 +52,47 @@
     public abstract void release();
 
     /**
-     * return supported properties among all properties.
-     * @return null if no properties are supported
+     * Returns all property IDs this HalService can support. If return value is empty,
+     * {@link #isSupportedProperty(int)} is used to query support for each property.
      */
+    @NonNull
+    public abstract int[] getAllSupportedProperties();
+
     /**
-     * Take supported properties from given allProperties and return List of supported properties.
-     * @param allProperties
-     * @return null if no properties are supported.
+     * Checks if given {@code propId} is supported.
      */
-    @Nullable
-    public Collection<VehiclePropConfig> takeSupportedProperties(
-            Collection<VehiclePropConfig> allProperties) {
-        return null;
+    public boolean isSupportedProperty(int propId) {
+        for (int supported: getAllSupportedProperties()) {
+            if (propId == supported) {
+                return true;
+            }
+        }
+        return false;
     }
 
-    public abstract void handleHalEvents(List<VehiclePropValue> values);
+    /**
+     * Takes the passed properties. Passed properties are a subset of properties returned from
+     * {@link #getAllSupportedProperties()} and are supported in the current device.
+     *
+     * @param properties properties that are available in this device. This is guaranteed to be
+     *                   supported by the HalService as the list is filtered with
+     *                   {@link #getAllSupportedProperties()} or {@link #isSupportedProperty(int)}.
+     *                   It can be empty if no property is available.
+     */
+    public abstract void takeProperties(@NonNull Collection<VehiclePropConfig> properties);
 
-    public void handlePropertySetError(int property, int area) {}
+    /**
+     * Handles property changes from HAL.
+     */
+    public abstract void onHalEvents(List<VehiclePropValue> values);
+
+    /**
+     * Handles errors and pass error codes  when setting properties.
+     */
+    public void onPropertySetError(int property, int area, int errorCode) {
+        Log.d(MY_TAG, getClass().getSimpleName() + ".onPropertySetError(): property=" + property
+                + ", area=" + area + " , errorCode = " + errorCode);
+    }
 
     public abstract void dump(PrintWriter writer);
 
diff --git a/service/src/com/android/car/hal/InputHalService.java b/service/src/com/android/car/hal/InputHalService.java
index d719510..d6e3750 100644
--- a/service/src/com/android/car/hal/InputHalService.java
+++ b/service/src/com/android/car/hal/InputHalService.java
@@ -15,8 +15,13 @@
  */
 package com.android.car.hal;
 
+import static android.hardware.automotive.vehicle.V2_0.RotaryInputType.ROTARY_INPUT_TYPE_AUDIO_VOLUME;
+import static android.hardware.automotive.vehicle.V2_0.RotaryInputType.ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION;
 import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.HW_KEY_INPUT;
+import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.HW_ROTARY_INPUT;
 
+import android.car.input.CarInputManager;
+import android.car.input.RotaryEvent;
 import android.hardware.automotive.vehicle.V2_0.VehicleDisplay;
 import android.hardware.automotive.vehicle.V2_0.VehicleHwKeyInputAction;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
@@ -28,25 +33,38 @@
 import android.view.KeyEvent;
 
 import com.android.car.CarLog;
+import com.android.car.CarServiceUtils;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.PrintWriter;
 import java.util.Collection;
-import java.util.LinkedList;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 import java.util.function.LongSupplier;
 
 public class InputHalService extends HalServiceBase {
 
     public static final int DISPLAY_MAIN = VehicleDisplay.MAIN;
     public static final int DISPLAY_INSTRUMENT_CLUSTER = VehicleDisplay.INSTRUMENT_CLUSTER;
+
+    private static final int[] SUPPORTED_PROPERTIES = new int[] {
+            HW_KEY_INPUT,
+            HW_ROTARY_INPUT
+    };
+
     private final VehicleHal mHal;
-    /** A function to retrieve the current system uptime - replaceable for testing. */
+
+    /**
+     * A function to retrieve the current system uptime in milliseconds - replaceable for testing.
+     */
     private final LongSupplier mUptimeSupplier;
 
     public interface InputListener {
+        /** Called for key event */
         void onKeyEvent(KeyEvent event, int targetDisplay);
+        /** Called for rotary event */
+        void onRotaryEvent(RotaryEvent event, int targetDisplay);
     }
 
     /** The current press state of a key. */
@@ -59,10 +77,15 @@
 
     private static final boolean DBG = false;
 
-    @GuardedBy("this")
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
     private boolean mKeyInputSupported = false;
 
-    @GuardedBy("this")
+    @GuardedBy("mLock")
+    private boolean mRotaryInputSupported = false;
+
+    @GuardedBy("mLock")
     private InputListener mListener;
 
     @GuardedBy("mKeyStates")
@@ -79,18 +102,38 @@
     }
 
     public void setInputListener(InputListener listener) {
-        synchronized (this) {
-            if (!mKeyInputSupported) {
-                Log.w(CarLog.TAG_INPUT, "input listener set while key input not supported");
+        boolean keyInputSupported;
+        boolean rotaryInputSupported;
+        synchronized (mLock) {
+            if (!mKeyInputSupported && !mRotaryInputSupported) {
+                Log.w(CarLog.TAG_INPUT,
+                        "input listener set while rotary and key input not supported");
                 return;
             }
             mListener = listener;
+            keyInputSupported = mKeyInputSupported;
+            rotaryInputSupported = mRotaryInputSupported;
         }
-        mHal.subscribeProperty(this, HW_KEY_INPUT);
+        if (keyInputSupported) {
+            mHal.subscribeProperty(this, HW_KEY_INPUT);
+        }
+        if (rotaryInputSupported) {
+            mHal.subscribeProperty(this, HW_ROTARY_INPUT);
+        }
     }
 
-    public synchronized boolean isKeyInputSupported() {
-        return mKeyInputSupported;
+    /** Returns whether {@code HW_KEY_INPUT} is supported. */
+    public boolean isKeyInputSupported() {
+        synchronized (mLock) {
+            return mKeyInputSupported;
+        }
+    }
+
+    /** Returns whether {@code HW_ROTARY_INPUT} is supported. */
+    public boolean isRotaryInputSupported() {
+        synchronized (mLock) {
+            return mRotaryInputSupported;
+        }
     }
 
     @Override
@@ -99,66 +142,166 @@
 
     @Override
     public void release() {
-        synchronized (this) {
+        synchronized (mLock) {
             mListener = null;
             mKeyInputSupported = false;
+            mRotaryInputSupported = false;
         }
     }
 
     @Override
-    public Collection<VehiclePropConfig> takeSupportedProperties(
-            Collection<VehiclePropConfig> allProperties) {
-        List<VehiclePropConfig> supported = new LinkedList<>();
-        for (VehiclePropConfig p: allProperties) {
-            if (p.prop == HW_KEY_INPUT) {
-                supported.add(p);
-                synchronized (this) {
-                    mKeyInputSupported = true;
-                }
+    public int[] getAllSupportedProperties() {
+        return SUPPORTED_PROPERTIES;
+    }
+
+    @Override
+    public void takeProperties(Collection<VehiclePropConfig> properties) {
+        for (VehiclePropConfig property : properties) {
+            switch (property.prop) {
+                case HW_KEY_INPUT:
+                    synchronized (mLock) {
+                        mKeyInputSupported = true;
+                    }
+                    break;
+                case HW_ROTARY_INPUT:
+                    synchronized (mLock) {
+                        mRotaryInputSupported = true;
+                    }
+                    break;
             }
         }
-        return supported;
     }
 
     @Override
-    public void handleHalEvents(List<VehiclePropValue> values) {
+    public void onHalEvents(List<VehiclePropValue> values) {
         InputListener listener;
-        synchronized (this) {
+        synchronized (mLock) {
             listener = mListener;
         }
         if (listener == null) {
             Log.w(CarLog.TAG_INPUT, "Input event while listener is null");
             return;
         }
-        for (VehiclePropValue v : values) {
-            if (v.prop != HW_KEY_INPUT) {
-                Log.e(CarLog.TAG_INPUT, "Wrong event dispatched, prop:0x" +
-                        Integer.toHexString(v.prop));
-                continue;
-            }
-            int action = (v.value.int32Values.get(0) == VehicleHwKeyInputAction.ACTION_DOWN) ?
-                            KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP;
-            int code = v.value.int32Values.get(1);
-            int display = v.value.int32Values.get(2);
-            int indentsCount = v.value.int32Values.size() < 4 ? 1 : v.value.int32Values.get(3);
-            if (DBG) {
-                Log.i(CarLog.TAG_INPUT, new StringBuilder()
-                                        .append("hal event code:").append(code)
-                                        .append(", action:").append(action)
-                                        .append(", display: ").append(display)
-                                        .append(", number of indents: ").append(indentsCount)
-                                        .toString());
-            }
-            while (indentsCount > 0) {
-                indentsCount--;
-                dispatchKeyEvent(listener, action, code, display);
+        for (VehiclePropValue value : values) {
+            switch (value.prop) {
+                case HW_KEY_INPUT:
+                    dispatchKeyInput(listener, value);
+                    break;
+                case HW_ROTARY_INPUT:
+                    dispatchRotaryInput(listener, value);
+                    break;
+                default:
+                    Log.e(CarLog.TAG_INPUT,
+                            "Wrong event dispatched, prop:0x" + Integer.toHexString(value.prop));
+                    break;
             }
         }
     }
 
-    private void dispatchKeyEvent(InputListener listener, int action, int code, int display) {
-        long eventTime = mUptimeSupplier.getAsLong();
+    private void dispatchKeyInput(InputListener listener, VehiclePropValue value) {
+        int action = (value.value.int32Values.get(0) == VehicleHwKeyInputAction.ACTION_DOWN)
+                ? KeyEvent.ACTION_DOWN
+                : KeyEvent.ACTION_UP;
+        int code = value.value.int32Values.get(1);
+        int display = value.value.int32Values.get(2);
+        int indentsCount = value.value.int32Values.size() < 4 ? 1 : value.value.int32Values.get(3);
+        if (DBG) {
+            Log.i(CarLog.TAG_INPUT, new StringBuilder()
+                    .append("hal event code:").append(code)
+                    .append(", action:").append(action)
+                    .append(", display: ").append(display)
+                    .append(", number of indents: ").append(indentsCount)
+                    .toString());
+        }
+        while (indentsCount > 0) {
+            indentsCount--;
+            dispatchKeyEvent(listener, action, code, display);
+        }
+    }
 
+    private void dispatchRotaryInput(InputListener listener, VehiclePropValue value) {
+        int timeValuesIndex = 3;  // remaining values are time deltas in nanoseconds
+        if (value.value.int32Values.size() < timeValuesIndex) {
+            Log.e(CarLog.TAG_INPUT, "Wrong int32 array size for RotaryInput from vhal:"
+                    + value.value.int32Values.size());
+            return;
+        }
+        int rotaryInputType = value.value.int32Values.get(0);
+        int detentCount = value.value.int32Values.get(1);
+        int display = value.value.int32Values.get(2);
+        long timestamp = value.timestamp;  // for first detent, uptime nanoseconds
+        if (DBG) {
+            Log.i(CarLog.TAG_INPUT, new StringBuilder()
+                    .append("hal rotary input type: ").append(rotaryInputType)
+                    .append(", number of detents:").append(detentCount)
+                    .append(", display: ").append(display)
+                    .toString());
+        }
+        boolean clockwise = detentCount > 0;
+        detentCount = Math.abs(detentCount);
+        if (detentCount == 0) { // at least there should be one event
+            Log.e(CarLog.TAG_INPUT, "Zero detentCount from vhal, ignore the event");
+            return;
+        }
+        if (display != DISPLAY_MAIN && display != DISPLAY_INSTRUMENT_CLUSTER) {
+            Log.e(CarLog.TAG_INPUT, "Wrong display type for RotaryInput from vhal:"
+                    + display);
+            return;
+        }
+        if (value.value.int32Values.size() != (timeValuesIndex + detentCount - 1)) {
+            Log.e(CarLog.TAG_INPUT, "Wrong int32 array size for RotaryInput from vhal:"
+                    + value.value.int32Values.size());
+            return;
+        }
+        int carInputManagerType;
+        switch (rotaryInputType) {
+            case ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION:
+                carInputManagerType = CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION;
+                break;
+            case ROTARY_INPUT_TYPE_AUDIO_VOLUME:
+                carInputManagerType = CarInputManager.INPUT_TYPE_ROTARY_VOLUME;
+                break;
+            default:
+                Log.e(CarLog.TAG_INPUT, "Unknown rotary input type: " + rotaryInputType);
+                return;
+        }
+
+        long[] timestamps = new long[detentCount];
+        // vhal returns elapsed time while rotary event is using uptime to be in line with KeyEvent.
+        long uptimeToElapsedTimeDelta = CarServiceUtils.getUptimeToElapsedTimeDeltaInMillis();
+        long startUptime = TimeUnit.NANOSECONDS.toMillis(timestamp) - uptimeToElapsedTimeDelta;
+        timestamps[0] = startUptime;
+        for (int i = 0; i < timestamps.length - 1; i++) {
+            timestamps[i + 1] = timestamps[i] + TimeUnit.NANOSECONDS.toMillis(
+                    value.value.int32Values.get(timeValuesIndex + i));
+        }
+        RotaryEvent event = new RotaryEvent(carInputManagerType, clockwise, timestamps);
+        listener.onRotaryEvent(event, display);
+    }
+
+    /**
+     * Dispatches a KeyEvent using {@link #mUptimeSupplier} for the event time.
+     *
+     * @param listener listener to dispatch the event to
+     * @param action action for the KeyEvent
+     * @param code keycode for the KeyEvent
+     * @param display target display the event is associated with
+     */
+    private void dispatchKeyEvent(InputListener listener, int action, int code, int display) {
+        dispatchKeyEvent(listener, action, code, display, mUptimeSupplier.getAsLong());
+    }
+
+    /**
+     * Dispatches a KeyEvent.
+     *
+     * @param listener listener to dispatch the event to
+     * @param action action for the KeyEvent
+     * @param code keycode for the KeyEvent
+     * @param display target display the event is associated with
+     * @param eventTime uptime in milliseconds when the event occurred
+     */
+    private void dispatchKeyEvent(InputListener listener, int action, int code, int display,
+            long eventTime) {
         long downTime;
         int repeat;
 
@@ -186,7 +329,7 @@
             }
         }
 
-        KeyEvent event = KeyEvent.obtain(
+        KeyEvent event = new KeyEvent(
                 downTime,
                 eventTime,
                 action,
@@ -196,17 +339,15 @@
                 0 /* deviceId */,
                 0 /* scancode */,
                 0 /* flags */,
-                InputDevice.SOURCE_CLASS_BUTTON,
-                null /* characters */);
+                InputDevice.SOURCE_CLASS_BUTTON);
 
         listener.onKeyEvent(event, display);
-        event.recycle();
     }
 
     @Override
     public void dump(PrintWriter writer) {
         writer.println("*Input HAL*");
         writer.println("mKeyInputSupported:" + mKeyInputSupported);
+        writer.println("mRotaryInputSupported:" + mRotaryInputSupported);
     }
-
 }
diff --git a/service/src/com/android/car/hal/PowerHalService.java b/service/src/com/android/car/hal/PowerHalService.java
index 0eaa5cc..28c8789 100644
--- a/service/src/com/android/car/hal/PowerHalService.java
+++ b/service/src/com/android/car/hal/PowerHalService.java
@@ -29,9 +29,11 @@
 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
+import android.os.ServiceSpecificException;
 import android.util.Log;
 
 import com.android.car.CarLog;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.PrintWriter;
@@ -44,6 +46,12 @@
     // Set display brightness from 0-100%
     public static final int MAX_BRIGHTNESS = 100;
 
+    private static final int[] SUPPORTED_PROPERTIES = new int[]{
+            AP_POWER_STATE_REQ,
+            AP_POWER_STATE_REPORT,
+            DISPLAY_BRIGHTNESS
+    };
+
     @VisibleForTesting
     public static final int SET_WAIT_FOR_VHAL = VehicleApPowerStateReport.WAIT_FOR_VHAL;
     @VisibleForTesting
@@ -69,6 +77,8 @@
     @VisibleForTesting
     public static final int SHUTDOWN_ONLY = VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY;
 
+    private final Object mLock = new Object();
+
     private static String powerStateReportName(int state) {
         String baseName;
         switch(state) {
@@ -132,7 +142,8 @@
             if (mState != VehicleApPowerStateReq.SHUTDOWN_PREPARE) {
                 throw new IllegalStateException("wrong state");
             }
-            return (mParam == VehicleApPowerStateShutdownParam.CAN_SLEEP);
+            return (mParam == VehicleApPowerStateShutdownParam.CAN_SLEEP
+                    || mParam == VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY);
         }
 
         /**
@@ -145,7 +156,8 @@
             if (mState != VehicleApPowerStateReq.SHUTDOWN_PREPARE) {
                 throw new IllegalStateException("wrong state");
             }
-            return (mParam != VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY);
+            return (mParam != VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY
+                    && mParam != VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY);
         }
 
         @Override
@@ -166,10 +178,14 @@
         }
     }
 
+    @GuardedBy("mLock")
     private final HashMap<Integer, VehiclePropConfig> mProperties = new HashMap<>();
     private final VehicleHal mHal;
+    @GuardedBy("mLock")
     private LinkedList<VehiclePropValue> mQueuedEvents;
+    @GuardedBy("mLock")
     private PowerEventListener mListener;
+    @GuardedBy("mLock")
     private int mMaxDisplayBrightness;
 
     public PowerHalService(VehicleHal hal) {
@@ -178,7 +194,7 @@
 
     public void setListener(PowerEventListener listener) {
         LinkedList<VehiclePropValue> eventsToDispatch = null;
-        synchronized (this) {
+        synchronized (mLock) {
             mListener = listener;
             if (mQueuedEvents != null && mQueuedEvents.size() > 0) {
                 eventsToDispatch = mQueuedEvents;
@@ -199,7 +215,7 @@
         setPowerState(VehicleApPowerStateReport.WAIT_FOR_VHAL, 0);
     }
 
-   /**
+    /**
      * Send SleepEntry message to VHAL
      * @param wakeupTimeSec Notify VHAL when system wants to be woken from sleep.
      */
@@ -274,7 +290,7 @@
         try {
             mHal.set(VehicleProperty.DISPLAY_BRIGHTNESS, 0).to(brightness);
             Log.i(CarLog.TAG_POWER, "send display brightness = " + brightness);
-        } catch (PropertyTimeoutException e) {
+        } catch (ServiceSpecificException | IllegalArgumentException e) {
             Log.e(CarLog.TAG_POWER, "cannot set DISPLAY_BRIGHTNESS", e);
         }
     }
@@ -286,7 +302,7 @@
                 mHal.set(VehicleProperty.AP_POWER_STATE_REPORT, 0).to(values);
                 Log.i(CarLog.TAG_POWER, "setPowerState=" + powerStateReportName(state)
                         + " param=" + additionalParam);
-            } catch (PropertyTimeoutException e) {
+            } catch (ServiceSpecificException e) {
                 Log.e(CarLog.TAG_POWER, "cannot set to AP_POWER_STATE_REPORT", e);
             }
         }
@@ -297,7 +313,7 @@
         int[] state;
         try {
             state = mHal.get(int[].class, VehicleProperty.AP_POWER_STATE_REQ);
-        } catch (PropertyTimeoutException e) {
+        } catch (ServiceSpecificException e) {
             Log.e(CarLog.TAG_POWER, "Cannot get AP_POWER_STATE_REQ", e);
             return null;
         }
@@ -305,16 +321,23 @@
                 state[VehicleApPowerStateReqIndex.ADDITIONAL]);
     }
 
-    public synchronized boolean isPowerStateSupported() {
-        return (mProperties.get(VehicleProperty.AP_POWER_STATE_REQ) != null)
-                && (mProperties.get(VehicleProperty.AP_POWER_STATE_REPORT) != null);
+    /**
+     * Determines if the current properties describe a valid power state
+     * @return true if both the power state request and power state report are valid
+     */
+    public boolean isPowerStateSupported() {
+        synchronized (mLock) {
+            return (mProperties.get(VehicleProperty.AP_POWER_STATE_REQ) != null)
+                    && (mProperties.get(VehicleProperty.AP_POWER_STATE_REPORT) != null);
+        }
     }
 
-    private synchronized boolean isConfigFlagSet(int flag) {
-        VehiclePropConfig config = mProperties.get(VehicleProperty.AP_POWER_STATE_REQ);
-        if (config == null) {
-            return false;
-        } else if (config.configArray.size() < 1) {
+    private boolean isConfigFlagSet(int flag) {
+        VehiclePropConfig config;
+        synchronized (mLock) {
+            config = mProperties.get(VehicleProperty.AP_POWER_STATE_REQ);
+        }
+        if (config == null || config.configArray.size() < 1) {
             return false;
         }
         return (config.configArray.get(0) & flag) != 0;
@@ -329,48 +352,54 @@
     }
 
     @Override
-    public synchronized void init() {
-        for (VehiclePropConfig config : mProperties.values()) {
-            if (VehicleHal.isPropertySubscribable(config)) {
-                mHal.subscribeProperty(this, config.prop);
+    public void init() {
+        synchronized (mLock) {
+            for (VehiclePropConfig config : mProperties.values()) {
+                if (VehicleHal.isPropertySubscribable(config)) {
+                    mHal.subscribeProperty(this, config.prop);
+                }
             }
-        }
-        VehiclePropConfig brightnessProperty = mProperties.get(DISPLAY_BRIGHTNESS);
-        if (brightnessProperty != null) {
-            mMaxDisplayBrightness = brightnessProperty.areaConfigs.size() > 0
-                    ? brightnessProperty.areaConfigs.get(0).maxInt32Value : 0;
-            if (mMaxDisplayBrightness <= 0) {
-                Log.w(CarLog.TAG_POWER, "Max display brightness from vehicle HAL is invalid:" +
-                        mMaxDisplayBrightness);
-                mMaxDisplayBrightness = 1;
+            VehiclePropConfig brightnessProperty = mProperties.get(DISPLAY_BRIGHTNESS);
+            if (brightnessProperty != null) {
+                mMaxDisplayBrightness = brightnessProperty.areaConfigs.size() > 0
+                        ? brightnessProperty.areaConfigs.get(0).maxInt32Value : 0;
+                if (mMaxDisplayBrightness <= 0) {
+                    Log.w(CarLog.TAG_POWER, "Max display brightness from vehicle HAL is invalid:"
+                            + mMaxDisplayBrightness);
+                    mMaxDisplayBrightness = 1;
+                }
             }
         }
     }
 
     @Override
-    public synchronized void release() {
-        mProperties.clear();
+    public void release() {
+        synchronized (mLock) {
+            mProperties.clear();
+        }
     }
 
     @Override
-    public synchronized Collection<VehiclePropConfig> takeSupportedProperties(
-            Collection<VehiclePropConfig> allProperties) {
-        for (VehiclePropConfig config : allProperties) {
-            switch (config.prop) {
-                case AP_POWER_STATE_REQ:
-                case AP_POWER_STATE_REPORT:
-                case DISPLAY_BRIGHTNESS:
-                    mProperties.put(config.prop, config);
-                    break;
+    public int[] getAllSupportedProperties() {
+        return SUPPORTED_PROPERTIES;
+    }
+
+    @Override
+    public void takeProperties(Collection<VehiclePropConfig> properties) {
+        if (properties.isEmpty()) {
+            return;
+        }
+        synchronized (mLock) {
+            for (VehiclePropConfig config : properties) {
+                mProperties.put(config.prop, config);
             }
         }
-        return new LinkedList<>(mProperties.values());
     }
 
     @Override
-    public void handleHalEvents(List<VehiclePropValue> values) {
+    public void onHalEvents(List<VehiclePropValue> values) {
         PowerEventListener listener;
-        synchronized (this) {
+        synchronized (mLock) {
             if (mListener == null) {
                 if (mQueuedEvents == null) {
                     mQueuedEvents = new LinkedList<>();
@@ -387,7 +416,7 @@
         for (VehiclePropValue v : values) {
             switch (v.prop) {
                 case AP_POWER_STATE_REPORT:
-                    // Should never see this; write-only property
+                    // Ignore this property event. It was generated inside of CarService.
                     break;
                 case AP_POWER_STATE_REQ:
                     int state = v.value.int32Values.get(VehicleApPowerStateReqIndex.STATE);
@@ -399,7 +428,7 @@
                 case DISPLAY_BRIGHTNESS:
                 {
                     int maxBrightness;
-                    synchronized (this) {
+                    synchronized (mLock) {
                         maxBrightness = mMaxDisplayBrightness;
                     }
                     int brightness = v.value.int32Values.get(0) * MAX_BRIGHTNESS / maxBrightness;
diff --git a/service/src/com/android/car/hal/PropertyHalService.java b/service/src/com/android/car/hal/PropertyHalService.java
index 484e667..15038cd 100644
--- a/service/src/com/android/car/hal/PropertyHalService.java
+++ b/service/src/com/android/car/hal/PropertyHalService.java
@@ -16,30 +16,37 @@
 package com.android.car.hal;
 
 import static com.android.car.hal.CarPropertyUtils.toCarPropertyValue;
+import static com.android.car.hal.CarPropertyUtils.toMixedCarPropertyValue;
+import static com.android.car.hal.CarPropertyUtils.toMixedVehiclePropValue;
 import static com.android.car.hal.CarPropertyUtils.toVehiclePropValue;
 
 import static java.lang.Integer.toHexString;
 
 import android.annotation.Nullable;
+import android.car.VehiclePropertyIds;
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.property.CarPropertyEvent;
+import android.car.hardware.property.CarPropertyManager;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
+import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType;
+import android.os.Build;
 import android.util.Log;
 import android.util.SparseArray;
 
-import com.android.car.CarLog;
+import com.android.car.CarServiceUtils;
 import com.android.internal.annotations.GuardedBy;
 
 import java.io.PrintWriter;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * Common interface for HAL services that send Vehicle Properties back and forth via ICarProperty.
@@ -49,42 +56,47 @@
 public class PropertyHalService extends HalServiceBase {
     private final boolean mDbg = true;
     private final LinkedList<CarPropertyEvent> mEventsToDispatch = new LinkedList<>();
-    private final Map<Integer, CarPropertyConfig<?>> mProps =
-            new ConcurrentHashMap<>();
-    private final SparseArray<Float> mRates = new SparseArray<Float>();
+    @GuardedBy("mLock")
+    private final Map<Integer, CarPropertyConfig<?>> mMgrPropIdToCarPropConfig = new HashMap<>();
+    @GuardedBy("mLock")
+    private final SparseArray<VehiclePropConfig> mHalPropIdToVehiclePropConfig =
+            new SparseArray<>();
+    // Only contains propId if the property Id is different in HAL and manager
+    private static final Map<Integer, Integer> PROPERTY_ID_HAL_TO_MANAGER = Map.of(
+            VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS,
+            VehiclePropertyIds.VEHICLE_SPEED_DISPLAY_UNITS);
+    // Only contains propId if the property Id is different in HAL and manager
+    private static final Map<Integer, Integer> PROPERTY_ID_MANAGER_TO_HAL = Map.of(
+            VehiclePropertyIds.VEHICLE_SPEED_DISPLAY_UNITS,
+            VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS);
     private static final String TAG = "PropertyHalService";
     private final VehicleHal mVehicleHal;
     private final PropertyHalServiceIds mPropIds;
 
     @GuardedBy("mLock")
     private PropertyHalListener mListener;
-
-    private Set<Integer> mSubscribedPropIds;
+    @GuardedBy("mLock")
+    private Set<Integer> mSubscribedHalPropIds;
 
     private final Object mLock = new Object();
 
     /**
      * Converts manager property ID to Vehicle HAL property ID.
-     * If property is not supported, it will return {@link #NOT_SUPPORTED_PROPERTY}.
      */
-    private int managerToHalPropId(int propId) {
-        if (mProps.containsKey(propId)) {
-            return propId;
-        } else {
-            return NOT_SUPPORTED_PROPERTY;
-        }
+    private int managerToHalPropId(int mgrPropId) {
+        return PROPERTY_ID_MANAGER_TO_HAL.getOrDefault(mgrPropId, mgrPropId);
     }
 
     /**
      * Converts Vehicle HAL property ID to manager property ID.
-     * If property is not supported, it will return {@link #NOT_SUPPORTED_PROPERTY}.
      */
     private int halToManagerPropId(int halPropId) {
-        if (mProps.containsKey(halPropId)) {
-            return halPropId;
-        } else {
-            return NOT_SUPPORTED_PROPERTY;
-        }
+        return PROPERTY_ID_HAL_TO_MANAGER.getOrDefault(halPropId, halPropId);
+    }
+
+    // Checks if the property exists in this VHAL before calling methods in IVehicle.
+    private boolean isPropertySupportedInVehicle(int halPropId) {
+        return mHalPropIdToVehiclePropConfig.contains(halPropId);
     }
 
     /**
@@ -93,7 +105,7 @@
     public interface PropertyHalListener {
         /**
          * This event is sent whenever the property value is updated
-         * @param event
+         * @param events
          */
         void onPropertyChange(List<CarPropertyEvent> events);
         /**
@@ -101,12 +113,14 @@
          * @param property
          * @param area
          */
-        void onPropertySetError(int property, int area);
+        void onPropertySetError(int property, int area,
+                @CarPropertyManager.CarSetPropertyErrorCode int errorCode);
+
     }
 
     public PropertyHalService(VehicleHal vehicleHal) {
         mPropIds = new PropertyHalServiceIds();
-        mSubscribedPropIds = new HashSet<Integer>();
+        mSubscribedHalPropIds = new HashSet<Integer>();
         mVehicleHal = vehicleHal;
         if (mDbg) {
             Log.d(TAG, "started PropertyHalService");
@@ -131,7 +145,17 @@
         if (mDbg) {
             Log.d(TAG, "getPropertyList");
         }
-        return mProps;
+        synchronized (mLock) {
+            if (mMgrPropIdToCarPropConfig.size() == 0) {
+                for (int i = 0; i < mHalPropIdToVehiclePropConfig.size(); i++) {
+                    VehiclePropConfig p = mHalPropIdToVehiclePropConfig.valueAt(i);
+                    int mgrPropId = halToManagerPropId(p.prop);
+                    CarPropertyConfig config = CarPropertyUtils.toCarPropertyConfig(p, mgrPropId);
+                    mMgrPropIdToCarPropConfig.put(mgrPropId, config);
+                }
+            }
+        }
+        return mMgrPropIdToCarPropConfig;
     }
 
     /**
@@ -142,52 +166,63 @@
     @Nullable
     public CarPropertyValue getProperty(int mgrPropId, int areaId) {
         int halPropId = managerToHalPropId(mgrPropId);
-        if (halPropId == NOT_SUPPORTED_PROPERTY) {
+        if (!isPropertySupportedInVehicle(halPropId)) {
             throw new IllegalArgumentException("Invalid property Id : 0x" + toHexString(mgrPropId));
         }
 
-        VehiclePropValue value = null;
-        try {
-            value = mVehicleHal.get(halPropId, areaId);
-        } catch (PropertyTimeoutException e) {
-            Log.e(CarLog.TAG_PROPERTY, "get, property not ready 0x" + toHexString(halPropId), e);
+        // CarPropertyManager catches and rethrows exception, no need to handle here.
+        VehiclePropValue value = mVehicleHal.get(halPropId, areaId);
+        if (isMixedTypeProperty(halPropId)) {
+            VehiclePropConfig propConfig;
+            synchronized (mLock) {
+                propConfig = mHalPropIdToVehiclePropConfig.get(halPropId);
+            }
+            boolean containBooleanType = propConfig.configArray.get(1) == 1;
+            return value == null ? null : toMixedCarPropertyValue(value,
+                    mgrPropId, containBooleanType);
         }
-
         return value == null ? null : toCarPropertyValue(value, mgrPropId);
     }
 
     /**
      * Returns sample rate for the property
-     * @param propId
+     * @param mgrPropId
      */
-    public float getSampleRate(int propId) {
-        return mVehicleHal.getSampleRate(propId);
+    public float getSampleRate(int mgrPropId) {
+        int halPropId = managerToHalPropId(mgrPropId);
+        if (!isPropertySupportedInVehicle(halPropId)) {
+            throw new IllegalArgumentException("Invalid property Id : 0x" + toHexString(mgrPropId));
+        }
+        return mVehicleHal.getSampleRate(halPropId);
     }
 
     /**
      * Get the read permission string for the property.
-     * @param propId
+     * @param mgrPropId
      */
     @Nullable
-    public String getReadPermission(int propId) {
-        return mPropIds.getReadPermission(propId);
+    public String getReadPermission(int mgrPropId) {
+        int halPropId = managerToHalPropId(mgrPropId);
+        return mPropIds.getReadPermission(halPropId);
     }
 
     /**
      * Get the write permission string for the property.
-     * @param propId
+     * @param mgrPropId
      */
     @Nullable
-    public String getWritePermission(int propId) {
-        return mPropIds.getWritePermission(propId);
+    public String getWritePermission(int mgrPropId) {
+        int halPropId = managerToHalPropId(mgrPropId);
+        return mPropIds.getWritePermission(halPropId);
     }
 
     /**
      * Return true if property is a display_units property
-     * @param propId
+     * @param mgrPropId
      */
-    public boolean isDisplayUnitsProperty(int propId) {
-        return mPropIds.isPropertyToChangeUnits(propId);
+    public boolean isDisplayUnitsProperty(int mgrPropId) {
+        int halPropId = managerToHalPropId(mgrPropId);
+        return mPropIds.isPropertyToChangeUnits(halPropId);
     }
 
     /**
@@ -196,62 +231,70 @@
      */
     public void setProperty(CarPropertyValue prop) {
         int halPropId = managerToHalPropId(prop.getPropertyId());
-        if (halPropId == NOT_SUPPORTED_PROPERTY) {
+        if (!isPropertySupportedInVehicle(halPropId)) {
             throw new IllegalArgumentException("Invalid property Id : 0x"
                     + toHexString(prop.getPropertyId()));
         }
-        VehiclePropValue halProp = toVehiclePropValue(prop, halPropId);
-        try {
-            mVehicleHal.set(halProp);
-        } catch (PropertyTimeoutException e) {
-            Log.e(CarLog.TAG_PROPERTY, "set, property not ready 0x" + toHexString(halPropId), e);
-            throw new RuntimeException(e);
+
+        VehiclePropValue halProp;
+        if (isMixedTypeProperty(halPropId)) {
+            // parse mixed type property value.
+            VehiclePropConfig propConfig;
+            synchronized (mLock) {
+                propConfig = mHalPropIdToVehiclePropConfig.get(prop.getPropertyId());
+            }
+            int[] configArray = propConfig.configArray.stream().mapToInt(i->i).toArray();
+            halProp = toMixedVehiclePropValue(prop, halPropId, configArray);
+        } else {
+            halProp = toVehiclePropValue(prop, halPropId);
         }
+        // CarPropertyManager catches and rethrows exception, no need to handle here.
+        mVehicleHal.set(halProp);
     }
 
     /**
      * Subscribe to this property at the specified update rate.
-     * @param propId
+     * @param mgrPropId
      * @param rate
      */
-    public void subscribeProperty(int propId, float rate) {
+    public void subscribeProperty(int mgrPropId, float rate) {
         if (mDbg) {
-            Log.d(TAG, "subscribeProperty propId=0x" + toHexString(propId) + ", rate=" + rate);
+            Log.d(TAG, "subscribeProperty propId=0x" + toHexString(mgrPropId) + ", rate=" + rate);
         }
-        int halPropId = managerToHalPropId(propId);
-        if (halPropId == NOT_SUPPORTED_PROPERTY) {
+        int halPropId = managerToHalPropId(mgrPropId);
+        if (!isPropertySupportedInVehicle(halPropId)) {
             throw new IllegalArgumentException("Invalid property Id : 0x"
-                    + toHexString(propId));
+                    + toHexString(mgrPropId));
         }
-        // Validate the min/max rate
-        CarPropertyConfig cfg = mProps.get(propId);
-        if (rate > cfg.getMaxSampleRate()) {
-            rate = cfg.getMaxSampleRate();
-        } else if (rate < cfg.getMinSampleRate()) {
-            rate = cfg.getMinSampleRate();
+        synchronized (mLock) {
+            VehiclePropConfig cfg = mHalPropIdToVehiclePropConfig.get(halPropId);
+            if (rate > cfg.maxSampleRate) {
+                rate = cfg.maxSampleRate;
+            } else if (rate < cfg.minSampleRate) {
+                rate = cfg.minSampleRate;
+            }
+            mSubscribedHalPropIds.add(halPropId);
         }
-        synchronized (mSubscribedPropIds) {
-            mSubscribedPropIds.add(halPropId);
-        }
+
         mVehicleHal.subscribeProperty(this, halPropId, rate);
     }
 
     /**
      * Unsubscribe the property and turn off update events for it.
-     * @param propId
+     * @param mgrPropId
      */
-    public void unsubscribeProperty(int propId) {
+    public void unsubscribeProperty(int mgrPropId) {
         if (mDbg) {
-            Log.d(TAG, "unsubscribeProperty propId=0x" + toHexString(propId));
+            Log.d(TAG, "unsubscribeProperty propId=0x" + toHexString(mgrPropId));
         }
-        int halPropId = managerToHalPropId(propId);
-        if (halPropId == NOT_SUPPORTED_PROPERTY) {
+        int halPropId = managerToHalPropId(mgrPropId);
+        if (!isPropertySupportedInVehicle(halPropId)) {
             throw new IllegalArgumentException("Invalid property Id : 0x"
-                    + toHexString(propId));
+                    + toHexString(mgrPropId));
         }
-        synchronized (mSubscribedPropIds) {
-            if (mSubscribedPropIds.contains(halPropId)) {
-                mSubscribedPropIds.remove(halPropId);
+        synchronized (mLock) {
+            if (mSubscribedHalPropIds.contains(halPropId)) {
+                mSubscribedHalPropIds.remove(halPropId);
                 mVehicleHal.unsubscribeProperty(this, halPropId);
             }
         }
@@ -269,42 +312,56 @@
         if (mDbg) {
             Log.d(TAG, "release()");
         }
-        synchronized (mSubscribedPropIds) {
-            for (Integer prop : mSubscribedPropIds) {
-                mVehicleHal.unsubscribeProperty(this, prop);
-            }
-            mSubscribedPropIds.clear();
-        }
-        mProps.clear();
-
         synchronized (mLock) {
+            for (Integer halProp : mSubscribedHalPropIds) {
+                mVehicleHal.unsubscribeProperty(this, halProp);
+            }
+            mSubscribedHalPropIds.clear();
+            mHalPropIdToVehiclePropConfig.clear();
+            mMgrPropIdToCarPropConfig.clear();
             mListener = null;
         }
     }
 
     @Override
-    public Collection<VehiclePropConfig> takeSupportedProperties(
-            Collection<VehiclePropConfig> allProperties) {
-        List<VehiclePropConfig> taken = new LinkedList<>();
+    public boolean isSupportedProperty(int propId) {
+        return mPropIds.isSupportedProperty(propId);
+    }
 
+    @Override
+    public int[] getAllSupportedProperties() {
+        return CarServiceUtils.EMPTY_INT_ARRAY;
+    }
+
+    @Override
+    public void takeProperties(Collection<VehiclePropConfig> allProperties) {
         for (VehiclePropConfig p : allProperties) {
             if (mPropIds.isSupportedProperty(p.prop)) {
-                CarPropertyConfig config = CarPropertyUtils.toCarPropertyConfig(p, p.prop);
-                taken.add(p);
-                mProps.put(p.prop, config);
+                synchronized (mLock) {
+                    mHalPropIdToVehiclePropConfig.put(p.prop, p);
+                }
                 if (mDbg) {
                     Log.d(TAG, "takeSupportedProperties: " + toHexString(p.prop));
                 }
             }
         }
         if (mDbg) {
-            Log.d(TAG, "takeSupportedProperties() took " + taken.size() + " properties");
+            Log.d(TAG, "takeSupportedProperties() took " + allProperties.size()
+                    + " properties");
         }
-        return taken;
+        // If vehicle hal support to select permission for vendor properties.
+        VehiclePropConfig customizePermission;
+        synchronized (mLock) {
+            customizePermission = mHalPropIdToVehiclePropConfig.get(
+                    VehicleProperty.SUPPORT_CUSTOMIZE_VENDOR_PERMISSION);
+        }
+        if (customizePermission != null) {
+            mPropIds.customizeVendorPermission(customizePermission.configArray);
+        }
     }
 
     @Override
-    public void handleHalEvents(List<VehiclePropValue> values) {
+    public void onHalEvents(List<VehiclePropValue> values) {
         PropertyHalListener listener;
         synchronized (mLock) {
             listener = mListener;
@@ -314,17 +371,32 @@
                 if (v == null) {
                     continue;
                 }
-                int mgrPropId = halToManagerPropId(v.prop);
-                if (mgrPropId == NOT_SUPPORTED_PROPERTY) {
+                if (!isPropertySupportedInVehicle(v.prop)) {
                     Log.e(TAG, "Property is not supported: 0x" + toHexString(v.prop));
                     continue;
                 }
-                CarPropertyValue<?> propVal = toCarPropertyValue(v, mgrPropId);
+                // Check payload if it is a userdebug build.
+                if (Build.IS_DEBUGGABLE && !mPropIds.checkPayload(v)) {
+                    Log.e(TAG, "Drop event for property: " + v + " because it is failed "
+                            + "in payload checking.");
+                    continue;
+                }
+                int mgrPropId = halToManagerPropId(v.prop);
+                CarPropertyValue<?> propVal;
+                if (isMixedTypeProperty(v.prop)) {
+                    // parse mixed type property value.
+                    VehiclePropConfig propConfig;
+                    synchronized (mLock) {
+                        propConfig = mHalPropIdToVehiclePropConfig.get(v.prop);
+                    }
+                    boolean containBooleanType = propConfig.configArray.get(1) == 1;
+                    propVal = toMixedCarPropertyValue(v, mgrPropId, containBooleanType);
+                } else {
+                    propVal = toCarPropertyValue(v, mgrPropId);
+                }
                 CarPropertyEvent event = new CarPropertyEvent(
                         CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, propVal);
-                if (event != null) {
-                    mEventsToDispatch.add(event);
-                }
+                mEventsToDispatch.add(event);
             }
             listener.onPropertyChange(mEventsToDispatch);
             mEventsToDispatch.clear();
@@ -332,13 +404,15 @@
     }
 
     @Override
-    public void handlePropertySetError(int property, int area) {
+    public void onPropertySetError(int halPropId, int area,
+            @CarPropertyManager.CarSetPropertyErrorCode int errorCode) {
         PropertyHalListener listener;
         synchronized (mLock) {
             listener = mListener;
         }
         if (listener != null) {
-            listener.onPropertySetError(property, area);
+            int mgrPropId = halToManagerPropId(halPropId);
+            listener.onPropertySetError(mgrPropId, area, errorCode);
         }
     }
 
@@ -346,8 +420,15 @@
     public void dump(PrintWriter writer) {
         writer.println(TAG);
         writer.println("  Properties available:");
-        for (CarPropertyConfig prop : mProps.values()) {
-            writer.println("    " + prop.toString());
+        synchronized (mLock) {
+            for (int i = 0; i < mHalPropIdToVehiclePropConfig.size(); i++) {
+                VehiclePropConfig p = mHalPropIdToVehiclePropConfig.valueAt(i);
+                writer.println("    " + p);
+            }
         }
     }
+
+    private static boolean isMixedTypeProperty(int halPropId) {
+        return (halPropId & VehiclePropertyType.MASK) == VehiclePropertyType.MIXED;
+    }
 }
diff --git a/service/src/com/android/car/hal/PropertyHalServiceIds.java b/service/src/com/android/car/hal/PropertyHalServiceIds.java
index 82a89d7..3772843 100644
--- a/service/src/com/android/car/hal/PropertyHalServiceIds.java
+++ b/service/src/com/android/car/hal/PropertyHalServiceIds.java
@@ -18,15 +18,37 @@
 
 import static java.lang.Integer.toHexString;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.car.Car;
+import android.car.VehicleHvacFanDirection;
+import android.car.hardware.property.VehicleVendorPermission;
+import android.hardware.automotive.vehicle.V2_0.EvConnectorType;
+import android.hardware.automotive.vehicle.V2_0.FuelType;
+import android.hardware.automotive.vehicle.V2_0.PortLocationType;
+import android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat;
+import android.hardware.automotive.vehicle.V2_0.VehicleGear;
+import android.hardware.automotive.vehicle.V2_0.VehicleIgnitionState;
+import android.hardware.automotive.vehicle.V2_0.VehicleLightState;
+import android.hardware.automotive.vehicle.V2_0.VehicleLightSwitch;
+import android.hardware.automotive.vehicle.V2_0.VehicleOilLevel;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyGroup;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType;
+import android.hardware.automotive.vehicle.V2_0.VehicleSeatOccupancyState;
+import android.hardware.automotive.vehicle.V2_0.VehicleTurnSignal;
+import android.hardware.automotive.vehicle.V2_0.VehicleUnit;
 import android.util.Log;
 import android.util.Pair;
 import android.util.SparseArray;
 
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 /**
  * Helper class to define which property IDs are used by PropertyHalService.  This class binds the
@@ -42,11 +64,96 @@
      */
     private final SparseArray<Pair<String, String>> mProps;
     private final HashSet<Integer> mPropForUnits;
+    // Key: propId, Value: possible value for the property
+    private final HashMap<Integer, Set<Integer>> mPropToValidValue;
+    private final HashMap<Integer, Integer> mPropToValidBitFlag;
     private static final String TAG = "PropertyHalServiceIds";
+    // Enums are used as return value in Vehicle HAL.
+    private static final Set<Integer> FUEL_TYPE =
+            new HashSet<>(getIntegersFromDataEnums(FuelType.class));
+    private static final Set<Integer> EV_CONNECTOR_TYPE =
+            new HashSet<>(getIntegersFromDataEnums(EvConnectorType.class));
+    private static final Set<Integer> PORT_LOCATION =
+            new HashSet<>(getIntegersFromDataEnums(PortLocationType.class));
+    private static final Set<Integer> VEHICLE_SEAT =
+            new HashSet<>(getIntegersFromDataEnums(VehicleAreaSeat.class));
+    private static final Set<Integer> OIL_LEVEL =
+            new HashSet<>(getIntegersFromDataEnums(VehicleOilLevel.class));
+    private static final Set<Integer> VEHICLE_GEAR =
+            new HashSet<>(getIntegersFromDataEnums(VehicleGear.class));
+    private static final Set<Integer> TURN_SIGNAL =
+            new HashSet<>(getIntegersFromDataEnums(VehicleTurnSignal.class));
+    private static final Set<Integer> IGNITION_STATE =
+            new HashSet<>(getIntegersFromDataEnums(VehicleIgnitionState.class));
+    private static final Set<Integer> VEHICLE_UNITS =
+            new HashSet<>(getIntegersFromDataEnums(VehicleUnit.class));
+    private static final Set<Integer> SEAT_OCCUPANCY_STATE =
+            new HashSet<>(getIntegersFromDataEnums(VehicleSeatOccupancyState.class));
+    private static final Set<Integer> VEHICLE_LIGHT_STATE =
+            new HashSet<>(getIntegersFromDataEnums(VehicleLightState.class));
+    private static final Set<Integer> VEHICLE_LIGHT_SWITCH =
+            new HashSet<>(getIntegersFromDataEnums(VehicleLightSwitch.class));
+    private static final int HVAC_FAN_DIRECTION_COMBINATIONS =
+            generateAllCombination(VehicleHvacFanDirection.class);
+
+    // default vendor permission
+    private static final int PERMISSION_CAR_VENDOR_DEFAULT = 0x00000000;
+
+    // permissions for the property related with window
+    private static final int PERMISSION_SET_CAR_VENDOR_CATEGORY_WINDOW = 0X00000001;
+    private static final int PERMISSION_GET_CAR_VENDOR_CATEGORY_WINDOW = 0x00000002;
+    // permissions for the property related with door
+    private static final int PERMISSION_SET_CAR_VENDOR_CATEGORY_DOOR = 0x00000003;
+    private static final int PERMISSION_GET_CAR_VENDOR_CATEGORY_DOOR = 0x00000004;
+    // permissions for the property related with seat
+    private static final int PERMISSION_SET_CAR_VENDOR_CATEGORY_SEAT = 0x00000005;
+    private static final int PERMISSION_GET_CAR_VENDOR_CATEGORY_SEAT = 0x00000006;
+    // permissions for the property related with mirror
+    private static final int PERMISSION_SET_CAR_VENDOR_CATEGORY_MIRROR = 0x00000007;
+    private static final int PERMISSION_GET_CAR_VENDOR_CATEGORY_MIRROR = 0x00000008;
+
+    // permissions for the property related with car's information
+    private static final int PERMISSION_SET_CAR_VENDOR_CATEGORY_INFO = 0x00000009;
+    private static final int PERMISSION_GET_CAR_VENDOR_CATEGORY_INFO = 0x0000000A;
+    // permissions for the property related with car's engine
+    private static final int PERMISSION_SET_CAR_VENDOR_CATEGORY_ENGINE = 0x0000000B;
+    private static final int PERMISSION_GET_CAR_VENDOR_CATEGORY_ENGINE = 0x0000000C;
+    // permissions for the property related with car's HVAC
+    private static final int PERMISSION_SET_CAR_VENDOR_CATEGORY_HVAC = 0x0000000D;
+    private static final int PERMISSION_GET_CAR_VENDOR_CATEGORY_HVAC = 0x0000000E;
+    // permissions for the property related with car's light
+    private static final int PERMISSION_SET_CAR_VENDOR_CATEGORY_LIGHT = 0x0000000F;
+    private static final int PERMISSION_GET_CAR_VENDOR_CATEGORY_LIGHT = 0x00000010;
+
+    // permissions reserved for other vendor permission
+    private static final int PERMISSION_SET_CAR_VENDOR_CATEGORY_1 = 0x00010000;
+    private static final int PERMISSION_GET_CAR_VENDOR_CATEGORY_1 = 0x00011000;
+    private static final int PERMISSION_SET_CAR_VENDOR_CATEGORY_2 = 0x00020000;
+    private static final int PERMISSION_GET_CAR_VENDOR_CATEGORY_2 = 0x00021000;
+    private static final int PERMISSION_SET_CAR_VENDOR_CATEGORY_3 = 0x00030000;
+    private static final int PERMISSION_GET_CAR_VENDOR_CATEGORY_3 = 0x00031000;
+    private static final int PERMISSION_SET_CAR_VENDOR_CATEGORY_4 = 0x00040000;
+    private static final int PERMISSION_GET_CAR_VENDOR_CATEGORY_4 = 0x00041000;
+    private static final int PERMISSION_SET_CAR_VENDOR_CATEGORY_5 = 0x00050000;
+    private static final int PERMISSION_GET_CAR_VENDOR_CATEGORY_5 = 0x00051000;
+    private static final int PERMISSION_SET_CAR_VENDOR_CATEGORY_6 = 0x00060000;
+    private static final int PERMISSION_GET_CAR_VENDOR_CATEGORY_6 = 0x00061000;
+    private static final int PERMISSION_SET_CAR_VENDOR_CATEGORY_7 = 0x00070000;
+    private static final int PERMISSION_GET_CAR_VENDOR_CATEGORY_7 = 0x00071000;
+    private static final int PERMISSION_SET_CAR_VENDOR_CATEGORY_8 = 0x00080000;
+    private static final int PERMISSION_GET_CAR_VENDOR_CATEGORY_8 = 0x00081000;
+    private static final int PERMISSION_SET_CAR_VENDOR_CATEGORY_9 = 0x00090000;
+    private static final int PERMISSION_GET_CAR_VENDOR_CATEGORY_9 = 0x00091000;
+    private static final int PERMISSION_SET_CAR_VENDOR_CATEGORY_10 = 0x000A0000;
+    private static final int PERMISSION_GET_CAR_VENDOR_CATEGORY_10 = 0x000A1000;
+    // Not available for android
+    private static final int PERMISSION_CAR_VENDOR_NOT_ACCESSIBLE = 0xF0000000;
 
     public PropertyHalServiceIds() {
         mProps = new SparseArray<>();
         mPropForUnits = new HashSet<>();
+        mPropToValidValue = new HashMap<>();
+        mPropToValidBitFlag = new HashMap<>();
         // Add propertyId and read/write permissions
         // Cabin Properties
         mProps.put(VehicleProperty.DOOR_POS, new Pair<>(
@@ -186,6 +293,9 @@
         mProps.put(VehicleProperty.HVAC_DEFROSTER, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
+        mProps.put(VehicleProperty.HVAC_ELECTRIC_DEFROSTER_ON, new Pair<>(
+                    Car.PERMISSION_CONTROL_CAR_CLIMATE,
+                    Car.PERMISSION_CONTROL_CAR_CLIMATE));
         mProps.put(VehicleProperty.HVAC_AC_ON, new Pair<>(
                     Car.PERMISSION_CONTROL_CAR_CLIMATE,
                     Car.PERMISSION_CONTROL_CAR_CLIMATE));
@@ -260,12 +370,18 @@
         mProps.put(VehicleProperty.INFO_FUEL_DOOR_LOCATION, new Pair<>(
                     Car.PERMISSION_CAR_INFO,
                     null));
+        mProps.put(VehicleProperty.INFO_MULTI_EV_PORT_LOCATIONS, new Pair<>(
+                    Car.PERMISSION_CAR_INFO,
+                    null));
         mProps.put(VehicleProperty.INFO_EV_PORT_LOCATION, new Pair<>(
                     Car.PERMISSION_CAR_INFO,
                     null));
         mProps.put(VehicleProperty.INFO_DRIVER_SEAT, new Pair<>(
                     Car.PERMISSION_CAR_INFO,
                     null));
+        mProps.put(VehicleProperty.INFO_EXTERIOR_DIMENSIONS, new Pair<>(
+                    Car.PERMISSION_CAR_INFO,
+                    null));
 
         // Sensor properties
         mProps.put(VehicleProperty.PERF_ODOMETER, new Pair<>(
@@ -297,13 +413,13 @@
                 null));
         mProps.put(VehicleProperty.FUEL_DOOR_OPEN, new Pair<>(
                 Car.PERMISSION_ENERGY_PORTS,
-                null));
+                Car.PERMISSION_CONTROL_ENERGY_PORTS));
         mProps.put(VehicleProperty.EV_BATTERY_LEVEL, new Pair<>(
                 Car.PERMISSION_ENERGY,
                 null));
         mProps.put(VehicleProperty.EV_CHARGE_PORT_OPEN, new Pair<>(
                 Car.PERMISSION_ENERGY_PORTS,
-                null));
+                Car.PERMISSION_CONTROL_ENERGY_PORTS));
         mProps.put(VehicleProperty.EV_CHARGE_PORT_CONNECTED, new Pair<>(
                 Car.PERMISSION_ENERGY_PORTS,
                 null));
@@ -312,13 +428,16 @@
                 null));
         mProps.put(VehicleProperty.RANGE_REMAINING, new Pair<>(
                 Car.PERMISSION_ENERGY,
-                null));
+                Car.PERMISSION_ADJUST_RANGE_REMAINING));
         mProps.put(VehicleProperty.TIRE_PRESSURE, new Pair<>(
                 Car.PERMISSION_TIRES,
                 null));
         mProps.put(VehicleProperty.PERF_STEERING_ANGLE, new Pair<>(
                 Car.PERMISSION_READ_STEERING_STATE,
                 null));
+        mProps.put(VehicleProperty.PERF_REAR_STEERING_ANGLE, new Pair<>(
+                Car.PERMISSION_READ_STEERING_STATE,
+                null));
         mProps.put(VehicleProperty.GEAR_SELECTION, new Pair<>(
                 Car.PERMISSION_POWERTRAIN,
                 null));
@@ -413,11 +532,51 @@
                 Car.PERMISSION_READ_DISPLAY_UNITS,
                 Car.PERMISSION_CONTROL_DISPLAY_UNITS));
         mPropForUnits.add(VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS);
+
+        mProps.put(VehicleProperty.SUPPORT_CUSTOMIZE_VENDOR_PERMISSION, new Pair<>(
+                Car.PERMISSION_READ_CAR_VENDOR_PERMISSION_INFO,
+                null));
+
+        // mPropToValidValue should contain all properties which has @data_enum in types.hal
+        mPropToValidValue.put(VehicleProperty.INFO_FUEL_TYPE, FUEL_TYPE);
+        mPropToValidValue.put(VehicleProperty.INFO_EV_CONNECTOR_TYPE, EV_CONNECTOR_TYPE);
+        mPropToValidValue.put(VehicleProperty.INFO_FUEL_DOOR_LOCATION, PORT_LOCATION);
+        mPropToValidValue.put(VehicleProperty.INFO_DRIVER_SEAT, VEHICLE_SEAT);
+        mPropToValidValue.put(VehicleProperty.INFO_MULTI_EV_PORT_LOCATIONS, PORT_LOCATION);
+        mPropToValidValue.put(VehicleProperty.ENGINE_OIL_LEVEL, OIL_LEVEL);
+        mPropToValidValue.put(VehicleProperty.GEAR_SELECTION, VEHICLE_GEAR);
+        mPropToValidValue.put(VehicleProperty.CURRENT_GEAR, VEHICLE_GEAR);
+        mPropToValidValue.put(VehicleProperty.TURN_SIGNAL_STATE, TURN_SIGNAL);
+        mPropToValidValue.put(VehicleProperty.IGNITION_STATE, IGNITION_STATE);
+        mPropToValidValue.put(VehicleProperty.HVAC_TEMPERATURE_DISPLAY_UNITS, VEHICLE_UNITS);
+        mPropToValidValue.put(VehicleProperty.DISTANCE_DISPLAY_UNITS, VEHICLE_UNITS);
+        mPropToValidValue.put(VehicleProperty.FUEL_VOLUME_DISPLAY_UNITS, VEHICLE_UNITS);
+        mPropToValidValue.put(VehicleProperty.TIRE_PRESSURE_DISPLAY_UNITS, VEHICLE_UNITS);
+        mPropToValidValue.put(VehicleProperty.EV_BATTERY_DISPLAY_UNITS, VEHICLE_UNITS);
+        mPropToValidValue.put(VehicleProperty.SEAT_OCCUPANCY, SEAT_OCCUPANCY_STATE);
+        mPropToValidValue.put(VehicleProperty.HIGH_BEAM_LIGHTS_STATE, VEHICLE_LIGHT_STATE);
+        mPropToValidValue.put(VehicleProperty.HEADLIGHTS_STATE, VEHICLE_LIGHT_STATE);
+        mPropToValidValue.put(VehicleProperty.FOG_LIGHTS_STATE, VEHICLE_LIGHT_STATE);
+        mPropToValidValue.put(VehicleProperty.HAZARD_LIGHTS_STATE, VEHICLE_LIGHT_STATE);
+        mPropToValidValue.put(VehicleProperty.CABIN_LIGHTS_STATE, VEHICLE_LIGHT_STATE);
+        mPropToValidValue.put(VehicleProperty.READING_LIGHTS_STATE, VEHICLE_LIGHT_STATE);
+        mPropToValidValue.put(VehicleProperty.HEADLIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
+        mPropToValidValue.put(VehicleProperty.HIGH_BEAM_LIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
+        mPropToValidValue.put(VehicleProperty.FOG_LIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
+        mPropToValidValue.put(VehicleProperty.HAZARD_LIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
+        mPropToValidValue.put(VehicleProperty.CABIN_LIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
+        mPropToValidValue.put(VehicleProperty.READING_LIGHTS_SWITCH, VEHICLE_LIGHT_SWITCH);
+
+        // mPropToValidBitFlag contains all properties which return values are combinations of bits
+        mPropToValidBitFlag.put(VehicleProperty.HVAC_FAN_DIRECTION_AVAILABLE,
+                HVAC_FAN_DIRECTION_COMBINATIONS);
+        mPropToValidBitFlag.put(VehicleProperty.HVAC_FAN_DIRECTION,
+                HVAC_FAN_DIRECTION_COMBINATIONS);
     }
 
     /**
      * @param propId Property ID
-     * @return Read permission string for given property ID. NULL if property ID dose not exist or
+     * @return Read permission string for given property ID. NULL if property ID does not exist or
      * the property is not available for reading.
      */
     @Nullable
@@ -429,6 +588,9 @@
                 Log.e(TAG, "propId is not available for reading : 0x" + toHexString(propId));
             }
             return p.first;
+        } else if (isVendorProperty(propId)) {
+            // if property is vendor property and do not have specific permission.
+            return Car.PERMISSION_VENDOR_EXTENSION;
         } else {
             return null;
         }
@@ -436,7 +598,7 @@
 
     /**
      * @param propId Property ID
-     * @return Write permission string for given property ID. NULL if property ID dose not exist or
+     * @return Write permission string for given property ID. NULL if property ID does not exist or
      * the property is not writable.
      */
     @Nullable
@@ -448,36 +610,23 @@
                 Log.e(TAG, "propId is not writable : 0x" + toHexString(propId));
             }
             return p.second;
+        } else if (isVendorProperty(propId)) {
+            // if property is vendor property and do not have specific permission.
+            return Car.PERMISSION_VENDOR_EXTENSION;
         } else {
             return null;
         }
     }
 
-    /**
-     * Return true if property is a vendor property and was added
-     */
-    public boolean insertVendorProperty(int propId) {
-        if ((propId & VehiclePropertyGroup.MASK) == VehiclePropertyGroup.VENDOR) {
-            mProps.put(propId, new Pair<>(
-                    Car.PERMISSION_VENDOR_EXTENSION, Car.PERMISSION_VENDOR_EXTENSION));
-            return true;
-        } else {
-            // This is not a vendor extension property, it is not added
-            return false;
-        }
+    private static boolean isVendorProperty(int propId) {
+        return (propId & VehiclePropertyGroup.MASK) == VehiclePropertyGroup.VENDOR;
     }
-
     /**
      * Check if property ID is in the list of known IDs that PropertyHalService is interested it.
      */
     public boolean isSupportedProperty(int propId) {
-        if (mProps.get(propId) != null) {
-            // Property is in the list of supported properties
-            return true;
-        } else {
-            // If it's a vendor property, insert it into the propId list and handle it
-            return insertVendorProperty(propId);
-        }
+        // Property is in the list of supported properties
+        return mProps.get(propId) != null || isVendorProperty(propId);
     }
 
     /**
@@ -486,4 +635,226 @@
     public boolean isPropertyToChangeUnits(int propertyId) {
         return mPropForUnits.contains(propertyId);
     }
+
+    /**
+     * Overrides the permission map for vendor properties
+     *
+     * @param configArray the configArray for
+     * {@link VehicleProperty#SUPPORT_CUSTOMIZE_VENDOR_PERMISSION}
+     */
+    public void customizeVendorPermission(@NonNull List<Integer> configArray) {
+        if (configArray == null || configArray.size() % 3 != 0) {
+            throw new IllegalArgumentException(
+                    "ConfigArray for SUPPORT_CUSTOMIZE_VENDOR_PERMISSION is wrong");
+        }
+        int index = 0;
+        while (index < configArray.size()) {
+            int propId = configArray.get(index++);
+            if (!isVendorProperty(propId)) {
+                throw new IllegalArgumentException("Property Id: " + propId
+                        + " is not in vendor range");
+            }
+            int readPermission = configArray.get(index++);
+            int writePermission = configArray.get(index++);
+            mProps.put(propId, new Pair<>(
+                    toPermissionString(readPermission, propId),
+                    toPermissionString(writePermission, propId)));
+        }
+
+    }
+
+    /**
+     * Map VehicleVendorPermission enums in VHAL to android permissions.
+     *
+     * @return permission string, return null if vendor property is not available.
+     */
+    @Nullable
+    private String toPermissionString(int permissionEnum, int propId) {
+        switch (permissionEnum) {
+            case PERMISSION_CAR_VENDOR_DEFAULT:
+                return Car.PERMISSION_VENDOR_EXTENSION;
+            case PERMISSION_SET_CAR_VENDOR_CATEGORY_WINDOW:
+                return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_WINDOW;
+            case PERMISSION_GET_CAR_VENDOR_CATEGORY_WINDOW:
+                return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_WINDOW;
+            case PERMISSION_SET_CAR_VENDOR_CATEGORY_DOOR:
+                return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_DOOR;
+            case PERMISSION_GET_CAR_VENDOR_CATEGORY_DOOR:
+                return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_DOOR;
+            case PERMISSION_SET_CAR_VENDOR_CATEGORY_SEAT:
+                return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_SEAT;
+            case PERMISSION_GET_CAR_VENDOR_CATEGORY_SEAT:
+                return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_SEAT;
+            case PERMISSION_SET_CAR_VENDOR_CATEGORY_MIRROR:
+                return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_MIRROR;
+            case PERMISSION_GET_CAR_VENDOR_CATEGORY_MIRROR:
+                return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_MIRROR;
+            case PERMISSION_SET_CAR_VENDOR_CATEGORY_INFO:
+                return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_INFO;
+            case PERMISSION_GET_CAR_VENDOR_CATEGORY_INFO:
+                return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_INFO;
+            case PERMISSION_SET_CAR_VENDOR_CATEGORY_ENGINE:
+                return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_ENGINE;
+            case PERMISSION_GET_CAR_VENDOR_CATEGORY_ENGINE:
+                return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_ENGINE;
+            case PERMISSION_SET_CAR_VENDOR_CATEGORY_HVAC:
+                return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_HVAC;
+            case PERMISSION_GET_CAR_VENDOR_CATEGORY_HVAC:
+                return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_HVAC;
+            case PERMISSION_SET_CAR_VENDOR_CATEGORY_LIGHT:
+                return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_LIGHT;
+            case PERMISSION_GET_CAR_VENDOR_CATEGORY_LIGHT:
+                return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_LIGHT;
+            case PERMISSION_SET_CAR_VENDOR_CATEGORY_1:
+                return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_1;
+            case PERMISSION_GET_CAR_VENDOR_CATEGORY_1:
+                return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_1;
+            case PERMISSION_SET_CAR_VENDOR_CATEGORY_2:
+                return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_2;
+            case PERMISSION_GET_CAR_VENDOR_CATEGORY_2:
+                return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_2;
+            case PERMISSION_SET_CAR_VENDOR_CATEGORY_3:
+                return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_3;
+            case PERMISSION_GET_CAR_VENDOR_CATEGORY_3:
+                return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_3;
+            case PERMISSION_SET_CAR_VENDOR_CATEGORY_4:
+                return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_4;
+            case PERMISSION_GET_CAR_VENDOR_CATEGORY_4:
+                return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_4;
+            case PERMISSION_SET_CAR_VENDOR_CATEGORY_5:
+                return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_5;
+            case PERMISSION_GET_CAR_VENDOR_CATEGORY_5:
+                return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_5;
+            case PERMISSION_SET_CAR_VENDOR_CATEGORY_6:
+                return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_6;
+            case PERMISSION_GET_CAR_VENDOR_CATEGORY_6:
+                return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_6;
+            case PERMISSION_SET_CAR_VENDOR_CATEGORY_7:
+                return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_7;
+            case PERMISSION_GET_CAR_VENDOR_CATEGORY_7:
+                return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_7;
+            case PERMISSION_SET_CAR_VENDOR_CATEGORY_8:
+                return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_8;
+            case PERMISSION_GET_CAR_VENDOR_CATEGORY_8:
+                return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_8;
+            case PERMISSION_SET_CAR_VENDOR_CATEGORY_9:
+                return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_9;
+            case PERMISSION_GET_CAR_VENDOR_CATEGORY_9:
+                return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_9;
+            case PERMISSION_SET_CAR_VENDOR_CATEGORY_10:
+                return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_10;
+            case PERMISSION_GET_CAR_VENDOR_CATEGORY_10:
+                return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_10;
+            case PERMISSION_CAR_VENDOR_NOT_ACCESSIBLE:
+                return null;
+            default:
+                throw new IllegalArgumentException("permission Id: " + permissionEnum
+                    + " for property:" + propId + " is invalid vendor permission Id");
+        }
+    }
+
+    /**
+     * Checks property value's format for all properties. Checks property value range if property
+     * has @data_enum flag in types.hal.
+     * @return true if property value's payload is valid.
+     */
+    public boolean checkPayload(VehiclePropValue propValue) {
+        // Mixed property uses config array to indicate the data format. Checked it when convert it
+        // to CarPropertyValue.
+        if ((propValue.prop & VehiclePropertyType.MASK) == VehiclePropertyType.MIXED) {
+            return true;
+        }
+        if (!checkFormatForAllProperties(propValue)) {
+            Log.e(TAG, "Property value" + propValue + "has an invalid data format");
+            return false;
+        }
+        if (mPropToValidValue.containsKey(propValue.prop)) {
+            return checkDataEnum(propValue);
+        }
+        if (mPropToValidBitFlag.containsKey(propValue.prop)) {
+            return checkValidBitFlag(propValue);
+        }
+        return true;
+    }
+
+    private boolean checkValidBitFlag(VehiclePropValue propValue) {
+        int flagCombination = mPropToValidBitFlag.get(propValue.prop);
+        for (int value : propValue.value.int32Values) {
+            if ((value & flagCombination) != value) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean checkFormatForAllProperties(VehiclePropValue propValue) {
+        int propId = propValue.prop;
+        VehiclePropValue.RawValue rawValue = propValue.value;
+        //Records sum size of int32values, floatValue, int64Values, bytes, String
+        int sizeOfAllValue = rawValue.int32Values.size() + rawValue.floatValues.size()
+                + rawValue.int64Values.size() + rawValue.bytes.size()
+                + rawValue.stringValue.length();
+        if (sizeOfAllValue == 0) {
+            Log.e(TAG, "Property value is empty: " + propValue);
+            return false;
+        }
+        switch (propId & VehiclePropertyType.MASK) {
+            case VehiclePropertyType.BOOLEAN:
+            case VehiclePropertyType.INT32:
+                return sizeOfAllValue == 1 && rawValue.int32Values.size() == 1;
+            case VehiclePropertyType.FLOAT:
+                return sizeOfAllValue == 1 && rawValue.floatValues.size() == 1;
+            case VehiclePropertyType.INT64:
+                return sizeOfAllValue == 1 && rawValue.int64Values.size() == 1;
+            case VehiclePropertyType.FLOAT_VEC:
+                return sizeOfAllValue == rawValue.floatValues.size();
+            case VehiclePropertyType.INT64_VEC:
+                return sizeOfAllValue == rawValue.int64Values.size();
+            case VehiclePropertyType.INT32_VEC:
+                return sizeOfAllValue == rawValue.int32Values.size();
+            case VehiclePropertyType.BYTES:
+                return sizeOfAllValue == rawValue.bytes.size();
+            case VehiclePropertyType.STRING:
+                return sizeOfAllValue == rawValue.stringValue.length();
+            default:
+                throw new IllegalArgumentException("Unexpected property type for propId: "
+                        + Integer.toHexString(propId));
+        }
+    }
+    private boolean checkDataEnum(VehiclePropValue propValue) {
+        int propId = propValue.prop;
+        VehiclePropValue.RawValue rawValue = propValue.value;
+        Set<Integer> validValue = mPropToValidValue.get(propId);
+        for (int value : rawValue.int32Values) {
+            if (!validValue.contains(value)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static List<Integer> getIntegersFromDataEnums(Class clazz) {
+        Field[] fields = clazz.getDeclaredFields();
+        List<Integer> integerList = new ArrayList<>(5);
+        for (Field f : fields) {
+            if (f.getType() == int.class) {
+                try {
+                    integerList.add(f.getInt(clazz));
+                } catch (Exception e) {
+                    Log.w(TAG, "Failed to get value");
+                }
+            }
+        }
+        return integerList;
+    }
+
+    // Generate all combinations at once
+    private static int generateAllCombination(Class clazz) {
+        List<Integer> allBits = getIntegersFromDataEnums(clazz);
+        int combination = allBits.get(0);
+        for (int i = 1; i < allBits.size(); i++) {
+            combination |= allBits.get(i);
+        }
+        return combination;
+    }
 }
diff --git a/service/src/com/android/car/hal/PropertyTimeoutException.java b/service/src/com/android/car/hal/PropertyTimeoutException.java
deleted file mode 100644
index 2d6120d..0000000
--- a/service/src/com/android/car/hal/PropertyTimeoutException.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.hal;
-
-import static java.lang.Integer.toHexString;
-
-/**
- * This exception is raised when IVehicle#get or IVehicle#set returns StatusCode.TRY_AGAIN. This
- * usually happens during boot-up meaning that Vehicle HAL is not ready to get or set that property.
- */
-class PropertyTimeoutException extends Exception {
-    PropertyTimeoutException(int property) {
-        super("Property 0x" + toHexString(property) + " is not ready yet.");
-    }
-}
diff --git a/service/src/com/android/car/hal/UserHalService.java b/service/src/com/android/car/hal/UserHalService.java
new file mode 100644
index 0000000..acf26c4
--- /dev/null
+++ b/service/src/com/android/car/hal/UserHalService.java
@@ -0,0 +1,1171 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.hal;
+
+import static android.car.VehiclePropertyIds.CREATE_USER;
+import static android.car.VehiclePropertyIds.INITIAL_USER_INFO;
+import static android.car.VehiclePropertyIds.REMOVE_USER;
+import static android.car.VehiclePropertyIds.SWITCH_USER;
+import static android.car.VehiclePropertyIds.USER_IDENTIFICATION_ASSOCIATION;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.car.hardware.property.CarPropertyManager;
+import android.car.user.CarUserManager;
+import android.car.userlib.HalCallback;
+import android.car.userlib.UserHalHelper;
+import android.car.userlib.UserHelper;
+import android.hardware.automotive.vehicle.V2_0.CreateUserRequest;
+import android.hardware.automotive.vehicle.V2_0.CreateUserResponse;
+import android.hardware.automotive.vehicle.V2_0.CreateUserStatus;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
+import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
+import android.hardware.automotive.vehicle.V2_0.SwitchUserMessageType;
+import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
+import android.hardware.automotive.vehicle.V2_0.SwitchUserResponse;
+import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociation;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetAssociation;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
+import android.hardware.automotive.vehicle.V2_0.UsersInfo;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.ServiceSpecificException;
+import android.sysprop.CarProperties;
+import android.text.TextUtils;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+
+import com.android.car.CarLocalServices;
+import com.android.car.CarStatsLog;
+import com.android.car.user.CarUserService;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.car.EventLogTags;
+import com.android.internal.util.FunctionalUtils;
+import com.android.internal.util.Preconditions;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * Service used to integrate the OEM's custom user management with Android's.
+ */
+public final class UserHalService extends HalServiceBase {
+
+    private static final String TAG = UserHalService.class.getSimpleName();
+
+    private static final String UNSUPPORTED_MSG = "Vehicle HAL does not support user management";
+    private static final String USER_ASSOCIATION_UNSUPPORTED_MSG =
+            "Vehicle HAL does not support user association";
+
+    private static final int[] SUPPORTED_PROPERTIES = new int[]{
+            CREATE_USER,
+            INITIAL_USER_INFO,
+            REMOVE_USER,
+            SWITCH_USER,
+            USER_IDENTIFICATION_ASSOCIATION
+    };
+
+    private static final int[] CORE_PROPERTIES = new int[]{
+            CREATE_USER,
+            INITIAL_USER_INFO,
+            REMOVE_USER,
+            SWITCH_USER,
+    };
+
+    private static final boolean DBG = false;
+
+    private final Object mLock = new Object();
+
+    private final VehicleHal mHal;
+
+    @GuardedBy("mLock")
+    @Nullable
+    private SparseArray<VehiclePropConfig> mProperties;
+
+    // This handler handles 2 types of messages:
+    // - "Anonymous" messages (what=0) containing runnables.
+    // - "Identifiable" messages used to check for timeouts (whose 'what' is the request id).
+    private final Handler mHandler;
+
+    /**
+     * Value used on the next request.
+     */
+    @GuardedBy("mLock")
+    private int mNextRequestId = 1;
+
+    /**
+     * Map of callbacks by request id.
+     */
+    @GuardedBy("mLock")
+    private final SparseArray<PendingRequest<?, ?>> mPendingRequests = new SparseArray<>();
+
+    public UserHalService(VehicleHal hal) {
+        this(hal, new Handler(Looper.getMainLooper()));
+    }
+
+    @VisibleForTesting
+    UserHalService(VehicleHal hal, Handler handler) {
+        mHal = hal;
+        mHandler = handler;
+    }
+
+    @Override
+    public void init() {
+        if (DBG) Log.d(TAG, "init()");
+
+        if (mProperties == null) {
+            return;
+        }
+
+        int size = mProperties.size();
+        for (int i = 0; i < size; i++) {
+            VehiclePropConfig config = mProperties.valueAt(i);
+            if (VehicleHal.isPropertySubscribable(config)) {
+                if (DBG) Log.d(TAG, "subscribing to property " + config.prop);
+                mHal.subscribeProperty(this, config.prop);
+            }
+        }
+    }
+
+    @Override
+    public void release() {
+        if (DBG) Log.d(TAG, "release()");
+    }
+
+    @Override
+    public void onHalEvents(List<VehiclePropValue> values) {
+        if (DBG) Log.d(TAG, "handleHalEvents(): " + values);
+
+        for (int i = 0; i < values.size(); i++) {
+            VehiclePropValue value = values.get(i);
+            switch (value.prop) {
+                case INITIAL_USER_INFO:
+                    mHandler.sendMessage(obtainMessage(
+                            UserHalService::handleOnInitialUserInfoResponse, this, value));
+                    break;
+                case SWITCH_USER:
+                    mHandler.sendMessage(obtainMessage(
+                            UserHalService::handleOnSwitchUserResponse, this, value));
+                    break;
+                case CREATE_USER:
+                    mHandler.sendMessage(obtainMessage(
+                            UserHalService::handleOnCreateUserResponse, this, value));
+                    break;
+                case REMOVE_USER:
+                    Log.w(TAG, "Received REMOVE_USER HAL event: " + value);
+                    break;
+                case USER_IDENTIFICATION_ASSOCIATION:
+                    mHandler.sendMessage(obtainMessage(
+                            UserHalService::handleOnUserIdentificationAssociation, this, value));
+                    break;
+                default:
+                    Log.w(TAG, "received unsupported event from HAL: " + value);
+            }
+        }
+    }
+
+    @Override
+    public void onPropertySetError(int property, int area,
+            @CarPropertyManager.CarSetPropertyErrorCode int errorCode) {
+        if (DBG) Log.d(TAG, "handlePropertySetError(" + property + "/" + area + ")");
+    }
+
+    @Override
+    public int[] getAllSupportedProperties() {
+        return SUPPORTED_PROPERTIES;
+    }
+
+    @Override
+    public void takeProperties(Collection<VehiclePropConfig> properties) {
+        if (properties.isEmpty()) {
+            Log.w(TAG, UNSUPPORTED_MSG);
+            return;
+        }
+        SparseArray<VehiclePropConfig> supportedProperties = new SparseArray<>(5);
+        for (VehiclePropConfig config : properties) {
+            supportedProperties.put(config.prop, config);
+        }
+        synchronized (mLock) {
+            mProperties = supportedProperties;
+        }
+    }
+
+    /**
+     * Checks if the Vehicle HAL supports core user management actions.
+     */
+    public boolean isSupported() {
+        synchronized (mLock) {
+            if (mProperties == null) return false;
+
+            for (int i = 0; i < CORE_PROPERTIES.length; i++) {
+                if (mProperties.get(CORE_PROPERTIES[i]) == null) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    /**
+     * Checks if the Vehicle HAL supports core user management actions.
+     */
+    public boolean isUserAssociationSupported() {
+        synchronized (mLock) {
+            if (mProperties == null) return false;
+            if (mProperties.get(USER_IDENTIFICATION_ASSOCIATION) == null) return false;
+            return true;
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void checkSupported() {
+        Preconditions.checkState(isSupported(), UNSUPPORTED_MSG);
+    }
+
+    @GuardedBy("mLock")
+    private void checkUserAssociationSupported() {
+        Preconditions.checkState(isUserAssociationSupported(), USER_ASSOCIATION_UNSUPPORTED_MSG);
+    }
+
+
+    /**
+     * Calls HAL to asynchronously get info about the initial user.
+     *
+     * @param requestType type of request (as defined by
+     * {@link android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType}).
+     * @param timeoutMs how long to wait (in ms) for the property change event.
+     * @param usersInfo current state of Android users.
+     * @param callback to handle the response.
+     *
+     * @throws IllegalStateException if the HAL does not support user management (callers should
+     * call {@link #isSupported()} first to avoid this exception).
+     */
+    public void getInitialUserInfo(int requestType, int timeoutMs, @NonNull UsersInfo usersInfo,
+            @NonNull HalCallback<InitialUserInfoResponse> callback) {
+        if (DBG) Log.d(TAG, "getInitialInfo(" + requestType + ")");
+        Preconditions.checkArgumentPositive(timeoutMs, "timeout must be positive");
+        Objects.requireNonNull(usersInfo);
+        UserHalHelper.checkValid(usersInfo);
+        Objects.requireNonNull(callback);
+        checkSupported();
+
+        int requestId = getNextRequestId();
+        VehiclePropValue propRequest = UserHalHelper.createPropRequest(INITIAL_USER_INFO, requestId,
+                requestType);
+        UserHalHelper.addUsersInfo(propRequest, usersInfo);
+
+        synchronized (mLock) {
+            if (hasPendingRequestLocked(InitialUserInfoResponse.class, callback)) return;
+            addPendingRequestLocked(requestId, InitialUserInfoResponse.class, callback);
+        }
+
+        EventLog.writeEvent(EventLogTags.CAR_USER_HAL_INITIAL_USER_INFO_REQ, requestId,
+                requestType, timeoutMs);
+        CarStatsLog.write(CarStatsLog.CAR_USER_HAL_INITIAL_USER_INFO_REQUEST_REPORTED,
+                requestId, getInitialUserInfoRequestTypeForStatsd(requestType), timeoutMs);
+
+        sendHalRequest(requestId, timeoutMs, propRequest, callback);
+    }
+
+    private static int getInitialUserInfoRequestTypeForStatsd(int requestType) {
+        // CHECKSTYLE:OFF IndentationCheck
+        switch (requestType) {
+            case InitialUserInfoRequestType.FIRST_BOOT:
+                return CarStatsLog
+                        .CAR_USER_HAL_INITIAL_USER_INFO_REQUEST_REPORTED__REQUEST_TYPE__FIRST_BOOT;
+            case InitialUserInfoRequestType.FIRST_BOOT_AFTER_OTA:
+                return CarStatsLog
+               .CAR_USER_HAL_INITIAL_USER_INFO_REQUEST_REPORTED__REQUEST_TYPE__FIRST_BOOT_AFTER_OTA;
+            case InitialUserInfoRequestType.COLD_BOOT:
+                return CarStatsLog
+                        .CAR_USER_HAL_INITIAL_USER_INFO_REQUEST_REPORTED__REQUEST_TYPE__COLD_BOOT;
+            case InitialUserInfoRequestType.RESUME:
+                return CarStatsLog
+                        .CAR_USER_HAL_INITIAL_USER_INFO_REQUEST_REPORTED__REQUEST_TYPE__RESUME;
+            default:
+                return CarStatsLog
+                        .CAR_USER_HAL_INITIAL_USER_INFO_REQUEST_REPORTED__REQUEST_TYPE__UNKNOWN;
+        }
+        // CHECKSTYLE:ON IndentationCheck
+    }
+
+    private void sendHalRequest(int requestId, int timeoutMs, @NonNull VehiclePropValue request,
+            @NonNull HalCallback<?> callback) {
+        mHandler.sendMessageDelayed(obtainMessage(
+                UserHalService::handleCheckIfRequestTimedOut, this, requestId).setWhat(requestId),
+                timeoutMs);
+        try {
+            if (DBG) Log.d(TAG, "Calling hal.set(): " + request);
+            mHal.set(request);
+        } catch (ServiceSpecificException e) {
+            handleRemovePendingRequest(requestId);
+            Log.w(TAG, "Failed to set " + request, e);
+            callback.onResponse(HalCallback.STATUS_HAL_SET_TIMEOUT, null);
+        }
+    }
+
+    /**
+     * Calls HAL to asynchronously switch user.
+     *
+     * @param request metadata
+     * @param timeoutMs how long to wait (in ms) for the property change event.
+     * @param callback to handle the response.
+     *
+     * @throws IllegalStateException if the HAL does not support user management (callers should
+     * call {@link #isSupported()} first to avoid this exception).
+     */
+    public void switchUser(@NonNull SwitchUserRequest request, int timeoutMs,
+            @NonNull HalCallback<SwitchUserResponse> callback) {
+        Preconditions.checkArgumentPositive(timeoutMs, "timeout must be positive");
+        Objects.requireNonNull(callback, "callback cannot be null");
+        Objects.requireNonNull(request, "request cannot be null");
+        if (DBG) Log.d(TAG, "switchUser(" + request + ")");
+
+        checkSupported();
+        request.requestId = getNextRequestId();
+        request.messageType = SwitchUserMessageType.ANDROID_SWITCH;
+        VehiclePropValue propRequest = UserHalHelper.toVehiclePropValue(request);
+
+        synchronized (mLock) {
+            if (hasPendingRequestLocked(SwitchUserResponse.class, callback)) return;
+            addPendingRequestLocked(request.requestId, SwitchUserResponse.class, callback);
+        }
+
+        EventLog.writeEvent(EventLogTags.CAR_USER_HAL_SWITCH_USER_REQ, request.requestId,
+                request.targetUser.userId, timeoutMs);
+        CarStatsLog.write(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED, request.requestId,
+                CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__SWITCH_REQUEST_ANDROID,
+                request.usersInfo.currentUser.userId, request.usersInfo.currentUser.flags,
+                request.targetUser.userId, request.targetUser.flags, timeoutMs);
+
+        sendHalRequest(request.requestId, timeoutMs, propRequest, callback);
+    }
+
+    /**
+     * Calls HAL to remove user.
+     *
+     * @throws IllegalStateException if the HAL does not support user management (callers should
+     * call {@link #isSupported()} first to avoid this exception).
+     */
+    public void removeUser(@NonNull RemoveUserRequest request) {
+        Objects.requireNonNull(request, "request cannot be null");
+        if (DBG) Log.d(TAG, "removeUser(" + request + ")");
+
+        checkSupported();
+        request.requestId = getNextRequestId();
+        VehiclePropValue propRequest = UserHalHelper.toVehiclePropValue(request);
+
+        EventLog.writeEvent(EventLogTags.CAR_USER_HAL_REMOVE_USER_REQ,
+                request.removedUserInfo.userId, request.usersInfo.currentUser.userId);
+        CarStatsLog.write(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED, request.requestId,
+                CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__REMOVE_REQUEST,
+                request.usersInfo.currentUser.userId, request.usersInfo.currentUser.flags,
+                request.removedUserInfo.userId, request.removedUserInfo.flags, /* timeout */ -1);
+
+        try {
+            if (DBG) Log.d(TAG, "Calling hal.set(): " + propRequest);
+            mHal.set(propRequest);
+        } catch (ServiceSpecificException e) {
+            Log.w(TAG, "Failed to set REMOVE USER", e);
+        }
+    }
+
+    /**
+     * Calls HAL to indicate an Android user was created.
+     *
+     * @param request info about the created user.
+     * @param timeoutMs how long to wait (in ms) for the property change event.
+     * @param callback to handle the response.
+     *
+     * @throws IllegalStateException if the HAL does not support user management (callers should
+     * call {@link #isSupported()} first to avoid this exception).
+     */
+    public void createUser(@NonNull CreateUserRequest request, int timeoutMs,
+            @NonNull HalCallback<CreateUserResponse> callback) {
+        Objects.requireNonNull(request);
+        Preconditions.checkArgumentPositive(timeoutMs, "timeout must be positive");
+        Objects.requireNonNull(callback);
+        if (DBG) Log.d(TAG, "createUser(): req=" + request + ", timeout=" + timeoutMs);
+
+        checkSupported();
+        request.requestId = getNextRequestId();
+        VehiclePropValue propRequest = UserHalHelper.toVehiclePropValue(request);
+
+        synchronized (mLock) {
+            if (hasPendingRequestLocked(CreateUserResponse.class, callback)) return;
+            addPendingRequestLocked(request.requestId, CreateUserResponse.class, callback);
+        }
+
+        EventLog.writeEvent(EventLogTags.CAR_USER_HAL_CREATE_USER_REQ, request.requestId,
+                UserHelper.safeName(request.newUserName), request.newUserInfo.flags, timeoutMs);
+        CarStatsLog.write(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED, request.requestId,
+                CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__CREATE_REQUEST,
+                request.usersInfo.currentUser.userId, request.usersInfo.currentUser.flags,
+                request.newUserInfo.userId, request.newUserInfo.flags, timeoutMs);
+
+        sendHalRequest(request.requestId, timeoutMs, propRequest, callback);
+    }
+
+    /**
+     * Calls HAL after android user switch.
+     */
+    public void postSwitchResponse(@NonNull SwitchUserRequest request) {
+        Objects.requireNonNull(request, "request cannot be null");
+        if (DBG) Log.d(TAG, "postSwitchResponse(" + request + ")");
+
+        checkSupported();
+        request.messageType = SwitchUserMessageType.ANDROID_POST_SWITCH;
+        VehiclePropValue propRequest = UserHalHelper.toVehiclePropValue(request);
+
+        EventLog.writeEvent(EventLogTags.CAR_USER_HAL_POST_SWITCH_USER_REQ, request.requestId,
+                request.targetUser.userId, request.usersInfo.currentUser.userId);
+        CarStatsLog.write(CarStatsLog.CAR_USER_HAL_POST_SWITCH_RESPONSE_REPORTED, request.requestId,
+                request.targetUser.userId == request.usersInfo.currentUser.userId
+                ? CarStatsLog.CAR_USER_HAL_POST_SWITCH_RESPONSE_REPORTED__SWITCH_STATUS__SUCCESS
+                : CarStatsLog.CAR_USER_HAL_POST_SWITCH_RESPONSE_REPORTED__SWITCH_STATUS__FAILURE);
+
+        try {
+            if (DBG) Log.d(TAG, "Calling hal.set(): " + propRequest);
+            mHal.set(propRequest);
+        } catch (ServiceSpecificException e) {
+            Log.w(TAG, "Failed to set ANDROID POST SWITCH", e);
+        }
+    }
+
+    /**
+     * Calls HAL to switch user after legacy Android user switch. Legacy Android user switch means
+     * user switch is not requested by {@link CarUserManager} or OEM, and user switch is directly
+     * requested by {@link ActivityManager}
+     */
+    public void legacyUserSwitch(@NonNull SwitchUserRequest request) {
+        Objects.requireNonNull(request, "request cannot be null");
+        if (DBG) Log.d(TAG, "userSwitchLegacy(" + request + ")");
+
+        checkSupported();
+        request.requestId = getNextRequestId();
+        request.messageType = SwitchUserMessageType.LEGACY_ANDROID_SWITCH;
+        VehiclePropValue propRequest = UserHalHelper.toVehiclePropValue(request);
+
+        EventLog.writeEvent(EventLogTags.CAR_USER_HAL_LEGACY_SWITCH_USER_REQ, request.requestId,
+                request.targetUser.userId, request.usersInfo.currentUser.userId);
+        //CHECKSTYLE:OFF IndentationCheck
+        CarStatsLog.write(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED,
+                request.requestId, CarStatsLog
+                .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__SWITCH_REQUEST_LEGACY,
+                request.usersInfo.currentUser.userId, request.usersInfo.currentUser.flags,
+                request.targetUser.userId, request.targetUser.flags, /* timeout_ms= */ -1);
+        //CHECKSTYLE:ON IndentationCheck
+
+        try {
+            if (DBG) Log.d(TAG, "Calling hal.set(): " + propRequest);
+            mHal.set(propRequest);
+        } catch (ServiceSpecificException e) {
+            Log.w(TAG, "Failed to set LEGACY ANDROID SWITCH", e);
+        }
+    }
+
+    /**
+     * Calls HAL to get the value of the user identifications associated with the given user.
+     *
+     * @return HAL response or {@code null} if it was invalid (for example, mismatch on the
+     * requested number of associations).
+     *
+     * @throws IllegalArgumentException if request is invalid (mismatch on number of associations,
+     *   duplicated association, invalid association type values, etc).
+     */
+    @Nullable
+    public UserIdentificationResponse getUserAssociation(
+            @NonNull UserIdentificationGetRequest request) {
+        Objects.requireNonNull(request, "request cannot be null");
+        checkUserAssociationSupported();
+
+        // Check that it doesn't have dupes
+        SparseBooleanArray types = new SparseBooleanArray(request.numberAssociationTypes);
+        for (int i = 0; i < request.numberAssociationTypes; i++) {
+            int type = request.associationTypes.get(i);
+            Preconditions.checkArgument(!types.get(type), "type %s found more than once on %s",
+                    UserIdentificationAssociationType.toString(type), request);
+            types.put(type, true);
+        }
+
+        request.requestId = getNextRequestId();
+
+        if (DBG) Log.d(TAG, "getUserAssociation(): req=" + request);
+
+        VehiclePropValue requestAsPropValue = UserHalHelper.toVehiclePropValue(request);
+
+        EventLog.writeEvent(EventLogTags.CAR_USER_HAL_GET_USER_AUTH_REQ,
+                requestAsPropValue.value.int32Values.toArray());
+
+        VehiclePropValue responseAsPropValue = mHal.get(requestAsPropValue);
+        if (responseAsPropValue == null) {
+            Log.w(TAG, "HAL returned null for request " + requestAsPropValue);
+            return null;
+        }
+
+        logEventWithErrorMessage(EventLogTags.CAR_USER_HAL_GET_USER_AUTH_RESP, responseAsPropValue);
+        if (DBG) Log.d(TAG, "getUserAssociation(): responseAsPropValue=" + responseAsPropValue);
+
+        UserIdentificationResponse response;
+        try {
+            response = UserHalHelper.toUserIdentificationResponse(responseAsPropValue);
+        } catch (IllegalArgumentException e) {
+            Log.w(TAG, "invalid response from HAL for " + requestAsPropValue, e);
+            return null;
+        }
+        if (DBG) Log.d(TAG, "getUserAssociation(): response=" + response);
+
+        // Validate the response according to the request
+        if (response.requestId != request.requestId) {
+            Log.w(TAG, "invalid request id (should be " + request.requestId + ") on HAL response: "
+                    + response);
+            return null;
+        }
+        if (response.numberAssociation != request.numberAssociationTypes) {
+            Log.w(TAG, "Wrong number of association types on HAL response (expected "
+                    + request.numberAssociationTypes + ") for request " + requestAsPropValue
+                    + ": " + response);
+            return null;
+        }
+        for (int i = 0; i < request.numberAssociationTypes; i++) {
+            int expectedType = request.associationTypes.get(i);
+            int actualType = response.associations.get(i).type;
+            if (actualType != expectedType) {
+                Log.w(TAG, "Wrong type on index " + i + " of HAL response (" + response + ") for "
+                        + "request " + requestAsPropValue + " : expected "
+                        + UserIdentificationAssociationType.toString(expectedType)
+                        + ", got " + UserIdentificationAssociationType.toString(actualType));
+                return null;
+            }
+        }
+
+        // TODO(b/153900032): move this logic to a common helper
+        int[] associationTypes = new int[response.numberAssociation];
+        int[] associationValues = new int[response.numberAssociation];
+        for (int i = 0; i < response.numberAssociation; i++) {
+            UserIdentificationAssociation association = response.associations.get(i);
+            associationTypes[i] = association.type;
+            associationValues[i] = association.value;
+        }
+
+        CarStatsLog.write(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED,
+                request.requestId,
+                CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED__REQUEST_TYPE__GET,
+                request.userInfo.userId,
+                request.userInfo.flags,
+                request.numberAssociationTypes,
+                Arrays.toString(associationTypes), Arrays.toString(associationValues));
+
+        return response;
+    }
+
+    /**
+     * Calls HAL to set the value of the user identifications associated with the given user.
+     *
+     * @throws IllegalArgumentException if request is invalid (mismatch on number of associations,
+     *   duplicated association, invalid association type values, etc).
+     */
+    public void setUserAssociation(int timeoutMs, @NonNull UserIdentificationSetRequest request,
+            @NonNull HalCallback<UserIdentificationResponse> callback) {
+        Preconditions.checkArgumentPositive(timeoutMs, "timeout must be positive");
+        Objects.requireNonNull(request, "request cannot be null");
+        Objects.requireNonNull(callback, "callback cannot be null");
+        if (DBG) Log.d(TAG, "setUserAssociation(" + request + ")");
+
+        // Check that it doesn't have dupes
+        SparseBooleanArray types = new SparseBooleanArray(request.numberAssociations);
+        for (int i = 0; i < request.numberAssociations; i++) {
+            int type = request.associations.get(i).type;
+            Preconditions.checkArgument(!types.get(type), "type %s found more than once on %s",
+                    UserIdentificationAssociationType.toString(type), request);
+            types.put(type, true);
+        }
+
+        checkUserAssociationSupported();
+        request.requestId = getNextRequestId();
+        VehiclePropValue propRequest = UserHalHelper.toVehiclePropValue(request);
+
+        synchronized (mLock) {
+            if (hasPendingRequestLocked(UserIdentificationResponse.class, callback)) return;
+            addPendingRequestLocked(request.requestId, UserIdentificationResponse.class, request,
+                    callback);
+        }
+
+        EventLog.writeEvent(EventLogTags.CAR_USER_HAL_SET_USER_AUTH_REQ,
+                propRequest.value.int32Values.toArray());
+        // TODO(b/153900032): move this logic to a common helper
+        int[] associationTypes = new int[request.numberAssociations];
+        int[] associationValues = new int[request.numberAssociations];
+        for (int i = 0; i < request.numberAssociations; i++) {
+            UserIdentificationSetAssociation association = request.associations.get(i);
+            associationTypes[i] = association.type;
+            associationValues[i] = association.value;
+        }
+        CarStatsLog.write(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED,
+                request.requestId,
+                CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED__REQUEST_TYPE__SET,
+                request.userInfo.userId, request.userInfo.flags, request.numberAssociations,
+                Arrays.toString(associationTypes), Arrays.toString(associationValues));
+        sendHalRequest(request.requestId, timeoutMs, propRequest, callback);
+    }
+
+    private void handleOnUserIdentificationAssociation(@NonNull VehiclePropValue value) {
+        logEventWithErrorMessage(EventLogTags.CAR_USER_HAL_SET_USER_AUTH_RESP, value);
+        if (DBG) Log.d(TAG, "handleOnUserIdentificationAssociation(): " + value);
+
+        int requestId = value.value.int32Values.get(0);
+        HalCallback<UserIdentificationResponse> callback = handleGetPendingCallback(requestId,
+                UserIdentificationResponse.class);
+        if (callback == null) {
+            Log.w(TAG, "no callback for requestId " + requestId + ": " + value);
+            return;
+        }
+        PendingRequest<?, ?> pendingRequest = handleRemovePendingRequest(requestId);
+        UserIdentificationResponse response;
+        try {
+            response = UserHalHelper.toUserIdentificationResponse(value);
+        } catch (RuntimeException e) {
+            Log.w(TAG, "error parsing UserIdentificationResponse (" + value + ")", e);
+            callback.onResponse(HalCallback.STATUS_WRONG_HAL_RESPONSE, null);
+            CarStatsLog.write(CarStatsLog.CAR_USER_HAL_SET_USER_ASSOCIATION_RESPONSE_REPORTED,
+                    getHalCallbackStatusForStatsd(HalCallback.STATUS_WRONG_HAL_RESPONSE), requestId,
+                    /* number_associations= */ 0, /* user_identification_association_types= */ "",
+                    /* user_identification_association_values= */ "");
+            return;
+        }
+
+        // Validate the response according to the request
+        UserIdentificationSetRequest request = PendingRequest.getRequest(pendingRequest,
+                UserIdentificationSetRequest.class, requestId);
+
+        if (request == null) {
+            // already logged on PendingRequest.getRequest
+            callback.onResponse(HalCallback.STATUS_WRONG_HAL_RESPONSE, null);
+            logSetUserAssociationResponse(requestId, response,
+                    HalCallback.STATUS_WRONG_HAL_RESPONSE);
+            return;
+        }
+
+        if (response.numberAssociation != request.numberAssociations) {
+            Log.w(TAG, "Wrong number of association types on HAL response (expected "
+                    + request.numberAssociations + ") for request " + request
+                    + ": " + response);
+            callback.onResponse(HalCallback.STATUS_WRONG_HAL_RESPONSE, null);
+            logSetUserAssociationResponse(requestId, response,
+                    HalCallback.STATUS_WRONG_HAL_RESPONSE);
+            return;
+        }
+
+        for (int i = 0; i < request.numberAssociations; i++) {
+            int expectedType = request.associations.get(i).type;
+            int actualType = response.associations.get(i).type;
+            if (actualType != expectedType) {
+                Log.w(TAG, "Wrong type on index " + i + " of HAL response (" + response + ") for "
+                        + "request " + value + " : expected "
+                        + UserIdentificationAssociationType.toString(expectedType)
+                        + ", got " + UserIdentificationAssociationType.toString(actualType));
+                callback.onResponse(HalCallback.STATUS_WRONG_HAL_RESPONSE, null);
+                logSetUserAssociationResponse(requestId, response,
+                        HalCallback.STATUS_WRONG_HAL_RESPONSE);
+                return;
+            }
+        }
+
+        if (DBG) Log.d(TAG, "replying to request " + requestId + " with " + response);
+        callback.onResponse(HalCallback.STATUS_OK, response);
+        logSetUserAssociationResponse(requestId, response, HalCallback.STATUS_OK);
+    }
+
+    private void logSetUserAssociationResponse(int requestId, UserIdentificationResponse response,
+            int halCallbackStatus) {
+        // TODO(b/153900032): move this logic to a common helper
+        int[] associationTypes = new int[response.numberAssociation];
+        int[] associationValues = new int[response.numberAssociation];
+        for (int i = 0; i < response.numberAssociation; i++) {
+            UserIdentificationAssociation association = response.associations.get(i);
+            associationTypes[i] = association.type;
+            associationValues[i] = association.value;
+        }
+        CarStatsLog.write(CarStatsLog.CAR_USER_HAL_SET_USER_ASSOCIATION_RESPONSE_REPORTED,
+                getHalCallbackStatusForStatsd(halCallbackStatus), requestId,
+                response.numberAssociation, Arrays.toString(associationTypes),
+                Arrays.toString(associationValues));
+    }
+
+    private static void logEventWithErrorMessage(int eventTag, @NonNull VehiclePropValue value) {
+        if (TextUtils.isEmpty(value.value.stringValue)) {
+            EventLog.writeEvent(eventTag, value.value.int32Values.toArray());
+        } else {
+            // Must manually append the error message to the array of values
+            int size = value.value.int32Values.size();
+            Object[] list = new Object[size + 1];
+            value.value.int32Values.toArray(list);
+            list[list.length - 1] = value.value.stringValue;
+            EventLog.writeEvent(eventTag, list);
+        }
+    }
+
+    @VisibleForTesting
+    int getNextRequestId() {
+        synchronized (mLock) {
+            return mNextRequestId++;
+        }
+    }
+
+    @GuardedBy("mLock")
+    private <REQ, RESP> void addPendingRequestLocked(int requestId,
+            @NonNull Class<RESP> responseClass, @NonNull REQ request,
+            @NonNull HalCallback<RESP> callback) {
+        PendingRequest<?, RESP> pendingRequest = new PendingRequest<>(responseClass, request,
+                callback);
+        if (DBG) {
+            Log.d(TAG, "adding pending request (" + pendingRequest + ") for requestId "
+                    + requestId);
+        }
+        mPendingRequests.put(requestId, pendingRequest);
+    }
+
+    @GuardedBy("mLock")
+    private <RESP> void addPendingRequestLocked(int requestId, @NonNull Class<RESP> responseClass,
+            @NonNull HalCallback<RESP> callback) {
+        addPendingRequestLocked(requestId, responseClass, /* request= */ null,
+                callback);
+    }
+
+    /**
+     * Checks if there is a pending request of type {@code requestClass}, calling {@code callback}
+     * with {@link HalCallback#STATUS_CONCURRENT_OPERATION} when there is.
+     */
+    @GuardedBy("mLock")
+    private boolean hasPendingRequestLocked(@NonNull Class<?> responseClass,
+            @NonNull HalCallback<?> callback) {
+        for (int i = 0; i < mPendingRequests.size(); i++) {
+            PendingRequest<?, ?> pendingRequest = mPendingRequests.valueAt(i);
+            if (pendingRequest.responseClass == responseClass) {
+                Log.w(TAG, "Already have pending request of type " + responseClass);
+                callback.onResponse(HalCallback.STATUS_CONCURRENT_OPERATION, null);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Removes the pending request and its timeout callback.
+     */
+    @Nullable
+    private PendingRequest<?, ?> handleRemovePendingRequest(int requestId) {
+        if (DBG) Log.d(TAG, "Removing pending request #" + requestId);
+        mHandler.removeMessages(requestId);
+        PendingRequest<?, ?> pendingRequest;
+        synchronized (mLock) {
+            pendingRequest = mPendingRequests.get(requestId);
+            mPendingRequests.remove(requestId);
+        }
+        return pendingRequest;
+    }
+
+    private void handleCheckIfRequestTimedOut(int requestId) {
+        PendingRequest<?, ?> pendingRequest = getPendingRequest(requestId);
+        if (pendingRequest == null) return;
+
+        Log.w(TAG, "Request #" + requestId + " timed out");
+        handleRemovePendingRequest(requestId);
+        pendingRequest.callback.onResponse(HalCallback.STATUS_HAL_RESPONSE_TIMEOUT, null);
+    }
+
+    @Nullable
+    private PendingRequest<?, ?> getPendingRequest(int requestId) {
+        synchronized (mLock) {
+            return mPendingRequests.get(requestId);
+        }
+    }
+
+    private void handleOnInitialUserInfoResponse(VehiclePropValue value) {
+        int requestId = value.value.int32Values.get(0);
+        HalCallback<InitialUserInfoResponse> callback = handleGetPendingCallback(requestId,
+                InitialUserInfoResponse.class);
+        if (callback == null) {
+            EventLog.writeEvent(EventLogTags.CAR_USER_HAL_INITIAL_USER_INFO_RESP, requestId,
+                    HalCallback.STATUS_INVALID);
+            CarStatsLog.write(CarStatsLog.CAR_USER_HAL_INITIAL_USER_INFO_RESPONSE_REPORTED,
+                    requestId, getHalCallbackStatusForStatsd(HalCallback.STATUS_INVALID),
+                    getInitialUserInfoResponseActionForStatsd(
+                            InitialUserInfoResponseAction.DEFAULT), /* user id= */ -1,
+                    /* flag= */ -1, /* user locales= */ "");
+
+            Log.w(TAG, "no callback for requestId " + requestId + ": " + value);
+            return;
+        }
+        handleRemovePendingRequest(requestId);
+
+        InitialUserInfoResponse response;
+        try {
+            response = UserHalHelper.toInitialUserInfoResponse(value);
+        } catch (RuntimeException e) {
+            Log.e(TAG, "invalid response (" + value + ") from HAL", e);
+            EventLog.writeEvent(EventLogTags.CAR_USER_HAL_INITIAL_USER_INFO_RESP, requestId,
+                    HalCallback.STATUS_WRONG_HAL_RESPONSE);
+            CarStatsLog.write(CarStatsLog.CAR_USER_HAL_INITIAL_USER_INFO_RESPONSE_REPORTED,
+                    requestId, getHalCallbackStatusForStatsd(HalCallback.STATUS_WRONG_HAL_RESPONSE),
+                    getInitialUserInfoResponseActionForStatsd(
+                            InitialUserInfoResponseAction.DEFAULT), /* user id= */ -1,
+                    /* flag= */ -1, /* user locales= */ "");
+
+            callback.onResponse(HalCallback.STATUS_WRONG_HAL_RESPONSE, null);
+            return;
+        }
+
+        EventLog.writeEvent(EventLogTags.CAR_USER_HAL_INITIAL_USER_INFO_RESP, requestId,
+                HalCallback.STATUS_OK, response.action,
+                response.userToSwitchOrCreate.userId, response.userToSwitchOrCreate.flags,
+                response.userNameToCreate, response.userLocales);
+        CarStatsLog.write(CarStatsLog.CAR_USER_HAL_INITIAL_USER_INFO_RESPONSE_REPORTED,
+                requestId, getHalCallbackStatusForStatsd(HalCallback.STATUS_OK),
+                getInitialUserInfoResponseActionForStatsd(response.action),
+                response.userToSwitchOrCreate.userId, response.userToSwitchOrCreate.flags,
+                response.userLocales);
+
+        if (DBG) Log.d(TAG, "replying to request " + requestId + " with " + response);
+        callback.onResponse(HalCallback.STATUS_OK, response);
+    }
+
+    private static int getInitialUserInfoResponseActionForStatsd(int action) {
+        switch (action) {
+            case InitialUserInfoResponseAction.CREATE:
+                return CarStatsLog
+                        .CAR_USER_HAL_INITIAL_USER_INFO_RESPONSE_REPORTED__RESPONSE_ACTION__CREATE;
+            case InitialUserInfoResponseAction.SWITCH:
+                return CarStatsLog
+                        .CAR_USER_HAL_INITIAL_USER_INFO_RESPONSE_REPORTED__RESPONSE_ACTION__SWITCH;
+            default:
+                return CarStatsLog
+                        .CAR_USER_HAL_INITIAL_USER_INFO_RESPONSE_REPORTED__RESPONSE_ACTION__DEFAULT;
+        }
+    }
+
+    private void handleOnSwitchUserResponse(VehiclePropValue value) {
+        int requestId = value.value.int32Values.get(0);
+        int messageType = value.value.int32Values.get(1);
+
+        if (messageType == SwitchUserMessageType.VEHICLE_RESPONSE) {
+            handleOnSwitchUserVehicleResponse(value);
+            return;
+        }
+
+        if (messageType == SwitchUserMessageType.VEHICLE_REQUEST) {
+            handleOnSwitchUserVehicleRequest(value);
+            return;
+        }
+
+        Log.e(TAG, "handleOnSwitchUserResponse invalid message type (" + messageType
+                + ") from HAL: " + value);
+
+        // check if a callback exists for the request ID
+        HalCallback<SwitchUserResponse> callback =
+                handleGetPendingCallback(requestId, SwitchUserResponse.class);
+        if (callback != null) {
+            handleRemovePendingRequest(requestId);
+            EventLog.writeEvent(EventLogTags.CAR_USER_HAL_SWITCH_USER_RESP, requestId,
+                    HalCallback.STATUS_WRONG_HAL_RESPONSE);
+            callback.onResponse(HalCallback.STATUS_WRONG_HAL_RESPONSE, null);
+            return;
+        }
+    }
+
+    private void handleOnSwitchUserVehicleRequest(VehiclePropValue value) {
+        int requestId = value.value.int32Values.get(0);
+        // Index 1 is message type, which is not required in this call.
+        int targetUserId = value.value.int32Values.get(2);
+        EventLog.writeEvent(EventLogTags.CAR_USER_HAL_OEM_SWITCH_USER_REQ, requestId, targetUserId);
+        CarStatsLog.write(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED, requestId,
+                CarStatsLog
+                    .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__SWITCH_REQUEST_OEM,
+                    /* current user id= */ -1, /* current user flag= */ -1, targetUserId,
+                    /* target user flag= */ -1, /* timeout_ms= */ -1);
+
+        // HAL vehicle request should have negative request ID
+        if (requestId >= 0) {
+            Log.e(TAG, "handleVehicleRequest invalid requestId (" + requestId + ") from HAL: "
+                    + value);
+            return;
+        }
+
+        CarUserService userService = CarLocalServices.getService(CarUserService.class);
+        userService.switchAndroidUserFromHal(requestId, targetUserId);
+    }
+
+    private void handleOnSwitchUserVehicleResponse(VehiclePropValue value) {
+        int requestId = value.value.int32Values.get(0);
+        HalCallback<SwitchUserResponse> callback =
+                handleGetPendingCallback(requestId, SwitchUserResponse.class);
+        if (callback == null) {
+            EventLog.writeEvent(EventLogTags.CAR_USER_HAL_SWITCH_USER_RESP, requestId,
+                    HalCallback.STATUS_INVALID);
+            Log.w(TAG, "no callback for requestId " + requestId + ": " + value);
+            logHalSwitchUserResponse(requestId, HalCallback.STATUS_WRONG_HAL_RESPONSE);
+            return;
+        }
+        handleRemovePendingRequest(requestId);
+        SwitchUserResponse response = new SwitchUserResponse();
+        response.requestId = requestId;
+        response.messageType = value.value.int32Values.get(1);
+        response.status = value.value.int32Values.get(2);
+        response.errorMessage = value.value.stringValue;
+        if (response.status == SwitchUserStatus.SUCCESS
+                || response.status == SwitchUserStatus.FAILURE) {
+            if (DBG) {
+                Log.d(TAG, "replying to request " + requestId + " with " + response);
+            }
+            EventLog.writeEvent(EventLogTags.CAR_USER_HAL_SWITCH_USER_RESP, requestId,
+                    HalCallback.STATUS_OK, response.status, response.errorMessage);
+            callback.onResponse(HalCallback.STATUS_OK, response);
+            logHalSwitchUserResponse(requestId, HalCallback.STATUS_OK, response.status);
+        } else {
+            EventLog.writeEvent(EventLogTags.CAR_USER_HAL_SWITCH_USER_RESP, requestId,
+                    HalCallback.STATUS_WRONG_HAL_RESPONSE, response.status, response.errorMessage);
+            Log.e(TAG, "invalid status (" + response.status + ") from HAL: " + value);
+            callback.onResponse(HalCallback.STATUS_WRONG_HAL_RESPONSE, null);
+            logHalSwitchUserResponse(requestId, HalCallback.STATUS_WRONG_HAL_RESPONSE,
+                    response.status);
+        }
+    }
+
+    private void handleOnCreateUserResponse(VehiclePropValue value) {
+        int requestId = value.value.int32Values.get(0);
+        HalCallback<CreateUserResponse> callback =
+                handleGetPendingCallback(requestId, CreateUserResponse.class);
+        if (callback == null) {
+            EventLog.writeEvent(EventLogTags.CAR_USER_HAL_CREATE_USER_RESP, requestId,
+                    HalCallback.STATUS_INVALID);
+            Log.w(TAG, "no callback for requestId " + requestId + ": " + value);
+            return;
+        }
+        handleRemovePendingRequest(requestId);
+        CreateUserResponse response = new CreateUserResponse();
+        response.requestId = requestId;
+        response.status = value.value.int32Values.get(1);
+        response.errorMessage = value.value.stringValue;
+        if (response.status == CreateUserStatus.SUCCESS
+                || response.status == CreateUserStatus.FAILURE) {
+            if (DBG) {
+                Log.d(TAG, "replying to request " + requestId + " with " + response);
+            }
+            EventLog.writeEvent(EventLogTags.CAR_USER_HAL_CREATE_USER_RESP, requestId,
+                    HalCallback.STATUS_OK, response.status, response.errorMessage);
+            callback.onResponse(HalCallback.STATUS_OK, response);
+            logHalCreateUserResponse(requestId, HalCallback.STATUS_OK, response.status);
+        } else {
+            EventLog.writeEvent(EventLogTags.CAR_USER_HAL_CREATE_USER_RESP, requestId,
+                    HalCallback.STATUS_WRONG_HAL_RESPONSE, response.status, response.errorMessage);
+            Log.e(TAG, "invalid status (" + response.status + ") from HAL: " + value);
+            callback.onResponse(HalCallback.STATUS_WRONG_HAL_RESPONSE, null);
+            logHalCreateUserResponse(requestId, HalCallback.STATUS_WRONG_HAL_RESPONSE);
+        }
+    }
+
+    private void logHalSwitchUserResponse(int requestId, int halCallbackStatus) {
+        //CHECKSTYLE:OFF IndentationCheck
+        CarStatsLog.write(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED, requestId,
+                getHalCallbackStatusForStatsd(halCallbackStatus),
+               CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__REQUEST_STATUS__UNSPECIFIED);
+        //CHECKSTYLE:ON IndentationCheck
+    }
+
+    private void logHalSwitchUserResponse(int requestId, int halCallbackStatus,
+            int userSwitchstatus) {
+        int userSwitchstatusForStatsd = userSwitchstatus == SwitchUserStatus.SUCCESS
+                ? CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__REQUEST_STATUS__SUCCESS
+                : CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__REQUEST_STATUS__FAILURE;
+        CarStatsLog.write(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED, requestId,
+                getHalCallbackStatusForStatsd(halCallbackStatus), userSwitchstatusForStatsd);
+    }
+
+    private void logHalCreateUserResponse(int requestId, int halCallbackStatus) {
+        //CHECKSTYLE:OFF IndentationCheck
+        CarStatsLog.write(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED, requestId,
+                getHalCallbackStatusForStatsd(halCallbackStatus),
+               CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__REQUEST_STATUS__UNSPECIFIED);
+        //CHECKSTYLE:ON IndentationCheck
+    }
+
+    private void logHalCreateUserResponse(int requestId, int halCallbackStatus,
+            int userCreatestatus) {
+        int userCreatestatusForStatsd = userCreatestatus == CreateUserStatus.SUCCESS
+                ? CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__REQUEST_STATUS__SUCCESS
+                : CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__REQUEST_STATUS__FAILURE;
+        CarStatsLog.write(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED, requestId,
+                getHalCallbackStatusForStatsd(halCallbackStatus), userCreatestatusForStatsd);
+    }
+
+    private int getHalCallbackStatusForStatsd(int halCallbackStatus) {
+        // CHECKSTYLE:OFF IndentationCheck
+        switch (halCallbackStatus) {
+            case HalCallback.STATUS_OK:
+                return CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__OK;
+            case HalCallback.STATUS_HAL_SET_TIMEOUT:
+                return CarStatsLog
+                      .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__HAL_SET_TIMEOUT;
+            case HalCallback.STATUS_HAL_RESPONSE_TIMEOUT:
+                return CarStatsLog
+                 .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__HAL_RESPONSE_TIMEOUT;
+            case HalCallback.STATUS_WRONG_HAL_RESPONSE:
+                return CarStatsLog
+                   .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__WRONG_HAL_RESPONSE;
+            case HalCallback.STATUS_CONCURRENT_OPERATION:
+                return CarStatsLog
+                 .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__CONCURRENT_OPERATION;
+            default:
+                return CarStatsLog
+                        .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__INVALID;
+        }
+        // CHECKSTYLE:ON IndentationCheck
+    }
+
+    private <T> HalCallback<T> handleGetPendingCallback(int requestId, Class<T> clazz) {
+        PendingRequest<?, ?> pendingRequest = getPendingRequest(requestId);
+        if (pendingRequest == null) return null;
+
+        if (pendingRequest.responseClass != clazz) {
+            Log.e(TAG, "Invalid callback class for request " + requestId + ": expected" + clazz
+                    + ", but got is " + pendingRequest.responseClass);
+            // TODO(b/150413515): add unit test for this scenario once it supports other properties
+            return null;
+        }
+        @SuppressWarnings("unchecked")
+        HalCallback<T> callback = (HalCallback<T>) pendingRequest.callback;
+        return callback;
+    }
+
+    @Override
+    public void dump(PrintWriter writer) {
+        String indent = "  ";
+        writer.printf("*User HAL*\n");
+
+        writer.printf("Relevant CarProperties\n");
+        dumpSystemProperty(writer, indent, "user_hal_enabled", CarProperties.user_hal_enabled());
+        dumpSystemProperty(writer, indent, "user_hal_timeout", CarProperties.user_hal_timeout());
+
+        synchronized (mLock) {
+            if (!isSupported()) {
+                writer.println(UNSUPPORTED_MSG);
+                return;
+            }
+            int numberProperties = mProperties.size();
+            writer.printf("%d supported properties\n", numberProperties);
+            for (int i = 0; i < numberProperties; i++) {
+                writer.printf("%s%s\n", indent, mProperties.valueAt(i));
+            }
+            writer.printf("next request id: %d\n", mNextRequestId);
+
+            int numberPendingCallbacks = mPendingRequests.size();
+            if (numberPendingCallbacks == 0) {
+                writer.println("no pending callbacks");
+            } else {
+                writer.printf("%d pending callbacks: %s\n", numberPendingCallbacks);
+                for (int i = 0; i < numberPendingCallbacks; i++) {
+                    writer.print(indent);
+                    mPendingRequests.valueAt(i).dump(writer);
+                    writer.println();
+                }
+            }
+        }
+    }
+
+    private static void dumpSystemProperty(@NonNull PrintWriter writer, @NonNull String indent,
+            @NonNull String name, Optional<?> prop) {
+        String value = prop.isPresent() ? prop.get().toString() : "<NOT SET>";
+        writer.printf("%s%s=%s\n", indent, name, value);
+    }
+
+    private static final class PendingRequest<REQ, RESP> {
+        @NonNull
+        public final Class<RESP> responseClass;
+
+        @Nullable
+        public final REQ request;
+
+        @NonNull
+        public final HalCallback<RESP> callback;
+
+        PendingRequest(@NonNull Class<RESP> responseClass, @Nullable REQ request,
+                @NonNull HalCallback<RESP> callback) {
+            this.responseClass = responseClass;
+            this.request = request;
+            this.callback = callback;
+        }
+
+        /**
+         * Gets the safely cast request for a given pending request.
+         */
+        @Nullable
+        private static <T> T getRequest(@Nullable PendingRequest<?, ?> pendingRequest,
+                @NonNull Class<T> clazz, int requestId) {
+            if (pendingRequest == null) {
+                Log.e(TAG, "No pending request for id " + requestId);
+                return null;
+
+            }
+            Object request = pendingRequest.request;
+            if (!clazz.isInstance(request)) {
+                Log.e(TAG, "Wrong pending request for id " + requestId + ": " + pendingRequest);
+                return null;
+            }
+            return clazz.cast(request);
+        }
+
+        public void dump(@NonNull PrintWriter pw) {
+            pw.printf("Class: %s Callback: %s", responseClass.getSimpleName(),
+                    FunctionalUtils.getLambdaName(callback));
+            if (request != null) {
+                pw.printf(" Request: %s", request);
+            }
+        }
+
+        @Override
+        public String toString() {
+            StringWriter sw = new StringWriter();
+            PrintWriter pw = new PrintWriter(sw);
+            pw.print("[PendingRequest: ");
+            dump(pw);
+            pw.print("]");
+            pw.flush();
+            return sw.toString();
+        }
+    }
+}
diff --git a/service/src/com/android/car/hal/VehicleHal.java b/service/src/com/android/car/hal/VehicleHal.java
index d85a357..8706c00 100644
--- a/service/src/com/android/car/hal/VehicleHal.java
+++ b/service/src/com/android/car/hal/VehicleHal.java
@@ -23,6 +23,8 @@
 import static java.lang.Integer.toHexString;
 
 import android.annotation.CheckResult;
+import android.annotation.Nullable;
+import android.car.hardware.property.CarPropertyManager;
 import android.content.Context;
 import android.hardware.automotive.vehicle.V2_0.IVehicle;
 import android.hardware.automotive.vehicle.V2_0.IVehicleCallback;
@@ -37,12 +39,15 @@
 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType;
 import android.os.HandlerThread;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.os.SystemClock;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.SparseArray;
 
 import com.android.car.CarLog;
+import com.android.car.CarServiceUtils;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
 import com.google.android.collect.Lists;
@@ -53,9 +58,10 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 /**
  * Abstraction for vehicle HAL. This class handles interface with native HAL and do basic parsing
@@ -74,36 +80,46 @@
     private final PropertyHalService mPropertyHal;
     private final InputHalService mInputHal;
     private final VmsHalService mVmsHal;
+    private final UserHalService mUserHal;
     private DiagnosticHalService mDiagnosticHal = null;
 
+    private final Object mLock = new Object();
+
     /** Might be re-assigned if Vehicle HAL is reconnected. */
     private volatile HalClient mHalClient;
 
     /** Stores handler for each HAL property. Property events are sent to handler. */
+    @GuardedBy("mLock")
     private final SparseArray<HalServiceBase> mPropertyHandlers = new SparseArray<>();
     /** This is for iterating all HalServices with fixed order. */
+    @GuardedBy("mLock")
     private final ArrayList<HalServiceBase> mAllServices = new ArrayList<>();
+    @GuardedBy("mLock")
     private final HashMap<Integer, SubscribeOptions> mSubscribedProperties = new HashMap<>();
+    @GuardedBy("mLock")
     private final HashMap<Integer, VehiclePropConfig> mAllProperties = new HashMap<>();
+
+    @GuardedBy("mLock")
     private final HashMap<Integer, VehiclePropertyEventInfo> mEventLog = new HashMap<>();
 
     // Used by injectVHALEvent for testing purposes.  Delimiter for an array of data
     private static final String DATA_DELIMITER = ",";
 
     public VehicleHal(Context context, IVehicle vehicle) {
-        mHandlerThread = new HandlerThread("VEHICLE-HAL");
-        mHandlerThread.start();
+        mHandlerThread = CarServiceUtils.getHandlerThread(VehicleHal.class.getSimpleName());
         // passing this should be safe as long as it is just kept and not used in constructor
         mPowerHal = new PowerHalService(this);
         mPropertyHal = new PropertyHalService(this);
         mInputHal = new InputHalService(this);
         mVmsHal = new VmsHalService(context, this);
         mDiagnosticHal = new DiagnosticHalService(this);
+        mUserHal = new UserHalService(this);
         mAllServices.addAll(Arrays.asList(mPowerHal,
                 mInputHal,
-                mPropertyHal,
                 mDiagnosticHal,
-                mVmsHal));
+                mVmsHal,
+                mUserHal,
+                mPropertyHal)); // mPropertyHal should be the last.
 
         mHalClient = new HalClient(vehicle, mHandlerThread.getLooper(), this /*IVehicleCallback*/);
     }
@@ -120,10 +136,11 @@
         mVmsHal = null;
         mHalClient = halClient;
         mDiagnosticHal = diagnosticHal;
+        mUserHal = null;
     }
 
     public void vehicleHalReconnected(IVehicle vehicle) {
-        synchronized (this) {
+        synchronized (mLock) {
             mHalClient = new HalClient(vehicle, mHandlerThread.getLooper(),
                     this /*IVehicleCallback*/);
 
@@ -138,35 +155,72 @@
         }
     }
 
-    public void init() {
-        Set<VehiclePropConfig> properties;
+    private void fetchAllPropConfigs() {
+        synchronized (mLock) {
+            if (!mAllProperties.isEmpty()) { // already set
+                Log.i(CarLog.TAG_HAL, "fetchAllPropConfigs already fetched");
+                return;
+            }
+        }
+        ArrayList<VehiclePropConfig> configs;
         try {
-            properties = new HashSet<>(mHalClient.getAllPropConfigs());
+            configs = mHalClient.getAllPropConfigs();
+            if (configs == null || configs.size() == 0) {
+                Log.e(CarLog.TAG_HAL, "getAllPropConfigs returned empty configs");
+                return;
+            }
         } catch (RemoteException e) {
             throw new RuntimeException("Unable to retrieve vehicle property configuration", e);
         }
 
-        synchronized (this) {
+        synchronized (mLock) {
             // Create map of all properties
-            for (VehiclePropConfig p : properties) {
+            for (VehiclePropConfig p : configs) {
+                if (DBG) {
+                    Log.i(CarLog.TAG_HAL, "Add config for prop:" + Integer.toHexString(p.prop)
+                            + " config:" + p);
+                }
                 mAllProperties.put(p.prop, p);
             }
         }
+    }
 
-        for (HalServiceBase service: mAllServices) {
-            Collection<VehiclePropConfig> taken = service.takeSupportedProperties(properties);
-            if (taken == null) {
-                continue;
-            }
-            if (DBG) {
-                Log.i(CarLog.TAG_HAL, "HalService " + service + " take properties " + taken.size());
-            }
-            synchronized (this) {
-                for (VehiclePropConfig p: taken) {
-                    mPropertyHandlers.append(p.prop, service);
+    /**
+     * Inits the vhal configurations.
+     *
+     * <p><Note that {@link #getIfAvailableOrFailForEarlyStage(int, int)}
+     * can be called before {@code init()}.
+     */
+    public void init() {
+        fetchAllPropConfigs();
+
+        // PropertyHalService will take most properties, so make it big enough.
+        ArrayList<VehiclePropConfig> configsForService = new ArrayList<>(mAllServices.size());
+        for (int i = 0; i < mAllServices.size(); i++) {
+            HalServiceBase service = mAllServices.get(i);
+            int[] supportedProps =  service.getAllSupportedProperties();
+            configsForService.clear();
+            synchronized (mLock) {
+                if (supportedProps.length == 0) {
+                    for (Integer propId : mAllProperties.keySet()) {
+                        if (service.isSupportedProperty(propId)) {
+                            VehiclePropConfig config = mAllProperties.get(propId);
+                            mPropertyHandlers.append(propId, service);
+                            configsForService.add(config);
+                        }
+                    }
+                } else {
+                    for (int prop : supportedProps) {
+                        VehiclePropConfig config = mAllProperties.get(prop);
+                        if (config == null) {
+                            continue;
+                        }
+                        mPropertyHandlers.append(prop, service);
+                        configsForService.add(config);
+                    }
                 }
             }
-            properties.removeAll(taken);
+            service.takeProperties(configsForService);
             service.init();
         }
     }
@@ -176,7 +230,7 @@
         for (int i = mAllServices.size() - 1; i >= 0; i--) {
             mAllServices.get(i).release();
         }
-        synchronized (this) {
+        synchronized (mLock) {
             for (int p : mSubscribedProperties.keySet()) {
                 try {
                     mHalClient.unsubscribe(p);
@@ -205,6 +259,10 @@
         return mInputHal;
     }
 
+    public UserHalService getUserHal() {
+        return mUserHal;
+    }
+
     public VmsHalService getVmsHal() { return mVmsHal; }
 
     private void assertServiceOwnerLocked(HalServiceBase service, int property) {
@@ -250,7 +308,7 @@
                     + ", property: 0x" + toHexString(property));
         }
         VehiclePropConfig config;
-        synchronized (this) {
+        synchronized (mLock) {
             config = mAllProperties.get(property);
         }
 
@@ -262,7 +320,7 @@
             opts.propId = property;
             opts.sampleRate = samplingRateHz;
             opts.flags = flags;
-            synchronized (this) {
+            synchronized (mLock) {
                 assertServiceOwnerLocked(service, property);
                 mSubscribedProperties.put(property, opts);
             }
@@ -282,14 +340,14 @@
                     + ", property: 0x" + toHexString(property));
         }
         VehiclePropConfig config;
-        synchronized (this) {
+        synchronized (mLock) {
             config = mAllProperties.get(property);
         }
 
         if (config == null) {
             Log.e(CarLog.TAG_HAL, "unsubscribeProperty: property " + property + " does not exist");
         } else if (isPropertySubscribable(config)) {
-            synchronized (this) {
+            synchronized (mLock) {
                 assertServiceOwnerLocked(service, property);
                 mSubscribedProperties.remove(property);
             }
@@ -305,18 +363,53 @@
     }
 
     public boolean isPropertySupported(int propertyId) {
-        return mAllProperties.containsKey(propertyId);
+        synchronized (mLock) {
+            return mAllProperties.containsKey(propertyId);
+        }
     }
 
-    public Collection<VehiclePropConfig> getAllPropConfigs() {
-        return mAllProperties.values();
+    /**
+     * Gets given property with retries.
+     *
+     * <p>If getting the property fails after all retries, it will throw
+     * {@code IllegalStateException}. If the property does not exist, it will simply return
+     * {@code null}.
+     */
+    public @Nullable VehiclePropValue getIfAvailableOrFail(int propertyId, int numberOfRetries) {
+        if (!isPropertySupported(propertyId)) {
+            return null;
+        }
+        VehiclePropValue value;
+        for (int i = 0; i < numberOfRetries; i++) {
+            try {
+                return get(propertyId);
+            } catch (ServiceSpecificException e) {
+                Log.e(CarLog.TAG_HAL, "Cannot get property:" + propertyId, e);
+            }
+        }
+        throw new IllegalStateException("Cannot get property:" + propertyId
+                + " after " + numberOfRetries + " retries");
     }
 
-    public VehiclePropValue get(int propertyId) throws PropertyTimeoutException {
+    /**
+     * This works similar to {@link #getIfAvailableOrFail(int, int)} except that this can be called
+     * before {@code init()} is called.
+     *
+     * <p>This call will check if requested vhal property is supported by querying directly to vhal
+     * and can have worse performance. Use this only for accessing vhal properties before
+     * {@code ICarImpl.init()} phase.
+     */
+    public @Nullable VehiclePropValue getIfAvailableOrFailForEarlyStage(int propertyId,
+            int numberOfRetries) {
+        fetchAllPropConfigs();
+        return getIfAvailableOrFail(propertyId, numberOfRetries);
+    }
+
+    public VehiclePropValue get(int propertyId) {
         return get(propertyId, NO_AREA);
     }
 
-    public VehiclePropValue get(int propertyId, int areaId) throws PropertyTimeoutException {
+    public VehiclePropValue get(int propertyId, int areaId) {
         if (DBG) {
             Log.i(CarLog.TAG_HAL, "get, property: 0x" + toHexString(propertyId)
                     + ", areaId: 0x" + toHexString(areaId));
@@ -327,17 +420,16 @@
         return mHalClient.getValue(propValue);
     }
 
-    public <T> T get(Class clazz, int propertyId) throws PropertyTimeoutException {
+    public <T> T get(Class clazz, int propertyId) {
         return get(clazz, createPropValue(propertyId, NO_AREA));
     }
 
-    public <T> T get(Class clazz, int propertyId, int areaId) throws PropertyTimeoutException {
+    public <T> T get(Class clazz, int propertyId, int areaId) {
         return get(clazz, createPropValue(propertyId, areaId));
     }
 
     @SuppressWarnings("unchecked")
-    public <T> T get(Class clazz, VehiclePropValue requestedPropValue)
-            throws PropertyTimeoutException {
+    public <T> T get(Class clazz, VehiclePropValue requestedPropValue) {
         VehiclePropValue propValue;
         propValue = mHalClient.getValue(requestedPropValue);
 
@@ -366,8 +458,7 @@
         }
     }
 
-    public VehiclePropValue get(VehiclePropValue requestedPropValue)
-            throws PropertyTimeoutException {
+    public VehiclePropValue get(VehiclePropValue requestedPropValue) {
         return mHalClient.getValue(requestedPropValue);
     }
 
@@ -388,7 +479,7 @@
         }
     }
 
-    protected void set(VehiclePropValue propValue) throws PropertyTimeoutException {
+    protected void set(VehiclePropValue propValue) {
         mHalClient.setValue(propValue);
     }
 
@@ -420,7 +511,7 @@
 
     @Override
     public void onPropertyEvent(ArrayList<VehiclePropValue> propValues) {
-        synchronized (this) {
+        synchronized (mLock) {
             for (VehiclePropValue v : propValues) {
                 HalServiceBase service = mPropertyHandlers.get(v.prop);
                 if(service == null) {
@@ -440,7 +531,7 @@
             }
         }
         for (HalServiceBase s : mServicesToDispatch) {
-            s.handleHalEvents(s.getDispatchList());
+            s.onHalEvents(s.getDispatchList());
             s.getDispatchList().clear();
         }
         mServicesToDispatch.clear();
@@ -452,13 +543,14 @@
     }
 
     @Override
-    public void onPropertySetError(int errorCode, int propId, int areaId) {
+    public void onPropertySetError(@CarPropertyManager.CarSetPropertyErrorCode int errorCode,
+            int propId, int areaId) {
         Log.e(CarLog.TAG_HAL, String.format("onPropertySetError, errorCode: %d, prop: 0x%x, "
                 + "area: 0x%x", errorCode, propId, areaId));
         if (propId != VehicleProperty.INVALID) {
             HalServiceBase service = mPropertyHandlers.get(propId);
             if (service != null) {
-                service.handlePropertySetError(propId, areaId);
+                service.onPropertySetError(propId, areaId, errorCode);
             }
         }
     }
@@ -486,6 +578,31 @@
     }
 
     /**
+     * Dumps the list of HALs.
+     */
+    public void dumpListHals(PrintWriter writer) {
+        for (HalServiceBase service: mAllServices) {
+            writer.println(service.getClass().getName());
+        }
+    }
+
+    /**
+     * Dumps the given HALs.
+     */
+    public void dumpSpecificHals(PrintWriter writer, String... halNames) {
+        Map<String, HalServiceBase> byName = mAllServices.stream()
+                .collect(Collectors.toMap(s -> s.getClass().getSimpleName(), s -> s));
+        for (String halName : halNames) {
+            HalServiceBase service = byName.get(halName);
+            if (service == null) {
+                writer.printf("No HAL named %s. Valid options are: %s\n", halName, byName.keySet());
+                continue;
+            }
+            service.dump(writer);
+        }
+    }
+
+    /**
      * Dumps vehicle property values.
      * @param writer
      * @param propId property id, dump all properties' value if it is empty string.
@@ -500,6 +617,10 @@
             }
         } else if (areaId.equals("")) {
             VehiclePropConfig config = mAllProperties.get(Integer.parseInt(propId, 16));
+            if (config == null) {
+                writer.printf("Property 0x%s not supported by HAL\n", propId);
+                return;
+            }
             dumpPropertyValueByConfig(writer, config);
         } else {
             int id = Integer.parseInt(propId, 16);
@@ -545,7 +666,7 @@
      */
     public void dumpPropertyConfigs(PrintWriter writer, String propId) {
         List<VehiclePropConfig> configList;
-        synchronized (this) {
+        synchronized (mLock) {
             configList = new ArrayList<>(mAllProperties.values());
         }
 
@@ -569,20 +690,20 @@
     private static String dumpPropertyConfigsHelp(VehiclePropConfig config) {
         StringBuilder builder = new StringBuilder()
                 .append("Property:0x").append(toHexString(config.prop))
-                .append(",Property name:").append(VehicleProperty.toString(config.prop))
-                .append(",access:0x").append(toHexString(config.access))
-                .append(",changeMode:0x").append(toHexString(config.changeMode))
-                .append(",config:0x").append(Arrays.toString(config.configArray.toArray()))
-                .append(",fs min:").append(config.minSampleRate)
-                .append(",fs max:").append(config.maxSampleRate);
+                .append(", Property name:").append(VehicleProperty.toString(config.prop))
+                .append(", access:0x").append(toHexString(config.access))
+                .append(", changeMode:0x").append(toHexString(config.changeMode))
+                .append(", config:0x").append(Arrays.toString(config.configArray.toArray()))
+                .append(", fs min:").append(config.minSampleRate)
+                .append(", fs max:").append(config.maxSampleRate);
         for (VehicleAreaConfig area : config.areaConfigs) {
-            builder.append(",areaId :").append(toHexString(area.areaId))
-                    .append(",f min:").append(area.minFloatValue)
-                    .append(",f max:").append(area.maxFloatValue)
-                    .append(",i min:").append(area.minInt32Value)
-                    .append(",i max:").append(area.maxInt32Value)
-                    .append(",i64 min:").append(area.minInt64Value)
-                    .append(",i64 max:").append(area.maxInt64Value);
+            builder.append("\n\tareaId:0x").append(toHexString(area.areaId))
+                    .append(", f min:").append(area.minFloatValue)
+                    .append(", f max:").append(area.maxFloatValue)
+                    .append(", i min:").append(area.minInt32Value)
+                    .append(", i max:").append(area.maxInt32Value)
+                    .append(", i64 min:").append(area.minInt64Value)
+                    .append(", i64 max:").append(area.maxInt64Value);
         }
         return builder.toString();
     }
@@ -592,14 +713,16 @@
      * @param property the Vehicle property Id as defined in the HAL
      * @param zone     Zone that this event services
      * @param value    Data value of the event
+     * @param delayTime Add a certain duration to event timestamp
      */
-    public void injectVhalEvent(String property, String zone, String value)
+    public void injectVhalEvent(String property, String zone, String value, String delayTime)
             throws NumberFormatException {
         if (value == null || zone == null || property == null) {
             return;
         }
         int propId = Integer.decode(property);
         int zoneId = Integer.decode(zone);
+        int duration = Integer.decode(delayTime);
         VehiclePropValue v = createPropValue(propId, zoneId);
         int propertyType = propId & VehiclePropertyType.MASK;
         // Values can be comma separated list
@@ -625,7 +748,7 @@
                 Log.e(CarLog.TAG_HAL, "Property type unsupported:" + propertyType);
                 return;
         }
-        v.timestamp = SystemClock.elapsedRealtimeNanos();
+        v.timestamp = SystemClock.elapsedRealtimeNanos() + TimeUnit.SECONDS.toNanos(duration);
         onPropertyEvent(Lists.newArrayList(v));
     }
 
@@ -672,28 +795,28 @@
             mPropValue.areaId = areaId;
         }
 
-        void to(boolean value) throws PropertyTimeoutException {
+        void to(boolean value) {
             to(value ? 1 : 0);
         }
 
-        void to(int value) throws PropertyTimeoutException {
+        void to(int value) {
             mPropValue.value.int32Values.add(value);
             submit();
         }
 
-        void to(int[] values) throws PropertyTimeoutException {
+        void to(int[] values) {
             for (int value : values) {
                 mPropValue.value.int32Values.add(value);
             }
             submit();
         }
 
-        void to(Collection<Integer> values) throws PropertyTimeoutException {
+        void to(Collection<Integer> values) {
             mPropValue.value.int32Values.addAll(values);
             submit();
         }
 
-        void submit() throws PropertyTimeoutException {
+        void submit() {
             HalClient client =  mClient.get();
             if (client != null) {
                 if (DBG) {
diff --git a/service/src/com/android/car/hal/VmsHalService.java b/service/src/com/android/car/hal/VmsHalService.java
index 99263d7..f1129f7 100644
--- a/service/src/com/android/car/hal/VmsHalService.java
+++ b/service/src/com/android/car/hal/VmsHalService.java
@@ -18,16 +18,13 @@
 import static com.android.car.CarServiceUtils.toByteArray;
 
 import android.car.VehicleAreaType;
-import android.car.vms.IVmsPublisherClient;
-import android.car.vms.IVmsPublisherService;
-import android.car.vms.IVmsSubscriberClient;
-import android.car.vms.IVmsSubscriberService;
 import android.car.vms.VmsAssociatedLayer;
 import android.car.vms.VmsAvailableLayers;
+import android.car.vms.VmsClient;
+import android.car.vms.VmsClientManager.VmsClientCallback;
 import android.car.vms.VmsLayer;
 import android.car.vms.VmsLayerDependency;
-import android.car.vms.VmsLayersOffering;
-import android.car.vms.VmsOperationRecorder;
+import android.car.vms.VmsSubscriptionHelper;
 import android.car.vms.VmsSubscriptionState;
 import android.content.Context;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
@@ -43,29 +40,30 @@
 import android.hardware.automotive.vehicle.V2_0.VmsStartSessionMessageIntegerValuesIndex;
 import android.os.Build;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Message;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.ArraySet;
 import android.util.Log;
 
+import androidx.annotation.GuardedBy;
 import androidx.annotation.VisibleForTesting;
 
-import com.android.car.vms.VmsClientManager;
+import com.android.car.CarLocalServices;
+import com.android.car.CarServiceUtils;
+import com.android.car.vms.VmsBrokerService;
 
 import java.io.FileDescriptor;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.function.BiFunction;
 import java.util.function.Supplier;
 
 /**
@@ -78,131 +76,72 @@
     private static final boolean DBG = false;
     private static final String TAG = "VmsHalService";
     private static final int HAL_PROPERTY_ID = VehicleProperty.VEHICLE_MAP_SERVICE;
+    private static final int[] SUPPORTED_PROPERTIES = new int[]{
+            HAL_PROPERTY_ID
+    };
     private static final int NUM_INTEGERS_IN_VMS_LAYER = 3;
     private static final int UNKNOWN_CLIENT_ID = -1;
+    private static final byte[] DEFAULT_PUBLISHER_INFO = new byte[0];
 
     private final VehicleHal mVehicleHal;
+    private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
+            getClass().getSimpleName());
+    private final Handler mHandler = new Handler(mHandlerThread.getLooper());
     private final int mCoreId;
-    private final MessageQueue mMessageQueue;
+    private final BiFunction<Handler, VmsClientCallback, VmsClient> mInitVmsClient;
     private final int mClientMetricsProperty;
     private final boolean mPropagatePropertyException;
-    private volatile boolean mIsSupported = false;
+    private final VmsSubscriptionHelper mSubscriptionHelper =
+            new VmsSubscriptionHelper(this::setSubscriptions);
 
-    private VmsClientManager mClientManager;
-    private IVmsPublisherService mPublisherService;
-    private IBinder mPublisherToken;
-    private IVmsSubscriberService mSubscriberService;
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private boolean mIsSupported;
+    @GuardedBy("mLock")
+    private VmsClient mClient;
 
-    private int mSubscriptionStateSequence = -1;
-    private int mAvailableLayersSequence = -1;
-
-    private final IVmsPublisherClient.Stub mPublisherClient = new IVmsPublisherClient.Stub() {
+    private final VmsClientCallback mClientCallback = new VmsClientCallback() {
         @Override
-        public void setVmsPublisherService(IBinder token, IVmsPublisherService service) {
-            mPublisherToken = token;
-            mPublisherService = service;
+        public void onClientConnected(VmsClient client) {
+            Log.wtf(TAG, "onClientConnnected triggered for local client");
         }
 
         @Override
-        public void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState) {
+        public void onSubscriptionStateChanged(VmsSubscriptionState subscriptionState) {
             if (DBG) Log.d(TAG, "Handling a subscription state change");
-            // Drop out-of-order notifications
-            if (subscriptionState.getSequenceNumber() <= mSubscriptionStateSequence) {
-                Log.w(TAG,
-                        String.format("Out of order subscription state received: %d (expecting %d)",
-                                subscriptionState.getSequenceNumber(),
-                                mSubscriptionStateSequence + 1));
-                return;
-            }
-            mSubscriptionStateSequence = subscriptionState.getSequenceNumber();
-            mMessageQueue.enqueue(VmsMessageType.SUBSCRIPTIONS_CHANGE,
-                    createSubscriptionStateMessage(VmsMessageType.SUBSCRIPTIONS_CHANGE,
+            setPropertyValue(createSubscriptionStateMessage(VmsMessageType.SUBSCRIPTIONS_CHANGE,
                             subscriptionState));
         }
-    };
-
-    private final IVmsSubscriberClient.Stub mSubscriberClient = new IVmsSubscriberClient.Stub() {
-        @Override
-        public void onVmsMessageReceived(VmsLayer layer, byte[] payload) {
-            if (DBG) Log.d(TAG, "Handling a data message for Layer: " + layer);
-            mMessageQueue.enqueue(VmsMessageType.DATA, createDataMessage(layer, payload));
-        }
 
         @Override
-        public void onLayersAvailabilityChanged(VmsAvailableLayers availableLayers) {
+        public void onLayerAvailabilityChanged(VmsAvailableLayers availableLayers) {
             if (DBG) Log.d(TAG, "Handling a layer availability change");
-            // Drop out-of-order notifications
-            if (availableLayers.getSequence() <= mAvailableLayersSequence) {
-                Log.w(TAG,
-                        String.format("Out of order layer availability received: %d (expecting %d)",
-                                availableLayers.getSequence(),
-                                mAvailableLayersSequence + 1));
-                return;
-            }
-            mAvailableLayersSequence = availableLayers.getSequence();
-            mMessageQueue.enqueue(VmsMessageType.AVAILABILITY_CHANGE,
-                    createAvailableLayersMessage(VmsMessageType.AVAILABILITY_CHANGE,
+            setPropertyValue(createAvailableLayersMessage(VmsMessageType.AVAILABILITY_CHANGE,
                             availableLayers));
         }
-    };
-
-    private class MessageQueue implements Handler.Callback {
-        private final Set<Integer> mSupportedMessageTypes = new ArraySet<>(Arrays.asList(
-                VmsMessageType.DATA,
-                VmsMessageType.START_SESSION,
-                VmsMessageType.AVAILABILITY_CHANGE,
-                VmsMessageType.SUBSCRIPTIONS_CHANGE
-        ));
-        private HandlerThread mHandlerThread;
-        private Handler mHandler;
-
-        synchronized void init() {
-            mHandlerThread = new HandlerThread(TAG);
-            mHandlerThread.start();
-            mHandler = new Handler(mHandlerThread.getLooper(), this);
-        }
-
-        synchronized void release() {
-            if (mHandlerThread != null) {
-                mHandlerThread.quitSafely();
-            }
-        }
-
-        synchronized void enqueue(int messageType, Object message) {
-            if (mSupportedMessageTypes.contains(messageType)) {
-                Message.obtain(mHandler, messageType, message).sendToTarget();
-            } else {
-                Log.e(TAG, "Unexpected message type: " + VmsMessageType.toString(messageType));
-            }
-        }
-
-        synchronized void clear() {
-            mSupportedMessageTypes.forEach(mHandler::removeMessages);
-        }
 
         @Override
-        public boolean handleMessage(Message msg) {
-            int messageType = msg.what;
-            VehiclePropValue vehicleProp = (VehiclePropValue) msg.obj;
-            if (DBG) Log.d(TAG, "Sending " + VmsMessageType.toString(messageType) + " message");
-            setPropertyValue(vehicleProp);
-            return true;
+        public void onPacketReceived(int providerId, VmsLayer layer, byte[] packet) {
+            if (DBG) Log.d(TAG, "Handling a data message for Layer: " + layer);
+            setPropertyValue(createDataMessage(layer, providerId, packet));
         }
-    }
+    };
 
     /**
      * Constructor used by {@link VehicleHal}
      */
     VmsHalService(Context context, VehicleHal vehicleHal) {
-        this(context, vehicleHal, SystemClock::uptimeMillis, (Build.IS_ENG || Build.IS_USERDEBUG));
+        this(context, vehicleHal, SystemClock::uptimeMillis, VmsHalService::initVmsClient,
+                Build.IS_DEBUGGABLE);
     }
 
     @VisibleForTesting
     VmsHalService(Context context, VehicleHal vehicleHal, Supplier<Long> getCoreId,
+            BiFunction<Handler, VmsClientCallback, VmsClient> initVmsClient,
             boolean propagatePropertyException) {
         mVehicleHal = vehicleHal;
         mCoreId = (int) (getCoreId.get() % Integer.MAX_VALUE);
-        mMessageQueue = new MessageQueue();
+        mInitVmsClient = initVmsClient;
         mClientMetricsProperty = getClientMetricsProperty(context);
         mPropagatePropertyException = propagatePropertyException;
     }
@@ -229,84 +168,69 @@
      */
     @VisibleForTesting
     Handler getHandler() {
-        return mMessageQueue.mHandler;
-    }
-
-    /**
-     * Sets a reference to the {@link VmsClientManager} implementation for use by the HAL.
-     */
-    public void setClientManager(VmsClientManager clientManager) {
-        mClientManager = clientManager;
-    }
-
-    /**
-     * Sets a reference to the {@link IVmsSubscriberService} implementation for use by the HAL.
-     */
-    public void setVmsSubscriberService(IVmsSubscriberService service) {
-        mSubscriberService = service;
+        return mHandler;
     }
 
     @Override
-    public Collection<VehiclePropConfig> takeSupportedProperties(
-            Collection<VehiclePropConfig> allProperties) {
-        for (VehiclePropConfig p : allProperties) {
-            if (p.prop == HAL_PROPERTY_ID) {
-                mIsSupported = true;
-                return Collections.singleton(p);
-            }
+    public int[] getAllSupportedProperties() {
+        return SUPPORTED_PROPERTIES;
+    }
+
+    @Override
+    public void takeProperties(Collection<VehiclePropConfig> properties) {
+        if (properties.isEmpty()) {
+            return;
         }
-        return Collections.emptySet();
+        synchronized (mLock) {
+            mIsSupported = true;
+        }
     }
 
     @Override
     public void init() {
-        if (mIsSupported) {
-            Log.i(TAG, "Initializing VmsHalService VHAL property");
-            mVehicleHal.subscribeProperty(this, HAL_PROPERTY_ID);
-        } else {
-            Log.i(TAG, "VmsHalService VHAL property not supported");
-            return; // Do not continue initialization
+        synchronized (mLock) {
+            if (!mIsSupported) {
+                Log.i(TAG, "VmsHalService VHAL property not supported");
+                return; // Do not continue initialization
+            }
+            connectVmsClient();
         }
 
-        mMessageQueue.init();
-        mMessageQueue.enqueue(VmsMessageType.START_SESSION,
-                createStartSessionMessage(mCoreId, UNKNOWN_CLIENT_ID));
+        Log.i(TAG, "Initializing VmsHalService VHAL property");
+        mVehicleHal.subscribeProperty(this, HAL_PROPERTY_ID);
+
+        mHandler.post(() ->
+                setPropertyValue(createStartSessionMessage(mCoreId, UNKNOWN_CLIENT_ID)));
     }
 
     @Override
     public void release() {
-        mMessageQueue.release();
-        mSubscriptionStateSequence = -1;
-        mAvailableLayersSequence = -1;
-
-        if (mIsSupported) {
-            if (DBG) Log.d(TAG, "Releasing VmsHalService VHAL property");
-            mVehicleHal.unsubscribeProperty(this, HAL_PROPERTY_ID);
-        } else {
-            return;
-        }
-
-        if (mSubscriberService != null) {
-            try {
-                mSubscriberService.removeVmsSubscriberToNotifications(mSubscriberClient);
-            } catch (RemoteException e) {
-                Log.e(TAG, "While removing subscriber callback", e);
+        synchronized (mLock) {
+            disconnectVmsClient();
+            if (!mIsSupported) {
+                return;
             }
         }
+        if (DBG) {
+            Log.d(TAG, "Releasing VmsHalService VHAL property");
+        }
+        mVehicleHal.unsubscribeProperty(this, HAL_PROPERTY_ID);
     }
 
     @Override
     public void dump(PrintWriter writer) {
-        writer.println("*VMS HAL*");
-
-        writer.println("VmsProperty: " + (mIsSupported ? "supported" : "unsupported"));
-        writer.println("VmsPublisherService: "
-                + (mPublisherService != null ? "registered " : "unregistered"));
-        writer.println("mSubscriptionStateSequence: " + mSubscriptionStateSequence);
-
-        writer.println("VmsSubscriberService: "
-                + (mSubscriberService != null ? "registered" : "unregistered"));
-        writer.println("mAvailableLayersSequence: " + mAvailableLayersSequence);
+        synchronized (mLock) {
+            writer.println("*VMS HAL*");
+            writer.printf("VmsProperty: %s\n", mIsSupported ? "supported" : "unsupported");
+            if (mClient == null) {
+                writer.println("VmsClient: disconnected");
+                return;
+            }
+            writer.println("VmsClient: connected");
+            writer.printf("Subscriptions: %s\n", mSubscriptionHelper.getSubscriptions());
+            writer.printf("AvailableLayers: %s\n", mClient.getAvailableLayers());
+            writer.printf("SubscriptionState: %s\n", mClient.getSubscriptionState());
+        }
     }
 
     /**
@@ -323,7 +247,7 @@
         VehiclePropValue vehicleProp = null;
         try {
             vehicleProp = mVehicleHal.get(mClientMetricsProperty);
-        } catch (PropertyTimeoutException | RuntimeException e) {
+        } catch (RuntimeException e) {
             // Failures to retrieve metrics should be non-fatal
             Log.e(TAG, "While reading metrics from client", e);
         }
@@ -332,12 +256,11 @@
             return;
         }
 
-        FileOutputStream fout = new FileOutputStream(fd);
-        try {
+        try (FileOutputStream fout = new FileOutputStream(fd)) {
             fout.write(toByteArray(vehicleProp.value.bytes));
             fout.flush();
         } catch (IOException e) {
-            Log.e(TAG, "Error writing metrics to output stream");
+            Log.e(TAG, "Error writing metrics to output stream", e);
         }
     }
 
@@ -348,7 +271,7 @@
      * hardware/interfaces/automotive/vehicle/2.0/types.hal
      */
     @Override
-    public void handleHalEvents(List<VehiclePropValue> values) {
+    public void onHalEvents(List<VehiclePropValue> values) {
         if (DBG) Log.d(TAG, "Handling a VMS property change");
         for (VehiclePropValue v : values) {
             ArrayList<Integer> vec = v.value.int32Values;
@@ -392,12 +315,57 @@
                     default:
                         Log.e(TAG, "Unexpected message type: " + messageType);
                 }
-            } catch (IndexOutOfBoundsException | RemoteException e) {
+            } catch (IndexOutOfBoundsException e) {
                 Log.e(TAG, "While handling " + VmsMessageType.toString(messageType), e);
             }
         }
     }
 
+    private void connectVmsClient() {
+        synchronized (mLock) {
+            mClient = mInitVmsClient.apply(mHandler, mClientCallback);
+        }
+    }
+
+    private void disconnectVmsClient() {
+        synchronized (mLock) {
+            if (mClient != null) {
+                try {
+                    mClient.unregister();
+                } catch (RemoteException e) {
+                    Log.wtf(TAG, "Local broker should not throw RemoteException", e);
+                }
+                mClient = null;
+            }
+        }
+    }
+
+    private static VmsClient initVmsClient(Handler handler, VmsClientCallback callback) {
+        VmsBrokerService brokerService = CarLocalServices.getService(VmsBrokerService.class);
+        if (brokerService == null) {
+            Log.e(TAG, "Broker service is not enabled");
+            return null;
+        }
+        VmsClient client = new VmsClient(brokerService, new HandlerExecutor(handler), callback,
+                /* legacyClient= */ true, /* autoCloseMemory */ false,
+                /* exceptionHandler= */ ignored -> { });
+        try {
+            client.register();
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Local broker should not throw RemoteException", e);
+        }
+        return client;
+    }
+
+    private VmsClient getVmsClient() {
+        synchronized (mLock) {
+            if (mClient == null) {
+                throw new IllegalStateException("VmsClient is not connected");
+            }
+            return mClient;
+        }
+    }
+
     /**
      * SESSION_START message format:
      * <ul>
@@ -412,39 +380,13 @@
         Log.i(TAG, "Starting new session with coreId: " + coreId + " client: " + clientId);
 
         if (coreId != mCoreId) {
-            if (mClientManager != null) {
-                mClientManager.onHalDisconnected();
-            } else {
-                Log.w(TAG, "Client manager not registered");
-            }
-
-            // Drop all queued messages and client state
-            mMessageQueue.clear();
-            mSubscriptionStateSequence = -1;
-            mAvailableLayersSequence = -1;
-
+            // Reset VmsClient
+            disconnectVmsClient();
+            connectVmsClient();
             // Send acknowledgement message
             setPropertyValue(createStartSessionMessage(mCoreId, clientId));
         }
-
-        // Notify client manager of connection
-        if (mClientManager != null) {
-            mClientManager.onHalConnected(mPublisherClient, mSubscriberClient);
-        } else {
-            Log.w(TAG, "Client manager not registered");
-        }
-
-        if (mSubscriberService != null) {
-            // Publish layer availability to HAL clients (this triggers HAL client initialization)
-            try {
-                mSubscriberClient.onLayersAvailabilityChanged(
-                        mSubscriberService.getAvailableLayers());
-            } catch (RemoteException e) {
-                Log.e(TAG, "While publishing layer availability", e);
-            }
-        } else {
-            Log.w(TAG, "Subscriber connect callback not registered");
-        }
+        mClientCallback.onLayerAvailabilityChanged(getVmsClient().getAvailableLayers());
     }
 
     /**
@@ -458,15 +400,14 @@
      * <li>Payload
      * </ul>
      */
-    private void handleDataEvent(List<Integer> message, byte[] payload)
-            throws RemoteException {
+    private void handleDataEvent(List<Integer> message, byte[] payload) {
         VmsLayer vmsLayer = parseVmsLayerFromMessage(message);
         int publisherId = parsePublisherIdFromMessage(message);
         if (DBG) {
             Log.d(TAG,
                     "Handling a data event for Layer: " + vmsLayer + " Publisher: " + publisherId);
         }
-        mPublisherService.publish(mPublisherToken, vmsLayer, publisherId, payload);
+        getVmsClient().publishPacket(publisherId, vmsLayer, payload);
     }
 
     /**
@@ -478,10 +419,10 @@
      * <li>Layer version
      * </ul>
      */
-    private void handleSubscribeEvent(List<Integer> message) throws RemoteException {
+    private void handleSubscribeEvent(List<Integer> message) {
         VmsLayer vmsLayer = parseVmsLayerFromMessage(message);
         if (DBG) Log.d(TAG, "Handling a subscribe event for Layer: " + vmsLayer);
-        mSubscriberService.addVmsSubscriber(mSubscriberClient, vmsLayer);
+        mSubscriptionHelper.subscribe(vmsLayer);
     }
 
     /**
@@ -494,16 +435,14 @@
      * <li>Publisher ID
      * </ul>
      */
-    private void handleSubscribeToPublisherEvent(List<Integer> message)
-            throws RemoteException {
+    private void handleSubscribeToPublisherEvent(List<Integer> message) {
         VmsLayer vmsLayer = parseVmsLayerFromMessage(message);
         int publisherId = parsePublisherIdFromMessage(message);
         if (DBG) {
-            Log.d(TAG,
-                    "Handling a subscribe event for Layer: " + vmsLayer + " Publisher: "
-                            + publisherId);
+            Log.d(TAG, "Handling a subscribe event for Layer: " + vmsLayer
+                    + " Publisher: " + publisherId);
         }
-        mSubscriberService.addVmsSubscriberToPublisher(mSubscriberClient, vmsLayer, publisherId);
+        mSubscriptionHelper.subscribe(vmsLayer, publisherId);
     }
 
     /**
@@ -515,10 +454,10 @@
      * <li>Layer version
      * </ul>
      */
-    private void handleUnsubscribeEvent(List<Integer> message) throws RemoteException {
+    private void handleUnsubscribeEvent(List<Integer> message) {
         VmsLayer vmsLayer = parseVmsLayerFromMessage(message);
         if (DBG) Log.d(TAG, "Handling an unsubscribe event for Layer: " + vmsLayer);
-        mSubscriberService.removeVmsSubscriber(mSubscriberClient, vmsLayer);
+        mSubscriptionHelper.unsubscribe(vmsLayer);
     }
 
     /**
@@ -531,15 +470,18 @@
      * <li>Publisher ID
      * </ul>
      */
-    private void handleUnsubscribeFromPublisherEvent(List<Integer> message)
-            throws RemoteException {
+    private void handleUnsubscribeFromPublisherEvent(List<Integer> message) {
         VmsLayer vmsLayer = parseVmsLayerFromMessage(message);
         int publisherId = parsePublisherIdFromMessage(message);
         if (DBG) {
-            Log.d(TAG, "Handling an unsubscribe event for Layer: " + vmsLayer + " Publisher: "
-                    + publisherId);
+            Log.d(TAG, "Handling an unsubscribe event for Layer: " + vmsLayer
+                    + " Publisher: " + publisherId);
         }
-        mSubscriberService.removeVmsSubscriberToPublisher(mSubscriberClient, vmsLayer, publisherId);
+        mSubscriptionHelper.unsubscribe(vmsLayer, publisherId);
+    }
+
+    private void setSubscriptions(Set<VmsAssociatedLayer> subscriptions) {
+        getVmsClient().setSubscriptions(subscriptions);
     }
 
     /**
@@ -555,14 +497,15 @@
      * <li>Publisher ID
      * </ul>
      */
-    private void handlePublisherIdRequest(byte[] payload)
-            throws RemoteException {
-        if (DBG) Log.d(TAG, "Handling a publisher id request event");
+    private void handlePublisherIdRequest(byte[] payload) {
+        if (DBG) {
+            Log.d(TAG, "Handling a publisher id request event");
+        }
 
         VehiclePropValue vehicleProp = createVmsMessage(VmsMessageType.PUBLISHER_ID_RESPONSE);
-        // Publisher ID
-        vehicleProp.value.int32Values.add(mPublisherService.getPublisherId(payload));
 
+        // Publisher ID
+        vehicleProp.value.int32Values.add(getVmsClient().registerProvider(payload));
         setPropertyValue(vehicleProp);
     }
 
@@ -580,16 +523,17 @@
      * <li>Publisher info (bytes)
      * </ul>
      */
-    private void handlePublisherInfoRequest(List<Integer> message)
-            throws RemoteException {
+    private void handlePublisherInfoRequest(List<Integer> message) {
         if (DBG) Log.d(TAG, "Handling a publisher info request event");
         int publisherId = message.get(VmsPublisherInformationIntegerValuesIndex.PUBLISHER_ID);
 
         VehiclePropValue vehicleProp =
                 createVmsMessage(VmsMessageType.PUBLISHER_INFORMATION_RESPONSE);
-        // Publisher Info
-        appendBytes(vehicleProp.value.bytes, mSubscriberService.getPublisherInfo(publisherId));
 
+        // Publisher Info
+        byte[] publisherInfo = getVmsClient().getProviderDescription(publisherId);
+        appendBytes(vehicleProp.value.bytes,
+                publisherInfo != null ? publisherInfo : DEFAULT_PUBLISHER_INFO);
         setPropertyValue(vehicleProp);
     }
 
@@ -614,7 +558,7 @@
      * </ul>
      * </ul>
      */
-    private void handleOfferingEvent(List<Integer> message) throws RemoteException {
+    private void handleOfferingEvent(List<Integer> message) {
         // Publisher ID for OFFERING is stored at a different index than in other message types
         int publisherId = message.get(VmsOfferingMessageIntegerValuesIndex.PUBLISHER_ID);
         int numLayerDependencies =
@@ -645,10 +589,7 @@
                 offeredLayers.add(new VmsLayerDependency(offeredLayer, dependencies));
             }
         }
-
-        VmsLayersOffering offering = new VmsLayersOffering(offeredLayers, publisherId);
-        VmsOperationRecorder.get().setHalPublisherLayersOffering(offering);
-        mPublisherService.setLayersOffering(mPublisherToken, offering);
+        getVmsClient().setProviderOfferings(publisherId, offeredLayers);
     }
 
     /**
@@ -657,10 +598,9 @@
      * <li>Message type
      * </ul>
      */
-    private void handleAvailabilityRequestEvent() throws RemoteException {
-        setPropertyValue(
-                createAvailableLayersMessage(VmsMessageType.AVAILABILITY_RESPONSE,
-                        mSubscriberService.getAvailableLayers()));
+    private void handleAvailabilityRequestEvent() {
+        setPropertyValue(createAvailableLayersMessage(VmsMessageType.AVAILABILITY_RESPONSE,
+                getVmsClient().getAvailableLayers()));
     }
 
     /**
@@ -669,26 +609,27 @@
      * <li>Message type
      * </ul>
      */
-    private void handleSubscriptionsRequestEvent() throws RemoteException {
-        setPropertyValue(
-                createSubscriptionStateMessage(VmsMessageType.SUBSCRIPTIONS_RESPONSE,
-                        mPublisherService.getSubscriptions()));
+    private void handleSubscriptionsRequestEvent() {
+        setPropertyValue(createSubscriptionStateMessage(VmsMessageType.SUBSCRIPTIONS_RESPONSE,
+                getVmsClient().getSubscriptionState()));
     }
 
     private void setPropertyValue(VehiclePropValue vehicleProp) {
         int messageType = vehicleProp.value.int32Values.get(
                 VmsBaseMessageIntegerValuesIndex.MESSAGE_TYPE);
 
-        if (!mIsSupported) {
-            Log.w(TAG, "HAL unsupported while attempting to send "
-                    + VmsMessageType.toString(messageType));
-            return;
+        synchronized (mLock) {
+            if (!mIsSupported) {
+                Log.w(TAG, "HAL unsupported while attempting to send "
+                        + VmsMessageType.toString(messageType));
+                return;
+            }
         }
 
         try {
             mVehicleHal.set(vehicleProp);
-        } catch (PropertyTimeoutException | RuntimeException e) {
-            Log.e(TAG, "While sending " + VmsMessageType.toString(messageType), e.getCause());
+        } catch (RuntimeException e) {
+            Log.e(TAG, "While sending " + VmsMessageType.toString(messageType), e);
             if (mPropagatePropertyException) {
                 throw new IllegalStateException(e);
             }
@@ -733,16 +674,18 @@
      * </ul>
      *
      * @param layer Layer for which message was published.
+     * @param publisherId Publisher of message
+     * @param payload Data message
      */
-    private static VehiclePropValue createDataMessage(VmsLayer layer, byte[] payload) {
+    private static VehiclePropValue createDataMessage(VmsLayer layer, int publisherId,
+            byte[] payload) {
         // Message type + layer
         VehiclePropValue vehicleProp = createVmsMessage(VmsMessageType.DATA);
         appendLayer(vehicleProp.value.int32Values, layer);
         List<Integer> message = vehicleProp.value.int32Values;
 
         // Publisher ID
-        // TODO(b/124130256): Set publisher ID of data message
-        message.add(0);
+        message.add(publisherId);
 
         // Payload
         appendBytes(vehicleProp.value.bytes, payload);
@@ -879,8 +822,8 @@
         message.add(layer.getVmsLayer().getType());
         message.add(layer.getVmsLayer().getSubtype());
         message.add(layer.getVmsLayer().getVersion());
-        message.add(layer.getPublisherIds().size());
-        message.addAll(layer.getPublisherIds());
+        message.add(layer.getProviderIds().size());
+        message.addAll(layer.getProviderIds());
     }
 
     private static void appendBytes(ArrayList<Byte> dst, byte[] src) {
diff --git a/service/src/com/android/car/pm/ActivityBlockingActivity.java b/service/src/com/android/car/pm/ActivityBlockingActivity.java
index a9f0d6a..991c966 100644
--- a/service/src/com/android/car/pm/ActivityBlockingActivity.java
+++ b/service/src/com/android/car/pm/ActivityBlockingActivity.java
@@ -21,38 +21,62 @@
 import static com.android.car.pm.CarPackageManagerService.BLOCKING_INTENT_EXTRA_ROOT_ACTIVITY_NAME;
 
 import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.IActivityManager;
 import android.car.Car;
 import android.car.content.pm.CarPackageManager;
 import android.car.drivingstate.CarUxRestrictions;
 import android.car.drivingstate.CarUxRestrictionsManager;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
+import android.graphics.Insets;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
+import android.opengl.GLSurfaceView;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.RemoteException;
 import android.text.TextUtils;
 import android.util.Log;
+import android.view.Display;
+import android.view.DisplayInfo;
 import android.view.View;
 import android.view.ViewTreeObserver;
+import android.view.WindowInsets;
 import android.widget.Button;
 import android.widget.TextView;
 
 import com.android.car.CarLog;
 import com.android.car.R;
+import com.android.car.pm.blurredbackground.BlurredSurfaceRenderer;
+
+import java.util.List;
 
 /**
  * Default activity that will be launched when the current foreground activity is not allowed.
  * Additional information on blocked Activity should be passed as intent extras.
  */
 public class ActivityBlockingActivity extends Activity {
+    private static final int EGL_CONTEXT_VERSION = 3;
+    private static final int EGL_CONFIG_SIZE = 8;
     private static final int INVALID_TASK_ID = -1;
+    private final Object mLock = new Object();
+
+    private GLSurfaceView mGLSurfaceView;
+    private BlurredSurfaceRenderer mSurfaceRenderer;
+    private boolean mIsGLSurfaceSetup = false;
 
     private Car mCar;
     private CarUxRestrictionsManager mUxRManager;
+    private CarPackageManager mCarPackageManager;
 
     private Button mExitButton;
     private Button mToggleDebug;
 
     private int mBlockedTaskId;
+    private IActivityManager mAm;
 
     private final View.OnClickListener mOnExitButtonClickedListener =
             v -> {
@@ -78,6 +102,7 @@
         setContentView(R.layout.activity_blocking);
 
         mExitButton = findViewById(R.id.exit_button);
+        mAm = ActivityManager.getService();
 
         // Listen to the CarUxRestrictions so this blocking activity can be dismissed when the
         // restrictions are lifted.
@@ -88,6 +113,8 @@
                     if (!ready) {
                         return;
                     }
+                    mCarPackageManager = (CarPackageManager) car.getCarManager(
+                            Car.PACKAGE_SERVICE);
                     mUxRManager = (CarUxRestrictionsManager) car.getCarManager(
                             Car.CAR_UX_RESTRICTION_SERVICE);
                     // This activity would have been launched only in a restricted state.
@@ -96,6 +123,16 @@
                     handleUxRChange(mUxRManager.getCurrentCarUxRestrictions());
                     mUxRManager.registerListener(ActivityBlockingActivity.this::handleUxRChange);
                 });
+
+        setupGLSurface();
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        if (mIsGLSurfaceSetup) {
+            mGLSurfaceView.onResume();
+        }
     }
 
     @Override
@@ -111,6 +148,12 @@
         String blockedActivity = getIntent().getStringExtra(
                 BLOCKING_INTENT_EXTRA_BLOCKED_ACTIVITY_NAME);
         if (!TextUtils.isEmpty(blockedActivity)) {
+            if (isTopActivityBehindAbaDistractionOptimized()) {
+                Log.e(CarLog.TAG_AM, "Top activity is already DO, so finishing");
+                finish();
+                return;
+            }
+
             if (Log.isLoggable(CarLog.TAG_AM, Log.DEBUG)) {
                 Log.d(CarLog.TAG_AM, "Blocking activity " + blockedActivity);
             }
@@ -124,6 +167,77 @@
         }
     }
 
+    @Override
+    protected void onStop() {
+        super.onStop();
+
+        if (mIsGLSurfaceSetup) {
+            // We queue this event so that it runs on the Rendering thread
+            mGLSurfaceView.queueEvent(() -> mSurfaceRenderer.onPause());
+
+            mGLSurfaceView.onPause();
+        }
+
+        // Finish when blocking activity goes invisible to avoid it accidentally re-surfaces with
+        // stale string regarding blocked activity.
+        finish();
+    }
+
+    private void setupGLSurface() {
+        DisplayManager displayManager = (DisplayManager) getApplicationContext().getSystemService(
+                Context.DISPLAY_SERVICE);
+        DisplayInfo displayInfo = new DisplayInfo();
+
+        int displayId = getDisplayId();
+        displayManager.getDisplay(displayId).getDisplayInfo(displayInfo);
+
+        Rect windowRect = getAppWindowRect();
+
+        // We currently don't support blur for secondary display
+        // (because it is hard to take a screenshot of a secondary display)
+        // So for secondary displays, the GLSurfaceView will not appear blurred
+        boolean shouldRenderBlurred = getDisplayId() == Display.DEFAULT_DISPLAY;
+
+        mSurfaceRenderer = new BlurredSurfaceRenderer(this, windowRect, shouldRenderBlurred);
+
+        mGLSurfaceView = findViewById(R.id.blurred_surface_view);
+        mGLSurfaceView.setEGLContextClientVersion(EGL_CONTEXT_VERSION);
+
+        // Sets up the surface so that we can make it translucent if needed
+        mGLSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
+        mGLSurfaceView.setEGLConfigChooser(EGL_CONFIG_SIZE, EGL_CONFIG_SIZE, EGL_CONFIG_SIZE,
+                EGL_CONFIG_SIZE, EGL_CONFIG_SIZE, EGL_CONFIG_SIZE);
+
+        mGLSurfaceView.setRenderer(mSurfaceRenderer);
+
+        // We only want to render the screen once
+        mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
+
+        mIsGLSurfaceSetup = true;
+    }
+
+    /**
+     * Computes a Rect that represents the portion of the screen that
+     * contains the activity that is being blocked.
+     *
+     * @return Rect that represents the application window
+     */
+    private Rect getAppWindowRect() {
+        Insets systemBarInsets = getWindowManager()
+                .getCurrentWindowMetrics()
+                .getWindowInsets()
+                .getInsets(WindowInsets.Type.systemBars());
+
+        Rect displayBounds = getWindowManager().getCurrentWindowMetrics().getBounds();
+
+        int leftX = systemBarInsets.left;
+        int rightX = displayBounds.width() - systemBarInsets.right;
+        int topY = systemBarInsets.top;
+        int bottomY = displayBounds.height() - systemBarInsets.bottom;
+
+        return new Rect(leftX, topY, rightX, bottomY);
+    }
+
     private void displayExitButton() {
         String exitButtonText = getExitButtonText();
 
@@ -144,6 +258,63 @@
                 : getString(R.string.exit_button_go_back);
     }
 
+    /**
+     * It is possible that the stack info has changed between when the intent to launch this
+     * activity was initiated and when this activity is started. Check whether the activity behind
+     * the ABA is distraction optimized.
+     */
+    private boolean isTopActivityBehindAbaDistractionOptimized() {
+        List<ActivityManager.StackInfo> stackInfos;
+        try {
+            stackInfos = mAm.getAllStackInfos();
+        } catch (RemoteException e) {
+            Log.e(CarLog.TAG_AM, "Unable to get stack info from ActivityManager");
+            // assume that the state is still correct, the activity behind is not DO
+            return false;
+        }
+
+        ActivityManager.StackInfo topStackBehindAba = null;
+        for (ActivityManager.StackInfo stackInfo : stackInfos) {
+            if (stackInfo.displayId != getDisplayId()) {
+                // ignore stacks on other displays
+                continue;
+            }
+
+            if (getComponentName().equals(stackInfo.topActivity)) {
+                // ignore stack with the blocking activity
+                continue;
+            }
+
+            if (!stackInfo.visible) {
+                // ignore stacks that aren't visible
+                continue;
+            }
+
+            if (topStackBehindAba == null || topStackBehindAba.position < stackInfo.position) {
+                topStackBehindAba = stackInfo;
+            }
+        }
+
+        if (Log.isLoggable(CarLog.TAG_AM, Log.DEBUG)) {
+            Log.d(CarLog.TAG_AM, String.format("Top stack behind ABA is: %s", topStackBehindAba));
+        }
+
+        if (topStackBehindAba != null && topStackBehindAba.topActivity != null) {
+            boolean isDo = mCarPackageManager.isActivityDistractionOptimized(
+                    topStackBehindAba.topActivity.getPackageName(),
+                    topStackBehindAba.topActivity.getClassName());
+            if (Log.isLoggable(CarLog.TAG_AM, Log.DEBUG)) {
+                Log.d(CarLog.TAG_AM,
+                        String.format("Top activity (%s) is DO: %s", topStackBehindAba.topActivity,
+                                isDo));
+            }
+            return isDo;
+        }
+
+        // unknown top stack / activity, default to considering it non-DO
+        return false;
+    }
+
     private void displayDebugInfo() {
         String blockedActivity = getIntent().getStringExtra(
                 BLOCKING_INTENT_EXTRA_BLOCKED_ACTIVITY_NAME);
@@ -208,18 +379,14 @@
     }
 
     @Override
-    protected void onStop() {
-        super.onStop();
-        // Finish when blocking activity goes invisible to avoid it accidentally re-surfaces with
-        // stale string regarding blocked activity.
-        finish();
-    }
-
-    @Override
     protected void onDestroy() {
         super.onDestroy();
+        mCar.disconnect();
         mUxRManager.unregisterListener();
-        mToggleDebug.getViewTreeObserver().removeOnGlobalLayoutListener(mOnGlobalLayoutListener);
+        if (mToggleDebug != null) {
+            mToggleDebug.getViewTreeObserver().removeOnGlobalLayoutListener(
+                    mOnGlobalLayoutListener);
+        }
         mCar.disconnect();
     }
 
@@ -247,18 +414,16 @@
     }
 
     private void handleRestartingTask() {
-        if (isFinishing()) {
-            return;
-        }
-
         // Lock on self to avoid restarting the same task twice.
-        synchronized (this) {
+        synchronized (mLock) {
+            if (isFinishing()) {
+                return;
+            }
+
             if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
                 Log.i(CarLog.TAG_AM, "Restarting task " + mBlockedTaskId);
             }
-            CarPackageManager carPm = (CarPackageManager)
-                    mCar.getCarManager(Car.PACKAGE_SERVICE);
-            carPm.restartTask(mBlockedTaskId);
+            mCarPackageManager.restartTask(mBlockedTaskId);
             finish();
         }
     }
diff --git a/service/src/com/android/car/pm/AppBlockingPolicyProxy.java b/service/src/com/android/car/pm/AppBlockingPolicyProxy.java
index 38b5a5a..22d4e42 100644
--- a/service/src/com/android/car/pm/AppBlockingPolicyProxy.java
+++ b/service/src/com/android/car/pm/AppBlockingPolicyProxy.java
@@ -38,9 +38,10 @@
     private final Context mContext;
     private final ServiceInfo mServiceInfo;
     private final ICarAppBlockingPolicySetterImpl mSetter;
+    private final Object mLock = new Object();
 
-    @GuardedBy("this")
-    private ICarAppBlockingPolicy mPolicyService = null;
+    @GuardedBy("mLock")
+    private ICarAppBlockingPolicy mPolicyService;
 
     /**
      * policy not set within this time after binding will be treated as failure and will be
@@ -48,10 +49,10 @@
      */
     private static final long TIMEOUT_MS = 5000;
     private static final int MAX_CRASH_RETRY = 2;
-    @GuardedBy("this")
-    private int mCrashCount = 0;
-    @GuardedBy("this")
-    private boolean mBound = false;
+    @GuardedBy("mLock")
+    private int mCrashCount;
+    @GuardedBy("mLock")
+    private boolean mBound;
 
     private final Handler mHandler;
     private final Runnable mTimeoutRunnable = new Runnable() {
@@ -81,14 +82,14 @@
         intent.setComponent(mServiceInfo.getComponentName());
         mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
                 UserHandle.CURRENT_OR_SELF);
-        synchronized (this) {
+        synchronized (mLock) {
             mBound = true;
         }
         mHandler.postDelayed(mTimeoutRunnable, TIMEOUT_MS);
     }
 
     public void disconnect() {
-        synchronized (this) {
+        synchronized (mLock) {
             if (!mBound) {
                 return;
             }
@@ -107,7 +108,7 @@
     public void onServiceConnected(ComponentName name, IBinder service) {
         ICarAppBlockingPolicy policy = null;
         boolean failed = false;
-        synchronized (this) {
+        synchronized (mLock) {
             mPolicyService = ICarAppBlockingPolicy.Stub.asInterface(service);
             policy = mPolicyService;
             if (policy == null) {
@@ -120,7 +121,7 @@
             return;
         }
         try {
-            mPolicyService.setAppBlockingPolicySetter(mSetter);
+            policy.setAppBlockingPolicySetter(mSetter);
         } catch (RemoteException e) {
             // let retry handle this
         }
@@ -129,7 +130,7 @@
     @Override
     public void onServiceDisconnected(ComponentName name) {
         boolean failed = false;
-        synchronized (this) {
+        synchronized (mLock) {
             mCrashCount++;
             if (mCrashCount > MAX_CRASH_RETRY) {
                 mPolicyService = null;
diff --git a/service/src/com/android/car/pm/CarPackageManagerService.java b/service/src/com/android/car/pm/CarPackageManagerService.java
index 54d577a..9f66e49 100644
--- a/service/src/com/android/car/pm/CarPackageManagerService.java
+++ b/service/src/com/android/car/pm/CarPackageManagerService.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManager.StackInfo;
+import android.app.PendingIntent;
 import android.car.Car;
 import android.car.content.pm.AppBlockingPackageInfo;
 import android.car.content.pm.CarAppBlockingPolicy;
@@ -28,7 +29,8 @@
 import android.car.content.pm.ICarPackageManager;
 import android.car.drivingstate.CarUxRestrictions;
 import android.car.drivingstate.ICarUxRestrictionsChangeListener;
-import android.car.userlib.CarUserManagerHelper;
+import android.car.user.CarUserManager;
+import android.car.user.CarUserManager.UserLifecycleListener;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -66,12 +68,14 @@
 import com.android.car.R;
 import com.android.car.SystemActivityMonitoringService;
 import com.android.car.SystemActivityMonitoringService.TopTaskInfoContainer;
+import com.android.car.user.CarUserService;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
 import com.google.android.collect.Sets;
 
 import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -91,13 +95,16 @@
     private static final int LOG_SIZE = 20;
 
     private final Context mContext;
+    private final CarUserService mUserService;
     private final SystemActivityMonitoringService mSystemActivityMonitoringService;
     private final PackageManager mPackageManager;
     private final ActivityManager mActivityManager;
     private final DisplayManager mDisplayManager;
 
-    private final HandlerThread mHandlerThread;
-    private final PackageHandler mHandler;
+    private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
+            getClass().getSimpleName());
+    private final PackageHandler mHandler  = new PackageHandler(mHandlerThread.getLooper(), this);
+    private final Object mLock = new Object();
 
     // For dumpsys logging.
     private final LinkedList<String> mBlockedActivityLogs = new LinkedList<>();
@@ -112,14 +119,14 @@
      * Hold policy set from policy service or client.
      * Key: packageName of policy service
      */
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private final HashMap<String, ClientPolicy> mClientPolicies = new HashMap<>();
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private HashMap<String, AppBlockingPackageInfoWrapper> mActivityWhitelistMap = new HashMap<>();
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private LinkedList<AppBlockingPolicyProxy> mProxies;
 
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private final LinkedList<CarAppBlockingPolicy> mWaitingPolicies = new LinkedList<>();
 
     private final CarUxRestrictionsManagerService mCarUxRestrictionsService;
@@ -143,8 +150,6 @@
 
     private final PackageParsingEventReceiver mPackageParsingEventReceiver =
             new PackageParsingEventReceiver();
-    private final UserSwitchedEventReceiver mUserSwitchedEventReceiver =
-            new UserSwitchedEventReceiver();
 
     // To track if the packages have been parsed for building white/black lists. If we haven't had
     // received any intents (boot complete or package changed), then the white list is null leading
@@ -187,16 +192,14 @@
     public CarPackageManagerService(Context context,
             CarUxRestrictionsManagerService uxRestrictionsService,
             SystemActivityMonitoringService systemActivityMonitoringService,
-            CarUserManagerHelper carUserManagerHelper) {
+            CarUserService userService) {
         mContext = context;
+        mUserService = userService;
         mCarUxRestrictionsService = uxRestrictionsService;
         mSystemActivityMonitoringService = systemActivityMonitoringService;
         mPackageManager = mContext.getPackageManager();
         mActivityManager = mContext.getSystemService(ActivityManager.class);
         mDisplayManager = mContext.getSystemService(DisplayManager.class);
-        mHandlerThread = new HandlerThread(CarLog.TAG_PACKAGE);
-        mHandlerThread.start();
-        mHandler = new PackageHandler(mHandlerThread.getLooper());
         Resources res = context.getResources();
         mEnableActivityBlocking = res.getBoolean(R.bool.enableActivityBlockingForSafety);
         String blockingActivity = res.getString(R.string.activityBlockingActivity);
@@ -204,7 +207,7 @@
         mAllowedAppInstallSources = Arrays.asList(
                 res.getStringArray(R.array.allowedAppInstallSources));
         mVendorServiceController = new VendorServiceController(
-                mContext, mHandler.getLooper(), carUserManagerHelper);
+                mContext, mHandler.getLooper());
     }
 
 
@@ -221,6 +224,11 @@
      */
     @Override
     public void restartTask(int taskId) {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.REAL_GET_TASKS)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException(
+                    "requires permission " + android.Manifest.permission.REAL_GET_TASKS);
+        }
         mSystemActivityMonitoringService.restartTask(taskId);
     }
 
@@ -240,17 +248,17 @@
             throw new IllegalArgumentException(
                     "Cannot set both FLAG_SET_POLICY_ADD and FLAG_SET_POLICY_REMOVE flag");
         }
-        synchronized (this) {
+        synchronized (mLock) {
             if ((flags & CarPackageManager.FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0) {
                 mWaitingPolicies.add(policy);
             }
         }
         mHandler.requestUpdatingPolicy(packageName, policy, flags);
         if ((flags & CarPackageManager.FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0) {
-            synchronized (this) {
+            synchronized (mLock) {
                 try {
                     while (mWaitingPolicies.contains(policy)) {
-                        wait();
+                        mLock.wait();
                     }
                 } catch (InterruptedException e) {
                     // Pass it over binder call
@@ -264,7 +272,7 @@
     @Override
     public boolean isActivityDistractionOptimized(String packageName, String className) {
         assertPackageAndClassName(packageName, className);
-        synchronized (this) {
+        synchronized (mLock) {
             if (DBG_POLICY_CHECK) {
                 Log.i(CarLog.TAG_PACKAGE, "isActivityDistractionOptimized"
                         + dumpPoliciesLocked(false));
@@ -278,11 +286,20 @@
     }
 
     @Override
+    public boolean isPendingIntentDistractionOptimized(PendingIntent pendingIntent) {
+        ResolveInfo info = mPackageManager.resolveActivity(
+                pendingIntent.getIntent(), PackageManager.MATCH_DEFAULT_ONLY);
+        if (info == null) return false;
+        ActivityInfo activityInfo = info.activityInfo;
+        return isActivityDistractionOptimized(activityInfo.packageName, activityInfo.name);
+    }
+
+    @Override
     public boolean isServiceDistractionOptimized(String packageName, String className) {
         if (packageName == null) {
             throw new IllegalArgumentException("Package name null");
         }
-        synchronized (this) {
+        synchronized (mLock) {
             if (DBG_POLICY_CHECK) {
                 Log.i(CarLog.TAG_PACKAGE, "isServiceDistractionOptimized"
                         + dumpPoliciesLocked(false));
@@ -331,7 +348,7 @@
         }
     }
 
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private AppBlockingPackageInfo searchFromBlacklistsLocked(String packageName) {
         for (ClientPolicy policy : mClientPolicies.values()) {
             AppBlockingPackageInfoWrapper wrapper = policy.blacklistsMap.get(packageName);
@@ -342,7 +359,7 @@
         return null;
     }
 
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private AppBlockingPackageInfo searchFromWhitelistsLocked(String packageName) {
         for (ClientPolicy policy : mClientPolicies.values()) {
             AppBlockingPackageInfoWrapper wrapper = policy.whitelistsMap.get(packageName);
@@ -354,7 +371,7 @@
         return (wrapper != null) ? wrapper.info : null;
     }
 
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private boolean isActivityInWhitelistsLocked(String packageName, String className) {
         for (ClientPolicy policy : mClientPolicies.values()) {
             if (isActivityInMapAndMatching(policy.whitelistsMap, packageName, className)) {
@@ -378,19 +395,22 @@
 
     @Override
     public void init() {
-        synchronized (this) {
+        synchronized (mLock) {
             mHandler.requestInit();
         }
     }
 
     @Override
     public void release() {
-        synchronized (this) {
+        synchronized (mLock) {
             mHandler.requestRelease();
             // wait for release do be done. This guarantees that init is done.
             try {
-                wait();
+                mLock.wait();
             } catch (InterruptedException e) {
+                Log.e(CarLog.TAG_PACKAGE,
+                        "Interrupted wait during release");
+                Thread.currentThread().interrupt();
             }
             mHasParsedPackages = false;
             mActivityWhitelistMap.clear();
@@ -402,10 +422,10 @@
                 mProxies.clear();
             }
             mWaitingPolicies.clear();
-            notifyAll();
+            mLock.notifyAll();
         }
         mContext.unregisterReceiver(mPackageParsingEventReceiver);
-        mContext.unregisterReceiver(mUserSwitchedEventReceiver);
+        mUserService.removeUserLifecycleListener(mUserLifecycleListener);
         mSystemActivityMonitoringService.registerActivityLaunchListener(null);
         for (int i = 0; i < mUxRestrictionsListeners.size(); i++) {
             UxRestrictionsListener listener = mUxRestrictionsListeners.valueAt(i);
@@ -413,12 +433,19 @@
         }
     }
 
+    private final UserLifecycleListener mUserLifecycleListener = event -> {
+        if (Log.isLoggable(CarLog.TAG_PACKAGE, Log.DEBUG)) {
+            Log.d(CarLog.TAG_PACKAGE, "CarPackageManagerService.onEvent(" + event + ")");
+        }
+        if (CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING == event.getEventType()) {
+            CarPackageManagerService.this.mHandler.requestParsingInstalledPkgs(0);
+        }
+    };
+
     // run from HandlerThread
     private void doHandleInit() {
         startAppBlockingPolicies();
-        IntentFilter intent = new IntentFilter();
-        intent.addAction(Intent.ACTION_USER_SWITCHED);
-        mContext.registerReceiver(mUserSwitchedEventReceiver, intent);
+        mUserService.addUserLifecycleListener(mUserLifecycleListener);
         IntentFilter pkgParseIntent = new IntentFilter();
         for (String action : mPackageManagerActions) {
             pkgParseIntent.addAction(action);
@@ -449,7 +476,7 @@
     private void doParseInstalledPackages() {
         int userId = mActivityManager.getCurrentUser();
         generateActivityWhitelistMap(userId);
-        synchronized (this) {
+        synchronized (mLock) {
             mHasParsedPackages = true;
         }
         // Once the activity launch listener is registered we attempt to block any non-whitelisted
@@ -459,9 +486,11 @@
         blockTopActivitiesIfNecessary();
     }
 
-    private synchronized void doHandleRelease() {
-        mVendorServiceController.release();
-        notifyAll();
+    private void doHandleRelease() {
+        synchronized (mLock) {
+            mVendorServiceController.release();
+            mLock.notifyAll();
+        }
     }
 
     private void doUpdatePolicy(String packageName, CarAppBlockingPolicy policy, int flags) {
@@ -471,7 +500,7 @@
         }
         AppBlockingPackageInfoWrapper[] blacklistWrapper = verifyList(policy.blacklists);
         AppBlockingPackageInfoWrapper[] whitelistWrapper = verifyList(policy.whitelists);
-        synchronized (this) {
+        synchronized (mLock) {
             ClientPolicy clientPolicy = mClientPolicies.get(packageName);
             if (clientPolicy == null) {
                 clientPolicy = new ClientPolicy();
@@ -489,7 +518,7 @@
             }
             if ((flags & CarPackageManager.FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0) {
                 mWaitingPolicies.remove(policy);
-                notifyAll();
+                mLock.notifyAll();
             }
             if (DBG_POLICY_SET) {
                 Log.i(CarLog.TAG_PACKAGE, "policy set:" + dumpPoliciesLocked(false));
@@ -598,7 +627,7 @@
                 activityWhitelist.put(packageName, userWhitelistedPackages.get(packageName));
             }
         }
-        synchronized (this) {
+        synchronized (mLock) {
             mActivityWhitelistMap.clear();
             mActivityWhitelistMap.putAll(activityWhitelist);
         }
@@ -662,11 +691,10 @@
             Map<String, Set<String>> configWhitelist, Map<String, Set<String>> configBlacklist) {
         HashMap<String, AppBlockingPackageInfoWrapper> activityWhitelist = new HashMap<>();
 
-        List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
-                PackageManager.GET_SIGNATURES | PackageManager.GET_ACTIVITIES
-                        | PackageManager.MATCH_DIRECT_BOOT_AWARE
-                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
-                userId);
+        List<PackageInfo> packages = mPackageManager
+                .getInstalledPackagesAsUser(PackageManager.GET_SIGNATURES
+                        | PackageManager.GET_ACTIVITIES | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
         for (PackageInfo info : packages) {
             if (info.applicationInfo == null) {
                 continue;
@@ -743,9 +771,8 @@
                     // Some of the activities in this app are Distraction Optimized.
                     if (DBG_POLICY_CHECK) {
                         for (String activity : doActivities) {
-                            Log.d(CarLog.TAG_PACKAGE,
-                                    "adding " + activity + " from " + info.packageName
-                                            + " to whitelist");
+                            Log.d(CarLog.TAG_PACKAGE, "adding " + activity + " from "
+                                    + info.packageName + " to whitelist");
                         }
                     }
                     activities.addAll(Arrays.asList(doActivities));
@@ -867,7 +894,7 @@
                 proxies.add(proxy);
             }
         }
-        synchronized (this) {
+        synchronized (mLock) {
             mProxies = proxies;
         }
     }
@@ -883,7 +910,7 @@
 
     private void doHandlePolicyConnection(AppBlockingPolicyProxy proxy,
             CarAppBlockingPolicy policy) {
-        synchronized (this) {
+        synchronized (mLock) {
             if (mProxies == null) {
                 proxy.disconnect();
                 return;
@@ -908,7 +935,7 @@
 
     @Override
     public void dump(PrintWriter writer) {
-        synchronized (this) {
+        synchronized (mLock) {
             writer.println("*CarPackageManagerService*");
             writer.println("mEnableActivityBlocking:" + mEnableActivityBlocking);
             writer.println("mHasParsedPackages:" + mHasParsedPackages);
@@ -926,7 +953,7 @@
         }
     }
 
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private String dumpPoliciesLocked(boolean dumpAll) {
         StringBuilder sb = new StringBuilder();
         if (dumpAll) {
@@ -1038,7 +1065,7 @@
         if (allowed) {
             return;
         }
-        synchronized (this) {
+        synchronized (mLock) {
             if (!mEnableActivityBlocking) {
                 Log.d(CarLog.TAG_PACKAGE, "Current activity " + topTask.topActivity +
                         " not allowed, blocking disabled. Number of tasks in stack:"
@@ -1120,17 +1147,18 @@
      * engineering builds for development convenience.
      */
     @Override
-    public synchronized void setEnableActivityBlocking(boolean enable) {
+    public void setEnableActivityBlocking(boolean enable) {
         if (!isDebugBuild()) {
             Log.e(CarLog.TAG_PACKAGE, "Cannot enable/disable activity blocking");
             return;
         }
+
         // Check if the caller has the same signature as that of the car service.
         if (mPackageManager.checkSignatures(Process.myUid(), Binder.getCallingUid())
                 != PackageManager.SIGNATURE_MATCH) {
             throw new SecurityException(
                     "Caller " + mPackageManager.getNameForUid(Binder.getCallingUid())
-                            + " does not have the right signature");
+                    + " does not have the right signature");
         }
         mCarUxRestrictionsService.setUxRChangeBroadcastEnabled(enable);
     }
@@ -1171,14 +1199,19 @@
     /**
      * Reading policy and setting policy can take time. Run it in a separate handler thread.
      */
-    private class PackageHandler extends Handler {
+    private static final class PackageHandler extends Handler {
+        private static final String TAG = PackageHandler.class.getSimpleName();
+
         private static final int MSG_INIT = 0;
         private static final int MSG_PARSE_PKG = 1;
         private static final int MSG_UPDATE_POLICY = 2;
         private static final int MSG_RELEASE = 3;
 
-        private PackageHandler(Looper looper) {
+        private final WeakReference<CarPackageManagerService> mService;
+
+        private PackageHandler(Looper looper, CarPackageManagerService service) {
             super(looper);
+            mService = new WeakReference<CarPackageManagerService>(service);
         }
 
         private void requestInit() {
@@ -1187,7 +1220,6 @@
         }
 
         private void requestRelease() {
-            removeMessages(MSG_INIT);
             removeMessages(MSG_UPDATE_POLICY);
             Message msg = obtainMessage(MSG_RELEASE);
             sendMessage(msg);
@@ -1214,20 +1246,25 @@
 
         @Override
         public void handleMessage(Message msg) {
+            CarPackageManagerService service = mService.get();
+            if (service == null) {
+                Log.i(TAG, "handleMessage null service");
+                return;
+            }
             switch (msg.what) {
                 case MSG_INIT:
-                    doHandleInit();
+                    service.doHandleInit();
                     break;
                 case MSG_PARSE_PKG:
-                    doParseInstalledPackages();
+                    service.doParseInstalledPackages();
                     break;
                 case MSG_UPDATE_POLICY:
                     Pair<String, CarAppBlockingPolicy> pair =
                             (Pair<String, CarAppBlockingPolicy>) msg.obj;
-                    doUpdatePolicy(pair.first, pair.second, msg.arg1);
+                    service.doUpdatePolicy(pair.first, pair.second, msg.arg1);
                     break;
                 case MSG_RELEASE:
-                    doHandleRelease();
+                    service.doHandleRelease();
                     break;
             }
         }
@@ -1335,7 +1372,7 @@
      * checking if the foreground Activity should be blocked.
      */
     private class UxRestrictionsListener extends ICarUxRestrictionsChangeListener.Stub {
-        @GuardedBy("this")
+        @GuardedBy("mLock")
         @Nullable
         private CarUxRestrictions mCurrentUxRestrictions;
         private final CarUxRestrictionsManagerService uxRestrictionsService;
@@ -1358,7 +1395,7 @@
                 return;
             }
 
-            synchronized (this) {
+            synchronized (mLock) {
                 mCurrentUxRestrictions = new CarUxRestrictions(restrictions);
             }
             checkIfTopActivityNeedsBlocking();
@@ -1366,7 +1403,7 @@
 
         private void checkIfTopActivityNeedsBlocking() {
             boolean shouldCheck = false;
-            synchronized (this) {
+            synchronized (mLock) {
                 if (mCurrentUxRestrictions != null
                         && mCurrentUxRestrictions.isRequiresDistractionOptimization()) {
                     shouldCheck = true;
@@ -1381,14 +1418,17 @@
             }
         }
 
-        private synchronized boolean isRestricted() {
+        private boolean isRestricted() {
             // if current restrictions is null, try querying the service, once.
-            if (mCurrentUxRestrictions == null) {
-                mCurrentUxRestrictions = uxRestrictionsService.getCurrentUxRestrictions();
+            synchronized (mLock) {
+                if (mCurrentUxRestrictions == null) {
+                    mCurrentUxRestrictions = uxRestrictionsService.getCurrentUxRestrictions();
+                }
+                if (mCurrentUxRestrictions != null) {
+                    return mCurrentUxRestrictions.isRequiresDistractionOptimization();
+                }
             }
-            if (mCurrentUxRestrictions != null) {
-                return mCurrentUxRestrictions.isRequiresDistractionOptimization();
-            }
+
             // If restriction information is still not available (could happen during bootup),
             // return not restricted.  This maintains parity with previous implementation but needs
             // a revisit as we test more.
@@ -1397,21 +1437,6 @@
     }
 
     /**
-     * Listens to the Boot intent to initiate parsing installed packages.
-     */
-    private class UserSwitchedEventReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (intent == null || intent.getAction() == null) {
-                return;
-            }
-            if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
-                mHandler.requestParsingInstalledPkgs(0);
-            }
-        }
-    }
-
-    /**
      * Listens to the package install/uninstall events to know when to initiate parsing
      * installed packages.
      */
diff --git a/service/src/com/android/car/pm/TEST_MAPPING b/service/src/com/android/car/pm/TEST_MAPPING
new file mode 100644
index 0000000..d37fe3d
--- /dev/null
+++ b/service/src/com/android/car/pm/TEST_MAPPING
@@ -0,0 +1,34 @@
+{
+  "auto-postsubmit": [
+    {
+      "name": "CarServiceTest",
+      "options" : [
+        {
+          "include-filter": "com.android.car.pm.CarPackageManagerServiceTest"
+        },
+        {
+          "include-filter": "com.android.car.CarPackageManagerTest"
+        }
+      ]
+    },
+    {
+      "name": "CarServiceUnitTest",
+      "options" : [
+        {
+          "include-filter": "com.android.car.pm.VendorServiceControllerTest"
+        },
+        {
+          "include-filter": "com.android.car.pm.VendorServiceInfoTest"
+        }
+      ]
+    },
+    {
+      "name": "AndroidCarApiTest",
+      "options": [
+        {
+          "include-filter": "android.car.apitest.CarPackageManagerTest"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/service/src/com/android/car/pm/VendorServiceController.java b/service/src/com/android/car/pm/VendorServiceController.java
index b20dc89..ffe4558 100644
--- a/service/src/com/android/car/pm/VendorServiceController.java
+++ b/service/src/com/android/car/pm/VendorServiceController.java
@@ -18,7 +18,10 @@
 
 import static android.content.Context.BIND_AUTO_CREATE;
 
-import android.car.userlib.CarUserManagerHelper;
+import android.app.ActivityManager;
+import android.car.user.CarUserManager;
+import android.car.user.CarUserManager.UserLifecycleEvent;
+import android.car.user.CarUserManager.UserLifecycleListener;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -52,7 +55,7 @@
  * possible pass {@link #mHandler} when subscribe for callbacks otherwise redirect code to the
  * handler.
  */
-class VendorServiceController implements CarUserService.UserCallback {
+class VendorServiceController implements UserLifecycleListener {
     private static final boolean DBG = true;
 
     private static final int MSG_SWITCH_USER = 1;
@@ -64,15 +67,12 @@
     private final Context mContext;
     private final UserManager mUserManager;
     private final Handler mHandler;
-    private final CarUserManagerHelper mUserManagerHelper;
     private CarUserService mCarUserService;
 
 
-    VendorServiceController(Context context, Looper looper,
-            CarUserManagerHelper userManagerHelper) {
+    VendorServiceController(Context context, Looper looper) {
         mContext = context;
         mUserManager = context.getSystemService(UserManager.class);
-        mUserManagerHelper = userManagerHelper;
         mHandler = new Handler(looper) {
             @Override
             public void handleMessage(Message msg) {
@@ -105,14 +105,14 @@
         }
 
         mCarUserService = CarLocalServices.getService(CarUserService.class);
-        mCarUserService.addUserCallback(this);
+        mCarUserService.addUserLifecycleListener(this);
 
         startOrBindServicesIfNeeded();
     }
 
     void release() {
         if (mCarUserService != null) {
-            mCarUserService.removeUserCallback(this);
+            mCarUserService.removeUserLifecycleListener(this);
         }
 
         for (ConnectionKey key : mConnections.keySet()) {
@@ -122,9 +122,32 @@
         mConnections.clear();
     }
 
+    @Override
+    public void onEvent(UserLifecycleEvent event) {
+        if (Log.isLoggable(CarLog.TAG_PACKAGE, Log.DEBUG)) {
+            Log.d(CarLog.TAG_PACKAGE, "onEvent(" + event + ")");
+        }
+        // TODO(b/152069895): Use USER_LIFECYCLE_EVENT_TYPE_UNLOCKED and not care about the
+        //     deprecated unlock=false scenario.
+        if (CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING == event.getEventType()) {
+            Message msg = mHandler.obtainMessage(
+                    MSG_USER_LOCK_CHANGED,
+                    event.getUserId(),
+                    /* unlocked= */ 1);
+            mHandler.executeOrSendMessage(msg);
+        } else if (CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING == event.getEventType()) {
+            mHandler.removeMessages(MSG_SWITCH_USER);
+            Message msg = mHandler.obtainMessage(
+                    MSG_SWITCH_USER,
+                    event.getUserId(),
+                    /* unlocked= */ 0);
+            mHandler.executeOrSendMessage(msg);
+        }
+    }
+
     private void doSwitchUser(int userId) {
         // Stop all services which which do not run under foreground or system user.
-        final int fgUser = mUserManagerHelper.getCurrentForegroundUserId();
+        final int fgUser = ActivityManager.getCurrentUser();
         if (fgUser != userId) {
             Log.w(CarLog.TAG_PACKAGE, "Received userSwitch event for user " + userId
                     + " while current foreground user is " + fgUser + "."
@@ -147,7 +170,7 @@
     }
 
     private void doUserLockChanged(int userId, boolean unlocked) {
-        final int currentUserId = mUserManagerHelper.getCurrentForegroundUserId();
+        final int currentUserId = ActivityManager.getCurrentUser();
 
         if (DBG) {
             Log.i(CarLog.TAG_PACKAGE, "onUserLockedChanged, user: " + userId
@@ -180,26 +203,13 @@
     }
 
     private void startOrBindServicesIfNeeded() {
-        int userId = mUserManagerHelper.getCurrentForegroundUserId();
+        int userId = ActivityManager.getCurrentUser();
         startOrBindServicesForUser(UserHandle.SYSTEM);
         if (userId > 0) {
             startOrBindServicesForUser(UserHandle.of(userId));
         }
     }
 
-    @Override
-    public void onUserLockChanged(int userId, boolean unlocked) {
-        Message msg = mHandler.obtainMessage(MSG_USER_LOCK_CHANGED, userId, unlocked ? 1 : 0);
-        mHandler.executeOrSendMessage(msg);
-    }
-
-    @Override
-    public void onSwitchUser(int userId) {
-        mHandler.removeMessages(MSG_SWITCH_USER);
-        Message msg = mHandler.obtainMessage(MSG_SWITCH_USER, userId, 0);
-        mHandler.executeOrSendMessage(msg);
-    }
-
     private void startOrBindService(VendorServiceInfo service, UserHandle user) {
         ConnectionKey key = ConnectionKey.of(service, user);
         VendorServiceConnection connection = getOrCreateConnection(key);
@@ -220,8 +230,8 @@
     private VendorServiceConnection getOrCreateConnection(ConnectionKey key) {
         VendorServiceConnection connection = mConnections.get(key);
         if (connection == null) {
-            connection = new VendorServiceConnection(mContext, mHandler, mUserManagerHelper,
-                    key.mVendorServiceInfo, key.mUserHandle);
+            connection = new VendorServiceConnection(mContext, mHandler, key.mVendorServiceInfo,
+                    key.mUserHandle);
             mConnections.put(key, connection);
         }
 
@@ -266,14 +276,11 @@
         private final UserHandle mUser;
         private final Handler mHandler;
         private final Handler mFailureHandler;
-        private final CarUserManagerHelper mUserManagerHelper;
 
         VendorServiceConnection(Context context, Handler handler,
-                CarUserManagerHelper userManagerHelper, VendorServiceInfo vendorServiceInfo,
-                UserHandle user) {
+                VendorServiceInfo vendorServiceInfo, UserHandle user) {
             mContext = context;
             mHandler = handler;
-            mUserManagerHelper = userManagerHelper;
             mVendorServiceInfo = vendorServiceInfo;
             mUser = user;
 
@@ -351,7 +358,7 @@
                 return;
             }
 
-            if (UserHandle.of(mUserManagerHelper.getCurrentForegroundUserId()).equals(mUser)
+            if (UserHandle.of(ActivityManager.getCurrentUser()).equals(mUser)
                     || UserHandle.SYSTEM.equals(mUser)) {
                 mFailureHandler.sendMessageDelayed(
                         mFailureHandler.obtainMessage(MSG_REBIND), REBIND_DELAY_MS);
diff --git a/service/src/com/android/car/pm/blurredbackground/BlurTextureProgram.java b/service/src/com/android/car/pm/blurredbackground/BlurTextureProgram.java
new file mode 100644
index 0000000..bb41af2
--- /dev/null
+++ b/service/src/com/android/car/pm/blurredbackground/BlurTextureProgram.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.pm.blurredbackground;
+
+import android.graphics.Rect;
+import android.opengl.GLES11Ext;
+import android.opengl.GLES30;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+
+/**
+ * A class containing the OpenGL programs used to render a blurred texture
+ */
+public class BlurTextureProgram {
+
+    private static final float[] FRAME_COORDS = {
+            -1.0f, -1.0f,   // 0 bottom left
+            1.0f, -1.0f,    // 1 bottom right
+            -1.0f, 1.0f,    // 2 top left
+            1.0f, 1.0f,     // 3 top right
+    };
+    private static final float[] TEXTURE_COORDS = {
+            0.0f, 0.0f,     // 0 bottom left
+            1.0f, 0.0f,     // 1 bottom right
+            0.0f, 1.0f,     // 2 top left
+            1.0f, 1.0f      // 3 top right
+    };
+
+    private static final float[] INVERTED_TEXTURE_COORDS = {
+            0.0f, 1.0f,     // 0 bottom left
+            1.0f, 1.0f,     // 1 bottom right
+            0.0f, 0.0f,     // 2 top left
+            1.0f, 0.0f      // 3 top right
+    };
+
+    private static final int SIZEOF_FLOAT = 4;
+    private static final int NUM_COORDS_PER_VERTEX = 2;
+    private static final float BLUR_RADIUS = 40.0f;
+
+    private final String mVertexShader;
+    private final String mHorizontalBlurShader;
+    private final String mVerticalBlurShader;
+
+    private final int mHorizontalBlurProgram;
+    private final int mVerticalBlurProgram;
+
+    private final int mWidth;
+    private final int mHeight;
+
+    private final int mScreenshotTextureId;
+    private final IntBuffer mScreenshotTextureBuffer;
+    private final float[] mTexMatrix;
+    private final FloatBuffer mResolutionBuffer;
+
+    private final FloatBuffer mVertexBuffer = GLHelper.createFloatBuffer(FRAME_COORDS);
+    private final FloatBuffer mTexBuffer = GLHelper.createFloatBuffer(TEXTURE_COORDS);
+    private final FloatBuffer mInvertedTexBuffer = GLHelper.createFloatBuffer(
+            INVERTED_TEXTURE_COORDS);
+
+    // Locations of the uniforms and attributes for the horizontal program
+    private final int mUHorizontalMVPMatrixLoc;
+    private final int mUHorizontalTexMatrixLoc;
+    private final int mUHorizontalResolutionLoc;
+    private final int mUHorizontalRadiusLoc;
+    private final int mAHorizontalPositionLoc;
+    private final int mAHorizontalTextureCoordLoc;
+
+    // Locations of the uniforms and attributes for the vertical program
+    private final int mUVerticalMVPMatrixLoc;
+    private final int mUVerticalTexMatrixLoc;
+    private final int mUVerticalResolutionLoc;
+    private final int mUVerticalRadiusLoc;
+    private final int mAVerticalPositionLoc;
+    private final int mAVerticalTextureCoordLoc;
+
+    private final IntBuffer mFrameBuffer = IntBuffer.allocate(1);
+    private final IntBuffer mFirstPassTextureBuffer = IntBuffer.allocate(1);
+
+    private int mFrameBufferId;
+    private int mFirstPassTextureId;
+
+    /**
+     * Constructor for the BlurTextureProgram
+     *
+     * @param screenshotTextureBuffer IntBuffer
+     * @param texMatrix Float array used to scale the screenshot texture
+     * @param vertexShader String containing the horizontal blur shader
+     * @param horizontalBlurShader String containing the fragment shader for horizontal blur
+     * @param verticalBlurShader String containing the fragment shader for vertical blur
+     * @param windowRect Rect representing the location of the window being covered
+     */
+    BlurTextureProgram(
+            IntBuffer screenshotTextureBuffer,
+            float[] texMatrix,
+            String vertexShader,
+            String horizontalBlurShader,
+            String verticalBlurShader,
+            Rect windowRect
+    ) {
+        mVertexShader = vertexShader;
+        mHorizontalBlurShader = horizontalBlurShader;
+        mVerticalBlurShader = verticalBlurShader;
+
+        mScreenshotTextureBuffer = screenshotTextureBuffer;
+        mScreenshotTextureId = screenshotTextureBuffer.get(0);
+        mTexMatrix = texMatrix;
+
+        mHorizontalBlurProgram = GLHelper.createProgram(mVertexShader, mHorizontalBlurShader);
+        mVerticalBlurProgram = GLHelper.createProgram(mVertexShader, mVerticalBlurShader);
+
+        mWidth = windowRect.width();
+        mHeight = windowRect.height();
+
+        mResolutionBuffer = FloatBuffer.wrap(new float[]{(float) mWidth, (float) mHeight, 1.0f});
+
+        // Initialize the uniform and attribute locations for the horizontal blur program
+        mUHorizontalMVPMatrixLoc = GLES30.glGetUniformLocation(mHorizontalBlurProgram,
+                "uMVPMatrix");
+        mUHorizontalTexMatrixLoc = GLES30.glGetUniformLocation(mHorizontalBlurProgram,
+                "uTexMatrix");
+        mUHorizontalResolutionLoc = GLES30.glGetUniformLocation(mHorizontalBlurProgram,
+                "uResolution");
+        mUHorizontalRadiusLoc = GLES30.glGetUniformLocation(mHorizontalBlurProgram, "uRadius");
+
+        mAHorizontalPositionLoc = GLES30.glGetAttribLocation(mHorizontalBlurProgram, "aPosition");
+        mAHorizontalTextureCoordLoc = GLES30.glGetAttribLocation(mHorizontalBlurProgram,
+                "aTextureCoord");
+
+        // Initialize the uniform and attribute locations for the vertical blur program
+        mUVerticalMVPMatrixLoc = GLES30.glGetUniformLocation(mVerticalBlurProgram, "uMVPMatrix");
+        mUVerticalTexMatrixLoc = GLES30.glGetUniformLocation(mVerticalBlurProgram, "uTexMatrix");
+        mUVerticalResolutionLoc = GLES30.glGetUniformLocation(mVerticalBlurProgram, "uResolution");
+        mUVerticalRadiusLoc = GLES30.glGetUniformLocation(mVerticalBlurProgram, "uRadius");
+
+        mAVerticalPositionLoc = GLES30.glGetAttribLocation(mVerticalBlurProgram, "aPosition");
+        mAVerticalTextureCoordLoc = GLES30.glGetAttribLocation(mVerticalBlurProgram,
+                "aTextureCoord");
+    }
+
+    /**
+     * Executes all of the rendering logic.  Sets up FrameBuffers and programs to complete
+     * two rendering passes on the captured screenshot to produce a blur.
+     */
+    public void render() {
+        setupProgram(mHorizontalBlurProgram, mScreenshotTextureId,
+                GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
+        setHorizontalUniformsAndAttributes();
+
+        // Create the framebuffer that will hold the texture we render to
+        // for the first shader pass
+        mFrameBufferId = GLHelper.createAndBindFramebuffer(mFrameBuffer);
+
+        // Create the empty texture that will store the output of the first shader pass (this'll
+        // be held in the Framebuffer Object)
+        mFirstPassTextureId = GLHelper.createAndBindTextureObject(mFirstPassTextureBuffer,
+                GLES30.GL_TEXTURE_2D);
+
+        setupTextureForFramebuffer(mFirstPassTextureId);
+        assertValidFramebufferStatus();
+        renderToFramebuffer(mFrameBufferId);
+
+        setupProgram(mVerticalBlurProgram, mFirstPassTextureId, GLES30.GL_TEXTURE_2D);
+        setVerticalUniformsAndAttributes();
+
+        renderToSurface();
+        cleanupResources();
+    }
+
+    /**
+     * Cleans up all OpenGL resources used by programs in this class
+     */
+    public void cleanupResources() {
+        deleteFramebufferTexture();
+        deleteFrameBuffer();
+        deletePrograms();
+
+        GLES30.glFlush();
+    }
+
+    /**
+     * Attaches a 2D texture image to the active framebuffer object
+     *
+     * @param textureId The ID of the texture to be attached
+     */
+    private void setupTextureForFramebuffer(int textureId) {
+        GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGB, mWidth, mHeight, 0,
+                GLES30.GL_RGB, GLES30.GL_UNSIGNED_BYTE, null);
+        GLHelper.checkGlErrors("glTexImage2D");
+        GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0,
+                GLES30.GL_TEXTURE_2D, textureId, 0);
+        GLHelper.checkGlErrors("glFramebufferTexture2D");
+    }
+
+    /**
+     * Deletes the texture stored in the framebuffer
+     */
+    private void deleteFramebufferTexture() {
+        GLES30.glDeleteTextures(mFirstPassTextureBuffer.capacity(), mFirstPassTextureBuffer);
+        GLHelper.checkGlErrors("glDeleteTextures");
+    }
+
+    /**
+     * Deletes the frame buffers.
+     */
+    private void deleteFrameBuffer() {
+        GLES30.glDeleteBuffers(1, mFrameBuffer);
+        GLHelper.checkGlErrors("glDeleteBuffers");
+    }
+
+    /**
+     * Deletes the GL programs.
+     */
+    private void deletePrograms() {
+        GLES30.glDeleteProgram(mHorizontalBlurProgram);
+        GLHelper.checkGlErrors("glDeleteProgram");
+        GLES30.glDeleteProgram(mVerticalBlurProgram);
+        GLHelper.checkGlErrors("glDeleteProgram");
+    }
+
+    /**
+     * Set all of the Uniform and Attribute variable values for the horizontal blur program
+     */
+    private void setHorizontalUniformsAndAttributes() {
+        GLES30.glUniformMatrix4fv(mUHorizontalMVPMatrixLoc, 1, false, GLHelper.getIdentityMatrix(),
+                0);
+        GLES30.glUniformMatrix4fv(mUHorizontalTexMatrixLoc, 1, false, mTexMatrix, 0);
+        GLES30.glUniform3fv(mUHorizontalResolutionLoc, 1, mResolutionBuffer);
+        GLES30.glUniform1f(mUHorizontalRadiusLoc, BLUR_RADIUS);
+
+        GLES30.glEnableVertexAttribArray(mAHorizontalPositionLoc);
+        GLES30.glVertexAttribPointer(mAHorizontalPositionLoc, NUM_COORDS_PER_VERTEX,
+                GLES30.GL_FLOAT, false, NUM_COORDS_PER_VERTEX * SIZEOF_FLOAT, mVertexBuffer);
+
+        GLES30.glEnableVertexAttribArray(mAHorizontalTextureCoordLoc);
+        GLES30.glVertexAttribPointer(mAHorizontalTextureCoordLoc, 2,
+                GLES30.GL_FLOAT, false, 2 * SIZEOF_FLOAT, mTexBuffer);
+    }
+
+    /**
+     * Set all of the Uniform and Attribute variable values for the vertical blur program
+     */
+    private void setVerticalUniformsAndAttributes() {
+        GLES30.glUniformMatrix4fv(mUVerticalMVPMatrixLoc, 1, false, GLHelper.getIdentityMatrix(),
+                0);
+        GLES30.glUniformMatrix4fv(mUVerticalTexMatrixLoc, 1, false, mTexMatrix, 0);
+        GLES30.glUniform3fv(mUVerticalResolutionLoc, 1, mResolutionBuffer);
+        GLES30.glUniform1f(mUVerticalRadiusLoc, BLUR_RADIUS);
+
+        GLES30.glEnableVertexAttribArray(mAVerticalPositionLoc);
+        GLES30.glVertexAttribPointer(mAVerticalPositionLoc, NUM_COORDS_PER_VERTEX,
+                GLES30.GL_FLOAT, false, NUM_COORDS_PER_VERTEX * SIZEOF_FLOAT, mVertexBuffer);
+
+        GLES30.glEnableVertexAttribArray(mAVerticalTextureCoordLoc);
+        GLES30.glVertexAttribPointer(mAVerticalTextureCoordLoc, 2,
+                GLES30.GL_FLOAT, false, 2 * SIZEOF_FLOAT, mInvertedTexBuffer);
+    }
+
+    /**
+     * Sets the program to be used in the next rendering, and binds
+     * a texture to it
+     *
+     * @param programId     The Id of the program
+     * @param textureId     The Id of the texture to be bound
+     * @param textureTarget The type of texture that is being bound
+     */
+    private void setupProgram(int programId, int textureId, int textureTarget) {
+        GLES30.glUseProgram(programId);
+        GLHelper.checkGlErrors("glUseProgram");
+
+        GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
+        GLHelper.checkGlErrors("glActiveTexture");
+
+        GLES30.glBindTexture(textureTarget, textureId);
+        GLHelper.checkGlErrors("glBindTexture");
+    }
+
+    /**
+     * Renders to a framebuffer using the current active program
+     *
+     * @param framebufferId The Id of the framebuffer being rendered to
+     */
+    private void renderToFramebuffer(int framebufferId) {
+        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
+        GLHelper.checkGlErrors("glClear");
+
+        GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, framebufferId);
+        GLHelper.checkGlErrors("glBindFramebuffer");
+
+        GLES30.glViewport(0, 0, mWidth, mHeight);
+        GLHelper.checkGlErrors("glViewport");
+
+        GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0,
+                FRAME_COORDS.length / NUM_COORDS_PER_VERTEX);
+        GLHelper.checkGlErrors("glDrawArrays");
+
+        GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0);
+    }
+
+    /**
+     * Renders to a the GLSurface using the current active program
+     */
+    private void renderToSurface() {
+        GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0);
+        GLHelper.checkGlErrors("glDrawArrays");
+
+        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
+        GLHelper.checkGlErrors("glDrawArrays");
+
+        GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0,
+                FRAME_COORDS.length / NUM_COORDS_PER_VERTEX);
+        GLHelper.checkGlErrors("glDrawArrays");
+    }
+
+    private void assertValidFramebufferStatus() {
+        if (GLES30.glCheckFramebufferStatus(GLES30.GL_FRAMEBUFFER)
+                != GLES30.GL_FRAMEBUFFER_COMPLETE) {
+            throw new RuntimeException(
+                    "Failed to attach Framebuffer. Framebuffer status code is: "
+                            + GLES30.glCheckFramebufferStatus(GLES30.GL_FRAMEBUFFER));
+        }
+    }
+}
diff --git a/service/src/com/android/car/pm/blurredbackground/BlurredSurfaceRenderer.java b/service/src/com/android/car/pm/blurredbackground/BlurredSurfaceRenderer.java
new file mode 100644
index 0000000..fb97113
--- /dev/null
+++ b/service/src/com/android/car/pm/blurredbackground/BlurredSurfaceRenderer.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.pm.blurredbackground;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
+import android.opengl.GLES11Ext;
+import android.opengl.GLES30;
+import android.opengl.GLSurfaceView;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceControl;
+
+import com.android.car.R;
+
+import java.nio.IntBuffer;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * The renderer class for the {@link GLSurfaceView} of the {@link ActivityBlockingActivity}
+ */
+public class BlurredSurfaceRenderer implements GLSurfaceView.Renderer {
+
+    private static final String TAG = "BlurredSurfaceRenderer";
+    private static final int NUM_INDICES_TO_RENDER = 4;
+
+    private final String mVertexShader;
+    private final String mHorizontalBlurShader;
+    private final String mVerticalBlurShader;
+    private final Rect mWindowRect;
+
+    private BlurTextureProgram mProgram;
+    private SurfaceTexture mSurfaceTexture;
+    private Surface mSurface;
+
+    private int mScreenshotTextureId;
+    private final IntBuffer mScreenshotTextureBuffer = IntBuffer.allocate(1);
+    private final float[] mTexMatrix = new float[16];
+
+    private final boolean mShadersLoadedSuccessfully;
+    private final boolean mShouldRenderBlurred;
+    private boolean mIsScreenShotCaptured = false;
+
+    /**
+     * Constructs a new {@link BlurredSurfaceRenderer} and loads the shaders
+     * needed for rendering a blurred texture
+     *
+     * @param windowRect Rect that represents the application window
+     */
+    public BlurredSurfaceRenderer(Context context, Rect windowRect, boolean shouldRenderBlurred) {
+        mShouldRenderBlurred = shouldRenderBlurred;
+
+        mVertexShader = GLHelper.getShaderFromRaw(context, R.raw.vertex_shader);
+        mHorizontalBlurShader = GLHelper.getShaderFromRaw(context,
+                R.raw.horizontal_blur_fragment_shader);
+        mVerticalBlurShader = GLHelper.getShaderFromRaw(context,
+                R.raw.vertical_blur_fragment_shader);
+
+        mShadersLoadedSuccessfully = mVertexShader != null
+                && mHorizontalBlurShader != null
+                && mVerticalBlurShader != null;
+
+        mWindowRect = windowRect;
+    }
+
+    @Override
+    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+        mScreenshotTextureId = GLHelper.createAndBindTextureObject(mScreenshotTextureBuffer,
+                GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
+
+        mSurfaceTexture = new SurfaceTexture(mScreenshotTextureId);
+        mSurface = new Surface(mSurfaceTexture);
+
+        if (mShouldRenderBlurred) {
+            mIsScreenShotCaptured = captureScreenshot();
+        }
+    }
+
+    @Override
+    public void onSurfaceChanged(GL10 gl, int width, int height) {
+    }
+
+    @Override
+    public void onDrawFrame(GL10 gl) {
+        if (shouldDrawFrame()) {
+            mProgram = new BlurTextureProgram(
+                    mScreenshotTextureBuffer,
+                    mTexMatrix,
+                    mVertexShader,
+                    mHorizontalBlurShader,
+                    mVerticalBlurShader,
+                    mWindowRect
+            );
+            mProgram.render();
+        } else {
+            logWillNotRenderBlurredMsg();
+
+            // If we determine we shouldn't render a blurred texture, we
+            // will default to rendering a transparent GLSurfaceView so that
+            // the ActivityBlockingActivity appears translucent
+            renderTransparent();
+        }
+    }
+
+    private void renderTransparent() {
+        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
+        GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, /*first index to render */ 0,
+                NUM_INDICES_TO_RENDER);
+    }
+
+    /**
+     * Called when the ActivityBlockingActivity pauses
+     * cleans up the OpenGL program
+     */
+    public void onPause() {
+        if (mProgram != null) {
+            mProgram.cleanupResources();
+        }
+        deleteScreenshotTexture();
+    }
+
+    private boolean captureScreenshot() {
+        boolean isScreenshotCaptured = false;
+
+        try {
+            final IBinder token = SurfaceControl.getInternalDisplayToken();
+            if (token == null) {
+                Log.e(TAG,
+                        "Could not find display token for screenshot. Will not capture screenshot");
+            } else {
+                SurfaceControl.screenshot(
+                        token,
+                        mSurface,
+                        mWindowRect,
+                        mWindowRect.width(),
+                        mWindowRect.height(),
+                        /* useIdentityTransform= */ false,
+                        Surface.ROTATION_0
+                );
+
+                mSurfaceTexture.updateTexImage();
+                mSurfaceTexture.getTransformMatrix(mTexMatrix);
+                isScreenshotCaptured = true;
+            }
+
+        } finally {
+            mSurface.release();
+            mSurfaceTexture.release();
+        }
+
+        return isScreenshotCaptured;
+    }
+
+    private void deleteScreenshotTexture() {
+        GLES30.glDeleteTextures(mScreenshotTextureBuffer.capacity(), mScreenshotTextureBuffer);
+        GLHelper.checkGlErrors("glDeleteTextures");
+
+        mIsScreenShotCaptured = false;
+    }
+
+    private void logWillNotRenderBlurredMsg() {
+        if (!mIsScreenShotCaptured) {
+            Log.e(TAG, "Screenshot was not captured. Will not render blurred surface");
+        }
+        if (!mShadersLoadedSuccessfully) {
+            Log.e(TAG, "Shaders were not loaded successfully. Will not render blurred surface");
+        }
+    }
+
+    private boolean shouldDrawFrame() {
+        return mIsScreenShotCaptured
+                && mShadersLoadedSuccessfully
+                && mShouldRenderBlurred;
+    }
+}
+
diff --git a/service/src/com/android/car/pm/blurredbackground/GLHelper.java b/service/src/com/android/car/pm/blurredbackground/GLHelper.java
new file mode 100644
index 0000000..42df687
--- /dev/null
+++ b/service/src/com/android/car/pm/blurredbackground/GLHelper.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.pm.blurredbackground;
+
+import android.content.Context;
+import android.opengl.GLES30;
+import android.opengl.Matrix;
+import android.os.Build;
+import android.util.Log;
+import android.util.Slog;
+
+import androidx.annotation.Nullable;
+
+import libcore.io.Streams;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+
+/**
+ * A helper class for simple OpenGL operations
+ */
+public class GLHelper {
+
+    private static final String TAG = "GLHelper";
+    private static final int SIZEOF_FLOAT = 4;
+
+    /**
+     * Creates an OpenGL program that uses the provided shader sources
+     * and returns the id of the created program
+     *
+     * @param vertexShaderSource   The source for the vertex shader
+     * @param fragmentShaderSource The source for the fragment shader
+     * @return The id of the created program
+     */
+    public static int createProgram(String vertexShaderSource, String fragmentShaderSource) {
+        int vertexShader = compileShader(GLES30.GL_VERTEX_SHADER, vertexShaderSource);
+        int fragmentShader = compileShader(GLES30.GL_FRAGMENT_SHADER, fragmentShaderSource);
+
+        int programId = GLES30.glCreateProgram();
+        checkGlErrors("glCreateProgram");
+
+        GLES30.glAttachShader(programId, vertexShader);
+        GLES30.glAttachShader(programId, fragmentShader);
+
+        // glDeleteShader flags these shaders to be deleted, the shaders
+        // are not actually deleted until the program they are attached to are deleted
+        GLES30.glDeleteShader(vertexShader);
+        checkGlErrors("glDeleteShader");
+        GLES30.glDeleteShader(fragmentShader);
+        checkGlErrors("glDeleteShader");
+
+        GLES30.glLinkProgram(programId);
+        checkGlErrors("glLinkProgram");
+
+        return programId;
+    }
+
+    /**
+     * Creates and binds a texture and returns the id of the created texture
+     *
+     * @param textureIdBuffer The IntBuffer that will contain the created texture id
+     * @param textureTarget   The texture target for the created texture
+     * @return The id of the created and bound texture
+     */
+    public static int createAndBindTextureObject(IntBuffer textureIdBuffer, int textureTarget) {
+        GLES30.glGenTextures(1, textureIdBuffer);
+
+        int textureId = textureIdBuffer.get(0);
+
+        GLES30.glBindTexture(textureTarget, textureId);
+        checkGlErrors("glBindTexture");
+
+        // We define the filters that will be applied to the textures if
+        // they get minified or magnified when they are sampled
+        GLES30.glTexParameterf(textureTarget, GLES30.GL_TEXTURE_MIN_FILTER,
+                GLES30.GL_LINEAR);
+        GLES30.glTexParameterf(textureTarget, GLES30.GL_TEXTURE_MAG_FILTER,
+                GLES30.GL_LINEAR);
+
+        // Set the wrap parameters for if the edges of the texture do not fill the surface
+        GLES30.glTexParameteri(textureTarget, GLES30.GL_TEXTURE_WRAP_S,
+                GLES30.GL_CLAMP_TO_EDGE);
+        GLES30.glTexParameteri(textureTarget, GLES30.GL_TEXTURE_WRAP_T,
+                GLES30.GL_CLAMP_TO_EDGE);
+
+        return textureId;
+    }
+
+    /**
+     * Creates and binds a Framebuffer object
+     *
+     * @param frameBuffer the IntBuffer that will contain the created Framebuffer ID
+     * @return The id of the created and bound Framebuffer
+     */
+    public static int createAndBindFramebuffer(IntBuffer frameBuffer) {
+        GLES30.glGenFramebuffers(1, frameBuffer);
+        checkGlErrors("glGenFramebuffers");
+
+        int frameBufferId = frameBuffer.get(0);
+
+        GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, frameBufferId);
+        checkGlErrors("glBindFramebuffer");
+
+        return frameBufferId;
+    }
+
+    /**
+     * Retrieves a string of an OpenGL shader
+     *
+     * @param id the ID of the raw shader resource
+     * @return The shader script, null if the shader failed to load
+     */
+    public static @Nullable String getShaderFromRaw(Context context, int id) {
+        try {
+            InputStream stream = context.getResources().openRawResource(id);
+            return new String(Streams.readFully(new InputStreamReader(stream)));
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to load shader");
+            return null;
+        }
+    }
+
+    /**
+     * Creates a FloatBuffer to hold texture and vertex coordinates
+     *
+     * @param coords The coordinates that will be held in the FloatBuffer
+     * @return a FloatBuffer containing the provided coordinates
+     */
+    public static FloatBuffer createFloatBuffer(float[] coords) {
+        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(coords.length * SIZEOF_FLOAT);
+        byteBuffer.order(ByteOrder.nativeOrder());
+
+        FloatBuffer floatBuffer = byteBuffer.asFloatBuffer();
+        floatBuffer.put(coords);
+        floatBuffer.position(0);
+        return floatBuffer;
+    }
+
+    /**
+     * @return a float[] representing a 4x4 identity matrix
+     */
+    public static float[] getIdentityMatrix() {
+        float[] identityMatrix = new float[16];
+        Matrix.setIdentityM(identityMatrix, 0);
+        return identityMatrix;
+    }
+
+    /**
+     * Checks for GL errors, logging any errors found
+     *
+     * @param func The name of the most recent GL function called
+     * @return a boolean representing if there was a GL error or not
+     */
+    public static boolean checkGlErrors(String func) {
+        boolean hadError = false;
+        int error;
+
+        while ((error = GLES30.glGetError()) != GLES30.GL_NO_ERROR) {
+            if (Build.IS_ENG || Build.IS_USERDEBUG) {
+                Slog.e(TAG, func + " failed: error " + error, new Throwable());
+            }
+            hadError = true;
+        }
+        return hadError;
+    }
+
+    private static int compileShader(int shaderType, String shaderSource) {
+        int shader = GLES30.glCreateShader(shaderType);
+        GLES30.glShaderSource(shader, shaderSource);
+
+        GLES30.glCompileShader(shader);
+        checkGlErrors("glCompileShader");
+
+        return shader;
+    }
+}
diff --git a/service/src/com/android/car/stats/CarStatsService.java b/service/src/com/android/car/stats/CarStatsService.java
index d74fb8c..bf79ee8 100644
--- a/service/src/com/android/car/stats/CarStatsService.java
+++ b/service/src/com/android/car/stats/CarStatsService.java
@@ -16,22 +16,21 @@
 
 package com.android.car.stats;
 
-import android.Manifest;
+import android.app.StatsManager;
+import android.app.StatsManager.PullAtomMetadata;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.os.StatsLogEventWrapper;
-import android.os.SystemClock;
 import android.util.ArrayMap;
 import android.util.Log;
-import android.util.StatsLog;
+import android.util.StatsEvent;
 
+import com.android.car.CarStatsLog;
 import com.android.car.stats.VmsClientLogger.ConnectionState;
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.car.ICarStatsService;
+import com.android.internal.util.ConcurrentUtils;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.List;
@@ -41,11 +40,11 @@
 import java.util.function.Function;
 
 /**
- * Implementation of {@link ICarStatsService}, for reporting pulled atoms via statsd.
+ * Registers pulled atoms with statsd via StatsManager.
  *
  * Also implements collection and dumpsys reporting of atoms in CSV format.
  */
-public class CarStatsService extends ICarStatsService.Stub {
+public class CarStatsService {
     private static final boolean DEBUG = false;
     private static final String TAG = "CarStatsService";
     private static final String VMS_CONNECTION_STATS_DUMPSYS_HEADER =
@@ -82,6 +81,7 @@
 
     private final Context mContext;
     private final PackageManager mPackageManager;
+    private final StatsManager mStatsManager;
 
     @GuardedBy("mVmsClientStats")
     private final Map<Integer, VmsClientLogger> mVmsClientStats = new ArrayMap<>();
@@ -89,6 +89,22 @@
     public CarStatsService(Context context) {
         mContext = context;
         mPackageManager = context.getPackageManager();
+        mStatsManager = (StatsManager) mContext.getSystemService(Context.STATS_MANAGER);
+    }
+
+    /**
+     * Registers VmsClientStats puller with StatsManager.
+     */
+    public void init() {
+        PullAtomMetadata metadata = new PullAtomMetadata.Builder()
+                .setAdditiveFields(new int[] {5, 6, 7, 8, 9, 10})
+                .build();
+        mStatsManager.setPullAtomCallback(
+                CarStatsLog.VMS_CLIENT_STATS,
+                metadata,
+                ConcurrentUtils.DIRECT_EXECUTOR,
+                (atomTag, data) -> pullVmsClientStats(atomTag, data)
+        );
     }
 
     /**
@@ -108,7 +124,6 @@
         }
     }
 
-    @Override
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         List<String> flags = Arrays.asList(args);
         if (args.length == 0 || flags.contains("--vms-client")) {
@@ -116,21 +131,6 @@
         }
     }
 
-    @Override
-    public StatsLogEventWrapper[] pullData(int tagId) {
-        mContext.enforceCallingPermission(Manifest.permission.DUMP, null);
-        if (tagId != StatsLog.VMS_CLIENT_STATS) {
-            Log.w(TAG, "Unexpected tagId: " + tagId);
-            return null;
-        }
-
-        List<StatsLogEventWrapper> ret = new ArrayList<>();
-        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
-        long wallClockNanos = SystemClock.currentTimeMicro() * 1000L;
-        pullVmsClientStats(tagId, elapsedNanos, wallClockNanos, ret);
-        return ret.toArray(new StatsLogEventWrapper[0]);
-    }
-
     private void dumpVmsStats(PrintWriter writer) {
         synchronized (mVmsClientStats) {
             writer.println(VMS_CONNECTION_STATS_DUMPSYS_HEADER);
@@ -149,25 +149,32 @@
         }
     }
 
-    private void pullVmsClientStats(int tagId, long elapsedNanos, long wallClockNanos,
-            List<StatsLogEventWrapper> pulledData) {
+    private int pullVmsClientStats(int atomTag, List<StatsEvent> pulledData) {
+        if (atomTag != CarStatsLog.VMS_CLIENT_STATS) {
+            Log.w(TAG, "Unexpected atom tag: " + atomTag);
+            return StatsManager.PULL_SKIP;
+        }
+
         dumpVmsClientStats((entry) -> {
-            StatsLogEventWrapper e =
-                    new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
-            e.writeInt(entry.getUid());
+            StatsEvent e = StatsEvent.newBuilder()
+                    .setAtomId(atomTag)
+                    .writeInt(entry.getUid())
+                    .addBooleanAnnotation(CarStatsLog.ANNOTATION_ID_IS_UID, true)
 
-            e.writeInt(entry.getLayerType());
-            e.writeInt(entry.getLayerChannel());
-            e.writeInt(entry.getLayerVersion());
+                    .writeInt(entry.getLayerType())
+                    .writeInt(entry.getLayerChannel())
+                    .writeInt(entry.getLayerVersion())
 
-            e.writeLong(entry.getTxBytes());
-            e.writeLong(entry.getTxPackets());
-            e.writeLong(entry.getRxBytes());
-            e.writeLong(entry.getRxPackets());
-            e.writeLong(entry.getDroppedBytes());
-            e.writeLong(entry.getDroppedPackets());
+                    .writeLong(entry.getTxBytes())
+                    .writeLong(entry.getTxPackets())
+                    .writeLong(entry.getRxBytes())
+                    .writeLong(entry.getRxPackets())
+                    .writeLong(entry.getDroppedBytes())
+                    .writeLong(entry.getDroppedPackets())
+                    .build();
             pulledData.add(e);
         });
+        return StatsManager.PULL_SUCCESS;
     }
 
     private void dumpVmsClientStats(Consumer<VmsClientStats> dumpFn) {
diff --git a/service/src/com/android/car/stats/VmsClientLogger.java b/service/src/com/android/car/stats/VmsClientLogger.java
index 948db05..39cade1 100644
--- a/service/src/com/android/car/stats/VmsClientLogger.java
+++ b/service/src/com/android/car/stats/VmsClientLogger.java
@@ -19,8 +19,8 @@
 import android.annotation.Nullable;
 import android.car.vms.VmsLayer;
 import android.util.ArrayMap;
-import android.util.StatsLog;
 
+import com.android.car.CarStatsLog;
 import com.android.internal.annotations.GuardedBy;
 
 import java.util.Collection;
@@ -38,19 +38,19 @@
     public static class ConnectionState {
         // Attempting to connect to the client
         public static final int CONNECTING =
-                StatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__CONNECTING;
+                CarStatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__CONNECTING;
         // Client connection established
         public static final int CONNECTED =
-                StatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__CONNECTED;
+                CarStatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__CONNECTED;
         // Client connection closed unexpectedly
         public static final int DISCONNECTED =
-                StatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__DISCONNECTED;
+                CarStatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__DISCONNECTED;
         // Client connection closed by VMS
         public static final int TERMINATED =
-                StatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__TERMINATED;
+                CarStatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__TERMINATED;
         // Error establishing the client connection
         public static final int CONNECTION_ERROR =
-                StatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__CONNECTION_ERROR;
+                CarStatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__CONNECTION_ERROR;
     }
 
     private final Object mLock = new Object();
@@ -83,8 +83,8 @@
      * @param connectionState New connection state
      */
     public void logConnectionState(int connectionState) {
-        StatsLog.write(StatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED,
-                mUid, mPackageName, connectionState);
+        CarStatsLog.write(CarStatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED,
+                mUid, connectionState);
 
         AtomicLong counter;
         synchronized (mLock) {
diff --git a/service/src/com/android/car/storagemonitoring/IoStatsTracker.java b/service/src/com/android/car/storagemonitoring/IoStatsTracker.java
index 724cd08..fee1bbf 100644
--- a/service/src/com/android/car/storagemonitoring/IoStatsTracker.java
+++ b/service/src/com/android/car/storagemonitoring/IoStatsTracker.java
@@ -13,24 +13,31 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.car.storagemonitoring;
 
 import android.car.storagemonitoring.IoStatsEntry;
 import android.car.storagemonitoring.UidIoRecord;
 import android.util.SparseArray;
+
+import androidx.annotation.GuardedBy;
+
 import com.android.car.SparseArrayStream;
 import com.android.car.procfsinspector.ProcessInfo;
 import com.android.car.systeminterface.SystemStateInterface;
+
 import java.util.List;
 import java.util.Optional;
 
 public class IoStatsTracker {
+
+    // NOTE: this class is not thread safe
     private abstract class Lazy<T> {
         protected Optional<T> mLazy = Optional.empty();
 
         protected abstract T supply();
 
-        public synchronized T get() {
+        public T get() {
             if (!mLazy.isPresent()) {
                 mLazy = Optional.of(supply());
             }
@@ -38,9 +45,12 @@
         }
     }
 
+    private final Object mLock = new Object();
     private final long mSampleWindowMs;
     private final SystemStateInterface mSystemStateInterface;
+    @GuardedBy("mLock")
     private SparseArray<IoStatsEntry> mTotal;
+    @GuardedBy("mLock")
     private SparseArray<IoStatsEntry> mCurrentSample;
 
     public IoStatsTracker(List<IoStatsEntry> initialValue,
@@ -52,7 +62,10 @@
         mSystemStateInterface = systemStateInterface;
     }
 
-    public synchronized void update(SparseArray<UidIoRecord> newMetrics) {
+    /**
+     * Updates the tracker information with new metrics.
+     */
+    public void update(SparseArray<UidIoRecord> newMetrics) {
         final Lazy<List<ProcessInfo>> processTable = new Lazy<List<ProcessInfo>>() {
             @Override
             protected List<ProcessInfo> supply() {
@@ -63,56 +76,68 @@
         SparseArray<IoStatsEntry> newSample = new SparseArray<>();
         SparseArray<IoStatsEntry> newTotal = new SparseArray<>();
 
-        // prepare the new values
-        SparseArrayStream.valueStream(newMetrics).forEach( newRecord -> {
-            final int uid = newRecord.uid;
-            final IoStatsEntry oldRecord = mTotal.get(uid);
+        synchronized (mLock) {
+            // prepare the new values
+            SparseArrayStream.valueStream(newMetrics).forEach(newRecord -> {
+                final int uid = newRecord.uid;
+                final IoStatsEntry oldRecord = mTotal.get(uid);
 
-            IoStatsEntry newStats = null;
+                IoStatsEntry newStats = null;
 
-            if (oldRecord == null) {
-                // this user id has just showed up, so just add it to the current sample
-                // and its runtime is the size of our sample window
-                newStats = new IoStatsEntry(newRecord, mSampleWindowMs);
-            } else {
-                // this user id has already been detected
+                if (oldRecord == null) {
+                    // this user id has just showed up, so just add it to the current sample
+                    // and its runtime is the size of our sample window
+                    newStats = new IoStatsEntry(newRecord, mSampleWindowMs);
+                } else {
+                    // this user id has already been detected
 
-                if (oldRecord.representsSameMetrics(newRecord)) {
-                    // if no new I/O happened, try to figure out if any process on behalf
-                    // of this user has happened, and use that to update the runtime metrics
-                    if (processTable.get().stream().anyMatch(pi -> pi.uid == uid)) {
+                    if (oldRecord.representsSameMetrics(newRecord)) {
+                        // if no new I/O happened, try to figure out if any process on behalf
+                        // of this user has happened, and use that to update the runtime metrics
+                        if (processTable.get().stream().anyMatch(pi -> pi.uid == uid)) {
+                            newStats = new IoStatsEntry(newRecord.delta(oldRecord),
+                                    oldRecord.runtimeMillis + mSampleWindowMs);
+                        }
+                        // if no new I/O happened and no process is running for this user
+                        // then do not prepare a new sample, as nothing has changed
+                    } else {
+                        // but if new I/O happened, assume something was running for the entire
+                        // sample window and compute the delta
                         newStats = new IoStatsEntry(newRecord.delta(oldRecord),
                                 oldRecord.runtimeMillis + mSampleWindowMs);
                     }
-                    // if no new I/O happened and no process is running for this user
-                    // then do not prepare a new sample, as nothing has changed
-                } else {
-                    // but if new I/O happened, assume something was running for the entire
-                    // sample window and compute the delta
-                    newStats = new IoStatsEntry(newRecord.delta(oldRecord),
-                            oldRecord.runtimeMillis + mSampleWindowMs);
                 }
-            }
 
-            if (newStats != null) {
-                newSample.put(uid, newStats);
-                newTotal.append(uid, new IoStatsEntry(newRecord, newStats.runtimeMillis));
-            } else {
-                // if oldRecord were null, newStats would be != null and we wouldn't be here
-                newTotal.append(uid, oldRecord);
-            }
-        });
+                if (newStats != null) {
+                    newSample.put(uid, newStats);
+                    newTotal.append(uid, new IoStatsEntry(newRecord, newStats.runtimeMillis));
+                } else {
+                    // if oldRecord were null, newStats would be != null and we wouldn't be here
+                    newTotal.append(uid, oldRecord);
+                }
+            });
 
-        // now update the stored values
-        mCurrentSample = newSample;
-        mTotal = newTotal;
+            // now update the stored values
+            mCurrentSample = newSample;
+            mTotal = newTotal;
+        }
     }
 
-    public synchronized SparseArray<IoStatsEntry> getTotal() {
-        return mTotal;
+    /**
+     * Returns all IO stats entries.
+     */
+    public SparseArray<IoStatsEntry> getTotal() {
+        synchronized (mLock) {
+            return mTotal.clone();
+        }
     }
 
-    public synchronized SparseArray<IoStatsEntry> getCurrentSample() {
-        return mCurrentSample;
+    /**
+     * Return newly added IO stats entries.
+     */
+    public SparseArray<IoStatsEntry> getCurrentSample() {
+        synchronized (mLock) {
+            return mCurrentSample.clone();
+        }
     }
 }
diff --git a/service/src/com/android/car/storagemonitoring/TEST_MAPPING b/service/src/com/android/car/storagemonitoring/TEST_MAPPING
new file mode 100644
index 0000000..a43eed0
--- /dev/null
+++ b/service/src/com/android/car/storagemonitoring/TEST_MAPPING
@@ -0,0 +1,23 @@
+{
+  "auto-postsubmit": [
+    {
+      "name": "CarServiceTest",
+      "options" : [
+        {
+          "include-filter": "com.android.car.CarStorageMonitoringTest"
+        }
+      ]
+    },
+    {
+      "name": "CarServiceUnitTest",
+      "options" : [
+        {
+          "include-filter": "com.android.car.storagemonitoring.CarStorageMonitoringTest"
+        },
+        {
+          "include-filter": "com.android.car.storagemonitoring.IoStatsTrackerTest"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/service/src/com/android/car/systeminterface/ActivityManagerInterface.java b/service/src/com/android/car/systeminterface/ActivityManagerInterface.java
new file mode 100644
index 0000000..c17ca48
--- /dev/null
+++ b/service/src/com/android/car/systeminterface/ActivityManagerInterface.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.systeminterface;
+
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.content.Intent;
+import android.os.UserHandle;
+
+/**
+ * Interface that abstracts activity manager operations
+ */
+public interface ActivityManagerInterface {
+    /**
+     * Sends a broadcast
+     */
+    void sendBroadcastAsUser(Intent intent, UserHandle user);
+
+    /**
+     * Default implementation of ActivityManagerInterface
+     */
+    class DefaultImpl implements ActivityManagerInterface {
+        private final Context mContext;
+
+        DefaultImpl(Context context) {
+            mContext = context;
+        }
+
+        @Override
+        public void sendBroadcastAsUser(@RequiresPermission Intent intent, UserHandle user) {
+            mContext.sendBroadcastAsUser(intent, user);
+        }
+    }
+}
diff --git a/service/src/com/android/car/systeminterface/DisplayInterface.java b/service/src/com/android/car/systeminterface/DisplayInterface.java
index d20a177..301a48a 100644
--- a/service/src/com/android/car/systeminterface/DisplayInterface.java
+++ b/service/src/com/android/car/systeminterface/DisplayInterface.java
@@ -21,10 +21,11 @@
 import static com.android.settingslib.display.BrightnessUtils.convertLinearToGamma;
 
 import android.app.ActivityManager;
-import android.car.userlib.CarUserManagerHelper;
-import android.car.userlib.CarUserManagerHelper.OnUsersUpdateListener;
+import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.database.ContentObserver;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
@@ -32,20 +33,17 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings.SettingNotFoundException;
 import android.provider.Settings.System;
 import android.util.Log;
 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;
+import com.android.internal.annotations.GuardedBy;
 
 /**
  * Interface that abstracts display operations
@@ -65,30 +63,27 @@
     void refreshDisplayBrightness();
 
     /**
-     * Reconfigure all secondary displays due to b/131909551
-     */
-    void reconfigureSecondaryDisplays();
-    /**
      * Default implementation of display operations
      */
-    class DefaultImpl implements DisplayInterface, OnUsersUpdateListener {
-        static final String TAG = DisplayInterface.class.getSimpleName();
-
+    class DefaultImpl implements DisplayInterface {
         private final ActivityManager mActivityManager;
         private final ContentResolver mContentResolver;
         private final Context mContext;
         private final DisplayManager mDisplayManager;
         private final InputManager mInputManager;
+        private final Object mLock = new Object();
         private final int mMaximumBacklight;
         private final int mMinimumBacklight;
         private final PowerManager mPowerManager;
         private final WakeLockInterface mWakeLockInterface;
+        @GuardedBy("mLock")
         private CarPowerManagementService mService;
+        @GuardedBy("mLock")
         private boolean mDisplayStateSet;
-        private CarUserManagerHelper mCarUserManagerHelper;
+        @GuardedBy("mLock")
         private int mLastBrightnessLevel = -1;
 
-        private ContentObserver mBrightnessObserver =
+        private final ContentObserver mBrightnessObserver =
                 new ContentObserver(new Handler(Looper.getMainLooper())) {
                     @Override
                     public void onChange(boolean selfChange) {
@@ -115,6 +110,13 @@
             }
         };
 
+        private final BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                onUsersUpdate();
+            }
+        };
+
         DefaultImpl(Context context, WakeLockInterface wakeLockInterface) {
             mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
             mContext = context;
@@ -125,30 +127,42 @@
             mMaximumBacklight = mPowerManager.getMaximumScreenBrightnessSetting();
             mMinimumBacklight = mPowerManager.getMinimumScreenBrightnessSetting();
             mWakeLockInterface = wakeLockInterface;
-            mCarUserManagerHelper = new CarUserManagerHelper(context);
-            mCarUserManagerHelper.registerOnUsersUpdateListener(this);
+
+            mContext.registerReceiverAsUser(
+                    mUserChangeReceiver,
+                    UserHandle.ALL,
+                    new IntentFilter(Intent.ACTION_USER_SWITCHED),
+                    null,
+                    null);
         }
 
         @Override
-        public synchronized void refreshDisplayBrightness() {
-            int gamma = GAMMA_SPACE_MAX;
-            try {
-                int linear = System.getIntForUser(
-                        mContentResolver,
-                        System.SCREEN_BRIGHTNESS,
-                        mActivityManager.getCurrentUser());
-                gamma = convertLinearToGamma(linear, mMinimumBacklight, mMaximumBacklight);
-            } catch (SettingNotFoundException e) {
-                Log.e(CarLog.TAG_POWER, "Could not get SCREEN_BRIGHTNESS:  " + e);
+        public void refreshDisplayBrightness() {
+            synchronized (mLock) {
+                if (mService == null) {
+                    Log.e(CarLog.TAG_POWER,
+                            "Could not set brightness: no CarPowerManagementService");
+                    return;
+                }
+                int gamma = GAMMA_SPACE_MAX;
+                try {
+                    int linear = System.getIntForUser(
+                            mContentResolver,
+                            System.SCREEN_BRIGHTNESS,
+                            ActivityManager.getCurrentUser());
+                    gamma = convertLinearToGamma(linear, mMinimumBacklight, mMaximumBacklight);
+                } catch (SettingNotFoundException e) {
+                    Log.e(CarLog.TAG_POWER, "Could not get SCREEN_BRIGHTNESS: " + e);
+                }
+                int percentBright = (gamma * 100 + ((GAMMA_SPACE_MAX + 1) / 2)) / GAMMA_SPACE_MAX;
+                mService.sendDisplayBrightness(percentBright);
             }
-            int percentBright = (gamma * 100 + ((GAMMA_SPACE_MAX + 1) / 2)) / GAMMA_SPACE_MAX;
-            mService.sendDisplayBrightness(percentBright);
         }
 
         private void handleMainDisplayChanged() {
             boolean isOn = isMainDisplayOn();
             CarPowerManagementService service;
-            synchronized (this) {
+            synchronized (mLock) {
                 if (mDisplayStateSet == isOn) { // same as what is set
                     return;
                 }
@@ -164,23 +178,25 @@
 
         @Override
         public void setDisplayBrightness(int percentBright) {
-            if (percentBright == mLastBrightnessLevel) {
-                // We have already set the value last time. Skipping
-                return;
+            synchronized (mLock) {
+                if (percentBright == mLastBrightnessLevel) {
+                    // We have already set the value last time. Skipping
+                    return;
+                }
+                mLastBrightnessLevel = percentBright;
             }
-            mLastBrightnessLevel = percentBright;
             int gamma = (percentBright * GAMMA_SPACE_MAX + 50) / 100;
             int linear = convertGammaToLinear(gamma, mMinimumBacklight, mMaximumBacklight);
             System.putIntForUser(
                     mContentResolver,
                     System.SCREEN_BRIGHTNESS,
                     linear,
-                    mActivityManager.getCurrentUser());
+                    ActivityManager.getCurrentUser());
         }
 
         @Override
         public void startDisplayStateMonitoring(CarPowerManagementService service) {
-            synchronized (this) {
+            synchronized (mLock) {
                 mService = service;
                 mDisplayStateSet = isMainDisplayOn();
             }
@@ -201,7 +217,7 @@
 
         @Override
         public void setDisplayState(boolean on) {
-            synchronized (this) {
+            synchronized (mLock) {
                 mDisplayStateSet = on;
             }
             if (on) {
@@ -228,42 +244,16 @@
             }
         }
 
-        @Override
-        public void onUsersUpdate() {
-            if (mService == null) {
-                // CarPowerManagementService is not connected yet
-                return;
+        private void onUsersUpdate() {
+            synchronized (mLock) {
+                if (mService == null) {
+                    // CarPowerManagementService is not connected yet
+                    return;
+                }
+                // We need to reset last value
+                mLastBrightnessLevel = -1;
             }
-            // We need to reset last value
-            mLastBrightnessLevel = -1;
             refreshDisplayBrightness();
         }
-
-        @Override
-        public void reconfigureSecondaryDisplays() {
-            IWindowManager wm = IWindowManager.Stub
-                    .asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
-            if (wm == null) {
-                Log.e(TAG, "reconfigureSecondaryDisplays IWindowManager not available");
-                return;
-            }
-            Display[] displays = mDisplayManager.getDisplays();
-            for (Display display : displays) {
-                if (display.getDisplayId() == Display.DEFAULT_DISPLAY) { // skip main
-                    continue;
-                }
-                // Only use physical secondary displays
-                if (display.getAddress() instanceof DisplayAddress.Physical) {
-                    int displayId = display.getDisplayId();
-                    try {
-                        // Do not change the mode but this triggers reconfiguring.
-                        int windowingMode = wm.getWindowingMode(displayId);
-                        wm.setWindowingMode(displayId, windowingMode);
-                    } catch (RemoteException e) {
-                        Log.e(CarLog.TAG_SERVICE, "cannot access IWindowManager", e);
-                    }
-                }
-            }
-        }
     }
 }
diff --git a/service/src/com/android/car/systeminterface/SystemInterface.java b/service/src/com/android/car/systeminterface/SystemInterface.java
index 8e7f863..ff3dcb0 100644
--- a/service/src/com/android/car/systeminterface/SystemInterface.java
+++ b/service/src/com/android/car/systeminterface/SystemInterface.java
@@ -17,6 +17,8 @@
 package com.android.car.systeminterface;
 
 import android.content.Context;
+import android.content.Intent;
+import android.os.UserHandle;
 
 import com.android.car.CarPowerManagementService;
 import com.android.car.procfsinspector.ProcessInfo;
@@ -34,9 +36,11 @@
  * This class contains references to all the different wrapper interfaces between
  * CarService and the Android OS APIs.
  */
-public class SystemInterface implements DisplayInterface, IOInterface,
-        StorageMonitoringInterface, SystemStateInterface, TimeInterface,
+public class SystemInterface implements ActivityManagerInterface,
+        DisplayInterface, IOInterface, StorageMonitoringInterface,
+        SystemStateInterface, TimeInterface,
         WakeLockInterface {
+    private final ActivityManagerInterface mActivityManagerInterface;
     private final DisplayInterface mDisplayInterface;
     private final IOInterface mIOInterface;
     private final StorageMonitoringInterface mStorageMonitoringInterface;
@@ -44,12 +48,14 @@
     private final TimeInterface mTimeInterface;
     private final WakeLockInterface mWakeLockInterface;
 
-    SystemInterface(DisplayInterface displayInterface,
+    SystemInterface(ActivityManagerInterface activityManagerInterface,
+            DisplayInterface displayInterface,
             IOInterface ioInterface,
             StorageMonitoringInterface storageMonitoringInterface,
             SystemStateInterface systemStateInterface,
             TimeInterface timeInterface,
             WakeLockInterface wakeLockInterface) {
+        mActivityManagerInterface = activityManagerInterface;
         mDisplayInterface = displayInterface;
         mIOInterface = ioInterface;
         mStorageMonitoringInterface = storageMonitoringInterface;
@@ -58,6 +64,9 @@
         mWakeLockInterface = wakeLockInterface;
     }
 
+    public ActivityManagerInterface getActivityManagerInterface() {
+        return mActivityManagerInterface;
+    }
     public DisplayInterface getDisplayInterface() { return mDisplayInterface; }
     public IOInterface getIOInterface() { return mIOInterface; }
     public SystemStateInterface getSystemStateInterface() { return mSystemStateInterface; }
@@ -68,6 +77,11 @@
     }
 
     @Override
+    public void sendBroadcastAsUser(Intent intent, UserHandle user) {
+        mActivityManagerInterface.sendBroadcastAsUser(intent, user);
+    }
+
+    @Override
     public File getSystemCarDir() {
         return mIOInterface.getSystemCarDir();
     }
@@ -123,11 +137,6 @@
     }
 
     @Override
-    public void reconfigureSecondaryDisplays() {
-        mDisplayInterface.reconfigureSecondaryDisplays();
-    }
-
-    @Override
     public void startDisplayStateMonitoring(CarPowerManagementService service) {
         mDisplayInterface.startDisplayStateMonitoring(service);
     }
@@ -183,6 +192,7 @@
     }
 
     public final static class Builder {
+        private ActivityManagerInterface mActivityManagerInterface;
         private DisplayInterface mDisplayInterface;
         private IOInterface mIOInterface;
         private StorageMonitoringInterface mStorageMonitoringInterface;
@@ -199,6 +209,7 @@
         public static Builder defaultSystemInterface(Context context) {
             Objects.requireNonNull(context);
             Builder builder = newSystemInterface();
+            builder.withActivityManagerInterface(new ActivityManagerInterface.DefaultImpl(context));
             builder.withWakeLockInterface(new WakeLockInterface.DefaultImpl(context));
             builder.withDisplayInterface(new DisplayInterface.DefaultImpl(context,
                     builder.mWakeLockInterface));
@@ -210,6 +221,7 @@
 
         public static Builder fromBuilder(Builder otherBuilder) {
             return newSystemInterface()
+                    .withActivityManagerInterface(otherBuilder.mActivityManagerInterface)
                     .withDisplayInterface(otherBuilder.mDisplayInterface)
                     .withIOInterface(otherBuilder.mIOInterface)
                     .withStorageMonitoringInterface(otherBuilder.mStorageMonitoringInterface)
@@ -218,6 +230,12 @@
                     .withWakeLockInterface(otherBuilder.mWakeLockInterface);
         }
 
+        public Builder withActivityManagerInterface(ActivityManagerInterface
+                activityManagerInterface) {
+            mActivityManagerInterface = activityManagerInterface;
+            return this;
+        }
+
         public Builder withDisplayInterface(DisplayInterface displayInterface) {
             mDisplayInterface = displayInterface;
             return this;
@@ -250,7 +268,8 @@
         }
 
         public SystemInterface build() {
-            return new SystemInterface(Objects.requireNonNull(mDisplayInterface),
+            return new SystemInterface(Objects.requireNonNull(mActivityManagerInterface),
+                Objects.requireNonNull(mDisplayInterface),
                 Objects.requireNonNull(mIOInterface),
                 Objects.requireNonNull(mStorageMonitoringInterface),
                 Objects.requireNonNull(mSystemStateInterface),
diff --git a/service/src/com/android/car/trust/BLEMessageV1Factory.java b/service/src/com/android/car/trust/BLEMessageV1Factory.java
index 4afe877..8bebc90 100644
--- a/service/src/com/android/car/trust/BLEMessageV1Factory.java
+++ b/service/src/com/android/car/trust/BLEMessageV1Factory.java
@@ -113,7 +113,8 @@
      * @param operation The operation this message represents
      * @return The generated {@link com.android.car.trust.BLEStream.BLEMessage}
      */
-    private static BLEMessage makeBLEMessage(byte[] payload, OperationType operation,
+    @VisibleForTesting
+    static BLEMessage makeBLEMessage(byte[] payload, OperationType operation,
             boolean isPayloadEncrypted) {
         return BLEMessage.newBuilder()
                 .setVersion(PROTOCOL_VERSION)
diff --git a/service/src/com/android/car/trust/BLEVersionExchangeResolver.java b/service/src/com/android/car/trust/BLEVersionExchangeResolver.java
index 4465b25..d5c7383 100644
--- a/service/src/com/android/car/trust/BLEVersionExchangeResolver.java
+++ b/service/src/com/android/car/trust/BLEVersionExchangeResolver.java
@@ -16,6 +16,12 @@
 
 package com.android.car.trust;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.os.Handler;
+import android.os.Looper;
 import android.util.Log;
 
 import com.android.car.BLEStreamProtos.VersionExchangeProto.BLEVersionExchange;
@@ -31,13 +37,23 @@
     private static final int SECURITY_VERSION = 1;
 
     /**
-     * Return whether or not the given version exchange proto has the a version that is currently
-     * supported by this device.
+     * Returns a message stream that can be used to send messages to the given
+     * {@link BluetoothDevice} based on the version exchange proto.
      *
      * @param versionExchange The version exchange proto to resolve
-     * @return {@code true} if there is a supported version.
+     * @param device The remote device to send messages to.
+     * @param readCharacteristic The characteristic the remote device will use to write messages to.
+     *                           This is the characteristic this IHU will read from.
+     * @param writeCharacteristic The characteristic on the remote device that this IHU can write
+     *                            messages to.
+     * @return A stream that can send message or {@code null} if resolution was not possible.
      */
-    static boolean hasSupportedVersion(BLEVersionExchange versionExchange) {
+    @Nullable
+    static BleMessageStream resolveToStream(
+            @NonNull BLEVersionExchange versionExchange,
+            @NonNull BluetoothDevice device, @NonNull BlePeripheralManager blePeripheralManager,
+            @NonNull BluetoothGattCharacteristic writeCharacteristic,
+            @NonNull BluetoothGattCharacteristic readCharacteristic) {
         int minMessagingVersion = versionExchange.getMinSupportedMessagingVersion();
         int minSecurityVersion = versionExchange.getMinSupportedSecurityVersion();
 
@@ -47,13 +63,23 @@
         }
 
         // Only one supported version, so ensure the minimum version matches.
-        return minMessagingVersion == MESSAGING_VERSION && minSecurityVersion == SECURITY_VERSION;
+        if (minMessagingVersion == MESSAGING_VERSION && minSecurityVersion == SECURITY_VERSION) {
+            return new BleMessageStreamV1(
+                    new Handler(Looper.getMainLooper()),
+                    blePeripheralManager,
+                    device,
+                    writeCharacteristic,
+                    readCharacteristic);
+        }
+
+        return null;
     }
 
     /**
      * Returns a version exchange proto with the maximum and minimum protocol and security versions
      * this device currently supports.
      */
+    @NonNull
     static BLEVersionExchange makeVersionExchange() {
         return BLEVersionExchange.newBuilder()
                 .setMinSupportedMessagingVersion(MESSAGING_VERSION)
diff --git a/service/src/com/android/car/trust/BleManager.java b/service/src/com/android/car/trust/BleManager.java
deleted file mode 100644
index 28a8fee..0000000
--- a/service/src/com/android/car/trust/BleManager.java
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.car.trust;
-
-import static android.bluetooth.BluetoothProfile.GATT_SERVER;
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothGatt;
-import android.bluetooth.BluetoothGattCallback;
-import android.bluetooth.BluetoothGattCharacteristic;
-import android.bluetooth.BluetoothGattDescriptor;
-import android.bluetooth.BluetoothGattServer;
-import android.bluetooth.BluetoothGattServerCallback;
-import android.bluetooth.BluetoothGattService;
-import android.bluetooth.BluetoothManager;
-import android.bluetooth.BluetoothProfile;
-import android.bluetooth.le.AdvertiseCallback;
-import android.bluetooth.le.AdvertiseData;
-import android.bluetooth.le.AdvertiseSettings;
-import android.bluetooth.le.BluetoothLeAdvertiser;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Handler;
-import android.util.Log;
-
-import androidx.annotation.Nullable;
-
-import com.android.car.Utils;
-
-import java.util.UUID;
-
-/**
- * A generic class that manages BLE operations like start/stop advertising, notifying connects/
- * disconnects and reading/writing values to GATT characteristics.
- *
- * TODO(b/123248433) This could move to a separate comms library.
- */
-public abstract class BleManager {
-    private static final String TAG = BleManager.class.getSimpleName();
-
-    private static final int BLE_RETRY_LIMIT = 5;
-    private static final int BLE_RETRY_INTERVAL_MS = 1000;
-
-    private static final int GATT_SERVER_RETRY_LIMIT = 20;
-    private static final int GATT_SERVER_RETRY_DELAY_MS = 200;
-
-    // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth
-    // .service.generic_access.xml
-    private static final UUID GENERIC_ACCESS_PROFILE_UUID =
-            UUID.fromString("00001800-0000-1000-8000-00805f9b34fb");
-    //https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth
-    // .characteristic.gap.device_name.xml
-    private static final UUID DEVICE_NAME_UUID =
-            UUID.fromString("00002a00-0000-1000-8000-00805f9b34fb");
-
-    private final Handler mHandler = new Handler();
-
-    private final Context mContext;
-    private BluetoothManager mBluetoothManager;
-    private BluetoothLeAdvertiser mAdvertiser;
-    private BluetoothGattServer mGattServer;
-    private BluetoothGatt mBluetoothGatt;
-    private int mAdvertiserStartCount;
-    private int mGattServerRetryStartCount;
-    private BluetoothGattService mBluetoothGattService;
-    private AdvertiseCallback mAdvertiseCallback;
-    private AdvertiseData mData;
-
-    BleManager(Context context) {
-        mContext = context;
-    }
-
-    /**
-     * Starts the GATT server with the given {@link BluetoothGattService} and begins
-     * advertising.
-     *
-     * <p>It is possible that BLE service is still in TURNING_ON state when this method is invoked.
-     * Therefore, several retries will be made to ensure advertising is started.
-     *
-     * @param service           {@link BluetoothGattService} that will be discovered by clients
-     * @param data              {@link AdvertiseData} data to advertise
-     * @param advertiseCallback {@link AdvertiseCallback} callback for advertiser
-     */
-    protected void startAdvertising(BluetoothGattService service, AdvertiseData data,
-            AdvertiseCallback advertiseCallback) {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "startAdvertising: " + service.getUuid().toString());
-        }
-        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
-            Log.e(TAG, "System does not support BLE");
-            return;
-        }
-
-        mBluetoothGattService = service;
-        mAdvertiseCallback = advertiseCallback;
-        mData = data;
-        mGattServerRetryStartCount = 0;
-        mBluetoothManager = (BluetoothManager) mContext.getSystemService(
-            Context.BLUETOOTH_SERVICE);
-        openGattServer();
-    }
-
-    private void openGattServer() {
-        // Only open one Gatt server.
-        if (mGattServer != null) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Gatt Server created, retry count: " + mGattServerRetryStartCount);
-            }
-            mGattServer.clearServices();
-            mGattServer.addService(mBluetoothGattService);
-            AdvertiseSettings settings = new AdvertiseSettings.Builder()
-                .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
-                .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
-                .setConnectable(true)
-                .build();
-            mAdvertiserStartCount = 0;
-            startAdvertisingInternally(settings, mData, mAdvertiseCallback);
-            mGattServerRetryStartCount = 0;
-        } else if (mGattServerRetryStartCount < GATT_SERVER_RETRY_LIMIT) {
-            mGattServer = mBluetoothManager.openGattServer(mContext, mGattServerCallback);
-            mGattServerRetryStartCount++;
-            mHandler.postDelayed(() -> openGattServer(), GATT_SERVER_RETRY_DELAY_MS);
-        } else {
-            Log.e(TAG, "Gatt server not created - exceeded retry limit.");
-        }
-    }
-
-    private void startAdvertisingInternally(AdvertiseSettings settings, AdvertiseData data,
-            AdvertiseCallback advertiseCallback) {
-        if (BluetoothAdapter.getDefaultAdapter() != null) {
-            mAdvertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
-        }
-
-        if (mAdvertiser != null) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Advertiser created, retry count: " + mAdvertiserStartCount);
-            }
-            mAdvertiser.startAdvertising(settings, data, advertiseCallback);
-            mAdvertiserStartCount = 0;
-        } else if (mAdvertiserStartCount < BLE_RETRY_LIMIT) {
-            mHandler.postDelayed(
-                    () -> startAdvertisingInternally(settings, data, advertiseCallback),
-                    BLE_RETRY_INTERVAL_MS);
-            mAdvertiserStartCount += 1;
-        } else {
-            Log.e(TAG, "Cannot start BLE Advertisement.  BT Adapter: "
-                    + BluetoothAdapter.getDefaultAdapter() + " Advertise Retry count: "
-                    + mAdvertiserStartCount);
-        }
-    }
-
-    protected void stopAdvertising(AdvertiseCallback advertiseCallback) {
-        if (mAdvertiser != null) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "stopAdvertising: ");
-            }
-            mAdvertiser.stopAdvertising(advertiseCallback);
-        }
-    }
-
-    /**
-     * Notifies the characteristic change via {@link BluetoothGattServer}
-     */
-    protected void notifyCharacteristicChanged(BluetoothDevice device,
-            BluetoothGattCharacteristic characteristic, boolean confirm) {
-        if (mGattServer == null) {
-            return;
-        }
-
-        boolean result = mGattServer.notifyCharacteristicChanged(device, characteristic, confirm);
-
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "notifyCharacteristicChanged succeeded: " + result);
-        }
-    }
-
-    /**
-     * Connect the Gatt server of the remote device to retrieve device name.
-     */
-    protected final void retrieveDeviceName(BluetoothDevice device) {
-        mBluetoothGatt = device.connectGatt(getContext(), false, mGattCallback);
-    }
-
-    protected Context getContext() {
-        return mContext;
-    }
-
-    /**
-     * Cleans up the BLE GATT server state.
-     */
-    void cleanup() {
-        // Stops the advertiser and GATT server. This needs to be done to avoid leaks
-        if (mAdvertiser != null) {
-            mAdvertiser.cleanup();
-        }
-
-        if (mGattServer != null) {
-            mGattServer.clearServices();
-            try {
-                for (BluetoothDevice d : mBluetoothManager.getConnectedDevices(GATT_SERVER)) {
-                    mGattServer.cancelConnection(d);
-                }
-            } catch (UnsupportedOperationException e) {
-                Log.e(TAG, "Error getting connected devices", e);
-            } finally {
-                stopGattServer();
-            }
-        }
-    }
-
-    /**
-     * Close the GATT Server
-     */
-    void stopGattServer() {
-        if (mGattServer == null) {
-            return;
-        }
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "stopGattServer");
-        }
-        if (mBluetoothGatt != null) {
-            mBluetoothGatt.disconnect();
-        }
-        mGattServer.close();
-        mGattServer = null;
-    }
-
-    /**
-     * Triggered when the name of the remote device is retrieved.
-     *
-     * @param deviceName Name of the remote device.
-     */
-    protected void onDeviceNameRetrieved(@Nullable String deviceName) {
-    }
-
-    /**
-     * Triggered if a remote client has requested to change the MTU for a given connection.
-     *
-     * @param size The new MTU size.
-     */
-    protected void onMtuSizeChanged(int size) {
-    }
-
-    /**
-     * Triggered when a device (GATT client) connected.
-     *
-     * @param device Remote device that connected on BLE.
-     */
-    protected void onRemoteDeviceConnected(BluetoothDevice device) {
-    }
-
-    /**
-     * Triggered when a device (GATT client) disconnected.
-     *
-     * @param device Remote device that disconnected on BLE.
-     */
-    protected void onRemoteDeviceDisconnected(BluetoothDevice device) {
-    }
-
-    /**
-     * Triggered when this BleManager receives a write request from a remote
-     * device. Sub-classes should implement how to handle requests.
-     * <p>
-     *
-     * @see BluetoothGattServerCallback#onCharacteristicWriteRequest(BluetoothDevice, int,
-     * BluetoothGattCharacteristic, boolean, boolean, int, byte[])
-     */
-    protected abstract void onCharacteristicWrite(BluetoothDevice device, int requestId,
-            BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean
-            responseNeeded, int offset, byte[] value);
-
-    /**
-     * Triggered when this BleManager receives a read request from a remote device.
-     * <p>
-     *
-     * @see BluetoothGattServerCallback#onCharacteristicReadRequest(BluetoothDevice, int, int,
-     * BluetoothGattCharacteristic)
-     */
-    protected abstract void onCharacteristicRead(BluetoothDevice device,
-            int requestId, int offset, BluetoothGattCharacteristic characteristic);
-
-    private final BluetoothGattServerCallback mGattServerCallback =
-            new BluetoothGattServerCallback() {
-                @Override
-                public void onConnectionStateChange(BluetoothDevice device, int status,
-                        int newState) {
-                    if (Log.isLoggable(TAG, Log.DEBUG)) {
-                        Log.d(TAG, "BLE Connection State Change: " + newState);
-                    }
-                    switch (newState) {
-                        case BluetoothProfile.STATE_CONNECTED:
-                            onRemoteDeviceConnected(device);
-                            break;
-                        case BluetoothProfile.STATE_DISCONNECTED:
-                            onRemoteDeviceDisconnected(device);
-                            break;
-                        default:
-                            Log.w(TAG,
-                                    "Connection state not connecting or disconnecting; ignoring: "
-                                            + newState);
-                    }
-                }
-
-                @Override
-                public void onServiceAdded(int status, BluetoothGattService service) {
-                    if (Log.isLoggable(TAG, Log.DEBUG)) {
-                        Log.d(TAG,
-                                "Service added status: " + status + " uuid: " + service.getUuid());
-                    }
-                }
-
-                @Override
-                public void onCharacteristicReadRequest(BluetoothDevice device, int requestId,
-                        int offset, BluetoothGattCharacteristic characteristic) {
-                    if (Log.isLoggable(TAG, Log.DEBUG)) {
-                        Log.d(TAG, "Read request for characteristic: " + characteristic.getUuid());
-                    }
-
-                    mGattServer.sendResponse(device, requestId,
-                            BluetoothGatt.GATT_SUCCESS, offset, characteristic.getValue());
-                    onCharacteristicRead(device, requestId, offset, characteristic);
-                }
-
-                @Override
-                public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,
-                        BluetoothGattCharacteristic characteristic, boolean preparedWrite,
-                        boolean responseNeeded, int offset, byte[] value) {
-                    if (Log.isLoggable(TAG, Log.DEBUG)) {
-                        Log.d(TAG, "Write request for characteristic: " + characteristic.getUuid()
-                                + "value: " + Utils.byteArrayToHexString(value));
-                    }
-
-                    mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS,
-                            offset, value);
-                    onCharacteristicWrite(device, requestId, characteristic,
-                            preparedWrite, responseNeeded, offset, value);
-                }
-
-                @Override
-                public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
-                        BluetoothGattDescriptor descriptor, boolean preparedWrite,
-                        boolean responseNeeded, int offset, byte[] value) {
-                    if (Log.isLoggable(TAG, Log.DEBUG)) {
-                        Log.d(TAG, "Write request for descriptor: " + descriptor.getUuid()
-                                + "; value: " + Utils.byteArrayToHexString(value));
-                    }
-
-                    mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS,
-                            offset, value);
-                }
-
-                @Override
-                public void onMtuChanged(BluetoothDevice device, int mtu) {
-                    if (Log.isLoggable(TAG, Log.DEBUG)) {
-                        Log.d(TAG, "onMtuChanged: " + mtu + " for device " + device.getAddress());
-                    }
-                    onMtuSizeChanged(mtu);
-                }
-
-            };
-
-    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
-        @Override
-        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Gatt Connection State Change: " + newState);
-            }
-            switch (newState) {
-                case BluetoothProfile.STATE_CONNECTED:
-                    if (Log.isLoggable(TAG, Log.DEBUG)) {
-                        Log.d(TAG, "Gatt connected");
-                    }
-                    mBluetoothGatt.discoverServices();
-                    break;
-                case BluetoothProfile.STATE_DISCONNECTED:
-                    if (Log.isLoggable(TAG, Log.DEBUG)) {
-                        Log.d(TAG, "Gatt Disconnected");
-                    }
-                    break;
-                default:
-                    if (Log.isLoggable(TAG, Log.DEBUG)) {
-                        Log.d(TAG,
-                                "Connection state not connecting or disconnecting; ignoring: "
-                                        + newState);
-                    }
-            }
-        }
-
-        @Override
-        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Gatt Services Discovered");
-            }
-            BluetoothGattService gapService = mBluetoothGatt.getService(
-                    GENERIC_ACCESS_PROFILE_UUID);
-            if (gapService == null) {
-                Log.e(TAG, "Generic Access Service is Null");
-                return;
-            }
-            BluetoothGattCharacteristic deviceNameCharacteristic = gapService.getCharacteristic(
-                    DEVICE_NAME_UUID);
-            if (deviceNameCharacteristic == null) {
-                Log.e(TAG, "Device Name Characteristic is Null");
-                return;
-            }
-            mBluetoothGatt.readCharacteristic(deviceNameCharacteristic);
-        }
-
-        @Override
-        public void onCharacteristicRead(BluetoothGatt gatt,
-                BluetoothGattCharacteristic characteristic, int status) {
-            if (status == BluetoothGatt.GATT_SUCCESS) {
-                String deviceName = characteristic.getStringValue(0);
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "BLE Device Name: " + deviceName);
-                }
-                onDeviceNameRetrieved(deviceName);
-            } else {
-                Log.e(TAG, "Reading GAP Failed: " + status);
-            }
-        }
-    };
-}
diff --git a/service/src/com/android/car/trust/BleMessageStream.java b/service/src/com/android/car/trust/BleMessageStream.java
new file mode 100644
index 0000000..19da2c2
--- /dev/null
+++ b/service/src/com/android/car/trust/BleMessageStream.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.trust;
+
+import android.annotation.NonNull;
+
+import com.android.car.BLEStreamProtos.BLEOperationProto.OperationType;
+
+/**
+ * Handles the streaming of BLE messages to a specific {@link android.bluetooth.BluetoothDevice}.
+ *
+ * <p>This stream will handle if messages to a particular peripheral need to be split into
+ * multiple messages or if the messages can be sent all at once. Internally, it will have its own
+ * protocol for how the split messages are structured.
+ */
+interface BleMessageStream {
+   /** Registers the given callback to be notified of various events within the stream. */
+    void registerCallback(@NonNull BleMessageStreamCallback callback);
+
+    /** Unregisters the given callback from being notified of stream events. */
+    void unregisterCallback(@NonNull BleMessageStreamCallback callback);
+
+    /** Sets the maximum size of a message that can be sent. */
+    void setMaxWriteSize(int maxWriteSize);
+
+    /** Returns the maximum size of a message that can be sent. */
+    int getMaxWriteSize();
+
+    /**
+     * Writes the given message to the write characteristic set on this stream to the
+     * {@code BleutoothDevice} associated with this stream.
+     *
+     * <p>The given message will adhere to the max write size set on this stream. If the message is
+     * larger than this size, then this stream should take the appropriate actions necessary to
+     * chunk the message to the device so that no parts of the message is dropped.
+     *
+     * <p>If there was an error, then this stream will notify the [callback] of this stream via a
+     * call to its {@code onWriteMessageError} method.
+     *
+     * @param message The message to send.
+     * @param operationType The {@link OperationType} of this message.
+     * @param isPayloadEncrypted {@code true} if the message to send has been encrypted.
+     */
+    void writeMessage(@NonNull byte[] message, @NonNull OperationType operationType,
+            boolean isPayloadEncrypted);
+}
diff --git a/service/src/com/android/car/trust/BleMessageStreamCallback.java b/service/src/com/android/car/trust/BleMessageStreamCallback.java
new file mode 100644
index 0000000..d497c85
--- /dev/null
+++ b/service/src/com/android/car/trust/BleMessageStreamCallback.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.trust;
+
+import android.annotation.NonNull;
+
+import java.util.UUID;
+
+/**
+ * The callback that will be notified of various actions that occur in a {@link BleMessageStream}.
+ */
+interface BleMessageStreamCallback {
+    /**
+     * Called if an error was encountered during a processing of a client message.
+     *
+     * @param uuid The {@link UUID} of the characteristic that the client message was retrieved
+     *             from.
+     */
+    void onMessageReceivedError(@NonNull UUID uuid);
+
+    /**
+     * Called when a complete message is received from the client.
+     *
+     * @param message The complete message.
+     * @param uuid The {@link UUID} of the characteristic that the client message was retrieved
+     *             from.
+     */
+    void onMessageReceived(@NonNull byte[] message, UUID uuid);
+
+    /**
+     * Called if there was an error during a write of a message to the stream.
+     */
+    void onWriteMessageError();
+}
diff --git a/service/src/com/android/car/trust/BleMessageStreamV1.java b/service/src/com/android/car/trust/BleMessageStreamV1.java
new file mode 100644
index 0000000..d3f68cf
--- /dev/null
+++ b/service/src/com/android/car/trust/BleMessageStreamV1.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.trust;
+
+import android.annotation.NonNull;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.os.Handler;
+import android.util.Log;
+
+import com.android.car.BLEStreamProtos.BLEMessageProto.BLEMessage;
+import com.android.car.BLEStreamProtos.BLEOperationProto.OperationType;
+import com.android.car.protobuf.InvalidProtocolBufferException;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Version 1 of the message stream.
+ */
+class BleMessageStreamV1 implements BleMessageStream {
+    private static final String TAG = "BleMessageStreamV1";
+
+    @VisibleForTesting
+    static final int BLE_MESSAGE_RETRY_LIMIT = 5;
+
+    /**
+     * The delay in milliseconds before a failed message is retried for sending.
+     *
+     * <p>This delay is only present for a message has been chunked. Each part of this chunked
+     * message requires an ACK from the remote device before the next chunk is sent. If this ACK is
+     * not received, then a second message is sent after this delay.
+     *
+     * <p>The value of this delay is 2 seconds to allow for 1 second to notify the remote device of
+     * a new message and 1 second to wait for an ACK.
+     */
+    private static final long BLE_MESSAGE_RETRY_DELAY_MS = TimeUnit.SECONDS.toMillis(2);
+
+    private final Handler mHandler;
+    private final BlePeripheralManager mBlePeripheralManager;
+    private final BluetoothDevice mDevice;
+    private final BluetoothGattCharacteristic mWriteCharacteristic;
+    private final BluetoothGattCharacteristic mReadCharacteristic;
+
+    // Explicitly using an ArrayDequeue here for performance when used as a queue.
+    private final Deque<BLEMessage> mMessageQueue = new ArrayDeque<>();
+    private final BLEMessagePayloadStream mPayloadStream = new BLEMessagePayloadStream();
+
+    /** The number of times that a message to send has been retried. */
+    private int mRetryCount = 0;
+
+    /**
+     * The maximum write size for a single message.
+     *
+     * <p>By default, this value is 20 because the smaller possible write size over BLE is 23 bytes.
+     * However, 3 bytes need to be subtracted due to them being used by the header of the BLE
+     * packet. Thus, the final value is 20.
+     */
+    private int mMaxWriteSize = 20;
+
+    private final List<BleMessageStreamCallback> mCallbacks = new ArrayList<>();
+
+    BleMessageStreamV1(@NonNull Handler handler, @NonNull BlePeripheralManager blePeripheralManager,
+            @NonNull BluetoothDevice device,
+            @NonNull BluetoothGattCharacteristic writeCharacteristic,
+            @NonNull BluetoothGattCharacteristic readCharacteristic) {
+        mHandler = handler;
+        mBlePeripheralManager = blePeripheralManager;
+        mDevice = device;
+        mWriteCharacteristic = writeCharacteristic;
+        mReadCharacteristic = readCharacteristic;
+
+        mBlePeripheralManager.addOnCharacteristicWriteListener(this::onCharacteristicWrite);
+    }
+
+    /** Registers the given callback to be notified of various events within the stream. */
+    @Override
+    public void registerCallback(@NonNull BleMessageStreamCallback callback) {
+        mCallbacks.add(callback);
+    }
+
+    /** Unregisters the given callback from being notified of stream events. */
+    @Override
+    public void unregisterCallback(@NonNull BleMessageStreamCallback callback) {
+        mCallbacks.remove(callback);
+    }
+
+    /** Sets the maximum size of a message that can be sent. */
+    @Override
+    public void setMaxWriteSize(int maxWriteSize) {
+        mMaxWriteSize = maxWriteSize;
+    }
+
+    /** Returns the maximum size of a message that can be sent. */
+    @Override
+    public int getMaxWriteSize() {
+        return mMaxWriteSize;
+    }
+
+    /**
+     * Writes the given message to the write characteristic of this stream.
+     *
+     * <p>This method will handle the chunking of messages based on maximum write size assigned to
+     * this stream.. If there is an error during the send, any callbacks on this stream will be
+     * notified of the error.
+     *
+     * @param message The message to send.
+     * @param operationType The {@link OperationType} of this message.
+     * @param isPayloadEncrypted {@code true} if the message to send has been encrypted.
+     */
+    @Override
+    public void writeMessage(@NonNull byte[] message, @NonNull OperationType operationType,
+            boolean isPayloadEncrypted) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "Writing message to device with name: " + mDevice.getName());
+        }
+
+        List<BLEMessage> bleMessages = BLEMessageV1Factory.makeBLEMessages(message, operationType,
+                mMaxWriteSize, isPayloadEncrypted);
+
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "Number of messages to send to device: " + bleMessages.size());
+        }
+
+        // Each write will override previous messages.
+        if (!mMessageQueue.isEmpty()) {
+            mMessageQueue.clear();
+            Log.w(TAG, "Request to write a new message when there are still messages in the "
+                    + "queue.");
+        }
+
+        mMessageQueue.addAll(bleMessages);
+
+        writeNextMessageInQueue();
+    }
+
+    /**
+     * Processes a message from the client and notifies any callbacks of the success of this
+     * call.
+     */
+    @VisibleForTesting
+    void onCharacteristicWrite(@NonNull BluetoothDevice device,
+            @NonNull BluetoothGattCharacteristic characteristic, @NonNull byte[] value) {
+        if (!mDevice.equals(device)) {
+            Log.w(TAG, "Received a message from a device (" + device.getAddress() + ") that is not "
+                    + "the expected device (" + mDevice.getAddress() + ") registered to this "
+                    + "stream. Ignoring.");
+            return;
+        }
+
+        if (!characteristic.getUuid().equals(mReadCharacteristic.getUuid())) {
+            Log.w(TAG, "Received a write to a characteristic (" + characteristic.getUuid()
+                    + ") that is not the expected UUID (" + mReadCharacteristic.getUuid()
+                    + "). Ignoring.");
+            return;
+        }
+
+        BLEMessage bleMessage;
+        try {
+            bleMessage = BLEMessage.parseFrom(value);
+        } catch (InvalidProtocolBufferException e) {
+            Log.e(TAG, "Can not parse BLE message from client.", e);
+
+            for (BleMessageStreamCallback callback : mCallbacks) {
+                callback.onMessageReceivedError(characteristic.getUuid());
+            }
+            return;
+        }
+
+        if (bleMessage.getOperation() == OperationType.ACK) {
+            handleClientAckMessage();
+            return;
+        }
+
+        try {
+            mPayloadStream.write(bleMessage);
+        } catch (IOException e) {
+            Log.e(TAG, "Unable to parse the BLE message's payload from client.", e);
+
+            for (BleMessageStreamCallback callback : mCallbacks) {
+                callback.onMessageReceivedError(characteristic.getUuid());
+            }
+            return;
+        }
+
+        // If it's not complete, make sure the client knows that this message was received.
+        if (!mPayloadStream.isComplete()) {
+            sendAcknowledgmentMessage();
+            return;
+        }
+
+        for (BleMessageStreamCallback callback : mCallbacks) {
+            callback.onMessageReceived(mPayloadStream.toByteArray(), characteristic.getUuid());
+        }
+
+        mPayloadStream.reset();
+    }
+
+    /**
+     * Writes the next message in the message queue to the write characteristic.
+     *
+     * <p>If the message queue is empty, then this method will do nothing.
+     */
+    private void writeNextMessageInQueue() {
+        // This should not happen in practice since this method is private and should only be called
+        // for a non-empty queue.
+        if (mMessageQueue.isEmpty()) {
+            Log.e(TAG, "Call to write next message in queue, but the message queue is empty.");
+            return;
+        }
+
+        if (mMessageQueue.size() == 1) {
+            writeValueAndNotify(mMessageQueue.remove().toByteArray());
+            return;
+        }
+
+        mHandler.post(mSendMessageWithTimeoutRunnable);
+    }
+
+    private void handleClientAckMessage() {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "Received ACK from client. Attempting to write next message in queue.");
+        }
+
+        mHandler.removeCallbacks(mSendMessageWithTimeoutRunnable);
+        mRetryCount = 0;
+
+        if (mMessageQueue.isEmpty()) {
+            Log.e(TAG, "Received ACK, but the message queue is empty. Ignoring.");
+            return;
+        }
+
+        // Previous message has been sent successfully so we can start the next message.
+        mMessageQueue.remove();
+        writeNextMessageInQueue();
+    }
+
+    private void sendAcknowledgmentMessage() {
+        writeValueAndNotify(BLEMessageV1Factory.makeAcknowledgementMessage().toByteArray());
+    }
+
+    /**
+     * Convenience method to write the given message to the {@link #mWriteCharacteristic} of this
+     * class. After writing, this method will also send notifications to any listening devices that
+     * the write was made.
+     */
+    private void writeValueAndNotify(@NonNull byte[] message) {
+        mWriteCharacteristic.setValue(message);
+
+        mBlePeripheralManager.notifyCharacteristicChanged(mDevice, mWriteCharacteristic,
+                /* confirm= */ false);
+    }
+
+    /**
+     * A runnable that will write the message at the head of the {@link #mMessageQueue} and set up
+     * a timeout for receiving an ACK for that write.
+     *
+     * <p>If the timeout is reached before an ACK is received, the message write is retried.
+     */
+    private final Runnable mSendMessageWithTimeoutRunnable = new Runnable() {
+        @Override
+        public void run() {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "Sending BLE message; retry count: " + mRetryCount);
+            }
+
+            if (mRetryCount < BLE_MESSAGE_RETRY_LIMIT) {
+                writeValueAndNotify(mMessageQueue.peek().toByteArray());
+                mRetryCount++;
+                mHandler.postDelayed(this, BLE_MESSAGE_RETRY_DELAY_MS);
+                return;
+            }
+
+            mHandler.removeCallbacks(this);
+            mRetryCount = 0;
+            mMessageQueue.clear();
+
+            Log.e(TAG, "Error during BLE message sending - exceeded retry limit.");
+
+            for (BleMessageStreamCallback callback : mCallbacks) {
+                callback.onWriteMessageError();
+            }
+        }
+    };
+}
diff --git a/service/src/com/android/car/trust/BlePeripheralManager.java b/service/src/com/android/car/trust/BlePeripheralManager.java
new file mode 100644
index 0000000..17528f4
--- /dev/null
+++ b/service/src/com/android/car/trust/BlePeripheralManager.java
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.trust;
+
+import static android.bluetooth.BluetoothProfile.GATT_SERVER;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCallback;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
+import android.bluetooth.BluetoothGattServer;
+import android.bluetooth.BluetoothGattServerCallback;
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.le.AdvertiseCallback;
+import android.bluetooth.le.AdvertiseData;
+import android.bluetooth.le.AdvertiseSettings;
+import android.bluetooth.le.BluetoothLeAdvertiser;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.util.Log;
+
+import com.android.car.Utils;
+
+import java.util.UUID;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * A generic class that manages BLE peripheral operations like start/stop advertising, notifying
+ * connects/disconnects and reading/writing values to GATT characteristics.
+ *
+ * @deprecated Enrolling a trusted device through car service is no longer a supported feature and
+ * these APIs will be removed in the next Android release.
+ */
+@Deprecated
+public class BlePeripheralManager {
+    private static final String TAG = BlePeripheralManager.class.getSimpleName();
+
+    private static final int BLE_RETRY_LIMIT = 5;
+    private static final int BLE_RETRY_INTERVAL_MS = 1000;
+
+    private static final int GATT_SERVER_RETRY_LIMIT = 20;
+    private static final int GATT_SERVER_RETRY_DELAY_MS = 200;
+
+    // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth
+    // .service.generic_access.xml
+    private static final UUID GENERIC_ACCESS_PROFILE_UUID =
+            UUID.fromString("00001800-0000-1000-8000-00805f9b34fb");
+    //https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth
+    // .characteristic.gap.device_name.xml
+    private static final UUID DEVICE_NAME_UUID =
+            UUID.fromString("00002a00-0000-1000-8000-00805f9b34fb");
+
+    private final Handler mHandler = new Handler();
+
+    private final Context mContext;
+    private final CopyOnWriteArrayList<Callback> mCallbacks = new CopyOnWriteArrayList<>();
+    private final CopyOnWriteArrayList<OnCharacteristicWriteListener> mWriteListeners =
+            new CopyOnWriteArrayList<>();
+    private final CopyOnWriteArrayList<OnCharacteristicReadListener> mReadListeners =
+            new CopyOnWriteArrayList<>();
+
+    private int mMtuSize = 20;
+
+    private BluetoothManager mBluetoothManager;
+    private BluetoothLeAdvertiser mAdvertiser;
+    private BluetoothGattServer mGattServer;
+    private BluetoothGatt mBluetoothGatt;
+    private int mAdvertiserStartCount;
+    private int mGattServerRetryStartCount;
+    private BluetoothGattService mBluetoothGattService;
+    private AdvertiseCallback mAdvertiseCallback;
+    private AdvertiseData mAdvertiseData;
+
+
+    BlePeripheralManager(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Registers the given callback to be notified of various events within the
+     * {@link BlePeripheralManager}.
+     *
+     * @param callback The callback to be notified.
+     */
+    void registerCallback(@NonNull Callback callback) {
+        mCallbacks.add(callback);
+    }
+
+    /**
+     * Unregisters a previously registered callback.
+     *
+     * @param callback The callback to unregister.
+     */
+    void unregisterCallback(@NonNull Callback callback) {
+        mCallbacks.remove(callback);
+    }
+
+    /**
+     * Adds a listener to be notified of a write to characteristics.
+     *
+     * @param listener The listener to notify.
+     */
+    void addOnCharacteristicWriteListener(@NonNull OnCharacteristicWriteListener listener) {
+        mWriteListeners.add(listener);
+    }
+
+    /**
+     * Removes the given listener from being notified of characteristic writes.
+     *
+     * @param listener The listener to remove.
+     */
+    void removeOnCharacteristicWriteListener(@NonNull OnCharacteristicWriteListener listener) {
+        mWriteListeners.remove(listener);
+    }
+
+    /**
+     * Adds a listener to be notified of reads to characteristics.
+     *
+     * @param listener The listener to notify.
+     */
+    void addOnCharacteristicReadListener(@NonNull OnCharacteristicReadListener listener) {
+        mReadListeners.add(listener);
+    }
+
+    /**
+     * Removes the given listener from being notified of characteristic reads.
+     *
+     * @param listener The listener to remove.
+     */
+    void removeOnCharacteristicReadistener(@NonNull OnCharacteristicReadListener listener) {
+        mReadListeners.remove(listener);
+    }
+
+    /**
+     * Returns the current MTU size.
+     *
+     * @return The size of the MTU in bytes.
+     */
+    int getMtuSize() {
+        return mMtuSize;
+    }
+
+    /**
+     * Starts the GATT server with the given {@link BluetoothGattService} and begins
+     * advertising.
+     *
+     * <p>It is possible that BLE service is still in TURNING_ON state when this method is invoked.
+     * Therefore, several retries will be made to ensure advertising is started.
+     *
+     * @param service           {@link BluetoothGattService} that will be discovered by clients
+     * @param data              {@link AdvertiseData} data to advertise
+     * @param advertiseCallback {@link AdvertiseCallback} callback for advertiser
+     */
+    void startAdvertising(BluetoothGattService service, AdvertiseData data,
+            AdvertiseCallback advertiseCallback) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "startAdvertising: " + service.getUuid().toString());
+        }
+        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
+            Log.e(TAG, "Attempted start advertising, but system does not support BLE. "
+                    + "Ignoring");
+            return;
+        }
+
+        mBluetoothGattService = service;
+        mAdvertiseCallback = advertiseCallback;
+        mAdvertiseData = data;
+        mGattServerRetryStartCount = 0;
+        mBluetoothManager = (BluetoothManager) mContext.getSystemService(
+                Context.BLUETOOTH_SERVICE);
+        openGattServer();
+    }
+
+    /**
+     * Stops the GATT server from advertising.
+     *
+     * @param advertiseCallback The callback that is associated with the advertisement.
+     */
+    void stopAdvertising(AdvertiseCallback advertiseCallback) {
+        if (mAdvertiser != null) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "stopAdvertising: ");
+            }
+            mAdvertiser.stopAdvertising(advertiseCallback);
+        }
+    }
+
+    /**
+     * Notifies the characteristic change via {@link BluetoothGattServer}
+     */
+    void notifyCharacteristicChanged(@NonNull BluetoothDevice device,
+            @NonNull BluetoothGattCharacteristic characteristic, boolean confirm) {
+        if (mGattServer == null) {
+            return;
+        }
+
+        boolean result = mGattServer.notifyCharacteristicChanged(device, characteristic, confirm);
+
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "notifyCharacteristicChanged succeeded: " + result);
+        }
+    }
+
+    /**
+     * Connect the Gatt server of the remote device to retrieve device name.
+     */
+    final void retrieveDeviceName(BluetoothDevice device) {
+        mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback);
+    }
+
+    /**
+     * Returns the currently opened GATT server within this manager.
+     *
+     * @return An opened GATT server or {@code null} if none have been opened.
+     */
+    @Nullable
+    BluetoothGattServer getGattServer() {
+        return mGattServer;
+    }
+
+    /**
+     * Cleans up the BLE GATT server state.
+     */
+    void cleanup() {
+        // Stops the advertiser, scanner and GATT server. This needs to be done to avoid leaks.
+        if (mAdvertiser != null) {
+            mAdvertiser.cleanup();
+        }
+
+        if (mGattServer != null) {
+            mGattServer.clearServices();
+            try {
+                for (BluetoothDevice d : mBluetoothManager.getConnectedDevices(GATT_SERVER)) {
+                    mGattServer.cancelConnection(d);
+                }
+            } catch (UnsupportedOperationException e) {
+                Log.e(TAG, "Error getting connected devices", e);
+            } finally {
+                stopGattServer();
+            }
+        }
+    }
+
+    /**
+     * Close the GATT Server
+     */
+    void stopGattServer() {
+        if (mGattServer == null) {
+            return;
+        }
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "stopGattServer");
+        }
+        if (mBluetoothGatt != null) {
+            mBluetoothGatt.disconnect();
+        }
+        mGattServer.close();
+        mGattServer = null;
+    }
+
+    private void openGattServer() {
+        // Only open one Gatt server.
+        if (mGattServer != null) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "Gatt Server created, retry count: " + mGattServerRetryStartCount);
+            }
+            mGattServer.clearServices();
+            mGattServer.addService(mBluetoothGattService);
+            AdvertiseSettings settings = new AdvertiseSettings.Builder()
+                    .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
+                    .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
+                    .setConnectable(true)
+                    .build();
+            mAdvertiserStartCount = 0;
+            startAdvertisingInternally(settings, mAdvertiseData, mAdvertiseCallback);
+            mGattServerRetryStartCount = 0;
+        } else if (mGattServerRetryStartCount < GATT_SERVER_RETRY_LIMIT) {
+            mGattServer = mBluetoothManager.openGattServer(mContext, mGattServerCallback);
+            mGattServerRetryStartCount++;
+            mHandler.postDelayed(() -> openGattServer(), GATT_SERVER_RETRY_DELAY_MS);
+        } else {
+            Log.e(TAG, "Gatt server not created - exceeded retry limit.");
+        }
+    }
+
+    private void startAdvertisingInternally(AdvertiseSettings settings, AdvertiseData data,
+            AdvertiseCallback advertiseCallback) {
+        if (BluetoothAdapter.getDefaultAdapter() != null) {
+            mAdvertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
+        }
+
+        if (mAdvertiser != null) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "Advertiser created, retry count: " + mAdvertiserStartCount);
+            }
+            mAdvertiser.startAdvertising(settings, data, advertiseCallback);
+            mAdvertiserStartCount = 0;
+        } else if (mAdvertiserStartCount < BLE_RETRY_LIMIT) {
+            mHandler.postDelayed(
+                    () -> startAdvertisingInternally(settings, data, advertiseCallback),
+                    BLE_RETRY_INTERVAL_MS);
+            mAdvertiserStartCount += 1;
+        } else {
+            Log.e(TAG, "Cannot start BLE Advertisement.  BT Adapter: "
+                    + BluetoothAdapter.getDefaultAdapter() + " Advertise Retry count: "
+                    + mAdvertiserStartCount);
+        }
+    }
+
+    private final BluetoothGattServerCallback mGattServerCallback =
+            new BluetoothGattServerCallback() {
+                @Override
+                public void onConnectionStateChange(BluetoothDevice device, int status,
+                        int newState) {
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        Log.d(TAG, "BLE Connection State Change: " + newState);
+                    }
+                    switch (newState) {
+                        case BluetoothProfile.STATE_CONNECTED:
+                            for (Callback callback : mCallbacks) {
+                                callback.onRemoteDeviceConnected(device);
+                            }
+                            break;
+                        case BluetoothProfile.STATE_DISCONNECTED:
+                            for (Callback callback : mCallbacks) {
+                                callback.onRemoteDeviceDisconnected(device);
+                            }
+                            break;
+                        default:
+                            Log.w(TAG,
+                                    "Connection state not connecting or disconnecting; ignoring: "
+                                            + newState);
+                    }
+                }
+
+                @Override
+                public void onServiceAdded(int status, BluetoothGattService service) {
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        Log.d(TAG,
+                                "Service added status: " + status + " uuid: " + service.getUuid());
+                    }
+                }
+
+                @Override
+                public void onCharacteristicReadRequest(BluetoothDevice device, int requestId,
+                        int offset, BluetoothGattCharacteristic characteristic) {
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        Log.d(TAG, "Read request for characteristic: " + characteristic.getUuid());
+                    }
+
+                    boolean isSuccessful = mGattServer.sendResponse(device, requestId,
+                            BluetoothGatt.GATT_SUCCESS, offset, characteristic.getValue());
+
+                    if (isSuccessful) {
+                        for (OnCharacteristicReadListener listener : mReadListeners) {
+                            listener.onCharacteristicRead(device, characteristic);
+                        }
+                    } else {
+                        stopGattServer();
+                        for (Callback callback : mCallbacks) {
+                            callback.onRemoteDeviceDisconnected(device);
+                        }
+                    }
+                }
+
+                @Override
+                public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,
+                        BluetoothGattCharacteristic characteristic, boolean preparedWrite,
+                        boolean responseNeeded, int offset, byte[] value) {
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        Log.d(TAG, "Write request for characteristic: " + characteristic.getUuid()
+                                + "value: " + Utils.byteArrayToHexString(value));
+                    }
+
+                    mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS,
+                            offset, value);
+
+                    for (OnCharacteristicWriteListener listener : mWriteListeners) {
+                        listener.onCharacteristicWrite(device, characteristic, value);
+                    }
+                }
+
+                @Override
+                public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
+                        BluetoothGattDescriptor descriptor, boolean preparedWrite,
+                        boolean responseNeeded, int offset, byte[] value) {
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        Log.d(TAG, "Write request for descriptor: " + descriptor.getUuid()
+                                + "; value: " + Utils.byteArrayToHexString(value));
+                    }
+
+                    mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS,
+                            offset, value);
+                }
+
+                @Override
+                public void onMtuChanged(BluetoothDevice device, int mtu) {
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        Log.d(TAG, "onMtuChanged: " + mtu + " for device " + device.getAddress());
+                    }
+
+                    mMtuSize = mtu;
+
+                    for (Callback callback : mCallbacks) {
+                        callback.onMtuSizeChanged(mtu);
+                    }
+                }
+
+            };
+
+    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
+        @Override
+        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "Gatt Connection State Change: " + newState);
+            }
+            switch (newState) {
+                case BluetoothProfile.STATE_CONNECTED:
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        Log.d(TAG, "Gatt connected");
+                    }
+                    mBluetoothGatt.discoverServices();
+                    break;
+                case BluetoothProfile.STATE_DISCONNECTED:
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        Log.d(TAG, "Gatt Disconnected");
+                    }
+                    break;
+                default:
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        Log.d(TAG,
+                                "Connection state not connecting or disconnecting; ignoring: "
+                                        + newState);
+                    }
+            }
+        }
+
+        @Override
+        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "Gatt Services Discovered");
+            }
+            BluetoothGattService gapService = mBluetoothGatt.getService(
+                    GENERIC_ACCESS_PROFILE_UUID);
+            if (gapService == null) {
+                Log.e(TAG, "Generic Access Service is Null");
+                return;
+            }
+            BluetoothGattCharacteristic deviceNameCharacteristic = gapService.getCharacteristic(
+                    DEVICE_NAME_UUID);
+            if (deviceNameCharacteristic == null) {
+                Log.e(TAG, "Device Name Characteristic is Null");
+                return;
+            }
+            mBluetoothGatt.readCharacteristic(deviceNameCharacteristic);
+        }
+
+        @Override
+        public void onCharacteristicRead(BluetoothGatt gatt,
+                BluetoothGattCharacteristic characteristic, int status) {
+            if (status == BluetoothGatt.GATT_SUCCESS) {
+                String deviceName = characteristic.getStringValue(0);
+                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                    Log.d(TAG, "BLE Device Name: " + deviceName);
+                }
+
+                for (Callback callback : mCallbacks) {
+                    callback.onDeviceNameRetrieved(deviceName);
+                }
+            } else {
+                Log.e(TAG, "Reading GAP Failed: " + status);
+            }
+        }
+    };
+
+    /**
+     * Interface to be notified of various events within the {@link BlePeripheralManager}.
+     */
+    interface Callback {
+         /**
+         * Triggered when the name of the remote device is retrieved.
+         *
+         * @param deviceName Name of the remote device.
+         */
+        void onDeviceNameRetrieved(@Nullable String deviceName);
+
+        /**
+         * Triggered if a remote client has requested to change the MTU for a given connection.
+         *
+         * @param size The new MTU size.
+         */
+        void onMtuSizeChanged(int size);
+
+        /**
+         * Triggered when a device (GATT client) connected.
+         *
+         * @param device Remote device that connected on BLE.
+         */
+        void onRemoteDeviceConnected(@NonNull BluetoothDevice device);
+
+        /**
+         * Triggered when a device (GATT client) disconnected.
+         *
+         * @param device Remote device that disconnected on BLE.
+         */
+        void onRemoteDeviceDisconnected(@NonNull BluetoothDevice device);
+    }
+
+    /**
+     * An interface for classes that wish to be notified of writes to a characteristic.
+     */
+    interface OnCharacteristicWriteListener {
+        /**
+         * Triggered when this BlePeripheralManager receives a write request from a remote device.
+         *
+         * @param device The bluetooth device that holds the characteristic.
+         * @param characteristic The characteristic that was written to.
+         * @param value The value that was written.
+         */
+        void onCharacteristicWrite(
+                @NonNull BluetoothDevice device,
+                @NonNull BluetoothGattCharacteristic characteristic,
+                @NonNull byte[] value);
+    }
+
+    /**
+     * An interface for classes that wish to be notified of reads on a characteristic.
+     */
+    interface OnCharacteristicReadListener {
+        /**
+         * Triggered when this BlePeripheralManager receives a read request from a remote device.
+         *
+         * @param device The bluetooth device that holds the characteristic.
+         * @param characteristic The characteristic that was read from.
+         */
+        void onCharacteristicRead(
+                @NonNull BluetoothDevice device,
+                @NonNull BluetoothGattCharacteristic characteristic);
+    }
+}
diff --git a/service/src/com/android/car/trust/CarBleTrustAgent.java b/service/src/com/android/car/trust/CarBleTrustAgent.java
index 5c6115e..7489b13 100644
--- a/service/src/com/android/car/trust/CarBleTrustAgent.java
+++ b/service/src/com/android/car/trust/CarBleTrustAgent.java
@@ -48,7 +48,11 @@
  * The system {@link com.android.server.trust.TrustManagerService} binds to this agent and uses
  * the data it receives from this agent to authorize a user in lieu of the PIN/Pattern/Password
  * credentials.
+ *
+ * @deprecated Enrolling a trusted device through car service is no longer supported and these APIs
+ * will be removed in the next Android release.
  */
+@Deprecated
 public class CarBleTrustAgent extends TrustAgentService {
     private static final String TAG = CarBleTrustAgent.class.getSimpleName();
     private boolean mIsDeviceLocked;
@@ -240,7 +244,7 @@
 
     private void onBluetoothStateChanged(int state) {
         if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "onBluetoothStateChanged: " + state);
+            Log.d(TAG, "onBluetoothStateChanged: " + BluetoothAdapter.nameForState(state));
         }
         if (!mIsDeviceLocked) {
             return;
diff --git a/service/src/com/android/car/trust/CarCompanionDeviceStorage.java b/service/src/com/android/car/trust/CarCompanionDeviceStorage.java
new file mode 100644
index 0000000..47edebb
--- /dev/null
+++ b/service/src/com/android/car/trust/CarCompanionDeviceStorage.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.trust;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.util.Base64;
+import android.util.Log;
+
+import com.android.car.R;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.util.UUID;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.GCMParameterSpec;
+
+/**
+ * Storage for Trusted Devices in a car.
+ */
+class CarCompanionDeviceStorage {
+    private static final String TAG = CarCompanionDeviceStorage.class.getSimpleName();
+
+    private static final String UNIQUE_ID_KEY = "CTABM_unique_id";
+    private static final String PREF_ENCRYPTION_KEY_PREFIX = "CTABM_encryption_key";
+    private static final String KEY_ALIAS = "Ukey2Key";
+    private static final String CIPHER_TRANSFORMATION = "AES/GCM/NoPadding";
+    private static final String KEYSTORE_PROVIDER = "AndroidKeyStore";
+    private static final String IV_SPEC_SEPARATOR = ";";
+
+    // The length of the authentication tag for a cipher in GCM mode. The GCM specification states
+    // that this length can only have the values {128, 120, 112, 104, 96}. Using the highest
+    // possible value.
+    private static final int GCM_AUTHENTICATION_TAG_LENGTH = 128;
+
+    private Context mContext;
+    private SharedPreferences mSharedPreferences;
+    private UUID mUniqueId;
+
+    CarCompanionDeviceStorage(@NonNull Context context) {
+        mContext = context;
+    }
+
+    /** Return the car TrustedAgent {@link SharedPreferences}. */
+    @NonNull
+    SharedPreferences getSharedPrefs() {
+        // This should be called only after user 0 is unlocked.
+        if (mSharedPreferences != null) {
+            return mSharedPreferences;
+        }
+        mSharedPreferences = mContext.getSharedPreferences(
+                mContext.getString(R.string.token_handle_shared_preferences), Context.MODE_PRIVATE);
+        return mSharedPreferences;
+    }
+
+    /**
+     * Returns User Id for the given token handle
+     *
+     * @param handle The handle corresponding to the escrow token
+     * @return User id corresponding to the handle
+     */
+    int getUserHandleByTokenHandle(long handle) {
+        return getSharedPrefs().getInt(String.valueOf(handle), -1);
+    }
+
+    /**
+     * Get communication encryption key for the given device
+     *
+     * @param deviceId id of trusted device
+     * @return encryption key, null if device id is not recognized
+     */
+    @Nullable
+    byte[] getEncryptionKey(@NonNull String deviceId) {
+        SharedPreferences prefs = getSharedPrefs();
+        String key = createSharedPrefKey(deviceId);
+        if (!prefs.contains(key)) {
+            return null;
+        }
+
+        // This value will not be "null" because we already checked via a call to contains().
+        String[] values = prefs.getString(key, null).split(IV_SPEC_SEPARATOR);
+
+        if (values.length != 2) {
+            return null;
+        }
+
+        byte[] encryptedKey = Base64.decode(values[0], Base64.DEFAULT);
+        byte[] ivSpec = Base64.decode(values[1], Base64.DEFAULT);
+        return decryptWithKeyStore(KEY_ALIAS, encryptedKey, ivSpec);
+    }
+
+    /**
+     * Save encryption key for the given device
+     *
+     * @param deviceId did of trusted device
+     * @param encryptionKey encryption key
+     * @return {@code true} if the operation succeeded
+     */
+    boolean saveEncryptionKey(@NonNull String deviceId, @NonNull byte[] encryptionKey) {
+        String encryptedKey = encryptWithKeyStore(KEY_ALIAS, encryptionKey);
+        if (encryptedKey == null) {
+            return false;
+        }
+        if (getSharedPrefs().contains(createSharedPrefKey(deviceId))) {
+            clearEncryptionKey(deviceId);
+        }
+
+        return getSharedPrefs()
+                .edit()
+                .putString(createSharedPrefKey(deviceId), encryptedKey)
+                .commit();
+    }
+
+    /**
+     * Clear the encryption key for the given device
+     *
+     * @param deviceId id of the peer device
+     */
+    void clearEncryptionKey(@Nullable String deviceId) {
+        if (deviceId == null) {
+            return;
+        }
+        getSharedPrefs()
+                .edit()
+                .remove(createSharedPrefKey(deviceId))
+                .commit();
+    }
+
+    /**
+     * Encrypt value with designated key
+     *
+     * <p>The encrypted value is of the form:
+     *
+     * <p>key + IV_SPEC_SEPARATOR + ivSpec
+     *
+     * <p>The {@code ivSpec} is needed to decrypt this key later on.
+     *
+     * @param keyAlias KeyStore alias for key to use
+     * @param value a value to encrypt
+     * @return encrypted value, null if unable to encrypt
+     */
+    @Nullable
+    String encryptWithKeyStore(@NonNull String keyAlias, @Nullable byte[] value) {
+        if (value == null) {
+            return null;
+        }
+
+        Key key = getKeyStoreKey(keyAlias);
+        try {
+            Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
+            cipher.init(Cipher.ENCRYPT_MODE, key);
+            return new StringBuffer(Base64.encodeToString(cipher.doFinal(value), Base64.DEFAULT))
+                    .append(IV_SPEC_SEPARATOR)
+                    .append(Base64.encodeToString(cipher.getIV(), Base64.DEFAULT))
+                    .toString();
+        } catch (IllegalBlockSizeException
+                | BadPaddingException
+                | NoSuchAlgorithmException
+                | NoSuchPaddingException
+                | IllegalStateException
+                | InvalidKeyException e) {
+            Log.e(TAG, "Unable to encrypt value with key " + keyAlias, e);
+            return null;
+        }
+    }
+
+    /**
+     * Decrypt value with designated key
+     *
+     * @param keyAlias KeyStore alias for key to use
+     * @param value encrypted value
+     * @return decrypted value, null if unable to decrypt
+     */
+    @Nullable
+    byte[] decryptWithKeyStore(@NonNull String keyAlias, @Nullable byte[] value,
+            @NonNull byte[] ivSpec) {
+        if (value == null) {
+            return null;
+        }
+
+        try {
+            Key key = getKeyStoreKey(keyAlias);
+            Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
+            cipher.init(Cipher.DECRYPT_MODE, key,
+                    new GCMParameterSpec(GCM_AUTHENTICATION_TAG_LENGTH, ivSpec));
+            return cipher.doFinal(value);
+        } catch (IllegalBlockSizeException
+                | BadPaddingException
+                | NoSuchAlgorithmException
+                | NoSuchPaddingException
+                | IllegalStateException
+                | InvalidKeyException
+                | InvalidAlgorithmParameterException e) {
+            Log.e(TAG, "Unable to decrypt value with key " + keyAlias, e);
+            return null;
+        }
+    }
+
+    private Key getKeyStoreKey(@NonNull String keyAlias) {
+        KeyStore keyStore;
+        try {
+            keyStore = KeyStore.getInstance(KEYSTORE_PROVIDER);
+            keyStore.load(null);
+            if (!keyStore.containsAlias(keyAlias)) {
+                KeyGenerator keyGenerator = KeyGenerator.getInstance(
+                        KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_PROVIDER);
+                keyGenerator.init(
+                        new KeyGenParameterSpec.Builder(keyAlias,
+                                KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+                                .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+                                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                                .build());
+                keyGenerator.generateKey();
+            }
+            return keyStore.getKey(keyAlias, null);
+
+        } catch (KeyStoreException
+                | NoSuchAlgorithmException
+                | UnrecoverableKeyException
+                | NoSuchProviderException
+                | CertificateException
+                | IOException
+                | InvalidAlgorithmParameterException e) {
+            Log.e(TAG, "Unable to retrieve key " + keyAlias + " from KeyStore.", e);
+            throw new IllegalStateException(e);
+        }
+    }
+
+    /**
+     * Get the unique id for head unit. Persists on device until factory reset.
+     * This should be called only after user 0 is unlocked.
+     *
+     * @return unique id, or null if unable to retrieve generated id (this should never happen)
+     */
+    @Nullable
+    UUID getUniqueId() {
+        if (mUniqueId != null) {
+            return mUniqueId;
+        }
+
+        SharedPreferences prefs = getSharedPrefs();
+        if (prefs.contains(UNIQUE_ID_KEY)) {
+            mUniqueId = UUID.fromString(
+                    prefs.getString(UNIQUE_ID_KEY, null));
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "Found existing trusted unique id: "
+                        + prefs.getString(UNIQUE_ID_KEY, ""));
+            }
+        } else {
+            mUniqueId = UUID.randomUUID();
+            if (!prefs.edit().putString(UNIQUE_ID_KEY, mUniqueId.toString()).commit()) {
+                mUniqueId = null;
+            } else if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "Generated new trusted unique id: "
+                        + prefs.getString(UNIQUE_ID_KEY, ""));
+            }
+        }
+
+        return mUniqueId;
+    }
+
+    private String createSharedPrefKey(@NonNull String deviceId) {
+        return PREF_ENCRYPTION_KEY_PREFIX + deviceId;
+    }
+}
diff --git a/service/src/com/android/car/trust/CarTrustAgentBleManager.java b/service/src/com/android/car/trust/CarTrustAgentBleManager.java
index 1e43300..b1fedd0 100644
--- a/service/src/com/android/car/trust/CarTrustAgentBleManager.java
+++ b/service/src/com/android/car/trust/CarTrustAgentBleManager.java
@@ -17,6 +17,7 @@
 package com.android.car.trust;
 
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothGattCharacteristic;
@@ -27,36 +28,33 @@
 import android.bluetooth.le.AdvertiseSettings;
 import android.content.Context;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.ParcelUuid;
 import android.util.Log;
 
-import androidx.annotation.Nullable;
+import androidx.collection.SimpleArrayMap;
 
-import com.android.car.BLEStreamProtos.BLEMessageProto.BLEMessage;
 import com.android.car.BLEStreamProtos.BLEOperationProto.OperationType;
 import com.android.car.BLEStreamProtos.VersionExchangeProto.BLEVersionExchange;
-import com.android.car.CarLocalServices;
 import com.android.car.R;
 import com.android.car.Utils;
 import com.android.car.protobuf.InvalidProtocolBufferException;
+import com.android.internal.annotations.VisibleForTesting;
 
-import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.LinkedList;
+import java.util.ArrayList;
 import java.util.List;
-import java.util.Queue;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 
 /**
  * A BLE Service that is used for communicating with the trusted peer device. This extends from a
- * more generic {@link BleManager} and has more context on the BLE requirements for the Trusted
- * device feature. It has knowledge on the GATT services and characteristics that are specific to
- * the Trusted Device feature.
+ * more generic {@link BlePeripheralManager} and has more context on the BLE requirements for the
+ * Trusted device feature. It has knowledge on the GATT services and characteristics that are
+ * specific to the Trusted Device feature.
  */
-class CarTrustAgentBleManager extends BleManager {
+class CarTrustAgentBleManager implements BleMessageStreamCallback, BlePeripheralManager.Callback,
+        BlePeripheralManager.OnCharacteristicWriteListener {
     private static final String TAG = "CarTrustBLEManager";
 
     /**
@@ -91,17 +89,16 @@
     private static final int TRUSTED_DEVICE_OPERATION_NONE = 0;
     private static final int TRUSTED_DEVICE_OPERATION_ENROLLMENT = 1;
     private static final int TRUSTED_DEVICE_OPERATION_UNLOCK = 2;
-    private static final long BLE_MESSAGE_RETRY_DELAY_MS = TimeUnit.SECONDS.toMillis(2);
-    private static final int BLE_MESSAGE_RETRY_LIMIT = 20;
+    @VisibleForTesting
+    static final long BLE_MESSAGE_RETRY_DELAY_MS = TimeUnit.SECONDS.toMillis(2);
+
+    private final Context mContext;
+    private final BlePeripheralManager mBlePeripheralManager;
 
     @TrustedDeviceOperation
     private int mCurrentTrustedDeviceOperation = TRUSTED_DEVICE_OPERATION_NONE;
-    private CarTrustedDeviceService mCarTrustedDeviceService;
-    private CarTrustAgentEnrollmentService mCarTrustAgentEnrollmentService;
-    private CarTrustAgentUnlockService mCarTrustAgentUnlockService;
     private String mOriginalBluetoothName;
     private byte[] mUniqueId;
-    private String mEnrollmentDeviceName;
 
     /**
      * The maximum amount of bytes that can be written over BLE.
@@ -113,6 +110,13 @@
      */
     private int mMaxWriteSize = 20;
 
+    @VisibleForTesting
+    int mBleMessageRetryLimit = 20;
+
+    private final List<BleEventCallback> mBleEventCallbacks = new ArrayList<>();
+    private AdvertiseCallback mEnrollmentAdvertisingCallback;
+    private SendMessageCallback mSendMessageCallback;
+
     // Enrollment Service and Characteristic UUIDs
     private UUID mEnrollmentServiceUuid;
     private UUID mEnrollmentClientWriteUuid;
@@ -125,23 +129,40 @@
     private UUID mUnlockServerWriteUuid;
     private BluetoothGattService mUnlockGattService;
 
-    private Queue<BLEMessage> mMessageQueue = new LinkedList<>();
-    private BLEMessagePayloadStream mBleMessagePayloadStream = new BLEMessagePayloadStream();
+    @Nullable
+    private BleMessageStream mMessageStream;
+    private final Handler mHandler = new Handler();
 
-    // This is a boolean because there's only one supported version.
-    private boolean mIsVersionExchanged;
-    private int mBleMessageRetryStartCount;
-    private Handler mHandler = new Handler(Looper.getMainLooper());
-    private Runnable mSendRepeatedBleMessage;
+    // A map of enrollment/unlock client write uuid -> listener
+    private final SimpleArrayMap<UUID, DataReceivedListener> mDataReceivedListeners =
+            new SimpleArrayMap<>();
 
-    CarTrustAgentBleManager(Context context) {
-        super(context);
+    CarTrustAgentBleManager(Context context, BlePeripheralManager blePeripheralManager) {
+        mContext = context;
+        mBlePeripheralManager = blePeripheralManager;
+        mBlePeripheralManager.registerCallback(this);
+    }
+
+    /**
+     * This should be called before starting unlock advertising
+     */
+    void setUniqueId(UUID uniqueId) {
+        mUniqueId = Utils.uuidToBytes(uniqueId);
+    }
+
+    void cleanup() {
+        mBlePeripheralManager.cleanup();
+    }
+
+    void stopGattServer() {
+        mBlePeripheralManager.stopGattServer();
     }
 
     // Overriding some of the {@link BLEManager} methods to be specific for Trusted Device feature.
     @Override
     public void onRemoteDeviceConnected(BluetoothDevice device) {
-        if (getTrustedDeviceService() == null) {
+        if (mBleEventCallbacks.isEmpty()) {
+            Log.e(TAG, "No valid BleEventCallback for trust device.");
             return;
         }
 
@@ -149,45 +170,49 @@
         // stored in sharedPreference for further use.
         if (mCurrentTrustedDeviceOperation == TRUSTED_DEVICE_OPERATION_ENROLLMENT
                 && device.getName() == null) {
-            retrieveDeviceName(device);
+            mBlePeripheralManager.retrieveDeviceName(device);
         }
 
-        mMessageQueue.clear();
-        mIsVersionExchanged = false;
-        getTrustedDeviceService().onRemoteDeviceConnected(device);
-        if (mSendRepeatedBleMessage != null) {
-            mHandler.removeCallbacks(mSendRepeatedBleMessage);
-            mSendRepeatedBleMessage = null;
+        if (mMessageStream != null) {
+            mMessageStream.unregisterCallback(this);
+            mMessageStream = null;
         }
+
+        mSendMessageCallback = null;
+
+        mBlePeripheralManager.addOnCharacteristicWriteListener(this);
+        mBleEventCallbacks.forEach(bleEventCallback ->
+                bleEventCallback.onRemoteDeviceConnected(device));
     }
 
     @Override
     public void onRemoteDeviceDisconnected(BluetoothDevice device) {
-        if (getTrustedDeviceService() != null) {
-            getTrustedDeviceService().onRemoteDeviceDisconnected(device);
+        mBlePeripheralManager.removeOnCharacteristicWriteListener(this);
+        mBleEventCallbacks.forEach(bleEventCallback ->
+                bleEventCallback.onRemoteDeviceDisconnected(device));
+
+        if (mMessageStream != null) {
+            mMessageStream.unregisterCallback(this);
+            mMessageStream = null;
         }
 
-        mMessageQueue.clear();
-        mIsVersionExchanged = false;
-        mBleMessagePayloadStream.reset();
-
-        if (mSendRepeatedBleMessage != null) {
-            mHandler.removeCallbacks(mSendRepeatedBleMessage);
-        }
-        mSendRepeatedBleMessage = null;
+        mSendMessageCallback = null;
     }
 
     @Override
-    protected void onDeviceNameRetrieved(@Nullable String deviceName) {
-        if (getTrustedDeviceService() != null) {
-            getTrustedDeviceService().onDeviceNameRetrieved(deviceName);
-        }
+    public void onDeviceNameRetrieved(@Nullable String deviceName) {
+        mBleEventCallbacks.forEach(bleEventCallback ->
+                bleEventCallback.onClientDeviceNameRetrieved(deviceName));
     }
 
     @Override
-    protected void onMtuSizeChanged(int size) {
+    public void onMtuSizeChanged(int size) {
         mMaxWriteSize = size - ATT_PAYLOAD_RESERVED_BYTES;
 
+        if (mMessageStream != null) {
+            mMessageStream.setMaxWriteSize(mMaxWriteSize);
+        }
+
         if (Log.isLoggable(TAG, Log.DEBUG)) {
             Log.d(TAG, "MTU size changed to: " + size
                     + "; setting max payload size to: " + mMaxWriteSize);
@@ -195,136 +220,52 @@
     }
 
     @Override
-    public void onCharacteristicWrite(BluetoothDevice device, int requestId,
-            BluetoothGattCharacteristic characteristic, boolean preparedWrite,
-            boolean responseNeeded, int offset, byte[] value) {
+    public void onCharacteristicWrite(BluetoothDevice device,
+            BluetoothGattCharacteristic characteristic, byte[] value) {
         UUID uuid = characteristic.getUuid();
         if (Log.isLoggable(TAG, Log.DEBUG)) {
             Log.d(TAG, "onCharacteristicWrite received uuid: " + uuid);
         }
 
-        if (!mIsVersionExchanged) {
+        if (mMessageStream == null) {
             resolveBLEVersion(device, value, uuid);
             return;
         }
 
-        BLEMessage message;
-        try {
-            message = BLEMessage.parseFrom(value);
-        } catch (InvalidProtocolBufferException e) {
-            Log.e(TAG, "Can not parse BLE message", e);
-            return;
-        }
-
-        if (message.getOperation() == OperationType.ACK) {
-            handleClientAckMessage(device, uuid);
-            return;
-        }
-
-        // This write operation is not thread safe individually, but is guarded by the callback
-        // here.
-        try {
-            mBleMessagePayloadStream.write(message);
-        } catch (IOException e) {
-            Log.e(TAG, "Can write the BLE message's payload", e);
-            return;
-        }
-
-        if (!mBleMessagePayloadStream.isComplete()) {
-            // If it's not complete, make sure the client knows that this message was received.
-            sendAcknowledgmentMessage(device, uuid);
-            return;
-        }
-
-        if (uuid.equals(mEnrollmentClientWriteUuid)) {
-            if (getEnrollmentService() != null) {
-                getEnrollmentService().onEnrollmentDataReceived(
-                        mBleMessagePayloadStream.toByteArray());
-            }
-        } else if (uuid.equals(mUnlockClientWriteUuid)) {
-            if (getUnlockService() != null) {
-                getUnlockService().onUnlockDataReceived(mBleMessagePayloadStream.toByteArray());
-            }
-        }
-
-        mBleMessagePayloadStream.reset();
+        Log.e(TAG, "Received a message but message stream has already been created. "
+                + "Was this manager not unregistered as a listener for writes?");
     }
 
-    @Override
-    public void onCharacteristicRead(BluetoothDevice device, int requestId, int offset,
-            final BluetoothGattCharacteristic characteristic) {
-        // Ignored read requests.
-    }
-
-    @Nullable
-    private CarTrustedDeviceService getTrustedDeviceService() {
-        if (mCarTrustedDeviceService == null) {
-            mCarTrustedDeviceService = CarLocalServices.getService(CarTrustedDeviceService.class);
-        }
-        return mCarTrustedDeviceService;
-    }
-
-    @Nullable
-    private CarTrustAgentEnrollmentService getEnrollmentService() {
-        if (mCarTrustAgentEnrollmentService != null) {
-            return mCarTrustAgentEnrollmentService;
-        }
-
-        if (getTrustedDeviceService() != null) {
-            mCarTrustAgentEnrollmentService =
-                    getTrustedDeviceService().getCarTrustAgentEnrollmentService();
-        }
-        return mCarTrustAgentEnrollmentService;
-    }
-
-    @Nullable
-    private CarTrustAgentUnlockService getUnlockService() {
-        if (mCarTrustAgentUnlockService != null) {
-            return mCarTrustAgentUnlockService;
-        }
-
-        if (getTrustedDeviceService() != null) {
-            mCarTrustAgentUnlockService = getTrustedDeviceService().getCarTrustAgentUnlockService();
-        }
-        return mCarTrustAgentUnlockService;
-    }
-
-    @Nullable
-    private byte[] getUniqueId() {
-        if (mUniqueId != null) {
-            return mUniqueId;
-        }
-
-        if (getTrustedDeviceService() != null && getTrustedDeviceService().getUniqueId() != null) {
-            mUniqueId = Utils.uuidToBytes(getTrustedDeviceService().getUniqueId());
-        }
-        return mUniqueId;
-    }
-
-    @Nullable
-    private String getEnrollmentDeviceName() {
-        if (mEnrollmentDeviceName != null) {
-            return mEnrollmentDeviceName;
-        }
-
-        if (getTrustedDeviceService() != null) {
-            mEnrollmentDeviceName = getTrustedDeviceService().getEnrollmentDeviceName();
-        }
-        return mEnrollmentDeviceName;
+    @VisibleForTesting
+    void setBleMessageRetryLimit(int limit) {
+        mBleMessageRetryLimit = limit;
     }
 
     private void resolveBLEVersion(BluetoothDevice device, byte[] value,
             UUID clientCharacteristicUUID) {
-        BluetoothGattCharacteristic characteristic =
+        BluetoothGattCharacteristic writeCharacteristic =
                 getCharacteristicForWrite(clientCharacteristicUUID);
 
-        if (characteristic == null) {
-            Log.e(TAG, "Invalid UUID (" + clientCharacteristicUUID
+        if (writeCharacteristic == null) {
+            Log.e(TAG, "Invalid write UUID (" + clientCharacteristicUUID
                     + ") during version exchange; disconnecting from remote device.");
             disconnectRemoteDevice();
             return;
         }
 
+        BluetoothGattCharacteristic readCharacteristic =
+                clientCharacteristicUUID.equals(mEnrollmentClientWriteUuid)
+                        ? mEnrollmentGattService.getCharacteristic(clientCharacteristicUUID)
+                        : mUnlockGattService.getCharacteristic(clientCharacteristicUUID);
+
+        // If this occurs, then there is a bug in the retrieval code above.
+        if (readCharacteristic == null) {
+            Log.e(TAG, "No read characteristic corresponding to UUID ("
+                    + clientCharacteristicUUID + "). Cannot listen for messages. Disconnecting.");
+            disconnectRemoteDevice();
+            return;
+        }
+
         BLEVersionExchange deviceVersion;
         try {
             deviceVersion = BLEVersionExchange.parseFrom(value);
@@ -334,20 +275,32 @@
             return;
         }
 
-        if (!BLEVersionExchangeResolver.hasSupportedVersion(deviceVersion)) {
-            Log.e(TAG, "No supported version found during version exchange.");
+        mMessageStream = BLEVersionExchangeResolver.resolveToStream(
+                deviceVersion, device, mBlePeripheralManager, writeCharacteristic,
+                readCharacteristic);
+        mMessageStream.setMaxWriteSize(mMaxWriteSize);
+        mMessageStream.registerCallback(this);
+
+        if (mMessageStream == null) {
+            Log.e(TAG, "No supported version found during version exchange. "
+                    +  "Could not create message stream.");
             disconnectRemoteDevice();
             return;
         }
 
+        // No need for this manager to listen for any writes; the stream will handle that from now
+        // on.
+        mBlePeripheralManager.removeOnCharacteristicWriteListener(this);
+
+        // The message stream is not used to send the IHU's version, but will be used for
+        // any subsequent messages.
         BLEVersionExchange headunitVersion = BLEVersionExchangeResolver.makeVersionExchange();
-        setValueOnCharacteristicAndNotify(device, headunitVersion.toByteArray(), characteristic);
+        setValueOnCharacteristicAndNotify(device, headunitVersion.toByteArray(),
+                writeCharacteristic);
 
         if (Log.isLoggable(TAG, Log.DEBUG)) {
             Log.d(TAG, "Sent supported version to the phone.");
         }
-
-        mIsVersionExchanged = true;
     }
 
     /**
@@ -357,11 +310,11 @@
      */
     void setupEnrollmentBleServer() {
         mEnrollmentServiceUuid = UUID.fromString(
-                getContext().getString(R.string.enrollment_service_uuid));
+                mContext.getString(R.string.enrollment_service_uuid));
         mEnrollmentClientWriteUuid = UUID.fromString(
-                getContext().getString(R.string.enrollment_client_write_uuid));
+                mContext.getString(R.string.enrollment_client_write_uuid));
         mEnrollmentServerWriteUuid = UUID.fromString(
-                getContext().getString(R.string.enrollment_server_write_uuid));
+                mContext.getString(R.string.enrollment_server_write_uuid));
 
         mEnrollmentGattService = new BluetoothGattService(mEnrollmentServiceUuid,
                 BluetoothGattService.SERVICE_TYPE_PRIMARY);
@@ -391,11 +344,11 @@
      * from the phone to the head unit.
      */
     void setupUnlockBleServer() {
-        mUnlockServiceUuid = UUID.fromString(getContext().getString(R.string.unlock_service_uuid));
+        mUnlockServiceUuid = UUID.fromString(mContext.getString(R.string.unlock_service_uuid));
         mUnlockClientWriteUuid = UUID
-                .fromString(getContext().getString(R.string.unlock_client_write_uuid));
+                .fromString(mContext.getString(R.string.unlock_client_write_uuid));
         mUnlockServerWriteUuid = UUID
-                .fromString(getContext().getString(R.string.unlock_server_write_uuid));
+                .fromString(mContext.getString(R.string.unlock_server_write_uuid));
 
         mUnlockGattService = new BluetoothGattService(mUnlockServiceUuid,
                 BluetoothGattService.SERVICE_TYPE_PRIMARY);
@@ -419,6 +372,25 @@
         mUnlockGattService.addCharacteristic(serverCharacteristic);
     }
 
+    @Override
+    public void onMessageReceivedError(UUID uuid) {
+        Log.e(TAG, "Error parsing the message from the client on UUID: " + uuid);
+    }
+
+    @Override
+    public void onMessageReceived(byte[] message, UUID uuid) {
+        if (mDataReceivedListeners.containsKey(uuid)) {
+            mDataReceivedListeners.get(uuid).onDataReceived(message);
+        }
+    }
+
+    @Override
+    public void onWriteMessageError() {
+        if (mSendMessageCallback != null) {
+            mSendMessageCallback.onSendMessageFailure();
+        }
+    }
+
     private void addDescriptorToCharacteristic(BluetoothGattCharacteristic characteristic) {
         BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(
                 CLIENT_CHARACTERISTIC_CONFIG,
@@ -427,22 +399,52 @@
         characteristic.addDescriptor(descriptor);
     }
 
-    void startEnrollmentAdvertising() {
+    /**
+     * Begins advertising for enrollment
+     *
+     * @param deviceName device name to advertise
+     * @param enrollmentAdvertisingCallback callback for advertiser
+     */
+    void startEnrollmentAdvertising(@Nullable String deviceName,
+            AdvertiseCallback enrollmentAdvertisingCallback) {
+        if (enrollmentAdvertisingCallback == null) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "Enrollment Advertising not started: "
+                        + "enrollmentAdvertisingCallback is null");
+            }
+            return;
+        }
         mCurrentTrustedDeviceOperation = TRUSTED_DEVICE_OPERATION_ENROLLMENT;
+        mEnrollmentAdvertisingCallback = enrollmentAdvertisingCallback;
         // Replace name to ensure it is small enough to be advertised
-        String name = getEnrollmentDeviceName();
-        if (name != null) {
+        if (deviceName != null) {
             BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
             if (mOriginalBluetoothName == null) {
                 mOriginalBluetoothName = adapter.getName();
             }
-            adapter.setName(name);
+            adapter.setName(deviceName);
             if (Log.isLoggable(TAG, Log.DEBUG)) {
                 Log.d(TAG, "Changing bluetooth adapter name from "
-                        + mOriginalBluetoothName + " to " + name);
+                        + mOriginalBluetoothName + " to " + deviceName);
             }
         }
-        startAdvertising(mEnrollmentGattService,
+
+        attemptAdvertising();
+    }
+
+    private void attemptAdvertising() {
+        // Validate the adapter name change has happened. If not, try again after delay.
+        if (mOriginalBluetoothName != null
+                && BluetoothAdapter.getDefaultAdapter().getName().equals(mOriginalBluetoothName)) {
+            mHandler.postDelayed(this::attemptAdvertising, BLE_MESSAGE_RETRY_DELAY_MS);
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "Adapter name change has not taken affect prior to advertising attempt. "
+                        + "Trying again.");
+            }
+            return;
+        }
+
+        mBlePeripheralManager.startAdvertising(mEnrollmentGattService,
                 new AdvertiseData.Builder()
                         .setIncludeDeviceName(true)
                         .addServiceUuid(new ParcelUuid(mEnrollmentServiceUuid))
@@ -457,16 +459,23 @@
                         + mOriginalBluetoothName);
             }
             BluetoothAdapter.getDefaultAdapter().setName(mOriginalBluetoothName);
+            mOriginalBluetoothName = null;
         }
-        stopAdvertising(mEnrollmentAdvertisingCallback);
+        if (mEnrollmentAdvertisingCallback != null) {
+            mBlePeripheralManager.stopAdvertising(mEnrollmentAdvertisingCallback);
+        }
     }
 
     void startUnlockAdvertising() {
+        if (mUniqueId == null) {
+            Log.e(TAG, "unique id is null");
+            return;
+        }
         mCurrentTrustedDeviceOperation = TRUSTED_DEVICE_OPERATION_UNLOCK;
-        startAdvertising(mUnlockGattService,
+        mBlePeripheralManager.startAdvertising(mUnlockGattService,
                 new AdvertiseData.Builder()
                         .setIncludeDeviceName(false)
-                        .addServiceData(new ParcelUuid(mUnlockServiceUuid), getUniqueId())
+                        .addServiceData(new ParcelUuid(mUnlockServiceUuid), mUniqueId)
                         .addServiceUuid(new ParcelUuid(mUnlockServiceUuid))
                         .build(),
                 mUnlockAdvertisingCallback);
@@ -474,144 +483,23 @@
 
     void stopUnlockAdvertising() {
         mCurrentTrustedDeviceOperation = TRUSTED_DEVICE_OPERATION_NONE;
-        stopAdvertising(mUnlockAdvertisingCallback);
+        mBlePeripheralManager.stopAdvertising(mUnlockAdvertisingCallback);
     }
 
     void disconnectRemoteDevice() {
-        stopGattServer();
+        mBlePeripheralManager.stopGattServer();
     }
 
-    void sendUnlockMessage(BluetoothDevice device, byte[] message, OperationType operation,
-            boolean isPayloadEncrypted) {
-        BluetoothGattCharacteristic writeCharacteristic = mUnlockGattService
-                .getCharacteristic(mUnlockServerWriteUuid);
-
-        sendMessage(device, writeCharacteristic, message, operation, isPayloadEncrypted);
-    }
-
-    void sendEnrollmentMessage(BluetoothDevice device, byte[] message, OperationType operation,
-            boolean isPayloadEncrypted) {
-        BluetoothGattCharacteristic writeCharacteristic = mEnrollmentGattService
-                .getCharacteristic(mEnrollmentServerWriteUuid);
-
-        sendMessage(device, writeCharacteristic, message, operation, isPayloadEncrypted);
-    }
-
-    /**
-     * Handles an ACK from the client.
-     *
-     * <p>An ACK means that the client has successfully received a partial BLEMessage, meaning the
-     * next part of the message can be sent.
-     *
-     * @param device                   The client device.
-     * @param clientCharacteristicUUID The UUID of the characteristic on the device that the ACK
-     *                                 was written to.
-     */
-    private void handleClientAckMessage(BluetoothDevice device, UUID clientCharacteristicUUID) {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "Received ACK from client. Attempting to write next message in queue. "
-                    + "UUID: " + clientCharacteristicUUID);
-        }
-
-        BluetoothGattCharacteristic writeCharacteristic =
-                getCharacteristicForWrite(clientCharacteristicUUID);
-
-        if (writeCharacteristic == null) {
-            Log.e(TAG, "No corresponding write characteristic found for writing next message in"
-                    + " queue. UUID: " + clientCharacteristicUUID);
-            return;
-        }
-        if (mSendRepeatedBleMessage != null) {
-            mHandler.removeCallbacks(mSendRepeatedBleMessage);
-            mSendRepeatedBleMessage = null;
-        }
-        // Previous message has been sent successfully so we can start the next message.
-        mMessageQueue.remove();
-        writeNextMessageInQueue(device, writeCharacteristic);
-    }
-
-    /**
-     * Sends the given message to the specified device and characteristic.
-     * The message will be splited into multiple messages wrapped in BLEMessage proto.
-     *
-     * @param device             The device to send the message to.
-     * @param characteristic     The characteristic to write to.
-     * @param message            A message to send.
-     * @param operation          The type of operation this message represents.
-     * @param isPayloadEncrypted {@code true} if the message is encrypted.
-     */
-    private void sendMessage(BluetoothDevice device, BluetoothGattCharacteristic characteristic,
-            byte[] message, OperationType operation, boolean isPayloadEncrypted) {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "sendMessage to: " + device.getAddress() + "; and characteristic UUID: "
-                    + characteristic.getUuid());
-        }
-
-        List<BLEMessage> bleMessages = BLEMessageV1Factory.makeBLEMessages(message, operation,
-                mMaxWriteSize, isPayloadEncrypted);
-
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "sending " + bleMessages.size() + " messages to device");
-        }
-
-        mMessageQueue.addAll(bleMessages);
-        writeNextMessageInQueue(device, characteristic);
-    }
-
-    /**
-     * Writes the next message in {@link #mMessageQueue} to the given characteristic.
-     *
-     * <p>If the message queue is empty, then this method will do nothing.
-     */
-    private void writeNextMessageInQueue(BluetoothDevice device,
-            BluetoothGattCharacteristic characteristic) {
-        if (mMessageQueue.isEmpty()) {
-            Log.e(TAG, "Call to write next message in queue, but the message queue is empty");
-            return;
-        }
-        // When there is only one message, no ACKs are sent, so we no need to retry based on ACKs.
-        if (mMessageQueue.size() == 1) {
-            setValueOnCharacteristicAndNotify(device, mMessageQueue.remove().toByteArray(),
-                    characteristic);
-            return;
-        }
-        mBleMessageRetryStartCount = 0;
-        mSendRepeatedBleMessage = new Runnable() {
-            @Override
-            public void run() {
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "BLE message sending... " + "retry count: "
-                            + mBleMessageRetryStartCount);
-                }
-                if (mBleMessageRetryStartCount < BLE_MESSAGE_RETRY_LIMIT) {
-                    setValueOnCharacteristicAndNotify(device, mMessageQueue.peek().toByteArray(),
-                            characteristic);
-                    mBleMessageRetryStartCount++;
-                    mHandler.postDelayed(this, BLE_MESSAGE_RETRY_DELAY_MS);
-                } else {
-                    Log.e(TAG, "Error during BLE message sending - exceeded retry limit.");
-                    mHandler.removeCallbacks(this);
-                    mCarTrustAgentEnrollmentService.terminateEnrollmentHandshake();
-                    mSendRepeatedBleMessage = null;
-                }
-            }
-        };
-        mHandler.post(mSendRepeatedBleMessage);
-    }
-
-    private void sendAcknowledgmentMessage(BluetoothDevice device, UUID clientCharacteristicUUID) {
-        BluetoothGattCharacteristic writeCharacteristic =
-                getCharacteristicForWrite(clientCharacteristicUUID);
-
-        if (writeCharacteristic == null) {
-            Log.e(TAG, "No corresponding write characteristic found for sending ACK. UUID: "
-                    + clientCharacteristicUUID);
+    void sendMessage(byte[] message, OperationType operation, boolean isPayloadEncrypted,
+            SendMessageCallback callback) {
+        if (mMessageStream == null) {
+            Log.e(TAG, "Request to send message, but no valid message stream.");
             return;
         }
 
-        setValueOnCharacteristicAndNotify(device,
-                BLEMessageV1Factory.makeAcknowledgementMessage().toByteArray(),
-                writeCharacteristic);
+        mSendMessageCallback = callback;
+
+        mMessageStream.writeMessage(message, operation, isPayloadEncrypted);
     }
 
     /**
@@ -627,7 +515,7 @@
     private void setValueOnCharacteristicAndNotify(BluetoothDevice device, byte[] message,
             BluetoothGattCharacteristic characteristic) {
         characteristic.setValue(message);
-        notifyCharacteristicChanged(device, characteristic, false);
+        mBlePeripheralManager.notifyCharacteristicChanged(device, characteristic, false);
     }
 
     /**
@@ -651,29 +539,6 @@
         return null;
     }
 
-    private final AdvertiseCallback mEnrollmentAdvertisingCallback = new AdvertiseCallback() {
-        @Override
-        public void onStartSuccess(AdvertiseSettings settingsInEffect) {
-            super.onStartSuccess(settingsInEffect);
-            if (getEnrollmentService() != null) {
-                getEnrollmentService().onEnrollmentAdvertiseStartSuccess();
-            }
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Successfully started advertising service");
-            }
-        }
-
-        @Override
-        public void onStartFailure(int errorCode) {
-            Log.e(TAG, "Failed to advertise, errorCode: " + errorCode);
-
-            super.onStartFailure(errorCode);
-            if (getEnrollmentService() != null) {
-                getEnrollmentService().onEnrollmentAdvertiseStartFailure();
-            }
-        }
-    };
-
     private final AdvertiseCallback mUnlockAdvertisingCallback = new AdvertiseCallback() {
         @Override
         public void onStartSuccess(AdvertiseSettings settingsInEffect) {
@@ -697,4 +562,93 @@
             startUnlockAdvertising();
         }
     };
+
+    /**
+     * Adds the given listener to be notified when the characteristic with the given uuid has
+     * received data.
+     */
+    void addDataReceivedListener(UUID uuid, DataReceivedListener listener) {
+        mDataReceivedListeners.put(uuid, listener);
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "Register DataReceivedListener: " + listener + "for uuid "
+                    + uuid.toString());
+        }
+    }
+
+    void removeDataReceivedListener(UUID uuid) {
+        if (!mDataReceivedListeners.containsKey(uuid)) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "No DataReceivedListener for uuid " + uuid.toString()
+                        + " to unregister.");
+            }
+            return;
+        }
+        mDataReceivedListeners.remove(uuid);
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "Unregister DataReceivedListener for uuid " + uuid.toString());
+        }
+    }
+
+    void addBleEventCallback(BleEventCallback callback) {
+        mBleEventCallbacks.add(callback);
+    }
+
+    void removeBleEventCallback(BleEventCallback callback) {
+        if (!mBleEventCallbacks.remove(callback)) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "Remove BleEventCallback that does not exist.");
+            }
+        }
+    }
+
+    /**
+     * Callback to be invoked for enrollment events
+     */
+    interface SendMessageCallback {
+
+        /**
+         * Called when enrollment handshake needs to be terminated
+         */
+        void onSendMessageFailure();
+    }
+
+    /**
+     * Callback to be invoked when BLE receives data from remote device.
+     */
+    interface DataReceivedListener {
+
+        /**
+         * Called when data has been received from a remote device.
+         *
+         * @param value received data
+         */
+        void onDataReceived(byte[] value);
+    }
+
+    /**
+     * The interface that device service has to implement to get notified when BLE events occur
+     */
+    interface BleEventCallback {
+
+        /**
+         * Called when a remote device is connected
+         *
+         * @param device the remote device
+         */
+        void onRemoteDeviceConnected(BluetoothDevice device);
+
+        /**
+         * Called when a remote device is disconnected
+         *
+         * @param device the remote device
+         */
+        void onRemoteDeviceDisconnected(BluetoothDevice device);
+
+        /**
+         * Called when the device name of the remote device is retrieved
+         *
+         * @param deviceName device name of the remote device
+         */
+        void onClientDeviceNameRetrieved(String deviceName);
+    }
 }
diff --git a/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java b/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java
index 7f2923d..bff833a 100644
--- a/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java
+++ b/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java
@@ -37,6 +37,8 @@
 import android.annotation.RequiresPermission;
 import android.app.ActivityManager;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.le.AdvertiseCallback;
+import android.bluetooth.le.AdvertiseSettings;
 import android.car.encryptionrunner.EncryptionRunner;
 import android.car.encryptionrunner.EncryptionRunnerFactory;
 import android.car.encryptionrunner.HandshakeException;
@@ -51,12 +53,15 @@
 import android.content.SharedPreferences;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.sysprop.CarProperties;
 import android.util.Log;
 
 import com.android.car.BLEStreamProtos.BLEOperationProto.OperationType;
 import com.android.car.ICarImpl;
 import com.android.car.R;
 import com.android.car.Utils;
+import com.android.car.trust.CarTrustAgentBleManager.DataReceivedListener;
+import com.android.car.trust.CarTrustAgentBleManager.SendMessageCallback;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -80,8 +85,13 @@
  * phone to enroll as a trusted device.  The enrolled phone can then be used for authenticating a
  * user on the HU.  This implements the {@link android.car.trust.CarTrustAgentEnrollmentManager}
  * APIs that an app like Car Settings can call to conduct an enrollment.
+ *
+ * @deprecated Enrollment of a trusted device is no longer a supported feature of car service and
+ * these APIs will be removed in the next Android release.
  */
-public class CarTrustAgentEnrollmentService extends ICarTrustAgentEnrollment.Stub {
+@Deprecated
+public class CarTrustAgentEnrollmentService extends ICarTrustAgentEnrollment.Stub implements
+        DataReceivedListener {
     private static final String TAG = "CarTrustAgentEnroll";
     private static final String TRUSTED_DEVICE_ENROLLMENT_ENABLED_KEY =
             "trusted_device_enrollment_enabled";
@@ -94,7 +104,21 @@
     // TrustedDeviceInfo and this delimiter will be removed.
     private static final char DEVICE_INFO_DELIMITER = '#';
 
+    // Device name length is limited by available bytes in BLE advertisement data packet.
+    //
+    // BLE advertisement limits data packet length to 31
+    // Currently we send:
+    // - 18 bytes for 16 chars UUID: 16 bytes + 2 bytes for header;
+    // - 3 bytes for advertisement being connectable;
+    // which leaves 10 bytes.
+    // Subtracting 2 bytes used by header, we have 8 bytes for device name.
+    private static final int DEVICE_NAME_LENGTH_LIMIT = 8;
+    // Limit prefix to 4 chars and fill the rest with randomly generated name. Use random name
+    // to improve uniqueness in paired device name.
+    private static final int DEVICE_NAME_PREFIX_LIMIT = 4;
+
     private final CarTrustedDeviceService mTrustedDeviceService;
+    private final CarCompanionDeviceStorage mCarCompanionDeviceStorage;
     // List of clients listening to Enrollment state change events.
     private final List<EnrollmentStateClient> mEnrollmentStateClients = new ArrayList<>();
     // List of clients listening to BLE state changes events during enrollment.
@@ -110,7 +134,10 @@
     private final Map<Long, Boolean> mTokenActiveStateMap = new HashMap<>();
     private String mClientDeviceName;
     private String mClientDeviceId;
+    private final UUID mEnrollmentClientWriteUuid;
     private final Context mContext;
+    private String mEnrollmentDeviceName;
+    private SendMessageCallback mSendMessageCallback = this::terminateEnrollmentHandshake;
 
     private EncryptionRunner mEncryptionRunner = EncryptionRunnerFactory.newRunner();
     private HandshakeMessage mHandshakeMessage;
@@ -143,10 +170,15 @@
         mContext = context;
         mTrustedDeviceService = service;
         mCarTrustAgentBleManager = bleService;
+        mEnrollmentClientWriteUuid = UUID.fromString(context
+                .getString(R.string.enrollment_client_write_uuid));
+        mCarCompanionDeviceStorage = new CarCompanionDeviceStorage(context);
     }
 
     public synchronized void init() {
         mCarTrustAgentBleManager.setupEnrollmentBleServer();
+        mCarTrustAgentBleManager.addDataReceivedListener(mEnrollmentClientWriteUuid,
+                this);
     }
 
     /**
@@ -177,7 +209,7 @@
     @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
     public void startEnrollmentAdvertising() {
         ICarImpl.assertTrustAgentEnrollmentPermission(mContext);
-        if (!mTrustedDeviceService.getSharedPrefs()
+        if (!mCarCompanionDeviceStorage.getSharedPrefs()
                 .getBoolean(TRUSTED_DEVICE_ENROLLMENT_ENABLED_KEY, true)) {
             Log.e(TAG, "Trusted Device Enrollment disabled");
             dispatchEnrollmentFailure(ENROLLMENT_NOT_ALLOWED);
@@ -189,7 +221,24 @@
 
         logEnrollmentEvent(START_ENROLLMENT_ADVERTISING);
         addEnrollmentServiceLog("startEnrollmentAdvertising");
-        mCarTrustAgentBleManager.startEnrollmentAdvertising();
+        mCarTrustAgentBleManager.startEnrollmentAdvertising(getEnrollmentDeviceName(),
+                new AdvertiseCallback() {
+                    @Override
+                    public void onStartSuccess(AdvertiseSettings settingsInEffect) {
+                        super.onStartSuccess(settingsInEffect);
+                        onEnrollmentAdvertiseStartSuccess();
+                        if (Log.isLoggable(TAG, Log.DEBUG)) {
+                            Log.d(TAG, "Successfully started advertising service");
+                        }
+                    }
+
+                    @Override
+                    public void onStartFailure(int errorCode) {
+                        super.onStartFailure(errorCode);
+                        Log.e(TAG, "Failed to advertise, errorCode: " + errorCode);
+                        onEnrollmentAdvertiseStartFailure();
+                    }
+            });
         mEnrollmentState = ENROLLMENT_STATE_NONE;
     }
 
@@ -224,8 +273,9 @@
             mCarTrustAgentBleManager.disconnectRemoteDevice();
             return;
         }
-        mCarTrustAgentBleManager.sendEnrollmentMessage(mRemoteEnrollmentDevice, CONFIRMATION_SIGNAL,
-                OperationType.ENCRYPTION_HANDSHAKE, /* isPayloadEncrypted= */ false);
+        mCarTrustAgentBleManager.sendMessage(CONFIRMATION_SIGNAL,
+                OperationType.ENCRYPTION_HANDSHAKE, /* isPayloadEncrypted= */ false,
+                mSendMessageCallback);
         setEnrollmentHandshakeAccepted();
     }
 
@@ -248,7 +298,8 @@
             boolean isHandleActive = pair.getValue();
             if (!isHandleActive) {
                 long handle = pair.getKey();
-                int uid = mTrustedDeviceService.getSharedPrefs().getInt(String.valueOf(handle), -1);
+                int uid = mCarCompanionDeviceStorage.getSharedPrefs().getInt(String.valueOf(handle),
+                        -1);
                 removeEscrowToken(handle, uid);
                 it.remove();
             }
@@ -311,7 +362,7 @@
     @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
     public void setTrustedDeviceEnrollmentEnabled(boolean isEnabled) {
         ICarImpl.assertTrustAgentEnrollmentPermission(mContext);
-        SharedPreferences.Editor editor = mTrustedDeviceService.getSharedPrefs().edit();
+        SharedPreferences.Editor editor = mCarCompanionDeviceStorage.getSharedPrefs().edit();
         editor.putBoolean(TRUSTED_DEVICE_ENROLLMENT_ENABLED_KEY, isEnabled);
         if (!editor.commit()) {
             Log.wtf(TAG,
@@ -346,7 +397,7 @@
     @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
     public List<TrustedDeviceInfo> getEnrolledDeviceInfosForUser(int uid) {
         ICarImpl.assertTrustAgentEnrollmentPermission(mContext);
-        Set<String> enrolledDeviceInfos = mTrustedDeviceService.getSharedPrefs().getStringSet(
+        Set<String> enrolledDeviceInfos = mCarCompanionDeviceStorage.getSharedPrefs().getStringSet(
                 String.valueOf(uid), new HashSet<>());
         List<TrustedDeviceInfo> trustedDeviceInfos = new ArrayList<>(enrolledDeviceInfos.size());
         for (String deviceInfoWithId : enrolledDeviceInfos) {
@@ -429,7 +480,7 @@
                 Log.e(TAG, "onEscrowTokenRemoved dispatch failed", e);
             }
         }
-        SharedPreferences sharedPrefs = mTrustedDeviceService.getSharedPrefs();
+        SharedPreferences sharedPrefs = mCarCompanionDeviceStorage.getSharedPrefs();
         SharedPreferences.Editor editor = sharedPrefs.edit();
         editor.remove(String.valueOf(handle));
         Set<String> deviceInfos = sharedPrefs.getStringSet(String.valueOf(uid), new HashSet<>());
@@ -479,7 +530,7 @@
 
         // Avoid storing duplicate info for same device by checking if there is already device info
         // and deleting it.
-        SharedPreferences sharedPrefs = mTrustedDeviceService.getSharedPrefs();
+        SharedPreferences sharedPrefs = mCarCompanionDeviceStorage.getSharedPrefs();
         if (sharedPrefs.contains(mClientDeviceId)) {
             removeEscrowToken(sharedPrefs.getLong(mClientDeviceId, -1), uid);
         }
@@ -535,9 +586,10 @@
             Log.d(TAG, "Sending handle: " + handle);
         }
         mHandle = handle;
-        mCarTrustAgentBleManager.sendEnrollmentMessage(mRemoteEnrollmentDevice,
+        mCarTrustAgentBleManager.sendMessage(
                 mEncryptionKey.encryptData(Utils.longToBytes(handle)),
-                OperationType.CLIENT_MESSAGE, /* isPayloadEncrypted= */ true);
+                OperationType.CLIENT_MESSAGE, /* isPayloadEncrypted= */ true,
+                mSendMessageCallback);
     }
 
     void onEnrollmentAdvertiseStartSuccess() {
@@ -610,7 +662,8 @@
      *
      * @param value received data
      */
-    void onEnrollmentDataReceived(byte[] value) {
+    @Override
+    public void onDataReceived(byte[] value) {
         if (mEnrollmentDelegate == null) {
             if (Log.isLoggable(TAG, Log.DEBUG)) {
                 Log.d(TAG, "Enrollment Delegate not set");
@@ -647,7 +700,7 @@
         }
     }
 
-    void onDeviceNameRetrieved(String deviceName) {
+    void onClientDeviceNameRetrieved(String deviceName) {
         mClientDeviceName = deviceName;
     }
 
@@ -661,7 +714,7 @@
         if (Log.isLoggable(TAG, Log.DEBUG)) {
             Log.d(TAG, "Received device id: " + mClientDeviceId);
         }
-        UUID uniqueId = mTrustedDeviceService.getUniqueId();
+        UUID uniqueId = mCarCompanionDeviceStorage.getUniqueId();
         if (uniqueId == null) {
             Log.e(TAG, "Cannot get Unique ID for the IHU");
             resetEnrollmentStateOnFailure();
@@ -671,9 +724,10 @@
         if (Log.isLoggable(TAG, Log.DEBUG)) {
             Log.d(TAG, "Sending device id: " + uniqueId.toString());
         }
-        mCarTrustAgentBleManager.sendEnrollmentMessage(mRemoteEnrollmentDevice,
+        mCarTrustAgentBleManager.sendMessage(
                 Utils.uuidToBytes(uniqueId), OperationType.CLIENT_MESSAGE,
-                /* isPayloadEncrypted= */ false);
+                /* isPayloadEncrypted= */ false,
+                mSendMessageCallback);
         mEnrollmentState++;
     }
 
@@ -709,9 +763,10 @@
 
                 mHandshakeMessage = mEncryptionRunner.respondToInitRequest(message);
                 mEncryptionState = mHandshakeMessage.getHandshakeState();
-                mCarTrustAgentBleManager.sendEnrollmentMessage(
-                        mRemoteEnrollmentDevice, mHandshakeMessage.getNextMessage(),
-                        OperationType.ENCRYPTION_HANDSHAKE, /* isPayloadEncrypted= */ false);
+                mCarTrustAgentBleManager.sendMessage(
+                        mHandshakeMessage.getNextMessage(),
+                        OperationType.ENCRYPTION_HANDSHAKE, /* isPayloadEncrypted= */ false,
+                        mSendMessageCallback);
 
                 logEnrollmentEvent(ENROLLMENT_ENCRYPTION_STATE, mEncryptionState);
                 break;
@@ -734,9 +789,9 @@
                     showVerificationCode();
                     return;
                 }
-                mCarTrustAgentBleManager.sendEnrollmentMessage(mRemoteEnrollmentDevice,
+                mCarTrustAgentBleManager.sendMessage(
                         mHandshakeMessage.getNextMessage(), OperationType.ENCRYPTION_HANDSHAKE,
-                        /* isPayloadEncrypted= */ false);
+                        /* isPayloadEncrypted= */ false, mSendMessageCallback);
                 break;
             case HandshakeState.VERIFICATION_NEEDED:
                 Log.w(TAG, "Encountered VERIFICATION_NEEDED state when it should have been "
@@ -825,7 +880,8 @@
 
         mEncryptionState = HandshakeState.FINISHED;
         mEncryptionKey = message.getKey();
-        if (!mTrustedDeviceService.saveEncryptionKey(mClientDeviceId, mEncryptionKey.asBytes())) {
+        if (!mCarCompanionDeviceStorage.saveEncryptionKey(mClientDeviceId,
+                mEncryptionKey.asBytes())) {
             resetEnrollmentStateOnFailure();
             dispatchEnrollmentFailure(ENROLLMENT_HANDSHAKE_FAILURE);
             return;
@@ -1134,4 +1190,22 @@
             }
         }
     }
+
+    /**
+     * Returns the name that should be used for the device during enrollment of a trusted device.
+     *
+     * <p>The returned name will be a combination of a prefix sysprop and randomized digits.
+     */
+    private String getEnrollmentDeviceName() {
+        if (mEnrollmentDeviceName == null) {
+            String deviceNamePrefix = CarProperties.trusted_device_device_name_prefix().orElse("");
+            deviceNamePrefix = deviceNamePrefix.substring(
+                0, Math.min(deviceNamePrefix.length(), DEVICE_NAME_PREFIX_LIMIT));
+
+            int randomNameLength = DEVICE_NAME_LENGTH_LIMIT - deviceNamePrefix.length();
+            String randomName = Utils.generateRandomNumberString(randomNameLength);
+            mEnrollmentDeviceName = deviceNamePrefix + randomName;
+        }
+        return mEnrollmentDeviceName;
+    }
 }
diff --git a/service/src/com/android/car/trust/CarTrustAgentUnlockService.java b/service/src/com/android/car/trust/CarTrustAgentUnlockService.java
index 2bc7aee..a163dba 100644
--- a/service/src/com/android/car/trust/CarTrustAgentUnlockService.java
+++ b/service/src/com/android/car/trust/CarTrustAgentUnlockService.java
@@ -35,31 +35,26 @@
 import android.car.encryptionrunner.HandshakeException;
 import android.car.encryptionrunner.HandshakeMessage;
 import android.car.encryptionrunner.Key;
+import android.content.Context;
 import android.content.SharedPreferences;
 import android.util.Log;
 
 import com.android.car.BLEStreamProtos.BLEOperationProto.OperationType;
 import com.android.car.PhoneAuthProtos.PhoneAuthProto.PhoneCredentials;
+import com.android.car.R;
 import com.android.car.Utils;
 import com.android.car.protobuf.InvalidProtocolBufferException;
+import com.android.car.trust.CarTrustAgentBleManager.SendMessageCallback;
 import com.android.internal.annotations.GuardedBy;
 
-import com.google.security.cryptauth.lib.securegcm.D2DConnectionContext;
-import com.google.security.cryptauth.lib.securemessage.CryptoOps;
-
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.security.InvalidKeyException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
 import java.security.SignatureException;
 import java.util.LinkedList;
 import java.util.Queue;
 import java.util.UUID;
 
-import javax.crypto.spec.SecretKeySpec;
-
 /**
  * A service that interacts with the Trust Agent {@link CarBleTrustAgent} and a comms (BLE) service
  * {@link CarTrustAgentBleManager} to receive the necessary credentials to authenticate
@@ -92,17 +87,17 @@
  * <li>Phone sends the encrypted escrow token and handle to the IHU.
  * <li>IHU retrieves the user id and authenticates the user.
  * </ol>
+ *
+ * @deprecated Unlocking of a trusted device is no longer a supported feature of car service and
+ * these APIs will be removed in the next Android release.
  */
+@Deprecated
 public class CarTrustAgentUnlockService {
     private static final String TAG = "CarTrustAgentUnlock";
     private static final String TRUSTED_DEVICE_UNLOCK_ENABLED_KEY = "trusted_device_unlock_enabled";
 
     // Arbitrary log size
     private static final int MAX_LOG_SIZE = 20;
-    private static final byte[] RESUME = "RESUME".getBytes();
-    private static final byte[] SERVER = "SERVER".getBytes();
-    private static final byte[] CLIENT = "CLIENT".getBytes();
-    private static final int RESUME_HMAC_LENGTH = 32;
 
     private static final byte[] ACKNOWLEDGEMENT_MESSAGE = "ACK".getBytes();
 
@@ -110,15 +105,14 @@
     // State increments to the next state on successful completion.
     private static final int UNLOCK_STATE_WAITING_FOR_UNIQUE_ID = 0;
     private static final int UNLOCK_STATE_KEY_EXCHANGE_IN_PROGRESS = 1;
-    private static final int UNLOCK_STATE_WAITING_FOR_CLIENT_AUTH = 2;
-    private static final int UNLOCK_STATE_MUTUAL_AUTH_ESTABLISHED = 3;
-    private static final int UNLOCK_STATE_PHONE_CREDENTIALS_RECEIVED = 4;
+    private static final int UNLOCK_STATE_MUTUAL_AUTH_ESTABLISHED = 2;
+    private static final int UNLOCK_STATE_PHONE_CREDENTIALS_RECEIVED = 3;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"UNLOCK_STATE_"}, value = {UNLOCK_STATE_WAITING_FOR_UNIQUE_ID,
-            UNLOCK_STATE_KEY_EXCHANGE_IN_PROGRESS, UNLOCK_STATE_WAITING_FOR_CLIENT_AUTH,
-            UNLOCK_STATE_MUTUAL_AUTH_ESTABLISHED, UNLOCK_STATE_PHONE_CREDENTIALS_RECEIVED})
+    @IntDef(prefix = {"UNLOCK_STATE_"},
+            value = {UNLOCK_STATE_WAITING_FOR_UNIQUE_ID, UNLOCK_STATE_KEY_EXCHANGE_IN_PROGRESS,
+                    UNLOCK_STATE_MUTUAL_AUTH_ESTABLISHED, UNLOCK_STATE_PHONE_CREDENTIALS_RECEIVED})
     @interface UnlockState {
     }
 
@@ -126,10 +120,13 @@
     private int mCurrentUnlockState = UNLOCK_STATE_WAITING_FOR_UNIQUE_ID;
 
     private final CarTrustedDeviceService mTrustedDeviceService;
+    private final CarCompanionDeviceStorage mCarCompanionDeviceStorage;
     private final CarTrustAgentBleManager mCarTrustAgentBleManager;
     private CarTrustAgentUnlockDelegate mUnlockDelegate;
     private String mClientDeviceId;
     private final Queue<String> mLogQueue = new LinkedList<>();
+    private final UUID mUnlockClientWriteUuid;
+    private SendMessageCallback mSendMessageCallback;
 
     // Locks
     private final Object mDeviceLock = new Object();
@@ -138,18 +135,19 @@
     private BluetoothDevice mRemoteUnlockDevice;
 
     private EncryptionRunner mEncryptionRunner = EncryptionRunnerFactory.newRunner();
-    private HandshakeMessage mHandshakeMessage;
     private Key mEncryptionKey;
     @HandshakeMessage.HandshakeState
     private int mEncryptionState = HandshakeMessage.HandshakeState.UNKNOWN;
 
-    private D2DConnectionContext mPrevContext;
-    private D2DConnectionContext mCurrentContext;
-
-    CarTrustAgentUnlockService(CarTrustedDeviceService service,
+    CarTrustAgentUnlockService(Context context, CarTrustedDeviceService service,
             CarTrustAgentBleManager bleService) {
         mTrustedDeviceService = service;
         mCarTrustAgentBleManager = bleService;
+        mUnlockClientWriteUuid = UUID.fromString(context
+                .getString(R.string.unlock_client_write_uuid));
+        mEncryptionRunner.setIsReconnect(true);
+        mSendMessageCallback = () -> mCarTrustAgentBleManager.disconnectRemoteDevice();
+        mCarCompanionDeviceStorage = new CarCompanionDeviceStorage(context);
     }
 
     /**
@@ -175,7 +173,7 @@
      *                  back.
      */
     public void setTrustedDeviceUnlockEnabled(boolean isEnabled) {
-        SharedPreferences.Editor editor = mTrustedDeviceService.getSharedPrefs().edit();
+        SharedPreferences.Editor editor = mCarCompanionDeviceStorage.getSharedPrefs().edit();
         editor.putBoolean(TRUSTED_DEVICE_UNLOCK_ENABLED_KEY, isEnabled);
         if (!editor.commit()) {
             Log.wtf(TAG, "Unlock Enable Failed. Enable? " + isEnabled);
@@ -195,8 +193,8 @@
      * Start Unlock Advertising
      */
     void startUnlockAdvertising() {
-        if (!mTrustedDeviceService.getSharedPrefs().getBoolean(TRUSTED_DEVICE_UNLOCK_ENABLED_KEY,
-                true)) {
+        if (!mCarCompanionDeviceStorage.getSharedPrefs().getBoolean(
+                TRUSTED_DEVICE_UNLOCK_ENABLED_KEY, true)) {
             Log.e(TAG, "Trusted Device Unlock is disabled");
             return;
         }
@@ -205,6 +203,7 @@
 
         logUnlockEvent(START_UNLOCK_ADVERTISING);
         queueMessageForLog("startUnlockAdvertising");
+        mCarTrustAgentBleManager.setUniqueId(mCarCompanionDeviceStorage.getUniqueId());
         mCarTrustAgentBleManager.startUnlockAdvertising();
     }
 
@@ -225,14 +224,14 @@
     void init() {
         logUnlockEvent(UNLOCK_SERVICE_INIT);
         mCarTrustAgentBleManager.setupUnlockBleServer();
+        mCarTrustAgentBleManager.addDataReceivedListener(mUnlockClientWriteUuid,
+                this::onUnlockDataReceived);
     }
 
     void release() {
         synchronized (mDeviceLock) {
             mRemoteUnlockDevice = null;
         }
-        mPrevContext = null;
-        mCurrentContext = null;
     }
 
     void onRemoteDeviceConnected(BluetoothDevice device) {
@@ -291,33 +290,19 @@
                     resetUnlockStateOnFailure();
                 }
                 break;
-            case UNLOCK_STATE_WAITING_FOR_CLIENT_AUTH:
-                if (!authenticateClient(value)) {
-                    if (Log.isLoggable(TAG, Log.DEBUG)) {
-                        Log.d(TAG, "HMAC from the phone is not correct. Cannot resume session. Need"
-                                + " to re-enroll");
-                    }
-                    mTrustedDeviceService.clearEncryptionKey(mClientDeviceId);
-                    resetUnlockStateOnFailure();
-                    return;
-                }
-
-                logUnlockEvent(CLIENT_AUTHENTICATED);
-                sendServerAuthToClient();
-                mCurrentUnlockState = UNLOCK_STATE_MUTUAL_AUTH_ESTABLISHED;
-                break;
             case UNLOCK_STATE_MUTUAL_AUTH_ESTABLISHED:
                 if (mEncryptionKey == null) {
                     Log.e(TAG, "Current session key null. Unexpected at this stage: "
                             + mCurrentUnlockState);
                     // Clear the previous session key.  Need to re-enroll the trusted device.
-                    mTrustedDeviceService.clearEncryptionKey(mClientDeviceId);
+                    mCarCompanionDeviceStorage.clearEncryptionKey(mClientDeviceId);
                     resetUnlockStateOnFailure();
                     return;
                 }
 
                 // Save the current session to be used for authenticating the next session
-                mTrustedDeviceService.saveEncryptionKey(mClientDeviceId, mEncryptionKey.asBytes());
+                mCarCompanionDeviceStorage.saveEncryptionKey(mClientDeviceId,
+                        mEncryptionKey.asBytes());
 
                 byte[] decryptedCredentials;
                 try {
@@ -348,8 +333,9 @@
         // Let the phone know that the handle was received.
         byte[] ack = isEncrypted ? mEncryptionKey.encryptData(ACKNOWLEDGEMENT_MESSAGE)
                 : ACKNOWLEDGEMENT_MESSAGE;
-        mCarTrustAgentBleManager.sendUnlockMessage(mRemoteUnlockDevice, ack,
-                OperationType.CLIENT_MESSAGE, /* isPayloadEncrypted= */ isEncrypted);
+        mCarTrustAgentBleManager.sendMessage(ack,
+                OperationType.CLIENT_MESSAGE, /* isPayloadEncrypted= */ isEncrypted,
+                mSendMessageCallback);
     }
 
     @Nullable
@@ -357,7 +343,7 @@
         // Validate if the id exists i.e., if the phone is enrolled already
         UUID deviceId = Utils.bytesToUUID(id);
         if (deviceId == null
-                || mTrustedDeviceService.getEncryptionKey(deviceId.toString()) == null) {
+                || mCarCompanionDeviceStorage.getEncryptionKey(deviceId.toString()) == null) {
             if (deviceId != null) {
                 Log.e(TAG, "Unknown phone connected: " + deviceId.toString());
             }
@@ -368,18 +354,19 @@
     }
 
     private void processKeyExchangeHandshakeMessage(byte[] message) throws HandshakeException {
+        HandshakeMessage handshakeMessage;
         switch (mEncryptionState) {
             case HandshakeMessage.HandshakeState.UNKNOWN:
                 if (Log.isLoggable(TAG, Log.DEBUG)) {
                     Log.d(TAG, "Responding to handshake init request.");
                 }
 
-                mHandshakeMessage = mEncryptionRunner.respondToInitRequest(message);
-                mEncryptionState = mHandshakeMessage.getHandshakeState();
-                mCarTrustAgentBleManager.sendUnlockMessage(mRemoteUnlockDevice,
-                        mHandshakeMessage.getNextMessage(),
+                handshakeMessage = mEncryptionRunner.respondToInitRequest(message);
+                mEncryptionState = handshakeMessage.getHandshakeState();
+                mCarTrustAgentBleManager.sendMessage(
+                        handshakeMessage.getNextMessage(),
                         OperationType.ENCRYPTION_HANDSHAKE,
-                        /* isPayloadEncrypted= */ false);
+                        /* isPayloadEncrypted= */ false, mSendMessageCallback);
                 logUnlockEvent(UNLOCK_ENCRYPTION_STATE, mEncryptionState);
                 break;
 
@@ -388,124 +375,58 @@
                     Log.d(TAG, "Continuing handshake.");
                 }
 
-                mHandshakeMessage = mEncryptionRunner.continueHandshake(message);
-                mEncryptionState = mHandshakeMessage.getHandshakeState();
+                handshakeMessage = mEncryptionRunner.continueHandshake(message);
+                mEncryptionState = handshakeMessage.getHandshakeState();
 
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "Updated encryption state: " + mEncryptionState);
-                }
+                logUnlockEvent(UNLOCK_ENCRYPTION_STATE, mEncryptionState);
 
-                // The state is updated after a call to continueHandshake(). Thus, need to check
-                // if we're in the next stage.
-                if (mEncryptionState == HandshakeMessage.HandshakeState.VERIFICATION_NEEDED) {
-                    logUnlockEvent(UNLOCK_ENCRYPTION_STATE, mEncryptionState);
-                    showVerificationCode();
+                if (mEncryptionState != HandshakeMessage.HandshakeState.RESUMING_SESSION) {
+                    Log.e(TAG,
+                            "Handshake did not went to resume session after calling verify PIN. "
+                                    + "Instead got state: " + mEncryptionState);
+                    resetUnlockStateOnFailure();
                     return;
                 }
-
-                // control shouldn't get here with Ukey2
-                mCarTrustAgentBleManager.sendUnlockMessage(mRemoteUnlockDevice,
-                        mHandshakeMessage.getNextMessage(),
-                        OperationType.ENCRYPTION_HANDSHAKE, /*isPayloadEncrypted= */false);
+                logUnlockEvent(WAITING_FOR_CLIENT_AUTH);
+                break;
+            case HandshakeMessage.HandshakeState.RESUMING_SESSION:
+                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                    Log.d(TAG, "Start reconnection authentication.");
+                }
+                if (mClientDeviceId == null) {
+                    resetUnlockStateOnFailure();
+                    return;
+                }
+                handshakeMessage = mEncryptionRunner.authenticateReconnection(
+                        message, mCarCompanionDeviceStorage.getEncryptionKey(mClientDeviceId));
+                mEncryptionKey = handshakeMessage.getKey();
+                mEncryptionState = handshakeMessage.getHandshakeState();
+                logUnlockEvent(UNLOCK_ENCRYPTION_STATE, mEncryptionState);
+                if (mEncryptionState != HandshakeMessage.HandshakeState.FINISHED) {
+                    resetUnlockStateOnFailure();
+                    return;
+                }
+                mCurrentUnlockState = UNLOCK_STATE_MUTUAL_AUTH_ESTABLISHED;
+                sendServerAuthToClient(handshakeMessage.getNextMessage());
+                logUnlockEvent(CLIENT_AUTHENTICATED);
                 break;
             case HandshakeMessage.HandshakeState.VERIFICATION_NEEDED:
             case HandshakeMessage.HandshakeState.FINISHED:
                 // Should never reach this case since this state should occur after a verification
                 // code has been accepted. But it should mean handshake is done and the message
-                // is one for the escrow token. Start Mutual Auth from server - compute MACs and
-                // send it over
-                showVerificationCode();
-                break;
-
+                // is one for the escrow token. Waiting Mutual Auth from client, authenticate,
+                // compute MACs and send it over
             default:
                 Log.w(TAG, "Encountered invalid handshake state: " + mEncryptionState);
                 break;
         }
     }
 
-    /**
-     * Verify the handshake.
-     * TODO(b/134073741) combine this with the method in CarTrustAgentEnrollmentService and
-     * have this take a boolean to blindly confirm the numeric code.
-     */
-    private void showVerificationCode() {
-        HandshakeMessage handshakeMessage;
-
-        // Blindly accept the verification code.
-        try {
-            handshakeMessage = mEncryptionRunner.verifyPin();
-        } catch (HandshakeException e) {
-            Log.e(TAG, "Verify pin failed for new keys - Unexpected");
-            resetUnlockStateOnFailure();
-            return;
-        }
-
-        if (handshakeMessage.getHandshakeState() != HandshakeMessage.HandshakeState.FINISHED) {
-            Log.e(TAG, "Handshake not finished after calling verify PIN. Instead got state: "
-                    + handshakeMessage.getHandshakeState());
-            resetUnlockStateOnFailure();
-            return;
-        }
-
-        mEncryptionState = HandshakeMessage.HandshakeState.FINISHED;
-        mEncryptionKey = handshakeMessage.getKey();
-        mCurrentContext = D2DConnectionContext.fromSavedSession(mEncryptionKey.asBytes());
-
-        if (mClientDeviceId == null) {
-            resetUnlockStateOnFailure();
-            return;
-        }
-        byte[] oldSessionKeyBytes = mTrustedDeviceService.getEncryptionKey(mClientDeviceId);
-        if (oldSessionKeyBytes == null) {
-            Log.e(TAG,
-                    "Could not retrieve previous session keys! Have to re-enroll trusted device");
-            resetUnlockStateOnFailure();
-            return;
-        }
-
-        mPrevContext = D2DConnectionContext.fromSavedSession(oldSessionKeyBytes);
-        if (mPrevContext == null) {
-            resetUnlockStateOnFailure();
-            return;
-        }
-
-        // Now wait for the phone to send its MAC.
-        mCurrentUnlockState = UNLOCK_STATE_WAITING_FOR_CLIENT_AUTH;
-        logUnlockEvent(WAITING_FOR_CLIENT_AUTH);
-    }
-
-    private void sendServerAuthToClient() {
-        byte[] resumeBytes = computeMAC(mPrevContext, mCurrentContext, SERVER);
-        if (resumeBytes == null) {
-            return;
-        }
+    private void sendServerAuthToClient(byte[] resumeBytes) {
         // send to client
-        mCarTrustAgentBleManager.sendUnlockMessage(mRemoteUnlockDevice, resumeBytes,
-                OperationType.CLIENT_MESSAGE, /* isPayloadEncrypted= */false);
-    }
-
-    @Nullable
-    private byte[] computeMAC(D2DConnectionContext previous, D2DConnectionContext next,
-            byte[] info) {
-        try {
-            SecretKeySpec inputKeyMaterial = new SecretKeySpec(
-                    Utils.concatByteArrays(previous.getSessionUnique(), next.getSessionUnique()),
-                    "" /* key type is just plain raw bytes */);
-            return CryptoOps.hkdf(inputKeyMaterial, RESUME, info);
-        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
-            // Does not happen in practice
-            Log.e(TAG, "Compute MAC failed");
-            return null;
-        }
-    }
-
-    private boolean authenticateClient(byte[] message) {
-        if (message.length != RESUME_HMAC_LENGTH) {
-            Log.e(TAG, "failing because message.length is " + message.length);
-            return false;
-        }
-        return MessageDigest.isEqual(message,
-                computeMAC(mPrevContext, mCurrentContext, CLIENT));
+        mCarTrustAgentBleManager.sendMessage(resumeBytes,
+                OperationType.CLIENT_MESSAGE, /* isPayloadEncrypted= */false,
+                mSendMessageCallback);
     }
 
     void processCredentials(byte[] credentials) {
@@ -529,7 +450,7 @@
         byte[] handle = phoneCredentials.getHandle().toByteArray();
 
         mUnlockDelegate.onUnlockDataReceived(
-                mTrustedDeviceService.getUserHandleByTokenHandle(Utils.bytesToLong(handle)),
+                mCarCompanionDeviceStorage.getUserHandleByTokenHandle(Utils.bytesToLong(handle)),
                 phoneCredentials.getEscrowToken().toByteArray(),
                 Utils.bytesToLong(handle));
     }
@@ -553,16 +474,12 @@
      */
     private void resetEncryptionState() {
         mEncryptionRunner = EncryptionRunnerFactory.newRunner();
-        mHandshakeMessage = null;
+        // It should always be a reconnection for unlock because only enrolled device can unlock
+        // the IHU.
+        mEncryptionRunner.setIsReconnect(true);
         mEncryptionKey = null;
         mEncryptionState = HandshakeMessage.HandshakeState.UNKNOWN;
         mCurrentUnlockState = UNLOCK_STATE_WAITING_FOR_UNIQUE_ID;
-        if (mCurrentContext != null) {
-            mCurrentContext = null;
-        }
-        if (mPrevContext != null) {
-            mPrevContext = null;
-        }
     }
 
     void dump(PrintWriter writer) {
diff --git a/service/src/com/android/car/trust/CarTrustedDeviceService.java b/service/src/com/android/car/trust/CarTrustedDeviceService.java
index 58869a4..972ff64 100644
--- a/service/src/com/android/car/trust/CarTrustedDeviceService.java
+++ b/service/src/com/android/car/trust/CarTrustedDeviceService.java
@@ -16,42 +16,17 @@
 
 package com.android.car.trust;
 
-import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.bluetooth.BluetoothDevice;
 import android.car.trust.TrustedDeviceInfo;
 import android.content.Context;
-import android.content.SharedPreferences;
-import android.security.keystore.KeyGenParameterSpec;
-import android.security.keystore.KeyProperties;
-import android.sysprop.CarProperties;
-import android.util.Base64;
 import android.util.Log;
 
 import com.android.car.CarServiceBase;
-import com.android.car.R;
-import com.android.car.Utils;
+import com.android.car.trust.CarTrustAgentBleManager.BleEventCallback;
 
-import java.io.IOException;
 import java.io.PrintWriter;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateException;
 import java.util.List;
-import java.util.UUID;
-
-import javax.crypto.BadPaddingException;
-import javax.crypto.Cipher;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.KeyGenerator;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.spec.GCMParameterSpec;
 
 /**
  * The part of the Car service that enables the Trusted device feature.  Trusted Device is a feature
@@ -61,53 +36,25 @@
  * It is comprised of the {@link CarTrustAgentEnrollmentService} for handling enrollment and
  * {@link CarTrustAgentUnlockService} for handling unlock/auth.
  *
+ * @deprecated Enrolling a trusted device is no longer a supported feature of car service and these
+ * APIs will be removed in the next Android release.
  */
-public class CarTrustedDeviceService implements CarServiceBase {
+@Deprecated
+public class CarTrustedDeviceService implements CarServiceBase, BleEventCallback {
     private static final String TAG = CarTrustedDeviceService.class.getSimpleName();
 
-    private static final String UNIQUE_ID_KEY = "CTABM_unique_id";
-    private static final String PREF_ENCRYPTION_KEY_PREFIX = "CTABM_encryption_key";
-    private static final String KEY_ALIAS = "Ukey2Key";
-    private static final String CIPHER_TRANSFORMATION = "AES/GCM/NoPadding";
-    private static final String KEYSTORE_PROVIDER = "AndroidKeyStore";
-    private static final String IV_SPEC_SEPARATOR = ";";
-
-    // Device name length is limited by available bytes in BLE advertisement data packet.
-    //
-    // BLE advertisement limits data packet length to 31
-    // Currently we send:
-    // - 18 bytes for 16 chars UUID: 16 bytes + 2 bytes for header;
-    // - 3 bytes for advertisement being connectable;
-    // which leaves 10 bytes.
-    // Subtracting 2 bytes used by header, we have 8 bytes for device name.
-    private static final int DEVICE_NAME_LENGTH_LIMIT = 8;
-    // Limit prefix to 4 chars and fill the rest with randomly generated name. Use random name
-    // to improve uniqueness in paired device name.
-    private static final int DEVICE_NAME_PREFIX_LIMIT = 4;
-
-    // The length of the authentication tag for a cipher in GCM mode. The GCM specification states
-    // that this length can only have the values {128, 120, 112, 104, 96}. Using the highest
-    // possible value.
-    private static final int GCM_AUTHENTICATION_TAG_LENGTH = 128;
-
     private final Context mContext;
     private CarTrustAgentEnrollmentService mCarTrustAgentEnrollmentService;
     private CarTrustAgentUnlockService mCarTrustAgentUnlockService;
     private CarTrustAgentBleManager mCarTrustAgentBleManager;
-    private SharedPreferences mTrustAgentTokenPreferences;
-    private UUID mUniqueId;
-    private String mEnrollmentDeviceName;
 
     public CarTrustedDeviceService(Context context) {
         mContext = context;
-
-        // TODO(b/134695083): Decouple these classes. The services should instead register as
-        // listeners on CarTrustAgentBleManager. CarTrustAgentBleManager should not know about
-        // the services and just dispatch BLE events.
-        mCarTrustAgentBleManager = new CarTrustAgentBleManager(context);
+        BlePeripheralManager blePeripheralManager = new BlePeripheralManager(context);
+        mCarTrustAgentBleManager = new CarTrustAgentBleManager(context, blePeripheralManager);
         mCarTrustAgentEnrollmentService = new CarTrustAgentEnrollmentService(mContext, this,
                 mCarTrustAgentBleManager);
-        mCarTrustAgentUnlockService = new CarTrustAgentUnlockService(this,
+        mCarTrustAgentUnlockService = new CarTrustAgentUnlockService(mContext, this,
                 mCarTrustAgentBleManager);
     }
 
@@ -115,6 +62,7 @@
     public synchronized void init() {
         mCarTrustAgentEnrollmentService.init();
         mCarTrustAgentUnlockService.init();
+        mCarTrustAgentBleManager.addBleEventCallback(this);
     }
 
     @Override
@@ -139,27 +87,25 @@
     }
 
     /**
-     * Returns User Id for the given token handle
+     * Called when a remote device is connected
      *
-     * @param handle The handle corresponding to the escrow token
-     * @return User id corresponding to the handle
+     * @param device the remote device
      */
-    int getUserHandleByTokenHandle(long handle) {
-        return getSharedPrefs().getInt(String.valueOf(handle), -1);
-    }
-
-    void onRemoteDeviceConnected(BluetoothDevice device) {
+    @Override
+    public void onRemoteDeviceConnected(BluetoothDevice device) {
         mCarTrustAgentEnrollmentService.onRemoteDeviceConnected(device);
         mCarTrustAgentUnlockService.onRemoteDeviceConnected(device);
     }
 
-    void onRemoteDeviceDisconnected(BluetoothDevice device) {
+    @Override
+    public void onRemoteDeviceDisconnected(BluetoothDevice device) {
         mCarTrustAgentEnrollmentService.onRemoteDeviceDisconnected(device);
         mCarTrustAgentUnlockService.onRemoteDeviceDisconnected(device);
     }
 
-    void onDeviceNameRetrieved(String deviceName) {
-        mCarTrustAgentEnrollmentService.onDeviceNameRetrieved(deviceName);
+    @Override
+    public void onClientDeviceNameRetrieved(String deviceName) {
+        mCarTrustAgentEnrollmentService.onClientDeviceNameRetrieved(deviceName);
     }
 
     void cleanupBleService() {
@@ -171,15 +117,6 @@
         mCarTrustAgentBleManager.stopUnlockAdvertising();
     }
 
-    SharedPreferences getSharedPrefs() {
-        if (mTrustAgentTokenPreferences != null) {
-            return mTrustAgentTokenPreferences;
-        }
-        mTrustAgentTokenPreferences = mContext.getSharedPreferences(
-                mContext.getString(R.string.token_handle_shared_preferences), Context.MODE_PRIVATE);
-        return mTrustAgentTokenPreferences;
-    }
-
     @Override
     public void dump(PrintWriter writer) {
         writer.println("*CarTrustedDeviceService*");
@@ -206,216 +143,4 @@
         return sb.toString();
     }
 
-    /**
-     * Get the unique id for head unit. Persists on device until factory reset.
-     *
-     * @return unique id, or null if unable to retrieve generated id (this should never happen)
-     */
-    @Nullable
-    UUID getUniqueId() {
-        if (mUniqueId != null) {
-            return mUniqueId;
-        }
-
-        SharedPreferences prefs = getSharedPrefs();
-        if (prefs.contains(UNIQUE_ID_KEY)) {
-            mUniqueId = UUID.fromString(
-                    prefs.getString(UNIQUE_ID_KEY, null));
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Found existing trusted unique id: "
-                        + prefs.getString(UNIQUE_ID_KEY, ""));
-            }
-        } else {
-            mUniqueId = UUID.randomUUID();
-            if (!prefs.edit().putString(UNIQUE_ID_KEY, mUniqueId.toString()).commit()) {
-                mUniqueId = null;
-            } else if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Generated new trusted unique id: "
-                        + prefs.getString(UNIQUE_ID_KEY, ""));
-            }
-        }
-
-        return mUniqueId;
-    }
-
-    /**
-     * Get communication encryption key for the given device
-     *
-     * @param deviceId id of trusted device
-     * @return encryption key, null if device id is not recognized
-     */
-    @Nullable
-    byte[] getEncryptionKey(String deviceId) {
-        SharedPreferences prefs = getSharedPrefs();
-        String key = PREF_ENCRYPTION_KEY_PREFIX + deviceId;
-        if (!prefs.contains(key)) {
-            return null;
-        }
-
-        // This value will not be "null" because we already checked via a call to contains().
-        String[] values = prefs.getString(key, null).split(IV_SPEC_SEPARATOR);
-
-        if (values.length != 2) {
-            return null;
-        }
-
-        byte[] encryptedKey = Base64.decode(values[0], Base64.DEFAULT);
-        byte[] ivSpec = Base64.decode(values[1], Base64.DEFAULT);
-        return decryptWithKeyStore(KEY_ALIAS, encryptedKey, ivSpec);
-    }
-
-    /**
-     * Save encryption key for the given device
-     *
-     * @param deviceId did of trusted device
-     * @param encryptionKey encryption key
-     * @return {@code true} if the operation succeeded
-     */
-    boolean saveEncryptionKey(@Nullable String deviceId, @Nullable byte[] encryptionKey) {
-        if (encryptionKey == null || deviceId == null) {
-            return false;
-        }
-        String encryptedKey = encryptWithKeyStore(KEY_ALIAS, encryptionKey);
-        if (encryptedKey == null) {
-            return false;
-        }
-        if (getSharedPrefs().contains(deviceId)) {
-            clearEncryptionKey(deviceId);
-        }
-
-        return getSharedPrefs()
-                .edit()
-                .putString(PREF_ENCRYPTION_KEY_PREFIX + deviceId, encryptedKey)
-                .commit();
-    }
-
-    /**
-     * Clear the encryption key for the given device
-     *
-     * @param deviceId id of the peer device
-     */
-    void clearEncryptionKey(@Nullable String deviceId) {
-        if (deviceId == null) {
-            return;
-        }
-        getSharedPrefs().edit().remove(deviceId);
-    }
-
-    /**
-     * Returns the name that should be used for the device during enrollment of a trusted device.
-     *
-     * <p>The returned name will be a combination of a prefix sysprop and randomized digits.
-     */
-    String getEnrollmentDeviceName() {
-        if (mEnrollmentDeviceName == null) {
-            String deviceNamePrefix =
-                    CarProperties.trusted_device_device_name_prefix().orElse("");
-            deviceNamePrefix = deviceNamePrefix.substring(
-                    0, Math.min(deviceNamePrefix.length(), DEVICE_NAME_PREFIX_LIMIT));
-
-            int randomNameLength = DEVICE_NAME_LENGTH_LIMIT - deviceNamePrefix.length();
-            String randomName = Utils.generateRandomNumberString(randomNameLength);
-            mEnrollmentDeviceName = deviceNamePrefix + randomName;
-        }
-        return mEnrollmentDeviceName;
-    }
-
-    /**
-     * Encrypt value with designated key
-     *
-     * <p>The encrypted value is of the form:
-     *
-     * <p>key + IV_SPEC_SEPARATOR + ivSpec
-     *
-     * <p>The {@code ivSpec} is needed to decrypt this key later on.
-     *
-     * @param keyAlias KeyStore alias for key to use
-     * @param value a value to encrypt
-     * @return encrypted value, null if unable to encrypt
-     */
-    @Nullable
-    String encryptWithKeyStore(String keyAlias, byte[] value) {
-        if (value == null) {
-            return null;
-        }
-
-        Key key = getKeyStoreKey(keyAlias);
-        try {
-            Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
-            cipher.init(Cipher.ENCRYPT_MODE, key);
-            return new StringBuffer(Base64.encodeToString(cipher.doFinal(value), Base64.DEFAULT))
-                .append(IV_SPEC_SEPARATOR)
-                .append(Base64.encodeToString(cipher.getIV(), Base64.DEFAULT))
-                .toString();
-        } catch (IllegalBlockSizeException
-                | BadPaddingException
-                | NoSuchAlgorithmException
-                | NoSuchPaddingException
-                | IllegalStateException
-                | InvalidKeyException e) {
-            Log.e(TAG, "Unable to encrypt value with key " + keyAlias, e);
-            return null;
-        }
-    }
-
-    /**
-     * Decrypt value with designated key
-     *
-     * @param keyAlias KeyStore alias for key to use
-     * @param value encrypted value
-     * @return decrypted value, null if unable to decrypt
-     */
-    @Nullable
-    byte[] decryptWithKeyStore(String keyAlias, byte[] value, byte[] ivSpec) {
-        if (value == null) {
-            return null;
-        }
-
-        try {
-            Key key = getKeyStoreKey(keyAlias);
-            Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
-            cipher.init(Cipher.DECRYPT_MODE, key,
-                    new GCMParameterSpec(GCM_AUTHENTICATION_TAG_LENGTH, ivSpec));
-            return cipher.doFinal(value);
-        } catch (IllegalBlockSizeException
-                | BadPaddingException
-                | NoSuchAlgorithmException
-                | NoSuchPaddingException
-                | IllegalStateException
-                | InvalidKeyException
-                | InvalidAlgorithmParameterException e) {
-            Log.e(TAG, "Unable to decrypt value with key " + keyAlias, e);
-            return null;
-        }
-    }
-
-    private Key getKeyStoreKey(String keyAlias) {
-        KeyStore keyStore;
-        try {
-            keyStore = KeyStore.getInstance(KEYSTORE_PROVIDER);
-            keyStore.load(null);
-            if (!keyStore.containsAlias(keyAlias)) {
-                KeyGenerator keyGenerator = KeyGenerator.getInstance(
-                        KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_PROVIDER);
-                keyGenerator.init(
-                        new KeyGenParameterSpec.Builder(keyAlias,
-                                KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
-                                .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
-                                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
-                                .build());
-                keyGenerator.generateKey();
-            }
-            return keyStore.getKey(keyAlias, null);
-
-        } catch (KeyStoreException
-                | NoSuchAlgorithmException
-                | UnrecoverableKeyException
-                | NoSuchProviderException
-                | CertificateException
-                | IOException
-                | InvalidAlgorithmParameterException e) {
-            Log.e(TAG, "Unable to retrieve key " + keyAlias + " from KeyStore.", e);
-            throw new IllegalStateException(e);
-        }
-    }
 }
diff --git a/service/src/com/android/car/user/CarUserNoticeService.java b/service/src/com/android/car/user/CarUserNoticeService.java
index 045d960..3e0891c 100644
--- a/service/src/com/android/car/user/CarUserNoticeService.java
+++ b/service/src/com/android/car/user/CarUserNoticeService.java
@@ -27,6 +27,8 @@
 import android.car.CarNotConnectedException;
 import android.car.hardware.power.CarPowerManager;
 import android.car.settings.CarSettings;
+import android.car.user.CarUserManager;
+import android.car.user.CarUserManager.UserLifecycleListener;
 import android.car.user.IUserNotice;
 import android.car.user.IUserNoticeUI;
 import android.content.BroadcastReceiver;
@@ -48,6 +50,8 @@
 import android.view.IWindowManager;
 import android.view.WindowManagerGlobal;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.car.CarLocalServices;
 import com.android.car.CarServiceBase;
 import com.android.car.R;
@@ -78,7 +82,7 @@
     @Nullable
     private final Intent mServiceIntent;
 
-    private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+    private final Handler mMainHandler;
 
     private final Object mLock = new Object();
 
@@ -106,19 +110,16 @@
     @UserIdInt
     private int mIgnoreUserId = UserHandle.USER_NULL;
 
-    private final CarUserService.UserCallback mUserCallback = new CarUserService.UserCallback() {
-        @Override
-        public void onUserLockChanged(@UserIdInt int userId, boolean unlocked) {
-            // Nothing to do
+    private final UserLifecycleListener mUserLifecycleListener = event -> {
+        if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+            Log.d(TAG_USER, "onEvent(" + event + ")");
         }
-
-        @Override
-        public void onSwitchUser(@UserIdInt int userId) {
-            mMainHandler.post(() -> {
+        if (CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING == event.getEventType()) {
+            CarUserNoticeService.this.mMainHandler.post(() -> {
                 stopUi(/* clearUiShown= */ true);
                 synchronized (mLock) {
-                    // This should be the only place to change user
-                    mUserId = userId;
+                   // This should be the only place to change user
+                    mUserId = event.getUserId();
                 }
                 startNoticeUiIfNecessary();
             });
@@ -167,6 +168,7 @@
     };
 
     private final ServiceConnection mUiServiceConnection = new ServiceConnection() {
+        @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
             synchronized (mLock) {
                 if (!mServiceBound) {
@@ -187,6 +189,7 @@
             }
         }
 
+        @Override
         public void onServiceDisconnected(ComponentName name) {
             // UI crashed. Stop it so that it does not come again.
             stopUi(/* clearUiShown= */ true);
@@ -205,6 +208,12 @@
     };
 
     public CarUserNoticeService(Context context) {
+        this(context, new Handler(Looper.getMainLooper()));
+    }
+
+    @VisibleForTesting
+    CarUserNoticeService(Context context, Handler handler) {
+        mMainHandler = handler;
         Resources res = context.getResources();
         String componentName = res.getString(R.string.config_userNoticeUiService);
         if (componentName.isEmpty()) {
@@ -365,7 +374,7 @@
             throw new RuntimeException("CarNotConnectedException from CarPowerManager", e);
         }
         CarUserService userService = CarLocalServices.getService(CarUserService.class);
-        userService.addUserCallback(mUserCallback);
+        userService.addUserLifecycleListener(mUserLifecycleListener);
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
         intentFilter.addAction(Intent.ACTION_SCREEN_ON);
@@ -380,7 +389,7 @@
         }
         mContext.unregisterReceiver(mDisplayBroadcastReceiver);
         CarUserService userService = CarLocalServices.getService(CarUserService.class);
-        userService.removeUserCallback(mUserCallback);
+        userService.removeUserLifecycleListener(mUserLifecycleListener);
         CarPowerManager carPowerManager;
         synchronized (mLock) {
             carPowerManager = mCarPowerManager;
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
index e0b4be8..e4aeea8 100644
--- a/service/src/com/android/car/user/CarUserService.java
+++ b/service/src/com/android/car/user/CarUserService.java
@@ -16,209 +16,1445 @@
 
 package com.android.car.user;
 
+import static com.android.car.CarLog.TAG_USER;
+
+import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
+import android.app.ActivityManager.StackInfo;
 import android.app.IActivityManager;
+import android.car.CarOccupantZoneManager;
+import android.car.CarOccupantZoneManager.OccupantTypeEnum;
+import android.car.CarOccupantZoneManager.OccupantZoneInfo;
+import android.car.ICarUserService;
 import android.car.settings.CarSettings;
+import android.car.user.CarUserManager;
+import android.car.user.CarUserManager.UserLifecycleEvent;
+import android.car.user.CarUserManager.UserLifecycleEventType;
+import android.car.user.CarUserManager.UserLifecycleListener;
+import android.car.user.UserCreationResult;
+import android.car.user.UserIdentificationAssociationResponse;
+import android.car.user.UserRemovalResult;
+import android.car.user.UserSwitchResult;
 import android.car.userlib.CarUserManagerHelper;
-import android.content.BroadcastReceiver;
+import android.car.userlib.CommonConstants.CarUserServiceConstants;
+import android.car.userlib.HalCallback;
+import android.car.userlib.UserHalHelper;
+import android.car.userlib.UserHelper;
+import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
+import android.content.pm.UserInfo.UserInfoFlag;
 import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.hardware.automotive.vehicle.V2_0.CreateUserRequest;
+import android.hardware.automotive.vehicle.V2_0.CreateUserStatus;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
+import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
+import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
+import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetAssociation;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
+import android.hardware.automotive.vehicle.V2_0.UsersInfo;
 import android.location.LocationManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.RemoteException;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.sysprop.CarProperties;
+import android.text.TextUtils;
+import android.util.EventLog;
 import android.util.Log;
+import android.util.SparseArray;
+import android.util.TimingsTraceLog;
 
 import com.android.car.CarServiceBase;
+import com.android.car.CarServiceUtils;
 import com.android.car.R;
+import com.android.car.hal.UserHalService;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.car.EventLogTags;
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FunctionalUtils;
+import com.android.internal.util.Preconditions;
+import com.android.internal.util.UserIcons;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * User service for cars. Manages users at boot time. Including:
  *
  * <ol>
+ *   <li> Creates a user used as driver.
+ *   <li> Creates a user used as passenger.
  *   <li> Creates a secondary admin user on first run.
- *   <li> Log in to the last active user.
+ *   <li> Switch drivers.
  * <ol/>
  */
-public class CarUserService extends BroadcastReceiver implements CarServiceBase {
-    private static final String TAG = "CarUserService";
+public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
+
+    private static final String TAG = TAG_USER;
+
+    /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
+    public static final String BUNDLE_USER_ID = CarUserServiceConstants.BUNDLE_USER_ID;
+    /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
+    public static final String BUNDLE_USER_FLAGS = CarUserServiceConstants.BUNDLE_USER_FLAGS;
+    /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
+    public static final String BUNDLE_USER_NAME = CarUserServiceConstants.BUNDLE_USER_NAME;
+    /**
+     * {@code int} extra used to represent the user locales in a {@link IResultReceiver} response.
+     */
+    public static final String BUNDLE_USER_LOCALES =
+            CarUserServiceConstants.BUNDLE_USER_LOCALES;
+    /**
+     * {@code int} extra used to represent the info action in a {@link IResultReceiver} response.
+     */
+    public static final String BUNDLE_INITIAL_INFO_ACTION =
+            CarUserServiceConstants.BUNDLE_INITIAL_INFO_ACTION;
+
+    public static final String VEHICLE_HAL_NOT_SUPPORTED = "Vehicle Hal not supported.";
+
     private final Context mContext;
     private final CarUserManagerHelper mCarUserManagerHelper;
     private final IActivityManager mAm;
+    private final UserManager mUserManager;
+    private final int mMaxRunningUsers;
+    private final boolean mEnablePassengerSupport;
 
-    private final Object mLock = new Object();
-    @GuardedBy("mLock")
+    private final Object mLockUser = new Object();
+    @GuardedBy("mLockUser")
     private boolean mUser0Unlocked;
-    @GuardedBy("mLock")
+    @GuardedBy("mLockUser")
     private final ArrayList<Runnable> mUser0UnlockTasks = new ArrayList<>();
+    // Only one passenger is supported.
+    @GuardedBy("mLockUser")
+    private @UserIdInt int mLastPassengerId;
     /**
      * Background users that will be restarted in garage mode. This list can include the
-     * current foreground user bit the current foreground user should not be restarted.
+     * current foreground user but the current foreground user should not be restarted.
      */
-    @GuardedBy("mLock")
+    @GuardedBy("mLockUser")
     private final ArrayList<Integer> mBackgroundUsersToRestart = new ArrayList<>();
     /**
      * Keep the list of background users started here. This is wholly for debugging purpose.
      */
-    @GuardedBy("mLock")
+    @GuardedBy("mLockUser")
     private final ArrayList<Integer> mBackgroundUsersRestartedHere = new ArrayList<>();
 
-    private final int mMaxRunningUsers;
+    private final UserHalService mHal;
 
-    private final UserManager mUserManager;
+    // HandlerThread and Handler used when notifying app listeners (mAppLifecycleListeners).
+    private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
+            getClass().getSimpleName());
+    private final Handler mHandler = new Handler(mHandlerThread.getLooper());
 
+    /**
+     * List of listeners to be notified on new user activities events.
+     * This collection should be accessed and manipulated by mHandlerThread only.
+     */
+    private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
 
-    private final CopyOnWriteArrayList<UserCallback> mUserCallbacks = new CopyOnWriteArrayList<>();
+    /**
+     * List of lifecycle listeners by uid.
+     * This collection should be accessed and manipulated by mHandlerThread only.
+     */
+    private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
 
-    /** Interface for callbacks related to user activities. */
-    public interface UserCallback {
-        /** Gets called when user lock status has been changed. */
-        void onUserLockChanged(int userId, boolean unlocked);
-        /** Called when new foreground user started to boot. */
-        void onSwitchUser(int userId);
+    /**
+     * User Id for the user switch in process, if any.
+     */
+    @GuardedBy("mLockUser")
+    private int mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
+    /**
+     * Request Id for the user switch in process, if any.
+     */
+    @GuardedBy("mLockUser")
+    private int mRequestIdForUserSwitchInProcess;
+    private final int mHalTimeoutMs = CarProperties.user_hal_timeout().orElse(5_000);
+
+    private final CopyOnWriteArrayList<PassengerCallback> mPassengerCallbacks =
+            new CopyOnWriteArrayList<>();
+
+    @Nullable
+    @GuardedBy("mLockUser")
+    private UserInfo mInitialUser;
+
+    private UserMetrics mUserMetrics;
+
+    private IResultReceiver mUserSwitchUiReceiver;
+
+    /** Interface for callbaks related to passenger activities. */
+    public interface PassengerCallback {
+        /** Called when passenger is started at a certain zone. */
+        void onPassengerStarted(@UserIdInt int passengerId, int zoneId);
+        /** Called when passenger is stopped. */
+        void onPassengerStopped(@UserIdInt int passengerId);
     }
 
-    public CarUserService(
-                @Nullable Context context, @Nullable CarUserManagerHelper carUserManagerHelper,
-                IActivityManager am, int maxRunningUsers) {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "constructed");
+    /** Interface for delegating zone-related implementation to CarOccupantZoneService. */
+    public interface ZoneUserBindingHelper {
+        /** Gets occupant zones corresponding to the occupant type. */
+        @NonNull
+        List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType);
+        /** Assigns the user to the occupant zone. */
+        boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId);
+        /** Makes the occupant zone unoccupied. */
+        boolean unassignUserFromOccupantZone(@UserIdInt int userId);
+        /** Returns whether there is a passenger display. */
+        boolean isPassengerDisplayAvailable();
+    }
+
+    private final Object mLockHelper = new Object();
+    @GuardedBy("mLockHelper")
+    private ZoneUserBindingHelper mZoneUserBindingHelper;
+
+    public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
+            @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
+            @NonNull IActivityManager am, int maxRunningUsers) {
+        this(context, hal, carUserManagerHelper, userManager, am, maxRunningUsers,
+                new UserMetrics());
+    }
+
+    @VisibleForTesting
+    CarUserService(@NonNull Context context, @NonNull UserHalService hal,
+            @NonNull CarUserManagerHelper carUserManagerHelper, @NonNull UserManager userManager,
+            @NonNull IActivityManager am, int maxRunningUsers, UserMetrics userMetrics) {
+        if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+            Log.d(TAG_USER, "constructed");
         }
         mContext = context;
+        mHal = hal;
         mCarUserManagerHelper = carUserManagerHelper;
         mAm = am;
         mMaxRunningUsers = maxRunningUsers;
-        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        mUserManager = userManager;
+        mLastPassengerId = UserHandle.USER_NULL;
+        mEnablePassengerSupport = context.getResources().getBoolean(R.bool.enablePassengerSupport);
+        mUserMetrics = userMetrics;
     }
 
     @Override
     public void init() {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "init");
+        if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+            Log.d(TAG_USER, "init");
         }
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_USER_SWITCHED);
-
-        mContext.registerReceiver(this, filter);
     }
 
     @Override
     public void release() {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "release");
+        if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+            Log.d(TAG_USER, "release");
         }
-        mContext.unregisterReceiver(this);
     }
 
     @Override
-    public void dump(PrintWriter writer) {
-        writer.println(TAG);
-        boolean user0Unlocked;
-        ArrayList<Integer> backgroundUsersToRestart;
-        ArrayList<Integer> backgroundUsersRestarted;
-        synchronized (mLock) {
-            user0Unlocked = mUser0Unlocked;
-            backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
-            backgroundUsersRestarted = new ArrayList<>(mBackgroundUsersRestartedHere);
-
-        }
-        writer.println("User0Unlocked: " + user0Unlocked);
-        writer.println("maxRunningUsers:" + mMaxRunningUsers);
-        writer.println("BackgroundUsersToRestart:" + backgroundUsersToRestart);
-        writer.println("BackgroundUsersRestarted:" + backgroundUsersRestarted);
-        writer.println("Relevant overlayable  properties");
-        Resources res = mContext.getResources();
+    public void dump(@NonNull PrintWriter writer) {
+        checkAtLeastOnePermission("dump()", android.Manifest.permission.DUMP);
+        writer.println("*CarUserService*");
         String indent = "  ";
+        handleDumpListeners(writer, indent);
+        writer.printf("User switch UI receiver %s\n", mUserSwitchUiReceiver);
+        synchronized (mLockUser) {
+            writer.println("User0Unlocked: " + mUser0Unlocked);
+            writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
+            writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
+        }
+        writer.println("MaxRunningUsers: " + mMaxRunningUsers);
+        List<UserInfo> allDrivers = getAllDrivers();
+        int driversSize = allDrivers.size();
+        writer.println("NumberOfDrivers: " + driversSize);
+        for (int i = 0; i < driversSize; i++) {
+            int driverId = allDrivers.get(i).id;
+            writer.print(indent + "#" + i + ": id=" + driverId);
+            List<UserInfo> passengers = getPassengers(driverId);
+            int passengersSize = passengers.size();
+            writer.print(" NumberPassengers: " + passengersSize);
+            if (passengersSize > 0) {
+                writer.print(" [");
+                for (int j = 0; j < passengersSize; j++) {
+                    writer.print(passengers.get(j).id);
+                    if (j < passengersSize - 1) {
+                        writer.print(" ");
+                    }
+                }
+                writer.print("]");
+            }
+            writer.println();
+        }
+        writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
+        writer.printf("User HAL timeout: %dms\n",  mHalTimeoutMs);
+        writer.printf("Initial user: %s\n", mInitialUser);
+
+        writer.println("Relevant overlayable properties");
+        Resources res = mContext.getResources();
         writer.printf("%sowner_name=%s\n", indent,
                 res.getString(com.android.internal.R.string.owner_name));
         writer.printf("%sdefault_guest_name=%s\n", indent,
                 res.getString(R.string.default_guest_name));
+        writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
+        writer.printf("Request Id for the user switch in process=%d\n ",
+                    mRequestIdForUserSwitchInProcess);
+        writer.printf("System UI package name=%s\n", getSystemUiPackageName());
+
+        writer.println("Relevant Global settings");
+        dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_USER_ID);
+        dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID);
+
+        dumpUserMetrics(writer);
+    }
+
+    private void dumpGlobalProperty(PrintWriter writer, String indent, String property) {
+        String value = Settings.Global.getString(mContext.getContentResolver(), property);
+        writer.printf("%s%s=%s\n", indent, property, value);
+    }
+
+    /**
+     * Dumps user metrics.
+     */
+    public void dumpUserMetrics(@NonNull PrintWriter writer) {
+        mUserMetrics.dump(writer);
+    }
+
+    /**
+     * Dumps first user unlocking time.
+     */
+    public void dumpFirstUserUnlockDuration(PrintWriter writer) {
+        mUserMetrics.dumpFirstUserUnlockDuration(writer);
+    }
+
+    private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
+        CountDownLatch latch = new CountDownLatch(1);
+        mHandler.post(() -> {
+            handleDumpServiceLifecycleListeners(writer);
+            handleDumpAppLifecycleListeners(writer, indent);
+            latch.countDown();
+        });
+        int timeout = 5;
+        try {
+            if (!latch.await(timeout, TimeUnit.SECONDS)) {
+                writer.printf("Handler thread didn't respond in %ds when dumping listeners\n",
+                        timeout);
+            }
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            writer.println("Interrupted waiting for handler thread to dump app and user listeners");
+        }
+    }
+
+    private void handleDumpServiceLifecycleListeners(@NonNull PrintWriter writer) {
+        if (mUserLifecycleListeners.isEmpty()) {
+            writer.println("No lifecycle listeners for internal services");
+            return;
+        }
+        int size = mUserLifecycleListeners.size();
+        writer.printf("%d lifecycle listener%s for services\n", size, size == 1 ? "" : "s");
+        String indent = "  ";
+        for (UserLifecycleListener listener : mUserLifecycleListeners) {
+            writer.printf("%s%s\n", indent, FunctionalUtils.getLambdaName(listener));
+        }
+    }
+
+    private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
+        int size = mAppLifecycleListeners.size();
+        if (size == 0) {
+            writer.println("No lifecycle listeners for apps");
+            return;
+        }
+        writer.printf("%d lifecycle listener%s for apps \n", size, size == 1 ? "" : "s");
+        for (int i = 0; i < size; i++) {
+            int uid = mAppLifecycleListeners.keyAt(i);
+            IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
+            writer.printf("%suid: %d\n", indent, uid);
+        }
+    }
+
+    /**
+     * @see ExperimentalCarUserManager.createDriver
+     */
+    @Override
+    public AndroidFuture<UserCreationResult> createDriver(@NonNull String name, boolean admin) {
+        checkManageUsersPermission("createDriver");
+        Objects.requireNonNull(name, "name cannot be null");
+
+        AndroidFuture<UserCreationResult> future = new AndroidFuture<UserCreationResult>() {
+            @Override
+            protected void onCompleted(UserCreationResult result, Throwable err) {
+                if (result == null) {
+                    Log.w(TAG, "createDriver(" + name + "," + admin + ") failed: " + err);
+                } else {
+                    if (result.getStatus() == UserCreationResult.STATUS_SUCCESSFUL) {
+                        assignDefaultIcon(result.getUser());
+                    }
+                }
+                super.onCompleted(result, err);
+            };
+        };
+        int flags = 0;
+        if (admin) {
+            if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
+                Log.e(TAG_USER, "Only admin users and system user can create other admins.");
+                sendUserCreationResultFailure(future, UserCreationResult.STATUS_INVALID_REQUEST);
+                return future;
+            }
+            flags = UserInfo.FLAG_ADMIN;
+        }
+        createUser(name, UserInfo.getDefaultUserType(flags), flags, mHalTimeoutMs, future);
+        return future;
+    }
+
+    /**
+     * @see ExperimentalCarUserManager.createPassenger
+     */
+    @Override
+    @Nullable
+    public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
+        checkManageUsersPermission("createPassenger");
+        Objects.requireNonNull(name, "name cannot be null");
+        UserInfo driver = mUserManager.getUserInfo(driverId);
+        if (driver == null) {
+            Log.w(TAG_USER, "the driver is invalid");
+            return null;
+        }
+        if (driver.isGuest()) {
+            Log.w(TAG_USER, "a guest driver cannot create a passenger");
+            return null;
+        }
+        // createPassenger doesn't use user HAL because user HAL doesn't support profile user yet.
+        UserInfo user = mUserManager.createProfileForUser(name,
+                UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
+        if (user == null) {
+            // Couldn't create user, most likely because there are too many.
+            Log.w(TAG_USER, "can't create a profile for user" + driverId);
+            return null;
+        }
+        // Passenger user should be a non-admin user.
+        mCarUserManagerHelper.setDefaultNonAdminRestrictions(user, /* enable= */ true);
+        assignDefaultIcon(user);
+        return user;
+    }
+
+    /**
+     * @see ExperimentalCarUserManager.switchDriver
+     */
+    @Override
+    public void switchDriver(@UserIdInt int driverId, AndroidFuture<UserSwitchResult> receiver) {
+        checkManageUsersPermission("switchDriver");
+        if (UserHelper.isHeadlessSystemUser(driverId)) {
+            // System user doesn't associate with real person, can not be switched to.
+            Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
+            sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
+            return;
+        }
+        int userSwitchable = mUserManager.getUserSwitchability();
+        if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
+            Log.w(TAG_USER, "current process is not allowed to switch user");
+            sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
+            return;
+        }
+        switchUser(driverId, mHalTimeoutMs, receiver);
+    }
+
+    /**
+     * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
+     *
+     * @return the list of {@link UserInfo} who can be a driver on the device.
+     */
+    @Override
+    @NonNull
+    public List<UserInfo> getAllDrivers() {
+        checkManageUsersOrDumpPermission("getAllDrivers");
+        return getUsers((user) -> !UserHelper.isHeadlessSystemUser(user.id) && user.isEnabled()
+                && !user.isManagedProfile() && !user.isEphemeral());
+    }
+
+    /**
+     * Returns all passengers under the given driver.
+     *
+     * @param driverId User id of a driver.
+     * @return the list of {@link UserInfo} who is a passenger under the given driver.
+     */
+    @Override
+    @NonNull
+    public List<UserInfo> getPassengers(@UserIdInt int driverId) {
+        checkManageUsersOrDumpPermission("getPassengers");
+        return getUsers((user) -> {
+            return !UserHelper.isHeadlessSystemUser(user.id) && user.isEnabled()
+                    && user.isManagedProfile() && user.profileGroupId == driverId;
+        });
+    }
+
+    /**
+     * @see CarUserManager.startPassenger
+     */
+    @Override
+    public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
+        checkManageUsersPermission("startPassenger");
+        synchronized (mLockUser) {
+            try {
+                if (!mAm.startUserInBackgroundWithListener(passengerId, null)) {
+                    Log.w(TAG_USER, "could not start passenger");
+                    return false;
+                }
+            } catch (RemoteException e) {
+                // ignore
+                Log.w(TAG_USER, "error while starting passenger", e);
+                return false;
+            }
+            if (!assignUserToOccupantZone(passengerId, zoneId)) {
+                Log.w(TAG_USER, "could not assign passenger to zone");
+                return false;
+            }
+            mLastPassengerId = passengerId;
+        }
+        for (PassengerCallback callback : mPassengerCallbacks) {
+            callback.onPassengerStarted(passengerId, zoneId);
+        }
+        return true;
+    }
+
+    /**
+     * @see CarUserManager.stopPassenger
+     */
+    @Override
+    public boolean stopPassenger(@UserIdInt int passengerId) {
+        checkManageUsersPermission("stopPassenger");
+        return stopPassengerInternal(passengerId, true);
+    }
+
+    private boolean stopPassengerInternal(@UserIdInt int passengerId, boolean checkCurrentDriver) {
+        synchronized (mLockUser) {
+            UserInfo passenger = mUserManager.getUserInfo(passengerId);
+            if (passenger == null) {
+                Log.w(TAG_USER, "passenger " + passengerId + " doesn't exist");
+                return false;
+            }
+            if (mLastPassengerId != passengerId) {
+                Log.w(TAG_USER, "passenger " + passengerId + " hasn't been started");
+                return true;
+            }
+            if (checkCurrentDriver) {
+                int currentUser = ActivityManager.getCurrentUser();
+                if (passenger.profileGroupId != currentUser) {
+                    Log.w(TAG_USER, "passenger " + passengerId
+                            + " is not a profile of the current user");
+                    return false;
+                }
+            }
+            // Passenger is a profile, so cannot be stopped through activity manager.
+            // Instead, activities started by the passenger are stopped and the passenger is
+            // unassigned from the zone.
+            stopAllTasks(passengerId);
+            if (!unassignUserFromOccupantZone(passengerId)) {
+                Log.w(TAG_USER, "could not unassign user from occupant zone");
+                return false;
+            }
+            mLastPassengerId = UserHandle.USER_NULL;
+        }
+        for (PassengerCallback callback : mPassengerCallbacks) {
+            callback.onPassengerStopped(passengerId);
+        }
+        return true;
+    }
+
+    private void stopAllTasks(@UserIdInt int userId) {
+        try {
+            for (StackInfo info : mAm.getAllStackInfos()) {
+                for (int i = 0; i < info.taskIds.length; i++) {
+                    if (info.taskUserIds[i] == userId) {
+                        int taskId = info.taskIds[i];
+                        if (!mAm.removeTask(taskId)) {
+                            Log.w(TAG_USER, "could not remove task " + taskId);
+                        }
+                    }
+                }
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG_USER, "could not get stack info", e);
+        }
+    }
+
+    @Override
+    public void setLifecycleListenerForUid(IResultReceiver listener) {
+        int uid = Binder.getCallingUid();
+        EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
+        checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
+
+        try {
+            listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
+        } catch (RemoteException e) {
+            Log.wtf(TAG_USER, "Cannot listen to death of " + uid);
+        }
+        mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
+    }
+
+    private void onListenerDeath(int uid) {
+        Log.i(TAG_USER, "Removing listeners for uid " + uid + " on binder death");
+        mHandler.post(() -> mAppLifecycleListeners.remove(uid));
+    }
+
+    @Override
+    public void resetLifecycleListenerForUid() {
+        int uid = Binder.getCallingUid();
+        EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
+        checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
+        mHandler.post(() -> mAppLifecycleListeners.remove(uid));
+    }
+
+    @Override
+    public void getInitialUserInfo(int requestType, int timeoutMs,
+            @NonNull IResultReceiver receiver) {
+        EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
+                timeoutMs);
+        Objects.requireNonNull(receiver, "receiver cannot be null");
+        checkManageUsersPermission("getInitialInfo");
+        if (!isUserHalSupported()) {
+            sendResult(receiver, HalCallback.STATUS_HAL_NOT_SUPPORTED, null);
+            return;
+        }
+        UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
+        mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
+            Bundle resultData = null;
+            if (resp != null) {
+                EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP,
+                        status, resp.action, resp.userToSwitchOrCreate.userId,
+                        resp.userToSwitchOrCreate.flags, resp.userNameToCreate, resp.userLocales);
+                switch (resp.action) {
+                    case InitialUserInfoResponseAction.SWITCH:
+                        resultData = new Bundle();
+                        resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
+                        resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
+                        break;
+                    case InitialUserInfoResponseAction.CREATE:
+                        resultData = new Bundle();
+                        resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
+                        resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
+                        resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
+                        break;
+                    case InitialUserInfoResponseAction.DEFAULT:
+                        resultData = new Bundle();
+                        resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
+                        break;
+                    default:
+                        // That's ok, it will be the same as DEFAULT...
+                        Log.w(TAG_USER, "invalid response action on " + resp);
+                }
+            } else {
+                EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
+            }
+            if (resultData != null && !TextUtils.isEmpty(resp.userLocales)) {
+                resultData.putString(BUNDLE_USER_LOCALES, resp.userLocales);
+            }
+
+            sendResult(receiver, status, resultData);
+        });
+    }
+
+    /**
+     * Gets the initial foreground user after the device boots or resumes from suspension.
+     *
+     * <p>When the OEM supports the User HAL, the initial user won't be available until the HAL
+     * returns the initial value to {@code CarService} - if HAL takes too long or times out, this
+     * method returns {@code null}.
+     *
+     * <p>If the HAL eventually times out, {@code CarService} will fallback to its default behavior
+     * (like switching to the last active user), and this method will return the result of such
+     * operation.
+     *
+     * <p>Notice that if {@code CarService} crashes, subsequent calls to this method will return
+     * {@code null}.
+     *
+     * @hide
+     */
+    @Nullable
+    public UserInfo getInitialUser() {
+        checkInteractAcrossUsersPermission("getInitialUser");
+        synchronized (mLockUser) {
+            return mInitialUser;
+        }
+    }
+
+    // TODO(b/150413515): temporary method called by ICarImpl.setInitialUser(int userId), as for
+    // some reason passing the whole UserInfo through a raw binder transaction  is not working.
+    /**
+     * Sets the initial foreground user after the device boots or resumes from suspension.
+     */
+    public void setInitialUser(@UserIdInt int userId) {
+        UserInfo initialUser = userId == UserHandle.USER_NULL ? null
+                : mUserManager.getUserInfo(userId);
+        setInitialUser(initialUser);
+    }
+
+    /**
+     * Sets the initial foreground user after the device boots or resumes from suspension.
+     */
+    public void setInitialUser(@Nullable UserInfo user) {
+        EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER,
+                user == null ? UserHandle.USER_NULL : user.id);
+        synchronized (mLockUser) {
+            mInitialUser = user;
+        }
+        if (user == null) {
+            // This mean InitialUserSetter failed and could not fallback, so the initial user was
+            // not switched (and most likely is SYSTEM_USER).
+            // TODO(b/153104378): should we set it to ActivityManager.getCurrentUser() instead?
+            Log.wtf(TAG_USER, "Initial user set to null");
+        }
+    }
+
+    /**
+     * Calls the User HAL to get the initial user info.
+     *
+     * @param requestType type as defined by {@code InitialUserInfoRequestType}.
+     * @param callback callback to receive the results.
+     */
+    public void getInitialUserInfo(int requestType,
+            HalCallback<InitialUserInfoResponse> callback) {
+        EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType,
+                mHalTimeoutMs);
+        Objects.requireNonNull(callback, "callback cannot be null");
+        checkManageUsersPermission("getInitialUserInfo");
+        if (!isUserHalSupported()) {
+            callback.onResponse(HalCallback.STATUS_HAL_NOT_SUPPORTED, null);
+            return;
+        }
+        UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
+        mHal.getInitialUserInfo(requestType, mHalTimeoutMs, usersInfo, callback);
+    }
+
+    /**
+     * Calls the {@link UserHalService} and {@link IActivityManager} for user switch.
+     *
+     * <p>
+     * When everything works well, the workflow is:
+     * <ol>
+     *   <li> {@link UserHalService} is called for HAL user switch with ANDROID_SWITCH request
+     *   type, current user id, target user id, and a callback.
+     *   <li> HAL called back with SUCCESS.
+     *   <li> {@link IActivityManager} is called for Android user switch.
+     *   <li> Receiver would receive {@code STATUS_SUCCESSFUL}.
+     *   <li> Once user is unlocked, {@link UserHalService} is again called with ANDROID_POST_SWITCH
+     *   request type, current user id, and target user id. In this case, the current and target
+     *   user IDs would be same.
+     * <ol/>
+     *
+     * <p>
+     * Corner cases:
+     * <ul>
+     *   <li> If target user is already the current user, no user switch is performed and receiver
+     *   would receive {@code STATUS_OK_USER_ALREADY_IN_FOREGROUND} right away.
+     *   <li> If HAL user switch call fails, no Android user switch. Receiver would receive
+     *   {@code STATUS_HAL_INTERNAL_FAILURE}.
+     *   <li> If HAL user switch call is successful, but android user switch call fails,
+     *   {@link UserHalService} is again called with request type POST_SWITCH, current user id, and
+     *   target user id, but in this case the current and target user IDs would be different.
+     *   <li> If another user switch request for the same target user is received while previous
+     *   request is in process, receiver would receive
+     *   {@code STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO} for the new request right away.
+     *   <li> If a user switch request is received while another user switch request for different
+     *   target user is in process, the previous request would be abandoned and new request will be
+     *   processed. No POST_SWITCH would be sent for the previous request.
+     * <ul/>
+     *
+     * @param targetUserId - target user Id
+     * @param timeoutMs - timeout for HAL to wait
+     * @param receiver - receiver for the results
+     */
+    @Override
+    public void switchUser(@UserIdInt int targetUserId, int timeoutMs,
+            @NonNull AndroidFuture<UserSwitchResult> receiver) {
+        EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, targetUserId, timeoutMs);
+        checkManageUsersPermission("switchUser");
+        Objects.requireNonNull(receiver);
+        UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
+        Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
+
+        int currentUser = ActivityManager.getCurrentUser();
+        if (currentUser == targetUserId) {
+            if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+                Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
+            }
+            int resultStatus = UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND;
+            sendUserSwitchResult(receiver, resultStatus);
+            return;
+        }
+
+        // If User Hal is not supported, just android user switch.
+        if (!isUserHalSupported()) {
+            try {
+                if (mAm.switchUser(targetUserId)) {
+                    sendUserSwitchResult(receiver, UserSwitchResult.STATUS_SUCCESSFUL);
+                    return;
+                }
+            } catch (RemoteException e) {
+                // ignore
+                Log.w(TAG_USER,
+                        "error while switching user " + targetUser.toFullString(), e);
+            }
+            sendUserSwitchResult(receiver, UserSwitchResult.STATUS_ANDROID_FAILURE);
+            return;
+        }
+
+        synchronized (mLockUser) {
+            if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+                Log.d(TAG_USER, "switchUser(" + targetUserId + "): currentuser=" + currentUser
+                        + ", mUserIdForUserSwitchInProcess=" + mUserIdForUserSwitchInProcess);
+            }
+
+            // If there is another request for the same target user, return another request in
+            // process, else {@link mUserIdForUserSwitchInProcess} is updated and {@link
+            // mRequestIdForUserSwitchInProcess} is reset. It is possible that there may be another
+            // user switch request in process for different target user, but that request is now
+            // ignored.
+            if (mUserIdForUserSwitchInProcess == targetUserId) {
+                if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+                    Log.d(TAG_USER,
+                            "Another user switch request in process for the requested target user: "
+                                    + targetUserId);
+                }
+
+                int resultStatus = UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO;
+                sendUserSwitchResult(receiver, resultStatus);
+                return;
+            }
+            else {
+                mUserIdForUserSwitchInProcess = targetUserId;
+                mRequestIdForUserSwitchInProcess = 0;
+            }
+        }
+
+        UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
+        SwitchUserRequest request = createUserSwitchRequest(targetUserId, usersInfo);
+
+        mHal.switchUser(request, timeoutMs, (status, resp) -> {
+            if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+                Log.d(TAG, "switch response: status="
+                        + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
+            }
+
+            int resultStatus = UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE;
+
+            synchronized (mLockUser) {
+                if (status != HalCallback.STATUS_OK) {
+                    EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status);
+                    Log.w(TAG, "invalid callback status ("
+                            + UserHalHelper.halCallbackStatusToString(status) + ") for response "
+                            + resp);
+                    sendUserSwitchResult(receiver, resultStatus);
+                    mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
+                    return;
+                }
+
+                EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, status, resp.status,
+                        resp.errorMessage);
+
+                if (mUserIdForUserSwitchInProcess != targetUserId) {
+                    // Another user switch request received while HAL responded. No need to process
+                    // this request further
+                    if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+                        Log.d(TAG_USER, "Another user switch received while HAL responsed. Request "
+                                + "abondoned for : " + targetUserId + ". Current user in process: "
+                                + mUserIdForUserSwitchInProcess);
+                    }
+                    resultStatus =
+                            UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST;
+                    sendUserSwitchResult(receiver, resultStatus);
+                    mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
+                    return;
+                }
+
+                switch (resp.status) {
+                    case SwitchUserStatus.SUCCESS:
+                        boolean switched;
+                        try {
+                            switched = mAm.switchUser(targetUserId);
+                            if (switched) {
+                                sendUserSwitchUiCallback(targetUserId);
+                                resultStatus = UserSwitchResult.STATUS_SUCCESSFUL;
+                                mRequestIdForUserSwitchInProcess = resp.requestId;
+                            } else {
+                                resultStatus = UserSwitchResult.STATUS_ANDROID_FAILURE;
+                                postSwitchHalResponse(resp.requestId, targetUserId);
+                            }
+                        } catch (RemoteException e) {
+                            // ignore
+                            Log.w(TAG_USER,
+                                    "error while switching user " + targetUser.toFullString(), e);
+                        }
+                        break;
+                    case SwitchUserStatus.FAILURE:
+                        // HAL failed to switch user
+                        resultStatus = UserSwitchResult.STATUS_HAL_FAILURE;
+                        break;
+                    default:
+                        // Shouldn't happen because UserHalService validates the status
+                        Log.wtf(TAG, "Received invalid user switch status from HAL: " + resp);
+                }
+
+                if (mRequestIdForUserSwitchInProcess == 0) {
+                    mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
+                }
+            }
+            sendUserSwitchResult(receiver, resultStatus, resp.errorMessage);
+        });
+    }
+
+    @Override
+    public UserRemovalResult removeUser(@UserIdInt int userId) {
+        checkManageUsersPermission("removeUser");
+        EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_REQ, userId);
+        // If the requested user is the current user, return error.
+        if (ActivityManager.getCurrentUser() == userId) {
+            return logAndGetResults(userId,
+                    UserRemovalResult.STATUS_TARGET_USER_IS_CURRENT_USER);
+        }
+
+        // If requested user is the only admin user, return error.
+        UserInfo userInfo = mUserManager.getUserInfo(userId);
+        if (userInfo == null) {
+            return logAndGetResults(userId, UserRemovalResult.STATUS_USER_DOES_NOT_EXIST);
+        }
+
+        android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
+                new android.hardware.automotive.vehicle.V2_0.UserInfo();
+        halUser.userId = userInfo.id;
+        halUser.flags = UserHalHelper.convertFlags(userInfo);
+        UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
+
+        // Do not delete last admin user.
+        if (UserHalHelper.isAdmin(halUser.flags)) {
+            int size = usersInfo.existingUsers.size();
+            int totalAdminUsers = 0;
+            for (int i = 0; i < size; i++) {
+                if (UserHalHelper.isAdmin(usersInfo.existingUsers.get(i).flags)) {
+                    totalAdminUsers++;
+                }
+            }
+            if (totalAdminUsers == 1) {
+                return logAndGetResults(userId,
+                        UserRemovalResult.STATUS_TARGET_USER_IS_LAST_ADMIN_USER);
+            }
+        }
+
+        // First remove user from android and then remove from HAL because HAL remove user is one
+        // way call.
+        if (!mUserManager.removeUser(userId)) {
+            return logAndGetResults(userId, UserRemovalResult.STATUS_ANDROID_FAILURE);
+        }
+
+        if (isUserHalSupported()) {
+            RemoveUserRequest request = new RemoveUserRequest();
+            request.removedUserInfo = halUser;
+            request.usersInfo = UserHalHelper.newUsersInfo(mUserManager);
+            mHal.removeUser(request);
+        }
+
+        return logAndGetResults(userId, UserRemovalResult.STATUS_SUCCESSFUL);
+    }
+
+    private UserRemovalResult logAndGetResults(@UserIdInt int userId,
+            @UserRemovalResult.Status int result) {
+        EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_RESP, userId, result);
+        return new UserRemovalResult(result);
+    }
+
+    private void sendUserSwitchUiCallback(@UserIdInt int targetUserId) {
+        if (mUserSwitchUiReceiver == null) {
+            Log.w(TAG_USER, "No User switch UI receiver.");
+            return;
+        }
+
+        EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_UI_REQ, targetUserId);
+        try {
+            mUserSwitchUiReceiver.send(targetUserId, null);
+        } catch (RemoteException e) {
+            Log.e(TAG_USER, "Error calling user switch UI receiver.", e);
+        }
+    }
+
+    @Override
+    public void createUser(@Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
+            int timeoutMs, @NonNull AndroidFuture<UserCreationResult> receiver) {
+        Objects.requireNonNull(userType, "user type cannot be null");
+        Objects.requireNonNull(receiver, "receiver cannot be null");
+        checkManageOrCreateUsersPermission("createUser");
+        EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_REQ, UserHelper.safeName(name),
+                userType, flags, timeoutMs);
+
+        UserInfo newUser;
+        try {
+            newUser = mUserManager.createUser(name, userType, flags);
+            if (newUser == null) {
+                Log.w(TAG, "um.createUser() returned null for user of type " + userType
+                        + " and flags " + UserInfo.flagsToString(flags));
+                sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
+                return;
+            }
+            if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+                Log.d(TAG, "Created user: " + newUser.toFullString());
+            }
+            EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_CREATED, newUser.id,
+                    UserHelper.safeName(newUser.name), newUser.userType, newUser.flags);
+        } catch (RuntimeException e) {
+            Log.e(TAG_USER, "Error creating user of type " + userType + " and flags"
+                    + UserInfo.flagsToString(flags), e);
+            sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
+            return;
+        }
+
+        if (!isUserHalSupported()) {
+            sendUserCreationResult(receiver, UserCreationResult.STATUS_SUCCESSFUL, newUser, null);
+            return;
+        }
+
+        CreateUserRequest request = new CreateUserRequest();
+        request.usersInfo = UserHalHelper.newUsersInfo(mUserManager);
+        if (!TextUtils.isEmpty(name)) {
+            request.newUserName = name;
+        }
+        request.newUserInfo.userId = newUser.id;
+        request.newUserInfo.flags = UserHalHelper.convertFlags(newUser);
+        if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+            Log.d(TAG, "Create user request: " + request);
+        }
+
+        try {
+            mHal.createUser(request, timeoutMs, (status, resp) -> {
+                int resultStatus = UserCreationResult.STATUS_HAL_INTERNAL_FAILURE;
+                if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+                    Log.d(TAG, "createUserResponse: status="
+                            + UserHalHelper.halCallbackStatusToString(status) + ", resp=" + resp);
+                }
+                UserInfo user = null; // user returned in the result
+                if (status != HalCallback.STATUS_OK) {
+                    Log.w(TAG, "invalid callback status ("
+                            + UserHalHelper.halCallbackStatusToString(status) + ") for response "
+                            + resp);
+                    EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status,
+                            resultStatus, resp.errorMessage);
+                    removeUser(newUser, "HAL call failed with "
+                            + UserHalHelper.halCallbackStatusToString(status));
+                    sendUserCreationResult(receiver, resultStatus, user, /* errorMsg= */ null);
+                    return;
+                }
+
+                switch (resp.status) {
+                    case CreateUserStatus.SUCCESS:
+                        resultStatus = UserCreationResult.STATUS_SUCCESSFUL;
+                        user = newUser;
+                        break;
+                    case CreateUserStatus.FAILURE:
+                        // HAL failed to switch user
+                        resultStatus = UserCreationResult.STATUS_HAL_FAILURE;
+                        break;
+                    default:
+                        // Shouldn't happen because UserHalService validates the status
+                        Log.wtf(TAG, "Received invalid user switch status from HAL: " + resp);
+                }
+                EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status,
+                        resultStatus, resp.errorMessage);
+                if (user == null) {
+                    removeUser(newUser, "HAL returned "
+                            + UserCreationResult.statusToString(resultStatus));
+                }
+                sendUserCreationResult(receiver, resultStatus, user, resp.errorMessage);
+            });
+        } catch (Exception e) {
+            Log.w(TAG, "mHal.createUser(" + request + ") failed", e);
+            removeUser(newUser, "mHal.createUser() failed");
+            sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
+        }
+    }
+
+    private void removeUser(@NonNull UserInfo user, @NonNull String reason) {
+        EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_REMOVED, user.id, reason);
+        try {
+            if (!mUserManager.removeUser(user.id)) {
+                Log.w(TAG, "Failed to remove user " + user.toFullString());
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to remove user " + user.toFullString(), e);
+        }
+    }
+
+    @Override
+    public UserIdentificationAssociationResponse getUserIdentificationAssociation(int[] types) {
+        if (!isUserHalUserAssociationSupported()) {
+            return UserIdentificationAssociationResponse.forFailure(VEHICLE_HAL_NOT_SUPPORTED);
+        }
+
+        Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
+        checkManageUsersPermission("getUserIdentificationAssociation");
+
+        int uid = getCallingUid();
+        int userId = UserHandle.getUserId(uid);
+        EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_REQ, uid, userId);
+
+        UserIdentificationGetRequest request = new UserIdentificationGetRequest();
+        request.userInfo.userId = userId;
+        request.userInfo.flags = getHalUserInfoFlags(userId);
+
+        request.numberAssociationTypes = types.length;
+        for (int i = 0; i < types.length; i++) {
+            request.associationTypes.add(types[i]);
+        }
+
+        UserIdentificationResponse halResponse = mHal.getUserAssociation(request);
+        if (halResponse == null) {
+            Log.w(TAG, "getUserIdentificationAssociation(): HAL returned null for "
+                    + Arrays.toString(types));
+            return UserIdentificationAssociationResponse.forFailure();
+        }
+
+        int[] values = new int[halResponse.associations.size()];
+        for (int i = 0; i < values.length; i++) {
+            values[i] = halResponse.associations.get(i).value;
+        }
+        EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_RESP, values.length);
+
+        return UserIdentificationAssociationResponse.forSuccess(values, halResponse.errorMessage);
+    }
+
+    @Override
+    public void setUserIdentificationAssociation(int timeoutMs, int[] types, int[] values,
+            AndroidFuture<UserIdentificationAssociationResponse> result) {
+        if (!isUserHalUserAssociationSupported()) {
+            result.complete(
+                    UserIdentificationAssociationResponse.forFailure(VEHICLE_HAL_NOT_SUPPORTED));
+            return;
+        }
+
+        Preconditions.checkArgument(!ArrayUtils.isEmpty(types), "must have at least one type");
+        Preconditions.checkArgument(!ArrayUtils.isEmpty(values), "must have at least one value");
+        if (types.length != values.length) {
+            throw new IllegalArgumentException("types (" + Arrays.toString(types) + ") and values ("
+                    + Arrays.toString(values) + ") should have the same length");
+        }
+        checkManageUsersPermission("setUserIdentificationAssociation");
+
+        int uid = getCallingUid();
+        int userId = UserHandle.getUserId(uid);
+        EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_REQ, uid, userId, types.length);
+
+        UserIdentificationSetRequest request = new UserIdentificationSetRequest();
+        request.userInfo.userId = userId;
+        request.userInfo.flags = getHalUserInfoFlags(userId);
+
+        request.numberAssociations = types.length;
+        for (int i = 0; i < types.length; i++) {
+            UserIdentificationSetAssociation association = new UserIdentificationSetAssociation();
+            association.type = types[i];
+            association.value = values[i];
+            request.associations.add(association);
+        }
+
+        mHal.setUserAssociation(timeoutMs, request, (status, resp) -> {
+            if (status != HalCallback.STATUS_OK) {
+                Log.w(TAG, "setUserIdentificationAssociation(): invalid callback status ("
+                        + UserHalHelper.halCallbackStatusToString(status) + ") for response "
+                        + resp);
+                if (resp == null || TextUtils.isEmpty(resp.errorMessage)) {
+                    EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0);
+                    result.complete(UserIdentificationAssociationResponse.forFailure());
+                    return;
+                }
+                EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, 0,
+                        resp.errorMessage);
+                result.complete(
+                        UserIdentificationAssociationResponse.forFailure(resp.errorMessage));
+                return;
+            }
+            int respSize = resp.associations.size();
+            EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, respSize,
+                    resp.errorMessage);
+
+            int[] responseTypes = new int[respSize];
+            for (int i = 0; i < respSize; i++) {
+                responseTypes[i] = resp.associations.get(i).value;
+            }
+            UserIdentificationAssociationResponse response = UserIdentificationAssociationResponse
+                    .forSuccess(responseTypes, resp.errorMessage);
+            if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+                Log.d(TAG, "setUserIdentificationAssociation(): resp= " + resp
+                        + ", converted=" + response);
+            }
+            result.complete(response);
+        });
+    }
+
+    /**
+     * Gets the User HAL flags for the given user.
+     *
+     * @throws IllegalArgumentException if the user does not exist.
+     */
+    private int getHalUserInfoFlags(@UserIdInt int userId) {
+        UserInfo user = mUserManager.getUserInfo(userId);
+        Preconditions.checkArgument(user != null, "no user for id %d", userId);
+        return UserHalHelper.convertFlags(user);
+    }
+
+    private void sendResult(@NonNull IResultReceiver receiver, int resultCode,
+            @Nullable Bundle resultData) {
+        try {
+            receiver.send(resultCode, resultData);
+        } catch (RemoteException e) {
+            // ignore
+            Log.w(TAG_USER, "error while sending results", e);
+        }
+    }
+
+    private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
+            @UserSwitchResult.Status int status) {
+        sendUserSwitchResult(receiver, status, /* errorMessage= */ null);
+    }
+
+    private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
+            @UserSwitchResult.Status int status, @Nullable String errorMessage) {
+        receiver.complete(new UserSwitchResult(status, errorMessage));
+    }
+
+    private void sendUserCreationResultFailure(@NonNull AndroidFuture<UserCreationResult> receiver,
+            @UserCreationResult.Status int status) {
+        sendUserCreationResult(receiver, status, /* user= */ null, /* errorMessage= */ null);
+    }
+
+    private void sendUserCreationResult(@NonNull AndroidFuture<UserCreationResult> receiver,
+            @UserCreationResult.Status int status, @NonNull UserInfo user,
+            @Nullable String errorMessage) {
+        if (TextUtils.isEmpty(errorMessage)) {
+            errorMessage = null;
+        }
+        receiver.complete(new UserCreationResult(status, user, errorMessage));
+    }
+
+    /**
+     * Calls activity manager for user switch.
+     *
+     * <p><b>NOTE</b> This method is meant to be called just by UserHalService.
+     *
+     * @param requestId for the user switch request
+     * @param targetUserId of the target user
+     *
+     * @hide
+     */
+    public void switchAndroidUserFromHal(int requestId, @UserIdInt int targetUserId) {
+        EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_FROM_HAL_REQ, requestId,
+                targetUserId);
+        Log.i(TAG_USER, "User hal requested a user switch. Target user id " + targetUserId);
+
+        try {
+            boolean result = mAm.switchUser(targetUserId);
+            if (result) {
+                updateUserSwitchInProcess(requestId, targetUserId);
+            } else {
+                postSwitchHalResponse(requestId, targetUserId);
+            }
+        } catch (RemoteException e) {
+            // ignore
+            Log.w(TAG_USER, "error while switching user " + targetUserId, e);
+        }
+    }
+
+    private void updateUserSwitchInProcess(int requestId, @UserIdInt int targetUserId) {
+        synchronized (mLockUser) {
+            if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
+                // Some other user switch is in process.
+                if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+                    Log.d(TAG_USER, "User switch for user: " + mUserIdForUserSwitchInProcess
+                            + " is in process. Abandoning it as a new user switch is requested"
+                            + " for the target user: " + targetUserId);
+                }
+            }
+            mUserIdForUserSwitchInProcess = targetUserId;
+            mRequestIdForUserSwitchInProcess = requestId;
+        }
+    }
+
+    private void postSwitchHalResponse(int requestId, @UserIdInt int targetUserId) {
+        if (!isUserHalSupported()) return;
+
+        UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
+        EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, requestId,
+                targetUserId, usersInfo.currentUser.userId);
+        SwitchUserRequest request = createUserSwitchRequest(targetUserId, usersInfo);
+        request.requestId = requestId;
+        mHal.postSwitchResponse(request);
+    }
+
+    private SwitchUserRequest createUserSwitchRequest(@UserIdInt int targetUserId,
+            @NonNull UsersInfo usersInfo) {
+        UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
+        android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
+                new android.hardware.automotive.vehicle.V2_0.UserInfo();
+        halTargetUser.userId = targetUser.id;
+        halTargetUser.flags = UserHalHelper.convertFlags(targetUser);
+        SwitchUserRequest request = new SwitchUserRequest();
+        request.targetUser = halTargetUser;
+        request.usersInfo = usersInfo;
+        return request;
+    }
+
+    /**
+     * Checks if the User HAL is supported.
+     */
+    public boolean isUserHalSupported() {
+        return mHal.isSupported();
+    }
+
+    /**
+     * Checks if the User HAL user association is supported.
+     */
+    @Override
+    public boolean isUserHalUserAssociationSupported() {
+        return mHal.isUserAssociationSupported();
+    }
+
+    /**
+     * Sets a callback which is invoked before user switch.
+     *
+     * <p>
+     * This method should only be called by the Car System UI. The purpose of this call is to notify
+     * Car System UI to show the user switch UI before the user switch.
+     */
+    @Override
+    public void setUserSwitchUiCallback(@NonNull IResultReceiver receiver) {
+        checkManageUsersPermission("setUserSwitchUiCallback");
+
+        // Confirm that caller is system UI.
+        String systemUiPackageName = getSystemUiPackageName();
+        if (systemUiPackageName == null) {
+            throw new IllegalStateException("System UI package not found.");
+        }
+
+        try {
+            int systemUiUid = mContext
+                    .createContextAsUser(UserHandle.SYSTEM, /* flags= */ 0).getPackageManager()
+                    .getPackageUid(systemUiPackageName, PackageManager.MATCH_SYSTEM_ONLY);
+            int callerUid = Binder.getCallingUid();
+            if (systemUiUid != callerUid) {
+                throw new SecurityException("Invalid caller. Only" + systemUiPackageName
+                        + " is allowed to make this call");
+            }
+        } catch (NameNotFoundException e) {
+            throw new IllegalStateException("Package " + systemUiPackageName + " not found.");
+        }
+
+        mUserSwitchUiReceiver = receiver;
+    }
+
+    // TODO(157082995): This information can be taken from
+    // PackageManageInternalImpl.getSystemUiServiceComponent
+    @Nullable
+    private String getSystemUiPackageName() {
+        try {
+            ComponentName componentName = ComponentName.unflattenFromString(mContext.getResources()
+                    .getString(com.android.internal.R.string.config_systemUIServiceComponent));
+            return componentName.getPackageName();
+        } catch (RuntimeException e) {
+            Log.w(TAG_USER, "error while getting system UI package name.", e);
+            return null;
+        }
     }
 
     private void updateDefaultUserRestriction() {
         // We want to set restrictions on system and guest users only once. These are persisted
         // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
         if (Settings.Global.getInt(mContext.getContentResolver(),
-                CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) == 0) {
-            // Only apply the system user restrictions if the system user is headless.
-            if (mCarUserManagerHelper.isHeadlessSystemUser()) {
-                setSystemUserRestrictions();
-            }
-            mCarUserManagerHelper.initDefaultGuestRestrictions();
-            Settings.Global.putInt(mContext.getContentResolver(),
-                    CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
+                CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
+            return;
         }
+        // Only apply the system user restrictions if the system user is headless.
+        if (UserManager.isHeadlessSystemUserMode()) {
+            setSystemUserRestrictions();
+        }
+        Settings.Global.putInt(mContext.getContentResolver(),
+                CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
     }
 
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "onReceive " + intent);
-        }
-
-        if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
-            // Update last active user if the switched-to user is a persistent, non-system user.
-            final int currentUser = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
-            if (currentUser > UserHandle.USER_SYSTEM) {
-                mCarUserManagerHelper.setLastActiveUser(currentUser);
-            }
-        }
-    }
-
-    /** Add callback to listen to user activity events. */
-    public void addUserCallback(UserCallback callback) {
-        mUserCallbacks.add(callback);
-    }
-
-    /** Removes previously added callback to listen user events. */
-    public void removeUserCallback(UserCallback callback) {
-        mUserCallbacks.remove(callback);
+    private boolean isPersistentUser(@UserIdInt int userId) {
+        return !mUserManager.getUserInfo(userId).isEphemeral();
     }
 
     /**
-     * Set user lock / unlocking status. This is coming from system server through ICar binder call.
-     * @param userHandle Handle of user
-     * @param unlocked unlocked (=true) or locked (=false)
+     * Adds a new {@link UserLifecycleListener} to listen to user activity events.
      */
-    public void setUserLockStatus(int userHandle, boolean unlocked) {
-        for (UserCallback callback : mUserCallbacks) {
-            callback.onUserLockChanged(userHandle, unlocked);
+    public void addUserLifecycleListener(@NonNull UserLifecycleListener listener) {
+        Objects.requireNonNull(listener, "listener cannot be null");
+        mHandler.post(() -> mUserLifecycleListeners.add(listener));
+    }
+
+    /**
+     * Removes previously added {@link UserLifecycleListener}.
+     */
+    public void removeUserLifecycleListener(@NonNull UserLifecycleListener listener) {
+        Objects.requireNonNull(listener, "listener cannot be null");
+        mHandler.post(() -> mUserLifecycleListeners.remove(listener));
+    }
+
+    /** Adds callback to listen to passenger activity events. */
+    public void addPassengerCallback(@NonNull PassengerCallback callback) {
+        Objects.requireNonNull(callback, "callback cannot be null");
+        mPassengerCallbacks.add(callback);
+    }
+
+    /** Removes previously added callback to listen passenger events. */
+    public void removePassengerCallback(@NonNull PassengerCallback callback) {
+        Objects.requireNonNull(callback, "callback cannot be null");
+        mPassengerCallbacks.remove(callback);
+    }
+
+    /** Sets the implementation of ZoneUserBindingHelper. */
+    public void setZoneUserBindingHelper(@NonNull ZoneUserBindingHelper helper) {
+        synchronized (mLockHelper) {
+            mZoneUserBindingHelper = helper;
         }
-        if (!unlocked) { // nothing else to do when it is locked back.
-            return;
-        }
+    }
+
+    private void onUserUnlocked(@UserIdInt int userId) {
         ArrayList<Runnable> tasks = null;
-        synchronized (mLock) {
-            if (userHandle == UserHandle.USER_SYSTEM) {
+        synchronized (mLockUser) {
+            sendPostSwitchToHalLocked(userId);
+            if (userId == UserHandle.USER_SYSTEM) {
                 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
                     updateDefaultUserRestriction();
                     tasks = new ArrayList<>(mUser0UnlockTasks);
                     mUser0UnlockTasks.clear();
-                    mUser0Unlocked = unlocked;
+                    mUser0Unlocked = true;
                 }
             } else { // none user0
-                Integer user = userHandle;
-                if (mCarUserManagerHelper.isPersistentUser(userHandle)) {
+                Integer user = userId;
+                if (isPersistentUser(userId)) {
                     // current foreground user should stay in top priority.
-                    if (userHandle == mCarUserManagerHelper.getCurrentForegroundUserId()) {
+                    if (userId == ActivityManager.getCurrentUser()) {
                         mBackgroundUsersToRestart.remove(user);
                         mBackgroundUsersToRestart.add(0, user);
                     }
                     // -1 for user 0
                     if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
-                        final int userToDrop = mBackgroundUsersToRestart.get(
+                        int userToDrop = mBackgroundUsersToRestart.get(
                                 mBackgroundUsersToRestart.size() - 1);
-                        Log.i(TAG, "New user unlocked:" + userHandle
+                        Log.i(TAG_USER, "New user unlocked:" + userId
                                 + ", dropping least recently user from restart list:" + userToDrop);
                         // Drop the least recently used user.
                         mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
@@ -227,7 +1463,7 @@
             }
         }
         if (tasks != null && tasks.size() > 0) {
-            Log.d(TAG, "User0 unlocked, run queued tasks:" + tasks.size());
+            Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
             for (Runnable r : tasks) {
                 r.run();
             }
@@ -235,19 +1471,21 @@
     }
 
     /**
-     * Start all background users that were active in system.
+     * Starts all background users that were active in system.
+     *
      * @return list of background users started successfully.
      */
+    @NonNull
     public ArrayList<Integer> startAllBackgroundUsers() {
         ArrayList<Integer> users;
-        synchronized (mLock) {
+        synchronized (mLockUser) {
             users = new ArrayList<>(mBackgroundUsersToRestart);
             mBackgroundUsersRestartedHere.clear();
             mBackgroundUsersRestartedHere.addAll(mBackgroundUsersToRestart);
         }
         ArrayList<Integer> startedUsers = new ArrayList<>();
         for (Integer user : users) {
-            if (user == mCarUserManagerHelper.getCurrentForegroundUserId()) {
+            if (user == ActivityManager.getCurrentUser()) {
                 continue;
             }
             try {
@@ -258,7 +1496,7 @@
                     } else if (mAm.unlockUser(user, null, null, null)) {
                         startedUsers.add(user);
                     } else { // started but cannot unlock
-                        Log.w(TAG, "Background user started but cannot be unlocked:" + user);
+                        Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
                         if (mUserManager.isUserRunning(user)) {
                             // add to started list so that it can be stopped later.
                             startedUsers.add(user);
@@ -267,10 +1505,11 @@
                 }
             } catch (RemoteException e) {
                 // ignore
+                Log.w(TAG_USER, "error while starting user in background", e);
             }
         }
         // Keep only users that were re-started in mBackgroundUsersRestartedHere
-        synchronized (mLock) {
+        synchronized (mLockUser) {
             ArrayList<Integer> usersToRemove = new ArrayList<>();
             for (Integer user : mBackgroundUsersToRestart) {
                 if (!startedUsers.contains(user)) {
@@ -283,55 +1522,212 @@
     }
 
     /**
-     * Stop all background users that were active in system.
-     * @return true if stopping succeeds.
+     * Stops all background users that were active in system.
+     *
+     * @return whether stopping succeeds.
      */
-    public boolean stopBackgroundUser(int userId) {
+    public boolean stopBackgroundUser(@UserIdInt int userId) {
         if (userId == UserHandle.USER_SYSTEM) {
             return false;
         }
-        if (userId == mCarUserManagerHelper.getCurrentForegroundUserId()) {
-            Log.i(TAG, "stopBackgroundUser, already a fg user:" + userId);
+        if (userId == ActivityManager.getCurrentUser()) {
+            Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
             return false;
         }
         try {
-            int r = mAm.stopUser(userId, true, null);
+            int r = mAm.stopUserWithDelayedLocking(userId, true, null);
             if (r == ActivityManager.USER_OP_SUCCESS) {
-                synchronized (mLock) {
+                synchronized (mLockUser) {
                     Integer user = userId;
                     mBackgroundUsersRestartedHere.remove(user);
                 }
             } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
                 return false;
             } else {
-                Log.i(TAG, "stopBackgroundUser failed, user:" + userId + " err:" + r);
+                Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
                 return false;
             }
         } catch (RemoteException e) {
             // ignore
+            Log.w(TAG_USER, "error while stopping user", e);
         }
         return true;
     }
 
     /**
-     * Called when new foreground user started to boot.
-     *
-     * @param userHandle user handle of new user
+     * Notifies all registered {@link UserLifecycleListener} with the event passed as argument.
      */
-    public void onSwitchUser(int userHandle) {
-        for (UserCallback callback : mUserCallbacks) {
-            callback.onSwitchUser(userHandle);
+    public void onUserLifecycleEvent(@UserLifecycleEventType int eventType, long timestampMs,
+            @UserIdInt int fromUserId, @UserIdInt int toUserId) {
+        int userId = toUserId;
+
+        // Handle special cases first...
+        if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
+            onUserSwitching(fromUserId, toUserId);
+        } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
+            onUserUnlocked(userId);
+        }
+
+        // ...then notify listeners.
+        UserLifecycleEvent event = new UserLifecycleEvent(eventType, fromUserId, userId);
+
+        mHandler.post(() -> {
+            handleNotifyServiceUserLifecycleListeners(event);
+            handleNotifyAppUserLifecycleListeners(event);
+        });
+
+        if (timestampMs != 0) {
+            // Finally, update metrics.
+            mUserMetrics.onEvent(eventType, timestampMs, fromUserId, toUserId);
         }
     }
 
     /**
-     * Run give runnable when user 0 is unlocked. If user 0 is already unlocked, it is
+     * Sets the first user unlocking metrics.
+     */
+    public void onFirstUserUnlocked(@UserIdInt int userId, long timestampMs, long duration,
+            int halResponseTime) {
+        mUserMetrics.logFirstUnlockedUser(userId, timestampMs, duration, halResponseTime);
+    }
+
+    private void sendPostSwitchToHalLocked(@UserIdInt int userId) {
+        if (mUserIdForUserSwitchInProcess == UserHandle.USER_NULL
+                || mUserIdForUserSwitchInProcess != userId
+                || mRequestIdForUserSwitchInProcess == 0) {
+            if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+                Log.d(TAG_USER, "No user switch request Id. No android post switch sent.");
+            }
+            return;
+        }
+        postSwitchHalResponse(mRequestIdForUserSwitchInProcess, mUserIdForUserSwitchInProcess);
+        mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
+        mRequestIdForUserSwitchInProcess = 0;
+    }
+
+    private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
+        int listenersSize = mAppLifecycleListeners.size();
+        if (listenersSize == 0) {
+            if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+                Log.d(TAG_USER, "No app listener to be notified of " + event);
+            }
+            return;
+        }
+        // Must use a different TimingsTraceLog because it's another thread
+        if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+            Log.d(TAG_USER, "Notifying " + listenersSize + " app listeners of " + event);
+        }
+        int userId = event.getUserId();
+        TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
+        int eventType = event.getEventType();
+        t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + eventType);
+        for (int i = 0; i < listenersSize; i++) {
+            int uid = mAppLifecycleListeners.keyAt(i);
+
+            IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
+            Bundle data = new Bundle();
+            data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, eventType);
+
+            int fromUserId = event.getPreviousUserId();
+            if (fromUserId != UserHandle.USER_NULL) {
+                data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUserId);
+            }
+
+            if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+                Log.d(TAG_USER, "Notifying listener for uid " + uid);
+            }
+            EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_APP_LIFECYCLE_LISTENER,
+                    uid, eventType, fromUserId, userId);
+            try {
+                t.traceBegin("notify-app-listener-uid-" + uid);
+                listener.send(userId, data);
+            } catch (RemoteException e) {
+                Log.e(TAG_USER, "Error calling lifecycle listener", e);
+            } finally {
+                t.traceEnd();
+            }
+        }
+        t.traceEnd(); // notify-app-listeners-user-USERID-event-EVENT_TYPE
+    }
+
+    private void handleNotifyServiceUserLifecycleListeners(UserLifecycleEvent event) {
+        TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
+        if (mUserLifecycleListeners.isEmpty()) {
+            Log.w(TAG_USER, "Not notifying internal UserLifecycleListeners");
+            return;
+        } else if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+            Log.d(TAG_USER, "Notifying " + mUserLifecycleListeners.size() + " service listeners of "
+                    + event);
+        }
+
+        int userId = event.getUserId();
+        int eventType = event.getEventType();
+        t.traceBegin("notify-listeners-user-" + userId + "-event-" + eventType);
+        for (UserLifecycleListener listener : mUserLifecycleListeners) {
+            String listenerName = FunctionalUtils.getLambdaName(listener);
+            EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_INTERNAL_LIFECYCLE_LISTENER,
+                    listenerName, eventType, event.getPreviousUserId(), userId);
+            try {
+                t.traceBegin("notify-listener-" + listenerName);
+                listener.onEvent(event);
+            } catch (RuntimeException e) {
+                Log.e(TAG_USER,
+                        "Exception raised when invoking onEvent for " + listenerName, e);
+            } finally {
+                t.traceEnd();
+            }
+        }
+        t.traceEnd(); // notify-listeners-user-USERID-event-EVENT_TYPE
+    }
+
+    private void onUserSwitching(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
+        Log.i(TAG_USER, "onUserSwitching() callback for user " + toUserId);
+        TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
+        t.traceBegin("onUserSwitching-" + toUserId);
+
+        // Switch HAL users if user switch is not requested by CarUserService
+        notifyHalLegacySwitch(fromUserId, toUserId);
+
+        mCarUserManagerHelper.setLastActiveUser(toUserId);
+
+        if (mLastPassengerId != UserHandle.USER_NULL) {
+            stopPassengerInternal(mLastPassengerId, false);
+        }
+        if (mEnablePassengerSupport && isPassengerDisplayAvailable()) {
+            setupPassengerUser();
+            startFirstPassenger(toUserId);
+        }
+        t.traceEnd();
+    }
+
+    private void notifyHalLegacySwitch(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
+        synchronized (mLockUser) {
+            if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
+                if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+                    Log.d(TAG, "notifyHalLegacySwitch(" + fromUserId + ", " + toUserId
+                            + "): not needed, normal switch for " + mUserIdForUserSwitchInProcess);
+                }
+                return;
+            }
+        }
+
+        if (!isUserHalSupported()) return;
+
+        // switch HAL user
+        UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager, fromUserId);
+        SwitchUserRequest request = createUserSwitchRequest(toUserId, usersInfo);
+        mHal.legacyUserSwitch(request);
+    }
+
+    /**
+     * Runs the given runnable when user 0 is unlocked. If user 0 is already unlocked, it is
      * run inside this call.
+     *
      * @param r Runnable to run.
      */
-    public void runOnUser0Unlock(Runnable r) {
+    public void runOnUser0Unlock(@NonNull Runnable r) {
+        Objects.requireNonNull(r, "runnable cannot be null");
         boolean runNow = false;
-        synchronized (mLock) {
+        synchronized (mLockUser) {
             if (mUser0Unlocked) {
                 runNow = true;
             } else {
@@ -344,23 +1740,231 @@
     }
 
     @VisibleForTesting
-    protected ArrayList<Integer> getBackgroundUsersToRestart() {
-        ArrayList<Integer> backgroundUsersToRestart;
-        synchronized (mLock) {
+    @NonNull
+    ArrayList<Integer> getBackgroundUsersToRestart() {
+        ArrayList<Integer> backgroundUsersToRestart = null;
+        synchronized (mLockUser) {
             backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
         }
         return backgroundUsersToRestart;
     }
 
     private void setSystemUserRestrictions() {
-        // Disable adding accounts for system user.
-        mCarUserManagerHelper.setUserRestriction(mCarUserManagerHelper.getSystemUserInfo(),
-                UserManager.DISALLOW_MODIFY_ACCOUNTS, /* enable= */ true);
-
         // Disable Location service for system user.
         LocationManager locationManager =
                 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
         locationManager.setLocationEnabledForUser(
                 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
     }
+
+    /**
+     * Assigns a default icon to a user according to the user's id.
+     *
+     * @param userInfo User whose avatar is set to default icon.
+     */
+    private void assignDefaultIcon(UserInfo userInfo) {
+        int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
+        Bitmap bitmap = UserIcons.convertToBitmap(
+                UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
+        mUserManager.setUserIcon(userInfo.id, bitmap);
+    }
+
+    private interface UserFilter {
+        boolean isEligibleUser(UserInfo user);
+    }
+
+    /** Returns all users who are matched by the given filter. */
+    private List<UserInfo> getUsers(UserFilter filter) {
+        List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
+
+        for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
+            UserInfo user = iterator.next();
+            if (!filter.isEligibleUser(user)) {
+                iterator.remove();
+            }
+        }
+        return users;
+    }
+
+    /**
+     * Enforces that apps which have the
+     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
+     * can make certain calls to the CarUserManager.
+     *
+     * @param message used as message if SecurityException is thrown.
+     * @throws SecurityException if the caller is not system or root.
+     */
+    private static void checkManageUsersPermission(String message) {
+        checkAtLeastOnePermission(message, android.Manifest.permission.MANAGE_USERS);
+    }
+
+    private static void checkManageOrCreateUsersPermission(String message) {
+        checkAtLeastOnePermission(message,
+                android.Manifest.permission.MANAGE_USERS,
+                android.Manifest.permission.CREATE_USERS);
+    }
+
+    private static void checkManageUsersOrDumpPermission(String message) {
+        checkAtLeastOnePermission(message,
+                android.Manifest.permission.MANAGE_USERS,
+                android.Manifest.permission.DUMP);
+    }
+
+    private void checkInteractAcrossUsersPermission(String message) {
+        checkAtLeastOnePermission(message, android.Manifest.permission.INTERACT_ACROSS_USERS,
+                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+    }
+
+    private static void checkAtLeastOnePermission(String message, String...permissions) {
+        int callingUid = Binder.getCallingUid();
+        if (!hasAtLeastOnePermissionGranted(callingUid, permissions)) {
+            throw new SecurityException("You need one of " + Arrays.toString(permissions)
+                    + " to: " + message);
+        }
+    }
+
+    private static boolean hasAtLeastOnePermissionGranted(int uid, String... permissions) {
+        for (String permission : permissions) {
+            if (ActivityManager.checkComponentPermission(permission, uid, /* owningUid = */-1,
+                    /* exported = */ true)
+                    == android.content.pm.PackageManager.PERMISSION_GRANTED) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private int getNumberOfManagedProfiles(@UserIdInt int userId) {
+        List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
+        // Count all users that are managed profiles of the given user.
+        int managedProfilesCount = 0;
+        for (UserInfo user : users) {
+            if (user.isManagedProfile() && user.profileGroupId == userId) {
+                managedProfilesCount++;
+            }
+        }
+        return managedProfilesCount;
+    }
+
+    /**
+     * Starts the first passenger of the given driver and assigns the passenger to the front
+     * passenger zone.
+     *
+     * @param driverId User id of the driver.
+     * @return whether it succeeds.
+     */
+    private boolean startFirstPassenger(@UserIdInt int driverId) {
+        int zoneId = getAvailablePassengerZone();
+        if (zoneId == OccupantZoneInfo.INVALID_ZONE_ID) {
+            Log.w(TAG_USER, "passenger occupant zone is not found");
+            return false;
+        }
+        List<UserInfo> passengers = getPassengers(driverId);
+        if (passengers.size() < 1) {
+            Log.w(TAG_USER, "passenger is not found");
+            return false;
+        }
+        // Only one passenger is supported. If there are two or more passengers, the first passenger
+        // is chosen.
+        int passengerId = passengers.get(0).id;
+        if (!startPassenger(passengerId, zoneId)) {
+            Log.w(TAG_USER, "cannot start passenger " + passengerId);
+            return false;
+        }
+        return true;
+    }
+
+    private int getAvailablePassengerZone() {
+        int[] occupantTypes = new int[] {CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
+                CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER};
+        for (int occupantType : occupantTypes) {
+            int zoneId = getZoneId(occupantType);
+            if (zoneId != OccupantZoneInfo.INVALID_ZONE_ID) {
+                return zoneId;
+            }
+        }
+        return OccupantZoneInfo.INVALID_ZONE_ID;
+    }
+
+    /**
+     * Creates a new passenger user when there is no passenger user.
+     */
+    private void setupPassengerUser() {
+        int currentUser = ActivityManager.getCurrentUser();
+        int profileCount = getNumberOfManagedProfiles(currentUser);
+        if (profileCount > 0) {
+            Log.w(TAG_USER, "max profile of user" + currentUser
+                    + " is exceeded: current profile count is " + profileCount);
+            return;
+        }
+        // TODO(b/140311342): Use resource string for the default passenger name.
+        UserInfo passenger = createPassenger("Passenger", currentUser);
+        if (passenger == null) {
+            // Couldn't create user, most likely because there are too many.
+            Log.w(TAG_USER, "cannot create a passenger user");
+            return;
+        }
+    }
+
+    @NonNull
+    private List<OccupantZoneInfo> getOccupantZones(@OccupantTypeEnum int occupantType) {
+        ZoneUserBindingHelper helper = null;
+        synchronized (mLockHelper) {
+            if (mZoneUserBindingHelper == null) {
+                Log.w(TAG_USER, "implementation is not delegated");
+                return new ArrayList<OccupantZoneInfo>();
+            }
+            helper = mZoneUserBindingHelper;
+        }
+        return helper.getOccupantZones(occupantType);
+    }
+
+    private boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
+        ZoneUserBindingHelper helper = null;
+        synchronized (mLockHelper) {
+            if (mZoneUserBindingHelper == null) {
+                Log.w(TAG_USER, "implementation is not delegated");
+                return false;
+            }
+            helper = mZoneUserBindingHelper;
+        }
+        return helper.assignUserToOccupantZone(userId, zoneId);
+    }
+
+    private boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
+        ZoneUserBindingHelper helper = null;
+        synchronized (mLockHelper) {
+            if (mZoneUserBindingHelper == null) {
+                Log.w(TAG_USER, "implementation is not delegated");
+                return false;
+            }
+            helper = mZoneUserBindingHelper;
+        }
+        return helper.unassignUserFromOccupantZone(userId);
+    }
+
+    private boolean isPassengerDisplayAvailable() {
+        ZoneUserBindingHelper helper = null;
+        synchronized (mLockHelper) {
+            if (mZoneUserBindingHelper == null) {
+                Log.w(TAG_USER, "implementation is not delegated");
+                return false;
+            }
+            helper = mZoneUserBindingHelper;
+        }
+        return helper.isPassengerDisplayAvailable();
+    }
+
+    /**
+     * Gets the zone id of the given occupant type. If there are two or more zones, the first found
+     * zone is returned.
+     *
+     * @param occupantType The type of an occupant.
+     * @return The zone id of the given occupant type. {@link OccupantZoneInfo.INVALID_ZONE_ID},
+     *         if not found.
+     */
+    private int getZoneId(@OccupantTypeEnum int occupantType) {
+        List<OccupantZoneInfo> zoneInfos = getOccupantZones(occupantType);
+        return (zoneInfos.size() > 0) ? zoneInfos.get(0).zoneId : OccupantZoneInfo.INVALID_ZONE_ID;
+    }
 }
diff --git a/service/src/com/android/car/user/UserMetrics.java b/service/src/com/android/car/user/UserMetrics.java
new file mode 100644
index 0000000..62b9755
--- /dev/null
+++ b/service/src/com/android/car/user/UserMetrics.java
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.user;
+
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING;
+import static android.car.user.CarUserManager.lifecycleEventTypeToString;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.car.user.CarUserManager.UserLifecycleEventType;
+import android.util.LocalLog;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseLongArray;
+import android.util.TimeUtils;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * Metrics for user switches.
+ *
+ * <p>It stores 2 types of metrics:
+ *
+ * <ol>
+ *   <li>Time to start a user (from start to unlock)
+ *   <li>Time to stop a user (from stop to shutdown)
+ * </ol>
+ *
+ * <p>It keeps track of the users being started and stopped, then logs the last
+ * {{@link #INITIAL_CAPACITY}} occurrences of each when the operation finished (so it can be dumped
+ * later).
+ */
+final class UserMetrics {
+
+    private static final String TAG = UserMetrics.class.getSimpleName();
+
+    /**
+     * Initial capacity for the current operations.
+     */
+    // Typically there are at most 2 users (system and 1st full), although it could be higher on
+    // garage mode
+    private static final int INITIAL_CAPACITY = 2;
+
+    // TODO(b/150413515): read from resources
+    private static final int LOG_SIZE = 10;
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private SparseArray<UserStartingMetric> mUserStartingMetrics;
+    @GuardedBy("mLock")
+    private SparseArray<UserStoppingMetric> mUserStoppingMetrics;
+
+    @GuardedBy("mLock")
+    private final LocalLog mUserStartedLogs = new LocalLog(LOG_SIZE);
+    @GuardedBy("mLock")
+    private final LocalLog mUserStoppedLogs = new LocalLog(LOG_SIZE);
+
+    @GuardedBy("mLock")
+    private final SparseLongArray mFirstUserUnlockDuration = new SparseLongArray(1);
+
+    @GuardedBy("mLock")
+    private int mHalResponseTime;
+
+    /**
+     * Logs a user lifecycle event.
+     */
+    public void onEvent(@UserLifecycleEventType int eventType, long timestampMs,
+            @UserIdInt int fromUserId, @UserIdInt int toUserId) {
+        synchronized (mLock) {
+            switch(eventType) {
+                case USER_LIFECYCLE_EVENT_TYPE_STARTING:
+                    onUserStartingEventLocked(timestampMs, toUserId);
+                    return;
+                case USER_LIFECYCLE_EVENT_TYPE_SWITCHING:
+                    onUserSwitchingEventLocked(timestampMs, fromUserId, toUserId);
+                    return;
+                case USER_LIFECYCLE_EVENT_TYPE_UNLOCKING:
+                    onUserUnlockingEventLocked(timestampMs, toUserId);
+                    return;
+                case USER_LIFECYCLE_EVENT_TYPE_UNLOCKED:
+                    onUserUnlockedEventLocked(timestampMs, toUserId);
+                    return;
+                case USER_LIFECYCLE_EVENT_TYPE_STOPPING:
+                    onUserStoppingEventLocked(timestampMs, toUserId);
+                    return;
+                case USER_LIFECYCLE_EVENT_TYPE_STOPPED:
+                    onUserStoppedEventLocked(timestampMs, toUserId);
+                    return;
+                default:
+                    Slog.w(TAG, "Invalid event: " + lifecycleEventTypeToString(eventType));
+            }
+        }
+    }
+
+    /**
+     * Logs when the first user was unlocked.
+     */
+    public void logFirstUnlockedUser(int userId, long timestampMs, long duration,
+            int halResponseTime) {
+        synchronized (mLock) {
+            mHalResponseTime = halResponseTime;
+            mFirstUserUnlockDuration.put(userId, duration);
+            onUserUnlockedEventLocked(timestampMs, userId);
+        }
+    }
+
+    @VisibleForTesting
+    SparseArray<UserStartingMetric> getUserStartMetrics() {
+        synchronized (mLock) {
+            return mUserStartingMetrics;
+        }
+    }
+
+    @VisibleForTesting
+    SparseArray<UserStoppingMetric> getUserStopMetrics() {
+        synchronized (mLock) {
+            return mUserStoppingMetrics;
+        }
+    }
+
+    private void onUserStartingEventLocked(long timestampMs, @UserIdInt int userId) {
+        if (mUserStartingMetrics == null) {
+            mUserStartingMetrics = new SparseArray<>(INITIAL_CAPACITY);
+        }
+
+        UserStartingMetric existingMetrics = mUserStartingMetrics.get(userId);
+        if (existingMetrics != null) {
+            Slog.w(TAG, "user re-started: " + existingMetrics);
+            finishUserStartingLocked(existingMetrics, /* removeMetric= */ false);
+        }
+
+        mUserStartingMetrics.put(userId, new UserStartingMetric(userId, timestampMs));
+    }
+
+    private void onUserSwitchingEventLocked(long timestampMs, @UserIdInt int fromUserId,
+            @UserIdInt int toUserId) {
+        UserStartingMetric metrics = getExistingMetricsLocked(mUserStartingMetrics, toUserId);
+        if (metrics == null) return;
+
+        metrics.switchFromUserId = fromUserId;
+        metrics.switchTime = timestampMs;
+    }
+
+    private void onUserUnlockingEventLocked(long timestampMs, @UserIdInt int userId) {
+        UserStartingMetric metrics = getExistingMetricsLocked(mUserStartingMetrics, userId);
+        if (metrics == null) return;
+
+        metrics.unlockingTime = timestampMs;
+    }
+
+    private void onUserUnlockedEventLocked(long timestampMs, @UserIdInt int userId) {
+        UserStartingMetric metrics = getExistingMetricsLocked(mUserStartingMetrics, userId);
+        if (metrics == null) return;
+
+        metrics.unlockedTime = timestampMs;
+
+        finishUserStartingLocked(metrics, /* removeMetric= */ true);
+    }
+
+    private void onUserStoppingEventLocked(long timestampMs, @UserIdInt int userId) {
+        if (mUserStoppingMetrics == null) {
+            mUserStoppingMetrics = new SparseArray<>(INITIAL_CAPACITY);
+        }
+        UserStoppingMetric existingMetrics = mUserStoppingMetrics.get(userId);
+        if (existingMetrics != null) {
+            Slog.w(TAG, "user re-stopped: " + existingMetrics);
+            finishUserStoppingLocked(existingMetrics, /* removeMetric= */ false);
+        }
+        mUserStoppingMetrics.put(userId, new UserStoppingMetric(userId, timestampMs));
+    }
+
+    private void onUserStoppedEventLocked(long timestampMs, @UserIdInt int userId) {
+        UserStoppingMetric metrics = getExistingMetricsLocked(mUserStoppingMetrics, userId);
+        if (metrics == null) return;
+
+        metrics.shutdownTime = timestampMs;
+        finishUserStoppingLocked(metrics, /* removeMetric= */ true);
+    }
+
+    @Nullable
+    private <T extends BaseUserMetric> T getExistingMetricsLocked(
+            @NonNull SparseArray<? extends BaseUserMetric> metrics, @UserIdInt int userId) {
+        if (metrics == null) {
+            Slog.w(TAG, "getExistingMetricsLocked() should not pass null metrics, except on tests");
+            return null;
+        }
+        @SuppressWarnings("unchecked")
+        T metric = (T) metrics.get(userId);
+        if (metric == null) {
+            String name = metrics == mUserStartingMetrics ? "starting" : "stopping";
+            Slog.w(TAG, "no " + name + " metrics for user " + userId);
+        }
+        return metric;
+    }
+
+    private void removeExistingMetricsLogged(@NonNull SparseArray<? extends BaseUserMetric> metrics,
+            @UserIdInt int userId) {
+        metrics.remove(userId);
+        if (metrics.size() != 0) return;
+
+        if (metrics == mUserStartingMetrics) {
+            mUserStartingMetrics = null;
+        } else {
+            mUserStoppingMetrics = null;
+        }
+    }
+
+    private void finishUserStartingLocked(@NonNull UserStartingMetric metrics,
+            boolean removeMetric) {
+        mUserStartedLogs.log(metrics.toString());
+        if (removeMetric) {
+            removeExistingMetricsLogged(mUserStartingMetrics, metrics.userId);
+        }
+    }
+
+    private void finishUserStoppingLocked(@NonNull UserStoppingMetric metrics,
+            boolean removeMetric) {
+        mUserStoppedLogs.log(metrics.toString());
+        if (removeMetric) {
+            removeExistingMetricsLogged(mUserStoppingMetrics, metrics.userId);
+        }
+    }
+
+    /**
+     * Dumps its contents.
+     */
+    public void dump(@NonNull PrintWriter pw) {
+        pw.println("* User Metrics *");
+        synchronized (mLock) {
+
+            if (mFirstUserUnlockDuration.size() == 0) {
+                pw.println("First user not unlocked yet");
+            } else {
+                pw.printf("First user (%d) unlocked in ", mFirstUserUnlockDuration.keyAt(0));
+                TimeUtils.formatDuration(mFirstUserUnlockDuration.valueAt(0), pw);
+                pw.println();
+            }
+
+            dump(pw, "starting", mUserStartingMetrics);
+            dump(pw, "stopping", mUserStoppingMetrics);
+
+            pw.printf("Last %d started users\n", LOG_SIZE);
+            mUserStartedLogs.dump("  ", pw);
+
+            pw.printf("Last %d stopped users\n", LOG_SIZE);
+            mUserStoppedLogs.dump("  ", pw);
+
+            pw.print("HAL response time: ");
+            if (mHalResponseTime == 0) {
+                pw.print("N/A");
+            } else if (mHalResponseTime < 0) {
+                pw.print("not replied yet, sent at ");
+                TimeUtils.formatUptime(-mHalResponseTime);
+            } else {
+                TimeUtils.formatDuration(mHalResponseTime, pw);
+            }
+            pw.println();
+        }
+    }
+
+    /**
+     * Dumps only how long it took to unlock the first user (or {@code -1} if not available).
+     */
+    public void dumpFirstUserUnlockDuration(@NonNull PrintWriter pw) {
+        synchronized (mLock) {
+            if (mFirstUserUnlockDuration.size() == 0) {
+                pw.println(-1);
+                return;
+            }
+            pw.println(mFirstUserUnlockDuration.valueAt(0));
+        }
+    }
+
+    private void dump(@NonNull PrintWriter pw, @NonNull String message,
+            @NonNull SparseArray<? extends BaseUserMetric> metrics) {
+        String indent = "  ";
+        if (metrics == null) {
+            pw.printf("%sno users %s\n", indent, message);
+            return;
+        }
+        int size = metrics.size();
+        pw.printf("%d users %s\n", size, message);
+        for (int i = 0; i < size; i++) {
+            BaseUserMetric metric = metrics.valueAt(i);
+            pw.printf("%s%d: ", indent, i);
+            metric.dump(pw);
+            pw.println();
+        }
+    }
+
+    private abstract class BaseUserMetric {
+        public final @UserIdInt int userId;
+
+        protected BaseUserMetric(@UserIdInt int userId) {
+            this.userId = userId;
+        }
+
+        @Override
+        public String toString() {
+            StringWriter sw = new StringWriter();
+            PrintWriter pw = new PrintWriter(sw);
+            dump(pw);
+            pw.flush();
+            return sw.toString();
+        }
+
+        abstract void dump(@NonNull PrintWriter pw);
+    }
+
+    @VisibleForTesting
+    final class UserStartingMetric extends BaseUserMetric {
+        public final long startTime;
+        public long switchTime;
+        public long unlockingTime;
+        public long unlockedTime;
+        public @UserIdInt int switchFromUserId;
+
+        UserStartingMetric(@UserIdInt int userId, long startTime) {
+            super(userId);
+            this.startTime = startTime;
+        }
+
+        @Override
+        public void dump(@NonNull PrintWriter pw) {
+            pw.printf("user=%d start=", userId);
+            TimeUtils.dumpTime(pw, startTime);
+
+            if (switchTime > 0) {
+                long delta = switchTime - startTime;
+                pw.print(" switch");
+                if (switchFromUserId != 0) {
+                    pw.printf("(from %d)", switchFromUserId);
+                }
+                pw.print('=');
+                TimeUtils.formatDuration(delta, pw);
+            }
+
+            if (unlockingTime > 0) {
+                long delta = unlockingTime - startTime;
+                pw.print(" unlocking=");
+                TimeUtils.formatDuration(delta, pw);
+            }
+            if (unlockedTime > 0) {
+                long delta = unlockedTime - startTime;
+                pw.print(" unlocked=");
+                TimeUtils.formatDuration(delta, pw);
+            }
+        }
+    }
+
+    @VisibleForTesting
+    final class UserStoppingMetric extends BaseUserMetric {
+        public final long stopTime;
+        public long shutdownTime;
+
+        UserStoppingMetric(@UserIdInt int userId, long stopTime) {
+            super(userId);
+            this.stopTime = stopTime;
+        }
+
+        @Override
+        public void dump(@NonNull PrintWriter pw) {
+            pw.printf("user=%d stop=", userId);
+            TimeUtils.dumpTime(pw, stopTime);
+
+            if (shutdownTime > 0) {
+                long delta = shutdownTime - stopTime;
+                pw.print(" shutdown=");
+                TimeUtils.formatDuration(delta, pw);
+            }
+        }
+    }
+}
diff --git a/service/src/com/android/car/vms/VmsBrokerService.java b/service/src/com/android/car/vms/VmsBrokerService.java
index ad0bfad..31c60bd 100644
--- a/service/src/com/android/car/vms/VmsBrokerService.java
+++ b/service/src/com/android/car/vms/VmsBrokerService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,360 +16,367 @@
 
 package com.android.car.vms;
 
-import android.car.vms.IVmsSubscriberClient;
+import static com.android.car.ICarImpl.assertAnyVmsPermission;
+import static com.android.car.ICarImpl.assertVmsPublisherPermission;
+import static com.android.car.ICarImpl.assertVmsSubscriberPermission;
+
+import android.car.vms.IVmsBrokerService;
+import android.car.vms.IVmsClientCallback;
+import android.car.vms.VmsAssociatedLayer;
 import android.car.vms.VmsAvailableLayers;
 import android.car.vms.VmsLayer;
+import android.car.vms.VmsLayerDependency;
 import android.car.vms.VmsLayersOffering;
-import android.car.vms.VmsOperationRecorder;
+import android.car.vms.VmsProviderInfo;
+import android.car.vms.VmsRegistrationInfo;
 import android.car.vms.VmsSubscriptionState;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
 import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SharedMemory;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 
-import com.android.car.VmsLayersAvailability;
-import com.android.car.VmsPublishersInfo;
-import com.android.car.VmsRouting;
+import com.android.car.CarServiceBase;
+import com.android.car.stats.CarStatsService;
+import com.android.car.stats.VmsClientLogger;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FunctionalUtils.ThrowingConsumer;
 
-import java.util.HashMap;
-import java.util.HashSet;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.IntSupplier;
+import java.util.stream.Collectors;
 
 /**
- * Broker service facilitating subscription handling and message passing between
- * VmsPublisherService, VmsSubscriberService, and VmsHalService.
+ * Message broker service for routing Vehicle Map Service messages between clients.
+ *
+ * This service is also responsible for tracking VMS client connections and broadcasting
+ * notifications to clients about layer offering or subscription state changes.
  */
-public class VmsBrokerService {
+public class VmsBrokerService extends IVmsBrokerService.Stub implements CarServiceBase {
     private static final boolean DBG = false;
-    private static final String TAG = "VmsBrokerService";
+    private static final String TAG = VmsBrokerService.class.getSimpleName();
 
-    private CopyOnWriteArrayList<PublisherListener> mPublisherListeners =
-            new CopyOnWriteArrayList<>();
-    private CopyOnWriteArrayList<SubscriberListener> mSubscriberListeners =
-            new CopyOnWriteArrayList<>();
+    private final Context mContext;
+    private final PackageManager mPackageManager;
+    private final CarStatsService mStatsService;
+    private final IntSupplier mGetCallingUid;
+
+    private final VmsProviderInfoStore mProviderInfoStore = new VmsProviderInfoStore();
+    private final VmsLayerAvailability mAvailableLayers = new VmsLayerAvailability();
 
     private final Object mLock = new Object();
     @GuardedBy("mLock")
-    private final VmsRouting mRouting = new VmsRouting();
+    private final Map<IBinder /* clientToken */, VmsClientInfo> mClientMap = new ArrayMap<>();
     @GuardedBy("mLock")
-    private final Map<IBinder, Map<Integer, VmsLayersOffering>> mOfferings = new HashMap<>();
+    private Set<VmsLayersOffering> mAllOfferings = Collections.emptySet();
     @GuardedBy("mLock")
-    private final VmsLayersAvailability mAvailableLayers = new VmsLayersAvailability();
-    @GuardedBy("mLock")
-    private final VmsPublishersInfo mPublishersInfo = new VmsPublishersInfo();
+    private VmsSubscriptionState mSubscriptionState = new VmsSubscriptionState(0,
+            Collections.emptySet(), Collections.emptySet());
 
-    /**
-     * The VMS publisher service implements this interface to receive publisher callbacks.
-     */
-    public interface PublisherListener {
-        /**
-         * Callback triggered when publisher subscription state changes.
-         *
-         * @param subscriptionState Current subscription state.
-         */
-        void onSubscriptionChange(VmsSubscriptionState subscriptionState);
+    public VmsBrokerService(Context context, CarStatsService statsService) {
+        this(context, statsService, Binder::getCallingUid);
     }
 
-    /**
-     * The VMS subscriber service implements this interface to receive subscriber callbacks.
-     */
-    public interface SubscriberListener {
-        /**
-         * Callback triggered when the layers available for subscription changes.
-         *
-         * @param availableLayers Current layer availability
-         */
-        void onLayersAvailabilityChange(VmsAvailableLayers availableLayers);
+    @VisibleForTesting
+    VmsBrokerService(
+            Context context,
+            CarStatsService statsService,
+            IntSupplier getCallingUid) {
+        mContext = context;
+        mPackageManager = context.getPackageManager();
+        mStatsService = statsService;
+        mGetCallingUid = getCallingUid;
     }
 
-    /**
-     * Adds a listener for publisher callbacks.
-     *
-     * @param listener Publisher callback listener
-     */
-    public void addPublisherListener(PublisherListener listener) {
-        mPublisherListeners.add(listener);
+    @Override
+    public void init() {
     }
 
-    /**
-     * Adds a listener for subscriber callbacks.
-     *
-     * @param listener Subscriber callback listener
-     */
-    public void addSubscriberListener(SubscriberListener listener) {
-        mSubscriberListeners.add(listener);
+    @Override
+    public void release() {
     }
 
-    /**
-     * Removes a listener for publisher callbacks.
-     *
-     * @param listener Publisher callback listener
-     */
-    public void removePublisherListener(PublisherListener listener) {
-        mPublisherListeners.remove(listener);
-    }
-
-    /**
-     * Removes a listener for subscriber callbacks.
-     *
-     * @param listener Subscriber callback listener
-     */
-    public void removeSubscriberListener(SubscriberListener listener) {
-        mSubscriberListeners.remove(listener);
-    }
-
-    /**
-     * Adds a subscription to all layers.
-     *
-     * @param subscriber Subscriber client to send layer data
-     */
-    public void addSubscription(IVmsSubscriberClient subscriber) {
+    @Override
+    public void dump(PrintWriter writer) {
+        writer.println("*" + TAG + "*");
         synchronized (mLock) {
-            mRouting.addSubscription(subscriber);
+            writer.println("mAvailableLayers: " + mAvailableLayers.getAvailableLayers());
+            writer.println();
+            writer.println("mSubscriptionState: " + mSubscriptionState);
+            writer.println();
+            writer.println("mClientMap:");
+            mClientMap.values().stream()
+                    .sorted(Comparator.comparingInt(VmsClientInfo::getUid))
+                    .forEach(client -> client.dump(writer, "  "));
         }
     }
 
-    /**
-     * Removes a subscription to all layers.
-     *
-     * @param subscriber Subscriber client to remove subscription for
-     */
-    public void removeSubscription(IVmsSubscriberClient subscriber) {
+    @Override
+    public VmsRegistrationInfo registerClient(IBinder clientToken, IVmsClientCallback callback,
+            boolean legacyClient) {
+        assertAnyVmsPermission(mContext);
+        int clientUid = mGetCallingUid.getAsInt();
+        String clientPackage = mPackageManager.getNameForUid(clientUid);
+        if (DBG) Log.d(TAG, "registerClient uid: " + clientUid + " package: " + clientPackage);
+
+        mStatsService.getVmsClientLogger(clientUid)
+                .logConnectionState(VmsClientLogger.ConnectionState.CONNECTED);
+
+        IBinder.DeathRecipient deathRecipient;
+        try {
+            deathRecipient = () -> unregisterClient(clientToken,
+                    VmsClientLogger.ConnectionState.DISCONNECTED);
+            callback.asBinder().linkToDeath(deathRecipient, 0);
+        } catch (RemoteException e) {
+            mStatsService.getVmsClientLogger(clientUid)
+                    .logConnectionState(VmsClientLogger.ConnectionState.DISCONNECTED);
+            throw new IllegalStateException("Client callback is already dead");
+        }
+
         synchronized (mLock) {
-            mRouting.removeSubscription(subscriber);
+            mClientMap.put(clientToken, new VmsClientInfo(clientUid, clientPackage, callback,
+                    legacyClient, deathRecipient));
+            return new VmsRegistrationInfo(
+                    mAvailableLayers.getAvailableLayers(),
+                    mSubscriptionState);
         }
     }
 
-    /**
-     * Adds a layer subscription.
-     *
-     * @param subscriber Subscriber client to send layer data
-     * @param layer      Layer to send
-     */
-    public void addSubscription(IVmsSubscriberClient subscriber, VmsLayer layer) {
-        boolean firstSubscriptionForLayer;
-        if (DBG) Log.d(TAG, "Checking for first subscription. Layer: " + layer);
-        synchronized (mLock) {
-            // Check if publishers need to be notified about this change in subscriptions.
-            firstSubscriptionForLayer = !mRouting.hasLayerSubscriptions(layer);
+    @Override
+    public void unregisterClient(IBinder clientToken) {
+        assertAnyVmsPermission(mContext);
+        unregisterClient(clientToken, VmsClientLogger.ConnectionState.TERMINATED);
+    }
 
-            // Add the listeners subscription to the layer
-            mRouting.addSubscription(subscriber, layer);
+    @Override
+    public VmsProviderInfo getProviderInfo(IBinder clientToken, int providerId) {
+        assertAnyVmsPermission(mContext);
+        getClient(clientToken); // Assert that the client is registered
+        return new VmsProviderInfo(mProviderInfoStore.getProviderInfo(providerId));
+    }
+
+    @Override
+    public void setSubscriptions(IBinder clientToken, List<VmsAssociatedLayer> layers) {
+        assertVmsSubscriberPermission(mContext);
+        getClient(clientToken).setSubscriptions(layers);
+        updateSubscriptionState();
+    }
+
+    @Override
+    public void setMonitoringEnabled(IBinder clientToken, boolean enabled) {
+        assertVmsSubscriberPermission(mContext);
+        getClient(clientToken).setMonitoringEnabled(enabled);
+    }
+
+    @Override
+    public int registerProvider(IBinder clientToken, VmsProviderInfo providerInfo) {
+        assertVmsPublisherPermission(mContext);
+        VmsClientInfo client = getClient(clientToken);
+        int providerId;
+        synchronized (mLock) {
+            providerId = mProviderInfoStore.getProviderId(providerInfo.getDescription());
         }
-        if (firstSubscriptionForLayer) {
-            notifyOfSubscriptionChange();
+        client.addProviderId(providerId);
+        return providerId;
+    }
+
+    @Override
+    public void setProviderOfferings(IBinder clientToken, int providerId,
+            List<VmsLayerDependency> offerings) {
+        assertVmsPublisherPermission(mContext);
+        VmsClientInfo client = getClient(clientToken);
+        if (!client.hasProviderId(providerId) && !client.isLegacyClient()) {
+            throw new IllegalArgumentException("Client not registered to offer layers as "
+                    + providerId);
+        }
+        if (client.setProviderOfferings(providerId, offerings)) {
+            updateAvailableLayers();
         }
     }
 
-    /**
-     * Removes a layer subscription.
-     *
-     * @param subscriber Subscriber client to remove subscription for
-     * @param layer      Layer to remove
-     */
-    public void removeSubscription(IVmsSubscriberClient subscriber, VmsLayer layer) {
-        boolean layerHasSubscribers;
+    @Override
+    public void publishPacket(IBinder clientToken, int providerId, VmsLayer layer, byte[] packet) {
+        assertVmsPublisherPermission(mContext);
+        deliverToSubscribers(clientToken, providerId, layer, packet.length,
+                callback -> callback.onPacketReceived(providerId, layer, packet));
+    }
+
+    @Override
+    public void publishLargePacket(IBinder clientToken, int providerId, VmsLayer layer,
+            SharedMemory packet) {
+        try (SharedMemory largePacket = packet) {
+            assertVmsPublisherPermission(mContext);
+            deliverToSubscribers(clientToken, providerId, layer, packet.getSize(),
+                    callback -> callback.onLargePacketReceived(providerId, layer, largePacket));
+        }
+    }
+
+    private void deliverToSubscribers(IBinder clientToken, int providerId, VmsLayer layer,
+            int packetLength, ThrowingConsumer<IVmsClientCallback> callbackConsumer) {
+        VmsClientInfo client = getClient(clientToken);
+        if (!client.hasOffering(providerId, layer) && !client.isLegacyClient()) {
+            throw new IllegalArgumentException("Client does not offer " + layer + " as "
+                    + providerId);
+        }
+
+        mStatsService.getVmsClientLogger(client.getUid())
+                .logPacketSent(layer, packetLength);
+
+        Collection<VmsClientInfo> subscribers;
         synchronized (mLock) {
-            if (!mRouting.hasLayerSubscriptions(layer)) {
-                if (DBG) Log.d(TAG, "Trying to remove a layer with no subscription: " + layer);
+            subscribers = mClientMap.values().stream()
+                    .filter(subscriber -> subscriber.isSubscribed(providerId, layer))
+                    .collect(Collectors.toList());
+        }
+
+        if (DBG) Log.d(TAG, String.format("Number of subscribers: %d", subscribers.size()));
+
+        if (subscribers.isEmpty()) {
+            // A negative UID signals that the packet had zero subscribers
+            mStatsService.getVmsClientLogger(-1).logPacketDropped(layer, packetLength);
+            return;
+        }
+
+        for (VmsClientInfo subscriber : subscribers) {
+            try {
+                callbackConsumer.accept(subscriber.getCallback());
+                mStatsService.getVmsClientLogger(subscriber.getUid())
+                        .logPacketReceived(layer, packetLength);
+            } catch (RuntimeException e) {
+                mStatsService.getVmsClientLogger(subscriber.getUid())
+                        .logPacketDropped(layer, packetLength);
+                Log.e(TAG, String.format("Unable to publish to listener: %s",
+                        subscriber.getPackageName()), e);
+            }
+        }
+    }
+
+    private void unregisterClient(IBinder clientToken, int connectionState) {
+        VmsClientInfo client;
+        synchronized (mLock) {
+            client = mClientMap.remove(clientToken);
+        }
+        if (client != null) {
+            client.getCallback().asBinder().unlinkToDeath(client.getDeathRecipient(), 0);
+            mStatsService.getVmsClientLogger(client.getUid())
+                    .logConnectionState(connectionState);
+            updateAvailableLayers();
+            updateSubscriptionState();
+        }
+    }
+
+    private VmsClientInfo getClient(IBinder clientToken) {
+        synchronized (mLock) {
+            VmsClientInfo client = mClientMap.get(clientToken);
+            if (client == null) {
+                throw new IllegalStateException("Unknown client token");
+            }
+            return client;
+        }
+    }
+
+    private Collection<VmsClientInfo> getActiveClients() {
+        synchronized (mLock) {
+            return new ArrayList<>(mClientMap.values());
+        }
+    }
+
+    private void updateAvailableLayers() {
+        synchronized (mLock) {
+            // Fuse layer offerings
+            Set<VmsLayersOffering> allOfferings = mClientMap.values().stream()
+                    .map(VmsClientInfo::getAllOfferings)
+                    .flatMap(Collection::stream)
+                    .collect(Collectors.toCollection(ArraySet::new));
+
+            // Ignore update if offerings are unchanged
+            if (mAllOfferings.equals(allOfferings)) {
                 return;
             }
 
-            // Remove the listeners subscription to the layer
-            mRouting.removeSubscription(subscriber, layer);
-
-            // Check if publishers need to be notified about this change in subscriptions.
-            layerHasSubscribers = mRouting.hasLayerSubscriptions(layer);
+            // Update offerings and compute available layers
+            mAllOfferings = allOfferings;
+            mAvailableLayers.setPublishersOffering(allOfferings);
         }
-        if (!layerHasSubscribers) {
-            notifyOfSubscriptionChange();
+        notifyOfAvailabilityChange(mAvailableLayers.getAvailableLayers());
+    }
+
+    private void notifyOfAvailabilityChange(VmsAvailableLayers availableLayers) {
+        Log.i(TAG, "Notifying clients of layer availability change: " + availableLayers);
+        for (VmsClientInfo client : getActiveClients()) {
+            try {
+                client.getCallback().onLayerAvailabilityChanged(availableLayers);
+            } catch (RemoteException e) {
+                Log.w(TAG, "onLayersAvailabilityChanged failed: " + client.getPackageName(),
+                        e);
+            }
         }
     }
 
-    /**
-     * Adds a publisher-specific layer subscription.
-     *
-     * @param subscriber  Subscriber client to send layer data
-     * @param layer       Layer to send
-     * @param publisherId Publisher of layer
-     */
-    public void addSubscription(IVmsSubscriberClient subscriber, VmsLayer layer, int publisherId) {
-        boolean firstSubscriptionForLayer;
+    private void updateSubscriptionState() {
+        VmsSubscriptionState subscriptionState;
         synchronized (mLock) {
-            // Check if publishers need to be notified about this change in subscriptions.
-            firstSubscriptionForLayer = !(mRouting.hasLayerSubscriptions(layer)
-                    || mRouting.hasLayerFromPublisherSubscriptions(layer, publisherId));
+            Set<VmsLayer> layerSubscriptions = new ArraySet<>();
+            Map<VmsLayer, Set<Integer>> layerAndProviderSubscriptions = new ArrayMap<>();
+            // Fuse subscriptions
+            for (VmsClientInfo client : mClientMap.values()) {
+                layerSubscriptions.addAll(client.getLayerSubscriptions());
+                client.getLayerAndProviderSubscriptions().forEach((layer, providerIds) -> {
+                    Set<Integer> providerSubscriptions =
+                            layerAndProviderSubscriptions.computeIfAbsent(
+                                    layer,
+                                    ignored -> new ArraySet<>());
+                    providerSubscriptions.addAll(providerIds);
+                });
+            }
 
-            // Add the listeners subscription to the layer
-            mRouting.addSubscription(subscriber, layer, publisherId);
-        }
-        if (firstSubscriptionForLayer) {
-            notifyOfSubscriptionChange();
-        }
-    }
+            // Remove global layer subscriptions from provider-specific subscription state
+            layerSubscriptions.forEach(layerAndProviderSubscriptions::remove);
 
-    /**
-     * Removes a publisher-specific layer subscription.
-     *
-     * @param subscriber  Subscriber client to remove subscription for
-     * @param layer       Layer to remove
-     * @param publisherId Publisher of layer
-     */
-    public void removeSubscription(IVmsSubscriberClient subscriber, VmsLayer layer,
-            int publisherId) {
-        boolean layerHasSubscribers;
-        synchronized (mLock) {
-            if (!mRouting.hasLayerFromPublisherSubscriptions(layer, publisherId)) {
-                if (DBG) {
-                    Log.d(TAG, "Trying to remove a layer with no subscription: "
-                        + layer + ", publisher ID:" + publisherId);
-                }
+            // Transform provider-specific subscriptions into VmsAssociatedLayers
+            Set<VmsAssociatedLayer> associatedLayers =
+                    layerAndProviderSubscriptions.entrySet().stream()
+                            .map(entry -> new VmsAssociatedLayer(entry.getKey(), entry.getValue()))
+                            .collect(Collectors.toCollection(ArraySet::new));
+
+            // Ignore update if subscriptions are unchanged
+            if (mSubscriptionState.getLayers().equals(layerSubscriptions)
+                    && mSubscriptionState.getAssociatedLayers().equals(associatedLayers)) {
                 return;
             }
 
-            // Remove the listeners subscription to the layer
-            mRouting.removeSubscription(subscriber, layer, publisherId);
-
-            // Check if publishers need to be notified about this change in subscriptions.
-            layerHasSubscribers = mRouting.hasLayerSubscriptions(layer)
-                    || mRouting.hasLayerFromPublisherSubscriptions(layer, publisherId);
+            // Update subscription state
+            subscriptionState = new VmsSubscriptionState(
+                    mSubscriptionState.getSequenceNumber() + 1,
+                    layerSubscriptions,
+                    associatedLayers);
+            mSubscriptionState = subscriptionState;
         }
-        if (!layerHasSubscribers) {
-            notifyOfSubscriptionChange();
-        }
+        // Notify clients of update
+        notifyOfSubscriptionChange(subscriptionState);
     }
 
-    /**
-     * Removes a disconnected subscriber's subscriptions
-     *
-     * @param subscriber Subscriber that was disconnected
-     */
-    public void removeDeadSubscriber(IVmsSubscriberClient subscriber) {
-        boolean subscriptionStateChanged;
-        synchronized (mLock) {
-            subscriptionStateChanged = mRouting.removeDeadSubscriber(subscriber);
-        }
-        if (subscriptionStateChanged) {
-            notifyOfSubscriptionChange();
-        }
-    }
-
-    /**
-     * Gets all subscribers for a specific layer/publisher combination.
-     *
-     * @param layer       Layer to query
-     * @param publisherId Publisher of layer
-     */
-    public Set<IVmsSubscriberClient> getSubscribersForLayerFromPublisher(VmsLayer layer,
-            int publisherId) {
-        synchronized (mLock) {
-            return mRouting.getSubscribersForLayerFromPublisher(layer, publisherId);
-        }
-    }
-
-    /**
-     * Gets the state of all layer subscriptions.
-     */
-    public VmsSubscriptionState getSubscriptionState() {
-        synchronized (mLock) {
-            return mRouting.getSubscriptionState();
-        }
-    }
-
-    /**
-     * Assigns an idempotent ID for publisherInfo and stores it. The idempotency in this case means
-     * that the same publisherInfo will always, within a trip of the vehicle, return the same ID.
-     * The publisherInfo should be static for a binary and should only change as part of a software
-     * update. The publisherInfo is a serialized proto message which VMS clients can interpret.
-     */
-    public int getPublisherId(byte[] publisherInfo) {
-        if (DBG) Log.i(TAG, "Getting publisher static ID");
-        synchronized (mLock) {
-            return mPublishersInfo.getIdForInfo(publisherInfo);
-        }
-    }
-
-    /**
-     * Gets the publisher information data registered in {@link #getPublisherId(byte[])}
-     *
-     * @param publisherId Publisher ID to query
-     * @return Publisher information
-     */
-    public byte[] getPublisherInfo(int publisherId) {
-        if (DBG) Log.i(TAG, "Getting information for publisher ID: " + publisherId);
-        synchronized (mLock) {
-            return mPublishersInfo.getPublisherInfo(publisherId);
-        }
-    }
-
-    /**
-     * Sets the layers offered by the publisher with the given publisher token.
-     *
-     * @param publisherToken Identifier token of publisher
-     * @param offering       Layers offered by publisher
-     */
-    public void setPublisherLayersOffering(IBinder publisherToken, VmsLayersOffering offering) {
-        synchronized (mLock) {
-            Map<Integer, VmsLayersOffering> publisherOfferings = mOfferings.computeIfAbsent(
-                    publisherToken, k -> new HashMap<>());
-            publisherOfferings.put(offering.getPublisherId(), offering);
-            updateLayerAvailability();
-        }
-        VmsOperationRecorder.get().setPublisherLayersOffering(offering);
-        notifyOfAvailabilityChange();
-    }
-
-    /**
-     * Removes a disconnected publisher's offerings
-     *
-     * @param publisherToken Identifier token of publisher to be removed
-     */
-    public void removeDeadPublisher(IBinder publisherToken) {
-        synchronized (mLock) {
-            mOfferings.remove(publisherToken);
-            updateLayerAvailability();
-        }
-        notifyOfAvailabilityChange();
-    }
-
-    /**
-     * Gets all layers available for subscription.
-     *
-     * @return All available layers
-     */
-    public VmsAvailableLayers getAvailableLayers() {
-        synchronized (mLock) {
-            return mAvailableLayers.getAvailableLayers();
-        }
-    }
-
-    private void updateLayerAvailability() {
-        Set<VmsLayersOffering> allPublisherOfferings = new HashSet<>();
-        synchronized (mLock) {
-            for (Map<Integer, VmsLayersOffering> offerings : mOfferings.values()) {
-                allPublisherOfferings.addAll(offerings.values());
+    private void notifyOfSubscriptionChange(VmsSubscriptionState subscriptionState) {
+        Log.i(TAG, "Notifying clients of subscription state change: " + subscriptionState);
+        for (VmsClientInfo client : getActiveClients()) {
+            try {
+                client.getCallback().onSubscriptionStateChanged(subscriptionState);
+            } catch (RemoteException e) {
+                Log.w(TAG, "onSubscriptionStateChanged failed: " + client.getPackageName(),
+                        e);
             }
-            if (DBG) Log.d(TAG, "New layer availability: " + allPublisherOfferings);
-            mAvailableLayers.setPublishersOffering(allPublisherOfferings);
-        }
-    }
-
-    private void notifyOfSubscriptionChange() {
-        VmsSubscriptionState subscriptionState = getSubscriptionState();
-        Log.i(TAG, "Notifying publishers of subscriptions: " + subscriptionState);
-        // Notify the App publishers
-        for (PublisherListener listener : mPublisherListeners) {
-            listener.onSubscriptionChange(subscriptionState);
-        }
-    }
-
-    private void notifyOfAvailabilityChange() {
-        VmsAvailableLayers availableLayers = getAvailableLayers();
-        Log.i(TAG, "Notifying subscribers of layers availability: " + availableLayers);
-        // Notify the App subscribers
-        for (SubscriberListener listener : mSubscriberListeners) {
-            listener.onLayersAvailabilityChange(availableLayers);
         }
     }
 }
diff --git a/service/src/com/android/car/vms/VmsClientInfo.java b/service/src/com/android/car/vms/VmsClientInfo.java
new file mode 100644
index 0000000..d64b6b7
--- /dev/null
+++ b/service/src/com/android/car/vms/VmsClientInfo.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.vms;
+
+import android.car.vms.IVmsClientCallback;
+import android.car.vms.VmsAssociatedLayer;
+import android.car.vms.VmsLayer;
+import android.car.vms.VmsLayerDependency;
+import android.car.vms.VmsLayersOffering;
+import android.os.IBinder;
+import android.util.ArraySet;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Class for tracking Vehicle Map Service client information, offerings, and subscriptions.
+ */
+final class VmsClientInfo {
+    private final int mUid;
+    private final String mPackageName;
+    private final IVmsClientCallback mCallback;
+    private final boolean mLegacyClient;
+    private final IBinder.DeathRecipient mDeathRecipient;
+
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private final SparseBooleanArray mProviderIds = new SparseBooleanArray();
+    @GuardedBy("mLock")
+    private final SparseArray<Set<VmsLayerDependency>> mOfferings = new SparseArray<>();
+    @GuardedBy("mLock")
+    private final SparseArray<Set<VmsLayer>> mPotentialOfferings = new SparseArray<>();
+    @GuardedBy("mLock")
+    private Set<VmsLayer> mLayerSubscriptions = Collections.emptySet();
+    @GuardedBy("mLock")
+    private Map<VmsLayer, Set<Integer>> mLayerAndProviderSubscriptions = Collections.emptyMap();
+    @GuardedBy("mLock")
+    private boolean mMonitoringEnabled;
+
+    VmsClientInfo(int uid, String packageName, IVmsClientCallback callback, boolean legacyClient,
+            IBinder.DeathRecipient deathRecipient) {
+        mUid = uid;
+        mPackageName = packageName;
+        mCallback = callback;
+        mLegacyClient = legacyClient;
+        mDeathRecipient = deathRecipient;
+    }
+
+    int getUid() {
+        return mUid;
+    }
+
+    String getPackageName() {
+        return mPackageName;
+    }
+
+    IVmsClientCallback getCallback() {
+        return mCallback;
+    }
+
+    boolean isLegacyClient() {
+        return mLegacyClient;
+    }
+
+    IBinder.DeathRecipient getDeathRecipient() {
+        return mDeathRecipient;
+    }
+
+    void addProviderId(int providerId) {
+        synchronized (mLock) {
+            mProviderIds.put(providerId, true);
+        }
+    }
+
+    boolean hasProviderId(int providerId) {
+        synchronized (mLock) {
+            return mProviderIds.get(providerId);
+        }
+    }
+
+    boolean setProviderOfferings(int providerId, Collection<VmsLayerDependency> offerings) {
+        synchronized (mLock) {
+            Set<VmsLayerDependency> providerOfferings = mOfferings.get(providerId);
+
+            // If the offerings are unchanged, do nothing
+            if (providerOfferings != null
+                    && providerOfferings.size() == offerings.size()
+                    && providerOfferings.containsAll(offerings)) {
+                return false;
+            }
+
+            // Otherwise, update the offerings and return true
+            mOfferings.put(providerId, new ArraySet<>(offerings));
+            mPotentialOfferings.put(providerId, offerings.stream()
+                    .map(VmsLayerDependency::getLayer)
+                    .collect(Collectors.toSet()));
+            return true;
+        }
+    }
+
+    Collection<VmsLayersOffering> getAllOfferings() {
+        List<VmsLayersOffering> result = new ArrayList<>(mOfferings.size());
+        synchronized (mLock) {
+            for (int i = 0; i < mOfferings.size(); i++) {
+                int providerId = mOfferings.keyAt(i);
+                Set<VmsLayerDependency> providerOfferings = mOfferings.valueAt(i);
+                result.add(new VmsLayersOffering(new ArraySet<>(providerOfferings), providerId));
+            }
+        }
+        return result;
+    }
+
+    boolean hasOffering(int providerId, VmsLayer layer) {
+        synchronized (mLock) {
+            return mPotentialOfferings.get(providerId, Collections.emptySet()).contains(layer);
+        }
+    }
+
+    void setSubscriptions(List<VmsAssociatedLayer> layers) {
+        synchronized (mLock) {
+            mLayerSubscriptions = layers.stream()
+                    .filter(associatedLayer -> associatedLayer.getProviderIds().isEmpty())
+                    .map(VmsAssociatedLayer::getVmsLayer)
+                    .collect(Collectors.toSet());
+            mLayerAndProviderSubscriptions = layers.stream()
+                    .filter(associatedLayer -> !associatedLayer.getProviderIds().isEmpty())
+                    .collect(Collectors.toMap(
+                            VmsAssociatedLayer::getVmsLayer,
+                            associatedLayer -> new ArraySet<>(associatedLayer.getProviderIds())));
+        }
+    }
+
+    Set<VmsLayer> getLayerSubscriptions() {
+        synchronized (mLock) {
+            return new ArraySet<>(mLayerSubscriptions);
+        }
+    }
+
+    Map<VmsLayer, Set<Integer>> getLayerAndProviderSubscriptions() {
+        synchronized (mLock) {
+            return deepCopy(mLayerAndProviderSubscriptions);
+        }
+    }
+
+    void setMonitoringEnabled(boolean enabled) {
+        synchronized (mLock) {
+            mMonitoringEnabled = enabled;
+        }
+    }
+
+    boolean isSubscribed(int providerId, VmsLayer layer) {
+        synchronized (mLock) {
+            return mMonitoringEnabled
+                    || mLayerSubscriptions.contains(layer)
+                    || mLayerAndProviderSubscriptions.getOrDefault(layer, Collections.emptySet())
+                            .contains(providerId);
+        }
+    }
+
+    void dump(PrintWriter writer, String indent) {
+        synchronized (mLock) {
+            String prefix = indent;
+            writer.println(prefix + "VmsClient [" + mPackageName + "]");
+
+            prefix = indent + "  ";
+            writer.println(prefix + "UID: " + mUid);
+            writer.println(prefix + "Legacy Client: " + mLegacyClient);
+            writer.println(prefix + "Monitoring: " + mMonitoringEnabled);
+
+            if (mProviderIds.size() > 0) {
+                writer.println(prefix + "Offerings:");
+                for (int i = 0; i < mProviderIds.size(); i++) {
+                    prefix = indent + "    ";
+                    int providerId = mProviderIds.keyAt(i);
+                    writer.println(prefix + "Provider [" + providerId + "]");
+
+                    for (VmsLayerDependency layerOffering : mOfferings.get(
+                            providerId, Collections.emptySet())) {
+                        prefix = indent + "      ";
+                        writer.println(prefix + layerOffering.getLayer());
+                        if (!layerOffering.getDependencies().isEmpty()) {
+                            prefix = indent + "        ";
+                            writer.println(prefix + "Dependencies: "
+                                    + layerOffering.getDependencies());
+                        }
+                    }
+                }
+            }
+
+            if (!mLayerSubscriptions.isEmpty() || !mLayerAndProviderSubscriptions.isEmpty()) {
+                prefix = indent + "  ";
+                writer.println(prefix + "Subscriptions:");
+
+                prefix = indent + "    ";
+                for (VmsLayer layer : mLayerSubscriptions) {
+                    writer.println(prefix + layer);
+                }
+                for (Map.Entry<VmsLayer, Set<Integer>> layerEntry :
+                        mLayerAndProviderSubscriptions.entrySet()) {
+                    writer.println(prefix + layerEntry.getKey() + ": " + layerEntry.getValue());
+                }
+            }
+        }
+    }
+
+    private static <K, V> Map<K, Set<V>> deepCopy(Map<K, Set<V>> original) {
+        return original.entrySet().stream().collect(Collectors.toMap(
+                Map.Entry::getKey,
+                entry -> new ArraySet<>(entry.getValue())));
+    }
+}
diff --git a/service/src/com/android/car/vms/VmsClientManager.java b/service/src/com/android/car/vms/VmsClientManager.java
deleted file mode 100644
index f2c4813..0000000
--- a/service/src/com/android/car/vms/VmsClientManager.java
+++ /dev/null
@@ -1,614 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.vms;
-
-import android.car.Car;
-import android.car.vms.IVmsPublisherClient;
-import android.car.vms.IVmsSubscriberClient;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import com.android.car.CarServiceBase;
-import com.android.car.R;
-import com.android.car.VmsPublisherService;
-import com.android.car.hal.VmsHalService;
-import com.android.car.stats.CarStatsService;
-import com.android.car.stats.VmsClientLogger;
-import com.android.car.stats.VmsClientLogger.ConnectionState;
-import com.android.car.user.CarUserService;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.PrintWriter;
-import java.util.Collection;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.function.IntSupplier;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-/**
- * Manages service connections lifecycle for VMS publisher clients.
- *
- * Binds to system-level clients at boot and creates/destroys bindings for userspace clients
- * according to the Android user lifecycle.
- */
-public class VmsClientManager implements CarServiceBase {
-    private static final boolean DBG = false;
-    private static final String TAG = "VmsClientManager";
-    private static final String HAL_CLIENT_NAME = "HalClient";
-    private static final String UNKNOWN_PACKAGE = "UnknownPackage";
-
-    private final Context mContext;
-    private final PackageManager mPackageManager;
-    private final UserManager mUserManager;
-    private final CarUserService mUserService;
-    private final CarStatsService mStatsService;
-    private final Handler mHandler;
-    private final IntSupplier mGetCallingUid;
-    private final int mMillisBeforeRebind;
-
-    private final Object mLock = new Object();
-
-    @GuardedBy("mLock")
-    private final VmsBrokerService mBrokerService;
-    @GuardedBy("mLock")
-    private VmsPublisherService mPublisherService;
-
-    @GuardedBy("mLock")
-    private final Map<String, PublisherConnection> mSystemClients = new ArrayMap<>();
-    @GuardedBy("mLock")
-    private IVmsPublisherClient mHalClient;
-    @GuardedBy("mLock")
-    private boolean mSystemUserUnlocked;
-
-    @GuardedBy("mLock")
-    private final Map<String, PublisherConnection> mCurrentUserClients = new ArrayMap<>();
-    @GuardedBy("mLock")
-    private int mCurrentUser;
-
-    @GuardedBy("mLock")
-    private final Map<IBinder, SubscriberConnection> mSubscribers = new ArrayMap<>();
-
-    @VisibleForTesting
-    final Runnable mSystemUserUnlockedListener = () -> {
-        synchronized (mLock) {
-            mSystemUserUnlocked = true;
-        }
-        bindToSystemClients();
-    };
-
-    @VisibleForTesting
-    public final CarUserService.UserCallback mUserCallback = new CarUserService.UserCallback() {
-        @Override
-        public void onSwitchUser(int userId) {
-            synchronized (mLock) {
-                if (mCurrentUser != userId) {
-                    mCurrentUser = userId;
-                    terminate(mCurrentUserClients);
-                    terminate(mSubscribers.values().stream()
-                            .filter(subscriber -> subscriber.mUserId != mCurrentUser)
-                            .filter(subscriber -> subscriber.mUserId != UserHandle.USER_SYSTEM));
-                }
-            }
-            bindToUserClients();
-        }
-
-        @Override
-        public void onUserLockChanged(int userId, boolean unlocked) {
-            synchronized (mLock) {
-                if (mCurrentUser == userId && unlocked) {
-                    bindToUserClients();
-                }
-            }
-        }
-    };
-
-    /**
-     * Constructor for client manager.
-     *
-     * @param context           Context to use for registering receivers and binding services.
-     * @param statsService      Service for logging client metrics.
-     * @param userService       User service for registering system unlock listener.
-     * @param brokerService     Service managing the VMS publisher/subscriber state.
-     * @param halService        Service providing the HAL client interface
-     */
-    public VmsClientManager(Context context, CarStatsService statsService,
-            CarUserService userService, VmsBrokerService brokerService,
-            VmsHalService halService) {
-        this(context, statsService, userService, brokerService, halService,
-                new Handler(Looper.getMainLooper()), Binder::getCallingUid);
-    }
-
-    @VisibleForTesting
-    VmsClientManager(Context context, CarStatsService statsService,
-            CarUserService userService, VmsBrokerService brokerService,
-            VmsHalService halService, Handler handler, IntSupplier getCallingUid) {
-        mContext = context;
-        mPackageManager = context.getPackageManager();
-        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
-        mStatsService = statsService;
-        mUserService = userService;
-        mCurrentUser = UserHandle.USER_NULL;
-        mBrokerService = brokerService;
-        mHandler = handler;
-        mGetCallingUid = getCallingUid;
-        mMillisBeforeRebind = context.getResources().getInteger(
-                com.android.car.R.integer.millisecondsBeforeRebindToVmsPublisher);
-
-        halService.setClientManager(this);
-    }
-
-    /**
-     * Registers the publisher service for connection callbacks.
-     *
-     * @param publisherService Publisher service to register.
-     */
-    public void setPublisherService(VmsPublisherService publisherService) {
-        synchronized (mLock) {
-            mPublisherService = publisherService;
-        }
-    }
-
-    @Override
-    public void init() {
-        mUserService.runOnUser0Unlock(mSystemUserUnlockedListener);
-        mUserService.addUserCallback(mUserCallback);
-    }
-
-    @Override
-    public void release() {
-        mUserService.removeUserCallback(mUserCallback);
-        synchronized (mLock) {
-            if (mHalClient != null) {
-                mPublisherService.onClientDisconnected(HAL_CLIENT_NAME);
-            }
-            terminate(mSystemClients);
-            terminate(mCurrentUserClients);
-            terminate(mSubscribers.values().stream());
-        }
-    }
-
-    @Override
-    public void dump(PrintWriter writer) {
-        writer.println("*" + getClass().getSimpleName() + "*");
-        synchronized (mLock) {
-            writer.println("mCurrentUser:" + mCurrentUser);
-            writer.println("mHalClient: " + (mHalClient != null ? "connected" : "disconnected"));
-            writer.println("mSystemClients:");
-            dumpConnections(writer, mSystemClients);
-
-            writer.println("mCurrentUserClients:");
-            dumpConnections(writer, mCurrentUserClients);
-
-            writer.println("mSubscribers:");
-            for (SubscriberConnection subscriber : mSubscribers.values()) {
-                writer.printf("\t%s\n", subscriber);
-            }
-        }
-    }
-
-
-    /**
-     * Adds a subscriber for connection tracking.
-     *
-     * @param subscriberClient Subscriber client to track.
-     */
-    public void addSubscriber(IVmsSubscriberClient subscriberClient) {
-        if (subscriberClient == null) {
-            Log.e(TAG, "Trying to add a null subscriber: "
-                    + getCallingPackage(mGetCallingUid.getAsInt()));
-            throw new IllegalArgumentException("subscriber cannot be null.");
-        }
-
-        synchronized (mLock) {
-            IBinder subscriberBinder = subscriberClient.asBinder();
-            if (mSubscribers.containsKey(subscriberBinder)) {
-                // Already registered
-                return;
-            }
-
-            int callingUid = mGetCallingUid.getAsInt();
-            int subscriberUserId = UserHandle.getUserId(callingUid);
-            if (subscriberUserId != mCurrentUser && subscriberUserId != UserHandle.USER_SYSTEM) {
-                throw new SecurityException("Caller must be foreground user or system");
-            }
-
-            SubscriberConnection subscriber = new SubscriberConnection(
-                    subscriberClient, callingUid, getCallingPackage(callingUid), subscriberUserId);
-            if (DBG) Log.d(TAG, "Registering subscriber: " + subscriber);
-            try {
-                subscriberBinder.linkToDeath(subscriber, 0);
-            } catch (RemoteException e) {
-                throw new IllegalStateException("Subscriber already dead: " + subscriber, e);
-            }
-            mSubscribers.put(subscriberBinder, subscriber);
-        }
-    }
-
-    /**
-     * Removes a subscriber for connection tracking and expires its subscriptions.
-     *
-     * @param subscriberClient Subscriber client to remove.
-     */
-    public void removeSubscriber(IVmsSubscriberClient subscriberClient) {
-        synchronized (mLock) {
-            SubscriberConnection subscriber = mSubscribers.get(subscriberClient.asBinder());
-            if (subscriber != null) {
-                subscriber.terminate();
-            }
-        }
-    }
-
-    /**
-     * Returns all active subscriber clients.
-     */
-    public Collection<IVmsSubscriberClient> getAllSubscribers() {
-        synchronized (mLock) {
-            return mSubscribers.values().stream()
-                    .map(subscriber -> subscriber.mClient)
-                    .collect(Collectors.toList());
-        }
-    }
-
-    /**
-     * Gets the application UID associated with a subscriber client.
-     */
-    public int getSubscriberUid(IVmsSubscriberClient subscriberClient) {
-        synchronized (mLock) {
-            SubscriberConnection subscriber = mSubscribers.get(subscriberClient.asBinder());
-            return subscriber != null ? subscriber.mUid : Process.INVALID_UID;
-        }
-    }
-
-    /**
-     * Gets the package name for a given subscriber client.
-     */
-    public String getPackageName(IVmsSubscriberClient subscriberClient) {
-        synchronized (mLock) {
-            SubscriberConnection subscriber = mSubscribers.get(subscriberClient.asBinder());
-            return subscriber != null ? subscriber.mPackageName : UNKNOWN_PACKAGE;
-        }
-    }
-
-    /**
-     * Registers the HAL client connections.
-     */
-    public void onHalConnected(IVmsPublisherClient publisherClient,
-            IVmsSubscriberClient subscriberClient) {
-        synchronized (mLock) {
-            mHalClient = publisherClient;
-            mPublisherService.onClientConnected(HAL_CLIENT_NAME, mHalClient);
-            mSubscribers.put(subscriberClient.asBinder(),
-                    new SubscriberConnection(subscriberClient, Process.myUid(), HAL_CLIENT_NAME,
-                            UserHandle.USER_SYSTEM));
-        }
-        mStatsService.getVmsClientLogger(Process.myUid())
-                .logConnectionState(ConnectionState.CONNECTED);
-    }
-
-    /**
-     *
-     */
-    public void onHalDisconnected() {
-        synchronized (mLock) {
-            if (mHalClient != null) {
-                mPublisherService.onClientDisconnected(HAL_CLIENT_NAME);
-                mStatsService.getVmsClientLogger(Process.myUid())
-                        .logConnectionState(ConnectionState.DISCONNECTED);
-            }
-            mHalClient = null;
-            terminate(mSubscribers.values().stream()
-                    .filter(subscriber -> HAL_CLIENT_NAME.equals(subscriber.mPackageName)));
-        }
-    }
-
-    private void dumpConnections(PrintWriter writer,
-            Map<String, PublisherConnection> connectionMap) {
-        for (PublisherConnection connection : connectionMap.values()) {
-            writer.printf("\t%s: %s\n",
-                    connection.mName.getPackageName(),
-                    connection.mIsBound ? "connected" : "disconnected");
-        }
-    }
-
-    private void bindToSystemClients() {
-        String[] clientNames = mContext.getResources().getStringArray(
-                R.array.vmsPublisherSystemClients);
-        synchronized (mLock) {
-            if (!mSystemUserUnlocked) {
-                return;
-            }
-            Log.i(TAG, "Attempting to bind " + clientNames.length + " system client(s)");
-            for (String clientName : clientNames) {
-                bind(mSystemClients, clientName, UserHandle.SYSTEM);
-            }
-        }
-    }
-
-    private void bindToUserClients() {
-        bindToSystemClients(); // Bind system clients on user switch, if they are not already bound.
-        synchronized (mLock) {
-            if (mCurrentUser == UserHandle.USER_NULL) {
-                Log.e(TAG, "Unknown user in foreground.");
-                return;
-            }
-            // To avoid the risk of double-binding, clients running as the system user must only
-            // ever be bound in bindToSystemClients().
-            if (mCurrentUser == UserHandle.USER_SYSTEM) {
-                Log.e(TAG, "System user in foreground. Userspace clients will not be bound.");
-                return;
-            }
-
-            if (!mUserManager.isUserUnlockingOrUnlocked(mCurrentUser)) {
-                Log.i(TAG, "Waiting for foreground user " + mCurrentUser + " to be unlocked.");
-                return;
-            }
-
-            String[] clientNames = mContext.getResources().getStringArray(
-                    R.array.vmsPublisherUserClients);
-            Log.i(TAG, "Attempting to bind " + clientNames.length + " user client(s)");
-            UserHandle currentUserHandle = UserHandle.of(mCurrentUser);
-            for (String clientName : clientNames) {
-                bind(mCurrentUserClients, clientName, currentUserHandle);
-            }
-        }
-    }
-
-    private void bind(Map<String, PublisherConnection> connectionMap, String clientName,
-            UserHandle userHandle) {
-        if (connectionMap.containsKey(clientName)) {
-            Log.i(TAG, "Already bound: " + clientName);
-            return;
-        }
-
-        ComponentName name = ComponentName.unflattenFromString(clientName);
-        if (name == null) {
-            Log.e(TAG, "Invalid client name: " + clientName);
-            return;
-        }
-
-        ServiceInfo serviceInfo;
-        try {
-            serviceInfo = mContext.getPackageManager().getServiceInfo(name,
-                    PackageManager.MATCH_DIRECT_BOOT_AUTO);
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.w(TAG, "Client not installed: " + clientName);
-            return;
-        }
-
-        VmsClientLogger statsLog = mStatsService.getVmsClientLogger(
-                UserHandle.getUid(userHandle.getIdentifier(), serviceInfo.applicationInfo.uid));
-
-        if (!Car.PERMISSION_BIND_VMS_CLIENT.equals(serviceInfo.permission)) {
-            Log.e(TAG, "Client service: " + clientName
-                    + " does not require " + Car.PERMISSION_BIND_VMS_CLIENT + " permission");
-            statsLog.logConnectionState(ConnectionState.CONNECTION_ERROR);
-            return;
-        }
-
-        PublisherConnection connection = new PublisherConnection(name, userHandle, statsLog);
-        if (connection.bind()) {
-            Log.i(TAG, "Client bound: " + connection);
-            connectionMap.put(clientName, connection);
-        } else {
-            Log.e(TAG, "Binding failed: " + connection);
-        }
-    }
-
-    private void terminate(Map<String, PublisherConnection> connectionMap) {
-        connectionMap.values().forEach(PublisherConnection::terminate);
-        connectionMap.clear();
-    }
-
-    class PublisherConnection implements ServiceConnection {
-        private final ComponentName mName;
-        private final UserHandle mUser;
-        private final String mFullName;
-        private final VmsClientLogger mStatsLog;
-        private boolean mIsBound = false;
-        private boolean mIsTerminated = false;
-        private boolean mRebindScheduled = false;
-        private IVmsPublisherClient mClientService;
-
-        PublisherConnection(ComponentName name, UserHandle user, VmsClientLogger statsLog) {
-            mName = name;
-            mUser = user;
-            mFullName = mName.flattenToString() + " U=" + mUser.getIdentifier();
-            mStatsLog = statsLog;
-        }
-
-        synchronized boolean bind() {
-            if (mIsBound) {
-                return true;
-            }
-            if (mIsTerminated) {
-                return false;
-            }
-            mStatsLog.logConnectionState(ConnectionState.CONNECTING);
-
-            if (DBG) Log.d(TAG, "binding: " + mFullName);
-            Intent intent = new Intent();
-            intent.setComponent(mName);
-            try {
-                mIsBound = mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
-                        mHandler, mUser);
-            } catch (SecurityException e) {
-                Log.e(TAG, "While binding " + mFullName, e);
-            }
-
-            if (!mIsBound) {
-                mStatsLog.logConnectionState(ConnectionState.CONNECTION_ERROR);
-            }
-
-            return mIsBound;
-        }
-
-        synchronized void unbind() {
-            if (!mIsBound) {
-                return;
-            }
-
-            if (DBG) Log.d(TAG, "unbinding: " + mFullName);
-            try {
-                mContext.unbindService(this);
-            } catch (Throwable t) {
-                Log.e(TAG, "While unbinding " + mFullName, t);
-            }
-            mIsBound = false;
-        }
-
-        synchronized void scheduleRebind() {
-            if (mRebindScheduled) {
-                return;
-            }
-
-            if (DBG) {
-                Log.d(TAG,
-                        String.format("rebinding %s after %dms", mFullName, mMillisBeforeRebind));
-            }
-            mHandler.postDelayed(this::doRebind, mMillisBeforeRebind);
-            mRebindScheduled = true;
-        }
-
-        synchronized void doRebind() {
-            mRebindScheduled = false;
-            // Do not rebind if the connection has been terminated, or the client service has
-            // reconnected on its own.
-            if (mIsTerminated || mClientService != null) {
-                return;
-            }
-
-            Log.i(TAG, "Rebinding: " + mFullName);
-            // Ensure that the client is not bound before attempting to rebind.
-            // If the client is not currently bound, unbind() will have no effect.
-            unbind();
-            bind();
-        }
-
-        synchronized void terminate() {
-            if (DBG) Log.d(TAG, "terminating: " + mFullName);
-            mIsTerminated = true;
-            notifyOnDisconnect(ConnectionState.TERMINATED);
-            unbind();
-        }
-
-        synchronized void notifyOnDisconnect(int connectionState) {
-            if (mClientService != null) {
-                mPublisherService.onClientDisconnected(mFullName);
-                mClientService = null;
-                mStatsLog.logConnectionState(connectionState);
-            }
-        }
-
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            if (DBG) Log.d(TAG, "onServiceConnected: " + mFullName);
-            mClientService = IVmsPublisherClient.Stub.asInterface(service);
-            mPublisherService.onClientConnected(mFullName, mClientService);
-            mStatsLog.logConnectionState(ConnectionState.CONNECTED);
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            if (DBG) Log.d(TAG, "onServiceDisconnected: " + mFullName);
-            notifyOnDisconnect(ConnectionState.DISCONNECTED);
-            scheduleRebind();
-        }
-
-        @Override
-        public void onBindingDied(ComponentName name) {
-            if (DBG) Log.d(TAG, "onBindingDied: " + mFullName);
-            notifyOnDisconnect(ConnectionState.DISCONNECTED);
-            scheduleRebind();
-        }
-
-        @Override
-        public String toString() {
-            return mFullName;
-        }
-    }
-
-    private void terminate(Stream<SubscriberConnection> subscribers) {
-        // Make a copy of the stream, so that terminate() doesn't cause a concurrent modification
-        subscribers.collect(Collectors.toList()).forEach(SubscriberConnection::terminate);
-    }
-
-    // If we're in a binder call, returns back the package name of the caller of the binder call.
-    private String getCallingPackage(int uid) {
-        String packageName = mPackageManager.getNameForUid(uid);
-        if (packageName == null) {
-            return UNKNOWN_PACKAGE;
-        } else {
-            return packageName;
-        }
-    }
-
-    private class SubscriberConnection implements IBinder.DeathRecipient {
-        private final IVmsSubscriberClient mClient;
-        private final int mUid;
-        private final String mPackageName;
-        private final int mUserId;
-
-        SubscriberConnection(IVmsSubscriberClient subscriberClient, int uid, String packageName,
-                int userId) {
-            mClient = subscriberClient;
-            mUid = uid;
-            mPackageName = packageName;
-            mUserId = userId;
-        }
-
-        @Override
-        public void binderDied() {
-            if (DBG) Log.d(TAG, "Subscriber died: " + this);
-            terminate();
-        }
-
-        @Override
-        public String toString() {
-            return mPackageName + " U=" + mUserId;
-        }
-
-        void terminate() {
-            if (DBG) Log.d(TAG, "Terminating subscriber: " + this);
-            synchronized (mLock) {
-                mBrokerService.removeDeadSubscriber(mClient);
-                IBinder subscriberBinder = mClient.asBinder();
-                try {
-                    subscriberBinder.unlinkToDeath(this, 0);
-                } catch (NoSuchElementException e) {
-                    if (DBG) Log.d(TAG, "While unlinking subscriber binder for " + this, e);
-                }
-                mSubscribers.remove(subscriberBinder);
-            }
-        }
-    }
-}
diff --git a/service/src/com/android/car/vms/VmsLayerAvailability.java b/service/src/com/android/car/vms/VmsLayerAvailability.java
new file mode 100644
index 0000000..3521336
--- /dev/null
+++ b/service/src/com/android/car/vms/VmsLayerAvailability.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.vms;
+
+import android.car.vms.VmsAssociatedLayer;
+import android.car.vms.VmsAvailableLayers;
+import android.car.vms.VmsLayer;
+import android.car.vms.VmsLayerDependency;
+import android.car.vms.VmsLayersOffering;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Manages VMS availability for layers.
+ *
+ * Each VMS publisher sets its layers offering which are a list of layers the publisher claims
+ * it might publish. VmsLayersAvailability calculates from all the offering what are the
+ * available layers.
+ */
+
+class VmsLayerAvailability {
+    private static final boolean DBG = false;
+    private static final String TAG = VmsLayerAvailability.class.getSimpleName();
+
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private final Map<VmsLayer, Set<Set<VmsLayer>>> mPotentialLayersAndDependencies =
+            new HashMap<>();
+    @GuardedBy("mLock")
+    private Set<VmsAssociatedLayer> mAvailableAssociatedLayers = Collections.emptySet();
+    @GuardedBy("mLock")
+    private Map<VmsLayer, Set<Integer>> mPotentialLayersAndPublishers = new HashMap<>();
+    @GuardedBy("mLock")
+    private int mSeq = 0;
+
+    /**
+     * Setting the current layers offerings as reported by publishers.
+     */
+    void setPublishersOffering(Collection<VmsLayersOffering> publishersLayersOfferings) {
+        synchronized (mLock) {
+            reset();
+
+            for (VmsLayersOffering offering : publishersLayersOfferings) {
+                for (VmsLayerDependency dependency : offering.getDependencies()) {
+                    VmsLayer layer = dependency.getLayer();
+
+                    // Associate publishers with layers.
+                    mPotentialLayersAndPublishers.computeIfAbsent(layer, k -> new HashSet<>())
+                            .add(offering.getPublisherId());
+
+                    // Add dependencies for availability calculation.
+                    mPotentialLayersAndDependencies.computeIfAbsent(layer, k -> new HashSet<>())
+                            .add(dependency.getDependencies());
+                }
+            }
+            calculateLayers();
+        }
+    }
+
+    /**
+     * Returns a collection of all the layers which may be published.
+     */
+    VmsAvailableLayers getAvailableLayers() {
+        synchronized (mLock) {
+            return new VmsAvailableLayers(mAvailableAssociatedLayers, mSeq);
+        }
+    }
+
+    private void reset() {
+        synchronized (mLock) {
+            mPotentialLayersAndDependencies.clear();
+            mPotentialLayersAndPublishers.clear();
+            mAvailableAssociatedLayers = Collections.emptySet();
+            mSeq += 1;
+        }
+    }
+
+    private void calculateLayers() {
+        synchronized (mLock) {
+            Set<VmsLayer> availableLayersSet = new HashSet<>();
+            Set<VmsLayer> cyclicAvoidanceAuxiliarySet = new HashSet<>();
+
+            for (VmsLayer layer : mPotentialLayersAndDependencies.keySet()) {
+                addLayerToAvailabilityCalculationLocked(layer,
+                        availableLayersSet,
+                        cyclicAvoidanceAuxiliarySet);
+            }
+
+            mAvailableAssociatedLayers = Collections.unmodifiableSet(
+                    availableLayersSet
+                            .stream()
+                            .map(l -> new VmsAssociatedLayer(l,
+                                    mPotentialLayersAndPublishers.get(l)))
+                            .collect(Collectors.toSet()));
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void addLayerToAvailabilityCalculationLocked(VmsLayer layer,
+                                                         Set<VmsLayer> currentAvailableLayers,
+                                                         Set<VmsLayer> cyclicAvoidanceSet) {
+        if (DBG) {
+            Log.d(TAG, "addLayerToAvailabilityCalculationLocked: checking layer: " + layer);
+        }
+        // If we already know that this layer is supported then we are done.
+        if (currentAvailableLayers.contains(layer)) {
+            return;
+        }
+        // If there is no offering for this layer we're done.
+        if (!mPotentialLayersAndDependencies.containsKey(layer)) {
+            return;
+        }
+        // Avoid cyclic dependency.
+        if (cyclicAvoidanceSet.contains(layer)) {
+            Log.e(TAG, "Detected a cyclic dependency: " + cyclicAvoidanceSet + " -> " + layer);
+            return;
+        }
+        // A layer may have multiple dependency sets. The layer is available if any dependency
+        // set is satisfied
+        for (Set<VmsLayer> dependencies : mPotentialLayersAndDependencies.get(layer)) {
+            // If layer does not have any dependencies then add to supported.
+            if (dependencies == null || dependencies.isEmpty()) {
+                currentAvailableLayers.add(layer);
+                return;
+            }
+            // Add the layer to cyclic avoidance set
+            cyclicAvoidanceSet.add(layer);
+
+            boolean isSupported = true;
+            for (VmsLayer dependency : dependencies) {
+                addLayerToAvailabilityCalculationLocked(dependency,
+                        currentAvailableLayers,
+                        cyclicAvoidanceSet);
+
+                if (!currentAvailableLayers.contains(dependency)) {
+                    isSupported = false;
+                    break;
+                }
+            }
+            cyclicAvoidanceSet.remove(layer);
+
+            if (isSupported) {
+                currentAvailableLayers.add(layer);
+                return;
+            }
+        }
+    }
+}
diff --git a/service/src/com/android/car/vms/VmsProviderInfoStore.java b/service/src/com/android/car/vms/VmsProviderInfoStore.java
new file mode 100644
index 0000000..5a3894c
--- /dev/null
+++ b/service/src/com/android/car/vms/VmsProviderInfoStore.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.vms;
+
+import android.annotation.Nullable;
+import android.util.ArrayMap;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+class VmsProviderInfoStore {
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private final ArrayMap<InfoWrapper, Integer> mProvidersIds = new ArrayMap<>();
+    @GuardedBy("mLock")
+    private final ArrayList<InfoWrapper> mProvidersInfo = new ArrayList<>();
+
+    private static class InfoWrapper {
+        private final byte[] mInfo;
+
+        InfoWrapper(byte[] info) {
+            mInfo = info;
+        }
+
+        public byte[] getInfo() {
+            return mInfo.clone();
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (!(o instanceof InfoWrapper)) {
+                return false;
+            }
+            InfoWrapper p = (InfoWrapper) o;
+            return Arrays.equals(this.mInfo, p.mInfo);
+        }
+
+        @Override
+        public int hashCode() {
+            return Arrays.hashCode(mInfo);
+        }
+    }
+
+    /**
+     * Retrieves the provider ID for the given provider information. If the provider information
+     * has not previously been seen, it will be assigned a new provider ID.
+     *
+     * @param providerInfo Provider information to query or register.
+     * @return Provider ID for the given provider information.
+     */
+    int getProviderId(byte[] providerInfo) {
+        Integer providerId;
+        InfoWrapper wrappedProviderInfo = new InfoWrapper(providerInfo);
+        synchronized (mLock) {
+            // Check if provider is already registered
+            providerId = mProvidersIds.get(wrappedProviderInfo);
+            if (providerId == null) {
+                // Add the new provider and assign it the next ID
+                mProvidersInfo.add(wrappedProviderInfo);
+                providerId = mProvidersInfo.size();
+                mProvidersIds.put(wrappedProviderInfo, providerId);
+            }
+        }
+        return providerId;
+    }
+
+    /**
+     * Returns the provider info associated with the given provider ID.
+     * @param providerId Provider ID to query.
+     * @return Provider info associated with the ID, or null if provider ID is unknown.
+     */
+    @Nullable
+    byte[] getProviderInfo(int providerId) {
+        synchronized (mLock) {
+            return providerId < 1 || providerId > mProvidersInfo.size()
+                    ? null
+                    : mProvidersInfo.get(providerId - 1).getInfo();
+        }
+    }
+}
diff --git a/service/src/com/android/car/watchdog/CarWatchdogService.java b/service/src/com/android/car/watchdog/CarWatchdogService.java
new file mode 100644
index 0000000..8a1ebc7
--- /dev/null
+++ b/service/src/com/android/car/watchdog/CarWatchdogService.java
@@ -0,0 +1,619 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.watchdog;
+
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
+import static android.car.watchdog.CarWatchdogManager.TIMEOUT_CRITICAL;
+import static android.car.watchdog.CarWatchdogManager.TIMEOUT_MODERATE;
+import static android.car.watchdog.CarWatchdogManager.TIMEOUT_NORMAL;
+
+import static com.android.car.CarLog.TAG_WATCHDOG;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.automotive.watchdog.ICarWatchdogClient;
+import android.automotive.watchdog.PowerCycle;
+import android.automotive.watchdog.StateType;
+import android.automotive.watchdog.UserState;
+import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
+import android.car.hardware.power.ICarPowerStateListener;
+import android.car.watchdog.ICarWatchdogService;
+import android.car.watchdoglib.CarWatchdogDaemonHelper;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+
+import com.android.car.CarLocalServices;
+import com.android.car.CarPowerManagementService;
+import com.android.car.CarServiceBase;
+import com.android.car.user.CarUserService;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Service to implement CarWatchdogManager API.
+ *
+ * <p>CarWatchdogService runs as car watchdog mediator, which checks clients' health status and
+ * reports the result to car watchdog server.
+ */
+public final class CarWatchdogService extends ICarWatchdogService.Stub implements CarServiceBase {
+
+    private static final boolean DEBUG = false; // STOPSHIP if true
+    private static final String TAG = TAG_WATCHDOG;
+    private static final int[] ALL_TIMEOUTS =
+            { TIMEOUT_CRITICAL, TIMEOUT_MODERATE, TIMEOUT_NORMAL };
+
+    private final Context mContext;
+    private final ICarWatchdogClientImpl mWatchdogClient;
+    private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+    private final CarWatchdogDaemonHelper mCarWatchdogDaemonHelper;
+    private final CarWatchdogDaemonHelper.OnConnectionChangeListener mConnectionListener =
+            (connected) -> {
+                if (connected) {
+                    registerToDaemon();
+                }
+            };
+    private final Object mLock = new Object();
+    /*
+     * Keeps the list of car watchdog client according to timeout:
+     * key => timeout, value => ClientInfo list.
+     * The value of SparseArray is guarded by mLock.
+     */
+    @GuardedBy("mLock")
+    private final SparseArray<ArrayList<ClientInfo>> mClientMap = new SparseArray<>();
+    /*
+     * Keeps the map of car watchdog client being checked by CarWatchdogService according to
+     * timeout: key => timeout, value => ClientInfo map.
+     * The value is also a map: key => session id, value => ClientInfo.
+     */
+    @GuardedBy("mLock")
+    private final SparseArray<SparseArray<ClientInfo>> mPingedClientMap = new SparseArray<>();
+    /*
+     * Keeps whether client health checking is being performed according to timeout:
+     * key => timeout, value => boolean (whether client health checking is being performed).
+     * The value of SparseArray is guarded by mLock.
+     */
+    @GuardedBy("mLock")
+    private final SparseArray<Boolean> mClientCheckInProgress = new SparseArray<>();
+    @GuardedBy("mLock")
+    private final ArrayList<ClientInfo> mClientsNotResponding = new ArrayList<>();
+    @GuardedBy("mMainHandler")
+    private int mLastSessionId;
+    @GuardedBy("mMainHandler")
+    private final SparseBooleanArray mStoppedUser = new SparseBooleanArray();
+
+    @VisibleForTesting
+    public CarWatchdogService(Context context) {
+        mContext = context;
+        mCarWatchdogDaemonHelper = new CarWatchdogDaemonHelper(TAG_WATCHDOG);
+        mWatchdogClient = new ICarWatchdogClientImpl(this);
+    }
+
+    @Override
+    public void init() {
+        for (int timeout : ALL_TIMEOUTS) {
+            mClientMap.put(timeout, new ArrayList<ClientInfo>());
+            mPingedClientMap.put(timeout, new SparseArray<ClientInfo>());
+            mClientCheckInProgress.put(timeout, false);
+        }
+        subscribePowerCycleChange();
+        subscribeUserStateChange();
+        mCarWatchdogDaemonHelper.addOnConnectionChangeListener(mConnectionListener);
+        mCarWatchdogDaemonHelper.connect();
+        if (DEBUG) {
+            Log.d(TAG, "CarWatchdogService is initialized");
+        }
+    }
+
+    @Override
+    public void release() {
+        unregisterFromDaemon();
+        mCarWatchdogDaemonHelper.disconnect();
+    }
+
+    @Override
+    public void dump(PrintWriter writer) {
+        String indent = "  ";
+        int count = 1;
+        synchronized (mLock) {
+            writer.println("*CarWatchdogService*");
+            writer.println("Registered clients");
+            for (int timeout : ALL_TIMEOUTS) {
+                ArrayList<ClientInfo> clients = mClientMap.get(timeout);
+                String timeoutStr = timeoutToString(timeout);
+                for (int i = 0; i < clients.size(); i++, count++) {
+                    ClientInfo clientInfo = clients.get(i);
+                    writer.printf("%sclient #%d: timeout = %s, pid = %d\n",
+                            indent, count, timeoutStr, clientInfo.pid);
+                }
+            }
+            writer.printf("Stopped users: ");
+            int size = mStoppedUser.size();
+            if (size > 0) {
+                writer.printf("%d", mStoppedUser.keyAt(0));
+                for (int i = 1; i < size; i++) {
+                    writer.printf(", %d", mStoppedUser.keyAt(i));
+                }
+                writer.printf("\n");
+            } else {
+                writer.printf("none\n");
+            }
+        }
+    }
+
+    /**
+     * Registers {@link android.automotive.watchdog. ICarWatchdogClient} to
+     * {@link CarWatchdogService}.
+     */
+    @Override
+    public void registerClient(ICarWatchdogClient client, int timeout) {
+        ArrayList<ClientInfo> clients = mClientMap.get(timeout);
+        if (clients == null) {
+            Log.w(TAG, "Cannot register the client: invalid timeout");
+            return;
+        }
+        synchronized (mLock) {
+            IBinder binder = client.asBinder();
+            for (int i = 0; i < clients.size(); i++) {
+                ClientInfo clientInfo = clients.get(i);
+                if (binder == clientInfo.client.asBinder()) {
+                    Log.w(TAG,
+                            "Cannot register the client: the client(pid:" + clientInfo.pid
+                            + ") has been already registered");
+                    return;
+                }
+            }
+            int pid = Binder.getCallingPid();
+            int userId = UserHandle.getUserId(Binder.getCallingUid());
+            ClientInfo clientInfo = new ClientInfo(client, pid, userId, timeout);
+            try {
+                clientInfo.linkToDeath();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Cannot register the client: linkToDeath to the client failed");
+                return;
+            }
+            clients.add(clientInfo);
+            if (DEBUG) {
+                Log.d(TAG, "Client(pid: " + pid + ") is registered");
+            }
+        }
+    }
+
+    /**
+     * Unregisters {@link android.automotive.watchdog. ICarWatchdogClient} from
+     * {@link CarWatchdogService}.
+     */
+    @Override
+    public void unregisterClient(ICarWatchdogClient client) {
+        synchronized (mLock) {
+            IBinder binder = client.asBinder();
+            for (int timeout : ALL_TIMEOUTS) {
+                ArrayList<ClientInfo> clients = mClientMap.get(timeout);
+                for (int i = 0; i < clients.size(); i++) {
+                    ClientInfo clientInfo = clients.get(i);
+                    if (binder != clientInfo.client.asBinder()) {
+                        continue;
+                    }
+                    clientInfo.unlinkToDeath();
+                    clients.remove(i);
+                    if (DEBUG) {
+                        Log.d(TAG, "Client(pid: " + clientInfo.pid + ") is unregistered");
+                    }
+                    return;
+                }
+            }
+        }
+        Log.w(TAG, "Cannot unregister the client: the client has not been registered before");
+        return;
+    }
+
+    /**
+     * Tells {@link CarWatchdogService} that the client is alive.
+     */
+    @Override
+    public void tellClientAlive(ICarWatchdogClient client, int sessionId) {
+        synchronized (mLock) {
+            for (int timeout : ALL_TIMEOUTS) {
+                if (!mClientCheckInProgress.get(timeout)) {
+                    continue;
+                }
+                SparseArray<ClientInfo> pingedClients = mPingedClientMap.get(timeout);
+                ClientInfo clientInfo = pingedClients.get(sessionId);
+                if (clientInfo != null && clientInfo.client.asBinder() == client.asBinder()) {
+                    pingedClients.remove(sessionId);
+                    return;
+                }
+            }
+        }
+    }
+
+    @VisibleForTesting
+    protected int getClientCount(int timeout) {
+        synchronized (mLock) {
+            ArrayList<ClientInfo> clients = mClientMap.get(timeout);
+            return clients != null ? clients.size() : 0;
+        }
+    }
+
+    private void registerToDaemon() {
+        try {
+            mCarWatchdogDaemonHelper.registerMediator(mWatchdogClient);
+            if (DEBUG) {
+                Log.d(TAG, "CarWatchdogService registers to car watchdog daemon");
+            }
+        } catch (RemoteException | RuntimeException e) {
+            Log.w(TAG, "Cannot register to car watchdog daemon: " + e);
+        }
+        UserManager userManager = UserManager.get(mContext);
+        List<UserInfo> users = userManager.getUsers();
+        try {
+            // TODO(b/152780162): reduce the number of RPC calls(isUserRunning).
+            for (UserInfo info : users) {
+                int userState = userManager.isUserRunning(info.id)
+                        ? UserState.USER_STATE_STARTED : UserState.USER_STATE_STOPPED;
+                mCarWatchdogDaemonHelper.notifySystemStateChange(StateType.USER_STATE, info.id,
+                        userState);
+                if (userState == UserState.USER_STATE_STOPPED) {
+                    mStoppedUser.put(info.id, true);
+                } else {
+                    mStoppedUser.delete(info.id);
+                }
+            }
+        } catch (RemoteException | RuntimeException e) {
+            Log.w(TAG, "Notifying system state change failed: " + e);
+        }
+    }
+
+    private void unregisterFromDaemon() {
+        try {
+            mCarWatchdogDaemonHelper.unregisterMediator(mWatchdogClient);
+            if (DEBUG) {
+                Log.d(TAG, "CarWatchdogService unregisters from car watchdog daemon");
+            }
+        } catch (RemoteException | RuntimeException e) {
+            Log.w(TAG, "Cannot unregister from car watchdog daemon: " + e);
+        }
+    }
+
+    private void onClientDeath(ICarWatchdogClient client, int timeout) {
+        synchronized (mLock) {
+            removeClientLocked(client.asBinder(), timeout);
+        }
+    }
+
+    private void postHealthCheckMessage(int sessionId) {
+        mMainHandler.sendMessage(obtainMessage(CarWatchdogService::doHealthCheck, this, sessionId));
+    }
+
+    private void doHealthCheck(int sessionId) {
+        // For critical clients, the response status are checked just before reporting to car
+        // watchdog daemon. For moderate and normal clients, the status are checked after allowed
+        // delay per timeout.
+        analyzeClientResponse(TIMEOUT_CRITICAL);
+        reportHealthCheckResult(sessionId);
+        sendPingToClients(TIMEOUT_CRITICAL);
+        sendPingToClientsAndCheck(TIMEOUT_MODERATE);
+        sendPingToClientsAndCheck(TIMEOUT_NORMAL);
+    }
+
+    private void analyzeClientResponse(int timeout) {
+        // Clients which are not responding are stored in mClientsNotResponding, and will be dumped
+        // and killed at the next response of CarWatchdogService to car watchdog daemon.
+        SparseArray<ClientInfo> pingedClients = mPingedClientMap.get(timeout);
+        synchronized (mLock) {
+            for (int i = 0; i < pingedClients.size(); i++) {
+                ClientInfo clientInfo = pingedClients.valueAt(i);
+                if (mStoppedUser.get(clientInfo.userId)) {
+                    continue;
+                }
+                mClientsNotResponding.add(clientInfo);
+                removeClientLocked(clientInfo.client.asBinder(), timeout);
+            }
+            mClientCheckInProgress.setValueAt(timeout, false);
+        }
+    }
+
+    private void sendPingToClients(int timeout) {
+        SparseArray<ClientInfo> pingedClients = mPingedClientMap.get(timeout);
+        ArrayList<ClientInfo> clientsToCheck;
+        synchronized (mLock) {
+            pingedClients.clear();
+            clientsToCheck = new ArrayList<>(mClientMap.get(timeout));
+            for (int i = 0; i < clientsToCheck.size(); i++) {
+                ClientInfo clientInfo = clientsToCheck.get(i);
+                if (mStoppedUser.get(clientInfo.userId)) {
+                    continue;
+                }
+                int sessionId = getNewSessionId();
+                clientInfo.sessionId = sessionId;
+                pingedClients.put(sessionId, clientInfo);
+            }
+            mClientCheckInProgress.setValueAt(timeout, true);
+        }
+        for (int i = 0; i < clientsToCheck.size(); i++) {
+            ClientInfo clientInfo = clientsToCheck.get(i);
+            try {
+                clientInfo.client.checkIfAlive(clientInfo.sessionId, timeout);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Sending a ping message to client(pid: " +  clientInfo.pid
+                        + ") failed: " + e);
+                synchronized (mLock) {
+                    pingedClients.remove(clientInfo.sessionId);
+                }
+            }
+        }
+    }
+
+    private void sendPingToClientsAndCheck(int timeout) {
+        synchronized (mLock) {
+            if (mClientCheckInProgress.get(timeout)) {
+                return;
+            }
+        }
+        sendPingToClients(timeout);
+        mMainHandler.sendMessageDelayed(obtainMessage(CarWatchdogService::analyzeClientResponse,
+                this, timeout), timeoutToDurationMs(timeout));
+    }
+
+    private int getNewSessionId() {
+        if (++mLastSessionId <= 0) {
+            mLastSessionId = 1;
+        }
+        return mLastSessionId;
+    }
+
+    private void removeClientLocked(IBinder clientBinder, int timeout) {
+        ArrayList<ClientInfo> clients = mClientMap.get(timeout);
+        for (int i = 0; i < clients.size(); i++) {
+            ClientInfo clientInfo = clients.get(i);
+            if (clientBinder == clientInfo.client.asBinder()) {
+                clients.remove(i);
+                return;
+            }
+        }
+    }
+
+    private void reportHealthCheckResult(int sessionId) {
+        int[] clientsNotResponding;
+        ArrayList<ClientInfo> clientsToNotify;
+        synchronized (mLock) {
+            clientsNotResponding = toIntArray(mClientsNotResponding);
+            clientsToNotify = new ArrayList<>(mClientsNotResponding);
+            mClientsNotResponding.clear();
+        }
+        for (int i = 0; i < clientsToNotify.size(); i++) {
+            ClientInfo clientInfo = clientsToNotify.get(i);
+            try {
+                clientInfo.client.prepareProcessTermination();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Notifying prepareProcessTermination to client(pid: " + clientInfo.pid
+                        + ") failed: " + e);
+            }
+        }
+
+        try {
+            mCarWatchdogDaemonHelper.tellMediatorAlive(mWatchdogClient, clientsNotResponding,
+                    sessionId);
+        } catch (RemoteException | RuntimeException e) {
+            Log.w(TAG, "Cannot respond to car watchdog daemon (sessionId=" + sessionId + "): " + e);
+        }
+    }
+
+    private void subscribePowerCycleChange() {
+        CarPowerManagementService powerService =
+                CarLocalServices.getService(CarPowerManagementService.class);
+        if (powerService == null) {
+            Log.w(TAG, "Cannot get CarPowerManagementService");
+            return;
+        }
+        powerService.registerListener(new ICarPowerStateListener.Stub() {
+            @Override
+            public void onStateChanged(int state) {
+                int powerCycle;
+                switch (state) {
+                    // SHUTDOWN_PREPARE covers suspend and shutdown.
+                    case CarPowerStateListener.SHUTDOWN_PREPARE:
+                        powerCycle = PowerCycle.POWER_CYCLE_SUSPEND;
+                        break;
+                    // ON covers resume.
+                    case CarPowerStateListener.ON:
+                        powerCycle = PowerCycle.POWER_CYCLE_RESUME;
+                        // There might be outdated & incorrect info. We should reset them before
+                        // starting to do health check.
+                        prepareHealthCheck();
+                        break;
+                    default:
+                        return;
+                }
+                try {
+                    mCarWatchdogDaemonHelper.notifySystemStateChange(StateType.POWER_CYCLE,
+                            powerCycle, /* arg2= */ -1);
+                    if (DEBUG) {
+                        Log.d(TAG, "Notified car watchdog daemon a power cycle("
+                                + powerCycle + ")");
+                    }
+                } catch (RemoteException | RuntimeException e) {
+                    Log.w(TAG, "Notifying system state change failed: " + e);
+                }
+            }
+        });
+    }
+
+    private void subscribeUserStateChange() {
+        CarUserService userService = CarLocalServices.getService(CarUserService.class);
+        if (userService == null) {
+            Log.w(TAG, "Cannot get CarUserService");
+            return;
+        }
+        userService.addUserLifecycleListener((event) -> {
+            int userId = event.getUserHandle().getIdentifier();
+            int userState;
+            String userStateDesc;
+            synchronized (mLock) {
+                switch (event.getEventType()) {
+                    case USER_LIFECYCLE_EVENT_TYPE_STARTING:
+                        mStoppedUser.delete(userId);
+                        userState = UserState.USER_STATE_STARTED;
+                        userStateDesc = "STARTING";
+                        break;
+                    case USER_LIFECYCLE_EVENT_TYPE_STOPPED:
+                        mStoppedUser.put(userId, true);
+                        userState = UserState.USER_STATE_STOPPED;
+                        userStateDesc = "STOPPING";
+                        break;
+                    default:
+                        return;
+                }
+            }
+            try {
+                mCarWatchdogDaemonHelper.notifySystemStateChange(StateType.USER_STATE, userId,
+                        userState);
+                if (DEBUG) {
+                    Log.d(TAG, "Notified car watchdog daemon a user state: userId = " + userId
+                            + ", userState = " + userStateDesc);
+                }
+            } catch (RemoteException | RuntimeException e) {
+                Log.w(TAG, "Notifying system state change failed: " + e);
+            }
+        });
+    }
+
+    private void prepareHealthCheck() {
+        synchronized (mLock) {
+            for (int timeout : ALL_TIMEOUTS) {
+                SparseArray<ClientInfo> pingedClients = mPingedClientMap.get(timeout);
+                pingedClients.clear();
+            }
+        }
+    }
+
+    @NonNull
+    private int[] toIntArray(@NonNull ArrayList<ClientInfo> list) {
+        int size = list.size();
+        int[] intArray = new int[size];
+        for (int i = 0; i < size; i++) {
+            intArray[i] = list.get(i).pid;
+        }
+        return intArray;
+    }
+
+    private String timeoutToString(int timeout) {
+        switch (timeout) {
+            case TIMEOUT_CRITICAL:
+                return "critical";
+            case TIMEOUT_MODERATE:
+                return "moderate";
+            case TIMEOUT_NORMAL:
+                return "normal";
+            default:
+                Log.w(TAG, "Unknown timeout value");
+                return "unknown";
+        }
+    }
+
+    private long timeoutToDurationMs(int timeout) {
+        switch (timeout) {
+            case TIMEOUT_CRITICAL:
+                return 3000L;
+            case TIMEOUT_MODERATE:
+                return 5000L;
+            case TIMEOUT_NORMAL:
+                return 10000L;
+            default:
+                Log.w(TAG, "Unknown timeout value");
+                return 10000L;
+        }
+    }
+
+    private static final class ICarWatchdogClientImpl extends ICarWatchdogClient.Stub {
+        private final WeakReference<CarWatchdogService> mService;
+
+        private ICarWatchdogClientImpl(CarWatchdogService service) {
+            mService = new WeakReference<>(service);
+        }
+
+        @Override
+        public void checkIfAlive(int sessionId, int timeout) {
+            CarWatchdogService service = mService.get();
+            if (service == null) {
+                Log.w(TAG, "CarWatchdogService is not available");
+                return;
+            }
+            service.postHealthCheckMessage(sessionId);
+        }
+
+        @Override
+        public void prepareProcessTermination() {
+            Log.w(TAG, "CarWatchdogService is about to be killed by car watchdog daemon");
+        }
+
+        @Override
+        public int getInterfaceVersion() {
+            return this.VERSION;
+        }
+
+        @Override
+        public String getInterfaceHash() {
+            return this.HASH;
+        }
+    }
+
+    private final class ClientInfo implements IBinder.DeathRecipient {
+        public final ICarWatchdogClient client;
+        public final int pid;
+        @UserIdInt public final int userId;
+        public final int timeout;
+        public volatile int sessionId;
+
+        private ClientInfo(ICarWatchdogClient client, int pid, @UserIdInt int userId, int timeout) {
+            this.client = client;
+            this.pid = pid;
+            this.userId = userId;
+            this.timeout = timeout;
+        }
+
+        @Override
+        public void binderDied() {
+            Log.w(TAG, "Client(pid: " + pid + ") died");
+            onClientDeath(client, timeout);
+        }
+
+        private void linkToDeath() throws RemoteException {
+            client.asBinder().linkToDeath(this, 0);
+        }
+
+        private void unlinkToDeath() {
+            client.asBinder().unlinkToDeath(this, 0);
+        }
+    }
+}
diff --git a/surround_view/OWNERS b/surround_view/OWNERS
new file mode 100644
index 0000000..2c5c8a7
--- /dev/null
+++ b/surround_view/OWNERS
@@ -0,0 +1,3 @@
+haoxiangl@google.com
+tanmayp@google.com
+swan@google.com
diff --git a/surround_view/app/Android.bp b/surround_view/app/Android.bp
new file mode 100644
index 0000000..efdbd43
--- /dev/null
+++ b/surround_view/app/Android.bp
@@ -0,0 +1,62 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+
+//#################################
+cc_binary {
+    name: "sv_app",
+
+    srcs: [
+        "SurroundViewServiceCallback.cpp",
+        "shader.cpp",
+        "sv_app.cpp",
+    ],
+
+    shared_libs: [
+        "android.hardware.automotive.evs@1.1",
+        "android.hardware.automotive.sv@1.0",
+        "libEGL",
+        "libGLESv2",
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "libutils",
+        "libui",
+    ],
+
+    static_libs: [
+        "libjsoncpp",
+        "libmath",
+    ],
+
+    strip: {
+        keep_symbols: true,
+    },
+
+    init_rc: ["sv_app.rc"],
+
+    cflags: [
+        "-DLOG_TAG=\"SvApp\"",
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+}
+
diff --git a/surround_view/app/SurroundViewServiceCallback.cpp b/surround_view/app/SurroundViewServiceCallback.cpp
new file mode 100644
index 0000000..05a598f
--- /dev/null
+++ b/surround_view/app/SurroundViewServiceCallback.cpp
@@ -0,0 +1,569 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SurroundViewServiceCallback.h"
+
+#include <android-base/logging.h>
+#include <math/mat4.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/Log.h>
+
+#include "shader_simpleTex.h"
+#include "shader.h"
+
+using android::GraphicBuffer;
+using android::hardware::automotive::evs::V1_0::DisplayState;
+using android::hardware::automotive::evs::V1_0::EvsResult;
+using android::hardware::Return;
+using android::sp;
+using std::string;
+
+EGLDisplay   SurroundViewServiceCallback::sGLDisplay;
+GLuint       SurroundViewServiceCallback::sFrameBuffer;
+GLuint       SurroundViewServiceCallback::sColorBuffer;
+GLuint       SurroundViewServiceCallback::sDepthBuffer;
+GLuint       SurroundViewServiceCallback::sTextureId;
+EGLImageKHR  SurroundViewServiceCallback::sKHRimage;
+
+const char* SurroundViewServiceCallback::getEGLError(void) {
+    switch (eglGetError()) {
+        case EGL_SUCCESS:
+            return "EGL_SUCCESS";
+        case EGL_NOT_INITIALIZED:
+            return "EGL_NOT_INITIALIZED";
+        case EGL_BAD_ACCESS:
+            return "EGL_BAD_ACCESS";
+        case EGL_BAD_ALLOC:
+            return "EGL_BAD_ALLOC";
+        case EGL_BAD_ATTRIBUTE:
+            return "EGL_BAD_ATTRIBUTE";
+        case EGL_BAD_CONTEXT:
+            return "EGL_BAD_CONTEXT";
+        case EGL_BAD_CONFIG:
+            return "EGL_BAD_CONFIG";
+        case EGL_BAD_CURRENT_SURFACE:
+            return "EGL_BAD_CURRENT_SURFACE";
+        case EGL_BAD_DISPLAY:
+            return "EGL_BAD_DISPLAY";
+        case EGL_BAD_SURFACE:
+            return "EGL_BAD_SURFACE";
+        case EGL_BAD_MATCH:
+            return "EGL_BAD_MATCH";
+        case EGL_BAD_PARAMETER:
+            return "EGL_BAD_PARAMETER";
+        case EGL_BAD_NATIVE_PIXMAP:
+            return "EGL_BAD_NATIVE_PIXMAP";
+        case EGL_BAD_NATIVE_WINDOW:
+            return "EGL_BAD_NATIVE_WINDOW";
+        case EGL_CONTEXT_LOST:
+            return "EGL_CONTEXT_LOST";
+        default:
+            return "Unknown error";
+    }
+}
+
+const string SurroundViewServiceCallback::getGLFramebufferError(void) {
+    switch (glCheckFramebufferStatus(GL_FRAMEBUFFER)) {
+    case GL_FRAMEBUFFER_COMPLETE:
+        return "GL_FRAMEBUFFER_COMPLETE";
+    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
+        return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
+    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
+        return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
+    case GL_FRAMEBUFFER_UNSUPPORTED:
+        return "GL_FRAMEBUFFER_UNSUPPORTED";
+    case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
+        return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
+    default:
+        return std::to_string(glCheckFramebufferStatus(GL_FRAMEBUFFER));
+    }
+}
+
+bool SurroundViewServiceCallback::prepareGL() {
+    LOG(DEBUG) << __FUNCTION__;
+
+    // Just trivially return success if we're already prepared
+    if (sGLDisplay != EGL_NO_DISPLAY) {
+        return true;
+    }
+
+    // Hardcoded to RGBx output display
+    const EGLint config_attribs[] = {
+        // Tag                  Value
+        EGL_RENDERABLE_TYPE,    EGL_OPENGL_ES2_BIT,
+        EGL_RED_SIZE,           8,
+        EGL_GREEN_SIZE,         8,
+        EGL_BLUE_SIZE,          8,
+        EGL_NONE
+    };
+
+    // Select OpenGL ES v 3
+    const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
+
+    // Set up our OpenGL ES context associated with the default display
+    // (though we won't be visible)
+    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    if (display == EGL_NO_DISPLAY) {
+        LOG(ERROR) << "Failed to get egl display";
+        return false;
+    }
+
+    EGLint major = 0;
+    EGLint minor = 0;
+    if (!eglInitialize(display, &major, &minor)) {
+        LOG(ERROR) << "Failed to initialize EGL: "
+                   << getEGLError();
+        return false;
+    } else {
+        LOG(INFO) << "Initialized EGL at "
+                  << major
+                  << "."
+                  << minor;
+    }
+
+    // Select the configuration that "best" matches our desired characteristics
+    EGLConfig egl_config;
+    EGLint num_configs;
+    if (!eglChooseConfig(display, config_attribs, &egl_config, 1,
+                         &num_configs)) {
+        LOG(ERROR) << "eglChooseConfig() failed with error: "
+                   << getEGLError();
+        return false;
+    }
+
+    // Create a dummy pbuffer so we have a surface to bind -- we never intend
+    // to draw to this because attachRenderTarget will be called first.
+    EGLint surface_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
+    EGLSurface sDummySurface = eglCreatePbufferSurface(display, egl_config,
+                                                       surface_attribs);
+    if (sDummySurface == EGL_NO_SURFACE) {
+        LOG(ERROR) << "Failed to create OpenGL ES Dummy surface: "
+                   << getEGLError();
+        return false;
+    } else {
+        LOG(INFO) << "Dummy surface looks good!  :)";
+    }
+
+    //
+    // Create the EGL context
+    //
+    EGLContext context = eglCreateContext(display, egl_config,
+                                          EGL_NO_CONTEXT, context_attribs);
+    if (context == EGL_NO_CONTEXT) {
+        LOG(ERROR) << "Failed to create OpenGL ES Context: "
+                   << getEGLError();
+        return false;
+    }
+
+    // Activate our render target for drawing
+    if (!eglMakeCurrent(display, sDummySurface, sDummySurface, context)) {
+        LOG(ERROR) << "Failed to make the OpenGL ES Context current: "
+                   << getEGLError();
+        return false;
+    } else {
+        LOG(INFO) << "We made our context current!  :)";
+    }
+
+    // Report the extensions available on this implementation
+    const char* gl_extensions = (const char*) glGetString(GL_EXTENSIONS);
+    LOG(INFO) << "GL EXTENSIONS:\n  "
+              << gl_extensions;
+
+    // Reserve handles for the color and depth targets we'll be setting up
+    glGenRenderbuffers(1, &sColorBuffer);
+    glGenRenderbuffers(1, &sDepthBuffer);
+
+    // Set up the frame buffer object we can modify and use for off screen
+    // rendering
+    glGenFramebuffers(1, &sFrameBuffer);
+    glBindFramebuffer(GL_FRAMEBUFFER, sFrameBuffer);
+
+    LOG(INFO) << "FrameBuffer is bound to "
+              << sFrameBuffer;
+
+    // New (from TextWrapper)
+    glGenTextures(1, &sTextureId);
+
+    // Now that we're assured success, store object handles we constructed
+    sGLDisplay = display;
+
+    GLuint mShaderProgram = 0;
+    // Load our shader program if we don't have it already
+    if (!mShaderProgram) {
+        mShaderProgram = buildShaderProgram(kVtxShaderSimpleTexture,
+                                            kPixShaderSimpleTexture,
+                                            "simpleTexture");
+        if (!mShaderProgram) {
+            LOG(ERROR) << "Error building shader program";
+            return false;
+        }
+    }
+
+    // Select our screen space simple texture shader
+    glUseProgram(mShaderProgram);
+
+    // Set up the model to clip space transform (identity matrix if we're
+    // modeling in screen space)
+    GLint loc = glGetUniformLocation(mShaderProgram, "cameraMat");
+    if (loc < 0) {
+        LOG(ERROR) << "Couldn't set shader parameter 'cameraMat'";
+    } else {
+        const android::mat4 identityMatrix;
+        glUniformMatrix4fv(loc, 1, false, identityMatrix.asArray());
+    }
+
+    GLint sampler = glGetUniformLocation(mShaderProgram, "tex");
+    if (sampler < 0) {
+        LOG(ERROR) << "Couldn't set shader parameter 'tex'";
+    } else {
+        // Tell the sampler we looked up from the shader to use texture slot 0
+        // as its source
+        glUniform1i(sampler, 0);
+    }
+
+    return true;
+}
+
+BufferDesc SurroundViewServiceCallback::convertBufferDesc(
+    const BufferDesc_1_0& src) {
+    BufferDesc dst = {};
+    AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<AHardwareBuffer_Desc *>(&dst.buffer.description);
+    pDesc->width  = src.width;
+    pDesc->height = src.height;
+    pDesc->layers = 1;
+    pDesc->format = src.format;
+    pDesc->usage  = static_cast<uint64_t>(src.usage);
+    pDesc->stride = src.stride;
+
+    dst.buffer.nativeHandle = src.memHandle;
+    dst.pixelSize = src.pixelSize;
+    dst.bufferId = src.bufferId;
+
+    return dst;
+}
+
+bool SurroundViewServiceCallback::attachRenderTarget(
+    const BufferDesc& tgtBuffer) {
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(
+            &tgtBuffer.buffer.description);
+    // Hardcoded to RGBx for now
+    if (pDesc->format != HAL_PIXEL_FORMAT_RGBA_8888) {
+        LOG(ERROR) << "Unsupported target buffer format";
+        return false;
+    }
+
+    // create a GraphicBuffer from the existing handle
+    sp<GraphicBuffer> pGfxBuffer =
+        new GraphicBuffer(tgtBuffer.buffer.nativeHandle,
+                          GraphicBuffer::CLONE_HANDLE,
+                          pDesc->width,
+                          pDesc->height,
+                          pDesc->format,
+                          pDesc->layers,
+                          GRALLOC_USAGE_HW_RENDER,
+                          pDesc->stride);
+    if (pGfxBuffer == nullptr) {
+        LOG(ERROR) << "Failed to allocate GraphicBuffer to wrap image handle";
+        return false;
+    }
+
+    // Get a GL compatible reference to the graphics buffer we've been given
+    EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
+    EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(
+        pGfxBuffer->getNativeBuffer());
+
+    // Destroy current KHR image due to new request.
+    if (sKHRimage != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(sGLDisplay, sKHRimage);
+    }
+
+    sKHRimage = eglCreateImageKHR(sGLDisplay, EGL_NO_CONTEXT,
+                                  EGL_NATIVE_BUFFER_ANDROID, clientBuf,
+                                  eglImageAttributes);
+    if (sKHRimage == EGL_NO_IMAGE_KHR) {
+        LOG(ERROR) << "error creating EGLImage for target buffer: "
+                   << getEGLError();
+        return false;
+    }
+
+    glBindFramebuffer(GL_FRAMEBUFFER, sFrameBuffer);
+
+    // Construct a render buffer around the external buffer
+    glBindRenderbuffer(GL_RENDERBUFFER, sColorBuffer);
+    glEGLImageTargetRenderbufferStorageOES(
+        GL_RENDERBUFFER, static_cast<GLeglImageOES>(sKHRimage));
+    if (eglGetError() != EGL_SUCCESS) {
+        LOG(INFO) << "glEGLImageTargetRenderbufferStorageOES => %s"
+                  << getEGLError();
+        return false;
+    }
+
+    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                              GL_RENDERBUFFER, sColorBuffer);
+    if (eglGetError() != EGL_SUCCESS) {
+        LOG(ERROR) << "glFramebufferRenderbuffer => %s", getEGLError();
+        return false;
+    }
+
+    GLenum checkResult = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+    if (checkResult != GL_FRAMEBUFFER_COMPLETE) {
+        LOG(ERROR) << "Offscreen framebuffer not configured successfully ("
+                   << checkResult
+                   << ": "
+                   << getGLFramebufferError().c_str()
+                   << ")";
+        if (eglGetError() != EGL_SUCCESS) {
+            LOG(ERROR) << "glCheckFramebufferStatus => "
+                       << getEGLError();
+        }
+        return false;
+    }
+
+    // Set the viewport
+    glViewport(0, 0, pDesc->width, pDesc->height);
+
+    // We don't actually need the clear if we're going to cover the whole
+    // screen anyway
+    // Clear the color buffer
+    glClearColor(0.8f, 0.1f, 0.2f, 1.0f);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    return true;
+}
+
+void SurroundViewServiceCallback::detachRenderTarget() {
+    // Drop our external render target
+    if (sKHRimage != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(sGLDisplay, sKHRimage);
+        sKHRimage = EGL_NO_IMAGE_KHR;
+    }
+}
+
+SurroundViewServiceCallback::SurroundViewServiceCallback(
+    sp<IEvsDisplay> pDisplay,
+    sp<ISurroundViewSession> pSession) :
+    mDisplay(pDisplay),
+    mSession(pSession) {
+    // Nothing but member initialization
+}
+
+Return<void> SurroundViewServiceCallback::notify(SvEvent svEvent) {
+    // Waiting for STREAM_STARTED event.
+    if (svEvent == SvEvent::STREAM_STARTED) {
+        LOG(INFO) << "Received STREAM_STARTED event";
+
+        // Set the display state to VISIBLE_ON_NEXT_FRAME
+        if (mDisplay != nullptr) {
+            Return<EvsResult> result =
+                mDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME);
+            if (result != EvsResult::OK) {
+              LOG(ERROR) << "Failed to setDisplayState";
+            }
+        } else {
+            LOG(WARNING) << "setDisplayState is ignored since EVS display"
+                         << " is null";
+        }
+
+        // Set up OpenGL (exit if fail)
+        if (!prepareGL()) {
+            LOG(ERROR) << "Error while setting up OpenGL!";
+            exit(EXIT_FAILURE);
+        }
+    } else if (svEvent == SvEvent::CONFIG_UPDATED) {
+        LOG(INFO) << "Received CONFIG_UPDATED event";
+    } else if (svEvent == SvEvent::STREAM_STOPPED) {
+        LOG(INFO) << "Received STREAM_STOPPED event";
+    } else if (svEvent == SvEvent::FRAME_DROPPED) {
+        LOG(INFO) << "Received FRAME_DROPPED event";
+    } else if (svEvent == SvEvent::TIMEOUT) {
+        LOG(INFO) << "Received TIMEOUT event";
+    } else {
+        LOG(INFO) << "Received unknown event";
+    }
+    return {};
+}
+
+Return<void> SurroundViewServiceCallback::receiveFrames(
+    const SvFramesDesc& svFramesDesc) {
+    LOG(INFO) << "Incoming frames with svBuffers size: "
+              << svFramesDesc.svBuffers.size();
+    if (svFramesDesc.svBuffers.size() == 0) {
+        return {};
+    }
+
+    // Now we assume there is only one frame for both 2d and 3d.
+    auto handle =
+          svFramesDesc.svBuffers[0].hardwareBuffer.nativeHandle
+          .getNativeHandle();
+    const AHardwareBuffer_Desc* pDesc =
+          reinterpret_cast<const AHardwareBuffer_Desc *>(
+              &svFramesDesc.svBuffers[0].hardwareBuffer.description);
+
+    LOG(INFO) << "App received frames";
+    LOG(INFO) << "descData: "
+              << pDesc->width
+              << pDesc->height
+              << pDesc->layers
+              << pDesc->format
+              << pDesc->usage
+              << pDesc->stride;
+    LOG(INFO) << "nativeHandle: "
+              << handle;
+
+    // Only process the frame when EVS display is valid. If
+    // not, ignore the coming frame.
+    if (mDisplay == nullptr) {
+        LOG(WARNING) << "Display is not ready. Skip the frame";
+    } else {
+        // Get display buffer from EVS display
+        BufferDesc_1_0 tgtBuffer = {};
+        mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) {
+            tgtBuffer = buff;
+        });
+
+        if (!attachRenderTarget(convertBufferDesc(tgtBuffer))) {
+            LOG(ERROR) << "Failed to attach render target";
+            return {};
+        } else {
+            LOG(INFO) << "Successfully attached render target";
+        }
+
+        // Call HIDL API "doneWithFrames" to return the ownership
+        // back to SV service
+        if (mSession == nullptr) {
+            LOG(ERROR) << "SurroundViewSession in callback is invalid";
+            return {};
+        } else {
+            mSession->doneWithFrames(svFramesDesc);
+        }
+
+        // Render frame to EVS display
+        LOG(INFO) << "Rendering to display buffer";
+        sp<GraphicBuffer> graphicBuffer =
+            new GraphicBuffer(handle,
+                              GraphicBuffer::CLONE_HANDLE,
+                              pDesc->width,
+                              pDesc->height,
+                              pDesc->format,
+                              pDesc->layers,  // layer count
+                              pDesc->usage,
+                              pDesc->stride);
+
+        EGLImageKHR KHRimage = EGL_NO_IMAGE_KHR;
+
+        // Get a GL compatible reference to the graphics buffer we've been given
+        EGLint eglImageAttributes[] = {
+            EGL_IMAGE_PRESERVED_KHR,
+            EGL_TRUE,
+            EGL_NONE
+        };
+        EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(
+            graphicBuffer->getNativeBuffer());
+        KHRimage = eglCreateImageKHR(sGLDisplay, EGL_NO_CONTEXT,
+                                     EGL_NATIVE_BUFFER_ANDROID, clientBuf,
+                                     eglImageAttributes);
+        if (KHRimage == EGL_NO_IMAGE_KHR) {
+            const char *msg = getEGLError();
+            LOG(ERROR) << "error creating EGLImage: "
+                       << msg;
+            return {};
+        } else {
+            LOG(INFO) << "Successfully created EGLImage";
+
+            // Update the texture handle we already created to refer to
+            // this gralloc buffer
+            glActiveTexture(GL_TEXTURE0);
+            glBindTexture(GL_TEXTURE_2D, sTextureId);
+            glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
+                                         static_cast<GLeglImageOES>(KHRimage));
+
+            // Initialize the sampling properties (it seems the sample may
+            // not work if this isn't done)
+            // The user of this texture may very well want to set their own
+            // filtering, but we're going to pay the (minor) price of
+            // setting this up for them to avoid the dreaded "black image"
+            // if they forget.
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+                            GL_LINEAR);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                            GL_NEAREST);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+                            GL_CLAMP_TO_EDGE);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
+                            GL_CLAMP_TO_EDGE);
+        }
+
+        // Bind the texture and assign it to the shader's sampler
+        glActiveTexture(GL_TEXTURE0);
+        glBindTexture(GL_TEXTURE_2D, sTextureId);
+
+        // We want our image to show up opaque regardless of alpha values
+        glDisable(GL_BLEND);
+
+        // Draw a rectangle on the screen
+        const GLfloat vertsCarPos[] = {
+            -1.0,  1.0, 0.0f,   // left top in window space
+            1.0,  1.0, 0.0f,    // right top
+            -1.0, -1.0, 0.0f,   // left bottom
+            1.0, -1.0, 0.0f     // right bottom
+        };
+        const GLfloat vertsCarTex[] = {
+            0.0f, 0.0f,   // left top
+            1.0f, 0.0f,   // right top
+            0.0f, 1.0f,   // left bottom
+            1.0f, 1.0f    // right bottom
+        };
+        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertsCarPos);
+        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, vertsCarTex);
+        glEnableVertexAttribArray(0);
+        glEnableVertexAttribArray(1);
+
+        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+        glDisableVertexAttribArray(0);
+        glDisableVertexAttribArray(1);
+
+        // Now that everything is submitted, release our hold on the
+        // texture resource
+        detachRenderTarget();
+
+        // Wait for the rendering to finish
+        glFinish();
+        detachRenderTarget();
+
+        // Drop our external render target
+        if (KHRimage != EGL_NO_IMAGE_KHR) {
+            eglDestroyImageKHR(sGLDisplay, KHRimage);
+            KHRimage = EGL_NO_IMAGE_KHR;
+        }
+
+        LOG(DEBUG) << "Rendering finished. Going to return the buffer";
+
+        // Call HIDL API "doneWithFrames" to return the ownership
+        // back to SV service
+        if (mSession == nullptr) {
+            LOG(WARNING) << "SurroundViewSession in callback is invalid";
+        } else {
+            mSession->doneWithFrames(svFramesDesc);
+        }
+
+        // Return display buffer back to EVS display
+        mDisplay->returnTargetBufferForDisplay(tgtBuffer);
+    }
+    return {};
+}
diff --git a/surround_view/app/SurroundViewServiceCallback.h b/surround_view/app/SurroundViewServiceCallback.h
new file mode 100644
index 0000000..b2ab831
--- /dev/null
+++ b/surround_view/app/SurroundViewServiceCallback.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdio.h>
+
+#include <utils/StrongPointer.h>
+
+#include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <android/hardware_buffer.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+
+using namespace android::hardware::automotive::sv::V1_0;
+using namespace android::hardware::automotive::evs::V1_1;
+
+using BufferDesc_1_0  = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+
+class SurroundViewServiceCallback : public ISurroundViewStream {
+public:
+    SurroundViewServiceCallback(android::sp<IEvsDisplay> pDisplay,
+                                android::sp<ISurroundViewSession> pSession);
+
+    // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewStream.
+    android::hardware::Return<void> notify(SvEvent svEvent) override;
+    android::hardware::Return<void> receiveFrames(const SvFramesDesc& svFramesDesc) override;
+
+private:
+    static const char* getEGLError(void);
+    static const std::string getGLFramebufferError(void);
+
+    bool prepareGL();
+    BufferDesc convertBufferDesc(const BufferDesc_1_0& src);
+    bool attachRenderTarget(const BufferDesc& tgtBuffer);
+    void detachRenderTarget();
+
+    static EGLDisplay   sGLDisplay;
+    static GLuint       sFrameBuffer;
+    static GLuint       sColorBuffer;
+    static GLuint       sDepthBuffer;
+    static GLuint       sTextureId;
+    static EGLImageKHR  sKHRimage;
+
+    android::sp<IEvsDisplay> mDisplay;
+    android::sp<ISurroundViewSession> mSession;
+};
diff --git a/surround_view/app/shader.cpp b/surround_view/app/shader.cpp
new file mode 100644
index 0000000..3ca6f74
--- /dev/null
+++ b/surround_view/app/shader.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "shader.h"
+
+#include <android-base/logging.h>
+#include <memory>
+#include <stdio.h>
+
+// Given shader source, load and compile it
+static GLuint loadShader(GLenum type, const char *shaderSrc, const char *name) {
+    // Create the shader object
+    GLuint shader = glCreateShader (type);
+    if (shader == 0) {
+        return 0;
+    }
+
+    // Load and compile the shader
+    glShaderSource(shader, 1, &shaderSrc, nullptr);
+    glCompileShader(shader);
+
+    // Verify the compilation worked as expected
+    GLint compiled = 0;
+    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+    if (!compiled) {
+        LOG(ERROR) << "Error compiling "
+                   << (type==GL_VERTEX_SHADER ? "vtx":"pxl")
+                   << " shader for "
+                   << name;
+
+        GLint size = 0;
+        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &size);
+        if (size > 0) {
+            // Get and report the error message
+            std::unique_ptr<char> infoLog(new char[size]);
+            glGetShaderInfoLog(shader, size, NULL, infoLog.get());
+            LOG(ERROR) << "  msg:\n"
+                       << infoLog.get();
+        }
+
+        glDeleteShader(shader);
+        return 0;
+    }
+
+    return shader;
+}
+
+
+// Create a program object given vertex and pixels shader source
+GLuint buildShaderProgram(const char* vtxSrc, const char* pxlSrc, const char* name) {
+    GLuint program = glCreateProgram();
+    if (program == 0) {
+        LOG(ERROR) << "Failed to allocate program object";
+        return 0;
+    }
+
+    // Compile the shaders and bind them to this program
+    GLuint vertexShader = loadShader(GL_VERTEX_SHADER, vtxSrc, name);
+    if (vertexShader == 0) {
+        LOG(ERROR) << "Failed to load vertex shader";
+        glDeleteProgram(program);
+        return 0;
+    }
+    GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pxlSrc, name);
+    if (pixelShader == 0) {
+        LOG(ERROR) << "Failed to load pixel shader";
+        glDeleteProgram(program);
+        glDeleteShader(vertexShader);
+        return 0;
+    }
+    glAttachShader(program, vertexShader);
+    glAttachShader(program, pixelShader);
+
+    // Link the program
+    glLinkProgram(program);
+    GLint linked = 0;
+    glGetProgramiv(program, GL_LINK_STATUS, &linked);
+    if (!linked) {
+        LOG(ERROR) << "Error linking program.";
+        GLint size = 0;
+        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &size);
+        if (size > 0) {
+            // Get and report the error message
+            std::unique_ptr<char> infoLog(new char[size]);
+            glGetProgramInfoLog(program, size, NULL, infoLog.get());
+            LOG(ERROR) << "  msg:  "
+                       << infoLog.get();
+        }
+
+        glDeleteProgram(program);
+        glDeleteShader(vertexShader);
+        glDeleteShader(pixelShader);
+        return 0;
+    }
+
+    return program;
+}
+
diff --git a/surround_view/app/shader.h b/surround_view/app/shader.h
new file mode 100644
index 0000000..63d5795
--- /dev/null
+++ b/surround_view/app/shader.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SHADER_H
+#define SHADER_H
+
+#include <GLES2/gl2.h>
+
+// Create a program object given vertex and pixels shader source
+GLuint buildShaderProgram(const char* vtxSrc, const char* pxlSrc, const char* name);
+
+#endif // SHADER_H
diff --git a/surround_view/app/shader_simpleTex.h b/surround_view/app/shader_simpleTex.h
new file mode 100644
index 0000000..4caf633
--- /dev/null
+++ b/surround_view/app/shader_simpleTex.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SHADER_SIMPLE_TEX_H
+#define SHADER_SIMPLE_TEX_H
+
+const char kVtxShaderSimpleTexture[] = ""
+        "#version 300 es                        \n"
+        "layout(location = 0) in vec4 posCoord; \n"
+        "layout(location = 1) in vec2 texCoord; \n"
+        "uniform mat4 cameraMat;                \n"
+        "out vec2 TexCoord;                     \n"
+        "void main()                            \n"
+        "{                                      \n"
+        "   gl_Position = cameraMat * posCoord; \n"
+        "   TexCoord = texCoord;                \n"
+        "}                                      \n";
+
+const char kPixShaderSimpleTexture[] =
+        "#version 300 es                                  \n"
+        "precision mediump float;                         \n"
+        "uniform sampler2D texSampler;                    \n"
+        "in vec2 TexCoord;                                \n"
+        "out vec4 color;                                  \n"
+        "void main()                                      \n"
+        "{                                                \n"
+        "    vec4 texel = texture(texSampler, TexCoord);  \n"
+        "    color = texel;                               \n"
+        "}                                                \n";
+
+#endif // SHADER_SIMPLE_TEX_H
diff --git a/surround_view/app/sv_app.cpp b/surround_view/app/sv_app.cpp
new file mode 100644
index 0000000..2fe0c86
--- /dev/null
+++ b/surround_view/app/sv_app.cpp
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
+#include <hidl/HidlTransportSupport.h>
+#include <stdio.h>
+#include <utils/StrongPointer.h>
+#include <utils/Log.h>
+#include <thread>
+
+#include "SurroundViewServiceCallback.h"
+
+// libhidl:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+using android::sp;
+using android::hardware::Return;
+using android::hardware::automotive::evs::V1_0::EvsResult;
+
+using BufferDesc_1_0  = android::hardware::automotive::evs::V1_0::BufferDesc;
+using DisplayState = android::hardware::automotive::evs::V1_0::DisplayState;
+
+using namespace android::hardware::automotive::sv::V1_0;
+using namespace android::hardware::automotive::evs::V1_1;
+
+const int kLowResolutionWidth = 120;
+const int kLowResolutionHeight = 90;
+
+enum DemoMode {
+    UNKNOWN,
+    DEMO_2D,
+    DEMO_3D,
+};
+
+bool run2dSurroundView(sp<ISurroundViewService> pSurroundViewService,
+                       sp<IEvsDisplay> pDisplay) {
+    LOG(INFO) << "Run 2d Surround View demo";
+
+    // Call HIDL API "start2dSession"
+    sp<ISurroundView2dSession> surroundView2dSession;
+
+    SvResult svResult;
+    pSurroundViewService->start2dSession(
+        [&surroundView2dSession, &svResult](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        surroundView2dSession = session;
+        svResult = result;
+    });
+
+    if (surroundView2dSession == nullptr || svResult != SvResult::OK) {
+        LOG(ERROR) << "Failed to start2dSession";
+        return false;
+    } else {
+        LOG(INFO) << "start2dSession succeeded";
+    }
+
+    sp<SurroundViewServiceCallback> sv2dCallback
+        = new SurroundViewServiceCallback(pDisplay, surroundView2dSession);
+
+    // Start 2d stream with callback
+    if (surroundView2dSession->startStream(sv2dCallback) != SvResult::OK) {
+        LOG(ERROR) << "Failed to start 2d stream";
+        return false;
+    }
+
+    // Let the SV algorithm run for 10 seconds for HIGH_QUALITY
+    std::this_thread::sleep_for(std::chrono::seconds(10));
+
+    // Switch to low quality and lower resolution
+    Sv2dConfig config;
+    config.width = kLowResolutionWidth;
+    config.blending = SvQuality::LOW;
+    if (surroundView2dSession->set2dConfig(config) != SvResult::OK) {
+        LOG(ERROR) << "Failed to set2dConfig";
+        return false;
+    }
+
+    // Let the SV algorithm run for 10 seconds for LOW_QUALITY
+    std::this_thread::sleep_for(std::chrono::seconds(10));
+
+    // TODO(b/150412555): wait for the last frame
+    // Stop the 2d stream and session
+    surroundView2dSession->stopStream();
+
+    pSurroundViewService->stop2dSession(surroundView2dSession);
+    surroundView2dSession = nullptr;
+
+    LOG(INFO) << "SV 2D session finished.";
+
+    return true;
+};
+
+bool run3dSurroundView(sp<ISurroundViewService> pSurroundViewService,
+                       sp<IEvsDisplay> pDisplay) {
+    LOG(INFO) << "Run 3d Surround View demo";
+
+    // Call HIDL API "start3dSession"
+    sp<ISurroundView3dSession> surroundView3dSession;
+
+    SvResult svResult;
+    pSurroundViewService->start3dSession(
+        [&surroundView3dSession, &svResult](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        surroundView3dSession = session;
+        svResult = result;
+    });
+
+    if (surroundView3dSession == nullptr || svResult != SvResult::OK) {
+        LOG(ERROR) << "Failed to start3dSession";
+        return false;
+    } else {
+        LOG(INFO) << "start3dSession succeeded";
+    }
+
+    // TODO(b/150412555): now we have the dummy view here since the views are
+    // set in service. This should be fixed.
+    std::vector<View3d> singleView(1);
+    surroundView3dSession->setViews(singleView);
+
+    if (surroundView3dSession->setViews(singleView) != SvResult::OK) {
+        LOG(ERROR) << "Failed to setViews";
+        return false;
+    }
+
+    sp<SurroundViewServiceCallback> sv3dCallback
+        = new SurroundViewServiceCallback(pDisplay, surroundView3dSession);
+
+    // Start 3d stream with callback
+    if (surroundView3dSession->startStream(sv3dCallback) != SvResult::OK) {
+        LOG(ERROR) << "Failed to start 3d stream";
+        return false;
+    }
+
+    // Let the SV algorithm run for 10 seconds for HIGH_QUALITY
+    std::this_thread::sleep_for(std::chrono::seconds(10));
+
+    // Switch to low quality and lower resolution
+    Sv3dConfig config;
+    config.width = kLowResolutionWidth;
+    config.height = kLowResolutionHeight;
+    config.carDetails = SvQuality::LOW;
+    if (surroundView3dSession->set3dConfig(config) != SvResult::OK) {
+        LOG(ERROR) << "Failed to set3dConfig";
+        return false;
+    }
+
+    // Let the SV algorithm run for 10 seconds for LOW_QUALITY
+    std::this_thread::sleep_for(std::chrono::seconds(10));
+
+    // TODO(b/150412555): wait for the last frame
+    // Stop the 3d stream and session
+    surroundView3dSession->stopStream();
+
+    pSurroundViewService->stop3dSession(surroundView3dSession);
+    surroundView3dSession = nullptr;
+
+    LOG(DEBUG) << "SV 3D session finished.";
+
+    return true;
+};
+
+// Main entry point
+int main(int argc, char** argv) {
+    // Start up
+    LOG(INFO) << "SV app starting";
+
+    DemoMode mode = UNKNOWN;
+    for (int i=1; i< argc; i++) {
+        if (strcmp(argv[i], "--use2d") == 0) {
+            mode = DEMO_2D;
+        } else if (strcmp(argv[i], "--use3d") == 0) {
+            mode = DEMO_3D;
+        } else {
+            LOG(WARNING) << "Ignoring unrecognized command line arg: "
+                         << argv[i];
+        }
+    }
+
+    if (mode == UNKNOWN) {
+        LOG(ERROR) << "No demo mode is specified. Exiting";
+        return EXIT_FAILURE;
+    }
+
+    // Set thread pool size to one to avoid concurrent events from the HAL.
+    // This pool will handle the SurroundViewStream callbacks.
+    configureRpcThreadpool(1, false /* callerWillJoin */);
+
+    // Try to connect to EVS service
+    LOG(INFO) << "Acquiring EVS Enumerator";
+    sp<IEvsEnumerator> evs = IEvsEnumerator::getService();
+    if (evs == nullptr) {
+        LOG(ERROR) << "getService(default) returned NULL.  Exiting.";
+        return EXIT_FAILURE;
+    }
+
+    // Try to connect to SV service
+    LOG(INFO) << "Acquiring SV Service";
+    android::sp<ISurroundViewService> surroundViewService
+        = ISurroundViewService::getService("default");
+
+    if (surroundViewService == nullptr) {
+        LOG(ERROR) << "getService(default) returned NULL.";
+        return EXIT_FAILURE;
+    } else {
+        LOG(INFO) << "Get ISurroundViewService default";
+    }
+
+    // Connect to evs display
+    int displayId;
+    evs->getDisplayIdList([&displayId](auto idList) {
+        displayId = idList[0];
+    });
+
+    LOG(INFO) << "Acquiring EVS Display with ID: "
+              << displayId;
+    sp<IEvsDisplay> display = evs->openDisplay_1_1(displayId);
+    if (display == nullptr) {
+        LOG(ERROR) << "EVS Display unavailable.  Exiting.";
+        return EXIT_FAILURE;
+    }
+
+    if (mode == DEMO_2D) {
+        if (!run2dSurroundView(surroundViewService, display)) {
+            LOG(ERROR) << "Something went wrong in 2d surround view demo. "
+                       << "Exiting.";
+            return EXIT_FAILURE;
+        }
+    } else if (mode == DEMO_3D) {
+        if (!run3dSurroundView(surroundViewService, display)) {
+            LOG(ERROR) << "Something went wrong in 3d surround view demo. "
+                       << "Exiting.";
+            return EXIT_FAILURE;
+        }
+    }
+
+    evs->closeDisplay(display);
+
+    LOG(DEBUG) << "SV sample app finished running successfully";
+    return EXIT_SUCCESS;
+}
diff --git a/surround_view/app/sv_app.rc b/surround_view/app/sv_app.rc
new file mode 100644
index 0000000..74ad768
--- /dev/null
+++ b/surround_view/app/sv_app.rc
@@ -0,0 +1,6 @@
+service sv_app /system/bin/sv_app
+    class hal
+    priority -20
+    user automotive_evs
+    group automotive_evs
+    disabled # will not automatically start with its class; must be explicitly started.
diff --git a/surround_view/sepolicy/file_contexts b/surround_view/sepolicy/file_contexts
new file mode 100644
index 0000000..34d2677
--- /dev/null
+++ b/surround_view/sepolicy/file_contexts
@@ -0,0 +1,8 @@
+
+###################################
+# Binaries associated with the Surround View
+#
+/system/bin/sv_app                                              u:object_r:sv_app_exec:s0
+/vendor/bin/android\.automotive\.sv\.service@1\.[0-9]+-impl     u:object_r:sv_service_impl_exec:s0
+
+###################################
diff --git a/surround_view/sepolicy/sv_app.te b/surround_view/sepolicy/sv_app.te
new file mode 100644
index 0000000..b1aca2d
--- /dev/null
+++ b/surround_view/sepolicy/sv_app.te
@@ -0,0 +1,9 @@
+# surround view sample app
+type sv_app, domain, coredomain;
+
+# allow init to launch processes in this context
+type sv_app_exec, exec_type, file_type, system_file_type;
+init_daemon_domain(sv_app)
+
+# Allow use of binder
+binder_use(sv_app);
diff --git a/surround_view/sepolicy/sv_service_impl.te b/surround_view/sepolicy/sv_service_impl.te
new file mode 100644
index 0000000..2bff1f9
--- /dev/null
+++ b/surround_view/sepolicy/sv_service_impl.te
@@ -0,0 +1,7 @@
+# surround view default service implementation
+type sv_service_impl, domain;
+
+# allow init to launch processes in this context
+type sv_service_impl_exec, exec_type, file_type, vendor_file_type;
+init_daemon_domain(sv_service_impl)
+binder_use(sv_service_impl)
diff --git a/surround_view/service-impl/Android.bp b/surround_view/service-impl/Android.bp
new file mode 100644
index 0000000..7580795
--- /dev/null
+++ b/surround_view/service-impl/Android.bp
@@ -0,0 +1,393 @@
+//
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library {
+    name : "libobj_reader",
+    vendor : true,
+    srcs: [
+        "MtlReader.cpp",
+        "ObjReader.cpp",
+    ],
+    shared_libs : [
+        "libbase",
+    ]
+}
+
+cc_test{
+    name : "obj_reader_tests",
+    test_suites : ["device-tests"],
+    vendor : true,
+    srcs : ["ObjReaderTests.cpp"],
+    shared_libs : [
+        "libobj_reader",
+        "libcutils",
+        "libbase",
+        "libutils",
+    ],
+    required: [
+        "sample_car.obj",
+        "sample_car_material.mtl",
+    ],
+}
+
+// Library for IO Module.
+cc_library {
+    name : "libio_module",
+    vendor : true,
+    srcs: [
+        "ConfigReader.cpp",
+        "CarModelConfigReader.cpp",
+        "ConfigReaderUtil.cpp",
+        "IOModule.cpp",
+    ],
+    shared_libs : [
+        "libbase",
+        "libobj_reader",
+        "libtinyxml2",
+    ]
+}
+
+cc_test{
+    name : "io_module_tests",
+    test_suites : ["device-tests"],
+    vendor : true,
+    srcs : [
+        "CarModelConfigReaderTests.cpp",
+        "ConfigReaderTests.cpp",
+    ],
+    shared_libs : [
+        "libbase",
+        "libcutils",
+        "libio_module",
+        "libobj_reader",
+        "libtinyxml2",
+        "libutils",
+    ],
+    required: [
+        "sv_sample_car_model_config.xml",
+        "sv_sample_config.xml",
+    ],
+}
+
+cc_library{
+    name : "libanimation_module",
+    vendor : true,
+    srcs : [
+        "AnimationModule.cpp",
+    ],
+    shared_libs : [
+        "android.hardware.automotive.vehicle@2.0",
+        "libbase",
+        "libhidlbase",
+        "libutils",
+    ],
+}
+
+cc_test{
+    name : "animation_module_tests",
+    test_suites : ["device-tests"],
+    vendor : true,
+    srcs : ["AnimationModuleTests.cpp"],
+    shared_libs : [
+        "android.hardware.automotive.vehicle@2.0",
+        "libanimation_module",
+        "libcutils",
+        "libbase",
+        "libhidlbase",
+        "libhardware",
+        "libutils",
+    ],
+}
+
+cc_library{
+    name : "libvhal_handler",
+    vendor : true,
+    srcs : [
+        "VhalHandler.cpp",
+    ],
+    shared_libs : [
+        "android.hardware.automotive.vehicle@2.0",
+        "android.hidl.memory@1.0",
+        "libcutils",
+        "libbase",
+        "libbinder",
+        "libhidlbase",
+        "libhardware",
+        "libhidlmemory",
+        "libui",
+        "libutils",
+    ],
+}
+
+cc_test{
+    name : "vhal_handler_tests",
+    test_suites : ["device-tests"],
+    vendor : true,
+    srcs : ["VhalHandlerTests.cpp"],
+    shared_libs : [
+        "android.hardware.automotive.vehicle@2.0",
+        "libvhal_handler",
+        "libcutils",
+        "libbase",
+        "libbinder",
+        "libhidlbase",
+        "libhardware",
+        "libhidlmemory",
+        "libui",
+        "libutils",
+    ],
+}
+
+cc_library{
+    name : "libsvsession",
+    vendor : true,
+    srcs : [
+        "CameraUtils.cpp",
+        "CoreLibSetupHelper.cpp",
+        "SurroundView2dSession.cpp",
+        "SurroundView3dSession.cpp",
+    ],
+    shared_libs : [
+        "android.hardware.automotive.evs@1.0",
+        "android.hardware.automotive.evs@1.1",
+        "android.hardware.automotive.sv@1.0",
+        "android.hardware.automotive.vehicle@2.0",
+        "android.hidl.memory@1.0",
+        "libanimation_module",
+        "libbase",
+        "libbinder",
+        "libcamera_metadata",
+        "libcore_lib_shared",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "libhidlmemory",
+        "libio_module",
+        "libui",
+        "libutils",
+        "libvhal_handler",
+    ],
+    required : [
+        "cam0.png",
+        "cam1.png",
+        "cam2.png",
+        "cam3.png",
+        "sample_car.obj",
+        "sample_car_material.mtl",
+        "sv_sample_config.xml",
+        "sv_sample_car_model_config.xml",
+    ],
+    // Disable builds except for arm64 and emulator devices
+    enabled : false,
+    arch : {
+        arm64 : {
+            enabled : true,
+        },
+        x86 : {
+            enabled : true,
+        },
+        x86_64 : {
+            enabled : true,
+        },
+    },
+}
+
+cc_test{
+    name : "sv_session_tests",
+    test_suites : ["device-tests"],
+    vendor : true,
+    srcs : [
+        "SurroundViewSessionTests.cpp",
+        "mock-evs/MockEvsCamera.cpp",
+        "mock-evs/MockEvsEnumerator.cpp",
+        "mock-evs/MockSurroundViewCallback.cpp",
+    ],
+    include_dirs: [
+        "packages/services/Car/evs/sampleDriver",
+    ],
+    shared_libs : [
+        "android.hardware.automotive.evs@1.0",
+        "android.hardware.automotive.evs@1.1",
+        "android.hardware.automotive.sv@1.0",
+        "android.hardware.automotive.vehicle@2.0",
+        "android.hidl.memory@1.0",
+        "libanimation_module",
+        "libbase",
+        "libbinder",
+        "libcamera_metadata",
+        "libcore_lib_shared",
+        "libcutils",
+        "libevsconfigmanager",
+        "libhardware",
+        "libhidlbase",
+        "libhidlmemory",
+        "libio_module",
+        "libsvsession",
+        "libtinyxml2",
+        "libui",
+        "libutils",
+        "libvhal_handler",
+    ],
+    // Disable builds except for arm64 and emulator devices
+    enabled : false,
+    arch : {
+        arm64 : {
+            enabled : true,
+        },
+        x86 : {
+            enabled : true,
+        },
+        x86_64 : {
+            enabled : true,
+        },
+    },
+}
+
+cc_binary{
+    name : "android.automotive.sv.service@1.0-impl",
+    vendor : true,
+    srcs : [
+        "SurroundViewService.cpp",
+        "service.cpp",
+    ],
+    init_rc : ["android.automotive.sv.service@1.0-impl.rc"],
+    shared_libs : [
+        "android.hardware.automotive.evs@1.1",
+        "android.hardware.automotive.sv@1.0",
+        "android.hardware.automotive.vehicle@2.0",
+        "android.hidl.memory@1.0",
+        "libanimation_module",
+        "libbase",
+        "libbinder",
+        "libcamera_metadata",
+        "libcore_lib_shared",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "libhidlmemory",
+        "libio_module",
+        "libsvsession",
+        "libui",
+        "libutils",
+        "libvhal_handler",
+    ],
+    cflags: ["-DLOG_TAG=\"SurroundViewService\""],
+    required : [
+        "cam0.png",
+        "cam1.png",
+        "cam2.png",
+        "cam3.png",
+        "sample_car.obj",
+        "sample_car_material.mtl",
+        "sv_sample_config.xml",
+        "sv_sample_car_model_config.xml",
+    ],
+    // Disable builds except for arm64 and emulator devices
+    enabled : false,
+    arch : {
+        arm64 : {
+            enabled : true,
+        },
+        x86 : {
+            enabled : true,
+        },
+        x86_64 : {
+            enabled : true,
+        },
+    },
+    vintf_fragments : [
+        "manifest_android.hardware.automotive.sv@1.0.xml",
+    ],
+}
+
+cc_prebuilt_library_shared{
+    name : "libcore_lib_shared",
+    proprietary : true,
+    arch : {
+        arm64 : {srcs : ["lib/arm64/libcore_lib_shared.so"]},
+        x86 : {srcs : ["lib/x86/libcore_lib_shared.so"]},
+        x86_64 : {srcs : ["lib/x86-64/libcore_lib_shared.so"]},
+    },
+    shared_libs : [
+        "libutils",
+        "libcutils",
+        "libbase",
+        "libEGL",
+        "libGLESv2",
+        "libGLESv3",
+        "libc",
+        "libm",
+        "libdl",
+        "libz",
+        "liblog",
+    ],
+}
+
+prebuilt_etc{
+    name : "cam0.png",
+    soc_specific : true,
+    src : "test_data/0.png",
+    sub_dir : "automotive/sv",
+}
+
+prebuilt_etc{
+    name : "cam1.png",
+    soc_specific : true,
+    src : "test_data/1.png",
+    sub_dir : "automotive/sv",
+}
+
+prebuilt_etc{
+    name : "cam2.png",
+    soc_specific : true,
+    src : "test_data/2.png",
+    sub_dir : "automotive/sv",
+}
+
+prebuilt_etc {
+    name :"cam3.png",
+    soc_specific : true,
+    src : "test_data/3.png",
+    sub_dir : "automotive/sv",
+}
+
+prebuilt_etc {
+    name : "sample_car.obj",
+    soc_specific : true,
+    src : "test_data/sample_car.obj",
+    sub_dir : "automotive/sv",
+}
+
+prebuilt_etc {
+    name : "sample_car_material.mtl",
+    soc_specific : true,
+    src: "test_data/sample_car_material.mtl",
+    sub_dir: "automotive/sv",
+}
+
+prebuilt_etc {
+    name : "sv_sample_config.xml",
+    soc_specific : true,
+    src : "test_data/sv_sample_config.xml",
+    sub_dir : "automotive/sv",
+}
+
+prebuilt_etc {
+    name:"sv_sample_car_model_config.xml",
+    soc_specific : true,
+    src : "test_data/sv_sample_car_model_config.xml",
+    sub_dir : "automotive/sv",
+}
diff --git a/surround_view/service-impl/AnimationModule.cpp b/surround_view/service-impl/AnimationModule.cpp
new file mode 100644
index 0000000..2eecdb0
--- /dev/null
+++ b/surround_view/service-impl/AnimationModule.cpp
@@ -0,0 +1,518 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AnimationModule.h"
+#include "MathHelp.h"
+
+#include <android-base/logging.h>
+#include <algorithm>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+namespace {
+std::array<float, 3> operator*(std::array<float, 3> lvector, float scalar) {
+    return std::array<float, 3>{
+            lvector[0] * scalar,
+            lvector[1] * scalar,
+            lvector[2] * scalar,
+    };
+}
+
+inline float getRationalNumber(const Range& mappedRange, float percentage) {
+    return mappedRange.start + (mappedRange.end - mappedRange.start) * percentage;
+}
+
+inline float getRationalNumber(const Range& mappedRange, const Range& rawRange, float rawValue) {
+    if (0 == rawRange.end - rawRange.start) {
+        return mappedRange.start;
+    }
+    const float percentage = (rawValue - rawRange.start) / (rawRange.end - rawRange.start);
+    return mappedRange.start + (mappedRange.end - mappedRange.start) * percentage > 1
+            ? 1
+            : percentage < 0 ? 0 : percentage;
+}
+
+inline uint64_t getCombinedId(const VehiclePropValue& vhalValueFloat) {
+    return static_cast<uint64_t>(vhalValueFloat.prop) << 32 | vhalValueFloat.areaId;
+}
+
+float getVhalValueFloat(const VehiclePropValue& vhalValue) {
+    int32_t type = vhalValue.prop & 0x00FF0000;
+    switch (type) {
+        case (int32_t)VehiclePropertyType::BOOLEAN:
+            return 0 == vhalValue.value.int32Values[0] ? 0.0f : 1.0f;
+        case (int32_t)VehiclePropertyType::FLOAT:
+            return vhalValue.value.floatValues[0];
+        case (int32_t)VehiclePropertyType::INT32:
+            return (float)vhalValue.value.int32Values[0];
+        case (int32_t)VehiclePropertyType::INT64:
+            return (float)vhalValue.value.int64Values[0];
+        default:
+            return 0;
+    }
+}
+}  // namespace
+
+AnimationModule::AnimationModule(const std::map<std::string, CarPart>& partsMap,
+                                 const std::map<std::string, CarTexture>& texturesMap,
+                                 const std::vector<AnimationInfo>& animations) :
+      mIsCalled(false), mPartsMap(partsMap), mTexturesMap(texturesMap), mAnimations(animations) {
+    mapVhalToParts();
+    initCarPartStatus();
+}
+
+void AnimationModule::mapVhalToParts() {
+    for (const auto& animationInfo : mAnimations) {
+        auto partId = animationInfo.partId;
+        for (const auto& gammaOp : animationInfo.gammaOpsMap) {
+            if (mVhalToPartsMap.find(gammaOp.first) != mVhalToPartsMap.end()) {
+                mVhalToPartsMap.at(gammaOp.first).insert(partId);
+            } else {
+                mVhalToPartsMap.emplace(
+                        std::make_pair(gammaOp.first, std::set<std::string>{partId}));
+            }
+        }
+        for (const auto& textureOp : animationInfo.textureOpsMap) {
+            if (mVhalToPartsMap.find(textureOp.first) != mVhalToPartsMap.end()) {
+                mVhalToPartsMap.at(textureOp.first).insert(partId);
+            } else {
+                mVhalToPartsMap.emplace(
+                        std::make_pair(textureOp.first, std::set<std::string>{partId}));
+            }
+        }
+        for (const auto& rotationOp : animationInfo.rotationOpsMap) {
+            if (mVhalToPartsMap.find(rotationOp.first) != mVhalToPartsMap.end()) {
+                mVhalToPartsMap.at(rotationOp.first).insert(partId);
+            } else {
+                mVhalToPartsMap.emplace(
+                        std::make_pair(rotationOp.first, std::set<std::string>{partId}));
+            }
+        }
+        for (const auto& translationOp : animationInfo.translationOpsMap) {
+            if (mVhalToPartsMap.find(translationOp.first) != mVhalToPartsMap.end()) {
+                mVhalToPartsMap.at(translationOp.first).insert(partId);
+            } else {
+                mVhalToPartsMap.emplace(
+                        std::make_pair(translationOp.first, std::set<std::string>{partId}));
+            }
+        }
+        mPartsToAnimationMap.emplace(std::make_pair(partId, animationInfo));
+    }
+}
+
+void AnimationModule::initCarPartStatus() {
+    for (const auto& part : mPartsMap) {
+        // Get child parts list from mPartsToAnimationMap.
+        std::vector<std::string> childIds;
+        if (mPartsToAnimationMap.find(part.first) != mPartsToAnimationMap.end()) {
+            childIds = mPartsToAnimationMap.at(part.first).childIds;
+        }
+
+        mCarPartsStatusMap.emplace(std::make_pair(part.first,
+                                                  CarPartStatus{
+                                                          .partId = part.first,
+                                                          .childIds = childIds,
+                                                          .parentModel = gMat4Identity,
+                                                          .localModel = gMat4Identity,
+                                                          .currentModel = gMat4Identity,
+                                                          .gamma = 1,
+                                                  }));
+    }
+
+    for (const auto& eachVhalToParts : mVhalToPartsMap) {
+        for (const auto& part : eachVhalToParts.second) {
+            if (mCarPartsStatusMap.at(part).vhalProgressMap.find(eachVhalToParts.first) !=
+                mCarPartsStatusMap.at(part).vhalProgressMap.end()) {
+                mCarPartsStatusMap.at(part).vhalProgressMap.at(eachVhalToParts.first) = 0.0f;
+            } else {
+                mCarPartsStatusMap.at(part).vhalProgressMap.emplace(
+                        std::make_pair(eachVhalToParts.first, 0.0f));
+            }
+            if (mCarPartsStatusMap.at(part).vhalOffMap.find(eachVhalToParts.first) !=
+                mCarPartsStatusMap.at(part).vhalOffMap.end()) {
+                mCarPartsStatusMap.at(part).vhalOffMap.at(eachVhalToParts.first) = true;
+            } else {
+                mCarPartsStatusMap.at(part).vhalOffMap.emplace(
+                        std::make_pair(eachVhalToParts.first, true));
+            }
+        }
+    }
+}
+
+// This implementation assumes the tree level is small. If tree level is large,
+// we may need to traverse the tree once and process each node(part) during
+// the reaversal.
+void AnimationModule::updateChildrenParts(const std::string& partId, const Mat4x4& parentModel) {
+    for (auto& childPart : mCarPartsStatusMap.at(partId).childIds) {
+        mCarPartsStatusMap.at(childPart).parentModel = parentModel;
+        mCarPartsStatusMap.at(childPart).currentModel =
+                appendMat(mCarPartsStatusMap.at(childPart).localModel,
+                          mCarPartsStatusMap.at(childPart).parentModel);
+        if (mUpdatedPartsMap.find(childPart) == mUpdatedPartsMap.end()) {
+            AnimationParam animationParam(childPart);
+            animationParam.SetModelMatrix(mCarPartsStatusMap.at(childPart).currentModel);
+            mUpdatedPartsMap.emplace(std::make_pair(childPart, animationParam));
+        } else {  // existing part in the map
+            mUpdatedPartsMap.at(childPart).SetModelMatrix(
+                    mCarPartsStatusMap.at(childPart).currentModel);
+        }
+        updateChildrenParts(childPart, mCarPartsStatusMap.at(childPart).currentModel);
+    }
+}
+
+void AnimationModule::performGammaOp(const std::string& partId, uint64_t vhalProperty,
+                                     const GammaOp& gammaOp) {
+    CarPartStatus& currentCarPartStatus = mCarPartsStatusMap.at(partId);
+    float& currentProgress = currentCarPartStatus.vhalProgressMap.at(vhalProperty);
+    if (currentCarPartStatus.vhalOffMap.at(vhalProperty)) {  // process off signal
+        if (currentProgress > 0) {                           // part not rest
+            if (0 == gammaOp.animationTime) {
+                currentCarPartStatus.gamma = gammaOp.gammaRange.start;
+                currentProgress = 0.0f;
+            } else {
+                const float progressDelta =
+                        (mCurrentCallTime - mLastCallTime) / gammaOp.animationTime;
+                if (progressDelta > currentProgress) {
+                    currentCarPartStatus.gamma = gammaOp.gammaRange.start;
+                    currentProgress = 0.0f;
+                } else {
+                    currentCarPartStatus.gamma =
+                            getRationalNumber(gammaOp.gammaRange, currentProgress - progressDelta);
+                    currentProgress -= progressDelta;
+                }
+            }
+        } else {
+            return;
+        }
+    } else {                               // regular signal process
+        if (0 == gammaOp.animationTime) {  // continuous value
+            currentCarPartStatus.gamma =
+                    getRationalNumber(gammaOp.gammaRange, gammaOp.vhalRange,
+                                      mVhalStatusMap.at(vhalProperty).vhalValueFloat);
+            currentProgress = mVhalStatusMap.at(vhalProperty).vhalValueFloat;
+        } else {  // non-continuous value
+            const float progressDelta = (mCurrentCallTime - mLastCallTime) / gammaOp.animationTime;
+            if (gammaOp.type == ADJUST_GAMMA_ONCE) {
+                if (progressDelta + currentCarPartStatus.vhalProgressMap.at(vhalProperty) > 1) {
+                    currentCarPartStatus.gamma = gammaOp.gammaRange.end;
+                    currentProgress = 1.0f;
+                } else {
+                    currentCarPartStatus.gamma =
+                            getRationalNumber(gammaOp.gammaRange, currentProgress + progressDelta);
+                    currentProgress += progressDelta;
+                }
+            } else if (gammaOp.type == ADJUST_GAMMA_REPEAT) {
+                if (progressDelta + currentCarPartStatus.vhalProgressMap.at(vhalProperty) > 1) {
+                    if (progressDelta + currentCarPartStatus.vhalProgressMap.at(vhalProperty) - 1 >
+                        1) {
+                        currentCarPartStatus.gamma =
+                                currentCarPartStatus.vhalProgressMap.at(vhalProperty) > 0.5
+                                ? gammaOp.gammaRange.start
+                                : gammaOp.gammaRange.end;
+                        currentProgress =
+                                currentCarPartStatus.vhalProgressMap.at(vhalProperty) > 0.5 ? 0.0f
+                                                                                            : 1.0f;
+                    } else {
+                        currentCarPartStatus.gamma =
+                                getRationalNumber(gammaOp.gammaRange,
+                                                  progressDelta +
+                                                          currentCarPartStatus.vhalProgressMap.at(
+                                                                  vhalProperty) -
+                                                          1);
+                        currentProgress += progressDelta - 1;
+                    }
+                } else {
+                    currentCarPartStatus.gamma =
+                            getRationalNumber(gammaOp.gammaRange, currentProgress + progressDelta);
+                    currentProgress += progressDelta;
+                }
+            } else {
+                LOG(ERROR) << "Error type of gamma op: " << gammaOp.type;
+            }
+        }
+    }
+
+    if (mUpdatedPartsMap.find(partId) == mUpdatedPartsMap.end()) {
+        AnimationParam animationParam(partId);
+        animationParam.SetGamma(currentCarPartStatus.gamma);
+        mUpdatedPartsMap.emplace(std::make_pair(partId, animationParam));
+    } else {  // existing part in the map
+        mUpdatedPartsMap.at(partId).SetGamma(currentCarPartStatus.gamma);
+    }
+}
+
+void AnimationModule::performTranslationOp(const std::string& partId, uint64_t vhalProperty,
+                                           const TranslationOp& translationOp) {
+    CarPartStatus& currentCarPartStatus = mCarPartsStatusMap.at(partId);
+    float& currentProgress = currentCarPartStatus.vhalProgressMap.at(vhalProperty);
+    if (currentCarPartStatus.vhalOffMap.at(vhalProperty)) {  // process off signal
+        if (currentProgress > 0) {
+            // part not rest
+            if (0 == translationOp.animationTime) {
+                currentCarPartStatus.localModel = gMat4Identity;
+                currentCarPartStatus.currentModel = currentCarPartStatus.parentModel;
+                currentProgress = 0.0f;
+            } else {
+                const float progressDelta =
+                        (mCurrentCallTime - mLastCallTime) / translationOp.animationTime;
+                float translationUnit =
+                        getRationalNumber(translationOp.translationRange,
+                                          std::max(currentProgress - progressDelta, 0.0f));
+                currentCarPartStatus.localModel =
+                        translationMatrixToMat4x4(translationOp.direction * translationUnit);
+                currentCarPartStatus.currentModel = appendMatrix(currentCarPartStatus.localModel,
+                                                                 currentCarPartStatus.parentModel);
+                currentProgress = std::max(currentProgress - progressDelta, 0.0f);
+            }
+        } else {
+            return;
+        }
+    } else {  // regular signal process
+        if (translationOp.type == TRANSLATION) {
+            if (0 == translationOp.animationTime) {
+                float translationUnit =
+                        getRationalNumber(translationOp.translationRange, translationOp.vhalRange,
+                                          mVhalStatusMap.at(vhalProperty).vhalValueFloat);
+                currentCarPartStatus.localModel =
+                        translationMatrixToMat4x4(translationOp.direction * translationUnit);
+                currentCarPartStatus.currentModel = appendMatrix(currentCarPartStatus.localModel,
+                                                                 currentCarPartStatus.parentModel);
+                currentProgress = mVhalStatusMap.at(vhalProperty).vhalValueFloat;
+            } else {
+                float progressDelta =
+                        (mCurrentCallTime - mLastCallTime) / translationOp.animationTime;
+                if (progressDelta + currentCarPartStatus.vhalProgressMap.at(vhalProperty) > 1) {
+                    float translationUnit = translationOp.translationRange.end;
+
+                    currentCarPartStatus.localModel =
+                            translationMatrixToMat4x4(translationOp.direction * translationUnit);
+                    currentCarPartStatus.currentModel =
+                            appendMatrix(currentCarPartStatus.localModel,
+                                         currentCarPartStatus.parentModel);
+                    currentProgress = 1.0f;
+                } else {
+                    float translationUnit = getRationalNumber(translationOp.translationRange,
+                                                              progressDelta + currentProgress);
+                    currentCarPartStatus.localModel =
+                            translationMatrixToMat4x4(translationOp.direction * translationUnit);
+                    currentCarPartStatus.currentModel =
+                            appendMatrix(currentCarPartStatus.localModel,
+                                         currentCarPartStatus.parentModel);
+                    currentProgress += progressDelta;
+                }
+            }
+        } else {
+            LOG(ERROR) << "Error type of translation op: " << translationOp.type;
+        }
+    }
+    if (mUpdatedPartsMap.find(partId) == mUpdatedPartsMap.end()) {
+        AnimationParam animationParam(partId);
+        animationParam.SetModelMatrix(currentCarPartStatus.currentModel);
+        mUpdatedPartsMap.emplace(std::make_pair(partId, animationParam));
+    } else {  // existing part in the map
+        mUpdatedPartsMap.at(partId).SetModelMatrix(currentCarPartStatus.currentModel);
+    }
+    updateChildrenParts(partId, currentCarPartStatus.currentModel);
+}
+
+void AnimationModule::performRotationOp(const std::string& partId, uint64_t vhalProperty,
+                                        const RotationOp& rotationOp) {
+    CarPartStatus& currentCarPartStatus = mCarPartsStatusMap.at(partId);
+    float& currentProgress = currentCarPartStatus.vhalProgressMap.at(vhalProperty);
+    if (currentCarPartStatus.vhalOffMap.at(vhalProperty)) {
+        // process off signal
+        if (currentProgress > 0) {  // part not rest
+            if (0 == rotationOp.animationTime) {
+                currentCarPartStatus.localModel = gMat4Identity;
+                currentCarPartStatus.currentModel = currentCarPartStatus.parentModel;
+                currentProgress = 0.0f;
+            } else {
+                const float progressDelta =
+                        (mCurrentCallTime - mLastCallTime) / rotationOp.animationTime;
+                if (progressDelta > currentProgress) {
+                    currentCarPartStatus.localModel = gMat4Identity;
+                    currentCarPartStatus.currentModel = currentCarPartStatus.parentModel;
+                    currentProgress = 0.0f;
+                } else {
+                    float anlgeInDegree = getRationalNumber(rotationOp.rotationRange,
+                                                            currentProgress - progressDelta);
+                    currentCarPartStatus.localModel =
+                            rotationAboutPoint(anlgeInDegree, rotationOp.axis.rotationPoint,
+                                               rotationOp.axis.axisVector);
+                    currentCarPartStatus.currentModel =
+                            appendMatrix(currentCarPartStatus.localModel,
+                                         currentCarPartStatus.parentModel);
+                    currentProgress -= progressDelta;
+                }
+            }
+        } else {
+            return;
+        }
+    } else {  // regular signal process
+        if (rotationOp.type == ROTATION_ANGLE) {
+            if (0 == rotationOp.animationTime) {
+                float angleInDegree =
+                        getRationalNumber(rotationOp.rotationRange, rotationOp.vhalRange,
+                                          mVhalStatusMap.at(vhalProperty).vhalValueFloat);
+                currentCarPartStatus.localModel =
+                        rotationAboutPoint(angleInDegree, rotationOp.axis.rotationPoint,
+                                           rotationOp.axis.axisVector);
+                currentCarPartStatus.currentModel = appendMatrix(currentCarPartStatus.localModel,
+                                                                 currentCarPartStatus.parentModel);
+                currentProgress = mVhalStatusMap.at(vhalProperty).vhalValueFloat;
+            } else {
+                float progressDelta = (mCurrentCallTime - mLastCallTime) / rotationOp.animationTime;
+                if (progressDelta + currentProgress > 1) {
+                    float angleInDegree = rotationOp.rotationRange.end;
+                    currentCarPartStatus.localModel =
+                            rotationAboutPoint(angleInDegree, rotationOp.axis.rotationPoint,
+                                               rotationOp.axis.axisVector);
+                    currentCarPartStatus.currentModel =
+                            appendMatrix(currentCarPartStatus.localModel,
+                                         currentCarPartStatus.parentModel);
+                    currentProgress = 1.0f;
+                } else {
+                    float anlgeInDegree = getRationalNumber(rotationOp.rotationRange,
+                                                            currentProgress + progressDelta);
+                    currentCarPartStatus.localModel =
+                            rotationAboutPoint(anlgeInDegree, rotationOp.axis.rotationPoint,
+                                               rotationOp.axis.axisVector);
+                    currentCarPartStatus.currentModel =
+                            appendMatrix(currentCarPartStatus.localModel,
+                                         currentCarPartStatus.parentModel);
+                    currentProgress += progressDelta;
+                }
+            }
+        } else if (rotationOp.type == ROTATION_SPEED) {
+            float angleDelta = (mCurrentCallTime - mLastCallTime) *
+                    getRationalNumber(rotationOp.rotationRange, rotationOp.vhalRange,
+                                      mVhalStatusMap.at(vhalProperty)
+                                              .vhalValueFloat);  // here vhalValueFloat unit is
+                                                                 // radian/ms.
+            currentCarPartStatus.localModel =
+                    appendMat(rotationAboutPoint(angleDelta, rotationOp.axis.rotationPoint,
+                                                 rotationOp.axis.axisVector),
+                              currentCarPartStatus.localModel);
+            currentCarPartStatus.currentModel =
+                    appendMatrix(currentCarPartStatus.localModel, currentCarPartStatus.parentModel);
+            currentProgress = 1.0f;
+        } else {
+            LOG(ERROR) << "Error type of rotation op: " << rotationOp.type;
+        }
+    }
+    if (mUpdatedPartsMap.find(partId) == mUpdatedPartsMap.end()) {
+        AnimationParam animationParam(partId);
+        animationParam.SetModelMatrix(currentCarPartStatus.currentModel);
+        mUpdatedPartsMap.emplace(std::make_pair(partId, animationParam));
+    } else {  // existing part in the map
+        mUpdatedPartsMap.at(partId).SetModelMatrix(currentCarPartStatus.currentModel);
+    }
+    updateChildrenParts(partId, currentCarPartStatus.currentModel);
+}
+
+std::vector<AnimationParam> AnimationModule::getUpdatedAnimationParams(
+        const std::vector<VehiclePropValue>& vehiclePropValue) {
+    mLastCallTime = mCurrentCallTime;
+    if (!mIsCalled) {
+        mIsCalled = true;
+        mLastCallTime = (float)elapsedRealtimeNano() / 1e6;
+    }
+
+    // get current time
+    mCurrentCallTime = (float)elapsedRealtimeNano() / 1e6;
+
+    // reset mUpdatedPartsMap
+    mUpdatedPartsMap.clear();
+
+    for (const auto& vhalSignal : vehiclePropValue) {
+        // existing vhal signal
+        const uint64_t combinedId = getCombinedId(vhalSignal);
+        if (mVhalToPartsMap.find(combinedId) != mVhalToPartsMap.end()) {
+            const float valueFloat = getVhalValueFloat(vhalSignal);
+            if (mVhalStatusMap.find(combinedId) != mVhalStatusMap.end()) {
+                mVhalStatusMap.at(combinedId).vhalValueFloat = valueFloat;
+            } else {
+                mVhalStatusMap.emplace(std::make_pair(combinedId,
+                                                      VhalStatus{
+                                                              .vhalValueFloat = valueFloat,
+                                                      }));
+            }
+            bool offStatus = 0 == valueFloat;
+            for (const auto& eachPart : mVhalToPartsMap.at(combinedId)) {
+                mCarPartsStatusMap.at(eachPart).vhalOffMap.at(combinedId) = offStatus;
+            }
+        }
+    }
+
+    for (auto& vhalStatus : mVhalStatusMap) {
+        // VHAL signal not found in animation
+        uint64_t vhalProperty = vhalStatus.first;
+        if (mVhalToPartsMap.find(vhalProperty) == mVhalToPartsMap.end()) {
+            LOG(WARNING) << "VHAL " << vhalProperty << " not processed.";
+        } else {  // VHAL signal found
+            const auto& partsSet = mVhalToPartsMap.at(vhalProperty);
+            for (const auto& partId : partsSet) {
+                const auto& animationInfo = mPartsToAnimationMap.at(partId);
+                if (animationInfo.gammaOpsMap.find(vhalProperty) !=
+                    animationInfo.gammaOpsMap.end()) {
+                    LOG(INFO) << "Processing VHAL " << vhalProperty << " for gamma op.";
+                    // TODO(b/158244276): add priority check.
+                    for (const auto& gammaOp : animationInfo.gammaOpsMap.at(vhalProperty)) {
+                        performGammaOp(partId, vhalProperty, gammaOp);
+                    }
+                }
+                if (animationInfo.textureOpsMap.find(vhalProperty) !=
+                    animationInfo.textureOpsMap.end()) {
+                    LOG(INFO) << "Processing VHAL " << vhalProperty << " for texture op.";
+                    LOG(INFO) << "Texture op currently not supported. Skipped.";
+                    // TODO(b158244721): do texture op.
+                }
+                if (animationInfo.rotationOpsMap.find(vhalProperty) !=
+                    animationInfo.rotationOpsMap.end()) {
+                    LOG(INFO) << "Processing VHAL " << vhalProperty << " for rotation op.";
+                    for (const auto& rotationOp : animationInfo.rotationOpsMap.at(vhalProperty)) {
+                        performRotationOp(partId, vhalProperty, rotationOp);
+                    }
+                }
+                if (animationInfo.translationOpsMap.find(vhalProperty) !=
+                    animationInfo.translationOpsMap.end()) {
+                    LOG(INFO) << "Processing VHAL " << vhalProperty << " for translation op.";
+                    for (const auto& translationOp :
+                         animationInfo.translationOpsMap.at(vhalProperty)) {
+                        performTranslationOp(partId, vhalProperty, translationOp);
+                    }
+                }
+            }
+        }
+    }
+
+    std::vector<AnimationParam> output;
+    for (auto& updatedPart : mUpdatedPartsMap) {
+        output.push_back(updatedPart.second);
+    }
+    return output;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/AnimationModule.h b/surround_view/service-impl/AnimationModule.h
new file mode 100644
index 0000000..de8dd35
--- /dev/null
+++ b/surround_view/service-impl/AnimationModule.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SURROUND_VIEW_SERVICE_IMPL_ANIMATION_H_
+#define SURROUND_VIEW_SERVICE_IMPL_ANIMATION_H_
+
+#include "IOModuleCommon.h"
+#include "core_lib.h"
+
+#include <utils/SystemClock.h>
+#include <cstdint>
+#include <map>
+#include <set>
+#include <vector>
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+
+using namespace ::android::hardware::automotive::vehicle::V2_0;
+using namespace android_auto::surround_view;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+// Car animation class. It is constructed with textures, animations, and
+// vhal_handler. It automatically updates animation params when
+// GetUpdatedAnimationParams() is called.
+class AnimationModule {
+public:
+    // Constructor.
+    // |parts| is from I/O module. The key value is part id.
+    // |textures| is from I/O module. The key value is texture id.
+    // |animations| is from I/O module.
+    AnimationModule(const std::map<std::string, CarPart>& partsMap,
+                    const std::map<std::string, CarTexture>& texturesMap,
+                    const std::vector<AnimationInfo>& animations);
+
+    // Gets Animation parameters with input of VehiclePropValue.
+    std::vector<AnimationParam> getUpdatedAnimationParams(
+            const std::vector<VehiclePropValue>& vehiclePropValue);
+
+private:
+    // Internal car part status.
+    struct CarPartStatus {
+        // Car part id.
+        std::string partId;
+
+        // Car part children ids.
+        std::vector<std::string> childIds;
+
+        // Parent model matrix.
+        Mat4x4 parentModel;
+
+        // Local model in local coordinate.
+        Mat4x4 localModel;
+
+        // Current status model matrix in global coordinate with
+        // animations combined.
+        // current_model = local_model * parent_model;
+        Mat4x4 currentModel;
+
+        // Gamma parameters.
+        float gamma;
+
+        // Texture id.
+        std::string textureId;
+
+        // Internal vhal percentage. Each car part maintain its own copy
+        // the vhal percentage.
+        // Key value is vhal property (combined with area id).
+        std::map<uint64_t, float> vhalProgressMap;
+
+        // Vhal off map. Key value is vhal property (combined with area id).
+        // Assume off status when vhal value is 0.
+        std::map<uint64_t, bool> vhalOffMap;
+    };
+
+    // Internal Vhal status.
+    struct VhalStatus {
+        float vhalValueFloat;
+    };
+
+    // Help function to get vhal to parts map.
+    void mapVhalToParts();
+
+    // Help function to init car part status for constructor.
+    void initCarPartStatus();
+
+    // Iteratively update children parts status if partent status is changed.
+    void updateChildrenParts(const std::string& partId, const Mat4x4& parentModel);
+
+    // Perform gamma opertion for the part with given vhal property.
+    void performGammaOp(const std::string& partId, uint64_t vhalProperty, const GammaOp& gammaOp);
+
+    // Perform translation opertion for the part with given vhal property.
+    void performTranslationOp(const std::string& partId, uint64_t vhalProperty,
+                              const TranslationOp& translationOp);
+
+    // Perform texture opertion for the part with given vhal property.
+    // Not implemented yet.
+    void performTextureOp(const std::string& partId, uint64_t vhalProperty,
+                          const TextureOp& textureOp);
+
+    // Perform rotation opertion for the part with given vhal property.
+    void performRotationOp(const std::string& partId, uint64_t vhalProperty,
+                           const RotationOp& rotationOp);
+
+    // Last call time of GetUpdatedAnimationParams() in millisecond.
+    float mLastCallTime;
+
+    // Current call time of GetUpdatedAnimationParams() in millisecond.
+    float mCurrentCallTime;
+
+    // Flag indicating if GetUpdatedAnimationParams() was called before.
+    bool mIsCalled;
+
+    std::map<std::string, CarPart> mPartsMap;
+
+    std::map<std::string, CarTexture> mTexturesMap;
+
+    std::vector<AnimationInfo> mAnimations;
+
+    std::map<std::string, AnimationInfo> mPartsToAnimationMap;
+
+    std::map<uint64_t, VhalStatus> mVhalStatusMap;
+
+    std::map<uint64_t, std::set<std::string>> mVhalToPartsMap;
+
+    std::map<std::string, CarPartStatus> mCarPartsStatusMap;
+
+    std::map<std::string, AnimationParam> mUpdatedPartsMap;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // SURROUND_VIEW_SERVICE_IMPL_ANIMATION_H_
diff --git a/surround_view/service-impl/AnimationModuleTests.cpp b/surround_view/service-impl/AnimationModuleTests.cpp
new file mode 100644
index 0000000..5d6e5d5
--- /dev/null
+++ b/surround_view/service-impl/AnimationModuleTests.cpp
@@ -0,0 +1,439 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AnimationModuleTests"
+
+#include "AnimationModule.h"
+#include "MathHelp.h"
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include <gtest/gtest.h>
+#include <map>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+namespace {
+
+std::map<std::string, CarPart> getSampleCarPartsMap() {
+    std::vector<std::string> carFrameChildPartIds{"front_left_door", "front_right_door",
+                                                  "front_left_blinker", "front_right_blinker",
+                                                  "sun_roof"};
+
+    android_auto::surround_view::CarPart frame(std::vector<CarVertex>(),
+                                               android_auto::surround_view::CarMaterial(),
+                                               gMat4Identity, "root", carFrameChildPartIds);
+
+    android_auto::surround_view::CarPart frameChild(std::vector<CarVertex>(),
+                                                    android_auto::surround_view::CarMaterial(),
+                                                    gMat4Identity, "frame",
+                                                    std::vector<std::string>());
+
+    std::map<std::string, CarPart> sampleCarParts;
+    sampleCarParts.emplace(std::make_pair("frame", frame));
+    sampleCarParts.emplace(std::make_pair("front_left_door", frameChild));
+    sampleCarParts.emplace(std::make_pair("front_right_door", frameChild));
+    sampleCarParts.emplace(std::make_pair("front_left_blinker", frameChild));
+    sampleCarParts.emplace(std::make_pair("front_right_blinker", frameChild));
+    sampleCarParts.emplace(std::make_pair("sun_roof", frameChild));
+    return sampleCarParts;
+}
+
+std::vector<AnimationInfo> getSampleAnimations() {
+    AnimationInfo frameAnimation = AnimationInfo{
+            .partId = "frame",
+            .parentId = "root",
+            .pose = gMat4Identity,
+    };
+
+    RotationOp frontLeftDoorRotationOp =
+            RotationOp{.vhalProperty = (int64_t)(0x0200 | VehiclePropertyGroup::SYSTEM |
+                                                 VehiclePropertyType::INT32 | VehicleArea::DOOR)
+                                       << 32 |
+                               (int64_t)(VehicleArea::DOOR),
+                       .type = AnimationType::ROTATION_ANGLE,
+                       .axis =
+                               RotationAxis{
+                                       .axisVector = std::array<float, 3>{0.0f, 0.0f, 1.0f},
+                                       .rotationPoint = std::array<float, 3>{-1.0f, 0.5f, 0.0f},
+                               },
+                       .animationTime = 2000,
+                       .rotationRange =
+                               Range{
+                                       .start = 0.0f,
+                                       .end = 90.0f,
+                               },
+                       .vhalRange = Range{
+                               .start = 0.0f,
+                               .end = (float)INT32_MAX,
+                       }};
+
+    std::map<uint64_t, std::vector<RotationOp>> frontLeftDoorRotationOpsMap;
+
+    frontLeftDoorRotationOpsMap.emplace(
+            std::make_pair(frontLeftDoorRotationOp.vhalProperty,
+                           std::vector<RotationOp>{frontLeftDoorRotationOp}));
+
+    AnimationInfo frontLeftDoorAnimation = AnimationInfo{
+            .partId = "front_left_door",
+            .parentId = "frame",
+            .pose = gMat4Identity,
+            .rotationOpsMap = frontLeftDoorRotationOpsMap,
+    };
+
+    RotationOp frontRightDoorRotationOp =
+            RotationOp{.vhalProperty = (int64_t)(0x0201 | VehiclePropertyGroup::SYSTEM |
+                                                 VehiclePropertyType::INT32 | VehicleArea::DOOR)
+                                       << 32 |
+                               (int64_t)(VehicleArea::DOOR),
+                       .type = AnimationType::ROTATION_ANGLE,
+                       .axis =
+                               RotationAxis{
+                                       .axisVector = std::array<float, 3>{0.0f, 0.0f, 1.0f},
+                                       .rotationPoint = std::array<float, 3>{1.0f, 0.5f, 0.0f},
+                               },
+                       .animationTime = 2000,
+                       .rotationRange =
+                               Range{
+                                       .start = 0.0f,
+                                       .end = -90.0f,
+                               },
+                       .vhalRange = Range{
+                               .start = 0.0f,
+                               .end = (float)INT32_MAX,
+                       }};
+
+    std::map<uint64_t, std::vector<RotationOp>> frontRightDoorRotationOpsMap;
+
+    frontRightDoorRotationOpsMap.emplace(
+            std::make_pair(frontRightDoorRotationOp.vhalProperty,
+                           std::vector<RotationOp>{frontRightDoorRotationOp}));
+
+    AnimationInfo frontRightDoorAnimation = AnimationInfo{
+            .partId = "front_right_door",
+            .parentId = "frame",
+            .pose = gMat4Identity,
+            .rotationOpsMap = frontRightDoorRotationOpsMap,
+    };
+
+    GammaOp frontLeftBlinkerGammaOp = GammaOp{
+            .vhalProperty = (int64_t)(0x0300 | VehiclePropertyGroup::SYSTEM |
+                                      VehiclePropertyType::INT32 | VehicleArea::GLOBAL)
+                            << 32 |
+                    (int64_t)(VehicleArea::GLOBAL),
+            .type = AnimationType::ADJUST_GAMMA_REPEAT,
+            .animationTime = 1000,
+            .gammaRange =
+                    Range{
+                            .start = 1.0f,
+                            .end = 0.5f,
+                    },
+            .vhalRange =
+                    Range{
+                            .start = 0.0f,
+                            .end = (float)INT32_MAX,
+                    },
+    };
+
+    std::map<uint64_t, std::vector<GammaOp>> frontLeftBlinkerGammaOpsMap;
+
+    frontLeftBlinkerGammaOpsMap.emplace(
+            std::make_pair(frontLeftBlinkerGammaOp.vhalProperty,
+                           std::vector<GammaOp>{frontLeftBlinkerGammaOp}));
+
+    AnimationInfo frontLeftBlinkerAnimation = AnimationInfo{
+            .partId = "front_left_blinker",
+            .parentId = "frame",
+            .pose = gMat4Identity,
+            .gammaOpsMap = frontLeftBlinkerGammaOpsMap,
+    };
+
+    GammaOp frontRightBlinkerGammaOp = GammaOp{
+            .vhalProperty = (int64_t)(0x0301 | VehiclePropertyGroup::SYSTEM |
+                                      VehiclePropertyType::INT32 | VehicleArea::GLOBAL)
+                            << 32 |
+                    (int64_t)(VehicleArea::GLOBAL),
+            .type = AnimationType::ADJUST_GAMMA_REPEAT,
+            .animationTime = 1000,
+            .gammaRange =
+                    Range{
+                            .start = 1.0f,
+                            .end = 0.5f,
+                    },
+            .vhalRange =
+                    Range{
+                            .start = 0.0f,
+                            .end = (float)INT32_MAX,
+                    },
+    };
+
+    std::map<uint64_t, std::vector<GammaOp>> frontRightBlinkerGammaOpsMap;
+
+    frontRightBlinkerGammaOpsMap.emplace(
+            std::make_pair(frontRightBlinkerGammaOp.vhalProperty,
+                           std::vector<GammaOp>{frontRightBlinkerGammaOp}));
+
+    AnimationInfo frontRightBlinkerAnimation = AnimationInfo{
+            .partId = "front_right_blinker",
+            .parentId = "frame",
+            .pose = gMat4Identity,
+            .gammaOpsMap = frontRightBlinkerGammaOpsMap,
+    };
+
+    TranslationOp sunRoofTranslationOp = TranslationOp{
+            .vhalProperty = (int64_t)(0x0400 | VehiclePropertyGroup::SYSTEM |
+                                      VehiclePropertyType::INT32 | VehicleArea::GLOBAL)
+                            << 32 |
+                    (int64_t)(VehicleArea::GLOBAL),
+            .type = AnimationType::TRANSLATION,
+            .direction = std::array<float, 3>{0.0f, -1.0f, 0.0f},
+            .animationTime = 3000,
+            .translationRange =
+                    Range{
+                            .start = 0.0f,
+                            .end = 0.5f,
+                    },
+            .vhalRange =
+                    Range{
+                            .start = 0.0f,
+                            .end = (float)INT32_MAX,
+                    },
+    };
+
+    std::map<uint64_t, std::vector<TranslationOp>> sunRoofRotationOpsMap;
+    sunRoofRotationOpsMap.emplace(std::make_pair(sunRoofTranslationOp.vhalProperty,
+                                                 std::vector<TranslationOp>{sunRoofTranslationOp}));
+
+    AnimationInfo sunRoofAnimation = AnimationInfo{
+            .partId = "sun_roof",
+            .parentId = "frame",
+            .pose = gMat4Identity,
+            .translationOpsMap = sunRoofRotationOpsMap,
+    };
+
+    return std::vector<AnimationInfo>{frameAnimation,
+                                      frontLeftDoorAnimation,
+                                      frontRightDoorAnimation,
+                                      frontLeftBlinkerAnimation,
+                                      frontRightBlinkerAnimation,
+                                      sunRoofAnimation};
+}
+
+TEST(AnimationModuleTests, EmptyVhalSuccess) {
+    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
+                                    getSampleAnimations());
+    std::vector<AnimationParam> result =
+            animationModule.getUpdatedAnimationParams(std::vector<VehiclePropValue>());
+    EXPECT_EQ(result.size(), 0);
+}
+
+TEST(AnimationModuleTests, LeftDoorAnimationOnceSuccess) {
+    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
+                                    getSampleAnimations());
+    std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
+            std::vector<VehiclePropValue>{VehiclePropValue{
+                    .areaId = (int32_t)VehicleArea::DOOR,
+                    .prop = 0x0200 | VehiclePropertyGroup::SYSTEM | VehiclePropertyType::INT32 |
+                            VehicleArea::DOOR,
+                    .value.int32Values = std::vector<int32_t>(1, INT32_MAX),
+            }});
+    EXPECT_EQ(result.size(), 1);
+}
+
+TEST(AnimationModuleTests, LeftDoorAnimationTenTimesSuccess) {
+    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
+                                    getSampleAnimations());
+    for (int i = 0; i < 10; ++i) {
+        std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
+                std::vector<VehiclePropValue>{VehiclePropValue{
+                        .areaId = (int32_t)VehicleArea::DOOR,
+                        .prop = 0x0200 | VehiclePropertyGroup::SYSTEM | VehiclePropertyType::INT32 |
+                                VehicleArea::DOOR,
+                        .value.int32Values = std::vector<int32_t>(1, INT32_MAX),
+                }});
+        EXPECT_EQ(result.size(), 1);
+    }
+}
+
+TEST(AnimationModuleTests, RightDoorAnimationOnceSuccess) {
+    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
+                                    getSampleAnimations());
+    std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
+            std::vector<VehiclePropValue>{VehiclePropValue{
+                    .areaId = (int32_t)VehicleArea::DOOR,
+                    .prop = 0x0201 | VehiclePropertyGroup::SYSTEM | VehiclePropertyType::INT32 |
+                            VehicleArea::DOOR,
+                    .value.int32Values = std::vector<int32_t>(1, INT32_MAX),
+            }});
+    EXPECT_EQ(result.size(), 1);
+}
+
+TEST(AnimationModuleTests, RightDoorAnimationTenTimesSuccess) {
+    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
+                                    getSampleAnimations());
+    for (int i = 0; i < 10; ++i) {
+        std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
+                std::vector<VehiclePropValue>{VehiclePropValue{
+                        .areaId = (int32_t)VehicleArea::DOOR,
+                        .prop = 0x0201 | VehiclePropertyGroup::SYSTEM | VehiclePropertyType::INT32 |
+                                VehicleArea::DOOR,
+                        .value.int32Values = std::vector<int32_t>(1, INT32_MAX),
+                }});
+        EXPECT_EQ(result.size(), 1);
+    }
+}
+
+TEST(AnimationModuleTests, LeftBlinkerAnimationOnceSuccess) {
+    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
+                                    getSampleAnimations());
+    std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
+            std::vector<VehiclePropValue>{VehiclePropValue{
+                    .areaId = (int32_t)VehicleArea::GLOBAL,
+                    .prop = 0x0300 | VehiclePropertyGroup::SYSTEM | VehiclePropertyType::INT32 |
+                            VehicleArea::GLOBAL,
+                    .value.int32Values = std::vector<int32_t>(1, INT32_MAX),
+            }});
+    EXPECT_EQ(result.size(), 1);
+}
+
+TEST(AnimationModuleTests, LeftBlinkerAnimationTenTimesSuccess) {
+    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
+                                    getSampleAnimations());
+    for (int i = 0; i < 10; ++i) {
+        std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
+                std::vector<VehiclePropValue>{VehiclePropValue{
+                        .areaId = (int32_t)VehicleArea::GLOBAL,
+                        .prop = 0x0300 | VehiclePropertyGroup::SYSTEM | VehiclePropertyType::INT32 |
+                                VehicleArea::GLOBAL,
+                        .value.int32Values = std::vector<int32_t>(1, INT32_MAX),
+                }});
+        EXPECT_EQ(result.size(), 1);
+    }
+}
+
+TEST(AnimationModuleTests, RightBlinkerAnimationOnceSuccess) {
+    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
+                                    getSampleAnimations());
+    std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
+            std::vector<VehiclePropValue>{VehiclePropValue{
+                    .areaId = (int32_t)VehicleArea::GLOBAL,
+                    .prop = 0x0301 | VehiclePropertyGroup::SYSTEM | VehiclePropertyType::INT32 |
+                            VehicleArea::GLOBAL,
+                    .value.int32Values = std::vector<int32_t>(1, INT32_MAX),
+            }});
+    EXPECT_EQ(result.size(), 1);
+}
+
+TEST(AnimationModuleTests, RightBlinkerAnimationTenTimesSuccess) {
+    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
+                                    getSampleAnimations());
+    for (int i = 0; i < 10; ++i) {
+        std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
+                std::vector<VehiclePropValue>{VehiclePropValue{
+                        .areaId = (int32_t)VehicleArea::GLOBAL,
+                        .prop = 0x0301 | VehiclePropertyGroup::SYSTEM | VehiclePropertyType::INT32 |
+                                VehicleArea::GLOBAL,
+                        .value.int32Values = std::vector<int32_t>(1, INT32_MAX),
+                }});
+        EXPECT_EQ(result.size(), 1);
+    }
+}
+
+TEST(AnimationModuleTests, SunRoofAnimationOnceSuccess) {
+    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
+                                    getSampleAnimations());
+    std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
+            std::vector<VehiclePropValue>{VehiclePropValue{
+                    .areaId = (int32_t)VehicleArea::GLOBAL,
+                    .prop = 0x0400 | VehiclePropertyGroup::SYSTEM | VehiclePropertyType::INT32 |
+                            VehicleArea::GLOBAL,
+                    .value.int32Values = std::vector<int32_t>(1, INT32_MAX),
+            }});
+    EXPECT_EQ(result.size(), 1);
+}
+
+TEST(AnimationModuleTests, SunRoofAnimationTenTimesSuccess) {
+    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
+                                    getSampleAnimations());
+    for (int i = 0; i < 10; ++i) {
+        std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
+                std::vector<VehiclePropValue>{VehiclePropValue{
+                        .areaId = (int32_t)VehicleArea::GLOBAL,
+                        .prop = 0x0400 | VehiclePropertyGroup::SYSTEM | VehiclePropertyType::INT32 |
+                                VehicleArea::GLOBAL,
+                        .value.int32Values = std::vector<int32_t>(1, INT32_MAX),
+                }});
+        EXPECT_EQ(result.size(), 1);
+    }
+}
+
+TEST(AnimationModuleTests, All5PartsAnimationOnceSuccess) {
+    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
+                                    getSampleAnimations());
+    std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
+            std::vector<VehiclePropValue>{VehiclePropValue{
+                                                  .areaId = (int32_t)VehicleArea::DOOR,
+                                                  .prop = 0x0200 | VehiclePropertyGroup::SYSTEM |
+                                                          VehiclePropertyType::INT32 |
+                                                          VehicleArea::DOOR,
+                                                  .value.int32Values =
+                                                          std::vector<int32_t>(1, INT32_MAX),
+                                          },
+                                          VehiclePropValue{
+                                                  .areaId = (int32_t)VehicleArea::DOOR,
+                                                  .prop = 0x0201 | VehiclePropertyGroup::SYSTEM |
+                                                          VehiclePropertyType::INT32 |
+                                                          VehicleArea::DOOR,
+                                                  .value.int32Values =
+                                                          std::vector<int32_t>(1, INT32_MAX),
+                                          },
+                                          VehiclePropValue{
+                                                  .areaId = (int32_t)VehicleArea::GLOBAL,
+                                                  .prop = 0x0300 | VehiclePropertyGroup::SYSTEM |
+                                                          VehiclePropertyType::INT32 |
+                                                          VehicleArea::GLOBAL,
+                                                  .value.int32Values =
+                                                          std::vector<int32_t>(1, INT32_MAX),
+                                          },
+                                          VehiclePropValue{
+                                                  .areaId = (int32_t)VehicleArea::GLOBAL,
+                                                  .prop = 0x0301 | VehiclePropertyGroup::SYSTEM |
+                                                          VehiclePropertyType::INT32 |
+                                                          VehicleArea::GLOBAL,
+                                                  .value.int32Values =
+                                                          std::vector<int32_t>(1, INT32_MAX),
+                                          },
+                                          VehiclePropValue{
+                                                  .areaId = (int32_t)VehicleArea::GLOBAL,
+                                                  .prop = 0x0400 | VehiclePropertyGroup::SYSTEM |
+                                                          VehiclePropertyType::INT32 |
+                                                          VehicleArea::GLOBAL,
+                                                  .value.int32Values =
+                                                          std::vector<int32_t>(1, INT32_MAX),
+                                          }});
+    EXPECT_EQ(result.size(), 5);
+}
+
+}  // namespace
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/CameraUtils.cpp b/surround_view/service-impl/CameraUtils.cpp
new file mode 100644
index 0000000..0dd6226
--- /dev/null
+++ b/surround_view/service-impl/CameraUtils.cpp
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CameraUtils.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
+
+#include <math.h>
+
+using namespace android::hardware::automotive::evs::V1_1;
+
+using ::android::sp;
+using ::std::string;
+using ::std::vector;
+using ::std::map;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+bool isLogicalCamera(const camera_metadata_t* metadata) {
+    if (metadata == nullptr) {
+        // A logical camera device must have a valid camera metadata.
+        return false;
+    }
+
+    // Looking for LOGICAL_MULTI_CAMERA capability from metadata.
+    camera_metadata_ro_entry_t entry;
+    int rc =
+        find_camera_metadata_ro_entry(metadata,
+                                      ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+                                      &entry);
+    if (0 != rc) {
+        // No capabilities are found.
+        return false;
+    }
+
+    for (size_t i = 0; i < entry.count; ++i) {
+        uint8_t cap = entry.data.u8[i];
+        if (cap ==
+            ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+vector<string> getPhysicalCameraIds(sp<IEvsCamera> camera) {
+    if (camera == nullptr) {
+        LOG(WARNING) << __FUNCTION__ << "The EVS camera object is invalid";
+        return {};
+    }
+
+    CameraDesc desc;
+    camera->getCameraInfo_1_1([&desc](const CameraDesc& info) {
+        desc = info;
+    });
+
+    vector<string> physicalCameras;
+    const camera_metadata_t* metadata =
+        reinterpret_cast<camera_metadata_t*>(&desc.metadata[0]);
+
+    if (!isLogicalCamera(metadata)) {
+        // EVS assumes that the device w/o a valid metadata is a physical
+        // device.
+        LOG(INFO) << desc.v1.cameraId << " is not a logical camera device.";
+        physicalCameras.emplace_back(desc.v1.cameraId);
+        return physicalCameras;
+    }
+
+    // Look for physical camera identifiers
+    camera_metadata_ro_entry entry;
+    int rc =
+        find_camera_metadata_ro_entry(metadata,
+                                      ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS,
+                                      &entry);
+    if (rc != 0) {
+        LOG(ERROR) << "No physical camera ID is found for "
+                   << desc.v1.cameraId;
+        return {};
+    }
+
+    const uint8_t* ids = entry.data.u8;
+    size_t start = 0;
+    for (size_t i = 0; i < entry.count; ++i) {
+        if (ids[i] == '\0') {
+            if (start != i) {
+                string id(reinterpret_cast<const char*>(ids + start));
+                physicalCameras.emplace_back(id);
+            }
+            start = i + 1;
+        }
+    }
+
+    LOG(INFO) << desc.v1.cameraId << " consists of " << physicalCameras.size()
+              << " physical camera devices";
+    return physicalCameras;
+}
+
+string tagToString(uint32_t tag) {
+    switch (tag) {
+        case ANDROID_LENS_DISTORTION:
+            return "ANDROID_LENS_DISTORTION";
+        case ANDROID_LENS_INTRINSIC_CALIBRATION:
+            return "ANDROID_LENS_INTRINSIC_CALIBRATION";
+        case ANDROID_LENS_POSE_TRANSLATION:
+            return "ANDROID_LENS_POSE_TRANSLATION";
+        case ANDROID_LENS_POSE_ROTATION:
+            return "ANDROID_LENS_POSE_ROTATION";
+        default:
+            LOG(WARNING) << "Cannot recognize the tag: " << tag;
+            return {};
+    }
+}
+
+bool getParam(const camera_metadata_t* metadata,
+              uint32_t tag,
+              int size,
+              float* param) {
+    camera_metadata_ro_entry_t entry = camera_metadata_ro_entry_t();
+    int rc = find_camera_metadata_ro_entry(metadata, tag, &entry);
+
+    if (rc != 0) {
+        LOG(ERROR) << "No metadata found for " << tagToString(tag);
+        return false;
+    }
+
+    if (entry.count != size || entry.type != TYPE_FLOAT) {
+        LOG(ERROR) << "Unexpected size or type for " << tagToString(tag);
+        return false;
+    }
+
+    const float* lensParam = entry.data.f;
+    for (int i = 0; i < size; i++) {
+        param[i] = lensParam[i];
+    }
+    return true;
+}
+
+bool getAndroidCameraParams(sp<IEvsCamera> camera,
+                            const string& cameraId,
+                            AndroidCameraParams& params) {
+    if (camera == nullptr) {
+        LOG(WARNING) << __FUNCTION__ << "The EVS camera object is invalid";
+        return {};
+    }
+
+    CameraDesc desc = {};
+    camera->getPhysicalCameraInfo(cameraId, [&desc](const CameraDesc& info) {
+        desc = info;
+    });
+
+    if (desc.metadata.size() == 0) {
+        LOG(ERROR) << "No metadata found for " << desc.v1.cameraId;
+        return false;
+    }
+
+    const camera_metadata_t* metadata =
+        reinterpret_cast<camera_metadata_t*>(&desc.metadata[0]);
+
+    // Look for ANDROID_LENS_DISTORTION
+    if (!getParam(metadata,
+                  ANDROID_LENS_DISTORTION,
+                  kSizeLensDistortion,
+                  &params.lensDistortion[0])) {
+        return false;
+    }
+
+    // Look for ANDROID_LENS_INTRINSIC_CALIBRATION
+    if (!getParam(metadata,
+                  ANDROID_LENS_INTRINSIC_CALIBRATION,
+                  kSizeLensIntrinsicCalibration,
+                  &params.lensIntrinsicCalibration[0])) {
+        return false;
+    }
+
+    // Look for ANDROID_LENS_POSE_TRANSLATION
+    if (!getParam(metadata,
+                  ANDROID_LENS_POSE_TRANSLATION,
+                  kSizeLensPoseTranslation,
+                  &params.lensPoseTranslation[0])) {
+        return false;
+    }
+
+    // Look for ANDROID_LENS_POSE_ROTATION
+    if (!getParam(metadata,
+                  ANDROID_LENS_POSE_ROTATION,
+                  kSizeLensPoseRotation,
+                  &params.lensPoseRotation[0])) {
+        return false;
+    }
+
+    return true;
+}
+
+vector<SurroundViewCameraParams> convertToSurroundViewCameraParams(
+        const map<string, AndroidCameraParams>& androidCameraParamsMap) {
+    vector<SurroundViewCameraParams> result;
+
+    // TODO(b/156101189): the cameras are in random order now. They need to be
+    // sorted based on the camera position info from config file.
+    for (const auto& entry : androidCameraParamsMap) {
+        SurroundViewCameraParams svParams;
+
+        // Android Camera format for intrinsics: [f_x, f_y, c_x, c_y, s]
+        //
+        // To corelib:
+        // SurroundViewCameraParams.intrinsics =
+        //         [ f_x,   s, c_x,
+        //             0, f_y, c_y,
+        //             0,   0,   1 ];
+        const float* intrinsics = &entry.second.lensIntrinsicCalibration[0];
+        svParams.intrinsics[0] = intrinsics[0];
+        svParams.intrinsics[1] = intrinsics[4];
+        svParams.intrinsics[2] = intrinsics[2];
+        svParams.intrinsics[3] = 0;
+        svParams.intrinsics[4] = intrinsics[1];
+        svParams.intrinsics[5] = intrinsics[3];
+        svParams.intrinsics[6] = 0;
+        svParams.intrinsics[7] = 0;
+        svParams.intrinsics[8] = 1;
+
+        // Android Camera format for lens distortion:
+        //         Radial: [kappa_1, kappa_2, kappa_3]
+        //         Tangential: [kappa_4, kappa_5]
+        //
+        // To corelib:
+        // SurroundViewCameraParams.distortion =
+        //         [kappa_1, kappa_2, kappa_3, kappa_4];
+        const float* distortion = &entry.second.lensDistortion[0];
+        svParams.distorion[0] = distortion[0];
+        svParams.distorion[1] = distortion[1];
+        svParams.distorion[2] = distortion[2];
+        svParams.distorion[3] = distortion[3];
+
+        // Android Camera format for rotation:
+        //         quaternion coefficients (x,y,z,w)
+        //
+        // To corelib:
+        //         theta = 2 * acos(w)
+        //         a_x = x / sin(theta/2)
+        //         a_y = y / sin(theta/2)
+        //         a_z = z / sin(theta/2)
+        // SurroundViewCameraParams.rvec =
+        //         [theta * a_x, theta * a_y, theta * a_z];
+        const float* rotation = &entry.second.lensPoseRotation[0];
+        const float theta = 2 * acos(rotation[3]);
+        const float a_x = rotation[0] / sin(theta / 2);
+        const float a_y = rotation[1] / sin(theta / 2);
+        const float a_z = rotation[2] / sin(theta / 2);
+        svParams.rvec[0] = theta * a_x;
+        svParams.rvec[1] = theta * a_y;
+        svParams.rvec[2] = theta * a_z;
+
+        // Android Camera format for translation: Translation = (x,y,z)
+        //
+        // To corelib:
+        // SurroundViewCameraParams.tvec = [x, y, z];
+        const float* translation = &entry.second.lensPoseTranslation[0];
+        svParams.tvec[0] = translation[0];
+        svParams.tvec[1] = translation[1];
+        svParams.tvec[2] = translation[2];
+
+        LOG(INFO) << "Camera parameters for " << entry.first
+                  << " have been converted to SV core lib format successfully";
+        result.emplace_back(svParams);
+    }
+
+    return result;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
diff --git a/surround_view/service-impl/CameraUtils.h b/surround_view/service-impl/CameraUtils.h
new file mode 100644
index 0000000..1fbc8d4
--- /dev/null
+++ b/surround_view/service-impl/CameraUtils.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <system/camera_metadata.h>
+
+#include <string>
+#include <vector>
+
+#include "core_lib.h"
+
+using ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+using ::android_auto::surround_view::SurroundViewCameraParams;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+const int kSizeLensDistortion = 5;
+const int kSizeLensIntrinsicCalibration = 5;
+const int kSizeLensPoseTranslation = 3;
+const int kSizeLensPoseRotation = 4;
+
+// Camera parameters that the Android Camera team defines.
+struct AndroidCameraParams {
+    float lensDistortion[kSizeLensDistortion];
+    float lensIntrinsicCalibration[kSizeLensIntrinsicCalibration];
+    float lensPoseTranslation[kSizeLensPoseTranslation];
+    float lensPoseRotation[kSizeLensPoseRotation];
+};
+
+// Gets the underlying physical camera ids for logical camera.
+// If the given camera is not a logical, its own id will be returned.
+std::vector<std::string> getPhysicalCameraIds(android::sp<IEvsCamera> camera);
+
+// Gets the intrinsic/extrinsic parameters for the given physical camera id.
+// Returns true if the parameters are obtained successfully. Returns false
+// otherwise.
+bool getAndroidCameraParams(android::sp<IEvsCamera> camera,
+                            const std::string& cameraId,
+                            AndroidCameraParams& params);
+
+// Converts the camera parameters from Android Camera format into Surround View
+// core lib format.
+std::vector<SurroundViewCameraParams> convertToSurroundViewCameraParams(
+        const std::map<std::string, AndroidCameraParams>& androidCameraParamsMap);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/CarModelConfigReader.cpp b/surround_view/service-impl/CarModelConfigReader.cpp
new file mode 100644
index 0000000..7be6cb0
--- /dev/null
+++ b/surround_view/service-impl/CarModelConfigReader.cpp
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CarModelConfigReader.h"
+#include "ConfigReaderUtil.h"
+#include "MathHelp.h"
+#include "core_lib.h"
+
+#include <android-base/logging.h>
+#include <tinyxml2.h>
+#include <sstream>
+#include <string>
+#include <utility>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+// Macro returning IoStatus::ERROR_READ_ANIMATION if condition evaluates to false.
+#define RETURN_ERROR_STATUS_IF_FALSE(cond)         \
+    do {                                           \
+        if (!(cond)) {                             \
+            return IOStatus::ERROR_READ_ANIMATION; \
+        }                                          \
+    } while (0)
+
+using tinyxml2::XML_SUCCESS;
+using tinyxml2::XMLDocument;
+using tinyxml2::XMLElement;
+
+namespace {
+
+bool ReadValueHex(const XMLElement* parent, const char* elementName, uint32_t* hex) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    RETURN_IF_FALSE(ElementHasText(element));
+    *hex = std::stoul(element->GetText(), nullptr, 16);
+    return true;
+}
+
+bool ReadValueList(const XMLElement* parent, const char* elementName,
+                   std::vector<std::string>* valueList) {
+    valueList->clear();
+    for (const XMLElement* elem = parent->FirstChildElement(elementName); elem != nullptr;
+         elem = elem->NextSiblingElement(elementName)) {
+        RETURN_IF_FALSE(ElementHasText(elem));
+        valueList->push_back(std::string(elem->GetText()));
+    }
+    return true;
+}
+
+// ReadValue for SurroundView2dParams::BlendingType.
+bool ReadAnimationType(const XMLElement* parent, const char* elementName, AnimationType* type) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    RETURN_IF_FALSE(ElementHasText(element));
+    const std::string animationTypeStr(element->GetText());
+
+    if (animationTypeStr == "RotationAngle") {
+        *type = AnimationType::ROTATION_ANGLE;
+    } else if (animationTypeStr == "RotationSpeed") {
+        *type = AnimationType::ROTATION_SPEED;
+    } else if (animationTypeStr == "Translation") {
+        *type = AnimationType::TRANSLATION;
+    } else if (animationTypeStr == "SwitchTextureOnce") {
+        *type = AnimationType::SWITCH_TEXTURE_ONCE;
+    } else if (animationTypeStr == "AdjustGammaOnce") {
+        *type = AnimationType::ADJUST_GAMMA_ONCE;
+    } else if (animationTypeStr == "SwitchTextureRepeat") {
+        *type = AnimationType::SWITCH_TEXTURE_REPEAT;
+    } else if (animationTypeStr == "AdjustGammaRepeat") {
+        *type = AnimationType::ADJUST_GAMMA_REPEAT;
+    } else {
+        LOG(ERROR) << "Unknown AnimationType specified: " << animationTypeStr;
+        return false;
+    }
+    return true;
+}
+
+bool ReadRange(const XMLElement* parent, const char* elementName, Range* range) {
+    const XMLElement* rangeElem = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &rangeElem));
+    {
+        RETURN_IF_FALSE(ReadValue(rangeElem, "Start", &range->start));
+        RETURN_IF_FALSE(ReadValue(rangeElem, "End", &range->end));
+    }
+    return true;
+}
+
+bool ReadFloat3(const XMLElement* parent, const char* elementName, std::array<float, 3>* float3) {
+    const XMLElement* arrayElem = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &arrayElem));
+    {
+        RETURN_IF_FALSE(ReadValue(arrayElem, "X", &float3->at(0)));
+        RETURN_IF_FALSE(ReadValue(arrayElem, "Y", &float3->at(1)));
+        RETURN_IF_FALSE(ReadValue(arrayElem, "Z", &float3->at(2)));
+    }
+    return true;
+}
+
+// Generic template for reading a animation op, each op type must be specialized.
+template <typename OpType>
+bool ReadOp(const XMLElement* opElem, OpType* op) {
+    (void)opElem;
+    (void)op;
+    LOG(ERROR) << "Unexpected internal error: Op type in not supported.";
+    return false;
+}
+
+// Reads vhal property.
+bool ReadVhalProperty(const XMLElement* parent, const char* elementName, uint64_t* vhalProperty) {
+    const XMLElement* vhalPropElem = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &vhalPropElem));
+    {
+        uint32_t propertyId;
+        uint32_t areaId;
+        RETURN_IF_FALSE(ReadValueHex(vhalPropElem, "PropertyId", &propertyId));
+        RETURN_IF_FALSE(ReadValueHex(vhalPropElem, "AreaId", &areaId));
+        *vhalProperty = (static_cast<uint64_t>(propertyId) << 32) | areaId;
+    }
+    return true;
+}
+
+template <>
+bool ReadOp<RotationOp>(const XMLElement* rotationOpElem, RotationOp* rotationOp) {
+    RETURN_IF_FALSE(ReadVhalProperty(rotationOpElem, "VhalProperty", &rotationOp->vhalProperty));
+
+    RETURN_IF_FALSE(ReadAnimationType(rotationOpElem, "AnimationType", &rotationOp->type));
+
+    RETURN_IF_FALSE(ReadFloat3(rotationOpElem, "RotationAxis", &rotationOp->axis.axisVector));
+
+    RETURN_IF_FALSE(ReadFloat3(rotationOpElem, "RotationPoint", &rotationOp->axis.rotationPoint));
+
+    RETURN_IF_FALSE(
+            ReadValue(rotationOpElem, "DefaultRotationValue", &rotationOp->defaultRotationValue));
+
+    RETURN_IF_FALSE(ReadValue(rotationOpElem, "AnimationTimeMs", &rotationOp->animationTime));
+
+    RETURN_IF_FALSE(ReadRange(rotationOpElem, "RotationRange", &rotationOp->rotationRange));
+
+    RETURN_IF_FALSE(ReadRange(rotationOpElem, "VhalRange", &rotationOp->vhalRange));
+
+    return true;
+}
+
+template <>
+bool ReadOp<TranslationOp>(const XMLElement* translationOpElem, TranslationOp* translationOp) {
+    RETURN_IF_FALSE(
+            ReadVhalProperty(translationOpElem, "VhalProperty", &translationOp->vhalProperty));
+
+    RETURN_IF_FALSE(ReadAnimationType(translationOpElem, "AnimationType", &translationOp->type));
+
+    RETURN_IF_FALSE(ReadFloat3(translationOpElem, "Direction", &translationOp->direction));
+
+    RETURN_IF_FALSE(ReadValue(translationOpElem, "DefaultTranslationValue",
+                              &translationOp->defaultTranslationValue));
+
+    RETURN_IF_FALSE(ReadValue(translationOpElem, "AnimationTimeMs", &translationOp->animationTime));
+
+    RETURN_IF_FALSE(
+            ReadRange(translationOpElem, "TranslationRange", &translationOp->translationRange));
+
+    RETURN_IF_FALSE(ReadRange(translationOpElem, "VhalRange", &translationOp->vhalRange));
+
+    return true;
+}
+
+template <>
+bool ReadOp<TextureOp>(const XMLElement* textureOpElem, TextureOp* textureOp) {
+    RETURN_IF_FALSE(ReadVhalProperty(textureOpElem, "VhalProperty", &textureOp->vhalProperty));
+
+    RETURN_IF_FALSE(ReadAnimationType(textureOpElem, "AnimationType", &textureOp->type));
+
+    RETURN_IF_FALSE(ReadValue(textureOpElem, "DefaultTexture", &textureOp->defaultTexture));
+
+    RETURN_IF_FALSE(ReadValue(textureOpElem, "AnimationTimeMs", &textureOp->animationTime));
+
+    RETURN_IF_FALSE(ReadRange(textureOpElem, "TextureRange", &textureOp->textureRange));
+
+    RETURN_IF_FALSE(ReadRange(textureOpElem, "VhalRange", &textureOp->vhalRange));
+
+    return true;
+}
+
+template <>
+bool ReadOp<GammaOp>(const XMLElement* gammaOpElem, GammaOp* gammaOp) {
+    RETURN_IF_FALSE(ReadVhalProperty(gammaOpElem, "VhalProperty", &gammaOp->vhalProperty));
+
+    RETURN_IF_FALSE(ReadAnimationType(gammaOpElem, "AnimationType", &gammaOp->type));
+
+    RETURN_IF_FALSE(ReadValue(gammaOpElem, "AnimationTimeMs", &gammaOp->animationTime));
+
+    RETURN_IF_FALSE(ReadRange(gammaOpElem, "GammaRange", &gammaOp->gammaRange));
+
+    RETURN_IF_FALSE(ReadRange(gammaOpElem, "VhalRange", &gammaOp->vhalRange));
+
+    return true;
+}
+
+template <typename OpType>
+bool ReadAllOps(const XMLElement* animationElem, const char* elemName,
+                std::map<uint64_t, std::vector<OpType>>* mapOps) {
+    for (const XMLElement* elem = animationElem->FirstChildElement(elemName); elem != nullptr;
+         elem = elem->NextSiblingElement(elemName)) {
+        OpType op;
+        RETURN_IF_FALSE(ReadOp(elem, &op));
+        if (mapOps->find(op.vhalProperty) == mapOps->end()) {
+            mapOps->emplace(op.vhalProperty, std::vector<OpType>());
+        }
+        mapOps->at(op.vhalProperty).push_back(op);
+    }
+    return true;
+}
+
+bool ReadAnimation(const XMLElement* animationElem, AnimationInfo* animationInfo) {
+    RETURN_IF_FALSE(ReadValue(animationElem, "PartId", &animationInfo->partId));
+    RETURN_IF_FALSE(ReadValue(animationElem, "ParentPartId", &animationInfo->parentId));
+
+    // Child Part Ids (Optional)
+    const XMLElement* childPartsElem = nullptr;
+    GetElement(animationElem, "ChildParts", &childPartsElem);
+    if (childPartsElem != nullptr) {
+        RETURN_IF_FALSE(ReadValueList(childPartsElem, "PartId", &animationInfo->childIds));
+    }
+
+    // Set to the default Identity.
+    animationInfo->pose = gMat4Identity;
+
+    // All animation operations.
+    RETURN_IF_FALSE(ReadAllOps(animationElem, "RotationOp", &animationInfo->rotationOpsMap));
+    RETURN_IF_FALSE(ReadAllOps(animationElem, "TranslationOp", &animationInfo->translationOpsMap));
+    RETURN_IF_FALSE(ReadAllOps(animationElem, "TextureOp", &animationInfo->textureOpsMap));
+    RETURN_IF_FALSE(ReadAllOps(animationElem, "GammaOp", &animationInfo->gammaOpsMap));
+    return true;
+}
+
+bool ReadAllAnimations(const XMLElement* rootElem, std::vector<AnimationInfo>* animations) {
+    animations->clear();
+    // Loop over animation elements.
+    for (const XMLElement* elem = rootElem->FirstChildElement("Animation"); elem != nullptr;
+         elem = elem->NextSiblingElement("Animation")) {
+        AnimationInfo animationInfo;
+        RETURN_IF_FALSE(ReadAnimation(elem, &animationInfo));
+        animations->push_back(animationInfo);
+    }
+    return true;
+}
+
+}  // namespace
+
+IOStatus ReadCarModelConfig(const std::string& carModelConfigFile,
+                            AnimationConfig* animationConfig) {
+    XMLDocument xmlDoc;
+
+    /* load and parse a configuration file */
+    xmlDoc.LoadFile(carModelConfigFile.c_str());
+    if (xmlDoc.ErrorID() != XML_SUCCESS) {
+        LOG(ERROR) << "Failed to load and/or parse a configuration file, " << xmlDoc.ErrorStr();
+        return IOStatus::ERROR_READ_ANIMATION;
+    }
+
+    const XMLElement* rootElem = xmlDoc.RootElement();
+    if (strcmp(rootElem->Name(), "SurroundViewCarModelConfig")) {
+        LOG(ERROR) << "Config file is not in the required format: " << carModelConfigFile;
+        return IOStatus::ERROR_READ_ANIMATION;
+    }
+
+    // version
+    RETURN_ERROR_STATUS_IF_FALSE(ReadValue(rootElem, "Version", &animationConfig->version));
+
+    // animations
+    RETURN_ERROR_STATUS_IF_FALSE(ReadAllAnimations(rootElem, &animationConfig->animations));
+
+    return IOStatus::OK;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/CarModelConfigReader.h b/surround_view/service-impl/CarModelConfigReader.h
new file mode 100644
index 0000000..c2e9049
--- /dev/null
+++ b/surround_view/service-impl/CarModelConfigReader.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SURROUND_VIEW_SERVICE_IMPL_CARMODELCONFIGREADER_H_
+#define SURROUND_VIEW_SERVICE_IMPL_CARMODELCONFIGREADER_H_
+
+#include <string>
+
+#include "IOModuleCommon.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+IOStatus ReadCarModelConfig(const std::string& carModelConfigFile,
+                            AnimationConfig* animationConfig);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+
+}  // namespace android
+
+#endif  // SURROUND_VIEW_SERVICE_IMPL_CARMODELCONFIGREADER_H_
diff --git a/surround_view/service-impl/CarModelConfigReaderTests.cpp b/surround_view/service-impl/CarModelConfigReaderTests.cpp
new file mode 100644
index 0000000..916002b
--- /dev/null
+++ b/surround_view/service-impl/CarModelConfigReaderTests.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "IoModuleTests"
+
+#include "CarModelConfigReader.h"
+
+#include "MathHelp.h"
+#include "core_lib.h"
+
+#include <gtest/gtest.h>
+#include <string>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+namespace {
+
+TEST(CarModelConfigReaderTests, CarModelReadConfigSuccess) {
+    AnimationConfig animationConfig;
+    EXPECT_EQ(ReadCarModelConfig("/vendor/automotive/sv/sv_sample_car_model_config.xml",
+                                 &animationConfig),
+              IOStatus::OK);
+
+    EXPECT_EQ(animationConfig.version, "1.0");
+
+    ASSERT_EQ(animationConfig.animations.size(), 2);
+
+    {
+        AnimationInfo doorAnimation = animationConfig.animations.at(0);
+        EXPECT_EQ(doorAnimation.partId, "door");
+        EXPECT_EQ(doorAnimation.childIds.size(), 2);
+        EXPECT_EQ(doorAnimation.pose, gMat4Identity);
+
+        EXPECT_EQ(doorAnimation.rotationOpsMap.size(), 1);
+        {
+            RotationOp rotationOp = (doorAnimation.rotationOpsMap.at(0x16000B0000000001)).at(0);
+            EXPECT_EQ(rotationOp.vhalProperty, 0x16000B0000000001);
+            EXPECT_EQ(rotationOp.type, AnimationType::ROTATION_ANGLE);
+            EXPECT_EQ(rotationOp.animationTime, 2000);
+            std::array<float, 3> axis = {0, 0, 1};
+            EXPECT_EQ(rotationOp.axis.axisVector, axis);
+            std::array<float, 3> point = {0, 0, 0};
+            EXPECT_EQ(rotationOp.axis.rotationPoint, point);
+            EXPECT_EQ(rotationOp.rotationRange.start, 0.0);
+            EXPECT_EQ(rotationOp.rotationRange.end, 90.0);
+            EXPECT_EQ(rotationOp.vhalRange.start, 0);
+            EXPECT_EQ(rotationOp.vhalRange.end, 0x7FFFFFFF);
+        }
+    }
+
+    {
+        AnimationInfo windowAnimation = animationConfig.animations.at(1);
+        EXPECT_EQ(windowAnimation.partId, "window");
+        EXPECT_EQ(windowAnimation.childIds.size(), 0);
+        EXPECT_EQ(windowAnimation.pose, gMat4Identity);
+
+        EXPECT_EQ(windowAnimation.translationOpsMap.size(), 1);
+        {
+            TranslationOp translationOp =
+                    (windowAnimation.translationOpsMap.at(0x13000BC000000010)).at(0);
+            EXPECT_EQ(translationOp.vhalProperty, 0x13000BC000000010);
+            EXPECT_EQ(translationOp.type, AnimationType::TRANSLATION);
+            EXPECT_EQ(translationOp.animationTime, 2000);
+            std::array<float, 3> dir = {0.0, 0.0, -1.0};
+            EXPECT_EQ(translationOp.direction, dir);
+            EXPECT_EQ(translationOp.defaultTranslationValue, 0.0);
+            EXPECT_EQ(translationOp.translationRange.start, 0.0);
+            EXPECT_EQ(translationOp.translationRange.end, 1.0);
+            EXPECT_EQ(translationOp.vhalRange.start, 0);
+            EXPECT_EQ(translationOp.vhalRange.end, 0x7FFFFFFF);
+        }
+    }
+}
+
+}  // namespace
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/ConfigReader.cpp b/surround_view/service-impl/ConfigReader.cpp
new file mode 100644
index 0000000..cc97d4e
--- /dev/null
+++ b/surround_view/service-impl/ConfigReader.cpp
@@ -0,0 +1,265 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConfigReader.h"
+#include "ConfigReaderUtil.h"
+#include "core_lib.h"
+
+#include <android-base/logging.h>
+#include <tinyxml2.h>
+#include <sstream>
+#include <string>
+#include <utility>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+using tinyxml2::XML_SUCCESS;
+using tinyxml2::XMLDocument;
+using tinyxml2::XMLElement;
+
+using android_auto::surround_view::SurroundView2dParams;
+using android_auto::surround_view::SurroundView3dParams;
+
+namespace {
+
+// Macro returning IoStatus::ERROR_CONFIG_FILE_FORMAT if condition evaluates to false.
+#define RETURN_ERROR_STATUS_IF_FALSE(cond)             \
+    do {                                               \
+        if (!(cond)) {                                 \
+            return IOStatus::ERROR_CONFIG_FILE_FORMAT; \
+        }                                              \
+    } while (0)
+
+// ReadValue for SurroundView2dParams::BlendingType.
+bool ReadValue2dBlendType(const XMLElement* parent, const char* elementName,
+                          SurroundView2dParams::BlendingType* value) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    RETURN_IF_FALSE(ElementHasText(element));
+    const std::string blendingTypeStr(element->GetText());
+
+    if (blendingTypeStr == "multiband") {
+        *value = SurroundView2dParams::BlendingType::MULTIBAND;
+    } else if (blendingTypeStr == "alpha") {
+        *value = SurroundView2dParams::BlendingType::ALPHA;
+    } else {
+        LOG(ERROR) << "Unknown BlendingType specified: " << blendingTypeStr;
+        return false;
+    }
+    return true;
+}
+
+bool ReadSvConfig2d(const XMLElement* parent, SvConfig2d* sv2dConfig) {
+    RETURN_IF_FALSE(ReadValue(parent, "Sv2dEnabled", &sv2dConfig->sv2dEnabled));
+    if (!sv2dConfig->sv2dEnabled) {
+        return true;
+    }
+
+    SurroundView2dParams* sv2dParams = &sv2dConfig->sv2dParams;
+    const XMLElement* param2dElem = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, "Sv2dParams", &param2dElem));
+    {
+        // OutputResolution
+        const XMLElement* outputResolutionElem = nullptr;
+        RETURN_IF_FALSE(GetElement(param2dElem, "OutputResolution", &outputResolutionElem));
+        {
+            RETURN_IF_FALSE(
+                    ReadValue(outputResolutionElem, "Width", &sv2dParams->resolution.width));
+            RETURN_IF_FALSE(
+                    ReadValue(outputResolutionElem, "Height", &sv2dParams->resolution.height));
+        }
+
+        // GroundMapping
+        const XMLElement* groundMappingElem = nullptr;
+        RETURN_IF_FALSE(GetElement(param2dElem, "GroundMapping", &groundMappingElem));
+        {
+            RETURN_IF_FALSE(
+                    ReadValue(groundMappingElem, "Width", &sv2dParams->physical_size.width));
+            RETURN_IF_FALSE(
+                    ReadValue(groundMappingElem, "Height", &sv2dParams->physical_size.height));
+
+            // Center
+            const XMLElement* centerElem = nullptr;
+            RETURN_IF_FALSE(GetElement(groundMappingElem, "Center", &centerElem));
+            {
+                RETURN_IF_FALSE(ReadValue(centerElem, "X", &sv2dParams->physical_center.x));
+                RETURN_IF_FALSE(ReadValue(centerElem, "Y", &sv2dParams->physical_center.y));
+            }
+        }
+
+        // Car Bounding Box
+        const XMLElement* carBoundingBoxElem = nullptr;
+        RETURN_IF_FALSE(GetElement(param2dElem, "CarBoundingBox", &carBoundingBoxElem));
+        {
+            RETURN_IF_FALSE(
+                    ReadValue(carBoundingBoxElem, "Width", &sv2dConfig->carBoundingBox.width));
+            RETURN_IF_FALSE(
+                    ReadValue(carBoundingBoxElem, "Height", &sv2dConfig->carBoundingBox.height));
+
+            // Center
+            const XMLElement* leftTopCornerElem = nullptr;
+            RETURN_IF_FALSE(GetElement(carBoundingBoxElem, "LeftTopCorner", &leftTopCornerElem));
+            {
+                RETURN_IF_FALSE(ReadValue(leftTopCornerElem, "X", &sv2dConfig->carBoundingBox.x));
+                RETURN_IF_FALSE(ReadValue(leftTopCornerElem, "Y", &sv2dConfig->carBoundingBox.y));
+            }
+        }
+
+        // Blending type
+        const XMLElement* blendingTypeElem = nullptr;
+        RETURN_IF_FALSE(GetElement(param2dElem, "BlendingType", &blendingTypeElem));
+        {
+            RETURN_IF_FALSE(ReadValue2dBlendType(blendingTypeElem, "HighQuality",
+                                                 &sv2dParams->high_quality_blending));
+            RETURN_IF_FALSE(ReadValue2dBlendType(blendingTypeElem, "LowQuality",
+                                                 &sv2dParams->low_quality_blending));
+        }
+    }
+    return true;
+}
+
+bool ReadSvConfig3d(const XMLElement* parent, SvConfig3d* sv3dConfig) {
+    RETURN_IF_FALSE(ReadValue(parent, "Sv3dEnabled", &sv3dConfig->sv3dEnabled));
+    if (!sv3dConfig->sv3dEnabled) {
+        return true;
+    }
+    RETURN_IF_FALSE(ReadValue(parent, "Sv3dAnimationsEnabled", &sv3dConfig->sv3dAnimationsEnabled));
+
+    if (sv3dConfig->sv3dAnimationsEnabled) {
+        RETURN_IF_FALSE(ReadValue(parent, "CarModelConfigFile", &sv3dConfig->carModelConfigFile));
+    }
+
+    RETURN_IF_FALSE(ReadValue(parent, "CarModelObjFile", &sv3dConfig->carModelObjFile));
+
+    SurroundView3dParams* sv3dParams = &sv3dConfig->sv3dParams;
+    const XMLElement* param3dElem = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, "Sv3dParams", &param3dElem));
+    {
+        // OutputResolution
+        const XMLElement* outputResolutionElem = nullptr;
+        RETURN_IF_FALSE(GetElement(param3dElem, "OutputResolution", &outputResolutionElem));
+        {
+            RETURN_IF_FALSE(
+                    ReadValue(outputResolutionElem, "Width", &sv3dParams->resolution.width));
+            RETURN_IF_FALSE(
+                    ReadValue(outputResolutionElem, "Height", &sv3dParams->resolution.height));
+        }
+
+        // Bowl Params
+        const XMLElement* bowlParamsElem = nullptr;
+        RETURN_IF_FALSE(GetElement(param3dElem, "BowlParams", &bowlParamsElem));
+        {
+            RETURN_IF_FALSE(ReadValue(bowlParamsElem, "PlaneRadius", &sv3dParams->plane_radius));
+            RETURN_IF_FALSE(
+                    ReadValue(bowlParamsElem, "PlaneDivisions", &sv3dParams->plane_divisions));
+            RETURN_IF_FALSE(ReadValue(bowlParamsElem, "CurveHeight", &sv3dParams->curve_height));
+            RETURN_IF_FALSE(
+                    ReadValue(bowlParamsElem, "CurveDivisions", &sv3dParams->curve_divisions));
+            RETURN_IF_FALSE(
+                    ReadValue(bowlParamsElem, "AngularDivisions", &sv3dParams->angular_divisions));
+            RETURN_IF_FALSE(
+                    ReadValue(bowlParamsElem, "CurveCoefficient", &sv3dParams->curve_coefficient));
+        }
+
+        // High Quality details
+        const XMLElement* highQualityDetailsElem = nullptr;
+        GetElement(param3dElem, "HighQualityDetails", &highQualityDetailsElem);
+        {
+            RETURN_IF_FALSE(ReadValue(highQualityDetailsElem, "Shadows",
+                                      &sv3dParams->high_details_shadows));
+            RETURN_IF_FALSE(ReadValue(highQualityDetailsElem, "Reflections",
+                                      &sv3dParams->high_details_reflections));
+        }
+    }
+    return true;
+}
+
+bool ReadCameraConfig(const XMLElement* parent, CameraConfig* cameraConfig) {
+    const XMLElement* cameraConfigElem = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, "CameraConfig", &cameraConfigElem));
+    {
+        // Evs Group Id
+        RETURN_IF_FALSE(ReadValue(cameraConfigElem, "EvsGroupId", &cameraConfig->evsGroupId));
+
+        // Evs Cameras Ids
+        const XMLElement* cameraIdsElem = nullptr;
+        RETURN_IF_FALSE(GetElement(cameraConfigElem, "EvsCameraIds", &cameraIdsElem));
+        {
+            cameraConfig->evsCameraIds.resize(4);
+            RETURN_IF_FALSE(ReadValue(cameraIdsElem, "Front", &cameraConfig->evsCameraIds[0]));
+            RETURN_IF_FALSE(ReadValue(cameraIdsElem, "Right", &cameraConfig->evsCameraIds[1]));
+            RETURN_IF_FALSE(ReadValue(cameraIdsElem, "Rear", &cameraConfig->evsCameraIds[2]));
+            RETURN_IF_FALSE(ReadValue(cameraIdsElem, "Left", &cameraConfig->evsCameraIds[3]));
+        }
+
+        // Masks (Optional).
+        const XMLElement* masksElem = nullptr;
+        GetElement(cameraConfigElem, "Masks", &masksElem);
+        if (masksElem != nullptr) {
+            cameraConfig->maskFilenames.resize(4);
+            RETURN_IF_FALSE(ReadValue(masksElem, "Front", &cameraConfig->maskFilenames[0]));
+            RETURN_IF_FALSE(ReadValue(masksElem, "Right", &cameraConfig->maskFilenames[1]));
+            RETURN_IF_FALSE(ReadValue(masksElem, "Rear", &cameraConfig->maskFilenames[2]));
+            RETURN_IF_FALSE(ReadValue(masksElem, "Left", &cameraConfig->maskFilenames[3]));
+        }
+    }
+    return true;
+}
+
+}  // namespace
+
+IOStatus ReadSurroundViewConfig(const std::string& configFile, SurroundViewConfig* svConfig) {
+    XMLDocument xmlDoc;
+
+    // load and parse a configuration file
+    xmlDoc.LoadFile(configFile.c_str());
+    if (xmlDoc.ErrorID() != XML_SUCCESS) {
+        LOG(ERROR) << "Failed to load and/or parse a configuration file, " << xmlDoc.ErrorStr();
+        return IOStatus::ERROR_READ_CONFIG_FILE;
+    }
+
+    const XMLElement* rootElem = xmlDoc.RootElement();
+    if (strcmp(rootElem->Name(), "SurroundViewConfig")) {
+        LOG(ERROR) << "Config file is not in the required format: " << configFile;
+        return IOStatus::ERROR_READ_CONFIG_FILE;
+    }
+
+    // version
+    RETURN_ERROR_STATUS_IF_FALSE(ReadValue(rootElem, "Version", &svConfig->version));
+
+    // CameraConfig
+    RETURN_ERROR_STATUS_IF_FALSE(ReadCameraConfig(rootElem, &svConfig->cameraConfig));
+
+    // Surround View 2D
+    RETURN_ERROR_STATUS_IF_FALSE(ReadSvConfig2d(rootElem, &svConfig->sv2dConfig));
+
+    // Surround View 3D
+    RETURN_ERROR_STATUS_IF_FALSE(ReadSvConfig3d(rootElem, &svConfig->sv3dConfig));
+
+    return IOStatus::OK;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/ConfigReader.h b/surround_view/service-impl/ConfigReader.h
new file mode 100644
index 0000000..7bdbe2a
--- /dev/null
+++ b/surround_view/service-impl/ConfigReader.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SURROUND_VIEW_SERVICE_IMPL_CONFIGREADER_H_
+#define SURROUND_VIEW_SERVICE_IMPL_CONFIGREADER_H_
+
+#include <string>
+
+#include "IOModuleCommon.h"
+#include "core_lib.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+// Parses the surround view config xml into struct SurroundViewConfig.
+IOStatus ReadSurroundViewConfig(const std::string& configFile, SurroundViewConfig* svConfig);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // SURROUND_VIEW_SERVICE_IMPL_CONFIGREADER_H_
diff --git a/surround_view/service-impl/ConfigReaderTests.cpp b/surround_view/service-impl/ConfigReaderTests.cpp
new file mode 100644
index 0000000..ef51a5f
--- /dev/null
+++ b/surround_view/service-impl/ConfigReaderTests.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ConfigReaderTests"
+
+#include "ConfigReader.h"
+
+#include "core_lib.h"
+
+#include <gtest/gtest.h>
+#include <string>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+namespace {
+
+using android_auto::surround_view::SurroundView2dParams;
+using android_auto::surround_view::SurroundView3dParams;
+
+TEST(ConfigReaderTests, ReadConfigSuccess) {
+    SurroundViewConfig svConfig;
+    EXPECT_EQ(ReadSurroundViewConfig("/vendor/automotive/sv/sv_sample_config.xml", &svConfig),
+              IOStatus::OK);
+
+    EXPECT_EQ(svConfig.version, "1.0");
+
+    // Camera config
+    EXPECT_EQ(svConfig.cameraConfig.evsGroupId, "v4l2loopback_group0");
+
+    // Camera Ids
+    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[0], "/dev/video90");
+    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[1], "/dev/video91");
+    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[2], "/dev/video92");
+    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[3], "/dev/video93");
+
+    // Masks
+    EXPECT_EQ(svConfig.cameraConfig.maskFilenames.size(), 4);
+    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[0], "/vendor/mask_front.png");
+    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[1], "/vendor/mask_right.png");
+    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[2], "/vendor/mask_rear.png");
+    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[3], "/vendor/mask_left.png");
+
+    // Surround view 2D
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dEnabled, true);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.resolution.width, 600);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.resolution.height, 900);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.physical_size.width, 6.0);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.physical_size.height, 9.0);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.physical_center.x, 0.0);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.physical_center.y, 0.0);
+    EXPECT_EQ(svConfig.sv2dConfig.carBoundingBox.width, 2.0);
+    EXPECT_EQ(svConfig.sv2dConfig.carBoundingBox.height, 3.0);
+    EXPECT_EQ(svConfig.sv2dConfig.carBoundingBox.x, 1.0);
+    EXPECT_EQ(svConfig.sv2dConfig.carBoundingBox.y, 1.5);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.high_quality_blending,
+              SurroundView2dParams::BlendingType::MULTIBAND);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.low_quality_blending,
+              SurroundView2dParams::BlendingType::ALPHA);
+
+    // Surround view 3D
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dEnabled, true);
+    EXPECT_NE(svConfig.sv3dConfig.carModelConfigFile, "");
+    EXPECT_NE(svConfig.sv3dConfig.carModelObjFile, "");
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.plane_radius, 6.0);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.plane_divisions, 20);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.curve_height, 5.0);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.curve_divisions, 30);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.angular_divisions, 50);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.curve_coefficient, 2.0);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.high_details_shadows, true);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.high_details_reflections, true);
+}
+
+}  // namespace
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/ConfigReaderUtil.cpp b/surround_view/service-impl/ConfigReaderUtil.cpp
new file mode 100644
index 0000000..e5fe7c4
--- /dev/null
+++ b/surround_view/service-impl/ConfigReaderUtil.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConfigReaderUtil.h"
+
+#include <android-base/logging.h>
+#include <tinyxml2.h>
+#include <utility>
+
+#include "core_lib.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+using tinyxml2::XML_SUCCESS;
+using tinyxml2::XMLElement;
+
+bool ElementHasText(const XMLElement* element) {
+    if (element->GetText() == "") {
+        LOG(ERROR) << "Expected element to have text: " << element->Name();
+        return false;
+    }
+    return true;
+}
+
+bool GetElement(const XMLElement* parent, const char* elementName, XMLElement const** element) {
+    *element = parent->FirstChildElement(elementName);
+    if (*element == nullptr) {
+        LOG(ERROR) << "Expected element '" << elementName << "' in parent '" << parent->Name()
+                   << "' not found";
+        return false;
+    }
+    return true;
+}
+
+bool ReadValue(const XMLElement* parent, const char* elementName, bool* value) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    if (element->QueryBoolText(value) != XML_SUCCESS) {
+        LOG(ERROR) << "Failed to read valid boolean value from: " << element->Name();
+        return false;
+    }
+    return true;
+}
+
+bool ReadValue(const XMLElement* parent, const char* elementName, std::string* value) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    RETURN_IF_FALSE(ElementHasText(element));
+    *value = std::string(element->GetText());
+    return true;
+}
+
+bool ReadValue(const XMLElement* parent, const char* elementName, float* value) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    if (element->QueryFloatText(value) != XML_SUCCESS) {
+        LOG(ERROR) << "Failed to read valid float value from: " << element->Name();
+        return false;
+    }
+    return true;
+}
+
+bool ReadValue(const XMLElement* parent, const char* elementName, int* value) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    if (element->QueryIntText(value) != XML_SUCCESS) {
+        LOG(ERROR) << "Failed to read valid int value from: " << element->Name();
+        return false;
+    }
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/ConfigReaderUtil.h b/surround_view/service-impl/ConfigReaderUtil.h
new file mode 100644
index 0000000..030cc0f
--- /dev/null
+++ b/surround_view/service-impl/ConfigReaderUtil.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SURROUND_VIEW_SERVICE_IMPL_CONFIGREADERUTIL_H_
+#define SURROUND_VIEW_SERVICE_IMPL_CONFIGREADERUTIL_H_
+
+#include <tinyxml2.h>
+#include <sstream>
+#include <string>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+// Macro returning false if condition evaluates to false.
+#define RETURN_IF_FALSE(cond) \
+    do {                      \
+        if (!(cond)) {        \
+            return false;     \
+        }                     \
+    } while (0)
+
+// Returns true if element has text.
+bool ElementHasText(const tinyxml2::XMLElement* element);
+
+// Gets a xml element from the parent element, returns false if not found.
+bool GetElement(const tinyxml2::XMLElement* parent, const char* elementName,
+                tinyxml2::XMLElement const** element);
+
+// Reads a boolean value from a element, returns false if not found.
+bool ReadValue(const tinyxml2::XMLElement* parent, const char* elementName, bool* value);
+
+// Reads a string value from a element, returns false if not found.
+bool ReadValue(const tinyxml2::XMLElement* parent, const char* elementName, std::string* value);
+
+// Reads a float value from a element, returns false if not found.
+bool ReadValue(const tinyxml2::XMLElement* parent, const char* elementName, float* value);
+
+// Reads a int value from a element, returns false if not found.
+bool ReadValue(const tinyxml2::XMLElement* parent, const char* elementName, int* value);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // SURROUND_VIEW_SERVICE_IMPL_CONFIGREADERUTIL_H_
diff --git a/surround_view/service-impl/CoreLibSetupHelper.cpp b/surround_view/service-impl/CoreLibSetupHelper.cpp
new file mode 100644
index 0000000..4812efe
--- /dev/null
+++ b/surround_view/service-impl/CoreLibSetupHelper.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CoreLibSetupHelper.h"
+
+using namespace android_auto::surround_view;
+
+namespace android_auto {
+namespace surround_view {
+
+vector<SurroundViewCameraParams> GetCameras() {
+  std::vector<android_auto::surround_view::SurroundViewCameraParams> cameras;
+
+  // Camera 1.
+  {
+    android_auto::surround_view::SurroundViewCameraParams camera_params;
+
+    camera_params.intrinsics[0] = 608.0026093794693;
+    camera_params.intrinsics[1] = 0.0;
+    camera_params.intrinsics[2] = 968.699544102168;
+    camera_params.intrinsics[3] = 0.0;
+    camera_params.intrinsics[4] = 608.205469489769;
+    camera_params.intrinsics[5] = 476.38843298898996;
+    camera_params.intrinsics[6] = 0.0;
+    camera_params.intrinsics[7] = 0.0;
+    camera_params.intrinsics[8] = 1.0;
+
+    camera_params.distorion[0] = -0.03711481733589263;
+    camera_params.distorion[1] = -0.0014805627895442888;
+    camera_params.distorion[2] = -0.00030212056866592464;
+    camera_params.distorion[3] = -0.00020149538570397933;
+
+    camera_params.rvec[0] = 2.26308;
+    camera_params.rvec[1] = 0.0382788;
+    camera_params.rvec[2] = -0.0220549;
+
+    camera_params.tvec[0] = -7.8028875403817685e-02;
+    camera_params.tvec[1] = 1.4537396465103221e+00;
+    camera_params.tvec[2] = -8.4197165554645001e-02;
+
+    camera_params.size.width = 1920;
+    camera_params.size.height = 1024;
+
+    camera_params.circular_fov = 179;
+
+    cameras.push_back(camera_params);
+  }
+
+  // Camera 2.
+  {
+    android_auto::surround_view::SurroundViewCameraParams camera_params;
+
+    camera_params.intrinsics[0] = 607.8691721095306;
+    camera_params.intrinsics[1] = 0.0;
+    camera_params.intrinsics[2] = 975.5686146375716;
+    camera_params.intrinsics[3] = 0.0;
+    camera_params.intrinsics[4] = 608.0112887189435;
+    camera_params.intrinsics[5] = 481.1938786570715;
+    camera_params.intrinsics[6] = 0.0;
+    camera_params.intrinsics[7] = 0.0;
+    camera_params.intrinsics[8] = 1.0;
+
+    camera_params.distorion[0] = -0.040116809827977926;
+    camera_params.distorion[1] = 0.0028769489398543014;
+    camera_params.distorion[2] = -0.002651039958977229;
+    camera_params.distorion[3] = 0.00024260630476736675;
+
+    camera_params.rvec[0] = 1.67415;
+    camera_params.rvec[1] = -1.74075;
+    camera_params.rvec[2] = 0.789399;
+
+    camera_params.tvec[0] = 2.9715052384687407e-01;
+    camera_params.tvec[1] = 1.1407102692699396e+00;
+    camera_params.tvec[2] = 3.0074545273489206e-01;
+
+    camera_params.size.width = 1920;
+    camera_params.size.height = 1024;
+
+    camera_params.circular_fov = 179;
+
+    cameras.push_back(camera_params);
+  }
+
+  // Camera 3.
+  {
+    android_auto::surround_view::SurroundViewCameraParams camera_params;
+
+    camera_params.intrinsics[0] = 608.557299289448;
+    camera_params.intrinsics[1] = 0.0;
+    camera_params.intrinsics[2] = 960.1949354417656;
+    camera_params.intrinsics[3] = 0.0;
+    camera_params.intrinsics[4] = 608.8093878512448;
+    camera_params.intrinsics[5] = 474.74744054048256;
+    camera_params.intrinsics[6] = 0.0;
+    camera_params.intrinsics[7] = 0.0;
+    camera_params.intrinsics[8] = 1.0;
+
+    camera_params.distorion[0] = -0.03998488563470043;
+    camera_params.distorion[1] = 0.0024786686909103388;
+    camera_params.distorion[2] = -0.002354736769480817;
+    camera_params.distorion[3] = 0.00018369619088506146;
+
+    camera_params.rvec[0] = -0.106409;
+    camera_params.rvec[1] = -2.83697;
+    camera_params.rvec[2] = 1.28629;
+
+    camera_params.tvec[0] = 1.7115269161259747e-01;
+    camera_params.tvec[1] = 1.4376160762596599e+00;
+    camera_params.tvec[2] = -1.9028844233159006e-02;
+
+    camera_params.size.width = 1920;
+    camera_params.size.height = 1024;
+
+    camera_params.circular_fov = 179;
+
+    cameras.push_back(camera_params);
+  }
+
+  // Camera 4.
+  {
+    android_auto::surround_view::SurroundViewCameraParams camera_params;
+
+    camera_params.intrinsics[0] = 608.1221963545495;
+    camera_params.intrinsics[1] = 0.0;
+    camera_params.intrinsics[2] = 943.6280444638576;
+    camera_params.intrinsics[3] = 0.0;
+    camera_params.intrinsics[4] = 608.0523818661524;
+    camera_params.intrinsics[5] = 474.8564698210861;
+    camera_params.intrinsics[6] = 0.0;
+    camera_params.intrinsics[7] = 0.0;
+    camera_params.intrinsics[8] = 1.0;
+
+    camera_params.distorion[0] = -0.038096507459563965;
+    camera_params.distorion[1] = 0.0004008114278766646;
+    camera_params.distorion[2] = -0.0013549275607082035;
+    camera_params.distorion[3] = -5.9961182248325556e-06;
+
+    camera_params.rvec[0] = 1.63019;
+    camera_params.rvec[1] = 1.76475;
+    camera_params.rvec[2] = -0.827941;
+
+    camera_params.tvec[0] = -3.0842691427126512e-01;
+    camera_params.tvec[1] = 1.0884122033556984e+00;
+    camera_params.tvec[2] = 3.4419058255954926e-01;
+
+    camera_params.size.width = 1920;
+    camera_params.size.height = 1024;
+
+    camera_params.circular_fov = 179;
+
+    cameras.push_back(camera_params);
+  }
+  return cameras;
+
+}
+
+SurroundView2dParams Get2dParams() {
+  android_auto::surround_view::Size2dInteger
+      resolution{ /*width=*/ 1024, /*height*/ 768};
+  // make sure resolution has the same ratio with physical_size.
+  // {480 *360 }
+  android_auto::surround_view::Size2dFloat physical_size{8.0, 6.0};
+  android_auto::surround_view::Coordinate2dFloat physical_center{0, 0};
+
+  return android_auto::surround_view::SurroundView2dParams(
+      resolution, physical_size, physical_center);
+}
+
+SurroundView3dParams Get3dParams() {
+  return android_auto::surround_view::SurroundView3dParams(
+      /*plane_radius=*/ 8.0f,
+      /*plane_divisions=*/ 50,
+      /*curve_height=*/ 6.0f,
+      /*curve_divisions=*/ 50,
+      /*angular_divisions=*/ 90,
+      /*curve_coefficient=*/ 3.0f,
+      /*resolution=*/ Size2dInteger(1024, 768));
+}
+
+BoundingBox GetBoundingBox() {
+  return android_auto::surround_view::BoundingBox(
+      /*x=*/ -0.01f,
+      /*y=*/ 0.01f,
+      /*width=*/ 0.01f,
+      /*height=*/ 0.01f);
+}
+
+vector<float> GetUndistortionScales() {
+  return vector<float>{1.0f, 1.0f, 1.0f, 1.0f};
+}
+
+
+} // namespace surround_view
+} // namespace audroid_auto
+
diff --git a/surround_view/service-impl/CoreLibSetupHelper.h b/surround_view/service-impl/CoreLibSetupHelper.h
new file mode 100644
index 0000000..889ebf2
--- /dev/null
+++ b/surround_view/service-impl/CoreLibSetupHelper.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+#include "core_lib.h"
+
+using namespace std;
+
+// TODO(b/150412555): The helper method should only be used for testing
+// purposes once EVS camera is used.
+namespace android_auto {
+namespace surround_view {
+
+vector<SurroundViewCameraParams> GetCameras();
+
+SurroundView2dParams Get2dParams();
+
+SurroundView3dParams Get3dParams();
+
+BoundingBox GetBoundingBox();
+
+vector<float> GetUndistortionScales();
+
+}  // namespace surround_view
+}  // namespace android_auto
+
diff --git a/surround_view/service-impl/IOModule.cpp b/surround_view/service-impl/IOModule.cpp
new file mode 100644
index 0000000..e1af11a
--- /dev/null
+++ b/surround_view/service-impl/IOModule.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include "CarModelConfigReader.h"
+#include "ConfigReader.h"
+#include "IOModule.h"
+#include "ObjReader.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+IOModule::IOModule(const std::string& svConfigFile) :
+      mSvConfigFile(svConfigFile), mIsInitialized(false) {}
+
+IOStatus IOModule::initialize() {
+    if (mIsInitialized) {
+        LOG(INFO) << "IOModule is already initialized.";
+        return IOStatus::OK;
+    }
+
+    SurroundViewConfig svConfig;
+    IOStatus status;
+    if ((status = ReadSurroundViewConfig(mSvConfigFile, &svConfig)) != IOStatus::OK) {
+        LOG(ERROR) << "ReadSurroundViewConfig() failed.";
+        return status;
+    }
+
+    mIOModuleConfig.cameraConfig = svConfig.cameraConfig;
+    mIOModuleConfig.sv2dConfig = svConfig.sv2dConfig;
+    mIOModuleConfig.sv3dConfig = svConfig.sv3dConfig;
+
+    if (mIOModuleConfig.sv3dConfig.sv3dEnabled) {
+        // Read obj and mtl files.
+        if (!ReadObjFromFile(svConfig.sv3dConfig.carModelObjFile,
+                             &mIOModuleConfig.carModelConfig.carModel.partsMap)) {
+            LOG(ERROR) << "ReadObjFromFile() failed.";
+            return IOStatus::ERROR_READ_CAR_MODEL;
+        }
+        // Read animations.
+        if (mIOModuleConfig.sv3dConfig.sv3dAnimationsEnabled) {
+            if ((status = ReadCarModelConfig(svConfig.sv3dConfig.carModelConfigFile,
+                                             &mIOModuleConfig.carModelConfig.animationConfig)) !=
+                IOStatus::OK) {
+                LOG(ERROR) << "ReadObjFromFile() failed.";
+                return status;
+            }
+        }
+    }
+    mIsInitialized = true;
+    return IOStatus::OK;
+}
+
+bool IOModule::getConfig(IOModuleConfig* ioModuleConfig) {
+    if (!mIsInitialized) {
+        LOG(ERROR) << "IOModule not initalized.";
+        return false;
+    }
+    *ioModuleConfig = mIOModuleConfig;
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/IOModule.h b/surround_view/service-impl/IOModule.h
new file mode 100644
index 0000000..2e19dc5
--- /dev/null
+++ b/surround_view/service-impl/IOModule.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef SURROUND_VIEW_SERVICE_IMPL_IOMODULE_H_
+#define SURROUND_VIEW_SERVICE_IMPL_IOMODULE_H_
+
+#include "IOModuleCommon.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+// I/O Module class processing all I/O related operations.
+class IOModule {
+public:
+    // Constructor with file name( and path) of config file.
+    IOModule(const std::string& svConfigFile);
+
+    // Reads all config files and stores parsed results in mIOModuleConfig.
+    IOStatus initialize();
+
+    // Gets config data read from files. initialize must be called this.
+    bool getConfig(IOModuleConfig* ioModuleConfig);
+
+private:
+    // Config string filename.
+    std::string mSvConfigFile;
+
+    // Indicates initialize success/fail.
+    bool mIsInitialized;
+
+    // Stores the parsed config.
+    IOModuleConfig mIOModuleConfig;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+#endif  // SURROUND_VIEW_SERVICE_IMPL_IOMODULE_H_
diff --git a/surround_view/service-impl/IOModuleCommon.h b/surround_view/service-impl/IOModuleCommon.h
new file mode 100644
index 0000000..5550fd5
--- /dev/null
+++ b/surround_view/service-impl/IOModuleCommon.h
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SURROUND_VIEW_SERVICE_IMPL_IOMODULECOMMON_H_
+#define SURROUND_VIEW_SERVICE_IMPL_IOMODULECOMMON_H_
+
+#include <string>
+
+#include "core_lib.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+// Struct for camera related configurations.
+// Note: Does not include camera intrinsics and extrinsics, these are specified in EVS metadata.
+struct CameraConfig {
+    // Id of logical group containing surronnd view cameras.
+    std::string evsGroupId;
+
+    // List of evs camera Ids  in order: front, right, rear, left.
+    std::vector<std::string> evsCameraIds;
+
+    // In order: front, right, rear, left.
+    std::vector<std::string> maskFilenames;
+};
+
+struct SvConfig2d {
+    // Bool flag for surround view 2d.
+    bool sv2dEnabled;
+
+    // Surround view 2d params.
+    android_auto::surround_view::SurroundView2dParams sv2dParams;
+
+    // Car model bounding box for 2d surround view.
+    // To be moved into sv 2d params.
+    android_auto::surround_view::BoundingBox carBoundingBox;
+};
+
+struct SvConfig3d {
+    // Bool flag for enabling/disabling surround view 3d.
+    bool sv3dEnabled;
+
+    // Bool flag for enabling/disabling animations.
+    bool sv3dAnimationsEnabled;
+
+    // Car model config file.
+    std::string carModelConfigFile;
+
+    // Car model obj file.
+    std::string carModelObjFile;
+
+    // Surround view 3d params.
+    android_auto::surround_view::SurroundView3dParams sv3dParams;
+};
+
+// Main struct in which surround view config is parsed into.
+struct SurroundViewConfig {
+    // Version info.
+    std::string version;
+
+    // Camera config.
+    CameraConfig cameraConfig;
+
+    // Surround view 2d config.
+    SvConfig2d sv2dConfig;
+
+    // Surround view 3d config.
+    SvConfig3d sv3dConfig;
+};
+
+struct Range {
+    // Range start.
+    // Start value may be greater than end value.
+    float start;
+
+    // Range end.
+    float end;
+};
+
+// Rotation axis
+struct RotationAxis {
+    // Unit axis direction vector.
+    std::array<float, 3> axisVector;
+
+    // Rotate about this point.
+    std::array<float, 3> rotationPoint;
+};
+
+enum AnimationType {
+    // Rotate a part about an axis from a start to end angle.
+    ROTATION_ANGLE = 0,
+
+    // Continuously rotate a part about an axis by a specified angular speed.
+    ROTATION_SPEED = 1,
+
+    // Linearly translates a part from one point to another.
+    TRANSLATION = 2,
+
+    // Switch to another texture once.
+    SWITCH_TEXTURE_ONCE = 3,
+
+    // Adjust the brightness of the texture once.
+    ADJUST_GAMMA_ONCE = 4,
+
+    // Repeatedly toggle between two textures.
+    SWITCH_TEXTURE_REPEAT = 5,
+
+    // Repeatedly toggle between two gamma values.
+    ADJUST_GAMMA_REPEAT = 6,
+};
+
+// Rotation operation
+struct RotationOp {
+    // VHAL signal to trigger operation.
+    uint64_t vhalProperty;
+
+    // Rotation operation type.
+    AnimationType type;
+
+    // Rotation axis.
+    RotationAxis axis;
+
+    // Default rotation (angle/speed) value.
+    // It is used for default rotation when the signal is on while vhal_range is
+    // not provided.
+    float defaultRotationValue;
+
+    // Default animation time elapsed to finish the rotation operation.
+    // It is ignored if VHAL provides continuous signal value.
+    float animationTime;
+
+    // physical rotation range with start mapped to vhal_range start and
+    // end mapped to vhal_range end.
+    Range rotationRange;
+
+    // VHAL signal range.
+    // Un-supported types: STRING, BYTES and VEC
+    // Refer:  hardware/interfaces/automotive/vehicle/2.0/types.hal
+    // VehiclePropertyType
+    Range vhalRange;
+};
+
+// Translation operation.
+struct TranslationOp {
+    // VHAL signal to trigger operation.
+    uint64_t vhalProperty;
+
+    // Translation operation type.
+    AnimationType type;
+
+    // Unit direction vector.
+    std::array<float, 3> direction;
+
+    // Default translation value.
+    // It is used for default translation when the signal is on while vhal_range
+    // is not provided.
+    float defaultTranslationValue;
+
+    // Default animation time elapsed to finish the texture operation.
+    // It is ignored if VHAL provides continuous signal value.
+    float animationTime;
+
+    // Physical translation range with start mapped to vhal_range start and
+    // end mapped to vhal_range end.
+    Range translationRange;
+
+    // VHAL signal range.
+    // Un-supported types: STRING, BYTES and VEC
+    // Refer:  hardware/interfaces/automotive/vehicle/2.0/types.hal
+    // VehiclePropertyType
+    Range vhalRange;
+};
+
+// Texture operation.
+struct TextureOp {
+    // VHAL signal to trigger operation.
+    uint64_t vhalProperty;
+
+    // Texture operation type.
+    AnimationType type;
+
+    // Default texture id.
+    // It is used as default texture when the signal is on while vhal_range is
+    // not provided.
+    std::string defaultTexture;
+
+    // Default animation time elapsed to finish the texture operation.
+    // Unit is milliseconds.
+    // If the animation time is specified, the vhal_property is assumed to be
+    // on/off type.
+    // It is ignored if it is equal or less than zero and vhal_property is
+    // assumed to provide continuous value.
+    int animationTime;
+
+    // texture range mapped to texture_ids[i].first.
+    Range textureRange;
+
+    // VHAL signal range.
+    // Un-supported types: STRING, BYTES and VEC
+    // Refer:  hardware/interfaces/automotive/vehicle/2.0/types.hal
+    // VehiclePropertyType
+    Range vhalRange;
+
+    // Texture ids for switching textures.
+    // Applicable for animation types: kSwitchTextureOnce and
+    // kSwitchTextureRepeated
+    // 0 - n-1
+    std::vector<std::pair<float, std::string>> textureIds;
+};
+
+// Gamma operation.
+struct GammaOp {
+    // VHAL signal to trigger operation.
+    uint64_t vhalProperty;
+
+    // Texture operation type.
+    // Applicable for animation types: kAdjustGammaOnce and kAdjustGammaRepeat.
+    AnimationType type;
+
+    // Default animation time elapsed to finish the gamma operation.
+    // Unit is milliseconds.
+    // If the animation time is specified, the vhal_property is assumed to be
+    // on/off type.
+    // It is ignored if it is equal or less than zero and vhal_property is
+    // assumed to provide continuous value.
+    int animationTime;
+
+    // Gamma range with start mapped to vhal_range start and
+    // end mapped to vhal_range end.
+    Range gammaRange;
+
+    // VHAL signal range.
+    // Un-supported types: STRING, BYTES and VEC
+    // Refer:  hardware/interfaces/automotive/vehicle/2.0/types.hal
+    // VehiclePropertyType
+    Range vhalRange;
+};
+
+// Animation info of a car part
+struct AnimationInfo {
+    // Car animation part id(name). It is a unique id.
+    std::string partId;
+
+    // Car part parent name.
+    std::string parentId;
+
+    // List of child Ids.
+    std::vector<std::string> childIds;
+
+    // Car part pose w.r.t parent's coordinate.
+    android_auto::surround_view::Mat4x4 pose;
+
+    // VHAL priority from high [0] to low [n-1]. Only VHALs specified in the
+    // vector have priority.
+    std::vector<uint64_t> vhalPriority;
+
+    // TODO(b/158245554): simplify xxOpsMap data structs.
+    // Map of gamma operations. Key value is VHAL property.
+    std::map<uint64_t, std::vector<GammaOp>> gammaOpsMap;
+
+    // Map of texture operations. Key value is VHAL property.
+    std::map<uint64_t, std::vector<TextureOp>> textureOpsMap;
+
+    // Map of rotation operations. Key value is VHAL property.
+    // Multiple rotation ops are supported and will be simultaneously animated in
+    // order if their rotation axis are different and rotation points are the
+    // same.
+    std::map<uint64_t, std::vector<RotationOp>> rotationOpsMap;
+
+    // Map of translation operations. Key value is VHAL property.
+    std::map<uint64_t, std::vector<TranslationOp>> translationOpsMap;
+};
+
+// Main struct in which surround view car model config is parsed into.
+struct AnimationConfig {
+    std::string version;
+
+    std::vector<AnimationInfo> animations;
+};
+
+// Car model.
+struct CarModel {
+    // Car model parts map.
+    std::map<std::string, android_auto::surround_view::CarPart> partsMap;
+
+    // Car testures map.
+    std::map<std::string, android_auto::surround_view::CarTexture> texturesMap;
+};
+
+struct CarModelConfig {
+    CarModel carModel;
+
+    AnimationConfig animationConfig;
+};
+
+struct IOModuleConfig {
+    // Camera config.
+    CameraConfig cameraConfig;
+
+    // Surround view 2d config.
+    SvConfig2d sv2dConfig;
+
+    // Surround view 3d config.
+    SvConfig3d sv3dConfig;
+
+    // Car model config.
+    CarModelConfig carModelConfig;
+};
+
+enum IOStatus : uint8_t {
+    // OK ststus. ALL fields read and parsed.
+    OK = 0,
+
+    // Error status. Cannot read the config file (config file missing or not
+    // accessible)
+    ERROR_READ_CONFIG_FILE = 1,
+
+    // Error ststus. Config file format doesn't match.
+    ERROR_CONFIG_FILE_FORMAT = 2,
+
+    // Warning status. Read car model (obj, mtl) error. Either the files are
+    // missing or wrong format.
+    ERROR_READ_CAR_MODEL = 3,
+
+    // Warning status. Read animation config file error. Either the file is
+    // missing or wrong format.
+    ERROR_READ_ANIMATION = 4,
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // SURROUND_VIEW_SERVICE_IMPL_IOMODULECOMMON_H_
diff --git a/surround_view/service-impl/MathHelp.h b/surround_view/service-impl/MathHelp.h
new file mode 100644
index 0000000..6623594
--- /dev/null
+++ b/surround_view/service-impl/MathHelp.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SURROUND_VIEW_SERVICE_IMPL_MATH_HELP_H_
+#define SURROUND_VIEW_SERVICE_IMPL_MATH_HELP_H_
+
+#include "Matrix4x4.h"
+#include "core_lib.h"
+
+#include <android-base/logging.h>
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+using android_auto::surround_view::Mat4x4;
+
+const int gMat4Size = 4 * 4 * sizeof(float);
+
+const Mat4x4 gMat4Identity = {1, 0, 0, /*tx=*/0.0, 0, 1, 0, /*ty=*/0,
+                              0, 0, 1, /*tz=*/0.0, 0, 0, 0, 1};
+
+inline float degToRad(float angleInDegrees) {
+    return 1.0f * angleInDegrees / 180 * M_PI;
+}
+
+typedef std::array<float, 3> VectorT;
+typedef std::array<float, 4> HomVectorT;
+typedef Matrix4x4<float> HomMatrixT;
+
+// Create a Translation matrix.
+inline HomMatrixT translationMatrix(const VectorT& v) {
+    HomMatrixT m = HomMatrixT::identity();
+    m.setRow(3, HomVectorT{v[0], v[1], v[2], 1});
+    return m;
+}
+
+// Create a Rotation matrix.
+inline HomMatrixT rotationMatrix(const VectorT& v, float angle, int orientation) {
+    const float c = cos(angle);
+    const float s = orientation * sin(angle);
+    const float t = 1 - c;
+    const float tx = t * v[0];
+    const float ty = t * v[1];
+    const float tz = t * v[2];
+    return HomMatrixT(tx * v[0] + c, tx * v[1] + s * v[2], tx * v[2] - s * v[1], 0,
+                      tx * v[1] - s * v[2], ty * v[1] + c, ty * v[2] + s * v[0], 0,
+                      tx * v[2] + s * v[1], ty * v[2] - s * v[0], tz * v[2] + c, 0, 0, 0, 0, 1);
+}
+
+inline Mat4x4 toMat4x4(const Matrix4x4F& matrix4x4F) {
+    Mat4x4 mat4x4;
+    memcpy(&mat4x4[0], matrix4x4F.transpose().data(), gMat4Size);
+    return mat4x4;
+}
+
+inline Matrix4x4F toMatrix4x4F(const Mat4x4& mat4x4) {
+    Matrix4x4F matrix4x4F;
+    memcpy(matrix4x4F.data(), &mat4x4[0], gMat4Size);
+
+    for (int i = 0; i < 4; i++) {
+        for (int j = 0; j < 4; j++) {
+            if (matrix4x4F(i, j) != mat4x4[i * 4 + j]) {
+                LOG(ERROR) << "Matrix error";
+            }
+        }
+    }
+    return matrix4x4F.transpose();
+}
+
+// Create a Rotation Matrix, around a unit vector by a ccw angle.
+inline Mat4x4 rotationMatrix(float angleInDegrees, const VectorT& axis) {
+    return toMat4x4(rotationMatrix(axis, degToRad(angleInDegrees), 1));
+}
+
+inline Mat4x4 appendRotation(float angleInDegrees, const VectorT& axis, const Mat4x4& mat4) {
+    return toMat4x4(toMatrix4x4F(mat4) * rotationMatrix(axis, degToRad(angleInDegrees), 1));
+}
+
+// Append mat_l * mat_r;
+inline Mat4x4 appendMat(const Mat4x4& matL, const Mat4x4& matR) {
+    return toMat4x4(toMatrix4x4F(matL) * toMatrix4x4F(matR));
+}
+
+// Rotate about a point about a unit vector.
+inline Mat4x4 rotationAboutPoint(float angleInDegrees, const VectorT& point, const VectorT& axis) {
+    VectorT pointInv = point;
+    pointInv[0] *= -1;
+    pointInv[1] *= -1;
+    pointInv[2] *= -1;
+    return toMat4x4(translationMatrix(pointInv) *
+                    rotationMatrix(axis, degToRad(angleInDegrees), 1) * translationMatrix(point));
+}
+
+inline Mat4x4 translationMatrixToMat4x4(const VectorT& translation) {
+    return toMat4x4(translationMatrix(translation));
+}
+
+inline Mat4x4 appendTranslation(const VectorT& translation, const Mat4x4& mat4) {
+    return toMat4x4(toMatrix4x4F(mat4) * translationMatrix(translation));
+}
+
+inline Mat4x4 appendMatrix(const Mat4x4& deltaMatrix, const Mat4x4& currentMatrix) {
+    return toMat4x4(toMatrix4x4F(deltaMatrix) * toMatrix4x4F(currentMatrix));
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // SURROUND_VIEW_SERVICE_IMPL_MATH_HELP_H_
diff --git a/surround_view/service-impl/Matrix4x4.h b/surround_view/service-impl/Matrix4x4.h
new file mode 100644
index 0000000..8854e69
--- /dev/null
+++ b/surround_view/service-impl/Matrix4x4.h
@@ -0,0 +1,397 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SURROUND_VIEW_SERVICE_IMPL_MATRIX4X4_H_
+#define SURROUND_VIEW_SERVICE_IMPL_MATRIX4X4_H_
+
+#include <array>
+#include <cassert>
+#include <cmath>
+#include <iosfwd>
+
+template <class VType>
+class Matrix4x4 {
+private:
+    VType m[4][4];
+
+public:
+    typedef Matrix4x4<VType> Self;
+    typedef VType BaseType;
+    typedef std::array<VType, 4> MVector;
+
+    // Initialize the matrix to 0
+    Matrix4x4() {
+        m[0][3] = m[0][2] = m[0][1] = m[0][0] = VType();
+        m[1][3] = m[1][2] = m[1][1] = m[1][0] = VType();
+        m[2][3] = m[2][2] = m[2][1] = m[2][0] = VType();
+        m[3][3] = m[3][2] = m[3][1] = m[3][0] = VType();
+    }
+
+    // Explicitly set every element on construction
+    Matrix4x4(const VType& m00, const VType& m01, const VType& m02, const VType& m03,
+              const VType& m10, const VType& m11, const VType& m12, const VType& m13,
+              const VType& m20, const VType& m21, const VType& m22, const VType& m23,
+              const VType& m30, const VType& m31, const VType& m32, const VType& m33) {
+        m[0][0] = m00;
+        m[0][1] = m01;
+        m[0][2] = m02;
+        m[0][3] = m03;
+
+        m[1][0] = m10;
+        m[1][1] = m11;
+        m[1][2] = m12;
+        m[1][3] = m13;
+
+        m[2][0] = m20;
+        m[2][1] = m21;
+        m[2][2] = m22;
+        m[2][3] = m23;
+
+        m[3][0] = m30;
+        m[3][1] = m31;
+        m[3][2] = m32;
+        m[3][3] = m33;
+    }
+
+    // Casting constructor
+    template <class VType2>
+    static Matrix4x4 cast(const Matrix4x4<VType2>& mb) {
+        return Matrix4x4(static_cast<VType>(mb(0, 0)), static_cast<VType>(mb(0, 1)),
+                         static_cast<VType>(mb(0, 2)), static_cast<VType>(mb(0, 3)),
+                         static_cast<VType>(mb(1, 0)), static_cast<VType>(mb(1, 1)),
+                         static_cast<VType>(mb(1, 2)), static_cast<VType>(mb(1, 3)),
+                         static_cast<VType>(mb(2, 0)), static_cast<VType>(mb(2, 1)),
+                         static_cast<VType>(mb(2, 2)), static_cast<VType>(mb(2, 3)),
+                         static_cast<VType>(mb(3, 0)), static_cast<VType>(mb(3, 1)),
+                         static_cast<VType>(mb(3, 2)), static_cast<VType>(mb(3, 3)));
+    }
+
+    // Change the value of all the coefficients of the matrix
+    inline Matrix4x4& set(const VType& m00, const VType& m01, const VType& m02, const VType& m03,
+                          const VType& m10, const VType& m11, const VType& m12, const VType& m13,
+                          const VType& m20, const VType& m21, const VType& m22, const VType& m23,
+                          const VType& m30, const VType& m31, const VType& m32, const VType& m33) {
+        m[0][0] = m00;
+        m[0][1] = m01;
+        m[0][2] = m02;
+        m[0][3] = m03;
+
+        m[1][0] = m10;
+        m[1][1] = m11;
+        m[1][2] = m12;
+        m[1][3] = m13;
+
+        m[2][0] = m20;
+        m[2][1] = m21;
+        m[2][2] = m22;
+        m[2][3] = m23;
+
+        m[3][0] = m30;
+        m[3][1] = m31;
+        m[3][2] = m32;
+        m[3][3] = m33;
+        return (*this);
+    }
+
+    // Matrix addition
+    inline Matrix4x4& operator+=(const Matrix4x4& addFrom) {
+        m[0][0] += addFrom.m[0][0];
+        m[0][1] += addFrom.m[0][1];
+        m[0][2] += addFrom.m[0][2];
+        m[0][3] += addFrom.m[0][3];
+
+        m[1][0] += addFrom.m[1][0];
+        m[1][1] += addFrom.m[1][1];
+        m[1][2] += addFrom.m[1][2];
+        m[1][3] += addFrom.m[1][3];
+
+        m[2][0] += addFrom.m[2][0];
+        m[2][1] += addFrom.m[2][1];
+        m[2][2] += addFrom.m[2][2];
+        m[2][3] += addFrom.m[2][3];
+
+        m[3][0] += addFrom.m[3][0];
+        m[3][1] += addFrom.m[3][1];
+        m[3][2] += addFrom.m[3][2];
+        m[3][3] += addFrom.m[3][3];
+        return (*this);
+    }
+
+    // Matrix subtration
+    inline Matrix4x4& operator-=(const Matrix4x4& subFrom) {
+        m[0][0] -= subFrom.m[0][0];
+        m[0][1] -= subFrom.m[0][1];
+        m[0][2] -= subFrom.m[0][2];
+        m[0][3] -= subFrom.m[0][3];
+
+        m[1][0] -= subFrom.m[1][0];
+        m[1][1] -= subFrom.m[1][1];
+        m[1][2] -= subFrom.m[1][2];
+        m[1][3] -= subFrom.m[1][3];
+
+        m[2][0] -= subFrom.m[2][0];
+        m[2][1] -= subFrom.m[2][1];
+        m[2][2] -= subFrom.m[2][2];
+        m[2][3] -= subFrom.m[2][3];
+
+        m[3][0] -= subFrom.m[3][0];
+        m[3][1] -= subFrom.m[3][1];
+        m[3][2] -= subFrom.m[3][2];
+        m[3][3] -= subFrom.m[3][3];
+        return (*this);
+    }
+
+    // Matrix multiplication by a scalar
+    inline Matrix4x4& operator*=(const VType& k) {
+        m[0][0] *= k;
+        m[0][1] *= k;
+        m[0][2] *= k;
+        m[0][3] *= k;
+
+        m[1][0] *= k;
+        m[1][1] *= k;
+        m[1][2] *= k;
+        m[1][3] *= k;
+
+        m[2][0] *= k;
+        m[2][1] *= k;
+        m[2][2] *= k;
+        m[2][3] *= k;
+
+        m[3][0] *= k;
+        m[3][1] *= k;
+        m[3][2] *= k;
+        m[3][3] *= k;
+        return (*this);
+    }
+
+    // Matrix addition
+    inline Matrix4x4 operator+(const Matrix4x4& mb) const { return Matrix4x4(*this) += mb; }
+
+    // Matrix subtraction
+    inline Matrix4x4 operator-(const Matrix4x4& mb) const { return Matrix4x4(*this) -= mb; }
+
+    // Change the sign of all the coefficients in the matrix
+    friend inline Matrix4x4 operator-(const Matrix4x4& vb) {
+        return Matrix4x4(-vb.m[0][0], -vb.m[0][1], -vb.m[0][2], -vb.m[0][3], -vb.m[1][0],
+                         -vb.m[1][1], -vb.m[1][2], -vb.m[1][3], -vb.m[2][0], -vb.m[2][1],
+                         -vb.m[2][2], -vb.m[2][3], -vb.m[3][0], -vb.m[3][1], -vb.m[3][2],
+                         -vb.m[3][3]);
+    }
+
+    // Matrix multiplication by a scalar
+    inline Matrix4x4 operator*(const VType& k) const { return Matrix4x4(*this) *= k; }
+
+    // Multiplication by a scaler
+    friend inline Matrix4x4 operator*(const VType& k, const Matrix4x4& mb) {
+        return Matrix4x4(mb) * k;
+    }
+
+    // Matrix multiplication
+    friend Matrix4x4 operator*(const Matrix4x4& a, const Matrix4x4& b) {
+        return Matrix4x4::fromCols(a * b.col(0), a * b.col(1), a * b.col(2), a * b.col(3));
+    }
+
+    // Multiplication of a matrix by a vector
+    friend MVector operator*(const Matrix4x4& a, const MVector& b) {
+        return MVector{dotProd(a.row(0), b), dotProd(a.row(1), b), dotProd(a.row(2), b),
+                       dotProd(a.row(3), b)};
+    }
+
+    // Return the trace of the matrix
+    inline VType trace() const { return m[0][0] + m[1][1] + m[2][2] + m[3][3]; }
+
+    // Return a pointer to the data array for interface with other libraries
+    // like opencv
+    VType* data() { return reinterpret_cast<VType*>(m); }
+    const VType* data() const { return reinterpret_cast<const VType*>(m); }
+
+    // Return matrix element (i,j) with 0<=i<=3 0<=j<=3
+    inline VType& operator()(const int i, const int j) {
+        assert(i >= 0);
+        assert(i < 4);
+        assert(j >= 0);
+        assert(j < 4);
+        return m[i][j];
+    }
+
+    inline VType operator()(const int i, const int j) const {
+        assert(i >= 0);
+        assert(i < 4);
+        assert(j >= 0);
+        assert(j < 4);
+        return m[i][j];
+    }
+
+    // Return matrix element (i/4,i%4) with 0<=i<=15 (access concatenated rows).
+    inline VType& operator[](const int i) {
+        assert(i >= 0);
+        assert(i < 16);
+        return reinterpret_cast<VType*>(m)[i];
+    }
+    inline VType operator[](const int i) const {
+        assert(i >= 0);
+        assert(i < 16);
+        return reinterpret_cast<const VType*>(m)[i];
+    }
+
+    // Return the transposed matrix
+    inline Matrix4x4 transpose() const {
+        return Matrix4x4(m[0][0], m[1][0], m[2][0], m[3][0], m[0][1], m[1][1], m[2][1], m[3][1],
+                         m[0][2], m[1][2], m[2][2], m[3][2], m[0][3], m[1][3], m[2][3], m[3][3]);
+    }
+
+    // Returns the transpose of the matrix of the cofactors.
+    // (Useful for inversion for example.)
+    inline Matrix4x4 comatrixTransposed() const {
+        const auto cof = [this](unsigned int row, unsigned int col) {
+            unsigned int r0 = (row + 1) % 4;
+            unsigned int r1 = (row + 2) % 4;
+            unsigned int r2 = (row + 3) % 4;
+            unsigned int c0 = (col + 1) % 4;
+            unsigned int c1 = (col + 2) % 4;
+            unsigned int c2 = (col + 3) % 4;
+
+            VType minor = m[r0][c0] * (m[r1][c1] * m[r2][c2] - m[r2][c1] * m[r1][c2]) -
+                    m[r1][c0] * (m[r0][c1] * m[r2][c2] - m[r2][c1] * m[r0][c2]) +
+                    m[r2][c0] * (m[r0][c1] * m[r1][c2] - m[r1][c1] * m[r0][c2]);
+            return (row + col) & 1 ? -minor : minor;
+        };
+
+        // Transpose
+        return Matrix4x4(cof(0, 0), cof(1, 0), cof(2, 0), cof(3, 0), cof(0, 1), cof(1, 1),
+                         cof(2, 1), cof(3, 1), cof(0, 2), cof(1, 2), cof(2, 2), cof(3, 2),
+                         cof(0, 3), cof(1, 3), cof(2, 3), cof(3, 3));
+    }
+
+    // Return dot production of two the vectors
+    static inline VType dotProd(const MVector& lhs, const MVector& rhs) {
+        return lhs[0] * rhs[0] + lhs[1] * rhs[1] + lhs[2] * rhs[2] + lhs[3] * rhs[3];
+    }
+
+    // Return the 4D vector at row i
+    inline MVector row(const int i) const {
+        assert(i >= 0);
+        assert(i < 4);
+        return MVector{m[i][0], m[i][1], m[i][2], m[i][3]};
+    }
+
+    // Return the 4D vector at col i
+    inline MVector col(const int i) const {
+        assert(i >= 0);
+        assert(i < 4);
+        return MVector{m[0][i], m[1][i], m[2][i], m[3][i]};
+    }
+
+    // Create a matrix from 4 row vectors
+    static inline Matrix4x4 fromRows(const MVector& v1, const MVector& v2, const MVector& v3,
+                                     const MVector& v4) {
+        return Matrix4x4(v1[0], v1[1], v1[2], v1[3], v2[0], v2[1], v2[2], v2[3], v3[0], v3[1],
+                         v3[2], v3[3], v4[0], v4[1], v4[2], v4[3]);
+    }
+
+    // Create a matrix from 3 column vectors
+    static inline Matrix4x4 fromCols(const MVector& v1, const MVector& v2, const MVector& v3,
+                                     const MVector& v4) {
+        return Matrix4x4(v1[0], v2[0], v3[0], v4[0], v1[1], v2[1], v3[1], v4[1], v1[2], v2[2],
+                         v3[2], v4[2], v1[3], v2[3], v3[3], v4[3]);
+    }
+
+    // Set the vector in row i to be v1
+    void setRow(int i, const MVector& v1) {
+        assert(i >= 0);
+        assert(i < 4);
+        m[i][0] = v1[0];
+        m[i][1] = v1[1];
+        m[i][2] = v1[2];
+        m[i][3] = v1[3];
+    }
+
+    // Set the vector in column i to be v1
+    void setCol(int i, const MVector& v1) {
+        assert(i >= 0);
+        assert(i < 4);
+        m[0][i] = v1[0];
+        m[1][i] = v1[1];
+        m[2][i] = v1[2];
+        m[3][i] = v1[3];
+    }
+
+    // Return the identity matrix
+    static inline Matrix4x4 identity() {
+        return Matrix4x4(VType(1), VType(), VType(), VType(), VType(), VType(1), VType(), VType(),
+                         VType(), VType(), VType(1), VType(), VType(), VType(), VType(), VType(1));
+    }
+
+    // Return a matrix full of zeros
+    static inline Matrix4x4 zero() { return Matrix4x4(); }
+
+    // Return a diagonal matrix with the coefficients in v
+    static inline Matrix4x4 diagonal(const MVector& v) {
+        return Matrix4x4(v[0], VType(), VType(), VType(),  //
+                         VType(), v[1], VType(), VType(),  //
+                         VType(), VType(), v[2], VType(),  //
+                         VType(), VType(), VType(), v[3]);
+    }
+
+    // Return the matrix vvT
+    static Matrix4x4 sym4(const MVector& v) {
+        return Matrix4x4(v[0] * v[0], v[0] * v[1], v[0] * v[2], v[0] * v[3], v[1] * v[0],
+                         v[1] * v[1], v[1] * v[2], v[1] * v[3], v[2] * v[0], v[2] * v[1],
+                         v[2] * v[2], v[2] * v[3], v[3] * v[0], v[3] * v[1], v[3] * v[2],
+                         v[3] * v[3]);
+    }
+
+    // Return the Frobenius norm of the matrix: sqrt(sum(aij^2))
+    VType frobeniusNorm() const {
+        VType sum = VType();
+        for (int i = 0; i < 4; i++) {
+            for (int j = 0; j < 4; j++) {
+                sum += m[i][j] * m[i][j];
+            }
+        }
+        return std::sqrt(sum);
+    }
+
+    // Return true is one of the elements of the matrix is NaN
+    bool isNaN() const {
+        for (int i = 0; i < 4; ++i) {
+            for (int j = 0; j < 4; ++j) {
+                if (isnan(m[i][j])) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    friend bool operator==(const Matrix4x4& a, const Matrix4x4& b) {
+        return a.m[0][0] == b.m[0][0] && a.m[0][1] == b.m[0][1] && a.m[0][2] == b.m[0][2] &&
+                a.m[0][3] == b.m[0][3] && a.m[1][0] == b.m[1][0] && a.m[1][1] == b.m[1][1] &&
+                a.m[1][2] == b.m[1][2] && a.m[1][3] == b.m[1][3] && a.m[2][0] == b.m[2][0] &&
+                a.m[2][1] == b.m[2][1] && a.m[2][2] == b.m[2][2] && a.m[2][3] == b.m[2][3] &&
+                a.m[3][0] == b.m[3][0] && a.m[3][1] == b.m[3][1] && a.m[3][2] == b.m[3][2] &&
+                a.m[3][3] == b.m[3][3];
+    }
+
+    friend bool operator!=(const Matrix4x4& a, const Matrix4x4& b) { return !(a == b); }
+};
+
+typedef Matrix4x4<int> Matrix4x4I;
+typedef Matrix4x4<float> Matrix4x4F;
+typedef Matrix4x4<double> Matrix4x4D;
+
+#endif  // #ifndef SURROUND_VIEW_SERVICE_IMPL_MATRIX4X4_H_
diff --git a/surround_view/service-impl/MtlReader.cpp b/surround_view/service-impl/MtlReader.cpp
new file mode 100644
index 0000000..7caccec
--- /dev/null
+++ b/surround_view/service-impl/MtlReader.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MtlReader.h"
+
+#include <android-base/logging.h>
+#include <cstdio>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+namespace {
+
+constexpr int kCharBufferSize = 128;
+
+void ReadFloat3(FILE* file, float* value) {
+    float temp[3];
+    int res = fscanf(file, "%f %f %f", &temp[0], &temp[1], &temp[2]);
+    3 == res ? std::memcpy(value, temp, 3 * sizeof(float)) : nullptr;
+}
+
+void ReadFloat(FILE* file, float* value) {
+    float temp;
+    int res = fscanf(file, "%f", &temp);
+    *value = res > 0 ? temp : -1;
+}
+
+void ReadInt(FILE* file, int* value) {
+    int temp;
+    int res = fscanf(file, "%d", &temp);
+    *value = res > 0 ? temp : -1;
+}
+
+void ReadString(FILE* file, std::string* value) {
+    char temp[kCharBufferSize];
+    fscanf(file, "%s", temp);
+    *value = temp;
+}
+}  // namespace
+
+bool ReadMtlFromFile(const std::string& mtlFilename,
+                     std::map<std::string, MtlConfigParams>* params) {
+    FILE* file = fopen(mtlFilename.c_str(), "r");
+    if (!file) {
+        LOG(ERROR) << "Failed to open mtl file: " << mtlFilename;
+        return false;
+    }
+
+    std::string currentConfig;
+    while (true) {
+        char lineHeader[kCharBufferSize];
+        // read the first word of the line
+        int res = fscanf(file, "%s", lineHeader);
+
+        if (res == EOF) {
+            break;  // EOF = End Of File. Quit the loop.
+        }
+
+        if (strcmp(lineHeader, "#") == 0) {
+            fgets(lineHeader, sizeof(lineHeader), file);
+            continue;
+        }
+        if (strcmp(lineHeader, "newmtl") == 0) {
+            res = fscanf(file, "%s", lineHeader);
+            if (params->find(lineHeader) != params->end()) {
+                fclose(file);
+                LOG(ERROR) << "Duplicated params of : " << lineHeader[0];
+                return false;
+            }
+            currentConfig = lineHeader;
+            continue;
+        }
+
+        if (strcmp(lineHeader, "Ns") == 0) {
+            ReadFloat(file, &((*params)[currentConfig].ns));
+            continue;
+        }
+        if (strcmp(lineHeader, "Ni") == 0) {
+            ReadFloat(file, &((*params)[currentConfig].ni));
+            continue;
+        }
+        if (strcmp(lineHeader, "d") == 0) {
+            ReadFloat(file, &((*params)[currentConfig].d));
+            continue;
+        }
+        if (strcmp(lineHeader, "Tr") == 0) {
+            ReadFloat(file, &((*params)[currentConfig].tr));
+            continue;
+        }
+        if (strcmp(lineHeader, "Tf") == 0) {
+            ReadFloat3(file, (*params)[currentConfig].tf);
+            continue;
+        }
+        if (strcmp(lineHeader, "illum") == 0) {
+            ReadInt(file, &((*params)[currentConfig].illum));
+            continue;
+        }
+        if (strcmp(lineHeader, "Ka") == 0) {
+            ReadFloat3(file, (*params)[currentConfig].ka);
+            continue;
+        }
+        if (strcmp(lineHeader, "Kd") == 0) {
+            ReadFloat3(file, (*params)[currentConfig].kd);
+            continue;
+        }
+        if (strcmp(lineHeader, "Ks") == 0) {
+            ReadFloat3(file, (*params)[currentConfig].ks);
+            continue;
+        }
+        if (strcmp(lineHeader, "Ke") == 0) {
+            ReadFloat3(file, (*params)[currentConfig].ke);
+            continue;
+        }
+        if (strcmp(lineHeader, "map_bump") == 0) {
+            ReadString(file, &((*params)[currentConfig].mapBump));
+            continue;
+        }
+        if (strcmp(lineHeader, "bump") == 0) {
+            ReadString(file, &((*params)[currentConfig].bump));
+            continue;
+        }
+        if (strcmp(lineHeader, "map_Ka") == 0) {
+            ReadString(file, &((*params)[currentConfig].mapKa));
+            continue;
+        }
+        if (strcmp(lineHeader, "map_Kd") == 0) {
+            ReadString(file, &((*params)[currentConfig].mapKd));
+            continue;
+        }
+        if (strcmp(lineHeader, "map_Ks") == 0) {
+            ReadString(file, &((*params)[currentConfig].mapKs));
+            continue;
+        } else {
+            LOG(WARNING) << "Unknown tag " << lineHeader << ". Skipped";
+            fgets(lineHeader, sizeof(lineHeader), file);
+            continue;
+        }
+    }
+
+    fclose(file);
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/MtlReader.h b/surround_view/service-impl/MtlReader.h
new file mode 100644
index 0000000..3e19876
--- /dev/null
+++ b/surround_view/service-impl/MtlReader.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SURROUND_VIEW_SERVICE_IMPL_MTLREADER_H_
+#define SURROUND_VIEW_SERVICE_IMPL_MTLREADER_H_
+
+#include <map>
+#include <string>
+
+#include "core_lib.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+// Mtl defined params.
+struct MtlConfigParams {
+    // Ns exponent
+    // Specifies the specular exponent for the current material. This defines
+    // the focus of the specular highlight.
+    // Ns values normally range from 0 to 1000.
+    float ns = -1;
+
+    // optical_density
+    // Specifies the optical density for the surface. This is also known as
+    // index of refraction.
+    //  "optical_density" is the value for the optical density. The values can
+    // range from 0.001 to 10. A value of 1.0 means that light does not bend
+    // as it passes through an object. Increasing the optical_density
+    // increases the amount of bending. Glass has an index of refraction of
+    // about 1.5.  Values of less than 1.0 produce bizarre results and are not
+    // recommended.
+    float ni = -1;
+
+    // d defines the non-transparency of the material to be alpha.
+    // The default is 1.0 (not transparent at all).
+    // The quantities d and Tr are the opposites of each other.
+    float d = -1;
+
+    // The Tr statement specifies the transparency of the material to be alpha.
+    // The default is 0.0 (not transparent at all).
+    // The quantities d and Tr are the opposites of each other,
+    float tr = -1;
+
+    // The Tf statement specifies the transmission filter using RGB values.
+    // "r g b" are the values for the red, green, and blue components of the
+    // atmosphere.  The g and b arguments are optional. If only r is
+    // specified, then g, and b are assumed to be equal to r. The r g b values
+    // are normally in the range of 0.0 to 1.0. Values outside this range
+    // increase or decrease the relectivity accordingly.
+    float tf[3] = {-1, -1, -1};
+
+    // illum_#
+    // The "illum" statement specifies the illumination model to use in the
+    // material.  Illumination models are mathematical equations that represent
+    // various material lighting and shading effects.
+    //
+    // "illum_#"can be a number from 0 to 10. The illumination models are
+    // summarized below;
+    //
+    //  Illumination    Properties that are turned on in the
+    //  model           Property Editor
+    //
+    //  0 Color on and Ambient off
+    //  1 Color on and Ambient on
+    //  2 Highlight on
+    //  3 Reflection on and Ray trace on
+    //  4 Transparency: Glass on
+    //    Reflection: Ray trace on
+    //  5 Reflection: Fresnel on and Ray trace on
+    //  6 Transparency: Refraction on
+    //    Reflection: Fresnel off and Ray trace on
+    //  7 Transparency: Refraction on
+    //    Reflection: Fresnel on and Ray trace on
+    //  8 Reflection on and Ray trace off
+    //  9 Transparency: Glass on
+    //    Reflection: Ray trace off
+    // 10 Casts shadows onto invisible surfaces
+    int illum = -1;
+
+    // The Ka statement specifies the ambient reflectivity using RGB values.
+    // "r g b" are the values for the red, green, and blue components of the
+    // color.  The g and b arguments are optional. If only r is specified,
+    // then g, and b are assumed to be equal to r. The r g b values are
+    // normally in the range of 0.0 to 1.0. Values outside this range increase
+    // or decrease the relectivity accordingly.
+    float ka[3] = {-1, -1, -1};
+
+    // The Kd statement specifies the diffuse reflectivity using RGB values.
+    //  "r g b" are the values for the red, green, and blue components of the
+    // atmosphere.  The g and b arguments are optional.  If only r is
+    // specified, then g, and b are assumed to be equal to r. The r g b values
+    // are normally in the range of 0.0 to 1.0. Values outside this range
+    // increase or decrease the relectivity accordingly.
+    float kd[3] = {-1, -1, -1};
+
+    // The Ks statement specifies the specular reflectivity using RGB values.
+    //  "r g b" are the values for the red, green, and blue components of the
+    // atmosphere. The g and b arguments are optional. If only r is
+    // specified, then g, and b are assumed to be equal to r. The r g b values
+    // are normally in the range of 0.0 to 1.0. Values outside this range
+    // increase or decrease the relectivity accordingly.
+    float ks[3] = {-1, -1, -1};
+
+    // Emissive coeficient. It goes together with ambient, diffuse and specular
+    // and represents the amount of light emitted by the material.
+    float ke[3] = {-1, -1, -1};
+
+    // Specifies that a color texture file or color procedural texture file is
+    // linked to the specular reflectivity of the material. During rendering,
+    // the map_Ks value is multiplied by the Ks value.
+    std::string mapKs;
+
+    // Specifies that a color texture file or a color procedural texture file
+    // is applied to the ambient reflectivity of the material. During
+    // rendering, the "map_Ka" value is multiplied by the "Ka" value.
+    std::string mapKa;
+
+    // Specifies that a color texture file or color procedural texture file is
+    // linked to the diffuse reflectivity of the material. During rendering,
+    // the map_Kd value is multiplied by the Kd value.
+    std::string mapKd;
+
+    // Same as bump
+    std::string mapBump;
+
+    // Specifies that a bump texture file or a bump procedural texture file is
+    // linked to the material.
+    std::string bump;
+
+    MtlConfigParams& operator=(const MtlConfigParams& rhs) {
+        ns = rhs.ns;
+        ni = rhs.ni;
+        d = rhs.d;
+        tr = rhs.tr;
+        std::memcpy(tf, rhs.tf, 3 * sizeof(float));
+        illum = rhs.illum;
+        std::memcpy(ka, rhs.ka, 3 * sizeof(float));
+        std::memcpy(kd, rhs.kd, 3 * sizeof(float));
+        std::memcpy(ks, rhs.ks, 3 * sizeof(float));
+        std::memcpy(ke, rhs.ke, 3 * sizeof(float));
+        mapKs = rhs.mapKs;
+        mapKa = rhs.mapKa;
+        mapKd = rhs.mapKd;
+        mapBump = rhs.mapBump;
+        bump = rhs.bump;
+
+        return *this;
+    }
+};
+
+// Reads mtl file associated with obj file.
+// |filename| is the full path and name of the obj file.
+bool ReadMtlFromFile(const std::string& mtlFilename,
+                     std::map<std::string, MtlConfigParams>* params);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // SURROUND_VIEW_SERVICE_IMPL_MTLREADER_H_
diff --git a/surround_view/service-impl/ObjReader.cpp b/surround_view/service-impl/ObjReader.cpp
new file mode 100644
index 0000000..dcb1973
--- /dev/null
+++ b/surround_view/service-impl/ObjReader.cpp
@@ -0,0 +1,305 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ObjReader.h"
+
+#include <array>
+#include <cstdio>
+#include <filesystem>
+#include <vector>
+
+#include "MtlReader.h"
+#include "core_lib.h"
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+using android_auto::surround_view::CarMaterial;
+using android_auto::surround_view::CarVertex;
+
+namespace {
+
+constexpr int kNumberOfVerticesPerFace = 3;
+constexpr int kNumberOfAxes = 3;
+constexpr int kCharBufferSize = 128;
+
+const std::array<float, 16> kMat4Identity = {
+        /*row 0*/ 1, 0, 0, 0,
+        /*row 1*/ 0, 1, 0, 0,
+        /*row 2*/ 0, 0, 1, 0,
+        /*row 3*/ 0, 0, 0, 1};
+
+// Copies face vertices parsed from obj to car vertices.
+void CopyFaceToCarVertex(const std::vector<std::array<float, kNumberOfAxes>>& currentVertices,
+                         const std::vector<std::array<float, kNumberOfAxes>>& currentTextures,
+                         const std::vector<std::array<float, kNumberOfAxes>>& currentNormals,
+                         int vertexId, int textureId, int normalId, CarVertex* carVertex) {
+    std::memcpy(carVertex->pos.data(), currentVertices[vertexId - 1].data(),
+                currentVertices[vertexId - 1].size() * sizeof(float));
+
+    if (textureId != -1) {
+        std::memcpy(carVertex->tex_coord.data(), currentTextures[textureId - 1].data(),
+                    2 * sizeof(float));
+        // Set texture coodinates as invalid.
+        carVertex->tex_coord = {-1.0, -1.0};
+    }
+
+    std::memcpy(carVertex->normal.data(), currentNormals[normalId - 1].data(),
+                currentNormals[normalId - 1].size() * sizeof(float));
+}
+
+}  // namespace
+
+bool ReadObjFromFile(const std::string& objFilename, std::map<std::string, CarPart>* carPartsMap) {
+    return ReadObjFromFile(objFilename, ReadObjOptions(), carPartsMap);
+}
+
+bool ReadObjFromFile(const std::string& objFilename, const ReadObjOptions& option,
+                     std::map<std::string, CarPart>* carPartsMap) {
+    FILE* file = fopen(objFilename.c_str(), "r");
+    if (!file) {
+        LOG(ERROR) << "Failed to open obj file: " << objFilename;
+        return false;
+    }
+
+    for (int i = 0; i < kNumberOfAxes; ++i) {
+        if (option.coordinateMapping[i] >= kNumberOfAxes || option.coordinateMapping[i] < 0) {
+            fclose(file);
+            LOG(ERROR) << "coordinateMapping index must be less than 3 and greater or equal "
+                          "to 0.";
+            return false;
+        }
+    }
+
+    std::vector<std::array<float, kNumberOfAxes>> currentVertices;
+    std::vector<std::array<float, kNumberOfAxes>> currentNormals;
+    std::vector<std::array<float, kNumberOfAxes>> currentTextures;
+    std::map<std::string, MtlConfigParams> mtlConfigParamsMap;
+    std::string currentGroupName;
+    MtlConfigParams currentMtlConfig;
+
+    while (true) {
+        char lineHeader[kCharBufferSize];
+        // read the first word of the line
+        int res = fscanf(file, "%s", lineHeader);
+
+        if (res == EOF) {
+            break;  // EOF = End Of File. Quit the loop.
+        }
+        if (strcmp(lineHeader, "#") == 0) {
+            fgets(lineHeader, sizeof(lineHeader), file);
+            continue;
+        }
+
+        // TODO(b/156558814): add object type support.
+        // TODO(b/156559272): add document for supported format.
+        // Only single group per line is supported.
+        if (strcmp(lineHeader, "g") == 0) {
+            res = fscanf(file, "%s", lineHeader);
+            currentGroupName = lineHeader;
+            currentMtlConfig = MtlConfigParams();
+
+            if (carPartsMap->find(currentGroupName) != carPartsMap->end()) {
+                LOG(WARNING) << "Duplicate group name: " << currentGroupName
+                             << ". using car part name as: " << currentGroupName << "_dup";
+                currentGroupName.append("_dup");
+            }
+            carPartsMap->emplace(
+                    std::make_pair(currentGroupName,
+                                   CarPart((std::vector<CarVertex>()), CarMaterial(), kMat4Identity,
+                                           std::string(), std::vector<std::string>())));
+            continue;
+        }
+
+        // no "g" case, assign it as default.
+        if (currentGroupName.empty()) {
+            currentGroupName = "default";
+            currentMtlConfig = MtlConfigParams();
+            carPartsMap->emplace(
+                    std::make_pair(currentGroupName,
+                                   CarPart((std::vector<CarVertex>()), CarMaterial(), kMat4Identity,
+                                           std::string(), std::vector<std::string>())));
+        }
+
+        if (strcmp(lineHeader, "usemtl") == 0) {
+            res = fscanf(file, "%s", lineHeader);
+
+            // If material name not found.
+            if (mtlConfigParamsMap.find(lineHeader) == mtlConfigParamsMap.end()) {
+                carPartsMap->at(currentGroupName).material = CarMaterial();
+                LOG(ERROR) << "Material not found: $0" << lineHeader;
+                return false;
+            }
+
+            currentMtlConfig = mtlConfigParamsMap[lineHeader];
+
+            carPartsMap->at(currentGroupName).material.ka = {currentMtlConfig.ka[0],
+                                                             currentMtlConfig.ka[1],
+                                                             currentMtlConfig.ka[2]};
+
+            carPartsMap->at(currentGroupName).material.kd = {currentMtlConfig.kd[0],
+                                                             currentMtlConfig.kd[1],
+                                                             currentMtlConfig.kd[2]};
+
+            carPartsMap->at(currentGroupName).material.ks = {currentMtlConfig.ks[0],
+                                                             currentMtlConfig.ks[1],
+                                                             currentMtlConfig.ks[2]};
+
+            carPartsMap->at(currentGroupName).material.d = currentMtlConfig.d;
+
+            carPartsMap->at(currentGroupName).material.textures.clear();
+
+            continue;
+        }
+
+        if (strcmp(lineHeader, "mtllib") == 0) {
+            res = fscanf(file, "%s", lineHeader);
+            mtlConfigParamsMap.clear();
+            std::string mtlFilename;
+            if (option.mtlFilename.empty()) {
+                mtlFilename = objFilename.substr(0, objFilename.find_last_of("/"));
+                mtlFilename.append("/");
+                mtlFilename.append(lineHeader);
+            } else {
+                mtlFilename = option.mtlFilename;
+            }
+            if (!ReadMtlFromFile(mtlFilename, &mtlConfigParamsMap)) {
+                LOG(ERROR) << "Parse MTL file " << mtlFilename << " failed.";
+                return false;
+            }
+            continue;
+        }
+
+        if (strcmp(lineHeader, "v") == 0) {
+            std::array<float, kNumberOfAxes> pos;
+            fscanf(file, "%f %f %f\n", &pos[option.coordinateMapping[0]],
+                   &pos[option.coordinateMapping[1]], &pos[option.coordinateMapping[2]]);
+            for (int i = 0; i < kNumberOfAxes; ++i) {
+                pos[i] *= option.scales[i];
+                pos[i] += option.offsets[i];
+            }
+            currentVertices.push_back(pos);
+        } else if (strcmp(lineHeader, "vt") == 0) {
+            std::array<float, kNumberOfAxes> texture;
+            fscanf(file, "%f %f %f\n", &texture[0], &texture[1], &texture[2]);
+            currentTextures.push_back(texture);
+        } else if (strcmp(lineHeader, "vn") == 0) {
+            std::array<float, kNumberOfAxes> normal;
+            fscanf(file, "%f %f %f\n", &normal[option.coordinateMapping[0]],
+                   &normal[option.coordinateMapping[1]], &normal[option.coordinateMapping[2]]);
+            currentNormals.push_back(normal);
+        } else if (strcmp(lineHeader, "f") == 0) {
+            int vertexId[kNumberOfVerticesPerFace];
+            int textureId[kNumberOfVerticesPerFace] = {-1, -1, -1};
+            int normalId[kNumberOfVerticesPerFace];
+
+            // Face vertices supported formats:
+            // With texture:     pos/texture/normal
+            // Without texture:  pos//normal
+
+            // Scan first vertex position.
+            int matches = fscanf(file, "%d/", &vertexId[0]);
+
+            if (matches != 1) {
+                LOG(WARNING) << "Face index error. Skipped.";
+                fgets(lineHeader, sizeof(lineHeader), file);
+                continue;
+            }
+
+            // Try scanning first two face 2 vertices with texture format present.
+            bool isTexturePresent = true;
+            matches = fscanf(file, "%d/%d %d/%d/%d", &textureId[0], &normalId[0], &vertexId[1],
+                             &textureId[1], &normalId[1]);
+
+            // If 5 matches not found, try scanning first 2 face vertices without
+            // texture format.
+            if (matches != 5) {
+                matches = fscanf(file, "/%d %d//%d", &normalId[0], &vertexId[1], &normalId[1]);
+
+                // If 3 matches not found return with error.
+                if (matches != 3) {
+                    LOG(WARNING) << "Face format not supported. Skipped.";
+                    fgets(lineHeader, sizeof(lineHeader), file);
+                    continue;
+                }
+
+                isTexturePresent = false;
+            }
+
+            // Copy first two face vertices to car vertices.
+            std::array<CarVertex, kNumberOfVerticesPerFace> carVertices;
+            CopyFaceToCarVertex(currentVertices, currentTextures, currentNormals, vertexId[0],
+                                textureId[0], normalId[0], &carVertices[0]);
+            CopyFaceToCarVertex(currentVertices, currentTextures, currentNormals, vertexId[1],
+                                textureId[1], normalId[1], &carVertices[1]);
+
+            // Add a triangle that the first two vertices make with every subsequent
+            // face vertex 3 and onwards. Note this assumes the face is a convex
+            // polygon.
+            do {
+                if (isTexturePresent) {
+                    matches = fscanf(file, " %d/%d/%d", &vertexId[2], &textureId[2], &normalId[2]);
+                    // Warn if un-expected number of matches.
+                    if (matches != 3 && matches != 0) {
+                        LOG(WARNING) << "Face matches, expected 3, read: " << matches;
+                        break;
+                    }
+                } else {
+                    // Warn if un-expected number of matches.
+                    matches = fscanf(file, " %d//%d", &vertexId[2], &normalId[2]);
+                    if (matches != 2 && matches != 0) {
+                        LOG(WARNING) << "Face matches, expected 2, read: " << matches;
+                        break;
+                    }
+                }
+
+                if (matches == 0) {
+                    break;
+                }
+
+                CopyFaceToCarVertex(currentVertices, currentTextures, currentNormals, vertexId[2],
+                                    textureId[2], normalId[2], &carVertices[2]);
+
+                carPartsMap->at(currentGroupName).vertices.push_back(carVertices[0]);
+                carPartsMap->at(currentGroupName).vertices.push_back(carVertices[1]);
+                carPartsMap->at(currentGroupName).vertices.push_back(carVertices[2]);
+
+                carVertices[1] = carVertices[2];
+            } while (true);
+
+        } else {
+            // LOG(WARNING) << "Unknown tag " << lineHeader << ". Skipped";
+            fgets(lineHeader, sizeof(lineHeader), file);
+            continue;
+        }
+    }
+
+    fclose(file);
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/ObjReader.h b/surround_view/service-impl/ObjReader.h
new file mode 100644
index 0000000..c19be14
--- /dev/null
+++ b/surround_view/service-impl/ObjReader.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SURROUND_VIEW_SERVICE_IMPL_OBJREADER_H_
+#define SURROUND_VIEW_SERVICE_IMPL_OBJREADER_H_
+
+#include <map>
+#include <string>
+
+#include "core_lib.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+using android_auto::surround_view::CarPart;
+
+// ReadObjOptions for processing obj's vertex coordinates.
+// Sequence of processing ReadObjOptions:
+// 1. coordinate_mapping
+// 2. scales
+// 3. offsets
+struct ReadObjOptions {
+    // Maps obj coordinates to the output overlay coordinate.
+    // 0 <-> x, 1 <-> y, 2 <-> z
+    // Default is {0, 1, 2}, without coordinate changes.
+    int coordinateMapping[3] = {0, 1, 2};
+
+    // scale of each coordinate (after offsets).
+    float scales[3] = {1.0f, 1.0f, 1.0f};
+
+    // offset of each coordinate (after mapping).
+    float offsets[3] = {0, 0, 0};
+
+    // Optional mtl filename. String name is obj file is used if this is empty.
+    std::string mtlFilename;
+};
+
+// Reads obj file to vector of OverlayVertex.
+// |obj_filename| is the full path and name of the obj file.
+// |car_parts_map| is a map containing all car parts.
+// Now it only supports two face formats:
+// 1. f x/x/x x/x/x x/x/x ...
+// 2. f x//x x//x x//x ...
+// b/
+bool ReadObjFromFile(const std::string& objFilename, std::map<std::string, CarPart>* carPartsMap);
+
+// Reads obj file to vector of OverlayVertex.
+// |obj_filename| is the full path and name of the obj file.
+// |option| provides optional changes on the coordinates.
+// |car_parts_map| is a map containing all car parts.
+bool ReadObjFromFile(const std::string& obFilename, const ReadObjOptions& option,
+                     std::map<std::string, CarPart>* carPartsMap);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // SURROUND_VIEW_SERVICE_IMPL_OBJREADER_H_
diff --git a/surround_view/service-impl/ObjReaderTests.cpp b/surround_view/service-impl/ObjReaderTests.cpp
new file mode 100644
index 0000000..9dae171
--- /dev/null
+++ b/surround_view/service-impl/ObjReaderTests.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ObjReaderTests"
+
+#include "ObjReader.h"
+
+#include "MtlReader.h"
+#include "core_lib.h"
+
+#include <gtest/gtest.h>
+#include <map>
+#include <string>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+namespace {
+
+TEST(ObjParserTests, ReadCubeSuccess) {
+    std::map<std::string, CarPart> carPartsMap;
+    EXPECT_TRUE(ReadObjFromFile("/etc/automotive/sv/cube.obj", &carPartsMap));
+    EXPECT_NE(carPartsMap.size(), 0);
+}
+
+}  // namespace
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/README b/surround_view/service-impl/README
new file mode 100644
index 0000000..d7b5e7c
--- /dev/null
+++ b/surround_view/service-impl/README
@@ -0,0 +1 @@
+The core_lib.h and the .so files are copied from google3 at Mar 19, 2020.
diff --git a/surround_view/service-impl/SurroundView2dSession.cpp b/surround_view/service-impl/SurroundView2dSession.cpp
new file mode 100644
index 0000000..b50049c
--- /dev/null
+++ b/surround_view/service-impl/SurroundView2dSession.cpp
@@ -0,0 +1,758 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SurroundView2dSession.h"
+
+#include <android-base/logging.h>
+#include <android/hardware_buffer.h>
+#include <system/camera_metadata.h>
+#include <utils/SystemClock.h>
+
+#include <thread>
+
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+
+#include "CameraUtils.h"
+
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using ::android::hardware::camera::device::V3_2::Stream;
+
+using GraphicsPixelFormat = ::android::hardware::graphics::common::V1_0::PixelFormat;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+// TODO(b/158479099): There are a lot of redundant code between 2d and 3d.
+// Decrease the degree of redundancy.
+typedef struct {
+    int32_t id;
+    int32_t width;
+    int32_t height;
+    int32_t format;
+    int32_t direction;
+    int32_t framerate;
+} RawStreamConfig;
+
+static const size_t kStreamCfgSz = sizeof(RawStreamConfig);
+static const uint8_t kGrayColor = 128;
+static const int kNumChannels = 3;
+static const int kNumFrames = 4;
+static const int kSv2dViewId = 0;
+
+SurroundView2dSession::FramesHandler::FramesHandler(
+    sp<IEvsCamera> pCamera, sp<SurroundView2dSession> pSession)
+    : mCamera(pCamera),
+      mSession(pSession) {}
+
+Return<void> SurroundView2dSession::FramesHandler::deliverFrame(
+    const BufferDesc_1_0& bufDesc_1_0) {
+    LOG(INFO) << "Ignores a frame delivered from v1.0 EVS service.";
+    mCamera->doneWithFrame(bufDesc_1_0);
+
+    return {};
+}
+
+Return<void> SurroundView2dSession::FramesHandler::deliverFrame_1_1(
+    const hidl_vec<BufferDesc_1_1>& buffers) {
+    LOG(INFO) << "Received " << buffers.size() << " frames from the camera";
+    mSession->mSequenceId++;
+
+    {
+        scoped_lock<mutex> lock(mSession->mAccessLock);
+        if (mSession->mProcessingEvsFrames) {
+            LOG(WARNING) << "EVS frames are being processed. Skip frames:" << mSession->mSequenceId;
+            mCamera->doneWithFrame_1_1(buffers);
+            return {};
+        }
+    }
+
+    if (buffers.size() != kNumFrames) {
+        LOG(ERROR) << "The number of incoming frames is " << buffers.size()
+                   << ", which is different from the number " << kNumFrames
+                   << ", specified in config file";
+        return {};
+    }
+
+    {
+        scoped_lock<mutex> lock(mSession->mAccessLock);
+        for (int i = 0; i < kNumFrames; i++) {
+            LOG(DEBUG) << "Copying buffer No." << i
+                       << " to Surround View Service";
+            mSession->copyFromBufferToPointers(buffers[i],
+                                               mSession->mInputPointers[i]);
+        }
+    }
+
+    mCamera->doneWithFrame_1_1(buffers);
+
+    // Notify the session that a new set of frames is ready
+    {
+        scoped_lock<mutex> lock(mSession->mAccessLock);
+        mSession->mProcessingEvsFrames = true;
+    }
+    mSession->mFramesSignal.notify_all();
+
+    return {};
+}
+
+Return<void> SurroundView2dSession::FramesHandler::notify(const EvsEventDesc& event) {
+    switch(event.aType) {
+        case EvsEventType::STREAM_STOPPED:
+        {
+            LOG(INFO) << "Received a STREAM_STOPPED event from Evs.";
+
+            // TODO(b/158339680): There is currently an issue in EVS reference
+            // implementation that causes STREAM_STOPPED event to be delivered
+            // properly. When the bug is fixed, we should deal with this event
+            // properly in case the EVS stream is stopped unexpectly.
+            break;
+        }
+
+        case EvsEventType::PARAMETER_CHANGED:
+            LOG(INFO) << "Camera parameter " << std::hex << event.payload[0]
+                      << " is set to " << event.payload[1];
+            break;
+
+        // Below events are ignored in reference implementation.
+        case EvsEventType::STREAM_STARTED:
+        [[fallthrough]];
+        case EvsEventType::FRAME_DROPPED:
+        [[fallthrough]];
+        case EvsEventType::TIMEOUT:
+            LOG(INFO) << "Event " << std::hex << static_cast<unsigned>(event.aType)
+                      << "is received but ignored.";
+            break;
+        default:
+            LOG(ERROR) << "Unknown event id: " << static_cast<unsigned>(event.aType);
+            break;
+    }
+
+    return {};
+}
+
+bool SurroundView2dSession::copyFromBufferToPointers(
+    BufferDesc_1_1 buffer, SurroundViewInputBufferPointers pointers) {
+
+    AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<AHardwareBuffer_Desc *>(&buffer.buffer.description);
+
+    // create a GraphicBuffer from the existing handle
+    sp<GraphicBuffer> inputBuffer = new GraphicBuffer(
+        buffer.buffer.nativeHandle, GraphicBuffer::CLONE_HANDLE, pDesc->width,
+        pDesc->height, pDesc->format, pDesc->layers,
+        GRALLOC_USAGE_HW_TEXTURE, pDesc->stride);
+
+    if (inputBuffer == nullptr) {
+        LOG(ERROR) << "Failed to allocate GraphicBuffer to wrap image handle";
+        // Returning "true" in this error condition because we already released the
+        // previous image (if any) and so the texture may change in unpredictable
+        // ways now!
+        return false;
+    } else {
+        LOG(INFO) << "Managed to allocate GraphicBuffer with "
+                  << " width: " << pDesc->width
+                  << " height: " << pDesc->height
+                  << " format: " << pDesc->format
+                  << " stride: " << pDesc->stride;
+    }
+
+    // Lock the input GraphicBuffer and map it to a pointer.  If we failed to
+    // lock, return false.
+    void* inputDataPtr;
+    inputBuffer->lock(
+        GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
+        &inputDataPtr);
+    if (!inputDataPtr) {
+        LOG(ERROR) << "Failed to gain read access to GraphicBuffer";
+        inputBuffer->unlock();
+        return false;
+    } else {
+        LOG(INFO) << "Managed to get read access to GraphicBuffer";
+    }
+
+    int stride = pDesc->stride;
+
+    // readPtr comes from EVS, and it is with 4 channels
+    uint8_t* readPtr = static_cast<uint8_t*>(inputDataPtr);
+
+    // writePtr comes from CV imread, and it is with 3 channels
+    uint8_t* writePtr = static_cast<uint8_t*>(pointers.cpu_data_pointer);
+
+    for (int i=0; i<pDesc->width; i++)
+        for (int j=0; j<pDesc->height; j++) {
+            writePtr[(i + j * stride) * 3 + 0] =
+                readPtr[(i + j * stride) * 4 + 0];
+            writePtr[(i + j * stride) * 3 + 1] =
+                readPtr[(i + j * stride) * 4 + 1];
+            writePtr[(i + j * stride) * 3 + 2] =
+                readPtr[(i + j * stride) * 4 + 2];
+        }
+    LOG(INFO) << "Brute force copying finished";
+
+    return true;
+}
+
+void SurroundView2dSession::processFrames() {
+    while (true) {
+        {
+            unique_lock<mutex> lock(mAccessLock);
+
+            if (mStreamState != RUNNING) {
+                break;
+            }
+
+            mFramesSignal.wait(lock, [this]() { return mProcessingEvsFrames; });
+        }
+
+        handleFrames(mSequenceId);
+
+        {
+            // Set the boolean to false to receive the next set of frames.
+            scoped_lock<mutex> lock(mAccessLock);
+            mProcessingEvsFrames = false;
+        }
+    }
+
+    // Notify the SV client that no new results will be delivered.
+    LOG(DEBUG) << "Notify SvEvent::STREAM_STOPPED";
+    mStream->notify(SvEvent::STREAM_STOPPED);
+
+    {
+        scoped_lock<mutex> lock(mAccessLock);
+        mStreamState = STOPPED;
+        mStream = nullptr;
+        LOG(DEBUG) << "Stream marked STOPPED.";
+    }
+}
+
+SurroundView2dSession::SurroundView2dSession(sp<IEvsEnumerator> pEvs,
+                                             IOModuleConfig* pConfig)
+    : mEvs(pEvs),
+      mIOModuleConfig(pConfig),
+      mStreamState(STOPPED) {
+    mEvsCameraIds = {"0", "1", "2", "3"};
+}
+
+SurroundView2dSession::~SurroundView2dSession() {
+    // In case the client did not call stopStream properly, we should stop the
+    // stream explicitly. Otherwise the process thread will take forever to
+    // join.
+    stopStream();
+
+    // Waiting for the process thread to finish the buffered frames.
+    if (mProcessThread.joinable()) {
+        mProcessThread.join();
+    }
+
+    mEvs->closeCamera(mCamera);
+}
+
+// Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession
+Return<SvResult> SurroundView2dSession::startStream(
+    const sp<ISurroundViewStream>& stream) {
+    LOG(DEBUG) << __FUNCTION__;
+    scoped_lock<mutex> lock(mAccessLock);
+
+    if (!mIsInitialized && !initialize()) {
+        LOG(ERROR) << "There is an error while initializing the use case. "
+                   << "Exiting";
+        return SvResult::INTERNAL_ERROR;
+    }
+
+    if (mStreamState != STOPPED) {
+        LOG(ERROR) << "Ignoring startVideoStream call"
+                   << "when a stream is already running.";
+        return SvResult::INTERNAL_ERROR;
+    }
+
+    if (stream == nullptr) {
+        LOG(ERROR) << "The input stream is invalid";
+        return SvResult::INTERNAL_ERROR;
+    }
+    mStream = stream;
+
+    mSequenceId = 0;
+    startEvs();
+
+    // TODO(b/158131080): the STREAM_STARTED event is not implemented in EVS
+    // reference implementation yet. Once implemented, this logic should be
+    // moved to EVS notify callback.
+    LOG(DEBUG) << "Notify SvEvent::STREAM_STARTED";
+    mStream->notify(SvEvent::STREAM_STARTED);
+    mProcessingEvsFrames = false;
+
+    // Start the frame generation thread
+    mStreamState = RUNNING;
+
+    mProcessThread = thread([this]() {
+        processFrames();
+    });
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView2dSession::stopStream() {
+    LOG(DEBUG) << __FUNCTION__;
+    unique_lock<mutex> lock(mAccessLock);
+
+    if (mStreamState == RUNNING) {
+        // Tell the processFrames loop to stop processing frames
+        mStreamState = STOPPING;
+
+        // Stop the EVS stream asynchronizely
+        mCamera->stopVideoStream();
+        mFramesHandler = nullptr;
+    }
+
+    return {};
+}
+
+Return<void> SurroundView2dSession::doneWithFrames(
+    const SvFramesDesc& svFramesDesc){
+    LOG(DEBUG) << __FUNCTION__;
+    scoped_lock <mutex> lock(mAccessLock);
+
+    mFramesRecord.inUse = false;
+
+    (void)svFramesDesc;
+    return {};
+}
+
+// Methods from ISurroundView2dSession follow.
+Return<void> SurroundView2dSession::get2dMappingInfo(
+    get2dMappingInfo_cb _hidl_cb) {
+    LOG(DEBUG) << __FUNCTION__;
+
+    _hidl_cb(mInfo);
+    return {};
+}
+
+Return<SvResult> SurroundView2dSession::set2dConfig(
+    const Sv2dConfig& sv2dConfig) {
+    LOG(DEBUG) << __FUNCTION__;
+    scoped_lock <mutex> lock(mAccessLock);
+
+    if (sv2dConfig.width <=0 || sv2dConfig.width > 4096) {
+        LOG(WARNING) << "The width of 2d config is out of the range (0, 4096]"
+                     << "Ignored!";
+        return SvResult::INVALID_ARG;
+    }
+
+    mConfig.width = sv2dConfig.width;
+    mConfig.blending = sv2dConfig.blending;
+    mHeight = mConfig.width * mInfo.height / mInfo.width;
+
+    if (mStream != nullptr) {
+        LOG(DEBUG) << "Notify SvEvent::CONFIG_UPDATED";
+        mStream->notify(SvEvent::CONFIG_UPDATED);
+    }
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView2dSession::get2dConfig(get2dConfig_cb _hidl_cb) {
+    LOG(DEBUG) << __FUNCTION__;
+
+    _hidl_cb(mConfig);
+    return {};
+}
+
+Return<void> SurroundView2dSession::projectCameraPoints(const hidl_vec<Point2dInt>& points2dCamera,
+                                                        const hidl_string& cameraId,
+                                                        projectCameraPoints_cb _hidl_cb) {
+    LOG(DEBUG) << __FUNCTION__;
+    std::vector<Point2dFloat> outPoints;
+    bool cameraIdFound = false;
+    int cameraIndex = 0;
+    // Note: mEvsCameraIds must be in the order front, right, rear, left.
+    for (auto& evsCameraId : mEvsCameraIds) {
+        if (cameraId == evsCameraId) {
+            cameraIdFound = true;
+            LOG(DEBUG) << "Camera id found for projection: " << cameraId;
+            break;
+        }
+        cameraIndex++;
+    }
+
+    if (!cameraIdFound) {
+        LOG(ERROR) << "Camera id not found for projection: " << cameraId;
+        _hidl_cb(outPoints);
+        return {};
+    }
+
+    int width = mConfig.width;
+    int height = mHeight;
+    for (const auto& cameraPoint : points2dCamera) {
+        Point2dFloat outPoint = {false, 0.0, 0.0};
+        // Check of the camear point is within the camera resolution bounds.
+        if (cameraPoint.x < 0 || cameraPoint.x > width - 1 || cameraPoint.y < 0 ||
+            cameraPoint.y > height - 1) {
+            LOG(WARNING) << "Camera point (" << cameraPoint.x << ", " << cameraPoint.y
+                         << ") is out of camera resolution bounds.";
+            outPoint.isValid = false;
+            outPoints.push_back(outPoint);
+            continue;
+        }
+
+        // Project points using mSurroundView function.
+        const Coordinate2dInteger camPoint(cameraPoint.x, cameraPoint.y);
+        Coordinate2dFloat projPoint2d(0.0, 0.0);
+
+        outPoint.isValid =
+                mSurroundView->GetProjectionPointFromRawCameraToSurroundView2d(camPoint,
+                                                                               cameraIndex,
+                                                                               &projPoint2d);
+        outPoint.x = projPoint2d.x;
+        outPoint.y = projPoint2d.y;
+        outPoints.push_back(outPoint);
+    }
+
+    _hidl_cb(outPoints);
+    return {};
+}
+
+bool SurroundView2dSession::handleFrames(int sequenceId) {
+    LOG(INFO) << __FUNCTION__ << "Handling sequenceId " << sequenceId << ".";
+
+    // TODO(b/157498592): Now only one sets of EVS input frames and one SV
+    // output frame is supported. Implement buffer queue for both of them.
+    {
+        scoped_lock<mutex> lock(mAccessLock);
+
+        if (mFramesRecord.inUse) {
+            LOG(DEBUG) << "Notify SvEvent::FRAME_DROPPED";
+            mStream->notify(SvEvent::FRAME_DROPPED);
+            return true;
+        }
+    }
+
+    if (mOutputWidth != mConfig.width || mOutputHeight != mHeight) {
+        LOG(DEBUG) << "Config changed. Re-allocate memory."
+                   << " Old width: "
+                   << mOutputWidth
+                   << " Old height: "
+                   << mOutputHeight
+                   << " New width: "
+                   << mConfig.width
+                   << " New height: "
+                   << mHeight;
+        delete[] static_cast<char*>(mOutputPointer.data_pointer);
+        mOutputWidth = mConfig.width;
+        mOutputHeight = mHeight;
+        mOutputPointer.height = mOutputHeight;
+        mOutputPointer.width = mOutputWidth;
+        mOutputPointer.format = Format::RGB;
+        mOutputPointer.data_pointer =
+            new char[mOutputHeight * mOutputWidth * kNumChannels];
+
+        if (!mOutputPointer.data_pointer) {
+            LOG(ERROR) << "Memory allocation failed. Exiting.";
+            return false;
+        }
+
+        Size2dInteger size = Size2dInteger(mOutputWidth, mOutputHeight);
+        mSurroundView->Update2dOutputResolution(size);
+
+        mSvTexture = new GraphicBuffer(mOutputWidth,
+                                       mOutputHeight,
+                                       HAL_PIXEL_FORMAT_RGB_888,
+                                       1,
+                                       GRALLOC_USAGE_HW_TEXTURE,
+                                       "SvTexture");
+        if (mSvTexture->initCheck() == OK) {
+            LOG(INFO) << "Successfully allocated Graphic Buffer";
+        } else {
+            LOG(ERROR) << "Failed to allocate Graphic Buffer";
+            return false;
+        }
+    }
+
+    if (mSurroundView->Get2dSurroundView(mInputPointers, &mOutputPointer)) {
+        LOG(INFO) << "Get2dSurroundView succeeded";
+    } else {
+        LOG(ERROR) << "Get2dSurroundView failed. "
+                   << "Using memset to initialize to gray";
+        memset(mOutputPointer.data_pointer, kGrayColor,
+               mOutputHeight * mOutputWidth * kNumChannels);
+    }
+
+    void* textureDataPtr = nullptr;
+    mSvTexture->lock(GRALLOC_USAGE_SW_WRITE_OFTEN
+                     | GRALLOC_USAGE_SW_READ_NEVER,
+                     &textureDataPtr);
+    if (!textureDataPtr) {
+        LOG(ERROR) << "Failed to gain write access to GraphicBuffer!";
+        return false;
+    }
+
+    // Note: there is a chance that the stride of the texture is not the same
+    // as the width. For example, when the input frame is 1920 * 1080, the
+    // width is 1080, but the stride is 2048. So we'd better copy the data line
+    // by line, instead of single memcpy.
+    uint8_t* writePtr = static_cast<uint8_t*>(textureDataPtr);
+    uint8_t* readPtr = static_cast<uint8_t*>(mOutputPointer.data_pointer);
+    const int readStride = mOutputWidth * kNumChannels;
+    const int writeStride = mSvTexture->getStride() * kNumChannels;
+    if (readStride == writeStride) {
+        memcpy(writePtr, readPtr, readStride * mSvTexture->getHeight());
+    } else {
+        for (int i=0; i<mSvTexture->getHeight(); i++) {
+            memcpy(writePtr, readPtr, readStride);
+            writePtr = writePtr + writeStride;
+            readPtr = readPtr + readStride;
+        }
+    }
+    LOG(DEBUG) << "memcpy finished";
+    mSvTexture->unlock();
+
+    ANativeWindowBuffer* buffer = mSvTexture->getNativeBuffer();
+    LOG(DEBUG) << "ANativeWindowBuffer->handle: "
+               << buffer->handle;
+
+    {
+        scoped_lock<mutex> lock(mAccessLock);
+
+        mFramesRecord.frames.svBuffers.resize(1);
+        SvBuffer& svBuffer = mFramesRecord.frames.svBuffers[0];
+        svBuffer.viewId = kSv2dViewId;
+        svBuffer.hardwareBuffer.nativeHandle = buffer->handle;
+        AHardwareBuffer_Desc* pDesc =
+            reinterpret_cast<AHardwareBuffer_Desc*>(
+                &svBuffer.hardwareBuffer.description);
+        pDesc->width = mOutputWidth;
+        pDesc->height = mOutputHeight;
+        pDesc->layers = 1;
+        pDesc->usage = GRALLOC_USAGE_HW_TEXTURE;
+        pDesc->stride = mSvTexture->getStride();
+        pDesc->format = HAL_PIXEL_FORMAT_RGB_888;
+        mFramesRecord.frames.timestampNs = elapsedRealtimeNano();
+        mFramesRecord.frames.sequenceId = sequenceId;
+
+        mFramesRecord.inUse = true;
+        mStream->receiveFrames(mFramesRecord.frames);
+    }
+
+    return true;
+}
+
+bool SurroundView2dSession::initialize() {
+    lock_guard<mutex> lock(mAccessLock, adopt_lock);
+
+    if (!setupEvs()) {
+        LOG(ERROR) << "Failed to setup EVS components for 2d session";
+        return false;
+    }
+
+    // TODO(b/150412555): ask core-lib team to add API description for "create"
+    // method in the .h file.
+    // The create method will never return a null pointer based the API
+    // description.
+    mSurroundView = unique_ptr<SurroundView>(Create());
+
+    SurroundViewStaticDataParams params =
+            SurroundViewStaticDataParams(
+                    mCameraParams,
+                    mIOModuleConfig->sv2dConfig.sv2dParams,
+                    mIOModuleConfig->sv3dConfig.sv3dParams,
+                    GetUndistortionScales(),
+                    mIOModuleConfig->sv2dConfig.carBoundingBox,
+                    mIOModuleConfig->carModelConfig.carModel.texturesMap,
+                    mIOModuleConfig->carModelConfig.carModel.partsMap);
+    mSurroundView->SetStaticData(params);
+    if (mSurroundView->Start2dPipeline()) {
+        LOG(INFO) << "Start2dPipeline succeeded";
+    } else {
+        LOG(ERROR) << "Start2dPipeline failed";
+        return false;
+    }
+
+    mInputPointers.resize(kNumFrames);
+    for (int i = 0; i < kNumFrames; i++) {
+        mInputPointers[i].width = mCameraParams[i].size.width;
+        mInputPointers[i].height = mCameraParams[i].size.height;
+        mInputPointers[i].format = Format::RGB;
+        mInputPointers[i].cpu_data_pointer =
+                (void*)new uint8_t[mInputPointers[i].width *
+                                   mInputPointers[i].height *
+                                   kNumChannels];
+    }
+    LOG(INFO) << "Allocated " << kNumFrames << " input pointers";
+
+    mOutputWidth = mIOModuleConfig->sv2dConfig.sv2dParams.resolution.width;
+    mOutputHeight = mIOModuleConfig->sv2dConfig.sv2dParams.resolution.height;
+
+    mConfig.width = mOutputWidth;
+    mConfig.blending = SvQuality::HIGH;
+    mHeight = mOutputHeight;
+
+    mOutputPointer.height = mOutputHeight;
+    mOutputPointer.width = mOutputWidth;
+    mOutputPointer.format = mInputPointers[0].format;
+    mOutputPointer.data_pointer = new char[
+        mOutputHeight * mOutputWidth * kNumChannels];
+
+    if (!mOutputPointer.data_pointer) {
+        LOG(ERROR) << "Memory allocation failed. Exiting.";
+        return false;
+    }
+
+    mSvTexture = new GraphicBuffer(mOutputWidth,
+                                   mOutputHeight,
+                                   HAL_PIXEL_FORMAT_RGB_888,
+                                   1,
+                                   GRALLOC_USAGE_HW_TEXTURE,
+                                   "SvTexture");
+
+    // Note: sv2dParams is in meters while mInfo must be in milli-meters.
+    mInfo.width = mIOModuleConfig->sv2dConfig.sv2dParams.physical_size.width * 1000.0;
+    mInfo.height = mIOModuleConfig->sv2dConfig.sv2dParams.physical_size.height * 1000.0;
+    mInfo.center.isValid = true;
+    mInfo.center.x = mIOModuleConfig->sv2dConfig.sv2dParams.physical_center.x * 1000.0;
+    mInfo.center.y = mIOModuleConfig->sv2dConfig.sv2dParams.physical_center.y * 1000.0;
+
+    if (mSvTexture->initCheck() == OK) {
+        LOG(INFO) << "Successfully allocated Graphic Buffer";
+    } else {
+        LOG(ERROR) << "Failed to allocate Graphic Buffer";
+        return false;
+    }
+
+    mIsInitialized = true;
+    return true;
+}
+
+bool SurroundView2dSession::setupEvs() {
+    // Reads the camera related information from the config object
+    const string evsGroupId = mIOModuleConfig->cameraConfig.evsGroupId;
+
+    // Setup for EVS
+    LOG(INFO) << "Requesting camera list";
+    mEvs->getCameraList_1_1(
+            [this, evsGroupId] (hidl_vec<CameraDesc> cameraList) {
+        LOG(INFO) << "Camera list callback received " << cameraList.size();
+        for (auto&& cam : cameraList) {
+            LOG(INFO) << "Found camera " << cam.v1.cameraId;
+            if (cam.v1.cameraId == evsGroupId) {
+                mCameraDesc = cam;
+            }
+        }
+    });
+
+    bool foundCfg = false;
+    std::unique_ptr<Stream> targetCfg(new Stream());
+
+    // This logic picks the configuration with the largest area that supports
+    // RGBA8888 format
+    int32_t maxArea = 0;
+    camera_metadata_entry_t streamCfgs;
+    if (!find_camera_metadata_entry(
+             reinterpret_cast<camera_metadata_t *>(mCameraDesc.metadata.data()),
+             ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+             &streamCfgs)) {
+        // Stream configurations are found in metadata
+        RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(
+            streamCfgs.data.i32);
+        for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
+            if (ptr->direction ==
+                ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+
+                if (ptr->width * ptr->height > maxArea) {
+                    targetCfg->id = ptr->id;
+                    targetCfg->width = ptr->width;
+                    targetCfg->height = ptr->height;
+
+                    // This client always wants below input data format
+                    targetCfg->format =
+                        static_cast<GraphicsPixelFormat>(
+                            HAL_PIXEL_FORMAT_RGBA_8888);
+
+                    maxArea = ptr->width * ptr->height;
+
+                    foundCfg = true;
+                }
+            }
+            ++ptr;
+        }
+    } else {
+        LOG(WARNING) << "No stream configuration data is found; "
+                     << "default parameters will be used.";
+    }
+
+    if (!foundCfg) {
+        LOG(INFO) << "No config was found";
+        targetCfg = nullptr;
+        return false;
+    }
+
+    string camId = mCameraDesc.v1.cameraId.c_str();
+    mCamera = mEvs->openCamera_1_1(camId.c_str(), *targetCfg);
+    if (mCamera == nullptr) {
+        LOG(ERROR) << "Failed to allocate EVS Camera interface for " << camId;
+        return false;
+    } else {
+        LOG(INFO) << "Camera " << camId << " is opened successfully";
+    }
+
+    map<string, AndroidCameraParams> cameraIdToAndroidParameters;
+    for (const auto& id : mIOModuleConfig->cameraConfig.evsCameraIds) {
+        AndroidCameraParams params;
+        if (getAndroidCameraParams(mCamera, id, params)) {
+            cameraIdToAndroidParameters.emplace(id, params);
+            LOG(INFO) << "Camera parameters are fetched successfully for "
+                      << "physical camera: " << id;
+        } else {
+            LOG(ERROR) << "Failed to get camera parameters for "
+                       << "physical camera: " << id;
+            return false;
+        }
+    }
+
+    mCameraParams =
+            convertToSurroundViewCameraParams(cameraIdToAndroidParameters);
+
+    for (auto& camera : mCameraParams) {
+        camera.size.width = targetCfg->width;
+        camera.size.height = targetCfg->height;
+        camera.circular_fov = 179;
+    }
+
+    return true;
+}
+
+bool SurroundView2dSession::startEvs() {
+    mFramesHandler = new FramesHandler(mCamera, this);
+    Return<EvsResult> result = mCamera->startVideoStream(mFramesHandler);
+    if (result != EvsResult::OK) {
+        LOG(ERROR) << "Failed to start video stream";
+        return false;
+    } else {
+        LOG(INFO) << "Video stream was started successfully";
+    }
+
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/SurroundView2dSession.h b/surround_view/service-impl/SurroundView2dSession.h
new file mode 100644
index 0000000..5a74c20
--- /dev/null
+++ b/surround_view/service-impl/SurroundView2dSession.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "CoreLibSetupHelper.h"
+#include "IOModule.h"
+
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
+
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <thread>
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+using namespace ::android::hardware::automotive::sv::V1_0;
+using namespace ::android_auto::surround_view;
+
+using ::android::hardware::Return;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+using ::std::condition_variable;
+
+using BufferDesc_1_0  = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using BufferDesc_1_1  = ::android::hardware::automotive::evs::V1_1::BufferDesc;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+class SurroundView2dSession : public ISurroundView2dSession {
+
+    /*
+     * FramesHandler:
+     * This class can be used to receive camera imagery from an IEvsCamera implementation.  It will
+     * hold onto the most recent image buffer, returning older ones.
+     * Note that the video frames are delivered on a background thread, while the control interface
+     * is actuated from the applications foreground thread.
+     */
+    class FramesHandler : public IEvsCameraStream {
+    public:
+        FramesHandler(sp<IEvsCamera> pCamera, sp<SurroundView2dSession> pSession);
+
+    private:
+        // Implementation for ::android::hardware::automotive::evs::V1_0::IEvsCameraStream
+        Return<void> deliverFrame(const BufferDesc_1_0& buffer) override;
+
+        // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream
+        Return<void> deliverFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffer) override;
+        Return<void> notify(const EvsEventDesc& event) override;
+
+        // Values initialized as startup
+        sp <IEvsCamera> mCamera;
+
+        sp<SurroundView2dSession> mSession;
+    };
+
+public:
+    SurroundView2dSession(sp<IEvsEnumerator> pEvs, IOModuleConfig* pConfig);
+    ~SurroundView2dSession();
+    bool initialize();
+
+    // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
+    Return<SvResult> startStream(
+        const sp<ISurroundViewStream>& stream) override;
+    Return<void> stopStream() override;
+    Return<void> doneWithFrames(const SvFramesDesc& svFramesDesc) override;
+
+    // Methods from ISurroundView2dSession follow.
+    Return<void> get2dMappingInfo(get2dMappingInfo_cb _hidl_cb) override;
+    Return<SvResult> set2dConfig(const Sv2dConfig& sv2dConfig) override;
+    Return<void> get2dConfig(get2dConfig_cb _hidl_cb) override;
+    Return<void> projectCameraPoints(
+        const hidl_vec<Point2dInt>& points2dCamera,
+        const hidl_string& cameraId,
+        projectCameraPoints_cb _hidl_cb) override;
+
+private:
+    void processFrames();
+
+    // Set up and open the Evs camera(s), triggered when session is created.
+    bool setupEvs();
+
+    // Start Evs camera video stream, triggered when SV stream is started.
+    bool startEvs();
+
+    bool handleFrames(int sequenceId);
+
+    bool copyFromBufferToPointers(BufferDesc_1_1 buffer,
+                                  SurroundViewInputBufferPointers pointers);
+
+    enum StreamStateValues {
+        STOPPED,
+        RUNNING,
+        STOPPING,
+        DEAD,
+    };
+
+    // EVS Enumerator to control the start/stop of the Evs Stream
+    sp<IEvsEnumerator> mEvs;
+
+    IOModuleConfig* mIOModuleConfig;
+
+    // Instance and metadata for the opened Evs Camera
+    sp<IEvsCamera> mCamera;
+    CameraDesc mCameraDesc;
+    vector<SurroundViewCameraParams> mCameraParams;
+
+    // Stream subscribed for the session.
+    sp<ISurroundViewStream> mStream GUARDED_BY(mAccessLock);
+    StreamStateValues mStreamState GUARDED_BY(mAccessLock);
+
+    thread mProcessThread; // The thread we'll use to process frames
+
+    // Reference to the inner class, to handle the incoming Evs frames
+    sp<FramesHandler> mFramesHandler;
+
+    // Used to signal a set of frames is ready
+    condition_variable mFramesSignal GUARDED_BY(mAccessLock);
+    bool mProcessingEvsFrames GUARDED_BY(mAccessLock);
+
+    int mSequenceId;
+
+    struct FramesRecord {
+        SvFramesDesc frames;
+        bool inUse = false;
+    };
+
+    FramesRecord mFramesRecord GUARDED_BY(mAccessLock);
+
+    // Synchronization necessary to deconflict mCaptureThread from the main
+    // service thread
+    mutex mAccessLock;
+
+    vector<string> mEvsCameraIds GUARDED_BY(mAccessLock);
+
+    unique_ptr<SurroundView> mSurroundView GUARDED_BY(mAccessLock);
+
+    vector<SurroundViewInputBufferPointers>
+        mInputPointers GUARDED_BY(mAccessLock);
+    SurroundViewResultPointer mOutputPointer GUARDED_BY(mAccessLock);
+
+    Sv2dConfig mConfig GUARDED_BY(mAccessLock);
+    int mHeight GUARDED_BY(mAccessLock);
+
+    // TODO(b/158479099): Rename it to mMappingInfo
+    Sv2dMappingInfo mInfo GUARDED_BY(mAccessLock);
+    int mOutputWidth, mOutputHeight GUARDED_BY(mAccessLock);
+
+    sp<GraphicBuffer> mSvTexture GUARDED_BY(mAccessLock);
+
+    bool mIsInitialized GUARDED_BY(mAccessLock) = false;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
diff --git a/surround_view/service-impl/SurroundView3dSession.cpp b/surround_view/service-impl/SurroundView3dSession.cpp
new file mode 100644
index 0000000..1a91e0d
--- /dev/null
+++ b/surround_view/service-impl/SurroundView3dSession.cpp
@@ -0,0 +1,902 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SurroundView3dSession.h"
+
+#include <android-base/logging.h>
+#include <android/hardware_buffer.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+#include <system/camera_metadata.h>
+#include <utils/SystemClock.h>
+
+#include <array>
+#include <thread>
+#include <set>
+
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+
+#include "CameraUtils.h"
+#include "sv_3d_params.h"
+
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::hidl_memory;
+using ::android::hidl::memory::V1_0::IMemory;
+
+using GraphicsPixelFormat = ::android::hardware::graphics::common::V1_0::PixelFormat;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+typedef struct {
+    int32_t id;
+    int32_t width;
+    int32_t height;
+    int32_t format;
+    int32_t direction;
+    int32_t framerate;
+} RawStreamConfig;
+
+static const size_t kStreamCfgSz = sizeof(RawStreamConfig);
+static const uint8_t kGrayColor = 128;
+static const int kNumFrames = 4;
+static const int kNumChannels = 4;
+
+SurroundView3dSession::FramesHandler::FramesHandler(
+    sp<IEvsCamera> pCamera, sp<SurroundView3dSession> pSession)
+    : mCamera(pCamera),
+      mSession(pSession) {}
+
+Return<void> SurroundView3dSession::FramesHandler::deliverFrame(
+    const BufferDesc_1_0& bufDesc_1_0) {
+    LOG(INFO) << "Ignores a frame delivered from v1.0 EVS service.";
+    mCamera->doneWithFrame(bufDesc_1_0);
+
+    return {};
+}
+
+Return<void> SurroundView3dSession::FramesHandler::deliverFrame_1_1(
+    const hidl_vec<BufferDesc_1_1>& buffers) {
+    LOG(INFO) << "Received " << buffers.size() << " frames from the camera";
+    mSession->mSequenceId++;
+
+    {
+        scoped_lock<mutex> lock(mSession->mAccessLock);
+        if (mSession->mProcessingEvsFrames) {
+            LOG(WARNING) << "EVS frames are being processed. Skip frames:"
+                         << mSession->mSequenceId;
+            mCamera->doneWithFrame_1_1(buffers);
+            return {};
+        }
+    }
+
+    if (buffers.size() != kNumFrames) {
+        LOG(ERROR) << "The number of incoming frames is " << buffers.size()
+                   << ", which is different from the number " << kNumFrames
+                   << ", specified in config file";
+        return {};
+    }
+
+    {
+        scoped_lock<mutex> lock(mSession->mAccessLock);
+        for (int i = 0; i < kNumFrames; i++) {
+            LOG(DEBUG) << "Copying buffer No." << i
+                       << " to Surround View Service";
+            mSession->copyFromBufferToPointers(buffers[i],
+                                               mSession->mInputPointers[i]);
+        }
+    }
+
+    mCamera->doneWithFrame_1_1(buffers);
+
+    // Notify the session that a new set of frames is ready
+    {
+        scoped_lock<mutex> lock(mSession->mAccessLock);
+        mSession->mProcessingEvsFrames = true;
+    }
+    mSession->mFramesSignal.notify_all();
+
+    return {};
+}
+
+Return<void> SurroundView3dSession::FramesHandler::notify(const EvsEventDesc& event) {
+    switch(event.aType) {
+        case EvsEventType::STREAM_STOPPED:
+            LOG(INFO) << "Received a STREAM_STOPPED event from Evs.";
+
+            // TODO(b/158339680): There is currently an issue in EVS reference
+            // implementation that causes STREAM_STOPPED event to be delivered
+            // properly. When the bug is fixed, we should deal with this event
+            // properly in case the EVS stream is stopped unexpectly.
+            break;
+
+        case EvsEventType::PARAMETER_CHANGED:
+            LOG(INFO) << "Camera parameter " << std::hex << event.payload[0]
+                      << " is set to " << event.payload[1];
+            break;
+
+        // Below events are ignored in reference implementation.
+        case EvsEventType::STREAM_STARTED:
+        [[fallthrough]];
+        case EvsEventType::FRAME_DROPPED:
+        [[fallthrough]];
+        case EvsEventType::TIMEOUT:
+            LOG(INFO) << "Event " << std::hex << static_cast<unsigned>(event.aType)
+                      << "is received but ignored.";
+            break;
+        default:
+            LOG(ERROR) << "Unknown event id: " << static_cast<unsigned>(event.aType);
+            break;
+    }
+
+    return {};
+}
+
+bool SurroundView3dSession::copyFromBufferToPointers(
+    BufferDesc_1_1 buffer, SurroundViewInputBufferPointers pointers) {
+
+    AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<AHardwareBuffer_Desc *>(&buffer.buffer.description);
+
+    // create a GraphicBuffer from the existing handle
+    sp<GraphicBuffer> inputBuffer = new GraphicBuffer(
+        buffer.buffer.nativeHandle, GraphicBuffer::CLONE_HANDLE, pDesc->width,
+        pDesc->height, pDesc->format, pDesc->layers,
+        GRALLOC_USAGE_HW_TEXTURE, pDesc->stride);
+
+    if (inputBuffer == nullptr) {
+        LOG(ERROR) << "Failed to allocate GraphicBuffer to wrap image handle";
+        // Returning "true" in this error condition because we already released the
+        // previous image (if any) and so the texture may change in unpredictable
+        // ways now!
+        return false;
+    } else {
+        LOG(INFO) << "Managed to allocate GraphicBuffer with "
+                  << " width: " << pDesc->width
+                  << " height: " << pDesc->height
+                  << " format: " << pDesc->format
+                  << " stride: " << pDesc->stride;
+    }
+
+    // Lock the input GraphicBuffer and map it to a pointer.  If we failed to
+    // lock, return false.
+    void* inputDataPtr;
+    inputBuffer->lock(
+        GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
+        &inputDataPtr);
+    if (!inputDataPtr) {
+        LOG(ERROR) << "Failed to gain read access to GraphicBuffer";
+        inputBuffer->unlock();
+        return false;
+    } else {
+        LOG(INFO) << "Managed to get read access to GraphicBuffer";
+    }
+
+    int stride = pDesc->stride;
+
+    // readPtr comes from EVS, and it is with 4 channels
+    uint8_t* readPtr = static_cast<uint8_t*>(inputDataPtr);
+
+    // writePtr is with 3 channels, since that is what SV core lib expects.
+    uint8_t* writePtr = static_cast<uint8_t*>(pointers.cpu_data_pointer);
+
+    for (int i = 0; i < pDesc->width; i++)
+        for (int j = 0; j < pDesc->height; j++) {
+            writePtr[(i + j * stride) * 3 + 0] =
+                readPtr[(i + j * stride) * 4 + 0];
+            writePtr[(i + j * stride) * 3 + 1] =
+                readPtr[(i + j * stride) * 4 + 1];
+            writePtr[(i + j * stride) * 3 + 2] =
+                readPtr[(i + j * stride) * 4 + 2];
+        }
+    LOG(INFO) << "Brute force copying finished";
+
+    return true;
+}
+
+void SurroundView3dSession::processFrames() {
+    if (mSurroundView->Start3dPipeline()) {
+        LOG(INFO) << "Start3dPipeline succeeded";
+    } else {
+        LOG(ERROR) << "Start3dPipeline failed";
+        return;
+    }
+
+    while (true) {
+        {
+            unique_lock<mutex> lock(mAccessLock);
+
+            if (mStreamState != RUNNING) {
+                break;
+            }
+
+            mFramesSignal.wait(lock, [this]() { return mProcessingEvsFrames; });
+        }
+
+        handleFrames(mSequenceId);
+
+        {
+            // Set the boolean to false to receive the next set of frames.
+            scoped_lock<mutex> lock(mAccessLock);
+            mProcessingEvsFrames = false;
+        }
+    }
+
+    // Notify the SV client that no new results will be delivered.
+    LOG(DEBUG) << "Notify SvEvent::STREAM_STOPPED";
+    mStream->notify(SvEvent::STREAM_STOPPED);
+
+    {
+        scoped_lock<mutex> lock(mAccessLock);
+        mStreamState = STOPPED;
+        mStream = nullptr;
+        LOG(DEBUG) << "Stream marked STOPPED.";
+    }
+}
+
+SurroundView3dSession::SurroundView3dSession(sp<IEvsEnumerator> pEvs,
+                                             VhalHandler* vhalHandler,
+                                             AnimationModule* animationModule,
+                                             IOModuleConfig* pConfig) :
+      mEvs(pEvs),
+      mStreamState(STOPPED),
+      mVhalHandler(vhalHandler),
+      mAnimationModule(animationModule),
+      mIOModuleConfig(pConfig) {
+    mEvsCameraIds = {"0" , "1", "2", "3"};
+}
+
+SurroundView3dSession::~SurroundView3dSession() {
+    // In case the client did not call stopStream properly, we should stop the
+    // stream explicitly. Otherwise the process thread will take forever to
+    // join.
+    stopStream();
+
+    // Waiting for the process thread to finish the buffered frames.
+    mProcessThread.join();
+
+    mEvs->closeCamera(mCamera);
+}
+
+// Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
+Return<SvResult> SurroundView3dSession::startStream(
+    const sp<ISurroundViewStream>& stream) {
+    LOG(DEBUG) << __FUNCTION__;
+    scoped_lock<mutex> lock(mAccessLock);
+
+    if (!mIsInitialized && !initialize()) {
+        LOG(ERROR) << "There is an error while initializing the use case. "
+                   << "Exiting";
+        return SvResult::INTERNAL_ERROR;
+    }
+
+    if (mStreamState != STOPPED) {
+        LOG(ERROR) << "Ignoring startVideoStream call when a stream is "
+                   << "already running.";
+        return SvResult::INTERNAL_ERROR;
+    }
+
+    if (mViews.empty()) {
+        LOG(ERROR) << "No views have been set for current Surround View"
+                   << "3d Session. Please call setViews before starting"
+                   << "the stream.";
+        return SvResult::VIEW_NOT_SET;
+    }
+
+    if (stream == nullptr) {
+        LOG(ERROR) << "The input stream is invalid";
+        return SvResult::INTERNAL_ERROR;
+    }
+    mStream = stream;
+
+    mSequenceId = 0;
+    startEvs();
+
+    if (mVhalHandler != nullptr) {
+        if (!mVhalHandler->startPropertiesUpdate()) {
+            LOG(WARNING) << "VhalHandler cannot be started properly";
+        }
+    } else {
+        LOG(WARNING) << "VhalHandler is null. Ignored";
+    }
+
+    // TODO(b/158131080): the STREAM_STARTED event is not implemented in EVS
+    // reference implementation yet. Once implemented, this logic should be
+    // moved to EVS notify callback.
+    LOG(DEBUG) << "Notify SvEvent::STREAM_STARTED";
+    mStream->notify(SvEvent::STREAM_STARTED);
+    mProcessingEvsFrames = false;
+
+    // Start the frame generation thread
+    mStreamState = RUNNING;
+
+    mProcessThread = thread([this]() {
+        processFrames();
+    });
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView3dSession::stopStream() {
+    LOG(DEBUG) << __FUNCTION__;
+    unique_lock <mutex> lock(mAccessLock);
+
+    if (mVhalHandler != nullptr) {
+        mVhalHandler->stopPropertiesUpdate();
+    } else {
+        LOG(WARNING) << "VhalHandler is null. Ignored";
+    }
+
+    if (mStreamState == RUNNING) {
+        // Tell the processFrames loop to stop processing frames
+        mStreamState = STOPPING;
+
+        // Stop the EVS stream asynchronizely
+        mCamera->stopVideoStream();
+    }
+
+    return {};
+}
+
+Return<void> SurroundView3dSession::doneWithFrames(
+    const SvFramesDesc& svFramesDesc){
+    LOG(DEBUG) << __FUNCTION__;
+    scoped_lock <mutex> lock(mAccessLock);
+
+    mFramesRecord.inUse = false;
+
+    (void)svFramesDesc;
+    return {};
+}
+
+// Methods from ISurroundView3dSession follow.
+Return<SvResult> SurroundView3dSession::setViews(
+    const hidl_vec<View3d>& views) {
+    LOG(DEBUG) << __FUNCTION__;
+    scoped_lock <mutex> lock(mAccessLock);
+
+    mViews.resize(views.size());
+    for (int i=0; i<views.size(); i++) {
+        mViews[i] = views[i];
+    }
+
+    return SvResult::OK;
+}
+
+Return<SvResult> SurroundView3dSession::set3dConfig(const Sv3dConfig& sv3dConfig) {
+    LOG(DEBUG) << __FUNCTION__;
+    scoped_lock <mutex> lock(mAccessLock);
+
+    if (sv3dConfig.width <=0 || sv3dConfig.width > 4096) {
+        LOG(WARNING) << "The width of 3d config is out of the range (0, 4096]"
+                     << "Ignored!";
+        return SvResult::INVALID_ARG;
+    }
+
+    if (sv3dConfig.height <=0 || sv3dConfig.height > 4096) {
+        LOG(WARNING) << "The height of 3d config is out of the range (0, 4096]"
+                     << "Ignored!";
+        return SvResult::INVALID_ARG;
+    }
+
+    mConfig.width = sv3dConfig.width;
+    mConfig.height = sv3dConfig.height;
+    mConfig.carDetails = sv3dConfig.carDetails;
+
+    if (mStream != nullptr) {
+        LOG(DEBUG) << "Notify SvEvent::CONFIG_UPDATED";
+        mStream->notify(SvEvent::CONFIG_UPDATED);
+    }
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView3dSession::get3dConfig(get3dConfig_cb _hidl_cb) {
+    LOG(DEBUG) << __FUNCTION__;
+
+    _hidl_cb(mConfig);
+    return {};
+}
+
+bool VerifyOverlayData(const OverlaysData& overlaysData) {
+    // Check size of shared memory matches overlaysMemoryDesc.
+    const int kVertexSize = 16;
+    const int kIdSize = 2;
+    int memDescSize = 0;
+    for (auto& overlayMemDesc : overlaysData.overlaysMemoryDesc) {
+        memDescSize += kIdSize + kVertexSize * overlayMemDesc.verticesCount;
+    }
+    if (memDescSize != overlaysData.overlaysMemory.size()) {
+        LOG(ERROR) << "shared memory and overlaysMemoryDesc size mismatch.";
+        return false;
+    }
+
+    // Map memory.
+    sp<IMemory> pSharedMemory = mapMemory(overlaysData.overlaysMemory);
+    if(pSharedMemory == nullptr) {
+        LOG(ERROR) << "mapMemory failed.";
+        return false;
+    }
+
+    // Get Data pointer.
+    uint8_t* pData = static_cast<uint8_t*>(
+        static_cast<void*>(pSharedMemory->getPointer()));
+    if (pData == nullptr) {
+        LOG(ERROR) << "Shared memory getPointer() failed.";
+        return false;
+    }
+
+    int idOffset = 0;
+    set<uint16_t> overlayIdSet;
+    for (auto& overlayMemDesc : overlaysData.overlaysMemoryDesc) {
+
+        if (overlayIdSet.find(overlayMemDesc.id) != overlayIdSet.end()) {
+            LOG(ERROR) << "Duplicate id within memory descriptor.";
+            return false;
+        }
+        overlayIdSet.insert(overlayMemDesc.id);
+
+        if(overlayMemDesc.verticesCount < 3) {
+            LOG(ERROR) << "Less than 3 vertices.";
+            return false;
+        }
+
+        if (overlayMemDesc.overlayPrimitive == OverlayPrimitive::TRIANGLES &&
+                overlayMemDesc.verticesCount % 3 != 0) {
+            LOG(ERROR) << "Triangles primitive does not have vertices "
+                       << "multiple of 3.";
+            return false;
+        }
+
+        const uint16_t overlayId = *((uint16_t*)(pData + idOffset));
+
+        if (overlayId != overlayMemDesc.id) {
+            LOG(ERROR) << "Overlay id mismatch "
+                       << overlayId
+                       << ", "
+                       << overlayMemDesc.id;
+            return false;
+        }
+
+        idOffset += kIdSize + (kVertexSize * overlayMemDesc.verticesCount);
+    }
+
+    return true;
+}
+
+// TODO(b/150412555): the overlay related methods are incomplete.
+Return<SvResult>  SurroundView3dSession::updateOverlays(
+        const OverlaysData& overlaysData) {
+
+    if(!VerifyOverlayData(overlaysData)) {
+        LOG(ERROR) << "VerifyOverlayData failed.";
+        return SvResult::INVALID_ARG;
+    }
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView3dSession::projectCameraPointsTo3dSurface(
+        const hidl_vec<Point2dInt>& cameraPoints, const hidl_string& cameraId,
+        projectCameraPointsTo3dSurface_cb _hidl_cb) {
+    LOG(DEBUG) << __FUNCTION__;
+    bool cameraIdFound = false;
+    int cameraIndex = 0;
+    std::vector<Point3dFloat> points3d;
+
+    // Note: mEvsCameraIds must be in the order front, right, rear, left.
+    for (auto& evsCameraId : mEvsCameraIds) {
+        if (cameraId == evsCameraId) {
+            cameraIdFound = true;
+            LOG(DEBUG) << "Camera id found for projection: " << cameraId;
+            break;
+        }
+        cameraIndex++;
+    }
+
+    if (!cameraIdFound) {
+        LOG(ERROR) << "Camera id not found for projection: " << cameraId;
+        _hidl_cb(points3d);
+        return {};
+    }
+
+    for (const auto& cameraPoint : cameraPoints) {
+        Point3dFloat point3d = {false, 0.0, 0.0, 0.0};
+
+        // Verify if camera point is within the camera resolution bounds.
+        point3d.isValid = (cameraPoint.x >= 0 && cameraPoint.x < mConfig.width &&
+                           cameraPoint.y >= 0 && cameraPoint.y < mConfig.height);
+        if (!point3d.isValid) {
+            LOG(WARNING) << "Camera point (" << cameraPoint.x << ", " << cameraPoint.y
+                         << ") is out of camera resolution bounds.";
+            points3d.push_back(point3d);
+            continue;
+        }
+
+        // Project points using mSurroundView function.
+        const Coordinate2dInteger camCoord(cameraPoint.x, cameraPoint.y);
+        Coordinate3dFloat projPoint3d(0.0, 0.0, 0.0);
+        point3d.isValid =
+                mSurroundView->GetProjectionPointFromRawCameraToSurroundView3d(camCoord,
+                                                                               cameraIndex,
+                                                                               &projPoint3d);
+        // Convert projPoint3d in meters to point3d which is in milli-meters.
+        point3d.x = projPoint3d.x * 1000.0;
+        point3d.y = projPoint3d.y * 1000.0;
+        point3d.z = projPoint3d.z * 1000.0;
+        points3d.push_back(point3d);
+    }
+    _hidl_cb(points3d);
+    return {};
+}
+
+bool SurroundView3dSession::handleFrames(int sequenceId) {
+    LOG(INFO) << __FUNCTION__ << "Handling sequenceId " << sequenceId << ".";
+
+    // TODO(b/157498592): Now only one sets of EVS input frames and one SV
+    // output frame is supported. Implement buffer queue for both of them.
+    {
+        scoped_lock<mutex> lock(mAccessLock);
+
+        if (mFramesRecord.inUse) {
+            LOG(DEBUG) << "Notify SvEvent::FRAME_DROPPED";
+            mStream->notify(SvEvent::FRAME_DROPPED);
+            return true;
+        }
+    }
+
+    // If the width/height was changed, re-allocate the data pointer.
+    if (mOutputWidth != mConfig.width
+        || mOutputHeight != mConfig.height) {
+        LOG(DEBUG) << "Config changed. Re-allocate memory. "
+                   << "Old width: "
+                   << mOutputWidth
+                   << ", old height: "
+                   << mOutputHeight
+                   << "; New width: "
+                   << mConfig.width
+                   << ", new height: "
+                   << mConfig.height;
+        delete[] static_cast<char*>(mOutputPointer.data_pointer);
+        mOutputWidth = mConfig.width;
+        mOutputHeight = mConfig.height;
+        mOutputPointer.height = mOutputHeight;
+        mOutputPointer.width = mOutputWidth;
+        mOutputPointer.format = Format::RGBA;
+        mOutputPointer.data_pointer =
+            new char[mOutputHeight * mOutputWidth * kNumChannels];
+
+        if (!mOutputPointer.data_pointer) {
+            LOG(ERROR) << "Memory allocation failed. Exiting.";
+            return false;
+        }
+
+        Size2dInteger size = Size2dInteger(mOutputWidth, mOutputHeight);
+        mSurroundView->Update3dOutputResolution(size);
+
+        mSvTexture = new GraphicBuffer(mOutputWidth,
+                                       mOutputHeight,
+                                       HAL_PIXEL_FORMAT_RGBA_8888,
+                                       1,
+                                       GRALLOC_USAGE_HW_TEXTURE,
+                                       "SvTexture");
+        if (mSvTexture->initCheck() == OK) {
+            LOG(INFO) << "Successfully allocated Graphic Buffer";
+        } else {
+            LOG(ERROR) << "Failed to allocate Graphic Buffer";
+            return false;
+        }
+    }
+
+    // TODO(b/150412555): do not use the setViews for frames generation
+    // since there is a discrepancy between the HIDL APIs and core lib APIs.
+    array<array<float, 4>, 4> matrix;
+
+    // TODO(b/150412555): use hard-coded views for now. Change view every
+    // frame.
+    int recViewId = sequenceId % 16;
+    for (int i=0; i<4; i++)
+        for (int j=0; j<4; j++) {
+            matrix[i][j] = kRecViews[recViewId][i*4+j];
+    }
+
+    // Get the latest VHal property values
+    if (mVhalHandler != nullptr) {
+        if (!mVhalHandler->getPropertyValues(&mPropertyValues)) {
+            LOG(ERROR) << "Failed to get property values";
+        }
+    } else {
+        LOG(WARNING) << "VhalHandler is null. Ignored";
+    }
+
+    vector<AnimationParam> params;
+    if (mAnimationModule != nullptr) {
+        params = mAnimationModule->getUpdatedAnimationParams(mPropertyValues);
+    } else {
+        LOG(WARNING) << "AnimationModule is null. Ignored";
+    }
+
+    if (!params.empty()) {
+        mSurroundView->SetAnimations(params);
+    } else {
+        LOG(INFO) << "AnimationParams is empty. Ignored";
+    }
+
+    if (mSurroundView->Get3dSurroundView(
+        mInputPointers, matrix, &mOutputPointer)) {
+        LOG(INFO) << "Get3dSurroundView succeeded";
+    } else {
+        LOG(ERROR) << "Get3dSurroundView failed. "
+                   << "Using memset to initialize to gray.";
+        memset(mOutputPointer.data_pointer, kGrayColor,
+               mOutputHeight * mOutputWidth * kNumChannels);
+    }
+
+    void* textureDataPtr = nullptr;
+    mSvTexture->lock(GRALLOC_USAGE_SW_WRITE_OFTEN
+                    | GRALLOC_USAGE_SW_READ_NEVER,
+                    &textureDataPtr);
+    if (!textureDataPtr) {
+        LOG(ERROR) << "Failed to gain write access to GraphicBuffer!";
+        return false;
+    }
+
+    // Note: there is a chance that the stride of the texture is not the
+    // same as the width. For example, when the input frame is 1920 * 1080,
+    // the width is 1080, but the stride is 2048. So we'd better copy the
+    // data line by line, instead of single memcpy.
+    uint8_t* writePtr = static_cast<uint8_t*>(textureDataPtr);
+    uint8_t* readPtr = static_cast<uint8_t*>(mOutputPointer.data_pointer);
+    const int readStride = mOutputWidth * kNumChannels;
+    const int writeStride = mSvTexture->getStride() * kNumChannels;
+    if (readStride == writeStride) {
+        memcpy(writePtr, readPtr, readStride * mSvTexture->getHeight());
+    } else {
+        for (int i=0; i<mSvTexture->getHeight(); i++) {
+            memcpy(writePtr, readPtr, readStride);
+            writePtr = writePtr + writeStride;
+            readPtr = readPtr + readStride;
+        }
+    }
+    LOG(INFO) << "memcpy finished!";
+    mSvTexture->unlock();
+
+    ANativeWindowBuffer* buffer = mSvTexture->getNativeBuffer();
+    LOG(DEBUG) << "ANativeWindowBuffer->handle: " << buffer->handle;
+
+    {
+        scoped_lock<mutex> lock(mAccessLock);
+
+        mFramesRecord.frames.svBuffers.resize(1);
+        SvBuffer& svBuffer = mFramesRecord.frames.svBuffers[0];
+        svBuffer.viewId = 0;
+        svBuffer.hardwareBuffer.nativeHandle = buffer->handle;
+        AHardwareBuffer_Desc* pDesc =
+            reinterpret_cast<AHardwareBuffer_Desc *>(
+                &svBuffer.hardwareBuffer.description);
+        pDesc->width = mOutputWidth;
+        pDesc->height = mOutputHeight;
+        pDesc->layers = 1;
+        pDesc->usage = GRALLOC_USAGE_HW_TEXTURE;
+        pDesc->stride = mSvTexture->getStride();
+        pDesc->format = HAL_PIXEL_FORMAT_RGBA_8888;
+        mFramesRecord.frames.timestampNs = elapsedRealtimeNano();
+        mFramesRecord.frames.sequenceId = sequenceId;
+
+        mFramesRecord.inUse = true;
+        mStream->receiveFrames(mFramesRecord.frames);
+    }
+
+    return true;
+}
+
+bool SurroundView3dSession::initialize() {
+    lock_guard<mutex> lock(mAccessLock, adopt_lock);
+
+    if (!setupEvs()) {
+        LOG(ERROR) << "Failed to setup EVS components for 3d session";
+        return false;
+    }
+
+    // TODO(b/150412555): ask core-lib team to add API description for "create"
+    // method in the .h file.
+    // The create method will never return a null pointer based the API
+    // description.
+    mSurroundView = unique_ptr<SurroundView>(Create());
+
+    SurroundViewStaticDataParams params =
+            SurroundViewStaticDataParams(
+                    mCameraParams,
+                    mIOModuleConfig->sv2dConfig.sv2dParams,
+                    mIOModuleConfig->sv3dConfig.sv3dParams,
+                    GetUndistortionScales(),
+                    mIOModuleConfig->sv2dConfig.carBoundingBox,
+                    mIOModuleConfig->carModelConfig.carModel.texturesMap,
+                    mIOModuleConfig->carModelConfig.carModel.partsMap);
+    mSurroundView->SetStaticData(params);
+
+    mInputPointers.resize(kNumFrames);
+    for (int i = 0; i < kNumFrames; i++) {
+        mInputPointers[i].width = mCameraParams[i].size.width;
+        mInputPointers[i].height = mCameraParams[i].size.height;
+        mInputPointers[i].format = Format::RGB;
+        mInputPointers[i].cpu_data_pointer =
+                (void*)new uint8_t[mInputPointers[i].width *
+                                   mInputPointers[i].height *
+                                   kNumChannels];
+    }
+    LOG(INFO) << "Allocated " << kNumFrames << " input pointers";
+
+    mOutputWidth = mIOModuleConfig->sv3dConfig.sv3dParams.resolution.width;
+    mOutputHeight = mIOModuleConfig->sv3dConfig.sv3dParams.resolution.height;
+
+    mConfig.width = mOutputWidth;
+    mConfig.height = mOutputHeight;
+    mConfig.carDetails = SvQuality::HIGH;
+
+    mOutputPointer.height = mOutputHeight;
+    mOutputPointer.width = mOutputWidth;
+    mOutputPointer.format = Format::RGBA;
+    mOutputPointer.data_pointer = new char[
+        mOutputHeight * mOutputWidth * kNumChannels];
+
+    if (!mOutputPointer.data_pointer) {
+        LOG(ERROR) << "Memory allocation failed. Exiting.";
+        return false;
+    }
+
+    mSvTexture = new GraphicBuffer(mOutputWidth,
+                                   mOutputHeight,
+                                   HAL_PIXEL_FORMAT_RGBA_8888,
+                                   1,
+                                   GRALLOC_USAGE_HW_TEXTURE,
+                                   "SvTexture");
+
+    if (mSvTexture->initCheck() == OK) {
+        LOG(INFO) << "Successfully allocated Graphic Buffer";
+    } else {
+        LOG(ERROR) << "Failed to allocate Graphic Buffer";
+        return false;
+    }
+
+
+    mIsInitialized = true;
+    return true;
+}
+
+bool SurroundView3dSession::setupEvs() {
+    // Reads the camera related information from the config object
+    const string evsGroupId = mIOModuleConfig->cameraConfig.evsGroupId;
+
+    // Setup for EVS
+    LOG(INFO) << "Requesting camera list";
+    mEvs->getCameraList_1_1(
+            [this, evsGroupId] (hidl_vec<CameraDesc> cameraList) {
+        LOG(INFO) << "Camera list callback received " << cameraList.size();
+        for (auto&& cam : cameraList) {
+            LOG(INFO) << "Found camera " << cam.v1.cameraId;
+            if (cam.v1.cameraId == evsGroupId) {
+                mCameraDesc = cam;
+            }
+        }
+    });
+
+    bool foundCfg = false;
+    std::unique_ptr<Stream> targetCfg(new Stream());
+
+    // This logic picks the configuration with the largest area that supports
+    // RGBA8888 format
+    int32_t maxArea = 0;
+    camera_metadata_entry_t streamCfgs;
+    if (!find_camera_metadata_entry(
+             reinterpret_cast<camera_metadata_t *>(mCameraDesc.metadata.data()),
+             ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+             &streamCfgs)) {
+        // Stream configurations are found in metadata
+        RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(
+            streamCfgs.data.i32);
+        for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
+            if (ptr->direction ==
+                ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+
+                if (ptr->width * ptr->height > maxArea) {
+                    targetCfg->id = ptr->id;
+                    targetCfg->width = ptr->width;
+                    targetCfg->height = ptr->height;
+
+                    // This client always wants below input data format
+                    targetCfg->format =
+                        static_cast<GraphicsPixelFormat>(
+                            HAL_PIXEL_FORMAT_RGBA_8888);
+
+                    maxArea = ptr->width * ptr->height;
+
+                    foundCfg = true;
+                }
+            }
+            ++ptr;
+        }
+    } else {
+        LOG(WARNING) << "No stream configuration data is found; "
+                     << "default parameters will be used.";
+    }
+
+    if (!foundCfg) {
+        LOG(INFO) << "No config was found";
+        targetCfg = nullptr;
+        return false;
+    }
+
+    string camId = mCameraDesc.v1.cameraId.c_str();
+    mCamera = mEvs->openCamera_1_1(camId.c_str(), *targetCfg);
+    if (mCamera == nullptr) {
+        LOG(ERROR) << "Failed to allocate EVS Camera interface for " << camId;
+        return false;
+    } else {
+        LOG(INFO) << "Camera " << camId << " is opened successfully";
+    }
+
+    map<string, AndroidCameraParams> cameraIdToAndroidParameters;
+    for (const auto& id : mIOModuleConfig->cameraConfig.evsCameraIds) {
+        AndroidCameraParams params;
+        if (getAndroidCameraParams(mCamera, id, params)) {
+            cameraIdToAndroidParameters.emplace(id, params);
+            LOG(INFO) << "Camera parameters are fetched successfully for "
+                      << "physical camera: " << id;
+        } else {
+            LOG(ERROR) << "Failed to get camera parameters for "
+                       << "physical camera: " << id;
+            return false;
+        }
+    }
+
+    mCameraParams =
+            convertToSurroundViewCameraParams(cameraIdToAndroidParameters);
+
+    for (auto& camera : mCameraParams) {
+        camera.size.width = targetCfg->width;
+        camera.size.height = targetCfg->height;
+        camera.circular_fov = 179;
+    }
+
+    return true;
+}
+
+bool SurroundView3dSession::startEvs() {
+    mFramesHandler = new FramesHandler(mCamera, this);
+    Return<EvsResult> result = mCamera->startVideoStream(mFramesHandler);
+    if (result != EvsResult::OK) {
+        LOG(ERROR) << "Failed to start video stream";
+        return false;
+    } else {
+        LOG(INFO) << "Video stream was started successfully";
+    }
+
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/SurroundView3dSession.h b/surround_view/service-impl/SurroundView3dSession.h
new file mode 100644
index 0000000..09f4c90
--- /dev/null
+++ b/surround_view/service-impl/SurroundView3dSession.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
+
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include "AnimationModule.h"
+#include "CoreLibSetupHelper.h"
+#include "VhalHandler.h"
+
+#include <thread>
+
+#include <ui/GraphicBuffer.h>
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+using namespace ::android::hardware::automotive::sv::V1_0;
+using namespace ::android::hardware::automotive::vehicle::V2_0;
+using namespace ::android_auto::surround_view;
+
+using ::android::hardware::Return;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+using ::std::condition_variable;
+
+using BufferDesc_1_0  = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using BufferDesc_1_1  = ::android::hardware::automotive::evs::V1_1::BufferDesc;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+class SurroundView3dSession : public ISurroundView3dSession {
+
+    /*
+     * FramesHandler:
+     * This class can be used to receive camera imagery from an IEvsCamera implementation.  It will
+     * hold onto the most recent image buffer, returning older ones.
+     * Note that the video frames are delivered on a background thread, while the control interface
+     * is actuated from the applications foreground thread.
+     */
+    class FramesHandler : public IEvsCameraStream {
+    public:
+        FramesHandler(sp<IEvsCamera> pCamera, sp<SurroundView3dSession> pSession);
+
+    private:
+        // Implementation for ::android::hardware::automotive::evs::V1_0::IEvsCameraStream
+        Return<void> deliverFrame(const BufferDesc_1_0& buffer) override;
+
+        // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream
+        Return<void> deliverFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffer) override;
+        Return<void> notify(const EvsEventDesc& event) override;
+
+        // Values initialized as startup
+        sp<IEvsCamera> mCamera;
+
+        sp<SurroundView3dSession> mSession;
+    };
+
+public:
+    // TODO(b/158479099): use strong pointer for VhalHandler
+    SurroundView3dSession(sp<IEvsEnumerator> pEvs,
+                          VhalHandler* vhalHandler,
+                          AnimationModule* animationModule,
+                          IOModuleConfig* pConfig);
+    ~SurroundView3dSession();
+    bool initialize();
+
+    // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
+    Return<SvResult> startStream(
+        const sp<ISurroundViewStream>& stream) override;
+    Return<void> stopStream() override;
+    Return<void> doneWithFrames(const SvFramesDesc& svFramesDesc) override;
+
+    // Methods from ISurroundView3dSession follow.
+    Return<SvResult> setViews(const hidl_vec<View3d>& views) override;
+    Return<SvResult> set3dConfig(const Sv3dConfig& sv3dConfig) override;
+    Return<void> get3dConfig(get3dConfig_cb _hidl_cb) override;
+    Return<SvResult>  updateOverlays(const OverlaysData& overlaysData);
+    Return<void> projectCameraPointsTo3dSurface(
+        const hidl_vec<Point2dInt>& cameraPoints,
+        const hidl_string& cameraId,
+        projectCameraPointsTo3dSurface_cb _hidl_cb);
+
+private:
+    void processFrames();
+
+    // Set up and open the Evs camera(s), triggered when session is created.
+    bool setupEvs();
+
+    // Start Evs camera video stream, triggered when SV stream is started.
+    bool startEvs();
+
+    bool handleFrames(int sequenceId);
+
+    bool copyFromBufferToPointers(BufferDesc_1_1 buffer,
+                                  SurroundViewInputBufferPointers pointers);
+
+    enum StreamStateValues {
+        STOPPED,
+        RUNNING,
+        STOPPING,
+        DEAD,
+    };
+
+    // EVS Enumerator to control the start/stop of the Evs Stream
+    sp<IEvsEnumerator> mEvs;
+
+    // Instance and metadata for the opened Evs Camera
+    sp<IEvsCamera> mCamera;
+    CameraDesc mCameraDesc;
+    vector<SurroundViewCameraParams> mCameraParams;
+
+    // Stream subscribed for the session.
+    sp<ISurroundViewStream> mStream GUARDED_BY(mAccessLock);
+    StreamStateValues mStreamState GUARDED_BY(mAccessLock);
+
+    thread mProcessThread; // The thread we'll use to process frames
+
+    // Reference to the inner class, to handle the incoming Evs frames
+    sp<FramesHandler> mFramesHandler;
+
+    // Used to signal a set of frames is ready
+    condition_variable mFramesSignal GUARDED_BY(mAccessLock);
+    bool mProcessingEvsFrames GUARDED_BY(mAccessLock);
+
+    int mSequenceId;
+
+    struct FramesRecord {
+        SvFramesDesc frames;
+        bool inUse = false;
+    };
+
+    FramesRecord mFramesRecord GUARDED_BY(mAccessLock);
+
+    // Synchronization necessary to deconflict mCaptureThread from the main service thread
+    mutex mAccessLock;
+
+    vector<View3d> mViews GUARDED_BY(mAccessLock);
+
+    Sv3dConfig mConfig GUARDED_BY(mAccessLock);
+
+    vector<string> mEvsCameraIds GUARDED_BY(mAccessLock);
+
+    unique_ptr<SurroundView> mSurroundView GUARDED_BY(mAccessLock);
+
+    vector<SurroundViewInputBufferPointers>
+        mInputPointers GUARDED_BY(mAccessLock);
+    SurroundViewResultPointer mOutputPointer GUARDED_BY(mAccessLock);
+    int mOutputWidth, mOutputHeight GUARDED_BY(mAccessLock);
+
+    sp<GraphicBuffer> mSvTexture GUARDED_BY(mAccessLock);
+
+    bool mIsInitialized GUARDED_BY(mAccessLock) = false;
+
+    VhalHandler* mVhalHandler;
+    AnimationModule* mAnimationModule;
+    IOModuleConfig* mIOModuleConfig;
+
+    std::vector<VehiclePropValue> mPropertyValues;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/SurroundViewService.cpp b/surround_view/service-impl/SurroundViewService.cpp
new file mode 100644
index 0000000..910b0ae
--- /dev/null
+++ b/surround_view/service-impl/SurroundViewService.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include "CoreLibSetupHelper.h"
+#include "SurroundViewService.h"
+
+using namespace android_auto::surround_view;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+std::mutex SurroundViewService::sLock;
+sp<SurroundViewService> SurroundViewService::sService;
+sp<SurroundView2dSession> SurroundViewService::sSurroundView2dSession;
+sp<SurroundView3dSession> SurroundViewService::sSurroundView3dSession;
+
+const std::string kCameraIds[] = {"0", "1", "2", "3"};
+static const int kVhalUpdateRate = 10;
+
+SurroundViewService::SurroundViewService() {
+    mVhalHandler = new VhalHandler();
+    mIOModule = new IOModule("/vendor/etc/automotive/sv/sv_sample_config.xml");
+}
+
+SurroundViewService::~SurroundViewService() {
+    delete mVhalHandler;
+    delete mAnimationModule;
+}
+
+sp<SurroundViewService> SurroundViewService::getInstance() {
+    std::scoped_lock<std::mutex> lock(sLock);
+    if (sService == nullptr) {
+        sService = new SurroundViewService();
+        if (!sService->initialize()) {
+            LOG(ERROR) << "Cannot initialize the service properly";
+            sService = nullptr;
+            return nullptr;
+        }
+    }
+    return sService;
+}
+
+std::vector<uint64_t> getAnimationPropertiesToRead(const AnimationConfig& animationConfig) {
+    std::set<uint64_t> propertiesSet;
+    for(const auto& animation: animationConfig.animations) {
+        for(const auto& opPair : animation.gammaOpsMap) {
+            propertiesSet.insert(opPair.first);
+        }
+
+        for(const auto& opPair : animation.textureOpsMap) {
+            propertiesSet.insert(opPair.first);
+        }
+
+        for(const auto& opPair : animation.rotationOpsMap) {
+            propertiesSet.insert(opPair.first);
+        }
+
+        for(const auto& opPair : animation.translationOpsMap) {
+            propertiesSet.insert(opPair.first);
+        }
+    }
+    std::vector<uint64_t> propertiesToRead;
+    propertiesToRead.assign(propertiesSet.begin(), propertiesSet.end());
+    return propertiesToRead;
+}
+
+bool SurroundViewService::initialize() {
+    // Get the EVS manager service
+    LOG(INFO) << "Acquiring EVS Enumerator";
+    mEvs = IEvsEnumerator::getService("default");
+    if (mEvs == nullptr) {
+        LOG(ERROR) << "getService returned NULL.  Exiting.";
+        return false;
+    }
+
+    IOStatus status = mIOModule->initialize();
+    if (status != IOStatus::OK) {
+        LOG(ERROR) << "IO Module cannot be initialized properly";
+        return false;
+    }
+
+    if (!mIOModule->getConfig(&mConfig)) {
+        LOG(ERROR) << "Cannot parse Car Config file properly";
+        return false;
+    }
+
+    // Since we only keep one instance of the SurroundViewService and initialize
+    // method is always called after the constructor, it is safe to put the
+    // allocation here and the de-allocation in service's constructor.
+    mAnimationModule = new AnimationModule(
+            mConfig.carModelConfig.carModel.partsMap,
+            mConfig.carModelConfig.carModel.texturesMap,
+            mConfig.carModelConfig.animationConfig.animations);
+
+    // Initialize the VHal Handler with update method and rate.
+    // TODO(b/157498592): The update rate should align with the EVS camera
+    // update rate.
+    if (mVhalHandler->initialize(VhalHandler::GET, kVhalUpdateRate)) {
+        // Initialize the vhal handler properties to read.
+        std::vector<uint64_t> propertiesToRead;
+
+        // Add animation properties to read if 3d and animations are enabled.
+        if (mConfig.sv3dConfig.sv3dEnabled && mConfig.sv3dConfig.sv3dAnimationsEnabled) {
+            const std::vector<uint64_t> animationPropertiesToRead =
+                    getAnimationPropertiesToRead(mConfig.carModelConfig.animationConfig);
+            propertiesToRead.insert(propertiesToRead.end(), animationPropertiesToRead.begin(),
+                    animationPropertiesToRead.end());
+        }
+
+        // Call vhal handler setPropertiesToRead with all properties.
+        if (!mVhalHandler->setPropertiesToRead(propertiesToRead)) {
+            LOG(WARNING) << "VhalHandler setPropertiesToRead failed.";
+        }
+    } else {
+        LOG(WARNING) << "VhalHandler cannot be initialized properly";
+    }
+
+    return true;
+}
+
+Return<void> SurroundViewService::getCameraIds(getCameraIds_cb _hidl_cb) {
+    hidl_vec<hidl_string> cameraIds = {kCameraIds[0], kCameraIds[1],
+        kCameraIds[2], kCameraIds[3]};
+    _hidl_cb(cameraIds);
+    return {};
+}
+
+Return<void> SurroundViewService::start2dSession(start2dSession_cb _hidl_cb) {
+    LOG(DEBUG) << __FUNCTION__;
+    std::scoped_lock<std::mutex> lock(sLock);
+
+    if (sSurroundView2dSession != nullptr) {
+        LOG(WARNING) << "Only one 2d session is supported at the same time";
+        _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
+    } else {
+        sSurroundView2dSession = new SurroundView2dSession(mEvs, &mConfig);
+        if (sSurroundView2dSession->initialize()) {
+            _hidl_cb(sSurroundView2dSession, SvResult::OK);
+        } else {
+            _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
+        }
+    }
+    return {};
+}
+
+Return<SvResult> SurroundViewService::stop2dSession(
+    const sp<ISurroundView2dSession>& sv2dSession) {
+    LOG(DEBUG) << __FUNCTION__;
+    std::scoped_lock<std::mutex> lock(sLock);
+
+    if (sv2dSession != nullptr && sv2dSession == sSurroundView2dSession) {
+        sSurroundView2dSession = nullptr;
+        return SvResult::OK;
+    } else {
+        LOG(ERROR) << __FUNCTION__ << ": Invalid argument";
+        return SvResult::INVALID_ARG;
+    }
+}
+
+Return<void> SurroundViewService::start3dSession(start3dSession_cb _hidl_cb) {
+    LOG(DEBUG) << __FUNCTION__;
+    std::scoped_lock<std::mutex> lock(sLock);
+
+    if (sSurroundView3dSession != nullptr) {
+        LOG(WARNING) << "Only one 3d session is supported at the same time";
+        _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
+    } else {
+        sSurroundView3dSession = new SurroundView3dSession(mEvs,
+                                                           mVhalHandler,
+                                                           mAnimationModule,
+                                                           &mConfig);
+        if (sSurroundView3dSession->initialize()) {
+            _hidl_cb(sSurroundView3dSession, SvResult::OK);
+        } else {
+            _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
+        }
+    }
+    return {};
+}
+
+Return<SvResult> SurroundViewService::stop3dSession(
+    const sp<ISurroundView3dSession>& sv3dSession) {
+    LOG(DEBUG) << __FUNCTION__;
+    std::scoped_lock<std::mutex> lock(sLock);
+
+    if (sv3dSession != nullptr && sv3dSession == sSurroundView3dSession) {
+        sSurroundView3dSession = nullptr;
+        return SvResult::OK;
+    } else {
+        LOG(ERROR) << __FUNCTION__ << ": Invalid argument";
+        return SvResult::INVALID_ARG;
+    }
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/SurroundViewService.h b/surround_view/service-impl/SurroundViewService.h
new file mode 100644
index 0000000..6950a27
--- /dev/null
+++ b/surround_view/service-impl/SurroundViewService.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "SurroundView2dSession.h"
+#include "SurroundView3dSession.h"
+#include "AnimationModule.h"
+#include "IOModule.h"
+#include "VhalHandler.h"
+
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <thread>
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::hardware::Return;
+using ::android::sp;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+class SurroundViewService : public ISurroundViewService {
+public:
+    // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewService follow.
+    Return<void> getCameraIds(getCameraIds_cb _hidl_cb) override;
+    Return<void> start2dSession(start2dSession_cb _hidl_cb) override;
+    Return<SvResult> stop2dSession(
+        const sp<ISurroundView2dSession>& sv2dSession) override;
+
+    Return<void> start3dSession(start3dSession_cb _hidl_cb) override;
+    Return<SvResult> stop3dSession(
+        const sp<ISurroundView3dSession>& sv3dSession) override;
+
+    static sp<SurroundViewService> getInstance();
+private:
+    SurroundViewService();
+    ~SurroundViewService();
+
+    VhalHandler* mVhalHandler;
+    AnimationModule* mAnimationModule;
+    IOModule* mIOModule;
+    IOModuleConfig mConfig;
+
+    bool initialize();
+    sp<IEvsEnumerator> mEvs;
+
+    static std::mutex sLock;
+    static sp<SurroundViewService> sService GUARDED_BY(sLock);
+
+    static sp<SurroundView2dSession> sSurroundView2dSession GUARDED_BY(sLock);
+    static sp<SurroundView3dSession> sSurroundView3dSession GUARDED_BY(sLock);
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/SurroundViewSessionTests.cpp b/surround_view/service-impl/SurroundViewSessionTests.cpp
new file mode 100644
index 0000000..b694aaf
--- /dev/null
+++ b/surround_view/service-impl/SurroundViewSessionTests.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SurroundViewSessionTests"
+
+#include "mock-evs/MockEvsEnumerator.h"
+#include "mock-evs/MockSurroundViewCallback.h"
+
+#include "IOModule.h"
+#include "SurroundView2dSession.h"
+#include "SurroundView3dSession.h"
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+
+#include <android-base/logging.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+namespace {
+
+const char* kSvConfigFilename = "vendor/etc/automotive/sv/sv_sample_config.xml";
+
+TEST(SurroundViewSessionTests, startAndStopSurroundView2dSession) {
+    sp<IEvsEnumerator> fakeEvs = new MockEvsEnumerator();
+    IOModule* ioModule = new IOModule(kSvConfigFilename);
+    EXPECT_EQ(ioModule->initialize(), IOStatus::OK);
+
+    IOModuleConfig config;
+    ioModule->getConfig(&config);
+
+    sp<SurroundView2dSession> sv2dSession =
+            new SurroundView2dSession(fakeEvs, &config);
+
+    EXPECT_TRUE(sv2dSession->initialize());
+
+    sp<MockSurroundViewCallback> sv2dCallback =
+            new MockSurroundViewCallback(sv2dSession);
+
+    EXPECT_EQ(sv2dSession->startStream(sv2dCallback), SvResult::OK);
+
+    sv2dSession->stopStream();
+}
+
+TEST(SurroundViewSessionTests, startAndStopSurroundView3dSession) {
+    sp<IEvsEnumerator> fakeEvs = new MockEvsEnumerator();
+    IOModule* ioModule = new IOModule(kSvConfigFilename);
+    EXPECT_EQ(ioModule->initialize(), IOStatus::OK);
+
+    IOModuleConfig config;
+    ioModule->getConfig(&config);
+
+    sp<SurroundView3dSession> sv3dSession =
+            new SurroundView3dSession(fakeEvs,
+                                      nullptr, /* VhalHandler */
+                                      nullptr, /* AnimationModule */
+                                      &config);
+
+    EXPECT_TRUE(sv3dSession->initialize());
+
+    sp<MockSurroundViewCallback> sv3dCallback =
+            new MockSurroundViewCallback(sv3dSession);
+
+    View3d view = {};
+    vector<View3d> views;
+    views.emplace_back(view);
+    sv3dSession->setViews(views);
+
+    EXPECT_EQ(sv3dSession->startStream(sv3dCallback), SvResult::OK);
+
+    sv3dSession->stopStream();
+}
+
+}  // namespace
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/VhalHandler.cpp b/surround_view/service-impl/VhalHandler.cpp
new file mode 100644
index 0000000..79ced83
--- /dev/null
+++ b/surround_view/service-impl/VhalHandler.cpp
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "VhalHandler.h"
+
+#include <chrono>
+#include <cmath>
+#include <condition_variable>
+#include <mutex>
+
+#include <android-base/logging.h>
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include <time.h>
+#include <utils/SystemClock.h>
+#include <utils/Timers.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+using vehicle::V2_0::IVehicle;
+using vehicle::V2_0::StatusCode;
+using vehicle::V2_0::VehiclePropertyType;
+using vehicle::V2_0::VehiclePropValue;
+
+bool VhalHandler::initialize(UpdateMethod updateMethod, int rate) {
+    LOG(DEBUG) << __FUNCTION__;
+    std::scoped_lock<std::mutex> lock(mAccessLock);
+
+    if (mIsInitialized) {
+        LOG(ERROR) << "Vehicle Handler is already initialized.";
+        return false;
+    }
+
+    LOG(INFO) << "Connecting to Vehicle HAL";
+    mVhalServicePtr = IVehicle::getService();
+    if (mVhalServicePtr.get() == nullptr) {
+        LOG(ERROR) << "Vehicle HAL getService failed.";
+        return false;
+    }
+
+    if (rate < 1 || rate > 100) {
+        LOG(ERROR) << "Rate must be in the range [1, 100].";
+        return false;
+    }
+
+    if (mUpdateMethod == UpdateMethod::SUBSCRIBE) {
+        LOG(ERROR) << "Update method Subscribe is not currently implemented.";
+        return false;
+    }
+
+    mUpdateMethod = updateMethod;
+    mRate = rate;
+    mIsInitialized = true;
+    mIsUpdateActive = false;
+
+    return true;
+}
+
+void VhalHandler::pollProperties() {
+    LOG(DEBUG) << "Polling thread started.";
+    while (true) {
+        nsecs_t startTime = elapsedRealtimeNano();
+
+        // Copy properties to read.
+        std::vector<VehiclePropValue> propertiesToRead;
+        int rate;
+        {
+            std::scoped_lock<std::mutex> lock(mAccessLock);
+            if (!mIsUpdateActive) {
+                LOG(DEBUG) << "Exiting polling thread.";
+                break;
+            }
+            propertiesToRead = mPropertiesToRead;
+            rate = mRate;
+        }
+
+        // Make get call for each VHAL property.
+        // Write to back property values, note lock is not needed as only this thread uses it.
+        std::vector<VehiclePropValue> vehiclePropValuesUpdated;
+        for (auto& propertyToRead : propertiesToRead) {
+            StatusCode statusResult;
+            VehiclePropValue propValueResult;
+            mVhalServicePtr->get(propertyToRead,
+                                 [&statusResult,
+                                  &propValueResult](StatusCode status,
+                                                    const VehiclePropValue& propValue) {
+                                     statusResult = status;
+                                     propValueResult = propValue;
+                                 });
+            if (statusResult != StatusCode::OK) {
+                LOG(WARNING) << "Failed to read vhal property: " << propertyToRead.prop
+                             << ", with status code: " << static_cast<int32_t>(statusResult);
+            } else {
+                vehiclePropValuesUpdated.push_back(propValueResult);
+            }
+        }
+
+        // Update property values by swapping with updated property values.
+        {
+            std::scoped_lock<std::mutex> lock(mAccessLock);
+            std::swap(mPropertyValues, vehiclePropValuesUpdated);
+        }
+
+        std::unique_lock<std::mutex> sleepLock(mPollThreadSleepMutex);
+        // Sleep to generate frames at kTargetFrameRate.
+        // rate is number of updates per seconds,
+        // Target time period between two updates in nano-seconds = (10 ^ 9) / rate.
+        const nsecs_t kTargetRateNs = std::pow(10, 9) / mRate;
+        const nsecs_t now = elapsedRealtimeNano();
+        const nsecs_t workTimeNs = now - startTime;
+        const nsecs_t sleepDurationNs = kTargetRateNs - workTimeNs;
+        if (sleepDurationNs > 0) {
+            // Sleep for sleepDurationNs or until a stop signal is received.
+            mPollThreadCondition.wait_for(sleepLock, std::chrono::nanoseconds(sleepDurationNs),
+                                          [this]() { return mPollStopSleeping; });
+        }
+    }
+}
+
+bool VhalHandler::startPropertiesUpdate() {
+    LOG(DEBUG) << __FUNCTION__;
+    std::scoped_lock<std::mutex> lock(mAccessLock);
+
+    // Check Vhal service is initialized.
+    if (!mIsInitialized) {
+        LOG(ERROR) << "VHAL handler not initialized.";
+        return false;
+    }
+
+    if (mIsUpdateActive) {
+        LOG(ERROR) << "Polling is already started.";
+        return false;
+    }
+
+    mIsUpdateActive = true;
+
+    {
+        std::scoped_lock<std::mutex> sleepLock(mPollThreadSleepMutex);
+        mPollStopSleeping = false;
+    }
+
+    // Start polling thread if updated method is GET.
+    if (mUpdateMethod == UpdateMethod::GET) {
+        mPollingThread = std::thread([this]() { pollProperties(); });
+    }
+
+    return true;
+}
+
+bool VhalHandler::setPropertiesToRead(const std::vector<VehiclePropValue>& propertiesToRead) {
+    LOG(DEBUG) << __FUNCTION__;
+    std::scoped_lock<std::mutex> lock(mAccessLock);
+
+    // Replace property ids to read.
+    mPropertiesToRead = propertiesToRead;
+
+    return true;
+}
+
+bool VhalHandler::setPropertiesToRead(const std::vector<uint64_t>& propertiesToRead) {
+    LOG(DEBUG) << __FUNCTION__;
+    std::vector<VehiclePropValue> vhalPropValues;
+    for (const auto& property : propertiesToRead) {
+        VehiclePropValue propValue;
+        // Higher 32 bits = property id, lower 32 bits = area id.
+        propValue.areaId = property & 0xFFFFFFFF;
+        propValue.prop = (property >> 32) & 0xFFFFFFFF;
+        vhalPropValues.push_back(propValue);
+    }
+    return setPropertiesToRead(vhalPropValues);
+}
+
+bool VhalHandler::getPropertyValues(std::vector<VehiclePropValue>* property_values) {
+    LOG(DEBUG) << __FUNCTION__;
+    std::scoped_lock<std::mutex> lock(mAccessLock);
+
+    // Check Vhal service is initialized.
+    if (!mIsInitialized) {
+        LOG(ERROR) << "VHAL handler not initialized.";
+        return false;
+    }
+
+    // Copy current property values to argument.
+    *property_values = mPropertyValues;
+
+    return true;
+}
+
+bool VhalHandler::stopPropertiesUpdate() {
+    LOG(DEBUG) << __FUNCTION__;
+    {
+        std::scoped_lock<std::mutex> lock(mAccessLock);
+
+        // Check Vhal service is initialized.
+        if (!mIsInitialized) {
+            LOG(ERROR) << "VHAL handler not initialized.";
+            return false;
+        }
+
+        if (!mIsUpdateActive) {
+            LOG(ERROR) << "Polling is already stopped.";
+            return false;
+        }
+
+        mIsUpdateActive = false;
+    }
+
+    // Wake up the polling thread.
+    {
+        std::scoped_lock<std::mutex> sleepLock(mPollThreadSleepMutex);
+        mPollStopSleeping = true;
+    }
+    mPollThreadCondition.notify_one();
+
+    // Wait for polling thread to exit.
+    mPollingThread.join();
+
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/VhalHandler.h b/surround_view/service-impl/VhalHandler.h
new file mode 100644
index 0000000..029e414
--- /dev/null
+++ b/surround_view/service-impl/VhalHandler.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SURROUND_VIEW_SERVICE_IMPL_VHALHANDLER_H_
+#define SURROUND_VIEW_SERVICE_IMPL_VHALHANDLER_H_
+
+#include <mutex>
+#include <thread>
+#include <vector>
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+
+using android::sp;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+// Vhal handler cache vhal properties needed and updates them at a fixed rate.
+class VhalHandler {
+public:
+    // Enumeration for the method to use for updating the VHAL properties,
+    enum UpdateMethod {
+        // Makes a periodic get call in a polling thread.
+        // Use when VHAL implementation does not support multiple clients in subscribe calls.
+        GET = 0,
+
+        // Subscribes to the VHAL properties, to receive values periodically in a callback.
+        // Use when VHAL implementation support multiple clients in subscribe calls.
+        // NOTE: Currently not implemented.
+        SUBSCRIBE
+    };
+
+    // Empty vhal handler constructor.
+    VhalHandler() : mIsInitialized(false), mUpdateMethod(GET), mRate(0), mIsUpdateActive(false) {}
+
+    // Initializes the VHAL handler.
+    // Valid range of rate is [1, 100] Hz.
+    // For subscribe the rate must be within each properties min and maximum sampling rate.
+    // For get, higher rate may result in excessive binder calls and increased latency.
+    bool initialize(UpdateMethod updateMethod, int rate);
+
+    // List of VHAL properties to read, can include vendor specific VHAL properties.
+    // The updated method determines if properties are updated using get or subscribe calls.
+    bool setPropertiesToRead(const std::vector<vehicle::V2_0::VehiclePropValue>& propertiesToRead);
+
+    // Convenience function to set vhal properties in a format returned from IO Module.
+    // uint64_t = (32 bits vhal property id) | (32 bits area id).
+    bool setPropertiesToRead(const std::vector<uint64_t>& propertiesToRead);
+
+    // Starts updating the VHAL properties with the specified rate.
+    bool startPropertiesUpdate();
+
+    // Gets the last updated VHAL property values.
+    // property_values is empty if startPropertiesUpdate() has not been called.
+    bool getPropertyValues(std::vector<vehicle::V2_0::VehiclePropValue>* property_values);
+
+    // Stops updating the VHAL properties.
+    // For Get method, waits for the polling thread to exit.
+    bool stopPropertiesUpdate();
+
+private:
+    // Thread function to poll properties.
+    void pollProperties();
+
+    // Pointer to VHAL service.
+    sp<vehicle::V2_0::IVehicle> mVhalServicePtr;
+
+    // Mutex for locking VHAL properties data.
+    std::mutex mAccessLock;
+
+    // Initialized parameters.
+    bool mIsInitialized;
+    UpdateMethod mUpdateMethod;
+    int mRate;
+    bool mIsUpdateActive;
+
+    // GET method related data members.
+    std::thread mPollingThread;
+    std::mutex mPollThreadSleepMutex;
+    std::condition_variable mPollThreadCondition;
+    bool mPollStopSleeping;
+
+    // List of properties to read.
+    std::vector<vehicle::V2_0::VehiclePropValue> mPropertiesToRead;
+
+    // Updated list of property values.
+    std::vector<vehicle::V2_0::VehiclePropValue> mPropertyValues;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // SURROUND_VIEW_SERVICE_IMPL_VHALHANDLER_H_
diff --git a/surround_view/service-impl/VhalHandlerTests.cpp b/surround_view/service-impl/VhalHandlerTests.cpp
new file mode 100644
index 0000000..cd7c0e3
--- /dev/null
+++ b/surround_view/service-impl/VhalHandlerTests.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VhalHandlerTests"
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include "VhalHandler.h"
+
+#include <gtest/gtest.h>
+#include <time.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+namespace {
+
+using vehicle::V2_0::VehicleArea;
+using vehicle::V2_0::VehicleProperty;
+
+void SetSamplePropertiesToRead(VhalHandler* vhalHandler) {
+    std::vector<vehicle::V2_0::VehiclePropValue> propertiesToRead;
+    vehicle::V2_0::VehiclePropValue propertyRead;
+    propertyRead.prop = static_cast<int32_t>(VehicleProperty::INFO_MAKE);
+    propertiesToRead.push_back(propertyRead);
+    ASSERT_TRUE(vhalHandler->setPropertiesToRead(propertiesToRead));
+}
+
+void SetSamplePropertiesToReadInt64(VhalHandler* vhalHandler) {
+    std::vector<uint64_t> propertiesToRead;
+    uint64_t propertyInt64 = (static_cast<uint64_t>(VehicleProperty::INFO_MAKE) << 32) |
+            static_cast<uint64_t>(VehicleArea::GLOBAL);
+    propertiesToRead.push_back(propertyInt64);
+    ASSERT_TRUE(vhalHandler->setPropertiesToRead(propertiesToRead));
+}
+
+TEST(VhalhandlerTests, UninitializedStartFail) {
+    VhalHandler vhalHandler;
+    ASSERT_FALSE(vhalHandler.startPropertiesUpdate());
+}
+
+TEST(VhalhandlerTests, StartStopSuccess) {
+    VhalHandler vhalHandler;
+    ASSERT_TRUE(vhalHandler.initialize(VhalHandler::UpdateMethod::GET, 10));
+    SetSamplePropertiesToRead(&vhalHandler);
+    ASSERT_TRUE(vhalHandler.startPropertiesUpdate());
+    ASSERT_TRUE(vhalHandler.stopPropertiesUpdate());
+}
+
+TEST(VhalhandlerTests, StopTwiceFail) {
+    VhalHandler vhalHandler;
+    ASSERT_TRUE(vhalHandler.initialize(VhalHandler::UpdateMethod::GET, 10));
+    SetSamplePropertiesToRead(&vhalHandler);
+    ASSERT_TRUE(vhalHandler.startPropertiesUpdate());
+    ASSERT_TRUE(vhalHandler.stopPropertiesUpdate());
+    ASSERT_FALSE(vhalHandler.stopPropertiesUpdate());
+}
+
+TEST(VhalhandlerTests, NoStartFail) {
+    VhalHandler vhalHandler;
+    ASSERT_TRUE(vhalHandler.initialize(VhalHandler::UpdateMethod::GET, 10));
+    SetSamplePropertiesToRead(&vhalHandler);
+    ASSERT_FALSE(vhalHandler.stopPropertiesUpdate());
+}
+
+TEST(VhalhandlerTests, StartAgainSuccess) {
+    VhalHandler vhalHandler;
+    ASSERT_TRUE(vhalHandler.initialize(VhalHandler::UpdateMethod::GET, 10));
+    SetSamplePropertiesToRead(&vhalHandler);
+    ASSERT_TRUE(vhalHandler.startPropertiesUpdate());
+    ASSERT_TRUE(vhalHandler.stopPropertiesUpdate());
+    ASSERT_TRUE(vhalHandler.startPropertiesUpdate());
+    ASSERT_TRUE(vhalHandler.stopPropertiesUpdate());
+}
+
+TEST(VhalhandlerTests, GetMethodSuccess) {
+    VhalHandler vhalHandler;
+    ASSERT_TRUE(vhalHandler.initialize(VhalHandler::UpdateMethod::GET, 10));
+
+    SetSamplePropertiesToRead(&vhalHandler);
+
+    ASSERT_TRUE(vhalHandler.startPropertiesUpdate());
+    sleep(1);
+    std::vector<vehicle::V2_0::VehiclePropValue> propertyValues;
+    EXPECT_TRUE(vhalHandler.getPropertyValues(&propertyValues));
+    EXPECT_EQ(propertyValues.size(), 1);
+
+    EXPECT_TRUE(vhalHandler.stopPropertiesUpdate());
+}
+
+TEST(VhalhandlerTests, GetMethodInt64Success) {
+    VhalHandler vhalHandler;
+    ASSERT_TRUE(vhalHandler.initialize(VhalHandler::UpdateMethod::GET, 10));
+
+    SetSamplePropertiesToReadInt64(&vhalHandler);
+
+    ASSERT_TRUE(vhalHandler.startPropertiesUpdate());
+    sleep(1);
+    std::vector<vehicle::V2_0::VehiclePropValue> propertyValues;
+    EXPECT_TRUE(vhalHandler.getPropertyValues(&propertyValues));
+    EXPECT_EQ(propertyValues.size(), 1);
+
+    EXPECT_TRUE(vhalHandler.stopPropertiesUpdate());
+}
+
+}  // namespace
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/android.automotive.sv.service@1.0-impl.rc b/surround_view/service-impl/android.automotive.sv.service@1.0-impl.rc
new file mode 100644
index 0000000..4207e8f
--- /dev/null
+++ b/surround_view/service-impl/android.automotive.sv.service@1.0-impl.rc
@@ -0,0 +1,5 @@
+service sv_service_impl /vendor/bin/android.automotive.sv.service@1.0-impl
+    class hal
+    user automotive_evs
+    group automotive_evs
+    disabled
diff --git a/surround_view/service-impl/core_lib.h b/surround_view/service-impl/core_lib.h
new file mode 100644
index 0000000..7a9e67d
--- /dev/null
+++ b/surround_view/service-impl/core_lib.h
@@ -0,0 +1,825 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIRELESS_ANDROID_AUTOMOTIVE_CAML_SURROUND_VIEW_CORE_LIB_H_
+#define WIRELESS_ANDROID_AUTOMOTIVE_CAML_SURROUND_VIEW_CORE_LIB_H_
+
+#include <array>
+#include <cstdint>
+#include <map>
+#include <string>
+#include <vector>
+
+namespace android_auto {
+namespace surround_view {
+
+// bounding box (bb)
+// It is used to describe the car model bounding box in 3D.
+// It assumes z = 0 and only x, y are used in the struct.
+// Of course, it is compatible to the 2d version bounding box and may be used
+// for other bounding box purpose (e.g., 2d bounding box in image).
+struct BoundingBox {
+    // (x,y) is bounding box's top left corner coordinate.
+    float x;
+    float y;
+
+    // (width, height) is the size of the bounding box.
+    float width;
+    float height;
+
+    BoundingBox() : x(0.0f), y(0.0f), width(0.0f), height(0.0f) {}
+
+    BoundingBox(float x_, float y_, float width_, float height_) :
+          x(x_), y(y_), width(width_), height(height_) {}
+
+    BoundingBox(const BoundingBox& bb_) :
+          x(bb_.x), y(bb_.y), width(bb_.width), height(bb_.height) {}
+
+    // Checks if data is valid.
+    bool IsValid() const { return width >= 0 && height >= 0; }
+
+    bool operator==(const BoundingBox& rhs) const {
+        return x == rhs.x && y == rhs.y && width == rhs.width && height == rhs.height;
+    }
+
+    BoundingBox& operator=(const BoundingBox& rhs) {
+        x = rhs.x;
+        y = rhs.y;
+        width = rhs.width;
+        height = rhs.height;
+        return *this;
+    }
+};
+
+template <typename T>
+struct Coordinate2dBase {
+    // x coordinate.
+    T x;
+
+    // y coordinate.
+    T y;
+
+    Coordinate2dBase() : x(0), y(0) {}
+
+    Coordinate2dBase(T x_, T y_) : x(x_), y(y_) {}
+
+    bool operator==(const Coordinate2dBase& rhs) const { return x == rhs.x && y == rhs.y; }
+
+    Coordinate2dBase& operator=(const Coordinate2dBase& rhs) {
+        x = rhs.x;
+        y = rhs.y;
+        return *this;
+    }
+};
+
+// integer type size.
+typedef Coordinate2dBase<int> Coordinate2dInteger;
+
+// float type size.
+typedef Coordinate2dBase<float> Coordinate2dFloat;
+
+struct Coordinate3dFloat {
+    // x coordinate.
+    float x;
+
+    // y coordinate.
+    float y;
+
+    // z coordinate.
+    float z;
+
+    Coordinate3dFloat() : x(0), y(0), z(0) {}
+
+    Coordinate3dFloat(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {}
+
+    bool operator==(const Coordinate3dFloat& rhs) const { return x == rhs.x && y == rhs.y; }
+
+    Coordinate3dFloat& operator=(const Coordinate3dFloat& rhs) {
+        x = rhs.x;
+        y = rhs.y;
+        return *this;
+    }
+};
+
+//  pixel weight used for illumination assessment
+struct PixelWeight {
+    // x and y are the coordinates (absolute value) in image space.
+    // pixel coordinate x in horizontal direction.
+    float x;
+
+    // pixel coordinate y in vertical direction.
+    float y;
+
+    // pixel weight, range in [0, 1].
+    float weight;
+
+    PixelWeight() : x(-1), y(-1), weight(0) {}
+
+    PixelWeight(int x_, int y_, int weight_) : x(x_), y(y_), weight(weight_) {}
+
+    bool operator==(const PixelWeight& rhs) const {
+        return x == rhs.x && y == rhs.y && weight == rhs.weight;
+    }
+
+    PixelWeight& operator=(const PixelWeight& rhs) {
+        x = rhs.x;
+        y = rhs.y;
+        weight = rhs.weight;
+        return *this;
+    }
+};
+
+// base size 2d type template.
+template <typename T>
+struct Size2dBase {
+    // width of size.
+    T width;
+
+    // height of size.
+    T height;
+
+    Size2dBase() : width(0), height(0) {}
+
+    Size2dBase(T width_, T height_) : width(width_), height(height_) {}
+
+    bool IsValid() const { return width > 0 && height > 0; }
+
+    bool operator==(const Size2dBase& rhs) const {
+        return width == rhs.width && height == rhs.height;
+    }
+
+    Size2dBase& operator=(const Size2dBase& rhs) {
+        width = rhs.width;
+        height = rhs.height;
+        return *this;
+    }
+};
+
+// integer type size.
+typedef Size2dBase<int> Size2dInteger;
+
+// float type size.
+typedef Size2dBase<float> Size2dFloat;
+
+//  surround view 2d parameters
+struct SurroundView2dParams {
+    // surround view 2d image resolution (width, height).
+    Size2dInteger resolution;
+
+    // the physical size of surround view 2d area in surround view coordinate.
+    // (surround view coordinate is defined as X rightward, Y forward and
+    // the origin lies on the center of the (symmetric) bowl (ground).
+    // When bowl is not used, surround view coordinate origin lies on the
+    // center of car model bounding box.)
+    // The unit should be consistent with camera extrinsics (translation).
+    Size2dFloat physical_size;
+
+    // the center of surround view 2d area in surround view coordinate
+    // (consistent with extrinsics coordinate).
+    Coordinate2dFloat physical_center;
+
+    // Enumeration for list of 2d blending types.
+    enum BlendingType { MULTIBAND = 0, ALPHA };
+
+    // Blending type for high quality preset.
+    BlendingType high_quality_blending;
+
+    // Blending type for low quality preset.
+    BlendingType low_quality_blending;
+
+    SurroundView2dParams() :
+          resolution{0, 0},
+          physical_size{0.0f, 0.0f},
+          physical_center{0.0f, 0.0f},
+          high_quality_blending(BlendingType::MULTIBAND),
+          low_quality_blending(BlendingType::ALPHA) {}
+
+    SurroundView2dParams(Size2dInteger resolution_, Size2dFloat physical_size_,
+                         Coordinate2dFloat physical_center_) :
+          resolution(resolution_),
+          physical_size(physical_size_),
+          physical_center(physical_center_),
+          high_quality_blending(BlendingType::MULTIBAND),
+          low_quality_blending(BlendingType::ALPHA) {}
+
+    // Checks if data is valid.
+    bool IsValid() const { return resolution.IsValid() && physical_size.IsValid(); }
+
+    bool operator==(const SurroundView2dParams& rhs) const {
+        return resolution == rhs.resolution && physical_size == rhs.physical_size &&
+                physical_center == rhs.physical_center &&
+                high_quality_blending == rhs.high_quality_blending &&
+                low_quality_blending == rhs.low_quality_blending;
+    }
+
+    SurroundView2dParams& operator=(const SurroundView2dParams& rhs) {
+        resolution = rhs.resolution;
+        physical_size = rhs.physical_size;
+        physical_center = rhs.physical_center;
+        high_quality_blending = rhs.high_quality_blending;
+        low_quality_blending = rhs.low_quality_blending;
+        return *this;
+    }
+};
+
+//  surround view 3d parameters
+struct SurroundView3dParams {
+    // Bowl center is the origin of the surround view coordinate. If surround view
+    // coordinate is different from the global one, a coordinate system
+    // transformation function is required.
+
+    // planar area radius.
+    // Range in (0, +Inf).
+    float plane_radius;
+
+    // the number of divisions on the plane area of bowl, in the direction
+    // of the radius.
+    // Range in [1, +Inf).
+    int plane_divisions;
+
+    // bowl curve curve height.
+    // Range in (0, +Inf).
+    float curve_height;
+
+    // the number of points on bowl curve curve along radius direction.
+    // Range in [1, +Inf).
+    int curve_divisions;
+
+    // the number of points along circle (360 degrees)
+    // Range in [1, +Inf).
+    int angular_divisions;
+
+    // the parabola coefficient of bowl curve curve.
+    // The curve formula is z = a * (x^2 + y^2) for sqrt(x^2 + y^2) >
+    // plane_radius; a is curve_coefficient.
+    // Range in (0, +Inf).
+    float curve_coefficient;
+
+    // render output image size.
+    Size2dInteger resolution;
+
+    // Include shadows in high details preset.
+    bool high_details_shadows;
+
+    // Include reflections in high details preset.
+    bool high_details_reflections;
+
+    SurroundView3dParams() :
+          plane_radius(0.0f),
+          plane_divisions(0),
+          curve_height(0.0f),
+          curve_divisions(0),
+          angular_divisions(0),
+          curve_coefficient(0.0f),
+          resolution(0, 0),
+          high_details_shadows(true),
+          high_details_reflections(true) {}
+
+    SurroundView3dParams(float plane_radius_, int plane_divisions_, float curve_height_,
+                         int curve_divisions_, int angular_divisions_, float curve_coefficient_,
+                         Size2dInteger resolution_) :
+          plane_radius(plane_radius_),
+          plane_divisions(plane_divisions_),
+          curve_height(curve_height_),
+          curve_divisions(curve_divisions_),
+          angular_divisions(angular_divisions_),
+          curve_coefficient(curve_coefficient_),
+          resolution(resolution_),
+          high_details_shadows(true),
+          high_details_reflections(true) {}
+
+    // Checks if data is valid.
+    bool IsValid() const {
+        return plane_radius > 0 && plane_divisions > 0 && curve_height > 0 &&
+                angular_divisions > 0 && curve_coefficient > 0 && curve_divisions > 0 &&
+                resolution.IsValid();
+    }
+
+    bool operator==(const SurroundView3dParams& rhs) const {
+        return plane_radius == rhs.plane_radius && plane_divisions == rhs.plane_divisions &&
+                curve_height == rhs.curve_height && curve_divisions == rhs.curve_divisions &&
+                angular_divisions == rhs.angular_divisions &&
+                curve_coefficient == rhs.curve_coefficient && resolution == rhs.resolution &&
+                high_details_shadows == rhs.high_details_shadows &&
+                high_details_reflections == rhs.high_details_reflections;
+    }
+
+    SurroundView3dParams& operator=(const SurroundView3dParams& rhs) {
+        plane_radius = rhs.plane_radius;
+        plane_divisions = rhs.plane_divisions;
+        curve_height = rhs.curve_height;
+        curve_divisions = rhs.curve_divisions;
+        angular_divisions = rhs.angular_divisions;
+        curve_coefficient = rhs.curve_coefficient;
+        resolution = rhs.resolution;
+        high_details_shadows = rhs.high_details_shadows;
+        high_details_reflections = rhs.high_details_reflections;
+        return *this;
+    }
+};
+
+// surround view camera parameters with native types only.
+struct SurroundViewCameraParams {
+    // All calibration data |intrinsics|, |rvec| and |tvec|
+    // follow OpenCV format excepting using native arrays, refer:
+    // https://docs.opencv.org/3.4.0/db/d58/group__calib3d__fisheye.html
+    // camera intrinsics. It is the 1d array of camera matrix(3X3) with row first.
+    float intrinsics[9];
+
+    // lens distortion parameters.
+    float distorion[4];
+
+    // rotation vector.
+    float rvec[3];
+
+    // translation vector.
+    float tvec[3];
+
+    // camera image size (width, height).
+    Size2dInteger size;
+
+    // fisheye circular fov.
+    float circular_fov;
+
+    bool operator==(const SurroundViewCameraParams& rhs) const {
+        return (0 == std::memcmp(intrinsics, rhs.intrinsics, 9 * sizeof(float))) &&
+                (0 == std::memcmp(distorion, rhs.distorion, 4 * sizeof(float))) &&
+                (0 == std::memcmp(rvec, rhs.rvec, 3 * sizeof(float))) &&
+                (0 == std::memcmp(tvec, rhs.tvec, 3 * sizeof(float))) && size == rhs.size &&
+                circular_fov == rhs.circular_fov;
+    }
+
+    SurroundViewCameraParams& operator=(const SurroundViewCameraParams& rhs) {
+        std::memcpy(intrinsics, rhs.intrinsics, 9 * sizeof(float));
+        std::memcpy(distorion, rhs.distorion, 4 * sizeof(float));
+        std::memcpy(rvec, rhs.rvec, 3 * sizeof(float));
+        std::memcpy(tvec, rhs.tvec, 3 * sizeof(float));
+        size = rhs.size;
+        circular_fov = rhs.circular_fov;
+        return *this;
+    }
+};
+
+// 3D vertex of an overlay object.
+struct OverlayVertex {
+    // Position in 3d coordinates in world space in order X,Y,Z.
+    float pos[3];
+    // RGBA values, A is used for transparency.
+    uint8_t rgba[4];
+
+    bool operator==(const OverlayVertex& rhs) const {
+        return (0 == std::memcmp(pos, rhs.pos, 3 * sizeof(float))) &&
+                (0 == std::memcmp(rgba, rhs.rgba, 4 * sizeof(uint8_t)));
+    }
+
+    OverlayVertex& operator=(const OverlayVertex& rhs) {
+        std::memcpy(pos, rhs.pos, 3 * sizeof(float));
+        std::memcpy(rgba, rhs.rgba, 4 * sizeof(uint8_t));
+        return *this;
+    }
+};
+
+// Overlay is a list of vertices (may be a single or multiple objects in scene)
+// coming from a single source or type of sensor.
+struct Overlay {
+    // Uniqiue Id identifying each overlay.
+    uint16_t id;
+
+    // List of overlay vertices. 3 consecutive vertices form a triangle.
+    std::vector<OverlayVertex> vertices;
+
+    // Constructor initializing all member.
+    Overlay(uint16_t id_, const std::vector<OverlayVertex>& vertices_) {
+        id = id_;
+        vertices = vertices_;
+    }
+
+    // Default constructor.
+    Overlay() {
+        id = 0;
+        vertices = std::vector<OverlayVertex>();
+    }
+};
+
+// -----------   Structs related to car model  ---------------
+
+// 3D Vertex of a car model with normal and optionally texture coordinates.
+struct CarVertex {
+    // 3d position in (x, y, z).
+    std::array<float, 3> pos;
+
+    // unit normal at vertex, used for diffuse shading.
+    std::array<float, 3> normal;
+
+    // texture coordinates, valid in range [0, 1]. (-1, -1) implies no
+    // texture sampling. Note: only a single texture coordinate is currently
+    // supported per vertex. This struct will need to be extended with another
+    // tex_coord if multiple textures are needed per vertex.
+    std::array<float, 2> tex_coord;
+
+    // Default constructor.
+    CarVertex() {
+        pos = {0, 0, 0};
+        normal = {1, 0, 0};
+        tex_coord = {-1.0f, -1.0f};
+    }
+
+    CarVertex(const std::array<float, 3>& _pos, const std::array<float, 3>& _normal,
+              const std::array<float, 2> _tex_coord) :
+          pos(_pos), normal(_normal), tex_coord(_tex_coord) {}
+};
+
+// Type of texture (color, bump, procedural etc.)
+// Currently only color is supported.
+enum CarTextureType : uint32_t {
+    // Texture map is applied to all color parameters: Ka, Kd and Ks.
+    // Data type of texture is RGB with each channel a uint8_t.
+    kKa = 0,
+    kKd,
+    kKs,
+
+    // Texture for bump maps. Data type is 3 channel float.
+    kBumpMap
+};
+
+// Textures to be used for rendering car model.
+struct CarTexture {
+    // Type and number of channels are dependant on each car texture type.
+    int width;
+    int height;
+    int channels;
+    int bytes_per_channel;
+    uint8_t* data;
+
+    CarTexture() {
+        width = 0;
+        height = 0;
+        channels = 0;
+        bytes_per_channel = 0;
+        data = nullptr;
+    }
+};
+
+// Material parameters for a car part.
+// Refer to MTL properties: http://paulbourke.net/dataformats/mtl/
+struct CarMaterial {
+    // Illumination model - 0, 1, 2 currently supported
+    // 0 = Color on and Ambient off
+    // 1 = Color on and Ambient on
+    // 2 = Highlight on
+    // 3 = Reflection on and Ray trace on
+    // 4 - 10 = Reflection/Transparency options not supported,
+    //          Will default to option 3.
+    uint8_t illum;
+
+    std::array<float, 3> ka;  // Ambient RGB [0, 1]
+    std::array<float, 3> kd;  // Diffuse RGB [0, 1]
+    std::array<float, 3> ks;  // Specular RGB [0, 1]
+
+    // Dissolve factor [0, 1], 0 = full transparent, 1 = full opaque.
+    float d;
+
+    // Specular exponent typically range from 0 to 1000.
+    // A high exponent results in a tight, concentrated highlight.
+    float ns;
+
+    // Set default values of material.
+    CarMaterial() {
+        illum = 0;                // Color on, ambient off
+        ka = {0.0f, 0.0f, 0.0f};  // No ambient.
+        kd = {0.0f, 0.0f, 0.0f};  // No dissolve.
+        ks = {0.0f, 0.0f, 0.0f};  // No specular.
+        d = 1.0f;                 // Fully opaque.
+        ns = 0;                   // No specular exponent.
+    }
+
+    // Map for texture type to a string id of a texture.
+    std::map<CarTextureType, std::string> textures;
+};
+
+// Type alias for 4x4 homogenous matrix, in row-major order.
+using Mat4x4 = std::array<float, 16>;
+
+// Represents a part of a car model.
+// Each car part is a object in the car that is individually animated and
+// has the same illumination properties. A car part may contain sub parts.
+struct CarPart {
+    // Car part vertices.
+    std::vector<CarVertex> vertices;
+
+    // Properties/attributes describing car material.
+    CarMaterial material;
+
+    // Model matrix to transform the car part from object space to its parent's
+    // coordinate space.
+    // The car's vertices are transformed by performing:
+    // parent_model_mat * model_mat * car_part_vertices to transform them to the
+    // global coordinate space.
+    // Model matrix must be a homogenous matrix with orthogonal rotation matrix.
+    Mat4x4 model_mat;
+
+    // Id of parent part. Parent part's model matrix is used to animate this part.
+    // empty string implies the part has no parent.
+    std::string parent_part_id;
+
+    // Ids of child parts. If current part is animated all its child parts
+    // are animated as well. Empty vector implies part has not children.
+    std::vector<std::string> child_part_ids;
+
+    CarPart(const std::vector<CarVertex>& car_vertices, const CarMaterial& car_material,
+            const Mat4x4& car_model_mat, std::string car_parent_part_id,
+            const std::vector<std::string>& car_child_part_ids) :
+          vertices(car_vertices),
+          material(car_material),
+          model_mat(car_model_mat),
+          parent_part_id(car_parent_part_id),
+          child_part_ids(car_child_part_ids) {}
+
+    CarPart& operator=(const CarPart& car_part) {
+        this->vertices = car_part.vertices;
+        this->material = car_part.material;
+        this->model_mat = car_part.model_mat;
+        this->parent_part_id = car_part.parent_part_id;
+        this->child_part_ids = car_part.child_part_ids;
+        return *this;
+    }
+};
+
+struct AnimationParam {
+    // part id
+    std::string part_id;
+
+    // model matrix.
+    Mat4x4 model_matrix;
+
+    // bool flag indicating if the model matrix is updated from last
+    // SetAnimations() call.
+    bool is_model_update;
+
+    // gamma.
+    float gamma;
+
+    // bool flag indicating if gamma is updated from last
+    // SetAnimations() call.
+    bool is_gamma_update;
+
+    // texture id.
+    std::string texture_id;
+
+    // bool flag indicating if texture is updated from last
+    // SetAnimations() call.
+    bool is_texture_update;
+
+    // Default constructor, no animations are updated.
+    AnimationParam() {
+        is_model_update = false;
+        is_gamma_update = false;
+        is_texture_update = false;
+    }
+
+    // Constructor with car part name.
+    explicit AnimationParam(const std::string& _part_id) :
+          part_id(_part_id),
+          is_model_update(false),
+          is_gamma_update(false),
+          is_texture_update(false) {}
+
+    void SetModelMatrix(const Mat4x4& model_mat) {
+        is_model_update = true;
+        model_matrix = model_mat;
+    }
+
+    void SetGamma(float gamma_value) {
+        is_gamma_update = true;
+        gamma = gamma_value;
+    }
+
+    void SetTexture(const std::string& tex_id) {
+        is_texture_update = true;
+        texture_id = tex_id;
+    }
+};
+
+enum Format {
+    GRAY = 0,
+    RGB = 1,
+    RGBA = 2,
+};
+
+// collection of surround view static data params.
+struct SurroundViewStaticDataParams {
+    std::vector<SurroundViewCameraParams> cameras_params;
+
+    // surround view 2d parameters.
+    SurroundView2dParams surround_view_2d_params;
+
+    // surround view 3d parameters.
+    SurroundView3dParams surround_view_3d_params;
+
+    // undistortion focal length scales.
+    std::vector<float> undistortion_focal_length_scales;
+
+    // car model bounding box for 2d surround view.
+    BoundingBox car_model_bb;
+
+    // map of texture name to a car texture. Lists all textures to be
+    // used for car model rendering.
+    std::map<std::string, CarTexture> car_textures;
+
+    // map of car id to a car part. Lists all car parts to be used
+    // for car model rendering.
+    std::map<std::string, CarPart> car_parts;
+
+    SurroundViewStaticDataParams(const std::vector<SurroundViewCameraParams>& sv_cameras_params,
+                                 const SurroundView2dParams& sv_2d_params,
+                                 const SurroundView3dParams& sv_3d_params,
+                                 const std::vector<float>& scales, const BoundingBox& bb,
+                                 const std::map<std::string, CarTexture>& textures,
+                                 const std::map<std::string, CarPart>& parts) :
+          cameras_params(sv_cameras_params),
+          surround_view_2d_params(sv_2d_params),
+          surround_view_3d_params(sv_3d_params),
+          undistortion_focal_length_scales(scales),
+          car_model_bb(bb),
+          car_textures(textures),
+          car_parts(parts) {}
+};
+
+struct SurroundViewInputBufferPointers {
+    void* gpu_data_pointer;
+    void* cpu_data_pointer;
+    Format format;
+    int width;
+    int height;
+    SurroundViewInputBufferPointers() :
+          gpu_data_pointer(nullptr), cpu_data_pointer(nullptr), width(0), height(0) {}
+    SurroundViewInputBufferPointers(void* gpu_data_pointer_, void* cpu_data_pointer_,
+                                    Format format_, int width_, int height_) :
+          gpu_data_pointer(gpu_data_pointer_),
+          cpu_data_pointer(cpu_data_pointer_),
+          format(format_),
+          width(width_),
+          height(height_) {}
+};
+
+struct SurroundViewResultPointer {
+    void* data_pointer;
+    Format format;
+    int width;
+    int height;
+    bool is_data_preallocated;
+    SurroundViewResultPointer() :
+          data_pointer(nullptr), width(0), height(0), is_data_preallocated(false) {}
+
+    // Constructor with result data pointer being allocated within core lib.
+    // Use for cases when no already existing buffer is available.
+    SurroundViewResultPointer(Format format_, int width_, int height_) :
+          format(format_), width(width_), height(height_) {
+        // default formate is gray.
+        const int byte_per_pixel = format_ == RGB ? 3 : format_ == RGBA ? 4 : 1;
+        data_pointer = static_cast<void*>(new char[width * height * byte_per_pixel]);
+        is_data_preallocated = false;
+    }
+
+    // Constructor with pre-allocated data.
+    // Use for cases when results must be added to an existing allocated buffer.
+    // Example, pre-allocated buffer of a display.
+    SurroundViewResultPointer(void* data_pointer_, Format format_, int width_, int height_) :
+          data_pointer(data_pointer_),
+          format(format_),
+          width(width_),
+          height(height_),
+          is_data_preallocated(true) {}
+
+    ~SurroundViewResultPointer() {
+        if (data_pointer) {
+            // TODO(b/154365307): Fix freeing up of pre-allocated memory.
+            // if (!is_data_preallocated) {
+            //   delete[] static_cast<char*>(data_pointer);
+            // }
+            data_pointer = nullptr;
+        }
+    }
+};
+
+class SurroundView {
+public:
+    virtual ~SurroundView() = default;
+
+    // Sets SurroundView static data.
+    // For details of SurroundViewStaticDataParams, please refer to the
+    // definition.
+    virtual bool SetStaticData(const SurroundViewStaticDataParams& static_data_params) = 0;
+
+    // Starts 2d pipeline. Returns false if error occurs.
+    virtual bool Start2dPipeline() = 0;
+
+    // Starts 3d pipeline. Returns false if error occurs.
+    virtual bool Start3dPipeline() = 0;
+
+    // Stops 2d pipleline. It releases resource owned by the pipeline.
+    // Returns false if error occurs.
+    virtual void Stop2dPipeline() = 0;
+
+    // Stops 3d pipeline. It releases resource owned by the pipeline.
+    virtual void Stop3dPipeline() = 0;
+
+    // Updates 2d output resolution on-the-fly. Starts2dPipeline() must be called
+    // before this can be called. For quality assurance, the |resolution| should
+    // not be larger than the original one. This call is not thread safe and there
+    // is no sync between Get2dSurroundView() and this call.
+    virtual bool Update2dOutputResolution(const Size2dInteger& resolution) = 0;
+
+    // Updates 3d output resolution on-the-fly. Starts3dPipeline() must be called
+    // before this can be called. For quality assurance, the |resolution| should
+    // not be larger than the original one. This call is not thread safe and there
+    // is no sync between Get3dSurroundView() and this call.
+    virtual bool Update3dOutputResolution(const Size2dInteger& resolution) = 0;
+
+    // Projects camera's pixel location to surround view 2d image location.
+    // |camera_point| is the pixel location in raw camera's space.
+    // |camera_index| is the camera's index.
+    // |surround_view_2d_point| is the surround view 2d image pixel location.
+    virtual bool GetProjectionPointFromRawCameraToSurroundView2d(
+            const Coordinate2dInteger& camera_point, int camera_index,
+            Coordinate2dFloat* surround_view_2d_point) = 0;
+
+    // Projects camera's pixel location to surround view 3d bowl coordinate.
+    // |camera_point| is the pixel location in raw camera's space.
+    // |camera_index| is the camera's index.
+    // |surround_view_3d_point| is the surround view 3d vertex.
+    virtual bool GetProjectionPointFromRawCameraToSurroundView3d(
+            const Coordinate2dInteger& camera_point, int camera_index,
+            Coordinate3dFloat* surround_view_3d_point) = 0;
+
+    // Gets 2d surround view image.
+    // It takes input_pointers as input, and output is result_pointer.
+    // Please refer to the definition of SurroundViewInputBufferPointers and
+    // SurroundViewResultPointer.
+    virtual bool Get2dSurroundView(
+            const std::vector<SurroundViewInputBufferPointers>& input_pointers,
+            SurroundViewResultPointer* result_pointer) = 0;
+
+    // Gets 3d surround view image.
+    // It takes |input_pointers| and |view_matrix| as input, and output is
+    // |result_pointer|. |view_matrix| is 4 x 4 matrix.
+    // Please refer to the definition of
+    // SurroundViewInputBufferPointers and
+    // SurroundViewResultPointer.
+    virtual bool Get3dSurroundView(
+            const std::vector<SurroundViewInputBufferPointers>& input_pointers,
+            const std::array<std::array<float, 4>, 4>& view_matrix,
+            SurroundViewResultPointer* result_pointer) = 0;
+
+    // Gets 3d surround view image overload.
+    // It takes |input_pointers|, |quaternion| and |translation| as input,
+    // and output is |result_pointer|.
+    // |quaternion| is 4 x 1 array (X, Y, Z, W).
+    // It is required to be unit quaternion as rotation quaternion.
+    // |translation| is 3 X 1 array (x, y, z).
+    // Please refer to the definition of
+    // SurroundViewInputBufferPointers and
+    // SurroundViewResultPointer.
+    virtual bool Get3dSurroundView(
+            const std::vector<SurroundViewInputBufferPointers>& input_pointers,
+            const std::array<float, 4>& quaternion, const std::array<float, 3>& translation,
+            SurroundViewResultPointer* result_pointer) = 0;
+
+    // Sets 3d overlays.
+    virtual bool Set3dOverlay(const std::vector<Overlay>& overlays) = 0;
+
+    // Animates a set of car parts.
+    // Only updated car parts are included.
+    // |car_animations| is a vector of AnimationParam specifying updated
+    // car parts with updated animation parameters.
+    virtual bool SetAnimations(const std::vector<AnimationParam>& car_animations) = 0;
+
+    // for test only.
+    virtual std::vector<SurroundViewInputBufferPointers> ReadImages(const char* filename0,
+                                                                    const char* filename1,
+                                                                    const char* filename2,
+                                                                    const char* filename3) = 0;
+
+    virtual void WriteImage(const SurroundViewResultPointer result_pointerer,
+                            const char* filename) = 0;
+};
+
+SurroundView* Create();
+
+}  // namespace surround_view
+}  // namespace android_auto
+
+#endif  // WIRELESS_ANDROID_AUTOMOTIVE_CAML_SURROUND_VIEW_CORE_LIB_H_
diff --git a/surround_view/service-impl/lib/arm64/libcore_lib_shared.so b/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
new file mode 100755
index 0000000..5ca36a5
--- /dev/null
+++ b/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
Binary files differ
diff --git a/surround_view/service-impl/lib/x86-64/libcore_lib_shared.so b/surround_view/service-impl/lib/x86-64/libcore_lib_shared.so
new file mode 100755
index 0000000..7f2e039
--- /dev/null
+++ b/surround_view/service-impl/lib/x86-64/libcore_lib_shared.so
Binary files differ
diff --git a/surround_view/service-impl/lib/x86/libcore_lib_shared.so b/surround_view/service-impl/lib/x86/libcore_lib_shared.so
new file mode 100755
index 0000000..9d0f4ef
--- /dev/null
+++ b/surround_view/service-impl/lib/x86/libcore_lib_shared.so
Binary files differ
diff --git a/surround_view/service-impl/manifest_android.hardware.automotive.sv@1.0.xml b/surround_view/service-impl/manifest_android.hardware.automotive.sv@1.0.xml
new file mode 100644
index 0000000..f9e4548
--- /dev/null
+++ b/surround_view/service-impl/manifest_android.hardware.automotive.sv@1.0.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest version="1.0" type="device" >
+    <hal format="hidl">
+        <name>android.hardware.automotive.sv</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>ISurroundViewService</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/surround_view/service-impl/mock-evs/MockEvsCamera.cpp b/surround_view/service-impl/mock-evs/MockEvsCamera.cpp
new file mode 100644
index 0000000..f268e5b
--- /dev/null
+++ b/surround_view/service-impl/mock-evs/MockEvsCamera.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MockEvsCamera.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+MockEvsCamera::MockEvsCamera() {
+    mConfigManager =
+            ConfigManager::Create(
+                    "/vendor/etc/automotive/evs/evs_sample_configuration.xml");
+}
+
+Return<void> MockEvsCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) {
+    // Not implemented.
+
+    (void)_hidl_cb;
+    return {};
+}
+
+Return<EvsResult> MockEvsCamera::setMaxFramesInFlight(uint32_t bufferCount) {
+    // Not implemented.
+
+    (void)bufferCount;
+    return EvsResult::OK;
+}
+
+Return<EvsResult> MockEvsCamera::startVideoStream(
+        const ::android::sp<IEvsCameraStream_1_0>& stream) {
+    LOG(INFO) << __FUNCTION__;
+
+    (void)stream;
+    return EvsResult::OK;
+}
+
+Return<void> MockEvsCamera::doneWithFrame(const BufferDesc_1_0& buffer) {
+    // Not implemented.
+
+    (void)buffer;
+    return {};
+}
+
+Return<void> MockEvsCamera::stopVideoStream() {
+    LOG(INFO) << __FUNCTION__;
+    return {};
+}
+
+Return<int32_t> MockEvsCamera::getExtendedInfo(uint32_t opaqueIdentifier) {
+    // Not implemented.
+
+    (void)opaqueIdentifier;
+    return 0;
+}
+
+Return<EvsResult> MockEvsCamera::setExtendedInfo(uint32_t opaqueIdentifier,
+                                                 int32_t opaqueValue) {
+    // Not implemented.
+
+    (void)opaqueIdentifier;
+    (void)opaqueValue;
+    return EvsResult::OK;
+}
+
+Return<void> MockEvsCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) {
+    // Not implemented.
+
+    (void)_hidl_cb;
+    return {};
+}
+
+Return<void> MockEvsCamera::getPhysicalCameraInfo(
+        const hidl_string& deviceId, getPhysicalCameraInfo_cb _hidl_cb) {
+    CameraDesc_1_1 desc = {};
+    desc.v1.cameraId = deviceId;
+
+    unique_ptr<ConfigManager::CameraInfo>& cameraInfo =
+            mConfigManager->getCameraInfo(deviceId);
+    if (cameraInfo != nullptr) {
+        desc.metadata.setToExternal(
+                (uint8_t*)cameraInfo->characteristics,
+                get_camera_metadata_size(cameraInfo->characteristics));
+    }
+
+    _hidl_cb(desc);
+
+    return {};
+}
+
+Return<EvsResult> MockEvsCamera::doneWithFrame_1_1(
+        const hardware::hidl_vec<BufferDesc_1_1>& buffer) {
+    // Not implemented.
+
+    (void)buffer;
+    return EvsResult::OK;
+}
+
+Return<EvsResult> MockEvsCamera::setMaster() {
+    // Not implemented.
+
+    return EvsResult::OK;
+}
+
+Return<EvsResult> MockEvsCamera::forceMaster(
+        const sp<IEvsDisplay_1_0>& display) {
+    // Not implemented.
+
+    (void)display;
+    return EvsResult::OK;
+}
+
+Return<EvsResult> MockEvsCamera::unsetMaster() {
+    // Not implemented.
+
+    return EvsResult::OK;
+}
+
+Return<void> MockEvsCamera::getParameterList(getParameterList_cb _hidl_cb) {
+    // Not implemented.
+
+    (void)_hidl_cb;
+    return {};
+}
+
+Return<void> MockEvsCamera::getIntParameterRange(
+        CameraParam id, getIntParameterRange_cb _hidl_cb) {
+    // Not implemented.
+
+    (void)id;
+    (void)_hidl_cb;
+    return {};
+}
+
+Return<void> MockEvsCamera::setIntParameter(CameraParam id, int32_t value,
+                                            setIntParameter_cb _hidl_cb) {
+    // Not implemented.
+
+    (void)id;
+    (void)value;
+    (void)_hidl_cb;
+    return {};
+}
+
+Return<void> MockEvsCamera::getIntParameter(
+        CameraParam id, getIntParameter_cb _hidl_cb) {
+    // Not implemented.
+
+    (void)id;
+    (void)_hidl_cb;
+    return {};
+}
+
+Return<EvsResult> MockEvsCamera::setExtendedInfo_1_1(
+    uint32_t opaqueIdentifier, const hidl_vec<uint8_t>& opaqueValue) {
+    // Not implemented.
+
+    (void)opaqueIdentifier;
+    (void)opaqueValue;
+    return EvsResult::OK;
+}
+
+Return<void> MockEvsCamera::getExtendedInfo_1_1(
+        uint32_t opaqueIdentifier, getExtendedInfo_1_1_cb _hidl_cb) {
+    // Not implemented.
+
+    (void)opaqueIdentifier;
+    (void)_hidl_cb;
+    return {};
+}
+
+Return<void> MockEvsCamera::importExternalBuffers(
+        const hidl_vec<BufferDesc_1_1>& buffers,
+        importExternalBuffers_cb _hidl_cb) {
+    // Not implemented.
+
+    (void)buffers;
+    (void)_hidl_cb;
+    return {};
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/mock-evs/MockEvsCamera.h b/surround_view/service-impl/mock-evs/MockEvsCamera.h
new file mode 100644
index 0000000..d393702
--- /dev/null
+++ b/surround_view/service-impl/mock-evs/MockEvsCamera.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+
+#include <ConfigManager.h>
+
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using ::android::hardware::automotive::evs::V1_1::CameraParam;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
+using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc;
+using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
+using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream;
+using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using IEvsEnumerator_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsEnumerator;
+
+// A simplified implementation for Evs Camera. Only necessary methods are
+// implemented.
+class MockEvsCamera : public IEvsCamera_1_1 {
+public:
+    MockEvsCamera();
+
+    // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
+    Return<void> getCameraInfo(getCameraInfo_cb _hidl_cb) override;
+    Return<EvsResult> setMaxFramesInFlight(uint32_t bufferCount) override;
+    Return<EvsResult> startVideoStream(const ::android::sp<IEvsCameraStream_1_0>& stream) override;
+    Return<void> doneWithFrame(const BufferDesc_1_0& buffer) override;
+    Return<void> stopVideoStream() override;
+    Return<int32_t> getExtendedInfo(uint32_t opaqueIdentifier) override;
+    Return<EvsResult> setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override;
+
+    // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
+    Return<void> getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) override;
+    Return<void> getPhysicalCameraInfo(const hidl_string& deviceId,
+                                       getPhysicalCameraInfo_cb _hidl_cb) override;
+    Return<EvsResult> doneWithFrame_1_1(const hardware::hidl_vec<BufferDesc_1_1>& buffer) override;
+    Return<EvsResult> pauseVideoStream() override { return EvsResult::UNDERLYING_SERVICE_ERROR; }
+    Return<EvsResult> resumeVideoStream() override { return EvsResult::UNDERLYING_SERVICE_ERROR; }
+    Return<EvsResult> setMaster() override;
+    Return<EvsResult> forceMaster(const sp<IEvsDisplay_1_0>& display) override;
+    Return<EvsResult> unsetMaster() override;
+    Return<void> getParameterList(getParameterList_cb _hidl_cb) override;
+    Return<void> getIntParameterRange(CameraParam id, getIntParameterRange_cb _hidl_cb) override;
+    Return<void> setIntParameter(CameraParam id, int32_t value,
+                                 setIntParameter_cb _hidl_cb) override;
+    Return<void> getIntParameter(CameraParam id, getIntParameter_cb _hidl_cb) override;
+    Return<EvsResult> setExtendedInfo_1_1(uint32_t opaqueIdentifier,
+                                          const hidl_vec<uint8_t>& opaqueValue) override;
+    Return<void> getExtendedInfo_1_1(uint32_t opaqueIdentifier,
+                                     getExtendedInfo_1_1_cb _hidl_cb) override;
+    Return<void> importExternalBuffers(const hidl_vec<BufferDesc_1_1>& buffers,
+                                       importExternalBuffers_cb _hidl_cb) override;
+
+private:
+    std::unique_ptr<ConfigManager> mConfigManager;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/mock-evs/MockEvsEnumerator.cpp b/surround_view/service-impl/mock-evs/MockEvsEnumerator.cpp
new file mode 100644
index 0000000..946083c
--- /dev/null
+++ b/surround_view/service-impl/mock-evs/MockEvsEnumerator.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MockEvsEnumerator.h"
+#include "MockEvsCamera.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+
+using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc;
+
+MockEvsEnumerator::MockEvsEnumerator() {
+    mConfigManager = ConfigManager::Create(
+            "/vendor/etc/automotive/evs/evs_sample_configuration.xml");
+}
+
+Return<void> MockEvsEnumerator::getCameraList(getCameraList_cb _hidl_cb) {
+    // Not implemented.
+
+    (void)_hidl_cb;
+    return {};
+}
+
+Return<sp<IEvsCamera_1_0>> MockEvsEnumerator::openCamera(
+        const hidl_string& cameraId) {
+    // Not implemented.
+
+    (void)cameraId;
+    return nullptr;
+}
+
+Return<void> MockEvsEnumerator::closeCamera(
+        const sp<IEvsCamera_1_0>& virtualCamera) {
+    // Not implemented.
+
+    (void)virtualCamera;
+    return {};
+}
+
+Return<sp<IEvsDisplay_1_0>> MockEvsEnumerator::openDisplay() {
+    // Not implemented.
+
+    return nullptr;
+}
+
+Return<void> MockEvsEnumerator::closeDisplay(
+        const sp<IEvsDisplay_1_0>& display) {
+    // Not implemented.
+
+    (void)display;
+    return {};
+}
+
+Return<EvsDisplayState> MockEvsEnumerator::getDisplayState() {
+    // Not implemented.
+
+    return EvsDisplayState::DEAD;
+}
+
+Return<void> MockEvsEnumerator::getCameraList_1_1(
+        getCameraList_1_1_cb _hidl_cb) {
+    // We only take camera group into consideration here.
+    vector<string> cameraGroupIdList = mConfigManager->getCameraGroupIdList();
+    LOG(INFO) << "getCameraGroupIdList: " << cameraGroupIdList.size();
+    for (int i = 0; i < cameraGroupIdList.size(); i++) {
+        LOG(INFO) << "Camera[" << i << "]: " << cameraGroupIdList[i];
+    }
+
+    vector<CameraDesc_1_1> hidlCameras;
+    for (int i = 0; i < cameraGroupIdList.size(); i++) {
+        CameraDesc_1_1 desc = {};
+        desc.v1.cameraId = cameraGroupIdList[i];
+        unique_ptr<ConfigManager::CameraGroupInfo>& cameraGroupInfo =
+                mConfigManager->getCameraGroupInfo(cameraGroupIdList[i]);
+        if (cameraGroupInfo != nullptr) {
+            desc.metadata.setToExternal(
+                    (uint8_t*)cameraGroupInfo->characteristics,
+                    get_camera_metadata_size(cameraGroupInfo->characteristics));
+        } else {
+            LOG(WARNING) << "Cannot find camera info for "
+                         << cameraGroupIdList[i];
+        }
+        hidlCameras.emplace_back(desc);
+    }
+    _hidl_cb(hidlCameras);
+
+    return {};
+}
+
+Return<sp<IEvsCamera_1_1>> MockEvsEnumerator::openCamera_1_1(
+        const hidl_string& cameraId, const Stream& streamCfg) {
+    // Not implemented.
+
+    (void)cameraId;
+    (void)streamCfg;
+    return new MockEvsCamera();
+}
+
+Return<void> MockEvsEnumerator::getDisplayIdList(getDisplayIdList_cb _list_cb) {
+    // Not implemented.
+
+    (void)_list_cb;
+    return {};
+}
+
+Return<sp<IEvsDisplay_1_1>> MockEvsEnumerator::openDisplay_1_1(uint8_t id) {
+    // Not implemented.
+
+    (void)id;
+    return nullptr;
+}
+
+Return<void> MockEvsEnumerator::getUltrasonicsArrayList(
+        getUltrasonicsArrayList_cb _hidl_cb) {
+    // Not implemented.
+
+    (void)_hidl_cb;
+    return {};
+}
+
+Return<sp<IEvsUltrasonicsArray>> MockEvsEnumerator::openUltrasonicsArray(
+        const hidl_string& ultrasonicsArrayId) {
+    // Not implemented.
+
+    (void)ultrasonicsArrayId;
+    return nullptr;
+}
+
+Return<void> MockEvsEnumerator::closeUltrasonicsArray(
+        const ::android::sp<IEvsUltrasonicsArray>& evsUltrasonicsArray) {
+    // Not implemented.
+
+    (void)evsUltrasonicsArray;
+    return {};
+}
+
+Return<void> MockEvsEnumerator::debug(
+        const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
+    // Not implemented.
+
+    (void)fd;
+    (void)options;
+    return {};
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/mock-evs/MockEvsEnumerator.h b/surround_view/service-impl/mock-evs/MockEvsEnumerator.h
new file mode 100644
index 0000000..7c1f8b0
--- /dev/null
+++ b/surround_view/service-impl/mock-evs/MockEvsEnumerator.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <system/camera_metadata.h>
+
+#include <ConfigManager.h>
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+using ::android::hardware::camera::device::V3_2::Stream;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+using EvsDisplayState = ::android::hardware::automotive::evs::V1_0::DisplayState;
+using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
+using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using IEvsDisplay_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
+using IEvsEnumerator_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsEnumerator;
+
+class MockEvsEnumerator : public IEvsEnumerator_1_1 {
+public:
+    MockEvsEnumerator();
+
+    // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
+    Return<void> getCameraList(getCameraList_cb _hidl_cb) override;
+    Return<sp<IEvsCamera_1_0>> openCamera(const hidl_string& cameraId) override;
+    Return<void> closeCamera(const ::android::sp<IEvsCamera_1_0>& virtualCamera) override;
+    Return<sp<IEvsDisplay_1_0>> openDisplay() override;
+    Return<void> closeDisplay(const ::android::sp<IEvsDisplay_1_0>& display) override;
+    Return<EvsDisplayState> getDisplayState() override;
+
+    // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
+    Return<void> getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) override;
+    Return<sp<IEvsCamera_1_1>> openCamera_1_1(const hidl_string& cameraId,
+                                              const Stream& streamCfg) override;
+    Return<bool> isHardware() override { return false; }
+    Return<void> getDisplayIdList(getDisplayIdList_cb _list_cb) override;
+    Return<sp<IEvsDisplay_1_1>> openDisplay_1_1(uint8_t id) override;
+    Return<void> getUltrasonicsArrayList(getUltrasonicsArrayList_cb _hidl_cb) override;
+    Return<sp<IEvsUltrasonicsArray>> openUltrasonicsArray(
+            const hidl_string& ultrasonicsArrayId) override;
+    Return<void> closeUltrasonicsArray(
+            const ::android::sp<IEvsUltrasonicsArray>& evsUltrasonicsArray) override;
+
+    // Methods from ::android.hidl.base::V1_0::IBase follow.
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
+
+private:
+    std::unique_ptr<ConfigManager> mConfigManager;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/mock-evs/MockSurroundViewCallback.cpp b/surround_view/service-impl/mock-evs/MockSurroundViewCallback.cpp
new file mode 100644
index 0000000..d059f72
--- /dev/null
+++ b/surround_view/service-impl/mock-evs/MockSurroundViewCallback.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MockSurroundViewCallback.h"
+
+#include <android-base/logging.h>
+
+using ::android::sp;
+using ::android::hardware::Return;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+MockSurroundViewCallback::MockSurroundViewCallback(
+        sp<ISurroundViewSession> pSession) {
+    (void)pSession;
+}
+
+Return<void> MockSurroundViewCallback::notify(SvEvent svEvent) {
+    LOG(INFO) << __FUNCTION__ << "SvEvent received: " << (int)svEvent;
+    return {};
+}
+
+Return<void> MockSurroundViewCallback::receiveFrames(
+        const SvFramesDesc& svFramesDesc) {
+    LOG(INFO) << __FUNCTION__ << svFramesDesc.svBuffers.size()
+              << " frames are received";
+    return {};
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/mock-evs/MockSurroundViewCallback.h b/surround_view/service-impl/mock-evs/MockSurroundViewCallback.h
new file mode 100644
index 0000000..7239bf6
--- /dev/null
+++ b/surround_view/service-impl/mock-evs/MockSurroundViewCallback.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+
+using namespace android::hardware::automotive::sv::V1_0;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+class MockSurroundViewCallback : public ISurroundViewStream {
+public:
+    MockSurroundViewCallback(android::sp<ISurroundViewSession> pSession);
+
+    // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewStream.
+    android::hardware::Return<void> notify(SvEvent svEvent) override;
+    android::hardware::Return<void> receiveFrames(const SvFramesDesc& svFramesDesc) override;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/service.cpp b/surround_view/service-impl/service.cpp
new file mode 100644
index 0000000..3ccc68f
--- /dev/null
+++ b/surround_view/service-impl/service.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware_buffer.h>
+#include <hidl/HidlTransportSupport.h>
+#include <thread>
+#include <ui/GraphicBuffer.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+#include <utils/SystemClock.h>
+
+#include "SurroundViewService.h"
+
+// libhidl:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// implementation:
+using android::hardware::automotive::sv::V1_0::implementation::SurroundViewService;
+
+int main() {
+    LOG(INFO) << "ISurroundViewService default implementation is starting";
+    android::sp<ISurroundViewService> service = SurroundViewService::getInstance();
+
+    configureRpcThreadpool(1, true /* callerWillJoin */);
+
+    // Register our service -- if somebody is already registered by our name,
+    // they will be killed (their thread pool will throw an exception).
+    android::status_t status = service->registerAsService();
+
+    if (status != android::OK) {
+        LOG(ERROR) << "Could not register default Surround View Service. Status: "
+                   << status;
+    }
+
+    joinRpcThreadpool();
+
+    // In normal operation, we don't expect the thread pool to exit
+    LOG(ERROR) << "Surround View Service is shutting down";
+    return 1;
+}
diff --git a/surround_view/service-impl/sv_3d_params.h b/surround_view/service-impl/sv_3d_params.h
new file mode 100644
index 0000000..0b6c223
--- /dev/null
+++ b/surround_view/service-impl/sv_3d_params.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SV_3D_PARAMS_H
+#define SV_3D_PARAMS_H
+
+#include <vector>
+#include <hidl/HidlSupport.h>
+
+using ::android::hardware::hidl_vec;
+
+static std::vector<android::hardware::hidl_vec<float>> kRecViews = {
+    {0, 1, -0, -0, -0.747409, 0, 0.664364, 1.32873, 0.664364, -0, 0.747409, -4.52598, 0, 0, 0, 1},
+    {-0.382683, 0.92388, 0, -0, -0.690516, -0.286021, 0.664364, 1.32873, 0.613792, 0.254241, 0.747409, -4.52598, 0, 0, 0, 1},
+    {-0.707107, 0.707107, 0, -0, -0.528498, -0.528498, 0.664364, 1.32873, 0.469776, 0.469776, 0.747409, -4.52598, 0, 0, 0, 1},
+    {-0.92388, 0.382683, 0, -1.19209e-07, -0.286021, -0.690516, 0.664364, 1.32873, 0.254241, 0.613792, 0.747409, -4.52598, 0, 0, 0, 1},
+    {-1, -4.37114e-08, 0, -0, 3.26703e-08, -0.747409, 0.664364, 1.32873, -2.90403e-08, 0.664364, 0.747409, -4.52598, 0, 0, 0, 1},
+    {-0.92388, -0.382683, 0, -0, 0.286021, -0.690516, 0.664364, 1.32873, -0.254241, 0.613792, 0.747409, -4.52598, 0, 0, 0, 1},
+    {-0.707107, -0.707107, 0, -0, 0.528498, -0.528498, 0.664364, 1.32873, -0.469776, 0.469776, 0.747409, -4.52598, 0, 0, 0, 1},
+    {-0.382683, -0.92388, 0, 1.19209e-07, 0.690516, -0.286021, 0.664364, 1.32873, -0.613792, 0.254241, 0.747409, -4.52598, 0, 0, 0, 1},
+    {8.74228e-08, -1, 0, -0, 0.747409, 6.53406e-08, 0.664364, 1.32873, -0.664364, -5.80805e-08, 0.747409, -4.52598, 0, 0, 0, 1},
+    {0.382683, -0.92388, 0, 1.19209e-07, 0.690516, 0.286021, 0.664364, 1.32873, -0.613792, -0.254241, 0.747409, -4.52598, 0, 0, 0, 1},
+    {0.707107, -0.707107, 0, 1.19209e-07, 0.528498, 0.528498, 0.664364, 1.32873, -0.469776, -0.469776, 0.747409, -4.52598, 0, 0, 0, 1},
+    {0.92388, -0.382684, 0, 1.19209e-07, 0.286021, 0.690516, 0.664364, 1.32873, -0.254241, -0.613792, 0.747409, -4.52598, 0, 0, 0, 1},
+    {1, 1.19249e-08, -0, 3.55271e-15, -8.91277e-09, 0.747409, 0.664364, 1.32873, 7.92246e-09, -0.664364, 0.747409, -4.52598, 0, 0, 0, 1},
+    {0.92388, 0.382684, -0, -0, -0.286021, 0.690516, 0.664364, 1.32873, 0.254241, -0.613792, 0.747409, -4.52598, 0, 0, 0, 1},
+    {0.707107, 0.707107, -0, -1.19209e-07, -0.528498, 0.528498, 0.664364, 1.32873, 0.469776, -0.469776, 0.747409, -4.52598, 0, 0, 0, 1},
+    {0.382683, 0.92388, -0, -1.19209e-07, -0.690516, 0.286021, 0.664364, 1.32873, 0.613792, -0.254241, 0.747409, -4.52598, 0, 0, 0, 1},
+};
+
+#endif // SV_3D_PARAMS_H
+
diff --git a/surround_view/service-impl/test_data/0.png b/surround_view/service-impl/test_data/0.png
new file mode 100644
index 0000000..283751b
--- /dev/null
+++ b/surround_view/service-impl/test_data/0.png
Binary files differ
diff --git a/surround_view/service-impl/test_data/1.png b/surround_view/service-impl/test_data/1.png
new file mode 100644
index 0000000..55abd66
--- /dev/null
+++ b/surround_view/service-impl/test_data/1.png
Binary files differ
diff --git a/surround_view/service-impl/test_data/2.png b/surround_view/service-impl/test_data/2.png
new file mode 100644
index 0000000..c66dd61
--- /dev/null
+++ b/surround_view/service-impl/test_data/2.png
Binary files differ
diff --git a/surround_view/service-impl/test_data/3.png b/surround_view/service-impl/test_data/3.png
new file mode 100644
index 0000000..f9d2c60
--- /dev/null
+++ b/surround_view/service-impl/test_data/3.png
Binary files differ
diff --git a/surround_view/service-impl/test_data/sample_car.obj b/surround_view/service-impl/test_data/sample_car.obj
new file mode 100644
index 0000000..3600a7b
--- /dev/null
+++ b/surround_view/service-impl/test_data/sample_car.obj
@@ -0,0 +1,64 @@
+# Sample Car Model Obj files
+# Consist of cubes representing a car part
+
+mtllib sample_car_material.mtl
+
+# Car Door Object
+v 0.0 0.0 0.0
+v 0.0 0.0 1.0
+v 0.0 1.0 0.0
+v 0.0 1.0 1.0
+v 1.0 0.0 0.0
+v 1.0 0.0 1.0
+v 1.0 1.0 0.0
+v 1.0 1.0 1.0
+vn 0.0 0.0 1.0
+vn 0.0 0.0 -1.0
+vn 0.0 1.0 0.0
+vn 0.0 -1.0 0.0
+vn 1.0 0.0 0.0
+vn -1.0 0.0 0.0
+g door
+usemtl door
+f 1//2 7//2 5//2
+f 1//2 3//2 7//2
+f 1//6 4//6 3//6
+f 1//6 2//6 4//6
+f 3//3 8//3 7//3
+f 3//3 4//3 8//3
+f 5//5 7//5 8//5
+f 5//5 8//5 6//5
+f 1//4 5//4 6//4
+f 1//4 6//4 2//4
+f 2//1 6//1 8//1
+f 2//1 8//1 4//1
+
+# Car Window Object
+v 0.0 0.0 0.0
+v 0.0 0.0 -1.0
+v 0.0 -1.0 0.0
+v 0.0 -1.0 1.0
+v -1.0 0.0 0.0
+v -1.0 0.0 -1.0
+v -1.0 -1.0 0.0
+v -1.0 -1.0 -1.0
+vn 0.0 0.0 1.0
+vn 0.0 0.0 -1.0
+vn 0.0 1.0 0.0
+vn 0.0 -1.0 0.0
+vn 1.0 0.0 0.0
+vn -1.0 0.0 0.0
+g window
+usemtl window
+f 1//2 7//2 5//2
+f 1//2 3//2 7//2
+f 1//6 4//6 3//6
+f 1//6 2//6 4//6
+f 3//3 8//3 7//3
+f 3//3 4//3 8//3
+f 5//5 7//5 8//5
+f 5//5 8//5 6//5
+f 1//4 5//4 6//4
+f 1//4 6//4 2//4
+f 2//1 6//1 8//1
+f 2//1 8//1 4//1
diff --git a/surround_view/service-impl/test_data/sample_car_material.mtl b/surround_view/service-impl/test_data/sample_car_material.mtl
new file mode 100644
index 0000000..aaa2f1b
--- /dev/null
+++ b/surround_view/service-impl/test_data/sample_car_material.mtl
@@ -0,0 +1,18 @@
+# Sample material file for car model.
+# referenced by sample_car.obj
+
+newmtl door
+    d 1.0000
+    illum 1
+    Ka 0.5000 0.5000 0.5000
+    Kd 1.0000 1.0000 1.0000
+    Ks 1.0000 1.0000 1.0000
+    ns 0.0000
+
+newmtl window
+    d 1.0000
+    illum 1
+    Ka 0.5000 0.5000 0.5000
+    Kd 1.0000 0.0000 0.0000
+    Ks 1.0000 1.0000 1.0000
+    ns 0.0000
diff --git a/surround_view/service-impl/test_data/sv_sample_car_model_config.xml b/surround_view/service-impl/test_data/sv_sample_car_model_config.xml
new file mode 100644
index 0000000..60541a8
--- /dev/null
+++ b/surround_view/service-impl/test_data/sv_sample_car_model_config.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<SurroundViewCarModelConfig>
+    <Version>1.0</Version>
+
+    <!-- Rotation animation for door -->
+    <Animation>
+        <PartId>door</PartId>
+        <ChildParts>
+            <PartId>window</PartId>
+        </ChildParts>
+        <ParentPartId>car_frame</ParentPartId>
+        <RotationOp>
+            <VhalProperty>
+                <!-- Uses VHAL Property DOOR_POS -->
+                <PropertyId>0x16000B00</PropertyId>
+                <!-- AreadId = VehicleAreaDoor::ROW_1_LEFT -->
+                <AreaId>0x00000001</AreaId>
+            </VhalProperty>
+            <AnimationType>RotationAngle</AnimationType>
+            <AnimationTimeMs>2000</AnimationTimeMs>
+            <RotationAxis>
+                <X>0.0</X>
+                <Y>0.0</Y>
+                <Z>1.0</Z>
+            </RotationAxis>
+            <RotationPoint>
+                <X>0.0</X>
+                <Y>0.0</Y>
+                <Z>0.0</Z>
+            </RotationPoint>
+            <DefaultRotationValue>0.0</DefaultRotationValue>
+            <RotationRange>
+                <Start>0.0</Start>
+                <End>90</End>
+            </RotationRange>
+            <VhalRange>
+                <!-- 0 => door closed -->
+                <Start>0x00000000</Start>
+                <!-- INT32_MAX => door fully open -->
+                <End>0x7FFFFFFF</End>
+            </VhalRange>
+        </RotationOp>
+    </Animation>
+
+    <!-- Translation animation for window -->
+    <Animation>
+        <PartId>window</PartId>
+        <ParentPartId>window</ParentPartId>
+        <ChildParts>
+        </ChildParts>
+        <TranslationOp>
+            <VhalProperty>
+                <!-- Uses VHAL Property WINDOW_POS -->
+                <PropertyId>0x13000BC0</PropertyId>
+                <!-- AreaId = VehicleAreaWindow::ROW_1_LEFT -->
+                <AreaId>0x00000010</AreaId>
+            </VhalProperty>
+            <AnimationType>Translation</AnimationType>
+            <AnimationTimeMs>2000</AnimationTimeMs>
+            <Direction>
+                <X>0.0</X>
+                <Y>0.0</Y>
+                <Z>-1.0</Z>
+            </Direction>
+            <DefaultTranslationValue>0.0</DefaultTranslationValue>
+            <TranslationRange>
+                <Start>0.0</Start>
+                <End>1.0</End>
+            </TranslationRange>
+            <VhalRange>
+                <!-- 0 => window up/closed -->
+                <Start>0x00000000</Start>
+                <!-- INT32_MAX => window down/open -->
+                <End>0x7FFFFFFF</End>
+            </VhalRange>
+        </TranslationOp>
+    </Animation>
+
+</SurroundViewCarModelConfig>
diff --git a/surround_view/service-impl/test_data/sv_sample_config.xml b/surround_view/service-impl/test_data/sv_sample_config.xml
new file mode 100644
index 0000000..88a5413
--- /dev/null
+++ b/surround_view/service-impl/test_data/sv_sample_config.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<SurroundViewConfig>
+    <Version>1.0</Version>
+
+    <CameraConfig>
+        <EvsGroupId>v4l2loopback_group0</EvsGroupId>
+        <EvsCameraIds>
+            <Front>/dev/video60</Front>
+            <Right>/dev/video61</Right>
+            <Rear>/dev/video62</Rear>
+            <Left>/dev/video63</Left>
+        </EvsCameraIds>
+        <Masks>
+            <Front>/vendor/mask_front.png</Front>
+            <Right>/vendor/mask_right.png</Right>
+            <Rear>/vendor/mask_rear.png</Rear>
+            <Left>/vendor/mask_left.png</Left>
+        </Masks>
+    </CameraConfig>
+
+    <Sv2dEnabled>true</Sv2dEnabled>
+    <Sv2dParams>
+        <OutputResolution>
+            <Width>1024</Width>
+            <Height>768</Height>
+        </OutputResolution>
+        <GroundMapping>
+            <Width>8.0</Width>
+            <Height>6.0</Height>
+            <Center>
+                <X>0.0</X>
+                <Y>0.0</Y>
+            </Center>
+        </GroundMapping>
+        <CarBoundingBox>
+            <Width>2.0</Width>
+            <Height>3.0</Height>
+            <LeftTopCorner>
+                <X>1.0</X>
+                <Y>1.5</Y>
+            </LeftTopCorner>
+        </CarBoundingBox>
+        <BlendingType>
+            <HighQuality>multiband</HighQuality>
+            <LowQuality>alpha</LowQuality>
+        </BlendingType>
+    </Sv2dParams>
+
+    <Sv3dEnabled>true</Sv3dEnabled>
+    <Sv3dAnimationsEnabled>true</Sv3dAnimationsEnabled>
+    <CarModelConfigFile>/vendor/etc/automotive/sv/sv_sample_car_model_config.xml</CarModelConfigFile>
+    <CarModelObjFile>/vendor/etc/automotive/sv/sample_car.obj</CarModelObjFile>
+    <Sv3dParams>
+        <OutputResolution>
+            <Width>1024</Width>
+            <Height>768</Height>
+        </OutputResolution>
+        <BowlParams>
+            <PlaneRadius>8.0</PlaneRadius>
+            <PlaneDivisions>50</PlaneDivisions>
+            <CurveHeight>6.0</CurveHeight>
+            <CurveDivisions>50</CurveDivisions>
+            <AngularDivisions>90</AngularDivisions>
+            <CurveCoefficient>3.0</CurveCoefficient>
+        </BowlParams>
+        <HighQualityDetails>
+            <Shadows>true</Shadows>
+            <Reflections>true</Reflections>
+        </HighQualityDetails>
+    </Sv3dParams>
+</SurroundViewConfig>
diff --git a/tests/BugReportApp/Android.bp b/tests/BugReportApp/Android.bp
new file mode 100644
index 0000000..5034ebf
--- /dev/null
+++ b/tests/BugReportApp/Android.bp
@@ -0,0 +1,64 @@
+// 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.
+
+android_app {
+    name: "BugReportApp",
+
+    srcs: ["src/**/*.java"],
+
+    resource_dirs: ["res"],
+
+    platform_apis: true,
+
+    aaptflags: ["--auto-add-overlay"],
+
+    optimize: {
+        enabled: false,
+    },
+
+    certificate: "platform",
+
+    privileged: true,
+
+    dex_preopt: {
+        enabled: false,
+    },
+
+    libs: [
+        "android.car",
+    ],
+
+    static_libs: [
+        "androidx.recyclerview_recyclerview",
+        "car-br-auto-value-jar",
+        "car-br-google-api-client-android-jar",
+        "car-br-google-api-java-client-jar",
+        "car-br-google-http-client-android-jar",
+        "car-br-google-http-client-jackson2-jar",
+        "car-br-google-http-client-jar",
+        "car-br-google-oauth-client-jar",
+        "car-br-google-storage-services-jar",
+        "car-br-jackson-core-jar",
+        "car-br-grpc-context-jar",
+        "car-br-opencensus-api-jar",
+        "car-br-opencensus-contrib-http-util-jar",
+        "guava",
+        "jsr305",
+    ],
+
+    required: ["privapp_whitelist_com.android.car.bugreport"],
+
+    // Explicitly define annotation processors even if javac can find them from static_libs.
+    plugins: ["car-br-auto-value"],
+}
diff --git a/tests/BugReportApp/Android.mk b/tests/BugReportApp/Android.mk
deleted file mode 100644
index 186fe4b..0000000
--- a/tests/BugReportApp/Android.mk
+++ /dev/null
@@ -1,109 +0,0 @@
-# Copyright (C) 2019 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_PACKAGE_NAME := BugReportApp
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_AAPT_FLAGS := --auto-add-overlay
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_CERTIFICATE := platform
-
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_JAVA_LIBRARIES += \
-    android.car \
-    br_google_auto_value_target
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    androidx.recyclerview_recyclerview \
-    br_google-api-java-client \
-    br_google-api-client-android \
-    br_google-oauth-client \
-    br_google-http-client \
-    br_google-http-client-android \
-    br_google-http-client-jackson2 \
-    br_jackson-core \
-    br_gson-2.1 \
-    br_google-storage-services \
-    br_apache_commons \
-    guava \
-    jsr305
-
-LOCAL_REQUIRED_MODULES := privapp_whitelist_com.google.android.car.bugreport
-
-# Explicitly define annotation processors even if javac can find them from
-# LOCAL_STATIC_JAVA_LIBRARIES.
-LOCAL_ANNOTATION_PROCESSORS := br_google_auto_value
-LOCAL_ANNOTATION_PROCESSOR_CLASSES := com.google.auto.value.processor.AutoValueProcessor
-
-include $(BUILD_PACKAGE)
-
-# ====  prebuilt library  ========================
-include $(CLEAR_VARS)
-
-COMMON_LIBS_PATH := ../../../../../prebuilts/tools/common/m2/repository
-
-LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
-    br_google-api-java-client:libs/google-api-client-1.25.0.jar \
-    br_google-api-client-android:libs/google-api-client-android-1.25.0.jar \
-    br_google-oauth-client:libs/google-oauth-client-1.25.0.jar \
-    br_google-http-client:libs/google-http-client-1.25.0.jar \
-    br_google-http-client-android:libs/google-http-client-android-1.25.0.jar \
-    br_jackson-core:libs/jackson-core-2.9.6.jar \
-    br_gson-2.1:libs/gson-2.1.jar \
-    br_google-http-client-jackson2:libs/google-http-client-jackson2-1.25.0.jar \
-    br_google-storage-services:libs/google-api-services-storage-v1-rev136-1.25.0.jar \
-    br_apache_commons:$(COMMON_LIBS_PATH)/org/eclipse/tycho/tycho-bundles-external/0.18.1/eclipse/plugins/org.apache.commons.codec_1.4.0.v201209201156.jar
-
-include $(BUILD_MULTI_PREBUILT)
-
-# Following shenanigans are needed for LOCAL_ANNOTATION_PROCESSORS.
-
-# ====  prebuilt host libraries  ========================
-include $(CLEAR_VARS)
-
-LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
-    br_google_auto_value:../../../../../prebuilts/tools/common/m2/repository/com/google/auto/value/auto-value/1.5.2/auto-value-1.5.2.jar
-
-include $(BUILD_HOST_PREBUILT)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-LOCAL_MODULE := br_google_auto_value_target
-LOCAL_SDK_VERSION := current
-LOCAL_SRC_FILES := ../../../../../prebuilts/tools/common/m2/repository/com/google/auto/value/auto-value/1.5.2/auto-value-1.5.2.jar
-LOCAL_UNINSTALLABLE_MODULE := true
-
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/BugReportApp/AndroidManifest.xml b/tests/BugReportApp/AndroidManifest.xml
index dcccb83..7389260 100644
--- a/tests/BugReportApp/AndroidManifest.xml
+++ b/tests/BugReportApp/AndroidManifest.xml
@@ -15,7 +15,7 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.google.android.car.bugreport"
+          package="com.android.car.bugreport"
           android:versionCode="13"
           android:versionName="1.7.2">
 
@@ -57,18 +57,18 @@
                   android:excludeFromRecents="true">
             <meta-data android:name="distractionOptimized" android:value="true"/>
             <intent-filter>
-                <action android:name="com.google.android.car.bugreport.action.START_SILENT"/>
+                <action android:name="com.android.car.bugreport.action.START_SILENT"/>
             </intent-filter>
         </activity>
 
         <service android:name=".BugReportService"
                  android:exported="true">
             <intent-filter>
-                <action android:name="com.google.android.car.bugreport.action.START_SILENT"/>
+                <action android:name="com.android.car.bugreport.action.START_SILENT"/>
             </intent-filter>
         </service>
 
-        <service android:name="com.google.android.car.bugreport.UploadJob"
+        <service android:name="com.android.car.bugreport.UploadJob"
                  android:permission="android.permission.BIND_JOB_SERVICE"
                  android:exported="true"/>
 
@@ -79,8 +79,8 @@
             </intent-filter>
         </receiver>
 
-        <provider android:name="com.google.android.car.bugreport.BugStorageProvider"
-                  android:authorities="com.google.android.car.bugreport"
+        <provider android:name="com.android.car.bugreport.BugStorageProvider"
+                  android:authorities="com.android.car.bugreport"
                   android:exported="false"
                   android:singleUser="true"
                   android:multiprocess="false">
diff --git a/tests/BugReportApp/README.md b/tests/BugReportApp/README.md
index 476efe4..ce952ad 100644
--- a/tests/BugReportApp/README.md
+++ b/tests/BugReportApp/README.md
@@ -30,7 +30,7 @@
 
 To allow AAE BugReport app to access the API, you need to overlay
 `config_car_bugreport_application` in `packages/services/Car/service/res/values/config.xml`
-with value `com.google.android.car.bugreport`.
+with value `com.android.car.bugreport`.
 
 ## App Configuration
 
@@ -55,10 +55,10 @@
 
 The app supports following intents:
 
-1. `adb shell am start com.google.android.car.bugreport/.BugReportActivity`
+1. `adb shell am start com.android.car.bugreport/.BugReportActivity`
     - generates `MetaBugReport.Type.INTERACTIVE` bug report, shows audio message dialog before
     collecting bugreport.
-2. `adb shell am start-foreground-service -a com.google.android.car.bugreport.action.START_SILENT com.google.android.car.bugreport/.BugReportService`
+2. `adb shell am start-foreground-service -a com.android.car.bugreport.action.START_SILENT com.android.car.bugreport/.BugReportService`
     - generates `MetaBugReport.Type.SILENT` bug report, without audio message. It shows audio dialog
     after collecting bugreport.
 
@@ -82,7 +82,7 @@
      task scheduling rules.
    * You should see progress bar in notification shade.
 5. Pull collected zip files from the device:
-   * `adb pull /data/user/0/com.google.android.car.bugreport/bug_reports_pending/`
+   * `adb pull /data/user/0/com.android.car.bugreport/bug_reports_pending/`
 6. Please manually verify bug report contents.
    * Images - the should contain screenshots of all the physical displays.
    * Audio files - they should contain the audio message you recorded.
diff --git a/tests/BugReportApp/libs/Android.bp b/tests/BugReportApp/libs/Android.bp
new file mode 100644
index 0000000..8f36053
--- /dev/null
+++ b/tests/BugReportApp/libs/Android.bp
@@ -0,0 +1,95 @@
+// 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.
+
+java_import {
+    name: "car-br-auto-value-jar",
+    host_supported: true,
+    sdk_version: "current",
+    jars: ["auto-value-1.5.2.jar"],
+}
+
+java_plugin {
+    name: "car-br-auto-value",
+    static_libs: [
+        "car-br-auto-value-jar",
+        "guava",
+    ],
+    processor_class: "com.google.auto.value.processor.AutoValueProcessor",
+}
+
+java_import {
+    name: "car-br-google-api-java-client-jar",
+    jars: ["google-api-client-1.30.2.jar"],
+    sdk_version: "current",
+}
+
+java_import {
+    name: "car-br-google-api-client-android-jar",
+    jars: ["google-api-client-android-1.30.2.jar"],
+    sdk_version: "current",
+}
+
+java_import {
+    name: "car-br-google-storage-services-jar",
+    jars: ["google-api-services-storage-v1-rev158-1.25.0.jar"],
+    sdk_version: "current",
+}
+
+java_import {
+    name: "car-br-google-oauth-client-jar",
+    jars: ["google-oauth-client-1.30.1.jar"],
+    sdk_version: "current",
+}
+
+java_import {
+    name: "car-br-google-http-client-jar",
+    jars: ["google-http-client-1.30.1.jar"],
+    sdk_version: "current",
+}
+
+java_import {
+    name: "car-br-google-http-client-android-jar",
+    jars: ["google-http-client-android-1.30.1.jar"],
+    sdk_version: "current",
+}
+
+java_import {
+    name: "car-br-google-http-client-jackson2-jar",
+    jars: ["google-http-client-jackson2-1.30.1.jar"],
+    sdk_version: "current",
+}
+
+java_import {
+    name: "car-br-grpc-context-jar",
+    jars: ["grpc-context-1.19.0.jar"],
+    sdk_version: "current",
+}
+
+java_import {
+    name: "car-br-jackson-core-jar",
+    jars: ["jackson-core-2.9.9.jar"],
+    sdk_version: "current",
+}
+
+java_import {
+    name: "car-br-opencensus-api-jar",
+    jars: ["opencensus-api-0.21.0.jar"],
+    sdk_version: "current",
+}
+
+java_import {
+    name: "car-br-opencensus-contrib-http-util-jar",
+    jars: ["opencensus-contrib-http-util-0.21.0.jar"],
+    sdk_version: "current",
+}
diff --git a/tests/BugReportApp/libs/auto-value-1.5.2.jar b/tests/BugReportApp/libs/auto-value-1.5.2.jar
new file mode 100644
index 0000000..8ac0567
--- /dev/null
+++ b/tests/BugReportApp/libs/auto-value-1.5.2.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-api-client-1.25.0.jar b/tests/BugReportApp/libs/google-api-client-1.25.0.jar
deleted file mode 100644
index f1e65b2..0000000
--- a/tests/BugReportApp/libs/google-api-client-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-api-client-1.30.2.jar b/tests/BugReportApp/libs/google-api-client-1.30.2.jar
new file mode 100644
index 0000000..b2330d8
--- /dev/null
+++ b/tests/BugReportApp/libs/google-api-client-1.30.2.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-api-client-android-1.25.0.jar b/tests/BugReportApp/libs/google-api-client-android-1.25.0.jar
deleted file mode 100644
index 2e62e7a..0000000
--- a/tests/BugReportApp/libs/google-api-client-android-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-api-client-android-1.30.2.jar b/tests/BugReportApp/libs/google-api-client-android-1.30.2.jar
new file mode 100644
index 0000000..fb04d53
--- /dev/null
+++ b/tests/BugReportApp/libs/google-api-client-android-1.30.2.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-api-client-gson-1.25.0.jar b/tests/BugReportApp/libs/google-api-client-gson-1.25.0.jar
deleted file mode 100644
index 734491d..0000000
--- a/tests/BugReportApp/libs/google-api-client-gson-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-api-client-jackson2-1.25.0.jar b/tests/BugReportApp/libs/google-api-client-jackson2-1.25.0.jar
deleted file mode 100644
index da08ebe..0000000
--- a/tests/BugReportApp/libs/google-api-client-jackson2-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-api-services-storage-v1-rev136-1.25.0.jar b/tests/BugReportApp/libs/google-api-services-storage-v1-rev136-1.25.0.jar
deleted file mode 100644
index 2f265eb..0000000
--- a/tests/BugReportApp/libs/google-api-services-storage-v1-rev136-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-api-services-storage-v1-rev158-1.25.0.jar b/tests/BugReportApp/libs/google-api-services-storage-v1-rev158-1.25.0.jar
new file mode 100644
index 0000000..a8e58a6
--- /dev/null
+++ b/tests/BugReportApp/libs/google-api-services-storage-v1-rev158-1.25.0.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-1.25.0.jar b/tests/BugReportApp/libs/google-http-client-1.25.0.jar
deleted file mode 100644
index 84c8ce3..0000000
--- a/tests/BugReportApp/libs/google-http-client-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-1.30.1.jar b/tests/BugReportApp/libs/google-http-client-1.30.1.jar
new file mode 100644
index 0000000..aa2ea71
--- /dev/null
+++ b/tests/BugReportApp/libs/google-http-client-1.30.1.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-android-1.25.0.jar b/tests/BugReportApp/libs/google-http-client-android-1.25.0.jar
deleted file mode 100644
index f2bb0d4..0000000
--- a/tests/BugReportApp/libs/google-http-client-android-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-android-1.30.1.jar b/tests/BugReportApp/libs/google-http-client-android-1.30.1.jar
new file mode 100644
index 0000000..31c88a8
--- /dev/null
+++ b/tests/BugReportApp/libs/google-http-client-android-1.30.1.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-gson-1.25.0.jar b/tests/BugReportApp/libs/google-http-client-gson-1.25.0.jar
deleted file mode 100644
index 158c0c8..0000000
--- a/tests/BugReportApp/libs/google-http-client-gson-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-jackson2-1.25.0.jar b/tests/BugReportApp/libs/google-http-client-jackson2-1.25.0.jar
deleted file mode 100644
index 34f5646..0000000
--- a/tests/BugReportApp/libs/google-http-client-jackson2-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-jackson2-1.30.1.jar b/tests/BugReportApp/libs/google-http-client-jackson2-1.30.1.jar
new file mode 100644
index 0000000..021b6b7
--- /dev/null
+++ b/tests/BugReportApp/libs/google-http-client-jackson2-1.30.1.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-jdo-1.25.0.jar b/tests/BugReportApp/libs/google-http-client-jdo-1.25.0.jar
deleted file mode 100644
index dcb7461..0000000
--- a/tests/BugReportApp/libs/google-http-client-jdo-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-oauth-client-1.25.0.jar b/tests/BugReportApp/libs/google-oauth-client-1.25.0.jar
deleted file mode 100644
index 1304c30..0000000
--- a/tests/BugReportApp/libs/google-oauth-client-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-oauth-client-1.30.1.jar b/tests/BugReportApp/libs/google-oauth-client-1.30.1.jar
new file mode 100644
index 0000000..2489729
--- /dev/null
+++ b/tests/BugReportApp/libs/google-oauth-client-1.30.1.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/grpc-context-1.19.0.jar b/tests/BugReportApp/libs/grpc-context-1.19.0.jar
new file mode 100644
index 0000000..94b2e38
--- /dev/null
+++ b/tests/BugReportApp/libs/grpc-context-1.19.0.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/gson-2.1.jar b/tests/BugReportApp/libs/gson-2.1.jar
deleted file mode 100644
index 83c5c99..0000000
--- a/tests/BugReportApp/libs/gson-2.1.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/httpclient-4.5.5.jar b/tests/BugReportApp/libs/httpclient-4.5.5.jar
deleted file mode 100644
index 7796b0e..0000000
--- a/tests/BugReportApp/libs/httpclient-4.5.5.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/jackson-core-2.9.6.jar b/tests/BugReportApp/libs/jackson-core-2.9.6.jar
deleted file mode 100644
index 09e7dd2..0000000
--- a/tests/BugReportApp/libs/jackson-core-2.9.6.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/jackson-core-2.9.9.jar b/tests/BugReportApp/libs/jackson-core-2.9.9.jar
new file mode 100644
index 0000000..02bd446
--- /dev/null
+++ b/tests/BugReportApp/libs/jackson-core-2.9.9.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/jdo2-api-2.3-eb.jar b/tests/BugReportApp/libs/jdo2-api-2.3-eb.jar
deleted file mode 100644
index a039ae7..0000000
--- a/tests/BugReportApp/libs/jdo2-api-2.3-eb.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/opencensus-api-0.21.0.jar b/tests/BugReportApp/libs/opencensus-api-0.21.0.jar
new file mode 100644
index 0000000..ad0646e
--- /dev/null
+++ b/tests/BugReportApp/libs/opencensus-api-0.21.0.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/opencensus-contrib-http-util-0.21.0.jar b/tests/BugReportApp/libs/opencensus-contrib-http-util-0.21.0.jar
new file mode 100644
index 0000000..32f0e51
--- /dev/null
+++ b/tests/BugReportApp/libs/opencensus-contrib-http-util-0.21.0.jar
Binary files differ
diff --git a/tests/BugReportApp/res/layout/bug_info_view.xml b/tests/BugReportApp/res/layout/bug_info_view.xml
index 199b368..1841f9c 100644
--- a/tests/BugReportApp/res/layout/bug_info_view.xml
+++ b/tests/BugReportApp/res/layout/bug_info_view.xml
@@ -30,8 +30,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="left"
-            android:textColor="@*android:color/car_yellow_500"
-            android:textSize="@dimen/bug_report_default_text_size" />
+            style="@style/TextAppearance.BugReportUi.Title" />
 
         <LinearLayout
             android:layout_width="wrap_content"
@@ -42,12 +41,12 @@
                 android:layout_height="wrap_content"
                 android:layout_marginRight="@dimen/bug_report_horizontal_layout_children_margin"
                 android:text="@string/bugreport_info_status"
-                android:textSize="@dimen/bug_report_default_text_size" />
+                style="@style/TextAppearance.BugReportUi.Body" />
             <TextView
                 android:id="@+id/bug_info_row_status"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:textSize="@dimen/bug_report_default_text_size" />
+                style="@style/TextAppearance.BugReportUi.Body" />
         </LinearLayout>
 
         <TextView
@@ -55,7 +54,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:visibility="gone"
-            android:textSize="@dimen/bug_report_default_text_size" />
+            style="@style/TextAppearance.BugReportUi.Body" />
 
         <LinearLayout
             android:layout_width="wrap_content"
@@ -68,8 +67,8 @@
                 android:layout_marginTop="@dimen/bug_report_user_action_button_padding"
                 android:layout_marginRight="@dimen/bug_report_horizontal_layout_children_margin"
                 android:visibility="gone"
-                android:textSize="@dimen/bug_report_button_text_size"
-                android:text="@string/bugreport_add_audio_button_text" />
+                android:text="@string/bugreport_add_audio_button_text"
+                style="@style/Widget.BugReportUi.InfoActionButton" />
             <Button
                 android:id="@+id/bug_info_upload_button"
                 android:layout_width="wrap_content"
@@ -77,16 +76,16 @@
                 android:layout_marginTop="@dimen/bug_report_user_action_button_padding"
                 android:layout_marginRight="@dimen/bug_report_horizontal_layout_children_margin"
                 android:visibility="gone"
-                android:textSize="@dimen/bug_report_button_text_size"
-                android:text="@string/bugreport_upload_button_text" />
+                android:text="@string/bugreport_upload_button_text"
+                style="@style/Widget.BugReportUi.InfoActionButton" />
             <Button
                 android:id="@+id/bug_info_move_button"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginTop="@dimen/bug_report_user_action_button_padding"
                 android:visibility="gone"
-                android:textSize="@dimen/bug_report_button_text_size"
-                android:text="@string/bugreport_move_button_text" />
+                android:text="@string/bugreport_move_button_text"
+                style="@style/Widget.BugReportUi.InfoActionButton" />
         </LinearLayout>
     </LinearLayout>
 
diff --git a/tests/BugReportApp/res/layout/bug_report_activity.xml b/tests/BugReportApp/res/layout/bug_report_activity.xml
index 888c628..1b1907d 100644
--- a/tests/BugReportApp/res/layout/bug_report_activity.xml
+++ b/tests/BugReportApp/res/layout/bug_report_activity.xml
@@ -45,7 +45,7 @@
             android:gravity="center"
             android:visibility="gone"
             android:text="@string/bugreport_dialog_add_audio_to_existing"/>
-        <com.google.android.car.bugreport.VoiceRecordingView
+        <com.android.car.bugreport.VoiceRecordingView
             android:id="@+id/voice_recording_view"
             android:layout_marginTop="@dimen/bug_report_voice_recording_margin_top"
             android:layout_height="@dimen/bug_report_voice_recording_height"
diff --git a/tests/BugReportApp/res/layout/bug_report_info_activity.xml b/tests/BugReportApp/res/layout/bug_report_info_activity.xml
index 1cbe9d4..4cc6fbf 100644
--- a/tests/BugReportApp/res/layout/bug_report_info_activity.xml
+++ b/tests/BugReportApp/res/layout/bug_report_info_activity.xml
@@ -32,13 +32,13 @@
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
             android:text="@string/bugreport_info_quit"
-            style="?android:attr/borderlessButtonStyle" />
+            style="@style/android:Widget.DeviceDefault.Button.Borderless.Colored" />
         <Button
             android:id="@+id/start_bug_report_button"
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
             android:text="@string/bugreport_info_start"
-            style="?android:attr/borderlessButtonStyle" />
+            style="@style/android:Widget.DeviceDefault.Button.Borderless.Colored" />
         <TextView
             android:id="@+id/version_text_view"
             android:layout_height="wrap_content"
@@ -46,7 +46,8 @@
             android:layout_weight="1"
             android:textSize="14sp"
             android:gravity="right"
-            android:text="" />
+            android:text=""
+            style="@style/android:TextAppearance.DeviceDefault" />
     </LinearLayout>
 
     <androidx.recyclerview.widget.RecyclerView
diff --git a/tests/BugReportApp/res/values-gu/strings.xml b/tests/BugReportApp/res/values-gu/strings.xml
index fc8c085..09b4141 100644
--- a/tests/BugReportApp/res/values-gu/strings.xml
+++ b/tests/BugReportApp/res/values-gu/strings.xml
@@ -17,7 +17,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="2596316479611335185">"ખામીની જાણકારી"</string>
+    <string name="app_name" msgid="2596316479611335185">"બગ રિપોર્ટ"</string>
     <string name="bugreport_info_quit" msgid="5590138890181142473">"બંધ કરો"</string>
     <string name="bugreport_info_start" msgid="667324824650830832">"ખામીની જાણકારી શરૂ કરો"</string>
     <string name="bugreport_info_status" msgid="7211044508792815451">"સ્ટેટસ:"</string>
diff --git a/tests/BugReportApp/res/values-hy/strings.xml b/tests/BugReportApp/res/values-hy/strings.xml
index 5ed63f9..d7dace3 100644
--- a/tests/BugReportApp/res/values-hy/strings.xml
+++ b/tests/BugReportApp/res/values-hy/strings.xml
@@ -28,9 +28,9 @@
     <string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"Ցույց տալ վրիպակի մասին զեկույցները"</string>
     <string name="bugreport_dialog_close" msgid="289925437277364266">"Փակել"</string>
     <string name="bugreport_dialog_title" msgid="3315160684205929910">"Բարձրաձայն նկարագրեք սխալը"</string>
-    <string name="bugreport_dialog_add_audio_to_existing" msgid="4958460267276935700">"Վրիպակների մասին հաղորդման վերաբերյալ ձայնային հաղորդագրություն, ժամը՝ %s։"</string>
+    <string name="bugreport_dialog_add_audio_to_existing" msgid="4958460267276935700">"Վրիպակների մասին հաշվետվության վերաբերյալ ձայնային հաղորդագրություն, ժամը՝ %s։"</string>
     <string name="bugreport_dialog_recording_finished" msgid="3982335902169398758">"Գրանցումն ավարտվեց"</string>
-    <string name="bugreport_dialog_in_progress_title" msgid="3782308141532622394">"Վրիպակների մասին զեկույցն արդեն բեռնվում է"</string>
+    <string name="bugreport_dialog_in_progress_title" msgid="3782308141532622394">"Վրիպակների մասին հաշվետվությունն արդեն բեռնվում է"</string>
     <string name="bugreport_dialog_in_progress_title_finished" msgid="1610236990020413471">"Սխալի մասին զեկույցը բեռնվել է"</string>
     <string name="bugreport_add_audio_button_text" msgid="8606400151705699144">"Ավելացնել աուդիո"</string>
     <string name="bugreport_add_audio_upload_button_text" msgid="3830917832551764694">"Ավելացնել աուդիո և վերբեռնել"</string>
@@ -38,7 +38,7 @@
     <string name="bugreport_upload_button_text" msgid="4136749466634820848">"Վերբեռնել"</string>
     <string name="bugreport_upload_gcs_button_text" msgid="5844929656507607424">"Վերբեռնել GCS"</string>
     <string name="toast_permissions_denied" msgid="7054832711916992770">"Տրամադրեք թույլտվություններ"</string>
-    <string name="toast_bug_report_in_progress" msgid="8319601113129121579">"Վրիպակների մասին զեկույցն արդեն բեռնվել է"</string>
+    <string name="toast_bug_report_in_progress" msgid="8319601113129121579">"Վրիպակների մասին հաշվետվությունն արդեն բեռնվել է"</string>
     <string name="toast_bug_report_started" msgid="7154589593986557754">"Վրիպակների մասին հաղորդումը սկսված է"</string>
     <string name="toast_status_failed" msgid="6365384202315043395">"Վրիպակի զեկույցի հետ կապված սխալ առաջացավ"</string>
     <string name="toast_status_screencap_failed" msgid="2187083897594745149">"Չհաջողվեց ստեղծել սքրինշոթ"</string>
diff --git a/tests/BugReportApp/res/values-ky/strings.xml b/tests/BugReportApp/res/values-ky/strings.xml
index 6ef7370..0cdce1c 100644
--- a/tests/BugReportApp/res/values-ky/strings.xml
+++ b/tests/BugReportApp/res/values-ky/strings.xml
@@ -17,7 +17,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="2596316479611335185">"Мүчүлүштүк тууралуу кабар берүү"</string>
+    <string name="app_name" msgid="2596316479611335185">"Мүчүлүштүк тууралуу кабарлоо"</string>
     <string name="bugreport_info_quit" msgid="5590138890181142473">"Жабуу"</string>
     <string name="bugreport_info_start" msgid="667324824650830832">"Мүчүлүштүк тууралуу кабарды берип баштоо"</string>
     <string name="bugreport_info_status" msgid="7211044508792815451">"Абалы:"</string>
@@ -45,5 +45,5 @@
     <string name="toast_status_dump_state_failed" msgid="8072469535227541761">"Абал тууралуу маалымат алынган жок"</string>
     <string name="notification_bugreport_in_progress" msgid="8486454116357963238">"Мүчүлүштүк тууралуу кабар даярдалууда"</string>
     <string name="notification_bugreport_finished_title" msgid="3970195939909624320">"Мүчүлүштүк тууралуу кабар алынды"</string>
-    <string name="notification_bugreport_channel_name" msgid="776902295433824255">"Мүчүлүштүк тууралуу кабар берүү абалынын каналы"</string>
+    <string name="notification_bugreport_channel_name" msgid="776902295433824255">"Мүчүлүштүк тууралуу кабарлоо абалынын каналы"</string>
 </resources>
diff --git a/tests/BugReportApp/res/values/dimens.xml b/tests/BugReportApp/res/values/dimens.xml
index 7f7967f..cb41f89 100644
--- a/tests/BugReportApp/res/values/dimens.xml
+++ b/tests/BugReportApp/res/values/dimens.xml
@@ -20,6 +20,7 @@
     <dimen name="bug_report_padding">30dp</dimen>
 
     <dimen name="bug_report_default_text_size">28dp</dimen>
+    <dimen name="bug_report_small_text_size">24dp</dimen>
 
     <!-- VoiceRecordingView dimensions -->
     <dimen name="bug_report_voice_recording_margin_top">20dp</dimen>
diff --git a/tests/BugReportApp/res/values/styles.xml b/tests/BugReportApp/res/values/styles.xml
index 6d8dd96..9b146a2 100644
--- a/tests/BugReportApp/res/values/styles.xml
+++ b/tests/BugReportApp/res/values/styles.xml
@@ -22,4 +22,17 @@
     <item name="android:clickable">true</item>
     <item name="android:background">@drawable/item_background</item>
   </style>
+
+  <style name="Widget.BugReportUi.InfoActionButton" parent="android:Widget.DeviceDefault.Button">
+    <item name="android:textSize">@dimen/bug_report_button_text_size</item>
+  </style>
+
+  <style name="TextAppearance.BugReportUi.Title" parent="android:TextAppearance.DeviceDefault">
+    <item name="android:textSize">@dimen/bug_report_default_text_size</item>
+  </style>
+
+  <style name="TextAppearance.BugReportUi.Body" parent="android:TextAppearance.DeviceDefault">
+    <item name="android:textColor">@*android:color/car_body1</item>
+    <item name="android:textSize">@dimen/bug_report_small_text_size</item>
+  </style>
 </resources>
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/BugInfoAdapter.java b/tests/BugReportApp/src/com/android/car/bugreport/BugInfoAdapter.java
new file mode 100644
index 0000000..7d508b1
--- /dev/null
+++ b/tests/BugReportApp/src/com/android/car/bugreport/BugInfoAdapter.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.bugreport;
+
+import android.os.Build;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Shows bugreport title, status, status message and user action buttons. "Upload to Google" button
+ * is enabled when the status is {@link Status#STATUS_PENDING_USER_ACTION}, "Move to USB" button is
+ * enabled only when status is  {@link Status#STATUS_PENDING_USER_ACTION} and USB device is plugged
+ * in.
+ */
+public class BugInfoAdapter extends RecyclerView.Adapter<BugInfoAdapter.BugInfoViewHolder> {
+    static final int BUTTON_TYPE_UPLOAD = 0;
+    static final int BUTTON_TYPE_MOVE = 1;
+    static final int BUTTON_TYPE_ADD_AUDIO = 2;
+
+    /** Provides a handler for click events*/
+    interface ItemClickedListener {
+        /**
+         * Handles click events differently depending on provided buttonType and
+         * uses additional information provided in metaBugReport.
+         *
+         * @param buttonType One of {@link #BUTTON_TYPE_UPLOAD}, {@link #BUTTON_TYPE_MOVE} or
+         *                   {@link #BUTTON_TYPE_ADD_AUDIO}.
+         * @param metaBugReport Selected bugreport.
+         * @param holder ViewHolder of the clicked item.
+         */
+        void onItemClicked(int buttonType, MetaBugReport metaBugReport, BugInfoViewHolder holder);
+    }
+
+    /**
+     * Reference to each bug report info views.
+     */
+    static class BugInfoViewHolder extends RecyclerView.ViewHolder {
+        /** Title view */
+        TextView mTitleView;
+
+        /** Status View */
+        TextView mStatusView;
+
+        /** Message View */
+        TextView mMessageView;
+
+        /** Move Button */
+        Button mMoveButton;
+
+        /** Upload Button */
+        Button mUploadButton;
+
+        /** Add Audio Button */
+        Button mAddAudioButton;
+
+        BugInfoViewHolder(View v) {
+            super(v);
+            mTitleView = itemView.findViewById(R.id.bug_info_row_title);
+            mStatusView = itemView.findViewById(R.id.bug_info_row_status);
+            mMessageView = itemView.findViewById(R.id.bug_info_row_message);
+            mMoveButton = itemView.findViewById(R.id.bug_info_move_button);
+            mUploadButton = itemView.findViewById(R.id.bug_info_upload_button);
+            mAddAudioButton = itemView.findViewById(R.id.bug_info_add_audio_button);
+        }
+    }
+
+    private List<MetaBugReport> mDataset;
+    private final ItemClickedListener mItemClickedListener;
+    private final Config mConfig;
+
+    BugInfoAdapter(ItemClickedListener itemClickedListener, Config config) {
+        mItemClickedListener = itemClickedListener;
+        mDataset = new ArrayList<>();
+        mConfig = config;
+        // Allow RecyclerView to efficiently update UI; getItemId() is implemented below.
+        setHasStableIds(true);
+    }
+
+    @Override
+    public BugInfoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        // create a new view
+        View v = LayoutInflater.from(parent.getContext())
+                .inflate(R.layout.bug_info_view, parent, false);
+        return new BugInfoViewHolder(v);
+    }
+
+    @Override
+    public void onBindViewHolder(BugInfoViewHolder holder, int position) {
+        MetaBugReport bugreport = mDataset.get(position);
+        holder.mTitleView.setText(bugreport.getTitle());
+        holder.mStatusView.setText(Status.toString(bugreport.getStatus()));
+        holder.mMessageView.setText(bugreport.getStatusMessage());
+        if (bugreport.getStatusMessage().isEmpty()) {
+            holder.mMessageView.setVisibility(View.GONE);
+        } else {
+            holder.mMessageView.setVisibility(View.VISIBLE);
+        }
+        boolean enableUserActionButtons =
+                bugreport.getStatus() == Status.STATUS_PENDING_USER_ACTION.getValue()
+                        || bugreport.getStatus() == Status.STATUS_MOVE_FAILED.getValue()
+                        || bugreport.getStatus() == Status.STATUS_UPLOAD_FAILED.getValue();
+        if (enableUserActionButtons) {
+            holder.mMoveButton.setEnabled(true);
+            holder.mMoveButton.setVisibility(View.VISIBLE);
+            holder.mMoveButton.setOnClickListener(
+                    view -> mItemClickedListener.onItemClicked(BUTTON_TYPE_MOVE, bugreport,
+                            holder));
+        } else {
+            holder.mMoveButton.setEnabled(false);
+            holder.mMoveButton.setVisibility(View.GONE);
+        }
+        // Enable the upload button only for userdebug/eng builds.
+        if (enableUserActionButtons && Build.IS_DEBUGGABLE) {
+            holder.mUploadButton.setText(R.string.bugreport_upload_gcs_button_text);
+            holder.mUploadButton.setEnabled(true);
+            holder.mUploadButton.setVisibility(View.VISIBLE);
+            holder.mUploadButton.setOnClickListener(
+                    view -> mItemClickedListener.onItemClicked(BUTTON_TYPE_UPLOAD, bugreport,
+                            holder));
+        } else {
+            holder.mUploadButton.setVisibility(View.GONE);
+            holder.mUploadButton.setEnabled(false);
+        }
+        if (bugreport.getStatus() == Status.STATUS_AUDIO_PENDING.getValue()) {
+            if (mConfig.getAutoUpload()) {
+                holder.mAddAudioButton.setText(R.string.bugreport_add_audio_upload_button_text);
+            } else {
+                holder.mAddAudioButton.setText(R.string.bugreport_add_audio_button_text);
+            }
+            holder.mAddAudioButton.setEnabled(true);
+            holder.mAddAudioButton.setVisibility(View.VISIBLE);
+            holder.mAddAudioButton.setOnClickListener(view ->
+                    mItemClickedListener.onItemClicked(BUTTON_TYPE_ADD_AUDIO, bugreport, holder));
+        } else {
+            holder.mAddAudioButton.setEnabled(false);
+            holder.mAddAudioButton.setVisibility(View.GONE);
+        }
+    }
+
+    /** Sets dataSet; it copies the list, because it modifies it in this adapter. */
+    void setDataset(List<MetaBugReport> bugReports) {
+        mDataset = new ArrayList<>(bugReports);
+        notifyDataSetChanged();
+    }
+
+    /** Update a bug report in the data set. */
+    void updateBugReportInDataSet(MetaBugReport bugReport, int position) {
+        if (position != RecyclerView.NO_POSITION) {
+            mDataset.set(position, bugReport);
+            notifyItemChanged(position);
+        }
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return mDataset.get(position).getId();
+    }
+
+    @Override
+    public int getItemCount() {
+        return mDataset.size();
+    }
+}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/BugReportActivity.java b/tests/BugReportApp/src/com/android/car/bugreport/BugReportActivity.java
new file mode 100644
index 0000000..67ae314
--- /dev/null
+++ b/tests/BugReportApp/src/com/android/car/bugreport/BugReportActivity.java
@@ -0,0 +1,712 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.bugreport;
+
+import static com.android.car.bugreport.BugReportService.MAX_PROGRESS_VALUE;
+
+import android.Manifest;
+import android.app.Activity;
+import android.car.Car;
+import android.car.CarNotConnectedException;
+import android.car.drivingstate.CarDrivingStateEvent;
+import android.car.drivingstate.CarDrivingStateManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.media.AudioAttributes;
+import android.media.AudioFocusRequest;
+import android.media.AudioManager;
+import android.media.MediaRecorder;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.UserManager;
+import android.util.Log;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.google.common.base.Preconditions;
+import com.google.common.io.ByteStreams;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Random;
+
+/**
+ * Activity that shows two types of dialogs: starting a new bug report and current status of already
+ * in progress bug report.
+ *
+ * <p>If there is no in-progress bug report, it starts recording voice message. After clicking
+ * submit button it initiates {@link BugReportService}.
+ *
+ * <p>If bug report is in-progress, it shows a progress bar.
+ */
+public class BugReportActivity extends Activity {
+    private static final String TAG = BugReportActivity.class.getSimpleName();
+
+    /** Starts silent (no audio message recording) bugreporting. */
+    private static final String ACTION_START_SILENT =
+            "com.android.car.bugreport.action.START_SILENT";
+
+    /** This is deprecated action. Please start SILENT bugreport using {@link BugReportService}. */
+    private static final String ACTION_ADD_AUDIO =
+            "com.android.car.bugreport.action.ADD_AUDIO";
+
+    private static final int VOICE_MESSAGE_MAX_DURATION_MILLIS = 60 * 1000;
+    private static final int AUDIO_PERMISSIONS_REQUEST_ID = 1;
+
+    private static final String EXTRA_BUGREPORT_ID = "bugreport-id";
+
+    /**
+     * NOTE: mRecorder related messages are cleared when the activity finishes.
+     */
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+    /** Look up string length, e.g. [ABCDEF]. */
+    static final int LOOKUP_STRING_LENGTH = 6;
+
+    private TextView mInProgressTitleText;
+    private ProgressBar mProgressBar;
+    private TextView mProgressText;
+    private TextView mAddAudioText;
+    private VoiceRecordingView mVoiceRecordingView;
+    private View mVoiceRecordingFinishedView;
+    private View mSubmitBugReportLayout;
+    private View mInProgressLayout;
+    private View mShowBugReportsButton;
+    private Button mSubmitButton;
+
+    private boolean mBound;
+    /** Audio message recording process started (including waiting for permission). */
+    private boolean mAudioRecordingStarted;
+    /** Audio recording using MIC is running (permission given). */
+    private boolean mAudioRecordingIsRunning;
+    private boolean mIsNewBugReport;
+    private boolean mIsOnActivityStartedWithBugReportServiceBoundCalled;
+    private boolean mIsSubmitButtonClicked;
+    private BugReportService mService;
+    private MediaRecorder mRecorder;
+    private MetaBugReport mMetaBugReport;
+    private File mAudioFile;
+    private Car mCar;
+    private CarDrivingStateManager mDrivingStateManager;
+    private AudioManager mAudioManager;
+    private AudioFocusRequest mLastAudioFocusRequest;
+    private Config mConfig;
+
+    /** Defines callbacks for service binding, passed to bindService() */
+    private ServiceConnection mConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            BugReportService.ServiceBinder binder = (BugReportService.ServiceBinder) service;
+            mService = binder.getService();
+            mBound = true;
+            onActivityStartedWithBugReportServiceBound();
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName arg0) {
+            // called when service connection breaks unexpectedly.
+            mBound = false;
+        }
+    };
+
+    /**
+     * Builds an intent that starts {@link BugReportActivity} to add audio message to the existing
+     * bug report.
+     */
+    static Intent buildAddAudioIntent(Context context, MetaBugReport bug) {
+        Intent addAudioIntent = new Intent(context, BugReportActivity.class);
+        addAudioIntent.setAction(ACTION_ADD_AUDIO);
+        addAudioIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        addAudioIntent.putExtra(EXTRA_BUGREPORT_ID, bug.getId());
+        return addAudioIntent;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        Preconditions.checkState(Config.isBugReportEnabled(), "BugReport is disabled.");
+
+        super.onCreate(savedInstanceState);
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+        // Bind to BugReportService.
+        Intent intent = new Intent(this, BugReportService.class);
+        bindService(intent, mConnection, BIND_AUTO_CREATE);
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+
+        if (mBound) {
+            onActivityStartedWithBugReportServiceBound();
+        }
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        // If SUBMIT button is clicked, cancelling audio has been taken care of.
+        if (!mIsSubmitButtonClicked) {
+            cancelAudioMessageRecording();
+        }
+        if (mBound) {
+            mService.removeBugReportProgressListener();
+        }
+        // Reset variables for the next onStart().
+        mAudioRecordingStarted = false;
+        mAudioRecordingIsRunning = false;
+        mIsSubmitButtonClicked = false;
+        mIsOnActivityStartedWithBugReportServiceBoundCalled = false;
+        mMetaBugReport = null;
+        mAudioFile = null;
+    }
+
+    @Override
+    public void onDestroy() {
+        if (mRecorder != null) {
+            mHandler.removeCallbacksAndMessages(/* token= */ mRecorder);
+        }
+        if (mBound) {
+            unbindService(mConnection);
+            mBound = false;
+        }
+        if (mCar != null && mCar.isConnected()) {
+            mCar.disconnect();
+            mCar = null;
+        }
+        super.onDestroy();
+    }
+
+    private void onCarDrivingStateChanged(CarDrivingStateEvent event) {
+        if (mShowBugReportsButton == null) {
+            Log.w(TAG, "Cannot handle driving state change, UI is not ready");
+            return;
+        }
+        // When adding audio message to the existing bugreport, do not show "Show Bug Reports"
+        // button, users either should explicitly Submit or Cancel.
+        if (mAudioRecordingStarted && !mIsNewBugReport) {
+            mShowBugReportsButton.setVisibility(View.GONE);
+            return;
+        }
+        if (event.eventValue == CarDrivingStateEvent.DRIVING_STATE_PARKED
+                || event.eventValue == CarDrivingStateEvent.DRIVING_STATE_IDLING) {
+            mShowBugReportsButton.setVisibility(View.VISIBLE);
+        } else {
+            mShowBugReportsButton.setVisibility(View.GONE);
+        }
+    }
+
+    private void onProgressChanged(float progress) {
+        int progressValue = (int) progress;
+        mProgressBar.setProgress(progressValue);
+        mProgressText.setText(progressValue + "%");
+        if (progressValue == MAX_PROGRESS_VALUE) {
+            mInProgressTitleText.setText(R.string.bugreport_dialog_in_progress_title_finished);
+        }
+    }
+
+    private void prepareUi() {
+        if (mSubmitBugReportLayout != null) {
+            return;
+        }
+        setContentView(R.layout.bug_report_activity);
+
+        // Connect to the services here, because they are used only when showing the dialog.
+        // We need to minimize system state change when performing SILENT bug report.
+        mConfig = new Config();
+        mConfig.start();
+        mCar = Car.createCar(this, /* handler= */ null,
+                Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT, this::onCarLifecycleChanged);
+
+        mInProgressTitleText = findViewById(R.id.in_progress_title_text);
+        mProgressBar = findViewById(R.id.progress_bar);
+        mProgressText = findViewById(R.id.progress_text);
+        mAddAudioText = findViewById(R.id.bug_report_add_audio_to_existing);
+        mVoiceRecordingView = findViewById(R.id.voice_recording_view);
+        mVoiceRecordingFinishedView = findViewById(R.id.voice_recording_finished_text_view);
+        mSubmitBugReportLayout = findViewById(R.id.submit_bug_report_layout);
+        mInProgressLayout = findViewById(R.id.in_progress_layout);
+        mShowBugReportsButton = findViewById(R.id.button_show_bugreports);
+        mSubmitButton = findViewById(R.id.button_submit);
+
+        mShowBugReportsButton.setOnClickListener(this::buttonShowBugReportsClick);
+        mSubmitButton.setOnClickListener(this::buttonSubmitClick);
+        findViewById(R.id.button_cancel).setOnClickListener(this::buttonCancelClick);
+        findViewById(R.id.button_close).setOnClickListener(this::buttonCancelClick);
+
+        if (mIsNewBugReport) {
+            mSubmitButton.setText(R.string.bugreport_dialog_submit);
+        } else {
+            mSubmitButton.setText(mConfig.getAutoUpload()
+                    ? R.string.bugreport_dialog_upload : R.string.bugreport_dialog_save);
+        }
+    }
+
+    private void onCarLifecycleChanged(Car car, boolean ready) {
+        if (!ready) {
+            mDrivingStateManager = null;
+            mCar = null;
+            Log.d(TAG, "Car service is not ready, ignoring");
+            // If car service is not ready for this activity, just ignore it - as it's only
+            // used to control UX restrictions.
+            return;
+        }
+        try {
+            mDrivingStateManager = (CarDrivingStateManager) car.getCarManager(
+                    Car.CAR_DRIVING_STATE_SERVICE);
+            mDrivingStateManager.registerListener(
+                    BugReportActivity.this::onCarDrivingStateChanged);
+            // Call onCarDrivingStateChanged(), because it's not called when Car is connected.
+            onCarDrivingStateChanged(mDrivingStateManager.getCurrentCarDrivingState());
+        } catch (CarNotConnectedException e) {
+            Log.w(TAG, "Failed to get CarDrivingStateManager", e);
+        }
+    }
+
+    private void showInProgressUi() {
+        mSubmitBugReportLayout.setVisibility(View.GONE);
+        mInProgressLayout.setVisibility(View.VISIBLE);
+        mInProgressTitleText.setText(R.string.bugreport_dialog_in_progress_title);
+        onProgressChanged(mService.getBugReportProgress());
+    }
+
+    private void showSubmitBugReportUi(boolean isRecording) {
+        mSubmitBugReportLayout.setVisibility(View.VISIBLE);
+        mInProgressLayout.setVisibility(View.GONE);
+        if (isRecording) {
+            mVoiceRecordingFinishedView.setVisibility(View.GONE);
+            mVoiceRecordingView.setVisibility(View.VISIBLE);
+        } else {
+            mVoiceRecordingFinishedView.setVisibility(View.VISIBLE);
+            mVoiceRecordingView.setVisibility(View.GONE);
+        }
+        // NOTE: mShowBugReportsButton visibility is also handled in #onCarDrivingStateChanged().
+        mShowBugReportsButton.setVisibility(View.GONE);
+        if (mDrivingStateManager != null) {
+            try {
+                onCarDrivingStateChanged(mDrivingStateManager.getCurrentCarDrivingState());
+            } catch (CarNotConnectedException e) {
+                Log.e(TAG, "Failed to get current driving state.", e);
+            }
+        }
+    }
+
+    /**
+     * Initializes MetaBugReport in a local DB and starts audio recording.
+     *
+     * <p>This method expected to be called when the activity is started and bound to the service.
+     */
+    private void onActivityStartedWithBugReportServiceBound() {
+        if (mIsOnActivityStartedWithBugReportServiceBoundCalled) {
+            return;
+        }
+        mIsOnActivityStartedWithBugReportServiceBoundCalled = true;
+
+        if (mService.isCollectingBugReport()) {
+            Log.i(TAG, "Bug report is already being collected.");
+            mService.setBugReportProgressListener(this::onProgressChanged);
+            prepareUi();
+            showInProgressUi();
+            return;
+        }
+
+        if (ACTION_START_SILENT.equals(getIntent().getAction())) {
+            Log.i(TAG, "Starting a silent bugreport.");
+            MetaBugReport bugReport = createBugReport(this, MetaBugReport.TYPE_SILENT);
+            startBugReportCollection(bugReport);
+            finish();
+            return;
+        }
+
+        // Close the notification shade and other dialogs when showing BugReportActivity dialog.
+        sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+
+        if (ACTION_ADD_AUDIO.equals(getIntent().getAction())) {
+            addAudioToExistingBugReport(
+                    getIntent().getIntExtra(EXTRA_BUGREPORT_ID, /* defaultValue= */ -1));
+            return;
+        }
+
+        Log.i(TAG, "Starting an interactive bugreport.");
+        createNewBugReportWithAudioMessage();
+    }
+
+    private void addAudioToExistingBugReport(int bugreportId) {
+        MetaBugReport bug = BugStorageUtils.findBugReport(this, bugreportId).orElseThrow(
+                () -> new RuntimeException("Failed to find bug report with id " + bugreportId));
+        Log.i(TAG, "Adding audio to the existing bugreport " + bug.getTimestamp());
+        if (bug.getStatus() != Status.STATUS_AUDIO_PENDING.getValue()) {
+            Log.e(TAG, "Failed to add audio, bad status, expected "
+                    + Status.STATUS_AUDIO_PENDING.getValue() + ", got " + bug.getStatus());
+            finish();
+        }
+        File audioFile;
+        try {
+            audioFile = File.createTempFile("audio", "mp3", getCacheDir());
+        } catch (IOException e) {
+            throw new RuntimeException("failed to create temp audio file");
+        }
+        startAudioMessageRecording(/* isNewBugReport= */ false, bug, audioFile);
+    }
+
+    private void createNewBugReportWithAudioMessage() {
+        MetaBugReport bug = createBugReport(this, MetaBugReport.TYPE_INTERACTIVE);
+        startAudioMessageRecording(
+                /* isNewBugReport= */ true,
+                bug,
+                FileUtils.getFileWithSuffix(this, bug.getTimestamp(), "-message.3gp"));
+    }
+
+    /** Shows a dialog UI and starts recording audio message. */
+    private void startAudioMessageRecording(
+            boolean isNewBugReport, MetaBugReport bug, File audioFile) {
+        if (mAudioRecordingStarted) {
+            Log.i(TAG, "Audio message recording is already started.");
+            return;
+        }
+        mAudioRecordingStarted = true;
+        mAudioManager = getSystemService(AudioManager.class);
+        mIsNewBugReport = isNewBugReport;
+        mMetaBugReport = bug;
+        mAudioFile = audioFile;
+        prepareUi();
+        showSubmitBugReportUi(/* isRecording= */ true);
+        if (isNewBugReport) {
+            mAddAudioText.setVisibility(View.GONE);
+        } else {
+            mAddAudioText.setVisibility(View.VISIBLE);
+            mAddAudioText.setText(String.format(
+                    getString(R.string.bugreport_dialog_add_audio_to_existing),
+                    mMetaBugReport.getTimestamp()));
+        }
+
+        if (!hasRecordPermissions()) {
+            requestRecordPermissions();
+        } else {
+            startRecordingWithPermission();
+        }
+    }
+
+    /**
+     * Cancels bugreporting by stopping audio recording and deleting temp files.
+     */
+    private void cancelAudioMessageRecording() {
+        // If audio recording is not running, most likely there were permission issues,
+        // so leave the bugreport as is without cancelling it.
+        if (!mAudioRecordingIsRunning) {
+            Log.w(TAG, "Cannot cancel, audio recording is not running.");
+            return;
+        }
+        stopAudioRecording();
+        if (mIsNewBugReport) {
+            // The app creates a temp dir only for new INTERACTIVE bugreports.
+            File tempDir = FileUtils.getTempDir(this, mMetaBugReport.getTimestamp());
+            new DeleteFilesAndDirectoriesAsyncTask().execute(tempDir);
+        } else {
+            BugStorageUtils.deleteBugReportFiles(this, mMetaBugReport.getId());
+            new DeleteFilesAndDirectoriesAsyncTask().execute(mAudioFile);
+        }
+        BugStorageUtils.setBugReportStatus(
+                this, mMetaBugReport, Status.STATUS_USER_CANCELLED, "");
+        Log.i(TAG, "Bug report " + mMetaBugReport.getTimestamp() + " is cancelled");
+        mAudioRecordingStarted = false;
+        mAudioRecordingIsRunning = false;
+    }
+
+    private void buttonCancelClick(View view) {
+        finish();
+    }
+
+    private void buttonSubmitClick(View view) {
+        stopAudioRecording();
+        mIsSubmitButtonClicked = true;
+        if (mIsNewBugReport) {
+            Log.i(TAG, "Starting bugreport service.");
+            startBugReportCollection(mMetaBugReport);
+        } else {
+            Log.i(TAG, "Adding audio file to the bugreport " + mMetaBugReport.getTimestamp());
+            new AddAudioToBugReportAsyncTask(this, mConfig, mMetaBugReport, mAudioFile).execute();
+        }
+        setResult(Activity.RESULT_OK);
+        finish();
+    }
+
+    /** Starts the {@link BugReportService} to collect bug report. */
+    private void startBugReportCollection(MetaBugReport bug) {
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(BugReportService.EXTRA_META_BUG_REPORT, bug);
+        Intent intent = new Intent(this, BugReportService.class);
+        intent.putExtras(bundle);
+        startForegroundService(intent);
+    }
+
+    /**
+     * Starts {@link BugReportInfoActivity} and finishes current activity, so it won't be running
+     * in the background and closing {@link BugReportInfoActivity} will not open the current
+     * activity again.
+     */
+    private void buttonShowBugReportsClick(View view) {
+        // First cancel the audio recording, then delete the bug report from database.
+        cancelAudioMessageRecording();
+        // Delete the bugreport from database, otherwise pressing "Show Bugreports" button will
+        // create unnecessary cancelled bugreports.
+        if (mMetaBugReport != null) {
+            BugStorageUtils.completeDeleteBugReport(this, mMetaBugReport.getId());
+        }
+        Intent intent = new Intent(this, BugReportInfoActivity.class);
+        startActivity(intent);
+        finish();
+    }
+
+    private void requestRecordPermissions() {
+        requestPermissions(
+                new String[]{Manifest.permission.RECORD_AUDIO}, AUDIO_PERMISSIONS_REQUEST_ID);
+    }
+
+    private boolean hasRecordPermissions() {
+        return checkSelfPermission(Manifest.permission.RECORD_AUDIO)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
+    @Override
+    public void onRequestPermissionsResult(
+            int requestCode, String[] permissions, int[] grantResults) {
+        if (requestCode != AUDIO_PERMISSIONS_REQUEST_ID) {
+            return;
+        }
+        for (int i = 0; i < grantResults.length; i++) {
+            if (Manifest.permission.RECORD_AUDIO.equals(permissions[i])
+                    && grantResults[i] == PackageManager.PERMISSION_GRANTED) {
+                // Start recording from UI thread, otherwise when MediaRecord#start() fails,
+                // stack trace gets confusing.
+                mHandler.post(this::startRecordingWithPermission);
+                return;
+            }
+        }
+        handleNoPermission(permissions);
+    }
+
+    private void handleNoPermission(String[] permissions) {
+        String text = this.getText(R.string.toast_permissions_denied) + " : "
+                + Arrays.toString(permissions);
+        Log.w(TAG, text);
+        Toast.makeText(this, text, Toast.LENGTH_LONG).show();
+        if (mIsNewBugReport) {
+            BugStorageUtils.setBugReportStatus(this, mMetaBugReport,
+                    Status.STATUS_USER_CANCELLED, text);
+        } else {
+            BugStorageUtils.setBugReportStatus(this, mMetaBugReport,
+                    Status.STATUS_AUDIO_PENDING, text);
+        }
+        finish();
+    }
+
+    private void startRecordingWithPermission() {
+        Log.i(TAG, "Started voice recording, and saving audio to " + mAudioFile);
+
+        mLastAudioFocusRequest = new AudioFocusRequest.Builder(
+                        AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)
+                .setOnAudioFocusChangeListener(focusChange ->
+                        Log.d(TAG, "AudioManager focus change " + focusChange))
+                .setAudioAttributes(new AudioAttributes.Builder()
+                        .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
+                        .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
+                        .build())
+                .setAcceptsDelayedFocusGain(true)
+                .build();
+        int focusGranted = mAudioManager.requestAudioFocus(mLastAudioFocusRequest);
+        // NOTE: We will record even if the audio focus was not granted.
+        Log.d(TAG,
+                "AudioFocus granted " + (focusGranted == AudioManager.AUDIOFOCUS_REQUEST_GRANTED));
+
+        mRecorder = new MediaRecorder();
+        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(mAudioFile);
+
+        try {
+            mRecorder.prepare();
+        } catch (IOException e) {
+            Log.e(TAG, "Failed on MediaRecorder#prepare(), filename: " + mAudioFile, e);
+            finish();
+            return;
+        }
+
+        mRecorder.start();
+        mVoiceRecordingView.setRecorder(mRecorder);
+        mAudioRecordingIsRunning = true;
+
+        // Messages with token mRecorder are cleared when the activity finishes or recording stops.
+        mHandler.postDelayed(() -> {
+            Log.i(TAG, "Timed out while recording voice message, cancelling.");
+            stopAudioRecording();
+            showSubmitBugReportUi(/* isRecording= */ false);
+        }, /* token= */ mRecorder, VOICE_MESSAGE_MAX_DURATION_MILLIS);
+    }
+
+    private void stopAudioRecording() {
+        if (mRecorder != null) {
+            Log.i(TAG, "Recording ended, stopping the MediaRecorder.");
+            mHandler.removeCallbacksAndMessages(/* token= */ mRecorder);
+            try {
+                mRecorder.stop();
+            } catch (RuntimeException 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;
+        }
+        if (mLastAudioFocusRequest != null) {
+            int focusAbandoned = mAudioManager.abandonAudioFocusRequest(mLastAudioFocusRequest);
+            Log.d(TAG, "Audio focus abandoned "
+                    + (focusAbandoned == AudioManager.AUDIOFOCUS_REQUEST_GRANTED));
+            mLastAudioFocusRequest = null;
+        }
+        mVoiceRecordingView.setRecorder(null);
+    }
+
+    private static String getCurrentUserName(Context context) {
+        UserManager um = UserManager.get(context);
+        return um.getUserName();
+    }
+
+    /**
+     * Creates a {@link MetaBugReport} and saves it in a local sqlite database.
+     *
+     * @param context an Android context.
+     * @param type bug report type, {@link MetaBugReport.BugReportType}.
+     */
+    static MetaBugReport createBugReport(Context context, int type) {
+        String timestamp = MetaBugReport.toBugReportTimestamp(new Date());
+        String username = getCurrentUserName(context);
+        String title = BugReportTitleGenerator.generateBugReportTitle(timestamp, username);
+        return BugStorageUtils.createBugReport(context, title, timestamp, username, type);
+    }
+
+    /** A helper class to generate bugreport title. */
+    private static final class BugReportTitleGenerator {
+        /** Contains easily readable characters. */
+        private static final char[] CHARS_FOR_RANDOM_GENERATOR =
+                new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P',
+                        'R', 'S', 'T', 'U', 'W', 'X', 'Y', 'Z'};
+
+        /**
+         * Generates a bugreport title from given timestamp and username.
+         *
+         * <p>Example: "[A45E8] Feedback from user Driver at 2019-09-21_12:00:00"
+         */
+        static String generateBugReportTitle(String timestamp, String username) {
+            // Lookup string is used to search a bug in Buganizer (see b/130915969).
+            String lookupString = generateRandomString(LOOKUP_STRING_LENGTH);
+            return "[" + lookupString + "] Feedback from user " + username + " at " + timestamp;
+        }
+
+        private static String generateRandomString(int length) {
+            Random random = new Random();
+            StringBuilder builder = new StringBuilder();
+            for (int i = 0; i < length; i++) {
+                int randomIndex = random.nextInt(CHARS_FOR_RANDOM_GENERATOR.length);
+                builder.append(CHARS_FOR_RANDOM_GENERATOR[randomIndex]);
+            }
+            return builder.toString();
+        }
+    }
+
+    /** AsyncTask that recursively deletes files and directories. */
+    private static class DeleteFilesAndDirectoriesAsyncTask extends AsyncTask<File, Void, Void> {
+        @Override
+        protected Void doInBackground(File... files) {
+            for (File file : files) {
+                Log.i(TAG, "Deleting " + file.getAbsolutePath());
+                if (file.isFile()) {
+                    file.delete();
+                } else {
+                    FileUtils.deleteDirectory(file);
+                }
+            }
+            return null;
+        }
+    }
+
+    /**
+     * AsyncTask that moves audio file to the system user's {@link FileUtils#getPendingDir} and
+     * sets status to either STATUS_UPLOAD_PENDING or STATUS_PENDING_USER_ACTION.
+     */
+    private static class AddAudioToBugReportAsyncTask extends AsyncTask<Void, Void, Void> {
+        private final Context mContext;
+        private final Config mConfig;
+        private final File mAudioFile;
+        private final MetaBugReport mOriginalBug;
+
+        AddAudioToBugReportAsyncTask(
+                Context context, Config config, MetaBugReport bug, File audioFile) {
+            mContext = context;
+            mConfig = config;
+            mOriginalBug = bug;
+            mAudioFile = audioFile;
+        }
+
+        @Override
+        protected Void doInBackground(Void... voids) {
+            String audioFileName = FileUtils.getAudioFileName(
+                    MetaBugReport.toBugReportTimestamp(new Date()), mOriginalBug);
+            MetaBugReport bug = BugStorageUtils.update(mContext,
+                    mOriginalBug.toBuilder().setAudioFileName(audioFileName).build());
+            try (OutputStream out = BugStorageUtils.openAudioMessageFileToWrite(mContext, bug);
+                 InputStream input = new FileInputStream(mAudioFile)) {
+                ByteStreams.copy(input, out);
+            } catch (IOException e) {
+                BugStorageUtils.setBugReportStatus(mContext, bug,
+                        com.android.car.bugreport.Status.STATUS_WRITE_FAILED,
+                        "Failed to write audio to bug report");
+                Log.e(TAG, "Failed to write audio to bug report", e);
+                return null;
+            }
+            if (mConfig.getAutoUpload()) {
+                BugStorageUtils.setBugReportStatus(mContext, bug,
+                        com.android.car.bugreport.Status.STATUS_UPLOAD_PENDING, "");
+            } else {
+                BugStorageUtils.setBugReportStatus(mContext, bug,
+                        com.android.car.bugreport.Status.STATUS_PENDING_USER_ACTION, "");
+                BugReportService.showBugReportFinishedNotification(mContext, bug);
+            }
+            mAudioFile.delete();
+            return null;
+        }
+    }
+}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/BugReportInfoActivity.java b/tests/BugReportApp/src/com/android/car/bugreport/BugReportInfoActivity.java
new file mode 100644
index 0000000..71c3aa8
--- /dev/null
+++ b/tests/BugReportApp/src/com/android/car/bugreport/BugReportInfoActivity.java
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.bugreport;
+
+import static com.android.car.bugreport.PackageUtils.getPackageVersion;
+
+import android.app.Activity;
+import android.app.NotificationManager;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.res.AssetFileDescriptor;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.DocumentsContract;
+import android.util.Log;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.recyclerview.widget.DividerItemDecoration;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.io.ByteStreams;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * Provides an activity that provides information on the bugreports that are filed.
+ */
+public class BugReportInfoActivity extends Activity {
+    public static final String TAG = BugReportInfoActivity.class.getSimpleName();
+
+    /** Used for moving bug reports to a new location (e.g. USB drive). */
+    private static final int SELECT_DIRECTORY_REQUEST_CODE = 1;
+
+    /** Used to start {@link BugReportActivity} to add audio message. */
+    private static final int ADD_AUDIO_MESSAGE_REQUEST_CODE = 2;
+
+    private RecyclerView mRecyclerView;
+    private BugInfoAdapter mBugInfoAdapter;
+    private RecyclerView.LayoutManager mLayoutManager;
+    private NotificationManager mNotificationManager;
+    private MetaBugReport mLastSelectedBugReport;
+    private BugInfoAdapter.BugInfoViewHolder mLastSelectedBugInfoViewHolder;
+    private BugStorageObserver mBugStorageObserver;
+    private Config mConfig;
+    private boolean mAudioRecordingStarted;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        Preconditions.checkState(Config.isBugReportEnabled(), "BugReport is disabled.");
+
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.bug_report_info_activity);
+
+        mNotificationManager = getSystemService(NotificationManager.class);
+
+        mRecyclerView = findViewById(R.id.rv_bug_report_info);
+        mRecyclerView.setHasFixedSize(true);
+        // use a linear layout manager
+        mLayoutManager = new LinearLayoutManager(this);
+        mRecyclerView.setLayoutManager(mLayoutManager);
+        mRecyclerView.addItemDecoration(new DividerItemDecoration(mRecyclerView.getContext(),
+                DividerItemDecoration.VERTICAL));
+
+        mConfig = new Config();
+        mConfig.start();
+
+        mBugInfoAdapter = new BugInfoAdapter(this::onBugReportItemClicked, mConfig);
+        mRecyclerView.setAdapter(mBugInfoAdapter);
+
+        mBugStorageObserver = new BugStorageObserver(this, new Handler());
+
+        findViewById(R.id.quit_button).setOnClickListener(this::onQuitButtonClick);
+        findViewById(R.id.start_bug_report_button).setOnClickListener(
+                this::onStartBugReportButtonClick);
+        ((TextView) findViewById(R.id.version_text_view)).setText(
+                String.format("v%s", getPackageVersion(this)));
+
+        cancelBugReportFinishedNotification();
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        new BugReportsLoaderAsyncTask(this).execute();
+        // As BugStorageProvider is running under user0, we register using USER_ALL.
+        getContentResolver().registerContentObserver(BugStorageProvider.BUGREPORT_CONTENT_URI, true,
+                mBugStorageObserver, UserHandle.USER_ALL);
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        getContentResolver().unregisterContentObserver(mBugStorageObserver);
+    }
+
+    /**
+     * Dismisses {@link BugReportService#BUGREPORT_FINISHED_NOTIF_ID}, otherwise the notification
+     * will stay there forever if this activity opened through the App Launcher.
+     */
+    private void cancelBugReportFinishedNotification() {
+        mNotificationManager.cancel(BugReportService.BUGREPORT_FINISHED_NOTIF_ID);
+    }
+
+    private void onBugReportItemClicked(
+            int buttonType, MetaBugReport bugReport, BugInfoAdapter.BugInfoViewHolder holder) {
+        if (buttonType == BugInfoAdapter.BUTTON_TYPE_UPLOAD) {
+            Log.i(TAG, "Uploading " + bugReport.getTimestamp());
+            BugStorageUtils.setBugReportStatus(this, bugReport, Status.STATUS_UPLOAD_PENDING, "");
+            // Refresh the UI to reflect the new status.
+            new BugReportsLoaderAsyncTask(this).execute();
+        } else if (buttonType == BugInfoAdapter.BUTTON_TYPE_MOVE) {
+            Log.i(TAG, "Moving " + bugReport.getTimestamp());
+            mLastSelectedBugReport = bugReport;
+            mLastSelectedBugInfoViewHolder = holder;
+            startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE),
+                    SELECT_DIRECTORY_REQUEST_CODE);
+        } else if (buttonType == BugInfoAdapter.BUTTON_TYPE_ADD_AUDIO) {
+            // Check mAudioRecordingStarted to prevent double click to BUTTON_TYPE_ADD_AUDIO.
+            if (!mAudioRecordingStarted) {
+                mAudioRecordingStarted = true;
+                startActivityForResult(BugReportActivity.buildAddAudioIntent(this, bugReport),
+                        ADD_AUDIO_MESSAGE_REQUEST_CODE);
+            }
+        } else {
+            throw new IllegalStateException("unreachable");
+        }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        if (requestCode == SELECT_DIRECTORY_REQUEST_CODE && resultCode == RESULT_OK) {
+            int takeFlags =
+                    data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION
+                            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+            Uri destDirUri = data.getData();
+            getContentResolver().takePersistableUriPermission(destDirUri, takeFlags);
+            if (mLastSelectedBugReport == null || mLastSelectedBugInfoViewHolder == null) {
+                Log.w(TAG, "No bug report is selected.");
+                return;
+            }
+            MetaBugReport updatedBugReport = BugStorageUtils.setBugReportStatus(this,
+                    mLastSelectedBugReport, Status.STATUS_MOVE_IN_PROGRESS, "");
+            mBugInfoAdapter.updateBugReportInDataSet(
+                    updatedBugReport, mLastSelectedBugInfoViewHolder.getAdapterPosition());
+            new AsyncMoveFilesTask(
+                this,
+                    mBugInfoAdapter,
+                    updatedBugReport,
+                    mLastSelectedBugInfoViewHolder,
+                    destDirUri).execute();
+        }
+    }
+
+    private void onQuitButtonClick(View view) {
+        finish();
+    }
+
+    private void onStartBugReportButtonClick(View view) {
+        Intent intent = new Intent(this, BugReportActivity.class);
+        // Clear top is needed, otherwise multiple BugReportActivity-ies get opened and
+        // MediaRecorder crashes.
+        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        startActivity(intent);
+    }
+
+    /**
+     * Print the Provider's state into the given stream. This gets invoked if
+     * you run "adb shell dumpsys activity BugReportInfoActivity".
+     *
+     * @param prefix Desired prefix to prepend at each line of output.
+     * @param fd The raw file descriptor that the dump is being sent to.
+     * @param writer The PrintWriter to which you should dump your state.  This will be
+     * closed for you after you return.
+     * @param args additional arguments to the dump request.
+     */
+    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+        super.dump(prefix, fd, writer, args);
+        mConfig.dump(prefix, writer);
+    }
+
+    /**
+     * Moves bugreport zip to USB drive and updates RecyclerView.
+     *
+     * <p>It merges bugreport zip file and audio file into one final zip file and moves it.
+     */
+    private static final class AsyncMoveFilesTask extends AsyncTask<Void, Void, MetaBugReport> {
+        private final BugReportInfoActivity mActivity;
+        private final MetaBugReport mBugReport;
+        private final Uri mDestinationDirUri;
+        /** RecyclerView.Adapter that contains all the bug reports. */
+        private final BugInfoAdapter mBugInfoAdapter;
+        /** ViewHolder for {@link #mBugReport}. */
+        private final BugInfoAdapter.BugInfoViewHolder mBugViewHolder;
+        private final ContentResolver mResolver;
+
+        AsyncMoveFilesTask(BugReportInfoActivity activity, BugInfoAdapter bugInfoAdapter,
+                MetaBugReport bugReport, BugInfoAdapter.BugInfoViewHolder holder,
+                Uri destinationDir) {
+            mActivity = activity;
+            mBugInfoAdapter = bugInfoAdapter;
+            mBugReport = bugReport;
+            mBugViewHolder = holder;
+            mDestinationDirUri = destinationDir;
+            mResolver = mActivity.getContentResolver();
+        }
+
+        /** Moves the bugreport to the USB drive and returns the updated {@link MetaBugReport}. */
+        @Override
+        protected MetaBugReport doInBackground(Void... params) {
+            try {
+                return copyFilesToUsb();
+            } catch (IOException e) {
+                Log.e(TAG, "Failed to copy bugreport "
+                        + mBugReport.getTimestamp() + " to USB", e);
+                return BugStorageUtils.setBugReportStatus(
+                    mActivity, mBugReport,
+                    com.android.car.bugreport.Status.STATUS_MOVE_FAILED, e);
+            }
+        }
+
+        private MetaBugReport copyFilesToUsb() throws IOException {
+            String documentId = DocumentsContract.getTreeDocumentId(mDestinationDirUri);
+            Uri parentDocumentUri =
+                    DocumentsContract.buildDocumentUriUsingTree(mDestinationDirUri, documentId);
+            if (!Strings.isNullOrEmpty(mBugReport.getFilePath())) {
+                // There are still old bugreports with deprecated filePath.
+                Uri sourceUri = BugStorageProvider.buildUriWithSegment(
+                        mBugReport.getId(), BugStorageProvider.URL_SEGMENT_OPEN_FILE);
+                copyFileToUsb(
+                        new File(mBugReport.getFilePath()).getName(), sourceUri, parentDocumentUri);
+            } else {
+                mergeFilesAndCopyToUsb(parentDocumentUri);
+            }
+            Log.d(TAG, "Deleting local bug report files.");
+            BugStorageUtils.deleteBugReportFiles(mActivity, mBugReport.getId());
+            return BugStorageUtils.setBugReportStatus(mActivity, mBugReport,
+                    com.android.car.bugreport.Status.STATUS_MOVE_SUCCESSFUL,
+                    "Moved to: " + mDestinationDirUri.getPath());
+        }
+
+        private void mergeFilesAndCopyToUsb(Uri parentDocumentUri) throws IOException {
+            Uri sourceBugReport = BugStorageProvider.buildUriWithSegment(
+                    mBugReport.getId(), BugStorageProvider.URL_SEGMENT_OPEN_BUGREPORT_FILE);
+            Uri sourceAudio = BugStorageProvider.buildUriWithSegment(
+                    mBugReport.getId(), BugStorageProvider.URL_SEGMENT_OPEN_AUDIO_FILE);
+            String mimeType = mResolver.getType(sourceBugReport); // It's a zip file.
+            Uri newFileUri = DocumentsContract.createDocument(
+                    mResolver, parentDocumentUri, mimeType, mBugReport.getBugReportFileName());
+            if (newFileUri == null) {
+                throw new IOException(
+                        "Unable to create a file " + mBugReport.getBugReportFileName() + " in USB");
+            }
+            try (InputStream bugReportInput = mResolver.openInputStream(sourceBugReport);
+                 AssetFileDescriptor fd = mResolver.openAssetFileDescriptor(newFileUri, "w");
+                 OutputStream outputStream = fd.createOutputStream();
+                 ZipOutputStream zipOutStream =
+                         new ZipOutputStream(new BufferedOutputStream(outputStream))) {
+                // Extract bugreport zip file to the final zip file in USB drive.
+                ZipInputStream zipInStream = new ZipInputStream(bugReportInput);
+                ZipEntry entry;
+                while ((entry = zipInStream.getNextEntry()) != null) {
+                    ZipUtils.writeInputStreamToZipStream(
+                            entry.getName(), zipInStream, zipOutStream);
+                }
+                // Add audio file to the final zip file.
+                if (!Strings.isNullOrEmpty(mBugReport.getAudioFileName())) {
+                    try (InputStream audioInput = mResolver.openInputStream(sourceAudio)) {
+                        ZipUtils.writeInputStreamToZipStream(
+                                mBugReport.getAudioFileName(), audioInput, zipOutStream);
+                    }
+                }
+            }
+            try (AssetFileDescriptor fd = mResolver.openAssetFileDescriptor(newFileUri, "w")) {
+                // Force sync the written data from memory to the disk.
+                fd.getFileDescriptor().sync();
+            }
+            Log.d(TAG, "Writing to " + newFileUri + " finished");
+        }
+
+        private void copyFileToUsb(String filename, Uri sourceUri, Uri parentDocumentUri)
+                throws IOException {
+            String mimeType = mResolver.getType(sourceUri);
+            Uri newFileUri = DocumentsContract.createDocument(
+                    mResolver, parentDocumentUri, mimeType, filename);
+            if (newFileUri == null) {
+                throw new IOException("Unable to create a file " + filename + " in USB");
+            }
+            try (InputStream input = mResolver.openInputStream(sourceUri);
+                 AssetFileDescriptor fd = mResolver.openAssetFileDescriptor(newFileUri, "w")) {
+                OutputStream output = fd.createOutputStream();
+                ByteStreams.copy(input, output);
+                // Force sync the written data from memory to the disk.
+                fd.getFileDescriptor().sync();
+            }
+        }
+
+        @Override
+        protected void onPostExecute(MetaBugReport updatedBugReport) {
+            // Refresh the UI to reflect the new status.
+            mBugInfoAdapter.updateBugReportInDataSet(
+                    updatedBugReport, mBugViewHolder.getAdapterPosition());
+        }
+    }
+
+    /** Asynchronously loads bugreports from {@link BugStorageProvider}. */
+    private static final class BugReportsLoaderAsyncTask extends
+            AsyncTask<Void, Void, List<MetaBugReport>> {
+        private final WeakReference<BugReportInfoActivity> mBugReportInfoActivityWeakReference;
+
+        BugReportsLoaderAsyncTask(BugReportInfoActivity activity) {
+            mBugReportInfoActivityWeakReference = new WeakReference<>(activity);
+        }
+
+        @Override
+        protected List<MetaBugReport> doInBackground(Void... voids) {
+            BugReportInfoActivity activity = mBugReportInfoActivityWeakReference.get();
+            if (activity == null) {
+                Log.w(TAG, "Activity is gone, cancelling BugReportsLoaderAsyncTask.");
+                return new ArrayList<>();
+            }
+            return BugStorageUtils.getAllBugReportsDescending(activity);
+        }
+
+        @Override
+        protected void onPostExecute(List<MetaBugReport> result) {
+            BugReportInfoActivity activity = mBugReportInfoActivityWeakReference.get();
+            if (activity == null) {
+                Log.w(TAG, "Activity is gone, cancelling onPostExecute.");
+                return;
+            }
+            activity.mBugInfoAdapter.setDataset(result);
+        }
+    }
+
+    /** Observer for {@link BugStorageProvider}. */
+    private static class BugStorageObserver extends ContentObserver {
+        private final BugReportInfoActivity mInfoActivity;
+
+        /**
+         * Creates a content observer.
+         *
+         * @param activity A {@link BugReportInfoActivity} instance.
+         * @param handler The handler to run {@link #onChange} on, or null if none.
+         */
+        BugStorageObserver(BugReportInfoActivity activity, Handler handler) {
+            super(handler);
+            mInfoActivity = activity;
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            new BugReportsLoaderAsyncTask(mInfoActivity).execute();
+        }
+    }
+}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java b/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java
new file mode 100644
index 0000000..6d73052
--- /dev/null
+++ b/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java
@@ -0,0 +1,613 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.bugreport;
+
+import static android.car.CarBugreportManager.CarBugreportManagerCallback.CAR_BUGREPORT_DUMPSTATE_CONNECTION_FAILED;
+import static android.car.CarBugreportManager.CarBugreportManagerCallback.CAR_BUGREPORT_DUMPSTATE_FAILED;
+import static android.car.CarBugreportManager.CarBugreportManagerCallback.CAR_BUGREPORT_SERVICE_NOT_AVAILABLE;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
+import static com.android.car.bugreport.PackageUtils.getPackageVersion;
+
+import android.annotation.FloatRange;
+import android.annotation.StringRes;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.car.Car;
+import android.car.CarBugreportManager;
+import android.car.CarNotConnectedException;
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.display.DisplayManager;
+import android.media.AudioManager;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+import android.view.Display;
+import android.widget.Toast;
+
+import com.google.common.base.Preconditions;
+import com.google.common.io.ByteStreams;
+import com.google.common.util.concurrent.AtomicDouble;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * Service that captures screenshot and bug report using dumpstate and bluetooth snoop logs.
+ *
+ * <p>After collecting all the logs it sets the {@link MetaBugReport} status to
+ * {@link Status#STATUS_AUDIO_PENDING} or {@link Status#STATUS_PENDING_USER_ACTION} depending
+ * on {@link MetaBugReport#getType}.
+ *
+ * <p>If the service is started with action {@link #ACTION_START_SILENT}, it will start
+ * bugreporting without showing dialog and recording audio message, see
+ * {@link MetaBugReport#TYPE_SILENT}.
+ */
+public class BugReportService extends Service {
+    private static final String TAG = BugReportService.class.getSimpleName();
+
+    /**
+     * Extra data from intent - current bug report.
+     */
+    static final String EXTRA_META_BUG_REPORT = "meta_bug_report";
+
+    /** Starts silent (no audio message recording) bugreporting. */
+    private static final String ACTION_START_SILENT =
+            "com.android.car.bugreport.action.START_SILENT";
+
+    // Wait a short time before starting to capture the bugreport and the screen, so that
+    // bugreport activity can detach from the view tree.
+    // It is ugly to have a timeout, but it is ok here because such a delay should not really
+    // cause bugreport to be tainted with so many other events. If in the future we want to change
+    // this, the best option is probably to wait for onDetach events from view tree.
+    private static final int ACTIVITY_FINISH_DELAY_MILLIS = 1000;
+
+    /** Stop the service only after some delay, to allow toasts to show on the screen. */
+    private static final int STOP_SERVICE_DELAY_MILLIS = 1000;
+
+    /**
+     * Wait a short time before showing "bugreport started" toast message, because the service
+     * will take a screenshot of the screen.
+     */
+    private static final int BUGREPORT_STARTED_TOAST_DELAY_MILLIS = 2000;
+
+    private static final String BT_SNOOP_LOG_LOCATION = "/data/misc/bluetooth/logs/btsnoop_hci.log";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    /** Notifications on this channel will silently appear in notification bar. */
+    private static final String PROGRESS_CHANNEL_ID = "BUGREPORT_PROGRESS_CHANNEL";
+
+    /** Notifications on this channel will pop-up. */
+    private static final String STATUS_CHANNEL_ID = "BUGREPORT_STATUS_CHANNEL";
+
+    /** Persistent notification is shown when bugreport is in progress or waiting for audio. */
+    private static final int BUGREPORT_IN_PROGRESS_NOTIF_ID = 1;
+
+    /** Dismissible notification is shown when bugreport is collected. */
+    static final int BUGREPORT_FINISHED_NOTIF_ID = 2;
+
+    private static final String OUTPUT_ZIP_FILE = "output_file.zip";
+    private static final String EXTRA_OUTPUT_ZIP_FILE = "extra_output_file.zip";
+
+    private static final String MESSAGE_FAILURE_DUMPSTATE = "Failed to grab dumpstate";
+    private static final String MESSAGE_FAILURE_ZIP = "Failed to zip files";
+
+    private static final int PROGRESS_HANDLER_EVENT_PROGRESS = 1;
+    private static final String PROGRESS_HANDLER_DATA_PROGRESS = "progress";
+
+    static final float MAX_PROGRESS_VALUE = 100f;
+
+    /** Binder given to clients. */
+    private final IBinder mBinder = new ServiceBinder();
+
+    /** True if {@link BugReportService} is already collecting bugreport, including zipping. */
+    private final AtomicBoolean mIsCollectingBugReport = new AtomicBoolean(false);
+    private final AtomicDouble mBugReportProgress = new AtomicDouble(0);
+
+    private MetaBugReport mMetaBugReport;
+    private NotificationManager mNotificationManager;
+    private ScheduledExecutorService mSingleThreadExecutor;
+    private BugReportProgressListener mBugReportProgressListener;
+    private Car mCar;
+    private CarBugreportManager mBugreportManager;
+    private CarBugreportManager.CarBugreportManagerCallback mCallback;
+    private Config mConfig;
+    private Context mWindowContext;
+
+    /** A handler on the main thread. */
+    private Handler mHandler;
+    /**
+     * A handler to the main thread to show toast messages, it will be cleared when the service
+     * finishes. We need to clear it otherwise when bugreport fails, it will show "bugreport start"
+     * toast, which will confuse users.
+     */
+    private Handler mHandlerStartedToast;
+
+    /** A listener that's notified when bugreport progress changes. */
+    interface BugReportProgressListener {
+        /**
+         * Called when bug report progress changes.
+         *
+         * @param progress - a bug report progress in [0.0, 100.0].
+         */
+        void onProgress(float progress);
+    }
+
+    /** Client binder. */
+    public class ServiceBinder extends Binder {
+        BugReportService getService() {
+            // Return this instance of LocalService so clients can call public methods
+            return BugReportService.this;
+        }
+    }
+
+    /** A handler on the main thread. */
+    private class BugReportHandler extends Handler {
+        @Override
+        public void handleMessage(Message message) {
+            switch (message.what) {
+                case PROGRESS_HANDLER_EVENT_PROGRESS:
+                    if (mBugReportProgressListener != null) {
+                        float progress = message.getData().getFloat(PROGRESS_HANDLER_DATA_PROGRESS);
+                        mBugReportProgressListener.onProgress(progress);
+                    }
+                    showProgressNotification();
+                    break;
+                default:
+                    Log.d(TAG, "Unknown event " + message.what + ", ignoring.");
+            }
+        }
+    }
+
+    @Override
+    public void onCreate() {
+        Preconditions.checkState(Config.isBugReportEnabled(), "BugReport is disabled.");
+
+        DisplayManager dm = getSystemService(DisplayManager.class);
+        Display primaryDisplay = dm.getDisplay(DEFAULT_DISPLAY);
+        mWindowContext = createDisplayContext(primaryDisplay)
+                .createWindowContext(TYPE_APPLICATION_OVERLAY, null);
+
+        mNotificationManager = getSystemService(NotificationManager.class);
+        mNotificationManager.createNotificationChannel(new NotificationChannel(
+                PROGRESS_CHANNEL_ID,
+                getString(R.string.notification_bugreport_channel_name),
+                NotificationManager.IMPORTANCE_DEFAULT));
+        mNotificationManager.createNotificationChannel(new NotificationChannel(
+                STATUS_CHANNEL_ID,
+                getString(R.string.notification_bugreport_channel_name),
+                NotificationManager.IMPORTANCE_HIGH));
+        mSingleThreadExecutor = Executors.newSingleThreadScheduledExecutor();
+        mHandler = new BugReportHandler();
+        mHandlerStartedToast = new Handler();
+        mConfig = new Config();
+        mConfig.start();
+    }
+
+    @Override
+    public void onDestroy() {
+        if (DEBUG) {
+            Log.d(TAG, "Service destroyed");
+        }
+        disconnectFromCarService();
+    }
+
+    @Override
+    public int onStartCommand(final Intent intent, int flags, int startId) {
+        if (mIsCollectingBugReport.getAndSet(true)) {
+            Log.w(TAG, "bug report is already being collected, ignoring");
+            Toast.makeText(mWindowContext,
+                    R.string.toast_bug_report_in_progress, Toast.LENGTH_SHORT).show();
+            return START_NOT_STICKY;
+        }
+
+        Log.i(TAG, String.format("Will start collecting bug report, version=%s",
+                getPackageVersion(this)));
+
+        if (ACTION_START_SILENT.equals(intent.getAction())) {
+            Log.i(TAG, "Starting a silent bugreport.");
+            mMetaBugReport = BugReportActivity.createBugReport(this, MetaBugReport.TYPE_SILENT);
+        } else {
+            Bundle extras = intent.getExtras();
+            mMetaBugReport = extras.getParcelable(EXTRA_META_BUG_REPORT);
+        }
+
+        mBugReportProgress.set(0);
+
+        startForeground(BUGREPORT_IN_PROGRESS_NOTIF_ID, buildProgressNotification());
+        showProgressNotification();
+
+        collectBugReport();
+
+        // Show a short lived "bugreport started" toast message after a short delay.
+        mHandlerStartedToast.postDelayed(() -> {
+            Toast.makeText(mWindowContext,
+                    getText(R.string.toast_bug_report_started), Toast.LENGTH_LONG).show();
+        }, BUGREPORT_STARTED_TOAST_DELAY_MILLIS);
+
+        // If the service process gets killed due to heavy memory pressure, do not restart.
+        return START_NOT_STICKY;
+    }
+
+    private void onCarLifecycleChanged(Car car, boolean ready) {
+        // not ready - car service is crashed or is restarting.
+        if (!ready) {
+            mBugreportManager = null;
+            mCar = null;
+
+            // NOTE: dumpstate still might be running, but we can't kill it or reconnect to it
+            //       so we ignore it.
+            handleBugReportManagerError(CAR_BUGREPORT_SERVICE_NOT_AVAILABLE);
+            return;
+        }
+        try {
+            mBugreportManager = (CarBugreportManager) car.getCarManager(Car.CAR_BUGREPORT_SERVICE);
+        } catch (CarNotConnectedException | NoClassDefFoundError e) {
+            throw new IllegalStateException("Failed to get CarBugreportManager.", e);
+        }
+    }
+
+    /** Shows an updated progress notification. */
+    private void showProgressNotification() {
+        if (isCollectingBugReport()) {
+            mNotificationManager.notify(
+                    BUGREPORT_IN_PROGRESS_NOTIF_ID, buildProgressNotification());
+        }
+    }
+
+    private Notification buildProgressNotification() {
+        Intent intent = new Intent(getApplicationContext(), BugReportInfoActivity.class);
+        PendingIntent startBugReportInfoActivity =
+                PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);
+        return new Notification.Builder(this, PROGRESS_CHANNEL_ID)
+                .setContentTitle(getText(R.string.notification_bugreport_in_progress))
+                .setContentText(mMetaBugReport.getTitle())
+                .setSubText(String.format("%.1f%%", mBugReportProgress.get()))
+                .setSmallIcon(R.drawable.download_animation)
+                .setCategory(Notification.CATEGORY_STATUS)
+                .setOngoing(true)
+                .setProgress((int) MAX_PROGRESS_VALUE, (int) mBugReportProgress.get(), false)
+                .setContentIntent(startBugReportInfoActivity)
+                .build();
+    }
+
+    /** Returns true if bugreporting is in progress. */
+    public boolean isCollectingBugReport() {
+        return mIsCollectingBugReport.get();
+    }
+
+    /** Returns current bugreport progress. */
+    public float getBugReportProgress() {
+        return (float) mBugReportProgress.get();
+    }
+
+    /** Sets a bugreport progress listener. The listener is called on a main thread. */
+    public void setBugReportProgressListener(BugReportProgressListener listener) {
+        mBugReportProgressListener = listener;
+    }
+
+    /** Removes the bugreport progress listener. */
+    public void removeBugReportProgressListener() {
+        mBugReportProgressListener = null;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+
+    private void showToast(@StringRes int resId) {
+        // run on ui thread.
+        mHandler.post(
+                () -> Toast.makeText(mWindowContext, getText(resId), Toast.LENGTH_LONG).show());
+    }
+
+    private void disconnectFromCarService() {
+        if (mCar != null) {
+            mCar.disconnect();
+            mCar = null;
+        }
+        mBugreportManager = null;
+    }
+
+    private void connectToCarServiceSync() {
+        if (mCar == null || !(mCar.isConnected() || mCar.isConnecting())) {
+            mCar = Car.createCar(this, /* handler= */ null,
+                    Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, this::onCarLifecycleChanged);
+        }
+    }
+
+    private void collectBugReport() {
+        // Connect to the car service before collecting bugreport, because when car service crashes,
+        // BugReportService doesn't automatically reconnect to it.
+        connectToCarServiceSync();
+
+        if (Build.IS_USERDEBUG || Build.IS_ENG) {
+            mSingleThreadExecutor.schedule(
+                    this::grabBtSnoopLog, ACTIVITY_FINISH_DELAY_MILLIS, TimeUnit.MILLISECONDS);
+        }
+        mSingleThreadExecutor.schedule(
+                this::saveBugReport, ACTIVITY_FINISH_DELAY_MILLIS, TimeUnit.MILLISECONDS);
+    }
+
+    private void grabBtSnoopLog() {
+        Log.i(TAG, "Grabbing bt snoop log");
+        File result = FileUtils.getFileWithSuffix(this, mMetaBugReport.getTimestamp(),
+                "-btsnoop.bin.log");
+        File snoopFile = new File(BT_SNOOP_LOG_LOCATION);
+        if (!snoopFile.exists()) {
+            Log.w(TAG, BT_SNOOP_LOG_LOCATION + " not found, skipping");
+            return;
+        }
+        try (FileInputStream input = new FileInputStream(snoopFile);
+             FileOutputStream output = new FileOutputStream(result)) {
+            ByteStreams.copy(input, output);
+        } catch (IOException e) {
+            // this regularly happens when snooplog is not enabled so do not log as an error
+            Log.i(TAG, "Failed to grab bt snooplog, continuing to take bug report.", e);
+        }
+    }
+
+    private void saveBugReport() {
+        Log.i(TAG, "Dumpstate to file");
+        File outputFile = FileUtils.getFile(this, mMetaBugReport.getTimestamp(), OUTPUT_ZIP_FILE);
+        File extraOutputFile = FileUtils.getFile(this, mMetaBugReport.getTimestamp(),
+                EXTRA_OUTPUT_ZIP_FILE);
+        try (ParcelFileDescriptor outFd = ParcelFileDescriptor.open(outputFile,
+                ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_READ_WRITE);
+             ParcelFileDescriptor extraOutFd = ParcelFileDescriptor.open(extraOutputFile,
+                ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_READ_WRITE)) {
+            requestBugReport(outFd, extraOutFd);
+        } catch (IOException | RuntimeException e) {
+            Log.e(TAG, "Failed to grab dump state", e);
+            BugStorageUtils.setBugReportStatus(this, mMetaBugReport, Status.STATUS_WRITE_FAILED,
+                    MESSAGE_FAILURE_DUMPSTATE);
+            showToast(R.string.toast_status_dump_state_failed);
+            disconnectFromCarService();
+            mIsCollectingBugReport.set(false);
+        }
+    }
+
+    private void sendProgressEventToHandler(float progress) {
+        Message message = new Message();
+        message.what = PROGRESS_HANDLER_EVENT_PROGRESS;
+        message.getData().putFloat(PROGRESS_HANDLER_DATA_PROGRESS, progress);
+        mHandler.sendMessage(message);
+    }
+
+    private void requestBugReport(ParcelFileDescriptor outFd, ParcelFileDescriptor extraOutFd) {
+        if (DEBUG) {
+            Log.d(TAG, "Requesting a bug report from CarBugReportManager.");
+        }
+        mCallback = new CarBugreportManager.CarBugreportManagerCallback() {
+            @Override
+            public void onError(@CarBugreportErrorCode int errorCode) {
+                Log.e(TAG, "CarBugreportManager failed: " + errorCode);
+                disconnectFromCarService();
+                handleBugReportManagerError(errorCode);
+            }
+
+            @Override
+            public void onProgress(@FloatRange(from = 0f, to = MAX_PROGRESS_VALUE) float progress) {
+                mBugReportProgress.set(progress);
+                sendProgressEventToHandler(progress);
+            }
+
+            @Override
+            public void onFinished() {
+                Log.d(TAG, "CarBugreportManager finished");
+                disconnectFromCarService();
+                mBugReportProgress.set(MAX_PROGRESS_VALUE);
+                sendProgressEventToHandler(MAX_PROGRESS_VALUE);
+                mSingleThreadExecutor.submit(BugReportService.this::zipDirectoryAndUpdateStatus);
+            }
+        };
+        if (mBugreportManager == null) {
+            mHandler.post(() -> Toast.makeText(mWindowContext,
+                    "Car service is not ready", Toast.LENGTH_LONG).show());
+            Log.e(TAG, "CarBugReportManager is not ready");
+            return;
+        }
+        mBugreportManager.requestBugreport(outFd, extraOutFd, mCallback);
+    }
+
+    private void handleBugReportManagerError(
+            @CarBugreportManager.CarBugreportManagerCallback.CarBugreportErrorCode int errorCode) {
+        if (mMetaBugReport == null) {
+            Log.w(TAG, "No bugreport is running");
+            mIsCollectingBugReport.set(false);
+            return;
+        }
+        // We let the UI know that bug reporting is finished, because the next step is to
+        // zip everything and upload.
+        mBugReportProgress.set(MAX_PROGRESS_VALUE);
+        sendProgressEventToHandler(MAX_PROGRESS_VALUE);
+        showToast(R.string.toast_status_failed);
+        BugStorageUtils.setBugReportStatus(
+                BugReportService.this, mMetaBugReport,
+                Status.STATUS_WRITE_FAILED, getBugReportFailureStatusMessage(errorCode));
+        mHandler.postDelayed(() -> {
+            mNotificationManager.cancel(BUGREPORT_IN_PROGRESS_NOTIF_ID);
+            stopForeground(true);
+        }, STOP_SERVICE_DELAY_MILLIS);
+        mHandlerStartedToast.removeCallbacksAndMessages(null);
+        mMetaBugReport = null;
+        mIsCollectingBugReport.set(false);
+    }
+
+    private static String getBugReportFailureStatusMessage(
+            @CarBugreportManager.CarBugreportManagerCallback.CarBugreportErrorCode int errorCode) {
+        switch (errorCode) {
+            case CAR_BUGREPORT_DUMPSTATE_CONNECTION_FAILED:
+            case CAR_BUGREPORT_DUMPSTATE_FAILED:
+                return "Failed to connect to dumpstate. Retry again after a minute.";
+            case CAR_BUGREPORT_SERVICE_NOT_AVAILABLE:
+                return "Car service is not available. Retry again.";
+            default:
+                return "Car service bugreport collection failed: " + errorCode;
+        }
+    }
+
+    /**
+     * Shows a clickable bugreport finished notification. When clicked it opens
+     * {@link BugReportInfoActivity}.
+     */
+    static void showBugReportFinishedNotification(Context context, MetaBugReport bug) {
+        Intent intent = new Intent(context, BugReportInfoActivity.class);
+        PendingIntent startBugReportInfoActivity =
+                PendingIntent.getActivity(context, 0, intent, 0);
+        Notification notification = new Notification
+                .Builder(context, STATUS_CHANNEL_ID)
+                .setContentTitle(context.getText(R.string.notification_bugreport_finished_title))
+                .setContentText(bug.getTitle())
+                .setCategory(Notification.CATEGORY_STATUS)
+                .setSmallIcon(R.drawable.ic_upload)
+                .setContentIntent(startBugReportInfoActivity)
+                .build();
+        context.getSystemService(NotificationManager.class)
+                .notify(BUGREPORT_FINISHED_NOTIF_ID, notification);
+    }
+
+    /**
+     * Zips the temp directory, writes to the system user's {@link FileUtils#getPendingDir} and
+     * updates the bug report status.
+     *
+     * <p>For {@link MetaBugReport#TYPE_INTERACTIVE}: Sets status to either STATUS_UPLOAD_PENDING or
+     * STATUS_PENDING_USER_ACTION and shows a regular notification.
+     *
+     * <p>For {@link MetaBugReport#TYPE_SILENT}: Sets status to STATUS_AUDIO_PENDING and shows
+     * a dialog to record audio message.
+     */
+    private void zipDirectoryAndUpdateStatus() {
+        try {
+            // All the generated zip files, images and audio messages are located in this dir.
+            // This is located under the current user.
+            String bugreportFileName = FileUtils.getZipFileName(mMetaBugReport);
+            Log.d(TAG, "Zipping bugreport into " + bugreportFileName);
+            mMetaBugReport = BugStorageUtils.update(this,
+                    mMetaBugReport.toBuilder().setBugReportFileName(bugreportFileName).build());
+            File bugReportTempDir = FileUtils.createTempDir(this, mMetaBugReport.getTimestamp());
+            zipDirectoryToOutputStream(bugReportTempDir,
+                    BugStorageUtils.openBugReportFileToWrite(this, mMetaBugReport));
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to zip files", e);
+            BugStorageUtils.setBugReportStatus(this, mMetaBugReport, Status.STATUS_WRITE_FAILED,
+                    MESSAGE_FAILURE_ZIP);
+            showToast(R.string.toast_status_failed);
+            return;
+        }
+        if (mMetaBugReport.getType() == MetaBugReport.TYPE_SILENT) {
+            BugStorageUtils.setBugReportStatus(BugReportService.this,
+                    mMetaBugReport, Status.STATUS_AUDIO_PENDING, /* message= */ "");
+            playNotificationSound();
+            startActivity(BugReportActivity.buildAddAudioIntent(this, mMetaBugReport));
+        } else {
+            // NOTE: If bugreport type is INTERACTIVE, it will already contain an audio message.
+            Status status = mConfig.getAutoUpload()
+                    ? Status.STATUS_UPLOAD_PENDING : Status.STATUS_PENDING_USER_ACTION;
+            BugStorageUtils.setBugReportStatus(BugReportService.this,
+                    mMetaBugReport, status, /* message= */ "");
+            showBugReportFinishedNotification(this, mMetaBugReport);
+        }
+        mHandler.post(() -> {
+            mNotificationManager.cancel(BUGREPORT_IN_PROGRESS_NOTIF_ID);
+            stopForeground(true);
+        });
+        mHandlerStartedToast.removeCallbacksAndMessages(null);
+        mMetaBugReport = null;
+        mIsCollectingBugReport.set(false);
+    }
+
+    private void playNotificationSound() {
+        Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
+        Ringtone ringtone = RingtoneManager.getRingtone(getApplicationContext(), notification);
+        if (ringtone == null) {
+            Log.w(TAG, "No notification ringtone found.");
+            return;
+        }
+        float volume = ringtone.getVolume();
+        // Use volume from audio manager, otherwise default ringtone volume can be too loud.
+        AudioManager audioManager = getSystemService(AudioManager.class);
+        if (audioManager != null) {
+            int currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_NOTIFICATION);
+            int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_NOTIFICATION);
+            volume = (currentVolume + 0.0f) / maxVolume;
+        }
+        Log.v(TAG, "Using volume " + volume);
+        ringtone.setVolume(volume);
+        ringtone.play();
+    }
+
+    /**
+     * Compresses a directory into a zip file. The method is not recursive. Any sub-directory
+     * contained in the main directory and any files contained in the sub-directories will be
+     * skipped.
+     *
+     * @param dirToZip  The path of the directory to zip
+     * @param outStream The output stream to write the zip file to
+     * @throws IOException if the directory does not exist, its files cannot be read, or the output
+     *                     zip file cannot be written.
+     */
+    private void zipDirectoryToOutputStream(File dirToZip, OutputStream outStream)
+            throws IOException {
+        if (!dirToZip.isDirectory()) {
+            throw new IOException("zip directory does not exist");
+        }
+        Log.v(TAG, "zipping directory " + dirToZip.getAbsolutePath());
+
+        File[] listFiles = dirToZip.listFiles();
+        try (ZipOutputStream zipStream = new ZipOutputStream(new BufferedOutputStream(outStream))) {
+            for (File file : listFiles) {
+                if (file.isDirectory()) {
+                    continue;
+                }
+                String filename = file.getName();
+                // 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)) {
+                    ZipUtils.extractZippedFileToZipStream(file, zipStream);
+                } else {
+                    ZipUtils.addFileToZipStream(file, zipStream);
+                }
+            }
+        } finally {
+            outStream.close();
+        }
+        // Zipping successful, now cleanup the temp dir.
+        FileUtils.deleteDirectory(dirToZip);
+    }
+}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/BugStorageProvider.java b/tests/BugReportApp/src/com/android/car/bugreport/BugStorageProvider.java
new file mode 100644
index 0000000..729fc15
--- /dev/null
+++ b/tests/BugReportApp/src/com/android/car/bugreport/BugStorageProvider.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.bugreport;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringDef;
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.net.Uri;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.function.Function;
+
+
+/**
+ * Provides a bug storage interface to save and upload bugreports filed from all users.
+ * In Android Automotive user 0 runs as the system and all the time, while other users won't once
+ * their session ends. This content provider enables bug reports to be uploaded even after
+ * user session ends.
+ *
+ * <p>A bugreport constists of two files: bugreport zip file and audio file. Audio file is added
+ * later through notification. {@link SimpleUploaderAsyncTask} merges two files into one zip file
+ * before uploading.
+ *
+ * <p>All files are stored under system user's {@link FileUtils#getPendingDir}.
+ */
+public class BugStorageProvider extends ContentProvider {
+    private static final String TAG = BugStorageProvider.class.getSimpleName();
+
+    private static final String AUTHORITY = "com.android.car.bugreport";
+    private static final String BUG_REPORTS_TABLE = "bugreports";
+
+    /** Deletes files associated with a bug report. */
+    static final String URL_SEGMENT_DELETE_FILES = "deleteZipFile";
+    /** Destructively deletes a bug report. */
+    static final String URL_SEGMENT_COMPLETE_DELETE = "completeDelete";
+    /** Opens bugreport file of a bug report, uses column {@link #COLUMN_BUGREPORT_FILENAME}. */
+    static final String URL_SEGMENT_OPEN_BUGREPORT_FILE = "openBugReportFile";
+    /** Opens audio file of a bug report, uses column {@link #URL_MATCHED_OPEN_AUDIO_FILE}. */
+    static final String URL_SEGMENT_OPEN_AUDIO_FILE = "openAudioFile";
+    /**
+     * Opens final bugreport zip file, uses column {@link #COLUMN_FILEPATH}.
+     *
+     * <p>NOTE: This is the old way of storing final zipped bugreport. In
+     * {@code BugStorageProvider#AUDIO_VERSION} {@link #COLUMN_FILEPATH} is dropped. But there are
+     * still some devices with this field set.
+     */
+    static final String URL_SEGMENT_OPEN_FILE = "openFile";
+
+    // URL Matcher IDs.
+    private static final int URL_MATCHED_BUG_REPORTS_URI = 1;
+    private static final int URL_MATCHED_BUG_REPORT_ID_URI = 2;
+    private static final int URL_MATCHED_DELETE_FILES = 3;
+    private static final int URL_MATCHED_COMPLETE_DELETE = 4;
+    private static final int URL_MATCHED_OPEN_BUGREPORT_FILE = 5;
+    private static final int URL_MATCHED_OPEN_AUDIO_FILE = 6;
+    private static final int URL_MATCHED_OPEN_FILE = 7;
+
+    @StringDef({
+            URL_SEGMENT_DELETE_FILES,
+            URL_SEGMENT_COMPLETE_DELETE,
+            URL_SEGMENT_OPEN_BUGREPORT_FILE,
+            URL_SEGMENT_OPEN_AUDIO_FILE,
+            URL_SEGMENT_OPEN_FILE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface UriActionSegments {}
+
+    static final Uri BUGREPORT_CONTENT_URI =
+            Uri.parse("content://" + AUTHORITY + "/" + BUG_REPORTS_TABLE);
+
+    /** See {@link MetaBugReport} for column descriptions. */
+    static final String COLUMN_ID = "_ID";
+    static final String COLUMN_USERNAME = "username";
+    static final String COLUMN_TITLE = "title";
+    static final String COLUMN_TIMESTAMP = "timestamp";
+    /** not used anymore */
+    static final String COLUMN_DESCRIPTION = "description";
+    /** not used anymore, but some devices still might have bugreports with this field set. */
+    static final String COLUMN_FILEPATH = "filepath";
+    static final String COLUMN_STATUS = "status";
+    static final String COLUMN_STATUS_MESSAGE = "message";
+    static final String COLUMN_TYPE = "type";
+    static final String COLUMN_BUGREPORT_FILENAME = "bugreport_filename";
+    static final String COLUMN_AUDIO_FILENAME = "audio_filename";
+
+    private DatabaseHelper mDatabaseHelper;
+    private final UriMatcher mUriMatcher;
+    private Config mConfig;
+
+    /**
+     * A helper class to work with sqlite database.
+     */
+    private static class DatabaseHelper extends SQLiteOpenHelper {
+        private static final String TAG = DatabaseHelper.class.getSimpleName();
+
+        private static final String DATABASE_NAME = "bugreport.db";
+
+        /**
+         * All changes in database versions should be recorded here.
+         * 1: Initial version.
+         * 2: Add integer column details_needed.
+         * 3: Add string column audio_filename and bugreport_filename.
+         */
+        private static final int INITIAL_VERSION = 1;
+        private static final int TYPE_VERSION = 2;
+        private static final int AUDIO_VERSION = 3;
+        private static final int DATABASE_VERSION = AUDIO_VERSION;
+
+        private static final String CREATE_TABLE = "CREATE TABLE " + BUG_REPORTS_TABLE + " ("
+                + COLUMN_ID + " INTEGER PRIMARY KEY,"
+                + COLUMN_USERNAME + " TEXT,"
+                + COLUMN_TITLE + " TEXT,"
+                + COLUMN_TIMESTAMP + " TEXT NOT NULL,"
+                + COLUMN_DESCRIPTION + " TEXT NULL,"
+                + COLUMN_FILEPATH + " TEXT DEFAULT NULL,"
+                + COLUMN_STATUS + " INTEGER DEFAULT " + Status.STATUS_WRITE_PENDING.getValue() + ","
+                + COLUMN_STATUS_MESSAGE + " TEXT NULL,"
+                + COLUMN_TYPE + " INTEGER DEFAULT " + MetaBugReport.TYPE_INTERACTIVE + ","
+                + COLUMN_BUGREPORT_FILENAME + " TEXT DEFAULT NULL,"
+                + COLUMN_AUDIO_FILENAME + " TEXT DEFAULT NULL"
+                + ");";
+
+        DatabaseHelper(Context context) {
+            super(context, DATABASE_NAME, null, DATABASE_VERSION);
+        }
+
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            db.execSQL(CREATE_TABLE);
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            Log.w(TAG, "Upgrading from " + oldVersion + " to " + newVersion);
+            if (oldVersion < TYPE_VERSION) {
+                db.execSQL("ALTER TABLE " + BUG_REPORTS_TABLE + " ADD COLUMN "
+                        + COLUMN_TYPE + " INTEGER DEFAULT " + MetaBugReport.TYPE_INTERACTIVE);
+            }
+            if (oldVersion < AUDIO_VERSION) {
+                db.execSQL("ALTER TABLE " + BUG_REPORTS_TABLE + " ADD COLUMN "
+                        + COLUMN_BUGREPORT_FILENAME + " TEXT DEFAULT NULL");
+                db.execSQL("ALTER TABLE " + BUG_REPORTS_TABLE + " ADD COLUMN "
+                        + COLUMN_AUDIO_FILENAME + " TEXT DEFAULT NULL");
+            }
+        }
+    }
+
+    /**
+     * Builds an {@link Uri} that points to the single bug report and performs an action
+     * defined by given URI segment.
+     */
+    static Uri buildUriWithSegment(int bugReportId, @UriActionSegments String segment) {
+        return Uri.parse("content://" + AUTHORITY + "/" + BUG_REPORTS_TABLE + "/"
+                + segment + "/" + bugReportId);
+    }
+
+    public BugStorageProvider() {
+        mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+        mUriMatcher.addURI(AUTHORITY, BUG_REPORTS_TABLE, URL_MATCHED_BUG_REPORTS_URI);
+        mUriMatcher.addURI(AUTHORITY, BUG_REPORTS_TABLE + "/#", URL_MATCHED_BUG_REPORT_ID_URI);
+        mUriMatcher.addURI(
+                AUTHORITY, BUG_REPORTS_TABLE + "/" + URL_SEGMENT_DELETE_FILES + "/#",
+                URL_MATCHED_DELETE_FILES);
+        mUriMatcher.addURI(
+                AUTHORITY, BUG_REPORTS_TABLE + "/" + URL_SEGMENT_COMPLETE_DELETE + "/#",
+                URL_MATCHED_COMPLETE_DELETE);
+        mUriMatcher.addURI(
+                AUTHORITY, BUG_REPORTS_TABLE + "/" + URL_SEGMENT_OPEN_BUGREPORT_FILE + "/#",
+                URL_MATCHED_OPEN_BUGREPORT_FILE);
+        mUriMatcher.addURI(
+                AUTHORITY, BUG_REPORTS_TABLE + "/" + URL_SEGMENT_OPEN_AUDIO_FILE + "/#",
+                URL_MATCHED_OPEN_AUDIO_FILE);
+        mUriMatcher.addURI(
+                AUTHORITY, BUG_REPORTS_TABLE + "/" + URL_SEGMENT_OPEN_FILE + "/#",
+                URL_MATCHED_OPEN_FILE);
+    }
+
+    @Override
+    public boolean onCreate() {
+        if (!Config.isBugReportEnabled()) {
+            return false;
+        }
+        mDatabaseHelper = new DatabaseHelper(getContext());
+        mConfig = new Config();
+        mConfig.start();
+        return true;
+    }
+
+    @Override
+    public Cursor query(
+            @NonNull Uri uri,
+            @Nullable String[] projection,
+            @Nullable String selection,
+            @Nullable String[] selectionArgs,
+            @Nullable String sortOrder) {
+        return query(uri, projection, selection, selectionArgs, sortOrder, null);
+    }
+
+    @Nullable
+    @Override
+    public Cursor query(
+            @NonNull Uri uri,
+            @Nullable String[] projection,
+            @Nullable String selection,
+            @Nullable String[] selectionArgs,
+            @Nullable String sortOrder,
+            @Nullable CancellationSignal cancellationSignal) {
+        Preconditions.checkState(Config.isBugReportEnabled(), "BugReport is disabled.");
+        String table;
+        switch (mUriMatcher.match(uri)) {
+            // returns the list of bugreports that match the selection criteria.
+            case URL_MATCHED_BUG_REPORTS_URI:
+                table = BUG_REPORTS_TABLE;
+                break;
+            //  returns the bugreport that match the id.
+            case URL_MATCHED_BUG_REPORT_ID_URI:
+                table = BUG_REPORTS_TABLE;
+                if (selection != null || selectionArgs != null) {
+                    throw new IllegalArgumentException("selection is not allowed for "
+                            + URL_MATCHED_BUG_REPORT_ID_URI);
+                }
+                selection = COLUMN_ID + "=?";
+                selectionArgs = new String[]{ uri.getLastPathSegment() };
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown URL " + uri);
+        }
+        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
+        Cursor cursor = db.query(false, table, null, selection, selectionArgs, null, null,
+                sortOrder, null, cancellationSignal);
+        cursor.setNotificationUri(getContext().getContentResolver(), uri);
+        return cursor;
+    }
+
+    @Nullable
+    @Override
+    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
+        Preconditions.checkState(Config.isBugReportEnabled(), "BugReport is disabled.");
+        String table;
+        if (values == null) {
+            throw new IllegalArgumentException("values cannot be null");
+        }
+        switch (mUriMatcher.match(uri)) {
+            case URL_MATCHED_BUG_REPORTS_URI:
+                table = BUG_REPORTS_TABLE;
+                break;
+            default:
+                throw new IllegalArgumentException("unknown uri" + uri);
+        }
+        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
+        long rowId = db.insert(table, null, values);
+        if (rowId > 0) {
+            Uri resultUri = Uri.parse("content://" + AUTHORITY + "/" + table + "/" + rowId);
+            // notify registered content observers
+            getContext().getContentResolver().notifyChange(resultUri, null);
+            return resultUri;
+        }
+        return null;
+    }
+
+    @Nullable
+    @Override
+    public String getType(@NonNull Uri uri) {
+        switch (mUriMatcher.match(uri)) {
+            case URL_MATCHED_OPEN_BUGREPORT_FILE:
+            case URL_MATCHED_OPEN_FILE:
+                return "application/zip";
+            case URL_MATCHED_OPEN_AUDIO_FILE:
+                return "audio/3gpp";
+            default:
+                throw new IllegalArgumentException("unknown uri:" + uri);
+        }
+    }
+
+    @Override
+    public int delete(
+            @NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
+        Preconditions.checkState(Config.isBugReportEnabled(), "BugReport is disabled.");
+        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
+        switch (mUriMatcher.match(uri)) {
+            case URL_MATCHED_DELETE_FILES:
+                if (selection != null || selectionArgs != null) {
+                    throw new IllegalArgumentException("selection is not allowed for "
+                            + URL_MATCHED_DELETE_FILES);
+                }
+                if (deleteFilesFor(getBugReportFromUri(uri))) {
+                    getContext().getContentResolver().notifyChange(uri, null);
+                    return 1;
+                }
+                return 0;
+            case URL_MATCHED_COMPLETE_DELETE:
+                if (selection != null || selectionArgs != null) {
+                    throw new IllegalArgumentException("selection is not allowed for "
+                            + URL_MATCHED_COMPLETE_DELETE);
+                }
+                selection = COLUMN_ID + " = ?";
+                selectionArgs = new String[]{uri.getLastPathSegment()};
+                // Ignore the results of zip file deletion, possibly it wasn't even created.
+                deleteFilesFor(getBugReportFromUri(uri));
+                getContext().getContentResolver().notifyChange(uri, null);
+                return db.delete(BUG_REPORTS_TABLE, selection, selectionArgs);
+            default:
+                throw new IllegalArgumentException("Unknown URL " + uri);
+        }
+    }
+
+    @Override
+    public int update(
+            @NonNull Uri uri,
+            @Nullable ContentValues values,
+            @Nullable String selection,
+            @Nullable String[] selectionArgs) {
+        Preconditions.checkState(Config.isBugReportEnabled(), "BugReport is disabled.");
+        if (values == null) {
+            throw new IllegalArgumentException("values cannot be null");
+        }
+        String table;
+        switch (mUriMatcher.match(uri)) {
+            case URL_MATCHED_BUG_REPORTS_URI:
+                table = BUG_REPORTS_TABLE;
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown URL " + uri);
+        }
+        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
+        int rowCount = db.update(table, values, selection, selectionArgs);
+        if (rowCount > 0) {
+            // notify registered content observers
+            getContext().getContentResolver().notifyChange(uri, null);
+        }
+        Integer status = values.getAsInteger(COLUMN_STATUS);
+        // When the status is set to STATUS_UPLOAD_PENDING, we schedule an UploadJob under the
+        // current user, which is the primary user.
+        if (status != null && status.equals(Status.STATUS_UPLOAD_PENDING.getValue())) {
+            JobSchedulingUtils.scheduleUploadJob(BugStorageProvider.this.getContext());
+        }
+        return rowCount;
+    }
+
+    /**
+     * This is called when a file is opened.
+     *
+     * <p>See {@link BugStorageUtils#openBugReportFileToWrite},
+     * {@link BugStorageUtils#openAudioMessageFileToWrite}.
+     */
+    @Nullable
+    @Override
+    public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode)
+            throws FileNotFoundException {
+        Preconditions.checkState(Config.isBugReportEnabled(), "BugReport is disabled.");
+        Function<MetaBugReport, String> fileNameExtractor;
+        switch (mUriMatcher.match(uri)) {
+            case URL_MATCHED_OPEN_BUGREPORT_FILE:
+                fileNameExtractor = MetaBugReport::getBugReportFileName;
+                break;
+            case URL_MATCHED_OPEN_AUDIO_FILE:
+                fileNameExtractor = MetaBugReport::getAudioFileName;
+                break;
+            case URL_MATCHED_OPEN_FILE:
+                File file = new File(getBugReportFromUri(uri).getFilePath());
+                Log.v(TAG, "Opening file " + file + " with mode " + mode);
+                return ParcelFileDescriptor.open(file, ParcelFileDescriptor.parseMode(mode));
+            default:
+                throw new IllegalArgumentException("unknown uri:" + uri);
+        }
+        // URI contains bugreport ID as the last segment, see the matched urls.
+        MetaBugReport bugReport = getBugReportFromUri(uri);
+        File file = new File(
+                FileUtils.getPendingDir(getContext()), fileNameExtractor.apply(bugReport));
+        Log.v(TAG, "Opening file " + file + " with mode " + mode);
+        int modeBits = ParcelFileDescriptor.parseMode(mode);
+        return ParcelFileDescriptor.open(file, modeBits);
+    }
+
+    private MetaBugReport getBugReportFromUri(@NonNull Uri uri) {
+        int bugreportId = Integer.parseInt(uri.getLastPathSegment());
+        return BugStorageUtils.findBugReport(getContext(), bugreportId)
+                .orElseThrow(() -> new IllegalArgumentException("No record found for " + uri));
+    }
+
+    /**
+     * Print the Provider's state into the given stream. This gets invoked if
+     * you run "dumpsys activity provider com.android.car.bugreport/.BugStorageProvider".
+     *
+     * @param fd The raw file descriptor that the dump is being sent to.
+     * @param writer The PrintWriter to which you should dump your state.  This will be
+     * closed for you after you return.
+     * @param args additional arguments to the dump request.
+     */
+    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        writer.println("BugStorageProvider:");
+        mConfig.dump(/* prefix= */ "  ", writer);
+    }
+
+    private boolean deleteFilesFor(MetaBugReport bugReport) {
+        if (!Strings.isNullOrEmpty(bugReport.getFilePath())) {
+            // Old bugreports have only filePath.
+            return new File(bugReport.getFilePath()).delete();
+        }
+        File pendingDir = FileUtils.getPendingDir(getContext());
+        boolean result = true;
+        if (!Strings.isNullOrEmpty(bugReport.getAudioFileName())) {
+            result = new File(pendingDir, bugReport.getAudioFileName()).delete();
+        }
+        if (!Strings.isNullOrEmpty(bugReport.getBugReportFileName())) {
+            result = result && new File(pendingDir, bugReport.getBugReportFileName()).delete();
+        }
+        return result;
+    }
+}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/BugStorageUtils.java b/tests/BugReportApp/src/com/android/car/bugreport/BugStorageUtils.java
new file mode 100644
index 0000000..cd0a12e
--- /dev/null
+++ b/tests/BugReportApp/src/com/android/car/bugreport/BugStorageUtils.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.bugreport;
+
+import static com.android.car.bugreport.BugStorageProvider.COLUMN_AUDIO_FILENAME;
+import static com.android.car.bugreport.BugStorageProvider.COLUMN_BUGREPORT_FILENAME;
+import static com.android.car.bugreport.BugStorageProvider.COLUMN_FILEPATH;
+import static com.android.car.bugreport.BugStorageProvider.COLUMN_ID;
+import static com.android.car.bugreport.BugStorageProvider.COLUMN_STATUS;
+import static com.android.car.bugreport.BugStorageProvider.COLUMN_STATUS_MESSAGE;
+import static com.android.car.bugreport.BugStorageProvider.COLUMN_TIMESTAMP;
+import static com.android.car.bugreport.BugStorageProvider.COLUMN_TITLE;
+import static com.android.car.bugreport.BugStorageProvider.COLUMN_TYPE;
+import static com.android.car.bugreport.BugStorageProvider.COLUMN_USERNAME;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.util.Log;
+
+import com.google.api.client.auth.oauth2.TokenResponseException;
+import com.google.common.base.Strings;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * A class that hides details when communicating with the bug storage provider.
+ */
+final class BugStorageUtils {
+    private static final String TAG = BugStorageUtils.class.getSimpleName();
+
+    /**
+     * When time/time-zone set incorrectly, Google API returns "400: invalid_grant" error with
+     * description containing this text.
+     */
+    private static final String CLOCK_SKEW_ERROR = "clock with skew to account";
+
+    /** When time/time-zone set incorrectly, Google API returns this error. */
+    private static final String INVALID_GRANT = "invalid_grant";
+
+    private static final DateFormat TIMESTAMP_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
+
+    /**
+     * Creates a new {@link Status#STATUS_WRITE_PENDING} bug report record in a local sqlite
+     * database.
+     *
+     * @param context   - an application context.
+     * @param title     - title of the bug report.
+     * @param timestamp - timestamp when the bug report was initiated.
+     * @param username  - current user name. Note, it's a user name, not an account name.
+     * @param type      - bug report type, {@link MetaBugReport.BugReportType}.
+     * @return an instance of {@link MetaBugReport} that was created in a database.
+     */
+    @NonNull
+    static MetaBugReport createBugReport(
+            @NonNull Context context,
+            @NonNull String title,
+            @NonNull String timestamp,
+            @NonNull String username,
+            @MetaBugReport.BugReportType int type) {
+        // insert bug report username and title
+        ContentValues values = new ContentValues();
+        values.put(COLUMN_TITLE, title);
+        values.put(COLUMN_TIMESTAMP, timestamp);
+        values.put(COLUMN_USERNAME, username);
+        values.put(COLUMN_TYPE, type);
+
+        ContentResolver r = context.getContentResolver();
+        Uri uri = r.insert(BugStorageProvider.BUGREPORT_CONTENT_URI, values);
+        return findBugReport(context, Integer.parseInt(uri.getLastPathSegment())).get();
+    }
+
+    /** Returns an output stream to write the zipped file to. */
+    @NonNull
+    static OutputStream openBugReportFileToWrite(
+            @NonNull Context context, @NonNull MetaBugReport metaBugReport)
+            throws FileNotFoundException {
+        ContentResolver r = context.getContentResolver();
+        return r.openOutputStream(BugStorageProvider.buildUriWithSegment(
+                metaBugReport.getId(), BugStorageProvider.URL_SEGMENT_OPEN_BUGREPORT_FILE));
+    }
+
+    /** Returns an output stream to write the audio message file to. */
+    static OutputStream openAudioMessageFileToWrite(
+            @NonNull Context context, @NonNull MetaBugReport metaBugReport)
+            throws FileNotFoundException {
+        ContentResolver r = context.getContentResolver();
+        return r.openOutputStream(BugStorageProvider.buildUriWithSegment(
+                metaBugReport.getId(), BugStorageProvider.URL_SEGMENT_OPEN_AUDIO_FILE));
+    }
+
+    /**
+     * Returns an input stream to read the final zip file from.
+     *
+     * <p>NOTE: This is the old way of storing final zipped bugreport. See
+     * {@link BugStorageProvider#URL_SEGMENT_OPEN_FILE} for more info.
+     */
+    static InputStream openFileToRead(Context context, MetaBugReport bug)
+            throws FileNotFoundException {
+        return context.getContentResolver().openInputStream(
+                BugStorageProvider.buildUriWithSegment(
+                        bug.getId(), BugStorageProvider.URL_SEGMENT_OPEN_FILE));
+    }
+
+    /** Returns an input stream to read the bug report zip file from. */
+    static InputStream openBugReportFileToRead(Context context, MetaBugReport bug)
+            throws FileNotFoundException {
+        return context.getContentResolver().openInputStream(
+                BugStorageProvider.buildUriWithSegment(
+                        bug.getId(), BugStorageProvider.URL_SEGMENT_OPEN_BUGREPORT_FILE));
+    }
+
+    /** Returns an input stream to read the audio file from. */
+    static InputStream openAudioFileToRead(Context context, MetaBugReport bug)
+            throws FileNotFoundException {
+        return context.getContentResolver().openInputStream(
+                BugStorageProvider.buildUriWithSegment(
+                        bug.getId(), BugStorageProvider.URL_SEGMENT_OPEN_AUDIO_FILE));
+    }
+
+    /**
+     * Deletes {@link MetaBugReport} record from a local database and deletes the associated file.
+     *
+     * <p>WARNING: destructive operation.
+     *
+     * @param context     - an application context.
+     * @param bugReportId - a bug report id.
+     * @return true if the record was deleted.
+     */
+    static boolean completeDeleteBugReport(@NonNull Context context, int bugReportId) {
+        ContentResolver r = context.getContentResolver();
+        return r.delete(BugStorageProvider.buildUriWithSegment(
+                bugReportId, BugStorageProvider.URL_SEGMENT_COMPLETE_DELETE), null, null) == 1;
+    }
+
+    /** Deletes all files for given bugreport id; doesn't delete sqlite3 record. */
+    static boolean deleteBugReportFiles(@NonNull Context context, int bugReportId) {
+        ContentResolver r = context.getContentResolver();
+        return r.delete(BugStorageProvider.buildUriWithSegment(
+                bugReportId, BugStorageProvider.URL_SEGMENT_DELETE_FILES), null, null) == 1;
+    }
+
+    /**
+     * Returns all the bugreports that are waiting to be uploaded.
+     */
+    @NonNull
+    public static List<MetaBugReport> getUploadPendingBugReports(@NonNull Context context) {
+        String selection = COLUMN_STATUS + "=?";
+        String[] selectionArgs = new String[]{
+                Integer.toString(Status.STATUS_UPLOAD_PENDING.getValue())};
+        return getBugreports(context, selection, selectionArgs, null);
+    }
+
+    /**
+     * Returns all bugreports in descending order by the ID field. ID is the index in the
+     * database.
+     */
+    @NonNull
+    public static List<MetaBugReport> getAllBugReportsDescending(@NonNull Context context) {
+        return getBugreports(context, null, null, COLUMN_ID + " DESC");
+    }
+
+    /** Returns {@link MetaBugReport} for given bugreport id. */
+    static Optional<MetaBugReport> findBugReport(Context context, int bugreportId) {
+        String selection = COLUMN_ID + " = ?";
+        String[] selectionArgs = new String[]{Integer.toString(bugreportId)};
+        List<MetaBugReport> bugs = BugStorageUtils.getBugreports(
+                context, selection, selectionArgs, null);
+        if (bugs.isEmpty()) {
+            return Optional.empty();
+        }
+        return Optional.of(bugs.get(0));
+    }
+
+    private static List<MetaBugReport> getBugreports(
+            Context context, String selection, String[] selectionArgs, String order) {
+        ArrayList<MetaBugReport> bugReports = new ArrayList<>();
+        String[] projection = {
+                COLUMN_ID,
+                COLUMN_USERNAME,
+                COLUMN_TITLE,
+                COLUMN_TIMESTAMP,
+                COLUMN_BUGREPORT_FILENAME,
+                COLUMN_AUDIO_FILENAME,
+                COLUMN_FILEPATH,
+                COLUMN_STATUS,
+                COLUMN_STATUS_MESSAGE,
+                COLUMN_TYPE};
+        ContentResolver r = context.getContentResolver();
+        Cursor c = r.query(BugStorageProvider.BUGREPORT_CONTENT_URI, projection,
+                selection, selectionArgs, order);
+
+        int count = (c != null) ? c.getCount() : 0;
+
+        if (count > 0) c.moveToFirst();
+        for (int i = 0; i < count; i++) {
+            MetaBugReport meta = MetaBugReport.builder()
+                    .setId(getInt(c, COLUMN_ID))
+                    .setTimestamp(getString(c, COLUMN_TIMESTAMP))
+                    .setUserName(getString(c, COLUMN_USERNAME))
+                    .setTitle(getString(c, COLUMN_TITLE))
+                    .setBugReportFileName(getString(c, COLUMN_BUGREPORT_FILENAME))
+                    .setAudioFileName(getString(c, COLUMN_AUDIO_FILENAME))
+                    .setFilePath(getString(c, COLUMN_FILEPATH))
+                    .setStatus(getInt(c, COLUMN_STATUS))
+                    .setStatusMessage(getString(c, COLUMN_STATUS_MESSAGE))
+                    .setType(getInt(c, COLUMN_TYPE))
+                    .build();
+            bugReports.add(meta);
+            c.moveToNext();
+        }
+        if (c != null) c.close();
+        return bugReports;
+    }
+
+    /**
+     * returns 0 if the column is not found. Otherwise returns the column value.
+     */
+    private static int getInt(Cursor c, String colName) {
+        int colIndex = c.getColumnIndex(colName);
+        if (colIndex == -1) {
+            Log.w(TAG, "Column " + colName + " not found.");
+            return 0;
+        }
+        return c.getInt(colIndex);
+    }
+
+    /**
+     * Returns the column value. If the column is not found returns empty string.
+     */
+    private static String getString(Cursor c, String colName) {
+        int colIndex = c.getColumnIndex(colName);
+        if (colIndex == -1) {
+            Log.w(TAG, "Column " + colName + " not found.");
+            return "";
+        }
+        return Strings.nullToEmpty(c.getString(colIndex));
+    }
+
+    /**
+     * Sets bugreport status to uploaded successfully.
+     */
+    public static void setUploadSuccess(Context context, MetaBugReport bugReport) {
+        setBugReportStatus(context, bugReport, Status.STATUS_UPLOAD_SUCCESS,
+                "Upload time: " + currentTimestamp());
+    }
+
+    /**
+     * Sets bugreport status pending, and update the message to last exception message.
+     *
+     * <p>Used when a transient error has occurred.
+     */
+    public static void setUploadRetry(Context context, MetaBugReport bugReport, Exception e) {
+        setBugReportStatus(context, bugReport, Status.STATUS_UPLOAD_PENDING,
+                getRootCauseMessage(e));
+    }
+
+    /**
+     * Sets bugreport status pending and update the message to last message.
+     *
+     * <p>Used when a transient error has occurred.
+     */
+    public static void setUploadRetry(Context context, MetaBugReport bugReport, String msg) {
+        setBugReportStatus(context, bugReport, Status.STATUS_UPLOAD_PENDING, msg);
+    }
+
+    /**
+     * Sets {@link MetaBugReport} status {@link Status#STATUS_EXPIRED}.
+     * Deletes the associated zip file from disk.
+     *
+     * @return true if succeeded.
+     */
+    static boolean expireBugReport(@NonNull Context context,
+            @NonNull MetaBugReport metaBugReport, @NonNull Instant expiredAt) {
+        metaBugReport = setBugReportStatus(
+                context, metaBugReport, Status.STATUS_EXPIRED, "Expired on " + expiredAt);
+        if (metaBugReport.getStatus() != Status.STATUS_EXPIRED.getValue()) {
+            return false;
+        }
+        return deleteBugReportFiles(context, metaBugReport.getId());
+    }
+
+    /** Gets the root cause of the error. */
+    @NonNull
+    private static String getRootCauseMessage(@Nullable Throwable t) {
+        if (t == null) {
+            return "No error";
+        } else if (t instanceof TokenResponseException) {
+            TokenResponseException ex = (TokenResponseException) t;
+            if (ex.getDetails().getError().equals(INVALID_GRANT)
+                    && ex.getDetails().getErrorDescription().contains(CLOCK_SKEW_ERROR)) {
+                return "Auth error. Check if time & time-zone is correct.";
+            }
+        }
+        while (t.getCause() != null) t = t.getCause();
+        return t.getMessage();
+    }
+
+    /**
+     * Updates bug report record status.
+     *
+     * <p>NOTE: When status is set to STATUS_UPLOAD_PENDING, BugStorageProvider automatically
+     * schedules the bugreport to be uploaded.
+     *
+     * @return Updated {@link MetaBugReport}.
+     */
+    static MetaBugReport setBugReportStatus(
+            Context context, MetaBugReport bugReport, Status status, String message) {
+        return update(context, bugReport.toBuilder()
+                .setStatus(status.getValue())
+                .setStatusMessage(message)
+                .build());
+    }
+
+    /**
+     * Updates bug report record status.
+     *
+     * <p>NOTE: When status is set to STATUS_UPLOAD_PENDING, BugStorageProvider automatically
+     * schedules the bugreport to be uploaded.
+     *
+     * @return Updated {@link MetaBugReport}.
+     */
+    static MetaBugReport setBugReportStatus(
+            Context context, MetaBugReport bugReport, Status status, Exception e) {
+        return setBugReportStatus(context, bugReport, status, getRootCauseMessage(e));
+    }
+
+    /**
+     * Updates the bugreport and returns the updated version.
+     *
+     * <p>NOTE: doesn't update all the fields.
+     */
+    static MetaBugReport update(Context context, MetaBugReport bugReport) {
+        // Update only necessary fields.
+        ContentValues values = new ContentValues();
+        values.put(COLUMN_BUGREPORT_FILENAME, bugReport.getBugReportFileName());
+        values.put(COLUMN_AUDIO_FILENAME, bugReport.getAudioFileName());
+        values.put(COLUMN_STATUS, bugReport.getStatus());
+        values.put(COLUMN_STATUS_MESSAGE, bugReport.getStatusMessage());
+        String where = COLUMN_ID + "=" + bugReport.getId();
+        context.getContentResolver().update(
+                BugStorageProvider.BUGREPORT_CONTENT_URI, values, where, null);
+        return findBugReport(context, bugReport.getId()).orElseThrow(
+                () -> new IllegalArgumentException("Bug " + bugReport.getId() + " not found"));
+    }
+
+    private static String currentTimestamp() {
+        return TIMESTAMP_FORMAT.format(new Date());
+    }
+}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/Config.java b/tests/BugReportApp/src/com/android/car/bugreport/Config.java
new file mode 100644
index 0000000..b37ac9e
--- /dev/null
+++ b/tests/BugReportApp/src/com/android/car/bugreport/Config.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.bugreport;
+
+import android.app.ActivityThread;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.provider.DeviceConfig;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import com.google.common.collect.ImmutableSet;
+
+import java.io.PrintWriter;
+
+/**
+ * Contains config for BugReport App.
+ *
+ * <p>The config is kept synchronized with {@code car} namespace. It's not defined in
+ * {@link DeviceConfig}.
+ *
+ * <ul>To get/set the flags via adb:
+ *   <li>{@code adb shell device_config get car bugreport_upload_destination}
+ *   <li>{@code adb shell device_config put car bugreport_upload_destination gcs}
+ *   <li>{@code adb shell device_config delete car bugreport_upload_destination}
+ * </ul>
+ */
+final class Config {
+    private static final String TAG = Config.class.getSimpleName();
+
+    /**
+     * Namespace for all Android Automotive related features.
+     *
+     * <p>In the future it will move to {@code DeviceConfig#NAMESPACE_CAR}.
+     */
+    private static final String NAMESPACE_CAR = "car";
+
+    /**
+     * A string flag, can be one of {@code null} or {@link #UPLOAD_DESTINATION_GCS}.
+     */
+    private static final String KEY_BUGREPORT_UPLOAD_DESTINATION = "bugreport_upload_destination";
+
+    /**
+     * A value for {@link #KEY_BUGREPORT_UPLOAD_DESTINATION}.
+     *
+     * Upload bugreports to GCS. Only works in {@code userdebug} or {@code eng} builds.
+     */
+    private static final String UPLOAD_DESTINATION_GCS = "gcs";
+
+    /**
+     * A system property to force enable the app bypassing the {@code userdebug/eng} build check.
+     */
+    private static final String PROP_FORCE_ENABLE = "android.car.bugreport.force_enable";
+
+    /*
+     * Enable uploading new bugreports to GCS for these devices. If the device is not in this list,
+     * {@link #KEY_UPLOAD_DESTINATION} flag will be used instead.
+     */
+    private static final ImmutableSet<String> ENABLE_FORCE_UPLOAD_TO_GCS_FOR_DEVICES =
+            ImmutableSet.of("hawk");
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private String mUploadDestination = null;
+
+    void start() {
+        DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_CAR,
+                ActivityThread.currentApplication().getMainExecutor(), this::onPropertiesChanged);
+        updateConstants();
+    }
+
+    private void onPropertiesChanged(DeviceConfig.Properties properties) {
+        if (properties.getKeyset().contains(KEY_BUGREPORT_UPLOAD_DESTINATION)) {
+            updateConstants();
+        }
+    }
+
+    /** Returns true if bugreport app is enabled for this device. */
+    static boolean isBugReportEnabled() {
+        return Build.IS_DEBUGGABLE || SystemProperties.getBoolean(PROP_FORCE_ENABLE, false);
+    }
+
+    /** If new bugreports should be scheduled for uploading. */
+    boolean getAutoUpload() {
+        // TODO(b/144851443): Enable auto-upload only if upload destination is Gcs until
+        //                    we create a way to allow implementing OEMs custom upload logic.
+        return isUploadDestinationGcs();
+    }
+
+    /**
+     * Returns {@link true} if bugreport upload destination is GCS.
+     */
+    private boolean isUploadDestinationGcs() {
+        if (isTempForceAutoUploadGcsEnabled()) {
+            Log.d(TAG, "Setting upload dest to GCS ENABLE_AUTO_UPLOAD is true");
+            return true;
+        }
+        // NOTE: enable it only for userdebug/eng builds.
+        return UPLOAD_DESTINATION_GCS.equals(getUploadDestination()) && Build.IS_DEBUGGABLE;
+    }
+
+    private static boolean isTempForceAutoUploadGcsEnabled() {
+        return ENABLE_FORCE_UPLOAD_TO_GCS_FOR_DEVICES.contains(Build.DEVICE);
+    }
+
+    /**
+     * Returns value of a flag {@link #KEY_BUGREPORT_UPLOAD_DESTINATION}.
+     */
+    private String getUploadDestination() {
+        synchronized (mLock) {
+            return mUploadDestination;
+        }
+    }
+
+    private void updateConstants() {
+        synchronized (mLock) {
+            mUploadDestination = DeviceConfig.getString(NAMESPACE_CAR,
+                    KEY_BUGREPORT_UPLOAD_DESTINATION, /* defaultValue= */ null);
+        }
+    }
+
+    void dump(String prefix, PrintWriter pw) {
+        pw.println(prefix + "car.bugreport.Config:");
+
+        pw.print(prefix + "  ");
+        pw.print("getAutoUpload");
+        pw.print("=");
+        pw.println(getAutoUpload() ? "true" : "false");
+
+        pw.print(prefix + "  ");
+        pw.print("getUploadDestination");
+        pw.print("=");
+        pw.println(getUploadDestination());
+
+        pw.print(prefix + "  ");
+        pw.print("isUploadDestinationGcs");
+        pw.print("=");
+        pw.println(isUploadDestinationGcs());
+    }
+}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/FileUtils.java b/tests/BugReportApp/src/com/android/car/bugreport/FileUtils.java
new file mode 100644
index 0000000..bf12aa7
--- /dev/null
+++ b/tests/BugReportApp/src/com/android/car/bugreport/FileUtils.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.bugreport;
+
+import android.content.Context;
+
+import com.google.common.base.Preconditions;
+
+import java.io.File;
+
+/**
+ * File utilities.
+ *
+ * Thread safety and file operations: All file operations should happen on the same worker
+ * thread for thread safety. This is provided by running both bugreport service and file upload
+ * service on a asynctask. Asynctasks are by default executed on the same worker thread in serial.
+ *
+ * There is one exception to the rule above:
+ * Voice recorder works on main thread, however this is not a thread safety problem because:
+ * i. voice recorder always works before starting to collect rest of the bugreport
+ * ii. a bug report cannot be moved to upload (pending) directory before it is completely
+ * collected.
+ */
+public class FileUtils {
+    private static final String PREFIX = "bugreport-";
+    /** A directory under the system user; contains bugreport zip files and audio files. */
+    private static final String PENDING_DIR = "bug_reports_pending";
+    // Temporary directory under the current user, used for zipping files.
+    private static final String TEMP_DIR = "bug_reports_temp";
+
+    private static final String FS = "@";
+
+    static File getPendingDir(Context context) {
+        Preconditions.checkArgument(context.getUser().isSystem(),
+                "Must be called from the system user.");
+        File dir = new File(context.getDataDir(), PENDING_DIR);
+        dir.mkdirs();
+        return dir;
+    }
+
+    /**
+     * Creates and returns file directory for storing bug report files before they are zipped into
+     * a single file.
+     */
+    static File createTempDir(Context context, String timestamp) {
+        File dir = getTempDir(context, timestamp);
+        dir.mkdirs();
+        return dir;
+    }
+
+    /**
+     * Returns path to the directory for storing bug report files before they are zipped into a
+     * single file.
+     */
+    static File getTempDir(Context context, String timestamp) {
+        Preconditions.checkArgument(!context.getUser().isSystem(),
+                "Must be called from the current user.");
+        return new File(context.getDataDir(), TEMP_DIR + "/" + timestamp);
+    }
+
+    /**
+     * Constructs a bugreport zip file name.
+     *
+     * <p>Add lookup code to the filename to allow matching audio file and bugreport file in USB.
+     */
+    static String getZipFileName(MetaBugReport bug) {
+        String lookupCode = extractLookupCode(bug);
+        return PREFIX + bug.getUserName() + FS + bug.getTimestamp() + "-" + lookupCode + ".zip";
+    }
+
+    /**
+     * Constructs a audio message file name.
+     *
+     * <p>Add lookup code to the filename to allow matching audio file and bugreport file in USB.
+     *
+     * @param timestamp - current timestamp, when audio was created.
+     * @param bug       - a bug report.
+     */
+    static String getAudioFileName(String timestamp, MetaBugReport bug) {
+        String lookupCode = extractLookupCode(bug);
+        return PREFIX + bug.getUserName() + FS + timestamp + "-" + lookupCode + "-message.3gp";
+    }
+
+    private static String extractLookupCode(MetaBugReport bug) {
+        Preconditions.checkArgument(bug.getTitle().startsWith("["),
+                "Invalid bugreport title, doesn't contain lookup code. ");
+        return bug.getTitle().substring(1, BugReportActivity.LOOKUP_STRING_LENGTH + 1);
+    }
+
+    /**
+     * Returns a {@link File} object pointing to a path in a temp directory under current users
+     * {@link Context#getDataDir}.
+     *
+     * @param context       - an application context.
+     * @param timestamp     - generates file for this timestamp
+     * @param suffix        - a filename suffix.
+     * @return A file.
+     */
+    static File getFileWithSuffix(Context context, String timestamp, String suffix) {
+        return new File(createTempDir(context, timestamp), timestamp + suffix);
+    }
+
+    /**
+     * Returns a {@link File} object pointing to a path in a temp directory under current users
+     * {@link Context#getDataDir}.
+     *
+     * @param context     - an application context.
+     * @param timestamp   - generates file for this timestamp.
+     * @param name        - a filename
+     * @return A file.
+     */
+    static File getFile(Context context, String timestamp, String name) {
+        return new File(getTempDir(context, timestamp), name);
+    }
+
+    /**
+     * Deletes a directory and its contents recursively
+     *
+     * @param directory to delete
+     */
+    static void deleteDirectory(File directory) {
+        File[] files = directory.listFiles();
+        if (files != null) {
+            for (File file : files) {
+                if (!file.isDirectory()) {
+                    file.delete();
+                } else {
+                    deleteDirectory(file);
+                }
+            }
+        }
+        directory.delete();
+    }
+}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/JobSchedulingUtils.java b/tests/BugReportApp/src/com/android/car/bugreport/JobSchedulingUtils.java
new file mode 100644
index 0000000..ec09b1f
--- /dev/null
+++ b/tests/BugReportApp/src/com/android/car/bugreport/JobSchedulingUtils.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.bugreport;
+
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.content.ComponentName;
+import android.content.Context;
+import android.util.Log;
+
+/**
+ * Utilities for scheduling upload jobs.
+ */
+class JobSchedulingUtils {
+    private static final String TAG = JobSchedulingUtils.class.getSimpleName();
+
+    private static final int UPLOAD_JOB_ID = 1;
+    private static final int RETRY_DELAY_IN_MS = 5_000;
+
+    /**
+     * Schedules {@link UploadJob} under the current user.
+     *
+     * <p>Make sure this method is called under the primary user.
+     *
+     * <ul>
+     *   <li>require network connectivity
+     *   <li>good quality network (large upload size)
+     *   <li>persist across reboots
+     * </ul>
+     */
+    static void scheduleUploadJob(Context context) {
+        JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
+        if (jobScheduler == null) {
+            Log.w(TAG, "Cannot get JobScheduler from context.");
+            return;
+        }
+
+        JobInfo pendingJob = jobScheduler.getPendingJob(UPLOAD_JOB_ID);
+        // if there is already a pending job, do not schedule a new one.
+        if (pendingJob != null) {
+            Log.d(TAG, "Upload job is already active, not re-scheduling");
+            return;
+        }
+
+        // NOTE: Don't set estimated network bytes, because we want bug reports to be uploaded
+        //       without any constraints.
+        jobScheduler.schedule(new JobInfo.Builder(UPLOAD_JOB_ID,
+                new ComponentName(context, UploadJob.class))
+                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+                .setBackoffCriteria(RETRY_DELAY_IN_MS, JobInfo.BACKOFF_POLICY_LINEAR)
+                .build());
+    }
+}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/MetaBugReport.java b/tests/BugReportApp/src/com/android/car/bugreport/MetaBugReport.java
new file mode 100644
index 0000000..e458e22
--- /dev/null
+++ b/tests/BugReportApp/src/com/android/car/bugreport/MetaBugReport.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.bugreport;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.google.auto.value.AutoValue;
+
+import java.lang.annotation.Retention;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/** Represents the information that a bugreport can contain. */
+@AutoValue
+abstract class MetaBugReport implements Parcelable {
+
+    private static final DateFormat BUG_REPORT_TIMESTAMP_DATE_FORMAT =
+            new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
+
+    /** The app records audio message when initiated. Can change audio state. */
+    static final int TYPE_INTERACTIVE = 0;
+
+    /**
+     * The app doesn't show dialog and doesn't record audio when initiated. It allows user to
+     * add audio message when bugreport is collected.
+     */
+    static final int TYPE_SILENT = 1;
+
+    /** Annotation for bug report types. */
+    @Retention(SOURCE)
+    @IntDef({TYPE_INTERACTIVE, TYPE_SILENT})
+    @interface BugReportType {};
+
+    /**
+     * @return Id of the bug report. Bug report id monotonically increases and is unique.
+     */
+    public abstract int getId();
+
+    /**
+     * @return Username (LDAP) that created this bugreport
+     */
+    public abstract String getUserName();
+
+    /**
+     * @return Title of the bug.
+     */
+    public abstract String getTitle();
+
+    /**
+     * @return Timestamp when the bug report is initialized.
+     */
+    public abstract String getTimestamp();
+
+    /**
+     * @return path to the zip file stored under the system user.
+     *
+     * <p>NOTE: This is the old way of storing final zipped bugreport. See
+     * {@link BugStorageProvider#URL_SEGMENT_OPEN_FILE} for more info.
+     */
+    public abstract String getFilePath();
+
+    /**
+     * @return filename of the bug report zip file stored under the system user.
+     */
+    public abstract String getBugReportFileName();
+
+    /**
+     * @return filename of the audio message file stored under the system user.
+     */
+    public abstract String getAudioFileName();
+
+    /**
+     * @return {@link Status} of the bug upload.
+     */
+    public abstract int getStatus();
+
+    /**
+     * @return StatusMessage of the bug upload.
+     */
+    public abstract String getStatusMessage();
+
+    /**
+     * @return {@link BugReportType}.
+     */
+    public abstract int getType();
+
+    /** @return {@link Builder} from the meta bug report. */
+    public abstract Builder toBuilder();
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(getId());
+        dest.writeString(getTimestamp());
+        dest.writeString(getTitle());
+        dest.writeString(getUserName());
+        dest.writeString(getFilePath());
+        dest.writeString(getBugReportFileName());
+        dest.writeString(getAudioFileName());
+        dest.writeInt(getStatus());
+        dest.writeString(getStatusMessage());
+        dest.writeInt(getType());
+    }
+
+    /** Converts {@link Date} to bugreport timestamp. */
+    static String toBugReportTimestamp(Date date) {
+        return BUG_REPORT_TIMESTAMP_DATE_FORMAT.format(date);
+    }
+
+    /** Creates a {@link Builder} with default, non-null values. */
+    static Builder builder() {
+        return new AutoValue_MetaBugReport.Builder()
+                .setTimestamp("")
+                .setFilePath("")
+                .setBugReportFileName("")
+                .setAudioFileName("")
+                .setStatusMessage("")
+                .setTitle("")
+                .setUserName("");
+    }
+
+    /** A creator that's used by Parcelable. */
+    public static final Parcelable.Creator<MetaBugReport> CREATOR =
+            new Parcelable.Creator<MetaBugReport>() {
+                public MetaBugReport createFromParcel(Parcel in) {
+                    int id = in.readInt();
+                    String timestamp = in.readString();
+                    String title = in.readString();
+                    String username = in.readString();
+                    String filePath = in.readString();
+                    String bugReportFileName = in.readString();
+                    String audioFileName = in.readString();
+                    int status = in.readInt();
+                    String statusMessage = in.readString();
+                    int type = in.readInt();
+                    return MetaBugReport.builder()
+                            .setId(id)
+                            .setTimestamp(timestamp)
+                            .setTitle(title)
+                            .setUserName(username)
+                            .setFilePath(filePath)
+                            .setBugReportFileName(bugReportFileName)
+                            .setAudioFileName(audioFileName)
+                            .setStatus(status)
+                            .setStatusMessage(statusMessage)
+                            .setType(type)
+                            .build();
+                }
+
+                public MetaBugReport[] newArray(int size) {
+                    return new MetaBugReport[size];
+                }
+            };
+
+    /** Builder for MetaBugReport. */
+    @AutoValue.Builder
+    abstract static class Builder {
+        /** Sets id. */
+        public abstract Builder setId(int id);
+
+        /** Sets timestamp. */
+        public abstract Builder setTimestamp(String timestamp);
+
+        /** Sets title. */
+        public abstract Builder setTitle(String title);
+
+        /** Sets username. */
+        public abstract Builder setUserName(String username);
+
+        /** Sets filepath. */
+        public abstract Builder setFilePath(String filePath);
+
+        /** Sets bugReportFileName. */
+        public abstract Builder setBugReportFileName(String bugReportFileName);
+
+        /** Sets audioFileName. */
+        public abstract Builder setAudioFileName(String audioFileName);
+
+        /** Sets {@link Status}. */
+        public abstract Builder setStatus(int status);
+
+        /** Sets statusmessage. */
+        public abstract Builder setStatusMessage(String statusMessage);
+
+        /** Sets the {@link BugReportType}. */
+        public abstract Builder setType(@BugReportType int type);
+
+        public abstract MetaBugReport build();
+    }
+}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/PackageUtils.java b/tests/BugReportApp/src/com/android/car/bugreport/PackageUtils.java
new file mode 100644
index 0000000..cc8b27b
--- /dev/null
+++ b/tests/BugReportApp/src/com/android/car/bugreport/PackageUtils.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.bugreport;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.util.Log;
+
+/**
+ * Package related utility methods.
+ */
+final class PackageUtils {
+    private static final String TAG = PackageUtils.class.getSimpleName();
+
+    /** Returns a BugReport app version name from {@code AndroidManifest.xml}. */
+    static String getPackageVersion(Context context) {
+        try {
+            PackageInfo packageInfo = context.getPackageManager().getPackageInfo(
+                    context.getPackageName(), 0);
+            return packageInfo.versionName;
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.e(TAG, "Can't get package version.", e);
+            return "unknown";
+        }
+    }
+
+    private PackageUtils() {
+    }
+}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/SimpleUploaderAsyncTask.java b/tests/BugReportApp/src/com/android/car/bugreport/SimpleUploaderAsyncTask.java
new file mode 100644
index 0000000..b5d86ec
--- /dev/null
+++ b/tests/BugReportApp/src/com/android/car/bugreport/SimpleUploaderAsyncTask.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.bugreport;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.AsyncTask;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.google.api.client.extensions.android.http.AndroidHttp;
+import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
+import com.google.api.client.http.HttpTransport;
+import com.google.api.client.http.InputStreamContent;
+import com.google.api.client.json.JsonFactory;
+import com.google.api.client.json.jackson2.JacksonFactory;
+import com.google.api.services.storage.Storage;
+import com.google.api.services.storage.model.StorageObject;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableMap;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * Uploads a bugreport files to GCS using a simple (no-multipart / no-resume) upload policy.
+ *
+ * <p>It merges bugreport zip file and audio file into one final zip file and uploads it.
+ *
+ * <p>Please see {@code res/values/configs.xml} and {@code res/raw/gcs_credentials.json} for the
+ * configuration.
+ */
+class SimpleUploaderAsyncTask extends AsyncTask<Void, Void, Boolean> {
+    private static final String TAG = SimpleUploaderAsyncTask.class.getSimpleName();
+
+    private static final String ACCESS_SCOPE =
+            "https://www.googleapis.com/auth/devstorage.read_write";
+
+    private static final String STORAGE_METADATA_TITLE = "title";
+
+    private final Context mContext;
+    private final Result mResult;
+
+    /**
+     * The uploader uploads only one bugreport each time it is called. This interface is
+     * used to reschedule upload job, if there are more bugreports waiting.
+     *
+     * Pass true to reschedule upload job, false not to reschedule.
+     */
+    interface Result {
+        void reschedule(boolean s);
+    }
+
+    /** Constructs SimpleUploaderAsyncTask. */
+    SimpleUploaderAsyncTask(@NonNull Context context, @NonNull Result result) {
+        mContext = context;
+        mResult = result;
+    }
+
+    private StorageObject uploadSimple(
+            Storage storage, MetaBugReport bugReport, String fileName, InputStream data)
+            throws IOException {
+        InputStreamContent mediaContent = new InputStreamContent("application/zip", data);
+
+        String bucket = mContext.getString(R.string.config_gcs_bucket);
+        if (TextUtils.isEmpty(bucket)) {
+            throw new RuntimeException("config_gcs_bucket is empty.");
+        }
+
+        // Create GCS MetaData.
+        Map<String, String> metadata = ImmutableMap.of(
+                STORAGE_METADATA_TITLE, bugReport.getTitle()
+        );
+        StorageObject object = new StorageObject()
+                .setBucket(bucket)
+                .setName(fileName)
+                .setMetadata(metadata)
+                .setContentDisposition("attachment");
+        Storage.Objects.Insert insertObject = storage.objects().insert(bucket, object,
+                mediaContent);
+
+        // The media uploader gzips content by default, and alters the Content-Encoding accordingly.
+        // GCS dutifully stores content as-uploaded. This line disables the media uploader behavior,
+        // so the service stores exactly what is in the InputStream, without transformation.
+        insertObject.getMediaHttpUploader().setDisableGZipContent(true);
+        Log.v(TAG, "started uploading object " + fileName + " to bucket " + bucket);
+        return insertObject.execute();
+    }
+
+    private void upload(MetaBugReport bugReport) throws IOException {
+        GoogleCredential credential = GoogleCredential
+                .fromStream(mContext.getResources().openRawResource(R.raw.gcs_credentials))
+                .createScoped(Collections.singleton(ACCESS_SCOPE));
+        Log.v(TAG, "Created credential");
+        HttpTransport httpTransport = AndroidHttp.newCompatibleTransport();
+        JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
+
+        Storage storage = new Storage.Builder(httpTransport, jsonFactory, credential)
+                .setApplicationName("Bugreportupload/1.0").build();
+
+        File tmpBugReportFile = zipBugReportFiles(bugReport);
+        Log.d(TAG, "Uploading file " + tmpBugReportFile);
+        try {
+            // Upload filename is bugreport filename, although, now it contains the audio message.
+            String fileName = bugReport.getBugReportFileName();
+            if (Strings.isNullOrEmpty(fileName)) {
+                // Old bugreports don't contain getBugReportFileName, fallback to getFilePath.
+                fileName = new File(bugReport.getFilePath()).getName();
+            }
+            try (FileInputStream inputStream = new FileInputStream(tmpBugReportFile)) {
+                StorageObject object = uploadSimple(storage, bugReport, fileName, inputStream);
+                Log.v(TAG, "finished uploading object " + object.getName() + " file " + fileName);
+            }
+            File pendingDir = FileUtils.getPendingDir(mContext);
+            // Delete only after successful upload; the files are needed for retry.
+            if (!Strings.isNullOrEmpty(bugReport.getAudioFileName())) {
+                Log.v(TAG, "Deleting file " + bugReport.getAudioFileName());
+                new File(pendingDir, bugReport.getAudioFileName()).delete();
+            }
+            if (!Strings.isNullOrEmpty(bugReport.getBugReportFileName())) {
+                Log.v(TAG, "Deleting file " + bugReport.getBugReportFileName());
+                new File(pendingDir, bugReport.getBugReportFileName()).delete();
+            }
+        } finally {
+            // Delete the temp file if it's not a MetaBugReport#getFilePath, because it's needed
+            // for retry.
+            if (Strings.isNullOrEmpty(bugReport.getFilePath())) {
+                Log.v(TAG, "Deleting file " + tmpBugReportFile);
+                tmpBugReportFile.delete();
+            }
+        }
+    }
+
+    private File zipBugReportFiles(MetaBugReport bugReport) throws IOException {
+        if (!Strings.isNullOrEmpty(bugReport.getFilePath())) {
+            // Old bugreports still have this field.
+            return new File(bugReport.getFilePath());
+        }
+        File finalZipFile =
+                File.createTempFile("bugreport", ".zip", mContext.getCacheDir());
+        File pendingDir = FileUtils.getPendingDir(mContext);
+        try (ZipOutputStream zipStream = new ZipOutputStream(
+                new BufferedOutputStream(new FileOutputStream(finalZipFile)))) {
+            ZipUtils.extractZippedFileToZipStream(
+                    new File(pendingDir, bugReport.getBugReportFileName()), zipStream);
+            ZipUtils.addFileToZipStream(
+                    new File(pendingDir, bugReport.getAudioFileName()), zipStream);
+        }
+        return finalZipFile;
+    }
+
+    @Override
+    protected void onPostExecute(Boolean success) {
+        mResult.reschedule(success);
+    }
+
+    /** Returns true is there are more files to upload. */
+    @Override
+    protected Boolean doInBackground(Void... voids) {
+        List<MetaBugReport> bugReports = BugStorageUtils.getUploadPendingBugReports(mContext);
+
+        for (MetaBugReport bugReport : bugReports) {
+            try {
+                if (isCancelled()) {
+                    BugStorageUtils.setUploadRetry(mContext, bugReport, "Upload Job Cancelled");
+                    return true;
+                }
+                upload(bugReport);
+                BugStorageUtils.setUploadSuccess(mContext, bugReport);
+            } catch (Exception e) {
+                Log.e(TAG, String.format("Failed uploading %s - likely a transient error",
+                        bugReport.getTimestamp()), e);
+                BugStorageUtils.setUploadRetry(mContext, bugReport, e);
+            }
+        }
+        return false;
+    }
+
+    @Override
+    protected void onCancelled(Boolean success) {
+        mResult.reschedule(true);
+    }
+}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/StartUpBootReceiver.java b/tests/BugReportApp/src/com/android/car/bugreport/StartUpBootReceiver.java
new file mode 100644
index 0000000..7528c21
--- /dev/null
+++ b/tests/BugReportApp/src/com/android/car/bugreport/StartUpBootReceiver.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.bugreport;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.UserManager;
+import android.util.Log;
+
+/**
+ * Handles device boot intents.
+ *
+ * <ul>
+ *     <li>Starts {@link UploadJob}</li>
+ * </ul>
+ */
+public class StartUpBootReceiver extends BroadcastReceiver {
+    public static final String TAG = StartUpBootReceiver.class.getSimpleName();
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (!Config.isBugReportEnabled()) {
+            return;
+        }
+        // Run it only once for the system user (u0) and ignore for other users.
+        UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        if (!userManager.isSystemUser()) {
+            return;
+        }
+
+        if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
+            Log.d(TAG, "StartUpBootReceiver BOOT_COMPLETED");
+            // We removed "persisted" from UploadJob scheduling, instead we will manually schedule
+            // the job on boot, because "persisted" seems more fragile.
+            JobSchedulingUtils.scheduleUploadJob(context);
+        }
+    }
+}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/Status.java b/tests/BugReportApp/src/com/android/car/bugreport/Status.java
new file mode 100644
index 0000000..84250bb
--- /dev/null
+++ b/tests/BugReportApp/src/com/android/car/bugreport/Status.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.bugreport;
+
+/** Defines {@link MetaBugReport} statuses. */
+public enum Status {
+    // Bugreport is being written
+    STATUS_WRITE_PENDING(0),
+
+    // Writing bugreport failed
+    STATUS_WRITE_FAILED(1),
+
+    // Bugreport is waiting to be uploaded
+    STATUS_UPLOAD_PENDING(2),
+
+    // Bugreport uploaded successfully
+    STATUS_UPLOAD_SUCCESS(3),
+
+    // Bugreport failed to upload
+    STATUS_UPLOAD_FAILED(4),
+
+    // Bugreport is cancelled by user
+    STATUS_USER_CANCELLED(5),
+
+    // Bugreport is pending user choice on whether to upload or copy.
+    STATUS_PENDING_USER_ACTION(6),
+
+    // Bugreport was moved successfully.
+    STATUS_MOVE_SUCCESSFUL(7),
+
+    // Bugreport move has failed.
+    STATUS_MOVE_FAILED(8),
+
+    // Bugreport is moving to USB drive.
+    STATUS_MOVE_IN_PROGRESS(9),
+
+    // Bugreport is expired. Associated file is deleted from the disk.
+    STATUS_EXPIRED(10),
+
+    // Bugreport needs audio message.
+    STATUS_AUDIO_PENDING(11);
+
+    private final int mValue;
+
+    Status(int value) {
+        mValue = value;
+    }
+
+    /** Returns integer value of the status. */
+    public int getValue() {
+        return mValue;
+    }
+
+    /** Generates human-readable string from a status value. */
+    public static String toString(int value) {
+        switch (value) {
+            case 0:
+                return "Write pending";
+            case 1:
+                return "Write failed";
+            case 2:
+                return "Upload pending";
+            case 3:
+                return "Upload successful";
+            case 4:
+                return "Upload failed";
+            case 5:
+                return "User cancelled";
+            case 6:
+                return "Pending user action";
+            case 7:
+                return "Move successful";
+            case 8:
+                return "Move failed";
+            case 9:
+                return "Move in progress";
+            case 10:
+                return "Expired";
+            case 11:
+                return "Audio message pending";
+        }
+        return "unknown";
+    }
+}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/UploadJob.java b/tests/BugReportApp/src/com/android/car/bugreport/UploadJob.java
new file mode 100644
index 0000000..a0b9cec
--- /dev/null
+++ b/tests/BugReportApp/src/com/android/car/bugreport/UploadJob.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.bugreport;
+
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.util.Log;
+
+/** Executes a {@link SimpleUploaderAsyncTask}. */
+public class UploadJob extends JobService {
+    private static final String TAG = UploadJob.class.getSimpleName();
+
+    private SimpleUploaderAsyncTask mUploader;
+
+    @Override
+    public boolean onStartJob(final JobParameters jobParameters) {
+        if (!Config.isBugReportEnabled()) {
+            return false;
+        }
+        Log.v(TAG, "Starting upload job");
+        mUploader = new SimpleUploaderAsyncTask(
+                this, reschedule -> jobFinished(jobParameters, reschedule));
+        mUploader.execute();
+        return true;
+    }
+
+    @Override
+    public boolean onStopJob(JobParameters jobParameters) {
+        mUploader.cancel(true);
+        return false;
+    }
+}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/VoiceRecordingView.java b/tests/BugReportApp/src/com/android/car/bugreport/VoiceRecordingView.java
new file mode 100644
index 0000000..32e66c4
--- /dev/null
+++ b/tests/BugReportApp/src/com/android/car/bugreport/VoiceRecordingView.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.bugreport;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.media.MediaRecorder;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+
+/**
+ * A view that draws MIC icon and an animated ellipsoid. The ellipsoid animation shows the sound
+ * amplitude from {@link MediaRecorder}.
+ *
+ * <p>All the constant values are chosen experimentally.
+ */
+public class VoiceRecordingView extends View {
+    private static final String TAG = VoiceRecordingView.class.getSimpleName();
+
+    private static final float DROPOFF_STEP = 10f;
+    private static final long ANIMATION_INTERVAL_MS = 70;
+    private static final float RECORDER_AMPLITUDE_NORMALIZER_COEF = 16192.0f;
+
+    private final Paint mPaint;
+    private final BitmapDrawable mMicIconDrawable;
+
+    private float mCurrentRadius;
+    private MediaRecorder mRecorder;
+
+    public VoiceRecordingView(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        mMicIconDrawable = (BitmapDrawable) context.getDrawable(
+                android.R.drawable.ic_btn_speak_now);
+
+        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mPaint.setColor(Color.LTGRAY);
+        mPaint.setStyle(Paint.Style.FILL);
+    }
+
+    /** Sets MediaRecorder that will be used to animate the ellipsoid. */
+    public void setRecorder(@Nullable MediaRecorder recorder) {
+        mRecorder = recorder;
+        invalidate();
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldW, int oldH) {
+        super.onSizeChanged(w, h, oldW, oldH);
+
+        float micIconWidth = mMicIconDrawable.getBitmap().getWidth();
+        float micIconHeight = mMicIconDrawable.getBitmap().getHeight();
+        int micIconDrawableWidth = (int) (micIconWidth / micIconHeight * h);
+        int micIconDrawableLeft = (w - micIconDrawableWidth) / 2;
+        mMicIconDrawable.setBounds(
+                new Rect(micIconDrawableLeft, 0, micIconDrawableLeft + micIconDrawableWidth, h));
+    }
+
+    private void updateCurrentRadius(int width) {
+        final float maxRadius = width / 4;
+        float radius = 0;
+
+        if (mRecorder != null) {
+            try {
+                radius += maxRadius * mRecorder.getMaxAmplitude()
+                        / RECORDER_AMPLITUDE_NORMALIZER_COEF;
+            } catch (IllegalStateException e) {
+                Log.v(TAG, "Failed to get max amplitude from MediaRecorder");
+            }
+        }
+
+        if (radius > mCurrentRadius) {
+            mCurrentRadius = radius;
+        } else {
+            mCurrentRadius = Math.max(radius, mCurrentRadius - DROPOFF_STEP);
+        }
+        mCurrentRadius = Math.min(maxRadius, mCurrentRadius);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+
+        final int width = canvas.getWidth();
+        final int height = canvas.getHeight();
+
+        updateCurrentRadius(width);
+
+        // Draws an ellipsoid with horizontal radius calculated from MediaRecorder's amplitude.
+        final int mx = width / 2;
+        final int my = height / 2;
+        canvas.drawCircle(mx, my, height / 2, mPaint);
+        canvas.drawCircle(mx - mCurrentRadius, my, height / 2, mPaint);
+        canvas.drawCircle(mx + mCurrentRadius, my, height / 2, mPaint);
+        canvas.drawRect(mx - mCurrentRadius, 0, mx + mCurrentRadius, height, mPaint);
+
+        if (mRecorder != null) {
+            postInvalidateDelayed(ANIMATION_INTERVAL_MS);
+        }
+
+        mMicIconDrawable.draw(canvas);
+    }
+}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/ZipUtils.java b/tests/BugReportApp/src/com/android/car/bugreport/ZipUtils.java
new file mode 100644
index 0000000..4fb4cfc
--- /dev/null
+++ b/tests/BugReportApp/src/com/android/car/bugreport/ZipUtils.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.bugreport;
+
+import android.util.Log;
+
+import com.google.common.io.ByteStreams;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+/** Zip utility functions. */
+final class ZipUtils {
+    private static final String TAG = ZipUtils.class.getSimpleName();
+
+    /** Extracts the contents of a zip file to the zip output stream. */
+    static void extractZippedFileToZipStream(File file, ZipOutputStream zipStream) {
+        if (!file.exists()) {
+            Log.w(TAG, "File " + file + " not found");
+            return;
+        }
+        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, "Zip file " + file.getName() + " is empty, skipping.");
+            return;
+        }
+        try (ZipFile zipFile = new ZipFile(file)) {
+            Enumeration<? extends ZipEntry> entries = zipFile.entries();
+            while (entries.hasMoreElements()) {
+                ZipEntry entry = entries.nextElement();
+                try (InputStream stream = zipFile.getInputStream(entry)) {
+                    writeInputStreamToZipStream(entry.getName(), stream, zipStream);
+                }
+            }
+        } catch (IOException e) {
+            Log.w(TAG, "Failed to add " + file + " to zip", e);
+        }
+    }
+
+    /** Adds a file to the zip output stream. */
+    static void addFileToZipStream(File file, ZipOutputStream zipStream) {
+        if (!file.exists()) {
+            Log.w(TAG, "File " + file + " not found");
+            return;
+        }
+        if (file.length() == 0) {
+            Log.w(TAG, "File " + file.getName() + " is empty, skipping.");
+            return;
+        }
+        try (FileInputStream audioInput = new FileInputStream(file)) {
+            writeInputStreamToZipStream(file.getName(), audioInput, zipStream);
+        } catch (IOException e) {
+            Log.w(TAG, "Failed to add " + file + "to the final zip");
+        }
+    }
+
+    /** Writes a new file from input stream to the zip stream. */
+    static void writeInputStreamToZipStream(
+            String filename, InputStream input, ZipOutputStream zipStream) throws IOException {
+        ZipEntry entry = new ZipEntry(filename);
+        zipStream.putNextEntry(entry);
+        ByteStreams.copy(input, zipStream);
+        zipStream.closeEntry();
+    }
+
+    private ZipUtils() {}
+}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/BugInfoAdapter.java b/tests/BugReportApp/src/com/google/android/car/bugreport/BugInfoAdapter.java
deleted file mode 100644
index 3d01729..0000000
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/BugInfoAdapter.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.android.car.bugreport;
-
-import android.os.Build;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.TextView;
-
-import androidx.recyclerview.widget.RecyclerView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Shows bugreport title, status, status message and user action buttons. "Upload to Google" button
- * is enabled when the status is {@link Status#STATUS_PENDING_USER_ACTION}, "Move to USB" button is
- * enabled only when status is  {@link Status#STATUS_PENDING_USER_ACTION} and USB device is plugged
- * in.
- */
-public class BugInfoAdapter extends RecyclerView.Adapter<BugInfoAdapter.BugInfoViewHolder> {
-    static final int BUTTON_TYPE_UPLOAD = 0;
-    static final int BUTTON_TYPE_MOVE = 1;
-    static final int BUTTON_TYPE_ADD_AUDIO = 2;
-
-    /** Provides a handler for click events*/
-    interface ItemClickedListener {
-        /**
-         * Handles click events differently depending on provided buttonType and
-         * uses additional information provided in metaBugReport.
-         *
-         * @param buttonType One of {@link #BUTTON_TYPE_UPLOAD}, {@link #BUTTON_TYPE_MOVE} or
-         *                   {@link #BUTTON_TYPE_ADD_AUDIO}.
-         * @param metaBugReport Selected bugreport.
-         * @param holder ViewHolder of the clicked item.
-         */
-        void onItemClicked(int buttonType, MetaBugReport metaBugReport, BugInfoViewHolder holder);
-    }
-
-    /**
-     * Reference to each bug report info views.
-     */
-    static class BugInfoViewHolder extends RecyclerView.ViewHolder {
-        /** Title view */
-        TextView mTitleView;
-
-        /** Status View */
-        TextView mStatusView;
-
-        /** Message View */
-        TextView mMessageView;
-
-        /** Move Button */
-        Button mMoveButton;
-
-        /** Upload Button */
-        Button mUploadButton;
-
-        /** Add Audio Button */
-        Button mAddAudioButton;
-
-        BugInfoViewHolder(View v) {
-            super(v);
-            mTitleView = itemView.findViewById(R.id.bug_info_row_title);
-            mStatusView = itemView.findViewById(R.id.bug_info_row_status);
-            mMessageView = itemView.findViewById(R.id.bug_info_row_message);
-            mMoveButton = itemView.findViewById(R.id.bug_info_move_button);
-            mUploadButton = itemView.findViewById(R.id.bug_info_upload_button);
-            mAddAudioButton = itemView.findViewById(R.id.bug_info_add_audio_button);
-        }
-    }
-
-    private List<MetaBugReport> mDataset;
-    private final ItemClickedListener mItemClickedListener;
-    private final Config mConfig;
-
-    BugInfoAdapter(ItemClickedListener itemClickedListener, Config config) {
-        mItemClickedListener = itemClickedListener;
-        mDataset = new ArrayList<>();
-        mConfig = config;
-        // Allow RecyclerView to efficiently update UI; getItemId() is implemented below.
-        setHasStableIds(true);
-    }
-
-    @Override
-    public BugInfoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-        // create a new view
-        View v = LayoutInflater.from(parent.getContext())
-                .inflate(R.layout.bug_info_view, parent, false);
-        return new BugInfoViewHolder(v);
-    }
-
-    @Override
-    public void onBindViewHolder(BugInfoViewHolder holder, int position) {
-        MetaBugReport bugreport = mDataset.get(position);
-        holder.mTitleView.setText(bugreport.getTitle());
-        holder.mStatusView.setText(Status.toString(bugreport.getStatus()));
-        holder.mMessageView.setText(bugreport.getStatusMessage());
-        if (bugreport.getStatusMessage().isEmpty()) {
-            holder.mMessageView.setVisibility(View.GONE);
-        } else {
-            holder.mMessageView.setVisibility(View.VISIBLE);
-        }
-        boolean enableUserActionButtons =
-                bugreport.getStatus() == Status.STATUS_PENDING_USER_ACTION.getValue()
-                        || bugreport.getStatus() == Status.STATUS_MOVE_FAILED.getValue()
-                        || bugreport.getStatus() == Status.STATUS_UPLOAD_FAILED.getValue();
-        if (enableUserActionButtons) {
-            holder.mMoveButton.setEnabled(true);
-            holder.mMoveButton.setVisibility(View.VISIBLE);
-            holder.mMoveButton.setOnClickListener(
-                    view -> mItemClickedListener.onItemClicked(BUTTON_TYPE_MOVE, bugreport,
-                            holder));
-        } else {
-            holder.mMoveButton.setEnabled(false);
-            holder.mMoveButton.setVisibility(View.GONE);
-        }
-        // Enable the upload button only for userdebug/eng builds.
-        if (enableUserActionButtons && Build.IS_DEBUGGABLE) {
-            holder.mUploadButton.setText(R.string.bugreport_upload_gcs_button_text);
-            holder.mUploadButton.setEnabled(true);
-            holder.mUploadButton.setVisibility(View.VISIBLE);
-            holder.mUploadButton.setOnClickListener(
-                    view -> mItemClickedListener.onItemClicked(BUTTON_TYPE_UPLOAD, bugreport,
-                            holder));
-        } else {
-            holder.mUploadButton.setVisibility(View.GONE);
-            holder.mUploadButton.setEnabled(false);
-        }
-        if (bugreport.getStatus() == Status.STATUS_AUDIO_PENDING.getValue()) {
-            if (mConfig.getAutoUpload()) {
-                holder.mAddAudioButton.setText(R.string.bugreport_add_audio_upload_button_text);
-            } else {
-                holder.mAddAudioButton.setText(R.string.bugreport_add_audio_button_text);
-            }
-            holder.mAddAudioButton.setEnabled(true);
-            holder.mAddAudioButton.setVisibility(View.VISIBLE);
-            holder.mAddAudioButton.setOnClickListener(view ->
-                    mItemClickedListener.onItemClicked(BUTTON_TYPE_ADD_AUDIO, bugreport, holder));
-        } else {
-            holder.mAddAudioButton.setEnabled(false);
-            holder.mAddAudioButton.setVisibility(View.GONE);
-        }
-    }
-
-    /** Sets dataSet; it copies the list, because it modifies it in this adapter. */
-    void setDataset(List<MetaBugReport> bugReports) {
-        mDataset = new ArrayList<>(bugReports);
-        notifyDataSetChanged();
-    }
-
-    /** Update a bug report in the data set. */
-    void updateBugReportInDataSet(MetaBugReport bugReport, int position) {
-        if (position != RecyclerView.NO_POSITION) {
-            mDataset.set(position, bugReport);
-            notifyItemChanged(position);
-        }
-    }
-
-    @Override
-    public long getItemId(int position) {
-        return mDataset.get(position).getId();
-    }
-
-    @Override
-    public int getItemCount() {
-        return mDataset.size();
-    }
-}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportActivity.java b/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportActivity.java
deleted file mode 100644
index 20fe5f9..0000000
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportActivity.java
+++ /dev/null
@@ -1,713 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.android.car.bugreport;
-
-import static com.google.android.car.bugreport.BugReportService.MAX_PROGRESS_VALUE;
-
-import android.Manifest;
-import android.app.Activity;
-import android.car.Car;
-import android.car.CarNotConnectedException;
-import android.car.drivingstate.CarDrivingStateEvent;
-import android.car.drivingstate.CarDrivingStateManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.media.AudioAttributes;
-import android.media.AudioFocusRequest;
-import android.media.AudioManager;
-import android.media.MediaRecorder;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.UserManager;
-import android.util.Log;
-import android.view.View;
-import android.view.Window;
-import android.widget.Button;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.google.common.base.Preconditions;
-import com.google.common.io.ByteStreams;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.Random;
-
-/**
- * Activity that shows two types of dialogs: starting a new bug report and current status of already
- * in progress bug report.
- *
- * <p>If there is no in-progress bug report, it starts recording voice message. After clicking
- * submit button it initiates {@link BugReportService}.
- *
- * <p>If bug report is in-progress, it shows a progress bar.
- */
-public class BugReportActivity extends Activity {
-    private static final String TAG = BugReportActivity.class.getSimpleName();
-
-    /** Starts silent (no audio message recording) bugreporting. */
-    private static final String ACTION_START_SILENT =
-            "com.google.android.car.bugreport.action.START_SILENT";
-
-    /** This is deprecated action. Please start SILENT bugreport using {@link BugReportService}. */
-    private static final String ACTION_ADD_AUDIO =
-            "com.google.android.car.bugreport.action.ADD_AUDIO";
-
-    private static final int VOICE_MESSAGE_MAX_DURATION_MILLIS = 60 * 1000;
-    private static final int AUDIO_PERMISSIONS_REQUEST_ID = 1;
-
-    private static final String EXTRA_BUGREPORT_ID = "bugreport-id";
-
-    /**
-     * NOTE: mRecorder related messages are cleared when the activity finishes.
-     */
-    private final Handler mHandler = new Handler(Looper.getMainLooper());
-
-    /** Look up string length, e.g. [ABCDEF]. */
-    static final int LOOKUP_STRING_LENGTH = 6;
-
-    private TextView mInProgressTitleText;
-    private ProgressBar mProgressBar;
-    private TextView mProgressText;
-    private TextView mAddAudioText;
-    private VoiceRecordingView mVoiceRecordingView;
-    private View mVoiceRecordingFinishedView;
-    private View mSubmitBugReportLayout;
-    private View mInProgressLayout;
-    private View mShowBugReportsButton;
-    private Button mSubmitButton;
-
-    private boolean mBound;
-    /** Audio message recording process started (including waiting for permission). */
-    private boolean mAudioRecordingStarted;
-    /** Audio recording using MIC is running (permission given). */
-    private boolean mAudioRecordingIsRunning;
-    private boolean mIsNewBugReport;
-    private boolean mIsOnActivityStartedWithBugReportServiceBoundCalled;
-    private boolean mIsSubmitButtonClicked;
-    private BugReportService mService;
-    private MediaRecorder mRecorder;
-    private MetaBugReport mMetaBugReport;
-    private File mAudioFile;
-    private Car mCar;
-    private CarDrivingStateManager mDrivingStateManager;
-    private AudioManager mAudioManager;
-    private AudioFocusRequest mLastAudioFocusRequest;
-    private Config mConfig;
-
-    /** Defines callbacks for service binding, passed to bindService() */
-    private ServiceConnection mConnection = new ServiceConnection() {
-        @Override
-        public void onServiceConnected(ComponentName className, IBinder service) {
-            BugReportService.ServiceBinder binder = (BugReportService.ServiceBinder) service;
-            mService = binder.getService();
-            mBound = true;
-            onActivityStartedWithBugReportServiceBound();
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName arg0) {
-            // called when service connection breaks unexpectedly.
-            mBound = false;
-        }
-    };
-
-    /**
-     * Builds an intent that starts {@link BugReportActivity} to add audio message to the existing
-     * bug report.
-     */
-    static Intent buildAddAudioIntent(Context context, MetaBugReport bug) {
-        Intent addAudioIntent = new Intent(context, BugReportActivity.class);
-        addAudioIntent.setAction(ACTION_ADD_AUDIO);
-        addAudioIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-        addAudioIntent.putExtra(EXTRA_BUGREPORT_ID, bug.getId());
-        return addAudioIntent;
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        Preconditions.checkState(Config.isBugReportEnabled(), "BugReport is disabled.");
-
-        super.onCreate(savedInstanceState);
-        requestWindowFeature(Window.FEATURE_NO_TITLE);
-
-        // Bind to BugReportService.
-        Intent intent = new Intent(this, BugReportService.class);
-        bindService(intent, mConnection, BIND_AUTO_CREATE);
-    }
-
-    @Override
-    protected void onStart() {
-        super.onStart();
-
-        if (mBound) {
-            onActivityStartedWithBugReportServiceBound();
-        }
-    }
-
-    @Override
-    protected void onStop() {
-        super.onStop();
-        // If SUBMIT button is clicked, cancelling audio has been taken care of.
-        if (!mIsSubmitButtonClicked) {
-            cancelAudioMessageRecording();
-        }
-        if (mBound) {
-            mService.removeBugReportProgressListener();
-        }
-        // Reset variables for the next onStart().
-        mAudioRecordingStarted = false;
-        mAudioRecordingIsRunning = false;
-        mIsSubmitButtonClicked = false;
-        mIsOnActivityStartedWithBugReportServiceBoundCalled = false;
-        mMetaBugReport = null;
-        mAudioFile = null;
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-
-        if (mRecorder != null) {
-            mHandler.removeCallbacksAndMessages(/* token= */ mRecorder);
-        }
-        if (mBound) {
-            unbindService(mConnection);
-            mBound = false;
-        }
-        if (mCar != null && mCar.isConnected()) {
-            mCar.disconnect();
-            mCar = null;
-        }
-    }
-
-    private void onCarDrivingStateChanged(CarDrivingStateEvent event) {
-        if (mShowBugReportsButton == null) {
-            Log.w(TAG, "Cannot handle driving state change, UI is not ready");
-            return;
-        }
-        // When adding audio message to the existing bugreport, do not show "Show Bug Reports"
-        // button, users either should explicitly Submit or Cancel.
-        if (mAudioRecordingStarted && !mIsNewBugReport) {
-            mShowBugReportsButton.setVisibility(View.GONE);
-            return;
-        }
-        if (event.eventValue == CarDrivingStateEvent.DRIVING_STATE_PARKED
-                || event.eventValue == CarDrivingStateEvent.DRIVING_STATE_IDLING) {
-            mShowBugReportsButton.setVisibility(View.VISIBLE);
-        } else {
-            mShowBugReportsButton.setVisibility(View.GONE);
-        }
-    }
-
-    private void onProgressChanged(float progress) {
-        int progressValue = (int) progress;
-        mProgressBar.setProgress(progressValue);
-        mProgressText.setText(progressValue + "%");
-        if (progressValue == MAX_PROGRESS_VALUE) {
-            mInProgressTitleText.setText(R.string.bugreport_dialog_in_progress_title_finished);
-        }
-    }
-
-    private void prepareUi() {
-        if (mSubmitBugReportLayout != null) {
-            return;
-        }
-        setContentView(R.layout.bug_report_activity);
-
-        // Connect to the services here, because they are used only when showing the dialog.
-        // We need to minimize system state change when performing SILENT bug report.
-        mConfig = new Config();
-        mConfig.start();
-        mCar = Car.createCar(this, /* handler= */ null,
-                Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT, this::onCarLifecycleChanged);
-
-        mInProgressTitleText = findViewById(R.id.in_progress_title_text);
-        mProgressBar = findViewById(R.id.progress_bar);
-        mProgressText = findViewById(R.id.progress_text);
-        mAddAudioText = findViewById(R.id.bug_report_add_audio_to_existing);
-        mVoiceRecordingView = findViewById(R.id.voice_recording_view);
-        mVoiceRecordingFinishedView = findViewById(R.id.voice_recording_finished_text_view);
-        mSubmitBugReportLayout = findViewById(R.id.submit_bug_report_layout);
-        mInProgressLayout = findViewById(R.id.in_progress_layout);
-        mShowBugReportsButton = findViewById(R.id.button_show_bugreports);
-        mSubmitButton = findViewById(R.id.button_submit);
-
-        mShowBugReportsButton.setOnClickListener(this::buttonShowBugReportsClick);
-        mSubmitButton.setOnClickListener(this::buttonSubmitClick);
-        findViewById(R.id.button_cancel).setOnClickListener(this::buttonCancelClick);
-        findViewById(R.id.button_close).setOnClickListener(this::buttonCancelClick);
-
-        if (mIsNewBugReport) {
-            mSubmitButton.setText(R.string.bugreport_dialog_submit);
-        } else {
-            mSubmitButton.setText(mConfig.getAutoUpload()
-                    ? R.string.bugreport_dialog_upload : R.string.bugreport_dialog_save);
-        }
-    }
-
-    private void onCarLifecycleChanged(Car car, boolean ready) {
-        if (!ready) {
-            mDrivingStateManager = null;
-            mCar = null;
-            Log.d(TAG, "Car service is not ready, ignoring");
-            // If car service is not ready for this activity, just ignore it - as it's only
-            // used to control UX restrictions.
-            return;
-        }
-        try {
-            mDrivingStateManager = (CarDrivingStateManager) car.getCarManager(
-                    Car.CAR_DRIVING_STATE_SERVICE);
-            mDrivingStateManager.registerListener(
-                    BugReportActivity.this::onCarDrivingStateChanged);
-            // Call onCarDrivingStateChanged(), because it's not called when Car is connected.
-            onCarDrivingStateChanged(mDrivingStateManager.getCurrentCarDrivingState());
-        } catch (CarNotConnectedException e) {
-            Log.w(TAG, "Failed to get CarDrivingStateManager", e);
-        }
-    }
-
-    private void showInProgressUi() {
-        mSubmitBugReportLayout.setVisibility(View.GONE);
-        mInProgressLayout.setVisibility(View.VISIBLE);
-        mInProgressTitleText.setText(R.string.bugreport_dialog_in_progress_title);
-        onProgressChanged(mService.getBugReportProgress());
-    }
-
-    private void showSubmitBugReportUi(boolean isRecording) {
-        mSubmitBugReportLayout.setVisibility(View.VISIBLE);
-        mInProgressLayout.setVisibility(View.GONE);
-        if (isRecording) {
-            mVoiceRecordingFinishedView.setVisibility(View.GONE);
-            mVoiceRecordingView.setVisibility(View.VISIBLE);
-        } else {
-            mVoiceRecordingFinishedView.setVisibility(View.VISIBLE);
-            mVoiceRecordingView.setVisibility(View.GONE);
-        }
-        // NOTE: mShowBugReportsButton visibility is also handled in #onCarDrivingStateChanged().
-        mShowBugReportsButton.setVisibility(View.GONE);
-        if (mDrivingStateManager != null) {
-            try {
-                onCarDrivingStateChanged(mDrivingStateManager.getCurrentCarDrivingState());
-            } catch (CarNotConnectedException e) {
-                Log.e(TAG, "Failed to get current driving state.", e);
-            }
-        }
-    }
-
-    /**
-     * Initializes MetaBugReport in a local DB and starts audio recording.
-     *
-     * <p>This method expected to be called when the activity is started and bound to the service.
-     */
-    private void onActivityStartedWithBugReportServiceBound() {
-        if (mIsOnActivityStartedWithBugReportServiceBoundCalled) {
-            return;
-        }
-        mIsOnActivityStartedWithBugReportServiceBoundCalled = true;
-
-        if (mService.isCollectingBugReport()) {
-            Log.i(TAG, "Bug report is already being collected.");
-            mService.setBugReportProgressListener(this::onProgressChanged);
-            prepareUi();
-            showInProgressUi();
-            return;
-        }
-
-        if (ACTION_START_SILENT.equals(getIntent().getAction())) {
-            Log.i(TAG, "Starting a silent bugreport.");
-            MetaBugReport bugReport = createBugReport(this, MetaBugReport.TYPE_SILENT);
-            startBugReportCollection(bugReport);
-            finish();
-            return;
-        }
-
-        // Close the notification shade and other dialogs when showing BugReportActivity dialog.
-        sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
-
-        if (ACTION_ADD_AUDIO.equals(getIntent().getAction())) {
-            addAudioToExistingBugReport(
-                    getIntent().getIntExtra(EXTRA_BUGREPORT_ID, /* defaultValue= */ -1));
-            return;
-        }
-
-        Log.i(TAG, "Starting an interactive bugreport.");
-        createNewBugReportWithAudioMessage();
-    }
-
-    private void addAudioToExistingBugReport(int bugreportId) {
-        MetaBugReport bug = BugStorageUtils.findBugReport(this, bugreportId).orElseThrow(
-                () -> new RuntimeException("Failed to find bug report with id " + bugreportId));
-        Log.i(TAG, "Adding audio to the existing bugreport " + bug.getTimestamp());
-        if (bug.getStatus() != Status.STATUS_AUDIO_PENDING.getValue()) {
-            Log.e(TAG, "Failed to add audio, bad status, expected "
-                    + Status.STATUS_AUDIO_PENDING.getValue() + ", got " + bug.getStatus());
-            finish();
-        }
-        File audioFile;
-        try {
-            audioFile = File.createTempFile("audio", "mp3", getCacheDir());
-        } catch (IOException e) {
-            throw new RuntimeException("failed to create temp audio file");
-        }
-        startAudioMessageRecording(/* isNewBugReport= */ false, bug, audioFile);
-    }
-
-    private void createNewBugReportWithAudioMessage() {
-        MetaBugReport bug = createBugReport(this, MetaBugReport.TYPE_INTERACTIVE);
-        startAudioMessageRecording(
-                /* isNewBugReport= */ true,
-                bug,
-                FileUtils.getFileWithSuffix(this, bug.getTimestamp(), "-message.3gp"));
-    }
-
-    /** Shows a dialog UI and starts recording audio message. */
-    private void startAudioMessageRecording(
-            boolean isNewBugReport, MetaBugReport bug, File audioFile) {
-        if (mAudioRecordingStarted) {
-            Log.i(TAG, "Audio message recording is already started.");
-            return;
-        }
-        mAudioRecordingStarted = true;
-        mAudioManager = getSystemService(AudioManager.class);
-        mIsNewBugReport = isNewBugReport;
-        mMetaBugReport = bug;
-        mAudioFile = audioFile;
-        prepareUi();
-        showSubmitBugReportUi(/* isRecording= */ true);
-        if (isNewBugReport) {
-            mAddAudioText.setVisibility(View.GONE);
-        } else {
-            mAddAudioText.setVisibility(View.VISIBLE);
-            mAddAudioText.setText(String.format(
-                    getString(R.string.bugreport_dialog_add_audio_to_existing),
-                    mMetaBugReport.getTimestamp()));
-        }
-
-        if (!hasRecordPermissions()) {
-            requestRecordPermissions();
-        } else {
-            startRecordingWithPermission();
-        }
-    }
-
-    /**
-     * Cancels bugreporting by stopping audio recording and deleting temp files.
-     */
-    private void cancelAudioMessageRecording() {
-        // If audio recording is not running, most likely there were permission issues,
-        // so leave the bugreport as is without cancelling it.
-        if (!mAudioRecordingIsRunning) {
-            Log.w(TAG, "Cannot cancel, audio recording is not running.");
-            return;
-        }
-        stopAudioRecording();
-        if (mIsNewBugReport) {
-            // The app creates a temp dir only for new INTERACTIVE bugreports.
-            File tempDir = FileUtils.getTempDir(this, mMetaBugReport.getTimestamp());
-            new DeleteFilesAndDirectoriesAsyncTask().execute(tempDir);
-        } else {
-            BugStorageUtils.deleteBugReportFiles(this, mMetaBugReport.getId());
-            new DeleteFilesAndDirectoriesAsyncTask().execute(mAudioFile);
-        }
-        BugStorageUtils.setBugReportStatus(
-                this, mMetaBugReport, Status.STATUS_USER_CANCELLED, "");
-        Log.i(TAG, "Bug report " + mMetaBugReport.getTimestamp() + " is cancelled");
-        mAudioRecordingStarted = false;
-        mAudioRecordingIsRunning = false;
-    }
-
-    private void buttonCancelClick(View view) {
-        finish();
-    }
-
-    private void buttonSubmitClick(View view) {
-        stopAudioRecording();
-        mIsSubmitButtonClicked = true;
-        if (mIsNewBugReport) {
-            Log.i(TAG, "Starting bugreport service.");
-            startBugReportCollection(mMetaBugReport);
-        } else {
-            Log.i(TAG, "Adding audio file to the bugreport " + mMetaBugReport.getTimestamp());
-            new AddAudioToBugReportAsyncTask(this, mConfig, mMetaBugReport, mAudioFile).execute();
-        }
-        setResult(Activity.RESULT_OK);
-        finish();
-    }
-
-    /** Starts the {@link BugReportService} to collect bug report. */
-    private void startBugReportCollection(MetaBugReport bug) {
-        Bundle bundle = new Bundle();
-        bundle.putParcelable(BugReportService.EXTRA_META_BUG_REPORT, bug);
-        Intent intent = new Intent(this, BugReportService.class);
-        intent.putExtras(bundle);
-        startForegroundService(intent);
-    }
-
-    /**
-     * Starts {@link BugReportInfoActivity} and finishes current activity, so it won't be running
-     * in the background and closing {@link BugReportInfoActivity} will not open the current
-     * activity again.
-     */
-    private void buttonShowBugReportsClick(View view) {
-        // First cancel the audio recording, then delete the bug report from database.
-        cancelAudioMessageRecording();
-        // Delete the bugreport from database, otherwise pressing "Show Bugreports" button will
-        // create unnecessary cancelled bugreports.
-        if (mMetaBugReport != null) {
-            BugStorageUtils.completeDeleteBugReport(this, mMetaBugReport.getId());
-        }
-        Intent intent = new Intent(this, BugReportInfoActivity.class);
-        startActivity(intent);
-        finish();
-    }
-
-    private void requestRecordPermissions() {
-        requestPermissions(
-                new String[]{Manifest.permission.RECORD_AUDIO}, AUDIO_PERMISSIONS_REQUEST_ID);
-    }
-
-    private boolean hasRecordPermissions() {
-        return checkSelfPermission(Manifest.permission.RECORD_AUDIO)
-                == PackageManager.PERMISSION_GRANTED;
-    }
-
-    @Override
-    public void onRequestPermissionsResult(
-            int requestCode, String[] permissions, int[] grantResults) {
-        if (requestCode != AUDIO_PERMISSIONS_REQUEST_ID) {
-            return;
-        }
-        for (int i = 0; i < grantResults.length; i++) {
-            if (Manifest.permission.RECORD_AUDIO.equals(permissions[i])
-                    && grantResults[i] == PackageManager.PERMISSION_GRANTED) {
-                // Start recording from UI thread, otherwise when MediaRecord#start() fails,
-                // stack trace gets confusing.
-                mHandler.post(this::startRecordingWithPermission);
-                return;
-            }
-        }
-        handleNoPermission(permissions);
-    }
-
-    private void handleNoPermission(String[] permissions) {
-        String text = this.getText(R.string.toast_permissions_denied) + " : "
-                + Arrays.toString(permissions);
-        Log.w(TAG, text);
-        Toast.makeText(this, text, Toast.LENGTH_LONG).show();
-        if (mIsNewBugReport) {
-            BugStorageUtils.setBugReportStatus(this, mMetaBugReport,
-                    Status.STATUS_USER_CANCELLED, text);
-        } else {
-            BugStorageUtils.setBugReportStatus(this, mMetaBugReport,
-                    Status.STATUS_AUDIO_PENDING, text);
-        }
-        finish();
-    }
-
-    private void startRecordingWithPermission() {
-        Log.i(TAG, "Started voice recording, and saving audio to " + mAudioFile);
-
-        mLastAudioFocusRequest = new AudioFocusRequest.Builder(
-                        AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)
-                .setOnAudioFocusChangeListener(focusChange ->
-                        Log.d(TAG, "AudioManager focus change " + focusChange))
-                .setAudioAttributes(new AudioAttributes.Builder()
-                        .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
-                        .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
-                        .build())
-                .setAcceptsDelayedFocusGain(true)
-                .build();
-        int focusGranted = mAudioManager.requestAudioFocus(mLastAudioFocusRequest);
-        // NOTE: We will record even if the audio focus was not granted.
-        Log.d(TAG,
-                "AudioFocus granted " + (focusGranted == AudioManager.AUDIOFOCUS_REQUEST_GRANTED));
-
-        mRecorder = new MediaRecorder();
-        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(mAudioFile);
-
-        try {
-            mRecorder.prepare();
-        } catch (IOException e) {
-            Log.e(TAG, "Failed on MediaRecorder#prepare(), filename: " + mAudioFile, e);
-            finish();
-            return;
-        }
-
-        mRecorder.start();
-        mVoiceRecordingView.setRecorder(mRecorder);
-        mAudioRecordingIsRunning = true;
-
-        // Messages with token mRecorder are cleared when the activity finishes or recording stops.
-        mHandler.postDelayed(() -> {
-            Log.i(TAG, "Timed out while recording voice message, cancelling.");
-            stopAudioRecording();
-            showSubmitBugReportUi(/* isRecording= */ false);
-        }, /* token= */ mRecorder, VOICE_MESSAGE_MAX_DURATION_MILLIS);
-    }
-
-    private void stopAudioRecording() {
-        if (mRecorder != null) {
-            Log.i(TAG, "Recording ended, stopping the MediaRecorder.");
-            mHandler.removeCallbacksAndMessages(/* token= */ mRecorder);
-            try {
-                mRecorder.stop();
-            } catch (RuntimeException 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;
-        }
-        if (mLastAudioFocusRequest != null) {
-            int focusAbandoned = mAudioManager.abandonAudioFocusRequest(mLastAudioFocusRequest);
-            Log.d(TAG, "Audio focus abandoned "
-                    + (focusAbandoned == AudioManager.AUDIOFOCUS_REQUEST_GRANTED));
-            mLastAudioFocusRequest = null;
-        }
-        mVoiceRecordingView.setRecorder(null);
-    }
-
-    private static String getCurrentUserName(Context context) {
-        UserManager um = UserManager.get(context);
-        return um.getUserName();
-    }
-
-    /**
-     * Creates a {@link MetaBugReport} and saves it in a local sqlite database.
-     *
-     * @param context an Android context.
-     * @param type bug report type, {@link MetaBugReport.BugReportType}.
-     */
-    static MetaBugReport createBugReport(Context context, int type) {
-        String timestamp = MetaBugReport.toBugReportTimestamp(new Date());
-        String username = getCurrentUserName(context);
-        String title = BugReportTitleGenerator.generateBugReportTitle(timestamp, username);
-        return BugStorageUtils.createBugReport(context, title, timestamp, username, type);
-    }
-
-    /** A helper class to generate bugreport title. */
-    private static final class BugReportTitleGenerator {
-        /** Contains easily readable characters. */
-        private static final char[] CHARS_FOR_RANDOM_GENERATOR =
-                new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P',
-                        'R', 'S', 'T', 'U', 'W', 'X', 'Y', 'Z'};
-
-        /**
-         * Generates a bugreport title from given timestamp and username.
-         *
-         * <p>Example: "[A45E8] Feedback from user Driver at 2019-09-21_12:00:00"
-         */
-        static String generateBugReportTitle(String timestamp, String username) {
-            // Lookup string is used to search a bug in Buganizer (see b/130915969).
-            String lookupString = generateRandomString(LOOKUP_STRING_LENGTH);
-            return "[" + lookupString + "] Feedback from user " + username + " at " + timestamp;
-        }
-
-        private static String generateRandomString(int length) {
-            Random random = new Random();
-            StringBuilder builder = new StringBuilder();
-            for (int i = 0; i < length; i++) {
-                int randomIndex = random.nextInt(CHARS_FOR_RANDOM_GENERATOR.length);
-                builder.append(CHARS_FOR_RANDOM_GENERATOR[randomIndex]);
-            }
-            return builder.toString();
-        }
-    }
-
-    /** AsyncTask that recursively deletes files and directories. */
-    private static class DeleteFilesAndDirectoriesAsyncTask extends AsyncTask<File, Void, Void> {
-        @Override
-        protected Void doInBackground(File... files) {
-            for (File file : files) {
-                Log.i(TAG, "Deleting " + file.getAbsolutePath());
-                if (file.isFile()) {
-                    file.delete();
-                } else {
-                    FileUtils.deleteDirectory(file);
-                }
-            }
-            return null;
-        }
-    }
-
-    /**
-     * AsyncTask that moves audio file to the system user's {@link FileUtils#getPendingDir} and
-     * sets status to either STATUS_UPLOAD_PENDING or STATUS_PENDING_USER_ACTION.
-     */
-    private static class AddAudioToBugReportAsyncTask extends AsyncTask<Void, Void, Void> {
-        private final Context mContext;
-        private final Config mConfig;
-        private final File mAudioFile;
-        private final MetaBugReport mOriginalBug;
-
-        AddAudioToBugReportAsyncTask(
-                Context context, Config config, MetaBugReport bug, File audioFile) {
-            mContext = context;
-            mConfig = config;
-            mOriginalBug = bug;
-            mAudioFile = audioFile;
-        }
-
-        @Override
-        protected Void doInBackground(Void... voids) {
-            String audioFileName = FileUtils.getAudioFileName(
-                    MetaBugReport.toBugReportTimestamp(new Date()), mOriginalBug);
-            MetaBugReport bug = BugStorageUtils.update(mContext,
-                    mOriginalBug.toBuilder().setAudioFileName(audioFileName).build());
-            try (OutputStream out = BugStorageUtils.openAudioMessageFileToWrite(mContext, bug);
-                 InputStream input = new FileInputStream(mAudioFile)) {
-                ByteStreams.copy(input, out);
-            } catch (IOException e) {
-                BugStorageUtils.setBugReportStatus(mContext, bug,
-                        com.google.android.car.bugreport.Status.STATUS_WRITE_FAILED,
-                        "Failed to write audio to bug report");
-                Log.e(TAG, "Failed to write audio to bug report", e);
-                return null;
-            }
-            if (mConfig.getAutoUpload()) {
-                BugStorageUtils.setBugReportStatus(mContext, bug,
-                        com.google.android.car.bugreport.Status.STATUS_UPLOAD_PENDING, "");
-            } else {
-                BugStorageUtils.setBugReportStatus(mContext, bug,
-                        com.google.android.car.bugreport.Status.STATUS_PENDING_USER_ACTION, "");
-                BugReportService.showBugReportFinishedNotification(mContext, bug);
-            }
-            mAudioFile.delete();
-            return null;
-        }
-    }
-}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportInfoActivity.java b/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportInfoActivity.java
deleted file mode 100644
index 5503706..0000000
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportInfoActivity.java
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.android.car.bugreport;
-
-import static com.google.android.car.bugreport.PackageUtils.getPackageVersion;
-
-import android.app.Activity;
-import android.app.NotificationManager;
-import android.content.ContentResolver;
-import android.content.Intent;
-import android.content.res.AssetFileDescriptor;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.DocumentsContract;
-import android.util.Log;
-import android.view.View;
-import android.widget.TextView;
-
-import androidx.recyclerview.widget.DividerItemDecoration;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-import com.google.common.io.ByteStreams;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-import java.util.zip.ZipOutputStream;
-
-/**
- * Provides an activity that provides information on the bugreports that are filed.
- */
-public class BugReportInfoActivity extends Activity {
-    public static final String TAG = BugReportInfoActivity.class.getSimpleName();
-
-    /** Used for moving bug reports to a new location (e.g. USB drive). */
-    private static final int SELECT_DIRECTORY_REQUEST_CODE = 1;
-
-    /** Used to start {@link BugReportActivity} to add audio message. */
-    private static final int ADD_AUDIO_MESSAGE_REQUEST_CODE = 2;
-
-    private RecyclerView mRecyclerView;
-    private BugInfoAdapter mBugInfoAdapter;
-    private RecyclerView.LayoutManager mLayoutManager;
-    private NotificationManager mNotificationManager;
-    private MetaBugReport mLastSelectedBugReport;
-    private BugInfoAdapter.BugInfoViewHolder mLastSelectedBugInfoViewHolder;
-    private BugStorageObserver mBugStorageObserver;
-    private Config mConfig;
-    private boolean mAudioRecordingStarted;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        Preconditions.checkState(Config.isBugReportEnabled(), "BugReport is disabled.");
-
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.bug_report_info_activity);
-
-        mNotificationManager = getSystemService(NotificationManager.class);
-
-        mRecyclerView = findViewById(R.id.rv_bug_report_info);
-        mRecyclerView.setHasFixedSize(true);
-        // use a linear layout manager
-        mLayoutManager = new LinearLayoutManager(this);
-        mRecyclerView.setLayoutManager(mLayoutManager);
-        mRecyclerView.addItemDecoration(new DividerItemDecoration(mRecyclerView.getContext(),
-                DividerItemDecoration.VERTICAL));
-
-        mConfig = new Config();
-        mConfig.start();
-
-        mBugInfoAdapter = new BugInfoAdapter(this::onBugReportItemClicked, mConfig);
-        mRecyclerView.setAdapter(mBugInfoAdapter);
-
-        mBugStorageObserver = new BugStorageObserver(this, new Handler());
-
-        findViewById(R.id.quit_button).setOnClickListener(this::onQuitButtonClick);
-        findViewById(R.id.start_bug_report_button).setOnClickListener(
-                this::onStartBugReportButtonClick);
-        ((TextView) findViewById(R.id.version_text_view)).setText(
-                String.format("v%s", getPackageVersion(this)));
-
-        cancelBugReportFinishedNotification();
-    }
-
-    @Override
-    protected void onStart() {
-        super.onStart();
-        new BugReportsLoaderAsyncTask(this).execute();
-        // As BugStorageProvider is running under user0, we register using USER_ALL.
-        getContentResolver().registerContentObserver(BugStorageProvider.BUGREPORT_CONTENT_URI, true,
-                mBugStorageObserver, UserHandle.USER_ALL);
-    }
-
-    @Override
-    protected void onStop() {
-        super.onStop();
-        getContentResolver().unregisterContentObserver(mBugStorageObserver);
-    }
-
-    /**
-     * Dismisses {@link BugReportService#BUGREPORT_FINISHED_NOTIF_ID}, otherwise the notification
-     * will stay there forever if this activity opened through the App Launcher.
-     */
-    private void cancelBugReportFinishedNotification() {
-        mNotificationManager.cancel(BugReportService.BUGREPORT_FINISHED_NOTIF_ID);
-    }
-
-    private void onBugReportItemClicked(
-            int buttonType, MetaBugReport bugReport, BugInfoAdapter.BugInfoViewHolder holder) {
-        if (buttonType == BugInfoAdapter.BUTTON_TYPE_UPLOAD) {
-            Log.i(TAG, "Uploading " + bugReport.getTimestamp());
-            BugStorageUtils.setBugReportStatus(this, bugReport, Status.STATUS_UPLOAD_PENDING, "");
-            // Refresh the UI to reflect the new status.
-            new BugReportsLoaderAsyncTask(this).execute();
-        } else if (buttonType == BugInfoAdapter.BUTTON_TYPE_MOVE) {
-            Log.i(TAG, "Moving " + bugReport.getTimestamp());
-            mLastSelectedBugReport = bugReport;
-            mLastSelectedBugInfoViewHolder = holder;
-            startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE),
-                    SELECT_DIRECTORY_REQUEST_CODE);
-        } else if (buttonType == BugInfoAdapter.BUTTON_TYPE_ADD_AUDIO) {
-            // Check mAudioRecordingStarted to prevent double click to BUTTON_TYPE_ADD_AUDIO.
-            if (!mAudioRecordingStarted) {
-                mAudioRecordingStarted = true;
-                startActivityForResult(BugReportActivity.buildAddAudioIntent(this, bugReport),
-                        ADD_AUDIO_MESSAGE_REQUEST_CODE);
-            }
-        } else {
-            throw new IllegalStateException("unreachable");
-        }
-    }
-
-    @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        super.onActivityResult(requestCode, resultCode, data);
-        if (requestCode == SELECT_DIRECTORY_REQUEST_CODE && resultCode == RESULT_OK) {
-            int takeFlags =
-                    data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION
-                            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-            Uri destDirUri = data.getData();
-            getContentResolver().takePersistableUriPermission(destDirUri, takeFlags);
-            if (mLastSelectedBugReport == null || mLastSelectedBugInfoViewHolder == null) {
-                Log.w(TAG, "No bug report is selected.");
-                return;
-            }
-            MetaBugReport updatedBugReport = BugStorageUtils.setBugReportStatus(this,
-                    mLastSelectedBugReport, Status.STATUS_MOVE_IN_PROGRESS, "");
-            mBugInfoAdapter.updateBugReportInDataSet(
-                    updatedBugReport, mLastSelectedBugInfoViewHolder.getAdapterPosition());
-            new AsyncMoveFilesTask(
-                this,
-                    mBugInfoAdapter,
-                    updatedBugReport,
-                    mLastSelectedBugInfoViewHolder,
-                    destDirUri).execute();
-        }
-    }
-
-    private void onQuitButtonClick(View view) {
-        finish();
-    }
-
-    private void onStartBugReportButtonClick(View view) {
-        Intent intent = new Intent(this, BugReportActivity.class);
-        // Clear top is needed, otherwise multiple BugReportActivity-ies get opened and
-        // MediaRecorder crashes.
-        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-        startActivity(intent);
-    }
-
-    /**
-     * Print the Provider's state into the given stream. This gets invoked if
-     * you run "adb shell dumpsys activity BugReportInfoActivity".
-     *
-     * @param prefix Desired prefix to prepend at each line of output.
-     * @param fd The raw file descriptor that the dump is being sent to.
-     * @param writer The PrintWriter to which you should dump your state.  This will be
-     * closed for you after you return.
-     * @param args additional arguments to the dump request.
-     */
-    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
-        super.dump(prefix, fd, writer, args);
-        mConfig.dump(prefix, writer);
-    }
-
-    /**
-     * Moves bugreport zip to USB drive and updates RecyclerView.
-     *
-     * <p>It merges bugreport zip file and audio file into one final zip file and moves it.
-     */
-    private static final class AsyncMoveFilesTask extends AsyncTask<Void, Void, MetaBugReport> {
-        private final BugReportInfoActivity mActivity;
-        private final MetaBugReport mBugReport;
-        private final Uri mDestinationDirUri;
-        /** RecyclerView.Adapter that contains all the bug reports. */
-        private final BugInfoAdapter mBugInfoAdapter;
-        /** ViewHolder for {@link #mBugReport}. */
-        private final BugInfoAdapter.BugInfoViewHolder mBugViewHolder;
-        private final ContentResolver mResolver;
-
-        AsyncMoveFilesTask(BugReportInfoActivity activity, BugInfoAdapter bugInfoAdapter,
-                MetaBugReport bugReport, BugInfoAdapter.BugInfoViewHolder holder,
-                Uri destinationDir) {
-            mActivity = activity;
-            mBugInfoAdapter = bugInfoAdapter;
-            mBugReport = bugReport;
-            mBugViewHolder = holder;
-            mDestinationDirUri = destinationDir;
-            mResolver = mActivity.getContentResolver();
-        }
-
-        /** Moves the bugreport to the USB drive and returns the updated {@link MetaBugReport}. */
-        @Override
-        protected MetaBugReport doInBackground(Void... params) {
-            try {
-                return copyFilesToUsb();
-            } catch (IOException e) {
-                Log.e(TAG, "Failed to copy bugreport "
-                        + mBugReport.getTimestamp() + " to USB", e);
-                return BugStorageUtils.setBugReportStatus(
-                    mActivity, mBugReport,
-                    com.google.android.car.bugreport.Status.STATUS_MOVE_FAILED, e);
-            }
-        }
-
-        private MetaBugReport copyFilesToUsb() throws IOException {
-            String documentId = DocumentsContract.getTreeDocumentId(mDestinationDirUri);
-            Uri parentDocumentUri =
-                    DocumentsContract.buildDocumentUriUsingTree(mDestinationDirUri, documentId);
-            if (!Strings.isNullOrEmpty(mBugReport.getFilePath())) {
-                // There are still old bugreports with deprecated filePath.
-                Uri sourceUri = BugStorageProvider.buildUriWithSegment(
-                        mBugReport.getId(), BugStorageProvider.URL_SEGMENT_OPEN_FILE);
-                copyFileToUsb(
-                        new File(mBugReport.getFilePath()).getName(), sourceUri, parentDocumentUri);
-            } else {
-                mergeFilesAndCopyToUsb(parentDocumentUri);
-            }
-            Log.d(TAG, "Deleting local bug report files.");
-            BugStorageUtils.deleteBugReportFiles(mActivity, mBugReport.getId());
-            return BugStorageUtils.setBugReportStatus(mActivity, mBugReport,
-                    com.google.android.car.bugreport.Status.STATUS_MOVE_SUCCESSFUL,
-                    "Moved to: " + mDestinationDirUri.getPath());
-        }
-
-        private void mergeFilesAndCopyToUsb(Uri parentDocumentUri) throws IOException {
-            Uri sourceBugReport = BugStorageProvider.buildUriWithSegment(
-                    mBugReport.getId(), BugStorageProvider.URL_SEGMENT_OPEN_BUGREPORT_FILE);
-            Uri sourceAudio = BugStorageProvider.buildUriWithSegment(
-                    mBugReport.getId(), BugStorageProvider.URL_SEGMENT_OPEN_AUDIO_FILE);
-            String mimeType = mResolver.getType(sourceBugReport); // It's a zip file.
-            Uri newFileUri = DocumentsContract.createDocument(
-                    mResolver, parentDocumentUri, mimeType, mBugReport.getBugReportFileName());
-            if (newFileUri == null) {
-                throw new IOException(
-                        "Unable to create a file " + mBugReport.getBugReportFileName() + " in USB");
-            }
-            try (InputStream bugReportInput = mResolver.openInputStream(sourceBugReport);
-                 AssetFileDescriptor fd = mResolver.openAssetFileDescriptor(newFileUri, "w");
-                 OutputStream outputStream = fd.createOutputStream();
-                 ZipOutputStream zipOutStream =
-                         new ZipOutputStream(new BufferedOutputStream(outputStream))) {
-                // Extract bugreport zip file to the final zip file in USB drive.
-                ZipInputStream zipInStream = new ZipInputStream(bugReportInput);
-                ZipEntry entry;
-                while ((entry = zipInStream.getNextEntry()) != null) {
-                    ZipUtils.writeInputStreamToZipStream(
-                            entry.getName(), zipInStream, zipOutStream);
-                }
-                // Add audio file to the final zip file.
-                if (!Strings.isNullOrEmpty(mBugReport.getAudioFileName())) {
-                    try (InputStream audioInput = mResolver.openInputStream(sourceAudio)) {
-                        ZipUtils.writeInputStreamToZipStream(
-                                mBugReport.getAudioFileName(), audioInput, zipOutStream);
-                    }
-                }
-            }
-            try (AssetFileDescriptor fd = mResolver.openAssetFileDescriptor(newFileUri, "w")) {
-                // Force sync the written data from memory to the disk.
-                fd.getFileDescriptor().sync();
-            }
-            Log.d(TAG, "Writing to " + newFileUri + " finished");
-        }
-
-        private void copyFileToUsb(String filename, Uri sourceUri, Uri parentDocumentUri)
-                throws IOException {
-            String mimeType = mResolver.getType(sourceUri);
-            Uri newFileUri = DocumentsContract.createDocument(
-                    mResolver, parentDocumentUri, mimeType, filename);
-            if (newFileUri == null) {
-                throw new IOException("Unable to create a file " + filename + " in USB");
-            }
-            try (InputStream input = mResolver.openInputStream(sourceUri);
-                 AssetFileDescriptor fd = mResolver.openAssetFileDescriptor(newFileUri, "w")) {
-                OutputStream output = fd.createOutputStream();
-                ByteStreams.copy(input, output);
-                // Force sync the written data from memory to the disk.
-                fd.getFileDescriptor().sync();
-            }
-        }
-
-        @Override
-        protected void onPostExecute(MetaBugReport updatedBugReport) {
-            // Refresh the UI to reflect the new status.
-            mBugInfoAdapter.updateBugReportInDataSet(
-                    updatedBugReport, mBugViewHolder.getAdapterPosition());
-        }
-    }
-
-    /** Asynchronously loads bugreports from {@link BugStorageProvider}. */
-    private static final class BugReportsLoaderAsyncTask extends
-            AsyncTask<Void, Void, List<MetaBugReport>> {
-        private final WeakReference<BugReportInfoActivity> mBugReportInfoActivityWeakReference;
-
-        BugReportsLoaderAsyncTask(BugReportInfoActivity activity) {
-            mBugReportInfoActivityWeakReference = new WeakReference<>(activity);
-        }
-
-        @Override
-        protected List<MetaBugReport> doInBackground(Void... voids) {
-            BugReportInfoActivity activity = mBugReportInfoActivityWeakReference.get();
-            if (activity == null) {
-                Log.w(TAG, "Activity is gone, cancelling BugReportsLoaderAsyncTask.");
-                return new ArrayList<>();
-            }
-            return BugStorageUtils.getAllBugReportsDescending(activity);
-        }
-
-        @Override
-        protected void onPostExecute(List<MetaBugReport> result) {
-            BugReportInfoActivity activity = mBugReportInfoActivityWeakReference.get();
-            if (activity == null) {
-                Log.w(TAG, "Activity is gone, cancelling onPostExecute.");
-                return;
-            }
-            activity.mBugInfoAdapter.setDataset(result);
-        }
-    }
-
-    /** Observer for {@link BugStorageProvider}. */
-    private static class BugStorageObserver extends ContentObserver {
-        private final BugReportInfoActivity mInfoActivity;
-
-        /**
-         * Creates a content observer.
-         *
-         * @param activity A {@link BugReportInfoActivity} instance.
-         * @param handler The handler to run {@link #onChange} on, or null if none.
-         */
-        BugStorageObserver(BugReportInfoActivity activity, Handler handler) {
-            super(handler);
-            mInfoActivity = activity;
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            new BugReportsLoaderAsyncTask(mInfoActivity).execute();
-        }
-    }
-}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportService.java b/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportService.java
deleted file mode 100644
index 2bebd72..0000000
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportService.java
+++ /dev/null
@@ -1,601 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.android.car.bugreport;
-
-import static android.car.CarBugreportManager.CarBugreportManagerCallback.CAR_BUGREPORT_DUMPSTATE_CONNECTION_FAILED;
-import static android.car.CarBugreportManager.CarBugreportManagerCallback.CAR_BUGREPORT_DUMPSTATE_FAILED;
-import static android.car.CarBugreportManager.CarBugreportManagerCallback.CAR_BUGREPORT_SERVICE_NOT_AVAILABLE;
-
-import static com.google.android.car.bugreport.PackageUtils.getPackageVersion;
-
-import android.annotation.FloatRange;
-import android.annotation.StringRes;
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.car.Car;
-import android.car.CarBugreportManager;
-import android.car.CarNotConnectedException;
-import android.content.Context;
-import android.content.Intent;
-import android.media.AudioManager;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
-import android.widget.Toast;
-
-import com.google.common.base.Preconditions;
-import com.google.common.io.ByteStreams;
-import com.google.common.util.concurrent.AtomicDouble;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.zip.ZipOutputStream;
-
-/**
- * Service that captures screenshot and bug report using dumpstate and bluetooth snoop logs.
- *
- * <p>After collecting all the logs it sets the {@link MetaBugReport} status to
- * {@link Status#STATUS_AUDIO_PENDING} or {@link Status#STATUS_PENDING_USER_ACTION} depending
- * on {@link MetaBugReport#getType}.
- *
- * <p>If the service is started with action {@link #ACTION_START_SILENT}, it will start
- * bugreporting without showing dialog and recording audio message, see
- * {@link MetaBugReport#TYPE_SILENT}.
- */
-public class BugReportService extends Service {
-    private static final String TAG = BugReportService.class.getSimpleName();
-
-    /**
-     * Extra data from intent - current bug report.
-     */
-    static final String EXTRA_META_BUG_REPORT = "meta_bug_report";
-
-    /** Starts silent (no audio message recording) bugreporting. */
-    private static final String ACTION_START_SILENT =
-            "com.google.android.car.bugreport.action.START_SILENT";
-
-    // Wait a short time before starting to capture the bugreport and the screen, so that
-    // bugreport activity can detach from the view tree.
-    // It is ugly to have a timeout, but it is ok here because such a delay should not really
-    // cause bugreport to be tainted with so many other events. If in the future we want to change
-    // this, the best option is probably to wait for onDetach events from view tree.
-    private static final int ACTIVITY_FINISH_DELAY_MILLIS = 1000;
-
-    /** Stop the service only after some delay, to allow toasts to show on the screen. */
-    private static final int STOP_SERVICE_DELAY_MILLIS = 1000;
-
-    /**
-     * Wait a short time before showing "bugreport started" toast message, because the service
-     * will take a screenshot of the screen.
-     */
-    private static final int BUGREPORT_STARTED_TOAST_DELAY_MILLIS = 2000;
-
-    private static final String BT_SNOOP_LOG_LOCATION = "/data/misc/bluetooth/logs/btsnoop_hci.log";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-    /** Notifications on this channel will silently appear in notification bar. */
-    private static final String PROGRESS_CHANNEL_ID = "BUGREPORT_PROGRESS_CHANNEL";
-
-    /** Notifications on this channel will pop-up. */
-    private static final String STATUS_CHANNEL_ID = "BUGREPORT_STATUS_CHANNEL";
-
-    /** Persistent notification is shown when bugreport is in progress or waiting for audio. */
-    private static final int BUGREPORT_IN_PROGRESS_NOTIF_ID = 1;
-
-    /** Dismissible notification is shown when bugreport is collected. */
-    static final int BUGREPORT_FINISHED_NOTIF_ID = 2;
-
-    private static final String OUTPUT_ZIP_FILE = "output_file.zip";
-    private static final String EXTRA_OUTPUT_ZIP_FILE = "extra_output_file.zip";
-
-    private static final String MESSAGE_FAILURE_DUMPSTATE = "Failed to grab dumpstate";
-    private static final String MESSAGE_FAILURE_ZIP = "Failed to zip files";
-
-    private static final int PROGRESS_HANDLER_EVENT_PROGRESS = 1;
-    private static final String PROGRESS_HANDLER_DATA_PROGRESS = "progress";
-
-    static final float MAX_PROGRESS_VALUE = 100f;
-
-    /** Binder given to clients. */
-    private final IBinder mBinder = new ServiceBinder();
-
-    /** True if {@link BugReportService} is already collecting bugreport, including zipping. */
-    private final AtomicBoolean mIsCollectingBugReport = new AtomicBoolean(false);
-    private final AtomicDouble mBugReportProgress = new AtomicDouble(0);
-
-    private MetaBugReport mMetaBugReport;
-    private NotificationManager mNotificationManager;
-    private ScheduledExecutorService mSingleThreadExecutor;
-    private BugReportProgressListener mBugReportProgressListener;
-    private Car mCar;
-    private CarBugreportManager mBugreportManager;
-    private CarBugreportManager.CarBugreportManagerCallback mCallback;
-    private Config mConfig;
-
-    /** A handler on the main thread. */
-    private Handler mHandler;
-    /**
-     * A handler to the main thread to show toast messages, it will be cleared when the service
-     * finishes. We need to clear it otherwise when bugreport fails, it will show "bugreport start"
-     * toast, which will confuse users.
-     */
-    private Handler mHandlerStartedToast;
-
-    /** A listener that's notified when bugreport progress changes. */
-    interface BugReportProgressListener {
-        /**
-         * Called when bug report progress changes.
-         *
-         * @param progress - a bug report progress in [0.0, 100.0].
-         */
-        void onProgress(float progress);
-    }
-
-    /** Client binder. */
-    public class ServiceBinder extends Binder {
-        BugReportService getService() {
-            // Return this instance of LocalService so clients can call public methods
-            return BugReportService.this;
-        }
-    }
-
-    /** A handler on the main thread. */
-    private class BugReportHandler extends Handler {
-        @Override
-        public void handleMessage(Message message) {
-            switch (message.what) {
-                case PROGRESS_HANDLER_EVENT_PROGRESS:
-                    if (mBugReportProgressListener != null) {
-                        float progress = message.getData().getFloat(PROGRESS_HANDLER_DATA_PROGRESS);
-                        mBugReportProgressListener.onProgress(progress);
-                    }
-                    showProgressNotification();
-                    break;
-                default:
-                    Log.d(TAG, "Unknown event " + message.what + ", ignoring.");
-            }
-        }
-    }
-
-    @Override
-    public void onCreate() {
-        Preconditions.checkState(Config.isBugReportEnabled(), "BugReport is disabled.");
-
-        mNotificationManager = getSystemService(NotificationManager.class);
-        mNotificationManager.createNotificationChannel(new NotificationChannel(
-                PROGRESS_CHANNEL_ID,
-                getString(R.string.notification_bugreport_channel_name),
-                NotificationManager.IMPORTANCE_DEFAULT));
-        mNotificationManager.createNotificationChannel(new NotificationChannel(
-                STATUS_CHANNEL_ID,
-                getString(R.string.notification_bugreport_channel_name),
-                NotificationManager.IMPORTANCE_HIGH));
-        mSingleThreadExecutor = Executors.newSingleThreadScheduledExecutor();
-        mHandler = new BugReportHandler();
-        mHandlerStartedToast = new Handler();
-        mConfig = new Config();
-        mConfig.start();
-    }
-
-    @Override
-    public void onDestroy() {
-        if (DEBUG) {
-            Log.d(TAG, "Service destroyed");
-        }
-        disconnectFromCarService();
-    }
-
-    @Override
-    public int onStartCommand(final Intent intent, int flags, int startId) {
-        if (mIsCollectingBugReport.getAndSet(true)) {
-            Log.w(TAG, "bug report is already being collected, ignoring");
-            Toast.makeText(this, R.string.toast_bug_report_in_progress, Toast.LENGTH_SHORT).show();
-            return START_NOT_STICKY;
-        }
-
-        Log.i(TAG, String.format("Will start collecting bug report, version=%s",
-                getPackageVersion(this)));
-
-        if (ACTION_START_SILENT.equals(intent.getAction())) {
-            Log.i(TAG, "Starting a silent bugreport.");
-            mMetaBugReport = BugReportActivity.createBugReport(this, MetaBugReport.TYPE_SILENT);
-        } else {
-            Bundle extras = intent.getExtras();
-            mMetaBugReport = extras.getParcelable(EXTRA_META_BUG_REPORT);
-        }
-
-        mBugReportProgress.set(0);
-
-        startForeground(BUGREPORT_IN_PROGRESS_NOTIF_ID, buildProgressNotification());
-        showProgressNotification();
-
-        collectBugReport();
-
-        // Show a short lived "bugreport started" toast message after a short delay.
-        mHandlerStartedToast.postDelayed(() -> {
-            Toast.makeText(this,
-                    getText(R.string.toast_bug_report_started), Toast.LENGTH_LONG).show();
-        }, BUGREPORT_STARTED_TOAST_DELAY_MILLIS);
-
-        // If the service process gets killed due to heavy memory pressure, do not restart.
-        return START_NOT_STICKY;
-    }
-
-    private void onCarLifecycleChanged(Car car, boolean ready) {
-        // not ready - car service is crashed or is restarting.
-        if (!ready) {
-            mBugreportManager = null;
-            mCar = null;
-
-            // NOTE: dumpstate still might be running, but we can't kill it or reconnect to it
-            //       so we ignore it.
-            handleBugReportManagerError(CAR_BUGREPORT_SERVICE_NOT_AVAILABLE);
-            return;
-        }
-        try {
-            mBugreportManager = (CarBugreportManager) car.getCarManager(Car.CAR_BUGREPORT_SERVICE);
-        } catch (CarNotConnectedException | NoClassDefFoundError e) {
-            throw new IllegalStateException("Failed to get CarBugreportManager.", e);
-        }
-    }
-
-    /** Shows an updated progress notification. */
-    private void showProgressNotification() {
-        if (isCollectingBugReport()) {
-            mNotificationManager.notify(
-                    BUGREPORT_IN_PROGRESS_NOTIF_ID, buildProgressNotification());
-        }
-    }
-
-    private Notification buildProgressNotification() {
-        Intent intent = new Intent(getApplicationContext(), BugReportInfoActivity.class);
-        PendingIntent startBugReportInfoActivity =
-                PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);
-        return new Notification.Builder(this, PROGRESS_CHANNEL_ID)
-                .setContentTitle(getText(R.string.notification_bugreport_in_progress))
-                .setContentText(mMetaBugReport.getTitle())
-                .setSubText(String.format("%.1f%%", mBugReportProgress.get()))
-                .setSmallIcon(R.drawable.download_animation)
-                .setCategory(Notification.CATEGORY_STATUS)
-                .setOngoing(true)
-                .setProgress((int) MAX_PROGRESS_VALUE, (int) mBugReportProgress.get(), false)
-                .setContentIntent(startBugReportInfoActivity)
-                .build();
-    }
-
-    /** Returns true if bugreporting is in progress. */
-    public boolean isCollectingBugReport() {
-        return mIsCollectingBugReport.get();
-    }
-
-    /** Returns current bugreport progress. */
-    public float getBugReportProgress() {
-        return (float) mBugReportProgress.get();
-    }
-
-    /** Sets a bugreport progress listener. The listener is called on a main thread. */
-    public void setBugReportProgressListener(BugReportProgressListener listener) {
-        mBugReportProgressListener = listener;
-    }
-
-    /** Removes the bugreport progress listener. */
-    public void removeBugReportProgressListener() {
-        mBugReportProgressListener = null;
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return mBinder;
-    }
-
-    private void showToast(@StringRes int resId) {
-        // run on ui thread.
-        mHandler.post(() -> Toast.makeText(this, getText(resId), Toast.LENGTH_LONG).show());
-    }
-
-    private void disconnectFromCarService() {
-        if (mCar != null) {
-            mCar.disconnect();
-            mCar = null;
-        }
-        mBugreportManager = null;
-    }
-
-    private void connectToCarServiceSync() {
-        if (mCar == null || !(mCar.isConnected() || mCar.isConnecting())) {
-            mCar = Car.createCar(this, /* handler= */ null,
-                    Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, this::onCarLifecycleChanged);
-        }
-    }
-
-    private void collectBugReport() {
-        // Connect to the car service before collecting bugreport, because when car service crashes,
-        // BugReportService doesn't automatically reconnect to it.
-        connectToCarServiceSync();
-
-        if (Build.IS_USERDEBUG || Build.IS_ENG) {
-            mSingleThreadExecutor.schedule(
-                    this::grabBtSnoopLog, ACTIVITY_FINISH_DELAY_MILLIS, TimeUnit.MILLISECONDS);
-        }
-        mSingleThreadExecutor.schedule(
-                this::saveBugReport, ACTIVITY_FINISH_DELAY_MILLIS, TimeUnit.MILLISECONDS);
-    }
-
-    private void grabBtSnoopLog() {
-        Log.i(TAG, "Grabbing bt snoop log");
-        File result = FileUtils.getFileWithSuffix(this, mMetaBugReport.getTimestamp(),
-                "-btsnoop.bin.log");
-        File snoopFile = new File(BT_SNOOP_LOG_LOCATION);
-        if (!snoopFile.exists()) {
-            Log.w(TAG, BT_SNOOP_LOG_LOCATION + " not found, skipping");
-            return;
-        }
-        try (FileInputStream input = new FileInputStream(snoopFile);
-             FileOutputStream output = new FileOutputStream(result)) {
-            ByteStreams.copy(input, output);
-        } catch (IOException e) {
-            // this regularly happens when snooplog is not enabled so do not log as an error
-            Log.i(TAG, "Failed to grab bt snooplog, continuing to take bug report.", e);
-        }
-    }
-
-    private void saveBugReport() {
-        Log.i(TAG, "Dumpstate to file");
-        File outputFile = FileUtils.getFile(this, mMetaBugReport.getTimestamp(), OUTPUT_ZIP_FILE);
-        File extraOutputFile = FileUtils.getFile(this, mMetaBugReport.getTimestamp(),
-                EXTRA_OUTPUT_ZIP_FILE);
-        try (ParcelFileDescriptor outFd = ParcelFileDescriptor.open(outputFile,
-                ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_READ_WRITE);
-             ParcelFileDescriptor extraOutFd = ParcelFileDescriptor.open(extraOutputFile,
-                ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_READ_WRITE)) {
-            requestBugReport(outFd, extraOutFd);
-        } catch (IOException | RuntimeException e) {
-            Log.e(TAG, "Failed to grab dump state", e);
-            BugStorageUtils.setBugReportStatus(this, mMetaBugReport, Status.STATUS_WRITE_FAILED,
-                    MESSAGE_FAILURE_DUMPSTATE);
-            showToast(R.string.toast_status_dump_state_failed);
-            disconnectFromCarService();
-            mIsCollectingBugReport.set(false);
-        }
-    }
-
-    private void sendProgressEventToHandler(float progress) {
-        Message message = new Message();
-        message.what = PROGRESS_HANDLER_EVENT_PROGRESS;
-        message.getData().putFloat(PROGRESS_HANDLER_DATA_PROGRESS, progress);
-        mHandler.sendMessage(message);
-    }
-
-    private void requestBugReport(ParcelFileDescriptor outFd, ParcelFileDescriptor extraOutFd) {
-        if (DEBUG) {
-            Log.d(TAG, "Requesting a bug report from CarBugReportManager.");
-        }
-        mCallback = new CarBugreportManager.CarBugreportManagerCallback() {
-            @Override
-            public void onError(@CarBugreportErrorCode int errorCode) {
-                Log.e(TAG, "CarBugreportManager failed: " + errorCode);
-                disconnectFromCarService();
-                handleBugReportManagerError(errorCode);
-            }
-
-            @Override
-            public void onProgress(@FloatRange(from = 0f, to = MAX_PROGRESS_VALUE) float progress) {
-                mBugReportProgress.set(progress);
-                sendProgressEventToHandler(progress);
-            }
-
-            @Override
-            public void onFinished() {
-                Log.d(TAG, "CarBugreportManager finished");
-                disconnectFromCarService();
-                mBugReportProgress.set(MAX_PROGRESS_VALUE);
-                sendProgressEventToHandler(MAX_PROGRESS_VALUE);
-                mSingleThreadExecutor.submit(BugReportService.this::zipDirectoryAndUpdateStatus);
-            }
-        };
-        if (mBugreportManager == null) {
-            mHandler.post(() -> Toast.makeText(this,
-                    "Car service is not ready", Toast.LENGTH_LONG).show());
-            Log.e(TAG, "CarBugReportManager is not ready");
-            return;
-        }
-        mBugreportManager.requestBugreport(outFd, extraOutFd, mCallback);
-    }
-
-    private void handleBugReportManagerError(
-            @CarBugreportManager.CarBugreportManagerCallback.CarBugreportErrorCode int errorCode) {
-        if (mMetaBugReport == null) {
-            Log.w(TAG, "No bugreport is running");
-            mIsCollectingBugReport.set(false);
-            return;
-        }
-        // We let the UI know that bug reporting is finished, because the next step is to
-        // zip everything and upload.
-        mBugReportProgress.set(MAX_PROGRESS_VALUE);
-        sendProgressEventToHandler(MAX_PROGRESS_VALUE);
-        showToast(R.string.toast_status_failed);
-        BugStorageUtils.setBugReportStatus(
-                BugReportService.this, mMetaBugReport,
-                Status.STATUS_WRITE_FAILED, getBugReportFailureStatusMessage(errorCode));
-        mHandler.postDelayed(() -> {
-            mNotificationManager.cancel(BUGREPORT_IN_PROGRESS_NOTIF_ID);
-            stopForeground(true);
-        }, STOP_SERVICE_DELAY_MILLIS);
-        mHandlerStartedToast.removeCallbacksAndMessages(null);
-        mMetaBugReport = null;
-        mIsCollectingBugReport.set(false);
-    }
-
-    private static String getBugReportFailureStatusMessage(
-            @CarBugreportManager.CarBugreportManagerCallback.CarBugreportErrorCode int errorCode) {
-        switch (errorCode) {
-            case CAR_BUGREPORT_DUMPSTATE_CONNECTION_FAILED:
-            case CAR_BUGREPORT_DUMPSTATE_FAILED:
-                return "Failed to connect to dumpstate. Retry again after a minute.";
-            case CAR_BUGREPORT_SERVICE_NOT_AVAILABLE:
-                return "Car service is not available. Retry again.";
-            default:
-                return "Car service bugreport collection failed: " + errorCode;
-        }
-    }
-
-    /**
-     * Shows a clickable bugreport finished notification. When clicked it opens
-     * {@link BugReportInfoActivity}.
-     */
-    static void showBugReportFinishedNotification(Context context, MetaBugReport bug) {
-        Intent intent = new Intent(context, BugReportInfoActivity.class);
-        PendingIntent startBugReportInfoActivity =
-                PendingIntent.getActivity(context, 0, intent, 0);
-        Notification notification = new Notification
-                .Builder(context, STATUS_CHANNEL_ID)
-                .setContentTitle(context.getText(R.string.notification_bugreport_finished_title))
-                .setContentText(bug.getTitle())
-                .setCategory(Notification.CATEGORY_STATUS)
-                .setSmallIcon(R.drawable.ic_upload)
-                .setContentIntent(startBugReportInfoActivity)
-                .build();
-        context.getSystemService(NotificationManager.class)
-                .notify(BUGREPORT_FINISHED_NOTIF_ID, notification);
-    }
-
-    /**
-     * Zips the temp directory, writes to the system user's {@link FileUtils#getPendingDir} and
-     * updates the bug report status.
-     *
-     * <p>For {@link MetaBugReport#TYPE_INTERACTIVE}: Sets status to either STATUS_UPLOAD_PENDING or
-     * STATUS_PENDING_USER_ACTION and shows a regular notification.
-     *
-     * <p>For {@link MetaBugReport#TYPE_SILENT}: Sets status to STATUS_AUDIO_PENDING and shows
-     * a dialog to record audio message.
-     */
-    private void zipDirectoryAndUpdateStatus() {
-        try {
-            // All the generated zip files, images and audio messages are located in this dir.
-            // This is located under the current user.
-            String bugreportFileName = FileUtils.getZipFileName(mMetaBugReport);
-            Log.d(TAG, "Zipping bugreport into " + bugreportFileName);
-            mMetaBugReport = BugStorageUtils.update(this,
-                    mMetaBugReport.toBuilder().setBugReportFileName(bugreportFileName).build());
-            File bugReportTempDir = FileUtils.createTempDir(this, mMetaBugReport.getTimestamp());
-            zipDirectoryToOutputStream(bugReportTempDir,
-                    BugStorageUtils.openBugReportFileToWrite(this, mMetaBugReport));
-        } catch (IOException e) {
-            Log.e(TAG, "Failed to zip files", e);
-            BugStorageUtils.setBugReportStatus(this, mMetaBugReport, Status.STATUS_WRITE_FAILED,
-                    MESSAGE_FAILURE_ZIP);
-            showToast(R.string.toast_status_failed);
-            return;
-        }
-        if (mMetaBugReport.getType() == MetaBugReport.TYPE_SILENT) {
-            BugStorageUtils.setBugReportStatus(BugReportService.this,
-                    mMetaBugReport, Status.STATUS_AUDIO_PENDING, /* message= */ "");
-            playNotificationSound();
-            startActivity(BugReportActivity.buildAddAudioIntent(this, mMetaBugReport));
-        } else {
-            // NOTE: If bugreport type is INTERACTIVE, it will already contain an audio message.
-            Status status = mConfig.getAutoUpload()
-                    ? Status.STATUS_UPLOAD_PENDING : Status.STATUS_PENDING_USER_ACTION;
-            BugStorageUtils.setBugReportStatus(BugReportService.this,
-                    mMetaBugReport, status, /* message= */ "");
-            showBugReportFinishedNotification(this, mMetaBugReport);
-        }
-        mHandler.post(() -> {
-            mNotificationManager.cancel(BUGREPORT_IN_PROGRESS_NOTIF_ID);
-            stopForeground(true);
-        });
-        mHandlerStartedToast.removeCallbacksAndMessages(null);
-        mMetaBugReport = null;
-        mIsCollectingBugReport.set(false);
-    }
-
-    private void playNotificationSound() {
-        Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
-        Ringtone ringtone = RingtoneManager.getRingtone(getApplicationContext(), notification);
-        if (ringtone == null) {
-            Log.w(TAG, "No notification ringtone found.");
-            return;
-        }
-        float volume = ringtone.getVolume();
-        // Use volume from audio manager, otherwise default ringtone volume can be too loud.
-        AudioManager audioManager = getSystemService(AudioManager.class);
-        if (audioManager != null) {
-            int currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_NOTIFICATION);
-            int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_NOTIFICATION);
-            volume = (currentVolume + 0.0f) / maxVolume;
-        }
-        Log.v(TAG, "Using volume " + volume);
-        ringtone.setVolume(volume);
-        ringtone.play();
-    }
-
-    /**
-     * Compresses a directory into a zip file. The method is not recursive. Any sub-directory
-     * contained in the main directory and any files contained in the sub-directories will be
-     * skipped.
-     *
-     * @param dirToZip  The path of the directory to zip
-     * @param outStream The output stream to write the zip file to
-     * @throws IOException if the directory does not exist, its files cannot be read, or the output
-     *                     zip file cannot be written.
-     */
-    private void zipDirectoryToOutputStream(File dirToZip, OutputStream outStream)
-            throws IOException {
-        if (!dirToZip.isDirectory()) {
-            throw new IOException("zip directory does not exist");
-        }
-        Log.v(TAG, "zipping directory " + dirToZip.getAbsolutePath());
-
-        File[] listFiles = dirToZip.listFiles();
-        try (ZipOutputStream zipStream = new ZipOutputStream(new BufferedOutputStream(outStream))) {
-            for (File file : listFiles) {
-                if (file.isDirectory()) {
-                    continue;
-                }
-                String filename = file.getName();
-                // 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)) {
-                    ZipUtils.extractZippedFileToZipStream(file, zipStream);
-                } else {
-                    ZipUtils.addFileToZipStream(file, zipStream);
-                }
-            }
-        } finally {
-            outStream.close();
-        }
-        // Zipping successful, now cleanup the temp dir.
-        FileUtils.deleteDirectory(dirToZip);
-    }
-}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/BugStorageProvider.java b/tests/BugReportApp/src/com/google/android/car/bugreport/BugStorageProvider.java
deleted file mode 100644
index d9e271e..0000000
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/BugStorageProvider.java
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.android.car.bugreport;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.StringDef;
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.UriMatcher;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.net.Uri;
-import android.os.CancellationSignal;
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileNotFoundException;
-import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.function.Function;
-
-
-/**
- * Provides a bug storage interface to save and upload bugreports filed from all users.
- * In Android Automotive user 0 runs as the system and all the time, while other users won't once
- * their session ends. This content provider enables bug reports to be uploaded even after
- * user session ends.
- *
- * <p>A bugreport constists of two files: bugreport zip file and audio file. Audio file is added
- * later through notification. {@link SimpleUploaderAsyncTask} merges two files into one zip file
- * before uploading.
- *
- * <p>All files are stored under system user's {@link FileUtils#getPendingDir}.
- */
-public class BugStorageProvider extends ContentProvider {
-    private static final String TAG = BugStorageProvider.class.getSimpleName();
-
-    private static final String AUTHORITY = "com.google.android.car.bugreport";
-    private static final String BUG_REPORTS_TABLE = "bugreports";
-
-    /** Deletes files associated with a bug report. */
-    static final String URL_SEGMENT_DELETE_FILES = "deleteZipFile";
-    /** Destructively deletes a bug report. */
-    static final String URL_SEGMENT_COMPLETE_DELETE = "completeDelete";
-    /** Opens bugreport file of a bug report, uses column {@link #COLUMN_BUGREPORT_FILENAME}. */
-    static final String URL_SEGMENT_OPEN_BUGREPORT_FILE = "openBugReportFile";
-    /** Opens audio file of a bug report, uses column {@link #URL_MATCHED_OPEN_AUDIO_FILE}. */
-    static final String URL_SEGMENT_OPEN_AUDIO_FILE = "openAudioFile";
-    /**
-     * Opens final bugreport zip file, uses column {@link #COLUMN_FILEPATH}.
-     *
-     * <p>NOTE: This is the old way of storing final zipped bugreport. In
-     * {@code BugStorageProvider#AUDIO_VERSION} {@link #COLUMN_FILEPATH} is dropped. But there are
-     * still some devices with this field set.
-     */
-    static final String URL_SEGMENT_OPEN_FILE = "openFile";
-
-    // URL Matcher IDs.
-    private static final int URL_MATCHED_BUG_REPORTS_URI = 1;
-    private static final int URL_MATCHED_BUG_REPORT_ID_URI = 2;
-    private static final int URL_MATCHED_DELETE_FILES = 3;
-    private static final int URL_MATCHED_COMPLETE_DELETE = 4;
-    private static final int URL_MATCHED_OPEN_BUGREPORT_FILE = 5;
-    private static final int URL_MATCHED_OPEN_AUDIO_FILE = 6;
-    private static final int URL_MATCHED_OPEN_FILE = 7;
-
-    @StringDef({
-            URL_SEGMENT_DELETE_FILES,
-            URL_SEGMENT_COMPLETE_DELETE,
-            URL_SEGMENT_OPEN_BUGREPORT_FILE,
-            URL_SEGMENT_OPEN_AUDIO_FILE,
-            URL_SEGMENT_OPEN_FILE,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    @interface UriActionSegments {}
-
-    static final Uri BUGREPORT_CONTENT_URI =
-            Uri.parse("content://" + AUTHORITY + "/" + BUG_REPORTS_TABLE);
-
-    /** See {@link MetaBugReport} for column descriptions. */
-    static final String COLUMN_ID = "_ID";
-    static final String COLUMN_USERNAME = "username";
-    static final String COLUMN_TITLE = "title";
-    static final String COLUMN_TIMESTAMP = "timestamp";
-    /** not used anymore */
-    static final String COLUMN_DESCRIPTION = "description";
-    /** not used anymore, but some devices still might have bugreports with this field set. */
-    static final String COLUMN_FILEPATH = "filepath";
-    static final String COLUMN_STATUS = "status";
-    static final String COLUMN_STATUS_MESSAGE = "message";
-    static final String COLUMN_TYPE = "type";
-    static final String COLUMN_BUGREPORT_FILENAME = "bugreport_filename";
-    static final String COLUMN_AUDIO_FILENAME = "audio_filename";
-
-    private DatabaseHelper mDatabaseHelper;
-    private final UriMatcher mUriMatcher;
-    private Config mConfig;
-
-    /**
-     * A helper class to work with sqlite database.
-     */
-    private static class DatabaseHelper extends SQLiteOpenHelper {
-        private static final String TAG = DatabaseHelper.class.getSimpleName();
-
-        private static final String DATABASE_NAME = "bugreport.db";
-
-        /**
-         * All changes in database versions should be recorded here.
-         * 1: Initial version.
-         * 2: Add integer column details_needed.
-         * 3: Add string column audio_filename and bugreport_filename.
-         */
-        private static final int INITIAL_VERSION = 1;
-        private static final int TYPE_VERSION = 2;
-        private static final int AUDIO_VERSION = 3;
-        private static final int DATABASE_VERSION = AUDIO_VERSION;
-
-        private static final String CREATE_TABLE = "CREATE TABLE " + BUG_REPORTS_TABLE + " ("
-                + COLUMN_ID + " INTEGER PRIMARY KEY,"
-                + COLUMN_USERNAME + " TEXT,"
-                + COLUMN_TITLE + " TEXT,"
-                + COLUMN_TIMESTAMP + " TEXT NOT NULL,"
-                + COLUMN_DESCRIPTION + " TEXT NULL,"
-                + COLUMN_FILEPATH + " TEXT DEFAULT NULL,"
-                + COLUMN_STATUS + " INTEGER DEFAULT " + Status.STATUS_WRITE_PENDING.getValue() + ","
-                + COLUMN_STATUS_MESSAGE + " TEXT NULL,"
-                + COLUMN_TYPE + " INTEGER DEFAULT " + MetaBugReport.TYPE_INTERACTIVE + ","
-                + COLUMN_BUGREPORT_FILENAME + " TEXT DEFAULT NULL,"
-                + COLUMN_AUDIO_FILENAME + " TEXT DEFAULT NULL"
-                + ");";
-
-        DatabaseHelper(Context context) {
-            super(context, DATABASE_NAME, null, DATABASE_VERSION);
-        }
-
-        @Override
-        public void onCreate(SQLiteDatabase db) {
-            db.execSQL(CREATE_TABLE);
-        }
-
-        @Override
-        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-            Log.w(TAG, "Upgrading from " + oldVersion + " to " + newVersion);
-            if (oldVersion < TYPE_VERSION) {
-                db.execSQL("ALTER TABLE " + BUG_REPORTS_TABLE + " ADD COLUMN "
-                        + COLUMN_TYPE + " INTEGER DEFAULT " + MetaBugReport.TYPE_INTERACTIVE);
-            }
-            if (oldVersion < AUDIO_VERSION) {
-                db.execSQL("ALTER TABLE " + BUG_REPORTS_TABLE + " ADD COLUMN "
-                        + COLUMN_BUGREPORT_FILENAME + " TEXT DEFAULT NULL");
-                db.execSQL("ALTER TABLE " + BUG_REPORTS_TABLE + " ADD COLUMN "
-                        + COLUMN_AUDIO_FILENAME + " TEXT DEFAULT NULL");
-            }
-        }
-    }
-
-    /**
-     * Builds an {@link Uri} that points to the single bug report and performs an action
-     * defined by given URI segment.
-     */
-    static Uri buildUriWithSegment(int bugReportId, @UriActionSegments String segment) {
-        return Uri.parse("content://" + AUTHORITY + "/" + BUG_REPORTS_TABLE + "/"
-                + segment + "/" + bugReportId);
-    }
-
-    public BugStorageProvider() {
-        mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
-        mUriMatcher.addURI(AUTHORITY, BUG_REPORTS_TABLE, URL_MATCHED_BUG_REPORTS_URI);
-        mUriMatcher.addURI(AUTHORITY, BUG_REPORTS_TABLE + "/#", URL_MATCHED_BUG_REPORT_ID_URI);
-        mUriMatcher.addURI(
-                AUTHORITY, BUG_REPORTS_TABLE + "/" + URL_SEGMENT_DELETE_FILES + "/#",
-                URL_MATCHED_DELETE_FILES);
-        mUriMatcher.addURI(
-                AUTHORITY, BUG_REPORTS_TABLE + "/" + URL_SEGMENT_COMPLETE_DELETE + "/#",
-                URL_MATCHED_COMPLETE_DELETE);
-        mUriMatcher.addURI(
-                AUTHORITY, BUG_REPORTS_TABLE + "/" + URL_SEGMENT_OPEN_BUGREPORT_FILE + "/#",
-                URL_MATCHED_OPEN_BUGREPORT_FILE);
-        mUriMatcher.addURI(
-                AUTHORITY, BUG_REPORTS_TABLE + "/" + URL_SEGMENT_OPEN_AUDIO_FILE + "/#",
-                URL_MATCHED_OPEN_AUDIO_FILE);
-        mUriMatcher.addURI(
-                AUTHORITY, BUG_REPORTS_TABLE + "/" + URL_SEGMENT_OPEN_FILE + "/#",
-                URL_MATCHED_OPEN_FILE);
-    }
-
-    @Override
-    public boolean onCreate() {
-        Preconditions.checkState(Config.isBugReportEnabled(), "BugReport is disabled.");
-
-        mDatabaseHelper = new DatabaseHelper(getContext());
-        mConfig = new Config();
-        mConfig.start();
-        return true;
-    }
-
-    @Override
-    public Cursor query(
-            @NonNull Uri uri,
-            @Nullable String[] projection,
-            @Nullable String selection,
-            @Nullable String[] selectionArgs,
-            @Nullable String sortOrder) {
-        return query(uri, projection, selection, selectionArgs, sortOrder, null);
-    }
-
-    @Nullable
-    @Override
-    public Cursor query(
-            @NonNull Uri uri,
-            @Nullable String[] projection,
-            @Nullable String selection,
-            @Nullable String[] selectionArgs,
-            @Nullable String sortOrder,
-            @Nullable CancellationSignal cancellationSignal) {
-        String table;
-        switch (mUriMatcher.match(uri)) {
-            // returns the list of bugreports that match the selection criteria.
-            case URL_MATCHED_BUG_REPORTS_URI:
-                table = BUG_REPORTS_TABLE;
-                break;
-            //  returns the bugreport that match the id.
-            case URL_MATCHED_BUG_REPORT_ID_URI:
-                table = BUG_REPORTS_TABLE;
-                if (selection != null || selectionArgs != null) {
-                    throw new IllegalArgumentException("selection is not allowed for "
-                            + URL_MATCHED_BUG_REPORT_ID_URI);
-                }
-                selection = COLUMN_ID + "=?";
-                selectionArgs = new String[]{ uri.getLastPathSegment() };
-                break;
-            default:
-                throw new IllegalArgumentException("Unknown URL " + uri);
-        }
-        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
-        Cursor cursor = db.query(false, table, null, selection, selectionArgs, null, null,
-                sortOrder, null, cancellationSignal);
-        cursor.setNotificationUri(getContext().getContentResolver(), uri);
-        return cursor;
-    }
-
-    @Nullable
-    @Override
-    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
-        String table;
-        if (values == null) {
-            throw new IllegalArgumentException("values cannot be null");
-        }
-        switch (mUriMatcher.match(uri)) {
-            case URL_MATCHED_BUG_REPORTS_URI:
-                table = BUG_REPORTS_TABLE;
-                break;
-            default:
-                throw new IllegalArgumentException("unknown uri" + uri);
-        }
-        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
-        long rowId = db.insert(table, null, values);
-        if (rowId > 0) {
-            Uri resultUri = Uri.parse("content://" + AUTHORITY + "/" + table + "/" + rowId);
-            // notify registered content observers
-            getContext().getContentResolver().notifyChange(resultUri, null);
-            return resultUri;
-        }
-        return null;
-    }
-
-    @Nullable
-    @Override
-    public String getType(@NonNull Uri uri) {
-        switch (mUriMatcher.match(uri)) {
-            case URL_MATCHED_OPEN_BUGREPORT_FILE:
-            case URL_MATCHED_OPEN_FILE:
-                return "application/zip";
-            case URL_MATCHED_OPEN_AUDIO_FILE:
-                return "audio/3gpp";
-            default:
-                throw new IllegalArgumentException("unknown uri:" + uri);
-        }
-    }
-
-    @Override
-    public int delete(
-            @NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
-        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
-        switch (mUriMatcher.match(uri)) {
-            case URL_MATCHED_DELETE_FILES:
-                if (selection != null || selectionArgs != null) {
-                    throw new IllegalArgumentException("selection is not allowed for "
-                            + URL_MATCHED_DELETE_FILES);
-                }
-                if (deleteFilesFor(getBugReportFromUri(uri))) {
-                    getContext().getContentResolver().notifyChange(uri, null);
-                    return 1;
-                }
-                return 0;
-            case URL_MATCHED_COMPLETE_DELETE:
-                if (selection != null || selectionArgs != null) {
-                    throw new IllegalArgumentException("selection is not allowed for "
-                            + URL_MATCHED_COMPLETE_DELETE);
-                }
-                selection = COLUMN_ID + " = ?";
-                selectionArgs = new String[]{uri.getLastPathSegment()};
-                // Ignore the results of zip file deletion, possibly it wasn't even created.
-                deleteFilesFor(getBugReportFromUri(uri));
-                getContext().getContentResolver().notifyChange(uri, null);
-                return db.delete(BUG_REPORTS_TABLE, selection, selectionArgs);
-            default:
-                throw new IllegalArgumentException("Unknown URL " + uri);
-        }
-    }
-
-    @Override
-    public int update(
-            @NonNull Uri uri,
-            @Nullable ContentValues values,
-            @Nullable String selection,
-            @Nullable String[] selectionArgs) {
-        if (values == null) {
-            throw new IllegalArgumentException("values cannot be null");
-        }
-        String table;
-        switch (mUriMatcher.match(uri)) {
-            case URL_MATCHED_BUG_REPORTS_URI:
-                table = BUG_REPORTS_TABLE;
-                break;
-            default:
-                throw new IllegalArgumentException("Unknown URL " + uri);
-        }
-        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
-        int rowCount = db.update(table, values, selection, selectionArgs);
-        if (rowCount > 0) {
-            // notify registered content observers
-            getContext().getContentResolver().notifyChange(uri, null);
-        }
-        Integer status = values.getAsInteger(COLUMN_STATUS);
-        // When the status is set to STATUS_UPLOAD_PENDING, we schedule an UploadJob under the
-        // current user, which is the primary user.
-        if (status != null && status.equals(Status.STATUS_UPLOAD_PENDING.getValue())) {
-            JobSchedulingUtils.scheduleUploadJob(BugStorageProvider.this.getContext());
-        }
-        return rowCount;
-    }
-
-    /**
-     * This is called when a file is opened.
-     *
-     * <p>See {@link BugStorageUtils#openBugReportFileToWrite},
-     * {@link BugStorageUtils#openAudioMessageFileToWrite}.
-     */
-    @Nullable
-    @Override
-    public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode)
-            throws FileNotFoundException {
-        Function<MetaBugReport, String> fileNameExtractor;
-        switch (mUriMatcher.match(uri)) {
-            case URL_MATCHED_OPEN_BUGREPORT_FILE:
-                fileNameExtractor = MetaBugReport::getBugReportFileName;
-                break;
-            case URL_MATCHED_OPEN_AUDIO_FILE:
-                fileNameExtractor = MetaBugReport::getAudioFileName;
-                break;
-            case URL_MATCHED_OPEN_FILE:
-                File file = new File(getBugReportFromUri(uri).getFilePath());
-                Log.v(TAG, "Opening file " + file + " with mode " + mode);
-                return ParcelFileDescriptor.open(file, ParcelFileDescriptor.parseMode(mode));
-            default:
-                throw new IllegalArgumentException("unknown uri:" + uri);
-        }
-        // URI contains bugreport ID as the last segment, see the matched urls.
-        MetaBugReport bugReport = getBugReportFromUri(uri);
-        File file = new File(
-                FileUtils.getPendingDir(getContext()), fileNameExtractor.apply(bugReport));
-        Log.v(TAG, "Opening file " + file + " with mode " + mode);
-        int modeBits = ParcelFileDescriptor.parseMode(mode);
-        return ParcelFileDescriptor.open(file, modeBits);
-    }
-
-    private MetaBugReport getBugReportFromUri(@NonNull Uri uri) {
-        int bugreportId = Integer.parseInt(uri.getLastPathSegment());
-        return BugStorageUtils.findBugReport(getContext(), bugreportId)
-                .orElseThrow(() -> new IllegalArgumentException("No record found for " + uri));
-    }
-
-    /**
-     * Print the Provider's state into the given stream. This gets invoked if
-     * you run "dumpsys activity provider com.google.android.car.bugreport/.BugStorageProvider".
-     *
-     * @param fd The raw file descriptor that the dump is being sent to.
-     * @param writer The PrintWriter to which you should dump your state.  This will be
-     * closed for you after you return.
-     * @param args additional arguments to the dump request.
-     */
-    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
-        writer.println("BugStorageProvider:");
-        mConfig.dump(/* prefix= */ "  ", writer);
-    }
-
-    private boolean deleteFilesFor(MetaBugReport bugReport) {
-        if (!Strings.isNullOrEmpty(bugReport.getFilePath())) {
-            // Old bugreports have only filePath.
-            return new File(bugReport.getFilePath()).delete();
-        }
-        File pendingDir = FileUtils.getPendingDir(getContext());
-        boolean result = true;
-        if (!Strings.isNullOrEmpty(bugReport.getAudioFileName())) {
-            result = new File(pendingDir, bugReport.getAudioFileName()).delete();
-        }
-        if (!Strings.isNullOrEmpty(bugReport.getBugReportFileName())) {
-            result = result && new File(pendingDir, bugReport.getBugReportFileName()).delete();
-        }
-        return result;
-    }
-}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/BugStorageUtils.java b/tests/BugReportApp/src/com/google/android/car/bugreport/BugStorageUtils.java
deleted file mode 100644
index a009129..0000000
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/BugStorageUtils.java
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.android.car.bugreport;
-
-import static com.google.android.car.bugreport.BugStorageProvider.COLUMN_AUDIO_FILENAME;
-import static com.google.android.car.bugreport.BugStorageProvider.COLUMN_BUGREPORT_FILENAME;
-import static com.google.android.car.bugreport.BugStorageProvider.COLUMN_FILEPATH;
-import static com.google.android.car.bugreport.BugStorageProvider.COLUMN_ID;
-import static com.google.android.car.bugreport.BugStorageProvider.COLUMN_STATUS;
-import static com.google.android.car.bugreport.BugStorageProvider.COLUMN_STATUS_MESSAGE;
-import static com.google.android.car.bugreport.BugStorageProvider.COLUMN_TIMESTAMP;
-import static com.google.android.car.bugreport.BugStorageProvider.COLUMN_TITLE;
-import static com.google.android.car.bugreport.BugStorageProvider.COLUMN_TYPE;
-import static com.google.android.car.bugreport.BugStorageProvider.COLUMN_USERNAME;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.util.Log;
-
-import com.google.api.client.auth.oauth2.TokenResponseException;
-import com.google.common.base.Strings;
-
-import java.io.FileNotFoundException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Optional;
-
-/**
- * A class that hides details when communicating with the bug storage provider.
- */
-final class BugStorageUtils {
-    private static final String TAG = BugStorageUtils.class.getSimpleName();
-
-    /**
-     * When time/time-zone set incorrectly, Google API returns "400: invalid_grant" error with
-     * description containing this text.
-     */
-    private static final String CLOCK_SKEW_ERROR = "clock with skew to account";
-
-    /** When time/time-zone set incorrectly, Google API returns this error. */
-    private static final String INVALID_GRANT = "invalid_grant";
-
-    private static final DateFormat TIMESTAMP_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
-
-    /**
-     * Creates a new {@link Status#STATUS_WRITE_PENDING} bug report record in a local sqlite
-     * database.
-     *
-     * @param context   - an application context.
-     * @param title     - title of the bug report.
-     * @param timestamp - timestamp when the bug report was initiated.
-     * @param username  - current user name. Note, it's a user name, not an account name.
-     * @param type      - bug report type, {@link MetaBugReport.BugReportType}.
-     * @return an instance of {@link MetaBugReport} that was created in a database.
-     */
-    @NonNull
-    static MetaBugReport createBugReport(
-            @NonNull Context context,
-            @NonNull String title,
-            @NonNull String timestamp,
-            @NonNull String username,
-            @MetaBugReport.BugReportType int type) {
-        // insert bug report username and title
-        ContentValues values = new ContentValues();
-        values.put(COLUMN_TITLE, title);
-        values.put(COLUMN_TIMESTAMP, timestamp);
-        values.put(COLUMN_USERNAME, username);
-        values.put(COLUMN_TYPE, type);
-
-        ContentResolver r = context.getContentResolver();
-        Uri uri = r.insert(BugStorageProvider.BUGREPORT_CONTENT_URI, values);
-        return findBugReport(context, Integer.parseInt(uri.getLastPathSegment())).get();
-    }
-
-    /** Returns an output stream to write the zipped file to. */
-    @NonNull
-    static OutputStream openBugReportFileToWrite(
-            @NonNull Context context, @NonNull MetaBugReport metaBugReport)
-            throws FileNotFoundException {
-        ContentResolver r = context.getContentResolver();
-        return r.openOutputStream(BugStorageProvider.buildUriWithSegment(
-                metaBugReport.getId(), BugStorageProvider.URL_SEGMENT_OPEN_BUGREPORT_FILE));
-    }
-
-    /** Returns an output stream to write the audio message file to. */
-    static OutputStream openAudioMessageFileToWrite(
-            @NonNull Context context, @NonNull MetaBugReport metaBugReport)
-            throws FileNotFoundException {
-        ContentResolver r = context.getContentResolver();
-        return r.openOutputStream(BugStorageProvider.buildUriWithSegment(
-                metaBugReport.getId(), BugStorageProvider.URL_SEGMENT_OPEN_AUDIO_FILE));
-    }
-
-    /**
-     * Returns an input stream to read the final zip file from.
-     *
-     * <p>NOTE: This is the old way of storing final zipped bugreport. See
-     * {@link BugStorageProvider#URL_SEGMENT_OPEN_FILE} for more info.
-     */
-    static InputStream openFileToRead(Context context, MetaBugReport bug)
-            throws FileNotFoundException {
-        return context.getContentResolver().openInputStream(
-                BugStorageProvider.buildUriWithSegment(
-                        bug.getId(), BugStorageProvider.URL_SEGMENT_OPEN_FILE));
-    }
-
-    /** Returns an input stream to read the bug report zip file from. */
-    static InputStream openBugReportFileToRead(Context context, MetaBugReport bug)
-            throws FileNotFoundException {
-        return context.getContentResolver().openInputStream(
-                BugStorageProvider.buildUriWithSegment(
-                        bug.getId(), BugStorageProvider.URL_SEGMENT_OPEN_BUGREPORT_FILE));
-    }
-
-    /** Returns an input stream to read the audio file from. */
-    static InputStream openAudioFileToRead(Context context, MetaBugReport bug)
-            throws FileNotFoundException {
-        return context.getContentResolver().openInputStream(
-                BugStorageProvider.buildUriWithSegment(
-                        bug.getId(), BugStorageProvider.URL_SEGMENT_OPEN_AUDIO_FILE));
-    }
-
-    /**
-     * Deletes {@link MetaBugReport} record from a local database and deletes the associated file.
-     *
-     * <p>WARNING: destructive operation.
-     *
-     * @param context     - an application context.
-     * @param bugReportId - a bug report id.
-     * @return true if the record was deleted.
-     */
-    static boolean completeDeleteBugReport(@NonNull Context context, int bugReportId) {
-        ContentResolver r = context.getContentResolver();
-        return r.delete(BugStorageProvider.buildUriWithSegment(
-                bugReportId, BugStorageProvider.URL_SEGMENT_COMPLETE_DELETE), null, null) == 1;
-    }
-
-    /** Deletes all files for given bugreport id; doesn't delete sqlite3 record. */
-    static boolean deleteBugReportFiles(@NonNull Context context, int bugReportId) {
-        ContentResolver r = context.getContentResolver();
-        return r.delete(BugStorageProvider.buildUriWithSegment(
-                bugReportId, BugStorageProvider.URL_SEGMENT_DELETE_FILES), null, null) == 1;
-    }
-
-    /**
-     * Returns all the bugreports that are waiting to be uploaded.
-     */
-    @NonNull
-    public static List<MetaBugReport> getUploadPendingBugReports(@NonNull Context context) {
-        String selection = COLUMN_STATUS + "=?";
-        String[] selectionArgs = new String[]{
-                Integer.toString(Status.STATUS_UPLOAD_PENDING.getValue())};
-        return getBugreports(context, selection, selectionArgs, null);
-    }
-
-    /**
-     * Returns all bugreports in descending order by the ID field. ID is the index in the
-     * database.
-     */
-    @NonNull
-    public static List<MetaBugReport> getAllBugReportsDescending(@NonNull Context context) {
-        return getBugreports(context, null, null, COLUMN_ID + " DESC");
-    }
-
-    /** Returns {@link MetaBugReport} for given bugreport id. */
-    static Optional<MetaBugReport> findBugReport(Context context, int bugreportId) {
-        String selection = COLUMN_ID + " = ?";
-        String[] selectionArgs = new String[]{Integer.toString(bugreportId)};
-        List<MetaBugReport> bugs = BugStorageUtils.getBugreports(
-                context, selection, selectionArgs, null);
-        if (bugs.isEmpty()) {
-            return Optional.empty();
-        }
-        return Optional.of(bugs.get(0));
-    }
-
-    private static List<MetaBugReport> getBugreports(
-            Context context, String selection, String[] selectionArgs, String order) {
-        ArrayList<MetaBugReport> bugReports = new ArrayList<>();
-        String[] projection = {
-                COLUMN_ID,
-                COLUMN_USERNAME,
-                COLUMN_TITLE,
-                COLUMN_TIMESTAMP,
-                COLUMN_BUGREPORT_FILENAME,
-                COLUMN_AUDIO_FILENAME,
-                COLUMN_FILEPATH,
-                COLUMN_STATUS,
-                COLUMN_STATUS_MESSAGE,
-                COLUMN_TYPE};
-        ContentResolver r = context.getContentResolver();
-        Cursor c = r.query(BugStorageProvider.BUGREPORT_CONTENT_URI, projection,
-                selection, selectionArgs, order);
-
-        int count = (c != null) ? c.getCount() : 0;
-
-        if (count > 0) c.moveToFirst();
-        for (int i = 0; i < count; i++) {
-            MetaBugReport meta = MetaBugReport.builder()
-                    .setId(getInt(c, COLUMN_ID))
-                    .setTimestamp(getString(c, COLUMN_TIMESTAMP))
-                    .setUserName(getString(c, COLUMN_USERNAME))
-                    .setTitle(getString(c, COLUMN_TITLE))
-                    .setBugReportFileName(getString(c, COLUMN_BUGREPORT_FILENAME))
-                    .setAudioFileName(getString(c, COLUMN_AUDIO_FILENAME))
-                    .setFilePath(getString(c, COLUMN_FILEPATH))
-                    .setStatus(getInt(c, COLUMN_STATUS))
-                    .setStatusMessage(getString(c, COLUMN_STATUS_MESSAGE))
-                    .setType(getInt(c, COLUMN_TYPE))
-                    .build();
-            bugReports.add(meta);
-            c.moveToNext();
-        }
-        if (c != null) c.close();
-        return bugReports;
-    }
-
-    /**
-     * returns 0 if the column is not found. Otherwise returns the column value.
-     */
-    private static int getInt(Cursor c, String colName) {
-        int colIndex = c.getColumnIndex(colName);
-        if (colIndex == -1) {
-            Log.w(TAG, "Column " + colName + " not found.");
-            return 0;
-        }
-        return c.getInt(colIndex);
-    }
-
-    /**
-     * Returns the column value. If the column is not found returns empty string.
-     */
-    private static String getString(Cursor c, String colName) {
-        int colIndex = c.getColumnIndex(colName);
-        if (colIndex == -1) {
-            Log.w(TAG, "Column " + colName + " not found.");
-            return "";
-        }
-        return Strings.nullToEmpty(c.getString(colIndex));
-    }
-
-    /**
-     * Sets bugreport status to uploaded successfully.
-     */
-    public static void setUploadSuccess(Context context, MetaBugReport bugReport) {
-        setBugReportStatus(context, bugReport, Status.STATUS_UPLOAD_SUCCESS,
-                "Upload time: " + currentTimestamp());
-    }
-
-    /**
-     * Sets bugreport status pending, and update the message to last exception message.
-     *
-     * <p>Used when a transient error has occurred.
-     */
-    public static void setUploadRetry(Context context, MetaBugReport bugReport, Exception e) {
-        setBugReportStatus(context, bugReport, Status.STATUS_UPLOAD_PENDING,
-                getRootCauseMessage(e));
-    }
-
-    /**
-     * Sets bugreport status pending and update the message to last message.
-     *
-     * <p>Used when a transient error has occurred.
-     */
-    public static void setUploadRetry(Context context, MetaBugReport bugReport, String msg) {
-        setBugReportStatus(context, bugReport, Status.STATUS_UPLOAD_PENDING, msg);
-    }
-
-    /**
-     * Sets {@link MetaBugReport} status {@link Status#STATUS_EXPIRED}.
-     * Deletes the associated zip file from disk.
-     *
-     * @return true if succeeded.
-     */
-    static boolean expireBugReport(@NonNull Context context,
-            @NonNull MetaBugReport metaBugReport, @NonNull Instant expiredAt) {
-        metaBugReport = setBugReportStatus(
-                context, metaBugReport, Status.STATUS_EXPIRED, "Expired on " + expiredAt);
-        if (metaBugReport.getStatus() != Status.STATUS_EXPIRED.getValue()) {
-            return false;
-        }
-        return deleteBugReportFiles(context, metaBugReport.getId());
-    }
-
-    /** Gets the root cause of the error. */
-    @NonNull
-    private static String getRootCauseMessage(@Nullable Throwable t) {
-        if (t == null) {
-            return "No error";
-        } else if (t instanceof TokenResponseException) {
-            TokenResponseException ex = (TokenResponseException) t;
-            if (ex.getDetails().getError().equals(INVALID_GRANT)
-                    && ex.getDetails().getErrorDescription().contains(CLOCK_SKEW_ERROR)) {
-                return "Auth error. Check if time & time-zone is correct.";
-            }
-        }
-        while (t.getCause() != null) t = t.getCause();
-        return t.getMessage();
-    }
-
-    /**
-     * Updates bug report record status.
-     *
-     * <p>NOTE: When status is set to STATUS_UPLOAD_PENDING, BugStorageProvider automatically
-     * schedules the bugreport to be uploaded.
-     *
-     * @return Updated {@link MetaBugReport}.
-     */
-    static MetaBugReport setBugReportStatus(
-            Context context, MetaBugReport bugReport, Status status, String message) {
-        return update(context, bugReport.toBuilder()
-                .setStatus(status.getValue())
-                .setStatusMessage(message)
-                .build());
-    }
-
-    /**
-     * Updates bug report record status.
-     *
-     * <p>NOTE: When status is set to STATUS_UPLOAD_PENDING, BugStorageProvider automatically
-     * schedules the bugreport to be uploaded.
-     *
-     * @return Updated {@link MetaBugReport}.
-     */
-    static MetaBugReport setBugReportStatus(
-            Context context, MetaBugReport bugReport, Status status, Exception e) {
-        return setBugReportStatus(context, bugReport, status, getRootCauseMessage(e));
-    }
-
-    /**
-     * Updates the bugreport and returns the updated version.
-     *
-     * <p>NOTE: doesn't update all the fields.
-     */
-    static MetaBugReport update(Context context, MetaBugReport bugReport) {
-        // Update only necessary fields.
-        ContentValues values = new ContentValues();
-        values.put(COLUMN_BUGREPORT_FILENAME, bugReport.getBugReportFileName());
-        values.put(COLUMN_AUDIO_FILENAME, bugReport.getAudioFileName());
-        values.put(COLUMN_STATUS, bugReport.getStatus());
-        values.put(COLUMN_STATUS_MESSAGE, bugReport.getStatusMessage());
-        String where = COLUMN_ID + "=" + bugReport.getId();
-        context.getContentResolver().update(
-                BugStorageProvider.BUGREPORT_CONTENT_URI, values, where, null);
-        return findBugReport(context, bugReport.getId()).orElseThrow(
-                () -> new IllegalArgumentException("Bug " + bugReport.getId() + " not found"));
-    }
-
-    private static String currentTimestamp() {
-        return TIMESTAMP_FORMAT.format(new Date());
-    }
-}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/Config.java b/tests/BugReportApp/src/com/google/android/car/bugreport/Config.java
deleted file mode 100644
index b253caf..0000000
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/Config.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.android.car.bugreport;
-
-import android.app.ActivityThread;
-import android.os.Build;
-import android.os.SystemProperties;
-import android.provider.DeviceConfig;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-
-import com.google.common.collect.ImmutableSet;
-
-import java.io.PrintWriter;
-
-/**
- * Contains config for BugReport App.
- *
- * <p>The config is kept synchronized with {@code car} namespace. It's not defined in
- * {@link DeviceConfig}.
- *
- * <ul>To get/set the flags via adb:
- *   <li>{@code adb shell device_config get car bugreport_upload_destination}
- *   <li>{@code adb shell device_config put car bugreport_upload_destination gcs}
- *   <li>{@code adb shell device_config delete car bugreport_upload_destination}
- * </ul>
- */
-final class Config {
-    private static final String TAG = Config.class.getSimpleName();
-
-    /**
-     * Namespace for all Android Automotive related features.
-     *
-     * <p>In the future it will move to {@code DeviceConfig#NAMESPACE_CAR}.
-     */
-    private static final String NAMESPACE_CAR = "car";
-
-    /**
-     * A string flag, can be one of {@code null} or {@link #UPLOAD_DESTINATION_GCS}.
-     */
-    private static final String KEY_BUGREPORT_UPLOAD_DESTINATION = "bugreport_upload_destination";
-
-    /**
-     * A value for {@link #KEY_BUGREPORT_UPLOAD_DESTINATION}.
-     *
-     * Upload bugreports to GCS. Only works in {@code userdebug} or {@code eng} builds.
-     */
-    private static final String UPLOAD_DESTINATION_GCS = "gcs";
-
-    /**
-     * A system property to force enable the app bypassing the {@code userdebug/eng} build check.
-     */
-    private static final String PROP_FORCE_ENABLE = "android.car.bugreport.force_enable";
-
-    /*
-     * Enable uploading new bugreports to GCS for these devices. If the device is not in this list,
-     * {@link #KEY_UPLOAD_DESTINATION} flag will be used instead.
-     */
-    private static final ImmutableSet<String> ENABLE_FORCE_UPLOAD_TO_GCS_FOR_DEVICES =
-            ImmutableSet.of("hawk");
-
-    private final Object mLock = new Object();
-
-    @GuardedBy("mLock")
-    private String mUploadDestination = null;
-
-    void start() {
-        DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_CAR,
-                ActivityThread.currentApplication().getMainExecutor(), this::onPropertiesChanged);
-        updateConstants();
-    }
-
-    private void onPropertiesChanged(DeviceConfig.Properties properties) {
-        if (properties.getKeyset().contains(KEY_BUGREPORT_UPLOAD_DESTINATION)) {
-            updateConstants();
-        }
-    }
-
-    /** Returns true if bugreport app is enabled for this device. */
-    static boolean isBugReportEnabled() {
-        return Build.IS_DEBUGGABLE || SystemProperties.getBoolean(PROP_FORCE_ENABLE, false);
-    }
-
-    /** If new bugreports should be scheduled for uploading. */
-    boolean getAutoUpload() {
-        // TODO(b/144851443): Enable auto-upload only if upload destination is Gcs until
-        //                    we create a way to allow implementing OEMs custom upload logic.
-        return isUploadDestinationGcs();
-    }
-
-    /**
-     * Returns {@link true} if bugreport upload destination is GCS.
-     */
-    private boolean isUploadDestinationGcs() {
-        if (isTempForceAutoUploadGcsEnabled()) {
-            Log.d(TAG, "Setting upload dest to GCS ENABLE_AUTO_UPLOAD is true");
-            return true;
-        }
-        // NOTE: enable it only for userdebug/eng builds.
-        return UPLOAD_DESTINATION_GCS.equals(getUploadDestination()) && Build.IS_DEBUGGABLE;
-    }
-
-    private static boolean isTempForceAutoUploadGcsEnabled() {
-        return ENABLE_FORCE_UPLOAD_TO_GCS_FOR_DEVICES.contains(Build.DEVICE);
-    }
-
-    /**
-     * Returns value of a flag {@link #KEY_BUGREPORT_UPLOAD_DESTINATION}.
-     */
-    private String getUploadDestination() {
-        synchronized (mLock) {
-            return mUploadDestination;
-        }
-    }
-
-    private void updateConstants() {
-        synchronized (mLock) {
-            mUploadDestination = DeviceConfig.getString(NAMESPACE_CAR,
-                    KEY_BUGREPORT_UPLOAD_DESTINATION, /* defaultValue= */ null);
-        }
-    }
-
-    void dump(String prefix, PrintWriter pw) {
-        pw.println(prefix + "car.bugreport.Config:");
-
-        pw.print(prefix + "  ");
-        pw.print("getAutoUpload");
-        pw.print("=");
-        pw.println(getAutoUpload() ? "true" : "false");
-
-        pw.print(prefix + "  ");
-        pw.print("getUploadDestination");
-        pw.print("=");
-        pw.println(getUploadDestination());
-
-        pw.print(prefix + "  ");
-        pw.print("isUploadDestinationGcs");
-        pw.print("=");
-        pw.println(isUploadDestinationGcs());
-    }
-}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/FileUtils.java b/tests/BugReportApp/src/com/google/android/car/bugreport/FileUtils.java
deleted file mode 100644
index b30035e..0000000
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/FileUtils.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.android.car.bugreport;
-
-import android.content.Context;
-
-import com.google.common.base.Preconditions;
-
-import java.io.File;
-
-/**
- * File utilities.
- *
- * Thread safety and file operations: All file operations should happen on the same worker
- * thread for thread safety. This is provided by running both bugreport service and file upload
- * service on a asynctask. Asynctasks are by default executed on the same worker thread in serial.
- *
- * There is one exception to the rule above:
- * Voice recorder works on main thread, however this is not a thread safety problem because:
- * i. voice recorder always works before starting to collect rest of the bugreport
- * ii. a bug report cannot be moved to upload (pending) directory before it is completely
- * collected.
- */
-public class FileUtils {
-    private static final String PREFIX = "bugreport-";
-    /** A directory under the system user; contains bugreport zip files and audio files. */
-    private static final String PENDING_DIR = "bug_reports_pending";
-    // Temporary directory under the current user, used for zipping files.
-    private static final String TEMP_DIR = "bug_reports_temp";
-
-    private static final String FS = "@";
-
-    static File getPendingDir(Context context) {
-        Preconditions.checkArgument(context.getUser().isSystem(),
-                "Must be called from the system user.");
-        File dir = new File(context.getDataDir(), PENDING_DIR);
-        dir.mkdirs();
-        return dir;
-    }
-
-    /**
-     * Creates and returns file directory for storing bug report files before they are zipped into
-     * a single file.
-     */
-    static File createTempDir(Context context, String timestamp) {
-        File dir = getTempDir(context, timestamp);
-        dir.mkdirs();
-        return dir;
-    }
-
-    /**
-     * Returns path to the directory for storing bug report files before they are zipped into a
-     * single file.
-     */
-    static File getTempDir(Context context, String timestamp) {
-        Preconditions.checkArgument(!context.getUser().isSystem(),
-                "Must be called from the current user.");
-        return new File(context.getDataDir(), TEMP_DIR + "/" + timestamp);
-    }
-
-    /**
-     * Constructs a bugreport zip file name.
-     *
-     * <p>Add lookup code to the filename to allow matching audio file and bugreport file in USB.
-     */
-    static String getZipFileName(MetaBugReport bug) {
-        String lookupCode = extractLookupCode(bug);
-        return PREFIX + bug.getUserName() + FS + bug.getTimestamp() + "-" + lookupCode + ".zip";
-    }
-
-    /**
-     * Constructs a audio message file name.
-     *
-     * <p>Add lookup code to the filename to allow matching audio file and bugreport file in USB.
-     *
-     * @param timestamp - current timestamp, when audio was created.
-     * @param bug       - a bug report.
-     */
-    static String getAudioFileName(String timestamp, MetaBugReport bug) {
-        String lookupCode = extractLookupCode(bug);
-        return PREFIX + bug.getUserName() + FS + timestamp + "-" + lookupCode + "-message.3gp";
-    }
-
-    private static String extractLookupCode(MetaBugReport bug) {
-        Preconditions.checkArgument(bug.getTitle().startsWith("["),
-                "Invalid bugreport title, doesn't contain lookup code. ");
-        return bug.getTitle().substring(1, BugReportActivity.LOOKUP_STRING_LENGTH + 1);
-    }
-
-    /**
-     * Returns a {@link File} object pointing to a path in a temp directory under current users
-     * {@link Context#getDataDir}.
-     *
-     * @param context       - an application context.
-     * @param timestamp     - generates file for this timestamp
-     * @param suffix        - a filename suffix.
-     * @return A file.
-     */
-    static File getFileWithSuffix(Context context, String timestamp, String suffix) {
-        return new File(createTempDir(context, timestamp), timestamp + suffix);
-    }
-
-    /**
-     * Returns a {@link File} object pointing to a path in a temp directory under current users
-     * {@link Context#getDataDir}.
-     *
-     * @param context     - an application context.
-     * @param timestamp   - generates file for this timestamp.
-     * @param name        - a filename
-     * @return A file.
-     */
-    static File getFile(Context context, String timestamp, String name) {
-        return new File(getTempDir(context, timestamp), name);
-    }
-
-    /**
-     * Deletes a directory and its contents recursively
-     *
-     * @param directory to delete
-     */
-    static void deleteDirectory(File directory) {
-        File[] files = directory.listFiles();
-        if (files != null) {
-            for (File file : files) {
-                if (!file.isDirectory()) {
-                    file.delete();
-                } else {
-                    deleteDirectory(file);
-                }
-            }
-        }
-        directory.delete();
-    }
-}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/JobSchedulingUtils.java b/tests/BugReportApp/src/com/google/android/car/bugreport/JobSchedulingUtils.java
deleted file mode 100644
index eac8b9a..0000000
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/JobSchedulingUtils.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.android.car.bugreport;
-
-import android.app.job.JobInfo;
-import android.app.job.JobScheduler;
-import android.content.ComponentName;
-import android.content.Context;
-import android.util.Log;
-
-/**
- * Utilities for scheduling upload jobs.
- */
-class JobSchedulingUtils {
-    private static final String TAG = JobSchedulingUtils.class.getSimpleName();
-
-    private static final int UPLOAD_JOB_ID = 1;
-    private static final int RETRY_DELAY_IN_MS = 5_000;
-
-    /**
-     * Schedules {@link UploadJob} under the current user.
-     *
-     * <p>Make sure this method is called under the primary user.
-     *
-     * <ul>
-     *   <li>require network connectivity
-     *   <li>good quality network (large upload size)
-     *   <li>persist across reboots
-     * </ul>
-     */
-    static void scheduleUploadJob(Context context) {
-        JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
-        if (jobScheduler == null) {
-            Log.w(TAG, "Cannot get JobScheduler from context.");
-            return;
-        }
-
-        JobInfo pendingJob = jobScheduler.getPendingJob(UPLOAD_JOB_ID);
-        // if there is already a pending job, do not schedule a new one.
-        if (pendingJob != null) {
-            Log.d(TAG, "Upload job is already active, not re-scheduling");
-            return;
-        }
-
-        // NOTE: Don't set estimated network bytes, because we want bug reports to be uploaded
-        //       without any constraints.
-        jobScheduler.schedule(new JobInfo.Builder(UPLOAD_JOB_ID,
-                new ComponentName(context, UploadJob.class))
-                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
-                .setBackoffCriteria(RETRY_DELAY_IN_MS, JobInfo.BACKOFF_POLICY_LINEAR)
-                .build());
-    }
-}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/MetaBugReport.java b/tests/BugReportApp/src/com/google/android/car/bugreport/MetaBugReport.java
deleted file mode 100644
index fcdb5b7..0000000
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/MetaBugReport.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.android.car.bugreport;
-
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.IntDef;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.google.auto.value.AutoValue;
-
-import java.lang.annotation.Retention;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-/** Represents the information that a bugreport can contain. */
-@AutoValue
-abstract class MetaBugReport implements Parcelable {
-
-    private static final DateFormat BUG_REPORT_TIMESTAMP_DATE_FORMAT =
-            new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
-
-    /** The app records audio message when initiated. Can change audio state. */
-    static final int TYPE_INTERACTIVE = 0;
-
-    /**
-     * The app doesn't show dialog and doesn't record audio when initiated. It allows user to
-     * add audio message when bugreport is collected.
-     */
-    static final int TYPE_SILENT = 1;
-
-    /** Annotation for bug report types. */
-    @Retention(SOURCE)
-    @IntDef({TYPE_INTERACTIVE, TYPE_SILENT})
-    @interface BugReportType {};
-
-    /**
-     * @return Id of the bug report. Bug report id monotonically increases and is unique.
-     */
-    public abstract int getId();
-
-    /**
-     * @return Username (LDAP) that created this bugreport
-     */
-    public abstract String getUserName();
-
-    /**
-     * @return Title of the bug.
-     */
-    public abstract String getTitle();
-
-    /**
-     * @return Timestamp when the bug report is initialized.
-     */
-    public abstract String getTimestamp();
-
-    /**
-     * @return path to the zip file stored under the system user.
-     *
-     * <p>NOTE: This is the old way of storing final zipped bugreport. See
-     * {@link BugStorageProvider#URL_SEGMENT_OPEN_FILE} for more info.
-     */
-    public abstract String getFilePath();
-
-    /**
-     * @return filename of the bug report zip file stored under the system user.
-     */
-    public abstract String getBugReportFileName();
-
-    /**
-     * @return filename of the audio message file stored under the system user.
-     */
-    public abstract String getAudioFileName();
-
-    /**
-     * @return {@link Status} of the bug upload.
-     */
-    public abstract int getStatus();
-
-    /**
-     * @return StatusMessage of the bug upload.
-     */
-    public abstract String getStatusMessage();
-
-    /**
-     * @return {@link BugReportType}.
-     */
-    public abstract int getType();
-
-    /** @return {@link Builder} from the meta bug report. */
-    public abstract Builder toBuilder();
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(getId());
-        dest.writeString(getTimestamp());
-        dest.writeString(getTitle());
-        dest.writeString(getUserName());
-        dest.writeString(getFilePath());
-        dest.writeString(getBugReportFileName());
-        dest.writeString(getAudioFileName());
-        dest.writeInt(getStatus());
-        dest.writeString(getStatusMessage());
-        dest.writeInt(getType());
-    }
-
-    /** Converts {@link Date} to bugreport timestamp. */
-    static String toBugReportTimestamp(Date date) {
-        return BUG_REPORT_TIMESTAMP_DATE_FORMAT.format(date);
-    }
-
-    /** Creates a {@link Builder} with default, non-null values. */
-    static Builder builder() {
-        return new AutoValue_MetaBugReport.Builder()
-                .setTimestamp("")
-                .setFilePath("")
-                .setBugReportFileName("")
-                .setAudioFileName("")
-                .setStatusMessage("")
-                .setTitle("")
-                .setUserName("");
-    }
-
-    /** A creator that's used by Parcelable. */
-    public static final Parcelable.Creator<MetaBugReport> CREATOR =
-            new Parcelable.Creator<MetaBugReport>() {
-                public MetaBugReport createFromParcel(Parcel in) {
-                    int id = in.readInt();
-                    String timestamp = in.readString();
-                    String title = in.readString();
-                    String username = in.readString();
-                    String filePath = in.readString();
-                    String bugReportFileName = in.readString();
-                    String audioFileName = in.readString();
-                    int status = in.readInt();
-                    String statusMessage = in.readString();
-                    int type = in.readInt();
-                    return MetaBugReport.builder()
-                            .setId(id)
-                            .setTimestamp(timestamp)
-                            .setTitle(title)
-                            .setUserName(username)
-                            .setFilePath(filePath)
-                            .setBugReportFileName(bugReportFileName)
-                            .setAudioFileName(audioFileName)
-                            .setStatus(status)
-                            .setStatusMessage(statusMessage)
-                            .setType(type)
-                            .build();
-                }
-
-                public MetaBugReport[] newArray(int size) {
-                    return new MetaBugReport[size];
-                }
-            };
-
-    /** Builder for MetaBugReport. */
-    @AutoValue.Builder
-    abstract static class Builder {
-        /** Sets id. */
-        public abstract Builder setId(int id);
-
-        /** Sets timestamp. */
-        public abstract Builder setTimestamp(String timestamp);
-
-        /** Sets title. */
-        public abstract Builder setTitle(String title);
-
-        /** Sets username. */
-        public abstract Builder setUserName(String username);
-
-        /** Sets filepath. */
-        public abstract Builder setFilePath(String filePath);
-
-        /** Sets bugReportFileName. */
-        public abstract Builder setBugReportFileName(String bugReportFileName);
-
-        /** Sets audioFileName. */
-        public abstract Builder setAudioFileName(String audioFileName);
-
-        /** Sets {@link Status}. */
-        public abstract Builder setStatus(int status);
-
-        /** Sets statusmessage. */
-        public abstract Builder setStatusMessage(String statusMessage);
-
-        /** Sets the {@link BugReportType}. */
-        public abstract Builder setType(@BugReportType int type);
-
-        public abstract MetaBugReport build();
-    }
-}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/PackageUtils.java b/tests/BugReportApp/src/com/google/android/car/bugreport/PackageUtils.java
deleted file mode 100644
index 26afc43..0000000
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/PackageUtils.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.android.car.bugreport;
-
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.util.Log;
-
-/**
- * Package related utility methods.
- */
-final class PackageUtils {
-    private static final String TAG = PackageUtils.class.getSimpleName();
-
-    /** Returns a BugReport app version name from {@code AndroidManifest.xml}. */
-    static String getPackageVersion(Context context) {
-        try {
-            PackageInfo packageInfo = context.getPackageManager().getPackageInfo(
-                    context.getPackageName(), 0);
-            return packageInfo.versionName;
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.e(TAG, "Can't get package version.", e);
-            return "unknown";
-        }
-    }
-
-    private PackageUtils() {
-    }
-}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/SimpleUploaderAsyncTask.java b/tests/BugReportApp/src/com/google/android/car/bugreport/SimpleUploaderAsyncTask.java
deleted file mode 100644
index 0e92010..0000000
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/SimpleUploaderAsyncTask.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.android.car.bugreport;
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.os.AsyncTask;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.google.api.client.extensions.android.http.AndroidHttp;
-import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
-import com.google.api.client.http.HttpTransport;
-import com.google.api.client.http.InputStreamContent;
-import com.google.api.client.json.JsonFactory;
-import com.google.api.client.json.jackson2.JacksonFactory;
-import com.google.api.services.storage.Storage;
-import com.google.api.services.storage.model.StorageObject;
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableMap;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.zip.ZipOutputStream;
-
-/**
- * Uploads a bugreport files to GCS using a simple (no-multipart / no-resume) upload policy.
- *
- * <p>It merges bugreport zip file and audio file into one final zip file and uploads it.
- *
- * <p>Please see {@code res/values/configs.xml} and {@code res/raw/gcs_credentials.json} for the
- * configuration.
- */
-class SimpleUploaderAsyncTask extends AsyncTask<Void, Void, Boolean> {
-    private static final String TAG = SimpleUploaderAsyncTask.class.getSimpleName();
-
-    private static final String ACCESS_SCOPE =
-            "https://www.googleapis.com/auth/devstorage.read_write";
-
-    private static final String STORAGE_METADATA_TITLE = "title";
-
-    private final Context mContext;
-    private final Result mResult;
-
-    /**
-     * The uploader uploads only one bugreport each time it is called. This interface is
-     * used to reschedule upload job, if there are more bugreports waiting.
-     *
-     * Pass true to reschedule upload job, false not to reschedule.
-     */
-    interface Result {
-        void reschedule(boolean s);
-    }
-
-    /** Constructs SimpleUploaderAsyncTask. */
-    SimpleUploaderAsyncTask(@NonNull Context context, @NonNull Result result) {
-        mContext = context;
-        mResult = result;
-    }
-
-    private StorageObject uploadSimple(
-            Storage storage, MetaBugReport bugReport, String fileName, InputStream data)
-            throws IOException {
-        InputStreamContent mediaContent = new InputStreamContent("application/zip", data);
-
-        String bucket = mContext.getString(R.string.config_gcs_bucket);
-        if (TextUtils.isEmpty(bucket)) {
-            throw new RuntimeException("config_gcs_bucket is empty.");
-        }
-
-        // Create GCS MetaData.
-        Map<String, String> metadata = ImmutableMap.of(
-                STORAGE_METADATA_TITLE, bugReport.getTitle()
-        );
-        StorageObject object = new StorageObject()
-                .setBucket(bucket)
-                .setName(fileName)
-                .setMetadata(metadata)
-                .setContentDisposition("attachment");
-        Storage.Objects.Insert insertObject = storage.objects().insert(bucket, object,
-                mediaContent);
-
-        // The media uploader gzips content by default, and alters the Content-Encoding accordingly.
-        // GCS dutifully stores content as-uploaded. This line disables the media uploader behavior,
-        // so the service stores exactly what is in the InputStream, without transformation.
-        insertObject.getMediaHttpUploader().setDisableGZipContent(true);
-        Log.v(TAG, "started uploading object " + fileName + " to bucket " + bucket);
-        return insertObject.execute();
-    }
-
-    private void upload(MetaBugReport bugReport) throws IOException {
-        GoogleCredential credential = GoogleCredential
-                .fromStream(mContext.getResources().openRawResource(R.raw.gcs_credentials))
-                .createScoped(Collections.singleton(ACCESS_SCOPE));
-        Log.v(TAG, "Created credential");
-        HttpTransport httpTransport = AndroidHttp.newCompatibleTransport();
-        JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
-
-        Storage storage = new Storage.Builder(httpTransport, jsonFactory, credential)
-                .setApplicationName("Bugreportupload/1.0").build();
-
-        File tmpBugReportFile = zipBugReportFiles(bugReport);
-        Log.d(TAG, "Uploading file " + tmpBugReportFile);
-        try {
-            // Upload filename is bugreport filename, although, now it contains the audio message.
-            String fileName = bugReport.getBugReportFileName();
-            if (Strings.isNullOrEmpty(fileName)) {
-                // Old bugreports don't contain getBugReportFileName, fallback to getFilePath.
-                fileName = new File(bugReport.getFilePath()).getName();
-            }
-            try (FileInputStream inputStream = new FileInputStream(tmpBugReportFile)) {
-                StorageObject object = uploadSimple(storage, bugReport, fileName, inputStream);
-                Log.v(TAG, "finished uploading object " + object.getName() + " file " + fileName);
-            }
-            File pendingDir = FileUtils.getPendingDir(mContext);
-            // Delete only after successful upload; the files are needed for retry.
-            if (!Strings.isNullOrEmpty(bugReport.getAudioFileName())) {
-                Log.v(TAG, "Deleting file " + bugReport.getAudioFileName());
-                new File(pendingDir, bugReport.getAudioFileName()).delete();
-            }
-            if (!Strings.isNullOrEmpty(bugReport.getBugReportFileName())) {
-                Log.v(TAG, "Deleting file " + bugReport.getBugReportFileName());
-                new File(pendingDir, bugReport.getBugReportFileName()).delete();
-            }
-        } finally {
-            // Delete the temp file if it's not a MetaBugReport#getFilePath, because it's needed
-            // for retry.
-            if (Strings.isNullOrEmpty(bugReport.getFilePath())) {
-                Log.v(TAG, "Deleting file " + tmpBugReportFile);
-                tmpBugReportFile.delete();
-            }
-        }
-    }
-
-    private File zipBugReportFiles(MetaBugReport bugReport) throws IOException {
-        if (!Strings.isNullOrEmpty(bugReport.getFilePath())) {
-            // Old bugreports still have this field.
-            return new File(bugReport.getFilePath());
-        }
-        File finalZipFile =
-                File.createTempFile("bugreport", ".zip", mContext.getCacheDir());
-        File pendingDir = FileUtils.getPendingDir(mContext);
-        try (ZipOutputStream zipStream = new ZipOutputStream(
-                new BufferedOutputStream(new FileOutputStream(finalZipFile)))) {
-            ZipUtils.extractZippedFileToZipStream(
-                    new File(pendingDir, bugReport.getBugReportFileName()), zipStream);
-            ZipUtils.addFileToZipStream(
-                    new File(pendingDir, bugReport.getAudioFileName()), zipStream);
-        }
-        return finalZipFile;
-    }
-
-    @Override
-    protected void onPostExecute(Boolean success) {
-        mResult.reschedule(success);
-    }
-
-    /** Returns true is there are more files to upload. */
-    @Override
-    protected Boolean doInBackground(Void... voids) {
-        List<MetaBugReport> bugReports = BugStorageUtils.getUploadPendingBugReports(mContext);
-
-        for (MetaBugReport bugReport : bugReports) {
-            try {
-                if (isCancelled()) {
-                    BugStorageUtils.setUploadRetry(mContext, bugReport, "Upload Job Cancelled");
-                    return true;
-                }
-                upload(bugReport);
-                BugStorageUtils.setUploadSuccess(mContext, bugReport);
-            } catch (Exception e) {
-                Log.e(TAG, String.format("Failed uploading %s - likely a transient error",
-                        bugReport.getTimestamp()), e);
-                BugStorageUtils.setUploadRetry(mContext, bugReport, e);
-            }
-        }
-        return false;
-    }
-
-    @Override
-    protected void onCancelled(Boolean success) {
-        mResult.reschedule(true);
-    }
-}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/StartUpBootReceiver.java b/tests/BugReportApp/src/com/google/android/car/bugreport/StartUpBootReceiver.java
deleted file mode 100644
index 7e89d2d..0000000
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/StartUpBootReceiver.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.android.car.bugreport;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.os.UserManager;
-import android.util.Log;
-
-/**
- * Handles device boot intents.
- *
- * <ul>
- *     <li>Starts {@link UploadJob}</li>
- * </ul>
- */
-public class StartUpBootReceiver extends BroadcastReceiver {
-    public static final String TAG = StartUpBootReceiver.class.getSimpleName();
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        if (!Config.isBugReportEnabled()) {
-            return;
-        }
-        // Run it only once for the system user (u0) and ignore for other users.
-        UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
-        if (!userManager.isSystemUser()) {
-            return;
-        }
-
-        if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
-            Log.d(TAG, "StartUpBootReceiver BOOT_COMPLETED");
-            // We removed "persisted" from UploadJob scheduling, instead we will manually schedule
-            // the job on boot, because "persisted" seems more fragile.
-            JobSchedulingUtils.scheduleUploadJob(context);
-        }
-    }
-}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/Status.java b/tests/BugReportApp/src/com/google/android/car/bugreport/Status.java
deleted file mode 100644
index 380944e..0000000
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/Status.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.android.car.bugreport;
-
-/** Defines {@link MetaBugReport} statuses. */
-public enum Status {
-    // Bugreport is being written
-    STATUS_WRITE_PENDING(0),
-
-    // Writing bugreport failed
-    STATUS_WRITE_FAILED(1),
-
-    // Bugreport is waiting to be uploaded
-    STATUS_UPLOAD_PENDING(2),
-
-    // Bugreport uploaded successfully
-    STATUS_UPLOAD_SUCCESS(3),
-
-    // Bugreport failed to upload
-    STATUS_UPLOAD_FAILED(4),
-
-    // Bugreport is cancelled by user
-    STATUS_USER_CANCELLED(5),
-
-    // Bugreport is pending user choice on whether to upload or copy.
-    STATUS_PENDING_USER_ACTION(6),
-
-    // Bugreport was moved successfully.
-    STATUS_MOVE_SUCCESSFUL(7),
-
-    // Bugreport move has failed.
-    STATUS_MOVE_FAILED(8),
-
-    // Bugreport is moving to USB drive.
-    STATUS_MOVE_IN_PROGRESS(9),
-
-    // Bugreport is expired. Associated file is deleted from the disk.
-    STATUS_EXPIRED(10),
-
-    // Bugreport needs audio message.
-    STATUS_AUDIO_PENDING(11);
-
-    private final int mValue;
-
-    Status(int value) {
-        mValue = value;
-    }
-
-    /** Returns integer value of the status. */
-    public int getValue() {
-        return mValue;
-    }
-
-    /** Generates human-readable string from a status value. */
-    public static String toString(int value) {
-        switch (value) {
-            case 0:
-                return "Write pending";
-            case 1:
-                return "Write failed";
-            case 2:
-                return "Upload pending";
-            case 3:
-                return "Upload successful";
-            case 4:
-                return "Upload failed";
-            case 5:
-                return "User cancelled";
-            case 6:
-                return "Pending user action";
-            case 7:
-                return "Move successful";
-            case 8:
-                return "Move failed";
-            case 9:
-                return "Move in progress";
-            case 10:
-                return "Expired";
-            case 11:
-                return "Audio message pending";
-        }
-        return "unknown";
-    }
-}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/UploadJob.java b/tests/BugReportApp/src/com/google/android/car/bugreport/UploadJob.java
deleted file mode 100644
index b2c17e9..0000000
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/UploadJob.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.android.car.bugreport;
-
-import android.app.job.JobParameters;
-import android.app.job.JobService;
-import android.util.Log;
-
-/** Executes a {@link SimpleUploaderAsyncTask}. */
-public class UploadJob extends JobService {
-    private static final String TAG = UploadJob.class.getSimpleName();
-
-    private SimpleUploaderAsyncTask mUploader;
-
-    @Override
-    public boolean onStartJob(final JobParameters jobParameters) {
-        if (!Config.isBugReportEnabled()) {
-            return false;
-        }
-        Log.v(TAG, "Starting upload job");
-        mUploader = new SimpleUploaderAsyncTask(
-                this, reschedule -> jobFinished(jobParameters, reschedule));
-        mUploader.execute();
-        return true;
-    }
-
-    @Override
-    public boolean onStopJob(JobParameters jobParameters) {
-        mUploader.cancel(true);
-        return false;
-    }
-}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/VoiceRecordingView.java b/tests/BugReportApp/src/com/google/android/car/bugreport/VoiceRecordingView.java
deleted file mode 100644
index 56d5679..0000000
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/VoiceRecordingView.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.android.car.bugreport;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
-import android.media.MediaRecorder;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-
-/**
- * A view that draws MIC icon and an animated ellipsoid. The ellipsoid animation shows the sound
- * amplitude from {@link MediaRecorder}.
- *
- * <p>All the constant values are chosen experimentally.
- */
-public class VoiceRecordingView extends View {
-    private static final String TAG = VoiceRecordingView.class.getSimpleName();
-
-    private static final float DROPOFF_STEP = 10f;
-    private static final long ANIMATION_INTERVAL_MS = 70;
-    private static final float RECORDER_AMPLITUDE_NORMALIZER_COEF = 16192.0f;
-
-    private final Paint mPaint;
-    private final BitmapDrawable mMicIconDrawable;
-
-    private float mCurrentRadius;
-    private MediaRecorder mRecorder;
-
-    public VoiceRecordingView(Context context, @Nullable AttributeSet attrs) {
-        super(context, attrs);
-        mMicIconDrawable = (BitmapDrawable) context.getDrawable(
-                android.R.drawable.ic_btn_speak_now);
-
-        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mPaint.setColor(Color.LTGRAY);
-        mPaint.setStyle(Paint.Style.FILL);
-    }
-
-    /** Sets MediaRecorder that will be used to animate the ellipsoid. */
-    public void setRecorder(@Nullable MediaRecorder recorder) {
-        mRecorder = recorder;
-        invalidate();
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldW, int oldH) {
-        super.onSizeChanged(w, h, oldW, oldH);
-
-        float micIconWidth = mMicIconDrawable.getBitmap().getWidth();
-        float micIconHeight = mMicIconDrawable.getBitmap().getHeight();
-        int micIconDrawableWidth = (int) (micIconWidth / micIconHeight * h);
-        int micIconDrawableLeft = (w - micIconDrawableWidth) / 2;
-        mMicIconDrawable.setBounds(
-                new Rect(micIconDrawableLeft, 0, micIconDrawableLeft + micIconDrawableWidth, h));
-    }
-
-    private void updateCurrentRadius(int width) {
-        final float maxRadius = width / 4;
-        float radius = 0;
-
-        if (mRecorder != null) {
-            try {
-                radius += maxRadius * mRecorder.getMaxAmplitude()
-                        / RECORDER_AMPLITUDE_NORMALIZER_COEF;
-            } catch (IllegalStateException e) {
-                Log.v(TAG, "Failed to get max amplitude from MediaRecorder");
-            }
-        }
-
-        if (radius > mCurrentRadius) {
-            mCurrentRadius = radius;
-        } else {
-            mCurrentRadius = Math.max(radius, mCurrentRadius - DROPOFF_STEP);
-        }
-        mCurrentRadius = Math.min(maxRadius, mCurrentRadius);
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-
-        final int width = canvas.getWidth();
-        final int height = canvas.getHeight();
-
-        updateCurrentRadius(width);
-
-        // Draws an ellipsoid with horizontal radius calculated from MediaRecorder's amplitude.
-        final int mx = width / 2;
-        final int my = height / 2;
-        canvas.drawCircle(mx, my, height / 2, mPaint);
-        canvas.drawCircle(mx - mCurrentRadius, my, height / 2, mPaint);
-        canvas.drawCircle(mx + mCurrentRadius, my, height / 2, mPaint);
-        canvas.drawRect(mx - mCurrentRadius, 0, mx + mCurrentRadius, height, mPaint);
-
-        if (mRecorder != null) {
-            postInvalidateDelayed(ANIMATION_INTERVAL_MS);
-        }
-
-        mMicIconDrawable.draw(canvas);
-    }
-}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/ZipUtils.java b/tests/BugReportApp/src/com/google/android/car/bugreport/ZipUtils.java
deleted file mode 100644
index 6c50d18..0000000
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/ZipUtils.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.android.car.bugreport;
-
-import android.util.Log;
-
-import com.google.common.io.ByteStreams;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Enumeration;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import java.util.zip.ZipOutputStream;
-
-/** Zip utility functions. */
-final class ZipUtils {
-    private static final String TAG = ZipUtils.class.getSimpleName();
-
-    /** Extracts the contents of a zip file to the zip output stream. */
-    static void extractZippedFileToZipStream(File file, ZipOutputStream zipStream) {
-        if (!file.exists()) {
-            Log.w(TAG, "File " + file + " not found");
-            return;
-        }
-        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, "Zip file " + file.getName() + " is empty, skipping.");
-            return;
-        }
-        try (ZipFile zipFile = new ZipFile(file)) {
-            Enumeration<? extends ZipEntry> entries = zipFile.entries();
-            while (entries.hasMoreElements()) {
-                ZipEntry entry = entries.nextElement();
-                try (InputStream stream = zipFile.getInputStream(entry)) {
-                    writeInputStreamToZipStream(entry.getName(), stream, zipStream);
-                }
-            }
-        } catch (IOException e) {
-            Log.w(TAG, "Failed to add " + file + " to zip", e);
-        }
-    }
-
-    /** Adds a file to the zip output stream. */
-    static void addFileToZipStream(File file, ZipOutputStream zipStream) {
-        if (!file.exists()) {
-            Log.w(TAG, "File " + file + " not found");
-            return;
-        }
-        if (file.length() == 0) {
-            Log.w(TAG, "File " + file.getName() + " is empty, skipping.");
-            return;
-        }
-        try (FileInputStream audioInput = new FileInputStream(file)) {
-            writeInputStreamToZipStream(file.getName(), audioInput, zipStream);
-        } catch (IOException e) {
-            Log.w(TAG, "Failed to add " + file + "to the final zip");
-        }
-    }
-
-    /** Writes a new file from input stream to the zip stream. */
-    static void writeInputStreamToZipStream(
-            String filename, InputStream input, ZipOutputStream zipStream) throws IOException {
-        ZipEntry entry = new ZipEntry(filename);
-        zipStream.putNextEntry(entry);
-        ByteStreams.copy(input, zipStream);
-        zipStream.closeEntry();
-    }
-
-    private ZipUtils() {}
-}
diff --git a/tests/BugReportApp/tests/Android.bp b/tests/BugReportApp/tests/Android.bp
new file mode 100644
index 0000000..9f54a75
--- /dev/null
+++ b/tests/BugReportApp/tests/Android.bp
@@ -0,0 +1,42 @@
+// 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.
+
+android_test {
+    name: "BugReportAppTest",
+
+    srcs: ["src/**/*.java"],
+
+    instrumentation_for: "BugReportApp",
+
+    certificate: "platform",
+    optimize: {
+        enabled: false,
+    },
+    platform_apis: true,
+
+    libs: [
+        "android.test.base",
+        "android.test.mock",
+        "android.test.runner",
+    ],
+
+    static_libs: [
+        "android-support-test",
+        "truth-prebuilt",
+    ],
+
+    test_suites: [
+        "device-tests",
+    ],
+}
diff --git a/tests/BugReportApp/tests/Android.mk b/tests/BugReportApp/tests/Android.mk
deleted file mode 100644
index 2a6ab88..0000000
--- a/tests/BugReportApp/tests/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright (C) 2019 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := BugReportAppTest
-LOCAL_INSTRUMENTATION_FOR := BugReportApp
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_CERTIFICATE := platform
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_JAVA_LIBRARIES := \
-    android.test.base \
-    android.test.mock \
-    android.test.runner
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    android-support-test \
-    truth-prebuilt
-
-include $(BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
diff --git a/tests/BugReportApp/tests/AndroidManifest.xml b/tests/BugReportApp/tests/AndroidManifest.xml
index e6a8537..26736c6 100644
--- a/tests/BugReportApp/tests/AndroidManifest.xml
+++ b/tests/BugReportApp/tests/AndroidManifest.xml
@@ -16,7 +16,7 @@
   -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.google.android.car.bugreport.tests" >
+    package="com.android.car.bugreport.tests" >
 
     <application>
         <uses-library android:name="android.test.runner" />
@@ -25,5 +25,5 @@
     <instrumentation
             android:name="android.support.test.runner.AndroidJUnitRunner"
             android:label="BugReportAppTest"
-            android:targetPackage="com.google.android.car.bugreport" />
+            android:targetPackage="com.android.car.bugreport" />
 </manifest>
diff --git a/tests/BugReportApp/tests/src/com/google/android/car/bugreport/BugStorageUtilsTest.java b/tests/BugReportApp/tests/src/com/google/android/car/bugreport/BugStorageUtilsTest.java
index 747cac4..29dcc19 100644
--- a/tests/BugReportApp/tests/src/com/google/android/car/bugreport/BugStorageUtilsTest.java
+++ b/tests/BugReportApp/tests/src/com/google/android/car/bugreport/BugStorageUtilsTest.java
@@ -13,10 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.google.android.car.bugreport;
+package com.android.car.bugreport;
 
-import static com.google.android.car.bugreport.MetaBugReport.TYPE_INTERACTIVE;
-import static com.google.android.car.bugreport.Status.STATUS_PENDING_USER_ACTION;
+import static com.android.car.bugreport.MetaBugReport.TYPE_INTERACTIVE;
+import static com.android.car.bugreport.Status.STATUS_PENDING_USER_ACTION;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertTrue;
diff --git a/tests/BugReportApp/utils/bugreport_app_tester.py b/tests/BugReportApp/utils/bugreport_app_tester.py
index e86f827..66d6f11 100755
--- a/tests/BugReportApp/utils/bugreport_app_tester.py
+++ b/tests/BugReportApp/utils/bugreport_app_tester.py
@@ -53,13 +53,13 @@
 
 VERSION = '0.2.0'
 
-BUGREPORT_PACKAGE = 'com.google.android.car.bugreport'
+BUGREPORT_PACKAGE = 'com.android.car.bugreport'
 PENDING_BUGREPORTS_DIR = ('/data/user/0/%s/bug_reports_pending' %
                           BUGREPORT_PACKAGE)
 SQLITE_DB_DIR = '/data/user/0/%s/databases' % BUGREPORT_PACKAGE
 SQLITE_DB_PATH = SQLITE_DB_DIR + '/bugreport.db'
 
-# The statuses are from `src/com/google/android/car/bugreport/Status.java.
+# The statuses are from `src/com.android.car.bugreport/Status.java.
 STATUS_WRITE_PENDING = 0
 STATUS_WRITE_FAILED = 1
 STATUS_UPLOAD_PENDING = 2
diff --git a/tests/BugReportApp/utils/bugreport_app_tester_test.py b/tests/BugReportApp/utils/bugreport_app_tester_test.py
index fd655f4..3a7198f 100644
--- a/tests/BugReportApp/utils/bugreport_app_tester_test.py
+++ b/tests/BugReportApp/utils/bugreport_app_tester_test.py
@@ -81,13 +81,13 @@
 
   def test_delete_all_bugreports(self):
     self._subject._delete_all_bugreports()
-    self.assertEqual(len(self._mock_device.adbx.calls), 2)
-    self.assertEqual(self._mock_device.adbx.calls[0]['args'][0], [
-        'shell', 'rm', '-f', '/data/user/0/com.google.android.car.bugreport/'
+    self.assertEqual(len(self._mock_device.adb.calls), 2)
+    self.assertEqual(self._mock_device.adb.calls[0]['args'][0], [
+        'shell', 'rm', '-f', '/data/user/0/com.android.car.bugreport/'
         'bug_reports_pending/*.zip'
     ])
-    self.assertEqual(self._mock_device.adbx.calls[1]['args'][0], [
-        'shell', 'sqlite3', '/data/user/0/com.google.android.car.bugreport/'
+    self.assertEqual(self._mock_device.adb.calls[1]['args'][0], [
+        'shell', 'sqlite3', '/data/user/0/com.android.car.bugreport/'
         'databases/bugreport.db', "'delete from bugreports;'"
     ])
 
@@ -96,7 +96,7 @@
     self.assertEqual(len(self._mock_device.adbx.calls), 1)
     self.assertEqual(self._mock_device.adbx.calls[0]['args'][0], [
         'shell', 'am', 'start',
-        'com.google.android.car.bugreport/.BugReportActivity'
+        'com.android.car.bugreport/.BugReportActivity'
     ])
 
 
diff --git a/tests/CarCtsDummyLauncher/Android.mk b/tests/CarCtsDummyLauncher/Android.mk
index 6382471..fec1106 100644
--- a/tests/CarCtsDummyLauncher/Android.mk
+++ b/tests/CarCtsDummyLauncher/Android.mk
@@ -17,17 +17,15 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_TAGS := optional
 
 # Only compile source java files in this apk.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_PACKAGE_NAME := CarCtsDummyLauncher
 
-LOCAL_SDK_VERSION := current
+LOCAL_PRIVATE_PLATFORM_APIS := true
 
-LOCAL_DEX_PREOPT := false
-
-LOCAL_CERTIFICATE := platform
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 include $(BUILD_PACKAGE)
diff --git a/tests/CarCtsDummyLauncher/AndroidManifest.xml b/tests/CarCtsDummyLauncher/AndroidManifest.xml
index 7f88233..32ada71 100644
--- a/tests/CarCtsDummyLauncher/AndroidManifest.xml
+++ b/tests/CarCtsDummyLauncher/AndroidManifest.xml
@@ -24,8 +24,14 @@
         <activity
             android:name=".LauncherActivity"
             android:label="@string/app_name"
-            android:theme="@android:style/Theme.Material.Light.DarkActionBar"
-            android:launchMode="singleTop">
+            android:configChanges="uiMode|mcc|mnc"
+            android:alwaysRetainTaskState="true"
+            android:launchMode="singleTask"
+            android:clearTaskOnLaunch="true"
+            android:stateNotNeeded="true"
+            android:resumeWhilePausing="true"
+            android:windowSoftInputMode="adjustPan"
+            android:theme="@android:style/Theme.NoTitleBar">
             <meta-data android:name="distractionOptimized" android:value="true"/>
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/tests/CarCtsDummyLauncher/res/layout/launcher_activity.xml b/tests/CarCtsDummyLauncher/res/layout/launcher_activity.xml
index 224404f..350f4f3 100644
--- a/tests/CarCtsDummyLauncher/res/layout/launcher_activity.xml
+++ b/tests/CarCtsDummyLauncher/res/layout/launcher_activity.xml
@@ -14,7 +14,8 @@
      limitations under the License.
 -->
 
-<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text"
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/message"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:gravity="center_vertical|center_horizontal"
diff --git a/tests/CarCtsDummyLauncher/src/com/android/car/dummylauncher/LauncherActivity.java b/tests/CarCtsDummyLauncher/src/com/android/car/dummylauncher/LauncherActivity.java
index 71b3c2b..7111700 100644
--- a/tests/CarCtsDummyLauncher/src/com/android/car/dummylauncher/LauncherActivity.java
+++ b/tests/CarCtsDummyLauncher/src/com/android/car/dummylauncher/LauncherActivity.java
@@ -17,8 +17,13 @@
 package com.android.car.dummylauncher;
 
 import android.app.Activity;
+import android.content.Intent;
 import android.os.Bundle;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.util.Log;
 import android.view.View;
+import android.widget.TextView;
 
 /**
  * A dummy launcher for CTS.
@@ -27,13 +32,76 @@
  * for CTS and they make CTS fail.
  */
 public class LauncherActivity extends Activity {
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
+    private static final String TAG = "DummyLauncher";
 
+    private int mUserId = UserHandle.USER_NULL;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        mUserId = UserHandle.myUserId();
+        Log.i(TAG, "pre.onCreate(): userId=" + mUserId);
+        super.onCreate(savedInstanceState);
+        Log.i(TAG, "post.onCreate(): userId=" + mUserId);
         View view = getLayoutInflater().inflate(R.layout.launcher_activity, null);
         setContentView(view);
+
+        TextView message = findViewById(R.id.message);
+        message.setText(message.getText() + "\n\nI am user " + mUserId);
         reportFullyDrawn();
+        Log.i(TAG, "done.onCreate(): userId=" + mUserId);
+    }
+
+    @Override
+    protected void onResume() {
+        Trace.traceBegin(Trace.TRACE_TAG_APP, "onResume-" + mUserId);
+        Log.i(TAG, "pre.onResume(): userId=" + mUserId);
+        super.onResume();
+        Log.i(TAG, "post.onResume(): userId=" + mUserId);
+        Trace.traceEnd(Trace.TRACE_TAG_APP);
+    }
+
+    @Override
+    protected void onPostResume() {
+        Trace.traceBegin(Trace.TRACE_TAG_APP, "onPostResume-" + mUserId);
+        Log.i(TAG, "pre.onPostResume(): userId=" + mUserId);
+        super.onPostResume();
+        Log.i(TAG, "post.onPostResume(): userId=" + mUserId);
+        Trace.traceEnd(Trace.TRACE_TAG_APP);
+    }
+
+    @Override
+    protected void onRestart() {
+        Log.i(TAG, "pre.onRestart(): userId=" + mUserId);
+        super.onRestart();
+        Log.i(TAG, "post.onRestart(): userId=" + mUserId);
+    }
+
+    @Override
+    public void onActivityReenter(int resultCode, Intent data) {
+        Log.i(TAG, "pre.onActivityReenter(): userId=" + mUserId);
+        super.onActivityReenter(resultCode, data);
+        Log.i(TAG, "post.onActivityReenter(): userId=" + mUserId);
+    }
+
+    @Override
+    public void onEnterAnimationComplete() {
+        Log.i(TAG, "pre.onEnterAnimationComplete(): userId=" + mUserId);
+        super.onEnterAnimationComplete();
+        Log.i(TAG, "post.onEnterAnimationComplete(): userId=" + mUserId);
+    }
+
+    @Override
+    protected void onStop() {
+        Log.i(TAG, "pre.onStop(): userId=" + mUserId);
+        super.onStop();
+        Log.i(TAG, "post.onStop(): userId=" + mUserId);
+    }
+
+    @Override
+    protected void onDestroy() {
+        Log.i(TAG, "pre.onDestroy(): userId=" + mUserId);
+        super.onDestroy();
+        Log.i(TAG, "post.onDestroy(): userId=" + mUserId);
     }
 }
 
diff --git a/tests/CarDeveloperOptions/Android.mk b/tests/CarDeveloperOptions/Android.mk
index 4ae3a4f..4523962 100644
--- a/tests/CarDeveloperOptions/Android.mk
+++ b/tests/CarDeveloperOptions/Android.mk
@@ -29,7 +29,7 @@
 LOCAL_PACKAGE_NAME := CarDeveloperOptions
 LOCAL_PRIVATE_PLATFORM_APIS := true
 LOCAL_CERTIFICATE := platform
-LOCAL_PRODUCT_MODULE := true
+LOCAL_SYSTEM_EXT_MODULE := true
 LOCAL_PRIVILEGED_MODULE := true
 LOCAL_REQUIRED_MODULES := privapp_whitelist_com.android.car.developeroptions
 LOCAL_MODULE_TAGS := optional
@@ -65,6 +65,7 @@
     carsettings-contextual-card-protos-lite \
     carsettings-log-bridge-protos-lite \
     carsettings-logtags \
+    statslog-settings \
     zxing-core-1.7
 
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
diff --git a/tests/CarDeveloperOptions/AndroidManifest.xml b/tests/CarDeveloperOptions/AndroidManifest.xml
index 046b386..436d7f0 100644
--- a/tests/CarDeveloperOptions/AndroidManifest.xml
+++ b/tests/CarDeveloperOptions/AndroidManifest.xml
@@ -53,6 +53,7 @@
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
     <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
     <uses-permission android:name="android.permission.WRITE_APN_SETTINGS"/>
@@ -84,7 +85,7 @@
     <uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
     <uses-permission android:name="android.permission.CONFIGURE_DISPLAY_COLOR_MODE" />
     <uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
-    <uses-permission android:name="android.permission.SET_TIME" />
+    <uses-permission android:name="android.permission.SUGGEST_MANUAL_TIME_AND_ZONE" />
     <uses-permission android:name="android.permission.ACCESS_NOTIFICATIONS" />
     <uses-permission android:name="android.permission.REBOOT" />
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
diff --git a/tests/CarDeveloperOptions/CleanSpec.mk b/tests/CarDeveloperOptions/CleanSpec.mk
index 332cf56..18b7928 100644
--- a/tests/CarDeveloperOptions/CleanSpec.mk
+++ b/tests/CarDeveloperOptions/CleanSpec.mk
@@ -47,6 +47,8 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Settings_intermediates)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Settings_intermediates)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/Settings)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/priv-app/CarDeveloperOptions)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/priv-app/CarDeveloperOptions)
 
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/tests/CarDeveloperOptions/OWNERS b/tests/CarDeveloperOptions/OWNERS
index efbf20d..b57ecbb 100644
--- a/tests/CarDeveloperOptions/OWNERS
+++ b/tests/CarDeveloperOptions/OWNERS
@@ -1,21 +1,18 @@
 # Use these reviewers by default.
-davidln@google.com
 hseog@google.com
 johnchoi@google.com
 kwaky@google.com
 priyanksingh@google.com
 stenning@google.com
+ericberglund@google.com
+jianyliu@google.com
 
 # People who can originally approve code for Settings.
-asapperstein@google.com
-asargent@google.com
-dehboxturtle@google.com
-dhnishi@google.com
-dling@google.com
-jackqdyulei@google.com
-mfritze@google.com
-zhfan@google.com
-miket@google.com
+edgarwang@google.com
+emilychuang@google.com
+tmfang@google.com
+
+# Emergency approvers in case the above are not available
 
 # Exempt resource files (because they are in a flat directory and too hard to manage via OWNERS)
-per-file *.xml=*
\ No newline at end of file
+per-file *.xml=*
diff --git a/tests/CarDeveloperOptions/res/values-af/arrays.xml b/tests/CarDeveloperOptions/res/values-af/arrays.xml
index 3b24efc..eee8364 100644
--- a/tests/CarDeveloperOptions/res/values-af/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-af/arrays.xml
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"Moet nooit toelaat dat"</item>
     <item msgid="8184570120217958741">"Laat altyd toe"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normaal"</item>
+    <item msgid="5101233285497327432">"Matig"</item>
+    <item msgid="1555861583162930714">"Laag"</item>
+    <item msgid="1719683776264798117">"Kritiek"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normaal"</item>
+    <item msgid="6107138933849816768">"Matig"</item>
+    <item msgid="182695359839047859">"Laag"</item>
+    <item msgid="8577246509202964244">"Kritiek"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Aanhoudend"</item>
     <item msgid="167418068739176448">"Topaktiwiteit"</item>
diff --git a/tests/CarDeveloperOptions/res/values-af/config.xml b/tests/CarDeveloperOptions/res/values-af/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-af/config.xml
+++ b/tests/CarDeveloperOptions/res/values-af/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-af/strings.xml b/tests/CarDeveloperOptions/res/values-af/strings.xml
index 6b63259..9857323 100644
--- a/tests/CarDeveloperOptions/res/values-af/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-af/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Maak die teks op die skerm kleiner of groter."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Maak kleiner"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Maak groter"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Voorbeeldteks"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Die Wonderlike Towenaar van Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Hoofstuk 11: Die Wonderlike Smaragstad van Oz"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Moet minder as <xliff:g id="NUMBER_1">%d</xliff:g> syfers wees</item>
       <item quantity="one">Moet minder as <xliff:g id="NUMBER_0">%d</xliff:g> syfer wees</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Mag net syfers 0-9 bevat"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Toesteladministrateur laat nie toe dat jy \'n onlangse PIN gebruik nie"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Jou IT-administrateur blokkeer algemene PIN\'e. Probeer \'n ander PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Dit mag nie \'n ongeldige karakter insluit nie"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Moet minstens <xliff:g id="COUNT">%d</xliff:g> nieletterkarakters bevat</item>
       <item quantity="one">Moet minstens 1 nieletterkarakter bevat</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Moet minstens <xliff:g id="COUNT">%d</xliff:g> nienumeriese karakters bevat</item>
+      <item quantity="one">Moet minstens 1 nienumeriese karakter bevat</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Toesteladministrateur laat nie toe dat jy \'n onlangse wagwoord gebruik nie"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Jou IT-administrateur blokkeer algemene wagwoorde. Probeer \'n ander wagwoord."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Stygende, dalende of herhalende volgorde van syfers word nie toegelaat nie"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mobiel"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"As Wi-Fi onbeskikbaar is, moet jy mobiele netwerk gebruik"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"As mobiele netwerk onbeskikbaar is, gebruik Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Bel oor Wi-Fi. Die oproep sal eindig as jy nie meer Wi-Fi het nie."</string>
@@ -2304,9 +2309,9 @@
       <item quantity="other">Beperk %1$d programme?</item>
       <item quantity="one">Beperk program?</item>
     </plurals>
-    <string name="battery_tip_restrict_app_dialog_message" msgid="6905822297507947381">"Om batterykrag te bespaar, keer <xliff:g id="APP">%1$s</xliff:g> om die battery op die agtergrond te gebruik. Hierdie program sal dalk nie behoorlik werk nie en kennisgewings sal dalk vertraag word."</string>
-    <string name="battery_tip_restrict_apps_less_than_5_dialog_message" msgid="4225881888543582456">"Om batterykrag te bespaar, keer hierdie programme om die battery op die agtergrond te gebruik. Beperkte programme sal dalk nie behoorlik werk nie en kennisgewings sal dalk vertraag word.\n\nProgramme:"</string>
-    <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"Om batterykrag te bespaar, keer hierdie programme om die battery op die agtergrond te gebruik. Beperkte programme sal dalk nie behoorlik werk nie en kennisgewings sal dalk vertraag word.\n\nProgramme:\n<xliff:g id="APP_LIST">%1$s</xliff:g>."</string>
+    <string name="battery_tip_restrict_app_dialog_message" msgid="6905822297507947381">"Verhoed <xliff:g id="APP">%1$s</xliff:g> om die battery op die agtergrond te gebruik om so batterykrag te bespaar. Hierdie program sal dalk nie behoorlik werk nie en kennisgewings sal dalk vertraag word."</string>
+    <string name="battery_tip_restrict_apps_less_than_5_dialog_message" msgid="4225881888543582456">"Verhoed hierdie programme om die battery op die agtergrond te gebruik om so batterykrag te bespaar. Beperkte programme sal dalk nie behoorlik werk nie en kennisgewings sal dalk vertraag word.\n\nProgramme:"</string>
+    <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"Verhoed hierdie programme om die battery op die agtergrond te gebruik om so batterykrag te bespaar. Beperkte programme sal dalk nie behoorlik werk nie en kennisgewings sal dalk vertraag word.\n\nProgramme:\n<xliff:g id="APP_LIST">%1$s</xliff:g>."</string>
     <string name="battery_tip_restrict_app_dialog_ok" msgid="2573410775701913487">"Beperk"</string>
     <string name="battery_tip_unrestrict_app_dialog_title" msgid="812458516399125710">"Verwyder beperking?"</string>
     <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"Hierdie program sal batterykrag op die agtergrond kan gebruik. Jou battery sal dalk gouer as verwag afloop."</string>
@@ -2624,8 +2629,8 @@
     <string name="remove_account_label" msgid="5885425720323823387">"Verwyder rekening"</string>
     <string name="header_add_an_account" msgid="8482614556580804956">"Voeg \'n rekening by"</string>
     <string name="really_remove_account_title" msgid="4166512362915154319">"Verwyder rekening?"</string>
-    <string name="really_remove_account_message" product="tablet" msgid="7403843371045856719">"Verwydering van hierdie rekening sal ook al sy boodskappe, kontakte en ander data van die tablet uitvee."</string>
-    <string name="really_remove_account_message" product="default" msgid="8951224626153163914">"Verwydering van hierdie rekening sal ook al sy boodskappe, kontakte en ander data van die foon uitvee."</string>
+    <string name="really_remove_account_message" product="tablet" msgid="7403843371045856719">"Verwydering van hierdie rekening sal ook al sy boodskappe, kontakte en ander data van die tablet af uitvee."</string>
+    <string name="really_remove_account_message" product="default" msgid="8951224626153163914">"Verwydering van hierdie rekening sal ook al sy boodskappe, kontakte en ander data van die foon af uitvee."</string>
     <string name="really_remove_account_message" product="device" msgid="3751798556257519916">"As hierdie rekening verwyder word, sal al sy boodskappe, kontakte en ander data van die toestel af uitgevee word!"</string>
     <string name="remove_account_failed" msgid="491458185327106966">"Hierdie verandering word nie deur jou administrateur toegelaat nie"</string>
     <string name="cant_sync_dialog_title" msgid="5483419398223189881">"Kan nie handmatig sinkroniseer nie"</string>
@@ -3703,7 +3708,7 @@
     </plurals>
     <string name="high_power_filter_on" msgid="5294209328473386403">"Nie geoptimeer nie"</string>
     <string name="high_power_on" msgid="3573501822510580334">"Nie geoptimeer nie"</string>
-    <string name="high_power_off" msgid="5906679734326490426">"Optimaliseer batterygebruik"</string>
+    <string name="high_power_off" msgid="5906679734326490426">"Optimeer batterygebruik"</string>
     <string name="high_power_system" msgid="739584574711292753">"Batteryoptimering is nie beskikbaar nie"</string>
     <string name="high_power_desc" msgid="333756885680362741">"Moenie batteryoptimering toepas nie. Dit kan jou battery dalk vinniger pap maak."</string>
     <string name="high_power_prompt_title" msgid="2805745781720454052">"Laat program altyd in die agtergrond loop?"</string>
diff --git a/tests/CarDeveloperOptions/res/values-am/arrays.xml b/tests/CarDeveloperOptions/res/values-am/arrays.xml
index 46bbc7e..acbc14e 100644
--- a/tests/CarDeveloperOptions/res/values-am/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-am/arrays.xml
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"በጭራሽ አትፍቀድ"</item>
     <item msgid="8184570120217958741">"ሁልጊዜ ፍቀድ"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"መደበኛ"</item>
+    <item msgid="5101233285497327432">"መጠነኛ"</item>
+    <item msgid="1555861583162930714">"ዝቅተኛ"</item>
+    <item msgid="1719683776264798117">"አሳሳቢ"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"መደበኛ"</item>
+    <item msgid="6107138933849816768">"መጠነኛ"</item>
+    <item msgid="182695359839047859">"ዝቅተኛ"</item>
+    <item msgid="8577246509202964244">"አሳሳቢ"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"የሚጸና"</item>
     <item msgid="167418068739176448">"ከፍተኛ እንቅስቃሴ"</item>
diff --git a/tests/CarDeveloperOptions/res/values-am/config.xml b/tests/CarDeveloperOptions/res/values-am/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-am/config.xml
+++ b/tests/CarDeveloperOptions/res/values-am/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-am/strings.xml b/tests/CarDeveloperOptions/res/values-am/strings.xml
index 8cc3ee5..ba77bc5 100644
--- a/tests/CarDeveloperOptions/res/values-am/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-am/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"በማያ ገጽ ላይ ያለውን ጽሑፍ ያሳንሱ ወይም ያተልቁ።"</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"አነስ አድርግ"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"ተለቅ አድርግ"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"የናሙና ጽሑፍ"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"አስደናቂው የኦዝ ምትሃተኛ"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"ምዕራፍ 11፦ ኦዝ፣ አስደናቂዋ የኤምራልድ ከተማ"</string>
@@ -197,7 +196,7 @@
     <string name="proxy_settings_title" msgid="6014901859338211713">"ተኪ"</string>
     <string name="proxy_clear_text" msgid="498317431076294101">"አጽዳ"</string>
     <string name="proxy_port_label" msgid="8285157632538848509">"የእጅ አዙርወደብ"</string>
-    <string name="proxy_exclusionlist_label" msgid="8179084955547941904">"የእጅ አዙሩን በጎንእለፍ"</string>
+    <string name="proxy_exclusionlist_label" msgid="8179084955547941904">"የእጅ አዙሩን በጎን እለፍ"</string>
     <string name="proxy_defaultView_text" msgid="5785775257042403261">"ወደ ነባሪዎች  እነበረበት መልስ"</string>
     <string name="proxy_action_text" msgid="814511434843981413">"ተከናውኗል"</string>
     <string name="proxy_hostname_label" msgid="6798891831427287847">"የእጅ አዙር ስመ ካዳም"</string>
@@ -668,7 +667,6 @@
       <item quantity="one">ከ<xliff:g id="NUMBER_1">%d</xliff:g> አሃዞች ያነሰ መሆን አለበት</item>
       <item quantity="other">ከ<xliff:g id="NUMBER_1">%d</xliff:g> አሃዞች ያነሰ መሆን አለበት</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"ከ0-9 የሆኑ አሃዞችን ብቻ ነው መያዝ አለበት"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"የመሣሪያ አስተዳዳሪው የቅርብ ጊዜ ፒን መጠቀም አይፈቅድም"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"የተለመዱ ፒኖች በአይቲ አስተዳዳሪዎ የታገዱ ናቸው። የተለየ ፒን ይሞክሩ።"</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"ይህ ልክ ያልሆነ ቁምፊ ማካተት አይችልም"</string>
@@ -699,6 +697,10 @@
       <item quantity="one">ቢያንስ <xliff:g id="COUNT">%d</xliff:g> ፊደል ያልሆኑ ቁምፊዎችን መያዝ አለበት</item>
       <item quantity="other">ቢያንስ <xliff:g id="COUNT">%d</xliff:g> ፊደል ያልሆኑ ቁምፊዎችን መያዝ አለበት</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">ቢያንስ <xliff:g id="COUNT">%d</xliff:g> ቁጥር ያልሆኑ ቁምፊዎች ሊኖረው ይገባል</item>
+      <item quantity="other">ቢያንስ <xliff:g id="COUNT">%d</xliff:g> ቁጥር ያልሆኑ ቁምፊዎች ሊኖረው ይገባል</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"የመሣሪያ አስተዳዳሪው የቅርብ ጊዜ የይለፍ ቃልን መጠቀም አይፈቅድም"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"የተለመዱ የይለፍ ቃላት በአይቲ አስተዳዳሪዎ የታገዱ ናቸው። የተለየ የይለፍ ቃል ይሞክሩ።"</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"ሽቅብ፣ ቁልቁል ወይም ተደጋጋሚ የአኃዞች ተከታታይ አይፈቀድም"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"ተንቀሳቃሽ ስልክ"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Wi‑Fi የማይገኝ ከሆነ፣ የተንቀሳቃሽ ስልክ አውታረ መረብ ተጠቀም"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"የተንቀሳቃስሽ ስልክ አውታረ መረብ የማይገኝ ከሆነ፣ Wi‑Fi ይጠቀሙ"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"በ Wi-Fi በኩል ደውል። Wi‑Fi ከጠፋ፣ ጥሪ ያበቃል።"</string>
@@ -1522,7 +1527,7 @@
     <string name="battery_status_title" msgid="8731200319740671905">"የባትሪሁኔታ"</string>
     <string name="battery_level_title" msgid="5207775387973771646">"የባትሪደረጃ፡"</string>
     <string name="apn_settings" msgid="8130776653826271664">"APNs"</string>
-    <string name="apn_edit" msgid="4350571070853305357">"የድረስ ነጥብ አርትዕ"</string>
+    <string name="apn_edit" msgid="4350571070853305357">"የመዳረሻ ነጥብ አርትዕ"</string>
     <string name="apn_not_set" msgid="5344235604466825691">"አልተዘጋጀም"</string>
     <string name="apn_name" msgid="8431432886706852226">"ስም"</string>
     <string name="apn_apn" msgid="190519449579357696">"APN"</string>
@@ -2446,7 +2451,7 @@
     <string name="battery_saver_auto_no_schedule" msgid="739814529432092706">"ምንም መርሐግብር የለም"</string>
     <string name="battery_saver_auto_routine" msgid="886514412067906980">"በዕለታዊ ተግባርዎ ላይ የተመሠረተ"</string>
     <string name="battery_saver_auto_percentage" msgid="5791982309331921556">"በመቶኛ ላይ የተመሠረተ"</string>
-    <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"በተመልዶ ባትሪዎ ከሚሞሉበት ቀጣዩ ጊዜ በፊት ባትሪዎ የማለቅ ዕድሉ ከፍ ያለ ከሆነ ባትሪ ቆጣቢ ይበራል።"</string>
+    <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"በተለምዶ ባትሪዎ ከሚሞሉበት ቀጣዩ ጊዜ በፊት ባትሪዎ የማለቅ ዕድሉ ከፍ ያለ ከሆነ ባትሪ ቆጣቢ ይበራል።"</string>
     <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"<xliff:g id="PERCENT">%1$s</xliff:g> ላይ ይበራል"</string>
     <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"መርሐግብር ያቀናብሩ"</string>
     <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"ሙሉ በሙሉ ኃይል ሲሞላ አጥፋ"</string>
@@ -2487,7 +2492,7 @@
     <string name="menu_duration_12h" msgid="1435242738163843797">"12 ሰዓቶች"</string>
     <string name="menu_duration_1d" msgid="6476370834372352174">"1 ቀን"</string>
     <string name="menu_show_system" msgid="6315865548558708248">"ስርዓት አሳይ"</string>
-    <string name="menu_hide_system" msgid="8457027118873733782">"የመደበቂያ ስርዓት"</string>
+    <string name="menu_hide_system" msgid="8457027118873733782">"ስርዓት ደብቅ"</string>
     <string name="menu_show_percentage" msgid="6983272380729890884">"መቶኛዎችን አሳይ"</string>
     <string name="menu_use_uss" msgid="3765054705208926803">"ዩ ኤስ ኤስ ይጠቀሙ"</string>
     <string name="menu_proc_stats_type" msgid="2680179749566186247">"የስታቲስቲክስ አይነት"</string>
@@ -3078,7 +3083,7 @@
     <string name="keywords_location" msgid="6439463166207072559">"አቅራቢያ፣ አካባቢ፣ ታሪክ፣ ሪፖርት ማድረግ"</string>
     <string name="keywords_accounts" msgid="5908945725229306088">"መለያ"</string>
     <string name="keywords_users" msgid="5880705776023155640">"ገደብ፣ ገድብ፣ የተገደበ"</string>
-    <string name="keywords_keyboard_and_ime" msgid="3327265741354129990">"የጽሑፍ እርማት፣ ትክክል፣ ድምፅ፣ ንዘር፣ ራስ-ሰር፣ ቋንቋ፣ የጣት ምልክት፣ ጠቁም፣ የአስተያየት ጥቆማ፣ ገጽታ፣ የሚያስከፋ፣ ቃል፣ ተይብ፣ ስሜት ገላጭ ምስል፣ አለምአቀፍ"</string>
+    <string name="keywords_keyboard_and_ime" msgid="3327265741354129990">"የጽሑፍ እርማት፣ ትክክል፣ ድምፅ፣ ንዘር፣ ራስ-ሰር፣ ቋንቋ፣ የጣት ምልክት፣ ጠቁም፣ የአስተያየት ጥቆማ፣ ገጽታ፣ የሚያስከፋ፣ ቃል፣ ተይብ፣ ስሜት ገላጭ ምስል፣ ዓለምአቀፍ"</string>
     <string name="keywords_reset_apps" msgid="2645701455052020435">"ዳግም አስጀምር፣ ምርጫዎች፣ ነባሪ"</string>
     <string name="keywords_all_apps" msgid="846444448435698930">"መተግበሪያዎች፣ ውርድ፣ መተግበሪያዎች፣ ስርዓት"</string>
     <string name="keywords_app_permissions" msgid="8539841019997048500">"መተግበሪያዎች፣ ፈቃዶች፣ ደህንነት"</string>
@@ -4353,7 +4358,7 @@
     <string name="preferred_network_mode_lte_summary" msgid="4281029367896990461">"ተመራጭ የአውታረ መረብ ሁነታ፦ LTE"</string>
     <string name="preferred_network_mode_lte_gsm_wcdma_summary" msgid="149627151786465701">"ተመራጭ የአውታረ መረብ ሁነታ፦ GSM/WCDMA/LTE"</string>
     <string name="preferred_network_mode_lte_cdma_evdo_summary" msgid="2892417308574212352">"ተመራጭ የአውታረ መረብ ሁነታ፦ CDMA+LTE/EVDO"</string>
-    <string name="preferred_network_mode_global_summary" msgid="487001671043476488">"ተመራጭ የአውታረ መረብ ሁነታ፦ አለምአቀፍ"</string>
+    <string name="preferred_network_mode_global_summary" msgid="487001671043476488">"ተመራጭ የአውታረ መረብ ሁነታ፦ ዓለምአቀፍ"</string>
     <string name="preferred_network_mode_lte_wcdma_summary" msgid="9029884385644299102">"ተመራጭ የአውታረ መረብ ሁነታ፦ LTE / WCDMA"</string>
     <string name="preferred_network_mode_lte_gsm_umts_summary" msgid="6583001637967763033">"ተመራጭ የአውታረ መረብ ሁነታ፦ LTE / GSM / UMTS"</string>
     <string name="preferred_network_mode_lte_cdma_summary" msgid="344294371859765484">"ተመራጭ የአውታረ መረብ ሁነታ፦ LTE / CDMA"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ar/arrays.xml b/tests/CarDeveloperOptions/res/values-ar/arrays.xml
index e6e5ee5..30c8a65 100644
--- a/tests/CarDeveloperOptions/res/values-ar/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-ar/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"التشغيل في الخلفية"</item>
     <item msgid="6423861043647911030">"مستوى صوت \"سهولة الاستخدام\""</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"الموقع"</item>
+    <item msgid="6656077694190491067">"الموقع"</item>
+    <item msgid="8790228218278477369">"الموقع"</item>
+    <item msgid="7836406246005211990">"اهتزاز"</item>
+    <item msgid="3951439024549922598">"قراءة جهات الاتصال"</item>
+    <item msgid="8802152411647068">"تعديل جهات الاتصال"</item>
+    <item msgid="229544934599698735">"قراءة سجل المكالمات"</item>
+    <item msgid="7396102294405899613">"تعديل سجل المكالمات"</item>
+    <item msgid="3597797992398484655">"قراءة التقويم"</item>
+    <item msgid="2705975774250907343">"تعديل التقويم"</item>
+    <item msgid="4668747371441932697">"الموقع"</item>
+    <item msgid="1487578921720243646">"نشر إشعار"</item>
+    <item msgid="4636080349724146638">"الموقع"</item>
+    <item msgid="673510900286463926">"اتصال هاتفي"</item>
+    <item msgid="542083422784609790">"قراءة الرسائل القصيرة SMS/رسائل الوسائط المتعددة"</item>
+    <item msgid="1033780373029588436">"كتابة الرسائل القصيرة SMS/رسائل الوسائط المتعددة"</item>
+    <item msgid="5647111115517787488">"تلقي الرسائل القصيرة SMS/رسائل الوسائط المتعددة"</item>
+    <item msgid="8591105601108455893">"تلقي الرسائل القصيرة SMS/رسائل الوسائط المتعددة"</item>
+    <item msgid="7730995008517841903">"تلقي الرسائل القصيرة SMS/رسائل الوسائط المتعددة"</item>
+    <item msgid="2613033109026626086">"تلقي الرسائل القصيرة SMS/رسائل الوسائط المتعددة"</item>
+    <item msgid="3037159047591081136">"إرسال الرسائل القصيرة SMS/رسائل الوسائط المتعددة"</item>
+    <item msgid="4726682243833913568">"قراءة الرسائل القصيرة SMS/رسائل الوسائط المتعددة"</item>
+    <item msgid="6555678522277865572">"كتابة الرسائل القصيرة SMS/رسائل الوسائط المتعددة"</item>
+    <item msgid="6981734935578130884">"تعديل الإعدادات"</item>
+    <item msgid="8705854389991425629">"رسم في الأعلى"</item>
+    <item msgid="5861356020344153651">"إشعارات الدخول"</item>
+    <item msgid="78432174621628659">"الكاميرا"</item>
+    <item msgid="3986116419882154794">"تسجيل الصوت"</item>
+    <item msgid="4516840825756409490">"تشغيل الصوت"</item>
+    <item msgid="6811712502798183957">"قراءة الحافظة"</item>
+    <item msgid="2780369012602289114">"تعديل الحافظة"</item>
+    <item msgid="2331359440170850868">"أزرار الوسائط"</item>
+    <item msgid="6133599737122751231">"التركيز على الصوت"</item>
+    <item msgid="6844485713404805301">"مستوى الصوت الرئيسي"</item>
+    <item msgid="1600379420669104929">"مستوى الصوت"</item>
+    <item msgid="6296768210470214866">"مستوى صوت الرنين"</item>
+    <item msgid="510690696071629241">"مستوى صوت الوسائط"</item>
+    <item msgid="406861638631430109">"مستوى صوت المنبّه"</item>
+    <item msgid="4715864795872233884">"مستوى صوت الإشعارات"</item>
+    <item msgid="2311478519251301183">"مستوى صوت البلوتوث"</item>
+    <item msgid="5133991377896747027">"ابق متيقظًا"</item>
+    <item msgid="2464189519136248621">"الموقع الجغرافي"</item>
+    <item msgid="2062677934050803037">"الموقع"</item>
+    <item msgid="1735171933192715957">"الحصول على إحصاءات الاستخدام"</item>
+    <item msgid="1014093788778383554">"كتم صوت/إلغاء كتم صوت الميكروفون"</item>
+    <item msgid="4199297950608622850">"عرض الإعلام المنبثق"</item>
+    <item msgid="2527962435313398821">"وسائط المشروع"</item>
+    <item msgid="5117506254221861929">"تفعيل الشبكة الافتراضية الخاصة"</item>
+    <item msgid="8291198322681891160">"كتابة الخلفية"</item>
+    <item msgid="7106921284621230961">"تركيبة مساعدة"</item>
+    <item msgid="4496533640894624799">"لقطة شاشة مساعدة"</item>
+    <item msgid="2598847264853993611">"قراءة حالة الهاتف"</item>
+    <item msgid="9215610846802973353">"إضافة بريد صوتي"</item>
+    <item msgid="9186411956086478261">"استخدام SIP"</item>
+    <item msgid="6884763100104539558">"معالجة المكالمات الصادرة"</item>
+    <item msgid="125513972170580692">"بصمة الإصبع"</item>
+    <item msgid="2556071024281275619">"أجهزة استشعار الجسم"</item>
+    <item msgid="617168514928339387">"قراءة رسائل البث الخلوي"</item>
+    <item msgid="7134693570516523585">"موقع وهمي"</item>
+    <item msgid="7224489175375229399">"قراءة مساحة التخزين"</item>
+    <item msgid="8472735063903258202">"كتابة مساحة التخزين"</item>
+    <item msgid="4069276819909595110">"تشغيل الشاشة"</item>
+    <item msgid="1228338896751121025">"الحصول على الحسابات"</item>
+    <item msgid="3181581793459233672">"التشغيل في الخلفية"</item>
+    <item msgid="2340936043025374076">"مستوى صوت \"سهولة الاستخدام\""</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"قصيرة"</item>
     <item msgid="4816511817309094890">"أهميّة متوسّطة"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"عدم السماح مطلقًا"</item>
     <item msgid="8184570120217958741">"السماح دومًا"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"عادية"</item>
+    <item msgid="5101233285497327432">"معتدلة"</item>
+    <item msgid="1555861583162930714">"منخفضة"</item>
+    <item msgid="1719683776264798117">"حرجة"</item>
+    <item msgid="1567326459340152525">"؟"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"عادية"</item>
+    <item msgid="6107138933849816768">"متوسطة"</item>
+    <item msgid="182695359839047859">"منخفضة"</item>
+    <item msgid="8577246509202964244">"حرجة"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"ثابتة"</item>
     <item msgid="167418068739176448">"أهم نشاط"</item>
diff --git a/tests/CarDeveloperOptions/res/values-ar/config.xml b/tests/CarDeveloperOptions/res/values-ar/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-ar/config.xml
+++ b/tests/CarDeveloperOptions/res/values-ar/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-ar/strings.xml b/tests/CarDeveloperOptions/res/values-ar/strings.xml
index de2eee3..fc4a397 100644
--- a/tests/CarDeveloperOptions/res/values-ar/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ar/strings.xml
@@ -87,8 +87,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"يمكنك تصغير النص الظاهر على الشاشة أو تكبيره."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"تصغير"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"تكبير"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"نموذج نص"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"ساحر أوز العجيب"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"الفصل ۱۱: مدينة أوز الزمردية العجيبة"</string>
@@ -212,8 +211,8 @@
     <string name="proxy_error_empty_port" msgid="8034561724923076215">"يلزمك إكمال حقل المنفذ."</string>
     <string name="proxy_error_empty_host_set_port" msgid="8471455809508588255">"يجب أن يكون حقل المنفذ فارغًا إذا كان حقل المضيف فارغًا."</string>
     <string name="proxy_error_invalid_port" msgid="4046559920586100637">"المنفذ الذي كتبته غير صالح."</string>
-    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"يستخدم المتصفح الخادم الوكيل HTTP، ولكنه ربما لا تستخدمه التطبيقات الأخرى."</string>
-    <string name="proxy_url_title" msgid="882042361706435904">"عنوان URL لتهيئة PAC: "</string>
+    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"يتم استخدام الخادم الوكيل HTTP على المتصفّح، ولكن قد لا تستخدمه التطبيقات الأخرى."</string>
+    <string name="proxy_url_title" msgid="882042361706435904">"عنوان URL لإعداد PAC: "</string>
     <string name="radio_info_dl_kbps" msgid="2903778264453410272">"معدّل نقل بيانات DL (كيلوبت في الثانية):"</string>
     <string name="radio_info_ul_kbps" msgid="3802245899811732716">"معدّل نقل بيانات UL (كيلوبت في الثانية):"</string>
     <string name="radio_info_signal_location_label" msgid="6788144906873498013">"معلومات الموقع الخلوية (تم الإيقاف):"</string>
@@ -359,7 +358,7 @@
     <string name="lock_after_timeout_summary" msgid="3160517585613694740">"<xliff:g id="TIMEOUT_STRING">%1$s</xliff:g> بعد السكون"</string>
     <string name="lock_immediately_summary_with_exception" msgid="6442552135409347556">"بعد السكون مباشرة، باستثناء عندما ميزة <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g> تبقي الجهاز مفتوحًا"</string>
     <string name="lock_after_timeout_summary_with_exception" msgid="7218267834086717545">"<xliff:g id="TIMEOUT_STRING">%1$s</xliff:g> بعد السكون، باستثناء عندما ميزة <xliff:g id="TRUST_AGENT_NAME">%2$s</xliff:g> تبقي الجهاز مفتوحًا"</string>
-    <string name="show_owner_info_on_lockscreen_label" msgid="4510756693837171575">"إظهار معلومات المالك في شاشة التأمين"</string>
+    <string name="show_owner_info_on_lockscreen_label" msgid="4510756693837171575">"إظهار معلومات المالك في شاشة القفل"</string>
     <string name="owner_info_settings_title" msgid="2537966178998339896">"رسالة شاشة القفل"</string>
     <string name="security_enable_widgets_title" msgid="1701510007926738088">"تفعيل الأدوات"</string>
     <string name="security_enable_widgets_disabled_summary" msgid="4408176087132339331">"تم إيقاف الإعداد بواسطة المشرف"</string>
@@ -373,7 +372,7 @@
     <string name="owner_info_settings_status" msgid="8049975536717685126">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="COUNT_1">%2$d</xliff:g>"</string>
     <string name="owner_info_settings_edit_text_hint" msgid="2250029417257939706">"جهاز Android الخاص بهاني مثلاً"</string>
     <string name="user_info_settings_title" msgid="1125111518759995748">"معلومات المستخدم"</string>
-    <string name="show_profile_info_on_lockscreen_label" msgid="5204282771893683026">"إظهار معلومات الملف الشخصي في شاشة التأمين"</string>
+    <string name="show_profile_info_on_lockscreen_label" msgid="5204282771893683026">"إظهار معلومات الملف الشخصي في شاشة القفل"</string>
     <string name="profile_info_settings_title" msgid="4855892878512562551">"معلومات الملف الشخصي"</string>
     <string name="Accounts_settings_title" msgid="7901374987121953746">"الحسابات"</string>
     <string name="location_settings_title" msgid="2707201457572301030">"الموقع الجغرافي"</string>
@@ -500,7 +499,7 @@
     <string name="lock_screen_pin_skip_title" msgid="8217519439213393785">"أتريد تخطي إعداد رقم التعريف الشخصي؟"</string>
     <string name="lock_screen_password_skip_title" msgid="3725788215672959827">"أتريد تخطّي إعداد كلمة المرور؟"</string>
     <string name="lock_screen_pattern_skip_title" msgid="4237030500353932005">"هل تريد تخطّي إعداد النقش؟"</string>
-    <string name="security_settings_fingerprint_enroll_setup_screen_lock" msgid="9036983528330627756">"إعداد تأمين الشاشة"</string>
+    <string name="security_settings_fingerprint_enroll_setup_screen_lock" msgid="9036983528330627756">"إعداد قفل الشاشة"</string>
     <string name="security_settings_fingerprint_enroll_done" msgid="4111289529758845926">"تم"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"عفوًا، هذا ليس جهاز الاستشعار"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"المس زر الاستشعار في الجزء الخلفي لهاتفك. استخدم إصبع السبابة."</string>
@@ -531,8 +530,8 @@
     <string name="crypt_keeper_button_text" product="default" msgid="8737394386627318489">"ترميز الهاتف"</string>
     <string name="crypt_keeper_low_charge_text" msgid="1422879728632636311">"اشحن البطارية وأعد المحاولة."</string>
     <string name="crypt_keeper_unplugged_text" msgid="6597684068340036200">"صل الشاحن وأعد المحاولة."</string>
-    <string name="crypt_keeper_dialog_need_password_title" msgid="8532211509636340535">"ليس هناك رقم تعريف شخصي (PIN) أو كلمة مرور لتأمين الشاشة"</string>
-    <string name="crypt_keeper_dialog_need_password_message" msgid="1341590897367808702">"يجب تعيين رقم تعريف شخصي أو كلمة مرور لتأمين الشاشة قبل أن تتمكن من بدء عملية التشفير."</string>
+    <string name="crypt_keeper_dialog_need_password_title" msgid="8532211509636340535">"ليس هناك رقم تعريف شخصي (PIN) أو كلمة مرور لقفل الشاشة"</string>
+    <string name="crypt_keeper_dialog_need_password_message" msgid="1341590897367808702">"يجب تعيين رقم تعريف شخصي أو كلمة مرور لقفل الشاشة قبل أن تتمكن من بدء عملية التشفير."</string>
     <string name="crypt_keeper_confirm_title" msgid="8884417036062084547">"التشفير؟"</string>
     <string name="crypt_keeper_final_desc" product="tablet" msgid="2713708841024805586">"لا يمكن التراجع عن عملية التشفير، وفي حالة مقاطعتها، ستفقد البيانات. تستغرق عملية التشفير ساعة أو أكثر، وسيتم خلالها إعادة تشغيل الجهاز اللوحي عدة مرات."</string>
     <string name="crypt_keeper_final_desc" product="default" msgid="2483549885938505746">"لا يمكن التراجع عن عملية التشفير، وفي حالة مقاطعتها، ستفقد البيانات. تستغرق عملية التشفير ساعة أو أكثر، وسيتم خلالها إعادة تشغيل الهاتف عدة مرات."</string>
@@ -577,9 +576,9 @@
     <string name="unlock_set_unlock_launch_picker_summary_lock_immediately" msgid="5596186270725220642">"<xliff:g id="UNLOCK_METHOD">%1$s</xliff:g> / بعد النوم مباشرة"</string>
     <string name="unlock_set_unlock_launch_picker_summary_lock_after_timeout" msgid="3861167251234952373">"<xliff:g id="UNLOCK_METHOD">%1$s</xliff:g> / <xliff:g id="TIMEOUT_STRING">%2$s</xliff:g> بعد النوم"</string>
     <string name="unlock_set_unlock_launch_picker_title_profile" msgid="7976345264630422921">"قفل الملف الشخصي للعمل"</string>
-    <string name="unlock_set_unlock_launch_picker_change_title" msgid="32310692507029407">"تغيير تأمين الشاشة"</string>
+    <string name="unlock_set_unlock_launch_picker_change_title" msgid="32310692507029407">"تغيير قفل الشاشة"</string>
     <string name="unlock_set_unlock_launch_picker_change_summary" msgid="2072792784866320522">"تغيير أو إيقاف النقش أو رمز PIN أو أمان كلمة المرور"</string>
-    <string name="unlock_set_unlock_launch_picker_enable_summary" msgid="9070847611379078795">"اختيار طريقة لتأمين الشاشة"</string>
+    <string name="unlock_set_unlock_launch_picker_enable_summary" msgid="9070847611379078795">"اختيار طريقة لقفل الشاشة"</string>
     <string name="unlock_set_unlock_off_title" msgid="5049876793411416079">"بدون"</string>
     <string name="unlock_set_unlock_off_summary" msgid="3997346045783359119"></string>
     <string name="unlock_set_unlock_none_title" msgid="1922027966983146392">"التمرير السريع"</string>
@@ -609,7 +608,7 @@
     <string name="unlock_set_unlock_mode_pin" msgid="7828354651668392875">"رقم تعريف شخصي"</string>
     <string name="unlock_set_unlock_mode_password" msgid="397703731925549447">"كلمة مرور"</string>
     <string name="unlock_setup_wizard_fingerprint_details" msgid="6515136915205473675">"بعد إعداد قفل شاشة، يمكنك أيضًا إعداد بصمة إصبعك في الإعدادات &gt; الأمان."</string>
-    <string name="unlock_disable_lock_title" msgid="3508492427073600294">"إيقاف تأمين الشاشة"</string>
+    <string name="unlock_disable_lock_title" msgid="3508492427073600294">"إيقاف قفل الشاشة"</string>
     <string name="unlock_disable_frp_warning_title" msgid="5858589970505254193">"هل تريد إزالة حماية الجهاز؟"</string>
     <string name="unlock_disable_frp_warning_title_profile" msgid="3814123014295965266">"هل تريد إزالة حماية الملف الشخصي؟"</string>
     <string name="unlock_disable_frp_warning_content_pattern" msgid="1843950215687159135">"لن تعمل ميزات حماية الجهاز بدون النقش."</string>
@@ -700,7 +699,6 @@
       <item quantity="other">يجب ألا يزيد رقم التعريف الشخصي عن <xliff:g id="NUMBER_1">%d</xliff:g> رقم.</item>
       <item quantity="one">يجب ألا يزيد رقم التعريف الشخصي عن رقم واحد (<xliff:g id="NUMBER_0">%d</xliff:g>).</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"يجب أن يحتوي رقم التعريف الشخصي على أرقام من ۰–٩ فقط."</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"لا يسمح مشرف الجهاز باستخدام رقم تعريف شخصي تم استخدامه مؤخرًا"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"حظرَ مشرف تكنولوجيا المعلومات استخدام أرقام التعريف الشخصية الشائعة. جرِّب استخدام رقم تعريف شخصي مختلف."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"لا يجب أن تتضمن كلمة المرور حرفًا غير صالح."</string>
@@ -755,6 +753,14 @@
       <item quantity="other">يجب أن تحتوي كلمة المرور على <xliff:g id="COUNT">%d</xliff:g> حرف ليس من الأحرف الأبجدية على الأقل</item>
       <item quantity="one">يجب أن تحتوي كلمة المرور على حرف واحد ليس من الأحرف الأبجدية على الأقل</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="zero">يجب أن تحتوي كلمة المرور على <xliff:g id="COUNT">%d</xliff:g> حرف أبجدي على الأقل.</item>
+      <item quantity="two">يجب أن تحتوي كلمة المرور على حرفين (<xliff:g id="COUNT">%d</xliff:g>) أبجديين على الأقل.</item>
+      <item quantity="few">يجب أن تحتوي كلمة المرور على <xliff:g id="COUNT">%d</xliff:g> أحرف أبجدية على الأقل.</item>
+      <item quantity="many">يجب أن تحتوي كلمة المرور على <xliff:g id="COUNT">%d</xliff:g> حرفًا أبجديًا على الأقل.</item>
+      <item quantity="other">يجب أن تحتوي كلمة المرور على <xliff:g id="COUNT">%d</xliff:g> حرف أبجدي على الأقل.</item>
+      <item quantity="one">يجب أن تحتوي كلمة المرور على حرف أبجدي واحد على الأقل.</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"لا يسمح مشرف الجهاز باستخدام كلمة مرور تم استخدامها مؤخرًا"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"حظرَ مشرف تكنولوجيا المعلومات استخدام كلمات المرور الشائعة. جرِّب استخدام كلمة مرور مختلفة."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"غير مسموح باستخدام الترتيب التصاعدي أو التنازلي أو المكرر للأرقام"</string>
@@ -985,7 +991,7 @@
     <string name="wifi_eap_anonymous" msgid="6352344972490839958">"هوية مجهولة"</string>
     <string name="wifi_password" msgid="6942983531275177771">"كلمة المرور"</string>
     <string name="wifi_show_password" msgid="7878398590772942202">"إظهار كلمة المرور"</string>
-    <string name="wifi_ap_band_config" msgid="6565016368079288433">"تحديد نطاق AP"</string>
+    <string name="wifi_ap_band_config" msgid="6565016368079288433">"اختيار نطاق AP"</string>
     <string name="wifi_ap_choose_auto" msgid="7927637960569365785">"تلقائي"</string>
     <string name="wifi_ap_choose_2G" msgid="43198403259714736">"نطاق بتردد ٢٫٤ غيغاهرتز"</string>
     <string name="wifi_ap_choose_5G" msgid="2624859713183683146">"نطاق بتردد ٥ غيغاهرتز"</string>
@@ -997,7 +1003,7 @@
     <string name="wifi_privacy_settings" msgid="4462092795794247809">"الخصوصية"</string>
     <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"عنوان MAC العشوائي"</string>
     <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"إضافة جهاز"</string>
-    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"توسيط رمز الاستجابة السريعة أدناه لإضافة الجهاز إلى \"<xliff:g id="SSID">%1$s</xliff:g>\""</string>
+    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"وضع رمز الاستجابة السريعة في الوسط أدناه لإضافة الجهاز إلى \"<xliff:g id="SSID">%1$s</xliff:g>\""</string>
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"المسح الضوئي لرمز الاستجابة السريعة"</string>
     <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"توسيط رمز الاستجابة السريعة أدناه للربط بالمعرِّف \"<xliff:g id="SSID">%1$s</xliff:g>\""</string>
     <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"يمكنك الانضمام إلى شبكة Wi‑Fi عن طريق المسح الضوئي لرمز مسح الاستجابة السريعة."</string>
@@ -1029,8 +1035,8 @@
     <string name="wifi_dpp_connect_network_using_qr_code" msgid="115993715600532357">"يمكنك الاتصال بهذه الشبكة باستخدام رمز استجابة سريعة."</string>
     <string name="retry" msgid="8500839563577344702">"إعادة المحاولة"</string>
     <string name="wifi_shared" msgid="5054256778276524960">"المشاركة مع مستخدمي الجهاز الآخرين"</string>
-    <string name="wifi_unchanged" msgid="6804964646942333992">"(لم يتم التغيير)"</string>
-    <string name="wifi_unspecified" msgid="893491188483500809">"يُرجى التحديد"</string>
+    <string name="wifi_unchanged" msgid="6804964646942333992">"(لم يتم تغييره)"</string>
+    <string name="wifi_unspecified" msgid="893491188483500809">"يُرجى الاختيار"</string>
     <string name="wifi_multiple_cert_added" msgid="7986200585749147204">"(تمت إضافة عدة شهادات)"</string>
     <string name="wifi_use_system_certs" msgid="4794489370929885022">"استخدام شهادات النظام"</string>
     <string name="wifi_do_not_provide_eap_user_cert" msgid="4044301449482425250">"عدم التوفير"</string>
@@ -1168,7 +1174,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"الجوّال"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"إذا لم تكن شبكة Wi-Fi متاحة، يمكنك استخدام شبكة الجوّال."</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"إذا لم تكن شبكة الجوّال متاحة، يمكنك استخدام شبكة Wi-Fi."</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"يمكنك الاتصال عبر شبكة Wi-Fi. وإذا لم تكن متوفرة، سيتم إنهاء المكالمة."</string>
@@ -1200,7 +1209,7 @@
     <string name="dock_settings_summary" msgid="3023630224867503210">"الإعدادات الصوتية للإرساء المرفق"</string>
     <string name="dtmf_tone_enable_title" msgid="3797301105270314782">"نغمات لمس لوحة الطلب"</string>
     <string name="sound_effects_enable_title" msgid="3693756476729696246">"أصوات النقر"</string>
-    <string name="lock_sounds_enable_title" msgid="6456726219456531315">"صوت تأمين الشاشة"</string>
+    <string name="lock_sounds_enable_title" msgid="6456726219456531315">"صوت قفل الشاشة"</string>
     <string name="audio_record_proc_title" msgid="5772134576781468721">"إلغاء الضجيج"</string>
     <string name="volume_media_description" msgid="3659485559976891268">"الموسيقى والفيديو والألعاب والوسائط الأخرى"</string>
     <string name="volume_ring_description" msgid="1975431532517579212">"نغمة الرنين والتنبيهات"</string>
@@ -1219,8 +1228,8 @@
     <string name="dock_audio_summary_none" product="default" msgid="2704912407397319084">"لم يتم إرساء الهاتف"</string>
     <string name="dock_audio_summary_unknown" msgid="1615958511030469507">"إعدادات الإرساء المرفق"</string>
     <string name="dock_not_found_title" msgid="2035088760477532435">"لم يتم العثور على الإرساء"</string>
-    <string name="dock_not_found_text" product="tablet" msgid="5996654431405111902">"يلزمك إرساء الجهاز اللوحي قبل تهيئة إعدادات الإرساء الصوتية."</string>
-    <string name="dock_not_found_text" product="default" msgid="8275091896320216368">"يلزمك إرساء الهاتف قبل تهيئة إعدادات الإرساء الصوتية."</string>
+    <string name="dock_not_found_text" product="tablet" msgid="5996654431405111902">"يلزمك إرساء الجهاز اللوحي قبل ضبط إعدادات الإرساء الصوتية."</string>
+    <string name="dock_not_found_text" product="default" msgid="8275091896320216368">"يلزمك إرساء الهاتف قبل ضبط إعدادات الإرساء الصوتية."</string>
     <string name="dock_sounds_enable_title" msgid="3385931465312084061">"صوت إدراج الإرساء"</string>
     <string name="dock_sounds_enable_summary_on" product="tablet" msgid="4322104626905111669">"تشغيل صوت أثناء إدراج الجهاز اللوحي أو إزالته من المرسى"</string>
     <string name="dock_sounds_enable_summary_on" product="default" msgid="2751810717801098293">"تشغيل الصوت عند إدراج أو إزالة الهاتف من الإرساء"</string>
@@ -1237,7 +1246,7 @@
     <string name="color_mode_title" msgid="8164858320869449142">"الألوان"</string>
     <string name="color_mode_option_natural" msgid="1292837781836645320">"طبيعي"</string>
     <string name="color_mode_option_boosted" msgid="453557938434778933">"مُحسن"</string>
-    <string name="color_mode_option_saturated" msgid="7758384943407859851">"مُشبع"</string>
+    <string name="color_mode_option_saturated" msgid="7758384943407859851">"مُشبعة"</string>
     <string name="color_mode_option_automatic" msgid="6572718611315165117">"توافقي"</string>
     <string name="color_mode_summary_natural" msgid="1247153893843263340">"استخدام الألوان الدقيقة فقط"</string>
     <string name="color_mode_summary_automatic" msgid="6066740785261330514">"ضبط إلى التبديل بين الألوان الزاهية والدقيقة"</string>
@@ -1264,7 +1273,7 @@
     <string name="auto_brightness_very_high_title" msgid="6649896560889239565">"مرتفع جدًا"</string>
     <string name="auto_brightness_subtitle" msgid="8516999348793100665">"مستوى السطوع المفضل بالنسبة لك"</string>
     <string name="auto_brightness_off_summary" msgid="6162650416289359104">"عدم ضبط السطوع بحسب الإضاءة المتاحة"</string>
-    <string name="auto_brightness_very_high_summary" msgid="7202032980509583918">"زيادة استخدام البطارية"</string>
+    <string name="auto_brightness_very_high_summary" msgid="7202032980509583918">"يزيد استخدام البطارية"</string>
     <string name="auto_brightness_disclaimer" msgid="5416696351199148809">"يمكنك تحسين مستوى السطوع حسب الإضاءة. وعند تفعيل هذه الميزة، سيظل بإمكانك ضبط السطوع مؤقتًا."</string>
     <string name="auto_brightness_description" msgid="8209140379089535411">"سيتم ضبط سطوع الشاشة تلقائيًا حسب البيئة المحيطة والأنشطة. ويمكنك تحريك شريط التمرير يدويًا لضبط السطوع التكيُّفي حسبما تفضّل."</string>
     <string name="display_white_balance_title" msgid="5747260735311935143">"موازنة اللون الأبيض للشاشة"</string>
@@ -1480,7 +1489,7 @@
     <string name="storage_menu_format" msgid="4285487419855632896">"تهيئة"</string>
     <string name="storage_menu_format_public" msgid="5361388353980722971">"تهيئة كوحدة تخزين محمولة"</string>
     <string name="storage_menu_format_private" msgid="5288599205435858720">"تهيئة كوحدة تخزين داخلية"</string>
-    <string name="storage_menu_migrate" msgid="1885806122515759703">"ترحيل البيانات"</string>
+    <string name="storage_menu_migrate" msgid="1885806122515759703">"نقل البيانات"</string>
     <string name="storage_menu_forget" msgid="4345021250834642640">"حذف"</string>
     <string name="storage_menu_set_up" msgid="2849170579745958513">"إعداد"</string>
     <string name="storage_menu_explore" msgid="3733439525636202662">"استكشاف"</string>
@@ -1594,7 +1603,7 @@
     <string name="battery_status_title" msgid="8731200319740671905">"حالة البطارية"</string>
     <string name="battery_level_title" msgid="5207775387973771646">"مستوى البطارية"</string>
     <string name="apn_settings" msgid="8130776653826271664">"أسماء نقاط الوصول"</string>
-    <string name="apn_edit" msgid="4350571070853305357">"تعديل نقطة الدخول"</string>
+    <string name="apn_edit" msgid="4350571070853305357">"تعديل نقطة الوصول"</string>
     <string name="apn_not_set" msgid="5344235604466825691">"لم يتم التعيين"</string>
     <string name="apn_name" msgid="8431432886706852226">"الاسم"</string>
     <string name="apn_apn" msgid="190519449579357696">"APN"</string>
@@ -1710,7 +1719,7 @@
     <string name="network_scorer_change_active_dialog_text" msgid="4264089809189760730">"هل تريد استخدام <xliff:g id="NEW_APP">%1$s</xliff:g> بدلاً من <xliff:g id="CURRENT_APP">%2$s</xliff:g> لإدارة اتصالات الشبكة لديك؟"</string>
     <string name="network_scorer_change_active_no_previous_dialog_text" msgid="6394483538843474495">"هل تريد استخدام <xliff:g id="NEW_APP">%s</xliff:g> لإدارة اتصالات الشبكة لديك؟"</string>
     <string name="mobile_unknown_sim_operator" msgid="872589370085135817">"مشغل SIM (مشغل شبكة الجوّال) غير معروف"</string>
-    <string name="mobile_no_provisioning_url" msgid="3216517414902166131">"ليس لدى <xliff:g id="OPERATOR">%1$s</xliff:g> موقع ويب معروف لإدارة حسابات"</string>
+    <string name="mobile_no_provisioning_url" msgid="3216517414902166131">"ليس لدى <xliff:g id="OPERATOR">%1$s</xliff:g> موقع إلكتروني معروف لإدارة حسابات"</string>
     <string name="mobile_insert_sim_card" msgid="7594550403454243732">"يُرجى إدخال شريحة SIM وإعادة التشغيل"</string>
     <string name="mobile_connect_to_internet" msgid="6031886097365170913">"يُرجى الاتصال بالإنترنت"</string>
     <string name="location_title" msgid="8664674161765477168">"موقعي"</string>
@@ -1753,8 +1762,8 @@
     <string name="location_sources_heading" msgid="8526658357120282741">"مصادر الموقع"</string>
     <string name="about_settings" product="tablet" msgid="4869626690708456341">"لمحة عن الجهاز اللوحي"</string>
     <string name="about_settings" product="default" msgid="6019547763377294261">"لمحة عن الهاتف"</string>
-    <string name="about_settings" product="device" msgid="1770438316234693655">"لمحة حول الجهاز"</string>
-    <string name="about_settings" product="emulator" msgid="4497482494770487014">"حول الجهاز في وضع المحاكاة"</string>
+    <string name="about_settings" product="device" msgid="1770438316234693655">"لمحة عن الجهاز"</string>
+    <string name="about_settings" product="emulator" msgid="4497482494770487014">"لمحة عن الجهاز في وضع المحاكاة"</string>
     <string name="about_settings_summary" msgid="4506081667462281647">"عرض المعلومات القانونية والحالة وإصدار البرنامج"</string>
     <string name="legal_information" msgid="2374267257615182139">"المعلومات القانونية"</string>
     <string name="contributors_title" msgid="6800028420806884340">"المساهمون"</string>
@@ -1790,8 +1799,8 @@
     <string name="lockpassword_confirm_passwords_dont_match" msgid="1783767008133345784">"كلمات المرور غير متطابقة"</string>
     <string name="lockpassword_confirm_pins_dont_match" msgid="5444357293637748942">"أرقام التعريف الشخصي غير متطابقة"</string>
     <string name="lockpassword_draw_your_pattern_again_header" msgid="9017394036814402348">"ارسم النقش مرة أخرى"</string>
-    <string name="lockpassword_choose_lock_generic_header" msgid="4418423132980560119">"تحديد طريقة فتح القفل"</string>
-    <string name="lockpassword_password_set_toast" msgid="601928982984489868">"تم تعيين كلمة المرور"</string>
+    <string name="lockpassword_choose_lock_generic_header" msgid="4418423132980560119">"اختيار طريقة فتح القفل"</string>
+    <string name="lockpassword_password_set_toast" msgid="601928982984489868">"تم ضبط كلمة المرور"</string>
     <string name="lockpassword_pin_set_toast" msgid="172594825722240059">"تم تعيين رمز PIN"</string>
     <string name="lockpassword_pattern_set_toast" msgid="6923260369475481406">"تم تعيين النقش"</string>
     <string name="lockpassword_choose_your_password_header_for_face" msgid="8823110536502072216">"لاستخدام المصادقة بالوجه، اضبط كلمة المرور"</string>
@@ -1834,7 +1843,7 @@
     <string name="lockpattern_continue_button_text" msgid="3328913552656376892">"متابعة"</string>
     <string name="lockpattern_settings_title" msgid="5152005866870766842">"نقش فتح القفل"</string>
     <string name="lockpattern_settings_enable_title" msgid="8508410891939268080">"النقش مطلوب"</string>
-    <string name="lockpattern_settings_enable_summary" msgid="8027605503917737512">"يجب رسم نقش لإلغاء تأمين الشاشة"</string>
+    <string name="lockpattern_settings_enable_summary" msgid="8027605503917737512">"يجب رسم نقش لإلغاء قفل الشاشة"</string>
     <string name="lockpattern_settings_enable_visible_pattern_title" msgid="4935583222709647096">"جعل النقش مرئيًا"</string>
     <string name="lockpattern_settings_enable_visible_pattern_title_profile" msgid="5338893138982642228">"إظهار نقش الملف الشخصي"</string>
     <string name="lockpattern_settings_enable_tactile_feedback_title" msgid="3203621862806531947">"اهتزاز عند النقر"</string>
@@ -1952,7 +1961,7 @@
     <string name="move_app_to_internal" product="default" msgid="1031111519418252055">"نقل إلى الهاتف"</string>
     <string name="move_app_to_sdcard" product="nosdcard" msgid="5555917755995563518">"نقل إلى وحدة تخزين USB"</string>
     <string name="move_app_to_sdcard" product="default" msgid="2348845109583354505">"نقل إلى بطاقة SD"</string>
-    <string name="another_migration_already_in_progress" msgid="3159694008286196454">"هناك عملية ترحيل أخرى قيد التقدم حاليًا."</string>
+    <string name="another_migration_already_in_progress" msgid="3159694008286196454">"هناك عملية نقل أخرى قيد التقدم حاليًا."</string>
     <string name="insufficient_storage" msgid="7089626244018569405">"ليست هناك مساحة تخزين كافية."</string>
     <string name="does_not_exist" msgid="4821267479183197109">"التطبيق غير موجود."</string>
     <string name="invalid_location" msgid="8057409982223429673">"موقع التثبيت غير صالح."</string>
@@ -2138,7 +2147,7 @@
     <string name="accessibility_screen_magnification_navbar_configuration_warning" msgid="6477234309484795550">"تم تعيين زر إمكانية الوصول لخدمة <xliff:g id="SERVICE">%1$s</xliff:g>. لاستخدام التكبير، المس زر إمكانية الوصول مع الاستمرار ثم اختر التكبير."</string>
     <string name="accessibility_global_gesture_preference_title" msgid="3842279082831426816">"مفتاح الاختصار لمستوى الصوت"</string>
     <string name="accessibility_shortcut_service_title" msgid="3516052294376744060">"خدمة الاختصار"</string>
-    <string name="accessibility_shortcut_service_on_lock_screen_title" msgid="1279441617927949980">"السماح من شاشة التأمين"</string>
+    <string name="accessibility_shortcut_service_on_lock_screen_title" msgid="1279441617927949980">"السماح من شاشة القفل"</string>
     <string name="accessibility_shortcut_description" msgid="1427049334225166395">"عندما يكون مفتاح الاختصار قيد التفعيل، يمكنك الضغط على مفتاحي مستوى الصوت لمدة 3 ثوانٍ لبدء تشغيل إحدى ميزات إمكانية الوصول."</string>
     <string name="accessibility_toggle_high_text_contrast_preference_title" msgid="5652244684961877255">"نص ذو درجة تباين عالية"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"التحديث التلقائي لتكبير الشاشة"</string>
@@ -2388,7 +2397,7 @@
     <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"قد تنفد البطارية قبل الوقت المعتاد."</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"تم تفعيل \"ميزة توفير شحن البطارية\"."</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"قد تكون بعض الميزات مقيّدة."</string>
-    <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"الهاتف المستخدَم أكثر من المعتاد"</string>
+    <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"مقدار استخدام الهاتف أكثر من المعتاد"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"الجهاز اللوحي المستخدَم أكثر من المعتاد"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"الجهاز المستخدَم أكثر من المعتاد"</string>
     <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"قد تنفد البطارية قبل الوقت المعتاد."</string>
@@ -2418,7 +2427,7 @@
       <item quantity="few">هناك %2$d تطبيقات تستخدم البطارية في الخلفية بدرجة عالية</item>
       <item quantity="many">هناك %2$d تطبيقًا يستخدم البطارية في الخلفية بدرجة عالية</item>
       <item quantity="other">هناك %2$d تطبيق يستخدم البطارية في الخلفية بدرجة عالية</item>
-      <item quantity="one">يستخدم تطبيق %1$s البطارية في الخلفية بدرجة عالية</item>
+      <item quantity="one">هناك تطبيق واحد (%1$s) يستخدم البطارية في الخلفية بدرجة عالية</item>
     </plurals>
     <plurals name="battery_tip_restrict_handled_summary" formatted="false" msgid="469696766640020557">
       <item quantity="zero">يتعذّر تشغيل هذه التطبيقات في الخلفية.</item>
@@ -2780,7 +2789,7 @@
     <string name="starting_android" msgid="4774187626261253089">"جارٍ تشغيل Android…"</string>
     <string name="delete" msgid="2325292565700865366">"حذف"</string>
     <string name="misc_files" msgid="1012397035001764693">"ملفات متنوعة"</string>
-    <string name="misc_files_selected_count" msgid="1434146080729502726">"تم تحديد <xliff:g id="NUMBER">%1$d</xliff:g> من إجمالي <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="misc_files_selected_count" msgid="1434146080729502726">"تم اختيار <xliff:g id="NUMBER">%1$d</xliff:g> من إجمالي <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="misc_files_selected_count_bytes" msgid="3752262902203465861">"<xliff:g id="NUMBER">%1$s</xliff:g> من إجمالي <xliff:g id="TOTAL">%2$s</xliff:g>"</string>
     <string name="select_all" msgid="452240217913675728">"اختيار الكل"</string>
     <string name="data_usage_summary_title" msgid="7288431048564861043">"استخدام البيانات"</string>
@@ -3032,7 +3041,7 @@
     <string name="user_cannot_manage_message" product="default" msgid="915260531390608092">"يمكن لمالك الهاتف فقط إدارة المستخدمين."</string>
     <string name="user_cannot_add_accounts_message" msgid="5993561303748749097">"لا يمكن للملفات الشخصية إضافة حسابات"</string>
     <string name="user_remove_user_menu" msgid="3505139157217459864">"حذف <xliff:g id="USER_NAME">%1$s</xliff:g> من هذا الجهاز"</string>
-    <string name="user_lockscreen_settings" msgid="3820813814848394568">"إعدادات شاشة التأمين"</string>
+    <string name="user_lockscreen_settings" msgid="3820813814848394568">"إعدادات شاشة القفل"</string>
     <string name="user_add_on_lockscreen_menu" msgid="5211604808199585774">"إضافة المستخدمين من شاشة القفل"</string>
     <string name="user_new_user_name" msgid="3880395219777884838">"مستخدم جديد"</string>
     <string name="user_new_profile_name" msgid="3074939718101489937">"ملف شخصي جديد"</string>
@@ -3076,7 +3085,7 @@
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"إلا إذا كان هناك تطبيق دفع آخر مفتوحًا"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"عند أحد أجهزة انقر وادفع الطرفية، يمكنك الدفع باستخدام:"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"الدفع عند الجهاز الطرفي"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"يمكنك إعداد تطبيق للدفع، وبعد ذلك لن يلزمك سوى توصيل الجزء الخلفي من الهاتف بأي جهاز طرفي يحتوي على رمز عدم لمس الجهاز."</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"يمكنك إعداد تطبيق للدفع، وبعد ذلك لن يلزمك سوى الإمساك بالجزء الخلفي من الهاتف أعلى جهاز طرفي يحتوي على رمز الدفع بدون تلامس الأجهزة."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"حسنًا"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"المزيد..."</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"هل تريد تعيينه كتفضيل؟"</string>
@@ -3134,7 +3143,7 @@
     <string name="wizard_finish" msgid="3742102879981212094">"إنهاء"</string>
     <string name="user_image_take_photo" msgid="2000247510236178111">"التقاط صورة"</string>
     <string name="user_image_choose_photo" msgid="4920315415203051898">"اختيار صورة"</string>
-    <string name="user_image_photo_selector" msgid="8429694590849882411">"تحديد صورة"</string>
+    <string name="user_image_photo_selector" msgid="8429694590849882411">"اختيار صورة"</string>
     <string name="regulatory_info_text" msgid="9112993912873512834"></string>
     <string name="sim_setup_wizard_title" msgid="77627575294867180">"بطاقات SIM"</string>
     <string name="sim_settings_title" msgid="8818243954752261922">"بطاقات SIM"</string>
@@ -3142,13 +3151,13 @@
     <string name="sim_cards_changed_message" msgid="1012486903583092731">"تم تغيير بطاقات SIM"</string>
     <string name="sim_cards_changed_message_summary" msgid="5753692480107865077">"انقر لتعيين الأنشطة."</string>
     <string name="sim_cellular_data_unavailable" msgid="1832472508352891641">"بيانات الجوّال غير متاحة"</string>
-    <string name="sim_cellular_data_unavailable_summary" msgid="3093797406601964131">"انقر لتحديد شريحة SIM للبيانات."</string>
+    <string name="sim_cellular_data_unavailable_summary" msgid="3093797406601964131">"انقر لاختيار شريحة SIM للبيانات."</string>
     <string name="sim_calls_always_use" msgid="5322696995795851734">"استخدام هذا للمكالمات دائمًا"</string>
-    <string name="select_sim_for_data" msgid="2099705792885526394">"تحديد شريحة SIM للبيانات"</string>
+    <string name="select_sim_for_data" msgid="2099705792885526394">"اختيار شريحة SIM للبيانات"</string>
     <string name="select_sim_for_sms" msgid="2481682560233370731">"اختيار شريحة SIM للرسائل القصيرة SMS"</string>
     <string name="data_switch_started" msgid="4517966162053949265">"جارٍ تبديل شريحة SIM للبيانات؛ قد يستغرق هذا مدة تصل إلى دقيقة..."</string>
     <string name="select_sim_for_calls" msgid="131091573472832807">"الاتصال باستخدام"</string>
-    <string name="sim_select_card" msgid="5558215843972182767">"تحديد شريحة SIM"</string>
+    <string name="sim_select_card" msgid="5558215843972182767">"اختيار شريحة SIM"</string>
     <string name="sim_card_number_title" msgid="8808663374497085634">"شريحة SIM <xliff:g id="CARD_NUMBER">%1$d</xliff:g>"</string>
     <string name="sim_slot_empty" msgid="2710430326225678239">"شريحة SIM فارغة"</string>
     <string name="sim_editor_name" msgid="3367549287943555967">"اسم شريحة SIM"</string>
@@ -3157,7 +3166,7 @@
     <string name="sim_editor_carrier" msgid="8860370077829961512">"مشغل شبكة الجوّال"</string>
     <string name="sim_editor_number" msgid="1757338150165234970">"الرقم"</string>
     <string name="sim_editor_color" msgid="373059962306191123">"لون شريحة SIM"</string>
-    <string name="sim_card_select_title" msgid="4925862525985187946">"تحديد شريحة SIM"</string>
+    <string name="sim_card_select_title" msgid="4925862525985187946">"اختيار شريحة SIM"</string>
     <string name="color_orange" msgid="3159707916066563431">"برتقالي"</string>
     <string name="color_purple" msgid="4391440966734810713">"أرجواني"</string>
     <string name="sim_no_inserted_msg" msgid="1197884607569714609">"لم يتم إدراج بطاقات SIM"</string>
@@ -3262,8 +3271,8 @@
     <string name="keywords_financial_apps_sms_access" msgid="3236014691838121857">"تطبيق مالي، رسائل قصيرة sms، إذن"</string>
     <string name="keywords_systemui_theme" msgid="9150908170417305866">"مظهر مُعتِم"</string>
     <string name="keywords_device_feedback" msgid="6948977907405738490">"خطأ"</string>
-    <string name="keywords_ambient_display_screen" msgid="5873935693887583428">"العرض على الشاشة، عرض شاشة التأمين"</string>
-    <string name="keywords_lock_screen_notif" msgid="4914337222856805463">"إشعار شاشة التأمين، الإشعارات"</string>
+    <string name="keywords_ambient_display_screen" msgid="5873935693887583428">"العرض على الشاشة، عرض شاشة القفل"</string>
+    <string name="keywords_lock_screen_notif" msgid="4914337222856805463">"إشعار شاشة القفل، الإشعارات"</string>
     <string name="keywords_face_settings" msgid="4117345666006836599">"وجه"</string>
     <string name="keywords_fingerprint_settings" msgid="902902368701134163">"بصمة إصبع، إضافة بصمة إصبع"</string>
     <string name="keywords_display_auto_brightness" msgid="1810596220466483996">"تعتيم الشاشة، شاشة تعمل باللمس، بطارية، سطوع ذكي، سطوع ديناميكي"</string>
@@ -3271,10 +3280,10 @@
     <string name="keywords_auto_rotate" msgid="4320791369951647513">"تدوير، قلب، دوران، عمودي، أفقي، اتجاه، رأسي، عرضي"</string>
     <string name="keywords_system_update_settings" msgid="4419971277998986067">"ترقية، android"</string>
     <string name="keywords_zen_mode_settings" msgid="4103819458182535493">"الرجاء عدم الإزعاج، جدول زمني، إشعارات، حظر، صامت، اهتزاز، سكون، عمل، تركيز، صوت، كتم الصوت، يوم، يوم من الأسبوع، عطلة نهاية الأسبوع، ليلة من الأسبوع، حدث"</string>
-    <string name="keywords_screen_timeout" msgid="4328381362313993666">"شاشة، وقت القفل، مهلة، شاشة تأمين"</string>
+    <string name="keywords_screen_timeout" msgid="4328381362313993666">"شاشة، وقت القفل، مهلة، شاشة قفل"</string>
     <string name="keywords_storage_settings" msgid="6422454520424236476">"ذاكرة، تخزين مؤقت، بيانات، حذف، محو، فارغة، مساحة"</string>
     <string name="keywords_bluetooth_settings" msgid="1152229891590622822">"متصل، جهاز، سماعات رأس، سماعة، مكبر صوت، لاسلكي، إقران، سمّاعات أذن، موسيقى، وسائط"</string>
-    <string name="keywords_wallpaper" msgid="7665778626293643625">"خلفية، شاشة، شاشة تأمين، موضوع"</string>
+    <string name="keywords_wallpaper" msgid="7665778626293643625">"خلفية، شاشة، شاشة قفل، موضوع"</string>
     <string name="keywords_assist_input" msgid="8392362788794886564">"تلقائي، مساعد"</string>
     <string name="keywords_default_payment_app" msgid="845369409578423996">"دفع، تلقائي"</string>
     <string name="keywords_ambient_display" msgid="8835182491798487184">"إشعار وارد"</string>
@@ -3486,11 +3495,11 @@
     <string name="swipe_direction_ltr" msgid="944932514821822709">"التمرير سريعًا باتجاه اليسار للتجاهل، وباتجاه اليمين لعرض القائمة"</string>
     <string name="swipe_direction_rtl" msgid="4521416787262888813">"التمرير سريعًا باتجاه اليمين للتجاهل، وباتجاه اليسار لعرض القائمة"</string>
     <string name="notification_pulse_title" msgid="4861418327614907116">"وميض الضوء"</string>
-    <string name="lock_screen_notifications_title" msgid="6889072265118747835">"على شاشة التأمين"</string>
+    <string name="lock_screen_notifications_title" msgid="6889072265118747835">"على شاشة القفل"</string>
     <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"عند قفل الملف الشخصي للعمل"</string>
     <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"عرض محتوى الإشعارات كاملاً"</string>
     <string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"إخفاء المحتوى الحساس"</string>
-    <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"عدم عرض إشعارات على الإطلاق"</string>
+    <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"عدم عرض الإشعارات على الإطلاق"</string>
     <string name="lock_screen_notifications_interstitial_message" msgid="4230189215124387818">"كيف تريد أن يتم عرض الإشعارات عندما يكون الجهاز مقفلاً؟"</string>
     <string name="lock_screen_notifications_interstitial_title" msgid="2832587379332443505">"الإشعارات"</string>
     <string name="lock_screen_notifications_summary_show_profile" msgid="8908775469657073273">"عرض محتوى إشعارات العمل كاملًا"</string>
@@ -3602,12 +3611,12 @@
     <string name="app_notification_block_title" msgid="7898269373875294367">"حظر الكل"</string>
     <string name="app_notification_block_summary" msgid="4502146897785692336">"عدم عرض هذه الإشعارات"</string>
     <string name="notification_content_block_title" msgid="2805138591864484587">"عرض الإشعارات"</string>
-    <string name="notification_content_block_summary" msgid="2743896875255591743">"عدم عرض الإشعارات في مركز الإشعارات أو على الأجهزة المرتبطة بحساب Google"</string>
+    <string name="notification_content_block_summary" msgid="2743896875255591743">"عدم عرض الإشعارات في مركز الإشعارات أو على الأجهزة الملحقة"</string>
     <string name="notification_badge_title" msgid="8989086619255666442">"السماح بنقطة الإشعار"</string>
     <string name="notification_channel_badge_title" msgid="8228215248332054612">"إظهار نقطة الإشعار"</string>
     <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"إلغاء وضع \"عدم الإزعاج\""</string>
     <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"السماح لهذه الإشعارات بمقاطعتك عندما يكون وضع \"عدم الإزعاج\" مفعلاً"</string>
-    <string name="app_notification_visibility_override_title" msgid="2349335170165637672">"على شاشة التأمين"</string>
+    <string name="app_notification_visibility_override_title" msgid="2349335170165637672">"على شاشة القفل"</string>
     <string name="app_notification_row_banned" msgid="2079325338122151677">"محظور"</string>
     <string name="app_notification_row_priority" msgid="432299064888787236">"الأولوية"</string>
     <string name="app_notification_row_sensitive" msgid="4919671519227722958">"حساس"</string>
@@ -3806,8 +3815,8 @@
     <string name="notifications_disabled" msgid="316658185757688983">"إيقاف"</string>
     <string name="notifications_partly_blocked" msgid="6330451240669068819">"تم إيقاف <xliff:g id="COUNT_0">%1$d</xliff:g> من <xliff:g id="COUNT_1">%2$d</xliff:g> من الفئات"</string>
     <string name="notifications_silenced" msgid="538923056987616372">"تم كتم الصوت"</string>
-    <string name="notifications_redacted" msgid="308836040236690014">"المحتوى الحساس ليس على شاشة التأمين"</string>
-    <string name="notifications_hidden" msgid="3665505522897010205">"ليست على شاشة التأمين"</string>
+    <string name="notifications_redacted" msgid="308836040236690014">"المحتوى الحساس ليس على شاشة القفل"</string>
+    <string name="notifications_hidden" msgid="3665505522897010205">"ليست على شاشة القفل"</string>
     <string name="notifications_priority" msgid="8849045645983017929">"تم تجاوز \"عدم الإزعاج\""</string>
     <string name="notifications_summary_divider" msgid="3148951310482572028">" / "</string>
     <string name="notification_summary_level" msgid="309162160355022027">"المستوى %d"</string>
@@ -3991,7 +4000,7 @@
     <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"السماح للتطبيق المساعد بالوصول إلى صورة للشاشة"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"إظهار وميض على الشاشة"</string>
     <string name="assist_flash_summary" msgid="6697095786317559129">"إظهار وميض على حدود الشاشة عند وصول التطبيق المساعد إلى النص من الشاشة أو لقطة الشاشة"</string>
-    <string name="assist_footer" msgid="7030121180457472165">"بإمكان التطبيقات المساعِدة تقديم المساعدة لك استنادًا إلى المعلومات على الشاشة التي تعرضها أنت. وتتوافق بعض التطبيقات مع كل من خدمة المشغّل وخدمة الإدخال الصوتي لتوفير مساعدة متكاملة لك."</string>
+    <string name="assist_footer" msgid="7030121180457472165">"بإمكان التطبيقات المساعِدة مساعدتك استنادًا إلى المعلومات على الشاشة التي تشاهدها. وتتوافق بعض التطبيقات مع كل من خدمة المشغّل وخدمة الإدخال الصوتي لتوفير مساعدة متكاملة لك."</string>
     <string name="average_memory_use" msgid="5333366040118953945">"متوسط ​​استخدام الذاكرة"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"الاستخدام الأقصى للذاكرة"</string>
     <string name="memory_usage" msgid="7963253555330830906">"استخدام الذاكرة"</string>
@@ -3999,8 +4008,8 @@
     <string name="memory_details" msgid="5165105904103664110">"التفاصيل"</string>
     <string name="memory_use_summary" msgid="7676311343819965850">"متوسط الذاكرة المستخدمة خلال آخر ٣ ساعات: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
     <string name="no_memory_use_summary" msgid="3966550113388917978">"لم يتم استخدام الذاكرة خلال آخر ٣ ساعات"</string>
-    <string name="sort_avg_use" msgid="78428601253054298">"الترتيب بحسب متوسط الاستخدام"</string>
-    <string name="sort_max_use" msgid="322772647893307413">"الترتيب بحسب الاستخدام الأقصى"</string>
+    <string name="sort_avg_use" msgid="78428601253054298">"الترتيب حسب متوسط الاستخدام"</string>
+    <string name="sort_max_use" msgid="322772647893307413">"الترتيب حسب الاستخدام الأقصى"</string>
     <string name="memory_performance" msgid="3506743771947250453">"الأداء"</string>
     <string name="total_memory" msgid="7352192982476976453">"إجمالي الذاكرة"</string>
     <string name="average_used" msgid="3022736210190754669">"متوسط استخدام الذاكرة (%)"</string>
@@ -4241,7 +4250,7 @@
     <string name="launch_mdp_app_text" msgid="9186559496664208252">"عرض الخطة"</string>
     <string name="launch_wifi_text" msgid="317820210431682605">"عرض التفاصيل"</string>
     <string name="data_saver_title" msgid="7903308134514179256">"توفير البيانات"</string>
-    <string name="unrestricted_data_saver" msgid="9139401849550738720">"الاستخدام غير المقيّد للبيانات"</string>
+    <string name="unrestricted_data_saver" msgid="9139401849550738720">"الاستخدام غير المحدود للبيانات"</string>
     <string name="restrict_background_blacklisted" msgid="7158991683849067124">"تم إيقاف بيانات الخلفية."</string>
     <string name="data_saver_on" msgid="7281809065420480881">"قيد التفعيل"</string>
     <string name="data_saver_off" msgid="7439439787358504018">"غير مفعّل"</string>
@@ -4321,7 +4330,7 @@
     <string name="button_confirm_convert_fbe" msgid="419832223125147297">"مسح وتحويل"</string>
     <string name="reset_shortcut_manager_throttling" msgid="1912184636360233397">"إعادة ضبط تقييد المعدّل في ShortcutManager"</string>
     <string name="reset_shortcut_manager_throttling_complete" msgid="2932990541160593632">"تمت إعادة ضبط تقييد المعدّل في ShortcutManager."</string>
-    <string name="notification_suggestion_title" msgid="3292107671498148560">"التحكم في المعلومات على شاشة التأمين"</string>
+    <string name="notification_suggestion_title" msgid="3292107671498148560">"التحكم في المعلومات على شاشة القفل"</string>
     <string name="notification_suggestion_summary" msgid="6516827892359614597">"إظهار محتوى الإشعار أو إخفاؤه"</string>
     <string name="page_tab_title_summary" msgid="4824744863994538006">"الكل"</string>
     <string name="page_tab_title_support" msgid="5569262185010367870">"النصائح والدعم"</string>
@@ -4489,7 +4498,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> شهادة CA كحد أدنى</item>
       <item quantity="one">شهادة CA واحدة (<xliff:g id="COUNT_0">%d</xliff:g>) كحد أدنى</item>
     </plurals>
-    <string name="enterprise_privacy_lock_device" msgid="1533125067038409945">"يمكن للمشرف قفل الجهاز وإعادة تعيين كلمة المرور"</string>
+    <string name="enterprise_privacy_lock_device" msgid="1533125067038409945">"يمكن للمشرف قفل الجهاز وإعادة ضبط كلمة المرور"</string>
     <string name="enterprise_privacy_wipe_device" msgid="7555287990273929922">"يمكن للمشرف حذف جميع بيانات الجهاز"</string>
     <string name="enterprise_privacy_failed_password_wipe_device" msgid="4101502079202483156">"محاولات كلمة المرور الخاطئة قبل حذف جميع بيانات الجهاز"</string>
     <string name="enterprise_privacy_failed_password_wipe_work" msgid="2881646286634693392">"محاولات كلمة المرور الخاطئة قبل حذف بيانات الملف الشخصي للعمل"</string>
@@ -4584,7 +4593,7 @@
     <string name="allow_background_activity_starts_summary" msgid="8170749270869606692">"السماح ببدء جميع الأنشطة في الخلفية"</string>
     <string name="show_first_crash_dialog" msgid="3682063068903692710">"عرض مربع حوار الأعطال دائمًا"</string>
     <string name="show_first_crash_dialog_summary" msgid="8197987550025401754">"عرض مربع الحوار في كل مرة يتعطل فيها تطبيق"</string>
-    <string name="angle_enabled_app" msgid="4359266182151708733">"تحديد التطبيق الذي يستخدم ANGLE"</string>
+    <string name="angle_enabled_app" msgid="4359266182151708733">"اختيار التطبيق الذي يستخدم ANGLE"</string>
     <string name="angle_enabled_app_not_set" msgid="7428910515748621910">"لم يتم تعيين تطبيق لاستخدام ANGLE"</string>
     <string name="angle_enabled_app_set" msgid="7313088703610569320">"التطبيق الذي يستخدم ANGLE: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="game_driver_dashboard_title" msgid="219443350404091201">"إعدادات Game Driver المفضّلة"</string>
diff --git a/tests/CarDeveloperOptions/res/values-as/arrays.xml b/tests/CarDeveloperOptions/res/values-as/arrays.xml
index f31c3f4..60b9ba7 100644
--- a/tests/CarDeveloperOptions/res/values-as/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-as/arrays.xml
@@ -29,9 +29,25 @@
     <item msgid="5194868215515664953">"প্ৰশান্ত মহাসাগৰীয়"</item>
     <item msgid="7044520255415007865">"সকলো"</item>
   </string-array>
-    <!-- no translation found for screen_timeout_entries:0 (8596143519087753804) -->
-    <!-- no translation found for screen_timeout_entries:5 (5827960506924849753) -->
-    <!-- no translation found for dream_timeout_entries:7 (8271452751594598661) -->
+  <string-array name="screen_timeout_entries">
+    <item msgid="8596143519087753804">"১৫ ছেকেণ্ড"</item>
+    <item msgid="772029947136115322">"৩০ ছেকেণ্ড"</item>
+    <item msgid="8743663928349474087">"১ মিনিট"</item>
+    <item msgid="1506508631223164814">"২ মিনিট"</item>
+    <item msgid="8664703938127907662">"৫ মিনিট"</item>
+    <item msgid="5827960506924849753">"১০ মিনিট"</item>
+    <item msgid="6677424950124253938">"৩০ মিনিট"</item>
+  </string-array>
+  <string-array name="dream_timeout_entries">
+    <item msgid="6487043225269853023">"কেতিয়াও নহয়"</item>
+    <item msgid="2517785806387977252">"১৫ ছেকেণ্ড"</item>
+    <item msgid="6347954399441173672">"৩০ ছেকেণ্ড"</item>
+    <item msgid="4858305253279921789">"১ মিনিট"</item>
+    <item msgid="8109273437140044073">"২ মিনিট"</item>
+    <item msgid="2788593551142462622">"৫ মিনিট"</item>
+    <item msgid="8012672183888404961">"১০ মিনিট"</item>
+    <item msgid="8271452751594598661">"৩০ মিনিট"</item>
+  </string-array>
   <string-array name="lock_after_timeout_entries">
     <item msgid="2232921187970351881">"তৎক্ষণাৎ"</item>
     <item msgid="2038544972632026612">"৫ ছেকেণ্ড"</item>
@@ -43,17 +59,47 @@
     <item msgid="811192536981678974">"১০ মিনিট"</item>
     <item msgid="7258394417241706272">"৩০ মিনিট"</item>
   </string-array>
-    <!-- no translation found for entries_font_size:0 (2340391964816059553) -->
-    <!-- no translation found for entries_font_size:0 (6490061470416867723) -->
-    <!-- no translation found for entries_font_size:2 (1714184661981538355) -->
-    <!-- no translation found for entries_font_size:2 (1678068858001018666) -->
-    <!-- no translation found for wifi_status:3 (5848277343965362748) -->
-    <!-- no translation found for wifi_status_with_ssid:1 (6816207058895999545) -->
-    <!-- no translation found for wifi_status_with_ssid:3 (7547609081339573756) -->
-    <!-- no translation found for wifi_status_with_ssid:4 (5145158315060185414) -->
+  <string-array name="entries_font_size">
+    <item msgid="2340391964816059553">"সৰু"</item>
+    <item msgid="591935967183159581">"ডিফ’ল্ট"</item>
+    <item msgid="1714184661981538355">"ডাঙৰ"</item>
+    <item msgid="6195563047686707484">"সকলোতকৈ ডাঙৰ"</item>
+  </string-array>
+  <string-array name="wifi_status">
+    <item msgid="1304883790721412351"></item>
+    <item msgid="4157625910392775808">"স্কেন কৰি থকা হৈছে…"</item>
+    <item msgid="5597394826455877834">"সংযোগ কৰি থকা হৈছে…"</item>
+    <item msgid="5848277343965362748">"বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰি থকা হৈছে…"</item>
+    <item msgid="3391238031431440676">"আইপি ঠিকনা সংগ্ৰহ কৰি থকা হৈছে…"</item>
+    <item msgid="5257597310494000224">"সংযোগ কৰা হ’ল"</item>
+    <item msgid="8472497592913050396">"স্থগিত"</item>
+    <item msgid="1228072488815999109">"সংযোগ বিচ্ছিন্ন কৰি থকা হৈছে…"</item>
+    <item msgid="7253087004422991731">"সংযোগ বিচ্ছিন্ন"</item>
+    <item msgid="4169850917304751227">"অসফল"</item>
+    <item msgid="6266658166690831131">"অৱৰোধিত"</item>
+    <item msgid="4517230805854909775">"কিছুসময়ৰ বাবে দুৰ্বল সংযোগ দেখুওৱা হোৱা নাই"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="4853670665485437464"></item>
+    <item msgid="6816207058895999545">"স্কেন কৰি থকা হৈছে…"</item>
+    <item msgid="8058143476674427024">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ সৈতে সংযোগ কৰি থকা হৈছে…"</item>
+    <item msgid="7547609081339573756">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ জৰিয়তে বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰি থকা হৈছে…"</item>
+    <item msgid="5145158315060185414">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ আইপি ঠিকনা পৰা সংগ্ৰহ কৰি থকা হৈছে…"</item>
+    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ সৈতে সংযোগ কৰা হ’ল"</item>
+    <item msgid="6600156231416890902">"স্থগিত"</item>
+    <item msgid="4133290864821295785">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ পৰা সংযোগ বিচ্ছিন্ন কৰি থকা হৈছে…"</item>
+    <item msgid="3980154971187953257">"সংযোগ বিচ্ছিন্ন"</item>
+    <item msgid="2847316776634969068">"অসফল"</item>
+    <item msgid="4390990424746035383">"অৱৰোধিত"</item>
+    <item msgid="3618248791367063949">"কিছুসময়ৰ বাবে দুৰ্বল সংযোগ দেখুওৱা হোৱা নাই"</item>
+  </string-array>
     <!-- no translation found for wifi_tether_security:0 (5586343370515598801) -->
     <!-- no translation found for wifi_tether_security:1 (6136336549994615745) -->
-    <!-- no translation found for wifi_p2p_wps_setup:0 (5390235347963255303) -->
+  <string-array name="wifi_p2p_wps_setup">
+    <item msgid="5390235347963255303">"পুশ্ব বুটাম"</item>
+    <item msgid="7401896200768713930">"সংযুক্ত ডিভাইচৰ পৰা পিন"</item>
+    <item msgid="4526848028011846710">"এই ডিভাইচৰ পিন"</item>
+  </string-array>
   <string-array name="wifi_p2p_status">
     <item msgid="8741947238021758201">"সংযোগ কৰা হ’ল"</item>
     <item msgid="983792611851499732">"নিমন্ত্ৰিত"</item>
@@ -61,7 +107,12 @@
     <item msgid="4646663015449312554">"উপলব্ধ"</item>
     <item msgid="3230556734162006146">"সীমাৰ বাহিৰত"</item>
   </string-array>
-    <!-- no translation found for bluetooth_visibility_timeout_entries:1 (2759776603549270587) -->
+  <string-array name="bluetooth_visibility_timeout_entries">
+    <item msgid="8247986727324120082">"২ মিনিট"</item>
+    <item msgid="2759776603549270587">"৫ মিনিট"</item>
+    <item msgid="167772676068860015">"১ ঘণ্টা"</item>
+    <item msgid="5985477119043628504">"কেতিয়াও সময় উকলি নাযায়"</item>
+  </string-array>
   <string-array name="bluetooth_max_connected_audio_devices">
     <item msgid="3800257971619063588">"ছিষ্টেম ডিফ\'ল্ট ব্যৱহাৰ কৰক: <xliff:g id="DEFAULT_BLUETOOTH_MAX_CONNECTED_AUDIO_DEVICES">%1$d</xliff:g>"</item>
     <item msgid="8572230405241423895">"১"</item>
@@ -70,8 +121,13 @@
     <item msgid="1644506614010085798">"৪"</item>
     <item msgid="3132506679404897150">"৫"</item>
   </string-array>
-    <!-- no translation found for wifi_signal:1 (7882129634982603782) -->
-    <!-- no translation found for wifi_signal:4 (999948812884919584) -->
+  <string-array name="wifi_signal">
+    <item msgid="1709949377823900951">"দুৰ্বল"</item>
+    <item msgid="7882129634982603782">"বেয়া"</item>
+    <item msgid="6457357501905996224">"গ্ৰহণযোগ্য"</item>
+    <item msgid="405271628162918841">"উচ্চ"</item>
+    <item msgid="999948812884919584">"উত্তম"</item>
+  </string-array>
   <string-array name="data_usage_data_range">
     <item msgid="8986775481492954015">"যোৱা ৩০ দিন"</item>
     <item msgid="3211287705232736964">"ডেটা ব্যৱহাৰ চক্ৰ..."</item>
@@ -107,7 +163,10 @@
     <item msgid="7330627471456865502">"MSCHAPV2"</item>
     <item msgid="6255179395132581882">"GTC"</item>
   </string-array>
-    <!-- no translation found for wifi_ip_settings:1 (4377002609760712163) -->
+  <string-array name="wifi_ip_settings">
+    <item msgid="2717196390555072244">"DHCP"</item>
+    <item msgid="4377002609760712163">"নিশ্চল"</item>
+  </string-array>
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"নাই"</item>
     <item msgid="1464741437353223198">"মেনুএল"</item>
@@ -124,8 +183,24 @@
     <item msgid="9148582221081416020">"IPv6"</item>
     <item msgid="4094895508821270572">"IPv4/IPv6"</item>
   </string-array>
-    <!-- no translation found for bearer_entries:0 (5231094118929435723) -->
-    <!-- no translation found for bearer_entries:9 (7246853278334311652) -->
+  <string-array name="bearer_entries">
+    <item msgid="5231094118929435723">"অনিৰ্দিষ্ট"</item>
+    <item msgid="2740477081395679090">"এলটিই"</item>
+    <item msgid="1807866878276630064">"HSPAP"</item>
+    <item msgid="7945352669463358624">"HSPA"</item>
+    <item msgid="4152166097223929133">"HSUPA"</item>
+    <item msgid="5134662517319988296">"HSDPA"</item>
+    <item msgid="4997539146036732961">"UMTS"</item>
+    <item msgid="4910169712073083585">"EDGE"</item>
+    <item msgid="3505904588897578792">"জিপিআৰএছ"</item>
+    <item msgid="7246853278334311652">"eHRPD"</item>
+    <item msgid="7037248100126710307">"EVDO_B"</item>
+    <item msgid="3440758673769932256">"EVDO_A"</item>
+    <item msgid="1782525731958596741">"EVDO_0"</item>
+    <item msgid="1819765960790884441">"1xRTT"</item>
+    <item msgid="3148192102183107944">"IS95B"</item>
+    <item msgid="3778273775365258534">"IS95A"</item>
+  </string-array>
   <string-array name="mvno_type_entries">
     <item msgid="6984770764726663331">"নাই"</item>
     <item msgid="1469208769491004112">"SPN"</item>
@@ -144,28 +219,185 @@
     <item msgid="8563996233342430477">"মিডিয়া"</item>
     <item msgid="5323851085993963783">"ডিভাইচ"</item>
   </string-array>
-    <!-- no translation found for app_ops_summaries:46 (4933375960222609935) -->
-    <!-- no translation found for app_ops_labels:3 (7836406246005211990) -->
-    <!-- no translation found for app_ops_labels:4 (3951439024549922598) -->
-    <!-- no translation found for app_ops_labels:8 (3597797992398484655) -->
-    <!-- no translation found for app_ops_labels:20 (3037159047591081136) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
-    <!-- no translation found for app_ops_labels:48 (8291198322681891160) -->
+  <string-array name="app_ops_summaries">
+    <item msgid="2585253854462134715">"আনুমানিক অৱস্থান"</item>
+    <item msgid="1830619568689922920">"সঠিক অৱস্থান"</item>
+    <item msgid="3317274469481923141">"জিপিএছ"</item>
+    <item msgid="8931785990160383356">"কম্পন"</item>
+    <item msgid="8632513128515114092">"সম্পৰ্কসমূহ পঢ়ক"</item>
+    <item msgid="3741042113569620272">"সম্পৰ্কসমূহ সংশোধন কৰক"</item>
+    <item msgid="4204420969709009931">"কলৰ লগ পঢ়ক"</item>
+    <item msgid="2260380357119423209">"কলৰ লগ সংশোধন কৰক"</item>
+    <item msgid="6550710385014530934">"কেলেণ্ডাৰ পঢ়ক"</item>
+    <item msgid="3575906174264853951">"কেলেণ্ডাৰ সাল-সলনি কৰক"</item>
+    <item msgid="4319843242568057174">"ৱাই-ফাই স্কেন"</item>
+    <item msgid="2981791890467303819">"জাননী"</item>
+    <item msgid="6617825156152476692">"চেল স্কেন"</item>
+    <item msgid="8865260890611559753">"ফ\'ন ক\'ল কৰক"</item>
+    <item msgid="3254999273961542982">"এছএমএছ পঢ়ক"</item>
+    <item msgid="7711446453028825171">"এছএমএছ লিখক"</item>
+    <item msgid="6123238544099198034">"SMS পাওক"</item>
+    <item msgid="838342167431596036">"জৰূৰীকালীন এছএমএছ পাওক"</item>
+    <item msgid="8554432731560956686">"এমএমএছ পাওক"</item>
+    <item msgid="7464863464299515059">"WAP পুশ্ব পাওক"</item>
+    <item msgid="310463075729606765">"এছএমএছ পঠিয়াওক"</item>
+    <item msgid="7338021933527689514">"আইচিচি এছএমএছ পঢ়ক"</item>
+    <item msgid="6130369335466613036">"আইচিচি এছএমএছ লিখক"</item>
+    <item msgid="6536865581421670942">"ছেটিংবোৰ সংশোধন কৰক"</item>
+    <item msgid="4547203129183558973">"ওপৰত আঁকক"</item>
+    <item msgid="9080347512916542840">"জাননীত প্ৰৱেশ কৰক"</item>
+    <item msgid="5332718516635907742">"কেমেৰা"</item>
+    <item msgid="6098422447246167852">"ধ্বনি ৰেকৰ্ড কৰক"</item>
+    <item msgid="9182794235292595296">"অডিঅ’ প্লে কৰক"</item>
+    <item msgid="8760743229597702019">"ক্লিপব\'ৰ্ড পঢ়ক"</item>
+    <item msgid="2266923698240538544">"ক্লিপব\'ৰ্ড সংশোধন কৰক"</item>
+    <item msgid="1801619438618539275">"মিডিয়া বুটামসমূহ"</item>
+    <item msgid="31588119965784465">"অডিঅ\' ফ\'কাছ"</item>
+    <item msgid="7565226799008076833">"মাষ্টাৰ ভলিউম"</item>
+    <item msgid="5420704980305018295">"ধ্বনিৰ ভলিউম"</item>
+    <item msgid="5797363115508970204">"ৰিঙৰ ভলিউম"</item>
+    <item msgid="8233154098550715999">"মিডিয়াৰ ভলিউম"</item>
+    <item msgid="5196715605078153950">"এলাৰ্মৰ ভলিউম"</item>
+    <item msgid="394030698764284577">"জাননীৰ ভলিউম"</item>
+    <item msgid="8952898972491680178">"ব্লুটুথ ভলিউম"</item>
+    <item msgid="8506227454543690851">"সক্ৰিয় কৰি ৰাখক"</item>
+    <item msgid="1108160036049727420">"অৱস্থান নিৰীক্ষণ কৰক"</item>
+    <item msgid="1496205959751719491">"উচ্চ ক্ষমতাসম্পন্ন অৱস্থান নিৰীক্ষণ কৰক"</item>
+    <item msgid="3776296279910987380">"ব্যৱহাৰ পৰিসংখ্যা লাভ কৰক"</item>
+    <item msgid="8827100324471975602">"মাইক্ৰ\'ফ\'ন মিউট/আনমিউট কৰক"</item>
+    <item msgid="6880736730520126864">"ট’ষ্ট দেখুৱাওক"</item>
+    <item msgid="4933375960222609935">"মিডিয়া প্ৰ’জেক্ট কৰক"</item>
+    <item msgid="8357907018938895462">"VPN সক্ৰিয় কৰক"</item>
+    <item msgid="8143812849911310973">"ৱালপেপাৰ লিখক"</item>
+    <item msgid="6266277260961066535">"সহায়ৰ গাঁঠনি"</item>
+    <item msgid="7715498149883482300">"সহায়ক স্ক্ৰীণশ্বট"</item>
+    <item msgid="4046679376726313293">"ফ\'নৰ স্থিতি পঢ়ক"</item>
+    <item msgid="6329507266039719587">"ভইচমেইল যোগ কৰক"</item>
+    <item msgid="7692440726415391408">"ছিপ ব্যৱহাৰ কৰক"</item>
+    <item msgid="8572453398128326267">"বৰ্হিগামী কল সম্পাদন কৰক"</item>
+    <item msgid="7775674394089376306">"ফিংগাৰপ্ৰিণ্ট"</item>
+    <item msgid="3182815133441738779">"শৰীৰৰ ছেন্সৰসমূহ"</item>
+    <item msgid="2793100005496829513">"চেল সম্প্ৰচাৰসমূহ পঢ়ক"</item>
+    <item msgid="2633626056029384366">"নকল অৱস্থান"</item>
+    <item msgid="8356842191824684631">"সঞ্চয়াগাৰত পঢ়ক"</item>
+    <item msgid="5671906070163291500">"সঞ্চয়াগাৰত লিখক"</item>
+    <item msgid="2791955098549340418">"স্ক্ৰীণ অন কৰক"</item>
+    <item msgid="5599435119609178367">"একাউণ্টবোৰ বিচাৰক"</item>
+    <item msgid="1165623660533024666">"নেপথ্যত চলাওক"</item>
+    <item msgid="6423861043647911030">"দিব্যাংসকলৰ বাবে থকা সুবিধাসমূহৰ ভলিউম"</item>
+  </string-array>
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"অৱস্থান"</item>
+    <item msgid="6656077694190491067">"অৱস্থান"</item>
+    <item msgid="8790228218278477369">"অৱস্থান"</item>
+    <item msgid="7836406246005211990">"কম্পন"</item>
+    <item msgid="3951439024549922598">"সম্পৰ্কসূচী পঢ়ক"</item>
+    <item msgid="8802152411647068">"সম্পৰ্কসূচী সংশোধন"</item>
+    <item msgid="229544934599698735">"কল লগ পঢ়ক"</item>
+    <item msgid="7396102294405899613">"কল লগ সলনি কৰক"</item>
+    <item msgid="3597797992398484655">"কেলেণ্ডাৰ পঢ়ক"</item>
+    <item msgid="2705975774250907343">"কেলেণ্ডাৰ সংশোধন কৰক"</item>
+    <item msgid="4668747371441932697">"অৱস্থান"</item>
+    <item msgid="1487578921720243646">"প\'ষ্ট জাননী"</item>
+    <item msgid="4636080349724146638">"অৱস্থান"</item>
+    <item msgid="673510900286463926">"ফ\'ন নম্বৰত কল কৰক"</item>
+    <item msgid="542083422784609790">"এছএমএছ/এমএমএছ পঢ়ক"</item>
+    <item msgid="1033780373029588436">"SMS/MMS লিখক"</item>
+    <item msgid="5647111115517787488">"SMS/MMS পাওক"</item>
+    <item msgid="8591105601108455893">"SMS/MMS পাওক"</item>
+    <item msgid="7730995008517841903">"এছএমএছ/এমএমএছ পাওক"</item>
+    <item msgid="2613033109026626086">"এছএমএছ/এমএমএছ পাওক"</item>
+    <item msgid="3037159047591081136">"এছএমএছ/এমএমএছ পঠিয়াওক"</item>
+    <item msgid="4726682243833913568">"এছএমএছ/এমএমএছ পঢ়ক"</item>
+    <item msgid="6555678522277865572">"এছএমএছ/এমএমএছ লিখক"</item>
+    <item msgid="6981734935578130884">"ছেটিংসমূহ সংশোধন কৰক"</item>
+    <item msgid="8705854389991425629">"ওপৰত আঁকক"</item>
+    <item msgid="5861356020344153651">"প্ৰৱেশৰ জাননীসমূহ"</item>
+    <item msgid="78432174621628659">"কেমেৰা"</item>
+    <item msgid="3986116419882154794">"ধ্বনি ৰেকৰ্ড কৰক"</item>
+    <item msgid="4516840825756409490">"অডিঅ\' প্লে কৰক"</item>
+    <item msgid="6811712502798183957">"ক্লিপব\'ৰ্ড পঢ়ক"</item>
+    <item msgid="2780369012602289114">"ক্লিপব\'ৰ্ড সংশোধন কৰক"</item>
+    <item msgid="2331359440170850868">"মিডিয়া বুটাম"</item>
+    <item msgid="6133599737122751231">"অডিঅ\' ফ\'কাছ"</item>
+    <item msgid="6844485713404805301">"মাষ্টাৰ ভলিউম"</item>
+    <item msgid="1600379420669104929">"কণ্ঠস্বৰৰ ভলিউম"</item>
+    <item msgid="6296768210470214866">"ৰিঙৰ ভলিউম"</item>
+    <item msgid="510690696071629241">"মিডিয়াৰ ভলিউম"</item>
+    <item msgid="406861638631430109">"এলাৰ্মৰ ভলিউম"</item>
+    <item msgid="4715864795872233884">"জাননী-ধ্বনিৰ ভলিউম"</item>
+    <item msgid="2311478519251301183">"ব্লুটুথ ভলিউম"</item>
+    <item msgid="5133991377896747027">"জাগ্ৰত কৰি ৰাখক"</item>
+    <item msgid="2464189519136248621">"অৱস্থান"</item>
+    <item msgid="2062677934050803037">"অৱস্থান"</item>
+    <item msgid="1735171933192715957">"ব্যৱহাৰ পৰিসংখ্যা লাভ কৰক"</item>
+    <item msgid="1014093788778383554">"মাইক্ৰ\'ফ\'ন মিউট/আনমিউট কৰক"</item>
+    <item msgid="4199297950608622850">"ট\'ষ্ট দেখুৱাওক"</item>
+    <item msgid="2527962435313398821">"মিডিয়া প্ৰ’জেক্ট কৰক"</item>
+    <item msgid="5117506254221861929">"ভিপিএন সক্ৰিয় কৰক"</item>
+    <item msgid="8291198322681891160">"ৱালপেপাৰ লিখক"</item>
+    <item msgid="7106921284621230961">"সহায়ৰ গাঁথনি"</item>
+    <item msgid="4496533640894624799">"সহায় স্ক্ৰীণশ্বট"</item>
+    <item msgid="2598847264853993611">"ফ\'নৰ স্থিতি পঢ়ক"</item>
+    <item msgid="9215610846802973353">"ভইচমেইল যোগ কৰক"</item>
+    <item msgid="9186411956086478261">"ছিপ ব্যৱহাৰ কৰক"</item>
+    <item msgid="6884763100104539558">"বৰ্হিগামী কল সম্পাদন কৰক"</item>
+    <item msgid="125513972170580692">"ফিংগাৰপ্ৰিণ্ট"</item>
+    <item msgid="2556071024281275619">"শৰীৰৰ ছেন্সৰসমূহ"</item>
+    <item msgid="617168514928339387">"চেল সম্প্ৰচাৰবোৰ পঢ়ক"</item>
+    <item msgid="7134693570516523585">"নকল অৱস্থান"</item>
+    <item msgid="7224489175375229399">"সঞ্চয়াগাৰ পঢ়ক"</item>
+    <item msgid="8472735063903258202">"সঞ্চয়াগাৰত লিখক"</item>
+    <item msgid="4069276819909595110">"স্ক্ৰীণ অন কৰক"</item>
+    <item msgid="1228338896751121025">"একাউণ্টবোৰ বিচাৰক"</item>
+    <item msgid="3181581793459233672">"নেপথ্যত চলাওক"</item>
+    <item msgid="2340936043025374076">"দিব্যাংসকলৰ বাবে থকা সুবিধাসমূহৰ ভলিউম"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"চুটি"</item>
     <item msgid="4816511817309094890">"মধ্যমীয়া"</item>
     <item msgid="8305084671259331134">"দীঘল"</item>
   </string-array>
-    <!-- no translation found for captioning_typeface_selector_titles:4 (1487203730637617924) -->
-    <!-- no translation found for captioning_font_size_selector_titles:3 (2784236342175159295) -->
-    <!-- no translation found for captioning_edge_type_selector_titles:4 (8019330250538856521) -->
+  <string-array name="captioning_typeface_selector_titles">
+    <item msgid="6928465258504250174">"ডিফ’ল্ট"</item>
+    <item msgid="4147246073737933622">"ছানছ-ছেৰিফ"</item>
+    <item msgid="3117680749167407907">"ছানছ-ছেৰিফ ঘনীকৃত"</item>
+    <item msgid="6529379119163117545">"ছান-ছেৰিফ ম\'ন\'স্পেচ"</item>
+    <item msgid="1487203730637617924">"ছেৰিফ"</item>
+    <item msgid="4937790671987480464">"ছেৰিফ ম\'ন\'স্পেচ"</item>
+    <item msgid="4448481989108928248">"অনানুষ্ঠানিক"</item>
+    <item msgid="4627069151979553527">"পকোৱা আখৰ"</item>
+    <item msgid="6896773537705206194">"সৰু বৰফলাৰ আখৰ"</item>
+  </string-array>
+  <string-array name="captioning_font_size_selector_titles">
+    <item msgid="1680223634161592855">"নিচেই সৰু"</item>
+    <item msgid="5091603983404027034">"সৰু"</item>
+    <item msgid="176844712416932112">"সাধাৰণ"</item>
+    <item msgid="2784236342175159295">"ডাঙৰ"</item>
+    <item msgid="218913203203160606">"অতি ডাঙৰ"</item>
+  </string-array>
+  <string-array name="captioning_edge_type_selector_titles">
+    <item msgid="3865198759294188069">"ডিফ’ল্ট"</item>
+    <item msgid="6488643537808152001">"নাই"</item>
+    <item msgid="552332815156010137">"ৰূপৰেখা"</item>
+    <item msgid="7187891159463789272">"ছাঁযুক্ত আখৰ"</item>
+    <item msgid="8019330250538856521">"উঠঙা"</item>
+    <item msgid="8987385315647049787">"পোটোকা পৰা"</item>
+  </string-array>
   <string-array name="captioning_opacity_selector_titles">
     <item msgid="313003243371588365">"২৫%"</item>
     <item msgid="4665048002584838262">"৫০%"</item>
     <item msgid="1874668269931014581">"৭৫%"</item>
     <item msgid="6462911487571123954">"১০০%"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"এপৰ ডিফ\'ল্টসমূহ ব্যৱহাৰ কৰক"</item>
+    <item msgid="8611890312638868524">"ক\'লাৰ ওপৰত বগা"</item>
+    <item msgid="5891360837786277638">"বগা ওপৰত ক’লা"</item>
+    <item msgid="2798457065945456853">"ক\'লাৰ ওপৰত হালধীয়া"</item>
+    <item msgid="5799049811524553967">"নীলাৰ ওপৰত হালধীয়া"</item>
+    <item msgid="3673930830658169860">"কাষ্টম"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"পিপিটিপি ভিপিএন"</item>
     <item msgid="1349760781118368659">"পূৰ্বে ভাগ-বতৰা কৰা কীসমূহৰ সৈতে L2TP/IPSec ভিপিএন"</item>
@@ -174,16 +406,36 @@
     <item msgid="3319427315593649917">"প্ৰমাণপত্ৰ আৰু Xauth বিশ্ৱাসযোগ্যতা প্ৰামাণিকৰণৰ সৈতে IPSec ভিপিএন"</item>
     <item msgid="8258927774145391041">"প্ৰমাণপত্ৰ আৰু হাইব্ৰিড সত্যাপনসহ IPSec ভিপিএন"</item>
   </string-array>
-    <!-- no translation found for vpn_proxy_settings:0 (2958623927055120839) -->
-    <!-- no translation found for vpn_states:4 (9135049670787351881) -->
+  <string-array name="vpn_proxy_settings">
+    <item msgid="2958623927055120839">"একো নাই"</item>
+    <item msgid="1157046369795346308">"মেনুএল"</item>
+  </string-array>
+  <string-array name="vpn_states">
+    <item msgid="5408915841694583740">"সংযোগ বিচ্ছিন্ন"</item>
+    <item msgid="8754480102834556765">"আৰম্ভ কৰা হৈছে…"</item>
+    <item msgid="3351334355574270250">"সংযোগ কৰি থকা হৈছে…"</item>
+    <item msgid="8303882153995748352">"সংযোগ কৰা হ’ল"</item>
+    <item msgid="9135049670787351881">"সময় উকলিছে"</item>
+    <item msgid="2124868417182583926">"অসফল"</item>
+  </string-array>
   <string-array name="security_settings_premium_sms_values">
     <item msgid="1164265643455394443">"সোধক"</item>
     <item msgid="7718817231348607934">"কেতিয়াও অনুমতি নিদিব"</item>
     <item msgid="8184570120217958741">"চিৰদিনৰ বাবে অনুমোদন"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"স্বাভাৱিক"</item>
+    <item msgid="5101233285497327432">"মজলীয়া"</item>
+    <item msgid="1555861583162930714">"নিম্ন"</item>
+    <item msgid="1719683776264798117">"জটিল"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"সাধাৰণ"</item>
+    <item msgid="6107138933849816768">"মজলীয়া"</item>
+    <item msgid="182695359839047859">"নিম্ন"</item>
+    <item msgid="8577246509202964244">"জটিল"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"নেৰানেপেৰা"</item>
     <item msgid="167418068739176448">"শীৰ্ষ কাৰ্যকলাপ"</item>
@@ -245,7 +497,31 @@
     <item msgid="8444727359525554695">"কেৱল গৃহ পৃষ্ঠাত"</item>
     <item msgid="1161026694891024702">"স্বয়ংক্ৰিয়"</item>
   </string-array>
-    <!-- no translation found for preferred_network_mode_choices:11 (5713723042183940349) -->
+  <string-array name="preferred_network_mode_choices">
+    <item msgid="1823884522189328861">"GSM/WCDMA অগ্ৰাধিকাৰপ্ৰাপ্ত"</item>
+    <item msgid="7581481130337402578">"কেৱল GSM"</item>
+    <item msgid="8579197487913425819">"কেৱল WCDMA"</item>
+    <item msgid="8465243227505412498">"GSM/WCDMA স্বয়ংক্ৰিয়"</item>
+    <item msgid="9107479914166352132">"CDMA/EvDo স্বয়ংক্ৰিয়"</item>
+    <item msgid="4219607161971472471">"CDMA w/o EvDo"</item>
+    <item msgid="7278975240951052041">"কেৱল EvDo"</item>
+    <item msgid="2295969832276827854">"CDMA/EvDo/GSM/WCDMA"</item>
+    <item msgid="9059227943989034424">"CDMA + LTE/EvDo"</item>
+    <item msgid="463168068025354541">"GSM/WCDMA/LTE"</item>
+    <item msgid="1770755308983338311">"গোলকীয়"</item>
+    <item msgid="5713723042183940349">"LTE"</item>
+    <item msgid="8600184258612405670">"LTE / WCDMA"</item>
+    <item msgid="5638632460322750180">"কেৱল TDSCDMA"</item>
+    <item msgid="4346392996298714633">"TDSCDMA/WCDMA"</item>
+    <item msgid="5004811216708487615">"LTE/TDSCDMA"</item>
+    <item msgid="9191730167201068525">"TDSCDMA/GSM"</item>
+    <item msgid="5874623229495009031">"LTE/TDSCDMA/GSM"</item>
+    <item msgid="5096480046347789213">"TDSCDMA/GSM/WCDMA"</item>
+    <item msgid="2075445917638134012">"LTE/TDSCDMA/WCDMA"</item>
+    <item msgid="3353351554070857366">"LTE/TDSCDMA/GSM/WCDMA"</item>
+    <item msgid="2067289929099567494">"TDSCDMA/CDMA/EVDO/GSM/WCDMA"</item>
+    <item msgid="4959483620561891661">"LTE/TDSCDMA/CDMA/EVDO/GSM/WCDMA"</item>
+  </string-array>
   <string-array name="cdma_subscription_choices">
     <item msgid="7691437408632563841">"RUIM/SIM"</item>
     <item msgid="6219184455685527822">"NV"</item>
diff --git a/tests/CarDeveloperOptions/res/values-as/config.xml b/tests/CarDeveloperOptions/res/values-as/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-as/config.xml
+++ b/tests/CarDeveloperOptions/res/values-as/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-as/strings.xml b/tests/CarDeveloperOptions/res/values-as/strings.xml
index 774a801..1abc711 100644
--- a/tests/CarDeveloperOptions/res/values-as/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-as/strings.xml
@@ -667,7 +667,6 @@
       <item quantity="one"><xliff:g id="NUMBER_1">%d</xliff:g>টা সংখ্যাতকৈ কম হ\'বই লাগিব</item>
       <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g>টা সংখ্যাতকৈ কম হ\'বই লাগিব</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"কেৱল অংকহে থাকিব লাগিব ০-৯"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"ডিভাইচ এডমিনে আপুনি ব্যৱহাৰ কৰা অন্তিমটো পিন আকৌ ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়া নাই"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"আপোনাৰ আইটি প্ৰশাসকে বিশেষত্বহীন পিনবোৰ অৱৰোধ কৰি থৈছে৷ এটা পৃথক পিনেৰে চেষ্টা কৰক৷"</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"কেৱল বৈধ বৰ্ণহে দিয়ক"</string>
@@ -698,6 +697,10 @@
       <item quantity="one">অতি কমেও <xliff:g id="COUNT">%d</xliff:g>টা সংখ্যা বা প্ৰতীক থাকিব লাগিব</item>
       <item quantity="other">অতি কমেও <xliff:g id="COUNT">%d</xliff:g>টা সংখ্যা বা প্ৰতীক থাকিব লাগিব</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">অতি কমেও <xliff:g id="COUNT">%d</xliff:g>টা এনেকুৱা বৰ্ণ থাকিবই লাগিব যিটো সংখ্যা নহয়</item>
+      <item quantity="other">অতি কমেও <xliff:g id="COUNT">%d</xliff:g>টা এনেকুৱা বৰ্ণ থাকিবই লাগিব যিটো সংখ্যা নহয়</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"ডিভাইচৰ প্ৰশাসকে শেহতীয়া পাছৱৰ্ড ব্যৱহাৰ কৰিব নিদিয়ে"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"আইটি এডমিনে উমৈহতীয়া পাছৱৰ্ডসমূহ অৱৰোধ কৰি থৈছে। এটা পৃথক পাছৱৰ্ডেৰে চেষ্টা কৰক।"</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"সংখ্যাবোৰৰ ঊৰ্দ্ধগামী, অধোগামী বা পুনৰাবৃত্তি ক্ৰম অনুমোদিত নহয়"</string>
@@ -1099,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"ৱাই-ফাই"</item>
+    <item msgid="2271962426654621656">"ম’বাইল"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"যদি ৱাই-ফাই উপলব্ধ নহয়, তেন্তে ম’বাইল নেটৱৰ্ক ব্যৱহাৰ কৰক"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"যদি ম’বাইল নেটৱৰ্ক নাথাকে তেন্তে ৱাই-ফাই ব্যৱহাৰ কৰক"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"ৱাই-ফাইৰ জৰিয়তে কল কৰক। ৱাই-ফাই সংযোগ হেৰালে কল সমাপ্ত হ’ব।"</string>
@@ -4233,7 +4239,7 @@
     <string name="storage_music_audio" msgid="3661289086715297149">"সংগীত আৰু ধ্বনি"</string>
     <string name="storage_games" msgid="7740038143749092373">"খেল"</string>
     <string name="storage_other_apps" msgid="3202407095387420842">"অন্যান্য এপসমূহ"</string>
-    <string name="storage_files" msgid="2087824267937487880">"ফাইলসমূহ"</string>
+    <string name="storage_files" msgid="2087824267937487880">"Files"</string>
     <string name="storage_size_large_alternate" msgid="1317796542509105857">"<xliff:g id="NUMBER">^1</xliff:g>"<small>" "<font size="20">"<xliff:g id="UNIT">^2</xliff:g>"</font></small>""</string>
     <string name="storage_volume_total" msgid="5021484171514159913">"<xliff:g id="TOTAL">%1$s</xliff:g>ৰ বাবে ব্যৱহৃত"</string>
     <string name="storage_percent_full" msgid="6924662861545958442">"ব্যৱহৃত"</string>
@@ -4467,7 +4473,7 @@
     <string name="privacy_dashboard_title" msgid="8764930992456607513">"গোপনীয়তা"</string>
     <string name="privacy_dashboard_summary" msgid="7916431309860824945">"অনুমতি, একাউণ্টৰ কাৰ্যকলাপ, ব্যক্তিগত ডেটা"</string>
     <string name="contextual_card_dismiss_remove" msgid="1750420285615827309">"আঁতৰাওক"</string>
-    <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"ৰাখক"</string>
+    <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"Keep"</string>
     <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"এই পৰামৰ্শটো আঁতৰাবনে?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"পৰামৰ্শ আঁতৰোৱা হ’ল"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"আনডু কৰক"</string>
diff --git a/tests/CarDeveloperOptions/res/values-az/arrays.xml b/tests/CarDeveloperOptions/res/values-az/arrays.xml
index d6ee9b7..08f6c45 100644
--- a/tests/CarDeveloperOptions/res/values-az/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-az/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"arka fonda işləyir"</item>
     <item msgid="6423861043647911030">"əlçatımlılıq dərəcəsi"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Yer"</item>
+    <item msgid="6656077694190491067">"Yer"</item>
+    <item msgid="8790228218278477369">"Yer"</item>
+    <item msgid="7836406246005211990">"Vibrasiya"</item>
+    <item msgid="3951439024549922598">"Kontaktları oxuyun"</item>
+    <item msgid="8802152411647068">"Kontaktları dəyişdirin"</item>
+    <item msgid="229544934599698735">"Zəng jurnalı oxuyun"</item>
+    <item msgid="7396102294405899613">"Zəng jurnalına dəyişiklik edin"</item>
+    <item msgid="3597797992398484655">"Təqvim oxuyun"</item>
+    <item msgid="2705975774250907343">"Təqvimə dəyişiklik edin"</item>
+    <item msgid="4668747371441932697">"Yer"</item>
+    <item msgid="1487578921720243646">"Bildiriş göndərin"</item>
+    <item msgid="4636080349724146638">"Məkan"</item>
+    <item msgid="673510900286463926">"Telefon zəngi"</item>
+    <item msgid="542083422784609790">"SMS/MMS oxuyun"</item>
+    <item msgid="1033780373029588436">"SMS/MMS yazın"</item>
+    <item msgid="5647111115517787488">"SMS/MMS alın"</item>
+    <item msgid="8591105601108455893">"SMS/MMS alın"</item>
+    <item msgid="7730995008517841903">"SMS/MMS alın"</item>
+    <item msgid="2613033109026626086">"SMS/MMS alın"</item>
+    <item msgid="3037159047591081136">"SMS/MMS göndərin"</item>
+    <item msgid="4726682243833913568">"SMS/MMS oxuyun"</item>
+    <item msgid="6555678522277865572">"SMS/MMS yazın"</item>
+    <item msgid="6981734935578130884">"Parametrləri dəyişin"</item>
+    <item msgid="8705854389991425629">"Yuxarıda çəkin"</item>
+    <item msgid="5861356020344153651">"Giriş bildirişi"</item>
+    <item msgid="78432174621628659">"Kamera"</item>
+    <item msgid="3986116419882154794">"Səs yazın"</item>
+    <item msgid="4516840825756409490">"Audio oxudun"</item>
+    <item msgid="6811712502798183957">"Mübadilə buferini oxuyun"</item>
+    <item msgid="2780369012602289114">"Mübadilə buferini dəyişin"</item>
+    <item msgid="2331359440170850868">"Media düymələri"</item>
+    <item msgid="6133599737122751231">"Audio fokus"</item>
+    <item msgid="6844485713404805301">"Master həcmi"</item>
+    <item msgid="1600379420669104929">"Səs həcmi"</item>
+    <item msgid="6296768210470214866">"Zəng həcmi"</item>
+    <item msgid="510690696071629241">"Media səsi"</item>
+    <item msgid="406861638631430109">"Siqnal səsi həcmi"</item>
+    <item msgid="4715864795872233884">"Bildiriş səsi"</item>
+    <item msgid="2311478519251301183">"Bluetooth həcmi"</item>
+    <item msgid="5133991377896747027">"Oyaq saxla"</item>
+    <item msgid="2464189519136248621">"Məkan"</item>
+    <item msgid="2062677934050803037">"Yer"</item>
+    <item msgid="1735171933192715957">"İstifadə statistikasını əldə edin"</item>
+    <item msgid="1014093788778383554">"Mikrofonu susdurun/susdurmayın"</item>
+    <item msgid="4199297950608622850">"Tostu göstərin"</item>
+    <item msgid="2527962435313398821">"Layihə mediası"</item>
+    <item msgid="5117506254221861929">"VPN aktivləşdirin"</item>
+    <item msgid="8291198322681891160">"Yazı divar kağızı"</item>
+    <item msgid="7106921284621230961">"Köməkçi struktur"</item>
+    <item msgid="4496533640894624799">"Köməkçi skrinşot"</item>
+    <item msgid="2598847264853993611">"Telefon statusunu oxuyun"</item>
+    <item msgid="9215610846802973353">"Səsli məktub əlavə edin"</item>
+    <item msgid="9186411956086478261">"Sip istifadə edin"</item>
+    <item msgid="6884763100104539558">"Gedən zəngi idarə edin"</item>
+    <item msgid="125513972170580692">"Barmaq izi"</item>
+    <item msgid="2556071024281275619">"Bədən sensorları"</item>
+    <item msgid="617168514928339387">"Şəbəkə yayımlarını oxuyun"</item>
+    <item msgid="7134693570516523585">"Sınaq yeri"</item>
+    <item msgid="7224489175375229399">"Yaddaşı oxuyun"</item>
+    <item msgid="8472735063903258202">"Yaddaşı yazın"</item>
+    <item msgid="4069276819909595110">"Ekranı yandırın"</item>
+    <item msgid="1228338896751121025">"Hesabları əldə edin"</item>
+    <item msgid="3181581793459233672">"Arxa fonda işlədin"</item>
+    <item msgid="2340936043025374076">"Əlçatımlılıq dərəcəsi"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Qısa"</item>
     <item msgid="4816511817309094890">"Orta"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Heç vaxt icazə verməyin"</item>
     <item msgid="8184570120217958741">"Həmişə icazə verin"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Orta"</item>
+    <item msgid="1555861583162930714">"Aşağı"</item>
+    <item msgid="1719683776264798117">"Kritik"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normal"</item>
+    <item msgid="6107138933849816768">"Orta"</item>
+    <item msgid="182695359839047859">"Aşağı"</item>
+    <item msgid="8577246509202964244">"Kritik"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Davamlı"</item>
     <item msgid="167418068739176448">"Top fəaliyyət"</item>
diff --git a/tests/CarDeveloperOptions/res/values-az/config.xml b/tests/CarDeveloperOptions/res/values-az/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-az/config.xml
+++ b/tests/CarDeveloperOptions/res/values-az/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-az/strings.xml b/tests/CarDeveloperOptions/res/values-az/strings.xml
index 0011fd3..35b1f01 100644
--- a/tests/CarDeveloperOptions/res/values-az/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-az/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Ekrandakı mətni kiçildin və ya böyüdün."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Kiçildin"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Böyüdün"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Mətn nümunəsi"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Ozlu Heyrətamiz Sehrbaz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Fəsil 11: Məftunedici Zümrüd Şəhəri Oz"</string>
@@ -668,7 +667,6 @@
       <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> rəqəmdən az olmalıdır</item>
       <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> rəqəmdən az olmalıdır</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Yalnız 0-9 rəqəmlərindən ibarət olmalıdır"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Cihaz admini son vaxtlardakı PIN kodu istifadə etməyə icazə vermir"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Ümumi PIN-lər IT admini tərəfindən blok edilib. Fərqli PIN-i sınayın."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Yalnış simvol daxil edə bilməzsiniz"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Ən azı hərf olmayan <xliff:g id="COUNT">%d</xliff:g> simvol olmalıdır</item>
       <item quantity="one">Ən azı hərf olmayan 1 simvol olmalıdır</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Ən azı rəqəm olmayan <xliff:g id="COUNT">%d</xliff:g> simvol olmalıdır</item>
+      <item quantity="one">Ən azı rəqəm olmayan 1 simvol olmalıdır</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Cihaz admini son vaxtlardakı parolu istifadə etməyə icazə vermir"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Ümumi parollar IT admini tərəfindən blok edilib. Fərqli parolu sınayın."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Artan, azalan və ya təkrarlanan rəqəm ardıcıllığı qadağandır"</string>
@@ -903,7 +905,7 @@
     <string name="wifi_ssid_hint" msgid="5010024648106585165">"SSID daxil edin"</string>
     <string name="wifi_security" msgid="9136702039496152831">"Təhlükəsizlik"</string>
     <string name="wifi_hidden_network" msgid="6647772204699776833">"Gizlədilmiş şəbəkə"</string>
-    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Yönləndirici şəbəkə ID-sini yayımlamırsa, lakin ona gələcəkdə qoşulmaq istəyirsinizsə, şəbəkəni gizlədə bilərsiniz.\n\nBu təhlükəsizliyinizi riskə ata bilər çünki telefon şəbəkəni tapmaq üçün daima siqnal yayımlayacaq.\n\nŞəbəkəini gizlətmək yönləndirici ayarlarını dəyişməyəcək."</string>
+    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Yönləndirici şəbəkə ID-sini yayımlamırsa, lakin ona gələcəkdə qoşulmaq istəyirsinizsə, şəbəkəni gizlədə bilərsiniz.\n\nBu təhlükəsizliyinizi riskə ata bilər, çünki telefon şəbəkəni tapmaq üçün daima siqnal yayımlayacaq.\n\nŞəbəkəini gizlətmək yönləndirici ayarlarını dəyişməyəcək."</string>
     <string name="wifi_signal" msgid="696548364467704808">"Siqnal gücü"</string>
     <string name="wifi_status" msgid="3439931558930689940">"Status"</string>
     <string name="tx_wifi_speed" msgid="2571810085003261073">"Link sürətini ötürün"</string>
@@ -938,7 +940,7 @@
     <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"\"<xliff:g id="SSID">%1$s</xliff:g>\" şəbəkəsinə qoşulmaq üçün aşağıdakı QR kodunu kameranın mərkəzinə tutun"</string>
     <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"QR kodunu skan etməklə Wi‑Fi şəbəkəsinə qoşulun"</string>
     <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Wi‑Fi şəbəkəsini paylaşın"</string>
-    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"\"<xliff:g id="SSID">%1$s</xliff:g>\" şəbəkəsinə qoşulmaq və parolu paylaşmaq üçün bu QR kodu skan edin"</string>
+    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"\"<xliff:g id="SSID">%1$s</xliff:g>\" şəbəkəsinə qoşulmaq və parolu paylaşmaq üçün bu QR kodunu skan edin"</string>
     <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"\"<xliff:g id="SSID">%1$s</xliff:g>\" şəbəkəsinə qoşulmaq üçün bu QR kodu skan edin"</string>
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"QR kodunu oxumaq mümkün olmadı. Kodu mərkəzə tutduqdan sonra yenidən cəhd edin"</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"Yenidən cəhd edin. Problem davam edərsə, cihaz istehsalçısı ilə əlaqə saxlayın"</string>
@@ -1044,7 +1046,7 @@
     <string name="wifi_p2p_menu_search" msgid="8207638860263805291">"Cihaz axtarışı"</string>
     <string name="wifi_p2p_menu_searching" msgid="7443249001543208106">"Axtarır..."</string>
     <string name="wifi_p2p_menu_rename" msgid="2129974878377065488">"Cihazı yenidən adlandır"</string>
-    <string name="wifi_p2p_peer_devices" msgid="8232126067045093382">"Peer cihazlar"</string>
+    <string name="wifi_p2p_peer_devices" msgid="8232126067045093382">"Əlçatımlı cihazlar"</string>
     <string name="wifi_p2p_remembered_groups" msgid="1356458238836730346">"Qrupları yadda saxla"</string>
     <string name="wifi_p2p_failed_connect_message" msgid="6103436959132424093">"Bağlana bilmədi."</string>
     <string name="wifi_p2p_failed_rename_message" msgid="638656605352538706">"Cihazın adı dəyişə bilmədi."</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mobil"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Wi‑Fi əlçatan olmasa, mobil şəbəkədən istifadə edin"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Mobil şəbəkə əlçatan olmasa, Wi‑Fi istifadə edin"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Wi‑Fi ilə zəng edin. Wi‑Fi itsə, zəng sonlandırılacaq."</string>
@@ -2276,7 +2281,7 @@
     <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Batareya həmişə olduğundan daha tez bitə bilər"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Batareya Qənaəti aktivdir"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Bəzi funksiyalar məhddudlaşdırıla bilər"</string>
-    <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Telefon həddindən çox istifadə etdi"</string>
+    <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Telefon gərəkdiyindən daha çox işlədib"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"Planşet hədindən çox istifadə etdi"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"Cihaz həddindən çox istifadə etdi"</string>
     <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"Batareya həmişə olduğundan daha tez bitə bilər"</string>
@@ -2526,7 +2531,7 @@
     <string name="credentials_reset_summary" msgid="7622528359699428555">"Bütün sertifikatları sil"</string>
     <string name="trusted_credentials" msgid="6989242522455395200">"İnanılmış etimadlar"</string>
     <string name="trusted_credentials_summary" msgid="7411781319056251582">"İnanılmış CA sertifikatları göstər"</string>
-    <string name="user_credentials" msgid="8365731467650306757">"İstifadəçi haqqında məlumatlar"</string>
+    <string name="user_credentials" msgid="8365731467650306757">"İstifadəçi məlumatı"</string>
     <string name="user_credentials_summary" msgid="7350223899317423252">"Saxlanılan məlumatlara baxın və dəyişin"</string>
     <string name="advanced_security_title" msgid="286883005673855845">"Qabaqcıl ayarlar"</string>
     <string name="credential_storage_type" msgid="2585337320206095255">"Saxlama növü"</string>
@@ -3129,7 +3134,7 @@
     <string name="sound_settings_summary_vibrate" msgid="2194491116884798590">"Zəng səsi vibrasiya rejimindədir"</string>
     <string name="sound_settings_summary_silent" msgid="899823817462768876">"Zəng səsi səssiz rejimdədir"</string>
     <string name="sound_settings_example_summary" msgid="2091822107298841827">"Zəng səsi 80% faizdir"</string>
-    <string name="media_volume_option_title" msgid="3553411883305505682">"Media həcmi"</string>
+    <string name="media_volume_option_title" msgid="3553411883305505682">"Media səsi"</string>
     <string name="remote_media_volume_option_title" msgid="6355710054191873836">"Yayım həcmi"</string>
     <string name="call_volume_option_title" msgid="5028003296631037334">"Zəng səsi"</string>
     <string name="alarm_volume_option_title" msgid="3184076022438477047">"Siqnal səsi həcmi"</string>
@@ -3189,7 +3194,7 @@
     <string name="zen_mode_summary_combination" msgid="6960111215170691605">"<xliff:g id="MODE">%1$s</xliff:g>: <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
     <string name="zen_mode_visual_interruptions_settings_title" msgid="8378266552787406849">"Vizual fəsadları blok edin"</string>
     <string name="zen_mode_visual_signals_settings_subtitle" msgid="6608239691864638854">"Görünən siqnallara icazə verin"</string>
-    <string name="zen_mode_settings_category" msgid="5601680733422424922">"Narahat Etməyin rejimi aktiv olduqda"</string>
+    <string name="zen_mode_settings_category" msgid="5601680733422424922">"Narahat Etmə rejimi aktiv olduqda"</string>
     <string name="zen_mode_restrict_notifications_title" msgid="7486753018073540477">"Bildirişləri məhdudlaşdırın"</string>
     <string name="zen_mode_restrict_notifications_mute" msgid="2673665450311184875">"Bildirişlər səs çıxarmır"</string>
     <string name="zen_mode_restrict_notifications_mute_summary" msgid="1696217042353376674">"Ekranda bildirişləri görəcəksiniz"</string>
@@ -3689,7 +3694,7 @@
     <string name="memory_avg_desc" msgid="1200185697910086968">"Orta <xliff:g id="MEMORY">%1$s</xliff:g>"</string>
     <string name="memory_use_running_format" msgid="3741170402563292232">"<xliff:g id="MEMORY">%1$s</xliff:g> / <xliff:g id="RUNNING">%2$s</xliff:g>"</string>
     <string name="process_format" msgid="8575347150598564509">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="COUNT">%2$d</xliff:g>)"</string>
-    <string name="high_power_apps" msgid="2518319744362028920">"Batareya optimallaşdırılması"</string>
+    <string name="high_power_apps" msgid="2518319744362028920">"Batareya optimallaşması"</string>
     <string name="additional_battery_info" msgid="6877663897819271203">"İstifadə siqnalları"</string>
     <string name="show_all_apps" msgid="5442552004569634846">"Tam cihaz istifadəsini göstərin"</string>
     <string name="hide_extra_apps" msgid="6798261081113299441">"Tətbiq istifadəsini göstərin"</string>
@@ -3799,7 +3804,7 @@
     <string name="system_alert_window_apps_title" msgid="9188448296493699566">"Tətbiqlər"</string>
     <string name="system_alert_window_access_title" msgid="5187343732185369675">"Tətbiqlər üzərindən görüntüləmə"</string>
     <string name="permit_draw_overlay" msgid="9039092257052422344">"Digər tətbiq üzərindən görüntüləmək icazəsi"</string>
-    <string name="allow_overlay_description" msgid="6669524816705082807">"Bu tətbiqə istifadə etdiyiniz digər tətbiqlərin üzərində göstərilmək icazəsi verin. Bu tətbiq həmin tətbiqlərin istifadəsinə müdaxilə edə və ya tətbiqlərin görünüş və davranışını dəyişə bilər."</string>
+    <string name="allow_overlay_description" msgid="6669524816705082807">"Bu tətbiqə işlətdiyiniz digər tətbiqlərin üzərində göstərilmək icazəsi verin. Bu tətbiq həmin tətbiqlərin istifadəsinə müdaxilə edə və ya tətbiqlərin görünüş və davranışını dəyişə bilər."</string>
     <string name="keywords_vr_listener" msgid="5312633527788917750">"vr virtual reallıq dinləyici stereo köməkçi xidməti"</string>
     <string name="keywords_system_alert_window" msgid="3936658600272194599">"digər tətbiqlərin üzərində sistem siqnalının pəncərə dialoq görüntüsü"</string>
     <string name="overlay_settings" msgid="3325154759946433666">"Tətbiqlər üzərindən görüntüləmə"</string>
diff --git a/tests/CarDeveloperOptions/res/values-b+sr+Latn/arrays.xml b/tests/CarDeveloperOptions/res/values-b+sr+Latn/arrays.xml
index b459ed6..5db0763 100644
--- a/tests/CarDeveloperOptions/res/values-b+sr+Latn/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-b+sr+Latn/arrays.xml
@@ -214,7 +214,7 @@
   </string-array>
   <string-array name="app_ops_categories">
     <item msgid="1102693344156734891">"Lokacija"</item>
-    <item msgid="6842381562497597649">"Lični"</item>
+    <item msgid="6842381562497597649">"Lično"</item>
     <item msgid="3966700236695683444">"Razmena poruka"</item>
     <item msgid="8563996233342430477">"Mediji"</item>
     <item msgid="5323851085993963783">"Uređaj"</item>
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"rad u pozadini"</item>
     <item msgid="6423861043647911030">"jačina zvuka za pristupačnost"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Lokacija"</item>
+    <item msgid="6656077694190491067">"Lokacija"</item>
+    <item msgid="8790228218278477369">"Lokacija"</item>
+    <item msgid="7836406246005211990">"Vibracija"</item>
+    <item msgid="3951439024549922598">"Čitanje kontakata"</item>
+    <item msgid="8802152411647068">"Menjanje kontakata"</item>
+    <item msgid="229544934599698735">"Čitanje evidencije poziva"</item>
+    <item msgid="7396102294405899613">"Menjanje evidencije poziva"</item>
+    <item msgid="3597797992398484655">"Čitanje kalendara"</item>
+    <item msgid="2705975774250907343">"Menjanje kalendara"</item>
+    <item msgid="4668747371441932697">"Lokacija"</item>
+    <item msgid="1487578921720243646">"Postavljanje obaveštenja"</item>
+    <item msgid="4636080349724146638">"Lokacija"</item>
+    <item msgid="673510900286463926">"Pozivanje telefona"</item>
+    <item msgid="542083422784609790">"Čitanje SMS/MMS poruka"</item>
+    <item msgid="1033780373029588436">"Pisanje SMS/MMS poruka"</item>
+    <item msgid="5647111115517787488">"Prijem SMS/MMS poruka"</item>
+    <item msgid="8591105601108455893">"Prijem SMS/MMS poruka"</item>
+    <item msgid="7730995008517841903">"Prijem SMS/MMS poruka"</item>
+    <item msgid="2613033109026626086">"Prijem SMS/MMS poruka"</item>
+    <item msgid="3037159047591081136">"Slanje SMS/MMS poruka"</item>
+    <item msgid="4726682243833913568">"Čitanje SMS/MMS poruka"</item>
+    <item msgid="6555678522277865572">"Pisanje SMS/MMS poruka"</item>
+    <item msgid="6981734935578130884">"Menjanje podešavanja"</item>
+    <item msgid="8705854389991425629">"Povlačenje na vrh"</item>
+    <item msgid="5861356020344153651">"Pristup obaveštenjima"</item>
+    <item msgid="78432174621628659">"Kamera"</item>
+    <item msgid="3986116419882154794">"Snimanje audio zapisa"</item>
+    <item msgid="4516840825756409490">"Puštanje audio zapisa"</item>
+    <item msgid="6811712502798183957">"Čitanje memorije"</item>
+    <item msgid="2780369012602289114">"Menjanje memorije"</item>
+    <item msgid="2331359440170850868">"Dugmad za medije"</item>
+    <item msgid="6133599737122751231">"Audio fokus"</item>
+    <item msgid="6844485713404805301">"Glavna jačina zvuka"</item>
+    <item msgid="1600379420669104929">"Jačina zvuka glasa"</item>
+    <item msgid="6296768210470214866">"Jačina zvuka zvona"</item>
+    <item msgid="510690696071629241">"Jačina zvuka medija"</item>
+    <item msgid="406861638631430109">"Jačina zvuka alarma"</item>
+    <item msgid="4715864795872233884">"Jačina zvuka za obaveštenja"</item>
+    <item msgid="2311478519251301183">"Jačina zvuka Bluetooth-a"</item>
+    <item msgid="5133991377896747027">"Zadrži van stanja spavanja"</item>
+    <item msgid="2464189519136248621">"Lokacija"</item>
+    <item msgid="2062677934050803037">"Lokacija"</item>
+    <item msgid="1735171933192715957">"Preuzmi statistiku o korišćenju"</item>
+    <item msgid="1014093788778383554">"Isključi/uključi zvuk mikrofona"</item>
+    <item msgid="4199297950608622850">"Prikazivanje iskačućih poruka"</item>
+    <item msgid="2527962435313398821">"Mediji za projekat"</item>
+    <item msgid="5117506254221861929">"Aktiviranje VPN-a"</item>
+    <item msgid="8291198322681891160">"Upis na pozadinu"</item>
+    <item msgid="7106921284621230961">"Struktura pomoći"</item>
+    <item msgid="4496533640894624799">"Snimak ekrana pomoći"</item>
+    <item msgid="2598847264853993611">"Čitanje stanja telefona"</item>
+    <item msgid="9215610846802973353">"Dodavanje govorne pošte"</item>
+    <item msgid="9186411956086478261">"Korišćenje SIP-a"</item>
+    <item msgid="6884763100104539558">"Obrada odlaznog poziva"</item>
+    <item msgid="125513972170580692">"Otisak prsta"</item>
+    <item msgid="2556071024281275619">"Senzori za telo"</item>
+    <item msgid="617168514928339387">"Čitanje poruka za mobilne uređaje na lokalitetu"</item>
+    <item msgid="7134693570516523585">"Lažna lokacija"</item>
+    <item msgid="7224489175375229399">"Čitanje memorijskog prostora"</item>
+    <item msgid="8472735063903258202">"Upis podataka u memorijski prostor"</item>
+    <item msgid="4069276819909595110">"Uključivanje ekrana"</item>
+    <item msgid="1228338896751121025">"Pristup nalozima"</item>
+    <item msgid="3181581793459233672">"Rad u pozadini"</item>
+    <item msgid="2340936043025374076">"Jačina zvuka za pristupačnost"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Kratko"</item>
     <item msgid="4816511817309094890">"Srednji"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Nikada ne dozvoli"</item>
     <item msgid="8184570120217958741">"Uvek dozvoli"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normalno"</item>
+    <item msgid="5101233285497327432">"Umereno"</item>
+    <item msgid="1555861583162930714">"Niska"</item>
+    <item msgid="1719683776264798117">"Kritična"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normalna"</item>
+    <item msgid="6107138933849816768">"Umerena"</item>
+    <item msgid="182695359839047859">"Niska"</item>
+    <item msgid="8577246509202964244">"Kritično"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Neprekidna"</item>
     <item msgid="167418068739176448">"Najveća aktivnost"</item>
diff --git a/tests/CarDeveloperOptions/res/values-b+sr+Latn/config.xml b/tests/CarDeveloperOptions/res/values-b+sr+Latn/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-b+sr+Latn/config.xml
+++ b/tests/CarDeveloperOptions/res/values-b+sr+Latn/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-b+sr+Latn/strings.xml b/tests/CarDeveloperOptions/res/values-b+sr+Latn/strings.xml
index be6b529..9e025f3 100644
--- a/tests/CarDeveloperOptions/res/values-b+sr+Latn/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-b+sr+Latn/strings.xml
@@ -84,8 +84,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Omogućava da tekst na ekranu bude manji ili veći."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Umanji"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Uvećaj"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Primer teksta"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Čarobnjak iz Oza"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Poglavlje 11: Čudesni Smaragdni grad Oza"</string>
@@ -507,7 +506,7 @@
     <string name="fingerprint_delete_title" msgid="3120894112324235536">"Uklonite „<xliff:g id="FINGERPRINT_ID">%1$s</xliff:g>“"</string>
     <string name="fingerprint_delete_message" msgid="5895802741486967970">"Želite li da izbrišete ovaj otisak prsta?"</string>
     <string name="fingerprint_last_delete_message" msgid="3346252479778971442">"Nećete moći da otključavate telefon, odobravate kupovine niti da se prijavljujete u aplikacije pomoću otisaka prstiju"</string>
-    <string name="fingerprint_last_delete_message_profile_challenge" msgid="5385095150532247025">"Nećete moći da otključavate profil za Work, odobravate kupovine niti da se prijavljujete u aplikacije za Work pomoću otisaka prstiju"</string>
+    <string name="fingerprint_last_delete_message_profile_challenge" msgid="5385095150532247025">"Nećete moći da otključavate poslovni profil, odobravate kupovine niti da se prijavljujete u poslovne aplikacije pomoću otisaka prstiju"</string>
     <string name="fingerprint_last_delete_confirm" msgid="7984595457589664004">"Da, ukloni"</string>
     <string name="crypt_keeper_settings_title" msgid="839783588093862748">"Šifrovanje"</string>
     <string name="crypt_keeper_encrypt_title" product="tablet" msgid="2292129135369853167">"Šifruj tablet"</string>
@@ -549,7 +548,7 @@
     <string name="suggested_fingerprint_lock_settings_summary" product="device" msgid="8114514312665251311"></string>
     <string name="suggested_fingerprint_lock_settings_summary" product="default" msgid="8114514312665251311"></string>
     <string name="lock_settings_picker_title" msgid="1034741644461982205">"Zaključavanje ekrana"</string>
-    <string name="lock_settings_picker_title_profile" msgid="5086594364428782115">"Izaberite zaključavanje za Work"</string>
+    <string name="lock_settings_picker_title_profile" msgid="5086594364428782115">"Izaberite zaključavanje za posao"</string>
     <string name="setup_lock_settings_picker_title" product="tablet" msgid="2429667472335773519">"Zaštitite tablet"</string>
     <string name="setup_lock_settings_picker_title" product="device" msgid="4739290104106645233">"Zaštitite uređaj"</string>
     <string name="setup_lock_settings_picker_title" product="default" msgid="3911582328576859628">"Zaštitite telefon"</string>
@@ -564,7 +563,7 @@
     <string name="unlock_set_unlock_launch_picker_title" msgid="2731152716948003853">"Zaključavanje ekrana"</string>
     <string name="unlock_set_unlock_launch_picker_summary_lock_immediately" msgid="5596186270725220642">"<xliff:g id="UNLOCK_METHOD">%1$s</xliff:g>/odmah posle spavanja"</string>
     <string name="unlock_set_unlock_launch_picker_summary_lock_after_timeout" msgid="3861167251234952373">"<xliff:g id="UNLOCK_METHOD">%1$s</xliff:g>/<xliff:g id="TIMEOUT_STRING">%2$s</xliff:g> posle spavanja"</string>
-    <string name="unlock_set_unlock_launch_picker_title_profile" msgid="7976345264630422921">"Zaključavanje profila za Work"</string>
+    <string name="unlock_set_unlock_launch_picker_title_profile" msgid="7976345264630422921">"Zaključavanje poslovnog profila"</string>
     <string name="unlock_set_unlock_launch_picker_change_title" msgid="32310692507029407">"Promena zaključ. ekrana"</string>
     <string name="unlock_set_unlock_launch_picker_change_summary" msgid="2072792784866320522">"Menjanje ili onemogućavanje šablona, PIN koda ili bezbednosti lozinke"</string>
     <string name="unlock_set_unlock_launch_picker_enable_summary" msgid="9070847611379078795">"Izaberite metod zaključavanja ekrana"</string>
@@ -648,12 +647,12 @@
     <string name="lock_last_pattern_attempt_before_wipe_user" msgid="5194192938934564218">"Ako u sledećem pokušaju unesete netačan šablon, izbrisaćemo ovog korisnika"</string>
     <string name="lock_last_pin_attempt_before_wipe_user" msgid="7833852187363499906">"Ako u sledećem pokušaju unesete netačan PIN, izbrisaćemo ovog korisnika"</string>
     <string name="lock_last_password_attempt_before_wipe_user" msgid="8979742220140001204">"Ako u sledećem pokušaju unesete netačnu lozinku, izbrisaćemo ovog korisnika"</string>
-    <string name="lock_last_pattern_attempt_before_wipe_profile" msgid="3877613047631174576">"Ako u sledećem pokušaju unesete netačan šablon, izbrisaćemo profil za Work i njegove podatke"</string>
-    <string name="lock_last_pin_attempt_before_wipe_profile" msgid="8132438288175428168">"Ako u sledećem pokušaju unesete netačan PIN, izbrisaćemo profil za Work i njegove podatke"</string>
-    <string name="lock_last_password_attempt_before_wipe_profile" msgid="1535128774464384305">"Ako u sledećem pokušaju unesete netačnu lozinku, izbrisaćemo profil za Work i njegove podatke"</string>
+    <string name="lock_last_pattern_attempt_before_wipe_profile" msgid="3877613047631174576">"Ako u sledećem pokušaju unesete netačan šablon, izbrisaćemo poslovni profil i njegove podatke"</string>
+    <string name="lock_last_pin_attempt_before_wipe_profile" msgid="8132438288175428168">"Ako u sledećem pokušaju unesete netačan PIN, izbrisaćemo poslovni profil i njegove podatke"</string>
+    <string name="lock_last_password_attempt_before_wipe_profile" msgid="1535128774464384305">"Ako u sledećem pokušaju unesete netačnu lozinku, izbrisaćemo poslovni profil i njegove podatke"</string>
     <string name="lock_failed_attempts_now_wiping_device" msgid="8662360098784762828">"Previše netačnih pokušaja. Izbrisaćemo podatke sa ovog uređaja."</string>
     <string name="lock_failed_attempts_now_wiping_user" msgid="3793513796171561873">"Previše netačnih pokušaja. Izbrisaćemo ovog korisnika."</string>
-    <string name="lock_failed_attempts_now_wiping_profile" msgid="5347108525299038285">"Previše netačnih pokušaja. Izbrisaćemo ovaj profil za Work i njegove podatke."</string>
+    <string name="lock_failed_attempts_now_wiping_profile" msgid="5347108525299038285">"Previše netačnih pokušaja. Izbrisaćemo ovaj poslovni profil i njegove podatke."</string>
     <string name="lock_failed_attempts_now_wiping_dialog_dismiss" msgid="3950582268749037318">"Odbaci"</string>
     <plurals name="lockpassword_password_too_short" formatted="false" msgid="694091983183310827">
       <item quantity="one">Mora da sadrži najmanje <xliff:g id="COUNT_1">%d</xliff:g> znak</item>
@@ -676,7 +675,6 @@
       <item quantity="few">Mora da sadrži manje od <xliff:g id="NUMBER_1">%d</xliff:g> cifre</item>
       <item quantity="other">Mora da sadrži manje od <xliff:g id="NUMBER_1">%d</xliff:g> cifara</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Mora da sadrži samo cifre 0–9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Administrator uređaja ne dozvoljava upotrebu nedavno korišćenog PIN-a"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"IT administrator blokira česte PIN-ove. Izaberite drugi PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Ne sme da obuhvata nevažeći znak"</string>
@@ -713,6 +711,11 @@
       <item quantity="few">Mora da sadrži najmanje <xliff:g id="COUNT">%d</xliff:g> znaka koji nisu slova</item>
       <item quantity="other">Mora da sadrži najmanje <xliff:g id="COUNT">%d</xliff:g> znakova koji nisu slova</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">Mora da sadrži najmanje <xliff:g id="COUNT">%d</xliff:g> znak koji nije broj</item>
+      <item quantity="few">Mora da sadrži najmanje <xliff:g id="COUNT">%d</xliff:g> znaka koji nisu brojevi</item>
+      <item quantity="other">Mora da sadrži najmanje <xliff:g id="COUNT">%d</xliff:g> znakova koji nisu brojevi</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Administrator uređaja ne dozvoljava upotrebu nedavno korišćene lozinke"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"IT administrator blokira česte lozinke. Izaberite drugu lozinku."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Rastući, opadajući ili ponovljeni niz cifara nije dozvoljen"</string>
@@ -743,7 +746,7 @@
     <string name="bluetooth_settings" msgid="5228032727293770389">"Bluetooth"</string>
     <string name="bluetooth_settings_title" msgid="7261244857456521825">"Bluetooth"</string>
     <string name="bluetooth_settings_summary" msgid="1221689092429277887">"Upravljanje vezama, podešavanje naziva i vidljivosti uređaja"</string>
-    <string name="bluetooth_pairing_request" msgid="7221745525632573125">"Upariti sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>?"</string>
+    <string name="bluetooth_pairing_request" msgid="7221745525632573125">"Želite da uparite sa <xliff:g id="DEVICE_NAME">%1$s</xliff:g>?"</string>
     <string name="bluetooth_pairing_key_msg" msgid="1139230917419961975">"Kôd za uparivanje sa Bluetooth uređajem"</string>
     <string name="bluetooth_enter_passkey_msg" msgid="6205151011298670207">"Unesite kôd za uparivanje, pa pritisnite Return ili Enter"</string>
     <string name="bluetooth_enable_alphanumeric_pin" msgid="9138308197078115672">"PIN sadrži slova ili simbole"</string>
@@ -941,7 +944,7 @@
     <string name="wifi_ap_choose_auto" msgid="7927637960569365785">"Automatski"</string>
     <string name="wifi_ap_choose_2G" msgid="43198403259714736">"Opseg od 2,4 GHz"</string>
     <string name="wifi_ap_choose_5G" msgid="2624859713183683146">"Opseg od 5,0 GHz"</string>
-    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"Prednost se daje opsegu od 5.0 GHz"</string>
+    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"Prednost ima opseg od 5,0 GHz"</string>
     <string name="wifi_ap_2G" msgid="5793110086517338494">"2,4 GHz"</string>
     <string name="wifi_ap_5G" msgid="4584892544393675403">"5,0 GHz"</string>
     <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"Izaberite barem jedan opseg za Wi‑Fi hotspot:"</string>
@@ -959,8 +962,8 @@
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"Čitanje QR koda nije uspelo. Ponovo centrirajte kôd, pa probajte ponovo"</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"Probajte ponovo. Ako se problem nastavi, kontaktirajte proizvođača uređaja"</string>
     <string name="wifi_dpp_failure_not_compatible" msgid="4320027179973678283">"Došlo je do greške"</string>
-    <string name="wifi_dpp_failure_timeout" msgid="5060065168142109420">"Uverite se da je uređaj priključen na izvor napajanja, napunjen i uključen"</string>
-    <string name="wifi_dpp_failure_generic" msgid="7840142544736640189">"Uverite se da je uređaj priključen na izvor napajanja, napunjen i uključen. Ako se problem nastavi, kontaktirajte proizvođača uređaja"</string>
+    <string name="wifi_dpp_failure_timeout" msgid="5060065168142109420">"Uverite se da je uređaj priključen na struju, napunjen i uključen"</string>
+    <string name="wifi_dpp_failure_generic" msgid="7840142544736640189">"Uverite se da je uređaj priključen na struju, napunjen i uključen. Ako se problem nastavi, kontaktirajte proizvođača uređaja"</string>
     <string name="wifi_dpp_failure_not_supported" msgid="111779621766171626">"Ovaj uređaj ne podržava dodavanje mreže „<xliff:g id="SSID">%1$s</xliff:g>“"</string>
     <string name="wifi_dpp_check_connection_try_again" msgid="7144663015219170999">"Proverite vezu i probajte ponovo"</string>
     <string name="wifi_dpp_choose_network" msgid="6251424431594491691">"Odaberite mrežu"</string>
@@ -977,7 +980,7 @@
     <string name="wifi_dpp_lockscreen_title" msgid="3910665850075275963">"Potvrdite da ste to vi"</string>
     <string name="wifi_dpp_wifi_password" msgid="8007558344032612455">"Lozinka za Wi-Fi: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
     <string name="wifi_dpp_hotspot_password" msgid="6172326289042241924">"Lozinka hotspota: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
-    <string name="wifi_dpp_add_device" msgid="1347056725253936358">"Dodajte uređaj"</string>
+    <string name="wifi_dpp_add_device" msgid="1347056725253936358">"Dodaj uređaj"</string>
     <string name="wifi_dpp_connect_network_using_qr_code" msgid="115993715600532357">"Povežite se na ovu mrežu pomoću QR koda"</string>
     <string name="retry" msgid="8500839563577344702">"Probaj ponovo"</string>
     <string name="wifi_shared" msgid="5054256778276524960">"Deli sa drugim korisnicima uređaja"</string>
@@ -1117,7 +1120,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mobilni podaci"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Ako je Wi‑Fi nedostupan, koristite mobilnu mrežu"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Ako mobilna mreža nije dostupna, koristi Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Pozivanje preko Wi-Fi-ja. Ako se Wi‑Fi veza izgubi, poziv će se završiti."</string>
@@ -1431,7 +1437,7 @@
     <string name="storage_menu_set_up" msgid="2849170579745958513">"Podesi"</string>
     <string name="storage_menu_explore" msgid="3733439525636202662">"Istraži"</string>
     <string name="storage_menu_free" msgid="6586253660759145508">"Oslobodite prostor"</string>
-    <string name="storage_menu_manage" msgid="461380717863926516">"Upravljaj skladištenjem"</string>
+    <string name="storage_menu_manage" msgid="461380717863926516">"Upravljaj memorijskim prostorom"</string>
     <string name="storage_title_usb" msgid="2015671467177303099">"USB uređaj je povezan sa računarom"</string>
     <string name="usb_connection_category" msgid="2888975803638116041">"Poveži kao"</string>
     <string name="usb_mtp_title" msgid="6893938968831995500">"Medijski uređaj (MTP)"</string>
@@ -1580,7 +1586,7 @@
     <string name="error_adding_apn_type" msgid="671634520340569678">"Mobilni operater ne dozvoljava nazive pristupnih tačaka tipa %s."</string>
     <string name="restore_default_apn" msgid="7195266404077471007">"Vraćanje podrazumevanih podešavanja naziva pristupne tačke."</string>
     <string name="menu_restore" msgid="3799288817317293115">"Resetuj na podrazumevano"</string>
-    <string name="restore_default_apn_completed" msgid="5671734152740058937">"Ponovno postavljanje podrazumevanih podešavanja naziva pristupne tačke je završeno"</string>
+    <string name="restore_default_apn_completed" msgid="5671734152740058937">"Ponovno postavljanje podrazumevanih podešavanja naziva pristupne tačke je završeno."</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"Opcije za resetovanje"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"Mreža, aplikacije ili uređaj mogu da se resetuju"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"Resetuj Wi-Fi, mobilnu mrežu i Bluetooth"</string>
@@ -1623,17 +1629,17 @@
     <string name="master_clear_progress_text" msgid="5418958116008976218">"Sačekajte..."</string>
     <string name="call_settings_title" msgid="5033906789261282752">"Podešavanja poziva"</string>
     <string name="call_settings_summary" msgid="2119161087671450035">"Podešavanje glasovne pošte, preusmeravanja poziva, stavljanja poziva na čekanje, ID-a pozivaoca"</string>
-    <string name="tether_settings_title_usb" msgid="4265582654602420357">"USB Internet povezivanje"</string>
+    <string name="tether_settings_title_usb" msgid="4265582654602420357">"USB privezivanje"</string>
     <string name="tether_settings_title_wifi" msgid="2060965130234484613">"Prenosni hotspot"</string>
     <string name="tether_settings_title_bluetooth" msgid="1999590158102569959">"Bluetooth privezivanje"</string>
-    <string name="tether_settings_title_usb_bluetooth" msgid="1159128764162788159">"Povezivanje sa internetom"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="1159128764162788159">"Privezivanje"</string>
     <string name="tether_settings_title_all" msgid="6935843543433954181">"Hotspot i privezivanje"</string>
     <string name="tether_settings_summary_hotspot_on_tether_on" msgid="1289593649526514499">"Hotspot je uključen, privezivanje"</string>
     <string name="tether_settings_summary_hotspot_on_tether_off" msgid="8010689354668285422">"Hotspot je uključen"</string>
     <string name="tether_settings_summary_hotspot_off_tether_on" msgid="1349909238672649877">"Privezivanje"</string>
     <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"Nije moguće privezivanje niti korišćenje prenosivih hotspotova dok je Ušteda podataka uključena"</string>
     <string name="usb_title" msgid="7480927657535578688">"USB"</string>
-    <string name="usb_tethering_button_text" msgid="6242228383142012332">"USB povezivanje"</string>
+    <string name="usb_tethering_button_text" msgid="6242228383142012332">"USB privezivanje"</string>
     <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"Deljenje internet veze telefona preko USB-a"</string>
     <string name="usb_tethering_subtext" product="tablet" msgid="154536000235361034">"Deljenje internet veze tableta preko USB-a"</string>
     <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"Bluetooth privezivanje"</string>
@@ -1652,7 +1658,7 @@
     <string name="sms_change_default_no_previous_dialog_text" msgid="4680224695080527907">"Želite li da koristite <xliff:g id="NEW_APP">%s</xliff:g> kao aplikaciju za SMS?"</string>
     <string name="network_scorer_picker_title" msgid="1691073966560952916">"Dobavljač ocene mreže"</string>
     <string name="network_scorer_picker_none_preference" msgid="6448280557733231737">"Ništa"</string>
-    <string name="network_scorer_change_active_dialog_title" msgid="4274159562371475090">"Želite da promenite Wi‑Fi assistant-a?"</string>
+    <string name="network_scorer_change_active_dialog_title" msgid="4274159562371475090">"Želite da promenite Wi‑Fi pomoćnik?"</string>
     <string name="network_scorer_change_active_dialog_text" msgid="4264089809189760730">"Želite li da koristite aplikaciju <xliff:g id="NEW_APP">%1$s</xliff:g> umesto aplikacije <xliff:g id="CURRENT_APP">%2$s</xliff:g> za upravljanje mrežnim vezama?"</string>
     <string name="network_scorer_change_active_no_previous_dialog_text" msgid="6394483538843474495">"Želite li da koristite aplikaciju <xliff:g id="NEW_APP">%s</xliff:g> za upravljanje mrežnim vezama?"</string>
     <string name="mobile_unknown_sim_operator" msgid="872589370085135817">"Nepoznati SIM operater"</string>
@@ -1670,7 +1676,7 @@
     </plurals>
     <string name="location_category_recent_location_access" msgid="286059523360285026">"Nedavni pristup lokaciji"</string>
     <string name="location_recent_location_access_view_details" msgid="2051602261436245905">"Prikaži detalje"</string>
-    <string name="location_no_recent_apps" msgid="77502059586413278">"Nijedna aplikacija nije skoro tražila lokaciju"</string>
+    <string name="location_no_recent_apps" msgid="77502059586413278">"Nijedna aplikacija nije nedavno tražila lokaciju"</string>
     <string name="location_no_recent_accesses" msgid="6289916310397279890">"Nijedna aplikacija nije nedavno pristupila lokaciji"</string>
     <string name="location_high_battery_use" msgid="7177199869979522663">"Velika potrošnja baterije"</string>
     <string name="location_low_battery_use" msgid="5030448574501435888">"Mala potrošnja baterije"</string>
@@ -1743,15 +1749,15 @@
     <string name="lockpassword_confirm_your_pattern_generic" msgid="6146545393074070916">"Upotrebite šablon za uređaj da biste nastavili"</string>
     <string name="lockpassword_confirm_your_pin_generic" msgid="8732268389177735264">"Unesite PIN uređaja da biste nastavili"</string>
     <string name="lockpassword_confirm_your_password_generic" msgid="6304552647060899594">"Unesite lozinku uređaja da biste nastavili"</string>
-    <string name="lockpassword_confirm_your_pattern_generic_profile" msgid="3074250084050465513">"Upotrebite šablon za profil za Work da biste nastavili"</string>
-    <string name="lockpassword_confirm_your_pin_generic_profile" msgid="6037908971086439523">"Unesite PIN za profil za Work da biste nastavili"</string>
-    <string name="lockpassword_confirm_your_password_generic_profile" msgid="2646162490703489685">"Unesite lozinku za profil za Work da biste nastavili"</string>
+    <string name="lockpassword_confirm_your_pattern_generic_profile" msgid="3074250084050465513">"Upotrebite šablon za poslovni profil da biste nastavili"</string>
+    <string name="lockpassword_confirm_your_pin_generic_profile" msgid="6037908971086439523">"Unesite PIN za poslovni profil da biste nastavili"</string>
+    <string name="lockpassword_confirm_your_password_generic_profile" msgid="2646162490703489685">"Unesite lozinku za poslovni profil da biste nastavili"</string>
     <string name="lockpassword_strong_auth_required_device_pattern" msgid="1014214190135045781">"Radi veće bezbednosti koristite šablon za uređaj"</string>
     <string name="lockpassword_strong_auth_required_device_pin" msgid="24030584350601016">"Radi veće bezbednosti unesite PIN za uređaj"</string>
     <string name="lockpassword_strong_auth_required_device_password" msgid="7746588206458754598">"Radi veće bezbednosti unesite lozinku za uređaj"</string>
-    <string name="lockpassword_strong_auth_required_work_pattern" msgid="6861154706098327320">"Radi veće bezbednosti koristite šablon za Work"</string>
-    <string name="lockpassword_strong_auth_required_work_pin" msgid="6306902249365524526">"Radi veće bezbednosti unesite PIN za Work"</string>
-    <string name="lockpassword_strong_auth_required_work_password" msgid="2917338218971012776">"Radi veće bezbednosti unesite lozinku za Work"</string>
+    <string name="lockpassword_strong_auth_required_work_pattern" msgid="6861154706098327320">"Radi veće bezbednosti koristite šablon za posao"</string>
+    <string name="lockpassword_strong_auth_required_work_pin" msgid="6306902249365524526">"Radi veće bezbednosti unesite poslovni PIN"</string>
+    <string name="lockpassword_strong_auth_required_work_password" msgid="2917338218971012776">"Radi veće bezbednosti unesite poslovnu lozinku"</string>
     <string name="lockpassword_confirm_your_pattern_details_frp" msgid="1085862410379709928">"Telefon je resetovan na fabrička podešavanja. Da biste ga koristili, unesite prethodni šablon."</string>
     <string name="lockpassword_confirm_your_pin_details_frp" msgid="6849889353126558761">"Telefon je resetovan na fabrička podešavanja. Da biste ga koristili, unesite prethodni PIN."</string>
     <string name="lockpassword_confirm_your_password_details_frp" msgid="3239944795659418737">"Telefon je resetovan na fabrička podešavanja. Da biste ga koristili, unesite prethodnu lozinku."</string>
@@ -1788,13 +1794,13 @@
     <string name="lockpattern_settings_help_how_to_record" msgid="6037403647312543908">"Kako nacrtati šablon za otključavanje"</string>
     <string name="lockpattern_too_many_failed_confirmation_attempts" msgid="3043127997770535921">"Previše netačnih pokušaja. Probajte ponovo za <xliff:g id="NUMBER">%d</xliff:g> sek."</string>
     <string name="activity_not_found" msgid="3492413375341165453">"Aplikacija nije instalirana na telefonu."</string>
-    <string name="lock_settings_profile_title" msgid="3928992050074556160">"Bezbednost profila za Work"</string>
-    <string name="lock_settings_profile_screen_lock_title" msgid="285267471459162203">"Zaključavanje ekrana za profil za Work"</string>
+    <string name="lock_settings_profile_title" msgid="3928992050074556160">"Bezbednost poslovnog profila"</string>
+    <string name="lock_settings_profile_screen_lock_title" msgid="285267471459162203">"Zaključavanje ekrana za poslovni profil"</string>
     <string name="lock_settings_profile_unification_title" msgid="2629698644191935287">"Koristi jedno zaključavanje"</string>
-    <string name="lock_settings_profile_unification_summary" msgid="4797188229308317207">"Koristite jedno zaključavanje ekrana za profil za Work i uređaj"</string>
+    <string name="lock_settings_profile_unification_summary" msgid="4797188229308317207">"Koristite jedno zaključavanje ekrana za poslovni profil i uređaj"</string>
     <string name="lock_settings_profile_unification_dialog_title" msgid="1690211342491067179">"Želite li da koristite jedno zaključavanje?"</string>
-    <string name="lock_settings_profile_unification_dialog_body" msgid="8629158560032603101">"Uređaj će koristiti zaključavanje ekrana za Work profil. Smernice za Work će se primenjivati na oba zaključavanja."</string>
-    <string name="lock_settings_profile_unification_dialog_uncompliant_body" msgid="1217609779267643474">"Zaključavanje ekrana za profil za Work nije u skladu sa bezbednosnim zahtevima vaše organizacije. Možete da koristite isto zaključavanje ekrana za uređaj i profil za Work, ali će se primenjivati sve smernice za zaključavanje ekrana za Work."</string>
+    <string name="lock_settings_profile_unification_dialog_body" msgid="8629158560032603101">"Uređaj će koristiti zaključavanje ekrana za poslovni profil. Smernice za posao će se primenjivati na oba zaključavanja."</string>
+    <string name="lock_settings_profile_unification_dialog_uncompliant_body" msgid="1217609779267643474">"Zaključavanje ekrana za poslovni profil nije u skladu sa bezbednosnim zahtevima vaše organizacije. Možete da koristite isto zaključavanje ekrana za uređaj i poslovni profil, ali će se primenjivati sve smernice za zaključavanje ekrana za posao."</string>
     <string name="lock_settings_profile_unification_dialog_confirm" msgid="888942752619181804">"Koristi jedno zaključavanje"</string>
     <string name="lock_settings_profile_unification_dialog_uncompliant_confirm" msgid="8046452284593057185">"Koristi jedno zaključavanje"</string>
     <string name="lock_settings_profile_unified_summary" msgid="5347244550751740962">"Isto kao zaključavanje ekrana uređaja"</string>
@@ -1988,7 +1994,7 @@
     <string name="show_ime_summary" msgid="3246628154011464373">"Zadrži je na ekranu dok je fizička tastatura aktivna"</string>
     <string name="keyboard_shortcuts_helper" msgid="6574386807271399788">"Pomoć za tasterske prečice"</string>
     <string name="keyboard_shortcuts_helper_summary" msgid="8024313306403779742">"Prikaz dostupnih prečica"</string>
-    <string name="language_and_input_for_work_category_title" msgid="2053255944038892588">"Tastature i alatke za profil za Work"</string>
+    <string name="language_and_input_for_work_category_title" msgid="2053255944038892588">"Tastature i alatke za poslovni profil"</string>
     <string name="virtual_keyboards_for_work_title" msgid="3968291646938204523">"Virtuelna tastatura za posao"</string>
     <string name="default_keyboard_layout" msgid="9171704064451242230">"Podrazumevano"</string>
     <string name="pointer_speed" msgid="800691982011350432">"Brzina pokazivača"</string>
@@ -2300,7 +2306,7 @@
     <string name="battery_tip_smart_battery_title" product="tablet" msgid="203494973250969040">"Produžite trajanje baterije tableta"</string>
     <string name="battery_tip_smart_battery_title" product="device" msgid="7419448992583346364">"Produžite trajanje baterije uređaja"</string>
     <string name="battery_tip_smart_battery_summary" msgid="5344821856478265778">"Uključite menadžer baterije"</string>
-    <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Uključi uštedu baterije"</string>
+    <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Uključite uštedu baterije"</string>
     <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Baterija može da se isprazni ranije nego obično"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Ušteda baterije je uključena"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Neke funkcije mogu da budu ograničene"</string>
@@ -2595,7 +2601,7 @@
     <string name="fullbackup_erase_dialog_message" msgid="2588536036471144070">"Želite li da zaustavite pravljenje rezervnih kopija podataka uređaja (poput Wi-Fi lozinki i istorije poziva) i podataka aplikacija (poput podešavanja i datoteka sačuvanih u aplikacijama) i izbrišete sve kopije na udaljenim serverima?"</string>
     <string name="fullbackup_data_summary" msgid="406274198094268556">"Automatski pravite rezervne kopije podataka uređaja (poput Wi-Fi lozinki i istorije poziva) i podataka aplikacija (poput podešavanja i datoteka sačuvanih u aplikacijama) daljinski.\n\nKada uključite automatsko pravljenje rezervnih kopija, podaci uređaja i aplikacija se povremeno čuvaju daljinski. Podaci aplikacija mogu da budu bilo koji podaci koje je aplikacija sačuvala (na osnovu podešavanja programera), uključujući potencijalno osetljive podatke kao što su kontakti, poruke i slike."</string>
     <string name="device_admin_settings_title" msgid="2074319456047334589">"Podešavanja administratora uređaja"</string>
-    <string name="active_device_admin_msg" msgid="6929247869516924549">"Aplikacija za administratore uređaja"</string>
+    <string name="active_device_admin_msg" msgid="6929247869516924549">"Aplikacija za administratora uređaja"</string>
     <string name="remove_device_admin" msgid="4413438593788336400">"Deaktiviraj ovu aplikaciju za administratora uređaja"</string>
     <string name="uninstall_device_admin" msgid="9017499299961719830">"Deinstaliraj aplikaciju"</string>
     <string name="remove_and_uninstall_device_admin" msgid="5607703579731496253">"Deaktiviraj i deinstaliraj"</string>
@@ -2610,7 +2616,7 @@
     <string name="add_device_admin" msgid="1621152410207260584">"Aktiviraj ovu aplikaciju za administratore uređaja"</string>
     <string name="device_admin_add_title" msgid="6097881332139146897">"Administrator uređaja"</string>
     <string name="device_admin_warning" msgid="4421817419326480449">"Aktiviranje ove aplikacije za administratore omogućiće aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> da obavi sledeće operacije:"</string>
-    <string name="device_admin_status" msgid="5424944611789040723">"Ova aplikacija za administratore je aktivna i omogućava aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> da obavi sledeće operacije:"</string>
+    <string name="device_admin_status" msgid="5424944611789040723">"Ova aplikacija za administratora je aktivna i omogućava aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> da obavi sledeće operacije:"</string>
     <string name="profile_owner_add_title" msgid="735805919754362791">"Aktivirati Menadžera profila?"</string>
     <string name="adding_profile_owner_warning" msgid="1284541194547382194">"Ako nastavite, korisnikom će upravljati administrator, koji će možda moći da čuva i povezane podatke, pored ličnih podataka.\n\nAdministrator može da prati podešavanja, pristup, aplikacije i podatke povezane sa ovim korisnikom, uključujući aktivnosti na mreži i informacije o lokaciji uređaja, kao i da upravlja njima."</string>
     <string name="admin_disabled_other_options" msgid="8097063307730025707">"Administrator je onemogućio druge opcije"</string>
@@ -2628,10 +2634,10 @@
     <string name="sync_is_failing" msgid="8284618104132302644">"Sinhronizacija trenutno ima problema. Uskoro će se vratiti."</string>
     <string name="add_account_label" msgid="4461298847239641874">"Dodaj nalog"</string>
     <string name="managed_profile_not_available_label" msgid="8784246681719821917">"Poslovni profil još uvek nije dostupan"</string>
-    <string name="work_mode_label" msgid="6845849194740195757">"Profil za Work"</string>
+    <string name="work_mode_label" msgid="6845849194740195757">"Poslovni profil"</string>
     <string name="work_mode_on_summary" msgid="1682781113156323592">"Ovim upravlja organizacija"</string>
     <string name="work_mode_off_summary" msgid="1688885392211178315">"Aplikacije i obaveštenja su isključeni"</string>
-    <string name="remove_managed_profile_label" msgid="4625542553784793536">"Ukloni profil za posao"</string>
+    <string name="remove_managed_profile_label" msgid="4625542553784793536">"Ukloni poslovni profil"</string>
     <string name="background_data" msgid="8275750862371471171">"Podaci o pozadini"</string>
     <string name="background_data_summary" msgid="799640633948841990">"Aplikacije uvek mogu da sinhronizuju, šalju i primaju podatke"</string>
     <string name="background_data_dialog_title" msgid="8306650658158895976">"Želite da onemogućite pozadinske podatke?"</string>
@@ -2871,7 +2877,7 @@
       <item quantity="other"><xliff:g id="MANAGING_DOMAIN_1">%s</xliff:g> su instalirala autoritete za izdavanje sertifikata na uređaju, što može da im omogući da prate aktivnosti uređaja na mreži, uključujući imejlove, aplikacije i bezbedne veb-sajtove.\n\nKontaktirajte administratora da biste dobili više informacija o ovim sertifikatima.</item>
     </plurals>
     <plurals name="ssl_ca_cert_info_message" formatted="false" msgid="8271858091418779584">
-      <item quantity="one"><xliff:g id="MANAGING_DOMAIN_1">%s</xliff:g> je instalirao autoritete za izdavanje sertifikata za profil za Work, što može da mu omogući da prati aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i bezbedne veb-sajtove.\n\nKontaktirajte administratora da biste dobili više informacija o ovim sertifikatima.</item>
+      <item quantity="one"><xliff:g id="MANAGING_DOMAIN_1">%s</xliff:g> je instalirao autoritete za izdavanje sertifikata za poslovni profil, što može da mu omogući da prati aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i bezbedne veb-sajtove.\n\nKontaktirajte administratora da biste dobili više informacija o ovim sertifikatima.</item>
       <item quantity="few"><xliff:g id="MANAGING_DOMAIN_1">%s</xliff:g> su instalirala autoritete za izdavanje sertifikata na uređaju, što može da im omogući da prate aktivnosti uređaja na mreži, uključujući imejlove, aplikacije i bezbedne veb-sajtove.\n\nKontaktirajte administratora da biste dobili više informacija o ovim sertifikatima.</item>
       <item quantity="other"><xliff:g id="MANAGING_DOMAIN_1">%s</xliff:g> su instalirala autoritete za izdavanje sertifikata na uređaju, što može da im omogući da prate aktivnosti uređaja na mreži, uključujući imejlove, aplikacije i bezbedne veb-sajtove.\n\nKontaktirajte administratora da biste dobili više informacija o ovim sertifikatima.</item>
     </plurals>
@@ -3128,7 +3134,7 @@
     <string name="keywords_color_temperature" msgid="2255253972992035046">"boja, temperatura, D65, D73, bela, žuta, plava, topla, hladna"</string>
     <string name="keywords_lockscreen" msgid="4936846554280830394">"prevlačenje za otključavanje, lozinka, šablon, PIN"</string>
     <string name="keywords_profile_challenge" msgid="8653718001253979611">"work izazov, work, profil"</string>
-    <string name="keywords_unification" msgid="2020759909366983593">"profil za Work, profil kojim se upravlja, objedini, objedinjavanje, Work, profil"</string>
+    <string name="keywords_unification" msgid="2020759909366983593">"poslovni profil, profil kojim se upravlja, objedini, objedinjavanje, posao, profil"</string>
     <string name="keywords_gesture" msgid="5031323247529869644">"pokreti"</string>
     <string name="keywords_payment_settings" msgid="4745023716567666052">"platite, dodirnite, plaćanja"</string>
     <string name="keywords_backup" msgid="7433356270034921627">"rezervna kopija, praviti rezervnu kopiju"</string>
@@ -3184,7 +3190,7 @@
     <string name="other_sound_settings" msgid="5250376066099818676">"Drugi zvukovi"</string>
     <string name="dial_pad_tones_title" msgid="8877212139988655769">"Tonovi numeričke tastature"</string>
     <string name="screen_locking_sounds_title" msgid="4407110895465866809">"Zvukovi zaključavanja ekrana"</string>
-    <string name="charging_sounds_title" msgid="5070437987230894287">"Menjajući zvuci i vibracija"</string>
+    <string name="charging_sounds_title" msgid="5070437987230894287">"Zvukovi i vibracija punjenja"</string>
     <string name="docking_sounds_title" msgid="2573137471605541366">"Zvukovi montiranja"</string>
     <string name="touch_sounds_title" msgid="165237488496165652">"Zvukovi pri dodiru"</string>
     <string name="vibrate_on_touch_title" msgid="6360155469279157684">"Vibracija pri dodiru"</string>
@@ -3249,10 +3255,10 @@
     <string name="zen_mode_block_effects_screen_off" msgid="6380935819882837552">"Kada je ekran isključen"</string>
     <string name="zen_mode_block_effect_sound" msgid="1499243540186357631">"Isključi zvuk i vibraciju"</string>
     <string name="zen_mode_block_effect_intent" msgid="5666951244667422668">"Ne uključuj ekran"</string>
-    <string name="zen_mode_block_effect_light" msgid="8679333758037487644">"Ne koristi treperenje lampice"</string>
+    <string name="zen_mode_block_effect_light" msgid="8679333758037487644">"Ne treperi lampicom"</string>
     <string name="zen_mode_block_effect_peek" msgid="6075662813575910221">"Ne prikazuj iskačuća obaveštenja na ekranu"</string>
     <string name="zen_mode_block_effect_status" msgid="6516614225115681068">"Sakrij ikone statusne trake u vrhu"</string>
-    <string name="zen_mode_block_effect_badge" msgid="3891743027347075136">"Sakrij tačke za obav. na ikonama apl."</string>
+    <string name="zen_mode_block_effect_badge" msgid="3891743027347075136">"Sakrij tačke za obaveštenja na ikonama aplikacija"</string>
     <string name="zen_mode_block_effect_ambient" msgid="6382013125863616197">"Ne budi zbog obaveštenja"</string>
     <string name="zen_mode_block_effect_list" msgid="6081548478844912181">"Ne prikazuj na listi obaveštenja"</string>
     <string name="zen_mode_block_effect_summary_none" msgid="7166175186759564510">"Nikad"</string>
@@ -3310,7 +3316,7 @@
     <string name="zen_custom_settings_notifications_header" msgid="7469592764589354302">"Obaveštenja"</string>
     <string name="zen_custom_settings_duration_header" msgid="1806465684026300942">"Trajanje"</string>
     <string name="zen_msg_event_reminder_title" msgid="8685224436389816905">"Poruke, događaji i podsetnici"</string>
-    <string name="zen_msg_event_reminder_footer" msgid="164400918479831580">"Kada je uključen režim Ne uznemiravaj, zvukovi obaveštenja za poruke, podsetnike i događaje će biti isključeni, osim za stavke koje ste dozvolili iznad. Možete da prilagodite podešavanja da biste dozvolili prijateljima, članovima porodice ili drugim kontaktima da vas kontaktiraju."</string>
+    <string name="zen_msg_event_reminder_footer" msgid="164400918479831580">"Kada je uključen režim Ne uznemiravaj, zvukovi obaveštenja za poruke, podsetnike i događaje će biti isključeni, osim za stavke koje ste dozvolili iznad. Možete da prilagodite podešavanja i dozvolite prijateljima, članovima porodice ili drugim kontaktima da dopru do vas."</string>
     <string name="zen_onboarding_ok" msgid="6403635918125323678">"Gotovo"</string>
     <string name="zen_onboarding_settings" msgid="1416466597876383322">"Podešavanja"</string>
     <string name="zen_onboarding_new_setting_title" msgid="3622673375041304362">"Bez zvučnog signala ili vizuelnog obaveštenja"</string>
@@ -3318,16 +3324,16 @@
     <string name="zen_onboarding_new_setting_summary" msgid="8264430315983860075">"Nećete videti niti čuti obaveštenja. Pozivi od kontakata sa zvezdicom i ponovnih pozivalaca su dozvoljeni."</string>
     <string name="zen_onboarding_current_setting_summary" msgid="3569246708507270821">"(trenutno podešavanje)"</string>
     <string name="zen_onboarding_dnd_visual_disturbances_header" msgid="7584229011611927613">"Želite li da promenite podešavanja obaveštenja za režim Ne uznemiravaj?"</string>
-    <string name="sound_work_settings" msgid="4140215240360927923">"Zvuci za profil za Work"</string>
+    <string name="sound_work_settings" msgid="4140215240360927923">"Zvuci za poslovni profil"</string>
     <string name="work_use_personal_sounds_title" msgid="531727195073003599">"Koristi zvuke ličnog profila"</string>
-    <string name="work_use_personal_sounds_summary" msgid="2886871383995187441">"Zvukovi profila za Work su isti kao i zvukovi za lične profile"</string>
-    <string name="work_ringtone_title" msgid="5499360583947410224">"Melodija zvona za telefon za Work"</string>
+    <string name="work_use_personal_sounds_summary" msgid="2886871383995187441">"Zvukovi poslovnog profila su isti kao i zvukovi za lične profile"</string>
+    <string name="work_ringtone_title" msgid="5499360583947410224">"Melodija zvona poslovnog telefona"</string>
     <string name="work_notification_ringtone_title" msgid="8059159087214025757">"Podrazumevani zvuk obaveštenja za posao"</string>
     <string name="work_alarm_ringtone_title" msgid="5328487181385375130">"Podrazumevani zvuk alarma za posao"</string>
     <string name="work_sound_same_as_personal" msgid="7728560881697159758">"Isto kao i za lični profil"</string>
     <string name="work_sync_dialog_title" msgid="4799120971202956837">"Želite li da zamenite zvukove?"</string>
     <string name="work_sync_dialog_yes" msgid="2110726233746476066">"Zameni"</string>
-    <string name="work_sync_dialog_message" msgid="944233463059129156">"Zvuci sa ličnog profila će se koristiti za profil za Work"</string>
+    <string name="work_sync_dialog_message" msgid="944233463059129156">"Zvuci sa ličnog profila će se koristiti za poslovni profil"</string>
     <string name="ringtones_install_custom_sound_title" msgid="210551218424553671">"Dodati prilagođeni zvuk?"</string>
     <string name="ringtones_install_custom_sound_content" msgid="6683649115132255452">"Ova datoteka će biti kopirana u direktorijum <xliff:g id="FOLDER_NAME">%s</xliff:g>"</string>
     <string name="ringtones_category_preference_title" msgid="4491932700769815470">"Melodije zvona"</string>
@@ -3336,7 +3342,7 @@
     <string name="recent_notifications" msgid="8125865995065032049">"Nedavno poslato"</string>
     <string name="recent_notifications_see_all_title" msgid="4089007770442871469">"Pogledajte sve iz poslednjih 7 dana"</string>
     <string name="advanced_section_header" msgid="984680389373090015">"Napredna"</string>
-    <string name="profile_section_header" msgid="5471479005472037417">"Obaveštenja za Work"</string>
+    <string name="profile_section_header" msgid="5471479005472037417">"Poslovna obaveštenja"</string>
     <string name="asst_capability_prioritizer_title" msgid="3488284760645922160">"Automatsko davanje prioriteta za obaveštenja"</string>
     <string name="asst_capability_prioritizer_summary" msgid="3525640645743790796">"Automatski isključuje zvuk i postavlja na dno manje važna obaveštenja"</string>
     <string name="asst_capabilities_actions_replies_title" msgid="3929395108744251338">"Pametne radnje i odgovori"</string>
@@ -3358,14 +3364,14 @@
     <string name="swipe_direction_rtl" msgid="4521416787262888813">"Prevucite ulevo da biste odbacili, udesno da bi se prikazao meni"</string>
     <string name="notification_pulse_title" msgid="4861418327614907116">"Uključi treperenje lampice"</string>
     <string name="lock_screen_notifications_title" msgid="6889072265118747835">"Na zaključanom ekranu"</string>
-    <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"Kada je profil za Work zaključan"</string>
+    <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"Kada je poslovni profil zaključan"</string>
     <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Prikaži sav sadržaj obaveštenja"</string>
     <string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"Sakrij osetljiv sadržaj"</string>
     <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"Ne prikazuj nikakva obaveštenja"</string>
     <string name="lock_screen_notifications_interstitial_message" msgid="4230189215124387818">"Kada je uređaj zaključan, kako želite da se obaveštenja prikazuju?"</string>
     <string name="lock_screen_notifications_interstitial_title" msgid="2832587379332443505">"Obaveštenja"</string>
-    <string name="lock_screen_notifications_summary_show_profile" msgid="8908775469657073273">"Prikazuj sav sadržaj obaveštenja o profilu za Work"</string>
-    <string name="lock_screen_notifications_summary_hide_profile" msgid="7898086300511010591">"Sakrij osetljiv sadržaj profila za Work"</string>
+    <string name="lock_screen_notifications_summary_show_profile" msgid="8908775469657073273">"Prikazuj sav sadržaj obaveštenja o poslovnom profilu"</string>
+    <string name="lock_screen_notifications_summary_hide_profile" msgid="7898086300511010591">"Sakrij osetljiv sadržaj poslovnog profila"</string>
     <string name="lock_screen_notifications_interstitial_message_profile" msgid="3324187664458600354">"Kada je uređaj zaključan, kako želite da se prikazuju obaveštenja o profilu?"</string>
     <string name="lock_screen_notifications_interstitial_title_profile" msgid="4043621508889929254">"Obaveštenja o profilu"</string>
     <string name="notifications_title" msgid="8334011924253810654">"Obaveštenja"</string>
@@ -3399,7 +3405,7 @@
     <string name="notifications_sent_weekly" msgid="5859675428990259432">"~<xliff:g id="NUMBER">%1$s</xliff:g> nedeljno"</string>
     <string name="notifications_sent_never" msgid="237997329598144638">"Nikad"</string>
     <string name="manage_notification_access_title" msgid="5348743662189787547">"Pristup obaveštenjima"</string>
-    <string name="work_profile_notification_access_blocked_summary" msgid="8148871282484870576">"Pristup obaveštenjima profila za Work je blokiran"</string>
+    <string name="work_profile_notification_access_blocked_summary" msgid="8148871282484870576">"Pristup obaveštenjima poslovnog profila je blokiran"</string>
     <string name="manage_notification_access_summary_zero" msgid="236809421271593016">"Aplikacije ne mogu da čitaju obaveštenja"</string>
     <plurals name="manage_notification_access_summary_nonzero" formatted="false" msgid="8496218948429646792">
       <item quantity="one">%d aplikacija može da čita obaveštenja</item>
@@ -3485,7 +3491,7 @@
     <string name="zen_mode_add_time_rule" msgid="5999467757140524729">"Dodajte vremenski raspored"</string>
     <string name="zen_mode_delete_rule" msgid="2292933835997203801">"Izbriši raspored"</string>
     <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"Odaberite tip rasporeda"</string>
-    <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"Želite li da izbrišete pravilo „<xliff:g id="RULE">%1$s</xliff:g>“?"</string>
+    <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"Želite da izbrišete pravilo „<xliff:g id="RULE">%1$s</xliff:g>“?"</string>
     <string name="zen_mode_delete_rule_button" msgid="611058106279881991">"Izbriši"</string>
     <string name="zen_mode_rule_type_unknown" msgid="2819480113355191421">"Nepoznato"</string>
     <string name="zen_mode_app_set_behavior" msgid="8597398780262575571">"Ova podešavanja trenutno ne mogu da se menjaju. Aplikacija (<xliff:g id="APP_NAME">%1$s</xliff:g>) je automatski uključila režim Ne uznemiravaj sa prilagođenim ponašanjem."</string>
@@ -3522,7 +3528,7 @@
     <string name="zen_mode_calls" msgid="1844534357711539325">"Dozvoli pozive"</string>
     <string name="zen_mode_calls_title" msgid="2024387562355793661">"Pozivi"</string>
     <string name="zen_mode_calls_footer" msgid="6319824006810688433">"Da biste bili sigurni da će se dozvoljeni pozivi čuti, proverite da li je uređaj podešen da zvoni, vibrira ili je u nečujnom režimu."</string>
-    <string name="zen_mode_custom_calls_footer" msgid="7329231648477682337">"Dolazni pozivi su blokirani za „<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>“. Možete da prilagodite podešavanja da biste dozvolili prijateljima, članovima porodice ili drugim kontaktima da vas kontaktiraju."</string>
+    <string name="zen_mode_custom_calls_footer" msgid="7329231648477682337">"Dolazni pozivi su blokirani za „<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>“. Možete da prilagodite podešavanja i dozvolite prijateljima, članovima porodice ili drugim kontaktima da dopru do vas."</string>
     <string name="zen_mode_starred_contacts_title" msgid="7099621384597127058">"Kontakti sa zvezdicom"</string>
     <plurals name="zen_mode_starred_contacts_summary_additional_contacts" formatted="false" msgid="1904181007981570805">
       <item quantity="one">Još <xliff:g id="NUM_PEOPLE">%d</xliff:g> osoba</item>
@@ -3531,7 +3537,7 @@
     </plurals>
     <string name="zen_mode_messages" msgid="2908722562188394107">"Dozvoli poruke"</string>
     <string name="zen_mode_messages_footer" msgid="5048951937714668561">"Da biste bili sigurni da će se dozvoljene poruke čuti, proverite da li je uređaj podešen da zvoni, vibrira ili je u nečujnom režimu."</string>
-    <string name="zen_mode_custom_messages_footer" msgid="5566007423100361691">"Dolazne poruke su blokirane za „<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>“. Možete da prilagodite podešavanja da biste dozvolili prijateljima, članovima porodice ili drugim kontaktima da vas kontaktiraju."</string>
+    <string name="zen_mode_custom_messages_footer" msgid="5566007423100361691">"Dolazne poruke su blokirane za „<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>“. Možete da prilagodite podešavanja i dozvolite prijateljima, članovima porodice ili drugim kontaktima da dopru do vas."</string>
     <string name="zen_mode_messages_title" msgid="786261471294055181">"SMS, MMS i aplikacije za razmenu poruka"</string>
     <string name="zen_mode_from_anyone" msgid="7778836826814131083">"Od bilo koga"</string>
     <string name="zen_mode_from_contacts" msgid="267034158294332688">"Samo od kontakata"</string>
@@ -3539,7 +3545,7 @@
     <string name="zen_calls_summary_starred_repeat" msgid="9191394641577678207">"Od kontakata sa zvezdicom i ponovnih pozivalaca"</string>
     <string name="zen_calls_summary_contacts_repeat" msgid="7747592096431111510">"Od kontakata i ponovnih pozivalaca"</string>
     <string name="zen_calls_summary_repeat_only" msgid="8839703337232747964">"Samo od ponovnih pozivalaca"</string>
-    <string name="zen_mode_from_none" msgid="7683889985618637010">"Ni od koga"</string>
+    <string name="zen_mode_from_none" msgid="7683889985618637010">"Niko"</string>
     <string name="zen_mode_from_none_calls" msgid="2967739140346917546">"Ne dozvoli pozive"</string>
     <string name="zen_mode_from_none_messages" msgid="9069143820057833634">"Ne dozvoljavaj nikakve poruke"</string>
     <string name="zen_mode_alarms" msgid="5528707742250954290">"Dozvoli alarme"</string>
@@ -3606,7 +3612,7 @@
     <string name="screen_pinning_unlock_pin" msgid="1441705536015645023">"Traži PIN pre otkačinjanja"</string>
     <string name="screen_pinning_unlock_password" msgid="1017776884000170841">"Traži lozinku pre otkačinjanja"</string>
     <string name="screen_pinning_unlock_none" msgid="9183040569733226911">"Zaključaj uređaj pre otkačinjanja"</string>
-    <string name="opening_paragraph_delete_profile_unknown_company" msgid="2350380017136403670">"Ovim profilom za Work upravlja:"</string>
+    <string name="opening_paragraph_delete_profile_unknown_company" msgid="2350380017136403670">"Ovim poslovnim profilom upravlja:"</string>
     <string name="managing_admin" msgid="3212584016377581608">"Upravlja <xliff:g id="ADMIN_APP_LABEL">%s</xliff:g>"</string>
     <string name="experimental_preference" msgid="5903223408406906322">"(Eksperimentalno)"</string>
     <string name="encryption_interstitial_header" msgid="3298397268731647519">"Bezbedno pokretanje"</string>
@@ -3764,8 +3770,8 @@
     <string name="high_power_off" msgid="5906679734326490426">"Optimizacija korišćenja baterije"</string>
     <string name="high_power_system" msgid="739584574711292753">"Optimizacija baterije nije dostupna"</string>
     <string name="high_power_desc" msgid="333756885680362741">"Ne primenjujte optimizaciju baterije. Može brže da isprazni bateriju."</string>
-    <string name="high_power_prompt_title" msgid="2805745781720454052">"Želite li da dozvolite da aplikacija uvek bude aktivna u pozadini?"</string>
-    <string name="high_power_prompt_body" msgid="8067395096053552289">"Ako dozvolite da aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> uvek bude aktivna u pozadini, to može da smanji trajanje baterije. \n\nKasnije možete to da promenite u odeljku Podešavanja &gt; Aplikacije i obaveštenja."</string>
+    <string name="high_power_prompt_title" msgid="2805745781720454052">"Dozvoljavate da aplikacija uvek bude aktivna u pozadini?"</string>
+    <string name="high_power_prompt_body" msgid="8067395096053552289">"Ako dozvolite da aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> uvek bude aktivna u pozadini, to može da skrati trajanje baterije. \n\nKasnije možete to da promenite u odeljku Podešavanja &gt; Aplikacije i obaveštenja."</string>
     <string name="battery_summary" msgid="4345690800899981339">"Potrošeno je <xliff:g id="PERCENTAGE">%1$s</xliff:g> od poslednjeg potpunog punjenja"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"Upravljanje napajanjem"</string>
     <string name="no_battery_summary" msgid="4105932628367471314">"Baterija nije korišćena od poslednjeg potpunog punjenja"</string>
@@ -3851,7 +3857,7 @@
     <string name="ignore_optimizations_off_desc" msgid="5598702251817814289">"Preporučeno za duže trajanje baterije"</string>
     <string name="ignore_optimizations_title" msgid="7924345545276166305">"Želite li da dozvolite aplikaciji <xliff:g id="APP">%s</xliff:g> da ignoriše optimizacije baterije?"</string>
     <string name="app_list_preference_none" msgid="7100409177446935028">"Ništa"</string>
-    <string name="work_profile_usage_access_warning" msgid="403208064382097510">"Isključivanje pristupa korišćenju za ovu aplikaciju ne sprečava administratora da prati potrošnju podataka za aplikacije na profilu za Work"</string>
+    <string name="work_profile_usage_access_warning" msgid="403208064382097510">"Isključivanje pristupa korišćenju za ovu aplikaciju ne sprečava administratora da prati potrošnju podataka za aplikacije na poslovnom profilu"</string>
     <string name="accessibility_lock_screen_progress" msgid="8242917828598820049">"Upotrebljeni znakovi: <xliff:g id="COUNT_0">%1$d</xliff:g> od <xliff:g id="COUNT_1">%2$d</xliff:g>"</string>
     <string name="draw_overlay" msgid="2878665072530660668">"Prikaz preko drugih aplikacija"</string>
     <string name="system_alert_window_settings" msgid="3024330223417646567">"Prikaz preko drugih aplikacija"</string>
@@ -3935,7 +3941,7 @@
     <string name="disabled_by_policy_title_suspend_packages" msgid="4254714213391802322">"Ne možete da otvorite ovu aplikaciju"</string>
     <string name="default_admin_support_msg" msgid="5789424433689798637">"Ako imate pitanja, obratite se IT administratoru"</string>
     <string name="admin_support_more_info" msgid="8737842638087863477">"Još detalja"</string>
-    <string name="admin_profile_owner_message" msgid="3199544166281052845">"Administrator može da nadgleda aplikacije i podatke povezane sa profilom za Work, uključujući podešavanja, dozvole, korporativni pristup, aktivnosti na mreži i informacije o lokaciji uređaja, kao i da upravlja njima."</string>
+    <string name="admin_profile_owner_message" msgid="3199544166281052845">"Administrator može da nadgleda aplikacije i podatke povezane sa poslovnim profilom, uključujući podešavanja, dozvole, korporativni pristup, aktivnosti na mreži i informacije o lokaciji uređaja, kao i da upravlja njima."</string>
     <string name="admin_profile_owner_user_message" msgid="2991249382056855531">"Administrator može da nadgleda aplikacije i podatke povezane sa ovim korisnikom, uključujući podešavanja, dozvole, korporativni pristup, aktivnosti na mreži i informacije o lokaciji uređaja, kao i da upravlja njima."</string>
     <string name="admin_device_owner_message" msgid="1823477572459610869">"Administrator može da prati aplikacije i podatke povezane sa ovim uređajem, uključujući podešavanja, dozvole, korporativni pristup, aktivnosti na mreži i informacije o lokaciji uređaja, kao i da upravlja njima."</string>
     <string name="condition_turn_off" msgid="4395150881365143558">"Isključi"</string>
@@ -3954,7 +3960,7 @@
     <string name="condition_cellular_summary" msgid="3607459310548343777">"Internet je dostupan samo preko Wi‑Fi mreže"</string>
     <string name="condition_bg_data_title" msgid="184684435298857712">"Ušteda podataka"</string>
     <string name="condition_bg_data_summary" msgid="5194942860807136682">"Funkcije su ograničene"</string>
-    <string name="condition_work_title" msgid="9046811302347490371">"Profil za Work je isključen"</string>
+    <string name="condition_work_title" msgid="9046811302347490371">"Poslovni profil je isključen"</string>
     <string name="condition_work_summary" msgid="5586134491975748565">"Za aplikacije i obaveštenja"</string>
     <string name="condition_device_muted_action_turn_on_sound" msgid="5849285946804815263">"Uključi zvuk"</string>
     <string name="condition_device_muted_title" msgid="3930542786434609976">"Zvuk zvona je isključen"</string>
@@ -4013,7 +4019,7 @@
     </plurals>
     <string name="operator_warning" msgid="4676042739221117031">"Obračun podataka kod mobilnog operatera se možda razlikuje od obračuna uređaja."</string>
     <string name="data_used_template" msgid="761605393453849477">"Potrošili ste <xliff:g id="ID_1">%1$s</xliff:g>"</string>
-    <string name="set_data_warning" msgid="8115980184415563941">"Podešavanje upozorenja o podacima"</string>
+    <string name="set_data_warning" msgid="8115980184415563941">"Podesi upozorenje o podacima"</string>
     <string name="data_warning" msgid="2699207195535036240">"Upozorenje za potrošnju podataka"</string>
     <string name="data_warning_footnote" msgid="965724845580257305">"Upozorenje za potrošnju podataka i ograničenje potrošnje podataka aktivira merenje uređaja. To može da se razlikuje od merenja mobilnog operatera."</string>
     <string name="set_data_limit" msgid="5043770023229990674">"Podesi ograničenje za podatke"</string>
@@ -4263,11 +4269,11 @@
     <string name="enterprise_privacy_input_method_name" msgid="439610095825218563">"Podešeno je na <xliff:g id="APP_LABEL">%s</xliff:g>"</string>
     <string name="enterprise_privacy_always_on_vpn_device" msgid="2022700916516458213">"Stalno uključen VPN je uključen"</string>
     <string name="enterprise_privacy_always_on_vpn_personal" msgid="5644065780843002044">"Stalno uključen VPN je uključen na ličnom profilu"</string>
-    <string name="enterprise_privacy_always_on_vpn_work" msgid="6443089897985373564">"Stalno uključen VPN je uključen na profilu za Work"</string>
+    <string name="enterprise_privacy_always_on_vpn_work" msgid="6443089897985373564">"Stalno uključen VPN je uključen na poslovnom profilu"</string>
     <string name="enterprise_privacy_global_http_proxy" msgid="3862135895716080830">"Globalni HTTP proksi je podešen"</string>
     <string name="enterprise_privacy_ca_certs_device" msgid="7715658848470643878">"Pouzdani akreditivi"</string>
     <string name="enterprise_privacy_ca_certs_personal" msgid="1356447417193483802">"Pouzdani akreditivi na ličnom profilu"</string>
-    <string name="enterprise_privacy_ca_certs_work" msgid="836419648894546893">"Pouzdani akreditivi na profilu za Work"</string>
+    <string name="enterprise_privacy_ca_certs_work" msgid="836419648894546893">"Pouzdani akreditivi na poslovnom profilu"</string>
     <plurals name="enterprise_privacy_number_ca_certs" formatted="false" msgid="7953528945502561752">
       <item quantity="one">Najmanje <xliff:g id="COUNT_1">%d</xliff:g> CA sertifikat</item>
       <item quantity="few">Najmanje <xliff:g id="COUNT_1">%d</xliff:g> CA sertifikata</item>
@@ -4276,7 +4282,7 @@
     <string name="enterprise_privacy_lock_device" msgid="1533125067038409945">"Administrator može da zaključava uređaj i resetuje lozinku"</string>
     <string name="enterprise_privacy_wipe_device" msgid="7555287990273929922">"Administrator može da briše sve podatke sa uređaja"</string>
     <string name="enterprise_privacy_failed_password_wipe_device" msgid="4101502079202483156">"Neuspeli pokušaji unosa lozinke pre brisanja svih podataka sa uređaja"</string>
-    <string name="enterprise_privacy_failed_password_wipe_work" msgid="2881646286634693392">"Neuspeli pokušaji unosa lozinke pre brisanja podataka sa profila za Work"</string>
+    <string name="enterprise_privacy_failed_password_wipe_work" msgid="2881646286634693392">"Neuspeli pokušaji unosa lozinke pre brisanja podataka sa poslovnog profila"</string>
     <plurals name="enterprise_privacy_number_failed_password_wipe" formatted="false" msgid="562550414712223382">
       <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> pokušaj</item>
       <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> pokušaja</item>
@@ -4550,7 +4556,7 @@
     <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"Želite li da uklonite ovaj predlog?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"Predlog je uklonjen"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"Opozovi"</string>
-    <string name="low_storage_summary" msgid="4562224870189133400">"Preostalo je malo slobodnog memorijskog prostora. <xliff:g id="PERCENTAGE">%1$s</xliff:g> je iskorišćeno – <xliff:g id="FREE_SPACE">%2$s</xliff:g> je slobodno"</string>
+    <string name="low_storage_summary" msgid="4562224870189133400">"Nema mnogo prostora. <xliff:g id="PERCENTAGE">%1$s</xliff:g> je iskorišćeno – <xliff:g id="FREE_SPACE">%2$s</xliff:g> je slobodno"</string>
     <string name="contextual_card_feedback_send" msgid="8698649023854350623">"Pošaljite povratne informacije"</string>
     <string name="contextual_card_feedback_confirm_message" msgid="3987973028353264878">"Želite li da nam pošaljete povratne informacije za ovaj predlog?"</string>
     <string name="copyable_slice_toast" msgid="1357518174923789947">"Kopirano je u privremenu memoriju: <xliff:g id="COPY_CONTENT">%1$s</xliff:g>"</string>
diff --git a/tests/CarDeveloperOptions/res/values-be/arrays.xml b/tests/CarDeveloperOptions/res/values-be/arrays.xml
index c8aaf44..d08aa63 100644
--- a/tests/CarDeveloperOptions/res/values-be/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-be/arrays.xml
@@ -29,7 +29,15 @@
     <item msgid="5194868215515664953">"Ціхі акіян"</item>
     <item msgid="7044520255415007865">"Усе"</item>
   </string-array>
-    <!-- no translation found for screen_timeout_entries:0 (8596143519087753804) -->
+  <string-array name="screen_timeout_entries">
+    <item msgid="8596143519087753804">"15 секунд"</item>
+    <item msgid="772029947136115322">"30 секунд"</item>
+    <item msgid="8743663928349474087">"1 хвіліна"</item>
+    <item msgid="1506508631223164814">"2 хвіліны"</item>
+    <item msgid="8664703938127907662">"5 хвілін"</item>
+    <item msgid="5827960506924849753">"10 хвілін"</item>
+    <item msgid="6677424950124253938">"30 хвілін"</item>
+  </string-array>
   <string-array name="dream_timeout_entries">
     <item msgid="6487043225269853023">"Ніколі"</item>
     <item msgid="2517785806387977252">"15 секунд"</item>
@@ -99,7 +107,12 @@
     <item msgid="4646663015449312554">"Даступна"</item>
     <item msgid="3230556734162006146">"Выхад за дазволеныя межы"</item>
   </string-array>
-    <!-- no translation found for bluetooth_visibility_timeout_entries:1 (2759776603549270587) -->
+  <string-array name="bluetooth_visibility_timeout_entries">
+    <item msgid="8247986727324120082">"2 хвіліны"</item>
+    <item msgid="2759776603549270587">"5 хвілін"</item>
+    <item msgid="167772676068860015">"1 гадзіна"</item>
+    <item msgid="5985477119043628504">"Ніколі не ўключаць тайм-аўт"</item>
+  </string-array>
   <string-array name="bluetooth_max_connected_audio_devices">
     <item msgid="3800257971619063588">"Выкарыстоўваць стандартныя налады сістэмы: <xliff:g id="DEFAULT_BLUETOOTH_MAX_CONNECTED_AUDIO_DEVICES">%1$d</xliff:g>"</item>
     <item msgid="8572230405241423895">"1"</item>
@@ -206,15 +219,156 @@
     <item msgid="8563996233342430477">"Медыя"</item>
     <item msgid="5323851085993963783">"Прылада"</item>
   </string-array>
-    <!-- no translation found for app_ops_summaries:46 (4933375960222609935) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
-    <!-- no translation found for app_ops_labels:48 (8291198322681891160) -->
+  <string-array name="app_ops_summaries">
+    <item msgid="2585253854462134715">"прыблiзнае месцазнаходжанне"</item>
+    <item msgid="1830619568689922920">"дакладнае месцазнаходжанне"</item>
+    <item msgid="3317274469481923141">"GPS"</item>
+    <item msgid="8931785990160383356">"вібрацыя"</item>
+    <item msgid="8632513128515114092">"чытанне кантактаў"</item>
+    <item msgid="3741042113569620272">"змяніць кантакты"</item>
+    <item msgid="4204420969709009931">"чытанне гiсторыi выклікаў"</item>
+    <item msgid="2260380357119423209">"змены ў гiсторыi выклікаў"</item>
+    <item msgid="6550710385014530934">"чытанне календара"</item>
+    <item msgid="3575906174264853951">"змяніць каляндар"</item>
+    <item msgid="4319843242568057174">"сканаванне Wi-Fi"</item>
+    <item msgid="2981791890467303819">"апавяшчэнне"</item>
+    <item msgid="6617825156152476692">"сканаванне па сотавым"</item>
+    <item msgid="8865260890611559753">"патэлефанаваць па нумары"</item>
+    <item msgid="3254999273961542982">"чытаць SMS"</item>
+    <item msgid="7711446453028825171">"напісаць SMS"</item>
+    <item msgid="6123238544099198034">"атрымліваць SMS"</item>
+    <item msgid="838342167431596036">"атрымліваць экстранныя SMS"</item>
+    <item msgid="8554432731560956686">"атрымліваць MMS"</item>
+    <item msgid="7464863464299515059">"атрымаць WAP Push"</item>
+    <item msgid="310463075729606765">"Адправiць SMS"</item>
+    <item msgid="7338021933527689514">"чытанне ICC SMS"</item>
+    <item msgid="6130369335466613036">"напiсаць ICC SMS"</item>
+    <item msgid="6536865581421670942">"змяніць налады"</item>
+    <item msgid="4547203129183558973">"намалюйце ўверсе"</item>
+    <item msgid="9080347512916542840">"доступ да паведамленняў"</item>
+    <item msgid="5332718516635907742">"камера"</item>
+    <item msgid="6098422447246167852">"запісваць аўдыё"</item>
+    <item msgid="9182794235292595296">"прайграць аўдыё"</item>
+    <item msgid="8760743229597702019">"счытаць буфер абмену"</item>
+    <item msgid="2266923698240538544">"змяніць буфер абмену"</item>
+    <item msgid="1801619438618539275">"мультымедыйныя кнопкі"</item>
+    <item msgid="31588119965784465">"аўдыёфокус"</item>
+    <item msgid="7565226799008076833">"асноўны рэгулятар гучнасці"</item>
+    <item msgid="5420704980305018295">"гучнасць голаса"</item>
+    <item msgid="5797363115508970204">"гучнасць званка"</item>
+    <item msgid="8233154098550715999">"гучнасць прайгравальніка"</item>
+    <item msgid="5196715605078153950">"гучнасць будзільніка"</item>
+    <item msgid="394030698764284577">"гучнасць апавяшчэнняў"</item>
+    <item msgid="8952898972491680178">"гучнасць Bluetooth"</item>
+    <item msgid="8506227454543690851">"не ўваходзіць у рэжым сна"</item>
+    <item msgid="1108160036049727420">"сачыць за вызначэннем месцазнаходжання"</item>
+    <item msgid="1496205959751719491">"сачыць за энергазатратным вызначэннем месцазнаходжання"</item>
+    <item msgid="3776296279910987380">"атрымліваць статыстыку выкарыстання"</item>
+    <item msgid="8827100324471975602">"адключаць/уключаць мікрафон"</item>
+    <item msgid="6880736730520126864">"паказваць усплывальнае паведамленне"</item>
+    <item msgid="4933375960222609935">"праецыраваць мультымедыя"</item>
+    <item msgid="8357907018938895462">"актываваць VPN"</item>
+    <item msgid="8143812849911310973">"запісваць шпалеры"</item>
+    <item msgid="6266277260961066535">"дапаможная структура"</item>
+    <item msgid="7715498149883482300">"дапаможны здымак экрана"</item>
+    <item msgid="4046679376726313293">"чытаць стан тэлефона"</item>
+    <item msgid="6329507266039719587">"дадаваць галасавое паведамленне"</item>
+    <item msgid="7692440726415391408">"выкарыстоўваць пратакол SIP"</item>
+    <item msgid="8572453398128326267">"апрацоўваць выходны выклік"</item>
+    <item msgid="7775674394089376306">"адбітак пальца"</item>
+    <item msgid="3182815133441738779">"датчыкі цела"</item>
+    <item msgid="2793100005496829513">"чытаць мабільныя трансляцыі"</item>
+    <item msgid="2633626056029384366">"імітаваць месцазнаходжанне"</item>
+    <item msgid="8356842191824684631">"чытаць сховішча"</item>
+    <item msgid="5671906070163291500">"пісаць на сховішча"</item>
+    <item msgid="2791955098549340418">"уключаць экран"</item>
+    <item msgid="5599435119609178367">"атрымліваць уліковыя запісы"</item>
+    <item msgid="1165623660533024666">"выконваць у фонавым рэжыме"</item>
+    <item msgid="6423861043647911030">"гучнасць для спецыяльных магчымасцей"</item>
+  </string-array>
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Месцазнаходжанне"</item>
+    <item msgid="6656077694190491067">"Месцазнаходжанне"</item>
+    <item msgid="8790228218278477369">"Месцазнаходжанне"</item>
+    <item msgid="7836406246005211990">"Вібрацыя"</item>
+    <item msgid="3951439024549922598">"Чытанне кантактаў"</item>
+    <item msgid="8802152411647068">"Змяніць кантакты"</item>
+    <item msgid="229544934599698735">"Чытанне гiсторыi выклікаў"</item>
+    <item msgid="7396102294405899613">"Змяненне запісаў у гiсторыi выклікаў"</item>
+    <item msgid="3597797992398484655">"Чытанне календара"</item>
+    <item msgid="2705975774250907343">"Змена календара"</item>
+    <item msgid="4668747371441932697">"Месцазнаходжанне"</item>
+    <item msgid="1487578921720243646">"Апублiкаваць апавяшчэнне"</item>
+    <item msgid="4636080349724146638">"Месцазнаходжанне"</item>
+    <item msgid="673510900286463926">"Патэлефанаваць па нумары"</item>
+    <item msgid="542083422784609790">"Чытаць SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Пісаць SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Прыём SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Прыём SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Прыём SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Прыём SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Адправiць SMS/MMS"</item>
+    <item msgid="4726682243833913568">"Чытаць SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Пісаць SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Змена налад"</item>
+    <item msgid="8705854389991425629">"Намалюйце ўверсе"</item>
+    <item msgid="5861356020344153651">"Доступ да паведамленняў"</item>
+    <item msgid="78432174621628659">"Камера"</item>
+    <item msgid="3986116419882154794">"Запісаць аўдыё"</item>
+    <item msgid="4516840825756409490">"Прайграванне аўдыё"</item>
+    <item msgid="6811712502798183957">"Счытаць буфер абмену"</item>
+    <item msgid="2780369012602289114">"Змяніць буфер абмену"</item>
+    <item msgid="2331359440170850868">"Мультымедыйныя кнопкі"</item>
+    <item msgid="6133599737122751231">"Аўдыёфокус"</item>
+    <item msgid="6844485713404805301">"Асноўны рэгулятар гучнасці"</item>
+    <item msgid="1600379420669104929">"Гучнасць голаса"</item>
+    <item msgid="6296768210470214866">"Гучнасць званка"</item>
+    <item msgid="510690696071629241">"Гучнасць медыя"</item>
+    <item msgid="406861638631430109">"Гучнасць будзільніка"</item>
+    <item msgid="4715864795872233884">"Гучнасць апавяшчэнняў"</item>
+    <item msgid="2311478519251301183">"Гучнасць Bluetooth"</item>
+    <item msgid="5133991377896747027">"Не ўвах. у рэжым сна"</item>
+    <item msgid="2464189519136248621">"Месцазнаходжанне"</item>
+    <item msgid="2062677934050803037">"Месцазнаходжанне"</item>
+    <item msgid="1735171933192715957">"Атрымаць статыстыку выкарыстання"</item>
+    <item msgid="1014093788778383554">"Адключаць/уключаць мікрафон"</item>
+    <item msgid="4199297950608622850">"Паказваць усплывальнае паведамленне"</item>
+    <item msgid="2527962435313398821">"Праецыраваць мультымедыя"</item>
+    <item msgid="5117506254221861929">"Актываваць VPN"</item>
+    <item msgid="8291198322681891160">"Запісаць шпалеры"</item>
+    <item msgid="7106921284621230961">"Дапаможная структура"</item>
+    <item msgid="4496533640894624799">"Дапаможны здымак экрана"</item>
+    <item msgid="2598847264853993611">"Чытаць стан тэлефона"</item>
+    <item msgid="9215610846802973353">"Дадаваць галасавое паведамленне"</item>
+    <item msgid="9186411956086478261">"Выкарыстоўваць пратакол SIP"</item>
+    <item msgid="6884763100104539558">"Апрацоўваць выходны выклік"</item>
+    <item msgid="125513972170580692">"Адбітак пальца"</item>
+    <item msgid="2556071024281275619">"Датчыкі цела"</item>
+    <item msgid="617168514928339387">"Чытаць мабільныя трансляцыі"</item>
+    <item msgid="7134693570516523585">"Імітаваць месцазнаходжанне"</item>
+    <item msgid="7224489175375229399">"Чытаць сховішча"</item>
+    <item msgid="8472735063903258202">"Пісаць на сховішча"</item>
+    <item msgid="4069276819909595110">"Уключаць экран"</item>
+    <item msgid="1228338896751121025">"Атрымліваць уліковыя запісы"</item>
+    <item msgid="3181581793459233672">"Выконваць у фонавым рэжыме"</item>
+    <item msgid="2340936043025374076">"Гучнасць для спецыяльных магчымасцей"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Кароткая"</item>
     <item msgid="4816511817309094890">"Сярэдняя"</item>
     <item msgid="8305084671259331134">"Доўгая"</item>
   </string-array>
-    <!-- no translation found for captioning_typeface_selector_titles:4 (1487203730637617924) -->
+  <string-array name="captioning_typeface_selector_titles">
+    <item msgid="6928465258504250174">"Стандартны"</item>
+    <item msgid="4147246073737933622">"Без засечак"</item>
+    <item msgid="3117680749167407907">"Без засечак сцягнуты"</item>
+    <item msgid="6529379119163117545">"Без засечак монашырынны"</item>
+    <item msgid="1487203730637617924">"З засечкамі"</item>
+    <item msgid="4937790671987480464">"З засечкамі монашырынны"</item>
+    <item msgid="4448481989108928248">"Нефармальны"</item>
+    <item msgid="4627069151979553527">"Курсіўны"</item>
+    <item msgid="6896773537705206194">"Капітэль"</item>
+  </string-array>
   <string-array name="captioning_font_size_selector_titles">
     <item msgid="1680223634161592855">"Вельмі дробны"</item>
     <item msgid="5091603983404027034">"Дробны"</item>
@@ -222,14 +376,28 @@
     <item msgid="2784236342175159295">"Вялікі"</item>
     <item msgid="218913203203160606">"Вельмі вялікі"</item>
   </string-array>
-    <!-- no translation found for captioning_edge_type_selector_titles:4 (8019330250538856521) -->
+  <string-array name="captioning_edge_type_selector_titles">
+    <item msgid="3865198759294188069">"Стандартны"</item>
+    <item msgid="6488643537808152001">"Няма"</item>
+    <item msgid="552332815156010137">"Контур"</item>
+    <item msgid="7187891159463789272">"Цень"</item>
+    <item msgid="8019330250538856521">"Прыўзняты"</item>
+    <item msgid="8987385315647049787">"Уціснуты"</item>
+  </string-array>
   <string-array name="captioning_opacity_selector_titles">
     <item msgid="313003243371588365">"25%"</item>
     <item msgid="4665048002584838262">"50 %"</item>
     <item msgid="1874668269931014581">"75%"</item>
     <item msgid="6462911487571123954">"100 %"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"Ужываць стандартныя налады праграмы"</item>
+    <item msgid="8611890312638868524">"Белы на чорным"</item>
+    <item msgid="5891360837786277638">"Чорны на белым"</item>
+    <item msgid="2798457065945456853">"Жоўты на чорным"</item>
+    <item msgid="5799049811524553967">"Жоўты на сінім"</item>
+    <item msgid="3673930830658169860">"Карыстальніцкія"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"PPTP VPN"</item>
     <item msgid="1349760781118368659">"L2TP/IPSec VPN з загадзя размеркаванымі ключамі"</item>
@@ -238,7 +406,10 @@
     <item msgid="3319427315593649917">"IPSec VPN з сертыфікатамі і аўтэнтыфікацыяй Xauth"</item>
     <item msgid="8258927774145391041">"IPSec VPN з сертыфікатамі і гібрыднай аўтэнтыфікацыяй"</item>
   </string-array>
-    <!-- no translation found for vpn_proxy_settings:0 (2958623927055120839) -->
+  <string-array name="vpn_proxy_settings">
+    <item msgid="2958623927055120839">"Няма"</item>
+    <item msgid="1157046369795346308">"Кіраўніцтва"</item>
+  </string-array>
   <string-array name="vpn_states">
     <item msgid="5408915841694583740">"Адключана"</item>
     <item msgid="8754480102834556765">"Ініцыялізацыя..."</item>
@@ -252,9 +423,19 @@
     <item msgid="7718817231348607934">"Нiколi не дазваляць"</item>
     <item msgid="8184570120217958741">"Заўсёды дазваляць"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Звычайны"</item>
+    <item msgid="5101233285497327432">"Умераны"</item>
+    <item msgid="1555861583162930714">"Нізкая"</item>
+    <item msgid="1719683776264798117">"Крытычны"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Звычайны"</item>
+    <item msgid="6107138933849816768">"Умераны"</item>
+    <item msgid="182695359839047859">"Нізкая"</item>
+    <item msgid="8577246509202964244">"Крытычны"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Пастаянны"</item>
     <item msgid="167418068739176448">"Папулярная дзейнасць"</item>
@@ -296,7 +477,7 @@
     <item msgid="1008268820118852416">"Безлімітная"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
-    <item msgid="6545683814310036454">"Выкарыстоўваць выпадковы MAC-адрас (стандартна)"</item>
+    <item msgid="6545683814310036454">"Выпадковы MAC-адрас (стандартна)"</item>
     <item msgid="214234417308375326">"Выкарыстоўваць прыладу MAC"</item>
   </string-array>
   <string-array name="wifi_hidden_entries">
diff --git a/tests/CarDeveloperOptions/res/values-be/config.xml b/tests/CarDeveloperOptions/res/values-be/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-be/config.xml
+++ b/tests/CarDeveloperOptions/res/values-be/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-be/strings.xml b/tests/CarDeveloperOptions/res/values-be/strings.xml
index 74871d2..2ae5de9 100644
--- a/tests/CarDeveloperOptions/res/values-be/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-be/strings.xml
@@ -85,8 +85,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Павелічэнне або памяншэнне тэксту на экране."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Паменшыць"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Павялічыць"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Прыклад тэксту"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Чараўнік краіны Оз"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Раздзел 11. Цудоўны Смарагдавы Горад у краіне Оз"</string>
@@ -210,7 +209,7 @@
     <string name="proxy_error_empty_port" msgid="8034561724923076215">"Трэба запоўніць поле порта."</string>
     <string name="proxy_error_empty_host_set_port" msgid="8471455809508588255">"Поле парта павінна быць пустым, калі поле хоста пустое."</string>
     <string name="proxy_error_invalid_port" msgid="4046559920586100637">"Вы ўвялі несапраўднае імя порта."</string>
-    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"Проксі HTTP выкарыстоўваецца браўзэрам, але ён не можа выкарыстоўвацца іншымі прыкладаннямi"</string>
+    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"Проксі HTTP выкарыстоўваецца браўзерам, але не можа выкарыстоўвацца іншымі праграмамі."</string>
     <string name="proxy_url_title" msgid="882042361706435904">"URL аўтаканфіг. проксі: "</string>
     <string name="radio_info_dl_kbps" msgid="2903778264453410272">"Паласа прапускання спампоўкі (кбіт/с):"</string>
     <string name="radio_info_ul_kbps" msgid="3802245899811732716">"Паласа прапускання запампоўкі (кбіт/с):"</string>
@@ -353,16 +352,16 @@
     <string name="time_picker_title" msgid="1596400307061268660">"Час"</string>
     <string name="lock_after_timeout" msgid="7755520959071097304">"Аўтаматычная блакіроўка"</string>
     <string name="lock_after_timeout_summary" msgid="3160517585613694740">"<xliff:g id="TIMEOUT_STRING">%1$s</xliff:g> пасля сну"</string>
-    <string name="lock_immediately_summary_with_exception" msgid="6442552135409347556">"Адразу ж пасля сну, за выключэннем выпадкаў, калі экран разблакіруецца функцыяй <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g>"</string>
-    <string name="lock_after_timeout_summary_with_exception" msgid="7218267834086717545">"<xliff:g id="TIMEOUT_STRING">%1$s</xliff:g> пасля сну, за выключэннем выпадкаў, калі экран разблакіруецца функцыяй <xliff:g id="TRUST_AGENT_NAME">%2$s</xliff:g>"</string>
+    <string name="lock_immediately_summary_with_exception" msgid="6442552135409347556">"Адразу пасля сну акрамя выпадкаў, калі экран застаецца разблакіраваным функцыяй <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g>"</string>
+    <string name="lock_after_timeout_summary_with_exception" msgid="7218267834086717545">"<xliff:g id="TIMEOUT_STRING">%1$s</xliff:g> пасля сну акрамя выпадкаў, калі экран застаецца разблакіраваным функцыяй <xliff:g id="TRUST_AGENT_NAME">%2$s</xliff:g>"</string>
     <string name="show_owner_info_on_lockscreen_label" msgid="4510756693837171575">"Паказаць інфармацыю аб уладальніку на экране блакавання"</string>
     <string name="owner_info_settings_title" msgid="2537966178998339896">"Тэкст на экране блакіроўкі"</string>
     <string name="security_enable_widgets_title" msgid="1701510007926738088">"Уключыць віджэты"</string>
     <string name="security_enable_widgets_disabled_summary" msgid="4408176087132339331">"Адключана адміністратарам"</string>
-    <string name="lockdown_settings_title" msgid="4534779922580115990">"Паказаць параметр блакіроўкі"</string>
+    <string name="lockdown_settings_title" msgid="4534779922580115990">"Паказваць кнопку блакіроўкі"</string>
     <string name="lockdown_settings_summary" msgid="7270756909878256174">"Дадаць у меню кнопкі сілкавання функцыю, якая выключае разумную блакіроўку, разблакіроўку адбіткам пальца і апавяшчэнні на экране блакіроўкі"</string>
-    <string name="trust_agents_extend_unlock_title" msgid="3582017561316089951">"Давераныя агенты падаўжаюць разблакіроўку"</string>
-    <string name="trust_agents_extend_unlock_summary" msgid="3543997596586078084">"Калі функцыя ўключана, давераныя агенты будуць даўжэй трымаць прыладу разблакіраванай, аднак не змогуць разблакіраваць ужо заблакіраваную прыладу."</string>
+    <string name="trust_agents_extend_unlock_title" msgid="3582017561316089951">"Даверчыя агенты падаўжаюць разблакіроўку"</string>
+    <string name="trust_agents_extend_unlock_summary" msgid="3543997596586078084">"Калі функцыя ўключана, даверчыя агенты будуць даўжэй трымаць прыладу разблакіраванай, аднак не змогуць разблакіраваць ужо заблакіраваную прыладу."</string>
     <string name="trust_lost_locks_screen_title" msgid="3094736590690459372">"Блакіраваць экран, калі давер страчаны"</string>
     <string name="trust_lost_locks_screen_summary" msgid="2058567484625606803">"Пры ўключанай функцыі прылада будзе заблакіравана, калі страціць давер апошні агент"</string>
     <string name="owner_info_settings_summary" msgid="4208702251226725583">"Няма"</string>
@@ -468,14 +467,14 @@
     <string name="go_back_button_label" msgid="7310586887969860472">"Назад"</string>
     <string name="skip_lock_screen_dialog_button_label" msgid="6706047245716780006">"Прапусціць"</string>
     <string name="cancel_lock_screen_dialog_button_label" msgid="2534925227627658819">"Скасаваць"</string>
-    <string name="security_settings_fingerprint_enroll_find_sensor_title" msgid="8909829699273726469">"Дакраніцеся да сэнсара"</string>
+    <string name="security_settings_fingerprint_enroll_find_sensor_title" msgid="8909829699273726469">"Дакраніцеся да сканера"</string>
     <string name="security_settings_fingerprint_enroll_find_sensor_message" msgid="581120963079780740">"Ён на задняй панэлі тэлефона. Карыстайцеся ўказальным пальцам."</string>
     <string name="security_settings_fingerprint_enroll_find_sensor_content_description" msgid="7835824123269738540">"Малюнак, які паказвае, дзе размяшчаецца датчык адбіткаў пальцаў на прыладзе"</string>
     <string name="security_settings_fingerprint_enroll_dialog_name_label" msgid="3519748398694308901">"Імя"</string>
     <string name="security_settings_fingerprint_enroll_dialog_ok" msgid="3428927518029038956">"ОК"</string>
     <string name="security_settings_fingerprint_enroll_dialog_delete" msgid="4312297515772004580">"Выдаліць"</string>
-    <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"Дакраніцеся да сэнсара"</string>
-    <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Прыкладзіце палец да сэнсара і ўтрымлівайце яго, пакуль не адчуеце вібрацыю"</string>
+    <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"Дакраніцеся да сканера"</string>
+    <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Прыкладзіце палец да сканера і ўтрымлівайце яго, пакуль не адчуеце вібрацыю"</string>
     <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"Падыміце і дакраніцеся зноў"</string>
     <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Дакраніцеся некалькі разоў, каб адбітак быў больш дакладны"</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"Адбітак пальца дададзены"</string>
@@ -646,13 +645,13 @@
     <string name="unlock_footer_none_complexity_requested" msgid="1669550050597044896">"<xliff:g id="APP_NAME">%1$s</xliff:g> рэкамендуе ўсталяваць новую блакіроўку экрана"</string>
     <string name="lock_failed_attempts_before_wipe" msgid="7565412834122130877">"Паўтарыце спробу. Спроба <xliff:g id="CURRENT_ATTEMPTS">%1$d</xliff:g> з дапушчальных <xliff:g id="TOTAL_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="lock_last_attempt_before_wipe_warning_title" msgid="7853820095898368793">"Вашы даныя будуць выдалены"</string>
-    <string name="lock_last_pattern_attempt_before_wipe_device" msgid="1021644947949306054">"Калі вы ўведзяце няправільны графічны ключ яшчэ раз, даныя з гэтай прылады будуць выдалены"</string>
+    <string name="lock_last_pattern_attempt_before_wipe_device" msgid="1021644947949306054">"Калі вы ўведзяце няправільны ўзор разблакіроўкі яшчэ раз, даныя з гэтай прылады будуць выдалены"</string>
     <string name="lock_last_pin_attempt_before_wipe_device" msgid="3823600293847594141">"Калі вы ўведзяце няправільны PIN-код яшчэ раз, даныя з гэтай прылады будуць выдалены"</string>
     <string name="lock_last_password_attempt_before_wipe_device" msgid="3548966006264835462">"Калі вы ўведзяце няправільны пароль яшчэ раз, даныя з гэтай прылады будуць выдалены"</string>
-    <string name="lock_last_pattern_attempt_before_wipe_user" msgid="5194192938934564218">"Калі вы яшчэ раз уведзяце няправільны графічны ключ, гэты карыстальнік будзе выдалены"</string>
+    <string name="lock_last_pattern_attempt_before_wipe_user" msgid="5194192938934564218">"Калі вы яшчэ раз уведзяце няправільны ўзор разблакіроўкі, гэты карыстальнік будзе выдалены"</string>
     <string name="lock_last_pin_attempt_before_wipe_user" msgid="7833852187363499906">"Калі вы яшчэ раз уведзяце няправільны PIN-код, гэты карыстальнік будзе выдалены"</string>
     <string name="lock_last_password_attempt_before_wipe_user" msgid="8979742220140001204">"Калі вы яшчэ раз уведзяце няправільны пароль, гэты карыстальнік будзе выдалены"</string>
-    <string name="lock_last_pattern_attempt_before_wipe_profile" msgid="3877613047631174576">"Калі вы яшчэ раз уведзяце няправільны графічны ключ, ваш рабочы профіль і звязаныя з ім даныя будуць выдалены"</string>
+    <string name="lock_last_pattern_attempt_before_wipe_profile" msgid="3877613047631174576">"Калі вы яшчэ раз уведзяце няправільны ўзор разблакіроўкі, ваш рабочы профіль і звязаныя з ім даныя будуць выдалены"</string>
     <string name="lock_last_pin_attempt_before_wipe_profile" msgid="8132438288175428168">"Калі вы яшчэ раз уведзяце няправільны PIN-код, ваш рабочы профіль і звязаныя з ім даныя будуць выдалены"</string>
     <string name="lock_last_password_attempt_before_wipe_profile" msgid="1535128774464384305">"Калі вы яшчэ раз уведзяце няправільны пароль, ваш рабочы профіль і звязаныя з ім даныя будуць выдалены"</string>
     <string name="lock_failed_attempts_now_wiping_device" msgid="8662360098784762828">"Занадта шмат няўдалых спроб. Даныя з гэтай прылады будуць выдалены."</string>
@@ -684,7 +683,6 @@
       <item quantity="many">PIN-код павінен змяшчаць менш за <xliff:g id="NUMBER_1">%d</xliff:g> лічбаў</item>
       <item quantity="other">PIN-код павінен змяшчаць менш за <xliff:g id="NUMBER_1">%d</xliff:g> лічбы</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Павінен змяшчаць толькі лічбы 0-9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Адміністратар прылады не дазваляе выкарыстоўваць апошні PIN-код"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"IT адміністратар блакіруе папулярныя PIN-коды. Паспрабуйце іншы PIN-код."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Не можа змяшчаць недапушчальны сімвал"</string>
@@ -727,6 +725,12 @@
       <item quantity="many">Павінен змяшчаць не менш за <xliff:g id="COUNT">%d</xliff:g> сімвалаў, якія не з\'яўляюцца літарамі</item>
       <item quantity="other">Павінен змяшчаць не менш за <xliff:g id="COUNT">%d</xliff:g> сімвала, якія не з\'яўляюцца літарамі</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">Павінен змяшчаць не менш за <xliff:g id="COUNT">%d</xliff:g> сімвал, які не з\'яўляецца лічбай</item>
+      <item quantity="few">Павінен змяшчаць не менш за <xliff:g id="COUNT">%d</xliff:g> сімвалы, якія не з\'яўляюцца лічбамі</item>
+      <item quantity="many">Павінен змяшчаць не менш за <xliff:g id="COUNT">%d</xliff:g> сімвалаў, якія не з\'яўляюцца лічбамі</item>
+      <item quantity="other">Павінен змяшчаць не менш за <xliff:g id="COUNT">%d</xliff:g> сімвала, якія не з\'яўляюцца лічбамі</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Адміністратар прылады не дазваляе выкарыстоўваць апошні пароль"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"IT адміністратар блакіруе папулярныя паролі. Паспрабуйце іншы пароль."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Забаронена ўводзіць узрастаючую, убываючую або паўторную паслядоўнасць лічбаў"</string>
@@ -745,14 +749,14 @@
       <item quantity="many"><xliff:g id="COUNT_1">%d</xliff:g> актыўных праграм</item>
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> актыўнай праграмы</item>
     </plurals>
-    <string name="manage_trust_agents" msgid="8129970926213142261">"Давераныя агенты"</string>
+    <string name="manage_trust_agents" msgid="8129970926213142261">"Даверчыя агенты"</string>
     <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"Перад выкарыстаннем задайце блакіроўку экрана"</string>
     <string name="manage_trust_agents_summary" msgid="2023116850759962248">"Няма"</string>
     <plurals name="manage_trust_agents_summary_on" formatted="false" msgid="5550538038916606097">
-      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> актыўны давераны агент</item>
-      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> актыўныя давераныя агенты</item>
-      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> актыўных давераных агентаў</item>
-      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> актыўнага даверанага агента</item>
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> актыўны даверчы агент</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> актыўныя даверчыя агенты</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> актыўных даверчых агентаў</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> актыўнага даверчага агента</item>
     </plurals>
     <string name="bluetooth_quick_toggle_title" msgid="7410319268406112792">"Bluetooth"</string>
     <string name="bluetooth_quick_toggle_summary" msgid="3951769568065428093">"Уключыць Bluetooth"</string>
@@ -876,10 +880,10 @@
     <string name="wifi_error" msgid="5605801874484465557">"Памылка"</string>
     <string name="wifi_sap_no_channel_error" msgid="6881796988574851628">"Дыяпазон 5 ГГц недаступны ў гэтай краіне"</string>
     <string name="wifi_in_airplane_mode" msgid="4729571191578262246">"У рэжыме палёту"</string>
-    <string name="wifi_notify_open_networks" msgid="4782239203624619655">"Апавяшчэнне пра адкрытыя сеткі"</string>
+    <string name="wifi_notify_open_networks" msgid="4782239203624619655">"Апавяшчаць пра адкрытыя сеткі"</string>
     <string name="wifi_notify_open_networks_summary" msgid="1383681260705466715">"Апавяшчаць, калі даступная высакаякасная сетка агульнага доступу"</string>
     <string name="wifi_wakeup" msgid="4963732992164721548">"Уключаць Wi‑Fi аўтаматычна"</string>
-    <string name="wifi_wakeup_summary" msgid="1152699417411690">"Wi‑Fi будзе ўключацца аўтаматычна побач з захаванымі высакаякаснымі сеткамі, напрыклад вашай дамашняй сеткай"</string>
+    <string name="wifi_wakeup_summary" msgid="1152699417411690">"Wi‑Fi будзе ўключацца аўтаматычна побач з захаванымі высакаякаснымі сеткамі, напрыклад у вашай дамашняй сетцы"</string>
     <string name="wifi_wakeup_summary_no_location" msgid="3007457288587966962">"Недаступна, таму што выключана вызначэнне месцазнаходжання. Уключыце "<annotation id="link">"Вызначаць месцазнаходжанне"</annotation>"."</string>
     <string name="wifi_wakeup_summary_scanning_disabled" msgid="6820040651529910914">"Недаступна, бо выключаны пошук сетак Wi-Fi"</string>
     <string name="wifi_wakeup_summary_scoring_disabled" msgid="7067018832237903151">"Для выкарыстання функцыі выберыце пастаўшчыка паслугі ацэнкі сеткі"</string>
@@ -935,7 +939,7 @@
     <string name="wifi_ssid_hint" msgid="5010024648106585165">"Увядзіце SSID"</string>
     <string name="wifi_security" msgid="9136702039496152831">"Бяспека"</string>
     <string name="wifi_hidden_network" msgid="6647772204699776833">"Схаваная сетка"</string>
-    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Калі маршрутызатар не перадае ідэнтыфікатар сеткі, але дапускаецца падключэнне да яе ў будучыні, сетку можна \"схаваць\".\n\nГэта пагражае бяспецы, таму што тэлефон будзе рэгулярна перадаваць сігнал для пошуку сеткі.\n\n\"Схаваная\" сетка не зменіць налады маршрутызатара."</string>
+    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Калі маршрутызатар не перадае ідэнтыфікатар сеткі, але дапускаецца падключэнне да яе ў будучыні, сетку можна схаваць.\n\nГэта пагражае бяспецы, таму што тэлефон будзе рэгулярна перадаваць сігнал для пошуку сеткі.\n\nСхаваная сетка не зменіць налады маршрутызатара."</string>
     <string name="wifi_signal" msgid="696548364467704808">"Магутнасць сігналу"</string>
     <string name="wifi_status" msgid="3439931558930689940">"Стан"</string>
     <string name="tx_wifi_speed" msgid="2571810085003261073">"Хуткасць перадачы даных"</string>
@@ -1134,7 +1138,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Мабільны інтэрнэт"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Калі Wi‑Fi недаступны, выкарыстоўвайце мабільную сетку"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Калі мабільная сетка недаступная, выкарыстоўвайце Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Выклікайце праз Wi‑Fi. Калі сігналу Wi‑Fi няма, выклік завяршаецца."</string>
@@ -1158,8 +1165,7 @@
     <string name="incoming_call_volume_title" msgid="4736570528754310450">"Рынгтон"</string>
     <string name="notification_volume_title" msgid="6022562909288085275">"Апавяшчэнне"</string>
     <string name="checkbox_notification_same_as_incoming_call" msgid="7312942422655861175">"Выкарыстоўваць гучнасць уваходных выклікаў для паведамленняў"</string>
-    <!-- no translation found for home_work_profile_not_supported (6137073723297076818) -->
-    <skip />
+    <string name="home_work_profile_not_supported" msgid="6137073723297076818">"Працоўныя профілі не падтрымліваюцца"</string>
     <string name="notification_sound_dialog_title" msgid="6653341809710423276">"Гук паведамлення па змаўчаннi"</string>
     <string name="media_volume_title" msgid="1030438549497800914">"Мультымедыя"</string>
     <string name="media_volume_summary" msgid="3142433516297061652">"Вызначыць гучнасць для музыкі і відэа"</string>
@@ -1240,8 +1246,8 @@
     <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"Выключана"</string>
     <string name="adaptive_sleep_description" msgid="812673735459170009">"Не дазваляе экрану выключацца, калі на яго глядзяць"</string>
     <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Адаптыўны рэжым з дапамогай пярэдняй камеры вызначае, калі хто-небудзь глядзіць на экран. Функцыя працуе толькі на прыладзе: відарысы не захоўваюцца і не адпраўляюцца ў Google."</string>
-    <string name="night_display_title" msgid="1305002424893349814">"Начны рэжым"</string>
-    <string name="night_display_text" msgid="5330502493684652527">"У начным рэжыме экран будзе мець бурштынавае адценне. Так вам будзе зручней глядзець на экран пры цьмяным асвятленні, а таксама лягчэй заснуць."</string>
+    <string name="night_display_title" msgid="1305002424893349814">"Начная падсветка"</string>
+    <string name="night_display_text" msgid="5330502493684652527">"У рэжыме Начной падсветкі экран будзе мець бурштынавае адценне. Так вам будзе зручней глядзець на экран пры цьмяным асвятленні, а таксама лягчэй заснуць."</string>
     <string name="night_display_auto_mode_title" msgid="8493573087102481588">"Расклад"</string>
     <string name="night_display_auto_mode_never" msgid="2897444637217807088">"Ніколі"</string>
     <string name="night_display_auto_mode_custom" msgid="1400891076453963151">"Уключаецца ў вызначаны час"</string>
@@ -1264,7 +1270,7 @@
     <string name="night_display_activation_off_twilight" msgid="6846727701281556110">"Выключыць да вечара"</string>
     <string name="night_display_activation_on_custom" msgid="4761140206778957611">"Уключыць да <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="night_display_activation_off_custom" msgid="4207238846687792731">"Выключыць да <xliff:g id="ID_1">%1$s</xliff:g>"</string>
-    <string name="night_display_not_currently_on" msgid="1436588493764429281">"Начны рэжым не ўключаны"</string>
+    <string name="night_display_not_currently_on" msgid="1436588493764429281">"Начная падсветка не ўключана"</string>
     <string name="screen_timeout" msgid="1700950247634525588">"Рэжым сну"</string>
     <string name="screen_timeout_title" msgid="150117777762864112">"Экран выключаецца"</string>
     <string name="screen_timeout_summary" msgid="8644192861778491060">"Пасля бяздзейнасці: <xliff:g id="TIMEOUT_DESCRIPTION">%1$s</xliff:g>"</string>
@@ -1560,7 +1566,7 @@
     <string name="battery_level_title" msgid="5207775387973771646">"Узровень батарэі"</string>
     <string name="apn_settings" msgid="8130776653826271664">"APN"</string>
     <string name="apn_edit" msgid="4350571070853305357">"Змянiць кропку доступу"</string>
-    <string name="apn_not_set" msgid="5344235604466825691">"Не задана"</string>
+    <string name="apn_not_set" msgid="5344235604466825691">"Не зададзена"</string>
     <string name="apn_name" msgid="8431432886706852226">"Назва"</string>
     <string name="apn_apn" msgid="190519449579357696">"APN"</string>
     <string name="apn_http_proxy" msgid="8816906767987944465">"Проксі"</string>
@@ -1599,7 +1605,7 @@
     <string name="error_adding_apn_type" msgid="671634520340569678">"Аператар не дазваляе дадаваць APN тыпу %s."</string>
     <string name="restore_default_apn" msgid="7195266404077471007">"Аднаўленне параметраў APN па змаўчанні"</string>
     <string name="menu_restore" msgid="3799288817317293115">"Скінуць налады"</string>
-    <string name="restore_default_apn_completed" msgid="5671734152740058937">"Скід налад кропкі доступу па змаўчанні завершаны."</string>
+    <string name="restore_default_apn_completed" msgid="5671734152740058937">"Стандартныя налады адноўлены."</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"Параметры скіду"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"Налады сеткі, праграмы або прылады могуць быць скінуты"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"Скінуць налады Wi-Fi, мабільнай перадачы даных і Bluetooth"</string>
@@ -1690,7 +1696,7 @@
     </plurals>
     <string name="location_category_recent_location_access" msgid="286059523360285026">"Доступ да апошняга вызначэння месцазнаходжання"</string>
     <string name="location_recent_location_access_view_details" msgid="2051602261436245905">"Паказаць падрабязныя звесткі"</string>
-    <string name="location_no_recent_apps" msgid="77502059586413278">"У апошні час запытаў ад дадаткаў на вызначэнне месцазнаходжання не паступала"</string>
+    <string name="location_no_recent_apps" msgid="77502059586413278">"У апошні час праграмы не запытвалі інфармацыю пра месцазнаходжанне"</string>
     <string name="location_no_recent_accesses" msgid="6289916310397279890">"У апошні час ніводная праграма не атрымлівала доступу да звестак пра месцазнаходжанне"</string>
     <string name="location_high_battery_use" msgid="7177199869979522663">"Выс. узровень выкарыст. акум."</string>
     <string name="location_low_battery_use" msgid="5030448574501435888">"Нізкі ўзровень выкарыст. акум."</string>
@@ -1723,13 +1729,13 @@
     <string name="contributors_title" msgid="6800028420806884340">"Удзельнікі"</string>
     <string name="manual" msgid="5431859421432581357">"Кіраўніцтва"</string>
     <string name="regulatory_labels" msgid="380968489247381025">"Ярлыкі сертыфікацыі"</string>
-    <string name="safety_and_regulatory_info" msgid="7113766428000920132">"Кіраўніцтва па эксплуатацыі і бяспецы"</string>
+    <string name="safety_and_regulatory_info" msgid="7113766428000920132">"Інфармацыя па эксплуатацыі і бяспецы"</string>
     <string name="copyright_title" msgid="3847703367689932190">"Аўтарскія правы"</string>
     <string name="license_title" msgid="7582145947873528540">"Ліцэнзія"</string>
     <string name="terms_title" msgid="1804549588198223771">"Правілы і ўмовы"</string>
     <string name="webview_license_title" msgid="8244960025549725051">"Сістэмная ліцэнзія WebView"</string>
     <string name="wallpaper_attributions" msgid="2941987966332943253">"Шпалеры"</string>
-    <string name="wallpaper_attributions_values" msgid="4461979853894606323">"Пастаўшчыкі спадарожнікавых выяў:\n©2014 CNES / Astrium, DigitalGlobe, Bluesky"</string>
+    <string name="wallpaper_attributions_values" msgid="4461979853894606323">"Спадарожнікавыя фота:\n©2014 CNES / Astrium, DigitalGlobe, Bluesky"</string>
     <string name="settings_manual_activity_title" msgid="7599911755054286789">"Кіраўніцтва"</string>
     <string name="settings_manual_activity_unavailable" msgid="4872502775018655343">"Не атрымлiваецца загрузіць кіраўніцтва."</string>
     <string name="settings_license_activity_title" msgid="1099045216283677608">"Ліцэнзіі трэціх бакоў"</string>
@@ -1798,11 +1804,11 @@
     <string name="lockpattern_settings_title" msgid="5152005866870766842">"Камбінацыя разблакоўкі"</string>
     <string name="lockpattern_settings_enable_title" msgid="8508410891939268080">"Патрабаваць камбінацыю разблакавання"</string>
     <string name="lockpattern_settings_enable_summary" msgid="8027605503917737512">"Патрабаваць камбінацыю разблакоўкі, каб разблакаваць экран"</string>
-    <string name="lockpattern_settings_enable_visible_pattern_title" msgid="4935583222709647096">"Зрабіць шаблон бачным"</string>
+    <string name="lockpattern_settings_enable_visible_pattern_title" msgid="4935583222709647096">"Зрабіць узор бачным"</string>
     <string name="lockpattern_settings_enable_visible_pattern_title_profile" msgid="5338893138982642228">"Зрабіць узор разблакіроўкі профілю бачным"</string>
     <string name="lockpattern_settings_enable_tactile_feedback_title" msgid="3203621862806531947">"Вібрацыя пры дотыку"</string>
     <string name="lockpattern_settings_enable_power_button_instantly_locks" msgid="5890335732200257777">"Блакір. кнопкай сілкавання"</string>
-    <string name="lockpattern_settings_power_button_instantly_locks_summary" msgid="1279989004145567840">"За выключэннем выпадкаў, калі экран разблакіруецца функцыяй <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g>"</string>
+    <string name="lockpattern_settings_power_button_instantly_locks_summary" msgid="1279989004145567840">"Акрамя выпадкаў, калі экран застаецца разблакіраваным функцыяй <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g>"</string>
     <string name="lockpattern_settings_choose_lock_pattern" msgid="9042142745571386381">"Усталяваць камбінацыю разблакоўкі"</string>
     <string name="lockpattern_settings_change_lock_pattern" msgid="1456643060737114885">"Змяніць камбінацыю разблакоўкі"</string>
     <string name="lockpattern_settings_help_how_to_record" msgid="6037403647312543908">"Як зрабіць камбінацыю разблакоўкі"</string>
@@ -1834,7 +1840,7 @@
     <string name="advanced_settings_summary" msgid="5912237062506771716">"Уключыць дадатковыя параметры налад"</string>
     <string name="application_info_label" msgid="3886253474964599105">"Звесткі пра праграмы"</string>
     <string name="storage_label" msgid="1109537840103290384">"Сховішча"</string>
-    <string name="auto_launch_label" msgid="47089737922907379">"Стандартна адкрываць"</string>
+    <string name="auto_launch_label" msgid="47089737922907379">"Адкрываць стандартна"</string>
     <string name="auto_launch_label_generic" msgid="7865828543459493308">"Па змаўчанні"</string>
     <string name="screen_compatibility_label" msgid="3638271673726075815">"Сумяшчальнасць экрана"</string>
     <string name="permissions_label" msgid="7341733648403464213">"Дазволы"</string>
@@ -1865,7 +1871,7 @@
     <string name="app_factory_reset" msgid="8718986000278776272">"Выдаліць абнаўленні"</string>
     <string name="auto_launch_enable_text" msgid="3372898942144027341">"Вы выбралi запуск гэтага дадатку па змаўчаннi для некаторых дзеянняў."</string>
     <string name="always_allow_bind_appwidgets_text" msgid="2286211654774611037">"Вы дазволілі гэтаму дадатку ствараць віджэты і атрымліваць доступ да іх даных."</string>
-    <string name="auto_launch_disable_text" msgid="8560921288036801416">"Параметры па змаўчанні не ўсталяваныя"</string>
+    <string name="auto_launch_disable_text" msgid="8560921288036801416">"Стандартныя налады не зададзены"</string>
     <string name="clear_activities" msgid="2068014972549235347">"Скінуць налады па змаўчанні"</string>
     <string name="screen_compatibility_text" msgid="1768064020294301496">"Магчыма, гэта прыкладанне не разлічана для вашага экрана. Наладзьце яго."</string>
     <string name="ask_compatibility" msgid="6687958195768084807">"Запытваць падчас запуску"</string>
@@ -2243,10 +2249,10 @@
     <string name="print_settings" msgid="7886184656544483072">"Друк"</string>
     <string name="print_settings_summary_no_service" msgid="634173687975841526">"Выключана"</string>
     <plurals name="print_settings_summary" formatted="false" msgid="7580293760281445137">
-      <item quantity="one">Уключана <xliff:g id="COUNT">%1$d</xliff:g> служба друку</item>
-      <item quantity="few">Уключаны <xliff:g id="COUNT">%1$d</xliff:g> службы друку</item>
-      <item quantity="many">Уключаны <xliff:g id="COUNT">%1$d</xliff:g> служб друку</item>
-      <item quantity="other">Уключаны <xliff:g id="COUNT">%1$d</xliff:g> службы друку</item>
+      <item quantity="one">Уключаны <xliff:g id="COUNT">%1$d</xliff:g> сэрвіс друку</item>
+      <item quantity="few">Уключаны <xliff:g id="COUNT">%1$d</xliff:g> сэрвісы друку</item>
+      <item quantity="many">Уключаны <xliff:g id="COUNT">%1$d</xliff:g> сэрвісаў друку</item>
+      <item quantity="other">Уключаны <xliff:g id="COUNT">%1$d</xliff:g> сэрвісу друку</item>
     </plurals>
     <plurals name="print_jobs_summary" formatted="false" msgid="6180308415569432845">
       <item quantity="one"><xliff:g id="COUNT">%1$d</xliff:g> заданне друку</item>
@@ -2254,14 +2260,14 @@
       <item quantity="many"><xliff:g id="COUNT">%1$d</xliff:g> заданняў друку</item>
       <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> задання друку</item>
     </plurals>
-    <string name="print_settings_title" msgid="2886445296786932763">"Службы друку"</string>
+    <string name="print_settings_title" msgid="2886445296786932763">"Сэрвісы друку"</string>
     <string name="print_no_services_installed" msgid="3387777739528003794">"Няма ўсталяваных службаў"</string>
     <string name="print_no_printers_found" msgid="5090925427392294881">"Прынтараў не знойдзена"</string>
     <string name="print_menu_item_settings" msgid="2654804159012579508">"Налады"</string>
     <string name="print_menu_item_add_printers" msgid="8198201275621756510">"Дадаць прынтары"</string>
     <string name="print_feature_state_on" msgid="1838010230650403367">"Уключана"</string>
     <string name="print_feature_state_off" msgid="208580346723223688">"Выключана"</string>
-    <string name="print_menu_item_add_service" msgid="6803000110578493782">"Дадаць службу"</string>
+    <string name="print_menu_item_add_service" msgid="6803000110578493782">"Дадаць сэрвіс"</string>
     <string name="print_menu_item_add_printer" msgid="8529196211179574921">"Дадаць прынтар"</string>
     <string name="print_menu_item_search" msgid="1165316329772287360">"Пошук"</string>
     <string name="print_searching_for_printers" msgid="6538687129687642542">"Пошук прынтараў"</string>
@@ -2495,7 +2501,7 @@
     <string name="battery_detail_since_full_charge" msgid="3814176986148084378">"Разбіўка з моманту апошняй поўнай зарадкі"</string>
     <string name="battery_last_full_charge" msgid="5624033030647170717">"Апошняя поўная зарадка"</string>
     <string name="battery_full_charge_last" msgid="4614554109170251301">"Прыблізны час працы пры поўным зарадзе акумулятара"</string>
-    <string name="battery_footer_summary" msgid="4828444679643906943">"Даныя аб выкарыстанні батарэі з\'яўляюцца прыблізнымі і могуць змяняцца ў залежнасці ад выкарыстання"</string>
+    <string name="battery_footer_summary" msgid="4828444679643906943">"Даныя аб выкарыстанні акумулятара з\'яўляюцца прыблізнымі і могуць змяняцца ў залежнасці ад канкрэтных умоў"</string>
     <string name="battery_detail_foreground" msgid="6616408559186553085">"У актыўным рэжыме"</string>
     <string name="battery_detail_background" msgid="7938146832943604280">"У фонавым рэжыме"</string>
     <string name="battery_detail_power_usage" msgid="3606930232257489212">"Выкарыстанне зараду"</string>
@@ -2992,7 +2998,7 @@
     <string name="nfc_payment_how_it_works" msgid="7607901964687787177">"Як гэта працуе"</string>
     <string name="nfc_payment_no_apps" msgid="8844440783395420860">"Плаціце ў крамах з дапамогай свайго тэлефона"</string>
     <string name="nfc_payment_default" msgid="7869273092463612271">"Стандартны спосаб аплаты"</string>
-    <string name="nfc_payment_default_not_set" msgid="955804193510335338">"Не задана"</string>
+    <string name="nfc_payment_default_not_set" msgid="955804193510335338">"Не зададзена"</string>
     <string name="nfc_payment_app_and_desc" msgid="102312684211458190">"<xliff:g id="APP">%1$s</xliff:g> – <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="nfc_payment_use_default" msgid="3098724195746409476">"Выкарыстоўваць стандартную праграму"</string>
     <string name="nfc_payment_favor_default" msgid="7555356982142464260">"Заўсёды"</string>
@@ -3388,10 +3394,10 @@
     <string name="hide_silent_icons_title" msgid="1070905516921542662">"Хаваць значкі стану для апавяшчэнняў без гуку"</string>
     <string name="hide_silent_icons_summary" msgid="2624346914488256888">"Хаваць значкі для апавяшчэнняў без гуку на панэлі стану"</string>
     <string name="notification_badging_title" msgid="6311699476970264712">"Паказваць значкі апавяшчэнняў"</string>
-    <string name="notification_bubbles_title" msgid="9196562435741861317">"Дыялогі"</string>
+    <string name="notification_bubbles_title" msgid="9196562435741861317">"Усплывальныя апавяшчэнні"</string>
     <string name="notification_bubbles_summary" msgid="4624512775901949578">"Адусюль атрымлівайце хуткі доступ да змесціва праграмы з дапамогай зменлівых спалучэнняў клавіш"</string>
     <string name="bubbles_feature_education" msgid="8979109826818881018">"Некаторыя апавяшчэнні і іншае змесціва могуць паказвацца на экране ў выглядзе дыялогаў. Каб адкрыць дыялог, націсніце на яго. Каб закрыць дыялог, перацягніце яго ўніз экрана."</string>
-    <string name="bubbles_app_toggle_title" msgid="6401217027603326439">"Дыялогі"</string>
+    <string name="bubbles_app_toggle_title" msgid="6401217027603326439">"Усплывальныя апавяшчэнні"</string>
     <string name="bubbles_app_toggle_summary" msgid="7707611139796553855">"Дазваляе праграме \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" паказваць некаторыя апавяшчэнні ў выглядзе дыялогаў"</string>
     <string name="bubbles_feature_disabled_dialog_title" msgid="3375452386012079293">"Уключыце дыялогі"</string>
     <string name="bubbles_feature_disabled_dialog_text" msgid="326945485806386477">"Каб уключыць дыялогі для гэтай праграмы, уключыце дыялогі для прылады. Гэта паўплывае на іншыя праграмы, у якіх вы раней уключалі дыялогі."</string>
@@ -3403,7 +3409,7 @@
     <string name="notification_pulse_title" msgid="4861418327614907116">"Мігценне святла"</string>
     <string name="lock_screen_notifications_title" msgid="6889072265118747835">"На экране блакіроўкі"</string>
     <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"Працоўны профіль заблакіраваны"</string>
-    <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Паказваць усё змесціва ў апавяшчэннях"</string>
+    <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Паказваць усе апавяшчэнні"</string>
     <string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"Схаваць канфідэнцыяльныя даныя"</string>
     <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"Ніколі не паказваць апавяшчэнні"</string>
     <string name="lock_screen_notifications_interstitial_message" msgid="4230189215124387818">"Як павінны паказвацца апавяшчэнні, калі прылада заблакіравана?"</string>
@@ -3686,7 +3692,7 @@
     <string name="imei_information_title" msgid="7666097743700170757">"Інфармацыя IMEI"</string>
     <string name="imei_information_summary" msgid="716516316022275083">"Інфармацыя, звязаная з IMEI (міжнародным ідэнтыфікатарам мабільнага абсталявання)"</string>
     <string name="slot_number" msgid="785422579177068698">"(Слот<xliff:g id="SLOT_NUM">%1$d</xliff:g>)"</string>
-    <string name="launch_by_default" msgid="6106985160202769725">"Адкрываць па змаўчанні"</string>
+    <string name="launch_by_default" msgid="6106985160202769725">"Адкрываць стандартна"</string>
     <string name="app_launch_domain_links_title" msgid="2987289657348349133">"Адкрыццё спасылак"</string>
     <string name="app_launch_open_domain_urls_title" msgid="8595126859922391331">"Адкрыць спасылкі, якія падтрымліваюцца"</string>
     <string name="app_launch_open_domain_urls_summary" msgid="6803029846855502366">"Адкрываць без запыту"</string>
@@ -3700,8 +3706,7 @@
     <string name="change" msgid="41563753961948554">"Змяніць"</string>
     <string name="change_storage" msgid="2064045078609862770">"Змяніць сховішча"</string>
     <string name="notifications_label" msgid="2792398288062643318">"Апавяшчэнні"</string>
-    <!-- no translation found for notifications_enabled (439339392141736137) -->
-    <skip />
+    <string name="notifications_enabled" msgid="439339392141736137">"Уключана"</string>
     <string name="notifications_enabled_with_info" msgid="7706460489443809452">"<xliff:g id="NOTIFICATIONS_SENT">%1$s</xliff:g> / <xliff:g id="NOTIFICATIONS_CATEGORIES_OFF">%2$s</xliff:g>"</string>
     <string name="notifications_disabled" msgid="316658185757688983">"Выключана"</string>
     <string name="notifications_partly_blocked" msgid="6330451240669068819">"Адключаны катэгорыі: <xliff:g id="COUNT_0">%1$d</xliff:g> з <xliff:g id="COUNT_1">%2$d</xliff:g>"</string>
@@ -3945,7 +3950,7 @@
     <string name="camera_gesture_desc" msgid="7751841175916789527">"Адкрыйце дадатак камеры, двойчы павярнуўшы сваё запясце"</string>
     <string name="camera_double_tap_power_gesture_title" msgid="8874747801078147525">"Каб адкр. кам., двойчы кран. кнопку сіл."</string>
     <string name="camera_double_tap_power_gesture_desc" msgid="6166349645433682873">"Хутка адкрыць камеру без разблакіроўкі экрана"</string>
-    <string name="screen_zoom_title" msgid="164369086350486104">"Памер дысплэя"</string>
+    <string name="screen_zoom_title" msgid="164369086350486104">"Памер элементаў дысплэя"</string>
     <string name="screen_zoom_short_summary" msgid="5508079362742276703">"Павелічэнне або памяншэнне элементаў на экране"</string>
     <string name="screen_zoom_keywords" msgid="8358462497896524092">"шчыльнасць дысплэя, маштаб экрана, маштаб, маштабаванне"</string>
     <string name="screen_zoom_summary" msgid="5294003755961312560">"Павелічэнне або памяншэнне элементаў на экране. Размяшчэнне некаторых праграм на вашым экране можа змяніцца."</string>
@@ -3988,7 +3993,7 @@
     <string name="backup_disabled" msgid="6941165814784765643">"Рэзервовае капіраванне адключана"</string>
     <string name="android_version_summary" msgid="2192751442789395445">"Абноўлена да версіі Android <xliff:g id="VERSION">%1$s</xliff:g>"</string>
     <string name="android_version_pending_update_summary" msgid="3554543810520655076">"Ёсць абнаўленне"</string>
-    <string name="disabled_by_policy_title" msgid="1238318274952958846">"Дзеянне не дапускаецца"</string>
+    <string name="disabled_by_policy_title" msgid="1238318274952958846">"Дзеянне забаронена"</string>
     <string name="disabled_by_policy_title_adjust_volume" msgid="7094547090629203316">"Не ўдалося змяніць гучнасць"</string>
     <string name="disabled_by_policy_title_outgoing_calls" msgid="3805836913095496278">"Выклікі забаронены"</string>
     <string name="disabled_by_policy_title_sms" msgid="1453236584236681105">"Адпраўка SMS забаронена"</string>
@@ -4023,9 +4028,9 @@
     <string name="condition_device_muted_summary" msgid="3101055117680109021">"Для выклікаў і апавяшчэнняў"</string>
     <string name="condition_device_vibrate_title" msgid="5712659354868872338">"Толькі вібрацыя"</string>
     <string name="condition_device_vibrate_summary" msgid="9073880731894828604">"Для выклікаў і апавяшчэнняў"</string>
-    <string name="night_display_suggestion_title" msgid="4222839610992282188">"Глядзець графік начнога рэжыму"</string>
+    <string name="night_display_suggestion_title" msgid="4222839610992282188">"Задаць расклад Начной падсветкі"</string>
     <string name="night_display_suggestion_summary" msgid="1754361016383576916">"Аўтаматычна мяняць колер экрана ўвечары"</string>
-    <string name="condition_night_display_title" msgid="9171491784857160135">"Начны рэжым уключаны"</string>
+    <string name="condition_night_display_title" msgid="9171491784857160135">"Начная падсветка ўключана"</string>
     <string name="condition_night_display_summary" msgid="7885776986937527558">"Бурштынавы колер экрана"</string>
     <string name="condition_grayscale_title" msgid="1226351649203551299">"Адценні шэрага"</string>
     <string name="condition_grayscale_summary" msgid="749172886527349546">"Паказ толькі ў шэрым колеры"</string>
@@ -4056,7 +4061,7 @@
     <string name="usage" msgid="9172908720164431622">"Выкарыстанне"</string>
     <string name="cellular_data_usage" msgid="1236562234207782386">"Выкарыстанне мабільнага трафіку"</string>
     <string name="app_cellular_data_usage" msgid="8499761516172121957">"Выкарыстанне трафіка"</string>
-    <string name="wifi_data_usage" msgid="275569900562265895">"Выкарыстанне трафіка Wi-Fi"</string>
+    <string name="wifi_data_usage" msgid="275569900562265895">"Выкарыстанне трафіка сеткай Wi-Fi"</string>
     <string name="ethernet_data_usage" msgid="747614925362556718">"Выкарыстанне даных Ethernet"</string>
     <string name="wifi" msgid="1586738489862966138">"Wi-Fi"</string>
     <string name="ethernet" msgid="2365753635113154667">"Ethernet"</string>
@@ -4459,7 +4464,7 @@
     <string name="change_wifi_state_title" msgid="5140754955787584174">"Кіраванне наладамі Wi-Fi"</string>
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"Дазволіць праграме кіраваць наладамі Wi-Fi"</string>
     <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"Дазволіць гэтай праграме ўключаць ці выключаць Wi-Fi, шукаць сеткі Wi-Fi і падключацца да іх, дадаваць або выдаляць сеткі ці запускаць лакальны хот-спот"</string>
-    <string name="media_output_title" msgid="8710632337456601848">"Прайграваць медыяфайлы на"</string>
+    <string name="media_output_title" msgid="8710632337456601848">"Дзе прайграваць"</string>
     <string name="media_output_default_summary" msgid="3159237976830415584">"Гэта прылада"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"Тэлефон"</string>
     <string name="media_output_summary" product="tablet" msgid="6672024060360538526">"Планшэт"</string>
diff --git a/tests/CarDeveloperOptions/res/values-bg/arrays.xml b/tests/CarDeveloperOptions/res/values-bg/arrays.xml
index f42800f..d5488d5 100644
--- a/tests/CarDeveloperOptions/res/values-bg/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-bg/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"пускане на заден план"</item>
     <item msgid="6423861043647911030">"сила на звука за услугите за достъпност"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Местоположение"</item>
+    <item msgid="6656077694190491067">"Местоположение"</item>
+    <item msgid="8790228218278477369">"Местоположение"</item>
+    <item msgid="7836406246005211990">"Вибриране"</item>
+    <item msgid="3951439024549922598">"Четене на контактите"</item>
+    <item msgid="8802152411647068">"Промяна на контактите"</item>
+    <item msgid="229544934599698735">"Четене на списъка с обажданията"</item>
+    <item msgid="7396102294405899613">"Промяна на списъка с обажданията"</item>
+    <item msgid="3597797992398484655">"Четене на календара"</item>
+    <item msgid="2705975774250907343">"Промяна на календара"</item>
+    <item msgid="4668747371441932697">"Местоположение"</item>
+    <item msgid="1487578921720243646">"Публикуване на известие"</item>
+    <item msgid="4636080349724146638">"Местоположение"</item>
+    <item msgid="673510900286463926">"Обаждане по телефона"</item>
+    <item msgid="542083422784609790">"Четене на SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Писане на SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Получаване на SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Получаване на SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Получаване на SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Получаване на SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Изпращане на SMS/MMS"</item>
+    <item msgid="4726682243833913568">"Четене на SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Писане на SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Промяна на настройките"</item>
+    <item msgid="8705854389991425629">"Рисуване върху елемент"</item>
+    <item msgid="5861356020344153651">"Достъп до известията"</item>
+    <item msgid="78432174621628659">"Камера"</item>
+    <item msgid="3986116419882154794">"Запис на звук"</item>
+    <item msgid="4516840825756409490">"Възпроизвеждане на звук"</item>
+    <item msgid="6811712502798183957">"Четене на буферната памет"</item>
+    <item msgid="2780369012602289114">"Промяна на буферната памет"</item>
+    <item msgid="2331359440170850868">"Бутони за мултимедия"</item>
+    <item msgid="6133599737122751231">"Фокусиране на звука"</item>
+    <item msgid="6844485713404805301">"Основна сила на звука"</item>
+    <item msgid="1600379420669104929">"Сила на звука за глас"</item>
+    <item msgid="6296768210470214866">"Сила на звука при звънене"</item>
+    <item msgid="510690696071629241">"Сила на звука за мултимедия"</item>
+    <item msgid="406861638631430109">"Сила на звука на будилника"</item>
+    <item msgid="4715864795872233884">"Сила на звука при известие"</item>
+    <item msgid="2311478519251301183">"Сила на звука за Bluetooth"</item>
+    <item msgid="5133991377896747027">"Оставяне в будно състояние"</item>
+    <item msgid="2464189519136248621">"Местоположение"</item>
+    <item msgid="2062677934050803037">"Местоположение"</item>
+    <item msgid="1735171933192715957">"Получаване на статистически данни за употребата"</item>
+    <item msgid="1014093788778383554">"Заглушаване/включване на микрофона"</item>
+    <item msgid="4199297950608622850">"Показване на съобщение в изскачащо прозорче"</item>
+    <item msgid="2527962435313398821">"Прожектиране на мултимедия"</item>
+    <item msgid="5117506254221861929">"Активиране на виртуална частна мрежа (VPN)"</item>
+    <item msgid="8291198322681891160">"Запис на тапет"</item>
+    <item msgid="7106921284621230961">"Структура за помощ"</item>
+    <item msgid="4496533640894624799">"Екранна снимка за помощ"</item>
+    <item msgid="2598847264853993611">"Четене на състоянието на телефона"</item>
+    <item msgid="9215610846802973353">"Добавяне на гласова поща"</item>
+    <item msgid="9186411956086478261">"Използване на SIP"</item>
+    <item msgid="6884763100104539558">"Обработване на изходящо обаждане"</item>
+    <item msgid="125513972170580692">"Отпечатък"</item>
+    <item msgid="2556071024281275619">"Телесни сензори"</item>
+    <item msgid="617168514928339387">"Четене на клетъчни излъчвания"</item>
+    <item msgid="7134693570516523585">"Мнимо местоположение"</item>
+    <item msgid="7224489175375229399">"Четене на хранилището"</item>
+    <item msgid="8472735063903258202">"Запис в хранилището"</item>
+    <item msgid="4069276819909595110">"Включване на екрана"</item>
+    <item msgid="1228338896751121025">"Създаване на профили"</item>
+    <item msgid="3181581793459233672">"Пускане на заден план"</item>
+    <item msgid="2340936043025374076">"Сила на звука за услугите за достъпност"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Кратко"</item>
     <item msgid="4816511817309094890">"Средна важност"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Никога да не се разрешава"</item>
     <item msgid="8184570120217958741">"Винаги да се разрешава"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Нормално"</item>
+    <item msgid="5101233285497327432">"Средно"</item>
+    <item msgid="1555861583162930714">"Ниска"</item>
+    <item msgid="1719683776264798117">"Критичнo"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Нормално"</item>
+    <item msgid="6107138933849816768">"Средно"</item>
+    <item msgid="182695359839047859">"Ниска"</item>
+    <item msgid="8577246509202964244">"Критичнo"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Постоянно"</item>
     <item msgid="167418068739176448">"Водеща активност"</item>
diff --git a/tests/CarDeveloperOptions/res/values-bg/config.xml b/tests/CarDeveloperOptions/res/values-bg/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-bg/config.xml
+++ b/tests/CarDeveloperOptions/res/values-bg/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-bg/strings.xml b/tests/CarDeveloperOptions/res/values-bg/strings.xml
index b34c516..6d0ce88 100644
--- a/tests/CarDeveloperOptions/res/values-bg/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-bg/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Намаляване или уголемяване на текста на екрана."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Намаляване на размера"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Увеличаване на размера"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Примерен текст"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Вълшебникът от Оз"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Глава 11: Удивителният изумруден град на Оз"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Трябва да съдържа по-малко от <xliff:g id="NUMBER_1">%d</xliff:g> цифри</item>
       <item quantity="one">Трябва да съдържа по-малко от <xliff:g id="NUMBER_0">%d</xliff:g> цифра</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Трябва да съдържа само цифри (от 0 до 9)"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Администраторът на у-вото не разрешава ползването на скорошен ПИН"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Често срещаните ПИН кодове се блокират от системния ви администратор. Опитайте с друг ПИН код."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Не може да включва невалиден знак"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Трябва да съдържа поне <xliff:g id="COUNT">%d</xliff:g> небуквени знака</item>
       <item quantity="one">Трябва да съдържа поне 1 небуквен знак</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Трябва да съдържа поне <xliff:g id="COUNT">%d</xliff:g> нецифрени знака</item>
+      <item quantity="one">Трябва да съдържа поне 1 нецифрен знак</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Администраторът на у-вото не разрешава ползването на скорошна парола"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Често срещаните пароли се блокират от системния ви администратор. Опитайте с друга парола."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Възходящите, низходящите и повтарящите се поредици от цифри не са разрешени"</string>
@@ -727,7 +729,7 @@
     <string name="bluetooth_settings" msgid="5228032727293770389">"Bluetooth"</string>
     <string name="bluetooth_settings_title" msgid="7261244857456521825">"Bluetooth"</string>
     <string name="bluetooth_settings_summary" msgid="1221689092429277887">"Управление на връзки, задаване на име и откриваемост на устройство"</string>
-    <string name="bluetooth_pairing_request" msgid="7221745525632573125">"Искате ли да сдвоите с/ъс „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“?"</string>
+    <string name="bluetooth_pairing_request" msgid="7221745525632573125">"Искате ли да сдвоите с(ъс) „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“?"</string>
     <string name="bluetooth_pairing_key_msg" msgid="1139230917419961975">"Код за сдвояване с Bluetooth"</string>
     <string name="bluetooth_enter_passkey_msg" msgid="6205151011298670207">"Въведете кода за сдвояване, след което натиснете „Return“ или „Enter“"</string>
     <string name="bluetooth_enable_alphanumeric_pin" msgid="9138308197078115672">"ПИН кодът съдържа букви или символи"</string>
@@ -818,7 +820,7 @@
     <string name="wifi_ask_disable" msgid="2146839060110412974">"<xliff:g id="REQUESTER">%s</xliff:g> иска да изключи Wi-Fi"</string>
     <string name="art_verifier_for_debuggable_title" msgid="5223835619409464642">"Потвържд. на байткода за прил. с възможн. за отстр. на грешки"</string>
     <string name="art_verifier_for_debuggable_summary" msgid="2204242476996701111">"Разрешаване на ART да потвърждава байткода за приложенията с възможност за отстраняване на грешки"</string>
-    <string name="nfc_quick_toggle_title" msgid="4990697912813795002">"КБП"</string>
+    <string name="nfc_quick_toggle_title" msgid="4990697912813795002">"NFC"</string>
     <string name="nfc_quick_toggle_summary" product="tablet" msgid="983451155092850657">"Разрешаване на обмен на данни, когато таблетът докосва друго устройство"</string>
     <string name="nfc_quick_toggle_summary" product="default" msgid="7141056939052895142">"Разрешаване на обмен на данни, когато телефонът докосва друго устройство"</string>
     <string name="nfc_disclaimer_title" msgid="4860231267351602970">"Включване на КБП"</string>
@@ -933,13 +935,13 @@
     <string name="wifi_privacy_settings" msgid="4462092795794247809">"Поверителност"</string>
     <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"Рандомизиран MAC адрес"</string>
     <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"Добавяне на устройство"</string>
-    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"За да добавите устройството към „<xliff:g id="SSID">%1$s</xliff:g>“, центрирайте по-долу кода за бърза реакция"</string>
+    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"За да добавите устройството към <xliff:g id="SSID">%1$s</xliff:g>, центрирайте по-долу кода за бърза реакция"</string>
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"Сканиране на кода за бърза реакция"</string>
-    <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"За да се свържете с „<xliff:g id="SSID">%1$s</xliff:g>“, центрирайте по-долу кода за бърза реакция"</string>
+    <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"За да се свържете към <xliff:g id="SSID">%1$s</xliff:g>, центрирайте по-долу кода за бърза реакция"</string>
     <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"Присъединете се към  Wi‑Fi мрежата, като сканирате код за бърза реакция"</string>
     <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Споделяне на Wi‑Fi мрежата"</string>
-    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"Сканирайте този код за бърза реакция, за да се свържете към „<xliff:g id="SSID">%1$s</xliff:g>“ и да споделите паролата"</string>
-    <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"Сканирайте този код за бърза реакция, за да се свържете към „<xliff:g id="SSID">%1$s</xliff:g>“"</string>
+    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"Сканирайте този код за бърза реакция, за да се свържете към <xliff:g id="SSID">%1$s</xliff:g> и да споделите паролата"</string>
+    <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"Сканирайте този код за бърза реакция, за да се свържете към <xliff:g id="SSID">%1$s</xliff:g>"</string>
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"Кодът за бърза реакция не можа да бъде прочетен. Центрирайте го отново и опитайте пак"</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"Опитайте отново. Ако проблемът не се отстрани, свържете се с производителя на устройството."</string>
     <string name="wifi_dpp_failure_not_compatible" msgid="4320027179973678283">"Нещо се обърка"</string>
@@ -949,11 +951,11 @@
     <string name="wifi_dpp_check_connection_try_again" msgid="7144663015219170999">"Проверете връзката и опитайте отново"</string>
     <string name="wifi_dpp_choose_network" msgid="6251424431594491691">"Избиране на мрежа"</string>
     <string name="wifi_dpp_choose_network_to_connect_device" msgid="6385259857886784285">"За да свържете устройството си, изберете мрежа"</string>
-    <string name="wifi_dpp_add_device_to_wifi" msgid="6454198064645462446">"Да се добави ли това устройство към „<xliff:g id="SSID">%1$s</xliff:g>“?"</string>
+    <string name="wifi_dpp_add_device_to_wifi" msgid="6454198064645462446">"Да се добави ли това устройство към <xliff:g id="SSID">%1$s</xliff:g>?"</string>
     <string name="wifi_dpp_wifi_shared_with_device" msgid="5713765471758272471">"Wi-Fi мрежата бе споделена с устройството"</string>
     <string name="wifi_dpp_add_another_device" msgid="3698441567235301565">"Добавяне на друго устройство"</string>
     <string name="wifi_dpp_choose_different_network" msgid="128515107488187050">"Избиране на друга мрежа"</string>
-    <string name="wifi_dpp_could_not_add_device" msgid="4966109556543584813">"Устройството не можа да се добави"</string>
+    <string name="wifi_dpp_could_not_add_device" msgid="4966109556543584813">"Устройството не бе добавено"</string>
     <string name="wifi_dpp_device_found" msgid="6488461467496850841">"Открито е устройство"</string>
     <string name="wifi_dpp_sharing_wifi_with_this_device" msgid="2540529164687476827">"Wi-Fi мрежата се споделя с това устройство…"</string>
     <string name="wifi_dpp_connecting" msgid="4229290407210299897">"Свързва се…"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Мобилни данни"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Използване на мобилната мрежа, ако няма достъп до Wi‑Fi"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Използване на Wi‑Fi, ако мобилната мрежа не е налице"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Обаждане през Wi‑Fi. Ако връзката прекъсне, обаждането ще завърши."</string>
@@ -1204,7 +1209,7 @@
     <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"Вкл. – Екранът няма да се изключи, ако гледате в него"</string>
     <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"Изключено"</string>
     <string name="adaptive_sleep_description" msgid="812673735459170009">"Предотвратява изключването на екрана ви, ако гледате в него."</string>
-    <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Функцията „Адаптивен екран“ използва предната камера, за да види дали някой гледа в екрана. Тя работи на устройството и изображенията не се съхраняват, нито се изпращат до Google."</string>
+    <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Функцията „Адаптивен екран“ използва предната камера, за да установи дали някой гледа в екрана. Тя работи на устройството и изображенията не се съхраняват, нито се изпращат до Google."</string>
     <string name="night_display_title" msgid="1305002424893349814">"Нощно осветление"</string>
     <string name="night_display_text" msgid="5330502493684652527">"Функцията „Нощно осветление“ придава кехлибареножълт нюанс на екрана. Това подобрява видимостта му и четенето на него при слаба светлина и може да ви помогне да заспите по-лесно."</string>
     <string name="night_display_auto_mode_title" msgid="8493573087102481588">"График"</string>
@@ -1562,7 +1567,7 @@
     <string name="error_adding_apn_type" msgid="671634520340569678">"Операторът не позволява добавянето на имена на точки за достъп (APN) от типа „%s“."</string>
     <string name="restore_default_apn" msgid="7195266404077471007">"Стандартните настройки за името на точката за достъп (APN) се възстановяват."</string>
     <string name="menu_restore" msgid="3799288817317293115">"Възстановяване на стандартни"</string>
-    <string name="restore_default_apn_completed" msgid="5671734152740058937">"Възстановяването на стандартните настройките за името на точката за достъп (APN) завърши."</string>
+    <string name="restore_default_apn_completed" msgid="5671734152740058937">"Възстановяването на стандартните настройки за името на точката за достъп (APN) завърши."</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"Опции за нулиране"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"Мрежата, приложенията или устройството могат да бъдат нулирани"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"Нулиране на настройките за Wi-Fi, мобилни данни и Bluetooth"</string>
@@ -2294,7 +2299,7 @@
     </plurals>
     <plurals name="battery_tip_restrict_summary" formatted="false" msgid="984148373944071669">
       <item quantity="other">%2$d приложения използват батерията интензивно на заден план</item>
-      <item quantity="one">%1$s приложение използва батерията интензивно на заден план</item>
+      <item quantity="one">Приложението %1$s използва батерията интензивно на заден план</item>
     </plurals>
     <plurals name="battery_tip_restrict_handled_summary" formatted="false" msgid="469696766640020557">
       <item quantity="other">Тези приложения не могат да се изпълняват на заден план</item>
@@ -2304,9 +2309,9 @@
       <item quantity="other">Да се ограничат ли %1$d приложения?</item>
       <item quantity="one">Да се ограничи ли приложението?</item>
     </plurals>
-    <string name="battery_tip_restrict_app_dialog_message" msgid="6905822297507947381">"За да не изразходвате батерията, спрете използването й на заден план от <xliff:g id="APP">%1$s</xliff:g>. Това приложение може да не работи правилно и е възможно да има забавяне на известията."</string>
-    <string name="battery_tip_restrict_apps_less_than_5_dialog_message" msgid="4225881888543582456">"За да не изразходвате батерията, спрете използването й на заден план от тези приложения. Ограничените приложения може да не работят правилно и е възможно да има забавяне на известията.\n\nПриложения:"</string>
-    <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"За да не изразходвате батерията, спрете използването й на заден план от тези приложения. Ограничените приложения може да не работят правилно и е възможно да има забавяне на известията.\n\nПриложения:\n<xliff:g id="APP_LIST">%1$s</xliff:g>."</string>
+    <string name="battery_tip_restrict_app_dialog_message" msgid="6905822297507947381">"За да не изразходвате батерията, спрете използването ѝ на заден план от <xliff:g id="APP">%1$s</xliff:g>. Това приложение може да не работи правилно и е възможно да има забавяне на известията."</string>
+    <string name="battery_tip_restrict_apps_less_than_5_dialog_message" msgid="4225881888543582456">"За да не изразходвате батерията, спрете използването ѝ на заден план от тези приложения. Ограничените приложения може да не работят правилно и е възможно да има забавяне на известията.\n\nПриложения:"</string>
+    <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"За да не изразходвате батерията, спрете използването ѝ на заден план от тези приложения. Ограничените приложения може да не работят правилно и е възможно да има забавяне на известията.\n\nПриложения:\n<xliff:g id="APP_LIST">%1$s</xliff:g>."</string>
     <string name="battery_tip_restrict_app_dialog_ok" msgid="2573410775701913487">"Ограничаване"</string>
     <string name="battery_tip_unrestrict_app_dialog_title" msgid="812458516399125710">"Да се премахне ли ограничението?"</string>
     <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"Това приложение ще може да използва батерията на заден план. Тя може да се изтощи по-рано от очакваното."</string>
@@ -2967,7 +2972,7 @@
     <string name="restriction_wifi_config_summary" msgid="2450206736438594690">"Разрешаване на промяна на настройките за Wi‑Fi и мобилни данни"</string>
     <string name="restriction_bluetooth_config_title" msgid="34551118506640221">"Bluetooth"</string>
     <string name="restriction_bluetooth_config_summary" msgid="5304900222614952895">"Разрешаване на промяна на сдвояванията и настройките на Bluetooth"</string>
-    <string name="restriction_nfc_enable_title" msgid="5146674482590550598">"КБП"</string>
+    <string name="restriction_nfc_enable_title" msgid="5146674482590550598">"NFC"</string>
     <string name="restriction_nfc_enable_summary_config" msgid="405349698260328073">"Разрешаване на обмен на данни, когато <xliff:g id="DEVICE_NAME">%1$s</xliff:g> докосне друго устройство с КБП"</string>
     <string name="restriction_nfc_enable_summary" product="tablet" msgid="3292205836938064931">"Разрешаване на обмен на данни, когато таблетът докосва друго устройство"</string>
     <string name="restriction_nfc_enable_summary" product="default" msgid="226439584043333608">"Разрешаване на обмен на данни, когато телефонът докосва друго устройство"</string>
diff --git a/tests/CarDeveloperOptions/res/values-bn/arrays.xml b/tests/CarDeveloperOptions/res/values-bn/arrays.xml
index 3b10fdc..a76eda3 100644
--- a/tests/CarDeveloperOptions/res/values-bn/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-bn/arrays.xml
@@ -38,7 +38,16 @@
     <item msgid="5827960506924849753">"১০ মিনিট"</item>
     <item msgid="6677424950124253938">"৩০ মিনিট"</item>
   </string-array>
-    <!-- no translation found for dream_timeout_entries:7 (8271452751594598661) -->
+  <string-array name="dream_timeout_entries">
+    <item msgid="6487043225269853023">"কখনই নয়"</item>
+    <item msgid="2517785806387977252">"১৫ সেকেন্ড"</item>
+    <item msgid="6347954399441173672">"৩০ সেকেন্ড"</item>
+    <item msgid="4858305253279921789">"১ মিনিট"</item>
+    <item msgid="8109273437140044073">"২ মিনিট"</item>
+    <item msgid="2788593551142462622">"৫ মিনিট"</item>
+    <item msgid="8012672183888404961">"১০ মিনিট"</item>
+    <item msgid="8271452751594598661">"৩০ মিনিট"</item>
+  </string-array>
   <string-array name="lock_after_timeout_entries">
     <item msgid="2232921187970351881">"অবিলম্বে"</item>
     <item msgid="2038544972632026612">"৫ সেকেন্ড"</item>
@@ -50,17 +59,47 @@
     <item msgid="811192536981678974">"১০ মিনিট"</item>
     <item msgid="7258394417241706272">"৩০ মিনিট"</item>
   </string-array>
-    <!-- no translation found for entries_font_size:0 (2340391964816059553) -->
-    <!-- no translation found for entries_font_size:0 (6490061470416867723) -->
-    <!-- no translation found for entries_font_size:2 (1714184661981538355) -->
-    <!-- no translation found for entries_font_size:2 (1678068858001018666) -->
-    <!-- no translation found for wifi_status:3 (5848277343965362748) -->
-    <!-- no translation found for wifi_status_with_ssid:1 (6816207058895999545) -->
-    <!-- no translation found for wifi_status_with_ssid:3 (7547609081339573756) -->
-    <!-- no translation found for wifi_status_with_ssid:4 (5145158315060185414) -->
+  <string-array name="entries_font_size">
+    <item msgid="2340391964816059553">"ছোট"</item>
+    <item msgid="591935967183159581">"ডিফল্ট"</item>
+    <item msgid="1714184661981538355">"বড়"</item>
+    <item msgid="6195563047686707484">"বৃহত্তম"</item>
+  </string-array>
+  <string-array name="wifi_status">
+    <item msgid="1304883790721412351"></item>
+    <item msgid="4157625910392775808">"স্ক্যান করা হচ্ছে…"</item>
+    <item msgid="5597394826455877834">"কানেক্ট হচ্ছে..."</item>
+    <item msgid="5848277343965362748">"যাচাই করা হচ্ছে…"</item>
+    <item msgid="3391238031431440676">"আইপি অ্যাড্রেস প্রাপ্ত করা হচ্ছে..."</item>
+    <item msgid="5257597310494000224">"কানেক্ট আছে"</item>
+    <item msgid="8472497592913050396">"স্থগিত করা হয়েছে"</item>
+    <item msgid="1228072488815999109">"ডিসকানেক্ট হচ্ছে..."</item>
+    <item msgid="7253087004422991731">"ডিসকানেক্ট করা হয়েছে"</item>
+    <item msgid="4169850917304751227">"অসফল"</item>
+    <item msgid="6266658166690831131">"অবরুদ্ধ"</item>
+    <item msgid="4517230805854909775">"সাময়িকরূপে দুর্বল কানেকশন এড়ানো হচ্ছে"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="4853670665485437464"></item>
+    <item msgid="6816207058895999545">"স্ক্যান করা হচ্ছে…"</item>
+    <item msgid="8058143476674427024">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> এর সাথে কানেক্ট হচ্ছে…"</item>
+    <item msgid="7547609081339573756">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>-এর সাথে যাচাই করা হচ্ছে…"</item>
+    <item msgid="5145158315060185414">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> থেকে আইপি অ্যাড্রেসের তথ্য সংগ্রহ করা হচ্ছে…"</item>
+    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> তে কানেক্ট হয়েছে"</item>
+    <item msgid="6600156231416890902">"স্থগিত করা হয়েছে"</item>
+    <item msgid="4133290864821295785">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> থেকে ডিসকানেক্ট হচ্ছে…"</item>
+    <item msgid="3980154971187953257">"ডিসকানেক্ট করা হয়েছে"</item>
+    <item msgid="2847316776634969068">"অসফল"</item>
+    <item msgid="4390990424746035383">"অবরুদ্ধ"</item>
+    <item msgid="3618248791367063949">"সাময়িকরূপে দুর্বল কানেকশন এড়ানো হচ্ছে"</item>
+  </string-array>
     <!-- no translation found for wifi_tether_security:0 (5586343370515598801) -->
     <!-- no translation found for wifi_tether_security:1 (6136336549994615745) -->
-    <!-- no translation found for wifi_p2p_wps_setup:0 (5390235347963255303) -->
+  <string-array name="wifi_p2p_wps_setup">
+    <item msgid="5390235347963255303">"পুশ বোতাম"</item>
+    <item msgid="7401896200768713930">"চেনা ডিভাইস থেকে পিন"</item>
+    <item msgid="4526848028011846710">"এই ডিভাইস থেকে পিন"</item>
+  </string-array>
   <string-array name="wifi_p2p_status">
     <item msgid="8741947238021758201">"কানেক্ট আছে"</item>
     <item msgid="983792611851499732">"আমন্ত্রিত"</item>
@@ -82,8 +121,13 @@
     <item msgid="1644506614010085798">"৪"</item>
     <item msgid="3132506679404897150">"৫"</item>
   </string-array>
-    <!-- no translation found for wifi_signal:1 (7882129634982603782) -->
-    <!-- no translation found for wifi_signal:4 (999948812884919584) -->
+  <string-array name="wifi_signal">
+    <item msgid="1709949377823900951">"খারাপ"</item>
+    <item msgid="7882129634982603782">"খারাপ"</item>
+    <item msgid="6457357501905996224">"ঠিকঠাক"</item>
+    <item msgid="405271628162918841">"ভাল"</item>
+    <item msgid="999948812884919584">"খুব ভাল"</item>
+  </string-array>
   <string-array name="data_usage_data_range">
     <item msgid="8986775481492954015">"গত ৩০ দিন"</item>
     <item msgid="3211287705232736964">"ব্যবহার চক্র সেট করুন..."</item>
@@ -119,7 +163,10 @@
     <item msgid="7330627471456865502">"MSCHAPV2"</item>
     <item msgid="6255179395132581882">"GTC"</item>
   </string-array>
-    <!-- no translation found for wifi_ip_settings:1 (4377002609760712163) -->
+  <string-array name="wifi_ip_settings">
+    <item msgid="2717196390555072244">"DHCP"</item>
+    <item msgid="4377002609760712163">"স্ট্যাটিক"</item>
+  </string-array>
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"কোনো কিছুই নয়"</item>
     <item msgid="1464741437353223198">"ম্যানুয়াল"</item>
@@ -239,11 +286,73 @@
     <item msgid="1165623660533024666">"পটভূমি্তে অ্যাপ্স চলছে"</item>
     <item msgid="6423861043647911030">"অ্যাক্সেসযোগ্যতার ভলিউম"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:3 (7836406246005211990) -->
-    <!-- no translation found for app_ops_labels:4 (3951439024549922598) -->
-    <!-- no translation found for app_ops_labels:8 (3597797992398484655) -->
-    <!-- no translation found for app_ops_labels:20 (3037159047591081136) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"লোকেশন"</item>
+    <item msgid="6656077694190491067">"লোকেশন"</item>
+    <item msgid="8790228218278477369">"লোকেশন"</item>
+    <item msgid="7836406246005211990">"ভাইব্রেট"</item>
+    <item msgid="3951439024549922598">"পরিচিতি পড়ুন"</item>
+    <item msgid="8802152411647068">"পরিচিতি পরিবর্তন করুন"</item>
+    <item msgid="229544934599698735">"কল লগ পড়ুন"</item>
+    <item msgid="7396102294405899613">"কল লগ পরিবর্তন করুন"</item>
+    <item msgid="3597797992398484655">"ক্যালেন্ডার পড়ুন"</item>
+    <item msgid="2705975774250907343">"ক্যালেন্ডারে পরিবর্তন করুন"</item>
+    <item msgid="4668747371441932697">"লোকেশন"</item>
+    <item msgid="1487578921720243646">"বিজ্ঞপ্তি পোস্ট করুন"</item>
+    <item msgid="4636080349724146638">"লোকেশন"</item>
+    <item msgid="673510900286463926">"ফোন করুন"</item>
+    <item msgid="542083422784609790">"SMS/MMS পড়ুন"</item>
+    <item msgid="1033780373029588436">"SMS/MMS লিখুন"</item>
+    <item msgid="5647111115517787488">"SMS/MMS পান"</item>
+    <item msgid="8591105601108455893">"SMS/MMS পান"</item>
+    <item msgid="7730995008517841903">"SMS/MMS পান"</item>
+    <item msgid="2613033109026626086">"SMS/MMS পান"</item>
+    <item msgid="3037159047591081136">"এসএমএস বা এমএমএস পাঠান"</item>
+    <item msgid="4726682243833913568">"SMS/MMS পড়ুন"</item>
+    <item msgid="6555678522277865572">"SMS/MMS লিখুন"</item>
+    <item msgid="6981734935578130884">"সেটিংস সংশোধন করুন"</item>
+    <item msgid="8705854389991425629">"উপরে অঙ্কন করুন"</item>
+    <item msgid="5861356020344153651">"বিজ্ঞপ্তিগুলি অ্যাক্সেস করুন"</item>
+    <item msgid="78432174621628659">"ক্যামেরা"</item>
+    <item msgid="3986116419882154794">"অডিও রেকর্ড"</item>
+    <item msgid="4516840825756409490">"অডিও প্লে করুন"</item>
+    <item msgid="6811712502798183957">"ক্লিপবোর্ড পড়ুন"</item>
+    <item msgid="2780369012602289114">"ক্লিপবোর্ড সংশোধন করুন"</item>
+    <item msgid="2331359440170850868">"মিডিয়া বোতামগুলি"</item>
+    <item msgid="6133599737122751231">"অডিও ফোকাস"</item>
+    <item msgid="6844485713404805301">"মাস্টার ভলিউম"</item>
+    <item msgid="1600379420669104929">"ভয়েস ভলিউম"</item>
+    <item msgid="6296768210470214866">"রিং ভলিউম"</item>
+    <item msgid="510690696071629241">"মিডিয়া ভলিউম"</item>
+    <item msgid="406861638631430109">"অ্যালার্মের ভলিউম"</item>
+    <item msgid="4715864795872233884">"বিজ্ঞপ্তির ভলিউম"</item>
+    <item msgid="2311478519251301183">"ব্লুটুথ এর ভলিউম"</item>
+    <item msgid="5133991377896747027">"জাগ্রত রাখুন"</item>
+    <item msgid="2464189519136248621">"লোকেশন"</item>
+    <item msgid="2062677934050803037">"লোকেশন"</item>
+    <item msgid="1735171933192715957">"ব্যবহারের পরিসংখ্যান পান"</item>
+    <item msgid="1014093788778383554">"মাইক্রোফোন মিউট/সশব্দ করুন"</item>
+    <item msgid="4199297950608622850">"টোস্ট দেখান"</item>
+    <item msgid="2527962435313398821">"মিডিয়াতে অভিক্ষেপ করুন"</item>
+    <item msgid="5117506254221861929">"VPN সক্রিয় করুন"</item>
+    <item msgid="8291198322681891160">"লেখার ওয়ালপেপার"</item>
+    <item msgid="7106921284621230961">"পরিকাঠামোর সহায়তা"</item>
+    <item msgid="4496533640894624799">"স্ক্রিনশটে সহায়তা"</item>
+    <item msgid="2598847264853993611">"ফোনের অবস্থা পড়ুন"</item>
+    <item msgid="9215610846802973353">"ভয়েসমেল যোগ করুন"</item>
+    <item msgid="9186411956086478261">"SIP ব্যবহার করুন"</item>
+    <item msgid="6884763100104539558">"আউটগোয়িং কলের প্রক্রিয়া করুন"</item>
+    <item msgid="125513972170580692">"আঙ্গুলের ছাপ"</item>
+    <item msgid="2556071024281275619">"শরীরের সেন্সরগুলি"</item>
+    <item msgid="617168514928339387">"সেলে সম্প্রচারগুলি পড়ুন"</item>
+    <item msgid="7134693570516523585">"ছদ্ম লোকেশন"</item>
+    <item msgid="7224489175375229399">"সঞ্চয়স্থানে পড়ুন"</item>
+    <item msgid="8472735063903258202">"সঞ্চয়স্থানে লিখুন"</item>
+    <item msgid="4069276819909595110">"স্ক্রিন চালু করুন"</item>
+    <item msgid="1228338896751121025">"অ্যাকাউন্ট পে‍য়ে যান"</item>
+    <item msgid="3181581793459233672">"পটভূমিতে অ্যাপ্স চলছে"</item>
+    <item msgid="2340936043025374076">"অ্যাক্সেসযোগ্যতার ভলিউম"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"স্বল্প"</item>
     <item msgid="4816511817309094890">"মাঝারি"</item>
@@ -260,7 +369,13 @@
     <item msgid="4627069151979553527">"কার্সিভ"</item>
     <item msgid="6896773537705206194">"Small Capitals"</item>
   </string-array>
-    <!-- no translation found for captioning_font_size_selector_titles:3 (2784236342175159295) -->
+  <string-array name="captioning_font_size_selector_titles">
+    <item msgid="1680223634161592855">"অতি ক্ষুদ্র"</item>
+    <item msgid="5091603983404027034">"ক্ষুদ্র"</item>
+    <item msgid="176844712416932112">"Normal"</item>
+    <item msgid="2784236342175159295">"বড়"</item>
+    <item msgid="218913203203160606">"খুব বড়"</item>
+  </string-array>
   <string-array name="captioning_edge_type_selector_titles">
     <item msgid="3865198759294188069">"ডিফল্ট"</item>
     <item msgid="6488643537808152001">"কোনো কিছুই নয়"</item>
@@ -275,7 +390,14 @@
     <item msgid="1874668269931014581">"৭৫%"</item>
     <item msgid="6462911487571123954">"১০০%"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"অ্যাপের ডিফল্টগুলি ব্যবহার করুন"</item>
+    <item msgid="8611890312638868524">"কালোর উপর সাদা"</item>
+    <item msgid="5891360837786277638">"সাদার উপর কালো"</item>
+    <item msgid="2798457065945456853">"কালোর উপর হলুদ"</item>
+    <item msgid="5799049811524553967">"নীলের উপর হলুদ"</item>
+    <item msgid="3673930830658169860">"কাস্টম"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"PPTP VPN"</item>
     <item msgid="1349760781118368659">"আগে থেকে শেয়ার করা কীগুলির সাথে L2TP/IPSec VPN"</item>
@@ -288,15 +410,32 @@
     <item msgid="2958623927055120839">"কোনো কিছুই নয়"</item>
     <item msgid="1157046369795346308">"ম্যানুয়াল"</item>
   </string-array>
-    <!-- no translation found for vpn_states:4 (9135049670787351881) -->
+  <string-array name="vpn_states">
+    <item msgid="5408915841694583740">"ডিসকানেক্ট করা হয়েছে"</item>
+    <item msgid="8754480102834556765">"আরম্ভ হচ্ছে..."</item>
+    <item msgid="3351334355574270250">"কানেক্ট হচ্ছে..."</item>
+    <item msgid="8303882153995748352">"কানেক্ট আছে"</item>
+    <item msgid="9135049670787351881">"টাইম-আউট"</item>
+    <item msgid="2124868417182583926">"অসফল"</item>
+  </string-array>
   <string-array name="security_settings_premium_sms_values">
     <item msgid="1164265643455394443">"জিজ্ঞাসা করুন"</item>
     <item msgid="7718817231348607934">"কখনো অনুমতি দেবেন না"</item>
     <item msgid="8184570120217958741">"সর্বদা অনুমতি দিন"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"সাধারণ"</item>
+    <item msgid="5101233285497327432">"মাঝারি"</item>
+    <item msgid="1555861583162930714">"কম করুন"</item>
+    <item msgid="1719683776264798117">"জটিল"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"স্বাভাবিক"</item>
+    <item msgid="6107138933849816768">"মাঝারি"</item>
+    <item msgid="182695359839047859">"কম করুন"</item>
+    <item msgid="8577246509202964244">"জটিল"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"ক্রমাগত"</item>
     <item msgid="167418068739176448">"শীর্ষ অ্যাক্টিভিটি"</item>
@@ -335,10 +474,10 @@
   <string-array name="wifi_metered_entries">
     <item msgid="4329206416008519163">"অটোমেটিক শনাক্ত হতে দিন"</item>
     <item msgid="773943026484148895">"মিটারিং চালু রাখুন"</item>
-    <item msgid="1008268820118852416">"মিটারিং এর দরকার নেই"</item>
+    <item msgid="1008268820118852416">"মিটারিং বন্ধ রাখুন"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
-    <item msgid="6545683814310036454">"র‍্যান্ডমাইজ করা MAC (ডিফল্ট)"</item>
+    <item msgid="6545683814310036454">"র‍্যান্ডমাইজ করা MAC ব্যবহার করুন (ডিফল্ট)"</item>
     <item msgid="214234417308375326">"MAC ডিভাইস ব্যবহার করুন"</item>
   </string-array>
   <string-array name="wifi_hidden_entries">
diff --git a/tests/CarDeveloperOptions/res/values-bn/config.xml b/tests/CarDeveloperOptions/res/values-bn/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-bn/config.xml
+++ b/tests/CarDeveloperOptions/res/values-bn/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-bn/strings.xml b/tests/CarDeveloperOptions/res/values-bn/strings.xml
index 63d2cc7..2f6b1b5 100644
--- a/tests/CarDeveloperOptions/res/values-bn/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-bn/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"স্ক্রিনের টেক্সট ছোট বা বড় করুন।"</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"আরো ছোট করুন"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"আরো বড় করুন"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"স্যাম্পেল টেক্সট"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"দ্যা ওয়ান্ডারফুল উইজার্ড অফ অজ"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"অধ্যায় ১১: দ্যা ওয়ান্ডারফুল এমারল্ড সিটি অফ ওজ"</string>
@@ -128,7 +127,7 @@
     <string name="bluetooth_notif_title" msgid="5090288898529286011">"যুক্ত করার অনুরোধ"</string>
     <string name="bluetooth_notif_message" msgid="6612367890895077938">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> এর সঙ্গে যুক্ত করতে আলতো চাপুন৷"</string>
     <string name="bluetooth_show_received_files" msgid="5060846395852236652">"ফাইল গ্রহণ করা হয়েছে"</string>
-    <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"ব্লুটুথের মাধ্যমে পেয়ে থাকা ফাইল"</string>
+    <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"ব্লুটুথের মাধ্যমে পাওয়া ফাইল"</string>
     <string name="device_picker" msgid="8345264486071697705">"ব্লুটুথ ডিভাইস বাছুন"</string>
     <string name="bluetooth_ask_enablement" msgid="8716802066127746062">"<xliff:g id="APP_NAME">%1$s</xliff:g> ব্লুটুথ চালু করতে চাইছে"</string>
     <string name="bluetooth_ask_disablement" msgid="7125319551097350783">"<xliff:g id="APP_NAME">%1$s</xliff:g> ব্লুটুথ বন্ধ করতে চাইছে"</string>
@@ -668,7 +667,6 @@
       <item quantity="one">অবশ্যই <xliff:g id="NUMBER_1">%d</xliff:g>টি সংখ্যার থেকে কম হতে হবে</item>
       <item quantity="other">অবশ্যই <xliff:g id="NUMBER_1">%d</xliff:g>টি সংখ্যার থেকে কম হতে হবে</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"শুধুমাত্র ০-৯ সংখ্যাগুলি থাকবে"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"ডিভাইস প্রশাসক একটি সাম্প্রতিক পিন ব্যবহার করতে দেয় না"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"একইধরনের পিন আপনার আইটি অ্যাডমিনের মাধ্যমে ব্লক করা হয়। অন্য একটি পিন ব্যবহার করার চেষ্টা করুন।"</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"এতে কোনো অবৈধ অক্ষর অন্তর্ভুক্ত করা যাবে না"</string>
@@ -699,6 +697,10 @@
       <item quantity="one">কমপক্ষে এমন <xliff:g id="COUNT">%d</xliff:g>টি অক্ষর থাকতে হবে যেটি বর্ণ নয়</item>
       <item quantity="other">কমপক্ষে এমন <xliff:g id="COUNT">%d</xliff:g>টি অক্ষর থাকতে হবে যেটি বর্ণ নয়</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">কমপক্ষে এমন <xliff:g id="COUNT">%d</xliff:g>টি অক্ষর থাকতে হবে যেটি সংখ্যা নয়</item>
+      <item quantity="other">কমপক্ষে এমন <xliff:g id="COUNT">%d</xliff:g>টি অক্ষর থাকতে হবে যেটি সংখ্যা নয়</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"ডিভাইস প্রশাসক একটি সাম্প্রতিক পাসওয়ার্ড ব্যবহার করতে দেয় না"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"একইধরনের পাসওয়ার্ড আপনার আইটি অ্যাডমিনের মাধ্যমে ব্লক করা হয়। অন্য একটি পাসওয়ার্ড ব্যবহার করার চেষ্টা করুন।"</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"সংখ্যাগুলি ছোট থেকে বড় ক্রমে, বড় থেকে ছোট ক্রমে বা একই সংখ্যাকে বার বার লেখা যাবে না"</string>
@@ -710,7 +712,7 @@
     <string name="lockpattern_tutorial_continue_label" msgid="8474690922559443018">"পরবর্তী"</string>
     <string name="lock_setup" msgid="8710689848703935088">"সেটআপ সম্পূর্ণ।"</string>
     <string name="manage_device_admin" msgid="322047441168191695">"ডিভাইস প্রশাসক অ্যাপ"</string>
-    <string name="number_of_device_admins_none" msgid="8519193548630223132">"কোনো সক্রিয় অ্যাপ নেই"</string>
+    <string name="number_of_device_admins_none" msgid="8519193548630223132">"কোনও সক্রিয় অ্যাপ নেই"</string>
     <plurals name="number_of_device_admins" formatted="false" msgid="6445613288828151224">
       <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>টি অ্যাপ সক্রিয় আছে</item>
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>টি অ্যাপ সক্রিয় আছে</item>
@@ -886,7 +888,7 @@
     <string name="wifi_menu_remember" msgid="717257200269700641">"নেটওয়ার্ক মনে রাখুন"</string>
     <string name="wifi_menu_forget" msgid="7561140554450163075">"নেটওয়ার্ক ভুলে যান"</string>
     <string name="wifi_menu_modify" msgid="4080178040721021101">"নেটওয়ার্ক পরিবর্তন করুন"</string>
-    <string name="wifi_empty_list_wifi_off" msgid="272877164691346240">"উপলব্ধ নেটওয়ার্কগুলি দেখতে, ওয়াই-ফাই চালু করুন।"</string>
+    <string name="wifi_empty_list_wifi_off" msgid="272877164691346240">"উপলভ্য নেটওয়ার্কগুলি দেখতে, ওয়াই-ফাই চালু করুন।"</string>
     <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"ওয়াই-ফাই নেটওয়ার্কগুলির জন্য সার্চ করা হচ্ছে..."</string>
     <string name="wifi_empty_list_user_restricted" msgid="2341613007817352431">"ওয়াই-ফাই নেটওয়ার্ক পরিবর্তন করার অনুমতি আপনার নেই।"</string>
     <string name="wifi_more" msgid="3538241640407382185">"আরো"</string>
@@ -968,7 +970,7 @@
     <string name="wifi_unchanged" msgid="6804964646942333992">"(অপরিবর্তিত)"</string>
     <string name="wifi_unspecified" msgid="893491188483500809">"অনুগ্রহ করে বেছে নিন"</string>
     <string name="wifi_multiple_cert_added" msgid="7986200585749147204">"(একাধিক সার্টিফিকেট যোগ করা হয়েছে)"</string>
-    <string name="wifi_use_system_certs" msgid="4794489370929885022">"সিস্টেমের শংসাপত্রগুলি ব্যবহার করুন"</string>
+    <string name="wifi_use_system_certs" msgid="4794489370929885022">"সিস্টেমের সার্টিফিকেটগুলি ব্যবহার করুন"</string>
     <string name="wifi_do_not_provide_eap_user_cert" msgid="4044301449482425250">"প্রদান করবেন না"</string>
     <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"যাচাই করবেন না"</string>
     <string name="wifi_do_not_validate_eap_server_warning" msgid="3895397996759837323">"কোনও সার্টিফিকেট নির্দিষ্ট করা নেই৷ আপনার কানেকশন ব্যক্তিগত করা হবে না৷"</string>
@@ -1043,7 +1045,7 @@
     <string name="wifi_p2p_persist_network" msgid="1110453878886476660">"এই সংযোগটি মনে রাখুন"</string>
     <string name="wifi_p2p_menu_search" msgid="8207638860263805291">"ডিভাইসগুলির জন্য খুঁজুন"</string>
     <string name="wifi_p2p_menu_searching" msgid="7443249001543208106">"সার্চ করছে..."</string>
-    <string name="wifi_p2p_menu_rename" msgid="2129974878377065488">"ডিভাইস পুনঃনামকরণ করুন"</string>
+    <string name="wifi_p2p_menu_rename" msgid="2129974878377065488">"ডিভাইসের নাম পরিবর্তন করুন"</string>
     <string name="wifi_p2p_peer_devices" msgid="8232126067045093382">"পিয়ার ডিভাইসগুলি"</string>
     <string name="wifi_p2p_remembered_groups" msgid="1356458238836730346">"স্মরণ রাখা গোষ্ঠীসমূহ"</string>
     <string name="wifi_p2p_failed_connect_message" msgid="6103436959132424093">"কানেক্ট করা যায়নি৷"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"ওয়াই-ফাই"</item>
+    <item msgid="2271962426654621656">"মোবাইল"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"ওয়াই-ফাই উপলভ্য না থাকলে, মোবাইল নেটওয়ার্ক ব্যবহার করুন"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"মোবাইল নেটওয়ার্ক উপলভ্য না থাকলে, ওয়াই-ফাই ব্যবহার করুন"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"ওয়াই-ফাইয়ের মাধ্যমে কল করুন। ওয়াই-ফাই বিঘ্নিত হলে, কল বন্ধ হয়ে যাবে।"</string>
@@ -1521,8 +1526,8 @@
     <string name="storage_wizard_ready_v2_internal_moved_body" msgid="4133133596316768033">"আপনার কন্টেন্ট <xliff:g id="NAME_0">^1</xliff:g>-এ সরানো হয়েছে। \n\nএই <xliff:g id="NAME_1">^2</xliff:g>টি পরিচালনা করতে "<b>"সেটিংস &gt; স্টোরেজে"</b>" যান।"</string>
     <string name="battery_status_title" msgid="8731200319740671905">"ব্যাটারি স্থিতি"</string>
     <string name="battery_level_title" msgid="5207775387973771646">"ব্যাটারি স্তর"</string>
-    <string name="apn_settings" msgid="8130776653826271664">"APNগুলি"</string>
-    <string name="apn_edit" msgid="4350571070853305357">"অ্যাক্সেস পয়েন্ট সম্পাদনা করুন"</string>
+    <string name="apn_settings" msgid="8130776653826271664">"APN"</string>
+    <string name="apn_edit" msgid="4350571070853305357">"অ্যাক্সেস পয়েন্ট এডিট করুন"</string>
     <string name="apn_not_set" msgid="5344235604466825691">"সেট করা নেই"</string>
     <string name="apn_name" msgid="8431432886706852226">"নাম"</string>
     <string name="apn_apn" msgid="190519449579357696">"APN"</string>
@@ -1541,14 +1546,14 @@
     <string name="apn_auth_type_pap" msgid="6155876141679480864">"PAP"</string>
     <string name="apn_auth_type_chap" msgid="5484031368454788686">"CHAP"</string>
     <string name="apn_auth_type_pap_chap" msgid="2977833804460109203">"PAP বা CHAP"</string>
-    <string name="apn_type" msgid="6725346490902871146">"APN এর প্রকার"</string>
+    <string name="apn_type" msgid="6725346490902871146">"APN-এর প্রকার"</string>
     <string name="apn_protocol" msgid="1240197323563960912">"APN প্রোটোকল"</string>
     <string name="apn_roaming_protocol" msgid="6913336248771263497">"APN রোমিং প্রোটোকল"</string>
     <string name="carrier_enabled" msgid="1819916725305365581">"APN সক্ষম/অক্ষম করুন"</string>
     <string name="carrier_enabled_summaryOn" msgid="6219221535461945771">"APN সক্ষম"</string>
     <string name="carrier_enabled_summaryOff" msgid="4093019532796386622">"APN অক্ষম"</string>
     <string name="bearer" msgid="4378444317087536401">"বিয়ারার"</string>
-    <string name="mvno_type" msgid="3150755279048149624">"MVNO প্রকারের"</string>
+    <string name="mvno_type" msgid="3150755279048149624">"MVNO প্রকার"</string>
     <string name="mvno_match_data" msgid="629287305803195245">"MVNO মান"</string>
     <string name="menu_delete" msgid="8646081395424055735">"APN মুছে দিন"</string>
     <string name="menu_new" msgid="7529219814721969024">"নতুন APN"</string>
@@ -1562,8 +1567,8 @@
     <string name="error_adding_apn_type" msgid="671634520340569678">"পরিষেবা প্রদানকারী %s এর মতো APN যোগ করার অনুমতি দেয়নি।"</string>
     <string name="restore_default_apn" msgid="7195266404077471007">"ডিফল্ট APN সেটিংস পুনরুদ্ধার করা হচ্ছে।"</string>
     <string name="menu_restore" msgid="3799288817317293115">"ডিফল্টে রিসেট করুন"</string>
-    <string name="restore_default_apn_completed" msgid="5671734152740058937">"ডিফল্ট APN সেটিংস আবার সেট করা সম্পন্ন হয়েছে।"</string>
-    <string name="reset_dashboard_title" msgid="7084966342252178530">"রিসেটের বিকল্পগুলি"</string>
+    <string name="restore_default_apn_completed" msgid="5671734152740058937">"ডিফল্ট APN সেটিংস রিসেট করা হয়েছে।"</string>
+    <string name="reset_dashboard_title" msgid="7084966342252178530">"রিসেট করার বিকল্প"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"নেটওয়ার্ক, অ্যাপ, অথবা ডিভাইস রিসেট করা যায়"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"ওয়াই-ফাই, মোবাইল ও ব্লুটুথ রিসেট"</string>
     <string name="reset_network_desc" msgid="4982633363916261109">"এগুলি সহ সমস্ত নেটওয়ার্ক সেটিংস আবার সেট করবে:\n\n"<li>"ওয়াই ফাই "</li>\n<li>"সেলুলার ডাটা "</li>\n<li>"ব্লুটুথ"</li></string>
@@ -1786,7 +1791,7 @@
     <string name="applications_settings_header" msgid="3766501606045211098">"অ্যাপ সেটিংস"</string>
     <string name="install_applications" msgid="7745902974984889179">"অজানা উৎসগুলি"</string>
     <string name="install_applications_title" msgid="8164828577588659496">"সব অ্যাপ্লিকেশান উৎসকে অনুমতি দিন"</string>
-    <string name="recent_app_category_title" msgid="7688788038277126727">"সম্প্রতি চালু করা অ্যাপ"</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>
@@ -1967,7 +1972,7 @@
     <string name="show_ime" msgid="7322620473198763563">"ভার্চুয়াল কীবোর্ড দেখুন"</string>
     <string name="show_ime_summary" msgid="3246628154011464373">"ফিজিক্যাল কীবোর্ড সক্রিয় থাকার সময় এটিকে স্ক্রীনে রাখুন"</string>
     <string name="keyboard_shortcuts_helper" msgid="6574386807271399788">"কীবোর্ড শর্টকাট সাহায্যকারী"</string>
-    <string name="keyboard_shortcuts_helper_summary" msgid="8024313306403779742">"উপলব্ধ শর্টকাটগুলি দেখান"</string>
+    <string name="keyboard_shortcuts_helper_summary" msgid="8024313306403779742">"উপলভ্য শর্টকাটগুলি দেখান"</string>
     <string name="language_and_input_for_work_category_title" msgid="2053255944038892588">"অফিসের প্রোফাইলের কীবোর্ড ও টুল"</string>
     <string name="virtual_keyboards_for_work_title" msgid="3968291646938204523">"অফিসের জন্য ভার্চুয়াল কীবোর্ড"</string>
     <string name="default_keyboard_layout" msgid="9171704064451242230">"ডিফল্ট"</string>
@@ -2033,7 +2038,7 @@
     <string name="accessibility_settings_title" msgid="1687226556576913576">"সহজ ব্যবহার সেটিংস"</string>
     <string name="accessibility_settings_summary" msgid="5742379519336396561">"স্ক্রিন রিডার, ডিসপ্লে, ইন্টারঅ্যাকশন নিয়ন্ত্রণগুলি"</string>
     <string name="vision_settings_title" msgid="7315352351051423944">"দৃষ্টিশক্তি সেটিংস"</string>
-    <string name="vision_settings_description" msgid="3476589459009287332">"আপনি এই ডিভাইসটি নিজের পছন্দমত সেট করতে পারেন৷ এই অ্যাক্সেসযোগ্যতার বৈশিষ্ট্যগুলি পরে সেটিংসে গিয়ে পরিবর্তন করা যাবে৷"</string>
+    <string name="vision_settings_description" msgid="3476589459009287332">"আপনি এই ডিভাইসটি নিজের পছন্দমত সেট করতে পারেন৷ এই অ্যাক্সেসিবিলিটি বৈশিষ্ট্যগুলি পরে সেটিংসে গিয়ে পরিবর্তন করা যাবে৷"</string>
     <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"হরফের মাপ পরিবর্তন করুন"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"স্ক্রিন রিডার"</string>
     <string name="audio_and_captions_category_title" msgid="6140472938769619212">"অডিও এবং অন-স্ক্রিন পাঠ্য"</string>
@@ -2091,7 +2096,7 @@
     <string name="accessibility_ring_vibration_title" msgid="7943341443551359985">"রিং ভাইব্রেশন"</string>
     <string name="accessibility_touch_vibration_title" msgid="285890135612038092">"স্পর্শ করলে ভাইব্রেশন"</string>
     <string name="accessibility_service_master_switch_title" msgid="2734791644475782924">"পরিষেবা ব্যবহার করুন"</string>
-    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"কালার কারেকশন ব্যবহার করুন"</string>
+    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"রঙ সংশোধন ফিচারটি ব্যবহার করুন"</string>
     <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"ক্যাপশন ব্যবহার করুন"</string>
     <string name="accessibility_hearingaid_instruction_continue_button" msgid="4650111296711466691">"এগিয়ে যান"</string>
     <string name="accessibility_hearingaid_title" msgid="3700978781235124891">"হিয়ারিং এড"</string>
@@ -2666,7 +2671,7 @@
     <string name="data_usage_cellular_data_summary" msgid="9162777397135709280">"সীমায় পৌঁছে বিরতি দেওয়া হয়েছে"</string>
     <string name="account_settings_menu_auto_sync" msgid="2673669556006027506">"ডেটা স্বতঃসিঙ্ক"</string>
     <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"ব্যক্তিগত ডেটা স্বতঃসিঙ্ক"</string>
-    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"কার্যের ডাটা স্বতঃ সিঙ্ক"</string>
+    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"কাজের ডেটা নিজে থেকে সিঙ্ক"</string>
     <string name="data_usage_change_cycle" msgid="447761920472170031">"চক্র পরিবর্তন করুন..."</string>
     <string name="data_usage_pick_cycle_day" msgid="6319750879145917066">"ডেটা ব্যবহারের চক্র আবার সেট করতে মাসের দিন:"</string>
     <string name="data_usage_empty" msgid="7981405723435034032">"এই সময়ের মধ্যে কোনো অ্যাপ্লিকেশান ডেট ব্যবহার করবে না।"</string>
@@ -2897,12 +2902,12 @@
     <string name="user_exit_guest_confirm_title" msgid="4767911571671099844">"অতিথি সরাবেন?"</string>
     <string name="user_exit_guest_confirm_message" msgid="6955182181145748919">"এই সেশনের সব অ্যাপ্লিকেশান ও ডেটা মুছে ফেলা হবে।"</string>
     <string name="user_exit_guest_dialog_remove" msgid="1878866060881115716">"সরান"</string>
-    <string name="user_enable_calling" msgid="864760054792249503">"ফোন কলগুলিকে চালু করুন"</string>
-    <string name="user_enable_calling_sms" msgid="3450252891736718793">"ফোন কলগুলিকে এবং SMS চালু করবেন?"</string>
+    <string name="user_enable_calling" msgid="864760054792249503">"ফোন কলের সুবিধা চালু করুন"</string>
+    <string name="user_enable_calling_sms" msgid="3450252891736718793">"ফোন কল এবং এসএমএস চালু করবেন?"</string>
     <string name="user_remove_user" msgid="3687544420125911166">"ব্যবহারকারীর অ্যাকাউন্ট মুছে দিন"</string>
     <string name="user_enable_calling_confirm_title" msgid="1141612415529158542">"ফোন কলগুলিকে চালু করবেন?"</string>
     <string name="user_enable_calling_confirm_message" msgid="2490126715153125970">"কলের ইতিহাস এই ব্যবহারকারীর সাথে শেয়ার করা হবে।"</string>
-    <string name="user_enable_calling_and_sms_confirm_title" msgid="4153856398523366976">"ফোন কলগুলিকে এবং SMS চালু করবেন?"</string>
+    <string name="user_enable_calling_and_sms_confirm_title" msgid="4153856398523366976">"ফোন কল এবং এসএমএস চালু করবেন?"</string>
     <string name="user_enable_calling_and_sms_confirm_message" msgid="3278802798876095734">"কল ও SMS ইতিহাস এই ব্যবহারকারীর সাথে শেয়ার করা হবে।"</string>
     <string name="emergency_info_title" msgid="1522609271881425375">"জরুরি তথ্য"</string>
     <string name="emergency_info_summary" msgid="7280464759837387342">"<xliff:g id="USER_NAME">%1$s</xliff:g>-এর তথ্য ও পরিচিতি"</string>
@@ -2912,12 +2917,12 @@
     <string name="nfc_payment_settings_title" msgid="5070077706735415291">"ট্যাপ করে পে করা"</string>
     <string name="nfc_payment_how_it_works" msgid="7607901964687787177">"এটি কীভাবে কাজ করে"</string>
     <string name="nfc_payment_no_apps" msgid="8844440783395420860">"আপনার ফোন দিয়ে অর্থপ্রদান করুন"</string>
-    <string name="nfc_payment_default" msgid="7869273092463612271">"অর্থপ্রদান ডিফল্ট"</string>
+    <string name="nfc_payment_default" msgid="7869273092463612271">"পেমেন্ট ডিফল্ট"</string>
     <string name="nfc_payment_default_not_set" msgid="955804193510335338">"সেট করা নেই"</string>
     <string name="nfc_payment_app_and_desc" msgid="102312684211458190">"<xliff:g id="APP">%1$s</xliff:g> - <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="nfc_payment_use_default" msgid="3098724195746409476">"ডিফল্ট ব্যবহার করুন"</string>
     <string name="nfc_payment_favor_default" msgid="7555356982142464260">"সবসময়"</string>
-    <string name="nfc_payment_favor_open" msgid="3739055715000436749">"অন্য কোনো অর্থপ্রদান অ্যাপ্লিকেশান খুলে থাকার সময় ব্যতিত"</string>
+    <string name="nfc_payment_favor_open" msgid="3739055715000436749">"অন্য কোনও পেমেন্ট অ্যাপ খোলা না থাকলে"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"ট্যাপ করে অর্থপ্রদান করুন টার্মিন্যালে, এর মাধ্যমে পেমেন্ট করুন:"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"টার্মিনালে পেমেন্টের পদ্ধতি"</string>
     <string name="nfc_how_it_works_content" msgid="9174575836302449343">"একটি পেমেন্টের অ্যাপ্লিকেশান সেট-আপ করুন৷ তারপরে যোগাযোগহীন চিহ্ন সহ কোনো টার্মিনালের উপর শুধু আপনার ফোনের পিছনের দিকটি ধরুন৷"</string>
@@ -3036,7 +3041,7 @@
     <string name="connected_devices_dashboard_no_driving_mode_summary" msgid="3524409078596318803">"ব্লুটুথ, এনএফসি"</string>
     <string name="connected_devices_dashboard_no_driving_mode_no_nfc_summary" msgid="7881286613528299400">"ব্লুটুথ"</string>
     <string name="app_and_notification_dashboard_title" msgid="8448096608058843730">"অ্যাপ ও বিজ্ঞপ্তি"</string>
-    <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"অ্যাসিস্ট্যান্ট, সাম্প্রতিক অ্যাপ, ডিফল্ট অ্যাপ"</string>
+    <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"Assistant, সাম্প্রতিক অ্যাপ, ডিফল্ট অ্যাপ"</string>
     <string name="notification_settings_work_profile" msgid="7190550347842400029">"কাজের প্রোফাইলে অ্যাপের জন্য বিজ্ঞপ্তি অ্যাক্সেস উপলভ্য নয়।"</string>
     <string name="account_dashboard_title" msgid="4734300939532555885">"অ্যাকাউন্ট"</string>
     <string name="account_dashboard_default_summary" msgid="6822549669771936206">"কোনও অ্যাকাউন্ট যোগ করা হয়নি"</string>
@@ -3355,7 +3360,7 @@
     <string name="notifications_sent_daily" msgid="6874886521964822824">"দৈনিক ~<xliff:g id="NUMBER">%1$s</xliff:g>"</string>
     <string name="notifications_sent_weekly" msgid="5859675428990259432">"প্রতি সপ্তাহে ~<xliff:g id="NUMBER">%1$s</xliff:g>"</string>
     <string name="notifications_sent_never" msgid="237997329598144638">"কখনও না"</string>
-    <string name="manage_notification_access_title" msgid="5348743662189787547">"বিজ্ঞপ্তির অ্যাক্সেস"</string>
+    <string name="manage_notification_access_title" msgid="5348743662189787547">"বিজ্ঞপ্তি অ্যাক্সেস"</string>
     <string name="work_profile_notification_access_blocked_summary" msgid="8148871282484870576">"কর্মস্থলের প্রোফাইলের বিজ্ঞপ্তিতে অ্যাক্সেস ব্লক করা হয়েছে"</string>
     <string name="manage_notification_access_summary_zero" msgid="236809421271593016">"অ্যাপ্লিকেশানগুলি বিজ্ঞপ্তি পড়তে পারে না"</string>
     <plurals name="manage_notification_access_summary_nonzero" formatted="false" msgid="8496218948429646792">
@@ -3672,7 +3677,7 @@
     <string name="default_app" msgid="8861276008866619872">"(ডিফল্ট)"</string>
     <string name="system_app" msgid="4111402206594443265">"(সিস্টেম)"</string>
     <string name="system_default_app" msgid="1454719098589351197">"(সিস্টেম ডিফল্ট)"</string>
-    <string name="apps_storage" msgid="5658466038269046038">"অ্যাপ্লিকেশনের স্টোরেজ"</string>
+    <string name="apps_storage" msgid="5658466038269046038">"অ্যাপ স্টোরেজ"</string>
     <string name="usage_access" msgid="2023443456361489516">"ব্যবহারের তথ্যে অ্যাক্সেস"</string>
     <string name="permit_usage_access" msgid="3321727608629752758">"ব্যবহার অ্যাক্সেসের অনুমতি"</string>
     <string name="app_usage_preference" msgid="5691545073101551727">"পছন্দের অ্যাপ্লিকেশানগুলির ব্যবহার"</string>
@@ -3704,10 +3709,10 @@
     <string name="high_power_filter_on" msgid="5294209328473386403">"অপ্টিমাইজ করা নেই"</string>
     <string name="high_power_on" msgid="3573501822510580334">"অপ্টিমাইজ করা নেই"</string>
     <string name="high_power_off" msgid="5906679734326490426">"ব্যাটারির ব্যবহার অপ্টিমাইজ করা হচ্ছে"</string>
-    <string name="high_power_system" msgid="739584574711292753">"ব্যাটারি অপ্টিমাইজেশান উপলব্ধ নেই"</string>
+    <string name="high_power_system" msgid="739584574711292753">"ব্যাটারি অপ্টিমাইজেশান উপলভ্য নেই"</string>
     <string name="high_power_desc" msgid="333756885680362741">"ব্যাটারি অপ্টিমাইজেশান প্রয়োগ করবেন না। আরো দ্রুত আপনার ব্যাটারির চার্জ শেষ হয়ে যেতে পারে৷"</string>
     <string name="high_power_prompt_title" msgid="2805745781720454052">"অ্যাপটিকে সবসময় পটভূমিতে চালু রাখবেন?"</string>
-    <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g> কে সবসময় পটভূমিতে চালু রাখলে ব্যাটারির ক্ষমতা কমে যেতে পারে। \n\nআপনি পরে সেটিংস &gt; অ্যাপ্স ও বিজ্ঞপ্তি থেকে এটি পরিবর্তন করতে পারেন।"</string>
+    <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g>-কে সবসময় পটভূমিতে চালু রাখলে ব্যাটারি বেশিদিন নাও টিকতে পারে। \n\nআপনি পরে সেটিংস &gt; অ্যাপ ও বিজ্ঞপ্তি বিকল্প থেকে এটি পরিবর্তন করতে পারেন।"</string>
     <string name="battery_summary" msgid="4345690800899981339">"শেষ বার সম্পূর্ণ চার্জ করার পর থেকে <xliff:g id="PERCENTAGE">%1$s</xliff:g> ব্যবহার হয়েছে"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"শক্তি পরিচালনা"</string>
     <string name="no_battery_summary" msgid="4105932628367471314">"শেষ সম্পূর্ণ চার্জ করার সময় থেকে কোনো ব্যাটারি ব্যবহার করা হয়নি"</string>
@@ -4066,7 +4071,7 @@
     <string name="premium_sms_warning" msgid="7604011651486294515">"প্রিমিয়াম SMS এর জন্য অর্থ খরচ হতে পারে এবং আপনার পরিষেবা প্রদানকারীর বিলে যোগ করা হবে৷ আপনি যদি কোনো অ্যাপ্লিকেশানের জন্য অনুমতি সক্ষম করেন তাহলে আপনি সেই অ্যাপ্লিকেশানটি ব্যবহার করে প্রিমিয়াম SMS পাঠাতে পারবেন৷"</string>
     <string name="premium_sms_access" msgid="4550027460595822851">"প্রিমিয়াম SMS অ্যাক্সেস"</string>
     <string name="bluetooth_disabled" msgid="6588102116819268238">"বন্ধ আছে"</string>
-    <string name="bluetooth_connected_summary" msgid="439920840053965217">"<xliff:g id="ID_1">%1$s</xliff:g> এর সাথে কানেক্ট আছে"</string>
+    <string name="bluetooth_connected_summary" msgid="439920840053965217">"<xliff:g id="ID_1">%1$s</xliff:g>-এ কানেক্ট আছে"</string>
     <string name="bluetooth_connected_multiple_devices_summary" msgid="596205630653123250">"একাধিক ডিভাইসের সাথে কানেক্ট আছে"</string>
     <string name="demo_mode" msgid="3831081808592541104">"সিস্টেম UI ডেমো মোড"</string>
     <string name="dark_ui_mode" msgid="703844190192599217">"থিম"</string>
@@ -4150,7 +4155,7 @@
     <string name="instant_apps_settings" msgid="879003203555847537">"ঝটপট অ্যাপের পছন্দগুলি"</string>
     <string name="domain_url_section_title" msgid="206403507921518321">"ইনস্টল করা অ্যাপ"</string>
     <string name="automatic_storage_manager_activation_warning" msgid="2630083316417707308">"আপনার স্টোরেজ এখন স্টোরেজ ম্যানেজারের দ্বারা পরিচালিত হচ্ছে"</string>
-    <string name="account_for_section_header" msgid="5975241715840642563">"<xliff:g id="USER_NAME">%1$s</xliff:g> এর অ্যাকাউন্ট"</string>
+    <string name="account_for_section_header" msgid="5975241715840642563">"<xliff:g id="USER_NAME">%1$s</xliff:g>-এর অ্যাকাউন্ট"</string>
     <string name="configure_section_header" msgid="6988981883075615136">"কনফিগার"</string>
     <string name="auto_sync_account_title" msgid="2394463123733529506">"ডেটা অটোমেটিক সিঙ্ক হবে"</string>
     <string name="auto_sync_personal_account_title" msgid="6844465157916100655">"ব্যাক্তিগত ডেটা অটোমেটিক সিঙ্ক করুন"</string>
@@ -4233,8 +4238,8 @@
     <string name="storage_photos_videos" msgid="1890829312367477559">"ফটো এবং ভিডিওগুলি"</string>
     <string name="storage_music_audio" msgid="3661289086715297149">"মিউজিক ও অডিও"</string>
     <string name="storage_games" msgid="7740038143749092373">"গেম"</string>
-    <string name="storage_other_apps" msgid="3202407095387420842">"অন্যান্য অ্যাপ্লিকেশান"</string>
-    <string name="storage_files" msgid="2087824267937487880">"ফাইল"</string>
+    <string name="storage_other_apps" msgid="3202407095387420842">"অন্যান্য অ্যাপ"</string>
+    <string name="storage_files" msgid="2087824267937487880">"Files"</string>
     <string name="storage_size_large_alternate" msgid="1317796542509105857">"<xliff:g id="NUMBER">^1</xliff:g>"<small>" "<font size="20">"<xliff:g id="UNIT">^2</xliff:g>"</font></small>""</string>
     <string name="storage_volume_total" msgid="5021484171514159913">"<xliff:g id="TOTAL">%1$s</xliff:g> এর মধ্যে ব্যবহার হয়েছে"</string>
     <string name="storage_percent_full" msgid="6924662861545958442">"ব্যবহৃত"</string>
@@ -4320,7 +4325,7 @@
     <string name="battery_suggestion_summary" msgid="2669070349482656490"></string>
     <string name="gesture_prevent_ringing_screen_title" msgid="4173494225145223638">"রিং হওয়া বন্ধ করুন"</string>
     <string name="gesture_prevent_ringing_title" msgid="8827963588425673557">"রিং হওয়া বন্ধ করতে পাওয়ার ও ভলিউম বাড়ানোর বোতাম একসাথে প্রেস করুন"</string>
-    <string name="gesture_prevent_ringing_sound_title" msgid="8642330448721033641">"রিং হওয়া আটকানোর শর্টকাট"</string>
+    <string name="gesture_prevent_ringing_sound_title" msgid="8642330448721033641">"রিংয়ের আরওয়াজ আটকানোর শর্টকাট"</string>
     <string name="prevent_ringing_option_vibrate" msgid="6456505293904544108">"ভাইব্রেশন হতে দিন"</string>
     <string name="prevent_ringing_option_mute" msgid="53662688921253613">"মিউট করুন"</string>
     <string name="prevent_ringing_option_none" msgid="1450985763137666231">"যেমন আছে থাক"</string>
@@ -4422,7 +4427,7 @@
     <string name="preferred_network_mode_summary" msgid="388957154320426335">"নেটওয়ার্ক অপারেটিং মোড পরিবর্তন করুন"</string>
     <string name="preferred_network_mode_dialogtitle" msgid="5448698073828567428">"পছন্দের নেটওয়ার্ক"</string>
     <string name="carrier_settings_euicc" msgid="7723199738771996732">"পরিষেবা প্রদানকারী"</string>
-    <string name="carrier_settings_version" msgid="2657511289029828425">"সেটিংসের ভার্সন"</string>
+    <string name="carrier_settings_version" msgid="2657511289029828425">"সেটিংস ভার্সন"</string>
     <string name="call_category" msgid="3418535202893644015">"কল করা হচ্ছে"</string>
     <string name="video_calling_settings_title" msgid="8011841542502156112">"পরিষেবা প্রদানকারীর ভিডিও কলিং"</string>
     <string name="cdma_system_select_title" msgid="5620679296177526467">"সিস্টেমের বেছে নেওয়া"</string>
@@ -4468,7 +4473,7 @@
     <string name="privacy_dashboard_title" msgid="8764930992456607513">"গোপনীয়তা"</string>
     <string name="privacy_dashboard_summary" msgid="7916431309860824945">"অনুমতি, অ্যাকাউন্ট অ্যাক্টিভিটি, ব্যক্তিগত ডেটা"</string>
     <string name="contextual_card_dismiss_remove" msgid="1750420285615827309">"সরান"</string>
-    <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"রাখুন"</string>
+    <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"Keep"</string>
     <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"সাজেশনটি সরাতে চান?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"সাজেশন সরিয়ে দেওয়া হয়েছে"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"আগের অবস্থায় ফিরে যান"</string>
diff --git a/tests/CarDeveloperOptions/res/values-bs/arrays.xml b/tests/CarDeveloperOptions/res/values-bs/arrays.xml
index 1890771..220dbb9 100644
--- a/tests/CarDeveloperOptions/res/values-bs/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-bs/arrays.xml
@@ -85,7 +85,7 @@
     <item msgid="8058143476674427024">"Povezivanje na mrežu <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
     <item msgid="7547609081339573756">"Autentifikacija s mrežom <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
     <item msgid="5145158315060185414">"Dohvaćanje IP adrese s mreže <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
-    <item msgid="3283243151651124831">"Povezano na mrežu <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="3283243151651124831">"Povezano s mrežom <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
     <item msgid="6600156231416890902">"Suspendirano"</item>
     <item msgid="4133290864821295785">"Prekidanje veze s mrežom <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
     <item msgid="3980154971187953257">"Isključena"</item>
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"radi u pozadini"</item>
     <item msgid="6423861043647911030">"jačina zvuka za pristupačnost"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Lokacija"</item>
+    <item msgid="6656077694190491067">"Lokacija"</item>
+    <item msgid="8790228218278477369">"Lokacija"</item>
+    <item msgid="7836406246005211990">"Vibriranje"</item>
+    <item msgid="3951439024549922598">"Čitaj kontakte"</item>
+    <item msgid="8802152411647068">"Promijeni kontakte"</item>
+    <item msgid="229544934599698735">"Čitaj zapisnik poziva"</item>
+    <item msgid="7396102294405899613">"Promijeni zapisnik poziva"</item>
+    <item msgid="3597797992398484655">"Čitanje kalendara"</item>
+    <item msgid="2705975774250907343">"Promijeni kalendar"</item>
+    <item msgid="4668747371441932697">"Lokacija"</item>
+    <item msgid="1487578921720243646">"Objavi obavještenje"</item>
+    <item msgid="4636080349724146638">"Lokacija"</item>
+    <item msgid="673510900286463926">"Pozovi telefon"</item>
+    <item msgid="542083422784609790">"Pročitaj SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Piši SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Primi SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Primi SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Primi SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Primi SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Slanje SMS-a/MMS-a"</item>
+    <item msgid="4726682243833913568">"Pročitaj SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Piši SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Promijeni postavke"</item>
+    <item msgid="8705854389991425629">"Crtaj preko"</item>
+    <item msgid="5861356020344153651">"Pristup obavještenjima"</item>
+    <item msgid="78432174621628659">"Fotoaparat"</item>
+    <item msgid="3986116419882154794">"Snimi zvuk"</item>
+    <item msgid="4516840825756409490">"Reproduciraj zvuk"</item>
+    <item msgid="6811712502798183957">"Pročitaj sadržaj međumemorije"</item>
+    <item msgid="2780369012602289114">"Promijeni međumemoriju"</item>
+    <item msgid="2331359440170850868">"Dugmad za medije"</item>
+    <item msgid="6133599737122751231">"Audio fokus"</item>
+    <item msgid="6844485713404805301">"Centar za upravljanje zvukom"</item>
+    <item msgid="1600379420669104929">"Jačina glasa"</item>
+    <item msgid="6296768210470214866">"Jačina zvuka zvona"</item>
+    <item msgid="510690696071629241">"Jačina zvuka medija"</item>
+    <item msgid="406861638631430109">"Jačina zvuka alarma"</item>
+    <item msgid="4715864795872233884">"Jačina zvuka za obavještenja"</item>
+    <item msgid="2311478519251301183">"Jačina zvuka za Bluetooth vezu"</item>
+    <item msgid="5133991377896747027">"Drži aktivnim"</item>
+    <item msgid="2464189519136248621">"Lokacija"</item>
+    <item msgid="2062677934050803037">"Lokacija"</item>
+    <item msgid="1735171933192715957">"Preuzmi statistiku korištenja"</item>
+    <item msgid="1014093788778383554">"Isključi/uključi mikrofon"</item>
+    <item msgid="4199297950608622850">"Prikaži toast poruku"</item>
+    <item msgid="2527962435313398821">"Projektuj sadržaj medija"</item>
+    <item msgid="5117506254221861929">"Aktiviraj VPN"</item>
+    <item msgid="8291198322681891160">"Pozadinska slika za pisanje"</item>
+    <item msgid="7106921284621230961">"Asistent za podešavanje strukture"</item>
+    <item msgid="4496533640894624799">"Asistent za snimak ekrana"</item>
+    <item msgid="2598847264853993611">"Čitaj podatke o stanju telefona"</item>
+    <item msgid="9215610846802973353">"Dodaj govornu poštu"</item>
+    <item msgid="9186411956086478261">"Koristi SIP"</item>
+    <item msgid="6884763100104539558">"Procesiraj odlazni poziv"</item>
+    <item msgid="125513972170580692">"Otisak prsta"</item>
+    <item msgid="2556071024281275619">"Tjelesni senzori"</item>
+    <item msgid="617168514928339387">"Čita informacije info servisā"</item>
+    <item msgid="7134693570516523585">"Lažna lokacija"</item>
+    <item msgid="7224489175375229399">"Čitaj sadržaj pohrane"</item>
+    <item msgid="8472735063903258202">"Piši u pohranu"</item>
+    <item msgid="4069276819909595110">"Uključi ekran"</item>
+    <item msgid="1228338896751121025">"Pregledaj račune"</item>
+    <item msgid="3181581793459233672">"Radi u pozadini"</item>
+    <item msgid="2340936043025374076">"Jačina zvuka za pristupačnost"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Kratko"</item>
     <item msgid="4816511817309094890">"Srednja"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Nikada ne dozvoli"</item>
     <item msgid="8184570120217958741">"Uvijek dozvoli"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normalno"</item>
+    <item msgid="5101233285497327432">"Umjerena"</item>
+    <item msgid="1555861583162930714">"Nisko"</item>
+    <item msgid="1719683776264798117">"Kritična"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normalna"</item>
+    <item msgid="6107138933849816768">"Umjerena"</item>
+    <item msgid="182695359839047859">"Nisko"</item>
+    <item msgid="8577246509202964244">"Kritično"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Uporna"</item>
     <item msgid="167418068739176448">"Maksimalna aktivnost"</item>
@@ -377,9 +453,9 @@
     <item msgid="6248998242443333892">"Keširano (prazno)"</item>
   </string-array>
   <string-array name="color_picker">
-    <item msgid="3151827842194201728">"Teal"</item>
+    <item msgid="3151827842194201728">"Plavozelena"</item>
     <item msgid="3228505970082457852">"Plava"</item>
-    <item msgid="6590260735734795647">"Indigo"</item>
+    <item msgid="6590260735734795647">"Indigoplava"</item>
     <item msgid="3521763377357218577">"Ljubičasta"</item>
     <item msgid="5932337981182999919">"Ružičasta"</item>
     <item msgid="5642914536624000094">"Crvena"</item>
diff --git a/tests/CarDeveloperOptions/res/values-bs/config.xml b/tests/CarDeveloperOptions/res/values-bs/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-bs/config.xml
+++ b/tests/CarDeveloperOptions/res/values-bs/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-bs/strings.xml b/tests/CarDeveloperOptions/res/values-bs/strings.xml
index ab18137..0028e39 100644
--- a/tests/CarDeveloperOptions/res/values-bs/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-bs/strings.xml
@@ -84,8 +84,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Smanjite ili povećajte tekst na ekranu."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Napravi manji"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Napravi veći"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Uzorak teksta"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Čarobnjak iz Oza"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Poglavlje 11: Smaragdni grad Oz"</string>
@@ -366,9 +365,9 @@
     <string name="owner_info_settings_summary" msgid="4208702251226725583">"Ništa"</string>
     <string name="owner_info_settings_status" msgid="8049975536717685126">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="COUNT_1">%2$d</xliff:g>"</string>
     <string name="owner_info_settings_edit_text_hint" msgid="2250029417257939706">"Npr. Edinov Android."</string>
-    <string name="user_info_settings_title" msgid="1125111518759995748">"Podaci o korisniku"</string>
+    <string name="user_info_settings_title" msgid="1125111518759995748">"Informacije o korisniku"</string>
     <string name="show_profile_info_on_lockscreen_label" msgid="5204282771893683026">"Prikazuj informacije o profilu na zaključ. ekranu"</string>
-    <string name="profile_info_settings_title" msgid="4855892878512562551">"Podaci o profilu"</string>
+    <string name="profile_info_settings_title" msgid="4855892878512562551">"Informacije o profilu"</string>
     <string name="Accounts_settings_title" msgid="7901374987121953746">"Računi"</string>
     <string name="location_settings_title" msgid="2707201457572301030">"Lokacija"</string>
     <string name="location_settings_master_switch_title" msgid="3108016866082816733">"Koristi lokaciju"</string>
@@ -445,8 +444,8 @@
     <string name="security_settings_fingerprint_enroll_introduction_title" msgid="889558002683900544">"Otključavanje otiskom prsta"</string>
     <string name="security_settings_fingerprint_enroll_introduction_title_unlock_disabled" msgid="7915504118657864429">"Koristite otisak prsta"</string>
     <string name="security_settings_fingerprint_enroll_introduction_message" msgid="5586198131986682472">"Samo dodirnite senzor za otisak prsta da otključate telefon, odobrite kupovinu ili da se prijavite u aplikaciju. Pazite čije otiske prsta dodajete. Samo jedan dodani otisak može izvršiti sve navedeno.\n\nNapomena: Vaš otisak prsta može biti manje siguran od jakog uzorka ili PIN-a."</string>
-    <string name="security_settings_fingerprint_enroll_introduction_message_unlock_disabled" msgid="1640839304679275468">"Pomoću otiska prsta otključavajte telefon ili odobravajte kupovinu.\n\nNapomena: otisak prsta ne možete koristiti za otključavanje ovog uređaja. Za više informacija, obratite se administratoru svoje organizacije"</string>
-    <string name="security_settings_fingerprint_enroll_introduction_message_setup" msgid="6734490666593320711">"Pomoću otiska prsta otključavajte telefon ili odobravajte kupovinu.\n\nNapomena: otisak vašeg prsta može biti manje siguran od jakog uzorka ili PIN-a."</string>
+    <string name="security_settings_fingerprint_enroll_introduction_message_unlock_disabled" msgid="1640839304679275468">"Koristite otisak prsta da otključate telefon ili odobrite kupovinu.\n\nNapomena: otisak prsta ne možete koristiti za otključavanje ovog uređaja. Za više informacija, obratite se administratoru svoje organizacije"</string>
+    <string name="security_settings_fingerprint_enroll_introduction_message_setup" msgid="6734490666593320711">"Koristite otisak prsta da otključate telefon ili odobrite kupovinu.\n\nNapomena: otisak vašeg prsta može biti manje siguran od jakog uzorka ili PIN-a."</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel" msgid="9168637333731599827">"Otkaži"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue" msgid="271662150372486535">"Nastavi"</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel_setup" msgid="756928427429893070">"Preskoči"</string>
@@ -676,7 +675,6 @@
       <item quantity="few">Ukupan broj cifara mora biti manji od <xliff:g id="NUMBER_1">%d</xliff:g></item>
       <item quantity="other">Ukupan broj cifara mora biti manji od <xliff:g id="NUMBER_1">%d</xliff:g></item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Mora sadržavati isključivo cifre 0-9."</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Administrator uređaja ne dozvoljava korištenje nedavnog PIN-a"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Vaš IT administrator je blokirao česte PIN kôdove. Probajte drugi PIN kôd."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Ne može sadržavati nevažeći znak"</string>
@@ -713,6 +711,11 @@
       <item quantity="few">Mora sadržavati najmanje <xliff:g id="COUNT">%d</xliff:g> znaka koja nisu slova</item>
       <item quantity="other">Mora sadržavati najmanje <xliff:g id="COUNT">%d</xliff:g> znakova koji nisu slova</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">Mora sadržavati najmanje <xliff:g id="COUNT">%d</xliff:g> znak koji nije broj</item>
+      <item quantity="few">Mora sadržavati najmanje <xliff:g id="COUNT">%d</xliff:g> znaka koja nisu brojevi</item>
+      <item quantity="other">Mora sadržavati najmanje <xliff:g id="COUNT">%d</xliff:g> znakova koji nisu brojevi</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Administrator uređaja ne dozvoljava korištenje nedavne lozinke"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Vaš IT administrator je blokirao česte lozinke. Probajte drugu lozinku."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Nije dozvoljen rastući, opadajući ili ponavljajući niz cifara"</string>
@@ -731,7 +734,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> aktivnih aplikacija</item>
     </plurals>
     <string name="manage_trust_agents" msgid="8129970926213142261">"Pouzdani agenti"</string>
-    <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"Da ovo koristite, prvo postavite zaključavanje ekrana"</string>
+    <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"Da biste ovo koristili, prvo postavite zaključavanje ekrana"</string>
     <string name="manage_trust_agents_summary" msgid="2023116850759962248">"Nema"</string>
     <plurals name="manage_trust_agents_summary_on" formatted="false" msgid="5550538038916606097">
       <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> aktivni pouzdani agent</item>
@@ -743,7 +746,7 @@
     <string name="bluetooth_settings" msgid="5228032727293770389">"Bluetooth"</string>
     <string name="bluetooth_settings_title" msgid="7261244857456521825">"Bluetooth"</string>
     <string name="bluetooth_settings_summary" msgid="1221689092429277887">"Upravljajte vezama, postavite ime uređaja i vidljivost"</string>
-    <string name="bluetooth_pairing_request" msgid="7221745525632573125">"Upariti sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>?"</string>
+    <string name="bluetooth_pairing_request" msgid="7221745525632573125">"Upariti s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>?"</string>
     <string name="bluetooth_pairing_key_msg" msgid="1139230917419961975">"Kod za Bluetooth uparivanje"</string>
     <string name="bluetooth_enter_passkey_msg" msgid="6205151011298670207">"Upišite kod za uparivanje, zatim pritisnite Return ili Enter"</string>
     <string name="bluetooth_enable_alphanumeric_pin" msgid="9138308197078115672">"PIN sadrži slova ili simbole"</string>
@@ -765,7 +768,7 @@
     <string name="bluetooth_preference_paired_dialog_internet_option" msgid="3693599743477470469">"Internet veza"</string>
     <string name="bluetooth_preference_paired_dialog_keyboard_option" msgid="4627309436489645755">"Tastatura"</string>
     <string name="bluetooth_preference_paired_dialog_contacts_option" msgid="5290994459307558039">"Kontakti i historija poziva"</string>
-    <string name="bluetooth_pairing_dialog_title" msgid="7900515495932064945">"Upariti sa ovim uređajem?"</string>
+    <string name="bluetooth_pairing_dialog_title" msgid="7900515495932064945">"Upariti s ovim uređajem?"</string>
     <string name="bluetooth_pairing_dialog_sharing_phonebook_title" msgid="7395493311980018460">"Podijeliti telefonski imenik?"</string>
     <string name="bluetooth_pairing_dialog_contants_request" msgid="2103132762434487717">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> želi pristupiti vašim kontaktima i historiji poziva."</string>
     <string name="bluetooth_pairing_dialog_paring_request" msgid="5513953935086446387">"Uređaj <xliff:g id="DEVICE_NAME">%1$s</xliff:g> želi uparivanje putem Bluetootha. Nakon povezivanja imat će pristup vašim kontaktima i historiji poziva."</string>
@@ -840,7 +843,7 @@
     <string name="nfc_disclaimer_title" msgid="4860231267351602970">"Uključite NFC"</string>
     <string name="nfc_disclaimer_content" msgid="3066113577854565782">"NFC razmjenjuje podatke između ovog i drugih uređaja ili ciljeva u blizini, kao što su terminali za plaćanje, čitači pristupa i interaktivni oglasi ili oznake."</string>
     <string name="nfc_secure_settings_title" msgid="5153751163174916581">"Osiguraj NFC"</string>
-    <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"Dozvoli NFC plaćanje i korištenje u javnom prijevozu samo kada je ekran otključan"</string>
+    <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"Dozvoli korištenje NFC-a za plaćanje i u javnom prijevozu samo kada je ekran otključan"</string>
     <string name="android_beam_settings_title" msgid="3083436415873738389">"Android Beam"</string>
     <string name="android_beam_on_summary" msgid="8068287225180474199">"Spremno za prijenos sadržaja aplikacije putem NFC-a"</string>
     <string name="android_beam_off_summary" msgid="7365818039159364600">"Isključeno"</string>
@@ -875,7 +878,7 @@
     <string name="use_open_wifi_automatically_summary_scoring_disabled" msgid="1559329344492373028">"Za korištenje funkcije odaberite ocjenjivača mreže"</string>
     <string name="use_open_wifi_automatically_summary_scorer_unsupported_disabled" msgid="1123080670578756834">"Za korištenje funkcije odaberite kompatibilnog ocjenjivača mreže"</string>
     <string name="wifi_install_credentials" msgid="5650088113710858289">"Instaliranje certifikata"</string>
-    <string name="wifi_scan_notify_text" msgid="7614101215028336927">"Kako bi poboljšale preciznost lokacije, aplikacije i usluge mogu i dalje uvijek skenirati WiFi mreže, čak i kada je WiFi isključen. Ovim se, naprimjer, mogu poboljšati funkcije i usluge zasnovane na lokaciji. Ovo možete izmijeniti u <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>postavkama skeniranja<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
+    <string name="wifi_scan_notify_text" msgid="7614101215028336927">"Kako bi poboljšale preciznost lokacije, aplikacije i usluge i dalje mogu skenirati WiFi mreže bilo kada, čak i kada je WiFi isključen. Ovim se, naprimjer, mogu poboljšati funkcije i usluge zasnovane na lokaciji. Ovo možete izmijeniti u <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>postavkama skeniranja<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
     <string name="wifi_scan_notify_text_scanning_off" msgid="723796963816095410">"Radi poboljšanja preciznosti lociranja, uključite skeniranje WiFi mreža u <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>postavkama skeniranja<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
     <string name="wifi_scan_notify_remember_choice" msgid="1235445971400237444">"Ne prikazuj ponovo"</string>
     <string name="wifi_setting_sleep_policy_title" msgid="2120785188625932076">"Zadrži WiFi uključenim tokom mirovanja"</string>
@@ -950,7 +953,7 @@
     <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"Nasumično odabrani MAC"</string>
     <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"Dodajte uređaj"</string>
     <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"Centrirajte QR kôd ispod da uređaj dodate na mrežu “<xliff:g id="SSID">%1$s</xliff:g>”"</string>
-    <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"Skeniraj QR kôd"</string>
+    <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"Skenirajte QR kôd"</string>
     <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"Centrirajte QR kôd ispod da se povežete na mrežu “<xliff:g id="SSID">%1$s</xliff:g>”"</string>
     <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"Skenirajte QR kôd da se pridružite WiFi mreži"</string>
     <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Dijeljenje WiFi mreže"</string>
@@ -1117,7 +1120,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"WiFi"</item>
+    <item msgid="2271962426654621656">"Mobilna mreža"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Ako WiFi nije dostupan, koristi mobilnu mrežu"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Ako mobilna mreža nije dostupna, koristi WiFi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Pozivanje putem WiFi-ja. Ako se izgubi WiFi, poziv će se prekinuti."</string>
@@ -1125,7 +1131,7 @@
     <string name="wifi_calling_off_explanation_2" msgid="8648609693875720408"></string>
     <string name="emergency_address_title" msgid="5779915349686787024">"Adresa za hitne slučajeve"</string>
     <string name="emergency_address_summary" msgid="478668478569851714">"Koristi se kao vaša lokacija prilikom hitnog poziva putem Wi‑Fi mreže"</string>
-    <string name="private_dns_help_message" msgid="7633526525131196650"><annotation id="url">"Saznajte više"</annotation>" o funkcijama Privatnog DNS-a"</string>
+    <string name="private_dns_help_message" msgid="7633526525131196650"><annotation id="url">"Saznajte više"</annotation>" o funkcijama privatnog DNS-a"</string>
     <string name="wifi_calling_pref_managed_by_carrier" msgid="5458050015417972072">"Postavkom upravlja mobilni operater"</string>
     <string name="wifi_calling_settings_activation_instructions" msgid="2863642668648110908">"Aktivirajte pozivanje putem WiFi-ja"</string>
     <string name="wifi_calling_turn_on" msgid="1212277809455062043">"Uključite pozivanje putem WiFi-ja"</string>
@@ -1278,7 +1284,7 @@
     <string name="doze_always_on_title" msgid="8555184965031789941">"Uvijek uključeno"</string>
     <string name="doze_always_on_summary" msgid="7654436900436328950">"Prikaz vremena, ikona obavještenja i drugih informacija. Veća potrošnja baterije."</string>
     <string name="title_font_size" msgid="5021464556860010851">"Veličina fonta"</string>
-    <string name="short_summary_font_size" msgid="4141077908728522946">"Povećavanje ili umanjivanje teksta"</string>
+    <string name="short_summary_font_size" msgid="4141077908728522946">"Povećajte ili smanjite tekst"</string>
     <string name="sim_lock_settings" msgid="1986924650622642189">"Postavke zaključavanja SIM kartice"</string>
     <string name="sim_lock_settings_category" msgid="1126759898277681516">"Zaključavanje SIM kartice"</string>
     <string name="sim_lock_settings_summary_off" msgid="348656447968142307">"Isključeno"</string>
@@ -1430,7 +1436,7 @@
     <string name="storage_menu_forget" msgid="4345021250834642640">"Zaboraviti"</string>
     <string name="storage_menu_set_up" msgid="2849170579745958513">"Postavi"</string>
     <string name="storage_menu_explore" msgid="3733439525636202662">"Istraži"</string>
-    <string name="storage_menu_free" msgid="6586253660759145508">"Oslobodi prostor"</string>
+    <string name="storage_menu_free" msgid="6586253660759145508">"Oslobodite prostor"</string>
     <string name="storage_menu_manage" msgid="461380717863926516">"Upravljaj prostorom za pohranu"</string>
     <string name="storage_title_usb" msgid="2015671467177303099">"Veza s računarom preko USB-a"</string>
     <string name="usb_connection_category" msgid="2888975803638116041">"Poveži kao"</string>
@@ -1542,7 +1548,7 @@
     <string name="apn_settings" msgid="8130776653826271664">"APN-ovi"</string>
     <string name="apn_edit" msgid="4350571070853305357">"Uredi pristupnu tačku"</string>
     <string name="apn_not_set" msgid="5344235604466825691">"Nije postavljeno"</string>
-    <string name="apn_name" msgid="8431432886706852226">"Ime"</string>
+    <string name="apn_name" msgid="8431432886706852226">"Naziv"</string>
     <string name="apn_apn" msgid="190519449579357696">"APN"</string>
     <string name="apn_http_proxy" msgid="8816906767987944465">"Proksi"</string>
     <string name="apn_http_port" msgid="5789193688960075486">"Priključak"</string>
@@ -1560,8 +1566,8 @@
     <string name="apn_auth_type_chap" msgid="5484031368454788686">"CHAP"</string>
     <string name="apn_auth_type_pap_chap" msgid="2977833804460109203">"PAP ili CHAP"</string>
     <string name="apn_type" msgid="6725346490902871146">"Vrsta APN-a"</string>
-    <string name="apn_protocol" msgid="1240197323563960912">"APN protokol"</string>
-    <string name="apn_roaming_protocol" msgid="6913336248771263497">"Protokol za APN roming"</string>
+    <string name="apn_protocol" msgid="1240197323563960912">"Protokol APN-a"</string>
+    <string name="apn_roaming_protocol" msgid="6913336248771263497">"Protokol APN-a za roming"</string>
     <string name="carrier_enabled" msgid="1819916725305365581">"Omogući/onemogući APN"</string>
     <string name="carrier_enabled_summaryOn" msgid="6219221535461945771">"APN omogućen"</string>
     <string name="carrier_enabled_summaryOff" msgid="4093019532796386622">"APN onemogućen"</string>
@@ -1580,7 +1586,7 @@
     <string name="error_adding_apn_type" msgid="671634520340569678">"Operater ne dozvoljava dodavanje APN-a tipa %s."</string>
     <string name="restore_default_apn" msgid="7195266404077471007">"Vraćanje zadanih postavki za APN."</string>
     <string name="menu_restore" msgid="3799288817317293115">"Vrati na zadano"</string>
-    <string name="restore_default_apn_completed" msgid="5671734152740058937">"Vraćanje zadanih postavki za APN dovršeno."</string>
+    <string name="restore_default_apn_completed" msgid="5671734152740058937">"Vraćanje zadanih postavki za APN je završeno."</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"Opcije vraćanja na zadano"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"Mreža, aplikacije ili uređaj mogu se vratiti na zadano"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"Vrati WiFi, mobilnu i Bluetooth vezu na zadano"</string>
@@ -1599,7 +1605,7 @@
     <string name="master_clear_title" msgid="1560712943955904673">"Izbriši sve podatke (vraćanje na fabričke postavke)"</string>
     <string name="master_clear_short_title" msgid="919098101581335101">"Potpuno izbriši sve podatke"</string>
     <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"Na ovaj način će se izbrisati svi podaci "<b>"interne memorije"</b>" tableta, uključujući:\n\n"<li>"Google račun"</li>\n<li>"sistemske i aplikacijske podatke i postavke"</li>\n<li>"preuzete aplikacije"</li></string>
-    <string name="master_clear_desc" product="default" msgid="8765543541962866697">"Na ovaj način će se izbrisati svi podaci "<b>"interne memorije"</b>" telefona, uključujući:\n\n"<li>"Google račun"</li>\n<li>"sistemske i aplikacijske podatke i postavke"</li>\n<li>"preuzete aplikacije"</li></string>
+    <string name="master_clear_desc" product="default" msgid="8765543541962866697">"Na ovaj način će se izbrisati svi podaci "<b>"interne memorije"</b>" telefona, uključujući:\n\n"<li>"vaš Google račun"</li>\n<li>"podatke i postavke sistema i aplikacija"</li>\n<li>"preuzete aplikacije"</li></string>
     <string name="master_clear_accounts" product="default" msgid="3432884235445405376">\n\n"Trenutno ste prijavljeni u sljedeće račune:\n"</string>
     <string name="master_clear_other_users_present" product="default" msgid="5993259656117566767">\n\n"Drugi korisnici su prisutni na ovom uređaju.\n"</string>
     <string name="master_clear_desc_also_erases_external" msgid="3947303501615091903"><li>"muziku"</li>\n<li>"fotografije"</li>\n<li>"ostale korisničke podatke"</li></string>
@@ -1660,7 +1666,7 @@
     <string name="mobile_insert_sim_card" msgid="7594550403454243732">"Umetnite SIM karticu i ponovo pokrenite uređaj"</string>
     <string name="mobile_connect_to_internet" msgid="6031886097365170913">"Povežite se na Internet"</string>
     <string name="location_title" msgid="8664674161765477168">"Moja lokacija"</string>
-    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"Lokacija za profil za Work"</string>
+    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"Lokacija za poslovni profil"</string>
     <string name="location_app_level_permissions" msgid="1298041503927632960">"Odobrenje za aplikaciju"</string>
     <string name="location_app_permission_summary_location_off" msgid="541372845344796336">"Lokacija je isključena"</string>
     <plurals name="location_app_permission_summary_location_on" formatted="false" msgid="7904821382328758218">
@@ -1676,9 +1682,9 @@
     <string name="location_low_battery_use" msgid="5030448574501435888">"Niska potrošnja baterije"</string>
     <string name="location_scanning_screen_title" msgid="7663329319689413454">"Skeniranje WiFi-ja i Bluetootha"</string>
     <string name="location_scanning_wifi_always_scanning_title" msgid="6750542206763112172">"Skeniranje WiFi mreže"</string>
-    <string name="location_scanning_wifi_always_scanning_description" msgid="4956048135941851712">"Dozvolite aplikacijama i uslugama da skeniraju WiFi mreže u svakom trenutku, čak i kada je WiFi mreža isključena. Ovim se naprimjer mogu poboljšati funkcije i usluge zasnovane na lokaciji."</string>
+    <string name="location_scanning_wifi_always_scanning_description" msgid="4956048135941851712">"Dozvolite aplikacijama i uslugama da skeniraju WiFi mreže u svakom trenutku, čak i kada je WiFi mreža isključena. Ovim se, naprimjer, mogu poboljšati funkcije i usluge zasnovane na lokaciji."</string>
     <string name="location_scanning_bluetooth_always_scanning_title" msgid="196241746742607453">"Skeniranje Bluetootha"</string>
-    <string name="location_scanning_bluetooth_always_scanning_description" msgid="3796673798637848690">"Dozvolite aplikacijama i uslugama da skeniraju uređaje u blizini u svakom trenutku, čak i kada je Bluetooth isključen. Ovim se naprimjer mogu poboljšati funkcije i usluge zasnovane na lokaciji."</string>
+    <string name="location_scanning_bluetooth_always_scanning_description" msgid="3796673798637848690">"Dozvolite aplikacijama i uslugama da skeniraju uređaje u blizini u svakom trenutku, čak i kada je Bluetooth isključen. Ovim se, naprimjer, mogu poboljšati funkcije i usluge zasnovane na lokaciji."</string>
     <string name="managed_profile_location_services" msgid="224925483299159541">"Usluge lokacije za posao"</string>
     <string name="location_network_based" msgid="1535812159327454835">"Lokacija Wi-Fi i mob. mreža"</string>
     <string name="location_neighborhood_level" msgid="8459352741296587916">"Omogućava da aplikacije koriste Googleovu uslugu lokacije kako bi brže procijenile vašu lokaciju. Anonimni podaci o lokaciji se prikupljaju i šalju Googleu."</string>
@@ -2183,7 +2189,7 @@
     <string name="captioning_edge_color" msgid="4330622137047993780">"Boja rubova"</string>
     <string name="captioning_edge_type" msgid="4414946407430588162">"Vrsta rubova"</string>
     <string name="captioning_typeface" msgid="7893208796949341767">"Porodica fontova"</string>
-    <string name="captioning_preview_text" msgid="4877753964772618049">"Stilovi će izgledati ovako"</string>
+    <string name="captioning_preview_text" msgid="4877753964772618049">"Titlovi će izgledati ovako"</string>
     <string name="captioning_preview_characters" msgid="6469599599352973561">"Aa"</string>
     <string name="locale_default" msgid="910074908458214054">"Zadano"</string>
     <string name="color_title" msgid="132875486061816584">"Boja"</string>
@@ -2301,13 +2307,13 @@
     <string name="battery_tip_smart_battery_title" product="device" msgid="7419448992583346364">"Poboljšajte vijek trajanja baterije uređaja"</string>
     <string name="battery_tip_smart_battery_summary" msgid="5344821856478265778">"Uključite Upravitelja baterije"</string>
     <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Uključite Uštedu baterije"</string>
-    <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Baterija bi vam se mogla isprazniti prije nego obično"</string>
+    <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Baterija bi vam se mogla isprazniti brže nego obično"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Uključena je Ušteda baterije"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Neke funkcije mogu biti ograničene"</string>
     <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Koristili ste telefon više nego obično"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"Koristili ste tablet više nego obično"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"Koristili ste uređaj više nego obično"</string>
-    <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"Moguće je da će se baterija isprazniti brže nego obično"</string>
+    <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"Baterija bi vam se mogla isprazniti brže nego obično"</string>
     <string name="battery_tip_dialog_message" product="default" msgid="8453700079047810964">"Vaš telefon je korišten više nego obično. Baterija se može istrošiti brže nego što je predviđeno.\n\nNajviše korištene aplikacije od potpunog punjenja:"</string>
     <string name="battery_tip_dialog_message" product="tablet" msgid="6489981050645444068">"Vaš tablet je korišten više nego obično. Baterija se može istrošiti brže nego što je predviđeno.\n\nNajviše korištene aplikacije od potpunog punjenja:"</string>
     <string name="battery_tip_dialog_message" product="device" msgid="6348123094674390337">"Vaš uređaj je korišten više nego obično. Baterija se može istrošiti brže nego što je predviđeno.\n\nNajviše korištene aplikacije od potpunog punjenja:"</string>
@@ -2341,13 +2347,13 @@
     <string name="battery_tip_restrict_apps_less_than_5_dialog_message" msgid="4225881888543582456">"Da uštedite bateriju, spriječite ove aplikacije da koriste bateriju u pozadini. Moguće je da aplikacije s ograničenjem neće raditi pravilno i da će obavještenja kasniti.\n\nAplikacije:"</string>
     <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"Da uštedite bateriju, spriječite ove aplikacije da koriste bateriju u pozadini. Moguće je da aplikacije s ograničenjem neće raditi pravilno i da će obavještenja kasniti.\n\nAplikacije:\n<xliff:g id="APP_LIST">%1$s</xliff:g>."</string>
     <string name="battery_tip_restrict_app_dialog_ok" msgid="2573410775701913487">"Ograniči"</string>
-    <string name="battery_tip_unrestrict_app_dialog_title" msgid="812458516399125710">"Želite ukloniti ograničenje?"</string>
+    <string name="battery_tip_unrestrict_app_dialog_title" msgid="812458516399125710">"Ukloniti ograničenje?"</string>
     <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"Ova aplikacija će moći koristiti bateriju u pozadini. Vaša baterija bi se mogla isprazniti prije nego što očekujete."</string>
     <string name="battery_tip_unrestrict_app_dialog_ok" msgid="9154938931448151479">"Ukloni"</string>
     <string name="battery_tip_unrestrict_app_dialog_cancel" msgid="7331148618292397166">"Otkaži"</string>
-    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"Vaše aplikacije troše bateriju uobičajenom brzinom. Ako prebrzo troše bateriju, telefon će predložiti radnje koje možete preduzeti.\n\nUvijek možete uključiti Uštedu baterije ako je baterija skoro prazna."</string>
-    <string name="battery_tip_dialog_summary_message" product="tablet" msgid="1721081030632329647">"Vaše aplikacije troše bateriju uobičajenom brzinom. Ako prebrzo troše bateriju, tablet će predložiti radnje koje možete preduzeti.\n\nUvijek možete uključiti Uštedu baterije ako je baterija skoro prazna."</string>
-    <string name="battery_tip_dialog_summary_message" product="device" msgid="146872407040848465">"Vaše aplikacije troše bateriju uobičajenom brzinom. Ako prebrzo troše bateriju, uređaj će predložiti radnje koje možete preduzeti.\n\nUvijek možete uključiti Uštedu baterije ako je baterija skoro prazna."</string>
+    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"Vaše aplikacije troše bateriju uobičajenom brzinom. Ako aplikacije budu prebrzo trošile bateriju, telefon će predložiti radnje koje možete preduzeti.\n\nUvijek možete uključiti Uštedu baterije ako je baterija skoro prazna."</string>
+    <string name="battery_tip_dialog_summary_message" product="tablet" msgid="1721081030632329647">"Vaše aplikacije troše bateriju uobičajenom brzinom. Ako aplikacije budu prebrzo trošile bateriju, tablet će predložiti radnje koje možete preduzeti.\n\nUvijek možete uključiti Uštedu baterije ako je baterija skoro prazna."</string>
+    <string name="battery_tip_dialog_summary_message" product="device" msgid="146872407040848465">"Vaše aplikacije troše bateriju uobičajenom brzinom. Ako aplikacije budu prebrzo trošile bateriju, uređaj će predložiti radnje koje možete preduzeti.\n\nUvijek možete uključiti Uštedu baterije ako je baterija skoro prazna."</string>
     <string name="smart_battery_manager_title" msgid="5744035036663849515">"Upravitelj baterije"</string>
     <string name="smart_battery_title" msgid="4919670408532804351">"Automatsko upravljanje aplikacijama"</string>
     <string name="smart_battery_summary" msgid="640027046471198174">"Ograničite upotrebu baterije za aplikacije koje ne koristite često"</string>
@@ -2769,7 +2775,7 @@
     <string name="data_usage_disclaimer" msgid="4683321532922590425">"Obračun podataka operatera može se razlikovati od obračuna vašeg uređaja."</string>
     <string name="cryptkeeper_emergency_call" msgid="4625420047524693116">"Poziv za hitne slučajeve"</string>
     <string name="cryptkeeper_return_to_call" msgid="4433942821196822815">"Vrati se na poziv"</string>
-    <string name="vpn_name" msgid="3538818658670774080">"Ime"</string>
+    <string name="vpn_name" msgid="3538818658670774080">"Naziv"</string>
     <string name="vpn_type" msgid="6389116710008658550">"Vrsta"</string>
     <string name="vpn_server" msgid="5216559017318406820">"Adresa servera"</string>
     <string name="vpn_mppe" msgid="4027660356538086985">"PPP šifriranje (MPPE)"</string>
@@ -2819,15 +2825,15 @@
     <string name="vpn_create" msgid="2477570636472897359">"Dodaj VPN profil"</string>
     <string name="vpn_menu_edit" msgid="8061437799373333593">"Uredi profil"</string>
     <string name="vpn_menu_delete" msgid="4128305800374946877">"Izbriši profil"</string>
-    <string name="vpn_menu_lockdown" msgid="6951452279924808089">"Uvijek aktivni VPN"</string>
-    <string name="vpn_no_vpns_added" msgid="6616183541896197147">"Nema dodanih VPN-ova"</string>
+    <string name="vpn_menu_lockdown" msgid="6951452279924808089">"Uvijek aktivan VPN"</string>
+    <string name="vpn_no_vpns_added" msgid="6616183541896197147">"Nije dodan nijedan VPN"</string>
     <string name="vpn_always_on_summary" msgid="3639994551631437397">"Ostanite stalno povezani na VPN"</string>
     <string name="vpn_always_on_summary_not_supported" msgid="9077720997795965133">"Ova aplikacija ne podržava ovu funkciju"</string>
     <string name="vpn_always_on_summary_active" msgid="8962619701962239088">"Funkcija Uvijek uključeno je aktivna"</string>
     <string name="vpn_require_connection" msgid="5413746839457797350">"Blokiraj veze bez VPN-a"</string>
     <string name="vpn_require_connection_title" msgid="8361434328767853717">"Treba li zahtijevati VPN vezu?"</string>
     <string name="vpn_lockdown_summary" msgid="6770030025737770861">"Odaberite VPN profil s kojim će uvijek biti uspostavljena veza. Mrežni saobraćaj će biti dopušten samo kad je uspostavljena veza s tim VPN-om."</string>
-    <string name="vpn_lockdown_none" msgid="3789288793603394679">"Nema"</string>
+    <string name="vpn_lockdown_none" msgid="3789288793603394679">"Ništa"</string>
     <string name="vpn_lockdown_config_error" msgid="8761770968704589885">"Uvijek aktivni VPN zahtijeva IP adresu i za server i za DNS."</string>
     <string name="vpn_no_network" msgid="8313250136194588023">"Nema mrežne veze. Pokušajte ponovo kasnije."</string>
     <string name="vpn_disconnected" msgid="4597953053220332539">"Isključeni ste iz VPN-a"</string>
@@ -2849,7 +2855,7 @@
     <string name="n_cacrts" msgid="7539893176217891549">"%d CA certifikati"</string>
     <string name="user_credential_title" msgid="6237611303219831419">"Detalji o akreditivima"</string>
     <string name="user_credential_removed" msgid="6243576567538844852">"Uklonjeni akreditiv: <xliff:g id="CREDENTIAL_NAME">%s</xliff:g>"</string>
-    <string name="user_credential_none_installed" msgid="4129252817676332368">"Nisu instalirani korisnički akreditivi"</string>
+    <string name="user_credential_none_installed" msgid="4129252817676332368">"Nije instaliran nijedan korisnički akreditiv"</string>
     <string name="spellcheckers_settings_title" msgid="1687210427248364327">"Provjera pravopisa"</string>
     <string name="spellcheckers_settings_for_work_title" msgid="7461318390801573022">"Provjera pravopisa za posao"</string>
     <string name="current_backup_pw_prompt" msgid="8914812770233159610">"Ovdje unesite trenutnu lozinku za sigurnosnu kopiju čitavog sistema"</string>
@@ -2904,7 +2910,7 @@
     <string name="user_add_user_item_title" msgid="6835385073795492410">"Korisnik"</string>
     <string name="user_add_profile_item_title" msgid="4932743891449790664">"Ograničeni profil"</string>
     <string name="user_add_user_title" msgid="2320897397066676472">"Dodati novog korisnika?"</string>
-    <string name="user_add_user_message_long" msgid="686637203224195465">"Za dijeljenje ovog uređaja s drugima možete napraviti dodatne korisnike. Svaki korisnik ima svoj prostor koji može prilagoditi pomoću aplikacija, pozadinske slike i slično. Korisnici također mogu prilagoditi postavke uređaja koje utiču na sve ostale korisnike, kao što je WiFi.\n\nKada dodate novog korisnika, ta osoba treba postaviti svoj prostor.\n\nSvaki korisnik može ažurirati aplikacije za sve ostale korisnike. Postavke i usluge pristupačnosti možda se neće prenijeti na novog korisnika."</string>
+    <string name="user_add_user_message_long" msgid="686637203224195465">"Ovaj uređaj možete dijeliti s drugima ako napravite dodatne korisnike. Svaki korisnik ima svoj prostor koji može prilagoditi pomoću aplikacija, pozadinske slike i slično. Korisnici također mogu prilagoditi postavke uređaja koje utiču na sve ostale korisnike, kao što je WiFi.\n\nKada dodate novog korisnika, ta osoba treba postaviti svoj prostor.\n\nSvaki korisnik može ažurirati aplikacije za sve ostale korisnike. Postavke i usluge pristupačnosti možda se neće prenijeti na novog korisnika."</string>
     <string name="user_add_user_message_short" msgid="1802594476285458254">"Kada dodate novog korisnika, ta osoba treba postaviti svoj prostor. \n\n Svaki korisnik može ažurirati aplikacije za sve ostale korisnike."</string>
     <string name="user_setup_dialog_title" msgid="6748950002206392396">"Postaviti korisnika sada?"</string>
     <string name="user_setup_dialog_message" msgid="2988559933258353919">"Provjerite može li osoba uzeti uređaj i postaviti svoj prostor"</string>
@@ -2937,8 +2943,8 @@
     <string name="user_exit_guest_confirm_message" msgid="6955182181145748919">"Sve aplikacije i podaci iz ove sesije će biti izbrisani."</string>
     <string name="user_exit_guest_dialog_remove" msgid="1878866060881115716">"Ukloniti"</string>
     <string name="user_enable_calling" msgid="864760054792249503">"Uključi telefonske pozive"</string>
-    <string name="user_enable_calling_sms" msgid="3450252891736718793">"Uključivanje telefonskih poziva i SMS-ova"</string>
-    <string name="user_remove_user" msgid="3687544420125911166">"Brisanje korisnika"</string>
+    <string name="user_enable_calling_sms" msgid="3450252891736718793">"Uključi telefonske pozive i SMS-ove"</string>
+    <string name="user_remove_user" msgid="3687544420125911166">"Izbriši korisnika"</string>
     <string name="user_enable_calling_confirm_title" msgid="1141612415529158542">"Uključiti telefonske pozive?"</string>
     <string name="user_enable_calling_confirm_message" msgid="2490126715153125970">"Historija poziva će se dijeliti s ovim korisnikom."</string>
     <string name="user_enable_calling_and_sms_confirm_title" msgid="4153856398523366976">"Uključiti telefonske pozive i SMS-ove?"</string>
@@ -2954,12 +2960,12 @@
     <string name="nfc_payment_default" msgid="7869273092463612271">"Zadana aplikacija za plaćanje"</string>
     <string name="nfc_payment_default_not_set" msgid="955804193510335338">"Nije postavljeno"</string>
     <string name="nfc_payment_app_and_desc" msgid="102312684211458190">"<xliff:g id="APP">%1$s</xliff:g> – <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
-    <string name="nfc_payment_use_default" msgid="3098724195746409476">"Koristiti zadanu aplikaciju"</string>
+    <string name="nfc_payment_use_default" msgid="3098724195746409476">"Koristi zadanu aplikaciju"</string>
     <string name="nfc_payment_favor_default" msgid="7555356982142464260">"Uvijek"</string>
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Osim kada je otvorena druga aplikacija za plaćanje"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"Na terminalu \"Dodirni i plati\" plaćajte pomoću:"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Plaćanje na terminalu"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Postavite aplikaciju za plaćanje, zatim jednostavno prislonite poleđinu svog telefona uz bilo koji terminal označen simbolom beskontaktne komunikacije."</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Postavite aplikaciju za plaćanje, zatim jednostavno prislonite poleđinu svog telefona uz bilo koji terminal označen simbolom beskontaktnog povezivanja."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"Razumijem"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"Više..."</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"Želite li da ga postavite kao željeni izbor?"</string>
@@ -2985,7 +2991,7 @@
     <string name="call_manager_title" msgid="1118074011469650421">"Upravitelj za pozive"</string>
     <!-- no translation found for call_manager_summary (1232655174841493040) -->
     <skip />
-    <string name="cell_broadcast_settings" msgid="5750066270993255966">"Poruke upozorenja"</string>
+    <string name="cell_broadcast_settings" msgid="5750066270993255966">"Hitna upozorenja"</string>
     <string name="network_operators_settings" msgid="7822337582828465633">"Mrežni operateri"</string>
     <string name="access_point_names" msgid="7992382237358800596">"Nazivi pristupnih tačaka"</string>
     <string name="enhanced_4g_lte_mode_title" msgid="1624079276378568594">"VoLTE"</string>
@@ -2993,7 +2999,7 @@
     <string name="enhanced_4g_lte_mode_title_4g_calling" msgid="1262729135500839141">"Pozivanje putem 4G mreže"</string>
     <string name="enhanced_4g_lte_mode_summary" msgid="4515503153340557170">"Koristite LTE usluge za poboljšanje glasovne i drugih komunikacija (preporučeno)"</string>
     <string name="enhanced_4g_lte_mode_summary_4g_calling" msgid="1006226172299077404">"Koristi usluge 4G mreže za poboljšanje glasovne i drugih komunikacija (preporučeno)"</string>
-    <string name="preferred_network_type_title" msgid="1980819233332592332">"Tip preferirane mreže"</string>
+    <string name="preferred_network_type_title" msgid="1980819233332592332">"Preferirana vrsta mreže"</string>
     <string name="preferred_network_type_summary" msgid="8828375904939960006">"LTE (preporučeno)"</string>
     <string name="work_sim_title" msgid="2885654516046971985">"SIM za Work"</string>
     <string name="user_restrictions_title" msgid="6454305007320972740">"Aplikacija i pristup sadržaju"</string>
@@ -3184,9 +3190,9 @@
     <string name="other_sound_settings" msgid="5250376066099818676">"Drugi zvukovi"</string>
     <string name="dial_pad_tones_title" msgid="8877212139988655769">"Tonovi tastature telefona"</string>
     <string name="screen_locking_sounds_title" msgid="4407110895465866809">"Zvukovi zaključavanja ekrana"</string>
-    <string name="charging_sounds_title" msgid="5070437987230894287">"Zvukovi/vibracija pri punjenju"</string>
+    <string name="charging_sounds_title" msgid="5070437987230894287">"Zvukovi/vibracija prilikom punjenja"</string>
     <string name="docking_sounds_title" msgid="2573137471605541366">"Zvukovi priključne stanice"</string>
-    <string name="touch_sounds_title" msgid="165237488496165652">"Zvukovi pri dodiru"</string>
+    <string name="touch_sounds_title" msgid="165237488496165652">"Zvukovi dodira"</string>
     <string name="vibrate_on_touch_title" msgid="6360155469279157684">"Vibracija pri dodiru"</string>
     <string name="vibrate_on_touch_summary" msgid="5504424764028676043">"Haptičke povratne informacije za dodir, tastaturu i drugo"</string>
     <string name="dock_audio_media_title" msgid="1859521680502040781">"Zvučnik priključne stanice reprodukuje zvuk"</string>
@@ -3196,7 +3202,7 @@
     <string name="emergency_tone_alert" msgid="907868135091891015">"Tonovi"</string>
     <string name="emergency_tone_vibrate" msgid="5020068066905681181">"Vibracije"</string>
     <string name="boot_sounds_title" msgid="7583926202411353620">"Uključivanje zvukova"</string>
-    <string name="live_caption_title" msgid="7926591158657997051">"Titlovanje uživo"</string>
+    <string name="live_caption_title" msgid="7926591158657997051">"Automatski titlovi"</string>
     <string name="live_caption_summary" msgid="9064771862352393125">"Automatski titluj medije"</string>
     <string name="zen_mode_settings_summary_off" msgid="6929319200478424962">"Nikada"</string>
     <plurals name="zen_mode_settings_summary_on" formatted="false" msgid="6061723291126091396">
@@ -3230,7 +3236,7 @@
     <string name="zen_mode_summary_combination" msgid="6960111215170691605">"<xliff:g id="MODE">%1$s</xliff:g>: <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
     <string name="zen_mode_visual_interruptions_settings_title" msgid="8378266552787406849">"Blokiranje vizuelnih ometanja"</string>
     <string name="zen_mode_visual_signals_settings_subtitle" msgid="6608239691864638854">"Dozvolite vizualnu signalizaciju"</string>
-    <string name="zen_mode_settings_category" msgid="5601680733422424922">"Kada je uključen način rada Ne ometaj"</string>
+    <string name="zen_mode_settings_category" msgid="5601680733422424922">"Kada je uključena funkcija Ne ometaj"</string>
     <string name="zen_mode_restrict_notifications_title" msgid="7486753018073540477">"Ograničite obavještenja"</string>
     <string name="zen_mode_restrict_notifications_mute" msgid="2673665450311184875">"Obavještenja bez zvuka"</string>
     <string name="zen_mode_restrict_notifications_mute_summary" msgid="1696217042353376674">"Obavještenja ćete vidjeti na ekranu"</string>
@@ -3251,8 +3257,8 @@
     <string name="zen_mode_block_effect_intent" msgid="5666951244667422668">"Nemoj uključivati ekran"</string>
     <string name="zen_mode_block_effect_light" msgid="8679333758037487644">"Nemoj bljeskati"</string>
     <string name="zen_mode_block_effect_peek" msgid="6075662813575910221">"Nemoj isticati obavještenja na ekranu"</string>
-    <string name="zen_mode_block_effect_status" msgid="6516614225115681068">"Sakrij ikone stat. trake u vrhu ekrana"</string>
-    <string name="zen_mode_block_effect_badge" msgid="3891743027347075136">"Sakrij tačke za obavj. na ikonama apl."</string>
+    <string name="zen_mode_block_effect_status" msgid="6516614225115681068">"Sakrij ikone statusne trake na vrhu ekrana"</string>
+    <string name="zen_mode_block_effect_badge" msgid="3891743027347075136">"Sakrij tačke za obavještenja na ikonama aplikacija"</string>
     <string name="zen_mode_block_effect_ambient" msgid="6382013125863616197">"Nemoj buditi zbog obavještenja"</string>
     <string name="zen_mode_block_effect_list" msgid="6081548478844912181">"Sakrij s liste obavještenja"</string>
     <string name="zen_mode_block_effect_summary_none" msgid="7166175186759564510">"Nikada"</string>
@@ -3261,7 +3267,7 @@
     <string name="zen_mode_block_effect_summary_sound" msgid="4907185880913861880">"Zvuk i vibracija"</string>
     <string name="zen_mode_block_effect_summary_some" msgid="6035118904496072665">"Zvuk, vibracija i neki vizuelni znakovi obavještenja"</string>
     <string name="zen_mode_block_effect_summary_all" msgid="2830443565687247759">"Zvuk, vibracija i vizuelni znakovi obavještenja"</string>
-    <string name="zen_mode_blocked_effects_footer" msgid="4375156159613413924">"Obavještenja koja su potrebna za osnovne radnje i status telefona nikada se neće sakriti"</string>
+    <string name="zen_mode_blocked_effects_footer" msgid="4375156159613413924">"Obavještenja koja su potrebna za osnovne radnje i status telefona se nikada neće sakriti"</string>
     <string name="zen_mode_no_exceptions" msgid="3099578343994492857">"Ništa"</string>
     <string name="zen_mode_other_options" msgid="7216192179063769057">"druge opcije"</string>
     <string name="zen_mode_add" msgid="2533484377786927366">"Dodaj"</string>
@@ -3269,7 +3275,7 @@
     <string name="zen_mode_button_turn_on" msgid="1097964136225943415">"Uključi sada"</string>
     <string name="zen_mode_button_turn_off" msgid="3990967728457149454">"Isključi sada"</string>
     <string name="zen_mode_settings_dnd_manual_end_time" msgid="4307574188962071429">"Način rada Ne ometaj će biti uključen do <xliff:g id="FORMATTED_TIME">%s</xliff:g>"</string>
-    <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"Način rada Ne ometaj će biti uključen dok ga ne isključite"</string>
+    <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"Funkcija Ne ometaj će biti uključena dok je ne isključite"</string>
     <string name="zen_mode_settings_dnd_automatic_rule" msgid="2843297614114625408">"Način rada Ne ometaj je automatski uključen na osnovu rasporeda (<xliff:g id="RULE_NAME">%s</xliff:g>)"</string>
     <string name="zen_mode_settings_dnd_automatic_rule_app" msgid="5103454923160912313">"Način rada Ne ometaj je automatski uključila aplikacija (<xliff:g id="APP_NAME">%s</xliff:g>)"</string>
     <string name="zen_mode_settings_dnd_custom_settings_footer" msgid="6335108298640066560">"Način rada Ne ometaj je uključen za <xliff:g id="RULE_NAMES">%s</xliff:g> zajedno sa zadanim postavkama."</string>
@@ -3464,8 +3470,8 @@
     <string name="notification_content_block_summary" msgid="2743896875255591743">"Nikad ne prikazuj obavještenja u nijansi ili na perifernim uređajima"</string>
     <string name="notification_badge_title" msgid="8989086619255666442">"Dozvoli tačku za obavještenja"</string>
     <string name="notification_channel_badge_title" msgid="8228215248332054612">"Prikaži tačku za obavještenja"</string>
-    <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"Zamijeni način rada Ne ometaj"</string>
-    <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"Dozvolite da se obavještenja nastave pojavljivati kada je uključen način rada Ne ometaj"</string>
+    <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"Zanemari način rada Ne ometaj"</string>
+    <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"Dozvoli da se obavještenja nastave pojavljivati kada je uključen način rada Ne ometaj"</string>
     <string name="app_notification_visibility_override_title" msgid="2349335170165637672">"Na zaključavanju ekrana"</string>
     <string name="app_notification_row_banned" msgid="2079325338122151677">"Blokirano"</string>
     <string name="app_notification_row_priority" msgid="432299064888787236">"Prioritetna"</string>
@@ -3547,7 +3553,7 @@
     <string name="zen_mode_media" msgid="3701280649874724055">"Reproduciraj zvukove medija"</string>
     <string name="zen_mode_media_list" msgid="509327580522287125">"mediji"</string>
     <string name="zen_mode_system" msgid="597437265986355038">"Dozvoli zvukove dodira"</string>
-    <string name="zen_mode_system_list" msgid="480192458506838077">"zvuci dodira"</string>
+    <string name="zen_mode_system_list" msgid="480192458506838077">"zvukovi dodira"</string>
     <string name="zen_mode_reminders" msgid="7560664194610054038">"Dozvoli podsjetnike"</string>
     <string name="zen_mode_reminders_list" msgid="7347061314032326677">"podsjetnici"</string>
     <string name="zen_mode_events" msgid="5784076928339534984">"Dozvoli događaje"</string>
@@ -3747,7 +3753,7 @@
     <string name="process_format" msgid="8575347150598564509">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="COUNT">%2$d</xliff:g>)"</string>
     <string name="high_power_apps" msgid="2518319744362028920">"Optimizacija baterije"</string>
     <string name="additional_battery_info" msgid="6877663897819271203">"Obavještenja o upotrebi"</string>
-    <string name="show_all_apps" msgid="5442552004569634846">"Prikaži potpuno korištenje uređaja"</string>
+    <string name="show_all_apps" msgid="5442552004569634846">"Prikaži korištenje cijelog uređaja"</string>
     <string name="hide_extra_apps" msgid="6798261081113299441">"Prikaži korištenje aplikacije"</string>
     <plurals name="power_high_usage_summary" formatted="false" msgid="4658343710126205199">
       <item quantity="one"><xliff:g id="NUMBER">%2$d</xliff:g> aplikacija se ne ponaša kako treba</item>
@@ -3885,7 +3891,7 @@
     <string name="camera_double_tap_power_gesture_title" msgid="8874747801078147525">"Dva pritiska na napajanje za kameru"</string>
     <string name="camera_double_tap_power_gesture_desc" msgid="6166349645433682873">"Brzo otvaranje fotoaparata bez otključavanja ekrana"</string>
     <string name="screen_zoom_title" msgid="164369086350486104">"Veličina prikaza"</string>
-    <string name="screen_zoom_short_summary" msgid="5508079362742276703">"Povećavanje ili umanjivanje objekata na ekranu"</string>
+    <string name="screen_zoom_short_summary" msgid="5508079362742276703">"Povećajte ili smanjite stavke na ekranu"</string>
     <string name="screen_zoom_keywords" msgid="8358462497896524092">"gustoća prikaza, uvećanje ekrana, promijeni veličinu, mijenjanje veličine"</string>
     <string name="screen_zoom_summary" msgid="5294003755961312560">"Smanjite ili povećajte stavke na ekranu. Neke aplikacije s vašeg ekrana mogu promijeniti svoj položaj."</string>
     <string name="screen_zoom_preview_title" msgid="2924312934036753091">"Pregled"</string>
@@ -3992,14 +3998,14 @@
     <string name="usage" msgid="9172908720164431622">"Potrošnja"</string>
     <string name="cellular_data_usage" msgid="1236562234207782386">"Prijenos podataka na mobilnoj mreži"</string>
     <string name="app_cellular_data_usage" msgid="8499761516172121957">"Prijenos podataka u aplikaciji"</string>
-    <string name="wifi_data_usage" msgid="275569900562265895">"Potrošnja WiFi podataka"</string>
+    <string name="wifi_data_usage" msgid="275569900562265895">"Prijenos podataka putem WiFi-ja"</string>
     <string name="ethernet_data_usage" msgid="747614925362556718">"Prijenos podataka putem Etherneta"</string>
     <string name="wifi" msgid="1586738489862966138">"WiFi"</string>
     <string name="ethernet" msgid="2365753635113154667">"Ethernet"</string>
     <string name="cell_data_template" msgid="5473177306229738078">"<xliff:g id="AMOUNT">^1</xliff:g> putem prijenosa podataka"</string>
     <string name="wifi_data_template" msgid="3146090439147042068">"<xliff:g id="AMOUNT">^1</xliff:g> WiFi podataka"</string>
     <string name="ethernet_data_template" msgid="6414118030827090119">"<xliff:g id="AMOUNT">^1</xliff:g> ethernet podataka"</string>
-    <string name="billing_cycle" msgid="5740717948341713190">"Upozorenje o podacima i ograničenje"</string>
+    <string name="billing_cycle" msgid="5740717948341713190">"Upozorenje o prijenosu pod. i ograničenje"</string>
     <string name="app_usage_cycle" msgid="213483325132959663">"Ciklus prijenosa podataka u aplikaciji"</string>
     <string name="cell_data_warning" msgid="8902740337286652689">"Upozorenje o prijenosu podataka: <xliff:g id="ID_1">^1</xliff:g>"</string>
     <string name="cell_data_limit" msgid="3175933829235314233">"Ograničenje prijenosa podataka: <xliff:g id="ID_1">^1</xliff:g>"</string>
@@ -4013,18 +4019,18 @@
     </plurals>
     <string name="operator_warning" msgid="4676042739221117031">"Obračun podataka koji vrši operater se može razlikovati od obračuna koji vrši uređaj."</string>
     <string name="data_used_template" msgid="761605393453849477">"Iskorišteno je <xliff:g id="ID_1">%1$s</xliff:g>"</string>
-    <string name="set_data_warning" msgid="8115980184415563941">"Postavi upozorenje o potrošnji"</string>
-    <string name="data_warning" msgid="2699207195535036240">"Upozorenje o podacima"</string>
+    <string name="set_data_warning" msgid="8115980184415563941">"Postavi upozor. o prij. podat."</string>
+    <string name="data_warning" msgid="2699207195535036240">"Upozorenje o prijenosu podataka"</string>
     <string name="data_warning_footnote" msgid="965724845580257305">"Uređaj mjeri upozorenje o prijenosu podataka i ograničenje prijenosa podataka. Ovo se može razlikovati od prijenosa podataka kojeg je izmjerio mobilni operater."</string>
-    <string name="set_data_limit" msgid="5043770023229990674">"Postavi ograničenje potrošnje"</string>
+    <string name="set_data_limit" msgid="5043770023229990674">"Postavi ogranič. prij. podat."</string>
     <string name="data_limit" msgid="5793521160051596228">"Ograničenje prijenosa podataka"</string>
     <string name="data_usage_template" msgid="6848274347956096882">"<xliff:g id="ID_1">%1$s</xliff:g> iskorišteno <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="configure" msgid="8232696842838580549">"Konfiguracija"</string>
     <string name="data_usage_other_apps" msgid="7002491980141402084">"Ostale aplikacije uključene u korištenje"</string>
     <plurals name="data_saver_unrestricted_summary" formatted="false" msgid="6046013861315713697">
-      <item quantity="one"><xliff:g id="COUNT">%1$d</xliff:g> aplikacija smije upotrebljavati neograničen prijenos podataka kada je Ušteda podataka uključena</item>
-      <item quantity="few"><xliff:g id="COUNT">%1$d</xliff:g> aplikacije smiju upotrebljavati neograničen prijenos podataka kada je Ušteda podataka uključena</item>
-      <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> aplikacija smije upotrebljavati neograničen prijenos podataka kada je Ušteda podataka uključena</item>
+      <item quantity="one"><xliff:g id="COUNT">%1$d</xliff:g> aplikacija smije upotrebljavati neograničen prijenos podataka kada je uključena Ušteda podataka</item>
+      <item quantity="few"><xliff:g id="COUNT">%1$d</xliff:g> aplikacije smiju upotrebljavati neograničen prijenos podataka kada je uključena Ušteda podataka</item>
+      <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> aplikacija smije upotrebljavati neograničen prijenos podataka kada je uključena Ušteda podataka</item>
     </plurals>
     <string name="data_usage_title" msgid="7874606430902201083">"Primarni plan prijenosa podataka"</string>
     <string name="data_usage_wifi_title" msgid="7161828479387766556">"Wi‑Fi podaci"</string>
@@ -4052,7 +4058,7 @@
     <string name="data_saver_off" msgid="7439439787358504018">"Isključeno"</string>
     <string name="data_saver_switch_title" msgid="8244008132112735207">"Koristi funkciju Ušteda podataka"</string>
     <string name="unrestricted_app_title" msgid="4390661122069905122">"Neograničen prijenos podataka"</string>
-    <string name="unrestricted_app_summary" msgid="2829141815077800483">"Dozvolite neograničen pristup podacima kada je Ušteda podataka uključena"</string>
+    <string name="unrestricted_app_summary" msgid="2829141815077800483">"Dozvolite neograničen pristup podacima kada je uključena Ušteda podataka"</string>
     <string name="home_app" msgid="3695063566006954160">"Aplikacija na početnom ekranu"</string>
     <string name="no_default_home" msgid="1518949210961918497">"Nema zadane početne aplikacije"</string>
     <string name="lockpattern_settings_require_cred_before_startup" msgid="63693894094570367">"Sigurno pokretanje"</string>
@@ -4214,7 +4220,7 @@
     <string name="oem_lock_info_message" msgid="5090850412279403901">"Ponovo pokrenite uređaj da omogućite funkciju zaštite uređaja."</string>
     <string name="automatic_storage_manager_freed_bytes" msgid="7360443072390107772">"<xliff:g id="SIZE">%1$s</xliff:g> je ukupno na raspolaganju\n\nPosljednji put je pokrenuto <xliff:g id="DATE">%2$s</xliff:g>"</string>
     <string name="web_action_enable_title" msgid="4462106633708675959">"Instant aplikacije"</string>
-    <string name="web_action_enable_summary" msgid="1729016644691793085">"Otvaranje linkova u aplikacijama, čak iako nisu instalirane"</string>
+    <string name="web_action_enable_summary" msgid="1729016644691793085">"Otvaraj linkove u aplikacijama, čak i ako nisu instalirane"</string>
     <string name="web_action_section_title" msgid="5563229447734734662">"Instant aplikacije"</string>
     <string name="instant_apps_settings" msgid="879003203555847537">"Postavke instant aplikacija"</string>
     <string name="domain_url_section_title" msgid="206403507921518321">"Instalirane aplikacije"</string>
@@ -4381,7 +4387,7 @@
     <string name="change_wifi_state_title" msgid="5140754955787584174">"Upravljanje WiFi mrežom"</string>
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"family link da upravlja WiFi mrežom"</string>
     <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"Dozvolite ovoj aplikaciji da uključi ili isključi WiFi, skenira i konektuje se na WiFi, doda ili ukloni mreže, te pokrene lokalnu pristupnu tačku"</string>
-    <string name="media_output_title" msgid="8710632337456601848">"Reproduciranje medija"</string>
+    <string name="media_output_title" msgid="8710632337456601848">"Reprodukcija medija na"</string>
     <string name="media_output_default_summary" msgid="3159237976830415584">"Ovaj uređaj"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"Telefon"</string>
     <string name="media_output_summary" product="tablet" msgid="6672024060360538526">"Tablet"</string>
@@ -4495,9 +4501,9 @@
     <string name="mobile_network_erase_sim_dialog_progress" msgid="4881754030959536493">"Brisanje SIM-a…"</string>
     <string name="mobile_network_erase_sim_error_dialog_title" msgid="9026625253242102706">"Nije moguće izbrisati SIM"</string>
     <string name="mobile_network_erase_sim_error_dialog_body" msgid="5955463559366034787">"Nije moguće izbrisati ovaj SIM zbog greške.\n\nPonovo pokrenite uređaj i pokušajte ponovo."</string>
-    <string name="preferred_network_mode_title" msgid="8324526359482124770">"Vrsta preferirane mreže"</string>
+    <string name="preferred_network_mode_title" msgid="8324526359482124770">"Preferirana vrsta mreže"</string>
     <string name="preferred_network_mode_summary" msgid="388957154320426335">"Promijenite način rada mreže"</string>
-    <string name="preferred_network_mode_dialogtitle" msgid="5448698073828567428">"Vrsta preferirane mreže"</string>
+    <string name="preferred_network_mode_dialogtitle" msgid="5448698073828567428">"Preferirana vrsta mreže"</string>
     <string name="carrier_settings_euicc" msgid="7723199738771996732">"Operater"</string>
     <string name="carrier_settings_version" msgid="2657511289029828425">"Verzija postavki"</string>
     <string name="call_category" msgid="3418535202893644015">"Pozivanje"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ca/arrays.xml b/tests/CarDeveloperOptions/res/values-ca/arrays.xml
index 593c847..dc71c8e 100644
--- a/tests/CarDeveloperOptions/res/values-ca/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-ca/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"executar en segon pla"</item>
     <item msgid="6423861043647911030">"volum d\'accessibilitat"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Ubicació"</item>
+    <item msgid="6656077694190491067">"Ubicació"</item>
+    <item msgid="8790228218278477369">"Ubicació"</item>
+    <item msgid="7836406246005211990">"Vibració"</item>
+    <item msgid="3951439024549922598">"Llegeix els contactes"</item>
+    <item msgid="8802152411647068">"Modifica els contactes"</item>
+    <item msgid="229544934599698735">"Llegeix el registre de trucades"</item>
+    <item msgid="7396102294405899613">"Modifica el registre de trucades"</item>
+    <item msgid="3597797992398484655">"Llegeix el calendari"</item>
+    <item msgid="2705975774250907343">"Modifica el calendari"</item>
+    <item msgid="4668747371441932697">"Ubicació"</item>
+    <item msgid="1487578921720243646">"Notificació de la publicació"</item>
+    <item msgid="4636080349724146638">"Ubicació"</item>
+    <item msgid="673510900286463926">"Trucada"</item>
+    <item msgid="542083422784609790">"Llegeix SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Escriu SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Rep SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Rep SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Rep SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Rep SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Envia SMS/MMS"</item>
+    <item msgid="4726682243833913568">"Llegeix SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Escriu SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Modifica la configuració"</item>
+    <item msgid="8705854389991425629">"Dibuixa a sobre"</item>
+    <item msgid="5861356020344153651">"Accedeix a les notificacions"</item>
+    <item msgid="78432174621628659">"Càmera"</item>
+    <item msgid="3986116419882154794">"Grava l\'àudio"</item>
+    <item msgid="4516840825756409490">"Reprodueix l\'àudio"</item>
+    <item msgid="6811712502798183957">"Llegeix el porta-retalls"</item>
+    <item msgid="2780369012602289114">"Modifica el porta-retalls"</item>
+    <item msgid="2331359440170850868">"Botons de multimèdia"</item>
+    <item msgid="6133599737122751231">"Enfocament de l\'àudio"</item>
+    <item msgid="6844485713404805301">"Volum general"</item>
+    <item msgid="1600379420669104929">"Volum de la veu"</item>
+    <item msgid="6296768210470214866">"Volum del to"</item>
+    <item msgid="510690696071629241">"Volum de multimèdia"</item>
+    <item msgid="406861638631430109">"Volum de l\'alarma"</item>
+    <item msgid="4715864795872233884">"Volum de notificació"</item>
+    <item msgid="2311478519251301183">"Volum del Bluetooth"</item>
+    <item msgid="5133991377896747027">"Mantén actiu"</item>
+    <item msgid="2464189519136248621">"Ubicació"</item>
+    <item msgid="2062677934050803037">"Ubicació"</item>
+    <item msgid="1735171933192715957">"Obtenir estadístiques d\'ús"</item>
+    <item msgid="1014093788778383554">"Silencia / deixa de silenciar el micròfon"</item>
+    <item msgid="4199297950608622850">"Mostrar l\'avís"</item>
+    <item msgid="2527962435313398821">"Projectar fitxers multimèdia"</item>
+    <item msgid="5117506254221861929">"Activar la VPN"</item>
+    <item msgid="8291198322681891160">"Fons de pantalla d\'escriptura"</item>
+    <item msgid="7106921284621230961">"Estructura d\'assistència"</item>
+    <item msgid="4496533640894624799">"Captura de pantalla d\'assistència"</item>
+    <item msgid="2598847264853993611">"Consultar l\'estat del telèfon"</item>
+    <item msgid="9215610846802973353">"Afegir missatges de veu"</item>
+    <item msgid="9186411956086478261">"Utilitzar el protocol SIP"</item>
+    <item msgid="6884763100104539558">"Processar les trucades sortints"</item>
+    <item msgid="125513972170580692">"Empremta digital"</item>
+    <item msgid="2556071024281275619">"Sensors corporals"</item>
+    <item msgid="617168514928339387">"Consultar les difusions mòbils"</item>
+    <item msgid="7134693570516523585">"Ubicació simulada"</item>
+    <item msgid="7224489175375229399">"Consultar l\'emmagatzematge"</item>
+    <item msgid="8472735063903258202">"Fer canvis a l\'emmagatzematge"</item>
+    <item msgid="4069276819909595110">"Activar la pantalla"</item>
+    <item msgid="1228338896751121025">"Obtenir comptes"</item>
+    <item msgid="3181581793459233672">"Executar en segon pla"</item>
+    <item msgid="2340936043025374076">"Volum d\'accessibilitat"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Breu"</item>
     <item msgid="4816511817309094890">"Mitjana"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"No permetis mai"</item>
     <item msgid="8184570120217958741">"Permet sempre"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Moderada"</item>
+    <item msgid="1555861583162930714">"Baixa"</item>
+    <item msgid="1719683776264798117">"Crítica"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normal"</item>
+    <item msgid="6107138933849816768">"Moderada"</item>
+    <item msgid="182695359839047859">"Baixa"</item>
+    <item msgid="8577246509202964244">"Crítica"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Persistent"</item>
     <item msgid="167418068739176448">"Activitat principal"</item>
diff --git a/tests/CarDeveloperOptions/res/values-ca/config.xml b/tests/CarDeveloperOptions/res/values-ca/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-ca/config.xml
+++ b/tests/CarDeveloperOptions/res/values-ca/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-ca/strings.xml b/tests/CarDeveloperOptions/res/values-ca/strings.xml
index 257d6b2..29423a2 100644
--- a/tests/CarDeveloperOptions/res/values-ca/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ca/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Amplia o redueix la mida del text de la pantalla."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Redueix"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Amplia"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Text de mostra"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"El meravellós mag d\'Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Capítol 11: La meravellosa Ciutat Maragda d\'Oz"</string>
@@ -364,7 +363,7 @@
     <string name="owner_info_settings_summary" msgid="4208702251226725583">"Cap"</string>
     <string name="owner_info_settings_status" msgid="8049975536717685126">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="COUNT_1">%2$d</xliff:g>"</string>
     <string name="owner_info_settings_edit_text_hint" msgid="2250029417257939706">"P. ex., Android del Lluís"</string>
-    <string name="user_info_settings_title" msgid="1125111518759995748">"Info. de l\'usuari"</string>
+    <string name="user_info_settings_title" msgid="1125111518759995748">"Informació de l\'usuari"</string>
     <string name="show_profile_info_on_lockscreen_label" msgid="5204282771893683026">"Mostra la inf. de perfil a la pantalla de bloqueig"</string>
     <string name="profile_info_settings_title" msgid="4855892878512562551">"Informació de perfil"</string>
     <string name="Accounts_settings_title" msgid="7901374987121953746">"Comptes"</string>
@@ -421,7 +420,7 @@
     <string name="security_settings_face_settings_use_face_unlock_phone" msgid="318274519126401671">"Desbloqueja el dispositiu"</string>
     <string name="security_settings_face_settings_use_face_for_apps" msgid="5479369083370664351">"Inici de sessió i pagaments"</string>
     <string name="security_settings_face_settings_require_attention" msgid="2755140150841557225">"Obre els ulls per desbloquejar"</string>
-    <string name="security_settings_face_settings_require_attention_details" msgid="2557060433599942587">"Els ulls han d\'estar oberts durant l\'autenticació facial"</string>
+    <string name="security_settings_face_settings_require_attention_details" msgid="2557060433599942587">"Quan utilitzis l\'autenticació facial, has de tenir els ulls oberts"</string>
     <string name="security_settings_face_settings_require_confirmation" msgid="7312024271060416438">"Requereix sempre confirmació"</string>
     <string name="security_settings_face_settings_require_confirmation_details" msgid="8740564864091803429">"En autenticar en aplicacions, requereix sempre confirmació"</string>
     <string name="security_settings_face_settings_remove_face_data" msgid="2821359954483136239">"Suprimeix les dades facials"</string>
@@ -461,13 +460,13 @@
     <string name="skip_lock_screen_dialog_button_label" msgid="6706047245716780006">"Omet"</string>
     <string name="cancel_lock_screen_dialog_button_label" msgid="2534925227627658819">"Cancel·la"</string>
     <string name="security_settings_fingerprint_enroll_find_sensor_title" msgid="8909829699273726469">"Toca el sensor"</string>
-    <string name="security_settings_fingerprint_enroll_find_sensor_message" msgid="581120963079780740">"És a la part posterior del telèfon. Fes servir el dit índex."</string>
+    <string name="security_settings_fingerprint_enroll_find_sensor_message" msgid="581120963079780740">"És a la part posterior del telèfon. Utilitza el dit índex."</string>
     <string name="security_settings_fingerprint_enroll_find_sensor_content_description" msgid="7835824123269738540">"Il·lustració amb la ubicació del sensor d\'empremtes digitals i de dispositiu"</string>
     <string name="security_settings_fingerprint_enroll_dialog_name_label" msgid="3519748398694308901">"Nom"</string>
     <string name="security_settings_fingerprint_enroll_dialog_ok" msgid="3428927518029038956">"D\'acord"</string>
     <string name="security_settings_fingerprint_enroll_dialog_delete" msgid="4312297515772004580">"Suprimeix"</string>
     <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"Toca el sensor"</string>
-    <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Col·loca el dit al sensor i aixeca\'l quan notis una vibració"</string>
+    <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Col·loca el dit al sensor i aixeca\'l quan notis una vibració."</string>
     <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"Aixeca el dit i toca de nou"</string>
     <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Continua aixecant el dit per afegir les diferents parts de l\'empremta digital"</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"Empremta digital afegida"</string>
@@ -487,9 +486,9 @@
     <string name="security_settings_fingerprint_enroll_setup_screen_lock" msgid="9036983528330627756">"Configura el bloqueig de pantalla"</string>
     <string name="security_settings_fingerprint_enroll_done" msgid="4111289529758845926">"Fet"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"Això no és el sensor"</string>
-    <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"Toca el sensor situat a la part posterior amb el dit índex."</string>
+    <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"Toca el sensor situat a la part posterior del telèfon. Utilitza el dit índex."</string>
     <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"No s\'ha completat el registre"</string>
-    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"S\'ha esgotat el temps d\'espera per inscriure l\'empremta digital. Torna-ho a provar."</string>
+    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"S\'ha esgotat el límit de temps per inscriure l\'empremta digital. Torna-ho a provar."</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"El registre de l\'empremta digital no ha funcionat. Torna-ho a provar o fes servir un altre dit."</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"Afegeix-ne una altra"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"Següent"</string>
@@ -549,7 +548,7 @@
     <string name="setup_lock_settings_picker_title" product="tablet" msgid="2429667472335773519">"Protegeix la tauleta"</string>
     <string name="setup_lock_settings_picker_title" product="device" msgid="4739290104106645233">"Protegeix el dispositiu"</string>
     <string name="setup_lock_settings_picker_title" product="default" msgid="3911582328576859628">"Protegeix el telèfon"</string>
-    <string name="lock_settings_picker_biometrics_added_security_message" msgid="799453282539387294">"Defineix un bloqueig de pantalla alternatiu per a més seguretat"</string>
+    <string name="lock_settings_picker_biometrics_added_security_message" msgid="799453282539387294">"Per a més seguretat, defineix un bloqueig de pantalla alternatiu"</string>
     <string name="setup_lock_settings_picker_message" product="tablet" msgid="7230799135599877804">"Activa les funcions de protecció del dispositiu per impedir que altres persones utilitzin aquesta tauleta sense permís. Tria el bloqueig de pantalla que vulguis utilitzar."</string>
     <string name="setup_lock_settings_picker_message" product="device" msgid="2098404520816295371">"Activa les funcions de protecció del dispositiu per impedir que altres persones el facin servir sense permís. Tria el bloqueig de pantalla que vulguis utilitzar."</string>
     <string name="setup_lock_settings_picker_message" product="default" msgid="2003984443953672040">"Activa les funcions de protecció del dispositiu per impedir que altres persones utilitzin aquest telèfon sense permís. Tria el bloqueig de pantalla que vulguis utilitzar."</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Ha de tenir <xliff:g id="NUMBER_1">%d</xliff:g> dígits o menys</item>
       <item quantity="one">Ha de tenir <xliff:g id="NUMBER_0">%d</xliff:g> dígit o menys</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Només pot contenir dígits del 0 al 9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"L\'administrador del dispositiu no permet que s\'utilitzi un PIN recent"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"L\'administrador de TI ha bloquejat els PIN més comuns. Prova un altre PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"No pot incloure un caràcter no vàlid"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Ha de contenir com a mínim <xliff:g id="COUNT">%d</xliff:g> caràcters que no siguin lletres</item>
       <item quantity="one">Ha de contenir com a mínim 1 caràcter que no sigui una lletra</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Ha de contenir com a mínim <xliff:g id="COUNT">%d</xliff:g> caràcters que no siguin números</item>
+      <item quantity="one">Ha de contenir com a mínim 1 caràcter que no sigui un número</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"L\'administrador del dispositiu no permet que s\'utilitzi una contrasenya recent"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"L\'administrador de TI ha bloquejat les contrasenyes més comunes. Prova una altra contrasenya."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"No es permet cap seqüència de dígits ascendents, descendents ni repetits"</string>
@@ -716,7 +718,7 @@
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> aplicació activa</item>
     </plurals>
     <string name="manage_trust_agents" msgid="8129970926213142261">"Agents de confiança"</string>
-    <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"Per utilitzar aquesta opció, has de configurar un bloqueig de pantalla"</string>
+    <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"Per utilitzar aquesta opció, has de definir un bloqueig de pantalla"</string>
     <string name="manage_trust_agents_summary" msgid="2023116850759962248">"Cap"</string>
     <plurals name="manage_trust_agents_summary_on" formatted="false" msgid="5550538038916606097">
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> agents de confiança actius</item>
@@ -873,7 +875,7 @@
     <string name="wifi_cellular_data_fallback_title" msgid="5067241930716252665">"Canvia automàticament a dades mòbils"</string>
     <string name="wifi_cellular_data_fallback_summary" msgid="2721467405851519769">"Utilitza dades mòbils quan la Wi-Fi no tingui accés a Internet. És possible que s\'hi apliquin càrrecs per ús de dades."</string>
     <string name="wifi_add_network" msgid="4094957940791876640">"Afegeix una xarxa"</string>
-    <string name="wifi_configure_settings_preference_title" msgid="2678534679408777268">"Preferències de la Wi‑Fi"</string>
+    <string name="wifi_configure_settings_preference_title" msgid="2678534679408777268">"Preferències de Wi‑Fi"</string>
     <string name="wifi_configure_settings_preference_summary_wakeup_on" msgid="5714892572614655675">"La Wi‑Fi es torna a connectar automàticament"</string>
     <string name="wifi_configure_settings_preference_summary_wakeup_off" msgid="286904094152909651">"La Wi‑Fi no es torna a activar automàticament"</string>
     <string name="wifi_access_points" msgid="1647976498906871869">"Xarxes Wi-Fi"</string>
@@ -903,7 +905,7 @@
     <string name="wifi_ssid_hint" msgid="5010024648106585165">"Introdueix l\'SSID"</string>
     <string name="wifi_security" msgid="9136702039496152831">"Seguretat"</string>
     <string name="wifi_hidden_network" msgid="6647772204699776833">"Xarxa amagada"</string>
-    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Si el teu encaminador no emet cap identificador de xarxa, però vols connectar-t\'hi més endavant, pots configurar la xarxa com a oculta.\n\nAixò pot crear un risc de seguretat perquè el telèfon emetrà el senyal per trobar la xarxa de manera regular.\n\nConfigurar la xarxa com a oculta no canviarà la configuració del teu encaminador."</string>
+    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Si el teu encaminador no emet cap identificador de xarxa, però vols connectar-t\'hi més endavant, pots configurar la xarxa com a oculta.\n\nAixò pot crear un risc de seguretat perquè el telèfon emetrà el senyal de manera regular per trobar la xarxa.\n\nConfigurar la xarxa com a oculta no canviarà la configuració del teu encaminador."</string>
     <string name="wifi_signal" msgid="696548364467704808">"Intensitat del senyal"</string>
     <string name="wifi_status" msgid="3439931558930689940">"Estat"</string>
     <string name="tx_wifi_speed" msgid="2571810085003261073">"Transmet la velocitat de l\'enllaç"</string>
@@ -925,7 +927,7 @@
     <string name="wifi_ap_choose_auto" msgid="7927637960569365785">"Automàtica"</string>
     <string name="wifi_ap_choose_2G" msgid="43198403259714736">"Banda de 2,4 GHz"</string>
     <string name="wifi_ap_choose_5G" msgid="2624859713183683146">"Banda de 5,0 GHz"</string>
-    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"Preferència per la banda de 5,0 GHz"</string>
+    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"Banda de 5,0 GHz preferida"</string>
     <string name="wifi_ap_2G" msgid="5793110086517338494">"2,4 GHz"</string>
     <string name="wifi_ap_5G" msgid="4584892544393675403">"5,0 GHz"</string>
     <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"Tria almenys una banda per al punt d\'accés Wi-Fi:"</string>
@@ -970,7 +972,7 @@
     <string name="wifi_multiple_cert_added" msgid="7986200585749147204">"(S\'han afegit diversos certificats)"</string>
     <string name="wifi_use_system_certs" msgid="4794489370929885022">"Utilitza certificats del sistema"</string>
     <string name="wifi_do_not_provide_eap_user_cert" msgid="4044301449482425250">"No proporcionis un certificat d\'usuari"</string>
-    <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"No validis el servidor d\'EAP"</string>
+    <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"No validis"</string>
     <string name="wifi_do_not_validate_eap_server_warning" msgid="3895397996759837323">"No s\'ha especificat cap certificat. La connexió no serà privada."</string>
     <string name="wifi_ssid_too_long" msgid="34911971389775920">"El nom de la xarxa és massa llarg."</string>
     <string name="wifi_no_domain_warning" msgid="735859919311067606">"Has d\'especificar un domini."</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi‑Fi"</item>
+    <item msgid="2271962426654621656">"Dades mòbils"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Si no pots fer servir la Wi‑Fi, utilitza la xarxa mòbil"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Si no pots fer servir la xarxa mòbil, utilitza la Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Trucades per Wi‑Fi. Si perds la connexió, la trucada finalitzarà."</string>
@@ -1215,7 +1220,7 @@
     <string name="night_display_end_time_title" msgid="2760793157124245911">"Hora de finalització"</string>
     <string name="night_display_status_title" msgid="1727020934735770319">"Estat"</string>
     <string name="night_display_temperature_title" msgid="8375126629902616296">"Intensitat"</string>
-    <string name="night_display_summary_off" msgid="8850539785332228069">"Desactivada / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="night_display_summary_off" msgid="8850539785332228069">"Desactivat / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="night_display_summary_off_auto_mode_never" msgid="8618824386434992487">"No s\'activarà mai automàticament"</string>
     <string name="night_display_summary_off_auto_mode_custom" msgid="596847003171394411">"S\'activarà automàticament a les <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="night_display_summary_off_auto_mode_twilight" msgid="4071750976585359952">"S\'activarà automàticament al vespre"</string>
@@ -1281,7 +1286,7 @@
     <string name="sim_reenter_new" msgid="5692585822458989725">"Torna a escriure el PIN nou"</string>
     <string name="sim_change_pin" msgid="1674620855223900785">"PIN de la SIM"</string>
     <string name="sim_bad_pin" msgid="2409776007569751629">"PIN incorrecte"</string>
-    <string name="sim_pins_dont_match" msgid="1076283313667637902">"Els codis PIN no coincideixen"</string>
+    <string name="sim_pins_dont_match" msgid="1076283313667637902">"Els PIN no coincideixen"</string>
     <string name="sim_change_failed" msgid="8874765697694275459">"No es pot canviar el PIN.\nÉs possible que sigui incorrecte."</string>
     <string name="sim_change_succeeded" msgid="8802418023120614533">"PIN de la SIM canviat correctament"</string>
     <string name="sim_lock_failed" msgid="7949781515066772755">"No es pot canviar l\'estat de bloqueig de la targeta SD.\nÉs possible que el PIN sigui incorrecte."</string>
@@ -1312,7 +1317,7 @@
     <string name="hardware_revision" msgid="3315744162524354246">"Versió del maquinari"</string>
     <string name="fcc_equipment_id" msgid="8681995718533066093">"Id. de l\'equip"</string>
     <string name="baseband_version" msgid="9115560821840757786">"Versió de banda base"</string>
-    <string name="kernel_version" msgid="8226014277756019297">"Versió del kernel"</string>
+    <string name="kernel_version" msgid="8226014277756019297">"Versió de kernel"</string>
     <string name="build_number" msgid="8648447688306248633">"Número de compilació"</string>
     <string name="module_version" msgid="1127871672527968730">"Versions del mòdul principal"</string>
     <string name="device_info_not_available" msgid="3762481874992799474">"No disponible"</string>
@@ -1425,7 +1430,7 @@
     <string name="storage_other_users" msgid="1055693465220962928">"Altres usuaris"</string>
     <string name="storage_internal_title" msgid="7969898703086593200">"Emmagatzematge del dispositiu"</string>
     <string name="storage_external_title" msgid="3308178326521953306">"Emmagatzematge portàtil"</string>
-    <string name="storage_volume_summary" msgid="3938298080954984809">"S\'han utilitzat <xliff:g id="USED">%1$s</xliff:g> d\'un total de <xliff:g id="TOTAL">%2$s</xliff:g>"</string>
+    <string name="storage_volume_summary" msgid="3938298080954984809">"<xliff:g id="USED">%1$s</xliff:g> en ús de <xliff:g id="TOTAL">%2$s</xliff:g>"</string>
     <string name="storage_size_large" msgid="2252229139037320440">"<xliff:g id="NUMBER">^1</xliff:g>"<small><small>" <xliff:g id="UNIT">^2</xliff:g>"</small></small>""</string>
     <string name="storage_volume_used" msgid="6762683251427947210">"En ús de: <xliff:g id="TOTAL">%1$s</xliff:g>"</string>
     <string name="storage_volume_used_total" msgid="1915664465366569853">"Total utilitzat de: <xliff:g id="TOTAL">%1$s</xliff:g>"</string>
@@ -1533,7 +1538,7 @@
     <string name="apn_server" msgid="625116221513279678">"Servidor"</string>
     <string name="apn_mmsc" msgid="4621771343217824216">"MMSC"</string>
     <string name="apn_mms_proxy" msgid="636948562860444714">"Servidor intermediari MMS"</string>
-    <string name="apn_mms_port" msgid="6606572282014819299">"Port per a MMS"</string>
+    <string name="apn_mms_port" msgid="6606572282014819299">"Port MMS"</string>
     <string name="apn_mcc" msgid="9138301167194779180">"MCC"</string>
     <string name="apn_mnc" msgid="1276161191283274976">"MNC"</string>
     <string name="apn_auth_type" msgid="4286147728662523362">"Tipus d\'autenticació"</string>
@@ -1544,11 +1549,11 @@
     <string name="apn_type" msgid="6725346490902871146">"Tipus d\'APN"</string>
     <string name="apn_protocol" msgid="1240197323563960912">"Protocol APN"</string>
     <string name="apn_roaming_protocol" msgid="6913336248771263497">"Protocol d\'itinerància d\'APN"</string>
-    <string name="carrier_enabled" msgid="1819916725305365581">"Activa/desactiva APN"</string>
+    <string name="carrier_enabled" msgid="1819916725305365581">"Activa/Desactiva APN"</string>
     <string name="carrier_enabled_summaryOn" msgid="6219221535461945771">"APN activat"</string>
     <string name="carrier_enabled_summaryOff" msgid="4093019532796386622">"APN desactivat"</string>
-    <string name="bearer" msgid="4378444317087536401">"Tipus de connexió"</string>
-    <string name="mvno_type" msgid="3150755279048149624">"Tipus de MVNO"</string>
+    <string name="bearer" msgid="4378444317087536401">"Portador"</string>
+    <string name="mvno_type" msgid="3150755279048149624">"Tipus d\'OMV"</string>
     <string name="mvno_match_data" msgid="629287305803195245">"Valor de MVNO"</string>
     <string name="menu_delete" msgid="8646081395424055735">"Suprimeix l\'APN"</string>
     <string name="menu_new" msgid="7529219814721969024">"APN nou"</string>
@@ -1562,7 +1567,7 @@
     <string name="error_adding_apn_type" msgid="671634520340569678">"L\'operador no permet afegir APN de tipus %s."</string>
     <string name="restore_default_apn" msgid="7195266404077471007">"S\'està restaurant la configuració predeterminada d\'APN."</string>
     <string name="menu_restore" msgid="3799288817317293115">"Restableix valors predeterminats"</string>
-    <string name="restore_default_apn_completed" msgid="5671734152740058937">"S\'ha restablert la configuració predeterminada d\'APN."</string>
+    <string name="restore_default_apn_completed" msgid="5671734152740058937">"S\'ha restablert la configuració d\'APN predeterminada."</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"Opcions de restabliment"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"Es poden restablir la xarxa, les aplicacions o el dispositiu"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"Restableix Wi-Fi, dades mòbils i Bluetooth"</string>
@@ -1581,7 +1586,7 @@
     <string name="master_clear_title" msgid="1560712943955904673">"Esborra totes les dades (restabliment de les dades de fàbrica)"</string>
     <string name="master_clear_short_title" msgid="919098101581335101">"Esborra totes les dades"</string>
     <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"Aquesta acció esborrarà totes les dades de l\'"<b>"emmagatzematge intern"</b>" de la tauleta, com ara:\n\n"<li>"el teu Compte de Google"</li>\n<li>"les dades i la configuració del sistema i de les aplicacions"</li>\n<li>"les aplicacions baixades"</li></string>
-    <string name="master_clear_desc" product="default" msgid="8765543541962866697">"Aquesta acció esborrarà totes les dades de l\'"<b>"emmagatzematge intern"</b>" del telèfon, com ara:\n\n"<li>"El teu Compte de Google"</li>\n<li>"Les dades i la configuració del sistema i de les aplicacions"</li>\n<li>"Les aplicacions baixades"</li></string>
+    <string name="master_clear_desc" product="default" msgid="8765543541962866697">"S\'esborraran totes les dades de l\'"<b>"emmagatzematge intern"</b>" del telèfon, inclosos:\n\n"<li>"El teu Compte de Google"</li>\n<li>"Les dades i la configuració del sistema i de les aplicacions"</li>\n<li>"Les aplicacions baixades"</li></string>
     <string name="master_clear_accounts" product="default" msgid="3432884235445405376">\n\n"Tens la sessió iniciada als comptes següents:\n"</string>
     <string name="master_clear_other_users_present" product="default" msgid="5993259656117566767">\n\n"En aquest dispositiu hi ha altres usuaris.\n"</string>
     <string name="master_clear_desc_also_erases_external" msgid="3947303501615091903"><li>"Música"</li>\n<li>"Fotos"</li>\n<li>"Altres dades de l\'usuari"</li></string>
@@ -1642,7 +1647,7 @@
     <string name="mobile_insert_sim_card" msgid="7594550403454243732">"Insereix la targeta SIM i reinicia"</string>
     <string name="mobile_connect_to_internet" msgid="6031886097365170913">"Connecta a Internet"</string>
     <string name="location_title" msgid="8664674161765477168">"La meva ubicació"</string>
-    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"Ubicació perfil de treball"</string>
+    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"Ubicació per al perfil de treball"</string>
     <string name="location_app_level_permissions" msgid="1298041503927632960">"Permís d\'aplicacions"</string>
     <string name="location_app_permission_summary_location_off" msgid="541372845344796336">"La ubicació està desactivada"</string>
     <plurals name="location_app_permission_summary_location_on" formatted="false" msgid="7904821382328758218">
@@ -1676,7 +1681,7 @@
     <string name="location_access_summary" msgid="6919495149026354355">"Permet que les aplicacions que hagin demanat permís utilitzin la informació sobre la ubicació"</string>
     <string name="location_sources_heading" msgid="8526658357120282741">"Fonts d\'ubicació"</string>
     <string name="about_settings" product="tablet" msgid="4869626690708456341">"Informació sobre la tauleta"</string>
-    <string name="about_settings" product="default" msgid="6019547763377294261">"Informació sobre el telèfon"</string>
+    <string name="about_settings" product="default" msgid="6019547763377294261">"Informació del telèfon"</string>
     <string name="about_settings" product="device" msgid="1770438316234693655">"Informació sobre el dispositiu"</string>
     <string name="about_settings" product="emulator" msgid="4497482494770487014">"Sobre el dispositiu emulat"</string>
     <string name="about_settings_summary" msgid="4506081667462281647">"Mostra informació legal, estat, versió de programari"</string>
@@ -1703,8 +1708,8 @@
     <string name="confirm_device_credential_use_alternate_method" msgid="1279869272895739941">"Utilitza un altre mètode"</string>
     <string name="lockpassword_choose_your_screen_lock_header" msgid="6283518876031424798">"Defineix un bloqueig de pantalla"</string>
     <string name="lockpassword_choose_your_password_message" msgid="2838273977481046536">"Per motius de seguretat, cal que defineixis una contrasenya"</string>
-    <string name="lockpassword_choose_your_password_header_for_fingerprint" msgid="4921343500484160894">"Defineix una contrasenya"</string>
-    <string name="lockpassword_choose_your_pattern_header_for_fingerprint" msgid="314870151462139417">"Defineix un patró"</string>
+    <string name="lockpassword_choose_your_password_header_for_fingerprint" msgid="4921343500484160894">"Per utilitzar l\'empremta, defineix una contrasenya"</string>
+    <string name="lockpassword_choose_your_pattern_header_for_fingerprint" msgid="314870151462139417">"Per utilitzar l\'empremta, defineix un patró"</string>
     <string name="lockpassword_choose_your_pin_message" msgid="8942598950627277885">"Per motius de seguretat, cal que defineixis un PIN"</string>
     <string name="lockpassword_choose_your_pin_header_for_fingerprint" msgid="1102927520952116303">"Per utilitzar l\'empremta, defineix un PIN"</string>
     <string name="lockpassword_choose_your_pattern_message" msgid="1503075455752279687">"Per motius de seguretat, cal que defineixis un patró"</string>
@@ -1712,7 +1717,7 @@
     <string name="lockpassword_confirm_your_pattern_header" msgid="7137526922696316545">"Confirma el patró"</string>
     <string name="lockpassword_confirm_your_pin_header" msgid="4335593948303036343">"Torna a introduir el PIN"</string>
     <string name="lockpassword_confirm_passwords_dont_match" msgid="1783767008133345784">"Les contrasenyes no coincideixen"</string>
-    <string name="lockpassword_confirm_pins_dont_match" msgid="5444357293637748942">"Els codis PIN no coincideixen"</string>
+    <string name="lockpassword_confirm_pins_dont_match" msgid="5444357293637748942">"Els PIN no coincideixen"</string>
     <string name="lockpassword_draw_your_pattern_again_header" msgid="9017394036814402348">"Torna a dibuixar el patró"</string>
     <string name="lockpassword_choose_lock_generic_header" msgid="4418423132980560119">"Mètode de desbloqueig"</string>
     <string name="lockpassword_password_set_toast" msgid="601928982984489868">"La contrasenya s\'ha definit"</string>
@@ -1759,7 +1764,7 @@
     <string name="lockpattern_settings_title" msgid="5152005866870766842">"Patró de desbloqueig"</string>
     <string name="lockpattern_settings_enable_title" msgid="8508410891939268080">"Requereix un patró"</string>
     <string name="lockpattern_settings_enable_summary" msgid="8027605503917737512">"Cal dibuixar el patró per desbloquejar la pantalla"</string>
-    <string name="lockpattern_settings_enable_visible_pattern_title" msgid="4935583222709647096">"Mostra el patró"</string>
+    <string name="lockpattern_settings_enable_visible_pattern_title" msgid="4935583222709647096">"Fes que el patró sigui visible"</string>
     <string name="lockpattern_settings_enable_visible_pattern_title_profile" msgid="5338893138982642228">"Mostra el patró del perfil"</string>
     <string name="lockpattern_settings_enable_tactile_feedback_title" msgid="3203621862806531947">"Vibra en tocar"</string>
     <string name="lockpattern_settings_enable_power_button_instantly_locks" msgid="5890335732200257777">"El botó d\'engegada bloqueja"</string>
@@ -1839,7 +1844,7 @@
     <string name="default_emergency_app" msgid="286530070173495823">"Aplicació en casos d\'emergència"</string>
     <string name="reset_app_preferences" msgid="1426500030595212077">"Restableix les preferències d\'aplicacions"</string>
     <string name="reset_app_preferences_title" msgid="792909865493673598">"Restablir les preferències d\'aplicacions?"</string>
-    <string name="reset_app_preferences_desc" msgid="7935273005301096031">"Es restabliran les preferències de:\n\n "<li>"Aplicacions desactivades"</li>\n" "<li>"Notificacions d\'aplicacions desactivades"</li>\n" "<li>"Aplicacions predeterminades per a accions"</li>\n" "<li>"Restriccions de dades en segon pla per a aplicacions"</li>\n" "<li>"Restriccions de permisos"</li>\n\n" No es perdran les dades de les aplicacions."</string>
+    <string name="reset_app_preferences_desc" msgid="7935273005301096031">"Es restabliran totes les preferències de:\n\n "<li>"Aplicacions desactivades"</li>\n" "<li>"Notificacions d\'aplicacions desactivades"</li>\n" "<li>"Aplicacions predeterminades per a accions"</li>\n" "<li>"Restriccions de dades en segon pla per a aplicacions"</li>\n" "<li>"Restriccions de permisos"</li>\n\n" No es perdran les dades de les aplicacions."</string>
     <string name="reset_app_preferences_button" msgid="2041894727477934656">"Restableix aplicacions"</string>
     <string name="manage_space_text" msgid="6166469422303124302">"Gestiona l\'espai"</string>
     <string name="filter" msgid="2426943916212457962">"Filtra"</string>
@@ -2081,7 +2086,7 @@
     <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"Tria el temps que necessites per llegir els missatges que es mostren temporalment.\n\nNo totes les aplicacions admeten aquesta opció de configuració."</string>
     <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"Selecciona el temps que vols tenir per llegir els missatges que es mostren temporalment i et demanen que duguis a terme una acció.\n\nAquesta opció no és compatible amb totes les aplicacions."</string>
     <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"Retard en mantenir premut"</string>
-    <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"Inversió dels colors"</string>
+    <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"Inversió de colors"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"Pot afectar el rendiment"</string>
     <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"Temps de permanència"</string>
     <string name="accessibility_autoclick_description" msgid="5492414927846407499">"Si utilitzes un ratolí, pots configurar-lo perquè el cursor faci accions automàticament quan deixi de moure\'s durant un determinat període de temps."</string>
@@ -2091,7 +2096,7 @@
     <string name="accessibility_ring_vibration_title" msgid="7943341443551359985">"Vibració de les trucades"</string>
     <string name="accessibility_touch_vibration_title" msgid="285890135612038092">"Vibració en tocar"</string>
     <string name="accessibility_service_master_switch_title" msgid="2734791644475782924">"Utilitza el servei"</string>
-    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Utilitza la correcció del color"</string>
+    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Utilitza la correcció de color"</string>
     <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"Utilitza subtítols"</string>
     <string name="accessibility_hearingaid_instruction_continue_button" msgid="4650111296711466691">"Continua"</string>
     <string name="accessibility_hearingaid_title" msgid="3700978781235124891">"Audiòfons"</string>
@@ -2263,7 +2268,7 @@
     <string name="controls_subtitle" msgid="6920199888882834620">"Redueix el consum de la bateria"</string>
     <string name="packages_subtitle" msgid="6506269487892204413">"Paquets inclosos"</string>
     <string name="battery_tip_summary_title" msgid="2750922152518825526">"Les aplicacions funcionen correctament"</string>
-    <string name="battery_tip_summary_summary" product="default" msgid="6294900413896440006">"El telèfon fa un ús normal de la bateria en segon pla"</string>
+    <string name="battery_tip_summary_summary" product="default" msgid="6294900413896440006">"El telèfon té un ús normal de la bateria en segon pla"</string>
     <string name="battery_tip_summary_summary" product="tablet" msgid="5280099016800644130">"La tauleta fa un ús normal de la bateria en segon pla"</string>
     <string name="battery_tip_summary_summary" product="device" msgid="4459840492610842705">"El dispositiu fa un ús normal de la bateria en segon pla"</string>
     <string name="battery_tip_low_battery_title" msgid="6784043681672161175">"La bateria té poca capacitat"</string>
@@ -2273,13 +2278,13 @@
     <string name="battery_tip_smart_battery_title" product="device" msgid="7419448992583346364">"Millora la durada de la bateria del dispositiu"</string>
     <string name="battery_tip_smart_battery_summary" msgid="5344821856478265778">"Activa el gestor de bateria"</string>
     <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Activa l\'estalvi de bateria"</string>
-    <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"És possible que la bateria s\'esgoti abans del que és habitual"</string>
+    <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Pot ser que la bateria s\'esgoti massa ràpid"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"S\'ha activat l\'estalvi de bateria"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"És possible que algunes funcions estiguin limitades"</string>
     <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"El telèfon s\'ha utilitzat més del que és habitual"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"La tauleta s\'ha utilitzat més del que és habitual"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"El dispositiu s\'ha utilitzat més del que és habitual"</string>
-    <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"És possible que la bateria s\'esgoti abans del que és habitual"</string>
+    <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"Pot ser que la bateria s\'esgoti massa ràpid"</string>
     <string name="battery_tip_dialog_message" product="default" msgid="8453700079047810964">"El telèfon s\'ha fet servir més del que és habitual i és possible que la bateria s\'esgoti abans del previst.\n\nAquestes són les aplicacions que han consumit més bateria des de la càrrega completa:"</string>
     <string name="battery_tip_dialog_message" product="tablet" msgid="6489981050645444068">"La tauleta s\'ha fet servir més del que és habitual. És possible que la bateria s\'esgoti abans del previst.\n\nAquestes són les aplicacions que han fet servir més bateria des de la càrrega completa:"</string>
     <string name="battery_tip_dialog_message" product="device" msgid="6348123094674390337">"El dispositiu s\'ha fet servir més del que és habitual. És possible que la bateria s\'esgoti abans del previst.\n\nAquestes són les aplicacions que han fet servir més bateria des de la càrrega completa:"</string>
@@ -2294,7 +2299,7 @@
     </plurals>
     <plurals name="battery_tip_restrict_summary" formatted="false" msgid="984148373944071669">
       <item quantity="other">%2$d aplicacions consumeixen molta bateria en segon pla</item>
-      <item quantity="one">%1$s aplicació consumeix molta bateria en segon pla</item>
+      <item quantity="one">%1$s consumeix molta bateria en segon pla</item>
     </plurals>
     <plurals name="battery_tip_restrict_handled_summary" formatted="false" msgid="469696766640020557">
       <item quantity="other">Aquestes aplicacions no es poden executar en segon pla</item>
@@ -2309,7 +2314,7 @@
     <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"Per estalviar bateria, impedeix que aquestes aplicacions consumeixin bateria en segon pla. És possible que les aplicacions restringides no funcionin correctament i que en rebis les notificacions amb retard.\n\nAplicacions:<xliff:g id="APP_LIST">%1$s</xliff:g>\n."</string>
     <string name="battery_tip_restrict_app_dialog_ok" msgid="2573410775701913487">"Restringeix"</string>
     <string name="battery_tip_unrestrict_app_dialog_title" msgid="812458516399125710">"Vols suprimir la restricció?"</string>
-    <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"Aquesta aplicació podrà consumir bateria en segon pla, cosa que pot provocar que s\'esgoti abans del previst."</string>
+    <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"Aquesta aplicació podrà utilitzar bateria en segon pla, cosa que pot provocar que s\'esgoti abans del previst."</string>
     <string name="battery_tip_unrestrict_app_dialog_ok" msgid="9154938931448151479">"Suprimeix"</string>
     <string name="battery_tip_unrestrict_app_dialog_cancel" msgid="7331148618292397166">"Cancel·la"</string>
     <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"Les teves aplicacions utilitzen una quantitat normal de bateria. Si n\'utilitzen massa, el telèfon et suggerirà mesures per evitar-ho.\n\nSi tens poca bateria, sempre pots activar l\'estalvi de bateria."</string>
@@ -2330,7 +2335,7 @@
     <string name="restricted_app_detail_footer" msgid="482460517275754465">"Aquestes aplicacions han estat consumint bateria en segon pla. És possible que les aplicacions restringides no funcionin correctament i que en rebis les notificacions amb retard."</string>
     <string name="battery_auto_restriction_title" msgid="488905332794794076">"Utilitza el gestor de bateria"</string>
     <string name="battery_auto_restriction_summary" msgid="1638072655581821837">"Detecta quan les aplicacions consumeixen bateria"</string>
-    <string name="battery_manager_on" msgid="5626982529932239656">"Activat: es detecta el consum de bateria de les aplicacions"</string>
+    <string name="battery_manager_on" msgid="5626982529932239656">"Activat / Es detecta el consum de bateria de les aplicacions"</string>
     <string name="battery_manager_off" msgid="9114027524232450371">"Desactivat"</string>
     <plurals name="battery_manager_app_restricted" formatted="false" msgid="6721813588142691216">
       <item quantity="other">S\'han restringit %1$d aplicacions</item>
@@ -2425,8 +2430,8 @@
     <string name="battery_last_full_charge" msgid="5624033030647170717">"Última càrrega completa"</string>
     <string name="battery_full_charge_last" msgid="4614554109170251301">"Durada aproximada de la càrrega completa"</string>
     <string name="battery_footer_summary" msgid="4828444679643906943">"Les dades d\'ús de la bateria són aproximades i poden variar en funció de l\'ús"</string>
-    <string name="battery_detail_foreground" msgid="6616408559186553085">"Durant l\'ús actiu"</string>
-    <string name="battery_detail_background" msgid="7938146832943604280">"En segon pla"</string>
+    <string name="battery_detail_foreground" msgid="6616408559186553085">"Mentre està en ús actiu"</string>
+    <string name="battery_detail_background" msgid="7938146832943604280">"Mentre està segon pla"</string>
     <string name="battery_detail_power_usage" msgid="3606930232257489212">"Ús de la bateria"</string>
     <string name="battery_detail_info_title" msgid="4617514228447481336">"Des de la càrrega completa"</string>
     <string name="battery_detail_manage_title" msgid="745194290572617507">"Gestiona l\'ús de la bateria"</string>
@@ -2449,8 +2454,8 @@
     <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"L\'estalvi de bateria s\'activa si és probable que et quedis sense bateria abans de la càrrega habitual següent"</string>
     <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"S\'activarà quan quedi un <xliff:g id="PERCENT">%1$s</xliff:g> de bateria"</string>
     <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"Defineix una programació"</string>
-    <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"Desactiva quan la càrrega estigui completa"</string>
-    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"L\'estalvi de bateria es desactivarà quan el telèfon tingui un <xliff:g id="PERCENT">%1$s</xliff:g> de bateria"</string>
+    <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"Desactiva quan estigui carregada per complet"</string>
+    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"L\'estalvi de bateria es desactiva quan el telèfon té un <xliff:g id="PERCENT">%1$s</xliff:g> de bateria"</string>
     <string name="battery_saver_sticky_description_new" product="tablet" msgid="3284967694001857194">"L\'estalvi de bateria es desactivarà quan la tauleta tingui un <xliff:g id="PERCENT">%1$s</xliff:g> de bateria"</string>
     <string name="battery_saver_sticky_description_new" product="device" msgid="5056520668081504111">"L\'estalvi de bateria es desactivarà quan el dispositiu tingui un <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <!-- no translation found for battery_saver_seekbar_title (7607123201469333645) -->
@@ -2561,7 +2566,7 @@
     <string name="fullbackup_data_summary" msgid="406274198094268556">"Crea còpies de seguretat automàtiques de les dades del dispositiu (com ara les contrasenyes de la Wi-Fi o l\'historial de trucades) i de les aplicacions (com ara les configuracions i els fitxers que desin) de manera remota.\n\nQuan activis les còpies de seguretat automàtiques, les dades dels dispositius i de les aplicacions s\'emmagatzemaran periòdicament de manera remota. Les dades de les aplicacions poden ser qualsevol mena de dada que hagi desat una aplicació (en funció de la configuració del desenvolupador), incloses les dades potencialment confidencials, com ara contactes, missatges i fotos."</string>
     <string name="device_admin_settings_title" msgid="2074319456047334589">"Configuració de l\'administrador del dispositiu"</string>
     <string name="active_device_admin_msg" msgid="6929247869516924549">"Aplicació d\'administració del dispositiu"</string>
-    <string name="remove_device_admin" msgid="4413438593788336400">"Desactiva aquesta aplicació d\'administració del dispositiu"</string>
+    <string name="remove_device_admin" msgid="4413438593788336400">"Desactiva l\'aplicació d\'administració d\'aquest dispositiu"</string>
     <string name="uninstall_device_admin" msgid="9017499299961719830">"Desinstal·la l\'aplicació"</string>
     <string name="remove_and_uninstall_device_admin" msgid="5607703579731496253">"Desactiva i desinstal·la"</string>
     <string name="select_device_admin_msg" msgid="4173769638399075387">"Aplicacions d\'administració del dispositiu"</string>
@@ -2666,7 +2671,7 @@
     <string name="data_usage_cellular_data_summary" msgid="9162777397135709280">"En pausa al límit"</string>
     <string name="account_settings_menu_auto_sync" msgid="2673669556006027506">"Sincronització automàtica de dades"</string>
     <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"Sincr. dades personals autom."</string>
-    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Sincron. dades feina automàt."</string>
+    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Sincr. dades treball autom."</string>
     <string name="data_usage_change_cycle" msgid="447761920472170031">"Canvia el cicle..."</string>
     <string name="data_usage_pick_cycle_day" msgid="6319750879145917066">"Dia del mes per restablir el cicle d\'ús de dades:"</string>
     <string name="data_usage_empty" msgid="7981405723435034032">"Cap aplicació no ha utilitzat dades en aquest període."</string>
@@ -2865,10 +2870,10 @@
     <string name="user_add_user_item_title" msgid="6835385073795492410">"Usuari"</string>
     <string name="user_add_profile_item_title" msgid="4932743891449790664">"Perfil restringit"</string>
     <string name="user_add_user_title" msgid="2320897397066676472">"Vols afegir un usuari nou?"</string>
-    <string name="user_add_user_message_long" msgid="686637203224195465">"Pots compartir aquest dispositiu amb altres usuaris creant usuaris addicionals. Cada usuari té el seu propi espai, que pot personalitzar amb aplicacions i fons de pantalla, entre d\'altres. Els usuaris també poden ajustar opcions de configuració del dispositiu, com ara la Wi-Fi, que afecten els altres usuaris.\n\nQuan afegeixis un usuari nou, haurà de configurar el seu espai.\n\nTots els usuaris poden actualitzar les aplicacions de la resta. És possible que la configuració i els serveis d\'accessibilitat no es transfereixin a l\'usuari nou."</string>
+    <string name="user_add_user_message_long" msgid="686637203224195465">"Pots compartir aquest dispositiu amb altres persones creant usuaris addicionals. Cada usuari té el seu propi espai, que pot personalitzar amb aplicacions i fons de pantalla, entre d\'altres. Els usuaris també poden ajustar opcions de configuració del dispositiu, com ara la Wi-Fi, que afecten els altres usuaris.\n\nQuan afegeixis un usuari nou, haurà de configurar el seu espai.\n\nTots els usuaris poden actualitzar les aplicacions de la resta. És possible que la configuració i els serveis d\'accessibilitat no es transfereixin a l\'usuari nou."</string>
     <string name="user_add_user_message_short" msgid="1802594476285458254">"Quan s\'afegeix un usuari nou, aquest usuari ha de configurar el seu espai.\n\nQualsevol usuari pot actualitzar les aplicacions dels altres usuaris."</string>
     <string name="user_setup_dialog_title" msgid="6748950002206392396">"Vols configurar l\'usuari ara?"</string>
-    <string name="user_setup_dialog_message" msgid="2988559933258353919">"Comprova que l\'usuari pugui accedir al dispositiu i configurar el seu espai."</string>
+    <string name="user_setup_dialog_message" msgid="2988559933258353919">"Assegura\'t que la persona estigui disponible per accedir al dispositiu i configurar el seu espai."</string>
     <string name="user_setup_profile_dialog_message" msgid="7611900802824048526">"Vols configurar el perfil ara?"</string>
     <string name="user_setup_button_setup_now" msgid="4941459406266856176">"Configura ara"</string>
     <string name="user_setup_button_setup_later" msgid="6596031428556518752">"Ara no"</string>
@@ -2917,10 +2922,10 @@
     <string name="nfc_payment_app_and_desc" msgid="102312684211458190">"<xliff:g id="APP">%1$s</xliff:g> - <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="nfc_payment_use_default" msgid="3098724195746409476">"Utilitza l\'aplicació predeterminada"</string>
     <string name="nfc_payment_favor_default" msgid="7555356982142464260">"Sempre"</string>
-    <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Excepte quan hi hagi oberta una altra aplicació de pagament"</string>
+    <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Excepte quan hi hagi oberta una altra aplicació per pagar"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"En un terminal que tingui la funció Toca i paga, paga amb:"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Pagar a la terminal"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Configura una aplicació de pagament. A continuació, apropa la part posterior del telèfon a un terminal amb el símbol de pagament sense contacte."</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Configura una aplicació per pagar. A continuació, apropa la part posterior del telèfon a un terminal amb el símbol de pagament sense contacte."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"Entesos"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"Més..."</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"Vols establir-ho com a preferència?"</string>
@@ -3135,7 +3140,7 @@
     <string name="alarm_volume_option_title" msgid="3184076022438477047">"Volum de l\'alarma"</string>
     <string name="ring_volume_option_title" msgid="2038924918468372264">"Volum del to"</string>
     <string name="notification_volume_option_title" msgid="1358512611511348260">"Volum de notificació"</string>
-    <string name="ringtone_title" msgid="1409086028485922583">"So de trucada"</string>
+    <string name="ringtone_title" msgid="1409086028485922583">"So de trucada del telèfon"</string>
     <string name="notification_ringtone_title" msgid="2932960620843976285">"So de notificació predeterminat"</string>
     <string name="notification_unknown_sound_title" msgid="8043718667804838398">"So de l\'aplicació"</string>
     <string name="notification_sound_default" msgid="2664544380802426260">"So de notificació predeterminat"</string>
@@ -3228,7 +3233,7 @@
     <string name="zen_mode_button_turn_on" msgid="1097964136225943415">"Activa ara"</string>
     <string name="zen_mode_button_turn_off" msgid="3990967728457149454">"Desactiva ara"</string>
     <string name="zen_mode_settings_dnd_manual_end_time" msgid="4307574188962071429">"El mode No molestis està activat fins a les <xliff:g id="FORMATTED_TIME">%s</xliff:g>"</string>
-    <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"El mode No molestis continuarà activat fins que no el desactivis"</string>
+    <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"El mode No molestis es manté activat fins que no el desactivis"</string>
     <string name="zen_mode_settings_dnd_automatic_rule" msgid="2843297614114625408">"Una programació (<xliff:g id="RULE_NAME">%s</xliff:g>) ha activat automàticament el mode No molestis"</string>
     <string name="zen_mode_settings_dnd_automatic_rule_app" msgid="5103454923160912313">"Una aplicació (<xliff:g id="APP_NAME">%s</xliff:g>) ha activat automàticament el mode No molestis"</string>
     <string name="zen_mode_settings_dnd_custom_settings_footer" msgid="6335108298640066560">"El mode No molestis està activat per a <xliff:g id="RULE_NAMES">%s</xliff:g> amb una configuració personalitzada."</string>
@@ -3380,7 +3385,7 @@
     <string name="display_vr_pref_low_persistence" msgid="3132583929174794245">"Redueix el desenfocament (recomanat)"</string>
     <string name="display_vr_pref_off" msgid="4681320968818852691">"Redueix el parpelleig"</string>
     <string name="picture_in_picture_title" msgid="4960733106166035448">"Pantalla en pantalla"</string>
-    <string name="picture_in_picture_empty_text" msgid="8664071475324685241">"Cap de les aplicacions instal·lades no admet la funció de pantalla en pantalla"</string>
+    <string name="picture_in_picture_empty_text" msgid="8664071475324685241">"Cap de les aplicacions instal·lades no admet pantalla en pantalla"</string>
     <string name="picture_in_picture_keywords" msgid="7326958702002259262">"pip imatge en"</string>
     <string name="picture_in_picture_app_detail_title" msgid="3916189052657425936">"Pantalla en pantalla"</string>
     <string name="picture_in_picture_app_detail_switch" msgid="747422998967185418">"Permet Pantalla en pantalla"</string>
@@ -3543,7 +3548,7 @@
     <string name="zen_mode_screen_off" msgid="84211490206459038">"Quan la pantalla estigui apagada"</string>
     <string name="zen_mode_screen_off_summary" msgid="8592179073243001267">"Permet que les notificacions silenciades pel mode No molestis encenguin la pantalla i facin parpellejar el llum"</string>
     <string name="zen_mode_screen_off_summary_no_led" msgid="7255874108150630145">"Permet que les notificacions silenciades pel mode No molestis encenguin la pantalla"</string>
-    <string name="notification_app_settings_button" msgid="3651180424198580907">"Configuració de les notificacions"</string>
+    <string name="notification_app_settings_button" msgid="3651180424198580907">"Configuració de notificacions"</string>
     <string name="suggestion_button_text" msgid="5783566542423813847">"D\'acord"</string>
     <string name="device_feedback" msgid="4042352891448769818">"Envia suggeriments sobre el dispositiu"</string>
     <string name="restr_pin_enter_admin_pin" msgid="8577847751493521230">"Introdueix el PIN d\'administrador"</string>
@@ -3692,7 +3697,7 @@
     <string name="high_power_apps" msgid="2518319744362028920">"Optimització de la bateria"</string>
     <string name="additional_battery_info" msgid="6877663897819271203">"Alertes d\'ús"</string>
     <string name="show_all_apps" msgid="5442552004569634846">"Mostra l\'ús complet del dispositiu"</string>
-    <string name="hide_extra_apps" msgid="6798261081113299441">"Mostra ús de les aplicacions"</string>
+    <string name="hide_extra_apps" msgid="6798261081113299441">"Mostra l\'ús de les aplicacions"</string>
     <plurals name="power_high_usage_summary" formatted="false" msgid="4658343710126205199">
       <item quantity="other"><xliff:g id="NUMBER">%2$d</xliff:g> aplicacions s\'estan comportant de manera anòmala</item>
       <item quantity="one"><xliff:g id="APP">%1$s</xliff:g> s\'està comportant de manera anòmala</item>
@@ -3741,7 +3746,7 @@
     <string name="usb_control_device" msgid="9154790265254725254">"Aquest dispositiu"</string>
     <string name="usb_switching" msgid="1230386065163529904">"S\'està canviant..."</string>
     <string name="usb_switching_failed" msgid="6857722544186145439">"No s\'ha pogut canviar"</string>
-    <string name="usb_summary_charging_only" msgid="4118449308708872339">"Càrrega del dispositiu"</string>
+    <string name="usb_summary_charging_only" msgid="4118449308708872339">"Càrregant el dispositiu"</string>
     <string name="usb_summary_power_only" msgid="3552240122641051107">"Càrrega de dispositius connectats"</string>
     <string name="usb_summary_file_transfers" msgid="7805342797099821502">"Transferència de fitxers"</string>
     <string name="usb_summary_tether" msgid="778845069037366883">"Compartició de xarxa per USB"</string>
@@ -3758,7 +3763,7 @@
     <string name="assist_access_screenshot_title" msgid="1991014038776117688">"Utilitza una captura de pantalla"</string>
     <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Permet que l\'aplicació d\'assistència accedeixi a una imatge de la pantalla"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"Fes centellejar la pantalla"</string>
-    <string name="assist_flash_summary" msgid="6697095786317559129">"Fa centellejar les vores de la pantalla quan l\'aplicació d\'assistència accedeix al text d\'una pantalla o d\'una captura de pantalla"</string>
+    <string name="assist_flash_summary" msgid="6697095786317559129">"Fa centellejar les vores de la pantalla quan l\'aplicació d\'assistència accedeix al text de la pantalla o a la captura de pantalla"</string>
     <string name="assist_footer" msgid="7030121180457472165">"Les aplicacions d\'assistència et poden ajudar en funció de la informació que es mostri a la pantalla. Algunes aplicacions admeten tant el menú d\'aplicacions com els serveis d\'entrada de veu per oferir-te una assistència integrada."</string>
     <string name="average_memory_use" msgid="5333366040118953945">"Ús mitjà de la memòria"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"Ús màxim de la memòria"</string>
@@ -3854,10 +3859,10 @@
     <string name="apps_summary" msgid="8355759446490212195">"S\'han instal·lat <xliff:g id="COUNT">%1$d</xliff:g> aplicacions"</string>
     <string name="apps_summary_example" msgid="3011143598675185269">"24 aplicacions instal·lades"</string>
     <string name="storage_summary" msgid="4835916510511133784">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> utilitzat - <xliff:g id="FREE_SPACE">%2$s</xliff:g> lliures"</string>
-    <string name="storage_summary_with_sdcard" msgid="8742907204848352697">"Emmagatzematge intern: <xliff:g id="PERCENTAGE">%1$s</xliff:g> utilitzat, <xliff:g id="FREE_SPACE">%2$s</xliff:g> lliure"</string>
+    <string name="storage_summary_with_sdcard" msgid="8742907204848352697">"Emmagatzematge intern: <xliff:g id="PERCENTAGE">%1$s</xliff:g> utilitzat, <xliff:g id="FREE_SPACE">%2$s</xliff:g> lliures"</string>
     <string name="display_summary" msgid="5725269449657325797">"Entra en repòs després de <xliff:g id="TIMEOUT_DESCRIPTION">%1$s</xliff:g> d\'inactivitat"</string>
     <string name="display_dashboard_summary" msgid="7678566148167010682">"Fons de pantalla, repòs, mida de la lletra"</string>
-    <string name="display_dashboard_summary_with_style" msgid="8981059474501210956">"Estils i fons de pantalla, repòs, mida de la lletra"</string>
+    <string name="display_dashboard_summary_with_style" msgid="8981059474501210956">"Estils i fons de pantalla, repòs, mida del tipus de lletra"</string>
     <string name="display_dashboard_nowallpaper_summary" msgid="8612534364908229000">"Repòs, mida de la lletra"</string>
     <string name="display_summary_example" msgid="4555020581960719296">"Entra en repòs després de 10 minuts d\'inactivitat"</string>
     <string name="memory_summary" msgid="9121871336058042600">"Ús mitjà de memòria: <xliff:g id="USED_MEMORY">%1$s</xliff:g> de <xliff:g id="TOTAL_MEMORY">%2$s</xliff:g>"</string>
@@ -3952,7 +3957,7 @@
     <string name="data_used_template" msgid="761605393453849477">"Dades utilitzades: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="set_data_warning" msgid="8115980184415563941">"Defineix advertiment de dades"</string>
     <string name="data_warning" msgid="2699207195535036240">"Advertiment de dades"</string>
-    <string name="data_warning_footnote" msgid="965724845580257305">"L\'advertiment de dades i el límit de dades es basen en els càlculs del dispositiu, que és possible que no coincideixin amb les dades de l\'operador."</string>
+    <string name="data_warning_footnote" msgid="965724845580257305">"L\'advertiment de dades i el límit de dades es basen en els càlculs del dispositiu, i és possible que no coincideixin amb les dades de l\'operador."</string>
     <string name="set_data_limit" msgid="5043770023229990674">"Defineix un límit de dades"</string>
     <string name="data_limit" msgid="5793521160051596228">"Límit de dades"</string>
     <string name="data_usage_template" msgid="6848274347956096882">"Dades utilitzades: <xliff:g id="ID_1">%1$s</xliff:g> (<xliff:g id="ID_2">%2$s</xliff:g>)"</string>
@@ -4116,12 +4121,12 @@
     <string name="swipe_up_to_switch_apps_suggestion_title" msgid="7641846365137536128">"Prova el botó d\'inici nou"</string>
     <string name="swipe_up_to_switch_apps_suggestion_summary" msgid="7338653224520387852">"Activa el gest nou per canviar d\'aplicació"</string>
     <string name="ambient_display_title" product="default" msgid="6785677099744344088">"Doble toc per consultar el telèfon"</string>
-    <string name="ambient_display_title" product="tablet" msgid="1106285490888683613">"Per consultar la tauleta, fes-hi doble toc"</string>
-    <string name="ambient_display_title" product="device" msgid="5064644474876041478">"Per consultar el dispositiu, fes-hi doble toc"</string>
+    <string name="ambient_display_title" product="tablet" msgid="1106285490888683613">"Doble toc per consultar la tauleta"</string>
+    <string name="ambient_display_title" product="device" msgid="5064644474876041478">"Doble toc per consultar el dispositiu"</string>
     <string name="ambient_display_summary" msgid="4882910328216411109">"Per veure l\'hora, les notificacions i altres dades, fes doble toc a la pantalla."</string>
-    <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"Aixeca per consultar-lo"</string>
-    <string name="ambient_display_pickup_title" product="tablet" msgid="1555456400210301959">"Per consultar la tauleta, aixeca-la"</string>
-    <string name="ambient_display_pickup_title" product="device" msgid="2480126522988135037">"Aixeca el dispositiu per consultar-lo"</string>
+    <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"Aixeca per consultar el telèfon"</string>
+    <string name="ambient_display_pickup_title" product="tablet" msgid="1555456400210301959">"Aixeca per consultar la tauleta"</string>
+    <string name="ambient_display_pickup_title" product="device" msgid="2480126522988135037">"Aixeca per consultar el dispositiu"</string>
     <string name="ambient_display_wake_screen_title" msgid="3376988352851077102">"Activa la pantalla"</string>
     <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"Per veure l\'hora, les notificacions i altres dades, agafa el telèfon."</string>
     <string name="ambient_display_pickup_summary" product="tablet" msgid="1077745287100012928">"Per veure l\'hora, les notificacions i altres dades, agafa la tauleta."</string>
@@ -4305,7 +4310,7 @@
     <string name="change_wifi_state_title" msgid="5140754955787584174">"Control de la Wi-Fi"</string>
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"Permet que l\'aplicació controli la Wi-Fi"</string>
     <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"Permet que aquesta aplicació activi o desactivi la Wi-Fi, cerqui xarxes Wi-Fi, s\'hi connecti, n\'afegeixi o en suprimeixi, o que iniciï un punt d\'accés Wi-Fi només local"</string>
-    <string name="media_output_title" msgid="8710632337456601848">"Reprodueix el contingut multimèdia a"</string>
+    <string name="media_output_title" msgid="8710632337456601848">"Reprodueix contingut multimèdia a"</string>
     <string name="media_output_default_summary" msgid="3159237976830415584">"Aquest dispositiu"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"Telèfon"</string>
     <string name="media_output_summary" product="tablet" msgid="6672024060360538526">"Tauleta"</string>
@@ -4321,7 +4326,7 @@
     <string name="gesture_prevent_ringing_screen_title" msgid="4173494225145223638">"Impedeix els sons"</string>
     <string name="gesture_prevent_ringing_title" msgid="8827963588425673557">"Prem els botons d\'engegada i d\'apujar el volum alhora per"</string>
     <string name="gesture_prevent_ringing_sound_title" msgid="8642330448721033641">"Drecera per impedir que soni"</string>
-    <string name="prevent_ringing_option_vibrate" msgid="6456505293904544108">"Activar la vibració"</string>
+    <string name="prevent_ringing_option_vibrate" msgid="6456505293904544108">"Vibrar"</string>
     <string name="prevent_ringing_option_mute" msgid="53662688921253613">"Silenciar"</string>
     <string name="prevent_ringing_option_none" msgid="1450985763137666231">"No fer res"</string>
     <string name="prevent_ringing_option_vibrate_summary" msgid="7961818570574683926">"Activat (vibració)"</string>
@@ -4440,7 +4445,7 @@
     <string name="mobile_network_mode_error" msgid="6818434186286086554">"El mode de xarxa <xliff:g id="NETWORKMODEID">%1$d</xliff:g> no és vàlid. Ignora."</string>
     <string name="mobile_network_apn_title" msgid="5628635067747404382">"Noms de punts d\'accés"</string>
     <string name="manual_mode_disallowed_summary" msgid="799800630000340665">"No està disponible quan està connectat a <xliff:g id="CARRIER">%1$s</xliff:g>"</string>
-    <string name="emergency_info_contextual_card_summary" msgid="5541444321969803486">"Informació mèdica, contactes d\'emergència"</string>
+    <string name="emergency_info_contextual_card_summary" msgid="5541444321969803486">"Informació mèdica i contactes d\'emergència"</string>
     <string name="see_more" msgid="7463940160389802632">"Mostra\'n més"</string>
     <string name="see_less" msgid="3718892257002813387">"Mostra\'n menys"</string>
     <string name="network_connection_request_dialog_title" msgid="3150489262902506588">"Dispositiu per fer servir amb <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
@@ -4472,7 +4477,7 @@
     <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"Vols suprimir aquest suggeriment?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"S\'ha suprimit el suggeriment"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"Desfés"</string>
-    <string name="low_storage_summary" msgid="4562224870189133400">"Queda poc espai d\'emmagatzematge: <xliff:g id="PERCENTAGE">%1$s</xliff:g> utilitzat; <xliff:g id="FREE_SPACE">%2$s</xliff:g> lliure"</string>
+    <string name="low_storage_summary" msgid="4562224870189133400">"Queda poc espai d\'emmagatzematge: <xliff:g id="PERCENTAGE">%1$s</xliff:g> utilitzat; <xliff:g id="FREE_SPACE">%2$s</xliff:g> lliures"</string>
     <string name="contextual_card_feedback_send" msgid="8698649023854350623">"Envia suggeriments"</string>
     <string name="contextual_card_feedback_confirm_message" msgid="3987973028353264878">"Vols enviar-nos algun comentari sobre aquest suggeriment?"</string>
     <string name="copyable_slice_toast" msgid="1357518174923789947">"S\'ha copiat <xliff:g id="COPY_CONTENT">%1$s</xliff:g> al porta-retalls."</string>
diff --git a/tests/CarDeveloperOptions/res/values-cs/arrays.xml b/tests/CarDeveloperOptions/res/values-cs/arrays.xml
index 815a6f0..88ea3e6 100644
--- a/tests/CarDeveloperOptions/res/values-cs/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-cs/arrays.xml
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"Nepovolit nikdy"</item>
     <item msgid="8184570120217958741">"Vždy povolit"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normální"</item>
+    <item msgid="5101233285497327432">"Střední"</item>
+    <item msgid="1555861583162930714">"Nízká"</item>
+    <item msgid="1719683776264798117">"Kritické"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normální"</item>
+    <item msgid="6107138933849816768">"Střední"</item>
+    <item msgid="182695359839047859">"Nízká"</item>
+    <item msgid="8577246509202964244">"Kritické"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Trvalé"</item>
     <item msgid="167418068739176448">"Nejvyšší aktivita"</item>
@@ -467,7 +477,7 @@
     <item msgid="1008268820118852416">"Považovat za neměřenou síť"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
-    <item msgid="6545683814310036454">"Použít náhodně vygenerovanou adresu MAC"</item>
+    <item msgid="6545683814310036454">"Použít náhodnou MAC (výchozí)"</item>
     <item msgid="214234417308375326">"Použít adresu MAC zařízení"</item>
   </string-array>
   <string-array name="wifi_hidden_entries">
diff --git a/tests/CarDeveloperOptions/res/values-cs/config.xml b/tests/CarDeveloperOptions/res/values-cs/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-cs/config.xml
+++ b/tests/CarDeveloperOptions/res/values-cs/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-cs/strings.xml b/tests/CarDeveloperOptions/res/values-cs/strings.xml
index d3caaf0..ad8cb3f 100644
--- a/tests/CarDeveloperOptions/res/values-cs/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-cs/strings.xml
@@ -85,8 +85,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Umožňuje zvětšit nebo zmenšit text na obrazovce."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Zmenšit"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Zvětšit"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Příliš žluťoučký kůň úpěl ďábelské ódy."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Ukázkový text"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Čaroděj ze země Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Kapitola 11: Smaragdové město v zemi Oz"</string>
@@ -684,7 +683,6 @@
       <item quantity="other">Musí obsahovat méně než <xliff:g id="NUMBER_1">%d</xliff:g> číslic</item>
       <item quantity="one">Musí obsahovat méně než <xliff:g id="NUMBER_0">%d</xliff:g> číslici</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"PIN smí obsahovat pouze číslice 0 až 9."</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Administrátor zařízení nedovoluje použití nedávno použitého kódu PIN"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Obvyklé kódy PIN jsou blokovány administrátorem IT. Použijte jiný PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Heslo nesmí obsahovat neplatné znaky."</string>
@@ -727,6 +725,12 @@
       <item quantity="other">Heslo musí obsahovat alespoň <xliff:g id="COUNT">%d</xliff:g> znaků jiných než písmeno</item>
       <item quantity="one">Heslo musí obsahovat alespoň 1 znak jiný než písmeno</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="few">Musí obsahovat alespoň <xliff:g id="COUNT">%d</xliff:g> znaky jiné než číslice</item>
+      <item quantity="many">Musí obsahovat alespoň <xliff:g id="COUNT">%d</xliff:g> znaku jiného než číslici</item>
+      <item quantity="other">Musí obsahovat alespoň <xliff:g id="COUNT">%d</xliff:g> znaků jiných než číslici</item>
+      <item quantity="one">Musí obsahovat alespoň 1 znak jiný než číslici</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Administrátor zařízení neumožňuje použít heslo, které jste použili nedávno"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Obvyklá hesla jsou blokována administrátorem IT. Použijte jiné heslo."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Posloupnost rostoucích, klesajících nebo opakujících se číslic není povolena"</string>
@@ -799,7 +803,7 @@
     <string name="bluetooth_scanning_on_info_message" msgid="5460370815156050550">"Když je zapnuté připojení Bluetooth, zařízení může komunikovat s ostatními zařízeními Bluetooth v okolí.\n\nZa účelem vylepšení funkcí mohou aplikace a služby nadále vyhledávat zařízení v okolí, i když je Bluetooth vypnuté. Lze tak například vylepšit funkce založené na poloze. Toto chování můžete změnit v "<annotation id="link">"nastavení vyhledávání"</annotation>"."</string>
     <string name="ble_scan_notify_text" msgid="6290170236546386932">"Za účelem zvýšení přesnosti určování polohy mohou systémové aplikace a služby neustále vyhledávat zařízení Bluetooth. Toto chování můžete změnit v <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>nastavení vyhledávání<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
     <string name="bluetooth_connect_failed" msgid="1151234676456333786">"Nelze se připojit. Zkuste to znovu."</string>
-    <string name="device_details_title" msgid="726517818032923222">"Podrobnosti o zařízení"</string>
+    <string name="device_details_title" msgid="726517818032923222">"O zařízení"</string>
     <string name="bluetooth_device_mac_address" msgid="5328203122581150405">"Adresa Bluetooth zařízení: <xliff:g id="ADDRESS">%1$s</xliff:g>"</string>
     <string name="bluetooth_unpair_dialog_title" msgid="3669848977755142047">"Zapomenout zařízení?"</string>
     <string name="bluetooth_unpair_dialog_body" product="default" msgid="5998071227980078077">"Telefon již nebude spárován se zařízením <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
@@ -1134,7 +1138,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mobilní"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Pokud Wi-Fi není k dispozici, použít mobilní síť"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Pokud mobilní síť nebude k dispozici, použít Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Volání přes Wi‑Fi. Pokud bude signál Wi-Fi ztracen, hovor skončí."</string>
@@ -2332,7 +2339,7 @@
     <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Baterie se možná vybije dříve než obvykle"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Spořič baterie je zapnutý"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Některé funkce mohou být omezeny"</string>
-    <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Telefon byl využíván víc než obvykle"</string>
+    <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Telefon využíván víc než obvykle"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"Tablet byl využíván víc než obvykle"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"Zařízení bylo využíváno víc než obvykle"</string>
     <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"Baterie se možná vybije dříve než obvykle"</string>
@@ -2736,7 +2743,7 @@
     <string name="data_usage_cellular_data_summary" msgid="9162777397135709280">"Pozastaveno při limitu"</string>
     <string name="account_settings_menu_auto_sync" msgid="2673669556006027506">"Autom. synchronizovat data"</string>
     <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"Autom. synch. osobní data"</string>
-    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Autom. synch. pracovní data"</string>
+    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Autosynchronizace pracovních dat"</string>
     <string name="data_usage_change_cycle" msgid="447761920472170031">"Změnit cyklus..."</string>
     <string name="data_usage_pick_cycle_day" msgid="6319750879145917066">"Den v měsíci, kdy se má obnovit počítání datových přenosů:"</string>
     <string name="data_usage_empty" msgid="7981405723435034032">"V tomto období nevyužily datové připojení žádné aplikace."</string>
@@ -3402,7 +3409,7 @@
     <string name="notification_pulse_title" msgid="4861418327614907116">"Blikání kontrolky"</string>
     <string name="lock_screen_notifications_title" msgid="6889072265118747835">"Na obrazovce uzamčení"</string>
     <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"Když je profil uzamčen"</string>
-    <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Zobrazit veškerý obsah oznámení"</string>
+    <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Zobrazovat veškerý obsah oznámení"</string>
     <string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"Skrýt citlivý obsah"</string>
     <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"Oznámení vůbec nezobrazovat"</string>
     <string name="lock_screen_notifications_interstitial_message" msgid="4230189215124387818">"Jak chcete zobrazovat oznámení, když bude zařízení uzamčeno?"</string>
@@ -3422,11 +3429,11 @@
     <string name="notification_importance_low" msgid="7609797151662295364">"Zobrazovat tiše"</string>
     <string name="notification_importance_default" msgid="4091563759103917166">"Vydat zvukový signál"</string>
     <string name="notification_importance_high" msgid="7973764540402436656">"Vydat zvukový signál a vyskočit na obrazovku"</string>
-    <string name="notification_importance_high_silent" msgid="3177662759865661155">"Vyskočit na obrazovce"</string>
+    <string name="notification_importance_high_silent" msgid="3177662759865661155">"Vyskakování na obrazovce"</string>
     <string name="notification_importance_min_title" msgid="705872537330744154">"Minimalizovat"</string>
     <string name="notification_importance_low_title" msgid="2956199021781786232">"Střední"</string>
     <string name="notification_importance_default_title" msgid="7985549807203332482">"Vysoká"</string>
-    <string name="notification_importance_high_title" msgid="7258373094258585858">"Vyskočit na obrazovce"</string>
+    <string name="notification_importance_high_title" msgid="7258373094258585858">"Vyskakování na obrazovce"</string>
     <string name="notification_block_title" msgid="2570364198866886906">"Blok"</string>
     <string name="notification_silence_title" msgid="6959637402003838093">"Zobrazovat tiše"</string>
     <string name="notification_alert_title" msgid="750683027055192648">"Upozornění"</string>
@@ -3801,7 +3808,7 @@
     <string name="memory_avg_desc" msgid="1200185697910086968">"Průměrně <xliff:g id="MEMORY">%1$s</xliff:g>"</string>
     <string name="memory_use_running_format" msgid="3741170402563292232">"<xliff:g id="MEMORY">%1$s</xliff:g> / <xliff:g id="RUNNING">%2$s</xliff:g>"</string>
     <string name="process_format" msgid="8575347150598564509">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="COUNT">%2$d</xliff:g>)"</string>
-    <string name="high_power_apps" msgid="2518319744362028920">"Optimalizace výdrže bat."</string>
+    <string name="high_power_apps" msgid="2518319744362028920">"Optimalizace baterie"</string>
     <string name="additional_battery_info" msgid="6877663897819271203">"Upozornění na využití"</string>
     <string name="show_all_apps" msgid="5442552004569634846">"Zobrazit úplné využití zařízení"</string>
     <string name="hide_extra_apps" msgid="6798261081113299441">"Zobrazit využití aplikací"</string>
@@ -3875,7 +3882,7 @@
     <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Asistenční aplikace bude mít přístup k obrazu na obrazovce"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"Zablikání obrazovky"</string>
     <string name="assist_flash_summary" msgid="6697095786317559129">"Když asistenční aplikace z obrazovky nebo snímku obrazovky získá text, okraje obrazovky zablikají"</string>
-    <string name="assist_footer" msgid="7030121180457472165">"Asistenční aplikace vám může pomoci na základě informací na zobrazené obrazovce. Některé aplikace podporují Launcher i hlasový vstup a nabízejí integrovanou asistenci."</string>
+    <string name="assist_footer" msgid="7030121180457472165">"Asistenční aplikace vám mohou pomoci na základě informací na zobrazené obrazovce. Některé aplikace podporují Launcher i hlasový vstup a nabízejí integrovanou asistenci."</string>
     <string name="average_memory_use" msgid="5333366040118953945">"Průměrné využití paměti"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"Maximální využití paměti"</string>
     <string name="memory_usage" msgid="7963253555330830906">"Využití paměti"</string>
@@ -3986,7 +3993,7 @@
     <string name="backup_disabled" msgid="6941165814784765643">"Zálohování bylo zakázáno"</string>
     <string name="android_version_summary" msgid="2192751442789395445">"Aktualizováno na Android <xliff:g id="VERSION">%1$s</xliff:g>"</string>
     <string name="android_version_pending_update_summary" msgid="3554543810520655076">"K dispozici je aktualizace"</string>
-    <string name="disabled_by_policy_title" msgid="1238318274952958846">"Akce není povolena."</string>
+    <string name="disabled_by_policy_title" msgid="1238318274952958846">"Akce není povolena"</string>
     <string name="disabled_by_policy_title_adjust_volume" msgid="7094547090629203316">"Hlasitost nelze změnit"</string>
     <string name="disabled_by_policy_title_outgoing_calls" msgid="3805836913095496278">"Volání není povoleno"</string>
     <string name="disabled_by_policy_title_sms" msgid="1453236584236681105">"Zprávy SMS nejsou povoleny"</string>
@@ -4177,7 +4184,7 @@
     <string name="display_cutout_emulation_keywords" msgid="6795671536772871439">"výřez displeje"</string>
     <string name="overlay_option_device_default" msgid="165508753381657697">"Výchozí nastavení zařízení"</string>
     <string name="overlay_toast_failed_to_apply" msgid="5692251825129250040">"Překrytí se nepodařilo použít"</string>
-    <string name="special_access" msgid="1453926335914696206">"Přístup ke spec. aplikacím"</string>
+    <string name="special_access" msgid="1453926335914696206">"Přístupy pro aplikace"</string>
     <plurals name="special_access_summary" formatted="false" msgid="5182092345063909346">
       <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> aplikace mohou využívat neomezená data</item>
       <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> aplikace může využívat neomezená data</item>
@@ -4268,8 +4275,8 @@
     <string name="ambient_display_tap_screen_title" product="tablet" msgid="6434521782016864148">"Kontrola tabletu klepnutím"</string>
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"Kontrola zařízení klepnutím"</string>
     <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"Chcete-li zobrazit čas, oznámení a další informace, klepněte na obrazovku."</string>
-    <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"Otisk prstu pro oznámení"</string>
-    <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"Přejeďte po otisku"</string>
+    <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"Sejmout otisk prstu pro zobrazení oznámení"</string>
+    <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"Sejmout otisk prstu"</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"Chcete-li zkontrolovat oznámení, přejeďte prstem dolů po snímači otisků prstů na zadní straně telefonu."</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="tablet" msgid="3480057984564476283">"Chcete-li zkontrolovat oznámení, přejeďte prstem dolů po snímači otisků prstů na zadní straně tabletu."</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="device" msgid="7950264130913070035">"Chcete-li zkontrolovat oznámení, přejeďte prstem dolů po snímači otisků prstů na zadní straně zařízení."</string>
@@ -4457,7 +4464,7 @@
     <string name="change_wifi_state_title" msgid="5140754955787584174">"Ovládání sítí Wi-Fi"</string>
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"Povolit aplikaci ovládat Wi-Fi"</string>
     <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"Povolte této aplikaci zapínat a vypínat Wi-Fi, vyhledávat sítě Wi-Fi a připojovat se k nim, přidávat nebo odstraňovat sítě nebo nastavit místní hotspot"</string>
-    <string name="media_output_title" msgid="8710632337456601848">"Přehrávat média v"</string>
+    <string name="media_output_title" msgid="8710632337456601848">"Kde přehrávat média"</string>
     <string name="media_output_default_summary" msgid="3159237976830415584">"Toto zařízení"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"Telefon"</string>
     <string name="media_output_summary" product="tablet" msgid="6672024060360538526">"Tablet"</string>
@@ -4471,7 +4478,7 @@
     <string name="battery_suggestion_title" product="default" msgid="3295786171830183688">"Zvyšte životnost baterie telefonu"</string>
     <string name="battery_suggestion_summary" msgid="2669070349482656490"></string>
     <string name="gesture_prevent_ringing_screen_title" msgid="4173494225145223638">"Blokování vyzvánění"</string>
-    <string name="gesture_prevent_ringing_title" msgid="8827963588425673557">"Stisknutí vypínače a zvýšení hlasitosti znamená:"</string>
+    <string name="gesture_prevent_ringing_title" msgid="8827963588425673557">"Současné stisknutí vypínače a tlačítka zvýšení hlasitosti umožní:"</string>
     <string name="gesture_prevent_ringing_sound_title" msgid="8642330448721033641">"Zkratka k vypnutí vyzvánění"</string>
     <string name="prevent_ringing_option_vibrate" msgid="6456505293904544108">"Vibrovat"</string>
     <string name="prevent_ringing_option_mute" msgid="53662688921253613">"Ztlumit"</string>
@@ -4628,7 +4635,7 @@
     <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"Odstranit tento návrh?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"Návrh byl odebrán"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"Zpět"</string>
-    <string name="low_storage_summary" msgid="4562224870189133400">"V úložišti je málo místa. Využito <xliff:g id="PERCENTAGE">%1$s</xliff:g> – volné místo: <xliff:g id="FREE_SPACE">%2$s</xliff:g>"</string>
+    <string name="low_storage_summary" msgid="4562224870189133400">"Málo místa. Využito: <xliff:g id="PERCENTAGE">%1$s</xliff:g> – volné: <xliff:g id="FREE_SPACE">%2$s</xliff:g>"</string>
     <string name="contextual_card_feedback_send" msgid="8698649023854350623">"Odeslat zpětnou vazbu"</string>
     <string name="contextual_card_feedback_confirm_message" msgid="3987973028353264878">"Chtěli byste nám k tomuto návrhu poskytnout zpětnou vazbu?"</string>
     <string name="copyable_slice_toast" msgid="1357518174923789947">"<xliff:g id="COPY_CONTENT">%1$s</xliff:g> – zkopírováno do schránky"</string>
diff --git a/tests/CarDeveloperOptions/res/values-da/arrays.xml b/tests/CarDeveloperOptions/res/values-da/arrays.xml
index 11985ea..63b7058 100644
--- a/tests/CarDeveloperOptions/res/values-da/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-da/arrays.xml
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"Tillad aldrig"</item>
     <item msgid="8184570120217958741">"Tillad altid"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Moderat"</item>
+    <item msgid="1555861583162930714">"Lav"</item>
+    <item msgid="1719683776264798117">"Kritisk"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normal"</item>
+    <item msgid="6107138933849816768">"Moderat"</item>
+    <item msgid="182695359839047859">"Lav"</item>
+    <item msgid="8577246509202964244">"Kritisk"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Vedvarende"</item>
     <item msgid="167418068739176448">"Topaktivitet"</item>
diff --git a/tests/CarDeveloperOptions/res/values-da/config.xml b/tests/CarDeveloperOptions/res/values-da/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-da/config.xml
+++ b/tests/CarDeveloperOptions/res/values-da/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-da/strings.xml b/tests/CarDeveloperOptions/res/values-da/strings.xml
index beadd32..fa6457c 100644
--- a/tests/CarDeveloperOptions/res/values-da/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-da/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Gør teksten på skærmen mindre eller større."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Formindsk"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Forstør"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Eksempeltekst"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Den vidunderlige troldmand fra Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Kapitel 11: Den vidunderlige smaragdby i Oz"</string>
@@ -504,7 +503,7 @@
     <string name="fingerprint_delete_message" msgid="5895802741486967970">"Vil du slette dette fingeraftryk?"</string>
     <string name="fingerprint_last_delete_message" msgid="3346252479778971442">"Du vil ikke kunne bruge dine fingeraftryk til at låse din telefon op, godkende køb eller logge ind på apps"</string>
     <string name="fingerprint_last_delete_message_profile_challenge" msgid="5385095150532247025">"Du vil ikke kunne bruge dine fingeraftryk til at låse din arbejdsprofil op, godkende køb eller logge ind på arbejdsapps"</string>
-    <string name="fingerprint_last_delete_confirm" msgid="7984595457589664004">"Ja, fjern det"</string>
+    <string name="fingerprint_last_delete_confirm" msgid="7984595457589664004">"Ja, fjern"</string>
     <string name="crypt_keeper_settings_title" msgid="839783588093862748">"Kryptering"</string>
     <string name="crypt_keeper_encrypt_title" product="tablet" msgid="2292129135369853167">"Krypter tablet"</string>
     <string name="crypt_keeper_encrypt_title" product="default" msgid="3110852053238357832">"Kryptér telefon"</string>
@@ -668,7 +667,6 @@
       <item quantity="one">Skal indeholde færre end <xliff:g id="NUMBER_1">%d</xliff:g> ciffer</item>
       <item quantity="other">Skal indeholde færre end <xliff:g id="NUMBER_1">%d</xliff:g> cifre</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Må kun indeholde tallene 0-9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Enhedens administrator tillader ikke brug af en nylig brugt pinkode"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Brug af almindelige pinkoder er blokeret af din it-administrator. Prøv en anden pinkode."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Der kan ikke bruges et ugyldigt tegn"</string>
@@ -699,6 +697,10 @@
       <item quantity="one">Skal indeholde mindst <xliff:g id="COUNT">%d</xliff:g> tegn, der ikke er et bogstav</item>
       <item quantity="other">Skal indeholde mindst <xliff:g id="COUNT">%d</xliff:g> tegn, der ikke er bogstaver</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">Skal indeholde mindst <xliff:g id="COUNT">%d</xliff:g> tegn, som ikke er et tal</item>
+      <item quantity="other">Skal indeholde mindst <xliff:g id="COUNT">%d</xliff:g> tegn, som ikke er et tal</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Enhedens administrator tillader ikke brug af en nylig brugt adgangskode"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Brug af almindelige adgangskoder er blokeret af din it-administrator. Prøv en anden adgangskode."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Stigende eller faldende talsekvens og gentagne tal er ikke tilladt"</string>
@@ -907,7 +909,7 @@
     <string name="wifi_signal" msgid="696548364467704808">"Signalstyrke"</string>
     <string name="wifi_status" msgid="3439931558930689940">"Status"</string>
     <string name="tx_wifi_speed" msgid="2571810085003261073">"Overførselshastighed"</string>
-    <string name="rx_wifi_speed" msgid="7392873246110937187">"Modtag linkhastighed"</string>
+    <string name="rx_wifi_speed" msgid="7392873246110937187">"Modtagelseshastighed"</string>
     <string name="wifi_frequency" msgid="6132852924995724246">"Frekvens"</string>
     <string name="wifi_ip_address" msgid="5572539114989914831">"IP-adresse"</string>
     <string name="passpoint_label" msgid="7429247462404128615">"Gemt via"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mobil"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Brug mobilnetværk, hvis der ikk er nogen Wi-Fi-forbindelse"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Brug Wi-Fi, hvis mobilnetværket ikke er tilgængeligt"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Ring via Wi‑Fi. Opkaldet afsluttes, hvis Wi-Fi-forbindelsen afbrydes."</string>
@@ -2043,7 +2048,7 @@
     <string name="experimental_category_title" msgid="3797000069740110717">"Eksperimentel"</string>
     <string name="feature_flags_dashboard_title" msgid="3153034144122754381">"Aktivering og deaktivering af demofunktioner"</string>
     <string name="talkback_title" msgid="3717960404234260050">"TalkBack"</string>
-    <string name="talkback_summary" msgid="6602857105831641574">"Skærmlæseren er primært til blinde og svagtseende brugere"</string>
+    <string name="talkback_summary" msgid="6602857105831641574">"Skærmlæser primært til blinde og svagtseende brugere"</string>
     <string name="select_to_speak_summary" msgid="7514180457557735421">"Tryk på elementer på din skærm for at få dem læst op"</string>
     <string name="accessibility_captioning_title" msgid="5878371993023439642">"Undertekster"</string>
     <string name="accessibility_screen_magnification_title" msgid="7250949681883917360">"Forstørrelse"</string>
@@ -2273,13 +2278,13 @@
     <string name="battery_tip_smart_battery_title" product="device" msgid="7419448992583346364">"Forlæng enhedens batteritid"</string>
     <string name="battery_tip_smart_battery_summary" msgid="5344821856478265778">"Aktivér batteriadministration"</string>
     <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Aktivér batterisparefunktionen"</string>
-    <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Enheden løber muligvis tør for batteri hurtigere end forventet"</string>
+    <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Batteriet aflades muligvis hurtigere end normalt"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Batterisparefunktion er aktiveret"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Nogle funktioner kan være begrænsede"</string>
     <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Telefonen er blevet brugt mere end normalt"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"Din tablet er blevet brugt mere end normalt"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"Enheden er blevet brugt mere end normalt"</string>
-    <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"Enheden løber muligvis tør for batteri hurtigere end forventet"</string>
+    <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"Batteriet aflades muligvis hurtigere end normalt"</string>
     <string name="battery_tip_dialog_message" product="default" msgid="8453700079047810964">"Din telefon er blevet brugt mere end normalt. Telefonen løber muligvis tør for batteri hurtigere end forventet.\n\nDe mest anvendte apps siden sidste fulde opladning:"</string>
     <string name="battery_tip_dialog_message" product="tablet" msgid="6489981050645444068">"Din tablet er blevet brugt mere end normalt. Din tablet løber muligvis tør for batteri hurtigere end forventet.\n\nDe mest anvendte apps siden sidste fulde opladning:"</string>
     <string name="battery_tip_dialog_message" product="device" msgid="6348123094674390337">"Din enhed er blevet brugt mere end normalt. Enheden løber muligvis tør for batteri hurtigere end forventet.\n\nDe mest anvendte apps siden sidste fulde opladning:"</string>
@@ -3142,13 +3147,13 @@
     <string name="alarm_ringtone_title" msgid="6411326147408635902">"Standardlyd for alarmer"</string>
     <string name="vibrate_when_ringing_title" msgid="2757996559847126952">"Vibrer ved opkald"</string>
     <string name="other_sound_settings" msgid="5250376066099818676">"Andre lyde"</string>
-    <string name="dial_pad_tones_title" msgid="8877212139988655769">"Toner for numerisk tastatur"</string>
+    <string name="dial_pad_tones_title" msgid="8877212139988655769">"Toner for tastatur"</string>
     <string name="screen_locking_sounds_title" msgid="4407110895465866809">"Lyd ved skærmlås"</string>
     <string name="charging_sounds_title" msgid="5070437987230894287">"Lyd og vibration ved opladning"</string>
     <string name="docking_sounds_title" msgid="2573137471605541366">"Lyde for dockingstation"</string>
     <string name="touch_sounds_title" msgid="165237488496165652">"Lyd ved berøring"</string>
     <string name="vibrate_on_touch_title" msgid="6360155469279157684">"Vibration ved berøring"</string>
-    <string name="vibrate_on_touch_summary" msgid="5504424764028676043">"Feedback ved berøring for tryk, tastatur og meget mere"</string>
+    <string name="vibrate_on_touch_summary" msgid="5504424764028676043">"Feedback ved berøring for tryk, tastatur og mere"</string>
     <string name="dock_audio_media_title" msgid="1859521680502040781">"Dockhøjttaler afspiller"</string>
     <string name="dock_audio_media_disabled" msgid="4300752306178486302">"Al lyd"</string>
     <string name="dock_audio_media_enabled" msgid="2873275045878628153">"Kun medielyd"</string>
@@ -3628,7 +3633,7 @@
     <string name="runtime_permissions_summary_no_permissions_requested" msgid="3901636077467389637">"Der er ikke anmodet om nogen tilladelser"</string>
     <string name="filter_all_apps" msgid="4042756539846043675">"Alle apps"</string>
     <string name="filter_enabled_apps" msgid="5888459261768538489">"Installerede aps"</string>
-    <string name="filter_instant_apps" msgid="8087483282854072366">"Instant apps"</string>
+    <string name="filter_instant_apps" msgid="8087483282854072366">"Instant-apps"</string>
     <string name="filter_personal_apps" msgid="3473268022652904457">"Personlig"</string>
     <string name="filter_work_apps" msgid="4202483998339465542">"Arbejde"</string>
     <string name="filter_notif_all_apps" msgid="1862666327228804896">"Apps: Alle"</string>
@@ -4144,9 +4149,9 @@
     <string name="oem_unlock_enable_disabled_summary_sim_locked_device" msgid="5223278198179877704">"Indstillingen er ikke tilgængelig på SIM-låste enheder"</string>
     <string name="oem_lock_info_message" msgid="5090850412279403901">"Genstart enheden for at aktivere funktionen Enhedsbeskyttelse."</string>
     <string name="automatic_storage_manager_freed_bytes" msgid="7360443072390107772">"<xliff:g id="SIZE">%1$s</xliff:g> blev frigjort\n\nSidst kørt den <xliff:g id="DATE">%2$s</xliff:g>"</string>
-    <string name="web_action_enable_title" msgid="4462106633708675959">"Instant apps"</string>
+    <string name="web_action_enable_title" msgid="4462106633708675959">"Instant-apps"</string>
     <string name="web_action_enable_summary" msgid="1729016644691793085">"Åbn links i apps – selv hvis de ikke er installeret"</string>
-    <string name="web_action_section_title" msgid="5563229447734734662">"Instant apps"</string>
+    <string name="web_action_section_title" msgid="5563229447734734662">"Instant-apps"</string>
     <string name="instant_apps_settings" msgid="879003203555847537">"Præferencer for Instant Apps"</string>
     <string name="domain_url_section_title" msgid="206403507921518321">"Installerede aps"</string>
     <string name="automatic_storage_manager_activation_warning" msgid="2630083316417707308">"Din lagerplads administreres nu af lageradministratoren"</string>
@@ -4239,7 +4244,7 @@
     <string name="storage_volume_total" msgid="5021484171514159913">"Anvendt lagerplads ud af <xliff:g id="TOTAL">%1$s</xliff:g>"</string>
     <string name="storage_percent_full" msgid="6924662861545958442">"brugt"</string>
     <string name="clear_instant_app_data" msgid="3673669086522890405">"Ryd appen"</string>
-    <string name="clear_instant_app_confirmation" msgid="1778553115373698061">"Vil du fjerne denne instant app?"</string>
+    <string name="clear_instant_app_confirmation" msgid="1778553115373698061">"Vil du fjerne denne instant-app?"</string>
     <string name="launch_instant_app" msgid="5251693061228352333">"Åbn"</string>
     <string name="game_storage_settings" msgid="6856911551799175914">"Spil"</string>
     <string name="audio_files_title" msgid="3073879661731363935">"Lydfiler"</string>
@@ -4262,7 +4267,7 @@
     <string name="storage_manager_indicator" msgid="4255140732848476875">"Lagerstyring: <xliff:g id="STATUS">^1</xliff:g>"</string>
     <string name="storage_manager_indicator_off" msgid="6404056007102580777">"Fra"</string>
     <string name="storage_manager_indicator_on" msgid="5295306384982062320">"Til"</string>
-    <string name="install_type_instant" msgid="6248487669862821874">"Instant app"</string>
+    <string name="install_type_instant" msgid="6248487669862821874">"Instant-app"</string>
     <string name="automatic_storage_manager_deactivation_warning" msgid="7867793739491286374">"Slå lagerstyring fra?"</string>
     <string name="storage_movies_tv" msgid="7282484273991655296">"Film- og tv-apps"</string>
     <string name="carrier_provisioning" msgid="3309125279191534469">"Oplysninger om mobilselskab"</string>
@@ -4338,7 +4343,7 @@
     <string name="network_connecting" msgid="8798611458457547110">"Opretter forbindelse…"</string>
     <string name="network_could_not_connect" msgid="552874922030763713">"Der kunne ikke oprettes forbindelse"</string>
     <string name="empty_networks_list" msgid="5170020017144403884">"Der blev ikke fundet nogen netværk."</string>
-    <string name="network_query_error" msgid="525635151099480463">"Der kunne ikke findes nogen netværk. Prøv igen."</string>
+    <string name="network_query_error" msgid="525635151099480463">"Der blev ikke fundet nogen netværk. Prøv igen."</string>
     <string name="forbidden_network" msgid="8493827960968261182">"(forbudt)"</string>
     <string name="no_sim_card" msgid="3708682108324275635">"Intet SIM-kort"</string>
     <string name="preferred_network_mode_wcdma_perf_summary" msgid="6899270534608086704">"Foretrukken netværkstilstand: WCDMA foretrækkes"</string>
diff --git a/tests/CarDeveloperOptions/res/values-de/arrays.xml b/tests/CarDeveloperOptions/res/values-de/arrays.xml
index 4ee4f1b..7b5df1a 100644
--- a/tests/CarDeveloperOptions/res/values-de/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-de/arrays.xml
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"Nie zulassen"</item>
     <item msgid="8184570120217958741">"Immer zulassen"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Mittelmäßig"</item>
+    <item msgid="1555861583162930714">"Niedrig"</item>
+    <item msgid="1719683776264798117">"Kritisch"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Mittel"</item>
+    <item msgid="6107138933849816768">"Moderat"</item>
+    <item msgid="182695359839047859">"Niedrig"</item>
+    <item msgid="8577246509202964244">"Kritisch"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Permanent"</item>
     <item msgid="167418068739176448">"Topaktivität"</item>
diff --git a/tests/CarDeveloperOptions/res/values-de/config.xml b/tests/CarDeveloperOptions/res/values-de/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-de/config.xml
+++ b/tests/CarDeveloperOptions/res/values-de/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-de/strings.xml b/tests/CarDeveloperOptions/res/values-de/strings.xml
index 61c564f..214c3c5 100644
--- a/tests/CarDeveloperOptions/res/values-de/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-de/strings.xml
@@ -80,7 +80,7 @@
     <string name="sdcard_format" product="default" msgid="4831611387627849108">"SD-Karte löschen"</string>
     <string name="preview_pager_content_description" msgid="5731599395893090038">"Vorschau"</string>
     <string name="preview_page_indicator_content_description" msgid="3192955679074998362">"Vorschau, Seite <xliff:g id="CURRENT_PAGE">%1$d</xliff:g> von <xliff:g id="NUM_PAGES">%2$d</xliff:g>"</string>
-    <string name="font_size_summary" msgid="9120023206321191067">"Text auf dem Display verkleinern oder vergrößern."</string>
+    <string name="font_size_summary" msgid="9120023206321191067">"Lege fest, wie groß Text angezeigt wird."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Verkleinern"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Vergrößern"</string>
     <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
@@ -468,7 +468,7 @@
     <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"Sensor berühren"</string>
     <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Lege deinen Finger auf den Sensor und hebe ihn an, wenn du eine Vibration spürst."</string>
     <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"Anheben und erneut berühren"</string>
-    <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Ändere zur vollständige Erfassung jedes Mal ein wenig die Position deines Fingers"</string>
+    <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Lege den Finger immer wieder in leicht geänderter Position auf, bis der Abdruck vollständig erfasst ist."</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"Fingerabdruck hinzugefügt"</string>
     <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"Wenn du dieses Symbol siehst, kannst du deinen Fingerabdruck verwenden, um dich zu identifizieren oder einen Kauf zu autorisieren."</string>
     <string name="security_settings_fingerprint_enroll_enrolling_skip" msgid="1473280156532146933">"Später"</string>
@@ -487,7 +487,7 @@
     <string name="security_settings_fingerprint_enroll_done" msgid="4111289529758845926">"Fertig"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"Das ist nicht der Sensor"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"Sensor auf Rückseite mit Zeigefinger berühren."</string>
-    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"Registrierung wurde nicht abgeschlossen."</string>
+    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"Registrierung wurde nicht abgeschlossen"</string>
     <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Zeitüberschreitung bei Fingerabdruckregistrierung. Bitte versuche es noch einmal."</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"Fehler bei Fingerabdruckregistrierung. Versuche es erneut oder verwende einen anderen Finger."</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"Weiteren hinzufügen"</string>
@@ -595,8 +595,8 @@
     <string name="unlock_disable_lock_title" msgid="3508492427073600294">"Displaysperre deaktivieren"</string>
     <string name="unlock_disable_frp_warning_title" msgid="5858589970505254193">"Geräteschutz entfernen?"</string>
     <string name="unlock_disable_frp_warning_title_profile" msgid="3814123014295965266">"Profilschutz entfernen?"</string>
-    <string name="unlock_disable_frp_warning_content_pattern" msgid="1843950215687159135">"Wenn du dein Muster entfernst, funktionieren die Funktionen zum Geräteschutz nicht."</string>
-    <string name="unlock_disable_frp_warning_content_pattern_fingerprint" msgid="8846957650251741548">"Wenn du dein Muster entfernst, funktionieren die Funktionen zum Geräteschutz nicht.<xliff:g id="EMPTY_LINE">
+    <string name="unlock_disable_frp_warning_content_pattern" msgid="1843950215687159135">"Der Geräteschutz funktioniert ohne dein Muster nicht."</string>
+    <string name="unlock_disable_frp_warning_content_pattern_fingerprint" msgid="8846957650251741548">"Der Geräteschutz funktioniert ohne dein Muster nicht.<xliff:g id="EMPTY_LINE">
 
 </xliff:g>Deine gespeicherten Fingerabdrücke werden ebenfalls von diesem Gerät entfernt und du kannst mit ihnen weder dein Smartphone entsperren noch Käufe autorisieren oder dich in Apps anmelden."</string>
     <string name="unlock_disable_frp_warning_content_pin" msgid="6760473271034592796">"Der Geräteschutz funktioniert ohne deine PIN nicht."</string>
@@ -667,7 +667,6 @@
       <item quantity="other">Muss weniger als <xliff:g id="NUMBER_1">%d</xliff:g> Ziffern haben</item>
       <item quantity="one">Muss weniger als <xliff:g id="NUMBER_0">%d</xliff:g> Ziffer haben</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Es dürfen nur Ziffern von 0 bis 9 enthalten sein"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Der Geräteadministrator lässt die Verwendung einer früheren PIN nicht zu"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Häufig verwendete PINs werden von deinem IT-Administrator blockiert. Versuch es mit einer anderen PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Es sind keine ungültigen Zeichen zulässig"</string>
@@ -698,6 +697,10 @@
       <item quantity="other">Das Passwort muss mindestens <xliff:g id="COUNT">%d</xliff:g> Zeichen enthalten, die keine Buchstaben sind</item>
       <item quantity="one">Das Passwort muss mindestens ein Zeichen enthalten, das kein Buchstabe ist</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Passwort muss mindestens <xliff:g id="COUNT">%d</xliff:g> Zeichen enthalten, die keine Ziffern sind</item>
+      <item quantity="one">Passwort muss mindestens ein Zeichen enthalten, das keine Ziffer ist</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Der Geräteadministrator lässt die Verwendung eines früheren Passworts nicht zu"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Häufig verwendete Passwörter werden von deinem IT-Administrator blockiert. Versuch es mit einem anderen Passwort."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Aufsteigende, absteigende oder wiederholte Ziffernfolgen sind unzulässig"</string>
@@ -715,7 +718,7 @@
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> aktive App</item>
     </plurals>
     <string name="manage_trust_agents" msgid="8129970926213142261">"Trust Agents"</string>
-    <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"Lege zunächst eine Displaysperre fest, damit du die Option verwenden kannst."</string>
+    <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"Lege zuerst eine Displaysperre fest, damit du die Option verwenden kannst."</string>
     <string name="manage_trust_agents_summary" msgid="2023116850759962248">"Keine"</string>
     <plurals name="manage_trust_agents_summary_on" formatted="false" msgid="5550538038916606097">
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> aktive Trust Agents</item>
@@ -738,7 +741,7 @@
 )  -->
     <string name="bluetooth_incoming_pairing_msg" msgid="940451919337185024">"Von:&lt;br&gt;&lt;b&gt;<xliff:g id="DEVICE_NAME">%1$s</xliff:g>&lt;/b&gt;&lt;br&gt;&lt;br&gt; Mit diesem Gerät koppeln?"</string>
     <string name="bluetooth_display_passkey_pin_msg" msgid="5909423849232791647">"Gib zur Kopplung mit <xliff:g id="BOLD1_0">&lt;br&gt;&lt;b&gt;</xliff:g><xliff:g id="DEVICE_NAME">%1$s</xliff:g><xliff:g id="END_BOLD1">&lt;/b&gt;&lt;br&gt;&lt;br&gt;</xliff:g> <xliff:g id="BOLD2_1">&lt;br&gt;&lt;b&gt;</xliff:g><xliff:g id="PASSKEY">%2$s</xliff:g><xliff:g id="END_BOLD2">&lt;/b&gt;</xliff:g> ein und drücke anschließend die Eingabetaste."</string>
-    <string name="bluetooth_pairing_shares_phonebook" msgid="7474404818877079813">"Zugriff auf deine Kontakte und deine Anrufliste zulassen"</string>
+    <string name="bluetooth_pairing_shares_phonebook" msgid="7474404818877079813">"Zugriff auf meine Kontakte und meine Anrufliste zulassen"</string>
     <string name="bluetooth_error_title" msgid="5718761586633101960"></string>
     <string name="bluetooth_connecting_error_message" msgid="8473359363469518478">"Keine Verbindung zu <xliff:g id="DEVICE_NAME">%1$s</xliff:g> möglich"</string>
     <string name="bluetooth_preference_scan_title" msgid="457781003962324807">"Scan nach Geräten"</string>
@@ -860,7 +863,7 @@
     <string name="use_open_wifi_automatically_summary_scorer_unsupported_disabled" msgid="1123080670578756834">"Für diese Funktion musst du zuerst einen kompatiblen Anbieter von Netzwerkbewertungen auswählen"</string>
     <string name="wifi_install_credentials" msgid="5650088113710858289">"Zertifikate installieren"</string>
     <string name="wifi_scan_notify_text" msgid="7614101215028336927">"Zur Verbesserung der Standortgenauigkeit können Apps und Dienste weiter nach WLANs suchen, auch wenn die WLAN-Funktion deaktiviert ist. Dadurch können beispielsweise standortbasierte Funktionen und Dienste verbessert werden. Dies lässt sich in den <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>Sucheinstellungen<xliff:g id="LINK_END_1">LINK_END</xliff:g> ändern."</string>
-    <string name="wifi_scan_notify_text_scanning_off" msgid="723796963816095410">"Um die Standortgenauigkeit zu erhöhen, aktiviere die WLAN-Suche in den <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>Sucheinstellungen<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
+    <string name="wifi_scan_notify_text_scanning_off" msgid="723796963816095410">"Aktiviere zur Erhöhung der Standortgenauigkeit die WLAN-Suche in den <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>Sucheinstellungen<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
     <string name="wifi_scan_notify_remember_choice" msgid="1235445971400237444">"Nicht mehr anzeigen"</string>
     <string name="wifi_setting_sleep_policy_title" msgid="2120785188625932076">"WLAN im Ruhemodus aktiviert lassen"</string>
     <string name="wifi_setting_on_during_sleep_title" msgid="856670183023402715">"WLAN im Ruhemodus aktiviert"</string>
@@ -887,7 +890,7 @@
     <string name="wifi_menu_forget" msgid="7561140554450163075">"Netzwerk entfernen"</string>
     <string name="wifi_menu_modify" msgid="4080178040721021101">"Netzwerk ändern"</string>
     <string name="wifi_empty_list_wifi_off" msgid="272877164691346240">"WLAN aktivieren, um verfügbare Netze abzurufen"</string>
-    <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"Suche nach WLAN-Netzwerken läuft…"</string>
+    <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"Suche nach WLAN läuft…"</string>
     <string name="wifi_empty_list_user_restricted" msgid="2341613007817352431">"Du verfügst nicht über die Berechtigung zum Ändern des WLAN-Netzwerks."</string>
     <string name="wifi_more" msgid="3538241640407382185">"Mehr"</string>
     <string name="wifi_setup_wps" msgid="6730131677695521321">"Automatisches Setup (WPS)"</string>
@@ -1037,7 +1040,7 @@
     <string name="wifi_dns1" msgid="5250809981658822505">"DNS 1"</string>
     <string name="wifi_dns2" msgid="1905876166783761641">"DNS 2"</string>
     <string name="wifi_gateway" msgid="7455334454444443397">"Gateway"</string>
-    <string name="wifi_network_prefix_length" msgid="1941206966133010633">"Länge Netzwerkpräfix"</string>
+    <string name="wifi_network_prefix_length" msgid="1941206966133010633">"Länge d. Netzwerkpräfixes"</string>
     <string name="wifi_p2p_settings_title" msgid="3213180637906683308">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_device_info" msgid="4717490498956029237">"Geräte-Informationen"</string>
     <string name="wifi_p2p_persist_network" msgid="1110453878886476660">"Diese Verbindung speichern"</string>
@@ -1100,7 +1103,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"WLAN"</item>
+    <item msgid="2271962426654621656">"Mobil"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Mobilfunknetz nutzen, wenn WLAN nicht verfügbar ist"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Bei nicht verfügbarem Mobilfunknetz WLAN verwenden"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Anruf über WLAN. Bei Abbruch der WLAN-Verbindung endet der Anruf."</string>
@@ -1198,7 +1204,7 @@
     <string name="auto_brightness_off_summary" msgid="6162650416289359104">"Nicht an Lichtverhältnisse anpassen"</string>
     <string name="auto_brightness_very_high_summary" msgid="7202032980509583918">"Erhöhter Akkuverbrauch"</string>
     <string name="auto_brightness_disclaimer" msgid="5416696351199148809">"\"Helligkeit an Lichtverhältnisse anpassen\": Ist diese Funktion aktiviert, kannst du die Helligkeit dennoch vorübergehend ändern."</string>
-    <string name="auto_brightness_description" msgid="8209140379089535411">"Die Helligkeit des Displays passt sich automatisch an deine Umgebung und deine Aktivitäten an. Mit dem Schieberegler kannst du manuell nachjustieren und \"Automatische Helligkeit\" merkt sich deine Präferenz."</string>
+    <string name="auto_brightness_description" msgid="8209140379089535411">"Die Helligkeit des Displays passt sich automatisch an deine Umgebung und deine Aktivitäten an. Mit dem Schieberegler kannst du manuell nachjustieren und die Funktion \"Automatische Helligkeit\" merkt sich deine Präferenz."</string>
     <string name="display_white_balance_title" msgid="5747260735311935143">"Weißabgleich des Bildschirms"</string>
     <string name="adaptive_sleep_title" msgid="3237620948260957018">"Screen Aware"</string>
     <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"An/Der Bildschirm wird nicht ausgeschaltet, wenn du ihn ansiehst"</string>
@@ -1562,7 +1568,7 @@
     <string name="error_adding_apn_type" msgid="671634520340569678">"Der Anbieter erlaubt das Hinzufügen von APNs des Typs %s nicht."</string>
     <string name="restore_default_apn" msgid="7195266404077471007">"Standard-APN-Einstellungen werden wiederhergestellt"</string>
     <string name="menu_restore" msgid="3799288817317293115">"Auf Standard zurücksetzen"</string>
-    <string name="restore_default_apn_completed" msgid="5671734152740058937">"Zurücksetzen auf Standard-APN-Einstellungen abgeschlossen"</string>
+    <string name="restore_default_apn_completed" msgid="5671734152740058937">"Zurücksetzen auf Standard-APN-Einstellungen abgeschlossen."</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"Optionen zum Zurücksetzen"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"Zurückgesetzt werden können das Netzwerk, Apps und das Gerät"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"WLAN, mobile Daten &amp; Bluetooth zurücksetzen"</string>
@@ -1578,7 +1584,7 @@
     <string name="reset_network_complete_toast" msgid="128225929536005495">"Die Netzwerkeinstellungen wurden zurückgesetzt."</string>
     <string name="reset_esim_error_title" msgid="4728931209471875632">"SIMs können nicht gelöscht werden"</string>
     <string name="reset_esim_error_msg" msgid="4716366079119742235">"Heruntergeladene SIMs können aufgrund eines Fehlers nicht gelöscht werden.\n\nStarte das Gerät neu und versuche es noch einmal."</string>
-    <string name="master_clear_title" msgid="1560712943955904673">"Alle Daten löschen (Auslieferungszustand)"</string>
+    <string name="master_clear_title" msgid="1560712943955904673">"Alle Daten löschen (auf Werkseinstellungen zurücksetzen)"</string>
     <string name="master_clear_short_title" msgid="919098101581335101">"Alle Daten löschen"</string>
     <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"Hierdurch werden alle Daten aus dem "<b>"internen Speicher"</b>" deines Tablets gelöscht, wie z. B. die Folgenden:\n\n"<li>"Dein Google-Konto"</li>\n<li>"System- und App-Daten sowie entsprechende Einstellungen"</li>\n<li>"Heruntergeladene Apps"</li></string>
     <string name="master_clear_desc" product="default" msgid="8765543541962866697">"Hierdurch werden alle Daten aus dem "<b>"internen Speicher"</b>" deines Smartphones gelöscht, wie z. B. die Folgenden:\n\n"<li>"Dein Google-Konto"</li>\n<li>"System- und App-Daten sowie entsprechende Einstellungen"</li>\n<li>"Heruntergeladene Apps"</li></string>
@@ -1703,15 +1709,15 @@
     <string name="confirm_device_credential_use_alternate_method" msgid="1279869272895739941">"Alternative Methode verwenden"</string>
     <string name="lockpassword_choose_your_screen_lock_header" msgid="6283518876031424798">"Displaysperre einrichten"</string>
     <string name="lockpassword_choose_your_password_message" msgid="2838273977481046536">"Richte zur Sicherheit ein Passwort ein"</string>
-    <string name="lockpassword_choose_your_password_header_for_fingerprint" msgid="4921343500484160894">"Passwort festlegen, um Fingerabdruck zu verwenden"</string>
-    <string name="lockpassword_choose_your_pattern_header_for_fingerprint" msgid="314870151462139417">"Muster festlegen, um Fingerabdruck zu verwenden"</string>
+    <string name="lockpassword_choose_your_password_header_for_fingerprint" msgid="4921343500484160894">"Für Fingerabdruck Passwort festlegen"</string>
+    <string name="lockpassword_choose_your_pattern_header_for_fingerprint" msgid="314870151462139417">"Für Fingerabdruck Muster festlegen"</string>
     <string name="lockpassword_choose_your_pin_message" msgid="8942598950627277885">"Richte zur Sicherheit eine PIN ein"</string>
-    <string name="lockpassword_choose_your_pin_header_for_fingerprint" msgid="1102927520952116303">"PIN festlegen, um Fingerabdruck zu verwenden"</string>
+    <string name="lockpassword_choose_your_pin_header_for_fingerprint" msgid="1102927520952116303">"Für Fingerabdruck PIN festlegen"</string>
     <string name="lockpassword_choose_your_pattern_message" msgid="1503075455752279687">"Richte zur Sicherheit ein Muster ein"</string>
     <string name="lockpassword_confirm_your_password_header" msgid="9055242184126838887">"Passwort noch einmal eingeben"</string>
     <string name="lockpassword_confirm_your_pattern_header" msgid="7137526922696316545">"Muster bestätigen"</string>
     <string name="lockpassword_confirm_your_pin_header" msgid="4335593948303036343">"PIN noch einmal eingeben"</string>
-    <string name="lockpassword_confirm_passwords_dont_match" msgid="1783767008133345784">"Die Passwörter stimmen nicht überein."</string>
+    <string name="lockpassword_confirm_passwords_dont_match" msgid="1783767008133345784">"Die Passwörter stimmen nicht überein"</string>
     <string name="lockpassword_confirm_pins_dont_match" msgid="5444357293637748942">"Die PINs stimmen nicht überein"</string>
     <string name="lockpassword_draw_your_pattern_again_header" msgid="9017394036814402348">"Muster noch einmal zeichnen"</string>
     <string name="lockpassword_choose_lock_generic_header" msgid="4418423132980560119">"Sperre einrichten"</string>
@@ -2228,7 +2234,7 @@
     <string name="power_usage_level_and_status" msgid="8873534076894160727">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATUS">%2$s</xliff:g>"</string>
     <string name="power_discharge_remaining" msgid="3461915627093471868">"Noch <xliff:g id="REMAIN">%1$s</xliff:g>"</string>
     <string name="power_charge_remaining" msgid="2730510256218879651">"Verbleibende Ladezeit: <xliff:g id="UNTIL_CHARGED">%1$s</xliff:g>"</string>
-    <string name="background_activity_title" msgid="7207836362312111483">"Hintergrundnutzung einschränken"</string>
+    <string name="background_activity_title" msgid="7207836362312111483">"Einschränkung der Hintergrundnutzung"</string>
     <string name="background_activity_summary" msgid="582372194738538145">"App darf im Hintergrund ausgeführt werden"</string>
     <string name="background_activity_summary_disabled" msgid="457944930942085876">"App darf nicht im Hintergrund ausgeführt werden"</string>
     <string name="background_activity_summary_whitelisted" msgid="4713321059375873828">"Hintergrundnutzung kann nicht eingeschränkt werden"</string>
@@ -2304,12 +2310,12 @@
       <item quantity="other">%1$d Apps einschränken?</item>
       <item quantity="one">App einschränken?</item>
     </plurals>
-    <string name="battery_tip_restrict_app_dialog_message" msgid="6905822297507947381">"Um den Akku zu schonen, verhindere, dass <xliff:g id="APP">%1$s</xliff:g> im Hintergrund Strom verbraucht. Eventuell funktioniert die App dann nicht mehr richtig und Benachrichtigungen werden verzögert angezeigt."</string>
-    <string name="battery_tip_restrict_apps_less_than_5_dialog_message" msgid="4225881888543582456">"Um den Akku zu schonen, verhindere, dass diese Apps im Hintergrund Strom verbrauchen. Eventuell funktionieren sie dann nicht mehr richtig und Benachrichtigungen werden verzögert angezeigt.\n\nApps:"</string>
-    <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"Um den Akku zu schonen, verhindere, dass diese Apps im Hintergrund Strom verbrauchen. Eventuell funktionieren sie dann nicht mehr richtig und Benachrichtigungen werden verzögert angezeigt.\n\nApps:\n<xliff:g id="APP_LIST">%1$s</xliff:g>."</string>
+    <string name="battery_tip_restrict_app_dialog_message" msgid="6905822297507947381">"Um den Akku zu schonen, kannst du verhindern, dass <xliff:g id="APP">%1$s</xliff:g> im Hintergrund Strom verbraucht. Eventuell funktioniert die App dann nicht mehr richtig und Benachrichtigungen werden verzögert angezeigt."</string>
+    <string name="battery_tip_restrict_apps_less_than_5_dialog_message" msgid="4225881888543582456">"Um den Akku zu schonen, kannst du verhindern, dass diese Apps im Hintergrund Strom verbrauchen. Eventuell funktionieren sie dann nicht mehr richtig und Benachrichtigungen werden verzögert angezeigt.\n\nApps:"</string>
+    <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"Um den Akku zu schonen, kannst du verhindern, dass diese Apps im Hintergrund Strom verbrauchen. Eventuell funktionieren sie dann nicht mehr richtig und Benachrichtigungen werden verzögert angezeigt.\n\nApps:\n<xliff:g id="APP_LIST">%1$s</xliff:g>."</string>
     <string name="battery_tip_restrict_app_dialog_ok" msgid="2573410775701913487">"Einschränken"</string>
     <string name="battery_tip_unrestrict_app_dialog_title" msgid="812458516399125710">"Beschränkung entfernen?"</string>
-    <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"Diese App läuft im Hintergrund und beansprucht dabei den Akku. Er könnte deshalb früher als erwartet leer sein."</string>
+    <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"Diese App kann dann im Hintergrund laufen und beansprucht dabei den Akku. Er könnte deshalb früher als erwartet leer sein."</string>
     <string name="battery_tip_unrestrict_app_dialog_ok" msgid="9154938931448151479">"Entfernen"</string>
     <string name="battery_tip_unrestrict_app_dialog_cancel" msgid="7331148618292397166">"Abbrechen"</string>
     <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"Der Akkuverbrauch durch Apps ist zurzeit normal. Falls der Akku zu stark beansprucht wird, werden dir mögliche Maßnahmen vorgeschlagen.\n\nBei niedrigem Akkustand kannst du jederzeit den Energiesparmodus aktivieren."</string>
@@ -2444,9 +2450,9 @@
     <string name="battery_saver" msgid="3989710213758938398">"Energiesparmodus"</string>
     <string name="battery_saver_auto_title" msgid="4158659069641849952">"Automatisch aktivieren"</string>
     <string name="battery_saver_auto_no_schedule" msgid="739814529432092706">"Keine Aktivierung nach Zeitplan"</string>
-    <string name="battery_saver_auto_routine" msgid="886514412067906980">"Anhand deiner üblichen Abläufe"</string>
+    <string name="battery_saver_auto_routine" msgid="886514412067906980">"Anhand meiner üblichen Abläufe"</string>
     <string name="battery_saver_auto_percentage" msgid="5791982309331921556">"Anhand des Ladestands"</string>
-    <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"Der Energiesparmodus wird automatisch aktiviert, wenn offenbar wird, dass der Akku wahrscheinlich nicht bis zum nächsten Aufladen hält (ermittelt anhand deines üblichen Aufladezeitpunkts)."</string>
+    <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"Der Energiesparmodus wird automatisch aktiviert, wenn der Akku wahrscheinlich nicht bis zum nächsten Aufladen hält (ermittelt anhand deines üblichen Aufladezeitpunkts)."</string>
     <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"Wird bei <xliff:g id="PERCENT">%1$s</xliff:g> aktiviert"</string>
     <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"Zeitplan festlegen"</string>
     <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"Bei vollem Akku ausschalten"</string>
@@ -2707,7 +2713,7 @@
     <string name="data_usage_cycle_editor_subtitle" msgid="6043098041946166597">"Jeden Monat zurücksetzen am:"</string>
     <string name="data_usage_cycle_editor_positive" msgid="9155752056537811646">"Übernehmen"</string>
     <string name="data_usage_warning_editor_title" msgid="1431385383278389290">"Warnung für Datenverbrauch festlegen"</string>
-    <string name="data_usage_limit_editor_title" msgid="1687908662154108293">"Limit festlegen"</string>
+    <string name="data_usage_limit_editor_title" msgid="1687908662154108293">"Datenlimit festlegen"</string>
     <string name="data_usage_limit_dialog_title" msgid="8804760847110131518">"Datennutzung begrenzen"</string>
     <string name="data_usage_limit_dialog_mobile" product="tablet" msgid="2000713577999830647">"Mobile Daten werden deaktiviert, sobald das von dir festgelegte Limit erreicht wurde.\n\nDer dabei angesetzte Wert wird von deinem Tablet berechnet und kann von der Messung des genutzten Datenvolumens durch deinen Mobilfunkanbieter abweichen. Daher empfiehlt es sich, einen eher etwas niedrigeren Limitwert anzugeben."</string>
     <string name="data_usage_limit_dialog_mobile" product="default" msgid="943546278705619205">"Mobile Daten werden deaktiviert, sobald das von dir festgelegte Limit erreicht wurde.\n\nDer dabei angesetzte Wert wird von deinem Smartphone berechnet und kann von der Messung des genutzten Datenvolumens durch deinen Mobilfunkanbieter abweichen. Daher empfiehlt es sich, einen eher etwas niedrigeren Limitwert anzugeben."</string>
@@ -2898,7 +2904,7 @@
     <string name="user_exit_guest_confirm_message" msgid="6955182181145748919">"Alle Apps und Daten in dieser Sitzung werden gelöscht."</string>
     <string name="user_exit_guest_dialog_remove" msgid="1878866060881115716">"Entfernen"</string>
     <string name="user_enable_calling" msgid="864760054792249503">"Telefonieren zulassen"</string>
-    <string name="user_enable_calling_sms" msgid="3450252891736718793">"Telefonieren &amp; SMS zulassen?"</string>
+    <string name="user_enable_calling_sms" msgid="3450252891736718793">"Telefonieren &amp; SMS zulassen"</string>
     <string name="user_remove_user" msgid="3687544420125911166">"Nutzer löschen"</string>
     <string name="user_enable_calling_confirm_title" msgid="1141612415529158542">"Telefonieren zulassen?"</string>
     <string name="user_enable_calling_confirm_message" msgid="2490126715153125970">"Die Anrufliste wird für diesen Nutzer freigegeben."</string>
@@ -3094,7 +3100,7 @@
     <string name="keywords_backup" msgid="7433356270034921627">"Sicherung, sicherung"</string>
     <string name="keywords_assist_gesture_launch" msgid="2711433664837843513">"bewegung, geste, touch-geste"</string>
     <string name="keywords_face_unlock" msgid="651615819291927262">"Face, Unlock, Gesichtserkennung, Anmeldung"</string>
-    <string name="keywords_imei_info" msgid="4325847870422053408">"imei, meid, min, prl version, imei sv"</string>
+    <string name="keywords_imei_info" msgid="4325847870422053408">"imei, meid, Min., prl version, imei sv"</string>
     <string name="keywords_sim_status" msgid="3852088576719874387">"netzwerk, status des mobilfunknetz, servicestatus, signalstärke, art des mobilfunknetzes, roaming, iccid"</string>
     <string name="keywords_model_and_hardware" msgid="2743197096210895251">"seriennummer, hardwareversion"</string>
     <string name="keywords_android_version" msgid="4842749998088987740">"stand der sicherheitsupdates android, baseband version, kernel version"</string>
@@ -3147,7 +3153,7 @@
     <string name="charging_sounds_title" msgid="5070437987230894287">"Töne und Vibration beim Aufladen"</string>
     <string name="docking_sounds_title" msgid="2573137471605541366">"Docking-Sounds"</string>
     <string name="touch_sounds_title" msgid="165237488496165652">"Töne bei Berührung"</string>
-    <string name="vibrate_on_touch_title" msgid="6360155469279157684">"Vibration bei Displayberührung"</string>
+    <string name="vibrate_on_touch_title" msgid="6360155469279157684">"Vibration bei Berührung"</string>
     <string name="vibrate_on_touch_summary" msgid="5504424764028676043">"Haptisches Feedback beim Tippen, bei der Tastaturnutzung und mehr"</string>
     <string name="dock_audio_media_title" msgid="1859521680502040781">"Dock-Lautsprecherwiedergabe"</string>
     <string name="dock_audio_media_disabled" msgid="4300752306178486302">"Alle Audioquellen"</string>
@@ -3228,7 +3234,7 @@
     <string name="zen_mode_button_turn_on" msgid="1097964136225943415">"Jetzt aktivieren"</string>
     <string name="zen_mode_button_turn_off" msgid="3990967728457149454">"Jetzt deaktivieren"</string>
     <string name="zen_mode_settings_dnd_manual_end_time" msgid="4307574188962071429">"\"Bitte nicht stören\" ist aktiviert bis <xliff:g id="FORMATTED_TIME">%s</xliff:g>"</string>
-    <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"\"Bitte nicht stören\" bleibt aktiviert, bis du es deaktivierst"</string>
+    <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"\"Bitte nicht stören\" bleibt aktiviert, bis du es deaktivierst."</string>
     <string name="zen_mode_settings_dnd_automatic_rule" msgid="2843297614114625408">"\"Bitte nicht stören\" wurde automatisch durch einen Zeitplan (<xliff:g id="RULE_NAME">%s</xliff:g>) aktiviert"</string>
     <string name="zen_mode_settings_dnd_automatic_rule_app" msgid="5103454923160912313">"\"Bitte nicht stören\" wurde automatisch durch eine App (<xliff:g id="APP_NAME">%s</xliff:g>) aktiviert"</string>
     <string name="zen_mode_settings_dnd_custom_settings_footer" msgid="6335108298640066560">"\"Bitte nicht stören\" ist mit benutzerdefinierten Einstellungen für \"<xliff:g id="RULE_NAMES">%s</xliff:g>\" aktiviert."</string>
@@ -3316,7 +3322,7 @@
     <string name="notification_pulse_title" msgid="4861418327614907116">"Benachrichtigungslicht blinkt"</string>
     <string name="lock_screen_notifications_title" msgid="6889072265118747835">"Auf dem Sperrbildschirm"</string>
     <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"Wenn das Arbeitsprofil gesperrt ist"</string>
-    <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Alle Benachrichtigungen anzeigen"</string>
+    <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Gesamten Benachrichtigungsinhalt anzeigen"</string>
     <string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"Vertrauliche Inhalte ausblenden"</string>
     <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"Keine Benachrichtigungen anzeigen"</string>
     <string name="lock_screen_notifications_interstitial_message" msgid="4230189215124387818">"Wie sollen Benachrichtigungen angezeigt werden, wenn dein Gerät gesperrt ist?"</string>
@@ -3465,7 +3471,7 @@
     <string name="zen_mode_schedule_rule_days_all" msgid="8814173364016139675">"Täglich"</string>
     <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"Wecker kann Schlusszeit außer Kraft setzen"</string>
     <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"Zeitplan wird deaktiviert, wenn ein Wecker klingelt"</string>
-    <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"\"Bitte nicht stören\"-Verhalten"</string>
+    <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"\"Bitte nicht stören\"-Modus"</string>
     <string name="zen_mode_custom_behavior_summary_default" msgid="3509865340195397447">"Standardeinstellungen verwenden"</string>
     <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"Benutzerdefinierte Einstellungen festlegen"</string>
     <string name="zen_mode_custom_behavior_category_title" msgid="7451686525113262087">"Für \"<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>\""</string>
@@ -3707,7 +3713,7 @@
     <string name="high_power_system" msgid="739584574711292753">"Akku-Optimierung nicht verfügbar"</string>
     <string name="high_power_desc" msgid="333756885680362741">"Keine Optimierung bezüglich der Akkuleistung anwenden. Dein Akku entleert sich hierdurch möglicherweise schneller."</string>
     <string name="high_power_prompt_title" msgid="2805745781720454052">"Soll die App immer im Hintergrund ausgeführt werden?"</string>
-    <string name="high_power_prompt_body" msgid="8067395096053552289">"Wenn du erlaubst, dass \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" dauerhaft im Hintergrund ausgeführt wird, kann dies die  Akkulaufzeit verringern. \n\nDu kannst diese Einstellung jederzeit unter \"Einstellungen\" &gt; \"Apps &amp; Benachrichtigungen\" ändern."</string>
+    <string name="high_power_prompt_body" msgid="8067395096053552289">"Wenn du erlaubst, dass die App \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" dauerhaft im Hintergrund ausgeführt wird, kann dies die  Akkulaufzeit verringern. \n\nDu kannst diese Einstellung jederzeit unter \"Einstellungen\" &gt; \"Apps &amp; Benachrichtigungen\" ändern."</string>
     <string name="battery_summary" msgid="4345690800899981339">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> Verbrauch seit der letzten vollständigen Aufladung"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"Energiespareinstellungen"</string>
     <string name="no_battery_summary" msgid="4105932628367471314">"Kein Verbrauch seit dem letzten vollen Aufladen"</string>
@@ -3759,7 +3765,7 @@
     <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Der Assistent-App den Zugriff auf eine Aufnahme deines Bildschirms gestatten"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"Bildschirm kurz aufleuchten lassen"</string>
     <string name="assist_flash_summary" msgid="6697095786317559129">"Bildschirmränder kurz aufleuchten lassen, wenn Assistent-App auf Bildschirm-Text oder Screenshot zugreift"</string>
-    <string name="assist_footer" msgid="7030121180457472165">"Assistent-Apps können dir bei bestimmten Dingen helfen. Dazu greifen sie auf die Informationen zu, die aktuell auf deinem Bildschirm angezeigt werden. Für eine integrierte Unterstützung unterstützen einige Apps sowohl Launcher- als auch Spracheingabedienste."</string>
+    <string name="assist_footer" msgid="7030121180457472165">"Assistent-Apps können dir bei bestimmten Dingen helfen. Dazu greifen sie auf die Informationen zu, die aktuell auf deinem Bildschirm angezeigt werden. Damit sie dir eine umfassende Hilfe sind, unterstützen einige Apps sowohl Launcher- als auch Spracheingabedienste."</string>
     <string name="average_memory_use" msgid="5333366040118953945">"Durchschnittl. Speicherverbrauch"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"Maximaler Speicherverbrauch"</string>
     <string name="memory_usage" msgid="7963253555330830906">"Speicherverbrauch"</string>
@@ -4118,18 +4124,18 @@
     <string name="ambient_display_title" product="default" msgid="6785677099744344088">"Für Blick aufs Display doppeltippen"</string>
     <string name="ambient_display_title" product="tablet" msgid="1106285490888683613">"Doppeltippen für schnellen Blick auf das Display des Tablets"</string>
     <string name="ambient_display_title" product="device" msgid="5064644474876041478">"Doppeltippen für schnellen Blick auf das Display des Geräts"</string>
-    <string name="ambient_display_summary" msgid="4882910328216411109">"Wenn auf den Bildschirm doppelgetippt wird, werden die Uhrzeit, Benachrichtigungen und andere Informationen angezeigt"</string>
-    <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"Für Blick aufs Display Smartphone in die Hand nehmen"</string>
+    <string name="ambient_display_summary" msgid="4882910328216411109">"Wenn du auf den Bildschirm doppeltippst, werden die Uhrzeit, Benachrichtigungen und andere Informationen angezeigt."</string>
+    <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"Beim Hochheben Display aktivieren"</string>
     <string name="ambient_display_pickup_title" product="tablet" msgid="1555456400210301959">"Tablet hochnehmen, um das Display anzusehen"</string>
     <string name="ambient_display_pickup_title" product="device" msgid="2480126522988135037">"Gerät hochnehmen, um das Display anzusehen"</string>
     <string name="ambient_display_wake_screen_title" msgid="3376988352851077102">"Bildschirm aktivieren"</string>
-    <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"Wenn das Smartphone in die Hand genommen wird, werden die Uhrzeit, Benachrichtigungen und andere Informationen angezeigt"</string>
-    <string name="ambient_display_pickup_summary" product="tablet" msgid="1077745287100012928">"Wenn das Tablet in die Hand genommen wird, werden die Uhrzeit, Benachrichtigungen und andere Informationen angezeigt"</string>
-    <string name="ambient_display_pickup_summary" product="device" msgid="404199660076598026">"Wenn das Gerät in die Hand genommen wird, werden die Uhrzeit, Benachrichtigungen und andere Informationen angezeigt"</string>
+    <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"Wenn du das Smartphone in die Hand nimmst, werden die Uhrzeit, Benachrichtigungen und andere Informationen angezeigt."</string>
+    <string name="ambient_display_pickup_summary" product="tablet" msgid="1077745287100012928">"Wenn du das Tablet in die Hand nimmst, werden die Uhrzeit, Benachrichtigungen und andere Informationen angezeigt."</string>
+    <string name="ambient_display_pickup_summary" product="device" msgid="404199660076598026">"Wenn du das Gerät in die Hand nimmst, werden die Uhrzeit, Benachrichtigungen und andere Informationen angezeigt."</string>
     <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"Tippen, um Informationen auf dem Smartphone anzusehen"</string>
     <string name="ambient_display_tap_screen_title" product="tablet" msgid="6434521782016864148">"Tippen, um Informationen auf dem Tablet anzusehen"</string>
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"Tippen, um Informationen auf dem Gerät anzusehen"</string>
-    <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"Wenn auf den Bildschirm getippt wird, werden die Uhrzeit, Benachrichtigungen und andere Informationen angezeigt"</string>
+    <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"Wenn du auf den Bildschirm tippst, werden die Uhrzeit, Benachrichtigungen und andere Informationen angezeigt."</string>
     <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"Benachrichtigungen durch Wischen über Fingerabdrucksensor öffnen"</string>
     <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"Fingerabdrucksensor verwenden"</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"Zum Lesen von Benachrichtigungen über den Fingerabdrucksensor auf der Rückseite des Smartphones nach unten wischen"</string>
@@ -4305,7 +4311,7 @@
     <string name="change_wifi_state_title" msgid="5140754955787584174">"WLAN-Steuerung"</string>
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"App darf WLAN steuern"</string>
     <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"Erlaubt der App das WLAN zu aktivieren oder zu deaktivieren, nach WLANs zu scannen und eine Verbindung zu ihnen herstellen, Netzwerke hinzuzufügen oder zu entfernen oder einen lokal beschränkten Hotspot zu starten"</string>
-    <string name="media_output_title" msgid="8710632337456601848">"Medien hier abspielen"</string>
+    <string name="media_output_title" msgid="8710632337456601848">"Medien hier abspielen:"</string>
     <string name="media_output_default_summary" msgid="3159237976830415584">"Dieses Gerät"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"Smartphone"</string>
     <string name="media_output_summary" product="tablet" msgid="6672024060360538526">"Tablet"</string>
diff --git a/tests/CarDeveloperOptions/res/values-el/arrays.xml b/tests/CarDeveloperOptions/res/values-el/arrays.xml
index 6b208c6..707b98e 100644
--- a/tests/CarDeveloperOptions/res/values-el/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-el/arrays.xml
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"Να μην επιτρέπεται ποτέ"</item>
     <item msgid="8184570120217958741">"Να επιτρέπεται πάντα"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Κανονική"</item>
+    <item msgid="5101233285497327432">"Μέτρια"</item>
+    <item msgid="1555861583162930714">"Χαμηλή"</item>
+    <item msgid="1719683776264798117">"Σημαντική"</item>
+    <item msgid="1567326459340152525">";"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Κανονική"</item>
+    <item msgid="6107138933849816768">"Μέτρια"</item>
+    <item msgid="182695359839047859">"Χαμηλή"</item>
+    <item msgid="8577246509202964244">"Κρίσιμη"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Συνεχής"</item>
     <item msgid="167418068739176448">"Κορυφαία δραστηριότητα"</item>
@@ -463,8 +473,8 @@
   </string-array>
   <string-array name="wifi_metered_entries">
     <item msgid="4329206416008519163">"Αυτόματος εντοπισμός"</item>
-    <item msgid="773943026484148895">"Χρήση ως δικτύου με περιορισμούς"</item>
-    <item msgid="1008268820118852416">"Χρήση ως δικτύου χωρίς περιορισμούς"</item>
+    <item msgid="773943026484148895">"Χρήση ως δικτύου με ογκοχρέωση"</item>
+    <item msgid="1008268820118852416">"Χρήση ως δικτύου χωρίς ογκοχρέωση"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
     <item msgid="6545683814310036454">"Χρήση τυχαίου MAC (προεπιλογή)"</item>
diff --git a/tests/CarDeveloperOptions/res/values-el/config.xml b/tests/CarDeveloperOptions/res/values-el/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-el/config.xml
+++ b/tests/CarDeveloperOptions/res/values-el/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-el/strings.xml b/tests/CarDeveloperOptions/res/values-el/strings.xml
index 0641a09..d77f924 100644
--- a/tests/CarDeveloperOptions/res/values-el/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-el/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Κάντε το κείμενο στην οθόνη μικρότερο ή μεγαλύτερο."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Να γίνουν μικρότερα"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Να γίνουν μεγαλύτερα"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Δείγμα κειμένου"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Ο Θαυμάσιος Μάγος του Οζ"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Κεφάλαιο 11: Η Θαυμάσια Πόλη Έμεραλντ του Οζ"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Πρέπει να αποτελείται από λιγότερα από <xliff:g id="NUMBER_1">%d</xliff:g> ψηφία</item>
       <item quantity="one">Πρέπει να αποτελείται από λιγότερα από <xliff:g id="NUMBER_0">%d</xliff:g> ψηφίο</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Πρέπει να περιέχει μόνο ψηφία από το 0 έως το 9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Ο διαχειριστής της συσκευής δεν επιτρέπει τη χρήση πρόσφατου PIN"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Τα συνηθισμένα PIN αποκλείονται από τον διαχειριστή IT. Δοκιμάστε να χρησιμοποιήσετε διαφορετικό PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Δεν μπορεί να περιλαμβάνει μη έγκυρο χαρακτήρα"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Πρέπει να περιέχει τουλάχιστον <xliff:g id="COUNT">%d</xliff:g> χαρακτήρες που δεν είναι γράμματα</item>
       <item quantity="one">Πρέπει να περιέχει τουλάχιστον 1 χαρακτήρα που δεν είναι γράμμα</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Πρέπει να περιέχει τουλάχιστον <xliff:g id="COUNT">%d</xliff:g> μη αριθμητικούς χαρακτήρες</item>
+      <item quantity="one">Πρέπει να περιέχει τουλάχιστον 1 μη αριθμητικό χαρακτήρα</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Ο διαχειριστής της συσκευής δεν επιτρέπει τη χρήση πρόσφατου κωδικού πρόσβασης"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Οι συνηθισμένοι κωδικοί πρόσβασης αποκλείονται από τον διαχειριστή IT. Δοκιμάστε να χρησιμοποιήσετε διαφορετικό κωδικό πρόσβασης."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Δεν επιτρέπεται η αύξουσα, φθίνουσα ή επαναλαμβανόμενη ακολουθία ψηφίων"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Δίκτυο κινητής τηλεφωνίας"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Όταν το Wi‑Fi δεν είναι διαθέσιμο, χρήση δικτύου κινητής τηλεφωνίας."</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Εάν το δίκτυο κινητής τηλεφωνίας δεν είναι διαθέσιμο, χρήση Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Κλήση μέσω Wi‑Fi. Εάν χαθεί η σύνδεση Wi‑Fi, η κλήση τερματίζεται."</string>
@@ -1332,7 +1337,7 @@
     <string name="status_number_sim_slot" product="tablet" msgid="4518232285651165459">"MDN (υποδοχή sim %1$d)"</string>
     <string name="status_number_sim_slot" product="default" msgid="3660851494421332328">"Αριθμ. τηλ. (υποδοχή sim %1$d)"</string>
     <string name="status_number_sim_status" product="tablet" msgid="8069693515860290952">"MDN στη SIM"</string>
-    <string name="status_number_sim_status" product="default" msgid="6602562692270457610">"Αριθμός τηλεφώνουν στη SIM"</string>
+    <string name="status_number_sim_status" product="default" msgid="6602562692270457610">"Αριθμός τηλεφώνου στη SIM"</string>
     <string name="status_min_number" msgid="8346889546673707777">"ΛΕΠΤΟ"</string>
     <string name="status_msid_number" msgid="7808175928664357661">"MSID"</string>
     <string name="status_prl_version" msgid="5634561205739199042">"Έκδοση PRL"</string>
@@ -1605,9 +1610,9 @@
     <string name="master_clear_progress_text" msgid="5418958116008976218">"Περιμένετε…"</string>
     <string name="call_settings_title" msgid="5033906789261282752">"Ρυθμίσεις κλήσης"</string>
     <string name="call_settings_summary" msgid="2119161087671450035">"Ορισμ.αυτόμ.τηλεφ., προώθ.κλήσης, αναμ.κλήσης, αναγν.κλήσ."</string>
-    <string name="tether_settings_title_usb" msgid="4265582654602420357">"Πρόσδεση USB"</string>
+    <string name="tether_settings_title_usb" msgid="4265582654602420357">"Σύνδεση USB"</string>
     <string name="tether_settings_title_wifi" msgid="2060965130234484613">"Φορητό σημείο πρόσβασης"</string>
-    <string name="tether_settings_title_bluetooth" msgid="1999590158102569959">"Πρόσδεση Bluetooth"</string>
+    <string name="tether_settings_title_bluetooth" msgid="1999590158102569959">"Σύνδεση με Bluetooth"</string>
     <string name="tether_settings_title_usb_bluetooth" msgid="1159128764162788159">"Πρόσδεση"</string>
     <string name="tether_settings_title_all" msgid="6935843543433954181">"Σημ. πρόσβ. Wi-Fi/σύνδεση"</string>
     <string name="tether_settings_summary_hotspot_on_tether_on" msgid="1289593649526514499">"Το σημείο πρόσβασης είναι ενεργό, σε σύνδεση"</string>
@@ -1615,10 +1620,10 @@
     <string name="tether_settings_summary_hotspot_off_tether_on" msgid="1349909238672649877">"Σύνδεση"</string>
     <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"Δεν είναι δυνατή η σύνδεση σε φορητό σημείο πρόσβασης Wi-Fi, ενώ είναι ενεργοποιημένη η Εξοικονόμηση δεδομένων"</string>
     <string name="usb_title" msgid="7480927657535578688">"USB"</string>
-    <string name="usb_tethering_button_text" msgid="6242228383142012332">"Πρόσδεση USB"</string>
-    <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"Μοιραστείτε τη σύνδεση του τηλεφώνου στο διαδίκτυο μέσω USB"</string>
+    <string name="usb_tethering_button_text" msgid="6242228383142012332">"Σύνδεση USB"</string>
+    <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"Κοινή χρήση της σύνδεσης του τηλεφώνου στο διαδίκτυο μέσω USB"</string>
     <string name="usb_tethering_subtext" product="tablet" msgid="154536000235361034">"Μοιραστείτε τη σύνδεση του tablet στο διαδίκτυο μέσω USB"</string>
-    <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"Πρόσδεση Bluetooth"</string>
+    <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"Σύνδεση με Bluetooth"</string>
     <string name="bluetooth_tethering_subtext" product="tablet" msgid="6868756914621131635">"Κοινή χρήση της σύνδεσης του tablet στο διαδίκτυο μέσω Bluetooth"</string>
     <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"Κοινή χρήση της σύνδεσης του τηλεφώνου στο διαδίκτυο μέσω Bluetooth"</string>
     <string name="bluetooth_tethering_off_subtext_config" msgid="3981528184780083266">"Κοινή χρήση σύνδεσης της συσκευής <xliff:g id="DEVICE_NAME">%1$d</xliff:g> στο διαδίκτυο μέσω Bluetooth"</string>
@@ -2080,7 +2085,7 @@
     <string name="accessibility_control_timeout_preference_title" msgid="2771808346038759474">"Ώρα για την εκτέλεση ενεργειών"</string>
     <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"Επιλέξτε το χρονικό διάστημα για το οποίο θέλετε να εμφανίζονται τα μηνύματα που θα πρέπει να διαβάζετε, αλλά τα οποία είναι ορατά μόνο προσωρινά.\n\nΑυτή η ρύθμιση δεν υποστηρίζεται από όλες τις εφαρμογές."</string>
     <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"Επιλέξτε το χρονικό διάστημα για το οποίο θέλετε να εμφανίζονται τα μηνύματα που σας ζητούν να προβείτε σε κάποια ενέργεια, αλλά τα οποία είναι ορατά μόνο προσωρινά.\n\nΑυτή η ρύθμιση δεν υποστηρίζεται από όλες τις εφαρμογές."</string>
-    <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"Καθυστέρηση παρατετ. αγγίγματος"</string>
+    <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"Διάρκεια παρατεταμένου αγγίγματος"</string>
     <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"Αντιστροφή χρωμάτων"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"Ενδέχεται να επηρεάσει την απόδοση"</string>
     <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"Χρόνος παραμονής"</string>
@@ -2446,7 +2451,7 @@
     <string name="battery_saver_auto_no_schedule" msgid="739814529432092706">"Δεν υπάρχει πρόγραμμα"</string>
     <string name="battery_saver_auto_routine" msgid="886514412067906980">"Με βάση τη ρουτίνα σας"</string>
     <string name="battery_saver_auto_percentage" msgid="5791982309331921556">"Βάσει ποσοστού"</string>
-    <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"Η εξοικονόμηση μπαταρίας ενεργοποιείται όταν υπάρχει σημαντική πιθανότητα εξάντλησης της μπαταρίας σας πριν την επόμενη τυπική φόρτιση"</string>
+    <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"Η εξοικονόμηση μπαταρίας ενεργοποιείται όταν υπάρχει σημαντική πιθανότητα εξάντλησης της μπαταρίας σας πριν την επόμενη κανονική φόρτιση"</string>
     <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"Θα ενεργοποιηθεί στο <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"Ορίστε ένα πρόγραμμα"</string>
     <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"Απενεργοποίηση κατά την πλήρη φόρτιση"</string>
@@ -2729,7 +2734,7 @@
     <string name="data_usage_metered_wifi" msgid="2955256408132426720">"Δίκτυα Wi‑Fi με βάση τη χρήση"</string>
     <string name="data_usage_metered_wifi_disabled" msgid="5771083253782103415">"Για επιλογή δικτύων με βάση τη χρήση, ενεργοποιήστε το Wi-Fi."</string>
     <string name="data_usage_metered_auto" msgid="7924116401382629319">"Αυτόματα"</string>
-    <string name="data_usage_metered_yes" msgid="7333744880035386073">"Με περιορισμούς"</string>
+    <string name="data_usage_metered_yes" msgid="7333744880035386073">"Με ογκοχρέωση"</string>
     <string name="data_usage_metered_no" msgid="1961524615778610008">"Χωρίς περιορισμούς"</string>
     <string name="data_usage_disclaimer" msgid="4683321532922590425">"Ο υπολογισμός δεδ.της εταιρείας κιν.τηλ. μπορεί να διαφέρει από τη συσκευή σας."</string>
     <string name="cryptkeeper_emergency_call" msgid="4625420047524693116">"Κλήση έκτακτης ανάγκης"</string>
@@ -2865,7 +2870,7 @@
     <string name="user_add_user_item_title" msgid="6835385073795492410">"Χρήστης"</string>
     <string name="user_add_profile_item_title" msgid="4932743891449790664">"Προφίλ περιορ. πρόσβασης"</string>
     <string name="user_add_user_title" msgid="2320897397066676472">"Προσθήκη νέου χρήστη;"</string>
-    <string name="user_add_user_message_long" msgid="686637203224195465">"Μπορείτε να μοιραστείτε αυτήν τη συσκευή με άλλα άτομα, δημιουργώντας επιπλέον χρήστες. Κάθε χρήστης θα έχει το δικό του χώρο, τον οποίο μπορεί να προσαρμόσει με τις δικές του εφαρμογές, ταπετσαρία κ.λπ. Οι χρήστες μπορούν επίσης να προσαρμόσουν ρυθμίσεις της συσκευής, όπως το Wi‑Fi, που επηρεάζουν τους πάντες.\n\nΚατά την προσθήκη ενός νέου χρήστη, αυτός θα πρέπει να ρυθμίσει τον χώρο του.\n\nΟποιοσδήποτε χρήστης μπορεί να ενημερώσει τις εφαρμογές για όλους τους άλλους χρήστες. Οι ρυθμίσεις και οι υπηρεσίες προσβασιμότητας ενδέχεται να μην μεταφερθούν στον νέο χρήστη"</string>
+    <string name="user_add_user_message_long" msgid="686637203224195465">"Μπορείτε να μοιραστείτε αυτήν τη συσκευή με άλλα άτομα, δημιουργώντας επιπλέον χρήστες. Κάθε χρήστης θα έχει το δικό του χώρο, τον οποίο μπορεί να προσαρμόσει με τις δικές του εφαρμογές, ταπετσαρία κ.λπ. Οι χρήστες μπορούν επίσης να προσαρμόσουν ρυθμίσεις της συσκευής, όπως το Wi‑Fi, που επηρεάζουν τους πάντες.\n\nΚατά την προσθήκη ενός νέου χρήστη, αυτός θα πρέπει να ρυθμίσει τον χώρο του.\n\nΟποιοσδήποτε χρήστης μπορεί να ενημερώσει τις εφαρμογές για όλους τους άλλους χρήστες. Οι ρυθμίσεις και οι υπηρεσίες προσβασιμότητας ενδέχεται να μην μεταφερθούν στον νέο χρήστη."</string>
     <string name="user_add_user_message_short" msgid="1802594476285458254">"Κατά την προσθήκη ενός νέου χρήστη, αυτός θα πρέπει να ρυθμίσει το χώρο του.\n\nΟποιοσδήποτε χρήστης μπορεί να ενημερώσει τις εφαρμογές για όλους τους άλλους χρήστες."</string>
     <string name="user_setup_dialog_title" msgid="6748950002206392396">"Να γίνει ρύθμιση χρήστη τώρα;"</string>
     <string name="user_setup_dialog_message" msgid="2988559933258353919">"Βεβαιωθείτε ότι ο χρήστης μπορεί να πάρει τη συσκευή και ρυθμίστε το χώρο του"</string>
@@ -4129,7 +4134,7 @@
     <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"Πατήστε για έλεγχο του τηλεφώνου"</string>
     <string name="ambient_display_tap_screen_title" product="tablet" msgid="6434521782016864148">"Πατήστε για έλεγχο του tablet"</string>
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"Πατήστε για έλεγχο της συσκευής"</string>
-    <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"Πατήστε την οθόνη για να ελέγξετε την ώρα, τις ειδοποιήσεις και άλλες πληροφορίες."</string>
+    <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"Πατήστε την οθόνη για να δείτε την ώρα, τις ειδοποιήσεις και άλλες πληροφορίες."</string>
     <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"Σύρετε στον αισθητήρα δακτυλικών αποτυπωμάτων για ειδοποιήσεις"</string>
     <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"Ολίσθηση δακτυλ. αποτυπ."</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"Για να ελέγξετε τις ειδοποιήσεις σας, σύρετε προς τα κάτω στον αισθητήρα δακτυλικών αποτυπωμάτων στο πίσω μέρος του τηλεφώνου."</string>
diff --git a/tests/CarDeveloperOptions/res/values-en-rAU/arrays.xml b/tests/CarDeveloperOptions/res/values-en-rAU/arrays.xml
index f718198..b001bdd 100644
--- a/tests/CarDeveloperOptions/res/values-en-rAU/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-en-rAU/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"run in background"</item>
     <item msgid="6423861043647911030">"accessibility volume"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Location"</item>
+    <item msgid="6656077694190491067">"Location"</item>
+    <item msgid="8790228218278477369">"Location"</item>
+    <item msgid="7836406246005211990">"Vibrate"</item>
+    <item msgid="3951439024549922598">"Read contacts"</item>
+    <item msgid="8802152411647068">"Modify contacts"</item>
+    <item msgid="229544934599698735">"Read call log"</item>
+    <item msgid="7396102294405899613">"Modify call log"</item>
+    <item msgid="3597797992398484655">"Read calendar"</item>
+    <item msgid="2705975774250907343">"Modify calendar"</item>
+    <item msgid="4668747371441932697">"Location"</item>
+    <item msgid="1487578921720243646">"Post notification"</item>
+    <item msgid="4636080349724146638">"Location"</item>
+    <item msgid="673510900286463926">"Call phone"</item>
+    <item msgid="542083422784609790">"Read SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Write SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Receive SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Receive SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Receive SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Receive SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Send SMS/MMS"</item>
+    <item msgid="4726682243833913568">"Read SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Write SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Modify settings"</item>
+    <item msgid="8705854389991425629">"Draw on top"</item>
+    <item msgid="5861356020344153651">"Access notifications"</item>
+    <item msgid="78432174621628659">"Camera"</item>
+    <item msgid="3986116419882154794">"Record audio"</item>
+    <item msgid="4516840825756409490">"Play audio"</item>
+    <item msgid="6811712502798183957">"Read clipboard"</item>
+    <item msgid="2780369012602289114">"Modify clipboard"</item>
+    <item msgid="2331359440170850868">"Media buttons"</item>
+    <item msgid="6133599737122751231">"Audio focus"</item>
+    <item msgid="6844485713404805301">"Master volume"</item>
+    <item msgid="1600379420669104929">"Voice volume"</item>
+    <item msgid="6296768210470214866">"Ring volume"</item>
+    <item msgid="510690696071629241">"Media volume"</item>
+    <item msgid="406861638631430109">"Alarm volume"</item>
+    <item msgid="4715864795872233884">"Notification volume"</item>
+    <item msgid="2311478519251301183">"Bluetooth volume"</item>
+    <item msgid="5133991377896747027">"Keep awake"</item>
+    <item msgid="2464189519136248621">"Location"</item>
+    <item msgid="2062677934050803037">"Location"</item>
+    <item msgid="1735171933192715957">"Get usage stats"</item>
+    <item msgid="1014093788778383554">"Mute/unmute microphone"</item>
+    <item msgid="4199297950608622850">"Show toast"</item>
+    <item msgid="2527962435313398821">"Project media"</item>
+    <item msgid="5117506254221861929">"Activate VPN"</item>
+    <item msgid="8291198322681891160">"Write wallpaper"</item>
+    <item msgid="7106921284621230961">"Assist structure"</item>
+    <item msgid="4496533640894624799">"Assist screenshot"</item>
+    <item msgid="2598847264853993611">"Read phone state"</item>
+    <item msgid="9215610846802973353">"Add voicemail"</item>
+    <item msgid="9186411956086478261">"Use sip"</item>
+    <item msgid="6884763100104539558">"Process outgoing call"</item>
+    <item msgid="125513972170580692">"Fingerprint"</item>
+    <item msgid="2556071024281275619">"Body sensors"</item>
+    <item msgid="617168514928339387">"Read mobile broadcasts"</item>
+    <item msgid="7134693570516523585">"Mock location"</item>
+    <item msgid="7224489175375229399">"Read storage"</item>
+    <item msgid="8472735063903258202">"Write storage"</item>
+    <item msgid="4069276819909595110">"Turn on screen"</item>
+    <item msgid="1228338896751121025">"Get accounts"</item>
+    <item msgid="3181581793459233672">"Run in background"</item>
+    <item msgid="2340936043025374076">"Accessibility volume"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Short"</item>
     <item msgid="4816511817309094890">"Medium"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Never allow"</item>
     <item msgid="8184570120217958741">"Always allow"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Moderate"</item>
+    <item msgid="1555861583162930714">"Low"</item>
+    <item msgid="1719683776264798117">"Critical"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normal"</item>
+    <item msgid="6107138933849816768">"Moderate"</item>
+    <item msgid="182695359839047859">"Low"</item>
+    <item msgid="8577246509202964244">"Critical"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Persistent"</item>
     <item msgid="167418068739176448">"Top activity"</item>
diff --git a/tests/CarDeveloperOptions/res/values-en-rAU/config.xml b/tests/CarDeveloperOptions/res/values-en-rAU/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-en-rAU/config.xml
+++ b/tests/CarDeveloperOptions/res/values-en-rAU/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-en-rAU/strings.xml b/tests/CarDeveloperOptions/res/values-en-rAU/strings.xml
index 0cf4a48..269d56e 100644
--- a/tests/CarDeveloperOptions/res/values-en-rAU/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-en-rAU/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Make the text on screen smaller or larger."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Make smaller"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Make larger"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Sample text"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"The Wonderful Wizard of Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Chapter 11: The Wonderful Emerald City of Oz"</string>
@@ -461,7 +460,7 @@
     <string name="skip_lock_screen_dialog_button_label" msgid="6706047245716780006">"Skip"</string>
     <string name="cancel_lock_screen_dialog_button_label" msgid="2534925227627658819">"Cancel"</string>
     <string name="security_settings_fingerprint_enroll_find_sensor_title" msgid="8909829699273726469">"Touch the sensor"</string>
-    <string name="security_settings_fingerprint_enroll_find_sensor_message" msgid="581120963079780740">"It’s on the back of your phone. Use your index finger."</string>
+    <string name="security_settings_fingerprint_enroll_find_sensor_message" msgid="581120963079780740">"It\'s on the back of your phone. Use your index finger."</string>
     <string name="security_settings_fingerprint_enroll_find_sensor_content_description" msgid="7835824123269738540">"Illustration with device and fingerprint sensor location"</string>
     <string name="security_settings_fingerprint_enroll_dialog_name_label" msgid="3519748398694308901">"Name"</string>
     <string name="security_settings_fingerprint_enroll_dialog_ok" msgid="3428927518029038956">"OK"</string>
@@ -502,7 +501,7 @@
     <string name="fingerprint_last_delete_title" msgid="3104596858161269635">"Remove all fingerprints?"</string>
     <string name="fingerprint_delete_title" msgid="3120894112324235536">"Remove \'<xliff:g id="FINGERPRINT_ID">%1$s</xliff:g>\'"</string>
     <string name="fingerprint_delete_message" msgid="5895802741486967970">"Do you want to delete this fingerprint?"</string>
-    <string name="fingerprint_last_delete_message" msgid="3346252479778971442">"You won\'t be able to use your fingerprints to unlock your phone, authorise purchases or sign in to apps"</string>
+    <string name="fingerprint_last_delete_message" msgid="3346252479778971442">"You won\'t be able to use your fingerprints to unlock your phone, authorise purchases, or sign in to apps"</string>
     <string name="fingerprint_last_delete_message_profile_challenge" msgid="5385095150532247025">"You won\'t be able to use your fingerprints to unlock your work profile, authorise purchases or sign in to work apps"</string>
     <string name="fingerprint_last_delete_confirm" msgid="7984595457589664004">"Yes, remove"</string>
     <string name="crypt_keeper_settings_title" msgid="839783588093862748">"Encryption"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Must be fewer than <xliff:g id="NUMBER_1">%d</xliff:g> digits</item>
       <item quantity="one">Must be fewer than <xliff:g id="NUMBER_0">%d</xliff:g> digit</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Must only contain digits 0-9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Device admin doesn\'t allow using a recent PIN"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Common PINs are blocked by your IT admin. Try a different PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"This can\'t include an invalid character"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Must contain at least <xliff:g id="COUNT">%d</xliff:g> non-letter characters</item>
       <item quantity="one">Must contain at least 1 non-letter character</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Must contain at least <xliff:g id="COUNT">%d</xliff:g> non-numeric characters</item>
+      <item quantity="one">Must contain at least 1 non-numeric character</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Device admin doesn\'t allow using a recent password"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Common passwords are blocked by your IT admin. Try a different password."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Ascending, descending or repeated sequence of digits isn\'t allowed"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mobile"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"If Wi‑Fi is unavailable, use mobile network"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"If mobile network is unavailable, use Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Call over Wi‑Fi. If Wi‑Fi is lost, call will end."</string>
@@ -1565,23 +1570,23 @@
     <string name="restore_default_apn_completed" msgid="5671734152740058937">"Reset default APN settings completed"</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"Reset options"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"Network, apps or device can be reset"</string>
-    <string name="reset_network_title" msgid="8944059136930806211">"Reset Wi-Fi, mobile &amp; Bluetooth"</string>
+    <string name="reset_network_title" msgid="8944059136930806211">"Reset wi-fi, mobile and Bluetooth"</string>
     <string name="reset_network_desc" msgid="4982633363916261109">"This will reset all network settings, including:\n\n"<li>"Wi‑Fi"</li>\n<li>"Mobile data"</li>\n<li>"Bluetooth"</li></string>
     <string name="reset_esim_title" msgid="7630781767040831893">"Erase downloaded SIMs"</string>
-    <string name="reset_esim_desc" msgid="433226911566802">"To download replacement SIMs, contact your operator. This won’t cancel any mobile service plans."</string>
+    <string name="reset_esim_desc" msgid="433226911566802">"To download replacement SIMs, contact your carrier. This won\'t cancel any mobile service plans."</string>
     <string name="reset_network_button_text" msgid="4293271046867912819">"Reset settings"</string>
-    <string name="reset_network_final_desc" msgid="2463817067048751373">"Reset all network settings? You can’t undo this action."</string>
-    <string name="reset_network_final_desc_esim" msgid="4676436976372555750">"Reset all network settings and delete downloaded SIMs? You can’t undo this action."</string>
+    <string name="reset_network_final_desc" msgid="2463817067048751373">"Reset all network settings? You can\'t undo this action."</string>
+    <string name="reset_network_final_desc_esim" msgid="4676436976372555750">"Reset all network settings and erase downloaded SIMs? You can\'t undo this action."</string>
     <string name="reset_network_final_button_text" msgid="345255333127794393">"Reset settings"</string>
     <string name="reset_network_confirm_title" msgid="2432145031070536008">"Reset?"</string>
     <string name="network_reset_not_available" msgid="6146655531868016281">"Network reset is not available for this user"</string>
     <string name="reset_network_complete_toast" msgid="128225929536005495">"Network settings have been reset"</string>
     <string name="reset_esim_error_title" msgid="4728931209471875632">"Can’t delete SIMs"</string>
     <string name="reset_esim_error_msg" msgid="4716366079119742235">"Downloaded SIMs can’t be deleted due to an error.\n\nRestart your device and try again."</string>
-    <string name="master_clear_title" msgid="1560712943955904673">"Erase all data (factory reset)"</string>
-    <string name="master_clear_short_title" msgid="919098101581335101">"Erase all data (factory reset)"</string>
+    <string name="master_clear_title" msgid="1560712943955904673">"Delete all data (factory reset)"</string>
+    <string name="master_clear_short_title" msgid="919098101581335101">"Delete all data (factory reset)"</string>
     <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"This will erase all data from your tablet’s "<b>"internal storage"</b>", including:\n\n"<li>"Your Google Account"</li>\n<li>"System and app data and settings"</li>\n<li>"Downloaded apps"</li></string>
-    <string name="master_clear_desc" product="default" msgid="8765543541962866697">"This will erase all data from your phone’s "<b>"internal storage"</b>", including:\n\n"<li>"Your Google Account"</li>\n<li>"System and app data and settings"</li>\n<li>"Downloaded apps"</li></string>
+    <string name="master_clear_desc" product="default" msgid="8765543541962866697">"This will erase all data from your phone\'s "<b>"internal storage"</b>", including:\n\n"<li>"Your Google Account"</li>\n<li>"System and app data and settings"</li>\n<li>"Downloaded apps"</li></string>
     <string name="master_clear_accounts" product="default" msgid="3432884235445405376">\n\n"You are currently signed in to the following accounts:\n"</string>
     <string name="master_clear_other_users_present" product="default" msgid="5993259656117566767">\n\n"There are other users present on this device.\n"</string>
     <string name="master_clear_desc_also_erases_external" msgid="3947303501615091903"><li>"Music"</li>\n<li>"Photos"</li>\n<li>"Other user data"</li></string>
@@ -1595,8 +1600,8 @@
     <string name="erase_external_storage_description" product="default" msgid="5029355708082861798">"Erase all the data on the SD card, such as music or photos"</string>
     <string name="master_clear_button_text" product="tablet" msgid="8000547818499182920">"Delete all data"</string>
     <string name="master_clear_button_text" product="default" msgid="8000547818499182920">"Delete all data"</string>
-    <string name="master_clear_final_desc" msgid="5189365498015339294">"All of your personal information and downloaded apps will be deleted. You can’t undo this action."</string>
-    <string name="master_clear_final_desc_esim" msgid="3058919823436953662">"All of your personal information, including downloaded apps &amp; SIMs, will be deleted. You can’t undo this action."</string>
+    <string name="master_clear_final_desc" msgid="5189365498015339294">"All of your personal information and downloaded apps will be deleted. You can\'t undo this action."</string>
+    <string name="master_clear_final_desc_esim" msgid="3058919823436953662">"All of your personal information, including downloaded apps &amp; SIMs, will be deleted. You can\'t undo this action."</string>
     <string name="master_clear_final_button_text" msgid="866772743886027768">"Erase everything"</string>
     <string name="master_clear_failed" msgid="7588397453984229892">"No reset was performed because the System Clear service isn\'t available."</string>
     <string name="master_clear_confirm_title" msgid="698328669893512402">"Erase all data?"</string>
@@ -2059,7 +2064,7 @@
     <string name="accessibility_global_gesture_preference_title" msgid="3842279082831426816">"Volume key shortcut"</string>
     <string name="accessibility_shortcut_service_title" msgid="3516052294376744060">"Shortcut service"</string>
     <string name="accessibility_shortcut_service_on_lock_screen_title" msgid="1279441617927949980">"Allow from lock screen"</string>
-    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"When the shortcut is on, you can press both volume keys for 3 seconds to start an accessibility feature."</string>
+    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"When the shortcut is on, you can press both volume keys for three seconds to start an accessibility feature."</string>
     <string name="accessibility_toggle_high_text_contrast_preference_title" msgid="5652244684961877255">"High-contrast text"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"Auto update screen magnification"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"Update screen magnification on app transitions"</string>
@@ -2197,7 +2202,7 @@
       <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> print jobs</item>
       <item quantity="one">1 print job</item>
     </plurals>
-    <string name="print_settings_title" msgid="2886445296786932763">"Printing services"</string>
+    <string name="print_settings_title" msgid="2886445296786932763">"Print services"</string>
     <string name="print_no_services_installed" msgid="3387777739528003794">"No services installed"</string>
     <string name="print_no_printers_found" msgid="5090925427392294881">"No printers found"</string>
     <string name="print_menu_item_settings" msgid="2654804159012579508">"Settings"</string>
@@ -2312,12 +2317,12 @@
     <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"This app will be able to use battery in the background. Your battery may run out sooner than expected."</string>
     <string name="battery_tip_unrestrict_app_dialog_ok" msgid="9154938931448151479">"Remove"</string>
     <string name="battery_tip_unrestrict_app_dialog_cancel" msgid="7331148618292397166">"Cancel"</string>
-    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"Your apps are using a normal amount of battery. If apps use too much battery, your phone will suggest actions that you can take.\n\nYou can always turn on Battery Saver if you’re running low on battery."</string>
+    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"Your apps are using a normal amount of battery. If apps use too much battery, your phone will suggest actions you can take.\n\nYou can always turn on Battery Saver if you\'re running low on battery."</string>
     <string name="battery_tip_dialog_summary_message" product="tablet" msgid="1721081030632329647">"Your apps are using a normal amount of battery. If apps use too much battery, your tablet will suggest actions that you can take.\n\nYou can always turn on Battery Saver if you’re running low on battery."</string>
     <string name="battery_tip_dialog_summary_message" product="device" msgid="146872407040848465">"Your apps are using a normal amount of battery. If apps use too much battery, your device will suggest actions that you can take.\n\nYou can always turn on Battery Saver if you’re running low on battery."</string>
     <string name="smart_battery_manager_title" msgid="5744035036663849515">"Battery Manager"</string>
     <string name="smart_battery_title" msgid="4919670408532804351">"Manage apps automatically"</string>
-    <string name="smart_battery_summary" msgid="640027046471198174">"Limit battery for apps that you don’t use often"</string>
+    <string name="smart_battery_summary" msgid="640027046471198174">"Limit battery for apps that you don\'t use often"</string>
     <string name="smart_battery_footer" product="default" msgid="3971715848890205632">"When Battery Manager detects that apps are draining battery, you’ll have the option to restrict these apps. Restricted apps may not work properly and notifications may be delayed."</string>
     <string name="smart_battery_footer" product="tablet" msgid="3971715848890205632">"When Battery Manager detects that apps are draining battery, you’ll have the option to restrict these apps. Restricted apps may not work properly and notifications may be delayed."</string>
     <string name="smart_battery_footer" product="device" msgid="3971715848890205632">"When Battery Manager detects that apps are draining battery, you’ll have the option to restrict these apps. Restricted apps may not work properly and notifications may be delayed."</string>
@@ -2710,7 +2715,7 @@
     <string name="data_usage_limit_editor_title" msgid="1687908662154108293">"Set data usage limit"</string>
     <string name="data_usage_limit_dialog_title" msgid="8804760847110131518">"Limiting data usage"</string>
     <string name="data_usage_limit_dialog_mobile" product="tablet" msgid="2000713577999830647">"Your tablet will turn off mobile data once it reaches the limit you set.\n\nSince data usage is measured by your tablet, and your operator may account for usage differently, consider setting a conservative limit."</string>
-    <string name="data_usage_limit_dialog_mobile" product="default" msgid="943546278705619205">"Your phone will turn off mobile data once it reaches the limit that you set.\n\nSince data usage is measured by your phone, and your operator may account for usage differently, consider setting a conservative limit."</string>
+    <string name="data_usage_limit_dialog_mobile" product="default" msgid="943546278705619205">"Your phone will turn off mobile data once it reaches the limit you set.\n\nSince data usage is measured by your phone, and your carrier may account for usage differently, consider setting a conservative limit."</string>
     <string name="data_usage_restrict_background_title" msgid="3568746530413220844">"Restrict background data?"</string>
     <string name="data_usage_restrict_background" msgid="995811034744808575">"If you restrict background mobile data, some apps and services won’t work unless you’re connected to Wi‑Fi."</string>
     <string name="data_usage_restrict_background_multiuser" product="tablet" msgid="6032810839234864814">"If you restrict background mobile data, some apps and services won’t work unless you’re connected to Wi‑Fi.\n\nThis setting affects all users on this tablet."</string>
@@ -2930,7 +2935,7 @@
     <string name="restriction_menu_reset" msgid="3642252461410370554">"Remove restrictions"</string>
     <string name="restriction_menu_change_pin" msgid="592512748243421101">"Change PIN"</string>
     <string name="app_notifications_switch_label" msgid="670683308275498821">"Show notifications"</string>
-    <string name="help_label" msgid="1296484776243905646">"Help &amp; feedback"</string>
+    <string name="help_label" msgid="1296484776243905646">"Help and feedback"</string>
     <string name="support_summary" msgid="3278943815956130740">"Help articles, phone &amp; chat, getting started"</string>
     <string name="user_account_title" msgid="2108666882630552859">"Account for content"</string>
     <string name="user_picture_title" msgid="6664602422948159123">"Photo ID"</string>
@@ -3937,7 +3942,7 @@
     <string name="cell_data_template" msgid="5473177306229738078">"<xliff:g id="AMOUNT">^1</xliff:g> mobile data"</string>
     <string name="wifi_data_template" msgid="3146090439147042068">"<xliff:g id="AMOUNT">^1</xliff:g> Wi-Fi data"</string>
     <string name="ethernet_data_template" msgid="6414118030827090119">"<xliff:g id="AMOUNT">^1</xliff:g> ethernet data"</string>
-    <string name="billing_cycle" msgid="5740717948341713190">"Data warning &amp; limit"</string>
+    <string name="billing_cycle" msgid="5740717948341713190">"Data warning and limit"</string>
     <string name="app_usage_cycle" msgid="213483325132959663">"App data usage cycle"</string>
     <string name="cell_data_warning" msgid="8902740337286652689">"<xliff:g id="ID_1">^1</xliff:g> data warning"</string>
     <string name="cell_data_limit" msgid="3175933829235314233">"<xliff:g id="ID_1">^1</xliff:g> data limit"</string>
@@ -4264,7 +4269,7 @@
     <string name="storage_manager_indicator_on" msgid="5295306384982062320">"On"</string>
     <string name="install_type_instant" msgid="6248487669862821874">"Instant app"</string>
     <string name="automatic_storage_manager_deactivation_warning" msgid="7867793739491286374">"Turn off the storage manager?"</string>
-    <string name="storage_movies_tv" msgid="7282484273991655296">"Movie &amp; TV apps"</string>
+    <string name="storage_movies_tv" msgid="7282484273991655296">"Movie and TV apps"</string>
     <string name="carrier_provisioning" msgid="3309125279191534469">"Operator Provisioning Info"</string>
     <string name="trigger_carrier_provisioning" msgid="6284005970057901477">"Trigger Operator Provisioning"</string>
     <string name="zen_suggestion_title" msgid="2134699720214231950">"Update Do Not Disturb"</string>
diff --git a/tests/CarDeveloperOptions/res/values-en-rCA/arrays.xml b/tests/CarDeveloperOptions/res/values-en-rCA/arrays.xml
index f718198..3202796 100644
--- a/tests/CarDeveloperOptions/res/values-en-rCA/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-en-rCA/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"run in background"</item>
     <item msgid="6423861043647911030">"accessibility volume"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Location"</item>
+    <item msgid="6656077694190491067">"Location"</item>
+    <item msgid="8790228218278477369">"Location"</item>
+    <item msgid="7836406246005211990">"Vibrate"</item>
+    <item msgid="3951439024549922598">"Read contacts"</item>
+    <item msgid="8802152411647068">"Modify contacts"</item>
+    <item msgid="229544934599698735">"Read call log"</item>
+    <item msgid="7396102294405899613">"Modify call log"</item>
+    <item msgid="3597797992398484655">"Read calendar"</item>
+    <item msgid="2705975774250907343">"Modify calendar"</item>
+    <item msgid="4668747371441932697">"Location"</item>
+    <item msgid="1487578921720243646">"Post notification"</item>
+    <item msgid="4636080349724146638">"Location"</item>
+    <item msgid="673510900286463926">"Call phone"</item>
+    <item msgid="542083422784609790">"Read SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Write SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Receive SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Receive SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Receive SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Receive SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Send SMS/MMS"</item>
+    <item msgid="4726682243833913568">"Read SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Write SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Modify settings"</item>
+    <item msgid="8705854389991425629">"Draw on top"</item>
+    <item msgid="5861356020344153651">"Access notifications"</item>
+    <item msgid="78432174621628659">"Camera"</item>
+    <item msgid="3986116419882154794">"Record audio"</item>
+    <item msgid="4516840825756409490">"Play audio"</item>
+    <item msgid="6811712502798183957">"Read clipboard"</item>
+    <item msgid="2780369012602289114">"Modify clipboard"</item>
+    <item msgid="2331359440170850868">"Media buttons"</item>
+    <item msgid="6133599737122751231">"Audio focus"</item>
+    <item msgid="6844485713404805301">"Master volume"</item>
+    <item msgid="1600379420669104929">"Voice volume"</item>
+    <item msgid="6296768210470214866">"Ring volume"</item>
+    <item msgid="510690696071629241">"Media volume"</item>
+    <item msgid="406861638631430109">"Alarm volume"</item>
+    <item msgid="4715864795872233884">"Notification volume"</item>
+    <item msgid="2311478519251301183">"Bluetooth volume"</item>
+    <item msgid="5133991377896747027">"Keep awake"</item>
+    <item msgid="2464189519136248621">"Location"</item>
+    <item msgid="2062677934050803037">"Location"</item>
+    <item msgid="1735171933192715957">"Get usage stats"</item>
+    <item msgid="1014093788778383554">"Mute/unmute microphone"</item>
+    <item msgid="4199297950608622850">"Show toast"</item>
+    <item msgid="2527962435313398821">"Project media"</item>
+    <item msgid="5117506254221861929">"Activate VPN"</item>
+    <item msgid="8291198322681891160">"Write wallpaper"</item>
+    <item msgid="7106921284621230961">"Assist structure"</item>
+    <item msgid="4496533640894624799">"Assist screenshot"</item>
+    <item msgid="2598847264853993611">"Read phone state"</item>
+    <item msgid="9215610846802973353">"Add voicemail"</item>
+    <item msgid="9186411956086478261">"Use sip"</item>
+    <item msgid="6884763100104539558">"Process outgoing call"</item>
+    <item msgid="125513972170580692">"Fingerprint"</item>
+    <item msgid="2556071024281275619">"Body sensors"</item>
+    <item msgid="617168514928339387">"Read mobile broadcasts"</item>
+    <item msgid="7134693570516523585">"Mock location"</item>
+    <item msgid="7224489175375229399">"Read storage"</item>
+    <item msgid="8472735063903258202">"Write storage"</item>
+    <item msgid="4069276819909595110">"Turn on screen"</item>
+    <item msgid="1228338896751121025">"Get accounts"</item>
+    <item msgid="3181581793459233672">"Run in background"</item>
+    <item msgid="2340936043025374076">"Accessibility volume"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Short"</item>
     <item msgid="4816511817309094890">"Medium"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Never allow"</item>
     <item msgid="8184570120217958741">"Always allow"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Moderate"</item>
+    <item msgid="1555861583162930714">"Low"</item>
+    <item msgid="1719683776264798117">"Critical"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normal"</item>
+    <item msgid="6107138933849816768">"Moderate"</item>
+    <item msgid="182695359839047859">"Low"</item>
+    <item msgid="8577246509202964244">"Critical"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Persistent"</item>
     <item msgid="167418068739176448">"Top activity"</item>
@@ -401,7 +477,7 @@
     <item msgid="1008268820118852416">"Treat as unmetered"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
-    <item msgid="6545683814310036454">"Use randomised MAC (default)"</item>
+    <item msgid="6545683814310036454">"Use randomized MAC (default)"</item>
     <item msgid="214234417308375326">"Use device MAC"</item>
   </string-array>
   <string-array name="wifi_hidden_entries">
diff --git a/tests/CarDeveloperOptions/res/values-en-rCA/config.xml b/tests/CarDeveloperOptions/res/values-en-rCA/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-en-rCA/config.xml
+++ b/tests/CarDeveloperOptions/res/values-en-rCA/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-en-rCA/strings.xml b/tests/CarDeveloperOptions/res/values-en-rCA/strings.xml
index f6ca7a1..d1009be 100644
--- a/tests/CarDeveloperOptions/res/values-en-rCA/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-en-rCA/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Make the text on screen smaller or larger."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Make smaller"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Make larger"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Sample text"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"The Wonderful Wizard of Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Chapter 11: The Wonderful Emerald City of Oz"</string>
@@ -163,7 +162,7 @@
     <string name="bluetooth_map_acceptance_dialog_text" msgid="736507842082640410">"%1$s wants to access your messages. Give access to %2$s?"</string>
     <string name="bluetooth_sap_request" msgid="6318039677671263261">"SIM access request"</string>
     <string name="bluetooth_sap_acceptance_dialog_text" msgid="1909352413109340355">"<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g> wants to access your SIM card. Granting access to the SIM card will disable data connectivity on your device for the duration of the connection. Give access to <xliff:g id="DEVICE_NAME_1">%2$s?</xliff:g>"</string>
-    <string name="bluetooth_device_name_summary" msgid="8661066392056595005">"Visible as \'<xliff:g id="DEVICE_NAME">^1</xliff:g>\' to other devices"</string>
+    <string name="bluetooth_device_name_summary" msgid="8661066392056595005">"Visible as \"<xliff:g id="DEVICE_NAME">^1</xliff:g>\" to other devices"</string>
     <string name="bluetooth_off_footer" msgid="7658444560543730571">"Turn on Bluetooth to connect to other devices."</string>
     <string name="bluetooth_paired_device_title" msgid="8361860197780425286">"Your devices"</string>
     <string name="bluetooth_pairing_page_title" msgid="9053463656712597709">"Pair new device"</string>
@@ -402,9 +401,9 @@
     <string name="security_settings_face_enroll_introduction_cancel" msgid="4190924649721437238">"Cancel"</string>
     <string name="security_settings_face_enroll_introduction_title" msgid="6073249653318265486">"Unlock with your face"</string>
     <string name="security_settings_face_enroll_introduction_title_unlock_disabled" msgid="9223270521083202896">"Use your face to authenticate"</string>
-    <string name="security_settings_face_enroll_introduction_message" msgid="484806903869220184">"Use your face to unlock your phone, authorise purchases or sign in to apps."</string>
+    <string name="security_settings_face_enroll_introduction_message" msgid="484806903869220184">"Use your face to unlock your phone, authorize purchases or sign in to apps."</string>
     <string name="security_settings_face_enroll_introduction_message_unlock_disabled" msgid="2850101281254663082">"Use your face to unlock your phone or approve purchases.\n\nNote: You can’t use your face to unlock this device. For more information, contact your organisation’s admin."</string>
-    <string name="security_settings_face_enroll_introduction_message_setup" msgid="4533297059466270074">"Use your face to unlock your phone, authorise purchases or sign in to apps"</string>
+    <string name="security_settings_face_enroll_introduction_message_setup" msgid="4533297059466270074">"Use your face to unlock your phone, authorize purchases or sign in to apps"</string>
     <string name="security_settings_face_enroll_introduction_footer_message" msgid="7764021721107723266"></string>
     <string name="security_settings_face_enroll_repeat_title" msgid="2507710348140837875">"Centre your face in the circle"</string>
     <string name="security_settings_face_enroll_enrolling_skip" msgid="4346077260378772613">"Do it later"</string>
@@ -440,7 +439,7 @@
     <string name="security_settings_fingerprint_preference_summary_none" msgid="3613424536269750172"></string>
     <string name="security_settings_fingerprint_enroll_introduction_title" msgid="889558002683900544">"Unlock with fingerprint"</string>
     <string name="security_settings_fingerprint_enroll_introduction_title_unlock_disabled" msgid="7915504118657864429">"Use your fingerprint"</string>
-    <string name="security_settings_fingerprint_enroll_introduction_message" msgid="5586198131986682472">"Just touch the fingerprint sensor to unlock your phone, authorise purchases or sign in to apps. Be careful whose fingerprints you add. Even one added print can do any of these things.\n\nNote: Your fingerprint may be less secure than a strong pattern or PIN."</string>
+    <string name="security_settings_fingerprint_enroll_introduction_message" msgid="5586198131986682472">"Just touch the fingerprint sensor to unlock your phone, authorize purchases or sign in to apps. Be careful whose fingerprints you add. Even one added print can do any of these things.\n\nNote: Your fingerprint may be less secure than a strong pattern or PIN."</string>
     <string name="security_settings_fingerprint_enroll_introduction_message_unlock_disabled" msgid="1640839304679275468">"Use your fingerprint to unlock your phone or approve purchases.\n\nNote: You can’t use your fingerprint to unlock this device. For more information, contact your organisation’s admin."</string>
     <string name="security_settings_fingerprint_enroll_introduction_message_setup" msgid="6734490666593320711">"Use your fingerprint to unlock your phone or approve purchases.\n\nNote: Your fingerprint may be less secure than a strong pattern or PIN."</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel" msgid="9168637333731599827">"Cancel"</string>
@@ -461,7 +460,7 @@
     <string name="skip_lock_screen_dialog_button_label" msgid="6706047245716780006">"Skip"</string>
     <string name="cancel_lock_screen_dialog_button_label" msgid="2534925227627658819">"Cancel"</string>
     <string name="security_settings_fingerprint_enroll_find_sensor_title" msgid="8909829699273726469">"Touch the sensor"</string>
-    <string name="security_settings_fingerprint_enroll_find_sensor_message" msgid="581120963079780740">"It’s on the back of your phone. Use your index finger."</string>
+    <string name="security_settings_fingerprint_enroll_find_sensor_message" msgid="581120963079780740">"It\'s on the back of your phone. Use your index finger."</string>
     <string name="security_settings_fingerprint_enroll_find_sensor_content_description" msgid="7835824123269738540">"Illustration with device and fingerprint sensor location"</string>
     <string name="security_settings_fingerprint_enroll_dialog_name_label" msgid="3519748398694308901">"Name"</string>
     <string name="security_settings_fingerprint_enroll_dialog_ok" msgid="3428927518029038956">"OK"</string>
@@ -493,8 +492,8 @@
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"Fingerprint enrolment didn\'t work. Try again or use a different finger."</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"Add another"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"Next"</string>
-    <string name="security_settings_fingerprint_enroll_disclaimer" msgid="5831834311961551423">"In addition to unlocking your phone, you can also use your fingerprint to authorise purchases and app access. "<annotation id="url">"Learn more"</annotation></string>
-    <string name="security_settings_fingerprint_enroll_disclaimer_lockscreen_disabled" msgid="7954742554236652690">" The screen lock option is disabled. To find out more, contact your organisation\'s admin. "<annotation id="admin_details">"More details"</annotation>\n\n"You can still use your fingerprint to authorise purchases and app access. "<annotation id="url">"Learn more"</annotation></string>
+    <string name="security_settings_fingerprint_enroll_disclaimer" msgid="5831834311961551423">"In addition to unlocking your phone, you can also use your fingerprint to authorize purchases and app access. "<annotation id="url">"Learn more"</annotation></string>
+    <string name="security_settings_fingerprint_enroll_disclaimer_lockscreen_disabled" msgid="7954742554236652690">" The screen lock option is disabled. To learn more, contact your organization\'s admin. "<annotation id="admin_details">"More details"</annotation>\n\n"You can still use your fingerprint to authorize purchases and app access. "<annotation id="url">"Learn more"</annotation></string>
     <string name="security_settings_fingerprint_enroll_lift_touch_again" msgid="1670703069782212223">"Lift finger, then touch sensor again"</string>
     <string name="fingerprint_add_max" msgid="2939393314646115661">"You can add up to <xliff:g id="COUNT">%d</xliff:g> fingerprints"</string>
     <string name="fingerprint_intro_error_max" msgid="3247720976621039437">"You’ve added the maximum number of fingerprints"</string>
@@ -502,8 +501,8 @@
     <string name="fingerprint_last_delete_title" msgid="3104596858161269635">"Remove all fingerprints?"</string>
     <string name="fingerprint_delete_title" msgid="3120894112324235536">"Remove \'<xliff:g id="FINGERPRINT_ID">%1$s</xliff:g>\'"</string>
     <string name="fingerprint_delete_message" msgid="5895802741486967970">"Do you want to delete this fingerprint?"</string>
-    <string name="fingerprint_last_delete_message" msgid="3346252479778971442">"You won\'t be able to use your fingerprints to unlock your phone, authorise purchases or sign in to apps"</string>
-    <string name="fingerprint_last_delete_message_profile_challenge" msgid="5385095150532247025">"You won\'t be able to use your fingerprints to unlock your work profile, authorise purchases or sign in to work apps"</string>
+    <string name="fingerprint_last_delete_message" msgid="3346252479778971442">"You won\'t be able to use your fingerprints to unlock your phone, authorize purchases or sign in to apps"</string>
+    <string name="fingerprint_last_delete_message_profile_challenge" msgid="5385095150532247025">"You won\'t be able to use your fingerprints to unlock your work profile, authorize purchases or sign in to work apps"</string>
     <string name="fingerprint_last_delete_confirm" msgid="7984595457589664004">"Yes, remove"</string>
     <string name="crypt_keeper_settings_title" msgid="839783588093862748">"Encryption"</string>
     <string name="crypt_keeper_encrypt_title" product="tablet" msgid="2292129135369853167">"Encrypt tablet"</string>
@@ -599,35 +598,35 @@
     <string name="unlock_disable_frp_warning_content_pattern" msgid="1843950215687159135">"Device protection features will not work without your pattern."</string>
     <string name="unlock_disable_frp_warning_content_pattern_fingerprint" msgid="8846957650251741548">"Device protection features will not work without your pattern.<xliff:g id="EMPTY_LINE">
 
-</xliff:g>Your saved fingerprints will also be removed from this device and you won\'t be able to unlock your phone, authorise purchases or sign in to apps with them."</string>
+</xliff:g>Your saved fingerprints will also be removed from this device and you won\'t be able to unlock your phone, authorize purchases or sign in to apps with them."</string>
     <string name="unlock_disable_frp_warning_content_pin" msgid="6760473271034592796">"Device protection features will not work without your PIN."</string>
     <string name="unlock_disable_frp_warning_content_pin_fingerprint" msgid="4384632309103635233">"Device protection features will not work without your PIN.<xliff:g id="EMPTY_LINE">
 
-</xliff:g>Your saved fingerprints will also be removed from this device and you won\'t be able to unlock your phone, authorise purchases or sign in to apps with them."</string>
+</xliff:g>Your saved fingerprints will also be removed from this device and you won\'t be able to unlock your phone, authorize purchases or sign in to apps with them."</string>
     <string name="unlock_disable_frp_warning_content_password" msgid="854665587186358170">"Device protection features will not work without your password."</string>
     <string name="unlock_disable_frp_warning_content_password_fingerprint" msgid="218143910981979545">"Device protection features will not work without your password.<xliff:g id="EMPTY_LINE">
 
-</xliff:g>Your saved fingerprints will also be removed from this device and you won\'t be able to unlock your phone, authorise purchases or sign in to apps with them."</string>
+</xliff:g>Your saved fingerprints will also be removed from this device and you won\'t be able to unlock your phone, authorize purchases or sign in to apps with them."</string>
     <string name="unlock_disable_frp_warning_content_unknown" msgid="3570135744390201244">"Device protection features will not work without your screen lock."</string>
     <string name="unlock_disable_frp_warning_content_unknown_fingerprint" msgid="5775815077478538855">"Device protection features will not work without your screen lock.<xliff:g id="EMPTY_LINE">
 
-</xliff:g>Your saved fingerprints will also be removed from this device and you won\'t be able to unlock your phone, authorise purchases or sign in to apps with them."</string>
+</xliff:g>Your saved fingerprints will also be removed from this device and you won\'t be able to unlock your phone, authorize purchases or sign in to apps with them."</string>
     <string name="unlock_disable_frp_warning_content_pattern_profile" msgid="2369992898062808499">"Profile protection features will not work without your pattern."</string>
     <string name="unlock_disable_frp_warning_content_pattern_fingerprint_profile" msgid="8511105093090018735">"Profile protection features will not work without your pattern.<xliff:g id="EMPTY_LINE">
 
-</xliff:g>Your saved fingerprints will also be removed from this profile and you won\'t be able to unlock your profile, authorise purchases or sign in to apps with them."</string>
+</xliff:g>Your saved fingerprints will also be removed from this profile and you won\'t be able to unlock your profile, authorize purchases or sign in to apps with them."</string>
     <string name="unlock_disable_frp_warning_content_pin_profile" msgid="7114165651000498040">"Profile protection features will not work without your PIN."</string>
     <string name="unlock_disable_frp_warning_content_pin_fingerprint_profile" msgid="5118210431544156122">"Profile protection features will not work without your PIN.<xliff:g id="EMPTY_LINE">
 
-</xliff:g>Your saved fingerprints will also be removed from this profile and you won\'t be able to unlock your profile, authorise purchases or sign in to apps with them."</string>
+</xliff:g>Your saved fingerprints will also be removed from this profile and you won\'t be able to unlock your profile, authorize purchases or sign in to apps with them."</string>
     <string name="unlock_disable_frp_warning_content_password_profile" msgid="3989497526180082037">"Profile protection features will not work without your password."</string>
     <string name="unlock_disable_frp_warning_content_password_fingerprint_profile" msgid="8360485354164416198">"Profile protection features will not work without your password.<xliff:g id="EMPTY_LINE">
 
-</xliff:g>Your saved fingerprints will also be removed from this profile and you won\'t be able to unlock your profile, authorise purchases or sign in to apps with them."</string>
+</xliff:g>Your saved fingerprints will also be removed from this profile and you won\'t be able to unlock your profile, authorize purchases or sign in to apps with them."</string>
     <string name="unlock_disable_frp_warning_content_unknown_profile" msgid="4066001421137974082">"Profile protection features will not work without your screen lock."</string>
     <string name="unlock_disable_frp_warning_content_unknown_fingerprint_profile" msgid="1201259228331105948">"Profile protection features will not work without your screen lock.<xliff:g id="EMPTY_LINE">
 
-</xliff:g>Your saved fingerprints will also be removed from this profile and you won\'t be able to unlock your profile, authorise purchases or sign in to apps with them."</string>
+</xliff:g>Your saved fingerprints will also be removed from this profile and you won\'t be able to unlock your profile, authorize purchases or sign in to apps with them."</string>
     <string name="unlock_disable_frp_warning_ok" msgid="2373890505202766456">"Yes, remove"</string>
     <string name="unlock_change_lock_pattern_title" msgid="7622476883851319877">"Change unlock pattern"</string>
     <string name="unlock_change_lock_pin_title" msgid="6671224158800812238">"Change unlock PIN"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Must be fewer than <xliff:g id="NUMBER_1">%d</xliff:g> digits</item>
       <item quantity="one">Must be fewer than <xliff:g id="NUMBER_0">%d</xliff:g> digit</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Must only contain digits 0-9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Device admin doesn\'t allow using a recent PIN"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Common PINs are blocked by your IT admin. Try a different PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"This can\'t include an invalid character"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Must contain at least <xliff:g id="COUNT">%d</xliff:g> non-letter characters</item>
       <item quantity="one">Must contain at least 1 non-letter character</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Must contain at least <xliff:g id="COUNT">%d</xliff:g> non-numeric characters</item>
+      <item quantity="one">Must contain at least 1 non-numeric character</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Device admin doesn\'t allow using a recent password"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Common passwords are blocked by your IT admin. Try a different password."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Ascending, descending or repeated sequence of digits isn\'t allowed"</string>
@@ -938,8 +940,8 @@
     <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"Centre the QR code below to connect to \'<xliff:g id="SSID">%1$s</xliff:g>\'"</string>
     <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"Join Wi‑Fi by scanning a QR code"</string>
     <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Share Wi‑Fi"</string>
-    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"Scan this QR code to connect to \'<xliff:g id="SSID">%1$s</xliff:g>\' and share the password"</string>
-    <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"Scan this QR code to connect to \'<xliff:g id="SSID">%1$s</xliff:g>\'"</string>
+    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"Scan this QR code to connect to \"<xliff:g id="SSID">%1$s</xliff:g>\" and share the password"</string>
+    <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"Scan this QR code to connect to \"<xliff:g id="SSID">%1$s</xliff:g>\""</string>
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"Couldn’t read QR code. Re-centre code and try again"</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"Try again. If the issue continues, contact the device manufacturer"</string>
     <string name="wifi_dpp_failure_not_compatible" msgid="4320027179973678283">"Something went wrong"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mobile"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"If Wi‑Fi is unavailable, use mobile network"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"If mobile network is unavailable, use Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Call over Wi‑Fi. If Wi‑Fi is lost, call will end."</string>
@@ -1565,13 +1570,13 @@
     <string name="restore_default_apn_completed" msgid="5671734152740058937">"Reset default APN settings completed"</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"Reset options"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"Network, apps or device can be reset"</string>
-    <string name="reset_network_title" msgid="8944059136930806211">"Reset Wi-Fi, mobile &amp; Bluetooth"</string>
+    <string name="reset_network_title" msgid="8944059136930806211">"Reset Wi-Fi, mobile and Bluetooth"</string>
     <string name="reset_network_desc" msgid="4982633363916261109">"This will reset all network settings, including:\n\n"<li>"Wi‑Fi"</li>\n<li>"Mobile data"</li>\n<li>"Bluetooth"</li></string>
     <string name="reset_esim_title" msgid="7630781767040831893">"Erase downloaded SIMs"</string>
-    <string name="reset_esim_desc" msgid="433226911566802">"To download replacement SIMs, contact your operator. This won’t cancel any mobile service plans."</string>
+    <string name="reset_esim_desc" msgid="433226911566802">"To download replacement SIMs, contact your carrier. This won\'t cancel any mobile service plans."</string>
     <string name="reset_network_button_text" msgid="4293271046867912819">"Reset settings"</string>
-    <string name="reset_network_final_desc" msgid="2463817067048751373">"Reset all network settings? You can’t undo this action."</string>
-    <string name="reset_network_final_desc_esim" msgid="4676436976372555750">"Reset all network settings and delete downloaded SIMs? You can’t undo this action."</string>
+    <string name="reset_network_final_desc" msgid="2463817067048751373">"Reset all network settings? You can\'t undo this action"</string>
+    <string name="reset_network_final_desc_esim" msgid="4676436976372555750">"Reset all network settings and erase downloaded SIMs? You can\'t undo this action"</string>
     <string name="reset_network_final_button_text" msgid="345255333127794393">"Reset settings"</string>
     <string name="reset_network_confirm_title" msgid="2432145031070536008">"Reset?"</string>
     <string name="network_reset_not_available" msgid="6146655531868016281">"Network reset is not available for this user"</string>
@@ -1581,7 +1586,7 @@
     <string name="master_clear_title" msgid="1560712943955904673">"Erase all data (factory reset)"</string>
     <string name="master_clear_short_title" msgid="919098101581335101">"Erase all data (factory reset)"</string>
     <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"This will erase all data from your tablet’s "<b>"internal storage"</b>", including:\n\n"<li>"Your Google Account"</li>\n<li>"System and app data and settings"</li>\n<li>"Downloaded apps"</li></string>
-    <string name="master_clear_desc" product="default" msgid="8765543541962866697">"This will erase all data from your phone’s "<b>"internal storage"</b>", including:\n\n"<li>"Your Google Account"</li>\n<li>"System and app data and settings"</li>\n<li>"Downloaded apps"</li></string>
+    <string name="master_clear_desc" product="default" msgid="8765543541962866697">"This will erase all data from your phone\'s "<b>"internal storage"</b>", including:\n\n"<li>"Your Google Account"</li>\n<li>"System and app data and settings"</li>\n<li>"Downloaded apps"</li></string>
     <string name="master_clear_accounts" product="default" msgid="3432884235445405376">\n\n"You are currently signed in to the following accounts:\n"</string>
     <string name="master_clear_other_users_present" product="default" msgid="5993259656117566767">\n\n"There are other users present on this device.\n"</string>
     <string name="master_clear_desc_also_erases_external" msgid="3947303501615091903"><li>"Music"</li>\n<li>"Photos"</li>\n<li>"Other user data"</li></string>
@@ -1593,10 +1598,10 @@
     <string name="erase_external_storage" product="default" msgid="194249742376770215">"Erase SD card"</string>
     <string name="erase_external_storage_description" product="nosdcard" msgid="8020275102431496261">"Erase all the data on the internal USB storage, such as music or photos"</string>
     <string name="erase_external_storage_description" product="default" msgid="5029355708082861798">"Erase all the data on the SD card, such as music or photos"</string>
-    <string name="master_clear_button_text" product="tablet" msgid="8000547818499182920">"Delete all data"</string>
-    <string name="master_clear_button_text" product="default" msgid="8000547818499182920">"Delete all data"</string>
-    <string name="master_clear_final_desc" msgid="5189365498015339294">"All of your personal information and downloaded apps will be deleted. You can’t undo this action."</string>
-    <string name="master_clear_final_desc_esim" msgid="3058919823436953662">"All of your personal information, including downloaded apps &amp; SIMs, will be deleted. You can’t undo this action."</string>
+    <string name="master_clear_button_text" product="tablet" msgid="8000547818499182920">"Erase all data"</string>
+    <string name="master_clear_button_text" product="default" msgid="8000547818499182920">"Erase all data"</string>
+    <string name="master_clear_final_desc" msgid="5189365498015339294">"All of your personal information and downloaded apps will be deleted. You can\'t undo this action."</string>
+    <string name="master_clear_final_desc_esim" msgid="3058919823436953662">"All of your personal information, including downloaded apps and SIMs, will be deleted. You can\'t undo this action."</string>
     <string name="master_clear_final_button_text" msgid="866772743886027768">"Erase everything"</string>
     <string name="master_clear_failed" msgid="7588397453984229892">"No reset was performed because the System Clear service isn\'t available."</string>
     <string name="master_clear_confirm_title" msgid="698328669893512402">"Erase all data?"</string>
@@ -2036,7 +2041,7 @@
     <string name="vision_settings_description" msgid="3476589459009287332">"You can customise this device to fit your needs. These accessibility features can be changed later in Settings."</string>
     <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"Change font size"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"Screen readers"</string>
-    <string name="audio_and_captions_category_title" msgid="6140472938769619212">"Audio &amp; on-screen text"</string>
+    <string name="audio_and_captions_category_title" msgid="6140472938769619212">"Audio and on-screen text"</string>
     <string name="display_category_title" msgid="545168481672250195">"Display"</string>
     <string name="interaction_control_category_title" msgid="8775039211811947683">"Interaction controls"</string>
     <string name="user_installed_services_category_title" msgid="4288689493753221319">"Downloaded services"</string>
@@ -2059,7 +2064,7 @@
     <string name="accessibility_global_gesture_preference_title" msgid="3842279082831426816">"Volume key shortcut"</string>
     <string name="accessibility_shortcut_service_title" msgid="3516052294376744060">"Shortcut service"</string>
     <string name="accessibility_shortcut_service_on_lock_screen_title" msgid="1279441617927949980">"Allow from lock screen"</string>
-    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"When the shortcut is on, you can press both volume keys for 3 seconds to start an accessibility feature."</string>
+    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"When the shortcut is on, you can press both volume keys for three seconds to start an accessibility feature."</string>
     <string name="accessibility_toggle_high_text_contrast_preference_title" msgid="5652244684961877255">"High-contrast text"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"Auto update screen magnification"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"Update screen magnification on app transitions"</string>
@@ -2080,7 +2085,7 @@
     <string name="accessibility_control_timeout_preference_title" msgid="2771808346038759474">"Time to take action"</string>
     <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"Choose how long to show messages that you need to read, but are visible only temporarily.\n\nNot all apps support this setting."</string>
     <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"Choose how long to show messages that ask you to take action, but are visible only temporarily.\n\nNot all apps support this setting."</string>
-    <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"Touch &amp; hold delay"</string>
+    <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"Touch and hold delay"</string>
     <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"Colour inversion"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"May affect performance"</string>
     <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"Dwell timing"</string>
@@ -2134,7 +2139,7 @@
     <string name="accessibility_vibration_summary_off" msgid="2894044066550518676">"Ring &amp; notification set to off"</string>
     <string name="accessibility_vibration_summary_low" msgid="2884160616131878204">"Ring &amp; notification set to low"</string>
     <string name="accessibility_vibration_summary_medium" msgid="3141272492346527298">"Ring &amp; notification set to medium"</string>
-    <string name="accessibility_vibration_summary_high" msgid="4188677504368202861">"Ring &amp; notification set to high"</string>
+    <string name="accessibility_vibration_summary_high" msgid="4188677504368202861">"Ring and notification set to high"</string>
     <string name="accessibility_vibration_intensity_off" msgid="4427927348723998194">"Off"</string>
     <string name="accessibility_vibration_intensity_low" msgid="8250688473513963211">"Low"</string>
     <string name="accessibility_vibration_intensity_medium" msgid="2249931147940383011">"Medium"</string>
@@ -2197,7 +2202,7 @@
       <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> print jobs</item>
       <item quantity="one">1 print job</item>
     </plurals>
-    <string name="print_settings_title" msgid="2886445296786932763">"Printing services"</string>
+    <string name="print_settings_title" msgid="2886445296786932763">"Print services"</string>
     <string name="print_no_services_installed" msgid="3387777739528003794">"No services installed"</string>
     <string name="print_no_printers_found" msgid="5090925427392294881">"No printers found"</string>
     <string name="print_menu_item_settings" msgid="2654804159012579508">"Settings"</string>
@@ -2234,7 +2239,7 @@
     <string name="background_activity_summary_whitelisted" msgid="4713321059375873828">"Background usage can’t be restricted"</string>
     <string name="background_activity_warning_dialog_title" msgid="2170790412855899678">"Limit background activity?"</string>
     <string name="background_activity_warning_dialog_text" msgid="8242749826732375096">"If you limit background activity for an app, it may misbehave"</string>
-    <string name="background_activity_disabled_dialog_text" msgid="4234598000779459640">"Since this app is not set to optimise battery, you can’t restrict it.\n\nTo restrict the app, first turn on battery optimisation."</string>
+    <string name="background_activity_disabled_dialog_text" msgid="4234598000779459640">"Since this app is not set to optimize battery, you can\'t restrict it.\n\nTo restrict the app, first turn on battery optimization."</string>
     <string name="device_screen_usage" msgid="4470485475363132750">"Screen usage since full charge"</string>
     <string name="power_usage_list_summary" msgid="4314438658308211057">"Battery usage since full charge"</string>
     <string name="screen_usage_summary" msgid="263396144684078341">"Amount of time screen has been on since full charge"</string>
@@ -2312,12 +2317,12 @@
     <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"This app will be able to use battery in the background. Your battery may run out sooner than expected."</string>
     <string name="battery_tip_unrestrict_app_dialog_ok" msgid="9154938931448151479">"Remove"</string>
     <string name="battery_tip_unrestrict_app_dialog_cancel" msgid="7331148618292397166">"Cancel"</string>
-    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"Your apps are using a normal amount of battery. If apps use too much battery, your phone will suggest actions that you can take.\n\nYou can always turn on Battery Saver if you’re running low on battery."</string>
+    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"Your apps are using a normal amount of battery. If apps use too much battery, your phone will suggest actions you can take.\n\nYou can always turn on Battery Saver if you\'re running low on battery."</string>
     <string name="battery_tip_dialog_summary_message" product="tablet" msgid="1721081030632329647">"Your apps are using a normal amount of battery. If apps use too much battery, your tablet will suggest actions that you can take.\n\nYou can always turn on Battery Saver if you’re running low on battery."</string>
     <string name="battery_tip_dialog_summary_message" product="device" msgid="146872407040848465">"Your apps are using a normal amount of battery. If apps use too much battery, your device will suggest actions that you can take.\n\nYou can always turn on Battery Saver if you’re running low on battery."</string>
     <string name="smart_battery_manager_title" msgid="5744035036663849515">"Battery Manager"</string>
     <string name="smart_battery_title" msgid="4919670408532804351">"Manage apps automatically"</string>
-    <string name="smart_battery_summary" msgid="640027046471198174">"Limit battery for apps that you don’t use often"</string>
+    <string name="smart_battery_summary" msgid="640027046471198174">"Limit battery for apps you don\'t use often"</string>
     <string name="smart_battery_footer" product="default" msgid="3971715848890205632">"When Battery Manager detects that apps are draining battery, you’ll have the option to restrict these apps. Restricted apps may not work properly and notifications may be delayed."</string>
     <string name="smart_battery_footer" product="tablet" msgid="3971715848890205632">"When Battery Manager detects that apps are draining battery, you’ll have the option to restrict these apps. Restricted apps may not work properly and notifications may be delayed."</string>
     <string name="smart_battery_footer" product="device" msgid="3971715848890205632">"When Battery Manager detects that apps are draining battery, you’ll have the option to restrict these apps. Restricted apps may not work properly and notifications may be delayed."</string>
@@ -2645,7 +2650,7 @@
     <string name="select_all" msgid="452240217913675728">"Select all"</string>
     <string name="data_usage_summary_title" msgid="7288431048564861043">"Data usage"</string>
     <string name="data_usage_app_summary_title" msgid="8277327968906074983">"Mobile data &amp; Wi‑Fi"</string>
-    <string name="data_usage_accounting" msgid="4681642832010140640">"Operator data accounting may differ from your device."</string>
+    <string name="data_usage_accounting" msgid="4681642832010140640">"Carrier data accounting may differ from your device."</string>
     <string name="data_usage_app" msgid="4995297799363021198">"App usage"</string>
     <string name="data_usage_app_info_label" msgid="5358288895158910477">"APP INFO"</string>
     <string name="data_usage_cellular_data" msgid="3509117353455285808">"Mobile data"</string>
@@ -2710,7 +2715,7 @@
     <string name="data_usage_limit_editor_title" msgid="1687908662154108293">"Set data usage limit"</string>
     <string name="data_usage_limit_dialog_title" msgid="8804760847110131518">"Limiting data usage"</string>
     <string name="data_usage_limit_dialog_mobile" product="tablet" msgid="2000713577999830647">"Your tablet will turn off mobile data once it reaches the limit you set.\n\nSince data usage is measured by your tablet, and your operator may account for usage differently, consider setting a conservative limit."</string>
-    <string name="data_usage_limit_dialog_mobile" product="default" msgid="943546278705619205">"Your phone will turn off mobile data once it reaches the limit that you set.\n\nSince data usage is measured by your phone, and your operator may account for usage differently, consider setting a conservative limit."</string>
+    <string name="data_usage_limit_dialog_mobile" product="default" msgid="943546278705619205">"Your phone will turn off mobile data once it reaches the limit you set.\n\nSince data usage is measured by your phone, and your carrier may account for usage differently, consider setting a conservative limit."</string>
     <string name="data_usage_restrict_background_title" msgid="3568746530413220844">"Restrict background data?"</string>
     <string name="data_usage_restrict_background" msgid="995811034744808575">"If you restrict background mobile data, some apps and services won’t work unless you’re connected to Wi‑Fi."</string>
     <string name="data_usage_restrict_background_multiuser" product="tablet" msgid="6032810839234864814">"If you restrict background mobile data, some apps and services won’t work unless you’re connected to Wi‑Fi.\n\nThis setting affects all users on this tablet."</string>
@@ -2731,7 +2736,7 @@
     <string name="data_usage_metered_auto" msgid="7924116401382629319">"Automatic"</string>
     <string name="data_usage_metered_yes" msgid="7333744880035386073">"Metered"</string>
     <string name="data_usage_metered_no" msgid="1961524615778610008">"Not metered"</string>
-    <string name="data_usage_disclaimer" msgid="4683321532922590425">"Operator data accounting may differ from your device."</string>
+    <string name="data_usage_disclaimer" msgid="4683321532922590425">"Carrier data accounting may differ from your device."</string>
     <string name="cryptkeeper_emergency_call" msgid="4625420047524693116">"Emergency call"</string>
     <string name="cryptkeeper_return_to_call" msgid="4433942821196822815">"Return to call"</string>
     <string name="vpn_name" msgid="3538818658670774080">"Name"</string>
@@ -2930,7 +2935,7 @@
     <string name="restriction_menu_reset" msgid="3642252461410370554">"Remove restrictions"</string>
     <string name="restriction_menu_change_pin" msgid="592512748243421101">"Change PIN"</string>
     <string name="app_notifications_switch_label" msgid="670683308275498821">"Show notifications"</string>
-    <string name="help_label" msgid="1296484776243905646">"Help &amp; feedback"</string>
+    <string name="help_label" msgid="1296484776243905646">"Help and feedback"</string>
     <string name="support_summary" msgid="3278943815956130740">"Help articles, phone &amp; chat, getting started"</string>
     <string name="user_account_title" msgid="2108666882630552859">"Account for content"</string>
     <string name="user_picture_title" msgid="6664602422948159123">"Photo ID"</string>
@@ -3689,7 +3694,7 @@
     <string name="memory_avg_desc" msgid="1200185697910086968">"Average <xliff:g id="MEMORY">%1$s</xliff:g>"</string>
     <string name="memory_use_running_format" msgid="3741170402563292232">"<xliff:g id="MEMORY">%1$s</xliff:g> / <xliff:g id="RUNNING">%2$s</xliff:g>"</string>
     <string name="process_format" msgid="8575347150598564509">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="COUNT">%2$d</xliff:g>)"</string>
-    <string name="high_power_apps" msgid="2518319744362028920">"Battery optimisation"</string>
+    <string name="high_power_apps" msgid="2518319744362028920">"Battery optimization"</string>
     <string name="additional_battery_info" msgid="6877663897819271203">"Usage alerts"</string>
     <string name="show_all_apps" msgid="5442552004569634846">"Show full device usage"</string>
     <string name="hide_extra_apps" msgid="6798261081113299441">"Show app usage"</string>
@@ -3703,9 +3708,9 @@
     </plurals>
     <string name="high_power_filter_on" msgid="5294209328473386403">"Not optimised"</string>
     <string name="high_power_on" msgid="3573501822510580334">"Not optimised"</string>
-    <string name="high_power_off" msgid="5906679734326490426">"Optimising battery use"</string>
-    <string name="high_power_system" msgid="739584574711292753">"Battery optimisation not available"</string>
-    <string name="high_power_desc" msgid="333756885680362741">"Don’t apply battery optimisation. May drain your battery more quickly."</string>
+    <string name="high_power_off" msgid="5906679734326490426">"Optimizing battery use"</string>
+    <string name="high_power_system" msgid="739584574711292753">"Battery optimization not available"</string>
+    <string name="high_power_desc" msgid="333756885680362741">"Don\'t apply battery optimization. May drain your battery more quickly."</string>
     <string name="high_power_prompt_title" msgid="2805745781720454052">"Let app always run in background?"</string>
     <string name="high_power_prompt_body" msgid="8067395096053552289">"Allowing <xliff:g id="APP_NAME">%1$s</xliff:g> to always run in the background may reduce battery life. \n\nYou can change this later from Settings &gt; Apps &amp; notifications."</string>
     <string name="battery_summary" msgid="4345690800899981339">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> use since last full charge"</string>
@@ -3905,7 +3910,7 @@
     <string name="night_display_suggestion_summary" msgid="1754361016383576916">"Automatically tint screen every night"</string>
     <string name="condition_night_display_title" msgid="9171491784857160135">"Night Light is on"</string>
     <string name="condition_night_display_summary" msgid="7885776986937527558">"Screen tinted amber"</string>
-    <string name="condition_grayscale_title" msgid="1226351649203551299">"Grey scale"</string>
+    <string name="condition_grayscale_title" msgid="1226351649203551299">"Greyscale"</string>
     <string name="condition_grayscale_summary" msgid="749172886527349546">"Display only in grey colour"</string>
     <string name="homepage_condition_footer_content_description" msgid="3563606465924396342">"Collapse"</string>
     <string name="suggestions_title_v2" msgid="1959786223276927042">"Suggested for You"</string>
@@ -3937,7 +3942,7 @@
     <string name="cell_data_template" msgid="5473177306229738078">"<xliff:g id="AMOUNT">^1</xliff:g> mobile data"</string>
     <string name="wifi_data_template" msgid="3146090439147042068">"<xliff:g id="AMOUNT">^1</xliff:g> Wi-Fi data"</string>
     <string name="ethernet_data_template" msgid="6414118030827090119">"<xliff:g id="AMOUNT">^1</xliff:g> ethernet data"</string>
-    <string name="billing_cycle" msgid="5740717948341713190">"Data warning &amp; limit"</string>
+    <string name="billing_cycle" msgid="5740717948341713190">"Data warning and limit"</string>
     <string name="app_usage_cycle" msgid="213483325132959663">"App data usage cycle"</string>
     <string name="cell_data_warning" msgid="8902740337286652689">"<xliff:g id="ID_1">^1</xliff:g> data warning"</string>
     <string name="cell_data_limit" msgid="3175933829235314233">"<xliff:g id="ID_1">^1</xliff:g> data limit"</string>
@@ -3948,7 +3953,7 @@
       <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> restrictions</item>
       <item quantity="one">1 restriction</item>
     </plurals>
-    <string name="operator_warning" msgid="4676042739221117031">"Operator data accounting may differ from device accounting"</string>
+    <string name="operator_warning" msgid="4676042739221117031">"Carrier data accounting may differ from device accounting"</string>
     <string name="data_used_template" msgid="761605393453849477">"<xliff:g id="ID_1">%1$s</xliff:g> used"</string>
     <string name="set_data_warning" msgid="8115980184415563941">"Set data warning"</string>
     <string name="data_warning" msgid="2699207195535036240">"Data warning"</string>
@@ -4001,7 +4006,7 @@
     <string name="battery_saver_off_summary" msgid="8736555723004299721">"Off"</string>
     <string name="battery_saver_button_turn_on" msgid="3748696527267573793">"Turn on now"</string>
     <string name="battery_saver_button_turn_off" msgid="2912950982503267828">"Turn off now"</string>
-    <string name="not_battery_optimizing" msgid="2616044774307734160">"Not using battery optimisation"</string>
+    <string name="not_battery_optimizing" msgid="2616044774307734160">"Not using battery optimization"</string>
     <string name="lockscreen_remote_input" msgid="3363310613165354434">"If device is locked, prevent typing replies or other text in notifications"</string>
     <string name="default_spell_checker" msgid="8636661093243189533">"Default spell checker"</string>
     <string name="choose_spell_checker" msgid="7619860861923582868">"Choose spell checker"</string>
@@ -4264,7 +4269,7 @@
     <string name="storage_manager_indicator_on" msgid="5295306384982062320">"On"</string>
     <string name="install_type_instant" msgid="6248487669862821874">"Instant app"</string>
     <string name="automatic_storage_manager_deactivation_warning" msgid="7867793739491286374">"Turn off the storage manager?"</string>
-    <string name="storage_movies_tv" msgid="7282484273991655296">"Movie &amp; TV apps"</string>
+    <string name="storage_movies_tv" msgid="7282484273991655296">"Movie and TV apps"</string>
     <string name="carrier_provisioning" msgid="3309125279191534469">"Operator Provisioning Info"</string>
     <string name="trigger_carrier_provisioning" msgid="6284005970057901477">"Trigger Operator Provisioning"</string>
     <string name="zen_suggestion_title" msgid="2134699720214231950">"Update Do Not Disturb"</string>
diff --git a/tests/CarDeveloperOptions/res/values-en-rGB/arrays.xml b/tests/CarDeveloperOptions/res/values-en-rGB/arrays.xml
index f718198..b001bdd 100644
--- a/tests/CarDeveloperOptions/res/values-en-rGB/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-en-rGB/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"run in background"</item>
     <item msgid="6423861043647911030">"accessibility volume"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Location"</item>
+    <item msgid="6656077694190491067">"Location"</item>
+    <item msgid="8790228218278477369">"Location"</item>
+    <item msgid="7836406246005211990">"Vibrate"</item>
+    <item msgid="3951439024549922598">"Read contacts"</item>
+    <item msgid="8802152411647068">"Modify contacts"</item>
+    <item msgid="229544934599698735">"Read call log"</item>
+    <item msgid="7396102294405899613">"Modify call log"</item>
+    <item msgid="3597797992398484655">"Read calendar"</item>
+    <item msgid="2705975774250907343">"Modify calendar"</item>
+    <item msgid="4668747371441932697">"Location"</item>
+    <item msgid="1487578921720243646">"Post notification"</item>
+    <item msgid="4636080349724146638">"Location"</item>
+    <item msgid="673510900286463926">"Call phone"</item>
+    <item msgid="542083422784609790">"Read SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Write SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Receive SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Receive SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Receive SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Receive SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Send SMS/MMS"</item>
+    <item msgid="4726682243833913568">"Read SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Write SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Modify settings"</item>
+    <item msgid="8705854389991425629">"Draw on top"</item>
+    <item msgid="5861356020344153651">"Access notifications"</item>
+    <item msgid="78432174621628659">"Camera"</item>
+    <item msgid="3986116419882154794">"Record audio"</item>
+    <item msgid="4516840825756409490">"Play audio"</item>
+    <item msgid="6811712502798183957">"Read clipboard"</item>
+    <item msgid="2780369012602289114">"Modify clipboard"</item>
+    <item msgid="2331359440170850868">"Media buttons"</item>
+    <item msgid="6133599737122751231">"Audio focus"</item>
+    <item msgid="6844485713404805301">"Master volume"</item>
+    <item msgid="1600379420669104929">"Voice volume"</item>
+    <item msgid="6296768210470214866">"Ring volume"</item>
+    <item msgid="510690696071629241">"Media volume"</item>
+    <item msgid="406861638631430109">"Alarm volume"</item>
+    <item msgid="4715864795872233884">"Notification volume"</item>
+    <item msgid="2311478519251301183">"Bluetooth volume"</item>
+    <item msgid="5133991377896747027">"Keep awake"</item>
+    <item msgid="2464189519136248621">"Location"</item>
+    <item msgid="2062677934050803037">"Location"</item>
+    <item msgid="1735171933192715957">"Get usage stats"</item>
+    <item msgid="1014093788778383554">"Mute/unmute microphone"</item>
+    <item msgid="4199297950608622850">"Show toast"</item>
+    <item msgid="2527962435313398821">"Project media"</item>
+    <item msgid="5117506254221861929">"Activate VPN"</item>
+    <item msgid="8291198322681891160">"Write wallpaper"</item>
+    <item msgid="7106921284621230961">"Assist structure"</item>
+    <item msgid="4496533640894624799">"Assist screenshot"</item>
+    <item msgid="2598847264853993611">"Read phone state"</item>
+    <item msgid="9215610846802973353">"Add voicemail"</item>
+    <item msgid="9186411956086478261">"Use sip"</item>
+    <item msgid="6884763100104539558">"Process outgoing call"</item>
+    <item msgid="125513972170580692">"Fingerprint"</item>
+    <item msgid="2556071024281275619">"Body sensors"</item>
+    <item msgid="617168514928339387">"Read mobile broadcasts"</item>
+    <item msgid="7134693570516523585">"Mock location"</item>
+    <item msgid="7224489175375229399">"Read storage"</item>
+    <item msgid="8472735063903258202">"Write storage"</item>
+    <item msgid="4069276819909595110">"Turn on screen"</item>
+    <item msgid="1228338896751121025">"Get accounts"</item>
+    <item msgid="3181581793459233672">"Run in background"</item>
+    <item msgid="2340936043025374076">"Accessibility volume"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Short"</item>
     <item msgid="4816511817309094890">"Medium"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Never allow"</item>
     <item msgid="8184570120217958741">"Always allow"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Moderate"</item>
+    <item msgid="1555861583162930714">"Low"</item>
+    <item msgid="1719683776264798117">"Critical"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normal"</item>
+    <item msgid="6107138933849816768">"Moderate"</item>
+    <item msgid="182695359839047859">"Low"</item>
+    <item msgid="8577246509202964244">"Critical"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Persistent"</item>
     <item msgid="167418068739176448">"Top activity"</item>
diff --git a/tests/CarDeveloperOptions/res/values-en-rGB/config.xml b/tests/CarDeveloperOptions/res/values-en-rGB/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-en-rGB/config.xml
+++ b/tests/CarDeveloperOptions/res/values-en-rGB/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-en-rGB/strings.xml b/tests/CarDeveloperOptions/res/values-en-rGB/strings.xml
index 0cf4a48..ff3da11 100644
--- a/tests/CarDeveloperOptions/res/values-en-rGB/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-en-rGB/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Make the text on screen smaller or larger."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Make smaller"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Make larger"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Sample text"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"The Wonderful Wizard of Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Chapter 11: The Wonderful Emerald City of Oz"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Must be fewer than <xliff:g id="NUMBER_1">%d</xliff:g> digits</item>
       <item quantity="one">Must be fewer than <xliff:g id="NUMBER_0">%d</xliff:g> digit</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Must only contain digits 0-9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Device admin doesn\'t allow using a recent PIN"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Common PINs are blocked by your IT admin. Try a different PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"This can\'t include an invalid character"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Must contain at least <xliff:g id="COUNT">%d</xliff:g> non-letter characters</item>
       <item quantity="one">Must contain at least 1 non-letter character</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Must contain at least <xliff:g id="COUNT">%d</xliff:g> non-numeric characters</item>
+      <item quantity="one">Must contain at least 1 non-numeric character</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Device admin doesn\'t allow using a recent password"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Common passwords are blocked by your IT admin. Try a different password."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Ascending, descending or repeated sequence of digits isn\'t allowed"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mobile"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"If Wi‑Fi is unavailable, use mobile network"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"If mobile network is unavailable, use Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Call over Wi‑Fi. If Wi‑Fi is lost, call will end."</string>
@@ -1578,8 +1583,8 @@
     <string name="reset_network_complete_toast" msgid="128225929536005495">"Network settings have been reset"</string>
     <string name="reset_esim_error_title" msgid="4728931209471875632">"Can’t delete SIMs"</string>
     <string name="reset_esim_error_msg" msgid="4716366079119742235">"Downloaded SIMs can’t be deleted due to an error.\n\nRestart your device and try again."</string>
-    <string name="master_clear_title" msgid="1560712943955904673">"Erase all data (factory reset)"</string>
-    <string name="master_clear_short_title" msgid="919098101581335101">"Erase all data (factory reset)"</string>
+    <string name="master_clear_title" msgid="1560712943955904673">"Delete all data (factory reset)"</string>
+    <string name="master_clear_short_title" msgid="919098101581335101">"Delete all data (factory reset)"</string>
     <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"This will erase all data from your tablet’s "<b>"internal storage"</b>", including:\n\n"<li>"Your Google Account"</li>\n<li>"System and app data and settings"</li>\n<li>"Downloaded apps"</li></string>
     <string name="master_clear_desc" product="default" msgid="8765543541962866697">"This will erase all data from your phone’s "<b>"internal storage"</b>", including:\n\n"<li>"Your Google Account"</li>\n<li>"System and app data and settings"</li>\n<li>"Downloaded apps"</li></string>
     <string name="master_clear_accounts" product="default" msgid="3432884235445405376">\n\n"You are currently signed in to the following accounts:\n"</string>
@@ -2059,7 +2064,7 @@
     <string name="accessibility_global_gesture_preference_title" msgid="3842279082831426816">"Volume key shortcut"</string>
     <string name="accessibility_shortcut_service_title" msgid="3516052294376744060">"Shortcut service"</string>
     <string name="accessibility_shortcut_service_on_lock_screen_title" msgid="1279441617927949980">"Allow from lock screen"</string>
-    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"When the shortcut is on, you can press both volume keys for 3 seconds to start an accessibility feature."</string>
+    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"When the shortcut is on, you can press both volume keys for three seconds to start an accessibility feature."</string>
     <string name="accessibility_toggle_high_text_contrast_preference_title" msgid="5652244684961877255">"High-contrast text"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"Auto update screen magnification"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"Update screen magnification on app transitions"</string>
@@ -2197,7 +2202,7 @@
       <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> print jobs</item>
       <item quantity="one">1 print job</item>
     </plurals>
-    <string name="print_settings_title" msgid="2886445296786932763">"Printing services"</string>
+    <string name="print_settings_title" msgid="2886445296786932763">"Print services"</string>
     <string name="print_no_services_installed" msgid="3387777739528003794">"No services installed"</string>
     <string name="print_no_printers_found" msgid="5090925427392294881">"No printers found"</string>
     <string name="print_menu_item_settings" msgid="2654804159012579508">"Settings"</string>
diff --git a/tests/CarDeveloperOptions/res/values-en-rIN/arrays.xml b/tests/CarDeveloperOptions/res/values-en-rIN/arrays.xml
index f718198..b001bdd 100644
--- a/tests/CarDeveloperOptions/res/values-en-rIN/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-en-rIN/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"run in background"</item>
     <item msgid="6423861043647911030">"accessibility volume"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Location"</item>
+    <item msgid="6656077694190491067">"Location"</item>
+    <item msgid="8790228218278477369">"Location"</item>
+    <item msgid="7836406246005211990">"Vibrate"</item>
+    <item msgid="3951439024549922598">"Read contacts"</item>
+    <item msgid="8802152411647068">"Modify contacts"</item>
+    <item msgid="229544934599698735">"Read call log"</item>
+    <item msgid="7396102294405899613">"Modify call log"</item>
+    <item msgid="3597797992398484655">"Read calendar"</item>
+    <item msgid="2705975774250907343">"Modify calendar"</item>
+    <item msgid="4668747371441932697">"Location"</item>
+    <item msgid="1487578921720243646">"Post notification"</item>
+    <item msgid="4636080349724146638">"Location"</item>
+    <item msgid="673510900286463926">"Call phone"</item>
+    <item msgid="542083422784609790">"Read SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Write SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Receive SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Receive SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Receive SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Receive SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Send SMS/MMS"</item>
+    <item msgid="4726682243833913568">"Read SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Write SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Modify settings"</item>
+    <item msgid="8705854389991425629">"Draw on top"</item>
+    <item msgid="5861356020344153651">"Access notifications"</item>
+    <item msgid="78432174621628659">"Camera"</item>
+    <item msgid="3986116419882154794">"Record audio"</item>
+    <item msgid="4516840825756409490">"Play audio"</item>
+    <item msgid="6811712502798183957">"Read clipboard"</item>
+    <item msgid="2780369012602289114">"Modify clipboard"</item>
+    <item msgid="2331359440170850868">"Media buttons"</item>
+    <item msgid="6133599737122751231">"Audio focus"</item>
+    <item msgid="6844485713404805301">"Master volume"</item>
+    <item msgid="1600379420669104929">"Voice volume"</item>
+    <item msgid="6296768210470214866">"Ring volume"</item>
+    <item msgid="510690696071629241">"Media volume"</item>
+    <item msgid="406861638631430109">"Alarm volume"</item>
+    <item msgid="4715864795872233884">"Notification volume"</item>
+    <item msgid="2311478519251301183">"Bluetooth volume"</item>
+    <item msgid="5133991377896747027">"Keep awake"</item>
+    <item msgid="2464189519136248621">"Location"</item>
+    <item msgid="2062677934050803037">"Location"</item>
+    <item msgid="1735171933192715957">"Get usage stats"</item>
+    <item msgid="1014093788778383554">"Mute/unmute microphone"</item>
+    <item msgid="4199297950608622850">"Show toast"</item>
+    <item msgid="2527962435313398821">"Project media"</item>
+    <item msgid="5117506254221861929">"Activate VPN"</item>
+    <item msgid="8291198322681891160">"Write wallpaper"</item>
+    <item msgid="7106921284621230961">"Assist structure"</item>
+    <item msgid="4496533640894624799">"Assist screenshot"</item>
+    <item msgid="2598847264853993611">"Read phone state"</item>
+    <item msgid="9215610846802973353">"Add voicemail"</item>
+    <item msgid="9186411956086478261">"Use sip"</item>
+    <item msgid="6884763100104539558">"Process outgoing call"</item>
+    <item msgid="125513972170580692">"Fingerprint"</item>
+    <item msgid="2556071024281275619">"Body sensors"</item>
+    <item msgid="617168514928339387">"Read mobile broadcasts"</item>
+    <item msgid="7134693570516523585">"Mock location"</item>
+    <item msgid="7224489175375229399">"Read storage"</item>
+    <item msgid="8472735063903258202">"Write storage"</item>
+    <item msgid="4069276819909595110">"Turn on screen"</item>
+    <item msgid="1228338896751121025">"Get accounts"</item>
+    <item msgid="3181581793459233672">"Run in background"</item>
+    <item msgid="2340936043025374076">"Accessibility volume"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Short"</item>
     <item msgid="4816511817309094890">"Medium"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Never allow"</item>
     <item msgid="8184570120217958741">"Always allow"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Moderate"</item>
+    <item msgid="1555861583162930714">"Low"</item>
+    <item msgid="1719683776264798117">"Critical"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normal"</item>
+    <item msgid="6107138933849816768">"Moderate"</item>
+    <item msgid="182695359839047859">"Low"</item>
+    <item msgid="8577246509202964244">"Critical"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Persistent"</item>
     <item msgid="167418068739176448">"Top activity"</item>
diff --git a/tests/CarDeveloperOptions/res/values-en-rIN/config.xml b/tests/CarDeveloperOptions/res/values-en-rIN/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-en-rIN/config.xml
+++ b/tests/CarDeveloperOptions/res/values-en-rIN/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-en-rIN/strings.xml b/tests/CarDeveloperOptions/res/values-en-rIN/strings.xml
index 0cf4a48..b65891c 100644
--- a/tests/CarDeveloperOptions/res/values-en-rIN/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-en-rIN/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Make the text on screen smaller or larger."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Make smaller"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Make larger"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Sample text"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"The Wonderful Wizard of Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Chapter 11: The Wonderful Emerald City of Oz"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Must be fewer than <xliff:g id="NUMBER_1">%d</xliff:g> digits</item>
       <item quantity="one">Must be fewer than <xliff:g id="NUMBER_0">%d</xliff:g> digit</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Must only contain digits 0-9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Device admin doesn\'t allow using a recent PIN"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Common PINs are blocked by your IT admin. Try a different PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"This can\'t include an invalid character"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Must contain at least <xliff:g id="COUNT">%d</xliff:g> non-letter characters</item>
       <item quantity="one">Must contain at least 1 non-letter character</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Must contain at least <xliff:g id="COUNT">%d</xliff:g> non-numeric characters</item>
+      <item quantity="one">Must contain at least 1 non-numeric character</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Device admin doesn\'t allow using a recent password"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Common passwords are blocked by your IT admin. Try a different password."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Ascending, descending or repeated sequence of digits isn\'t allowed"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mobile"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"If Wi‑Fi is unavailable, use mobile network"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"If mobile network is unavailable, use Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Call over Wi‑Fi. If Wi‑Fi is lost, call will end."</string>
@@ -1565,7 +1570,7 @@
     <string name="restore_default_apn_completed" msgid="5671734152740058937">"Reset default APN settings completed"</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"Reset options"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"Network, apps or device can be reset"</string>
-    <string name="reset_network_title" msgid="8944059136930806211">"Reset Wi-Fi, mobile &amp; Bluetooth"</string>
+    <string name="reset_network_title" msgid="8944059136930806211">"Reset Wi-Fi, mobile and Bluetooth"</string>
     <string name="reset_network_desc" msgid="4982633363916261109">"This will reset all network settings, including:\n\n"<li>"Wi‑Fi"</li>\n<li>"Mobile data"</li>\n<li>"Bluetooth"</li></string>
     <string name="reset_esim_title" msgid="7630781767040831893">"Erase downloaded SIMs"</string>
     <string name="reset_esim_desc" msgid="433226911566802">"To download replacement SIMs, contact your operator. This won’t cancel any mobile service plans."</string>
@@ -1573,13 +1578,13 @@
     <string name="reset_network_final_desc" msgid="2463817067048751373">"Reset all network settings? You can’t undo this action."</string>
     <string name="reset_network_final_desc_esim" msgid="4676436976372555750">"Reset all network settings and delete downloaded SIMs? You can’t undo this action."</string>
     <string name="reset_network_final_button_text" msgid="345255333127794393">"Reset settings"</string>
-    <string name="reset_network_confirm_title" msgid="2432145031070536008">"Reset?"</string>
+    <string name="reset_network_confirm_title" msgid="2432145031070536008">"Want to reset?"</string>
     <string name="network_reset_not_available" msgid="6146655531868016281">"Network reset is not available for this user"</string>
     <string name="reset_network_complete_toast" msgid="128225929536005495">"Network settings have been reset"</string>
     <string name="reset_esim_error_title" msgid="4728931209471875632">"Can’t delete SIMs"</string>
     <string name="reset_esim_error_msg" msgid="4716366079119742235">"Downloaded SIMs can’t be deleted due to an error.\n\nRestart your device and try again."</string>
-    <string name="master_clear_title" msgid="1560712943955904673">"Erase all data (factory reset)"</string>
-    <string name="master_clear_short_title" msgid="919098101581335101">"Erase all data (factory reset)"</string>
+    <string name="master_clear_title" msgid="1560712943955904673">"Delete all data (factory reset)"</string>
+    <string name="master_clear_short_title" msgid="919098101581335101">"Delete all data (factory reset)"</string>
     <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"This will erase all data from your tablet’s "<b>"internal storage"</b>", including:\n\n"<li>"Your Google Account"</li>\n<li>"System and app data and settings"</li>\n<li>"Downloaded apps"</li></string>
     <string name="master_clear_desc" product="default" msgid="8765543541962866697">"This will erase all data from your phone’s "<b>"internal storage"</b>", including:\n\n"<li>"Your Google Account"</li>\n<li>"System and app data and settings"</li>\n<li>"Downloaded apps"</li></string>
     <string name="master_clear_accounts" product="default" msgid="3432884235445405376">\n\n"You are currently signed in to the following accounts:\n"</string>
@@ -2036,7 +2041,7 @@
     <string name="vision_settings_description" msgid="3476589459009287332">"You can customise this device to fit your needs. These accessibility features can be changed later in Settings."</string>
     <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"Change font size"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"Screen readers"</string>
-    <string name="audio_and_captions_category_title" msgid="6140472938769619212">"Audio &amp; on-screen text"</string>
+    <string name="audio_and_captions_category_title" msgid="6140472938769619212">"Audio and on-screen text"</string>
     <string name="display_category_title" msgid="545168481672250195">"Display"</string>
     <string name="interaction_control_category_title" msgid="8775039211811947683">"Interaction controls"</string>
     <string name="user_installed_services_category_title" msgid="4288689493753221319">"Downloaded services"</string>
@@ -2059,7 +2064,7 @@
     <string name="accessibility_global_gesture_preference_title" msgid="3842279082831426816">"Volume key shortcut"</string>
     <string name="accessibility_shortcut_service_title" msgid="3516052294376744060">"Shortcut service"</string>
     <string name="accessibility_shortcut_service_on_lock_screen_title" msgid="1279441617927949980">"Allow from lock screen"</string>
-    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"When the shortcut is on, you can press both volume keys for 3 seconds to start an accessibility feature."</string>
+    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"When the shortcut is on, you can press both volume keys for three seconds to start an accessibility feature."</string>
     <string name="accessibility_toggle_high_text_contrast_preference_title" msgid="5652244684961877255">"High-contrast text"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"Auto update screen magnification"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"Update screen magnification on app transitions"</string>
@@ -2080,7 +2085,7 @@
     <string name="accessibility_control_timeout_preference_title" msgid="2771808346038759474">"Time to take action"</string>
     <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"Choose how long to show messages that you need to read, but are visible only temporarily.\n\nNot all apps support this setting."</string>
     <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"Choose how long to show messages that ask you to take action, but are visible only temporarily.\n\nNot all apps support this setting."</string>
-    <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"Touch &amp; hold delay"</string>
+    <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"Touch and hold delay"</string>
     <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"Colour inversion"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"May affect performance"</string>
     <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"Dwell timing"</string>
@@ -2134,7 +2139,7 @@
     <string name="accessibility_vibration_summary_off" msgid="2894044066550518676">"Ring &amp; notification set to off"</string>
     <string name="accessibility_vibration_summary_low" msgid="2884160616131878204">"Ring &amp; notification set to low"</string>
     <string name="accessibility_vibration_summary_medium" msgid="3141272492346527298">"Ring &amp; notification set to medium"</string>
-    <string name="accessibility_vibration_summary_high" msgid="4188677504368202861">"Ring &amp; notification set to high"</string>
+    <string name="accessibility_vibration_summary_high" msgid="4188677504368202861">"Ring and notification set to high"</string>
     <string name="accessibility_vibration_intensity_off" msgid="4427927348723998194">"Off"</string>
     <string name="accessibility_vibration_intensity_low" msgid="8250688473513963211">"Low"</string>
     <string name="accessibility_vibration_intensity_medium" msgid="2249931147940383011">"Medium"</string>
@@ -2197,7 +2202,7 @@
       <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> print jobs</item>
       <item quantity="one">1 print job</item>
     </plurals>
-    <string name="print_settings_title" msgid="2886445296786932763">"Printing services"</string>
+    <string name="print_settings_title" msgid="2886445296786932763">"Print services"</string>
     <string name="print_no_services_installed" msgid="3387777739528003794">"No services installed"</string>
     <string name="print_no_printers_found" msgid="5090925427392294881">"No printers found"</string>
     <string name="print_menu_item_settings" msgid="2654804159012579508">"Settings"</string>
@@ -2930,7 +2935,7 @@
     <string name="restriction_menu_reset" msgid="3642252461410370554">"Remove restrictions"</string>
     <string name="restriction_menu_change_pin" msgid="592512748243421101">"Change PIN"</string>
     <string name="app_notifications_switch_label" msgid="670683308275498821">"Show notifications"</string>
-    <string name="help_label" msgid="1296484776243905646">"Help &amp; feedback"</string>
+    <string name="help_label" msgid="1296484776243905646">"Help and feedback"</string>
     <string name="support_summary" msgid="3278943815956130740">"Help articles, phone &amp; chat, getting started"</string>
     <string name="user_account_title" msgid="2108666882630552859">"Account for content"</string>
     <string name="user_picture_title" msgid="6664602422948159123">"Photo ID"</string>
@@ -3937,7 +3942,7 @@
     <string name="cell_data_template" msgid="5473177306229738078">"<xliff:g id="AMOUNT">^1</xliff:g> mobile data"</string>
     <string name="wifi_data_template" msgid="3146090439147042068">"<xliff:g id="AMOUNT">^1</xliff:g> Wi-Fi data"</string>
     <string name="ethernet_data_template" msgid="6414118030827090119">"<xliff:g id="AMOUNT">^1</xliff:g> ethernet data"</string>
-    <string name="billing_cycle" msgid="5740717948341713190">"Data warning &amp; limit"</string>
+    <string name="billing_cycle" msgid="5740717948341713190">"Data warning and limit"</string>
     <string name="app_usage_cycle" msgid="213483325132959663">"App data usage cycle"</string>
     <string name="cell_data_warning" msgid="8902740337286652689">"<xliff:g id="ID_1">^1</xliff:g> data warning"</string>
     <string name="cell_data_limit" msgid="3175933829235314233">"<xliff:g id="ID_1">^1</xliff:g> data limit"</string>
@@ -4264,7 +4269,7 @@
     <string name="storage_manager_indicator_on" msgid="5295306384982062320">"On"</string>
     <string name="install_type_instant" msgid="6248487669862821874">"Instant app"</string>
     <string name="automatic_storage_manager_deactivation_warning" msgid="7867793739491286374">"Turn off the storage manager?"</string>
-    <string name="storage_movies_tv" msgid="7282484273991655296">"Movie &amp; TV apps"</string>
+    <string name="storage_movies_tv" msgid="7282484273991655296">"Movie and TV apps"</string>
     <string name="carrier_provisioning" msgid="3309125279191534469">"Operator Provisioning Info"</string>
     <string name="trigger_carrier_provisioning" msgid="6284005970057901477">"Trigger Operator Provisioning"</string>
     <string name="zen_suggestion_title" msgid="2134699720214231950">"Update Do Not Disturb"</string>
diff --git a/tests/CarDeveloperOptions/res/values-en-rXC/config.xml b/tests/CarDeveloperOptions/res/values-en-rXC/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-en-rXC/config.xml
+++ b/tests/CarDeveloperOptions/res/values-en-rXC/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-en-rXC/strings.xml b/tests/CarDeveloperOptions/res/values-en-rXC/strings.xml
index 562c28d..a8c34fd 100644
--- a/tests/CarDeveloperOptions/res/values-en-rXC/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-en-rXC/strings.xml
@@ -667,7 +667,6 @@
       <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‏‏‏‏‏‎‏‎‏‏‎‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎‎Must be fewer than ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%d</xliff:g>‎‏‎‎‏‏‏‎ digits‎‏‎‎‏‎</item>
       <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‏‏‏‏‏‎‏‎‏‏‎‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎‎Must be fewer than ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%d</xliff:g>‎‏‎‎‏‏‏‎ digit‎‏‎‎‏‎</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‏‎‏‏‏‎‎‏‏‎‏‏‏‎‎‏‏‏‏‏‎‎‏‏‎‏‏‎‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‏‏‎‏‎‎‏‎‎‎Must contain only digits 0-9‎‏‎‎‏‎"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‏‏‎‏‏‎‏‏‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‎‎‏‏‎‎‏‎‏‎‏‏‏‏‎Device admin doesn\'t allow using a recent PIN‎‏‎‎‏‎"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‏‎‎‎‏‎‎‏‏‎‎‏‏‏‏‎‎‏‏‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‎‏‎Common PINs are blocked by your IT admin. Try a different PIN.‎‏‎‎‏‎"</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‎‎‏‏‎‏‎‎‏‎‏‏‎‏‏‏‏‏‎‎‎‎‏‏‎‏‎‏‎‏‎‎‎‏‏‏‏‎‎‏‎‏‎‏‏‏‏‏‎‎‏‏‏‎This can\'t include an invalid character‎‏‎‎‏‎"</string>
@@ -698,6 +697,10 @@
       <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‎‎‏‎‎‎‏‎‏‏‎‏‏‎Must contain at least ‎‏‎‎‏‏‎<xliff:g id="COUNT">%d</xliff:g>‎‏‎‎‏‏‏‎ non-letter characters‎‏‎‎‏‎</item>
       <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‎‎‏‎‎‎‏‎‏‏‎‏‏‎Must contain at least 1 non-letter character‎‏‎‎‏‎</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‎‎‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‎‏‎‏‏‏‎‎‏‏‏‎‏‏‎‏‏‎‎Must contain at least ‎‏‎‎‏‏‎<xliff:g id="COUNT">%d</xliff:g>‎‏‎‎‏‏‏‎ non-numerical characters‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‎‎‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‎‏‎‏‏‏‎‎‏‏‏‎‏‏‎‏‏‎‎Must contain at least 1 non-numerical character‎‏‎‎‏‎</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‎‎‎‎‏‎‏‎‎‎‏‎‏‏‎‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎Device admin doesn\'t allow using a recent password‎‏‎‎‏‎"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‎‎‎‎‏‏‏‎‎‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‎‏‎‏‏‏‏‏‎‏‎‏‎‏‏‎‎‏‏‎Common passwords are blocked by your IT admin. Try a different password.‎‏‎‎‏‎"</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‏‎‎‎‎‎‎‏‎‎‎‎‏‎‎‏‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‎‎‎‎‎‏‎‎‎Ascending, descending, or repeated sequence of digits isn\'t allowed‎‏‎‎‏‎"</string>
diff --git a/tests/CarDeveloperOptions/res/values-es-rUS/arrays.xml b/tests/CarDeveloperOptions/res/values-es-rUS/arrays.xml
index 195115c..490207d 100644
--- a/tests/CarDeveloperOptions/res/values-es-rUS/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-es-rUS/arrays.xml
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"No permitir nunca"</item>
     <item msgid="8184570120217958741">"Permitir siempre"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Moderado"</item>
+    <item msgid="1555861583162930714">"Baja"</item>
+    <item msgid="1719683776264798117">"Crítico"</item>
+    <item msgid="1567326459340152525">"Desconocido"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normal"</item>
+    <item msgid="6107138933849816768">"Moderado"</item>
+    <item msgid="182695359839047859">"Baja"</item>
+    <item msgid="8577246509202964244">"Crítico"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Persistente"</item>
     <item msgid="167418068739176448">"Actividad principal"</item>
@@ -467,7 +477,7 @@
     <item msgid="1008268820118852416">"Tratar como red sin tarifa plana"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
-    <item msgid="6545683814310036454">"Usar MAC aleatoria (predeterminada)"</item>
+    <item msgid="6545683814310036454">"Usar MAC aleatoria (pred.)"</item>
     <item msgid="214234417308375326">"Usar MAC del dispositivo"</item>
   </string-array>
   <string-array name="wifi_hidden_entries">
diff --git a/tests/CarDeveloperOptions/res/values-es-rUS/config.xml b/tests/CarDeveloperOptions/res/values-es-rUS/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-es-rUS/config.xml
+++ b/tests/CarDeveloperOptions/res/values-es-rUS/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-es-rUS/strings.xml b/tests/CarDeveloperOptions/res/values-es-rUS/strings.xml
index 215453a..54d857e 100644
--- a/tests/CarDeveloperOptions/res/values-es-rUS/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-es-rUS/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Aumenta o reduce el tamaño del texto en pantalla."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Reducir el tamaño"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Aumentar el tamaño"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Texto de muestra"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"El maravilloso mago de Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Capítulo 11: La maravillosa Ciudad Esmeralda de Oz"</string>
@@ -407,11 +406,11 @@
     <string name="security_settings_face_enroll_introduction_message_setup" msgid="4533297059466270074">"Usa tu rostro para desbloquear el teléfono, autorizar compras o acceder a las apps"</string>
     <string name="security_settings_face_enroll_introduction_footer_message" msgid="7764021721107723266"></string>
     <string name="security_settings_face_enroll_repeat_title" msgid="2507710348140837875">"Centra el rostro en el círculo"</string>
-    <string name="security_settings_face_enroll_enrolling_skip" msgid="4346077260378772613">"Hacerlo más tarde"</string>
+    <string name="security_settings_face_enroll_enrolling_skip" msgid="4346077260378772613">"Más tarde"</string>
     <string name="face_add_max" msgid="8870899421165189413">"Puedes agregar hasta <xliff:g id="COUNT">%d</xliff:g> rostros"</string>
     <string name="face_intro_error_max" msgid="4024147799079828937">"Agregaste la cantidad máxima permitida de rostros"</string>
     <string name="face_intro_error_unknown" msgid="3241592604198351134">"No se pueden agregar más rostros"</string>
-    <string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"No se completó el registro"</string>
+    <string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"No se completó la inscripción"</string>
     <string name="security_settings_face_enroll_dialog_ok" msgid="1078348922734845090">"Aceptar"</string>
     <string name="security_settings_face_enroll_error_timeout_dialog_message" msgid="4917894418448325405">"Se alcanzó el límite de tiempo para el registro de rostros. Vuelve a intentarlo."</string>
     <string name="security_settings_face_enroll_error_generic_dialog_message" msgid="5160473187142616862">"No funcionó el registro de rostros."</string>
@@ -472,7 +471,7 @@
     <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Sigue levantando el dedo para agregar diferentes partes de la huella digital."</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"Se agregó la huella digital"</string>
     <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"Cuando veas este ícono, usa tu huella digital para identificarte o aprobar compras."</string>
-    <string name="security_settings_fingerprint_enroll_enrolling_skip" msgid="1473280156532146933">"Hacerlo más tarde"</string>
+    <string name="security_settings_fingerprint_enroll_enrolling_skip" msgid="1473280156532146933">"Más tarde"</string>
     <string name="setup_fingerprint_enroll_enrolling_skip_title" msgid="2816424026528101690">"¿Omitir configuración de huella digital?"</string>
     <string name="setup_fingerprint_enroll_enrolling_skip_message" msgid="8139299964344809780">"Decidiste usar la huella digital como una de las formas para desbloquear el teléfono. Si omites este paso, tendrás que configurarla más tarde. La configuración tarda un minuto aproximadamente."</string>
     <string name="fingerprint_lock_screen_setup_skip_dialog_text" product="tablet" msgid="1384438077720821127">"Protege la tablet con una opción de bloqueo de pantalla para que nadie pueda usarla si la pierdes o te la roban. Además, tienes que establecer una opción de bloqueo de pantalla para configurar la huella digital. Presiona Cancelar y, luego, establece un PIN o elige otra opción de bloqueo de pantalla."</string>
@@ -488,8 +487,8 @@
     <string name="security_settings_fingerprint_enroll_done" msgid="4111289529758845926">"Listo"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"Ese no es el sensor"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"Toca el sensor en la parte posterior del teléfono con el dedo índice."</string>
-    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"No se completó el registro"</string>
-    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Se alcanzó el límite de tiempo para el registro de huellas digitales. Vuelve a intentarlo."</string>
+    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"No se completó la inscripción"</string>
+    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Se alcanzó el límite de tiempo para la inscripción de huellas digitales. Vuelve a intentarlo."</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"El registro de huellas digitales no funcionó. Vuelve a intentarlo o usa otro dedo."</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"Agregar otra huella digital"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"Siguiente"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Debe tener menos de <xliff:g id="NUMBER_1">%d</xliff:g> dígitos</item>
       <item quantity="one">Debe tener menos de <xliff:g id="NUMBER_0">%d</xliff:g> dígito</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Solo puede contener dígitos entre el 0 y el 9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"El administrador del dispositivo no permite el uso de un PIN reciente"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Tu administrador de TI bloquea los PIN comunes. Prueba uno diferente."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"No puede incluir un carácter no válido"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Debe tener al menos <xliff:g id="COUNT">%d</xliff:g> caracteres que no sean letras</item>
       <item quantity="one">Debe tener al menos 1 carácter que no sea una letra</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Debe tener al menos <xliff:g id="COUNT">%d</xliff:g> caracteres no numéricos</item>
+      <item quantity="one">Debe tener al menos 1 carácter no numérico</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"El administrador del dispositivo no permite el uso de contraseñas recientes"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Tu administrador de TI bloquea las contraseñas comunes. Prueba una diferente."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"No se permiten secuencias de dígitos ascendentes, descendentes ni repetidas"</string>
@@ -824,7 +826,7 @@
     <string name="nfc_disclaimer_title" msgid="4860231267351602970">"Activa NFC"</string>
     <string name="nfc_disclaimer_content" msgid="3066113577854565782">"NFC intercambia datos entre este dispositivo y otras orientaciones o dispositivos cercanos, como terminales de pago, lectores de acceso o etiquetas."</string>
     <string name="nfc_secure_settings_title" msgid="5153751163174916581">"Proteger NFC"</string>
-    <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"Permitir uso de pagos NFC y Transit solo cuando la pantalla está desbloqueada"</string>
+    <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"Permitir el uso de NFC en pagos y transporte público solo cuando la pantalla está desbloqueada"</string>
     <string name="android_beam_settings_title" msgid="3083436415873738389">"Android Beam"</string>
     <string name="android_beam_on_summary" msgid="8068287225180474199">"Listo para transmitir contenido de aplicaciones por NFC"</string>
     <string name="android_beam_off_summary" msgid="7365818039159364600">"Desactivada"</string>
@@ -886,7 +888,7 @@
     <string name="wifi_menu_remember" msgid="717257200269700641">"Recordar red"</string>
     <string name="wifi_menu_forget" msgid="7561140554450163075">"Olvidar red"</string>
     <string name="wifi_menu_modify" msgid="4080178040721021101">"Modificar red"</string>
-    <string name="wifi_empty_list_wifi_off" msgid="272877164691346240">"Para ver las redes disponibles, activa Wi-Fi."</string>
+    <string name="wifi_empty_list_wifi_off" msgid="272877164691346240">"Para ver las redes disponibles, activa el Wi-Fi."</string>
     <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"Buscando redes Wi-Fi…"</string>
     <string name="wifi_empty_list_user_restricted" msgid="2341613007817352431">"No tienes permiso para cambiar la red Wi‑Fi."</string>
     <string name="wifi_more" msgid="3538241640407382185">"Más"</string>
@@ -903,11 +905,11 @@
     <string name="wifi_ssid_hint" msgid="5010024648106585165">"Ingresa el SSID"</string>
     <string name="wifi_security" msgid="9136702039496152831">"Seguridad"</string>
     <string name="wifi_hidden_network" msgid="6647772204699776833">"Red oculta"</string>
-    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Si tu router no emite un ID de red, pero quieres conectarte a la red en el futuro, configúrala para que esté oculta.\n\nEs posible que esta acción suponga un riesgo de seguridad, ya que tu teléfono emitirá su señal de forma regular para buscar la red.\n\nSi configuras la red para que esté oculta, no se modificarán los ajustes del router."</string>
+    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Si el router no emite un ID de red, pero quieres conectarte a la red en el futuro, configúrala para que esté oculta.\n\nEs posible que esta acción implique riesgos de seguridad porque el teléfono emitirá la señal regularmente para buscar la red.\n\nSi configuras la red para que esté oculta, no se modificarán los ajustes del router."</string>
     <string name="wifi_signal" msgid="696548364467704808">"Potencia de la señal"</string>
     <string name="wifi_status" msgid="3439931558930689940">"Estado"</string>
-    <string name="tx_wifi_speed" msgid="2571810085003261073">"Transmitir velocidad de vínculo"</string>
-    <string name="rx_wifi_speed" msgid="7392873246110937187">"Recibir velocidad de vínculo"</string>
+    <string name="tx_wifi_speed" msgid="2571810085003261073">"Velocidad enlace de transmisión"</string>
+    <string name="rx_wifi_speed" msgid="7392873246110937187">"Velocidad enlace de recepción"</string>
     <string name="wifi_frequency" msgid="6132852924995724246">"Frecuencia"</string>
     <string name="wifi_ip_address" msgid="5572539114989914831">"Dirección IP"</string>
     <string name="passpoint_label" msgid="7429247462404128615">"Se guardó mediante"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Móvil"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Si no hay ninguna red Wi-Fi disponible, usa una red móvil"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Si la red móvil no está disponible, usa Wi-Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Llamar mediante Wi-Fi. La llamada finalizará si se pierde la conexión."</string>
@@ -1581,7 +1586,7 @@
     <string name="master_clear_title" msgid="1560712943955904673">"Borrar todos los datos (restablecer la configuración de fábrica)"</string>
     <string name="master_clear_short_title" msgid="919098101581335101">"Borrar todos los datos"</string>
     <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"Esta acción borrará todos los datos del "<b>"almacenamiento interno"</b>" de tu tablet, como\n\n"<li>"Tu Cuenta de Google"</li>\n<li>"Los datos y la configuración del sistema y de las apps"</li>\n<li>"Las apps descargadas"</li></string>
-    <string name="master_clear_desc" product="default" msgid="8765543541962866697">"Esta acción borrará todos los datos del "<b>"almacenamiento interno"</b>" de tu teléfono, como\n\n"<li>"Tu Cuenta de Google"</li>\n<li>"Los datos y la configuración del sistema y de las apps"</li>\n<li>"Las apps descargadas"</li></string>
+    <string name="master_clear_desc" product="default" msgid="8765543541962866697">"Se borrarán todos los datos del "<b>"almacenamiento interno"</b>" del teléfono, por ejemplo:\n\n"<li>"Tu Cuenta de Google"</li>\n<li>"Los datos y la configuración del sistema y de las apps"</li>\n<li>"Las apps descargadas"</li></string>
     <string name="master_clear_accounts" product="default" msgid="3432884235445405376">\n\n"Accediste a las siguientes cuentas:\n"</string>
     <string name="master_clear_other_users_present" product="default" msgid="5993259656117566767">\n\n"Hay otros usuarios presentes en este dispositivo.\n"</string>
     <string name="master_clear_desc_also_erases_external" msgid="3947303501615091903"><li>"Música"</li>\n<li>"Fotos"</li>\n<li>"Otros datos de usuario"</li></string>
@@ -2050,7 +2055,7 @@
     <string name="accessibility_screen_magnification_gestures_title" msgid="9199287875401817974">"Ampliar presionando tres veces"</string>
     <string name="accessibility_screen_magnification_navbar_title" msgid="400655612610761242">"Ampliar con el botón"</string>
     <string name="accessibility_screen_magnification_state_navbar_gesture" msgid="1863831350878995600">"Ampliar con el botón y al presionar tres veces"</string>
-    <string name="accessibility_preference_magnification_summary" msgid="753307741814376312">"Ampliar la pantalla"</string>
+    <string name="accessibility_preference_magnification_summary" msgid="753307741814376312">"Amplía la pantalla"</string>
     <string name="accessibility_screen_magnification_short_summary" msgid="5698545174944494486">"Presiona tres veces para ampliar"</string>
     <string name="accessibility_screen_magnification_navbar_short_summary" msgid="5418767043532322397">"Presiona un botón para ampliar"</string>
     <string name="accessibility_screen_magnification_summary" msgid="3363006902079431772"><b>"Para ampliar"</b>", presiona la pantalla 3 veces rápidamente \n"<ul><li>"Arrastra 2 o más dedos para desplazarte."</li>\n<li>"Pellizca con 2 o más dedos para ajustar el zoom."</li></ul>\n\n<b>"Para hacer zoom de manera temporal"</b>", presiona la pantalla 3 veces rápidamente y mantén presionado la última vez.\n"<ul><li>"Arrastra el dedo para moverte por la pantalla."</li>\n<li>"Levanta el dedo para alejar la imagen."</li></ul>\n\n"No se puede ampliar el teclado ni la barra de navegación."</string>
@@ -2312,9 +2317,9 @@
     <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"Esta app podrá usar la batería en segundo plano. La batería podría agotarse antes de lo esperado."</string>
     <string name="battery_tip_unrestrict_app_dialog_ok" msgid="9154938931448151479">"Quitar"</string>
     <string name="battery_tip_unrestrict_app_dialog_cancel" msgid="7331148618292397166">"Cancelar"</string>
-    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"La cantidad de batería que usan tus apps es normal. Si consumen demasiada batería, el teléfono te recomendará acciones.\n\nSi tienes poca batería, también puedes activar el Ahorro de batería."</string>
-    <string name="battery_tip_dialog_summary_message" product="tablet" msgid="1721081030632329647">"La cantidad de batería que usan tus apps es normal. Si consumen demasiada batería, la tablet te recomendará acciones.\n\nSi tienes poca batería, también puedes activar el Ahorro de batería."</string>
-    <string name="battery_tip_dialog_summary_message" product="device" msgid="146872407040848465">"La cantidad de batería que usan tus apps es normal. Si consumen demasiada batería, el dispositivo te recomendará acciones.\n\nSi tienes poca batería, también puedes activar el Ahorro de batería."</string>
+    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"Tus apps consumen una cantidad normal de batería. Si consumen demasiada batería, el teléfono te recomendará acciones.\n\nSi tienes poca batería, también puedes activar el Ahorro de batería."</string>
+    <string name="battery_tip_dialog_summary_message" product="tablet" msgid="1721081030632329647">"Tus apps consumen una cantidad normal de batería. Si consumen demasiada batería, la tablet te recomendará acciones.\n\nSi tienes poca batería, también puedes activar el Ahorro de batería."</string>
+    <string name="battery_tip_dialog_summary_message" product="device" msgid="146872407040848465">"Tus apps consumen una cantidad normal de batería. Si consumen demasiada batería, el dispositivo te recomendará acciones.\n\nSi tienes poca batería, también puedes activar el Ahorro de batería."</string>
     <string name="smart_battery_manager_title" msgid="5744035036663849515">"Administrador de batería"</string>
     <string name="smart_battery_title" msgid="4919670408532804351">"Administra apps automáticamente"</string>
     <string name="smart_battery_summary" msgid="640027046471198174">"Limitar el consumo de batería de las apps que no uses con frecuencia"</string>
@@ -2526,7 +2531,7 @@
     <string name="credentials_reset_summary" msgid="7622528359699428555">"Quitar todos los certificados"</string>
     <string name="trusted_credentials" msgid="6989242522455395200">"Credenciales de confianza"</string>
     <string name="trusted_credentials_summary" msgid="7411781319056251582">"Mostrar certificados de CA de confianza"</string>
-    <string name="user_credentials" msgid="8365731467650306757">"Credenciales del usuario"</string>
+    <string name="user_credentials" msgid="8365731467650306757">"Credenciales de usuario"</string>
     <string name="user_credentials_summary" msgid="7350223899317423252">"Ver y modificar las credenciales guardadas"</string>
     <string name="advanced_security_title" msgid="286883005673855845">"Configuración avanzada"</string>
     <string name="credential_storage_type" msgid="2585337320206095255">"Tipo de almacenamiento"</string>
@@ -2751,7 +2756,7 @@
     <string name="vpn_username" msgid="5357878823189445042">"Nombre de usuario"</string>
     <string name="vpn_password" msgid="5325943601523662246">"Contraseña"</string>
     <string name="vpn_save_login" msgid="6215503139606646915">"Guardar información de la cuenta"</string>
-    <string name="vpn_not_used" msgid="2889520789132261454">"(no se utiliza)"</string>
+    <string name="vpn_not_used" msgid="2889520789132261454">"(No se utiliza)"</string>
     <string name="vpn_no_ca_cert" msgid="486605757354800838">"(no verificar el servidor)"</string>
     <string name="vpn_no_server_cert" msgid="679622228649855629">"(recibido desde el servidor)"</string>
     <string name="vpn_always_on_invalid_reason_type" msgid="165810330614905489">"Este tipo de VPN no puede permanecer conectada todo el tiempo"</string>
@@ -3435,7 +3440,7 @@
     <string name="zen_mode_add_event_rule" msgid="1398181272397489506">"Agregar programa de eventos"</string>
     <string name="zen_mode_add_time_rule" msgid="5999467757140524729">"Agregar programa de tiempo"</string>
     <string name="zen_mode_delete_rule" msgid="2292933835997203801">"Borrar programa"</string>
-    <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"Elegir tipo de programa"</string>
+    <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"Elegir el tipo de programa"</string>
     <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"¿Quieres borrar la regla \"<xliff:g id="RULE">%1$s</xliff:g>\"?"</string>
     <string name="zen_mode_delete_rule_button" msgid="611058106279881991">"Borrar"</string>
     <string name="zen_mode_rule_type_unknown" msgid="2819480113355191421">"Desconocido"</string>
@@ -3704,7 +3709,7 @@
     <string name="high_power_off" msgid="5906679734326490426">"Optimizando el uso de la batería"</string>
     <string name="high_power_system" msgid="739584574711292753">"Optimización de la batería no disponible"</string>
     <string name="high_power_desc" msgid="333756885680362741">"No se aplica la optimización de la batería, por lo que se puede agotar más rápido."</string>
-    <string name="high_power_prompt_title" msgid="2805745781720454052">"¿Deseas permitir que la app se ejecute siempre en segundo plano?"</string>
+    <string name="high_power_prompt_title" msgid="2805745781720454052">"¿Permitir que la app se ejecute siempre en segundo plano?"</string>
     <string name="high_power_prompt_body" msgid="8067395096053552289">"Si permites que <xliff:g id="APP_NAME">%1$s</xliff:g> se ejecute siempre en segundo plano, es posible que se reduzca la duración de la batería. \n\nPuedes cambiar esta opción más tarde en Configuración &gt; Apps y notificaciones."</string>
     <string name="battery_summary" msgid="4345690800899981339">"Se usó el <xliff:g id="PERCENTAGE">%1$s</xliff:g> desde la última carga completa"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"Administración de energía"</string>
diff --git a/tests/CarDeveloperOptions/res/values-es/arrays.xml b/tests/CarDeveloperOptions/res/values-es/arrays.xml
index 5b52eee..81d4f62 100644
--- a/tests/CarDeveloperOptions/res/values-es/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-es/arrays.xml
@@ -71,7 +71,7 @@
     <item msgid="5597394826455877834">"Conectando…"</item>
     <item msgid="5848277343965362748">"Autenticando..."</item>
     <item msgid="3391238031431440676">"Obteniendo dirección IP…"</item>
-    <item msgid="5257597310494000224">"Conectada"</item>
+    <item msgid="5257597310494000224">"Conectado"</item>
     <item msgid="8472497592913050396">"Suspendido"</item>
     <item msgid="1228072488815999109">"Desconectando…"</item>
     <item msgid="7253087004422991731">"Desconectado"</item>
@@ -101,7 +101,7 @@
     <item msgid="4526848028011846710">"PIN del dispositivo"</item>
   </string-array>
   <string-array name="wifi_p2p_status">
-    <item msgid="8741947238021758201">"Conectada"</item>
+    <item msgid="8741947238021758201">"Conectado"</item>
     <item msgid="983792611851499732">"Invitado"</item>
     <item msgid="5438273405428201793">"Con error"</item>
     <item msgid="4646663015449312554">"Disponible"</item>
@@ -170,7 +170,7 @@
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"Ninguna"</item>
     <item msgid="1464741437353223198">"Manual"</item>
-    <item msgid="5793600062487886090">"Proxy autoconfigurado"</item>
+    <item msgid="5793600062487886090">"Proxy configurado automáticamente"</item>
   </string-array>
   <string-array name="apn_auth_entries">
     <item msgid="7099647881902405997">"Ninguna"</item>
@@ -414,7 +414,7 @@
     <item msgid="5408915841694583740">"Desconectado"</item>
     <item msgid="8754480102834556765">"Iniciando..."</item>
     <item msgid="3351334355574270250">"Conectando…"</item>
-    <item msgid="8303882153995748352">"Conectada"</item>
+    <item msgid="8303882153995748352">"Conectado"</item>
     <item msgid="9135049670787351881">"Tiempo de espera"</item>
     <item msgid="2124868417182583926">"Con error"</item>
   </string-array>
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"No permitir nunca"</item>
     <item msgid="8184570120217958741">"Permitir siempre"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Moderada"</item>
+    <item msgid="1555861583162930714">"Baja"</item>
+    <item msgid="1719683776264798117">"Crítico"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normal"</item>
+    <item msgid="6107138933849816768">"Moderado"</item>
+    <item msgid="182695359839047859">"Baja"</item>
+    <item msgid="8577246509202964244">"Crítico"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Persistente"</item>
     <item msgid="167418068739176448">"Actividad principal"</item>
@@ -446,14 +456,14 @@
     <item msgid="3151827842194201728">"Verde azulado"</item>
     <item msgid="3228505970082457852">"Azul"</item>
     <item msgid="6590260735734795647">"Índigo"</item>
-    <item msgid="3521763377357218577">"Violeta"</item>
+    <item msgid="3521763377357218577">"Morado"</item>
     <item msgid="5932337981182999919">"Rosa"</item>
     <item msgid="5642914536624000094">"Rojo"</item>
   </string-array>
   <string-array name="automatic_storage_management_days">
-    <item msgid="2860293514533486236">"Más de 30 días de antigüedad"</item>
-    <item msgid="8699273238891265610">"Más de 60 días de antigüedad"</item>
-    <item msgid="8346279419423837266">"Más de 90 días de antigüedad"</item>
+    <item msgid="2860293514533486236">"De más de 30 días de antigüedad"</item>
+    <item msgid="8699273238891265610">"De más de 60 días de antigüedad"</item>
+    <item msgid="8346279419423837266">"De más de 90 días de antigüedad"</item>
   </string-array>
     <!-- no translation found for swipe_direction_titles:0 (6583090603341402282) -->
     <!-- no translation found for swipe_direction_titles:1 (4965730704403236310) -->
diff --git a/tests/CarDeveloperOptions/res/values-es/config.xml b/tests/CarDeveloperOptions/res/values-es/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-es/config.xml
+++ b/tests/CarDeveloperOptions/res/values-es/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-es/strings.xml b/tests/CarDeveloperOptions/res/values-es/strings.xml
index fe6c748..c67b9da 100644
--- a/tests/CarDeveloperOptions/res/values-es/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-es/strings.xml
@@ -23,8 +23,8 @@
     <string name="deny" msgid="3998166389989144025">"Denegar"</string>
     <string name="device_info_default" msgid="1548919563979154348">"Desconocido"</string>
     <plurals name="show_dev_countdown" formatted="false" msgid="3953785659137161981">
-      <item quantity="other">Solo te quedan <xliff:g id="STEP_COUNT_1">%1$d</xliff:g> pasos de ser un desarrollador.</item>
-      <item quantity="one">Solo te queda <xliff:g id="STEP_COUNT_0">%1$d</xliff:g> paso de ser un desarrollador.</item>
+      <item quantity="other">Estás a <xliff:g id="STEP_COUNT_1">%1$d</xliff:g> pasos de ser desarrollador.</item>
+      <item quantity="one">Estás a <xliff:g id="STEP_COUNT_0">%1$d</xliff:g> paso de ser desarrollador.</item>
     </plurals>
     <string name="show_dev_on" msgid="9075712234786224065">"¡Ahora están activadas las opciones para desarrolladores!"</string>
     <string name="show_dev_already" msgid="7665948832405148689">"Las opciones para desarrolladores ya están activadas."</string>
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Aumenta o disminuye el tamaño del texto de la pantalla."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Reducir el tamaño"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Aumentar el tamaño"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Texto de ejemplo"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"El maravilloso mago de Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Capítulo 11: La maravillosa Ciudad Esmeralda de Oz"</string>
@@ -128,7 +127,7 @@
     <string name="bluetooth_notif_title" msgid="5090288898529286011">"Solicitud de vinculación"</string>
     <string name="bluetooth_notif_message" msgid="6612367890895077938">"Toca para vincular con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="bluetooth_show_received_files" msgid="5060846395852236652">"Archivos recibidos"</string>
-    <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"Archivos recibidos (Bluetooth)"</string>
+    <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"Archivos recibidos por Bluetooth"</string>
     <string name="device_picker" msgid="8345264486071697705">"Seleccionar dispositivo Bluetooth"</string>
     <string name="bluetooth_ask_enablement" msgid="8716802066127746062">"<xliff:g id="APP_NAME">%1$s</xliff:g> quiere activar el Bluetooth"</string>
     <string name="bluetooth_ask_disablement" msgid="7125319551097350783">"<xliff:g id="APP_NAME">%1$s</xliff:g> quiere desactivar el Bluetooth"</string>
@@ -197,7 +196,7 @@
     <string name="proxy_settings_title" msgid="6014901859338211713">"Proxy"</string>
     <string name="proxy_clear_text" msgid="498317431076294101">"Borrar"</string>
     <string name="proxy_port_label" msgid="8285157632538848509">"Puerto del proxy"</string>
-    <string name="proxy_exclusionlist_label" msgid="8179084955547941904">"Saltarproxy para"</string>
+    <string name="proxy_exclusionlist_label" msgid="8179084955547941904">"Saltar proxy para"</string>
     <string name="proxy_defaultView_text" msgid="5785775257042403261">"Restaurar valores predeterminados"</string>
     <string name="proxy_action_text" msgid="814511434843981413">"Listo"</string>
     <string name="proxy_hostname_label" msgid="6798891831427287847">"Nombre de host del proxy"</string>
@@ -209,7 +208,7 @@
     <string name="proxy_error_empty_host_set_port" msgid="8471455809508588255">"El campo de puerto debe estar vacío si el campo de host también lo está."</string>
     <string name="proxy_error_invalid_port" msgid="4046559920586100637">"El puerto que has introducido no es válido."</string>
     <string name="proxy_warning_limited_support" msgid="9026539134219095768">"El navegador utiliza el proxy HTTP, pero otras aplicaciones no pueden usarlo."</string>
-    <string name="proxy_url_title" msgid="882042361706435904">"URL PAC "</string>
+    <string name="proxy_url_title" msgid="882042361706435904">"URL de archivo PAC "</string>
     <string name="radio_info_dl_kbps" msgid="2903778264453410272">"Ancho de banda de bajada (Kbps):"</string>
     <string name="radio_info_ul_kbps" msgid="3802245899811732716">"Ancho de banda de subida (Kbps):"</string>
     <string name="radio_info_signal_location_label" msgid="6788144906873498013">"Información sobre la ubicación del teléfono (obsoleto):"</string>
@@ -317,7 +316,7 @@
     <string name="roaming_warning" msgid="5488050911277592868">"El coste de este servicio puede ser significativo."</string>
     <string name="roaming_warning_multiuser" product="tablet" msgid="7090388691615686893">"Al permitir la itinerancia de datos, los costes de itinerancia que deberás asumir pueden ser significativos.\n\nEsta configuración afecta a todos los usuarios de este tablet."</string>
     <string name="roaming_warning_multiuser" product="default" msgid="6999819541078827556">"Al permitir la itinerancia de datos, los costes de itinerancia que deberás asumir pueden ser significativos.\n\nEsta configuración afecta a todos los usuarios de este teléfono."</string>
-    <string name="roaming_reenable_title" msgid="6985082191178297921">"¿Permitir la itinerancia de datos?"</string>
+    <string name="roaming_reenable_title" msgid="6985082191178297921">"¿Permitir itinerancia de datos?"</string>
     <string name="networks" msgid="3073876464102136771">"Selección de operador"</string>
     <string name="sum_carrier_select" msgid="8964744180598499121">"Selecciona un operador de red"</string>
     <string name="date_and_time_settings_title" msgid="7827088656940910631">"Fecha y hora"</string>
@@ -356,7 +355,7 @@
     <string name="security_enable_widgets_title" msgid="1701510007926738088">"Habilitar widgets"</string>
     <string name="security_enable_widgets_disabled_summary" msgid="4408176087132339331">"Inhabilitado por el administrador"</string>
     <string name="lockdown_settings_title" msgid="4534779922580115990">"Mostrar opción de bloqueo de seguridad"</string>
-    <string name="lockdown_settings_summary" msgid="7270756909878256174">"Mostrar la opción del botón de encendido que desactiva Smart Lock, el desbloqueo con huella digital y las notificaciones en la pantalla de bloqueo"</string>
+    <string name="lockdown_settings_summary" msgid="7270756909878256174">"Muestra una opción al pulsar el botón de encendido que desactiva Smart Lock, el desbloqueo con huella digital y las notificaciones en la pantalla de bloqueo"</string>
     <string name="trust_agents_extend_unlock_title" msgid="3582017561316089951">"Los agentes de confianza solo extienden el desbloqueo"</string>
     <string name="trust_agents_extend_unlock_summary" msgid="3543997596586078084">"Si se habilita esta opción, los agentes de confianza mantendrán el dispositivo desbloqueado durante más tiempo, pero ya no podrán desbloquear un dispositivo bloqueado"</string>
     <string name="trust_lost_locks_screen_title" msgid="3094736590690459372">"Bloquear pantalla si no hay confianza"</string>
@@ -369,7 +368,7 @@
     <string name="profile_info_settings_title" msgid="4855892878512562551">"Información del perfil"</string>
     <string name="Accounts_settings_title" msgid="7901374987121953746">"Cuentas"</string>
     <string name="location_settings_title" msgid="2707201457572301030">"Ubicación"</string>
-    <string name="location_settings_master_switch_title" msgid="3108016866082816733">"Utilizar ubicación"</string>
+    <string name="location_settings_master_switch_title" msgid="3108016866082816733">"Usar ubicación"</string>
     <string name="location_settings_summary_location_off" msgid="5563530256978372978">"Desactivada"</string>
     <plurals name="location_settings_summary_location_on" formatted="false" msgid="7893342914540884818">
       <item quantity="other">Activada: <xliff:g id="COUNT_1">%1$d</xliff:g> aplicaciones tienen acceso a la ubicación</item>
@@ -413,20 +412,20 @@
     <string name="face_intro_error_unknown" msgid="3241592604198351134">"No se pueden añadir más caras"</string>
     <string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"Registro no completado"</string>
     <string name="security_settings_face_enroll_dialog_ok" msgid="1078348922734845090">"Aceptar"</string>
-    <string name="security_settings_face_enroll_error_timeout_dialog_message" msgid="4917894418448325405">"Se ha alcanzado el tiempo de registro de la cara. Vuelve a intentarlo."</string>
+    <string name="security_settings_face_enroll_error_timeout_dialog_message" msgid="4917894418448325405">"Se ha alcanzado el tiempo límite de registro de la cara. Vuelve a intentarlo."</string>
     <string name="security_settings_face_enroll_error_generic_dialog_message" msgid="5160473187142616862">"El registro de la cara no ha funcionado."</string>
     <string name="security_settings_face_enroll_finish_title" msgid="6800717857394410769">"Ya has terminado. Todo perfecto."</string>
     <string name="security_settings_face_enroll_done" msgid="5409739233373490971">"Listo"</string>
     <string name="security_settings_face_settings_use_face_category" msgid="1586532139528115416">"Usar la cara para"</string>
     <string name="security_settings_face_settings_use_face_unlock_phone" msgid="318274519126401671">"Desbloq. dispositivo"</string>
-    <string name="security_settings_face_settings_use_face_for_apps" msgid="5479369083370664351">"Inicio de sesión y pagos"</string>
+    <string name="security_settings_face_settings_use_face_for_apps" msgid="5479369083370664351">"Iniciar sesión y pagos"</string>
     <string name="security_settings_face_settings_require_attention" msgid="2755140150841557225">"Ojos abiertos para desbloquear"</string>
     <string name="security_settings_face_settings_require_attention_details" msgid="2557060433599942587">"Cuando uses la autenticación facial, abre los ojos"</string>
     <string name="security_settings_face_settings_require_confirmation" msgid="7312024271060416438">"Pedir confirmación siempre"</string>
     <string name="security_settings_face_settings_require_confirmation_details" msgid="8740564864091803429">"Pedir confirmación siempre al autenticarse en aplicaciones"</string>
     <string name="security_settings_face_settings_remove_face_data" msgid="2821359954483136239">"Eliminar datos faciales"</string>
     <string name="security_settings_face_settings_footer" msgid="4627175759990550715">"Puedes desbloquear el dispositivo y acceder a tus aplicaciones mediante el reconocimiento facial. "<annotation id="url">"Más información"</annotation></string>
-    <string name="security_settings_face_settings_remove_dialog_title" msgid="5675319895815271094">"¿Quieres eliminar los datos faciales?"</string>
+    <string name="security_settings_face_settings_remove_dialog_title" msgid="5675319895815271094">"¿Eliminar los datos faciales?"</string>
     <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"Los datos grabados de la función Desbloqueo facial se eliminarán de manera segura y permanente. Una vez que se hayan eliminado, necesitarás el PIN, patrón o contraseña para desbloquear el teléfono, iniciar sesión en aplicaciones y confirmar pagos."</string>
     <string name="security_settings_fingerprint_preference_title" msgid="4177132225930582928">"Huella digital"</string>
     <string name="fingerprint_manage_category_title" msgid="1463406696801542090">"Administrar huellas"</string>
@@ -469,7 +468,7 @@
     <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"Toca el sensor"</string>
     <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Pon el dedo en el sensor y levántalo cuando notes una vibración"</string>
     <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"Levanta el dedo y toca de nuevo"</string>
-    <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Junta y separa el dedo varias veces para añadir las distintas partes de tu huella digital"</string>
+    <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Sigue levantando el dedo para añadir diferentes partes de tu huella digital"</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"Huella digital añadida"</string>
     <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"Cuando veas este icono, utiliza tu huella digital para identificarte o aprobar compras"</string>
     <string name="security_settings_fingerprint_enroll_enrolling_skip" msgid="1473280156532146933">"Hacerlo más adelante"</string>
@@ -489,7 +488,7 @@
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"¡Vaya! Ese no es el sensor"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"Toca el sensor situado detrás del teléfono con el dedo índice."</string>
     <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"Registro no completado"</string>
-    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Se ha alcanzado el tiempo de registro de la huella digital. Vuelve a intentarlo."</string>
+    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Se ha alcanzado el tiempo límite de registro de la huella digital. Vuelve a intentarlo."</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"El registro de la huella digital no se ha realizado correctamente. Vuelve a intentarlo o utiliza otro dedo."</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"Añadir otra"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"Siguiente"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Debe tener menos de <xliff:g id="NUMBER_1">%d</xliff:g> dígitos</item>
       <item quantity="one">Debe tener menos de <xliff:g id="NUMBER_0">%d</xliff:g> dígito</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Solo debe tener dígitos comprendidos entre el 0 y el 9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"El administrador de dispositivos no permite utilizar un PIN reciente"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"El administrador de TI bloquea los PIN comunes. Prueba a utilizar otro PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"No puede incluir un carácter que no sea válido"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Debe tener al menos <xliff:g id="COUNT">%d</xliff:g> caracteres que no sean una letra</item>
       <item quantity="one">Debe tener al menos 1 carácter que no sea una letra</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Debe incluir al menos <xliff:g id="COUNT">%d</xliff:g> caracteres que no sean números</item>
+      <item quantity="one">Debe incluir al menos 1 carácter que no sea un número</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"El administrador de dispositivos no permite utilizar una contraseña reciente"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"El administrador de TI bloquea las contraseñas comunes. Prueba a utilizar otra contraseña."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"No se permite utilizar una secuencia ascendente, descendente ni repetida de dígitos"</string>
@@ -763,9 +765,9 @@
     <string name="bluetooth_device_context_connect_advanced" msgid="423463405499392444">"Opciones…"</string>
     <string name="bluetooth_menu_advanced" msgid="7566858513372603652">"Avanzado"</string>
     <string name="bluetooth_advanced_titlebar" msgid="6459469494039004784">"Ajustes avanzados de Bluetooth"</string>
-    <string name="bluetooth_empty_list_bluetooth_off" msgid="6255367297830430459">"Si se activa el Bluetooth, tu dispositivo se puede comunicar con otros dispositivos con Bluetooth cercanos"</string>
+    <string name="bluetooth_empty_list_bluetooth_off" msgid="6255367297830430459">"Cuando el Bluetooth está activado, tu dispositivo se puede comunicar con otros dispositivos con Bluetooth cercanos"</string>
     <string name="bluetooth_scanning_on_info_message" msgid="5460370815156050550">"Si el Bluetooth está activado, el dispositivo se puede comunicar con otros dispositivos Bluetooth cercanos.\n\nPara mejorar la experiencia de uso del dispositivo, las aplicaciones y los servicios pueden seguir buscando dispositivos cercanos en cualquier momento, aunque el Bluetooth esté desactivado. Esta opción se puede utilizar, por ejemplo, para mejorar los servicios y funciones basados en la ubicación, y puedes cambiarla en los "<annotation id="link">"ajustes de búsqueda"</annotation>"."</string>
-    <string name="ble_scan_notify_text" msgid="6290170236546386932">"Para mejorar la precisión de la ubicación, los servicios y las aplicaciones del sistema pueden detectar dispositivos Bluetooth aunque esta conexión esté desactivada. Puedes cambiar esta opción en los <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>ajustes de búsqueda<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
+    <string name="ble_scan_notify_text" msgid="6290170236546386932">"Para mejorar la precisión de la ubicación, los servicios y las aplicaciones del sistema pueden seguir detectando dispositivos Bluetooth. Puedes cambiar esta opción en los <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>ajustes de búsqueda de Bluetooth<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
     <string name="bluetooth_connect_failed" msgid="1151234676456333786">"No se ha podido establecer conexión. Vuelve a intentarlo."</string>
     <string name="device_details_title" msgid="726517818032923222">"Detalles del dispositivo"</string>
     <string name="bluetooth_device_mac_address" msgid="5328203122581150405">"Dirección de Bluetooth del dispositivo: <xliff:g id="ADDRESS">%1$s</xliff:g>"</string>
@@ -824,7 +826,7 @@
     <string name="nfc_disclaimer_title" msgid="4860231267351602970">"Activar NFC"</string>
     <string name="nfc_disclaimer_content" msgid="3066113577854565782">"La tecnología NFC permite intercambiar datos entre este dispositivo y otros dispositivos u objetivos cercanos, como terminales de pago, lectores de acceso y etiquetas o anuncios interactivos."</string>
     <string name="nfc_secure_settings_title" msgid="5153751163174916581">"Proteger NFC"</string>
-    <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"Permitir uso de NFC en pagos y transporte público solo con la pantalla desbloqueada"</string>
+    <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"Permite usar NFC en pagos y transporte público solo con la pantalla desbloqueada"</string>
     <string name="android_beam_settings_title" msgid="3083436415873738389">"Android Beam"</string>
     <string name="android_beam_on_summary" msgid="8068287225180474199">"Listo para compartir contenido de aplicaciones por NFC"</string>
     <string name="android_beam_off_summary" msgid="7365818039159364600">"Desactivado"</string>
@@ -834,7 +836,7 @@
     <string name="wifi_quick_toggle_title" msgid="7935778388625246184">"Wi-Fi"</string>
     <string name="wifi_quick_toggle_summary" msgid="2879870570547594266">"Activar conexión Wi-Fi"</string>
     <string name="wifi_settings" msgid="7486492317310514109">"Wi-Fi"</string>
-    <string name="wifi_settings_master_switch_title" msgid="3917916944694253946">"Utilizar redes Wi‑Fi"</string>
+    <string name="wifi_settings_master_switch_title" msgid="3917916944694253946">"Usar Wi‑Fi"</string>
     <string name="wifi_settings_category" msgid="9094716747565527901">"Ajustes de Wi-Fi"</string>
     <string name="wifi_settings_title" msgid="5265554991622344805">"Wi-Fi"</string>
     <string name="wifi_settings_summary" msgid="7117267255799892820">"Configurar y administrar puntos de acceso inalámbricos"</string>
@@ -844,7 +846,7 @@
     <string name="wifi_error" msgid="5605801874484465557">"Error"</string>
     <string name="wifi_sap_no_channel_error" msgid="6881796988574851628">"Banda de 5 GHz no disponible en este país"</string>
     <string name="wifi_in_airplane_mode" msgid="4729571191578262246">"Modo avión"</string>
-    <string name="wifi_notify_open_networks" msgid="4782239203624619655">"Notificaciones de redes abiertas"</string>
+    <string name="wifi_notify_open_networks" msgid="4782239203624619655">"Notificar redes abiertas"</string>
     <string name="wifi_notify_open_networks_summary" msgid="1383681260705466715">"Recibir una notificación si hay una red pública de alta calidad disponible"</string>
     <string name="wifi_wakeup" msgid="4963732992164721548">"Activar Wi-Fi automáticamente"</string>
     <string name="wifi_wakeup_summary" msgid="1152699417411690">"La conexión Wi-Fi se volverá a activar automáticamente cerca de las redes de alta calidad guardadas, como la de tu casa"</string>
@@ -859,8 +861,8 @@
     <string name="use_open_wifi_automatically_summary_scoring_disabled" msgid="1559329344492373028">"Para usar esta función, selecciona un proveedor de valoración de redes"</string>
     <string name="use_open_wifi_automatically_summary_scorer_unsupported_disabled" msgid="1123080670578756834">"Para usar esta función, selecciona un proveedor de valoración de redes compatible"</string>
     <string name="wifi_install_credentials" msgid="5650088113710858289">"Instalar certificados"</string>
-    <string name="wifi_scan_notify_text" msgid="7614101215028336927">"Para mejorar la precisión de la ubicación, las aplicaciones y los servicios pueden seguir buscando redes Wi‑Fi en cualquier momento, aunque esta conexión esté desactivada. Esta opción se puede utilizar, por ejemplo, para mejorar los servicios y funciones basados en la ubicación, y puedes cambiarla en los <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>ajustes de búsqueda<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
-    <string name="wifi_scan_notify_text_scanning_off" msgid="723796963816095410">"Para mejorar la precisión de la ubicación, activa la búsqueda de redes Wi-Fi en los <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>ajustes de la búsqueda<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
+    <string name="wifi_scan_notify_text" msgid="7614101215028336927">"Para mejorar la precisión de la ubicación, las aplicaciones y los servicios pueden seguir buscando redes Wi‑Fi en cualquier momento incluso si el ajuste de Wi-Fi está desactivado. Esta opción se puede utilizar, por ejemplo, para mejorar los servicios y funciones basados en la ubicación. Puedes cambiar este ajuste en la <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>búsqueda de redes Wi-Fi<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
+    <string name="wifi_scan_notify_text_scanning_off" msgid="723796963816095410">"Para mejorar la precisión de la ubicación, activa la <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>búsqueda de redes Wi-Fi<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
     <string name="wifi_scan_notify_remember_choice" msgid="1235445971400237444">"No volver a mostrar"</string>
     <string name="wifi_setting_sleep_policy_title" msgid="2120785188625932076">"Usar Wi-Fi en suspensión"</string>
     <string name="wifi_setting_on_during_sleep_title" msgid="856670183023402715">"Wi‑Fi activado en suspensión"</string>
@@ -891,11 +893,11 @@
     <string name="wifi_empty_list_user_restricted" msgid="2341613007817352431">"No tienes permiso para cambiar la red Wi‑Fi."</string>
     <string name="wifi_more" msgid="3538241640407382185">"Más"</string>
     <string name="wifi_setup_wps" msgid="6730131677695521321">"Configuración automática (WPS)"</string>
-    <string name="wifi_settings_scanning_required_title" msgid="3593457187659922490">"¿Quieres activar la búsqueda de redes Wi‑Fi?"</string>
+    <string name="wifi_settings_scanning_required_title" msgid="3593457187659922490">"¿Activar la búsqueda de redes Wi‑Fi?"</string>
     <string name="wifi_settings_scanning_required_summary" msgid="7469610959462708782">"Para que la conexión Wi‑Fi se active automáticamente, es necesario activar la búsqueda de redes Wi‑Fi."</string>
     <string name="wifi_settings_scanning_required_info" msgid="5913535073390607386">"La búsqueda de redes Wi‑Fi permite que las aplicaciones y los servicios busquen redes Wi‑Fi en cualquier momento aunque la conexión Wi‑Fi esté desactivada. Se utiliza, por ejemplo, para mejorar los servicios y funciones basados en la ubicación."</string>
     <string name="wifi_settings_scanning_required_turn_on" msgid="4327570180594277049">"Activar"</string>
-    <string name="wifi_settings_scanning_required_enabled" msgid="3336102100425307040">"Se ha activado la búsqueda de redes Wi‑Fi"</string>
+    <string name="wifi_settings_scanning_required_enabled" msgid="3336102100425307040">"Búsqueda de redes Wi‑Fi activada"</string>
     <string name="wifi_show_advanced" msgid="8199779277168030597">"Opciones avanzadas"</string>
     <string name="wifi_advanced_toggle_description_expanded" msgid="1506697245302596510">"Lista desplegable Opciones Avanzadas. Tócala dos veces para ocultarla."</string>
     <string name="wifi_advanced_toggle_description_collapsed" msgid="3014965593695454879">"Lista desplegable Opciones Avanzadas. Tócala dos veces para mostrarla."</string>
@@ -903,11 +905,11 @@
     <string name="wifi_ssid_hint" msgid="5010024648106585165">"Introduce el SSID"</string>
     <string name="wifi_security" msgid="9136702039496152831">"Seguridad"</string>
     <string name="wifi_hidden_network" msgid="6647772204699776833">"Red oculta"</string>
-    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Si tu router no emite ningún identificador de red, pero quieres conectarte más adelante, puedes configurar la red como oculta.\n\nEsto puede suponer un riesgo para la seguridad, ya que el teléfono emitirá la señal de forma regular para buscar la red.\n\nConfigurar la red como oculta no cambiará la configuración del router."</string>
+    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Si tu router no emite ningún ID de red, pero quieres conectarte a la red más adelante, puedes configurar la red como oculta.\n\nEsto puede suponer un riesgo para la seguridad, ya que el teléfono emitirá la señal de forma habitual para buscar la red.\n\nConfigurar la red como oculta no cambiará la configuración del router."</string>
     <string name="wifi_signal" msgid="696548364467704808">"Intensidad de la señal"</string>
     <string name="wifi_status" msgid="3439931558930689940">"Estado"</string>
-    <string name="tx_wifi_speed" msgid="2571810085003261073">"Transmitir velocidad de enlace"</string>
-    <string name="rx_wifi_speed" msgid="7392873246110937187">"Recibir velocidad de enlace"</string>
+    <string name="tx_wifi_speed" msgid="2571810085003261073">"Velocidad de enlace de transmisión"</string>
+    <string name="rx_wifi_speed" msgid="7392873246110937187">"Velocidad de enlace de recepción"</string>
     <string name="wifi_frequency" msgid="6132852924995724246">"Frecuencia"</string>
     <string name="wifi_ip_address" msgid="5572539114989914831">"Dirección IP"</string>
     <string name="passpoint_label" msgid="7429247462404128615">"Guardada a través de"</string>
@@ -925,7 +927,7 @@
     <string name="wifi_ap_choose_auto" msgid="7927637960569365785">"Automática"</string>
     <string name="wifi_ap_choose_2G" msgid="43198403259714736">"Banda de 2,4 GHz"</string>
     <string name="wifi_ap_choose_5G" msgid="2624859713183683146">"Banda de 5,0 GHz"</string>
-    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"Banda preferida: 5,0 GHz"</string>
+    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"Banda de 5,0 GHz (preferida)"</string>
     <string name="wifi_ap_2G" msgid="5793110086517338494">"2,4 GHz"</string>
     <string name="wifi_ap_5G" msgid="4584892544393675403">"5,0 GHz"</string>
     <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"Selecciona al menos una banda para el punto de acceso Wi‑Fi:"</string>
@@ -933,13 +935,13 @@
     <string name="wifi_privacy_settings" msgid="4462092795794247809">"Privacidad"</string>
     <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"Dirección MAC aleatoria"</string>
     <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"Añadir un dispositivo"</string>
-    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"Encuadra el código QR para añadir el dispositivo a \"<xliff:g id="SSID">%1$s</xliff:g>\""</string>
-    <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"Escanear código QR"</string>
-    <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"Encuadra el código QR para conectarte a \"<xliff:g id="SSID">%1$s</xliff:g>\""</string>
-    <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"Escanea el código QR para conectarte al Wi‑Fi"</string>
+    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"Encuadra el código QR abajo para añadir el dispositivo a \"<xliff:g id="SSID">%1$s</xliff:g>\""</string>
+    <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"Escanea el código QR"</string>
+    <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"Encuadra el código QR abajo para conectarte a \"<xliff:g id="SSID">%1$s</xliff:g>\""</string>
+    <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"Conéctate a la red Wi-Fi escaneando un código QR"</string>
     <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Compartir Wi‑Fi"</string>
-    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"Escanea el código QR con otro dispositivo para conectarlo a \"<xliff:g id="SSID">%1$s</xliff:g>\" y compartir la contraseña"</string>
-    <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"Escanea el código QR con otro dispositivo para conectarte a \"<xliff:g id="SSID">%1$s</xliff:g>\""</string>
+    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"Escanea este código QR con otro dispositivo para conectarlo a \"<xliff:g id="SSID">%1$s</xliff:g>\" y compartir la contraseña"</string>
+    <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"Escanea este código QR con otro dispositivo para conectarte a \"<xliff:g id="SSID">%1$s</xliff:g>\""</string>
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"No se ha podido leer el código QR. Encuadra bien el código y vuelve a intentarlo."</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"Vuelve a intentarlo. Si el problema persiste, ponte en contacto con el fabricante del dispositivo"</string>
     <string name="wifi_dpp_failure_not_compatible" msgid="4320027179973678283">"Ha habido un error"</string>
@@ -949,7 +951,7 @@
     <string name="wifi_dpp_check_connection_try_again" msgid="7144663015219170999">"Comprueba la conexión y vuelve a intentarlo"</string>
     <string name="wifi_dpp_choose_network" msgid="6251424431594491691">"Elegir red"</string>
     <string name="wifi_dpp_choose_network_to_connect_device" msgid="6385259857886784285">"Elige una red para conectar tu dispositivo"</string>
-    <string name="wifi_dpp_add_device_to_wifi" msgid="6454198064645462446">"¿Quieres añadir este dispositivo a \"<xliff:g id="SSID">%1$s</xliff:g>\"?"</string>
+    <string name="wifi_dpp_add_device_to_wifi" msgid="6454198064645462446">"¿Añadir este dispositivo a \"<xliff:g id="SSID">%1$s</xliff:g>\"?"</string>
     <string name="wifi_dpp_wifi_shared_with_device" msgid="5713765471758272471">"Se ha compartido la red Wi‑Fi con el dispositivo"</string>
     <string name="wifi_dpp_add_another_device" msgid="3698441567235301565">"Añadir otro dispositivo"</string>
     <string name="wifi_dpp_choose_different_network" msgid="128515107488187050">"Elegir otra red"</string>
@@ -957,7 +959,7 @@
     <string name="wifi_dpp_device_found" msgid="6488461467496850841">"Dispositivo encontrado"</string>
     <string name="wifi_dpp_sharing_wifi_with_this_device" msgid="2540529164687476827">"Compartiendo Wi‑Fi con este dispositivo…"</string>
     <string name="wifi_dpp_connecting" msgid="4229290407210299897">"Conectando…"</string>
-    <string name="wifi_dpp_share_hotspot" msgid="847987212473038179">"Compartir punto de red Wi‑Fi"</string>
+    <string name="wifi_dpp_share_hotspot" msgid="847987212473038179">"Comparte el punto de red Wi‑Fi"</string>
     <string name="wifi_dpp_lockscreen_title" msgid="3910665850075275963">"Verifica que eres tú"</string>
     <string name="wifi_dpp_wifi_password" msgid="8007558344032612455">"Contraseña de la red Wi‑Fi: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
     <string name="wifi_dpp_hotspot_password" msgid="6172326289042241924">"Contraseña del punto de acceso: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
@@ -968,7 +970,7 @@
     <string name="wifi_unchanged" msgid="6804964646942333992">"(no modificada)"</string>
     <string name="wifi_unspecified" msgid="893491188483500809">"Selecciona una opción"</string>
     <string name="wifi_multiple_cert_added" msgid="7986200585749147204">"(Se han añadido varios certificados)"</string>
-    <string name="wifi_use_system_certs" msgid="4794489370929885022">"Utilizar certificados del sistema"</string>
+    <string name="wifi_use_system_certs" msgid="4794489370929885022">"Usar certificados del sistema"</string>
     <string name="wifi_do_not_provide_eap_user_cert" msgid="4044301449482425250">"No proporcionar"</string>
     <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"No validar"</string>
     <string name="wifi_do_not_validate_eap_server_warning" msgid="3895397996759837323">"No se ha especificado ningún certificado. La conexión no será privada."</string>
@@ -1055,7 +1057,7 @@
     <string name="wifi_p2p_cancel_connect_message" msgid="3752679335020392154">"¿Quieres cancelar la invitación para conectar con <xliff:g id="PEER_NAME">%1$s</xliff:g>?"</string>
     <string name="wifi_p2p_delete_group_message" msgid="3206660449067701089">"¿Olvidar este grupo?"</string>
     <string name="wifi_hotspot_checkbox_text" msgid="12062341344410520">"Punto de acceso Wi-Fi"</string>
-    <string name="wifi_hotspot_off_subtext" msgid="6177054857136221058">"No se está compartiendo la conexión a Internet ni el contenido con otros dispositivos"</string>
+    <string name="wifi_hotspot_off_subtext" msgid="6177054857136221058">"No se está compartiendo Internet ni el contenido con otros dispositivos"</string>
     <string name="wifi_hotspot_tethering_on_subtext" product="tablet" msgid="71421730039785897">"Se está compartiendo la conexión a Internet de este tablet mediante un punto de acceso"</string>
     <string name="wifi_hotspot_tethering_on_subtext" product="default" msgid="8914285514605049879">"Se está compartiendo la conexión a Internet de este teléfono mediante un punto de acceso"</string>
     <string name="wifi_hotspot_on_local_only_subtext" msgid="7415381343846704553">"La aplicación está compartiendo contenido. Para compartir la conexión a Internet, desactiva el punto de acceso y vuelve a activarlo"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Móvil"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Si la red Wi‑Fi no está disponible, utiliza la red móvil"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Si la red móvil no está disponible, utiliza la red Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Llamar a través de Wi‑Fi. Si se pierde conexión, se cortará la llamada."</string>
@@ -1198,7 +1203,7 @@
     <string name="auto_brightness_off_summary" msgid="6162650416289359104">"No ajustar en función de la luz ambiental"</string>
     <string name="auto_brightness_very_high_summary" msgid="7202032980509583918">"Aumenta el uso de la batería"</string>
     <string name="auto_brightness_disclaimer" msgid="5416696351199148809">"Optimiza el brillo en función de la luz ambiental. Puedes ajustarlo temporalmente aunque actives esta función."</string>
-    <string name="auto_brightness_description" msgid="8209140379089535411">"El brillo de la pantalla se ajustará automáticamente según el entorno y las actividades que hagas. Puedes mover el control deslizante para que la función de brillo adaptativo reconozca tus preferencias."</string>
+    <string name="auto_brightness_description" msgid="8209140379089535411">"El brillo de la pantalla se ajustará automáticamente según el entorno y lo que hagas. Puedes mover el control deslizante para que la función de brillo adaptativo reconozca tus preferencias."</string>
     <string name="display_white_balance_title" msgid="5747260735311935143">"Balance de blancos de pantalla"</string>
     <string name="adaptive_sleep_title" msgid="3237620948260957018">"Modo privado"</string>
     <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"Activado: la pantalla no se apagará si estás mirándola"</string>
@@ -1219,7 +1224,7 @@
     <string name="night_display_summary_off_auto_mode_never" msgid="8618824386434992487">"No se activará nunca automáticamente"</string>
     <string name="night_display_summary_off_auto_mode_custom" msgid="596847003171394411">"Se activará automáticamente a esta hora: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="night_display_summary_off_auto_mode_twilight" msgid="4071750976585359952">"Se activará automáticamente al anochecer"</string>
-    <string name="night_display_summary_on" msgid="6580571388791426596">"Activado/<xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="night_display_summary_on" msgid="6580571388791426596">"Activado / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="night_display_summary_on_auto_mode_never" msgid="5461580863060506687">"No se desactivará nunca automáticamente"</string>
     <string name="night_display_summary_on_auto_mode_custom" msgid="2200631112239399233">"Se desactivará automáticamente a esta hora: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="night_display_summary_on_auto_mode_twilight" msgid="8386769601369289561">"Se desactivará automáticamente al amanecer"</string>
@@ -1250,7 +1255,7 @@
     <string name="screensaver_settings_disabled_prompt" msgid="1897518064782596947">"Para controlar lo que ocurre cuando el teléfono está en un dock o inactivo, activa el salvapantallas."</string>
     <string name="screensaver_settings_when_to_dream" msgid="3763052013516826348">"Cuándo empezar a mostrarlo"</string>
     <string name="screensaver_settings_current" msgid="4017556173596361672">"Salvapantallas actual"</string>
-    <string name="screensaver_settings_dream_start" msgid="3772227299054662550">"Iniciar ahora"</string>
+    <string name="screensaver_settings_dream_start" msgid="3772227299054662550">"Empezar ahora"</string>
     <string name="screensaver_settings_button" msgid="4662384378821837589">"Ajustes"</string>
     <string name="automatic_brightness" msgid="8663792987774126192">"Brillo automático"</string>
     <string name="lift_to_wake_title" msgid="5523752279947392868">"Levantar el dispositivo para activarlo"</string>
@@ -1337,10 +1342,10 @@
     <string name="status_msid_number" msgid="7808175928664357661">"MSID"</string>
     <string name="status_prl_version" msgid="5634561205739199042">"Versión de PRL"</string>
     <string name="meid_multi_sim" msgid="7449892644113569529">"MEID (ranura SIM %1$d)"</string>
-    <string name="scanning_status_text_wifi_on_ble_on" msgid="6370507836346838473">"Las redes Wi‑Fi y las conexiones Bluetooth tienen la búsqueda activada"</string>
-    <string name="scanning_status_text_wifi_on_ble_off" msgid="8205014713732412608">"La búsqueda de redes Wi‑Fi está activa y la de conexiones Bluetooth, desactivada"</string>
-    <string name="scanning_status_text_wifi_off_ble_on" msgid="7400522456303307057">"La búsqueda de conexiones Bluetooth está activada y la de redes Wi‑Fi, desactivada"</string>
-    <string name="scanning_status_text_wifi_off_ble_off" msgid="8575026386237481457">"Está desactivada la búsqueda de redes Wi‑Fi y conexiones Bluetooth"</string>
+    <string name="scanning_status_text_wifi_on_ble_on" msgid="6370507836346838473">"Tanto la búsqueda de redes Wi‑Fi como la de dispositivos Bluetooth están activadas"</string>
+    <string name="scanning_status_text_wifi_on_ble_off" msgid="8205014713732412608">"La búsqueda de redes Wi‑Fi está activada; la búsqueda de dispositivos Bluetooth está desactivada"</string>
+    <string name="scanning_status_text_wifi_off_ble_on" msgid="7400522456303307057">"La búsqueda de dispositivos Bluetooth está activada; la búsqueda de redes Wi‑Fi está desactivada"</string>
+    <string name="scanning_status_text_wifi_off_ble_off" msgid="8575026386237481457">"Tanto la búsqueda de redes Wi‑Fi como la de dispositivos Bluetooth están desactivadas"</string>
     <string name="status_meid_number" msgid="8756271256760479835">"MEID"</string>
     <string name="status_icc_id" msgid="9191847562997702709">"ICCID"</string>
     <string name="status_data_network_type" msgid="2344720457353394909">"Tipo de red de datos móviles"</string>
@@ -1522,8 +1527,8 @@
     <string name="battery_status_title" msgid="8731200319740671905">"Estado de la batería"</string>
     <string name="battery_level_title" msgid="5207775387973771646">"Nivel de batería"</string>
     <string name="apn_settings" msgid="8130776653826271664">"APNs"</string>
-    <string name="apn_edit" msgid="4350571070853305357">"Editar punto acceso"</string>
-    <string name="apn_not_set" msgid="5344235604466825691">"No definido"</string>
+    <string name="apn_edit" msgid="4350571070853305357">"Editar punto de acceso"</string>
+    <string name="apn_not_set" msgid="5344235604466825691">"Sin definir"</string>
     <string name="apn_name" msgid="8431432886706852226">"Nombre"</string>
     <string name="apn_apn" msgid="190519449579357696">"APN"</string>
     <string name="apn_http_proxy" msgid="8816906767987944465">"Proxy"</string>
@@ -1564,11 +1569,11 @@
     <string name="menu_restore" msgid="3799288817317293115">"Restablecer ajustes"</string>
     <string name="restore_default_apn_completed" msgid="5671734152740058937">"Se ha restablecido la configuración predeterminada de APN."</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"Opciones de recuperación"</string>
-    <string name="reset_dashboard_summary" msgid="8778383341461126642">"Se puede recuperar la configuración de la red, de las aplicaciones o del dispositivo"</string>
+    <string name="reset_dashboard_summary" msgid="8778383341461126642">"Se pueden recuperar los ajustes de red, de las aplicaciones y del dispositivo"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"Recuperar Wi-Fi, red móvil y Bluetooth"</string>
     <string name="reset_network_desc" msgid="4982633363916261109">"Se recuperarán todos los ajustes de red, como:\n\n"<li>"Wi‑Fi"</li>\n<li>"Datos móviles"</li>\n<li>"Bluetooth"</li></string>
     <string name="reset_esim_title" msgid="7630781767040831893">"Borrar las SIM descargadas"</string>
-    <string name="reset_esim_desc" msgid="433226911566802">"Para descargar SIMs de sustitución, ponte en contacto con tu operador. Esta acción no cancelará ninguno de los planes de servicios móviles."</string>
+    <string name="reset_esim_desc" msgid="433226911566802">"Para descargar SIM de sustitución, ponte en contacto con tu operador. Esta acción no cancelará ningún plan de servicios móviles."</string>
     <string name="reset_network_button_text" msgid="4293271046867912819">"Recuperar ajustes"</string>
     <string name="reset_network_final_desc" msgid="2463817067048751373">"¿Quieres restablecer la configuración de red? No podrás deshacer esta acción."</string>
     <string name="reset_network_final_desc_esim" msgid="4676436976372555750">"¿Quieres recuperar todos los ajustes de red y borrar todas las SIM descargadas? No podrás deshacer esta acción."</string>
@@ -1586,7 +1591,7 @@
     <string name="master_clear_other_users_present" product="default" msgid="5993259656117566767">\n\n"Hay otros usuarios presentes en este dispositivo.\n"</string>
     <string name="master_clear_desc_also_erases_external" msgid="3947303501615091903"><li>"Música"</li>\n<li>"Fotos"</li>\n<li>"Otros datos de usuario"</li></string>
     <string name="master_clear_desc_also_erases_esim" msgid="4497260499055258773"><li>"eSIMs"</li></string>
-    <string name="master_clear_desc_no_cancel_mobile_plan" msgid="6072668588881679461">\n\n"Tu plan de servicios móviles no se cancelará."</string>
+    <string name="master_clear_desc_no_cancel_mobile_plan" msgid="6072668588881679461">\n\n"Esta acción no cancelará tu plan de servicios móviles."</string>
     <string name="master_clear_desc_erase_external_storage" product="nosdcard" msgid="2723272952715259307">\n\n"Para eliminar la música, las imágenes y otros datos de usuario, debes borrar el "<b>"almacenamiento USB"</b>"."</string>
     <string name="master_clear_desc_erase_external_storage" product="default" msgid="9003555775524798797">\n\n"Para eliminar la música, las imágenes y otros datos de usuario, debes borrar la "<b>"tarjeta SD"</b>"."</string>
     <string name="erase_external_storage" product="nosdcard" msgid="8989746770347525207">"Borrar almacenamiento USB"</string>
@@ -1616,11 +1621,11 @@
     <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"No se puede hacer el anclaje de red ni utilizar zonas Wi-Fi portátiles mientras el ahorro de datos esté activado"</string>
     <string name="usb_title" msgid="7480927657535578688">"USB"</string>
     <string name="usb_tethering_button_text" msgid="6242228383142012332">"Compartir conexión por USB"</string>
-    <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"Compartir la conexión a Internet del teléfono por USB"</string>
+    <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"Comparte la conexión a Internet del teléfono por USB"</string>
     <string name="usb_tethering_subtext" product="tablet" msgid="154536000235361034">"Compartir la conexión a Internet del tablet por USB"</string>
     <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"Compartir conexión por Bluetooth"</string>
     <string name="bluetooth_tethering_subtext" product="tablet" msgid="6868756914621131635">"Compartir la conexión a Internet del tablet por Bluetooth"</string>
-    <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"Compartir la conexión a Internet del teléfono por Bluetooth"</string>
+    <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"Comparte la conexión a Internet del teléfono por Bluetooth"</string>
     <string name="bluetooth_tethering_off_subtext_config" msgid="3981528184780083266">"Se está compartiendo la conexión a Internet de este <xliff:g id="DEVICE_NAME">%1$d</xliff:g> por Bluetooth"</string>
     <string name="bluetooth_tethering_overflow_error" msgid="6946561351369376943">"No se puede anclar a más de <xliff:g id="MAXCONNECTION">%1$d</xliff:g> dispositivos."</string>
     <string name="bluetooth_untether_blank" msgid="5428300773782256084">"Se desactivará el anclaje a red de <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
@@ -1701,7 +1706,7 @@
     <string name="settings_safetylegal_activity_unreachable" msgid="3541894966476445833">"No tienes conexión de datos. Para ver esta información, accede a %s desde cualquier ordenador conectado a Internet."</string>
     <string name="settings_safetylegal_activity_loading" msgid="7680998654145172">"Cargando…"</string>
     <string name="confirm_device_credential_use_alternate_method" msgid="1279869272895739941">"Utilizar método alternativo"</string>
-    <string name="lockpassword_choose_your_screen_lock_header" msgid="6283518876031424798">"Establecer el bloqueo de pantalla"</string>
+    <string name="lockpassword_choose_your_screen_lock_header" msgid="6283518876031424798">"Establece un bloqueo de pantalla"</string>
     <string name="lockpassword_choose_your_password_message" msgid="2838273977481046536">"Por seguridad, establece una contraseña"</string>
     <string name="lockpassword_choose_your_password_header_for_fingerprint" msgid="4921343500484160894">"Para usar la huella, añade una contraseña"</string>
     <string name="lockpassword_choose_your_pattern_header_for_fingerprint" msgid="314870151462139417">"Para usar tu huella, añade un patrón"</string>
@@ -1954,7 +1959,7 @@
     <string name="hardkeyboard_category" msgid="5937171470391551627">"Ajustes del teclado físico"</string>
     <string name="auto_punctuate_summary" msgid="245694025030386370">"Pulsa la barra espaciadora dos veces para insertar el carácter \".\""</string>
     <string name="show_password" msgid="620964020348073739">"Mostrar contraseñas"</string>
-    <string name="show_password_summary" msgid="1403805089582258620">"Mostrar los caracteres brevemente al escribir"</string>
+    <string name="show_password_summary" msgid="1403805089582258620">"Muestra los caracteres brevemente al escribir"</string>
     <string name="spellchecker_security_warning" msgid="792070474432612097">"Este corrector ortográfico puede registrar todo lo que escribas, incluidos datos personales, como las contraseñas y los números de las tarjetas de crédito. Procede de la aplicación <xliff:g id="SPELLCHECKER_APPLICATION_NAME">%1$s</xliff:g>. ¿Quieres usar este corrector ortográfico?"</string>
     <string name="spellchecker_quick_settings" msgid="5193036510190696655">"Ajustes"</string>
     <string name="spellchecker_language" msgid="5168501692418112444">"Idioma"</string>
@@ -1965,7 +1970,7 @@
     <string name="keyboard_assistance_category" msgid="2276351807419818125">"Ayuda del teclado"</string>
     <string name="physical_keyboard_title" msgid="3508591962962814313">"Teclado físico"</string>
     <string name="show_ime" msgid="7322620473198763563">"Mostrar teclado virtual"</string>
-    <string name="show_ime_summary" msgid="3246628154011464373">"Mantener en la pantalla mientras el teclado físico está activo"</string>
+    <string name="show_ime_summary" msgid="3246628154011464373">"Lo mantiene en pantalla mientras el teclado físico está activo"</string>
     <string name="keyboard_shortcuts_helper" msgid="6574386807271399788">"Ayuda de accesos directos de teclado"</string>
     <string name="keyboard_shortcuts_helper_summary" msgid="8024313306403779742">"Muestra accesos directos de teclado disponibles"</string>
     <string name="language_and_input_for_work_category_title" msgid="2053255944038892588">"Perfiles de trabajo y herramientas"</string>
@@ -2031,10 +2036,10 @@
     <string name="usage_time_label" msgid="5615725415876461039">"Tiempo de uso"</string>
     <string name="accessibility_settings" msgid="9140621093888234485">"Accesibilidad"</string>
     <string name="accessibility_settings_title" msgid="1687226556576913576">"Ajustes de accesibilidad"</string>
-    <string name="accessibility_settings_summary" msgid="5742379519336396561">"Lectores de pantalla, pantalla y controles de interacción"</string>
+    <string name="accessibility_settings_summary" msgid="5742379519336396561">"Lectores de pantalla, pantalla, controles de interacción"</string>
     <string name="vision_settings_title" msgid="7315352351051423944">"Ajustes de visión"</string>
-    <string name="vision_settings_description" msgid="3476589459009287332">"Personaliza este dispositivo para adaptarlo a tus necesidades. Puedes modificar las funciones de accesibilidad posteriormente en Ajustes."</string>
-    <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"Cambiar el tamaño de la fuente"</string>
+    <string name="vision_settings_description" msgid="3476589459009287332">"Personaliza este dispositivo para adaptarlo a tus necesidades. Puedes modificar las funciones de accesibilidad más tarde en Ajustes."</string>
+    <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"Cambia el tamaño de la fuente"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"Lectores de pantalla"</string>
     <string name="audio_and_captions_category_title" msgid="6140472938769619212">"Audio y texto en pantalla"</string>
     <string name="display_category_title" msgid="545168481672250195">"Pantalla"</string>
@@ -2046,7 +2051,7 @@
     <string name="talkback_summary" msgid="6602857105831641574">"El lector de pantalla está destinado principalmente a personas ciegas y con problemas de visión"</string>
     <string name="select_to_speak_summary" msgid="7514180457557735421">"Toca cualquier elemento de la pantalla para escucharlo"</string>
     <string name="accessibility_captioning_title" msgid="5878371993023439642">"Subtítulos"</string>
-    <string name="accessibility_screen_magnification_title" msgid="7250949681883917360">"Ampliar"</string>
+    <string name="accessibility_screen_magnification_title" msgid="7250949681883917360">"Ampliación"</string>
     <string name="accessibility_screen_magnification_gestures_title" msgid="9199287875401817974">"Ampliar con tres toques"</string>
     <string name="accessibility_screen_magnification_navbar_title" msgid="400655612610761242">"Ampliar con botón"</string>
     <string name="accessibility_screen_magnification_state_navbar_gesture" msgid="1863831350878995600">"Amplía con un botón y tres toques"</string>
@@ -2067,7 +2072,7 @@
     <string name="accessibility_toggle_large_pointer_icon_title" msgid="9127905775116570565">"Puntero del ratón grande"</string>
     <string name="accessibility_disable_animations" msgid="8378441317115710009">"Quitar animaciones"</string>
     <string name="accessibility_toggle_master_mono_title" msgid="899550848196702565">"Audio en mono"</string>
-    <string name="accessibility_toggle_master_mono_summary" msgid="3847052868469033235">"Combinar canales al reproducir audio"</string>
+    <string name="accessibility_toggle_master_mono_summary" msgid="3847052868469033235">"Combina canales al reproducir audio"</string>
     <string name="accessibility_toggle_master_balance_title" msgid="8723492001092647562">"Balance de audio"</string>
     <string name="accessibility_toggle_master_balance_left_label" msgid="8531986342666527970">"Izquierdo"</string>
     <string name="accessibility_toggle_master_balance_right_label" msgid="7757024572140589558">"Derecho"</string>
@@ -2091,7 +2096,7 @@
     <string name="accessibility_ring_vibration_title" msgid="7943341443551359985">"Vibración del tono"</string>
     <string name="accessibility_touch_vibration_title" msgid="285890135612038092">"Vibración al tocar la pantalla"</string>
     <string name="accessibility_service_master_switch_title" msgid="2734791644475782924">"Usar servicio"</string>
-    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Utilizar la corrección de color"</string>
+    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Usar corrección de color"</string>
     <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"Utilizar subtítulos"</string>
     <string name="accessibility_hearingaid_instruction_continue_button" msgid="4650111296711466691">"Continuar"</string>
     <string name="accessibility_hearingaid_title" msgid="3700978781235124891">"Audífonos"</string>
@@ -2262,7 +2267,7 @@
     <string name="details_subtitle" msgid="7279638828004951382">"Detalles de uso"</string>
     <string name="controls_subtitle" msgid="6920199888882834620">"Cómo reducir el uso de la batería"</string>
     <string name="packages_subtitle" msgid="6506269487892204413">"Paquetes incluidos"</string>
-    <string name="battery_tip_summary_title" msgid="2750922152518825526">"Las aplicaciones funcionan correctamente"</string>
+    <string name="battery_tip_summary_title" msgid="2750922152518825526">"Las aplicaciones funcionan con normalidad"</string>
     <string name="battery_tip_summary_summary" product="default" msgid="6294900413896440006">"El teléfono tiene un consumo normal de batería en segundo plano"</string>
     <string name="battery_tip_summary_summary" product="tablet" msgid="5280099016800644130">"El tablet tiene un consumo normal de batería en segundo plano"</string>
     <string name="battery_tip_summary_summary" product="device" msgid="4459840492610842705">"El dispositivo tiene un consumo normal de batería en segundo plano"</string>
@@ -2276,7 +2281,7 @@
     <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Es posible que te quedes sin batería antes de lo normal"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Ahorro de batería activado"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Es posible que algunas funciones estén limitadas"</string>
-    <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"El teléfono se ha usado más de lo normal"</string>
+    <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Teléfono usado más de lo normal"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"El tablet se ha usado más de lo normal"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"El dispositivo se ha usado más de lo normal"</string>
     <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"Es posible que te quedes sin batería antes de lo normal"</string>
@@ -2293,28 +2298,28 @@
       <item quantity="one">%1$s aplicación se ha restringido recientemente</item>
     </plurals>
     <plurals name="battery_tip_restrict_summary" formatted="false" msgid="984148373944071669">
-      <item quantity="other">%2$d aplicaciones consumen mucha batería en segundo plano</item>
-      <item quantity="one">%1$s aplicación consume mucha batería en segundo plano</item>
+      <item quantity="other">%2$d apps gastan mucho en segundo plano</item>
+      <item quantity="one">%1$s gasta mucho en segundo plano</item>
     </plurals>
     <plurals name="battery_tip_restrict_handled_summary" formatted="false" msgid="469696766640020557">
       <item quantity="other">Estas aplicaciones no se pueden ejecutar en segundo plano</item>
       <item quantity="one">Esta aplicación no se puede ejecutar en segundo plano</item>
     </plurals>
     <plurals name="battery_tip_restrict_app_dialog_title" formatted="false" msgid="3042021435866172168">
-      <item quantity="other">¿Quieres restringir %1$d aplicaciones?</item>
-      <item quantity="one">¿Quieres restringir la aplicación?</item>
+      <item quantity="other">¿Restringir %1$d aplicaciones?</item>
+      <item quantity="one">¿Restringir aplicación?</item>
     </plurals>
     <string name="battery_tip_restrict_app_dialog_message" msgid="6905822297507947381">"Si quieres ahorrar batería, evita que <xliff:g id="APP">%1$s</xliff:g> consuma batería en segundo plano. Es posible que la aplicación no funcione correctamente y las notificaciones se retrasen."</string>
     <string name="battery_tip_restrict_apps_less_than_5_dialog_message" msgid="4225881888543582456">"Si quieres ahorrar batería, evita que estas aplicaciones consuman batería en segundo plano. Es posible que las aplicaciones restringidas no funcionen correctamente y las notificaciones se retrasen.\n\nAplicaciones:"</string>
     <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"Si quieres ahorrar batería, evita que estas aplicaciones consuman batería en segundo plano. Es posible que las aplicaciones restringidas no funcionen correctamente y las notificaciones se retrasen.\n\nAplicaciones:\n<xliff:g id="APP_LIST">%1$s</xliff:g>."</string>
     <string name="battery_tip_restrict_app_dialog_ok" msgid="2573410775701913487">"Restringir"</string>
     <string name="battery_tip_unrestrict_app_dialog_title" msgid="812458516399125710">"¿Quitar restricción?"</string>
-    <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"Esta aplicación puede utilizar la batería en segundo plano y provocar que te quedes sin batería antes de lo que pensabas."</string>
+    <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"Esta aplicación podrá usar la batería en segundo plano. Es posible que la batería se agote antes de lo esperado."</string>
     <string name="battery_tip_unrestrict_app_dialog_ok" msgid="9154938931448151479">"Quitar"</string>
     <string name="battery_tip_unrestrict_app_dialog_cancel" msgid="7331148618292397166">"Cancelar"</string>
-    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"Tus aplicaciones usan una cantidad normal de batería. Si consumieran demasiada, tu dispositivo te recomendaría medidas para evitarlo.\n\nSi te queda poca carga, también puedes activar el Ahorro de batería."</string>
-    <string name="battery_tip_dialog_summary_message" product="tablet" msgid="1721081030632329647">"Tus aplicaciones usan una cantidad normal de batería. Si consumieran demasiada, tu dispositivo te recomendaría medidas para evitarlo.\n\nSi te queda poca carga, también puedes activar el Ahorro de batería."</string>
-    <string name="battery_tip_dialog_summary_message" product="device" msgid="146872407040848465">"Tus aplicaciones usan una cantidad normal de batería. Si consumieran demasiada, tu dispositivo te recomendaría medidas para evitarlo.\n\nSi te queda poca carga, también puedes activar el Ahorro de batería."</string>
+    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"Tus aplicaciones usan una cantidad normal de batería. Si consumieran demasiada, el teléfono te recomendaría medidas para evitarlo.\n\nSi te queda poca carga, también puedes activar el modo Ahorro de batería."</string>
+    <string name="battery_tip_dialog_summary_message" product="tablet" msgid="1721081030632329647">"Tus aplicaciones usan una cantidad normal de batería. Si consumieran demasiada, el tablet te recomendaría medidas para evitarlo.\n\nSi te queda poca carga, también puedes activar el modo Ahorro de batería."</string>
+    <string name="battery_tip_dialog_summary_message" product="device" msgid="146872407040848465">"Tus aplicaciones usan una cantidad normal de batería. Si consumieran demasiada, el dispositivo te recomendaría medidas para evitarlo.\n\nSi te queda poca carga, también puedes activar el modo Ahorro de batería."</string>
     <string name="smart_battery_manager_title" msgid="5744035036663849515">"Gestor de batería"</string>
     <string name="smart_battery_title" msgid="4919670408532804351">"Gestionar aplicaciones automáticamente"</string>
     <string name="smart_battery_summary" msgid="640027046471198174">"Limitar el consumo de batería de las aplicaciones que no utilices con frecuencia"</string>
@@ -2444,24 +2449,24 @@
     <string name="battery_saver" msgid="3989710213758938398">"Ahorro de batería"</string>
     <string name="battery_saver_auto_title" msgid="4158659069641849952">"Activar automáticamente"</string>
     <string name="battery_saver_auto_no_schedule" msgid="739814529432092706">"Sin programación"</string>
-    <string name="battery_saver_auto_routine" msgid="886514412067906980">"Según tu rutina"</string>
+    <string name="battery_saver_auto_routine" msgid="886514412067906980">"Basado en tu rutina"</string>
     <string name="battery_saver_auto_percentage" msgid="5791982309331921556">"Según el porcentaje"</string>
-    <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"La función Ahorro de batería se activa si es probable que te quedes sin batería antes de tu próxima carga normal."</string>
+    <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"El modo Ahorro de batería se activa si es probable que te quedes sin batería antes de tu próxima carga normal."</string>
     <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"Se activará cuando llegue al <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
-    <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"Definir una programación"</string>
+    <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"Establecer una programación"</string>
     <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"Desactivar con la carga al máximo"</string>
-    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"El modo Ahorro de batería se desactiva cuando tu teléfono está al <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
-    <string name="battery_saver_sticky_description_new" product="tablet" msgid="3284967694001857194">"El modo Ahorro de batería se desactiva cuando tu teléfono está al <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
-    <string name="battery_saver_sticky_description_new" product="device" msgid="5056520668081504111">"El modo Ahorro de batería se desactiva cuando tu teléfono está al <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
+    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"El modo Ahorro de batería se desactiva cuando el teléfono está al <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
+    <string name="battery_saver_sticky_description_new" product="tablet" msgid="3284967694001857194">"El modo Ahorro de batería se desactiva cuando el teléfono está al <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
+    <string name="battery_saver_sticky_description_new" product="device" msgid="5056520668081504111">"El modo Ahorro de batería se desactiva cuando el teléfono está al <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <!-- no translation found for battery_saver_seekbar_title (7607123201469333645) -->
     <skip />
     <string name="battery_saver_seekbar_title_placeholder" msgid="2321082163892561703">"Activar"</string>
-    <string name="battery_saver_master_switch_title" msgid="8241862826825517212">"Utilizar la función Ahorro de batería"</string>
+    <string name="battery_saver_master_switch_title" msgid="8241862826825517212">"Usar modo Ahorro de batería"</string>
     <string name="battery_saver_turn_on_automatically_title" msgid="7316920304024245838">"Activar automáticamente"</string>
     <string name="battery_saver_turn_on_automatically_never" msgid="2623381258359775227">"Nunca"</string>
     <string name="battery_saver_turn_on_automatically_pct" msgid="434270432432390307">"con un <xliff:g id="PERCENT">%1$s</xliff:g> de batería"</string>
     <string name="battery_percentage" msgid="7782252476471033843">"Porcentaje de batería"</string>
-    <string name="battery_percentage_description" msgid="9219875229166700610">"Mostrar el porcentaje de batería en la barra de estado"</string>
+    <string name="battery_percentage_description" msgid="9219875229166700610">"Muestra el porcentaje de batería en la barra de estado"</string>
     <string name="process_stats_summary_title" msgid="9189588417488537954">"Estadísticas de procesos"</string>
     <string name="process_stats_summary" msgid="8077998499161221885">"Estadísticas técnicas sobre procesos en ejecución"</string>
     <string name="app_memory_use" msgid="5126237308545653706">"Uso de memoria"</string>
@@ -2520,14 +2525,14 @@
     <string name="credentials_title" msgid="7119207354982673965">"Almacenamiento de credenciales"</string>
     <string name="credentials_install" product="nosdcard" msgid="8509362500537206883">"Instalar desde almacenamiento"</string>
     <string name="credentials_install" product="default" msgid="8997183776710118353">"Instalar desde la tarjeta SD"</string>
-    <string name="credentials_install_summary" product="nosdcard" msgid="3426661965567059596">"Instalar certificados desde almacenamiento"</string>
+    <string name="credentials_install_summary" product="nosdcard" msgid="3426661965567059596">"Instala certificados desde el almacenamiento"</string>
     <string name="credentials_install_summary" product="default" msgid="4943897416156671633">"Instalar certificados desde la tarjeta SD"</string>
-    <string name="credentials_reset" msgid="355080737664731678">"Eliminar certificados"</string>
-    <string name="credentials_reset_summary" msgid="7622528359699428555">"Quitar todos los certificados"</string>
+    <string name="credentials_reset" msgid="355080737664731678">"Borrar credenciales"</string>
+    <string name="credentials_reset_summary" msgid="7622528359699428555">"Quita todos los certificados"</string>
     <string name="trusted_credentials" msgid="6989242522455395200">"Credenciales de confianza"</string>
-    <string name="trusted_credentials_summary" msgid="7411781319056251582">"Mostrar certificados de CA de confianza"</string>
+    <string name="trusted_credentials_summary" msgid="7411781319056251582">"Muestra los certificados de CA de confianza"</string>
     <string name="user_credentials" msgid="8365731467650306757">"Credenciales de usuario"</string>
-    <string name="user_credentials_summary" msgid="7350223899317423252">"Ver y modificar credenciales almacenadas"</string>
+    <string name="user_credentials_summary" msgid="7350223899317423252">"Consulta y modifica credenciales almacenadas"</string>
     <string name="advanced_security_title" msgid="286883005673855845">"Avanzado"</string>
     <string name="credential_storage_type" msgid="2585337320206095255">"Tipo de almacenamiento"</string>
     <string name="credential_storage_type_hardware" msgid="5054143224259023600">"Almacenado en hardware"</string>
@@ -2596,7 +2601,7 @@
     <string name="work_mode_label" msgid="6845849194740195757">"Perfil de trabajo"</string>
     <string name="work_mode_on_summary" msgid="1682781113156323592">"Administrado por tu organización"</string>
     <string name="work_mode_off_summary" msgid="1688885392211178315">"Las aplicaciones y las notificaciones están desactivadas"</string>
-    <string name="remove_managed_profile_label" msgid="4625542553784793536">"Eliminar perfil de trabajo"</string>
+    <string name="remove_managed_profile_label" msgid="4625542553784793536">"Quitar perfil de trabajo"</string>
     <string name="background_data" msgid="8275750862371471171">"Datos en segundo plano"</string>
     <string name="background_data_summary" msgid="799640633948841990">"Las aplicaciones pueden sincronizar datos, enviarlos y recibirlos."</string>
     <string name="background_data_dialog_title" msgid="8306650658158895976">"¿Inhabilitar datos en segundo plano?"</string>
@@ -2665,7 +2670,7 @@
     <string name="data_usage_menu_sim_cards" msgid="8508154611676507088">"Tarjetas SIM"</string>
     <string name="data_usage_cellular_data_summary" msgid="9162777397135709280">"En pausa al límite"</string>
     <string name="account_settings_menu_auto_sync" msgid="2673669556006027506">"Sincronización automática"</string>
-    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"Sincr. autom. datos personales"</string>
+    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"Sincronizar datos personales automáticamente"</string>
     <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Sincr. autom. datos trabajo"</string>
     <string name="data_usage_change_cycle" msgid="447761920472170031">"Cambiar ciclo…"</string>
     <string name="data_usage_pick_cycle_day" msgid="6319750879145917066">"Día del mes para restablecer ciclo de uso de datos:"</string>
@@ -2673,7 +2678,7 @@
     <string name="data_usage_label_foreground" msgid="2471091128648754601">"Primer plano"</string>
     <string name="data_usage_label_background" msgid="1618794447370396845">"Segundo plano"</string>
     <string name="data_usage_app_restricted" msgid="7569077654579299326">"con restricción"</string>
-    <string name="data_usage_disable_mobile" msgid="4125335076749119451">"¿Desactivar los datos móviles?"</string>
+    <string name="data_usage_disable_mobile" msgid="4125335076749119451">"¿Desactivar datos móviles?"</string>
     <string name="data_usage_disable_mobile_limit" msgid="1937796699758613667">"Limitar datos móviles"</string>
     <string name="data_usage_disable_4g_limit" msgid="7131367986548147266">"Limitar datos 4G"</string>
     <string name="data_usage_disable_3g_limit" msgid="6746819313032692220">"Limitar datos 2G-3G"</string>
@@ -2706,11 +2711,11 @@
     <string name="data_usage_cycle_editor_title" msgid="4967309390043599889">"Elige el día en el que empezará cada ciclo"</string>
     <string name="data_usage_cycle_editor_subtitle" msgid="6043098041946166597">"Día de cada mes:"</string>
     <string name="data_usage_cycle_editor_positive" msgid="9155752056537811646">"Establecer"</string>
-    <string name="data_usage_warning_editor_title" msgid="1431385383278389290">"Establecer advertencia de uso de datos"</string>
-    <string name="data_usage_limit_editor_title" msgid="1687908662154108293">"Limitar uso de datos"</string>
+    <string name="data_usage_warning_editor_title" msgid="1431385383278389290">"Establece la advertencia de uso de datos"</string>
+    <string name="data_usage_limit_editor_title" msgid="1687908662154108293">"Limita el uso de datos"</string>
     <string name="data_usage_limit_dialog_title" msgid="8804760847110131518">"Limitar uso de datos"</string>
-    <string name="data_usage_limit_dialog_mobile" product="tablet" msgid="2000713577999830647">"El tablet desactivará los datos móviles cuando se alcance el límite establecido.\n\nSe tiene en cuenta el uso de datos medido por el tablet, aunque tu operador podría registrarlo de forma diferente. Por tanto, debes ser prudente al establecer un límite."</string>
-    <string name="data_usage_limit_dialog_mobile" product="default" msgid="943546278705619205">"El teléfono desactivará los datos móviles cuando se alcance el límite establecido.\n\nSe tiene en cuenta el uso de datos medido por el teléfono, aunque tu operador podría registrarlo de forma diferente. Por tanto, debes ser prudente al establecer un límite."</string>
+    <string name="data_usage_limit_dialog_mobile" product="tablet" msgid="2000713577999830647">"El tablet desactivará los datos móviles cuando se alcance el límite establecido.\n\nComo el uso de datos lo calcula el tablet y es posible que tu operador lo mida de forma diferente, se recomienda establecer un límite conservador."</string>
+    <string name="data_usage_limit_dialog_mobile" product="default" msgid="943546278705619205">"El teléfono desactivará los datos móviles cuando se alcance el límite establecido.\n\nComo el uso de datos lo calcula el teléfono y es posible que tu operador lo mida de forma diferente, se recomienda establecer un límite conservador."</string>
     <string name="data_usage_restrict_background_title" msgid="3568746530413220844">"¿Restringir datos en segundo plano?"</string>
     <string name="data_usage_restrict_background" msgid="995811034744808575">"Si restringes el uso de datos en segundo plano móviles, algunas aplicaciones y servicios no funcionarán si no tienes conexión a una red Wi‑Fi."</string>
     <string name="data_usage_restrict_background_multiuser" product="tablet" msgid="6032810839234864814">"Si restringes el uso de datos en segundo plano, algunas aplicaciones y servicios no funcionarán si no tienes conexión a una red Wi‑Fi.\n\nEsta configuración afecta a todos los usuarios del tablet."</string>
@@ -2763,15 +2768,15 @@
     <string name="vpn_done" msgid="6314426362224527349">"Cerrar"</string>
     <string name="vpn_save" msgid="1332625259182278316">"Guardar"</string>
     <string name="vpn_connect" msgid="772295154834334710">"Conectar"</string>
-    <string name="vpn_replace" msgid="7818130465019803404">"Sustituir"</string>
+    <string name="vpn_replace" msgid="7818130465019803404">"Reemplazar"</string>
     <string name="vpn_edit" msgid="7284861108584255618">"Editar perfil de VPN"</string>
     <string name="vpn_forget" msgid="7662717604542624887">"Olvidar"</string>
     <string name="vpn_connect_to" msgid="7926776854873218762">"Conectar a <xliff:g id="PROFILE">%s</xliff:g>"</string>
     <string name="vpn_disconnect_confirm" msgid="3505111947735651082">"¿Desconectar esta VPN?"</string>
     <string name="vpn_disconnect" msgid="4625914562388652486">"Desconectar"</string>
     <string name="vpn_version" msgid="2006792987077940456">"Versión <xliff:g id="VERSION">%s</xliff:g>"</string>
-    <string name="vpn_forget_long" msgid="8457511440635534478">"Borrar VPN"</string>
-    <string name="vpn_replace_vpn_title" msgid="8517436922021598103">"¿Sustituir VPN actual?"</string>
+    <string name="vpn_forget_long" msgid="8457511440635534478">"Olvidar VPN"</string>
+    <string name="vpn_replace_vpn_title" msgid="8517436922021598103">"¿Reemplazar VPN actual?"</string>
     <string name="vpn_set_vpn_title" msgid="6483554732067951052">"¿Configurar el modo de VPN siempre activada?"</string>
     <string name="vpn_first_always_on_vpn_message" msgid="7050017738816963855">"Si esta opción está activada, no tendrás acceso a Internet hasta que se conecte la red VPN"</string>
     <string name="vpn_replace_always_on_vpn_enable_message" msgid="4149931501300203205">"La nueva red VPN sustituirá a la actual y no tendrás acceso a Internet hasta que dicha VPN se conecte"</string>
@@ -2868,7 +2873,7 @@
     <string name="user_add_user_message_long" msgid="686637203224195465">"Puedes compartir este dispositivo si creas más usuarios. Cada uno tendrá su propio espacio y podrá personalizarlo con aplicaciones, un fondo de pantalla y mucho más. Los usuarios también pueden ajustar opciones del dispositivo, como la conexión Wi‑Fi, que afectan a todos los usuarios.\n\nCuando añadas un usuario, tendrá que configurar su espacio.\n\nCualquier usuario puede actualizar aplicaciones de todos los usuarios. Es posible que no se transfieran los servicios y opciones de accesibilidad al nuevo usuario."</string>
     <string name="user_add_user_message_short" msgid="1802594476285458254">"Al añadir un usuario nuevo, este debe configurar su espacio.\n\nCualquier usuario puede actualizar las aplicaciones del resto de usuarios."</string>
     <string name="user_setup_dialog_title" msgid="6748950002206392396">"¿Configurar usuario ahora?"</string>
-    <string name="user_setup_dialog_message" msgid="2988559933258353919">"Asegúrate de que la persona pueda acceder al dispositivo y configurar su espacio."</string>
+    <string name="user_setup_dialog_message" msgid="2988559933258353919">"Asegúrate de que la persona está disponible en este momento para usar el dispositivo y configurar su espacio."</string>
     <string name="user_setup_profile_dialog_message" msgid="7611900802824048526">"¿Quieres configurar un perfil ahora?"</string>
     <string name="user_setup_button_setup_now" msgid="4941459406266856176">"Configurar ahora"</string>
     <string name="user_setup_button_setup_later" msgid="6596031428556518752">"Ahora no"</string>
@@ -2883,7 +2888,7 @@
     <string name="user_confirm_remove_self_title" msgid="6739480453680217543">"¿Eliminarte a ti mismo?"</string>
     <string name="user_confirm_remove_title" msgid="1034498514019462084">"¿Eliminar este usuario?"</string>
     <string name="user_profile_confirm_remove_title" msgid="6138684743385947063">"¿Quitar este perfil?"</string>
-    <string name="work_profile_confirm_remove_title" msgid="3168910958076735800">"¿Eliminar perfil de trabajo?"</string>
+    <string name="work_profile_confirm_remove_title" msgid="3168910958076735800">"¿Quitar perfil de trabajo?"</string>
     <string name="user_confirm_remove_self_message" product="tablet" msgid="2889456786320157545">"Perderás tu espacio y tus datos en este tablet. Esta acción no se puede deshacer."</string>
     <string name="user_confirm_remove_self_message" product="default" msgid="8441729423565705183">"Perderás tu espacio y tus datos en este teléfono. Esta acción no se puede deshacer."</string>
     <string name="user_confirm_remove_message" msgid="5202150470271756013">"Se eliminarán todas las aplicaciones y datos"</string>
@@ -2919,8 +2924,8 @@
     <string name="nfc_payment_favor_default" msgid="7555356982142464260">"Siempre"</string>
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Excepto si hay otra aplicación de pago abierta"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"En terminales Toca y paga, pagar con:"</string>
-    <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Pago en terminal"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Configura una aplicación de pago. A continuación, solo tienes que sostener la parte trasera del teléfono sobre cualquier terminal con el símbolo de pago sin contacto."</string>
+    <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Cómo pagar en el terminal"</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Configura una aplicación de pago. A continuación, solo tienes que sostener la parte trasera del teléfono sobre cualquier terminal con el símbolo de pago contactless."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"Entendido"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"Más..."</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"¿Establecer como preferencia?"</string>
@@ -2931,7 +2936,7 @@
     <string name="restriction_menu_change_pin" msgid="592512748243421101">"Cambiar PIN"</string>
     <string name="app_notifications_switch_label" msgid="670683308275498821">"Mostrar notificaciones"</string>
     <string name="help_label" msgid="1296484776243905646">"Ayuda y sugerencias"</string>
-    <string name="support_summary" msgid="3278943815956130740">"Artículos de ayuda, teléfono y chat, y cómo empezar"</string>
+    <string name="support_summary" msgid="3278943815956130740">"Artículos de ayuda, teléfono y chat, cómo empezar"</string>
     <string name="user_account_title" msgid="2108666882630552859">"Cuenta para contenido"</string>
     <string name="user_picture_title" msgid="6664602422948159123">"ID de foto"</string>
     <string name="extreme_threats_title" msgid="1405820547540456436">"Amenazas extremas"</string>
@@ -3003,7 +3008,7 @@
     <string name="sim_editor_color" msgid="373059962306191123">"Color de la SIM"</string>
     <string name="sim_card_select_title" msgid="4925862525985187946">"Selecciona una tarjeta SIM"</string>
     <string name="color_orange" msgid="3159707916066563431">"Naranja"</string>
-    <string name="color_purple" msgid="4391440966734810713">"Violeta"</string>
+    <string name="color_purple" msgid="4391440966734810713">"Morado"</string>
     <string name="sim_no_inserted_msg" msgid="1197884607569714609">"No se ha insertado ninguna tarjeta SIM"</string>
     <string name="sim_status_title" msgid="4483653750844520871">"Estado de la SIM"</string>
     <string name="sim_status_title_sim_slot" msgid="416005570947546124">"Estado de la SIM (ranura SIM %1$d)"</string>
@@ -3033,7 +3038,7 @@
     <string name="connected_devices_dashboard_title" msgid="7795222675849060444">"Dispositivos conectados"</string>
     <string name="connected_devices_dashboard_summary" msgid="1072664369515033179">"Bluetooth, modo de conducción, NFC"</string>
     <string name="connected_devices_dashboard_no_nfc_summary" msgid="2610085597733526722">"Bluetooth, modo de conducción"</string>
-    <string name="connected_devices_dashboard_no_driving_mode_summary" msgid="3524409078596318803">"Bluetooth y NFC"</string>
+    <string name="connected_devices_dashboard_no_driving_mode_summary" msgid="3524409078596318803">"Bluetooth, NFC"</string>
     <string name="connected_devices_dashboard_no_driving_mode_no_nfc_summary" msgid="7881286613528299400">"Bluetooth"</string>
     <string name="app_and_notification_dashboard_title" msgid="8448096608058843730">"Aplicaciones y notificaciones"</string>
     <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"Asistente, aplicaciones recientes y aplicaciones predeterminadas"</string>
@@ -3041,7 +3046,7 @@
     <string name="account_dashboard_title" msgid="4734300939532555885">"Cuentas"</string>
     <string name="account_dashboard_default_summary" msgid="6822549669771936206">"No se ha añadido ninguna cuenta"</string>
     <string name="app_default_dashboard_title" msgid="6575301028225232193">"Aplicaciones predeterminadas"</string>
-    <string name="system_dashboard_summary" msgid="6582464466735779394">"Idiomas, gestos, hora y copias de seguridad"</string>
+    <string name="system_dashboard_summary" msgid="6582464466735779394">"Idiomas, gestos, hora, copias de seguridad"</string>
     <string name="search_results_title" msgid="4160717656435503940">"Ajustes"</string>
     <string name="keywords_wifi" msgid="8477688080895466846">"wifi, wi‑fi, conexión de red, internet, inalámbrica, datos, wi fi"</string>
     <string name="keywords_wifi_notify_open_networks" msgid="1031260564121854773">"Notificación Wi‑Fi, notificación Wi‑Fi"</string>
@@ -3125,7 +3130,7 @@
     <string name="keywords_battery_saver_sticky" msgid="8733804259716284872">"ahorro de batería, batería fija, duradera, ahorro de batería, batería"</string>
     <string name="default_sound" msgid="6675629744816442953">"Sonido predeterminado"</string>
     <string name="sound_settings_summary" msgid="8467549670633195109">"Volumen del tono de llamada al <xliff:g id="PERCENTAGE">%1$s</xliff:g>"</string>
-    <string name="sound_dashboard_summary" msgid="5187301919242823508">"Volumen, vibración y No molestar"</string>
+    <string name="sound_dashboard_summary" msgid="5187301919242823508">"Volumen, vibración, No molestar"</string>
     <string name="sound_settings_summary_vibrate" msgid="2194491116884798590">"Timbre en vibración"</string>
     <string name="sound_settings_summary_silent" msgid="899823817462768876">"Timbre en silencio"</string>
     <string name="sound_settings_example_summary" msgid="2091822107298841827">"Volumen del tono de llamada al 80 %"</string>
@@ -3135,7 +3140,7 @@
     <string name="alarm_volume_option_title" msgid="3184076022438477047">"Volumen de alarma"</string>
     <string name="ring_volume_option_title" msgid="2038924918468372264">"Volumen del tono"</string>
     <string name="notification_volume_option_title" msgid="1358512611511348260">"Volumen de notificaciones"</string>
-    <string name="ringtone_title" msgid="1409086028485922583">"Tono del teléfono"</string>
+    <string name="ringtone_title" msgid="1409086028485922583">"Tono de llamada del teléfono"</string>
     <string name="notification_ringtone_title" msgid="2932960620843976285">"Sonido de notificación predeterminado"</string>
     <string name="notification_unknown_sound_title" msgid="8043718667804838398">"Sonido proporcionado de app"</string>
     <string name="notification_sound_default" msgid="2664544380802426260">"Sonido de notificación predeterminado"</string>
@@ -3157,7 +3162,7 @@
     <string name="emergency_tone_vibrate" msgid="5020068066905681181">"Vibraciones"</string>
     <string name="boot_sounds_title" msgid="7583926202411353620">"Sonidos de encendido"</string>
     <string name="live_caption_title" msgid="7926591158657997051">"Subtítulos instantáneos"</string>
-    <string name="live_caption_summary" msgid="9064771862352393125">"Subtítulos automáticos de multimedia"</string>
+    <string name="live_caption_summary" msgid="9064771862352393125">"Subtitula automáticamente el contenido multimedia"</string>
     <string name="zen_mode_settings_summary_off" msgid="6929319200478424962">"Nunca"</string>
     <plurals name="zen_mode_settings_summary_on" formatted="false" msgid="6061723291126091396">
       <item quantity="other"><xliff:g id="ON_COUNT">%d</xliff:g> habilitadas</item>
@@ -3196,7 +3201,7 @@
     <string name="zen_mode_restrict_notifications_mute_footer" msgid="3049522809520549054">"Cuando recibas notificaciones, tu teléfono no sonará ni vibrará."</string>
     <string name="zen_mode_restrict_notifications_hide" msgid="3296933643539682552">"Notificaciones sin sonido ni elementos visuales"</string>
     <string name="zen_mode_restrict_notifications_hide_summary" msgid="1449301153755270168">"No verás ni escucharás notificaciones"</string>
-    <string name="zen_mode_restrict_notifications_hide_footer" msgid="7617688597593946765">"Las notificaciones no se mostrarán ni harán que el teléfono suene o vibre. Recuerda que las notificaciones críticas sobre la actividad y el estado del teléfono se seguirán mostrando.\n\nCuando desactives el modo No molestar, podrás deslizar el dedo desde la parte superior de la pantalla para leer las notificaciones que no hayas visto."</string>
+    <string name="zen_mode_restrict_notifications_hide_footer" msgid="7617688597593946765">"Las notificaciones no se mostrarán ni harán que el teléfono suene o vibre. Recuerda que las notificaciones críticas sobre la actividad y el estado del teléfono se seguirán mostrando.\n\nCuando desactives el modo No molestar, desliza el dedo desde la parte superior de la pantalla para leer las notificaciones que no hayas visto."</string>
     <string name="zen_mode_restrict_notifications_custom" msgid="3167252482570424133">"Personalizado"</string>
     <string name="zen_mode_restrict_notifications_enable_custom" msgid="6376983315529894440">"Habilitar configuración personalizada"</string>
     <string name="zen_mode_restrict_notifications_disable_custom" msgid="8004212081465043044">"Quitar configuración personalizada"</string>
@@ -3209,8 +3214,8 @@
     <string name="zen_mode_block_effect_sound" msgid="1499243540186357631">"Silenciar sonido y vibración"</string>
     <string name="zen_mode_block_effect_intent" msgid="5666951244667422668">"No encender la pantalla"</string>
     <string name="zen_mode_block_effect_light" msgid="8679333758037487644">"No hacer parpadear la luz"</string>
-    <string name="zen_mode_block_effect_peek" msgid="6075662813575910221">"No mostrar notificaciones en pantalla"</string>
-    <string name="zen_mode_block_effect_status" msgid="6516614225115681068">"Ocultar iconos de la barra de estado en la parte superior de la pantalla"</string>
+    <string name="zen_mode_block_effect_peek" msgid="6075662813575910221">"No mostrar notificaciones en la pantalla"</string>
+    <string name="zen_mode_block_effect_status" msgid="6516614225115681068">"Ocultar iconos de la barra de estado superior"</string>
     <string name="zen_mode_block_effect_badge" msgid="3891743027347075136">"Ocultar puntos de notificación en los iconos de las aplicaciones"</string>
     <string name="zen_mode_block_effect_ambient" msgid="6382013125863616197">"No activar con notificaciones"</string>
     <string name="zen_mode_block_effect_list" msgid="6081548478844912181">"Ocultar de la lista de notificaciones"</string>
@@ -3235,8 +3240,8 @@
     <string name="zen_mode_settings_dnd_custom_settings_footer_link" msgid="4007974052885089379"><annotation id="link">" Ver ajustes personalizados"</annotation></string>
     <string name="zen_interruption_level_priority" msgid="9178419297408319234">"Solo interrupciones prioritarias"</string>
     <string name="zen_mode_and_condition" msgid="4123722186007123567">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
-    <string name="zen_mode_sound_summary_on_with_info" msgid="2539952366467518398">"Activado/<xliff:g id="ID_1">%1$s</xliff:g>"</string>
-    <string name="zen_mode_sound_summary_off_with_info" msgid="3910718455243440265">"Desactivado/<xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="zen_mode_sound_summary_on_with_info" msgid="2539952366467518398">"Activado / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="zen_mode_sound_summary_off_with_info" msgid="3910718455243440265">"Desactivado / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="zen_mode_sound_summary_off" msgid="2800265178411749309">"Desactivado"</string>
     <string name="zen_mode_sound_summary_on" msgid="6964666541479146310">"Activado"</string>
     <string name="zen_mode_duration_summary_always_prompt" msgid="7642321938427056823">"Preguntar siempre (a menos que se haya activado automáticamente)"</string>
@@ -3282,8 +3287,8 @@
     <string name="work_notification_ringtone_title" msgid="8059159087214025757">"Sonido de notificación de trabajo predeterminado"</string>
     <string name="work_alarm_ringtone_title" msgid="5328487181385375130">"Sonido de alarma de trabajo predeterminado"</string>
     <string name="work_sound_same_as_personal" msgid="7728560881697159758">"Igual que el perfil personal"</string>
-    <string name="work_sync_dialog_title" msgid="4799120971202956837">"¿Sustituir sonidos?"</string>
-    <string name="work_sync_dialog_yes" msgid="2110726233746476066">"Sustituir"</string>
+    <string name="work_sync_dialog_title" msgid="4799120971202956837">"¿Reemplazar sonidos?"</string>
+    <string name="work_sync_dialog_yes" msgid="2110726233746476066">"Reemplazar"</string>
     <string name="work_sync_dialog_message" msgid="944233463059129156">"Se utilizarán los sonidos de tu perfil personal en tu perfil de trabajo"</string>
     <string name="ringtones_install_custom_sound_title" msgid="210551218424553671">"¿Añadir sonido personalizado?"</string>
     <string name="ringtones_install_custom_sound_content" msgid="6683649115132255452">"Este archivo se copiará en la carpeta <xliff:g id="FOLDER_NAME">%s</xliff:g>"</string>
@@ -3417,7 +3422,7 @@
     <string name="notification_content_block_summary" msgid="2743896875255591743">"No mostrar nunca notificaciones en el panel de notificaciones ni en dispositivos periféricos"</string>
     <string name="notification_badge_title" msgid="8989086619255666442">"Permitir burbuja de notificación"</string>
     <string name="notification_channel_badge_title" msgid="8228215248332054612">"Mostrar burbuja de notificación"</string>
-    <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"Omitir No molestar"</string>
+    <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"Ignorar modo No molestar"</string>
     <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"Permitir notificaciones cuando el modo No molestar esté activado"</string>
     <string name="app_notification_visibility_override_title" msgid="2349335170165637672">"En la pantalla de bloqueo"</string>
     <string name="app_notification_row_banned" msgid="2079325338122151677">"Bloqueada"</string>
@@ -3438,7 +3443,7 @@
     <string name="zen_mode_add_time_rule" msgid="5999467757140524729">"Añadir programación horaria"</string>
     <string name="zen_mode_delete_rule" msgid="2292933835997203801">"Eliminar programación"</string>
     <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"Elige un tipo de programación"</string>
-    <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"¿Quieres eliminar la regla \"<xliff:g id="RULE">%1$s</xliff:g>\"?"</string>
+    <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"¿Eliminar regla \"<xliff:g id="RULE">%1$s</xliff:g>\"?"</string>
     <string name="zen_mode_delete_rule_button" msgid="611058106279881991">"Eliminar"</string>
     <string name="zen_mode_rule_type_unknown" msgid="2819480113355191421">"Desconocida"</string>
     <string name="zen_mode_app_set_behavior" msgid="8597398780262575571">"Estas opciones no se pueden modificar en este momento. Una aplicación (<xliff:g id="APP_NAME">%1$s</xliff:g>) ha activado automáticamente el modo No molestar con funcionamiento personalizado."</string>
@@ -3464,10 +3469,10 @@
     <string name="zen_mode_schedule_rule_days_none" msgid="6011716195119389956">"Ninguno"</string>
     <string name="zen_mode_schedule_rule_days_all" msgid="8814173364016139675">"Todos los días"</string>
     <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"La alarma puede anular la hora de finalización"</string>
-    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"La programación se desactiva cuando suena una alarma"</string>
+    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"La programación se desactiva si suena una alarma"</string>
     <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"Comportamiento del modo No molestar"</string>
     <string name="zen_mode_custom_behavior_summary_default" msgid="3509865340195397447">"Usar configuración predeterminada"</string>
-    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"Crear opciones de configuración personalizadas para esta programación"</string>
+    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"Crear ajustes personalizados para esta programación"</string>
     <string name="zen_mode_custom_behavior_category_title" msgid="7451686525113262087">"En la programación \"<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>\""</string>
     <string name="summary_divider_text" msgid="4780683204694442666">", "</string>
     <string name="summary_range_symbol_combination" msgid="6038631664844488406">"<xliff:g id="START">%1$s</xliff:g>-<xliff:g id="END">%2$s</xliff:g>"</string>
@@ -3754,12 +3759,12 @@
     <string name="background_check_pref" msgid="664081406854758392">"Comprobación de uso en segundo plano"</string>
     <string name="background_check_title" msgid="4136736684290307970">"Acceso completo en segundo plano"</string>
     <string name="assist_access_context_title" msgid="2274614501747710439">"Usar texto de la pantalla"</string>
-    <string name="assist_access_context_summary" msgid="5867997494395842785">"Permitir que la aplicación de asistencia acceda a los contenidos de la pantalla (como texto)"</string>
+    <string name="assist_access_context_summary" msgid="5867997494395842785">"Permite que la aplicación de asistencia acceda a los contenidos de la pantalla como texto"</string>
     <string name="assist_access_screenshot_title" msgid="1991014038776117688">"Usar captura de pantalla"</string>
-    <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Permitir que la aplicación de asistencia acceda a una imagen de la pantalla"</string>
+    <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Permite que la aplicación de asistencia acceda a una imagen de la pantalla"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"Parpadear la pantalla"</string>
-    <string name="assist_flash_summary" msgid="6697095786317559129">"Hacer parpadear los bordes de la pantalla cuando la aplicación de asistencia acceda al texto de una pantalla o una captura de pantalla"</string>
-    <string name="assist_footer" msgid="7030121180457472165">"Las aplicaciones de asistencia te ayudan según la información que aparece en la pantalla. Algunas aplicaciones admiten tanto el launcher como los servicios de entrada de voz para ofrecerte asistencia integrada."</string>
+    <string name="assist_flash_summary" msgid="6697095786317559129">"Los bordes de la pantalla parpadearán cuando la aplicación de asistencia acceda al texto de una pantalla o una captura de pantalla"</string>
+    <string name="assist_footer" msgid="7030121180457472165">"Las aplicaciones de asistencia te ayudan según la información que aparezca en la pantalla. Algunas aplicaciones admiten tanto el launcher como los servicios de entrada de voz para ofrecerte asistencia integrada."</string>
     <string name="average_memory_use" msgid="5333366040118953945">"Uso medio de memoria"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"Uso máximo de memoria"</string>
     <string name="memory_usage" msgid="7963253555330830906">"Uso de memoria"</string>
@@ -3857,7 +3862,7 @@
     <string name="storage_summary_with_sdcard" msgid="8742907204848352697">"Almacenamiento interno: <xliff:g id="PERCENTAGE">%1$s</xliff:g> usado (<xliff:g id="FREE_SPACE">%2$s</xliff:g> disponible)"</string>
     <string name="display_summary" msgid="5725269449657325797">"Suspender después de <xliff:g id="TIMEOUT_DESCRIPTION">%1$s</xliff:g> de inactividad"</string>
     <string name="display_dashboard_summary" msgid="7678566148167010682">"Fondo de pantalla, suspensión, tamaño de la fuente"</string>
-    <string name="display_dashboard_summary_with_style" msgid="8981059474501210956">"Estilos y fondos de pantalla, suspensión y tamaño de fuente"</string>
+    <string name="display_dashboard_summary_with_style" msgid="8981059474501210956">"Estilos y fondos de pantalla, suspensión, tamaño de fuente"</string>
     <string name="display_dashboard_nowallpaper_summary" msgid="8612534364908229000">"Tamaño de letra en la pantalla de suspensión"</string>
     <string name="display_summary_example" msgid="4555020581960719296">"Suspender después de 10 minutos de inactividad"</string>
     <string name="memory_summary" msgid="9121871336058042600">"Se está usando una media de <xliff:g id="USED_MEMORY">%1$s</xliff:g> de <xliff:g id="TOTAL_MEMORY">%2$s</xliff:g> de memoria"</string>
@@ -3952,7 +3957,7 @@
     <string name="data_used_template" msgid="761605393453849477">"<xliff:g id="ID_1">%1$s</xliff:g> usados"</string>
     <string name="set_data_warning" msgid="8115980184415563941">"Establecer advertencia de datos"</string>
     <string name="data_warning" msgid="2699207195535036240">"Advertencia de datos"</string>
-    <string name="data_warning_footnote" msgid="965724845580257305">"La advertencia y el límite de datos se basan en los cálculos del dispositivo y es posible que no coincidan con los datos del operador."</string>
+    <string name="data_warning_footnote" msgid="965724845580257305">"La advertencia y el límite de datos se basan en los cálculos del dispositivo, así que es posible que no coincidan con los datos del operador."</string>
     <string name="set_data_limit" msgid="5043770023229990674">"Establecer límite de datos"</string>
     <string name="data_limit" msgid="5793521160051596228">"Límite de datos"</string>
     <string name="data_usage_template" msgid="6848274347956096882">"<xliff:g id="ID_1">%1$s</xliff:g> usados (<xliff:g id="ID_2">%2$s</xliff:g>)"</string>
@@ -3997,7 +4002,7 @@
     <string name="suggestion_additional_fingerprints" msgid="3434467207282466411">"Añadir otra huella digital"</string>
     <string name="suggestion_additional_fingerprints_summary" msgid="1916547587832484196">"Desbloquear con un dedo diferente"</string>
     <string name="battery_saver_on_summary" msgid="6841062406467435672">"Activado"</string>
-    <string name="battery_saver_off_scheduled_summary" msgid="3740414764069188669">"Se activará cuando esté al <xliff:g id="BATTERY_PERCENTAGE">%1$s</xliff:g>"</string>
+    <string name="battery_saver_off_scheduled_summary" msgid="3740414764069188669">"Se activará cuando la batería esté al <xliff:g id="BATTERY_PERCENTAGE">%1$s</xliff:g>"</string>
     <string name="battery_saver_off_summary" msgid="8736555723004299721">"Desactivado"</string>
     <string name="battery_saver_button_turn_on" msgid="3748696527267573793">"Activar ahora"</string>
     <string name="battery_saver_button_turn_off" msgid="2912950982503267828">"Desactivar"</string>
@@ -4005,7 +4010,7 @@
     <string name="lockscreen_remote_input" msgid="3363310613165354434">"Si el dispositivo está bloqueado, evitar que se escriban respuestas u otros textos en las notificaciones"</string>
     <string name="default_spell_checker" msgid="8636661093243189533">"Corrector predeterminado"</string>
     <string name="choose_spell_checker" msgid="7619860861923582868">"Elige corrector ortográfico"</string>
-    <string name="spell_checker_master_switch_title" msgid="5712693172227400668">"Usar el corrector ortográfico"</string>
+    <string name="spell_checker_master_switch_title" msgid="5712693172227400668">"Usar corrector ortográfico"</string>
     <string name="spell_checker_not_selected" msgid="331034541988255137">"No seleccionado"</string>
     <string name="notification_log_no_title" msgid="3668232437235348628">"(ninguno)"</string>
     <string name="notification_log_details_delimiter" msgid="5485526744689532908">": "</string>
@@ -4057,7 +4062,7 @@
     <string name="button_confirm_convert_fbe" msgid="419832223125147297">"Borrar y convertir"</string>
     <string name="reset_shortcut_manager_throttling" msgid="1912184636360233397">"Restablecer límite de frecuencia de ShortcutManager"</string>
     <string name="reset_shortcut_manager_throttling_complete" msgid="2932990541160593632">"Se ha restablecido el límite de frecuencia de ShortcutManager"</string>
-    <string name="notification_suggestion_title" msgid="3292107671498148560">"Controlar los datos que aparecen en la pantalla de bloqueo"</string>
+    <string name="notification_suggestion_title" msgid="3292107671498148560">"Controla los datos que aparecen en la pantalla de bloqueo"</string>
     <string name="notification_suggestion_summary" msgid="6516827892359614597">"Mostrar u ocultar contenido de las notificaciones"</string>
     <string name="page_tab_title_summary" msgid="4824744863994538006">"Todo"</string>
     <string name="page_tab_title_support" msgid="5569262185010367870">"Ayuda y consejos"</string>
@@ -4101,7 +4106,7 @@
     <string name="automatic_storage_manager_master_switch_title" msgid="1456978117739582562">"Utilizar el Administrador de Almacenamiento"</string>
     <string name="deletion_helper_automatic_title" msgid="4370975149425263205">"Automático"</string>
     <string name="deletion_helper_manual_title" msgid="1011785013431162078">"Manual"</string>
-    <string name="deletion_helper_preference_title" msgid="797270307034242206">"Liberar espacio"</string>
+    <string name="deletion_helper_preference_title" msgid="797270307034242206">"Liberar espacio ahora"</string>
     <string name="gesture_preference_title" msgid="583646591518373785">"Gestos"</string>
     <string name="gesture_preference_summary" product="default" msgid="2990736567599191163">"Gestos rápidos para controlar el teléfono"</string>
     <string name="gesture_preference_summary" product="tablet" msgid="8303793594714075580">"Gestos rápidos para controlar el tablet"</string>
@@ -4115,9 +4120,9 @@
     <string name="swipe_up_to_switch_apps_summary" msgid="4644068184114154787">"Para cambiar de aplicación, desliza el dedo hacia arriba sobre el botón de inicio. Vuelve a deslizarlo hacia arriba para ver todas las aplicaciones. Funciona en cualquier pantalla. El botón Aplicaciones recientes ya no aparecerá en la parte inferior derecha."</string>
     <string name="swipe_up_to_switch_apps_suggestion_title" msgid="7641846365137536128">"Prueba el nuevo botón de inicio"</string>
     <string name="swipe_up_to_switch_apps_suggestion_summary" msgid="7338653224520387852">"Activa el nuevo gesto para cambiar de aplicación"</string>
-    <string name="ambient_display_title" product="default" msgid="6785677099744344088">"Tocar el teléfono dos veces para consultarlo"</string>
-    <string name="ambient_display_title" product="tablet" msgid="1106285490888683613">"Tocar el tablet dos veces para comprobar notificaciones"</string>
-    <string name="ambient_display_title" product="device" msgid="5064644474876041478">"Tocar el dispositivo dos veces para comprobar notificaciones"</string>
+    <string name="ambient_display_title" product="default" msgid="6785677099744344088">"Doble toque para consultar el teléfono"</string>
+    <string name="ambient_display_title" product="tablet" msgid="1106285490888683613">"Doble toque para consultar el tablet"</string>
+    <string name="ambient_display_title" product="device" msgid="5064644474876041478">"Doble toque para consultar el dispositivo"</string>
     <string name="ambient_display_summary" msgid="4882910328216411109">"Toca la pantalla dos veces para consultar la hora, las notificaciones y otra información."</string>
     <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"Levantar el teléfono para consultarlo"</string>
     <string name="ambient_display_pickup_title" product="tablet" msgid="1555456400210301959">"Levantar el tablet para comprobar las notificaciones"</string>
@@ -4131,10 +4136,10 @@
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"Toca para comprobar el dispositivo"</string>
     <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"Para ver la hora, las notificaciones y otra información, toca la pantalla."</string>
     <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"Deslizar por el sensor de huellas para ver notificaciones"</string>
-    <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"Deslizar huella digital"</string>
-    <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"Para ver tus notificaciones, desliza el dedo hacia abajo en el sensor de huellas digitales situado en la parte trasera del teléfono."</string>
-    <string name="fingerprint_swipe_for_notifications_summary" product="tablet" msgid="3480057984564476283">"Para ver tus notificaciones, desliza el dedo hacia abajo en el sensor de huellas digitales situado en la parte trasera del tablet."</string>
-    <string name="fingerprint_swipe_for_notifications_summary" product="device" msgid="7950264130913070035">"Para ver tus notificaciones, desliza el dedo hacia abajo en el sensor de huellas digitales situado en la parte trasera del dispositivo."</string>
+    <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"Deslizar por sensor de huella digital"</string>
+    <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"Para ver tus notificaciones, desliza el dedo hacia abajo en el sensor de huellas digitales de la parte trasera del teléfono."</string>
+    <string name="fingerprint_swipe_for_notifications_summary" product="tablet" msgid="3480057984564476283">"Para ver tus notificaciones, desliza el dedo hacia abajo en el sensor de huellas digitales de la parte trasera del tablet."</string>
+    <string name="fingerprint_swipe_for_notifications_summary" product="device" msgid="7950264130913070035">"Para ver tus notificaciones, desliza el dedo hacia abajo en el sensor de huellas digitales de la parte trasera del dispositivo."</string>
     <string name="fingerprint_swipe_for_notifications_suggestion_title" msgid="948946491233738823">"Ver las notificaciones más rápido"</string>
     <string name="gesture_setting_on" msgid="7573680730101327866">"Activado"</string>
     <string name="gesture_setting_off" msgid="2540159841716890511">"Desactivado"</string>
@@ -4155,7 +4160,7 @@
     <string name="auto_sync_account_title" msgid="2394463123733529506">"Sincronizar datos automáticamente"</string>
     <string name="auto_sync_personal_account_title" msgid="6844465157916100655">"Sincronizar datos personales automáticamente"</string>
     <string name="auto_sync_work_account_title" msgid="2403222633447522376">"Sincronizar datos del trabajo automáticamente"</string>
-    <string name="auto_sync_account_summary" msgid="6316230976974033772">"Permitir que las aplicaciones actualicen los datos automáticamente"</string>
+    <string name="auto_sync_account_summary" msgid="6316230976974033772">"Permite que las aplicaciones actualicen los datos automáticamente"</string>
     <string name="account_sync_title" msgid="1570164819114297154">"Sincronización"</string>
     <string name="account_sync_summary_some_on" msgid="1934556869158274053">"Sincronización activada para <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g> elementos"</string>
     <string name="account_sync_summary_all_on" msgid="3634161204232431700">"Sincronización activada para todos los elementos"</string>
@@ -4246,7 +4251,7 @@
     <string name="app_info_storage_title" msgid="6643391804949509308">"Espacio usado"</string>
     <string name="webview_uninstalled_for_user" msgid="3407952144444040557">"(opción desinstalada para <xliff:g id="USER">%s</xliff:g>)"</string>
     <string name="webview_disabled_for_user" msgid="8057805373224993504">"(opción inhabilitada para <xliff:g id="USER">%s</xliff:g>)"</string>
-    <string name="autofill_app" msgid="3990765434980280073">"Servicio Autocompletar"</string>
+    <string name="autofill_app" msgid="3990765434980280073">"Autocompletar"</string>
     <string name="autofill_keywords" msgid="7717726766232862218">"automático, completar, autocompletar"</string>
     <string name="autofill_confirmation_message" msgid="1385894598730361304">"&lt;b&gt;Asegúrate de que confías en esta aplicación&lt;/b&gt; &lt;br/&gt; &lt;br/&gt; &lt;xliff:g id=app_name example=Autocompletar de Google&gt;%1$s&lt;/xliff:g&gt; utiliza el contenido que se muestra en la pantalla para determinar el texto que se puede autocompletar."</string>
     <string name="debug_autofill_category" msgid="6262526615416295645">"Autocompletar"</string>
@@ -4302,7 +4307,7 @@
     <string name="unknown_unavailability_setting_summary" msgid="5785931810977403534">"La opción no está disponible"</string>
     <string name="my_device_info_account_preference_title" msgid="7965847995028952373">"Cuenta"</string>
     <string name="my_device_info_device_name_preference_title" msgid="7384446683248009296">"Nombre del dispositivo"</string>
-    <string name="change_wifi_state_title" msgid="5140754955787584174">"Control de la conexión Wi‑Fi"</string>
+    <string name="change_wifi_state_title" msgid="5140754955787584174">"Control de Wi‑Fi"</string>
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"Permitir que la aplicación controle la conexión Wi‑Fi"</string>
     <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"Permitir que esta aplicación active o desactive la conexión Wi‑Fi, busque redes Wi‑Fi y se conecte a ellas, añada o quite redes o inicie un punto de acceso local"</string>
     <string name="media_output_title" msgid="8710632337456601848">"Reproducir contenido multimedia en"</string>
@@ -4334,7 +4339,7 @@
     <string name="homepage_personal_settings" msgid="7472638597249114564">"Sugerencias"</string>
     <string name="choose_network_title" msgid="3213314359630522396">"Elegir red"</string>
     <string name="network_disconnected" msgid="8677203031237141594">"Desconectado"</string>
-    <string name="network_connected" msgid="8197627827976712053">"Conectada"</string>
+    <string name="network_connected" msgid="8197627827976712053">"Conectado"</string>
     <string name="network_connecting" msgid="8798611458457547110">"Conectando…"</string>
     <string name="network_could_not_connect" msgid="552874922030763713">"No se ha podido conectar"</string>
     <string name="empty_networks_list" msgid="5170020017144403884">"No se ha encontrado ninguna red."</string>
@@ -4380,7 +4385,7 @@
     <string name="carrier_settings_title" msgid="7989949967020825268">"Ajustes del operador"</string>
     <string name="cdma_lte_data_service" msgid="8996857851150069339">"Configurar servicio de datos"</string>
     <string name="mobile_data_settings_title" msgid="3439626666647519547">"Datos móviles"</string>
-    <string name="mobile_data_settings_summary" msgid="6492798151325636912">"Acceder a los datos con la red móvil"</string>
+    <string name="mobile_data_settings_summary" msgid="6492798151325636912">"Acceder a datos con la red móvil"</string>
     <string name="mobile_data_settings_summary_auto_switch" msgid="3665863214578471494">"El teléfono cambiará automáticamente a este operador cuando esté en su rango"</string>
     <string name="calls_preference" msgid="2076353032705811243">"Preferencias de llamadas"</string>
     <string name="sms_preference" msgid="8449270011976880">"Preferencia de SMS"</string>
@@ -4418,9 +4423,9 @@
     <string name="mobile_network_erase_sim_dialog_progress" msgid="4881754030959536493">"Borrando SIM…"</string>
     <string name="mobile_network_erase_sim_error_dialog_title" msgid="9026625253242102706">"No se puede borrar la SIM"</string>
     <string name="mobile_network_erase_sim_error_dialog_body" msgid="5955463559366034787">"No se puede eliminar esta SIM debido a un error.\n\nReinicia el dispositivo y vuelve a intentarlo."</string>
-    <string name="preferred_network_mode_title" msgid="8324526359482124770">"Preferencia de tipo de red"</string>
+    <string name="preferred_network_mode_title" msgid="8324526359482124770">"Tipo de red preferido"</string>
     <string name="preferred_network_mode_summary" msgid="388957154320426335">"Cambiar el modo operativo de la red"</string>
-    <string name="preferred_network_mode_dialogtitle" msgid="5448698073828567428">"Preferencia de tipo de red"</string>
+    <string name="preferred_network_mode_dialogtitle" msgid="5448698073828567428">"Tipo de red preferido"</string>
     <string name="carrier_settings_euicc" msgid="7723199738771996732">"Operador"</string>
     <string name="carrier_settings_version" msgid="2657511289029828425">"Versión de Ajustes"</string>
     <string name="call_category" msgid="3418535202893644015">"Llamadas"</string>
@@ -4434,13 +4439,13 @@
     <string name="cdma_subscription_summary" msgid="2298861419202726628">"Cambiar entre RUIM/SIM y NV"</string>
     <string name="cdma_subscription_dialogtitle" msgid="232485231569225126">"suscripción"</string>
     <string name="register_automatically" msgid="1858081641661493109">"Registro automático…"</string>
-    <string name="roaming_alert_title" msgid="1849237823113454475">"¿Permitir la itinerancia de datos?"</string>
+    <string name="roaming_alert_title" msgid="1849237823113454475">"¿Permitir itinerancia de datos?"</string>
     <string name="roaming_check_price_warning" msgid="5883499714594419439">"Ponte en contacto con tu proveedor de red para consultar el precio."</string>
     <string name="mobile_data_usage_title" msgid="2376358672434990037">"Uso de datos de la aplicación"</string>
     <string name="mobile_network_mode_error" msgid="6818434186286086554">"El modo de red <xliff:g id="NETWORKMODEID">%1$d</xliff:g> no es válido. Ignorar."</string>
     <string name="mobile_network_apn_title" msgid="5628635067747404382">"Nombres de puntos de acceso"</string>
     <string name="manual_mode_disallowed_summary" msgid="799800630000340665">"No está disponible cuando se está conectado a <xliff:g id="CARRIER">%1$s</xliff:g>"</string>
-    <string name="emergency_info_contextual_card_summary" msgid="5541444321969803486">"Información médica y contactos de emergencia"</string>
+    <string name="emergency_info_contextual_card_summary" msgid="5541444321969803486">"Información médica, contactos de emergencia"</string>
     <string name="see_more" msgid="7463940160389802632">"Ver más"</string>
     <string name="see_less" msgid="3718892257002813387">"Ver menos"</string>
     <string name="network_connection_request_dialog_title" msgid="3150489262902506588">"Dispositivo para usar con <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
@@ -4466,13 +4471,13 @@
     <string name="hwui_force_dark_title" msgid="3744825212652331461">"Forzar el modo oscuro"</string>
     <string name="hwui_force_dark_summary" msgid="2051891908674765817">"Forzar el modo oscuro para que esté siempre activo"</string>
     <string name="privacy_dashboard_title" msgid="8764930992456607513">"Privacidad"</string>
-    <string name="privacy_dashboard_summary" msgid="7916431309860824945">"Permisos, actividad de la cuenta y datos personales"</string>
+    <string name="privacy_dashboard_summary" msgid="7916431309860824945">"Permisos, actividad de la cuenta, datos personales"</string>
     <string name="contextual_card_dismiss_remove" msgid="1750420285615827309">"Eliminar"</string>
     <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"Conservar"</string>
-    <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"¿Eliminar esta sugerencia?"</string>
+    <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"¿Quitar esta sugerencia?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"Sugerencia eliminada"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"Deshacer"</string>
-    <string name="low_storage_summary" msgid="4562224870189133400">"Queda poco espacio de almacenamiento. <xliff:g id="PERCENTAGE">%1$s</xliff:g> usado (disponible: <xliff:g id="FREE_SPACE">%2$s</xliff:g>)"</string>
+    <string name="low_storage_summary" msgid="4562224870189133400">"Queda poco espacio. <xliff:g id="PERCENTAGE">%1$s</xliff:g> usado - <xliff:g id="FREE_SPACE">%2$s</xliff:g> libre"</string>
     <string name="contextual_card_feedback_send" msgid="8698649023854350623">"Enviar comentarios"</string>
     <string name="contextual_card_feedback_confirm_message" msgid="3987973028353264878">"¿Te gustaría darnos tu opinión sobre esta sugerencia?"</string>
     <string name="copyable_slice_toast" msgid="1357518174923789947">"<xliff:g id="COPY_CONTENT">%1$s</xliff:g> se ha copiado en el portapapeles."</string>
diff --git a/tests/CarDeveloperOptions/res/values-et/arrays.xml b/tests/CarDeveloperOptions/res/values-et/arrays.xml
index 62ffe5d..b61fb65 100644
--- a/tests/CarDeveloperOptions/res/values-et/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-et/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"taustal käitamine"</item>
     <item msgid="6423861043647911030">"juurdepääsetavuse helitugevus"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Asukoht"</item>
+    <item msgid="6656077694190491067">"Asukoht"</item>
+    <item msgid="8790228218278477369">"Asukoht"</item>
+    <item msgid="7836406246005211990">"Vibratsioon"</item>
+    <item msgid="3951439024549922598">"Kontaktide lugemine"</item>
+    <item msgid="8802152411647068">"Kontaktide muutmine"</item>
+    <item msgid="229544934599698735">"Kõnelogi lugemine"</item>
+    <item msgid="7396102294405899613">"Kõnelogi muutmine"</item>
+    <item msgid="3597797992398484655">"Kalendri lugemine"</item>
+    <item msgid="2705975774250907343">"Kalendri muutmine"</item>
+    <item msgid="4668747371441932697">"Asukoht"</item>
+    <item msgid="1487578921720243646">"Märguande postitamine"</item>
+    <item msgid="4636080349724146638">"Asukoht"</item>
+    <item msgid="673510900286463926">"Helistamine telefonile"</item>
+    <item msgid="542083422784609790">"SMS-i/MMS-i lugemine"</item>
+    <item msgid="1033780373029588436">"SMS-i/MMS-i kirjutamine"</item>
+    <item msgid="5647111115517787488">"SMS-i/MMS-i vastuvõtmine"</item>
+    <item msgid="8591105601108455893">"SMS-i/MMS-i vastuvõtmine"</item>
+    <item msgid="7730995008517841903">"SMS-i/MMS-i vastuvõtmine"</item>
+    <item msgid="2613033109026626086">"SMS-i/MMS-i vastuvõtmine"</item>
+    <item msgid="3037159047591081136">"SMS-i/MMS-i saatmine"</item>
+    <item msgid="4726682243833913568">"SMS-i/MMS-i lugemine"</item>
+    <item msgid="6555678522277865572">"SMS-i/MMS-i kirjutamine"</item>
+    <item msgid="6981734935578130884">"Seadete muutmine"</item>
+    <item msgid="8705854389991425629">"Peale joonistamine"</item>
+    <item msgid="5861356020344153651">"Juurdepääsumärguanded"</item>
+    <item msgid="78432174621628659">"Kaamera"</item>
+    <item msgid="3986116419882154794">"Heli salvestamine"</item>
+    <item msgid="4516840825756409490">"Heli esitamine"</item>
+    <item msgid="6811712502798183957">"Lõikelaua lugemine"</item>
+    <item msgid="2780369012602289114">"Lõikelaua muutmine"</item>
+    <item msgid="2331359440170850868">"Meedianupud"</item>
+    <item msgid="6133599737122751231">"Helifookus"</item>
+    <item msgid="6844485713404805301">"Põhihelitugevus"</item>
+    <item msgid="1600379420669104929">"Hääle helitugevus"</item>
+    <item msgid="6296768210470214866">"Helina helitugevus"</item>
+    <item msgid="510690696071629241">"Meedia helitugevus"</item>
+    <item msgid="406861638631430109">"Äratuse helitugevus"</item>
+    <item msgid="4715864795872233884">"Märguande helitugevus"</item>
+    <item msgid="2311478519251301183">"Bluetoothi helitugevus"</item>
+    <item msgid="5133991377896747027">"Hoia ärkvel"</item>
+    <item msgid="2464189519136248621">"Asukoht"</item>
+    <item msgid="2062677934050803037">"Asukoht"</item>
+    <item msgid="1735171933192715957">"Kasutusstatistika hankimine"</item>
+    <item msgid="1014093788778383554">"Mikrofoni vaigistamine või vaigistuse tühistamine"</item>
+    <item msgid="4199297950608622850">"Teatiste kuvamine"</item>
+    <item msgid="2527962435313398821">"Meediumi projitseerimine"</item>
+    <item msgid="5117506254221861929">"VPN-i aktiveerimine"</item>
+    <item msgid="8291198322681891160">"Taustapilt kirjutamiseks"</item>
+    <item msgid="7106921284621230961">"Abistruktuur"</item>
+    <item msgid="4496533640894624799">"Abistav ekraanipilt"</item>
+    <item msgid="2598847264853993611">"Telefoni oleku lugemine"</item>
+    <item msgid="9215610846802973353">"Kõneposti lisamine"</item>
+    <item msgid="9186411956086478261">"SIP kasutamine"</item>
+    <item msgid="6884763100104539558">"Väljamineva kõne töötlemine"</item>
+    <item msgid="125513972170580692">"Sõrmejälg"</item>
+    <item msgid="2556071024281275619">"Kehaandurid"</item>
+    <item msgid="617168514928339387">"Kärjeteadete lugemine"</item>
+    <item msgid="7134693570516523585">"Tehislik asukoht"</item>
+    <item msgid="7224489175375229399">"Salvestusruumi lugemine"</item>
+    <item msgid="8472735063903258202">"Salvestusruumi kirjutamine"</item>
+    <item msgid="4069276819909595110">"Ekraani sisselülitamine"</item>
+    <item msgid="1228338896751121025">"Kontode hankimine"</item>
+    <item msgid="3181581793459233672">"Taustal käitamine"</item>
+    <item msgid="2340936043025374076">"Juurdepääsetavuse helitugevus"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Lühike"</item>
     <item msgid="4816511817309094890">"Keskmine"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Ära luba kunagi"</item>
     <item msgid="8184570120217958741">"Luba alati"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Tavaline"</item>
+    <item msgid="5101233285497327432">"Keskmine"</item>
+    <item msgid="1555861583162930714">"Väike"</item>
+    <item msgid="1719683776264798117">"Kriitiline"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Tavaline"</item>
+    <item msgid="6107138933849816768">"Mõõdukas"</item>
+    <item msgid="182695359839047859">"Väike"</item>
+    <item msgid="8577246509202964244">"Kriitiline"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Püsiv"</item>
     <item msgid="167418068739176448">"Sagedasim tegevus"</item>
diff --git a/tests/CarDeveloperOptions/res/values-et/config.xml b/tests/CarDeveloperOptions/res/values-et/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-et/config.xml
+++ b/tests/CarDeveloperOptions/res/values-et/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-et/strings.xml b/tests/CarDeveloperOptions/res/values-et/strings.xml
index 627f509..c94af1e 100644
--- a/tests/CarDeveloperOptions/res/values-et/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-et/strings.xml
@@ -80,11 +80,10 @@
     <string name="sdcard_format" product="default" msgid="4831611387627849108">"Kustuta SD-kaart"</string>
     <string name="preview_pager_content_description" msgid="5731599395893090038">"Eelvaade"</string>
     <string name="preview_page_indicator_content_description" msgid="3192955679074998362">"Eelvaade, <xliff:g id="CURRENT_PAGE">%1$d</xliff:g>. leht <xliff:g id="NUM_PAGES">%2$d</xliff:g>-st"</string>
-    <string name="font_size_summary" msgid="9120023206321191067">"Muutke ekraanil kuvatavat tekst suuremaks või väiksemaks."</string>
+    <string name="font_size_summary" msgid="9120023206321191067">"Muutke ekraanil kuvatavat teksti suuremaks või väiksemaks."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Vähendamine"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Suurendamine"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Näidistekst"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Võlur Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"11. peatükk: Ozi imeline smaragdlinn"</string>
@@ -384,7 +383,7 @@
     <string name="encryption_and_credential_settings_summary" product="tablet" msgid="8170667308598998791">"Seade on krüpteeritud"</string>
     <string name="decryption_settings_summary" product="tablet" msgid="7524119945312453569">"Seade ei ole krüpteeritud"</string>
     <string name="lockscreen_settings_title" msgid="1221505938891948413">"Lukustuskuva seaded"</string>
-    <string name="lockscreen_settings_what_to_show_category" msgid="3133378945821488654">"Mida näidata?"</string>
+    <string name="lockscreen_settings_what_to_show_category" msgid="3133378945821488654">"Mida kuvada?"</string>
     <string name="security_settings_summary" msgid="5210109100643223686">"Määrake Minu asukoht, ekraani avamine, SIM-kaardi lukk, mandaadi talletuslukk"</string>
     <string name="cdma_security_settings_summary" msgid="1783066617800041869">"Määrake oma asukoht, ekraani avamine, mandaadi talletuslukk"</string>
     <string name="security_passwords_title" msgid="6853942836045862315">"Privaatsus"</string>
@@ -467,11 +466,11 @@
     <string name="security_settings_fingerprint_enroll_dialog_ok" msgid="3428927518029038956">"OK"</string>
     <string name="security_settings_fingerprint_enroll_dialog_delete" msgid="4312297515772004580">"Kustuta"</string>
     <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"Puudutage andurit"</string>
-    <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Asetage oma sõrm andurile ja kui tunnete värinat, siis tõstke see üles"</string>
+    <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Asetage oma sõrm andurile ja kui tunnete värinat, siis tõstke see üles."</string>
     <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"Tõstke, seejärel puudutage uuesti"</string>
-    <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Tõstke sõrme, et lisada sõrmejälje eri osad"</string>
+    <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Tõstke sõrme, et lisada sõrmejälje eri osad."</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"Sõrmejälg on lisatud"</string>
-    <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"Kui näete seda ikooni, kasutage tuvastamiseks või ostude kinnitamiseks oma sõrmejälge"</string>
+    <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"Kui näete seda ikooni, kasutage tuvastamiseks või ostude kinnitamiseks oma sõrmejälge."</string>
     <string name="security_settings_fingerprint_enroll_enrolling_skip" msgid="1473280156532146933">"Teen seda hiljem"</string>
     <string name="setup_fingerprint_enroll_enrolling_skip_title" msgid="2816424026528101690">"Kas jätta sõrmejälje seadistus vahele?"</string>
     <string name="setup_fingerprint_enroll_enrolling_skip_message" msgid="8139299964344809780">"Valisite telefoni avamise üheks viisiks sõrmejälje kasutamise. Kui seadistamise praegu vahele jätate, peate seda tegema hiljem. See võtab ainult umbes minuti."</string>
@@ -495,7 +494,7 @@
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"Järgmine"</string>
     <string name="security_settings_fingerprint_enroll_disclaimer" msgid="5831834311961551423">"Lisaks telefoni avamisele saate oma sõrmejälje abil volitada ka ostusid ja juurdepääsu rakendustele. "<annotation id="url">"Lisateave"</annotation></string>
     <string name="security_settings_fingerprint_enroll_disclaimer_lockscreen_disabled" msgid="7954742554236652690">" Ekraaniluku valik on keelatud. Küsige lisateavet organisatsiooni administraatorilt. "<annotation id="admin_details">"Rohkem üksikasju"</annotation>\n\n"Saate ka edaspidi sõrmejäljega oste volitada ja rakendustele juurde pääseda. "<annotation id="url">"Lisateave"</annotation></string>
-    <string name="security_settings_fingerprint_enroll_lift_touch_again" msgid="1670703069782212223">"Tõstke sõrme, seejärel puudutage sõrmejäljelugejat uuesti"</string>
+    <string name="security_settings_fingerprint_enroll_lift_touch_again" msgid="1670703069782212223">"Tõstke sõrme, seejärel puudutage sõrmejäljeandurit uuesti"</string>
     <string name="fingerprint_add_max" msgid="2939393314646115661">"Saate lisada kuni <xliff:g id="COUNT">%d</xliff:g> sõrmejälge"</string>
     <string name="fingerprint_intro_error_max" msgid="3247720976621039437">"Olete lisanud maksimaalse arvu sõrmejälgi"</string>
     <string name="fingerprint_intro_error_unknown" msgid="3975674268256524015">"Rohkem sõrmejälgi ei saa lisada"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Peab olema alla <xliff:g id="NUMBER_1">%d</xliff:g> numbri</item>
       <item quantity="one">Peab olema alla <xliff:g id="NUMBER_0">%d</xliff:g> numbri</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Tohib sisaldada ainult numbreid 0–9."</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Seadme administraator ei luba kasutada viimast PIN-koodi"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"IT-administraator on levinud PIN-koodid blokeerinud. Proovige muud PIN-koodi."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"See ei tohi sisaldada sobimatut tähemärki"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Peab sisaldama vähemalt <xliff:g id="COUNT">%d</xliff:g> tähemärki, mis ei ole täht</item>
       <item quantity="one">Peab sisaldama vähemalt 1 tähemärki, mis ei ole täht</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Peab sisaldama vähemalt <xliff:g id="COUNT">%d</xliff:g> tähemärki, mis ei ole number</item>
+      <item quantity="one">Peab sisaldama vähemalt 1 tähemärki, mis ei ole number</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Seadme administraator ei luba kasutada hiljutist parooli"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"IT-administraator on levinud paroolid blokeerinud. Proovige muud parooli."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Kasvavad, kahanevad või korduvad numbrijadad on keelatud"</string>
@@ -780,7 +782,7 @@
     <string name="bluetooth_disconnect_hid_profile" msgid="6964226087090465662">"Seadme <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ühendus sisendseadmega katkestatakse."</string>
     <string name="bluetooth_disconnect_pan_user_profile" msgid="5523689915196343097">"Katkestatakse Interneti-ühendus seadme <xliff:g id="DEVICE_NAME">%1$s</xliff:g> kaudu."</string>
     <string name="bluetooth_disconnect_pan_nap_profile" product="tablet" msgid="8145126793699232403">"Tahvelarvuti Interneti-ühenduse jagamine seadmega <xliff:g id="DEVICE_NAME">%1$s</xliff:g> katkestatakse."</string>
-    <string name="bluetooth_disconnect_pan_nap_profile" product="default" msgid="6040826983120279685">"Telefoni Interneti-ühenduse jagamine seadmega <xliff:g id="DEVICE_NAME">%1$s</xliff:g> katkestatakse."</string>
+    <string name="bluetooth_disconnect_pan_nap_profile" product="default" msgid="6040826983120279685">"Telefoni internetiühenduse jagamine seadmega <xliff:g id="DEVICE_NAME">%1$s</xliff:g> katkestatakse."</string>
     <string name="bluetooth_device_advanced_title" msgid="5752155558126694036">"Seotud Bluetooth-seade"</string>
     <string name="bluetooth_device_advanced_online_mode_title" msgid="7665622268007450665">"Ühenda"</string>
     <string name="bluetooth_device_advanced_online_mode_summary" msgid="4180673788239241086">"Ühenda Bluetooth-seadmega"</string>
@@ -931,11 +933,11 @@
     <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"Valige WiFi-kuumkoha lubamiseks vähemalt üks sagedusriba:"</string>
     <string name="wifi_ip_settings" msgid="4636102290236116946">"IP-seaded"</string>
     <string name="wifi_privacy_settings" msgid="4462092795794247809">"Privaatsus"</string>
-    <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"Juhuslik MAC-aadress"</string>
+    <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"Juhulikustatud MAC-aadress"</string>
     <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"Seadme lisamine"</string>
-    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"Seadme võrku „<xliff:g id="SSID">%1$s</xliff:g>” lisamiseks paigutage allolev QR-kood aknas keskele"</string>
+    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"Seadme võrku „<xliff:g id="SSID">%1$s</xliff:g>” lisamiseks paigutage QR-kood allolevas aknas keskele"</string>
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"QR-koodi skannimine"</string>
-    <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"Võrguga „<xliff:g id="SSID">%1$s</xliff:g>” ühenduse loomiseks paigutage allolev QR-kood aknas keskele"</string>
+    <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"Võrguga „<xliff:g id="SSID">%1$s</xliff:g>” ühenduse loomiseks paigutage QR-kood allolevas aknas keskele"</string>
     <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"Liituge WiFi-võrguga, skannides QR-koodi"</string>
     <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"WiFi jagamine"</string>
     <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"Skannige see QR-kood, et luua ühendus võrguga „<xliff:g id="SSID">%1$s</xliff:g>” ja jagada parooli"</string>
@@ -961,7 +963,7 @@
     <string name="wifi_dpp_lockscreen_title" msgid="3910665850075275963">"Kinnitage oma isik"</string>
     <string name="wifi_dpp_wifi_password" msgid="8007558344032612455">"WiFi-võrgu parool: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
     <string name="wifi_dpp_hotspot_password" msgid="6172326289042241924">"Kuumkoha parool: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
-    <string name="wifi_dpp_add_device" msgid="1347056725253936358">"Lisa seade"</string>
+    <string name="wifi_dpp_add_device" msgid="1347056725253936358">"Seadme lisamine"</string>
     <string name="wifi_dpp_connect_network_using_qr_code" msgid="115993715600532357">"Looge võrguga ühendus QR-koodi abil"</string>
     <string name="retry" msgid="8500839563577344702">"Proovi uuesti"</string>
     <string name="wifi_shared" msgid="5054256778276524960">"Jaga seadme teiste kasutajatega"</string>
@@ -973,7 +975,7 @@
     <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"Ära kinnita"</string>
     <string name="wifi_do_not_validate_eap_server_warning" msgid="3895397996759837323">"Sertifikaati pole määratud. Teie ühendus pole privaatne."</string>
     <string name="wifi_ssid_too_long" msgid="34911971389775920">"Võrgu nimi on liiga pikk."</string>
-    <string name="wifi_no_domain_warning" msgid="735859919311067606">"Tuleb määrata domeen."</string>
+    <string name="wifi_no_domain_warning" msgid="735859919311067606">"Domeeni määramine on kohustuslik."</string>
     <string name="wifi_wps_available_first_item" msgid="3221671453930485243">"WPS on saadaval"</string>
     <string name="wifi_wps_available_second_item" msgid="5703265526619705185">" WPS on saadaval"</string>
     <string name="wifi_carrier_connect" msgid="7202618367339982884">"Operaatori WiFi-võrk"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"WiFi"</item>
+    <item msgid="2271962426654621656">"Mobiilne andmeside"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Kasuta mobiilsidevõrku, kui WiFi ei ole saadaval"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Kasuta WiFi-ühendust, kui mobiilsidevõrk ei ole saadaval"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Helistage WiFi-võrgu kaudu. WiFi-ühenduse katkemisel kõne lõpeb."</string>
@@ -1521,11 +1526,11 @@
     <string name="storage_wizard_ready_v2_internal_moved_body" msgid="4133133596316768033">"Sisu teisaldati seadmesse <xliff:g id="NAME_0">^1</xliff:g>. \n\nSeadme <xliff:g id="NAME_1">^2</xliff:g> haldamiseks tehke valikud "<b>"Seaded &gt; Salvestusruum"</b>"."</string>
     <string name="battery_status_title" msgid="8731200319740671905">"Aku olek"</string>
     <string name="battery_level_title" msgid="5207775387973771646">"Aku tase"</string>
-    <string name="apn_settings" msgid="8130776653826271664">"Pääsupunktid"</string>
+    <string name="apn_settings" msgid="8130776653826271664">"Pääsupunktid (APN-id)"</string>
     <string name="apn_edit" msgid="4350571070853305357">"Pääsupunkti muutmine"</string>
     <string name="apn_not_set" msgid="5344235604466825691">"Määramata"</string>
     <string name="apn_name" msgid="8431432886706852226">"Nimi"</string>
-    <string name="apn_apn" msgid="190519449579357696">"Pääsupunktnimi"</string>
+    <string name="apn_apn" msgid="190519449579357696">"Pääsupunkti nimi"</string>
     <string name="apn_http_proxy" msgid="8816906767987944465">"Puhverserver"</string>
     <string name="apn_http_port" msgid="5789193688960075486">"Port"</string>
     <string name="apn_user" msgid="6979724587671704006">"Kasutajanimi"</string>
@@ -1541,7 +1546,7 @@
     <string name="apn_auth_type_pap" msgid="6155876141679480864">"PAP"</string>
     <string name="apn_auth_type_chap" msgid="5484031368454788686">"CHAP"</string>
     <string name="apn_auth_type_pap_chap" msgid="2977833804460109203">"PAP või CHAP"</string>
-    <string name="apn_type" msgid="6725346490902871146">"Pääsupunktinime tüüp"</string>
+    <string name="apn_type" msgid="6725346490902871146">"APN-i tüüp"</string>
     <string name="apn_protocol" msgid="1240197323563960912">"APN-i protokoll"</string>
     <string name="apn_roaming_protocol" msgid="6913336248771263497">"APN-i rändlusprotokoll"</string>
     <string name="carrier_enabled" msgid="1819916725305365581">"Luba/keela APN"</string>
@@ -1616,11 +1621,11 @@
     <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"Kui andmemahu säästja on sisse lülitatud, siis ei saa jagada ega kasutada teisaldatavat kuumkohta"</string>
     <string name="usb_title" msgid="7480927657535578688">"USB"</string>
     <string name="usb_tethering_button_text" msgid="6242228383142012332">"USB jagamine"</string>
-    <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"Telefoni Interneti-ühenduse jagamine USB kaudu"</string>
+    <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"Telefoni internetiühenduse jagamine USB kaudu"</string>
     <string name="usb_tethering_subtext" product="tablet" msgid="154536000235361034">"Tahvelarvuti Interneti-ühenduse jagamine USB kaudu"</string>
     <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"Jagamine Bluetoothiga"</string>
     <string name="bluetooth_tethering_subtext" product="tablet" msgid="6868756914621131635">"Tahvelarvuti Interneti-ühenduse jagamine Bluetoothi kaudu"</string>
-    <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"Telefoni Interneti-ühenduse jagamine Bluetoothi kaudu"</string>
+    <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"Telefoni internetiühenduse jagamine Bluetoothi kaudu"</string>
     <string name="bluetooth_tethering_off_subtext_config" msgid="3981528184780083266">"Seadme <xliff:g id="DEVICE_NAME">%1$d</xliff:g> Interneti-ühenduse jagamine Bluetoothi kaudu"</string>
     <string name="bluetooth_tethering_overflow_error" msgid="6946561351369376943">"Ei saa jagada rohkem kui <xliff:g id="MAXCONNECTION">%1$d</xliff:g> seadmele."</string>
     <string name="bluetooth_untether_blank" msgid="5428300773782256084">"Seadme <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ühenduse jagamine lõpetatakse."</string>
@@ -1642,7 +1647,7 @@
     <string name="mobile_insert_sim_card" msgid="7594550403454243732">"Sisestage SIM-kaart ja taaskäivitage"</string>
     <string name="mobile_connect_to_internet" msgid="6031886097365170913">"Looge Interneti-ühendus"</string>
     <string name="location_title" msgid="8664674161765477168">"Minu asukoht"</string>
-    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"Tööprofiili asukoht"</string>
+    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"Tööprofiili asukohaluba"</string>
     <string name="location_app_level_permissions" msgid="1298041503927632960">"Rakenduste load"</string>
     <string name="location_app_permission_summary_location_off" msgid="541372845344796336">"Asukoht on välja lülitatud"</string>
     <plurals name="location_app_permission_summary_location_on" formatted="false" msgid="7904821382328758218">
@@ -2034,7 +2039,7 @@
     <string name="accessibility_settings_summary" msgid="5742379519336396561">"Ekraanilugejad, ekraan, interaktsiooni juhtnupud"</string>
     <string name="vision_settings_title" msgid="7315352351051423944">"Nähtavuse seaded"</string>
     <string name="vision_settings_description" msgid="3476589459009287332">"Seadet saab kohandada vastavalt oma vajadustele. Neid juurdepääsetavuse funktsioone saab hiljem muuta menüüs Seaded."</string>
-    <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"Fondi suuruse muutmine"</string>
+    <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"Muutke fondi suurust"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"Ekraanilugejad"</string>
     <string name="audio_and_captions_category_title" msgid="6140472938769619212">"Heli ja ekraanil kuvatud tekst"</string>
     <string name="display_category_title" msgid="545168481672250195">"Ekraan"</string>
@@ -2059,7 +2064,7 @@
     <string name="accessibility_global_gesture_preference_title" msgid="3842279082831426816">"Helitugevuse nupu otsetee"</string>
     <string name="accessibility_shortcut_service_title" msgid="3516052294376744060">"Otsetee teenus"</string>
     <string name="accessibility_shortcut_service_on_lock_screen_title" msgid="1279441617927949980">"Lukustuskuval lubamine"</string>
-    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"Kui otsetee on sisse lülitatud, võite hõlbustusfunktsiooni käivitamiseks hoida mõlemat helitugevuse nuppu 3 sekundit all."</string>
+    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"Kui otsetee on sisse lülitatud, võite hõlbustusfunktsiooni käivitamiseks hoida mõlemat helitugevuse klahvi 3 sekundit all."</string>
     <string name="accessibility_toggle_high_text_contrast_preference_title" msgid="5652244684961877255">"Suure kontrastsusega tekst"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"Ekraanisuurenduse värskendus"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"Ekraanisuurenduse kasutus rakenduste vahetamisel"</string>
@@ -2081,7 +2086,7 @@
     <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"Valige, kui kaua soovite kuvada sõnumeid, mida peate lugema, kuid mis on nähtavad ainult ajutiselt.\n\nKõik rakendused seda seadet ei toeta"</string>
     <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"Valige, kui kaua soovite kuvada sõnumeid, milles palutakse teil toiminguid teha, kuid mis on nähtaval ainult ajutiselt.\n\nKõik rakendused seda seadet ei toeta."</string>
     <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"Puute ja hoidmise viide"</string>
-    <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"Värvuste ümberpööramine"</string>
+    <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"Värvide ümberpööramine"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"Võib mõjutada toimivust"</string>
     <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"Peatumisaeg"</string>
     <string name="accessibility_autoclick_description" msgid="5492414927846407499">"Kui kasutate hiirt, võite kursori seadistada automaatselt mõne toimingu tegema, kui see teatud aja jooksul ei liigu."</string>
@@ -2146,7 +2151,7 @@
     <string name="captioning_standard_options_title" msgid="4124898413348084226">"Standardvalikud"</string>
     <string name="captioning_locale" msgid="4734464353806207943">"Keel"</string>
     <string name="captioning_text_size" msgid="1707122517246408084">"Teksti suurus"</string>
-    <string name="captioning_preset" msgid="7429888317480872337">"Tiitri stiil"</string>
+    <string name="captioning_preset" msgid="7429888317480872337">"Subtiitri stiil"</string>
     <string name="captioning_custom_options_title" msgid="4530479671071326732">"Kohandatud valikud"</string>
     <string name="captioning_background_color" msgid="2434458880326292180">"Tausta värv"</string>
     <string name="captioning_background_opacity" msgid="8178926599201811936">"Tausta läbipaistvus"</string>
@@ -2157,7 +2162,7 @@
     <string name="captioning_edge_color" msgid="4330622137047993780">"Serva värv"</string>
     <string name="captioning_edge_type" msgid="4414946407430588162">"Serva tüüp"</string>
     <string name="captioning_typeface" msgid="7893208796949341767">"Fondi perekond"</string>
-    <string name="captioning_preview_text" msgid="4877753964772618049">"Tiitrid näevad välja sellised"</string>
+    <string name="captioning_preview_text" msgid="4877753964772618049">"Subtiitrid näevad välja sellised"</string>
     <string name="captioning_preview_characters" msgid="6469599599352973561">"Aa"</string>
     <string name="locale_default" msgid="910074908458214054">"Vaikeseade"</string>
     <string name="color_title" msgid="132875486061816584">"Värv"</string>
@@ -2294,7 +2299,7 @@
     </plurals>
     <plurals name="battery_tip_restrict_summary" formatted="false" msgid="984148373944071669">
       <item quantity="other">%2$d rakendust kasutavad taustal palju akut</item>
-      <item quantity="one">%1$s rakendus kasutab taustal palju akut</item>
+      <item quantity="one">Rakendus %1$s kasutab taustal palju akut</item>
     </plurals>
     <plurals name="battery_tip_restrict_handled_summary" formatted="false" msgid="469696766640020557">
       <item quantity="other">Neid rakendusi ei saa taustal käitada</item>
@@ -2307,7 +2312,7 @@
     <string name="battery_tip_restrict_app_dialog_message" msgid="6905822297507947381">"Aku säästmiseks peatage rakenduse <xliff:g id="APP">%1$s</xliff:g> jaoks taustal aku kasutamine. See rakendus ei pruugi korralikult töötada ja märguanded võivad viibida."</string>
     <string name="battery_tip_restrict_apps_less_than_5_dialog_message" msgid="4225881888543582456">"Aku säästmiseks peatage nende rakenduste jaoks taustal aku kasutamine. Piiratud rakendused ei pruugi korralikult töötada ja märguanded võivad viibida.\n\nRakendused:"</string>
     <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"Aku säästmiseks peatage nende rakenduste jaoks taustal aku kasutamine. Piiratud rakendused ei pruugi korralikult töötada ja märguanded võivad viibida.\n\nRakendused:\n<xliff:g id="APP_LIST">%1$s</xliff:g>."</string>
-    <string name="battery_tip_restrict_app_dialog_ok" msgid="2573410775701913487">"Piira"</string>
+    <string name="battery_tip_restrict_app_dialog_ok" msgid="2573410775701913487">"Piira:"</string>
     <string name="battery_tip_unrestrict_app_dialog_title" msgid="812458516399125710">"Kas eemaldada piirang?"</string>
     <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"See rakendus saab taustal akut kasutada. Aku võib oodatust varem tühjaks saada."</string>
     <string name="battery_tip_unrestrict_app_dialog_ok" msgid="9154938931448151479">"Eemalda"</string>
@@ -2525,7 +2530,7 @@
     <string name="credentials_reset" msgid="355080737664731678">"Mandaatide kustutamine"</string>
     <string name="credentials_reset_summary" msgid="7622528359699428555">"Kõikide sertifikaatide eemaldamine"</string>
     <string name="trusted_credentials" msgid="6989242522455395200">"Usaldusväärsed mandaadid"</string>
-    <string name="trusted_credentials_summary" msgid="7411781319056251582">"Usaldusväärsete CA-sertifikaatide kuvamine"</string>
+    <string name="trusted_credentials_summary" msgid="7411781319056251582">"Kuva usaldusväärsed CA-sertifikaadid"</string>
     <string name="user_credentials" msgid="8365731467650306757">"Kasutaja mandaadid"</string>
     <string name="user_credentials_summary" msgid="7350223899317423252">"Salvestatud mandaatide vaatamine ja muutmine"</string>
     <string name="advanced_security_title" msgid="286883005673855845">"Täpsemad"</string>
@@ -2574,7 +2579,7 @@
     <string name="add_device_admin_msg" msgid="3573765823476931173">"Kas aktiveerida admin. rakendus?"</string>
     <string name="add_device_admin" msgid="1621152410207260584">"Aktiveeri seadme administraatori rakendus"</string>
     <string name="device_admin_add_title" msgid="6097881332139146897">"Seadme administraator"</string>
-    <string name="device_admin_warning" msgid="4421817419326480449">"Selle administraatori rakenduse aktiveerimisel lubatakse rakendusel <xliff:g id="APP_NAME">%1$s</xliff:g> teha järgmisi toiminguid:"</string>
+    <string name="device_admin_warning" msgid="4421817419326480449">"Selle administraatori rakenduse aktiveerimisel lubatakse rakendusel <xliff:g id="APP_NAME">%1$s</xliff:g> teha järgmisi toiminguid."</string>
     <string name="device_admin_status" msgid="5424944611789040723">"See administraatori rakendus on aktiivne ja lubab rakendusel <xliff:g id="APP_NAME">%1$s</xliff:g> teha järgmisi toiminguid."</string>
     <string name="profile_owner_add_title" msgid="735805919754362791">"Kas aktiveerida profiilihaldur?"</string>
     <string name="adding_profile_owner_warning" msgid="1284541194547382194">"Kui jätkate, haldab teie kasutajat edaspidi administraator, kes saab võib-olla talletada peale teie isiklike andmete ka seotud andmeid.\n\nTeie administraator saab jälgida ja hallata selle kasutajaga seotud seadeid, juurdepääsu, rakendusi ja andmeid, sealhulgas veebitegevusi ja seadme asukohateavet."</string>
@@ -2899,7 +2904,7 @@
     <string name="user_exit_guest_dialog_remove" msgid="1878866060881115716">"Eemalda"</string>
     <string name="user_enable_calling" msgid="864760054792249503">"Lülita telefonikõned sisse"</string>
     <string name="user_enable_calling_sms" msgid="3450252891736718793">"Lülita telefonikõned ja SMS-id sisse"</string>
-    <string name="user_remove_user" msgid="3687544420125911166">"Kasutaja kustutamine"</string>
+    <string name="user_remove_user" msgid="3687544420125911166">"Kustuta kasutaja"</string>
     <string name="user_enable_calling_confirm_title" msgid="1141612415529158542">"Kas lülitada telefonikõned sisse?"</string>
     <string name="user_enable_calling_confirm_message" msgid="2490126715153125970">"Selle kasutajaga jagatakse kõneajalugu."</string>
     <string name="user_enable_calling_and_sms_confirm_title" msgid="4153856398523366976">"Kas lülitada telefonikõned ja SMS-id sisse?"</string>
@@ -2917,7 +2922,7 @@
     <string name="nfc_payment_app_and_desc" msgid="102312684211458190">"<xliff:g id="APP">%1$s</xliff:g> – <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="nfc_payment_use_default" msgid="3098724195746409476">"Kasuta vaikerakendust"</string>
     <string name="nfc_payment_favor_default" msgid="7555356982142464260">"Alati"</string>
-    <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Välja arvatud siis, kui mõni teine makserakendus on avatud"</string>
+    <string name="nfc_payment_favor_open" msgid="3739055715000436749">"V.a siis, kui mõni teine makserakendus on avatud"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"Maksa teenuse Puuduta ja maksa terminalis rakendusega"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Terminali kaudu maksmine"</string>
     <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Seadistage makserakendus. Seejärel peate oma telefoni tagakülge hoidma lihtsalt mis tahes terminali suunas, millel on kontaktivaba makse sümbol."</string>
@@ -3491,7 +3496,7 @@
     <string name="zen_calls_summary_starred_repeat" msgid="9191394641577678207">"Tärniga tähistatud kontaktidelt ja korduvatelt helistajatelt"</string>
     <string name="zen_calls_summary_contacts_repeat" msgid="7747592096431111510">"Kontaktidelt ja korduvatelt helistajatelt"</string>
     <string name="zen_calls_summary_repeat_only" msgid="8839703337232747964">"Ainult korduvatelt helistajatelt"</string>
-    <string name="zen_mode_from_none" msgid="7683889985618637010">"Mitte kelleltki"</string>
+    <string name="zen_mode_from_none" msgid="7683889985618637010">"Mitte ükski"</string>
     <string name="zen_mode_from_none_calls" msgid="2967739140346917546">"Ära luba kõnesid"</string>
     <string name="zen_mode_from_none_messages" msgid="9069143820057833634">"Ära luba ühtki sõnumit"</string>
     <string name="zen_mode_alarms" msgid="5528707742250954290">"Luba märguanded"</string>
@@ -3512,9 +3517,9 @@
     <string name="zen_mode_events_list" msgid="8578102701815684873">"sündmused"</string>
     <string name="zen_mode_all_callers" msgid="4455039040077343838">"igaüks"</string>
     <string name="zen_mode_contacts_callers" msgid="3116829245339716399">"kontaktid"</string>
-    <string name="zen_mode_starred_callers" msgid="1317376207713013472">"tärniga tähistatud kontaktidelt"</string>
+    <string name="zen_mode_starred_callers" msgid="1317376207713013472">"tärniga tähistatud kontaktid"</string>
     <string name="zen_mode_repeat_callers" msgid="1435309867554692340">"Korduvad helistajad"</string>
-    <string name="zen_mode_repeat_callers_list" msgid="2750270907597457279">"korduvatelt helistajatelt"</string>
+    <string name="zen_mode_repeat_callers_list" msgid="2750270907597457279">"korduvad helistajad"</string>
     <string name="zen_mode_repeat_callers_title" msgid="7192952181541813487">"Luba korduvad helistajad"</string>
     <string name="zen_mode_calls_summary_one" msgid="8327371053236689649">"Luba <xliff:g id="CALLER_TYPE">%1$s</xliff:g>"</string>
     <string name="zen_mode_calls_summary_two" msgid="9017678770532673578">"Luba <xliff:g id="CALLER_TYPE">%1$s</xliff:g> ja <xliff:g id="CALLERT_TPYE">%2$s</xliff:g>"</string>
@@ -3625,7 +3630,7 @@
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> täiendav luba</item>
     </plurals>
     <string name="runtime_permissions_summary_no_permissions_granted" msgid="3477934429220828771">"Lube pole antud"</string>
-    <string name="runtime_permissions_summary_no_permissions_requested" msgid="3901636077467389637">"Lube ei taotletud"</string>
+    <string name="runtime_permissions_summary_no_permissions_requested" msgid="3901636077467389637">"Lube pole taotletud"</string>
     <string name="filter_all_apps" msgid="4042756539846043675">"Kõik rakendused"</string>
     <string name="filter_enabled_apps" msgid="5888459261768538489">"Installitud rakendused"</string>
     <string name="filter_instant_apps" msgid="8087483282854072366">"Installimata avat. rakendused"</string>
@@ -3707,7 +3712,7 @@
     <string name="high_power_system" msgid="739584574711292753">"Aku optimeerimine pole saadaval"</string>
     <string name="high_power_desc" msgid="333756885680362741">"Aku optimeerimist ei rakendata. Aku võib kiiremini tühjeneda."</string>
     <string name="high_power_prompt_title" msgid="2805745781720454052">"Kas soovite lubada rakendusel pidevalt taustal töötada?"</string>
-    <string name="high_power_prompt_body" msgid="8067395096053552289">"Kui lubate rakendusel <xliff:g id="APP_NAME">%1$s</xliff:g> pidevalt taustal töötada, võib see vähendada aku tööiga.\n\nSaate seda hiljem muuta jaotises Seaded &gt; Rakendused ja märguanded."</string>
+    <string name="high_power_prompt_body" msgid="8067395096053552289">"Kui lubate rakendusel <xliff:g id="APP_NAME">%1$s</xliff:g> pidevalt taustal töötada, võib see lühendada aku tööiga.\n\nSaate seda hiljem muuta jaotises Seaded &gt; Rakendused ja märguanded."</string>
     <string name="battery_summary" msgid="4345690800899981339">"Kasutus alates viimasest täislaadimisest on <xliff:g id="PERCENTAGE">%1$s</xliff:g>"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"Toitehaldus"</string>
     <string name="no_battery_summary" msgid="4105932628367471314">"Akut pole pärast viimast täislaadimist kasutatud"</string>
@@ -4003,7 +4008,7 @@
     <string name="battery_saver_button_turn_off" msgid="2912950982503267828">"Lülita kohe välja"</string>
     <string name="not_battery_optimizing" msgid="2616044774307734160">"Aku optimeerimist ei kasutata"</string>
     <string name="lockscreen_remote_input" msgid="3363310613165354434">"Kui seade on lukus, keela märguannetes vastuste või muu teksti sisestamine"</string>
-    <string name="default_spell_checker" msgid="8636661093243189533">"Vaikimisi õigekirjakontroll"</string>
+    <string name="default_spell_checker" msgid="8636661093243189533">"Vaikeõigekirjakontroll"</string>
     <string name="choose_spell_checker" msgid="7619860861923582868">"Õigekirjakontrolli valimine"</string>
     <string name="spell_checker_master_switch_title" msgid="5712693172227400668">"Kasuta õigekirjakontrolli"</string>
     <string name="spell_checker_not_selected" msgid="331034541988255137">"Pole valitud"</string>
@@ -4047,7 +4052,7 @@
     <string name="display_cutout_emulation_keywords" msgid="6795671536772871439">"ekraani väljalõige, lõige"</string>
     <string name="overlay_option_device_default" msgid="165508753381657697">"Seadme vaikeseade"</string>
     <string name="overlay_toast_failed_to_apply" msgid="5692251825129250040">"Ülekatet ei õnnestunud rakendada"</string>
-    <string name="special_access" msgid="1453926335914696206">"Rakenduste erijuurdepääs"</string>
+    <string name="special_access" msgid="1453926335914696206">"Rakenduse erijuurdepääs"</string>
     <plurals name="special_access_summary" formatted="false" msgid="5182092345063909346">
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> rakendusel on piiranguteta juurdepääs andmesidele</item>
       <item quantity="one">1 rakendusel on piiranguteta juurdepääs andmesidele</item>
@@ -4107,7 +4112,7 @@
     <string name="gesture_preference_summary" product="tablet" msgid="8303793594714075580">"Kiirliigutused tahvelarvuti juhtimiseks"</string>
     <string name="gesture_preference_summary" product="device" msgid="7792199669106960922">"Kiirliigutused seadme juhtimiseks"</string>
     <string name="double_tap_power_for_camera_title" msgid="5480829329052517484">"Kaamera avamine"</string>
-    <string name="double_tap_power_for_camera_summary" msgid="6591026425496323965">"Kaamera kiireks avamiseks vajutage toitenuppu kaks korda. See töötab igast kuvast."</string>
+    <string name="double_tap_power_for_camera_summary" msgid="6591026425496323965">"Kaamera kiireks avamiseks vajutage toitenuppu kaks korda. See töötab igal kuval."</string>
     <string name="double_tap_power_for_camera_suggestion_title" msgid="509078029429865036">"Kaamera kiiresti avamine"</string>
     <string name="double_twist_for_camera_mode_title" msgid="2606032140297556018">"Kaamera vahetamine"</string>
     <string name="double_twist_for_camera_mode_summary" msgid="8979914206876018137"></string>
@@ -4126,7 +4131,7 @@
     <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"Kellaaja, märguannete ja muu teabe vaatamiseks võtke telefon kätte."</string>
     <string name="ambient_display_pickup_summary" product="tablet" msgid="1077745287100012928">"Kellaaja, märguannete ja muu teabe vaatamiseks võtke tahvelarvuti kätte."</string>
     <string name="ambient_display_pickup_summary" product="device" msgid="404199660076598026">"Kellaaja, märguannete ja muu teabe vaatamiseks võtke seade kätte."</string>
-    <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"Puudutamine telefoni kontrollimiseks"</string>
+    <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"Telefoni kontrollimiseks puudutamine"</string>
     <string name="ambient_display_tap_screen_title" product="tablet" msgid="6434521782016864148">"Puudutamine tahvelarvuti kontrollimiseks"</string>
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"Puudutamine seadme kontrollimiseks"</string>
     <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"Kellaaja, märguannete ja muu teabe vaatamiseks puudutage oma ekraani."</string>
@@ -4305,7 +4310,7 @@
     <string name="change_wifi_state_title" msgid="5140754955787584174">"WiFi-seadete juhtimine"</string>
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"Lubage rakendusel WiFi-seadeid juhtida"</string>
     <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"Lubage sellel rakendusel WiFi sisse või välja lülitada, otsida WiFi-võrke ja nendega ühendus luua, võrke lisada või eemaldada või luua kohalik kuumkoht"</string>
-    <string name="media_output_title" msgid="8710632337456601848">"Esita meedia seadmes"</string>
+    <string name="media_output_title" msgid="8710632337456601848">"Meedia esitamise seade:"</string>
     <string name="media_output_default_summary" msgid="3159237976830415584">"See seade"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"Telefon"</string>
     <string name="media_output_summary" product="tablet" msgid="6672024060360538526">"Tahvelarvuti"</string>
@@ -4436,7 +4441,7 @@
     <string name="register_automatically" msgid="1858081641661493109">"Automaatne registreerimine …"</string>
     <string name="roaming_alert_title" msgid="1849237823113454475">"Kas lubada andmesiderändlus?"</string>
     <string name="roaming_check_price_warning" msgid="5883499714594419439">"Hinnakirja küsige oma võrguteenuse pakkujalt."</string>
-    <string name="mobile_data_usage_title" msgid="2376358672434990037">"Rakenduse andmekasutus"</string>
+    <string name="mobile_data_usage_title" msgid="2376358672434990037">"Rakenduste andmekasutus"</string>
     <string name="mobile_network_mode_error" msgid="6818434186286086554">"Võrgu režiim <xliff:g id="NETWORKMODEID">%1$d</xliff:g> on sobimatu. Eirake seda."</string>
     <string name="mobile_network_apn_title" msgid="5628635067747404382">"Pääsupunktide nimed"</string>
     <string name="manual_mode_disallowed_summary" msgid="799800630000340665">"Pole saadaval, kui on ühendus on loodud operaatoriga <xliff:g id="CARRIER">%1$s</xliff:g>"</string>
diff --git a/tests/CarDeveloperOptions/res/values-eu/arrays.xml b/tests/CarDeveloperOptions/res/values-eu/arrays.xml
index 03259f7..a0df5ca 100644
--- a/tests/CarDeveloperOptions/res/values-eu/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-eu/arrays.xml
@@ -38,7 +38,16 @@
     <item msgid="5827960506924849753">"10 minutu"</item>
     <item msgid="6677424950124253938">"30 minutu"</item>
   </string-array>
-    <!-- no translation found for dream_timeout_entries:7 (8271452751594598661) -->
+  <string-array name="dream_timeout_entries">
+    <item msgid="6487043225269853023">"Inoiz ez"</item>
+    <item msgid="2517785806387977252">"15 segundo"</item>
+    <item msgid="6347954399441173672">"30 segundo"</item>
+    <item msgid="4858305253279921789">"1 minutu"</item>
+    <item msgid="8109273437140044073">"2 minutu"</item>
+    <item msgid="2788593551142462622">"5 minutu"</item>
+    <item msgid="8012672183888404961">"10 minutu"</item>
+    <item msgid="8271452751594598661">"30 minutu"</item>
+  </string-array>
   <string-array name="lock_after_timeout_entries">
     <item msgid="2232921187970351881">"Berehala"</item>
     <item msgid="2038544972632026612">"5 segundo"</item>
@@ -50,17 +59,47 @@
     <item msgid="811192536981678974">"10 minutu"</item>
     <item msgid="7258394417241706272">"30 minutu"</item>
   </string-array>
-    <!-- no translation found for entries_font_size:0 (2340391964816059553) -->
-    <!-- no translation found for entries_font_size:0 (6490061470416867723) -->
-    <!-- no translation found for entries_font_size:2 (1714184661981538355) -->
-    <!-- no translation found for entries_font_size:2 (1678068858001018666) -->
-    <!-- no translation found for wifi_status:3 (5848277343965362748) -->
-    <!-- no translation found for wifi_status_with_ssid:1 (6816207058895999545) -->
-    <!-- no translation found for wifi_status_with_ssid:3 (7547609081339573756) -->
-    <!-- no translation found for wifi_status_with_ssid:4 (5145158315060185414) -->
+  <string-array name="entries_font_size">
+    <item msgid="2340391964816059553">"Txikia"</item>
+    <item msgid="591935967183159581">"Lehenetsia"</item>
+    <item msgid="1714184661981538355">"Handia"</item>
+    <item msgid="6195563047686707484">"Handiena"</item>
+  </string-array>
+  <string-array name="wifi_status">
+    <item msgid="1304883790721412351"></item>
+    <item msgid="4157625910392775808">"Bilatzen…"</item>
+    <item msgid="5597394826455877834">"Konektatzen…"</item>
+    <item msgid="5848277343965362748">"Autentifikatzen…"</item>
+    <item msgid="3391238031431440676">"IP helbidea lortzen…"</item>
+    <item msgid="5257597310494000224">"Konektatuta"</item>
+    <item msgid="8472497592913050396">"Etenda"</item>
+    <item msgid="1228072488815999109">"Deskonektatzen…"</item>
+    <item msgid="7253087004422991731">"Deskonektatuta"</item>
+    <item msgid="4169850917304751227">"Ezin izan da egin"</item>
+    <item msgid="6266658166690831131">"Blokeatuta"</item>
+    <item msgid="4517230805854909775">"Konexio ahula aldi baterako saihesten"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="4853670665485437464"></item>
+    <item msgid="6816207058895999545">"Bilatzen…"</item>
+    <item msgid="8058143476674427024">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> sarera konektatzen…"</item>
+    <item msgid="7547609081339573756">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> sarearekin autentifikatzen…"</item>
+    <item msgid="5145158315060185414">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> sarearen IP helbidea lortzen…"</item>
+    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> sarera konektatuta"</item>
+    <item msgid="6600156231416890902">"Etenda"</item>
+    <item msgid="4133290864821295785">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> saretik deskonektatzen…"</item>
+    <item msgid="3980154971187953257">"Deskonektatuta"</item>
+    <item msgid="2847316776634969068">"Ezin izan da egin"</item>
+    <item msgid="4390990424746035383">"Blokeatuta"</item>
+    <item msgid="3618248791367063949">"Konexio ahula aldi baterako saihesten"</item>
+  </string-array>
     <!-- no translation found for wifi_tether_security:0 (5586343370515598801) -->
     <!-- no translation found for wifi_tether_security:1 (6136336549994615745) -->
-    <!-- no translation found for wifi_p2p_wps_setup:0 (5390235347963255303) -->
+  <string-array name="wifi_p2p_wps_setup">
+    <item msgid="5390235347963255303">"Sakatu botoia"</item>
+    <item msgid="7401896200768713930">"Pareko gailuaren PINa"</item>
+    <item msgid="4526848028011846710">"Gailuaren PINa"</item>
+  </string-array>
   <string-array name="wifi_p2p_status">
     <item msgid="8741947238021758201">"Konektatuta"</item>
     <item msgid="983792611851499732">"Gonbidatuta"</item>
@@ -82,8 +121,13 @@
     <item msgid="1644506614010085798">"4"</item>
     <item msgid="3132506679404897150">"5"</item>
   </string-array>
-    <!-- no translation found for wifi_signal:1 (7882129634982603782) -->
-    <!-- no translation found for wifi_signal:4 (999948812884919584) -->
+  <string-array name="wifi_signal">
+    <item msgid="1709949377823900951">"Txarra"</item>
+    <item msgid="7882129634982603782">"Txarra"</item>
+    <item msgid="6457357501905996224">"Hala-holakoa"</item>
+    <item msgid="405271628162918841">"Ona"</item>
+    <item msgid="999948812884919584">"Bikaina"</item>
+  </string-array>
   <string-array name="data_usage_data_range">
     <item msgid="8986775481492954015">"Azken 30 egunak"</item>
     <item msgid="3211287705232736964">"Erabilera-zikloa…"</item>
@@ -119,7 +163,10 @@
     <item msgid="7330627471456865502">"MSCHAPV2"</item>
     <item msgid="6255179395132581882">"GTC"</item>
   </string-array>
-    <!-- no translation found for wifi_ip_settings:1 (4377002609760712163) -->
+  <string-array name="wifi_ip_settings">
+    <item msgid="2717196390555072244">"DHCP"</item>
+    <item msgid="4377002609760712163">"Estatikoa"</item>
+  </string-array>
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"Bat ere ez"</item>
     <item msgid="1464741437353223198">"Eskuliburua"</item>
@@ -239,11 +286,73 @@
     <item msgid="1165623660533024666">"exekutatu atzeko planoan"</item>
     <item msgid="6423861043647911030">"erabilerraztasun-eginbideen bolumena"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:3 (7836406246005211990) -->
-    <!-- no translation found for app_ops_labels:4 (3951439024549922598) -->
-    <!-- no translation found for app_ops_labels:8 (3597797992398484655) -->
-    <!-- no translation found for app_ops_labels:20 (3037159047591081136) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Kokapena"</item>
+    <item msgid="6656077694190491067">"Kokapena"</item>
+    <item msgid="8790228218278477369">"Kokapena"</item>
+    <item msgid="7836406246005211990">"Egin dar-dar"</item>
+    <item msgid="3951439024549922598">"Irakurri kontaktuak"</item>
+    <item msgid="8802152411647068">"Aldatu kontaktuak"</item>
+    <item msgid="229544934599698735">"Irakurri deien erregistroa"</item>
+    <item msgid="7396102294405899613">"Aldatu deien erregistroa"</item>
+    <item msgid="3597797992398484655">"Irakurri egutegia"</item>
+    <item msgid="2705975774250907343">"Aldatu egutegia"</item>
+    <item msgid="4668747371441932697">"Kokapena"</item>
+    <item msgid="1487578921720243646">"Bidali jakinarazpena"</item>
+    <item msgid="4636080349724146638">"Kokapena"</item>
+    <item msgid="673510900286463926">"Deitu telefonora"</item>
+    <item msgid="542083422784609790">"Irakurri SMS/MMS mezuak"</item>
+    <item msgid="1033780373029588436">"Idatzi SMS/MMS mezuak"</item>
+    <item msgid="5647111115517787488">"Jaso SMS/MMS mezuak"</item>
+    <item msgid="8591105601108455893">"Jaso SMS/MMS mezuak"</item>
+    <item msgid="7730995008517841903">"Jaso SMS/MMS mezuak"</item>
+    <item msgid="2613033109026626086">"Jaso SMS/MMS mezuak"</item>
+    <item msgid="3037159047591081136">"Bidali SMS/MMS mezuak"</item>
+    <item msgid="4726682243833913568">"Irakurri SMS/MMS mezuak"</item>
+    <item msgid="6555678522277865572">"Idatzi SMS/MMS mezuak"</item>
+    <item msgid="6981734935578130884">"Aldatu ezarpenak"</item>
+    <item msgid="8705854389991425629">"Marraztu gainean"</item>
+    <item msgid="5861356020344153651">"Atzitu jakinarazpenak"</item>
+    <item msgid="78432174621628659">"Kamera"</item>
+    <item msgid="3986116419882154794">"Grabatu audioa"</item>
+    <item msgid="4516840825756409490">"Erreproduzitu audioa"</item>
+    <item msgid="6811712502798183957">"Irakurri arbela"</item>
+    <item msgid="2780369012602289114">"Aldatu arbela"</item>
+    <item msgid="2331359440170850868">"Multimedia-botoiak"</item>
+    <item msgid="6133599737122751231">"Audio-fokuratzea"</item>
+    <item msgid="6844485713404805301">"Bolumen nagusia"</item>
+    <item msgid="1600379420669104929">"Ahotsaren bolumena"</item>
+    <item msgid="6296768210470214866">"Tonuaren bolumena"</item>
+    <item msgid="510690696071629241">"Multimedia-edukiaren bolumena"</item>
+    <item msgid="406861638631430109">"Alarmaren bolumena"</item>
+    <item msgid="4715864795872233884">"Jakinarazpenen bolumena"</item>
+    <item msgid="2311478519251301183">"Bluetooth bidezko audioaren bolumena"</item>
+    <item msgid="5133991377896747027">"Mantendu aktibo"</item>
+    <item msgid="2464189519136248621">"Kokapena"</item>
+    <item msgid="2062677934050803037">"Kokapena"</item>
+    <item msgid="1735171933192715957">"Lortu erabilera-estatistikak"</item>
+    <item msgid="1014093788778383554">"Aktibatu edo desaktibatu mikrofonoa"</item>
+    <item msgid="4199297950608622850">"Erakutsi leiho gainerakorra"</item>
+    <item msgid="2527962435313398821">"Proiektatu multimedia-edukia"</item>
+    <item msgid="5117506254221861929">"Aktibatu VPN konexioa"</item>
+    <item msgid="8291198322681891160">"Idatzi horma-paperean"</item>
+    <item msgid="7106921284621230961">"Lagundu egiturarekin"</item>
+    <item msgid="4496533640894624799">"Lagundu pantaila-argazkiarekin"</item>
+    <item msgid="2598847264853993611">"Irakurri telefonoaren egoera"</item>
+    <item msgid="9215610846802973353">"Gehitu erantzungailua"</item>
+    <item msgid="9186411956086478261">"Erabili SIP deiak"</item>
+    <item msgid="6884763100104539558">"Prozesatu egindako deia"</item>
+    <item msgid="125513972170580692">"Hatz-marka digitala"</item>
+    <item msgid="2556071024281275619">"Gorputz-sentsoreak"</item>
+    <item msgid="617168514928339387">"Irakurri sare mugikor bidezko igorpenak"</item>
+    <item msgid="7134693570516523585">"Imitatu kokapena"</item>
+    <item msgid="7224489175375229399">"Irakurri memoria"</item>
+    <item msgid="8472735063903258202">"Idatzi memorian"</item>
+    <item msgid="4069276819909595110">"Aktibatu pantaila"</item>
+    <item msgid="1228338896751121025">"Lortu kontuak"</item>
+    <item msgid="3181581793459233672">"Abiarazi atzeko planoan"</item>
+    <item msgid="2340936043025374076">"Erabilerraztasun-eginbideen bolumena"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Laburra"</item>
     <item msgid="4816511817309094890">"Ertaina"</item>
@@ -260,7 +369,13 @@
     <item msgid="4627069151979553527">"Etzana"</item>
     <item msgid="6896773537705206194">"Maiuskula txikiak"</item>
   </string-array>
-    <!-- no translation found for captioning_font_size_selector_titles:3 (2784236342175159295) -->
+  <string-array name="captioning_font_size_selector_titles">
+    <item msgid="1680223634161592855">"Oso txikia"</item>
+    <item msgid="5091603983404027034">"Txikia"</item>
+    <item msgid="176844712416932112">"Normala"</item>
+    <item msgid="2784236342175159295">"Handia"</item>
+    <item msgid="218913203203160606">"Oso handia"</item>
+  </string-array>
   <string-array name="captioning_edge_type_selector_titles">
     <item msgid="3865198759294188069">"Lehenetsia"</item>
     <item msgid="6488643537808152001">"Bat ere ez"</item>
@@ -275,7 +390,14 @@
     <item msgid="1874668269931014581">"% 75"</item>
     <item msgid="6462911487571123954">"% 100"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"Erabili aplikazioaren lehenespenak"</item>
+    <item msgid="8611890312638868524">"Zuria beltzaren gainean"</item>
+    <item msgid="5891360837786277638">"Beltza zuriaren gainean"</item>
+    <item msgid="2798457065945456853">"Horia beltzaren gainean"</item>
+    <item msgid="5799049811524553967">"Horia urdinaren gainean"</item>
+    <item msgid="3673930830658169860">"Pertsonalizatua"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"PPTP VPN"</item>
     <item msgid="1349760781118368659">"L2TP/IPSec VPNa aurrez partekatutako gakoekin"</item>
@@ -288,15 +410,32 @@
     <item msgid="2958623927055120839">"Bat ere ez"</item>
     <item msgid="1157046369795346308">"Eskuliburua"</item>
   </string-array>
-    <!-- no translation found for vpn_states:4 (9135049670787351881) -->
+  <string-array name="vpn_states">
+    <item msgid="5408915841694583740">"Deskonektatuta"</item>
+    <item msgid="8754480102834556765">"Hasieratzen…"</item>
+    <item msgid="3351334355574270250">"Konektatzen…"</item>
+    <item msgid="8303882153995748352">"Konektatuta"</item>
+    <item msgid="9135049670787351881">"Denbora-muga"</item>
+    <item msgid="2124868417182583926">"Ezin izan da egin"</item>
+  </string-array>
   <string-array name="security_settings_premium_sms_values">
     <item msgid="1164265643455394443">"Galdetu"</item>
     <item msgid="7718817231348607934">"Ukatu beti"</item>
     <item msgid="8184570120217958741">"Eman baimena beti"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normala"</item>
+    <item msgid="5101233285497327432">"Ez oso ona"</item>
+    <item msgid="1555861583162930714">"Txikia"</item>
+    <item msgid="1719683776264798117">"Oso handia"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normala"</item>
+    <item msgid="6107138933849816768">"Ertaina"</item>
+    <item msgid="182695359839047859">"Txikia"</item>
+    <item msgid="8577246509202964244">"Larria"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Etengabea"</item>
     <item msgid="167418068739176448">"Jarduera nagusia"</item>
diff --git a/tests/CarDeveloperOptions/res/values-eu/config.xml b/tests/CarDeveloperOptions/res/values-eu/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-eu/config.xml
+++ b/tests/CarDeveloperOptions/res/values-eu/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-eu/strings.xml b/tests/CarDeveloperOptions/res/values-eu/strings.xml
index f385ddf..8c778bf 100644
--- a/tests/CarDeveloperOptions/res/values-eu/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-eu/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Handitu edo txikitu pantailako testua."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Txikitu"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Handitu"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Testu-lagina"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Ozeko azti miragarria"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"11. kapitulua: Esmeraldazko Oz hiri harrigarria"</string>
@@ -116,9 +115,9 @@
     <string name="bluetooth_empty_list_user_restricted" msgid="3616298363281495777">"Ez daukazu Bluetooth-aren ezarpenak aldatzeko baimenik."</string>
     <string name="bluetooth_pairing_pref_title" msgid="2904954138013884029">"Parekatu gailu batekin"</string>
     <string name="bluetooth_is_visible_message" msgid="6341088682252805612">"Bluetooth-aren ezarpenak irekita badaude, inguruko gailuek <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ikusi ahal izango dute."</string>
-    <string name="bluetooth_footer_mac_message" product="default" msgid="335341476746836260">"Telefonoaren Bluetooth helbidea: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
-    <string name="bluetooth_footer_mac_message" product="tablet" msgid="6033609611245782463">"Tabletaren Bluetooth helbidea: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
-    <string name="bluetooth_footer_mac_message" product="device" msgid="7639919867088358038">"Gailuaren Bluetooth helbidea: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="bluetooth_footer_mac_message" product="default" msgid="335341476746836260">"Telefonoa Bluetooth bidez konektatzeko helbidea: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="bluetooth_footer_mac_message" product="tablet" msgid="6033609611245782463">"Tableta Bluetooth bidez konektatzeko helbidea: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="bluetooth_footer_mac_message" product="device" msgid="7639919867088358038">"Gailua Bluetooth bidez konektatzeko helbidea: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
     <string name="bluetooth_is_disconnect_question" msgid="6180709281434591654">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> deskonektatu nahi duzu?"</string>
     <string name="bluetooth_broadcasting" msgid="8926408584599563760">"Igorpena"</string>
     <string name="bluetooth_device" msgid="3170974107364990008">"Izenik gabeko Bluetooth bidezko gailua"</string>
@@ -130,10 +129,10 @@
     <string name="bluetooth_show_received_files" msgid="5060846395852236652">"Jasotako fitxategiak"</string>
     <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"Bluetooth bidez jasotako fitxategiak"</string>
     <string name="device_picker" msgid="8345264486071697705">"Aukeratu Bluetooth bidezko gailua"</string>
-    <string name="bluetooth_ask_enablement" msgid="8716802066127746062">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth konexioa aktibatu nahi du"</string>
-    <string name="bluetooth_ask_disablement" msgid="7125319551097350783">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth konexioa desaktibatu nahi du"</string>
-    <string name="bluetooth_ask_enablement_no_name" msgid="6105893027185475233">"Aplikazio batek Bluetooth konexioa aktibatu nahi du"</string>
-    <string name="bluetooth_ask_disablement_no_name" msgid="8648888502291681310">"Aplikazio batek Bluetooth konexioa desaktibatu nahi du"</string>
+    <string name="bluetooth_ask_enablement" msgid="8716802066127746062">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth-a aktibatu nahi du"</string>
+    <string name="bluetooth_ask_disablement" msgid="7125319551097350783">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth-a desaktibatu nahi du"</string>
+    <string name="bluetooth_ask_enablement_no_name" msgid="6105893027185475233">"Aplikazio batek Bluetooth-a aktibatu nahi du"</string>
+    <string name="bluetooth_ask_disablement_no_name" msgid="8648888502291681310">"Aplikazio batek Bluetooth-a desaktibatu nahi du"</string>
     <string name="bluetooth_ask_discovery" product="tablet" msgid="6871595755186170115">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak tableta Bluetooth bidezko beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%2$d</xliff:g> segundoz."</string>
     <string name="bluetooth_ask_discovery" product="default" msgid="3388041479101348095">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak telefonoa Bluetooth bidezko beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%2$d</xliff:g> segundoz."</string>
     <string name="bluetooth_ask_discovery_no_name" product="tablet" msgid="1472358802231150345">"Aplikazio batek tableta Bluetooth bidezko beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%1$d</xliff:g> segundoz."</string>
@@ -142,14 +141,14 @@
     <string name="bluetooth_ask_lasting_discovery" product="default" msgid="7796723473397303412">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak telefonoa beste Bluetooth bidezko gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
     <string name="bluetooth_ask_lasting_discovery_no_name" product="tablet" msgid="5961921359655434504">"Aplikazio batek tableta beste Bluetooth bidezko gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
     <string name="bluetooth_ask_lasting_discovery_no_name" product="default" msgid="3585910858758443872">"Aplikazio batek telefonoa beste Bluetooth bidezko gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
-    <string name="bluetooth_ask_enablement_and_discovery" product="tablet" msgid="5676466923424941153">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth konexioa aktibatu eta tableta beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%2$d</xliff:g> segundoz."</string>
-    <string name="bluetooth_ask_enablement_and_discovery" product="default" msgid="507088376226791063">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth konexioa aktibatu eta telefonoa beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%2$d</xliff:g> segundoz."</string>
-    <string name="bluetooth_ask_enablement_and_discovery_no_name" product="tablet" msgid="1164681893121736219">"Aplikazio batek Bluetooth konexioa aktibatu eta tableta beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%1$d</xliff:g> segundoz."</string>
-    <string name="bluetooth_ask_enablement_and_discovery_no_name" product="default" msgid="2542247690119921188">"Aplikazio batek Bluetooth konexioa aktibatu eta telefonoa beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%1$d</xliff:g> segundoz."</string>
-    <string name="bluetooth_ask_enablement_and_lasting_discovery" product="tablet" msgid="7118362102769177771">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth konexioa aktibatu eta tableta beste gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
-    <string name="bluetooth_ask_enablement_and_lasting_discovery" product="default" msgid="2577488464813970727">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth konexioa aktibatu eta telefonoa beste gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
-    <string name="bluetooth_ask_enablement_and_lasting_discovery_no_name" product="tablet" msgid="7083038132794842691">"Aplikazio batek Bluetooth konexioa aktibatu eta tableta beste gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
-    <string name="bluetooth_ask_enablement_and_lasting_discovery_no_name" product="default" msgid="3541668604020109525">"Aplikazio batek Bluetooth konexioa aktibatu eta telefonoa beste gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
+    <string name="bluetooth_ask_enablement_and_discovery" product="tablet" msgid="5676466923424941153">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth-a aktibatu, eta tableta beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%2$d</xliff:g> segundoz."</string>
+    <string name="bluetooth_ask_enablement_and_discovery" product="default" msgid="507088376226791063">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth-a aktibatu eta telefonoa beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%2$d</xliff:g> segundoz."</string>
+    <string name="bluetooth_ask_enablement_and_discovery_no_name" product="tablet" msgid="1164681893121736219">"Aplikazio batek Bluetooth-a aktibatu, eta tableta beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%1$d</xliff:g> segundoz."</string>
+    <string name="bluetooth_ask_enablement_and_discovery_no_name" product="default" msgid="2542247690119921188">"Aplikazio batek Bluetooth-a aktibatu, eta telefonoa beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%1$d</xliff:g> segundoz."</string>
+    <string name="bluetooth_ask_enablement_and_lasting_discovery" product="tablet" msgid="7118362102769177771">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth-a aktibatu, eta tableta beste gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
+    <string name="bluetooth_ask_enablement_and_lasting_discovery" product="default" msgid="2577488464813970727">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth-a aktibatu, eta telefonoa beste gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
+    <string name="bluetooth_ask_enablement_and_lasting_discovery_no_name" product="tablet" msgid="7083038132794842691">"Aplikazio batek Bluetooth-a aktibatu, eta tableta beste gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
+    <string name="bluetooth_ask_enablement_and_lasting_discovery_no_name" product="default" msgid="3541668604020109525">"Aplikazio batek Bluetooth-a aktibatu eta telefonoa beste gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
     <string name="bluetooth_turning_on" msgid="6935183036449748493">"Bluetooth-a aktibatzen…"</string>
     <string name="bluetooth_turning_off" msgid="9214026723789756620">"Bluetooth-a desaktibatzen…"</string>
     <string name="bluetooth_connection_permission_request" msgid="2382506002340643398">"Bluetooth bidez konektatzeko eskaera"</string>
@@ -164,7 +163,7 @@
     <string name="bluetooth_sap_request" msgid="6318039677671263261">"SIM txartelerako sarbide-eskaera"</string>
     <string name="bluetooth_sap_acceptance_dialog_text" msgid="1909352413109340355">"<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g> gailuak SIM txartela atzitu nahi du. SIM txartelerako sarbidea ematen badiozu, gailuaren datu-konexioa desgaituko da, txartelerako konexioak dirauen bitartean. Eman sarbidea <xliff:g id="DEVICE_NAME_1">%2$s?</xliff:g> gailuari"</string>
     <string name="bluetooth_device_name_summary" msgid="8661066392056595005">"\"<xliff:g id="DEVICE_NAME">^1</xliff:g>\" gisa dago ikusgai beste gailuetan"</string>
-    <string name="bluetooth_off_footer" msgid="7658444560543730571">"Aktibatu Bluetooth konexioa beste gailu batzuetara konektatzeko."</string>
+    <string name="bluetooth_off_footer" msgid="7658444560543730571">"Aktibatu Bluetooth bidezko konexioa beste gailu batzuetara konektatzeko."</string>
     <string name="bluetooth_paired_device_title" msgid="8361860197780425286">"Zure gailuak"</string>
     <string name="bluetooth_pairing_page_title" msgid="9053463656712597709">"Parekatu gailu batekin"</string>
     <string name="bluetooth_pref_summary" product="tablet" msgid="3601662966604648212">"Baimendu tabletari inguruko Bluetooth bidezko gailuekin komunikatzea"</string>
@@ -179,11 +178,11 @@
     <string name="connected_device_available_call_title" msgid="6774859446815858428">"Deitzeko balio duten gailu erabilgarriak"</string>
     <string name="connected_device_connected_title" msgid="6255107326608785482">"Konektatuta daudenak"</string>
     <string name="connected_device_saved_title" msgid="8270136893488475163">"Gordetako gailuak"</string>
-    <string name="connected_device_add_device_summary" msgid="7960491471270158891">"Bluetooth konexioa aktibatuko da parekatu ahal izateko"</string>
+    <string name="connected_device_add_device_summary" msgid="7960491471270158891">"Bluetooth bidezko konexioa aktibatuko da parekatu ahal izateko"</string>
     <string name="connected_device_connections_title" msgid="9205000271382018428">"Konexio-hobespenak"</string>
     <string name="connected_device_previously_connected_title" msgid="225918223397410428">"Aurrez konektatutako gailuak"</string>
     <string name="connected_device_previously_connected_screen_title" msgid="2018789662358162716">"Aurretik konektatutakoak"</string>
-    <string name="connected_device_bluetooth_turned_on_toast" msgid="4652326177920814476">"Aktibatu da Bluetooth konexioa"</string>
+    <string name="connected_device_bluetooth_turned_on_toast" msgid="4652326177920814476">"Aktibatu da Bluetooth-a"</string>
     <string name="previous_connected_see_all" msgid="7237095013087310923">"Ikusi guztiak"</string>
     <string name="date_and_time" msgid="2957463607025909857">"Data eta ordua"</string>
     <string name="choose_timezone" msgid="8215332993926818147">"Aukeratu ordu-zona"</string>
@@ -197,18 +196,18 @@
     <string name="proxy_settings_title" msgid="6014901859338211713">"Proxya"</string>
     <string name="proxy_clear_text" msgid="498317431076294101">"Garbitu"</string>
     <string name="proxy_port_label" msgid="8285157632538848509">"Proxy-ataka"</string>
-    <string name="proxy_exclusionlist_label" msgid="8179084955547941904">"Egin hauen proxyaren salbuespena"</string>
+    <string name="proxy_exclusionlist_label" msgid="8179084955547941904">"Egin ez ikusi proxyari kasu hauetan"</string>
     <string name="proxy_defaultView_text" msgid="5785775257042403261">"Leheneratu balio lehenetsiak"</string>
     <string name="proxy_action_text" msgid="814511434843981413">"Eginda"</string>
     <string name="proxy_hostname_label" msgid="6798891831427287847">"Proxyaren ostalari-izena"</string>
     <string name="proxy_error" msgid="5036164133669802299">"Abisua"</string>
     <string name="proxy_error_dismiss" msgid="883805570485635650">"Ados"</string>
     <string name="proxy_error_invalid_host" msgid="5430640241353307223">"Idatzi duzun ostalari-izena ez da baliozkoa."</string>
-    <string name="proxy_error_invalid_exclusion_list" msgid="4314503082913856333">"Idatzi duzun salbuespen-zerrendak ez du formatu egokia. Idatzi domeinuen zerrenda, komaz bereizita."</string>
+    <string name="proxy_error_invalid_exclusion_list" msgid="4314503082913856333">"Idatzi duzun salbuespen-zerrendak ez du formatu egokia. Idatzi kanpo utzitako domeinuen zerrenda, komaz bereizita."</string>
     <string name="proxy_error_empty_port" msgid="8034561724923076215">"Atakaren eremua bete behar duzu."</string>
     <string name="proxy_error_empty_host_set_port" msgid="8471455809508588255">"Ataka eremuak hutsik egon behar du Ostalaria eremua ere hutsik badago."</string>
     <string name="proxy_error_invalid_port" msgid="4046559920586100637">"Idatzi duzun ataka ez da baliozkoa."</string>
-    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"Arakatzaileak HTTP proxya erabiltzen du baina ezin dute beste aplikazioek erabili."</string>
+    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"Arakatzaileak HTTP proxya erabiltzen du, baina ezin dute beste aplikazioek erabili."</string>
     <string name="proxy_url_title" msgid="882042361706435904">"Proxya auto. konf. URLa: "</string>
     <string name="radio_info_dl_kbps" msgid="2903778264453410272">"Deskargatzeko banda-zabalera (Kb/s):"</string>
     <string name="radio_info_ul_kbps" msgid="3802245899811732716">"Kargen banda-zabalera (Kb/s):"</string>
@@ -427,7 +426,7 @@
     <string name="security_settings_face_settings_remove_face_data" msgid="2821359954483136239">"Kendu aurpegiaren datuak"</string>
     <string name="security_settings_face_settings_footer" msgid="4627175759990550715">"Gailua desblokeatzeko eta aplikazioetan sartzeko erabil dezakezu aurpegia. "<annotation id="url">"Lortu informazio gehiago"</annotation></string>
     <string name="security_settings_face_settings_remove_dialog_title" msgid="5675319895815271094">"Aurpegiari buruzko datuak ezabatu?"</string>
-    <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"Aurpegiaren bidez desblokeatzeko aukerak erregistratutako datuak betiko eta segurtasun osoz ezabatuko dira. Horren ondoren, PIN kodea, eredua edo pasahitza beharko duzu telefonoa desblokeatzeko, aplikazioetan saioa hasteko eta ordainketak berresteko."</string>
+    <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"Aurpegiaren bidez desblokeatzeko eginbideak erregistratutako datuak betiko eta segurtasun osoz ezabatuko dira. Horren ondoren, PIN kodea, eredua edo pasahitza beharko duzu telefonoa desblokeatzeko, aplikazioetan saioa hasteko eta ordainketak berresteko."</string>
     <string name="security_settings_fingerprint_preference_title" msgid="4177132225930582928">"Hatz-marka digitala"</string>
     <string name="fingerprint_manage_category_title" msgid="1463406696801542090">"Kudeatu hatz-markak"</string>
     <string name="fingerprint_usage_category_title" msgid="7298369141954599706">"Hatz-marken erabilera"</string>
@@ -447,7 +446,7 @@
     <string name="security_settings_fingerprint_enroll_introduction_continue" msgid="271662150372486535">"Jarraitu"</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel_setup" msgid="756928427429893070">"Saltatu"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue_setup" msgid="4125977169169671144">"Hurrengoa"</string>
-    <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"Saltatu hatz-marka?"</string>
+    <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"Hatz-markaren urratsa saltatu?"</string>
     <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"Minutu bat edo bi baino ez dituzu beharko hatz-marka konfiguratzeko. Urrats hau saltatuz gero, geroago ere gehi dezakezu hatz-marka ezarpenetan."</string>
     <string name="lock_screen_intro_skip_title" msgid="5307431665496346914">"Pantailaren blokeoa saltatu?"</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="tablet" msgid="7553945981266845264">"Ez dira aktibatuko gailuaren babes-eginbideak. Tableta galtzen baduzu, lapurtzen badizute edo berrezarri egiten bada, ezin izango duzu ekidin beste pertsona batzuek erabiltzea."</string>
@@ -668,9 +667,8 @@
       <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> digitu baino gutxiago izan behar ditu</item>
       <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> digitu baino gutxiago izan behar du</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"0 eta 9 arteko digituak soilik izan ditzake"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Gailuaren administratzaileak ez du eman beste PIN kode bat erabiltzeko baimenik"</string>
-    <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"IKT administratzaileak blokeatu egiten ditu asmatzen errazak diren PIN kodeak. Erabili beste PIN bat."</string>
+    <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"IKT saileko administratzaileak blokeatu egiten ditu asmatzen errazak diren PIN kodeak. Erabili beste PIN bat."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Ezin da erabili onartzen ez den karaktererik"</string>
     <string name="lockpassword_password_requires_alpha" msgid="7017799931349816346">"Hizki bat eduki behar du gutxienez"</string>
     <string name="lockpassword_password_requires_digit" msgid="6856775151626646011">"Zenbaki bat eduki behar du gutxienez"</string>
@@ -699,8 +697,12 @@
       <item quantity="other">Hizkiak ez diren <xliff:g id="COUNT">%d</xliff:g> karaktere bat izan behar du gutxienez</item>
       <item quantity="one">Hizkia ez den karaktere bat izan behar du gutxienez</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Gutxienez, zenbakizkoak ez diren <xliff:g id="COUNT">%d</xliff:g> karaktere izan behar ditu</item>
+      <item quantity="one">Gutxienez, zenbakizkoa ez den 1 karaktere izan behar du</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Gailuaren administratzaileak ez du eman beste pasahitz bat erabiltzeko baimenik"</string>
-    <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"IKT administratzaileak blokeatu egiten ditu asmatzen errazak diren pasahitzak. Erabili beste pasahitz bat."</string>
+    <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"IKT saileko administratzaileak blokeatu egiten ditu asmatzen errazak diren pasahitzak. Erabili beste pasahitz bat."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Ezin da erabili goranzko, beheranzko edo errepikatutako digitu-sekuentziarik"</string>
     <string name="lockpassword_confirm_label" msgid="1512364313516715624">"Berretsi"</string>
     <string name="lockpassword_cancel_label" msgid="3799907375604482766">"Utzi"</string>
@@ -768,7 +770,7 @@
     <string name="ble_scan_notify_text" msgid="6290170236546386932">"Kokapenaren zehaztasuna hobetzeko, sistemaren aplikazioek eta zerbitzuek Bluetooth bidezko gailuak hautematen jarraituko dute. Hori aldatzeko, zoaz <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>gailuak bilatzeko ezarpenetara<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
     <string name="bluetooth_connect_failed" msgid="1151234676456333786">"Ezin izan da konektatu. Saiatu berriro."</string>
     <string name="device_details_title" msgid="726517818032923222">"Gailuaren xehetasunak"</string>
-    <string name="bluetooth_device_mac_address" msgid="5328203122581150405">"Gailuaren Bluetooth helbidea: <xliff:g id="ADDRESS">%1$s</xliff:g>"</string>
+    <string name="bluetooth_device_mac_address" msgid="5328203122581150405">"Gailua Bluetooth bidez konektatzeko helbidea: <xliff:g id="ADDRESS">%1$s</xliff:g>"</string>
     <string name="bluetooth_unpair_dialog_title" msgid="3669848977755142047">"Gailua ahaztu nahi duzu?"</string>
     <string name="bluetooth_unpair_dialog_body" product="default" msgid="5998071227980078077">"Aurrerantzean, telefonoa ez da parekatuko <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailuarekin"</string>
     <string name="bluetooth_unpair_dialog_body" product="tablet" msgid="4696157463230518866">"Aurrerantzean, tableta ez da parekatuko <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailuarekin"</string>
@@ -824,7 +826,7 @@
     <string name="nfc_disclaimer_title" msgid="4860231267351602970">"Aktibatu NFC"</string>
     <string name="nfc_disclaimer_content" msgid="3066113577854565782">"NFC eginbideak datuak trukatzen ditu gailu honen eta inguruko beste gailu edo helburu batzuen artean (adibidez, ordainketa-terminalak, sarbide-irakurgailuak, eta iragarki edo etiketa interaktiboak)."</string>
     <string name="nfc_secure_settings_title" msgid="5153751163174916581">"Babestu NFC konexioak"</string>
-    <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"Onartu NFC ordainketak eta garraio publikoetan ordaintzeko aukera pantaila desblokeatuta dagoenean soilik"</string>
+    <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"Onartu NFC bidezko ordainketak eta garraio publikoetan ordaintzeko aukera pantaila desblokeatuta dagoenean soilik"</string>
     <string name="android_beam_settings_title" msgid="3083436415873738389">"Android Beam"</string>
     <string name="android_beam_on_summary" msgid="8068287225180474199">"Aplikazioaren edukia NFC bidez transmititzeko prest"</string>
     <string name="android_beam_off_summary" msgid="7365818039159364600">"Desaktibatuta"</string>
@@ -887,7 +889,7 @@
     <string name="wifi_menu_forget" msgid="7561140554450163075">"Ahaztu sarea"</string>
     <string name="wifi_menu_modify" msgid="4080178040721021101">"Aldatu sarea"</string>
     <string name="wifi_empty_list_wifi_off" msgid="272877164691346240">"Sare erabilgarriak ikusteko, aktibatu wifi-konexioa."</string>
-    <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"Wi-Fi sareak bilatzen…"</string>
+    <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"Wifi-sareak bilatzen…"</string>
     <string name="wifi_empty_list_user_restricted" msgid="2341613007817352431">"Ez duzu wifi-sarea aldatzeko baimenik."</string>
     <string name="wifi_more" msgid="3538241640407382185">"Gehiago"</string>
     <string name="wifi_setup_wps" msgid="6730131677695521321">"Konf. automatikoa (WPS)"</string>
@@ -928,8 +930,8 @@
     <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"5,0 GHz-ko banda hobetsia"</string>
     <string name="wifi_ap_2G" msgid="5793110086517338494">"2,4 GHz"</string>
     <string name="wifi_ap_5G" msgid="4584892544393675403">"5,0 GHz"</string>
-    <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"Aukeratu gutxienez banda bat wifi-sare publikorako:"</string>
-    <string name="wifi_ip_settings" msgid="4636102290236116946">"IP ezarpenak"</string>
+    <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"Aukeratu gutxienez banda bat wifi-gunerako:"</string>
+    <string name="wifi_ip_settings" msgid="4636102290236116946">"IParen ezarpenak"</string>
     <string name="wifi_privacy_settings" msgid="4462092795794247809">"Pribatutasuna"</string>
     <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"Ausaz aukeratutako MACa"</string>
     <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"Gehitu gailua"</string>
@@ -957,10 +959,10 @@
     <string name="wifi_dpp_device_found" msgid="6488461467496850841">"Gailua aurkitu da"</string>
     <string name="wifi_dpp_sharing_wifi_with_this_device" msgid="2540529164687476827">"Gailu honekin wifi-konexioa partekatzen…"</string>
     <string name="wifi_dpp_connecting" msgid="4229290407210299897">"Konektatzen…"</string>
-    <string name="wifi_dpp_share_hotspot" msgid="847987212473038179">"Partekatu sare publikoa"</string>
+    <string name="wifi_dpp_share_hotspot" msgid="847987212473038179">"Partekatu wifi-gunea"</string>
     <string name="wifi_dpp_lockscreen_title" msgid="3910665850075275963">"Egiaztatu zeu zarela"</string>
     <string name="wifi_dpp_wifi_password" msgid="8007558344032612455">"Wifi-sarearen pasahitza: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
-    <string name="wifi_dpp_hotspot_password" msgid="6172326289042241924">"Sare publikoaren pasahitza: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
+    <string name="wifi_dpp_hotspot_password" msgid="6172326289042241924">"Wifi-gunearen pasahitza: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
     <string name="wifi_dpp_add_device" msgid="1347056725253936358">"Gehitu gailu bat"</string>
     <string name="wifi_dpp_connect_network_using_qr_code" msgid="115993715600532357">"Konektatu sare honetara QR kode baten bidez"</string>
     <string name="retry" msgid="8500839563577344702">"Saiatu berriro"</string>
@@ -1026,7 +1028,7 @@
     <string name="wifi_subscribed_access_points_tab" msgid="7498765485953257229">"Harpidetzak"</string>
     <!-- no translation found for wifi_saved_access_points_tab (4677730543624191122) -->
     <skip />
-    <string name="wifi_advanced_settings_label" msgid="9147669851658738784">"IP ezarpenak"</string>
+    <string name="wifi_advanced_settings_label" msgid="9147669851658738784">"IParen ezarpenak"</string>
     <string name="wifi_advanced_not_available" msgid="5751084989400195009">"Erabiltzaile honek ezin ditu erabili Wi-Fi aurreratuaren ezarpenak"</string>
     <string name="wifi_ip_settings_menu_save" msgid="6557330818360425933">"Gorde"</string>
     <string name="wifi_ip_settings_menu_cancel" msgid="8098696509412462494">"Utzi"</string>
@@ -1054,28 +1056,28 @@
     <string name="wifi_p2p_cancel_connect_title" msgid="2465200999145769427">"Gonbidapena bertan behera utzi nahi duzu?"</string>
     <string name="wifi_p2p_cancel_connect_message" msgid="3752679335020392154">"<xliff:g id="PEER_NAME">%1$s</xliff:g> gailura konektatzeko gonbidapena bertan behera utzi nahi duzu?"</string>
     <string name="wifi_p2p_delete_group_message" msgid="3206660449067701089">"Taldea ahaztu?"</string>
-    <string name="wifi_hotspot_checkbox_text" msgid="12062341344410520">"Wifi-sare publikoa"</string>
+    <string name="wifi_hotspot_checkbox_text" msgid="12062341344410520">"Wifi-gunea"</string>
     <string name="wifi_hotspot_off_subtext" msgid="6177054857136221058">"Ez zara ari partekatzen ez Interneteko konexiorik ez edukirik beste gailuekin"</string>
-    <string name="wifi_hotspot_tethering_on_subtext" product="tablet" msgid="71421730039785897">"Tabletaren Interneteko konexioa partekatzen ari zara sare publiko bidez"</string>
-    <string name="wifi_hotspot_tethering_on_subtext" product="default" msgid="8914285514605049879">"Telefonoaren Interneteko konexioa partekatzen ari zara sare publiko bidez"</string>
-    <string name="wifi_hotspot_on_local_only_subtext" msgid="7415381343846704553">"Edukia partekatzen ari da aplikazioa. Interneteko konexioa partekatzeko, desaktibatu eta aktibatu berriro sare publikoa"</string>
+    <string name="wifi_hotspot_tethering_on_subtext" product="tablet" msgid="71421730039785897">"Tabletaren Interneteko konexioa partekatzen ari zara wifi-gunearen bidez"</string>
+    <string name="wifi_hotspot_tethering_on_subtext" product="default" msgid="8914285514605049879">"Telefonoaren Interneteko konexioa partekatzen ari zara wifi-gunearen bidez"</string>
+    <string name="wifi_hotspot_on_local_only_subtext" msgid="7415381343846704553">"Edukia partekatzen ari da aplikazioa. Interneteko konexioa partekatzeko, desaktibatu eta aktibatu berriro wifi-gunea"</string>
     <string name="wifi_hotspot_no_password_subtext" msgid="5400500962974373706">"Ez da ezarri pasahitzik"</string>
-    <string name="wifi_hotspot_name_title" msgid="6572202165400226127">"Sare publikoaren izena"</string>
+    <string name="wifi_hotspot_name_title" msgid="6572202165400226127">"Wifi-gunearen izena"</string>
     <string name="wifi_hotspot_name_summary_connecting" msgid="5176787959408511889">"<xliff:g id="WIFI_HOTSPOT_NAME">%1$s</xliff:g> aktibatzen…"</string>
     <string name="wifi_hotspot_name_summary_connected" msgid="8387768642326756749">"<xliff:g id="WIFI_HOTSPOT_NAME">%1$s</xliff:g> sarera konekta daitezke beste gailuak"</string>
-    <string name="wifi_hotspot_password_title" msgid="4289338152595154889">"Sare publikoaren pasahitza"</string>
+    <string name="wifi_hotspot_password_title" msgid="4289338152595154889">"Wifi-gunearen pasahitza"</string>
     <string name="wifi_hotspot_ap_band_title" msgid="3485744480410441949">"Sarbide-puntuaren banda"</string>
-    <string name="wifi_hotspot_footer_info_regular" msgid="3876006922622827363">"Erabili sare publikoa beste gailuentzako wifi-sare bat sortzeko. Sare publikoen bidez, Interneteko konexioa ematen da datu-konexioa erabilita. Baliteke datu-konexioa erabiltzeagatiko kostu gehigarriak ordaindu behar izatea."</string>
-    <string name="wifi_hotspot_footer_info_local_only" msgid="3339582350894639261">"Aplikazioek sare publikoak sor ditzakete edukia inguruko gailuekin partekatzeko."</string>
-    <string name="wifi_hotspot_auto_off_title" msgid="7416022590415189590">"Desaktibatu automatikoki sare publikoa"</string>
-    <string name="wifi_hotspot_auto_off_summary" msgid="3866769400624802105">"Wifi-sare publikoa desaktibatu egingo da ez badago gailurik konektatuta"</string>
-    <string name="wifi_tether_starting" msgid="7676952148471297900">"Sare publikoa aktibatzen…"</string>
-    <string name="wifi_tether_stopping" msgid="7478561853791953349">"Sare publikoa desaktibatzen…"</string>
+    <string name="wifi_hotspot_footer_info_regular" msgid="3876006922622827363">"Erabili wifi-gunea beste gailuentzako wifi-sare bat sortzeko. Wifi-guneen bidez, Interneteko konexioa ematen da datu-konexioa erabilita. Baliteke datu-konexioa erabiltzeagatiko kostu gehigarriak ordaindu behar izatea."</string>
+    <string name="wifi_hotspot_footer_info_local_only" msgid="3339582350894639261">"Aplikazioek wifi-guneak sor ditzakete edukia inguruko gailuekin partekatzeko."</string>
+    <string name="wifi_hotspot_auto_off_title" msgid="7416022590415189590">"Desaktibatu automatikoki wifi-gunea"</string>
+    <string name="wifi_hotspot_auto_off_summary" msgid="3866769400624802105">"Wifi-gunea desaktibatu egingo da ez badago gailurik konektatuta"</string>
+    <string name="wifi_tether_starting" msgid="7676952148471297900">"Wifi-gunea aktibatzen…"</string>
+    <string name="wifi_tether_stopping" msgid="7478561853791953349">"Wifi-gunea desaktibatzen…"</string>
     <string name="wifi_tether_enabled_subtext" msgid="7534760116478734006">"Aktibatu da <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
-    <string name="wifi_tether_failed_subtext" msgid="3501001612207106">"wifi-sare publiko eramangarriaren errorea gertatu da"</string>
-    <string name="wifi_tether_configure_ap_text" msgid="4081852770996455902">"Konfiguratu wifi-sare publikoa"</string>
-    <string name="wifi_hotspot_configure_ap_text" msgid="1000003286253019522">"Wi‑Fi publikoaren konfigurazioa"</string>
-    <string name="wifi_hotspot_configure_ap_text_summary" msgid="2303120188509955656">"AndroidAP WPA2 PSK sare publikoa"</string>
+    <string name="wifi_tether_failed_subtext" msgid="3501001612207106">"Wifi-gune eramangarriaren errorea gertatu da"</string>
+    <string name="wifi_tether_configure_ap_text" msgid="4081852770996455902">"Konfiguratu wifi-gunea"</string>
+    <string name="wifi_hotspot_configure_ap_text" msgid="1000003286253019522">"Wifi-gunearen konfigurazioa"</string>
+    <string name="wifi_hotspot_configure_ap_text_summary" msgid="2303120188509955656">"AndroidAP WPA2 PSK wifi-gunea"</string>
     <string name="wifi_tether_configure_ssid_default" msgid="1722238925876152663">"AndroidSarePublikoa"</string>
     <string name="wifi_calling_settings_title" msgid="626821542308601806">"Wi-Fi bidezko deiak"</string>
     <string name="wifi_calling_suggestion_title" msgid="1402265373543523970">"Zabaldu deiak egiteko aukera Wi‑Fi konexioarekin"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wifia"</item>
+    <item msgid="2271962426654621656">"Datu-konexioa"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Wifi-sarerik ez badago, erabili sare mugikorra"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Sare mugikorra erabilgarri ez badago, erabili wifi-konexioa"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Deitu wifi bidez. Wifi-konexioa galduz gero, eseki egingo da deia."</string>
@@ -1204,10 +1209,10 @@
     <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"Aktibatuta / Pantaila ez da itzaliko hari begira zauden bitartean"</string>
     <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"Desaktibatuta"</string>
     <string name="adaptive_sleep_description" msgid="812673735459170009">"Pantaila itzaltzea eragozten du hari begira zauden bitartean."</string>
-    <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Pantaila kontzientea eginbideak aurreko kamera erabiltzen du inor pantailari begira dagoen jakiteko. Gailuko eginbidea da, eta irudiak ez dira inoiz gordetzen, ez eta Google-ra bidaltzen ere."</string>
+    <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Pantaila kontzientea eginbideak aurreko kamera erabiltzen du inor pantailari begira dagoen jakiteko. Gailuan funtzionatzen du, eta irudiak ez dira inoiz gordetzen, ez eta Google-ra bidaltzen ere."</string>
     <string name="night_display_title" msgid="1305002424893349814">"Gaueko argia"</string>
     <string name="night_display_text" msgid="5330502493684652527">"Gaueko argiak tindu horikaraz janzten du pantaila. Horrela, ez zaizu horren nekagarria egingo argi gutxirekin pantailari begira egotea eta errazago hartuko duzu lo, gainera."</string>
-    <string name="night_display_auto_mode_title" msgid="8493573087102481588">"Ordutegia"</string>
+    <string name="night_display_auto_mode_title" msgid="8493573087102481588">"Programazioa"</string>
     <string name="night_display_auto_mode_never" msgid="2897444637217807088">"Bat ere ez"</string>
     <string name="night_display_auto_mode_custom" msgid="1400891076453963151">"Ordu jakinetan aktibatzen da"</string>
     <string name="night_display_auto_mode_twilight" msgid="4000162110017520674">"Ilunabarretik egunsentira"</string>
@@ -1241,13 +1246,13 @@
     <string name="wallpaper_suggestion_summary" msgid="4247262938988875842">"Pertsonalizatu pantaila"</string>
     <string name="wallpaper_settings_fragment_title" msgid="1503701065297188901">"Aukeratu horma-papera"</string>
     <string name="screensaver_settings_title" msgid="7720091234133721021">"Pantaila-babeslea"</string>
-    <string name="screensaver_settings_summary_either_long" msgid="6078038506795498288">"Kargatzen ari denean edo oinarrira konektatuta dagoenean"</string>
+    <string name="screensaver_settings_summary_either_long" msgid="6078038506795498288">"Kargatzen ari denean edo oinarrian dagoenean"</string>
     <string name="screensaver_settings_summary_either_short" msgid="2453772128682850053">"Bietako edozein"</string>
     <string name="screensaver_settings_summary_sleep" msgid="6097363596749362692">"Kargatzen ari denean"</string>
-    <string name="screensaver_settings_summary_dock" msgid="6297808146601570196">"Euskarrian dagoenean"</string>
+    <string name="screensaver_settings_summary_dock" msgid="6297808146601570196">"Oinarrian dagoenean"</string>
     <string name="screensaver_settings_summary_never" msgid="3995259444981620707">"Inoiz ez"</string>
     <string name="screensaver_settings_summary_off" msgid="6119947316484763131">"Desaktibatuta"</string>
-    <string name="screensaver_settings_disabled_prompt" msgid="1897518064782596947">"Telefonoa oinarrira konektatuta edo lo dagoenean zer gertatzen den kontrolatzeko, aktiba ezazu pantaila-babeslea."</string>
+    <string name="screensaver_settings_disabled_prompt" msgid="1897518064782596947">"Telefonoa oinarrian edo inaktibo dagoenean zer gertatzen den kontrolatzeko, aktibatu pantaila-babeslea."</string>
     <string name="screensaver_settings_when_to_dream" msgid="3763052013516826348">"Noiz abiarazi"</string>
     <string name="screensaver_settings_current" msgid="4017556173596361672">"Uneko pantaila-babeslea"</string>
     <string name="screensaver_settings_dream_start" msgid="3772227299054662550">"Abiarazi"</string>
@@ -1304,7 +1309,7 @@
     <string name="pin_failed" msgid="4877356137480446727">"SIMaren PIN kodearen eragiketak huts egin du!"</string>
     <string name="system_update_settings_list_item_title" msgid="1907497454722790033">"Sistemaren eguneratzeak"</string>
     <string name="system_update_settings_list_item_summary" msgid="3497456690691907873"></string>
-    <string name="firmware_version" msgid="547095584029938749">"Android bertsioa"</string>
+    <string name="firmware_version" msgid="547095584029938749">"Android-en bertsioa"</string>
     <string name="security_patch" msgid="483709031051932208">"Android-en segurtasunaren adabaki-maila"</string>
     <string name="model_info" msgid="1729765474260797594">"Modeloa"</string>
     <string name="model_summary" msgid="8781425868254352168">"Modeloa: %1$s"</string>
@@ -1337,10 +1342,10 @@
     <string name="status_msid_number" msgid="7808175928664357661">"MSID"</string>
     <string name="status_prl_version" msgid="5634561205739199042">"PRL bertsioa"</string>
     <string name="meid_multi_sim" msgid="7449892644113569529">"MEID (%1$d. SIM zirrikitua)"</string>
-    <string name="scanning_status_text_wifi_on_ble_on" msgid="6370507836346838473">"Wifi-sareen eta Bluetooth gailuen bilaketa aktibatuta daude"</string>
-    <string name="scanning_status_text_wifi_on_ble_off" msgid="8205014713732412608">"Wifi-sareen bilaketa aktibatuta dago; Bluetooth gailuen bilaketa, berriz, desaktibatuta"</string>
-    <string name="scanning_status_text_wifi_off_ble_on" msgid="7400522456303307057">"Bluetooth gailuen bilaketa aktibatuta dago; Wifi-sareen bilaketa, berriz, desaktibatuta"</string>
-    <string name="scanning_status_text_wifi_off_ble_off" msgid="8575026386237481457">"Wifi-sareen eta Bluetooth gailuen bilaketa desaktibatuta daude"</string>
+    <string name="scanning_status_text_wifi_on_ble_on" msgid="6370507836346838473">"Wifi-sareen bilaketa eta Bluetooth bidezko gailuen bilaketa aktibatuta daude"</string>
+    <string name="scanning_status_text_wifi_on_ble_off" msgid="8205014713732412608">"Wifi-sareen bilaketa aktibatuta dago; Bluetooth bidezko gailuen bilaketa, berriz, desaktibatuta"</string>
+    <string name="scanning_status_text_wifi_off_ble_on" msgid="7400522456303307057">"Bluetooth bidezko gailuen bilaketa aktibatuta dago; Wifi-sareen bilaketa, berriz, desaktibatuta"</string>
+    <string name="scanning_status_text_wifi_off_ble_off" msgid="8575026386237481457">"Wifi-sareen bilaketa eta Bluetooth bidezko gailuen bilaketa desaktibatuta daude"</string>
     <string name="status_meid_number" msgid="8756271256760479835">"MEID"</string>
     <string name="status_icc_id" msgid="9191847562997702709">"ICCID"</string>
     <string name="status_data_network_type" msgid="2344720457353394909">"Datuetarako sare mugikor mota"</string>
@@ -1353,7 +1358,7 @@
     <string name="status_roaming" msgid="5191044997355099561">"Ibiltaritza"</string>
     <string name="status_operator" msgid="6017986100643755390">"Sarea"</string>
     <string name="status_wifi_mac_address" msgid="3868452167971295995">"Wifi-sarearen MAC helbidea"</string>
-    <string name="status_bt_address" msgid="460568179311735657">"Bluetooth helbidea"</string>
+    <string name="status_bt_address" msgid="460568179311735657">"Gailua Bluetooth bidez konektatzeko helbidea"</string>
     <string name="status_serial_number" msgid="8257722124627415159">"Serie-zenbakia"</string>
     <string name="status_up_time" msgid="77128395333934087">"Berrabiarazi ondoren abian izandako denbora"</string>
     <string name="status_awake_time" msgid="1251959094010776954">"Aktibo egondako denbora"</string>
@@ -1452,7 +1457,7 @@
     <string name="storage_detail_other" msgid="9164851767437306618">"Beste datu batzuk"</string>
     <string name="storage_detail_system" msgid="6784247618772153283">"Sistema"</string>
     <string name="storage_detail_explore" msgid="8206900269596580264">"Arakatu <xliff:g id="NAME">^1</xliff:g>"</string>
-    <string name="storage_detail_dialog_other" msgid="5073511663616043370">"Hauek dira \"Beste fitxategi batzuk\" atalean gordetzen diren fitxategiak: aplikazioek gordetako fitxategi partekatuak, Internetetik edo Bluetooth konexioaren bidez deskargatutakoak, Android fitxategiak, etab.\n\n<xliff:g id="NAME">^1</xliff:g> honetan ikusgai dagoen edukia ikusteko, sakatu Arakatu."</string>
+    <string name="storage_detail_dialog_other" msgid="5073511663616043370">"Hauek dira \"Beste fitxategi batzuk\" atalean gordetzen diren fitxategiak: aplikazioek gordetako fitxategi partekatuak, Internet edo Bluetooth bidez deskargatutakoak, Android-eko fitxategiak, etab.\n\n<xliff:g id="NAME">^1</xliff:g> honetan ikusgai dagoen edukia ikusteko, sakatu Arakatu."</string>
     <string name="storage_detail_dialog_system" msgid="1472572861360014226">"Android-en <xliff:g id="VERSION">%s</xliff:g>. bertsioa exekutatzeko balio duten fitxategiak daude sisteman"</string>
     <string name="storage_detail_dialog_user" msgid="1663117417635010371">"Baliteke <xliff:g id="USER_0">^1</xliff:g> erabiltzaileak argazkiak, musika, aplikazioak edo bestelako datuak gorde izatea, memorian <xliff:g id="SIZE">^2</xliff:g> hartuta. \n\nXehetasunak ikusteko, aldatu <xliff:g id="USER_1">^1</xliff:g> erabiltzailearen kontura."</string>
     <string name="storage_wizard_init_title" msgid="3407283236421089014">"Konfiguratu <xliff:g id="NAME">^1</xliff:g> memoria"</string>
@@ -1560,13 +1565,13 @@
     <string name="error_mcc_not3" msgid="1333037488064427164">"MCC eremuak 3 digitu izan behar ditu."</string>
     <string name="error_mnc_not23" msgid="6738398924368729180">"MNC eremuak 2 edo 3 digitu izan behar ditu."</string>
     <string name="error_adding_apn_type" msgid="671634520340569678">"Operadoreak ez du onartzen %s motako APN identifikatzailerik."</string>
-    <string name="restore_default_apn" msgid="7195266404077471007">"APN ezarpen lehenetsiak leheneratzen."</string>
+    <string name="restore_default_apn" msgid="7195266404077471007">"APNaren ezarpen lehenetsiak leheneratzen."</string>
     <string name="menu_restore" msgid="3799288817317293115">"Berrezarri balio lehenetsiak"</string>
-    <string name="restore_default_apn_completed" msgid="5671734152740058937">"APN ezarpen lehenetsiak berrezarri dira."</string>
+    <string name="restore_default_apn_completed" msgid="5671734152740058937">"APNaren ezarpen lehenetsiak berrezarri dira."</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"Berrezartzeko aukerak"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"Sarea, aplikazioak edota gailua berrezar daitezke"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"Berrezarri wifi, Bluetooth eta sare mugikorrak"</string>
-    <string name="reset_network_desc" msgid="4982633363916261109">"Hori eginez gero, sare guztien ezarpenak berrezarri egingo dira, besteak beste: \n\n"<li>"Wifia"</li>\n<li>"Datu-konexioa"</li>\n<li>"Bluetooth-a"</li></string>
+    <string name="reset_network_desc" msgid="4982633363916261109">"Hori eginez gero, sare guztien ezarpenak berrezarriko dira, besteak beste: \n\n"<li>"Wifia"</li>\n<li>"Datu-konexioa"</li>\n<li>"Bluetooth-a"</li></string>
     <string name="reset_esim_title" msgid="7630781767040831893">"Ezabatu deskargatutako SIMen edukia"</string>
     <string name="reset_esim_desc" msgid="433226911566802">"Ordezko SIM txartelak deskargatzeko, jarri operadorearekin harremanetan. Ez da utziko bertan behera mugikorraren zerbitzu-planik."</string>
     <string name="reset_network_button_text" msgid="4293271046867912819">"Berrezarri ezarpenak"</string>
@@ -1606,14 +1611,14 @@
     <string name="call_settings_title" msgid="5033906789261282752">"Dei-ezarpenak"</string>
     <string name="call_settings_summary" msgid="2119161087671450035">"Konfiguratu erantzungailua, dei-desbideratzea, deia zain uzteko eginbidea, deien identifikazio-zerbitzua."</string>
     <string name="tether_settings_title_usb" msgid="4265582654602420357">"Konexioa partekatzea (USB)"</string>
-    <string name="tether_settings_title_wifi" msgid="2060965130234484613">"Sare publiko eramangarria"</string>
+    <string name="tether_settings_title_wifi" msgid="2060965130234484613">"Wifi-gune eramangarria"</string>
     <string name="tether_settings_title_bluetooth" msgid="1999590158102569959">"Konexioa partekatzea (Bluetooth)"</string>
     <string name="tether_settings_title_usb_bluetooth" msgid="1159128764162788159">"Konexioa partekatzea"</string>
-    <string name="tether_settings_title_all" msgid="6935843543433954181">"Sare publikoa eta konexioa partekatzea"</string>
-    <string name="tether_settings_summary_hotspot_on_tether_on" msgid="1289593649526514499">"Sare publikoa aktibatuta, konexioa partekatzea"</string>
-    <string name="tether_settings_summary_hotspot_on_tether_off" msgid="8010689354668285422">"Sare publikoa aktibatuta"</string>
+    <string name="tether_settings_title_all" msgid="6935843543433954181">"Wifi-gunea eta konexioa partekatzea"</string>
+    <string name="tether_settings_summary_hotspot_on_tether_on" msgid="1289593649526514499">"Wifi-gunea aktibatuta, konexioa partekatzea"</string>
+    <string name="tether_settings_summary_hotspot_on_tether_off" msgid="8010689354668285422">"Wifi-gunea aktibatuta dago"</string>
     <string name="tether_settings_summary_hotspot_off_tether_on" msgid="1349909238672649877">"Konexioa partekatzea"</string>
-    <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"Datu-aurrezlea aktibatuta badago, ezin da partekatu konexioa, ezta sare publiko eramangarriak erabili ere"</string>
+    <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"Datu-aurrezlea aktibatuta badago, ezin da partekatu konexioa, ezta wifi-gune eramangarriak erabili ere"</string>
     <string name="usb_title" msgid="7480927657535578688">"USB"</string>
     <string name="usb_tethering_button_text" msgid="6242228383142012332">"Konexioa partekatzea (USB)"</string>
     <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"Partekatu telefonoaren Interneteko konexioa USB bidez"</string>
@@ -1624,7 +1629,7 @@
     <string name="bluetooth_tethering_off_subtext_config" msgid="3981528184780083266">"<xliff:g id="DEVICE_NAME">%1$d</xliff:g> gailuaren Interneteko konexioa partekatzen ari zara Bluetooth bidez"</string>
     <string name="bluetooth_tethering_overflow_error" msgid="6946561351369376943">"Ezin da <xliff:g id="MAXCONNECTION">%1$d</xliff:g> gailurekin baino gehiagorekin konexioa partekatu."</string>
     <string name="bluetooth_untether_blank" msgid="5428300773782256084">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailuko konexioa amaituko da."</string>
-    <string name="tethering_footer_info" msgid="8019555174339154124">"Erabili sare publikoa eta konexioa partekatzea beste gailuei Interneteko konexioa emateko zure datu-konexioaren bidez. Halaber, aplikazioek sare publikoak sor ditzakete, edukia inguruko gailuekin partekatzeko."</string>
+    <string name="tethering_footer_info" msgid="8019555174339154124">"Erabili wifi-gunea eta konexioa partekatzea beste gailuei Interneteko konexioa emateko zure datu-konexioaren bidez. Halaber, aplikazioek wifi-guneak sor ditzakete, edukia inguruko gailuekin partekatzeko."</string>
     <string name="tethering_help_button_text" msgid="7653022000284543996">"Laguntza"</string>
     <string name="network_settings_title" msgid="8516526011407061679">"Sare mugikorra"</string>
     <string name="manage_mobile_plan_title" msgid="3312016665522553062">"Mugikorraren plana"</string>
@@ -1655,11 +1660,11 @@
     <string name="location_no_recent_accesses" msgid="6289916310397279890">"Ez dago kokapena berriki atzitu duen aplikaziorik"</string>
     <string name="location_high_battery_use" msgid="7177199869979522663">"Bateria-erabilera handia"</string>
     <string name="location_low_battery_use" msgid="5030448574501435888">"Bateria-erabilera txikia"</string>
-    <string name="location_scanning_screen_title" msgid="7663329319689413454">"Wifi eta Bluetooth bidezko bilaketa"</string>
+    <string name="location_scanning_screen_title" msgid="7663329319689413454">"Wifi-sareen bilaketa eta Bluetooth bidezko gailuen bilaketa"</string>
     <string name="location_scanning_wifi_always_scanning_title" msgid="6750542206763112172">"Wifi-sareen bilaketa"</string>
     <string name="location_scanning_wifi_always_scanning_description" msgid="4956048135941851712">"Eman wifi-sareak edozein unetan bilatzeko baimena aplikazioei eta zerbitzuei, baita wifi-konexioa desaktibatuta dagoenean ere. Kokapenean oinarritutako eginbideak eta zerbitzuak hobetzeko erabil daiteke hori, besteak beste."</string>
-    <string name="location_scanning_bluetooth_always_scanning_title" msgid="196241746742607453">"Bluetooth gailuak bilatzea"</string>
-    <string name="location_scanning_bluetooth_always_scanning_description" msgid="3796673798637848690">"Eman inguruko gailuak edozein unetan bilatzeko baimena aplikazioei eta zerbitzuei, baita Bluetooth konexioa desaktibatuta dagoenean ere. Kokapenean oinarritutako eginbideak eta zerbitzuak hobetzeko erabil daiteke hori, besteak beste."</string>
+    <string name="location_scanning_bluetooth_always_scanning_title" msgid="196241746742607453">"Bluetooth bidezko gailuen bilaketa"</string>
+    <string name="location_scanning_bluetooth_always_scanning_description" msgid="3796673798637848690">"Eman inguruko gailuak edozein unetan bilatzeko baimena aplikazioei eta zerbitzuei, baita Bluetooth-a desaktibatuta dagoenean ere. Kokapenean oinarritutako eginbideak eta zerbitzuak hobetzeko erabil daiteke hori, besteak beste."</string>
     <string name="managed_profile_location_services" msgid="224925483299159541">"Lanerako kokapen-zerbitzuak"</string>
     <string name="location_network_based" msgid="1535812159327454835">"Wi‑Fi eta sare mugikor bidezko kokapena"</string>
     <string name="location_neighborhood_level" msgid="8459352741296587916">"Utzi aplikazioei zure kokapena bizkorrago zehazteko Google-ren kokapen-zerbitzua erabiltzen. Kokapen-datu anonimoak bildu eta Google-ra bidaliko dira."</string>
@@ -1684,7 +1689,7 @@
     <string name="contributors_title" msgid="6800028420806884340">"Kolaboratzaileak"</string>
     <string name="manual" msgid="5431859421432581357">"Eskuliburua"</string>
     <string name="regulatory_labels" msgid="380968489247381025">"Legezko etiketak"</string>
-    <string name="safety_and_regulatory_info" msgid="7113766428000920132">"Segurtasunaren eta legeen esku-liburua"</string>
+    <string name="safety_and_regulatory_info" msgid="7113766428000920132">"Segurtasunaren eta legeen eskuliburua"</string>
     <string name="copyright_title" msgid="3847703367689932190">"Copyrighta"</string>
     <string name="license_title" msgid="7582145947873528540">"Lizentzia"</string>
     <string name="terms_title" msgid="1804549588198223771">"Zehaztapenak eta baldintzak"</string>
@@ -2056,10 +2061,10 @@
     <string name="accessibility_screen_magnification_summary" msgid="3363006902079431772"><b>"Zooma aplikatzeko"</b>", sakatu pantaila bizkor hiru aldiz.\n"<ul><li>"Gora edo behera egiteko, arrastatu gutxienez bi hatz."</li>\n<li>"Zooma doitzeko, atximurkatu pantaila gutxienez bi hatzekin."</li></ul>\n\n<b>"Zooma une batez bakarrik aplikatzeko"</b>", sakatu pantaila bizkor hiru aldiz eta, hirugarren aldian, utzi hatza pantailan jarrita.\n"<ul><li>"Pantailan mugitzeko, arrastatu hatza."</li>\n<li>"Zooma aplikatzeari uzteko, altxatu hatza."</li></ul>\n\n"Zooma ezin da aplikatu ez teklatuan ez nabigazio-barran."</string>
     <string name="accessibility_screen_magnification_navbar_summary" msgid="4726360285256503132">"Lupa aktibatuta dagoenean, sakatu pantailaren behealdeko Erabilerraztasuna botoia pantaila azkar handitzeko.\n\n"<b>"Zooma aplikatzeko"</b>", sakatu Erabilerraztasuna botoia eta sakatu pantailako edozein toki.\n"<ul><li>"Gora edo behera egiteko, arrastatu gutxienez bi hatz."</li>\n<li>"Zooma doitzeko, atximurkatu pantaila gutxienez bi hatzekin."</li></ul>\n\n<b>"Zooma une batez bakarrik aplikatzeko"</b>", sakatu Erabilerraztasuna botoia eta eduki sakatuta pantailako puntu bat.\n"<ul><li>"Pantailan mugitzeko, arrastatu hatza."</li>\n<li>"Zooma aplikatzeari uzteko, altxatu hatza."</li></ul>\n\n"Zooma ezin da aplikatu ez teklatuan ez nabigazio-barran."</string>
     <string name="accessibility_screen_magnification_navbar_configuration_warning" msgid="6477234309484795550">"Erabilerraztasuna botoia labur sakatuta \"<xliff:g id="SERVICE">%1$s</xliff:g>\" aukera aktibatzen da. Lupa aplikatzeko, eduki sakatuta Erabilerraztasuna botoia eta, ondoren, hautatu lupa."</string>
-    <string name="accessibility_global_gesture_preference_title" msgid="3842279082831426816">"Bolumen-teklen lasterbidea"</string>
+    <string name="accessibility_global_gesture_preference_title" msgid="3842279082831426816">"Bolumen-botoien lasterbidea"</string>
     <string name="accessibility_shortcut_service_title" msgid="3516052294376744060">"Lasterbideari esleitutako zerbitzua"</string>
     <string name="accessibility_shortcut_service_on_lock_screen_title" msgid="1279441617927949980">"Baimendu pantaila blokeatuan"</string>
-    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"Lasterbidea aktibatuta dagoenean, bi bolumen-teklak hiru segundoz sakatuta abiarazten da erabilerraztasun-eginbidea."</string>
+    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"Lasterbidea aktibatuta dagoenean, bi bolumen-botoiak hiru segundoz sakatuta abiarazten da erabilerraztasun-eginbidea."</string>
     <string name="accessibility_toggle_high_text_contrast_preference_title" msgid="5652244684961877255">"Kontraste handiko testua"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"Eguneratu auto. pantaila-handiagotzea"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"Eguneratu handiagotzea aplik. batetik bestera pasatzean."</string>
@@ -2229,7 +2234,7 @@
     <string name="power_discharge_remaining" msgid="3461915627093471868">"Geratzen den denbora: <xliff:g id="REMAIN">%1$s</xliff:g>"</string>
     <string name="power_charge_remaining" msgid="2730510256218879651">"Kargatu arteko denbora: <xliff:g id="UNTIL_CHARGED">%1$s</xliff:g>"</string>
     <string name="background_activity_title" msgid="7207836362312111483">"Atzeko planoa erabiltzeko muga"</string>
-    <string name="background_activity_summary" msgid="582372194738538145">"Baimendu aplikazioari atzeko planoan funtzionatzea"</string>
+    <string name="background_activity_summary" msgid="582372194738538145">"Eman atzeko planoan exekutatzeko baimena aplikazioari"</string>
     <string name="background_activity_summary_disabled" msgid="457944930942085876">"Aplikazioak ez du baimenik atzeko planoan exekutatzeko"</string>
     <string name="background_activity_summary_whitelisted" msgid="4713321059375873828">"Ezin da mugatu atzeko planoko erabilera"</string>
     <string name="background_activity_warning_dialog_title" msgid="2170790412855899678">"Atzeko planoko jarduerak mugatu nahi dituzu?"</string>
@@ -2443,12 +2448,12 @@
     <string name="process_dex2oat_label" msgid="8249082119748556085">"Aplikazio-optimizazioa"</string>
     <string name="battery_saver" msgid="3989710213758938398">"Bateria-aurrezlea"</string>
     <string name="battery_saver_auto_title" msgid="4158659069641849952">"Aktibatu automatikoki"</string>
-    <string name="battery_saver_auto_no_schedule" msgid="739814529432092706">"Ordutegirik ez"</string>
+    <string name="battery_saver_auto_no_schedule" msgid="739814529432092706">"Programaziorik ez"</string>
     <string name="battery_saver_auto_routine" msgid="886514412067906980">"Zure ohituretan oinarrituta"</string>
     <string name="battery_saver_auto_percentage" msgid="5791982309331921556">"Bateria-mailaren ehunekoan oinarrituta"</string>
     <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"Bateria kargatzeko ohiko ordua iritsi aurretik bateria agortzeko arriskua badago aktibatzen da bateria-aurrezlea"</string>
     <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"Bateria-maila <xliff:g id="PERCENT">%1$s</xliff:g> denean aktibatuko da"</string>
-    <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"Ezarri ordutegia"</string>
+    <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"Ezarri programazioa"</string>
     <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"Desaktibatu guztiz kargatu ondoren"</string>
     <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"Telefonoaren bateria <xliff:g id="PERCENT">%1$s</xliff:g> denean, desaktibatu egiten da bateria-aurrezlea"</string>
     <string name="battery_saver_sticky_description_new" product="tablet" msgid="3284967694001857194">"Tabletaren bateria <xliff:g id="PERCENT">%1$s</xliff:g> denean, desaktibatu egiten da bateria-aurrezlea"</string>
@@ -2486,8 +2491,8 @@
     <string name="menu_duration_6h" msgid="6169009210638008417">"6 ordu"</string>
     <string name="menu_duration_12h" msgid="1435242738163843797">"12 ordu"</string>
     <string name="menu_duration_1d" msgid="6476370834372352174">"1 egun"</string>
-    <string name="menu_show_system" msgid="6315865548558708248">"Erakutsi sistema"</string>
-    <string name="menu_hide_system" msgid="8457027118873733782">"Ezkutatu sistema"</string>
+    <string name="menu_show_system" msgid="6315865548558708248">"Erakutsi sistemaren prozesuak"</string>
+    <string name="menu_hide_system" msgid="8457027118873733782">"Ezkutatu sistemaren prozesuak"</string>
     <string name="menu_show_percentage" msgid="6983272380729890884">"Erakutsi ehunekoak"</string>
     <string name="menu_use_uss" msgid="3765054705208926803">"Erabili USS"</string>
     <string name="menu_proc_stats_type" msgid="2680179749566186247">"Estatistika mota"</string>
@@ -2535,7 +2540,7 @@
     <string name="credentials_settings_not_available" msgid="5490259681690183274">"Erabiltzaile honek ez dauka kredentzialik"</string>
     <string name="credential_for_vpn_and_apps" msgid="2462642486949593841">"VPN konexioarekin eta aplikazioekin erabiltzeko instalatuta"</string>
     <string name="credential_for_wifi" msgid="2903295786961726388">"Wi-Fi konexioarekin erabiltzeko instalatuta"</string>
-    <string name="credentials_reset_hint" msgid="3484350477764088169">"Eduki guztiak kendu?"</string>
+    <string name="credentials_reset_hint" msgid="3484350477764088169">"Eduki guztiak kendu nahi dituzu?"</string>
     <string name="credentials_erased" msgid="7287088033523869085">"Kredentz. biltegia ezabatu da."</string>
     <string name="credentials_not_erased" msgid="9137227570738627637">"Ezin izan da kredentzialen biltegia ezabatu."</string>
     <string name="usage_access_title" msgid="7981321142726540574">"Erabilera-baimena dutenak"</string>
@@ -2558,7 +2563,7 @@
     <string name="backup_erase_dialog_title" msgid="8178424339104463014"></string>
     <string name="backup_erase_dialog_message" msgid="8767843355330070902">"Wifi-sareen pasahitzen, laster-marken, bestelako ezarpenen eta aplikazioetako datuen babeskopiak egiteari utzi eta Google-ren zerbitzarietako kopia guztiak ezabatu nahi dituzu?"</string>
     <string name="fullbackup_erase_dialog_message" msgid="2588536036471144070">"Gailuko datuen (adibidez, Wi-Fi pasahitzak eta deien historia) eta aplikazioetako datuen (besteak beste, ezarpenak eta aplikazioek gordetako fitxategiak) babeskopiak egiteari utzi nahi diozu eta urruneko zerbitzarietako kopia guztiak ezabatu nahi dituzu?"</string>
-    <string name="fullbackup_data_summary" msgid="406274198094268556">"Egin babeskopiak automatikoki urrunetik, bai gailuetako datuenak (esaterako, Wi-Fi sareetako pasahitzak eta deien historia), bai aplikazioetako datuenak (esaterako, ezarpenak eta aplikazioek gordetako fitxategiak).\n\nBabeskopiak automatikoki egiteko aukera aktibatzean, gailuko eta aplikazioetako datuak urrunetik gordetzen dira aldizka. Aplikazioetako datuak aplikazioek gordetako edozein datu izan daitezke (garatzailearen ezarpenen arabera), eta kontuzkoak izan litezkeen datuak ere sar daitezke (adibidez, kontaktuak, mezuak eta argazkiak)."</string>
+    <string name="fullbackup_data_summary" msgid="406274198094268556">"Egin babeskopiak automatikoki urrunetik, bai gailuetako datuenak (esaterako, Wi-Fi sareetako pasahitzak eta deien historia), bai aplikazioetako datuenak (esaterako, ezarpenak eta aplikazioek gordetako fitxategiak).\n\nBabeskopiak automatikoki egiteko aukera aktibatzean, gailuko eta aplikazioetako datuak urrunetik gordetzen dira aldizka. Aplikazioetako datuak aplikazioek gordetako edozein datu izan daitezke (garatzaileen ezarpenen arabera), eta kontuzkoak izan litezkeen datuak ere sar daitezke (adibidez, kontaktuak, mezuak eta argazkiak)."</string>
     <string name="device_admin_settings_title" msgid="2074319456047334589">"Gailua administratzeko aplikazioaren ezarpenak"</string>
     <string name="active_device_admin_msg" msgid="6929247869516924549">"Gailua administratzeko aplikazioa"</string>
     <string name="remove_device_admin" msgid="4413438593788336400">"Desaktibatu gailua administratzeko aplikazioa"</string>
@@ -2624,8 +2629,8 @@
     <string name="remove_account_label" msgid="5885425720323823387">"Kendu kontua"</string>
     <string name="header_add_an_account" msgid="8482614556580804956">"Gehitu kontu bat"</string>
     <string name="really_remove_account_title" msgid="4166512362915154319">"Kontua kendu nahi duzu?"</string>
-    <string name="really_remove_account_message" product="tablet" msgid="7403843371045856719">"Kontua kentzen baduzu, bere mezu, kontaktu eta bestelako datu guztiak tabletatik ezabatuko dira!"</string>
-    <string name="really_remove_account_message" product="default" msgid="8951224626153163914">"Kontua kentzen baduzu, bere mezu, kontaktu eta bestelako datu guztiak telefonotik ezabatuko dira!"</string>
+    <string name="really_remove_account_message" product="tablet" msgid="7403843371045856719">"Kontua kentzen baduzu, hartako mezu, kontaktu eta bestelako datu guztiak tabletatik ezabatuko dira!"</string>
+    <string name="really_remove_account_message" product="default" msgid="8951224626153163914">"Kontua kentzen baduzu, hartako mezu, kontaktu eta bestelako datu guztiak telefonotik ezabatuko dira!"</string>
     <string name="really_remove_account_message" product="device" msgid="3751798556257519916">"Kontua kentzen baduzu, bertako mezu, kontaktu eta bestelako datu guztiak ezabatuko dira gailutik!"</string>
     <string name="remove_account_failed" msgid="491458185327106966">"Administratzaileak ez du eman aldaketa egiteko baimena"</string>
     <string name="cant_sync_dialog_title" msgid="5483419398223189881">"Ezin da eskuz sinkronizatu"</string>
@@ -2644,7 +2649,7 @@
     <string name="misc_files_selected_count_bytes" msgid="3752262902203465861">"<xliff:g id="NUMBER">%1$s</xliff:g>/<xliff:g id="TOTAL">%2$s</xliff:g>"</string>
     <string name="select_all" msgid="452240217913675728">"Hautatu guztiak"</string>
     <string name="data_usage_summary_title" msgid="7288431048564861043">"Datuen erabilera"</string>
-    <string name="data_usage_app_summary_title" msgid="8277327968906074983">"Datu-konexioa eta wifi-konexioa"</string>
+    <string name="data_usage_app_summary_title" msgid="8277327968906074983">"Datu- eta wifi-konexioa"</string>
     <string name="data_usage_accounting" msgid="4681642832010140640">"Beharbada operadoreak zenbatzen duen datu kopurua eta gailuak zenbatzen duena ez datoz bat."</string>
     <string name="data_usage_app" msgid="4995297799363021198">"Aplikazioen erabilera"</string>
     <string name="data_usage_app_info_label" msgid="5358288895158910477">"APLIKAZIOARI BURUZKO INFORMAZIOA"</string>
@@ -2666,7 +2671,7 @@
     <string name="data_usage_cellular_data_summary" msgid="9162777397135709280">"Pausatu mugara iristean"</string>
     <string name="account_settings_menu_auto_sync" msgid="2673669556006027506">"Sinkronizatu datuak automatikoki"</string>
     <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"Sinkr. datu pertsonalak auto."</string>
-    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Sinkr. laneko datuak auto."</string>
+    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Sinkronizatu laneko datuak auto."</string>
     <string name="data_usage_change_cycle" msgid="447761920472170031">"Aldatu zikloa…"</string>
     <string name="data_usage_pick_cycle_day" msgid="6319750879145917066">"Datuen erabilera-zikloa berrezarri beharreko hilabeteko eguna:"</string>
     <string name="data_usage_empty" msgid="7981405723435034032">"Ez dago epean daturik erabili duen aplikaziorik."</string>
@@ -2917,7 +2922,7 @@
     <string name="nfc_payment_app_and_desc" msgid="102312684211458190">"<xliff:g id="APP">%1$s</xliff:g> - <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="nfc_payment_use_default" msgid="3098724195746409476">"Erabili lehenetsia"</string>
     <string name="nfc_payment_favor_default" msgid="7555356982142464260">"Beti"</string>
-    <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Ordaintzeko beste aplikazio bat zabalik egotean ez ezik"</string>
+    <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Ordaintzeko beste aplikazio bat irekita badago izan ezik"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"\"Ukitu eta ordaindu\" terminalean, ordaindu honekin:"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Terminalean ordaintzea"</string>
     <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Konfiguratu ordaintzeko aplikazioa. Ondoren, jarri telefonoaren atzeko aldea ukipen gabeko sistemaren ikurra duen terminalaren aurrean."</string>
@@ -3029,7 +3034,7 @@
     <string name="network_dashboard_title" msgid="8288134139584687806">"Sareak eta Internet"</string>
     <string name="network_dashboard_summary_mobile" msgid="5560545061217580626">"mugikorra"</string>
     <string name="network_dashboard_summary_data_usage" msgid="4695629715072542102">"datuen erabilera"</string>
-    <string name="network_dashboard_summary_hotspot" msgid="3928610802321995214">"sare publikoa"</string>
+    <string name="network_dashboard_summary_hotspot" msgid="3928610802321995214">"wifi-gunea"</string>
     <string name="connected_devices_dashboard_title" msgid="7795222675849060444">"Konektatutako gailuak"</string>
     <string name="connected_devices_dashboard_summary" msgid="1072664369515033179">"Bluetooth, gidatze modua, NFC"</string>
     <string name="connected_devices_dashboard_no_nfc_summary" msgid="2610085597733526722">"Bluetooth, gidatze modua"</string>
@@ -3097,7 +3102,7 @@
     <string name="keywords_imei_info" msgid="4325847870422053408">"imei, meid, min, prl bertsioa, imei sv"</string>
     <string name="keywords_sim_status" msgid="3852088576719874387">"sarea, sare mugikorraren egoera, zerbitzuaren egoera, seinalearen indarra, sare mugikor mota, ibiltaritza, iccid"</string>
     <string name="keywords_model_and_hardware" msgid="2743197096210895251">"serie-zenbakia, hardwarearen bertsioa"</string>
-    <string name="keywords_android_version" msgid="4842749998088987740">"android-en segurtasunaren adabaki-maila, oinarri-bandaren bertsioa, kernelaren bertsioa"</string>
+    <string name="keywords_android_version" msgid="4842749998088987740">"android-en segurtasunaren adabaki-maila, oinarri-bandaren bertsioa, kernel bertsioa"</string>
     <string name="keywords_dark_ui_mode" msgid="1027966176887770318">"gai, argi, modu, ilun"</string>
     <string name="keywords_financial_apps_sms_access" msgid="3236014691838121857">"finantza-aplikazioa, SMSa, baimena"</string>
     <string name="keywords_systemui_theme" msgid="9150908170417305866">"gai iluna"</string>
@@ -3110,7 +3115,7 @@
     <string name="keywords_display_adaptive_sleep" msgid="1695357782432822811">"ilundu pantaila, pantaila ilundu, ezarri inaktibo, inaktibo ezarri, bateria, denbora-muga, arreta, pantaila, bistaratzea, jarduera eza, inaktibo"</string>
     <string name="keywords_auto_rotate" msgid="4320791369951647513">"biratu, irauli, errotazioa, bertikala, horizontala, orientazioa"</string>
     <string name="keywords_system_update_settings" msgid="4419971277998986067">"bertsio-berritu, android"</string>
-    <string name="keywords_zen_mode_settings" msgid="4103819458182535493">"ez molestatu, ordutegia, jakinarazpenak, blokeatu, isilik, dardara, inaktibo ezarri, lantokia, arreta, soinua, desaktibatu audioa, eguna, asteguna, asteburua, asteguneko gaua, gertaera"</string>
+    <string name="keywords_zen_mode_settings" msgid="4103819458182535493">"ez molestatu, programazioa, jakinarazpenak, blokeatu, isilik, dardara, inaktibo ezarri, lantokia, arreta, soinua, desaktibatu audioa, eguna, asteguna, asteburua, asteguneko gaua, gertaera"</string>
     <string name="keywords_screen_timeout" msgid="4328381362313993666">"pantaila, blokeatzeko denbora, denbora-muga, pantaila blokeatua"</string>
     <string name="keywords_storage_settings" msgid="6422454520424236476">"memoria, cachea, datuak, ezabatu, garbitu, tokia egin, tokia"</string>
     <string name="keywords_bluetooth_settings" msgid="1152229891590622822">"konektatuta, gailua, aurikularrak, entzungailua, bozgorailua, hari gabekoak, parekatu, musika, multimedia-edukia"</string>
@@ -3118,7 +3123,7 @@
     <string name="keywords_assist_input" msgid="8392362788794886564">"lehenetsia, laguntzailea"</string>
     <string name="keywords_default_payment_app" msgid="845369409578423996">"ordaindu, lehenetsia"</string>
     <string name="keywords_ambient_display" msgid="8835182491798487184">"jasotako jakinarazpena"</string>
-    <string name="keywords_hotspot_tethering" msgid="1723591462602613867">"usb konexioa partekatu, bluetooth konexioa partekatu, wifi sare publikoa"</string>
+    <string name="keywords_hotspot_tethering" msgid="1723591462602613867">"usb konexioa partekatu, bluetooth bidezko konexioa partekatu, wifi-gunea"</string>
     <string name="keywords_touch_vibration" msgid="2081175517528255224">"ukipena, dardara, pantaila, sentikortasuna"</string>
     <string name="keywords_ring_vibration" msgid="4210509151866460210">"ukipena, dardara, telefonoa, deia, sentikortasuna, tonua"</string>
     <string name="keywords_notification_vibration" msgid="1077515502086745166">"ukipena, dardara, sentikortasuna"</string>
@@ -3172,17 +3177,17 @@
     <string name="zen_mode_behavior_total_silence" msgid="371498357539257671">"Isiltasun osoa"</string>
     <string name="zen_mode_behavior_no_sound_except" msgid="8894465423364103198">"Ez egin soinurik. Salbuespena: <xliff:g id="CATEGORIES">%1$s</xliff:g>."</string>
     <string name="zen_mode_behavior_alarms_only" msgid="8406622989983047562">"Alarmen eta multimedia-edukiaren soinuak soilik"</string>
-    <string name="zen_mode_automation_settings_title" msgid="3916960043054489008">"Ordutegiak"</string>
-    <string name="zen_mode_delete_automatic_rules" msgid="2455264581527305755">"Ezabatu ordutegiak"</string>
+    <string name="zen_mode_automation_settings_title" msgid="3916960043054489008">"Programazioak"</string>
+    <string name="zen_mode_delete_automatic_rules" msgid="2455264581527305755">"Ezabatu programazioak"</string>
     <string name="zen_mode_schedule_delete" msgid="7786092652527516740">"Ezabatu"</string>
     <string name="zen_mode_rule_name_edit" msgid="5479435215341745578">"Editatu"</string>
-    <string name="zen_mode_automation_settings_page_title" msgid="3001783354881078983">"Ordutegiak"</string>
-    <string name="zen_mode_automatic_rule_settings_page_title" msgid="5272888746413504692">"Antolatu"</string>
-    <string name="zen_mode_schedule_category_title" msgid="1936785755444711221">"Ordutegia"</string>
+    <string name="zen_mode_automation_settings_page_title" msgid="3001783354881078983">"Programazioak"</string>
+    <string name="zen_mode_automatic_rule_settings_page_title" msgid="5272888746413504692">"Programatu"</string>
+    <string name="zen_mode_schedule_category_title" msgid="1936785755444711221">"Programazioa"</string>
     <string name="zen_mode_automation_suggestion_title" msgid="4921779962633710347">"Isilarazi telefonoa ordu jakinetan"</string>
     <string name="zen_mode_automation_suggestion_summary" msgid="2709837472884371037">"Ezarri ez molestatzeko moduaren arauak"</string>
-    <string name="zen_mode_schedule_title" msgid="5275268813192802631">"Ordutegia"</string>
-    <string name="zen_mode_use_automatic_rule" msgid="446326253915861824">"Erabili ordutegia"</string>
+    <string name="zen_mode_schedule_title" msgid="5275268813192802631">"Programazioa"</string>
+    <string name="zen_mode_use_automatic_rule" msgid="446326253915861824">"Erabili programazioa"</string>
     <string name="zen_mode_option_important_interruptions" msgid="5173944276846940149">"Lehentasuna dutenak soilik"</string>
     <string name="zen_mode_option_alarms" msgid="4843278125235203076">"Alarmak soilik"</string>
     <string name="zen_mode_option_no_interruptions" msgid="4723700274519260852">"Isiltasun osoa"</string>
@@ -3192,11 +3197,11 @@
     <string name="zen_mode_settings_category" msgid="5601680733422424922">"Ez molestatzeko modua aktibatuta dagoenean"</string>
     <string name="zen_mode_restrict_notifications_title" msgid="7486753018073540477">"Murriztu jakinarazpenak"</string>
     <string name="zen_mode_restrict_notifications_mute" msgid="2673665450311184875">"Ez egin soinurik jakinarazpenak jasotzean"</string>
-    <string name="zen_mode_restrict_notifications_mute_summary" msgid="1696217042353376674">"Jakinarazpenak ikusiko dituzu pantailan"</string>
+    <string name="zen_mode_restrict_notifications_mute_summary" msgid="1696217042353376674">"Jakinarazpenak pantailan ikusiko dituzu"</string>
     <string name="zen_mode_restrict_notifications_mute_footer" msgid="3049522809520549054">"Jakinarazpenak iristen direnean, telefonoak ez du egingo soinurik edo dardararik."</string>
     <string name="zen_mode_restrict_notifications_hide" msgid="3296933643539682552">"Ez egin soinurik eta ez erakutsi ezer jakinarazpenak jasotzean"</string>
     <string name="zen_mode_restrict_notifications_hide_summary" msgid="1449301153755270168">"Ez duzu ikusi edo entzungo jakinarazpenik"</string>
-    <string name="zen_mode_restrict_notifications_hide_footer" msgid="7617688597593946765">"Telefonoak ez ditu erakutsiko ez jakinarazpen berriak, ez lehendik daudenak, eta ez du dar-dar edo soinurik egingo haiek jasotzean. Kontuan izan, ordea, telefonoaren jarduerei edo egoerari buruzko ezinbesteko jakinarazpenak agertuko direla.\n\nEz molestatzeko modua desaktibatzean, galdutako jakinarazpenak ikusi nahi badituzu, pasatu hatza pantailaren goialdetik behera."</string>
+    <string name="zen_mode_restrict_notifications_hide_footer" msgid="7617688597593946765">"Telefonoak ez ditu erakutsiko ez jakinarazpen berriak, ez lehendik daudenak, eta ez du dar-dar edo soinurik egingo haiek jasotzean. Kontuan izan, ordea, telefonoaren jarduerei edo egoerari buruzko ezinbesteko jakinarazpenak agertuko direla.\n\nEz molestatzeko modua desaktibatzean galdutako jakinarazpenak ikusi nahi badituzu, pasatu hatza pantailaren goialdetik behera."</string>
     <string name="zen_mode_restrict_notifications_custom" msgid="3167252482570424133">"Pertsonalizatua"</string>
     <string name="zen_mode_restrict_notifications_enable_custom" msgid="6376983315529894440">"Gaitu ezarpen pertsonalizatua"</string>
     <string name="zen_mode_restrict_notifications_disable_custom" msgid="8004212081465043044">"Kendu ezarpen pertsonalizatua"</string>
@@ -3212,7 +3217,7 @@
     <string name="zen_mode_block_effect_peek" msgid="6075662813575910221">"Ez agerrarazi jakinarazpenak pantailan"</string>
     <string name="zen_mode_block_effect_status" msgid="6516614225115681068">"Ezkutatu pantailaren goialdeko egoera-barraren ikonoak"</string>
     <string name="zen_mode_block_effect_badge" msgid="3891743027347075136">"Ezkutatu aplikazioen ikonoetako jakinarazpen-biribiltxoak"</string>
-    <string name="zen_mode_block_effect_ambient" msgid="6382013125863616197">"Ez esnarazi jakinarazpenekin"</string>
+    <string name="zen_mode_block_effect_ambient" msgid="6382013125863616197">"Ez aktibatu jakinarazpenekin"</string>
     <string name="zen_mode_block_effect_list" msgid="6081548478844912181">"Ezkutatu jakinarazpen-zerrendatik"</string>
     <string name="zen_mode_block_effect_summary_none" msgid="7166175186759564510">"Inoiz ez"</string>
     <string name="zen_mode_block_effect_summary_screen_off" msgid="2985086455557755722">"Pantaila itzalita dagoenean"</string>
@@ -3229,7 +3234,7 @@
     <string name="zen_mode_button_turn_off" msgid="3990967728457149454">"Desaktibatu"</string>
     <string name="zen_mode_settings_dnd_manual_end_time" msgid="4307574188962071429">"<xliff:g id="FORMATTED_TIME">%s</xliff:g> arte egongo da aktibatuta ez molestatzeko modua"</string>
     <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"Desaktibatzen duzun arte egongo da aktibatuta ez molestatzeko modua"</string>
-    <string name="zen_mode_settings_dnd_automatic_rule" msgid="2843297614114625408">"Antolaketa batek (<xliff:g id="RULE_NAME">%s</xliff:g>) automatikoki aktibatu du ez molestatzeko modua"</string>
+    <string name="zen_mode_settings_dnd_automatic_rule" msgid="2843297614114625408">"Programazio batek (<xliff:g id="RULE_NAME">%s</xliff:g>) automatikoki aktibatu du ez molestatzeko modua"</string>
     <string name="zen_mode_settings_dnd_automatic_rule_app" msgid="5103454923160912313">"<xliff:g id="APP_NAME">%s</xliff:g> aplikazioak automatikoki aktibatu du ez molestatzeko modua"</string>
     <string name="zen_mode_settings_dnd_custom_settings_footer" msgid="6335108298640066560">"Ez molestatzeko modua aktibatuta dago <xliff:g id="RULE_NAMES">%s</xliff:g> arauetan, ezarpen pertsonalizatuekin."</string>
     <string name="zen_mode_settings_dnd_custom_settings_footer_link" msgid="4007974052885089379"><annotation id="link">" Ikusi ezarpen pertsonalizatuak"</annotation></string>
@@ -3247,12 +3252,12 @@
     </plurals>
     <string name="zen_mode_duration_summary_time_minutes" msgid="6988728116715208859">"<xliff:g id="NUM_MINUTES">%d</xliff:g> minutu (automatikoki aktibatu ezean)"</string>
     <plurals name="zen_mode_sound_summary_summary_off_info" formatted="false" msgid="8527428833487709278">
-      <item quantity="other"><xliff:g id="ON_COUNT">%d</xliff:g> ordutegi aktiba daitezke automatikoki</item>
-      <item quantity="one">1 ordutegi aktiba daiteke automatikoki</item>
+      <item quantity="other"><xliff:g id="ON_COUNT">%d</xliff:g> programazio aktiba daitezke automatikoki</item>
+      <item quantity="one">1 programazio aktiba daiteke automatikoki</item>
     </plurals>
     <string name="zen_category_behavior" msgid="7695750848671443532">"Desaktibatu gailuaren audioa, baina onartu salbuespenak"</string>
     <string name="zen_category_exceptions" msgid="2139670640033601899">"Salbuespenak"</string>
-    <string name="zen_category_schedule" msgid="989629666210114164">"Antolaketa"</string>
+    <string name="zen_category_schedule" msgid="989629666210114164">"Programazioa"</string>
     <string name="zen_sound_title" msgid="3429086967245473870">"Ikusi salbuespen guztiak"</string>
     <string name="zen_sound_footer" msgid="1778673975517424878">"Ez molestatzeko modua aktibatuta dagoenean, audioa eta dardara desaktibatuta egongo dira, goian baimendutako elementuetan izan ezik."</string>
     <string name="zen_sound_category_title" msgid="2109447208414722786">"Desaktibatu guztien audioa eta dardara, hauena izan ezik:"</string>
@@ -3262,7 +3267,7 @@
     <string name="zen_sound_two_allowed" msgid="299344481401823614">"Audioa eta dardara desaktibatuta, baina baimendu <xliff:g id="SOUND_TYPE_0">%1$s</xliff:g> eta <xliff:g id="SOUND_TYPE_1">%2$s</xliff:g>"</string>
     <string name="zen_sound_three_allowed" msgid="8374564453060696012">"Audioa eta dardara desaktibatuta, baina baimendu <xliff:g id="SOUND_TYPE_0">%1$s</xliff:g>, <xliff:g id="SOUND_TYPE_1">%2$s</xliff:g> eta <xliff:g id="SOUND_TYPE_2">%3$s</xliff:g>"</string>
     <string name="zen_custom_settings_dialog_title" msgid="908049494676219236">"Ezarpen pertsonalizatuak"</string>
-    <string name="zen_custom_settings_dialog_review_schedule" msgid="2247761749333893513">"Berrikusi antolaketa"</string>
+    <string name="zen_custom_settings_dialog_review_schedule" msgid="2247761749333893513">"Berrikusi programazioa"</string>
     <string name="zen_custom_settings_dialog_ok" msgid="3572754922025853427">"Ados"</string>
     <string name="zen_custom_settings_notifications_header" msgid="7469592764589354302">"Jakinarazpenak"</string>
     <string name="zen_custom_settings_duration_header" msgid="1806465684026300942">"Iraupena"</string>
@@ -3299,7 +3304,7 @@
     <string name="asst_capabilities_actions_replies_title" msgid="3929395108744251338">"Ekintza eta erantzun adimendunak"</string>
     <string name="asst_capabilities_actions_replies_summary" msgid="5647029698181357902">"Gehitu automatikoki testuinguru-jakinarazpenetarako ekintzak eta jakinarazpenetarako erantzun bizkorrak"</string>
     <string name="hide_silent_icons_title" msgid="1070905516921542662">"Ezkutatu jakinarazpen isilen egoera-ikonoak"</string>
-    <string name="hide_silent_icons_summary" msgid="2624346914488256888">"Ezkutatu jakinarazpen isilen ikonoak egoera-barran"</string>
+    <string name="hide_silent_icons_summary" msgid="2624346914488256888">"Ezkutatu soinurik gabeko jakinarazpenen ikonoak egoera-barran"</string>
     <string name="notification_badging_title" msgid="6311699476970264712">"Baimendu jakinarazpen-biribiltxoak"</string>
     <string name="notification_bubbles_title" msgid="9196562435741861317">"Burbuilak"</string>
     <string name="notification_bubbles_summary" msgid="4624512775901949578">"Atzitu bizkor aplikazioetako edukia lasterbide gainerakorrak erabilita"</string>
@@ -3430,14 +3435,14 @@
     <string name="notification_channel_sound_title" msgid="7635366839003304745">"Soinua"</string>
     <string name="zen_mode_rule_delete_button" msgid="6763486487220471193">"Ezabatu"</string>
     <string name="zen_mode_rule_rename_button" msgid="1428130397306726792">"Aldatu izena"</string>
-    <string name="zen_mode_rule_name" msgid="8583652780885724670">"Ordutegiaren izena"</string>
-    <string name="zen_mode_rule_name_hint" msgid="6569877315858105901">"Idatzi ordutegiaren izena"</string>
-    <string name="zen_mode_rule_name_warning" msgid="4773465816059587512">"Badago izen hori duen beste ordutegi bat"</string>
+    <string name="zen_mode_rule_name" msgid="8583652780885724670">"Programazioaren izena"</string>
+    <string name="zen_mode_rule_name_hint" msgid="6569877315858105901">"Idatzi programazioaren izena"</string>
+    <string name="zen_mode_rule_name_warning" msgid="4773465816059587512">"Badago izen hori duen beste programazio bat"</string>
     <string name="zen_mode_add_rule" msgid="7200004557856029928">"Gehitu beste batzuk"</string>
-    <string name="zen_mode_add_event_rule" msgid="1398181272397489506">"Gehitu gertaera baten ordutegia"</string>
-    <string name="zen_mode_add_time_rule" msgid="5999467757140524729">"Gehitu ordutegia"</string>
-    <string name="zen_mode_delete_rule" msgid="2292933835997203801">"Ezabatu ordutegia"</string>
-    <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"Aukeratu ordutegi mota"</string>
+    <string name="zen_mode_add_event_rule" msgid="1398181272397489506">"Gehitu gertaera baten programazioa"</string>
+    <string name="zen_mode_add_time_rule" msgid="5999467757140524729">"Gehitu programazioa"</string>
+    <string name="zen_mode_delete_rule" msgid="2292933835997203801">"Ezabatu programazioa"</string>
+    <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"Aukeratu programazio mota"</string>
     <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"\"<xliff:g id="RULE">%1$s</xliff:g>\" araua ezabatu nahi duzu?"</string>
     <string name="zen_mode_delete_rule_button" msgid="611058106279881991">"Ezabatu"</string>
     <string name="zen_mode_rule_type_unknown" msgid="2819480113355191421">"Ezezaguna"</string>
@@ -3464,10 +3469,10 @@
     <string name="zen_mode_schedule_rule_days_none" msgid="6011716195119389956">"Bat ere ez"</string>
     <string name="zen_mode_schedule_rule_days_all" msgid="8814173364016139675">"Egunero"</string>
     <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"Alarmak amaiera-ordua deusezta dezake"</string>
-    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"Alarmak jotzen duenean, ordutegia desaktibatu egiten da"</string>
+    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"Alarmak jotzen duenean, programazioa desaktibatu egiten da"</string>
     <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"Ez molestatzeko moduaren jokabidea"</string>
     <string name="zen_mode_custom_behavior_summary_default" msgid="3509865340195397447">"Erabili ezarpen lehenetsiak"</string>
-    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"Sortu ezarpen pertsonalizatuak ordutegi honetarako"</string>
+    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"Sortu ezarpen pertsonalizatuak programazio honetarako"</string>
     <string name="zen_mode_custom_behavior_category_title" msgid="7451686525113262087">"<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g> arauari dagokionez"</string>
     <string name="summary_divider_text" msgid="4780683204694442666">", "</string>
     <string name="summary_range_symbol_combination" msgid="6038631664844488406">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
@@ -3549,8 +3554,8 @@
     <string name="restr_pin_enter_admin_pin" msgid="8577847751493521230">"Idatzi administratzailearen PIN kodea"</string>
     <string name="switch_on_text" msgid="7100491749799298324">"Aktibatuta"</string>
     <string name="switch_off_text" msgid="3539551289454353555">"Desaktibatuta"</string>
-    <string name="screen_pinning_title" msgid="578020318289781102">"Pantaila ainguratzea"</string>
-    <string name="screen_pinning_description" msgid="3814537379086412278">"Ezarpen hau aktibatzen baduzu, pantailak aingura ditzakezu, aukeratzen duzun ikuspegi hori egon dadin ikusgai harik eta aingura kentzen diozun arte.\n\nHorretarako:\n\n1. Aktibatu pantaila ainguratzeko eginbidea.\n\n2. Ireki Ikuspegi orokorra.\n\n3. Sakatu pantailaren goialdeko aplikazio-ikonoa, eta sakatu Ainguratu."</string>
+    <string name="screen_pinning_title" msgid="578020318289781102">"Pantaila ainguratzeko aukera"</string>
+    <string name="screen_pinning_description" msgid="3814537379086412278">"Ezarpen hau aktibatzen baduzu, pantailak aingura ditzakezu, aukeratzen duzun ikuspegi hori egon dadin ikusgai harik eta aingura kentzen diozun arte.\n\nHorretarako:\n\n1. Aktibatu pantaila ainguratzeko aukera.\n\n2. Ireki Ikuspegi orokorra.\n\n3. Sakatu pantailaren goialdeko aplikazio-ikonoa, eta sakatu Ainguratu."</string>
     <string name="screen_pinning_unlock_pattern" msgid="1060334707088339444">"Eskatu desblokeatzeko eredua aingura kendu aurretik"</string>
     <string name="screen_pinning_unlock_pin" msgid="1441705536015645023">"Eskatu PIN kodea aingura kendu aurretik"</string>
     <string name="screen_pinning_unlock_password" msgid="1017776884000170841">"Eskatu pasahitza aingura kendu aurretik"</string>
@@ -3625,7 +3630,7 @@
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> baimen gehigarri</item>
     </plurals>
     <string name="runtime_permissions_summary_no_permissions_granted" msgid="3477934429220828771">"Ez du baimenik"</string>
-    <string name="runtime_permissions_summary_no_permissions_requested" msgid="3901636077467389637">"Ez du baimenik eskatu"</string>
+    <string name="runtime_permissions_summary_no_permissions_requested" msgid="3901636077467389637">"Ez da baimenik eskatu"</string>
     <string name="filter_all_apps" msgid="4042756539846043675">"Aplikazio guztiak"</string>
     <string name="filter_enabled_apps" msgid="5888459261768538489">"Instalatutako aplikazioak"</string>
     <string name="filter_instant_apps" msgid="8087483282854072366">"Zuzeneko aplikazioak"</string>
@@ -3706,19 +3711,19 @@
     <string name="high_power_off" msgid="5906679734326490426">"Bateria optimizatu egiten da"</string>
     <string name="high_power_system" msgid="739584574711292753">"Bateria-optimizazioa ez dago erabilgarri"</string>
     <string name="high_power_desc" msgid="333756885680362741">"Ez aplikatu bateria-optimizazioa. Aukera horrekin, bizkorrago agortuko da bateria."</string>
-    <string name="high_power_prompt_title" msgid="2805745781720454052">"Beti atzeko planoan abiarazteko baimena eman nahi diozu aplikazioari?"</string>
+    <string name="high_power_prompt_title" msgid="2805745781720454052">"Aplikazioa beti atzeko planoan exekutatzea nahi duzu?"</string>
     <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioari atzeko planoan beti abiarazteko baimena emanez gero, baliteke bateriak gutxiago irautea. \n\nAukera hori aldatzeko, sakatu Ezarpenak &gt; Aplikazioak eta jakinarazpenak."</string>
     <string name="battery_summary" msgid="4345690800899981339">"Bateriaren <xliff:g id="PERCENTAGE">%1$s</xliff:g> erabili du bateria guztiz kargatu zenetik"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"Bateriaren kudeaketa"</string>
-    <string name="no_battery_summary" msgid="4105932628367471314">"Ez du bateriarik erabili bateria guztiz kargatu zenetik"</string>
+    <string name="no_battery_summary" msgid="4105932628367471314">"Ez da bateriarik erabili bateria guztiz kargatu zenetik"</string>
     <string name="app_notification_preferences" msgid="5154466638524523201">"Aplikazioaren ezarpenak"</string>
     <string name="system_ui_settings" msgid="6751165163665775447">"Erakutsi sistemako erabiltzaile-interfazearen konfiguratzailea"</string>
     <string name="additional_permissions" msgid="3142290772324571654">"Baimen gehigarriak"</string>
     <string name="additional_permissions_more" msgid="714264060348056246">"Beste <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="share_remote_bugreport_dialog_title" msgid="1390719492733882678">"Akatsen txostena partekatu nahi duzu?"</string>
-    <string name="share_remote_bugreport_dialog_message_finished" msgid="5133489230646384192">"IKT administratzaileak akatsen txostena eskatu du gailuko arazoa konpontzeko. Baliteke aplikazioak eta datuak partekatzea."</string>
-    <string name="share_remote_bugreport_dialog_message" msgid="6680361103125933760">"IKT administratzaileak akatsen txostena eskatu du gailuko arazoa konpontzeko. Baliteke aplikazioak eta datuak partekatzea, eta agian motelago ibiliko da gailua aldi batez."</string>
-    <string name="sharing_remote_bugreport_dialog_message" msgid="3814787466701526359">"IKT administratzailearekin partekatu dugu akatsen txostena. Xehetasun gehiago lortzeko, jarri harekin harremanetan."</string>
+    <string name="share_remote_bugreport_dialog_message_finished" msgid="5133489230646384192">"IKT saileko administratzaileak akatsen txostena eskatu du gailuko arazoa konpontzeko. Baliteke aplikazioak eta datuak partekatzea."</string>
+    <string name="share_remote_bugreport_dialog_message" msgid="6680361103125933760">"IKT saileko administratzaileak akatsen txostena eskatu du gailuko arazoa konpontzeko. Baliteke aplikazioak eta datuak partekatzea, eta agian motelago ibiliko da gailua aldi batez."</string>
+    <string name="sharing_remote_bugreport_dialog_message" msgid="3814787466701526359">"IKT saileko administratzailearekin partekatu dugu akatsen txostena. Xehetasun gehiago lortzeko, jarri harekin harremanetan."</string>
     <string name="share_remote_bugreport_action" msgid="8600797271670537888">"Partekatu"</string>
     <string name="decline_remote_bugreport_action" msgid="706319275774199033">"Baztertu"</string>
     <string name="usb_use_charging_only" msgid="2344625733377110164">"Ez transferitu daturik"</string>
@@ -3795,11 +3800,11 @@
     <string name="work_profile_usage_access_warning" msgid="403208064382097510">"Administratzaileari aplikazio hau erabiltzeko gaitasuna kendu arren, administratzaileak aplikazioen datuen erabileraren jarraipena egiten jarraitu ahal izango du zure laneko profilean"</string>
     <string name="accessibility_lock_screen_progress" msgid="8242917828598820049">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="COUNT_1">%2$d</xliff:g> karaktere erabili dira"</string>
     <string name="draw_overlay" msgid="2878665072530660668">"Bistaratu aplikazioen gainean"</string>
-    <string name="system_alert_window_settings" msgid="3024330223417646567">"Beste aplikazioen gainean bistaratzea"</string>
+    <string name="system_alert_window_settings" msgid="3024330223417646567">"Bistaratu beste aplikazioen gainean"</string>
     <string name="system_alert_window_apps_title" msgid="9188448296493699566">"Aplikazioak"</string>
-    <string name="system_alert_window_access_title" msgid="5187343732185369675">"Beste aplikazioen gainean bistaratzea"</string>
-    <string name="permit_draw_overlay" msgid="9039092257052422344">"Baimendu beste aplikazioen gainean bistaratzea"</string>
-    <string name="allow_overlay_description" msgid="6669524816705082807">"Baimendu aplikazioari erabiltzen ari zaren aplikazioen gainean agertzea. Eginbide honek abian diren aplikazioen erabilera oztopa dezake, edo haien itxura edo portaera aldatu."</string>
+    <string name="system_alert_window_access_title" msgid="5187343732185369675">"Bistaratu beste aplikazioen gainean"</string>
+    <string name="permit_draw_overlay" msgid="9039092257052422344">"Eman beste aplik. gainean bistaratzeko baimena"</string>
+    <string name="allow_overlay_description" msgid="6669524816705082807">"Eman aplikazioari erabiltzen ari zaren aplikazioen gainean agertzeko baimena. Eginbide honek abian diren aplikazioen erabilera oztopa dezake, edo haien itxura edo portaera aldatu."</string>
     <string name="keywords_vr_listener" msgid="5312633527788917750">"eb errealitate birtuala hautemailea estereoa laguntzailea laguntza zerbitzua"</string>
     <string name="keywords_system_alert_window" msgid="3936658600272194599">"sistema alerta leiho koadro bistaratu beste aplikazio gainean"</string>
     <string name="overlay_settings" msgid="3325154759946433666">"Bistaratu aplikazioen gainean"</string>
@@ -3808,15 +3813,15 @@
     <string name="app_permission_summary_allowed" msgid="6458476982015518778">"Baimena dauka"</string>
     <string name="app_permission_summary_not_allowed" msgid="1171642541675462584">"Ez dauka baimenik"</string>
     <string name="keywords_install_other_apps" msgid="5383559540695847668">"instalatu aplikazio iturburu ezezagun"</string>
-    <string name="write_settings" msgid="9009040811145552108">"Sistemaren ezarpenak aldatzea"</string>
+    <string name="write_settings" msgid="9009040811145552108">"Aldatu sistemaren ezarpenak"</string>
     <string name="keywords_write_settings" msgid="3450405263390246293">"idatzi aldatu sistema ezarpenak"</string>
     <string name="write_settings_summary" msgid="4650251358459404247">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="COUNT_1">%2$d</xliff:g> aplikaziok alda ditzakete sistemaren ezarpenak"</string>
     <string name="financial_apps_sms_access_title" msgid="3422655018008259655">"Finantza-aplikazioetarako SMS bidezko sarbidea"</string>
     <string name="filter_install_sources_apps" msgid="4519839764020866701">"Ezin da instalatu beste aplikaziorik"</string>
     <string name="filter_write_settings_apps" msgid="6864144615530081121">"Sistemaren ezarpenak alda ditzaketenak"</string>
     <string name="write_settings_title" msgid="5852614614193830632">"Sistemaren ezarpenak alda ditzaketenak"</string>
-    <string name="write_system_settings" msgid="20450765210832463">"Sistemaren ezarpenak aldatzea"</string>
-    <string name="permit_write_settings" msgid="4198491281216818756">"Baimendu sistemaren ezarpenak aldatzea"</string>
+    <string name="write_system_settings" msgid="20450765210832463">"Aldatu sistemaren ezarpenak"</string>
+    <string name="permit_write_settings" msgid="4198491281216818756">"Eman sistemaren ezarpenak aldatzeko baimena"</string>
     <string name="write_settings_description" msgid="2536706293042882500">"Baimen honekin, sistemaren ezarpenak alda ditzakete aplikazioek."</string>
     <string name="write_settings_on" msgid="7328986337962635118">"Bai"</string>
     <string name="write_settings_off" msgid="5708257434958406202">"Ez"</string>
@@ -3873,7 +3878,7 @@
     <string name="disabled_by_policy_title_camera" msgid="3741138901926111197">"Ez da onartzen kamera erabiltzea"</string>
     <string name="disabled_by_policy_title_screen_capture" msgid="1856835333536274665">"Ez da onartzen pantaila-argazkiak ateratzea"</string>
     <string name="disabled_by_policy_title_suspend_packages" msgid="4254714213391802322">"Ezin da ireki aplikazioa"</string>
-    <string name="default_admin_support_msg" msgid="5789424433689798637">"Galderarik baduzu, jarri IKT administratzailearekin harremanetan"</string>
+    <string name="default_admin_support_msg" msgid="5789424433689798637">"Galderarik baduzu, jarri IKT saileko administratzailearekin harremanetan"</string>
     <string name="admin_support_more_info" msgid="8737842638087863477">"Xehetasun gehiago"</string>
     <string name="admin_profile_owner_message" msgid="3199544166281052845">"Administratzaileak gainbegiratu eta kudeatu egin ditzake laneko profilarekin erlazionatutako aplikazioak eta datuak, besteak beste, ezarpenak, baimenak, enpresaren sarbide-baimenak, sareko jarduerak eta gailuaren kokapen-informazioa."</string>
     <string name="admin_profile_owner_user_message" msgid="2991249382056855531">"Administratzaileak gainbegiratu eta kudeatu egin ditzake erabiltzailearekin erlazionatutako aplikazioak eta datuak, besteak beste, ezarpenak, baimenak, enpresaren sarbide-baimenak, sareko jarduerak eta gailuaren kokapen-informazioa."</string>
@@ -3882,7 +3887,7 @@
     <string name="condition_turn_on" msgid="1699088245481841159">"Aktibatu"</string>
     <string name="condition_expand_show" msgid="4118818022763913777">"Erakutsi"</string>
     <string name="condition_expand_hide" msgid="1112721783024332643">"Ezkutatu"</string>
-    <string name="condition_hotspot_title" msgid="4143299802283098506">"Sare publikoa aktiboa dago"</string>
+    <string name="condition_hotspot_title" msgid="4143299802283098506">"Wifi-gunea aktibo dago"</string>
     <string name="condition_airplane_title" msgid="8484582712516148433">"Hegaldi modua aktibatuta"</string>
     <string name="condition_airplane_summary" msgid="3021193218494740742">"Sareak ez daude erabilgarri"</string>
     <string name="condition_zen_title" msgid="2128184708916052585">"Aktibatuta dago ez molestatzeko modua"</string>
@@ -3901,7 +3906,7 @@
     <string name="condition_device_muted_summary" msgid="3101055117680109021">"Dei eta jakinarazpenetarako"</string>
     <string name="condition_device_vibrate_title" msgid="5712659354868872338">"Dardara soilik"</string>
     <string name="condition_device_vibrate_summary" msgid="9073880731894828604">"Dei eta jakinarazpenetarako"</string>
-    <string name="night_display_suggestion_title" msgid="4222839610992282188">"Ezarri gaueko argiaren ordutegia"</string>
+    <string name="night_display_suggestion_title" msgid="4222839610992282188">"Ezarri gaueko argiaren programazioa"</string>
     <string name="night_display_suggestion_summary" msgid="1754361016383576916">"Tindatu automatikoki pantaila gauez"</string>
     <string name="condition_night_display_title" msgid="9171491784857160135">"Gaueko argia aktibatuta"</string>
     <string name="condition_night_display_summary" msgid="7885776986937527558">"Pantaila horixkaz tindatuta"</string>
@@ -4304,7 +4309,7 @@
     <string name="my_device_info_device_name_preference_title" msgid="7384446683248009296">"Gailuaren izena"</string>
     <string name="change_wifi_state_title" msgid="5140754955787584174">"Wifi-konexioa kontrolatzeko aukera"</string>
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"Baimendu aplikazioari Wi-Fi konexioa kontrolatzea"</string>
-    <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"Baimendu aplikazio honi Wi-Fi konexioa aktibatzea edo desaktibatzea, Wi-Fi sareak bilatzea eta haietara konektatzea, sareak gehitzea edo kentzea, edota sare publiko lokal bat sortzea"</string>
+    <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"Baimendu aplikazio honi Wi-Fi konexioa aktibatzea edo desaktibatzea, Wi-Fi sareak bilatzea eta haietara konektatzea, sareak gehitzea edo kentzea, edota wifi-gune lokal bat sortzea"</string>
     <string name="media_output_title" msgid="8710632337456601848">"Erreproduzitu multimedia-edukia hemen:"</string>
     <string name="media_output_default_summary" msgid="3159237976830415584">"Gailu hau"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"Telefonoa"</string>
@@ -4328,7 +4333,7 @@
     <string name="prevent_ringing_option_mute_summary" msgid="3509459199090688328">"Aktibatuta (audioa desaktibatuta)"</string>
     <string name="prevent_ringing_option_none_summary" msgid="5152618221093037451">"Desaktibatuta"</string>
     <string name="pref_title_network_details" msgid="3971074015034595956">"Sarearen xehetasunak"</string>
-    <string name="about_phone_device_name_warning" msgid="9088572775969880106">"Mugikorreko aplikazioek gailuaren izena ikus dezakete. Halaber, jendeak ere ikus dezake Bluetooth bidezko gailuetara konektatzean edo wifi-sare publiko bat konfiguratzean."</string>
+    <string name="about_phone_device_name_warning" msgid="9088572775969880106">"Mugikorreko aplikazioek gailuaren izena ikus dezakete. Halaber, jendeak ere ikus dezake Bluetooth bidezko gailuetara konektatzean edo wifi-gune bat konfiguratzean."</string>
     <string name="devices_title" msgid="4768432575951993648">"Gailuak"</string>
     <string name="homepage_all_settings" msgid="3201220879559136116">"Ezarpen guztiak"</string>
     <string name="homepage_personal_settings" msgid="7472638597249114564">"Iradokizunak"</string>
diff --git a/tests/CarDeveloperOptions/res/values-fa/arrays.xml b/tests/CarDeveloperOptions/res/values-fa/arrays.xml
index dd1ef51..2fcb737 100644
--- a/tests/CarDeveloperOptions/res/values-fa/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-fa/arrays.xml
@@ -111,7 +111,7 @@
     <item msgid="8247986727324120082">"۲ دقیقه"</item>
     <item msgid="2759776603549270587">"۵ دقیقه"</item>
     <item msgid="167772676068860015">"۱ ساعت"</item>
-    <item msgid="5985477119043628504">"بدون مهلت زمانی"</item>
+    <item msgid="5985477119043628504">"بدون درنگ"</item>
   </string-array>
   <string-array name="bluetooth_max_connected_audio_devices">
     <item msgid="3800257971619063588">"استفاده از پیش‌فرض سیستم: <xliff:g id="DEFAULT_BLUETOOTH_MAX_CONNECTED_AUDIO_DEVICES">%1$d</xliff:g>"</item>
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"اجرا در پس‌زمینه"</item>
     <item msgid="6423861043647911030">"میزان دسترس‌پذیری"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"مکان"</item>
+    <item msgid="6656077694190491067">"مکان"</item>
+    <item msgid="8790228218278477369">"مکان"</item>
+    <item msgid="7836406246005211990">"لرزش"</item>
+    <item msgid="3951439024549922598">"خواندن مخاطبین"</item>
+    <item msgid="8802152411647068">"تغییر مخاطبین"</item>
+    <item msgid="229544934599698735">"خواندن گزارش تماس"</item>
+    <item msgid="7396102294405899613">"تغییر گزارش تماس"</item>
+    <item msgid="3597797992398484655">"خواندن تقویم"</item>
+    <item msgid="2705975774250907343">"تغییر تقویم"</item>
+    <item msgid="4668747371441932697">"مکان"</item>
+    <item msgid="1487578921720243646">"اعلان پست"</item>
+    <item msgid="4636080349724146638">"موقعیت مکانی"</item>
+    <item msgid="673510900286463926">"تماس تلفنی"</item>
+    <item msgid="542083422784609790">"خواندن پیامک/فراپیام"</item>
+    <item msgid="1033780373029588436">"نوشتن پیامک/فراپیام"</item>
+    <item msgid="5647111115517787488">"دریافت پیامک/فراپیام"</item>
+    <item msgid="8591105601108455893">"دریافت پیامک/فراپیام"</item>
+    <item msgid="7730995008517841903">"دریافت پیامک/فراپیام"</item>
+    <item msgid="2613033109026626086">"دریافت پیامک/فراپیام"</item>
+    <item msgid="3037159047591081136">"ارسال پیامک/فراپیام"</item>
+    <item msgid="4726682243833913568">"خواندن پیامک/فراپیام"</item>
+    <item msgid="6555678522277865572">"نوشتن پیامک/فراپیام"</item>
+    <item msgid="6981734935578130884">"تغییر تنظیمات"</item>
+    <item msgid="8705854389991425629">"در بالا طراحی کنید"</item>
+    <item msgid="5861356020344153651">"اعلان‌های دسترسی"</item>
+    <item msgid="78432174621628659">"دوربین"</item>
+    <item msgid="3986116419882154794">"ضبط صدا"</item>
+    <item msgid="4516840825756409490">"پخش صدا"</item>
+    <item msgid="6811712502798183957">"خواندن بریده‌دان"</item>
+    <item msgid="2780369012602289114">"تغییر بریده‌دان"</item>
+    <item msgid="2331359440170850868">"دکمه‌های رسانه‌"</item>
+    <item msgid="6133599737122751231">"فوکوس صدا"</item>
+    <item msgid="6844485713404805301">"میزان صدای اصلی"</item>
+    <item msgid="1600379420669104929">"میزان صدای مکالمه"</item>
+    <item msgid="6296768210470214866">"میزان صدای زنگ"</item>
+    <item msgid="510690696071629241">"میزان صدای رسانه"</item>
+    <item msgid="406861638631430109">"میزان صدای زنگ"</item>
+    <item msgid="4715864795872233884">"میزان صدای اعلان"</item>
+    <item msgid="2311478519251301183">"میزان صدای بلوتوث"</item>
+    <item msgid="5133991377896747027">"بیدار باش"</item>
+    <item msgid="2464189519136248621">"مکان"</item>
+    <item msgid="2062677934050803037">"موقعیت مکانی"</item>
+    <item msgid="1735171933192715957">"دریافت آمار استفاده"</item>
+    <item msgid="1014093788778383554">"صدادار/بی‌صدا کردن میکروفن"</item>
+    <item msgid="4199297950608622850">"نمایش تست"</item>
+    <item msgid="2527962435313398821">"فرستادن رسانه"</item>
+    <item msgid="5117506254221861929">"فعال کردن VPN"</item>
+    <item msgid="8291198322681891160">"نوشتن کاغذدیواری"</item>
+    <item msgid="7106921284621230961">"ساختار دستیار"</item>
+    <item msgid="4496533640894624799">"عکس‌ صفحه‌نمایش دستیار"</item>
+    <item msgid="2598847264853993611">"خواندن وضعیت تلفن"</item>
+    <item msgid="9215610846802973353">"افزودن پست صوتی"</item>
+    <item msgid="9186411956086478261">"استفاده از SIP"</item>
+    <item msgid="6884763100104539558">"پردازش تماس خروجی"</item>
+    <item msgid="125513972170580692">"اثر انگشت"</item>
+    <item msgid="2556071024281275619">"حسگرهای بدن"</item>
+    <item msgid="617168514928339387">"خواندن پخش‌های سلولی"</item>
+    <item msgid="7134693570516523585">"مکان کاذب"</item>
+    <item msgid="7224489175375229399">"خواندن حافظه"</item>
+    <item msgid="8472735063903258202">"نوشتن در حافظه"</item>
+    <item msgid="4069276819909595110">"روشن کردن صفحه"</item>
+    <item msgid="1228338896751121025">"دریافت حساب‌ها"</item>
+    <item msgid="3181581793459233672">"اجرا در پس‌زمینه"</item>
+    <item msgid="2340936043025374076">"میزان دسترس‌پذیری"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"کوتاه"</item>
     <item msgid="4816511817309094890">"متوسط"</item>
@@ -349,7 +415,7 @@
     <item msgid="8754480102834556765">"آماده سازی..."</item>
     <item msgid="3351334355574270250">"در حال اتصال..."</item>
     <item msgid="8303882153995748352">"متصل"</item>
-    <item msgid="9135049670787351881">"وقفه زمانی"</item>
+    <item msgid="9135049670787351881">"درنگ"</item>
     <item msgid="2124868417182583926">"ناموفق"</item>
   </string-array>
   <string-array name="security_settings_premium_sms_values">
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"همیشه غیرمجاز"</item>
     <item msgid="8184570120217958741">"همیشه مجاز است"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"عادی"</item>
+    <item msgid="5101233285497327432">"متوسط"</item>
+    <item msgid="1555861583162930714">"کم"</item>
+    <item msgid="1719683776264798117">"خیلی کم"</item>
+    <item msgid="1567326459340152525">"؟"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"عادی"</item>
+    <item msgid="6107138933849816768">"متوسط"</item>
+    <item msgid="182695359839047859">"کم"</item>
+    <item msgid="8577246509202964244">"بحرانی"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"دائمی"</item>
     <item msgid="167418068739176448">"فعالیت برتر"</item>
diff --git a/tests/CarDeveloperOptions/res/values-fa/config.xml b/tests/CarDeveloperOptions/res/values-fa/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-fa/config.xml
+++ b/tests/CarDeveloperOptions/res/values-fa/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-fa/strings.xml b/tests/CarDeveloperOptions/res/values-fa/strings.xml
index 23f8022..f08ac41 100644
--- a/tests/CarDeveloperOptions/res/values-fa/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-fa/strings.xml
@@ -53,7 +53,7 @@
     <string name="radio_info_ims_reg_status_not_registered" msgid="1286050699734226077">"ثبت‌نشده"</string>
     <string name="radio_info_ims_feature_status_available" msgid="2040629393134756058">"در دسترس"</string>
     <string name="radio_info_ims_feature_status_unavailable" msgid="3348223769202693596">"در دسترس نیست"</string>
-    <string name="radio_info_ims_reg_status" msgid="4771711884059371514">"ثبت IMS:‏ <xliff:g id="STATUS">%1$s</xliff:g>\nصدا ازطریق LTE‏: <xliff:g id="AVAILABILITY_0">%2$s</xliff:g>\nصدا ازطریق WiFi‏: <xliff:g id="AVAILABILITY_1">%3$s</xliff:g>\n‏تماس ویدیویی: <xliff:g id="AVAILABILITY_2">%4$s</xliff:g>\nواسط UT: <xliff:g id="AVAILABILITY_3">%5$s</xliff:g>"</string>
+    <string name="radio_info_ims_reg_status" msgid="4771711884059371514">"ثبت IMS:‏ <xliff:g id="STATUS">%1$s</xliff:g>\nصدا ازطریق LTE‏: <xliff:g id="AVAILABILITY_0">%2$s</xliff:g>\nصدا ازطریق WiFi‏: <xliff:g id="AVAILABILITY_1">%3$s</xliff:g>\n‏تماس تصویری: <xliff:g id="AVAILABILITY_2">%4$s</xliff:g>\nواسط UT: <xliff:g id="AVAILABILITY_3">%5$s</xliff:g>"</string>
     <string name="radioInfo_service_in" msgid="1297020186765943857">"سرویس دارد"</string>
     <string name="radioInfo_service_out" msgid="8460363463722476510">"خارج از سرویس"</string>
     <string name="radioInfo_service_emergency" msgid="7674989004735662599">"فقط تماس‌های اضطراری"</string>
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"نوشتار روی صفحه‌نمایش را بزرگ‌تر یا کوچک‌تر کنید."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"کوچک‌تر کردن"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"بزرگ‌تر کردن"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"برای این آقا آبجو و کیوی سرو کنید."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"نوشتار نمونه"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"جادوگر شهر اوز"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"فصل ۱۱: شهر زمردی شگفت‌انگیز اوز"</string>
@@ -354,7 +353,7 @@
     <string name="show_owner_info_on_lockscreen_label" msgid="4510756693837171575">"نمایش اطلاعات مالک در صفحه قفل"</string>
     <string name="owner_info_settings_title" msgid="2537966178998339896">"پیام صفحه قفل"</string>
     <string name="security_enable_widgets_title" msgid="1701510007926738088">"فعال کردن ابزارک‌ها"</string>
-    <string name="security_enable_widgets_disabled_summary" msgid="4408176087132339331">"غیرفعال‌شده توسط سرپرست"</string>
+    <string name="security_enable_widgets_disabled_summary" msgid="4408176087132339331">"توسط سرپرست غیرفعال شده"</string>
     <string name="lockdown_settings_title" msgid="4534779922580115990">"نمایش گزینه «قفل همه»"</string>
     <string name="lockdown_settings_summary" msgid="7270756909878256174">"نمایش گزینه دکمه روشن/خاموش که Smart Lock، باز کردن قفل با اثرانگشت و اعلان‌های در صفحه قفل را خاموش می‌کند"</string>
     <string name="trust_agents_extend_unlock_title" msgid="3582017561316089951">"نماینده‌های معتمد فقط تمدید حالت باز"</string>
@@ -384,11 +383,11 @@
     <string name="encryption_and_credential_settings_summary" product="tablet" msgid="8170667308598998791">"دستگاه رمزگذاری شد"</string>
     <string name="decryption_settings_summary" product="tablet" msgid="7524119945312453569">"دستگاه رمزگذاری نشده است"</string>
     <string name="lockscreen_settings_title" msgid="1221505938891948413">"نمایش صفحه قفل"</string>
-    <string name="lockscreen_settings_what_to_show_category" msgid="3133378945821488654">"آنچه باید نمایش داده شود"</string>
+    <string name="lockscreen_settings_what_to_show_category" msgid="3133378945821488654">"چه چیزی نشان داده شود"</string>
     <string name="security_settings_summary" msgid="5210109100643223686">"تنظیم مکان من، قفل صفحه، قفل سیم کارت، قفل حافظه اطلاعات کاربری"</string>
     <string name="cdma_security_settings_summary" msgid="1783066617800041869">"تنظیم مکان من، بازگشایی قفل صفحه، قفل حافظه اطلاعات کاربری"</string>
     <string name="security_passwords_title" msgid="6853942836045862315">"حریم خصوصی"</string>
-    <string name="disabled_by_administrator_summary" msgid="6099821045360491127">"غیرفعال‌شده توسط سرپرست"</string>
+    <string name="disabled_by_administrator_summary" msgid="6099821045360491127">"توسط سرپرست غیرفعال شده"</string>
     <string name="security_status_title" msgid="1261960357751754428">"وضعیت امنیتی"</string>
     <string name="security_dashboard_summary_face" msgid="2536136110153593745">"قفل صفحه، بازگشایی با چهره"</string>
     <string name="security_dashboard_summary" msgid="4048877125766167227">"قفل صفحه، اثرانگشت"</string>
@@ -413,7 +412,7 @@
     <string name="face_intro_error_unknown" msgid="3241592604198351134">"چهره بیشتری نمی‌توان اضافه کرد"</string>
     <string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"ثبت انجام نشد"</string>
     <string name="security_settings_face_enroll_dialog_ok" msgid="1078348922734845090">"تأیید"</string>
-    <string name="security_settings_face_enroll_error_timeout_dialog_message" msgid="4917894418448325405">"مهلت زمانی ثبت چهره به پایان رسید. دوباره امتحان کنید."</string>
+    <string name="security_settings_face_enroll_error_timeout_dialog_message" msgid="4917894418448325405">"درنگ ثبت چهره به پایان رسید. دوباره امتحان کنید."</string>
     <string name="security_settings_face_enroll_error_generic_dialog_message" msgid="5160473187142616862">"ثبت چهره کار نکرد."</string>
     <string name="security_settings_face_enroll_finish_title" msgid="6800717857394410769">"همه چیز تنظیم شد. خوب به نظر می‌رسد."</string>
     <string name="security_settings_face_enroll_done" msgid="5409739233373490971">"تمام"</string>
@@ -489,7 +488,7 @@
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"اووه، آن حسگر نیست"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"با استفاده از انگشت اشاره، حسگر را در  پشت تلفن لمس کنید."</string>
     <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"ثبت انجام نشد"</string>
-    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"مهلت زمانی ثبت اثر انگشت به پایان رسید. دوباره امتحان کنید."</string>
+    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"درنگ ثبت اثر انگشت به پایان رسید. دوباره امتحان کنید."</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"ثبت اثر انگشت کار نمی‌کند. دوباره امتحان کنید یا از انگشت دیگری استفاده کنید."</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"افزودن مورد دیگر"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"بعدی"</string>
@@ -586,7 +585,7 @@
     <string name="face_unlock_set_unlock_password" msgid="8962344604388383659">"احراز هویت با چهره + گذرواژه"</string>
     <string name="face_unlock_skip_face" msgid="7173197040501143880">"ادامه بدون احراز هویت با چهره"</string>
     <string name="face_unlock_title" msgid="1298031162909236127">"می‌توانید با استفاده از چهره‌تان قفل تلفنتان را باز کنید. بنا به دلایل ایمنی این گزینه مستلزم قفل صفحه پشتیبان است."</string>
-    <string name="unlock_set_unlock_disabled_summary" msgid="1713159782896140817">"غیرفعال‌شده توسط سرپرست، طبق خط‌مشی رمزگذاری یا حافظه اطلاعات کاربردی"</string>
+    <string name="unlock_set_unlock_disabled_summary" msgid="1713159782896140817">"توسط سرپرست غیرفعال شده، طبق خط‌مشی رمزگذاری یا حافظه اطلاعات کاربردی"</string>
     <string name="unlock_set_unlock_mode_off" msgid="2950701212659081973">"هیچ‌کدام"</string>
     <string name="unlock_set_unlock_mode_none" msgid="3441605629077912292">"تند کشیدن"</string>
     <string name="unlock_set_unlock_mode_pattern" msgid="8564909572968419459">"الگو"</string>
@@ -596,10 +595,10 @@
     <string name="unlock_disable_lock_title" msgid="3508492427073600294">"خاموش کردن قفل صفحه"</string>
     <string name="unlock_disable_frp_warning_title" msgid="5858589970505254193">"محافظ دستگاه برداشته شود؟"</string>
     <string name="unlock_disable_frp_warning_title_profile" msgid="3814123014295965266">"محافظت از نمایه غیرفعال شود؟"</string>
-    <string name="unlock_disable_frp_warning_content_pattern" msgid="1843950215687159135">"قابلیت‌های محافظ دستگاه بدون الگوی شما کار نمی‌کند."</string>
-    <string name="unlock_disable_frp_warning_content_pattern_fingerprint" msgid="8846957650251741548">"قابلیت‌های محافظت از دستگاه، بدون الگوی شما کار نمی‌کنند.<xliff:g id="EMPTY_LINE">
+    <string name="unlock_disable_frp_warning_content_pattern" msgid="1843950215687159135">"ویژگی‌های محافظ دستگاه بدون الگوی شما کار نمی‌کند."</string>
+    <string name="unlock_disable_frp_warning_content_pattern_fingerprint" msgid="8846957650251741548">"ویژگی‌های محافظ دستگاه بدون الگوی شما کار نمی‌کند.<xliff:g id="EMPTY_LINE">
 
-</xliff:g>اثرانگشت‌های ذخیره‌شده‌تان هم از این دستگاه پاک می‌شود و نمی‌توانید با آن‌ها قفل تلفنتان را باز کنید، خریدها را تأیید کنید یا به سیستم برنامه‌ها وارد شوید."</string>
+</xliff:g>اثرانگشت‌های ذخیره‌شده‌تان هم از این دستگاه پاک می‌شود و نمی‌توانید با آن‌ها قفل تلفنتان را باز کنید، خریدها را تأیید کنید، یا به سیستم برنامه‌ها وارد شوید."</string>
     <string name="unlock_disable_frp_warning_content_pin" msgid="6760473271034592796">"قابلیت‌های محافظ دستگاه بدون پین شما کار نمی‌کند."</string>
     <string name="unlock_disable_frp_warning_content_pin_fingerprint" msgid="4384632309103635233">"قابلیت‌های محافظت از دستگاه، بدون پین شما کار نمی‌کنند.<xliff:g id="EMPTY_LINE">
 
@@ -668,7 +667,6 @@
       <item quantity="one">باید کمتر از <xliff:g id="NUMBER_1">%d</xliff:g> رقم باشد</item>
       <item quantity="other">باید کمتر از <xliff:g id="NUMBER_1">%d</xliff:g> رقم باشد</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"فقط می‌تواند شامل اعداد ۰ تا ۹ باشد"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"سرپرست دستگاه اجازه استفاده از پین اخیر را نمی‌دهد"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"پین‌های رایج توسط سرپرست فناوری اطلاعات شما مسدود شده‌اند. پین متفاوتی را امتحان کنید."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"نمی‌تواند نویسه نامعتبر داشته باشد"</string>
@@ -699,6 +697,10 @@
       <item quantity="one">باید حداقل <xliff:g id="COUNT">%d</xliff:g> نویسه غیرحرف داشته باشد</item>
       <item quantity="other">باید حداقل <xliff:g id="COUNT">%d</xliff:g> نویسه غیرحرف داشته باشد</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">باید حداقل <xliff:g id="COUNT">%d</xliff:g> نویسه غیرعددی داشته باشد</item>
+      <item quantity="other">باید حداقل <xliff:g id="COUNT">%d</xliff:g> نویسه غیرعددی داشته باشد</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"سرپرست دستگاه اجازه استفاده از گذرواژه اخیر را نمی‌دهد"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"گذرواژه‌های رایج توسط سرپرست فناوری اطلاعات شما مسدود شده‌اند. گذرواژه متفاوتی را امتحان کنید."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"ترتیب صعودی، نزولی یا تکراری ارقام مجاز نیست"</string>
@@ -824,7 +826,7 @@
     <string name="nfc_disclaimer_title" msgid="4860231267351602970">"روشن کردن NFC"</string>
     <string name="nfc_disclaimer_content" msgid="3066113577854565782">"NFC داده‌ها را میان این دستگاه و سایر دستگا‌ه‌ها یا اهداف اطراف (مانند پایانه‌های پرداخت، کارت‌خوان‌ها و آگهی‌ها یا برچسب‌های تعاملی) مبادله می‌کند."</string>
     <string name="nfc_secure_settings_title" msgid="5153751163174916581">"NFC ایمن"</string>
-    <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"استفاده از حمل‌و‌نقل عمومی و پرداخت NFC تنها وقتی قفل صفحه باز است مجاز شود"</string>
+    <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"استفاده از حمل‌و‌نقل عمومی و پرداخت «ارتباط میدان نزدیک» (NFC) تنها وقتی قفل صفحه باز است مجاز شود"</string>
     <string name="android_beam_settings_title" msgid="3083436415873738389">"Android Beam"</string>
     <string name="android_beam_on_summary" msgid="8068287225180474199">"آماده برای انتقال محتوای برنامه از طریق NFC"</string>
     <string name="android_beam_off_summary" msgid="7365818039159364600">"خاموش"</string>
@@ -931,14 +933,14 @@
     <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"حداقل یک باند برای نقطه اتصال Wi‑Fi انتخاب کنید:"</string>
     <string name="wifi_ip_settings" msgid="4636102290236116946">"تنظیمات IP"</string>
     <string name="wifi_privacy_settings" msgid="4462092795794247809">"حریم خصوصی"</string>
-    <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"MAC تصادفی‌سازی‌شده"</string>
+    <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"MAC تصادفی"</string>
     <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"افزودن دستگاه"</string>
     <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"برای افزودن دستگاه به «<xliff:g id="SSID">%1$s</xliff:g>»،‌ کد QR را در مرکز پنجره زیر قرار دهید"</string>
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"اسکن کد QR"</string>
     <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"برای اتصال به «<xliff:g id="SSID">%1$s</xliff:g>»،‌ کد QR را در مرکز پنجره زیر قرار دهید"</string>
     <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"با اسکن کردن کد QR، به Wi‑Fi بپیوندید"</string>
     <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"استفاده مشترک از Wi‑Fi"</string>
-    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"برای اتصال به «<xliff:g id="SSID">%1$s</xliff:g>»، این کد QR را اسکن کنید و گذرواژه مربوطه را به اشتراک گذارید"</string>
+    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"برای اتصال به «<xliff:g id="SSID">%1$s</xliff:g>»، این کد QR را اسکن کنید و گذرواژه مربوطه را هم‌رسانی کنید"</string>
     <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"برای اتصال به «<xliff:g id="SSID">%1$s</xliff:g>»، این کد QR را اسکن کنید"</string>
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"کد QR خوانده نشد. کد را در مرکز قرار دهید و دوباره امتحان کنید"</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"دوباره امتحان کنید. اگر مشکل همچنان ادامه دارد، با سازنده دستگاه تماس بگیرید"</string>
@@ -1022,7 +1024,7 @@
     <string name="wifi_details_subnet_mask" msgid="53396707004763012">"پوشش زیرشبکه"</string>
     <string name="wifi_details_dns" msgid="1118251455740116559">"DNS"</string>
     <string name="wifi_details_ipv6_address_header" msgid="1642310137145363299">"نشانی‌های IPv6"</string>
-    <string name="wifi_saved_access_points_label" msgid="3790693285928292563">"شبکه‌های ذخیره شده"</string>
+    <string name="wifi_saved_access_points_label" msgid="3790693285928292563">"شبکه‌های ذخیره‌شده"</string>
     <string name="wifi_subscribed_access_points_tab" msgid="7498765485953257229">"اشتراک‌ها"</string>
     <!-- no translation found for wifi_saved_access_points_tab (4677730543624191122) -->
     <skip />
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"داده شبکه تلفن همراه"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"استفاده از شبکه تلفن همراه، درصورت عدم‌دسترسی به Wi-Fi"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"اگر شبکه تلفن همراه دردسترس نبود، از Wi-Fi استفاده شود"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"تماس ازطریق Wi-Fi. اگر اتصال Wi-Fi قطع شود، تماس متوقف می‌شود."</string>
@@ -1196,7 +1201,7 @@
     <string name="auto_brightness_very_high_title" msgid="6649896560889239565">"بسیار زیاد"</string>
     <string name="auto_brightness_subtitle" msgid="8516999348793100665">"میزان روشنایی ترجیحی"</string>
     <string name="auto_brightness_off_summary" msgid="6162650416289359104">"برای چراغ‌های در دسترس تنظیم نکنید"</string>
-    <string name="auto_brightness_very_high_summary" msgid="7202032980509583918">"استفاده باتری افزایش‌یافته"</string>
+    <string name="auto_brightness_very_high_summary" msgid="7202032980509583918">"مصرف باتری بالا"</string>
     <string name="auto_brightness_disclaimer" msgid="5416696351199148809">"میزان روشنایی را برای چراغ‌ در دسترس بهینه کنید. تازمانی‌که این ویژگی روشن است، می‌توانید روشنایی را به‌طورموقت تنظیم کنید."</string>
     <string name="auto_brightness_description" msgid="8209140379089535411">"روشنایی صفحه‌نمایش به‌طور خودکار با محیط و فعالیت‌هایتان تنظیم می‌شود. می‌توانید لغزاننده را به‌طور دستی حرکت دهید تا روشنایی تطبیقی ترجیح شما را دریابد."</string>
     <string name="display_white_balance_title" msgid="5747260735311935143">"تعادل سفیدی نمایشگر"</string>
@@ -1244,7 +1249,7 @@
     <string name="screensaver_settings_summary_either_long" msgid="6078038506795498288">"هنگام شارژ یا اتصال به پایه"</string>
     <string name="screensaver_settings_summary_either_short" msgid="2453772128682850053">"هر دو"</string>
     <string name="screensaver_settings_summary_sleep" msgid="6097363596749362692">"هنگام شارژ شدن"</string>
-    <string name="screensaver_settings_summary_dock" msgid="6297808146601570196">"وقتی در جایگاه است"</string>
+    <string name="screensaver_settings_summary_dock" msgid="6297808146601570196">"وقتی روی پایه است"</string>
     <string name="screensaver_settings_summary_never" msgid="3995259444981620707">"هرگز"</string>
     <string name="screensaver_settings_summary_off" msgid="6119947316484763131">"خاموش"</string>
     <string name="screensaver_settings_disabled_prompt" msgid="1897518064782596947">"برای کنترل اینکه وقتی تلفن روی پایه اتصال قرار دارد و/یا در حالت خواب است چه اتفاقی بیفتد، محافظ صفحه را روشن کنید."</string>
@@ -1255,11 +1260,11 @@
     <string name="automatic_brightness" msgid="8663792987774126192">"روشنایی خودکار"</string>
     <string name="lift_to_wake_title" msgid="5523752279947392868">"بیدار شدن با بالا بردن"</string>
     <string name="ambient_display_screen_title" msgid="2632871676917956691">"نمایشگر محیط"</string>
-    <string name="ambient_display_category_triggers" msgid="3496111745340047504">"زمان نمایش دادن"</string>
+    <string name="ambient_display_category_triggers" msgid="3496111745340047504">"کی نشان داده شود"</string>
     <string name="doze_title" msgid="235269029233857546">"اعلان‌های جدید"</string>
     <string name="doze_summary" msgid="6762274282827831706">"روشن شدن صفحه‌نمایش هنگامی که اعلانی دریافت می‌کنید"</string>
     <string name="doze_always_on_title" msgid="8555184965031789941">"همیشه روشن"</string>
-    <string name="doze_always_on_summary" msgid="7654436900436328950">"نمایش زمان، نمادهای اعلان و سایر اطلاعات. استفاده باتری افزایش‌یافته."</string>
+    <string name="doze_always_on_summary" msgid="7654436900436328950">"نمایش زمان، نمادهای اعلان و سایر اطلاعات. مصرف باتری بالا."</string>
     <string name="title_font_size" msgid="5021464556860010851">"اندازه قلم"</string>
     <string name="short_summary_font_size" msgid="4141077908728522946">"نوشتار را بزرگ‌تر یا کوچک‌تر کنید"</string>
     <string name="sim_lock_settings" msgid="1986924650622642189">"تنظیمات قفل سیم کارت"</string>
@@ -1413,7 +1418,7 @@
     <string name="storage_menu_set_up" msgid="2849170579745958513">"راه‌اندازی"</string>
     <string name="storage_menu_explore" msgid="3733439525636202662">"کاوش"</string>
     <string name="storage_menu_free" msgid="6586253660759145508">"آزاد کردن فضا"</string>
-    <string name="storage_menu_manage" msgid="461380717863926516">"مدیریت حافظه"</string>
+    <string name="storage_menu_manage" msgid="461380717863926516">"مدیریت فضای ذخیره‌سازی"</string>
     <string name="storage_title_usb" msgid="2015671467177303099">"اتصال به کامپیوتر با USB"</string>
     <string name="usb_connection_category" msgid="2888975803638116041">"اتصال به‌عنوان"</string>
     <string name="usb_mtp_title" msgid="6893938968831995500">"دستگاه رسانه‌ای (MTP)"</string>
@@ -1609,16 +1614,16 @@
     <string name="tether_settings_title_wifi" msgid="2060965130234484613">"نقطه اتصال قابل حمل"</string>
     <string name="tether_settings_title_bluetooth" msgid="1999590158102569959">"اشتراک‌گذاری اینترنت با بلوتوث"</string>
     <string name="tether_settings_title_usb_bluetooth" msgid="1159128764162788159">"اشتراک‌گذاری اینترنت"</string>
-    <string name="tether_settings_title_all" msgid="6935843543433954181">"نقطه اتصال و اتصال به اینترنت با تلفن همراه"</string>
+    <string name="tether_settings_title_all" msgid="6935843543433954181">"نقطه اتصال و اشتراک‌گذاری اینترنت"</string>
     <string name="tether_settings_summary_hotspot_on_tether_on" msgid="1289593649526514499">"نقطه اتصال روشن، اشتراک‌گذاری اینترنت"</string>
     <string name="tether_settings_summary_hotspot_on_tether_off" msgid="8010689354668285422">"نقطه اتصال روشن"</string>
     <string name="tether_settings_summary_hotspot_off_tether_on" msgid="1349909238672649877">"اشتراک‌گذاری اینترنت"</string>
-    <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"هنگامی که محافظ صفحه روشن است نمی‌توانید از نقاط اتصال قابل حمل یا اتصال به اینترنت با تلفن همراه استفاده کنید"</string>
+    <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"هنگامی که محافظ صفحه روشن است نمی‌توانید از نقاط اتصال قابل حمل یا اشتراک‌گذاری اینترنت استفاده کنید"</string>
     <string name="usb_title" msgid="7480927657535578688">"USB"</string>
     <string name="usb_tethering_button_text" msgid="6242228383142012332">"اشتراک‌گذاری اینترنت با USB"</string>
     <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"هم‌رسانی اتصال اینترنت تلفن ازطریق USB"</string>
     <string name="usb_tethering_subtext" product="tablet" msgid="154536000235361034">"هم‌رسانی اینترنت رایانه لوحی ازطریق USB"</string>
-    <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"تترینگ با بلوتوث"</string>
+    <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"اشتراک‌گذاری اینترنت با بلوتوث"</string>
     <string name="bluetooth_tethering_subtext" product="tablet" msgid="6868756914621131635">"هم‌رسانی اتصال اینترنت رایانه لوحی ازطریق بلوتوث"</string>
     <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"هم‌رسانی اتصال اینترنت تلفن ازطریق بلوتوث"</string>
     <string name="bluetooth_tethering_off_subtext_config" msgid="3981528184780083266">"هم‌رسانی اتصال اینترنت این <xliff:g id="DEVICE_NAME">%1$d</xliff:g> ازطریق بلوتوث"</string>
@@ -1795,7 +1800,7 @@
     <string name="advanced_settings_summary" msgid="5912237062506771716">"گزینه‌های تنظیمات بیشتری فعال شود"</string>
     <string name="application_info_label" msgid="3886253474964599105">"اطلاعات برنامه"</string>
     <string name="storage_label" msgid="1109537840103290384">"حافظه"</string>
-    <string name="auto_launch_label" msgid="47089737922907379">"باز کردن به صورت پیش‌فرض"</string>
+    <string name="auto_launch_label" msgid="47089737922907379">"باز کردن به‌صورت پیش‌فرض"</string>
     <string name="auto_launch_label_generic" msgid="7865828543459493308">"پیش‌فرض‌ها"</string>
     <string name="screen_compatibility_label" msgid="3638271673726075815">"سازگاری با صفحه‌نمایش"</string>
     <string name="permissions_label" msgid="7341733648403464213">"مجوزها"</string>
@@ -1820,11 +1825,11 @@
     <string name="install_text" msgid="2798092278891807849">"نصب"</string>
     <string name="disable_text" msgid="5065834603951474397">"غیرفعال کردن"</string>
     <string name="enable_text" msgid="7179141636849225884">"فعال کردن"</string>
-    <string name="clear_user_data_text" msgid="8894073247302821764">"پاک کردن محل ذخیره‌سازی"</string>
+    <string name="clear_user_data_text" msgid="8894073247302821764">"پاک کردن فضای ذخیره‌سازی"</string>
     <string name="app_factory_reset" msgid="8718986000278776272">"حذف نصب نسخه‌های به روز"</string>
     <string name="auto_launch_enable_text" msgid="3372898942144027341">"شما انتخاب کرده‌اید که این برنامه را به‌طور پیش‌فرض برای برخی از عملکردها راه‌اندازی کنید."</string>
     <string name="always_allow_bind_appwidgets_text" msgid="2286211654774611037">"شما انتخاب کردید تا به این برنامه برای ایجاد ابزارک و دسترسی به اطلاعات آن‌ها اجازه دهید."</string>
-    <string name="auto_launch_disable_text" msgid="8560921288036801416">"پیش فرضی تنظیم نشده است."</string>
+    <string name="auto_launch_disable_text" msgid="8560921288036801416">"پیش‌فرضی تنظیم نشده است."</string>
     <string name="clear_activities" msgid="2068014972549235347">"پاک کردن پیش‌فرض‌ها"</string>
     <string name="screen_compatibility_text" msgid="1768064020294301496">"ممکن است این برنامه برای صفحه شما طراحی نشده باشد، نحوه تنظیم آن برای صفحه را می‌توانید از این قسمت کنترل کنید."</string>
     <string name="ask_compatibility" msgid="6687958195768084807">"هنگام راه‌اندازی سؤال شود"</string>
@@ -1833,7 +1838,7 @@
     <string name="sort_order_alpha" msgid="6689698854460261212">"مرتب سازی براساس نام"</string>
     <string name="sort_order_size" msgid="3167376197248713027">"مرتب‌سازی براساس اندازه"</string>
     <string name="sort_order_recent_notification" msgid="5592496977404445941">"جدیدترین"</string>
-    <string name="sort_order_frequent_notification" msgid="5640245013098010347">"دارای بیشترین اعلان"</string>
+    <string name="sort_order_frequent_notification" msgid="5640245013098010347">"پرتکرارترین"</string>
     <string name="show_running_services" msgid="1895994322704667543">"نمایش سرویس‌های در حال اجرا"</string>
     <string name="show_background_processes" msgid="88012264528093617">"فرآیندهای ذخیره شده در حافظهٔ پنهان"</string>
     <string name="default_emergency_app" msgid="286530070173495823">"برنامه اضطراری"</string>
@@ -2033,7 +2038,7 @@
     <string name="accessibility_settings_title" msgid="1687226556576913576">"تنظیمات دسترس‌پذیری"</string>
     <string name="accessibility_settings_summary" msgid="5742379519336396561">"صفحه‌خوان‌ها، نمایشگر، کنترل‌های تعامل"</string>
     <string name="vision_settings_title" msgid="7315352351051423944">"تنظیمات بینایی"</string>
-    <string name="vision_settings_description" msgid="3476589459009287332">"می‌توانید این دستگاه را متناسب با نیازهایتان سفارشی کنید. می‌توانید بعداً در «تنظیمات»، این قابلیت‌های دسترس‌پذیری را تغییر دهید."</string>
+    <string name="vision_settings_description" msgid="3476589459009287332">"می‌توانید این دستگاه را متناسب با نیازهایتان سفارشی کنید. می‌توانید بعداً در «تنظیمات»، این ویژگی‌های دسترس‌پذیری را تغییر دهید."</string>
     <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"تغییر اندازه قلم"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"صفحه‌خوان‌ها"</string>
     <string name="audio_and_captions_category_title" msgid="6140472938769619212">"صدا و نوشتار روی صفحه"</string>
@@ -2146,7 +2151,7 @@
     <string name="captioning_standard_options_title" msgid="4124898413348084226">"گزینه‌های استاندارد"</string>
     <string name="captioning_locale" msgid="4734464353806207943">"زبان"</string>
     <string name="captioning_text_size" msgid="1707122517246408084">"اندازه نوشتار"</string>
-    <string name="captioning_preset" msgid="7429888317480872337">"سبک برنگاشت"</string>
+    <string name="captioning_preset" msgid="7429888317480872337">"سبک زیرنویس"</string>
     <string name="captioning_custom_options_title" msgid="4530479671071326732">"گزینه‌های سفارشی"</string>
     <string name="captioning_background_color" msgid="2434458880326292180">"رنگ پس‌زمینه"</string>
     <string name="captioning_background_opacity" msgid="8178926599201811936">"ماتی پس‌زمینه"</string>
@@ -2450,7 +2455,7 @@
     <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"در <xliff:g id="PERCENT">%1$s</xliff:g> روشن خواهد شد"</string>
     <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"تنظیم زمان‌بندی"</string>
     <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"وقتی شارژ کامل شد، خاموش شود"</string>
-    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"وقتی شارژ تلفن <xliff:g id="PERCENT">%1$s</xliff:g> باشد، «بهینه‌سازی باتری» خاموش می‌شود"</string>
+    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"وقتی شارژ تلفن <xliff:g id="PERCENT">%1$s</xliff:g> شود، «بهینه‌سازی باتری» خاموش می‌شود"</string>
     <string name="battery_saver_sticky_description_new" product="tablet" msgid="3284967694001857194">"وقتی شارژ رایانه لوحی <xliff:g id="PERCENT">%1$s</xliff:g> باشد، «بهینه‌سازی باتری» خاموش می‌شود"</string>
     <string name="battery_saver_sticky_description_new" product="device" msgid="5056520668081504111">"وقتی شارژ دستگاه <xliff:g id="PERCENT">%1$s</xliff:g> باشد، «بهینه‌سازی باتری» خاموش می‌شود"</string>
     <!-- no translation found for battery_saver_seekbar_title (7607123201469333645) -->
@@ -2814,7 +2819,7 @@
     <string name="n_cacrts" msgid="7539893176217891549">"%d گواهی CA"</string>
     <string name="user_credential_title" msgid="6237611303219831419">"جزئیات اعتبارنامه"</string>
     <string name="user_credential_removed" msgid="6243576567538844852">"اعتبارنامه برداشته شد: <xliff:g id="CREDENTIAL_NAME">%s</xliff:g>"</string>
-    <string name="user_credential_none_installed" msgid="4129252817676332368">"اطلاعات کاربری‌ای نصب نشد"</string>
+    <string name="user_credential_none_installed" msgid="4129252817676332368">"اطلاعات کاربری‌ای نصب نشده"</string>
     <string name="spellcheckers_settings_title" msgid="1687210427248364327">"غلط‌گیر املا"</string>
     <string name="spellcheckers_settings_for_work_title" msgid="7461318390801573022">"غلط‌گیر املا برای کار"</string>
     <string name="current_backup_pw_prompt" msgid="8914812770233159610">"گذرواژه فعلی پشتیبان‌گیری‌تان را به‌طور کامل اینجا تایپ کنید"</string>
@@ -2842,7 +2847,7 @@
       <item quantity="one">بررسی گواهی</item>
       <item quantity="other">بررسی گواهی‌ها</item>
     </plurals>
-    <string name="user_settings_title" msgid="7917598650933179545">"چندین کاربر"</string>
+    <string name="user_settings_title" msgid="7917598650933179545">"چند کاربر"</string>
     <string name="user_settings_footer_text" product="device" msgid="4573858247439190545">"با افزودن کاربران جدید، از دستگاهتان به‌صورت مشترک استفاده کنید. هر کاربر فضایی شخصی برای سفارشی کردن صفحه‌های اصلی، حساب‌ها، برنامه‌ها، تنظیمات و موارد دیگر در دستگاه شما دارد."</string>
     <string name="user_settings_footer_text" product="tablet" msgid="780018221428132918">"با افزودن کاربران جدید، از رایانه لوحی‌تان به‌صورت مشترک استفاده کنید. هر کاربر فضایی شخصی برای سفارشی کردن صفحه‌های اصلی، حساب‌ها، برنامه‌ها، تنظیمات و موارد دیگر در رایانه لوحی شما دارد."</string>
     <string name="user_settings_footer_text" product="default" msgid="1470859614968237491">"با افزودن کاربران جدید، از تلفنتان به‌صورت مشترک استفاده کنید. هر کاربر فضایی شخصی برای سفارشی کردن صفحه‌های اصلی، حساب‌ها، برنامه‌ها، تنظیمات و موارد دیگر در تلفن شما دارد."</string>
@@ -2920,7 +2925,7 @@
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"به‌جز وقتی برنامه پرداخت دیگری باز است"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"در پایانه «ضربه و پرداخت»، با این مورد پرداخت شود:"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"پرداخت در پایانه"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"یک برنامه پرداخت تنظیم کنید. سپس کافیست پشت تلفنتان را بالای هر پایانه دارای نشان «بدون تماس» نگه دارید."</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"یک برنامه پرداخت تنظیم کنید. سپس کافی است پشت تلفنتان را بالای هر پایانه دارای نشان «بدون تماس» نگه دارید."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"متوجه شدم"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"بیشتر..."</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"به عنوان روش ترجیحی شما تنظیم شود؟"</string>
@@ -3039,7 +3044,7 @@
     <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"دستیار، برنامه‌های اخیر، برنامه‌های پیش‌فرض"</string>
     <string name="notification_settings_work_profile" msgid="7190550347842400029">"برنامه‌ها نمی‌توانند در نمایه کاری به اعلان‌ها دسترسی داشته باشند."</string>
     <string name="account_dashboard_title" msgid="4734300939532555885">"حساب‌ها"</string>
-    <string name="account_dashboard_default_summary" msgid="6822549669771936206">"حسابی اضافه نشد"</string>
+    <string name="account_dashboard_default_summary" msgid="6822549669771936206">"حسابی اضافه نشده"</string>
     <string name="app_default_dashboard_title" msgid="6575301028225232193">"برنامه‌های پیش‌فرض"</string>
     <string name="system_dashboard_summary" msgid="6582464466735779394">"زبان‌ها، ژست‌ها، زمان، پشتیبان"</string>
     <string name="search_results_title" msgid="4160717656435503940">"تنظیمات"</string>
@@ -3062,7 +3067,7 @@
     <string name="keywords_display_night_display" msgid="3647370193110044967">"صفحه کم‌نور، شب، رنگ‌مایه، شیفت شب، روشنایی، رنگ صفحه، رنگ، رنگ"</string>
     <string name="keywords_display_wallpaper" msgid="1202089324795933197">"پس‌زمینه، شخصی کردن، سفارشی کردن نمایشگر"</string>
     <string name="keywords_display_font_size" msgid="1496431330244040196">"اندازه نوشتار"</string>
-    <string name="keywords_display_cast_screen" msgid="5744566533025100355">"نمایش دادن، ارسال محتوا، نمایش صفحه‌نمایش روی دستگاه دیگر، اشتراک‌گذای صفحه‌نمایش، صفحه‌نمایش مشترک، ارسال محتوای صفحه‌نمایش"</string>
+    <string name="keywords_display_cast_screen" msgid="5744566533025100355">"نمایش دادن، ارسال محتوا، نمایش صفحه‌نمایش روی دستگاه دیگر، هم‌رسانیی صفحه‌نمایش، صفحه‌نمایش مشترک، ارسال محتوای صفحه‌نمایش"</string>
     <string name="keywords_storage" msgid="7704519289838065803">"فضا، دیسک، دیسک سخت، مصرف دستگاه"</string>
     <string name="keywords_battery" msgid="3860198379310375112">"مصرف نیرو، شارژ"</string>
     <string name="keywords_spell_checker" msgid="6032411442958278879">"املا، واژه‌نامه، غلط‌گیر املا، تصحیح خودکار"</string>
@@ -3081,7 +3086,7 @@
     <string name="keywords_keyboard_and_ime" msgid="3327265741354129990">"تصحیح نوشتار، تصحیح، صدا، لرزش، خودکار، زبان، اشاره، پیشنهاد دادن، پیشنهاد، طرح زمینه، توهین‌آمیز، کلمه، نوع، اموجی، بین‌المللی"</string>
     <string name="keywords_reset_apps" msgid="2645701455052020435">"بازنشانی، اولویت‌ها، پیش‌فرض"</string>
     <string name="keywords_all_apps" msgid="846444448435698930">"برنامه‌ها، بارگیری، برنامه‌های کاربردی، سیستم"</string>
-    <string name="keywords_app_permissions" msgid="8539841019997048500">"برنامه‌ها، مجوزها، امنیت"</string>
+    <string name="keywords_app_permissions" msgid="8539841019997048500">"برنامه‌ها، اجازه‌ها، امنیت"</string>
     <string name="keywords_default_apps" msgid="7435952699323965532">"برنامه‌ها، پیش‌فرض"</string>
     <string name="keywords_ignore_optimizations" msgid="9127632532176249438">"نادیده گرفتن بهینه‌سازی، چرت، حالت آماده به‌کار برنامه"</string>
     <string name="keywords_color_mode" msgid="8893345199519181751">"زنده، RGB، ‏sRGB، رنگ، طبیعی، استاندارد"</string>
@@ -3107,18 +3112,18 @@
     <string name="keywords_face_settings" msgid="4117345666006836599">"چهره"</string>
     <string name="keywords_fingerprint_settings" msgid="902902368701134163">"اثر انگشت، افزودن اثر انگشت"</string>
     <string name="keywords_display_auto_brightness" msgid="1810596220466483996">"تار کردن صفحه‌نمایش، صفحه لمسی، باتری، روشنایی هوشمند، روشنایی پویا"</string>
-    <string name="keywords_display_adaptive_sleep" msgid="1695357782432822811">"کم‌نور کردن صفحه، خواب، باتری، مهلت زمانی، توجه، نمایشگر، صفحه، بی‌فعالیتی"</string>
+    <string name="keywords_display_adaptive_sleep" msgid="1695357782432822811">"کم‌نور کردن صفحه، خواب، باتری، درنگ، توجه، نمایشگر، صفحه، بی‌فعالیتی"</string>
     <string name="keywords_auto_rotate" msgid="4320791369951647513">"چرخاندن، چرخش، چرخش، پرتره، منظره، جهت، عمودی، افقی"</string>
     <string name="keywords_system_update_settings" msgid="4419971277998986067">"ارتقا دادن، Android"</string>
     <string name="keywords_zen_mode_settings" msgid="4103819458182535493">"«مزاحم نشوید»، زمان‌بندی، اعلان‌ها، مسدود کردن، سکوت، لرزش، خواب، کار، کانونی کردن، صدا، صامت کردن، روز، روز هفته، آخر هفته، شب‌های طول هفته، رویداد"</string>
-    <string name="keywords_screen_timeout" msgid="4328381362313993666">"صفحه نمایش، زمان قفل شدن، مهلت زمانی، صفحه درحالت قفل"</string>
+    <string name="keywords_screen_timeout" msgid="4328381362313993666">"صفحه نمایش، زمان قفل شدن، درنگ، صفحه درحالت قفل"</string>
     <string name="keywords_storage_settings" msgid="6422454520424236476">"حافظه، حافظه پنهان، داده، حذف، پاک کردن، آزاد، فضا"</string>
     <string name="keywords_bluetooth_settings" msgid="1152229891590622822">"متصل، دستگاه، هدفون‌ها، هدست‌ها، بلندگو، بی‌سیم، مرتبط‌سازی، هدفون‌های توگوشی، موسیقی، رسانه"</string>
     <string name="keywords_wallpaper" msgid="7665778626293643625">"پس‌زمینه، صفحه نمایش، صفحه در حالت قفل، طرح زمینه"</string>
     <string name="keywords_assist_input" msgid="8392362788794886564">"پیش‌فرض، دستیار"</string>
     <string name="keywords_default_payment_app" msgid="845369409578423996">"پرداخت، پیش‌فرض"</string>
     <string name="keywords_ambient_display" msgid="8835182491798487184">"اعلان ورودی"</string>
-    <string name="keywords_hotspot_tethering" msgid="1723591462602613867">"اتصال به اینترنت با USB تلفن همراه، اتصال اینترنت به بلوتوث تلفن همراه، نقطه اتصال Wi-Fi"</string>
+    <string name="keywords_hotspot_tethering" msgid="1723591462602613867">"اشتراک‌گذاری اینترنت با USB، اتصال اینترنت به بلوتوث تلفن همراه، نقطه اتصال Wi-Fi"</string>
     <string name="keywords_touch_vibration" msgid="2081175517528255224">"لمسی، لرزش، صفحه نمایش، حساسیت"</string>
     <string name="keywords_ring_vibration" msgid="4210509151866460210">"لمس، لرزش، تلفن، تماس، حساسیت، به صدا در آوردن زنگ"</string>
     <string name="keywords_notification_vibration" msgid="1077515502086745166">"لمس، لرزش، حساسیت"</string>
@@ -3146,7 +3151,7 @@
     <string name="screen_locking_sounds_title" msgid="4407110895465866809">"صداهای قفل شدن صفحه"</string>
     <string name="charging_sounds_title" msgid="5070437987230894287">"صدا و لرزش هنگام شارژ شدن"</string>
     <string name="docking_sounds_title" msgid="2573137471605541366">"صداهای اتصال به پایه"</string>
-    <string name="touch_sounds_title" msgid="165237488496165652">"صداهای لمس"</string>
+    <string name="touch_sounds_title" msgid="165237488496165652">"صدای لمس کردن"</string>
     <string name="vibrate_on_touch_title" msgid="6360155469279157684">"لرزش لمس کردن"</string>
     <string name="vibrate_on_touch_summary" msgid="5504424764028676043">"بازخورد لمسی برای ضربه زدن، صفحه‌کلید و موارد بیشتر"</string>
     <string name="dock_audio_media_title" msgid="1859521680502040781">"پخش بلندگوی پایه"</string>
@@ -3156,7 +3161,7 @@
     <string name="emergency_tone_alert" msgid="907868135091891015">"آهنگ‌ها"</string>
     <string name="emergency_tone_vibrate" msgid="5020068066905681181">"لرزش‌ها"</string>
     <string name="boot_sounds_title" msgid="7583926202411353620">"صدای راه‌اندازی"</string>
-    <string name="live_caption_title" msgid="7926591158657997051">"برنگاشت زنده"</string>
+    <string name="live_caption_title" msgid="7926591158657997051">"زیرنویس زنده"</string>
     <string name="live_caption_summary" msgid="9064771862352393125">"رسانه زیرنویس خودکار"</string>
     <string name="zen_mode_settings_summary_off" msgid="6929319200478424962">"هرگز"</string>
     <plurals name="zen_mode_settings_summary_on" formatted="false" msgid="6061723291126091396">
@@ -3196,7 +3201,7 @@
     <string name="zen_mode_restrict_notifications_mute_footer" msgid="3049522809520549054">"هنگام دریافت اعلان‌، تلفنتان صدا نمی‌دهد یا نمی‌لرزد."</string>
     <string name="zen_mode_restrict_notifications_hide" msgid="3296933643539682552">"بدون تصویر یا صدای اعلان‌ها"</string>
     <string name="zen_mode_restrict_notifications_hide_summary" msgid="1449301153755270168">"اعلان‌ها را نخواهید دید یا صدایشان را نخواهید شنید."</string>
-    <string name="zen_mode_restrict_notifications_hide_footer" msgid="7617688597593946765">"تلفنتان برای اعلان‌های جدید یا موجود صدایی نمی‌کند، نمی‌لرزد، یا آن‌ها را نشان نمی‌دهد. به‌خاطر داشته باشید، اعلان‌های مهم مربوط به فعالیت و وضعیت تلفن هنوز نمایش داده می‌شود.\n\nوقتی «مزاحم نشوید» را خاموش می‌کنید، می‌توانید با تند کشیدن از بالای صفحه به پایین، اعلان‌های بررسی‌نشده را پیدا کنید."</string>
+    <string name="zen_mode_restrict_notifications_hide_footer" msgid="7617688597593946765">"تلفنتان برای اعلان‌های جدید یا موجود صدا نمی‌دهد، نمی‌لرزد، یا آن‌ها را نشان نمی‌دهد. به‌خاطر داشته باشید که اعلان‌های مهم مربوط به فعالیت و وضعیت تلفن هنوز نمایش داده می‌شود.\n\nوقتی «مزاحم نشوید» را خاموش می‌کنید، می‌توانید با تند کشیدن از بالای صفحه به پایین، اعلان‌های بررسی‌نشده را پیدا کنید."</string>
     <string name="zen_mode_restrict_notifications_custom" msgid="3167252482570424133">"سفارشی"</string>
     <string name="zen_mode_restrict_notifications_enable_custom" msgid="6376983315529894440">"فعال کردن تنظیم سفارشی"</string>
     <string name="zen_mode_restrict_notifications_disable_custom" msgid="8004212081465043044">"حذف تنظیم سفارشی"</string>
@@ -3301,13 +3306,13 @@
     <string name="hide_silent_icons_title" msgid="1070905516921542662">"پنهان کردن نمادهای وضعیت اعلان‌ بی‌صدا"</string>
     <string name="hide_silent_icons_summary" msgid="2624346914488256888">"پنهان کردن نمادهای اعلان بی‌صدا در نوار وضعیت"</string>
     <string name="notification_badging_title" msgid="6311699476970264712">"اجازه به نقطه‌های اعلان"</string>
-    <string name="notification_bubbles_title" msgid="9196562435741861317">"ابزارک‌های اعلان"</string>
+    <string name="notification_bubbles_title" msgid="9196562435741861317">"حبابک‌ها"</string>
     <string name="notification_bubbles_summary" msgid="4624512775901949578">"دسترسی سریع به محتوای برنامه از هرجایی بااستفاده از میانبرهای شنارو"</string>
-    <string name="bubbles_feature_education" msgid="8979109826818881018">"برخی اعلان‌ها و سایر محتواها می‌تواند درقالب ابزارک اعلان روی صفحه نشان داده شود. برای باز کردن ابزارک اعلان، روی آن ضربه بزنید. برای رد کردن، آن را به پایین صفحه بکشید."</string>
-    <string name="bubbles_app_toggle_title" msgid="6401217027603326439">"ابزارک‌های اعلان"</string>
-    <string name="bubbles_app_toggle_summary" msgid="7707611139796553855">"مجاز کردن <xliff:g id="APP_NAME">%1$s</xliff:g> برای نمایش برخی اعلان‌ها درقالب ابزارک اعلان"</string>
-    <string name="bubbles_feature_disabled_dialog_title" msgid="3375452386012079293">"روشن کردن ابزارک اعلان"</string>
-    <string name="bubbles_feature_disabled_dialog_text" msgid="326945485806386477">"برای روشن کردن ابزارک‌های اعلان برای این برنامه، ابتدا باید آن‌ها را برای این دستگاه روشن کنید. این کار بر سایر برنامه‌هایی که قبلاً ابزارک‌های اعلان را در آن‌ها روشن کرده‌اید تأثیر می‌گذارد."</string>
+    <string name="bubbles_feature_education" msgid="8979109826818881018">"برخی اعلان‌ها و سایر محتواها می‌تواند درقالب حبابک روی صفحه نشان داده شود. برای باز کردن حبابک، روی آن ضربه بزنید. برای رد کردن، آن را به پایین صفحه بکشید."</string>
+    <string name="bubbles_app_toggle_title" msgid="6401217027603326439">"حبابک‌ها"</string>
+    <string name="bubbles_app_toggle_summary" msgid="7707611139796553855">"مجاز کردن <xliff:g id="APP_NAME">%1$s</xliff:g> برای نمایش برخی اعلان‌ها درقالب حبابک"</string>
+    <string name="bubbles_feature_disabled_dialog_title" msgid="3375452386012079293">"روشن کردن حبابک‌ها"</string>
+    <string name="bubbles_feature_disabled_dialog_text" msgid="326945485806386477">"برای روشن کردن حبابک‌ها برای این برنامه، ابتدا باید آن‌ها را برای این دستگاه روشن کنید. این کار روی سایر برنامه‌هایی که قبلاً حبابک‌ها را در آن‌ها روشن کرده‌اید تأثیر می‌گذارد."</string>
     <string name="bubbles_feature_disabled_button_approve" msgid="6661464849674493351">"روشن کردن برای دستگاه"</string>
     <string name="bubbles_feature_disabled_button_cancel" msgid="4807286844588486198">"لغو"</string>
     <string name="swipe_direction_title" msgid="7535031630668873009">"کنش‌های تند کشیدن"</string>
@@ -3498,8 +3503,8 @@
     <string name="zen_mode_alarms_list" msgid="9162210238533665593">"هشدارها"</string>
     <string name="zen_mode_media" msgid="3701280649874724055">"پخش صداهای رسانه"</string>
     <string name="zen_mode_media_list" msgid="509327580522287125">"رسانه‌ها"</string>
-    <string name="zen_mode_system" msgid="597437265986355038">"مجاز کردن صداهای لمس"</string>
-    <string name="zen_mode_system_list" msgid="480192458506838077">"صداهای لمس"</string>
+    <string name="zen_mode_system" msgid="597437265986355038">"مجاز کردن صدای لمس کردن"</string>
+    <string name="zen_mode_system_list" msgid="480192458506838077">"صدای لمس کردن"</string>
     <string name="zen_mode_reminders" msgid="7560664194610054038">"مجاز کردن یادآوری‌ها"</string>
     <string name="zen_mode_reminders_list" msgid="7347061314032326677">"یادآوری‌ها"</string>
     <string name="zen_mode_events" msgid="5784076928339534984">"مجاز کردن رویدادها"</string>
@@ -3583,7 +3588,7 @@
     <string name="imei_information_title" msgid="7666097743700170757">"اطلاعات IMEI"</string>
     <string name="imei_information_summary" msgid="716516316022275083">"اطلاعات مربوط به IMEI"</string>
     <string name="slot_number" msgid="785422579177068698">"(شکاف<xliff:g id="SLOT_NUM">%1$d</xliff:g>)"</string>
-    <string name="launch_by_default" msgid="6106985160202769725">"باز کردن به صورت پیش‌فرض"</string>
+    <string name="launch_by_default" msgid="6106985160202769725">"باز کردن به‌صورت پیش‌فرض"</string>
     <string name="app_launch_domain_links_title" msgid="2987289657348349133">"باز کردن پیوندها"</string>
     <string name="app_launch_open_domain_urls_title" msgid="8595126859922391331">"باز کردن پیوندهای پشتیبانی شده"</string>
     <string name="app_launch_open_domain_urls_summary" msgid="6803029846855502366">"باز کردن بدون پرسش"</string>
@@ -3621,8 +3626,8 @@
       <item quantity="other">‏<xliff:g id="COUNT_2">%d</xliff:g> از <xliff:g id="COUNT_3">%d</xliff:g> اجازه اعطا شد</item>
     </plurals>
     <plurals name="runtime_permissions_additional_count" formatted="false" msgid="2068102378805218668">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> مجوز اضافی</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> مجوز اضافی</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> اجازه تکمیلی</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> اجازه‌های تکمیلی</item>
     </plurals>
     <string name="runtime_permissions_summary_no_permissions_granted" msgid="3477934429220828771">"اجازه‌ای داده نشده"</string>
     <string name="runtime_permissions_summary_no_permissions_requested" msgid="3901636077467389637">"اجازه‌ای درخواست نشده"</string>
@@ -3640,7 +3645,7 @@
     <string name="advanced_apps" msgid="6643869089344883537">"پیشرفته"</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" msgid="3215958256821756086">"مدیر اجازه‌ها"</string>
     <string name="app_permissions_summary" msgid="8785798165776061594">"برنامه‌های درحال استفاده از <xliff:g id="APPS">%1$s</xliff:g>"</string>
     <string name="tap_to_wake" msgid="1902991239401652323">"ضربه برای بیدار شدن"</string>
     <string name="tap_to_wake_summary" msgid="8485222120721006793">"برای بیدار کردن دستگاه روی قسمتی از صفحه دوبار ضربه بزنید"</string>
@@ -3713,7 +3718,7 @@
     <string name="no_battery_summary" msgid="4105932628367471314">"از آخرین شارژ کامل، از باتری استفاده نشده است"</string>
     <string name="app_notification_preferences" msgid="5154466638524523201">"تنظیمات برنامه"</string>
     <string name="system_ui_settings" msgid="6751165163665775447">"نمایش تنظیم‌گر واسط کاربری سیستم"</string>
-    <string name="additional_permissions" msgid="3142290772324571654">"مجوزهای بیشتر"</string>
+    <string name="additional_permissions" msgid="3142290772324571654">"اجازه‌های تکمیلی"</string>
     <string name="additional_permissions_more" msgid="714264060348056246">"<xliff:g id="COUNT">%1$d</xliff:g> مورد دیگر"</string>
     <string name="share_remote_bugreport_dialog_title" msgid="1390719492733882678">"گزارش اشکال به اشتراک گذاشته شود؟"</string>
     <string name="share_remote_bugreport_dialog_message_finished" msgid="5133489230646384192">"سرپرست فناوری اطلاعات شما برای کمک به عیب‌یابی این دستگاه، گزارش اشکال درخواست کرده است. ممکن است برنامه‌ها و داده‌ها به اشتراک گذاشته شوند."</string>
@@ -3755,10 +3760,10 @@
     <string name="background_check_title" msgid="4136736684290307970">"دسترسی کامل به پس‌زمینه"</string>
     <string name="assist_access_context_title" msgid="2274614501747710439">"استفاده از نوشتار صفحه"</string>
     <string name="assist_access_context_summary" msgid="5867997494395842785">"اجازه به برنامه همیار برای دسترسی به محتوای صفحه به‌عنوان نوشتار"</string>
-    <string name="assist_access_screenshot_title" msgid="1991014038776117688">"استفاده از عکس صفحه‌نمایش"</string>
+    <string name="assist_access_screenshot_title" msgid="1991014038776117688">"استفاده از نماگرفت"</string>
     <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"اجازه به برنامه همیار برای دسترسی به تصویری از صفحه"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"چشمک زدن صفحه‌نمایش"</string>
-    <string name="assist_flash_summary" msgid="6697095786317559129">"چشمک زدن لبه‌های صفحه‌نمایش وقتی برنامه همیار به نوشتار صفحه‌نمایش یا عکس صفحه‌نمایش دسترسی پیدا می‌کند"</string>
+    <string name="assist_flash_summary" msgid="6697095786317559129">"چشمک زدن لبه‌های صفحه‌نمایش وقتی برنامه همیار به نوشتار صفحه‌نمایش یا نماگرفت دسترسی پیدا می‌کند"</string>
     <string name="assist_footer" msgid="7030121180457472165">"برنامه‌های همیار براساس اطلاعات از صفحه‌ای که در آن هستید به شما کمک می‌کنند. بعضی از برنامه‌ها از هر دو سرویس راه‌انداز و ورودی صوتی پشتیبانی می‌کنند تا کمک یکپارچه‌ای به شما ارائه دهند."</string>
     <string name="average_memory_use" msgid="5333366040118953945">"مصرف حافظه به‌طور متوسط"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"حداکثر مصرف حافظه"</string>
@@ -3866,7 +3871,7 @@
     <string name="backup_disabled" msgid="6941165814784765643">"پشتیبان‌گیری غیرفعال است"</string>
     <string name="android_version_summary" msgid="2192751442789395445">"به‌روزرسانی‌شده به Android نسخه <xliff:g id="VERSION">%1$s</xliff:g>"</string>
     <string name="android_version_pending_update_summary" msgid="3554543810520655076">"به‌روزرسانی در دسترس است"</string>
-    <string name="disabled_by_policy_title" msgid="1238318274952958846">"عملکرد مجاز نیست"</string>
+    <string name="disabled_by_policy_title" msgid="1238318274952958846">"کنش مجاز نیست"</string>
     <string name="disabled_by_policy_title_adjust_volume" msgid="7094547090629203316">"نمی‌توان بلندی صدا را تغییر داد"</string>
     <string name="disabled_by_policy_title_outgoing_calls" msgid="3805836913095496278">"برقراری تماس تلفنی مجاز نیست"</string>
     <string name="disabled_by_policy_title_sms" msgid="1453236584236681105">"استفاده از پیامک مجاز نیست"</string>
@@ -4094,11 +4099,11 @@
       <item quantity="one">‏<xliff:g id="NUMBER">%s</xliff:g> ثانیه</item>
       <item quantity="other">‏<xliff:g id="NUMBER">%s</xliff:g> ثانیه</item>
     </plurals>
-    <string name="automatic_storage_manager_settings" msgid="2403621409625820182">"مدیریت حافظه"</string>
+    <string name="automatic_storage_manager_settings" msgid="2403621409625820182">"مدیریت فضای ذخیره‌سازی"</string>
     <string name="automatic_storage_manager_text" msgid="4270379105066667493">"برای کمک به خالی کردن فضای ذخیره‌سازی، مدیر ذخیره‌سازی عکس‌ها و ویدیوهای پشتیبان‌گیری‌شده را از دستگاهتان پاک می‌کند."</string>
     <string name="automatic_storage_manager_days_title" msgid="1783767804707813799">"پاک کردن عکس‌ها و ویدئوها"</string>
     <string name="automatic_storage_manager_preference_title" msgid="4668642150512639466">"مدیر فضای ذخیره‌سازی"</string>
-    <string name="automatic_storage_manager_master_switch_title" msgid="1456978117739582562">"استفاده از مدیر حافظه"</string>
+    <string name="automatic_storage_manager_master_switch_title" msgid="1456978117739582562">"استفاده از «مدیر فضای ذخیره‌سازی»"</string>
     <string name="deletion_helper_automatic_title" msgid="4370975149425263205">"خودکار"</string>
     <string name="deletion_helper_manual_title" msgid="1011785013431162078">"دستی"</string>
     <string name="deletion_helper_preference_title" msgid="797270307034242206">"هم‌اکنون فضا را خالی کنید"</string>
@@ -4149,7 +4154,7 @@
     <string name="web_action_section_title" msgid="5563229447734734662">"برنامه‌های فوری"</string>
     <string name="instant_apps_settings" msgid="879003203555847537">"اولویت‌های برنامه‌های فوری"</string>
     <string name="domain_url_section_title" msgid="206403507921518321">"برنامه‌های نصب‌شده"</string>
-    <string name="automatic_storage_manager_activation_warning" msgid="2630083316417707308">"حافظه شما اکنون توسط مدیر حافظه مدیریت می‌شود"</string>
+    <string name="automatic_storage_manager_activation_warning" msgid="2630083316417707308">"مدیر فضای ذخیره‌سازی اکنون فضای ذخیره‌سازی شما را مدیریت می‌کند"</string>
     <string name="account_for_section_header" msgid="5975241715840642563">"حساب‌های <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="configure_section_header" msgid="6988981883075615136">"پیکربندی"</string>
     <string name="auto_sync_account_title" msgid="2394463123733529506">"همگام‌سازی خودکار داده‌ها"</string>
@@ -4243,7 +4248,7 @@
     <string name="launch_instant_app" msgid="5251693061228352333">"باز کردن"</string>
     <string name="game_storage_settings" msgid="6856911551799175914">"بازی"</string>
     <string name="audio_files_title" msgid="3073879661731363935">"فایل‌های صوتی"</string>
-    <string name="app_info_storage_title" msgid="6643391804949509308">"فضای مورداستفاده"</string>
+    <string name="app_info_storage_title" msgid="6643391804949509308">"فضای استفاده‌شده"</string>
     <string name="webview_uninstalled_for_user" msgid="3407952144444040557">"(برای کاربر <xliff:g id="USER">%s</xliff:g> حذف نصب شد)"</string>
     <string name="webview_disabled_for_user" msgid="8057805373224993504">"(برای کاربر <xliff:g id="USER">%s</xliff:g> غیرفعال شد)"</string>
     <string name="autofill_app" msgid="3990765434980280073">"سرویس تکمیل خودکار"</string>
@@ -4259,7 +4264,7 @@
     <string name="default_theme" msgid="5986996377385956138">"پیش‌فرض"</string>
     <string name="show_operator_name_title" msgid="5056163028128447308">"نام شبکه"</string>
     <string name="show_operator_name_summary" msgid="6352180285743777497">"نمایش نام شبکه در نوار وضعیت"</string>
-    <string name="storage_manager_indicator" msgid="4255140732848476875">"مدیریت حافظه: <xliff:g id="STATUS">^1</xliff:g>"</string>
+    <string name="storage_manager_indicator" msgid="4255140732848476875">"مدیریت فضای ذخیره‌سازی: <xliff:g id="STATUS">^1</xliff:g>"</string>
     <string name="storage_manager_indicator_off" msgid="6404056007102580777">"خاموش"</string>
     <string name="storage_manager_indicator_on" msgid="5295306384982062320">"روشن"</string>
     <string name="install_type_instant" msgid="6248487669862821874">"برنامه فوری"</string>
@@ -4424,7 +4429,7 @@
     <string name="carrier_settings_euicc" msgid="7723199738771996732">"شرکت مخابراتی"</string>
     <string name="carrier_settings_version" msgid="2657511289029828425">"نسخه تنظیمات"</string>
     <string name="call_category" msgid="3418535202893644015">"درحال تماس"</string>
-    <string name="video_calling_settings_title" msgid="8011841542502156112">"تماس ویدیویی با شرکت مخابراتی"</string>
+    <string name="video_calling_settings_title" msgid="8011841542502156112">"تماس تصویری با شرکت مخابراتی"</string>
     <string name="cdma_system_select_title" msgid="5620679296177526467">"انتخاب سیستم"</string>
     <string name="cdma_system_select_summary" msgid="6749131988334321244">"تغییر حالت فراگردی CDMA"</string>
     <string name="cdma_system_select_dialogtitle" msgid="7489000866289285390">"انتخاب سیستم"</string>
diff --git a/tests/CarDeveloperOptions/res/values-fi/arrays.xml b/tests/CarDeveloperOptions/res/values-fi/arrays.xml
index 2a383bb..a92007f 100644
--- a/tests/CarDeveloperOptions/res/values-fi/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-fi/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"toimi taustalla"</item>
     <item msgid="6423861043647911030">"esteettömyys äänenvoimakkuus"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Sijainti"</item>
+    <item msgid="6656077694190491067">"Sijainti"</item>
+    <item msgid="8790228218278477369">"Sijainti"</item>
+    <item msgid="7836406246005211990">"Värinä"</item>
+    <item msgid="3951439024549922598">"Lue yhteystietoja"</item>
+    <item msgid="8802152411647068">"Muokkaa yhteystietoja"</item>
+    <item msgid="229544934599698735">"Lue puhelulokia"</item>
+    <item msgid="7396102294405899613">"Muokkaa puhelulokia"</item>
+    <item msgid="3597797992398484655">"Lue kalenteria"</item>
+    <item msgid="2705975774250907343">"Muokkaa kalenteria"</item>
+    <item msgid="4668747371441932697">"Sijainti"</item>
+    <item msgid="1487578921720243646">"Lisää ilmoitus"</item>
+    <item msgid="4636080349724146638">"Sijainti"</item>
+    <item msgid="673510900286463926">"Soita numeroon"</item>
+    <item msgid="542083422784609790">"Lue SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Kirjoita SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Vastaanota multimedia- tai tekstiviestejä"</item>
+    <item msgid="8591105601108455893">"Vastaanota multimedia- tai tekstiviestejä"</item>
+    <item msgid="7730995008517841903">"Vastaanota multimedia- tai tekstiviestejä"</item>
+    <item msgid="2613033109026626086">"Vastaanota multimedia- tai tekstiviestejä"</item>
+    <item msgid="3037159047591081136">"Lähetä multimedia- tai tekstiviestejä"</item>
+    <item msgid="4726682243833913568">"Lue SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Kirjoita SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Muokkaa asetuksia"</item>
+    <item msgid="8705854389991425629">"Piirrä päälle"</item>
+    <item msgid="5861356020344153651">"Käytä ilmoituksia"</item>
+    <item msgid="78432174621628659">"Kamera"</item>
+    <item msgid="3986116419882154794">"Tallenna ääntä"</item>
+    <item msgid="4516840825756409490">"Toista ääntä"</item>
+    <item msgid="6811712502798183957">"Lue leikepöytä"</item>
+    <item msgid="2780369012602289114">"Muokkaa leikepöytää"</item>
+    <item msgid="2331359440170850868">"Mediapainikkeet"</item>
+    <item msgid="6133599737122751231">"Äänen painopiste"</item>
+    <item msgid="6844485713404805301">"Pää-äänenvoimakkuus"</item>
+    <item msgid="1600379420669104929">"Puheäänen voimakkuus"</item>
+    <item msgid="6296768210470214866">"Soittoäänen voimakkuus"</item>
+    <item msgid="510690696071629241">"Median äänenvoimakkuus"</item>
+    <item msgid="406861638631430109">"Hälytyksen voimakkuus"</item>
+    <item msgid="4715864795872233884">"Ilmoituksen äänenvoimakkuus"</item>
+    <item msgid="2311478519251301183">"Bluetooth-äänenvoimakkuus"</item>
+    <item msgid="5133991377896747027">"Ei virransäästötilaa"</item>
+    <item msgid="2464189519136248621">"Sijainti"</item>
+    <item msgid="2062677934050803037">"Sijainti"</item>
+    <item msgid="1735171933192715957">"Hae käyttötilastot"</item>
+    <item msgid="1014093788778383554">"Mykistä mikrofoni / poista mykistys"</item>
+    <item msgid="4199297950608622850">"Näytä ilmoitus"</item>
+    <item msgid="2527962435313398821">"Lähetä media"</item>
+    <item msgid="5117506254221861929">"Aktivoi VPN"</item>
+    <item msgid="8291198322681891160">"Kirjoita taustakuva"</item>
+    <item msgid="7106921284621230961">"Apurakenne"</item>
+    <item msgid="4496533640894624799">"Apukuvakaappaus"</item>
+    <item msgid="2598847264853993611">"Tarkastele puhelimen tilaa"</item>
+    <item msgid="9215610846802973353">"Lisää vastaajaviesti"</item>
+    <item msgid="9186411956086478261">"Käytä SIP:tä"</item>
+    <item msgid="6884763100104539558">"Käsittele lähtevä puhelu"</item>
+    <item msgid="125513972170580692">"Sormenjälki"</item>
+    <item msgid="2556071024281275619">"Kehon anturit"</item>
+    <item msgid="617168514928339387">"Tarkastele solulähetyksiä"</item>
+    <item msgid="7134693570516523585">"Käytä imitoitua sijaintia"</item>
+    <item msgid="7224489175375229399">"Tarkastele tallennustilaa"</item>
+    <item msgid="8472735063903258202">"Kirjoita tallennustilaan"</item>
+    <item msgid="4069276819909595110">"Kytke näyttö päälle"</item>
+    <item msgid="1228338896751121025">"Hae tilit"</item>
+    <item msgid="3181581793459233672">"Toimi taustalla"</item>
+    <item msgid="2340936043025374076">"Esteettömyys äänenvoimakkuus"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Lyhyt"</item>
     <item msgid="4816511817309094890">"Keskitaso"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Älä salli koskaan"</item>
     <item msgid="8184570120217958741">"Salli aina"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normaali"</item>
+    <item msgid="5101233285497327432">"Tyydyttävä"</item>
+    <item msgid="1555861583162930714">"Matala"</item>
+    <item msgid="1719683776264798117">"Kriittinen"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normaali"</item>
+    <item msgid="6107138933849816768">"Keskitaso"</item>
+    <item msgid="182695359839047859">"Matala"</item>
+    <item msgid="8577246509202964244">"Kriittinen"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Pysyvä"</item>
     <item msgid="167418068739176448">"Tärkein toiminta"</item>
@@ -396,12 +472,12 @@
     <item msgid="3118234477029486741">"0"</item>
   </string-array>
   <string-array name="wifi_metered_entries">
-    <item msgid="4329206416008519163">"Tunnista automaattisesti."</item>
+    <item msgid="4329206416008519163">"Tunnista automaattisesti"</item>
     <item msgid="773943026484148895">"Merkitse maksulliseksi"</item>
     <item msgid="1008268820118852416">"Merkitse maksuttomaksi"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
-    <item msgid="6545683814310036454">"Käytä satunnaistettua MAC-osoitetta (oletus)."</item>
+    <item msgid="6545683814310036454">"Käytä satunnaistettua MAC-osoitetta (oletus)"</item>
     <item msgid="214234417308375326">"Käytä laitteen MAC-osoitetta"</item>
   </string-array>
   <string-array name="wifi_hidden_entries">
diff --git a/tests/CarDeveloperOptions/res/values-fi/config.xml b/tests/CarDeveloperOptions/res/values-fi/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-fi/config.xml
+++ b/tests/CarDeveloperOptions/res/values-fi/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-fi/strings.xml b/tests/CarDeveloperOptions/res/values-fi/strings.xml
index 64e8db2..6f55fcb 100644
--- a/tests/CarDeveloperOptions/res/values-fi/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-fi/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Suurenna tai pienennä tekstiä näytöllä."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Pienennä"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Suurenna"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Esimerkkiteksti"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Ihmemaa Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Luku 11: Ozin ihastuttava smaragdikaupunki"</string>
@@ -247,7 +246,7 @@
     <string name="band_mode_set" msgid="4962130364076526789">"Aseta"</string>
     <string name="band_mode_failed" msgid="8350123391471974137">"Epäonnistui"</string>
     <string name="band_mode_succeeded" msgid="5516613616395402809">"Onnistui"</string>
-    <string name="sdcard_changes_instructions" msgid="4138217393448114001">"Muutokset tulevat voimaan, kun USB-kaapeli kytketään uudelleen."</string>
+    <string name="sdcard_changes_instructions" msgid="4138217393448114001">"Muutokset tulevat voimaan, kun USB-johto kytketään uudelleen."</string>
     <string name="sdcard_settings_screen_mass_storage_text" msgid="7486030250999007641">"Ota USB-massamuisti käyttöön"</string>
     <string name="sdcard_settings_total_bytes_label" msgid="6461741874400909157">"Tavuja yhteensä:"</string>
     <string name="sdcard_settings_not_present_status" product="nosdcard" msgid="5419085128792417589">"USB-tallennustila ei käytössä."</string>
@@ -310,8 +309,8 @@
     <string name="cellular_data_summary" msgid="8817717603450318646">"Salli tiedonsiirto mobiiliverkossa"</string>
     <string name="allow_data_usage_title" msgid="5381624105803294315">"Salli roaming-tiedonsiirto"</string>
     <string name="roaming" msgid="8860308342135146004">"Roaming"</string>
-    <string name="roaming_enable" msgid="2108142024297441116">"Yhdistä verkkoon roaming-tilassa."</string>
-    <string name="roaming_disable" msgid="1915440242079953809">"Yhdistä verkkoon roaming-tilassa."</string>
+    <string name="roaming_enable" msgid="2108142024297441116">"Yhdistä verkkoon roaming-tilassa"</string>
+    <string name="roaming_disable" msgid="1915440242079953809">"Yhdistä verkkoon roaming-tilassa"</string>
     <string name="roaming_reenable_message" msgid="8388505868655113258">"Verkkoyhteys katkesi, koska poistuit kotiverkkosi alueelta eikä roaming-tilaa ole otettu käyttöön."</string>
     <string name="roaming_turn_it_on_button" msgid="4370846458830537578">"Ota käyttöön"</string>
     <string name="roaming_warning" msgid="5488050911277592868">"Tästä voi aiheutua huomattavia kuluja."</string>
@@ -356,7 +355,7 @@
     <string name="security_enable_widgets_title" msgid="1701510007926738088">"Käytä widgetejä"</string>
     <string name="security_enable_widgets_disabled_summary" msgid="4408176087132339331">"Järjestelmänvalvojan estämä"</string>
     <string name="lockdown_settings_title" msgid="4534779922580115990">"Näytä lukitusasetus"</string>
-    <string name="lockdown_settings_summary" msgid="7270756909878256174">"Näytä virtapainikeasetus, joka poistaa käytöstä Smart Lockin, lukituksen avaamisen sormenjäljellä ja lukitusnäytön ilmoitukset."</string>
+    <string name="lockdown_settings_summary" msgid="7270756909878256174">"Näytä virtapainikeasetus, joka poistaa käytöstä Smart Lockin, lukituksen avaamisen sormenjäljellä ja lukitusnäytön ilmoitukset"</string>
     <string name="trust_agents_extend_unlock_title" msgid="3582017561316089951">"Luotettavat tahot vain pitävät avattuna"</string>
     <string name="trust_agents_extend_unlock_summary" msgid="3543997596586078084">"Kun tämä on käytössä, luotettavat tahot pitävät puhelimen avattuna pidempään mutta eivät voi enää avata lukittua laitetta."</string>
     <string name="trust_lost_locks_screen_title" msgid="3094736590690459372">"Lukitse näyttö ilman luotettavaa tahoa"</string>
@@ -411,7 +410,7 @@
     <string name="face_add_max" msgid="8870899421165189413">"Voit lisätä korkeintaan <xliff:g id="COUNT">%d</xliff:g> kasvoa"</string>
     <string name="face_intro_error_max" msgid="4024147799079828937">"Et voi lisätä useampia kasvoja"</string>
     <string name="face_intro_error_unknown" msgid="3241592604198351134">"Enimmäismäärä kasvoja lisätty"</string>
-    <string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"Rekisteröitymistä ei suoritettu loppuun."</string>
+    <string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"Käyttöönottoa ei suoritettu loppuun asti"</string>
     <string name="security_settings_face_enroll_dialog_ok" msgid="1078348922734845090">"OK"</string>
     <string name="security_settings_face_enroll_error_timeout_dialog_message" msgid="4917894418448325405">"Kasvojen rekisteröinnin aikaraja on saavutettu. Yritä uudelleen."</string>
     <string name="security_settings_face_enroll_error_generic_dialog_message" msgid="5160473187142616862">"Kasvojen rekisteröinti epäonnistui."</string>
@@ -448,7 +447,7 @@
     <string name="security_settings_fingerprint_enroll_introduction_cancel_setup" msgid="756928427429893070">"Ohita"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue_setup" msgid="4125977169169671144">"Seuraava"</string>
     <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"Ohitetaanko sormenjälki?"</string>
-    <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"Sormenjälkitunnistus kestää vain minuutin tai pari. Jos ohitat tämän, voit lisätä sormenjäljen myöhemmin asetuksissa."</string>
+    <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"Sormenjälkitunnistuksen käyttöönotossa menee vain minuutti tai pari. Jos ohitat sen nyt, voit lisätä sormenjälkesi myöhemmin asetuksista."</string>
     <string name="lock_screen_intro_skip_title" msgid="5307431665496346914">"Ohitetaanko näytön lukitus?"</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="tablet" msgid="7553945981266845264">"Laitteen suojausominaisuuksia ei oteta käyttöön. Et voi estää tabletin käyttöä, jos se varastetaan, katoaa tai sen tiedot pyyhitään."</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="device" msgid="1378243257238015603">"Laitteen suojausominaisuuksia ei oteta käyttöön. Et voi estää laitteen käyttöä, jos se varastetaan, katoaa tai sen tiedot pyyhitään."</string>
@@ -488,8 +487,8 @@
     <string name="security_settings_fingerprint_enroll_done" msgid="4111289529758845926">"Valmis"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"Hups, anturi ei ole siinä."</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"Kosketa puhelimen takaosan tunnistinta etusormella."</string>
-    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"Rekisteröitymistä ei suoritettu loppuun."</string>
-    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Sormenjäljen rekisteröinnin aikaraja on saavutettu. Yritä uudelleen."</string>
+    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"Käyttöönottoa ei suoritettu loppuun asti"</string>
+    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Sormenjäljen käyttöönoton enimmäisaika ylittyi. Yritä uudelleen."</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"Sormenjäljen rekisteröinti ei onnistunut. Yritä uudelleen tai käytä eri sormea."</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"Lisää toinen"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"Seuraava"</string>
@@ -549,7 +548,7 @@
     <string name="setup_lock_settings_picker_title" product="tablet" msgid="2429667472335773519">"Tabletin suojaaminen"</string>
     <string name="setup_lock_settings_picker_title" product="device" msgid="4739290104106645233">"Laitteen suojaaminen"</string>
     <string name="setup_lock_settings_picker_title" product="default" msgid="3911582328576859628">"Suojaa puhelintasi"</string>
-    <string name="lock_settings_picker_biometrics_added_security_message" msgid="799453282539387294">"Paranna suojausta määrittämällä näytön varalukitustapa"</string>
+    <string name="lock_settings_picker_biometrics_added_security_message" msgid="799453282539387294">"Paranna suojausta määrittämällä näytön varalukitustapa."</string>
     <string name="setup_lock_settings_picker_message" product="tablet" msgid="7230799135599877804">"Estä tablettisi luvaton käyttö ottamalla laitteen suojausominaisuudet käyttöön. Valitse näytön lukitusmenetelmä."</string>
     <string name="setup_lock_settings_picker_message" product="device" msgid="2098404520816295371">"Estä laitteesi luvaton käyttö ottamalla laitteen suojausominaisuudet käyttöön. Valitse näytön lukitusmenetelmä."</string>
     <string name="setup_lock_settings_picker_message" product="default" msgid="2003984443953672040">"Estä puhelimesi luvaton käyttö ottamalla laitteen suojausominaisuudet käyttöön. Valitse näytön lukitusmenetelmä."</string>
@@ -668,7 +667,6 @@
       <item quantity="other">PIN-koodissa saa olla enintään <xliff:g id="NUMBER_1">%d</xliff:g> numeroa.</item>
       <item quantity="one">PIN-koodissa saa olla enintään <xliff:g id="NUMBER_0">%d</xliff:g> numero.</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"PIN-koodi saa sisältää vain numeroita 0–9."</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Järjestelmänvalvoja esti PIN-koodin, koska sitä on käytetty hiljattain."</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"IT-järjestelmänvalvoja on estänyt yleiset PIN-koodit. Kokeile eri PIN-koodia."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Salasanassa ei saa olla virheellisiä merkkejä."</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Salasanassa on oltava vähintään <xliff:g id="COUNT">%d</xliff:g> merkkiä, jotka eivät ole kirjaimia.</item>
       <item quantity="one">Salasanassa on oltava vähintään 1 merkki, joka ei ole kirjain.</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Salasanassa on oltava vähintään <xliff:g id="COUNT">%d</xliff:g> merkki, joka ei ole numero</item>
+      <item quantity="one">Salasanassa on oltava vähintään 1 merkki, joka ei ole numero</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Järjestelmänvalvoja esti salasanan, koska sitä on käytetty hiljattain."</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"IT-järjestelmänvalvoja on estänyt yleiset salasanat. Kokeile eri salasanaa."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Nousevat, laskevat tai toistuvat numerosarjat on kielletty."</string>
@@ -716,7 +718,7 @@
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> aktiivinen sovellus</item>
     </plurals>
     <string name="manage_trust_agents" msgid="8129970926213142261">"Luotettavat tahot"</string>
-    <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"Käytä asettamalla ensin näytön lukitus."</string>
+    <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"Käyttääksesi tätä valitse ensin näytön lukitus"</string>
     <string name="manage_trust_agents_summary" msgid="2023116850759962248">"–"</string>
     <plurals name="manage_trust_agents_summary_on" formatted="false" msgid="5550538038916606097">
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> aktiivista luotettavaa tahoa</item>
@@ -846,8 +848,8 @@
     <string name="wifi_in_airplane_mode" msgid="4729571191578262246">"Lentokonetilassa"</string>
     <string name="wifi_notify_open_networks" msgid="4782239203624619655">"Avaa verkkoilmoitus"</string>
     <string name="wifi_notify_open_networks_summary" msgid="1383681260705466715">"Ilmoita, kun käytettävissä on laadukkaita julkisia verkkoja."</string>
-    <string name="wifi_wakeup" msgid="4963732992164721548">"Ota Wi-Fi käyttöön automaattisesti"</string>
-    <string name="wifi_wakeup_summary" msgid="1152699417411690">"Wi-Fi otetaan automaattisesti käyttöön, kun lähistöllä on kotiverkkosi tai muita laadukkaita tallennettuja verkkoja."</string>
+    <string name="wifi_wakeup" msgid="4963732992164721548">"Laita Wi-Fi päälle automaattisesti"</string>
+    <string name="wifi_wakeup_summary" msgid="1152699417411690">"Wi-Fi laitetaan automaattisesti päälle, kun lähistöllä on kotiverkkosi tai muita laadukkaita tallennettuja verkkoja"</string>
     <string name="wifi_wakeup_summary_no_location" msgid="3007457288587966962">"Ei käytettävissä, koska sijainti on poistettu käytöstä. Ota "<annotation id="link">"sijainti"</annotation>" käyttöön."</string>
     <string name="wifi_wakeup_summary_scanning_disabled" msgid="6820040651529910914">"Ei käytettävissä, koska Wi‑Fi-haku on pois päältä."</string>
     <string name="wifi_wakeup_summary_scoring_disabled" msgid="7067018832237903151">"Valitse verkon arviointipalvelu, jotta voit käyttää tätä."</string>
@@ -933,9 +935,9 @@
     <string name="wifi_privacy_settings" msgid="4462092795794247809">"Tietosuoja"</string>
     <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"Satunnaistettu MAC-osoite"</string>
     <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"Lisää laite"</string>
-    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"Lisää laite verkkoon <xliff:g id="SSID">%1$s</xliff:g> keskittämällä alla olevaan QR-koodiin."</string>
+    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"Keskitä QR-koodi alle yhdistääksesi laitteen <xliff:g id="SSID">%1$s</xliff:g>:iin"</string>
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"Lue QR-koodi"</string>
-    <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"Yhdistä verkkoon <xliff:g id="SSID">%1$s</xliff:g> keskittämällä alla olevaan QR-koodiin"</string>
+    <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"Keskitä QR-koodi alle yhdistääksesi <xliff:g id="SSID">%1$s</xliff:g>:iin"</string>
     <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"Yhdistä Wi-Fi-verkkoon lukemalla QR-koodi."</string>
     <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Jaa Wi‑Fi"</string>
     <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"Yhdistä <xliff:g id="SSID">%1$s</xliff:g> ja jaa salasana lukemalla tämä QR-koodi."</string>
@@ -949,7 +951,7 @@
     <string name="wifi_dpp_check_connection_try_again" msgid="7144663015219170999">"Tarkista yhteys ja yritä uudelleen"</string>
     <string name="wifi_dpp_choose_network" msgid="6251424431594491691">"Valitse verkko"</string>
     <string name="wifi_dpp_choose_network_to_connect_device" msgid="6385259857886784285">"Yhdistä laitteesi valitsemalla verkko"</string>
-    <string name="wifi_dpp_add_device_to_wifi" msgid="6454198064645462446">"Lisätäänkö laite verkkoon <xliff:g id="SSID">%1$s</xliff:g>?"</string>
+    <string name="wifi_dpp_add_device_to_wifi" msgid="6454198064645462446">"Lisätäänkö laite \"<xliff:g id="SSID">%1$s</xliff:g>\"-verkkoon?"</string>
     <string name="wifi_dpp_wifi_shared_with_device" msgid="5713765471758272471">"Wi‑Fi jaettu laitteen kanssa"</string>
     <string name="wifi_dpp_add_another_device" msgid="3698441567235301565">"Lisää toinen laite"</string>
     <string name="wifi_dpp_choose_different_network" msgid="128515107488187050">"Valitse eri verkko"</string>
@@ -1067,7 +1069,7 @@
     <string name="wifi_hotspot_ap_band_title" msgid="3485744480410441949">"AP-taajuus"</string>
     <string name="wifi_hotspot_footer_info_regular" msgid="3876006922622827363">"Hotspot-ominaisuudella voit luoda muille laitteillesi Wi-Fi-verkon. Ominaisuus jakaa internetyhteyden muille laitteille mobiilidatayhteydellä. Lisämaksuja mobiilidatan käytöstä voidaan periä."</string>
     <string name="wifi_hotspot_footer_info_local_only" msgid="3339582350894639261">"Sovellukset voivat luoda hotspotin ja jakaa sisältöä lähellä olevien laitteiden kanssa."</string>
-    <string name="wifi_hotspot_auto_off_title" msgid="7416022590415189590">"Poista hotspot käytöstä automaattisesti"</string>
+    <string name="wifi_hotspot_auto_off_title" msgid="7416022590415189590">"Laita hotspot pois päältä automaattisesti"</string>
     <string name="wifi_hotspot_auto_off_summary" msgid="3866769400624802105">"Wi‑Fi-hotspot poistetaan käytöstä, jos laitteita ei ole yhdistetty."</string>
     <string name="wifi_tether_starting" msgid="7676952148471297900">"Otetaan yhteyspiste käyttöön..."</string>
     <string name="wifi_tether_stopping" msgid="7478561853791953349">"Poistetaan yhteyspiste käytöstä..."</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mobiili"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Jos Wi-Fi-yhteys ei ole käytettävissä, käytä mobiiliverkkoa"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Jos mobiiliverkkoa ei ole saatavilla, käytä Wi-Fi-yhteyttä."</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Soita Wi-Fi-yhteyden kautta. Jos Wi-Fi-yhteys katkeaa, puhelu päättyy."</string>
@@ -1223,8 +1228,8 @@
     <string name="night_display_summary_on_auto_mode_never" msgid="5461580863060506687">"Ei sammu automaattisesti"</string>
     <string name="night_display_summary_on_auto_mode_custom" msgid="2200631112239399233">"Sammuu automaattisesti kello <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="night_display_summary_on_auto_mode_twilight" msgid="8386769601369289561">"Sammuu automaattisesti, kun aurinko nousee"</string>
-    <string name="night_display_activation_on_manual" msgid="8379477527072027346">"Ota käyttöön nyt"</string>
-    <string name="night_display_activation_off_manual" msgid="7776082151269794201">"Poista käytöstä nyt"</string>
+    <string name="night_display_activation_on_manual" msgid="8379477527072027346">"Laita päälle"</string>
+    <string name="night_display_activation_off_manual" msgid="7776082151269794201">"Laita pois päältä"</string>
     <string name="night_display_activation_on_twilight" msgid="5610294051700287249">"Käytössä auringonnousuun asti"</string>
     <string name="night_display_activation_off_twilight" msgid="6846727701281556110">"Pois käytöstä auringonlaskuun asti"</string>
     <string name="night_display_activation_on_custom" msgid="4761140206778957611">"Käytössä <xliff:g id="ID_1">%1$s</xliff:g> asti"</string>
@@ -1340,7 +1345,7 @@
     <string name="scanning_status_text_wifi_on_ble_on" msgid="6370507836346838473">"Wi-Fi- ja Bluetooth-haku ovat käytössä."</string>
     <string name="scanning_status_text_wifi_on_ble_off" msgid="8205014713732412608">"Wi‑Fi-haku on käytössä, Bluetooth-haku ei ole käytössä"</string>
     <string name="scanning_status_text_wifi_off_ble_on" msgid="7400522456303307057">"Bluetooth-haku on käytössä, Wi-Fi-haku ei ole käytössä"</string>
-    <string name="scanning_status_text_wifi_off_ble_off" msgid="8575026386237481457">"Wi-Fi- ja Bluetooth-haku eivät ole käytössä."</string>
+    <string name="scanning_status_text_wifi_off_ble_off" msgid="8575026386237481457">"Wi-Fi- ja Bluetooth-haku eivät ole käytössä"</string>
     <string name="status_meid_number" msgid="8756271256760479835">"MEID"</string>
     <string name="status_icc_id" msgid="9191847562997702709">"ICCID"</string>
     <string name="status_data_network_type" msgid="2344720457353394909">"Mobiilidataverkon tyyppi"</string>
@@ -1544,7 +1549,7 @@
     <string name="apn_type" msgid="6725346490902871146">"APN-tyyppi"</string>
     <string name="apn_protocol" msgid="1240197323563960912">"APN-protokolla"</string>
     <string name="apn_roaming_protocol" msgid="6913336248771263497">"APN roaming -protokolla"</string>
-    <string name="carrier_enabled" msgid="1819916725305365581">"Ota APN käyttöön / poista se käytöstä."</string>
+    <string name="carrier_enabled" msgid="1819916725305365581">"Ota APN käyttöön / pois käytöstä"</string>
     <string name="carrier_enabled_summaryOn" msgid="6219221535461945771">"APN otettu käyttöön"</string>
     <string name="carrier_enabled_summaryOff" msgid="4093019532796386622">"APN poistettu käytöstä"</string>
     <string name="bearer" msgid="4378444317087536401">"Bearer"</string>
@@ -1564,7 +1569,7 @@
     <string name="menu_restore" msgid="3799288817317293115">"Palauta oletukset"</string>
     <string name="restore_default_apn_completed" msgid="5671734152740058937">"APN-oletusasetukset on palautettu."</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"Palautusvalinnat"</string>
-    <string name="reset_dashboard_summary" msgid="8778383341461126642">"Voit nollata verkon, sovellusten tai laitteen asetukset."</string>
+    <string name="reset_dashboard_summary" msgid="8778383341461126642">"Voit nollata verkon, sovellusten tai laitteen asetukset"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"Nollaa Wi-Fin, mobiiliverkon ja Bluetoothin asetukset"</string>
     <string name="reset_network_desc" msgid="4982633363916261109">"Tämä nollaa kaikki verkkoasetukset, esimerkiksi seuraavat:\n\n"<li>"Wi‑Fi"</li>\n<li>"Mobiilidata"</li>\n<li>"Bluetooth"</li></string>
     <string name="reset_esim_title" msgid="7630781767040831893">"Tyhjennä ladatut SIM-kortit"</string>
@@ -1616,11 +1621,11 @@
     <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"Kun Data Saver on käytössä, puhelinta ei voi käyttää modeemina eikä kannettavien hotspotien käyttäminen onnistu."</string>
     <string name="usb_title" msgid="7480927657535578688">"USB"</string>
     <string name="usb_tethering_button_text" msgid="6242228383142012332">"Internetin jakaminen USB:n kautta"</string>
-    <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"Jaa puhelimen internetyhteys USB:llä."</string>
+    <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"Jaa puhelimen internetyhteys USB:llä"</string>
     <string name="usb_tethering_subtext" product="tablet" msgid="154536000235361034">"Jaa tabletin internetyhteys USB:llä"</string>
     <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"Jaettu Bluetooth-yhteys"</string>
     <string name="bluetooth_tethering_subtext" product="tablet" msgid="6868756914621131635">"Jaa tabletin internetyhteys Bluetoothilla"</string>
-    <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"Jaa puhelimen internetyhteys Bluetoothilla."</string>
+    <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"Jaa puhelimen internetyhteys Bluetoothilla"</string>
     <string name="bluetooth_tethering_off_subtext_config" msgid="3981528184780083266">"<xliff:g id="DEVICE_NAME">%1$d</xliff:g> jakaa internetyhteyden Bluetoothilla"</string>
     <string name="bluetooth_tethering_overflow_error" msgid="6946561351369376943">"Voidaan yhdistää korkeintaan <xliff:g id="MAXCONNECTION">%1$d</xliff:g> laitteeseen."</string>
     <string name="bluetooth_untether_blank" msgid="5428300773782256084">"Jaettu internetyhteys katkaistaan laitteesta <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
@@ -1798,7 +1803,7 @@
     <string name="auto_launch_label" msgid="47089737922907379">"Avaa oletuksena"</string>
     <string name="auto_launch_label_generic" msgid="7865828543459493308">"Oletukset"</string>
     <string name="screen_compatibility_label" msgid="3638271673726075815">"Ruudun yhteensopivuus"</string>
-    <string name="permissions_label" msgid="7341733648403464213">"Käyttöoikeudet"</string>
+    <string name="permissions_label" msgid="7341733648403464213">"Luvat"</string>
     <string name="cache_header_label" msgid="3202284481380361966">"Välimuisti"</string>
     <string name="clear_cache_btn_text" msgid="107507684844780651">"Tyhjennä välimuisti"</string>
     <string name="cache_size_label" msgid="6205173678102220499">"Välimuisti"</string>
@@ -1824,7 +1829,7 @@
     <string name="app_factory_reset" msgid="8718986000278776272">"Poista päivitykset"</string>
     <string name="auto_launch_enable_text" msgid="3372898942144027341">"Olet valinnut tämän sovelluksen käynnistettäväksi oletuksena tiettyjen toimintojen yhteydessä."</string>
     <string name="always_allow_bind_appwidgets_text" msgid="2286211654774611037">"Olet antanut sovellukselle oikeuden luoda widgetejä ja käyttää niiden tietoja."</string>
-    <string name="auto_launch_disable_text" msgid="8560921288036801416">"Oletuksia ei asetettu."</string>
+    <string name="auto_launch_disable_text" msgid="8560921288036801416">"Ei oletuksia valittuina."</string>
     <string name="clear_activities" msgid="2068014972549235347">"Tyhjennä oletukset"</string>
     <string name="screen_compatibility_text" msgid="1768064020294301496">"Tätä sovellusta ei välttämättä ole suunniteltu näytöllesi sopivaksi. Voit muuttaa asetuksia täältä."</string>
     <string name="ask_compatibility" msgid="6687958195768084807">"Kysy käynnistettäessä"</string>
@@ -1965,9 +1970,9 @@
     <string name="keyboard_assistance_category" msgid="2276351807419818125">"Näppäimistön apuvälineet"</string>
     <string name="physical_keyboard_title" msgid="3508591962962814313">"Fyysinen näppäimistö"</string>
     <string name="show_ime" msgid="7322620473198763563">"Näytä virtuaalinen näppäimistö"</string>
-    <string name="show_ime_summary" msgid="3246628154011464373">"Pidä näytöllä, kun fyysinen näppäimistö on aktiivinen."</string>
+    <string name="show_ime_summary" msgid="3246628154011464373">"Pidä näytöllä, kun fyysinen näppäimistö on aktiivinen"</string>
     <string name="keyboard_shortcuts_helper" msgid="6574386807271399788">"Pikanäppäinapuri"</string>
-    <string name="keyboard_shortcuts_helper_summary" msgid="8024313306403779742">"Näytä käytettävissä olevat pikanäppäimet."</string>
+    <string name="keyboard_shortcuts_helper_summary" msgid="8024313306403779742">"Näytä käytettävissä olevat pikanäppäimet"</string>
     <string name="language_and_input_for_work_category_title" msgid="2053255944038892588">"Työprofiilin näppäimistöt ja työkalut"</string>
     <string name="virtual_keyboards_for_work_title" msgid="3968291646938204523">"Virtuaalinen näppäimistö työkäyttöön"</string>
     <string name="default_keyboard_layout" msgid="9171704064451242230">"Oletus"</string>
@@ -2067,7 +2072,7 @@
     <string name="accessibility_toggle_large_pointer_icon_title" msgid="9127905775116570565">"Suuri hiiren osoitin"</string>
     <string name="accessibility_disable_animations" msgid="8378441317115710009">"Poista animaatiot"</string>
     <string name="accessibility_toggle_master_mono_title" msgid="899550848196702565">"Monoääni"</string>
-    <string name="accessibility_toggle_master_mono_summary" msgid="3847052868469033235">"Yhdistä kanavat ääntä toistettaessa."</string>
+    <string name="accessibility_toggle_master_mono_summary" msgid="3847052868469033235">"Yhdistä kanavat ääntä toistettaessa"</string>
     <string name="accessibility_toggle_master_balance_title" msgid="8723492001092647562">"Äänitasapaino"</string>
     <string name="accessibility_toggle_master_balance_left_label" msgid="8531986342666527970">"Vasen"</string>
     <string name="accessibility_toggle_master_balance_right_label" msgid="7757024572140589558">"Oikea"</string>
@@ -2274,13 +2279,13 @@
     <string name="battery_tip_smart_battery_summary" msgid="5344821856478265778">"Ota Virranhallinta käyttöön"</string>
     <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Ota Virransäästö käyttöön"</string>
     <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Akku voi loppua odotettua aiemmin"</string>
-    <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Virransäästö on käytössä"</string>
+    <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Virransäästö on päällä"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Joitakin toimintoja voidaan rajoittaa"</string>
-    <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Puhelinta on käytetty tavallista enemmän"</string>
+    <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Puhelinta käytetty tavallista enemmän"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"Tablettia on käytetty tavallista enemmän"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"Laitetta on käytetty tavallista enemmän"</string>
     <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"Akku voi loppua odotettua aiemmin"</string>
-    <string name="battery_tip_dialog_message" product="default" msgid="8453700079047810964">"Puhelinta on käytetty tavallista enemmän. Akku voi loppua odotettua aiemmin.\n\nKäytetyimmät sovellukset edellisen latauksen jälkeen:"</string>
+    <string name="battery_tip_dialog_message" product="default" msgid="8453700079047810964">"Puhelinta käytetty tavallista enemmän. Akku voi loppua odotettua aiemmin.\n\nKäytetyimmät sovellukset edellisen latauksen jälkeen:"</string>
     <string name="battery_tip_dialog_message" product="tablet" msgid="6489981050645444068">"Tablettia on käytetty tavallista enemmän. Akku voi loppua odotettua aiemmin.\n\nKäytetyimmät sovellukset edellisen latauksen jälkeen:"</string>
     <string name="battery_tip_dialog_message" product="device" msgid="6348123094674390337">"Laitetta on käytetty tavallista enemmän. Akku voi loppua odotettua aiemmin.\n\nKäytetyimmät sovellukset edellisen latauksen jälkeen:"</string>
     <string name="battery_tip_dialog_message_footer" msgid="1118827395267487197">"Sisältää virtaa paljon kuluttavat taustatoiminnot"</string>
@@ -2294,7 +2299,7 @@
     </plurals>
     <plurals name="battery_tip_restrict_summary" formatted="false" msgid="984148373944071669">
       <item quantity="other">%2$d sovellusta käyttää paljon akkua taustalla</item>
-      <item quantity="one">%1$s sovellus käyttää paljon akkua taustalla</item>
+      <item quantity="one">%1$s käyttää paljon akkua taustalla</item>
     </plurals>
     <plurals name="battery_tip_restrict_handled_summary" formatted="false" msgid="469696766640020557">
       <item quantity="other">Nämä sovellukset eivät voi toimia taustalla</item>
@@ -2446,13 +2451,13 @@
     <string name="battery_saver_auto_no_schedule" msgid="739814529432092706">"Ei aikataulua"</string>
     <string name="battery_saver_auto_routine" msgid="886514412067906980">"Perustuu ohjelmaasi"</string>
     <string name="battery_saver_auto_percentage" msgid="5791982309331921556">"Perustuu varausprosenttiin"</string>
-    <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"Virransäästö käynnistyy, jos akku näyttää todennäköisesti loppuvan ennen seuraavaa tavallista lataamista."</string>
-    <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"Käynnistyy, kun taso on <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
+    <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"Virransäästö käynnistyy, jos akku näyttää todennäköisesti loppuvan ennen seuraavaa tavallista lataamista"</string>
+    <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"Menee päälle kun jäljellä on <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"Luo aikataulu"</string>
     <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"Poista käytöstä, kun ladattu täyteen"</string>
-    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"Virransäästö poistetaan käytöstä, kun puhelimen varaus on <xliff:g id="PERCENT">%1$s</xliff:g>."</string>
-    <string name="battery_saver_sticky_description_new" product="tablet" msgid="3284967694001857194">"Virransäästö poistetaan käytöstä, kun tabletin varaus on <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
-    <string name="battery_saver_sticky_description_new" product="device" msgid="5056520668081504111">"Virransäästö poistetaan käytöstä, kun laitteen varaus on <xliff:g id="PERCENT">%1$s</xliff:g>."</string>
+    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"Virransäästö menee pois päältä, kun puhelimen varaus on <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
+    <string name="battery_saver_sticky_description_new" product="tablet" msgid="3284967694001857194">"Virransäästö menee pois päältä, kun tabletin varaus on <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
+    <string name="battery_saver_sticky_description_new" product="device" msgid="5056520668081504111">"Virransäästö menee pois päältä, kun laitteen varaus on <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <!-- no translation found for battery_saver_seekbar_title (7607123201469333645) -->
     <skip />
     <string name="battery_saver_seekbar_title_placeholder" msgid="2321082163892561703">"Ota käyttöön"</string>
@@ -2461,7 +2466,7 @@
     <string name="battery_saver_turn_on_automatically_never" msgid="2623381258359775227">"Ei koskaan"</string>
     <string name="battery_saver_turn_on_automatically_pct" msgid="434270432432390307">"kun akun varaus on <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <string name="battery_percentage" msgid="7782252476471033843">"Akun varaus prosentteina"</string>
-    <string name="battery_percentage_description" msgid="9219875229166700610">"Näytä akun varaus prosentteina tilapalkissa."</string>
+    <string name="battery_percentage_description" msgid="9219875229166700610">"Näytä akun varaus prosentteina tilapalkissa"</string>
     <string name="process_stats_summary_title" msgid="9189588417488537954">"Käsittelytiedot"</string>
     <string name="process_stats_summary" msgid="8077998499161221885">"Käsittelyn tarkat tiedot"</string>
     <string name="app_memory_use" msgid="5126237308545653706">"Muistin käyttö"</string>
@@ -2543,7 +2548,7 @@
     <string name="emergency_tone_summary" msgid="8035940153401622240">"Aseta toiminta hätäpuhelun tapauksessa"</string>
     <string name="privacy_settings_title" msgid="3573891462732375772">"Varmuuskopiointi"</string>
     <string name="backup_summary_state_on" msgid="1725597360282574647">"Käytössä"</string>
-    <string name="backup_summary_state_off" msgid="7138020503288730492">"Ei käytössä"</string>
+    <string name="backup_summary_state_off" msgid="7138020503288730492">"Ei päällä"</string>
     <string name="backup_section_title" msgid="8177209731777904656">"Varmuuskopiointi &amp; palautus"</string>
     <string name="personal_data_section_title" msgid="9161854418510071558">"Henkilötiedot"</string>
     <string name="backup_data_title" msgid="4461508563849583624">"Tietojen varmuuskopiointi"</string>
@@ -2665,7 +2670,7 @@
     <string name="data_usage_menu_sim_cards" msgid="8508154611676507088">"SIM-kortit"</string>
     <string name="data_usage_cellular_data_summary" msgid="9162777397135709280">"Keskeytetään rajalla."</string>
     <string name="account_settings_menu_auto_sync" msgid="2673669556006027506">"Tietojen autom. synkronointi"</string>
-    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"Omien tietojen autom. synkron."</string>
+    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"Oman datan autosynkronointi"</string>
     <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Työtietojen autom. synkron."</string>
     <string name="data_usage_change_cycle" msgid="447761920472170031">"Muuta jaksoa…"</string>
     <string name="data_usage_pick_cycle_day" msgid="6319750879145917066">"Tiedonsiirtojakson nollauspäivä (kk):"</string>
@@ -2673,7 +2678,7 @@
     <string name="data_usage_label_foreground" msgid="2471091128648754601">"Etualalla"</string>
     <string name="data_usage_label_background" msgid="1618794447370396845">"Taustalla"</string>
     <string name="data_usage_app_restricted" msgid="7569077654579299326">"rajoitettu"</string>
-    <string name="data_usage_disable_mobile" msgid="4125335076749119451">"Poistetaanko mobiilidata käytöstä?"</string>
+    <string name="data_usage_disable_mobile" msgid="4125335076749119451">"Laitetaanko mobiilidata pois päältä?"</string>
     <string name="data_usage_disable_mobile_limit" msgid="1937796699758613667">"Aseta mobiilitiedonsiirtoraja"</string>
     <string name="data_usage_disable_4g_limit" msgid="7131367986548147266">"Aseta 4G-datankäyttöraja"</string>
     <string name="data_usage_disable_3g_limit" msgid="6746819313032692220">"Aseta 2G-3G-datankäyttöraja"</string>
@@ -2867,8 +2872,8 @@
     <string name="user_add_user_title" msgid="2320897397066676472">"Lisätäänkö uusi käyttäjä?"</string>
     <string name="user_add_user_message_long" msgid="686637203224195465">"Voit jakaa tämän laitteen muiden kanssa luomalla lisää käyttäjiä. Kullakin käyttäjällä on oma tilansa, jota he voivat muokata esimerkiksi omilla sovelluksilla ja taustakuvilla. Käyttäjät voivat myös muokata laiteasetuksia, kuten Wi‑Fi-asetuksia, jotka vaikuttavat laitteen kaikkiin käyttäjiin.\n\nKun lisäät uuden käyttäjän, hänen tulee määrittää oman tilansa asetukset.\n\nKaikki käyttäjät voivat päivittää muiden käyttäjien sovelluksia. Esteettömyysominaisuuksia tai ‑palveluita ei välttämättä siirretä uudelle käyttäjälle."</string>
     <string name="user_add_user_message_short" msgid="1802594476285458254">"Kun lisäät uuden käyttäjän, hänen tulee määrittää oman tilansa asetukset.\n\nKaikki käyttäjät voivat päivittää sovelluksia muille käyttäjille."</string>
-    <string name="user_setup_dialog_title" msgid="6748950002206392396">"Määritetäänkö käyttäjän asetukset nyt?"</string>
-    <string name="user_setup_dialog_message" msgid="2988559933258353919">"Varmista, että käyttäjä voi vastaanottaa laitteen ja määrittää oman tilansa."</string>
+    <string name="user_setup_dialog_title" msgid="6748950002206392396">"Lisätäänkö käyttäjä nyt?"</string>
+    <string name="user_setup_dialog_message" msgid="2988559933258353919">"Varmista, että käyttäjä voi ottaa laitteen nyt ja määrittää oman tilansa."</string>
     <string name="user_setup_profile_dialog_message" msgid="7611900802824048526">"Määritetäänkö profiilin asetukset nyt?"</string>
     <string name="user_setup_button_setup_now" msgid="4941459406266856176">"Määritä nyt"</string>
     <string name="user_setup_button_setup_later" msgid="6596031428556518752">"Ei nyt"</string>
@@ -2904,13 +2909,13 @@
     <string name="user_enable_calling_confirm_message" msgid="2490126715153125970">"Soittohistoria jaetaan tämän käyttäjän kanssa."</string>
     <string name="user_enable_calling_and_sms_confirm_title" msgid="4153856398523366976">"Otetaanko puhelut ja tekstiviestit käyttöön?"</string>
     <string name="user_enable_calling_and_sms_confirm_message" msgid="3278802798876095734">"Soitto- ja tekstiviestihistoria jaetaan tämän käyttäjän kanssa."</string>
-    <string name="emergency_info_title" msgid="1522609271881425375">"Hätätilannetiedot"</string>
+    <string name="emergency_info_title" msgid="1522609271881425375">"Vaaratiedot"</string>
     <string name="emergency_info_summary" msgid="7280464759837387342">"Käyttäjän <xliff:g id="USER_NAME">%1$s</xliff:g> tiedot ja yhteystiedot"</string>
     <string name="application_restrictions" msgid="6871981013736536763">"Sovellusten ja sisällön salliminen"</string>
     <string name="apps_with_restrictions_header" msgid="8656739605673756176">"Rajoitetut sovellukset"</string>
     <string name="apps_with_restrictions_settings_button" msgid="5065896213467171744">"Laajenna sovelluksen asetuksia"</string>
     <string name="nfc_payment_settings_title" msgid="5070077706735415291">"Napauttamalla maksaminen"</string>
-    <string name="nfc_payment_how_it_works" msgid="7607901964687787177">"Toimintatapa"</string>
+    <string name="nfc_payment_how_it_works" msgid="7607901964687787177">"Miten se toimii"</string>
     <string name="nfc_payment_no_apps" msgid="8844440783395420860">"Maksa puhelimella myymälöissä"</string>
     <string name="nfc_payment_default" msgid="7869273092463612271">"Oletusmaksusovellus"</string>
     <string name="nfc_payment_default_not_set" msgid="955804193510335338">"Ei asetettu"</string>
@@ -2920,7 +2925,7 @@
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Paitsi jos jokin toinen maksusovellus on auki"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"Maksa napauttamalla maksamisen päätteellä tällä sovelluksella:"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Maksaminen päätteellä"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Määritä maksusovellus. Sen jälkeen sinun tarvitsee vain pitää puhelimen takaosaa etämaksut hyväksyvää maksupäätettä vasten."</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Asenna maksusovellus. Maksa ostoksesi pitämällä puhelimen takaosaa lähimaksupäätettä vasten."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"Selvä"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"Lisää…"</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"Valitaanko asetukseksi?"</string>
@@ -3192,7 +3197,7 @@
     <string name="zen_mode_settings_category" msgid="5601680733422424922">"Kun älä häiritse -tila on käytössä"</string>
     <string name="zen_mode_restrict_notifications_title" msgid="7486753018073540477">"Rajoita ilmoituksia"</string>
     <string name="zen_mode_restrict_notifications_mute" msgid="2673665450311184875">"Ei ilmoitusääniä"</string>
-    <string name="zen_mode_restrict_notifications_mute_summary" msgid="1696217042353376674">"Näet ilmoituksia näytöllä."</string>
+    <string name="zen_mode_restrict_notifications_mute_summary" msgid="1696217042353376674">"Näet ilmoitukset näytölläsi"</string>
     <string name="zen_mode_restrict_notifications_mute_footer" msgid="3049522809520549054">"Puhelin ei anna äänimerkkiä eikä värise ilmoituksen saapuessa."</string>
     <string name="zen_mode_restrict_notifications_hide" msgid="3296933643539682552">"Ei ilmoitusgrafiikoita tai ‑ääntä"</string>
     <string name="zen_mode_restrict_notifications_hide_summary" msgid="1449301153755270168">"Et näe tai kuule ilmoituksia."</string>
@@ -3207,7 +3212,7 @@
     <string name="zen_mode_block_effects_screen_on" msgid="1042489123800404560">"Kun näyttö on päällä"</string>
     <string name="zen_mode_block_effects_screen_off" msgid="6380935819882837552">"Kun näyttö on pois päältä"</string>
     <string name="zen_mode_block_effect_sound" msgid="1499243540186357631">"Mykistä ääni ja sammuta värinä"</string>
-    <string name="zen_mode_block_effect_intent" msgid="5666951244667422668">"Älä kytke näyttöä päälle"</string>
+    <string name="zen_mode_block_effect_intent" msgid="5666951244667422668">"Älä laita näyttöä päälle"</string>
     <string name="zen_mode_block_effect_light" msgid="8679333758037487644">"Älä vilkuta merkkivaloa"</string>
     <string name="zen_mode_block_effect_peek" msgid="6075662813575910221">"Älä tuo ilmoituksia näytölle"</string>
     <string name="zen_mode_block_effect_status" msgid="6516614225115681068">"Piilota näytön yläreunan tilapalkkikuvakkeet"</string>
@@ -3225,8 +3230,8 @@
     <string name="zen_mode_other_options" msgid="7216192179063769057">"muut vaihtoehdot"</string>
     <string name="zen_mode_add" msgid="2533484377786927366">"Lisää"</string>
     <string name="zen_mode_enable_dialog_turn_on" msgid="6396050543542026184">"Ota käyttöön"</string>
-    <string name="zen_mode_button_turn_on" msgid="1097964136225943415">"Ota käyttöön nyt"</string>
-    <string name="zen_mode_button_turn_off" msgid="3990967728457149454">"Poista käytöstä nyt"</string>
+    <string name="zen_mode_button_turn_on" msgid="1097964136225943415">"Laita päälle"</string>
+    <string name="zen_mode_button_turn_off" msgid="3990967728457149454">"Laita pois päältä"</string>
     <string name="zen_mode_settings_dnd_manual_end_time" msgid="4307574188962071429">"Älä häiritse ‑tila on käytössä <xliff:g id="FORMATTED_TIME">%s</xliff:g> asti."</string>
     <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"Älä häiritse ‑tila on käytössä, kunnes poistat sen käytöstä."</string>
     <string name="zen_mode_settings_dnd_automatic_rule" msgid="2843297614114625408">"Aikataulu (<xliff:g id="RULE_NAME">%s</xliff:g>) otti Älä häiritse ‑tilan automaattisesti käyttöön."</string>
@@ -3240,7 +3245,7 @@
     <string name="zen_mode_sound_summary_off" msgid="2800265178411749309">"Pois käytöstä"</string>
     <string name="zen_mode_sound_summary_on" msgid="6964666541479146310">"Käytössä"</string>
     <string name="zen_mode_duration_summary_always_prompt" msgid="7642321938427056823">"Kysy aina (paitsi jos se käynnistyy automaattisesti)"</string>
-    <string name="zen_mode_duration_summary_forever" msgid="4563938129424903030">"Kunnes poistat sen käytöstä (paitsi jos se käynnistyy automaattisesti)"</string>
+    <string name="zen_mode_duration_summary_forever" msgid="4563938129424903030">"Kunnes laitat pois päältä (paitsi jos se käynnistyy automaattisesti)"</string>
     <plurals name="zen_mode_duration_summary_time_hours" formatted="false" msgid="8872000022033647725">
       <item quantity="other"><xliff:g id="NUM_HOURS">%d</xliff:g> tuntia (paitsi jos se käynnistyy automaattisesti)</item>
       <item quantity="one">1 tunti (paitsi jos se käynnistyy automaattisesti)</item>
@@ -3291,7 +3296,7 @@
     <string name="other_sound_category_preference_title" msgid="2045757472469840859">"Muut äänet ja värinä"</string>
     <string name="configure_notification_settings" msgid="291914315140851270">"Ilmoitukset"</string>
     <string name="recent_notifications" msgid="8125865995065032049">"Äskettäin lähetetyt"</string>
-    <string name="recent_notifications_see_all_title" msgid="4089007770442871469">"Näytä kaikki viimeisen 7 päivän ajalta"</string>
+    <string name="recent_notifications_see_all_title" msgid="4089007770442871469">"Näytä kaikki 7 viime päivän ajalta"</string>
     <string name="advanced_section_header" msgid="984680389373090015">"Lisäasetukset"</string>
     <string name="profile_section_header" msgid="5471479005472037417">"Työilmoitukset"</string>
     <string name="asst_capability_prioritizer_title" msgid="3488284760645922160">"Automaattinen ilmoitusten priorisointi"</string>
@@ -3316,9 +3321,9 @@
     <string name="notification_pulse_title" msgid="4861418327614907116">"Vilkuta valoa"</string>
     <string name="lock_screen_notifications_title" msgid="6889072265118747835">"Lukitusnäytöllä"</string>
     <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"Kun työprofiili on lukittu"</string>
-    <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Näytä ilmoitusten koko sisältö."</string>
+    <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Näytä ilmoitusten koko sisältö"</string>
     <string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"Piilota arkaluontoinen sisältö"</string>
-    <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"Älä näytä ilmoituksia lainkaan."</string>
+    <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"Älä näytä ilmoituksia lainkaan"</string>
     <string name="lock_screen_notifications_interstitial_message" msgid="4230189215124387818">"Miten haluat ilmoitusten näkyvän, kun laite on lukittu?"</string>
     <string name="lock_screen_notifications_interstitial_title" msgid="2832587379332443505">"Ilmoitukset"</string>
     <string name="lock_screen_notifications_summary_show_profile" msgid="8908775469657073273">"Näytä kaikki työilmoitussisältö"</string>
@@ -3385,7 +3390,7 @@
     <string name="picture_in_picture_app_detail_title" msgid="3916189052657425936">"Kuva kuvassa"</string>
     <string name="picture_in_picture_app_detail_switch" msgid="747422998967185418">"Salli kuva kuvassa"</string>
     <string name="picture_in_picture_app_detail_summary" msgid="918632751775525347">"Anna sovellukselle lupa luoda kuva kuvassa ‑ikkuna, kun se on auki tai siirryt siitä muualle (esimerkiksi palaat videoon). Tämä ikkuna näytetään muiden sovellusten ikkunoiden päällä."</string>
-    <string name="manage_zen_access_title" msgid="3058206309728524196">"Älä häiritse -käyttöoikeudet"</string>
+    <string name="manage_zen_access_title" msgid="3058206309728524196">"Älä häiritse -pääsy"</string>
     <string name="zen_access_detail_switch" msgid="8706332327904974500">"Salli Älä häiritse ‑tila"</string>
     <string name="zen_access_empty_text" msgid="7667538993781607731">"Yksikään asennettu sovellus ei ole pyytänyt Älä häiritse -tilan käyttöoikeutta."</string>
     <string name="loading_notification_apps" msgid="1978345231934072091">"Ladataan sovelluksia…"</string>
@@ -3438,7 +3443,7 @@
     <string name="zen_mode_add_time_rule" msgid="5999467757140524729">"Lisää aikapohjainen aikataulu"</string>
     <string name="zen_mode_delete_rule" msgid="2292933835997203801">"Poista aikataulu"</string>
     <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"Valitse aikataulutyyppi"</string>
-    <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"Poistetaanko sääntö <xliff:g id="RULE">%1$s</xliff:g>?"</string>
+    <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"Poistetaanko tämä sääntö (<xliff:g id="RULE">%1$s</xliff:g>)?"</string>
     <string name="zen_mode_delete_rule_button" msgid="611058106279881991">"Poista"</string>
     <string name="zen_mode_rule_type_unknown" msgid="2819480113355191421">"Tuntematon"</string>
     <string name="zen_mode_app_set_behavior" msgid="8597398780262575571">"Näitä asetuksia ei voi muuttaa juuri nyt. Sovellus <xliff:g id="APP_NAME">%1$s</xliff:g> otti Älä häiritse ‑tilan automaattisesti käyttöön muokatulla toiminnalla."</string>
@@ -3463,11 +3468,11 @@
     <string name="zen_mode_schedule_rule_days" msgid="220627703673691816">"Päivät"</string>
     <string name="zen_mode_schedule_rule_days_none" msgid="6011716195119389956">"Ei mitään"</string>
     <string name="zen_mode_schedule_rule_days_all" msgid="8814173364016139675">"Joka päivä"</string>
-    <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"Herätys voi ohittaa päättymisajan"</string>
-    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"Aikataulu poistuu käytöstä, kun hälytys soi"</string>
+    <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"Herätys voi kumota päättymisajan"</string>
+    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"Aikataulu menee pois päältä herätyksen yhteydessä"</string>
     <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"Älä häiritse ‑tilan toiminta"</string>
     <string name="zen_mode_custom_behavior_summary_default" msgid="3509865340195397447">"Käytä oletusasetuksia"</string>
-    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"Luo tälle aikataululle omia asetuksia"</string>
+    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"Valitse omat asetukset tälle aikataululle"</string>
     <string name="zen_mode_custom_behavior_category_title" msgid="7451686525113262087">"<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>"</string>
     <string name="summary_divider_text" msgid="4780683204694442666">", "</string>
     <string name="summary_range_symbol_combination" msgid="6038631664844488406">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
@@ -3488,9 +3493,9 @@
     <string name="zen_mode_from_anyone" msgid="7778836826814131083">"Keneltä tahansa"</string>
     <string name="zen_mode_from_contacts" msgid="267034158294332688">"Vain yhteystiedoilta"</string>
     <string name="zen_mode_from_starred" msgid="7349984569117392260">"Vain tähdellä merkityiltä yhteystiedoilta"</string>
-    <string name="zen_calls_summary_starred_repeat" msgid="9191394641577678207">"Tähdellä merkityiltä yhteyshenkilöiltä ja toistuvilta soittajilta"</string>
-    <string name="zen_calls_summary_contacts_repeat" msgid="7747592096431111510">"Yhteyshenkilöiltä ja toistuvilta soittajilta"</string>
-    <string name="zen_calls_summary_repeat_only" msgid="8839703337232747964">"Vain toistuvilta soittajilta"</string>
+    <string name="zen_calls_summary_starred_repeat" msgid="9191394641577678207">"Tähdellä merkityiltä yhteyshenkilöiltä ja usein soittavilta"</string>
+    <string name="zen_calls_summary_contacts_repeat" msgid="7747592096431111510">"Yhteyshenkilöiltä ja usein soittavilta"</string>
+    <string name="zen_calls_summary_repeat_only" msgid="8839703337232747964">"Vain usein soittavilta"</string>
     <string name="zen_mode_from_none" msgid="7683889985618637010">"Ei keneltäkään"</string>
     <string name="zen_mode_from_none_calls" msgid="2967739140346917546">"Älä salli puheluja"</string>
     <string name="zen_mode_from_none_messages" msgid="9069143820057833634">"Älä salli viestejä."</string>
@@ -3513,9 +3518,9 @@
     <string name="zen_mode_all_callers" msgid="4455039040077343838">"kuka tahansa"</string>
     <string name="zen_mode_contacts_callers" msgid="3116829245339716399">"yhteyshenkilöt"</string>
     <string name="zen_mode_starred_callers" msgid="1317376207713013472">"tähdellä merkityt yhteyshenkilöt"</string>
-    <string name="zen_mode_repeat_callers" msgid="1435309867554692340">"Toistuvat soitot"</string>
+    <string name="zen_mode_repeat_callers" msgid="1435309867554692340">"Usein soittavat"</string>
     <string name="zen_mode_repeat_callers_list" msgid="2750270907597457279">"toistuvat puhelut"</string>
-    <string name="zen_mode_repeat_callers_title" msgid="7192952181541813487">"Salli toistuvat soitot"</string>
+    <string name="zen_mode_repeat_callers_title" msgid="7192952181541813487">"Salli usein soittavat"</string>
     <string name="zen_mode_calls_summary_one" msgid="8327371053236689649">"Salli puhelut: <xliff:g id="CALLER_TYPE">%1$s</xliff:g>"</string>
     <string name="zen_mode_calls_summary_two" msgid="9017678770532673578">"Salli puhelut: <xliff:g id="CALLER_TYPE">%1$s</xliff:g> ja <xliff:g id="CALLERT_TPYE">%2$s</xliff:g>"</string>
     <string name="zen_mode_repeat_callers_summary" msgid="1752513516040525545">"Jos sama henkilö soittaa uudelleen <xliff:g id="MINUTES">%d</xliff:g> minuutin kuluessa"</string>
@@ -3548,7 +3553,7 @@
     <string name="device_feedback" msgid="4042352891448769818">"Lähetä palautetta tästä laitteesta"</string>
     <string name="restr_pin_enter_admin_pin" msgid="8577847751493521230">"Anna järjestelmänvalvojan PIN-koodi"</string>
     <string name="switch_on_text" msgid="7100491749799298324">"Käytössä"</string>
-    <string name="switch_off_text" msgid="3539551289454353555">"Ei käytössä"</string>
+    <string name="switch_off_text" msgid="3539551289454353555">"Ei päällä"</string>
     <string name="screen_pinning_title" msgid="578020318289781102">"Näytön kiinnitys"</string>
     <string name="screen_pinning_description" msgid="3814537379086412278">"Kun tämä asetus on käytössä, voit kiinnittää näytön. Tällöin näyttö pysyy näkyvissä, kunnes poistat kiinnityksen.\n\nNäytön kiinnittäminen:\n\n1. Varmista, että näytön kiinnitys on otettu käyttöön.\n\n2. Valitse Viimeisimmät.\n\n3. Valitse yläreunasta sovelluskuvake ja sitten kiinnityskuvake."</string>
     <string name="screen_pinning_unlock_pattern" msgid="1060334707088339444">"Pyydä lukituksenpoistokuviota ennen irrotusta"</string>
@@ -3640,14 +3645,14 @@
     <string name="advanced_apps" msgid="6643869089344883537">"Lisäasetukset"</string>
     <string name="configure_apps" msgid="4066683118857400943">"Sovellusten konfigurointi"</string>
     <string name="unknown_app" msgid="2312052973570376877">"Tuntematon sovellus"</string>
-    <string name="app_permissions" msgid="3215958256821756086">"Käyttöoikeuksien ylläpitäjä"</string>
+    <string name="app_permissions" msgid="3215958256821756086">"Käyttöoikeuksien ylläpito"</string>
     <string name="app_permissions_summary" msgid="8785798165776061594">"Sovellukset, joilla on lupa käyttää seuraavia: <xliff:g id="APPS">%1$s</xliff:g>"</string>
     <string name="tap_to_wake" msgid="1902991239401652323">"Herätä napauttamalla"</string>
     <string name="tap_to_wake_summary" msgid="8485222120721006793">"Herätä laite napauttamalla näyttöä kahdesti."</string>
     <string name="domain_urls_title" msgid="7939209950373945367">"Linkkien avautuminen"</string>
-    <string name="domain_urls_summary_none" msgid="5401203416941265109">"Älä avaa tuettuja linkkejä."</string>
+    <string name="domain_urls_summary_none" msgid="5401203416941265109">"Älä avaa tuettuja linkkejä"</string>
     <string name="domain_urls_summary_one" msgid="3893975485064803435">"Avaa <xliff:g id="DOMAIN">%s</xliff:g>"</string>
-    <string name="domain_urls_summary_some" msgid="2130534984153210797">"Avaa <xliff:g id="DOMAIN">%s</xliff:g> ja muut URL-osoitteet."</string>
+    <string name="domain_urls_summary_some" msgid="2130534984153210797">"Avaa <xliff:g id="DOMAIN">%s</xliff:g> ja muut URL-osoitteet"</string>
     <string name="domain_urls_apps_summary_off" msgid="1110203970617922543">"Ei tuettuja linkkejä avaavia sovelluksia"</string>
     <plurals name="domain_urls_apps_summary_on" formatted="false" msgid="3571309605151815405">
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sovellusta avaa tuettuja linkkejä</item>
@@ -3703,8 +3708,8 @@
     </plurals>
     <string name="high_power_filter_on" msgid="5294209328473386403">"Ei optimointia"</string>
     <string name="high_power_on" msgid="3573501822510580334">"Ei optimointia"</string>
-    <string name="high_power_off" msgid="5906679734326490426">"Akun käyttöä optimoidaan."</string>
-    <string name="high_power_system" msgid="739584574711292753">"Akun käytön optimointi ei ole käytettävissä."</string>
+    <string name="high_power_off" msgid="5906679734326490426">"Akun käyttöä optimoidaan"</string>
+    <string name="high_power_system" msgid="739584574711292753">"Akun käytön optimointi ei käytettävissä"</string>
     <string name="high_power_desc" msgid="333756885680362741">"Älä optimoi akun käyttöä. Tämä voi kuluttaa akkua nopeammin."</string>
     <string name="high_power_prompt_title" msgid="2805745781720454052">"Annetaanko sovellukselle oikeus toimia aina taustalla?"</string>
     <string name="high_power_prompt_body" msgid="8067395096053552289">"Jos <xliff:g id="APP_NAME">%1$s</xliff:g> saa toimia aina taustalla, laitteen akku voi kulua loppuun nopeammin. \n\nVoit muuttaa tätä asetusta myöhemmin kohdassa Asetukset &gt; Sovellukset ja ilmoitukset."</string>
@@ -3713,7 +3718,7 @@
     <string name="no_battery_summary" msgid="4105932628367471314">"Ei akun käyttöä täyteen lataamisen jälkeen"</string>
     <string name="app_notification_preferences" msgid="5154466638524523201">"Sovellusasetukset"</string>
     <string name="system_ui_settings" msgid="6751165163665775447">"Näytä SystemUI-viritin"</string>
-    <string name="additional_permissions" msgid="3142290772324571654">"Lisäkäyttöoikeudet"</string>
+    <string name="additional_permissions" msgid="3142290772324571654">"Lisäluvat"</string>
     <string name="additional_permissions_more" msgid="714264060348056246">"<xliff:g id="COUNT">%1$d</xliff:g> lisää"</string>
     <string name="share_remote_bugreport_dialog_title" msgid="1390719492733882678">"Jaetaanko virheraportti?"</string>
     <string name="share_remote_bugreport_dialog_message_finished" msgid="5133489230646384192">"Järjestelmänvalvoja pyysi virheraporttia voidakseen auttaa laitteen vianetsinnässä. Sovelluksia ja tietoja voidaan jakaa."</string>
@@ -3754,11 +3759,11 @@
     <string name="background_check_pref" msgid="664081406854758392">"Taustatarkistus"</string>
     <string name="background_check_title" msgid="4136736684290307970">"Täydet taustakäyttöoikeudet"</string>
     <string name="assist_access_context_title" msgid="2274614501747710439">"Käytä näytön tekstiä"</string>
-    <string name="assist_access_context_summary" msgid="5867997494395842785">"Salli avustajasovelluksen käsitellä näytön sisältöä tekstinä."</string>
+    <string name="assist_access_context_summary" msgid="5867997494395842785">"Salli avustajasovellukselle pääsy näytön sisältöön tekstinä"</string>
     <string name="assist_access_screenshot_title" msgid="1991014038776117688">"Käytä kuvakaappausta"</string>
-    <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Salli avustajasovelluksen käsitellä näytön kuvaa."</string>
+    <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Salli avustajasovellukselle pääsy näytön kuvaan"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"Näytön välkytys"</string>
-    <string name="assist_flash_summary" msgid="6697095786317559129">"Välkytä näytön reunoja, kun avustajasovellus käyttää näytöllä tai kuvakaappauksessa näkyvää tekstiä."</string>
+    <string name="assist_flash_summary" msgid="6697095786317559129">"Välkytä näytön reunoja, kun avustajasovellus käyttää näytöllä tai kuvakaappauksessa näkyvää tekstiä"</string>
     <string name="assist_footer" msgid="7030121180457472165">"Avustajasovellukset voivat auttaa sinua näytöllä näkyvien tietojen perusteella. Jotkin sovellukset tukevat myös käynnistysohjelma- ja äänisyötepalveluja, joten ne voivat tarjota sinulle integroitua apua."</string>
     <string name="average_memory_use" msgid="5333366040118953945">"Keskimääräinen muistin käyttö"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"Muistin enimmäiskäyttö"</string>
@@ -3780,7 +3785,7 @@
     </plurals>
     <string name="running_frequency" msgid="7545170806968474449">"Toistuvuus"</string>
     <string name="memory_maximum_usage" msgid="4734981118293469479">"Enimmäiskäyttö"</string>
-    <string name="no_data_usage" msgid="903383745620135746">"Dataa ei käytetty"</string>
+    <string name="no_data_usage" msgid="903383745620135746">"Dataa ei ole käytetty"</string>
     <string name="zen_access_warning_dialog_title" msgid="7704910289810337055">"Myönnetäänkö Älä häiritse -tilan käyttöoikeus sovellukselle <xliff:g id="APP">%1$s</xliff:g>?"</string>
     <string name="zen_access_warning_dialog_summary" msgid="2717755746850874577">"Sovellus voi ottaa Älä häiritse -tilan käyttöön tai poistaa sen käytöstä sekä muokata siihen liittyviä asetuksia."</string>
     <string name="zen_access_disabled_package_warning" msgid="7086237569177576966">"Tämän täytyy olla käytössä, sillä ilmoitusten käyttöoikeus on myönnetty."</string>
@@ -3997,9 +4002,9 @@
     <string name="suggestion_additional_fingerprints" msgid="3434467207282466411">"Lisää uusi sormenjälki"</string>
     <string name="suggestion_additional_fingerprints_summary" msgid="1916547587832484196">"Avaa lukitus toisella sormella."</string>
     <string name="battery_saver_on_summary" msgid="6841062406467435672">"Käytössä"</string>
-    <string name="battery_saver_off_scheduled_summary" msgid="3740414764069188669">"Käynnistyy, kun taso on <xliff:g id="BATTERY_PERCENTAGE">%1$s</xliff:g>"</string>
+    <string name="battery_saver_off_scheduled_summary" msgid="3740414764069188669">"Menee päälle kun jäljellä on <xliff:g id="BATTERY_PERCENTAGE">%1$s</xliff:g>"</string>
     <string name="battery_saver_off_summary" msgid="8736555723004299721">"Pois käytöstä"</string>
-    <string name="battery_saver_button_turn_on" msgid="3748696527267573793">"Ota käyttöön nyt"</string>
+    <string name="battery_saver_button_turn_on" msgid="3748696527267573793">"Laita päälle"</string>
     <string name="battery_saver_button_turn_off" msgid="2912950982503267828">"Sammuta nyt"</string>
     <string name="not_battery_optimizing" msgid="2616044774307734160">"Akun käytön optimointi ei käytössä"</string>
     <string name="lockscreen_remote_input" msgid="3363310613165354434">"Estä vastausten ja muun tekstin kirjoittaminen ilmoituksiin, kun laite on lukittu."</string>
@@ -4049,8 +4054,8 @@
     <string name="overlay_toast_failed_to_apply" msgid="5692251825129250040">"Peittokuvan piirto epäonnistui"</string>
     <string name="special_access" msgid="1453926335914696206">"Sovellusten erikoiskäyttö"</string>
     <plurals name="special_access_summary" formatted="false" msgid="5182092345063909346">
-      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sovelluksen datankäyttöä ei rajoiteta.</item>
-      <item quantity="one">1 sovelluksen datankäyttöä ei rajoiteta.</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sovelluksen datankäyttöä ei rajoiteta</item>
+      <item quantity="one">1 sovelluksen datankäyttöä ei rajoiteta</item>
     </plurals>
     <string name="special_access_more" msgid="7086690625048471400">"Katso lisää"</string>
     <string name="confirm_convert_to_fbe_warning" msgid="4972595831034280189">"Haluatko varmasti poistaa käyttäjätiedot ja ottaa tiedostojen salauksen käyttöön?"</string>
@@ -4137,7 +4142,7 @@
     <string name="fingerprint_swipe_for_notifications_summary" product="device" msgid="7950264130913070035">"Voit katsoa ilmoitukset pyyhkäisemällä laitteen takaosassa olevasta sormenjälkitunnistimesta alaspäin."</string>
     <string name="fingerprint_swipe_for_notifications_suggestion_title" msgid="948946491233738823">"Katso ilmoitukset nopeasti"</string>
     <string name="gesture_setting_on" msgid="7573680730101327866">"Käytössä"</string>
-    <string name="gesture_setting_off" msgid="2540159841716890511">"Ei käytössä"</string>
+    <string name="gesture_setting_off" msgid="2540159841716890511">"Ei päällä"</string>
     <string name="oem_unlock_enable_disabled_summary_bootloader_unlocked" msgid="7233244080078311793">"Käynnistysohjelman lukitus on jo avattu."</string>
     <string name="oem_unlock_enable_disabled_summary_connectivity" msgid="262986780389836168">"Muodosta ensin internetyhteys"</string>
     <string name="oem_unlock_enable_disabled_summary_connectivity_or_locked" msgid="3331374502670483142">"Muodosta internetyhteys tai ota yhteyttä operaattoriin"</string>
@@ -4145,7 +4150,7 @@
     <string name="oem_lock_info_message" msgid="5090850412279403901">"Käynnistä laite uudelleen, niin voit ottaa laitteen turvaominaisuuden käyttöön."</string>
     <string name="automatic_storage_manager_freed_bytes" msgid="7360443072390107772">"<xliff:g id="SIZE">%1$s</xliff:g> tilaa vapautettu yhteensä\n\nKäytetty viimeksi <xliff:g id="DATE">%2$s</xliff:g>"</string>
     <string name="web_action_enable_title" msgid="4462106633708675959">"Pikasovellukset"</string>
-    <string name="web_action_enable_summary" msgid="1729016644691793085">"Avaa linkkejä sovelluksessa, vaikka sitä ei ole asennettu."</string>
+    <string name="web_action_enable_summary" msgid="1729016644691793085">"Avaa linkkejä sovelluksessa, vaikka sitä ei ole asennettu"</string>
     <string name="web_action_section_title" msgid="5563229447734734662">"Pikasovellukset"</string>
     <string name="instant_apps_settings" msgid="879003203555847537">"Pikasovellusvalinnat"</string>
     <string name="domain_url_section_title" msgid="206403507921518321">"Asennetut sovellukset"</string>
@@ -4155,7 +4160,7 @@
     <string name="auto_sync_account_title" msgid="2394463123733529506">"Synkronoi tiedot automaattisesti"</string>
     <string name="auto_sync_personal_account_title" msgid="6844465157916100655">"Synkronoi henkilökohtaiset tiedot automaattisesti"</string>
     <string name="auto_sync_work_account_title" msgid="2403222633447522376">"Synkronoi työtiedot automaattisesti"</string>
-    <string name="auto_sync_account_summary" msgid="6316230976974033772">"Salli sovellusten päivittää tietoja automaattisesti."</string>
+    <string name="auto_sync_account_summary" msgid="6316230976974033772">"Salli sovellusten päivittää tietoja automaattisesti"</string>
     <string name="account_sync_title" msgid="1570164819114297154">"Tilin synkronointi"</string>
     <string name="account_sync_summary_some_on" msgid="1934556869158274053">"Synkronointi käytössä <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g> kohteella"</string>
     <string name="account_sync_summary_all_on" msgid="3634161204232431700">"Synkronointi käytössä kaikilla kohteilla"</string>
@@ -4326,7 +4331,7 @@
     <string name="prevent_ringing_option_none" msgid="1450985763137666231">"Älä tee mitään"</string>
     <string name="prevent_ringing_option_vibrate_summary" msgid="7961818570574683926">"Käytössä (värinä)"</string>
     <string name="prevent_ringing_option_mute_summary" msgid="3509459199090688328">"Käytössä (mykistys)"</string>
-    <string name="prevent_ringing_option_none_summary" msgid="5152618221093037451">"Ei käytössä"</string>
+    <string name="prevent_ringing_option_none_summary" msgid="5152618221093037451">"Ei päällä"</string>
     <string name="pref_title_network_details" msgid="3971074015034595956">"Verkon tiedot"</string>
     <string name="about_phone_device_name_warning" msgid="9088572775969880106">"Puhelimen sovellukset näkevät laitteesi nimen. Muut voivat myös nähdä nimen, kun muodostat Bluetooth-yhteyden laitteisiin tai aktivoit Wi-Fi-hotspotin."</string>
     <string name="devices_title" msgid="4768432575951993648">"Laitteet"</string>
@@ -4380,7 +4385,7 @@
     <string name="carrier_settings_title" msgid="7989949967020825268">"Operaattoriasetukset"</string>
     <string name="cdma_lte_data_service" msgid="8996857851150069339">"Määritä datapalvelu"</string>
     <string name="mobile_data_settings_title" msgid="3439626666647519547">"Mobiilidata"</string>
-    <string name="mobile_data_settings_summary" msgid="6492798151325636912">"Käytä mobiiliverkon dataa."</string>
+    <string name="mobile_data_settings_summary" msgid="6492798151325636912">"Käytä mobiiliverkon dataa"</string>
     <string name="mobile_data_settings_summary_auto_switch" msgid="3665863214578471494">"Puhelin vaihtaa automaattisesti tähän operaattoriin, kun se on kantoalueella."</string>
     <string name="calls_preference" msgid="2076353032705811243">"Puheluasetus"</string>
     <string name="sms_preference" msgid="8449270011976880">"Tekstiviestiasetus"</string>
@@ -4466,7 +4471,7 @@
     <string name="hwui_force_dark_title" msgid="3744825212652331461">"Ohita SmartDarkin pakottaminen päälle"</string>
     <string name="hwui_force_dark_summary" msgid="2051891908674765817">"Ohittaa toiminnon, joka pakottaa SmartDark-ominaisuuden aina päälle"</string>
     <string name="privacy_dashboard_title" msgid="8764930992456607513">"Tietosuoja"</string>
-    <string name="privacy_dashboard_summary" msgid="7916431309860824945">"Käyttöoikeudet, tilitoiminta, henkilökohtaiset tiedot"</string>
+    <string name="privacy_dashboard_summary" msgid="7916431309860824945">"Luvat, tilitoiminta, henkilökohtaiset tiedot"</string>
     <string name="contextual_card_dismiss_remove" msgid="1750420285615827309">"Poista"</string>
     <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"Säilytä"</string>
     <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"Poistetaanko tämä ehdotus?"</string>
@@ -4478,7 +4483,7 @@
     <string name="copyable_slice_toast" msgid="1357518174923789947">"<xliff:g id="COPY_CONTENT">%1$s</xliff:g> kopioitiin leikepöydälle"</string>
     <string name="search_bar_account_avatar_content_description" msgid="947628881535053409"></string>
     <string name="permission_bar_chart_empty_text" msgid="5893326513700540130">"0 sovellusta käytti käyttöoikeuksia"</string>
-    <string name="permission_bar_chart_title" msgid="874145405516650073">"Käyttöoikeudet viimeisten 24 tunnin ajalta"</string>
+    <string name="permission_bar_chart_title" msgid="874145405516650073">"Luvat viimeisten 24 tunnin ajalta"</string>
     <string name="permission_bar_chart_details" msgid="942094334321073927">"Näytä kaikki ohjauspaneelissa"</string>
     <plurals name="permission_bar_chart_label" formatted="false" msgid="2831305719356562097">
       <item quantity="other"><xliff:g id="NUMBER">%s</xliff:g> sovellusta</item>
diff --git a/tests/CarDeveloperOptions/res/values-fr-rCA/arrays.xml b/tests/CarDeveloperOptions/res/values-fr-rCA/arrays.xml
index 40e4daa..066375c 100644
--- a/tests/CarDeveloperOptions/res/values-fr-rCA/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-fr-rCA/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"fonctionner en arrière-plan"</item>
     <item msgid="6423861043647911030">"volume d\'accessibilité"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Position"</item>
+    <item msgid="6656077694190491067">"Position"</item>
+    <item msgid="8790228218278477369">"Position"</item>
+    <item msgid="7836406246005211990">"Vibreur"</item>
+    <item msgid="3951439024549922598">"Lire des contacts"</item>
+    <item msgid="8802152411647068">"Modifier les contacts"</item>
+    <item msgid="229544934599698735">"Lire le journal d\'appels"</item>
+    <item msgid="7396102294405899613">"Modifier le journal d\'appels"</item>
+    <item msgid="3597797992398484655">"Accéder à l\'agenda"</item>
+    <item msgid="2705975774250907343">"Modifier l\'agenda"</item>
+    <item msgid="4668747371441932697">"Position"</item>
+    <item msgid="1487578921720243646">"Publier des notifications"</item>
+    <item msgid="4636080349724146638">"Position"</item>
+    <item msgid="673510900286463926">"Appeler"</item>
+    <item msgid="542083422784609790">"Lire des messages texte ou des messages multimédias"</item>
+    <item msgid="1033780373029588436">"Écrire des messages texte ou des messages multimédias"</item>
+    <item msgid="5647111115517787488">"Recevoir des SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Recevoir des SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Recevoir des SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Recevoir des SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Envoyer des SMS/MMS"</item>
+    <item msgid="4726682243833913568">"Lire des messages texte ou des messages multimédias"</item>
+    <item msgid="6555678522277865572">"Écrire des messages texte ou des messages multimédias"</item>
+    <item msgid="6981734935578130884">"Modifier les paramètres"</item>
+    <item msgid="8705854389991425629">"Dessiner par dessus"</item>
+    <item msgid="5861356020344153651">"Accéder aux notifications"</item>
+    <item msgid="78432174621628659">"Appareil photo"</item>
+    <item msgid="3986116419882154794">"Enregistrer des fichiers audio"</item>
+    <item msgid="4516840825756409490">"Lire le fichier audio"</item>
+    <item msgid="6811712502798183957">"Lire le presse-papiers"</item>
+    <item msgid="2780369012602289114">"Modifier le presse-papiers"</item>
+    <item msgid="2331359440170850868">"Boutons multimédias"</item>
+    <item msgid="6133599737122751231">"Priorité audio"</item>
+    <item msgid="6844485713404805301">"Volume général"</item>
+    <item msgid="1600379420669104929">"Volume de la voix"</item>
+    <item msgid="6296768210470214866">"Volume de la sonnerie"</item>
+    <item msgid="510690696071629241">"Volume du contenu multimédia"</item>
+    <item msgid="406861638631430109">"Volume de l\'alarme"</item>
+    <item msgid="4715864795872233884">"Volume des notifications"</item>
+    <item msgid="2311478519251301183">"Volume Bluetooth"</item>
+    <item msgid="5133991377896747027">"Maintenir activé"</item>
+    <item msgid="2464189519136248621">"Lieu"</item>
+    <item msgid="2062677934050803037">"Position"</item>
+    <item msgid="1735171933192715957">"Obtenir les statistiques d\'utilisation"</item>
+    <item msgid="1014093788778383554">"Activer/Désactiver le micro"</item>
+    <item msgid="4199297950608622850">"Afficher le message"</item>
+    <item msgid="2527962435313398821">"Projeter des contenus multimédias"</item>
+    <item msgid="5117506254221861929">"Activer le RPV"</item>
+    <item msgid="8291198322681891160">"Définir le fond d\'écran"</item>
+    <item msgid="7106921284621230961">"Structure d\'assistance"</item>
+    <item msgid="4496533640894624799">"Saisie d\'écran d\'assistance"</item>
+    <item msgid="2598847264853993611">"Lire l\'état du téléphone"</item>
+    <item msgid="9215610846802973353">"Ajouter des messages vocaux"</item>
+    <item msgid="9186411956086478261">"Utiliser le protocole SIP"</item>
+    <item msgid="6884763100104539558">"Traiter l\'appel sortant"</item>
+    <item msgid="125513972170580692">"Empreintes digitales"</item>
+    <item msgid="2556071024281275619">"Capteurs corporels"</item>
+    <item msgid="617168514928339387">"Lire les messages de diffusion cellulaire"</item>
+    <item msgid="7134693570516523585">"Créer une position fictive"</item>
+    <item msgid="7224489175375229399">"Lire les données de l\'espace de stockage"</item>
+    <item msgid="8472735063903258202">"Écrire dans les données de l\'espace de stockage"</item>
+    <item msgid="4069276819909595110">"Activer l\'écran"</item>
+    <item msgid="1228338896751121025">"Obtenir les comptes"</item>
+    <item msgid="3181581793459233672">"Fonctionner en arrière-plan"</item>
+    <item msgid="2340936043025374076">"Volume d\'accessibilité"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Court"</item>
     <item msgid="4816511817309094890">"Moyenne"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Ne jamais autoriser"</item>
     <item msgid="8184570120217958741">"Toujours autoriser"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Modérée"</item>
+    <item msgid="1555861583162930714">"Faible"</item>
+    <item msgid="1719683776264798117">"Critique"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normale"</item>
+    <item msgid="6107138933849816768">"Modérée"</item>
+    <item msgid="182695359839047859">"Faible"</item>
+    <item msgid="8577246509202964244">"Critique"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Permanent"</item>
     <item msgid="167418068739176448">"Activité principale"</item>
diff --git a/tests/CarDeveloperOptions/res/values-fr-rCA/config.xml b/tests/CarDeveloperOptions/res/values-fr-rCA/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-fr-rCA/config.xml
+++ b/tests/CarDeveloperOptions/res/values-fr-rCA/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-fr-rCA/strings.xml b/tests/CarDeveloperOptions/res/values-fr-rCA/strings.xml
index 4f4a8c2..1a89acc 100644
--- a/tests/CarDeveloperOptions/res/values-fr-rCA/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-fr-rCA/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Agrandissez ou réduisez le texte affiché."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Rapetisser"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Agrandir"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Exemple de texte"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Le Magicien d\'Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Chapitre 11 : La merveilleuse cité d\'émeraude d\'Oz"</string>
@@ -212,7 +211,7 @@
     <string name="proxy_url_title" msgid="882042361706435904">"URL config. auto mand. : "</string>
     <string name="radio_info_dl_kbps" msgid="2903778264453410272">"Bande passante de téléchargement (kb/s) :"</string>
     <string name="radio_info_ul_kbps" msgid="3802245899811732716">"Bande passante de téléversement (kb/s) :"</string>
-    <string name="radio_info_signal_location_label" msgid="6788144906873498013">"Données de la position de la cellule (discontinuées) :"</string>
+    <string name="radio_info_signal_location_label" msgid="6788144906873498013">"Données de la position de la cellule (obsolètes) :"</string>
     <string name="radio_info_phy_chan_config" msgid="1184401689381480522">"Configuration du canal physique LTE :"</string>
     <string name="radio_info_cell_info_refresh_rate" msgid="3557422342215875913">"Taux d\'actualisation des données de la cellule :"</string>
     <string name="radio_info_cellinfo_label" msgid="632796561627452215">"Données des mesures de toutes les cellules :"</string>
@@ -419,7 +418,7 @@
     <string name="security_settings_face_enroll_done" msgid="5409739233373490971">"Terminé"</string>
     <string name="security_settings_face_settings_use_face_category" msgid="1586532139528115416">"Util. votre visage pour"</string>
     <string name="security_settings_face_settings_use_face_unlock_phone" msgid="318274519126401671">"Déverr. l\'appareil"</string>
-    <string name="security_settings_face_settings_use_face_for_apps" msgid="5479369083370664351">"Connex. et paiements dans applis"</string>
+    <string name="security_settings_face_settings_use_face_for_apps" msgid="5479369083370664351">"Connexion applis et paiements"</string>
     <string name="security_settings_face_settings_require_attention" msgid="2755140150841557225">"Yeux ouverts pour déverrouillage"</string>
     <string name="security_settings_face_settings_require_attention_details" msgid="2557060433599942587">"Lorsque vous utilisez l\'authent. visage, vos yeux doivent être ouverts"</string>
     <string name="security_settings_face_settings_require_confirmation" msgid="7312024271060416438">"Toujours demander une confirmation"</string>
@@ -440,15 +439,15 @@
     <string name="security_settings_fingerprint_preference_summary_none" msgid="3613424536269750172"></string>
     <string name="security_settings_fingerprint_enroll_introduction_title" msgid="889558002683900544">"Déverrouillage avec empreinte"</string>
     <string name="security_settings_fingerprint_enroll_introduction_title_unlock_disabled" msgid="7915504118657864429">"Utilisez empreinte digitale"</string>
-    <string name="security_settings_fingerprint_enroll_introduction_message" msgid="5586198131986682472">"Il vous suffit de toucher le lecteur d\'empreintes digitales pour déverrouiller votre téléphone, autoriser des achats ou vous connecter à des applications. Toutes les personnes dont les empreintes digitales sont ajoutées sur votre téléphone peuvent effectuer ces opérations. Sélectionnez donc ces personnes avec soin.\n\nRemarque : Vos empreintes digitales peuvent être moins sécurisées qu\'un schéma ou un code fiables."</string>
+    <string name="security_settings_fingerprint_enroll_introduction_message" msgid="5586198131986682472">"Il vous suffit de toucher le lecteur d\'empreintes digitales pour déverrouiller votre téléphone, autoriser des achats ou vous connecter à des applications. Toutes les personnes dont les empreintes digitales sont ajoutées sur votre téléphone peuvent effectuer ces opérations. Sélectionnez donc ces personnes avec soin.\n\nRemarque : Votre empreinte digitale peut être moins sécurisée qu\'un schéma ou un NIP fiables."</string>
     <string name="security_settings_fingerprint_enroll_introduction_message_unlock_disabled" msgid="1640839304679275468">"Utilisez votre empreinte digitale pour déverrouiller votre téléphone ou autoriser des achats.\n\nRemarque : Vous ne pouvez pas utiliser vos empreintes digitales pour déverrouiller cet appareil. Pour obtenir plus d\'information, communiquez avec l\'administrateur de votre organisation."</string>
-    <string name="security_settings_fingerprint_enroll_introduction_message_setup" msgid="6734490666593320711">"Utilisez votre empreinte digitale pour déverrouiller votre téléphone ou autoriser des achats.\n\nRemarque : Vos empreintes digitales peuvent être moins sécurisées qu\'un schéma ou un NIP fiables."</string>
+    <string name="security_settings_fingerprint_enroll_introduction_message_setup" msgid="6734490666593320711">"Utilisez votre empreinte digitale pour déverrouiller votre téléphone ou autoriser des achats.\n\nRemarque : Votre empreinte digitale peut être moins sécurisée qu\'un schéma ou un NIP fiables."</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel" msgid="9168637333731599827">"Annuler"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue" msgid="271662150372486535">"Continuer"</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel_setup" msgid="756928427429893070">"Passer"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue_setup" msgid="4125977169169671144">"Suivant"</string>
-    <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"Ignorer l\'empreinte digitale?"</string>
-    <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"La configuration des empreintes digitales ne prend qu\'une minute ou deux. Si vous ignorez cette étape, vous pouvez ajouter votre empreinte digitale plus tard dans les paramètres."</string>
+    <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"Ignorer configuration empreinte?"</string>
+    <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"La configuration de l\'empreinte digitale ne prend qu\'une minute ou deux. Si vous ignorez cette étape, vous pouvez ajouter votre empreinte digitale plus tard dans les paramètres."</string>
     <string name="lock_screen_intro_skip_title" msgid="5307431665496346914">"Ignorer verrouillage d\'écran?"</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="tablet" msgid="7553945981266845264">"Les fonctionnalités de protection de l\'appareil ne seront pas activées. Vous ne pourrez pas empêcher d\'autres personnes d\'utiliser cette tablette en cas de perte, de vol ou de réinitialisation."</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="device" msgid="1378243257238015603">"Les fonctionnalités de protection de l\'appareil ne seront pas activées. Vous ne pourrez pas empêcher d\'autres personnes d\'utiliser cet appareil en cas de perte, de vol ou de réinitialisation."</string>
@@ -596,20 +595,20 @@
     <string name="unlock_disable_lock_title" msgid="3508492427073600294">"Désactiver le verrouillage de l\'écran"</string>
     <string name="unlock_disable_frp_warning_title" msgid="5858589970505254193">"Supprimer la protection de l\'appareil?"</string>
     <string name="unlock_disable_frp_warning_title_profile" msgid="3814123014295965266">"Supprimer la protection du profil?"</string>
-    <string name="unlock_disable_frp_warning_content_pattern" msgid="1843950215687159135">"Les fonctions de protection de l\'appareil ne fonctionneront pas sans votre schéma."</string>
-    <string name="unlock_disable_frp_warning_content_pattern_fingerprint" msgid="8846957650251741548">"Les fonctions de protection de l\'appareil ne fonctionneront pas sans votre schéma.<xliff:g id="EMPTY_LINE">
+    <string name="unlock_disable_frp_warning_content_pattern" msgid="1843950215687159135">"Les fonctionnalités de protection de l\'appareil ne fonctionneront pas sans votre schéma."</string>
+    <string name="unlock_disable_frp_warning_content_pattern_fingerprint" msgid="8846957650251741548">"Les fonctionnalités de protection de l\'appareil ne fonctionneront pas sans votre schéma.<xliff:g id="EMPTY_LINE">
 
 </xliff:g>Vos empreintes digitales enregistrées seront également supprimées de cet appareil et vous ne pourrez pas déverrouiller votre téléphone, autoriser des achats ni vous connecter à des applications avec celles-ci."</string>
-    <string name="unlock_disable_frp_warning_content_pin" msgid="6760473271034592796">"Les fonctions de protection de l\'appareil ne fonctionneront pas sans votre NIP."</string>
-    <string name="unlock_disable_frp_warning_content_pin_fingerprint" msgid="4384632309103635233">"Les fonctions de protection de l\'appareil ne fonctionneront pas sans votre NIP.<xliff:g id="EMPTY_LINE">
+    <string name="unlock_disable_frp_warning_content_pin" msgid="6760473271034592796">"Les fonctionnalités de protection de l\'appareil ne fonctionneront pas sans votre NIP."</string>
+    <string name="unlock_disable_frp_warning_content_pin_fingerprint" msgid="4384632309103635233">"Les fonctionnalités de protection de l\'appareil ne fonctionneront pas sans votre NIP.<xliff:g id="EMPTY_LINE">
 
 </xliff:g>Vos empreintes digitales enregistrées seront également supprimées de cet appareil et vous ne pourrez pas déverrouiller votre téléphone, autoriser des achats ni vous connecter à des applications avec celles-ci."</string>
-    <string name="unlock_disable_frp_warning_content_password" msgid="854665587186358170">"Les fonctions de protection de l\'appareil ne fonctionneront pas sans votre mot de passe."</string>
-    <string name="unlock_disable_frp_warning_content_password_fingerprint" msgid="218143910981979545">"Les fonctions de protection de l\'appareil ne fonctionneront pas sans votre mot de passe. <xliff:g id="EMPTY_LINE">
+    <string name="unlock_disable_frp_warning_content_password" msgid="854665587186358170">"Les fonctionnalités de protection de l\'appareil ne fonctionneront pas sans votre mot de passe."</string>
+    <string name="unlock_disable_frp_warning_content_password_fingerprint" msgid="218143910981979545">"Les fonctionnalités de protection de l\'appareil ne fonctionneront pas sans votre mot de passe. <xliff:g id="EMPTY_LINE">
 
 </xliff:g>Vos empreintes digitales enregistrées seront également supprimées de cet appareil et vous ne pourrez pas déverrouiller votre téléphone, autoriser des achats ni vous connecter à des applications avec celles-ci."</string>
-    <string name="unlock_disable_frp_warning_content_unknown" msgid="3570135744390201244">"Les fonctions de protection de l\'appareil ne fonctionneront pas sans votre verrouillage d\'écran."</string>
-    <string name="unlock_disable_frp_warning_content_unknown_fingerprint" msgid="5775815077478538855">"Les fonctions de protection de l\'appareil ne fonctionneront pas sans votre verrouillage d\'écran.<xliff:g id="EMPTY_LINE">
+    <string name="unlock_disable_frp_warning_content_unknown" msgid="3570135744390201244">"Les fonctionnalités de protection de l\'appareil ne fonctionneront pas sans votre verrouillage d\'écran."</string>
+    <string name="unlock_disable_frp_warning_content_unknown_fingerprint" msgid="5775815077478538855">"Les fonctionnalités de protection de l\'appareil ne fonctionneront pas sans votre verrouillage d\'écran.<xliff:g id="EMPTY_LINE">
 
 </xliff:g>Vos empreintes digitales enregistrées seront également supprimées de cet appareil et vous ne pourrez pas déverrouiller votre téléphone, autoriser des achats ni vous connecter à des applications avec celles-ci."</string>
     <string name="unlock_disable_frp_warning_content_pattern_profile" msgid="2369992898062808499">"Les fonctions de protection du profil ne fonctionneront pas sans votre schéma."</string>
@@ -668,7 +667,6 @@
       <item quantity="one">Doit contenir moins de <xliff:g id="NUMBER_1">%d</xliff:g> chiffre</item>
       <item quantity="other">Doit contenir moins de <xliff:g id="NUMBER_1">%d</xliff:g> chiffres</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Doit contenir uniquement des chiffres contenus entre 0 et 9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"L\'administrateur de l\'appareil ne permet pas l\'utilisation d\'un NIP récent"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Les NIP communs sont bloqués par l\'administrateur de votre service informatique. Essayez un NIP différent."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Vous ne pouvez pas inclure de caractère non valide"</string>
@@ -699,6 +697,10 @@
       <item quantity="one">Doit contenir au moins <xliff:g id="COUNT">%d</xliff:g> caractère autre qu\'une lettre</item>
       <item quantity="other">Doit contenir au moins <xliff:g id="COUNT">%d</xliff:g> caractères autres qu\'une lettre</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">Doit contenir au moins <xliff:g id="COUNT">%d</xliff:g> caractère non numérique</item>
+      <item quantity="other">Doit contenir au moins <xliff:g id="COUNT">%d</xliff:g> caractères non numériques</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"L\'administrateur de l\'appareil ne permet pas l\'utilisation d\'un mot de passe récent"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Les mots de passe communs sont bloqués par l\'administrateur de votre service informatique. Essayez un mot de passe différent."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Les suites croissantes, décroissantes ou répétitives de chiffres ne sont pas autorisées"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Cellulaire"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Si aucun réseau Wi‑Fi n\'est accessible, utiliser le réseau cellulaire"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Si le réseau cellulaire n\'est pas accessible, utiliser le Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Appeler sur réseau Wi‑Fi. Si le Wi‑Fi est interr., l\'appel prendra fin."</string>
@@ -1793,7 +1798,7 @@
     <string name="install_all_warning" product="device" msgid="9141585291103603515">"Votre appareil et vos données personnelles sont plus vulnérables aux attaques provenant d\'applications inconnues. En installant des applications provenant de cette source, vous acceptez d\'être responsable de tout dommage causé à votre appareil ou de toute perte de données pouvant découler de l\'utilisation de telles applications."</string>
     <string name="advanced_settings" msgid="6282069364060968122">"Paramètres avancés"</string>
     <string name="advanced_settings_summary" msgid="5912237062506771716">"Activer d\'autres paramètres"</string>
-    <string name="application_info_label" msgid="3886253474964599105">"Infos sur l\'application"</string>
+    <string name="application_info_label" msgid="3886253474964599105">"Infos sur les applis"</string>
     <string name="storage_label" msgid="1109537840103290384">"Stockage"</string>
     <string name="auto_launch_label" msgid="47089737922907379">"Ouvert par défaut"</string>
     <string name="auto_launch_label_generic" msgid="7865828543459493308">"Valeurs par défaut"</string>
@@ -2272,9 +2277,9 @@
     <string name="battery_tip_smart_battery_title" product="tablet" msgid="203494973250969040">"Améliorer l\'autonomie de la tablette"</string>
     <string name="battery_tip_smart_battery_title" product="device" msgid="7419448992583346364">"Améliorer l\'autonomie de l\'appareil"</string>
     <string name="battery_tip_smart_battery_summary" msgid="5344821856478265778">"Activer le gestionnaire de pile"</string>
-    <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Activer la fonction Économie d\'énergie"</string>
+    <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Activer l\'économiseur de pile"</string>
     <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"La pile pourrait s\'épuiser plus tôt que d\'habitude"</string>
-    <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"La fonction Économie d\'énergie est activée"</string>
+    <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Économiseur de pile activé"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Certaines fonctionnalités pourraient être limitées"</string>
     <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Le téléphone a été sollicité plus que d\'habitude"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"La tablette a été sollicitée plus que d\'habitude"</string>
@@ -2312,9 +2317,9 @@
     <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"Cette application pourra utiliser la pile en arrière-plan. Cela pourrait épuiser la pile plus rapidement."</string>
     <string name="battery_tip_unrestrict_app_dialog_ok" msgid="9154938931448151479">"Supprimer"</string>
     <string name="battery_tip_unrestrict_app_dialog_cancel" msgid="7331148618292397166">"Annuler"</string>
-    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"Vos applications utilisent une quantité normale d\'énergie. Si les applications utilisent trop d\'énergie, votre téléphone vous suggérera des actions à essayer.\n\nVous pouvez toujours activer la fonction Économie d\'énergie si la pile est trop faible."</string>
-    <string name="battery_tip_dialog_summary_message" product="tablet" msgid="1721081030632329647">"Vos applications utilisent une quantité normale d\'énergie. Si les applications utilisent trop d\'énergie, votre tablette vous suggérera des actions à essayer.\n\nVous pouvez toujours activer la fonction Économie d\'énergie si la pile est trop faible."</string>
-    <string name="battery_tip_dialog_summary_message" product="device" msgid="146872407040848465">"Vos applications utilisent une quantité normale d\'énergie. Si les applications utilisent trop d\'énergie, votre appareil vous suggérera des actions à essayer.\n\nVous pouvez toujours activer la fonction Économie d\'énergie si la pile est trop faible."</string>
+    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"Vos applications utilisent une quantité normale d\'énergie. Si les applications utilisent trop d\'énergie, votre téléphone vous suggérera des actions à essayer.\n\nVous pouvez toujours activer la fonction Économiseur de pile si la pile est trop faible."</string>
+    <string name="battery_tip_dialog_summary_message" product="tablet" msgid="1721081030632329647">"Vos applications utilisent une quantité normale d\'énergie. Si les applications utilisent trop d\'énergie, votre tablette vous suggérera des actions à essayer.\n\nVous pouvez toujours activer l\'économiseur de pile si la pile est trop faible."</string>
+    <string name="battery_tip_dialog_summary_message" product="device" msgid="146872407040848465">"Vos applications utilisent une quantité normale d\'énergie. Si les applications utilisent trop d\'énergie, votre appareil vous suggérera des actions à essayer.\n\nVous pouvez toujours activer l\'économiseur de pile si la pile est trop faible."</string>
     <string name="smart_battery_manager_title" msgid="5744035036663849515">"Gestionnaire de pile"</string>
     <string name="smart_battery_title" msgid="4919670408532804351">"Gérer les applications automatiquement"</string>
     <string name="smart_battery_summary" msgid="640027046471198174">"Restreindre l\'usage de la pile pour les applications que vous n\'utilisez pas souvent"</string>
@@ -2441,7 +2446,7 @@
     <string name="process_kernel_label" msgid="4175060316414593760">"Système d\'exploitation Android"</string>
     <string name="process_mediaserver_label" msgid="8591722404282619153">"Serveur multimédia"</string>
     <string name="process_dex2oat_label" msgid="8249082119748556085">"Optimisation des applications"</string>
-    <string name="battery_saver" msgid="3989710213758938398">"Économie d\'énergie"</string>
+    <string name="battery_saver" msgid="3989710213758938398">"Économiseur de pile"</string>
     <string name="battery_saver_auto_title" msgid="4158659069641849952">"Activer automatiquement"</string>
     <string name="battery_saver_auto_no_schedule" msgid="739814529432092706">"Aucun horaire"</string>
     <string name="battery_saver_auto_routine" msgid="886514412067906980">"Selon votre routine"</string>
@@ -2666,7 +2671,7 @@
     <string name="data_usage_cellular_data_summary" msgid="9162777397135709280">"Interrompues à la limite"</string>
     <string name="account_settings_menu_auto_sync" msgid="2673669556006027506">"Synchronisation auto données"</string>
     <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"Synchro auto des données perso"</string>
-    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Synchro auto données profess."</string>
+    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Synchro auto des données pros"</string>
     <string name="data_usage_change_cycle" msgid="447761920472170031">"Changer le cycle..."</string>
     <string name="data_usage_pick_cycle_day" msgid="6319750879145917066">"Jour du mois de réinitialisation du cycle utilisation données :"</string>
     <string name="data_usage_empty" msgid="7981405723435034032">"Aucune donnée utilisée par les applications pendant cette période."</string>
@@ -2746,8 +2751,8 @@
     <string name="vpn_ipsec_server_cert" msgid="3066696943831527934">"Certificat de serveur IPSec"</string>
     <string name="vpn_show_options" msgid="7672984921872882859">"Afficher les options avancées"</string>
     <string name="vpn_search_domains" msgid="8469394307693909080">"Domaines de recherche DNS"</string>
-    <string name="vpn_dns_servers" msgid="3017453300909321239">"Serveurs DNS (Ex. 8.8.8.8)"</string>
-    <string name="vpn_routes" msgid="3393989650778663742">"Itinéraires transfert (Ex. 10.0.0.0/8)"</string>
+    <string name="vpn_dns_servers" msgid="3017453300909321239">"Serveurs DNS (p. ex. 8.8.8.8)"</string>
+    <string name="vpn_routes" msgid="3393989650778663742">"Itinéraires transfert (p. ex. 10.0.0.0/8)"</string>
     <string name="vpn_username" msgid="5357878823189445042">"Nom d\'utilisateur"</string>
     <string name="vpn_password" msgid="5325943601523662246">"Mot de passe"</string>
     <string name="vpn_save_login" msgid="6215503139606646915">"Enregistrer les informations de compte"</string>
@@ -3164,7 +3169,7 @@
       <item quantity="other"><xliff:g id="ON_COUNT">%d</xliff:g> règles activées</item>
     </plurals>
     <string name="zen_mode_settings_title" msgid="3425263414594779244">"Ne pas déranger"</string>
-    <string name="zen_mode_settings_turn_on_dialog_title" msgid="3062548369931058282">"Activer la fonction « Ne pas déranger »"</string>
+    <string name="zen_mode_settings_turn_on_dialog_title" msgid="3062548369931058282">"Activer le mode Ne pas déranger"</string>
     <string name="zen_mode_behavior_settings_title" msgid="423125904296667490">"Exceptions"</string>
     <string name="zen_mode_duration_settings_title" msgid="5522668871014735728">"Durée par défaut"</string>
     <string name="zen_mode_behavior_allow_title" msgid="2440627647424280842">"Autoriser sons et vibrations de"</string>
@@ -3189,7 +3194,7 @@
     <string name="zen_mode_summary_combination" msgid="6960111215170691605">"<xliff:g id="MODE">%1$s</xliff:g> : <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
     <string name="zen_mode_visual_interruptions_settings_title" msgid="8378266552787406849">"Bloquer dérangements visuels"</string>
     <string name="zen_mode_visual_signals_settings_subtitle" msgid="6608239691864638854">"Autoriser les signaux visuels"</string>
-    <string name="zen_mode_settings_category" msgid="5601680733422424922">"Quand la fonction Ne pas déranger est activée"</string>
+    <string name="zen_mode_settings_category" msgid="5601680733422424922">"Quand le mode Ne pas déranger est activé"</string>
     <string name="zen_mode_restrict_notifications_title" msgid="7486753018073540477">"Restreindre les notifications"</string>
     <string name="zen_mode_restrict_notifications_mute" msgid="2673665450311184875">"Aucun son des notifications"</string>
     <string name="zen_mode_restrict_notifications_mute_summary" msgid="1696217042353376674">"Vous verrez des notifications sur l\'écran"</string>
@@ -3366,10 +3371,10 @@
     <string name="no_notification_assistant" msgid="9140123568386413264">"Aucun assistant"</string>
     <string name="no_notification_listeners" msgid="1366386609506834717">"Aucune demande d\'accès aux notifications n\'a été envoyée pour les applications installées."</string>
     <string name="notification_assistant_security_warning_title" msgid="4190584438086738496">"Autoriser <xliff:g id="SERVICE">%1$s</xliff:g> à accéder aux notifications?"</string>
-    <string name="notification_assistant_security_warning_summary" msgid="6924513399671031930">"<xliff:g id="NOTIFICATION_ASSISTANT_NAME">%1$s</xliff:g> pourra lire toutes les notifications, y compris des données personnelles, telles que des noms de contacts et le texte des messages que vous recevez. Ce service pourra également masquer des notifications ou déclencher les boutons d\'action que celles-ci contiennent. \n\nCela permettra également à l\'application d\'activer et de désactiver la fonction Ne pas déranger et de modifier les paramètres connexes."</string>
+    <string name="notification_assistant_security_warning_summary" msgid="6924513399671031930">"<xliff:g id="NOTIFICATION_ASSISTANT_NAME">%1$s</xliff:g> pourra lire toutes les notifications, y compris des données personnelles, telles que des noms de contacts et le texte des messages que vous recevez. Ce service pourra également masquer des notifications ou déclencher les boutons d\'action que celles-ci contiennent. \n\nCela permettra également à l\'application d\'activer et de désactiver le mode Ne pas déranger et de modifier les paramètres connexes."</string>
     <string name="notification_listener_security_warning_title" msgid="4902253246428777797">"Autoriser <xliff:g id="SERVICE">%1$s</xliff:g> à accéder aux notifications?"</string>
-    <string name="notification_listener_security_warning_summary" msgid="4454702907350100288">"<xliff:g id="NOTIFICATION_LISTENER_NAME">%1$s</xliff:g> pourra lire toutes les notifications, y compris des données personnelles, telles que des noms de contacts et le texte des messages que vous recevez. Ce service pourra également masquer des notifications ou déclencher les boutons d\'action que celles-ci contiennent. \n\nCela permettra également à l\'application d\'activer et de désactiver la fonction Ne pas déranger et de modifier les paramètres connexes."</string>
-    <string name="notification_listener_disable_warning_summary" msgid="162165151519082978">"Si vous désactivez l\'accès aux notifications pour <xliff:g id="NOTIFICATION_LISTENER_NAME">%1$s</xliff:g>, l\'accès à la fonction Ne pas déranger peut également être désactivé."</string>
+    <string name="notification_listener_security_warning_summary" msgid="4454702907350100288">"<xliff:g id="NOTIFICATION_LISTENER_NAME">%1$s</xliff:g> pourra lire toutes les notifications, y compris des données personnelles, telles que des noms de contacts et le texte des messages que vous recevez. Ce service pourra également masquer des notifications ou déclencher les boutons d\'action que celles-ci contiennent. \n\nCela permettra également à l\'application d\'activer et de désactiver le mode Ne pas déranger et de modifier les paramètres connexes."</string>
+    <string name="notification_listener_disable_warning_summary" msgid="162165151519082978">"Si vous désactivez l\'accès aux notifications pour <xliff:g id="NOTIFICATION_LISTENER_NAME">%1$s</xliff:g>, l\'accès au mode Ne pas déranger peut également être désactivé."</string>
     <string name="notification_listener_disable_warning_confirm" msgid="7863495391671154188">"Désactiver"</string>
     <string name="notification_listener_disable_warning_cancel" msgid="6264631825225298458">"Annuler"</string>
     <string name="vr_listeners_title" msgid="511483902408792832">"Services d\'assistance de réalité virtuelle"</string>
@@ -3721,7 +3726,7 @@
     <string name="sharing_remote_bugreport_dialog_message" msgid="3814787466701526359">"Ce rapport de bogue est partagé avec votre administrateur informatique. Pour en savoir plus, communiquez avec lui."</string>
     <string name="share_remote_bugreport_action" msgid="8600797271670537888">"Partager"</string>
     <string name="decline_remote_bugreport_action" msgid="706319275774199033">"Refuser"</string>
-    <string name="usb_use_charging_only" msgid="2344625733377110164">"Pas de transfert de données"</string>
+    <string name="usb_use_charging_only" msgid="2344625733377110164">"Aucun transfert de données"</string>
     <string name="usb_use_charging_only_desc" msgid="3283518562582478950">"Charger cet appareil seulement"</string>
     <string name="usb_use_power_only" msgid="6595783381323810697">"Charger l\'appareil connecté"</string>
     <string name="usb_use_file_transfers" msgid="6153021302176151884">"Transfert de fichiers"</string>
@@ -3808,14 +3813,14 @@
     <string name="app_permission_summary_allowed" msgid="6458476982015518778">"Autorisée"</string>
     <string name="app_permission_summary_not_allowed" msgid="1171642541675462584">"Non autorisée"</string>
     <string name="keywords_install_other_apps" msgid="5383559540695847668">"installer des applications provenant de sources inconnues"</string>
-    <string name="write_settings" msgid="9009040811145552108">"Modifier param. système"</string>
+    <string name="write_settings" msgid="9009040811145552108">"Modifier les paramètres système"</string>
     <string name="keywords_write_settings" msgid="3450405263390246293">"écrire des modifications aux paramètres du système"</string>
     <string name="write_settings_summary" msgid="4650251358459404247">"<xliff:g id="COUNT_0">%1$d</xliff:g> applis sur <xliff:g id="COUNT_1">%2$d</xliff:g> sont autorisées à modifier les param. système"</string>
     <string name="financial_apps_sms_access_title" msgid="3422655018008259655">"Accès des applications financières aux textos"</string>
     <string name="filter_install_sources_apps" msgid="4519839764020866701">"Peut installer d\'autres applications"</string>
     <string name="filter_write_settings_apps" msgid="6864144615530081121">"Peut modifier les paramètres du système"</string>
     <string name="write_settings_title" msgid="5852614614193830632">"Peut modifier les paramètres du système"</string>
-    <string name="write_system_settings" msgid="20450765210832463">"Modifier param. système"</string>
+    <string name="write_system_settings" msgid="20450765210832463">"Modifier les paramètres système"</string>
     <string name="permit_write_settings" msgid="4198491281216818756">"Autoriser la modification des paramètres du système"</string>
     <string name="write_settings_description" msgid="2536706293042882500">"Cette autorisation permet à une application de modifier les paramètres du système."</string>
     <string name="write_settings_on" msgid="7328986337962635118">"Oui"</string>
@@ -3888,7 +3893,7 @@
     <string name="condition_zen_title" msgid="2128184708916052585">"Mode Ne pas déranger activé"</string>
     <string name="condition_zen_summary_phone_muted" msgid="4396050395522974654">"Téléphone en sourdine"</string>
     <string name="condition_zen_summary_with_exceptions" msgid="3435216391993785818">"Avec des exceptions"</string>
-    <string name="condition_battery_title" msgid="6704870010912986274">"Économie d\'énergie activée"</string>
+    <string name="condition_battery_title" msgid="6704870010912986274">"Économiseur de pile activé"</string>
     <string name="condition_battery_summary" msgid="1236078243905690620">"Fonctionnalités restreintes"</string>
     <string name="condition_cellular_title" msgid="6605277435894307935">"Données cellulaires désactivées"</string>
     <string name="condition_cellular_summary" msgid="3607459310548343777">"Internet est uniquement accessible par Wi‑Fi"</string>
@@ -3937,7 +3942,7 @@
     <string name="cell_data_template" msgid="5473177306229738078">"Données cellulaires utilisées : <xliff:g id="AMOUNT">^1</xliff:g>"</string>
     <string name="wifi_data_template" msgid="3146090439147042068">"Données Wi-Fi : <xliff:g id="AMOUNT">^1</xliff:g>"</string>
     <string name="ethernet_data_template" msgid="6414118030827090119">"Données Ethernet : <xliff:g id="AMOUNT">^1</xliff:g>"</string>
-    <string name="billing_cycle" msgid="5740717948341713190">"Avertissement et limites données"</string>
+    <string name="billing_cycle" msgid="5740717948341713190">"Avertissement et limites de données"</string>
     <string name="app_usage_cycle" msgid="213483325132959663">"Cycle d\'util. données d\'appli."</string>
     <string name="cell_data_warning" msgid="8902740337286652689">"Seuil à partir duquel un avertissement relatif à la consommation des données est envoyé : <xliff:g id="ID_1">^1</xliff:g>"</string>
     <string name="cell_data_limit" msgid="3175933829235314233">"Limite d\'utilisation de données : <xliff:g id="ID_1">^1</xliff:g>"</string>
@@ -4305,7 +4310,7 @@
     <string name="change_wifi_state_title" msgid="5140754955787584174">"Gestion du Wi-Fi"</string>
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"Autoriser l\'application à gérer le Wi-Fi"</string>
     <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"Autorisez cette application à activer ou à désactiver le Wi-Fi, à rechercher les réseaux Wi-Fi et à s\'y connecter, à ajouter et à supprimer des réseaux ou à créer un point d\'accès local uniquement"</string>
-    <string name="media_output_title" msgid="8710632337456601848">"Faire jouer les médias vers"</string>
+    <string name="media_output_title" msgid="8710632337456601848">"Faire jouer les contenus multimédias sur"</string>
     <string name="media_output_default_summary" msgid="3159237976830415584">"Cet appareil"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"Téléphone"</string>
     <string name="media_output_summary" product="tablet" msgid="6672024060360538526">"Tablette"</string>
diff --git a/tests/CarDeveloperOptions/res/values-fr/arrays.xml b/tests/CarDeveloperOptions/res/values-fr/arrays.xml
index 27ba552..0a5df1f 100644
--- a/tests/CarDeveloperOptions/res/values-fr/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-fr/arrays.xml
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"Ne jamais autoriser"</item>
     <item msgid="8184570120217958741">"Toujours autoriser"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Moyenne"</item>
+    <item msgid="1555861583162930714">"Faible"</item>
+    <item msgid="1719683776264798117">"Critique"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normale"</item>
+    <item msgid="6107138933849816768">"Moyenne"</item>
+    <item msgid="182695359839047859">"Faible"</item>
+    <item msgid="8577246509202964244">"Critique"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Permanent"</item>
     <item msgid="167418068739176448">"Activité principale"</item>
diff --git a/tests/CarDeveloperOptions/res/values-fr/config.xml b/tests/CarDeveloperOptions/res/values-fr/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-fr/config.xml
+++ b/tests/CarDeveloperOptions/res/values-fr/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-fr/strings.xml b/tests/CarDeveloperOptions/res/values-fr/strings.xml
index f243009..2d4038f 100644
--- a/tests/CarDeveloperOptions/res/values-fr/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-fr/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Agrandissez ou réduisez la taille du texte affiché."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Réduire"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Agrandir"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Exemple de texte"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Le Magicien d\'Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Chapitre 11 : La merveilleuse cité d\'émeraude"</string>
@@ -549,7 +548,7 @@
     <string name="setup_lock_settings_picker_title" product="tablet" msgid="2429667472335773519">"Protéger la tablette"</string>
     <string name="setup_lock_settings_picker_title" product="device" msgid="4739290104106645233">"Protéger l\'appareil"</string>
     <string name="setup_lock_settings_picker_title" product="default" msgid="3911582328576859628">"Protégez votre téléphone"</string>
-    <string name="lock_settings_picker_biometrics_added_security_message" msgid="799453282539387294">"Pour plus de sécurité, définissez un mode de verrouillage d\'écran secondaire"</string>
+    <string name="lock_settings_picker_biometrics_added_security_message" msgid="799453282539387294">"Pour plus de sécurité, définissez une méthode secondaire pour verrouiller l\'écran"</string>
     <string name="setup_lock_settings_picker_message" product="tablet" msgid="7230799135599877804">"Activez les fonctionnalités de protection de l\'appareil pour empêcher d\'autres personnes d\'utiliser cette tablette sans votre autorisation. Choisissez la méthode de verrouillage de l\'écran à utiliser."</string>
     <string name="setup_lock_settings_picker_message" product="device" msgid="2098404520816295371">"Activez les fonctionnalités de protection de l\'appareil pour empêcher d\'autres personnes d\'utiliser cet appareil sans votre autorisation. Choisissez la méthode de verrouillage de l\'écran à utiliser."</string>
     <string name="setup_lock_settings_picker_message" product="default" msgid="2003984443953672040">"Activez les fonctionnalités de protection de l\'appareil pour empêcher d\'autres personnes d\'utiliser ce téléphone sans votre autorisation. Choisissez la méthode de verrouillage de l\'écran à utiliser."</string>
@@ -637,7 +636,7 @@
     <string name="unlock_footer_low_complexity_requested" msgid="513212093196833566">"<xliff:g id="APP_NAME">%1$s</xliff:g> recommande d\'utiliser un nouveau schéma, code ou mot de passe et risque de ne pas fonctionner comme prévu si vous n\'en définissez pas"</string>
     <string name="unlock_footer_none_complexity_requested" msgid="1669550050597044896">"<xliff:g id="APP_NAME">%1$s</xliff:g> recommande d\'utiliser un nouveau verrouillage d\'écran"</string>
     <string name="lock_failed_attempts_before_wipe" msgid="7565412834122130877">"Réessayez. Tentative <xliff:g id="CURRENT_ATTEMPTS">%1$d</xliff:g> sur <xliff:g id="TOTAL_ATTEMPTS">%2$d</xliff:g>."</string>
-    <string name="lock_last_attempt_before_wipe_warning_title" msgid="7853820095898368793">"Vos données seront supprimées"</string>
+    <string name="lock_last_attempt_before_wipe_warning_title" msgid="7853820095898368793">"Risque de perte des données"</string>
     <string name="lock_last_pattern_attempt_before_wipe_device" msgid="1021644947949306054">"Si vous dessinez un schéma incorrect lors de la prochaine tentative, les données de cet appareil seront supprimées"</string>
     <string name="lock_last_pin_attempt_before_wipe_device" msgid="3823600293847594141">"Si vous saisissez un code incorrect lors de la prochaine tentative, les données de cet appareil seront supprimées"</string>
     <string name="lock_last_password_attempt_before_wipe_device" msgid="3548966006264835462">"Si vous saisissez un mot de passe incorrect lors de la prochaine tentative, les données de cet appareil seront supprimées"</string>
@@ -668,7 +667,6 @@
       <item quantity="one">Le code doit contenir moins de <xliff:g id="NUMBER_1">%d</xliff:g> chiffre</item>
       <item quantity="other">Le code doit contenir moins de <xliff:g id="NUMBER_1">%d</xliff:g> chiffres</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Le code ne doit comporter que des chiffres compris entre 0 et 9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"L\'administrateur de l\'appareil n\'autorise pas l\'utilisation d\'un code récent"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Les codes courants sont bloqués par votre administrateur informatique. Choisissez un autre code."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Vous ne pouvez pas inclure de caractère non valide."</string>
@@ -699,6 +697,10 @@
       <item quantity="one">Le mot de passe doit comporter au moins <xliff:g id="COUNT">%d</xliff:g> caractère autre qu\'une lettre</item>
       <item quantity="other">Le mot de passe doit comporter au moins <xliff:g id="COUNT">%d</xliff:g> caractères autre qu\'une lettre</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">Doit contenir au moins <xliff:g id="COUNT">%d</xliff:g> caractère non numérique</item>
+      <item quantity="other">Doit contenir au moins <xliff:g id="COUNT">%d</xliff:g> caractères non numériques</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"L\'administrateur de l\'appareil n\'autorise pas l\'utilisation d\'un mot de passe récent"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Les mots de passe courants sont bloqués par votre administrateur informatique. Choisissez un autre mot de passe."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Les suites de chiffres croissantes, décroissantes ou répétitives ne sont pas autorisées"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mobile"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Si le réseau Wi‑Fi n\'est pas disponible, utilisez le réseau mobile"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Si le réseau mobile n\'est pas disponible, utiliser le réseau Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Appel via le Wi-Fi. Si vous perdez le Wi‑Fi, l\'appel se terminera."</string>
@@ -1180,7 +1185,7 @@
     <string name="brightness" msgid="7309120144111305275">"Niveau de luminosité"</string>
     <string name="brightness_title" msgid="5660190946911149690">"Luminosité"</string>
     <string name="brightness_summary" msgid="8687101964451818730">"Régler la luminosité de l\'écran"</string>
-    <string name="auto_brightness_title" msgid="908511534369820426">"Adaptation de la luminosité"</string>
+    <string name="auto_brightness_title" msgid="908511534369820426">"Luminosité adaptative"</string>
     <string name="auto_brightness_summary_on" msgid="121488862610275737">"Activée"</string>
     <string name="auto_brightness_summary_off" msgid="8569141123211510256">"Désactivé"</string>
     <string name="auto_brightness_summary_very_low" msgid="7625647285740629347">"Niveau de luminosité préféré très faible"</string>
@@ -1605,7 +1610,7 @@
     <string name="master_clear_progress_text" msgid="5418958116008976218">"Veuillez patienter..."</string>
     <string name="call_settings_title" msgid="5033906789261282752">"Paramètres d\'appel"</string>
     <string name="call_settings_summary" msgid="2119161087671450035">"Messagerie vocale, transferts d\'appel, mise en attente, numéro de l\'appelant"</string>
-    <string name="tether_settings_title_usb" msgid="4265582654602420357">"Partage connexion Bluetooth par USB"</string>
+    <string name="tether_settings_title_usb" msgid="4265582654602420357">"Partage de connexion via USB"</string>
     <string name="tether_settings_title_wifi" msgid="2060965130234484613">"Point d\'accès Wi-Fi mobile"</string>
     <string name="tether_settings_title_bluetooth" msgid="1999590158102569959">"Partage connexion Bluetooth"</string>
     <string name="tether_settings_title_usb_bluetooth" msgid="1159128764162788159">"Partage de connexion"</string>
@@ -1642,7 +1647,7 @@
     <string name="mobile_insert_sim_card" msgid="7594550403454243732">"Insérez la carte SIM, puis redémarrez."</string>
     <string name="mobile_connect_to_internet" msgid="6031886097365170913">"Connectez-vous à Internet."</string>
     <string name="location_title" msgid="8664674161765477168">"Ma position"</string>
-    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"Emplacement du profil pro"</string>
+    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"Position du profil pro"</string>
     <string name="location_app_level_permissions" msgid="1298041503927632960">"Autorisation des applications"</string>
     <string name="location_app_permission_summary_location_off" msgid="541372845344796336">"La localisation est désactivée"</string>
     <plurals name="location_app_permission_summary_location_on" formatted="false" msgid="7904821382328758218">
@@ -2091,7 +2096,7 @@
     <string name="accessibility_ring_vibration_title" msgid="7943341443551359985">"Vibreur de la sonnerie"</string>
     <string name="accessibility_touch_vibration_title" msgid="285890135612038092">"Vibration au toucher"</string>
     <string name="accessibility_service_master_switch_title" msgid="2734791644475782924">"Utiliser le service"</string>
-    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Corriger les couleurs"</string>
+    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Utiliser la correction des couleurs"</string>
     <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"Utiliser les sous-titres"</string>
     <string name="accessibility_hearingaid_instruction_continue_button" msgid="4650111296711466691">"Continuer"</string>
     <string name="accessibility_hearingaid_title" msgid="3700978781235124891">"Appareils auditifs"</string>
@@ -2447,7 +2452,7 @@
     <string name="battery_saver_auto_routine" msgid="886514412067906980">"En fonction de vos habitudes"</string>
     <string name="battery_saver_auto_percentage" msgid="5791982309331921556">"En fonction du pourcentage de batterie"</string>
     <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"L\'économiseur de batterie s\'activera si l\'autonomie restante risque d\'être insuffisante pour tenir jusqu\'au moment où vous mettez généralement votre téléphone en charge"</string>
-    <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"S\'activera à <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
+    <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"S\'active à <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"Paramétrer l\'économiseur de batterie"</string>
     <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"Désactiver une fois la batterie complètement chargée"</string>
     <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"L\'économiseur de batterie se désactive lorsque votre téléphone atteint un niveau de charge de <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
@@ -2461,7 +2466,7 @@
     <string name="battery_saver_turn_on_automatically_never" msgid="2623381258359775227">"Jamais"</string>
     <string name="battery_saver_turn_on_automatically_pct" msgid="434270432432390307">"niveau de la batterie : <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <string name="battery_percentage" msgid="7782252476471033843">"Pourcentage de la batterie"</string>
-    <string name="battery_percentage_description" msgid="9219875229166700610">"Afficher le pourcentage de la batterie dans la barre d\'état"</string>
+    <string name="battery_percentage_description" msgid="9219875229166700610">"Afficher dans la barre d\'état"</string>
     <string name="process_stats_summary_title" msgid="9189588417488537954">"Statistiques relatives aux processus"</string>
     <string name="process_stats_summary" msgid="8077998499161221885">"Statistiques détaillées relatives aux processus en cours d\'exécution"</string>
     <string name="app_memory_use" msgid="5126237308545653706">"Utilisation de la mémoire"</string>
@@ -2920,7 +2925,7 @@
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Sauf si une autre application de paiement est ouverte"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"Application à utiliser pour le paiement sans contact :"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Paiement à un terminal"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Configurez une application de paiement. Il suffit ensuite de poser l\'arrière de votre téléphone sur n\'importe quel terminal disposant du symbole Sans contact."</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Configurez une application de paiement. Il suffit ensuite d\'approcher l\'arrière de votre appareil de n\'importe quel terminal disposant du symbole Sans contact."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"OK"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"Plus..."</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"Définir comme mode de paiement prioritaire ?"</string>
@@ -3303,11 +3308,11 @@
     <string name="notification_badging_title" msgid="6311699476970264712">"Autoriser les pastilles de notification"</string>
     <string name="notification_bubbles_title" msgid="9196562435741861317">"Bulles"</string>
     <string name="notification_bubbles_summary" msgid="4624512775901949578">"Accéder rapidement au contenu des applications grâce aux raccourcis flottants"</string>
-    <string name="bubbles_feature_education" msgid="8979109826818881018">"Certaines notifications ainsi que d\'autres contenus peuvent s\'afficher à l\'écran sous forme de bulles. Pour ouvrir une bulle, appuyez dessus. Pour l\'ignorer, faites-la glisser vers le bas de l\'écran."</string>
+    <string name="bubbles_feature_education" msgid="8979109826818881018">"Certaines notifications et d\'autres contenus peuvent s\'afficher à l\'écran sous forme de bulles. Pour ouvrir une bulle, appuyez dessus. Pour l\'ignorer, faites-la glisser vers le bas de l\'écran."</string>
     <string name="bubbles_app_toggle_title" msgid="6401217027603326439">"Bulles"</string>
     <string name="bubbles_app_toggle_summary" msgid="7707611139796553855">"Autoriser <xliff:g id="APP_NAME">%1$s</xliff:g> à afficher certaines notifications sous forme de bulles"</string>
     <string name="bubbles_feature_disabled_dialog_title" msgid="3375452386012079293">"Activer les bulles"</string>
-    <string name="bubbles_feature_disabled_dialog_text" msgid="326945485806386477">"Avant d\'activer les bulles pour cette application, vous devez les activer pour votre appareil. Ceci a une incidence sur les autres applications dans lesquelles vous avez déjà activé les bulles."</string>
+    <string name="bubbles_feature_disabled_dialog_text" msgid="326945485806386477">"Pour activer les bulles dans cette application, vous devez d\'abord les activer pour votre appareil. Ceci a une incidence sur les autres applications dans lesquelles vous avez déjà activé les bulles."</string>
     <string name="bubbles_feature_disabled_button_approve" msgid="6661464849674493351">"Activer pour l\'appareil"</string>
     <string name="bubbles_feature_disabled_button_cancel" msgid="4807286844588486198">"Annuler"</string>
     <string name="swipe_direction_title" msgid="7535031630668873009">"Actions associées au balayage"</string>
@@ -3515,7 +3520,7 @@
     <string name="zen_mode_starred_callers" msgid="1317376207713013472">"contacts favoris"</string>
     <string name="zen_mode_repeat_callers" msgid="1435309867554692340">"Appels répétés"</string>
     <string name="zen_mode_repeat_callers_list" msgid="2750270907597457279">"appelants fréquents"</string>
-    <string name="zen_mode_repeat_callers_title" msgid="7192952181541813487">"Autoriser les appelants fréquents"</string>
+    <string name="zen_mode_repeat_callers_title" msgid="7192952181541813487">"Autoriser les appels répétés"</string>
     <string name="zen_mode_calls_summary_one" msgid="8327371053236689649">"Autoriser les appels de <xliff:g id="CALLER_TYPE">%1$s</xliff:g>"</string>
     <string name="zen_mode_calls_summary_two" msgid="9017678770532673578">"Autoriser les appels de <xliff:g id="CALLER_TYPE">%1$s</xliff:g> et <xliff:g id="CALLERT_TPYE">%2$s</xliff:g>"</string>
     <string name="zen_mode_repeat_callers_summary" msgid="1752513516040525545">"Si la même personne appelle deux fois en <xliff:g id="MINUTES">%d</xliff:g> minutes"</string>
@@ -3997,7 +4002,7 @@
     <string name="suggestion_additional_fingerprints" msgid="3434467207282466411">"Ajouter une empreinte digitale"</string>
     <string name="suggestion_additional_fingerprints_summary" msgid="1916547587832484196">"Déverrouiller avec un autre doigt"</string>
     <string name="battery_saver_on_summary" msgid="6841062406467435672">"Activé"</string>
-    <string name="battery_saver_off_scheduled_summary" msgid="3740414764069188669">"Activer à <xliff:g id="BATTERY_PERCENTAGE">%1$s</xliff:g>"</string>
+    <string name="battery_saver_off_scheduled_summary" msgid="3740414764069188669">"S\'active à <xliff:g id="BATTERY_PERCENTAGE">%1$s</xliff:g>"</string>
     <string name="battery_saver_off_summary" msgid="8736555723004299721">"Désactivé"</string>
     <string name="battery_saver_button_turn_on" msgid="3748696527267573793">"Activer maintenant"</string>
     <string name="battery_saver_button_turn_off" msgid="2912950982503267828">"Désactiver maintenant"</string>
@@ -4126,7 +4131,7 @@
     <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"Pour afficher l\'heure, les notifications et d\'autres informations, saisissez votre téléphone."</string>
     <string name="ambient_display_pickup_summary" product="tablet" msgid="1077745287100012928">"Pour afficher l\'heure, les notifications et d\'autres informations, saisissez votre tablette."</string>
     <string name="ambient_display_pickup_summary" product="device" msgid="404199660076598026">"Pour afficher l\'heure, les notifications et d\'autres informations, saisissez votre appareil."</string>
-    <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"Appuyer pour vérifier le téléphone"</string>
+    <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"Appuyer pour consulter le téléphone"</string>
     <string name="ambient_display_tap_screen_title" product="tablet" msgid="6434521782016864148">"Appuyer pour vérifier la tablette"</string>
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"Appuyer pour vérifier l\'appareil"</string>
     <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"Pour afficher l\'heure, les notifications et d\'autres informations, appuyez sur l\'écran."</string>
diff --git a/tests/CarDeveloperOptions/res/values-gl/arrays.xml b/tests/CarDeveloperOptions/res/values-gl/arrays.xml
index 905bdc7..b3e835e 100644
--- a/tests/CarDeveloperOptions/res/values-gl/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-gl/arrays.xml
@@ -38,7 +38,16 @@
     <item msgid="5827960506924849753">"10 minutos"</item>
     <item msgid="6677424950124253938">"30 minutos"</item>
   </string-array>
-    <!-- no translation found for dream_timeout_entries:7 (8271452751594598661) -->
+  <string-array name="dream_timeout_entries">
+    <item msgid="6487043225269853023">"Nunca"</item>
+    <item msgid="2517785806387977252">"15 segundos"</item>
+    <item msgid="6347954399441173672">"30 segundos"</item>
+    <item msgid="4858305253279921789">"1 minuto"</item>
+    <item msgid="8109273437140044073">"2 minutos"</item>
+    <item msgid="2788593551142462622">"5 minutos"</item>
+    <item msgid="8012672183888404961">"10 minutos"</item>
+    <item msgid="8271452751594598661">"30 minutos"</item>
+  </string-array>
   <string-array name="lock_after_timeout_entries">
     <item msgid="2232921187970351881">"Inmediatamente"</item>
     <item msgid="2038544972632026612">"5 segundos"</item>
@@ -50,17 +59,47 @@
     <item msgid="811192536981678974">"10 minutos"</item>
     <item msgid="7258394417241706272">"30 minutos"</item>
   </string-array>
-    <!-- no translation found for entries_font_size:0 (2340391964816059553) -->
-    <!-- no translation found for entries_font_size:0 (6490061470416867723) -->
-    <!-- no translation found for entries_font_size:2 (1714184661981538355) -->
-    <!-- no translation found for entries_font_size:2 (1678068858001018666) -->
-    <!-- no translation found for wifi_status:3 (5848277343965362748) -->
-    <!-- no translation found for wifi_status_with_ssid:1 (6816207058895999545) -->
-    <!-- no translation found for wifi_status_with_ssid:3 (7547609081339573756) -->
-    <!-- no translation found for wifi_status_with_ssid:4 (5145158315060185414) -->
+  <string-array name="entries_font_size">
+    <item msgid="2340391964816059553">"Pequeno"</item>
+    <item msgid="591935967183159581">"Predeterminado"</item>
+    <item msgid="1714184661981538355">"Grande"</item>
+    <item msgid="6195563047686707484">"O máis grande"</item>
+  </string-array>
+  <string-array name="wifi_status">
+    <item msgid="1304883790721412351"></item>
+    <item msgid="4157625910392775808">"Buscando..."</item>
+    <item msgid="5597394826455877834">"Conectando..."</item>
+    <item msgid="5848277343965362748">"Autenticando…"</item>
+    <item msgid="3391238031431440676">"Obtendo enderezo IP..."</item>
+    <item msgid="5257597310494000224">"Rede conectada"</item>
+    <item msgid="8472497592913050396">"Suspendido"</item>
+    <item msgid="1228072488815999109">"Desconectando..."</item>
+    <item msgid="7253087004422991731">"Desconectado"</item>
+    <item msgid="4169850917304751227">"Incorrecto"</item>
+    <item msgid="6266658166690831131">"Bloqueada"</item>
+    <item msgid="4517230805854909775">"Evitando conexión deficiente temporalmente"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="4853670665485437464"></item>
+    <item msgid="6816207058895999545">"Buscando…"</item>
+    <item msgid="8058143476674427024">"Conectando con <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7547609081339573756">"Autenticándose na rede (<xliff:g id="NETWORK_NAME">%1$s</xliff:g>)…"</item>
+    <item msgid="5145158315060185414">"Obtendo enderezo IP da rede (<xliff:g id="NETWORK_NAME">%1$s</xliff:g>)…"</item>
+    <item msgid="3283243151651124831">"Conectado a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="6600156231416890902">"Suspendido"</item>
+    <item msgid="4133290864821295785">"Desconectando de <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="3980154971187953257">"Desconectado"</item>
+    <item msgid="2847316776634969068">"Incorrecto"</item>
+    <item msgid="4390990424746035383">"Bloqueada"</item>
+    <item msgid="3618248791367063949">"Evitando conexión deficiente temporalmente"</item>
+  </string-array>
     <!-- no translation found for wifi_tether_security:0 (5586343370515598801) -->
     <!-- no translation found for wifi_tether_security:1 (6136336549994615745) -->
-    <!-- no translation found for wifi_p2p_wps_setup:0 (5390235347963255303) -->
+  <string-array name="wifi_p2p_wps_setup">
+    <item msgid="5390235347963255303">"Preme o botón"</item>
+    <item msgid="7401896200768713930">"PIN do dispositivo mesmo nivel"</item>
+    <item msgid="4526848028011846710">"PIN do dispositivo"</item>
+  </string-array>
   <string-array name="wifi_p2p_status">
     <item msgid="8741947238021758201">"Rede conectada"</item>
     <item msgid="983792611851499732">"Invitado"</item>
@@ -82,8 +121,13 @@
     <item msgid="1644506614010085798">"4"</item>
     <item msgid="3132506679404897150">"5"</item>
   </string-array>
-    <!-- no translation found for wifi_signal:1 (7882129634982603782) -->
-    <!-- no translation found for wifi_signal:4 (999948812884919584) -->
+  <string-array name="wifi_signal">
+    <item msgid="1709949377823900951">"Baixa"</item>
+    <item msgid="7882129634982603782">"Baixa"</item>
+    <item msgid="6457357501905996224">"Aceptable"</item>
+    <item msgid="405271628162918841">"Boa"</item>
+    <item msgid="999948812884919584">"Excelente"</item>
+  </string-array>
   <string-array name="data_usage_data_range">
     <item msgid="8986775481492954015">"Últimos 30 días"</item>
     <item msgid="3211287705232736964">"Definir ciclo de uso..."</item>
@@ -119,7 +163,10 @@
     <item msgid="7330627471456865502">"MSCHAPV2"</item>
     <item msgid="6255179395132581882">"GTC"</item>
   </string-array>
-    <!-- no translation found for wifi_ip_settings:1 (4377002609760712163) -->
+  <string-array name="wifi_ip_settings">
+    <item msgid="2717196390555072244">"DHCP"</item>
+    <item msgid="4377002609760712163">"Estático"</item>
+  </string-array>
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"Ningunha"</item>
     <item msgid="1464741437353223198">"Manual"</item>
@@ -239,11 +286,73 @@
     <item msgid="1165623660533024666">"executar en segundo plano"</item>
     <item msgid="6423861043647911030">"volume de accesibilidade"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:3 (7836406246005211990) -->
-    <!-- no translation found for app_ops_labels:4 (3951439024549922598) -->
-    <!-- no translation found for app_ops_labels:8 (3597797992398484655) -->
-    <!-- no translation found for app_ops_labels:20 (3037159047591081136) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Localización"</item>
+    <item msgid="6656077694190491067">"Localización"</item>
+    <item msgid="8790228218278477369">"Localización"</item>
+    <item msgid="7836406246005211990">"Vibrar"</item>
+    <item msgid="3951439024549922598">"Ler contactos"</item>
+    <item msgid="8802152411647068">"Modificar contactos"</item>
+    <item msgid="229544934599698735">"Ler rexistro de chamadas"</item>
+    <item msgid="7396102294405899613">"Modificar rexistro de chamadas"</item>
+    <item msgid="3597797992398484655">"Ler calendario"</item>
+    <item msgid="2705975774250907343">"Modificar calendario"</item>
+    <item msgid="4668747371441932697">"Localización"</item>
+    <item msgid="1487578921720243646">"Notificación de publicación"</item>
+    <item msgid="4636080349724146638">"Localización"</item>
+    <item msgid="673510900286463926">"Chamada telefónica"</item>
+    <item msgid="542083422784609790">"Ler SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Escribir SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Recibir SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Recibir SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Recibir SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Recibir SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Enviar SMS/MMS"</item>
+    <item msgid="4726682243833913568">"Ler SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Escribir SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Modificar configuración"</item>
+    <item msgid="8705854389991425629">"Debuxar na parte superior"</item>
+    <item msgid="5861356020344153651">"Acceso ás notificacións"</item>
+    <item msgid="78432174621628659">"Cámara"</item>
+    <item msgid="3986116419882154794">"Gravar audio"</item>
+    <item msgid="4516840825756409490">"Reproducir audio"</item>
+    <item msgid="6811712502798183957">"Ler portapapeis"</item>
+    <item msgid="2780369012602289114">"Modificar portapapeis"</item>
+    <item msgid="2331359440170850868">"Botóns multimedia"</item>
+    <item msgid="6133599737122751231">"Enfoque de audio"</item>
+    <item msgid="6844485713404805301">"Volume principal"</item>
+    <item msgid="1600379420669104929">"Volume da voz"</item>
+    <item msgid="6296768210470214866">"Volume do ton"</item>
+    <item msgid="510690696071629241">"Volume dos elementos multimedia"</item>
+    <item msgid="406861638631430109">"Volume da alarma"</item>
+    <item msgid="4715864795872233884">"Volume das notificacións"</item>
+    <item msgid="2311478519251301183">"Volume do Bluetooth"</item>
+    <item msgid="5133991377896747027">"Activo"</item>
+    <item msgid="2464189519136248621">"Localización"</item>
+    <item msgid="2062677934050803037">"Localización"</item>
+    <item msgid="1735171933192715957">"Obter estatísticas de uso"</item>
+    <item msgid="1014093788778383554">"Desactivar/activar o son do micrófono"</item>
+    <item msgid="4199297950608622850">"Mostrar notificación emerxente"</item>
+    <item msgid="2527962435313398821">"Multimedia do proxecto"</item>
+    <item msgid="5117506254221861929">"Activar VPN"</item>
+    <item msgid="8291198322681891160">"Fondo de pantalla de escritura"</item>
+    <item msgid="7106921284621230961">"Estrutura do asistente"</item>
+    <item msgid="4496533640894624799">"Captura de pantalla do asistente"</item>
+    <item msgid="2598847264853993611">"Ler estado do teléfono"</item>
+    <item msgid="9215610846802973353">"Engadir correo de voz"</item>
+    <item msgid="9186411956086478261">"Usar SIP"</item>
+    <item msgid="6884763100104539558">"Procesar chamada saínte"</item>
+    <item msgid="125513972170580692">"Impresión dixital"</item>
+    <item msgid="2556071024281275619">"Sensores corporais"</item>
+    <item msgid="617168514928339387">"Ler difusións de cela"</item>
+    <item msgid="7134693570516523585">"Localización falsa"</item>
+    <item msgid="7224489175375229399">"Ler almacenamento"</item>
+    <item msgid="8472735063903258202">"Escribir almacenamento"</item>
+    <item msgid="4069276819909595110">"Activar pantalla"</item>
+    <item msgid="1228338896751121025">"Obter contas"</item>
+    <item msgid="3181581793459233672">"Executar en segundo plano"</item>
+    <item msgid="2340936043025374076">"Volume de accesibilidade"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Curto"</item>
     <item msgid="4816511817309094890">"Media"</item>
@@ -260,7 +369,13 @@
     <item msgid="4627069151979553527">"Cursiva"</item>
     <item msgid="6896773537705206194">"Versaleta"</item>
   </string-array>
-    <!-- no translation found for captioning_font_size_selector_titles:3 (2784236342175159295) -->
+  <string-array name="captioning_font_size_selector_titles">
+    <item msgid="1680223634161592855">"Moi pequeno"</item>
+    <item msgid="5091603983404027034">"Pequeno"</item>
+    <item msgid="176844712416932112">"Normal"</item>
+    <item msgid="2784236342175159295">"Grande"</item>
+    <item msgid="218913203203160606">"Moi grande"</item>
+  </string-array>
   <string-array name="captioning_edge_type_selector_titles">
     <item msgid="3865198759294188069">"Predeterminado"</item>
     <item msgid="6488643537808152001">"Ningunha"</item>
@@ -275,7 +390,14 @@
     <item msgid="1874668269931014581">"75%"</item>
     <item msgid="6462911487571123954">"100 %"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"Usar config. predet. da aplicación"</item>
+    <item msgid="8611890312638868524">"Branco sobre negro"</item>
+    <item msgid="5891360837786277638">"Negro sobre branco"</item>
+    <item msgid="2798457065945456853">"Amarelo sobre negro"</item>
+    <item msgid="5799049811524553967">"Amarelo sobre azul"</item>
+    <item msgid="3673930830658169860">"Personalizados"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"VPN PPTP"</item>
     <item msgid="1349760781118368659">"VPN L2TP/IPSec con claves precompartidas"</item>
@@ -288,15 +410,32 @@
     <item msgid="2958623927055120839">"Ningún"</item>
     <item msgid="1157046369795346308">"Manual"</item>
   </string-array>
-    <!-- no translation found for vpn_states:4 (9135049670787351881) -->
+  <string-array name="vpn_states">
+    <item msgid="5408915841694583740">"Desconectado"</item>
+    <item msgid="8754480102834556765">"Inicializando..."</item>
+    <item msgid="3351334355574270250">"Conectando..."</item>
+    <item msgid="8303882153995748352">"Rede conectada"</item>
+    <item msgid="9135049670787351881">"Tempo de espera"</item>
+    <item msgid="2124868417182583926">"Incorrecto"</item>
+  </string-array>
   <string-array name="security_settings_premium_sms_values">
     <item msgid="1164265643455394443">"Preguntar"</item>
     <item msgid="7718817231348607934">"Non permitir nunca"</item>
     <item msgid="8184570120217958741">"Permitir sempre"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Moderada"</item>
+    <item msgid="1555861583162930714">"Baixa"</item>
+    <item msgid="1719683776264798117">"Crítico"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normal"</item>
+    <item msgid="6107138933849816768">"Moderado"</item>
+    <item msgid="182695359839047859">"Baixa"</item>
+    <item msgid="8577246509202964244">"Crítico"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Persistente"</item>
     <item msgid="167418068739176448">"Actividade principal"</item>
diff --git a/tests/CarDeveloperOptions/res/values-gl/config.xml b/tests/CarDeveloperOptions/res/values-gl/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-gl/config.xml
+++ b/tests/CarDeveloperOptions/res/values-gl/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-gl/strings.xml b/tests/CarDeveloperOptions/res/values-gl/strings.xml
index 7c516e0..51e5d0c 100644
--- a/tests/CarDeveloperOptions/res/values-gl/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-gl/strings.xml
@@ -80,11 +80,10 @@
     <string name="sdcard_format" product="default" msgid="4831611387627849108">"Borrar tarxeta SD"</string>
     <string name="preview_pager_content_description" msgid="5731599395893090038">"Vista previa"</string>
     <string name="preview_page_indicator_content_description" msgid="3192955679074998362">"Vista previa, páxina <xliff:g id="CURRENT_PAGE">%1$d</xliff:g> de <xliff:g id="NUM_PAGES">%2$d</xliff:g>"</string>
-    <string name="font_size_summary" msgid="9120023206321191067">"Reduce ou amplía o texto da pantalla."</string>
+    <string name="font_size_summary" msgid="9120023206321191067">"Reduce ou amplía o tamaño do texto na pantalla."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Reducir"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Ampliar"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Texto de mostra"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"O marabilloso mago de Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Capítulo 11: A marabillosa Cidade Esmeralda de Oz"</string>
@@ -448,7 +447,7 @@
     <string name="security_settings_fingerprint_enroll_introduction_cancel_setup" msgid="756928427429893070">"Omitir"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue_setup" msgid="4125977169169671144">"Seguinte"</string>
     <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"Omitir a impresión dixital?"</string>
-    <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"Configurar a impresión dixital só leva un ou dous minutos, pero tamén podes facelo más tarde en Configuración."</string>
+    <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"Configurar a impresión dixital só leva un ou dous minutos, pero tamén podes facelo máis tarde en Configuración."</string>
     <string name="lock_screen_intro_skip_title" msgid="5307431665496346914">"Omitir o bloqueo de pantalla?"</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="tablet" msgid="7553945981266845264">"As funcións de protección do dispositivo non se activarán. Non poderás evitar que outros usuarios utilicen a tableta en caso de perda, roubo ou restablecemento"</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="device" msgid="1378243257238015603">"As funcións de protección do dispositivo non se activarán. Non poderás evitar que outros usuarios o utilicen en caso de perda, roubo ou restablecemento."</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Debe conter menos de <xliff:g id="NUMBER_1">%d</xliff:g> díxitos</item>
       <item quantity="one">Debe conter menos de <xliff:g id="NUMBER_0">%d</xliff:g> díxito</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Só pode conter díxitos comprendidos entre o 0 e o 9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"O administrador de dispositivos non permite o uso dun PIN recente"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"O teu administrador de TI bloqueou os PIN comúns. Proba cun PIN diferente."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Non pode conter un carácter non válido"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Debe conter polo menos <xliff:g id="COUNT">%d</xliff:g> caracteres que non sexan letras</item>
       <item quantity="one">Debe conter polo menos 1 carácter que non sexa unha letra</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Debe conter polo menos <xliff:g id="COUNT">%d</xliff:g> caracteres que non sexan números</item>
+      <item quantity="one">Debe conter polo menos 1 carácter que non sexa un número</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"O administrador de dispositivos non permite o uso dun contrasinal recente"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"O teu administrador de TI bloqueou os contrasinais comúns. Proba cun contrasinal diferente."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Non se permite unha secuencia de díxitos ascendente, descendente nin repetida"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wifi"</item>
+    <item msgid="2271962426654621656">"Datos móbiles"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Se non hai ningunha rede wifi dispoñible, utilizar a rede móbil"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Se a rede de telefonía móbil non está dispoñible, utiliza a wifi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Chama por wifi. Se se perde a conexión wifi, a chamada rematará."</string>
@@ -1170,7 +1175,7 @@
     <string name="color_mode_option_natural" msgid="1292837781836645320">"Naturais"</string>
     <string name="color_mode_option_boosted" msgid="453557938434778933">"Realzadas"</string>
     <string name="color_mode_option_saturated" msgid="7758384943407859851">"Saturadas"</string>
-    <string name="color_mode_option_automatic" msgid="6572718611315165117">"Automática"</string>
+    <string name="color_mode_option_automatic" msgid="6572718611315165117">"Automáticas"</string>
     <string name="color_mode_summary_natural" msgid="1247153893843263340">"Utiliza só cores precisas"</string>
     <string name="color_mode_summary_automatic" msgid="6066740785261330514">"Axuste entre cores vivas e precisas"</string>
     <string name="accelerometer_summary_on" product="tablet" msgid="5750977897791656412">"Cambia a orientación automaticamente ao xirar a tableta"</string>
@@ -1207,9 +1212,9 @@
     <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"A función Pantalla adaptable utiliza a cámara dianteira para ver se alguén está mirando a pantalla. Funciona no dispositivo e as imaxes nunca se almacenan nin envían a Google."</string>
     <string name="night_display_title" msgid="1305002424893349814">"Luz nocturna"</string>
     <string name="night_display_text" msgid="5330502493684652527">"A función Luz nocturna dálle un ton ámbar á pantalla pola noite para que che resulte máis fácil mirala con pouca luz e che axude a coller o sono."</string>
-    <string name="night_display_auto_mode_title" msgid="8493573087102481588">"Planificar"</string>
+    <string name="night_display_auto_mode_title" msgid="8493573087102481588">"Planificación"</string>
     <string name="night_display_auto_mode_never" msgid="2897444637217807088">"Nunca"</string>
-    <string name="night_display_auto_mode_custom" msgid="1400891076453963151">"Actívase en horario personalizado"</string>
+    <string name="night_display_auto_mode_custom" msgid="1400891076453963151">"Actívase no horario escollido"</string>
     <string name="night_display_auto_mode_twilight" msgid="4000162110017520674">"Actívase do solpor ao amencer"</string>
     <string name="night_display_start_time_title" msgid="1069255169673371077">"Hora de inicio"</string>
     <string name="night_display_end_time_title" msgid="2760793157124245911">"Hora de finalización"</string>
@@ -1762,7 +1767,7 @@
     <string name="lockpattern_settings_enable_visible_pattern_title" msgid="4935583222709647096">"Facer visible o padrón"</string>
     <string name="lockpattern_settings_enable_visible_pattern_title_profile" msgid="5338893138982642228">"Facer visible o padrón do perfil"</string>
     <string name="lockpattern_settings_enable_tactile_feedback_title" msgid="3203621862806531947">"Vibrar ao tocar"</string>
-    <string name="lockpattern_settings_enable_power_button_instantly_locks" msgid="5890335732200257777">"Bloquear ao acender"</string>
+    <string name="lockpattern_settings_enable_power_button_instantly_locks" msgid="5890335732200257777">"Bloquear co botón de acender"</string>
     <string name="lockpattern_settings_power_button_instantly_locks_summary" msgid="1279989004145567840">"Excepto se <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g> mantén o dispositivo desbloqueado"</string>
     <string name="lockpattern_settings_choose_lock_pattern" msgid="9042142745571386381">"Definir padrón de desbloqueo"</string>
     <string name="lockpattern_settings_change_lock_pattern" msgid="1456643060737114885">"Cambiar padrón de desbloqueo"</string>
@@ -1793,7 +1798,7 @@
     <string name="install_all_warning" product="device" msgid="9141585291103603515">"O teu dispositivo e os datos persoais son máis vulnerables aos ataques de aplicacións descoñecidas. Ao instalar aplicacións desta fonte, aceptas que es responsable dos danos que se poidan producir no dispositivo ou da perda de datos que se poida derivar do seu uso."</string>
     <string name="advanced_settings" msgid="6282069364060968122">"Configuración avanzada"</string>
     <string name="advanced_settings_summary" msgid="5912237062506771716">"Activa máis opcións de configuración"</string>
-    <string name="application_info_label" msgid="3886253474964599105">"Info da app"</string>
+    <string name="application_info_label" msgid="3886253474964599105">"Información das aplicacións"</string>
     <string name="storage_label" msgid="1109537840103290384">"Almacenamento"</string>
     <string name="auto_launch_label" msgid="47089737922907379">"Abrir de forma predeterminada"</string>
     <string name="auto_launch_label_generic" msgid="7865828543459493308">"Valores predeterminados"</string>
@@ -2056,7 +2061,7 @@
     <string name="accessibility_screen_magnification_summary" msgid="3363006902079431772"><b>"Para achegar o zoom"</b>", toca a pantalla 3 veces rapidamente.\n"<ul><li>"Arrastra 2 ou máis dedos para desprazarte"</li>\n<li>"Belisca con 2 ou máis dedos para axustar o zoom"</li></ul>\n\n<b>"Para achegar o zoom temporalmente"</b>", toca a pantalla 3 veces rapidamente e mantén o dedo sobre a pantalla despois do terceiro toque.\n"<ul><li>"Arrastra o dedo para moverte pola pantalla"</li>\n<li>"Levántao para afastar o zoom"</li></ul>\n\n"Non podes achegar o zoom sobre o teclado nin sobre a barra de navegación."</string>
     <string name="accessibility_screen_magnification_navbar_summary" msgid="4726360285256503132">"Cando a ampliación estea activada, utiliza o botón Accesibilidade da parte inferior da pantalla para ampliar rapidamente o contido.\n\n"<b>"Para achegar o zoom"</b>", toca o botón Accesibilidade e, a continuación, toca en calquera parte da pantalla.\n"<ul><li>"Arrastra 2 ou máis dedos para desprazarte"</li>\n<li>"Belisca con 2 ou máis dedos para axustar o zoom"</li></ul>\n\n<b>"Para achegar o zoom temporalmente"</b>", toca o botón Accesibilidade e, a continuación, mantén tocada calquera parte da pantalla.\n"<ul><li>"Arrastra o dedo para moverte pola pantalla"</li>\n<li>"Levántao para afastar o zoom"</li></ul>\n\n"Non podes achegar o zoom sobre o teclado nin sobre a barra de navegación."</string>
     <string name="accessibility_screen_magnification_navbar_configuration_warning" msgid="6477234309484795550">"O botón Accesibilidade está configurado en <xliff:g id="SERVICE">%1$s</xliff:g>. Para utilizar a ampliación, mantén tocado o botón Accesibilidade e, a continuación, selecciona a ampliación."</string>
-    <string name="accessibility_global_gesture_preference_title" msgid="3842279082831426816">"Atallo mediante as teclas de volume"</string>
+    <string name="accessibility_global_gesture_preference_title" msgid="3842279082831426816">"Atallo da tecla de volume"</string>
     <string name="accessibility_shortcut_service_title" msgid="3516052294376744060">"Servizo de atallo"</string>
     <string name="accessibility_shortcut_service_on_lock_screen_title" msgid="1279441617927949980">"Permitir na pantalla bloqueo"</string>
     <string name="accessibility_shortcut_description" msgid="1427049334225166395">"Cando o atallo está activado, podes premer as dúas teclas de volume durante 3 segundos para iniciar unha función de accesibilidade."</string>
@@ -2157,7 +2162,7 @@
     <string name="captioning_edge_color" msgid="4330622137047993780">"Cor do bordo"</string>
     <string name="captioning_edge_type" msgid="4414946407430588162">"Tipo de bordo"</string>
     <string name="captioning_typeface" msgid="7893208796949341767">"Familia do tipo de letra"</string>
-    <string name="captioning_preview_text" msgid="4877753964772618049">"Os subtítulos terán un aspecto similar ao seguinte"</string>
+    <string name="captioning_preview_text" msgid="4877753964772618049">"Os subtítulos veranse así"</string>
     <string name="captioning_preview_characters" msgid="6469599599352973561">"Aa"</string>
     <string name="locale_default" msgid="910074908458214054">"Predeterminado"</string>
     <string name="color_title" msgid="132875486061816584">"Cor"</string>
@@ -2293,8 +2298,8 @@
       <item quantity="one">Restrinxiuse recentemente a aplicación %1$s</item>
     </plurals>
     <plurals name="battery_tip_restrict_summary" formatted="false" msgid="984148373944071669">
-      <item quantity="other">%2$d aplicacións utilizan moita batería en segundo plano</item>
-      <item quantity="one">A aplicación %1$s utiliza moita batería en segundo plano</item>
+      <item quantity="other">%2$d apps usan moita batería en segundo plano</item>
+      <item quantity="one">%1$s usa moita batería en segundo plano</item>
     </plurals>
     <plurals name="battery_tip_restrict_handled_summary" formatted="false" msgid="469696766640020557">
       <item quantity="other">Estas aplicacións non se poden executar en segundo plano</item>
@@ -2444,7 +2449,7 @@
     <string name="battery_saver" msgid="3989710213758938398">"Aforro de batería"</string>
     <string name="battery_saver_auto_title" msgid="4158659069641849952">"Activar automaticamente"</string>
     <string name="battery_saver_auto_no_schedule" msgid="739814529432092706">"Sen planificación"</string>
-    <string name="battery_saver_auto_routine" msgid="886514412067906980">"Baseada na túa rutina"</string>
+    <string name="battery_saver_auto_routine" msgid="886514412067906980">"Segundo a túa rutina"</string>
     <string name="battery_saver_auto_percentage" msgid="5791982309331921556">"Baseada nunha porcentaxe"</string>
     <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"A función Aforro de batería actívase se se prevé que a batería pode esgotarse antes da seguinte carga. Esta estimación realízase a partir da rutina que segues habitualmente"</string>
     <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"Activarase cando a batería estea ao <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
@@ -2601,8 +2606,7 @@
     <string name="background_data_summary" msgid="799640633948841990">"Aplicacións poden sincronizar, enviar e recibir datos sempre"</string>
     <string name="background_data_dialog_title" msgid="8306650658158895976">"Des. datos 2º plano?"</string>
     <string name="background_data_dialog_message" msgid="8126774244911656527">"A desactivación dos datos en segundo plano amplía a duración da batería e reduce o uso de datos. É posible que algunhas aplicacións continúen utilizando a conexión de datos en segundo plano."</string>
-    <!-- no translation found for sync_automatically (5746117156896468099) -->
-    <skip />
+    <string name="sync_automatically" msgid="5746117156896468099">"Sincronizar automat. datos das apps"</string>
     <string name="sync_enabled" msgid="535172627223336983">"Sincronización activada"</string>
     <string name="sync_disabled" msgid="713721807204805062">"Sen sincronización"</string>
     <string name="sync_error" msgid="988155155932442765">"Erro de sincronización"</string>
@@ -2912,7 +2916,7 @@
     <string name="apps_with_restrictions_settings_button" msgid="5065896213467171744">"Ampliar axustes aplicación"</string>
     <string name="nfc_payment_settings_title" msgid="5070077706735415291">"Tocar e pagar"</string>
     <string name="nfc_payment_how_it_works" msgid="7607901964687787177">"Como funciona"</string>
-    <string name="nfc_payment_no_apps" msgid="8844440783395420860">"Paga co teu teléfono nas tendas"</string>
+    <string name="nfc_payment_no_apps" msgid="8844440783395420860">"Paga co teléfono nas tendas"</string>
     <string name="nfc_payment_default" msgid="7869273092463612271">"Aplicación de pago predeterminada"</string>
     <string name="nfc_payment_default_not_set" msgid="955804193510335338">"Sen configurar"</string>
     <string name="nfc_payment_app_and_desc" msgid="102312684211458190">"<xliff:g id="APP">%1$s</xliff:g> - <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
@@ -3197,7 +3201,7 @@
     <string name="zen_mode_restrict_notifications_mute_footer" msgid="3049522809520549054">"O teléfono non vibrará nin emitirá sons cando cheguen notificacións."</string>
     <string name="zen_mode_restrict_notifications_hide" msgid="3296933643539682552">"Notificacións sen son nin elementos visuais"</string>
     <string name="zen_mode_restrict_notifications_hide_summary" msgid="1449301153755270168">"Non verás nin escoitarás notificacións"</string>
-    <string name="zen_mode_restrict_notifications_hide_footer" msgid="7617688597593946765">"O teléfono non mostrará notificacións, nin vibrará nin emitirá sons con notificacións novas ou existentes. Ten en conta que se seguirán mostrando as notificacións esenciais para o estado e a actividade do teléfono.\n\nCando desactives o modo Non molestar, poderás pasar o dedo cara abaixo desde a parte superior da pantalla para ler as notificacións que non viches."</string>
+    <string name="zen_mode_restrict_notifications_hide_footer" msgid="7617688597593946765">"O teléfono non mostrará notificacións, vibrará nin emitirá sons con notificacións novas ou existentes. Ten en conta que se seguirán mostrando as notificacións esenciais para o estado e a actividade do teléfono.\n\nCando desactives o modo Non molestar, poderás pasar o dedo cara abaixo desde a parte superior da pantalla para ler as notificacións que non viches."</string>
     <string name="zen_mode_restrict_notifications_custom" msgid="3167252482570424133">"Configuración personalizada"</string>
     <string name="zen_mode_restrict_notifications_enable_custom" msgid="6376983315529894440">"Activar configuración personalizada"</string>
     <string name="zen_mode_restrict_notifications_disable_custom" msgid="8004212081465043044">"Quitar configuración personalizada"</string>
@@ -3492,7 +3496,7 @@
     <string name="zen_calls_summary_starred_repeat" msgid="9191394641577678207">"De contactos marcados con estrela e chamadas repetidas"</string>
     <string name="zen_calls_summary_contacts_repeat" msgid="7747592096431111510">"Dos contactos e de chamadas repetidas"</string>
     <string name="zen_calls_summary_repeat_only" msgid="8839703337232747964">"Só de chamadas repetidas"</string>
-    <string name="zen_mode_from_none" msgid="7683889985618637010">"De ninguén"</string>
+    <string name="zen_mode_from_none" msgid="7683889985618637010">"Ninguén"</string>
     <string name="zen_mode_from_none_calls" msgid="2967739140346917546">"Non permitir ningunha chamada"</string>
     <string name="zen_mode_from_none_messages" msgid="9069143820057833634">"Non permitir ningunha mensaxe"</string>
     <string name="zen_mode_alarms" msgid="5528707742250954290">"Permitir alarmas"</string>
@@ -3692,7 +3696,7 @@
     <string name="process_format" msgid="8575347150598564509">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="COUNT">%2$d</xliff:g>)"</string>
     <string name="high_power_apps" msgid="2518319744362028920">"Optimización da batería"</string>
     <string name="additional_battery_info" msgid="6877663897819271203">"Alertas de uso"</string>
-    <string name="show_all_apps" msgid="5442552004569634846">"Mostrar uso completo do dispositivo"</string>
+    <string name="show_all_apps" msgid="5442552004569634846">"Uso do dispositivo"</string>
     <string name="hide_extra_apps" msgid="6798261081113299441">"Mostrar uso das aplicacións"</string>
     <plurals name="power_high_usage_summary" formatted="false" msgid="4658343710126205199">
       <item quantity="other"><xliff:g id="NUMBER">%2$d</xliff:g> aplicacións presentan un comportamento anormal</item>
@@ -3707,7 +3711,7 @@
     <string name="high_power_off" msgid="5906679734326490426">"Optimizando o uso da batería"</string>
     <string name="high_power_system" msgid="739584574711292753">"A optimización da batería non está dispoñible"</string>
     <string name="high_power_desc" msgid="333756885680362741">"Non aplicar a optimización da batería, xa que esta pode esgotarse máis rápido."</string>
-    <string name="high_power_prompt_title" msgid="2805745781720454052">"Queres permitir que esta aplicación se execute sempre en segundo plano?"</string>
+    <string name="high_power_prompt_title" msgid="2805745781720454052">"Permitir que se execute sempre en segundo plano?"</string>
     <string name="high_power_prompt_body" msgid="8067395096053552289">"Se permites que <xliff:g id="APP_NAME">%1$s</xliff:g> estea executándose sempre en segundo plano, é posible que se  reduza a duración da batería. \n\nPodes cambiar esta opción máis tarde en Configuración &gt; Aplicacións e notificacións."</string>
     <string name="battery_summary" msgid="4345690800899981339">"Uso do <xliff:g id="PERCENTAGE">%1$s</xliff:g> desde a última carga completa"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"Xestión da batería"</string>
@@ -3795,7 +3799,7 @@
     <string name="app_list_preference_none" msgid="7100409177446935028">"Ningún"</string>
     <string name="work_profile_usage_access_warning" msgid="403208064382097510">"A desactivación do acceso de uso desta aplicación non impide que o teu administrador realice o seguimento do uso de datos das aplicacións no teu perfil de traballo"</string>
     <string name="accessibility_lock_screen_progress" msgid="8242917828598820049">"Uso de <xliff:g id="COUNT_0">%1$d</xliff:g> de <xliff:g id="COUNT_1">%2$d</xliff:g> caracteres"</string>
-    <string name="draw_overlay" msgid="2878665072530660668">"Superpoñer sobre aplicacións"</string>
+    <string name="draw_overlay" msgid="2878665072530660668">"Superpor a aplicacións"</string>
     <string name="system_alert_window_settings" msgid="3024330223417646567">"Mostrar sobre outras aplicacións"</string>
     <string name="system_alert_window_apps_title" msgid="9188448296493699566">"Aplicacións"</string>
     <string name="system_alert_window_access_title" msgid="5187343732185369675">"Mostrar sobre outras aplicacións"</string>
@@ -3803,7 +3807,7 @@
     <string name="allow_overlay_description" msgid="6669524816705082807">"Permite que esta aplicación se mostre enriba doutras aplicacións que estás utilizando. Pode interferir no uso desas aplicacións ou cambiar a forma na que aparecen ou se comportan."</string>
     <string name="keywords_vr_listener" msgid="5312633527788917750">"rv realidade virtual axente de escoita estéreo asistente servizo"</string>
     <string name="keywords_system_alert_window" msgid="3936658600272194599">"cadro de diálogo da ventá de alerta do sistema para mostrar sobre outras aplicacións"</string>
-    <string name="overlay_settings" msgid="3325154759946433666">"Superpoñer sobre aplicacións"</string>
+    <string name="overlay_settings" msgid="3325154759946433666">"Superpor a aplicacións"</string>
     <string name="system_alert_window_summary" msgid="7703582115861844158">"Aplicacións con permiso para superpoñerse a outras: <xliff:g id="COUNT_0">%1$d</xliff:g> de <xliff:g id="COUNT_1">%2$d</xliff:g>"</string>
     <string name="filter_overlay_apps" msgid="6336897660213304743">"Aplicacións con permiso"</string>
     <string name="app_permission_summary_allowed" msgid="6458476982015518778">"Permitido"</string>
@@ -3829,7 +3833,7 @@
     <string name="screen_zoom_title" msgid="164369086350486104">"Tamaño de visualización"</string>
     <string name="screen_zoom_short_summary" msgid="5508079362742276703">"Reduce ou amplía os elementos da pantalla"</string>
     <string name="screen_zoom_keywords" msgid="8358462497896524092">"densidade de visualización, zoom da pantalla, escala, escalado"</string>
-    <string name="screen_zoom_summary" msgid="5294003755961312560">"Reduce ou amplía os elementos da pantalla. É posible que algunhas aplicacións da pantalla cambien de posición."</string>
+    <string name="screen_zoom_summary" msgid="5294003755961312560">"Reduce ou amplía o tamaño dos elementos na pantalla. É posible que algunhas aplicacións da pantalla cambien de posición."</string>
     <string name="screen_zoom_preview_title" msgid="2924312934036753091">"Vista previa"</string>
     <string name="screen_zoom_make_smaller_desc" msgid="1374501139722916729">"Facer máis pequeno"</string>
     <string name="screen_zoom_make_larger_desc" msgid="5306684807895846141">"Facer máis grande"</string>
@@ -4473,7 +4477,7 @@
     <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"Queres eliminar esta suxestión?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"Quitouse a suxestión"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"Desfacer"</string>
-    <string name="low_storage_summary" msgid="4562224870189133400">"Queda pouco espazo. Utilizado: <xliff:g id="PERCENTAGE">%1$s</xliff:g>. Libre: <xliff:g id="FREE_SPACE">%2$s</xliff:g>"</string>
+    <string name="low_storage_summary" msgid="4562224870189133400">"Queda pouco espazo. En uso: <xliff:g id="PERCENTAGE">%1$s</xliff:g>. Libre: <xliff:g id="FREE_SPACE">%2$s</xliff:g>"</string>
     <string name="contextual_card_feedback_send" msgid="8698649023854350623">"Enviar comentarios"</string>
     <string name="contextual_card_feedback_confirm_message" msgid="3987973028353264878">"Queres indicarnos a túa opinión sobre esta suxestión?"</string>
     <string name="copyable_slice_toast" msgid="1357518174923789947">"<xliff:g id="COPY_CONTENT">%1$s</xliff:g>: copiouse no portapapeis."</string>
diff --git a/tests/CarDeveloperOptions/res/values-gu/arrays.xml b/tests/CarDeveloperOptions/res/values-gu/arrays.xml
index 4691201..9671c68 100644
--- a/tests/CarDeveloperOptions/res/values-gu/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-gu/arrays.xml
@@ -29,8 +29,25 @@
     <item msgid="5194868215515664953">"પેસિફિક"</item>
     <item msgid="7044520255415007865">"તમામ"</item>
   </string-array>
-    <!-- no translation found for screen_timeout_entries:0 (8596143519087753804) -->
-    <!-- no translation found for dream_timeout_entries:7 (8271452751594598661) -->
+  <string-array name="screen_timeout_entries">
+    <item msgid="8596143519087753804">"15 સેકન્ડ"</item>
+    <item msgid="772029947136115322">"30 સેકન્ડ"</item>
+    <item msgid="8743663928349474087">"1 મિનિટ"</item>
+    <item msgid="1506508631223164814">"2 મિનિટ"</item>
+    <item msgid="8664703938127907662">"5 મિનિટ"</item>
+    <item msgid="5827960506924849753">"10 મિનિટ"</item>
+    <item msgid="6677424950124253938">"30 મિનિટ"</item>
+  </string-array>
+  <string-array name="dream_timeout_entries">
+    <item msgid="6487043225269853023">"ક્યારેય નહીં"</item>
+    <item msgid="2517785806387977252">"15 સેકન્ડ"</item>
+    <item msgid="6347954399441173672">"30 સેકન્ડ"</item>
+    <item msgid="4858305253279921789">"1 મિનિટ"</item>
+    <item msgid="8109273437140044073">"2 મિનિટ"</item>
+    <item msgid="2788593551142462622">"5 મિનિટ"</item>
+    <item msgid="8012672183888404961">"10 મિનિટ"</item>
+    <item msgid="8271452751594598661">"30 મિનિટ"</item>
+  </string-array>
   <string-array name="lock_after_timeout_entries">
     <item msgid="2232921187970351881">"ત્વરિત"</item>
     <item msgid="2038544972632026612">"5 સેકન્ડ"</item>
@@ -42,17 +59,47 @@
     <item msgid="811192536981678974">"10 મિનિટ"</item>
     <item msgid="7258394417241706272">"30 મિનિટ"</item>
   </string-array>
-    <!-- no translation found for entries_font_size:0 (2340391964816059553) -->
-    <!-- no translation found for entries_font_size:0 (6490061470416867723) -->
-    <!-- no translation found for entries_font_size:2 (1714184661981538355) -->
-    <!-- no translation found for entries_font_size:2 (1678068858001018666) -->
-    <!-- no translation found for wifi_status:3 (5848277343965362748) -->
-    <!-- no translation found for wifi_status_with_ssid:1 (6816207058895999545) -->
-    <!-- no translation found for wifi_status_with_ssid:3 (7547609081339573756) -->
-    <!-- no translation found for wifi_status_with_ssid:4 (5145158315060185414) -->
+  <string-array name="entries_font_size">
+    <item msgid="2340391964816059553">"નાના"</item>
+    <item msgid="591935967183159581">"ડિફૉલ્ટ"</item>
+    <item msgid="1714184661981538355">"મોટા"</item>
+    <item msgid="6195563047686707484">"સૌથી મોટું"</item>
+  </string-array>
+  <string-array name="wifi_status">
+    <item msgid="1304883790721412351"></item>
+    <item msgid="4157625910392775808">"સ્કેન કરી રહ્યું છે..."</item>
+    <item msgid="5597394826455877834">"કનેક્ટ થઈ રહ્યું છે…"</item>
+    <item msgid="5848277343965362748">"પ્રમાણિત કરી રહ્યું છે…"</item>
+    <item msgid="3391238031431440676">"IP ઍડ્રેસ મેળવી રહ્યાં છે..."</item>
+    <item msgid="5257597310494000224">"કનેક્ટ થયું"</item>
+    <item msgid="8472497592913050396">"સસ્પેન્ડેડ"</item>
+    <item msgid="1228072488815999109">"ડિસ્કનેક્ટ થઈ રહ્યું છે..."</item>
+    <item msgid="7253087004422991731">"ડિસ્કનેક્ટ કર્યું"</item>
+    <item msgid="4169850917304751227">"અસફળ"</item>
+    <item msgid="6266658166690831131">"અવરોધિત"</item>
+    <item msgid="4517230805854909775">"નબળા કનેક્શનને અસ્થાયી રૂપે ટાળી રહ્યું છે"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="4853670665485437464"></item>
+    <item msgid="6816207058895999545">"સ્કૅન કરી રહ્યાં છીએ…"</item>
+    <item msgid="8058143476674427024">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> પર કનેક્ટ થઈ રહ્યું છે..."</item>
+    <item msgid="7547609081339573756">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> સાથે પ્રમાણિત કરી રહ્યું છે…"</item>
+    <item msgid="5145158315060185414">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> તરફથી IP ઍડ્રેસ મેળવી રહ્યું છે…"</item>
+    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> સાથે કનેક્ટ થયાં"</item>
+    <item msgid="6600156231416890902">"સસ્પેન્ડેડ"</item>
+    <item msgid="4133290864821295785">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> થી ડિસ્કનેક્ટ થઈ રહ્યાં છે…"</item>
+    <item msgid="3980154971187953257">"ડિસ્કનેક્ટ કર્યું"</item>
+    <item msgid="2847316776634969068">"અસફળ"</item>
+    <item msgid="4390990424746035383">"અવરોધિત"</item>
+    <item msgid="3618248791367063949">"અસ્થાયી રૂપે નબળા કનેક્શનને ટાળી રહ્યું છે"</item>
+  </string-array>
     <!-- no translation found for wifi_tether_security:0 (5586343370515598801) -->
     <!-- no translation found for wifi_tether_security:1 (6136336549994615745) -->
-    <!-- no translation found for wifi_p2p_wps_setup:0 (5390235347963255303) -->
+  <string-array name="wifi_p2p_wps_setup">
+    <item msgid="5390235347963255303">"પુશ બટન"</item>
+    <item msgid="7401896200768713930">"પીઅર ઉપકરણ પરથી પિન"</item>
+    <item msgid="4526848028011846710">"આ ઉપકરણ પરથી પિન"</item>
+  </string-array>
   <string-array name="wifi_p2p_status">
     <item msgid="8741947238021758201">"કનેક્ટ થયું"</item>
     <item msgid="983792611851499732">"આમંત્રિત"</item>
@@ -60,7 +107,12 @@
     <item msgid="4646663015449312554">"ઉપલબ્ધ"</item>
     <item msgid="3230556734162006146">"શ્રેણીથી બહાર"</item>
   </string-array>
-    <!-- no translation found for bluetooth_visibility_timeout_entries:1 (2759776603549270587) -->
+  <string-array name="bluetooth_visibility_timeout_entries">
+    <item msgid="8247986727324120082">"2 મિનિટ"</item>
+    <item msgid="2759776603549270587">"5 મિનિટ"</item>
+    <item msgid="167772676068860015">"1 કલાક"</item>
+    <item msgid="5985477119043628504">"ક્યારેય સમયસમાપ્તિ નહીં"</item>
+  </string-array>
   <string-array name="bluetooth_max_connected_audio_devices">
     <item msgid="3800257971619063588">"સિસ્ટમ ડિફૉલ્ટનો ઉપયોગ કરો: <xliff:g id="DEFAULT_BLUETOOTH_MAX_CONNECTED_AUDIO_DEVICES">%1$d</xliff:g>"</item>
     <item msgid="8572230405241423895">"1"</item>
@@ -69,8 +121,13 @@
     <item msgid="1644506614010085798">"4"</item>
     <item msgid="3132506679404897150">"5"</item>
   </string-array>
-    <!-- no translation found for wifi_signal:1 (7882129634982603782) -->
-    <!-- no translation found for wifi_signal:4 (999948812884919584) -->
+  <string-array name="wifi_signal">
+    <item msgid="1709949377823900951">"નબળી"</item>
+    <item msgid="7882129634982603782">"નબળી"</item>
+    <item msgid="6457357501905996224">"ઠીક"</item>
+    <item msgid="405271628162918841">"સારી"</item>
+    <item msgid="999948812884919584">"ઉત્તમ"</item>
+  </string-array>
   <string-array name="data_usage_data_range">
     <item msgid="8986775481492954015">"છેલ્લા 30 દિવસ"</item>
     <item msgid="3211287705232736964">"વપરાશ સાયકલ સેટ કરો..."</item>
@@ -106,7 +163,10 @@
     <item msgid="7330627471456865502">"MSCHAPV2"</item>
     <item msgid="6255179395132581882">"GTC"</item>
   </string-array>
-    <!-- no translation found for wifi_ip_settings:1 (4377002609760712163) -->
+  <string-array name="wifi_ip_settings">
+    <item msgid="2717196390555072244">"DHCP"</item>
+    <item msgid="4377002609760712163">"સ્ટેટિક"</item>
+  </string-array>
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"કોઈ નહીં"</item>
     <item msgid="1464741437353223198">"મેન્યુઅલ"</item>
@@ -226,11 +286,73 @@
     <item msgid="1165623660533024666">"પૃષ્ઠભૂમિમાં ચલાવો"</item>
     <item msgid="6423861043647911030">"ઍક્સેસિબિલિટી વૉલ્યૂમ"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:3 (7836406246005211990) -->
-    <!-- no translation found for app_ops_labels:4 (3951439024549922598) -->
-    <!-- no translation found for app_ops_labels:8 (3597797992398484655) -->
-    <!-- no translation found for app_ops_labels:20 (3037159047591081136) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"સ્થાન"</item>
+    <item msgid="6656077694190491067">"સ્થાન"</item>
+    <item msgid="8790228218278477369">"સ્થાન"</item>
+    <item msgid="7836406246005211990">"વાઇબ્રેટ"</item>
+    <item msgid="3951439024549922598">"સંપર્કો વાંચો"</item>
+    <item msgid="8802152411647068">"સંપર્કો સંશોધિત કરો"</item>
+    <item msgid="229544934599698735">"કૉલ લૉગ વાંચો"</item>
+    <item msgid="7396102294405899613">"કૉલ લૉગ સંશોધિત કરો"</item>
+    <item msgid="3597797992398484655">"કૅલેન્ડર વાંચો"</item>
+    <item msgid="2705975774250907343">"કૅલેન્ડર સંશોધિત કરો"</item>
+    <item msgid="4668747371441932697">"સ્થાન"</item>
+    <item msgid="1487578921720243646">"પોસ્ટ નોટિફિકેશન"</item>
+    <item msgid="4636080349724146638">"સ્થાન"</item>
+    <item msgid="673510900286463926">"કૉલ કરો"</item>
+    <item msgid="542083422784609790">"SMS/MMS વાંચો"</item>
+    <item msgid="1033780373029588436">"SMS/MMS લખો"</item>
+    <item msgid="5647111115517787488">"SMS/MMS પ્રાપ્ત કરો"</item>
+    <item msgid="8591105601108455893">"SMS/MMS પ્રાપ્ત કરો"</item>
+    <item msgid="7730995008517841903">"SMS/MMS પ્રાપ્ત કરો"</item>
+    <item msgid="2613033109026626086">"SMS/MMS પ્રાપ્ત કરો"</item>
+    <item msgid="3037159047591081136">"SMS/MMS મોકલો"</item>
+    <item msgid="4726682243833913568">"SMS/MMS વાંચો"</item>
+    <item msgid="6555678522277865572">"SMS/MMS લખો"</item>
+    <item msgid="6981734935578130884">"સેટિંગ્સ સંશોધિત કરો"</item>
+    <item msgid="8705854389991425629">"શીર્ષ પર ખેંચો"</item>
+    <item msgid="5861356020344153651">"સૂચનાઓ ઍક્સેસ કરો"</item>
+    <item msgid="78432174621628659">"કૅમેરો"</item>
+    <item msgid="3986116419882154794">"ઑડિઓ રેકોર્ડ કરો"</item>
+    <item msgid="4516840825756409490">"ઑડિઓ ચલાવો"</item>
+    <item msgid="6811712502798183957">"ક્લિપબોર્ડ વાંચો"</item>
+    <item msgid="2780369012602289114">"ક્લિપબોર્ડ સંશોધિત કરો"</item>
+    <item msgid="2331359440170850868">"મીડિયા બટન્સ"</item>
+    <item msgid="6133599737122751231">"ઑડિઓ ફોકસ"</item>
+    <item msgid="6844485713404805301">"માસ્ટર વૉલ્યૂમ"</item>
+    <item msgid="1600379420669104929">"વૉઇસ વૉલ્યૂમ"</item>
+    <item msgid="6296768210470214866">"રિંગ વૉલ્યૂમ"</item>
+    <item msgid="510690696071629241">"મીડિયા વૉલ્યૂમ"</item>
+    <item msgid="406861638631430109">"એલાર્મ વૉલ્યૂમ"</item>
+    <item msgid="4715864795872233884">"નોટિફિકેશન વૉલ્યૂમ"</item>
+    <item msgid="2311478519251301183">"બ્લૂટૂથ વૉલ્યૂમ"</item>
+    <item msgid="5133991377896747027">"સક્રિય રાખો"</item>
+    <item msgid="2464189519136248621">"સ્થાન"</item>
+    <item msgid="2062677934050803037">"સ્થાન"</item>
+    <item msgid="1735171933192715957">"ઉપયોગના આંકડા મેળવો"</item>
+    <item msgid="1014093788778383554">"માઇક્રોફોનનો અવાજ બંધ/ચાલુ કરો"</item>
+    <item msgid="4199297950608622850">"ટોસ્ટ બતાવો"</item>
+    <item msgid="2527962435313398821">"પ્રોજેક્ટ મીડિયા"</item>
+    <item msgid="5117506254221861929">"VPN સક્રિય કરો"</item>
+    <item msgid="8291198322681891160">"વૉલપેપર લખો"</item>
+    <item msgid="7106921284621230961">"મદદ સંરચના"</item>
+    <item msgid="4496533640894624799">"મદદ સ્ક્રીનશોટ"</item>
+    <item msgid="2598847264853993611">"ફોન સ્થિતિ વાંચો"</item>
+    <item msgid="9215610846802973353">"વૉઇસમેઇલ ઉમેરો"</item>
+    <item msgid="9186411956086478261">"sip નો ઉપયોગ કરો"</item>
+    <item msgid="6884763100104539558">"આઉટગોઇંગ કૉલ પર પ્રક્રિયા કરો"</item>
+    <item msgid="125513972170580692">"ફિંગરપ્રિન્ટ"</item>
+    <item msgid="2556071024281275619">"બોડી સેન્સર્સ"</item>
+    <item msgid="617168514928339387">"સેલ બ્રોડકાસ્ટ્સ વાંચો"</item>
+    <item msgid="7134693570516523585">"મોક સ્થાન"</item>
+    <item msgid="7224489175375229399">"સ્ટોરેજ વાંચો"</item>
+    <item msgid="8472735063903258202">"સ્ટોરેજ પર લખો"</item>
+    <item msgid="4069276819909595110">"સ્ક્રીન ચાલુ કરો"</item>
+    <item msgid="1228338896751121025">"એકાઉન્ટ્સ મેળવો"</item>
+    <item msgid="3181581793459233672">"પૃષ્ઠભૂમિમાં ચલાવો"</item>
+    <item msgid="2340936043025374076">"ઍક્સેસિબિલિટી વૉલ્યૂમ"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"નાનો"</item>
     <item msgid="4816511817309094890">"મધ્યમ"</item>
@@ -247,15 +369,35 @@
     <item msgid="4627069151979553527">"કર્સિવ"</item>
     <item msgid="6896773537705206194">"નાના કેપિટલ્સ"</item>
   </string-array>
-    <!-- no translation found for captioning_font_size_selector_titles:3 (2784236342175159295) -->
-    <!-- no translation found for captioning_edge_type_selector_titles:4 (8019330250538856521) -->
+  <string-array name="captioning_font_size_selector_titles">
+    <item msgid="1680223634161592855">"ઘણું નાનું"</item>
+    <item msgid="5091603983404027034">"નાનું"</item>
+    <item msgid="176844712416932112">"સામાન્ય"</item>
+    <item msgid="2784236342175159295">"મોટા"</item>
+    <item msgid="218913203203160606">"ઘણું મોટું"</item>
+  </string-array>
+  <string-array name="captioning_edge_type_selector_titles">
+    <item msgid="3865198759294188069">"ડિફૉલ્ટ"</item>
+    <item msgid="6488643537808152001">"કોઈ નહીં"</item>
+    <item msgid="552332815156010137">"બાહ્યરેખા"</item>
+    <item msgid="7187891159463789272">"છાયો છોડો"</item>
+    <item msgid="8019330250538856521">"ઉપસેલા"</item>
+    <item msgid="8987385315647049787">"દબાવેલ"</item>
+  </string-array>
   <string-array name="captioning_opacity_selector_titles">
     <item msgid="313003243371588365">"25%"</item>
     <item msgid="4665048002584838262">"50%"</item>
     <item msgid="1874668269931014581">"75%"</item>
     <item msgid="6462911487571123954">"100%"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"ઍપ્લિકેશન ડિફોલ્ટ્સનો ઉપયોગ કરો"</item>
+    <item msgid="8611890312638868524">"કાળા પર સફેદ"</item>
+    <item msgid="5891360837786277638">"સફેદ પર કાળી"</item>
+    <item msgid="2798457065945456853">"કાળા પર પીળી"</item>
+    <item msgid="5799049811524553967">"વાદળી પર પીળી"</item>
+    <item msgid="3673930830658169860">"કસ્ટમ"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"PPTP VPN"</item>
     <item msgid="1349760781118368659">"પહેલાંથી શેર કરેલ કીઝ સાથે L2TP/IPSec VPN"</item>
@@ -264,16 +406,36 @@
     <item msgid="3319427315593649917">"પ્રમાણપત્રો અને Xauth પ્રમાણીકરણ સાથે IPSec VPN"</item>
     <item msgid="8258927774145391041">"પ્રમાણપત્રો અને સંકર પ્રમાણીકરણ સાથે IPSec VPN"</item>
   </string-array>
-    <!-- no translation found for vpn_proxy_settings:0 (2958623927055120839) -->
-    <!-- no translation found for vpn_states:4 (9135049670787351881) -->
+  <string-array name="vpn_proxy_settings">
+    <item msgid="2958623927055120839">"કોઈ નહીં"</item>
+    <item msgid="1157046369795346308">"મેન્યુઅલ"</item>
+  </string-array>
+  <string-array name="vpn_states">
+    <item msgid="5408915841694583740">"ડિસ્કનેક્ટ કર્યું"</item>
+    <item msgid="8754480102834556765">"પ્રારંભ કરી રહ્યું છે..."</item>
+    <item msgid="3351334355574270250">"કનેક્ટ થઈ રહ્યું છે…"</item>
+    <item msgid="8303882153995748352">"કનેક્ટ થયું"</item>
+    <item msgid="9135049670787351881">"સમયસમાપ્તિ"</item>
+    <item msgid="2124868417182583926">"અસફળ"</item>
+  </string-array>
   <string-array name="security_settings_premium_sms_values">
     <item msgid="1164265643455394443">"પૂછો"</item>
     <item msgid="7718817231348607934">"ક્યારેય મંજૂરી આપશો નહીં"</item>
     <item msgid="8184570120217958741">"હંમેશા મંજૂરી આપો"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"સામાન્ય"</item>
+    <item msgid="5101233285497327432">"મધ્યમ"</item>
+    <item msgid="1555861583162930714">"ઓછી"</item>
+    <item msgid="1719683776264798117">"ગંભીર"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"સામાન્ય"</item>
+    <item msgid="6107138933849816768">"મધ્યમ"</item>
+    <item msgid="182695359839047859">"ઓછી"</item>
+    <item msgid="8577246509202964244">"ગંભીર"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"નિરંતર"</item>
     <item msgid="167418068739176448">"ટોચની પ્રવૃત્તિ"</item>
@@ -310,7 +472,7 @@
     <item msgid="3118234477029486741">"0"</item>
   </string-array>
   <string-array name="wifi_metered_entries">
-    <item msgid="4329206416008519163">"આપમેળે શોધો"</item>
+    <item msgid="4329206416008519163">"ઑટોમૅટિક રીતે શોધો"</item>
     <item msgid="773943026484148895">"મીટર કરેલ તરીકે ગણો"</item>
     <item msgid="1008268820118852416">"મીટર ન કરેલ તરીકે ગણો"</item>
   </string-array>
diff --git a/tests/CarDeveloperOptions/res/values-gu/config.xml b/tests/CarDeveloperOptions/res/values-gu/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-gu/config.xml
+++ b/tests/CarDeveloperOptions/res/values-gu/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-gu/strings.xml b/tests/CarDeveloperOptions/res/values-gu/strings.xml
index 41d4146..d72a8e6 100644
--- a/tests/CarDeveloperOptions/res/values-gu/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-gu/strings.xml
@@ -27,7 +27,7 @@
       <item quantity="other">તમે હવે એક વિકાસકર્તા બનવાથી <xliff:g id="STEP_COUNT_1">%1$d</xliff:g> પગલાં દૂર છો.</item>
     </plurals>
     <string name="show_dev_on" msgid="9075712234786224065">"તમે હવે વિકાસકર્તા છો!"</string>
-    <string name="show_dev_already" msgid="7665948832405148689">"કોઈ જરૂર નથી, તમે પહેલાંથી જ એક વિકાસકર્તા છો."</string>
+    <string name="show_dev_already" msgid="7665948832405148689">"કોઈ જરૂર નથી, તમે પહેલાંથી જ એક ડેવલપર છો."</string>
     <string name="dev_settings_disabled_warning" msgid="3198732189395396721">"કૃપા કરીને પહેલાં વિકાસકર્તાના વિકલ્પો સક્ષમ કરો."</string>
     <string name="header_category_wireless_networks" msgid="8968405993937795898">"વાયરલેસ અને નેટવર્ક્સ"</string>
     <string name="header_category_system" msgid="4045988717359334410">"સિસ્ટમ"</string>
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"સ્ક્રીન પરની ટેક્સ્ટને નાની અથવા મોટી કરો."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"વધુ નાનું બનાવો"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"વધુ મોટું બનાવો"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"ટેક્સ્ટની સાઇઝનો નમૂનો"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"અદ્ભુત Wizard of Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"પ્રકરણ 11: ધ વન્ડરફૂલ એમરલ્ડ સીટી ઓફ ઓઝ"</string>
@@ -100,13 +99,13 @@
     <string name="bluetooth_visibility_timeout" msgid="4804679276398564496">"દૃશ્યતાની સમયસમાપ્તિ"</string>
     <string name="bluetooth_lock_voice_dialing" msgid="1600385868298081015">"વૉઇસ ડાયલિંગ લૉક કરો"</string>
     <string name="bluetooth_lock_voice_dialing_summary" msgid="5005776616112427980">"જ્યારે સ્ક્રીન લૉક થયેલ હોય ત્યારે બ્લૂટૂથ ડાયલરના ઉપયોગને અટકાવો"</string>
-    <string name="bluetooth_devices" msgid="4143880830505625666">"બ્લૂટૂથ ઉપકરણો"</string>
-    <string name="bluetooth_device_name" msgid="3682016026866302981">"ઉપકરણનું નામ"</string>
-    <string name="bluetooth_device_details" msgid="2500840679106321361">"ઉપકરણ સેટિંગ્સ"</string>
+    <string name="bluetooth_devices" msgid="4143880830505625666">"બ્લૂટૂથ ડિવાઇસ"</string>
+    <string name="bluetooth_device_name" msgid="3682016026866302981">"ડિવાઇસનું નામ"</string>
+    <string name="bluetooth_device_details" msgid="2500840679106321361">"ડિવાઇસના સેટિંગ"</string>
     <string name="bluetooth_profile_details" msgid="1785505059738682493">"પ્રોફાઇલ સેટિંગ્સ"</string>
     <string name="bluetooth_name_not_set" msgid="1886067683138385142">"કોઈ નામ સેટ નથી, એકાઉન્ટ નામનો ઉપયોગ કરીને"</string>
     <string name="bluetooth_scan_for_devices" msgid="3215740768422735880">"ઉપકરણો માટે સ્કૅન કરો"</string>
-    <string name="bluetooth_rename_device" msgid="7862992396452800566">"આ ઉપકરણનું નામ બદલો"</string>
+    <string name="bluetooth_rename_device" msgid="7862992396452800566">"આ ડિવાઇસનું નામ બદલો"</string>
     <string name="bluetooth_rename_button" msgid="8946904845821073267">"નામ બદલો"</string>
     <string name="bluetooth_disconnect_title" msgid="2689706557852333780">"ઉપકરણને ડિસ્કનેક્ટ કરીએ?"</string>
     <string name="bluetooth_disconnect_all_profiles" product="default" msgid="8920448151607060442">"તમારો ફોન <xliff:g id="DEVICE_NAME">%1$s</xliff:g>થી ડિસ્કનેક્ટ થઈ જશે."</string>
@@ -114,11 +113,11 @@
     <string name="bluetooth_disconnect_all_profiles" product="device" msgid="4707569949253450208">"તમારું ઉપકરણ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>થી ડિસ્કનેક્ટ થઈ જશે."</string>
     <string name="bluetooth_disconnect_dialog_ok" msgid="4183522987246110145">"ડિસ્કનેક્ટ"</string>
     <string name="bluetooth_empty_list_user_restricted" msgid="3616298363281495777">"તમારી પાસે બ્લૂટૂથ સેટિંગ્સ બદલવાની પરવાનગી નથી."</string>
-    <string name="bluetooth_pairing_pref_title" msgid="2904954138013884029">"નવા ઉપકરણ જોડો"</string>
+    <string name="bluetooth_pairing_pref_title" msgid="2904954138013884029">"નવા ડિવાઇસ જોડો"</string>
     <string name="bluetooth_is_visible_message" msgid="6341088682252805612">"જ્યારે બ્લૂટૂથ  સેટિંગ્સ ખુલ્લી હોય ત્યારે <xliff:g id="DEVICE_NAME">%1$s</xliff:g> નજીકનાં ઉપકરણોને દૃશ્યક્ષમ છે."</string>
     <string name="bluetooth_footer_mac_message" product="default" msgid="335341476746836260">"ફોનનું બ્લૂટૂથ ઍડ્રેસ: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
     <string name="bluetooth_footer_mac_message" product="tablet" msgid="6033609611245782463">"ટૅબ્લેટનું બ્લૂટૂથ ઍડ્રેસ: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
-    <string name="bluetooth_footer_mac_message" product="device" msgid="7639919867088358038">"ઉપકરણનું બ્લૂટૂથ ઍડ્રેસ: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="bluetooth_footer_mac_message" product="device" msgid="7639919867088358038">"ડિવાઇસનું બ્લૂટૂથ ઍડ્રેસ: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
     <string name="bluetooth_is_disconnect_question" msgid="6180709281434591654">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ને ડિસ્કનેક્ટ કરીએ?"</string>
     <string name="bluetooth_broadcasting" msgid="8926408584599563760">"બ્રૉડકાસ્ટ કરી રહ્યાં છે"</string>
     <string name="bluetooth_device" msgid="3170974107364990008">"અનામાંકિત બ્લૂટૂથ ઉપકરણ"</string>
@@ -163,10 +162,10 @@
     <string name="bluetooth_map_acceptance_dialog_text" msgid="736507842082640410">"%1$s તમારા સંદેશા અ‍ૅક્સેસ કરવા માંગે છે. %2$s ને અ‍ૅક્સેસ આપીએ?"</string>
     <string name="bluetooth_sap_request" msgid="6318039677671263261">"સિમ ઍક્સેસ વિનંતી"</string>
     <string name="bluetooth_sap_acceptance_dialog_text" msgid="1909352413109340355">"<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g> તમારા સિમ કાર્ડને અ‍ૅક્સેસ કરવા માગે છે. સિમ કાર્ડની અ‍ૅક્સેસને મંજૂરી આપવું કનેક્શનના સમયગાળા માટે તમારા ઉપકરણ પર ડેટા કનેક્ટિવિટીને અક્ષમ કરશે. <xliff:g id="DEVICE_NAME_1">%2$s?</xliff:g> ને અ‍ૅક્સેસ આપો"</string>
-    <string name="bluetooth_device_name_summary" msgid="8661066392056595005">"તે અન્ય ઉપકરણોને \'<xliff:g id="DEVICE_NAME">^1</xliff:g>\' તરીકે દેખાય છે"</string>
+    <string name="bluetooth_device_name_summary" msgid="8661066392056595005">"તે અન્ય ડિવાઇસને \'<xliff:g id="DEVICE_NAME">^1</xliff:g>\' તરીકે દેખાય છે"</string>
     <string name="bluetooth_off_footer" msgid="7658444560543730571">"અન્ય ઉપકરણો સાથે કનેક્ટ કરવા માટે બ્લૂટૂથ ચાલુ કરો."</string>
     <string name="bluetooth_paired_device_title" msgid="8361860197780425286">"તમારા ડિવાઇસ"</string>
-    <string name="bluetooth_pairing_page_title" msgid="9053463656712597709">"નવા ઉપકરણ જોડો"</string>
+    <string name="bluetooth_pairing_page_title" msgid="9053463656712597709">"નવા ડિવાઇસ જોડો"</string>
     <string name="bluetooth_pref_summary" product="tablet" msgid="3601662966604648212">"તમારા ટૅબ્લેટને નજીકના બ્લૂટૂથ ઉપકરણો સાથે સંચાર કરવાની મંજૂરી આપો"</string>
     <string name="bluetooth_pref_summary" product="device" msgid="2286727776570956969">"તમારા ઉપકરણને નજીકના બ્લૂટૂથ ઉપકરણો સાથે સંચાર કરવાની મંજૂરી આપો"</string>
     <string name="bluetooth_pref_summary" product="default" msgid="863659221858781186">"તમારા ફોનને નજીકના બ્લૂટૂથ ઉપકરણો સાથે સંચાર કરવાની મંજૂરી આપો"</string>
@@ -181,7 +180,7 @@
     <string name="connected_device_saved_title" msgid="8270136893488475163">"સાચવેલ ઉપકરણો"</string>
     <string name="connected_device_add_device_summary" msgid="7960491471270158891">"બ્લૂટૂથ જોડી બનાવવાનું ચાલુ કરશે"</string>
     <string name="connected_device_connections_title" msgid="9205000271382018428">"કનેક્શનની પસંદગીઓ"</string>
-    <string name="connected_device_previously_connected_title" msgid="225918223397410428">"પહેલાં કનેક્ટ થયેલા ઉપકરણો"</string>
+    <string name="connected_device_previously_connected_title" msgid="225918223397410428">"પહેલાં કનેક્ટ થયેલા ડિવાઇસ"</string>
     <string name="connected_device_previously_connected_screen_title" msgid="2018789662358162716">"પહેલાં કનેક્ટ કરેલા"</string>
     <string name="connected_device_bluetooth_turned_on_toast" msgid="4652326177920814476">"બ્લૂટૂથ ચાલુ કર્યું"</string>
     <string name="previous_connected_see_all" msgid="7237095013087310923">"બધા ડિવાઇસ જુઓ"</string>
@@ -355,7 +354,7 @@
     <string name="owner_info_settings_title" msgid="2537966178998339896">"લૉક સ્ક્રીન સંદેશ"</string>
     <string name="security_enable_widgets_title" msgid="1701510007926738088">"વિજેટ્સને સક્ષમ કરો"</string>
     <string name="security_enable_widgets_disabled_summary" msgid="4408176087132339331">"વ્યવસ્થાપકે અક્ષમ કરેલ"</string>
-    <string name="lockdown_settings_title" msgid="4534779922580115990">"લોકડાઉનનો વિકલ્પ બતાવો"</string>
+    <string name="lockdown_settings_title" msgid="4534779922580115990">"લૉકડાઉનનો વિકલ્પ બતાવો"</string>
     <string name="lockdown_settings_summary" msgid="7270756909878256174">"ડિસ્પ્લે પાવર બટનનો વિકલ્પ જે Smart Lock, ફિંગરપ્રિન્ટ અનલૉક કરવાનું, અને લૉક સ્ક્રીન પર નોટિફિકેશનને બંધ કરે છે"</string>
     <string name="trust_agents_extend_unlock_title" msgid="3582017561316089951">"માત્ર ટ્રસ્ટ એજન્ટ અનલૉક મોડ લંબાવી શકશે"</string>
     <string name="trust_agents_extend_unlock_summary" msgid="3543997596586078084">"જો ચાલુ કરવામાં આવે, તો ટ્રસ્ટ એજન્ટ વધુ લાંબા સમય માટે ડિવાઇસને અનલૉક રાખી શકશે, પરંતુ લૉક થયેલા ડિવાઇસને ફરી અનલૉક કરી શકશે નહીં."</string>
@@ -499,12 +498,12 @@
     <string name="fingerprint_add_max" msgid="2939393314646115661">"તમે <xliff:g id="COUNT">%d</xliff:g> જેટલી ફિંગરપ્રિન્ટ્સ ઉમેરી શકો છો"</string>
     <string name="fingerprint_intro_error_max" msgid="3247720976621039437">"તમે મહત્તમ ફિંગરપ્રિન્ટ્સ ઉમેર્યા છે"</string>
     <string name="fingerprint_intro_error_unknown" msgid="3975674268256524015">"વધુ ફિંગરપ્રિન્ટ્સ ઉમેરી શકતાં નથી"</string>
-    <string name="fingerprint_last_delete_title" msgid="3104596858161269635">"તમામ ફિંગરપ્રિન્ટ્સ દૂર કરીએ?"</string>
+    <string name="fingerprint_last_delete_title" msgid="3104596858161269635">"તમામ ફિંગરપ્રિન્ટ કાઢી નાખીએ?"</string>
     <string name="fingerprint_delete_title" msgid="3120894112324235536">"\'<xliff:g id="FINGERPRINT_ID">%1$s</xliff:g>\'ને દૂર કરો"</string>
     <string name="fingerprint_delete_message" msgid="5895802741486967970">"શું તમે આ ફિંગરપ્રિન્ટ કાઢી નાખવા માગો છો?"</string>
     <string name="fingerprint_last_delete_message" msgid="3346252479778971442">"તમારી ફિંગરપ્રિન્ટનો ઉપયોગ કરીને તમે તમારો ફોન અનલૉક, ખરીદીઓ અધિકૃત અથવા તેમના વડે ઍપ્લિકેશનો પર સાઇન ઇન કરવામાં સમર્થ હશો નહીં"</string>
     <string name="fingerprint_last_delete_message_profile_challenge" msgid="5385095150532247025">"તમારી ફિંગરપ્રિન્ટનો ઉપયોગ કરીને તમે તમારી કાર્યાલયની પ્રોફાઇલ અનલૉક, ખરીદીઓ અધિકૃત અથવા કાર્ય ઍપ્લિકેશનો પર સાઇન ઇન કરવામાં સમર્થ હશો નહીં"</string>
-    <string name="fingerprint_last_delete_confirm" msgid="7984595457589664004">"હા, દૂર કરો"</string>
+    <string name="fingerprint_last_delete_confirm" msgid="7984595457589664004">"હા, કાઢી નાખો"</string>
     <string name="crypt_keeper_settings_title" msgid="839783588093862748">"એન્ક્રિપ્શન"</string>
     <string name="crypt_keeper_encrypt_title" product="tablet" msgid="2292129135369853167">"ટેબ્લેટને એન્ક્રિપ્ટ કરો"</string>
     <string name="crypt_keeper_encrypt_title" product="default" msgid="3110852053238357832">"ફોન એન્ક્રિપ્ટ કરો"</string>
@@ -594,9 +593,9 @@
     <string name="unlock_set_unlock_mode_password" msgid="397703731925549447">"પાસવર્ડ"</string>
     <string name="unlock_setup_wizard_fingerprint_details" msgid="6515136915205473675">"એકવાર તમે સ્ક્રીન લૉક સેટ કરી લો, પછી તમે સેટિંગ્સ &gt; સુરક્ષામાં ફિંગરપ્રિન્ટ પણ સેટ કરી શકો છો."</string>
     <string name="unlock_disable_lock_title" msgid="3508492427073600294">"સ્ક્રીન લૉક બંધ કરો"</string>
-    <string name="unlock_disable_frp_warning_title" msgid="5858589970505254193">"ઉપકરણ સુરક્ષા દૂર કરીએ?"</string>
+    <string name="unlock_disable_frp_warning_title" msgid="5858589970505254193">"ડિવાઇસની સુરક્ષા કાઢી નાખીએ?"</string>
     <string name="unlock_disable_frp_warning_title_profile" msgid="3814123014295965266">"પ્રોફાઇલ સુરક્ષા દૂર કરીએ?"</string>
-    <string name="unlock_disable_frp_warning_content_pattern" msgid="1843950215687159135">"તમારી પૅટર્ન વગર ઉપકરણ સુરક્ષા સુવિધાઓ કામ કરશે નહીં."</string>
+    <string name="unlock_disable_frp_warning_content_pattern" msgid="1843950215687159135">"તમારી પૅટર્ન વગર ડિવાઇસની સુરક્ષા સુવિધાઓ કામ કરશે નહીં."</string>
     <string name="unlock_disable_frp_warning_content_pattern_fingerprint" msgid="8846957650251741548">"ઉપકરણની સુરક્ષા સુવિધાઓ તમારી પૅટર્ન વગર કાર્ય કરશે નહીં.<xliff:g id="EMPTY_LINE">
 
 </xliff:g>આ ઉપકરણમાંથી તમારી સાચવેલ રેફરન્સ ફાઇલને પણ દૂર કરવામાં આવશે અને તમે તમારા ફોનને અનલૉક કરી શકશો નહીં, ખરીદીઓને અધિકૃત કરી શકશો નહીં અથવા તેના વડે ઍપ્લિકેશનો પર સાઇન ઇન કરી શકશો નહીં."</string>
@@ -628,7 +627,7 @@
     <string name="unlock_disable_frp_warning_content_unknown_fingerprint_profile" msgid="1201259228331105948">"પ્રોફાઇલ સુરક્ષા સુવિધાઓ તમારા સ્ક્રીન લૉક વગર કાર્ય કરશે નહીં.<xliff:g id="EMPTY_LINE">
 
 </xliff:g>આ પ્રોફાઇલમાંથી તમારી સાચવેલ રેફરન્સ ફાઇલને પણ દૂર કરવામાં આવશે અને તમે તમારી પ્રોફાઇલને અનલૉક કરી શકશો નહીં, ખરીદીઓને અધિકૃત કરી શકશો નહીં અથવા તેના વડે ઍપ્લિકેશનો પર સાઇન ઇન કરી શકશો નહીં."</string>
-    <string name="unlock_disable_frp_warning_ok" msgid="2373890505202766456">"હા, દૂર કરો"</string>
+    <string name="unlock_disable_frp_warning_ok" msgid="2373890505202766456">"હા, કાઢી નાખો"</string>
     <string name="unlock_change_lock_pattern_title" msgid="7622476883851319877">"અનલૉક પૅટર્ન બદલો"</string>
     <string name="unlock_change_lock_pin_title" msgid="6671224158800812238">"અનલૉક પિન બદલો"</string>
     <string name="unlock_change_lock_password_title" msgid="7886432065775170719">"અનલૉક પાસવર્ડ બદલો"</string>
@@ -649,7 +648,7 @@
     <string name="lock_last_password_attempt_before_wipe_profile" msgid="1535128774464384305">"જો તમે આગલા પ્રયત્નમાં ખોટો પાસવર્ડ દાખલ કરશો, તો તમારી કાર્યાલયની પ્રોફાઇલ અને તેનો ડેટા કાઢી નાખવામાં આવશે"</string>
     <string name="lock_failed_attempts_now_wiping_device" msgid="8662360098784762828">"ઘણા બધા ખોટા પ્રયત્નો. આ ઉપકરણોનો ડેટા કાઢી નાખવામાં આવશે."</string>
     <string name="lock_failed_attempts_now_wiping_user" msgid="3793513796171561873">"ઘણા બધા ખોટા પ્રયત્નો. આ વપરાશકર્તાને કાઢી નાખવામાં આવશે."</string>
-    <string name="lock_failed_attempts_now_wiping_profile" msgid="5347108525299038285">"ઘણા બધા ખોટા પ્રયત્નો. આ કાર્યાલયની પ્રોફાઇલ અને તેનો ડેટા કાઢી નાખવામાં આવશે."</string>
+    <string name="lock_failed_attempts_now_wiping_profile" msgid="5347108525299038285">"ઘણા બધા ખોટા પ્રયત્નો. આ કાર્યાલયની પ્રોફાઇલ અને તેનો ડેટા ડિલીટ કરવામાં આવશે."</string>
     <string name="lock_failed_attempts_now_wiping_dialog_dismiss" msgid="3950582268749037318">"છોડી દો"</string>
     <plurals name="lockpassword_password_too_short" formatted="false" msgid="694091983183310827">
       <item quantity="one">ઓછામાં ઓછા <xliff:g id="COUNT_1">%d</xliff:g> અક્ષરો હોવા જરૂરી છે</item>
@@ -668,7 +667,6 @@
       <item quantity="one"><xliff:g id="NUMBER_1">%d</xliff:g> કરતાં ઓછા અંક હોવા જરૂરી છે</item>
       <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> કરતાં ઓછા અંક હોવા જરૂરી છે</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"માત્ર 0-9 અંક શામેલ હોવા આવશ્યક છે"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"ઉપકરણ વ્યવસ્થાપક તાજેતરનાં પિનનો ઉપયોગ કરવાની મંજૂરી આપતા નથી"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"સામાન્ય પિન તમારા IT વ્યવસ્થાપક દ્વારા બ્લૉક કરવામાં આવે છે. એક અલગ પિન અજમાવી જુઓ."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"આમાં અમાન્ય અક્ષરોનો સમાવેશ થઈ શકતો નથી"</string>
@@ -699,6 +697,10 @@
       <item quantity="one">ઓછામાં ઓછા <xliff:g id="COUNT">%d</xliff:g> વર્ણ સિવાયના અક્ષર ધરાવતો હોવો જોઈએ</item>
       <item quantity="other">ઓછામાં ઓછા <xliff:g id="COUNT">%d</xliff:g> વર્ણ સિવાયના અક્ષર ધરાવતો હોવો જોઈએ</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">ઓછામાં ઓછો <xliff:g id="COUNT">%d</xliff:g> અક્ષર એવો હોવો જોઈએ કે જે સંખ્યા ન હોય</item>
+      <item quantity="other">ઓછામાં ઓછા <xliff:g id="COUNT">%d</xliff:g> અક્ષર એવા હોવા જોઈએ કે જે સંખ્યા ન હોય</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"ઉપકરણ વ્યવસ્થાપક તાજેતરનાં પાસવર્ડનો ઉપયોગ કરવાની મંજૂરી આપતા નથી"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"સામાન્ય પાસવર્ડ તમારા IT વ્યવસ્થાપક દ્વારા બ્લૉક કરવામાં આવે છે. એક અલગ પાસવર્ડ અજમાવી જુઓ."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"અંકોના ચઢતા ક્રમની, ઉતરતા ક્રમની અથવા પુનરાવર્તિત અનુક્રમની મંજૂરી નથી"</string>
@@ -715,7 +717,7 @@
       <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> સક્રિય ઍપ્લિકેશન</item>
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> સક્રિય ઍપ્લિકેશન</item>
     </plurals>
-    <string name="manage_trust_agents" msgid="8129970926213142261">"ટ્રસ્ટ એજન્ટ્સ"</string>
+    <string name="manage_trust_agents" msgid="8129970926213142261">"ટ્રસ્ટ એજન્ટ"</string>
     <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"ઉપયોગ કરવા માટે, પ્રથમ એક સ્ક્રીન લૉક સેટ કરો"</string>
     <string name="manage_trust_agents_summary" msgid="2023116850759962248">"કોઈ નહીં"</string>
     <plurals name="manage_trust_agents_summary_on" formatted="false" msgid="5550538038916606097">
@@ -744,7 +746,7 @@
     <string name="bluetooth_preference_scan_title" msgid="457781003962324807">"ઉપકરણો માટે સ્કૅન કરો"</string>
     <string name="bluetooth_search_for_devices" msgid="6796307228261078451">"તાજું કરો"</string>
     <string name="bluetooth_searching_for_devices" msgid="7820814625522702494">"શોધી રહ્યું છે..."</string>
-    <string name="bluetooth_preference_device_settings" msgid="4247085616427015908">"ઉપકરણ સેટિંગ્સ"</string>
+    <string name="bluetooth_preference_device_settings" msgid="4247085616427015908">"ડિવાઇસના સેટિંગ"</string>
     <string name="bluetooth_preference_paired_dialog_title" msgid="3567187438908143693">"જોડી કરેલ ઉપકરણ"</string>
     <string name="bluetooth_preference_paired_dialog_internet_option" msgid="3693599743477470469">"ઇન્ટરનેટ કનેક્શન"</string>
     <string name="bluetooth_preference_paired_dialog_keyboard_option" msgid="4627309436489645755">"કીબોર્ડ"</string>
@@ -753,7 +755,7 @@
     <string name="bluetooth_pairing_dialog_sharing_phonebook_title" msgid="7395493311980018460">"ફોન પુસ્તિકા શેર કરીએ?"</string>
     <string name="bluetooth_pairing_dialog_contants_request" msgid="2103132762434487717">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> તમારા સંપર્કો અને કૉલ ઇતિહાસને અ‍ૅક્સેસ કરવા માંગે છે."</string>
     <string name="bluetooth_pairing_dialog_paring_request" msgid="5513953935086446387">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>, બ્લૂટૂથ સાથે જોડી કરવા માંગે છે. જ્યારે કનેક્ટ થયેલ હોય, ત્યારે તેની પાસે તમારા સંપર્કો અને કૉલ ઇતિહાસની ઍક્સેસ હશે."</string>
-    <string name="bluetooth_preference_found_media_devices" msgid="5748539613567836379">"ઉપલબ્ધ ઉપકરણો"</string>
+    <string name="bluetooth_preference_found_media_devices" msgid="5748539613567836379">"ઉપલબ્ધ ડિવાઇસ"</string>
     <string name="bluetooth_preference_no_found_devices" msgid="4190090666412408576">"કોઈ ઉપકરણો ઉપલબ્ધ નથી"</string>
     <string name="bluetooth_device_context_connect" msgid="1812090541371432890">"કનેક્ટ કરો"</string>
     <string name="bluetooth_device_context_disconnect" msgid="8085015949275771802">"ડિસ્કનેક્ટ કરો"</string>
@@ -763,12 +765,12 @@
     <string name="bluetooth_device_context_connect_advanced" msgid="423463405499392444">"વિકલ્પો..."</string>
     <string name="bluetooth_menu_advanced" msgid="7566858513372603652">"વિગતવાર"</string>
     <string name="bluetooth_advanced_titlebar" msgid="6459469494039004784">"વિગતવાર બ્લૂટૂથ"</string>
-    <string name="bluetooth_empty_list_bluetooth_off" msgid="6255367297830430459">"જ્યારે બ્લૂટૂથ ચાલુ હોય, ત્યારે તમારું ઉપકરણ નજીકનાં અન્ય બ્લૂટૂથ ઉપકરણો સાથે સંચાર કરી શકે છે."</string>
+    <string name="bluetooth_empty_list_bluetooth_off" msgid="6255367297830430459">"જ્યારે બ્લૂટૂથ ચાલુ હોય, ત્યારે તમારું ડિવાઇસ નજીકનાં અન્ય બ્લૂટૂથ ડિવાઇસ સાથે સંચાર કરી શકે છે."</string>
     <string name="bluetooth_scanning_on_info_message" msgid="5460370815156050550">"જ્યારે બ્લૂટૂથ ચાલુ હોય, ત્યારે તમારું ઉપકરણ નજીકના અન્ય બ્લૂટૂથ ઉપકરણો સાથે સંચાર કરી શકે છે.\n\nતમારા ઉપકરણનો અનુભવ બહેતર બનાવવા માટે, જ્યારે બ્લૂટૂથ બંધ હોય ત્યારે પણ ઍપ અને સેવાઓ નજીકના ઉપકરણો માટે ગમે ત્યારે સ્કૅન કરી શકે છે. ઉદાહરણ તરીકે, આનો ઉપયોગ સ્થાન આધારિત સુવિધાઓ અને સેવાઓને બહેતર બનાવવા માટે કરી શકાય છે. તમે આને "<annotation id="link">"સ્કૅનીંગ સેટિંગ"</annotation>"માં બદલી શકો છો."</string>
     <string name="ble_scan_notify_text" msgid="6290170236546386932">"સ્થાન સચોટતા બહેતર બનાવવા માટે, સિસ્ટમ ઍપ્લિકેશનો અને સેવાઓ હજી પણ બ્લૂટૂથ ઉપકરણો શોધી શકે છે. તમે આને <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>સ્કેનિંગ સેટિંગ્સ<xliff:g id="LINK_END_1">LINK_END</xliff:g>માં બદલી શકો છો."</string>
     <string name="bluetooth_connect_failed" msgid="1151234676456333786">"કનેક્ટ ન કરી શક્યાં. ફરી પ્રયાસ કરો."</string>
-    <string name="device_details_title" msgid="726517818032923222">"ઉપકરણની વિગતો"</string>
-    <string name="bluetooth_device_mac_address" msgid="5328203122581150405">"ઉપકરણનું બ્લૂટૂથ ઍડ્રેસ: <xliff:g id="ADDRESS">%1$s</xliff:g>"</string>
+    <string name="device_details_title" msgid="726517818032923222">"ડિવાઇસની વિગતો"</string>
+    <string name="bluetooth_device_mac_address" msgid="5328203122581150405">"ડિવાઇસનું બ્લૂટૂથ ઍડ્રેસ: <xliff:g id="ADDRESS">%1$s</xliff:g>"</string>
     <string name="bluetooth_unpair_dialog_title" msgid="3669848977755142047">"ઉપકરણને ભૂલી જઈએ?"</string>
     <string name="bluetooth_unpair_dialog_body" product="default" msgid="5998071227980078077">"હવેથી તમારા ફોનની <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ની સાથે જોડી કરવામાં નહીં આવે"</string>
     <string name="bluetooth_unpair_dialog_body" product="tablet" msgid="4696157463230518866">"હવેથી તમારા ટૅબ્લેટની <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ની સાથે જોડી કરવામાં નહીં આવે"</string>
@@ -798,7 +800,7 @@
     <string name="bluetooth_max_connected_audio_devices_dialog_title" msgid="6049527354499590314">"મહત્તમ સંખ્યામાં કનેક્ટ થયેલા બ્લૂટૂથ ઑડિઓ ઉપકરણો પસંદ કરો"</string>
     <string name="wifi_display_settings_title" msgid="8718182672694575456">"કાસ્ટ કરો"</string>
     <string name="wifi_display_enable_menu_item" msgid="4578340247147692250">"વાયરલેસ ડિસ્પ્લે સક્ષમ કરો"</string>
-    <string name="wifi_display_no_devices_found" msgid="186501729518830451">"કોઈ નજીકના ઉપકરણો મળ્યાં નથી"</string>
+    <string name="wifi_display_no_devices_found" msgid="186501729518830451">"કોઈ નજીકના ડિવાઇસ મળ્યાં નથી"</string>
     <string name="wifi_display_status_connecting" msgid="3799827425457383349">"કનેક્ટ થઈ રહ્યું છે"</string>
     <string name="wifi_display_status_connected" msgid="85692409327461403">"કનેક્ટ કર્યું"</string>
     <string name="wifi_display_status_in_use" msgid="7646114501132773174">"ઉપયોગમાં છે"</string>
@@ -858,9 +860,9 @@
     <string name="use_open_wifi_automatically_summary" msgid="8338020172673161754">"ઉચ્ચ ગુણવત્તાવાળા સાર્વજનિક નેટવર્ક સાથે આપમેળે કનેક્ટ કરો"</string>
     <string name="use_open_wifi_automatically_summary_scoring_disabled" msgid="1559329344492373028">"આ સુવિધાનો ઉપયોગ કરવા માટે, નેટવર્ક રેટિંગ પ્રદાતાને પસંદ કરો"</string>
     <string name="use_open_wifi_automatically_summary_scorer_unsupported_disabled" msgid="1123080670578756834">"આ સુવિધાનો ઉપયોગ કરવા માટે, સુસંગત નેટવર્ક રેટિંગ પ્રદાતાને પસંદ કરો"</string>
-    <string name="wifi_install_credentials" msgid="5650088113710858289">"પ્રમાણપત્રો ઇન્સ્ટોલ કરો"</string>
+    <string name="wifi_install_credentials" msgid="5650088113710858289">"પ્રમાણપત્રો ઇન્સ્ટૉલ કરો"</string>
     <string name="wifi_scan_notify_text" msgid="7614101215028336927">"સ્થાન સચોટતાને બહેતર બનાવવા માટે, જ્યારે વાઇ-ફાઇ બંધ હોય ત્યારે પણ ઍપ અને સેવાઓ વાઇ-ફાઇ નેટવર્ક માટે ગમે ત્યારે સ્કૅન કરી શકે છે. ઉદાહરણ તરીકે, આનો ઉપયોગ સ્થાન આધારિત સુવિધાઓ અને સેવાઓને બહેતર બનાવવા માટે કરી શકાય છે. તમે આને <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>સ્કૅનીંગ સેટિંગ<xliff:g id="LINK_END_1">LINK_END</xliff:g>માં બદલી શકો છો."</string>
-    <string name="wifi_scan_notify_text_scanning_off" msgid="723796963816095410">"સ્થાનની સચોટતા સુધારવા માટે, <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>સ્કૅનીંગ સેટિંગ્સ<xliff:g id="LINK_END_1">LINK_END</xliff:g> માં જઈને વાઇ-ફાઇ સ્કૅનિંગ ચાલુ કરો."</string>
+    <string name="wifi_scan_notify_text_scanning_off" msgid="723796963816095410">"સ્થાનની સચોટતા સુધારવા માટે, <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>સ્કૅનિંગ સેટિંગ<xliff:g id="LINK_END_1">LINK_END</xliff:g> માં જઈને વાઇ-ફાઇ સ્કૅનિંગ ચાલુ કરો."</string>
     <string name="wifi_scan_notify_remember_choice" msgid="1235445971400237444">"ફરીથી બતાવશો નહીં"</string>
     <string name="wifi_setting_sleep_policy_title" msgid="2120785188625932076">"નિષ્ક્રિય દરમ્યાન વાઇ-ફાઇ ચાલુ રાખો"</string>
     <string name="wifi_setting_on_during_sleep_title" msgid="856670183023402715">"નિષ્ક્રિય હોય તે દરમ્યાન વાઇ-ફાઇ ચાલુ"</string>
@@ -876,7 +878,7 @@
     <string name="wifi_configure_settings_preference_title" msgid="2678534679408777268">"વાઇ-ફાઇ પસંદગીઓ"</string>
     <string name="wifi_configure_settings_preference_summary_wakeup_on" msgid="5714892572614655675">"વાઇ-ફાઇ ફરી આપમેળે ચાલુ થાય છે"</string>
     <string name="wifi_configure_settings_preference_summary_wakeup_off" msgid="286904094152909651">"વાઇ-ફાઇ પાછું આપમેળે ચાલુ થતું નથી"</string>
-    <string name="wifi_access_points" msgid="1647976498906871869">"વાઇ-ફાઇ નેટવર્ક્સ"</string>
+    <string name="wifi_access_points" msgid="1647976498906871869">"વાઇ-ફાઇ નેટવર્ક"</string>
     <string name="wifi_menu_more_options" msgid="8318269834264035524">"વધુ વિકલ્પો"</string>
     <string name="wifi_menu_p2p" msgid="4945665601551289791">"વાઇ-ફાઇ ડાઇરેક્ટ"</string>
     <string name="wifi_menu_scan" msgid="9082691677803181629">"સ્કેન"</string>
@@ -886,8 +888,8 @@
     <string name="wifi_menu_remember" msgid="717257200269700641">"નેટવર્ક યાદ રાખો"</string>
     <string name="wifi_menu_forget" msgid="7561140554450163075">"નેટવર્કને ભૂલી જાઓ"</string>
     <string name="wifi_menu_modify" msgid="4080178040721021101">"નેટવર્ક સંશોધિત કરો"</string>
-    <string name="wifi_empty_list_wifi_off" msgid="272877164691346240">"ઉપલબ્ધ નેટવર્ક્સ જોવા માટે, વાઇ-ફાઇ ચાલુ કરો."</string>
-    <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"વાઇ-ફાઇ નેટવર્ક્સ માટે શોધી રહ્યું છે..."</string>
+    <string name="wifi_empty_list_wifi_off" msgid="272877164691346240">"ઉપલબ્ધ નેટવર્ક જોવા માટે, વાઇ-ફાઇ ચાલુ કરો."</string>
+    <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"વાઇ-ફાઇ નેટવર્ક માટે શોધી રહ્યું છે..."</string>
     <string name="wifi_empty_list_user_restricted" msgid="2341613007817352431">"તમને વાઇ-ફાઇ નેટવર્ક બદલવાની પરવાનગી નથી."</string>
     <string name="wifi_more" msgid="3538241640407382185">"વધુ"</string>
     <string name="wifi_setup_wps" msgid="6730131677695521321">"ઑટોમૅટિક સેટઅપ (WPS)"</string>
@@ -1022,7 +1024,7 @@
     <string name="wifi_details_subnet_mask" msgid="53396707004763012">"સબનેટ માસ્ક"</string>
     <string name="wifi_details_dns" msgid="1118251455740116559">"DNS"</string>
     <string name="wifi_details_ipv6_address_header" msgid="1642310137145363299">"IPv6 સરનામા"</string>
-    <string name="wifi_saved_access_points_label" msgid="3790693285928292563">"સાચવેલા નેટવર્ક્સ"</string>
+    <string name="wifi_saved_access_points_label" msgid="3790693285928292563">"સાચવેલા નેટવર્ક"</string>
     <string name="wifi_subscribed_access_points_tab" msgid="7498765485953257229">"સબ્સ્ક્રિપ્શન"</string>
     <!-- no translation found for wifi_saved_access_points_tab (4677730543624191122) -->
     <skip />
@@ -1044,7 +1046,7 @@
     <string name="wifi_p2p_menu_search" msgid="8207638860263805291">"ઉપકરણો શોધો"</string>
     <string name="wifi_p2p_menu_searching" msgid="7443249001543208106">"શોધી રહ્યું છે..."</string>
     <string name="wifi_p2p_menu_rename" msgid="2129974878377065488">"ઉપકરણનું નામ બદલો"</string>
-    <string name="wifi_p2p_peer_devices" msgid="8232126067045093382">"પીઅર ઉપકરણો"</string>
+    <string name="wifi_p2p_peer_devices" msgid="8232126067045093382">"પીઅર ડિવાઇસ"</string>
     <string name="wifi_p2p_remembered_groups" msgid="1356458238836730346">"યાદ રાખેલ જૂથો"</string>
     <string name="wifi_p2p_failed_connect_message" msgid="6103436959132424093">"કનેક્ટ કરી શકાયું નહીં."</string>
     <string name="wifi_p2p_failed_rename_message" msgid="638656605352538706">"ઉપકરણનું નામ બદલવામાં નિષ્ફળ."</string>
@@ -1067,7 +1069,7 @@
     <string name="wifi_hotspot_ap_band_title" msgid="3485744480410441949">"AP બૅન્ડ"</string>
     <string name="wifi_hotspot_footer_info_regular" msgid="3876006922622827363">"તમારા અન્ય ઉપકરણો માટે વાઇ-ફાઇ નેટવર્ક બનાવવા હૉટસ્પૉટનો ઉપયોગ કરો. હૉટસ્પૉટ તમારા મોબાઇલ ડેટા કનેક્શનનો ઉપયોગ કરીને ઇન્ટરનેટ પૂરું પાડે છે. વધારાનો મોબાઇલ ડેટા શુલ્ક લાગુ થઈ શકે છે."</string>
     <string name="wifi_hotspot_footer_info_local_only" msgid="3339582350894639261">"ઍપ્લિકેશનો નજીકના ઉપકરણો સાથે કન્ટેન્ટ શેર કરવા માટે હૉટસ્પૉટ બનાવી શકે છે."</string>
-    <string name="wifi_hotspot_auto_off_title" msgid="7416022590415189590">"હૉટસ્પૉટ આપમેળે બંધ કરો"</string>
+    <string name="wifi_hotspot_auto_off_title" msgid="7416022590415189590">"હૉટસ્પૉટ ઑટોમૅટિક રીતે બંધ કરો"</string>
     <string name="wifi_hotspot_auto_off_summary" msgid="3866769400624802105">"જો કોઈ ઉપકરણો કનેક્ટ થયેલા ન હશે તો વાઇ-ફાઇ હૉટસ્પૉટ બંધ થઈ જશે"</string>
     <string name="wifi_tether_starting" msgid="7676952148471297900">"હૉટસ્પૉટ ચાલુ કરી રહ્યું છે…"</string>
     <string name="wifi_tether_stopping" msgid="7478561853791953349">"હૉટસ્પૉટ બંધ કરી રહ્યું છે…"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"વાઇ-ફાઇ"</item>
+    <item msgid="2271962426654621656">"મોબાઇલ"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"વાઇ-ફાઇ ઉપલબ્ધ ન હોય, તો મોબાઇલ નેટવર્કનો ઉપયોગ કરો"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"મોબાઇલ નેટવર્ક ઉપલબ્ધ ન હોય, તો વાઇ-ફાઇનો ઉપયોગ કરો"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"વાઇ-ફાઇ પરથી કૉલ કરો. વાઇ-ફાઇ જતું રહેશે, તો કૉલ સમાપ્ત થઈ જશે."</string>
@@ -1115,17 +1120,17 @@
     <string name="wifi_calling_not_supported" msgid="216781767605669775">"%1$s માટે વાઇ-ફાઇ કૉલિંગ સમર્થિત નથી"</string>
     <string name="carrier" msgid="3413463182542176886">"કૅરિઅર"</string>
     <string name="display_settings_title" msgid="1243571562133261601">"ડિસ્પ્લે"</string>
-    <string name="sound_settings" msgid="3306063041029638807">"ધ્વનિ"</string>
+    <string name="sound_settings" msgid="3306063041029638807">"સાઉન્ડ"</string>
     <string name="all_volume_title" msgid="1750261506951315423">"વૉલ્યૂમ્સ"</string>
     <string name="musicfx_title" msgid="6456079041566773649">"સંગીત પ્રભાવો"</string>
     <string name="ring_volume_title" msgid="5874791723449821646">"રિંગ વૉલ્યુમ"</string>
     <string name="vibrate_in_silent_title" msgid="2314667015729841220">"શાંત હોય ત્યારે વાઇબ્રેટ કરો"</string>
-    <string name="notification_sound_title" msgid="6812164482799723931">"નોટિફિકેશન માટે ડિફૉલ્ટ ધ્વનિ"</string>
+    <string name="notification_sound_title" msgid="6812164482799723931">"ડિફૉલ્ટ નોટિફિકેશન સાઉન્ડ"</string>
     <string name="incoming_call_volume_title" msgid="4736570528754310450">"રિંગટોન"</string>
     <string name="notification_volume_title" msgid="6022562909288085275">"નોટિફિકેશન"</string>
     <string name="checkbox_notification_same_as_incoming_call" msgid="7312942422655861175">"સૂચનાઓ માટે ઇનકમિંગ કૉલ વોલ્યુમનો ઉપયોગ કરો"</string>
     <string name="home_work_profile_not_supported" msgid="6137073723297076818">"કાર્ય પ્રોફાઇલ્સનું સમર્થન કરતું નથી"</string>
-    <string name="notification_sound_dialog_title" msgid="6653341809710423276">"નોટિફિકેશન માટે ડિફૉલ્ટ ધ્વનિ"</string>
+    <string name="notification_sound_dialog_title" msgid="6653341809710423276">"ડિફૉલ્ટ નોટિફિકેશન સાઉન્ડ"</string>
     <string name="media_volume_title" msgid="1030438549497800914">"મીડિયા"</string>
     <string name="media_volume_summary" msgid="3142433516297061652">"સંગીત અને વીડિઓ માટે વોલ્યૂમ સેટ કરો"</string>
     <string name="alarm_volume_title" msgid="8902277801531496243">"એલાર્મ"</string>
@@ -1137,7 +1142,7 @@
     <string name="volume_media_description" msgid="3659485559976891268">"સંગીત, વીડિઓ, રમતો, અને અને અન્ય મીડિયા"</string>
     <string name="volume_ring_description" msgid="1975431532517579212">"રિંગટોન અને સૂચનાઓ"</string>
     <string name="volume_notification_description" msgid="8871940450828766751">"નોટિફિકેશનો"</string>
-    <string name="volume_alarm_description" msgid="3230692343946237658">"એલાર્મ્સ"</string>
+    <string name="volume_alarm_description" msgid="3230692343946237658">"એલાર્મ"</string>
     <string name="volume_ring_mute" msgid="6022038055768721847">"રિંગટોન અને સૂચનાઓ મ્યૂટ કરો"</string>
     <string name="volume_media_mute" msgid="816848304566175614">"સંગીત અને અન્ય મીડિયાને મ્યૂટ કરો"</string>
     <string name="volume_notification_mute" msgid="7759564556421535211">"સૂચનાઓ મ્યૂટ કરો"</string>
@@ -1304,7 +1309,7 @@
     <string name="pin_failed" msgid="4877356137480446727">"સિમ પિન ઑપરેશન નિષ્ફળ થયું!"</string>
     <string name="system_update_settings_list_item_title" msgid="1907497454722790033">"સિસ્ટમ અપડેટ્સ"</string>
     <string name="system_update_settings_list_item_summary" msgid="3497456690691907873"></string>
-    <string name="firmware_version" msgid="547095584029938749">"Android સંસ્કરણ"</string>
+    <string name="firmware_version" msgid="547095584029938749">"Android વર્ઝન"</string>
     <string name="security_patch" msgid="483709031051932208">"Android સુરક્ષા પૅચ સ્તર"</string>
     <string name="model_info" msgid="1729765474260797594">"મોડલ"</string>
     <string name="model_summary" msgid="8781425868254352168">"મૉડલ: %1$s"</string>
@@ -1366,7 +1371,7 @@
     <string name="memory_calculating_size" msgid="8407591625479256510">"ગણતરી કરી રહ્યું છે..."</string>
     <string name="memory_apps_usage" msgid="1886814780760368266">"ઍપ્લિકેશનો અને ઍપ્લિકેશન ડેટા"</string>
     <string name="memory_media_usage" msgid="2744652206722240527">"મીડિયા"</string>
-    <string name="memory_downloads_usage" msgid="7039979723012065168">"ડાઉનલોડ્સ"</string>
+    <string name="memory_downloads_usage" msgid="7039979723012065168">"ડાઉનલોડ"</string>
     <string name="memory_dcim_usage" msgid="599009211606524732">"ચિત્રો, વિડિઓઝ"</string>
     <string name="memory_music_usage" msgid="809605300042546279">"ઑડિઓ (સંગીત, રિંગટોન્સ, પોડકાસ્ટ્સ વગેરે)"</string>
     <string name="memory_media_misc_usage" msgid="6258827529046910705">"અન્ય ફાઇલો"</string>
@@ -1453,7 +1458,7 @@
     <string name="storage_detail_system" msgid="6784247618772153283">"સિસ્ટમ"</string>
     <string name="storage_detail_explore" msgid="8206900269596580264">"<xliff:g id="NAME">^1</xliff:g> નું અન્વેષણ કરો"</string>
     <string name="storage_detail_dialog_other" msgid="5073511663616043370">"ઍપ દ્વારા સાચવવામાં આવેલ શેર કરેલ ફાઇલો, ઇન્ટરનેટ અથવા બ્લૂટૂથ વડે ડાઉનલોડ કરેલ ફાઇલો, Android ફાઇલો અને આના જેવી વધુ ફાઇલો અન્યમાં શામેલ હોય છે. \n\nઆ <xliff:g id="NAME">^1</xliff:g>નું દૃશ્યક્ષમ કન્ટેન્ટ જોવા માટે શોધખોળ કરો પર ટૅપ કરો."</string>
-    <string name="storage_detail_dialog_system" msgid="1472572861360014226">"સિસ્ટમમાં Android સંસ્કરણ <xliff:g id="VERSION">%s</xliff:g> ચલાવવા માટે ઉપયોગી ફાઇલોનો સમાવેશ છે"</string>
+    <string name="storage_detail_dialog_system" msgid="1472572861360014226">"સિસ્ટમમાં Android વર્ઝન <xliff:g id="VERSION">%s</xliff:g> ચલાવવા માટે ઉપયોગી ફાઇલોનો સમાવેશ છે"</string>
     <string name="storage_detail_dialog_user" msgid="1663117417635010371">"<xliff:g id="USER_0">^1</xliff:g>એ <xliff:g id="SIZE">^2</xliff:g> સ્ટોરેજનો ઉપયોગ કરીને ફોટો, સંગીત, ઍપ્લિકેશનો અથવા અન્ય ડેટા સાચવ્યો હોઈ શકે છે.\n\nવિગતો જોવા માટે, <xliff:g id="USER_1">^1</xliff:g> પર સ્વિચ કરો."</string>
     <string name="storage_wizard_init_title" msgid="3407283236421089014">"તમારું <xliff:g id="NAME">^1</xliff:g> સેટ કરો"</string>
     <string name="storage_wizard_init_external_title" msgid="6853250619674645478">"પોર્ટેબલ સંગ્રહ તરીકે ઉપયોગ કરો"</string>
@@ -1564,9 +1569,9 @@
     <string name="menu_restore" msgid="3799288817317293115">"ડીફોલ્ટ પર ફરીથી સેટ કરો"</string>
     <string name="restore_default_apn_completed" msgid="5671734152740058937">"ડિફોલ્ટ APN સેટિંગ્સ ફરીથી સેટ કરો પૂર્ણ થયું."</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"રીસેટ માટેના વિકલ્પો"</string>
-    <string name="reset_dashboard_summary" msgid="8778383341461126642">"નેટવર્ક, ઍપ અથવા ઉપકરણ રીસેટ કરી શકાય છે"</string>
+    <string name="reset_dashboard_summary" msgid="8778383341461126642">"નેટવર્ક, ઍપ અથવા ડિવાઇસ રીસેટ કરી શકાય છે"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"વાઇ-ફાઇ, મોબાઇલ અને બ્લૂટૂથ રીસેટ કરો"</string>
-    <string name="reset_network_desc" msgid="4982633363916261109">"આ બધી નેટવર્ક સેટિંગ્સ ફરીથી સેટ કરશે, જેમાં સમાવિષ્ટ છે: \n\n"<li>"Wi‑Fi"</li>\n<li>"મોબાઇલ ડેટા"</li>\n<li>"Bluetooth"</li></string>
+    <string name="reset_network_desc" msgid="4982633363916261109">"આ બધા નેટવર્ક સેટિંગ રીસેટ કરશે, જેમાં આનો સમાવેશ છે: \n\n"<li>"Wi‑Fi"</li>\n<li>"મોબાઇલ ડેટા"</li>\n<li>"Bluetooth"</li></string>
     <string name="reset_esim_title" msgid="7630781767040831893">"ડાઉનલોડ કરેલાં સિમ કાઢી નખાશે"</string>
     <string name="reset_esim_desc" msgid="433226911566802">"બદલીને લેવાના સિમ ડાઉનલોડ કરવા માટે, તમારા કૅરિઅરનો સંપર્ક કરો. આનાથી કોઈપણ મોબાઇલ સેવા પ્લાન રદ થશે નહીં."</string>
     <string name="reset_network_button_text" msgid="4293271046867912819">"સેટિંગ્સ ફરીથી સેટ કરો"</string>
@@ -1578,7 +1583,7 @@
     <string name="reset_network_complete_toast" msgid="128225929536005495">"નેટવર્ક સેટિંગ્સ ફરીથી સેટ કરવામાં આવી છે"</string>
     <string name="reset_esim_error_title" msgid="4728931209471875632">"સિમ કાઢી નાખી શકાતાં નથી"</string>
     <string name="reset_esim_error_msg" msgid="4716366079119742235">"ડાઉનલોડ કરેલાં સિમ ભૂલને કારણે કાઢી નાખી શકાતાં નથી.\n\nતમારું ડિવાઇસ ફરી શરૂ કરો અને ફરી પ્રયાસ કરો."</string>
-    <string name="master_clear_title" msgid="1560712943955904673">"બધો ડેટા ભૂંસી નાખો (ફેક્ટરી રીસેટ)"</string>
+    <string name="master_clear_title" msgid="1560712943955904673">"બધો ડેટા કાઢી નાખો (ફેક્ટરી રીસેટ)"</string>
     <string name="master_clear_short_title" msgid="919098101581335101">"બધો ડેટા કાઢી નાખો (ફેક્ટરી રીસેટ)"</string>
     <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"આ ક્રિયા તમારા ટૅબ્લેટના "<b>"આંતરિક સ્ટોરેજ"</b>"માંથી બધો ડેટા કાઢી નાખશે, જેમાં આનો સમાવેશ થાય છે:\n\n"<li>"તમારું Google એકાઉન્ટ"</li>\n<li>"સિસ્ટમ તેમજ ઍપ ડેટા અને સેટિંગ"</li>\n<li>"ડાઉનલોડ કરેલી ઍપ"</li></string>
     <string name="master_clear_desc" product="default" msgid="8765543541962866697">"આ ક્રિયા તમારા ફોનના "<b>"આંતરિક સ્ટોરેજ"</b>"માંથી બધો ડેટા કાઢી નાખશે, જેમાં આનો સમાવેશ થાય છે:\n\n"<li>"તમારું Google એકાઉન્ટ"</li>\n<li>"સિસ્ટમ તેમજ ઍપ ડેટા અને સેટિંગ"</li>\n<li>"ડાઉનલોડ કરેલી ઍપ"</li></string>
@@ -1603,7 +1608,7 @@
     <string name="master_clear_not_available" msgid="4676613348163652454">"આ વપરાશકર્તા માટે ફેક્ટરી રીસેટ ઉપલબ્ધ નથી"</string>
     <string name="master_clear_progress_title" msgid="378953167274114857">"કાઢી નાંખી રહ્યું છે"</string>
     <string name="master_clear_progress_text" msgid="5418958116008976218">"કૃપા કરીને રાહ જુઓ..."</string>
-    <string name="call_settings_title" msgid="5033906789261282752">"કૉલ સેટિંગ્સ"</string>
+    <string name="call_settings_title" msgid="5033906789261282752">"કૉલ સેટિંગ"</string>
     <string name="call_settings_summary" msgid="2119161087671450035">"વૉઇસમેઇલ, કૉલ ફોરવર્ડિંગ, કૉલ પ્રતીક્ષા, કૉલર ID સેટ કરો"</string>
     <string name="tether_settings_title_usb" msgid="4265582654602420357">"USB ટિથરિંગ"</string>
     <string name="tether_settings_title_wifi" msgid="2060965130234484613">"પોર્ટેબલ હૉટસ્પૉટ"</string>
@@ -1642,7 +1647,7 @@
     <string name="mobile_insert_sim_card" msgid="7594550403454243732">"કૃપા કરીને સિમ કાર્ડ શામેલ કરો અને પુનઃપ્રારંભ કરો"</string>
     <string name="mobile_connect_to_internet" msgid="6031886097365170913">"કૃપા કરીને ઇન્ટરનેટ સાથે કનેક્ટ કરો"</string>
     <string name="location_title" msgid="8664674161765477168">"મારું સ્થાન"</string>
-    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"કાર્યાલયની પ્રોફાઇલ માટે સ્થાન"</string>
+    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"ઑફિસની પ્રોફાઇલ માટે સ્થાન"</string>
     <string name="location_app_level_permissions" msgid="1298041503927632960">"ઍપ પરવાનગી"</string>
     <string name="location_app_permission_summary_location_off" msgid="541372845344796336">"સ્થાન બંધ છે"</string>
     <plurals name="location_app_permission_summary_location_on" formatted="false" msgid="7904821382328758218">
@@ -1711,7 +1716,7 @@
     <string name="lockpassword_confirm_your_password_header" msgid="9055242184126838887">"તમારો પાસવર્ડ ફરી દાખલ કરો"</string>
     <string name="lockpassword_confirm_your_pattern_header" msgid="7137526922696316545">"તમારા પેટર્નની પુષ્ટિ કરો"</string>
     <string name="lockpassword_confirm_your_pin_header" msgid="4335593948303036343">"તમારો પિન ફરી દાખલ કરો"</string>
-    <string name="lockpassword_confirm_passwords_dont_match" msgid="1783767008133345784">"પાસવર્ડ્સ મેળ ખાતા નથી"</string>
+    <string name="lockpassword_confirm_passwords_dont_match" msgid="1783767008133345784">"પાસવર્ડ મેળ ખાતા નથી"</string>
     <string name="lockpassword_confirm_pins_dont_match" msgid="5444357293637748942">"પિન મેળ ખાતા નથી"</string>
     <string name="lockpassword_draw_your_pattern_again_header" msgid="9017394036814402348">"તમારી પૅટર્ન ફરીથી દોરો"</string>
     <string name="lockpassword_choose_lock_generic_header" msgid="4418423132980560119">"અનલૉક પસંદગી"</string>
@@ -1866,7 +1871,7 @@
     <string name="join_two_unrelated_items" msgid="8257688498236358394">"<xliff:g id="FIRST_ITEM">%1$s</xliff:g>, <xliff:g id="SECOND_ITEM">%2$s</xliff:g>"</string>
     <string name="computing_size" msgid="2234106107535318136">"ગણતરી કરી રહ્યું છે…"</string>
     <string name="invalid_size_value" msgid="1202239724000802296">"પેકેજ કદની ગણતરી કરી શક્યાં નથી."</string>
-    <string name="version_text" msgid="5421619604445758652">"સંસ્કરણ <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+    <string name="version_text" msgid="5421619604445758652">"વર્ઝન <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
     <string name="move_app" msgid="5400135231255614785">"ખસેડો"</string>
     <string name="move_app_to_internal" product="tablet" msgid="8658767231643024635">"ટેબ્લેટ પર ખસેડો"</string>
     <string name="move_app_to_internal" product="default" msgid="1031111519418252055">"ફોન પર ખસેડો"</string>
@@ -1967,7 +1972,7 @@
     <string name="show_ime" msgid="7322620473198763563">"વર્ચ્યુઅલ કીબોર્ડ બતાવો"</string>
     <string name="show_ime_summary" msgid="3246628154011464373">"જ્યારે ભૌતિક કીબોર્ડ સક્રિય હોય ત્યારે તેને સ્ક્રીન પર રાખો"</string>
     <string name="keyboard_shortcuts_helper" msgid="6574386807271399788">"કીબોર્ડ શૉર્ટકટ્સ સહાયક"</string>
-    <string name="keyboard_shortcuts_helper_summary" msgid="8024313306403779742">"ઉપલબ્ધ શૉર્ટકટ્સ પ્રદર્શિત કરો"</string>
+    <string name="keyboard_shortcuts_helper_summary" msgid="8024313306403779742">"ઉપલબ્ધ શૉર્ટકટ પ્રદર્શિત કરો"</string>
     <string name="language_and_input_for_work_category_title" msgid="2053255944038892588">"કાર્યાલયનું પ્રોફાઇલ અને સાધનો"</string>
     <string name="virtual_keyboards_for_work_title" msgid="3968291646938204523">"કાર્ય માટે વર્ચ્યુઅલ કીબોર્ડ"</string>
     <string name="default_keyboard_layout" msgid="9171704064451242230">"ડિફોલ્ટ"</string>
@@ -1995,7 +2000,7 @@
     <string name="user_dict_settings_add_word_hint" msgid="4184010899351180735">"એક શબ્દ લખો"</string>
     <string name="user_dict_settings_add_shortcut_hint" msgid="2212771507741334156">"વૈકલ્પિક શોર્ટકટ"</string>
     <string name="user_dict_settings_edit_dialog_title" msgid="6492621665762797309">"શબ્દ સંપાદિત કરો"</string>
-    <string name="user_dict_settings_context_menu_edit_title" msgid="4577283176672181497">"સંપાદિત કરો"</string>
+    <string name="user_dict_settings_context_menu_edit_title" msgid="4577283176672181497">"ફેરફાર કરો"</string>
     <string name="user_dict_settings_context_menu_delete_title" msgid="670470172230144069">"ડિલીટ કરો"</string>
     <string name="user_dict_settings_empty_text" msgid="2774939221998982609">"તમારી પાસે વપરાશકર્તા શબ્દકોશમાં કોઈપણ શબ્દ નથી. શબ્દને ઉમેરવા માટે, ઉમેરો (+) બટન ટૅપ કરો."</string>
     <string name="user_dict_settings_all_languages" msgid="8839702015353418176">"તમામ ભાષાઓ માટે"</string>
@@ -2032,7 +2037,7 @@
     <string name="accessibility_settings" msgid="9140621093888234485">"ઍક્સેસિબિલિટી"</string>
     <string name="accessibility_settings_title" msgid="1687226556576913576">"ઍક્સેસિબિલિટી સેટિંગ્સ"</string>
     <string name="accessibility_settings_summary" msgid="5742379519336396561">"સ્ક્રીન રીડર, પ્રદર્શન, ક્રિયાપ્રતિક્રિયા સંબંધી નિયંત્રણો"</string>
-    <string name="vision_settings_title" msgid="7315352351051423944">"વિઝન સેટિંગ્સ"</string>
+    <string name="vision_settings_title" msgid="7315352351051423944">"વિઝન સેટિંગ"</string>
     <string name="vision_settings_description" msgid="3476589459009287332">"તમે તમારી જરૂરિયાતો મુજબ આ ઉપકરણને કસ્ટમાઇઝ કરી શકો છો. સેટિંગ્સમાં આ ઍક્સેસિબિલિટી સુવિધાઓ પછીથી બદલી શકાય છે."</string>
     <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"ફોન્ટનું કદ બદલો"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"સ્ક્રીન રીડર"</string>
@@ -2081,7 +2086,7 @@
     <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"તમારે વાંચવા જરૂરી હોય, પરંતુ હંગામી રૂપે દેખાતા સંદેશાને કેટલા સમય સુધી બતાવવા તે પસંદ કરો.\n\nઆ સેટિંગની સુવિધા બધી ઍપમાં નથી હોતી."</string>
     <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"તમને ક્રિયા કરવાનું કહેતાં હોય, પરંતુ હંગામી રૂપે દેખાતા સંદેશાને કેટલા સમય સુધી દેખાડવા તે પસંદ કરો.\n\nઆ સેટિંગની સુવિધા બધી ઍપમાં નથી હોતી."</string>
     <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"ટચ કરી અને પકડવા પર વિલંબ"</string>
-    <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"રંગ બદલવાની સુવિધા"</string>
+    <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"વિપરીત રંગમાં બદલવું"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"કાર્યપ્રદર્શનને અસર થઈ શકે છે"</string>
     <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"જોવાયાનો સમયગાળો"</string>
     <string name="accessibility_autoclick_description" msgid="5492414927846407499">"જો તમે માઉસનો ઉપયોગ કરી રહ્યાં હોય, તો જ્યારે કર્સર અમુક ચોક્કસ સમય માટે કાર્ય કરતું રોકાઈ જાય ત્યારે તમે તેને આપમેળે ક્રિયા કરવા માટે સેટ કરી શકો છો."</string>
@@ -2430,7 +2435,7 @@
     <string name="battery_detail_power_usage" msgid="3606930232257489212">"બૅટરી વપરાશ"</string>
     <string name="battery_detail_info_title" msgid="4617514228447481336">"સંપૂર્ણ ચાર્જ પછી"</string>
     <string name="battery_detail_manage_title" msgid="745194290572617507">"બૅટરી વપરાશ સંચાલિત કરો"</string>
-    <string name="advanced_battery_graph_subtext" msgid="3349760453669664057">"બાકી રહેલી બૅટરીનો અંદાજ ઉપકરણના તમારા ઉપયોગ પર આધારિત છે"</string>
+    <string name="advanced_battery_graph_subtext" msgid="3349760453669664057">"બાકી રહેલી બૅટરીનો અંદાજ ડિવાઇસના તમારા ઉપયોગ પર આધારિત છે"</string>
     <string name="estimated_time_left" msgid="8849913193475011250">"અંદાજિત બાકી સમય"</string>
     <string name="estimated_charging_time_left" msgid="7597080379844486777">"સંપૂર્ણપણે ચાર્જ થવામાં"</string>
     <string name="estimated_time_description" msgid="9220355793080184567">"વપરાશના આધારે અનુમાન બદલાઈ શકે છે"</string>
@@ -2560,18 +2565,18 @@
     <string name="fullbackup_erase_dialog_message" msgid="2588536036471144070">"ઉપકરણ ડેટા (જેમ કે વાઇ-ફાઇ પાસવર્ડ્સ અને કૉલ ઇતિહાસ) અને ઍપ્લિકેશન ડેટા (જેમ કે સેટિંગ્સ અને ઍપ્લિકેશનો દ્વારા સંગ્રહિત ફાઇલો) નું બેકઅપ લેવાનું રોકીએ, ઉપરાંત રિમોટ સર્વર્સ પરની તમામ કૉપિઝ કાઢી નાખીએ?"</string>
     <string name="fullbackup_data_summary" msgid="406274198094268556">"ઉપકરણ ડેટા (જેમ કે વાઇ-ફાઇ પાસવર્ડ્સ અને કૉલ ઇતિહાસ) અને ઍપ્લિકેશન ડેટા (જેમ કે સેટિંગ્સ અને ઍપ્લિકેશનો દ્વારા સંગ્રહિત ફાઇલો)નો રિમોટલી આપમેળે બેક અપ લો.\n\nજ્યારે તમે સ્વચલિત બેકઅપ ચાલુ કરો છો, ત્યારે ઉપકરણ અને ઍપ્લિકેશન ડેટા સમયાંતરે રિમોટલી સચવાય છે. ઍપ્લિકેશન ડેટા એવો કોઈપણ ડેટા હોઈ શકે જેને કોઈ ઍપ્લિકેશને સાચવ્યો હોય (વિકાસકર્તા સેટિંગ્સનાં આધારે) જેમાં સંપર્કો, સંદેશા અને ફોટો જેવા સંભવિતપણે સંવેદનશીલ ડેટાનો સમાવેશ થાય છે."</string>
     <string name="device_admin_settings_title" msgid="2074319456047334589">"ઉપકરણ વ્યવસ્થાપક સેટિંગ્સ"</string>
-    <string name="active_device_admin_msg" msgid="6929247869516924549">"ઉપકરણ વ્યવસ્થાપક ઍપ્લિકેશન"</string>
+    <string name="active_device_admin_msg" msgid="6929247869516924549">"ડિવાઇસ વ્યવસ્થાપક ઍપ્લિકેશન"</string>
     <string name="remove_device_admin" msgid="4413438593788336400">"આ ઉપકરણ વ્યવસ્થાપક ઍપ્લિકેશનને નિષ્ક્રિય કરો"</string>
     <string name="uninstall_device_admin" msgid="9017499299961719830">"ઍપ્લિકેશન અનઇન્સ્ટૉલ કરો"</string>
     <string name="remove_and_uninstall_device_admin" msgid="5607703579731496253">"નિષ્ક્રિય અને અનઇન્સ્ટૉલ કરો"</string>
     <string name="select_device_admin_msg" msgid="4173769638399075387">"ઉપકરણ વ્યવસ્થાપક ઍપ્લિકેશનો"</string>
     <string name="no_device_admins" msgid="4129231900385977460">"કોઈ ઉપકરણ વ્યવસ્થાપક ઍપ્લિકેશનો ઉપલબ્ધ નથી"</string>
     <string name="personal_device_admin_title" msgid="759440849188565661">"વ્યક્તિગત"</string>
-    <string name="managed_device_admin_title" msgid="8021522755492551726">"કાર્યાલય"</string>
+    <string name="managed_device_admin_title" msgid="8021522755492551726">"ઑફિસ"</string>
     <string name="sms_access_restriction_enabled" msgid="3006320256764718303">"SMS અને કૉલ લૉગનો અ‍ૅક્સેસ પ્રતિબંધિત કરો"</string>
     <string name="sms_access_restriction_enabled_summary" msgid="9011946580977780063">"માત્ર ડિફૉલ્ટ ફોન અને સંદેશ માટેની અ‍ૅપ પાસે SMS અને કૉલ લૉગની પરવાનગીઓ હોય છે"</string>
     <string name="no_trust_agents" msgid="5757792915019113084">"કોઈ ઉપલબ્ધ ટ્રસ્ટ એજન્ટ્સ નથી"</string>
-    <string name="add_device_admin_msg" msgid="3573765823476931173">"ઉપકરણ વ્યવસ્થાપક ઍપ્લિકેશન સક્રિય કરીએ?"</string>
+    <string name="add_device_admin_msg" msgid="3573765823476931173">"ડિવાઇસ વ્યવસ્થાપક ઍપ્લિકેશન સક્રિય કરીએ?"</string>
     <string name="add_device_admin" msgid="1621152410207260584">"આ ઉપકરણ વ્યવસ્થાપક ઍપ્લિકેશન સક્રિય કરો"</string>
     <string name="device_admin_add_title" msgid="6097881332139146897">"ઉપકરણ વ્યવસ્થાપક"</string>
     <string name="device_admin_warning" msgid="4421817419326480449">"આ વ્યવસ્થાપક ઍપ્લિકેશનને સક્રિય કરવું ઍપ્લિકેશન <xliff:g id="APP_NAME">%1$s</xliff:g>ને નીચેની ક્રિયાઓ કરવાની મંજૂરી આપશે:"</string>
@@ -2593,10 +2598,10 @@
     <string name="sync_is_failing" msgid="8284618104132302644">"સમન્વયનમાં હાલમાં સમસ્યા આવી રહી છે. તે ટૂંક સમયમાં પાછું આવશે."</string>
     <string name="add_account_label" msgid="4461298847239641874">"એકાઉન્ટ ઉમેરો"</string>
     <string name="managed_profile_not_available_label" msgid="8784246681719821917">"કાર્યાલયની પ્રોફાઇલ હજી સુધી ઉપલબ્ધ નથી"</string>
-    <string name="work_mode_label" msgid="6845849194740195757">"કાર્યાલયની પ્રોફાઇલ"</string>
+    <string name="work_mode_label" msgid="6845849194740195757">"ઑફિસની પ્રોફાઇલ"</string>
     <string name="work_mode_on_summary" msgid="1682781113156323592">"તમારી સંસ્થા દ્વારા મેનેજ કરેલ"</string>
     <string name="work_mode_off_summary" msgid="1688885392211178315">"ઍપ અને નોટિફિકેશન બંધ છે"</string>
-    <string name="remove_managed_profile_label" msgid="4625542553784793536">"કાર્યાલયની પ્રોફાઇલ દૂર કરો"</string>
+    <string name="remove_managed_profile_label" msgid="4625542553784793536">"ઑફિસની પ્રોફાઇલ દૂર કરો"</string>
     <string name="background_data" msgid="8275750862371471171">"બૅકગ્રાઉન્ડ ડેટા"</string>
     <string name="background_data_summary" msgid="799640633948841990">"ઍપ્લિકેશનો કોઈપણ સમયે ડેટાને સમન્વયિત, મોકલી અને પ્રાપ્ત કરી શકે છે"</string>
     <string name="background_data_dialog_title" msgid="8306650658158895976">"બૅકગ્રાઉન્ડ ડેટાને અક્ષમ કરીએ?"</string>
@@ -2665,8 +2670,8 @@
     <string name="data_usage_menu_sim_cards" msgid="8508154611676507088">"સિમ કાર્ડ"</string>
     <string name="data_usage_cellular_data_summary" msgid="9162777397135709280">"થોભાવવાની મર્યાદા"</string>
     <string name="account_settings_menu_auto_sync" msgid="2673669556006027506">"ડેટાને આપમેળે સિંક કરો"</string>
-    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"વ્યક્તિગત ડેટાને આપમેળે સિંક કરો"</string>
-    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"કાર્યાલયના ડેટાને આપમેળે સિંક કરો"</string>
+    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"વ્યક્તિગત ડેટાને ઑટો સિંક કરો"</string>
+    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"ઑફિસના ડેટાને ઑટો સિંક કરો"</string>
     <string name="data_usage_change_cycle" msgid="447761920472170031">"ચક્ર બદલો…"</string>
     <string name="data_usage_pick_cycle_day" msgid="6319750879145917066">"ડેટા વપરાશ ચક્ર ફરીથી સેટ કરવા માટે મહિનાનો દિવસ:"</string>
     <string name="data_usage_empty" msgid="7981405723435034032">"આ સમયગાળા દરમ્યાન કોઈ એપ્લિકેશને ડેટાનો ઉપયોગ કર્યો નથી."</string>
@@ -2769,7 +2774,7 @@
     <string name="vpn_connect_to" msgid="7926776854873218762">"<xliff:g id="PROFILE">%s</xliff:g> સાથે કનેક્ટ કરો"</string>
     <string name="vpn_disconnect_confirm" msgid="3505111947735651082">"આ VPNને ડિસ્કનેક્ટ કરીએ?"</string>
     <string name="vpn_disconnect" msgid="4625914562388652486">"ડિસ્કનેક્ટ કરો"</string>
-    <string name="vpn_version" msgid="2006792987077940456">"સંસ્કરણ <xliff:g id="VERSION">%s</xliff:g>"</string>
+    <string name="vpn_version" msgid="2006792987077940456">"વર્ઝન <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="8457511440635534478">"VPN ભૂલી ગયાં"</string>
     <string name="vpn_replace_vpn_title" msgid="8517436922021598103">"અસ્તિત્વમાંની VPN ને બદલીએ?"</string>
     <string name="vpn_set_vpn_title" msgid="6483554732067951052">"હંમેશાં ચાલુ VPN સેટ કરીએ?"</string>
@@ -2865,10 +2870,10 @@
     <string name="user_add_user_item_title" msgid="6835385073795492410">"વપરાશકર્તા"</string>
     <string name="user_add_profile_item_title" msgid="4932743891449790664">"પ્રતિબંધિત પ્રોફાઇલ"</string>
     <string name="user_add_user_title" msgid="2320897397066676472">"નવા વપરાશકર્તાને ઉમેરીએ?"</string>
-    <string name="user_add_user_message_long" msgid="686637203224195465">"તમે વધારાના વપરાશકર્તાઓ બનાવીને અન્ય લોકો સાથે આ ઉપકરણને શેર કરી શકો છો. દરેક વપરાશકર્તા પાસે તેમની પોતાની સ્પેસ છે, જેને તેઓ ઍપ, વૉલપેપર, વગેરે સાથે કસ્ટમાઇઝ કરી શકે છે. વપરાશકર્તાઓ પ્રત્યેક વ્યક્તિને અસર કરતી હોય તેવી ઉપકરણ સેટિંગ જેમ કે વાઇ-ફાઇને પણ સમાયોજિત કરી શકે છે.\n\nજ્યારે તમે કોઈ નવા વપરાશકર્તાને ઉમેરો છો, ત્યારે તે વ્યક્તિને તેમની સ્પેસ સેટ કરવાની જરૂર પડે છે.\n\nકોઈપણ વપરાશકર્તા અન્ય બધા વપરાશકર્તાઓ માટે ઍપને અપડેટ કરી શકે છે. નવા વપરાશકર્તાને ઍક્સેસિબિલિટી સેટિંગ અને સેવાઓ ટ્રાન્સફર ન પણ થાય."</string>
+    <string name="user_add_user_message_long" msgid="686637203224195465">"તમે વધારાના વપરાશકર્તાઓ બનાવીને અન્ય લોકો સાથે આ ડિવાઇસને શેર કરી શકો છો. દરેક વપરાશકર્તા પાસે તેમની પોતાની સ્પેસ છે, જેને તેઓ ઍપ, વૉલપેપર, વગેરે સાથે કસ્ટમાઇઝ કરી શકે છે. વપરાશકર્તાઓ પ્રત્યેક વ્યક્તિને અસર કરતી હોય તેવી ડિવાઇસ સેટિંગ જેમ કે વાઇ-ફાઇને પણ સમાયોજિત કરી શકે છે.\n\nજ્યારે તમે કોઈ નવા વપરાશકર્તાને ઉમેરો છો, ત્યારે તે વ્યક્તિને તેમની સ્પેસ સેટ કરવાની જરૂર પડે છે.\n\nકોઈપણ વપરાશકર્તા અન્ય બધા વપરાશકર્તાઓ માટે ઍપને અપડેટ કરી શકે છે. નવા વપરાશકર્તાને ઍક્સેસિબિલિટી સેટિંગ અને સેવાઓ ટ્રાન્સફર ન પણ થાય."</string>
     <string name="user_add_user_message_short" msgid="1802594476285458254">"જ્યારે તમે કોઈ નવા વપરાશકર્તાને ઉમેરો છો, ત્યારે તે વ્યક્તિને તેમનું સ્થાન સેટ અપ કરવાની જરૂર પડે છે.\n\nકોઈપણ વપરાશકર્તા બધા અન્ય વપરાશકર્તાઓ માટે એપ્લિકેશન્સને અપડેટ કરી શકે છે."</string>
     <string name="user_setup_dialog_title" msgid="6748950002206392396">"અત્યારે જ વપરાશકર્તાને સેટ અપ કરીએ?"</string>
-    <string name="user_setup_dialog_message" msgid="2988559933258353919">"ખાતરી કરો કે વ્યક્તિ ઉપકરણ લેવા અને તેમના સ્થાનનું સેટ અપ કરવા માટે ઉપલબ્ધ છે"</string>
+    <string name="user_setup_dialog_message" msgid="2988559933258353919">"ખાતરી કરો કે વ્યક્તિ ડિવાઇસ લેવા અને તેમના સ્થાનનું સેટ અપ કરવા માટે ઉપલબ્ધ છે"</string>
     <string name="user_setup_profile_dialog_message" msgid="7611900802824048526">"હવે પ્રોફાઇલ સેટ કરીએ?"</string>
     <string name="user_setup_button_setup_now" msgid="4941459406266856176">"હવે સેટ કરો"</string>
     <string name="user_setup_button_setup_later" msgid="6596031428556518752">"હમણાં નહીં"</string>
@@ -2883,7 +2888,7 @@
     <string name="user_confirm_remove_self_title" msgid="6739480453680217543">"તમને પોતાને કાઢી નાખીએ?"</string>
     <string name="user_confirm_remove_title" msgid="1034498514019462084">"આ વપરાશકર્તા ડિલીટ કરીએ?"</string>
     <string name="user_profile_confirm_remove_title" msgid="6138684743385947063">"આ પ્રોફાઇલ દૂર કરીએ?"</string>
-    <string name="work_profile_confirm_remove_title" msgid="3168910958076735800">"કાર્યાલયની પ્રોફાઇલ દૂર કરીએ?"</string>
+    <string name="work_profile_confirm_remove_title" msgid="3168910958076735800">"ઑફિસની પ્રોફાઇલ દૂર કરીએ?"</string>
     <string name="user_confirm_remove_self_message" product="tablet" msgid="2889456786320157545">"તમ તમારું સ્થાન અને ડેટા આ ટેબ્લેટ પરથી ગુમાવશો. તમે આ ક્રિયાને પૂર્વવત્ કરી શકતા નથી."</string>
     <string name="user_confirm_remove_self_message" product="default" msgid="8441729423565705183">"તમે આ ફોન પરથી તમારું સ્થાન અને ડેટા ગુમાવશો. તમે આ ક્રિયાને પૂર્વવત્ કરી શકતા નથી."</string>
     <string name="user_confirm_remove_message" msgid="5202150470271756013">"તમામ ઍપ્લિકેશનો અને ડેટા કાઢી નાખવામાં આવશે."</string>
@@ -2897,12 +2902,12 @@
     <string name="user_exit_guest_confirm_title" msgid="4767911571671099844">"અતિથિ દૂર કરીએ?"</string>
     <string name="user_exit_guest_confirm_message" msgid="6955182181145748919">"આ સત્રમાંની તમામ ઍપ્લિકેશનો અને ડેટા કાઢી નાખવામાં આવશે."</string>
     <string name="user_exit_guest_dialog_remove" msgid="1878866060881115716">"દૂર કરો"</string>
-    <string name="user_enable_calling" msgid="864760054792249503">"ફોન કોલ્સ ચાલુ કરો"</string>
-    <string name="user_enable_calling_sms" msgid="3450252891736718793">"ફોન કૉલ્સ અને SMS ચાલુ કરો"</string>
+    <string name="user_enable_calling" msgid="864760054792249503">"ફોન કૉલ ચાલુ કરો"</string>
+    <string name="user_enable_calling_sms" msgid="3450252891736718793">"ફોન કૉલ અને SMS ચાલુ કરો"</string>
     <string name="user_remove_user" msgid="3687544420125911166">"વપરાશકર્તાને ડિલીટ કરો"</string>
     <string name="user_enable_calling_confirm_title" msgid="1141612415529158542">"ફોન કૉલ્સ ચાલુ કરીએ?"</string>
     <string name="user_enable_calling_confirm_message" msgid="2490126715153125970">"કૉલ ઇતિહાસ આ વપરાશકર્તા સાથે શેર કરવામાં આવશે."</string>
-    <string name="user_enable_calling_and_sms_confirm_title" msgid="4153856398523366976">"ફોન કૉલ્સ અને SMS ચાલુ કરીએ?"</string>
+    <string name="user_enable_calling_and_sms_confirm_title" msgid="4153856398523366976">"ફોન કૉલ અને SMS ચાલુ કરીએ?"</string>
     <string name="user_enable_calling_and_sms_confirm_message" msgid="3278802798876095734">"કૉલ અને SMS ઇતિહાસ આ વપરાશકર્તા સાથે શેર કરવામાં આવશે."</string>
     <string name="emergency_info_title" msgid="1522609271881425375">"ઇમર્જન્સીની માહિતી"</string>
     <string name="emergency_info_summary" msgid="7280464759837387342">"<xliff:g id="USER_NAME">%1$s</xliff:g> માટે માહિતી અને સંપર્કો"</string>
@@ -2912,10 +2917,10 @@
     <string name="nfc_payment_settings_title" msgid="5070077706735415291">"ટેપ કરો અને ચુકવો"</string>
     <string name="nfc_payment_how_it_works" msgid="7607901964687787177">"તે કેવી રીતે કાર્ય કરે છે"</string>
     <string name="nfc_payment_no_apps" msgid="8844440783395420860">"સ્ટોર્સમાં તમારા ફોન વડે ચુકવો"</string>
-    <string name="nfc_payment_default" msgid="7869273092463612271">"ચુકવણી ડિફોલ્ટ"</string>
+    <string name="nfc_payment_default" msgid="7869273092463612271">"ચુકવણી ડિફૉલ્ટ"</string>
     <string name="nfc_payment_default_not_set" msgid="955804193510335338">"સેટ નથી"</string>
     <string name="nfc_payment_app_and_desc" msgid="102312684211458190">"<xliff:g id="APP">%1$s</xliff:g> - <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
-    <string name="nfc_payment_use_default" msgid="3098724195746409476">"ડિફોલ્ટનો ઉપયોગ કરો"</string>
+    <string name="nfc_payment_use_default" msgid="3098724195746409476">"ડિફૉલ્ટનો ઉપયોગ કરો"</string>
     <string name="nfc_payment_favor_default" msgid="7555356982142464260">"હંમેશા"</string>
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"જ્યારે અન્ય ચુકવણી ઍપ્લિકેશન ખુલ્લી હોય તે સિવાય"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"ટેપ કરો અને ચૂકવણી કરો ટર્મિનલ પર, આનાથી ચૂકવણી કરો:"</string>
@@ -3030,13 +3035,13 @@
     <string name="network_dashboard_summary_mobile" msgid="5560545061217580626">"મોબાઇલ"</string>
     <string name="network_dashboard_summary_data_usage" msgid="4695629715072542102">"ડેટા વપરાશ"</string>
     <string name="network_dashboard_summary_hotspot" msgid="3928610802321995214">"હૉટસ્પૉટ"</string>
-    <string name="connected_devices_dashboard_title" msgid="7795222675849060444">"કનેક્ટ થયેલ ઉપકરણો"</string>
+    <string name="connected_devices_dashboard_title" msgid="7795222675849060444">"કનેક્ટ થયેલા ડિવાઇસ"</string>
     <string name="connected_devices_dashboard_summary" msgid="1072664369515033179">"બ્લૂટૂથ, ડ્રાઇવિંગ મોડ, NFC"</string>
     <string name="connected_devices_dashboard_no_nfc_summary" msgid="2610085597733526722">"બ્લૂટૂથ, ડ્રાઇવિંગ મોડ"</string>
     <string name="connected_devices_dashboard_no_driving_mode_summary" msgid="3524409078596318803">"બ્લૂટૂથ, NFC"</string>
     <string name="connected_devices_dashboard_no_driving_mode_no_nfc_summary" msgid="7881286613528299400">"બ્લૂટૂથ"</string>
     <string name="app_and_notification_dashboard_title" msgid="8448096608058843730">"ઍપ્લિકેશનો અને નોટિફિકેશન"</string>
-    <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"આસિસ્ટંટ, તાજેતરની ઍપ, ડિફૉલ્ટ ઍપ"</string>
+    <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"Assistant, તાજેતરની ઍપ, ડિફૉલ્ટ ઍપ"</string>
     <string name="notification_settings_work_profile" msgid="7190550347842400029">"કાર્યાલયની પ્રોફાઇલમાં ઍપ માટે નોટિફિકેશન ઍક્સેસ ઉપલબ્ધ નથી."</string>
     <string name="account_dashboard_title" msgid="4734300939532555885">"એકાઉન્ટ"</string>
     <string name="account_dashboard_default_summary" msgid="6822549669771936206">"કોઈ એકાઉન્ટ ઉમેરવામાં આવ્યાં નથી"</string>
@@ -3136,9 +3141,9 @@
     <string name="ring_volume_option_title" msgid="2038924918468372264">"રિંગ વૉલ્યૂમ"</string>
     <string name="notification_volume_option_title" msgid="1358512611511348260">"નોટિફિકેશન વૉલ્યૂમ"</string>
     <string name="ringtone_title" msgid="1409086028485922583">"ફોન રિંગટોન"</string>
-    <string name="notification_ringtone_title" msgid="2932960620843976285">"નોટિફિકેશન માટે ડિફૉલ્ટ ધ્વનિ"</string>
+    <string name="notification_ringtone_title" msgid="2932960620843976285">"ડિફૉલ્ટ નોટિફિકેશન સાઉન્ડ"</string>
     <string name="notification_unknown_sound_title" msgid="8043718667804838398">"ઍપ્લિકેશને અવાજ પૂરો પાડ્યો"</string>
-    <string name="notification_sound_default" msgid="2664544380802426260">"નોટિફિકેશન માટે ડિફૉલ્ટ ધ્વનિ"</string>
+    <string name="notification_sound_default" msgid="2664544380802426260">"ડિફૉલ્ટ નોટિફિકેશન સાઉન્ડ"</string>
     <string name="alarm_ringtone_title" msgid="6411326147408635902">"ડિફૉલ્ટ એલાર્મ સાઉન્ડ"</string>
     <string name="vibrate_when_ringing_title" msgid="2757996559847126952">"કૉલ માટે વાઇબ્રેટ કરો"</string>
     <string name="other_sound_settings" msgid="5250376066099818676">"અન્ય ધ્વનિઓ"</string>
@@ -3318,7 +3323,7 @@
     <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"કાર્ય પ્રોફાઇલ લૉક થાય ત્યારે"</string>
     <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"તમામ નોટિફિકેશન કન્ટેન્ટ બતાવો"</string>
     <string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"સંવેદનશીલ કન્ટેન્ટ છુપાવો"</string>
-    <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"નોટિફિકેશનો બિલકુલ બતાવશો નહીં"</string>
+    <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"નોટિફિકેશન બિલકુલ બતાવશો નહીં"</string>
     <string name="lock_screen_notifications_interstitial_message" msgid="4230189215124387818">"જ્યારે તમારું ઉપકરણ લૉક કરેલું હોય, ત્યારે તમે નોટિફિકેશનો કેવી રીતે બતાવવા માગો છો?"</string>
     <string name="lock_screen_notifications_interstitial_title" msgid="2832587379332443505">"નોટિફિકેશનો"</string>
     <string name="lock_screen_notifications_summary_show_profile" msgid="8908775469657073273">"કાર્યાલયનું તમામ નોટિફિકેશન કન્ટેન્ટ બતાવો"</string>
@@ -3376,7 +3381,7 @@
     <string name="no_vr_listeners" msgid="7675484190394450979">"કોઇ ઇન્સ્ટૉલ કરેલ ઍપ્લિકેશનોએ VR સહાયક સેવાઓ તરીકે શરૂ કરવાની વિનંતી કરી નથી."</string>
     <string name="vr_listener_security_warning_title" msgid="7019322246707645361">"<xliff:g id="SERVICE">%1$s</xliff:g> માટે VR સેવા ઍક્સેસની મંજૂરી આપીએ?"</string>
     <string name="vr_listener_security_warning_summary" msgid="5093225583584522067">"જ્યારે તમે વર્ચ્યુઅલ રિયાલિટી મોડમાં ઍપ્લિકેશનોનો ઉપયોગ કરી રહ્યાં હોવ ત્યારે <xliff:g id="VR_LISTENER_NAME">%1$s</xliff:g> શરૂ થવા માટે સમર્થ હશે."</string>
-    <string name="display_vr_pref_title" msgid="1088464812293416981">"ઉપકરણ, VR માં હોય ત્યારે"</string>
+    <string name="display_vr_pref_title" msgid="1088464812293416981">"ડિવાઇસ, VR માં હોય ત્યારે"</string>
     <string name="display_vr_pref_low_persistence" msgid="3132583929174794245">"બ્લર ઘટાડો (ભલામણ કરેલ)"</string>
     <string name="display_vr_pref_off" msgid="4681320968818852691">"ફ્લિકર ઘટાડો"</string>
     <string name="picture_in_picture_title" msgid="4960733106166035448">"ચિત્ર-માં-ચિત્ર"</string>
@@ -3427,7 +3432,7 @@
     <string name="app_notification_importance_title" msgid="1902794400671001142">"મહત્વ"</string>
     <string name="notification_show_lights_title" msgid="5381920725933228542">"લાઇટ ઝબકવી"</string>
     <string name="notification_vibrate_title" msgid="8221718258793835282">"વાઇબ્રેટ"</string>
-    <string name="notification_channel_sound_title" msgid="7635366839003304745">"ધ્વનિ"</string>
+    <string name="notification_channel_sound_title" msgid="7635366839003304745">"સાઉન્ડ"</string>
     <string name="zen_mode_rule_delete_button" msgid="6763486487220471193">"ડિલીટ કરો"</string>
     <string name="zen_mode_rule_rename_button" msgid="1428130397306726792">"નામ બદલો"</string>
     <string name="zen_mode_rule_name" msgid="8583652780885724670">"શેડ્યૂલનું નામ"</string>
@@ -3545,7 +3550,7 @@
     <string name="zen_mode_screen_off_summary_no_led" msgid="7255874108150630145">"ખલેલ પાડશો નહીં દ્વારા શાંત કરેલ નોટિફિકેશનોને સ્ક્રીન ચાલુ કરવા દો"</string>
     <string name="notification_app_settings_button" msgid="3651180424198580907">"સૂચનાઓની સેટિંગ્સ"</string>
     <string name="suggestion_button_text" msgid="5783566542423813847">"ઓકે"</string>
-    <string name="device_feedback" msgid="4042352891448769818">"આ ઉપકરણ વિશે પ્રતિસાદ મોકલો"</string>
+    <string name="device_feedback" msgid="4042352891448769818">"આ ડિવાઇસ વિશે પ્રતિસાદ મોકલો"</string>
     <string name="restr_pin_enter_admin_pin" msgid="8577847751493521230">"વ્યવસ્થાપક પિન દાખલ કરો"</string>
     <string name="switch_on_text" msgid="7100491749799298324">"ચાલુ"</string>
     <string name="switch_off_text" msgid="3539551289454353555">"બંધ"</string>
@@ -3630,7 +3635,7 @@
     <string name="filter_enabled_apps" msgid="5888459261768538489">"ઇન્સ્ટૉલ કરેલી ઍપ્લિકેશનો"</string>
     <string name="filter_instant_apps" msgid="8087483282854072366">"ઝટપટ ઍપ્લિકેશનો"</string>
     <string name="filter_personal_apps" msgid="3473268022652904457">"વ્યક્તિગત"</string>
-    <string name="filter_work_apps" msgid="4202483998339465542">"કાર્યાલય"</string>
+    <string name="filter_work_apps" msgid="4202483998339465542">"ઑફિસ"</string>
     <string name="filter_notif_all_apps" msgid="1862666327228804896">"ઍપ્લિકેશનો: તમામ"</string>
     <string name="filter_notif_blocked_apps" msgid="5694956954776028202">"બંધ કરેલી છે"</string>
     <string name="filter_notif_urgent_channels" msgid="5000735867167027148">"કૅટેગરી: તાત્કાલિક મહત્વની"</string>
@@ -3691,7 +3696,7 @@
     <string name="process_format" msgid="8575347150598564509">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="COUNT">%2$d</xliff:g>)"</string>
     <string name="high_power_apps" msgid="2518319744362028920">"બૅટરી ઓપ્ટિમાઇઝેશન"</string>
     <string name="additional_battery_info" msgid="6877663897819271203">"વપરાશ સંબંધી ચેતવણીઓ"</string>
-    <string name="show_all_apps" msgid="5442552004569634846">"ઉપકરણનો સંપૂર્ણ વપરાશ બતાવો"</string>
+    <string name="show_all_apps" msgid="5442552004569634846">"ડિવાઇસનો સંપૂર્ણ વપરાશ બતાવો"</string>
     <string name="hide_extra_apps" msgid="6798261081113299441">"ઍપ્લિકેશનનો વપરાશ બતાવો"</string>
     <plurals name="power_high_usage_summary" formatted="false" msgid="4658343710126205199">
       <item quantity="one"><xliff:g id="NUMBER">%2$d</xliff:g> ઍપ્લિકેશન અસાધારણ રીતે વર્તન કરી રહી છે</item>
@@ -3706,8 +3711,8 @@
     <string name="high_power_off" msgid="5906679734326490426">"બૅટરી વપરાશને ઓપ્ટિમાઇઝ કરી રહ્યું છે"</string>
     <string name="high_power_system" msgid="739584574711292753">"બૅટરી ઓપ્ટિમાઇઝેશન ઉપલબ્ધ નથી"</string>
     <string name="high_power_desc" msgid="333756885680362741">"બૅટરી ઓપ્ટિમાઇઝેશન લાગુ કરશો નહીં. તેનાથી તમારી બૅટરી વધુ ઝડપથી ખાલી થઈ શકે છે."</string>
-    <string name="high_power_prompt_title" msgid="2805745781720454052">"ઍપ્લિકેશનને હંમેશાં પૃષ્ઠભૂમિમાં ચાલવા દઈએ?"</string>
-    <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g>ને હંમેશાં પૃષ્ઠભૂમિમાં ચાલવાની મંજૂરી આપવાથી બૅટરી આવરદા ઓછી થઈ શકે છે. \n\nતમે આને સેટિંગ્સ &gt; ઍપ્લિકેશનો અને સૂચનાઓમાં પછીથી બદલી શકો છો."</string>
+    <string name="high_power_prompt_title" msgid="2805745781720454052">"ઍપને હંમેશાં બૅકગ્રાઉન્ડમાં ચાલવા દઈએ?"</string>
+    <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g>ને હંમેશાં બૅકગ્રાઉન્ડમાં ચાલવાની મંજૂરી આપવાથી બૅટરી આવરદા ઓછી થઈ શકે છે. \n\nતમે આને સેટિંગ &gt; ઍપ અને નોટિફિકેશનોમાં પછીથી બદલી શકો છો."</string>
     <string name="battery_summary" msgid="4345690800899981339">"છેલ્લા પૂર્ણ ચાર્જ પછી <xliff:g id="PERCENTAGE">%1$s</xliff:g> ઉપયોગ"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"પાવર સંચાલન"</string>
     <string name="no_battery_summary" msgid="4105932628367471314">"છેલ્લા પૂર્ણ ચાર્જ પછી કોઈ બૅટરી ઉપયોગ નહીં"</string>
@@ -3738,10 +3743,10 @@
     <string name="usb_preference" msgid="7092987095048592826">"USBની પસંદગીઓ"</string>
     <string name="usb_control_title" msgid="2379698856760894768">"આના દ્વારા નિયંત્રિત USB"</string>
     <string name="usb_control_host" msgid="193292043691034178">"કનેક્ટ થયેલ ઉપકરણ"</string>
-    <string name="usb_control_device" msgid="9154790265254725254">"આ ઉપકરણ"</string>
+    <string name="usb_control_device" msgid="9154790265254725254">"આ ડિવાઇસ"</string>
     <string name="usb_switching" msgid="1230386065163529904">"સ્વિચ કરી રહ્યાં છીએ…"</string>
     <string name="usb_switching_failed" msgid="6857722544186145439">"સ્વિચ કરી શક્યા નથી"</string>
-    <string name="usb_summary_charging_only" msgid="4118449308708872339">"આ ઉપકરણને ચાર્જ કરવું"</string>
+    <string name="usb_summary_charging_only" msgid="4118449308708872339">"આ ડિવાઇસને ચાર્જ કરવું"</string>
     <string name="usb_summary_power_only" msgid="3552240122641051107">"કનેક્ટેડ ઉપકરણ ચાર્જ કરી રહ્યાં છીએ"</string>
     <string name="usb_summary_file_transfers" msgid="7805342797099821502">"ફાઇલ ટ્રાન્સફર"</string>
     <string name="usb_summary_tether" msgid="778845069037366883">"USBથી ઇન્ટરનેટ શેર કરવાની સુવિધા"</string>
@@ -3808,14 +3813,14 @@
     <string name="app_permission_summary_allowed" msgid="6458476982015518778">"મંજૂરી છે"</string>
     <string name="app_permission_summary_not_allowed" msgid="1171642541675462584">"મંજૂરી નથી"</string>
     <string name="keywords_install_other_apps" msgid="5383559540695847668">"ઍપ્લિકેશનો ઇન્સ્ટૉલ કરો અજાણ્યા સ્રોતો"</string>
-    <string name="write_settings" msgid="9009040811145552108">"સિસ્ટમ સેટિંગ્સ સંશોધિત કરો"</string>
+    <string name="write_settings" msgid="9009040811145552108">"સિસ્ટમ સેટિંગમાં ફેરફાર કરો"</string>
     <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">"નાણાકીય ઍપ sms પરવાનગી"</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>
+    <string name="write_system_settings" msgid="20450765210832463">"સિસ્ટમ સેટિંગમાં ફેરફાર કરો"</string>
     <string name="permit_write_settings" msgid="4198491281216818756">"સિસ્ટમ સેટિંગને સંશોધિત કરવાની મંજૂરી આપો"</string>
     <string name="write_settings_description" msgid="2536706293042882500">"આ પરવાનગી એપ્લિકેશનને સિસ્ટમ સેટિંગ્સ સંશોધિત કરવાની મંજૂરી આપે છે."</string>
     <string name="write_settings_on" msgid="7328986337962635118">"હા"</string>
@@ -3948,7 +3953,7 @@
       <item quantity="one"><xliff:g id="COUNT">%1$d</xliff:g> પ્રતિબંધ</item>
       <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> પ્રતિબંધ</item>
     </plurals>
-    <string name="operator_warning" msgid="4676042739221117031">"કૅરિઅર ડેટા ગણતરી, ઉપકરણ ગણતરીથી અલગ હોઈ શકે છે"</string>
+    <string name="operator_warning" msgid="4676042739221117031">"કૅરિઅર ડેટા ગણતરી, ડિવાઇસ ગણતરીથી અલગ હોઈ શકે છે"</string>
     <string name="data_used_template" msgid="761605393453849477">"<xliff:g id="ID_1">%1$s</xliff:g> ઉપયોગ થયો"</string>
     <string name="set_data_warning" msgid="8115980184415563941">"ડેટા ચેતવણી સેટ કરો"</string>
     <string name="data_warning" msgid="2699207195535036240">"ડેટા ચેતવણી"</string>
@@ -4031,7 +4036,7 @@
     <string name="notification_log_details_parcel" msgid="4024970850647594029">"પાર્સલનું કદ"</string>
     <string name="notification_log_details_ashmem" msgid="4272241723105041393">"એશ્મેમ"</string>
     <string name="notification_log_details_alerted" msgid="1891749888625061319">"નોટિફિકેશન અલર્ટ કરેલ"</string>
-    <string name="notification_log_details_sound" msgid="4028782443557466322">"ધ્વનિ"</string>
+    <string name="notification_log_details_sound" msgid="4028782443557466322">"સાઉન્ડ"</string>
     <string name="notification_log_details_vibrate" msgid="8372400602058888072">"વાઇબ્રેટ"</string>
     <string name="notification_log_details_vibrate_pattern" msgid="7015554755444260922">"પૅટર્ન"</string>
     <string name="notification_log_details_default" msgid="455451833359888182">"ડિફોલ્ટ"</string>
@@ -4076,7 +4081,7 @@
     <string name="quick_settings_developer_tiles" msgid="7423485925757678719">"ઝપડી સેટિંગ્સ વિકાસકર્તા ટાઇલ"</string>
     <string name="winscope_trace_quick_settings_title" msgid="940971040388411374">"Winscope ટ્રેસ"</string>
     <string name="sensors_off_quick_settings_title" msgid="3655699045300438902">"સેન્સર બંધ છે"</string>
-    <string name="managed_profile_settings_title" msgid="4340409321523532402">"કાર્યાલયની પ્રોફાઇલની સેટિંગ્સ"</string>
+    <string name="managed_profile_settings_title" msgid="4340409321523532402">"ઑફિસની પ્રોફાઇલના સેટિંગ"</string>
     <string name="managed_profile_contact_search_title" msgid="7337225196804457095">"સંપર્ક શોધ"</string>
     <string name="managed_profile_contact_search_summary" msgid="7278267480246726951">"કૉલર્સ અને સંપર્કોને ઓળખવા માટે તમારી સંસ્થા દ્વારા સંપર્ક શોધની મંજૂરી આપો"</string>
     <string name="cross_profile_calendar_title" msgid="2351605904015067145">"ક્રૉસ-પ્રોફાઇલ કૅલેન્ડર"</string>
@@ -4155,7 +4160,7 @@
     <string name="auto_sync_account_title" msgid="2394463123733529506">"ડેટાને ઑટોમૅટિક રીતે સિંક કરો"</string>
     <string name="auto_sync_personal_account_title" msgid="6844465157916100655">"વ્યક્તિગત ડેટાનું આપમેળે સમન્વયન કરો"</string>
     <string name="auto_sync_work_account_title" msgid="2403222633447522376">"કાર્ય ડેટાનું આપમેળે સમન્વયન કરો"</string>
-    <string name="auto_sync_account_summary" msgid="6316230976974033772">"ઍપને આપમેળે ડેટાને રિફ્રેશ કરવા દો"</string>
+    <string name="auto_sync_account_summary" msgid="6316230976974033772">"ઍપને ઑટોમૅટિક રીતે ડેટાને રિફ્રેશ કરવા દો"</string>
     <string name="account_sync_title" msgid="1570164819114297154">"એકાઉન્ટ સિંક"</string>
     <string name="account_sync_summary_some_on" msgid="1934556869158274053">"<xliff:g id="ID_2">%2$d</xliff:g> માંથી <xliff:g id="ID_1">%1$d</xliff:g> આઇટમ માટે સમન્વયન ચાલુ છે"</string>
     <string name="account_sync_summary_all_on" msgid="3634161204232431700">"બધી આઇટમ માટે સમન્વયન ચાલુ છે"</string>
@@ -4230,11 +4235,11 @@
     </plurals>
     <string name="app_names_concatenation_template_2" msgid="8267577900046506189">"<xliff:g id="FIRST_APP_NAME">%1$s</xliff:g>, <xliff:g id="SECOND_APP_NAME">%2$s</xliff:g>"</string>
     <string name="app_names_concatenation_template_3" msgid="5129064036161862327">"<xliff:g id="FIRST_APP_NAME">%1$s</xliff:g>, <xliff:g id="SECOND_APP_NAME">%2$s</xliff:g>, <xliff:g id="THIRD_APP_NAME">%3$s</xliff:g>"</string>
-    <string name="storage_photos_videos" msgid="1890829312367477559">"ફોટો અને વીડિઓ"</string>
-    <string name="storage_music_audio" msgid="3661289086715297149">"સંગીત અને ઑડિઓ"</string>
+    <string name="storage_photos_videos" msgid="1890829312367477559">"ફોટો અને વીડિયો"</string>
+    <string name="storage_music_audio" msgid="3661289086715297149">"સંગીત અને ઑડિયો"</string>
     <string name="storage_games" msgid="7740038143749092373">"રમતો"</string>
     <string name="storage_other_apps" msgid="3202407095387420842">"અન્ય ઍપ્લિકેશનો"</string>
-    <string name="storage_files" msgid="2087824267937487880">"ફાઇલો"</string>
+    <string name="storage_files" msgid="2087824267937487880">"Files"</string>
     <string name="storage_size_large_alternate" msgid="1317796542509105857">"<xliff:g id="NUMBER">^1</xliff:g>"<small>" "<font size="20">"<xliff:g id="UNIT">^2</xliff:g>"</font></small>""</string>
     <string name="storage_volume_total" msgid="5021484171514159913">"<xliff:g id="TOTAL">%1$s</xliff:g>માંથી ઉપયોગમાં લેવાયો"</string>
     <string name="storage_percent_full" msgid="6924662861545958442">"વપરાયો"</string>
@@ -4242,7 +4247,7 @@
     <string name="clear_instant_app_confirmation" msgid="1778553115373698061">"શું તમે આ ઝટપટ ઍપ્લિકેશન દૂર કરવા માંગો છો?"</string>
     <string name="launch_instant_app" msgid="5251693061228352333">"ખોલો"</string>
     <string name="game_storage_settings" msgid="6856911551799175914">"રમતો"</string>
-    <string name="audio_files_title" msgid="3073879661731363935">"ઑડિઓ ફાઇલો"</string>
+    <string name="audio_files_title" msgid="3073879661731363935">"ઑડિયો ફાઇલો"</string>
     <string name="app_info_storage_title" msgid="6643391804949509308">"જગ્યા વપરાઈ"</string>
     <string name="webview_uninstalled_for_user" msgid="3407952144444040557">"(<xliff:g id="USER">%s</xliff:g> માટે અનઇન્સ્ટૉલ કરેલ)"</string>
     <string name="webview_disabled_for_user" msgid="8057805373224993504">"(વપરાશકર્તા <xliff:g id="USER">%s</xliff:g> માટે અક્ષમ કરેલ)"</string>
@@ -4301,12 +4306,12 @@
     <string name="disabled_dependent_setting_summary" msgid="7668590009599010842">"અન્ય સેટિંગ પર આધાર રાખે છે"</string>
     <string name="unknown_unavailability_setting_summary" msgid="5785931810977403534">"સેટિંગ અનુપલબ્ધ છે"</string>
     <string name="my_device_info_account_preference_title" msgid="7965847995028952373">"એકાઉન્ટ"</string>
-    <string name="my_device_info_device_name_preference_title" msgid="7384446683248009296">"ઉપકરણનું નામ"</string>
+    <string name="my_device_info_device_name_preference_title" msgid="7384446683248009296">"ડિવાઇસનું નામ"</string>
     <string name="change_wifi_state_title" msgid="5140754955787584174">"વાઇ-ફાઇ નિયંત્રણ"</string>
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"ઍપને વાઇ-ફાઇ નિયંત્રિત કરવાની મંજૂરી આપો"</string>
     <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"આ ઍપને વાઇ-ફાઇ ચાલુ અથવા બંધ કરવા, વાઇ-ફાઇ નેટવર્કને સ્કૅન અને કનેક્ટ કરવા, નેટવર્ક ઉમેરવા અથવા કાઢી નાખવા અથવા માત્ર-સ્થાનિક હૉટસ્પૉટ શરૂ કરવાની મંજૂરી આપો"</string>
     <string name="media_output_title" msgid="8710632337456601848">"મીડિયા આના પર ચલાવો"</string>
-    <string name="media_output_default_summary" msgid="3159237976830415584">"આ ઉપકરણ"</string>
+    <string name="media_output_default_summary" msgid="3159237976830415584">"આ ડિવાઇસ"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"ફોન"</string>
     <string name="media_output_summary" product="tablet" msgid="6672024060360538526">"ટૅબ્લેટ"</string>
     <string name="media_output_summary" product="device" msgid="5132223072593052660">"ઉપકરણ"</string>
@@ -4468,7 +4473,7 @@
     <string name="privacy_dashboard_title" msgid="8764930992456607513">"પ્રાઇવસી"</string>
     <string name="privacy_dashboard_summary" msgid="7916431309860824945">"પરવાનગીઓ, એકાઉન્ટ પ્રવૃત્તિ, વ્યક્તિગત ડેટા"</string>
     <string name="contextual_card_dismiss_remove" msgid="1750420285615827309">"કાઢી નાખો"</string>
-    <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"રાખો"</string>
+    <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"Keep"</string>
     <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"આ સુઝાવ કાઢી નાખીએ?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"સૂચન કાઢી નાખ્યું"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"છેલ્લો ફેરફાર રદ કરો"</string>
diff --git a/tests/CarDeveloperOptions/res/values-hi/arrays.xml b/tests/CarDeveloperOptions/res/values-hi/arrays.xml
index 68fe0bf..acc4345 100644
--- a/tests/CarDeveloperOptions/res/values-hi/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-hi/arrays.xml
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"कभी भी अनुमति न दें"</item>
     <item msgid="8184570120217958741">"हमेशा अनुमति दें"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"मेमोरी की स्थिति सामान्य है"</item>
+    <item msgid="5101233285497327432">"मध्यम"</item>
+    <item msgid="1555861583162930714">"कम"</item>
+    <item msgid="1719683776264798117">"महत्वपूर्ण"</item>
+    <item msgid="1567326459340152525">"कितनी मेमोरी है?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"सामान्य"</item>
+    <item msgid="6107138933849816768">"मध्यम"</item>
+    <item msgid="182695359839047859">"कम"</item>
+    <item msgid="8577246509202964244">"मेमोरी बेहद कम है"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"निरंतर"</item>
     <item msgid="167418068739176448">"शीर्ष गतिविधि"</item>
@@ -467,7 +477,7 @@
     <item msgid="1008268820118852416">"इस कनेक्शन में डेटा से जुड़ी पाबंदी नहीं है"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
-    <item msgid="6545683814310036454">"किसी भी MAC पते का इस्तेमाल करें (डिफ़ॉल्ट सेटिंग)"</item>
+    <item msgid="6545683814310036454">"MAC पते का इस्तेमाल करें (डिफ़ॉल्ट सेटिंग)"</item>
     <item msgid="214234417308375326">"डिवाइस के एमएसी का इस्तेमाल करें"</item>
   </string-array>
   <string-array name="wifi_hidden_entries">
diff --git a/tests/CarDeveloperOptions/res/values-hi/config.xml b/tests/CarDeveloperOptions/res/values-hi/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-hi/config.xml
+++ b/tests/CarDeveloperOptions/res/values-hi/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-hi/strings.xml b/tests/CarDeveloperOptions/res/values-hi/strings.xml
index b1c1375..e19e3fa 100644
--- a/tests/CarDeveloperOptions/res/values-hi/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-hi/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"स्क्रीन पर मौजूद लेख को छोटा या बड़ा करें."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"छोटा करें"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"बड़ा करें"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"नमूना लेख"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"ओज़ का अद्भुत जादू"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"अध्याय 11: पन्ने का अद्भुत शहर ओज़"</string>
@@ -467,7 +466,7 @@
     <string name="security_settings_fingerprint_enroll_dialog_ok" msgid="3428927518029038956">"ठीक है"</string>
     <string name="security_settings_fingerprint_enroll_dialog_delete" msgid="4312297515772004580">"मिटाएं"</string>
     <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"सेंसर को छुएं"</string>
-    <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"अपनी उंगली सेंसर पर रखें और कंपन (वाइब्रेशन) महसूस होने पर उठा लें"</string>
+    <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"अपनी उंगली सेंसर पर रखें और कंपन (वाइब्रेशन) महसूस होने पर हटा लें"</string>
     <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"उठाएं, फिर दोबारा छुएं"</string>
     <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"अपने फ़िंगरप्रिंट के अलग-अलग भागों को जोड़ने के लिए अपनी उंगली को उठाते रहें"</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"फ़िंगरप्रिंट जोड़ा गया"</string>
@@ -668,7 +667,6 @@
       <item quantity="one">पिन में <xliff:g id="NUMBER_1">%d</xliff:g> से कम अंक होने चाहिए</item>
       <item quantity="other">पिन में <xliff:g id="NUMBER_1">%d</xliff:g> से कम अंक होने चाहिए</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"इसमें सिर्फ़ 0 से 9 तक के अंक होने चाहिए"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"डिवाइस व्यवस्थापक हाल ही के पिन का उपयोग करने की अनुमति नहीं देता"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"आपके आईटी एडमिन ने आम तौर पर इस्तेमाल होने वाले पिन पर रोक लगा रखी है. दूसरा पिन बनाएं."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"इसमें अमान्य वर्ण शामिल नहीं हो सकता"</string>
@@ -699,6 +697,10 @@
       <item quantity="one">इसमें कम से कम <xliff:g id="COUNT">%d</xliff:g> वर्ण ऐसे होने चाहिए जो अक्षर ना हों</item>
       <item quantity="other">इसमें कम से कम <xliff:g id="COUNT">%d</xliff:g> वर्ण ऐसे होने चाहिए जो अक्षर ना हों</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">पासवर्ड में कम से कम <xliff:g id="COUNT">%d</xliff:g> वर्ण ऐसे होने चाहिए जो संख्या न हो</item>
+      <item quantity="other">पासवर्ड में कम से कम <xliff:g id="COUNT">%d</xliff:g> वर्ण ऐसे होने चाहिए जो संख्या न हो</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"डिवाइस व्यवस्थापक हाल ही के पासवर्ड का उपयोग करने की अनुमति नहीं देता"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"आपके आईटी एडमिन ने आम तौर पर इस्तेमाल होने वाले पासवर्ड पर रोक लगा रखी है. कोई दूसरा पासवर्ड बनाएं."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"अंकों के बढ़ते, घटते या दोहराए जाने वाले क्रम की अनुमति नहीं है"</string>
@@ -818,7 +820,7 @@
     <string name="wifi_ask_disable" msgid="2146839060110412974">"<xliff:g id="REQUESTER">%s</xliff:g> वाई-फ़ाई को बंद करना चाहता है"</string>
     <string name="art_verifier_for_debuggable_title" msgid="5223835619409464642">"डीबग वाले ऐप्लिकेशन के बाइटकोड की पुष्टि करें"</string>
     <string name="art_verifier_for_debuggable_summary" msgid="2204242476996701111">"डीबग किए जा सकने वाले ऐप्लिकेशन के लिए, ART को बाइटकोड की पुष्टि करने की मंज़ूरी दें"</string>
-    <string name="nfc_quick_toggle_title" msgid="4990697912813795002">"आस-पास के डिवाइस से संपर्क (एनएफसी)"</string>
+    <string name="nfc_quick_toggle_title" msgid="4990697912813795002">"आस-पास के डिवाइस से संपर्क (एनएफ़सी)"</string>
     <string name="nfc_quick_toggle_summary" product="tablet" msgid="983451155092850657">"जब टैबलेट अन्य डिवाइस को स्पर्श करे तो डेटा ट्रांसफर करने दें"</string>
     <string name="nfc_quick_toggle_summary" product="default" msgid="7141056939052895142">"जब फ़ोन दूसरे डिवाइस को टच करे, तो डेटा ट्रांसफर करने दें"</string>
     <string name="nfc_disclaimer_title" msgid="4860231267351602970">"NFC चालू करें"</string>
@@ -933,13 +935,13 @@
     <string name="wifi_privacy_settings" msgid="4462092795794247809">"निजता"</string>
     <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"अपने आप चुना गया एमएसी"</string>
     <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"कोई डिवाइस जोड़ें"</string>
-    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"डिवाइस को “<xliff:g id="SSID">%1$s</xliff:g>” से जोड़ने के लिए QR कोड को कैमरा विंडो के बीच में लाएं"</string>
+    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"डिवाइस को “<xliff:g id="SSID">%1$s</xliff:g>” से जोड़ने के लिए क्यूआर कोड को कैमरा विंडो के बीच में लाएं"</string>
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"QR कोड स्कैन करें"</string>
     <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"डिवाइस को “<xliff:g id="SSID">%1$s</xliff:g>” से जोड़ने के लिए QR कोड को नीचे मौजूद कैमरा विंडो के बीच में लाएं"</string>
-    <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"QR कोड स्कैन करके वाई-फ़ाई से जुड़ें"</string>
+    <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"क्यूआर कोड स्कैन करके वाई-फ़ाई से जुड़ें"</string>
     <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"वाई-फ़ाई शेयर करें"</string>
     <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"“<xliff:g id="SSID">%1$s</xliff:g>” से जुड़ने के लिए इस QR कोड को स्कैन करें और पासवर्ड शेयर करें"</string>
-    <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"“<xliff:g id="SSID">%1$s</xliff:g>” से जुड़ने के लिए इस QR कोड को स्कैन करें"</string>
+    <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"“<xliff:g id="SSID">%1$s</xliff:g>” से जुड़ने के लिए इस क्यूआर कोड को स्कैन करें"</string>
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"QR कोड नहीं पहचाना जा सका. कोड को बीच में रखें और दोबारा कोशिश करें"</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"फिर से कोशिश करें. अगर समस्या ठीक नहीं होती है, तो डिवाइस बनाने वाली कंपनी से संपर्क करें"</string>
     <string name="wifi_dpp_failure_not_compatible" msgid="4320027179973678283">"काेई गड़बड़ी हुई"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"वाई-फ़ाई"</item>
+    <item msgid="2271962426654621656">"मोबाइल"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"वाई-फ़ाई उपलब्ध न होने पर मोबाइल नेटवर्क इस्तेमाल करें"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"मोबाइल नेटवर्क न होने पर वाई-फ़ाई इस्तेमाल करें"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"वाई-फ़ाई के ज़रिए कॉल करें. वाई-फ़ाई रुक जाने पर कॉल खत्म हो जाएगी."</string>
@@ -1198,7 +1203,7 @@
     <string name="auto_brightness_off_summary" msgid="6162650416289359104">"मौजूदा रोशनी के लिए एडजस्ट न करें"</string>
     <string name="auto_brightness_very_high_summary" msgid="7202032980509583918">"बढ़ा हुआ बैटरी उपयोग"</string>
     <string name="auto_brightness_disclaimer" msgid="5416696351199148809">"मौजूदा रोशनी के लिए स्क्रीन की चमक का स्तर अनुकूलित करें. इस सुविधा के चालू होने पर, आप अब भी स्क्रीन की रोशनी कुछ समय के लिए एडजस्ट कर सकते हैं."</string>
-    <string name="auto_brightness_description" msgid="8209140379089535411">"आपकी गतिविधियों और आपके आस-पास मौजूद रोशनी के हिसाब से आपके डिवाइस की स्क्रीन की चमक अपने आप सेट हो जाएगी. आपके आस-पास मौजूद रोशनी के हिसाब से स्क्रीन की चमक अपने आप बदलने वाली इस सुविधा को आप अपनी पसंद के हिसाब से ढाल सकते हैं. ऐसा करने के लिए स्लाइडर को आगे-पीछे करें और मैन्युअल रूप से स्क्रीन की चमक सेट करें."</string>
+    <string name="auto_brightness_description" msgid="8209140379089535411">"आपकी गतिविधियों और आपके आस-पास मौजूद रोशनी के हिसाब से आपके डिवाइस की स्क्रीन की चमक अपने-आप सेट हो जाएगी. आपके आस-पास मौजूद रोशनी के हिसाब से स्क्रीन की चमक अपने-आप बदलने वाली इस सुविधा को आप अपनी पसंद के हिसाब से ढाल सकते हैं. ऐसा करने के लिए स्लाइडर को आगे-पीछे करें और मैन्युअल रूप से स्क्रीन की चमक सेट करें."</string>
     <string name="display_white_balance_title" msgid="5747260735311935143">"डिसप्ले का वाइट बैलेंस"</string>
     <string name="adaptive_sleep_title" msgid="3237620948260957018">"स्क्रीन अवेयर"</string>
     <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"चालू करें / अगर आप स्क्रीन को देख रहे हैं, तो वह बंद नहीं होगी"</string>
@@ -1260,7 +1265,7 @@
     <string name="doze_summary" msgid="6762274282827831706">"आपको सूचना मिलने पर स्‍क्रीन चालू करें"</string>
     <string name="doze_always_on_title" msgid="8555184965031789941">"हमेशा चालू"</string>
     <string name="doze_always_on_summary" msgid="7654436900436328950">"समय, सूचना के आइकॉन और दूसरी जानकारी दिखाएं. इसमें ज़्यादा बैटरी का इस्तेमाल होगा."</string>
-    <string name="title_font_size" msgid="5021464556860010851">"अक्षरों का आकार"</string>
+    <string name="title_font_size" msgid="5021464556860010851">"फ़ॉन्ट साइज़"</string>
     <string name="short_summary_font_size" msgid="4141077908728522946">"लेख को छोटा या बड़ा करें"</string>
     <string name="sim_lock_settings" msgid="1986924650622642189">"सिम कार्ड लॉक सेटिंग"</string>
     <string name="sim_lock_settings_category" msgid="1126759898277681516">"सिम कार्ड लॉक"</string>
@@ -1616,7 +1621,7 @@
     <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"डेटा बचाने की सेटिंग चालू होने पर इंटरनेट शेयर नहीं किया जा सकता या पोर्टेबल हॉटस्पॉट का इस्तेमाल नहीं किया जा सकता"</string>
     <string name="usb_title" msgid="7480927657535578688">"यूएसबी"</string>
     <string name="usb_tethering_button_text" msgid="6242228383142012332">"यूएसबी से टेदरिंग"</string>
-    <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"यूएसबी के ज़रिए फ़ोन का इंटरनेट कनेक्‍शन शेयर करें"</string>
+    <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"यूएसबी से फ़ोन का इंटरनेट कनेक्‍शन शेयर करें"</string>
     <string name="usb_tethering_subtext" product="tablet" msgid="154536000235361034">"यूएसबी के ज़रिए टैबलेट का इंटरनेट कनेक्‍शन शेयर करें"</string>
     <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"ब्लूटूथ टेदरिंग"</string>
     <string name="bluetooth_tethering_subtext" product="tablet" msgid="6868756914621131635">"ब्लूटूथ के ज़रिए टैबलेट का इंटरनेट कनेक्शन शेयर करें"</string>
@@ -1651,7 +1656,7 @@
     </plurals>
     <string name="location_category_recent_location_access" msgid="286059523360285026">"हाल ही में ऐक्सेस की गई जगह की जानकारी"</string>
     <string name="location_recent_location_access_view_details" msgid="2051602261436245905">"जानकारी देखें"</string>
-    <string name="location_no_recent_apps" msgid="77502059586413278">"किसी भी ऐप ने हाल में जगह का अनुरोध नहीं किया है"</string>
+    <string name="location_no_recent_apps" msgid="77502059586413278">"किसी भी ऐप्लिकेशन ने हाल में जगह की जानकारी नहीं मांगी है"</string>
     <string name="location_no_recent_accesses" msgid="6289916310397279890">"किसी भी ऐप्लिकेशन ने हाल ही में जगह की जानकारी का इस्तेमाल नहीं किया"</string>
     <string name="location_high_battery_use" msgid="7177199869979522663">"ज़्यादा बैटरी उपयोग"</string>
     <string name="location_low_battery_use" msgid="5030448574501435888">"कम बैटरी उपयोग"</string>
@@ -1832,7 +1837,7 @@
     <string name="unknown" msgid="2780743426415501227">"अज्ञात"</string>
     <string name="sort_order_alpha" msgid="6689698854460261212">"नाम के हिसाब से क्रम से लगाएं"</string>
     <string name="sort_order_size" msgid="3167376197248713027">"आकार के अनुसार क्रमित करें"</string>
-    <string name="sort_order_recent_notification" msgid="5592496977404445941">"सबसे हालिया सूचनाएं भेजने वाले ऐप्लिकेशन"</string>
+    <string name="sort_order_recent_notification" msgid="5592496977404445941">"सबसे हाल ही में सूचनाएं भेजने वाले ऐप्लिकेशन"</string>
     <string name="sort_order_frequent_notification" msgid="5640245013098010347">"अक्सर"</string>
     <string name="show_running_services" msgid="1895994322704667543">"चल रही सेवाएं दिखाएं"</string>
     <string name="show_background_processes" msgid="88012264528093617">"कैश की गई प्रक्रियाएं दिखाएं"</string>
@@ -2064,10 +2069,10 @@
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"स्क्रीन को बड़ा करने की सुविधा को अपने आप अपडेट करें"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"ऐप ट्रांज़िशन पर स्क्रीन को बड़ा दिखाना अपडेट करें"</string>
     <string name="accessibility_power_button_ends_call_prerefence_title" msgid="6172987104538172869">"पावर बटन से कॉल काटना"</string>
-    <string name="accessibility_toggle_large_pointer_icon_title" msgid="9127905775116570565">"बड़ा माउस सूचक"</string>
+    <string name="accessibility_toggle_large_pointer_icon_title" msgid="9127905775116570565">"बड़ा माउस पॉइंटर"</string>
     <string name="accessibility_disable_animations" msgid="8378441317115710009">"ऐनिमेशन हटाएं"</string>
     <string name="accessibility_toggle_master_mono_title" msgid="899550848196702565">"मोनो ऑडियो"</string>
-    <string name="accessibility_toggle_master_mono_summary" msgid="3847052868469033235">"ऑडियो चलाते समय चैनल संयोजित करें"</string>
+    <string name="accessibility_toggle_master_mono_summary" msgid="3847052868469033235">"ऑडियो चलाते समय कई चैनल को एकसाथ जोड़ें"</string>
     <string name="accessibility_toggle_master_balance_title" msgid="8723492001092647562">"ऑडियो बैलेंस"</string>
     <string name="accessibility_toggle_master_balance_left_label" msgid="8531986342666527970">"बायां"</string>
     <string name="accessibility_toggle_master_balance_right_label" msgid="7757024572140589558">"दायां"</string>
@@ -2081,7 +2086,7 @@
     <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"चुनें कि कुछ समय तक दिखाई देने वाले ऐसे मैसेज जो आपको पढ़ने हैं वे कितनी देर तक दिखाई दें.\n\nयह सेटिंग सभी ऐप्लिकेशन में काम नहीं करती."</string>
     <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"चुनें कि आपको कार्रवाई करने के लिए कहने वाले मैसेज कितनी देर तक दिखाने हैं, लेकिन वे सिर्फ़ कुछ समय के लिए ही दिखाई देते हैं.\n\nयह सेटिंग सभी ऐप्लिकेशन पर काम नहीं करती है."</string>
     <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"दबाकर रखने की अवधि"</string>
-    <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"रंग बदलें"</string>
+    <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"रंग बदलने की सुविधा"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"डिसप्ले पर असर पड़ सकता है"</string>
     <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"कर्सर रुकने की अवधि"</string>
     <string name="accessibility_autoclick_description" msgid="5492414927846407499">"अगर आप माउस इस्तेमाल कर रहे हैं तो, सेट कर सकते हैं कि किसी जगह पर एक तय समय तक रुकने के बाद कर्सर अपने आप कार्रवाई करे."</string>
@@ -2095,7 +2100,7 @@
     <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"कैप्शन इस्तेमाल करें"</string>
     <string name="accessibility_hearingaid_instruction_continue_button" msgid="4650111296711466691">"जारी रखें"</string>
     <string name="accessibility_hearingaid_title" msgid="3700978781235124891">"सुनने में मदद करने वाला डिवाइस"</string>
-    <string name="accessibility_hearingaid_not_connected_summary" msgid="634573930469952213">"सुनने में मददगार कोई भी डिवाइस जुड़ा हुआ नहीं है"</string>
+    <string name="accessibility_hearingaid_not_connected_summary" msgid="634573930469952213">"कान की कोई भी मशीन नहीं जुड़ी है"</string>
     <string name="accessibility_hearingaid_adding_summary" msgid="4139031880828714300">"सुनने में मदद करने वाले डिवाइस जोड़ें"</string>
     <string name="accessibility_hearingaid_pair_instructions_first_message" msgid="2671518890909750740">"सुनने में मदद करने वाला डिवाइस जोड़ने के लिए, अगली स्क्रीन पर अपना डिवाइस ढूंढें और टैप करें."</string>
     <string name="accessibility_hearingaid_pair_instructions_second_message" msgid="1584538735488464991">"यह देख लें कि सुनने में आपकी मदद करने वाला डिवाइस दूसरे डिवाइस से जुड़ने वाले मोड में है."</string>
@@ -2424,7 +2429,7 @@
     <string name="battery_detail_since_full_charge" msgid="3814176986148084378">"पूरी तरह चार्ज होने के बाद से अब तक का विश्लेषण"</string>
     <string name="battery_last_full_charge" msgid="5624033030647170717">"पिछली बार पूरी तरह चार्ज किया गया"</string>
     <string name="battery_full_charge_last" msgid="4614554109170251301">"बैटरी पूरी चार्ज होने पर करीब इतनी देर चलती है"</string>
-    <string name="battery_footer_summary" msgid="4828444679643906943">"बैटरी के इस्तेमाल का यह डेटा अनुमान के हिसाब से है और यह इस्तेमाल करने के तरीके के मुताबिक बदल सकता है"</string>
+    <string name="battery_footer_summary" msgid="4828444679643906943">"बैटरी के इस्तेमाल का यह डेटा अनुमान के हिसाब से है. यह इस्तेमाल करने के तरीके के मुताबिक बदल सकता है"</string>
     <string name="battery_detail_foreground" msgid="6616408559186553085">"जब इस्तेमाल में हो"</string>
     <string name="battery_detail_background" msgid="7938146832943604280">"बैकग्राउंड में होने पर"</string>
     <string name="battery_detail_power_usage" msgid="3606930232257489212">"बैटरी खर्च"</string>
@@ -2596,7 +2601,7 @@
     <string name="work_mode_label" msgid="6845849194740195757">"वर्क प्रोफ़ाइल"</string>
     <string name="work_mode_on_summary" msgid="1682781113156323592">"आपका संगठन प्रबंधित कर रहा है"</string>
     <string name="work_mode_off_summary" msgid="1688885392211178315">"ऐप्लिकेशन और सूचनाएं बंद हैं"</string>
-    <string name="remove_managed_profile_label" msgid="4625542553784793536">"वर्क प्रोफ़ाइल निकालें"</string>
+    <string name="remove_managed_profile_label" msgid="4625542553784793536">"वर्क प्रोफ़ाइल हटाएं"</string>
     <string name="background_data" msgid="8275750862371471171">"पृष्ठभूमि डेटा"</string>
     <string name="background_data_summary" msgid="799640633948841990">"ऐप्लिकेशन किसी भी समय डेटा सिंक करना, भेज, और पा सकते हैं"</string>
     <string name="background_data_dialog_title" msgid="8306650658158895976">"पृष्ठभू. डेटा अक्षम करें?"</string>
@@ -2665,8 +2670,8 @@
     <string name="data_usage_menu_sim_cards" msgid="8508154611676507088">"सिम कार्ड"</string>
     <string name="data_usage_cellular_data_summary" msgid="9162777397135709280">"सीमा पर रोका गया"</string>
     <string name="account_settings_menu_auto_sync" msgid="2673669556006027506">"अपने आप डेटा समन्वयन"</string>
-    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"निजी डेटा अपने आप सिंक करें"</string>
-    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"काम से जुड़ा डेटा अपने आप सिंक करें"</string>
+    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"निजी डेटा अपने-आप सिंक हो जाए"</string>
+    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"काम से जुड़ा डेटा अपने-आप सिंक हो"</string>
     <string name="data_usage_change_cycle" msgid="447761920472170031">"चक्र बदलें ..."</string>
     <string name="data_usage_pick_cycle_day" msgid="6319750879145917066">"डेटा खर्च की अवधि रीसेट करने के लिए महीने का दिन:"</string>
     <string name="data_usage_empty" msgid="7981405723435034032">"इस दौरान कि‍सी भी ऐप्लिकेशन ने डेटा का उपयोग नहीं कि‍या."</string>
@@ -2770,7 +2775,7 @@
     <string name="vpn_disconnect_confirm" msgid="3505111947735651082">"इस VPN को डिसकनेक्ट करना चाहते हैं?"</string>
     <string name="vpn_disconnect" msgid="4625914562388652486">"डिसकनेक्ट करें"</string>
     <string name="vpn_version" msgid="2006792987077940456">"वर्शन <xliff:g id="VERSION">%s</xliff:g>"</string>
-    <string name="vpn_forget_long" msgid="8457511440635534478">"VPN भूल जाएं"</string>
+    <string name="vpn_forget_long" msgid="8457511440635534478">"वीपीएन भूल जाएं"</string>
     <string name="vpn_replace_vpn_title" msgid="8517436922021598103">"मौजूदा VPN को बदलें?"</string>
     <string name="vpn_set_vpn_title" msgid="6483554732067951052">"हमेशा-चालू VPN सेट करें?"</string>
     <string name="vpn_first_always_on_vpn_message" msgid="7050017738816963855">"यह सेटिंग चालू होने पर, आपके पास तब तक इंटरनेट कनेक्शन नहीं होगा, जब तक कि VPN अच्छी तरह कनेक्ट नहीं हो जाता"</string>
@@ -2789,7 +2794,7 @@
     <string name="vpn_always_on_summary" msgid="3639994551631437397">"VPN से हमेशा कनेक्ट रहें"</string>
     <string name="vpn_always_on_summary_not_supported" msgid="9077720997795965133">"यह ऐप्लिकेशन समर्थन नहीं करता"</string>
     <string name="vpn_always_on_summary_active" msgid="8962619701962239088">"हमेशा चालू"</string>
-    <string name="vpn_require_connection" msgid="5413746839457797350">"बिना VPN वाले कनेक्शन ब्लॉक करें"</string>
+    <string name="vpn_require_connection" msgid="5413746839457797350">"बिना वीपीएन वाले कनेक्शन ब्लॉक करें"</string>
     <string name="vpn_require_connection_title" msgid="8361434328767853717">"VPN कनेक्शन ज़रूरी है?"</string>
     <string name="vpn_lockdown_summary" msgid="6770030025737770861">"वह VPN प्रोफ़ाइल चुनें जिससे हमेशा कनेक्ट रहना है. नेटवर्क ट्रैफ़िक की अनुमति केवल इस VPN से कनेक्ट रहने पर ही दी जाएगी."</string>
     <string name="vpn_lockdown_none" msgid="3789288793603394679">"कोई नहीं"</string>
@@ -2899,7 +2904,7 @@
     <string name="user_exit_guest_dialog_remove" msgid="1878866060881115716">"निकालें"</string>
     <string name="user_enable_calling" msgid="864760054792249503">"फ़ोन कॉल चालू करें"</string>
     <string name="user_enable_calling_sms" msgid="3450252891736718793">"फ़ोन कॉल और मैसेज (एसएमएस) चालू करें"</string>
-    <string name="user_remove_user" msgid="3687544420125911166">"उपयोगकर्ता को हटाना"</string>
+    <string name="user_remove_user" msgid="3687544420125911166">"उपयोगकर्ता को मिटाएं"</string>
     <string name="user_enable_calling_confirm_title" msgid="1141612415529158542">"फ़ोन कॉल चालू करें?"</string>
     <string name="user_enable_calling_confirm_message" msgid="2490126715153125970">"कॉल इतिहास इस उपयोगकर्ता के साथ शेयर किया जाएगा."</string>
     <string name="user_enable_calling_and_sms_confirm_title" msgid="4153856398523366976">"फ़ोन कॉल और मैसेज (एसएमएस) चालू करें?"</string>
@@ -3417,7 +3422,7 @@
     <string name="notification_content_block_summary" msgid="2743896875255591743">"सूचना कभी भी शेड में या पेरिफ़ेरल डिवाइस पर ना दिखाएं"</string>
     <string name="notification_badge_title" msgid="8989086619255666442">"नई सूचनाएं बताने वाले गोल निशान की अनुमति दें"</string>
     <string name="notification_channel_badge_title" msgid="8228215248332054612">"नई सूचनाएं बताने वाला गोल निशान दिखाएं"</string>
-    <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"\'परेशान न करें\' मोड बंद करें"</string>
+    <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"\'परेशान न करें\' मोड में भी सूचनाएं दिखाएं"</string>
     <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"\'परेशान न करें\' मोड चालू होने पर भी ये सूचनाएं दिखाना जारी रखें"</string>
     <string name="app_notification_visibility_override_title" msgid="2349335170165637672">"लॉक स्क्रीन पर"</string>
     <string name="app_notification_row_banned" msgid="2079325338122151677">"अवरोधित"</string>
@@ -3437,7 +3442,7 @@
     <string name="zen_mode_add_event_rule" msgid="1398181272397489506">"इवेंट का शेड्यूल जोड़ें"</string>
     <string name="zen_mode_add_time_rule" msgid="5999467757140524729">"समय का शेड्यूल जोड़ें"</string>
     <string name="zen_mode_delete_rule" msgid="2292933835997203801">"शेड्यूल मिटाएं"</string>
-    <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"शेड्यूल का प्रकार चुनें"</string>
+    <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"किस तरह का शेड्यूल चुनना चाहते हैं"</string>
     <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"<xliff:g id="RULE">%1$s</xliff:g> नियम मिटाएं?"</string>
     <string name="zen_mode_delete_rule_button" msgid="611058106279881991">"मिटाएं"</string>
     <string name="zen_mode_rule_type_unknown" msgid="2819480113355191421">"अज्ञात"</string>
@@ -3630,7 +3635,7 @@
     <string name="filter_enabled_apps" msgid="5888459261768538489">"इंस्‍टॉल किए गए ऐप"</string>
     <string name="filter_instant_apps" msgid="8087483282854072366">"झटपट ऐप"</string>
     <string name="filter_personal_apps" msgid="3473268022652904457">"व्यक्तिगत"</string>
-    <string name="filter_work_apps" msgid="4202483998339465542">"कार्यस्‍थल"</string>
+    <string name="filter_work_apps" msgid="4202483998339465542">"ऑफ़िस"</string>
     <string name="filter_notif_all_apps" msgid="1862666327228804896">"ऐप्लिकेशन: सभी"</string>
     <string name="filter_notif_blocked_apps" msgid="5694956954776028202">"सूचनाएं बंद कर दी गई हैं"</string>
     <string name="filter_notif_urgent_channels" msgid="5000735867167027148">"श्रेणियां: अत्यंत महत्वपूर्ण"</string>
@@ -3758,7 +3763,7 @@
     <string name="assist_access_screenshot_title" msgid="1991014038776117688">"स्क्रीनशॉट का उपयोग करना"</string>
     <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"सहायक ऐप्लिकेशन को स्क्रीन की इमेज तक पहुंचने दें"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"स्क्रीन फ़्लैश करें"</string>
-    <string name="assist_flash_summary" msgid="6697095786317559129">"जब सहायक ऐप्लिकेशन स्क्रीन पर मौजूद लेख या स्क्रीनशॉट को ऐक्सेस करे तो स्क्रीन के किनारों पर रोशनी चमकाएं"</string>
+    <string name="assist_flash_summary" msgid="6697095786317559129">"जब सहायक ऐप्लिकेशन स्क्रीन पर मौजूद लेख या स्क्रीनशॉट को ऐक्सेस करे, तो स्क्रीन के किनारों पर रोशनी चमकाएं"</string>
     <string name="assist_footer" msgid="7030121180457472165">"आप जो स्क्रीन देख रहे हैं, उसकी जानकारी के आधार पर सहायक ऐप्लिकेशन आपकी मदद कर सकते हैं. कुछ ऐप्लिकेशन पर, आपकी पूरी मदद करने के लिए लॉन्चर और बोलकर फ़ोन को निर्देश देना, ये दोनों सेवाएं काम करती हैं."</string>
     <string name="average_memory_use" msgid="5333366040118953945">"औसत मेमोरी उपयोग"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"अधिकतम मेमोरी उपयोग"</string>
@@ -3873,7 +3878,7 @@
     <string name="disabled_by_policy_title_camera" msgid="3741138901926111197">"कैमरा की अनुमति नहीं है"</string>
     <string name="disabled_by_policy_title_screen_capture" msgid="1856835333536274665">"स्क्रीनशॉट की अनुमति नहीं है"</string>
     <string name="disabled_by_policy_title_suspend_packages" msgid="4254714213391802322">"इस ऐप्लिकेशन को खोला नहीं जा सकता"</string>
-    <string name="default_admin_support_msg" msgid="5789424433689798637">"अगर आपके कोई सवाल हैं तो, अपने आईटी एडमिन से संपर्क करें"</string>
+    <string name="default_admin_support_msg" msgid="5789424433689798637">"अगर आपके कोई सवाल हैं, तो अपने आईटी एडमिन से संपर्क करें"</string>
     <string name="admin_support_more_info" msgid="8737842638087863477">"ज़्यादा विवरण"</string>
     <string name="admin_profile_owner_message" msgid="3199544166281052845">"आपका एडमिन आपकी वर्क प्रोफ़ाइल से जुड़े ऐप और डेटा की निगरानी और उनका प्रबंधन कर सकता है, जिनमें सेटिंग, अनुमतियां, कॉर्पोरेट पहुंच, नेटवर्क गतिविधि और डिवाइस के जगह की जानकारी शामिल हैं."</string>
     <string name="admin_profile_owner_user_message" msgid="2991249382056855531">"आपका एडमिन इस उपयोगकर्ता से जुड़े ऐप्लिकेशन और डेटा की निगरानी और उनका प्रबंधन कर सकता है, जिनमें सेटिंग, अनुमतियां, कॉर्पोरेट पहुंच, नेटवर्क गतिविधि और डिवाइस के जगह की जानकारी शामिल है."</string>
@@ -4123,7 +4128,7 @@
     <string name="ambient_display_pickup_title" product="tablet" msgid="1555456400210301959">"टैबलेट देखने के लिए लिफ़्ट करें"</string>
     <string name="ambient_display_pickup_title" product="device" msgid="2480126522988135037">"डिवाइस देखने के लिए लिफ़्ट करें"</string>
     <string name="ambient_display_wake_screen_title" msgid="3376988352851077102">"चालू करने का डिसप्ले"</string>
-    <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"समय, सूचनाएं और दूसरी जानकारी देखने के लिए, अपना फ़ोन इस्तेमाल करें"</string>
+    <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"समय, सूचनाएं और दूसरी जानकारी देखने के लिए, अपना फ़ोन उठाएं."</string>
     <string name="ambient_display_pickup_summary" product="tablet" msgid="1077745287100012928">"समय, सूचनाएं और दूसरी जानकारी देखने के लिए, अपना टैबलेट इस्तेमाल करें."</string>
     <string name="ambient_display_pickup_summary" product="device" msgid="404199660076598026">"समय, सूचनाएं और दूसरी जानकारी देखने के लिए, अपना डिवाइस इस्तेमाल करें."</string>
     <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"फ़ोन की स्क्रीन पर टैप करके देखें कि सूचना मिली है या नहीं"</string>
@@ -4155,7 +4160,7 @@
     <string name="auto_sync_account_title" msgid="2394463123733529506">"डेटा को अपने आप सिंक करें"</string>
     <string name="auto_sync_personal_account_title" msgid="6844465157916100655">"व्यक्तिगत डेटा अपने आप सिंक करें"</string>
     <string name="auto_sync_work_account_title" msgid="2403222633447522376">"दफ़्तर डेटा अपने आप सिंक करें"</string>
-    <string name="auto_sync_account_summary" msgid="6316230976974033772">"ऐप्लिकेशन को डेटा अपने आप रीफ्रे़श करने दें"</string>
+    <string name="auto_sync_account_summary" msgid="6316230976974033772">"ऐप्लिकेशन को डेटा अपने-आप रीफ्रे़श करने दें"</string>
     <string name="account_sync_title" msgid="1570164819114297154">"खाता सिंक"</string>
     <string name="account_sync_summary_some_on" msgid="1934556869158274053">"<xliff:g id="ID_2">%2$d</xliff:g> में से <xliff:g id="ID_1">%1$d</xliff:g> आइटम के लिए सिंक करना चालू है"</string>
     <string name="account_sync_summary_all_on" msgid="3634161204232431700">"सभी आइटम के लिए सिंक करना चालू है"</string>
@@ -4468,7 +4473,7 @@
     <string name="privacy_dashboard_title" msgid="8764930992456607513">"निजता"</string>
     <string name="privacy_dashboard_summary" msgid="7916431309860824945">"अनुमतियां, खाता गतिविधि, निजी डेटा"</string>
     <string name="contextual_card_dismiss_remove" msgid="1750420285615827309">"हटाएं"</string>
-    <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"रखें"</string>
+    <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"Keep"</string>
     <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"यह सुझाव हटा दें?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"सुझाव हटाया गया"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"पहले जैसा करें"</string>
diff --git a/tests/CarDeveloperOptions/res/values-hr/arrays.xml b/tests/CarDeveloperOptions/res/values-hr/arrays.xml
index 66ab70c..238797e 100644
--- a/tests/CarDeveloperOptions/res/values-hr/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-hr/arrays.xml
@@ -34,7 +34,7 @@
     <item msgid="772029947136115322">"30 sekundi"</item>
     <item msgid="8743663928349474087">"1 minuta"</item>
     <item msgid="1506508631223164814">"2 minute"</item>
-    <item msgid="8664703938127907662">"5 minuta"</item>
+    <item msgid="8664703938127907662">"5 min"</item>
     <item msgid="5827960506924849753">"10 minuta"</item>
     <item msgid="6677424950124253938">"30 minuta"</item>
   </string-array>
@@ -56,7 +56,7 @@
     <item msgid="227647485917789272">"1 minuta"</item>
     <item msgid="3367011891231217504">"2 minute"</item>
     <item msgid="4376575879222393045">"5 minuta"</item>
-    <item msgid="811192536981678974">"10 minuta"</item>
+    <item msgid="811192536981678974">"10 min"</item>
     <item msgid="7258394417241706272">"30 minuta"</item>
   </string-array>
   <string-array name="entries_font_size">
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"izvođenje u pozadini"</item>
     <item msgid="6423861043647911030">"glasnoća pristupačnosti"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Lokacija"</item>
+    <item msgid="6656077694190491067">"Lokacija"</item>
+    <item msgid="8790228218278477369">"Lokacija"</item>
+    <item msgid="7836406246005211990">"Vibriranje"</item>
+    <item msgid="3951439024549922598">"Čitaj kontakte"</item>
+    <item msgid="8802152411647068">"Izmjena kontakata"</item>
+    <item msgid="229544934599698735">"Čitanje zapisnika poziva"</item>
+    <item msgid="7396102294405899613">"Izmjena zapisnika poziva"</item>
+    <item msgid="3597797992398484655">"Čitanje kalendara"</item>
+    <item msgid="2705975774250907343">"Izmjena kalendara"</item>
+    <item msgid="4668747371441932697">"Lokacija"</item>
+    <item msgid="1487578921720243646">"Objavljivanje obavijesti"</item>
+    <item msgid="4636080349724146638">"Lokacija"</item>
+    <item msgid="673510900286463926">"Poziv na telefon"</item>
+    <item msgid="542083422784609790">"Čitanje SMS-a/MMS-a"</item>
+    <item msgid="1033780373029588436">"Pisanje SMS-a/MMS-a"</item>
+    <item msgid="5647111115517787488">"Primanje SMS-a/MMS-a"</item>
+    <item msgid="8591105601108455893">"Primanje SMS-a/MMS-a"</item>
+    <item msgid="7730995008517841903">"Primanje SMS-a/MMS-a"</item>
+    <item msgid="2613033109026626086">"Primanje SMS-a/MMS-a"</item>
+    <item msgid="3037159047591081136">"Slanje SMS-a/MMS-a"</item>
+    <item msgid="4726682243833913568">"Čitanje SMS-a/MMS-a"</item>
+    <item msgid="6555678522277865572">"Pisanje SMS-a/MMS-a"</item>
+    <item msgid="6981734935578130884">"Izmjena postavki"</item>
+    <item msgid="8705854389991425629">"Povlačenje na vrh"</item>
+    <item msgid="5861356020344153651">"Pristup obavijestima"</item>
+    <item msgid="78432174621628659">"Fotoaparat"</item>
+    <item msgid="3986116419882154794">"Snimanje zvuka"</item>
+    <item msgid="4516840825756409490">"Reprodukcija audiozapisa"</item>
+    <item msgid="6811712502798183957">"Čitaj međuspremnik"</item>
+    <item msgid="2780369012602289114">"Izmijeni međuspremnik"</item>
+    <item msgid="2331359440170850868">"Medijski gumbi"</item>
+    <item msgid="6133599737122751231">"Audiofokus"</item>
+    <item msgid="6844485713404805301">"Glavna glasnoća"</item>
+    <item msgid="1600379420669104929">"Glasnoća glasa"</item>
+    <item msgid="6296768210470214866">"Glasnoća zvona"</item>
+    <item msgid="510690696071629241">"Glasnoća medija"</item>
+    <item msgid="406861638631430109">"Glasnoća alarma"</item>
+    <item msgid="4715864795872233884">"Glasnoća obavijesti"</item>
+    <item msgid="2311478519251301183">"Glasnoća Bluetootha"</item>
+    <item msgid="5133991377896747027">"Zadrži u aktivnom stanju"</item>
+    <item msgid="2464189519136248621">"Lokacija"</item>
+    <item msgid="2062677934050803037">"Lokacija"</item>
+    <item msgid="1735171933192715957">"Dohvaćanje statistike o upotrebi"</item>
+    <item msgid="1014093788778383554">"Isključivanje/uključivanje mikrofona"</item>
+    <item msgid="4199297950608622850">"Prikaži poruku"</item>
+    <item msgid="2527962435313398821">"Projiciraj medijske sadržaje"</item>
+    <item msgid="5117506254221861929">"Aktiviraj VPN"</item>
+    <item msgid="8291198322681891160">"Pozadinska slika za pisanje"</item>
+    <item msgid="7106921284621230961">"Pomoćna struktura"</item>
+    <item msgid="4496533640894624799">"Pomoćna snimka zaslona"</item>
+    <item msgid="2598847264853993611">"Pročitaj stanje telefona"</item>
+    <item msgid="9215610846802973353">"Dodaj govornu poštu"</item>
+    <item msgid="9186411956086478261">"Koristi SIP"</item>
+    <item msgid="6884763100104539558">"Obradi odlazni poziv"</item>
+    <item msgid="125513972170580692">"Otisak prsta"</item>
+    <item msgid="2556071024281275619">"Biometrijski senzori"</item>
+    <item msgid="617168514928339387">"Čitanje poruka mobilne mreže"</item>
+    <item msgid="7134693570516523585">"Lažiraj lokaciju"</item>
+    <item msgid="7224489175375229399">"Pročitaj pohranu"</item>
+    <item msgid="8472735063903258202">"Piši u pohranu"</item>
+    <item msgid="4069276819909595110">"Uključi zaslon"</item>
+    <item msgid="1228338896751121025">"Dohvati račune"</item>
+    <item msgid="3181581793459233672">"Izvodi u pozadini"</item>
+    <item msgid="2340936043025374076">"Glasnoća pristupačnosti"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Kratko"</item>
     <item msgid="4816511817309094890">"Srednja"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Ne dopuštaj nikada"</item>
     <item msgid="8184570120217958741">"Dopusti uvijek"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Obično"</item>
+    <item msgid="5101233285497327432">"Umjereno"</item>
+    <item msgid="1555861583162930714">"Niska"</item>
+    <item msgid="1719683776264798117">"Kritična"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Uobičajena"</item>
+    <item msgid="6107138933849816768">"Umjerena"</item>
+    <item msgid="182695359839047859">"Niska"</item>
+    <item msgid="8577246509202964244">"Kritično"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Postojana"</item>
     <item msgid="167418068739176448">"Glavna aktivnost"</item>
@@ -401,7 +477,7 @@
     <item msgid="1008268820118852416">"Mreža bez ograničenja prometa"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
-    <item msgid="6545683814310036454">"Koristi nasumično određen MAC (zadano)"</item>
+    <item msgid="6545683814310036454">"Koristi nasumičnu MAC adresu (zadano)"</item>
     <item msgid="214234417308375326">"Upotrijebite MAC uređaja"</item>
   </string-array>
   <string-array name="wifi_hidden_entries">
diff --git a/tests/CarDeveloperOptions/res/values-hr/config.xml b/tests/CarDeveloperOptions/res/values-hr/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-hr/config.xml
+++ b/tests/CarDeveloperOptions/res/values-hr/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-hr/strings.xml b/tests/CarDeveloperOptions/res/values-hr/strings.xml
index a7eefb7..be961be 100644
--- a/tests/CarDeveloperOptions/res/values-hr/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-hr/strings.xml
@@ -84,8 +84,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Smanjite ili povećajte tekst na zaslonu."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Smanji"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Povećaj"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Primjer teksta"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Čarobnjak iz Oza"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"11. poglavlje: Čudesni Smaragdni Grad čarobnjaka Oza"</string>
@@ -312,8 +311,8 @@
     <string name="cellular_data_summary" msgid="8817717603450318646">"Dopusti prijenos pod. putem mobilne mreže"</string>
     <string name="allow_data_usage_title" msgid="5381624105803294315">"Podatkovni promet u roamingu"</string>
     <string name="roaming" msgid="8860308342135146004">"Roaming"</string>
-    <string name="roaming_enable" msgid="2108142024297441116">"Povezivanje s podatkovnim uslugama u roamingu"</string>
-    <string name="roaming_disable" msgid="1915440242079953809">"Povezivanje s podatkovnim uslugama u roamingu"</string>
+    <string name="roaming_enable" msgid="2108142024297441116">"Poveži se s podatkovnim uslugama u roamingu"</string>
+    <string name="roaming_disable" msgid="1915440242079953809">"Poveži se s podatkovnim uslugama u roamingu"</string>
     <string name="roaming_reenable_message" msgid="8388505868655113258">"Izgubili ste podatkovnu vezu jer ste isključili mrežni roaming podataka."</string>
     <string name="roaming_turn_it_on_button" msgid="4370846458830537578">"Uključi"</string>
     <string name="roaming_warning" msgid="5488050911277592868">"To može biti dosta skupo."</string>
@@ -410,7 +409,7 @@
     <string name="security_settings_face_enroll_introduction_message_setup" msgid="4533297059466270074">"Licem možete otključati telefon, autorizirati kupnje ili se prijaviti na aplikacije"</string>
     <string name="security_settings_face_enroll_introduction_footer_message" msgid="7764021721107723266"></string>
     <string name="security_settings_face_enroll_repeat_title" msgid="2507710348140837875">"Postavite lice u središte kruga"</string>
-    <string name="security_settings_face_enroll_enrolling_skip" msgid="4346077260378772613">"Učinit ću to kasnije"</string>
+    <string name="security_settings_face_enroll_enrolling_skip" msgid="4346077260378772613">"Kasnije ću"</string>
     <string name="face_add_max" msgid="8870899421165189413">"Ne možete dodati više od <xliff:g id="COUNT">%d</xliff:g> lica"</string>
     <string name="face_intro_error_max" msgid="4024147799079828937">"Dodali ste maksimalan broj lica"</string>
     <string name="face_intro_error_unknown" msgid="3241592604198351134">"Nije moguće dodati više lica"</string>
@@ -422,7 +421,7 @@
     <string name="security_settings_face_enroll_done" msgid="5409739233373490971">"Gotovo"</string>
     <string name="security_settings_face_settings_use_face_category" msgid="1586532139528115416">"Koristite lice za"</string>
     <string name="security_settings_face_settings_use_face_unlock_phone" msgid="318274519126401671">"Otključavanje uređaja"</string>
-    <string name="security_settings_face_settings_use_face_for_apps" msgid="5479369083370664351">"Prijava u aplikaciju i plaćanja"</string>
+    <string name="security_settings_face_settings_use_face_for_apps" msgid="5479369083370664351">"Prijava u aplikacije i plaćanja"</string>
     <string name="security_settings_face_settings_require_attention" msgid="2755140150841557225">"Oči otvorene za otključavanje"</string>
     <string name="security_settings_face_settings_require_attention_details" msgid="2557060433599942587">"Prilikom autentifikacije licem oči moraju biti otvorene"</string>
     <string name="security_settings_face_settings_require_confirmation" msgid="7312024271060416438">"Uvijek traži potvrdu"</string>
@@ -430,11 +429,11 @@
     <string name="security_settings_face_settings_remove_face_data" msgid="2821359954483136239">"Ukloni podatke lica"</string>
     <string name="security_settings_face_settings_footer" msgid="4627175759990550715">"Za otključavanje uređaja i pristup aplikacijama može se upotrijebiti vaše lice. "<annotation id="url">"Saznajte više"</annotation></string>
     <string name="security_settings_face_settings_remove_dialog_title" msgid="5675319895815271094">"Želite li izbrisati podatke o licu?"</string>
-    <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"Podaci koje je snimilo Otključavanje licem izbrisat će se trajno i na siguran način. Nakon uklanjanja trebat će vam PIN, uzorak ili zaporka da biste otključali telefon, prijavili se na aplikacije i potvrdili plaćanja."</string>
+    <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"Podaci koje je snimilo Otključavanje licem izbrisat će se trajno i na siguran način. Nakon uklanjanja trebat će vam PIN, uzorak ili zaporka da biste otključali telefon, prijavili se u aplikacije i potvrdili plaćanja."</string>
     <string name="security_settings_fingerprint_preference_title" msgid="4177132225930582928">"Otisak prsta"</string>
     <string name="fingerprint_manage_category_title" msgid="1463406696801542090">"Otisci prstiju"</string>
     <string name="fingerprint_usage_category_title" msgid="7298369141954599706">"Upotreba otiska prsta"</string>
-    <string name="fingerprint_add_title" msgid="6840343900784463856">"Dodaj otisak prsta"</string>
+    <string name="fingerprint_add_title" msgid="6840343900784463856">"Dodajte otisak prsta"</string>
     <string name="fingerprint_enable_keyguard_toggle_title" msgid="8847663949921113437">"zaključavanje zaslona"</string>
     <plurals name="security_settings_fingerprint_preference_summary" formatted="false" msgid="2033416761172877041">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> otisak prsta postavljen</item>
@@ -444,7 +443,7 @@
     <string name="security_settings_fingerprint_preference_summary_none" msgid="3613424536269750172"></string>
     <string name="security_settings_fingerprint_enroll_introduction_title" msgid="889558002683900544">"Otključavanje otiskom"</string>
     <string name="security_settings_fingerprint_enroll_introduction_title_unlock_disabled" msgid="7915504118657864429">"Upotreba otiska prsta"</string>
-    <string name="security_settings_fingerprint_enroll_introduction_message" msgid="5586198131986682472">"Jednostavno dodirnite senzor otiska prsta da biste otključali telefon, autorizirali kupnje ili se prijavili na aplikacije. Pazite čije otiske dodajete. Svaki otisak koji dodate može se upotrijebiti za sve te radnje.\n\nNapomena: otisak prsta nije toliko siguran kao snažan uzorak ili PIN."</string>
+    <string name="security_settings_fingerprint_enroll_introduction_message" msgid="5586198131986682472">"Jednostavno dodirnite senzor otiska prsta da biste otključali telefon, autorizirali kupnje ili se prijavili u aplikacije. Pazite čije otiske dodajete. Svaki otisak koji dodate može se upotrijebiti za sve te radnje.\n\nNapomena: otisak prsta nije toliko siguran kao snažan uzorak ili PIN."</string>
     <string name="security_settings_fingerprint_enroll_introduction_message_unlock_disabled" msgid="1640839304679275468">"Otključajte telefon ili odobrite kupnje otiskom prsta.\n\nNapomena: ovaj uređaj ne možete otključati otiskom prsta. Za više informacija obratite se administratoru organizacije."</string>
     <string name="security_settings_fingerprint_enroll_introduction_message_setup" msgid="6734490666593320711">"Otključajte telefon ili odobrite kupnje otiskom prsta.\n\nNapomena: otisak prst može biti manje siguran od snažnog uzorka ili PIN-a."</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel" msgid="9168637333731599827">"Odustani"</string>
@@ -452,7 +451,7 @@
     <string name="security_settings_fingerprint_enroll_introduction_cancel_setup" msgid="756928427429893070">"Preskoči"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue_setup" msgid="4125977169169671144">"Dalje"</string>
     <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"Želite li preskočiti otisak prsta?"</string>
-    <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"Postavljanje otisaka prstiju traje samo jednu ili dvije minute. Ako to preskočite, otiske prstiju možete dodati kasnije u postavkama."</string>
+    <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"Postavljanje otiska prsta traje samo jednu ili dvije minute. Ako to preskočite, otisak prsta možete dodati kasnije u postavkama."</string>
     <string name="lock_screen_intro_skip_title" msgid="5307431665496346914">"Želite li preskočiti zaključavanje zaslona?"</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="tablet" msgid="7553945981266845264">"Značajke za zaštitu uređaja neće se uključiti. Nećete moći spriječiti druge da upotrebljavaju ovaj tablet u slučaju gubitka, krađe ili vraćanja na zadano."</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="device" msgid="1378243257238015603">"Značajke za zaštitu uređaja neće se uključiti. Nećete moći spriječiti druge da upotrebljavaju ovaj uređaj u slučaju gubitka, krađe ili vraćanja na zadano."</string>
@@ -476,7 +475,7 @@
     <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Nastavite podizati prst da biste dodali različite dijelove otiska prsta"</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"Otisak prsta dodan"</string>
     <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"Kada se prikaže ta ikona, upotrijebite otisak prsta da biste se identificirali ili odobrili kupnju"</string>
-    <string name="security_settings_fingerprint_enroll_enrolling_skip" msgid="1473280156532146933">"Učinit ću to kasnije"</string>
+    <string name="security_settings_fingerprint_enroll_enrolling_skip" msgid="1473280156532146933">"Kasnije ću"</string>
     <string name="setup_fingerprint_enroll_enrolling_skip_title" msgid="2816424026528101690">"Preskočiti postavljanje otiska prsta?"</string>
     <string name="setup_fingerprint_enroll_enrolling_skip_message" msgid="8139299964344809780">"Odlučili ste se za otisak prsta kao jedan od načina za otključavanje telefona. Ako sad preskočite, morat ćete ga postaviti kasnije. Postavljanje traje samo otprilike jednu minutu."</string>
     <string name="fingerprint_lock_screen_setup_skip_dialog_text" product="tablet" msgid="1384438077720821127">"Zaštitite tablet pomoću opcije zaključavanja zaslona kako se nitko ne bi mogao njime koristiti ako ga izgubite ili ga netko ukrade. Opcija zaključavanja zaslona treba vam i za postavljanje otiska prsta. Dodirnite Odustani, a zatim postavite PIN ili odaberite neku drugu opciju zaključavanja zaslona."</string>
@@ -676,7 +675,6 @@
       <item quantity="few">Mora sadržavati manje od <xliff:g id="NUMBER_1">%d</xliff:g> znamenke</item>
       <item quantity="other">Mora sadržavati manje od <xliff:g id="NUMBER_1">%d</xliff:g> znamenki</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Smije sadržavati samo znamenke od 0 do 9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Administrator uređaja ne dopušta upotrebu nedavnog PIN-a"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Vaš je IT administrator blokirao uobičajene PIN-ove. Pokušajte s nekom drugim PIN-om."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Unos ne smije sadržavati nevažeće znakove"</string>
@@ -713,6 +711,11 @@
       <item quantity="few">Mora sadržavati najmanje <xliff:g id="COUNT">%d</xliff:g> znaka koji nisu slova</item>
       <item quantity="other">Mora sadržavati najmanje <xliff:g id="COUNT">%d</xliff:g> znakova koji nisu slova</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">Mora sadržavati najmanje <xliff:g id="COUNT">%d</xliff:g> znak koji nije znamenka</item>
+      <item quantity="few">Mora sadržavati najmanje <xliff:g id="COUNT">%d</xliff:g> znaka koji nisu znamenke</item>
+      <item quantity="other">Mora sadržavati najmanje <xliff:g id="COUNT">%d</xliff:g> znakova koji nisu znamenke</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Administrator uređaja ne dopušta upotrebu nedavne zaporke"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Vaš je IT administrator blokirao uobičajene zaporke. Pokušajte s nekom drugom zaporkom."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Uzastopno rastući ili padajući slijed brojeva ili ponavljanje brojeva nije dopušteno"</string>
@@ -730,7 +733,7 @@
       <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> aktivne aplikacije</item>
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> aktivnih aplikacija</item>
     </plurals>
-    <string name="manage_trust_agents" msgid="8129970926213142261">"Pouzdani predstavnici"</string>
+    <string name="manage_trust_agents" msgid="8129970926213142261">"Agenti za pouzdanost"</string>
     <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"Za upotrebu prvo postavite zaključavanje zaslona"</string>
     <string name="manage_trust_agents_summary" msgid="2023116850759962248">"Ništa"</string>
     <plurals name="manage_trust_agents_summary_on" formatted="false" msgid="5550538038916606097">
@@ -888,7 +891,7 @@
     <string name="wifi_switch_away_when_unvalidated" msgid="2418577764071293971">"Prijeđi na mobilne podatke ako Wi‑Fi izgubi pristup internetu."</string>
     <string name="wifi_cellular_data_fallback_title" msgid="5067241930716252665">"Automatski prijeđi na mobilne podatke"</string>
     <string name="wifi_cellular_data_fallback_summary" msgid="2721467405851519769">"Koristite mobilne podatke kada Wi-Fi nema pristup internetu. Moguća je naplata potrošnje podatkovnog prometa."</string>
-    <string name="wifi_add_network" msgid="4094957940791876640">"Dodaj mrežu"</string>
+    <string name="wifi_add_network" msgid="4094957940791876640">"Dodajte mrežu"</string>
     <string name="wifi_configure_settings_preference_title" msgid="2678534679408777268">"Postavke Wi‑Fi-ja"</string>
     <string name="wifi_configure_settings_preference_summary_wakeup_on" msgid="5714892572614655675">"Wi‑Fi se automatski ponovo uključuje"</string>
     <string name="wifi_configure_settings_preference_summary_wakeup_off" msgid="286904094152909651">"Wi‑Fi se ne uključuje ponovno automatski"</string>
@@ -953,7 +956,7 @@
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"Skeniraj QR kôd"</string>
     <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"Centrirajte QR kôd u nastavku da biste se povezali s mrežom “<xliff:g id="SSID">%1$s</xliff:g>”"</string>
     <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"Pridružite se Wi‑Fiju tako što ćete skenirati QR kôd"</string>
-    <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Dijeli Wi‑Fi"</string>
+    <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Dijelite Wi‑Fi"</string>
     <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"Skenirajte ovaj QR kôd da biste se povezali s mrežom \"<xliff:g id="SSID">%1$s</xliff:g>\" i podijelili zaporku"</string>
     <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"Skenirajte ovaj QR kôd da biste se povezali s mrežom \"<xliff:g id="SSID">%1$s</xliff:g>\""</string>
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"Čitanje QR koda nije uspjelo. Ponovo centrirajte kôd, a zatim pokušajte opet"</string>
@@ -989,7 +992,7 @@
     <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"Nemoj potvrditi"</string>
     <string name="wifi_do_not_validate_eap_server_warning" msgid="3895397996759837323">"Nije naveden nijedan certifikat. Veza neće biti privatna."</string>
     <string name="wifi_ssid_too_long" msgid="34911971389775920">"Mreža ima predugačak naziv."</string>
-    <string name="wifi_no_domain_warning" msgid="735859919311067606">"Mora navoditi domenu."</string>
+    <string name="wifi_no_domain_warning" msgid="735859919311067606">"Mora se navesti domena."</string>
     <string name="wifi_wps_available_first_item" msgid="3221671453930485243">"WPS dostupan"</string>
     <string name="wifi_wps_available_second_item" msgid="5703265526619705185">" (WPS dostupan)"</string>
     <string name="wifi_carrier_connect" msgid="7202618367339982884">"Wi‑Fi mreža mobilnog operatera"</string>
@@ -1035,7 +1038,7 @@
     <string name="wifi_advanced_ssid_title" msgid="4229741334913894856">"SSID"</string>
     <string name="wifi_advanced_mac_address_title" msgid="1162782083754021737">"MAC adresa"</string>
     <string name="wifi_advanced_ip_address_title" msgid="2708185994512829071">"IP adresa"</string>
-    <string name="wifi_details_title" msgid="2164042631550920157">"Pojedinosti o mreži"</string>
+    <string name="wifi_details_title" msgid="2164042631550920157">"Podaci o mreži"</string>
     <string name="wifi_details_subnet_mask" msgid="53396707004763012">"Maska podmreže"</string>
     <string name="wifi_details_dns" msgid="1118251455740116559">"DNS"</string>
     <string name="wifi_details_ipv6_address_header" msgid="1642310137145363299">"IPv6 adrese"</string>
@@ -1060,7 +1063,7 @@
     <string name="wifi_p2p_persist_network" msgid="1110453878886476660">"Zapamti tu vezu"</string>
     <string name="wifi_p2p_menu_search" msgid="8207638860263805291">"Traženje uređaja"</string>
     <string name="wifi_p2p_menu_searching" msgid="7443249001543208106">"Traženje..."</string>
-    <string name="wifi_p2p_menu_rename" msgid="2129974878377065488">"Preimenuj uređaj"</string>
+    <string name="wifi_p2p_menu_rename" msgid="2129974878377065488">"Promjena naziva uređaja"</string>
     <string name="wifi_p2p_peer_devices" msgid="8232126067045093382">"Paralelni uređaji"</string>
     <string name="wifi_p2p_remembered_groups" msgid="1356458238836730346">"Zapamćene grupe"</string>
     <string name="wifi_p2p_failed_connect_message" msgid="6103436959132424093">"Povezivanje nije bilo moguće."</string>
@@ -1117,7 +1120,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mobilni uređaj"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Ako Wi‑Fi nije dostupan, koristi mobilnu mrežu"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Ako mobilna mreža nije dostupna, koristi Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Pozivi putem Wi-Fija. Ako se Wi‑Fi izgubi, poziv će završiti."</string>
@@ -1471,7 +1477,7 @@
     <string name="storage_detail_system" msgid="6784247618772153283">"Sustav"</string>
     <string name="storage_detail_explore" msgid="8206900269596580264">"Istraži <xliff:g id="NAME">^1</xliff:g>"</string>
     <string name="storage_detail_dialog_other" msgid="5073511663616043370">"Ostalo uključuje dijeljene datoteke koje su spremile aplikacije, datoteke preuzete s interneta ili Bluetoothom, Android datoteke i tako dalje. \n\nDa biste vidjeli što sadrži <xliff:g id="NAME">^1</xliff:g>, dodirnite Istraži."</string>
-    <string name="storage_detail_dialog_system" msgid="1472572861360014226">"Sustav uključuje datoteke koje se upotrebljavaju za pokretanje verzije Androida <xliff:g id="VERSION">%s</xliff:g>"</string>
+    <string name="storage_detail_dialog_system" msgid="1472572861360014226">"Sustav uključuje datoteke koje se upotrebljavaju za pokretanje Androida verzije <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="storage_detail_dialog_user" msgid="1663117417635010371">"Korisnik <xliff:g id="USER_0">^1</xliff:g> možda je spremio fotografije, glazbu, aplikacije ili druge podatke, čime je iskorišteno <xliff:g id="SIZE">^2</xliff:g> prostora. \n\nZa prikaz pojedinosti prijeđite na račun korisnika <xliff:g id="USER_1">^1</xliff:g>."</string>
     <string name="storage_wizard_init_title" msgid="3407283236421089014">"Postavite uređaj <xliff:g id="NAME">^1</xliff:g>"</string>
     <string name="storage_wizard_init_external_title" msgid="6853250619674645478">"Upotrebljavaj kao prijenosnu pohranu"</string>
@@ -1633,7 +1639,7 @@
     <string name="tether_settings_summary_hotspot_off_tether_on" msgid="1349909238672649877">"Modemsko povezivanje"</string>
     <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"Dok je Štednja podatkovnog prometa uključena, ne možete upotrebljavati modemsko povezivanje ni prijenosne žarišne točke"</string>
     <string name="usb_title" msgid="7480927657535578688">"USB"</string>
-    <string name="usb_tethering_button_text" msgid="6242228383142012332">"Dijeljenje USB-om"</string>
+    <string name="usb_tethering_button_text" msgid="6242228383142012332">"Dijeljenje veze USB-om"</string>
     <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"Dijelite internetsku vezu telefona putem USB-a"</string>
     <string name="usb_tethering_subtext" product="tablet" msgid="154536000235361034">"Dijelite internetsku vezu tableta putem USB-a"</string>
     <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"Dijeljenje veze Bluetoothom"</string>
@@ -1819,7 +1825,7 @@
     <string name="screen_compatibility_label" msgid="3638271673726075815">"Kompatibilnost zaslona"</string>
     <string name="permissions_label" msgid="7341733648403464213">"Dozvole"</string>
     <string name="cache_header_label" msgid="3202284481380361966">"Predmemorija"</string>
-    <string name="clear_cache_btn_text" msgid="107507684844780651">"Očisti predmemoriju"</string>
+    <string name="clear_cache_btn_text" msgid="107507684844780651">"Isprazni predmemoriju"</string>
     <string name="cache_size_label" msgid="6205173678102220499">"Predmemorija"</string>
     <plurals name="uri_permissions_text" formatted="false" msgid="8938478333743197020">
       <item quantity="one">%d stavka</item>
@@ -1840,7 +1846,7 @@
     <string name="install_text" msgid="2798092278891807849">"Instaliraj"</string>
     <string name="disable_text" msgid="5065834603951474397">"Onemogući"</string>
     <string name="enable_text" msgid="7179141636849225884">"Omogući"</string>
-    <string name="clear_user_data_text" msgid="8894073247302821764">"Izbriši pohranu"</string>
+    <string name="clear_user_data_text" msgid="8894073247302821764">"Isprazni pohranu"</string>
     <string name="app_factory_reset" msgid="8718986000278776272">"Deinstaliraj ažuriranja"</string>
     <string name="auto_launch_enable_text" msgid="3372898942144027341">"Odlučili ste da se ta aplikacija pokreće prema zadanim postavkama za neke radnje."</string>
     <string name="always_allow_bind_appwidgets_text" msgid="2286211654774611037">"Odlučili ste dopustiti ovoj aplikaciji izradu widgeta i pristupanje njihovim podacima."</string>
@@ -2056,7 +2062,7 @@
     <string name="vision_settings_description" msgid="3476589459009287332">"Ovaj uređaj možete prilagoditi svojim potrebama. Značajke pristupačnosti možete promijeniti kasnije u postavkama."</string>
     <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"Promjena veličine fonta"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"Čitači zaslona"</string>
-    <string name="audio_and_captions_category_title" msgid="6140472938769619212">"Audio i tekst na zaslonu"</string>
+    <string name="audio_and_captions_category_title" msgid="6140472938769619212">"Zvuk i tekst na zaslonu"</string>
     <string name="display_category_title" msgid="545168481672250195">"Zaslon"</string>
     <string name="interaction_control_category_title" msgid="8775039211811947683">"Kontrole interakcije"</string>
     <string name="user_installed_services_category_title" msgid="4288689493753221319">"Preuzete usluge"</string>
@@ -2086,9 +2092,9 @@
     <string name="accessibility_power_button_ends_call_prerefence_title" msgid="6172987104538172869">"Tipka za uklj. prekida poziv"</string>
     <string name="accessibility_toggle_large_pointer_icon_title" msgid="9127905775116570565">"Veliki pokazivač miša"</string>
     <string name="accessibility_disable_animations" msgid="8378441317115710009">"Uklanjanje animacija"</string>
-    <string name="accessibility_toggle_master_mono_title" msgid="899550848196702565">"Monoaudio"</string>
+    <string name="accessibility_toggle_master_mono_title" msgid="899550848196702565">"Monozvuk"</string>
     <string name="accessibility_toggle_master_mono_summary" msgid="3847052868469033235">"Kombiniranje kanala prilikom reprodukcije zvuka"</string>
-    <string name="accessibility_toggle_master_balance_title" msgid="8723492001092647562">"Audio balans"</string>
+    <string name="accessibility_toggle_master_balance_title" msgid="8723492001092647562">"Ravnoteža zvuka"</string>
     <string name="accessibility_toggle_master_balance_left_label" msgid="8531986342666527970">"Lijevi"</string>
     <string name="accessibility_toggle_master_balance_right_label" msgid="7757024572140589558">"Desni"</string>
     <string name="accessibility_timeout_default" msgid="9118596941362716397">"Zadano"</string>
@@ -2111,7 +2117,7 @@
     <string name="accessibility_ring_vibration_title" msgid="7943341443551359985">"Vibracija pri zvonjenju"</string>
     <string name="accessibility_touch_vibration_title" msgid="285890135612038092">"Vibracija za dodir"</string>
     <string name="accessibility_service_master_switch_title" msgid="2734791644475782924">"Upotreba usluge"</string>
-    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Upotreba korekcije boje"</string>
+    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Korekcija boje"</string>
     <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"Upotreba titlova"</string>
     <string name="accessibility_hearingaid_instruction_continue_button" msgid="4650111296711466691">"Nastavi"</string>
     <string name="accessibility_hearingaid_title" msgid="3700978781235124891">"Slušni aparati"</string>
@@ -2605,11 +2611,11 @@
     <string name="managed_device_admin_title" msgid="8021522755492551726">"Posao"</string>
     <string name="sms_access_restriction_enabled" msgid="3006320256764718303">"Ograniči pristup SMS-ovima i zapisniku poziva"</string>
     <string name="sms_access_restriction_enabled_summary" msgid="9011946580977780063">"Samo zadane aplikacije za telefon i poruke imaju dopuštenja za SMS i zapisnik poziva"</string>
-    <string name="no_trust_agents" msgid="5757792915019113084">"Pouzdani predstavnici nisu dostupni"</string>
+    <string name="no_trust_agents" msgid="5757792915019113084">"Agenti za pouzdanost nisu dostupni"</string>
     <string name="add_device_admin_msg" msgid="3573765823476931173">"Aktivirati apl. administratora uređaja?"</string>
     <string name="add_device_admin" msgid="1621152410207260584">"Aktiviraj aplikaciju administratora ovog uređaja"</string>
     <string name="device_admin_add_title" msgid="6097881332139146897">"Administrator uređaja"</string>
-    <string name="device_admin_warning" msgid="4421817419326480449">"Aktiviranjem ove administratorske aplikacije dopustit ćete aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> da izvede sljedeće postupke:"</string>
+    <string name="device_admin_warning" msgid="4421817419326480449">"Aktiviranjem ove administratorske aplikacije dopustit ćete aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> izvođenje sljedećih postupaka:"</string>
     <string name="device_admin_status" msgid="5424944611789040723">"Ova je administratorska aplikacija aktivna i omogućuje aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> izvođenje sljedećih postupaka:"</string>
     <string name="profile_owner_add_title" msgid="735805919754362791">"Želite li aktivirati upravitelj profila?"</string>
     <string name="adding_profile_owner_warning" msgid="1284541194547382194">"Ako nastavite, vašim će korisnikom upravljati administrator, koji uz vaše osobne podatke može spremiti i povezane podatke.\n\nVaš administrator može nadzirati postavke, pristup, aplikacije i podatke povezane s tim korisnikom, uključujući aktivnosti na mreži i podatke o lokaciji uređaja te njima upravljati."</string>
@@ -2789,7 +2795,7 @@
     <string name="vpn_not_used" msgid="2889520789132261454">"(ne koristi se)"</string>
     <string name="vpn_no_ca_cert" msgid="486605757354800838">"(ne potvrđuj poslužitelj)"</string>
     <string name="vpn_no_server_cert" msgid="679622228649855629">"(primljen od poslužitelja)"</string>
-    <string name="vpn_always_on_invalid_reason_type" msgid="165810330614905489">"Ova vrsta VPN-a ne može ostati povezana u svakom trenutku"</string>
+    <string name="vpn_always_on_invalid_reason_type" msgid="165810330614905489">"Ova vrsta VPN-a ne podržava stalnu vezu"</string>
     <string name="vpn_always_on_invalid_reason_server" msgid="3864424127328210700">"Uvijek uključeni VPN podržava samo numeričke adrese poslužitelja"</string>
     <string name="vpn_always_on_invalid_reason_no_dns" msgid="3814114757059738225">"Za uvijek uključeni VPN mora biti naveden DNS poslužitelj"</string>
     <string name="vpn_always_on_invalid_reason_dns" msgid="501388894176868973">"Adrese DNS poslužitelja za uvijek uključeni VPN moraju biti numeričke"</string>
@@ -2821,7 +2827,7 @@
     <string name="vpn_menu_delete" msgid="4128305800374946877">"Izbriši profil"</string>
     <string name="vpn_menu_lockdown" msgid="6951452279924808089">"Uvijek uključena VPN mreža"</string>
     <string name="vpn_no_vpns_added" msgid="6616183541896197147">"Nije dodan nijedan VPN"</string>
-    <string name="vpn_always_on_summary" msgid="3639994551631437397">"Zadrži vezu s VPN-om u svakom trenutku"</string>
+    <string name="vpn_always_on_summary" msgid="3639994551631437397">"Održavaj stalnu vezu s VPN-om"</string>
     <string name="vpn_always_on_summary_not_supported" msgid="9077720997795965133">"Ova aplikacija ne podržava tu opciju"</string>
     <string name="vpn_always_on_summary_active" msgid="8962619701962239088">"Značajka Uvijek uključeno aktivna"</string>
     <string name="vpn_require_connection" msgid="5413746839457797350">"Blokiraj veze bez VPN-a"</string>
@@ -2906,8 +2912,8 @@
     <string name="user_add_user_title" msgid="2320897397066676472">"Dodati novog korisnika?"</string>
     <string name="user_add_user_message_long" msgid="686637203224195465">"Da biste ovaj uređaj dijelili s drugima, možete napraviti dodatne korisnike. Svaki korisnik ima svoj prostor koji može prilagoditi pomoću vlastitih aplikacija, pozadine i tako dalje. Korisnici mogu prilagoditi i postavke uređaja koje utječu na sve ostale korisnike, na primjer Wi‑Fi.\n\nKada dodate novog korisnika, ta osoba mora postaviti svoj prostor.\n\nBilo koji korisnik može ažurirati aplikacije za sve ostale korisnike. Postavke i usluge pristupačnosti možda se neće prenijeti na novog korisnika."</string>
     <string name="user_add_user_message_short" msgid="1802594476285458254">"Kada dodate novog korisnika, ta osoba mora postaviti vlastiti prostor.\n\nBilo koji korisnik može ažurirati aplikacije za sve ostale korisnike."</string>
-    <string name="user_setup_dialog_title" msgid="6748950002206392396">"Postaviti korisnika sada?"</string>
-    <string name="user_setup_dialog_message" msgid="2988559933258353919">"Provjerite može li osoba uzeti uređaj i postaviti svoj prostor"</string>
+    <string name="user_setup_dialog_title" msgid="6748950002206392396">"Želite li postaviti korisnika?"</string>
+    <string name="user_setup_dialog_message" msgid="2988559933258353919">"Uređaj morate dati toj osobi da sama postavi svoj prostor"</string>
     <string name="user_setup_profile_dialog_message" msgid="7611900802824048526">"Želite li sada postaviti profil?"</string>
     <string name="user_setup_button_setup_now" msgid="4941459406266856176">"Postavi sada"</string>
     <string name="user_setup_button_setup_later" msgid="6596031428556518752">"Ne sad"</string>
@@ -3015,8 +3021,8 @@
     <string name="wizard_back" msgid="223654213898117594">"Natrag"</string>
     <string name="wizard_next" msgid="5239664512608113542">"Dalje"</string>
     <string name="wizard_finish" msgid="3742102879981212094">"Završi"</string>
-    <string name="user_image_take_photo" msgid="2000247510236178111">"Snimi fotografiju"</string>
-    <string name="user_image_choose_photo" msgid="4920315415203051898">"Odaberi sliku"</string>
+    <string name="user_image_take_photo" msgid="2000247510236178111">"Snimite fotografiju"</string>
+    <string name="user_image_choose_photo" msgid="4920315415203051898">"Odaberite sliku"</string>
     <string name="user_image_photo_selector" msgid="8429694590849882411">"Odabir slike"</string>
     <string name="regulatory_info_text" msgid="9112993912873512834"></string>
     <string name="sim_setup_wizard_title" msgid="77627575294867180">"SIM kartice"</string>
@@ -3187,7 +3193,7 @@
     <string name="charging_sounds_title" msgid="5070437987230894287">"Zvukovi i vibracija punjenja"</string>
     <string name="docking_sounds_title" msgid="2573137471605541366">"Zvukovi priključivanja"</string>
     <string name="touch_sounds_title" msgid="165237488496165652">"Zvukovi dodirivanja"</string>
-    <string name="vibrate_on_touch_title" msgid="6360155469279157684">"Vibracija za dodir"</string>
+    <string name="vibrate_on_touch_title" msgid="6360155469279157684">"Vibracija pri dodirivanju"</string>
     <string name="vibrate_on_touch_summary" msgid="5504424764028676043">"Haptičke povratne informacije za dodir, tipkovnicu i više"</string>
     <string name="dock_audio_media_title" msgid="1859521680502040781">"Priključna stanica reproducira"</string>
     <string name="dock_audio_media_disabled" msgid="4300752306178486302">"Sve zvukove"</string>
@@ -3269,7 +3275,7 @@
     <string name="zen_mode_button_turn_on" msgid="1097964136225943415">"Uključi sada"</string>
     <string name="zen_mode_button_turn_off" msgid="3990967728457149454">"Odmah isključi"</string>
     <string name="zen_mode_settings_dnd_manual_end_time" msgid="4307574188962071429">"Način Ne uznemiravaj uključen je do <xliff:g id="FORMATTED_TIME">%s</xliff:g>"</string>
-    <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"Način Ne ometaj ostat će uključen dok ga ne isključite"</string>
+    <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"Način Ne uznemiravaj ostat će uključen dok ga ne isključite"</string>
     <string name="zen_mode_settings_dnd_automatic_rule" msgid="2843297614114625408">"Raspored <xliff:g id="RULE_NAME">%s</xliff:g> automatski je uključio Ne uznemiravaj"</string>
     <string name="zen_mode_settings_dnd_automatic_rule_app" msgid="5103454923160912313">"Način Ne uznemiravaj automatski je uključila aplikacija (<xliff:g id="APP_NAME">%s</xliff:g>)"</string>
     <string name="zen_mode_settings_dnd_custom_settings_footer" msgid="6335108298640066560">"Način Ne uznemiravaj uključen je za <xliff:g id="RULE_NAMES">%s</xliff:g> uz prilagođene postavke."</string>
@@ -3334,7 +3340,7 @@
     <string name="other_sound_category_preference_title" msgid="2045757472469840859">"Ostali zvukovi i vibracije"</string>
     <string name="configure_notification_settings" msgid="291914315140851270">"Obavijesti"</string>
     <string name="recent_notifications" msgid="8125865995065032049">"Nedavno poslano"</string>
-    <string name="recent_notifications_see_all_title" msgid="4089007770442871469">"Prikaži sve u posljednjih 7 dana"</string>
+    <string name="recent_notifications_see_all_title" msgid="4089007770442871469">"Pogledajte sve u posljednjih 7 dana"</string>
     <string name="advanced_section_header" msgid="984680389373090015">"Dodatne postavke"</string>
     <string name="profile_section_header" msgid="5471479005472037417">"Obavijesti s radnog profila"</string>
     <string name="asst_capability_prioritizer_title" msgid="3488284760645922160">"Automatsko određivanje prioriteta za obavijesti"</string>
@@ -3359,12 +3365,12 @@
     <string name="notification_pulse_title" msgid="4861418327614907116">"Trepereće svjetlo"</string>
     <string name="lock_screen_notifications_title" msgid="6889072265118747835">"Na zaključanom zaslonu"</string>
     <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"Kad je radni profil zaključan"</string>
-    <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Prikaži sav sadržaj obavijesti"</string>
+    <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Prikazuje se cijeli sadržaj obavijesti"</string>
     <string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"Sakrij osjetljiv sadržaj"</string>
-    <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"Uopće ne prikazuj obavijesti"</string>
+    <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"Obavijesti se ne prikazuju"</string>
     <string name="lock_screen_notifications_interstitial_message" msgid="4230189215124387818">"Kako želite da se prikazuju obavijesti kad je uređaj zaključan?"</string>
     <string name="lock_screen_notifications_interstitial_title" msgid="2832587379332443505">"Obavijesti"</string>
-    <string name="lock_screen_notifications_summary_show_profile" msgid="8908775469657073273">"Prikaži sav sadržaj obavijesti radnog profila"</string>
+    <string name="lock_screen_notifications_summary_show_profile" msgid="8908775469657073273">"Prikazuje se cijeli sadržaj obavijesti  radnog profila"</string>
     <string name="lock_screen_notifications_summary_hide_profile" msgid="7898086300511010591">"Sakrij osjetljiv sadržaj s posla"</string>
     <string name="lock_screen_notifications_interstitial_message_profile" msgid="3324187664458600354">"Kako želite da se prikazuju obavijesti profila kada je uređaj zaključan?"</string>
     <string name="lock_screen_notifications_interstitial_title_profile" msgid="4043621508889929254">"Obavijesti profila"</string>
@@ -3464,7 +3470,7 @@
     <string name="notification_content_block_summary" msgid="2743896875255591743">"Nikad ne prikazuj obavijesti na zaslonu obavijesti ili na perifernim uređajima"</string>
     <string name="notification_badge_title" msgid="8989086619255666442">"Dopusti točku obavijesti"</string>
     <string name="notification_channel_badge_title" msgid="8228215248332054612">"Prikaži točku obavijesti"</string>
-    <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"Nadjačaj Ne ometaj"</string>
+    <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"Nadjačaj način rada Ne uznemiravaj"</string>
     <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"Dopusti obavijesti u načinu Ne ometaj kad je postavljen na \"Samo prioritetno\""</string>
     <string name="app_notification_visibility_override_title" msgid="2349335170165637672">"Na zaključanom zaslonu"</string>
     <string name="app_notification_row_banned" msgid="2079325338122151677">"Blokirano"</string>
@@ -3747,8 +3753,8 @@
     <string name="process_format" msgid="8575347150598564509">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="COUNT">%2$d</xliff:g>)"</string>
     <string name="high_power_apps" msgid="2518319744362028920">"Optimizacija baterije"</string>
     <string name="additional_battery_info" msgid="6877663897819271203">"Upozorenja o upotrebi"</string>
-    <string name="show_all_apps" msgid="5442552004569634846">"Prikaži potpunu upotrebu uređaja"</string>
-    <string name="hide_extra_apps" msgid="6798261081113299441">"Prikaži upotrebu aplikacije"</string>
+    <string name="show_all_apps" msgid="5442552004569634846">"Prikaži ukupnu potrošnju uređaja"</string>
+    <string name="hide_extra_apps" msgid="6798261081113299441">"Prikaži potrošnju aplikacija"</string>
     <plurals name="power_high_usage_summary" formatted="false" msgid="4658343710126205199">
       <item quantity="one"><xliff:g id="NUMBER">%2$d</xliff:g> aplikacija ne ponaša se na uobičajen način</item>
       <item quantity="few"><xliff:g id="NUMBER">%2$d</xliff:g> aplikacije ne ponašaju se na uobičajen način</item>
@@ -3926,7 +3932,7 @@
     <string name="backup_disabled" msgid="6941165814784765643">"Sigurnosno kopiranje onemogućeno"</string>
     <string name="android_version_summary" msgid="2192751442789395445">"Ažuriran na Android <xliff:g id="VERSION">%1$s</xliff:g>"</string>
     <string name="android_version_pending_update_summary" msgid="3554543810520655076">"Dostupno je ažuriranje"</string>
-    <string name="disabled_by_policy_title" msgid="1238318274952958846">"Radnja nije dopuštena."</string>
+    <string name="disabled_by_policy_title" msgid="1238318274952958846">"Radnja nije dopuštena"</string>
     <string name="disabled_by_policy_title_adjust_volume" msgid="7094547090629203316">"Glasnoća se ne može promijeniti"</string>
     <string name="disabled_by_policy_title_outgoing_calls" msgid="3805836913095496278">"Pozivanje nije dopušteno"</string>
     <string name="disabled_by_policy_title_sms" msgid="1453236584236681105">"SMS nije dopušten"</string>
@@ -3952,7 +3958,7 @@
     <string name="condition_battery_summary" msgid="1236078243905690620">"Značajke su ograničene"</string>
     <string name="condition_cellular_title" msgid="6605277435894307935">"Mobilni su podaci isključeni"</string>
     <string name="condition_cellular_summary" msgid="3607459310548343777">"Internet je dostupan samo putem Wi‑Fija"</string>
-    <string name="condition_bg_data_title" msgid="184684435298857712">"Štednja podat. prometa"</string>
+    <string name="condition_bg_data_title" msgid="184684435298857712">"Štednja podatkovnog prometa"</string>
     <string name="condition_bg_data_summary" msgid="5194942860807136682">"Značajke su ograničene"</string>
     <string name="condition_work_title" msgid="9046811302347490371">"Radni je profil isključen"</string>
     <string name="condition_work_summary" msgid="5586134491975748565">"Za aplikacije i obavijesti"</string>
@@ -4045,8 +4051,8 @@
     <string name="no_carrier_update_now_text" msgid="4405472895804759042">"Upravo je ažurirano"</string>
     <string name="launch_mdp_app_text" msgid="9186559496664208252">"Prikaži plan"</string>
     <string name="launch_wifi_text" msgid="317820210431682605">"Prikaz pojedinosti"</string>
-    <string name="data_saver_title" msgid="7903308134514179256">"Štednja podat. prometa"</string>
-    <string name="unrestricted_data_saver" msgid="9139401849550738720">"Neograničena potrošnja"</string>
+    <string name="data_saver_title" msgid="7903308134514179256">"Štednja podatkovnog prometa"</string>
+    <string name="unrestricted_data_saver" msgid="9139401849550738720">"Neograničeni podaci"</string>
     <string name="restrict_background_blacklisted" msgid="7158991683849067124">"Pozadinski su podaci isključeni"</string>
     <string name="data_saver_on" msgid="7281809065420480881">"Uključeno"</string>
     <string name="data_saver_off" msgid="7439439787358504018">"Isključeno"</string>
@@ -4112,7 +4118,7 @@
     <string name="display_cutout_emulation_keywords" msgid="6795671536772871439">"obrezana slika za zaslon, urez"</string>
     <string name="overlay_option_device_default" msgid="165508753381657697">"Zadana postavka uređaja"</string>
     <string name="overlay_toast_failed_to_apply" msgid="5692251825129250040">"Primjena preklapanja nije uspjela"</string>
-    <string name="special_access" msgid="1453926335914696206">"Pristup aplikacija"</string>
+    <string name="special_access" msgid="1453926335914696206">"Poseban pristup za aplikacije"</string>
     <plurals name="special_access_summary" formatted="false" msgid="5182092345063909346">
       <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> aplikacija može upotrebljavati neograničene podatke</item>
       <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> aplikacije mogu upotrebljavati neograničene podatke</item>
@@ -4199,8 +4205,8 @@
     <string name="ambient_display_tap_screen_title" product="tablet" msgid="6434521782016864148">"Dodirnite da biste provjerili tablet"</string>
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"Dodirnite da biste provjerili uređaj"</string>
     <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"Da biste pogledali vrijeme, obavijesti i druge informacije, dodirnite zaslon."</string>
-    <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"Otisak prsta za obavijesti"</string>
-    <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"Pokret za otisak prsta"</string>
+    <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"Prelazak prstom preko senzora za obavijesti"</string>
+    <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"Prelazak prstom preko senzora"</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"Da biste pogledali obavijesti, prijeđite prstom prema dolje po senzoru otiska prsta na stražnjoj strani telefona."</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="tablet" msgid="3480057984564476283">"Da biste pogledali obavijesti, prijeđite prstom prema dolje po senzoru otiska prsta na stražnjoj strani tableta."</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="device" msgid="7950264130913070035">"Da biste pogledali obavijesti, prijeđite prstom prema dolje po senzoru otiska prsta na stražnjoj strani uređaja."</string>
@@ -4312,7 +4318,7 @@
     <string name="storage_other_apps" msgid="3202407095387420842">"Ostale aplikacije"</string>
     <string name="storage_files" msgid="2087824267937487880">"Datoteke"</string>
     <string name="storage_size_large_alternate" msgid="1317796542509105857">"<xliff:g id="NUMBER">^1</xliff:g>"<small>" "<font size="20">"<xliff:g id="UNIT">^2</xliff:g>"</font></small>""</string>
-    <string name="storage_volume_total" msgid="5021484171514159913">"Upotrijebljeno od <xliff:g id="TOTAL">%1$s</xliff:g>"</string>
+    <string name="storage_volume_total" msgid="5021484171514159913">"iskorišteno od <xliff:g id="TOTAL">%1$s</xliff:g>"</string>
     <string name="storage_percent_full" msgid="6924662861545958442">"upot."</string>
     <string name="clear_instant_app_data" msgid="3673669086522890405">"Izbriši podatke aplikacije"</string>
     <string name="clear_instant_app_confirmation" msgid="1778553115373698061">"Želite li ukloniti tu instant aplikaciju?"</string>
@@ -4403,7 +4409,7 @@
     <string name="prevent_ringing_option_vibrate_summary" msgid="7961818570574683926">"Uključeno (vibracija)"</string>
     <string name="prevent_ringing_option_mute_summary" msgid="3509459199090688328">"Uključi (isključi zvuk)"</string>
     <string name="prevent_ringing_option_none_summary" msgid="5152618221093037451">"Isključi"</string>
-    <string name="pref_title_network_details" msgid="3971074015034595956">"Pojedinosti o mreži"</string>
+    <string name="pref_title_network_details" msgid="3971074015034595956">"Podaci o mreži"</string>
     <string name="about_phone_device_name_warning" msgid="9088572775969880106">"Naziv vašeg uređaja vidljiv je aplikacijama na vašem telefonu. Mogu ga vidjeti i drugi ljudi kada se povežete s Bluetooth uređajima ili postavite Wi-Fi žarišnu točku."</string>
     <string name="devices_title" msgid="4768432575951993648">"Uređaji"</string>
     <string name="homepage_all_settings" msgid="3201220879559136116">"Sve postavke"</string>
diff --git a/tests/CarDeveloperOptions/res/values-hu/arrays.xml b/tests/CarDeveloperOptions/res/values-hu/arrays.xml
index c735ccf..c3578f9 100644
--- a/tests/CarDeveloperOptions/res/values-hu/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-hu/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"futtatás a háttérben"</item>
     <item msgid="6423861043647911030">"kisegítő lehetőségek – hangerő"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Tartózkodási hely"</item>
+    <item msgid="6656077694190491067">"Tartózkodási hely"</item>
+    <item msgid="8790228218278477369">"Tartózkodási hely"</item>
+    <item msgid="7836406246005211990">"Rezgés"</item>
+    <item msgid="3951439024549922598">"Névjegyek olvasása"</item>
+    <item msgid="8802152411647068">"Névjegyek módosítása"</item>
+    <item msgid="229544934599698735">"Hívásnapló olvasása"</item>
+    <item msgid="7396102294405899613">"Hívásnapló módosítása"</item>
+    <item msgid="3597797992398484655">"Naptár olvasása"</item>
+    <item msgid="2705975774250907343">"Naptár módosítása"</item>
+    <item msgid="4668747371441932697">"Tartózkodási hely"</item>
+    <item msgid="1487578921720243646">"Értesítés közzététele"</item>
+    <item msgid="4636080349724146638">"Hely"</item>
+    <item msgid="673510900286463926">"Telefonálás"</item>
+    <item msgid="542083422784609790">"SMS/MMS olvasása"</item>
+    <item msgid="1033780373029588436">"SMS/MMS írása"</item>
+    <item msgid="5647111115517787488">"SMS/MMS fogadása"</item>
+    <item msgid="8591105601108455893">"SMS/MMS fogadása"</item>
+    <item msgid="7730995008517841903">"SMS/MMS fogadása"</item>
+    <item msgid="2613033109026626086">"SMS/MMS fogadása"</item>
+    <item msgid="3037159047591081136">"SMS/MMS küldése"</item>
+    <item msgid="4726682243833913568">"SMS/MMS olvasása"</item>
+    <item msgid="6555678522277865572">"SMS/MMS írása"</item>
+    <item msgid="6981734935578130884">"Beállítások módosítása"</item>
+    <item msgid="8705854389991425629">"Megjelenítés felül"</item>
+    <item msgid="5861356020344153651">"Hozzáférési értesítések"</item>
+    <item msgid="78432174621628659">"Kamera"</item>
+    <item msgid="3986116419882154794">"Hanganyag rögzítése"</item>
+    <item msgid="4516840825756409490">"Hanganyag lejátszása"</item>
+    <item msgid="6811712502798183957">"Vágólap olvasása"</item>
+    <item msgid="2780369012602289114">"Vágólap módosítása"</item>
+    <item msgid="2331359440170850868">"Médiagombok"</item>
+    <item msgid="6133599737122751231">"Audiofókusz"</item>
+    <item msgid="6844485713404805301">"Hangerő-szabályozó"</item>
+    <item msgid="1600379420669104929">"Beszéd hangereje"</item>
+    <item msgid="6296768210470214866">"Csengés hangereje"</item>
+    <item msgid="510690696071629241">"Média hangereje"</item>
+    <item msgid="406861638631430109">"Ébresztés hangereje"</item>
+    <item msgid="4715864795872233884">"Értesítés hangereje"</item>
+    <item msgid="2311478519251301183">"Bluetooth hangereje"</item>
+    <item msgid="5133991377896747027">"Ébren tartás"</item>
+    <item msgid="2464189519136248621">"Hely"</item>
+    <item msgid="2062677934050803037">"Tartózkodási hely"</item>
+    <item msgid="1735171933192715957">"Használati statisztikák lekérése"</item>
+    <item msgid="1014093788778383554">"Mikrofon némítása és a némítás feloldása"</item>
+    <item msgid="4199297950608622850">"Üzenet megjelenítése"</item>
+    <item msgid="2527962435313398821">"Médiatartalom kivetítése"</item>
+    <item msgid="5117506254221861929">"VPN aktiválása"</item>
+    <item msgid="8291198322681891160">"Háttérkép írása"</item>
+    <item msgid="7106921284621230961">"Segédlet a szerkezethez"</item>
+    <item msgid="4496533640894624799">"Segédlet a képernyőképhez"</item>
+    <item msgid="2598847264853993611">"Telefonállapot olvasása"</item>
+    <item msgid="9215610846802973353">"Hangposta hozzáadása"</item>
+    <item msgid="9186411956086478261">"SIP használata"</item>
+    <item msgid="6884763100104539558">"Kimenő hívás feldolgozása"</item>
+    <item msgid="125513972170580692">"Ujjlenyomat"</item>
+    <item msgid="2556071024281275619">"Testérzékelők"</item>
+    <item msgid="617168514928339387">"Cellán belüli üzenetszórás olvasása"</item>
+    <item msgid="7134693570516523585">"Helyimitálás"</item>
+    <item msgid="7224489175375229399">"Tárhely olvasása"</item>
+    <item msgid="8472735063903258202">"Tárhely írása"</item>
+    <item msgid="4069276819909595110">"Képernyő bekapcsolása"</item>
+    <item msgid="1228338896751121025">"Fiókok beszerzése"</item>
+    <item msgid="3181581793459233672">"Futtatás a háttérben"</item>
+    <item msgid="2340936043025374076">"Kisegítő lehetőségek – hangerő"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Rövid"</item>
     <item msgid="4816511817309094890">"Közepes"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Soha nem engedélyezem"</item>
     <item msgid="8184570120217958741">"Engedélyezés mindig"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normál"</item>
+    <item msgid="5101233285497327432">"Közepes"</item>
+    <item msgid="1555861583162930714">"Alacsony"</item>
+    <item msgid="1719683776264798117">"Kritikus"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normál"</item>
+    <item msgid="6107138933849816768">"Mérsékelt"</item>
+    <item msgid="182695359839047859">"Alacsony"</item>
+    <item msgid="8577246509202964244">"Kritikus"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Állandó"</item>
     <item msgid="167418068739176448">"Leggyakoribb tevékenység"</item>
diff --git a/tests/CarDeveloperOptions/res/values-hu/config.xml b/tests/CarDeveloperOptions/res/values-hu/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-hu/config.xml
+++ b/tests/CarDeveloperOptions/res/values-hu/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-hu/strings.xml b/tests/CarDeveloperOptions/res/values-hu/strings.xml
index 2e2b8de..eec3eb8 100644
--- a/tests/CarDeveloperOptions/res/values-hu/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-hu/strings.xml
@@ -58,7 +58,7 @@
     <string name="radioInfo_service_out" msgid="8460363463722476510">"Nem működik"</string>
     <string name="radioInfo_service_emergency" msgid="7674989004735662599">"Csak segélyhívások"</string>
     <string name="radioInfo_service_off" msgid="1873939869994136791">"Rádió kikapcsolva"</string>
-    <string name="radioInfo_roaming_in" msgid="7059350234710947417">"Barangolás"</string>
+    <string name="radioInfo_roaming_in" msgid="7059350234710947417">"Roaming"</string>
     <string name="radioInfo_roaming_not" msgid="7733269160603599835">"Nem barangol"</string>
     <string name="radioInfo_phone_idle" msgid="1893851191227617344">"Tétlen"</string>
     <string name="radioInfo_phone_ringing" msgid="5587975376222853265">"Csengés"</string>
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Kicsinyítheti vagy nagyíthatja a képernyőn megjelenő szöveget."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Kisebb"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Nagyobb"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Árvíztűrő tükörfúrógép"</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Mintaszöveg"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Óz, a csodák csodája"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"11. fejezet: A csodálatos Smaragdváros"</string>
@@ -208,7 +207,7 @@
     <string name="proxy_error_empty_port" msgid="8034561724923076215">"Ki kell töltenie a port mezőt."</string>
     <string name="proxy_error_empty_host_set_port" msgid="8471455809508588255">"A port mezőnek is üresnek kell maradnia, ha a gazdagép mező üres."</string>
     <string name="proxy_error_invalid_port" msgid="4046559920586100637">"A megadott port nem érvényes."</string>
-    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"A HTTP proxyt a böngésző használja, ám más alkalmazások nem használhatják."</string>
+    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"A HTTP proxyt a böngésző használja, de más alkalmazások nem használhatják."</string>
     <string name="proxy_url_title" msgid="882042361706435904">"PAC URL: "</string>
     <string name="radio_info_dl_kbps" msgid="2903778264453410272">"Letöltési sávszélesség (kbps):"</string>
     <string name="radio_info_ul_kbps" msgid="3802245899811732716">"Feltöltési sávszélesség (kbps):"</string>
@@ -217,7 +216,7 @@
     <string name="radio_info_cell_info_refresh_rate" msgid="3557422342215875913">"Cellainformáció frissítési gyakorisága:"</string>
     <string name="radio_info_cellinfo_label" msgid="632796561627452215">"Minden cellamérési információ:"</string>
     <string name="radio_info_gprs_service_label" msgid="7926626443442993242">"Adatszolgáltatás:"</string>
-    <string name="radio_info_roaming_label" msgid="3131949337031835485">"Barangolás:"</string>
+    <string name="radio_info_roaming_label" msgid="3131949337031835485">"Roaming:"</string>
     <string name="radio_info_imei_label" msgid="7300156592358133405">"IMEI:"</string>
     <string name="radio_info_call_redirect_label" msgid="2679891718182753061">"Hívásátirányítás:"</string>
     <string name="radio_info_ppp_resets_label" msgid="2785162965440312941">"PPP-visszaállítások száma a legutolsó rendszerindítás óta:"</string>
@@ -310,14 +309,14 @@
     <string name="cellular_data_summary" msgid="8817717603450318646">"Mobiladat-forgalom engedélyezése"</string>
     <string name="allow_data_usage_title" msgid="5381624105803294315">"Adatforgalom barangoláskor"</string>
     <string name="roaming" msgid="8860308342135146004">"Roaming"</string>
-    <string name="roaming_enable" msgid="2108142024297441116">"Csatlakozás adatszolgáltatásokhoz barangolás során"</string>
-    <string name="roaming_disable" msgid="1915440242079953809">"Csatlakozás adatszolgáltatásokhoz barangolás során"</string>
+    <string name="roaming_enable" msgid="2108142024297441116">"Csatlakozás adatszolgáltatásokhoz roaming során"</string>
+    <string name="roaming_disable" msgid="1915440242079953809">"Csatlakozás adatszolgáltatásokhoz roaming során"</string>
     <string name="roaming_reenable_message" msgid="8388505868655113258">"Megszakadt az adatkapcsolat, mert elhagyta az otthoni hálózatot, és az adatbarangolás nincs bekapcsolva."</string>
     <string name="roaming_turn_it_on_button" msgid="4370846458830537578">"Bekapcsolás"</string>
     <string name="roaming_warning" msgid="5488050911277592868">"Lehet, hogy jelentős összeget számítanak fel érte."</string>
     <string name="roaming_warning_multiuser" product="tablet" msgid="7090388691615686893">"Az adatbarangolás engedélyezése jelentős díjnövekedéssel járhat.\n\nEz a beállítás minden felhasználót érint ezen a táblagépen."</string>
     <string name="roaming_warning_multiuser" product="default" msgid="6999819541078827556">"Az adatbarangolás engedélyezése jelentős díjnövekedéssel járhat.\n\nEz a beállítás minden felhasználót érint ezen a telefonon."</string>
-    <string name="roaming_reenable_title" msgid="6985082191178297921">"Engedélyezi az adatbarangolást?"</string>
+    <string name="roaming_reenable_title" msgid="6985082191178297921">"Engedélyezi az adatroamingot?"</string>
     <string name="networks" msgid="3073876464102136771">"Szolgáltatóválasztás"</string>
     <string name="sum_carrier_select" msgid="8964744180598499121">"Válassza ki a hálózat üzemeltetőjét"</string>
     <string name="date_and_time_settings_title" msgid="7827088656940910631">"Dátum és idő"</string>
@@ -411,10 +410,10 @@
     <string name="face_add_max" msgid="8870899421165189413">"Legfeljebb <xliff:g id="COUNT">%d</xliff:g> arcot adhat hozzá"</string>
     <string name="face_intro_error_max" msgid="4024147799079828937">"Elérte a hozzáadható arcok maximális számát"</string>
     <string name="face_intro_error_unknown" msgid="3241592604198351134">"Nem lehet további arcokat hozzáadni"</string>
-    <string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"A regisztráció nincs kész"</string>
+    <string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"A rögzítés nincs kész"</string>
     <string name="security_settings_face_enroll_dialog_ok" msgid="1078348922734845090">"OK"</string>
     <string name="security_settings_face_enroll_error_timeout_dialog_message" msgid="4917894418448325405">"Letelt az arcregisztráció időkorlátja. Próbálja újra."</string>
-    <string name="security_settings_face_enroll_error_generic_dialog_message" msgid="5160473187142616862">"Az arc regisztrálása sikertelen volt."</string>
+    <string name="security_settings_face_enroll_error_generic_dialog_message" msgid="5160473187142616862">"Az arc rögzítése sikertelen volt."</string>
     <string name="security_settings_face_enroll_finish_title" msgid="6800717857394410769">"Minden beállítva. Jónak tűnik."</string>
     <string name="security_settings_face_enroll_done" msgid="5409739233373490971">"Kész"</string>
     <string name="security_settings_face_settings_use_face_category" msgid="1586532139528115416">"Arc használata erre:"</string>
@@ -488,8 +487,8 @@
     <string name="security_settings_fingerprint_enroll_done" msgid="4111289529758845926">"Kész"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"Hoppá! Az nem az érzékelő"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"Érintse meg a hátsó érzékelőt mutatóujjával."</string>
-    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"A regisztráció nincs kész"</string>
-    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Letelt az ujjlenyomat-regisztráció időkorlátja. Próbálja újra."</string>
+    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"A rögzítés nincs kész"</string>
+    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Letelt az ujjlenyomat-rögzítés időkorlátja. Próbálja újra."</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"Az ujjlenyomat regisztrációja nem sikerült. Próbálja újra, vagy próbálkozzon egy másik ujjával."</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"Még egy hozzáadása"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"Következő"</string>
@@ -668,7 +667,6 @@
       <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> számjegynél rövidebbnek kell lennie</item>
       <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> számjegynél rövidebbnek kell lennie</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Csak számokat tartalmazhat, 0-tól 9-ig"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Az eszközrendszergazda nem engedélyezi a legutóbbi PIN-kódok használatát"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Rendszergazdája letiltotta a gyakran használt PIN-kódokat. Próbálkozzon másik PIN-kóddal."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Ez nem tartalmazhat érvénytelen karaktert"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Tartalmaznia kell legalább <xliff:g id="COUNT">%d</xliff:g> olyan karaktert, amely nem betű</item>
       <item quantity="one">Tartalmaznia kell legalább 1 olyan karaktert, amely nem betű</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Tartalmaznia kell legalább <xliff:g id="COUNT">%d</xliff:g> olyan karaktert, amely nem szám</item>
+      <item quantity="one">Tartalmaznia kell legalább 1 olyan karaktert, amely nem szám</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Az eszközrendszergazda nem engedélyezi a legutóbbi jelszavak használatát"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Rendszergazdája letiltotta a gyakran használt jelszavakat. Próbálkozzon másik jelszóval."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Növekvő, csökkenő vagy ismétlődő számsor megadása nem engedélyezett"</string>
@@ -933,9 +935,9 @@
     <string name="wifi_privacy_settings" msgid="4462092795794247809">"Adatvédelem"</string>
     <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"Véletlenszerű MAC-cím"</string>
     <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"Eszköz hozzáadása"</string>
-    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"Irányítsa a QR-kódot az alábbi panel közepéhez az eszköznek a következőhöz való hozzáadásához: <xliff:g id="SSID">%1$s</xliff:g>"</string>
+    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"Irányítsa a QR-kódot az alábbi panel közepére, hogy hozzáadja az eszközt a(z) <xliff:g id="SSID">%1$s</xliff:g> hálózathoz"</string>
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"QR-kód beolvasása"</string>
-    <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"Irányítsa a QR-kódot az alábbi panel közepéhez a következőhöz való csatlakozáshoz: <xliff:g id="SSID">%1$s</xliff:g>"</string>
+    <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"Irányítsa a QR-kódot az alábbi panel közepére, hogy hozzáadja az eszközt a(z) <xliff:g id="SSID">%1$s</xliff:g> hálózathoz"</string>
     <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"Csatlakozzon Wi-Fi-hálózathoz QR-kód beolvasásával"</string>
     <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Wi‑Fi megosztása"</string>
     <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"A(z) „<xliff:g id="SSID">%1$s</xliff:g>” hálózathoz való csatlakozás érdekében olvassa be ezt a QR-kódot, és ossza meg a jelszót"</string>
@@ -1082,10 +1084,10 @@
     <string name="wifi_calling_suggestion_summary" msgid="198402175473169630">"Kapcsolja be a Wi-Fi-hívást a lefedettség növeléséhez"</string>
     <string name="wifi_calling_mode_title" msgid="3350624859819920176">"Híváspreferencia"</string>
     <string name="wifi_calling_mode_dialog_title" msgid="652534533091724333">"Híváspreferencia"</string>
-    <string name="wifi_calling_roaming_mode_title" msgid="2059151080231602753">"Barangolási beállítás"</string>
+    <string name="wifi_calling_roaming_mode_title" msgid="2059151080231602753">"Roaming beállítása"</string>
     <!-- no translation found for wifi_calling_roaming_mode_summary (620031651074963360) -->
     <skip />
-    <string name="wifi_calling_roaming_mode_dialog_title" msgid="4018579440109122790">"Barangolási beállítás"</string>
+    <string name="wifi_calling_roaming_mode_dialog_title" msgid="4018579440109122790">"Roaming beállítása"</string>
   <string-array name="wifi_calling_mode_choices">
     <item msgid="7952573372663890448">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="2552412793005571845">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mobil"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Mobilhálózat használata, ha nem áll rendelkezésre Wi-Fi-hálózat"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Wi‑Fi használata, ha nem áll rendelkezésre mobilhálózat"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Hívás Wi-Fi-n. Ha a Wi-Fi kapcsolat megszűnik, a hívás véget ér."</string>
@@ -1210,7 +1215,7 @@
     <string name="night_display_auto_mode_title" msgid="8493573087102481588">"Ütemezés"</string>
     <string name="night_display_auto_mode_never" msgid="2897444637217807088">"Nincs"</string>
     <string name="night_display_auto_mode_custom" msgid="1400891076453963151">"Adott időpontban kapcsol be"</string>
-    <string name="night_display_auto_mode_twilight" msgid="4000162110017520674">"Napnyugtától napkeltéig kapcsol be"</string>
+    <string name="night_display_auto_mode_twilight" msgid="4000162110017520674">"Napnyugtától napkeltéig"</string>
     <string name="night_display_start_time_title" msgid="1069255169673371077">"Kezdés ideje"</string>
     <string name="night_display_end_time_title" msgid="2760793157124245911">"Befejezés ideje"</string>
     <string name="night_display_status_title" msgid="1727020934735770319">"Állapot"</string>
@@ -1305,7 +1310,7 @@
     <string name="system_update_settings_list_item_title" msgid="1907497454722790033">"Rendszerfrissítések"</string>
     <string name="system_update_settings_list_item_summary" msgid="3497456690691907873"></string>
     <string name="firmware_version" msgid="547095584029938749">"Android verziója"</string>
-    <string name="security_patch" msgid="483709031051932208">"Androidos biztonsági hibajavító csomag szintje"</string>
+    <string name="security_patch" msgid="483709031051932208">"Androidos biztonsági hibajavító csomag"</string>
     <string name="model_info" msgid="1729765474260797594">"Modell"</string>
     <string name="model_summary" msgid="8781425868254352168">"Modell: %1$s"</string>
     <string name="hardware_info" msgid="174270144950621815">"Modell és hardver"</string>
@@ -1350,7 +1355,7 @@
     <string name="status_esim_id" msgid="9201767073386770286">"EID"</string>
     <string name="status_service_state" msgid="4406215321296496234">"Szolgáltatás állapota"</string>
     <string name="status_signal_strength" msgid="4302597886933728789">"Jelerősség"</string>
-    <string name="status_roaming" msgid="5191044997355099561">"Barangolás"</string>
+    <string name="status_roaming" msgid="5191044997355099561">"Roaming"</string>
     <string name="status_operator" msgid="6017986100643755390">"Hálózat"</string>
     <string name="status_wifi_mac_address" msgid="3868452167971295995">"Wi-Fi MAC-címe"</string>
     <string name="status_bt_address" msgid="460568179311735657">"Bluetooth-cím"</string>
@@ -1543,7 +1548,7 @@
     <string name="apn_auth_type_pap_chap" msgid="2977833804460109203">"PAP vagy CHAP"</string>
     <string name="apn_type" msgid="6725346490902871146">"APN típusa"</string>
     <string name="apn_protocol" msgid="1240197323563960912">"Hozzáférési pont protokollja"</string>
-    <string name="apn_roaming_protocol" msgid="6913336248771263497">"Hozzáférési pont barangolási protokollja"</string>
+    <string name="apn_roaming_protocol" msgid="6913336248771263497">"Hozzáférési pont roamingprotokollja"</string>
     <string name="carrier_enabled" msgid="1819916725305365581">"APN be-/kikapcsolása"</string>
     <string name="carrier_enabled_summaryOn" msgid="6219221535461945771">"APN engedélyezve"</string>
     <string name="carrier_enabled_summaryOff" msgid="4093019532796386622">"APN kikapcsolva"</string>
@@ -1684,7 +1689,7 @@
     <string name="contributors_title" msgid="6800028420806884340">"Közreműködők"</string>
     <string name="manual" msgid="5431859421432581357">"Útmutató"</string>
     <string name="regulatory_labels" msgid="380968489247381025">"Szabályozási címkék"</string>
-    <string name="safety_and_regulatory_info" msgid="7113766428000920132">"Biztonsági és az előírásokkal kapcsolatos útmutató"</string>
+    <string name="safety_and_regulatory_info" msgid="7113766428000920132">"Biztonsági és szabályozási útmutató"</string>
     <string name="copyright_title" msgid="3847703367689932190">"Szerzői jog"</string>
     <string name="license_title" msgid="7582145947873528540">"Licenc"</string>
     <string name="terms_title" msgid="1804549588198223771">"Általános Szerződési Feltételek"</string>
@@ -2032,7 +2037,7 @@
     <string name="accessibility_settings" msgid="9140621093888234485">"Kisegítő lehetőségek"</string>
     <string name="accessibility_settings_title" msgid="1687226556576913576">"Kisegítő lehetőségek beállításai"</string>
     <string name="accessibility_settings_summary" msgid="5742379519336396561">"Képernyőolvasók, megjelenítés, interakcióvezérlők"</string>
-    <string name="vision_settings_title" msgid="7315352351051423944">"Látási beállítások"</string>
+    <string name="vision_settings_title" msgid="7315352351051423944">"Vizuális beállítások"</string>
     <string name="vision_settings_description" msgid="3476589459009287332">"Eszközét saját igényeinek megfelelően testre szabhatja. Ezeket a kisegítő lehetőségeket később a Beállítások menüben módosíthatja."</string>
     <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"Betűméret módosítása"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"Képernyőolvasók"</string>
@@ -2067,7 +2072,7 @@
     <string name="accessibility_toggle_large_pointer_icon_title" msgid="9127905775116570565">"Nagy egérmutató"</string>
     <string name="accessibility_disable_animations" msgid="8378441317115710009">"Animációk eltávolítása"</string>
     <string name="accessibility_toggle_master_mono_title" msgid="899550848196702565">"Monó hang"</string>
-    <string name="accessibility_toggle_master_mono_summary" msgid="3847052868469033235">"Csatornák kombinálása hang lejátszásakor"</string>
+    <string name="accessibility_toggle_master_mono_summary" msgid="3847052868469033235">"Csatornák egyesítése hang lejátszásakor"</string>
     <string name="accessibility_toggle_master_balance_title" msgid="8723492001092647562">"Hangegyensúly"</string>
     <string name="accessibility_toggle_master_balance_left_label" msgid="8531986342666527970">"Bal"</string>
     <string name="accessibility_toggle_master_balance_right_label" msgid="7757024572140589558">"Jobb"</string>
@@ -2571,7 +2576,7 @@
     <string name="sms_access_restriction_enabled" msgid="3006320256764718303">"Korlátozott SMS- és hívásnapló-hozzáférés"</string>
     <string name="sms_access_restriction_enabled_summary" msgid="9011946580977780063">"Csak az alapértelmezett telefon- és üzenetküldő alkalmazások rendelkeznek SMS-ekhez és hívásnaplóhoz való hozzáféréssel"</string>
     <string name="no_trust_agents" msgid="5757792915019113084">"Nincs elérhető trust agent komponens"</string>
-    <string name="add_device_admin_msg" msgid="3573765823476931173">"Aktiválja az eszközrendszergazdai alkalmazást?"</string>
+    <string name="add_device_admin_msg" msgid="3573765823476931173">"Aktiválja a rendszergazdai alkalmazást?"</string>
     <string name="add_device_admin" msgid="1621152410207260584">"Az eszközrendszergazdai alkalmazás aktiválása"</string>
     <string name="device_admin_add_title" msgid="6097881332139146897">"Eszközrendszergazda"</string>
     <string name="device_admin_warning" msgid="4421817419326480449">"A rendszergazdai alkalmazás aktiválása engedélyezi a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás számára a következő műveletek elvégzését:"</string>
@@ -2688,7 +2693,7 @@
     <string name="data_usage_enable_mobile" msgid="7238385042860001374">"Mobiladatok"</string>
     <string name="data_usage_enable_3g" msgid="3725838726334043367">"2G-3G adatforgalom"</string>
     <string name="data_usage_enable_4g" msgid="8872517106293561179">"4G adatforgalom"</string>
-    <string name="data_roaming_enable_mobile" msgid="5886394350890765947">"Barangolás"</string>
+    <string name="data_roaming_enable_mobile" msgid="5886394350890765947">"Roaming"</string>
     <string name="data_usage_forground_label" msgid="8992577451178005406">"Előtér:"</string>
     <string name="data_usage_background_label" msgid="8460891123904985128">"Háttér:"</string>
     <string name="data_usage_app_settings" msgid="3276444867375694809">"Alkalmazásbeállítások"</string>
@@ -2920,7 +2925,7 @@
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Kivéve, ha meg van nyitva egy másik alkalmazás a fizetéshez"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"Érintéses fizetésre alkalmas terminál esetén fizetés a következővel:"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Fizetés a terminálnál"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Állítson be egy alkalmazást a fizetéshez. Ezután elég csak telefonja hátulját odatartani az érintés nélküli fizetést jelző szimbólummal ellátott terminálhoz."</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Állítson be egy alkalmazást a fizetéshez. Ezután elég csak telefonja hátulját odatartani az érintéses fizetést jelző szimbólummal ellátott terminálhoz."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"Értem"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"Egyebek…"</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"Beállítja előnyben részesítettként?"</string>
@@ -3095,7 +3100,7 @@
     <string name="keywords_assist_gesture_launch" msgid="2711433664837843513">"kézmozdulat"</string>
     <string name="keywords_face_unlock" msgid="651615819291927262">"arc, feloldás, hitelesítés, bejelentkezés"</string>
     <string name="keywords_imei_info" msgid="4325847870422053408">"imei, meid, min, prl-verzió, imei sv"</string>
-    <string name="keywords_sim_status" msgid="3852088576719874387">"hálózat, mobilhálózat állapota, szolgáltatás állapota, jelerősség, mobilhálózat típusa, barangolás, iccid"</string>
+    <string name="keywords_sim_status" msgid="3852088576719874387">"hálózat, mobilhálózat állapota, szolgáltatás állapota, jelerősség, mobilhálózat típusa, roaming, iccid"</string>
     <string name="keywords_model_and_hardware" msgid="2743197096210895251">"sorozatszám, hardververzió"</string>
     <string name="keywords_android_version" msgid="4842749998088987740">"androidos biztonsági javítókészlet szintje, alapsáv verziója, kernel verziója"</string>
     <string name="keywords_dark_ui_mode" msgid="1027966176887770318">"téma, világos, sötét, mód"</string>
@@ -3706,7 +3711,7 @@
     <string name="high_power_off" msgid="5906679734326490426">"Akkumulátorhasználat optimalizálása"</string>
     <string name="high_power_system" msgid="739584574711292753">"Nincs lehetőség akkumulátoroptimalizálásra"</string>
     <string name="high_power_desc" msgid="333756885680362741">"Ne vonatkozzon rá az akkumulátoroptimalizálás. Így az akkumulátor gyorsabban lemerülhet."</string>
-    <string name="high_power_prompt_title" msgid="2805745781720454052">"Engedélyezi az alkalmazás számára, hogy mindig fusson a háttérben?"</string>
+    <string name="high_power_prompt_title" msgid="2805745781720454052">"Engedélyezi, hogy az alkalmazás mindig fusson a háttérben?"</string>
     <string name="high_power_prompt_body" msgid="8067395096053552289">"Ha engedélyezi, hogy a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> mindig fusson a háttérben, csökkenhet az akkumulátor üzemideje.\n\nEzt később bármikor módosíthatja a Beállítások &gt; Alkalmazások és értesítések menüpontban."</string>
     <string name="battery_summary" msgid="4345690800899981339">"Akkumulátorhasználat az utolsó teljes feltöltés óta: <xliff:g id="PERCENTAGE">%1$s</xliff:g>"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"Energiagazdálkodás"</string>
@@ -4434,7 +4439,7 @@
     <string name="cdma_subscription_summary" msgid="2298861419202726628">"Váltás RUIM/SIM és NV között"</string>
     <string name="cdma_subscription_dialogtitle" msgid="232485231569225126">"előfizetés"</string>
     <string name="register_automatically" msgid="1858081641661493109">"Automatikus regisztráció…"</string>
-    <string name="roaming_alert_title" msgid="1849237823113454475">"Engedélyezi az adatbarangolást?"</string>
+    <string name="roaming_alert_title" msgid="1849237823113454475">"Engedélyezi az adatroamingot?"</string>
     <string name="roaming_check_price_warning" msgid="5883499714594419439">"Az árakat a szolgáltatótól tudhatja meg."</string>
     <string name="mobile_data_usage_title" msgid="2376358672434990037">"Alkalmazás adathasználata"</string>
     <string name="mobile_network_mode_error" msgid="6818434186286086554">"Érvénytelen hálózati mód: <xliff:g id="NETWORKMODEID">%1$d</xliff:g>. Figyelmen kívül hagyás."</string>
diff --git a/tests/CarDeveloperOptions/res/values-hy/arrays.xml b/tests/CarDeveloperOptions/res/values-hy/arrays.xml
index 74d88a3..c4c9599 100644
--- a/tests/CarDeveloperOptions/res/values-hy/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-hy/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"աշխատել ֆոնային ռեժիմում"</item>
     <item msgid="6423861043647911030">"մատչելիության ծավալ"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Տեղադրություն"</item>
+    <item msgid="6656077694190491067">"Տեղադրություն"</item>
+    <item msgid="8790228218278477369">"Տեղադրություն"</item>
+    <item msgid="7836406246005211990">"Թրթռոց"</item>
+    <item msgid="3951439024549922598">"Տեսնել կոնտակտները"</item>
+    <item msgid="8802152411647068">"Փոփոխել կոնտակտները"</item>
+    <item msgid="229544934599698735">"Տեսնել զանգերի մատյանը"</item>
+    <item msgid="7396102294405899613">"Փոփոխել զանգերի մատյանը"</item>
+    <item msgid="3597797992398484655">"Տեսնել օրացույցը"</item>
+    <item msgid="2705975774250907343">"Փոփոխել օրացույցը"</item>
+    <item msgid="4668747371441932697">"Տեղադրություն"</item>
+    <item msgid="1487578921720243646">"Փակցնել ծանուցում"</item>
+    <item msgid="4636080349724146638">"Տեղադրություն"</item>
+    <item msgid="673510900286463926">"Հեռախոս"</item>
+    <item msgid="542083422784609790">"Կարդալ SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Գրել SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Ստանալ SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Ստանալ SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Ստանալ SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Ստանալ SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Ուղարկել SMS/MMS"</item>
+    <item msgid="4726682243833913568">"Կարդալ SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Գրել SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Փոփոխել կարգավորումները"</item>
+    <item msgid="8705854389991425629">"Պատկերել վերևի մասում"</item>
+    <item msgid="5861356020344153651">"Մուտք գործել ծանուցումներ"</item>
+    <item msgid="78432174621628659">"Տեսախցիկ"</item>
+    <item msgid="3986116419882154794">"Ձայնագրել աուդիո ֆայլ"</item>
+    <item msgid="4516840825756409490">"Նվագարկել ձայնանյութը"</item>
+    <item msgid="6811712502798183957">"Կարդալ սեղմատախտակը"</item>
+    <item msgid="2780369012602289114">"Փոփոխել սեղմատախտակը"</item>
+    <item msgid="2331359440170850868">"Մեդիա կոճակներ"</item>
+    <item msgid="6133599737122751231">"Աուդիո ֆոկուս"</item>
+    <item msgid="6844485713404805301">"Ձայնի հիմնական բարձրություն"</item>
+    <item msgid="1600379420669104929">"Ձայնի բարձրություն"</item>
+    <item msgid="6296768210470214866">"Զանգերանգ"</item>
+    <item msgid="510690696071629241">"Մուլտիմեդիա"</item>
+    <item msgid="406861638631430109">"Զարթուցիչ"</item>
+    <item msgid="4715864795872233884">"Ծանուցման ձայնի բարձրություն"</item>
+    <item msgid="2311478519251301183">"Bluetooth-ի ձայնի բարձրություն"</item>
+    <item msgid="5133991377896747027">"Արթուն պահել"</item>
+    <item msgid="2464189519136248621">"Տեղորոշում"</item>
+    <item msgid="2062677934050803037">"Տեղադրություն"</item>
+    <item msgid="1735171933192715957">"Ստանալ օգտագործման վիճակագրությունը"</item>
+    <item msgid="1014093788778383554">"Խոսափողն անջատել/միացնել"</item>
+    <item msgid="4199297950608622850">"Ցույց տալ ծանուցումը"</item>
+    <item msgid="2527962435313398821">"Տեսարձակել մեդիան"</item>
+    <item msgid="5117506254221861929">"Ակտիվացնել VPN-ը"</item>
+    <item msgid="8291198322681891160">"Պաստառների պահում"</item>
+    <item msgid="7106921284621230961">"Օժանդակ կառույց"</item>
+    <item msgid="4496533640894624799">"Օժանդակ սքրինշոթ"</item>
+    <item msgid="2598847264853993611">"Կարդալ հեռախոսի վիճակի տվյալները"</item>
+    <item msgid="9215610846802973353">"Ավելացնել ձայնային փոստ"</item>
+    <item msgid="9186411956086478261">"Օգտագործել sip-ը"</item>
+    <item msgid="6884763100104539558">"Մշակել ելքային զանգը"</item>
+    <item msgid="125513972170580692">"Մատնահետք"</item>
+    <item msgid="2556071024281275619">"Մարմնի տվիչներ"</item>
+    <item msgid="617168514928339387">"Կարդալ բջջային հեռարձակումները"</item>
+    <item msgid="7134693570516523585">"Կեղծել տեղադրությունը"</item>
+    <item msgid="7224489175375229399">"Կարդալ կրիչի բովանդակությունը"</item>
+    <item msgid="8472735063903258202">"Փոփոխել կրիչի բովանդակությունը"</item>
+    <item msgid="4069276819909595110">"Միացնել էկրանը"</item>
+    <item msgid="1228338896751121025">"Ստանալ հաշիվները"</item>
+    <item msgid="3181581793459233672">"Աշխատել ֆոնային ռեժիմում"</item>
+    <item msgid="2340936043025374076">"Մատչելիության ծավալ"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Կարճ"</item>
     <item msgid="4816511817309094890">"Միջին"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Երբեք չթույլատրել"</item>
     <item msgid="8184570120217958741">"Միշտ թույլատրել"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Սովորական"</item>
+    <item msgid="5101233285497327432">"Չափավոր"</item>
+    <item msgid="1555861583162930714">"Ցածր"</item>
+    <item msgid="1719683776264798117">"Կրիտիկական"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Սովորական"</item>
+    <item msgid="6107138933849816768">"Չափավոր"</item>
+    <item msgid="182695359839047859">"Ցածր"</item>
+    <item msgid="8577246509202964244">"Կրիտիկական"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Կայուն"</item>
     <item msgid="167418068739176448">"Առավել հաճախակի կատարվող գործողությունը"</item>
@@ -396,7 +472,7 @@
     <item msgid="3118234477029486741">"0"</item>
   </string-array>
   <string-array name="wifi_metered_entries">
-    <item msgid="4329206416008519163">"Ավտոմատ հայտնաբերում"</item>
+    <item msgid="4329206416008519163">"Ավտոմատ որոշում"</item>
     <item msgid="773943026484148895">"Սահմանափակ"</item>
     <item msgid="1008268820118852416">"Անսահմանափակ"</item>
   </string-array>
diff --git a/tests/CarDeveloperOptions/res/values-hy/config.xml b/tests/CarDeveloperOptions/res/values-hy/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-hy/config.xml
+++ b/tests/CarDeveloperOptions/res/values-hy/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-hy/strings.xml b/tests/CarDeveloperOptions/res/values-hy/strings.xml
index cb33ff1..5d6c540 100644
--- a/tests/CarDeveloperOptions/res/values-hy/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-hy/strings.xml
@@ -27,7 +27,7 @@
       <item quantity="other">Ծրագրավորող դառնալու համար ձեզ մնացել է կատարել <xliff:g id="STEP_COUNT_1">%1$d</xliff:g> քայլ:</item>
     </plurals>
     <string name="show_dev_on" msgid="9075712234786224065">"Դուք արդեն ծրագրավորո՛ղ եք:"</string>
-    <string name="show_dev_already" msgid="7665948832405148689">"Կարիք չկա, դուք արդեն իսկ ծրագրավորող եք:"</string>
+    <string name="show_dev_already" msgid="7665948832405148689">"Կարիք չկա, ծրագրավորողի ընտրանքներն արդեն միացված են։"</string>
     <string name="dev_settings_disabled_warning" msgid="3198732189395396721">"Խնդրում ենք նախ միացնել մշակողի ընտրանքները:"</string>
     <string name="header_category_wireless_networks" msgid="8968405993937795898">"Անլար կապ և ցանցեր"</string>
     <string name="header_category_system" msgid="4045988717359334410">"Համակարգ"</string>
@@ -65,7 +65,7 @@
     <string name="radioInfo_phone_offhook" msgid="3186071430568806208">"Զանգն ընթանում է"</string>
     <string name="radioInfo_data_disconnected" msgid="5311119240521915279">"Անջատված է"</string>
     <string name="radioInfo_data_connecting" msgid="47095003276717745">"Միանում է"</string>
-    <string name="radioInfo_data_connected" msgid="3755289851642913750">"Կապակցված է"</string>
+    <string name="radioInfo_data_connected" msgid="3755289851642913750">"Միացված է"</string>
     <string name="radioInfo_data_suspended" msgid="5013451375409737795">"Անջատված"</string>
     <string name="radioInfo_unknown" msgid="3148839102896278859">"Անհայտ"</string>
     <string name="radioInfo_display_packets" msgid="5472652398031589527">"pkts"</string>
@@ -83,12 +83,11 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Փոփոխեք տեքստի չափը։"</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Փոքրացնել"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Մեծացնել"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Տեքստի նմուշ"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Օզի կախարդը"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Գլուխ 11. Օզի հրաշալի Զմրուխտե քաղաքը"</string>
-    <string name="font_size_preview_text_body" msgid="6803085337474390845">"Նույնիսկ հագնելով կանաչ ապակիներով ակնոցներ՝ Դորոթին և նրա ընկերները շլացան այս զարմանահրաշ քաղաքի փայլից: Փողոցների երկայնքով շարված էին կանաչ մարմարից գեղեցիկ տներ՝ զարդարված փայլուն զմրուխտներով: Ճամփորդները քայլում էին այդ նույն կանաչ մարմարով պատած մայթերով, որոնց սալիկների արանքները լցված էին արևի շողերի տակ փայլող զմրուխտներով: Տների պատուհանները կանաչ ապակուց էին: Զմրուխտե քաղաքում նույնիսկ երկինքն ուներ կանաչ երանգ, իսկ կանաչ արևը պայծառ կանաչ շողեր էր արձակում: \n\nՇուրջը տղամարդիկ, կանայք և երեխաներ էին քայլում, որոնք բոլորը կրում էին կանաչ հագուստ և ունեին կանաչավուն մաշկ: Նրանք զարմանքով էին նայում Դորոթիին և նրա տարօրինակ ուղեկիցներին: Նկատելով Առյուծին՝ երեխաները թաքնվում էին իրենց ծնողների մեջքի ետևում և ոչ-ոք չեր համարձակվում խոսել անծանոթների հետ: Խանութներում վաճառվում էին կանաչ գույնի ապրանքներ. կանաչ կոնֆետներ և կանաչ ադիբուդի, տարբեր տեսակի կանաչ կոշիկներ, գլխարկներ և զգեստներ: Վաճառականներից մեկն առաջարկում էր կանաչ լիմոնադ, իսկ նրան շրջապատող երեխաները լիմոնադի համար վճարում էին կանաչ մետաղադրամներով: \n\nԶմրուխտե քաղաքի փողոցներում ոչ ձիեր, ոչ էլ այլ կենդանիներ չկային: Տղամարդիկ իրենց իրերը կրում էին փոքր կանաչ ձեռնասայլակներով: Քաղաքի բոլոր բնակիչները ուրախ և անհոգ տեսք ունեին:"</string>
+    <string name="font_size_preview_text_body" msgid="6803085337474390845">"Նույնիսկ հագնելով կանաչ ապակիներով ակնոցներ՝ Դորոթին և իր ընկերները շլացան այս զարմանահրաշ քաղաքի փայլից: Փողոցների երկայնքով շարված էին կանաչ մարմարից գեղեցիկ տներ՝ զարդարված փայլուն զմրուխտներով: Ճամփորդները քայլում էին այդ նույն կանաչ մարմարով պատած մայթերով, որոնց սալիկների արանքները լցված էին արևի շողերի տակ փայլող զմրուխտներով: Տների պատուհանները կանաչ ապակուց էին: Զմրուխտե քաղաքում նույնիսկ երկինքն ուներ կանաչ երանգ, իսկ կանաչ արևը պայծառ կանաչ շողեր էր արձակում: \n\nՇուրջը տղամարդիկ, կանայք և երեխաներ էին քայլում, որոնք բոլորը կրում էին կանաչ հագուստ և ունեին կանաչավուն մաշկ: Նրանք զարմանքով էին նայում Դորոթիին և նրա տարօրինակ ուղեկիցներին: Նկատելով Առյուծին՝ երեխաները թաքնվում էին իրենց ծնողների մեջքի ետևում և ոչ-ոք չեր համարձակվում խոսել անծանոթների հետ: Խանութներում վաճառվում էին կանաչ գույնի ապրանքներ. կանաչ կոնֆետներ և կանաչ ադիբուդի, տարբեր տեսակի կանաչ կոշիկներ, գլխարկներ և զգեստներ: Վաճառականներից մեկն առաջարկում էր կանաչ լիմոնադ, իսկ նրան շրջապատող երեխաները լիմոնադի համար վճարում էին կանաչ մետաղադրամներով: \n\nԶմրուխտե քաղաքի փողոցներում ոչ ձիեր, ոչ էլ այլ կենդանիներ չկային: Տղամարդիկ իրենց իրերը կրում էին փոքր կանաչ ձեռնասայլակներով: Քաղաքի բոլոր բնակիչները ուրախ և անհոգ տեսք ունեին:"</string>
     <string name="font_size_save" msgid="8652044574655753921">"Հաստատել"</string>
     <string name="sdcard_setting" product="nosdcard" msgid="1533784309105748696">"USB կրիչ"</string>
     <string name="sdcard_setting" product="default" msgid="8398782065765523178">"SD քարտ"</string>
@@ -100,7 +99,7 @@
     <string name="bluetooth_visibility_timeout" msgid="4804679276398564496">"Տեսանելիության ժամանակի սպառում"</string>
     <string name="bluetooth_lock_voice_dialing" msgid="1600385868298081015">"Կողպել ձայնային համարհավաքումը"</string>
     <string name="bluetooth_lock_voice_dialing_summary" msgid="5005776616112427980">"Կանխել Bluetooth համարհավաքչի օգտագործումը, երբ էկրանը կողպված է"</string>
-    <string name="bluetooth_devices" msgid="4143880830505625666">"Bluetooth-ով սարքեր"</string>
+    <string name="bluetooth_devices" msgid="4143880830505625666">"Bluetooth սարքեր"</string>
     <string name="bluetooth_device_name" msgid="3682016026866302981">"Սարքի անունը"</string>
     <string name="bluetooth_device_details" msgid="2500840679106321361">"Սարքի կարգավորումներ"</string>
     <string name="bluetooth_profile_details" msgid="1785505059738682493">"Պրոֆիլի կարգավորումներ"</string>
@@ -208,7 +207,7 @@
     <string name="proxy_error_empty_port" msgid="8034561724923076215">"Պետք է լրացնել միացքի դաշտը:"</string>
     <string name="proxy_error_empty_host_set_port" msgid="8471455809508588255">"Միացքի դաշտը պետք է ազատ լինի, եթե հանգույցի դաշտը դատարկ է:"</string>
     <string name="proxy_error_invalid_port" msgid="4046559920586100637">"Ձեր մուտքագրած միացքը վավեր չէ:"</string>
-    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"HTTP պրոքսին օգտագործվում է դիտարկիչի կողմից, բայց չի կարող օգտագործվել այլ ծրագրերի կողմից:"</string>
+    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"HTTP պրոքսին օգտագործվում է միայն դիտարկիչի կողմից:"</string>
     <string name="proxy_url_title" msgid="882042361706435904">"PAC URL` "</string>
     <string name="radio_info_dl_kbps" msgid="2903778264453410272">"DL թողունակությունը (կբ/վ)՝"</string>
     <string name="radio_info_ul_kbps" msgid="3802245899811732716">"UL թողունակությունը (կբ/վ)՝"</string>
@@ -325,7 +324,7 @@
     <string name="date_and_time_settings_summary" msgid="4617979434474713417">"Սահմանել ամսաթիվը, ժամը, ժամային գոտին, &amp; ձևաչափերը"</string>
     <string name="date_time_auto" msgid="2679132152303750218">"Օգտագործել ցանցի ժամանակը"</string>
     <string name="zone_auto_title" msgid="5500880975376882488">"Օգտագործել ցանցի ժամային գոտին"</string>
-    <string name="date_time_24hour_auto" msgid="7499659679134962547">"Օգտագործել տեղույթի կանխադրված կարգավորումը"</string>
+    <string name="date_time_24hour_auto" msgid="7499659679134962547">"Օգտագործել կանխադրված տեղույթը"</string>
     <string name="date_time_24hour_title" msgid="6209923858891621283">"24-ժամյա ձևաչափ"</string>
     <string name="date_time_24hour" msgid="1265706705061608742">"Օգտագործել 24-ժամյա ձևաչափը"</string>
     <string name="date_time_set_time_title" msgid="7116850506333406367">"Ժամը"</string>
@@ -355,7 +354,7 @@
     <string name="owner_info_settings_title" msgid="2537966178998339896">"Կողպէկրանի տեքստը"</string>
     <string name="security_enable_widgets_title" msgid="1701510007926738088">"Միացնել վիջեթները"</string>
     <string name="security_enable_widgets_disabled_summary" msgid="4408176087132339331">"Անջատվել է ադմինիստրատորի կողմից"</string>
-    <string name="lockdown_settings_title" msgid="4534779922580115990">"Ավելացնել մուտքի արգելափակման ընտրանքը"</string>
+    <string name="lockdown_settings_title" msgid="4534779922580115990">"Ավելացնել արգելափակման կոճակը"</string>
     <string name="lockdown_settings_summary" msgid="7270756909878256174">"Ցուցադրել սնուցման կոճակի ընտրանքը, որն անջատում է Smart Lock-ը, մատնահետքով ապակողպումը և կողպէկրանին ցուցադրվող ծանուցումները"</string>
     <string name="trust_agents_extend_unlock_title" msgid="3582017561316089951">"Միջանկյալ գործակալները հետաձգում են կողպումը"</string>
     <string name="trust_agents_extend_unlock_summary" msgid="3543997596586078084">"Եթե միացված է, միջանկյալ գործակալները երկար ժամանակ չեն թողնի, որ ձեր սարքը կողպվի, սակայն այլևս չեն կարողանա ապակողպել որևէ կողպված սարք:"</string>
@@ -403,7 +402,7 @@
     <string name="security_settings_face_enroll_introduction_title" msgid="6073249653318265486">"Բացեք դեմքի ճանաչման միջոցով"</string>
     <string name="security_settings_face_enroll_introduction_title_unlock_disabled" msgid="9223270521083202896">"Օգտագործեք դեմքը՝ նույնականացման համար"</string>
     <string name="security_settings_face_enroll_introduction_message" msgid="484806903869220184">"Դեմքի ճանաչման միջոցով ապակողպեք ձեր հեռախոսը, գնումներ կատարեք և մուտք գործեք հավելվածներ:"</string>
-    <string name="security_settings_face_enroll_introduction_message_unlock_disabled" msgid="2850101281254663082">"Օգտագործեք ձեր դեմքը՝ հեռախոսն ապակողպելու կամ գնումները թույլատրելու համար:\n\nՆշում. այս սարքն ապակողպելու համար չեք կարող օգտագործել ձեր դեմքը: Լրացուցիչ տեղեկություններ ստանալու համար դիմեք ձեր կազմակերպության ադմինիստրատորին:"</string>
+    <string name="security_settings_face_enroll_introduction_message_unlock_disabled" msgid="2850101281254663082">"Օգտագործեք ձեր դեմքը՝ հեռախոսն ապակողպելու կամ գնումներ թույլատրելու համար:\n\nՆշում. այս սարքն ապակողպելու համար չեք կարող օգտագործել ձեր դեմքը: Լրացուցիչ տեղեկություններ ստանալու համար դիմեք ձեր կազմակերպության ադմինիստրատորին:"</string>
     <string name="security_settings_face_enroll_introduction_message_setup" msgid="4533297059466270074">"Դեմքի ճանաչման միջոցով ապակողպեք ձեր հեռախոսը, գնումներ կատարեք և մուտք գործեք հավելվածներ"</string>
     <string name="security_settings_face_enroll_introduction_footer_message" msgid="7764021721107723266"></string>
     <string name="security_settings_face_enroll_repeat_title" msgid="2507710348140837875">"Դեմքը պահեք կենտրոնում"</string>
@@ -441,15 +440,15 @@
     <string name="security_settings_fingerprint_enroll_introduction_title" msgid="889558002683900544">"Ապակողպում մատնահետքով"</string>
     <string name="security_settings_fingerprint_enroll_introduction_title_unlock_disabled" msgid="7915504118657864429">"Օգտագործեք ձեր մատնահետքը"</string>
     <string name="security_settings_fingerprint_enroll_introduction_message" msgid="5586198131986682472">"Հեռախոսն ապակողպելու, գնումները թույլատրելու կամ հավելվածներ մուտք գործելու համար պարզապես մատը հպեք մատնահետքի սենսորին: Այդ գործողությունները հնարավոր է անել հեռախոսում ավելացված ցանկացած մատնահետքի միջոցով, այնպես որ մտածված ավելացրեք նոր մարդկանց մատնահետքերը:\n\nՆշում. ապակողպման հուսալի նախշը կամ PIN կոդը կարող է մատնահետքից ավելի ապահով լինել:"</string>
-    <string name="security_settings_fingerprint_enroll_introduction_message_unlock_disabled" msgid="1640839304679275468">"Օգտագործեք ձեր մատնահետքը՝ հեռախոսն ապակողպելու կամ գնումները թույլատրելու համար:\n\nՆշում. այս սարքն ապակողպելու համար չեք կարող օգտագործել ձեր մատնահետքը: Լրացուցիչ տեղեկություններ ստանալու համար դիմեք ձեր կազմակերպության ադմինիստրատորին:"</string>
-    <string name="security_settings_fingerprint_enroll_introduction_message_setup" msgid="6734490666593320711">"Օգտագործեք ձեր մատնահետքը՝ հեռախոսն ապակողպելու կամ գնումները թույլատրելու համար:\n\nՆշում. ապակողպման հուսալի նախշը կամ PIN կոդը կարող է մատնահետքից ավելի ապահով լինել:"</string>
+    <string name="security_settings_fingerprint_enroll_introduction_message_unlock_disabled" msgid="1640839304679275468">"Օգտագործեք ձեր մատնահետքը՝ հեռախոսն ապակողպելու կամ գնումներ թույլատրելու համար:\n\nՆշում. այս սարքն ապակողպելու համար չեք կարող օգտագործել ձեր մատնահետքը: Լրացուցիչ տեղեկություններ ստանալու համար դիմեք ձեր կազմակերպության ադմինիստրատորին:"</string>
+    <string name="security_settings_fingerprint_enroll_introduction_message_setup" msgid="6734490666593320711">"Օգտագործեք ձեր մատնահետքը՝ հեռախոսն ապակողպելու կամ գնումներ թույլատրելու համար:\n\nՆշում. ապակողպման հուսալի նախշը կամ PIN կոդը կարող է մատնահետքից ավելի ապահով լինել:"</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel" msgid="9168637333731599827">"Չեղարկել"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue" msgid="271662150372486535">"Շարունակել"</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel_setup" msgid="756928427429893070">"Բաց թողնել"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue_setup" msgid="4125977169169671144">"Հաջորդը"</string>
-    <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"Բա՞ց թողնել"</string>
+    <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"Բաց թողնե՞լ"</string>
     <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"Մատնահետքի կարգավորումն ընդամենը մեկ-երկու րոպե է տևում: Եթե բաց թողնեք, ավելի ուշ կարող եք անցնել կարգավորումներ և ավելացնել ձեր մատնահետքը:"</string>
-    <string name="lock_screen_intro_skip_title" msgid="5307431665496346914">"Բա՞ց թողնել"</string>
+    <string name="lock_screen_intro_skip_title" msgid="5307431665496346914">"Բաց թողնե՞լ"</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="tablet" msgid="7553945981266845264">"Սարքի պաշտպանության գործառույթները չեն միացվելու: Դուք չեք կարողանա կանխել այլ անձանց կողմից այս պլանշետի օգտագործումը՝ այն կորցնելու, գողանալու կամ վերակայելու դեպքում:"</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="device" msgid="1378243257238015603">"Սարքի պաշտպանության գործառույթները չեն միացվելու: Դուք չեք կարողանա կանխել այլ անձանց կողմից այս սարքի օգտագործումը՝ այն կորցնելու, գողանալու կամ վերակայելու դեպքում:"</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="default" msgid="8395540117461339748">"Սարքի պաշտպանության գործառույթները չեն միացվելու: Դուք չեք կարողանա կանխել այլ անձանց կողմից այս հեռախոսի օգտագործումը՝ այն կորցնելու, գողանալու կամ վերակայելու դեպքում:"</string>
@@ -467,11 +466,11 @@
     <string name="security_settings_fingerprint_enroll_dialog_ok" msgid="3428927518029038956">"Հաստատել"</string>
     <string name="security_settings_fingerprint_enroll_dialog_delete" msgid="4312297515772004580">"Ջնջել"</string>
     <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"Հպեք սենսորին"</string>
-    <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Դրեք ձեր մատը սենսորի վրա և բարձրացրեք թրթռոց զգալուց հետո"</string>
+    <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Մատը դրենք սենսորի վրա և բարձրացրեք թրթռոց զգալուց հետո"</string>
     <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"Բարձրացրեք, ապա կրկին հպեք"</string>
     <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Փոքր-ինչ տեղաշարժեք մատը՝ մատնահետքի տարբեր հատվածներ ավելացնելու համար"</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"Մատնահետքն ավելացվեց"</string>
-    <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"Այս պատկերակը նշանակում է, որ դուք կարող եք հաստատել ձեր ինքնությունն ու գնումները մատնահետքի միջոցով"</string>
+    <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"Այս պատկերակը ցույց է տալիս, որ դուք կարող եք ձեր ինքնությունն ու գնումները հաստատել մատնահետքի միջոցով"</string>
     <string name="security_settings_fingerprint_enroll_enrolling_skip" msgid="1473280156532146933">"Ավելի ուշ"</string>
     <string name="setup_fingerprint_enroll_enrolling_skip_title" msgid="2816424026528101690">"Բաց թողնե՞լ մատնահետքի կարգավորումը:"</string>
     <string name="setup_fingerprint_enroll_enrolling_skip_message" msgid="8139299964344809780">"Դուք ընտրել եք մատնահետքի օգտագործումը որպես հեռախոսն ապակողպելու եղանակներից մեկը: Եթե բաց թողնեք հիմա, ապա ձեզ անհրաժեշտ կլինի կատարել կարգավորումն ավելի ուշ: Կարգավորումը տևում է ընդամենը մոտ մեկ րոպե:"</string>
@@ -668,7 +667,6 @@
       <item quantity="one">Պետք է <xliff:g id="NUMBER_1">%d</xliff:g>-ից քիչ թվանշան պարունակի</item>
       <item quantity="other">Պետք է <xliff:g id="NUMBER_1">%d</xliff:g>-ից քիչ թվանշան պարունակի</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Պետք է պարունակի միայն 0-9 թվանշաններ"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Սարքի ադմինիստրատորը չի թույլատրում օգտագործել վերջին PIN կոդերը"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"ՏՏ ադմինիստրատորն արգելափակել է պարզ PIN կոդերը: Փորձեք մեկ այլ PIN:"</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Այն չի կարող պարունակել անվավեր գրանշան"</string>
@@ -699,6 +697,10 @@
       <item quantity="one">Must contain at least <xliff:g id="COUNT">%d</xliff:g> non-letter characters</item>
       <item quantity="other">Պետք է պարունակի առնվազն <xliff:g id="COUNT">%d</xliff:g> ոչ-տառային գրանշան</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">Պետք է պարունակի առնվազն <xliff:g id="COUNT">%d</xliff:g> ոչ թվային նիշ</item>
+      <item quantity="other">Պետք է պարունակի առնվազն <xliff:g id="COUNT">%d</xliff:g> ոչ թվային նիշ</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Սարքի ադմինիստրատորը թույլ չի տալիս օգտագործել վերջին գաղտնաբառը"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"ՏՏ ադմինիստրատորն արգելափակել է պարզ գաղտնաբառերը: Փորձեք մեկ այլ գաղտնաբառ:"</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Թվանշանների աճող, նվազող կամ կրկնվող հաջորդականությունն արգելված է"</string>
@@ -727,7 +729,7 @@
     <string name="bluetooth_settings" msgid="5228032727293770389">"Bluetooth"</string>
     <string name="bluetooth_settings_title" msgid="7261244857456521825">"Bluetooth"</string>
     <string name="bluetooth_settings_summary" msgid="1221689092429277887">"Կառավարել կապերը, կարգավորել սարքի անունը &amp; հայտնաբերելիությունը"</string>
-    <string name="bluetooth_pairing_request" msgid="7221745525632573125">"Զուգակցե՞լ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> սարքի հետ:"</string>
+    <string name="bluetooth_pairing_request" msgid="7221745525632573125">"Զուգակցե՞լ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> սարքի հետ"</string>
     <string name="bluetooth_pairing_key_msg" msgid="1139230917419961975">"Bluetooth զուգակցման կոդը"</string>
     <string name="bluetooth_enter_passkey_msg" msgid="6205151011298670207">"Մուտքագրեք զուգավորման կոդը, ապա սեղմեք Վերադառնալ կամ Մուտք"</string>
     <string name="bluetooth_enable_alphanumeric_pin" msgid="9138308197078115672">"PIN-ը տառեր և նշաններ է պարունակում"</string>
@@ -757,7 +759,7 @@
     <string name="bluetooth_preference_no_found_devices" msgid="4190090666412408576">"Հասանելի սարքեր չկան"</string>
     <string name="bluetooth_device_context_connect" msgid="1812090541371432890">"Միանալ"</string>
     <string name="bluetooth_device_context_disconnect" msgid="8085015949275771802">"Անջատել"</string>
-    <string name="bluetooth_device_context_pair_connect" msgid="1503322591778810032">"Զուգավորել &amp; միանալ"</string>
+    <string name="bluetooth_device_context_pair_connect" msgid="1503322591778810032">"Զուգակցել &amp; միանալ"</string>
     <string name="bluetooth_device_context_unpair" msgid="250588431708253041">"Ապամիավորել"</string>
     <string name="bluetooth_device_context_disconnect_unpair" msgid="4519151805677280077">"Անջատել &amp; ապազուգավորել"</string>
     <string name="bluetooth_device_context_connect_advanced" msgid="423463405499392444">"Ընտրանքներ..."</string>
@@ -847,7 +849,7 @@
     <string name="wifi_notify_open_networks" msgid="4782239203624619655">"Ծանուցումներ բաց ցանցերի մասին"</string>
     <string name="wifi_notify_open_networks_summary" msgid="1383681260705466715">"Տեղեկացնել լավ ազդանշանով բաց ցանցերի հասանելիության մասին"</string>
     <string name="wifi_wakeup" msgid="4963732992164721548">"Ավտոմատ միացնել Wi‑Fi-ը"</string>
-    <string name="wifi_wakeup_summary" msgid="1152699417411690">"Wi‑Fi-ը կրկին կմիանա պահված լավ ազդանշանով պահված ցանցերի, օրինակ, ձեր տան ցանցի մոտակայքում"</string>
+    <string name="wifi_wakeup_summary" msgid="1152699417411690">"Wi‑Fi-ը կրկին կմիանա լավ ազդանշանով պահված ցանցերի, օրինակ, ձեր տան ցանցի մոտակայքում"</string>
     <string name="wifi_wakeup_summary_no_location" msgid="3007457288587966962">"Անհասանելի է, քանի որ տեղորոշումն անջատված է։ Միացրեք "<annotation id="link">"տեղորոշումը"</annotation>"։"</string>
     <string name="wifi_wakeup_summary_scanning_disabled" msgid="6820040651529910914">"Անհասանելի է, քանի որ Wi‑Fi ցանցերի որոնումն անջատված է"</string>
     <string name="wifi_wakeup_summary_scoring_disabled" msgid="7067018832237903151">"Օգտագործելու համար ընտրեք ցանցի վարկանիշի մատակարարը"</string>
@@ -887,7 +889,7 @@
     <string name="wifi_menu_forget" msgid="7561140554450163075">"Մոռանալ ցանցը"</string>
     <string name="wifi_menu_modify" msgid="4080178040721021101">"Փոփոխել ցանցը"</string>
     <string name="wifi_empty_list_wifi_off" msgid="272877164691346240">"Հասանելի ցանցերը տեսնելու համար միացրեք Wi‑Fi-ը:"</string>
-    <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"Wi‑Fi ցանցերը փնտրվում են…"</string>
+    <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"Որոնում ենք Wi-Fi ցանցեր…"</string>
     <string name="wifi_empty_list_user_restricted" msgid="2341613007817352431">"Դուք թույլտվություն չունեք փոխելու Wi‑Fi-ի ցանցը:"</string>
     <string name="wifi_more" msgid="3538241640407382185">"Ավելին"</string>
     <string name="wifi_setup_wps" msgid="6730131677695521321">"Ավտոմատ կարգավորում (WPS)"</string>
@@ -914,9 +916,9 @@
     <string name="passpoint_content" msgid="340527524510304327">"<xliff:g id="NAME">%1$s</xliff:g>-ի հավատարմագրեր"</string>
     <string name="wifi_eap_method" msgid="3752116941487485859">"EAP եղանակ"</string>
     <string name="please_select_phase2" msgid="5848080896810435677">"Փուլ 2-ի նույնականացում"</string>
-    <string name="wifi_eap_ca_cert" msgid="1496395241849383785">"CA վկայական"</string>
+    <string name="wifi_eap_ca_cert" msgid="1496395241849383785">"CA հավաստագիր"</string>
     <string name="wifi_eap_domain" msgid="3298302320003640130">"Տիրույթ"</string>
-    <string name="wifi_eap_user_cert" msgid="6786839531765719173">"Օգտատիրոջ վկայական"</string>
+    <string name="wifi_eap_user_cert" msgid="6786839531765719173">"Օգտատիրոջ հավաստագիր"</string>
     <string name="wifi_eap_identity" msgid="5280457017705738773">"Ինքնություն"</string>
     <string name="wifi_eap_anonymous" msgid="6352344972490839958">"Անանուն ինքնություն"</string>
     <string name="wifi_password" msgid="6942983531275177771">"Գաղտնաբառ"</string>
@@ -932,9 +934,9 @@
     <string name="wifi_ip_settings" msgid="4636102290236116946">"IP կարգավորումներ"</string>
     <string name="wifi_privacy_settings" msgid="4462092795794247809">"Գաղտնիություն"</string>
     <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"Պատահական ընտրված MAC"</string>
-    <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"Ավելացնել սարք"</string>
+    <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"Ավելացրեք սարք"</string>
     <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"Սարքը «<xliff:g id="SSID">%1$s</xliff:g>» ցանցին ավելացնելու համար տեսախցիկը պահեք QR կոդի վրա"</string>
-    <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"Սկանավորել QR կոդը"</string>
+    <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"Սկանավորեք QR կոդը"</string>
     <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"«<xliff:g id="SSID">%1$s</xliff:g>» ցանցին միանալու համար տեսախցիկը պահեք QR կոդի վրա"</string>
     <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"Wi‑Fi ցանցին միանալու համար սկանավորեք QR կոդը"</string>
     <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Կիսվել Wi‑Fi-ով"</string>
@@ -949,18 +951,18 @@
     <string name="wifi_dpp_check_connection_try_again" msgid="7144663015219170999">"Ստուգեք ինտերնետ կապը և նորից փորձեք"</string>
     <string name="wifi_dpp_choose_network" msgid="6251424431594491691">"Ընտրեք ցանց"</string>
     <string name="wifi_dpp_choose_network_to_connect_device" msgid="6385259857886784285">"Սարքը միացնելու համար ընտրեք ցանցը"</string>
-    <string name="wifi_dpp_add_device_to_wifi" msgid="6454198064645462446">"Կապակցե՞լ այս սարքը «<xliff:g id="SSID">%1$s</xliff:g>» ցանցին"</string>
+    <string name="wifi_dpp_add_device_to_wifi" msgid="6454198064645462446">"Ավելացնե՞լ այս սարքը «<xliff:g id="SSID">%1$s</xliff:g>» ցանցում"</string>
     <string name="wifi_dpp_wifi_shared_with_device" msgid="5713765471758272471">"Սարքը միացված է Wi‑Fi-ին"</string>
     <string name="wifi_dpp_add_another_device" msgid="3698441567235301565">"Կապացել այլ սարք"</string>
     <string name="wifi_dpp_choose_different_network" msgid="128515107488187050">"Ընտրել այլ ցանց"</string>
-    <string name="wifi_dpp_could_not_add_device" msgid="4966109556543584813">"Չհաջողվեց ավելացնել սարք"</string>
+    <string name="wifi_dpp_could_not_add_device" msgid="4966109556543584813">"Չհաջողվեց ավելացնել սարքը"</string>
     <string name="wifi_dpp_device_found" msgid="6488461467496850841">"Գտնվել է 1 սարք"</string>
     <string name="wifi_dpp_sharing_wifi_with_this_device" msgid="2540529164687476827">"Սարքը միանում է Wi‑Fi-ին…"</string>
     <string name="wifi_dpp_connecting" msgid="4229290407210299897">"Միացում…"</string>
     <string name="wifi_dpp_share_hotspot" msgid="847987212473038179">"Ընդհանուր թեժ կետ"</string>
     <string name="wifi_dpp_lockscreen_title" msgid="3910665850075275963">"Հաստատեք ձեր ինքնությունը"</string>
     <string name="wifi_dpp_wifi_password" msgid="8007558344032612455">"Wi-Fi-ի գաղտնաբառ՝ <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
-    <string name="wifi_dpp_hotspot_password" msgid="6172326289042241924">"Թեժ կետի գաղտնաբառ՝ <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
+    <string name="wifi_dpp_hotspot_password" msgid="6172326289042241924">"Թեժ կետի գաղտնաբառը՝ <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
     <string name="wifi_dpp_add_device" msgid="1347056725253936358">"Ավելացնել սարք"</string>
     <string name="wifi_dpp_connect_network_using_qr_code" msgid="115993715600532357">"Միացեք այս ցանցին QR կոդի միջոցով"</string>
     <string name="retry" msgid="8500839563577344702">"Կրկնել"</string>
@@ -968,7 +970,7 @@
     <string name="wifi_unchanged" msgid="6804964646942333992">"(անփոփոխ)"</string>
     <string name="wifi_unspecified" msgid="893491188483500809">"Ընտրեք"</string>
     <string name="wifi_multiple_cert_added" msgid="7986200585749147204">"(Ավելացվել են մի քանի վկայագրեր)"</string>
-    <string name="wifi_use_system_certs" msgid="4794489370929885022">"Օգտագործել համակարգի վկայագրերը"</string>
+    <string name="wifi_use_system_certs" msgid="4794489370929885022">"Օգտագործել համակարգի հավաստագրերը"</string>
     <string name="wifi_do_not_provide_eap_user_cert" msgid="4044301449482425250">"Չտրամադրել"</string>
     <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"Չվավերացնել"</string>
     <string name="wifi_do_not_validate_eap_server_warning" msgid="3895397996759837323">"Վկայականը նշված չէ: Միացումը գաղտնի չի լինի:"</string>
@@ -1064,7 +1066,7 @@
     <string name="wifi_hotspot_name_summary_connecting" msgid="5176787959408511889">"<xliff:g id="WIFI_HOTSPOT_NAME">%1$s</xliff:g>-ը միանում է…"</string>
     <string name="wifi_hotspot_name_summary_connected" msgid="8387768642326756749">"Այլ սարքերը կարող են միանալ <xliff:g id="WIFI_HOTSPOT_NAME">%1$s</xliff:g>-ին"</string>
     <string name="wifi_hotspot_password_title" msgid="4289338152595154889">"Թեժ կետի գաղտնաբառը"</string>
-    <string name="wifi_hotspot_ap_band_title" msgid="3485744480410441949">"Հաճախականությունների դիապազոն"</string>
+    <string name="wifi_hotspot_ap_band_title" msgid="3485744480410441949">"Հաճախականությունների միջակայք"</string>
     <string name="wifi_hotspot_footer_info_regular" msgid="3876006922622827363">"Թեժ կետի միջոցով ստեղծեք Wi‑Fi ցանց ձեր այլ սարքերի hամար: Թեժ կետը տրամադրում է ինտերնետային կապ բջջային ցանցի միջոցով: Կարող են կիրառվել լրացուցիչ գանձումներ։"</string>
     <string name="wifi_hotspot_footer_info_local_only" msgid="3339582350894639261">"Հավելվածները կարող են ստեղծել թեժ կետ՝ մոտակա սարքերին նյութեր փոխանցելու համար:"</string>
     <string name="wifi_hotspot_auto_off_title" msgid="7416022590415189590">"Ավտոմատ անջատել թեժ կետը"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Բջջային"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Եթե Wi-Fi-ը հասանելի չէ, օգտագործել բջջային ցանցը"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Եթե բջջային ցանցը հասանելի չէ, օգտագործել Wi-Fi-ը"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Զանգ Wi-Fi-ի միջոցով։ Եթե Wi‑Fi կապն ընդհատվի, զանգը կավարտվի։"</string>
@@ -1196,7 +1201,7 @@
     <string name="auto_brightness_very_high_title" msgid="6649896560889239565">"Շատ բարձր"</string>
     <string name="auto_brightness_subtitle" msgid="8516999348793100665">"Ձեր նախընտրելի պայծառության մակարդակը"</string>
     <string name="auto_brightness_off_summary" msgid="6162650416289359104">"Չկարգավորել առկա լույսի համար"</string>
-    <string name="auto_brightness_very_high_summary" msgid="7202032980509583918">"Մարտկոցի ավելի երկար օգտագործում"</string>
+    <string name="auto_brightness_very_high_summary" msgid="7202032980509583918">"Մարտկոցի ավելի արագ սպառում"</string>
     <string name="auto_brightness_disclaimer" msgid="5416696351199148809">"Լույսի պայծառության մակարդակի օպտիմալացում: Նույնիսկ երբ այս գործառույթը միացված է, դուք կարող եք ժամանակավորապես կարգավորել պայծառությունը:"</string>
     <string name="auto_brightness_description" msgid="8209140379089535411">"Էկրանի պայծառությունն ավտոմատ կկարգավորվի՝ կախված միջավայրի պայմաններից և ձեր գործողություններից։ Դուք կարող եք տեղաշարժել սահիչը՝ թույլ տալով հարմարվող պայծառությանը հիշել ձեր կարգավորումները։"</string>
     <string name="display_white_balance_title" msgid="5747260735311935143">"Էկրանի սպիտակի բալանս"</string>
@@ -1259,7 +1264,7 @@
     <string name="doze_title" msgid="235269029233857546">"Նոր ծանուցումներ"</string>
     <string name="doze_summary" msgid="6762274282827831706">"Ակտիվացնել էկրանը ծանուցումներ ստանալու դեպքում"</string>
     <string name="doze_always_on_title" msgid="8555184965031789941">"Միշտ միացված է"</string>
-    <string name="doze_always_on_summary" msgid="7654436900436328950">"Ցուցադրել ժամանակը, ծանուցումների պատկերակները և այլ տեղեկատվություն: Մարտկոցի ավելի երկար օգտագործում:"</string>
+    <string name="doze_always_on_summary" msgid="7654436900436328950">"Ցուցադրել ժամանակը, ծանուցումների պատկերակները և այլ տեղեկատվություն: Մարտկոցի ավելի արագ սպառում:"</string>
     <string name="title_font_size" msgid="5021464556860010851">"Տառաչափ"</string>
     <string name="short_summary_font_size" msgid="4141077908728522946">"Տառաչափի մեծացում կամ փոքրացում"</string>
     <string name="sim_lock_settings" msgid="1986924650622642189">"SIM քարտի կողպման կարգավորումներ"</string>
@@ -1308,7 +1313,7 @@
     <string name="security_patch" msgid="483709031051932208">"Անվտանգության համակարգի վերջին թարմացումը"</string>
     <string name="model_info" msgid="1729765474260797594">"Մոդելը"</string>
     <string name="model_summary" msgid="8781425868254352168">"Մոդել՝ %1$s"</string>
-    <string name="hardware_info" msgid="174270144950621815">"Մոդելը և սարքակազմը"</string>
+    <string name="hardware_info" msgid="174270144950621815">"Մոդել և սարքակազմ"</string>
     <string name="hardware_revision" msgid="3315744162524354246">"Սարքակազմի տարբերակը"</string>
     <string name="fcc_equipment_id" msgid="8681995718533066093">"Սարքավորման ID-ն"</string>
     <string name="baseband_version" msgid="9115560821840757786">"Baseband-ի տարբերակը"</string>
@@ -1353,7 +1358,7 @@
     <string name="status_roaming" msgid="5191044997355099561">"Ռոումինգ"</string>
     <string name="status_operator" msgid="6017986100643755390">"Ցանց"</string>
     <string name="status_wifi_mac_address" msgid="3868452167971295995">"Wi‑Fi MAC հասցե"</string>
-    <string name="status_bt_address" msgid="460568179311735657">"Bluetooth-ի հասցեն"</string>
+    <string name="status_bt_address" msgid="460568179311735657">"Bluetooth հասցե"</string>
     <string name="status_serial_number" msgid="8257722124627415159">"Հերթական համարը"</string>
     <string name="status_up_time" msgid="77128395333934087">"Աշխատած ժամանակը"</string>
     <string name="status_awake_time" msgid="1251959094010776954">"Արթուն մնալու տևողությունը"</string>
@@ -1563,10 +1568,10 @@
     <string name="restore_default_apn" msgid="7195266404077471007">"Կանխադրված APN կարգավորումների վերականգնում:"</string>
     <string name="menu_restore" msgid="3799288817317293115">"Վերականգնել կանխադրվածները"</string>
     <string name="restore_default_apn_completed" msgid="5671734152740058937">"Սկզբնական APN կարգավորումների վերակարգավորումն ավարտված է:"</string>
-    <string name="reset_dashboard_title" msgid="7084966342252178530">"Զրոյացման ընտրանքներ"</string>
+    <string name="reset_dashboard_title" msgid="7084966342252178530">"Վերակայման ընտրանքներ"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"Ցանցի, հավելվածների և սարքի կարգավորումները հնարավոր է զրոյացնել"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"Զրոյացնել Wi-Fi-ի, բջջային թրաֆիկի և Bluetooth-ի կարգավորումները"</string>
-    <string name="reset_network_desc" msgid="4982633363916261109">"Արդյունքում կվերակայվեն բոլոր ցանցային կարգավորումները, ներառյալ հետևյալը՝\n\n"<li>"Wi‑Fi"</li>\n<li>"Բջջային ինտերնետ"</li>\n<li>"Bluetooth"</li></string>
+    <string name="reset_network_desc" msgid="4982633363916261109">"Արդյունքում կզրոյացվեն բոլոր ցանցային կարգավորումները, ներառյալ հետևյալը՝\n\n"<li>"Wi‑Fi"</li>\n<li>"Բջջային ինտերնետ"</li>\n<li>"Bluetooth"</li></string>
     <string name="reset_esim_title" msgid="7630781767040831893">"Ջնջել ներբեռնված SIM-երը"</string>
     <string name="reset_esim_desc" msgid="433226911566802">"Նոր SIM քարտ ներբեռնելու համար դիմեք ձեր օպերատորին։ Բջջային կապի սակագնային պլանները չեն չեղարկվի:"</string>
     <string name="reset_network_button_text" msgid="4293271046867912819">"Զրոյացնել կարգավորումները"</string>
@@ -1651,7 +1656,7 @@
     </plurals>
     <string name="location_category_recent_location_access" msgid="286059523360285026">"Տեղադրության տվյալների վերջին օգտագործումը"</string>
     <string name="location_recent_location_access_view_details" msgid="2051602261436245905">"Մանրամասն"</string>
-    <string name="location_no_recent_apps" msgid="77502059586413278">"Որևէ ծրագիր տեղադրության հարցում չի կատարել վերջերս"</string>
+    <string name="location_no_recent_apps" msgid="77502059586413278">"Վերջին ժամանակաշրջանում հավելվածները տեղադրության հարցում չեն արել"</string>
     <string name="location_no_recent_accesses" msgid="6289916310397279890">"Ոչ մի հավելված չի օգտագործել տեղադրությունը"</string>
     <string name="location_high_battery_use" msgid="7177199869979522663">"Մարտկոցի շատ օգտագործում"</string>
     <string name="location_low_battery_use" msgid="5030448574501435888">"Մարտկոցի ցածր սպառում"</string>
@@ -1684,7 +1689,7 @@
     <string name="contributors_title" msgid="6800028420806884340">"Աջակցողներ"</string>
     <string name="manual" msgid="5431859421432581357">"Ձեռքով"</string>
     <string name="regulatory_labels" msgid="380968489247381025">"Հավաստագրման պիտակներ"</string>
-    <string name="safety_and_regulatory_info" msgid="7113766428000920132">"Անվտանգության և կանոնակարգումների ձեռնարկ"</string>
+    <string name="safety_and_regulatory_info" msgid="7113766428000920132">"Անվտանգության և ստանդարտների ձեռնարկ"</string>
     <string name="copyright_title" msgid="3847703367689932190">"Հեղինակային իրավունք"</string>
     <string name="license_title" msgid="7582145947873528540">"Արտոնագիր"</string>
     <string name="terms_title" msgid="1804549588198223771">"Կանոններն ու պայմանները"</string>
@@ -1702,7 +1707,7 @@
     <string name="settings_safetylegal_activity_loading" msgid="7680998654145172">"Բեռնում..."</string>
     <string name="confirm_device_credential_use_alternate_method" msgid="1279869272895739941">"Օգտագործել այլ եղանակ"</string>
     <string name="lockpassword_choose_your_screen_lock_header" msgid="6283518876031424798">"Էկրանի կողպում"</string>
-    <string name="lockpassword_choose_your_password_message" msgid="2838273977481046536">"Սարքը պաշտպանելու համար գաղտնաբառ"</string>
+    <string name="lockpassword_choose_your_password_message" msgid="2838273977481046536">"Ստեղծեք գաղտնաբառ՝ սարքը պաշտպանելու համար"</string>
     <string name="lockpassword_choose_your_password_header_for_fingerprint" msgid="4921343500484160894">"Մատնահետքն օգտագործելու համար ընտրեք գաղտնաբառ"</string>
     <string name="lockpassword_choose_your_pattern_header_for_fingerprint" msgid="314870151462139417">"Մատնահետքն օգտագործելու համար ստեղծեք նախշ"</string>
     <string name="lockpassword_choose_your_pin_message" msgid="8942598950627277885">"Պաշտպանության համար ավելացրեք PIN կոդ"</string>
@@ -1749,7 +1754,7 @@
     <string name="lockpattern_recording_intro_footer" msgid="5426745740754065099">"Սեղմեք Ցանկ` օգնության համար:"</string>
     <string name="lockpattern_recording_inprogress" msgid="4060818382176523671">"Հեռացրեք մատը ավարտելուց հետո"</string>
     <string name="lockpattern_recording_incorrect_too_short" msgid="6374760294545431845">"Միացրեք առնվազն <xliff:g id="NUMBER">%d</xliff:g> կետ: Փորձեք կրկին:"</string>
-    <string name="lockpattern_pattern_entered_header" msgid="2108106638322637851">"Նախշն ընդունված է"</string>
+    <string name="lockpattern_pattern_entered_header" msgid="2108106638322637851">"Նախշը պահվեց"</string>
     <string name="lockpattern_need_to_confirm" msgid="4079482507985867389">"Նկարեք նախշը նորից` հաստատելու համար"</string>
     <string name="lockpattern_pattern_confirmed_header" msgid="5603156929428721407">"Նոր նախշ"</string>
     <string name="lockpattern_confirm_button_text" msgid="7059311304112902598">"Հաստատել"</string>
@@ -2034,7 +2039,7 @@
     <string name="accessibility_settings_summary" msgid="5742379519336396561">"Էկրանի ընթերցիչներ, էկրան, կառավարման տարրեր"</string>
     <string name="vision_settings_title" msgid="7315352351051423944">"Տեսողության կարգավորումներ"</string>
     <string name="vision_settings_description" msgid="3476589459009287332">"Օգտվեք հատուկ հնարավորություններից՝ հարմար աշխատանքի համար։ Այս գործառույթները կարող եք փոփոխել սարքի կարգավորումներում։"</string>
-    <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"Փոխել տառաչափը"</string>
+    <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"Փոխեք տառաչափը"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"Էկրանի ընթերցիչներ"</string>
     <string name="audio_and_captions_category_title" msgid="6140472938769619212">"Աուդիո և էկրանի տեքստ"</string>
     <string name="display_category_title" msgid="545168481672250195">"Էկրան"</string>
@@ -2060,12 +2065,12 @@
     <string name="accessibility_shortcut_service_title" msgid="3516052294376744060">"Դյուրանցման ծառայությունը"</string>
     <string name="accessibility_shortcut_service_on_lock_screen_title" msgid="1279441617927949980">"Թույլատրել կողպէկրանից"</string>
     <string name="accessibility_shortcut_description" msgid="1427049334225166395">"Հատուկ գործառույթն օգտագործելու համար սեղմեք և 3 վայրկյան սեղմած պահեք ձայնի ուժգնության երկու կոճակները, երբ դյուրանցումը միացված է։"</string>
-    <string name="accessibility_toggle_high_text_contrast_preference_title" msgid="5652244684961877255">"Ցայտուն տեքստ"</string>
+    <string name="accessibility_toggle_high_text_contrast_preference_title" msgid="5652244684961877255">"Բարձր կոնտրաստի տեքստ"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"Ավտոմատ թարմացնել էկրանի խոշորությունը"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"Թարմացնել էկրանի խոշորությունը ծրագրի տարանցումների վրա"</string>
     <string name="accessibility_power_button_ends_call_prerefence_title" msgid="6172987104538172869">"Սնուցման կոճակը ավարտում է զանգը"</string>
     <string name="accessibility_toggle_large_pointer_icon_title" msgid="9127905775116570565">"Մկնիկի խոշոր նշորդ"</string>
-    <string name="accessibility_disable_animations" msgid="8378441317115710009">"Անջատել շարժանկարները"</string>
+    <string name="accessibility_disable_animations" msgid="8378441317115710009">"Անջատել շարժունացումը"</string>
     <string name="accessibility_toggle_master_mono_title" msgid="899550848196702565">"Մոնո"</string>
     <string name="accessibility_toggle_master_mono_summary" msgid="3847052868469033235">"Աուդիո նվագարկելիս միավորել ալիքները"</string>
     <string name="accessibility_toggle_master_balance_title" msgid="8723492001092647562">"Աուդիո բալանս"</string>
@@ -2078,8 +2083,8 @@
     <string name="accessibility_timeout_2mins" msgid="4124259290444829477">"2 րոպե"</string>
     <string name="accessibility_content_timeout_preference_title" msgid="5160746882250939464">"Ժամանակ կարդալու համար"</string>
     <string name="accessibility_control_timeout_preference_title" msgid="2771808346038759474">"Ժամանակ գործողության կատարման համար"</string>
-    <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"Նշեք, թե որքան ժամանակ է ձեզ անհրաժեշտ` ավտոմատ անհետացող հաղորդագրությունները կարդալու համար:\n\nԱյս կարգավորումը ոչ բոլոր հավելվածներում է աջակցվում:"</string>
-    <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"Նշեք, թե որքան ժամանակ է ձեզ անհրաժեշտ՝ կատարելու ավտոմատ անհետացող հաղորդագրություններում ներկայացված գործողությունները:\n\nԱյս կարգավորումը ոչ բոլոր հավելվածներում է աջակցվում:"</string>
+    <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"Ընտրեք, թե որքան ժամանակ է ձեզ անհրաժեշտ ավտոմատ անհետացող հաղորդագրությունները կարդալու համար:\n\nԱյս կարգավորումը ոչ բոլոր հավելվածներում է աջակցվում:"</string>
+    <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"Ընտրեք, թե որքան ժամանակ է ձեզ անհրաժեշտ ավտոմատ անհետացող հաղորդագրությունների հետ կապված գործողություն կատարելու համար:\n\nԱյս կարգավորումը ոչ բոլոր հավելվածներում է աջակցվում:"</string>
     <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"Սեղմելու և պահելու հապաղումը"</string>
     <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"Գունաշրջում"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"Կարող է ազդել սարքի աշխատանքի վրա"</string>
@@ -2190,8 +2195,8 @@
     <string name="print_settings" msgid="7886184656544483072">"Տպում"</string>
     <string name="print_settings_summary_no_service" msgid="634173687975841526">"Անջատված է"</string>
     <plurals name="print_settings_summary" formatted="false" msgid="7580293760281445137">
-      <item quantity="one"><xliff:g id="COUNT">%1$d</xliff:g> print services on</item>
-      <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> տպման ծառայություն միացված է</item>
+      <item quantity="one">Միացված է <xliff:g id="COUNT">%1$d</xliff:g> տպման ծառայություն</item>
+      <item quantity="other">Միացված է <xliff:g id="COUNT">%1$d</xliff:g> տպման ծառայություն</item>
     </plurals>
     <plurals name="print_jobs_summary" formatted="false" msgid="6180308415569432845">
       <item quantity="one"><xliff:g id="COUNT">%1$d</xliff:g> print jobs</item>
@@ -2273,10 +2278,10 @@
     <string name="battery_tip_smart_battery_title" product="device" msgid="7419448992583346364">"Երկարացրեք սարքի մարտկոցի աշխատաժամանակը"</string>
     <string name="battery_tip_smart_battery_summary" msgid="5344821856478265778">"Միացնել մարտկոցի կառավարիչը"</string>
     <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Միացնել մարտկոցի տնտեսումը"</string>
-    <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Մարտկոցի լիցքը կարող է սպասվածից շուտ սպառվել"</string>
+    <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Մարտկոցը գուցե սպասվածից շուտ սպառվի"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Մարտկոցի տնտեսումը միացված է"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Որոշ գործառույթներ կարող են պատշաճ չաշխատել"</string>
-    <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Հեռախոսը սովորականից շատ է էներգիա օգտագործել"</string>
+    <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Սարքը սովորականից շատ է օգտագործվել"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"Պլանշետը սովորականից շատ է էներգիա օգտագործել"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"Սարքը սովորականից շատ է էներգիա օգտագործել"</string>
     <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"Մարտկոցի լիցքը կարող է սովորականից շուտ սպառվել"</string>
@@ -2371,7 +2376,7 @@
     <string name="usage_type_wake_lock" msgid="6729977238748413476">"Արթուն պահել"</string>
     <string name="usage_type_gps" msgid="5914062195732419196">"GPS"</string>
     <string name="usage_type_wifi_running" msgid="4192567991891907030">"Wi‑Fi-ն աշխատում է"</string>
-    <string name="usage_type_phone" product="tablet" msgid="4279605085824633501">"Գրասալիկ"</string>
+    <string name="usage_type_phone" product="tablet" msgid="4279605085824633501">"Պլանշետ"</string>
     <string name="usage_type_phone" product="default" msgid="3901842461077646153">"Հեռախոս"</string>
     <string name="usage_type_data_send" msgid="6339880867171142725">"Ուղարկված բջջային փաթեթներ"</string>
     <string name="usage_type_data_recv" msgid="2099757621601333453">"Ստացված բջջային փաթեթներ"</string>
@@ -2444,11 +2449,11 @@
     <string name="battery_saver" msgid="3989710213758938398">"Մարտկոցի տնտեսում"</string>
     <string name="battery_saver_auto_title" msgid="4158659069641849952">"Ավտոմատ միացնել"</string>
     <string name="battery_saver_auto_no_schedule" msgid="739814529432092706">"Ժամանակացույց չկա"</string>
-    <string name="battery_saver_auto_routine" msgid="886514412067906980">"Լիցքավորումների վիճակագրության հիման վրա"</string>
+    <string name="battery_saver_auto_routine" msgid="886514412067906980">"Լիցքավորման պատմության հիման վրա"</string>
     <string name="battery_saver_auto_percentage" msgid="5791982309331921556">"Լիցքի մակարդակի հիման վրա"</string>
     <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"Միացնել, եթե հավանականությունը մեծ է, որ լիցքի մակարդակը չի բավականացնի մինչև հաջորդ լիցքավորումը"</string>
-    <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"Միացնել <xliff:g id="PERCENT">%1$s</xliff:g> լիցքի դեպքում"</string>
-    <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"Ժամանակացույցի ստեղծում"</string>
+    <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"Կմիանա <xliff:g id="PERCENT">%1$s</xliff:g> լիցքի դեպքում"</string>
+    <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"Ստեղծել ժամանակացույց"</string>
     <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"Անջատել լրիվ լիցքավորված ժամանակ"</string>
     <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"Մարտկոցի տնտեսման ռեժիմն անջատվում է, երբ հեռախոսի լիցքը <xliff:g id="PERCENT">%1$s</xliff:g> է"</string>
     <string name="battery_saver_sticky_description_new" product="tablet" msgid="3284967694001857194">"Մարտկոցի տնտեսման ռեժիմն անջատվում է, երբ պլանշետի լիցքը <xliff:g id="PERCENT">%1$s</xliff:g> է"</string>
@@ -2461,7 +2466,7 @@
     <string name="battery_saver_turn_on_automatically_never" msgid="2623381258359775227">"Երբեք"</string>
     <string name="battery_saver_turn_on_automatically_pct" msgid="434270432432390307">"մատկոցի <xliff:g id="PERCENT">%1$s</xliff:g> լիցքի դեպքում"</string>
     <string name="battery_percentage" msgid="7782252476471033843">"Մարտկոցի լիցքը"</string>
-    <string name="battery_percentage_description" msgid="9219875229166700610">"Մարտկոցի տոկոսը ցուցադրել կարգավիճակի գոտում"</string>
+    <string name="battery_percentage_description" msgid="9219875229166700610">"Մարտկոցի լիցքի տոկոսը ցույց տալ կարգավիճակի տողում"</string>
     <string name="process_stats_summary_title" msgid="9189588417488537954">"Գործընթացի վիճակագրություն"</string>
     <string name="process_stats_summary" msgid="8077998499161221885">"Ընթացիկ գործընթացների տեխնիկական վիճակագրություն"</string>
     <string name="app_memory_use" msgid="5126237308545653706">"Օգտագործվող հիշողություն"</string>
@@ -2504,7 +2509,7 @@
     <string name="voice_interactor_preference_summary" msgid="7321365727286121067">"Ամբողջական թեժ բառեր և շփում"</string>
     <string name="voice_recognizer_preference_summary" msgid="3681161319745912594">"Խոսքից տեքստի պարզ տարբերակ"</string>
     <string name="voice_interaction_security_warning" msgid="4986261746316889768">"Ձայնի ներածման այս ծառայությունը կկարողանա կատարել ձայնի մշտադիտարկում և ձեր անունից վերահսկել ձայնի հնարավորությամբ ծրագրերը: Դրա պատճառը <xliff:g id="VOICE_INPUT_SERVICE_APP_NAME">%s</xliff:g> ծրագիրն է: Միացնե՞լ այս ծառայությունը:"</string>
-    <string name="tts_engine_preference_title" msgid="1183116842356275061">"Նախընտրելի մեխանիզմը"</string>
+    <string name="tts_engine_preference_title" msgid="1183116842356275061">"Նախընտրելի համակարգը"</string>
     <string name="tts_engine_settings_title" msgid="4079757915136562358">"Համակարգի կարգավորումները"</string>
     <string name="tts_sliders_title" msgid="1927481069989092278">"Խոսքի արագությունը և բարձրությունը"</string>
     <string name="tts_engine_section_title" msgid="7796486438271227076">"Համակարգ"</string>
@@ -2575,7 +2580,7 @@
     <string name="add_device_admin" msgid="1621152410207260584">"Ակտիվացնել այս սարքի ադմինիստրատորի հավելվածը"</string>
     <string name="device_admin_add_title" msgid="6097881332139146897">"Սարքի ադմինիստրատոր"</string>
     <string name="device_admin_warning" msgid="4421817419326480449">"Ադմինիստրատորի այս հավելվածի ակտիվացումը <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածին թույլ կտա կատարել հետևյալ գործողությունները`"</string>
-    <string name="device_admin_status" msgid="5424944611789040723">"Այս ադմինիստրատորն ակտիվ է և թույլ է տալիս <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածին կատարել հետևյալ գործողությունները`"</string>
+    <string name="device_admin_status" msgid="5424944611789040723">"Ադմինիստրատորի այս հավելվածը ակտիվ է և թույլ է տալիս <xliff:g id="APP_NAME">%1$s</xliff:g>-ին կատարել հետևյալ գործողությունները`"</string>
     <string name="profile_owner_add_title" msgid="735805919754362791">"Ակտիվացնե՞լ պրոֆիլների կառավարիչը:"</string>
     <string name="adding_profile_owner_warning" msgid="1284541194547382194">"Շարունակելու դեպքում օգտատերը կկառավարվի ձեր ադմինիստրատորի կողմից, որը, ձեր անձնական տվյալներից բացի, կկարողանա պահել նաև դրա հետ առնչվող տվյալները:\n\nՁեր ադմինիստրատորը կարող է վերահսկել և կառավարել կարգավորումները, մուտքը, հավելվածները և այս օգտատիրոջ հետ առնչվող տվյալները, ներառյալ ցանցային գործունեությունը և ձեր սարքի տեղադրության տվյալները:"</string>
     <string name="admin_disabled_other_options" msgid="8097063307730025707">"Ադմինիստրատորն անջատել է այլ ընտրանքները"</string>
@@ -2596,7 +2601,7 @@
     <string name="work_mode_label" msgid="6845849194740195757">"Աշխատանքային պրոֆիլ"</string>
     <string name="work_mode_on_summary" msgid="1682781113156323592">"Կառավարվում է ձեր կազմակերպության կողմից"</string>
     <string name="work_mode_off_summary" msgid="1688885392211178315">"Հավելվածներն ու ծանուցումներն անջատված են"</string>
-    <string name="remove_managed_profile_label" msgid="4625542553784793536">"Հեռացնել աշխատանքային դիտարկումը"</string>
+    <string name="remove_managed_profile_label" msgid="4625542553784793536">"Հեռացնել աշխատանքային պրոֆիլը"</string>
     <string name="background_data" msgid="8275750862371471171">"Հետնաշերտի տվյալներ"</string>
     <string name="background_data_summary" msgid="799640633948841990">"Ծրագրերը կարող են համաժամացնել, ուղարկել և ստանալ տվյալներ ցանկացած պահի"</string>
     <string name="background_data_dialog_title" msgid="8306650658158895976">"Կասեցնե՞լ հետնաշերտի տվյալները:"</string>
@@ -2710,7 +2715,7 @@
     <string name="data_usage_limit_editor_title" msgid="1687908662154108293">"Թրաֆիկի օգտագործման սահմանը"</string>
     <string name="data_usage_limit_dialog_title" msgid="8804760847110131518">"Սահմանափակել տվյալների օգտագործումը"</string>
     <string name="data_usage_limit_dialog_mobile" product="tablet" msgid="2000713577999830647">"Նշված սահմանաչափն անցնելու դեպքում պլանշետը կանջատի բջջային ինտերնետը։\n\nՔանի որ տվյալների օգտագործումը չափում է պլանշետը, իսկ օպերատորի հաշվարկները կարող են տարբերվել, խորհուրդ ենք տալիս նշել նախատեսվածից ցածր սահմանաչափ։"</string>
-    <string name="data_usage_limit_dialog_mobile" product="default" msgid="943546278705619205">"Նշված սահմանաչափն անցնելու դեպքում հեռախոսը կանջատի բջջային ինտերնետը։\n\nՕպերատորի վիճակագրությունը կարող է տարբերվել հեռախոսի տվյալներից, խորհուրդ ենք տալիս նշել նախատեսվածից ցածր սահմանաչափ։"</string>
+    <string name="data_usage_limit_dialog_mobile" product="default" msgid="943546278705619205">"Նշված սահմանաչափն անցնելու դեպքում հեռախոսում կանջատվի բջջային ինտերնետը։\n\nՕպերատորի վիճակագրությունը կարող է տարբերվել հեռախոսի տվյալներից, խորհուրդ ենք տալիս նշել նախատեսվածից ցածր սահմանաչափ։"</string>
     <string name="data_usage_restrict_background_title" msgid="3568746530413220844">"Սահմանափակե՞լ հետնաշերտի տվյալները:"</string>
     <string name="data_usage_restrict_background" msgid="995811034744808575">"Եթե սահմանափակեք բջջային ինտերնետի ֆոնային օգտագործումը, ապա որոշ հավելվածներ և ծառայություններ չեն աշխատի մինչև Wi‑Fi ցանցին միանալը:"</string>
     <string name="data_usage_restrict_background_multiuser" product="tablet" msgid="6032810839234864814">"Եթե սահմանափակեք բջջային ինտերնետի ֆոնային օգտագործումը, ապա որոշ հավելվածներ և ծառայություններ չեն աշխատի մինչև Wi‑Fi ցանցին միանալը:\n\nԱյս կարգավորումը վերաբերում է այս պլանշետի բոլոր օգտատերերին:"</string>
@@ -2742,7 +2747,7 @@
     <string name="vpn_ipsec_identifier" msgid="1230238784830362888">"IPSec նույնացուցիչ"</string>
     <string name="vpn_ipsec_secret" msgid="1531503910441962752">"IPSec նախորոշված բանալին"</string>
     <string name="vpn_ipsec_user_cert" msgid="2762078384595366852">"IPSec օգտատիրոջ վկայագիրը"</string>
-    <string name="vpn_ipsec_ca_cert" msgid="5537567128766402789">"IPSec CA վկայական"</string>
+    <string name="vpn_ipsec_ca_cert" msgid="5537567128766402789">"IPSec CA հավաստագիր"</string>
     <string name="vpn_ipsec_server_cert" msgid="3066696943831527934">"IPSec սերվերի վկայական"</string>
     <string name="vpn_show_options" msgid="7672984921872882859">"Ցույց տալ լրացուցիչ ընտրանքները"</string>
     <string name="vpn_search_domains" msgid="8469394307693909080">"DNS որոնման տիրույթներ"</string>
@@ -2789,7 +2794,7 @@
     <string name="vpn_always_on_summary" msgid="3639994551631437397">"VPN-ին միշտ կապակցված մնալ"</string>
     <string name="vpn_always_on_summary_not_supported" msgid="9077720997795965133">"Չի աջակցվում այս հավելվածում"</string>
     <string name="vpn_always_on_summary_active" msgid="8962619701962239088">"Միշտ միացված ընտրանքն ակտիվ է"</string>
-    <string name="vpn_require_connection" msgid="5413746839457797350">"Արգելափակել առանց VPN-ի կապակցումները"</string>
+    <string name="vpn_require_connection" msgid="5413746839457797350">"Արգելափակել առանց VPN-ի միացումները"</string>
     <string name="vpn_require_connection_title" msgid="8361434328767853717">"VPN միացում պահանջե՞լ։"</string>
     <string name="vpn_lockdown_summary" msgid="6770030025737770861">"Ընտրել VPN պրոֆիլ` այդ պրոֆիլին միշտ միացված լինելու համար: Ցանցային շրջանառությունը թույլատրված կլինի միայն VPN-ին միացված ժամանակ:"</string>
     <string name="vpn_lockdown_none" msgid="3789288793603394679">"Ոչ մեկը"</string>
@@ -2910,17 +2915,17 @@
     <string name="apps_with_restrictions_header" msgid="8656739605673756176">"Սահմանափակումներով ծրագրեր"</string>
     <string name="apps_with_restrictions_settings_button" msgid="5065896213467171744">"Ընդլայնել ծրագրի կարգավորումները"</string>
     <string name="nfc_payment_settings_title" msgid="5070077706735415291">"Հպել ու վճարել"</string>
-    <string name="nfc_payment_how_it_works" msgid="7607901964687787177">"Ինչպես է այն աշխատում"</string>
-    <string name="nfc_payment_no_apps" msgid="8844440783395420860">"Վճարեք հեռախոսի միջոցով խանութներում"</string>
-    <string name="nfc_payment_default" msgid="7869273092463612271">"Վճարման հիմնական հավելվածը"</string>
+    <string name="nfc_payment_how_it_works" msgid="7607901964687787177">"Ինչպես է դա աշխատում"</string>
+    <string name="nfc_payment_no_apps" msgid="8844440783395420860">"Խանութներում վճարեք հեռախոսի միջոցով"</string>
+    <string name="nfc_payment_default" msgid="7869273092463612271">"Վճարումների հիմնական հավելված"</string>
     <string name="nfc_payment_default_not_set" msgid="955804193510335338">"Կարգավորված չէ"</string>
     <string name="nfc_payment_app_and_desc" msgid="102312684211458190">"<xliff:g id="APP">%1$s</xliff:g> - <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="nfc_payment_use_default" msgid="3098724195746409476">"Օգտագործել կանխադրվածը"</string>
     <string name="nfc_payment_favor_default" msgid="7555356982142464260">"Միշտ"</string>
-    <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Բացի այն դեպքերից, երբ վճարումների այլ հավելված է բացված"</string>
+    <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Եթե ուրիշ վճարային հավելված բացված չէ"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"«Հպել ու վճարել» տերմինալում օգտագործել"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Վճարում տերմինալով"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Տեղադրեք վճարումների որևէ հավելված: Ապա պարզապես մոտեցրեք հեռախոսը հետևի մասով ցանկացած տերմինալի՝ առանց անհպում վճարման նշանը դեպի տերմինալը:"</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Կարգավորեք վճարային հավելվածը, ապա հեռախոսի հետևի մասով հպեք անհպում վճարման նշան ունեցող որևէ տերմինալի։"</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"Պարզ է"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"Ավելին..."</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"Սահմանե՞լ որպես նախընտրանք:"</string>
@@ -3018,7 +3023,7 @@
     <string name="sim_notification_title" msgid="2457890173055955672">"SIM քարտերը փոխարինվել են:"</string>
     <string name="sim_notification_summary" msgid="6421556454979313850">"Հպեք՝ կարգավորելու համար"</string>
     <string name="sim_pref_divider" msgid="4967718397875240190">"Օգտագործել SIM քարտը հետևյալի համար՝"</string>
-    <string name="sim_calls_ask_first_prefs_title" msgid="8209265235625420102">"Հարցնել ամեն անգամ"</string>
+    <string name="sim_calls_ask_first_prefs_title" msgid="8209265235625420102">"Ամեն անգամ հարցնել"</string>
     <string name="sim_selection_required_pref" msgid="8738591348923992419">"Ընտրեք SIM քարտը"</string>
     <string name="sim_selection_channel_title" msgid="5671915549529226023">"SIM քարտի ընտրություն"</string>
     <string name="dashboard_title" msgid="3343056553551876215">"Կարգավորումներ"</string>
@@ -3140,13 +3145,13 @@
     <string name="notification_unknown_sound_title" msgid="8043718667804838398">"Հավելվածի տրամադրված ձայնը"</string>
     <string name="notification_sound_default" msgid="2664544380802426260">"Ծանուցման կանխադրված ձայնը"</string>
     <string name="alarm_ringtone_title" msgid="6411326147408635902">"Զարթուցիչի կանխադրված ձայնը"</string>
-    <string name="vibrate_when_ringing_title" msgid="2757996559847126952">"Թրթռալ զանգերի ժամանակ"</string>
+    <string name="vibrate_when_ringing_title" msgid="2757996559847126952">"Թրթռալ զանգի ժամանակ"</string>
     <string name="other_sound_settings" msgid="5250376066099818676">"Այլ ձայներ"</string>
     <string name="dial_pad_tones_title" msgid="8877212139988655769">"Թվաշարի հնչերանգներ"</string>
     <string name="screen_locking_sounds_title" msgid="4407110895465866809">"Էկրանի կողպման ձայներ"</string>
     <string name="charging_sounds_title" msgid="5070437987230894287">"Լիցքավորման ձայներ և թրթռոց"</string>
     <string name="docking_sounds_title" msgid="2573137471605541366">"Միակցման ձայներ"</string>
-    <string name="touch_sounds_title" msgid="165237488496165652">"Հպման ձայներ"</string>
+    <string name="touch_sounds_title" msgid="165237488496165652">"Հպում"</string>
     <string name="vibrate_on_touch_title" msgid="6360155469279157684">"Թրթռոց հպելիս"</string>
     <string name="vibrate_on_touch_summary" msgid="5504424764028676043">"Թրթռալ՝ կոճակները, ստեղները սեղմելու և այլ գործողությունների դեպքում"</string>
     <string name="dock_audio_media_title" msgid="1859521680502040781">"Նվագարկել միակցիչի բարձրախոսով"</string>
@@ -3209,8 +3214,8 @@
     <string name="zen_mode_block_effect_sound" msgid="1499243540186357631">"Անջատել ձայնը և թրթռոցը"</string>
     <string name="zen_mode_block_effect_intent" msgid="5666951244667422668">"Չմիացնել էկրանը"</string>
     <string name="zen_mode_block_effect_light" msgid="8679333758037487644">"Չմիացնել թարթող լույսը"</string>
-    <string name="zen_mode_block_effect_peek" msgid="6075662813575910221">"Չցուցադրել էկրանին հայտնվող ծանուցումներ"</string>
-    <string name="zen_mode_block_effect_status" msgid="6516614225115681068">"Թաքցնել կարգավիճակի գոտու պատկերակները էկրանի վերևից"</string>
+    <string name="zen_mode_block_effect_peek" msgid="6075662813575910221">"Հավելվածների վրայից չցուցադրել ծանուցումներ"</string>
+    <string name="zen_mode_block_effect_status" msgid="6516614225115681068">"Թաքցնել կարգավիճ․ գոտու պատկերակները էկրանի վերևից"</string>
     <string name="zen_mode_block_effect_badge" msgid="3891743027347075136">"Թաքցնել ծանուց․ կետիկները հավելվ․ պատկերակներից"</string>
     <string name="zen_mode_block_effect_ambient" msgid="6382013125863616197">"Ցույց չտալ ծանուցումները"</string>
     <string name="zen_mode_block_effect_list" msgid="6081548478844912181">"Թաքցնել ծանուցումների ցանկից"</string>
@@ -3239,7 +3244,7 @@
     <string name="zen_mode_sound_summary_off_with_info" msgid="3910718455243440265">"Անջատված է/<xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="zen_mode_sound_summary_off" msgid="2800265178411749309">"Անջատված է"</string>
     <string name="zen_mode_sound_summary_on" msgid="6964666541479146310">"Միացված է"</string>
-    <string name="zen_mode_duration_summary_always_prompt" msgid="7642321938427056823">"Հարցնել ամեն անգամ (եթե ավտոմատ չմիանա)"</string>
+    <string name="zen_mode_duration_summary_always_prompt" msgid="7642321938427056823">"Ամեն անգամ հարցնել (եթե ավտոմատ չմիանա)"</string>
     <string name="zen_mode_duration_summary_forever" msgid="4563938129424903030">"Մինչև չանջատեք (եթե ավտոմատ չմիանա)"</string>
     <plurals name="zen_mode_duration_summary_time_hours" formatted="false" msgid="8872000022033647725">
       <item quantity="one"><xliff:g id="NUM_HOURS">%d</xliff:g> ժամ (եթե ավտոմատ չմիանա)</item>
@@ -3272,7 +3277,7 @@
     <string name="zen_onboarding_settings" msgid="1416466597876383322">"Կարգավորումներ"</string>
     <string name="zen_onboarding_new_setting_title" msgid="3622673375041304362">"Ամբողջությամբ անջատել ծանուցումները"</string>
     <string name="zen_onboarding_current_setting_title" msgid="2560330551761407563">"Անջատել ծանուցումների ձայնը"</string>
-    <string name="zen_onboarding_new_setting_summary" msgid="8264430315983860075">"Ծանուցումներն ամբողջությամբ կանջատվեն։ Դուք կստանաք միայն աստղանշված կոնտակտներից և կրկնվող զանգեր։"</string>
+    <string name="zen_onboarding_new_setting_summary" msgid="8264430315983860075">"Ծանուցումներն ամբողջությամբ կանջատվեն։ Զանգեր կստանաք միայն աստղանշված և հաճախակի զանգող բաժանորդներից։"</string>
     <string name="zen_onboarding_current_setting_summary" msgid="3569246708507270821">"(ընթացիկ կարգավորումը)"</string>
     <string name="zen_onboarding_dnd_visual_disturbances_header" msgid="7584229011611927613">"Փոփոխե՞լ «Չանհանգստացնել» ռեժիմի ծանուցումների կարգավորումները"</string>
     <string name="sound_work_settings" msgid="4140215240360927923">"Աշխատանքային պրոֆիլի ձայները"</string>
@@ -3316,7 +3321,7 @@
     <string name="notification_pulse_title" msgid="4861418327614907116">"Թարթող լույս"</string>
     <string name="lock_screen_notifications_title" msgid="6889072265118747835">"Կողպէկրանին"</string>
     <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"Երբ պրոֆիլն արգելափակված է"</string>
-    <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Ցուցադրել ծանուցումներն ամբողջությամբ"</string>
+    <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Ծանուցումները ցույց տալ ամբողջությամբ"</string>
     <string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"Թաքցնել գաղտնի տվյալները"</string>
     <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"Չցուցադրել ծանուցումներ"</string>
     <string name="lock_screen_notifications_interstitial_message" msgid="4230189215124387818">"Ընտրեք ծանուցումների ցուցադրման ռեժիմը կողպված սարքում։"</string>
@@ -3385,7 +3390,7 @@
     <string name="picture_in_picture_app_detail_title" msgid="3916189052657425936">"Նկար նկարի մեջ"</string>
     <string name="picture_in_picture_app_detail_switch" msgid="747422998967185418">"Թույլատրել «Նկար նկարի մեջ» ռեժիմը"</string>
     <string name="picture_in_picture_app_detail_summary" msgid="918632751775525347">"Թույլատրել հավելվածին ստեղծել նկար նկարի մեջ պատուհան, երբ հավելվածը բաց է կամ այն օգտագործելուց հետո (օրինակ՝ տեսանյութի դիտումը շարունակելու համար): Այս պատուհանը ցուցադրվում է ձեր կողմից օգտագործվող այլ հավելվածների վրայից:"</string>
-    <string name="manage_zen_access_title" msgid="3058206309728524196">"«Չանհանգստացնել» գործառույթի հասանելիությունը"</string>
+    <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>
@@ -3474,7 +3479,7 @@
     <string name="summary_range_verbal_combination" msgid="8799629589758200970">"<xliff:g id="START">%1$s</xliff:g>-ից <xliff:g id="END">%2$s</xliff:g>"</string>
     <string name="zen_mode_calls" msgid="1844534357711539325">"Թույլատրել զանգերը"</string>
     <string name="zen_mode_calls_title" msgid="2024387562355793661">"Զանգեր"</string>
-    <string name="zen_mode_calls_footer" msgid="6319824006810688433">"Համոզվելու, որ թույլատրված զանգերը կազդանշվեն, ստուգեք՝ արդյոք սարքում միացված է զանգը կամ թրթռոցը, թե լռեցված է:"</string>
+    <string name="zen_mode_calls_footer" msgid="6319824006810688433">"Համոզվելու, որ թույլատրված զանգերը կազդանշվեն, ստուգեք՝ արդյոք սարքում միացված է զանգի ձայնը կամ թրթռոցը, թե լռեցված է:"</string>
     <string name="zen_mode_custom_calls_footer" msgid="7329231648477682337">"«<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>» կանոնի համար մուտքային զանգերն արգելափակված են: Փոխեք կարգավորումները, որպեսզի ձեր մտերիմները և այլ կոնտակտներ կարողանան կապվել ձեզ հետ:"</string>
     <string name="zen_mode_starred_contacts_title" msgid="7099621384597127058">"Աստղանշված կոնտակտներ"</string>
     <plurals name="zen_mode_starred_contacts_summary_additional_contacts" formatted="false" msgid="1904181007981570805">
@@ -3482,13 +3487,13 @@
       <item quantity="other">Եվս <xliff:g id="NUM_PEOPLE">%d</xliff:g> կոնտակտ</item>
     </plurals>
     <string name="zen_mode_messages" msgid="2908722562188394107">"Թույլատրել SMS"</string>
-    <string name="zen_mode_messages_footer" msgid="5048951937714668561">"Համոզվելու, որ թույլատրված հաղորդագրությունները կազդանշվեն, ստուգեք՝ արդյոք սարքում միացված է զանգը կամ թրթռոցը, թե լռեցված է:"</string>
+    <string name="zen_mode_messages_footer" msgid="5048951937714668561">"Համոզվելու, որ թույլատրված հաղորդագրությունները կազդանշվեն, ստուգեք՝ արդյոք սարքում միացված է զանգի ձայնը կամ թրթռոցը, թե լռեցված է:"</string>
     <string name="zen_mode_custom_messages_footer" msgid="5566007423100361691">"«<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>» կանոնի համար մուտքային հաղորդագրություններն արգելափակված են: Փոխեք կարգավորումները, որպեսզի ձեր մտերիմները և այլ կոնտակտներ կարողանան կապվել ձեզ հետ:"</string>
     <string name="zen_mode_messages_title" msgid="786261471294055181">"SMS, MMS և հաղորդագրման հավելվածներ"</string>
     <string name="zen_mode_from_anyone" msgid="7778836826814131083">"Բոլորից"</string>
     <string name="zen_mode_from_contacts" msgid="267034158294332688">"Միայն կոնտակտներից"</string>
     <string name="zen_mode_from_starred" msgid="7349984569117392260">"Միայն աստղանշված կոնտակտներից"</string>
-    <string name="zen_calls_summary_starred_repeat" msgid="9191394641577678207">"Աստղանշված կոնտակտներից և կրկնվող զանգեր"</string>
+    <string name="zen_calls_summary_starred_repeat" msgid="9191394641577678207">"Աստղանշված և հաճախակի զանգող բաժանորդներից"</string>
     <string name="zen_calls_summary_contacts_repeat" msgid="7747592096431111510">"Կոնտակտներից և կրկնվող զանգեր"</string>
     <string name="zen_calls_summary_repeat_only" msgid="8839703337232747964">"Միայն կրկնվող զանգեր"</string>
     <string name="zen_mode_from_none" msgid="7683889985618637010">"Ոչ ոքից"</string>
@@ -3504,7 +3509,7 @@
     <string name="zen_mode_reminders_list" msgid="7347061314032326677">"հիշեցումներ"</string>
     <string name="zen_mode_events" msgid="5784076928339534984">"Թույլատրել միջոցառումները"</string>
     <string name="zen_mode_bypassing_apps" msgid="3080739479028713449">"Թույլատրել հավելվածներին փոխել «Չանհանգստացնել» ռեժիմի կարգավորումները"</string>
-    <string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"Հավելվածների ընդլայնումներ"</string>
+    <string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"Հավելվածների բացառություններ"</string>
     <plurals name="zen_mode_bypassing_apps_subtext" formatted="false" msgid="8723144434730871572">
       <item quantity="one"><xliff:g id="NUMBER">%1$d</xliff:g> հավելվածի ծանուցումները կարող են փոխել «Չանհանգստացնել» ռեժիմի կարգավորումները</item>
       <item quantity="other"><xliff:g id="NUMBER">%1$d</xliff:g> հավելվածի ծանուցումները կարող են փոխել «Չանհանգստացնել» ռեժիմի կարգավորումները</item>
@@ -3625,7 +3630,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> լրացուցիչ թույլտվություն</item>
     </plurals>
     <string name="runtime_permissions_summary_no_permissions_granted" msgid="3477934429220828771">"Թույլտվություններ չեն շնորհվել"</string>
-    <string name="runtime_permissions_summary_no_permissions_requested" msgid="3901636077467389637">"Թույլտվություններ չեն հայցվել"</string>
+    <string name="runtime_permissions_summary_no_permissions_requested" msgid="3901636077467389637">"Հավելվածը թույլտվություններ չի պահանջել"</string>
     <string name="filter_all_apps" msgid="4042756539846043675">"Բոլոր հավելվածները"</string>
     <string name="filter_enabled_apps" msgid="5888459261768538489">"Տեղադրված հավելվածներ"</string>
     <string name="filter_instant_apps" msgid="8087483282854072366">"Ակնթարթային հավելվածները"</string>
@@ -3654,7 +3659,7 @@
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> հավելված կարող է աջակցվող հղումներ բացել</item>
     </plurals>
     <string name="app_link_open_always" msgid="7723587434377688415">"Բացել այս հավելվածով"</string>
-    <string name="app_link_open_ask" msgid="4054678686331517561">"Հարցնել ամեն անգամ"</string>
+    <string name="app_link_open_ask" msgid="4054678686331517561">"Ամեն անգամ հարցնել"</string>
     <string name="app_link_open_never" msgid="5774359835242754350">"Չբացել այս հավելվածով"</string>
     <string name="default_apps_title" msgid="3848048391400989931">"Կանխադրված"</string>
     <string name="default_for_work" msgid="7290411716804495366">"Կանխադրված՝ աշխատանքի համար"</string>
@@ -3706,8 +3711,8 @@
     <string name="high_power_off" msgid="5906679734326490426">"Մարտկոցի սպառման օպտիմալացում"</string>
     <string name="high_power_system" msgid="739584574711292753">"Մարտկոցի օպտիմալացումը հասանելի չէ"</string>
     <string name="high_power_desc" msgid="333756885680362741">"Մի կիրառեք մարտկոցի օպտիմալացումը: Մարտկոցի լիցքը կարող է ավելի արագ սպառվել:"</string>
-    <string name="high_power_prompt_title" msgid="2805745781720454052">"Թույլատրե՞լ հավելվածին միշտ աշխատել ֆոնում:"</string>
-    <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածին ֆոնում միշտ աշխատելու թույլատվություն տրամադրելու դեպքում մարտկոցի օգտագործման ժամանակը կարող է նվազել: \n\nԱյս կարգավորումը կարող եք հետագայում փոխել՝ անցնելով Կարգավորումներ &gt; Հավելվածներ և ծանուցումներ:"</string>
+    <string name="high_power_prompt_title" msgid="2805745781720454052">"Թույլ տա՞լ հավելվածի աշխատանքը ֆոնային ռեժիմում"</string>
+    <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածին ֆոնային ռեժիմում աշխատելու թույլատվություն տրամադրելու դեպքում մարտկոցը կարող է ավելի արագ սպառվել: \n\nԱյս կարգավորումը կարող եք հետագայում փոխել՝ անցնելով Կարգավորումներ &gt; Հավելվածներ և ծանուցումներ:"</string>
     <string name="battery_summary" msgid="4345690800899981339">"Վերջին լրիվ լիցքավորումից հետո օգտագործվել է <xliff:g id="PERCENTAGE">%1$s</xliff:g>"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"Սնուցման կառավարում"</string>
     <string name="no_battery_summary" msgid="4105932628367471314">"Վերջին լրիվ լիցքավորումից հետո մարտկոցը չի օգտագործվել"</string>
@@ -3737,7 +3742,7 @@
     <string name="usb_pref" msgid="6194821550693495068">"USB"</string>
     <string name="usb_preference" msgid="7092987095048592826">"USB-ի կարգավորումներ"</string>
     <string name="usb_control_title" msgid="2379698856760894768">"USB-ն վերահսկող սարքը"</string>
-    <string name="usb_control_host" msgid="193292043691034178">"Կապված սարք"</string>
+    <string name="usb_control_host" msgid="193292043691034178">"Միացված սարք"</string>
     <string name="usb_control_device" msgid="9154790265254725254">"Այս սարքը"</string>
     <string name="usb_switching" msgid="1230386065163529904">"Փոխարկում…"</string>
     <string name="usb_switching_failed" msgid="6857722544186145439">"Չհաջողվեց փոխարկել"</string>
@@ -3756,10 +3761,10 @@
     <string name="assist_access_context_title" msgid="2274614501747710439">"Օգտվել էկրանի տեքստային բովանդակությունից"</string>
     <string name="assist_access_context_summary" msgid="5867997494395842785">"Թույլ տալ օգնական հավելվածին օգտվել էկրանի տեքստային բովանդակությունից"</string>
     <string name="assist_access_screenshot_title" msgid="1991014038776117688">"Օգտագործել սքրինշոթը"</string>
-    <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Թույլ տալ օգնական հավելվածին օգտվել էկրանի պատկերներից"</string>
+    <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Թույլ տալ օգնական հավելվածին օգտագործել էկրանի պատկերը"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"Էկրանի թարթում"</string>
     <string name="assist_flash_summary" msgid="6697095786317559129">"Երբ օգնական հավելվածը բացում է տեքստը Էկրանից կամ էկրանի պատկերից, էկրանի եզրագծերը թարթում են"</string>
-    <string name="assist_footer" msgid="7030121180457472165">"Օգնական հավելվածներն աշխատում են էկրանին առկա տեղեկությունների հետ: Որոշ հավելվածներ աջակցում են և գործարկիչի, և ձայնային ներածման ծառայությունները, ինչը ավելի լայն հնարավորություններ է տալիս ձեզ:"</string>
+    <string name="assist_footer" msgid="7030121180457472165">"Օգնական հավելվածներն աշխատում են էկրանին առկա տեղեկությունների հետ: Որոշ հավելվածներ աջակցում են և՛ գործարկիչը, և՛ ձայնային ներածումը, ինչը ավելի լայն հնարավորություններ է տալիս ձեզ:"</string>
     <string name="average_memory_use" msgid="5333366040118953945">"Հիշողության միջին օգտագործումը"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"Առավելագույն օգտագործումը"</string>
     <string name="memory_usage" msgid="7963253555330830906">"Հիշողության օգտագործումը"</string>
@@ -3828,7 +3833,7 @@
     <string name="screen_zoom_title" msgid="164369086350486104">"Ցուցադրման չափը"</string>
     <string name="screen_zoom_short_summary" msgid="5508079362742276703">"Տարրերի մեծացում և փոքրացում"</string>
     <string name="screen_zoom_keywords" msgid="8358462497896524092">"ցուցադրման խտություն, էկրանի մասշտաբ, մասշտաբ, մասշտաբավորում"</string>
-    <string name="screen_zoom_summary" msgid="5294003755961312560">"Էկրանի տարրերի մեծացում կամ փոքրացում։ Այս կարգավորումը փոխելուց հետո որոշ հավելվածներ կարող են փոխել իրենց դիրքը:"</string>
+    <string name="screen_zoom_summary" msgid="5294003755961312560">"Մեծացրեք կամ փոքրացրեք էկրանին ցուցադրվող տարրերը։ Այս կարգավորումը փոխելուց հետո որոշ հավելվածներ կարող են փոխել իրենց դիրքը էկրանին։"</string>
     <string name="screen_zoom_preview_title" msgid="2924312934036753091">"Նախադիտում"</string>
     <string name="screen_zoom_make_smaller_desc" msgid="1374501139722916729">"Փոքրացնել"</string>
     <string name="screen_zoom_make_larger_desc" msgid="5306684807895846141">"Մեծացնել"</string>
@@ -3866,7 +3871,7 @@
     <string name="backup_disabled" msgid="6941165814784765643">"Պահուստավորումն անջատված է"</string>
     <string name="android_version_summary" msgid="2192751442789395445">"Տեղադրվել է Android <xliff:g id="VERSION">%1$s</xliff:g> տարբերակը"</string>
     <string name="android_version_pending_update_summary" msgid="3554543810520655076">"Հասանելի է նոր տարբերակը"</string>
-    <string name="disabled_by_policy_title" msgid="1238318274952958846">"Գործողությունը չի թույլատրվում"</string>
+    <string name="disabled_by_policy_title" msgid="1238318274952958846">"Գործողությունն արգելված է"</string>
     <string name="disabled_by_policy_title_adjust_volume" msgid="7094547090629203316">"Հնարավոր չէ փոխել ձայնի ուժգնությունը"</string>
     <string name="disabled_by_policy_title_outgoing_calls" msgid="3805836913095496278">"Զանգելն արգելված է"</string>
     <string name="disabled_by_policy_title_sms" msgid="1453236584236681105">"SMS-ների ուղարկումն արգելված է"</string>
@@ -4066,14 +4071,14 @@
     <string name="premium_sms_warning" msgid="7604011651486294515">"Վճարովի SMS-ները կարող են լրացուցիչ ծախսեր առաջացնել: Հավելվածին թույտվություն տալու դեպքում կկարողանաք դրա միջոցով վճարովի SMS-ներ ուղարկել։"</string>
     <string name="premium_sms_access" msgid="4550027460595822851">"Վճարովի SMS"</string>
     <string name="bluetooth_disabled" msgid="6588102116819268238">"Անջատված է"</string>
-    <string name="bluetooth_connected_summary" msgid="439920840053965217">"Կապակցված է <xliff:g id="ID_1">%1$s</xliff:g>-ին"</string>
-    <string name="bluetooth_connected_multiple_devices_summary" msgid="596205630653123250">"Կապակցված է բազմակի շարժական սարքերի"</string>
+    <string name="bluetooth_connected_summary" msgid="439920840053965217">"Միացված է <xliff:g id="ID_1">%1$s</xliff:g>-ին"</string>
+    <string name="bluetooth_connected_multiple_devices_summary" msgid="596205630653123250">"Միացված է բազմակի շարժական սարքերի"</string>
     <string name="demo_mode" msgid="3831081808592541104">"Համակարգի միջերեսի ցուցադրական ռեժիմ"</string>
     <string name="dark_ui_mode" msgid="703844190192599217">"Թեմա"</string>
     <string name="dark_ui_mode_title" msgid="8774932716427742413">"Ընտրել թեմա"</string>
     <string name="dark_ui_settings_light_summary" msgid="5219102347744462812">"Այս կարգավորումը կիրառվում է նաև հավելվածների համար"</string>
     <string name="dark_ui_settings_dark_summary" msgid="7042737828943784289">"Աջակցվող հավելվածները ևս կանցնեն մուգ թեմային"</string>
-    <string name="quick_settings_developer_tiles" msgid="7423485925757678719">"Մշակողի արագ կարգավորման սալիկներ"</string>
+    <string name="quick_settings_developer_tiles" msgid="7423485925757678719">"Ծրագրավորողի արագ կարգավորման սալիկներ"</string>
     <string name="winscope_trace_quick_settings_title" msgid="940971040388411374">"Winscope-ի հետագծում"</string>
     <string name="sensors_off_quick_settings_title" msgid="3655699045300438902">"Տվիչներն անջատված են"</string>
     <string name="managed_profile_settings_title" msgid="4340409321523532402">"Աշխատանքային պրոֆիլի կարգավորումներ"</string>
@@ -4118,18 +4123,18 @@
     <string name="ambient_display_title" product="default" msgid="6785677099744344088">"Կրկնակի հպել՝ հեռախոսը ստուգելու համար"</string>
     <string name="ambient_display_title" product="tablet" msgid="1106285490888683613">"Կրկնակի հպեք՝ պլանշետը ստուգելու համար"</string>
     <string name="ambient_display_title" product="device" msgid="5064644474876041478">"Կրկնակի հպեք՝ սարքը ստուգելու համար"</string>
-    <string name="ambient_display_summary" msgid="4882910328216411109">"Ժամանակը, ծանուցումները և այլ տեղեկություններ տեսնելու համար կրկնակի հպել էկրանին:"</string>
+    <string name="ambient_display_summary" msgid="4882910328216411109">"Ժամը, ծանուցումները և այլ տեղեկություններ տեսնելու համար կրկնակի հպել էկրանին:"</string>
     <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"Բարձրացնել՝ հեռախոսը ստուգելու համար"</string>
     <string name="ambient_display_pickup_title" product="tablet" msgid="1555456400210301959">"Բարձրացրեք՝ պլանշետը ստուգելու համար"</string>
     <string name="ambient_display_pickup_title" product="device" msgid="2480126522988135037">"Բարձրացրեք՝ սարքը ստուգելու համար"</string>
     <string name="ambient_display_wake_screen_title" msgid="3376988352851077102">"Անջատել էկրանի քնի ռեժիմը"</string>
-    <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"Ժամանակը, ծանուցումները և այլ տեղեկություններ տեսնելու համար վերցնել հեռախոսը:"</string>
-    <string name="ambient_display_pickup_summary" product="tablet" msgid="1077745287100012928">"Ժամանակը, ծանուցումները և այլ տեղեկություններ տեսնելու համար վերցնել պլանշետը:"</string>
-    <string name="ambient_display_pickup_summary" product="device" msgid="404199660076598026">"Ժամանակը, ծանուցումները և այլ տեղեկություններ տեսնելու համար վերցնել սարքը:"</string>
+    <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"Ժամը, ծանուցումները և այլ տեղեկություններ տեսնելու համար վերցնել հեռախոսը:"</string>
+    <string name="ambient_display_pickup_summary" product="tablet" msgid="1077745287100012928">"Ժամը, ծանուցումները և այլ տեղեկություններ տեսնելու համար վերցնել պլանշետը:"</string>
+    <string name="ambient_display_pickup_summary" product="device" msgid="404199660076598026">"Ժամը, ծանուցումները և այլ տեղեկություններ տեսնելու համար վերցնել սարքը:"</string>
     <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"Հպել՝ հեռախոսը ստուգելու համար"</string>
     <string name="ambient_display_tap_screen_title" product="tablet" msgid="6434521782016864148">"Հպեք՝ պլանշետը ստուգելու համար"</string>
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"Հպեք՝ սարքը ստուգելու համար"</string>
-    <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"Ժամանակը, ծանուցումները և այլ տեղեկություններ տեսնելու համար կրկնակի հպեք էկրանին:"</string>
+    <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"Ժամը, ծանուցումները և այլ տեղեկություններ տեսնելու համար կրկնակի հպեք էկրանին:"</string>
     <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"Ծանուցումները դիտելու համար օգտագործել մատնահետքերի սկաները"</string>
     <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"Մատնահետքերի սկաներ"</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"Ծանուցումները տեսնելու համար՝ մատը սահեցրեք ներքև հեռախոսի հետևի մասում գտնվող մատնահետքերի սկաների վրա"</string>
@@ -4243,7 +4248,7 @@
     <string name="launch_instant_app" msgid="5251693061228352333">"Բացել"</string>
     <string name="game_storage_settings" msgid="6856911551799175914">"Խաղեր"</string>
     <string name="audio_files_title" msgid="3073879661731363935">"Աուդիո ֆայլեր"</string>
-    <string name="app_info_storage_title" msgid="6643391804949509308">"Օգտագործած տարածքը"</string>
+    <string name="app_info_storage_title" msgid="6643391804949509308">"Օգտագործված տարածք"</string>
     <string name="webview_uninstalled_for_user" msgid="3407952144444040557">"(հեռացված է <xliff:g id="USER">%s</xliff:g> օգտատիրոջ համար)"</string>
     <string name="webview_disabled_for_user" msgid="8057805373224993504">"(անջատված է <xliff:g id="USER">%s</xliff:g> օգտատիրոջ համար)"</string>
     <string name="autofill_app" msgid="3990765434980280073">"Ինքնալրացման ծառայություն"</string>
@@ -4305,7 +4310,7 @@
     <string name="change_wifi_state_title" msgid="5140754955787584174">"Wi-Fi-ի կառավարում"</string>
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"Թույլ տվեք հավելվածին կառավարել Wi-Fi-ը"</string>
     <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"Թույլ տվեք այս հավելվածին միացնել և անջատել Wi-Fi-ը, գտնել Wi-Fi ցանցեր և միանալ դրանց, ավելացնել և հեռացնել ցանցեր, միացնել միայն տեղային թեժ կետ"</string>
-    <string name="media_output_title" msgid="8710632337456601848">"Միացնել…"</string>
+    <string name="media_output_title" msgid="8710632337456601848">"Որտեղ նվագարկել"</string>
     <string name="media_output_default_summary" msgid="3159237976830415584">"Այս սարքը"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"Հեռախոս"</string>
     <string name="media_output_summary" product="tablet" msgid="6672024060360538526">"Պլանշետ"</string>
@@ -4318,10 +4323,10 @@
     <string name="battery_suggestion_title" product="device" msgid="765005476863631528">"Երկարացրեք սարքի մարտկոցի աշխատաժամանակը"</string>
     <string name="battery_suggestion_title" product="default" msgid="3295786171830183688">"Երկարացրեք հեռախոսի մարտկոցի աշխատաժամանակը"</string>
     <string name="battery_suggestion_summary" msgid="2669070349482656490"></string>
-    <string name="gesture_prevent_ringing_screen_title" msgid="4173494225145223638">"Չզնգալ"</string>
-    <string name="gesture_prevent_ringing_title" msgid="8827963588425673557">"Սնուցման և ձայնի բարձրացման կոճակների միաժամանակ սեղմումը՝"</string>
-    <string name="gesture_prevent_ringing_sound_title" msgid="8642330448721033641">"Զնգոցը կանխելու դյուրանցում"</string>
-    <string name="prevent_ringing_option_vibrate" msgid="6456505293904544108">"Թրթռոց"</string>
+    <string name="gesture_prevent_ringing_screen_title" msgid="4173494225145223638">"Զանգի ձայնի անջատում"</string>
+    <string name="gesture_prevent_ringing_title" msgid="8827963588425673557">"Սնուցման և ձայնի բարձրացման կոճակները միաժամանակ սեղմելու դեպքում"</string>
+    <string name="gesture_prevent_ringing_sound_title" msgid="8642330448721033641">"Զանգի ձայնի արագ անջատում"</string>
+    <string name="prevent_ringing_option_vibrate" msgid="6456505293904544108">"Թրթռալ"</string>
     <string name="prevent_ringing_option_mute" msgid="53662688921253613">"Անջատել ձայնը"</string>
     <string name="prevent_ringing_option_none" msgid="1450985763137666231">"Ոչինչ չանել"</string>
     <string name="prevent_ringing_option_vibrate_summary" msgid="7961818570574683926">"Միացված է (թրթռոց)"</string>
@@ -4384,7 +4389,7 @@
     <string name="mobile_data_settings_summary_auto_switch" msgid="3665863214578471494">"Հեռախոսն ավտոմատ կանցնի այս օպերատորին, երբ այն հասանելի լինի"</string>
     <string name="calls_preference" msgid="2076353032705811243">"Զանգերի կարգավորում"</string>
     <string name="sms_preference" msgid="8449270011976880">"SMS-ների կարգավորում"</string>
-    <string name="calls_and_sms_ask_every_time" msgid="2776167541223210738">"Հարցնել ամեն անգամ"</string>
+    <string name="calls_and_sms_ask_every_time" msgid="2776167541223210738">"Ամեն անգամ հարցնել"</string>
     <string name="mobile_network_summary_add_a_network" msgid="5408745221357144009">"Ավելացնել ցանց"</string>
     <plurals name="mobile_network_summary_count" formatted="false" msgid="6222822873390636020">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> SIM քարտ</item>
@@ -4472,7 +4477,7 @@
     <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"Հեռացնե՞լ առաջարկը:"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"Առաջարկությունը հեռացվեց"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"Հետարկել"</string>
-    <string name="low_storage_summary" msgid="4562224870189133400">"Բավարար տարածք չկա՝ <xliff:g id="PERCENTAGE">%1$s</xliff:g> օգտագործված – <xliff:g id="FREE_SPACE">%2$s</xliff:g> ազատ"</string>
+    <string name="low_storage_summary" msgid="4562224870189133400">"Ազատ տեղը քիչ է՝ <xliff:g id="PERCENTAGE">%1$s</xliff:g> օգտագործված – <xliff:g id="FREE_SPACE">%2$s</xliff:g> ազատ"</string>
     <string name="contextual_card_feedback_send" msgid="8698649023854350623">"Կարծիք հայտնել"</string>
     <string name="contextual_card_feedback_confirm_message" msgid="3987973028353264878">"Ուզո՞ւմ եք կարծիք հայտնել այս առաջարկության մասին"</string>
     <string name="copyable_slice_toast" msgid="1357518174923789947">"<xliff:g id="COPY_CONTENT">%1$s</xliff:g>՝ պատճենվեց սեղմատախտակին:"</string>
diff --git a/tests/CarDeveloperOptions/res/values-in/arrays.xml b/tests/CarDeveloperOptions/res/values-in/arrays.xml
index 1ef5224..0c81b79 100644
--- a/tests/CarDeveloperOptions/res/values-in/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-in/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"jalankan di latar belakang"</item>
     <item msgid="6423861043647911030">"volume aksesibilitas"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Lokasi"</item>
+    <item msgid="6656077694190491067">"Lokasi"</item>
+    <item msgid="8790228218278477369">"Lokasi"</item>
+    <item msgid="7836406246005211990">"Getar"</item>
+    <item msgid="3951439024549922598">"Membaca kontak"</item>
+    <item msgid="8802152411647068">"Ubah kontak"</item>
+    <item msgid="229544934599698735">"Baca log panggilan"</item>
+    <item msgid="7396102294405899613">"Ubah log panggilan"</item>
+    <item msgid="3597797992398484655">"Baca kalender"</item>
+    <item msgid="2705975774250907343">"Ubah kalender"</item>
+    <item msgid="4668747371441932697">"Lokasi"</item>
+    <item msgid="1487578921720243646">"Notifikasi postingan"</item>
+    <item msgid="4636080349724146638">"Lokasi"</item>
+    <item msgid="673510900286463926">"Telepon"</item>
+    <item msgid="542083422784609790">"Baca SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Tulis SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Terima SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Terima SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Terima SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Terima SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Kirim SMS/MMS"</item>
+    <item msgid="4726682243833913568">"Baca SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Tulis SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Ubah setelan"</item>
+    <item msgid="8705854389991425629">"Gambar di atas"</item>
+    <item msgid="5861356020344153651">"Akses notifikasi"</item>
+    <item msgid="78432174621628659">"Kamera"</item>
+    <item msgid="3986116419882154794">"Rekam audio"</item>
+    <item msgid="4516840825756409490">"Putar audio"</item>
+    <item msgid="6811712502798183957">"Baca papan klip"</item>
+    <item msgid="2780369012602289114">"Ubah papan klip"</item>
+    <item msgid="2331359440170850868">"Tombol media"</item>
+    <item msgid="6133599737122751231">"Fokus audio"</item>
+    <item msgid="6844485713404805301">"Volume utama"</item>
+    <item msgid="1600379420669104929">"Volume suara"</item>
+    <item msgid="6296768210470214866">"Volume dering"</item>
+    <item msgid="510690696071629241">"Volume media"</item>
+    <item msgid="406861638631430109">"Volume alarm"</item>
+    <item msgid="4715864795872233884">"Volume notifikasi"</item>
+    <item msgid="2311478519251301183">"Volume bluetooth"</item>
+    <item msgid="5133991377896747027">"Tetap aktif"</item>
+    <item msgid="2464189519136248621">"Lokasi"</item>
+    <item msgid="2062677934050803037">"Lokasi"</item>
+    <item msgid="1735171933192715957">"Dapatkan statistik penggunaan"</item>
+    <item msgid="1014093788778383554">"Bisukan/suarakan mikrofon"</item>
+    <item msgid="4199297950608622850">"Tampilkan seranta"</item>
+    <item msgid="2527962435313398821">"Media proyek"</item>
+    <item msgid="5117506254221861929">"Aktifkan VPN"</item>
+    <item msgid="8291198322681891160">"Tulis wallpaper"</item>
+    <item msgid="7106921284621230961">"Bantu struktur"</item>
+    <item msgid="4496533640894624799">"Bantu screenshot"</item>
+    <item msgid="2598847264853993611">"Baca status telepon"</item>
+    <item msgid="9215610846802973353">"Tambahkan pesan suara"</item>
+    <item msgid="9186411956086478261">"Gunakan sip"</item>
+    <item msgid="6884763100104539558">"Proses panggilan keluar"</item>
+    <item msgid="125513972170580692">"Sidik jari"</item>
+    <item msgid="2556071024281275619">"Sensor tubuh"</item>
+    <item msgid="617168514928339387">"Baca siaran sel"</item>
+    <item msgid="7134693570516523585">"Lokasi palsu"</item>
+    <item msgid="7224489175375229399">"Baca penyimpanan"</item>
+    <item msgid="8472735063903258202">"Tulis penyimpanan"</item>
+    <item msgid="4069276819909595110">"Aktifkan layar"</item>
+    <item msgid="1228338896751121025">"Dapatkan akun"</item>
+    <item msgid="3181581793459233672">"Jalankan di latar belakang"</item>
+    <item msgid="2340936043025374076">"Volume aksesibilitas"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Singkat"</item>
     <item msgid="4816511817309094890">"Sedang"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Jangan pernah izinkan"</item>
     <item msgid="8184570120217958741">"Selalu izinkan"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Sedang"</item>
+    <item msgid="1555861583162930714">"Rendah"</item>
+    <item msgid="1719683776264798117">"Kritis"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normal"</item>
+    <item msgid="6107138933849816768">"Sedang"</item>
+    <item msgid="182695359839047859">"Rendah"</item>
+    <item msgid="8577246509202964244">"Kritis"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Tetap"</item>
     <item msgid="167418068739176448">"Aktivitas teratas"</item>
diff --git a/tests/CarDeveloperOptions/res/values-in/config.xml b/tests/CarDeveloperOptions/res/values-in/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-in/config.xml
+++ b/tests/CarDeveloperOptions/res/values-in/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-in/strings.xml b/tests/CarDeveloperOptions/res/values-in/strings.xml
index d5638a0..b522fe4 100644
--- a/tests/CarDeveloperOptions/res/values-in/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-in/strings.xml
@@ -34,7 +34,7 @@
     <string name="radio_info_data_connection_enable" msgid="2554249462719717119">"Aktifkan Sambungan Data"</string>
     <string name="radio_info_data_connection_disable" msgid="2430609627397999371">"Nonaktifkan Sambungan Data"</string>
     <string name="volte_provisioned_switch_string" msgid="6326756678226686704">"VoLTE Disediakan"</string>
-    <string name="vt_provisioned_switch_string" msgid="7458479879009293613">"Video Call Disediakan"</string>
+    <string name="vt_provisioned_switch_string" msgid="7458479879009293613">"Panggilan Video Disediakan"</string>
     <string name="wfc_provisioned_switch_string" msgid="5446697646596639516">"Panggilan Wi-Fi Disediakan"</string>
     <string name="eab_provisioned_switch_string" msgid="3921103790584572430">"EAB/Presence Disediakan"</string>
     <string name="cbrs_data_switch_string" msgid="9120919504831536183">"Data Cbrs"</string>
@@ -53,7 +53,7 @@
     <string name="radio_info_ims_reg_status_not_registered" msgid="1286050699734226077">"Tidak Terdaftar"</string>
     <string name="radio_info_ims_feature_status_available" msgid="2040629393134756058">"Tersedia"</string>
     <string name="radio_info_ims_feature_status_unavailable" msgid="3348223769202693596">"Tidak tersedia"</string>
-    <string name="radio_info_ims_reg_status" msgid="4771711884059371514">"Pendaftaran IMS: <xliff:g id="STATUS">%1$s</xliff:g>\nSuara melalui LTE: <xliff:g id="AVAILABILITY_0">%2$s</xliff:g>\nSuara melalui Wi-Fi: <xliff:g id="AVAILABILITY_1">%3$s</xliff:g>\nVideo Call: <xliff:g id="AVAILABILITY_2">%4$s</xliff:g>\nAntarmuka UT: <xliff:g id="AVAILABILITY_3">%5$s</xliff:g>"</string>
+    <string name="radio_info_ims_reg_status" msgid="4771711884059371514">"Pendaftaran IMS: <xliff:g id="STATUS">%1$s</xliff:g>\nSuara melalui LTE: <xliff:g id="AVAILABILITY_0">%2$s</xliff:g>\nSuara melalui Wi-Fi: <xliff:g id="AVAILABILITY_1">%3$s</xliff:g>\nPanggilan Video: <xliff:g id="AVAILABILITY_2">%4$s</xliff:g>\nAntarmuka UT: <xliff:g id="AVAILABILITY_3">%5$s</xliff:g>"</string>
     <string name="radioInfo_service_in" msgid="1297020186765943857">"Dalam Layanan"</string>
     <string name="radioInfo_service_out" msgid="8460363463722476510">"Di Luar Area Layanan"</string>
     <string name="radioInfo_service_emergency" msgid="7674989004735662599">"Panggilan Darurat Saja"</string>
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Buat teks di layar jadi lebih kecil atau lebih besar."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Buat lebih kecil"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Buat lebih besar"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Teks contoh"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Penyihir Oz yang Menakjubkan"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Bab 11: Oz, Kota Zamrud yang Menakjubkan"</string>
@@ -180,7 +179,7 @@
     <string name="connected_device_connected_title" msgid="6255107326608785482">"Tersambung saat ini"</string>
     <string name="connected_device_saved_title" msgid="8270136893488475163">"Perangkat yang tersimpan"</string>
     <string name="connected_device_add_device_summary" msgid="7960491471270158891">"Bluetooth akan diaktifkan untuk menyambungkan"</string>
-    <string name="connected_device_connections_title" msgid="9205000271382018428">"Preferensi sambungan"</string>
+    <string name="connected_device_connections_title" msgid="9205000271382018428">"Preferensi koneksi"</string>
     <string name="connected_device_previously_connected_title" msgid="225918223397410428">"Perangkat yang sebelumnya tersambung"</string>
     <string name="connected_device_previously_connected_screen_title" msgid="2018789662358162716">"Perangkat yang terhubung sebelumnya"</string>
     <string name="connected_device_bluetooth_turned_on_toast" msgid="4652326177920814476">"Bluetooth diaktifkan"</string>
@@ -489,7 +488,7 @@
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"Ups, bukan itu sensornya"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"Sentuh sensor di bagian belakang ponsel. Gunakan jari telunjuk Anda."</string>
     <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"Pendaftaran tidak selesai"</string>
-    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Batas waktu pendaftaran sidik jari tercapai. Coba lagi."</string>
+    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Waktu pendaftaran sidik jari habis. Coba lagi."</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"Pendaftaran sidik jari tidak berhasil. Coba lagi atau gunakan jari lain."</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"Tambahkan yang lain"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"Berikutnya"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Harus kurang dari <xliff:g id="NUMBER_1">%d</xliff:g> digit</item>
       <item quantity="one">Harus kurang dari <xliff:g id="NUMBER_0">%d</xliff:g> digit</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Hanya boleh berisi angka 0-9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Admin perangkat tidak mengizinkan penggunaan PIN terbaru."</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"PIN umum diblokir oleh admin IT. Coba PIN lain."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Tidak boleh berisi karakter yang tidak valid"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Minimal berisi <xliff:g id="COUNT">%d</xliff:g> karakter bukan huruf</item>
       <item quantity="one">Minimal berisi 1 karakter bukan huruf</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Minimal berisi <xliff:g id="COUNT">%d</xliff:g> karakter bukan numerik</item>
+      <item quantity="one">Minimal berisi 1 karakter bukan numerik</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Admin perangkat tidak mengizinkan penggunaan sandi terbaru."</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Sandi umum diblokir oleh admin IT. Coba sandi lain."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Urutan digit naik, turun, atau berulang tidak diizinkan"</string>
@@ -824,7 +826,7 @@
     <string name="nfc_disclaimer_title" msgid="4860231267351602970">"Aktifkan NFC"</string>
     <string name="nfc_disclaimer_content" msgid="3066113577854565782">"NFC mempertukarkan data antara perangkat ini dan perangkat atau target lain di sekitar, seperti terminal pembayaran, pembaca akses, dan iklan atau tag interaktif."</string>
     <string name="nfc_secure_settings_title" msgid="5153751163174916581">"Amankan NFC"</string>
-    <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"Izinkan penggunaan Pembayaran NFC dan Transit hanya jika layar terbuka kuncinya"</string>
+    <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"Izinkan penggunaan Pembayaran NFC dan Transportasi Umum hanya jika layar terbuka kuncinya"</string>
     <string name="android_beam_settings_title" msgid="3083436415873738389">"Android Beam"</string>
     <string name="android_beam_on_summary" msgid="8068287225180474199">"Siap mentransmisikan konten apl melalui NFC"</string>
     <string name="android_beam_off_summary" msgid="7365818039159364600">"Mati"</string>
@@ -923,7 +925,7 @@
     <string name="wifi_show_password" msgid="7878398590772942202">"Tampilkan sandi"</string>
     <string name="wifi_ap_band_config" msgid="6565016368079288433">"Pilih AP Band"</string>
     <string name="wifi_ap_choose_auto" msgid="7927637960569365785">"Otomatis"</string>
-    <string name="wifi_ap_choose_2G" msgid="43198403259714736">"Pita frekuensi 2,4 GHz"</string>
+    <string name="wifi_ap_choose_2G" msgid="43198403259714736">"Band 2,4 GHz"</string>
     <string name="wifi_ap_choose_5G" msgid="2624859713183683146">"Pita frekuensi 5,0 GHz"</string>
     <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"Disarankan Band 5.0 GHz"</string>
     <string name="wifi_ap_2G" msgid="5793110086517338494">"2,4 GHz"</string>
@@ -936,7 +938,7 @@
     <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"Posisikan kode QR di tengah jendela kamera untuk menambahkan perangkat ke “<xliff:g id="SSID">%1$s</xliff:g>”"</string>
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"Pindai kode QR"</string>
     <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"Posisikan kode QR di tengah jendela kamera untuk menyambungkan ke “<xliff:g id="SSID">%1$s</xliff:g>”"</string>
-    <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"Hubungkan ke Wi‑Fi dengan meminta kode QR"</string>
+    <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"Hubungkan ke Wi‑Fi dengan memindai kode QR"</string>
     <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Bagikan Wi‑Fi"</string>
     <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"Pindai kode QR ini untuk terhubung ke “<xliff:g id="SSID">%1$s</xliff:g>” dan membagikan sandi"</string>
     <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"Pindai kode QR ini untuk terhubung ke “<xliff:g id="SSID">%1$s</xliff:g>”"</string>
@@ -973,7 +975,7 @@
     <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"Jangan validasi"</string>
     <string name="wifi_do_not_validate_eap_server_warning" msgid="3895397996759837323">"Sertifikat tidak ditentukan. Sambungan tidak bersifat pribadi."</string>
     <string name="wifi_ssid_too_long" msgid="34911971389775920">"Nama jaringan terlalu panjang."</string>
-    <string name="wifi_no_domain_warning" msgid="735859919311067606">"Harus menentukan domain."</string>
+    <string name="wifi_no_domain_warning" msgid="735859919311067606">"Domain harus ditentukan."</string>
     <string name="wifi_wps_available_first_item" msgid="3221671453930485243">"WPS tersedia"</string>
     <string name="wifi_wps_available_second_item" msgid="5703265526619705185">" (WPS tersedia)"</string>
     <string name="wifi_carrier_connect" msgid="7202618367339982884">"Jaringan Wi‑Fi operator"</string>
@@ -1100,11 +1102,14 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Ponsel"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Jika Wi-Fi tidak tersedia, gunakan jaringan seluler"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Jika jaringan seluler tidak tersedia, gunakan Wi-Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Telepon melalui Wi-Fi. Jika Wi-Fi terputus, panggilan akan berakhir."</string>
-    <string name="wifi_calling_off_explanation" msgid="1653424723742898015">"Jika panggilan Wi-Fi aktif, ponsel dapat merutekan panggilan telepon melalui jaringan Wi-Fi atau jaringan operator, bergantung pada preferensi dan sinyal mana yang lebih kuat. Sebelum mengaktifkan fitur ini, sebaiknya tanyakan info biaya dan detail lainnya ke operator.<xliff:g id="ADDITIONAL_TEXT">%1$s</xliff:g>"</string>
+    <string name="wifi_calling_off_explanation" msgid="1653424723742898015">"Jika panggilan Wi-Fi aktif, ponsel dapat mengarahkan panggilan telepon melalui jaringan Wi-Fi atau jaringan operator, bergantung pada preferensi dan sinyal mana yang lebih kuat. Sebelum mengaktifkan fitur ini, sebaiknya tanyakan info biaya dan detail lainnya ke operator.<xliff:g id="ADDITIONAL_TEXT">%1$s</xliff:g>"</string>
     <string name="wifi_calling_off_explanation_2" msgid="8648609693875720408"></string>
     <string name="emergency_address_title" msgid="5779915349686787024">"Alamat Darurat"</string>
     <string name="emergency_address_summary" msgid="478668478569851714">"Digunakan sebagai lokasi Anda ketika Anda melakukan panggilan darurat melalui Wi‑Fi"</string>
@@ -1563,7 +1568,7 @@
     <string name="restore_default_apn" msgid="7195266404077471007">"Memulihkan setelan APN default."</string>
     <string name="menu_restore" msgid="3799288817317293115">"Setel ulang ke default"</string>
     <string name="restore_default_apn_completed" msgid="5671734152740058937">"Penyetelan ulang setelan APN default selesai."</string>
-    <string name="reset_dashboard_title" msgid="7084966342252178530">"Opsi setel ulang"</string>
+    <string name="reset_dashboard_title" msgid="7084966342252178530">"Opsi reset"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"Jaringan, aplikasi, atau perangkat dapat disetel ulang"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"Setel ulang Wi-Fi, kuota seluler &amp; Bluetooth"</string>
     <string name="reset_network_desc" msgid="4982633363916261109">"Tindakan ini akan menyetel ulang semua setelan jaringan, termasuk:\n\n"<li>"Wi‑Fi"</li>\n<li>"Kuota seluler"</li>\n<li>"Bluetooth"</li></string>
@@ -1704,7 +1709,7 @@
     <string name="lockpassword_choose_your_screen_lock_header" msgid="6283518876031424798">"Setel kunci layar"</string>
     <string name="lockpassword_choose_your_password_message" msgid="2838273977481046536">"Untuk keamanan, setel sandi"</string>
     <string name="lockpassword_choose_your_password_header_for_fingerprint" msgid="4921343500484160894">"Setel sandi untuk pakai sidik jari"</string>
-    <string name="lockpassword_choose_your_pattern_header_for_fingerprint" msgid="314870151462139417">"Setel pola untuk fitur sidik jari"</string>
+    <string name="lockpassword_choose_your_pattern_header_for_fingerprint" msgid="314870151462139417">"Setel pola untuk pakai sidik jari"</string>
     <string name="lockpassword_choose_your_pin_message" msgid="8942598950627277885">"Untuk keamanan, setel PIN"</string>
     <string name="lockpassword_choose_your_pin_header_for_fingerprint" msgid="1102927520952116303">"Setel PIN untuk pakai sidik jari"</string>
     <string name="lockpassword_choose_your_pattern_message" msgid="1503075455752279687">"Untuk keamanan, setel pola"</string>
@@ -1954,7 +1959,7 @@
     <string name="hardkeyboard_category" msgid="5937171470391551627">"Setelan keyboard fisik"</string>
     <string name="auto_punctuate_summary" msgid="245694025030386370">"Tekan Spasi dua kali untuk memasukkan \".\""</string>
     <string name="show_password" msgid="620964020348073739">"Tampilkan sandi"</string>
-    <string name="show_password_summary" msgid="1403805089582258620">"Tampilkan karakter secara singkat saat Anda mengetik"</string>
+    <string name="show_password_summary" msgid="1403805089582258620">"Tampilkan karakter sejenak saat Anda mengetik"</string>
     <string name="spellchecker_security_warning" msgid="792070474432612097">"Pemeriksa ejaan ini mungkin dapat mengumpulkan semua teks yang Anda ketik, termasuk data pribadi seperti sandi dan nomor kartu kredit. Pemeriksa ejaan ini berasal dari aplikasi <xliff:g id="SPELLCHECKER_APPLICATION_NAME">%1$s</xliff:g>. Gunakan pemeriksa ejaan ini?"</string>
     <string name="spellchecker_quick_settings" msgid="5193036510190696655">"Setelan"</string>
     <string name="spellchecker_language" msgid="5168501692418112444">"Bahasa"</string>
@@ -2304,12 +2309,12 @@
       <item quantity="other">Batasi %1$d aplikasi?</item>
       <item quantity="one">Batasi aplikasi?</item>
     </plurals>
-    <string name="battery_tip_restrict_app_dialog_message" msgid="6905822297507947381">"Untuk menghemat baterai, hentikan <xliff:g id="APP">%1$s</xliff:g> menggunakan baterai di background. Aplikasi ini mungkin tidak berfungsi dengan baik dan notifikasi dapat tertunda."</string>
-    <string name="battery_tip_restrict_apps_less_than_5_dialog_message" msgid="4225881888543582456">"Untuk menghemat baterai, hentikan aplikasi ini menggunakan baterai di background. Aplikasi yang dibatasi mungkin tidak berfungsi dengan baik dan notifikasi dapat tertunda.\n\nAplikasi:"</string>
-    <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"Untuk menghemat baterai, hentikan aplikasi ini menggunakan baterai di background. Aplikasi yang dibatasi mungkin tidak berfungsi dengan baik dan notifikasi dapat tertunda.\n\nAplikasi:\n<xliff:g id="APP_LIST">%1$s</xliff:g>."</string>
+    <string name="battery_tip_restrict_app_dialog_message" msgid="6905822297507947381">"Untuk menghemat baterai, hentikan <xliff:g id="APP">%1$s</xliff:g> menggunakan baterai di latar belakang. Aplikasi ini mungkin tidak berfungsi dengan baik dan notifikasi dapat tertunda."</string>
+    <string name="battery_tip_restrict_apps_less_than_5_dialog_message" msgid="4225881888543582456">"Untuk menghemat baterai, hentikan aplikasi ini menggunakan baterai di latar belakang. Aplikasi yang dibatasi mungkin tidak berfungsi dengan baik dan notifikasi dapat tertunda.\n\nAplikasi:"</string>
+    <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"Untuk menghemat baterai, hentikan aplikasi ini menggunakan baterai di latar belakang. Aplikasi yang dibatasi mungkin tidak berfungsi dengan baik dan notifikasi dapat tertunda.\n\nAplikasi:\n<xliff:g id="APP_LIST">%1$s</xliff:g>."</string>
     <string name="battery_tip_restrict_app_dialog_ok" msgid="2573410775701913487">"Batasi"</string>
     <string name="battery_tip_unrestrict_app_dialog_title" msgid="812458516399125710">"Hapus batasan?"</string>
-    <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"Aplikasi ini dapat menggunakan baterai di background. Baterai mungkin lebih cepat habis dari biasanya."</string>
+    <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"Aplikasi ini dapat menggunakan baterai di latar belakang. Baterai mungkin lebih cepat habis dari biasanya."</string>
     <string name="battery_tip_unrestrict_app_dialog_ok" msgid="9154938931448151479">"Hapus"</string>
     <string name="battery_tip_unrestrict_app_dialog_cancel" msgid="7331148618292397166">"Batal"</string>
     <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"Aplikasi Anda menggunakan baterai secara normal. Jika aplikasi terlalu banyak menggunakan daya baterai, ponsel Anda akan menyarankan beberapa tindakan.\n\nAnda selalu dapat mengaktifkan Penghemat Baterai jika daya baterai hampir habis."</string>
@@ -2327,7 +2332,7 @@
       <item quantity="one">Membatasi penggunaan baterai untuk %1$d aplikasi</item>
     </plurals>
     <string name="restricted_app_time_summary" msgid="5205881852523135226">"Dibatasi <xliff:g id="TIME">%1$s</xliff:g>"</string>
-    <string name="restricted_app_detail_footer" msgid="482460517275754465">"Aplikasi ini telah menggunakan daya baterai di background. Aplikasi yang dibatasi mungkin tidak berfungsi dengan baik dan notifikasi dapat tertunda."</string>
+    <string name="restricted_app_detail_footer" msgid="482460517275754465">"Aplikasi ini telah menggunakan daya baterai di latar belakang. Aplikasi yang dibatasi mungkin tidak berfungsi dengan baik dan notifikasi dapat tertunda."</string>
     <string name="battery_auto_restriction_title" msgid="488905332794794076">"Gunakan Pengelola Baterai"</string>
     <string name="battery_auto_restriction_summary" msgid="1638072655581821837">"Mendeteksi jika aplikasi menghabiskan baterai"</string>
     <string name="battery_manager_on" msgid="5626982529932239656">"Aktif / Mendeteksi jika aplikasi menghabiskan baterai"</string>
@@ -2596,7 +2601,7 @@
     <string name="work_mode_label" msgid="6845849194740195757">"Profil kerja"</string>
     <string name="work_mode_on_summary" msgid="1682781113156323592">"Dikelola oleh organisasi"</string>
     <string name="work_mode_off_summary" msgid="1688885392211178315">"Aplikasi dan notifikasi dinonaktifkan"</string>
-    <string name="remove_managed_profile_label" msgid="4625542553784793536">"Buang profil kerja"</string>
+    <string name="remove_managed_profile_label" msgid="4625542553784793536">"Hapus profil kerja"</string>
     <string name="background_data" msgid="8275750862371471171">"Data latar belakang"</string>
     <string name="background_data_summary" msgid="799640633948841990">"Apl dapat menyinkronkan, mengirimkan, dan menerima data kapan saja"</string>
     <string name="background_data_dialog_title" msgid="8306650658158895976">"Matikn data ltr blkg?"</string>
@@ -2625,7 +2630,7 @@
     <string name="header_add_an_account" msgid="8482614556580804956">"Tambahkan akun"</string>
     <string name="really_remove_account_title" msgid="4166512362915154319">"Hapus akun?"</string>
     <string name="really_remove_account_message" product="tablet" msgid="7403843371045856719">"Menghapus akun ini akan menghapus semua pesan, kontak, dan data lain akun tersebut dari tablet!"</string>
-    <string name="really_remove_account_message" product="default" msgid="8951224626153163914">"Menghapus akun ini akan menghapus semua pesan, kontak, dan data lainnya akun tersebut dari ponsel!"</string>
+    <string name="really_remove_account_message" product="default" msgid="8951224626153163914">"Menghapus akun ini akan menghapus semua pesan, kontak, dan data lain akun tersebut dari ponsel."</string>
     <string name="really_remove_account_message" product="device" msgid="3751798556257519916">"Menghapus akun ini akan menghapus semua pesan, kontak, dan data lain akun tersebut dari perangkat."</string>
     <string name="remove_account_failed" msgid="491458185327106966">"Perubahan ini tidak diizinkan oleh admin"</string>
     <string name="cant_sync_dialog_title" msgid="5483419398223189881">"Tidak dapat menyinkronkan secara manual"</string>
@@ -2857,7 +2862,7 @@
     <string name="user_summary_managed_profile_not_set_up" msgid="3032986082684011281">"Tidak disiapkan - Profil kerja"</string>
     <string name="user_admin" msgid="805802526361071709">"Admin"</string>
     <string name="user_you" msgid="8212549708652717106">"Anda (<xliff:g id="NAME">%s</xliff:g>)"</string>
-    <string name="user_nickname" msgid="1088216221559125529">"Nama julukan"</string>
+    <string name="user_nickname" msgid="1088216221559125529">"Nama panggilan"</string>
     <string name="user_add_user_type_title" msgid="8672326434351387845">"Tambahkan"</string>
     <string name="user_add_max_count" msgid="4524573950126500416">"Anda dapat menambahkan maksimal <xliff:g id="USER_COUNT">%1$d</xliff:g> pengguna"</string>
     <string name="user_add_user_item_summary" msgid="6114355152711455716">"Pengguna memiliki aplikasi dan konten mereka sendiri"</string>
@@ -2865,7 +2870,7 @@
     <string name="user_add_user_item_title" msgid="6835385073795492410">"Pengguna"</string>
     <string name="user_add_profile_item_title" msgid="4932743891449790664">"Profil dibatasi"</string>
     <string name="user_add_user_title" msgid="2320897397066676472">"Tambahkan pengguna baru?"</string>
-    <string name="user_add_user_message_long" msgid="686637203224195465">"Anda dapat berbagi penggunaan perangkat ini dengan orang lain dengan membuat pengguna tambahan. Setiap pengguna memiliki ruang sendiri, yang dapat disesuaikan dengan aplikasi, wallpaper, dan lainnya.\n\nSaat Anda menambahkan pengguna baru, pengguna tersebut perlu menyiapkan ruangnya.\n\nPengguna mana pun dapat mengupdate aplikasi untuk semua pengguna lainnya. Layanan dan setelan aksesibilitas mungkin tidak ditransfer ke pengguna baru."</string>
+    <string name="user_add_user_message_long" msgid="686637203224195465">"Anda dapat berbagi penggunaan perangkat ini dengan orang lain dengan membuat pengguna tambahan. Setiap pengguna memiliki ruang sendiri, yang dapat disesuaikan dengan aplikasi, wallpaper, dan lainnya. Pengguna juga dapat menyesuaikan setelan perangkat seperti Wi-Fi yang dapat memengaruhi semua pengguna lain.\n\nSaat Anda menambahkan pengguna baru, pengguna tersebut perlu menyiapkan ruangnya.\n\nPengguna mana pun dapat mengupdate aplikasi untuk semua pengguna lainnya. Layanan dan setelan aksesibilitas mungkin tidak ditransfer ke pengguna baru."</string>
     <string name="user_add_user_message_short" msgid="1802594476285458254">"Saat Anda menambahkan pengguna baru, orang tersebut perlu menyiapkan ruang mereka sendiri.\n\nPengguna mana pun dapat memperbarui aplikasi untuk semua pengguna lain."</string>
     <string name="user_setup_dialog_title" msgid="6748950002206392396">"Siapkan pengguna sekarang?"</string>
     <string name="user_setup_dialog_message" msgid="2988559933258353919">"Pastikan orang tersebut ada untuk mengambil perangkat dan menyiapkan ruangnya"</string>
@@ -2883,7 +2888,7 @@
     <string name="user_confirm_remove_self_title" msgid="6739480453680217543">"Hapus diri Anda sendiri?"</string>
     <string name="user_confirm_remove_title" msgid="1034498514019462084">"Hapus pengguna ini?"</string>
     <string name="user_profile_confirm_remove_title" msgid="6138684743385947063">"Buang profil ini?"</string>
-    <string name="work_profile_confirm_remove_title" msgid="3168910958076735800">"Buang profil kerja?"</string>
+    <string name="work_profile_confirm_remove_title" msgid="3168910958076735800">"Hapus profil kerja?"</string>
     <string name="user_confirm_remove_self_message" product="tablet" msgid="2889456786320157545">"Ruang dan data Anda akan hilang dari tablet ini. Anda tidak dapat mengurungkan tindakan ini."</string>
     <string name="user_confirm_remove_self_message" product="default" msgid="8441729423565705183">"Ruang dan data Anda akan hilang dari ponsel ini. Anda tidak dapat mengurungkan tindakan ini."</string>
     <string name="user_confirm_remove_message" msgid="5202150470271756013">"Semua aplikasi dan data akan dihapus."</string>
@@ -3030,7 +3035,7 @@
     <string name="network_dashboard_summary_mobile" msgid="5560545061217580626">"seluler"</string>
     <string name="network_dashboard_summary_data_usage" msgid="4695629715072542102">"penggunaan kuota"</string>
     <string name="network_dashboard_summary_hotspot" msgid="3928610802321995214">"hotspot"</string>
-    <string name="connected_devices_dashboard_title" msgid="7795222675849060444">"Perangkat tersambung"</string>
+    <string name="connected_devices_dashboard_title" msgid="7795222675849060444">"Perangkat terhubung"</string>
     <string name="connected_devices_dashboard_summary" msgid="1072664369515033179">"Bluetooth, mode mengemudi, NFC"</string>
     <string name="connected_devices_dashboard_no_nfc_summary" msgid="2610085597733526722">"Bluetooth, mode mengemudi"</string>
     <string name="connected_devices_dashboard_no_driving_mode_summary" msgid="3524409078596318803">"Bluetooth, NFC"</string>
@@ -3706,8 +3711,8 @@
     <string name="high_power_off" msgid="5906679734326490426">"Mengoptimalkan penggunaan baterai"</string>
     <string name="high_power_system" msgid="739584574711292753">"Pengoptimalan baterai tidak tersedia"</string>
     <string name="high_power_desc" msgid="333756885680362741">"Jangan terapkan pengoptimalan baterai. Baterai akan lebih cepat habis."</string>
-    <string name="high_power_prompt_title" msgid="2805745781720454052">"Izinkan aplikasi selalu berjalan di background?"</string>
-    <string name="high_power_prompt_body" msgid="8067395096053552289">"Mengizinkan <xliff:g id="APP_NAME">%1$s</xliff:g> untuk selalu berjalan di background dapat mengurangi masa pakai baterai. \n\nAnda dapat mengubah ini nanti dari Setelan &gt; Aplikasi &amp; notifikasi."</string>
+    <string name="high_power_prompt_title" msgid="2805745781720454052">"Izinkan aplikasi selalu berjalan di latar belakang?"</string>
+    <string name="high_power_prompt_body" msgid="8067395096053552289">"Mengizinkan <xliff:g id="APP_NAME">%1$s</xliff:g> untuk selalu berjalan di latar belakang dapat mengurangi masa pakai baterai. \n\nAnda dapat mengubah ini nanti dari Setelan &gt; Aplikasi &amp; notifikasi."</string>
     <string name="battery_summary" msgid="4345690800899981339">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> digunakan sejak terakhir kali baterai diisi penuh"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"Pengelolaan daya"</string>
     <string name="no_battery_summary" msgid="4105932628367471314">"Tidak ada penggunaan baterai sejak isi daya penuh terakhir"</string>
@@ -3892,7 +3897,7 @@
     <string name="condition_battery_summary" msgid="1236078243905690620">"Fitur dibatasi"</string>
     <string name="condition_cellular_title" msgid="6605277435894307935">"Kuota tidak aktif"</string>
     <string name="condition_cellular_summary" msgid="3607459310548343777">"Internet hanya tersedia melalui Wi‑Fi"</string>
-    <string name="condition_bg_data_title" msgid="184684435298857712">"Penghemat Kuota"</string>
+    <string name="condition_bg_data_title" msgid="184684435298857712">"Penghemat Data"</string>
     <string name="condition_bg_data_summary" msgid="5194942860807136682">"Fitur dibatasi"</string>
     <string name="condition_work_title" msgid="9046811302347490371">"Profil kerja nonaktif"</string>
     <string name="condition_work_summary" msgid="5586134491975748565">"Untuk aplikasi &amp; notifikasi"</string>
@@ -3930,7 +3935,7 @@
     <string name="usage" msgid="9172908720164431622">"Penggunaan"</string>
     <string name="cellular_data_usage" msgid="1236562234207782386">"Penggunaan kuota seluler"</string>
     <string name="app_cellular_data_usage" msgid="8499761516172121957">"Penggunaan kuota aplikasi"</string>
-    <string name="wifi_data_usage" msgid="275569900562265895">"Penggunaan kuota Wi-Fi"</string>
+    <string name="wifi_data_usage" msgid="275569900562265895">"Penggunaan data Wi-Fi"</string>
     <string name="ethernet_data_usage" msgid="747614925362556718">"Penggunaan data ethernet"</string>
     <string name="wifi" msgid="1586738489862966138">"Wi-Fi"</string>
     <string name="ethernet" msgid="2365753635113154667">"Ethernet"</string>
@@ -3948,7 +3953,7 @@
       <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> pembatasan</item>
       <item quantity="one">1 pembatasan</item>
     </plurals>
-    <string name="operator_warning" msgid="4676042739221117031">"Perhitungan kuota operator dapat berbeda dengan perhitungan perangkat"</string>
+    <string name="operator_warning" msgid="4676042739221117031">"Perhitungan data oleh operator dapat berbeda dengan perhitungan perangkat"</string>
     <string name="data_used_template" msgid="761605393453849477">"<xliff:g id="ID_1">%1$s</xliff:g> digunakan"</string>
     <string name="set_data_warning" msgid="8115980184415563941">"Setel peringatan kuota"</string>
     <string name="data_warning" msgid="2699207195535036240">"Peringatan kuota"</string>
@@ -3959,8 +3964,8 @@
     <string name="configure" msgid="8232696842838580549">"Konfigurasi"</string>
     <string name="data_usage_other_apps" msgid="7002491980141402084">"Aplikasi lain yang disertakan dalam penggunaan"</string>
     <plurals name="data_saver_unrestricted_summary" formatted="false" msgid="6046013861315713697">
-      <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> aplikasi diizinkan untuk menggunakan kuota tak terbatas saat Penghemat Kuota Internet aktif</item>
-      <item quantity="one">1 aplikasi diizinkan untuk menggunakan kuota tak terbatas saat Penghemat Kuota Internet aktif</item>
+      <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> aplikasi diizinkan untuk menggunakan data tak terbatas saat Penghemat Data aktif</item>
+      <item quantity="one">1 aplikasi diizinkan untuk menggunakan data tak terbatas saat Penghemat Data aktif</item>
     </plurals>
     <string name="data_usage_title" msgid="7874606430902201083">"Kuota utama"</string>
     <string name="data_usage_wifi_title" msgid="7161828479387766556">"Data Wi-Fi"</string>
@@ -3980,14 +3985,14 @@
     <string name="no_carrier_update_now_text" msgid="4405472895804759042">"Baru saja diupdate"</string>
     <string name="launch_mdp_app_text" msgid="9186559496664208252">"Lihat paket"</string>
     <string name="launch_wifi_text" msgid="317820210431682605">"Lihat detail"</string>
-    <string name="data_saver_title" msgid="7903308134514179256">"Penghemat Kuota"</string>
-    <string name="unrestricted_data_saver" msgid="9139401849550738720">"Kuota tidak dibatasi"</string>
+    <string name="data_saver_title" msgid="7903308134514179256">"Penghemat Data"</string>
+    <string name="unrestricted_data_saver" msgid="9139401849550738720">"Data tidak dibatasi"</string>
     <string name="restrict_background_blacklisted" msgid="7158991683849067124">"Data latar belakang nonaktif"</string>
     <string name="data_saver_on" msgid="7281809065420480881">"Aktif"</string>
     <string name="data_saver_off" msgid="7439439787358504018">"Nonaktif"</string>
-    <string name="data_saver_switch_title" msgid="8244008132112735207">"Gunakan Penghemat Kuota"</string>
-    <string name="unrestricted_app_title" msgid="4390661122069905122">"Penggunaan kuota tidak dibatasi"</string>
-    <string name="unrestricted_app_summary" msgid="2829141815077800483">"Izinkan akses kuota tak terbatas saat Penghemat Kuota Internet aktif"</string>
+    <string name="data_saver_switch_title" msgid="8244008132112735207">"Gunakan Penghemat Data"</string>
+    <string name="unrestricted_app_title" msgid="4390661122069905122">"Penggunaan data tidak dibatasi"</string>
+    <string name="unrestricted_app_summary" msgid="2829141815077800483">"Izinkan akses data tak terbatas saat Penghemat Data aktif"</string>
     <string name="home_app" msgid="3695063566006954160">"Aplikasi layar utama"</string>
     <string name="no_default_home" msgid="1518949210961918497">"Tidak ada Layar Utama default"</string>
     <string name="lockpattern_settings_require_cred_before_startup" msgid="63693894094570367">"Proses memulai dengan aman"</string>
@@ -3997,7 +4002,7 @@
     <string name="suggestion_additional_fingerprints" msgid="3434467207282466411">"Tambahkan sidik jari lain"</string>
     <string name="suggestion_additional_fingerprints_summary" msgid="1916547587832484196">"Buka kunci dengan jari lain"</string>
     <string name="battery_saver_on_summary" msgid="6841062406467435672">"Aktif"</string>
-    <string name="battery_saver_off_scheduled_summary" msgid="3740414764069188669">"Akan aktif jika <xliff:g id="BATTERY_PERCENTAGE">%1$s</xliff:g>"</string>
+    <string name="battery_saver_off_scheduled_summary" msgid="3740414764069188669">"Akan aktif pada <xliff:g id="BATTERY_PERCENTAGE">%1$s</xliff:g>"</string>
     <string name="battery_saver_off_summary" msgid="8736555723004299721">"Nonaktif"</string>
     <string name="battery_saver_button_turn_on" msgid="3748696527267573793">"Aktifkan sekarang"</string>
     <string name="battery_saver_button_turn_off" msgid="2912950982503267828">"Nonaktifkan sekarang"</string>
@@ -4107,7 +4112,7 @@
     <string name="gesture_preference_summary" product="tablet" msgid="8303793594714075580">"Isyarat cepat untuk mengontrol tablet"</string>
     <string name="gesture_preference_summary" product="device" msgid="7792199669106960922">"Isyarat cepat untuk mengontrol perangkat"</string>
     <string name="double_tap_power_for_camera_title" msgid="5480829329052517484">"Buka kamera"</string>
-    <string name="double_tap_power_for_camera_summary" msgid="6591026425496323965">"Untuk membuka kamera dengan cepat, tekan tombol power 2 kali. Berfungsi di layar mana pun."</string>
+    <string name="double_tap_power_for_camera_summary" msgid="6591026425496323965">"Untuk membuka kamera dengan cepat, tekan tombol daya 2 kali. Berfungsi di layar mana pun."</string>
     <string name="double_tap_power_for_camera_suggestion_title" msgid="509078029429865036">"Buka kamera dengan cepat"</string>
     <string name="double_twist_for_camera_mode_title" msgid="2606032140297556018">"Balik kamera"</string>
     <string name="double_twist_for_camera_mode_summary" msgid="8979914206876018137"></string>
@@ -4130,7 +4135,7 @@
     <string name="ambient_display_tap_screen_title" product="tablet" msgid="6434521782016864148">"Ketuk untuk memeriksa tablet"</string>
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"Ketuk untuk memeriksa perangkat"</string>
     <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"Untuk memeriksa waktu, notifikasi, dan info lainnya, ketuk layar Anda."</string>
-    <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"Usapkan sidik jari untuk melihat notifikasi"</string>
+    <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"Geserkan sidik jari untuk melihat notifikasi"</string>
     <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"Usapkan sidik jari"</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"Untuk memeriksa notifikasi, usapkan jari ke bawah pada sensor sidik jari di bagian belakang ponsel."</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="tablet" msgid="3480057984564476283">"Untuk memeriksa notifikasi, usapkan jari ke bawah pada sensor sidik jari di bagian belakang tablet."</string>
@@ -4319,7 +4324,7 @@
     <string name="battery_suggestion_title" product="default" msgid="3295786171830183688">"Tingkatkan masa pakai baterai ponsel"</string>
     <string name="battery_suggestion_summary" msgid="2669070349482656490"></string>
     <string name="gesture_prevent_ringing_screen_title" msgid="4173494225145223638">"Cegah berdering"</string>
-    <string name="gesture_prevent_ringing_title" msgid="8827963588425673557">"Tekan tombol Power &amp; Keraskan Volume secara bersamaan untuk"</string>
+    <string name="gesture_prevent_ringing_title" msgid="8827963588425673557">"Tekan tombol Daya &amp; Naikkan Volume secara bersamaan untuk"</string>
     <string name="gesture_prevent_ringing_sound_title" msgid="8642330448721033641">"Pintasan untuk mencegah berdering"</string>
     <string name="prevent_ringing_option_vibrate" msgid="6456505293904544108">"Getar"</string>
     <string name="prevent_ringing_option_mute" msgid="53662688921253613">"Nonaktifkan suara"</string>
@@ -4424,7 +4429,7 @@
     <string name="carrier_settings_euicc" msgid="7723199738771996732">"Operator"</string>
     <string name="carrier_settings_version" msgid="2657511289029828425">"Versi setelan"</string>
     <string name="call_category" msgid="3418535202893644015">"Memanggil"</string>
-    <string name="video_calling_settings_title" msgid="8011841542502156112">"Video call operator"</string>
+    <string name="video_calling_settings_title" msgid="8011841542502156112">"Panggilan video operator"</string>
     <string name="cdma_system_select_title" msgid="5620679296177526467">"Pilih sistem"</string>
     <string name="cdma_system_select_summary" msgid="6749131988334321244">"Mengubah mode roaming CDMA"</string>
     <string name="cdma_system_select_dialogtitle" msgid="7489000866289285390">"Pilih sistem"</string>
diff --git a/tests/CarDeveloperOptions/res/values-is/arrays.xml b/tests/CarDeveloperOptions/res/values-is/arrays.xml
index 1cec986..6e6dc6c 100644
--- a/tests/CarDeveloperOptions/res/values-is/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-is/arrays.xml
@@ -38,7 +38,16 @@
     <item msgid="5827960506924849753">"10 mínútur"</item>
     <item msgid="6677424950124253938">"30 mínútur"</item>
   </string-array>
-    <!-- no translation found for dream_timeout_entries:7 (8271452751594598661) -->
+  <string-array name="dream_timeout_entries">
+    <item msgid="6487043225269853023">"Aldrei"</item>
+    <item msgid="2517785806387977252">"15 sekúndur"</item>
+    <item msgid="6347954399441173672">"30 sekúndur"</item>
+    <item msgid="4858305253279921789">"1 mínúta"</item>
+    <item msgid="8109273437140044073">"2 mínútur"</item>
+    <item msgid="2788593551142462622">"5 mínútur"</item>
+    <item msgid="8012672183888404961">"10 mínútur"</item>
+    <item msgid="8271452751594598661">"30 mínútur"</item>
+  </string-array>
   <string-array name="lock_after_timeout_entries">
     <item msgid="2232921187970351881">"Strax"</item>
     <item msgid="2038544972632026612">"5 sekúndur"</item>
@@ -50,17 +59,47 @@
     <item msgid="811192536981678974">"10 mínútur"</item>
     <item msgid="7258394417241706272">"30 mínútur"</item>
   </string-array>
-    <!-- no translation found for entries_font_size:0 (2340391964816059553) -->
-    <!-- no translation found for entries_font_size:0 (6490061470416867723) -->
-    <!-- no translation found for entries_font_size:2 (1714184661981538355) -->
-    <!-- no translation found for entries_font_size:2 (1678068858001018666) -->
-    <!-- no translation found for wifi_status:3 (5848277343965362748) -->
-    <!-- no translation found for wifi_status_with_ssid:1 (6816207058895999545) -->
-    <!-- no translation found for wifi_status_with_ssid:3 (7547609081339573756) -->
-    <!-- no translation found for wifi_status_with_ssid:4 (5145158315060185414) -->
+  <string-array name="entries_font_size">
+    <item msgid="2340391964816059553">"Lítil"</item>
+    <item msgid="591935967183159581">"Sjálfgefið"</item>
+    <item msgid="1714184661981538355">"Stór"</item>
+    <item msgid="6195563047686707484">"Stærst"</item>
+  </string-array>
+  <string-array name="wifi_status">
+    <item msgid="1304883790721412351"></item>
+    <item msgid="4157625910392775808">"Leitar…"</item>
+    <item msgid="5597394826455877834">"Tengist…"</item>
+    <item msgid="5848277343965362748">"Auðkennir…"</item>
+    <item msgid="3391238031431440676">"Sækir IP-tölu…"</item>
+    <item msgid="5257597310494000224">"Tengt"</item>
+    <item msgid="8472497592913050396">"Í bið"</item>
+    <item msgid="1228072488815999109">"Aftengist…"</item>
+    <item msgid="7253087004422991731">"Aftengt"</item>
+    <item msgid="4169850917304751227">"Mistókst"</item>
+    <item msgid="6266658166690831131">"Á bannlista"</item>
+    <item msgid="4517230805854909775">"Forðast lélega tengingu tímabundið"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="4853670665485437464"></item>
+    <item msgid="6816207058895999545">"Leitar…"</item>
+    <item msgid="8058143476674427024">"Tengist <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7547609081339573756">"Auðkennir á <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="5145158315060185414">"Sækir IP-tölu frá <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="3283243151651124831">"Tengt við <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="6600156231416890902">"Í bið"</item>
+    <item msgid="4133290864821295785">"Aftengist <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="3980154971187953257">"Aftengt"</item>
+    <item msgid="2847316776634969068">"Mistókst"</item>
+    <item msgid="4390990424746035383">"Á bannlista"</item>
+    <item msgid="3618248791367063949">"Forðast lélega tengingu tímabundið"</item>
+  </string-array>
     <!-- no translation found for wifi_tether_security:0 (5586343370515598801) -->
     <!-- no translation found for wifi_tether_security:1 (6136336549994615745) -->
-    <!-- no translation found for wifi_p2p_wps_setup:0 (5390235347963255303) -->
+  <string-array name="wifi_p2p_wps_setup">
+    <item msgid="5390235347963255303">"Hnappur"</item>
+    <item msgid="7401896200768713930">"PIN-númer úr tengdu tæki"</item>
+    <item msgid="4526848028011846710">"PIN frá þessu tæki"</item>
+  </string-array>
   <string-array name="wifi_p2p_status">
     <item msgid="8741947238021758201">"Tengt"</item>
     <item msgid="983792611851499732">"Boðið"</item>
@@ -82,8 +121,13 @@
     <item msgid="1644506614010085798">"4"</item>
     <item msgid="3132506679404897150">"5"</item>
   </string-array>
-    <!-- no translation found for wifi_signal:1 (7882129634982603782) -->
-    <!-- no translation found for wifi_signal:4 (999948812884919584) -->
+  <string-array name="wifi_signal">
+    <item msgid="1709949377823900951">"Lélegt"</item>
+    <item msgid="7882129634982603782">"Lélegt"</item>
+    <item msgid="6457357501905996224">"Sæmilegt"</item>
+    <item msgid="405271628162918841">"Góður"</item>
+    <item msgid="999948812884919584">"Frábært"</item>
+  </string-array>
   <string-array name="data_usage_data_range">
     <item msgid="8986775481492954015">"Síðustu 30 dagar"</item>
     <item msgid="3211287705232736964">"Velja notkunartímabil..."</item>
@@ -119,7 +163,10 @@
     <item msgid="7330627471456865502">"MSCHAPV2"</item>
     <item msgid="6255179395132581882">"GTC"</item>
   </string-array>
-    <!-- no translation found for wifi_ip_settings:1 (4377002609760712163) -->
+  <string-array name="wifi_ip_settings">
+    <item msgid="2717196390555072244">"DHCP"</item>
+    <item msgid="4377002609760712163">"Föst"</item>
+  </string-array>
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"Ekkert"</item>
     <item msgid="1464741437353223198">"Handbók"</item>
@@ -239,11 +286,73 @@
     <item msgid="1165623660533024666">"keyra í bakgrunni"</item>
     <item msgid="6423861043647911030">"hljóðstyrkur aðgengis"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:3 (7836406246005211990) -->
-    <!-- no translation found for app_ops_labels:4 (3951439024549922598) -->
-    <!-- no translation found for app_ops_labels:8 (3597797992398484655) -->
-    <!-- no translation found for app_ops_labels:20 (3037159047591081136) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Staðsetning"</item>
+    <item msgid="6656077694190491067">"Staðsetning"</item>
+    <item msgid="8790228218278477369">"Staðsetning"</item>
+    <item msgid="7836406246005211990">"Titringur"</item>
+    <item msgid="3951439024549922598">"Lesa tengiliði"</item>
+    <item msgid="8802152411647068">"Breyta tengiliðum"</item>
+    <item msgid="229544934599698735">"Lesa símtalaskrá"</item>
+    <item msgid="7396102294405899613">"Breyta símtalaskrá"</item>
+    <item msgid="3597797992398484655">"Lesa dagatal"</item>
+    <item msgid="2705975774250907343">"Breyta dagatali"</item>
+    <item msgid="4668747371441932697">"Staðsetning"</item>
+    <item msgid="1487578921720243646">"Færslutilkynning"</item>
+    <item msgid="4636080349724146638">"Staðsetning"</item>
+    <item msgid="673510900286463926">"Hringja í síma"</item>
+    <item msgid="542083422784609790">"Lesa SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Skrifa SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Taka á móti SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Taka á móti SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Taka á móti SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Taka á móti SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Senda SMS/MMS"</item>
+    <item msgid="4726682243833913568">"Lesa SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Skrifa SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Breyta stillingum"</item>
+    <item msgid="8705854389991425629">"Teikna yfir"</item>
+    <item msgid="5861356020344153651">"Opna tilkynningar"</item>
+    <item msgid="78432174621628659">"Myndavél"</item>
+    <item msgid="3986116419882154794">"Taka upp hljóð"</item>
+    <item msgid="4516840825756409490">"Spila hljóð"</item>
+    <item msgid="6811712502798183957">"Lesa klippiborð"</item>
+    <item msgid="2780369012602289114">"Breyta klippiborði"</item>
+    <item msgid="2331359440170850868">"Margmiðlunarhnappar"</item>
+    <item msgid="6133599737122751231">"Fókus hljóðs"</item>
+    <item msgid="6844485713404805301">"Meginhljóðstyrkur"</item>
+    <item msgid="1600379420669104929">"Hljóðstyrkur raddar"</item>
+    <item msgid="6296768210470214866">"Hljóðstyrkur hringingar"</item>
+    <item msgid="510690696071629241">"Hljóðstyrkur margmiðlunarefnis"</item>
+    <item msgid="406861638631430109">"Hljóðstyrkur vekjara"</item>
+    <item msgid="4715864795872233884">"Hljóðstyrkur tilkynninga"</item>
+    <item msgid="2311478519251301183">"Hljóðstyrkur Bluetooth"</item>
+    <item msgid="5133991377896747027">"Halda vakandi"</item>
+    <item msgid="2464189519136248621">"Staður"</item>
+    <item msgid="2062677934050803037">"Staðsetning"</item>
+    <item msgid="1735171933192715957">"Fá talnagögn um notkun"</item>
+    <item msgid="1014093788778383554">"Kveikja/slökkva á hljóðnema"</item>
+    <item msgid="4199297950608622850">"Sýna tilkynningu"</item>
+    <item msgid="2527962435313398821">"Margmiðlunarefni verkefnis"</item>
+    <item msgid="5117506254221861929">"Virkja VPN"</item>
+    <item msgid="8291198322681891160">"Skrifa veggfóður"</item>
+    <item msgid="7106921284621230961">"Aðstoða við uppbyggingu"</item>
+    <item msgid="4496533640894624799">"Aðstoða við skjámynd"</item>
+    <item msgid="2598847264853993611">"Lesa stöðu síma"</item>
+    <item msgid="9215610846802973353">"Bæta við talhólfi"</item>
+    <item msgid="9186411956086478261">"Nota SIP"</item>
+    <item msgid="6884763100104539558">"Vinna úr hringdu símtali"</item>
+    <item msgid="125513972170580692">"Fingrafar"</item>
+    <item msgid="2556071024281275619">"Líkamsskynjarar"</item>
+    <item msgid="617168514928339387">"Lesa skilaboð frá endurvarpa"</item>
+    <item msgid="7134693570516523585">"Gervistaðsetning"</item>
+    <item msgid="7224489175375229399">"Lesa geymslu"</item>
+    <item msgid="8472735063903258202">"Skrifa í geymslu"</item>
+    <item msgid="4069276819909595110">"Kveikja á skjánum"</item>
+    <item msgid="1228338896751121025">"Fá reikninga"</item>
+    <item msgid="3181581793459233672">"Keyra í bakgrunni"</item>
+    <item msgid="2340936043025374076">"Hljóðstyrkur aðgengis"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Stutt"</item>
     <item msgid="4816511817309094890">"Í meðallagi"</item>
@@ -260,7 +369,13 @@
     <item msgid="4627069151979553527">"Tengt"</item>
     <item msgid="6896773537705206194">"Litlir hástafir"</item>
   </string-array>
-    <!-- no translation found for captioning_font_size_selector_titles:3 (2784236342175159295) -->
+  <string-array name="captioning_font_size_selector_titles">
+    <item msgid="1680223634161592855">"Mjög lítið"</item>
+    <item msgid="5091603983404027034">"Lítið"</item>
+    <item msgid="176844712416932112">"Venjulegt"</item>
+    <item msgid="2784236342175159295">"Stór"</item>
+    <item msgid="218913203203160606">"Mjög stórt"</item>
+  </string-array>
   <string-array name="captioning_edge_type_selector_titles">
     <item msgid="3865198759294188069">"Sjálfgefið"</item>
     <item msgid="6488643537808152001">"Ekkert"</item>
@@ -275,7 +390,14 @@
     <item msgid="1874668269931014581">"75%"</item>
     <item msgid="6462911487571123954">"100%"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"Nota sjálfgildi forrits"</item>
+    <item msgid="8611890312638868524">"Hvítt á svörtu"</item>
+    <item msgid="5891360837786277638">"Svart á hvítu"</item>
+    <item msgid="2798457065945456853">"Gult á svörtu"</item>
+    <item msgid="5799049811524553967">"Gult á bláu"</item>
+    <item msgid="3673930830658169860">"Sérstillt"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"PPTP VPN"</item>
     <item msgid="1349760781118368659">"L2TP/IPSec VPN með lyklum sem hefur verið deilt"</item>
@@ -288,15 +410,32 @@
     <item msgid="2958623927055120839">"Ekkert"</item>
     <item msgid="1157046369795346308">"Handbók"</item>
   </string-array>
-    <!-- no translation found for vpn_states:4 (9135049670787351881) -->
+  <string-array name="vpn_states">
+    <item msgid="5408915841694583740">"Aftengt"</item>
+    <item msgid="8754480102834556765">"Frumstillir…"</item>
+    <item msgid="3351334355574270250">"Tengist…"</item>
+    <item msgid="8303882153995748352">"Tengt"</item>
+    <item msgid="9135049670787351881">"Tímamörk"</item>
+    <item msgid="2124868417182583926">"Mistókst"</item>
+  </string-array>
   <string-array name="security_settings_premium_sms_values">
     <item msgid="1164265643455394443">"Spyrja"</item>
     <item msgid="7718817231348607934">"Leyfa aldrei"</item>
     <item msgid="8184570120217958741">"Leyfa alltaf"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Venjuleg"</item>
+    <item msgid="5101233285497327432">"Í meðallagi"</item>
+    <item msgid="1555861583162930714">"Lítið"</item>
+    <item msgid="1719683776264798117">"Alvarlegt"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Venjulegt"</item>
+    <item msgid="6107138933849816768">"Í meðallagi"</item>
+    <item msgid="182695359839047859">"Lítið"</item>
+    <item msgid="8577246509202964244">"Á þrotum"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Viðvarandi"</item>
     <item msgid="167418068739176448">"Mesta virkni"</item>
diff --git a/tests/CarDeveloperOptions/res/values-is/config.xml b/tests/CarDeveloperOptions/res/values-is/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-is/config.xml
+++ b/tests/CarDeveloperOptions/res/values-is/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-is/strings.xml b/tests/CarDeveloperOptions/res/values-is/strings.xml
index 5abef77..0707eb3 100644
--- a/tests/CarDeveloperOptions/res/values-is/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-is/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Stækkaðu eða minnkaðu texta á skjá."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Minnka"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Stækka"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Textadæmi"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Galdrakarlinn í Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"11. kafli: Smaragðsborgin dásamlega í Oz"</string>
@@ -668,7 +667,6 @@
       <item quantity="one">Má ekki vera lengra en <xliff:g id="NUMBER_1">%d</xliff:g> tölustafur</item>
       <item quantity="other">Má ekki vera lengra en <xliff:g id="NUMBER_1">%d</xliff:g> tölustafir</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Má eingöngu innihalda tölustafi, 0–9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Tækjastjóri leyfir ekki notkun nýlegs PIN-númers"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Kerfisstjórinn þinn hefur lokað á algeng PIN-númer. Prófaðu annað PIN-númer."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Þetta má ekki innihalda ógildan staf"</string>
@@ -699,6 +697,10 @@
       <item quantity="one">Verður að innihalda að minnsta kosti <xliff:g id="COUNT">%d</xliff:g> staftákn sem ekki er bókstafur</item>
       <item quantity="other">Verður að innihalda að minsta kosti <xliff:g id="COUNT">%d</xliff:g> staftákn sem ekki eru bókstafir</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">Verður að innihalda að minnsta kosti <xliff:g id="COUNT">%d</xliff:g> staftákn sem er ekki tölustafur</item>
+      <item quantity="other">Verður að innihalda að minnsta kosti <xliff:g id="COUNT">%d</xliff:g> staftákn sem eru ekki tölustafir</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Tækjastjóri leyfir ekki notkun nýlegs aðgangsorðs"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Kerfisstjórinn þinn hefur lokað á algeng aðgangsorð. Prófaðu annað aðgangsorð."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Hækkandi, lækkandi eða endurtekin röð tölustafa er óheimil"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Farsímakerfi"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Nota farsímakerfi ef ekki er hægt að nota Wi‑Fi"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Ef farsímakerfi er ekki tiltækt skaltu nota Wi-Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Hringja í gegnum Wi-Fi. Ef Wi-Fi tenging slitnar lýkur símtalinu."</string>
@@ -1259,7 +1264,7 @@
     <string name="doze_title" msgid="235269029233857546">"Nýjar tilkynningar"</string>
     <string name="doze_summary" msgid="6762274282827831706">"Vekja skjáinn þegar þú færð tilkynningar"</string>
     <string name="doze_always_on_title" msgid="8555184965031789941">"Alltaf kveikt"</string>
-    <string name="doze_always_on_summary" msgid="7654436900436328950">"Sýna tíma, tilkynningartákn og aðrar upplýsingar. Aukin rafhlöðunotkun."</string>
+    <string name="doze_always_on_summary" msgid="7654436900436328950">"Sýna klukku, tilkynningartákn og aðrar upplýsingar. Aukin rafhlöðunotkun."</string>
     <string name="title_font_size" msgid="5021464556860010851">"Leturstærð"</string>
     <string name="short_summary_font_size" msgid="4141077908728522946">"Gera texta stærri eða minni"</string>
     <string name="sim_lock_settings" msgid="1986924650622642189">"Stillingar SIM-kortaláss"</string>
@@ -3454,8 +3459,8 @@
     <string name="zen_mode_event_rule_summary_reply_template" msgid="3917497077674876311">"Þar sem svarið er <xliff:g id="REPLY">%1$s</xliff:g>"</string>
     <string name="zen_mode_event_rule_calendar_any" msgid="155915101132859764">"Öll dagatöl"</string>
     <string name="zen_mode_event_rule_reply" msgid="9100941281268256319">"Þar sem svarið er"</string>
-    <string name="zen_mode_event_rule_reply_any_except_no" msgid="3344044163641764449">"„Já“, „Kannski“ eða „Ekki svarað“"</string>
-    <string name="zen_mode_event_rule_reply_yes_or_maybe" msgid="5042234361937256329">"„Já“ eða „Kannski“"</string>
+    <string name="zen_mode_event_rule_reply_any_except_no" msgid="3344044163641764449">"Já, Kannski eða Ekki svarað"</string>
+    <string name="zen_mode_event_rule_reply_yes_or_maybe" msgid="5042234361937256329">"Já eða Kannski"</string>
     <string name="zen_mode_event_rule_reply_yes" msgid="7039756546321205552">"Já"</string>
     <string name="zen_mode_rule_not_found_text" msgid="6553855397424553685">"Regla fannst ekki."</string>
     <string name="zen_mode_rule_summary_enabled_combination" msgid="8269105393636454359">"Kveikt / <xliff:g id="MODE">%1$s</xliff:g>"</string>
diff --git a/tests/CarDeveloperOptions/res/values-it/arrays.xml b/tests/CarDeveloperOptions/res/values-it/arrays.xml
index 22a26a0..a2f4d11 100644
--- a/tests/CarDeveloperOptions/res/values-it/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-it/arrays.xml
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"Non consentire mai"</item>
     <item msgid="8184570120217958741">"Consenti sempre"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normale"</item>
+    <item msgid="5101233285497327432">"Discreta"</item>
+    <item msgid="1555861583162930714">"Bassa"</item>
+    <item msgid="1719683776264798117">"Critica"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normale"</item>
+    <item msgid="6107138933849816768">"Moderata"</item>
+    <item msgid="182695359839047859">"Bassa"</item>
+    <item msgid="8577246509202964244">"Critico"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Persistente"</item>
     <item msgid="167418068739176448">"Prima attività"</item>
diff --git a/tests/CarDeveloperOptions/res/values-it/config.xml b/tests/CarDeveloperOptions/res/values-it/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-it/config.xml
+++ b/tests/CarDeveloperOptions/res/values-it/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-it/strings.xml b/tests/CarDeveloperOptions/res/values-it/strings.xml
index 89d101a..02abed3 100644
--- a/tests/CarDeveloperOptions/res/values-it/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-it/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Ingrandisci o riduci il testo sullo schermo."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Rimpicciolisci"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Ingrandisci"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Testo di esempio"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Il meraviglioso mago di Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Capitolo 11: La splendida Città di smeraldo di Oz"</string>
@@ -413,7 +412,7 @@
     <string name="face_intro_error_unknown" msgid="3241592604198351134">"Impossibile aggiungere altri volti"</string>
     <string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"Registrazione non completata"</string>
     <string name="security_settings_face_enroll_dialog_ok" msgid="1078348922734845090">"OK"</string>
-    <string name="security_settings_face_enroll_error_timeout_dialog_message" msgid="4917894418448325405">"Raggiunto il tempo limite per la registrazione del volto. Riprova."</string>
+    <string name="security_settings_face_enroll_error_timeout_dialog_message" msgid="4917894418448325405">"Hai raggiunto il tempo limite per la registrazione del volto. Riprova."</string>
     <string name="security_settings_face_enroll_error_generic_dialog_message" msgid="5160473187142616862">"Registrazione del volto non riuscita."</string>
     <string name="security_settings_face_enroll_finish_title" msgid="6800717857394410769">"Fatto. Tutto OK."</string>
     <string name="security_settings_face_enroll_done" msgid="5409739233373490971">"Fine"</string>
@@ -469,7 +468,7 @@
     <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"Tocca il sensore"</string>
     <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Appoggia il dito sul sensore e sollevalo quando senti una vibrazione"</string>
     <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"Solleva, quindi tocca di nuovo"</string>
-    <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Solleva ripetutamente il dito per aggiungere le diverse parti dell\'impronta digitale"</string>
+    <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Solleva ripetutamente il dito per aggiungere le varie parti dell\'impronta"</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"Impronta aggiunta"</string>
     <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"Quando vedi questa icona, usa l\'impronta digitale per identificarti o autorizzare gli acquisti"</string>
     <string name="security_settings_fingerprint_enroll_enrolling_skip" msgid="1473280156532146933">"Più tardi"</string>
@@ -489,7 +488,7 @@
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"Ops, questo non è il sensore"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"Tocca il sensore sulla parte posteriore del telefono. Utilizza il dito indice."</string>
     <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"Registrazione non completata"</string>
-    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Raggiunto tempo limite per la registrazione dell\'impronta digitale. Riprova."</string>
+    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Hai raggiunto il tempo limite per la registrazione dell\'impronta digitale. Riprova."</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"Registrazione dell\'impronta digitale non riuscita. Riprova o utilizza un dito diverso."</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"Aggiungine un\'altra"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"Avanti"</string>
@@ -499,10 +498,10 @@
     <string name="fingerprint_add_max" msgid="2939393314646115661">"Puoi aggiungere fino a <xliff:g id="COUNT">%d</xliff:g> impronte digitali"</string>
     <string name="fingerprint_intro_error_max" msgid="3247720976621039437">"Hai aggiunto il numero massimo di impronte digitali"</string>
     <string name="fingerprint_intro_error_unknown" msgid="3975674268256524015">"Impossibile aggiungere ulteriori impronte digitali"</string>
-    <string name="fingerprint_last_delete_title" msgid="3104596858161269635">"Rimuovere tutte le impronte digitali?"</string>
+    <string name="fingerprint_last_delete_title" msgid="3104596858161269635">"Rimuovere tutte le impronte?"</string>
     <string name="fingerprint_delete_title" msgid="3120894112324235536">"Rimuovi \"<xliff:g id="FINGERPRINT_ID">%1$s</xliff:g>\""</string>
     <string name="fingerprint_delete_message" msgid="5895802741486967970">"Vuoi eliminare questa impronta digitale?"</string>
-    <string name="fingerprint_last_delete_message" msgid="3346252479778971442">"Non potrai più utilizzare le impronte digitali per sbloccare il telefono, autorizzare gli acquisti o accedere alle app."</string>
+    <string name="fingerprint_last_delete_message" msgid="3346252479778971442">"Non potrai più utilizzare le impronte per sbloccare il telefono, autorizzare gli acquisti o accedere alle app."</string>
     <string name="fingerprint_last_delete_message_profile_challenge" msgid="5385095150532247025">"Non potrai utilizzare le impronte digitali per sbloccare il profilo di lavoro, autorizzare gli acquisti o accedere alle app di lavoro."</string>
     <string name="fingerprint_last_delete_confirm" msgid="7984595457589664004">"Sì, rimuovi"</string>
     <string name="crypt_keeper_settings_title" msgid="839783588093862748">"Crittografia"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Deve contenere meno di <xliff:g id="NUMBER_1">%d</xliff:g> cifre</item>
       <item quantity="one">Deve contenere meno di <xliff:g id="NUMBER_0">%d</xliff:g> cifra</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Deve contenere solo cifre da 0 a 9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"L\'amministratore del dispositivo non consente l\'utilizzo di un PIN recente"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"I PIN comuni sono stati bloccati dall\'amministratore IT. Prova a usare un altro PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Non può contenere un carattere non valido"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Deve contenere almeno <xliff:g id="COUNT">%d</xliff:g> caratteri non costituiti da una lettera</item>
       <item quantity="one">Deve contenere almeno 1 carattere non costituito da una lettera</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Deve contenere almeno <xliff:g id="COUNT">%d</xliff:g> caratteri non numerici</item>
+      <item quantity="one">Deve contenere almeno 1 carattere non numerico</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"L\'amministratore del dispositivo non consente l\'utilizzo di una password recente."</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Le password comuni sono state bloccate dall\'amministratore IT. Prova a usare un\'altra password."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Non sono consentite sequenze di cifre in ordine ascendente o discendente oppure ripetute"</string>
@@ -709,7 +711,7 @@
     <string name="lockpattern_tutorial_cancel_label" msgid="450401426127674369">"Annulla"</string>
     <string name="lockpattern_tutorial_continue_label" msgid="8474690922559443018">"Avanti"</string>
     <string name="lock_setup" msgid="8710689848703935088">"Impostazione completata."</string>
-    <string name="manage_device_admin" msgid="322047441168191695">"App di amministrazione dispositivo"</string>
+    <string name="manage_device_admin" msgid="322047441168191695">"App di amministrazione del dispositivo"</string>
     <string name="number_of_device_admins_none" msgid="8519193548630223132">"Nessuna app attiva"</string>
     <plurals name="number_of_device_admins" formatted="false" msgid="6445613288828151224">
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> app attive</item>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Rete mobile"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Se il Wi‑Fi non è disponibile, usa la rete mobile"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Se la rete mobile non è disponibile, usa il Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Chiamata tramite Wi‑Fi. Se il Wi‑Fi viene perso, la chiamata termina."</string>
@@ -1209,7 +1214,7 @@
     <string name="night_display_text" msgid="5330502493684652527">"Con la funzione Luminosità notturna, il tuo schermo diventa color ambra. In questo modo potrai guardarlo senza sforzare la vista o leggere in condizioni di luce attenuata e potrai addormentarti più facilmente."</string>
     <string name="night_display_auto_mode_title" msgid="8493573087102481588">"Pianificazione"</string>
     <string name="night_display_auto_mode_never" msgid="2897444637217807088">"Nessuna"</string>
-    <string name="night_display_auto_mode_custom" msgid="1400891076453963151">"Attiva in un orario personalizzato"</string>
+    <string name="night_display_auto_mode_custom" msgid="1400891076453963151">"Attiva in orario personalizzato"</string>
     <string name="night_display_auto_mode_twilight" msgid="4000162110017520674">"Attiva dal tramonto all\'alba"</string>
     <string name="night_display_start_time_title" msgid="1069255169673371077">"Ora inizio"</string>
     <string name="night_display_end_time_title" msgid="2760793157124245911">"Ora fine"</string>
@@ -1713,7 +1718,7 @@
     <string name="lockpassword_confirm_your_pin_header" msgid="4335593948303036343">"Inserisci di nuovo il PIN"</string>
     <string name="lockpassword_confirm_passwords_dont_match" msgid="1783767008133345784">"Le password non corrispondono"</string>
     <string name="lockpassword_confirm_pins_dont_match" msgid="5444357293637748942">"I PIN non corrispondono"</string>
-    <string name="lockpassword_draw_your_pattern_again_header" msgid="9017394036814402348">"Traccia di nuovo la sequenza"</string>
+    <string name="lockpassword_draw_your_pattern_again_header" msgid="9017394036814402348">"Inserisci di nuovo la sequenza"</string>
     <string name="lockpassword_choose_lock_generic_header" msgid="4418423132980560119">"Seleziona metodo di sblocco"</string>
     <string name="lockpassword_password_set_toast" msgid="601928982984489868">"Password impostata"</string>
     <string name="lockpassword_pin_set_toast" msgid="172594825722240059">"PIN impostato"</string>
@@ -4264,7 +4269,7 @@
     <string name="storage_manager_indicator_on" msgid="5295306384982062320">"Attiva"</string>
     <string name="install_type_instant" msgid="6248487669862821874">"App istantanea"</string>
     <string name="automatic_storage_manager_deactivation_warning" msgid="7867793739491286374">"Disattivare la gestione della memoria?"</string>
-    <string name="storage_movies_tv" msgid="7282484273991655296">"App per film e programmi televisivi"</string>
+    <string name="storage_movies_tv" msgid="7282484273991655296">"App per film e programmi TV"</string>
     <string name="carrier_provisioning" msgid="3309125279191534469">"Informazioni sul provisioning operatore"</string>
     <string name="trigger_carrier_provisioning" msgid="6284005970057901477">"Attiva provisioning operatore"</string>
     <string name="zen_suggestion_title" msgid="2134699720214231950">"Aggiorna modalità Non disturbare"</string>
@@ -4320,7 +4325,7 @@
     <string name="battery_suggestion_summary" msgid="2669070349482656490"></string>
     <string name="gesture_prevent_ringing_screen_title" msgid="4173494225145223638">"Disattiva suoneria"</string>
     <string name="gesture_prevent_ringing_title" msgid="8827963588425673557">"Premi contemporaneamente i tasti di accensione e Volume su per"</string>
-    <string name="gesture_prevent_ringing_sound_title" msgid="8642330448721033641">"Scorciatoia per impedire al telefono di suonare"</string>
+    <string name="gesture_prevent_ringing_sound_title" msgid="8642330448721033641">"Scorciatoia per disattivare la suoneria"</string>
     <string name="prevent_ringing_option_vibrate" msgid="6456505293904544108">"Vibrazione"</string>
     <string name="prevent_ringing_option_mute" msgid="53662688921253613">"Disattiva audio"</string>
     <string name="prevent_ringing_option_none" msgid="1450985763137666231">"Non fare niente"</string>
diff --git a/tests/CarDeveloperOptions/res/values-iw/arrays.xml b/tests/CarDeveloperOptions/res/values-iw/arrays.xml
index cf0a6b7..fb404ea 100644
--- a/tests/CarDeveloperOptions/res/values-iw/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-iw/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"הרצה ברקע"</item>
     <item msgid="6423861043647911030">"עוצמת קול של נגישות"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"מיקום"</item>
+    <item msgid="6656077694190491067">"מיקום"</item>
+    <item msgid="8790228218278477369">"מיקום"</item>
+    <item msgid="7836406246005211990">"רטט"</item>
+    <item msgid="3951439024549922598">"קרא אנשי קשר"</item>
+    <item msgid="8802152411647068">"שנה אנשי קשר"</item>
+    <item msgid="229544934599698735">"קרא יומן שיחות"</item>
+    <item msgid="7396102294405899613">"שנה יומן שיחות"</item>
+    <item msgid="3597797992398484655">"קרא יומן"</item>
+    <item msgid="2705975774250907343">"שנה יומן"</item>
+    <item msgid="4668747371441932697">"מיקום"</item>
+    <item msgid="1487578921720243646">"פירסום התראה"</item>
+    <item msgid="4636080349724146638">"מיקום"</item>
+    <item msgid="673510900286463926">"שיחת טלפון"</item>
+    <item msgid="542083422784609790">"קרא SMS/MMS"</item>
+    <item msgid="1033780373029588436">"כתוב SMS/MMS"</item>
+    <item msgid="5647111115517787488">"קבל SMS/MMS"</item>
+    <item msgid="8591105601108455893">"קבל SMS/MMS"</item>
+    <item msgid="7730995008517841903">"קבל SMS/MMS"</item>
+    <item msgid="2613033109026626086">"קבל SMS/MMS"</item>
+    <item msgid="3037159047591081136">"שלח SMS/MMS"</item>
+    <item msgid="4726682243833913568">"קרא SMS/MMS"</item>
+    <item msgid="6555678522277865572">"כתוב SMS/MMS"</item>
+    <item msgid="6981734935578130884">"שנה הגדרות"</item>
+    <item msgid="8705854389991425629">"צייר מעל"</item>
+    <item msgid="5861356020344153651">"גישה אל ההתראות"</item>
+    <item msgid="78432174621628659">"מצלמה"</item>
+    <item msgid="3986116419882154794">"הקלט אודיו"</item>
+    <item msgid="4516840825756409490">"הפעל את האודיו"</item>
+    <item msgid="6811712502798183957">"קרא לוח"</item>
+    <item msgid="2780369012602289114">"שנה לוח"</item>
+    <item msgid="2331359440170850868">"לחצני מדיה"</item>
+    <item msgid="6133599737122751231">"מיקוד אודיו"</item>
+    <item msgid="6844485713404805301">"שליטה ראשית בעוצמת קול"</item>
+    <item msgid="1600379420669104929">"עוצמת קול של דיבור"</item>
+    <item msgid="6296768210470214866">"עוצמת צלצול"</item>
+    <item msgid="510690696071629241">"עוצמת קול של מדיה"</item>
+    <item msgid="406861638631430109">"עוצמת קול של התראה"</item>
+    <item msgid="4715864795872233884">"עוצמת קול של התראות"</item>
+    <item msgid="2311478519251301183">"עוצמת קול של Bluetooth"</item>
+    <item msgid="5133991377896747027">"שמירה במצב פעיל"</item>
+    <item msgid="2464189519136248621">"מיקום"</item>
+    <item msgid="2062677934050803037">"מיקום"</item>
+    <item msgid="1735171933192715957">"קבל סטטיסטיקת שימוש"</item>
+    <item msgid="1014093788778383554">"השתק/בטל השתקה של המיקרופון"</item>
+    <item msgid="4199297950608622850">"הצגת הודעה קופצת"</item>
+    <item msgid="2527962435313398821">"הקרנת מדיה"</item>
+    <item msgid="5117506254221861929">"הפעלת VPN"</item>
+    <item msgid="8291198322681891160">"כתיבת טפט"</item>
+    <item msgid="7106921284621230961">"סיוע למבנה"</item>
+    <item msgid="4496533640894624799">"סיוע לצילום מסך"</item>
+    <item msgid="2598847264853993611">"קריאת מצב טלפון"</item>
+    <item msgid="9215610846802973353">"הוספת דואר קולי"</item>
+    <item msgid="9186411956086478261">"שימוש ב-SIP"</item>
+    <item msgid="6884763100104539558">"עיבוד שיחה יוצאת"</item>
+    <item msgid="125513972170580692">"טביעת אצבע"</item>
+    <item msgid="2556071024281275619">"חיישני גוף"</item>
+    <item msgid="617168514928339387">"קריאת שידורים סלולריים"</item>
+    <item msgid="7134693570516523585">"מיקום מדומה"</item>
+    <item msgid="7224489175375229399">"קריאת אחסון"</item>
+    <item msgid="8472735063903258202">"כתיבת אחסון"</item>
+    <item msgid="4069276819909595110">"הפעלת מסך"</item>
+    <item msgid="1228338896751121025">"קבלת חשבונות"</item>
+    <item msgid="3181581793459233672">"הרצה ברקע"</item>
+    <item msgid="2340936043025374076">"עוצמת קול של נגישות"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"קצר"</item>
     <item msgid="4816511817309094890">"בינונית"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"לעולם אל תאפשר"</item>
     <item msgid="8184570120217958741">"אפשר תמיד"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"רגיל"</item>
+    <item msgid="5101233285497327432">"בינוני"</item>
+    <item msgid="1555861583162930714">"נמוכה"</item>
+    <item msgid="1719683776264798117">"קריטי"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"רגיל"</item>
+    <item msgid="6107138933849816768">"בינוני"</item>
+    <item msgid="182695359839047859">"נמוכה"</item>
+    <item msgid="8577246509202964244">"קריטי"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"קבוע"</item>
     <item msgid="167418068739176448">"פעילות מובילה"</item>
diff --git a/tests/CarDeveloperOptions/res/values-iw/config.xml b/tests/CarDeveloperOptions/res/values-iw/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-iw/config.xml
+++ b/tests/CarDeveloperOptions/res/values-iw/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-iw/strings.xml b/tests/CarDeveloperOptions/res/values-iw/strings.xml
index 3b30e25..9f9d37e 100644
--- a/tests/CarDeveloperOptions/res/values-iw/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-iw/strings.xml
@@ -85,8 +85,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"שינוי גודל הטקסט שמופיע במסך."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"הקטנה"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"הגדלה"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"טקסט לדוגמה"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"הקוסם המופלא מארץ עוץ"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"פרק 11: עיר הברקת המופלאה של ארץ עוץ"</string>
@@ -684,7 +683,6 @@
       <item quantity="other">צריכה להכיל פחות מ-<xliff:g id="NUMBER_1">%d</xliff:g> ספרות</item>
       <item quantity="one">צריכה להכיל פחות מספרה אחת (<xliff:g id="NUMBER_0">%d</xliff:g>)</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"צריך להכיל רק את הספרות 0-9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"מנהל המכשיר לא מאפשר להשתמש בקוד גישה שנעשה בו שימוש לאחרונה"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"קודי גישה נפוצים חסומים בידי מנהל ה-IT. יש לנסות קוד גישה אחר."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"לא ניתן לכלול תו לא חוקי"</string>
@@ -727,6 +725,12 @@
       <item quantity="other">צריכה להכיל לפחות <xliff:g id="COUNT">%d</xliff:g> תווים שאינם אותיות</item>
       <item quantity="one">צריכה להכיל לפחות תו אחד שאינו אות</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="two">חייבת להכיל לפחות <xliff:g id="COUNT">%d</xliff:g> תווים שאינם מספרים</item>
+      <item quantity="many">חייבת להכיל לפחות <xliff:g id="COUNT">%d</xliff:g> תווים שאינם מספרים</item>
+      <item quantity="other">חייבת להכיל לפחות <xliff:g id="COUNT">%d</xliff:g> תווים שאינם מספרים</item>
+      <item quantity="one">חייבת להכיל לפחות תו אחד שאינו מספר</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"מנהל המכשיר לא מאפשר להשתמש בסיסמה שנעשה בה שימוש לאחרונה"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"סיסמאות נפוצות חסומות בידי מנהל ה-IT. יש לנסות סיסמה אחרת."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"אין להגדיר רצף ספרות עולה, יורד או חוזר"</string>
@@ -1134,7 +1138,10 @@
     <item msgid="3658897985297386665">"‎@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"‎@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"סלולרי"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"אם חיבור Wi‑Fi לא זמין, ייעשה שימוש ברשת סלולרית"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"אם אין רשת סלולרית זמינה יש להשתמש ב-Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"התקשרות בחיבור Wi-Fi. אם חיבור ה-Wi‑Fi יתנתק, השיחה תסתיים."</string>
@@ -2084,7 +2091,7 @@
     <string name="feature_flags_dashboard_title" msgid="3153034144122754381">"סימוני תכונות"</string>
     <string name="talkback_title" msgid="3717960404234260050">"Talkback"</string>
     <string name="talkback_summary" msgid="6602857105831641574">"קורא מסך המיועד בעיקר לעיוורים או לבעלי ראייה לקויה"</string>
-    <string name="select_to_speak_summary" msgid="7514180457557735421">"הקש על פריטים במסך כדי לשמוע הקראה שלהם"</string>
+    <string name="select_to_speak_summary" msgid="7514180457557735421">"ניתן להקיש על פריטים במסך כדי לשמוע הקראה שלהם"</string>
     <string name="accessibility_captioning_title" msgid="5878371993023439642">"כתוביות"</string>
     <string name="accessibility_screen_magnification_title" msgid="7250949681883917360">"הגדלה"</string>
     <string name="accessibility_screen_magnification_gestures_title" msgid="9199287875401817974">"הגדלה על-ידי הקשה שלוש פעמים"</string>
@@ -3473,7 +3480,7 @@
     <string name="picture_in_picture_empty_text" msgid="8664071475324685241">"אין אפליקציות מותקנות שתומכות ב\'תמונה בתוך תמונה\'"</string>
     <string name="picture_in_picture_keywords" msgid="7326958702002259262">"תמונה בתוך תמונה"</string>
     <string name="picture_in_picture_app_detail_title" msgid="3916189052657425936">"תמונה בתוך תמונה"</string>
-    <string name="picture_in_picture_app_detail_switch" msgid="747422998967185418">"עם תמונה בתוך תמונה"</string>
+    <string name="picture_in_picture_app_detail_switch" msgid="747422998967185418">"תמונה בתוך תמונה"</string>
     <string name="picture_in_picture_app_detail_summary" msgid="918632751775525347">"אפליקציה זו תוכל ליצור חלון מסוג תמונה-בתוך-תמונה בזמן שהיא תהיה פתוחה או לאחר היציאה ממנה (למשל, כדי להמשיך לצפות בסרטון). חלון זה מוצג מעל אפליקציות אחרות שנמצאות בשימוש."</string>
     <string name="manage_zen_access_title" msgid="3058206309728524196">"גישה אל \'נא לא להפריע\'"</string>
     <string name="zen_access_detail_switch" msgid="8706332327904974500">"הפעלת ההרשאה \'נא לא להפריע\'"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ja/arrays.xml b/tests/CarDeveloperOptions/res/values-ja/arrays.xml
index fc69723..af8b5ec 100644
--- a/tests/CarDeveloperOptions/res/values-ja/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-ja/arrays.xml
@@ -85,7 +85,7 @@
     <item msgid="8058143476674427024">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>に接続中..."</item>
     <item msgid="7547609081339573756">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>で認証しています..."</item>
     <item msgid="5145158315060185414">"IPアドレスを<xliff:g id="NETWORK_NAME">%1$s</xliff:g>から取得しています..."</item>
-    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>に接続しました"</item>
+    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> に接続済み"</item>
     <item msgid="6600156231416890902">"強制停止"</item>
     <item msgid="4133290864821295785">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>から切断中..."</item>
     <item msgid="3980154971187953257">"切断"</item>
@@ -170,7 +170,7 @@
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"なし"</item>
     <item msgid="1464741437353223198">"マニュアル"</item>
-    <item msgid="5793600062487886090">"プロキシの自動設定"</item>
+    <item msgid="5793600062487886090">"プロキシを自動設定"</item>
   </string-array>
   <string-array name="apn_auth_entries">
     <item msgid="7099647881902405997">"なし"</item>
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"許可しない"</item>
     <item msgid="8184570120217958741">"常に許可する"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"標準"</item>
+    <item msgid="5101233285497327432">"やや良好"</item>
+    <item msgid="1555861583162930714">"低"</item>
+    <item msgid="1719683776264798117">"残りわずか"</item>
+    <item msgid="1567326459340152525">"不明"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"標準"</item>
+    <item msgid="6107138933849816768">"やや不足"</item>
+    <item msgid="182695359839047859">"低"</item>
+    <item msgid="8577246509202964244">"重大"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"常駐"</item>
     <item msgid="167418068739176448">"上位のアクティビティ"</item>
@@ -463,11 +473,11 @@
   </string-array>
   <string-array name="wifi_metered_entries">
     <item msgid="4329206416008519163">"自動的に検出"</item>
-    <item msgid="773943026484148895">"従量制として処理"</item>
-    <item msgid="1008268820118852416">"定額制として処理"</item>
+    <item msgid="773943026484148895">"従量制として扱う"</item>
+    <item msgid="1008268820118852416">"定額制として扱う"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
-    <item msgid="6545683814310036454">"ランダムな MAC を使用する(デフォルト)"</item>
+    <item msgid="6545683814310036454">"ランダム MAC を使用(デフォルト)"</item>
     <item msgid="214234417308375326">"デバイスの MAC を使用する"</item>
   </string-array>
   <string-array name="wifi_hidden_entries">
diff --git a/tests/CarDeveloperOptions/res/values-ja/config.xml b/tests/CarDeveloperOptions/res/values-ja/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-ja/config.xml
+++ b/tests/CarDeveloperOptions/res/values-ja/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-ja/strings.xml b/tests/CarDeveloperOptions/res/values-ja/strings.xml
index ff4be74..218aa51 100644
--- a/tests/CarDeveloperOptions/res/values-ja/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ja/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"画面上のテキストのサイズを変更します。"</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"縮小"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"拡大"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"サンプル テキスト"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"オズの魔法使い"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"第 11 章: オズの不思議なエメラルド シティ"</string>
@@ -310,8 +309,8 @@
     <string name="cellular_data_summary" msgid="8817717603450318646">"モバイル ネットワークでのデータ使用を許可"</string>
     <string name="allow_data_usage_title" msgid="5381624105803294315">"ローミング時にデータ使用を許可"</string>
     <string name="roaming" msgid="8860308342135146004">"ローミング"</string>
-    <string name="roaming_enable" msgid="2108142024297441116">"ローミング中にデータサービスに接続する"</string>
-    <string name="roaming_disable" msgid="1915440242079953809">"ローミング中にデータサービスに接続する"</string>
+    <string name="roaming_enable" msgid="2108142024297441116">"ローミング中にデータサービスに接続"</string>
+    <string name="roaming_disable" msgid="1915440242079953809">"ローミング中にデータサービスに接続"</string>
     <string name="roaming_reenable_message" msgid="8388505868655113258">"データローミングをOFFにしたままホームネットワークの外に出たためデータ接続が切断されました。"</string>
     <string name="roaming_turn_it_on_button" msgid="4370846458830537578">"ONにする"</string>
     <string name="roaming_warning" msgid="5488050911277592868">"高額な通信料が発生することがあります。"</string>
@@ -356,10 +355,10 @@
     <string name="security_enable_widgets_title" msgid="1701510007926738088">"ウィジェットの有効化"</string>
     <string name="security_enable_widgets_disabled_summary" msgid="4408176087132339331">"管理アプリによって無効化"</string>
     <string name="lockdown_settings_title" msgid="4534779922580115990">"ロックダウン オプションの表示"</string>
-    <string name="lockdown_settings_summary" msgid="7270756909878256174">"Smart Lock、指紋認証によるロック解除、ロック画面上の通知を無効にする電源ボタン オプションを表示します"</string>
+    <string name="lockdown_settings_summary" msgid="7270756909878256174">"Smart Lock、指紋認証によるロック解除、ロック画面上の通知をすべて無効にするオプションを、電源ボタンの長押しで表示します"</string>
     <string name="trust_agents_extend_unlock_title" msgid="3582017561316089951">"信頼エージェントはロック解除の延長のみ"</string>
     <string name="trust_agents_extend_unlock_summary" msgid="3543997596586078084">"有効にすると、信頼エージェントによりデバイスのロック解除状態が延長されます。ただし、ロック状態のデバイスのロックは解除できなくなります。"</string>
-    <string name="trust_lost_locks_screen_title" msgid="3094736590690459372">"信頼が失われた場合に画面をロックする"</string>
+    <string name="trust_lost_locks_screen_title" msgid="3094736590690459372">"信頼が失われた場合に画面をロック"</string>
     <string name="trust_lost_locks_screen_summary" msgid="2058567484625606803">"有効にすると、前回の信頼エージェントの信頼が失われたときにデバイスがロックされます。"</string>
     <string name="owner_info_settings_summary" msgid="4208702251226725583">"なし"</string>
     <string name="owner_info_settings_status" msgid="8049975536717685126">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="COUNT_1">%2$d</xliff:g>"</string>
@@ -468,7 +467,7 @@
     <string name="security_settings_fingerprint_enroll_dialog_delete" msgid="4312297515772004580">"削除"</string>
     <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"センサーに触れる"</string>
     <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"指をセンサーに当て、振動したら離します。"</string>
-    <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"指を離してからもう一度触れる"</string>
+    <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"指をタッチして離す"</string>
     <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"指を何度か離して、あらゆる角度から指紋を登録します。"</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"指紋の登録完了"</string>
     <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"このアイコンが表示されているときは、本人確認や購入の承認に指紋認証を使用できます"</string>
@@ -668,7 +667,6 @@
       <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> 桁未満にしてください</item>
       <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> 桁未満にしてください</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"使用できるのは 0~9 の数字のみです"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"デバイス管理により、最近使用した PIN は使用できません"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"一般的な PIN は IT 管理者によってブロックされています。別の PIN をお試しください。"</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"無効な文字があります"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">記号または数字が <xliff:g id="COUNT">%d</xliff:g> つ以上必要です</item>
       <item quantity="one">記号または数字が 1 つ以上必要です</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">数字以外の文字を <xliff:g id="COUNT">%d</xliff:g> 個以上使用してください</item>
+      <item quantity="one">数字以外の文字を 1 個以上使用してください</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"デバイス管理により、最近使用したパスワードは使用できません"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"一般的なパスワードは IT 管理者によってブロックされています。別のパスワードをお試しください。"</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"一連の数字を昇順や降順にしたり、繰り返したりすることはできません"</string>
@@ -797,14 +799,14 @@
     <string name="bluetooth_max_connected_audio_devices_string" msgid="6799012540303500020">"接続できる Bluetooth オーディオ デバイスの上限"</string>
     <string name="bluetooth_max_connected_audio_devices_dialog_title" msgid="6049527354499590314">"接続できる Bluetooth オーディオ デバイス数の上限の選択"</string>
     <string name="wifi_display_settings_title" msgid="8718182672694575456">"キャスト"</string>
-    <string name="wifi_display_enable_menu_item" msgid="4578340247147692250">"ワイヤレスディスプレイの有効化"</string>
+    <string name="wifi_display_enable_menu_item" msgid="4578340247147692250">"ワイヤレス ディスプレイの有効化"</string>
     <string name="wifi_display_no_devices_found" msgid="186501729518830451">"周辺にデバイスが見つかりません"</string>
     <string name="wifi_display_status_connecting" msgid="3799827425457383349">"接続中"</string>
     <string name="wifi_display_status_connected" msgid="85692409327461403">"接続済み"</string>
     <string name="wifi_display_status_in_use" msgid="7646114501132773174">"使用中"</string>
     <string name="wifi_display_status_not_available" msgid="5600448733204688205">"ご利用いただけません"</string>
     <string name="wifi_display_details" msgid="6379855523460749126">"ディスプレイの設定"</string>
-    <string name="wifi_display_options_title" msgid="4587264519668872213">"ワイヤレスディスプレイのオプション"</string>
+    <string name="wifi_display_options_title" msgid="4587264519668872213">"ワイヤレス ディスプレイのオプション"</string>
     <string name="wifi_display_options_forget" msgid="7882982544626742073">"削除"</string>
     <string name="wifi_display_options_done" msgid="5922060890309265817">"完了"</string>
     <string name="wifi_display_options_name" msgid="8477627781133827607">"名前"</string>
@@ -820,7 +822,7 @@
     <string name="art_verifier_for_debuggable_summary" msgid="2204242476996701111">"ART にデバッグ可能なアプリのバイトコードの確認を許可する"</string>
     <string name="nfc_quick_toggle_title" msgid="4990697912813795002">"NFC"</string>
     <string name="nfc_quick_toggle_summary" product="tablet" msgid="983451155092850657">"タブレットが他のデバイスと接触したときのデータ交換を許可する"</string>
-    <string name="nfc_quick_toggle_summary" product="default" msgid="7141056939052895142">"デバイスが他のデバイスと接触したときのデータ交換を許可する"</string>
+    <string name="nfc_quick_toggle_summary" product="default" msgid="7141056939052895142">"他のデバイスと接触したときのデータ交換を許可します"</string>
     <string name="nfc_disclaimer_title" msgid="4860231267351602970">"NFC を ON にする"</string>
     <string name="nfc_disclaimer_content" msgid="3066113577854565782">"NFC がこのデバイスと他の付近のデバイスまたはターゲット(決済デバイス、アクセス リーダー、インタラクティブ広告またはタグなど)の間でデータのやり取りを行います。"</string>
     <string name="nfc_secure_settings_title" msgid="5153751163174916581">"NFC の保護"</string>
@@ -860,7 +862,7 @@
     <string name="use_open_wifi_automatically_summary_scorer_unsupported_disabled" msgid="1123080670578756834">"この機能を使用するには、対応するネットワーク評価プロバイダを選択してください"</string>
     <string name="wifi_install_credentials" msgid="5650088113710858289">"証明書のインストール"</string>
     <string name="wifi_scan_notify_text" msgid="7614101215028336927">"位置情報の精度を向上させるため、Wi‑Fi が OFF の場合でも、アプリやサービスはいつでも Wi‑Fi ネットワークをスキャンできます。この設定は、位置情報を使用する機能やサービスの改善などに役立ちます。この設定は<xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>スキャンの設定<xliff:g id="LINK_END_1">LINK_END</xliff:g>で変更できます。"</string>
-    <string name="wifi_scan_notify_text_scanning_off" msgid="723796963816095410">"位置情報の精度を上げるには、<xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>スキャンの設定<xliff:g id="LINK_END_1">LINK_END</xliff:g>で Wi-Fi スキャンをオンにしてください。"</string>
+    <string name="wifi_scan_notify_text_scanning_off" msgid="723796963816095410">"位置情報の精度を上げるには、<xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>スキャンの設定<xliff:g id="LINK_END_1">LINK_END</xliff:g>で Wi-Fi スキャンを ON にしてください。"</string>
     <string name="wifi_scan_notify_remember_choice" msgid="1235445971400237444">"次回から表示しない"</string>
     <string name="wifi_setting_sleep_policy_title" msgid="2120785188625932076">"スリープ時にWi-Fi接続を維持"</string>
     <string name="wifi_setting_on_during_sleep_title" msgid="856670183023402715">"スリープ時にWi-Fi接続を維持"</string>
@@ -886,7 +888,7 @@
     <string name="wifi_menu_remember" msgid="717257200269700641">"ネットワークを保存"</string>
     <string name="wifi_menu_forget" msgid="7561140554450163075">"ネットワークを削除"</string>
     <string name="wifi_menu_modify" msgid="4080178040721021101">"ネットワークを変更"</string>
-    <string name="wifi_empty_list_wifi_off" msgid="272877164691346240">"利用可能なネットワークを表示するにはWi-FiをON"</string>
+    <string name="wifi_empty_list_wifi_off" msgid="272877164691346240">"利用可能なネットワークを表示するには Wi-Fi を ON にします。"</string>
     <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"Wi-Fiネットワークを検索しています…"</string>
     <string name="wifi_empty_list_user_restricted" msgid="2341613007817352431">"Wi-Fiネットワークを変更する権限がありません。"</string>
     <string name="wifi_more" msgid="3538241640407382185">"その他"</string>
@@ -931,14 +933,14 @@
     <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"Wi‑Fi アクセス ポイントの帯域幅を少なくとも 1 つ選択してください。"</string>
     <string name="wifi_ip_settings" msgid="4636102290236116946">"IP 設定"</string>
     <string name="wifi_privacy_settings" msgid="4462092795794247809">"プライバシー"</string>
-    <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"ランダム化 MAC"</string>
+    <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"ランダム MAC"</string>
     <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"デバイスの追加"</string>
-    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"「<xliff:g id="SSID">%1$s</xliff:g>」にデバイスを追加するには、下記の中心に QR コードを合わせてください"</string>
+    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"「<xliff:g id="SSID">%1$s</xliff:g>」にデバイスを追加するには、下の枠に QR コードを合わせてください"</string>
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"QR コードのスキャン"</string>
     <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"「<xliff:g id="SSID">%1$s</xliff:g>」に接続するには、下記の中心に QR コードを合わせてください"</string>
     <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"Wi‑Fi に接続するには、QR コードをスキャンしてください"</string>
     <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Wi‑Fi の共有"</string>
-    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"「<xliff:g id="SSID">%1$s</xliff:g>」に接続してパスワードを共有するには、この QR コードをスキャンしてください"</string>
+    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"この QR コードをスキャンすると、パスワードが共有されて「<xliff:g id="SSID">%1$s</xliff:g>」に接続できます"</string>
     <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"「<xliff:g id="SSID">%1$s</xliff:g>」に接続するには、この QR コードをスキャンしてください"</string>
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"QR コードを読み取れませんでした。コードを再度中央に捉えて、もう一度お試しください"</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"もう一度お試しください。問題が解決しない場合は、デバイスのメーカーにお問い合わせください"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"モバイル"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Wi‑Fi が利用できない場合は、モバイル ネットワークを使用します"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"モバイル ネットワークが使用できない場合は、Wi‑Fi を使用します"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Wi‑Fi 経由で通話します。Wi‑Fi が切断されると、通話は終了します。"</string>
@@ -1153,7 +1158,7 @@
     <string name="dock_not_found_title" msgid="2035088760477532435">"ホルダーが見つかりません"</string>
     <string name="dock_not_found_text" product="tablet" msgid="5996654431405111902">"ホルダーの音声を設定するにはタブレットをホルダーに装着する必要があります。"</string>
     <string name="dock_not_found_text" product="default" msgid="8275091896320216368">"ホルダーの音声を設定するにはデバイスをホルダーに装着する必要があります。"</string>
-    <string name="dock_sounds_enable_title" msgid="3385931465312084061">"ホルダー装着時の音"</string>
+    <string name="dock_sounds_enable_title" msgid="3385931465312084061">"ドッキング時の音"</string>
     <string name="dock_sounds_enable_summary_on" product="tablet" msgid="4322104626905111669">"タブレットのホルダー脱着時に音を鳴らす"</string>
     <string name="dock_sounds_enable_summary_on" product="default" msgid="2751810717801098293">"携帯のホルダー脱着時に音を鳴らす"</string>
     <string name="dock_sounds_enable_summary_off" product="tablet" msgid="2125391395745266946">"タブレットのホルダー脱着時に音を鳴らさない"</string>
@@ -1204,7 +1209,7 @@
     <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"ON / 見ている間は画面が OFF になりません"</string>
     <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"OFF"</string>
     <string name="adaptive_sleep_description" msgid="812673735459170009">"見ている間は画面が OFF にならなくなります。"</string>
-    <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Screen Aware は前面カメラを使用して、ユーザーが画面を見ているかどうかを検出します。この検出はデバイスのみで行われ、画像が保存されたり、Google に送信されたりすることはありません。"</string>
+    <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Screen Aware は前面カメラを使用して、ユーザーが画面を見ているかどうかを検出します。この検出はデバイスのみで行われます。画像が保存されたり、Google に送信されたりすることはありません。"</string>
     <string name="night_display_title" msgid="1305002424893349814">"夜間モード"</string>
     <string name="night_display_text" msgid="5330502493684652527">"夜間モードを利用すると画面が黄味がかった色になります。薄明かりの下でも画面を見やすくなり、寝付きを良くする効果も期待できます。"</string>
     <string name="night_display_auto_mode_title" msgid="8493573087102481588">"スケジュール"</string>
@@ -1241,13 +1246,13 @@
     <string name="wallpaper_suggestion_summary" msgid="4247262938988875842">"画面のカスタマイズ"</string>
     <string name="wallpaper_settings_fragment_title" msgid="1503701065297188901">"壁紙タイプの選択"</string>
     <string name="screensaver_settings_title" msgid="7720091234133721021">"スクリーンセーバー"</string>
-    <string name="screensaver_settings_summary_either_long" msgid="6078038506795498288">"充電時またはホルダー装着時"</string>
+    <string name="screensaver_settings_summary_either_long" msgid="6078038506795498288">"充電時またはドッキング時"</string>
     <string name="screensaver_settings_summary_either_short" msgid="2453772128682850053">"いずれか"</string>
     <string name="screensaver_settings_summary_sleep" msgid="6097363596749362692">"充電時"</string>
-    <string name="screensaver_settings_summary_dock" msgid="6297808146601570196">"ホルダー装着時"</string>
+    <string name="screensaver_settings_summary_dock" msgid="6297808146601570196">"ドッキング時"</string>
     <string name="screensaver_settings_summary_never" msgid="3995259444981620707">"なし"</string>
     <string name="screensaver_settings_summary_off" msgid="6119947316484763131">"OFF"</string>
-    <string name="screensaver_settings_disabled_prompt" msgid="1897518064782596947">"スマートフォンのホルダー装着時やスリープ時の動作を管理するには、スクリーン セーバーを ON にします。"</string>
+    <string name="screensaver_settings_disabled_prompt" msgid="1897518064782596947">"スマートフォンのドッキング時やスリープ時の動作を管理するには、スクリーン セーバーを ON にします。"</string>
     <string name="screensaver_settings_when_to_dream" msgid="3763052013516826348">"起動するタイミング"</string>
     <string name="screensaver_settings_current" msgid="4017556173596361672">"現在のスクリーンセーバー"</string>
     <string name="screensaver_settings_dream_start" msgid="3772227299054662550">"今すぐ起動"</string>
@@ -1352,7 +1357,7 @@
     <string name="status_signal_strength" msgid="4302597886933728789">"電波強度"</string>
     <string name="status_roaming" msgid="5191044997355099561">"ローミング"</string>
     <string name="status_operator" msgid="6017986100643755390">"ネットワーク"</string>
-    <string name="status_wifi_mac_address" msgid="3868452167971295995">"Wi-Fi MACアドレス"</string>
+    <string name="status_wifi_mac_address" msgid="3868452167971295995">"Wi-Fi MAC アドレス"</string>
     <string name="status_bt_address" msgid="460568179311735657">"Bluetoothアドレス"</string>
     <string name="status_serial_number" msgid="8257722124627415159">"シリアル番号"</string>
     <string name="status_up_time" msgid="77128395333934087">"稼働時間"</string>
@@ -1567,11 +1572,11 @@
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"ネットワーク、アプリ、デバイスをリセットできます"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"Wi-Fi、モバイル、Bluetooth をリセット"</string>
     <string name="reset_network_desc" msgid="4982633363916261109">"以下を含む、すべてのネットワーク設定がリセットされます。\n\n"<li>"Wi‑Fi"</li>\n<li>"モバイルデータ"</li>\n<li>"Bluetooth"</li></string>
-    <string name="reset_esim_title" msgid="7630781767040831893">"ダウンロード型 SIM の消去"</string>
-    <string name="reset_esim_desc" msgid="433226911566802">"交換用 SIM のダウンロードについては、携帯通信会社にお問い合わせください。この操作でモバイルのサービスプランが解約されることはありません。"</string>
+    <string name="reset_esim_title" msgid="7630781767040831893">"ダウンロードされた eSIM の消去"</string>
+    <string name="reset_esim_desc" msgid="433226911566802">"別の eSIM をダウンロードするには、携帯通信会社にお問い合わせください。この操作でモバイルのサービスプランが解約されることはありません。"</string>
     <string name="reset_network_button_text" msgid="4293271046867912819">"設定をリセット"</string>
     <string name="reset_network_final_desc" msgid="2463817067048751373">"すべてのネットワーク設定をリセットしますか?この操作を取り消すことはできません。"</string>
-    <string name="reset_network_final_desc_esim" msgid="4676436976372555750">"すべてのネットワーク設定をリセットして、ダウンロード型 SIM を消去しますか?この操作を取り消すことはできません。"</string>
+    <string name="reset_network_final_desc_esim" msgid="4676436976372555750">"すべてのネットワーク設定をリセットして、ダウンロードされた eSIM を消去しますか?この操作を取り消すことはできません。"</string>
     <string name="reset_network_final_button_text" msgid="345255333127794393">"設定をリセット"</string>
     <string name="reset_network_confirm_title" msgid="2432145031070536008">"リセットしますか?"</string>
     <string name="network_reset_not_available" msgid="6146655531868016281">"ネットワークのリセットはこのユーザーには許可されていません"</string>
@@ -1642,7 +1647,7 @@
     <string name="mobile_insert_sim_card" msgid="7594550403454243732">"SIMカードを挿入して再起動してください"</string>
     <string name="mobile_connect_to_internet" msgid="6031886097365170913">"インターネットに接続してください"</string>
     <string name="location_title" msgid="8664674161765477168">"現在地"</string>
-    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"仕事用プロファイルの場所"</string>
+    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"仕事用プロファイルで位置情報を使用"</string>
     <string name="location_app_level_permissions" msgid="1298041503927632960">"アプリの権限"</string>
     <string name="location_app_permission_summary_location_off" msgid="541372845344796336">"位置情報は OFF です"</string>
     <plurals name="location_app_permission_summary_location_on" formatted="false" msgid="7904821382328758218">
@@ -1965,7 +1970,7 @@
     <string name="keyboard_assistance_category" msgid="2276351807419818125">"キーボード補助機能"</string>
     <string name="physical_keyboard_title" msgid="3508591962962814313">"物理キーボード"</string>
     <string name="show_ime" msgid="7322620473198763563">"仮想キーボードの表示"</string>
-    <string name="show_ime_summary" msgid="3246628154011464373">"物理キーボードが有効になっていても画面に表示されます"</string>
+    <string name="show_ime_summary" msgid="3246628154011464373">"物理キーボードが有効になっていても画面に表示させます"</string>
     <string name="keyboard_shortcuts_helper" msgid="6574386807271399788">"キーボード ショートカット ヘルパー"</string>
     <string name="keyboard_shortcuts_helper_summary" msgid="8024313306403779742">"使用可能なショートカットを表示します"</string>
     <string name="language_and_input_for_work_category_title" msgid="2053255944038892588">"仕事用プロファイルのキーボードとツール"</string>
@@ -2064,8 +2069,8 @@
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"画面の拡大を自動更新"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"アプリの遷移時に画面の拡大を更新"</string>
     <string name="accessibility_power_button_ends_call_prerefence_title" msgid="6172987104538172869">"電源ボタンで通話を終了"</string>
-    <string name="accessibility_toggle_large_pointer_icon_title" msgid="9127905775116570565">"大きなマウスポインタ"</string>
-    <string name="accessibility_disable_animations" msgid="8378441317115710009">"アニメーションの削除"</string>
+    <string name="accessibility_toggle_large_pointer_icon_title" msgid="9127905775116570565">"マウスポインタを拡大"</string>
+    <string name="accessibility_disable_animations" msgid="8378441317115710009">"アニメーションを無効化"</string>
     <string name="accessibility_toggle_master_mono_title" msgid="899550848196702565">"モノラル音声"</string>
     <string name="accessibility_toggle_master_mono_summary" msgid="3847052868469033235">"音声再生時のチャンネルを統合する"</string>
     <string name="accessibility_toggle_master_balance_title" msgid="8723492001092647562">"オーディオ バランス"</string>
@@ -2079,11 +2084,11 @@
     <string name="accessibility_content_timeout_preference_title" msgid="5160746882250939464">"表示しておく時間"</string>
     <string name="accessibility_control_timeout_preference_title" msgid="2771808346038759474">"操作を行う時間"</string>
     <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"表示可能な時間が限られているメッセージの表示時間を指定してください。\n\nこの設定に対応していないアプリもあります。"</string>
-    <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"操作が必要にもかかわらず、短い時間しか表示されないメッセージの表示時間を指定してください。\n\nこの設定に対応していないアプリもあります。"</string>
+    <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"短い時間しか表示されない操作要求メッセージについて、表示時間を指定してください。\n\nこの設定に対応していないアプリもあります。"</string>
     <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"長押しする時間"</string>
     <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"色反転"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"パフォーマンスに影響することがあります"</string>
-    <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"停止時間"</string>
+    <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"静止時間"</string>
     <string name="accessibility_autoclick_description" msgid="5492414927846407499">"マウスを使用している場合は、カーソルの動きが一定時間停止したときに自動的に操作を行うよう設定できます。"</string>
     <string name="accessibility_autoclick_delay_preference_title" msgid="8303022510942147049">"クリックまでの時間"</string>
     <string name="accessibility_vibration_settings_title" msgid="1902649657883159406">"バイブレーション"</string>
@@ -2136,9 +2141,9 @@
     <string name="accessibility_vibration_summary_medium" msgid="3141272492346527298">"着信と通知は [中] に設定されています"</string>
     <string name="accessibility_vibration_summary_high" msgid="4188677504368202861">"着信と通知は [高] に設定されています"</string>
     <string name="accessibility_vibration_intensity_off" msgid="4427927348723998194">"OFF"</string>
-    <string name="accessibility_vibration_intensity_low" msgid="8250688473513963211">"低"</string>
+    <string name="accessibility_vibration_intensity_low" msgid="8250688473513963211">"弱"</string>
     <string name="accessibility_vibration_intensity_medium" msgid="2249931147940383011">"中"</string>
-    <string name="accessibility_vibration_intensity_high" msgid="7850793704772123134">"高"</string>
+    <string name="accessibility_vibration_intensity_high" msgid="7850793704772123134">"強"</string>
     <string name="accessibility_menu_item_settings" msgid="6809813639403725032">"設定"</string>
     <string name="accessibility_feature_state_on" msgid="8649102771420898911">"ON"</string>
     <string name="accessibility_feature_state_off" msgid="7536392255214437050">"OFF"</string>
@@ -2207,7 +2212,7 @@
     <string name="print_menu_item_add_service" msgid="6803000110578493782">"サービスを追加"</string>
     <string name="print_menu_item_add_printer" msgid="8529196211179574921">"プリンタを追加"</string>
     <string name="print_menu_item_search" msgid="1165316329772287360">"検索"</string>
-    <string name="print_searching_for_printers" msgid="6538687129687642542">"プリンタの検索中"</string>
+    <string name="print_searching_for_printers" msgid="6538687129687642542">"プリンタを検索しています"</string>
     <string name="print_service_disabled" msgid="6376344992705893436">"サービスが無効です"</string>
     <string name="print_print_jobs" msgid="7357841034181762157">"印刷ジョブ"</string>
     <string name="print_print_job" msgid="6846889971435170443">"印刷ジョブ"</string>
@@ -2309,8 +2314,8 @@
     <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"このアプリによるバックグラウンドでの電池使用を停止すると、電池が長持ちします。制限したアプリは正常に動作しないことがあります。また、通知が遅れる可能性もあります。\n\nアプリ:\n<xliff:g id="APP_LIST">%1$s</xliff:g>."</string>
     <string name="battery_tip_restrict_app_dialog_ok" msgid="2573410775701913487">"制限"</string>
     <string name="battery_tip_unrestrict_app_dialog_title" msgid="812458516399125710">"制限を解除しますか?"</string>
-    <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"このアプリはバックグラウンドで電池を使用するため、電池が予想より早くなくなる可能性があります。"</string>
-    <string name="battery_tip_unrestrict_app_dialog_ok" msgid="9154938931448151479">"削除"</string>
+    <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"このアプリはバックグラウンドで電池を使用するため、電池を予想より早く消費する可能性があります。"</string>
+    <string name="battery_tip_unrestrict_app_dialog_ok" msgid="9154938931448151479">"解除"</string>
     <string name="battery_tip_unrestrict_app_dialog_cancel" msgid="7331148618292397166">"キャンセル"</string>
     <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"アプリの電池使用量は正常です。アプリが電池を使いすぎる場合は、おすすめの対処方法をスマートフォンがお知らせします。\n\n電池の残量が少なくなったら、いつでもバッテリー セーバーを ON にできます。"</string>
     <string name="battery_tip_dialog_summary_message" product="tablet" msgid="1721081030632329647">"アプリの電池使用量は正常です。アプリが電池を使いすぎる場合は、対処可能なおすすめの方法がタブレットに表示されます。\n\n電池の残量が少なくなったら、いつでもバッテリー セーバーを ON にできます。"</string>
@@ -2450,7 +2455,7 @@
     <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"<xliff:g id="PERCENT">%1$s</xliff:g> で ON"</string>
     <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"スケジュールの設定"</string>
     <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"フル充電で無効"</string>
-    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"スマートフォンの電池残量が <xliff:g id="PERCENT">%1$s</xliff:g> になると、バッテリー セーバーは無効になります"</string>
+    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"スマートフォンの電池が <xliff:g id="PERCENT">%1$s</xliff:g> まで充電されると、バッテリー セーバーが OFF になります"</string>
     <string name="battery_saver_sticky_description_new" product="tablet" msgid="3284967694001857194">"タブレットの電池残量が <xliff:g id="PERCENT">%1$s</xliff:g> になると、バッテリー セーバーは無効になります"</string>
     <string name="battery_saver_sticky_description_new" product="device" msgid="5056520668081504111">"デバイスの電池残量が <xliff:g id="PERCENT">%1$s</xliff:g> になると、バッテリー セーバーは無効になります"</string>
     <!-- no translation found for battery_saver_seekbar_title (7607123201469333645) -->
@@ -2649,7 +2654,7 @@
     <string name="data_usage_app" msgid="4995297799363021198">"アプリの使用状況"</string>
     <string name="data_usage_app_info_label" msgid="5358288895158910477">"アプリ情報"</string>
     <string name="data_usage_cellular_data" msgid="3509117353455285808">"モバイルデータ"</string>
-    <string name="data_usage_data_limit" msgid="4070740691087063670">"データの上限の設定"</string>
+    <string name="data_usage_data_limit" msgid="4070740691087063670">"データ使用量を制限"</string>
     <string name="data_usage_cycle" msgid="1877235461828192940">"データ使用サイクル"</string>
     <string name="data_usage_app_items_header_text" msgid="5396134508509913851">"アプリの使用状況"</string>
     <string name="data_usage_menu_roaming" msgid="6933555994416977198">"データローミング"</string>
@@ -2709,8 +2714,8 @@
     <string name="data_usage_warning_editor_title" msgid="1431385383278389290">"データ使用量の警告の設定"</string>
     <string name="data_usage_limit_editor_title" msgid="1687908662154108293">"データ使用量の上限の設定"</string>
     <string name="data_usage_limit_dialog_title" msgid="8804760847110131518">"データ使用量の上限の設定"</string>
-    <string name="data_usage_limit_dialog_mobile" product="tablet" msgid="2000713577999830647">"タブレットで設定した上限に達するとモバイルデータが OFF になります。\n\nデータ使用量はタブレットで測定された値ですが、携帯通信会社での使用量の計算はこれと異なることがあるため、余裕をもって上限を設定することをおすすめします。"</string>
-    <string name="data_usage_limit_dialog_mobile" product="default" msgid="943546278705619205">"スマートフォンで設定した上限に達するとモバイルデータが OFF になります。\n\nデータ使用量はスマートフォンで測定された値ですが、携帯通信会社での使用量の計算はこれと異なることがあるため、余裕をもって上限を設定することをおすすめします。"</string>
+    <string name="data_usage_limit_dialog_mobile" product="tablet" msgid="2000713577999830647">"タブレットで設定した上限に達するとモバイルデータが OFF になります。\n\nデータ使用量はタブレットで測定された値ですが、携帯通信会社による測定結果とは異なることがあるため、余裕をもって上限を設定することをおすすめします。"</string>
+    <string name="data_usage_limit_dialog_mobile" product="default" msgid="943546278705619205">"スマートフォンで設定した上限に達するとモバイルデータが OFF になります。\n\nデータ使用量はスマートフォンで測定された値ですが、携帯通信会社による測定結果とは異なることがあるため、余裕をもって上限を設定することをおすすめします。"</string>
     <string name="data_usage_restrict_background_title" msgid="3568746530413220844">"バックグラウンドデータを制限しますか?"</string>
     <string name="data_usage_restrict_background" msgid="995811034744808575">"バックグラウンドのモバイルデータを制限すると、アプリやサービスによっては、Wi-Fi 未接続時に機能しない場合があります。"</string>
     <string name="data_usage_restrict_background_multiuser" product="tablet" msgid="6032810839234864814">"バックグラウンドのモバイルデータを制限すると、アプリやサービスによっては、Wi‑Fi 未接続時に機能しない場合があります。\n\nこの設定はこのタブレット上のすべてのユーザーに影響します。"</string>
@@ -2931,7 +2936,7 @@
     <string name="restriction_menu_change_pin" msgid="592512748243421101">"PINを変更"</string>
     <string name="app_notifications_switch_label" msgid="670683308275498821">"通知を表示"</string>
     <string name="help_label" msgid="1296484776243905646">"ヘルプとフィードバック"</string>
-    <string name="support_summary" msgid="3278943815956130740">"ヘルプ記事、電話とチャット、使ってみる"</string>
+    <string name="support_summary" msgid="3278943815956130740">"ヘルプ記事、電話とチャット、スタートガイド"</string>
     <string name="user_account_title" msgid="2108666882630552859">"コンテンツのアカウント"</string>
     <string name="user_picture_title" msgid="6664602422948159123">"画像ID"</string>
     <string name="extreme_threats_title" msgid="1405820547540456436">"極めて重大な脅威"</string>
@@ -2970,7 +2975,7 @@
     <string name="restriction_nfc_enable_title" msgid="5146674482590550598">"NFC"</string>
     <string name="restriction_nfc_enable_summary_config" msgid="405349698260328073">"この<xliff:g id="DEVICE_NAME">%1$s</xliff:g>が他のNFCデバイスと接触したときのデータ交換を許可する"</string>
     <string name="restriction_nfc_enable_summary" product="tablet" msgid="3292205836938064931">"タブレットが他のデバイスと接触したときのデータ交換を許可する"</string>
-    <string name="restriction_nfc_enable_summary" product="default" msgid="226439584043333608">"携帯電話が他のデバイスと接触したときのデータ交換を許可する"</string>
+    <string name="restriction_nfc_enable_summary" product="default" msgid="226439584043333608">"他のデバイスと接触したときのデータ交換を許可する"</string>
     <string name="restriction_location_enable_title" msgid="358506740636434856">"位置情報"</string>
     <string name="restriction_location_enable_summary" msgid="4159500201124004463">"アプリに位置情報の使用を許可する"</string>
     <string name="wizard_back" msgid="223654213898117594">"戻る"</string>
@@ -3005,7 +3010,7 @@
     <string name="color_orange" msgid="3159707916066563431">"オレンジ"</string>
     <string name="color_purple" msgid="4391440966734810713">"パープル"</string>
     <string name="sim_no_inserted_msg" msgid="1197884607569714609">"SIMカードが挿入されていません"</string>
-    <string name="sim_status_title" msgid="4483653750844520871">"SIMのステータス"</string>
+    <string name="sim_status_title" msgid="4483653750844520871">"SIM のステータス"</string>
     <string name="sim_status_title_sim_slot" msgid="416005570947546124">"SIM ステータス(SIM スロット %1$d)"</string>
     <string name="sim_call_back_title" msgid="2497274034557717457">"デフォルトのSIMからコールバック"</string>
     <string name="sim_outgoing_call_title" msgid="4683645160838507363">"発信用のSIM"</string>
@@ -3145,7 +3150,7 @@
     <string name="dial_pad_tones_title" msgid="8877212139988655769">"ダイヤルパッドの操作音"</string>
     <string name="screen_locking_sounds_title" msgid="4407110895465866809">"画面ロック音"</string>
     <string name="charging_sounds_title" msgid="5070437987230894287">"充電時の音とバイブレーション"</string>
-    <string name="docking_sounds_title" msgid="2573137471605541366">"装着音"</string>
+    <string name="docking_sounds_title" msgid="2573137471605541366">"ドッキング音"</string>
     <string name="touch_sounds_title" msgid="165237488496165652">"タッチ操作音"</string>
     <string name="vibrate_on_touch_title" msgid="6360155469279157684">"タップ操作時のバイブ"</string>
     <string name="vibrate_on_touch_summary" msgid="5504424764028676043">"タップ、キー操作などの触覚フィードバック"</string>
@@ -3318,7 +3323,7 @@
     <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"仕事用プロファイルのロック時"</string>
     <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"すべての通知内容を表示する"</string>
     <string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"プライベートな内容を非表示"</string>
-    <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"通知をすべて表示しない"</string>
+    <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"通知を一切表示しない"</string>
     <string name="lock_screen_notifications_interstitial_message" msgid="4230189215124387818">"デバイスがロックされている場合、通知をどのように表示しますか?"</string>
     <string name="lock_screen_notifications_interstitial_title" msgid="2832587379332443505">"通知"</string>
     <string name="lock_screen_notifications_summary_show_profile" msgid="8908775469657073273">"仕事用通知の内容をすべて表示する"</string>
@@ -3756,7 +3761,7 @@
     <string name="assist_access_context_title" msgid="2274614501747710439">"画面のテキストを使用"</string>
     <string name="assist_access_context_summary" msgid="5867997494395842785">"画面コンテンツのテキストにアクセスすることをアシストアプリに許可する"</string>
     <string name="assist_access_screenshot_title" msgid="1991014038776117688">"スクリーンショットを使用"</string>
-    <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"画面の画像にアクセスすることをアシストアプリに許可する"</string>
+    <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"表示中の画像にアクセスすることをアシストアプリに許可する"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"画面の点滅"</string>
     <string name="assist_flash_summary" msgid="6697095786317559129">"アシストアプリが画面のテキストやスクリーンショットにアクセスしたときに画面の端を点滅させる"</string>
     <string name="assist_footer" msgid="7030121180457472165">"アシストアプリは、表示している画面の情報に基づいてアシスタントを提供します。一部のアプリはランチャーと音声入力サービスの両方に対応しており、統合されたアシスタントを提供します。"</string>
@@ -3937,9 +3942,9 @@
     <string name="cell_data_template" msgid="5473177306229738078">"モバイルデータ使用量 <xliff:g id="AMOUNT">^1</xliff:g>"</string>
     <string name="wifi_data_template" msgid="3146090439147042068">"<xliff:g id="AMOUNT">^1</xliff:g>(Wi-Fi データ)"</string>
     <string name="ethernet_data_template" msgid="6414118030827090119">"<xliff:g id="AMOUNT">^1</xliff:g>(イーサネット データ)"</string>
-    <string name="billing_cycle" msgid="5740717948341713190">"データの警告と制限"</string>
+    <string name="billing_cycle" msgid="5740717948341713190">"データ使用量の警告と制限"</string>
     <string name="app_usage_cycle" msgid="213483325132959663">"アプリのデータ使用量のサイクル"</string>
-    <string name="cell_data_warning" msgid="8902740337286652689">"データ警告: <xliff:g id="ID_1">^1</xliff:g>"</string>
+    <string name="cell_data_warning" msgid="8902740337286652689">"警告するデータ使用量: <xliff:g id="ID_1">^1</xliff:g>"</string>
     <string name="cell_data_limit" msgid="3175933829235314233">"データ上限: <xliff:g id="ID_1">^1</xliff:g>"</string>
     <string name="cell_data_warning_and_limit" msgid="3846150001253927594">"データ警告: <xliff:g id="ID_1">^1</xliff:g> / データ上限: <xliff:g id="ID_2">^2</xliff:g>"</string>
     <string name="billing_cycle_fragment_summary" msgid="4926047002107855543">"毎月 <xliff:g id="ID_1">%1$s</xliff:g> 日"</string>
@@ -3950,10 +3955,10 @@
     </plurals>
     <string name="operator_warning" msgid="4676042739221117031">"デバイスで記録されるデータ使用量と携帯通信会社のデータ使用量は異なる場合があります"</string>
     <string name="data_used_template" msgid="761605393453849477">"<xliff:g id="ID_1">%1$s</xliff:g> 使用"</string>
-    <string name="set_data_warning" msgid="8115980184415563941">"データ警告を設定"</string>
-    <string name="data_warning" msgid="2699207195535036240">"データ警告"</string>
-    <string name="data_warning_footnote" msgid="965724845580257305">"データ警告とデータ上限はお使いのデバイスで測定されます。測定結果は携帯通信会社のデータとは異なることがあります。"</string>
-    <string name="set_data_limit" msgid="5043770023229990674">"データ上限を設定"</string>
+    <string name="set_data_warning" msgid="8115980184415563941">"データ使用量を警告"</string>
+    <string name="data_warning" msgid="2699207195535036240">"警告するデータ使用量"</string>
+    <string name="data_warning_footnote" msgid="965724845580257305">"警告や制限の基準となるデータ使用量はお使いのデバイスで測定されます。測定結果は携帯通信会社のデータとは異なることがあります。"</string>
+    <string name="set_data_limit" msgid="5043770023229990674">"データ使用量を制限"</string>
     <string name="data_limit" msgid="5793521160051596228">"データ上限"</string>
     <string name="data_usage_template" msgid="6848274347956096882">"<xliff:g id="ID_1">%1$s</xliff:g> 使用(<xliff:g id="ID_2">%2$s</xliff:g>)"</string>
     <string name="configure" msgid="8232696842838580549">"設定"</string>
@@ -3981,7 +3986,7 @@
     <string name="launch_mdp_app_text" msgid="9186559496664208252">"プランを表示"</string>
     <string name="launch_wifi_text" msgid="317820210431682605">"詳細を表示"</string>
     <string name="data_saver_title" msgid="7903308134514179256">"データセーバー"</string>
-    <string name="unrestricted_data_saver" msgid="9139401849550738720">"無制限のデータアクセス"</string>
+    <string name="unrestricted_data_saver" msgid="9139401849550738720">"モバイルデータの無制限利用"</string>
     <string name="restrict_background_blacklisted" msgid="7158991683849067124">"バックグラウンド データは無効になっています"</string>
     <string name="data_saver_on" msgid="7281809065420480881">"ON"</string>
     <string name="data_saver_off" msgid="7439439787358504018">"OFF"</string>
@@ -4049,8 +4054,8 @@
     <string name="overlay_toast_failed_to_apply" msgid="5692251825129250040">"オーバーレイを適用できませんでした"</string>
     <string name="special_access" msgid="1453926335914696206">"特別なアプリアクセス"</string>
     <plurals name="special_access_summary" formatted="false" msgid="5182092345063909346">
-      <item quantity="other">データの無制限使用が可能なアプリは <xliff:g id="COUNT">%d</xliff:g> 個です</item>
-      <item quantity="one">データの無制限使用が可能なアプリは 1 個です</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> 個のアプリがモバイルデータを無制限に使用可能</item>
+      <item quantity="one">1 個のアプリがモバイルデータを無制限に使用可能</item>
     </plurals>
     <string name="special_access_more" msgid="7086690625048471400">"詳細"</string>
     <string name="confirm_convert_to_fbe_warning" msgid="4972595831034280189">"ファイル暗号化のためにユーザーのデータを消去して変換してもよろしいですか?"</string>
@@ -4107,7 +4112,7 @@
     <string name="gesture_preference_summary" product="tablet" msgid="8303793594714075580">"簡単な操作でタブレットを管理できます"</string>
     <string name="gesture_preference_summary" product="device" msgid="7792199669106960922">"簡単な操作でデバイスを管理できます"</string>
     <string name="double_tap_power_for_camera_title" msgid="5480829329052517484">"カメラの起動"</string>
-    <string name="double_tap_power_for_camera_summary" msgid="6591026425496323965">"カメラをすばやく起動するには、電源ボタンを 2 回押します。どの画面からでも操作できます。"</string>
+    <string name="double_tap_power_for_camera_summary" msgid="6591026425496323965">"電源ボタンを 2 回押して、カメラをすばやく起動できます。どの画面からでも操作できます。"</string>
     <string name="double_tap_power_for_camera_suggestion_title" msgid="509078029429865036">"カメラをすばやく起動"</string>
     <string name="double_twist_for_camera_mode_title" msgid="2606032140297556018">"カメラの切り替え"</string>
     <string name="double_twist_for_camera_mode_summary" msgid="8979914206876018137"></string>
@@ -4115,26 +4120,26 @@
     <string name="swipe_up_to_switch_apps_summary" msgid="4644068184114154787">"アプリを切り替えるには、ホームボタンを上にスワイプします。もう一度上にスワイプするとすべてのアプリが表示されます。どの画面からでも操作できます。画面右下の [最近] ボタンは表示されなくなります。"</string>
     <string name="swipe_up_to_switch_apps_suggestion_title" msgid="7641846365137536128">"新しいホームボタンを試す"</string>
     <string name="swipe_up_to_switch_apps_suggestion_summary" msgid="7338653224520387852">"アプリを切り替えるための新しい操作を有効にしてください"</string>
-    <string name="ambient_display_title" product="default" msgid="6785677099744344088">"画面をダブルタップして通知をチェック"</string>
+    <string name="ambient_display_title" product="default" msgid="6785677099744344088">"画面をダブルタップして通知を確認"</string>
     <string name="ambient_display_title" product="tablet" msgid="1106285490888683613">"タブレットの画面をダブルタップして通知をチェック"</string>
     <string name="ambient_display_title" product="device" msgid="5064644474876041478">"デバイスの画面をダブルタップして通知をチェック"</string>
-    <string name="ambient_display_summary" msgid="4882910328216411109">"時刻、通知などの情報を確認するには、画面をダブルタップします。"</string>
-    <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"デバイスを持ち上げて通知をチェック"</string>
+    <string name="ambient_display_summary" msgid="4882910328216411109">"画面をダブルタップして、時刻、通知などの情報を確認できます。"</string>
+    <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"スマートフォンを持ち上げて通知を確認"</string>
     <string name="ambient_display_pickup_title" product="tablet" msgid="1555456400210301959">"タブレットを持ち上げて通知をチェック"</string>
     <string name="ambient_display_pickup_title" product="device" msgid="2480126522988135037">"デバイスを持ち上げて通知をチェック"</string>
     <string name="ambient_display_wake_screen_title" msgid="3376988352851077102">"ディスプレイの復帰"</string>
-    <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"時刻、通知などの情報を確認するには、スマートフォンを持ち上げます。"</string>
+    <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"スマートフォンを持ち上げることで、時刻、通知などの情報を確認できます。"</string>
     <string name="ambient_display_pickup_summary" product="tablet" msgid="1077745287100012928">"時刻、通知などの情報を確認するには、タブレットを持ち上げます。"</string>
     <string name="ambient_display_pickup_summary" product="device" msgid="404199660076598026">"時刻、通知などの情報を確認するには、デバイスを持ち上げます。"</string>
-    <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"スマートフォンをタップしてチェック"</string>
+    <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"デバイスをタップして通知を確認"</string>
     <string name="ambient_display_tap_screen_title" product="tablet" msgid="6434521782016864148">"タブレットをタップしてチェックする"</string>
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"デバイスをタップしてチェックする"</string>
     <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"時刻、通知などの情報を確認するには、画面をタップします。"</string>
     <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"指紋センサーをスワイプして通知を表示"</string>
     <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"指紋センサーのスワイプ"</string>
-    <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"通知を確認するには、スマートフォンの背面にある指紋認証センサーを下にスワイプします。"</string>
-    <string name="fingerprint_swipe_for_notifications_summary" product="tablet" msgid="3480057984564476283">"通知を確認するには、タブレットの背面にある指紋認証センサーを下にスワイプします。"</string>
-    <string name="fingerprint_swipe_for_notifications_summary" product="device" msgid="7950264130913070035">"通知を確認するには、デバイスの背面にある指紋認証センサーを下にスワイプします。"</string>
+    <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"スマートフォンの背面にある指紋認証センサーを下にスワイプして、通知を確認できます。"</string>
+    <string name="fingerprint_swipe_for_notifications_summary" product="tablet" msgid="3480057984564476283">"タブレットの背面にある指紋認証センサーを下にスワイプして、通知を確認できます。"</string>
+    <string name="fingerprint_swipe_for_notifications_summary" product="device" msgid="7950264130913070035">"デバイスの背面にある指紋認証センサーを下にスワイプして、通知を確認できます。"</string>
     <string name="fingerprint_swipe_for_notifications_suggestion_title" msgid="948946491233738823">"通知をすばやく確認"</string>
     <string name="gesture_setting_on" msgid="7573680730101327866">"ON"</string>
     <string name="gesture_setting_off" msgid="2540159841716890511">"OFF"</string>
@@ -4145,7 +4150,7 @@
     <string name="oem_lock_info_message" msgid="5090850412279403901">"デバイス保護機能を有効にするには、デバイスを再起動してください。"</string>
     <string name="automatic_storage_manager_freed_bytes" msgid="7360443072390107772">"計 <xliff:g id="SIZE">%1$s</xliff:g> が利用可能になりました\n\n最終実行: <xliff:g id="DATE">%2$s</xliff:g>"</string>
     <string name="web_action_enable_title" msgid="4462106633708675959">"Instant Apps"</string>
-    <string name="web_action_enable_summary" msgid="1729016644691793085">"アプリがインストールされていなくても、アプリ内のリンクを開くことができます"</string>
+    <string name="web_action_enable_summary" msgid="1729016644691793085">"アプリがインストールされていなくても、アプリでリンクを開けるようにします"</string>
     <string name="web_action_section_title" msgid="5563229447734734662">"Instant Apps"</string>
     <string name="instant_apps_settings" msgid="879003203555847537">"Instant Apps の設定"</string>
     <string name="domain_url_section_title" msgid="206403507921518321">"インストール済みアプリ"</string>
@@ -4440,7 +4445,7 @@
     <string name="mobile_network_mode_error" msgid="6818434186286086554">"ネットワーク モード <xliff:g id="NETWORKMODEID">%1$d</xliff:g> は無効です。無視してください。"</string>
     <string name="mobile_network_apn_title" msgid="5628635067747404382">"アクセス ポイント名"</string>
     <string name="manual_mode_disallowed_summary" msgid="799800630000340665">"<xliff:g id="CARRIER">%1$s</xliff:g> への接続時は利用できません"</string>
-    <string name="emergency_info_contextual_card_summary" msgid="5541444321969803486">"医療記録、緊急連絡先"</string>
+    <string name="emergency_info_contextual_card_summary" msgid="5541444321969803486">"医療情報、緊急連絡先"</string>
     <string name="see_more" msgid="7463940160389802632">"詳細"</string>
     <string name="see_less" msgid="3718892257002813387">"一部を表示"</string>
     <string name="network_connection_request_dialog_title" msgid="3150489262902506588">"<xliff:g id="APPNAME">%1$s</xliff:g> で使用するデバイス"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ka/arrays.xml b/tests/CarDeveloperOptions/res/values-ka/arrays.xml
index bddbdec..1cec46d 100644
--- a/tests/CarDeveloperOptions/res/values-ka/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-ka/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"ფონურ რეჟიმში გაშვება"</item>
     <item msgid="6423861043647911030">"მარტივი წვდომის ხმის სიმძლავრე"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"მდებარეობა"</item>
+    <item msgid="6656077694190491067">"მდებარეობა"</item>
+    <item msgid="8790228218278477369">"მდებარეობა"</item>
+    <item msgid="7836406246005211990">"ვიბრაცია"</item>
+    <item msgid="3951439024549922598">"კონტაქტების მონაცემების წაკითხვა"</item>
+    <item msgid="8802152411647068">"კონტაქტების შეცვლა"</item>
+    <item msgid="229544934599698735">"ზარების ჟურნალის ნახვა"</item>
+    <item msgid="7396102294405899613">"ზარების ჟურნალის ჩასწორება"</item>
+    <item msgid="3597797992398484655">"კალენდრის მონაცემების წაკითხვა"</item>
+    <item msgid="2705975774250907343">"კალენდრის ჩასწორება"</item>
+    <item msgid="4668747371441932697">"მდებარეობა"</item>
+    <item msgid="1487578921720243646">"შეტყობინების გამოქვეყნება"</item>
+    <item msgid="4636080349724146638">"მდებარეობა"</item>
+    <item msgid="673510900286463926">"ტელეფონზე დარეკვა"</item>
+    <item msgid="542083422784609790">"SMS/MMS-ის წაკითხვა"</item>
+    <item msgid="1033780373029588436">"SMS/MMS-ის დაწერა"</item>
+    <item msgid="5647111115517787488">"SMS/MMS-ის მიღება"</item>
+    <item msgid="8591105601108455893">"SMS/MMS-ის მიღება"</item>
+    <item msgid="7730995008517841903">"SMS/MMS მიღება"</item>
+    <item msgid="2613033109026626086">"SMS/MMS მიღება"</item>
+    <item msgid="3037159047591081136">"SMS/MMS-ის გაგზავნა"</item>
+    <item msgid="4726682243833913568">"SMS/MMS-ის წაკითხვა"</item>
+    <item msgid="6555678522277865572">"SMS/MMS-ის დაწერა"</item>
+    <item msgid="6981734935578130884">"პარამეტრების შეცვლა"</item>
+    <item msgid="8705854389991425629">"დახაზვა ზემოთ"</item>
+    <item msgid="5861356020344153651">"შეტყობინებებზე წვდომა"</item>
+    <item msgid="78432174621628659">"კამერა"</item>
+    <item msgid="3986116419882154794">"აუდიოს ჩაწერა"</item>
+    <item msgid="4516840825756409490">"აუდიოს დაკვრა"</item>
+    <item msgid="6811712502798183957">"გაცვლის ბუფერის წაკითხვა"</item>
+    <item msgid="2780369012602289114">"გაცვლის ბუფერის შეცვლა"</item>
+    <item msgid="2331359440170850868">"მედიის ღილაკები"</item>
+    <item msgid="6133599737122751231">"აუდიოს ფოკუსი"</item>
+    <item msgid="6844485713404805301">"მასტერ-ხმის სიმძლავრე"</item>
+    <item msgid="1600379420669104929">"ხმის სიმძღლავრე"</item>
+    <item msgid="6296768210470214866">"ზარის სიმძლავრე"</item>
+    <item msgid="510690696071629241">"მედიის ხმა"</item>
+    <item msgid="406861638631430109">"მაღვიძარას ხმა"</item>
+    <item msgid="4715864795872233884">"შეტყობინების ხმა"</item>
+    <item msgid="2311478519251301183">"Bluetooth-ის ხმა"</item>
+    <item msgid="5133991377896747027">"დარჩეს აქტიური"</item>
+    <item msgid="2464189519136248621">"მდებარეობა"</item>
+    <item msgid="2062677934050803037">"მდებარეობა"</item>
+    <item msgid="1735171933192715957">"გამოყენების სტატისტიკის მიღება"</item>
+    <item msgid="1014093788778383554">"მიკროფონის დადუმება/გააქტიურება"</item>
+    <item msgid="4199297950608622850">"შეტყობინების ჩვენება"</item>
+    <item msgid="2527962435313398821">"მედიის პროეცირება"</item>
+    <item msgid="5117506254221861929">"VPN-ის აქტივაცია"</item>
+    <item msgid="8291198322681891160">"ფონის ჩაწერა"</item>
+    <item msgid="7106921284621230961">"დამხმარე სტრუქტურა"</item>
+    <item msgid="4496533640894624799">"დამხმარე ეკრანის ანაბეჭდი"</item>
+    <item msgid="2598847264853993611">"ტელეფონის მდგომარეობის წაკითხვა"</item>
+    <item msgid="9215610846802973353">"ხმოვანი ფოსტის დამატება"</item>
+    <item msgid="9186411956086478261">"SIP-ის გამოყენება"</item>
+    <item msgid="6884763100104539558">"გამავალი ზარის დამუშავება"</item>
+    <item msgid="125513972170580692">"თითის ანაბეჭდი"</item>
+    <item msgid="2556071024281275619">"სხეულის სენსორები"</item>
+    <item msgid="617168514928339387">"Cell Broadcast-ების წაკითხვა"</item>
+    <item msgid="7134693570516523585">"მდებარეობის იმიტირება"</item>
+    <item msgid="7224489175375229399">"მეხსიერების წაკითხვა"</item>
+    <item msgid="8472735063903258202">"მეხსიერებაში ჩაწერა"</item>
+    <item msgid="4069276819909595110">"ეკრანის ჩართვა"</item>
+    <item msgid="1228338896751121025">"ანგარიშების მიღება"</item>
+    <item msgid="3181581793459233672">"ფონურ რეჟიმში გაშვება"</item>
+    <item msgid="2340936043025374076">"მარტივი წვდომის ხმის სიმძლავრე"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"მოკლე"</item>
     <item msgid="4816511817309094890">"საშუალო"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"არასოდეს მიეცეს უფლება"</item>
     <item msgid="8184570120217958741">"ნებართვის მიცემა - ყოველთვის"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"ჩვეულებრივი"</item>
+    <item msgid="5101233285497327432">"ზომიერი"</item>
+    <item msgid="1555861583162930714">"დაბალი"</item>
+    <item msgid="1719683776264798117">"კრიტიკული"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"ჩვეულებრივი"</item>
+    <item msgid="6107138933849816768">"ზომიერი"</item>
+    <item msgid="182695359839047859">"დაბალი"</item>
+    <item msgid="8577246509202964244">"კრიტიკული"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"სისტემატური"</item>
     <item msgid="167418068739176448">"ტოპ-აქტივობა"</item>
diff --git a/tests/CarDeveloperOptions/res/values-ka/config.xml b/tests/CarDeveloperOptions/res/values-ka/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-ka/config.xml
+++ b/tests/CarDeveloperOptions/res/values-ka/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-ka/strings.xml b/tests/CarDeveloperOptions/res/values-ka/strings.xml
index 9536e8f..f38954f 100644
--- a/tests/CarDeveloperOptions/res/values-ka/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ka/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"ეკრანზე ტექსტის დაპატარავება ან გადიდება."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"დაპატარავება"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"გადიდება"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"ტექსტის ნიმუში"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"ოზის საოცარი ჯადოქარი"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"თავი 11: ოზის ზურმუხტის ქალაქი"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">უნდა შეიცავდეს <xliff:g id="NUMBER_1">%d</xliff:g> ციფრზე ნაკლებს</item>
       <item quantity="one">უნდა შეიცავდეს <xliff:g id="NUMBER_0">%d</xliff:g> ციფრზე ნაკლებს</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"უნდა შეიცავდეს მხოლოდ ციფრებს 0-დან 9-მდე"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"ბოლოდროინდელი PIN-კოდის ხელახლა გამოყენება მოწყობილობის ადმინისტრატორის მიერ ნებადართული არ არის"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"ხშირად გამოყენებული PIN-კოდები თქვენი IT ადმინისტრატორის მიერ დაბლოკილია. ცადეთ სხვა PIN-კოდი."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"არ უნდა შეიცავდეს არასწორ სიმბოლოს"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">უნდა შეიცავდეს მინიმუმ <xliff:g id="COUNT">%d</xliff:g> არაანბანურ სიმბოლოს</item>
       <item quantity="one">უნდა შეიცავდეს მინიმუმ 1 არაანბანურ სიმბოლოს</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">უნდა შეიცავდეს, სულ მცირე, <xliff:g id="COUNT">%d</xliff:g> არარიცხვით სიმბოლოს</item>
+      <item quantity="one">უნდა შეიცავდეს, სულ მცირე, 1 არარიცხვით სიმბოლოს</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"ბოლოდროინდელი პაროლის ხელახლა გამოყენება მოწყობილობის ადმინისტრატორის მიერ ნებადართული არ არის"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"ხშირად გამოყენებული პაროლები თქვენი IT ადმინისტრატორის მიერ დაბლოკილია. ცადეთ სხვა პაროლი."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"ციფრების ზრდადი, კლებადი ან გამეორებადი მიმდევრობის გამოყენება ნებადართული არ არის"</string>
@@ -923,9 +925,9 @@
     <string name="wifi_show_password" msgid="7878398590772942202">"პაროლის გამოჩენა"</string>
     <string name="wifi_ap_band_config" msgid="6565016368079288433">"აირჩიეთ AP Band"</string>
     <string name="wifi_ap_choose_auto" msgid="7927637960569365785">"ავტომატური"</string>
-    <string name="wifi_ap_choose_2G" msgid="43198403259714736">"2,4 GHz დიაპაზონი"</string>
-    <string name="wifi_ap_choose_5G" msgid="2624859713183683146">"5 GHz დიაპაზონი"</string>
-    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"სასურველია 5-გიგაჰერციანი დიაპაზონი"</string>
+    <string name="wifi_ap_choose_2G" msgid="43198403259714736">"2,4 გჰც დიაპაზონი"</string>
+    <string name="wifi_ap_choose_5G" msgid="2624859713183683146">"5 გჰც დიაპაზონი"</string>
+    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"სასურველია 5 გჰც დიაპაზონი"</string>
     <string name="wifi_ap_2G" msgid="5793110086517338494">"2.4 გჰც"</string>
     <string name="wifi_ap_5G" msgid="4584892544393675403">"5 გჰც"</string>
     <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"აირჩიეთ მინიმუმ ერთი დიაპაზონი Wi‑Fi უსადენო ქსელისთვის:"</string>
@@ -1036,7 +1038,7 @@
     <string name="wifi_ip_settings_invalid_network_prefix_length" msgid="392977552691002076">"შეიყვანეთ ქსელის პრეფიქსი, რომლის სიგრძეა 0-დან 32-მდე."</string>
     <string name="wifi_dns1" msgid="5250809981658822505">"DNS 1"</string>
     <string name="wifi_dns2" msgid="1905876166783761641">"DNS 2"</string>
-    <string name="wifi_gateway" msgid="7455334454444443397">"კარიბჭე"</string>
+    <string name="wifi_gateway" msgid="7455334454444443397">"გეითვეი"</string>
     <string name="wifi_network_prefix_length" msgid="1941206966133010633">"ქსელის პრეფიქსის სიგრძე"</string>
     <string name="wifi_p2p_settings_title" msgid="3213180637906683308">"Wi‑Fi Direct"</string>
     <string name="wifi_p2p_device_info" msgid="4717490498956029237">"ინფორმაცია მოწყობილობის შესახებ"</string>
@@ -1055,7 +1057,7 @@
     <string name="wifi_p2p_cancel_connect_message" msgid="3752679335020392154">"ნამდვილად გსურთ <xliff:g id="PEER_NAME">%1$s</xliff:g>-თან დაკავშირების მიწვევის გაუქმება?"</string>
     <string name="wifi_p2p_delete_group_message" msgid="3206660449067701089">"გსურთ, ამ ჯგუფის დავიწყება?"</string>
     <string name="wifi_hotspot_checkbox_text" msgid="12062341344410520">"Wi‑Fi უსადენო ქსელი"</string>
-    <string name="wifi_hotspot_off_subtext" msgid="6177054857136221058">"არ მოხდეს ინტერნეტის ან კონტენტის სხვა მოწყობილობებთან გაზიარება"</string>
+    <string name="wifi_hotspot_off_subtext" msgid="6177054857136221058">"არ ხორციელდება ინტერნეტის ან კონტენტის სხვა მოწყობილობებთან გაზიარება"</string>
     <string name="wifi_hotspot_tethering_on_subtext" product="tablet" msgid="71421730039785897">"ამ ტაბლეტის ინტერნეტ-კავშირი უსადენო ქსელით ზიარდება"</string>
     <string name="wifi_hotspot_tethering_on_subtext" product="default" msgid="8914285514605049879">"ამ ტელეფონის ინტერნეტ-კავშირი უსადენო ქსელით ზიარდება"</string>
     <string name="wifi_hotspot_on_local_only_subtext" msgid="7415381343846704553">"აპი კონტენტს აზიარებს. ინტერნეტ-კავშირის გასაზიარებლად, ჯერ გამორთეთ, შემდეგ კი ხელახლა ჩართეთ უსადენო ქსელი"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"მობილური"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"თუ Wi‑Fi მიუწვდომელია, ისარგებლეთ მობილური ქსელით"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"თუ მობილური ქსელი მიუწვდომელია, გამოიყენეთ Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"დარეკვა Wi-Fi-ის მეშვეობით. თუ Wi‑Fi გაითიშა, ზარი დასრულდება."</string>
@@ -1793,7 +1798,7 @@
     <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>
-    <string name="application_info_label" msgid="3886253474964599105">"აპის მონაცემები"</string>
+    <string name="application_info_label" msgid="3886253474964599105">"აპების მონაცემები"</string>
     <string name="storage_label" msgid="1109537840103290384">"საცავი"</string>
     <string name="auto_launch_label" msgid="47089737922907379">"გახსნა ნაგულისხმევად"</string>
     <string name="auto_launch_label_generic" msgid="7865828543459493308">"ნაგულისხმევი"</string>
@@ -2235,7 +2240,7 @@
     <string name="background_activity_warning_dialog_title" msgid="2170790412855899678">"გსურთ ფონური აქტივობის შეზღუდვა?"</string>
     <string name="background_activity_warning_dialog_text" msgid="8242749826732375096">"აპისთვის ფონური აქტივობის შეზღუდვის შემთხვევაში, მან შეიძლება არასათანადოდ იმუშაოს"</string>
     <string name="background_activity_disabled_dialog_text" msgid="4234598000779459640">"რადგან ეს აპი ბატარეის ოპტიმიზებისთვის დაყენებული არაა, მას ვერ შეზღუდავთ.\n\nჩართეთ ბატარეის ოპტიმიზაცია აპის შესაზღუდავად."</string>
-    <string name="device_screen_usage" msgid="4470485475363132750">"ეკრანის მოხმარება ბოლო სრული დატენვიდან"</string>
+    <string name="device_screen_usage" msgid="4470485475363132750">"ეკრანის გამოყენება ბოლო სრული დატენვიდან"</string>
     <string name="power_usage_list_summary" msgid="4314438658308211057">"ბატარეის მოხმარება ბოლო სრული დატენვიდან"</string>
     <string name="screen_usage_summary" msgid="263396144684078341">"დროის ხანგრძლივობა სრული დატენვიდან, რომლის განმავლობაშიც ეკრანი ჩართული იყო"</string>
     <string name="device_usage_list_summary" msgid="8299017481332816368">"მოწყობილობის მოხმარება ბოლო სრული დატენვიდან"</string>
@@ -2704,7 +2709,7 @@
     <string name="data_usage_auto_sync_off_dialog_title" msgid="7105334544291643305">"გამოირთოს მონაცემთა ავტომატური სინქრონიზაცია?"</string>
     <string name="data_usage_auto_sync_off_dialog" msgid="4057984234450947964">"ეს გამოიწვევს მონაცემებისა და ბატარეის გამოყენების დაზოგვას, მაგრამ თქვენ ბოლო ინფორმაციის შესაგროვებლად დაგჭირდებათ თითოეულ ანგარიშთან მექანიკურად სინქრონიზაცია. განახლებების შესახებ შეტყობინებებს არ მიიღებთ."</string>
     <string name="data_usage_cycle_editor_title" msgid="4967309390043599889">"გამოყენების ციკლის ჩამოყრის თარიღი"</string>
-    <string name="data_usage_cycle_editor_subtitle" msgid="6043098041946166597">"თითოეული თვის თარიღი:"</string>
+    <string name="data_usage_cycle_editor_subtitle" msgid="6043098041946166597">"თვის შემდეგ რიცხვში:"</string>
     <string name="data_usage_cycle_editor_positive" msgid="9155752056537811646">"შენახვა"</string>
     <string name="data_usage_warning_editor_title" msgid="1431385383278389290">"გაფრთხილების დაყენება"</string>
     <string name="data_usage_limit_editor_title" msgid="1687908662154108293">"ინტერნეტის მოხმარების ლიმიტის დაყენება"</string>
@@ -3139,7 +3144,7 @@
     <string name="notification_ringtone_title" msgid="2932960620843976285">"შეტყობინებების ნაგულისხმევი ხმა"</string>
     <string name="notification_unknown_sound_title" msgid="8043718667804838398">"აპის მიერ უზრუნველყოფილი ხმა"</string>
     <string name="notification_sound_default" msgid="2664544380802426260">"შეტყობინებების ნაგულისხმევი ხმა"</string>
-    <string name="alarm_ringtone_title" msgid="6411326147408635902">"მაღვიძარას ნაგულისხმევი ხმა"</string>
+    <string name="alarm_ringtone_title" msgid="6411326147408635902">"მაღვიძარას ნაგულ. ხმა"</string>
     <string name="vibrate_when_ringing_title" msgid="2757996559847126952">"ვიბრაცია ზარებისას"</string>
     <string name="other_sound_settings" msgid="5250376066099818676">"სხვა ხმები"</string>
     <string name="dial_pad_tones_title" msgid="8877212139988655769">"ციფერბლატის ტონური რეჟიმი"</string>
@@ -3318,7 +3323,7 @@
     <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"როცა სამსახურის პროფილი დაბლოკილია"</string>
     <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"შეტყობინების მთელი შინაარსის ჩვენება"</string>
     <string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"სენსიტიური კონტენტის დამალვა"</string>
-    <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"არ მაჩვენო არანაირი შეტყობინება"</string>
+    <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"არ მაჩვენო შეტყობინება"</string>
     <string name="lock_screen_notifications_interstitial_message" msgid="4230189215124387818">"როგორ გსურთ შეტყობინებების ჩვენება, როდესაც მოწყობილობა ჩაკეტილია?"</string>
     <string name="lock_screen_notifications_interstitial_title" msgid="2832587379332443505">"შეტყობინებები"</string>
     <string name="lock_screen_notifications_summary_show_profile" msgid="8908775469657073273">"სამსახურის შეტყობინებების მთელი კონტენტის ჩვენება"</string>
diff --git a/tests/CarDeveloperOptions/res/values-kk/arrays.xml b/tests/CarDeveloperOptions/res/values-kk/arrays.xml
index 2dca861..bfa188c 100644
--- a/tests/CarDeveloperOptions/res/values-kk/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-kk/arrays.xml
@@ -29,8 +29,25 @@
     <item msgid="5194868215515664953">"Тынық"</item>
     <item msgid="7044520255415007865">"Барлығы"</item>
   </string-array>
-    <!-- no translation found for screen_timeout_entries:0 (8596143519087753804) -->
-    <!-- no translation found for dream_timeout_entries:7 (8271452751594598661) -->
+  <string-array name="screen_timeout_entries">
+    <item msgid="8596143519087753804">"15 секунд"</item>
+    <item msgid="772029947136115322">"30 секунд"</item>
+    <item msgid="8743663928349474087">"1 минут"</item>
+    <item msgid="1506508631223164814">"2 минут"</item>
+    <item msgid="8664703938127907662">"5 минут"</item>
+    <item msgid="5827960506924849753">"10 минут"</item>
+    <item msgid="6677424950124253938">"30 минут"</item>
+  </string-array>
+  <string-array name="dream_timeout_entries">
+    <item msgid="6487043225269853023">"Ешқашан"</item>
+    <item msgid="2517785806387977252">"15 секунд"</item>
+    <item msgid="6347954399441173672">"30 секунд"</item>
+    <item msgid="4858305253279921789">"1 минут"</item>
+    <item msgid="8109273437140044073">"2 минут"</item>
+    <item msgid="2788593551142462622">"5 минут"</item>
+    <item msgid="8012672183888404961">"10 минут"</item>
+    <item msgid="8271452751594598661">"30 минут"</item>
+  </string-array>
   <string-array name="lock_after_timeout_entries">
     <item msgid="2232921187970351881">"Бірден"</item>
     <item msgid="2038544972632026612">"5 секунд"</item>
@@ -42,17 +59,47 @@
     <item msgid="811192536981678974">"10 минут"</item>
     <item msgid="7258394417241706272">"30 минут"</item>
   </string-array>
-    <!-- no translation found for entries_font_size:0 (2340391964816059553) -->
-    <!-- no translation found for entries_font_size:0 (6490061470416867723) -->
-    <!-- no translation found for entries_font_size:2 (1714184661981538355) -->
-    <!-- no translation found for entries_font_size:2 (1678068858001018666) -->
-    <!-- no translation found for wifi_status:3 (5848277343965362748) -->
-    <!-- no translation found for wifi_status_with_ssid:1 (6816207058895999545) -->
-    <!-- no translation found for wifi_status_with_ssid:3 (7547609081339573756) -->
-    <!-- no translation found for wifi_status_with_ssid:4 (5145158315060185414) -->
+  <string-array name="entries_font_size">
+    <item msgid="2340391964816059553">"Кішi"</item>
+    <item msgid="591935967183159581">"Әдепкі"</item>
+    <item msgid="1714184661981538355">"Үлкен"</item>
+    <item msgid="6195563047686707484">"Ең үлкен"</item>
+  </string-array>
+  <string-array name="wifi_status">
+    <item msgid="1304883790721412351"></item>
+    <item msgid="4157625910392775808">"Тексеруде…"</item>
+    <item msgid="5597394826455877834">"Қосылуда..."</item>
+    <item msgid="5848277343965362748">"Растауда…"</item>
+    <item msgid="3391238031431440676">"IP мекенжайына қол жеткізуде…"</item>
+    <item msgid="5257597310494000224">"Жалғанған"</item>
+    <item msgid="8472497592913050396">"Тоқтатылған"</item>
+    <item msgid="1228072488815999109">"Ажыратылуда…"</item>
+    <item msgid="7253087004422991731">"Ажыратылған"</item>
+    <item msgid="4169850917304751227">"Сәтсіз"</item>
+    <item msgid="6266658166690831131">"Бөгелген"</item>
+    <item msgid="4517230805854909775">"Нашар байланысты уақытша қолданбау"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="4853670665485437464"></item>
+    <item msgid="6816207058895999545">"Іздеуде…"</item>
+    <item msgid="8058143476674427024">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> қосылуда…"</item>
+    <item msgid="7547609081339573756">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> арқылы расталуда…"</item>
+    <item msgid="5145158315060185414">"IP мекенжайы <xliff:g id="NETWORK_NAME">%1$s</xliff:g> желісінен алынуда…"</item>
+    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> жалғанған"</item>
+    <item msgid="6600156231416890902">"Тоқтатылған"</item>
+    <item msgid="4133290864821295785">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> байланысынан ажыратылуда…"</item>
+    <item msgid="3980154971187953257">"Ажыратылған"</item>
+    <item msgid="2847316776634969068">"Сәтсіз"</item>
+    <item msgid="4390990424746035383">"Бөгелген"</item>
+    <item msgid="3618248791367063949">"Нашар байланысты уақытша қолданбау"</item>
+  </string-array>
     <!-- no translation found for wifi_tether_security:0 (5586343370515598801) -->
     <!-- no translation found for wifi_tether_security:1 (6136336549994615745) -->
-    <!-- no translation found for wifi_p2p_wps_setup:0 (5390235347963255303) -->
+  <string-array name="wifi_p2p_wps_setup">
+    <item msgid="5390235347963255303">"Push түймесі"</item>
+    <item msgid="7401896200768713930">"Басқа құрылғының PIN коды"</item>
+    <item msgid="4526848028011846710">"Осы құралдың PIN коды"</item>
+  </string-array>
   <string-array name="wifi_p2p_status">
     <item msgid="8741947238021758201">"Жалғанған"</item>
     <item msgid="983792611851499732">"Шақырылған"</item>
@@ -60,7 +107,12 @@
     <item msgid="4646663015449312554">"Қолжетімді"</item>
     <item msgid="3230556734162006146">"Аумақтан тыc"</item>
   </string-array>
-    <!-- no translation found for bluetooth_visibility_timeout_entries:1 (2759776603549270587) -->
+  <string-array name="bluetooth_visibility_timeout_entries">
+    <item msgid="8247986727324120082">"2 минут"</item>
+    <item msgid="2759776603549270587">"5 минут"</item>
+    <item msgid="167772676068860015">"1 сағат"</item>
+    <item msgid="5985477119043628504">"Ешқашан"</item>
+  </string-array>
   <string-array name="bluetooth_max_connected_audio_devices">
     <item msgid="3800257971619063588">"Жүйенінің әдепкі мәнін пайдалану: <xliff:g id="DEFAULT_BLUETOOTH_MAX_CONNECTED_AUDIO_DEVICES">%1$d</xliff:g>"</item>
     <item msgid="8572230405241423895">"1"</item>
@@ -69,8 +121,13 @@
     <item msgid="1644506614010085798">"4"</item>
     <item msgid="3132506679404897150">"5"</item>
   </string-array>
-    <!-- no translation found for wifi_signal:1 (7882129634982603782) -->
-    <!-- no translation found for wifi_signal:4 (999948812884919584) -->
+  <string-array name="wifi_signal">
+    <item msgid="1709949377823900951">"Нашар"</item>
+    <item msgid="7882129634982603782">"Нашар"</item>
+    <item msgid="6457357501905996224">"Орташа"</item>
+    <item msgid="405271628162918841">"Жақсы"</item>
+    <item msgid="999948812884919584">"Өте жақсы"</item>
+  </string-array>
   <string-array name="data_usage_data_range">
     <item msgid="8986775481492954015">"Соңғы 30 күн"</item>
     <item msgid="3211287705232736964">"Пайдалану циклын орнату…"</item>
@@ -106,7 +163,10 @@
     <item msgid="7330627471456865502">"MSCHAPV2"</item>
     <item msgid="6255179395132581882">"GTC"</item>
   </string-array>
-    <!-- no translation found for wifi_ip_settings:1 (4377002609760712163) -->
+  <string-array name="wifi_ip_settings">
+    <item msgid="2717196390555072244">"DHCP"</item>
+    <item msgid="4377002609760712163">"Статикалық"</item>
+  </string-array>
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"Ешқандай"</item>
     <item msgid="1464741437353223198">"Қолмен"</item>
@@ -226,11 +286,73 @@
     <item msgid="1165623660533024666">"фонда іске қосу"</item>
     <item msgid="6423861043647911030">"арнайы мүмкіндіктердің дыбыс деңгейі"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:3 (7836406246005211990) -->
-    <!-- no translation found for app_ops_labels:4 (3951439024549922598) -->
-    <!-- no translation found for app_ops_labels:8 (3597797992398484655) -->
-    <!-- no translation found for app_ops_labels:20 (3037159047591081136) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Орналасу"</item>
+    <item msgid="6656077694190491067">"Орналасу"</item>
+    <item msgid="8790228218278477369">"Орналасу"</item>
+    <item msgid="7836406246005211990">"Діріл"</item>
+    <item msgid="3951439024549922598">"Контактілерді оқу"</item>
+    <item msgid="8802152411647068">"Контактілерді жөндеу"</item>
+    <item msgid="229544934599698735">"Қоңыраулар тіркелімін оқу"</item>
+    <item msgid="7396102294405899613">"Қоңыраулар тіркелімін өзгерту"</item>
+    <item msgid="3597797992398484655">"Күнтізбені оқу"</item>
+    <item msgid="2705975774250907343">"Күнтізбені жөндеу"</item>
+    <item msgid="4668747371441932697">"Орналасу"</item>
+    <item msgid="1487578921720243646">"Пост хабарлары"</item>
+    <item msgid="4636080349724146638">"Орналасу"</item>
+    <item msgid="673510900286463926">"Қоңырау шалу"</item>
+    <item msgid="542083422784609790">"SMS/MMS оқу"</item>
+    <item msgid="1033780373029588436">"SMS/MMS жазу"</item>
+    <item msgid="5647111115517787488">"SMS/MMS алу"</item>
+    <item msgid="8591105601108455893">"SMS/MMS алу"</item>
+    <item msgid="7730995008517841903">"SMS/MMS алу"</item>
+    <item msgid="2613033109026626086">"SMS/MMS алу"</item>
+    <item msgid="3037159047591081136">"SMS/MMS жіберу"</item>
+    <item msgid="4726682243833913568">"SMS/MMS оқу"</item>
+    <item msgid="6555678522277865572">"SMS/MMS жазу"</item>
+    <item msgid="6981734935578130884">"Параметрлерді өзгерту"</item>
+    <item msgid="8705854389991425629">"Үстінен сызу"</item>
+    <item msgid="5861356020344153651">"Хабарларға кіру"</item>
+    <item msgid="78432174621628659">"Камера"</item>
+    <item msgid="3986116419882154794">"Аудио жазу"</item>
+    <item msgid="4516840825756409490">"Аудио ойнату"</item>
+    <item msgid="6811712502798183957">"Ақпарат алмастыру қорын оқу"</item>
+    <item msgid="2780369012602289114">"Ақпарат алмастыру қорын өзгерту"</item>
+    <item msgid="2331359440170850868">"Meдиа түймелері"</item>
+    <item msgid="6133599737122751231">"Аудио көздеу"</item>
+    <item msgid="6844485713404805301">"Негізгі дыбыс"</item>
+    <item msgid="1600379420669104929">"Дыбыс қаттылығы"</item>
+    <item msgid="6296768210470214866">"Қоңыраудың дыбыс деңгейі"</item>
+    <item msgid="510690696071629241">"Mультимeдиа дыбыс деңгейі"</item>
+    <item msgid="406861638631430109">"Оятқыштың дыбыс деңгейі"</item>
+    <item msgid="4715864795872233884">"Хабарландырудың дыбыс деңгейі"</item>
+    <item msgid="2311478519251301183">"Bluetooth дыбысының қаттылығы"</item>
+    <item msgid="5133991377896747027">"Ұйқы бермеу"</item>
+    <item msgid="2464189519136248621">"Орын"</item>
+    <item msgid="2062677934050803037">"Орналасу"</item>
+    <item msgid="1735171933192715957">"Пайдалану статистикасын алу"</item>
+    <item msgid="1014093788778383554">"Микрофон дыбысын өшіру/қосу"</item>
+    <item msgid="4199297950608622850">"Қалқымалы хабарландыру көрсету"</item>
+    <item msgid="2527962435313398821">"Жоба тасушысы"</item>
+    <item msgid="5117506254221861929">"VPN функциясын белсендіру"</item>
+    <item msgid="8291198322681891160">"Артқы фонды жазу"</item>
+    <item msgid="7106921284621230961">"Көмекші құрылым"</item>
+    <item msgid="4496533640894624799">"Көмекші скриншот"</item>
+    <item msgid="2598847264853993611">"Телефон күйін оқу"</item>
+    <item msgid="9215610846802973353">"Дауыстық хабар қосу"</item>
+    <item msgid="9186411956086478261">"SIP пайдалану"</item>
+    <item msgid="6884763100104539558">"Шығыс қоңырауды өңдеу"</item>
+    <item msgid="125513972170580692">"Саусақ ізі"</item>
+    <item msgid="2556071024281275619">"Дене датчиктері"</item>
+    <item msgid="617168514928339387">"Ұялы таратылымдарды оқу"</item>
+    <item msgid="7134693570516523585">"Жалған орын"</item>
+    <item msgid="7224489175375229399">"Жадты оқу"</item>
+    <item msgid="8472735063903258202">"Жадқа жазу"</item>
+    <item msgid="4069276819909595110">"Экранды қосу"</item>
+    <item msgid="1228338896751121025">"Есептік жазбаларды алу"</item>
+    <item msgid="3181581793459233672">"Фонда іске қосу"</item>
+    <item msgid="2340936043025374076">"Арнайы мүмкіндіктердің дыбыс деңгейі"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Қысқа"</item>
     <item msgid="4816511817309094890">"Орташа"</item>
@@ -247,7 +369,13 @@
     <item msgid="4627069151979553527">"Көлбеу"</item>
     <item msgid="6896773537705206194">"Кішкене бас әріптер"</item>
   </string-array>
-    <!-- no translation found for captioning_font_size_selector_titles:3 (2784236342175159295) -->
+  <string-array name="captioning_font_size_selector_titles">
+    <item msgid="1680223634161592855">"Өте кішкене"</item>
+    <item msgid="5091603983404027034">"Кішкене"</item>
+    <item msgid="176844712416932112">"Орташа"</item>
+    <item msgid="2784236342175159295">"Үлкен"</item>
+    <item msgid="218913203203160606">"Өте үлкен"</item>
+  </string-array>
   <string-array name="captioning_edge_type_selector_titles">
     <item msgid="3865198759294188069">"Әдепкі"</item>
     <item msgid="6488643537808152001">"Ешқандай"</item>
@@ -262,7 +390,14 @@
     <item msgid="1874668269931014581">"75%"</item>
     <item msgid="6462911487571123954">"100%"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"Әдепкі параметр"</item>
+    <item msgid="8611890312638868524">"Қара түсте ақпен"</item>
+    <item msgid="5891360837786277638">"Ақта қарамен"</item>
+    <item msgid="2798457065945456853">"Қара түсте сарымен"</item>
+    <item msgid="5799049811524553967">"Көк түсте сарымен"</item>
+    <item msgid="3673930830658169860">"Арнаулы"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"PPTP VPN"</item>
     <item msgid="1349760781118368659">"L2TP/IPSec, пернелері ортақ ВЖЖ"</item>
@@ -275,15 +410,32 @@
     <item msgid="2958623927055120839">"Ешқандай"</item>
     <item msgid="1157046369795346308">"Қолмен"</item>
   </string-array>
-    <!-- no translation found for vpn_states:4 (9135049670787351881) -->
+  <string-array name="vpn_states">
+    <item msgid="5408915841694583740">"Ажыратылған"</item>
+    <item msgid="8754480102834556765">"Бастауда…"</item>
+    <item msgid="3351334355574270250">"Қосылуда..."</item>
+    <item msgid="8303882153995748352">"Жалғанған"</item>
+    <item msgid="9135049670787351881">"Күту уақыты"</item>
+    <item msgid="2124868417182583926">"Сәтсіз"</item>
+  </string-array>
   <string-array name="security_settings_premium_sms_values">
     <item msgid="1164265643455394443">"Сұрау"</item>
     <item msgid="7718817231348607934">"Әрқашан рұқсат емес"</item>
     <item msgid="8184570120217958741">"Әрқашан рұқсат"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Орташа"</item>
+    <item msgid="5101233285497327432">"Орташа"</item>
+    <item msgid="1555861583162930714">"Төмен"</item>
+    <item msgid="1719683776264798117">"Маңызды"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Қалыпты"</item>
+    <item msgid="6107138933849816768">"Орташа"</item>
+    <item msgid="182695359839047859">"Төмен"</item>
+    <item msgid="8577246509202964244">"Өте аз"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Тұрақты"</item>
     <item msgid="167418068739176448">"Ең жоғары белсенділік"</item>
@@ -304,7 +456,7 @@
     <item msgid="3151827842194201728">"Көгілдір"</item>
     <item msgid="3228505970082457852">"Көк"</item>
     <item msgid="6590260735734795647">"Индиго түсі"</item>
-    <item msgid="3521763377357218577">"Қызылкүрең"</item>
+    <item msgid="3521763377357218577">"Күлгін"</item>
     <item msgid="5932337981182999919">"Қызғылт"</item>
     <item msgid="5642914536624000094">"Қызыл"</item>
   </string-array>
diff --git a/tests/CarDeveloperOptions/res/values-kk/config.xml b/tests/CarDeveloperOptions/res/values-kk/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-kk/config.xml
+++ b/tests/CarDeveloperOptions/res/values-kk/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-kk/strings.xml b/tests/CarDeveloperOptions/res/values-kk/strings.xml
index f301c5e..60d43a3 100644
--- a/tests/CarDeveloperOptions/res/values-kk/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-kk/strings.xml
@@ -83,12 +83,11 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Экрандағы мәтінді кішірейтеді немесе үлкейтеді."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Кішірек ету"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Үлкенірек ету"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Мәтін үлгісі"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Оз қаласының ғажап сиқыршысы"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"11-тарау: Ғажайып жасыл қала Оз"</string>
-    <string name="font_size_preview_text_body" msgid="6803085337474390845">"Көздеріне жасыл көзілдірік таққан Дороти мен оның достары қалаға алғаш келгенде, оның ғажайып көркіне таңғалды. Әдемі жасыл мәрмәр үйлер көшені жағалай тізіліп тұр, бүкіл жерде жарқыраған зүбаржат тастар шашылып жатқандай. Мәрмәр жол да дәл сондай жап-жасыл, зүбаржат кірпіштен қаланған тұрғын үйлер күннен жарқырап тұр. Терезелердің әйнектері де жасыл шыныдан. Қала үстіндегі жасыл аспаннан жасыл түсті күн сәулесі түсіп тұр. \n\nКөшедегі ерлер, әйелдер мен балалар жасыл түсті киім киіп алған, олардың терілері де жасыл реңді екен. Олар Дороти мен оның әпенді достарына таңдана қарайды. Балалар Арыстанды көре сала қашып, аналарының артына тығылады. Сөйлесуге де ешкім батпайды ғой. Дороти көше бойындағы қаз-қатар дүкендердегі нәрселердің барлығы жасыл түсті екеніне тамсана қарайды. Бұл дүкендерде сатылатын кәмпиттер, поп-корн, аяқ киім, қалпақтар мен неше түрлі киімдер – барлығы жасыл еді. Бір кісі жасыл лимонад сатып тұр, балалар оны жасыл ақшаға сатып алып жатыр. \n\nМұнда жануарлар жоқ сияқты, ер адамдар заттарды кішкене жасыл арбамен алдына салып тасып барады. Барлығы бақытты, өмірге риза және уайымсыз секілді."</string>
+    <string name="font_size_preview_text_body" msgid="6803085337474390845">"Көздеріне жасыл көзілдірік таққан Дороти мен оның достары қалаға алғаш келгенде, оның ғажайып көркіне таңғалды. Әдемі жасыл мәрмәр үйлер көшені жағалай тізіліп тұр. Бүкіл жерде жарқыраған зүбаржат тастар шашылып жатқандай. Мәрмәр жол да дәл сондай жап-жасыл. Зүбаржат кірпіштен қаланған тұрғын үйлер күннен жарқырап тұр. Терезелердің әйнектері де жасыл шыныдан. Қала үстіндегі жасыл аспаннан жасыл түсті күн сәулесі түсіп тұр. \n\nКөшедегі ерлер, әйелдер мен балалар жасыл түсті киім киіп алған, олардың терілері де жасыл реңді екен. Олар Дороти мен оның әпенді достарына таңдана қарайды. Балалар Арыстанды көре сала қашып, аналарының артына тығылады. Сөйлесуге де ешкім батпайды ғой. Дороти көше бойындағы қаз-қатар дүкендердегі нәрселердің барлығы жасыл түсті екеніне тамсана қарайды. Бұл дүкендерде сатылатын кәмпиттер, поп-корн, аяқ киім, қалпақтар мен неше түрлі киімдер – барлығы жасыл еді. Бір кісі жасыл лимонад сатып тұр, балалар оны жасыл ақшаға сатып алып жатыр. \n\nМұнда жануарлар жоқ сияқты. Ер адамдар заттарды кішкене жасыл арбамен алдына салып тасып барады. Барлығы бақытты, өмірге риза және уайымсыз секілді."</string>
     <string name="font_size_save" msgid="8652044574655753921">"Жарайды"</string>
     <string name="sdcard_setting" product="nosdcard" msgid="1533784309105748696">"USB жады"</string>
     <string name="sdcard_setting" product="default" msgid="8398782065765523178">"SD картасы"</string>
@@ -349,8 +348,8 @@
     <string name="time_picker_title" msgid="1596400307061268660">"Уақыт"</string>
     <string name="lock_after_timeout" msgid="7755520959071097304">"Aвтоматты құлыптау"</string>
     <string name="lock_after_timeout_summary" msgid="3160517585613694740">"<xliff:g id="TIMEOUT_STRING">%1$s</xliff:g> ұйқыдан кейін"</string>
-    <string name="lock_immediately_summary_with_exception" msgid="6442552135409347556">"Ұйықтаудан кейін бірден, <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g> арқылы құлпы ашулы ұстаған кезді қоспағанда"</string>
-    <string name="lock_after_timeout_summary_with_exception" msgid="7218267834086717545">"<xliff:g id="TRUST_AGENT_NAME">%2$s</xliff:g> ашық күйінде ұстап тұрмаса, ұйықтағаннан кейін <xliff:g id="TIMEOUT_STRING">%1$s</xliff:g> өткен соң"</string>
+    <string name="lock_immediately_summary_with_exception" msgid="6442552135409347556">"Ұйықтаудан кейін бірден (<xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g> ашық күйінде ұстап тұрмаса)"</string>
+    <string name="lock_after_timeout_summary_with_exception" msgid="7218267834086717545">"Ұйқыдан кейін <xliff:g id="TIMEOUT_STRING">%1$s</xliff:g> өткен соң (<xliff:g id="TRUST_AGENT_NAME">%2$s</xliff:g> ашық күйінде ұстап тұрмаса)"</string>
     <string name="show_owner_info_on_lockscreen_label" msgid="4510756693837171575">"Құлыпталған экранда пайдаланушы ақпаратын көрсету"</string>
     <string name="owner_info_settings_title" msgid="2537966178998339896">"Құлып экраны мәтіні"</string>
     <string name="security_enable_widgets_title" msgid="1701510007926738088">"Виджеттерді қосу"</string>
@@ -469,9 +468,9 @@
     <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"Сканерді түртіңіз"</string>
     <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Саусақты сканерге қойып, дірілді сезгеннен кейін көтеріңіз"</string>
     <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"Саусағыңызды алып, қайта түртіңіз"</string>
-    <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Саусақ ізінің басқа бөліктерін енгізу үшін саусағыңызды көтеріп тұрыңыз"</string>
+    <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Саусақ ізінің басқа бөліктерін енгізу үшін саусағыңызды бір тигізіп, бір көтеріп тұрыңыз"</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"Саусақ ізі енгізілді"</string>
-    <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"Бұл белгіше шыққан кезде, саусақ ізі арқылы жеке басыңызды растаңыз не сатып алған нәрсені мақұлдаңыз"</string>
+    <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"Осы белгіше шыққан кезде, саусақ ізі арқылы жеке басыңызды растаңыз не сатып алған нәрсені мақұлдаңыз"</string>
     <string name="security_settings_fingerprint_enroll_enrolling_skip" msgid="1473280156532146933">"Кейінірек"</string>
     <string name="setup_fingerprint_enroll_enrolling_skip_title" msgid="2816424026528101690">"Саусақ ізін орнатуды өткізіп жіберу керек пе?"</string>
     <string name="setup_fingerprint_enroll_enrolling_skip_message" msgid="8139299964344809780">"Саусақ ізін пайдалануды телефон құлпын ашудың бір жолы ретінде таңдадыңыз. Қазір өткізіп жіберсеңіз, мұны кейінірек орнату керек. Орнату бір минутқа жақын уақыт алады."</string>
@@ -489,7 +488,7 @@
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"Бұл сенсор емес"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"Телефонның артындағы датчикті сұқ саусақпен түртіңіз."</string>
     <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"Тіркеу аяқталмады"</string>
-    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Саусақ ізін тіркеу уақытының шегіне жеттіңіз. Әрекетті қайталаңыз."</string>
+    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Саусақ ізін тіркеу уақыты бітті. Әрекетті қайталаңыз."</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"Саусақ ізін тіркеу нәтиже бермеді. Әрекетті қайталаңыз немесе басқа саусақты пайдаланыңыз."</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"Тағы біреуін енгізу"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"Келесі"</string>
@@ -502,7 +501,7 @@
     <string name="fingerprint_last_delete_title" msgid="3104596858161269635">"Барлық саусақ іздерін жою керек пе?"</string>
     <string name="fingerprint_delete_title" msgid="3120894112324235536">"\"<xliff:g id="FINGERPRINT_ID">%1$s</xliff:g>\" жою"</string>
     <string name="fingerprint_delete_message" msgid="5895802741486967970">"Саусақ ізі жойылсын ба?"</string>
-    <string name="fingerprint_last_delete_message" msgid="3346252479778971442">"Телефон құлпын ашу, сатып алуларды авторизациялау немесе олармен қолданбаларға кіру үшін саусақ іздерін пайдалана алмайсыз"</string>
+    <string name="fingerprint_last_delete_message" msgid="3346252479778971442">"Телефон құлпын ашу, сатып алу транзакцияларын мақұлдау немесе қолданбаларға кіру үшін саусақ іздерін пайдалана алмайсыз."</string>
     <string name="fingerprint_last_delete_message_profile_challenge" msgid="5385095150532247025">"Жұмыс профилінің құлпын ашу, сатып алуды авторизациялау немесе жұмыс қолданбаларына кіру үшін саусақ ізін пайдалану мүмкін болмайды"</string>
     <string name="fingerprint_last_delete_confirm" msgid="7984595457589664004">"Иә, жою"</string>
     <string name="crypt_keeper_settings_title" msgid="839783588093862748">"Шифрлау"</string>
@@ -668,7 +667,6 @@
       <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> таңбадан аз болуы керек</item>
       <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> таңбадан аз болуы керек</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Тек 0-9 арасындағы сандар болуы керек"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Құрылғы әкімшісі жақында пайдаланылған PIN кодын қолдануға рұқсат бермейді"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"АТ әкімшісі оңай PIN кодтарына тыйым салды. Басқа PIN кодын енгізіп көріңіз."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Жарамсыз таңба болмауы керек"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Кемінде <xliff:g id="COUNT">%d</xliff:g> әріптік емес таңба болуы керек</item>
       <item quantity="one">Кемінде 1 әріптік емес таңба болуы керек</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Кемінде <xliff:g id="COUNT">%d</xliff:g> сандық емес таңба болуы керек.</item>
+      <item quantity="one">Кемінде 1 сандық емес таңба болуы керек.</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Құрылғы әкімшісі жуықтағы құпиясөзді қолдануға рұқсат бермейді"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Оңай құпия сөздерге АТ әкімшісі тыйым салды. Басқа құпия сөз енгізіп көріңіз."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Сандардың артатын, кемитін немесе қайталанатын ретіне рұқсат берілмейді"</string>
@@ -855,7 +857,7 @@
     <string name="wifi_poor_network_detection_summary" msgid="5539951465985614590">"Интернет байланысы жақсы болмаса, Wi‑Fi желісі қолданылмайды"</string>
     <string name="wifi_avoid_poor_network_detection_summary" msgid="1976503191780928104">"Тек жақсы интернет байланысы бар желілерді пайдалану"</string>
     <string name="use_open_wifi_automatically_title" msgid="3084513215481454350">"Ашық желілерге қосылу"</string>
-    <string name="use_open_wifi_automatically_summary" msgid="8338020172673161754">"Жоғары сапалы ашық желілерге автоматты қосылу"</string>
+    <string name="use_open_wifi_automatically_summary" msgid="8338020172673161754">"Жоғары сапалы қоғамдық желілерге автоматты қосылу"</string>
     <string name="use_open_wifi_automatically_summary_scoring_disabled" msgid="1559329344492373028">"Пайдалану үшін желіні бағалау провайдерін таңдаңыз"</string>
     <string name="use_open_wifi_automatically_summary_scorer_unsupported_disabled" msgid="1123080670578756834">"Пайдалану үшін үйлесімді желіні бағалау провайдерін таңдаңыз"</string>
     <string name="wifi_install_credentials" msgid="5650088113710858289">"Сертификаттар орнату"</string>
@@ -912,13 +914,13 @@
     <string name="wifi_ip_address" msgid="5572539114989914831">"IP мекенжайы"</string>
     <string name="passpoint_label" msgid="7429247462404128615">"Сақталу жолы"</string>
     <string name="passpoint_content" msgid="340527524510304327">"<xliff:g id="NAME">%1$s</xliff:g> тіркелгі деректері"</string>
-    <string name="wifi_eap_method" msgid="3752116941487485859">"EAP (кеңейтілген растау протоколы) әдісі"</string>
-    <string name="please_select_phase2" msgid="5848080896810435677">"Фаза 2 растауы"</string>
+    <string name="wifi_eap_method" msgid="3752116941487485859">"EAP әдісі"</string>
+    <string name="please_select_phase2" msgid="5848080896810435677">"Аутентификацияның 2-сатысы"</string>
     <string name="wifi_eap_ca_cert" msgid="1496395241849383785">"Растама мекемесінің сертификаты"</string>
     <string name="wifi_eap_domain" msgid="3298302320003640130">"Домен"</string>
     <string name="wifi_eap_user_cert" msgid="6786839531765719173">"Пайдаланушы сертификаты"</string>
     <string name="wifi_eap_identity" msgid="5280457017705738773">"Бірлік"</string>
-    <string name="wifi_eap_anonymous" msgid="6352344972490839958">"Анонимді бірлік"</string>
+    <string name="wifi_eap_anonymous" msgid="6352344972490839958">"Белгісіз"</string>
     <string name="wifi_password" msgid="6942983531275177771">"Құпия сөз"</string>
     <string name="wifi_show_password" msgid="7878398590772942202">"Құпия сөзді көрсету"</string>
     <string name="wifi_ap_band_config" msgid="6565016368079288433">"Wi-Fi жиілік ауқымын таңдау"</string>
@@ -931,7 +933,7 @@
     <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"Wi‑Fi хотспоты үшін кемінде бір диапазонды таңдаңыз:"</string>
     <string name="wifi_ip_settings" msgid="4636102290236116946">"IP параметрлері"</string>
     <string name="wifi_privacy_settings" msgid="4462092795794247809">"Құпиялылық"</string>
-    <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"Еркін таңдалған MAC"</string>
+    <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"Кездейсоқ MAC"</string>
     <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"Құрылғыны қосу"</string>
     <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"Құрылғыны “<xliff:g id="SSID">%1$s</xliff:g>” желісіне қосу үшін төмендегі QR кодын ортасына туралаңыз"</string>
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"QR кодын сканерлеу"</string>
@@ -961,7 +963,7 @@
     <string name="wifi_dpp_lockscreen_title" msgid="3910665850075275963">"Сіз екеніңізді растаңыз"</string>
     <string name="wifi_dpp_wifi_password" msgid="8007558344032612455">"Wi-Fi құпия сөзі: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
     <string name="wifi_dpp_hotspot_password" msgid="6172326289042241924">"Хотспот құпия сөзі: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
-    <string name="wifi_dpp_add_device" msgid="1347056725253936358">"Құрылғы енгізу"</string>
+    <string name="wifi_dpp_add_device" msgid="1347056725253936358">"Құрылғы қосу"</string>
     <string name="wifi_dpp_connect_network_using_qr_code" msgid="115993715600532357">"Бұл желіге QR коды арқылы кіріңіз."</string>
     <string name="retry" msgid="8500839563577344702">"Қайталау"</string>
     <string name="wifi_shared" msgid="5054256778276524960">"Басқа құрылғы пайдаланушыларымен бөлісу"</string>
@@ -1034,8 +1036,8 @@
     <string name="wifi_ip_settings_invalid_gateway" msgid="7602732367437862422">"Жарамды торап мекенжайын теріңіз."</string>
     <string name="wifi_ip_settings_invalid_dns" msgid="4471473055625376300">"Жарамды DNS мекенжайын теріңіз."</string>
     <string name="wifi_ip_settings_invalid_network_prefix_length" msgid="392977552691002076">"Желі префиксінің ұзындығын 0 және 32 аралығында теріңіз"</string>
-    <string name="wifi_dns1" msgid="5250809981658822505">"DNS 1 (домен атауы жүйесі)"</string>
-    <string name="wifi_dns2" msgid="1905876166783761641">"DNS 2  (домен атауы жүйесі)"</string>
+    <string name="wifi_dns1" msgid="5250809981658822505">"DNS 1"</string>
+    <string name="wifi_dns2" msgid="1905876166783761641">"DNS 2"</string>
     <string name="wifi_gateway" msgid="7455334454444443397">"Торап"</string>
     <string name="wifi_network_prefix_length" msgid="1941206966133010633">"Желі префиксінің ұзындығы"</string>
     <string name="wifi_p2p_settings_title" msgid="3213180637906683308">"Wi‑Fi Direct"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Мобильдік"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Егер Wi‑Fi қолжетімді болмаса, мобильдік желі пайдаланылады."</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Мобильдік желі қолжетімді болмаса, Wi‑Fi пайдалану"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Wi‑Fi арқылы қоңырау шалу. Wi‑Fi байланысы жоғалса, қоңырау аяқталады."</string>
@@ -1204,7 +1209,7 @@
     <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"Қосулы кезде экранға қарап тұрсаңыз, ол өшпейді."</string>
     <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"Өшірулі"</string>
     <string name="adaptive_sleep_description" msgid="812673735459170009">"Экранға қарап тұрған кезде, оның өшуіне жол бермейді."</string>
-    <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Адаптивті ұйқы режимі экранға қараған адамды тану үшін алдыңғы камераны пайдаланады. Ол құрылғыда жұмыс істейді, суреттер Google жүйесінде сақталмайды және оған жіберілмейді."</string>
+    <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"\"Экран сезімталдығы\" функциясы алдыңғы камера арқылы экранға адамның қарап тұрғанын тани алады. Ол құрылғыда ғана жұмыс істейді. Суреттер Google жүйесінде сақталмайды және оған жіберілмейді."</string>
     <string name="night_display_title" msgid="1305002424893349814">"Түнгі жарық"</string>
     <string name="night_display_text" msgid="5330502493684652527">"\"Түнгі жарық\" функциясы экраныңызға ашық сары реңк береді. Бұл қараңғыда экранға қарауды жеңілдетеді әрі жылдам ұйықтауға да көмектесуі мүмкін."</string>
     <string name="night_display_auto_mode_title" msgid="8493573087102481588">"Уақыт кестесі"</string>
@@ -1453,7 +1458,7 @@
     <string name="storage_detail_system" msgid="6784247618772153283">"Жүйе"</string>
     <string name="storage_detail_explore" msgid="8206900269596580264">"<xliff:g id="NAME">^1</xliff:g> ашу"</string>
     <string name="storage_detail_dialog_other" msgid="5073511663616043370">"Басқаларында қолданбалар сақтаған файлдар, интернет немесе Bluetooth арқылы жүктелген файлдар, Android файлдары, т.б. қамтылады. \n\n<xliff:g id="NAME">^1</xliff:g> құрылғысындағы мазмұндарды көру үшін \"Зерттеу\" түймесін түртіңіз."</string>
-    <string name="storage_detail_dialog_system" msgid="1472572861360014226">"Жүйе Android <xliff:g id="VERSION">%s</xliff:g> нұсқасын іске қосуға пайдаланылатын файлдарды қамтиды"</string>
+    <string name="storage_detail_dialog_system" msgid="1472572861360014226">"\"Жүйе\" қалтасында Android <xliff:g id="VERSION">%s</xliff:g> жұмысына қажетті файлдар орналасқан."</string>
     <string name="storage_detail_dialog_user" msgid="1663117417635010371">"<xliff:g id="USER_0">^1</xliff:g> жадта <xliff:g id="SIZE">^2</xliff:g> орын алатын суреттерді, музыка файлдарын, қолданбаларды не басқа деректерді сақтаған болуы керек. \n\nМәліметтерді көру үшін <xliff:g id="USER_1">^1</xliff:g> есептік жазбасына кіріңіз."</string>
     <string name="storage_wizard_init_title" msgid="3407283236421089014">"<xliff:g id="NAME">^1</xliff:g> орнату"</string>
     <string name="storage_wizard_init_external_title" msgid="6853250619674645478">"Портативті жад ретінде пайдалану"</string>
@@ -1632,9 +1637,9 @@
     <string name="sms_change_default_dialog_title" msgid="6301260161969667578">"SMS қолданбасы өзгертілсін бе?"</string>
     <string name="sms_change_default_dialog_text" msgid="8275088077930942680">"<xliff:g id="NEW_APP">%1$s</xliff:g> қолданбасы <xliff:g id="CURRENT_APP">%2$s</xliff:g> орнына SMS қолданбасы ретінде қолданылсын ба?"</string>
     <string name="sms_change_default_no_previous_dialog_text" msgid="4680224695080527907">"<xliff:g id="NEW_APP">%s</xliff:g> қолданбасы SMS қолданбасы ретінде қолданылсын ба?"</string>
-    <string name="network_scorer_picker_title" msgid="1691073966560952916">"Желі рейтингісін ұсынған"</string>
+    <string name="network_scorer_picker_title" msgid="1691073966560952916">"Желіні бағалау провайдері"</string>
     <string name="network_scorer_picker_none_preference" msgid="6448280557733231737">"Ешқандай"</string>
-    <string name="network_scorer_change_active_dialog_title" msgid="4274159562371475090">"Wi‑Fi assistant өзгерту керек пе?"</string>
+    <string name="network_scorer_change_active_dialog_title" msgid="4274159562371475090">"Wi‑Fi көмек құралын ауыстыру керек пе?"</string>
     <string name="network_scorer_change_active_dialog_text" msgid="4264089809189760730">"Желілік байланыстарды басқару үшін <xliff:g id="CURRENT_APP">%2$s</xliff:g> орнына <xliff:g id="NEW_APP">%1$s</xliff:g> қолданбасын пайдалану керек пе?"</string>
     <string name="network_scorer_change_active_no_previous_dialog_text" msgid="6394483538843474495">"Желілік байланыстарды басқару үшін <xliff:g id="NEW_APP">%s</xliff:g> қолданбасын пайдалану керек пе?"</string>
     <string name="mobile_unknown_sim_operator" msgid="872589370085135817">"Белгісіз SIM операторы"</string>
@@ -1837,8 +1842,8 @@
     <string name="show_running_services" msgid="1895994322704667543">"Қосылған қызметтерді көрсету"</string>
     <string name="show_background_processes" msgid="88012264528093617">"Кэштелген үрдістерді көрсету"</string>
     <string name="default_emergency_app" msgid="286530070173495823">"Төтенше жағдай қолданбасы"</string>
-    <string name="reset_app_preferences" msgid="1426500030595212077">"Қолданба реттеуін бастапқы күйге қайтару"</string>
-    <string name="reset_app_preferences_title" msgid="792909865493673598">"Қолданба реттеулері бастапқы күйге қайтарылсын ба?"</string>
+    <string name="reset_app_preferences" msgid="1426500030595212077">"Қолданба параметрлерін бастапқы күйге қайтару"</string>
+    <string name="reset_app_preferences_title" msgid="792909865493673598">"Қолданба параметрлері бастапқы күйге қайтарылсын ба?"</string>
     <string name="reset_app_preferences_desc" msgid="7935273005301096031">"Төмендегі реттеулер бастапқы күйге қайтарылады: \n\n "<li>"Өшірілген қолданбалар"</li>\n" "<li>"Өшірілген қолданба хабарландырулары"</li>\n" "<li>"Әрекеттерге арналған әдепкі қолданбалар"</li>\n" "<li>"Фондық режимдегі дерек тасымалын шектеу"</li>\n" "<li>"Қандай да бір рұқсат шектеулері"</li>\n\n" Қолданба деректері жоғалмайды."</string>
     <string name="reset_app_preferences_button" msgid="2041894727477934656">"Бастапқы күйге қайтару"</string>
     <string name="manage_space_text" msgid="6166469422303124302">"Кеңістікті басқару"</string>
@@ -2036,9 +2041,9 @@
     <string name="vision_settings_description" msgid="3476589459009287332">"Бұл құрылғыны қажеттіліктерге сай реттей аласыз. Бұл арнайы мүмкіндіктерді кейінірек \"Параметрлер\" тармағында өзгертуге болады."</string>
     <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"Қаріп өлшемін өзгерту"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"Экранды оқу құралдары"</string>
-    <string name="audio_and_captions_category_title" msgid="6140472938769619212">"Аудиомазмұн және экранға шығатын мәтін"</string>
+    <string name="audio_and_captions_category_title" msgid="6140472938769619212">"Аудио және экранға шығатын мәтін"</string>
     <string name="display_category_title" msgid="545168481672250195">"Дисплей"</string>
-    <string name="interaction_control_category_title" msgid="8775039211811947683">"Өзара әрекеттестікті басқару элементтері"</string>
+    <string name="interaction_control_category_title" msgid="8775039211811947683">"Басқару элементтері"</string>
     <string name="user_installed_services_category_title" msgid="4288689493753221319">"Жүктеп алынған қызметтер"</string>
     <string name="experimental_category_title" msgid="3797000069740110717">"Эксперименттік"</string>
     <string name="feature_flags_dashboard_title" msgid="3153034144122754381">"Функция жалаушалары"</string>
@@ -2272,7 +2277,7 @@
     <string name="battery_tip_smart_battery_title" product="tablet" msgid="203494973250969040">"Планшет батареясының қызметтік мерзімін ұзартыңыз"</string>
     <string name="battery_tip_smart_battery_title" product="device" msgid="7419448992583346364">"Құрылғы батареясының қызметтік мерзімін ұзартыңыз"</string>
     <string name="battery_tip_smart_battery_summary" msgid="5344821856478265778">"Battery Manager функциясын қосыңыз"</string>
-    <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Battery Saver функциясын қосыңыз"</string>
+    <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Battery Saver функциясын қосу"</string>
     <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Батареяның заряды тез азаюы мүмкін"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Battery Saver қосулы"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Кейбір функциялар шектелуі мүмкін"</string>
@@ -2601,7 +2606,7 @@
     <string name="background_data_summary" msgid="799640633948841990">"Қолданбалар деректерді синхрондау, жіберу жұмыстарын орындайды және кез келген уақытта қабылдай алады."</string>
     <string name="background_data_dialog_title" msgid="8306650658158895976">"Жалпы мағлұматтар дерекқоры істен шығарылсын ба?"</string>
     <string name="background_data_dialog_message" msgid="8126774244911656527">"Артқы шеп деректерін өшіру батарея жұмысын ұзартады және дерек қолданысын азайтады. Кейбір қолданбалар сонда да артқы шеп байланысын қолдануы мүмкін."</string>
-    <string name="sync_automatically" msgid="5746117156896468099">"Қолданба дерекқорын авто синхрондау"</string>
+    <string name="sync_automatically" msgid="5746117156896468099">"Қолданба дерегін автосинхрондау"</string>
     <string name="sync_enabled" msgid="535172627223336983">"Синхронизация ҚОСУЛЫ"</string>
     <string name="sync_disabled" msgid="713721807204805062">"Синх ӨШІРУЛІ"</string>
     <string name="sync_error" msgid="988155155932442765">"Синх қателігі"</string>
@@ -2661,12 +2666,12 @@
     <string name="data_usage_menu_show_ethernet" msgid="2130574690318410238">"Этернет қолданысын көрсету"</string>
     <string name="data_usage_menu_hide_ethernet" msgid="1191233197312414533">"Ethernet пайдал-ды жасыру"</string>
     <string name="data_usage_menu_metered" msgid="3087525150259956831">"Желілік шектеулер"</string>
-    <string name="data_usage_menu_auto_sync" msgid="3350154877737572146">"Дерекқорды авто-синхрондау"</string>
+    <string name="data_usage_menu_auto_sync" msgid="3350154877737572146">"Деректі автосинхрондау"</string>
     <string name="data_usage_menu_sim_cards" msgid="8508154611676507088">"SIM карталары"</string>
     <string name="data_usage_cellular_data_summary" msgid="9162777397135709280">"Шектеуде кідіртілген"</string>
     <string name="account_settings_menu_auto_sync" msgid="2673669556006027506">"Деректерді автосинхрондау"</string>
-    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"Жеке деректерді авто-синхрондау"</string>
-    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Жұмыс деректерін авто-синхрондау"</string>
+    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"Жеке деректі автосинхрондау"</string>
+    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Жұмыс дерегін автосинхрондау"</string>
     <string name="data_usage_change_cycle" msgid="447761920472170031">"Айналымды өзгерту…"</string>
     <string name="data_usage_pick_cycle_day" msgid="6319750879145917066">"Дерекқор қолдану айналымын қайта реттеу күні:"</string>
     <string name="data_usage_empty" msgid="7981405723435034032">"Бұл уақыт аралығында ешқандай қолданба дерек пайдаланған жоқ."</string>
@@ -2845,7 +2850,7 @@
     <string name="user_settings_title" msgid="7917598650933179545">"Бірнеше пайдаланушы"</string>
     <string name="user_settings_footer_text" product="device" msgid="4573858247439190545">"Жаңа пайдаланушыларды енгізу арқылы құрылғыны ортақ пайдаланыңыз. Әр пайдаланушының құрылғыда арнаулы негізгі экрандар, есептік жазбалар, қолданбалар, параметрлер, т.б. үшін жеке профилі болады."</string>
     <string name="user_settings_footer_text" product="tablet" msgid="780018221428132918">"Жаңа пайдаланушыларды енгізу арқылы планшетті ортақ пайдаланыңыз. Әр пайдаланушының планшетте арнаулы негізгі экрандар, есептік жазбалар, қолданбалар, параметрлер, т.б. үшін жеке профилі болады."</string>
-    <string name="user_settings_footer_text" product="default" msgid="1470859614968237491">"Жаңа пайдаланушыларды енгізу арқылы телефонды ортақ пайдаланыңыз. Әр пайдаланушының телефонда арнаулы негізгі экрандар, есептік жазбалар, қолданбалар, параметрлер, т.б. үшін жеке профилі болады."</string>
+    <string name="user_settings_footer_text" product="default" msgid="1470859614968237491">"Басқа пайдаланушыларды қосу арқылы телефонды бөлісіп пайдалануға болады. Әр пайдаланушының өз негізгі экраны, есептік жазбалары, қолданбалары, параметрлері, т.б. үшін жеке профилі болады."</string>
     <string name="user_list_title" msgid="6670258645246192324">"Пайдаланушылар мен профайлдар"</string>
     <string name="user_add_user_or_profile_menu" msgid="4220679989900149336">"Пайдаланушы немесе профиль қосу"</string>
     <string name="user_add_user_menu" msgid="9006572936456324794">"Пайдаланушы қосу"</string>
@@ -2868,7 +2873,7 @@
     <string name="user_add_user_message_long" msgid="686637203224195465">"Қосымша профильдер жасай отырып, бұл құрылғыны басқалармен ортақ пайдалануға болады. Әр пайдаланушы қолданбаларды, тұсқағаздарды орнатып, профилін өз қалауынша реттей алады. Сондай-ақ барлығы ортақ қолданатын Wi‑Fi сияқты параметрлерді де реттеуге болады.\n\nЖаңа пайдаланушы енгізілгенде, ол өз профилін реттеуі керек болады.\n\nКез келген пайдаланушы барлық басқа пайдаланушылар үшін қолданбаларды жаңарта алады. Арнайы мүмкіндіктерге қатысты параметрлер мен қызметтер жаңа пайдаланушыға өтпейді."</string>
     <string name="user_add_user_message_short" msgid="1802594476285458254">"Жаңа пайдаланушыны қосқанда сол адам өз кеңістігін реттеуі керек.\n\nКез келген пайдаланушы барлық басқа пайдаланушылар үшін қолданбаларды жаңарта алады."</string>
     <string name="user_setup_dialog_title" msgid="6748950002206392396">"Профиль құру керек пе?"</string>
-    <string name="user_setup_dialog_message" msgid="2988559933258353919">"Пайдаланушы құрылығыны алып, өз профилін реттеуі керек."</string>
+    <string name="user_setup_dialog_message" msgid="2988559933258353919">"Пайдаланушы құрылғыны алып, өз профилін реттеуі керек."</string>
     <string name="user_setup_profile_dialog_message" msgid="7611900802824048526">"Профайл қазір жасақталсын ба?"</string>
     <string name="user_setup_button_setup_now" msgid="4941459406266856176">"Қазір құру"</string>
     <string name="user_setup_button_setup_later" msgid="6596031428556518752">"Қазір емес"</string>
@@ -2877,7 +2882,7 @@
     <string name="user_cannot_add_accounts_message" msgid="5993561303748749097">"Шектелген профайлдардың есептік жазба қосу мүмкіндігі жоқ"</string>
     <string name="user_remove_user_menu" msgid="3505139157217459864">"<xliff:g id="USER_NAME">%1$s</xliff:g> осы құралдан жою"</string>
     <string name="user_lockscreen_settings" msgid="3820813814848394568">"Құлып экранының параметрлері"</string>
-    <string name="user_add_on_lockscreen_menu" msgid="5211604808199585774">"Пайдаланушыларды құлып экранынан енгізу"</string>
+    <string name="user_add_on_lockscreen_menu" msgid="5211604808199585774">"Құлыптаулы экраннан пайдаланушыларды енгізу"</string>
     <string name="user_new_user_name" msgid="3880395219777884838">"Жаңа пайдаланушы"</string>
     <string name="user_new_profile_name" msgid="3074939718101489937">"Жаңа профайл"</string>
     <string name="user_confirm_remove_self_title" msgid="6739480453680217543">"Өзіңізді жоясыз ба?"</string>
@@ -2920,7 +2925,7 @@
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Басқа төлем қолданбасы ашық кезді қоспағанда"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"\"Tap &amp; pay\" терминалында төлеу жолы:"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Терминалда төлеу"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Төлем қолданбасын орнатыңыз. Содан кейін жай телефонның артқы жағын тигізбейтін таңбасы бар кез келген терминал жанында ұстап тұрыңыз."</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Төлем қолданбасын реттеңіз. Содан кейін телефонның артқы жағын контактісіз төлем таңбасы бар терминалға жақындатыңыз."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"Түсінікті"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"Қосымша…"</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"Қалаулы ретінде реттеу қажет пе?"</string>
@@ -3002,8 +3007,8 @@
     <string name="sim_editor_number" msgid="1757338150165234970">"Нөмір"</string>
     <string name="sim_editor_color" msgid="373059962306191123">"SIM түсі"</string>
     <string name="sim_card_select_title" msgid="4925862525985187946">"SIM картасын таңдау"</string>
-    <string name="color_orange" msgid="3159707916066563431">"Сарғылт"</string>
-    <string name="color_purple" msgid="4391440966734810713">"Қызылкүрең"</string>
+    <string name="color_orange" msgid="3159707916066563431">"Қызғылт сары"</string>
+    <string name="color_purple" msgid="4391440966734810713">"Күлгін"</string>
     <string name="sim_no_inserted_msg" msgid="1197884607569714609">"SIM карталары салынбаған"</string>
     <string name="sim_status_title" msgid="4483653750844520871">"SIM күйі"</string>
     <string name="sim_status_title_sim_slot" msgid="416005570947546124">"SIM картасының күйі (sim ұясы: %1$d)"</string>
@@ -3132,7 +3137,7 @@
     <string name="media_volume_option_title" msgid="3553411883305505682">"Mультимeдиа дыбыс деңгейі"</string>
     <string name="remote_media_volume_option_title" msgid="6355710054191873836">"Трансляцияның дыбыс деңгейі"</string>
     <string name="call_volume_option_title" msgid="5028003296631037334">"Сөйлескендегі дыбыс деңгейі"</string>
-    <string name="alarm_volume_option_title" msgid="3184076022438477047">"Дабылдың дыбыс деңгейі"</string>
+    <string name="alarm_volume_option_title" msgid="3184076022438477047">"Оятқыштың дыбыс деңгейі"</string>
     <string name="ring_volume_option_title" msgid="2038924918468372264">"Қоңыраудың дыбыс деңгейі"</string>
     <string name="notification_volume_option_title" msgid="1358512611511348260">"Хабарландырудың дыбыс деңгейі"</string>
     <string name="ringtone_title" msgid="1409086028485922583">"Телефон әуені"</string>
@@ -3157,7 +3162,7 @@
     <string name="emergency_tone_vibrate" msgid="5020068066905681181">"Діріл"</string>
     <string name="boot_sounds_title" msgid="7583926202411353620">"Дыбыстарды қосу"</string>
     <string name="live_caption_title" msgid="7926591158657997051">"Live Caption"</string>
-    <string name="live_caption_summary" msgid="9064771862352393125">"Автоматты субтитр мультимедиасы"</string>
+    <string name="live_caption_summary" msgid="9064771862352393125">"Автоматты субтитр қосу"</string>
     <string name="zen_mode_settings_summary_off" msgid="6929319200478424962">"Ешқашан"</string>
     <plurals name="zen_mode_settings_summary_on" formatted="false" msgid="6061723291126091396">
       <item quantity="other"><xliff:g id="ON_COUNT">%d</xliff:g> іске қосылды</item>
@@ -3171,7 +3176,7 @@
     <string name="zen_mode_behavior_no_sound" msgid="7290387625018248748">"Дыбыссыз"</string>
     <string name="zen_mode_behavior_total_silence" msgid="371498357539257671">"Толық тыныштық"</string>
     <string name="zen_mode_behavior_no_sound_except" msgid="8894465423364103198">"<xliff:g id="CATEGORIES">%1$s</xliff:g> санатынан басқа дыбыстар қосылмасын"</string>
-    <string name="zen_mode_behavior_alarms_only" msgid="8406622989983047562">"Дабылдар мен медиа сигналдарынан басқа дыбыстар болмасын"</string>
+    <string name="zen_mode_behavior_alarms_only" msgid="8406622989983047562">"Оятқыштар мен мультимедиадан басқа дыбыстар болмасын"</string>
     <string name="zen_mode_automation_settings_title" msgid="3916960043054489008">"Кестелер"</string>
     <string name="zen_mode_delete_automatic_rules" msgid="2455264581527305755">"Кестелерді жою"</string>
     <string name="zen_mode_schedule_delete" msgid="7786092652527516740">"Жою"</string>
@@ -3184,7 +3189,7 @@
     <string name="zen_mode_schedule_title" msgid="5275268813192802631">"Кесте"</string>
     <string name="zen_mode_use_automatic_rule" msgid="446326253915861824">"Кестені пайдалану"</string>
     <string name="zen_mode_option_important_interruptions" msgid="5173944276846940149">"Маңыздылары ғана"</string>
-    <string name="zen_mode_option_alarms" msgid="4843278125235203076">"Тек дабылдар"</string>
+    <string name="zen_mode_option_alarms" msgid="4843278125235203076">"Оятқыштар ғана"</string>
     <string name="zen_mode_option_no_interruptions" msgid="4723700274519260852">"Толық тыныштық"</string>
     <string name="zen_mode_summary_combination" msgid="6960111215170691605">"<xliff:g id="MODE">%1$s</xliff:g>: <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
     <string name="zen_mode_visual_interruptions_settings_title" msgid="8378266552787406849">"Көрнекі мазалағыштарды бөгеу"</string>
@@ -3301,10 +3306,10 @@
     <string name="hide_silent_icons_title" msgid="1070905516921542662">"Дыбыссыз хабарландыру күйінің белгішелерін жасыру"</string>
     <string name="hide_silent_icons_summary" msgid="2624346914488256888">"Күй жолағындағы дыбыссыз хабарландырулардың белгішелерін жасыру"</string>
     <string name="notification_badging_title" msgid="6311699476970264712">"Хабарландыру белгілеріне рұқсат беру"</string>
-    <string name="notification_bubbles_title" msgid="9196562435741861317">"Қалқымалы анықтамалар"</string>
+    <string name="notification_bubbles_title" msgid="9196562435741861317">"Қалқыма хабарлар"</string>
     <string name="notification_bubbles_summary" msgid="4624512775901949578">"Қалқымалы таңбашалар арқылы кез келген жерден қолданба мазмұнына жылдам кіру"</string>
     <string name="bubbles_feature_education" msgid="8979109826818881018">"Кейбір хабарландырулар және басқа мазмұндар экранға қалқымалы анықтамалар түрінде шығуы мүмкін. Қалқымалы анықтаманы ашу үшін оны түртіңіз. Жасыру үшін экранның төменгі жағына қарай сүйреңіз."</string>
-    <string name="bubbles_app_toggle_title" msgid="6401217027603326439">"Қалқымалы анықтамалар"</string>
+    <string name="bubbles_app_toggle_title" msgid="6401217027603326439">"Қалқыма хабарлар"</string>
     <string name="bubbles_app_toggle_summary" msgid="7707611139796553855">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасына кейбір хабарландыруларды қалқымалы анықтама түрінде көрсетуге рұқсат береді."</string>
     <string name="bubbles_feature_disabled_dialog_title" msgid="3375452386012079293">"Қалқымалы анықтамаларды қосу"</string>
     <string name="bubbles_feature_disabled_dialog_text" msgid="326945485806386477">"Қалқымалы анықтамаларды қолданбада қосу үшін оларды алдымен құрылғыда қосу керек. Бұл бұрын қалқымалы анықтамалар қосылған қолданбалардың жұмысына әсер етеді."</string>
@@ -3316,12 +3321,12 @@
     <string name="notification_pulse_title" msgid="4861418327614907116">"Жыпылықтаған жарық"</string>
     <string name="lock_screen_notifications_title" msgid="6889072265118747835">"Құлып экранында"</string>
     <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"Жұмыс профилі өшірулі болғанда"</string>
-    <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Бүкіл хабарландыру мазмұнын көрсету"</string>
+    <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Хабарландыруды толық көрсету"</string>
     <string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"Құпия мәліметті жасыру"</string>
     <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"Хабарландыруларды мүлде көрсетпеу"</string>
     <string name="lock_screen_notifications_interstitial_message" msgid="4230189215124387818">"Құрылғы құлыптаулы кезде, хабарландырулар қалай көрсетілуі керек?"</string>
     <string name="lock_screen_notifications_interstitial_title" msgid="2832587379332443505">"Хабарландырулар"</string>
-    <string name="lock_screen_notifications_summary_show_profile" msgid="8908775469657073273">"Жұмыс хабарландыруының бүкіл мазмұнын көрсету"</string>
+    <string name="lock_screen_notifications_summary_show_profile" msgid="8908775469657073273">"Жұмыс хабарландыруын толық көрсету"</string>
     <string name="lock_screen_notifications_summary_hide_profile" msgid="7898086300511010591">"Маңызды жұмыс мазмұнын жасыру"</string>
     <string name="lock_screen_notifications_interstitial_message_profile" msgid="3324187664458600354">"Құрылғы бекітілген болса, профиль хабарландырулары қалай көрсетілуі керек?"</string>
     <string name="lock_screen_notifications_interstitial_title_profile" msgid="4043621508889929254">"Профиль хабарландырулары"</string>
@@ -3463,8 +3468,8 @@
     <string name="zen_mode_schedule_rule_days" msgid="220627703673691816">"Күндер"</string>
     <string name="zen_mode_schedule_rule_days_none" msgid="6011716195119389956">"Ешқандай"</string>
     <string name="zen_mode_schedule_rule_days_all" msgid="8814173364016139675">"Күн сайын"</string>
-    <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"Дабыл аяқталу уақытын өзгерте алады"</string>
-    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"Дабыл берілген кезде, кесте өшеді"</string>
+    <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"Оятқыш аяқталу уақытын өзгерте алады"</string>
+    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"Оятқыш қосылған кезде, кесте өшеді"</string>
     <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"\"Мазаламау\" режимі"</string>
     <string name="zen_mode_custom_behavior_summary_default" msgid="3509865340195397447">"Әдепкі параметрлерді пайдалану"</string>
     <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"Осы кесте үшін ерекше параметрлер орнату"</string>
@@ -3504,7 +3509,7 @@
     <string name="zen_mode_reminders_list" msgid="7347061314032326677">"еске салғыштар"</string>
     <string name="zen_mode_events" msgid="5784076928339534984">"Іс-шараларға рұқсат ету"</string>
     <string name="zen_mode_bypassing_apps" msgid="3080739479028713449">"Қолданбаларға қайта анықтауға рұқсат беру"</string>
-    <string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"Қолданба ерекшеліктері"</string>
+    <string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"Қолданбаларға арналған ерекшеліктер"</string>
     <plurals name="zen_mode_bypassing_apps_subtext" formatted="false" msgid="8723144434730871572">
       <item quantity="other"><xliff:g id="NUMBER">%1$d</xliff:g> қолданбадан келетін хабарландырулар \"Мазаламау\" режимін қайта анықтай алады</item>
       <item quantity="one">1 қолданбадан келетін хабарландырулар \"Мазаламау\" режимін қайта анықтай алады</item>
@@ -3672,7 +3677,7 @@
     <string name="default_app" msgid="8861276008866619872">"(Әдепкі)"</string>
     <string name="system_app" msgid="4111402206594443265">"(Жүйе)"</string>
     <string name="system_default_app" msgid="1454719098589351197">"(Жүйенің әдепкі мәні)"</string>
-    <string name="apps_storage" msgid="5658466038269046038">"Қолданбалар қоймасы"</string>
+    <string name="apps_storage" msgid="5658466038269046038">"Қолданбалар жады"</string>
     <string name="usage_access" msgid="2023443456361489516">"Пайдалану тарихын көру"</string>
     <string name="permit_usage_access" msgid="3321727608629752758">"Пайдалануға рұқсат беру"</string>
     <string name="app_usage_preference" msgid="5691545073101551727">"Қолданба пайдалану параметрлері"</string>
@@ -3758,8 +3763,8 @@
     <string name="assist_access_screenshot_title" msgid="1991014038776117688">"Скриншотты пайдалану"</string>
     <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Қолданбаға экран кескінін пайдалануға рұқсат ету"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"Экранды жарықтандыру"</string>
-    <string name="assist_flash_summary" msgid="6697095786317559129">"Көмекші қолданба экрандағы не скриншоттағы мәтінге кірген кезде, экранның шеттері жанады"</string>
-    <string name="assist_footer" msgid="7030121180457472165">"Көмекші қолданбалар көріп жатқан экран ақпаратының негізінде сізге көмектесе алады. Кейбір қолданбалар көмекті арттыру үшін іске қосу құралын да, дауыспен енгізу қызметтерін де пайдаланады."</string>
+    <string name="assist_flash_summary" msgid="6697095786317559129">"Көмекші қолданба экрандағы мәтінге не скриншотқа кірген кезде, экранның шеттері жанады"</string>
+    <string name="assist_footer" msgid="7030121180457472165">"Көмекші қолданбалар ашық тұрған экрандағы ақпарат бойынша көмек бере алады. Кейбір қолданбалар қосымша көмек ретінде іске қосу құралын да, дауыспен енгізу қызметтерін де пайдаланады."</string>
     <string name="average_memory_use" msgid="5333366040118953945">"Жадты орташа пайдалануы"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"Жадты ең көп пайдалануы"</string>
     <string name="memory_usage" msgid="7963253555330830906">"Жадтың пайдаланылуы"</string>
@@ -3842,8 +3847,8 @@
     <string name="screen_zoom_conversation_timestamp_2" msgid="816265985618121370">"Бс 18:01"</string>
     <string name="screen_zoom_conversation_timestamp_3" msgid="7346540212221792932">"Бс 18:02"</string>
     <string name="screen_zoom_conversation_timestamp_4" msgid="1452374487089625022">"Бс 18:03"</string>
-    <string name="disconnected" msgid="4088439352761747084">"Қосылмаған"</string>
-    <string name="keyboard_disconnected" msgid="3068615097201531871">"Қосылмаған"</string>
+    <string name="disconnected" msgid="4088439352761747084">"Жалғанбаған"</string>
+    <string name="keyboard_disconnected" msgid="3068615097201531871">"Жалғанбаған"</string>
     <string name="data_usage_summary_format" msgid="7788095271598602797">"Деректердің <xliff:g id="AMOUNT">%1$s</xliff:g> пайдаланылған"</string>
     <string name="data_usage_wifi_format" msgid="9028934101966264710">"Wi‑Fi арқылы <xliff:g id="AMOUNT">^1</xliff:g> пайдаланылды"</string>
     <plurals name="notification_summary" formatted="false" msgid="761061343339229103">
@@ -4066,7 +4071,7 @@
     <string name="premium_sms_warning" msgid="7604011651486294515">"Ақылы SMS жіберу үшін оператор тарифтеріне сәйкес ақы алынады. Егер қолданбаға рұқсат берсеңіз, сол қолданба арқылы ақылы SMS жібере аласыз."</string>
     <string name="premium_sms_access" msgid="4550027460595822851">"Ақылы SMS жіберу"</string>
     <string name="bluetooth_disabled" msgid="6588102116819268238">"Өшірулі"</string>
-    <string name="bluetooth_connected_summary" msgid="439920840053965217">"<xliff:g id="ID_1">%1$s</xliff:g> құрылғысына қосылған"</string>
+    <string name="bluetooth_connected_summary" msgid="439920840053965217">"<xliff:g id="ID_1">%1$s</xliff:g> құрылғысына жалғанған"</string>
     <string name="bluetooth_connected_multiple_devices_summary" msgid="596205630653123250">"Түрлі құрылғыларға қосылған"</string>
     <string name="demo_mode" msgid="3831081808592541104">"Жүйе интерфейсінің демо режимі"</string>
     <string name="dark_ui_mode" msgid="703844190192599217">"Тақырып"</string>
@@ -4126,7 +4131,7 @@
     <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"Уақытты, хабарландыруларды және басқа ақпаратты көру үшін телефонды қолыңызға алыңыз."</string>
     <string name="ambient_display_pickup_summary" product="tablet" msgid="1077745287100012928">"Уақытты, хабарландыруларды және басқа ақпаратты көру үшін планшетіңізді таңдаңыз."</string>
     <string name="ambient_display_pickup_summary" product="device" msgid="404199660076598026">"Уақытты, хабарландыруларды және басқа ақпаратты көру үшін құрылғыңызды таңдаңыз."</string>
-    <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"Телефонды тексеру үшін түртіңіз"</string>
+    <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"Телефонды тексеру үшін түрту"</string>
     <string name="ambient_display_tap_screen_title" product="tablet" msgid="6434521782016864148">"Планшетті тексеру үшін түртіңіз"</string>
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"Құрылғыны тексеру үшін түртіңіз"</string>
     <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"Уақытты, хабарландыруларды және басқа ақпаратты көру үшін экранды түртіңіз."</string>
@@ -4231,7 +4236,7 @@
     <string name="app_names_concatenation_template_2" msgid="8267577900046506189">"<xliff:g id="FIRST_APP_NAME">%1$s</xliff:g>, <xliff:g id="SECOND_APP_NAME">%2$s</xliff:g>"</string>
     <string name="app_names_concatenation_template_3" msgid="5129064036161862327">"<xliff:g id="FIRST_APP_NAME">%1$s</xliff:g>, <xliff:g id="SECOND_APP_NAME">%2$s</xliff:g>, <xliff:g id="THIRD_APP_NAME">%3$s</xliff:g>"</string>
     <string name="storage_photos_videos" msgid="1890829312367477559">"Суреттер және бейнелер"</string>
-    <string name="storage_music_audio" msgid="3661289086715297149">"Музыка және аудиомазмұн"</string>
+    <string name="storage_music_audio" msgid="3661289086715297149">"Музыка және аудио"</string>
     <string name="storage_games" msgid="7740038143749092373">"Ойындар"</string>
     <string name="storage_other_apps" msgid="3202407095387420842">"Басқа қолданбалар"</string>
     <string name="storage_files" msgid="2087824267937487880">"Файлдар"</string>
@@ -4514,6 +4519,6 @@
     <string name="automatic_system_heap_dump_title" msgid="2153897396923488317">"Жүйенің дамп файлын автоматты жасау"</string>
     <string name="automatic_system_heap_dump_summary" msgid="4962129546638974661">"Android жүйесі тым көп жад пайдаланғанда, ол үшін дамп файлы автоматты түрде жасалады."</string>
     <string name="wifi_disconnect_button_text" msgid="787688024070426706">"Ажырату"</string>
-    <string name="wfc_disclaimer_emergency_limitation_title_text" msgid="26884532087670844">"Жедел қызметке қоңырау шалу"</string>
+    <string name="wfc_disclaimer_emergency_limitation_title_text" msgid="26884532087670844">"Құтқару қызметіне қоңырау шалу"</string>
     <string name="wfc_disclaimer_emergency_limitation_desc_text" msgid="8726152486964822599">"Wi‑Fi қоңыраулары арқылы жедел қызметке қоңырау шалуды операторыңыз қолдамайды.\nЖедел қызметке қоңырау шалу үшін құрылғы ұялы желіге автоматты түрде ауысады.\nТек мобильдік байланыс бар аймақтарда ғана жедел қызметке қоңырау шалуға болады."</string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-km/arrays.xml b/tests/CarDeveloperOptions/res/values-km/arrays.xml
index 5951f65..299a516 100644
--- a/tests/CarDeveloperOptions/res/values-km/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-km/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"រត់នៅក្នុងផ្ទៃខាងក្រោយ"</item>
     <item msgid="6423861043647911030">"កម្រិតសំឡេងភាពងាយស្រួល"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"ទី​តាំង​"</item>
+    <item msgid="6656077694190491067">"ទី​តាំង​"</item>
+    <item msgid="8790228218278477369">"ទី​តាំង​"</item>
+    <item msgid="7836406246005211990">"ញ័រ"</item>
+    <item msgid="3951439024549922598">"អាន​ទំនាក់ទំនង"</item>
+    <item msgid="8802152411647068">"កែ​ទំនាក់ទំនង"</item>
+    <item msgid="229544934599698735">"អាន​កំណត់ហេតុ​ហៅ"</item>
+    <item msgid="7396102294405899613">"កែ​បញ្ជី​ហៅ"</item>
+    <item msgid="3597797992398484655">"អាន​ប្រតិទិន"</item>
+    <item msgid="2705975774250907343">"កែ​ប្រតិទិន"</item>
+    <item msgid="4668747371441932697">"ទី​តាំង​"</item>
+    <item msgid="1487578921720243646">"ប្រកាស​ការ​ជូន​ដំណឹង"</item>
+    <item msgid="4636080349724146638">"ទី​តាំង​"</item>
+    <item msgid="673510900286463926">"ហៅ​ទូរស័ព្ទ"</item>
+    <item msgid="542083422784609790">"អាន​សារ SMS/MMS"</item>
+    <item msgid="1033780373029588436">"សរសេរ​សារ SMS/MMS"</item>
+    <item msgid="5647111115517787488">"ទទួល SMS/MMS"</item>
+    <item msgid="8591105601108455893">"ទទួល SMS/MMS​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​"</item>
+    <item msgid="7730995008517841903">"ទទួល SMS/MMS"</item>
+    <item msgid="2613033109026626086">"ទទួល SMS/MMS"</item>
+    <item msgid="3037159047591081136">"ផ្ញើ SMS/MMS"</item>
+    <item msgid="4726682243833913568">"អាន​សារ SMS/MMS"</item>
+    <item msgid="6555678522277865572">"សរសេរ​សារ SMS/MMS"</item>
+    <item msgid="6981734935578130884">"កែ​ការ​កំណត់"</item>
+    <item msgid="8705854389991425629">"គូរ​​​ខាង​លើ"</item>
+    <item msgid="5861356020344153651">"​ជូន​ដំណឹង​ចូល​ដំណើរការ"</item>
+    <item msgid="78432174621628659">"កាមេរ៉ា"</item>
+    <item msgid="3986116419882154794">"ថត​សំឡេង"</item>
+    <item msgid="4516840825756409490">"ចាក់អូឌីយ៉ូ"</item>
+    <item msgid="6811712502798183957">"អាន​ក្ដារតម្បៀតខ្ទាស់"</item>
+    <item msgid="2780369012602289114">"កែ​ក្ដារតម្បៀតខ្ទាស់"</item>
+    <item msgid="2331359440170850868">"ប៊ូតុង​មេឌៀ"</item>
+    <item msgid="6133599737122751231">"ការ​ផ្ដោត​សំឡេង"</item>
+    <item msgid="6844485713404805301">"កម្រិត​សំឡេង​មេ"</item>
+    <item msgid="1600379420669104929">"កម្រិត​សំឡេង"</item>
+    <item msgid="6296768210470214866">"កម្រិត​សំឡេង​រោទ៍"</item>
+    <item msgid="510690696071629241">"កម្រិត​សំឡេង​មេឌៀ"</item>
+    <item msgid="406861638631430109">"កម្រិត​សំឡេងម៉ោង​រោទ៍"</item>
+    <item msgid="4715864795872233884">"កម្រិត​សំឡេង​ការ​ជូន​ដំណឹង"</item>
+    <item msgid="2311478519251301183">"កម្រិត​សំឡេង​ប៊្លូធូស"</item>
+    <item msgid="5133991377896747027">"មិន​ដេក"</item>
+    <item msgid="2464189519136248621">"ទីតាំង"</item>
+    <item msgid="2062677934050803037">"ទី​តាំង​"</item>
+    <item msgid="1735171933192715957">"ទទួល​​ស្ថិតិ​​ប្រើប្រាស់"</item>
+    <item msgid="1014093788778383554">"បិទ/បើក​សំឡេង​មីក្រូហ្វូន"</item>
+    <item msgid="4199297950608622850">"បង្ហាញថូស"</item>
+    <item msgid="2527962435313398821">"មេឌៀគម្រោង"</item>
+    <item msgid="5117506254221861929">"ធ្វើឲ្យ VPN សកម្ម"</item>
+    <item msgid="8291198322681891160">"ការបង្កើតផ្ទាំងរូបភាព"</item>
+    <item msgid="7106921284621230961">"រចនាសម្ព័ន្ធជំនួយ"</item>
+    <item msgid="4496533640894624799">"រូបថតអេក្រង់ជំនួយ"</item>
+    <item msgid="2598847264853993611">"អានស្ថានភាពទូរស័ព្ទ"</item>
+    <item msgid="9215610846802973353">"បន្ថែមសារជាសំឡេង"</item>
+    <item msgid="9186411956086478261">"ប្រើ sip"</item>
+    <item msgid="6884763100104539558">"កំពុងដំណើរការហៅចេញ"</item>
+    <item msgid="125513972170580692">"ស្នាមម្រាមដៃ"</item>
+    <item msgid="2556071024281275619">"ឧបករណ៍ចាប់សញ្ញារាងកាយ"</item>
+    <item msgid="617168514928339387">"អានការផ្សព្វផ្សាយសារចល័ត"</item>
+    <item msgid="7134693570516523585">"ទីតាំងបញ្ឆោត"</item>
+    <item msgid="7224489175375229399">"អានទំហំផ្ទុក"</item>
+    <item msgid="8472735063903258202">"សរសេរទំហំផ្ទុក"</item>
+    <item msgid="4069276819909595110">"បើកអេក្រង់"</item>
+    <item msgid="1228338896751121025">"ទទួលគណនី"</item>
+    <item msgid="3181581793459233672">"រត់នៅក្នុងផ្ទៃខាងក្រោយ"</item>
+    <item msgid="2340936043025374076">"កម្រិតសំឡេងភាពងាយស្រួល"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"ខ្លី"</item>
     <item msgid="4816511817309094890">"មធ្យម"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"កុំ​អនុញ្ញាត"</item>
     <item msgid="8184570120217958741">"អនុញ្ញាត​ជា​និច្ច"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"ធម្មតា"</item>
+    <item msgid="5101233285497327432">"មធ្យម"</item>
+    <item msgid="1555861583162930714">"ទាប"</item>
+    <item msgid="1719683776264798117">"ខ្លាំង​មែនទែន"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"ធម្មតា"</item>
+    <item msgid="6107138933849816768">"មធ្យម"</item>
+    <item msgid="182695359839047859">"ទាប"</item>
+    <item msgid="8577246509202964244">"សំខាន់ខ្លាំង"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"ជាប់​លាប់"</item>
     <item msgid="167418068739176448">"សកម្មភាព​​លើ​គេ"</item>
@@ -379,7 +455,7 @@
   <string-array name="color_picker">
     <item msgid="3151827842194201728">"បៃតង​​ចាស់"</item>
     <item msgid="3228505970082457852">"ពណ៌ខៀវ"</item>
-    <item msgid="6590260735734795647">"ពណ៌​ឆ្លុះ"</item>
+    <item msgid="6590260735734795647">"ទឹកប៊ិក"</item>
     <item msgid="3521763377357218577">"ស្វាយ"</item>
     <item msgid="5932337981182999919">"ផ្កាឈូក"</item>
     <item msgid="5642914536624000094">"ពណ៌ក្រហម"</item>
diff --git a/tests/CarDeveloperOptions/res/values-km/config.xml b/tests/CarDeveloperOptions/res/values-km/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-km/config.xml
+++ b/tests/CarDeveloperOptions/res/values-km/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-km/strings.xml b/tests/CarDeveloperOptions/res/values-km/strings.xml
index c54c6a9..f07f03b 100644
--- a/tests/CarDeveloperOptions/res/values-km/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-km/strings.xml
@@ -56,7 +56,7 @@
     <string name="radio_info_ims_reg_status" msgid="4771711884059371514">"ការចុះឈ្មោះ IMS៖ <xliff:g id="STATUS">%1$s</xliff:g>\nសំឡេងតាមរយៈ LTE៖ <xliff:g id="AVAILABILITY_0">%2$s</xliff:g>\nសំឡេងតាមរយៈ WiFi៖ <xliff:g id="AVAILABILITY_1">%3$s</xliff:g>\nការហៅជាវីដេអូ៖ <xliff:g id="AVAILABILITY_2">%4$s</xliff:g>\nចំណុចប្រទាក់ UT៖ <xliff:g id="AVAILABILITY_3">%5$s</xliff:g>"</string>
     <string name="radioInfo_service_in" msgid="1297020186765943857">"កំពុងដំណើរការ"</string>
     <string name="radioInfo_service_out" msgid="8460363463722476510">"មិនដំណើរការ"</string>
-    <string name="radioInfo_service_emergency" msgid="7674989004735662599">"សម្រាប់តែការហៅពេលអាសន្នប៉ុណ្ណោះ"</string>
+    <string name="radioInfo_service_emergency" msgid="7674989004735662599">"ការហៅទៅលេខសង្គ្រោះបន្ទាន់​តែប៉ុណ្ណោះ"</string>
     <string name="radioInfo_service_off" msgid="1873939869994136791">"បិទវិទ្យុ"</string>
     <string name="radioInfo_roaming_in" msgid="7059350234710947417">"រ៉ូមីង"</string>
     <string name="radioInfo_roaming_not" msgid="7733269160603599835">"មិនរ៉ូមីងទេ"</string>
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"ធ្វើឲ្យអត្ថបទនៅលើអេក្រង់តូចជាងមុន ឬធំជាងមុន។"</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"កំណត់ឲ្យតូចជាងមុន"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"កំណត់ឲ្យធំជាងមុន"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"អត្ថបទគំរូ"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"មេធ្មប់ដ៏អស្ចារ្យនៃទឹកដីពិសិដ្ឋ"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"ជំពូកទី 11៖ ទីក្រុងមរកតដ៏អស្ចារ្យនៃទឹកដីពិសិដ្ឋ"</string>
@@ -456,7 +455,7 @@
     <string name="lock_screen_intro_skip_dialog_text" product="tablet" msgid="7572334562915795226">"មុខងារការពារឧបករណ៍នឹងមិនត្រូវបានបើកទេ។ អ្នកនឹងមិនអាច​រារាំង​អ្នកផ្សេង​មិនឲ្យប្រើប្រាស់ថេប្លេតនេះបានទេ ប្រសិនបើវាបាត់ ឬត្រូវបានគេលួច។"</string>
     <string name="lock_screen_intro_skip_dialog_text" product="device" msgid="3819285334459763813">"មុខងារការពារឧបករណ៍នឹងមិនត្រូវបានបើកទេ។ អ្នកនឹងមិនអាច​រារាំង​អ្នកផ្សេង​មិនឲ្យប្រើប្រាស់ឧបករណ៍នេះបានទេ ប្រសិនបើវាបាត់ ឬត្រូវបានគេលួច។"</string>
     <string name="lock_screen_intro_skip_dialog_text" product="default" msgid="5361573789585652826">"មុខងារការពារឧបករណ៍នឹងមិនត្រូវបានបើកទេ។ អ្នកនឹងមិនអាច​រារាំង​អ្នកផ្សេង​មិនឲ្យប្រើប្រាស់ទូរសព្ទនេះបានទេ ប្រសិនបើវាបាត់ ឬត្រូវបានគេលួច។"</string>
-    <string name="skip_anyway_button_label" msgid="4437815969645175429">"រំលងទោះបីយ៉ាងណាក៏ដោយ"</string>
+    <string name="skip_anyway_button_label" msgid="4437815969645175429">"មិនអីទេ រំលង​ចុះ"</string>
     <string name="go_back_button_label" msgid="7310586887969860472">"ថយ​ក្រោយ"</string>
     <string name="skip_lock_screen_dialog_button_label" msgid="6706047245716780006">"រំលង"</string>
     <string name="cancel_lock_screen_dialog_button_label" msgid="2534925227627658819">"បោះបង់"</string>
@@ -574,7 +573,7 @@
     <string name="unlock_set_unlock_pin_summary" msgid="8076921768675948228">"សុវត្ថិភាព​ពី​មធ្យម​ទៅ​ខ្ពស់"</string>
     <string name="unlock_set_unlock_password_title" msgid="2092949379238466560">"ពាក្យសម្ងាត់​"</string>
     <string name="unlock_set_unlock_password_summary" msgid="7042787631866059147">"សុវត្ថិភាព​ខ្ពស់"</string>
-    <string name="unlock_set_do_later_title" msgid="2939110070503695956">"កុំអាល"</string>
+    <string name="unlock_set_do_later_title" msgid="2939110070503695956">"កុំទាន់"</string>
     <string name="current_screen_lock" msgid="398328543694154510">"ការចាក់សោអេក្រង់បច្ចុប្បន្ន"</string>
     <string name="fingerprint_unlock_set_unlock_pattern" msgid="132337696546315927">"ស្នាមម្រាមដៃ + លំនាំ"</string>
     <string name="fingerprint_unlock_set_unlock_pin" msgid="886426673328906002">"ស្នាមម្រាមដៃ + កូដ PIN"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">ត្រូវ​តែ​តិច​ជាង <xliff:g id="NUMBER_1">%d</xliff:g> ខ្ទង់</item>
       <item quantity="one">ត្រូវ​តែ​តិច​ជាង <xliff:g id="NUMBER_0">%d</xliff:g> ខ្ទង់</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"ត្រូវមានលេខពី 0-9 តែប៉ុណ្ណោះ"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"អ្នក​គ្រប់គ្រង​ឧបករណ៍​មិនអនុញ្ញាត​កូដ PIN ​ទើបប្រើហើយទេ"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"កូដ PIN លក្ខណៈ​សាមញ្ញ​ត្រូវ​បាន​ទប់ស្កាត់​ដោយ​អ្នក​គ្រប់គ្រង​ព័ត៌មាន​វិទ្យា​របស់អ្នក។ សាកល្បង​ប្រើ​កូដ PIN ផ្សេង​ពី​នេះ។"</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"វាមិនអាចប្រើតួអក្សរដែលគ្មានសុពលភាពទេ"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">ត្រូវ​មាន​តួ​ដែល​មិន​មែន​ជា​អក្សរ​យ៉ាង​ហោច​ណាស់ <xliff:g id="COUNT">%d</xliff:g></item>
       <item quantity="one">ត្រូវមានតួដែលមិនមែនជាអក្សរយ៉ាងហោចណាស់ 1</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">ត្រូវតែមាន​តួដែលមិនមែន​ជាលេខ​យ៉ាងហោចណាស់ <xliff:g id="COUNT">%d</xliff:g></item>
+      <item quantity="one">ត្រូវតែមាន​តួដែលមិនមែន​ជាលេខ​យ៉ាងហោចណាស់ 1</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"អ្នក​គ្រប់គ្រង​ឧបករណ៍​មិន​អនុញ្ញាត​ឲ្យ​ប្រើ​ពាក្យ​សម្ងាត់​បច្ចុប្បន្ន​ទេ"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"ពាក្យសម្ងាត់​លក្ខណៈ​សាមញ្ញ​ត្រូវ​បាន​ទប់ស្កាត់​ដោយ​អ្នក​គ្រប់គ្រង​ព័ត៌មាន​វិទ្យា​របស់អ្នក។ សាកល្បង​ប្រើ​ពាក្យ​សម្ងាត់​ផ្សេង​ពី​នេះ។"</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"មិន​អនុញ្ញាត​ឲ្យ​មានលំដាប់ឡើង ចុះ ឬច្រំដែលទេ"</string>
@@ -903,7 +905,7 @@
     <string name="wifi_ssid_hint" msgid="5010024648106585165">"បញ្ចូល SSID"</string>
     <string name="wifi_security" msgid="9136702039496152831">"សុវត្ថិភាព"</string>
     <string name="wifi_hidden_network" msgid="6647772204699776833">"បណ្តាញ​ដែល​បាន​លាក់"</string>
-    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"ប្រសិនបើ​រូតទ័រ​របស់អ្នក​មិន​បង្ហាញ​លេខសម្គាល់​បណ្តាញ ប៉ុន្តែ​អ្នក​ចង់​ភ្ជាប់វា​នៅ​ពេល​អនាគត អ្នក​អាច​កំណត់​បណ្តាញ​ដូច​ដែល​បានលាក់។\n\nសកម្មភាព​នេះ​អាច​បង្កើតឱ្យមាន​ហានិភ័យ​ផ្នែក​សុវត្ថិភាព ដោយសារ​ទូរសព្ទ​របស់អ្នក​នឹងបង្ហាញ​រលកសញ្ញា​របស់វា​ជាប្រចាំ ដើម្បី​ស្វែងរក​បណ្តាញ។\n\nការកំណត់​បណ្តាញ​ដូច​ដែល​បាន​លាក់​នឹង​មិន​ប្តូរ​ការកំណត់​រូតទ័រ​របស់អ្នក​នោះទេ។"</string>
+    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"ប្រសិនបើ​រូតទ័រ​របស់អ្នក​មិន​ផ្សាយ​លេខសម្គាល់​បណ្តាញ ប៉ុន្តែ​អ្នក​ចង់​ភ្ជាប់វា​នៅ​ពេល​អនាគត អ្នក​អាច​កំណត់​បណ្តាញ​ថា​បានលាក់។\n\nសកម្មភាព​នេះ​អាច​បង្កើតឱ្យមាន​ហានិភ័យ​ផ្នែក​សុវត្ថិភាព ដោយសារ​ទូរសព្ទ​របស់អ្នក​នឹងផ្សាយ​រលកសញ្ញា​របស់វា​ជាប្រចាំ ដើម្បី​ស្វែងរក​បណ្តាញ។\n\nការកំណត់​បណ្តាញ​ថា​បាន​លាក់​នឹង​មិន​ប្តូរ​ការកំណត់​រូតទ័រ​របស់អ្នក​នោះទេ។"</string>
     <string name="wifi_signal" msgid="696548364467704808">"កម្លាំង​សញ្ញា"</string>
     <string name="wifi_status" msgid="3439931558930689940">"ស្ថានភាព"</string>
     <string name="tx_wifi_speed" msgid="2571810085003261073">"ល្បឿនតភ្ជាប់​សម្រាប់​ការផ្ទេរ"</string>
@@ -913,7 +915,7 @@
     <string name="passpoint_label" msgid="7429247462404128615">"បានរក្សាទុកតាមរយៈ"</string>
     <string name="passpoint_content" msgid="340527524510304327">"អត្តសញ្ញាណ <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_eap_method" msgid="3752116941487485859">"វិធីសាស្ត្រ EAP"</string>
-    <string name="please_select_phase2" msgid="5848080896810435677">"ជំហាន​ ២ ផ្ទៀងផ្ទាត់"</string>
+    <string name="please_select_phase2" msgid="5848080896810435677">"ការផ្ទៀងផ្ទាត់ជំហាន​ទី 2"</string>
     <string name="wifi_eap_ca_cert" msgid="1496395241849383785">"វិញ្ញាបនបត្រ CA"</string>
     <string name="wifi_eap_domain" msgid="3298302320003640130">"Domain"</string>
     <string name="wifi_eap_user_cert" msgid="6786839531765719173">"វិញ្ញាបនបត្រ​អ្នក​ប្រើ"</string>
@@ -943,7 +945,7 @@
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"មិនអាច​អាន​កូដ QR បានទេ។ ដាក់កូដ​ឱ្យនៅចំកណ្ដាលវិញ រួច​ព្យាយាម​ម្ដងទៀត"</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"សូមព្យាយាមម្ដងទៀត។ ប្រសិនបើ​បញ្ហា​នៅតែបន្តកើតឡើង សូមទាក់ទង​ក្រុមហ៊ុនផលិត​ឧបករណ៍"</string>
     <string name="wifi_dpp_failure_not_compatible" msgid="4320027179973678283">"មានអ្វីមួយ​ខុសប្រក្រតី"</string>
-    <string name="wifi_dpp_failure_timeout" msgid="5060065168142109420">"សូមប្រាកដថា​ឧបករណ៍​ត្រូវបានបើក និងសាកថ្ម​ចូលហើយ"</string>
+    <string name="wifi_dpp_failure_timeout" msgid="5060065168142109420">"សូមប្រាកដថា​ឧបករណ៍​ត្រូវបានដោត សាកថ្ម និងបើក"</string>
     <string name="wifi_dpp_failure_generic" msgid="7840142544736640189">"សូមប្រាកដថា​ឧបករណ៍​ត្រូវបានបើក និងសាកថ្ម​ចូលហើយ។ ប្រសិនបើ​បញ្ហា​នៅតែបន្តកើតឡើង សូមទាក់ទង​ក្រុមហ៊ុនផលិត​ឧបករណ៍"</string>
     <string name="wifi_dpp_failure_not_supported" msgid="111779621766171626">"មិន​អាច​បញ្ចូល “<xliff:g id="SSID">%1$s</xliff:g>” ទៅក្នុងឧបករណ៍​នេះ​បាន​ទេ"</string>
     <string name="wifi_dpp_check_connection_try_again" msgid="7144663015219170999">"សូម​ពិនិត្យមើល​ការតភ្ជាប់ រួចព្យាយាម​ម្ដងទៀត"</string>
@@ -1022,7 +1024,7 @@
     <string name="wifi_details_subnet_mask" msgid="53396707004763012">"របាំងបណ្តាញរង"</string>
     <string name="wifi_details_dns" msgid="1118251455740116559">"DNS"</string>
     <string name="wifi_details_ipv6_address_header" msgid="1642310137145363299">"អាសយដ្ឋាន IPv6"</string>
-    <string name="wifi_saved_access_points_label" msgid="3790693285928292563">"បណ្ដាញ​បាន​រក្សាទុក"</string>
+    <string name="wifi_saved_access_points_label" msgid="3790693285928292563">"បណ្ដាញ​ដែលបាន​រក្សាទុក"</string>
     <string name="wifi_subscribed_access_points_tab" msgid="7498765485953257229">"ការ​ជាវ"</string>
     <!-- no translation found for wifi_saved_access_points_tab (4677730543624191122) -->
     <skip />
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"ទូរសព្ទ​ចល័ត"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"ប្រសិនបើ​មិនអាច​ប្រើ Wi‑Fi សូមប្រើ​បណ្ដាញ​ទូរសព្ទ​ចល័ត"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"ប្រសិនបើ​មិន​អាច​ប្រើបណ្ដាញ​ទូរសព្ទ​ចល័ត សូម​ប្រើ Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"ហៅទូរសព្ទតាមរយៈ Wi‑Fi ។ ប្រសិនបើ​ដាច់ Wi‑Fi ការហៅទូរសព្ទនឹងបញ្ចប់។"</string>
@@ -1642,7 +1647,7 @@
     <string name="mobile_insert_sim_card" msgid="7594550403454243732">"សូម​បញ្ចូល​ស៊ីមកាត និង​ចាប់ផ្ដើម​ឡើង​វិញ"</string>
     <string name="mobile_connect_to_internet" msgid="6031886097365170913">"សូម​ភ្ជាប់​អ៊ីនធឺណិត"</string>
     <string name="location_title" msgid="8664674161765477168">"ទីតាំង​ខ្ញុំ"</string>
-    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"ទីតាំងសម្រាប់ប្រវត្តិរូបការងាររបស់អ្នក"</string>
+    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"ទីតាំងសម្រាប់កម្រងព័ត៌មានការងារ"</string>
     <string name="location_app_level_permissions" msgid="1298041503927632960">"ការអនុញ្ញាតកម្មវិធី"</string>
     <string name="location_app_permission_summary_location_off" msgid="541372845344796336">"ទីតាំង​បាន​បិទ"</string>
     <plurals name="location_app_permission_summary_location_on" formatted="false" msgid="7904821382328758218">
@@ -1690,7 +1695,7 @@
     <string name="terms_title" msgid="1804549588198223771">"លក្ខខណ្ឌ​ប្រើប្រាស់"</string>
     <string name="webview_license_title" msgid="8244960025549725051">"អាជ្ញាប័ណ្ណ System WebView"</string>
     <string name="wallpaper_attributions" msgid="2941987966332943253">"ផ្ទាំង​រូបភាព"</string>
-    <string name="wallpaper_attributions_values" msgid="4461979853894606323">"កម្មវិធី​ផ្ដល់​សេវា​រូបភាព​ផ្កាយ​រណប​៖\n©2014 CNES / Astrium, DigitalGlobe, Bluesky"</string>
+    <string name="wallpaper_attributions_values" msgid="4461979853894606323">"ក្រុមហ៊ុន​ផ្ដល់​សេវា​រូបភាព​ផ្កាយ​រណប​៖\n©2014 CNES / Astrium, DigitalGlobe, Bluesky"</string>
     <string name="settings_manual_activity_title" msgid="7599911755054286789">"ឯកសារណែនាំ"</string>
     <string name="settings_manual_activity_unavailable" msgid="4872502775018655343">"មានបញ្ហាក្នុងការបើកឯកសារណែនាំ"</string>
     <string name="settings_license_activity_title" msgid="1099045216283677608">"អាជ្ញាបណ្ណភាគីទីបី"</string>
@@ -2275,7 +2280,7 @@
     <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"បើក​កម្មវិធី​សន្សំ​ថ្ម​"</string>
     <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"អាចនឹងឆាប់​អស់​ថ្ម​​ជាងធម្មតា"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"កម្មវិធីសន្សំថ្មបានបើក"</string>
-    <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"មុខងារ​មួយចំនួន​អាច​ត្រូវ​បាន​កម្រិត"</string>
+    <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"មុខងារ​មួយចំនួន​អាច​ត្រូវ​បាន​ដាក់កំហិត"</string>
     <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"ទូរសព្ទ​ត្រូវបានប្រើ​ប្រាស់ច្រើន​ជាង​ធម្មតា"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"ថេប្លេត​ត្រូវបានប្រើប្រាស់ច្រើន​ជាង​ធម្មតា"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"ឧបករណ៍​ត្រូវបានប្រើប្រាស់​ច្រើន​ជាង​ធម្មតា"</string>
@@ -2596,7 +2601,7 @@
     <string name="work_mode_label" msgid="6845849194740195757">"កម្រងព័ត៌មានការងារ"</string>
     <string name="work_mode_on_summary" msgid="1682781113156323592">"គ្រប់គ្រងដោយ​ស្ថាប័ន​របស់អ្នក"</string>
     <string name="work_mode_off_summary" msgid="1688885392211178315">"កម្មវិធី និង​ការ​ជូនដំណឹង​បាន​បិទ"</string>
-    <string name="remove_managed_profile_label" msgid="4625542553784793536">"លុប​ប្រវត្តិរូប​ការងារ"</string>
+    <string name="remove_managed_profile_label" msgid="4625542553784793536">"លុបកម្រងព័ត៌មានការងារ"</string>
     <string name="background_data" msgid="8275750862371471171">"ទិន្នន័យ​ផ្ទៃ​ខាង​ក្រោយ"</string>
     <string name="background_data_summary" msgid="799640633948841990">"កម្មវិធី​អាច​ធ្វើ​សម​កាល​កម្ម​ ផ្ញើ និង​ទទួល​ទិន្នន័យ​នៅ​ពេល​ណា​មួយ"</string>
     <string name="background_data_dialog_title" msgid="8306650658158895976">"បិទ​ទិន្នន័យ​ផ្ទៃ​ខាង​ក្រោយ?"</string>
@@ -2871,7 +2876,7 @@
     <string name="user_setup_dialog_message" msgid="2988559933258353919">"សូម​ប្រាកដ​ថា​​អ្នក​ប្រើ​ប្រាស់នេះ​អាច​យក​​ឧបករណ៍ ​និង​រៀបចំ​​ទំហំ​ផ្ទុករបស់​គេបាន"</string>
     <string name="user_setup_profile_dialog_message" msgid="7611900802824048526">"រៀបចំ​ប្រវត្តិរូប​ឥឡូវ?"</string>
     <string name="user_setup_button_setup_now" msgid="4941459406266856176">"រៀបចំ​ឥឡូវ"</string>
-    <string name="user_setup_button_setup_later" msgid="6596031428556518752">"កុំអាល"</string>
+    <string name="user_setup_button_setup_later" msgid="6596031428556518752">"កុំទាន់"</string>
     <string name="user_cannot_manage_message" product="tablet" msgid="7108992906553210763">"មាន​តែ​ម្ចាស់​កុំព្យូទ័រ​បន្ទះ​ប៉ុណ្ណោះ​អាច​គ្រប់គ្រង​អ្នកប្រើ"</string>
     <string name="user_cannot_manage_message" product="default" msgid="915260531390608092">"មាន​តែ​ម្ចាស់​ទូរស័ព្ទ​ប៉ុណ្ណោះ​អាច​គ្រប់គ្រង​អ្នកប្រើ។"</string>
     <string name="user_cannot_add_accounts_message" msgid="5993561303748749097">"ប្រវត្តិរូប​បាន​ដាក់កម្រិត​មិន​អាច​បន្ថែម​គណនី"</string>
@@ -2883,7 +2888,7 @@
     <string name="user_confirm_remove_self_title" msgid="6739480453680217543">"លុប​ខ្លួន​ឯង​ផ្ទាល់?"</string>
     <string name="user_confirm_remove_title" msgid="1034498514019462084">"លុបអ្នកប្រើប្រាស់​នេះ?"</string>
     <string name="user_profile_confirm_remove_title" msgid="6138684743385947063">"លុប​ប្រវត្តិ​រូប​នេះ?"</string>
-    <string name="work_profile_confirm_remove_title" msgid="3168910958076735800">"លុប​ប្រវត្តិរូប​ការងារ?"</string>
+    <string name="work_profile_confirm_remove_title" msgid="3168910958076735800">"លុបកម្រងព័ត៌មានការងារឬ?"</string>
     <string name="user_confirm_remove_self_message" product="tablet" msgid="2889456786320157545">"អ្នក​នឹង​បាត់បង់​ទំហំ​ ព្រម​ទាំង​ទិន្នន័យ​របស់​អ្នក​លើ​កុំព្យូទ័រ​បន្ទះ​នេះ​។ អ្នក​មិន​អាច​ធ្វើ​សកម្មភាព​នេះ​វិញ​បាន​ទេ។"</string>
     <string name="user_confirm_remove_self_message" product="default" msgid="8441729423565705183">"អ្នក​នឹង​បាត់បង់​ទំហំ និង​ទិន្នន័យ​របស់​អ្នក​លើ​ទូរស័ព្ទ​នេះ។ អ្នក​មិន​អាច​ធ្វើ​សកម្មភាព​នេះ​វិញ​បាន​ទេ។"</string>
     <string name="user_confirm_remove_message" msgid="5202150470271756013">"កម្មវិធី និង​ទិន្នន័យ​ទាំងអស់​នឹង​ត្រូវ​បាន​លុប។"</string>
@@ -3131,7 +3136,7 @@
     <string name="sound_settings_example_summary" msgid="2091822107298841827">"កម្រិតសំឡេងរោទ៍ត្រឹម 80%"</string>
     <string name="media_volume_option_title" msgid="3553411883305505682">"កម្រិត​សំឡេង​មេឌៀ"</string>
     <string name="remote_media_volume_option_title" msgid="6355710054191873836">"កម្រិតសំឡេងនៃការបញ្ជូន"</string>
-    <string name="call_volume_option_title" msgid="5028003296631037334">"កម្រិត​សំឡេង​ហៅ"</string>
+    <string name="call_volume_option_title" msgid="5028003296631037334">"កម្រិត​សំឡេង​ហៅទូរសព្ទ"</string>
     <string name="alarm_volume_option_title" msgid="3184076022438477047">"កម្រិត​សំឡេងម៉ោង​រោទ៍"</string>
     <string name="ring_volume_option_title" msgid="2038924918468372264">"កម្រិត​សំឡេង​រោទ៍"</string>
     <string name="notification_volume_option_title" msgid="1358512611511348260">"កម្រិត​សំឡេង​ការ​ជូន​ដំណឹង"</string>
@@ -3148,7 +3153,7 @@
     <string name="docking_sounds_title" msgid="2573137471605541366">"សំឡេង​​ភ្ជាប់"</string>
     <string name="touch_sounds_title" msgid="165237488496165652">"សំឡេង​ប៉ះ"</string>
     <string name="vibrate_on_touch_title" msgid="6360155469279157684">"ការ​ញ័រ​ពេល​ប៉ះ"</string>
-    <string name="vibrate_on_touch_summary" msgid="5504424764028676043">"មតិស្ថាបនា​តាម​ការប៉ះ​សម្រាប់​ការចុច ក្ដារចុច និងច្រើនទៀត"</string>
+    <string name="vibrate_on_touch_summary" msgid="5504424764028676043">"ប្រតិកម្មញ័រពេលចុច ក្ដារចុច និងច្រើនទៀត"</string>
     <string name="dock_audio_media_title" msgid="1859521680502040781">"ភ្ជាប់ការ​ចាក់​តាមអូប៉ាល័រ"</string>
     <string name="dock_audio_media_disabled" msgid="4300752306178486302">"អូឌីយ៉ូ​​ទាំងអស់"</string>
     <string name="dock_audio_media_enabled" msgid="2873275045878628153">"តែ​អូឌីយ៉ូ​​មេឌៀ​ប៉ុណ្ណោះ"</string>
@@ -3454,8 +3459,8 @@
     <string name="zen_mode_event_rule_summary_reply_template" msgid="3917497077674876311">"នៅពេលឆ្លើយតបថា <xliff:g id="REPLY">%1$s</xliff:g>"</string>
     <string name="zen_mode_event_rule_calendar_any" msgid="155915101132859764">"ប្រតិទិនណាមួយ"</string>
     <string name="zen_mode_event_rule_reply" msgid="9100941281268256319">"នៅពេលឆ្លើយតបថា"</string>
-    <string name="zen_mode_event_rule_reply_any_except_no" msgid="3344044163641764449">"យល់ព្រម ប្រហែល ឬមិនឆ្លើយតប"</string>
-    <string name="zen_mode_event_rule_reply_yes_or_maybe" msgid="5042234361937256329">"យល់ព្រម ឬប្រហែល"</string>
+    <string name="zen_mode_event_rule_reply_any_except_no" msgid="3344044163641764449">"បាទ/ចាស ប្រហែល ឬមិនឆ្លើយតប"</string>
+    <string name="zen_mode_event_rule_reply_yes_or_maybe" msgid="5042234361937256329">"បាទ/ចាស ឬប្រហែល"</string>
     <string name="zen_mode_event_rule_reply_yes" msgid="7039756546321205552">"បាទ/ចាស"</string>
     <string name="zen_mode_rule_not_found_text" msgid="6553855397424553685">"រកមិនឃើញច្បាប់ទេ។"</string>
     <string name="zen_mode_rule_summary_enabled_combination" msgid="8269105393636454359">"បើក / <xliff:g id="MODE">%1$s</xliff:g>"</string>
@@ -3625,7 +3630,7 @@
       <item quantity="one">សិទ្ធិអនុញ្ញាតបន្ថែម <xliff:g id="COUNT_0">%d</xliff:g></item>
     </plurals>
     <string name="runtime_permissions_summary_no_permissions_granted" msgid="3477934429220828771">"គ្មានការផ្តល់សិទ្ធិអនុញ្ញាតទេ"</string>
-    <string name="runtime_permissions_summary_no_permissions_requested" msgid="3901636077467389637">"គ្មានការស្នើសិទ្ធិអនុញ្ញាតទេ"</string>
+    <string name="runtime_permissions_summary_no_permissions_requested" msgid="3901636077467389637">"គ្មានការអនុញ្ញាត​ដែលបានស្នើសុំទេ"</string>
     <string name="filter_all_apps" msgid="4042756539846043675">"កម្មវិធីទាំងអស់"</string>
     <string name="filter_enabled_apps" msgid="5888459261768538489">"កម្មវិធី​ដែល​បាន​ដំឡើង"</string>
     <string name="filter_instant_apps" msgid="8087483282854072366">"កម្មវិធី​ប្រើ​ភ្លាមៗ"</string>
@@ -4076,7 +4081,7 @@
     <string name="quick_settings_developer_tiles" msgid="7423485925757678719">"ប្រអប់​ការ​កំណត់​រហ័ស​សម្រាប់​អ្នកអភិវឌ្ឍន៍"</string>
     <string name="winscope_trace_quick_settings_title" msgid="940971040388411374">"ដាន Winscope"</string>
     <string name="sensors_off_quick_settings_title" msgid="3655699045300438902">"ឧបករណ៍​ចាប់សញ្ញាបានបិទ"</string>
-    <string name="managed_profile_settings_title" msgid="4340409321523532402">"ការកំណត់ប្រវត្តិរូបការងារ"</string>
+    <string name="managed_profile_settings_title" msgid="4340409321523532402">"ការកំណត់កម្រងព័ត៌មានការងារ"</string>
     <string name="managed_profile_contact_search_title" msgid="7337225196804457095">"ការស្វែងរកទំនាក់ទំនង"</string>
     <string name="managed_profile_contact_search_summary" msgid="7278267480246726951">"អនុញ្ញាតការស្វែងរកទំនាក់ទំនងដោយស្ថាប័នរបស់អ្នកដើម្បីកំណត់អត្តសញ្ញាណអ្នកហៅ និងលេខទំនាក់ទំនង"</string>
     <string name="cross_profile_calendar_title" msgid="2351605904015067145">"ប្រតិទិនអន្តរ​កម្រងព័ត៌មាន"</string>
@@ -4305,7 +4310,7 @@
     <string name="change_wifi_state_title" msgid="5140754955787584174">"ការ​គ្រប់គ្រង Wi-Fi"</string>
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"អនុញ្ញាត​ឱ្យ​កម្មវិធី​គ្រប់គ្រង Wi-Fi"</string>
     <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"អនុញ្ញាត​ឱ្យ​កម្មវិធី​នេះ​បើក ឬបិទ Wi-Fi ស្កេន និងភ្ជាប់បណ្តាញ Wi-Fi បញ្ចូល ឬលុប​បណ្តាញ ឬចាប់ផ្តើមតែហតស្ប៉តមូលដ្ឋាន​ប៉ុណ្ណោះ"</string>
-    <string name="media_output_title" msgid="8710632337456601848">"ចាក់​មេឌៀទៅកាន់"</string>
+    <string name="media_output_title" msgid="8710632337456601848">"ចាក់​មេឌៀនៅលើ"</string>
     <string name="media_output_default_summary" msgid="3159237976830415584">"ឧបករណ៍នេះ"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"ទូរសព្ទ"</string>
     <string name="media_output_summary" product="tablet" msgid="6672024060360538526">"ថេប្លេត"</string>
diff --git a/tests/CarDeveloperOptions/res/values-kn/arrays.xml b/tests/CarDeveloperOptions/res/values-kn/arrays.xml
index 073f9a3..2b09f58 100644
--- a/tests/CarDeveloperOptions/res/values-kn/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-kn/arrays.xml
@@ -38,7 +38,16 @@
     <item msgid="5827960506924849753">"10 ನಿಮಿಷಗಳು"</item>
     <item msgid="6677424950124253938">"30 ನಿಮಿಷಗಳು"</item>
   </string-array>
-    <!-- no translation found for dream_timeout_entries:7 (8271452751594598661) -->
+  <string-array name="dream_timeout_entries">
+    <item msgid="6487043225269853023">"ಎಂದಿಗೂ ಇಲ್ಲ"</item>
+    <item msgid="2517785806387977252">"15 ಸೆಕೆಂಡುಗಳು"</item>
+    <item msgid="6347954399441173672">"30 ಸೆಕೆಂಡುಗಳು"</item>
+    <item msgid="4858305253279921789">"1 ನಿಮಿಷ"</item>
+    <item msgid="8109273437140044073">"2 ನಿಮಿಷಗಳು"</item>
+    <item msgid="2788593551142462622">"5 ನಿಮಿಷಗಳು"</item>
+    <item msgid="8012672183888404961">"10 ನಿಮಿಷಗಳು"</item>
+    <item msgid="8271452751594598661">"30 ನಿಮಿಷಗಳು"</item>
+  </string-array>
   <string-array name="lock_after_timeout_entries">
     <item msgid="2232921187970351881">"ತಕ್ಷಣವೇ"</item>
     <item msgid="2038544972632026612">"5 ಸೆಕೆಂಡುಗಳು"</item>
@@ -50,17 +59,47 @@
     <item msgid="811192536981678974">"10 ನಿಮಿಷಗಳು"</item>
     <item msgid="7258394417241706272">"30 ನಿಮಿಷಗಳು"</item>
   </string-array>
-    <!-- no translation found for entries_font_size:0 (2340391964816059553) -->
-    <!-- no translation found for entries_font_size:0 (6490061470416867723) -->
-    <!-- no translation found for entries_font_size:2 (1714184661981538355) -->
-    <!-- no translation found for entries_font_size:2 (1678068858001018666) -->
-    <!-- no translation found for wifi_status:3 (5848277343965362748) -->
-    <!-- no translation found for wifi_status_with_ssid:1 (6816207058895999545) -->
-    <!-- no translation found for wifi_status_with_ssid:3 (7547609081339573756) -->
-    <!-- no translation found for wifi_status_with_ssid:4 (5145158315060185414) -->
+  <string-array name="entries_font_size">
+    <item msgid="2340391964816059553">"ಸಣ್ಣ"</item>
+    <item msgid="591935967183159581">"ಡೀಫಾಲ್ಟ್"</item>
+    <item msgid="1714184661981538355">"ದೊಡ್ಡದು"</item>
+    <item msgid="6195563047686707484">"ದೊಡ್ಡ"</item>
+  </string-array>
+  <string-array name="wifi_status">
+    <item msgid="1304883790721412351"></item>
+    <item msgid="4157625910392775808">"ಸ್ಕ್ಯಾನ್ ಮಾಡಲಾಗುತ್ತಿದೆ…"</item>
+    <item msgid="5597394826455877834">"ಸಂಪರ್ಕಗೊಳಿಸಲಾಗುತ್ತಿದೆ..."</item>
+    <item msgid="5848277343965362748">"ದೃಢೀಕರಿಸಲಾಗುತ್ತಿದೆ…"</item>
+    <item msgid="3391238031431440676">"IP ವಿಳಾಸವನ್ನು ಪಡೆಯಲಾಗುತ್ತಿದೆ…"</item>
+    <item msgid="5257597310494000224">"ಸಂಪರ್ಕಗೊಂಡಿದೆ"</item>
+    <item msgid="8472497592913050396">"ತಡೆಹಿಡಿಯಲಾಗಿದೆ"</item>
+    <item msgid="1228072488815999109">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗುತ್ತಿದೆ..."</item>
+    <item msgid="7253087004422991731">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ"</item>
+    <item msgid="4169850917304751227">"ವಿಫಲವಾಗಿದೆ"</item>
+    <item msgid="6266658166690831131">"ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</item>
+    <item msgid="4517230805854909775">"ಕಳಪೆ ಸಂಪರ್ಕವನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ತಡೆಗಟ್ಟಲಾಗುತ್ತಿದೆ"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="4853670665485437464"></item>
+    <item msgid="6816207058895999545">"ಸ್ಕ್ಯಾನ್ ಮಾಡಲಾಗುತ್ತಿದೆ…"</item>
+    <item msgid="8058143476674427024">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗುತ್ತಿದೆ…"</item>
+    <item msgid="7547609081339573756">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ಜೊತೆ ಪ್ರಮಾಣೀಕರಿಸಲಾಗುತ್ತಿದೆ…"</item>
+    <item msgid="5145158315060185414">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ನಿಂದ IP ವಿಳಾಸವನ್ನು ಪಡೆಯಲಾಗುತ್ತಿದೆ…"</item>
+    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ"</item>
+    <item msgid="6600156231416890902">"ತಡೆಹಿಡಿಯಲಾಗಿದೆ"</item>
+    <item msgid="4133290864821295785">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ನಿಂದ ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗುತ್ತಿದೆ…"</item>
+    <item msgid="3980154971187953257">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ"</item>
+    <item msgid="2847316776634969068">"ವಿಫಲವಾಗಿದೆ"</item>
+    <item msgid="4390990424746035383">"ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</item>
+    <item msgid="3618248791367063949">"ಕಳಪೆ ಸಂಪರ್ಕವನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ತಡೆಗಟ್ಟಲಾಗುತ್ತಿದೆ"</item>
+  </string-array>
     <!-- no translation found for wifi_tether_security:0 (5586343370515598801) -->
     <!-- no translation found for wifi_tether_security:1 (6136336549994615745) -->
-    <!-- no translation found for wifi_p2p_wps_setup:0 (5390235347963255303) -->
+  <string-array name="wifi_p2p_wps_setup">
+    <item msgid="5390235347963255303">"ಒತ್ತುವ ಬಟನ್"</item>
+    <item msgid="7401896200768713930">"ಪೀರ್ ಸಾಧನದಿಂದ ಪಿನ್‌"</item>
+    <item msgid="4526848028011846710">"ಈ ಸಾಧನದಿಂದ ಪಿನ್‌"</item>
+  </string-array>
   <string-array name="wifi_p2p_status">
     <item msgid="8741947238021758201">"ಸಂಪರ್ಕಗೊಂಡಿದೆ"</item>
     <item msgid="983792611851499732">"ಆಹ್ವಾನಿಸಲಾಗಿದೆ"</item>
@@ -82,8 +121,13 @@
     <item msgid="1644506614010085798">"4"</item>
     <item msgid="3132506679404897150">"5"</item>
   </string-array>
-    <!-- no translation found for wifi_signal:1 (7882129634982603782) -->
-    <!-- no translation found for wifi_signal:4 (999948812884919584) -->
+  <string-array name="wifi_signal">
+    <item msgid="1709949377823900951">"ಕಳಪೆ"</item>
+    <item msgid="7882129634982603782">"ಕಳಪೆ"</item>
+    <item msgid="6457357501905996224">"ಸಾಮಾನ್ಯ"</item>
+    <item msgid="405271628162918841">"ಉತ್ತಮ"</item>
+    <item msgid="999948812884919584">"ಅತ್ಯುತ್ತಮ"</item>
+  </string-array>
   <string-array name="data_usage_data_range">
     <item msgid="8986775481492954015">"ಕಳೆದ 30 ದಿನಗಳು"</item>
     <item msgid="3211287705232736964">"ಬಳಕೆಯ ಆವರ್ತನೆಯನ್ನು ಹೊಂದಿಸಿ..."</item>
@@ -119,7 +163,10 @@
     <item msgid="7330627471456865502">"MSCHAPV2"</item>
     <item msgid="6255179395132581882">"GTC"</item>
   </string-array>
-    <!-- no translation found for wifi_ip_settings:1 (4377002609760712163) -->
+  <string-array name="wifi_ip_settings">
+    <item msgid="2717196390555072244">"DHCP"</item>
+    <item msgid="4377002609760712163">"ಸ್ಥಿರ"</item>
+  </string-array>
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"ಯಾವುದೂ ಇಲ್ಲ"</item>
     <item msgid="1464741437353223198">"ಹಸ್ತಚಾಲಿತ"</item>
@@ -176,7 +223,7 @@
     <item msgid="2585253854462134715">"ಒರಟು ಸ್ಥಳ"</item>
     <item msgid="1830619568689922920">"ಉತ್ಕೃಷ್ಟ ಸ್ಥಳ"</item>
     <item msgid="3317274469481923141">"GPS"</item>
-    <item msgid="8931785990160383356">"ಕಂಪನ"</item>
+    <item msgid="8931785990160383356">"ವೈಬ್ರೇಟ್‌"</item>
     <item msgid="8632513128515114092">"ಓದುವ ಸಂಪರ್ಕಗಳು"</item>
     <item msgid="3741042113569620272">"ಸಂಪರ್ಕಗಳನ್ನು ಮಾರ್ಪಡಿಸಿ"</item>
     <item msgid="4204420969709009931">"ಕರೆಯ ಲಾಗ್‌ ಓದಿ"</item>
@@ -239,11 +286,73 @@
     <item msgid="1165623660533024666">"ಹಿನ್ನೆಲೆಯಲ್ಲಿ ರನ್ ಮಾಡಿ"</item>
     <item msgid="6423861043647911030">"ಪ್ರವೇಶಿಸುವಿಕೆ ವಾಲ್ಯೂಮ್‌"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:3 (7836406246005211990) -->
-    <!-- no translation found for app_ops_labels:4 (3951439024549922598) -->
-    <!-- no translation found for app_ops_labels:8 (3597797992398484655) -->
-    <!-- no translation found for app_ops_labels:20 (3037159047591081136) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"ಸ್ಥಳ"</item>
+    <item msgid="6656077694190491067">"ಸ್ಥಳ"</item>
+    <item msgid="8790228218278477369">"ಸ್ಥಳ"</item>
+    <item msgid="7836406246005211990">"ವೈಬ್ರೇಟ್‌"</item>
+    <item msgid="3951439024549922598">"ಓದುವ ಸಂಪರ್ಕಗಳು"</item>
+    <item msgid="8802152411647068">"ಸಂಪರ್ಕಗಳನ್ನು ಮಾರ್ಪಡಿಸಿ"</item>
+    <item msgid="229544934599698735">"ಕರೆಯ ಲಾಗ್‌ ಓದಿ"</item>
+    <item msgid="7396102294405899613">"ಕರೆಯ ಲಾಗ್‌ ಮಾರ್ಪಡಿಸಿ"</item>
+    <item msgid="3597797992398484655">"ಕ್ಯಾಲೆಂಡರ್ ಓದಿ"</item>
+    <item msgid="2705975774250907343">"ಕ್ಯಾಲೆಂಡರ್ ಮಾರ್ಪಡಿಸಿ"</item>
+    <item msgid="4668747371441932697">"ಸ್ಥಳ"</item>
+    <item msgid="1487578921720243646">"ಪೋಸ್ಟ್‌ ಅಧಿಸೂಚನೆ"</item>
+    <item msgid="4636080349724146638">"ಸ್ಥಳ"</item>
+    <item msgid="673510900286463926">"ಫೋನ್‌ ಕರೆ"</item>
+    <item msgid="542083422784609790">"SMS/MMS ಓದಿ"</item>
+    <item msgid="1033780373029588436">"SMS/MMS ಬರೆಯಿರಿ"</item>
+    <item msgid="5647111115517787488">"SMS/MMS ಸ್ವೀಕರಿಸಿ"</item>
+    <item msgid="8591105601108455893">"SMS/MMS ಸ್ವೀಕರಿಸಿ"</item>
+    <item msgid="7730995008517841903">"SMS/MMS ಸ್ವೀಕರಿಸಿ"</item>
+    <item msgid="2613033109026626086">"SMS/MMS ಸ್ವೀಕರಿಸಿ"</item>
+    <item msgid="3037159047591081136">"SMS/MMS ಕಳುಹಿಸಿ"</item>
+    <item msgid="4726682243833913568">"SMS/MMS ಓದಿ"</item>
+    <item msgid="6555678522277865572">"SMS/MMS ಬರೆಯಿರಿ"</item>
+    <item msgid="6981734935578130884">"ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಮಾರ್ಪಡಿಸಿ"</item>
+    <item msgid="8705854389991425629">"ಮೇಲಕ್ಕೆ ಎಳೆಯಿರಿ"</item>
+    <item msgid="5861356020344153651">"ಅಧಿಸೂಚನೆಗಳನ್ನು ಪ್ರವೇಶಿಸಿ"</item>
+    <item msgid="78432174621628659">"ಕ್ಯಾಮರಾ"</item>
+    <item msgid="3986116419882154794">"ಆಡಿಯೋ ರೆಕಾರ್ಡ್‌ ಮಾಡಲು"</item>
+    <item msgid="4516840825756409490">"ಆಡಿಯೋ ಪ್ಲೇ ಮಾಡಿ"</item>
+    <item msgid="6811712502798183957">"ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ ಓದಿ"</item>
+    <item msgid="2780369012602289114">"ಕ್ಲಿಪ್‌ಬೋರ್ಡ್ ಮಾರ್ಪಡಿಸಿ"</item>
+    <item msgid="2331359440170850868">"ಮಾಧ್ಯಮ ಬಟನ್‌ಗಳು"</item>
+    <item msgid="6133599737122751231">"ಆಡಿಯೊ ಫೋಕಸ್"</item>
+    <item msgid="6844485713404805301">"ಮಾಸ್ಟರ್ ವಾಲ್ಯೂಮ್"</item>
+    <item msgid="1600379420669104929">"ಧ್ವನಿ ವಾಲ್ಯೂಮ್"</item>
+    <item msgid="6296768210470214866">"ರಿಂಗ್ ವಾಲ್ಯೂಮ್"</item>
+    <item msgid="510690696071629241">"ಮಾಧ್ಯಮ ವಾಲ್ಯೂಮ್"</item>
+    <item msgid="406861638631430109">"ಅಲಾರಮ್ ವಾಲ್ಯೂಮ್"</item>
+    <item msgid="4715864795872233884">"ಅಧಿಸೂಚನೆ ವಾಲ್ಯೂಮ್"</item>
+    <item msgid="2311478519251301183">"ಬ್ಲೂಟೂತ್‌‌ ವಾಲ್ಯೂಮ್"</item>
+    <item msgid="5133991377896747027">"ಎಚ್ಚರವಾಗಿಡಿ"</item>
+    <item msgid="2464189519136248621">"ಸ್ಥಳ"</item>
+    <item msgid="2062677934050803037">"ಸ್ಥಳ"</item>
+    <item msgid="1735171933192715957">"ಬಳಕೆ ಅಂಕಿಅಂಶಗಳನ್ನು ಪಡೆದುಕೊಳ್ಳಿ"</item>
+    <item msgid="1014093788778383554">"ಮೈಕ್ರೋಫೋನ್ ಮ್ಯೂಟ್/ಅನ್‌ಮ್ಯೂಟ್ ಮಾಡಿ"</item>
+    <item msgid="4199297950608622850">"ಟೋಸ್ಟ್ ತೋರಿಸಿ"</item>
+    <item msgid="2527962435313398821">"ಪ್ರಾಜೆಕ್ಟ್ ಮೀಡಿಯಾ"</item>
+    <item msgid="5117506254221861929">"VPN ಸಕ್ರಿಯಗೊಳಿಸಿ"</item>
+    <item msgid="8291198322681891160">"ವಾಲ್‌ಪೇಪರ್‌ ರೈಟ್‌ ಮಾಡಿ"</item>
+    <item msgid="7106921284621230961">"ವಿನ್ಯಾಸಕ್ಕೆ ಸಹಾಯ"</item>
+    <item msgid="4496533640894624799">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ಗೆ ಸಹಾಯ"</item>
+    <item msgid="2598847264853993611">"ಫೋನ್ ಸ್ಥಿತಿಯನ್ನು ರೀಡ್‌ ಮಾಡಿ"</item>
+    <item msgid="9215610846802973353">"ಧ್ವನಿಮೇಲ್ ಸೇರಿಸಿ"</item>
+    <item msgid="9186411956086478261">"sip ಬಳಸಿ"</item>
+    <item msgid="6884763100104539558">"ಹೊರಹೋಗುವ ಕರೆಯನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಿ"</item>
+    <item msgid="125513972170580692">"ಬೆರಳಚ್ಚು"</item>
+    <item msgid="2556071024281275619">"ದೇಹ ಸೆನ್ಸರ್‌ಗಳು"</item>
+    <item msgid="617168514928339387">"ಸೆಲ್ ಪ್ರಸಾರಗಳನ್ನು ರೀಡ್ ಮಾಡಿ"</item>
+    <item msgid="7134693570516523585">"ಸ್ಥಳ ನಕಲಿಸು"</item>
+    <item msgid="7224489175375229399">"ಸಂಗ್ರಹಣೆಯನ್ನು ರೀಡ್ ಮಾಡಿ"</item>
+    <item msgid="8472735063903258202">"ಸಂಗ್ರಹಣೆಯನ್ನು ರೈಟ್ ಮಾಡಿ"</item>
+    <item msgid="4069276819909595110">"ಸ್ಕ್ರೀನ್ ಆನ್ ಮಾಡಿ"</item>
+    <item msgid="1228338896751121025">"ಖಾತೆಗಳನ್ನು ಪಡೆದುಕೊಳ್ಳಿ"</item>
+    <item msgid="3181581793459233672">"ಹಿನ್ನೆಲೆಯಲ್ಲಿ ರನ್ ಮಾಡಿ"</item>
+    <item msgid="2340936043025374076">"ಪ್ರವೇಶಿಸುವಿಕೆ ವಾಲ್ಯೂಮ್‌"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"ಚಿಕ್ಕದು"</item>
     <item msgid="4816511817309094890">"ಮಧ್ಯಮ"</item>
@@ -260,7 +369,13 @@
     <item msgid="4627069151979553527">"ಹಸ್ತಾಕ್ಷರಲಿಪಿ"</item>
     <item msgid="6896773537705206194">"ಸ್ಮಾಲ್‌ ಕ್ಯಾಪಿಟಲ್ಸ್‌‌"</item>
   </string-array>
-    <!-- no translation found for captioning_font_size_selector_titles:3 (2784236342175159295) -->
+  <string-array name="captioning_font_size_selector_titles">
+    <item msgid="1680223634161592855">"ತುಂಬಾ ಸಣ್ಣ"</item>
+    <item msgid="5091603983404027034">"ಸಣ್ಣ"</item>
+    <item msgid="176844712416932112">"ಸಾಮಾನ್ಯ"</item>
+    <item msgid="2784236342175159295">"ದೊಡ್ಡದು"</item>
+    <item msgid="218913203203160606">"ತುಂಬಾ ದೊಡ್ಡದು"</item>
+  </string-array>
   <string-array name="captioning_edge_type_selector_titles">
     <item msgid="3865198759294188069">"ಡೀಫಾಲ್ಟ್"</item>
     <item msgid="6488643537808152001">"ಯಾವುದೂ ಇಲ್ಲ"</item>
@@ -275,7 +390,14 @@
     <item msgid="1874668269931014581">"75%"</item>
     <item msgid="6462911487571123954">"100%"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"ಆಪ್‌‌ ಡಿಫಾಲ್ಟ್‌ ಬಳಸಿ"</item>
+    <item msgid="8611890312638868524">"ಕಪ್ಪು ಬಣ್ಣದಲ್ಲಿ ಬಿಳಿ"</item>
+    <item msgid="5891360837786277638">"ಬಿಳಿ ಬಣ್ಣದಲ್ಲಿ ಕಪ್ಪು"</item>
+    <item msgid="2798457065945456853">"ಕಪ್ಪು ಬಣ್ಣದಲ್ಲಿ ಹಳದಿ"</item>
+    <item msgid="5799049811524553967">"ನೀಲಿ ಬಣ್ಣದಲ್ಲಿ ಹಳದಿ"</item>
+    <item msgid="3673930830658169860">"ಕಸ್ಟಮ್"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"PPTP VPN"</item>
     <item msgid="1349760781118368659">"ಪೂರ್ವ-ಹಂಚಿಕೆಯಾದ ಕೀಗಳನ್ನು ಹೊಂದಿರುವ L2TP/IPSec VPN"</item>
@@ -288,15 +410,32 @@
     <item msgid="2958623927055120839">"ಯಾವುದೂ ಅಲ್ಲ"</item>
     <item msgid="1157046369795346308">"ಹಸ್ತಚಾಲಿತ"</item>
   </string-array>
-    <!-- no translation found for vpn_states:4 (9135049670787351881) -->
+  <string-array name="vpn_states">
+    <item msgid="5408915841694583740">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ"</item>
+    <item msgid="8754480102834556765">"ಆರಂಭಿಸಲಾಗುತ್ತಿದೆ..."</item>
+    <item msgid="3351334355574270250">"ಸಂಪರ್ಕಗೊಳಿಸಲಾಗುತ್ತಿದೆ..."</item>
+    <item msgid="8303882153995748352">"ಸಂಪರ್ಕಗೊಂಡಿದೆ"</item>
+    <item msgid="9135049670787351881">"ಅವಧಿ ಮೀರಿದೆ"</item>
+    <item msgid="2124868417182583926">"ವಿಫಲವಾಗಿದೆ"</item>
+  </string-array>
   <string-array name="security_settings_premium_sms_values">
     <item msgid="1164265643455394443">"ಕೇಳಿ"</item>
     <item msgid="7718817231348607934">"ಎಂದಿಗೂ ಅನುಮತಿಸಬೇಡಿ"</item>
     <item msgid="8184570120217958741">"ಯಾವಾಗಲೂ ಅನುಮತಿಸಿ"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"ಸಾಮಾನ್ಯ"</item>
+    <item msgid="5101233285497327432">"ಮಧ್ಯಮ"</item>
+    <item msgid="1555861583162930714">"ಕಡಿಮೆ"</item>
+    <item msgid="1719683776264798117">"ಗಂಭೀರ"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"ಸಾಮಾನ್ಯ"</item>
+    <item msgid="6107138933849816768">"ಮಧ್ಯಮ"</item>
+    <item msgid="182695359839047859">"ಕಡಿಮೆ"</item>
+    <item msgid="8577246509202964244">"ಗಂಭೀರ"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"ನಿರಂತರ"</item>
     <item msgid="167418068739176448">"ಉನ್ನತ ಚಟುವಟಿಕೆ"</item>
diff --git a/tests/CarDeveloperOptions/res/values-kn/config.xml b/tests/CarDeveloperOptions/res/values-kn/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-kn/config.xml
+++ b/tests/CarDeveloperOptions/res/values-kn/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-kn/strings.xml b/tests/CarDeveloperOptions/res/values-kn/strings.xml
index af78069..ad359d0 100644
--- a/tests/CarDeveloperOptions/res/values-kn/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-kn/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"ಪರದೆಯ ಮೇಲೆ ಪಠ್ಯದ ಗಾತ್ರವನ್ನು ಹಿಗ್ಗಿಸಿ ಅಥವಾ ಕುಗ್ಗಿಸಿ."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"ಚಿಕ್ಕದಾಗಿಸು"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"ದೊಡ್ಡದಾಗಿಸು"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"ಮಾದರಿ ಪಠ್ಯ"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Oz ನ ಅದ್ಭುತವಾದ ಮಾಂತ್ರಿಕ"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"ಅಧ್ಯಾಯ 11: Oz ನ ಅದ್ಭುತವಾದ ಎಮೆರಾಲ್ಡ್ ಸಿಟಿ"</string>
@@ -180,7 +179,7 @@
     <string name="connected_device_connected_title" msgid="6255107326608785482">"ಪ್ರಸ್ತುತ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string>
     <string name="connected_device_saved_title" msgid="8270136893488475163">"ಉಳಿಸಿರುವ ಸಾಧನಗಳು"</string>
     <string name="connected_device_add_device_summary" msgid="7960491471270158891">"ಜೋಡಿಸಲು ಬ್ಲೂಟೂತ್ ಆನ್ ಆಗುತ್ತದೆ"</string>
-    <string name="connected_device_connections_title" msgid="9205000271382018428">"ಸಂಪರ್ಕ ಆದ್ಯತೆಗಳು"</string>
+    <string name="connected_device_connections_title" msgid="9205000271382018428">"ಕನೆಕ್ಷನ್ ಆದ್ಯತೆಗಳು"</string>
     <string name="connected_device_previously_connected_title" msgid="225918223397410428">"ಹಿಂದೆ ಸಂಪರ್ಕಗೊಂಡಿದ್ದ ಸಾಧನಗಳು"</string>
     <string name="connected_device_previously_connected_screen_title" msgid="2018789662358162716">"ಹಿಂದೆ ಸಂಪರ್ಕಗೊಂಡಿದ್ದ"</string>
     <string name="connected_device_bluetooth_turned_on_toast" msgid="4652326177920814476">"ಬ್ಲೂಟೂತ್ ಆನ್ ಮಾಡಲಾಗಿದೆ"</string>
@@ -208,7 +207,7 @@
     <string name="proxy_error_empty_port" msgid="8034561724923076215">"ನೀವು ಪೋರ್ಟ್‌ ಕ್ಷೇತ್ರವನ್ನು ಪೂರ್ಣಗೊಳಿಸುವ ಅಗತ್ಯವಿದೆ."</string>
     <string name="proxy_error_empty_host_set_port" msgid="8471455809508588255">"ಹೋಸ್ಟ್ ಕ್ಷೇತ್ರವು ಖಾಲಿ ಇದ್ದಲ್ಲಿ, ಪೋರ್ಟ್‌ ಕ್ಷೇತ್ರವು ಕೂಡ ಖಾಲಿ ಇರಬೇಕು."</string>
     <string name="proxy_error_invalid_port" msgid="4046559920586100637">"ನೀವು ಟೈಪ್‌ ಮಾಡಿದ ಪೋರ್ಟ್ ಮಾನ್ಯವಾಗಿಲ್ಲ."</string>
-    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"ಬ್ರೌಸರ್ HTTP ಪ್ರಾಕ್ಸಿ ಬಳಸಿಕೊಂಡಿದೆ. ಇತರೆ ಆಪ್‌ಗಳು ಬಳಸಿಕೊಳ್ಳದೆ ಇರಬಹುದು."</string>
+    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"ಬ್ರೌಸರ್ HTTP ಪ್ರಾಕ್ಸಿ ಬಳಸಿಕೊಂಡಿದೆ. ಇತರೆ ಆ್ಯಪ್‌ಗಳು ಬಳಸಿಕೊಳ್ಳದೆ ಇರಬಹುದು."</string>
     <string name="proxy_url_title" msgid="882042361706435904">"PAC URL: "</string>
     <string name="radio_info_dl_kbps" msgid="2903778264453410272">"DL ಬ್ಯಾಂಡ್‌ವಿಡ್ತ್ (kbps):"</string>
     <string name="radio_info_ul_kbps" msgid="3802245899811732716">"UL ಬ್ಯಾಂಡ್‌ವಿಡ್ತ್ (kbps):"</string>
@@ -481,7 +480,7 @@
     <string name="face_lock_screen_setup_skip_dialog_text" product="tablet" msgid="2998863111689476550">"ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಆಯ್ಕೆಯ ಜೊತೆಗೆ ಸುರಕ್ಷಿತಗೊಳಿಸಿ, ಆದ್ದರಿಂದ ಅದು ಕಳೆದುಹೋದಾಗ ಅಥವಾ ಅಪಹರಣವಾದಾಗ ಅದನ್ನು ಯಾರಾದರೂ ಬಳಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಮುಖ ಗುರುತಿಸುವಿಕೆಯನ್ನು ಸೆಟಪ್ ಮಾಡಲು ನಿಮಗೆ ಸ್ಕ್ರೀನ್ ಲಾಕ್‌ ಆಯ್ಕೆಯೂ ಸಹ ಅಗತ್ಯವಿದೆ. ರದ್ದುಗೊಳಿಸಿ ಟ್ಯಾಪ್ ಮಾಡಿ, ನಂತರ ಪಿನ್ ಅನ್ನು ಹೊಂದಿಸಿ ಅಥವಾ ಮತ್ತೊಂದು ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಆಯ್ಕೆಯನ್ನು ಆರಿಸಿ."</string>
     <string name="face_lock_screen_setup_skip_dialog_text" product="device" msgid="6780557259734235952">"ನಿಮ್ಮ ಸಾಧನವನ್ನು ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಆಯ್ಕೆಯ ಜೊತೆಗೆ ಸುರಕ್ಷಿತಗೊಳಿಸಿ, ಆದ್ದರಿಂದ ಅದು ಕಳೆದುಹೋದಾಗ ಅಥವಾ ಅಪಹರಣವಾದಾಗ ಅದನ್ನು ಯಾರಾದರೂ ಬಳಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಮುಖ ಗುರುತಿಸುವಿಕೆಯನ್ನು ಸೆಟಪ್ ಮಾಡಲು ನಿಮಗೆ ಸ್ಕ್ರೀನ್ ಲಾಕ್‌ ಆಯ್ಕೆಯೂ ಸಹ ಅಗತ್ಯವಿದೆ. ರದ್ದುಗೊಳಿಸಿ ಟ್ಯಾಪ್ ಮಾಡಿ, ನಂತರ ಪಿನ್ ಅನ್ನು ಹೊಂದಿಸಿ ಅಥವಾ ಮತ್ತೊಂದು ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಆಯ್ಕೆಯನ್ನು ಆರಿಸಿ."</string>
     <string name="face_lock_screen_setup_skip_dialog_text" product="default" msgid="8541640018478926775">"ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಆಯ್ಕೆಯ ಜೊತೆಗೆ ಸುರಕ್ಷಿತಗೊಳಿಸಿ, ಆದ್ದರಿಂದ ಅದು ಕಳೆದುಹೋದಾಗ ಅಥವಾ ಅಪಹರಣವಾದಾಗ ಅದನ್ನು ಯಾರಾದರೂ ಬಳಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಮುಖ ಗುರುತಿಸುವಿಕೆಯನ್ನು ಸೆಟಪ್ ಮಾಡಲು ನಿಮಗೆ ಸ್ಕ್ರೀನ್ ಲಾಕ್‌ ಆಯ್ಕೆಯೂ ಸಹ ಅಗತ್ಯವಿದೆ. ರದ್ದುಗೊಳಿಸಿ ಟ್ಯಾಪ್ ಮಾಡಿ, ನಂತರ ಪಿನ್ ಅನ್ನು ಹೊಂದಿಸಿ ಅಥವಾ ಮತ್ತೊಂದು ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಆಯ್ಕೆಯನ್ನು ಆರಿಸಿ."</string>
-    <string name="lock_screen_pin_skip_title" msgid="8217519439213393785">"ಪಿನ್ ಸೆಟಪ್ ಸ್ಕಿಪ್ ಮಾಡುವುದೇ?"</string>
+    <string name="lock_screen_pin_skip_title" msgid="8217519439213393785">"ಪಿನ್ ಸೆಟಪ್ ಸ್ಕಿಪ್ ಮಾಡಬೇಕೇ?"</string>
     <string name="lock_screen_password_skip_title" msgid="3725788215672959827">"ಪಾಸ್‌ವರ್ಡ್ ಸೆಟಪ್ ಸ್ಕಿಪ್ ಮಾಡುವುದೇ?"</string>
     <string name="lock_screen_pattern_skip_title" msgid="4237030500353932005">"ಪ್ಯಾಟರ್ನ್ ಸೆಟಪ್ ಸ್ಕಿಪ್ ಮಾಡುವುದೇ?"</string>
     <string name="security_settings_fingerprint_enroll_setup_screen_lock" msgid="9036983528330627756">"ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಹೊಂದಿಸಿ"</string>
@@ -668,7 +667,6 @@
       <item quantity="one"> <xliff:g id="NUMBER_1">%d</xliff:g> ಗಿಂತ ಕಡಿಮೆ ಅಂಕಿಗಳನ್ನು ಹೊಂದಿರಬೇಕು</item>
       <item quantity="other"> <xliff:g id="NUMBER_1">%d</xliff:g> ಗಿಂತ ಕಡಿಮೆ ಅಂಕಿಗಳನ್ನು ಹೊಂದಿರಬೇಕು</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"ಕೇವಲ 0-9 ಅಂಕಿಗಳನ್ನು ಮಾತ್ರ ಹೊಂದಿರಬೇಕು"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"ಇತ್ತೀಚಿನ ಪಿನ್ ಬಳಸಲು ಸಾಧನದ ನಿರ್ವಾಹಕರು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"ಸರಳವಾದ ಪಿನ್‌ಗಳನ್ನು ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರಿಂದ ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ. ಬೇರೆಯ ಪಿನ್ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"ಇದು ಅಮಾನ್ಯ ಅಕ್ಷರವನ್ನು ಒಳಗೊಂಡಿರಬಾರದು"</string>
@@ -699,6 +697,10 @@
       <item quantity="one">ಕನಿಷ್ಠ <xliff:g id="COUNT">%d</xliff:g> ಅಕ್ಷರೇತರ ಕ್ಯಾರೆಕ್ಟರ್‌ಗಳನ್ನು ಹೊಂದಿರಬೇಕು</item>
       <item quantity="other">ಕನಿಷ್ಠ <xliff:g id="COUNT">%d</xliff:g> ಅಕ್ಷರೇತರ ಕ್ಯಾರೆಕ್ಟರ್‌ಗಳನ್ನು ಹೊಂದಿರಬೇಕು</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">ಕನಿಷ್ಠ <xliff:g id="COUNT">%d</xliff:g> ಸಂಖ್ಯೆಯಲ್ಲದ ಅಕ್ಷರಗಳನ್ನು ಹೊಂದಿರಬೇಕು</item>
+      <item quantity="other">ಕನಿಷ್ಠ <xliff:g id="COUNT">%d</xliff:g> ಸಂಖ್ಯೆಯಲ್ಲದ ಅಕ್ಷರಗಳನ್ನು ಹೊಂದಿರಬೇಕು</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"ಇತ್ತೀಚಿನ ಪಾಸ್‌ವರ್ಡ್ ಬಳಸಲು ಸಾಧನದ ನಿರ್ವಾಹಕರು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"ಸರಳವಾದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳನ್ನು ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರಿಂದ ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ. ಬೇರೆಯ ಪಾಸ್‌ವರ್ಡ್‌ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"ಅಂಕಿಗಳ ಆರೋಹಣ, ಅವರೋಹಣ ಅಥವಾ ಪುನರಾವರ್ತಿತ ಅನುಕ್ರಮವನ್ನು ನಿಷೇಧಿಸಲಾಗಿದೆ"</string>
@@ -906,8 +908,8 @@
     <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್ ID ಯನ್ನು ರೂಟರ್ ಪ್ರಸಾರ ಮಾಡದಿದ್ದಲ್ಲಿ ಆದರೆ ಭವಿಷ್ಯದಲ್ಲಿ ನೀವು ಅದಕ್ಕೆ ಸಂಪರ್ಕಿಸಲು ಬಯಸಿದರೆ, ನೀವು ನೆಟ್‌ವರ್ಕ್ ಅನ್ನು ಮರೆಮಾಡಲಾಗಿರುವುದು ಎಂದು ಹೊಂದಿಸಬಹುದು.\n\nನಿಮ್ಮ ಫೋನ್ ನಿಯಮಿತವಾಗಿ ನೆಟ್ವರ್ಕ್ ಅನ್ನು ಹುಡುಕಲು ಸಿಗ್ನಲ್ ಅನ್ನು ಪ್ರಸಾರ ಮಾಡುವುದರಿಂದ ಭದ್ರತಾ ಅಪಾಯ ಎದುರಾಗಬಹುದು.\n\nನೆಟ್‌ವರ್ಕ್‌ ಅನ್ನು ಮರೆಮಾಡಿದ ಕೂಡಲೇ ರೂಟರ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳು ಬದಲಾಗುವುದಿಲ್ಲ."</string>
     <string name="wifi_signal" msgid="696548364467704808">"ಸಿಗ್ನಲ್ ಸಾಮರ್ಥ್ಯ"</string>
     <string name="wifi_status" msgid="3439931558930689940">"ಸ್ಥಿತಿ"</string>
-    <string name="tx_wifi_speed" msgid="2571810085003261073">"ಲಿಂಕ್ ವೇಗವನ್ನು ಪ್ರಸಾರ ಮಾಡಿ"</string>
-    <string name="rx_wifi_speed" msgid="7392873246110937187">"ಲಿಂಕ್ ವೇಗವನ್ನು ಸ್ವೀಕರಿಸಿ"</string>
+    <string name="tx_wifi_speed" msgid="2571810085003261073">"ಟ್ರಾನ್ಸ್‌ಮಿಟ್ ಲಿಂಕ್ ವೇಗ"</string>
+    <string name="rx_wifi_speed" msgid="7392873246110937187">"ಸ್ವೀಕರಿಸುವ ಲಿಂಕ್ ವೇಗ"</string>
     <string name="wifi_frequency" msgid="6132852924995724246">"ಫ್ರೀಕ್ವೆನ್ಸಿ"</string>
     <string name="wifi_ip_address" msgid="5572539114989914831">"IP ವಿಳಾಸ"</string>
     <string name="passpoint_label" msgid="7429247462404128615">"ಇದರ ಮೂಲಕ ಉಳಿಸಲಾಗಿದೆ"</string>
@@ -938,7 +940,7 @@
     <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"“<xliff:g id="SSID">%1$s</xliff:g>” ಗೆ ಸಂಪರ್ಕಿಸಲು QR ಕೋಡ್ ಅನ್ನು ಕೆಳಗೆ ಕೇಂದ್ರೀಕರಿಸಿ"</string>
     <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"QR ಕೋಡ್ ಸ್ಕ್ಯಾನ್ ಮಾಡುವ ಮೂಲಕ ವೈ-ಫೈ ಗೆ ಸೇರಿ"</string>
     <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"ವೈ-ಫೈ ಹಂಚಿಕೊಳ್ಳಿ"</string>
-    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"“<xliff:g id="SSID">%1$s</xliff:g>” ಗೆ ಸಂಪರ್ಕಪಡಿಸಲು ಮತ್ತು ಪಾಸ್‌ವರ್ಡ್ ಹಂಚಿಕೊಳ್ಳಲು ಈ QR ಕೋಡ್ ಅನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡಿ"</string>
+    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"“<xliff:g id="SSID">%1$s</xliff:g>” ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಲು ಮತ್ತು ಪಾಸ್‌ವರ್ಡ್ ಹಂಚಿಕೊಳ್ಳಲು ಈ QR ಕೋಡ್ ಅನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡಿ"</string>
     <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"“<xliff:g id="SSID">%1$s</xliff:g>” ಗೆ ಸಂಪರ್ಕಪಡಿಸಲು ಈ QR ಕೋಡ್ ಅನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡಿ"</string>
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"QR ಕೋಡ್ ಅನ್ನು ಓದಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ. ಕೋಡ್ ಮರುನಮೂದಿಸಿ ಅಥವಾ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ"</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"ಪುನಃ ಪ್ರಯತ್ನಿಸಿ. ಸಮಸ್ಯೆ ಮುಂದುವರಿದರೆ, ಸಾಧನ ತಯಾರಕರನ್ನು ಸಂಪರ್ಕಿಸಿ"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"ವೈ-ಫೈ"</item>
+    <item msgid="2271962426654621656">"ಮೊಬೈಲ್"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"ವೈ-ಫೈ ಲಭ್ಯವಿಲ್ಲದಿದ್ದರೆ, ಮೊಬೈಲ್ ನೆಟ್‌ವರ್ಕ್ ಬಳಸಿ"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"ಮೊಬೈಲ್ ನೆಟ್‌ವರ್ಕ್ ಲಭ್ಯವಿಲ್ಲದಿದ್ದರೆ, ವೈ-ಫೈ ಬಳಸಿ"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"ವೈ-ಫೈ ಬಳಸಿ ಕರೆ ಮಾಡಿ. ವೈ-ಫೈ ಸಂಪರ್ಕ ಕಡಿತಗೊಂಡರೆ, ಕರೆ ಕೊನೆಗೊಳ್ಳುತ್ತದೆ."</string>
@@ -1332,7 +1337,7 @@
     <string name="status_number_sim_slot" product="tablet" msgid="4518232285651165459">"MDN (ಸಿಮ್ ಸ್ಲಾಟ್ %1$d)"</string>
     <string name="status_number_sim_slot" product="default" msgid="3660851494421332328">"ಫೋನ್ ಸಂಖ್ಯೆ (ಸಿಮ್ ಸ್ಲಾಟ್ %1$d)"</string>
     <string name="status_number_sim_status" product="tablet" msgid="8069693515860290952">"ಸಿಮ್‌ ನಲ್ಲಿ MDN"</string>
-    <string name="status_number_sim_status" product="default" msgid="6602562692270457610">"ಸಿಮ್‌ನಲ್ಲಿ ಫೋನ್ ಸಂಖ್ಯೆ"</string>
+    <string name="status_number_sim_status" product="default" msgid="6602562692270457610">"ಸಿಮ್‌ನ ಫೋನ್ ಸಂಖ್ಯೆ"</string>
     <string name="status_min_number" msgid="8346889546673707777">"ನಿಮಿ"</string>
     <string name="status_msid_number" msgid="7808175928664357661">"MSID"</string>
     <string name="status_prl_version" msgid="5634561205739199042">"PRL ಆವೃತ್ತಿ"</string>
@@ -1609,7 +1614,7 @@
     <string name="tether_settings_title_wifi" msgid="2060965130234484613">"ಪೋರ್ಟಬಲ್ ಹಾಟ್‌ಸ್ಪಾಟ್"</string>
     <string name="tether_settings_title_bluetooth" msgid="1999590158102569959">"ಬ್ಲೂಟೂತ್‌‌ ಟೆಥರಿಂಗ್‌"</string>
     <string name="tether_settings_title_usb_bluetooth" msgid="1159128764162788159">"ಟೆಥರಿಂಗ್‌"</string>
-    <string name="tether_settings_title_all" msgid="6935843543433954181">"ಹಾಟ್‌ಸ್ಪಾಟ್ ಮತ್ತು ಟೆಥರಿಂಗ್"</string>
+    <string name="tether_settings_title_all" msgid="6935843543433954181">"ಹಾಟ್‌ಸ್ಪಾಟ್ &amp; ಟೆಥರಿಂಗ್"</string>
     <string name="tether_settings_summary_hotspot_on_tether_on" msgid="1289593649526514499">"ಹಾಟ್‌ಸ್ಪಾಟ್ ಆನ್ ಆಗಿದೆ, ಟೆಥರಿಂಗ್‌"</string>
     <string name="tether_settings_summary_hotspot_on_tether_off" msgid="8010689354668285422">"ಹಾಟ್‌ಸ್ಪಾಟ್ ಆನ್ ಆಗಿದೆ"</string>
     <string name="tether_settings_summary_hotspot_off_tether_on" msgid="1349909238672649877">"ಟೆಥರಿಂಗ್‌"</string>
@@ -1741,14 +1746,14 @@
     <string name="lockpassword_confirm_your_password_header_frp" msgid="7326670978891793470">"ಪಾಸ್‌ವರ್ಡ್‌ ಪರಿಶೀಲಿಸಿ"</string>
     <string name="lockpassword_invalid_pin" msgid="3059022215815900137">"ತಪ್ಪಾದ ಪಿನ್‌"</string>
     <string name="lockpassword_invalid_password" msgid="8374331995318204099">"ತಪ್ಪು ಪಾಸ್‌ವರ್ಡ್‌"</string>
-    <string name="lockpattern_need_to_unlock_wrong" msgid="1328670466959377948">"ತಪ್ಪು ಪ್ಯಾಟರ್ನ್"</string>
+    <string name="lockpattern_need_to_unlock_wrong" msgid="1328670466959377948">"ಪ್ಯಾಟರ್ನ್ ತಪ್ಪಾಗಿದೆ"</string>
     <string name="lock_settings_title" msgid="233657584969886812">"ಸಾಧನ ಭದ್ರತೆ"</string>
     <string name="lockpattern_change_lock_pattern_label" msgid="333149762562581510">"ಅನ್‌ಲಾಕ್ ನಮೂನೆಯನ್ನು ಬದಲಾಯಿಸಿ"</string>
     <string name="lockpattern_change_lock_pin_label" msgid="3435796032210265723">"ಅನ್‌ಲಾಕ್ ಪಿನ್‌ ಬದಲಾಯಿಸಿ"</string>
     <string name="lockpattern_recording_intro_header" msgid="2262005028838969839">"ಅನ್‌ಲಾಕ್‌ ಪ್ಯಾಟರ್ನ್ ಚಿತ್ರಿಸಿ"</string>
     <string name="lockpattern_recording_intro_footer" msgid="5426745740754065099">"ಸಹಾಯಕ್ಕಾಗಿ ಮೆನು ಒತ್ತಿರಿ."</string>
     <string name="lockpattern_recording_inprogress" msgid="4060818382176523671">"ಬಳಿಕ ಬೆರಳು ತೆಗೆಯಿರಿ"</string>
-    <string name="lockpattern_recording_incorrect_too_short" msgid="6374760294545431845">"ಕನಿಷ್ಠ <xliff:g id="NUMBER">%d</xliff:g> ಡಾಟ್‌ಗಳನ್ನು ಸಂಪರ್ಕಿಸಿ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
+    <string name="lockpattern_recording_incorrect_too_short" msgid="6374760294545431845">"ಕನಿಷ್ಠ <xliff:g id="NUMBER">%d</xliff:g> ಡಾಟ್‌ಗಳನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಿ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="lockpattern_pattern_entered_header" msgid="2108106638322637851">"ಪ್ಯಾಟರ್ನ್ ರೆಕಾರ್ಡ್ ಆಗಿದೆ"</string>
     <string name="lockpattern_need_to_confirm" msgid="4079482507985867389">"ಖಚಿತಪಡಿಸಲು ಪ್ಯಾಟರ್ನ್ ಚಿತ್ರಿಸಿ"</string>
     <string name="lockpattern_pattern_confirmed_header" msgid="5603156929428721407">"ನಿಮ್ಮ ಹೊಸ ಅನ್‌ಲಾಕ್‌ ಪ್ಯಾಟರ್ನ್"</string>
@@ -2273,10 +2278,10 @@
     <string name="battery_tip_smart_battery_title" product="device" msgid="7419448992583346364">"ನಿಮ್ಮ ಸಾಧನದ ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯನ್ನು ಸುಧಾರಿಸಿ"</string>
     <string name="battery_tip_smart_battery_summary" msgid="5344821856478265778">"ಬ್ಯಾಟರಿ ನಿರ್ವಾಹಕರನ್ನು ಆನ್‌ ಮಾಡಿ"</string>
     <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"ಬ್ಯಾಟರಿ ಸೇವರ್‌ ಆನ್‌ ಮಾಡಿ"</string>
-    <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"ಬ್ಯಾಟರಿ ಸಾಮಾನ್ಯಕ್ಕಿಂತ ಮೊದಲೇ ರನ್ ಆಗಬಹುದು"</string>
+    <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"ಬ್ಯಾಟರಿ ಸಾಮಾನ್ಯಕ್ಕಿಂತ ಮೊದಲೇ ಖಾಲಿಯಾಗಬಹುದು"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಆನ್ ಆಗಿದೆ"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳು ಸೀಮಿತವಾಗಿರಬಹುದು"</string>
-    <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"ಫೋನ್ ಸಾಮಾನ್ಯಕ್ಕಿಂತ ಹೆಚ್ಚಿನದನ್ನು ಬಳಸಿದೆ"</string>
+    <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"ಫೋನ್ ಅನ್ನು ಸಾಮಾನ್ಯಕ್ಕಿಂತ ಹೆಚ್ಚು ಬಳಸಲಾಗಿದೆ"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"ಟ್ಯಾಬ್ಲೆಟ್ ಸಾಮಾನ್ಯಕ್ಕಿಂತ ಹೆಚ್ಚಿನದನ್ನು ಬಳಸಿದೆ"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"ಸಾಧನವು ಸಾಮಾನ್ಯಕ್ಕಿಂತ ಹೆಚ್ಚಿನದನ್ನು ಬಳಸಿದೆ"</string>
     <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"ಬ್ಯಾಟರಿ ಸಾಮಾನ್ಯ ಅವಧಿಗಿಂತ ಮೊದಲೇ ಖಾಲಿಯಾಗಬಹುದು"</string>
@@ -2920,7 +2925,7 @@
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"ಮತ್ತೊಂದು ಪಾವತಿ ಅಪ್ಲಿಕೇಶನ್ ತೆರೆದಿರುವುದನ್ನು ಹೊರತುಪಡಿಸಿ"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"ಟ್ಯಾಪ್‌ ಮಾಡಿ ಮತ್ತು ಪಾವತಿ ಟರ್ಮಿನಲ್‌ನಲ್ಲಿ, ಇದರ ಮೂಲಕ ಪಾವತಿಸಿ:"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"ಟರ್ಮಿನಲ್‌ನಲ್ಲಿ ಪಾವತಿಸಲಾಗುತ್ತಿದೆ"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"ಪಾವತಿ ಅಪ್ಲಿಕೇಶನ್ ಹೊಂದಿಸಿ. ನಂತರ ಸಂಪರ್ಕವಿಲ್ಲದ ಚಿಹ್ನೆಯೊಂದಿಗೆ ಯಾವುದೇ ಟರ್ಮಿನಲ್‌ಗೆ ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"ಪಾವತಿ ಆ್ಯಪ್ ಹೊಂದಿಸಿ. ನಂತರ ಸಂಪರ್ಕವಿಲ್ಲದ ಚಿಹ್ನೆಯೊಂದಿಗೆ ಯಾವುದೇ ಟರ್ಮಿನಲ್‌ಗೆ ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"ತಿಳಿಯಿತು"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"ಇನ್ನಷ್ಟು..."</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"ನಿಮ್ಮ ಪ್ರಾಶಸ್ತ್ಯವನ್ನು ಹೊಂದಿಸಬೇಕೆ?"</string>
@@ -3119,7 +3124,7 @@
     <string name="keywords_default_payment_app" msgid="845369409578423996">"ಪಾವತಿ, ಡಿಫಾಲ್ಟ್"</string>
     <string name="keywords_ambient_display" msgid="8835182491798487184">"ಒಳಬರುವ ಅಧಿಸೂಚನೆ"</string>
     <string name="keywords_hotspot_tethering" msgid="1723591462602613867">"usb ಟೆಥರ್, ಬ್ಲೂಟೂತ್ ಟೆಥರ್, ವೈಫೈ ಹಾಟ್‌ಸ್ಪಾಟ್"</string>
-    <string name="keywords_touch_vibration" msgid="2081175517528255224">"ಹ್ಯಾಪ್ಟಿಕ್ಸ್, ಕಂಪನ, ಪರದೆ, ಸಂವೇದನೆ"</string>
+    <string name="keywords_touch_vibration" msgid="2081175517528255224">"ಹ್ಯಾಪ್ಟಿಕ್ಸ್, ವೈಬ್ರೇಟ್‌, ಪರದೆ, ಸಂವೇದನೆ"</string>
     <string name="keywords_ring_vibration" msgid="4210509151866460210">"ಹ್ಯಾಪ್ಟಿಕ್ಸ್, ವೈಬ್ರೇಟ್‌, ಫೋನ್, ಕರೆ, ಸೂಕ್ಷ್ಮತೆ, ರಿಂಗ್"</string>
     <string name="keywords_notification_vibration" msgid="1077515502086745166">"ಹ್ಯಾಪ್ಟಿಕ್ಸ್, ವೈಬ್ರೇಟ್‌, ಸೂಕ್ಷ್ಮತೆ"</string>
     <string name="keywords_battery_saver_sticky" msgid="8733804259716284872">"ಬ್ಯಾಟರಿ ಸೇವರ್, ಸ್ಟಿಕಿ, ತಡೆ ಹಿಡಿ, ಪವರ್ ಸೇವರ್, ಬ್ಯಾಟರಿ"</string>
@@ -3144,7 +3149,7 @@
     <string name="other_sound_settings" msgid="5250376066099818676">"ಇತರ ಧ್ವನಿಗಳು"</string>
     <string name="dial_pad_tones_title" msgid="8877212139988655769">"ಡಯಲ್‌ ಪ್ಯಾಡ್‌ ಟೋನ್‌ಗಳು"</string>
     <string name="screen_locking_sounds_title" msgid="4407110895465866809">"ಸ್ಕ್ರೀನ್ ಲಾಕಿಂಗ್ ಧ್ವನಿಗಳು"</string>
-    <string name="charging_sounds_title" msgid="5070437987230894287">"ಚಾರ್ಜಿಂಗ್ ಧ್ವನಿಗಳು ಮತ್ತು ಕಂಪನ"</string>
+    <string name="charging_sounds_title" msgid="5070437987230894287">"ಚಾರ್ಜಿಂಗ್ ಧ್ವನಿಗಳು ಮತ್ತು ವೈಬ್ರೇಟ್‌"</string>
     <string name="docking_sounds_title" msgid="2573137471605541366">"ಡಾಕಿಂಗ್ ಧ್ವನಿಗಳು"</string>
     <string name="touch_sounds_title" msgid="165237488496165652">"ಸ್ಪರ್ಶ ಧ್ವನಿಗಳು"</string>
     <string name="vibrate_on_touch_title" msgid="6360155469279157684">"ಸ್ಪರ್ಶಿಸಿದಾಗ ವೈಬ್ರೇಷನ್‌"</string>
@@ -3318,7 +3323,7 @@
     <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ಲಾಕ್ ಮಾಡಿದಾಗ"</string>
     <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"ಅಧಿಸೂಚನೆ ವಿಷಯವನ್ನು ಪೂರ್ತಿ ತೋರಿಸು"</string>
     <string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"ಸೂಕ್ಷ್ಮ ವಿಷಯವನ್ನು ಮರೆಮಾಡು"</string>
-    <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"ಅಧಿಸೂಚನೆಗಳನ್ನು ತೋರಿಸಲೇ ಬೇಡ"</string>
+    <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"ಅಧಿಸೂಚನೆಗಳನ್ನು ತೋರಿಸಬೇಡಿ"</string>
     <string name="lock_screen_notifications_interstitial_message" msgid="4230189215124387818">"ಸಾಧನ ಲಾಕ್‌ ಆದಾಗ, ಅಧಿಸೂಚನೆಗಳು ಹೇಗೆ ಕಾಣಿಸಿಕೊಳ್ಳಬೇಕು?"</string>
     <string name="lock_screen_notifications_interstitial_title" msgid="2832587379332443505">"ಅಧಿಸೂಚನೆಗಳು"</string>
     <string name="lock_screen_notifications_summary_show_profile" msgid="8908775469657073273">"ಉದ್ಯೋಗದ ಅಧಿಸೂಚನೆ ವಿಷಯವನ್ನು ಪೂರ್ತಿ ತೋರಿಸು"</string>
@@ -4032,7 +4037,7 @@
     <string name="notification_log_details_ashmem" msgid="4272241723105041393">"ಆಶ್ಮೆಮ್"</string>
     <string name="notification_log_details_alerted" msgid="1891749888625061319">"ಅಧಿಸೂಚನೆಯ ಎಚ್ಚರಿಕೆಯನ್ನು ನೀಡಲಾಗಿದೆ"</string>
     <string name="notification_log_details_sound" msgid="4028782443557466322">"ಶಬ್ದ"</string>
-    <string name="notification_log_details_vibrate" msgid="8372400602058888072">"ಕಂಪನ"</string>
+    <string name="notification_log_details_vibrate" msgid="8372400602058888072">"ವೈಬ್ರೇಟ್‌"</string>
     <string name="notification_log_details_vibrate_pattern" msgid="7015554755444260922">"ಪ್ಯಾಟರ್ನ್"</string>
     <string name="notification_log_details_default" msgid="455451833359888182">"ಡಿಫಾಲ್ಟ್"</string>
     <string name="notification_log_details_none" msgid="4294690532744821638">"ಯಾವುದೂ ಇಲ್ಲ"</string>
@@ -4234,7 +4239,7 @@
     <string name="storage_music_audio" msgid="3661289086715297149">"ಸಂಗೀತ ಮತ್ತು ಆಡಿಯೋ"</string>
     <string name="storage_games" msgid="7740038143749092373">"ಗೇಮ್‌ಗಳು"</string>
     <string name="storage_other_apps" msgid="3202407095387420842">"ಇತರ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"</string>
-    <string name="storage_files" msgid="2087824267937487880">"ಫೈಲ್‌ಗಳು"</string>
+    <string name="storage_files" msgid="2087824267937487880">"Files"</string>
     <string name="storage_size_large_alternate" msgid="1317796542509105857">"<xliff:g id="NUMBER">^1</xliff:g>"<small>" "<font size="20">"<xliff:g id="UNIT">^2</xliff:g>"</font></small>""</string>
     <string name="storage_volume_total" msgid="5021484171514159913">"<xliff:g id="TOTAL">%1$s</xliff:g> ನಲ್ಲಿ ಬಳಸಿರುವುದು"</string>
     <string name="storage_percent_full" msgid="6924662861545958442">"ಬಳಕೆಯಾಗಿದೆ"</string>
@@ -4264,7 +4269,7 @@
     <string name="storage_manager_indicator_on" msgid="5295306384982062320">"ಆನ್"</string>
     <string name="install_type_instant" msgid="6248487669862821874">"ತತ್‌ಕ್ಷಣದ ಅಪ್ಲಿಕೇಶನ್"</string>
     <string name="automatic_storage_manager_deactivation_warning" msgid="7867793739491286374">"ಸಂಗ್ರಹಣೆ ನಿರ್ವಾಹಕವನ್ನು ಆಫ್ ಮಾಡುವುದೇ?"</string>
-    <string name="storage_movies_tv" msgid="7282484273991655296">"ಚಲನಚಿತ್ರ ಮತ್ತು ಟಿವಿ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"</string>
+    <string name="storage_movies_tv" msgid="7282484273991655296">"ಚಲನಚಿತ್ರ ಮತ್ತು ಟಿವಿ ಆ್ಯಪ್‍‍ಗಳು"</string>
     <string name="carrier_provisioning" msgid="3309125279191534469">"ವಾಹಕ ಪೂರೈಕೆಯ ಮಾಹಿತಿ"</string>
     <string name="trigger_carrier_provisioning" msgid="6284005970057901477">"ಟ್ರಿಗ್ಗರ್ ವಾಹಕ ಪೂರೈಕೆ"</string>
     <string name="zen_suggestion_title" msgid="2134699720214231950">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಅನ್ನು ಅಪ್‌ಡೇಟ್‌ ಮಾಡಿ"</string>
@@ -4324,7 +4329,7 @@
     <string name="prevent_ringing_option_vibrate" msgid="6456505293904544108">"ವೈಬ್ರೇಟ್‌"</string>
     <string name="prevent_ringing_option_mute" msgid="53662688921253613">"ಮ್ಯೂಟ್"</string>
     <string name="prevent_ringing_option_none" msgid="1450985763137666231">"ಏನೂ ಮಾಡಬೇಡಿ"</string>
-    <string name="prevent_ringing_option_vibrate_summary" msgid="7961818570574683926">"(ವೈಬ್ರೇಟ್‌) ನಲ್ಲಿ"</string>
+    <string name="prevent_ringing_option_vibrate_summary" msgid="7961818570574683926">"ಆನ್ ಆಗಿದೆ (ವೈಬ್ರೇಟ್‌)"</string>
     <string name="prevent_ringing_option_mute_summary" msgid="3509459199090688328">"(ಮ್ಯೂಟ್) ನಲ್ಲಿ"</string>
     <string name="prevent_ringing_option_none_summary" msgid="5152618221093037451">"ಆಫ್"</string>
     <string name="pref_title_network_details" msgid="3971074015034595956">"ನೆಟ್‌ವರ್ಕ್‌ ವಿವರಗಳು"</string>
@@ -4468,7 +4473,7 @@
     <string name="privacy_dashboard_title" msgid="8764930992456607513">"ಗೌಪ್ಯತೆ"</string>
     <string name="privacy_dashboard_summary" msgid="7916431309860824945">"ಅನುಮತಿಗಳು, ಖಾತೆ ಚಟುವಟಿಕೆ, ವೈಯಕ್ತಿಕ ಡೇಟಾ"</string>
     <string name="contextual_card_dismiss_remove" msgid="1750420285615827309">"ತೆಗೆದುಹಾಕಿ"</string>
-    <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"ಇರಿಸಿಕೊಳ್ಳಿ"</string>
+    <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"Keep"</string>
     <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"ಈ ಸಲಹೆಯನ್ನು ತೆಗೆದುಹಾಕುವುದೇ?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"ಸಲಹೆಯನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"ರದ್ದುಗೊಳಿಸಿ"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ko/arrays.xml b/tests/CarDeveloperOptions/res/values-ko/arrays.xml
index a7a5ba5..75a36b3 100644
--- a/tests/CarDeveloperOptions/res/values-ko/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-ko/arrays.xml
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"허용 안함"</item>
     <item msgid="8184570120217958741">"항상 허용"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"보통"</item>
+    <item msgid="5101233285497327432">"일반"</item>
+    <item msgid="1555861583162930714">"낮음"</item>
+    <item msgid="1719683776264798117">"중요"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"보통"</item>
+    <item msgid="6107138933849816768">"중간"</item>
+    <item msgid="182695359839047859">"낮음"</item>
+    <item msgid="8577246509202964244">"심각"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"영구"</item>
     <item msgid="167418068739176448">"메모리 사용이 가장 많은 활동"</item>
@@ -467,7 +477,7 @@
     <item msgid="1008268820118852416">"무제한 Wi-Fi로 취급"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
-    <item msgid="6545683814310036454">"임의의 MAC 사용(기본값)"</item>
+    <item msgid="6545683814310036454">"무작위 MAC 사용(기본값)"</item>
     <item msgid="214234417308375326">"기기 MAC 사용"</item>
   </string-array>
   <string-array name="wifi_hidden_entries">
diff --git a/tests/CarDeveloperOptions/res/values-ko/config.xml b/tests/CarDeveloperOptions/res/values-ko/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-ko/config.xml
+++ b/tests/CarDeveloperOptions/res/values-ko/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-ko/strings.xml b/tests/CarDeveloperOptions/res/values-ko/strings.xml
index b8657ba..8d36e87 100644
--- a/tests/CarDeveloperOptions/res/values-ko/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ko/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"화면 텍스트를 축소 또는 확대합니다."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"축소"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"확대"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"샘플 텍스트"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"오즈의 마법사"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"11장: 오즈의 멋진 에메랄드 도시"</string>
@@ -668,7 +667,6 @@
       <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g>자리 미만이어야 합니다.</item>
       <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g>자리 미만이어야 합니다.</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"0에서 9까지의 숫자만 포함되어야 합니다."</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"기기 관리자가 최근 PIN 사용을 허용하지 않습니다."</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"IT 관리자가 일반 PIN을 차단했습니다. 다른 PIN을 시도해 보세요."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"잘못된 문자를 포함할 수 없습니다."</string>
@@ -699,6 +697,10 @@
       <item quantity="other">글자가 아닌 문자를 <xliff:g id="COUNT">%d</xliff:g>개 이상 포함해야 합니다.</item>
       <item quantity="one">글자가 아닌 문자를 1개 이상 포함해야 합니다.</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">숫자가 아닌 문자를 <xliff:g id="COUNT">%d</xliff:g>개 이상 포함해야 합니다.</item>
+      <item quantity="one">숫자가 아닌 문자를 1개 이상 포함해야 합니다.</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"기기 관리자가 최근 비밀번호 사용을 허용하지 않습니다."</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"IT 관리자가 일반적인 단어로 된 비밀번호를 허용하지 않습니다. 다른 비밀번호를 시도해 보세요."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"연속으로 올라가거나 내려가는 숫자 또는 반복되는 숫자의 배열은 허용되지 않습니다."</string>
@@ -764,7 +766,7 @@
     <string name="bluetooth_menu_advanced" msgid="7566858513372603652">"고급"</string>
     <string name="bluetooth_advanced_titlebar" msgid="6459469494039004784">"고급 블루투스"</string>
     <string name="bluetooth_empty_list_bluetooth_off" msgid="6255367297830430459">"기기에서 블루투스가 켜져 있으면 주변의 다른 블루투스 기기와 통신할 수 있습니다."</string>
-    <string name="bluetooth_scanning_on_info_message" msgid="5460370815156050550">"기기에서 블루투스가 켜져 있으면 주변의 다른 블루투스 기기와 통신할 수 있습니다.\n\n기기 환경을 개선하려면 블루투스가 꺼져 있을 때도 항상 앱 및 서비스에서 주변 기기를 검색할 수 있어야 합니다. 예를 들면 위치 기반 기능 및 서비스를 개선하는 데 이 설정이 사용될 수 있습니다. "<annotation id="link">"검색 설정"</annotation>"에서 관련 설정을 변경할 수 있습니다."</string>
+    <string name="bluetooth_scanning_on_info_message" msgid="5460370815156050550">"기기에서 블루투스가 켜져 있으면 주변의 다른 블루투스 기기와 통신할 수 있습니다.\n\n기기 환경을 개선하기 위해 블루투스가 꺼져 있을 때도 항상 앱 및 서비스에서 주변 기기를 검색할 수 있습니다. 예를 들면 위치 기반 기능 및 서비스를 개선하는 데 이 설정이 사용될 수 있습니다. "<annotation id="link">"검색 설정"</annotation>"에서 관련 설정을 변경할 수 있습니다."</string>
     <string name="ble_scan_notify_text" msgid="6290170236546386932">"위치 정확도 개선을 위해 시스템 앱과 서비스에서 블루투스 기기를 계속 감지할 수 있습니다. <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>검색 설정<xliff:g id="LINK_END_1">LINK_END</xliff:g>에서 설정을 변경할 수 있습니다."</string>
     <string name="bluetooth_connect_failed" msgid="1151234676456333786">"연결할 수 없습니다. 다시 시도해 주세요."</string>
     <string name="device_details_title" msgid="726517818032923222">"기기 세부정보"</string>
@@ -936,7 +938,7 @@
     <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"\'<xliff:g id="SSID">%1$s</xliff:g>\'에 기기를 추가하려면 아래 창의 가운데 부분에 QR 코드를 맞추세요."</string>
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"QR 코드 스캔"</string>
     <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"\'<xliff:g id="SSID">%1$s</xliff:g>\'에 연결하려면 아래 창의 가운데 부분에 QR 코드를 맞추세요."</string>
-    <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"QR 코드를 스캔하여 Wi‑Fi에 연결"</string>
+    <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"QR 코드를 스캔하여 Wi‑Fi에 연결하세요."</string>
     <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Wi‑Fi 공유"</string>
     <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"이 QR 코드를 스캔하여 \'<xliff:g id="SSID">%1$s</xliff:g>\'에 연결하고 비밀번호를 공유하세요."</string>
     <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"이 QR 코드를 스캔하여 \'<xliff:g id="SSID">%1$s</xliff:g>\'에 연결"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"모바일"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Wi‑Fi를 사용할 수 없는 경우 모바일 네트워크를 사용하세요."</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"모바일 네트워크를 사용할 수 없는 경우 Wi‑Fi를 사용합니다."</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Wi‑Fi를 통해 통화합니다. Wi‑Fi 연결이 끊기면 통화가 종료됩니다."</string>
@@ -1522,7 +1527,7 @@
     <string name="battery_status_title" msgid="8731200319740671905">"배터리 상태"</string>
     <string name="battery_level_title" msgid="5207775387973771646">"배터리 수준"</string>
     <string name="apn_settings" msgid="8130776653826271664">"APN"</string>
-    <string name="apn_edit" msgid="4350571070853305357">"액세스 포인트(APN) 편집"</string>
+    <string name="apn_edit" msgid="4350571070853305357">"액세스 포인트 수정"</string>
     <string name="apn_not_set" msgid="5344235604466825691">"설정되지 않음"</string>
     <string name="apn_name" msgid="8431432886706852226">"이름"</string>
     <string name="apn_apn" msgid="190519449579357696">"APN"</string>
@@ -2262,7 +2267,7 @@
     <string name="details_subtitle" msgid="7279638828004951382">"사용 세부정보"</string>
     <string name="controls_subtitle" msgid="6920199888882834620">"전원 사용 조절"</string>
     <string name="packages_subtitle" msgid="6506269487892204413">"포함된 패키지"</string>
-    <string name="battery_tip_summary_title" msgid="2750922152518825526">"앱이 정상적으로 작동 중입니다."</string>
+    <string name="battery_tip_summary_title" msgid="2750922152518825526">"앱이 정상적으로 작동 중"</string>
     <string name="battery_tip_summary_summary" product="default" msgid="6294900413896440006">"배터리 사용량이 평소와 같습니다."</string>
     <string name="battery_tip_summary_summary" product="tablet" msgid="5280099016800644130">"태블릿의 배터리 사용량이 평소와 같습니다."</string>
     <string name="battery_tip_summary_summary" product="device" msgid="4459840492610842705">"기기의 배터리 사용량이 평소와 같습니다."</string>
@@ -3228,7 +3233,7 @@
     <string name="zen_mode_button_turn_on" msgid="1097964136225943415">"지금 사용 설정"</string>
     <string name="zen_mode_button_turn_off" msgid="3990967728457149454">"지금 사용 중지"</string>
     <string name="zen_mode_settings_dnd_manual_end_time" msgid="4307574188962071429">"<xliff:g id="FORMATTED_TIME">%s</xliff:g>까지 방해 금지 모드를 사용합니다"</string>
-    <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"방해 금지 모드를 끌 때까지 계속 사용합니다"</string>
+    <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"방해 금지 모드를 사용 중지할 때까지 계속 사용합니다"</string>
     <string name="zen_mode_settings_dnd_automatic_rule" msgid="2843297614114625408">"예약(<xliff:g id="RULE_NAME">%s</xliff:g>)에 따라 방해 금지 모드가 자동으로 시작되었습니다."</string>
     <string name="zen_mode_settings_dnd_automatic_rule_app" msgid="5103454923160912313">"방해 금지 모드가 앱(<xliff:g id="APP_NAME">%s</xliff:g>)에 의해 자동으로 사용 설정되었습니다"</string>
     <string name="zen_mode_settings_dnd_custom_settings_footer" msgid="6335108298640066560">"<xliff:g id="RULE_NAMES">%s</xliff:g>까지 맞춤 설정이 적용된 방해 금지 모드를 사용합니다."</string>
@@ -3247,8 +3252,8 @@
     </plurals>
     <string name="zen_mode_duration_summary_time_minutes" msgid="6988728116715208859">"<xliff:g id="NUM_MINUTES">%d</xliff:g>분(자동으로 사용 설정되지 않은 경우)"</string>
     <plurals name="zen_mode_sound_summary_summary_off_info" formatted="false" msgid="8527428833487709278">
-      <item quantity="other"><xliff:g id="ON_COUNT">%d</xliff:g>개의 예약이 자동으로 설정될 수 있습니다.</item>
-      <item quantity="one">1개의 예약이 자동으로 설정될 수 있습니다.</item>
+      <item quantity="other"><xliff:g id="ON_COUNT">%d</xliff:g>개의 예약이 자동으로 사용 설정될 수 있습니다.</item>
+      <item quantity="one">1개의 예약이 자동으로 사용 설정될 수 있습니다.</item>
     </plurals>
     <string name="zen_category_behavior" msgid="7695750848671443532">"기기를 음소거하되 예외 허용"</string>
     <string name="zen_category_exceptions" msgid="2139670640033601899">"예외"</string>
@@ -3757,8 +3762,8 @@
     <string name="assist_access_context_summary" msgid="5867997494395842785">"지원 앱이 화면의 텍스트 콘텐츠에 액세스하도록 허용합니다."</string>
     <string name="assist_access_screenshot_title" msgid="1991014038776117688">"스크린샷 사용"</string>
     <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"지원 앱이 화면의 이미지에 액세스하도록 허용합니다."</string>
-    <string name="assist_flash_title" msgid="8852484250748551092">"플래시 화면"</string>
-    <string name="assist_flash_summary" msgid="6697095786317559129">"지원 앱이 화면이나 스크린샷에서 텍스트에 액세스할 때 화면 가장자리에 플래시를 표시합니다."</string>
+    <string name="assist_flash_title" msgid="8852484250748551092">"화면 깜빡이기"</string>
+    <string name="assist_flash_summary" msgid="6697095786317559129">"지원 앱이 화면이나 스크린샷에서 텍스트에 액세스할 때 화면 가장자리가 깜빡입니다."</string>
     <string name="assist_footer" msgid="7030121180457472165">"지원 앱은 화면에 표시된 정보에 맞게 도움을 줄 수 있습니다. 일부 앱은 통합된 지원을 제공하기 위해 런처와 음성 입력 서비스를 모두 지원합니다."</string>
     <string name="average_memory_use" msgid="5333366040118953945">"평균 메모리 사용"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"최대 메모리 사용"</string>
@@ -4474,7 +4479,7 @@
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"실행취소"</string>
     <string name="low_storage_summary" msgid="4562224870189133400">"저장용량이 얼마 남지 않았습니다. <xliff:g id="PERCENTAGE">%1$s</xliff:g> 사용 중 - <xliff:g id="FREE_SPACE">%2$s</xliff:g> 사용 가능"</string>
     <string name="contextual_card_feedback_send" msgid="8698649023854350623">"의견 보내기"</string>
-    <string name="contextual_card_feedback_confirm_message" msgid="3987973028353264878">"이 제안에 관한 의견을 보내주세요."</string>
+    <string name="contextual_card_feedback_confirm_message" msgid="3987973028353264878">"이 추천 항목에 관한 의견을 보내주세요."</string>
     <string name="copyable_slice_toast" msgid="1357518174923789947">"<xliff:g id="COPY_CONTENT">%1$s</xliff:g>이(가) 클립보드에 복사되었습니다."</string>
     <string name="search_bar_account_avatar_content_description" msgid="947628881535053409"></string>
     <string name="permission_bar_chart_empty_text" msgid="5893326513700540130">"권한을 사용한 앱 0개"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ky/arrays.xml b/tests/CarDeveloperOptions/res/values-ky/arrays.xml
index 46dc219..248e0a2 100644
--- a/tests/CarDeveloperOptions/res/values-ky/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-ky/arrays.xml
@@ -29,8 +29,25 @@
     <item msgid="5194868215515664953">"Тынч океан"</item>
     <item msgid="7044520255415007865">"Бардыгы"</item>
   </string-array>
-    <!-- no translation found for screen_timeout_entries:0 (8596143519087753804) -->
-    <!-- no translation found for dream_timeout_entries:7 (8271452751594598661) -->
+  <string-array name="screen_timeout_entries">
+    <item msgid="8596143519087753804">"15 секунд"</item>
+    <item msgid="772029947136115322">"30 секунд"</item>
+    <item msgid="8743663928349474087">"1 мүнөт"</item>
+    <item msgid="1506508631223164814">"2 мүнөт"</item>
+    <item msgid="8664703938127907662">"5 мүнөт"</item>
+    <item msgid="5827960506924849753">"10 мүнөт"</item>
+    <item msgid="6677424950124253938">"30 мүнөт"</item>
+  </string-array>
+  <string-array name="dream_timeout_entries">
+    <item msgid="6487043225269853023">"Эч качан"</item>
+    <item msgid="2517785806387977252">"15 секунд"</item>
+    <item msgid="6347954399441173672">"30 секунд"</item>
+    <item msgid="4858305253279921789">"1 мүнөт"</item>
+    <item msgid="8109273437140044073">"2 мүнөт"</item>
+    <item msgid="2788593551142462622">"5 мүнөт"</item>
+    <item msgid="8012672183888404961">"10 мүнөт"</item>
+    <item msgid="8271452751594598661">"30 мүнөт"</item>
+  </string-array>
   <string-array name="lock_after_timeout_entries">
     <item msgid="2232921187970351881">"Дароо"</item>
     <item msgid="2038544972632026612">"5 секунд"</item>
@@ -42,17 +59,47 @@
     <item msgid="811192536981678974">"10 мүнөт"</item>
     <item msgid="7258394417241706272">"30 мүнөт"</item>
   </string-array>
-    <!-- no translation found for entries_font_size:0 (2340391964816059553) -->
-    <!-- no translation found for entries_font_size:0 (6490061470416867723) -->
-    <!-- no translation found for entries_font_size:2 (1714184661981538355) -->
-    <!-- no translation found for entries_font_size:2 (1678068858001018666) -->
-    <!-- no translation found for wifi_status:3 (5848277343965362748) -->
-    <!-- no translation found for wifi_status_with_ssid:1 (6816207058895999545) -->
-    <!-- no translation found for wifi_status_with_ssid:3 (7547609081339573756) -->
-    <!-- no translation found for wifi_status_with_ssid:4 (5145158315060185414) -->
+  <string-array name="entries_font_size">
+    <item msgid="2340391964816059553">"Кичине"</item>
+    <item msgid="591935967183159581">"Демейки"</item>
+    <item msgid="1714184661981538355">"Чоң"</item>
+    <item msgid="6195563047686707484">"Эң чоң"</item>
+  </string-array>
+  <string-array name="wifi_status">
+    <item msgid="1304883790721412351"></item>
+    <item msgid="4157625910392775808">"Скандалууда…"</item>
+    <item msgid="5597394826455877834">"Туташууда…"</item>
+    <item msgid="5848277343965362748">"Аныктыгы текшерилүүдө…"</item>
+    <item msgid="3391238031431440676">"IP дареги алынууда…"</item>
+    <item msgid="5257597310494000224">"Туташты"</item>
+    <item msgid="8472497592913050396">"Убактылуу токтотулду"</item>
+    <item msgid="1228072488815999109">"Ажыратылууда…"</item>
+    <item msgid="7253087004422991731">"Ажыратылган"</item>
+    <item msgid="4169850917304751227">"Ийгиликсиз"</item>
+    <item msgid="6266658166690831131">"Бөгөттөлгөн"</item>
+    <item msgid="4517230805854909775">"Начар байланыштан убактылуу баш тартууда"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="4853670665485437464"></item>
+    <item msgid="6816207058895999545">"Изделүүдө…"</item>
+    <item msgid="8058143476674427024">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> тармагына туташууда…"</item>
+    <item msgid="7547609081339573756">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> менен аныктыгы текшерилүүдө…"</item>
+    <item msgid="5145158315060185414">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> тармагынан IP дареги алынууда…"</item>
+    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> тармагына туташты"</item>
+    <item msgid="6600156231416890902">"Убактылуу токтотулду"</item>
+    <item msgid="4133290864821295785">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> тармагынан ажыратылууда…"</item>
+    <item msgid="3980154971187953257">"Ажыратылган"</item>
+    <item msgid="2847316776634969068">"Ийгиликсиз"</item>
+    <item msgid="4390990424746035383">"Бөгөттөлгөн"</item>
+    <item msgid="3618248791367063949">"Начар байланыштан убактылуу баш тартууда"</item>
+  </string-array>
     <!-- no translation found for wifi_tether_security:0 (5586343370515598801) -->
     <!-- no translation found for wifi_tether_security:1 (6136336549994615745) -->
-    <!-- no translation found for wifi_p2p_wps_setup:0 (5390235347963255303) -->
+  <string-array name="wifi_p2p_wps_setup">
+    <item msgid="5390235347963255303">"Баскычты басыңыз"</item>
+    <item msgid="7401896200768713930">"Туташуучу түзмөктүн PIN\'и"</item>
+    <item msgid="4526848028011846710">"Ушул түзмөктүн PIN\'и"</item>
+  </string-array>
   <string-array name="wifi_p2p_status">
     <item msgid="8741947238021758201">"Туташты"</item>
     <item msgid="983792611851499732">"Чакырылды"</item>
@@ -60,7 +107,12 @@
     <item msgid="4646663015449312554">"Жеткиликтүү"</item>
     <item msgid="3230556734162006146">"Аракет чегинен тышкары"</item>
   </string-array>
-    <!-- no translation found for bluetooth_visibility_timeout_entries:1 (2759776603549270587) -->
+  <string-array name="bluetooth_visibility_timeout_entries">
+    <item msgid="8247986727324120082">"2 мүнөт"</item>
+    <item msgid="2759776603549270587">"5 мүнөт"</item>
+    <item msgid="167772676068860015">"1 саат"</item>
+    <item msgid="5985477119043628504">"Токтотпоо"</item>
+  </string-array>
   <string-array name="bluetooth_max_connected_audio_devices">
     <item msgid="3800257971619063588">"Демейки маани колдонулат: <xliff:g id="DEFAULT_BLUETOOTH_MAX_CONNECTED_AUDIO_DEVICES">%1$d</xliff:g>"</item>
     <item msgid="8572230405241423895">"1"</item>
@@ -69,8 +121,13 @@
     <item msgid="1644506614010085798">"4"</item>
     <item msgid="3132506679404897150">"5"</item>
   </string-array>
-    <!-- no translation found for wifi_signal:1 (7882129634982603782) -->
-    <!-- no translation found for wifi_signal:4 (999948812884919584) -->
+  <string-array name="wifi_signal">
+    <item msgid="1709949377823900951">"Начар"</item>
+    <item msgid="7882129634982603782">"Начар"</item>
+    <item msgid="6457357501905996224">"Орто"</item>
+    <item msgid="405271628162918841">"Жакшы"</item>
+    <item msgid="999948812884919584">"Эң жакшы"</item>
+  </string-array>
   <string-array name="data_usage_data_range">
     <item msgid="8986775481492954015">"Акыркы 30 күн"</item>
     <item msgid="3211287705232736964">"Колдонуу мерчимин коюу…"</item>
@@ -106,10 +163,13 @@
     <item msgid="7330627471456865502">"MSCHAPV2"</item>
     <item msgid="6255179395132581882">"GTC"</item>
   </string-array>
-    <!-- no translation found for wifi_ip_settings:1 (4377002609760712163) -->
+  <string-array name="wifi_ip_settings">
+    <item msgid="2717196390555072244">"DHCP"</item>
+    <item msgid="4377002609760712163">"Туруктуу"</item>
+  </string-array>
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"Эчтеке жок"</item>
-    <item msgid="1464741437353223198">"Нускама"</item>
+    <item msgid="1464741437353223198">"Кол менен"</item>
     <item msgid="5793600062487886090">"Прокси авто-конфигурац."</item>
   </string-array>
   <string-array name="apn_auth_entries">
@@ -226,11 +286,73 @@
     <item msgid="1165623660533024666">"фондо ойнотуу"</item>
     <item msgid="6423861043647911030">"атайын мүмкүнчүлүктөрдүн үнүнүн катуулугу"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:3 (7836406246005211990) -->
-    <!-- no translation found for app_ops_labels:4 (3951439024549922598) -->
-    <!-- no translation found for app_ops_labels:8 (3597797992398484655) -->
-    <!-- no translation found for app_ops_labels:20 (3037159047591081136) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Жайгашкан жер"</item>
+    <item msgid="6656077694190491067">"Жайгашкан жер"</item>
+    <item msgid="8790228218278477369">"Жайгашкан жер"</item>
+    <item msgid="7836406246005211990">"Дирилдөө"</item>
+    <item msgid="3951439024549922598">"Байланыштарды окуу"</item>
+    <item msgid="8802152411647068">"Байланыштарды өзгөртүү"</item>
+    <item msgid="229544934599698735">"Чалуулар тизмесин окуу"</item>
+    <item msgid="7396102294405899613">"Чалуулар тизмесин өзгөртүү"</item>
+    <item msgid="3597797992398484655">"Жылнааманы окуу"</item>
+    <item msgid="2705975774250907343">"Күнбаракты өзгөртүү"</item>
+    <item msgid="4668747371441932697">"Жайгашкан жер"</item>
+    <item msgid="1487578921720243646">"Эскертүү жайгаштыруу"</item>
+    <item msgid="4636080349724146638">"Орду"</item>
+    <item msgid="673510900286463926">"Телефон чалуу"</item>
+    <item msgid="542083422784609790">"SMS/MMS окуу"</item>
+    <item msgid="1033780373029588436">"SMS/MMS жазуу"</item>
+    <item msgid="5647111115517787488">"SMS/MMS алуу"</item>
+    <item msgid="8591105601108455893">"SMS/MMS алуу"</item>
+    <item msgid="7730995008517841903">"SMS/MMS алуу"</item>
+    <item msgid="2613033109026626086">"SMS/MMS алуу"</item>
+    <item msgid="3037159047591081136">"SMS/MMS жөнөтүү"</item>
+    <item msgid="4726682243833913568">"SMS/MMS окуу"</item>
+    <item msgid="6555678522277865572">"SMS/MMS жазуу"</item>
+    <item msgid="6981734935578130884">"Тууралоолорду өзгөртүү"</item>
+    <item msgid="8705854389991425629">"Үстүнө тартуу"</item>
+    <item msgid="5861356020344153651">"Жетки билдирмелери"</item>
+    <item msgid="78432174621628659">"Камера"</item>
+    <item msgid="3986116419882154794">"Аудио жаздыруу"</item>
+    <item msgid="4516840825756409490">"Аудио ойнотуу"</item>
+    <item msgid="6811712502798183957">"Алмашуу буферин окуу"</item>
+    <item msgid="2780369012602289114">"Алмашуу буферин өзгөртүү"</item>
+    <item msgid="2331359440170850868">"Медиа баскычтар"</item>
+    <item msgid="6133599737122751231">"Аудио фокус"</item>
+    <item msgid="6844485713404805301">"Үн башкаргыч"</item>
+    <item msgid="1600379420669104929">"Үндүн деңгээли"</item>
+    <item msgid="6296768210470214866">"Шыңгырдын үнү"</item>
+    <item msgid="510690696071629241">"Мультимедианын катуулугу"</item>
+    <item msgid="406861638631430109">"Ойготкучтун катуулугу"</item>
+    <item msgid="4715864795872233884">"Эскертме үнүнүн катуулугу"</item>
+    <item msgid="2311478519251301183">"Bluetooth үнү"</item>
+    <item msgid="5133991377896747027">"Ойгоо кармоо"</item>
+    <item msgid="2464189519136248621">"Жайгашкан жер"</item>
+    <item msgid="2062677934050803037">"Орду"</item>
+    <item msgid="1735171933192715957">"Колдонуу статистикасын алуу"</item>
+    <item msgid="1014093788778383554">"Микрофондун үнүн басуу/чыгаруу"</item>
+    <item msgid="4199297950608622850">"Эскертмени көрсөтүү"</item>
+    <item msgid="2527962435313398821">"Долбоор медиясы"</item>
+    <item msgid="5117506254221861929">"VPN\'ди жандыруу"</item>
+    <item msgid="8291198322681891160">"Тушкагаз жазуу"</item>
+    <item msgid="7106921284621230961">"Көмөкчү түзүм"</item>
+    <item msgid="4496533640894624799">"Көмөкчү скриншот"</item>
+    <item msgid="2598847264853993611">"Телефон абалын окуу"</item>
+    <item msgid="9215610846802973353">"Үн почтасын кошуу"</item>
+    <item msgid="9186411956086478261">"Sip пайдалануу"</item>
+    <item msgid="6884763100104539558">"Чыгуучу чалууну иштетүү"</item>
+    <item msgid="125513972170580692">"Манжа изи"</item>
+    <item msgid="2556071024281275619">"Дене сенсорлору"</item>
+    <item msgid="617168514928339387">"Калкка кабар берүү тутумунун билдирүүлөрүн окуу"</item>
+    <item msgid="7134693570516523585">"Жайгашкан жер дайындарын бурмалоо"</item>
+    <item msgid="7224489175375229399">"Сактагычтагы дайындарды окуу"</item>
+    <item msgid="8472735063903258202">"Сактагычка дайындарды жазуу"</item>
+    <item msgid="4069276819909595110">"Экранды күйгүзүү"</item>
+    <item msgid="1228338896751121025">"Аккаунттарды алуу"</item>
+    <item msgid="3181581793459233672">"Фондо ойнотуу"</item>
+    <item msgid="2340936043025374076">"Атайын мүмкүнчүлүктөрдүн үнүнүн катуулугу"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Кыска"</item>
     <item msgid="4816511817309094890">"Орто"</item>
@@ -247,7 +369,13 @@
     <item msgid="4627069151979553527">"Жантык"</item>
     <item msgid="6896773537705206194">"Кичине баш тамгалар"</item>
   </string-array>
-    <!-- no translation found for captioning_font_size_selector_titles:3 (2784236342175159295) -->
+  <string-array name="captioning_font_size_selector_titles">
+    <item msgid="1680223634161592855">"Өтө кичине"</item>
+    <item msgid="5091603983404027034">"Кичине"</item>
+    <item msgid="176844712416932112">"Кадимки"</item>
+    <item msgid="2784236342175159295">"Чоң"</item>
+    <item msgid="218913203203160606">"Өтө чоң"</item>
+  </string-array>
   <string-array name="captioning_edge_type_selector_titles">
     <item msgid="3865198759294188069">"Демейки"</item>
     <item msgid="6488643537808152001">"Эчтеке жок"</item>
@@ -262,7 +390,14 @@
     <item msgid="1874668269931014581">"75%"</item>
     <item msgid="6462911487571123954">"100%"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"Колдонмонун демейкилерин колдонуу"</item>
+    <item msgid="8611890312638868524">"Ак карада"</item>
+    <item msgid="5891360837786277638">"Кара акта"</item>
+    <item msgid="2798457065945456853">"Сары карада"</item>
+    <item msgid="5799049811524553967">"Сары көктө"</item>
+    <item msgid="3673930830658169860">"Ыңгайлаштырылган"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"PPTP VPN"</item>
     <item msgid="1349760781118368659">"Алдын ала бөлүшүлгөн ачкычтары бар L2TP/IPSec VPN"</item>
@@ -273,17 +408,34 @@
   </string-array>
   <string-array name="vpn_proxy_settings">
     <item msgid="2958623927055120839">"Эч нерсе жок"</item>
-    <item msgid="1157046369795346308">"Нускама"</item>
+    <item msgid="1157046369795346308">"Кол менен"</item>
   </string-array>
-    <!-- no translation found for vpn_states:4 (9135049670787351881) -->
+  <string-array name="vpn_states">
+    <item msgid="5408915841694583740">"Ажыратылган"</item>
+    <item msgid="8754480102834556765">"Демилгеленүүдө…"</item>
+    <item msgid="3351334355574270250">"Туташууда…"</item>
+    <item msgid="8303882153995748352">"Туташты"</item>
+    <item msgid="9135049670787351881">"Таймаут"</item>
+    <item msgid="2124868417182583926">"Ийгиликсиз"</item>
+  </string-array>
   <string-array name="security_settings_premium_sms_values">
     <item msgid="1164265643455394443">"Суроо"</item>
     <item msgid="7718817231348607934">"Эч качан уруксат жок"</item>
     <item msgid="8184570120217958741">"Дайым уруксат"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Орточо"</item>
+    <item msgid="5101233285497327432">"Орточо"</item>
+    <item msgid="1555861583162930714">"Төмөн"</item>
+    <item msgid="1719683776264798117">"Кескин"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Кадимки"</item>
+    <item msgid="6107138933849816768">"Орточо"</item>
+    <item msgid="182695359839047859">"Төмөн"</item>
+    <item msgid="8577246509202964244">"Кескин"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Туруктуу"</item>
     <item msgid="167418068739176448">"Көп аткарылган иш"</item>
@@ -325,7 +477,7 @@
     <item msgid="1008268820118852416">"Ченелбейт"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
-    <item msgid="6545683814310036454">"Демейки (туш келди MAC дарегин колдонуу)"</item>
+    <item msgid="6545683814310036454">"Туш келди MAC дарек колдонулат (демейки)"</item>
     <item msgid="214234417308375326">"MAC түзмөгүн колдонуу"</item>
   </string-array>
   <string-array name="wifi_hidden_entries">
@@ -338,7 +490,7 @@
   </string-array>
   <string-array name="autofill_logging_level_entries">
     <item msgid="6882729786516723474">"Өчүк"</item>
-    <item msgid="4072198137051566919">"Мүчүлүштүктөрдү оңдоо"</item>
+    <item msgid="4072198137051566919">"Мүчүлүштүктөрдү аныктоо"</item>
     <item msgid="2473005316958868509">"Оозеки кирүү"</item>
   </string-array>
   <string-array name="cdma_system_select_choices">
diff --git a/tests/CarDeveloperOptions/res/values-ky/config.xml b/tests/CarDeveloperOptions/res/values-ky/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-ky/config.xml
+++ b/tests/CarDeveloperOptions/res/values-ky/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-ky/strings.xml b/tests/CarDeveloperOptions/res/values-ky/strings.xml
index 4d00850..d694743 100644
--- a/tests/CarDeveloperOptions/res/values-ky/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ky/strings.xml
@@ -27,7 +27,7 @@
       <item quantity="one">Сиздин иштеп чыгуучу болушуңузга <xliff:g id="STEP_COUNT_0">%1$d</xliff:g> кадам калды.</item>
     </plurals>
     <string name="show_dev_on" msgid="9075712234786224065">"Сиз өндүрүүчү болдуңуз!"</string>
-    <string name="show_dev_already" msgid="7665948832405148689">"Кереги жок, сиз өндүрүүчү болгонсуз."</string>
+    <string name="show_dev_already" msgid="7665948832405148689">"Кереги жок, сиз иштеп чыгуучусуз."</string>
     <string name="dev_settings_disabled_warning" msgid="3198732189395396721">"Алгач иштеп чыгуучунун параметрлерин иштетиңиз"</string>
     <string name="header_category_wireless_networks" msgid="8968405993937795898">"Зымсыз тармактар"</string>
     <string name="header_category_system" msgid="4045988717359334410">"Тутум"</string>
@@ -113,7 +113,7 @@
     <string name="bluetooth_disconnect_all_profiles" product="device" msgid="4707569949253450208">"Түзмөгүңүз <xliff:g id="DEVICE_NAME">%1$s</xliff:g> түзмөгүнөн ажыратылат."</string>
     <string name="bluetooth_disconnect_dialog_ok" msgid="4183522987246110145">"Ажыратуу"</string>
     <string name="bluetooth_empty_list_user_restricted" msgid="3616298363281495777">"Bluetooth жөндөөлөрүн өзгөртүүгө уруксатыңыз жок."</string>
-    <string name="bluetooth_pairing_pref_title" msgid="2904954138013884029">"Жаңы түзмөктү жупташтыруу"</string>
+    <string name="bluetooth_pairing_pref_title" msgid="2904954138013884029">"Жаңы түзмөк кошуу"</string>
     <string name="bluetooth_is_visible_message" msgid="6341088682252805612">"Bluetooth жөндөөлөрү ачылып турганда <xliff:g id="DEVICE_NAME">%1$s</xliff:g> жакын арадагы түзмөктөргө көрүнөт."</string>
     <string name="bluetooth_footer_mac_message" product="default" msgid="335341476746836260">"Телефондун Bluetooth дареги: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
     <string name="bluetooth_footer_mac_message" product="tablet" msgid="6033609611245782463">"Планшеттин Bluetooth дареги: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
@@ -127,7 +127,7 @@
     <string name="bluetooth_notif_title" msgid="5090288898529286011">"Жупташтыруу өтүнүчү"</string>
     <string name="bluetooth_notif_message" msgid="6612367890895077938">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> менен жупташуу үчүн таптап коюңуз."</string>
     <string name="bluetooth_show_received_files" msgid="5060846395852236652">"Алынган файлдар"</string>
-    <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"Bluetooth аркылуу кабыл алынган файлдар"</string>
+    <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"Bluetooth аркылуу алынган файлдар"</string>
     <string name="device_picker" msgid="8345264486071697705">"Bluetooth түзмөгүн тандоо"</string>
     <string name="bluetooth_ask_enablement" msgid="8716802066127746062">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу Bluetooth\'ду күйгүзгөнү жатат"</string>
     <string name="bluetooth_ask_disablement" msgid="7125319551097350783">"<xliff:g id="APP_NAME">%1$s</xliff:g> бул түзмөктө Bluetooth\'ду өчүргөнү жатат"</string>
@@ -165,14 +165,14 @@
     <string name="bluetooth_device_name_summary" msgid="8661066392056595005">"Башка түзмөктөргө \"<xliff:g id="DEVICE_NAME">^1</xliff:g>\" деп көрүнөт"</string>
     <string name="bluetooth_off_footer" msgid="7658444560543730571">"Башка түзмөктөргө туташуу үчүн Bluetooth\'ду күйгүзүңүз."</string>
     <string name="bluetooth_paired_device_title" msgid="8361860197780425286">"Түзмөктөрүңүз"</string>
-    <string name="bluetooth_pairing_page_title" msgid="9053463656712597709">"Жаңы түзмөктү жупташтыруу"</string>
+    <string name="bluetooth_pairing_page_title" msgid="9053463656712597709">"Жаңы түзмөктү байланыштыруу"</string>
     <string name="bluetooth_pref_summary" product="tablet" msgid="3601662966604648212">"Планшетиңизге жакын жердеги Bluetooth түзмөктөрү менен байланышууга уруксат бериңиз"</string>
     <string name="bluetooth_pref_summary" product="device" msgid="2286727776570956969">"Түзмөгүңүзгө жакын жердеги Bluetooth түзмөктөрү менен байланышууга уруксат бериңиз"</string>
     <string name="bluetooth_pref_summary" product="default" msgid="863659221858781186">"Телефонуңузду жакын жердеги Bluetooth түзмөктөрүнө байланыштырат."</string>
     <string name="bluetooth_disable_a2dp_hw_offload" msgid="293429878480958234">"Bluetooth A2DP программасын кайра баштоону өчүрүү"</string>
     <string name="bluetooth_disable_a2dp_hw_offload_dialog_title" msgid="7362106962085861626">"Түзмөк өчүп күйсүнбү?"</string>
     <string name="bluetooth_disable_a2dp_hw_offload_dialog_message" msgid="4837282201316413412">"Бул жөндөөнү өзгөртүү үчүн түзмөгүңүздү өчүрүп күйгүзүңүз."</string>
-    <string name="bluetooth_disable_a2dp_hw_offload_dialog_confirm" msgid="9066883770039735632">"Кайра баштоо"</string>
+    <string name="bluetooth_disable_a2dp_hw_offload_dialog_confirm" msgid="9066883770039735632">"Өчүрүп күйгүзүү"</string>
     <string name="bluetooth_disable_a2dp_hw_offload_dialog_cancel" msgid="116355977067301404">"Жок"</string>
     <string name="connected_device_available_media_title" msgid="9126345752002774342">"Жеткиликтүү медиа түзмөктөрү"</string>
     <string name="connected_device_available_call_title" msgid="6774859446815858428">"Жеткиликтүү чалуу түзмөктөрү"</string>
@@ -180,7 +180,7 @@
     <string name="connected_device_saved_title" msgid="8270136893488475163">"Сакталган түзмөктөр"</string>
     <string name="connected_device_add_device_summary" msgid="7960491471270158891">"Bluetooth жупташтыруу үчүн күйгүзүлөт"</string>
     <string name="connected_device_connections_title" msgid="9205000271382018428">"Туташуу параметрлери"</string>
-    <string name="connected_device_previously_connected_title" msgid="225918223397410428">"Мурунтан туташкан түзмөктөр"</string>
+    <string name="connected_device_previously_connected_title" msgid="225918223397410428">"Буга чейин туташкан түзмөктөр"</string>
     <string name="connected_device_previously_connected_screen_title" msgid="2018789662358162716">"Мурда туташкан"</string>
     <string name="connected_device_bluetooth_turned_on_toast" msgid="4652326177920814476">"Bluetooth күйгүзүлдү"</string>
     <string name="previous_connected_see_all" msgid="7237095013087310923">"Баарын көрүү"</string>
@@ -207,7 +207,7 @@
     <string name="proxy_error_empty_port" msgid="8034561724923076215">"Сиз порттун талаасын толтурушуңуз керек."</string>
     <string name="proxy_error_empty_host_set_port" msgid="8471455809508588255">"Эгер хост талаасы бош болсо, оюкча талаасы да бош болуусу зарыл."</string>
     <string name="proxy_error_invalid_port" msgid="4046559920586100637">"Сиз терген порт жараксыз."</string>
-    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"HTTP прокси серепчи тарабынан колдонулат, бирок башка колдонмолор пайдалана алышпайт."</string>
+    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"HTTP прокси серверин серепчи гана колдонот."</string>
     <string name="proxy_url_title" msgid="882042361706435904">"PAC URL: "</string>
     <string name="radio_info_dl_kbps" msgid="2903778264453410272">"DL өткөрүү жөндөмдүүлүгү (кб/сек.):"</string>
     <string name="radio_info_ul_kbps" msgid="3802245899811732716">"UL өткөрүү жөндөмдүүлүгү (кб/сек.):"</string>
@@ -309,8 +309,8 @@
     <string name="cellular_data_summary" msgid="8817717603450318646">"Дайындар моб. тармак аркылуу өткөрүлсүн"</string>
     <string name="allow_data_usage_title" msgid="5381624105803294315">"Роуминг учурунда дайындарды пайдаланууга уруксат берүү"</string>
     <string name="roaming" msgid="8860308342135146004">"Роуминг"</string>
-    <string name="roaming_enable" msgid="2108142024297441116">"Роуминг учурунда мобилдик Интернетке туташат"</string>
-    <string name="roaming_disable" msgid="1915440242079953809">"Роуминг учурунда мобилдик Интернетке туташат"</string>
+    <string name="roaming_enable" msgid="2108142024297441116">"Роуминг учурунда дайын-даректерди өткөрүүчү кызматтарга туташуу"</string>
+    <string name="roaming_disable" msgid="1915440242079953809">"Роуминг учурунда дайын-даректерди өткөрүүчү кызматтарга туташуу"</string>
     <string name="roaming_reenable_message" msgid="8388505868655113258">"Жергиликтүү тармагыңыздан интернет-роуминг өчүрүлгөн абалда кеткендиктен Интернет туташуусун жоготтуңуз."</string>
     <string name="roaming_turn_it_on_button" msgid="4370846458830537578">"Аны күйгүзүү"</string>
     <string name="roaming_warning" msgid="5488050911277592868">"Бир топ чыгымдарга дуушар болуп калышыңыз мүмкүн."</string>
@@ -324,7 +324,7 @@
     <string name="date_and_time_settings_summary" msgid="4617979434474713417">"Датаны, убакытты, саат алкагын, жана форматтарды тууралоо"</string>
     <string name="date_time_auto" msgid="2679132152303750218">"Тармактын убакыты колдонулсун"</string>
     <string name="zone_auto_title" msgid="5500880975376882488">"Тармактын убакыт алкагы колдонулсун"</string>
-    <string name="date_time_24hour_auto" msgid="7499659679134962547">"Демейки жергиликтүү формат колдонулат"</string>
+    <string name="date_time_24hour_auto" msgid="7499659679134962547">"Демейки жергиликтүү форматты колдонуу"</string>
     <string name="date_time_24hour_title" msgid="6209923858891621283">"24 сааттык формат"</string>
     <string name="date_time_24hour" msgid="1265706705061608742">"24 сааттык форматты колдонуу"</string>
     <string name="date_time_set_time_title" msgid="7116850506333406367">"Убакыт"</string>
@@ -368,7 +368,7 @@
     <string name="profile_info_settings_title" msgid="4855892878512562551">"Профилдин чоо-жайы"</string>
     <string name="Accounts_settings_title" msgid="7901374987121953746">"Аккаунттар"</string>
     <string name="location_settings_title" msgid="2707201457572301030">"Жайгашкан жер"</string>
-    <string name="location_settings_master_switch_title" msgid="3108016866082816733">"Кайда жүргөнүм аныкталып турсун"</string>
+    <string name="location_settings_master_switch_title" msgid="3108016866082816733">"Кайда жүргөнүм көрүнүп турсун"</string>
     <string name="location_settings_summary_location_off" msgid="5563530256978372978">"Өчүк"</string>
     <plurals name="location_settings_summary_location_on" formatted="false" msgid="7893342914540884818">
       <item quantity="other">Күйүк - <xliff:g id="COUNT_1">%1$d</xliff:g> жайгашкан жерди көрө алат</item>
@@ -402,7 +402,7 @@
     <string name="security_settings_face_enroll_introduction_title" msgid="6073249653318265486">"Кулпуну жүзүңүз менен ачасыз"</string>
     <string name="security_settings_face_enroll_introduction_title_unlock_disabled" msgid="9223270521083202896">"Жүзүңүз менен аныктыгыңызды текшертиңиз"</string>
     <string name="security_settings_face_enroll_introduction_message" msgid="484806903869220184">"Телефонуңуздун кулпусун ачып, сатып алууга уруксат берип же колдонмолорго кирүү үчүн жүзүңүздү көрсөтүңүз."</string>
-    <string name="security_settings_face_enroll_introduction_message_unlock_disabled" msgid="2850101281254663082">"Телефонуңуздун кулпусун ачуу же сатып алууларды ырастоо үчүн жүзүңүздү пайдаланыңыз.\n\nЭскертүү: Жүзүңүздү бул түзмөктүн кулпусун ачууга колдоно албайсыз. Кеңири маалымат үчүн ишканаңыздын администраторуна кайрылыңыз."</string>
+    <string name="security_settings_face_enroll_introduction_message_unlock_disabled" msgid="2850101281254663082">"Жүзүнөн таануу функциясы аркылуу телефонуңуздун кулпусун ачып, ар кандай нерселерди сатып ала аласыз.\n\nЭскертүү: Бул түзмөктүн кулпусун жүзүнөн таануу функциясы менен ачууга болбойт. Кененирээк маалымат алгыңыз келсе, ишканаңыздын администраторуна кайрылыңыз."</string>
     <string name="security_settings_face_enroll_introduction_message_setup" msgid="4533297059466270074">"Телефонуңуздун кулпусун ачып, сатып алууга уруксат берип же колдонмолорго кирүү үчүн жүзүңүздү көрсөтүңүз."</string>
     <string name="security_settings_face_enroll_introduction_footer_message" msgid="7764021721107723266"></string>
     <string name="security_settings_face_enroll_repeat_title" msgid="2507710348140837875">"Жүзүңүздү тегеректин борборуна жайгаштырыңыз"</string>
@@ -425,7 +425,7 @@
     <string name="security_settings_face_settings_require_confirmation_details" msgid="8740564864091803429">"Колдонмодо аутентификациядан өткөндө, ар дайым ырастоо талап кылынсын"</string>
     <string name="security_settings_face_settings_remove_face_data" msgid="2821359954483136239">"Жүздү өчүрүү"</string>
     <string name="security_settings_face_settings_footer" msgid="4627175759990550715">"Түзмөгүңүздүн кулпусун жүзүңүздү көрсөтүп ачып, колдонмолорго киресиз. "<annotation id="url">"Кеңири маалымат"</annotation></string>
-    <string name="security_settings_face_settings_remove_dialog_title" msgid="5675319895815271094">"Жүзүңүздү таануу дайындарын өчүрөсүзбү?"</string>
+    <string name="security_settings_face_settings_remove_dialog_title" msgid="5675319895815271094">"Бул функциянын дайындарын өчүрөсүзбү?"</string>
     <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"Жүзүнөн таануу функциясын колдонууда топтолгон дайын-даректер биротоло өчүрүлөт. Өчүрүлгөндөн кийин, телефонуңуздун кулпусун ачып, колдонмолорго кирип жана төлөмдөрдү ырастоо үчүн, PIN кодуңуз, графикалык ачкычыңыз же сырсөзүңүз суралат."</string>
     <string name="security_settings_fingerprint_preference_title" msgid="4177132225930582928">"Манжа изи"</string>
     <string name="fingerprint_manage_category_title" msgid="1463406696801542090">"Манжа издерин башкаруу"</string>
@@ -440,14 +440,14 @@
     <string name="security_settings_fingerprint_enroll_introduction_title" msgid="889558002683900544">"Кулпну манж из менн ач"</string>
     <string name="security_settings_fingerprint_enroll_introduction_title_unlock_disabled" msgid="7915504118657864429">"Манжа изиңизди колдонуңуз"</string>
     <string name="security_settings_fingerprint_enroll_introduction_message" msgid="5586198131986682472">"Телефонуңуздун кулпусун ачып, кандайдыр бир нерсени сатып алып жатканыңызды ырастап же колдонмолорго кирүү үчүн жөн гана манжаңызды сенсорго тийгизип коюңуз. Кимдир-бирөөнүн манжа изин кошуп жатканыңызда этият болуңуз. Бир эле манжа изи кошулса да, ушул нерселердин баарын аткара алат.\n\nТүзмөгүңүздү манжа изи менен коргоого караганда графикалык ачкыч же PIN код менен коргоо бир кыйла коопсуз."</string>
-    <string name="security_settings_fingerprint_enroll_introduction_message_unlock_disabled" msgid="1640839304679275468">"Телефонуңуздун кулпусун ачуу же сатып алууларды ырастоо үчүн манжа изиңизди пайдаланыңыз.\n\nЭскертүү: Манжа изиңизди бул түзмөктүн кулпусун ачууга колдоно албайсыз. Кеңири маалымат үчүн ишканаңыздын администраторуна кайрылыңыз."</string>
-    <string name="security_settings_fingerprint_enroll_introduction_message_setup" msgid="6734490666593320711">"Телефонуңуздун кулпусун ачуу же сатып алууларды ырастоо үчүн манжа изиңизди пайдаланыңыз.\n\nЭскертүү: Түзмөгүңүздү манжа изи менен коргоого караганда графикалык ачкыч же PIN код менен коргоо бир кыйла коопсуз."</string>
+    <string name="security_settings_fingerprint_enroll_introduction_message_unlock_disabled" msgid="1640839304679275468">"Манжаңыздын изи менен, телефонуңуздун кулпусун ачып, ар кандай нерселерди сатып ала аласыз.\n\nЭскертүү: Бул түзмөктүн кулпусун манжаңыздын изи менен ачууга болбойт. Кененирээк маалымат алгыңыз келсе, ишканаңыздын администраторуна кайрылыңыз."</string>
+    <string name="security_settings_fingerprint_enroll_introduction_message_setup" msgid="6734490666593320711">"Манжаңызды коюп экранды ачып, ар кандай нерселерди сатып ала аласыз.\n\nЭскертүү: Түзмөгүңүздү манжа изи менен коргоого караганда, графикалык ачкыч же PIN код менен коргоо бир кыйла коопсуз."</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel" msgid="9168637333731599827">"Жокко чыгаруу"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue" msgid="271662150372486535">"Улантуу"</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel_setup" msgid="756928427429893070">"Өткөрүп жиберүү"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue_setup" msgid="4125977169169671144">"Кийинки"</string>
-    <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"Манжа изин жөндөбөйсүзбү?"</string>
-    <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"Манжа изин жөндөө бир-эки эле мүнөткө созулат. Азыр өткөрүп жиберсеңиз, манжа изиңизди кийинчерээк кошсоңуз болот."</string>
+    <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"Манжа издерин койбойсузбу?"</string>
+    <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"Манжаңыздын изин бир-эки мүнөттүн ичинде эле коесуз. Азыр койгуңуз келбесе, кийинчерээк кошуп койсоңуз болот."</string>
     <string name="lock_screen_intro_skip_title" msgid="5307431665496346914">"Экран кулпусун жөндөбөйсүзбү?"</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="tablet" msgid="7553945981266845264">"Түзмөктү коргоо мүмкүнчүлүктөрү жандырылбайт. Эгер планшет жоголуп же уурдалып кетсе, же баштапкы абалга келтирилсе, башкалар аны пайдалана беришет."</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="device" msgid="1378243257238015603">"Түзмөктү коргоо мүмкүнчүлүктөрү жандырылбайт. Эгер түзмөк жоголуп же уурдалып кетсе, же баштапкы абалга келтирилсе, башкалар аны пайдалана беришет."</string>
@@ -468,7 +468,7 @@
     <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"Сенсорго тийиңиз"</string>
     <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Манжаңызды сенсорго коюп, дирилдегенин сезгенден кийин көтөрүңүз"</string>
     <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"Көтөрүп, кайра тийип коюңуз"</string>
-    <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Манжа изиңиздин ар кайсы бөлүгүн кошуу үчүн манжаңызды кичинеден өйдө жылдырыңыз"</string>
+    <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Манжаңызды толугу менен скандоо үчүн, акырындык менен жылдырыңыз."</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"Манжа изи кошулду"</string>
     <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"Бул сүрөтчө көрүнгөндө, манжаңыздын изи менен өздүгүңүздү же кандайдыр бир нерсени сатып алууну ырастайсыз"</string>
     <string name="security_settings_fingerprint_enroll_enrolling_skip" msgid="1473280156532146933">"Азыр эмес"</string>
@@ -476,10 +476,10 @@
     <string name="setup_fingerprint_enroll_enrolling_skip_message" msgid="8139299964344809780">"Телефонуңуздун кулпусун манжа изи менен ачуу ыкмасын тандадыңыз. Эгер азыр өткөрүп жиберсеңиз, аны кийинчерээк жөндөшүңүз керек болот. Жөндөөгө бир мүнөтчө эле убакыт кетет."</string>
     <string name="fingerprint_lock_screen_setup_skip_dialog_text" product="tablet" msgid="1384438077720821127">"Планшетиңизди экранды бөгөттөө опциясы менен коргоңуз, ошондо ал жоголсо же бирөө уурдап кетсе, эч ким колдоно албай калат. Экранды бөгөттөө функциясы менен манжа изин жөндөсөңүз да болот. \"Жокко чыгарууну\" таптаңыз, анан PIN кодду жөндөңүз же экранды бөгөттөөнүн башка опциясын тандаңыз."</string>
     <string name="fingerprint_lock_screen_setup_skip_dialog_text" product="device" msgid="7207112623501771824">"Түзмөгүңүздү экранды бөгөттөө опциясы менен коргоңуз, ошондо ал жоголсо же бирөө уурдап кетсе, эч ким колдоно албай калат. Экранды бөгөттөө функциясы менен манжа изин жөндөсөңүз да болот. \"Жокко чыгарууну\" таптаңыз, анан PIN кодду жөндөңүз же экранды бөгөттөөнүн башка опциясын тандаңыз."</string>
-    <string name="fingerprint_lock_screen_setup_skip_dialog_text" product="default" msgid="7623975730623531606">"Телефонуңузду экранды бөгөттөө опциясы менен коргоңуз, ошондо ал жоголсо же бирөө уурдап кетсе, эч ким колдоно албай калат. Экранды бөгөттөө функциясы менен манжа изин жөндөсөңүз да болот. \"Жокко чыгарууну\" таптаңыз, анан PIN кодду жөндөңүз же экранды бөгөттөөнүн башка опциясын тандаңыз."</string>
+    <string name="fingerprint_lock_screen_setup_skip_dialog_text" product="default" msgid="7623975730623531606">"Манжа изинин сканерин жөндөө үчүн, телефондун экранын кулпулоону иштетүү керек. Ушуну менен, телефонуңуз жоголуп же бирөө уурдап кетсе, анын ичиндегилерди эч ким көрө албай калат. Экранды кулпулоо функциясын иштетүү үчүн, \"Жок\" дегенди басып, андан соң PIN код коюңуз же экранды кулпулоонун башка ыкмасын тандаңыз."</string>
     <string name="face_lock_screen_setup_skip_dialog_text" product="tablet" msgid="2998863111689476550">"Планшетиңизди экранды бөгөттөө опциясы менен коргоңуз, ошондо ал жоголсо же бирөө уурдап кетсе, эч ким колдоно албай калат. Экранды бөгөттөө функциясы менен жүздүн аныктыгын текшерүүнү жөндөсөңүз да болот. \"Жокко чыгарууну\" таптаңыз, анан PIN кодду жөндөңүз же экранды бөгөттөөнүн башка опциясын тандаңыз."</string>
     <string name="face_lock_screen_setup_skip_dialog_text" product="device" msgid="6780557259734235952">"Түзмөгүңүздү экранды бөгөттөө опциясы менен коргоңуз, ошондо ал жоголсо же бирөө уурдап кетсе, эч ким колдоно албай калат. Экранды бөгөттөө функциясы менен жүздүн аныктыгын текшерүүнү жөндөсөңүз да болот. \"Жокко чыгарууну\" таптаңыз, анан PIN кодду жөндөңүз же экранды бөгөттөөнүн башка опциясын тандаңыз."</string>
-    <string name="face_lock_screen_setup_skip_dialog_text" product="default" msgid="8541640018478926775">"Телефонуңузду экранды бөгөттөө опциясы менен коргоңуз, ошондо ал жоголсо же бирөө уурдап кетсе, эч ким колдоно албай калат. Экранды бөгөттөө функциясы менен жүздүн аныктыгын текшерүүнү жөндөсөңүз да болот. \"Жокко чыгарууну\" таптаңыз, анан PIN кодду жөндөңүз же экранды бөгөттөөнүн башка опциясын тандаңыз."</string>
+    <string name="face_lock_screen_setup_skip_dialog_text" product="default" msgid="8541640018478926775">"Жүзүнөн таанып ачуу функциясын жөндөө үчүн, телефондун экранын кулпулоону иштетүү керек. Ушуну менен, телефонуңуз жоголуп же бирөө уурдап кетсе, анын ичиндегилерди эч ким көрө албай калат. Экранды кулпулоо функциясын иштетүү үчүн, \"Жок\" дегенди басып, андан соң PIN код коюңуз же экранды кулпулоонун башка ыкмасын тандаңыз."</string>
     <string name="lock_screen_pin_skip_title" msgid="8217519439213393785">"PIN кодду жөндөөнү өткөрүп жибересизби?"</string>
     <string name="lock_screen_password_skip_title" msgid="3725788215672959827">"Сырсөздү жөндөөнү өткөрүп жибересизби?"</string>
     <string name="lock_screen_pattern_skip_title" msgid="4237030500353932005">"Графикалык ачкычты жөндөөнү өткөрүп жибересизби?"</string>
@@ -494,14 +494,14 @@
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"Кийинки"</string>
     <string name="security_settings_fingerprint_enroll_disclaimer" msgid="5831834311961551423">"Телефонуңуздун кулпусун ачуу, ар кандай нерселерди сатып алуу жана колдонмолорду ачуу үчүн, манжа изиңизди кошуп коюңуз. "<annotation id="url">"Көбүрөөк билүү"</annotation></string>
     <string name="security_settings_fingerprint_enroll_disclaimer_lockscreen_disabled" msgid="7954742554236652690">" Экранды кулпулоо параметри өчүрүлгөн. Көбүрөөк маалымат үчүн ишканаңыздын администраторуна кайрылыңыз. "<annotation id="admin_details">"Кошумча маалымат"</annotation>\n\n"Манжа изиңиз аркылуу сатып алууларга уруксат берип жана колдонмолорго кире берсеңиз болот. "<annotation id="url">"Көбүрөөк маалымат"</annotation></string>
-    <string name="security_settings_fingerprint_enroll_lift_touch_again" msgid="1670703069782212223">"Манжаңызды көтөрүп, сенсорго кайра тийип коюңуз"</string>
+    <string name="security_settings_fingerprint_enroll_lift_touch_again" msgid="1670703069782212223">"Манжаңызды көтөрүп, кайра сенсорго тийгизиңиз"</string>
     <string name="fingerprint_add_max" msgid="2939393314646115661">"<xliff:g id="COUNT">%d</xliff:g> чейин манжа изин кошсоңуз болот"</string>
     <string name="fingerprint_intro_error_max" msgid="3247720976621039437">"Кошулган манжа издеринин саны жогорку чегине жетти"</string>
     <string name="fingerprint_intro_error_unknown" msgid="3975674268256524015">"Дагы манжа издерин кошуу мүмкүн эмес"</string>
     <string name="fingerprint_last_delete_title" msgid="3104596858161269635">"Манжа издерин өчүрөсүзбү?"</string>
     <string name="fingerprint_delete_title" msgid="3120894112324235536">"\"<xliff:g id="FINGERPRINT_ID">%1$s</xliff:g>\" манжа изин алып салуу"</string>
     <string name="fingerprint_delete_message" msgid="5895802741486967970">"Бул манжа изин өчүрөсүзбү?"</string>
-    <string name="fingerprint_last_delete_message" msgid="3346252479778971442">"Телефонуңуздун кулпусун ачып, сатып алууга уруксат берип же колдонмолорго кирүү үчүн манжа издерин башка колдоно албай каласыз"</string>
+    <string name="fingerprint_last_delete_message" msgid="3346252479778971442">"Манжаңыздын изи менен экранды ачып, кандайдыр бир нерсе сатып алып же колдонмолорго уруксат бере албай каласыз"</string>
     <string name="fingerprint_last_delete_message_profile_challenge" msgid="5385095150532247025">"Жумуш профилиңиздин кулпусун ачып, сатып алууга уруксат берип же жумуштагы колдонмолорго кирүү үчүн манжа издерин башка колдоно албай каласыз"</string>
     <string name="fingerprint_last_delete_confirm" msgid="7984595457589664004">"Ооба, өчүрөм"</string>
     <string name="crypt_keeper_settings_title" msgid="839783588093862748">"Шифрлөө"</string>
@@ -548,7 +548,7 @@
     <string name="setup_lock_settings_picker_title" product="tablet" msgid="2429667472335773519">"Планшетиңизди коргоңуз"</string>
     <string name="setup_lock_settings_picker_title" product="device" msgid="4739290104106645233">"Түзмөгүңүздү коргоңуз"</string>
     <string name="setup_lock_settings_picker_title" product="default" msgid="3911582328576859628">"Телефонуңузду коргоңуз"</string>
-    <string name="lock_settings_picker_biometrics_added_security_message" msgid="799453282539387294">"Кошумча коопсуздук үчүн көмөкчү экран кулпусун коюп алыңыз"</string>
+    <string name="lock_settings_picker_biometrics_added_security_message" msgid="799453282539387294">"Бекемирээк коргоо үчүн, экранды дагы бир ыкма менен кулпулаңыз"</string>
     <string name="setup_lock_settings_picker_message" product="tablet" msgid="7230799135599877804">"Түзмөктү коргоо функциялары жандырылганда, башкалар бул планшетти сиздин уруксатыңызсыз пайдалана албай калышат. Колдонгуңуз келген экран кулпусун тандаңыз."</string>
     <string name="setup_lock_settings_picker_message" product="device" msgid="2098404520816295371">"Түзмөктү коргоо функциялары жандырылганда, башкалар бул түзмөктү сиздин уруксатыңызсыз пайдалана албай калышат. Колдонгуңуз келген экран кулпусун тандаңыз."</string>
     <string name="setup_lock_settings_picker_message" product="default" msgid="2003984443953672040">"Түзмөктү коргоо функциялары жандырылганда, башкалар бул телефонду сиздин уруксатыңызсыз пайдалана албай калышат. Колдонгуңуз келген экран кулпусун тандаңыз."</string>
@@ -646,9 +646,9 @@
     <string name="lock_last_pattern_attempt_before_wipe_profile" msgid="3877613047631174576">"Эгер графикалык ачкычты кийинки жолу туура эмес киргизсеңиз, жумуш профилиңиз жана анын дайындары өчүрүлөт"</string>
     <string name="lock_last_pin_attempt_before_wipe_profile" msgid="8132438288175428168">"Эгер PIN кодду кийинки жолу туура эмес киргизсеңиз, жумуш профилиңиз жана анын дайындары өчүрүлөт"</string>
     <string name="lock_last_password_attempt_before_wipe_profile" msgid="1535128774464384305">"Эгер сырсөздү кийинки жолу туура эмес киргизсеңиз, жумуш профилиңиз жана анын дайындары өчүрүлөт"</string>
-    <string name="lock_failed_attempts_now_wiping_device" msgid="8662360098784762828">"Өтө көп жолу туура эмес аракет кылынды. Бул түзмөктүн дайындары өчүрүлөт."</string>
-    <string name="lock_failed_attempts_now_wiping_user" msgid="3793513796171561873">"Өтө көп жолу туура эмес аракет кылынды. Бул колдонуучу өчүрүлөт."</string>
-    <string name="lock_failed_attempts_now_wiping_profile" msgid="5347108525299038285">"Өтө көп жолу туура эмес аракет кылынды. Бул жумуш профили жана анын дайындары өчүрүлөт."</string>
+    <string name="lock_failed_attempts_now_wiping_device" msgid="8662360098784762828">"Өтө көп жолу жаңылдыңыз. Бул түзмөктүн дайындары өчүрүлөт."</string>
+    <string name="lock_failed_attempts_now_wiping_user" msgid="3793513796171561873">"Өтө көп жолу жаңылдыңыз. Бул колдонуучу өчүрүлөт."</string>
+    <string name="lock_failed_attempts_now_wiping_profile" msgid="5347108525299038285">"Өтө көп жолу жаңылдыңыз. Бул жумуш профили жана андагы нерселер өчүрүлөт."</string>
     <string name="lock_failed_attempts_now_wiping_dialog_dismiss" msgid="3950582268749037318">"Этибарга албоо"</string>
     <plurals name="lockpassword_password_too_short" formatted="false" msgid="694091983183310827">
       <item quantity="other">Кеминде <xliff:g id="COUNT_1">%d</xliff:g> символ болушу керек</item>
@@ -667,7 +667,6 @@
       <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> сандан ашпашы керек</item>
       <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> сандан ашпашы керек</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"0-9 сандарынан гана турушу керек"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Түзмөктүн администратору акыркы PIN кодду колдонууга тыюу салган"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Жөнөкөй PIN-коддорду коюу IT администраторуңуз тарабынан бөгөттөлгөн. Татаалыраак PIN-кодду коюп көрүңүз."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Бул жерде жараксыз белги камтылбашы керек"</string>
@@ -698,6 +697,10 @@
       <item quantity="other">Тамгадан башка кеминде <xliff:g id="COUNT">%d</xliff:g> белги болушу керек</item>
       <item quantity="one">Тамгадан башка кеминде 1 белги болушу керек</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Тамгадан башка кеминде <xliff:g id="COUNT">%d</xliff:g> сандык эмес символ болушу керек</item>
+      <item quantity="one">Тамгадан башка кеминде 1 сандык эмес символ болушу керек</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Түзмөктүн администратору акыркы сырсөздү колдонууга тыюу салган"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Жөнөкөй сырсөздөрү коюу IT администраторуңуз тарабынан бөгөттөлгөн. Татаалыраак сырсөздү коюп көрүңүз."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Сандар чоңойгон, кичирейген же кайталанган ыраатта болбошу керек"</string>
@@ -737,7 +740,7 @@
     <string name="bluetooth_confirm_passkey_msg" msgid="7094455604290076371">"Муну менен туташыш үчүн:&lt;br&gt;&lt;b&gt;<xliff:g id="DEVICE_NAME">%1$s</xliff:g>&lt;/b&gt;&lt;br&gt;&lt;br&gt;Ал бул кодду көрсөтүп жатканын текшериңиз:&lt;br&gt;&lt;b&gt;<xliff:g id="PASSKEY">%2$s</xliff:g>&lt;/b&gt;"</string>
     <string name="bluetooth_incoming_pairing_msg" msgid="940451919337185024">"Жөнөтүүчү:&lt;br&gt;&lt;b&gt;<xliff:g id="DEVICE_NAME">%1$s</xliff:g>&lt;/b&gt;&lt;br&gt;&lt;br&gt;Бул түзмөк менен туташсынбы?"</string>
     <string name="bluetooth_display_passkey_pin_msg" msgid="5909423849232791647">"Кийинки менен туташуу үчүн:<xliff:g id="BOLD1_0">&lt;br&gt;&lt;b&gt;</xliff:g><xliff:g id="DEVICE_NAME">%1$s</xliff:g><xliff:g id="END_BOLD1">&lt;/b&gt;&lt;br&gt;&lt;br&gt;</xliff:g>Андан муну терип:<xliff:g id="BOLD2_1">&lt;br&gt;&lt;b&gt;</xliff:g><xliff:g id="PASSKEY">%2$s</xliff:g><xliff:g id="END_BOLD2">&lt;/b&gt;</xliff:g>, Return же Enter\'ди басыңыз."</string>
-    <string name="bluetooth_pairing_shares_phonebook" msgid="7474404818877079813">"Байланыштар менен чалуулар таржымалын пайдалануу мүмкүнчүлүгү берилсин"</string>
+    <string name="bluetooth_pairing_shares_phonebook" msgid="7474404818877079813">"Байланыштар менен чалуулар таржымалына мүмкүнчүлүк берүү"</string>
     <string name="bluetooth_error_title" msgid="5718761586633101960"></string>
     <string name="bluetooth_connecting_error_message" msgid="8473359363469518478">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> менен байланыша албай жатат."</string>
     <string name="bluetooth_preference_scan_title" msgid="457781003962324807">"Түзмөктөрдү издөө"</string>
@@ -833,7 +836,7 @@
     <string name="wifi_quick_toggle_title" msgid="7935778388625246184">"Wi‑Fi"</string>
     <string name="wifi_quick_toggle_summary" msgid="2879870570547594266">"Wi‑Fi\'ды жандыруу"</string>
     <string name="wifi_settings" msgid="7486492317310514109">"Wi‑Fi"</string>
-    <string name="wifi_settings_master_switch_title" msgid="3917916944694253946">"Wi-Fi\'ды колдонуу"</string>
+    <string name="wifi_settings_master_switch_title" msgid="3917916944694253946">"Wi-Fi\'ды иштетүү"</string>
     <string name="wifi_settings_category" msgid="9094716747565527901">"Wi‑Fi тууралоолору"</string>
     <string name="wifi_settings_title" msgid="5265554991622344805">"Wi‑Fi"</string>
     <string name="wifi_settings_summary" msgid="7117267255799892820">"Зымсыз кошулуу түйүндөрүн орнотуу жана башкаруу"</string>
@@ -846,7 +849,7 @@
     <string name="wifi_notify_open_networks" msgid="4782239203624619655">"Ачык тармактар тууралуу билдирмелер"</string>
     <string name="wifi_notify_open_networks_summary" msgid="1383681260705466715">"Байланыш сигналы күчтүү жалпыга ачык тармактар жеткиликтүү болгондо эскертет"</string>
     <string name="wifi_wakeup" msgid="4963732992164721548">"Wi‑Fi автоматтык түрдө күйсүн"</string>
-    <string name="wifi_wakeup_summary" msgid="1152699417411690">"Байланыш сигналы күчтүү сакталган тармактарга (мисалы, үйүңүздөгү) жакындаганда, Wi‑Fi автоматтык түрдө күйөт"</string>
+    <string name="wifi_wakeup_summary" msgid="1152699417411690">"Сигналы күчтүү, сакталган тармактарга жакындаганда (мисалы, үйүңүздөгү), Wi‑Fi автоматтык түрдө күйөт"</string>
     <string name="wifi_wakeup_summary_no_location" msgid="3007457288587966962">"Жайгашкан жерди аныктоо мүмкүнчүлүгү өчүрүлгөндүктөн, жеткиликтүү эмес. "<annotation id="link">"Жайгашкан жерди"</annotation>" күйгүзүңүз."</string>
     <string name="wifi_wakeup_summary_scanning_disabled" msgid="6820040651529910914">"Wi‑Fi издөө функциясы өчүрүлгөндүктөн, бул опция иштебейт"</string>
     <string name="wifi_wakeup_summary_scoring_disabled" msgid="7067018832237903151">"Пайдалануу үчүн тармактын рейтингин камсыздоочуну тандаңыз"</string>
@@ -859,7 +862,7 @@
     <string name="use_open_wifi_automatically_summary_scorer_unsupported_disabled" msgid="1123080670578756834">"Пайдалануу үчүн шайкеш келген тармактын рейтингин камсыздоочуну тандаңыз"</string>
     <string name="wifi_install_credentials" msgid="5650088113710858289">"Тастыктамаларды орнотуу"</string>
     <string name="wifi_scan_notify_text" msgid="7614101215028336927">"Кайда жүргөнүңүздү тагыраак аныктоо үчүн, Wi‑Fi өчүп турса да, колдонмолор менен кызматтар зымсыз тармактарды издей беришет. Бул режим жайгашкан жерди аныктоо функцияларын жакшыртууга мүмкүнчүлүк берет. Аны <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>Wi-Fi тармактарын издөө жөндөөлөрүнөн<xliff:g id="LINK_END_1">LINK_END</xliff:g> өчүрүп койсоңуз болот."</string>
-    <string name="wifi_scan_notify_text_scanning_off" msgid="723796963816095410">"Кандайдыр бир жерди тагыраак аныктоо үчүн <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>издөө жөндөөлөрүнөн<xliff:g id="LINK_END_1">LINK_END</xliff:g> Wi-Fi издөө дегенди күйгүзүңүз."</string>
+    <string name="wifi_scan_notify_text_scanning_off" msgid="723796963816095410">"Кандайдыр бир жерди тагыраак аныктоо үчүн, <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>издөө жөндөөлөрүнөн<xliff:g id="LINK_END_1">LINK_END</xliff:g> Wi-Fi издөө дегенди күйгүзүңүз."</string>
     <string name="wifi_scan_notify_remember_choice" msgid="1235445971400237444">"Экинчи көргөзбө"</string>
     <string name="wifi_setting_sleep_policy_title" msgid="2120785188625932076">"Уктап жатканда Wi‑Fi иштей берсин"</string>
     <string name="wifi_setting_on_during_sleep_title" msgid="856670183023402715">"Уктап жатканда Wi‑Fi күйүк"</string>
@@ -872,7 +875,7 @@
     <string name="wifi_cellular_data_fallback_title" msgid="5067241930716252665">"Мобилдик дайындарга автоматтык түрдө которулсун"</string>
     <string name="wifi_cellular_data_fallback_summary" msgid="2721467405851519769">"Wi-Fi аркылуу Интернетке туташуу мүмкүнчүлүгү жок болгондо, мобилдик дайындар колдонулсун. Дайындардын колдонулгандыгы үчүн акы алынышы мүмкүн."</string>
     <string name="wifi_add_network" msgid="4094957940791876640">"Тармак кошуу"</string>
-    <string name="wifi_configure_settings_preference_title" msgid="2678534679408777268">"Wi‑Fi жеке жөндөөлөрү"</string>
+    <string name="wifi_configure_settings_preference_title" msgid="2678534679408777268">"Wi‑Fi жөндөөлөрү"</string>
     <string name="wifi_configure_settings_preference_summary_wakeup_on" msgid="5714892572614655675">"Wi‑Fi тармагы автоматтык түрдө өзү күйөт"</string>
     <string name="wifi_configure_settings_preference_summary_wakeup_off" msgid="286904094152909651">"Wi‑Fi тармагы автоматтык түрдө күйбөйт"</string>
     <string name="wifi_access_points" msgid="1647976498906871869">"Wi‑Fi түйүндөрү"</string>
@@ -885,7 +888,7 @@
     <string name="wifi_menu_remember" msgid="717257200269700641">"Тармакты эстеп калуу"</string>
     <string name="wifi_menu_forget" msgid="7561140554450163075">"Тармак унутулсун"</string>
     <string name="wifi_menu_modify" msgid="4080178040721021101">"Тармакты өзгөртүү"</string>
-    <string name="wifi_empty_list_wifi_off" msgid="272877164691346240">"Жеткиликтүү тармактарды көрүү үчүн Wi‑Fi\'ды иштетиңиз."</string>
+    <string name="wifi_empty_list_wifi_off" msgid="272877164691346240">"Жеткиликтүү тармактарды көрүү үчүн, Wi‑Fi\'ды иштетиңиз."</string>
     <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"Wi‑Fi түйүндөрү изделүүдө…"</string>
     <string name="wifi_empty_list_user_restricted" msgid="2341613007817352431">"Wi‑Fi түйүнүн алмаштырууга урукатыңыз жок."</string>
     <string name="wifi_more" msgid="3538241640407382185">"Дагы"</string>
@@ -902,22 +905,22 @@
     <string name="wifi_ssid_hint" msgid="5010024648106585165">"SSID киргизиңиз"</string>
     <string name="wifi_security" msgid="9136702039496152831">"Коопсуздук"</string>
     <string name="wifi_hidden_network" msgid="6647772204699776833">"Жашырылган тармак"</string>
-    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Эгер роутериңиз тармактын ID\'син таратпай жатса, бирок ага келечекте туташууну кааласаңыз, ал тармакты жашыруун кылып койсоңуз болот.\n\nТелефонуңуз тармакты табуу үчүн сигналын такай таратканына байланыштуу бул коопсуздукка зыян келтириши мүмкүн.\n\nТармакты жашыруун кылып жөндөсөңүз, роутериңиздин жөндөөлөрү өзгөрбөйт."</string>
+    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Эгер роутериңиз тармактын идентификаторун таратпай жатса, бирок ага кийинчерээк туташа турган болсоңуз, аны жашыруун кылып койсоңуз болот.\n\nБирок телефонуңуз сигнал берип, тармакты издей берет. Ушундан улам, түзмөгүңүздүн коопсуздугуна коркунуч келтирилиши мүмкүн.\n\nЖашыруун тармактын сакталышы роутердин параметрлерин өзгөртпөйт."</string>
     <string name="wifi_signal" msgid="696548364467704808">"Сигналдын күчү"</string>
     <string name="wifi_status" msgid="3439931558930689940">"Абалы"</string>
-    <string name="tx_wifi_speed" msgid="2571810085003261073">"Байланыш ылдамдыгын берүү"</string>
-    <string name="rx_wifi_speed" msgid="7392873246110937187">"Байланыш ылдамдыгын алуу"</string>
+    <string name="tx_wifi_speed" msgid="2571810085003261073">"Маалымат берүү ылдамдыгы"</string>
+    <string name="rx_wifi_speed" msgid="7392873246110937187">"Маалымат алуу ылдамдыгы"</string>
     <string name="wifi_frequency" msgid="6132852924995724246">"Жыштык"</string>
     <string name="wifi_ip_address" msgid="5572539114989914831">"IP дарек"</string>
     <string name="passpoint_label" msgid="7429247462404128615">"Төмөнкү аркылуу сакталган"</string>
     <string name="passpoint_content" msgid="340527524510304327">"<xliff:g id="NAME">%1$s</xliff:g> эсептик дайындары"</string>
     <string name="wifi_eap_method" msgid="3752116941487485859">"EAP ыкмасы"</string>
-    <string name="please_select_phase2" msgid="5848080896810435677">"Аныктыктын текшерүүнүн 2-этабы"</string>
+    <string name="please_select_phase2" msgid="5848080896810435677">"Аутентификациянын 2-этабы"</string>
     <string name="wifi_eap_ca_cert" msgid="1496395241849383785">"CA тастыктамасы"</string>
     <string name="wifi_eap_domain" msgid="3298302320003640130">"Домен"</string>
     <string name="wifi_eap_user_cert" msgid="6786839531765719173">"Колдонуучунун тастыктамасы"</string>
     <string name="wifi_eap_identity" msgid="5280457017705738773">"Идентификация"</string>
-    <string name="wifi_eap_anonymous" msgid="6352344972490839958">"Аныктыгы жашыруун"</string>
+    <string name="wifi_eap_anonymous" msgid="6352344972490839958">"Белгисиз"</string>
     <string name="wifi_password" msgid="6942983531275177771">"Сырсөз"</string>
     <string name="wifi_show_password" msgid="7878398590772942202">"Сырсөздү көрсөтүү"</string>
     <string name="wifi_ap_band_config" msgid="6565016368079288433">"Wi-Fi жыштыгынын диапазону"</string>
@@ -927,15 +930,15 @@
     <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"5.0 ГГц жыштыгы сунушталат"</string>
     <string name="wifi_ap_2G" msgid="5793110086517338494">"2.4 ГГц"</string>
     <string name="wifi_ap_5G" msgid="4584892544393675403">"5.0 ГГц"</string>
-    <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"Wi‑Fi туташуу түйүнүн иштетүү үчүн кеминде бир жыштыкты тандаңыз:"</string>
+    <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"Wi‑Fi байланыш түйүнүн иштетүү үчүн кеминде бир жыштыкты тандаңыз:"</string>
     <string name="wifi_ip_settings" msgid="4636102290236116946">"IP жөндөөлөрү"</string>
     <string name="wifi_privacy_settings" msgid="4462092795794247809">"Купуялык"</string>
     <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"Кокустан тандалган MAC"</string>
     <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"Түзмөк кошуу"</string>
-    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"QR кодду борборго жайгаштырып, түзмөктү \"<xliff:g id="SSID">%1$s</xliff:g>\" тармагына кошуңуз"</string>
+    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"\"<xliff:g id="SSID">%1$s</xliff:g>\" тармагына кошулуу үчүн, камераны төмөнкү QR кодго алып келиңиз"</string>
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"QR кодун скандоо"</string>
-    <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"QR кодду борборго жайгаштырып, түзмөктү \"<xliff:g id="SSID">%1$s</xliff:g>\" тармагына туташтырыңыз"</string>
-    <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"QR кодун скандоо менен Wi‑Fi\'га кошулуңуз"</string>
+    <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"\"<xliff:g id="SSID">%1$s</xliff:g>\" тармагына туташуу үчүн, камераңызды төмөнкү QR кодго алып келиңиз"</string>
+    <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"Wi‑Fi\'га кошулуу үчүн, QR кодун скандаңыз"</string>
     <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Wi‑Fi\'ды бөлүшүү"</string>
     <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"\"<xliff:g id="SSID">%1$s</xliff:g>\" тармагына туташып, сырсөз менен бөлүшүү үчүн, бул QR кодун скандаңыз"</string>
     <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"\"<xliff:g id="SSID">%1$s</xliff:g>\" тармагына туташуу үчүн, бул QR кодун скандаңыз"</string>
@@ -964,12 +967,12 @@
     <string name="wifi_dpp_connect_network_using_qr_code" msgid="115993715600532357">"Бул тармакка туташуу үчүн, QR кодун колдонуңуз"</string>
     <string name="retry" msgid="8500839563577344702">"Кайталоо"</string>
     <string name="wifi_shared" msgid="5054256778276524960">"Түзмөктүн башка колдонуучулары менен бөлүшүлсүн"</string>
-    <string name="wifi_unchanged" msgid="6804964646942333992">"(өзгөрбөгөн)"</string>
+    <string name="wifi_unchanged" msgid="6804964646942333992">"(өзгөрүүсүз)"</string>
     <string name="wifi_unspecified" msgid="893491188483500809">"Тандаңыз"</string>
     <string name="wifi_multiple_cert_added" msgid="7986200585749147204">"(Бир нече тастыктама кошулду)"</string>
     <string name="wifi_use_system_certs" msgid="4794489370929885022">"Тутумдун тастыктамаларын көрсөтүү"</string>
     <string name="wifi_do_not_provide_eap_user_cert" msgid="4044301449482425250">"Берилбесин"</string>
-    <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"Күчүнө киргизилбесин"</string>
+    <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"Текшерилбесин"</string>
     <string name="wifi_do_not_validate_eap_server_warning" msgid="3895397996759837323">"Эч тастыктама көрсөтүлгөн жок. Туташууңуз купуя болбойт."</string>
     <string name="wifi_ssid_too_long" msgid="34911971389775920">"Тармактын аталышы өтө узун."</string>
     <string name="wifi_no_domain_warning" msgid="735859919311067606">"Домен көрсөтүлүшү керек."</string>
@@ -991,7 +994,7 @@
     <string name="lost_internet_access_text" msgid="8962010031520731813">"Wi-Fi байланышы начар болгондо, ар дайым мобилдик тармакка өтө аласыз. Дайындардын өткөрүлгөндүгү үчүн акы алынышы мүмкүн."</string>
     <string name="lost_internet_access_switch" msgid="9218006455779873700">"Мобилдик түзмөккө которуу"</string>
     <string name="lost_internet_access_cancel" msgid="6577871064062518744">"Wi-Fi тармагында калуу"</string>
-    <string name="lost_internet_access_persist" msgid="6368659013482055611">"Кайра көрсөтүлбөсүн"</string>
+    <string name="lost_internet_access_persist" msgid="6368659013482055611">"Кайра көрүнбөсүн"</string>
     <string name="wifi_connect" msgid="5653612760223533650">"Туташуу"</string>
     <string name="wifi_turned_on_message" msgid="3377779146238242894">"Wi-Fi күйгүзүлдү"</string>
     <!-- no translation found for wifi_connected_to_message (2875589636437599620) -->
@@ -1057,7 +1060,7 @@
     <string name="wifi_hotspot_off_subtext" msgid="6177054857136221058">"Интернет же мазмун башка түзмөктөр менен бөлүшүлгөн жок"</string>
     <string name="wifi_hotspot_tethering_on_subtext" product="tablet" msgid="71421730039785897">"Бул планшеттин Интернети байланыш түйүнү аркылуу бөлүшүлүүдө"</string>
     <string name="wifi_hotspot_tethering_on_subtext" product="default" msgid="8914285514605049879">"Бул телефондун Интернети байланыш түйүнү аркылуу бөлүшүлүүдө"</string>
-    <string name="wifi_hotspot_on_local_only_subtext" msgid="7415381343846704553">"Колдонмо мазмунду бөлүшүүдө. Интернет байланышын бөлүшүү үчүн туташуу түйүнүн өчүрүп, кайра күйгүзүңүз"</string>
+    <string name="wifi_hotspot_on_local_only_subtext" msgid="7415381343846704553">"Колдонмо мазмунду бөлүшүүдө. Интернет байланышын бөлүшүү үчүн байланыш түйүнүн өчүрүп, кайра күйгүзүңүз"</string>
     <string name="wifi_hotspot_no_password_subtext" msgid="5400500962974373706">"Бир да сырсөз коюлган жок"</string>
     <string name="wifi_hotspot_name_title" msgid="6572202165400226127">"Байланыш түйүнүнүн аталышы"</string>
     <string name="wifi_hotspot_name_summary_connecting" msgid="5176787959408511889">"<xliff:g id="WIFI_HOTSPOT_NAME">%1$s</xliff:g> күйгүзүлүүдө…"</string>
@@ -1079,7 +1082,7 @@
     <string name="wifi_calling_settings_title" msgid="626821542308601806">"Wi-Fi чалуу"</string>
     <string name="wifi_calling_suggestion_title" msgid="1402265373543523970">"Байланыш аймагын кеңейтүү үчүн Wi-Fi аркылуу чалуу"</string>
     <string name="wifi_calling_suggestion_summary" msgid="198402175473169630">"Байланыш аймагын кеңейтүү үчүн Wi-Fi аркылуу чалууну күйгүзүңүз"</string>
-    <string name="wifi_calling_mode_title" msgid="3350624859819920176">"Чалуунун жеке жөндөөлөрү"</string>
+    <string name="wifi_calling_mode_title" msgid="3350624859819920176">"Чалуунун жөндөөлөрү"</string>
     <string name="wifi_calling_mode_dialog_title" msgid="652534533091724333">"Чалуу параметрлери"</string>
     <string name="wifi_calling_roaming_mode_title" msgid="2059151080231602753">"Роуминг жөндөөлөрү"</string>
     <!-- no translation found for wifi_calling_roaming_mode_summary (620031651074963360) -->
@@ -1099,13 +1102,16 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi‑Fi"</item>
+    <item msgid="2271962426654621656">"Мобилдик түзмөк"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Wi‑Fi жеткиликсиз болсо, мобилдик тармакты колдонуу"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Мобилдик тармак жеткиликсиз болсо, Wi‑Fi’ды колдонуңуз"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Wi-Fi аркылуу чалуу. Wi‑Fi жоголуп кетсе, чалуу үзүлөт."</string>
     <string name="wifi_calling_off_explanation" msgid="1653424723742898015">"Wi-Fi аркылуу чалуу күйгүзүлгөндө, телефонуңуз, жеке жөндөөлөрүңүзгө жана сигналдын күчтүүлүгүнө жараша, чалууларды Wi-Fi тармактары же операторуңуздун тармагы аркылуу багыттай алат. Бул функцияны күйгүзүүдөн мурда, төлөмдөрү жана башка маалымат боюнча операторуңузга кайрылыңыз.<xliff:g id="ADDITIONAL_TEXT">%1$s</xliff:g>"</string>
     <string name="wifi_calling_off_explanation_2" msgid="8648609693875720408"></string>
-    <string name="emergency_address_title" msgid="5779915349686787024">"Өзгөчө кырдаалда кайрыла турган дарек"</string>
+    <string name="emergency_address_title" msgid="5779915349686787024">"Кырсыктаганда кайрыла турган дарек"</string>
     <string name="emergency_address_summary" msgid="478668478569851714">"WiFi аркылуу өзгөчө кырдаалдар кызматынын номерине чалганыңызда куткаруучуларга жайгашкан жериңиз катары көрсөтүлөт"</string>
     <string name="private_dns_help_message" msgid="7633526525131196650">"Жеке DNS функциялары жөнүндө "<annotation id="url">"кененирээк маалымат"</annotation>" алыңыз"</string>
     <string name="wifi_calling_pref_managed_by_carrier" msgid="5458050015417972072">"Жөндөө байланыш оператору тарабынан башкарылат"</string>
@@ -1164,7 +1170,7 @@
     <string name="accessibility_personal_account_title" msgid="7251761883688839354">"Жеке аккаунт - <xliff:g id="MANAGED_BY">%s</xliff:g>"</string>
     <string name="search_settings" msgid="5809250790214921377">"Издөө"</string>
     <string name="display_settings" msgid="1045535829232307190">"Экран"</string>
-    <string name="accelerometer_title" msgid="2427487734964971453">"Экранды авто-буруу"</string>
+    <string name="accelerometer_title" msgid="2427487734964971453">"Экранды авто буруу"</string>
     <string name="color_mode_title" msgid="8164858320869449142">"Түстөр"</string>
     <string name="color_mode_option_natural" msgid="1292837781836645320">"Табигый"</string>
     <string name="color_mode_option_boosted" msgid="453557938434778933">"Күчөтүлгөн"</string>
@@ -1197,13 +1203,13 @@
     <string name="auto_brightness_off_summary" msgid="6162650416289359104">"Учурдагы жарыкка ыңгайлаштырылбасын"</string>
     <string name="auto_brightness_very_high_summary" msgid="7202032980509583918">"Батарея тез отуруп калат"</string>
     <string name="auto_brightness_disclaimer" msgid="5416696351199148809">"Жарык деңгээли учурдагы жарыкка карап өзгөрөт. Зарылчылыкка жараша аны убактылуу өзгөртсөңүз болот."</string>
-    <string name="auto_brightness_description" msgid="8209140379089535411">"Экрандын жарыктыгы жүргөн жериңизге жана аткарган ишиңизге жараша автоматтык түрдө өзгөрөт. Сыдырманы колуңуз менен сыдырып, ыңгайлаштырылуучу жарыкты өзүңүз каалагандай жөндөп алыңыз."</string>
+    <string name="auto_brightness_description" msgid="8209140379089535411">"Экрандын жарыктыгы жүргөн жериңизге жана аткарган ишиңизге жараша автоматтык түрдө өзгөрөт. Сыдырманы колуңуз менен сыдырып, жарыкты өзүңүз каалагандай ыңгайлаштырып алыңыз."</string>
     <string name="display_white_balance_title" msgid="5747260735311935143">"Экрандын ак балансы"</string>
     <string name="adaptive_sleep_title" msgid="3237620948260957018">"Screen aware"</string>
     <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"Күйүк / Экранды карап турганда, ал өчүп калбайт"</string>
     <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"Өчүк"</string>
     <string name="adaptive_sleep_description" msgid="812673735459170009">"Экранды карап турганда, ал өчүп калбайт."</string>
-    <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Screen aware экранды кимдир-бирөө карап жатканын текшерүү үчүн маңдайкы камераны колдонот. Ал түзмөктө иштеп, сүрөттөрдү эч качан сактап калбайт жана Google\'га жөнөтпөйт."</string>
+    <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Screen aware экранды кимдир-бирөө карап жатканын текшерүү үчүн, маңдайкы камераны колдонот. Ал түзмөктө иштеп, сүрөттөрдү эч качан сактап калбайт жана Google\'га жөнөтпөйт."</string>
     <string name="night_display_title" msgid="1305002424893349814">"Түнкү режим"</string>
     <string name="night_display_text" msgid="5330502493684652527">"Түнкү режимде экран сары түскө боёлот. Ушуну менен күңүрт жерде көзүңүзгө күч келбей, тезирээк уктап каласыз."</string>
     <string name="night_display_auto_mode_title" msgid="8493573087102481588">"Ырааттама"</string>
@@ -1223,7 +1229,7 @@
     <string name="night_display_summary_on_auto_mode_custom" msgid="2200631112239399233">"<xliff:g id="ID_1">%1$s</xliff:g> болгондо автоматтык түрдө өчөт"</string>
     <string name="night_display_summary_on_auto_mode_twilight" msgid="8386769601369289561">"Күн чыкканда автоматтык түрдө өчөт"</string>
     <string name="night_display_activation_on_manual" msgid="8379477527072027346">"Күйгүзүү"</string>
-    <string name="night_display_activation_off_manual" msgid="7776082151269794201">"Азыр өчүрүлсүн"</string>
+    <string name="night_display_activation_off_manual" msgid="7776082151269794201">"Өчүрүү"</string>
     <string name="night_display_activation_on_twilight" msgid="5610294051700287249">"Күн чыкканга чейин күйгүзүлсүн"</string>
     <string name="night_display_activation_off_twilight" msgid="6846727701281556110">"Күн батканга чейин өчүрүлсүн"</string>
     <string name="night_display_activation_on_custom" msgid="4761140206778957611">"<xliff:g id="ID_1">%1$s</xliff:g> чейин күйгүзүлсүн"</string>
@@ -1236,7 +1242,7 @@
     <string name="style_and_wallpaper_settings_title" msgid="8898539141152705754">"Стилдер жана тушкагаздар"</string>
     <string name="wallpaper_settings_summary_default" msgid="2626880032742784599">"Демейки"</string>
     <string name="wallpaper_settings_summary_custom" msgid="8950504698015331202">"Өзгөчө"</string>
-    <string name="wallpaper_suggestion_title" msgid="3012130414886743201">"Тушкагазды өзгөртүп алыңыз"</string>
+    <string name="wallpaper_suggestion_title" msgid="3012130414886743201">"Тушкагазды өзгөртө аласыз"</string>
     <string name="wallpaper_suggestion_summary" msgid="4247262938988875842">"Экраныңызды жекелештириңиз"</string>
     <string name="wallpaper_settings_fragment_title" msgid="1503701065297188901">"Тушкагаз тандоо"</string>
     <string name="screensaver_settings_title" msgid="7720091234133721021">"Көшөгө"</string>
@@ -1260,7 +1266,7 @@
     <string name="doze_always_on_title" msgid="8555184965031789941">"Ар дайым күйүк"</string>
     <string name="doze_always_on_summary" msgid="7654436900436328950">"Убакыт, билдирмелер сүрөтчөлөрү жана башка маалымат көрүнүп турат (батарея тез отуруп калат)."</string>
     <string name="title_font_size" msgid="5021464556860010851">"Арип өлчөмү"</string>
-    <string name="short_summary_font_size" msgid="4141077908728522946">"Текстти чоңойтуп же кичирейтиңиз"</string>
+    <string name="short_summary_font_size" msgid="4141077908728522946">"Текстти чоңойтуп же кичирейтесиз"</string>
     <string name="sim_lock_settings" msgid="1986924650622642189">"SIM картаны кулпулоо жөндөөлөрү"</string>
     <string name="sim_lock_settings_category" msgid="1126759898277681516">"SIM карта кулпусу"</string>
     <string name="sim_lock_settings_summary_off" msgid="348656447968142307">"Өчүк"</string>
@@ -1283,7 +1289,7 @@
     <string name="sim_pins_dont_match" msgid="1076283313667637902">"PINдер туура келген жок"</string>
     <string name="sim_change_failed" msgid="8874765697694275459">"PIN\'ди алмаштыруу мүмкүн эмес.\nPIN туура эмес өңдөнөт."</string>
     <string name="sim_change_succeeded" msgid="8802418023120614533">"SIM картанын PIN коду алмаштырылды"</string>
-    <string name="sim_lock_failed" msgid="7949781515066772755">"SIM-картаны бөгөттөн чыгаруу мүмкүн эмес.\nPIN туура эмес өңдөнөт."</string>
+    <string name="sim_lock_failed" msgid="7949781515066772755">"SIM картаны бөгөттөн чыгаруу мүмкүн эмес.\nPIN туура эмес өңдөнөт."</string>
     <string name="sim_pin_disable_failed" msgid="6780973900290546751">"PIN код өчүрүлбөй жатат."</string>
     <string name="sim_pin_enable_failed" msgid="804897359922298792">"PIN код иштетилбей жатат."</string>
     <string name="sim_enter_ok" msgid="5103626479976731229">"Жарайт"</string>
@@ -1304,7 +1310,7 @@
     <string name="system_update_settings_list_item_title" msgid="1907497454722790033">"Тутум жаңыртуулары"</string>
     <string name="system_update_settings_list_item_summary" msgid="3497456690691907873"></string>
     <string name="firmware_version" msgid="547095584029938749">"Android версиясы"</string>
-    <string name="security_patch" msgid="483709031051932208">"Коопсуздук тутуму качан жаңырды"</string>
+    <string name="security_patch" msgid="483709031051932208">"Коопсуздук тутуму качан жаңырган"</string>
     <string name="model_info" msgid="1729765474260797594">"Үлгүсү"</string>
     <string name="model_summary" msgid="8781425868254352168">"Үлгүсү: %1$s"</string>
     <string name="hardware_info" msgid="174270144950621815">"Түзмөктүн үлгүсү/аппараттык камсыздалышы"</string>
@@ -1330,8 +1336,8 @@
     <string name="status_number" product="default" msgid="6404365757066475145">"Телефон номери"</string>
     <string name="status_number_sim_slot" product="tablet" msgid="4518232285651165459">"MDN (SIM-карта оюкчасы %1$d)"</string>
     <string name="status_number_sim_slot" product="default" msgid="3660851494421332328">"Телефон номери (SIM-карта оюкчасы %1$d)"</string>
-    <string name="status_number_sim_status" product="tablet" msgid="8069693515860290952">"SIM-картадагы MDN"</string>
-    <string name="status_number_sim_status" product="default" msgid="6602562692270457610">"SIM-картадагы телефон номери"</string>
+    <string name="status_number_sim_status" product="tablet" msgid="8069693515860290952">"SIM картадагы MDN"</string>
+    <string name="status_number_sim_status" product="default" msgid="6602562692270457610">"SIM картадагы телефон номери"</string>
     <string name="status_min_number" msgid="8346889546673707777">"MIN"</string>
     <string name="status_msid_number" msgid="7808175928664357661">"MSID"</string>
     <string name="status_prl_version" msgid="5634561205739199042">"PRL версиясы"</string>
@@ -1522,7 +1528,7 @@
     <string name="battery_level_title" msgid="5207775387973771646">"Батарея деңгээли"</string>
     <string name="apn_settings" msgid="8130776653826271664">"APN\'дер"</string>
     <string name="apn_edit" msgid="4350571070853305357">"Байланыш түйүнүн өзгөртүү"</string>
-    <string name="apn_not_set" msgid="5344235604466825691">"Аныкталган эмес"</string>
+    <string name="apn_not_set" msgid="5344235604466825691">"Коюлган эмес"</string>
     <string name="apn_name" msgid="8431432886706852226">"Аталышы"</string>
     <string name="apn_apn" msgid="190519449579357696">"APN"</string>
     <string name="apn_http_proxy" msgid="8816906767987944465">"Прокси"</string>
@@ -1559,26 +1565,26 @@
     <string name="error_mcc_not3" msgid="1333037488064427164">"MCC талаасы 3 орундуу болууга тийиш."</string>
     <string name="error_mnc_not23" msgid="6738398924368729180">"MNC талаасы 2 же 3 орундуу болууга тийиш."</string>
     <string name="error_adding_apn_type" msgid="671634520340569678">"Байланыш оператору %s түрүндөгү APN\'дерди кошууга уруксат бербейт."</string>
-    <string name="restore_default_apn" msgid="7195266404077471007">"Абалкы APN тууралоолорун кайтарууда."</string>
+    <string name="restore_default_apn" msgid="7195266404077471007">"Демейки APN тууралоолорун кайтарууда."</string>
     <string name="menu_restore" msgid="3799288817317293115">"Баштапкы абалга келтирүү"</string>
-    <string name="restore_default_apn_completed" msgid="5671734152740058937">"Абалкы APN тууралоолорун кайтаруу аяктады."</string>
+    <string name="restore_default_apn_completed" msgid="5671734152740058937">"Демейки APN жөндөөлөрү калыбына келди."</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"Кайра коюу опциялары"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"Тармактын, колдонмолордун же түзмөктүн жөндөөлөрүн баштапкы абалга келтирсеңиз болот"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"Wi-Fi\'ды, мобилдик түзмөктү жана Bluetooth\'ду баштапкы абалга келтирүү"</string>
     <string name="reset_network_desc" msgid="4982633363916261109">"Ушуну менен тармактын бардык жөндөөлөрү баштапкы абалга келет. Тактап айтканда: \n\n"<li>"Wi‑Fi"</li>\n<li>"Мобилдик Интернет"</li>\n<li>"Bluetooth"</li></string>
-    <string name="reset_esim_title" msgid="7630781767040831893">"Жүктөп алган SIM’дерди тазалоо"</string>
-    <string name="reset_esim_desc" msgid="433226911566802">"Ордуна башка SIM карта жүктөп алуу үчүн, операторуңуз менен байланышыңыз. Ушуну менен байланыш операторунун тарифтик пландары жокко чыгарылбайт."</string>
+    <string name="reset_esim_title" msgid="7630781767040831893">"Жүктөп алган SIM’дерди өчүрүү"</string>
+    <string name="reset_esim_desc" msgid="433226911566802">"Ордуна башка SIM карта жүктөп алуу үчүн, операторуңуз менен байланышыңыз. Тарифтик пландарыңыз өзгөрбөйт."</string>
     <string name="reset_network_button_text" msgid="4293271046867912819">"Жөндөөлөрдү кайра коюу"</string>
     <string name="reset_network_final_desc" msgid="2463817067048751373">"Тармак жөндөөлөрүнүн баары баштапкы абалга келтирилсинби? Бул аракетти кайра кайтара албайсыз."</string>
-    <string name="reset_network_final_desc_esim" msgid="4676436976372555750">"Тармак жөндөөлөрүнүн баары баштапкы абалга келтирилип, жүктөлүп алынган SIM карталар тазалансынбы? Бул аракетти артка кайтара албайсыз."</string>
+    <string name="reset_network_final_desc_esim" msgid="4676436976372555750">"Тармак жөндөөлөрүнүн баарын баштапкы абалга келтирип, жүктөлүп алынган SIM карталарды өчүрөсүзбү? Бул аракетти артка кайтара албайсыз."</string>
     <string name="reset_network_final_button_text" msgid="345255333127794393">"Жөндөөлөрдү кайра коюу"</string>
     <string name="reset_network_confirm_title" msgid="2432145031070536008">"Кайра коесузбу?"</string>
     <string name="network_reset_not_available" msgid="6146655531868016281">"Бул колдонуучу тармакты баштапкы абалына келтире албайт"</string>
     <string name="reset_network_complete_toast" msgid="128225929536005495">"Тармак жөндөөлөрү баштапкы абалга келди"</string>
     <string name="reset_esim_error_title" msgid="4728931209471875632">"SIM карталар тазаланбай жатат"</string>
     <string name="reset_esim_error_msg" msgid="4716366079119742235">"Жүктөлүп алынган SIM карталарды катадан улам тазалоого болбойт.\n\nТүзмөгүңүздү өчүрүп күйгүзүп, кайталап көрүңүз."</string>
-    <string name="master_clear_title" msgid="1560712943955904673">"Бардык дайындарды тазалоо (баштапкы абалга келтирүү)"</string>
-    <string name="master_clear_short_title" msgid="919098101581335101">"Бардык дайындарды тазалоо"</string>
+    <string name="master_clear_title" msgid="1560712943955904673">"Бардык дайын-даректерди өчүрүү (баштапкы абалга келтирүү)"</string>
+    <string name="master_clear_short_title" msgid="919098101581335101">"Бардык дайын-даректерди өчүрүү"</string>
     <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"Планшетиңиздин "<b>"ички сактагычындагы"</b>" бардык маалымат өчүрүлөт, тактап айтканда:\n\n"<li>"Google аккаунтуңуз"</li>\n<li>"Тутумдун жана колдонмолордун жөндөөлөрү жана дайындары"</li>\n<li>"Жүктөлүп алынган колдонмолор"</li></string>
     <string name="master_clear_desc" product="default" msgid="8765543541962866697">"Телефонуңуздун "<b>"ички сактагычындагы"</b>" бардык маалымат өчүрүлөт, тактап айтканда:\n\n"<li>"Google аккаунтуңуз"</li>\n<li>"Тутумдун жана колдонмолордун жөндөөлөрү жана дайындары"</li>\n<li>"Жүктөлүп алынган колдонмолор"</li></string>
     <string name="master_clear_accounts" product="default" msgid="3432884235445405376">\n\n"Ушул түзмөктөгү аккаунттар:\n"</string>
@@ -1607,16 +1613,16 @@
     <string name="tether_settings_title_usb" msgid="4265582654602420357">"USB модем"</string>
     <string name="tether_settings_title_wifi" msgid="2060965130234484613">"Wi-Fi байланыш түйүнү"</string>
     <string name="tether_settings_title_bluetooth" msgid="1999590158102569959">"Bluetooth модем"</string>
-    <string name="tether_settings_title_usb_bluetooth" msgid="1159128764162788159">"Жалгаштыруу"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="1159128764162788159">"Модем режими"</string>
     <string name="tether_settings_title_all" msgid="6935843543433954181">"Байланыш түйүнү жана модем"</string>
     <string name="tether_settings_summary_hotspot_on_tether_on" msgid="1289593649526514499">"Байланыш түйүнү күйүк, модем режими"</string>
     <string name="tether_settings_summary_hotspot_on_tether_off" msgid="8010689354668285422">"Байланыш түйүнү күйүк"</string>
-    <string name="tether_settings_summary_hotspot_off_tether_on" msgid="1349909238672649877">"Тетеринг"</string>
+    <string name="tether_settings_summary_hotspot_off_tether_on" msgid="1349909238672649877">"Модем режими"</string>
     <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"Трафикти үнөмдөө режиминде түзмөктү модем же байланыш түйүнү катары колдонууга болбойт"</string>
     <string name="usb_title" msgid="7480927657535578688">"USB"</string>
     <string name="usb_tethering_button_text" msgid="6242228383142012332">"USB модем"</string>
     <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"Телефондун Интернетин USB аркылуу бөлүшөсүз"</string>
-    <string name="usb_tethering_subtext" product="tablet" msgid="154536000235361034">"Планшеттин Интернетин USB аркылуу бөлүшүү"</string>
+    <string name="usb_tethering_subtext" product="tablet" msgid="154536000235361034">"Планшеттин Интернетин USB аркылуу бөлүшөсүз"</string>
     <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"Bluetooth модем"</string>
     <string name="bluetooth_tethering_subtext" product="tablet" msgid="6868756914621131635">"Планшеттин Интернетин Bluetooth аркылуу бөлүшүү"</string>
     <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"Телефондун Интернетин Bluetooth аркылуу бөлүшөсүз"</string>
@@ -1631,17 +1637,17 @@
     <string name="sms_change_default_dialog_title" msgid="6301260161969667578">"SMS колдонмону алмаштырасызбы?"</string>
     <string name="sms_change_default_dialog_text" msgid="8275088077930942680">"SMS билдирүүлөрү менен жазышуу үчүн <xliff:g id="CURRENT_APP">%2$s</xliff:g> ордуна <xliff:g id="NEW_APP">%1$s</xliff:g> колдоносузбу?"</string>
     <string name="sms_change_default_no_previous_dialog_text" msgid="4680224695080527907">"<xliff:g id="NEW_APP">%s</xliff:g> SMS колдонмосу болсунбу?"</string>
-    <string name="network_scorer_picker_title" msgid="1691073966560952916">"Тармактар рейтингинин автору"</string>
+    <string name="network_scorer_picker_title" msgid="1691073966560952916">"Тармактар рейтингинин булагы"</string>
     <string name="network_scorer_picker_none_preference" msgid="6448280557733231737">"Жок"</string>
-    <string name="network_scorer_change_active_dialog_title" msgid="4274159562371475090">"Wi‑Fi жардамчысы өзгөрүлсүнбү?"</string>
+    <string name="network_scorer_change_active_dialog_title" msgid="4274159562371475090">"Wi‑Fi жардамчысын өзгөртөсүзбү?"</string>
     <string name="network_scorer_change_active_dialog_text" msgid="4264089809189760730">"Тармактык туташууларыңызды башкаруу үчүн, <xliff:g id="CURRENT_APP">%2$s</xliff:g> ордуна <xliff:g id="NEW_APP">%1$s</xliff:g> колдоносузбу?"</string>
     <string name="network_scorer_change_active_no_previous_dialog_text" msgid="6394483538843474495">"Тармактык туташууларыңызды башкаруу үчүн <xliff:g id="NEW_APP">%s</xliff:g> колдоносузбу?"</string>
     <string name="mobile_unknown_sim_operator" msgid="872589370085135817">"Белгисиз SIM оператору"</string>
     <string name="mobile_no_provisioning_url" msgid="3216517414902166131">"<xliff:g id="OPERATOR">%1$s</xliff:g> операторунда белгилүү камсыздоочу вебсайт жок"</string>
-    <string name="mobile_insert_sim_card" msgid="7594550403454243732">"SIM-картаны салып, кайра иштетиңиз"</string>
+    <string name="mobile_insert_sim_card" msgid="7594550403454243732">"SIM картаны салып, кайра иштетиңиз"</string>
     <string name="mobile_connect_to_internet" msgid="6031886097365170913">"Интернетке кошулуңуз"</string>
     <string name="location_title" msgid="8664674161765477168">"Жайгашкан жерим"</string>
-    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"Жумуш профилинин жайгашкн жери"</string>
+    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"Жумуш профилинин жери"</string>
     <string name="location_app_level_permissions" msgid="1298041503927632960">"Колдонмонун уруксаты"</string>
     <string name="location_app_permission_summary_location_off" msgid="541372845344796336">"Жайгашкан жерди аныктоо өчүрүлгөн"</string>
     <plurals name="location_app_permission_summary_location_on" formatted="false" msgid="7904821382328758218">
@@ -1650,11 +1656,11 @@
     </plurals>
     <string name="location_category_recent_location_access" msgid="286059523360285026">"Гео маалымат акыркы жолу качан колдонулду"</string>
     <string name="location_recent_location_access_view_details" msgid="2051602261436245905">"Кеңири маалымат"</string>
-    <string name="location_no_recent_apps" msgid="77502059586413278">"Акыркы мезгилде жайгашууну сураган колдонмолор болгон жок"</string>
+    <string name="location_no_recent_apps" msgid="77502059586413278">"Жакында жайгашкан жерди сураган колдонмолор болгон жок"</string>
     <string name="location_no_recent_accesses" msgid="6289916310397279890">"Жакында жайгашкан жерди аныктоо кызматына бир да колдонмо кирген жок"</string>
     <string name="location_high_battery_use" msgid="7177199869979522663">"Батарейди көп колдонуу"</string>
     <string name="location_low_battery_use" msgid="5030448574501435888">"Батареянын кубаты үнөмдөлүүдө"</string>
-    <string name="location_scanning_screen_title" msgid="7663329319689413454">"Wi‑Fi жана Bluetooth менен издөө"</string>
+    <string name="location_scanning_screen_title" msgid="7663329319689413454">"Wi‑Fi менен Bluetooth\'ду издөө"</string>
     <string name="location_scanning_wifi_always_scanning_title" msgid="6750542206763112172">"Wi‑Fi издөө"</string>
     <string name="location_scanning_wifi_always_scanning_description" msgid="4956048135941851712">"Wi-Fi өчүп турса да, колдонмолор менен кызматтарга Wi-Fi тармактарын издегенге уруксат бересиз. Бул параметр менен жайгашкан жерди тагыраак аныктоого болот."</string>
     <string name="location_scanning_bluetooth_always_scanning_title" msgid="196241746742607453">"Bluetooth түзмөктөрүн издөө"</string>
@@ -1681,7 +1687,7 @@
     <string name="about_settings_summary" msgid="4506081667462281647">"Юридикалык маалыматты, абалын, программа версиясын көрүү"</string>
     <string name="legal_information" msgid="2374267257615182139">"Юридикалык маалымат"</string>
     <string name="contributors_title" msgid="6800028420806884340">"Салым кошуучулар"</string>
-    <string name="manual" msgid="5431859421432581357">"Нускама"</string>
+    <string name="manual" msgid="5431859421432581357">"Кол менен"</string>
     <string name="regulatory_labels" msgid="380968489247381025">"Тастыктама энбелгилери"</string>
     <string name="safety_and_regulatory_info" msgid="7113766428000920132">"Коопсуздук жана стандарттарга жооп берүү"</string>
     <string name="copyright_title" msgid="3847703367689932190">"Автордук укук"</string>
@@ -1690,7 +1696,7 @@
     <string name="webview_license_title" msgid="8244960025549725051">"WebView тутум уруксаттамасы"</string>
     <string name="wallpaper_attributions" msgid="2941987966332943253">"Тушкагаздар"</string>
     <string name="wallpaper_attributions_values" msgid="4461979853894606323">"Спутник сүрөттөрү:\n©2014 CNES/Astrium, DigitalGlobe, Bluesky"</string>
-    <string name="settings_manual_activity_title" msgid="7599911755054286789">"Нускама"</string>
+    <string name="settings_manual_activity_title" msgid="7599911755054286789">"Кол менен"</string>
     <string name="settings_manual_activity_unavailable" msgid="4872502775018655343">"Нускаманы жүктөөдө көйгөй чыкты."</string>
     <string name="settings_license_activity_title" msgid="1099045216283677608">"Үчүнчү тараптын уруксаттамалары"</string>
     <string name="settings_license_activity_unavailable" msgid="1039356188263821287">"Уруксаттамалар жүктөлүп жатканда көйгөй келип чыкты."</string>
@@ -1702,17 +1708,17 @@
     <string name="confirm_device_credential_use_alternate_method" msgid="1279869272895739941">"Башка ыкманы колдонуу"</string>
     <string name="lockpassword_choose_your_screen_lock_header" msgid="6283518876031424798">"Экран кулпусун коюу"</string>
     <string name="lockpassword_choose_your_password_message" msgid="2838273977481046536">"Коопсуздук үчүн сырсөз коюп алыңыз"</string>
-    <string name="lockpassword_choose_your_password_header_for_fingerprint" msgid="4921343500484160894">"Манжа изин колдонуу үчүн сырсөздү коюңуз"</string>
-    <string name="lockpassword_choose_your_pattern_header_for_fingerprint" msgid="314870151462139417">"Манжа изин колдонуу үчүн графикалык ачкычты коюңуз"</string>
+    <string name="lockpassword_choose_your_password_header_for_fingerprint" msgid="4921343500484160894">"Сырсөздү коюңуз"</string>
+    <string name="lockpassword_choose_your_pattern_header_for_fingerprint" msgid="314870151462139417">"Графикалык ачкычты коюңуз"</string>
     <string name="lockpassword_choose_your_pin_message" msgid="8942598950627277885">"Коопсуздук үчүн PIN код коюп алыңыз"</string>
-    <string name="lockpassword_choose_your_pin_header_for_fingerprint" msgid="1102927520952116303">"Манжа изин колдонуу үчүн PIN кодду коюңуз"</string>
+    <string name="lockpassword_choose_your_pin_header_for_fingerprint" msgid="1102927520952116303">"PIN код коюңуз"</string>
     <string name="lockpassword_choose_your_pattern_message" msgid="1503075455752279687">"Коопсуздук үчүн графикалык ачкыч коюп алыңыз"</string>
     <string name="lockpassword_confirm_your_password_header" msgid="9055242184126838887">"Сырсөзүңүздү кайра киргизиңиз"</string>
     <string name="lockpassword_confirm_your_pattern_header" msgid="7137526922696316545">"Графикалык ачкычыңызды ырастаңыз"</string>
     <string name="lockpassword_confirm_your_pin_header" msgid="4335593948303036343">"PIN кодуңузду кайра киргизиңиз"</string>
     <string name="lockpassword_confirm_passwords_dont_match" msgid="1783767008133345784">"Сырсөздөр дал келген жок"</string>
     <string name="lockpassword_confirm_pins_dont_match" msgid="5444357293637748942">"PIN коддор дал келген жок"</string>
-    <string name="lockpassword_draw_your_pattern_again_header" msgid="9017394036814402348">"Графикалык ачкычты кайрадан тартыңыз"</string>
+    <string name="lockpassword_draw_your_pattern_again_header" msgid="9017394036814402348">"Графикалык ачкычты кайра тартыңыз"</string>
     <string name="lockpassword_choose_lock_generic_header" msgid="4418423132980560119">"Кулпуну ачуу ыкмасын тандоо"</string>
     <string name="lockpassword_password_set_toast" msgid="601928982984489868">"Сырсөз коюлду"</string>
     <string name="lockpassword_pin_set_toast" msgid="172594825722240059">"PIN код коюлду"</string>
@@ -1809,7 +1815,7 @@
     <string name="controls_label" msgid="5609285071259457221">"Көзөмөлдөр"</string>
     <string name="force_stop" msgid="9213858124674772386">"Мажбурлап токтотуу"</string>
     <string name="total_size_label" msgid="3929917501176594692">"Жалпы"</string>
-    <string name="application_size_label" msgid="175357855490253032">"Колдонмонун өлчөмү"</string>
+    <string name="application_size_label" msgid="175357855490253032">"Колдонмонун көлөмү"</string>
     <string name="external_code_size_label" msgid="3434421216268309411">"USB сактагычтын колдонмосу"</string>
     <string name="data_size_label" msgid="7790201846922671662">"Колдонуучунун дайындары"</string>
     <string name="external_data_size_label" product="nosdcard" msgid="8004991551882573479">"USB сактагычтын дайындары"</string>
@@ -1837,7 +1843,7 @@
     <string name="show_background_processes" msgid="88012264528093617">"Кэштелген процсстрд көрст"</string>
     <string name="default_emergency_app" msgid="286530070173495823">"Өзгөчө кырдаал колдонмосу"</string>
     <string name="reset_app_preferences" msgid="1426500030595212077">"Колдонмонун жөндөөлөрүн кайра коюу"</string>
-    <string name="reset_app_preferences_title" msgid="792909865493673598">"Колдонмо кайра баштан жөндөлсүнбү?"</string>
+    <string name="reset_app_preferences_title" msgid="792909865493673598">"Колдонмону кайра баштан жөндөйсүзбү?"</string>
     <string name="reset_app_preferences_desc" msgid="7935273005301096031">"Ушуну менен төмөнкү жөндөөлөр жоюлат:\n\n "<li>"Өчүрүлгөн колдонмолор"</li>\n" "<li>"Өчүрүлгөн колдонмолордун билдирмелери"</li>\n" "<li>"Демейки колдонмолор"</li>\n" "<li>"Фондук дайындарга коюлган чектөөлөр"</li>\n" "<li>"Бардык уруксат чектөөлөрү"</li>\n\n"Колдонмолордун дайындары жоголбойт."</string>
     <string name="reset_app_preferences_button" msgid="2041894727477934656">"Баштапкы абалга келтирүү"</string>
     <string name="manage_space_text" msgid="6166469422303124302">"Бош орунду башкаруу"</string>
@@ -1996,7 +2002,7 @@
     <string name="user_dict_settings_edit_dialog_title" msgid="6492621665762797309">"Сөздү түзөтүү"</string>
     <string name="user_dict_settings_context_menu_edit_title" msgid="4577283176672181497">"Түзөтүү"</string>
     <string name="user_dict_settings_context_menu_delete_title" msgid="670470172230144069">"Жок кылуу"</string>
-    <string name="user_dict_settings_empty_text" msgid="2774939221998982609">"Колдонуучу сөздүгүңүздө бир дагы сөз жок. Сөз кошуу үчүн кошуу (+) баскычын таптап коюңуз."</string>
+    <string name="user_dict_settings_empty_text" msgid="2774939221998982609">"Сөздүгүңүздө бир дагы сөз жок. Сөз кошуу үчүн кошуу (+) баскычын таптап коюңуз."</string>
     <string name="user_dict_settings_all_languages" msgid="8839702015353418176">"Бардык тилдер үчүн"</string>
     <string name="user_dict_settings_more_languages" msgid="8345984308635521364">"Дагы тилдер…"</string>
     <string name="testing" msgid="4255916838792186365">"Сыноо"</string>
@@ -2033,7 +2039,7 @@
     <string name="accessibility_settings_summary" msgid="5742379519336396561">"Экрандагыны окугучтар, экран, башкаруу элементтери"</string>
     <string name="vision_settings_title" msgid="7315352351051423944">"Атайн мүмкүнчлктрдн жөндлр"</string>
     <string name="vision_settings_description" msgid="3476589459009287332">"Түзмөктү өзүңүзгө карап ыңгайлаштырып алыңыз. Бул атайын мүмкүнчүлүктөрдүн параметрлерин кийинчерээк өзгөртсөңүз болот."</string>
-    <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"Арип өлчөмүн өзгөртсөңүз болот"</string>
+    <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"Арип өлчөмүн өзгөртө аласыз"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"Экрандагыны окугучтар"</string>
     <string name="audio_and_captions_category_title" msgid="6140472938769619212">"Аудио жана текстти окуп берүү"</string>
     <string name="display_category_title" msgid="545168481672250195">"Экран"</string>
@@ -2043,13 +2049,13 @@
     <string name="feature_flags_dashboard_title" msgid="3153034144122754381">"Функцияларды белгилөө"</string>
     <string name="talkback_title" msgid="3717960404234260050">"Talkback"</string>
     <string name="talkback_summary" msgid="6602857105831641574">"Экрандагы нерсени окуп берүүчү курал көздөрү начар көргөн адамдарга арналган"</string>
-    <string name="select_to_speak_summary" msgid="7514180457557735421">"Экраныңыздагы элементтерди түзмөк окуп бериши үчүн аларды таптап коюңуз"</string>
+    <string name="select_to_speak_summary" msgid="7514180457557735421">"Экрандагы нерсени түзмөк окуп бериши үчүн, аны басып коесуз"</string>
     <string name="accessibility_captioning_title" msgid="5878371993023439642">"Коштомо жазуулар"</string>
     <string name="accessibility_screen_magnification_title" msgid="7250949681883917360">"Чоңойтуу"</string>
     <string name="accessibility_screen_magnification_gestures_title" msgid="9199287875401817974">"Үч жолу таптап чоңойтуу"</string>
     <string name="accessibility_screen_magnification_navbar_title" msgid="400655612610761242">"Баскыч менен чоңойтуу"</string>
     <string name="accessibility_screen_magnification_state_navbar_gesture" msgid="1863831350878995600">"Баскыч менен жана үч жолу таптоо аркылуу чоңойтуу"</string>
-    <string name="accessibility_preference_magnification_summary" msgid="753307741814376312">"Экранды чоңойтуу"</string>
+    <string name="accessibility_preference_magnification_summary" msgid="753307741814376312">"Экран чоңоет"</string>
     <string name="accessibility_screen_magnification_short_summary" msgid="5698545174944494486">"Өлчөмүн өзгөртүү үчүн 3 жолу таптаңыз"</string>
     <string name="accessibility_screen_magnification_navbar_short_summary" msgid="5418767043532322397">"Чоңойтуп/кичирейтүү үчүн баскычты басыңыз"</string>
     <string name="accessibility_screen_magnification_summary" msgid="3363006902079431772"><b>"Чоңойтуу үчүн"</b>" экранды бир манжаңыз менен 3 жолу бат-бат таптаңыз.\n"<ul><li>"Эки манжаңыз менен сыдырып карасаңыз болот."</li>\n<li>"Масштабын тууралоо үчүн эки манжаңызды бириктирип жана ажыратыңыз."</li></ul>\n\n<b>"Ал эми убактылуу чоңойтуу үчүн"</b>" экранды 3 жолу бат-бат таптап, үчүнчүсүндө манжаңызды басып туруңуз.\n"<ul><li>"Көрүнүштүн экранга батпаган жерлерин ары-бери сүйрөп карасаңыз болот."</li>\n<li>"Кичирейтүү үчүн манжаңызды көтөрүп коюңуз."</li></ul>\n\n"Баскычтоптон же чабыттоо тилкесинен чоңойто албайсыз."</string>
@@ -2168,7 +2174,7 @@
     <string name="color_red" msgid="7426040122729897596">"Кызыл"</string>
     <string name="color_green" msgid="3432648781089648971">"Жашыл"</string>
     <string name="color_blue" msgid="4055855996393833996">"Көк"</string>
-    <string name="color_cyan" msgid="7669317410901991453">"Кызгылт көк"</string>
+    <string name="color_cyan" msgid="7669317410901991453">"Көгүш"</string>
     <string name="color_yellow" msgid="8847327436896180799">"Сары"</string>
     <string name="color_magenta" msgid="721976999611563071">"Кочкул"</string>
     <string name="enable_service_title" msgid="2746143093464928251">"<xliff:g id="SERVICE">%1$s</xliff:g> колдоносузбу?"</string>
@@ -2227,7 +2233,7 @@
     <string name="power_usage_level_and_status" msgid="8873534076894160727">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATUS">%2$s</xliff:g>"</string>
     <string name="power_discharge_remaining" msgid="3461915627093471868">"<xliff:g id="REMAIN">%1$s</xliff:g> калды"</string>
     <string name="power_charge_remaining" msgid="2730510256218879651">"<xliff:g id="UNTIL_CHARGED">%1$s</xliff:g> кубаттоо"</string>
-    <string name="background_activity_title" msgid="7207836362312111483">"Фондо колдонууну чектөө"</string>
+    <string name="background_activity_title" msgid="7207836362312111483">"Фондо керектелишин чектөө"</string>
     <string name="background_activity_summary" msgid="582372194738538145">"Колдонмо фондо аткарылсын"</string>
     <string name="background_activity_summary_disabled" msgid="457944930942085876">"Колдонмону фондо иштетүүгө уруксат жок"</string>
     <string name="background_activity_summary_whitelisted" msgid="4713321059375873828">"Фондо колдонуу чектелбейт"</string>
@@ -2257,7 +2263,7 @@
     <string name="bluetooth_on_time" msgid="6400569492287292639">"Өз убагындагы Wi‑Fi"</string>
     <string name="advanced_battery_title" msgid="5026866913848464170">"Батареянын колдонулушу"</string>
     <string name="history_details_title" msgid="8608193822257799936">"Таржымалдын чоо-жайы"</string>
-    <string name="battery_details_title" msgid="5358230551490703067">"Батарея колдонулушу"</string>
+    <string name="battery_details_title" msgid="5358230551490703067">"Батареянын керектелиши"</string>
     <string name="details_subtitle" msgid="7279638828004951382">"Чоо-жайын колдонуу"</string>
     <string name="controls_subtitle" msgid="6920199888882834620">"Кубат сарпталышын тууралоо"</string>
     <string name="packages_subtitle" msgid="6506269487892204413">"Камтылган топтомдор"</string>
@@ -2271,14 +2277,14 @@
     <string name="battery_tip_smart_battery_title" product="tablet" msgid="203494973250969040">"Планшетиңиздин батарея кубатынын мөөнөтүн узартыңыз"</string>
     <string name="battery_tip_smart_battery_title" product="device" msgid="7419448992583346364">"Түзмөгүңүздүн батарея кубатынын мөөнөтүн узартыңыз"</string>
     <string name="battery_tip_smart_battery_summary" msgid="5344821856478265778">"Battery Manager\'ди күйгүзүңүз"</string>
-    <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Батареяны үнөмдөгүч режимин күйгүзүү"</string>
-    <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Батарея адаттагыдан эртерээк отуруп калышы мүмкүн"</string>
+    <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Батареяны үнөмдөгүчтү күйгүзүү"</string>
+    <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Батарея эртерээк отуруп калышы мүмкүн"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Батареяны үнөмдөгүч режими күйүк"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Айрым кызматтардын функциялары чектелиши мүмкүн"</string>
     <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Телефон адаттагыдан көбүрөөк колдонулду"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"Планшет адаттагыдан көбүрөөк колдонулду"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"Түзмөк адаттагыдан көбүрөөк колдонулду"</string>
-    <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"Батарея адаттагыдан эртерээк отуруп калышы мүмкүн"</string>
+    <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"Батарея эртерээк отуруп калышы мүмкүн"</string>
     <string name="battery_tip_dialog_message" product="default" msgid="8453700079047810964">"Телефонуңуз адаттагыдан көбүрөөк колдонулду. Батареяңыз күтүлгөндөн эртерээк отуруп калышы мүмкүн.\n\nАкыркы толук кубаттоодон бери эң көп батарея сарптаган колдонмолор:"</string>
     <string name="battery_tip_dialog_message" product="tablet" msgid="6489981050645444068">"Планшетиңиз адаттагыдан көбүрөөк колдонулду. Батареяңыз күтүлгөндөн эртерээк отуруп калышы мүмкүн.\n\nАкыркы толук кубаттоодон бери эң көп батарея сарптаган колдонмолор:"</string>
     <string name="battery_tip_dialog_message" product="device" msgid="6348123094674390337">"Түзмөгүңүз адаттагыдан көбүрөөк колдонулду. Батареяңыз күтүлгөндөн эртерээк отуруп калышы мүмкүн.\n\nАкыркы толук кубаттоодон бери эң көп батарея сарптаган колдонмолор:"</string>
@@ -2292,8 +2298,8 @@
       <item quantity="one">%1$s колдонмо жакында чектелди</item>
     </plurals>
     <plurals name="battery_tip_restrict_summary" formatted="false" msgid="984148373944071669">
-      <item quantity="other">%2$d колдонмо батареяны фондо сарптайт</item>
-      <item quantity="one">%1$s колдонмо батареяны фондо сарптайт</item>
+      <item quantity="other">%2$d батареяны бат отургузуп жатат</item>
+      <item quantity="one">%1$s батареяны бат отургузуп жатат</item>
     </plurals>
     <plurals name="battery_tip_restrict_handled_summary" formatted="false" msgid="469696766640020557">
       <item quantity="other">Бул колдонмолор фондо иштебейт</item>
@@ -2308,12 +2314,12 @@
     <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"Батареяны үнөмдөө максатында, бул колдонмолордун фондо иштөөсүн токтотуп койсоңуз болот. Чектелген колдонмолор талаптагыдай иштебей, билдирмелери кечигүү менен көрсөтүлүшү мүмкүн.\n\nКолдонмолор:\n<xliff:g id="APP_LIST">%1$s</xliff:g>."</string>
     <string name="battery_tip_restrict_app_dialog_ok" msgid="2573410775701913487">"Чектөө"</string>
     <string name="battery_tip_unrestrict_app_dialog_title" msgid="812458516399125710">"Чектөөлөр өчүрүлсүнбү?"</string>
-    <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"Бул колдонмо батареяны фондо колдоно берет. Батареяңыз күтүлгөндөн эртерээк отуруп калышы мүмкүн."</string>
+    <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"Бул колдонмо батареяны фондо керектей берет. Батареяңыз күтүлгөндөн эртерээк отуруп калышы мүмкүн."</string>
     <string name="battery_tip_unrestrict_app_dialog_ok" msgid="9154938931448151479">"Алып салуу"</string>
     <string name="battery_tip_unrestrict_app_dialog_cancel" msgid="7331148618292397166">"Жокко чыгаруу"</string>
-    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"Колдонмолоруңуз батареяны орточо деңгээлде колдонуп жатышат. Эгер алар батареяны өтө көп колдонушса, телефонуңуз ал боюнча чара көрүүнү сунуштайт.\n\nЭгер батареяңыз азайып баратса, каалаган убакта Батареяны үнөмдөгүч режимин күйгүзүп койсоңуз болот."</string>
-    <string name="battery_tip_dialog_summary_message" product="tablet" msgid="1721081030632329647">"Колдонмолоруңуз батареяны орточо деңгээлде колдонуп жатышат. Эгер алар батареяны өтө көп колдонушса, планшетиңиз ал боюнча чара көрүүнү сунуштайт.\n\nЭгер батареяңыз азайып баратса, каалаган убакта Батареяны үнөмдөгүч режимин күйгүзүп койсоңуз болот."</string>
-    <string name="battery_tip_dialog_summary_message" product="device" msgid="146872407040848465">"Колдонмолоруңуз батареяны орточо деңгээлде колдонуп жатышат. Эгер алар батареяны өтө көп колдонушса, түзмөгүңүз ал боюнча чара көрүүнү сунуштайт.\n\nЭгер батареяңыз азайып баратса, каалаган убакта Батареяны үнөмдөгүч режимин күйгүзүп койсоңуз болот."</string>
+    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"Колдонмолоруңуз батареяны орточо деңгээлде керектеп жатышат. Эгер өтө көп керектеп жиберишсе, телефонуңуз ал боюнча чара көрүүнү сунуштайт.\n\nАл эми таптакыр калбай баратса, Батареяны үнөмдөгүчтү күйгүзүп койсоңуз болот."</string>
+    <string name="battery_tip_dialog_summary_message" product="tablet" msgid="1721081030632329647">"Колдонмолоруңуз батареяны орточо деңгээлде керектеп жатышат. Эгер өтө көп керектеп жиберишсе, планшетиңиз ал боюнча чара көрүүнү сунуштайт.\n\nАл эми таптакыр калбай баратса, Батареяны үнөмдөгүчтү күйгүзүп койсоңуз болот."</string>
+    <string name="battery_tip_dialog_summary_message" product="device" msgid="146872407040848465">"Колдонмолоруңуз батареяны орточо деңгээлде керектеп жатышат. Эгер өтө көп керектеп жиберишсе, түзмөгүңүз ал боюнча чара көрүүнү сунуштайт.\n\nАл эми таптакыр калбай баратса, Батареяны үнөмдөгүчтү күйгүзүп койсоңуз болот."</string>
     <string name="smart_battery_manager_title" msgid="5744035036663849515">"Battery Manager"</string>
     <string name="smart_battery_title" msgid="4919670408532804351">"Колдонмолорду автоматтык түрдө башкаруу"</string>
     <string name="smart_battery_summary" msgid="640027046471198174">"Сейрек колдонулган колдонмолор чектелген режимде иштешет"</string>
@@ -2423,12 +2429,12 @@
     <string name="battery_detail_since_full_charge" msgid="3814176986148084378">"Толук кубатталгандан бери канчасы колдонулду:"</string>
     <string name="battery_last_full_charge" msgid="5624033030647170717">"Акыркы жолу толук кубатталды"</string>
     <string name="battery_full_charge_last" msgid="4614554109170251301">"Толук кубатталгандан кийинки иштөө убакыты"</string>
-    <string name="battery_footer_summary" msgid="4828444679643906943">"Батареяны пайдалануу убактысы болжол менен көрсөтүлүп, колдонулушуна жараша өзгөрүшү мүмкүн"</string>
-    <string name="battery_detail_foreground" msgid="6616408559186553085">"Колдонулуп жатканда"</string>
+    <string name="battery_footer_summary" msgid="4828444679643906943">"Батареяны керектөө убактысы болжол менен көрсөтүлүп, түзмөктүн колдонулушуна жараша өзгөрүшү мүмкүн"</string>
+    <string name="battery_detail_foreground" msgid="6616408559186553085">"Активдүү режимде"</string>
     <string name="battery_detail_background" msgid="7938146832943604280">"Фондук режимде"</string>
-    <string name="battery_detail_power_usage" msgid="3606930232257489212">"Батарея колдонулушу"</string>
+    <string name="battery_detail_power_usage" msgid="3606930232257489212">"Батареянын керектелиши"</string>
     <string name="battery_detail_info_title" msgid="4617514228447481336">"Толук кубатталгандан бери"</string>
-    <string name="battery_detail_manage_title" msgid="745194290572617507">"Батареянын колдонулушун башкаруу"</string>
+    <string name="battery_detail_manage_title" msgid="745194290572617507">"Батареянын керектелишин башкаруу"</string>
     <string name="advanced_battery_graph_subtext" msgid="3349760453669664057">"Калган убакыт түзмөктүн колдонулушуна жараша эсептелип, көрсөтүлүүдө."</string>
     <string name="estimated_time_left" msgid="8849913193475011250">"Болжолдуу калган убакыт"</string>
     <string name="estimated_charging_time_left" msgid="7597080379844486777">"Батарея толгонго чейин калган убакыт"</string>
@@ -2446,12 +2452,12 @@
     <string name="battery_saver_auto_routine" msgid="886514412067906980">"Кубаттоо таржымалынын негизинде"</string>
     <string name="battery_saver_auto_percentage" msgid="5791982309331921556">"Кубат деңгээлинин негизинде"</string>
     <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"Кубат деңгээли кубаттала турган убакытка чейин жетпей кала турган болгондо иштетилет"</string>
-    <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"<xliff:g id="PERCENT">%1$s</xliff:g> жеткенде, күйгүзүлөт"</string>
-    <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"Ырааттама түзүү"</string>
+    <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"<xliff:g id="PERCENT">%1$s</xliff:g> жеткенде автоматтык түрдө күйөт"</string>
+    <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"Пландаштыруу"</string>
     <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"Толук кубатталганда өчүрүү"</string>
-    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"Телефон <xliff:g id="PERCENT">%1$s</xliff:g> болгондо, батареяны үнөмдөгүч өчүрүлөт"</string>
-    <string name="battery_saver_sticky_description_new" product="tablet" msgid="3284967694001857194">"Планшет <xliff:g id="PERCENT">%1$s</xliff:g> болгондо, батареяны үнөмдөгүч өчүрүлөт"</string>
-    <string name="battery_saver_sticky_description_new" product="device" msgid="5056520668081504111">"Түзмөк <xliff:g id="PERCENT">%1$s</xliff:g> болгондо, батареяны үнөмдөгүч өчүрүлөт"</string>
+    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"Телефон <xliff:g id="PERCENT">%1$s</xliff:g> жеткенде, батареяны үнөмдөгүч өчүп калат"</string>
+    <string name="battery_saver_sticky_description_new" product="tablet" msgid="3284967694001857194">"Планшет <xliff:g id="PERCENT">%1$s</xliff:g> жеткенде, батареяны үнөмдөгүч өчүп калат"</string>
+    <string name="battery_saver_sticky_description_new" product="device" msgid="5056520668081504111">"Түзмөк <xliff:g id="PERCENT">%1$s</xliff:g> жеткенде, батареяны үнөмдөгүч өчүп калат"</string>
     <!-- no translation found for battery_saver_seekbar_title (7607123201469333645) -->
     <skip />
     <string name="battery_saver_seekbar_title_placeholder" msgid="2321082163892561703">"Күйгүзүү"</string>
@@ -2534,7 +2540,7 @@
     <string name="credentials_settings_not_available" msgid="5490259681690183274">"Бул колдонуучу далдаштырма дайындарын колдоно албайт"</string>
     <string name="credential_for_vpn_and_apps" msgid="2462642486949593841">"VPN жана колдонмолор үчүн орнотулган"</string>
     <string name="credential_for_wifi" msgid="2903295786961726388">"Wi-Fi үчүн орнотулган"</string>
-    <string name="credentials_reset_hint" msgid="3484350477764088169">"Бардык мазмундар өчүрүлсүнбү?"</string>
+    <string name="credentials_reset_hint" msgid="3484350477764088169">"Баарын өчүрөсүзбү?"</string>
     <string name="credentials_erased" msgid="7287088033523869085">"Каттоо маалыматы сакталган жер тазаланды."</string>
     <string name="credentials_not_erased" msgid="9137227570738627637">"Сертификат сактагычты тазалоо мүмкүн эмес."</string>
     <string name="usage_access_title" msgid="7981321142726540574">"Пайдалануу уруксаты бар колдн."</string>
@@ -2574,7 +2580,7 @@
     <string name="add_device_admin" msgid="1621152410207260584">"Түзмөктү башкарган колдонмону иштетүү"</string>
     <string name="device_admin_add_title" msgid="6097881332139146897">"Түзмөктү башкаруу"</string>
     <string name="device_admin_warning" msgid="4421817419326480449">"Түзмөктү башкаруучу колдонмо иштетилгенде, <xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу төмөнкү аракеттерди аткарат:"</string>
-    <string name="device_admin_status" msgid="5424944611789040723">"Администратордун колдонмосу иштетилген жана <xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосуна төмөнкү аракеттерди аткарууга уруксат берет:"</string>
+    <string name="device_admin_status" msgid="5424944611789040723">"Администратордун колдонмосу иштетилип, <xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосуна төмөнкү аракеттерди аткарууга уруксат берет:"</string>
     <string name="profile_owner_add_title" msgid="735805919754362791">"Профиль башкаргычы жандырылсынбы?"</string>
     <string name="adding_profile_owner_warning" msgid="1284541194547382194">"Улантсаңыз, профилиңизди администратор башкарып, ал жеке дайын-даректериңиз менен кошо башка тийиштүү дайындарды да сактап турат.\n\nАдминистратор бул колдонуучунун жөндөөлөрүн, кирүү мүмкүнчүлүгүн, колдонмолорду жана дайындарды, ошондой эле тармактагы аракеттер менен түзмөгүңүздүн жайгашкан жери тууралуу маалыматты көзөмөлдөп, башкара алат."</string>
     <string name="admin_disabled_other_options" msgid="8097063307730025707">"Башка параметрлер администратор тарабынан өчүрүлгөн"</string>
@@ -2617,7 +2623,7 @@
     <string name="sync_contacts" msgid="5687434785723746534">"Байланыштар"</string>
     <string name="sync_plug" msgid="6703804441408427257"><font fgcolor="#ffffffff">"Google sync\'ке кош келиңиз!"</font>" \nБайланыштарды, жолугушууларды жана башкаларды, сиз кайдан болбосун жеткидей кылуунун Google сунуштаган жолу."</string>
     <string name="header_application_sync_settings" msgid="4581847153669774489">"Колдонмонун синхрондошуу тууралоолору"</string>
-    <string name="header_data_and_synchronization" msgid="400831816068697286">"Дайындар жана шайкештирүү"</string>
+    <string name="header_data_and_synchronization" msgid="400831816068697286">"Дайын-даректер жана шайкештирүү"</string>
     <string name="preference_change_password_title" msgid="7243527448378789274">"Сызсөздү өзгөртүү"</string>
     <string name="header_account_settings" msgid="8586173964125512219">"Аккаунттун жөндөөлөрү"</string>
     <string name="remove_account_label" msgid="5885425720323823387">"Аккаунтту алып салуу"</string>
@@ -2665,7 +2671,7 @@
     <string name="data_usage_cellular_data_summary" msgid="9162777397135709280">"Тындырылды (лимит)"</string>
     <string name="account_settings_menu_auto_sync" msgid="2673669556006027506">"Дайындарды авто-шайкештирүү"</string>
     <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"Жеке дайындарды авто-шайкештирүү"</string>
-    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Жумуш дайындарын авто-шайкештирүү"</string>
+    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Жумуш маалыматын автошайкештирүү"</string>
     <string name="data_usage_change_cycle" msgid="447761920472170031">"Циклди өзгөртүү…"</string>
     <string name="data_usage_pick_cycle_day" msgid="6319750879145917066">"Дайындарды колдонуу циклин баштапкы абалга келтире турган күн:"</string>
     <string name="data_usage_empty" msgid="7981405723435034032">"Бул мезгилде колдонмолор трафик сарптаган жок."</string>
@@ -2788,7 +2794,7 @@
     <string name="vpn_always_on_summary" msgid="3639994551631437397">"VPN кызматына ар дайым туташып турсун"</string>
     <string name="vpn_always_on_summary_not_supported" msgid="9077720997795965133">"Бул колдонмодо колдоого алынбайт"</string>
     <string name="vpn_always_on_summary_active" msgid="8962619701962239088">"Иштеп турат"</string>
-    <string name="vpn_require_connection" msgid="5413746839457797350">"VPN кызматынан башка туташуу бөгөттөлсүн"</string>
+    <string name="vpn_require_connection" msgid="5413746839457797350">"VPN\'сиз туташууларга тыюу салуу"</string>
     <string name="vpn_require_connection_title" msgid="8361434328767853717">"VPN туташуусу талап кылынсынбы?"</string>
     <string name="vpn_lockdown_summary" msgid="6770030025737770861">"Дайым туташып туруучу VPN профайл тандаңыз. Бул VPN\'ге кошулганда гана желе трафигине уруксат берилет."</string>
     <string name="vpn_lockdown_none" msgid="3789288793603394679">"Эч бир"</string>
@@ -2844,7 +2850,7 @@
     <string name="user_settings_title" msgid="7917598650933179545">"Бир нече колдонуучу"</string>
     <string name="user_settings_footer_text" product="device" msgid="4573858247439190545">"Жаңы колдонуучуларды кошуу аркылуу түзмөгүңүздү башкалар менен чогуу колдонуңуз. Ар бир колдонуучунун түзмөктө ыңгайлаштырылган Башкы экран, аккаунттар, колдонмолор, жөндөөлөр жана башкалар үчүн жеке мейкиндиги болот."</string>
     <string name="user_settings_footer_text" product="tablet" msgid="780018221428132918">"Жаңы колдонуучуларды кошуу аркылуу планшетиңизди башкалар менен чогуу колдонуңуз. Ар бир колдонуучунун планшетте ыңгайлаштырылган Башкы экран, аккаунттар, колдонмолор, жөндөөлөр жана башкалар үчүн жеке мейкиндиги болот."</string>
-    <string name="user_settings_footer_text" product="default" msgid="1470859614968237491">"Жаңы колдонуучуларды кошуу аркылуу телефонуңузду башкалар менен чогуу колдонуңуз. Ар бир колдонуучунун телефондо ыңгайлаштырылган Башкы экран, аккаунттар, колдонмолор, жөндөөлөр жана башкалар үчүн жеке мейкиндиги болот."</string>
+    <string name="user_settings_footer_text" product="default" msgid="1470859614968237491">"Телефонуңузду бир нече адам менен чогуу пайдалансаңыз болот. Ал үчүн алардын ар бирине профиль түзүп бериңиз. Ар бир колдонуучу өз профилин өзү каалагандай жөндөп алышат (башкы экранын өзгөртүп, аккаунттарын жана колдонмолорун кошуп)."</string>
     <string name="user_list_title" msgid="6670258645246192324">"Колдонуучулар жана профайлдар"</string>
     <string name="user_add_user_or_profile_menu" msgid="4220679989900149336">"Колдонуучу же профиль кошуу"</string>
     <string name="user_add_user_menu" msgid="9006572936456324794">"Колдонуучу кошуу"</string>
@@ -2867,7 +2873,7 @@
     <string name="user_add_user_message_long" msgid="686637203224195465">"Эгер түзмөгүңүздү дагы бир адам колдонуп жаткан болсо, кошумча профилдерди түзүп коюңуз. Профилдин ээси аны өзү каалагандай жөндөп, тушкагаздарды коюп, керектүү колдонмолорду орнотуп алат. Мындан тышкары, колдонуучулар түзмөктүн Wi‑Fi´ды өчүрүү/күйгүзүү сыяктуу жалпы жөндөөлөрүн өзгөртө алат.\n\nПрофиль түзүлгөндөн кийин, аны жөндөп алуу керек.\n\nЖалпы колдонмолорду баары жаңырта алат, бирок атайын мүмкүнчүлүктөр өз-өзүнчө жөндөлөт."</string>
     <string name="user_add_user_message_short" msgid="1802594476285458254">"Жаңы колдонуучу кошулганда, ал өз мейкиндигин түзүп алышы керек.\n\nКолдонмолорду бир колдонуучу жаңыртканда, ал калган бардык колдонуучулар үчүн да жаңырат."</string>
     <string name="user_setup_dialog_title" msgid="6748950002206392396">"Профилди жөндөйсүзбү?"</string>
-    <string name="user_setup_dialog_message" msgid="2988559933258353919">"Өз мейкиндигин жөндөп алышы үчүн түзмөктү колдонуучуга беришиңиз керек."</string>
+    <string name="user_setup_dialog_message" msgid="2988559933258353919">"Өз мейкиндигин жөндөп алышы үчүн, түзмөктү колдонуучуга беришиңиз керек."</string>
     <string name="user_setup_profile_dialog_message" msgid="7611900802824048526">"Профайл азыр түзүлсүнбү?"</string>
     <string name="user_setup_button_setup_now" msgid="4941459406266856176">"Азыр түзүү"</string>
     <string name="user_setup_button_setup_later" msgid="6596031428556518752">"Азыр эмес"</string>
@@ -2903,7 +2909,7 @@
     <string name="user_enable_calling_confirm_message" msgid="2490126715153125970">"Чалуулар таржымалы бул колдонуучу менен бөлүшүлөт."</string>
     <string name="user_enable_calling_and_sms_confirm_title" msgid="4153856398523366976">"Чалуулар менен SMS иштетилсинби?"</string>
     <string name="user_enable_calling_and_sms_confirm_message" msgid="3278802798876095734">"Чалуулар жана SMS таржымалы бул колдонуучу менен бөлүшүлөт."</string>
-    <string name="emergency_info_title" msgid="1522609271881425375">"Өзгөчө кырдаал жөнүндө маалымат"</string>
+    <string name="emergency_info_title" msgid="1522609271881425375">"Кырсыктаганда керек болчу маалымат"</string>
     <string name="emergency_info_summary" msgid="7280464759837387342">"<xliff:g id="USER_NAME">%1$s</xliff:g> жөнүндө маалымат жана байланыштар"</string>
     <string name="application_restrictions" msgid="6871981013736536763">"Колдонмолорго жана мазмунга уруксат"</string>
     <string name="apps_with_restrictions_header" msgid="8656739605673756176">"Чектелген колдонмолор"</string>
@@ -2916,10 +2922,10 @@
     <string name="nfc_payment_app_and_desc" msgid="102312684211458190">"<xliff:g id="APP">%1$s</xliff:g> - <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="nfc_payment_use_default" msgid="3098724195746409476">"Демейкини колдонуу"</string>
     <string name="nfc_payment_favor_default" msgid="7555356982142464260">"Ар дайым"</string>
-    <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Акы төлөнүүчү башка колдонмо ачылып турган учурларды эске албаганда"</string>
+    <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Башка төлөм колдонмосу ачылып турбаса"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"Аралыктан төлөө терминалында төмөнкүнү колдонуу:"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Терминалдан акы төлөө"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Акы төлөнүүчү колдонмону жөндөп туруп, телефондун арткы бетин колду тийгизбей туруп төлөө белгиси түшүрүлгөн терминалга ыктап кармап туруңуз."</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Төлөм колдонмосун жөндөп туруп, телефондун арткы бетин тийбей төлөө белгиси түшүрүлгөн терминалга жакындатыңыз."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"Түшүндүм"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"Дагы…"</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"Сиздин тандооңуз катары орнотулсунбу?"</string>
@@ -2988,7 +2994,7 @@
     <string name="sim_cellular_data_unavailable_summary" msgid="3093797406601964131">"Мобилдик Интернет үчүн SIM картаны тандоо үчүн таптап коюңуз"</string>
     <string name="sim_calls_always_use" msgid="5322696995795851734">"Бул нерсе дайым чалуулр үчүн колдонулсн"</string>
     <string name="select_sim_for_data" msgid="2099705792885526394">"Дайындар үчүн SIM тандаңыз"</string>
-    <string name="select_sim_for_sms" msgid="2481682560233370731">"SMS жөнөтүү үчүн SIM-картаны тандаңыз"</string>
+    <string name="select_sim_for_sms" msgid="2481682560233370731">"SMS жөнөтүү үчүн SIM картаны тандаңыз"</string>
     <string name="data_switch_started" msgid="4517966162053949265">"Дайындар SIM\'и которулууда, бул бир мүнөткө чейин созулушу мүмкүн…"</string>
     <string name="select_sim_for_calls" msgid="131091573472832807">"Төмөнкү менен чалуу"</string>
     <string name="sim_select_card" msgid="5558215843972182767">"SIM карта тандаңыз"</string>
@@ -3019,7 +3025,7 @@
     <string name="sim_pref_divider" msgid="4967718397875240190">"Төмөнкү үчүн тандалган SIM"</string>
     <string name="sim_calls_ask_first_prefs_title" msgid="8209265235625420102">"Чалган сайын сурасын"</string>
     <string name="sim_selection_required_pref" msgid="8738591348923992419">"Тандоо керек"</string>
-    <string name="sim_selection_channel_title" msgid="5671915549529226023">"SIM-картаны тандоо"</string>
+    <string name="sim_selection_channel_title" msgid="5671915549529226023">"SIM картаны тандоо"</string>
     <string name="dashboard_title" msgid="3343056553551876215">"Жөндөөлөр"</string>
     <plurals name="settings_suggestion_header_summary_hidden_items" formatted="false" msgid="4475734332610696843">
       <item quantity="other">Жашырылган %d нерсе көрсөтүлсүн</item>
@@ -3027,9 +3033,9 @@
     </plurals>
     <string name="network_dashboard_title" msgid="8288134139584687806">"Тармак жана Интернет"</string>
     <string name="network_dashboard_summary_mobile" msgid="5560545061217580626">"мобилдик"</string>
-    <string name="network_dashboard_summary_data_usage" msgid="4695629715072542102">"дайындардын колдонулушу"</string>
+    <string name="network_dashboard_summary_data_usage" msgid="4695629715072542102">"дайын-даректердин өткөрүлүшү"</string>
     <string name="network_dashboard_summary_hotspot" msgid="3928610802321995214">"байланыш түйүнү"</string>
-    <string name="connected_devices_dashboard_title" msgid="7795222675849060444">"Туташкан түзмөктөр"</string>
+    <string name="connected_devices_dashboard_title" msgid="7795222675849060444">"Байланышкан түзмөктөр"</string>
     <string name="connected_devices_dashboard_summary" msgid="1072664369515033179">"Bluetooth, айдоо режими, NFC"</string>
     <string name="connected_devices_dashboard_no_nfc_summary" msgid="2610085597733526722">"Bluetooth, айдоо режими"</string>
     <string name="connected_devices_dashboard_no_driving_mode_summary" msgid="3524409078596318803">"Bluetooth, NFC"</string>
@@ -3117,7 +3123,7 @@
     <string name="keywords_assist_input" msgid="8392362788794886564">"демейки, жардамчы"</string>
     <string name="keywords_default_payment_app" msgid="845369409578423996">"төлөм, демейки"</string>
     <string name="keywords_ambient_display" msgid="8835182491798487184">"кирүүчү эскертме"</string>
-    <string name="keywords_hotspot_tethering" msgid="1723591462602613867">"usb аркылуу туташуу, bluetooth аркылуу туташуу, wifi хотспоту"</string>
+    <string name="keywords_hotspot_tethering" msgid="1723591462602613867">"usb аркылуу туташуу, bluetooth аркылуу туташуу, wifi байланыш түйүнү"</string>
     <string name="keywords_touch_vibration" msgid="2081175517528255224">"сенсорлор, дирилдөө, экран, сезгичтик"</string>
     <string name="keywords_ring_vibration" msgid="4210509151866460210">"сенсорлор, дирилдөө, телефон, чалуу, сезгичтик, шыңгыратуу"</string>
     <string name="keywords_notification_vibration" msgid="1077515502086745166">"сенсорлор, дирилдөө, сезгичтик"</string>
@@ -3128,10 +3134,10 @@
     <string name="sound_settings_summary_vibrate" msgid="2194491116884798590">"Коңгуроо дирилдейт"</string>
     <string name="sound_settings_summary_silent" msgid="899823817462768876">"Коңгуроонун үнү өчүрүлгөн"</string>
     <string name="sound_settings_example_summary" msgid="2091822107298841827">"Шыңгырдын катуулугу 80%"</string>
-    <string name="media_volume_option_title" msgid="3553411883305505682">"Мультимедианын үнү"</string>
+    <string name="media_volume_option_title" msgid="3553411883305505682">"Мультимедианын катуулугу"</string>
     <string name="remote_media_volume_option_title" msgid="6355710054191873836">"Үндү алыстан башкаруу"</string>
-    <string name="call_volume_option_title" msgid="5028003296631037334">"Чалуунун үнү"</string>
-    <string name="alarm_volume_option_title" msgid="3184076022438477047">"Ойготкучтун үнү"</string>
+    <string name="call_volume_option_title" msgid="5028003296631037334">"Сүйлөшүү"</string>
+    <string name="alarm_volume_option_title" msgid="3184076022438477047">"Ойготкучтун катуулугу"</string>
     <string name="ring_volume_option_title" msgid="2038924918468372264">"Шыңгырдын үнү"</string>
     <string name="notification_volume_option_title" msgid="1358512611511348260">"Эскертме үнүнүн катуулугу"</string>
     <string name="ringtone_title" msgid="1409086028485922583">"Телефондун шыңгыры"</string>
@@ -3145,7 +3151,7 @@
     <string name="screen_locking_sounds_title" msgid="4407110895465866809">"Экран кулпуланганда үн чыксын"</string>
     <string name="charging_sounds_title" msgid="5070437987230894287">"Кубаттоо үндөрү жана дирилдөө"</string>
     <string name="docking_sounds_title" msgid="2573137471605541366">"Жалгаштыруу үндөрү"</string>
-    <string name="touch_sounds_title" msgid="165237488496165652">"Экранга тийгенде үн чыксын"</string>
+    <string name="touch_sounds_title" msgid="165237488496165652">"Экранга тийгенде чыккан үндөр"</string>
     <string name="vibrate_on_touch_title" msgid="6360155469279157684">"Тийгенде дирилдейт"</string>
     <string name="vibrate_on_touch_summary" msgid="5504424764028676043">"Баскычтарды басканда, баскычтопко тийгенде ж.б. учурларда дирилдейт"</string>
     <string name="dock_audio_media_title" msgid="1859521680502040781">"Док катуу сүйлөткүч ойнотот"</string>
@@ -3190,16 +3196,16 @@
     <string name="zen_mode_visual_signals_settings_subtitle" msgid="6608239691864638854">"Визуалдык сигнал иштетилсин"</string>
     <string name="zen_mode_settings_category" msgid="5601680733422424922">"\"Тынчымды алба\" режими күйүп турганда"</string>
     <string name="zen_mode_restrict_notifications_title" msgid="7486753018073540477">"Билдирмелерди чектөө"</string>
-    <string name="zen_mode_restrict_notifications_mute" msgid="2673665450311184875">"Билдирмелердин добушу чыкпайт"</string>
+    <string name="zen_mode_restrict_notifications_mute" msgid="2673665450311184875">"Билдирмелердин үнү чыкпайт"</string>
     <string name="zen_mode_restrict_notifications_mute_summary" msgid="1696217042353376674">"Билдирмелерди экранда көрөсүз"</string>
     <string name="zen_mode_restrict_notifications_mute_footer" msgid="3049522809520549054">"Билдирмелер келгенде телефонуңуздун үнү чыкпайт же дирилдебейт."</string>
     <string name="zen_mode_restrict_notifications_hide" msgid="3296933643539682552">"Билдирмелерди көрбөйсүз да, укпайсыз"</string>
     <string name="zen_mode_restrict_notifications_hide_summary" msgid="1449301153755270168">"Билдирмелерди көрбөйсүз да, укпайсыз"</string>
-    <string name="zen_mode_restrict_notifications_hide_footer" msgid="7617688597593946765">"Жаңы же учурдагы билдирмелер көрүнбөйт, телефондун үнү чыкпайт же дирилдебейт. Бирок телефондун негизги функцияларынын иштеши үчүн керектүү маанилүү билдирмелерди ала бересиңер.\n\n\"Тынчымды алба\" режими өчүрүлгөндөн кийин, жашырылган билдирмелерди көрүү үчүн экранды ылдый сүрүп коюңуз."</string>
+    <string name="zen_mode_restrict_notifications_hide_footer" msgid="7617688597593946765">"Жаңы же учурдагы билдирмелер көрүнбөйт, телефондун үнү чыкпайт же дирилдебейт. Бирок телефондун негизги функцияларынын иштеши үчүн керектүү болгон билдирмелерди ала бересиңер.\n\n\"Тынчымды алба\" режими өчүрүлгөндөн кийин, жашырылган билдирмелерди көрүү үчүн экранды ылдый сүрүп коюңуз."</string>
     <string name="zen_mode_restrict_notifications_custom" msgid="3167252482570424133">"Ыңгайлаштырылган"</string>
     <string name="zen_mode_restrict_notifications_enable_custom" msgid="6376983315529894440">"Ыңгайлаштырылган жөндөөнү иштетүү"</string>
     <string name="zen_mode_restrict_notifications_disable_custom" msgid="8004212081465043044">"Ыңгайлаштырылган жөндөөнү алып салуу"</string>
-    <string name="zen_mode_restrict_notifications_summary_muted" msgid="1075196788469381282">"Билдирмелердин добушу чыкпайт"</string>
+    <string name="zen_mode_restrict_notifications_summary_muted" msgid="1075196788469381282">"Билдирмелердин үнү чыкпайт"</string>
     <string name="zen_mode_restrict_notifications_summary_custom" msgid="4982187708274505748">"Жарым-жартылай жашырылган"</string>
     <string name="zen_mode_restrict_notifications_summary_hidden" msgid="7637206880685474111">"Билдирмелерди көрбөйсүз да, укпайсыз"</string>
     <string name="zen_mode_what_to_block_title" msgid="2142809942549840800">"Ыңгайлаштырылган чектөөлөр"</string>
@@ -3225,7 +3231,7 @@
     <string name="zen_mode_add" msgid="2533484377786927366">"Кошуу"</string>
     <string name="zen_mode_enable_dialog_turn_on" msgid="6396050543542026184">"Күйгүзүү"</string>
     <string name="zen_mode_button_turn_on" msgid="1097964136225943415">"Күйгүзүү"</string>
-    <string name="zen_mode_button_turn_off" msgid="3990967728457149454">"Азыр өчүрүлсүн"</string>
+    <string name="zen_mode_button_turn_off" msgid="3990967728457149454">"Өчүрүү"</string>
     <string name="zen_mode_settings_dnd_manual_end_time" msgid="4307574188962071429">"<xliff:g id="FORMATTED_TIME">%s</xliff:g> чейин \"Тынчымды алба\" режими күйгүзүлгөн"</string>
     <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"Өзүңүз өчүрмөйүнчө, \"Тынчымды алба\" режими күйүп турат"</string>
     <string name="zen_mode_settings_dnd_automatic_rule" msgid="2843297614114625408">"\"Тынчымды алба\" режими автоматтык түрдө <xliff:g id="RULE_NAME">%s</xliff:g> ырааттамасына ылайык күйгүзүлдү"</string>
@@ -3270,7 +3276,7 @@
     <string name="zen_onboarding_ok" msgid="6403635918125323678">"Бүттү"</string>
     <string name="zen_onboarding_settings" msgid="1416466597876383322">"Жөндөөлөр"</string>
     <string name="zen_onboarding_new_setting_title" msgid="3622673375041304362">"Билдирмелерди көрбөйсүз да, укпайсыз"</string>
-    <string name="zen_onboarding_current_setting_title" msgid="2560330551761407563">"Билдирмелердин добушу чыкпайт"</string>
+    <string name="zen_onboarding_current_setting_title" msgid="2560330551761407563">"Билдирмелердин үнү чыкпайт"</string>
     <string name="zen_onboarding_new_setting_summary" msgid="8264430315983860075">"Билдирмелерди көрбөйсүз да, укпайсыз. Жылдызчаланган байланыштарга жана кайталап чалгандарга уруксат берилди."</string>
     <string name="zen_onboarding_current_setting_summary" msgid="3569246708507270821">"(Учурдагы жөндөө)"</string>
     <string name="zen_onboarding_dnd_visual_disturbances_header" msgid="7584229011611927613">"\"Тынчымды алба\" режиминин билдирмелеринин жөндөөлөрү өзгөртүлсүнбү?"</string>
@@ -3411,7 +3417,7 @@
     <string name="notification_toggle_on" msgid="5119816745741139542">"Күйүк"</string>
     <string name="notification_toggle_off" msgid="5289843670514922751">"Өчүк"</string>
     <string name="app_notification_block_title" msgid="7898269373875294367">"Баарын бөгөттөө"</string>
-    <string name="app_notification_block_summary" msgid="4502146897785692336">"Бул билдирмелер эч качан көрсөтүлбөсүн"</string>
+    <string name="app_notification_block_summary" msgid="4502146897785692336">"Бул билдирмелер эч качан көрүнбөсүн"</string>
     <string name="notification_content_block_title" msgid="2805138591864484587">"Билдирмелер"</string>
     <string name="notification_content_block_summary" msgid="2743896875255591743">"Билдирмелер эч качан фондо же тышкы түзмөктөрдө көрүнбөсүн"</string>
     <string name="notification_badge_title" msgid="8989086619255666442">"Билдирмелер белгиси көрүнсүн"</string>
@@ -3571,7 +3577,7 @@
     <string name="encryption_interstitial_yes" msgid="1839339586101502601">"Ооба"</string>
     <string name="encryption_interstitial_no" msgid="6517277668879344227">"Жок"</string>
     <string name="restricted_true_label" msgid="1545180379083441282">"Чектелген"</string>
-    <string name="restricted_false_label" msgid="4512495920090068495">"Колдонмо батареяны фондо колдоно алат"</string>
+    <string name="restricted_false_label" msgid="4512495920090068495">"Колдонмо батареяны фондо керектей алат"</string>
     <string name="encrypt_talkback_dialog_require_pin" msgid="2781758476498571031">"PIN талап кылынсынбы?"</string>
     <string name="encrypt_talkback_dialog_require_pattern" msgid="8705104812047332411">"Үлгү талап кылынсынбы?"</string>
     <string name="encrypt_talkback_dialog_require_password" msgid="5070710417271353306">"Сырсөз талап кылынсынбы?"</string>
@@ -3674,7 +3680,7 @@
     <string name="apps_storage" msgid="5658466038269046038">"Колдонмолор кампасы"</string>
     <string name="usage_access" msgid="2023443456361489516">"Колдонуу таржымалын көрүү"</string>
     <string name="permit_usage_access" msgid="3321727608629752758">"Колдонуу мүмкүнчүлүгүнө уруксат берүү"</string>
-    <string name="app_usage_preference" msgid="5691545073101551727">"Колдонмону пайдалануунун жеке жөндөөлөрү"</string>
+    <string name="app_usage_preference" msgid="5691545073101551727">"Колдонмону пайдалануунун жөндөөлөрү"</string>
     <string name="time_spent_in_app_pref_title" msgid="2803186835902798451">"Түзмөктү колдонуу убакыты"</string>
     <string name="usage_access_description" msgid="2178083292760305207">"Колдонуу таржымалы аркылуу кайсы колдонмолор канчалык көп колдонула турганын, ошондой эле байланыш операторуңузду, тил жөндөөлөрүн жана башка параметрлерди көрө аласыз."</string>
     <string name="memory_settings_title" msgid="7867148522014070721">"Эстутум"</string>
@@ -3706,7 +3712,7 @@
     <string name="high_power_system" msgid="739584574711292753">"Кубатты үнөмдөөнү иштетүү мүмкүн эмес"</string>
     <string name="high_power_desc" msgid="333756885680362741">"Батареянын кубаты үнөмдөлбөсүн. Батареяңыз тез эле отуруп калышы мүмкүн."</string>
     <string name="high_power_prompt_title" msgid="2805745781720454052">"Колдонмо фондо тынымсыз иштей берсинби?"</string>
-    <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу фондо тынымсыз иштей берсе, батареянын кубаты тез сарпталышы мүмкүн. \n\nАны кийинчерээк Жөндөөлөр, Колдонмолор жана билдирмелер бөлүмүнөн өзгөртсөңүз болот."</string>
+    <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу фондо тынымсыз иштей берсе, батарея бат отуруп калышы мүмкүн. \n\nАны кийинчерээк Жөндөөлөр, Колдонмолор жана билдирмелер бөлүмүнөн өзгөртсөңүз болот."</string>
     <string name="battery_summary" msgid="4345690800899981339">"Акыркы жолу толук кубатталгандан бери <xliff:g id="PERCENTAGE">%1$s</xliff:g> сарпталды"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"Батареянын кубатын башкаруу"</string>
     <string name="no_battery_summary" msgid="4105932628367471314">"Акыркы жолу толук кубатталгандан бери батарея керектеле элек"</string>
@@ -3734,7 +3740,7 @@
     <string name="usb_default_label" msgid="7471316635263936101">"USB\'нин демейки конфигурациясы"</string>
     <string name="usb_default_info" msgid="953775292571786528">"Телефонуңуз башка түзмөккө туташып, кулпуланбай турганда, ушул жөндөөлөр колдонулат. Телефонуңузду ишенимдүү түзмөктөргө гана туташтырыңыз."</string>
     <string name="usb_pref" msgid="6194821550693495068">"USB"</string>
-    <string name="usb_preference" msgid="7092987095048592826">"USB\'нин жеке жөндөөлөрү"</string>
+    <string name="usb_preference" msgid="7092987095048592826">"USB\'нин жөндөөлөрү"</string>
     <string name="usb_control_title" msgid="2379698856760894768">"USB\'ни көзөмөлдөгөн түзмөк:"</string>
     <string name="usb_control_host" msgid="193292043691034178">"Туташкан түзмөк"</string>
     <string name="usb_control_device" msgid="9154790265254725254">"Ушул түзмөк"</string>
@@ -3753,9 +3759,9 @@
     <string name="background_check_pref" msgid="664081406854758392">"Фондо текшерүү"</string>
     <string name="background_check_title" msgid="4136736684290307970">"Фондук режимде толук мүмкүнчүлүк"</string>
     <string name="assist_access_context_title" msgid="2274614501747710439">"Экрандагы текстти колдонуу"</string>
-    <string name="assist_access_context_summary" msgid="5867997494395842785">"Көмөкчү колдонмого экрандагы текстти колдонууга уруксат бересиз"</string>
+    <string name="assist_access_context_summary" msgid="5867997494395842785">"Көмөкчү колдонмого экрандагы текстти көрүү мүмкүнчүлүгүн бересиз"</string>
     <string name="assist_access_screenshot_title" msgid="1991014038776117688">"Скриншот колдонуу"</string>
-    <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Көмөкчү колдонмого экрандагы сүрөттү колдонууга уруксат бересиз"</string>
+    <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Көмөкчү колдонмого экрандагы сүрөттү көрүү мүмкүнчүлүгүн бересиз"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"Экран жаркылдасын"</string>
     <string name="assist_flash_summary" msgid="6697095786317559129">"Көмөкчү колдонмо скриншотту же текстти колдонуу мүмкүнчүлүгүн алганда, экрандын чети жаркылдайт"</string>
     <string name="assist_footer" msgid="7030121180457472165">"Көмөкчү колдонмолор экрандагы маалымат менен иштейт. Айрым колдонмолордо үн буйруктары жана жүргүзгүч тактасы колдоого алынат."</string>
@@ -3798,7 +3804,7 @@
     <string name="system_alert_window_apps_title" msgid="9188448296493699566">"Колдонмолор"</string>
     <string name="system_alert_window_access_title" msgid="5187343732185369675">"Башка терезелердин үстүнөн көрсөтүү"</string>
     <string name="permit_draw_overlay" msgid="9039092257052422344">"Башка терезелердин үстүнөн көрсөтүүгө уруксат"</string>
-    <string name="allow_overlay_description" msgid="6669524816705082807">"Бул колдонмону башка терезелердин үстүнөн көрсөтүүгө уруксат бериңиз. Бирок башка колдонмолорду пайдаланууга тоскоол болуп же алардын интерфейсин бузуп салышы мүмкүн."</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="overlay_settings" msgid="3325154759946433666">"Башка терезел-н үст-н көрсөтүү"</string>
@@ -3825,7 +3831,7 @@
     <string name="camera_double_tap_power_gesture_title" msgid="8874747801078147525">"Камера үчүн кубат баскычын эки басыңыз"</string>
     <string name="camera_double_tap_power_gesture_desc" msgid="6166349645433682873">"Камераны экраныңыздын кулпусун ачпастан, тез эле ачып алыңыз"</string>
     <string name="screen_zoom_title" msgid="164369086350486104">"Көрсөтүлүүчү өлчөмү"</string>
-    <string name="screen_zoom_short_summary" msgid="5508079362742276703">"Экрандагы нерселерди чоңойтуп же кичирейтиңиз"</string>
+    <string name="screen_zoom_short_summary" msgid="5508079362742276703">"Экрандагы нерселерди чоңойтуп же кичирейтесиз"</string>
     <string name="screen_zoom_keywords" msgid="8358462497896524092">"дисплей тыгыздыгы, экранды чоңойтуу, шкла, шкалалоо"</string>
     <string name="screen_zoom_summary" msgid="5294003755961312560">"Экраныңыздагы нерселерди кичирейтип же чоңойтуңуз. Экраныңыздагы айрым колдонмолордун орду өзгөрүшү мүмкүн."</string>
     <string name="screen_zoom_preview_title" msgid="2924312934036753091">"Алдын ала көрүү"</string>
@@ -3865,7 +3871,7 @@
     <string name="backup_disabled" msgid="6941165814784765643">"Камдык көчүрмө өчүрүлгөн"</string>
     <string name="android_version_summary" msgid="2192751442789395445">"Android <xliff:g id="VERSION">%1$s</xliff:g> версиясына жаңырды"</string>
     <string name="android_version_pending_update_summary" msgid="3554543810520655076">"Жаңы версия бар"</string>
-    <string name="disabled_by_policy_title" msgid="1238318274952958846">"Аракетке уруксат жок"</string>
+    <string name="disabled_by_policy_title" msgid="1238318274952958846">"Аракетке тыюу салынган"</string>
     <string name="disabled_by_policy_title_adjust_volume" msgid="7094547090629203316">"Үнү өзгөртүлбөйт"</string>
     <string name="disabled_by_policy_title_outgoing_calls" msgid="3805836913095496278">"Чалууга тыюу салынган"</string>
     <string name="disabled_by_policy_title_sms" msgid="1453236584236681105">"SMS жөнөтүүгө тыюу салынган"</string>
@@ -3938,9 +3944,9 @@
     <string name="ethernet_data_template" msgid="6414118030827090119">"<xliff:g id="AMOUNT">^1</xliff:g> Ethernet дайындары"</string>
     <string name="billing_cycle" msgid="5740717948341713190">"Трафик жана чектөөлөр"</string>
     <string name="app_usage_cycle" msgid="213483325132959663">"Статистика цикли"</string>
-    <string name="cell_data_warning" msgid="8902740337286652689">"Трафик тууралуу эскертүү: <xliff:g id="ID_1">^1</xliff:g>"</string>
-    <string name="cell_data_limit" msgid="3175933829235314233">"Трафикти чектөө: <xliff:g id="ID_1">^1</xliff:g>"</string>
-    <string name="cell_data_warning_and_limit" msgid="3846150001253927594">"Трафик тууралуу эскертүү: <xliff:g id="ID_1">^1</xliff:g> / Трафикти чектөө: <xliff:g id="ID_2">^2</xliff:g>"</string>
+    <string name="cell_data_warning" msgid="8902740337286652689">"Качан эскертүү берилет: <xliff:g id="ID_1">^1</xliff:g>"</string>
+    <string name="cell_data_limit" msgid="3175933829235314233">"Трафик чектелген: <xliff:g id="ID_1">^1</xliff:g>"</string>
+    <string name="cell_data_warning_and_limit" msgid="3846150001253927594">"Качан эскертүү берилет: <xliff:g id="ID_1">^1</xliff:g> / Трафик чектелген: <xliff:g id="ID_2">^2</xliff:g>"</string>
     <string name="billing_cycle_fragment_summary" msgid="4926047002107855543">"Ай сайын <xliff:g id="ID_1">%1$s</xliff:g> күнү"</string>
     <string name="network_restrictions" msgid="196294262243618198">"Тармак чектөөлөрү"</string>
     <plurals name="network_restrictions_summary" formatted="false" msgid="1664494781594839837">
@@ -3976,7 +3982,7 @@
     <string name="carrier_and_update_text" msgid="4100603877929297103">"<xliff:g id="ID_1">^1</xliff:g> тарабынан <xliff:g id="ID_2">^2</xliff:g> мурда жаңырды"</string>
     <string name="no_carrier_update_text" msgid="8797522203060970532">"<xliff:g id="ID_1">^2</xliff:g> мурда жаңырды"</string>
     <string name="carrier_and_update_now_text" msgid="7619705504438908034">"<xliff:g id="ID_1">^1</xliff:g> тарабынан жаңы эле жаңырды"</string>
-    <string name="no_carrier_update_now_text" msgid="4405472895804759042">"Азыр эле жаңырды"</string>
+    <string name="no_carrier_update_now_text" msgid="4405472895804759042">"Жаңы эле жаңырды"</string>
     <string name="launch_mdp_app_text" msgid="9186559496664208252">"Планды көрүү"</string>
     <string name="launch_wifi_text" msgid="317820210431682605">"Кеңири маалымат"</string>
     <string name="data_saver_title" msgid="7903308134514179256">"Трафикти үнөмдөө"</string>
@@ -3996,10 +4002,10 @@
     <string name="suggestion_additional_fingerprints" msgid="3434467207282466411">"Дагы бир манжа изин кошуңуз"</string>
     <string name="suggestion_additional_fingerprints_summary" msgid="1916547587832484196">"Кулпуну башка манжа менен ачуу"</string>
     <string name="battery_saver_on_summary" msgid="6841062406467435672">"Күйүк"</string>
-    <string name="battery_saver_off_scheduled_summary" msgid="3740414764069188669">"<xliff:g id="BATTERY_PERCENTAGE">%1$s</xliff:g> жеткенде, күйгүзүлөт"</string>
+    <string name="battery_saver_off_scheduled_summary" msgid="3740414764069188669">"<xliff:g id="BATTERY_PERCENTAGE">%1$s</xliff:g> жеткенде автоматтык түрдө күйөт"</string>
     <string name="battery_saver_off_summary" msgid="8736555723004299721">"Өчүк"</string>
     <string name="battery_saver_button_turn_on" msgid="3748696527267573793">"Күйгүзүү"</string>
-    <string name="battery_saver_button_turn_off" msgid="2912950982503267828">"Азыр өчүрүлсүн"</string>
+    <string name="battery_saver_button_turn_off" msgid="2912950982503267828">"Өчүрүү"</string>
     <string name="not_battery_optimizing" msgid="2616044774307734160">"Батареянын кубатын үнөмдөө функциясы колдонулбай эле"</string>
     <string name="lockscreen_remote_input" msgid="3363310613165354434">"Түзмөк кулпуланып турса, эскертмелерде жооптор жана башка тексттер жазылбасын"</string>
     <string name="default_spell_checker" msgid="8636661093243189533">"Демейки орфография текшергич"</string>
@@ -4099,36 +4105,36 @@
     <string name="automatic_storage_manager_preference_title" msgid="4668642150512639466">"Сактагычты көзөмөлдөгүч"</string>
     <string name="automatic_storage_manager_master_switch_title" msgid="1456978117739582562">"Сактагычты көзөмөлдөгүчтү колдонуу"</string>
     <string name="deletion_helper_automatic_title" msgid="4370975149425263205">"Автоматтык"</string>
-    <string name="deletion_helper_manual_title" msgid="1011785013431162078">"Нускама"</string>
+    <string name="deletion_helper_manual_title" msgid="1011785013431162078">"Кол менен"</string>
     <string name="deletion_helper_preference_title" msgid="797270307034242206">"Орун бошотуу"</string>
     <string name="gesture_preference_title" msgid="583646591518373785">"Жаңсоолор"</string>
     <string name="gesture_preference_summary" product="default" msgid="2990736567599191163">"Телефонуңузду көзөмөлдөй турган ыкчам жаңсоолор"</string>
     <string name="gesture_preference_summary" product="tablet" msgid="8303793594714075580">"Планшетиңизди көзөмөлдөй турган ыкчам жаңсоолор"</string>
     <string name="gesture_preference_summary" product="device" msgid="7792199669106960922">"Түзмөгүңүздү көзөмөлдөй турган ыкчам жаңсоолор"</string>
     <string name="double_tap_power_for_camera_title" msgid="5480829329052517484">"Камерага өтүү"</string>
-    <string name="double_tap_power_for_camera_summary" msgid="6591026425496323965">"Камераны тез ачуу үчүн каалаган экрандан кубат баскычын эки жолу басыңыз."</string>
+    <string name="double_tap_power_for_camera_summary" msgid="6591026425496323965">"Камераны тез ачуу үчүн, каалаган экрандан кубат баскычын эки жолу басыңыз."</string>
     <string name="double_tap_power_for_camera_suggestion_title" msgid="509078029429865036">"Камераны тез ачуу"</string>
     <string name="double_twist_for_camera_mode_title" msgid="2606032140297556018">"Камераны которуштуруу"</string>
     <string name="double_twist_for_camera_mode_summary" msgid="8979914206876018137"></string>
     <string name="double_twist_for_camera_suggestion_title" msgid="5932411386316771246">"Селфилерди тез тартуу"</string>
-    <string name="swipe_up_to_switch_apps_summary" msgid="4644068184114154787">"Колдонмолорду которуштуруу үчүн Башкы бет баскычын өйдө сүрүп коюңуз. Бардык колдонмолорду көрүү үчүн кайра өйдө сүрүп коюңуз. Бардык экрандарда иштейт. Мындан ары экраныңыздын төмөнкү оң жагында Сереп салуу баскычы болбойт."</string>
+    <string name="swipe_up_to_switch_apps_summary" msgid="4644068184114154787">"Башка колдонмого которулуу үчүн, Башкы бет баскычын басып, өйдө сүрүңүз. Бардык колдонмолорду көрүү үчүн, дагы бир жолу өйдө сүрүп коюңуз. Бул жаңсоо бардык экрандарда иштейт. Мындан ары экраныңыздын төмөнкү оң жагында Сереп салуу баскычы болбойт."</string>
     <string name="swipe_up_to_switch_apps_suggestion_title" msgid="7641846365137536128">"Жаңы Башкы бет баскычын колдонуп көрүңүз"</string>
-    <string name="swipe_up_to_switch_apps_suggestion_summary" msgid="7338653224520387852">"Колдонмолорду которуштуруу үчүн жаңы жаңсоону күйгүзүңүз"</string>
+    <string name="swipe_up_to_switch_apps_suggestion_summary" msgid="7338653224520387852">"Башка колдонмого которулуу үчүн,, жаңы жаңсоону күйгүзүңүз"</string>
     <string name="ambient_display_title" product="default" msgid="6785677099744344088">"Убакытты жана билдирмелерди текшерүү үчүн эки жолу басуу"</string>
     <string name="ambient_display_title" product="tablet" msgid="1106285490888683613">"Планшетти текшерүү үчүн эки жолу таптаңыз"</string>
     <string name="ambient_display_title" product="device" msgid="5064644474876041478">"Түзмөктү текшерүү үчүн эки жолу таптаңыз"</string>
-    <string name="ambient_display_summary" msgid="4882910328216411109">"Убакытты, билдирмелерди жана башка маалыматты көрүү үчүн экраныңызды эки жолу таптаңыз."</string>
+    <string name="ambient_display_summary" msgid="4882910328216411109">"Убакытты, билдирмелерди жана башка маалыматты көрүү үчүн, экраныңызды эки жолу таптаңыз."</string>
     <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"Билдирмелерди текшерүү үчүн телефонду көтөрүү"</string>
     <string name="ambient_display_pickup_title" product="tablet" msgid="1555456400210301959">"Планшетти текшерүү үчүн көтөрүңүз"</string>
     <string name="ambient_display_pickup_title" product="device" msgid="2480126522988135037">"Түзмөктү текшерүү үчүн көтөрүңүз"</string>
     <string name="ambient_display_wake_screen_title" msgid="3376988352851077102">"Дисплейди ачуу"</string>
-    <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"Убакытты, билдирмелерди жана башка маалыматты көрүү үчүн телефонуңузду колуңузга алыңыз."</string>
-    <string name="ambient_display_pickup_summary" product="tablet" msgid="1077745287100012928">"Убакытты, билдирмелерди жана башка маалыматты көрүү үчүн планшетиңизди колуңузга алыңыз."</string>
-    <string name="ambient_display_pickup_summary" product="device" msgid="404199660076598026">"Убакытты, билдирмелерди жана башка маалыматты көрүү үчүн түзмөгүңүздү колуңузга алыңыз."</string>
+    <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"Убакытты, билдирмелерди жана башка маалыматты көрүү үчүн, телефонуңузду колуңузга алыңыз."</string>
+    <string name="ambient_display_pickup_summary" product="tablet" msgid="1077745287100012928">"Убакытты, билдирмелерди жана башка маалыматты көрүү үчүн, планшетиңизди колуңузга алыңыз."</string>
+    <string name="ambient_display_pickup_summary" product="device" msgid="404199660076598026">"Убакытты, билдирмелерди жана башка маалыматты көрүү үчүн, түзмөгүңүздү колуңузга алыңыз."</string>
     <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"Телефонду текшерүү үчүн басып коюу"</string>
     <string name="ambient_display_tap_screen_title" product="tablet" msgid="6434521782016864148">"Планшетти текшерүү үчүн басып коюу"</string>
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"Түзмөктү текшерүү үчүн басып коюу"</string>
-    <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"Убакытты, билдирмелерди жана башка маалыматты көрүү үчүн экранды таптап коюңуз."</string>
+    <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"Убакытты, билдирмелерди жана башка маалыматты көрүү үчүн, экранды таптап коюңуз."</string>
     <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"Билдирмелерди манжа изинин сенсору менен көрүү"</string>
     <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"Манжа изинин сканери"</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"Билдирмелериңизди текшерүү үчүн телефондун аркасындагы манжа изинин сенсорун ылдый сүртүп коюңуз"</string>
@@ -4151,7 +4157,7 @@
     <string name="automatic_storage_manager_activation_warning" msgid="2630083316417707308">"Учурда сактагычыңыз сактагычты көзөмөлдөгүч тарабынан башкарылууда"</string>
     <string name="account_for_section_header" msgid="5975241715840642563">"<xliff:g id="USER_NAME">%1$s</xliff:g> таандык аккаунттар"</string>
     <string name="configure_section_header" msgid="6988981883075615136">"Конфигурациялоо"</string>
-    <string name="auto_sync_account_title" msgid="2394463123733529506">"Дайындарды автоматтык түрдө шайкештирүү"</string>
+    <string name="auto_sync_account_title" msgid="2394463123733529506">"Дайын-даректердин автоматтык түрдө шайкештирилиши"</string>
     <string name="auto_sync_personal_account_title" msgid="6844465157916100655">"Жеке дайындарды автоматтык түрдө шайкештирүү"</string>
     <string name="auto_sync_work_account_title" msgid="2403222633447522376">"Жумушка байланыштуу дайындарды автоматтык түрдө шайкештирүү"</string>
     <string name="auto_sync_account_summary" msgid="6316230976974033772">"Колдонмолордун маалыматы автоматтык түрдө жаңырып турат"</string>
@@ -4170,7 +4176,7 @@
     <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_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>
@@ -4282,7 +4288,7 @@
     <string name="angle_enabled_app" msgid="4359266182151708733">"ANGLE иштетилген колдонмону тандоо"</string>
     <string name="angle_enabled_app_not_set" msgid="7428910515748621910">"ANGLE иштетилген колдонмо жөндөлгөн жок"</string>
     <string name="angle_enabled_app_set" msgid="7313088703610569320">"ANGLE иштетилген колдонмо: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-    <string name="game_driver_dashboard_title" msgid="219443350404091201">"Оюн драйверинин жеке жөндөөлөрү"</string>
+    <string name="game_driver_dashboard_title" msgid="219443350404091201">"Оюн драйверинин жөндөөлөрү"</string>
     <string name="game_driver_dashboard_summary" msgid="1500674075618790528">"Оюн драйверинин жөндөөлөрү өзгөрөт"</string>
     <string name="game_driver_footer_text" msgid="1540158284161797913">"Оюн драйвери күйүк болгондо, түзмөктө орнотулган колдонмолор үчүн жаңыртылган графикалык драйверди колдонууну тандасаңыз болот."</string>
     <string name="game_driver_all_apps_preference_title" msgid="2453795714218707495">"Бардык колдонмолор үчүн иштетүү"</string>
@@ -4303,7 +4309,7 @@
     <string name="my_device_info_device_name_preference_title" msgid="7384446683248009296">"Түзмөктүн аталышы"</string>
     <string name="change_wifi_state_title" msgid="5140754955787584174">"Wi-Fi\'ды көзөмөлдөө"</string>
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"Колдонмого Wi-Fi\'ды көзөмөлдөөгө уруксат берүү"</string>
-    <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"Бул колдонмого Wi-Fi\'ды өчүрүп же күйгүзүүгө, Wi-Fi тармактарын издеп, аларга туташууга, тармактарды кошуп же алып салууга же жергиликтүү туташуу түйүнүн иштетүүгө уруксат берүү"</string>
+    <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"Бул колдонмого Wi-Fi\'ды өчүрүп же күйгүзүүгө, Wi-Fi тармактарын издеп, аларга туташууга, тармактарды кошуп же алып салууга же жергиликтүү байланыш түйүнүн иштетүүгө уруксат берүү"</string>
     <string name="media_output_title" msgid="8710632337456601848">"Медиа файл төмөнкүдө ойнотулсун:"</string>
     <string name="media_output_default_summary" msgid="3159237976830415584">"Ушул түзмөк"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"Телефон"</string>
@@ -4327,7 +4333,7 @@
     <string name="prevent_ringing_option_mute_summary" msgid="3509459199090688328">"Күйүк (үнсүз)"</string>
     <string name="prevent_ringing_option_none_summary" msgid="5152618221093037451">"Өчүк"</string>
     <string name="pref_title_network_details" msgid="3971074015034595956">"Тармактын чоо-жайы"</string>
-    <string name="about_phone_device_name_warning" msgid="9088572775969880106">"Түзмөгүңүздүн аталышы телефонуңуздагы колдонмолорго көрүнүктүү. Bluetooth түзмөктөрүнө туташканыңызда же Wi‑Fi туташуу түйүнүн жөндөгөнүңүздө, аны башка адамдар да көрүшү мүмкүн."</string>
+    <string name="about_phone_device_name_warning" msgid="9088572775969880106">"Түзмөгүңүздүн аталышы телефонуңуздагы колдонмолорго көрүнүктүү. Bluetooth түзмөктөрүнө туташканыңызда же Wi‑Fi байланыш түйүнүн жөндөгөнүңүздө, аны башка адамдар да көрүшү мүмкүн."</string>
     <string name="devices_title" msgid="4768432575951993648">"Түзмөктөр"</string>
     <string name="homepage_all_settings" msgid="3201220879559136116">"Бардык жөндөөлөр"</string>
     <string name="homepage_personal_settings" msgid="7472638597249114564">"Сунуштар"</string>
@@ -4372,7 +4378,7 @@
     <string name="label_available" msgid="8167122783750674408">"Жеткиликтүү тармактар"</string>
     <string name="load_networks_progress" msgid="8155227447618984212">"Издөөдө…"</string>
     <string name="register_on_network" msgid="423929472895070205">"<xliff:g id="NETWORK">%s</xliff:g> тармагына катталууда…"</string>
-    <string name="not_allowed" msgid="3047048893776257915">"Сиздин SIM-картаңыз менен бул тармакка туташууга болбойт."</string>
+    <string name="not_allowed" msgid="3047048893776257915">"Сиздин SIM картаңыз менен бул тармакка туташууга болбойт."</string>
     <string name="connect_later" msgid="4742215038190504328">"Бул тармакка азыр кошулуу мүмкүн эмес. Бир аздан кийин кайталап көрүңүз."</string>
     <string name="registration_done" msgid="8635020229073784432">"Тармакка катталды."</string>
     <string name="select_automatically" msgid="3421552364854534865">"Тармак автоматтык түрдө тандалат"</string>
@@ -4439,7 +4445,7 @@
     <string name="mobile_network_mode_error" msgid="6818434186286086554">"Тармактын режими жараксыз: <xliff:g id="NETWORKMODEID">%1$d</xliff:g>. Баш тартыңыз."</string>
     <string name="mobile_network_apn_title" msgid="5628635067747404382">"Байланыш түйүнүнүн аталыштары"</string>
     <string name="manual_mode_disallowed_summary" msgid="799800630000340665">"<xliff:g id="CARRIER">%1$s</xliff:g> операторуна туташып турганда жеткиликсиз"</string>
-    <string name="emergency_info_contextual_card_summary" msgid="5541444321969803486">"Медициналык маалымат, өзгөчө кырдаал байланыштары"</string>
+    <string name="emergency_info_contextual_card_summary" msgid="5541444321969803486">"Медициналык маалымат, кырсыктаганда байланышуучу адамдар"</string>
     <string name="see_more" msgid="7463940160389802632">"Дагы көрүү"</string>
     <string name="see_less" msgid="3718892257002813387">"Азыраак көрүү"</string>
     <string name="network_connection_request_dialog_title" msgid="3150489262902506588">"<xliff:g id="APPNAME">%1$s</xliff:g> менен колдонулуучу түзмөк"</string>
@@ -4471,7 +4477,7 @@
     <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"Бул сунуш өчүрүлсүнбү?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"Сунуш өчүрүлдү"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"Кайтаруу"</string>
-    <string name="low_storage_summary" msgid="4562224870189133400">"Сактагычта бош орун аз калды. <xliff:g id="PERCENTAGE">%1$s</xliff:g> ээленген – <xliff:g id="FREE_SPACE">%2$s</xliff:g> бош"</string>
+    <string name="low_storage_summary" msgid="4562224870189133400">"Сактагычта орун калбай баратат. <xliff:g id="PERCENTAGE">%1$s</xliff:g> ээленген – <xliff:g id="FREE_SPACE">%2$s</xliff:g> бош"</string>
     <string name="contextual_card_feedback_send" msgid="8698649023854350623">"Пикир билдирүү"</string>
     <string name="contextual_card_feedback_confirm_message" msgid="3987973028353264878">"Бул сунуш боюнча бизге пикириңизди билдирбейт белеңиз?"</string>
     <string name="copyable_slice_toast" msgid="1357518174923789947">"<xliff:g id="COPY_CONTENT">%1$s</xliff:g> буферге көчүрүлдү."</string>
diff --git a/tests/CarDeveloperOptions/res/values-lo/arrays.xml b/tests/CarDeveloperOptions/res/values-lo/arrays.xml
index 0dabc66..ff9fc4a 100644
--- a/tests/CarDeveloperOptions/res/values-lo/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-lo/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"ນຳໃຊ້ໃນພື້ນຫຼັງ"</item>
     <item msgid="6423861043647911030">"accessibility volume"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"ສະຖານທີ່"</item>
+    <item msgid="6656077694190491067">"ສະຖານທີ່"</item>
+    <item msgid="8790228218278477369">"ສະຖານທີ່"</item>
+    <item msgid="7836406246005211990">"ສັ່ນເຕືອນ"</item>
+    <item msgid="3951439024549922598">"ອ່ານລາຍຊື່ຜູ່ຕິດຕໍ່"</item>
+    <item msgid="8802152411647068">"ແກ້ໄຂລາຍຊື່ຜູ່ຕິດຕໍ່"</item>
+    <item msgid="229544934599698735">"ອ່ານບັນທຶກການໂທ"</item>
+    <item msgid="7396102294405899613">"ແກ້ໄຂບັນທຶກການໂຕ"</item>
+    <item msgid="3597797992398484655">"ອ່ານປະຕິທິນ"</item>
+    <item msgid="2705975774250907343">"ແກ້ໄຂປະຕິທິນ"</item>
+    <item msgid="4668747371441932697">"ສະຖານທີ່"</item>
+    <item msgid="1487578921720243646">"ການແຈ້ງເຕືອນໂພສ"</item>
+    <item msgid="4636080349724146638">"Location"</item>
+    <item msgid="673510900286463926">"ໂທຫາໂທລະສັບ"</item>
+    <item msgid="542083422784609790">"ອ່ານ SMS/MMS"</item>
+    <item msgid="1033780373029588436">"ຂຽນ SMS/MMS"</item>
+    <item msgid="5647111115517787488">"ຮັບ SMS/MMS"</item>
+    <item msgid="8591105601108455893">"ຮັບ SMS/MMS"</item>
+    <item msgid="7730995008517841903">"ຮັບ SMS/MMS"</item>
+    <item msgid="2613033109026626086">"ຮັບ SMS/MMS"</item>
+    <item msgid="3037159047591081136">"ສົ່ງ SMS/MMS"</item>
+    <item msgid="4726682243833913568">"ອ່ານ SMS/MMS"</item>
+    <item msgid="6555678522277865572">"ຂຽນ SMS/MMS"</item>
+    <item msgid="6981734935578130884">"ແກ້ໄຂການຕັ້ງຄ່າ"</item>
+    <item msgid="8705854389991425629">"ແຕ້ມທາງ​ເທິງ"</item>
+    <item msgid="5861356020344153651">"ເຂົ້າເຖິງການແຈ້ງເຕືອນ"</item>
+    <item msgid="78432174621628659">"ກ້ອງຖ່າຍຮູບ"</item>
+    <item msgid="3986116419882154794">"ບັນທຶກສຽງ"</item>
+    <item msgid="4516840825756409490">"ຫຼິ້ນສຽງ"</item>
+    <item msgid="6811712502798183957">"ອ່ານຄລິບບອດ"</item>
+    <item msgid="2780369012602289114">"ແກ້ໄຂຄລິບບອດ"</item>
+    <item msgid="2331359440170850868">"ປຸ່ມ​ມີເດຍ"</item>
+    <item msgid="6133599737122751231">"Audio focus"</item>
+    <item msgid="6844485713404805301">"ລະດັບສຽງຫຼັກ"</item>
+    <item msgid="1600379420669104929">"ລະດັບສຽງເວົ້າ"</item>
+    <item msgid="6296768210470214866">"​ລະ​ດັບ​ສຽງ​ໂທ​ລະ​ສັບ"</item>
+    <item msgid="510690696071629241">"​ລະ​ດັບ​ສຽງ​ມີ​ເດຍ"</item>
+    <item msgid="406861638631430109">"ລະ​ດັບ​ສຽງ​ໂມງ​ປຸກ"</item>
+    <item msgid="4715864795872233884">"ລະ​ດັບ​ສຽງ​ແຈ້ງ​ເຕືອນ"</item>
+    <item msgid="2311478519251301183">"ລະດັບສຽງ Bluetooth"</item>
+    <item msgid="5133991377896747027">"ເຮັດວຽກຕະຫຼອດເວລາ"</item>
+    <item msgid="2464189519136248621">"ສະຖານທີ່"</item>
+    <item msgid="2062677934050803037">"ສະຖານທີ່"</item>
+    <item msgid="1735171933192715957">"ໂຫຼດ​ສະ​ຖິ​ຕິ​ການ​ນຳ​ໃຊ້"</item>
+    <item msgid="1014093788778383554">"ປິດ/ເປີດ ​ໄມ​ໂຄຣ​ໂຟນ"</item>
+    <item msgid="4199297950608622850">"ສະແດງຂໍ້ຄວາມປາກົດຂຶ້ນຊົ່ວຄາວ"</item>
+    <item msgid="2527962435313398821">"ໂປຣເຈັກມີເດຍ"</item>
+    <item msgid="5117506254221861929">"ເປີດນຳໃຊ້ VPN"</item>
+    <item msgid="8291198322681891160">"ຂຽນ​ວອ​ລ​ເປ​ເປີ"</item>
+    <item msgid="7106921284621230961">"ໂຄງຮ່າງຊ່ວຍ"</item>
+    <item msgid="4496533640894624799">"ຮູບຖ່າຍໜ້າຈໍຊ່ວຍ"</item>
+    <item msgid="2598847264853993611">"ອ່ານສະຖານະໂທລະສັບ"</item>
+    <item msgid="9215610846802973353">"ເພີ່ມຂໍ້ຄວາມສຽງ"</item>
+    <item msgid="9186411956086478261">"ໃຊ້ sip"</item>
+    <item msgid="6884763100104539558">"ດຳເນີນການໂທອອກ"</item>
+    <item msgid="125513972170580692">"ລາຍນີ້ວມື"</item>
+    <item msgid="2556071024281275619">"ເຊັນເຊີຮ່າງກາຍ"</item>
+    <item msgid="617168514928339387">"ອ່ານການປະກາດຜ່ານເຄືອຂ່າຍ"</item>
+    <item msgid="7134693570516523585">"ສະຖານທີ່ຈຳລອງ"</item>
+    <item msgid="7224489175375229399">"ອ່ານພື້ນທີ່ຈັດເກັບ"</item>
+    <item msgid="8472735063903258202">"ຂຽນພື້ນທີ່ຈັດເກັບ"</item>
+    <item msgid="4069276819909595110">"ເປີດໜ້າຈໍ"</item>
+    <item msgid="1228338896751121025">"ຮັບບັນຊີ"</item>
+    <item msgid="3181581793459233672">"ນຳໃຊ້ໃນພື້ນຫຼັງ"</item>
+    <item msgid="2340936043025374076">"Accessibility volume"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"ສັ້ນ"</item>
     <item msgid="4816511817309094890">"ປານກາງ"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"ບໍ່ອະນຸຍາດ"</item>
     <item msgid="8184570120217958741">"ອະນຸຍາດສະເໝີ"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"ທົ່ວໄປ"</item>
+    <item msgid="5101233285497327432">"ປານກາງ"</item>
+    <item msgid="1555861583162930714">"ຕ່ຳ"</item>
+    <item msgid="1719683776264798117">"ອັນ​ຕະ​ລາຍ"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"ປົກ​ກະ​ຕິ"</item>
+    <item msgid="6107138933849816768">"ປານກາງ"</item>
+    <item msgid="182695359839047859">"ຕ່ຳ"</item>
+    <item msgid="8577246509202964244">"ວິກິດ"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"ໜຽວແໜ້ນ"</item>
     <item msgid="167418068739176448">"​ການເຄື່ອນ​ໄຫວ​ສູງ​ສຸດ"</item>
diff --git a/tests/CarDeveloperOptions/res/values-lo/config.xml b/tests/CarDeveloperOptions/res/values-lo/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-lo/config.xml
+++ b/tests/CarDeveloperOptions/res/values-lo/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-lo/strings.xml b/tests/CarDeveloperOptions/res/values-lo/strings.xml
index 380f9ea..f43a442 100644
--- a/tests/CarDeveloperOptions/res/values-lo/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-lo/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"ເຮັດໃຫ້ຂໍ້ຄວາມໃນໜ້າຈໍນ້ອຍລົງ ຫຼື ໃຫຍ່ຂຶ້ນ."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"ເຮັດໃຫ້ນ້ອຍລົງ"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"ເຮັດໃຫ້ໃຫຍ່ຂຶ້ນ"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"ຂໍ້ຄວາມຕົວຢ່າງ"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"ພໍ່ມົດອັດສະຈັນແຫ່ງອອດຊ໌"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"ບົດທີ 11: ເມືອງມໍລະກົດອັນໜ້າອັດສະຈັນຂອງອອດຊ໌"</string>
@@ -208,7 +207,7 @@
     <string name="proxy_error_empty_port" msgid="8034561724923076215">"ທ່ານຈຳເປັນຕ້ອງຕື່ມຂໍ້ມູນໃສ່ໃນຊ່ອງພອດ."</string>
     <string name="proxy_error_empty_host_set_port" msgid="8471455809508588255">"ຊ່ອງຂໍ້ມູນພອດຈະຕ້ອງປ່ອຍຫວ່າງໄວ້ ຫາກວ່າຊ່ອງ host ຫວ່າງຢູ່."</string>
     <string name="proxy_error_invalid_port" msgid="4046559920586100637">"ພອດທີ່ທ່ານລະບຸນັ້ນບໍ່ຖືກຕ້ອງ."</string>
-    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"HTTP proxy ນີ້ຖືກໃຊ້ໂດຍໂປຣແກຣມທ່ອງເວັບແລ້ວ ແລະບໍ່ອາດໃຊ້ກັບແອັບຯອື່ນໄດ້."</string>
+    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"HTTP proxy ນີ້ຖືກໃຊ້ໂດຍໂປຣແກຣມທ່ອງເວັບແລ້ວ ແລະ ບໍ່ອາດໃຊ້ກັບແອັບອື່ນໄດ້."</string>
     <string name="proxy_url_title" msgid="882042361706435904">"PAC URL: "</string>
     <string name="radio_info_dl_kbps" msgid="2903778264453410272">"ແບນວິດ DL (kbps):"</string>
     <string name="radio_info_ul_kbps" msgid="3802245899811732716">"ແບນວິດ UL (kbps):"</string>
@@ -456,7 +455,7 @@
     <string name="lock_screen_intro_skip_dialog_text" product="tablet" msgid="7572334562915795226">"ບໍ່ສາມາດເປີດຄຸນສົມບັດການປ້ອງກັນອຸປະກອນໄດ້. ທ່ານຈະບໍ່ສາມາດປ້ອງກັນບໍ່ໃຫ້ຄົນອື່ນໃຊ້ແທັບເລັດນີ້ໄດ້ຫາກມັນເສຍ ຫຼື ຖືກລັກ."</string>
     <string name="lock_screen_intro_skip_dialog_text" product="device" msgid="3819285334459763813">"ບໍ່ສາມາດເປີດຄຸນສົມບັດການປ້ອງກັນອຸປະກອນໄດ້. ທ່ານຈະບໍ່ສາມາດປ້ອງກັນບໍ່ໃຫ້ຄົນອື່ນໃຊ້ອຸປະກອນນີ້ໄດ້ຫາກມັນເສຍ ຫຼື ຖືກລັກ."</string>
     <string name="lock_screen_intro_skip_dialog_text" product="default" msgid="5361573789585652826">"ບໍ່ສາມາດເປີດຄຸນສົມບັດການປ້ອງກັນອຸປະກອນໄດ້. ທ່ານຈະບໍ່ສາມາດປ້ອງກັນບໍ່ໃຫ້ຄົນອື່ນໃຊ້ໂທລະສັບນີ້ໄດ້ຫາກມັນເສຍ ຫຼື ຖືກລັກ."</string>
-    <string name="skip_anyway_button_label" msgid="4437815969645175429">"ແນວ​ໃດ​ກໍ​ຂ້າມ​ໄປ"</string>
+    <string name="skip_anyway_button_label" msgid="4437815969645175429">"ຢືນຢັນການຂ້າມ"</string>
     <string name="go_back_button_label" msgid="7310586887969860472">"​ກັບ​ຄືນ"</string>
     <string name="skip_lock_screen_dialog_button_label" msgid="6706047245716780006">"ຂ້າມ"</string>
     <string name="cancel_lock_screen_dialog_button_label" msgid="2534925227627658819">"ຍົກເລີກ"</string>
@@ -489,7 +488,7 @@
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"ອຸ້ຍ, ນັ້ນ​ບໍ່​ແມ່ນ​ເຊັນ​ເຊີ"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"ແຕະທີ່ເຊັນເຊີຢູ່ຫຼັງຂອງໂທລະສັບຂອງທ່ານ. ໃຫ້ໃຊ້ນິ້ວຊີ້ທ່ານ."</string>
     <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"ການ​ລົງ​ທະ​ບຽນ​ບໍ່​ສຳ​ເລັດ"</string>
-    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"ຮອດ​ຂີດ​ຈຳ​ກັດ​ເວ​ລາ​ການ​ລົງ​ທະ​ບຽນ​ລາຍ​ນີ້ວ​ມື​ແລ້ວ. ລອງ​ໃໝ່​ອີກ."</string>
+    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"ຮອດ​ຂີດ​ຈຳ​ກັດ​ເວ​ລາ​ການ​ລົງ​ທະ​ບຽນ​ລາຍ​ນີ້ວ​ມື​ແລ້ວ. ກະລຸນາລອງ​ໃໝ່​ອີກຄັ້ງ."</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"ການ​ລົງ​ທະ​ບຽນ​ລາຍ​ນີ້ວ​ມື​ບໍ່​ເຮັດ​ວຽກ. ລອງ​ໃໝ່​ອີກ ຫຼື ໃຊ້​ນີ້ວ​ມື​ນີ້ວ​ອື່ນ."</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"ເພີ່ມ​ອັນ​ອື່ນ"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"ຕໍ່​ໄປ"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">ຕ້ອງມີໜ້ອຍກວ່າ <xliff:g id="NUMBER_1">%d</xliff:g> ຕົວເລກ</item>
       <item quantity="one">ຕ້ອງມີໜ້ອຍກວ່າ <xliff:g id="NUMBER_0">%d</xliff:g> ຕົວເລກ</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"ຕ້ອງມີຕົວເລກ 0 ຫາ 9 ເທົ່ານັ້ນ"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"ຜູ້ເບິ່ງແຍງລະບົບອຸປະກອນບໍ່ອະນຸຍາດໃຫ້ໃຊ້ລະຫັດ PIN ເມື່ອບໍ່ດົນມານີ້"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"ລະຫັດ PIN ທົ່ວໄປແມ່ນຖືກບລັອກໂດຍຜູ້ເບິ່ງແຍງລະບົບໄອທີຂອງທ່ານ. ໃຫ້ລອງໃຊ້ລະຫັດ PIN ອື່ນແທນ."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"ນີ້ບໍ່ສາມາດຮວມມີຕົວອັກສອນທີ່ບໍ່ຖືກຕ້ອງນຳໄດ້"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">ຕ້ອງມີຕົວອັກຂະລະທີ່ບໍ່ແມ່ນຕົວອັກສອນຢ່າງໜ້ອຍ <xliff:g id="COUNT">%d</xliff:g> ຕົວ</item>
       <item quantity="one">ຕ້ອງມີຕົວອັກຂະລະທີ່ບໍ່ແມ່ນຕົວອັກສອນຢ່າງໜ້ອຍ 1 ຕົວ</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">ຕ້ອງມີຕົວອັກສອນທີ່ບໍ່ແມ່ນຕົວເລກຢ່າງໜ້ອຍ <xliff:g id="COUNT">%d</xliff:g> ຕົວ</item>
+      <item quantity="one">ຕ້ອງມີຕົວອັກສອນທີ່ບໍ່ແມ່ນຕົວເລກຢ່າງໜ້ອຍ 1 ຕົວ</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"ຜູ້ເບິ່ງແຍງລະບົບບໍ່ອະນຸຍາດໃຫ້ໃຊ້ລະຫັດຜ່ານເມື່ອບໍ່ດົນມານີ້ໄດ້"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"ລະຫັດຜ່ານທົ່ວໄປແມ່ນຖືກບລັອກໂດຍຜູ້ເບິ່ງແຍງລະບົບໄອທີຂອງທ່ານ. ໃຫ້ລອງໃຊ້ລະຫັດອື່ນແທນ."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"ນ້ອຍຫາໃຫຍ່, ໃຫຍ່ຫານ້ອຍ ຫຼື ຊຸດຕົວເລກຊ້ຳໆແມ່ນບໍ່ສາມາດໃຊ້ໄດ້"</string>
@@ -968,7 +970,7 @@
     <string name="wifi_unchanged" msgid="6804964646942333992">"(ບໍ່ມີການປ່ຽນແປງ)"</string>
     <string name="wifi_unspecified" msgid="893491188483500809">"ກະລຸນາເລືອກ"</string>
     <string name="wifi_multiple_cert_added" msgid="7986200585749147204">"(ເພີ່ມຫຼາຍໃບຢັ້ງຢືນແລ້ວ)"</string>
-    <string name="wifi_use_system_certs" msgid="4794489370929885022">"ໃຊ້ໃບຢັ້ງຢືນຂອງລະບົບ"</string>
+    <string name="wifi_use_system_certs" msgid="4794489370929885022">"ໃຊ້ໃບຮັບຮອງລະບົບ"</string>
     <string name="wifi_do_not_provide_eap_user_cert" msgid="4044301449482425250">"ບໍ່ໃຫ້"</string>
     <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"ບໍ່ກວດຮັບຮອງ"</string>
     <string name="wifi_do_not_validate_eap_server_warning" msgid="3895397996759837323">"ບໍ່ໄດ້ລະບຸໃບຢັ້ງຢືນໃດໆ. ການເຊື່ອມຕໍ່ຂອງທ່ານຈະບໍ່ເປັນສ່ວນຕົວ."</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"ມືຖື"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"ຫາກບໍ່ສາມາດໃຊ້ Wi‑Fi ໄດ້, ໃຫ້ໃຊ້ເຄືອຂ່າຍມືຖືແທນ"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"ຫາກເຄືອຂ່າຍມືຖືບໍ່ສາມາດໃຊ້ໄດ້, ໃຫ້ໃຊ້ Wi‑Fi ແທນ"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"ໂທຜ່ານ Wi‑Fi. ຫາກໃຊ້ Wi‑Fi ບໍ່ໄດ້, ການໂທຈະສິ້ນສຸດລົງ."</string>
@@ -1533,7 +1538,7 @@
     <string name="apn_server" msgid="625116221513279678">"ເຊີບເວີ"</string>
     <string name="apn_mmsc" msgid="4621771343217824216">"MMSC"</string>
     <string name="apn_mms_proxy" msgid="636948562860444714">"MMS proxy"</string>
-    <string name="apn_mms_port" msgid="6606572282014819299">"ພອດ MMS"</string>
+    <string name="apn_mms_port" msgid="6606572282014819299">"ຜອດ MMS"</string>
     <string name="apn_mcc" msgid="9138301167194779180">"MCC"</string>
     <string name="apn_mnc" msgid="1276161191283274976">"MNC"</string>
     <string name="apn_auth_type" msgid="4286147728662523362">"ປະເພດການພິສູດຢືນຢັນ"</string>
@@ -1642,7 +1647,7 @@
     <string name="mobile_insert_sim_card" msgid="7594550403454243732">"ກະ​ລຸ​ນາ​ໃສ່​ຊິມກາດ ​ແລະເປີດເຄື່ອງຄືນໃໝ່"</string>
     <string name="mobile_connect_to_internet" msgid="6031886097365170913">"ກະ​ລຸ​ນາ​ເຊື່ອມ​ຕໍ່​ກັບ​ອິນ​ເຕີ​ເນັດ"</string>
     <string name="location_title" msgid="8664674161765477168">"ທີ່ຢູ່ຂອງຂ້ອຍ"</string>
-    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"ຈຸດ​ທີ່​ຕັ້ງ​ສຳ​ລັບ​ໂປ​ຣ​ໄຟ​ລ໌​ບ່ອນ​ເຮັດ​ວຽກ​"</string>
+    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"ສະຖານທີ່ສຳລັບໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string>
     <string name="location_app_level_permissions" msgid="1298041503927632960">"ສິດອະນຸຍາດແອັບ"</string>
     <string name="location_app_permission_summary_location_off" msgid="541372845344796336">"ປິດສະຖານທີ່ແລ້ວ"</string>
     <plurals name="location_app_permission_summary_location_on" formatted="false" msgid="7904821382328758218">
@@ -1651,7 +1656,7 @@
     </plurals>
     <string name="location_category_recent_location_access" msgid="286059523360285026">"ສິດການເຂົ້າເຖິງຫຼ້າສຸດ"</string>
     <string name="location_recent_location_access_view_details" msgid="2051602261436245905">"ເບິ່ງລາຍລະອຽດ"</string>
-    <string name="location_no_recent_apps" msgid="77502059586413278">"ຫຼ້າສຸດນີ້ບໍ່ມີແອັບຯໃດເອີ້ນໃຊ້ຂໍ້ມູນຕຳແໜ່ງ"</string>
+    <string name="location_no_recent_apps" msgid="77502059586413278">"ບໍ່ມີແອັບທີ່ຮ້ອງຂໍສະຖານທີ່ເມື່ອບໍ່ດົນມານີ້"</string>
     <string name="location_no_recent_accesses" msgid="6289916310397279890">"ບໍ່ມີແອັບໃດເຂົ້າເຖິງສະຖານທີ່ຫຼ້າສຸດ"</string>
     <string name="location_high_battery_use" msgid="7177199869979522663">"ໃຊ້ແບັດເຕີຣີ່ຫຼາຍ"</string>
     <string name="location_low_battery_use" msgid="5030448574501435888">"ໃຊ້ແບັດເຕີຣີ່ໜ້ອຍ"</string>
@@ -1750,7 +1755,7 @@
     <string name="lockpattern_recording_inprogress" msgid="4060818382176523671">"ປ່ອຍນິ້ວມືຂອງທ່ານເມື່ອເຮັດແລ້ວ."</string>
     <string name="lockpattern_recording_incorrect_too_short" msgid="6374760294545431845">"ໃຫ້ເຊື່ອມຕໍ່ຢ່າງໜ້ອຍ <xliff:g id="NUMBER">%d</xliff:g> ຈຸດເຂົ້າຫາກັນ. ແລ້ວລອງໃໝ່ອີກຄັ້ງ."</string>
     <string name="lockpattern_pattern_entered_header" msgid="2108106638322637851">"ຮູບແບບຖືກບັນທຶກແລ້ວ"</string>
-    <string name="lockpattern_need_to_confirm" msgid="4079482507985867389">"ແຕ້ມຮູບແບບຄືນອີກຄັ້ງເພື່ອຢັ້ງຢືນ"</string>
+    <string name="lockpattern_need_to_confirm" msgid="4079482507985867389">"ແຕ້ມຮູບແບບຄືນອີກຄັ້ງເພື່ອຢືນຢັນ"</string>
     <string name="lockpattern_pattern_confirmed_header" msgid="5603156929428721407">"ຮູບ​ແບບ​ປົດ​ລັອກ​ໃໝ່​ຂອງ​ທ່ານ"</string>
     <string name="lockpattern_confirm_button_text" msgid="7059311304112902598">"ຢືນຢັນ"</string>
     <string name="lockpattern_restart_button_text" msgid="4322968353922529868">"ແຕ້ມໃໝ່"</string>
@@ -1793,7 +1798,7 @@
     <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>
-    <string name="application_info_label" msgid="3886253474964599105">"ຂໍ້ມູນແອັບຯ"</string>
+    <string name="application_info_label" msgid="3886253474964599105">"ຂໍ້ມູນແອັບ"</string>
     <string name="storage_label" msgid="1109537840103290384">"ພື້ນທີ່ຈັດເກັບຂໍ້ມູນ"</string>
     <string name="auto_launch_label" msgid="47089737922907379">"ເປີດ​ຕາມຄ່າເລີ່ມຕົ້ນ"</string>
     <string name="auto_launch_label_generic" msgid="7865828543459493308">"ຄ່າເລີ່ມຕົ້ນ"</string>
@@ -2091,7 +2096,7 @@
     <string name="accessibility_ring_vibration_title" msgid="7943341443551359985">"ສຽງພ້ອມການສັ່ນເຕືອນ"</string>
     <string name="accessibility_touch_vibration_title" msgid="285890135612038092">"ການສັ່ນເມື່ອສຳຜັດ"</string>
     <string name="accessibility_service_master_switch_title" msgid="2734791644475782924">"ໃຊ້ບໍລິການ"</string>
-    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"ໃຊ້ການແກ້ໄຂສີ"</string>
+    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"ໃຊ້ການປັບແຕ່ງສີ"</string>
     <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"ໃຊ້ຄຳບັນຍາຍ"</string>
     <string name="accessibility_hearingaid_instruction_continue_button" msgid="4650111296711466691">"ສືບຕໍ່"</string>
     <string name="accessibility_hearingaid_title" msgid="3700978781235124891">"ເຄື່ອງຊ່ວຍຟັງ"</string>
@@ -2388,7 +2393,7 @@
     <string name="usage_type_computed_power" msgid="2594890316149868151">"​ການ​ນຳ​ໃຊ້​ພະ​ລັງ​ງານ​ທີ່​ຄຳ​ນວນ​​ໄວ້"</string>
     <string name="usage_type_actual_power" msgid="8067253427718526111">"ການ​ນຳ​ໃຊ້​ພະ​ລັງ​ງານ​ທີ່​ຕິດ​ຕາມ"</string>
     <string name="battery_action_stop" msgid="1866624019460630143">"ບັງ​ຄັບ​ປິດ"</string>
-    <string name="battery_action_app_details" msgid="1077011181969550402">"ຂໍ້ມູນແອັບຯ"</string>
+    <string name="battery_action_app_details" msgid="1077011181969550402">"ຂໍ້ມູນແອັບ"</string>
     <string name="battery_action_app_settings" msgid="587998773852488539">"ການຕັ້ງຄ່າແອັບຯ"</string>
     <string name="battery_action_display" msgid="4887913003634317465">"ການຕັ້ງຄ່າໜ້າຈໍ"</string>
     <string name="battery_action_wifi" msgid="7123520587925323824">"ການຕັ້ງຄ່າ Wi-Fi"</string>
@@ -2535,7 +2540,7 @@
     <string name="credentials_settings_not_available" msgid="5490259681690183274">"ບໍ່​ມີຂໍ້​ມູນ​​ຮັບ​ຮອງ​ໂຕສຳ​ລັບ​ຜູ່​ໃຊ້​ນີ້"</string>
     <string name="credential_for_vpn_and_apps" msgid="2462642486949593841">"ຕິດຕັ້ງສຳລັບ VPN ແລະ ແອັບຕ່າງໆແລ້ວ"</string>
     <string name="credential_for_wifi" msgid="2903295786961726388">"ຕິດຕັ້ງສຳລັບ Wi-Fi ແລ້ວ"</string>
-    <string name="credentials_reset_hint" msgid="3484350477764088169">"ລຶບເນື້ອຫາທັງໝົດອອກ?"</string>
+    <string name="credentials_reset_hint" msgid="3484350477764088169">"ລຶບເນື້ອຫາທັງໝົດອອກບໍ?"</string>
     <string name="credentials_erased" msgid="7287088033523869085">"ພື້ນທີ່ຈັດເກັບຂໍ້ມູນຮັບຮອງຖືກລຶບແລ້ວ."</string>
     <string name="credentials_not_erased" msgid="9137227570738627637">"ບ່ອນຈັດເກັບຂໍ້ມູນຮັບຮອງບໍ່ສາມາດຖືກລຶບໄດ້."</string>
     <string name="usage_access_title" msgid="7981321142726540574">"ແອັບທີ່ມີສິດອະນຸຍາດເຂົ້າເຖິງ"</string>
@@ -2919,8 +2924,8 @@
     <string name="nfc_payment_favor_default" msgid="7555356982142464260">"​ທຸກ​ເທື່ອ"</string>
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"ຍົກ​ເວັ້ນ​ເມື່ອ​ແອັບ​ການ​ຊຳ​ລະ​ເງິນ​ອື່ນ​ເປີດ"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"ຢູ່​ທີ່​ຊ່ອງ​ແຕະ ແລະ​ຈ່າຍ, ຈ່າຍ​ດ້ວຍ:"</string>
-    <string name="nfc_how_it_works_title" msgid="6531433737926327904">"ການ​ຈ່າຍ​ຢູ່​ປາຍທາງ"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"ຕັ້ງ​ແອັບ​ການ​ຊຳ​ລະ​ເງິນ. ຈາກນັ້ນ​ຈັບ​ໂທ​ລະ​ສັບ​ຂອງ​ທ່ານ​ທາງ​ດ້ານ​ຫຼັງ​ໄປ​ຈົນ​ຮອດ​ບ່ອນ​ວາງ​ໃດ​ໜຶ່ງ​ທີ່​ມີ​ສັນ​ຍາ​ລັກ​ບໍ່​ມີ​ການສຳ​ຜັດ​."</string>
+    <string name="nfc_how_it_works_title" msgid="6531433737926327904">"ການຈ່າຍເງິນຢູ່ເຄື່ອງຈ່າຍເງິນ"</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"ຕັ້ງ​ແອັບ​ການ​ຈ່າຍເງິນ. ຈາກນັ້ນ​ຈັບ​ໂທ​ລະ​ສັບ​ຂອງ​ທ່ານ​ທາງ​ດ້ານ​ຫຼັງ​ໄປ​ຈົນ​ຮອດ​ບ່ອນ​ວາງ​ໃດ​ໜຶ່ງ​ທີ່​ມີ​ສັນ​ຍາ​ລັກ contactless​."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"ໄດ້​ແລ້ວ"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"ເພີ່ມເຕີມ..."</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"ກຳນົດເປັນຄ່າທີ່ທ່ານຕ້ອງການ?"</string>
@@ -3398,7 +3403,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ໝວດໝູ່</item>
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ໝວດໝູ່</item>
     </plurals>
-    <string name="no_channels" msgid="8884254729302501652">"This app has not posted any notifications"</string>
+    <string name="no_channels" msgid="8884254729302501652">"ແອັບນີ້ຍັງບໍ່ໄດ້ໂພສການແຈ້ງເຕືອນໃດເທື່ອ"</string>
     <string name="app_settings_link" msgid="8465287765715790984">"ການຕັ້ງຄ່າເພີ່ມເຕີມໃນແອັບ"</string>
     <string name="app_notification_listing_summary_zero" msgid="4047782719487686699">"ເປີດສຳລັບທຸກແອັບ"</string>
     <plurals name="app_notification_listing_summary_others" formatted="false" msgid="1161774065480666519">
@@ -3704,7 +3709,7 @@
     <string name="high_power_filter_on" msgid="5294209328473386403">"ບໍ່ໄດ້ປັບໃຫ້ເໝາະສົມ"</string>
     <string name="high_power_on" msgid="3573501822510580334">"ບໍ່ໄດ້ປັບໃຫ້ເໝາະສົມ"</string>
     <string name="high_power_off" msgid="5906679734326490426">"ກຳລັງປັບການໃຊ້ແບັດເຕີຣີໃຫ້ເໝາະສົມ"</string>
-    <string name="high_power_system" msgid="739584574711292753">"ການປັບແບັດເຕີຣີໃຫ້ເໝາະສົມບໍ່ມີໃຫ້ໃຊ້ງານ"</string>
+    <string name="high_power_system" msgid="739584574711292753">"ບໍ່ສາມາດໃຊ້ການປັບແບັດເຕີຣີໃຫ້ເໝາະສົມໄດ້"</string>
     <string name="high_power_desc" msgid="333756885680362741">"ບໍ່ນໍາໃຊ້ການປັບແບັດເຕີຣີໃຫ້ເໝາະສົມ. ອາດຈະເຮັດໃຫ້ແບັດເຕີຣີຂອງທ່ານໝົດໄວ."</string>
     <string name="high_power_prompt_title" msgid="2805745781720454052">"ໃຫ້ແອັບເຮັດວຽກໃນພື້ນຫຼັງໄດ້ຕະຫຼອດເວລາບໍ?"</string>
     <string name="high_power_prompt_body" msgid="8067395096053552289">"ການອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME">%1$s</xliff:g> ເຮັດວຽກໃນພື້ນຫຼັງໄດ້ຕະຫຼອດເວລາອາດຫຼຸດອາຍຸແບັດເຕີຣີລົງ. \n\nທ່ານສາມາດປ່ຽນແປງຄ່ານີ້ໃນພາຍຫຼັງໄດ້ຈາກການຕັ້ງຄ່າ &gt; ແອັບ &amp; ການແຈ້ງເຕືອນ."</string>
@@ -4132,9 +4137,9 @@
     <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"ເພື່ອກວດສອບເວລາ, ການແຈ້ງເຕືອນ ແລະ ຂໍ້ມູນອື່ນໆ, ໃຫ້ແຕະໃສ່ໜ້າຈໍຂອງທ່ານ."</string>
     <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"ປັດລາຍນິ້ວມືສຳລັບການແຈ້ງເຕືອນ"</string>
     <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"ປັດລາຍນິ້ວມື"</string>
-    <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"ເພື່ອກວດເບິ່ງການແຈ້ງເຕືອນຂອງທ່ານ, ໃຫ້ເລື່ອນລົງໃສ່ເຊັນເຊີນລາຍນິ້ວມືທີ່ຢູ່ຫຼັງໂທລະສັບຂອງທ່ານ"</string>
-    <string name="fingerprint_swipe_for_notifications_summary" product="tablet" msgid="3480057984564476283">"ເພື່ອກວດເບິ່ງການແຈ້ງເຕືອນຂອງທ່ານ, ໃຫ້ເລື່ອນລົງໃສ່ເຊັນເຊີນລາຍນິ້ວມືທີ່ຢູ່ຫຼັງແທັບເລັດຂອງທ່ານ"</string>
-    <string name="fingerprint_swipe_for_notifications_summary" product="device" msgid="7950264130913070035">"ເພື່ອກວດເບິ່ງການແຈ້ງເຕືອນຂອງທ່ານ, ໃຫ້ເລື່ອນລົງໃສ່ເຊັນເຊີນລາຍນິ້ວມືທີ່ຢູ່ຫຼັງອຸປະກອນຂອງທ່ານ"</string>
+    <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"ເພື່ອກວດເບິ່ງການແຈ້ງເຕືອນຂອງທ່ານ, ໃຫ້ເລື່ອນລົງໃສ່ເຊັນເຊີນລາຍນິ້ວມືທີ່ຢູ່ຫຼັງໂທລະສັບຂອງທ່ານ."</string>
+    <string name="fingerprint_swipe_for_notifications_summary" product="tablet" msgid="3480057984564476283">"ເພື່ອກວດເບິ່ງການແຈ້ງເຕືອນຂອງທ່ານ, ໃຫ້ເລື່ອນລົງໃສ່ເຊັນເຊີນລາຍນິ້ວມືທີ່ຢູ່ຫຼັງແທັບເລັດຂອງທ່ານ."</string>
+    <string name="fingerprint_swipe_for_notifications_summary" product="device" msgid="7950264130913070035">"ເພື່ອກວດເບິ່ງການແຈ້ງເຕືອນຂອງທ່ານ, ໃຫ້ເລື່ອນລົງໃສ່ເຊັນເຊີນລາຍນິ້ວມືທີ່ຢູ່ຫຼັງອຸປະກອນຂອງທ່ານ."</string>
     <string name="fingerprint_swipe_for_notifications_suggestion_title" msgid="948946491233738823">"ເບິ່ງການແຈ້ງເຕືອນແບບດ່ວນ"</string>
     <string name="gesture_setting_on" msgid="7573680730101327866">"ເປີດ"</string>
     <string name="gesture_setting_off" msgid="2540159841716890511">"ປິດ"</string>
diff --git a/tests/CarDeveloperOptions/res/values-lt/arrays.xml b/tests/CarDeveloperOptions/res/values-lt/arrays.xml
index 18c51ce..b7ef95c 100644
--- a/tests/CarDeveloperOptions/res/values-lt/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-lt/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"vykdyti fone"</item>
     <item msgid="6423861043647911030">"pritaikymo neįgaliesiems garsas"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Vietovė"</item>
+    <item msgid="6656077694190491067">"Vietovė"</item>
+    <item msgid="8790228218278477369">"Vietovė"</item>
+    <item msgid="7836406246005211990">"Vibruoti"</item>
+    <item msgid="3951439024549922598">"Skaityti kontaktus"</item>
+    <item msgid="8802152411647068">"Keisti kontaktus"</item>
+    <item msgid="229544934599698735">"Skaityti skambučių žurnalą"</item>
+    <item msgid="7396102294405899613">"Keisti skambučių žurnalą"</item>
+    <item msgid="3597797992398484655">"Nuskaityti kalendorių"</item>
+    <item msgid="2705975774250907343">"Keisti kalendorių"</item>
+    <item msgid="4668747371441932697">"Vietovė"</item>
+    <item msgid="1487578921720243646">"Paskelbti pranešimą"</item>
+    <item msgid="4636080349724146638">"Vietovė"</item>
+    <item msgid="673510900286463926">"Skambinti į telefoną"</item>
+    <item msgid="542083422784609790">"Skaityti SMS / MMS"</item>
+    <item msgid="1033780373029588436">"Rašyti SMS / MMS"</item>
+    <item msgid="5647111115517787488">"Gauti SMS / MMS"</item>
+    <item msgid="8591105601108455893">"Gauti SMS / MMS"</item>
+    <item msgid="7730995008517841903">"Gauti SMS / MMS"</item>
+    <item msgid="2613033109026626086">"Gauti SMS / MMS"</item>
+    <item msgid="3037159047591081136">"Siųsti SMS / MMS"</item>
+    <item msgid="4726682243833913568">"Skaityti SMS / MMS"</item>
+    <item msgid="6555678522277865572">"Rašyti SMS / MMS"</item>
+    <item msgid="6981734935578130884">"Keisti nustatymus"</item>
+    <item msgid="8705854389991425629">"Piešti viršuje"</item>
+    <item msgid="5861356020344153651">"Pasiekti pranešimus"</item>
+    <item msgid="78432174621628659">"Fotoaparatas"</item>
+    <item msgid="3986116419882154794">"Įrašyti garso įrašą"</item>
+    <item msgid="4516840825756409490">"Leisti garso įrašą"</item>
+    <item msgid="6811712502798183957">"Skaityti iškarpinę"</item>
+    <item msgid="2780369012602289114">"Keisti iškarpinę"</item>
+    <item msgid="2331359440170850868">"Medijos mygtukai"</item>
+    <item msgid="6133599737122751231">"Garso sutelktis"</item>
+    <item msgid="6844485713404805301">"Pagrindinis garsumas"</item>
+    <item msgid="1600379420669104929">"Balso garsumas"</item>
+    <item msgid="6296768210470214866">"Skambučio garsumas"</item>
+    <item msgid="510690696071629241">"Medijų garsumas"</item>
+    <item msgid="406861638631430109">"Signalo garsumas"</item>
+    <item msgid="4715864795872233884">"Pranešimo garsumas"</item>
+    <item msgid="2311478519251301183">"„Bluetooth“ garsumas"</item>
+    <item msgid="5133991377896747027">"Neužmigdyti"</item>
+    <item msgid="2464189519136248621">"Vietovė"</item>
+    <item msgid="2062677934050803037">"Vietovė"</item>
+    <item msgid="1735171933192715957">"Gauti naudojimo statistiką"</item>
+    <item msgid="1014093788778383554">"Nutildyti / įjungti mikrofono garsą"</item>
+    <item msgid="4199297950608622850">"Rodyti pranešimą"</item>
+    <item msgid="2527962435313398821">"Projektuoti mediją"</item>
+    <item msgid="5117506254221861929">"Suaktyvinti VPN"</item>
+    <item msgid="8291198322681891160">"Rašymo ekrano fonas"</item>
+    <item msgid="7106921284621230961">"Pagalbinė struktūra"</item>
+    <item msgid="4496533640894624799">"Pagalbinė ekrano kopija"</item>
+    <item msgid="2598847264853993611">"Skaityti telefono būseną"</item>
+    <item msgid="9215610846802973353">"Pridėti balso pašto pranešimą"</item>
+    <item msgid="9186411956086478261">"Naudoti SIP"</item>
+    <item msgid="6884763100104539558">"Apdoroti siunčiamąjį skambutį"</item>
+    <item msgid="125513972170580692">"Piršto antspaudas"</item>
+    <item msgid="2556071024281275619">"Kūno jutikliai"</item>
+    <item msgid="617168514928339387">"Skaityti transliacijas mobiliuoju"</item>
+    <item msgid="7134693570516523585">"Imituoti vietovę"</item>
+    <item msgid="7224489175375229399">"Skaityti saugyklą"</item>
+    <item msgid="8472735063903258202">"Rašyti į saugyklą"</item>
+    <item msgid="4069276819909595110">"Įjungti ekraną"</item>
+    <item msgid="1228338896751121025">"Gauti paskyras"</item>
+    <item msgid="3181581793459233672">"Vykdyti fone"</item>
+    <item msgid="2340936043025374076">"Pritaikymo neįgaliesiems garsas"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Trumpa"</item>
     <item msgid="4816511817309094890">"Vidutinis"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Niekada neleisti"</item>
     <item msgid="8184570120217958741">"Visada leisti"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Įprasta"</item>
+    <item msgid="5101233285497327432">"Vidutiniška"</item>
+    <item msgid="1555861583162930714">"Mažas"</item>
+    <item msgid="1719683776264798117">"Kritinė"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Įprasta"</item>
+    <item msgid="6107138933849816768">"Vidutinė"</item>
+    <item msgid="182695359839047859">"Mažas"</item>
+    <item msgid="8577246509202964244">"Kritinė"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Nuolatinė"</item>
     <item msgid="167418068739176448">"Populiariausia veikla"</item>
diff --git a/tests/CarDeveloperOptions/res/values-lt/config.xml b/tests/CarDeveloperOptions/res/values-lt/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-lt/config.xml
+++ b/tests/CarDeveloperOptions/res/values-lt/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-lt/strings.xml b/tests/CarDeveloperOptions/res/values-lt/strings.xml
index 4d5754b..1c9d019 100644
--- a/tests/CarDeveloperOptions/res/values-lt/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-lt/strings.xml
@@ -85,8 +85,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Sumažinkite arba padidinkite ekrane rodomą tekstą."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Padaryti mažesnius"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Padaryti didesnius"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Pavyzdinis tekstas"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Nuostabusis Ozo šalies burtininkas"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"11 skyrius. Nuostabusis Smaragdo miestas"</string>
@@ -384,7 +383,7 @@
     <string name="location_settings_loading_app_permission_stats" msgid="7818169326621327628">"Įkeliama…"</string>
     <string name="account_settings_title" msgid="7870321267198486578">"Paskyros"</string>
     <string name="security_settings_title" msgid="8228075165942416425">"Sauga"</string>
-    <string name="encryption_and_credential_settings_title" msgid="6911729638397745353">"Šifruotė ir prisijungimo duomenys"</string>
+    <string name="encryption_and_credential_settings_title" msgid="6911729638397745353">"Šifruotė ir prisi. duom."</string>
     <string name="encryption_and_credential_settings_summary" product="default" msgid="468749700109808546">"Telefonas užšifruotas"</string>
     <string name="decryption_settings_summary" product="default" msgid="7401802133199522441">"Telefonas nešifruotas"</string>
     <string name="encryption_and_credential_settings_summary" product="tablet" msgid="8170667308598998791">"Įrenginys šifruotas"</string>
@@ -684,7 +683,6 @@
       <item quantity="many">Turi būti mažiau nei <xliff:g id="NUMBER_1">%d</xliff:g> skaitmens</item>
       <item quantity="other">Turi būti mažiau nei <xliff:g id="NUMBER_1">%d</xliff:g> skaitmenų</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Turi būti sudarytas tik iš skaitmenų (0–9)"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Įrenginio administratorius neleidžia naudoti pastarojo PIN kodo"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Dažnai naudojamus PIN kodus užblokavo IT administratorius. Bandykite naudoti kitą PIN kodą."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Negali būti netinkamų simbolių"</string>
@@ -727,6 +725,12 @@
       <item quantity="many">Turi būti bent <xliff:g id="COUNT">%d</xliff:g> neraidinio simbolio</item>
       <item quantity="other">Turi būti bent <xliff:g id="COUNT">%d</xliff:g> neraidinių simbolių</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">Turi būti bent <xliff:g id="COUNT">%d</xliff:g> neskaitinis simbolis</item>
+      <item quantity="few">Turi būti bent <xliff:g id="COUNT">%d</xliff:g> neskaitiniai simboliai</item>
+      <item quantity="many">Turi būti bent <xliff:g id="COUNT">%d</xliff:g> neskaitinio simbolio</item>
+      <item quantity="other">Turi būti bent <xliff:g id="COUNT">%d</xliff:g> neskaitinių simbolių</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Įrenginio administratorius neleidžia naudoti pastarojo slaptažodžio"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Dažnai naudojamus slaptažodžius užblokavo IT administratorius. Bandykite naudoti kitą slaptažodį."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Didėjanti, mažėjanti ar pasikartojanti skaitmenų seka neleidžiama"</string>
@@ -1134,7 +1138,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mobiliojo ryšio tinklas"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Jei „Wi‑Fi“ nepasiekiamas, naudokite mobiliojo ryšio tinklą"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Jei mobiliojo ryšio tinklas nepasiekiamas, naudoti „Wi‑Fi“"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Skambinimas naudojant „Wi-Fi“. Nutrūkus „Wi‑Fi“ skambutis bus baigtas."</string>
@@ -2641,7 +2648,7 @@
     <string name="sms_access_restriction_enabled" msgid="3006320256764718303">"Apriboti SMS ir skambučių žurnalo prieigą"</string>
     <string name="sms_access_restriction_enabled_summary" msgid="9011946580977780063">"Tik numatytosios telefono ir susirašinėjimo programos turi SMS ir skambučių žurnalo leidimus"</string>
     <string name="no_trust_agents" msgid="5757792915019113084">"Nėra jokių galimų „trust agents“"</string>
-    <string name="add_device_admin_msg" msgid="3573765823476931173">"Suaktyvinti įrenginio administravimo programą?"</string>
+    <string name="add_device_admin_msg" msgid="3573765823476931173">"Suaktyvinti įren. administravimo progr.?"</string>
     <string name="add_device_admin" msgid="1621152410207260584">"Suaktyvinti šio įrenginio administravimo programą"</string>
     <string name="device_admin_add_title" msgid="6097881332139146897">"Įrenginio administratorius"</string>
     <string name="device_admin_warning" msgid="4421817419326480449">"Suaktyvinus šią administravimo programą programai <xliff:g id="APP_NAME">%1$s</xliff:g> bus leidžiama vykdyti toliau nurodytas operacijas."</string>
diff --git a/tests/CarDeveloperOptions/res/values-lv/arrays.xml b/tests/CarDeveloperOptions/res/values-lv/arrays.xml
index 32d2fbc..69c113f 100644
--- a/tests/CarDeveloperOptions/res/values-lv/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-lv/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"darbināt fonā"</item>
     <item msgid="6423861043647911030">"pieejamības paziņojumu skaļums"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Atrašanās vieta"</item>
+    <item msgid="6656077694190491067">"Atrašanās vieta"</item>
+    <item msgid="8790228218278477369">"Atrašanās vieta"</item>
+    <item msgid="7836406246005211990">"Vibrācija"</item>
+    <item msgid="3951439024549922598">"Lasīt kontaktpersonas"</item>
+    <item msgid="8802152411647068">"Mainīt kontaktpersonu informāciju"</item>
+    <item msgid="229544934599698735">"Nolasīt zvanu žurnālu"</item>
+    <item msgid="7396102294405899613">"Modificēt zvanu žurnālu"</item>
+    <item msgid="3597797992398484655">"Lasīt kalendāru"</item>
+    <item msgid="2705975774250907343">"Modificēt kalendāru"</item>
+    <item msgid="4668747371441932697">"Atrašanās vieta"</item>
+    <item msgid="1487578921720243646">"Publicēt paziņojumu"</item>
+    <item msgid="4636080349724146638">"Atrašanās vieta"</item>
+    <item msgid="673510900286463926">"Zvanīt uz tālruņa numuru"</item>
+    <item msgid="542083422784609790">"Lasīt īsziņu vai multiziņu"</item>
+    <item msgid="1033780373029588436">"Rakstīt īsziņu vai multiziņu"</item>
+    <item msgid="5647111115517787488">"Saņemt īsziņu vai multiziņu"</item>
+    <item msgid="8591105601108455893">"Saņemt īsziņu vai multiziņu"</item>
+    <item msgid="7730995008517841903">"Saņemt īsziņu vai multiziņu"</item>
+    <item msgid="2613033109026626086">"Saņemt īsziņu vai multiziņu"</item>
+    <item msgid="3037159047591081136">"Sūtīt īsziņu vai multiziņu"</item>
+    <item msgid="4726682243833913568">"Lasīt īsziņu vai multiziņu"</item>
+    <item msgid="6555678522277865572">"Rakstīt īsziņu vai multiziņu"</item>
+    <item msgid="6981734935578130884">"Modificēt iestatījumus"</item>
+    <item msgid="8705854389991425629">"Zīmēt augšdaļā"</item>
+    <item msgid="5861356020344153651">"Piekļūt paziņojumiem"</item>
+    <item msgid="78432174621628659">"Kamera"</item>
+    <item msgid="3986116419882154794">"Ierakstīt audio"</item>
+    <item msgid="4516840825756409490">"Atskaņot audio"</item>
+    <item msgid="6811712502798183957">"Lasīt starpliktuvi"</item>
+    <item msgid="2780369012602289114">"Modificēt starpliktuvi"</item>
+    <item msgid="2331359440170850868">"Multivides pogas"</item>
+    <item msgid="6133599737122751231">"Audio uzsvars"</item>
+    <item msgid="6844485713404805301">"Galvenais skaļums"</item>
+    <item msgid="1600379420669104929">"Balss skaļums"</item>
+    <item msgid="6296768210470214866">"Zvana skaļums"</item>
+    <item msgid="510690696071629241">"Multivides skaļums"</item>
+    <item msgid="406861638631430109">"Signāla skaļums"</item>
+    <item msgid="4715864795872233884">"Paziņojumu skaļums"</item>
+    <item msgid="2311478519251301183">"Bluetooth apjoms"</item>
+    <item msgid="5133991377896747027">"Neļaut pāriet miega rež."</item>
+    <item msgid="2464189519136248621">"Atrašanās vieta"</item>
+    <item msgid="2062677934050803037">"Atrašanās vieta"</item>
+    <item msgid="1735171933192715957">"Iegūt lietojuma statistiku"</item>
+    <item msgid="1014093788778383554">"Izslēgt/ieslēgt mikrofonu"</item>
+    <item msgid="4199297950608622850">"Rādīt paziņojumu"</item>
+    <item msgid="2527962435313398821">"Projicēt saturu"</item>
+    <item msgid="5117506254221861929">"Aktivizēt VPN"</item>
+    <item msgid="8291198322681891160">"Izveidot fona tapeti"</item>
+    <item msgid="7106921284621230961">"Palīdzīga struktūra"</item>
+    <item msgid="4496533640894624799">"Palīdzīgs ekrānuzņēmums"</item>
+    <item msgid="2598847264853993611">"Lasīt tālruņa stāvokļa datus"</item>
+    <item msgid="9215610846802973353">"Pievienot balss pastu"</item>
+    <item msgid="9186411956086478261">"Izmantot SIP"</item>
+    <item msgid="6884763100104539558">"Apstrādāt izejošo zvanu"</item>
+    <item msgid="125513972170580692">"Pirksta nospiedums"</item>
+    <item msgid="2556071024281275619">"Ķermeņa sensori"</item>
+    <item msgid="617168514928339387">"Lasīt šūnu apraides"</item>
+    <item msgid="7134693570516523585">"Neīsta atrašanās vieta"</item>
+    <item msgid="7224489175375229399">"Lasīt krātuves datus"</item>
+    <item msgid="8472735063903258202">"Rakstīt krātuves datus"</item>
+    <item msgid="4069276819909595110">"Ieslēgt ekrānu"</item>
+    <item msgid="1228338896751121025">"Iegūt kontus"</item>
+    <item msgid="3181581793459233672">"Darbināt fonā"</item>
+    <item msgid="2340936043025374076">"Pieejamības paziņojumu skaļums"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Īss"</item>
     <item msgid="4816511817309094890">"Vidēji svarīgs"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Neatļaut nekad"</item>
     <item msgid="8184570120217958741">"Vienmēr atļaut"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normāls"</item>
+    <item msgid="5101233285497327432">"Vidējs"</item>
+    <item msgid="1555861583162930714">"Zems"</item>
+    <item msgid="1719683776264798117">"Kritisks"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normāls"</item>
+    <item msgid="6107138933849816768">"Vidējs"</item>
+    <item msgid="182695359839047859">"Zems"</item>
+    <item msgid="8577246509202964244">"Kritisks"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Pastāvīgs"</item>
     <item msgid="167418068739176448">"Biežākā darbība"</item>
diff --git a/tests/CarDeveloperOptions/res/values-lv/config.xml b/tests/CarDeveloperOptions/res/values-lv/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-lv/config.xml
+++ b/tests/CarDeveloperOptions/res/values-lv/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-lv/strings.xml b/tests/CarDeveloperOptions/res/values-lv/strings.xml
index 9eef33e..58022bf 100644
--- a/tests/CarDeveloperOptions/res/values-lv/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-lv/strings.xml
@@ -84,8 +84,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Palieliniet vai samaziniet tekstu ekrānā."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Samazināt"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Palielināt"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Teksta paraugs"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Brīnumainais burvis no Oza zemes"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"11. nodaļa: Oza zemes brīnumainā Smaragda pilsēta"</string>
@@ -472,7 +471,7 @@
     <string name="security_settings_fingerprint_enroll_dialog_delete" msgid="4312297515772004580">"Dzēst"</string>
     <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"Pieskarieties sensoram"</string>
     <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Novietojiet pirkstu uz sensora un paceliet to pēc tam, kad sajūtat vibrāciju"</string>
-    <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"Paceliet un vēlreiz pieskar."</string>
+    <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"Pieskarieties vēlreiz"</string>
     <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Atkārtoti uzlieciet pirkstu, lai pievienotu dažādas pirksta nospieduma daļas."</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"Pirksta nospiedums pievienots"</string>
     <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"Kad tiek rādīta šī ikona, izmantojiet pirksta nospiedumu identifikācijai vai pirkuma autorizēšanai."</string>
@@ -676,7 +675,6 @@
       <item quantity="one">Ir jābūt mazāk par <xliff:g id="NUMBER_1">%d</xliff:g> ciparu.</item>
       <item quantity="other">Ir jābūt mazāk par <xliff:g id="NUMBER_1">%d</xliff:g> cipariem.</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Ir jāietver tikai cipari no 0 līdz 9."</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Ierīces administrators neļauj izmantot nesen izveidotu PIN."</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Jūsu IT administrators ir bloķējis pārāk vienkāršus PIN kodus. Izmēģiniet sarežģītāku PIN kodu."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Nedrīkst ietvert nederīgu rakstzīmi."</string>
@@ -713,6 +711,11 @@
       <item quantity="one">Ir jāietver vismaz <xliff:g id="COUNT">%d</xliff:g> rakstzīme, kas nav burts.</item>
       <item quantity="other">Ir jāietver vismaz <xliff:g id="COUNT">%d</xliff:g> rakstzīmes, kas nav burti.</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="zero">Ir jāietver vismaz <xliff:g id="COUNT">%d</xliff:g> rakstzīmes, kas nav cipari.</item>
+      <item quantity="one">Ir jāietver vismaz <xliff:g id="COUNT">%d</xliff:g> rakstzīme, kas nav cipari.</item>
+      <item quantity="other">Ir jāietver vismaz <xliff:g id="COUNT">%d</xliff:g> rakstzīmes, kas nav cipari.</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Ierīces administrators neļauj izmantot nesen izveidotu paroli."</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Jūsu IT administrators ir bloķējis pārāk vienkāršas paroles. Izmēģiniet sarežģītāku paroli."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Augoša, dilstoša vai atkārtota ciparu secība nav atļauta."</string>
@@ -1117,7 +1120,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mobilie dati"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Ja Wi-Fi savienojums nav pieejams, izmantot mobilo tīklu"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Ja mobilais tīkls nav pieejams, izmantot Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Zvans Wi-Fi tīklā. Ja Wi-Fi savienojums tiks zaudēts, zvans beigsies."</string>
@@ -1681,7 +1687,7 @@
     <string name="location_scanning_bluetooth_always_scanning_description" msgid="3796673798637848690">"Ļauj lietotnēm un pakalpojumiem meklēt tuvumā esošas ierīces vienmēr, pat ja Bluetooth ir izslēgts. Šo iestatījumu var izmantot, piemēram, lai uzlabotu atrašanās vietas funkcijas un pakalpojumus."</string>
     <string name="managed_profile_location_services" msgid="224925483299159541">"Atrašanās vietu pakalpojumi darbam"</string>
     <string name="location_network_based" msgid="1535812159327454835">"Wi-Fi un mob. tīklu atr. vieta"</string>
-    <string name="location_neighborhood_level" msgid="8459352741296587916">"Ļaut lietotnēm izmantot Google atrašanās vietas pakalpojumu, lai ātrāk noteiktu jūsu atrašanās vietu. Tiks apkopoti un nosūtīti uz Google serveriem anonīmi atrašanās vietas dati."</string>
+    <string name="location_neighborhood_level" msgid="8459352741296587916">"Ļaut lietotnēm izmantot Google atrašanās vietas pakalpojumu, lai ātrāk noteiktu jūsu atrašanās vietu. Tiks vākti un nosūtīti uz Google serveriem anonīmi atrašanās vietas dati."</string>
     <string name="location_neighborhood_level_wifi" msgid="6120133551482003840">"Wi-Fi noteikta atrašanās vieta"</string>
     <string name="location_gps" msgid="688049341158297763">"GPS satelīti"</string>
     <string name="location_street_level" product="tablet" msgid="4459804798444296650">"Ļaut lietotnēm izmantot jūsu planšetdatorā esošo GPS, lai noteiktu jūsu atrašanās vietu."</string>
@@ -2737,7 +2743,7 @@
     <string name="data_usage_auto_sync_on_dialog" product="tablet" msgid="4935430284683238901">"Visas izmaiņas, ko veiksiet kontos tīmeklī, tiks automātiski pārkopētas planšetdatorā.\n\nDažos kontos planšetdatorā veiktās izmaiņas var automātiski pārkopēt tīmeklī. Šādi darbojas Google konts."</string>
     <string name="data_usage_auto_sync_on_dialog" product="default" msgid="5004823486046340090">"Visas izmaiņas, ko veiksiet kontos tīmeklī, tiks automātiski pārkopētas tālrunī.\n\nDažos kontos tālrunī veiktās izmaiņas var automātiski pārkopēt tīmeklī. Šādi darbojas Google konts."</string>
     <string name="data_usage_auto_sync_off_dialog_title" msgid="7105334544291643305">"Vai izslēgt datu automātisko sinhronizāciju?"</string>
-    <string name="data_usage_auto_sync_off_dialog" msgid="4057984234450947964">"Tiks saglabāti dati un akumulatora lietojums, bet jums vajadzēs manuāli sinhronizēt katru kontu, lai apkopotu jaunāko informāciju. Un jūs nesaņemsiet paziņojumus par atjauninājumiem."</string>
+    <string name="data_usage_auto_sync_off_dialog" msgid="4057984234450947964">"Tiks saglabāti dati un akumulatora lietojums, bet jums vajadzēs manuāli sinhronizēt katru kontu, lai vāktu jaunāko informāciju. Un jūs nesaņemsiet paziņojumus par atjauninājumiem."</string>
     <string name="data_usage_cycle_editor_title" msgid="4967309390043599889">"Izmantošanas cikla atiestatīšanas datums"</string>
     <string name="data_usage_cycle_editor_subtitle" msgid="6043098041946166597">"Katra mēneša datums:"</string>
     <string name="data_usage_cycle_editor_positive" msgid="9155752056537811646">"Iestatīt"</string>
@@ -4584,7 +4590,7 @@
     <string name="wfc_disclaimer_agree_button_text" msgid="4706101805260434404">"TURPINĀT"</string>
     <string name="wfc_disclaimer_disagree_text" msgid="908289420390194127">"NĒ, PALDIES"</string>
     <string name="wfc_disclaimer_location_title_text" msgid="5696194250838686019">"Atrašanās vieta"</string>
-    <string name="wfc_disclaimer_location_desc_text" msgid="3879710366995108723">"Pakalpojuma sniedzējs var apkopot jūsu atrašanās informāciju, lai nodrošinātu šo pakalpojumu.\n\nSkatiet pakalpojuma sniedzēja konfidencialitātes politiku."</string>
+    <string name="wfc_disclaimer_location_desc_text" msgid="3879710366995108723">"Pakalpojuma sniedzējs var vākt jūsu atrašanās informāciju, lai nodrošinātu šo pakalpojumu.\n\nSkatiet pakalpojuma sniedzēja konfidencialitātes politiku."</string>
     <string name="forget_passpoint_dialog_message" msgid="3337626966248310367">"Iespējams, zaudēsiet piekļuvi atlikušajam laikam vai datiem. Pirms noņemšanas sazinieties ar pakalpojuma sniedzēju."</string>
     <string name="keywords_content_capture" msgid="5401877823529928976">"satura uzņēmums, viedie ieteikumi"</string>
     <string name="content_capture" msgid="1709538093513983279">"Viedie ieteikumi"</string>
diff --git a/tests/CarDeveloperOptions/res/values-mk/arrays.xml b/tests/CarDeveloperOptions/res/values-mk/arrays.xml
index 872a655..000a585 100644
--- a/tests/CarDeveloperOptions/res/values-mk/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-mk/arrays.xml
@@ -29,8 +29,25 @@
     <item msgid="5194868215515664953">"Пацифик"</item>
     <item msgid="7044520255415007865">"Сите"</item>
   </string-array>
-    <!-- no translation found for screen_timeout_entries:0 (8596143519087753804) -->
-    <!-- no translation found for dream_timeout_entries:7 (8271452751594598661) -->
+  <string-array name="screen_timeout_entries">
+    <item msgid="8596143519087753804">"15 секунди"</item>
+    <item msgid="772029947136115322">"30 секунди"</item>
+    <item msgid="8743663928349474087">"1 минута"</item>
+    <item msgid="1506508631223164814">"2 минути"</item>
+    <item msgid="8664703938127907662">"5 минути"</item>
+    <item msgid="5827960506924849753">"10 минути"</item>
+    <item msgid="6677424950124253938">"30 минути"</item>
+  </string-array>
+  <string-array name="dream_timeout_entries">
+    <item msgid="6487043225269853023">"Никогаш"</item>
+    <item msgid="2517785806387977252">"15 секунди"</item>
+    <item msgid="6347954399441173672">"30 секунди"</item>
+    <item msgid="4858305253279921789">"1 минута"</item>
+    <item msgid="8109273437140044073">"2 минути"</item>
+    <item msgid="2788593551142462622">"5 минути"</item>
+    <item msgid="8012672183888404961">"10 минути"</item>
+    <item msgid="8271452751594598661">"30 минути"</item>
+  </string-array>
   <string-array name="lock_after_timeout_entries">
     <item msgid="2232921187970351881">"Веднаш"</item>
     <item msgid="2038544972632026612">"5 секунди"</item>
@@ -42,25 +59,60 @@
     <item msgid="811192536981678974">"10 минути"</item>
     <item msgid="7258394417241706272">"30 минути"</item>
   </string-array>
-    <!-- no translation found for entries_font_size:0 (2340391964816059553) -->
-    <!-- no translation found for entries_font_size:0 (6490061470416867723) -->
-    <!-- no translation found for entries_font_size:2 (1714184661981538355) -->
-    <!-- no translation found for entries_font_size:2 (1678068858001018666) -->
-    <!-- no translation found for wifi_status:3 (5848277343965362748) -->
-    <!-- no translation found for wifi_status_with_ssid:1 (6816207058895999545) -->
-    <!-- no translation found for wifi_status_with_ssid:3 (7547609081339573756) -->
-    <!-- no translation found for wifi_status_with_ssid:4 (5145158315060185414) -->
+  <string-array name="entries_font_size">
+    <item msgid="2340391964816059553">"Мал"</item>
+    <item msgid="591935967183159581">"Стандардно"</item>
+    <item msgid="1714184661981538355">"Голем"</item>
+    <item msgid="6195563047686707484">"Најголем"</item>
+  </string-array>
+  <string-array name="wifi_status">
+    <item msgid="1304883790721412351"></item>
+    <item msgid="4157625910392775808">"Скенирање..."</item>
+    <item msgid="5597394826455877834">"Се поврзува..."</item>
+    <item msgid="5848277343965362748">"Се проверува…"</item>
+    <item msgid="3391238031431440676">"Добивање ИП адреса..."</item>
+    <item msgid="5257597310494000224">"Поврзано"</item>
+    <item msgid="8472497592913050396">"Суспендирани"</item>
+    <item msgid="1228072488815999109">"Се исклучува..."</item>
+    <item msgid="7253087004422991731">"Исклучени"</item>
+    <item msgid="4169850917304751227">"Неуспешно"</item>
+    <item msgid="6266658166690831131">"Блокирана"</item>
+    <item msgid="4517230805854909775">"Привремено избегнува лоша врска"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="4853670665485437464"></item>
+    <item msgid="6816207058895999545">"Се скенира…"</item>
+    <item msgid="8058143476674427024">"Поврзување на <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="7547609081339573756">"Се проверува со <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="5145158315060185414">"Се добива IP-адресата од <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="3283243151651124831">"Поврзано на <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="6600156231416890902">"Суспендирани"</item>
+    <item msgid="4133290864821295785">"Исклучување од <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="3980154971187953257">"Исклучени"</item>
+    <item msgid="2847316776634969068">"Неуспешно"</item>
+    <item msgid="4390990424746035383">"Блокирана"</item>
+    <item msgid="3618248791367063949">"Привремено избегнува лоша врска"</item>
+  </string-array>
     <!-- no translation found for wifi_tether_security:0 (5586343370515598801) -->
     <!-- no translation found for wifi_tether_security:1 (6136336549994615745) -->
-    <!-- no translation found for wifi_p2p_wps_setup:0 (5390235347963255303) -->
+  <string-array name="wifi_p2p_wps_setup">
+    <item msgid="5390235347963255303">"Копче „Притисни“"</item>
+    <item msgid="7401896200768713930">"PIN од спарен уред"</item>
+    <item msgid="4526848028011846710">"PIN од овој уред"</item>
+  </string-array>
   <string-array name="wifi_p2p_status">
-    <item msgid="8741947238021758201">"Поврзана"</item>
+    <item msgid="8741947238021758201">"Поврзано"</item>
     <item msgid="983792611851499732">"Покането"</item>
     <item msgid="5438273405428201793">"Неуспешно"</item>
     <item msgid="4646663015449312554">"Достапна"</item>
     <item msgid="3230556734162006146">"Надвор од опсег"</item>
   </string-array>
-    <!-- no translation found for bluetooth_visibility_timeout_entries:1 (2759776603549270587) -->
+  <string-array name="bluetooth_visibility_timeout_entries">
+    <item msgid="8247986727324120082">"2 минути"</item>
+    <item msgid="2759776603549270587">"5 минути"</item>
+    <item msgid="167772676068860015">"1 час"</item>
+    <item msgid="5985477119043628504">"Времето никогаш да не истече"</item>
+  </string-array>
   <string-array name="bluetooth_max_connected_audio_devices">
     <item msgid="3800257971619063588">"Користи ја стандардната поставка на системот: <xliff:g id="DEFAULT_BLUETOOTH_MAX_CONNECTED_AUDIO_DEVICES">%1$d</xliff:g>"</item>
     <item msgid="8572230405241423895">"1"</item>
@@ -69,8 +121,13 @@
     <item msgid="1644506614010085798">"4"</item>
     <item msgid="3132506679404897150">"5"</item>
   </string-array>
-    <!-- no translation found for wifi_signal:1 (7882129634982603782) -->
-    <!-- no translation found for wifi_signal:4 (999948812884919584) -->
+  <string-array name="wifi_signal">
+    <item msgid="1709949377823900951">"Слаб"</item>
+    <item msgid="7882129634982603782">"Слаб"</item>
+    <item msgid="6457357501905996224">"Умерен"</item>
+    <item msgid="405271628162918841">"Добар"</item>
+    <item msgid="999948812884919584">"Одличен"</item>
+  </string-array>
   <string-array name="data_usage_data_range">
     <item msgid="8986775481492954015">"Минатите 30 дена"</item>
     <item msgid="3211287705232736964">"Пост. цикл. на корист...."</item>
@@ -106,11 +163,14 @@
     <item msgid="7330627471456865502">"MSCHAPV2"</item>
     <item msgid="6255179395132581882">"GTC"</item>
   </string-array>
-    <!-- no translation found for wifi_ip_settings:1 (4377002609760712163) -->
+  <string-array name="wifi_ip_settings">
+    <item msgid="2717196390555072244">"DHCP"</item>
+    <item msgid="4377002609760712163">"Статична"</item>
+  </string-array>
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"Ниедна"</item>
     <item msgid="1464741437353223198">"Упатство"</item>
-    <item msgid="5793600062487886090">"Прокси автоконфигурација"</item>
+    <item msgid="5793600062487886090">"Прокси: автоконфигурација"</item>
   </string-array>
   <string-array name="apn_auth_entries">
     <item msgid="7099647881902405997">"Ниедна"</item>
@@ -226,11 +286,73 @@
     <item msgid="1165623660533024666">"извршувај во заднина"</item>
     <item msgid="6423861043647911030">"јачина на звук на пристапноста"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:3 (7836406246005211990) -->
-    <!-- no translation found for app_ops_labels:4 (3951439024549922598) -->
-    <!-- no translation found for app_ops_labels:8 (3597797992398484655) -->
-    <!-- no translation found for app_ops_labels:20 (3037159047591081136) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Локација"</item>
+    <item msgid="6656077694190491067">"Локација"</item>
+    <item msgid="8790228218278477369">"Локација"</item>
+    <item msgid="7836406246005211990">"Вибрации"</item>
+    <item msgid="3951439024549922598">"Прочитај ги контактите"</item>
+    <item msgid="8802152411647068">"Измени контакти"</item>
+    <item msgid="229544934599698735">"Прочитај евиденција на повици"</item>
+    <item msgid="7396102294405899613">"Измени евиденција на повици"</item>
+    <item msgid="3597797992398484655">"Прочитај го календарот"</item>
+    <item msgid="2705975774250907343">"Измени календар"</item>
+    <item msgid="4668747371441932697">"Локација"</item>
+    <item msgid="1487578921720243646">"Објави известување"</item>
+    <item msgid="4636080349724146638">"Локација"</item>
+    <item msgid="673510900286463926">"Повикај телефонски број"</item>
+    <item msgid="542083422784609790">"Прочитај SMS/MMS порака"</item>
+    <item msgid="1033780373029588436">"Напиши SMS/MMS порака"</item>
+    <item msgid="5647111115517787488">"Прими SMS/MMS порака"</item>
+    <item msgid="8591105601108455893">"Прими SMS/MMS порака"</item>
+    <item msgid="7730995008517841903">"Прими SMS/MMS порака"</item>
+    <item msgid="2613033109026626086">"Прими SMS/MMS порака"</item>
+    <item msgid="3037159047591081136">"Испрати SMS/MMS-порака"</item>
+    <item msgid="4726682243833913568">"Прочитај SMS/MMS порака"</item>
+    <item msgid="6555678522277865572">"Напиши SMS/MMS порака"</item>
+    <item msgid="6981734935578130884">"Измени поставки"</item>
+    <item msgid="8705854389991425629">"Цртај на врвот"</item>
+    <item msgid="5861356020344153651">"Пристапи кон известувања"</item>
+    <item msgid="78432174621628659">"Камера"</item>
+    <item msgid="3986116419882154794">"Снимај аудио"</item>
+    <item msgid="4516840825756409490">"Репродуцирај аудио"</item>
+    <item msgid="6811712502798183957">"Прочитај табла со исечоци"</item>
+    <item msgid="2780369012602289114">"Измени табла со исечоци"</item>
+    <item msgid="2331359440170850868">"Копчиња за медиуми"</item>
+    <item msgid="6133599737122751231">"Аудио фокус"</item>
+    <item msgid="6844485713404805301">"Основна јачина на звук"</item>
+    <item msgid="1600379420669104929">"Јачина на звук на глас"</item>
+    <item msgid="6296768210470214866">"Јачина на звук на ѕвонење"</item>
+    <item msgid="510690696071629241">"Јачина на аудио/видео звук"</item>
+    <item msgid="406861638631430109">"Јачина на звук на аларм"</item>
+    <item msgid="4715864795872233884">"Јачина на звук на известување"</item>
+    <item msgid="2311478519251301183">"Јачина на звук на Bluetooth"</item>
+    <item msgid="5133991377896747027">"Задржи активен"</item>
+    <item msgid="2464189519136248621">"Локација"</item>
+    <item msgid="2062677934050803037">"Локација"</item>
+    <item msgid="1735171933192715957">"Добиј статистики за користење"</item>
+    <item msgid="1014093788778383554">"Вклучи/исклучи звук на микрофон"</item>
+    <item msgid="4199297950608622850">"Прикажи известување"</item>
+    <item msgid="2527962435313398821">"Прикажувај содржини"</item>
+    <item msgid="5117506254221861929">"Активирај ВПН"</item>
+    <item msgid="8291198322681891160">"Напиши тапет"</item>
+    <item msgid="7106921284621230961">"Помошна структура"</item>
+    <item msgid="4496533640894624799">"Помошна слика од екранот"</item>
+    <item msgid="2598847264853993611">"Прочитај ја состојбата на телефонот"</item>
+    <item msgid="9215610846802973353">"Додај говорна пошта"</item>
+    <item msgid="9186411956086478261">"Користи SIP"</item>
+    <item msgid="6884763100104539558">"Обработи појдовен повик"</item>
+    <item msgid="125513972170580692">"Отпечаток"</item>
+    <item msgid="2556071024281275619">"Телесни сензори"</item>
+    <item msgid="617168514928339387">"Читај пораки Cell Broadcast"</item>
+    <item msgid="7134693570516523585">"Лажна локација"</item>
+    <item msgid="7224489175375229399">"Прочитај ја меморијата"</item>
+    <item msgid="8472735063903258202">"Напиши во меморијата"</item>
+    <item msgid="4069276819909595110">"Вклучи го екранот"</item>
+    <item msgid="1228338896751121025">"Земи сметки"</item>
+    <item msgid="3181581793459233672">"Извршувај во заднина"</item>
+    <item msgid="2340936043025374076">"Јачина на звук на пристапноста"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Кратко"</item>
     <item msgid="4816511817309094890">"Средно"</item>
@@ -247,7 +369,13 @@
     <item msgid="4627069151979553527">"Курзив"</item>
     <item msgid="6896773537705206194">"Мали големи букви"</item>
   </string-array>
-    <!-- no translation found for captioning_font_size_selector_titles:3 (2784236342175159295) -->
+  <string-array name="captioning_font_size_selector_titles">
+    <item msgid="1680223634161592855">"Многу мали"</item>
+    <item msgid="5091603983404027034">"Мали"</item>
+    <item msgid="176844712416932112">"Нормално"</item>
+    <item msgid="2784236342175159295">"Голем"</item>
+    <item msgid="218913203203160606">"Многу големи"</item>
+  </string-array>
   <string-array name="captioning_edge_type_selector_titles">
     <item msgid="3865198759294188069">"Стандардно"</item>
     <item msgid="6488643537808152001">"Ниедна"</item>
@@ -262,7 +390,14 @@
     <item msgid="1874668269931014581">"75%"</item>
     <item msgid="6462911487571123954">"100%"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"Користи стандарди на апликација"</item>
+    <item msgid="8611890312638868524">"Бели на црно"</item>
+    <item msgid="5891360837786277638">"Црни на бело"</item>
+    <item msgid="2798457065945456853">"Жолти на црно"</item>
+    <item msgid="5799049811524553967">"Жолти на сино"</item>
+    <item msgid="3673930830658169860">"Приспособен"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"PPTP VPN"</item>
     <item msgid="1349760781118368659">"L2TP/IPSec VPN со претходно споделени клучеви"</item>
@@ -275,15 +410,32 @@
     <item msgid="2958623927055120839">"Ништо"</item>
     <item msgid="1157046369795346308">"Упатство"</item>
   </string-array>
-    <!-- no translation found for vpn_states:4 (9135049670787351881) -->
+  <string-array name="vpn_states">
+    <item msgid="5408915841694583740">"Исклучени"</item>
+    <item msgid="8754480102834556765">"Се иницијализира..."</item>
+    <item msgid="3351334355574270250">"Се поврзува..."</item>
+    <item msgid="8303882153995748352">"Поврзано"</item>
+    <item msgid="9135049670787351881">"Времето истече"</item>
+    <item msgid="2124868417182583926">"Неуспешно"</item>
+  </string-array>
   <string-array name="security_settings_premium_sms_values">
     <item msgid="1164265643455394443">"Прашај"</item>
     <item msgid="7718817231348607934">"Никогаш не дозволувај"</item>
     <item msgid="8184570120217958741">"Секогаш дозволувај"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Нормална"</item>
+    <item msgid="5101233285497327432">"Умерена"</item>
+    <item msgid="1555861583162930714">"Ниска"</item>
+    <item msgid="1719683776264798117">"Критично"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Нормално"</item>
+    <item msgid="6107138933849816768">"Умерено"</item>
+    <item msgid="182695359839047859">"Ниска"</item>
+    <item msgid="8577246509202964244">"Критична"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Постојано"</item>
     <item msgid="167418068739176448">"Врвна активност"</item>
@@ -320,7 +472,7 @@
     <item msgid="3118234477029486741">"0"</item>
   </string-array>
   <string-array name="wifi_metered_entries">
-    <item msgid="4329206416008519163">"Откриј автоматски"</item>
+    <item msgid="4329206416008519163">"Откривај автоматски"</item>
     <item msgid="773943026484148895">"Сметај како ограничена мрежа"</item>
     <item msgid="1008268820118852416">"Сметај како неограничена мрежа"</item>
   </string-array>
diff --git a/tests/CarDeveloperOptions/res/values-mk/config.xml b/tests/CarDeveloperOptions/res/values-mk/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-mk/config.xml
+++ b/tests/CarDeveloperOptions/res/values-mk/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-mk/strings.xml b/tests/CarDeveloperOptions/res/values-mk/strings.xml
index b95427b..8aa9d8a 100644
--- a/tests/CarDeveloperOptions/res/values-mk/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-mk/strings.xml
@@ -27,7 +27,7 @@
       <item quantity="other">Сега сте на <xliff:g id="STEP_COUNT_1">%1$d</xliff:g> чекори поблиску да станете програмер.</item>
     </plurals>
     <string name="show_dev_on" msgid="9075712234786224065">"Сега сте развивач"</string>
-    <string name="show_dev_already" msgid="7665948832405148689">"Нема потреба, веќе сте развивач"</string>
+    <string name="show_dev_already" msgid="7665948832405148689">"Нема потреба, веќе сте програмер"</string>
     <string name="dev_settings_disabled_warning" msgid="3198732189395396721">"Прво овозможете ги опциите за програмери."</string>
     <string name="header_category_wireless_networks" msgid="8968405993937795898">"Безжичен и мрежи"</string>
     <string name="header_category_system" msgid="4045988717359334410">"Систем"</string>
@@ -52,7 +52,7 @@
     <string name="radio_info_ims_reg_status_registered" msgid="2500942310925593662">"Регистриран"</string>
     <string name="radio_info_ims_reg_status_not_registered" msgid="1286050699734226077">"Не е регистриран"</string>
     <string name="radio_info_ims_feature_status_available" msgid="2040629393134756058">"Достапен"</string>
-    <string name="radio_info_ims_feature_status_unavailable" msgid="3348223769202693596">"Недостапен"</string>
+    <string name="radio_info_ims_feature_status_unavailable" msgid="3348223769202693596">"Недостапно"</string>
     <string name="radio_info_ims_reg_status" msgid="4771711884059371514">"IMS-регистрација: <xliff:g id="STATUS">%1$s</xliff:g>\nКомуникација преку LTE (VoLTE): <xliff:g id="AVAILABILITY_0">%2$s</xliff:g>\nКомуникација преку Wi-Fi: <xliff:g id="AVAILABILITY_1">%3$s</xliff:g>\nВидеоповици: <xliff:g id="AVAILABILITY_2">%4$s</xliff:g>\nUT-интерфејс: <xliff:g id="AVAILABILITY_3">%5$s</xliff:g>"</string>
     <string name="radioInfo_service_in" msgid="1297020186765943857">"Во употреба"</string>
     <string name="radioInfo_service_out" msgid="8460363463722476510">"Надвор од употреба"</string>
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Намалете го или зголемете го текстот на екранот."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Намали"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Зголеми"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Примерок на текст"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Чудесниот волшебник од Оз"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Поглавје 11: Чудесниот смарагден град Оз"</string>
@@ -101,7 +100,7 @@
     <string name="bluetooth_lock_voice_dialing" msgid="1600385868298081015">"Заклучи гласовно бирање"</string>
     <string name="bluetooth_lock_voice_dialing_summary" msgid="5005776616112427980">"Спречи употреба на бирач со Bluetooth кога екранот е заклучен"</string>
     <string name="bluetooth_devices" msgid="4143880830505625666">"Уреди со Bluetooth"</string>
-    <string name="bluetooth_device_name" msgid="3682016026866302981">"Име на уред"</string>
+    <string name="bluetooth_device_name" msgid="3682016026866302981">"Име на уредот"</string>
     <string name="bluetooth_device_details" msgid="2500840679106321361">"Поставки за уред"</string>
     <string name="bluetooth_profile_details" msgid="1785505059738682493">"Поставки на профил"</string>
     <string name="bluetooth_name_not_set" msgid="1886067683138385142">"Нема поставено име, се користи името на сметката"</string>
@@ -196,11 +195,11 @@
     <string name="intent_sender_account_label" msgid="7904284551281213567">"Сметка:"</string>
     <string name="proxy_settings_title" msgid="6014901859338211713">"Прокси"</string>
     <string name="proxy_clear_text" msgid="498317431076294101">"Исчисти"</string>
-    <string name="proxy_port_label" msgid="8285157632538848509">"Порт за прокси"</string>
+    <string name="proxy_port_label" msgid="8285157632538848509">"Порта за прокси"</string>
     <string name="proxy_exclusionlist_label" msgid="8179084955547941904">"Заобиколи прокси за"</string>
     <string name="proxy_defaultView_text" msgid="5785775257042403261">"Врати стандардни вредности"</string>
     <string name="proxy_action_text" msgid="814511434843981413">"Готово"</string>
-    <string name="proxy_hostname_label" msgid="6798891831427287847">"Име на домаќин на прокси"</string>
+    <string name="proxy_hostname_label" msgid="6798891831427287847">"Име на хост за прокси"</string>
     <string name="proxy_error" msgid="5036164133669802299">"Внимание"</string>
     <string name="proxy_error_dismiss" msgid="883805570485635650">"Во ред"</string>
     <string name="proxy_error_invalid_host" msgid="5430640241353307223">"Името на домаќинот што го внесовте не е важечко."</string>
@@ -208,7 +207,7 @@
     <string name="proxy_error_empty_port" msgid="8034561724923076215">"Порт полето треба да се пополни."</string>
     <string name="proxy_error_empty_host_set_port" msgid="8471455809508588255">"Полето на портот мора да биде празно ако полето на хостот е празно."</string>
     <string name="proxy_error_invalid_port" msgid="4046559920586100637">"Внесениот порт не е исправен."</string>
-    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"HTTP проксито го користи прелистувачот, но не може да го користат другите апликации."</string>
+    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"Прелистувачот користи HTTP-прокси, но не може да го користат и другите апликации."</string>
     <string name="proxy_url_title" msgid="882042361706435904">"PAC URL: "</string>
     <string name="radio_info_dl_kbps" msgid="2903778264453410272">"Брзина на пренос при преземање (кбит/с):"</string>
     <string name="radio_info_ul_kbps" msgid="3802245899811732716">"Брзина на пренос при прикачување (кбит/с):"</string>
@@ -268,7 +267,7 @@
     <string name="next_label" msgid="4710056309804362410">"Следно"</string>
     <string name="language_picker_title" msgid="7807759931261107686">"Јазици"</string>
     <string name="locale_remove_menu" msgid="3395565699934985486">"Отстрани"</string>
-    <string name="add_a_language" msgid="4103889327406274800">"Додај јазик"</string>
+    <string name="add_a_language" msgid="4103889327406274800">"Додајте јазик"</string>
     <plurals name="dlg_remove_locales_title" formatted="false" msgid="7362450618787242592">
       <item quantity="one">Да се отстранат избраните јазици?</item>
       <item quantity="other">Да се отстранат избраните јазици?</item>
@@ -323,8 +322,8 @@
     <string name="date_and_time_settings_title" msgid="7827088656940910631">"Датум и време"</string>
     <string name="date_and_time_settings_title_setup_wizard" msgid="1573030770187844365">"Постави датум и време"</string>
     <string name="date_and_time_settings_summary" msgid="4617979434474713417">"Постави датум, време, временска зона и формати"</string>
-    <string name="date_time_auto" msgid="2679132152303750218">"Користи време дадено од мрежа"</string>
-    <string name="zone_auto_title" msgid="5500880975376882488">"Користи временска зона обезбедена од мрежа"</string>
+    <string name="date_time_auto" msgid="2679132152303750218">"Користи време од мрежата"</string>
+    <string name="zone_auto_title" msgid="5500880975376882488">"Користи часовна зона од мрежата"</string>
     <string name="date_time_24hour_auto" msgid="7499659679134962547">"Користи локален стандард"</string>
     <string name="date_time_24hour_title" msgid="6209923858891621283">"Формат од 24 часа"</string>
     <string name="date_time_24hour" msgid="1265706705061608742">"Користи 24-часовен формат"</string>
@@ -356,7 +355,7 @@
     <string name="security_enable_widgets_title" msgid="1701510007926738088">"Овозможи виџети"</string>
     <string name="security_enable_widgets_disabled_summary" msgid="4408176087132339331">"Оневозможено од администраторот"</string>
     <string name="lockdown_settings_title" msgid="4534779922580115990">"Приказ на опцијата за заклучување"</string>
-    <string name="lockdown_settings_summary" msgid="7270756909878256174">"Опција на копчето за вклучување на екранот што ги исклучува Smart Lock, отклучувањето со отпечаток и известувањата на заклучениот екран"</string>
+    <string name="lockdown_settings_summary" msgid="7270756909878256174">"Прикажувај опција на копчето за вклучување на екранот што ги исклучува Smart Lock, отклучувањето со отпечаток и известувањата на заклучениот екран"</string>
     <string name="trust_agents_extend_unlock_title" msgid="3582017561316089951">"Продолжено отклуч. за агенти од доверба"</string>
     <string name="trust_agents_extend_unlock_summary" msgid="3543997596586078084">"Ако се овозможени, агентите од доверба ќе го држат уредот отклучен подолго време, но веќе нема да може да отклучат заклучен уред."</string>
     <string name="trust_lost_locks_screen_title" msgid="3094736590690459372">"Заклучен екран кога довербата е загубена"</string>
@@ -411,7 +410,7 @@
     <string name="face_add_max" msgid="8870899421165189413">"Може да додадете до <xliff:g id="COUNT">%d</xliff:g> лица"</string>
     <string name="face_intro_error_max" msgid="4024147799079828937">"Додадовте максимален број лица"</string>
     <string name="face_intro_error_unknown" msgid="3241592604198351134">"Не може да додадете повеќе лица"</string>
-    <string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"Запишувањето не е завршено"</string>
+    <string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"Регистрацијата не е завршена"</string>
     <string name="security_settings_face_enroll_dialog_ok" msgid="1078348922734845090">"Во ред"</string>
     <string name="security_settings_face_enroll_error_timeout_dialog_message" msgid="4917894418448325405">"Се достигна временското ограничување на запишувањето со лице. Обидете се повторно."</string>
     <string name="security_settings_face_enroll_error_generic_dialog_message" msgid="5160473187142616862">"Не успеа запишувањето со лице."</string>
@@ -488,7 +487,7 @@
     <string name="security_settings_fingerprint_enroll_done" msgid="4111289529758845926">"Готово"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"Упс, тоа не е сензорот"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"Допрете го сензорот одзади со показалецот."</string>
-    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"Запишувањето не е завршено"</string>
+    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"Регистрацијата не е завршена"</string>
     <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Се достигна временското ограничување на запишувањето со отпечаток од прст. Обидете се повторно."</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"Запишувањето со отпечаток од прст не успеа. Обидете се повторно или користете друг прст."</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"Додај друг"</string>
@@ -504,7 +503,7 @@
     <string name="fingerprint_delete_message" msgid="5895802741486967970">"Дали сакате да го избришете отпечатоков?"</string>
     <string name="fingerprint_last_delete_message" msgid="3346252479778971442">"Нема да може да ги користите отпечатоците за да го отклучите телефонот, да одобрувате купувања или да се најавувате на апликации со нив"</string>
     <string name="fingerprint_last_delete_message_profile_challenge" msgid="5385095150532247025">"Нема да може да ги користите отпечатоците за да го отклучите работниот профил, да одобрувате купувања или да се најавувате на апликациите за работа"</string>
-    <string name="fingerprint_last_delete_confirm" msgid="7984595457589664004">"Отстрани го"</string>
+    <string name="fingerprint_last_delete_confirm" msgid="7984595457589664004">"Отстрани"</string>
     <string name="crypt_keeper_settings_title" msgid="839783588093862748">"Шифрирање"</string>
     <string name="crypt_keeper_encrypt_title" product="tablet" msgid="2292129135369853167">"Шифрирај таблет"</string>
     <string name="crypt_keeper_encrypt_title" product="default" msgid="3110852053238357832">"Шифрирање на телефонот"</string>
@@ -544,7 +543,7 @@
     <string name="suggested_fingerprint_lock_settings_summary" product="tablet" msgid="8114514312665251311"></string>
     <string name="suggested_fingerprint_lock_settings_summary" product="device" msgid="8114514312665251311"></string>
     <string name="suggested_fingerprint_lock_settings_summary" product="default" msgid="8114514312665251311"></string>
-    <string name="lock_settings_picker_title" msgid="1034741644461982205">"Избери заклучување на екранот"</string>
+    <string name="lock_settings_picker_title" msgid="1034741644461982205">"Заклучување на екранот"</string>
     <string name="lock_settings_picker_title_profile" msgid="5086594364428782115">"Избери закл. раб. профил"</string>
     <string name="setup_lock_settings_picker_title" product="tablet" msgid="2429667472335773519">"Заштитете го таблетот"</string>
     <string name="setup_lock_settings_picker_title" product="device" msgid="4739290104106645233">"Заштитете го уредот"</string>
@@ -656,8 +655,8 @@
       <item quantity="other">Мора да содржи барем <xliff:g id="COUNT_1">%d</xliff:g> знаци</item>
     </plurals>
     <plurals name="lockpassword_pin_too_short" formatted="false" msgid="6805936168283187298">
-      <item quantity="one">PIN-от мора да има најмалку <xliff:g id="COUNT_1">%d</xliff:g> цифра</item>
-      <item quantity="other">PIN-от мора да има најмалку <xliff:g id="COUNT_1">%d</xliff:g> цифри</item>
+      <item quantity="one">PIN-кодот мора да содржи барем <xliff:g id="COUNT_1">%d</xliff:g> цифра</item>
+      <item quantity="other">PIN-кодот мора да содржи барем <xliff:g id="COUNT_1">%d</xliff:g> цифри</item>
     </plurals>
     <string name="lockpassword_continue_label" msgid="7279261861924400655">"Продолжи"</string>
     <plurals name="lockpassword_password_too_long" formatted="false" msgid="7994068708438608179">
@@ -668,7 +667,6 @@
       <item quantity="one">Мора да има помалку од <xliff:g id="NUMBER_1">%d</xliff:g> цифра</item>
       <item quantity="other">Мора да има помалку од <xliff:g id="NUMBER_1">%d</xliff:g> цифри</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Мора да содржи само цифри од 0 до 9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Администраторот на уредот не дозволува користење на неодамнешен PIN"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Обичните PIN-кодови се блокирани од вашиот IT-администратор. Обидете се со друг PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Ова не може да вклучува неважечки знак"</string>
@@ -699,6 +697,10 @@
       <item quantity="one">Мора да содржи најмалку <xliff:g id="COUNT">%d</xliff:g> знак што не е буква</item>
       <item quantity="other">Мора да содржи најмалку <xliff:g id="COUNT">%d</xliff:g> знаци што не се букви</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">Мора да содржи најмалку <xliff:g id="COUNT">%d</xliff:g> знак што не е буква</item>
+      <item quantity="other">Мора да содржи најмалку <xliff:g id="COUNT">%d</xliff:g> знаци што не се букви</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Администраторот на уредот не дозволува користење на неодамнешна лозинка"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Обичните лозинки се блокирани од вашиот IT-администратор. Обидете се со друга лозинка."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Не е дозволена нагорна, надолна или повторлива секвенца на цифри"</string>
@@ -716,7 +718,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> активни апликации</item>
     </plurals>
     <string name="manage_trust_agents" msgid="8129970926213142261">"Агенти од доверба"</string>
-    <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"Прво поставете заклучување на екран"</string>
+    <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"Прво поставете заклучување екран"</string>
     <string name="manage_trust_agents_summary" msgid="2023116850759962248">"Ниеден"</string>
     <plurals name="manage_trust_agents_summary_on" formatted="false" msgid="5550538038916606097">
       <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> активен агент од доверба</item>
@@ -727,7 +729,7 @@
     <string name="bluetooth_settings" msgid="5228032727293770389">"Bluetooth"</string>
     <string name="bluetooth_settings_title" msgid="7261244857456521825">"Bluetooth"</string>
     <string name="bluetooth_settings_summary" msgid="1221689092429277887">"Управувај со конекции, постави име и откривливост на уредот"</string>
-    <string name="bluetooth_pairing_request" msgid="7221745525632573125">"Спарете со <xliff:g id="DEVICE_NAME">%1$s</xliff:g>?"</string>
+    <string name="bluetooth_pairing_request" msgid="7221745525632573125">"Да се спари со <xliff:g id="DEVICE_NAME">%1$s</xliff:g>?"</string>
     <string name="bluetooth_pairing_key_msg" msgid="1139230917419961975">"Код за спарување на Bluetooth"</string>
     <string name="bluetooth_enter_passkey_msg" msgid="6205151011298670207">"Внесете го кодот за спарување, а потоа притиснете Врати или Внеси"</string>
     <string name="bluetooth_enable_alphanumeric_pin" msgid="9138308197078115672">"PIN-от содржи букви или симболи"</string>
@@ -744,7 +746,7 @@
     <string name="bluetooth_preference_scan_title" msgid="457781003962324807">"Скенирај за уреди"</string>
     <string name="bluetooth_search_for_devices" msgid="6796307228261078451">"Освежи"</string>
     <string name="bluetooth_searching_for_devices" msgid="7820814625522702494">"Пребарување..."</string>
-    <string name="bluetooth_preference_device_settings" msgid="4247085616427015908">"Поставки на уред"</string>
+    <string name="bluetooth_preference_device_settings" msgid="4247085616427015908">"Поставки за уредот"</string>
     <string name="bluetooth_preference_paired_dialog_title" msgid="3567187438908143693">"Спарен уред"</string>
     <string name="bluetooth_preference_paired_dialog_internet_option" msgid="3693599743477470469">"Интернет врска"</string>
     <string name="bluetooth_preference_paired_dialog_keyboard_option" msgid="4627309436489645755">"Тастатура"</string>
@@ -800,7 +802,7 @@
     <string name="wifi_display_enable_menu_item" msgid="4578340247147692250">"Овозможи приказ на безжични мрежи"</string>
     <string name="wifi_display_no_devices_found" msgid="186501729518830451">"Не се пронајдени уреди во близина."</string>
     <string name="wifi_display_status_connecting" msgid="3799827425457383349">"Се поврзува"</string>
-    <string name="wifi_display_status_connected" msgid="85692409327461403">"Поврзана"</string>
+    <string name="wifi_display_status_connected" msgid="85692409327461403">"Поврзано"</string>
     <string name="wifi_display_status_in_use" msgid="7646114501132773174">"Во употреба"</string>
     <string name="wifi_display_status_not_available" msgid="5600448733204688205">"Недостапна"</string>
     <string name="wifi_display_details" msgid="6379855523460749126">"Поставки за приказ"</string>
@@ -824,7 +826,7 @@
     <string name="nfc_disclaimer_title" msgid="4860231267351602970">"Вклучете NFC"</string>
     <string name="nfc_disclaimer_content" msgid="3066113577854565782">"NFC разменува податоци меѓу уредов и други уреди или цели во близина, како што се терминали за плаќање, читачи за пристап и интерактивни реклами или ознаки."</string>
     <string name="nfc_secure_settings_title" msgid="5153751163174916581">"Заштитете ја NFC"</string>
-    <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"Дозволете употреба на плаќања и јавен превоза преку NFC само кога екранот е отклучен"</string>
+    <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"Дозволи користење на NFC за плаќање и јавен превоз само кога екранот е отклучен"</string>
     <string name="android_beam_settings_title" msgid="3083436415873738389">"Android Beam"</string>
     <string name="android_beam_on_summary" msgid="8068287225180474199">"Подготвено за пренос на содржина на апликација преку комуникација на блиско поле (NFC)"</string>
     <string name="android_beam_off_summary" msgid="7365818039159364600">"Исклучено"</string>
@@ -842,22 +844,22 @@
     <string name="wifi_starting" msgid="1299466156783469023">"Вклучување на Wi-Fi..."</string>
     <string name="wifi_stopping" msgid="413711069039939520">"Исклучување на Wi-Fi..."</string>
     <string name="wifi_error" msgid="5605801874484465557">"Грешка"</string>
-    <string name="wifi_sap_no_channel_error" msgid="6881796988574851628">"Појас од 5 GHz не е достапен во земјава"</string>
+    <string name="wifi_sap_no_channel_error" msgid="6881796988574851628">"Опсег од 5 GHz не е достапен во земјава"</string>
     <string name="wifi_in_airplane_mode" msgid="4729571191578262246">"Во режим на работа во авион"</string>
-    <string name="wifi_notify_open_networks" msgid="4782239203624619655">"Известување за отворени мрежи"</string>
+    <string name="wifi_notify_open_networks" msgid="4782239203624619655">"Известувај за отворени мрежи"</string>
     <string name="wifi_notify_open_networks_summary" msgid="1383681260705466715">"Извести ме кога ќе биде достапна јавна мрежа со висок квалитет"</string>
-    <string name="wifi_wakeup" msgid="4963732992164721548">"Автоматски вклучи Wi‑Fi"</string>
-    <string name="wifi_wakeup_summary" msgid="1152699417411690">"Wi‑Fi ќе се вклучи автоматски на зачувани мрежи со висок квалитет во близина, како на пр., вашата домашна мрежа"</string>
+    <string name="wifi_wakeup" msgid="4963732992164721548">"Автоматски вклучувај Wi‑Fi"</string>
+    <string name="wifi_wakeup_summary" msgid="1152699417411690">"Wi‑Fi ќе се вклучува автоматски во близина на зачувани мрежи со висок квалитет, како на пр., вашата домашна мрежа"</string>
     <string name="wifi_wakeup_summary_no_location" msgid="3007457288587966962">"Недостапно бидејќи локацијата е исклучена. Вклучете ја "<annotation id="link">"локацијата"</annotation>"."</string>
     <string name="wifi_wakeup_summary_scanning_disabled" msgid="6820040651529910914">"Недостапно бидејќи скенирањето на Wi-Fi е исклучено"</string>
-    <string name="wifi_wakeup_summary_scoring_disabled" msgid="7067018832237903151">"За користење, изберете оператор за оценување мрежа"</string>
+    <string name="wifi_wakeup_summary_scoring_disabled" msgid="7067018832237903151">"За користење, изберете оценувач на мрежата"</string>
     <string name="wifi_poor_network_detection" msgid="7193423327400703073">"Избегнувај слаби поврзувања"</string>
-    <string name="wifi_poor_network_detection_summary" msgid="5539951465985614590">"Не користи Wi-Fi-мрежа, освен ако има добра интернет-врска"</string>
+    <string name="wifi_poor_network_detection_summary" msgid="5539951465985614590">"Не користи Wi-Fi мрежа, освен ако има добра интернет-врска"</string>
     <string name="wifi_avoid_poor_network_detection_summary" msgid="1976503191780928104">"Користи само мрежи со добра интернет-врска"</string>
     <string name="use_open_wifi_automatically_title" msgid="3084513215481454350">"Поврзувај се на отворени мрежи"</string>
     <string name="use_open_wifi_automatically_summary" msgid="8338020172673161754">"Автоматски поврзувај се на јавни мрежи со висок квалитет"</string>
-    <string name="use_open_wifi_automatically_summary_scoring_disabled" msgid="1559329344492373028">"За користење, изберете оператор за оценување мрежа"</string>
-    <string name="use_open_wifi_automatically_summary_scorer_unsupported_disabled" msgid="1123080670578756834">"За користење, изберете компатибилен оператор за оценување мрежа"</string>
+    <string name="use_open_wifi_automatically_summary_scoring_disabled" msgid="1559329344492373028">"За користење, изберете оценувач на мрежата"</string>
+    <string name="use_open_wifi_automatically_summary_scorer_unsupported_disabled" msgid="1123080670578756834">"За користење, изберете компатибилен оценувач на мрежата"</string>
     <string name="wifi_install_credentials" msgid="5650088113710858289">"Инсталирај сертификати"</string>
     <string name="wifi_scan_notify_text" msgid="7614101215028336927">"За да се подобри точноста на локацијата, апликациите и услугите можат да скенираат Wi‑Fi мрежи во секое време, дури и кога Wi‑Fi е исклучено. Ова може да се користи, на пример, за подобрување на функциите и услугите базирани на локација. Може да го измените ова во <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>поставките за скенирање<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
     <string name="wifi_scan_notify_text_scanning_off" msgid="723796963816095410">"За да се подобри точноста на локацијата, вклучете „Скенирање на Wi‑Fi“ во <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>поставките за скенирање<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
@@ -872,10 +874,10 @@
     <string name="wifi_switch_away_when_unvalidated" msgid="2418577764071293971">"Префрли се на мобилен интернет ако Wi-Fi-мрежата го губи пристапот до интернет."</string>
     <string name="wifi_cellular_data_fallback_title" msgid="5067241930716252665">"Автоматски префрли се на мобилен интернет"</string>
     <string name="wifi_cellular_data_fallback_summary" msgid="2721467405851519769">"Користете мобилен интернет кога Wi‑Fi нема пристап до интернет. Може да ви се наплати за потрошениот сообраќај."</string>
-    <string name="wifi_add_network" msgid="4094957940791876640">"Додај мрежа"</string>
+    <string name="wifi_add_network" msgid="4094957940791876640">"Додајте мрежа"</string>
     <string name="wifi_configure_settings_preference_title" msgid="2678534679408777268">"Поставки за Wi‑Fi"</string>
     <string name="wifi_configure_settings_preference_summary_wakeup_on" msgid="5714892572614655675">"Wi‑Fi се вклучува повторно автоматски"</string>
-    <string name="wifi_configure_settings_preference_summary_wakeup_off" msgid="286904094152909651">"Wi‑Fi не се вклучува повторно автоматски"</string>
+    <string name="wifi_configure_settings_preference_summary_wakeup_off" msgid="286904094152909651">"Wi‑Fi не се вклучува автоматски"</string>
     <string name="wifi_access_points" msgid="1647976498906871869">"Wi-Fi мрежи"</string>
     <string name="wifi_menu_more_options" msgid="8318269834264035524">"Повеќе опции"</string>
     <string name="wifi_menu_p2p" msgid="4945665601551289791">"Wi‑Fi Direct"</string>
@@ -887,7 +889,7 @@
     <string name="wifi_menu_forget" msgid="7561140554450163075">"Заборави мрежа"</string>
     <string name="wifi_menu_modify" msgid="4080178040721021101">"Измени мрежа"</string>
     <string name="wifi_empty_list_wifi_off" msgid="272877164691346240">"За да ги видите достапните мрежи, вклучете Wi-Fi."</string>
-    <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"Се пребарува за Wi-Fi мрежи..."</string>
+    <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"Се бараат Wi-Fi мрежи..."</string>
     <string name="wifi_empty_list_user_restricted" msgid="2341613007817352431">"Немате дозвола за промена на Wi-Fi мрежата."</string>
     <string name="wifi_more" msgid="3538241640407382185">"Повеќе"</string>
     <string name="wifi_setup_wps" msgid="6730131677695521321">"Автоматско подесување (WPS)"</string>
@@ -900,19 +902,19 @@
     <string name="wifi_advanced_toggle_description_expanded" msgid="1506697245302596510">"Паѓачки список „Напредни опции“. Допрете двапати за да се собере."</string>
     <string name="wifi_advanced_toggle_description_collapsed" msgid="3014965593695454879">"Паѓачки список „Напредни опции“. Допрете двапати за да се прошири."</string>
     <string name="wifi_ssid" msgid="6746270925975522641">"Име на мрежа"</string>
-    <string name="wifi_ssid_hint" msgid="5010024648106585165">"Внеси SSID"</string>
+    <string name="wifi_ssid_hint" msgid="5010024648106585165">"Внесете SSID"</string>
     <string name="wifi_security" msgid="9136702039496152831">"Безбедност"</string>
     <string name="wifi_hidden_network" msgid="6647772204699776833">"Сокриена мрежа"</string>
     <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Ако вашиот рутер не емитува мрежен ID, а сакате да се поврзете со него во иднина, може да ја поставите мрежата како сокриена.\n\nОва може да создаде безбедносен ризик бидејќи вашиот телефон редовно ќе го емитува својот сигнал за да ја најде мрежата.\n\nПоставувањето на мрежата како сокриена нема да ги смени поставките на рутерот."</string>
     <string name="wifi_signal" msgid="696548364467704808">"Јачина на сигнал"</string>
     <string name="wifi_status" msgid="3439931558930689940">"Статус"</string>
-    <string name="tx_wifi_speed" msgid="2571810085003261073">"Брзина на линкот за пренесување"</string>
-    <string name="rx_wifi_speed" msgid="7392873246110937187">"Брзина на линкот за примање"</string>
+    <string name="tx_wifi_speed" msgid="2571810085003261073">"Брзина на пренос"</string>
+    <string name="rx_wifi_speed" msgid="7392873246110937187">"Брзина на прием"</string>
     <string name="wifi_frequency" msgid="6132852924995724246">"Фреквенција"</string>
     <string name="wifi_ip_address" msgid="5572539114989914831">"IP-адреса"</string>
     <string name="passpoint_label" msgid="7429247462404128615">"Зачувано преку"</string>
     <string name="passpoint_content" msgid="340527524510304327">"Акредитиви на <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_eap_method" msgid="3752116941487485859">"EAP метод"</string>
+    <string name="wifi_eap_method" msgid="3752116941487485859">"EAP-метод"</string>
     <string name="please_select_phase2" msgid="5848080896810435677">"Автентикација во фаза 2"</string>
     <string name="wifi_eap_ca_cert" msgid="1496395241849383785">"Сертификат CA"</string>
     <string name="wifi_eap_domain" msgid="3298302320003640130">"Домен"</string>
@@ -923,22 +925,22 @@
     <string name="wifi_show_password" msgid="7878398590772942202">"Прикажи лозинка"</string>
     <string name="wifi_ap_band_config" msgid="6565016368079288433">"Изберете појас на АП"</string>
     <string name="wifi_ap_choose_auto" msgid="7927637960569365785">"Автоматски"</string>
-    <string name="wifi_ap_choose_2G" msgid="43198403259714736">"Појас од 2,4 GHz"</string>
-    <string name="wifi_ap_choose_5G" msgid="2624859713183683146">"Појас од 5,0 GHz"</string>
-    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"Претпочитан појас: 5,0 GHz"</string>
+    <string name="wifi_ap_choose_2G" msgid="43198403259714736">"Опсег од 2,4 GHz"</string>
+    <string name="wifi_ap_choose_5G" msgid="2624859713183683146">"Опсег од 5,0 GHz"</string>
+    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"Претпочитан опсег: 5,0 GHz"</string>
     <string name="wifi_ap_2G" msgid="5793110086517338494">"2,4 GHz"</string>
     <string name="wifi_ap_5G" msgid="4584892544393675403">"5,0 GHz"</string>
     <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"Изберете барем еден појас за Wi‑Fi точка на пристап:"</string>
-    <string name="wifi_ip_settings" msgid="4636102290236116946">"Поставки на IP"</string>
+    <string name="wifi_ip_settings" msgid="4636102290236116946">"Поставки за IP"</string>
     <string name="wifi_privacy_settings" msgid="4462092795794247809">"Приватност"</string>
     <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"Рандомизирана MAC-адреса"</string>
     <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"Додајте уред"</string>
-    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"Наместете го QR-кодот во средината на подолниот прозорец за да го додадете уредот на „<xliff:g id="SSID">%1$s</xliff:g>“"</string>
-    <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"Скенирај QR-код"</string>
+    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"Наместете го QR-кодот во средината на подолниот прозорец за да го додадете уредот во мрежата „<xliff:g id="SSID">%1$s</xliff:g>“"</string>
+    <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"Скенирајте QR-код"</string>
     <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"Наместете го QR-кодот во средината на подолниот прозорец за да се поврзете со „<xliff:g id="SSID">%1$s</xliff:g>“"</string>
-    <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"Придружете се на Wi‑Fi со скенирање на QR-кодот"</string>
-    <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Сподели Wi‑Fi"</string>
-    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"Скенирајте го овој QR-код за да се поврзете со „<xliff:g id="SSID">%1$s</xliff:g>“ и споделете ја лозинката"</string>
+    <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"Скенирајте го QR-кодот за да се поврзете на Wi‑Fi"</string>
+    <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Споделете Wi‑Fi"</string>
+    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"Скенирајте го овој QR-код за да се поврзете со „<xliff:g id="SSID">%1$s</xliff:g>“ и да ја споделите лозинката"</string>
     <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"Скенирајте го овој QR-код за да се поврзете со „<xliff:g id="SSID">%1$s</xliff:g>“"</string>
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"Не можеше да се прочита QR-кодот. Центрирајте го кодот и обидете се повторно"</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"Обидете се повторно. Ако проблемот продолжи, контактирајте со производителот на уредот"</string>
@@ -960,15 +962,15 @@
     <string name="wifi_dpp_share_hotspot" msgid="847987212473038179">"Споделете точка на пристап"</string>
     <string name="wifi_dpp_lockscreen_title" msgid="3910665850075275963">"Потврдете дека сте вие"</string>
     <string name="wifi_dpp_wifi_password" msgid="8007558344032612455">"Лозинка за Wi-Fi: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
-    <string name="wifi_dpp_hotspot_password" msgid="6172326289042241924">"Лозинка за точка на пристап: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
+    <string name="wifi_dpp_hotspot_password" msgid="6172326289042241924">"Лозинка за точката на пристап: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
     <string name="wifi_dpp_add_device" msgid="1347056725253936358">"Додајте уред"</string>
     <string name="wifi_dpp_connect_network_using_qr_code" msgid="115993715600532357">"ПОврзете се на мрежава со QR-код"</string>
     <string name="retry" msgid="8500839563577344702">"Обиди се повторно"</string>
     <string name="wifi_shared" msgid="5054256778276524960">"Сподели со други корисници на уредот"</string>
-    <string name="wifi_unchanged" msgid="6804964646942333992">"(непроменети)"</string>
+    <string name="wifi_unchanged" msgid="6804964646942333992">"(непроменето)"</string>
     <string name="wifi_unspecified" msgid="893491188483500809">"Изберете"</string>
     <string name="wifi_multiple_cert_added" msgid="7986200585749147204">"(Додадени се повеќе сертификати)"</string>
-    <string name="wifi_use_system_certs" msgid="4794489370929885022">"Користете системски сертификати"</string>
+    <string name="wifi_use_system_certs" msgid="4794489370929885022">"Користи системски сертификати"</string>
     <string name="wifi_do_not_provide_eap_user_cert" msgid="4044301449482425250">"Не обезбедувај"</string>
     <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"Не потврдувај"</string>
     <string name="wifi_do_not_validate_eap_server_warning" msgid="3895397996759837323">"Нема назначено сертификат. Вашата врска нема да биде приватна."</string>
@@ -1018,26 +1020,26 @@
     <string name="wifi_advanced_ssid_title" msgid="4229741334913894856">"SSID"</string>
     <string name="wifi_advanced_mac_address_title" msgid="1162782083754021737">"MAC адреса"</string>
     <string name="wifi_advanced_ip_address_title" msgid="2708185994512829071">"IP-адреса"</string>
-    <string name="wifi_details_title" msgid="2164042631550920157">"Детали за мрежа"</string>
-    <string name="wifi_details_subnet_mask" msgid="53396707004763012">"Маска на подмрежа"</string>
+    <string name="wifi_details_title" msgid="2164042631550920157">"Детали за мрежата"</string>
+    <string name="wifi_details_subnet_mask" msgid="53396707004763012">"Подмрежна маска"</string>
     <string name="wifi_details_dns" msgid="1118251455740116559">"DNS"</string>
-    <string name="wifi_details_ipv6_address_header" msgid="1642310137145363299">"IPv6 адреси"</string>
+    <string name="wifi_details_ipv6_address_header" msgid="1642310137145363299">"IPv6-адреси"</string>
     <string name="wifi_saved_access_points_label" msgid="3790693285928292563">"Зачувани мрежи"</string>
     <string name="wifi_subscribed_access_points_tab" msgid="7498765485953257229">"Претплати"</string>
     <!-- no translation found for wifi_saved_access_points_tab (4677730543624191122) -->
     <skip />
-    <string name="wifi_advanced_settings_label" msgid="9147669851658738784">"Поставки на IP"</string>
+    <string name="wifi_advanced_settings_label" msgid="9147669851658738784">"Поставки за IP"</string>
     <string name="wifi_advanced_not_available" msgid="5751084989400195009">"Напредни поставки за Wi‑Fi не се достапни за корисников"</string>
     <string name="wifi_ip_settings_menu_save" msgid="6557330818360425933">"Зачувај"</string>
     <string name="wifi_ip_settings_menu_cancel" msgid="8098696509412462494">"Откажи"</string>
     <string name="wifi_ip_settings_invalid_ip_address" msgid="7764507690387286292">"Внеси важечка ИП адреса."</string>
     <string name="wifi_ip_settings_invalid_gateway" msgid="7602732367437862422">"Внеси важечка адреса на капија."</string>
     <string name="wifi_ip_settings_invalid_dns" msgid="4471473055625376300">"Внеси важечка адреса на DNS."</string>
-    <string name="wifi_ip_settings_invalid_network_prefix_length" msgid="392977552691002076">"Напишете префикс на мрежа со должина меѓу 0 и 32."</string>
+    <string name="wifi_ip_settings_invalid_network_prefix_length" msgid="392977552691002076">"Внесете мрежен префикс со должина од 0 до 32."</string>
     <string name="wifi_dns1" msgid="5250809981658822505">"DNS 1"</string>
     <string name="wifi_dns2" msgid="1905876166783761641">"DNS 2"</string>
-    <string name="wifi_gateway" msgid="7455334454444443397">"Мрежен мост"</string>
-    <string name="wifi_network_prefix_length" msgid="1941206966133010633">"Долж. на префикс на мрежа"</string>
+    <string name="wifi_gateway" msgid="7455334454444443397">"Портал"</string>
+    <string name="wifi_network_prefix_length" msgid="1941206966133010633">"Должина на мрежен префикс"</string>
     <string name="wifi_p2p_settings_title" msgid="3213180637906683308">"Wi‑Fi Direct"</string>
     <string name="wifi_p2p_device_info" msgid="4717490498956029237">"Информации за уредот"</string>
     <string name="wifi_p2p_persist_network" msgid="1110453878886476660">"Запомни ја оваа врска"</string>
@@ -1060,11 +1062,11 @@
     <string name="wifi_hotspot_tethering_on_subtext" product="default" msgid="8914285514605049879">"Интернет-врската на телефонов се споделува преку точка на пристап"</string>
     <string name="wifi_hotspot_on_local_only_subtext" msgid="7415381343846704553">"Апликацијата споделува содржини. За споделување на интернет-врската, исклучете ја, а потоа вклучете ја точката на пристап"</string>
     <string name="wifi_hotspot_no_password_subtext" msgid="5400500962974373706">"Не е поставена лозинка"</string>
-    <string name="wifi_hotspot_name_title" msgid="6572202165400226127">"Име на точка на пристап"</string>
+    <string name="wifi_hotspot_name_title" msgid="6572202165400226127">"Име на точката на пристап"</string>
     <string name="wifi_hotspot_name_summary_connecting" msgid="5176787959408511889">"Се вклучува <xliff:g id="WIFI_HOTSPOT_NAME">%1$s</xliff:g>…"</string>
     <string name="wifi_hotspot_name_summary_connected" msgid="8387768642326756749">"Другите уреди може да се поврзат на <xliff:g id="WIFI_HOTSPOT_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_hotspot_password_title" msgid="4289338152595154889">"Лозинка на точка на пристап"</string>
-    <string name="wifi_hotspot_ap_band_title" msgid="3485744480410441949">"Појас на точката на пристап"</string>
+    <string name="wifi_hotspot_password_title" msgid="4289338152595154889">"Лозинка за точката на пристап"</string>
+    <string name="wifi_hotspot_ap_band_title" msgid="3485744480410441949">"Опсег на точката на пристап"</string>
     <string name="wifi_hotspot_footer_info_regular" msgid="3876006922622827363">"Користете точка на пристап за да создадете Wi‑Fi мрежа за другите уреди. Точката на пристап обезбедува интернет со помош на мобилната интернет-врска. Може да ви се наплатат дополнителни трошоци за мобилен интернет."</string>
     <string name="wifi_hotspot_footer_info_local_only" msgid="3339582350894639261">"Апликациите може да создадат точка на пристап за да споделуваат содржини со уредите во близина."</string>
     <string name="wifi_hotspot_auto_off_title" msgid="7416022590415189590">"Автоматско исклучување на точката на пристап"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Мобилен интернет"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Ако Wi‑Fi не е достапно, користи ја мобилната мрежа"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Ако мобилната мрежа не е достапна, користи Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Повикувај преку Wi-Fi. Ако Wi‑Fi врската се загуби, повикот ќе заврши."</string>
@@ -1281,7 +1286,7 @@
     <string name="sim_reenter_new" msgid="5692585822458989725">"Повторно внеси нов PIN"</string>
     <string name="sim_change_pin" msgid="1674620855223900785">"PIN на SIM картичка"</string>
     <string name="sim_bad_pin" msgid="2409776007569751629">"Неточен PIN"</string>
-    <string name="sim_pins_dont_match" msgid="1076283313667637902">"PIN-овите не се совпаѓаат"</string>
+    <string name="sim_pins_dont_match" msgid="1076283313667637902">"PIN-кодовите не се совпаѓаат"</string>
     <string name="sim_change_failed" msgid="8874765697694275459">"Не може да го промените PIN-от.\nМожно е PIN-от да е погрешен."</string>
     <string name="sim_change_succeeded" msgid="8802418023120614533">"PIN на SIM картичката е успешно променет"</string>
     <string name="sim_lock_failed" msgid="7949781515066772755">"Не може да се промени состојбата на заклучување на SIM картичката.\nМожно е PIN-от да е погрешен."</string>
@@ -1311,7 +1316,7 @@
     <string name="hardware_info" msgid="174270144950621815">"Модел и хардвер"</string>
     <string name="hardware_revision" msgid="3315744162524354246">"Верзија на хардвер"</string>
     <string name="fcc_equipment_id" msgid="8681995718533066093">"ID на опрема"</string>
-    <string name="baseband_version" msgid="9115560821840757786">"Верзија со основен појас на фреквенција"</string>
+    <string name="baseband_version" msgid="9115560821840757786">"Верзија на немодулиран опсег"</string>
     <string name="kernel_version" msgid="8226014277756019297">"Верзија на кернел"</string>
     <string name="build_number" msgid="8648447688306248633">"Број на верзија"</string>
     <string name="module_version" msgid="1127871672527968730">"Верзии на модулот за главната линија"</string>
@@ -1352,7 +1357,7 @@
     <string name="status_signal_strength" msgid="4302597886933728789">"Јачина на сигнал"</string>
     <string name="status_roaming" msgid="5191044997355099561">"Роаминг"</string>
     <string name="status_operator" msgid="6017986100643755390">"Мрежа"</string>
-    <string name="status_wifi_mac_address" msgid="3868452167971295995">"Адреса на MAC за Wi-Fi"</string>
+    <string name="status_wifi_mac_address" msgid="3868452167971295995">"MAC-адреса на Wi-Fi"</string>
     <string name="status_bt_address" msgid="460568179311735657">"Адреса на Bluetooth"</string>
     <string name="status_serial_number" msgid="8257722124627415159">"Сериски број"</string>
     <string name="status_up_time" msgid="77128395333934087">"Време од последно рестартирање"</string>
@@ -1411,7 +1416,7 @@
     <string name="storage_menu_migrate" msgid="1885806122515759703">"Мигрирај податоци"</string>
     <string name="storage_menu_forget" msgid="4345021250834642640">"Заборави"</string>
     <string name="storage_menu_set_up" msgid="2849170579745958513">"Постави"</string>
-    <string name="storage_menu_explore" msgid="3733439525636202662">"Истражувај"</string>
+    <string name="storage_menu_explore" msgid="3733439525636202662">"Разгледајте"</string>
     <string name="storage_menu_free" msgid="6586253660759145508">"Ослободи простор"</string>
     <string name="storage_menu_manage" msgid="461380717863926516">"Управувајте со капацитетот"</string>
     <string name="storage_title_usb" msgid="2015671467177303099">"USB врска со компјутер"</string>
@@ -1453,7 +1458,7 @@
     <string name="storage_detail_system" msgid="6784247618772153283">"Систем"</string>
     <string name="storage_detail_explore" msgid="8206900269596580264">"Истражи <xliff:g id="NAME">^1</xliff:g>"</string>
     <string name="storage_detail_dialog_other" msgid="5073511663616043370">"Под друго, се подразбира споделени датотеки што ги зачувале апликациите, датотеки преземени од интернет или Bluetooth, датотеки на Android итн. \n\nЗа да ги видите видливите содржини на <xliff:g id="NAME">^1</xliff:g>, допрете „Истражете“."</string>
-    <string name="storage_detail_dialog_system" msgid="1472572861360014226">"Системот опфаќа датотеки што се извршуваат на верзијата <xliff:g id="VERSION">%s</xliff:g> на Android"</string>
+    <string name="storage_detail_dialog_system" msgid="1472572861360014226">"Системот опфаќа датотеки што се користат за извршување на верзијата <xliff:g id="VERSION">%s</xliff:g> на Android"</string>
     <string name="storage_detail_dialog_user" msgid="1663117417635010371">"<xliff:g id="USER_0">^1</xliff:g> може да има зачувани фотографии, музика, апликации или други податоци што зафаќаат <xliff:g id="SIZE">^2</xliff:g> меморија. \n\nЗа детали, префрлете се на <xliff:g id="USER_1">^1</xliff:g>."</string>
     <string name="storage_wizard_init_title" msgid="3407283236421089014">"Поставете <xliff:g id="NAME">^1</xliff:g>"</string>
     <string name="storage_wizard_init_external_title" msgid="6853250619674645478">"Користи како пренослива меморија"</string>
@@ -1523,7 +1528,7 @@
     <string name="battery_level_title" msgid="5207775387973771646">"Ниво на батерија"</string>
     <string name="apn_settings" msgid="8130776653826271664">"Поставки на APN"</string>
     <string name="apn_edit" msgid="4350571070853305357">"Измени пристапна точка"</string>
-    <string name="apn_not_set" msgid="5344235604466825691">"Не е подесено"</string>
+    <string name="apn_not_set" msgid="5344235604466825691">"Не е поставено"</string>
     <string name="apn_name" msgid="8431432886706852226">"Име"</string>
     <string name="apn_apn" msgid="190519449579357696">"APN"</string>
     <string name="apn_http_proxy" msgid="8816906767987944465">"Прокси"</string>
@@ -1564,11 +1569,11 @@
     <string name="menu_restore" msgid="3799288817317293115">"Ресетирај на стандардни вредности"</string>
     <string name="restore_default_apn_completed" msgid="5671734152740058937">"Ресетирањето стандардни поставки на APN е завршено."</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"Опции за ресетирање"</string>
-    <string name="reset_dashboard_summary" msgid="8778383341461126642">"Може да се ресетира мрежа, апликации или уред"</string>
+    <string name="reset_dashboard_summary" msgid="8778383341461126642">"Мрежата, апликациите или уредот може да се ресетираат"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"Ресетирај Wi-Fi, мобилен интернет и Bluetooth"</string>
     <string name="reset_network_desc" msgid="4982633363916261109">"Ова ќе ги ресетира сите мрежни поставки, вклучувајќи:\n\n"<li>"Wi‑Fi"</li>\n<li>"Мобилен интернет"</li>\n<li>"Bluetooth"</li></string>
     <string name="reset_esim_title" msgid="7630781767040831893">"Избриши преземени SIM-картички"</string>
-    <string name="reset_esim_desc" msgid="433226911566802">"За да преземете SIM-картички за замена, контактирајте со операторот. Ова нема да ги откаже плановите за мобилни услуги."</string>
+    <string name="reset_esim_desc" msgid="433226911566802">"За да преземете SIM-картички за замена, контактирајте со операторот. Со ова не се откажуваат пакети за мобилни услуги."</string>
     <string name="reset_network_button_text" msgid="4293271046867912819">"Ресетирај поставки"</string>
     <string name="reset_network_final_desc" msgid="2463817067048751373">"Да се ресетираат сите мрежни поставки? Ова дејство не може да се врати."</string>
     <string name="reset_network_final_desc_esim" msgid="4676436976372555750">"Да се ресетираат сите мрежни поставки и да се избришат преземените SIM-картички? Ова дејство не може да се врати."</string>
@@ -1580,13 +1585,13 @@
     <string name="reset_esim_error_msg" msgid="4716366079119742235">"Преземените SIM-картички не може да се избришат поради грешка.\n\nРестартирајте го уредот и обидете се повторно."</string>
     <string name="master_clear_title" msgid="1560712943955904673">"Избриши ги сите податоци (фабричко ресетирање)"</string>
     <string name="master_clear_short_title" msgid="919098101581335101">"Избриши ги сите податоци"</string>
-    <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"Ова ќе ги избрише сите податоци од "<b>"внатрешна меморија"</b>"на вашиот таблет, заедно со:\n\n"<li>"вашата сметка на Google;"</li>\n<li>"податоците и поставките на системот и апликациите;"</li>\n<li>"преземените апликации."</li></string>
-    <string name="master_clear_desc" product="default" msgid="8765543541962866697">"Ова ќе ги избрише сите податоци од "<b>"внатрешната меморија"</b>" на телефонот, заедно со:\n\n"<li>"вашата сметка на Google;"</li>\n<li>"податоците и поставките на системот и апликациите;"</li>\n<li>"преземените апликации."</li></string>
+    <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"Ова ќе ги избрише сите податоци од "<b>"внатрешната меморија"</b>"на таблетот, заедно со:\n\n"<li>"вашата сметка на Google"</li>\n<li>"податоците и поставките на системот и апликациите"</li>\n<li>"преземените апликации"</li></string>
+    <string name="master_clear_desc" product="default" msgid="8765543541962866697">"Ова ќе ги избрише сите податоци од "<b>"внатрешната меморија"</b>" на телефонот, заедно со:\n\n"<li>"вашата сметка на Google"</li>\n<li>"податоците и поставките на системот и апликациите"</li>\n<li>"преземените апликации"</li></string>
     <string name="master_clear_accounts" product="default" msgid="3432884235445405376">\n\n"Моментално сте најавени на следниве сметки:\n"</string>
     <string name="master_clear_other_users_present" product="default" msgid="5993259656117566767">\n\n"Присутни се и други корисници на уредот.\n"</string>
     <string name="master_clear_desc_also_erases_external" msgid="3947303501615091903"><li>"Музика"</li>\n<li>"Фотографии"</li>\n<li>"Други податоци за корисникот"</li></string>
-    <string name="master_clear_desc_also_erases_esim" msgid="4497260499055258773"><li>"eSIM-картички"</li></string>
-    <string name="master_clear_desc_no_cancel_mobile_plan" msgid="6072668588881679461">\n\n"Тоа нема да го откаже вашиот пакет за мобилни услуги."</string>
+    <string name="master_clear_desc_also_erases_esim" msgid="4497260499055258773"><li>"eSIM-картичките"</li></string>
+    <string name="master_clear_desc_no_cancel_mobile_plan" msgid="6072668588881679461">\n\n"Со ова нема да се откаже вашиот пакет за мобилни услуги."</string>
     <string name="master_clear_desc_erase_external_storage" product="nosdcard" msgid="2723272952715259307">\n\n"За да исчистите музика, слики и други податоци на корисникот, "<b>"меморијата"</b>" треба да се избрише."</string>
     <string name="master_clear_desc_erase_external_storage" product="default" msgid="9003555775524798797">\n\n"За да исчистите музика, слики и други податоци на корисникот, "<b>"СД картичката"</b>" треба да се избрише."</string>
     <string name="erase_external_storage" product="nosdcard" msgid="8989746770347525207">"Избриши USB меморија"</string>
@@ -1603,22 +1608,22 @@
     <string name="master_clear_not_available" msgid="4676613348163652454">"Фабричкото ресетирање не е достапно за овој корисник"</string>
     <string name="master_clear_progress_title" msgid="378953167274114857">"Се брише"</string>
     <string name="master_clear_progress_text" msgid="5418958116008976218">"Почекајте..."</string>
-    <string name="call_settings_title" msgid="5033906789261282752">"Поставки на повик"</string>
+    <string name="call_settings_title" msgid="5033906789261282752">"Поставки за повици"</string>
     <string name="call_settings_summary" msgid="2119161087671450035">"Постави говорна пошта, проследување на повик, повик на чекање, ID на повикувач"</string>
-    <string name="tether_settings_title_usb" msgid="4265582654602420357">"Поврзување со USB"</string>
+    <string name="tether_settings_title_usb" msgid="4265582654602420357">"Интернет преку USB"</string>
     <string name="tether_settings_title_wifi" msgid="2060965130234484613">"Преносл. точка на пристап"</string>
-    <string name="tether_settings_title_bluetooth" msgid="1999590158102569959">"Поврзување со Bluetooth"</string>
-    <string name="tether_settings_title_usb_bluetooth" msgid="1159128764162788159">"Поврзување"</string>
+    <string name="tether_settings_title_bluetooth" msgid="1999590158102569959">"Интернет преку Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="1159128764162788159">"Врзување"</string>
     <string name="tether_settings_title_all" msgid="6935843543433954181">"Точка на пристап и врзување"</string>
     <string name="tether_settings_summary_hotspot_on_tether_on" msgid="1289593649526514499">"Точката на пристап е вклучена, се поврзува"</string>
     <string name="tether_settings_summary_hotspot_on_tether_off" msgid="8010689354668285422">"Точката на пристап е вклучена"</string>
-    <string name="tether_settings_summary_hotspot_off_tether_on" msgid="1349909238672649877">"Поврзување"</string>
+    <string name="tether_settings_summary_hotspot_off_tether_on" msgid="1349909238672649877">"Врзување"</string>
     <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"Не може да се врзе или се да користат преносни точки на пристап додека е вклучен Штедачот на интернет"</string>
     <string name="usb_title" msgid="7480927657535578688">"USB"</string>
-    <string name="usb_tethering_button_text" msgid="6242228383142012332">"Поврзување со USB"</string>
+    <string name="usb_tethering_button_text" msgid="6242228383142012332">"Интернет преку USB"</string>
     <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"Споделете ја интернет-врската на телефонот преку USB"</string>
     <string name="usb_tethering_subtext" product="tablet" msgid="154536000235361034">"Споделете ја интернет-врската на таблетот преку USB"</string>
-    <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"Поврзување со Bluetooth"</string>
+    <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"Интернет преку Bluetooth"</string>
     <string name="bluetooth_tethering_subtext" product="tablet" msgid="6868756914621131635">"Споделете ја интернет-врската на таблетот преку Bluetooth"</string>
     <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"Споделете ја интернет-врската на телефонот преку Bluetooth"</string>
     <string name="bluetooth_tethering_off_subtext_config" msgid="3981528184780083266">"Интернет-врската на <xliff:g id="DEVICE_NAME">%1$d</xliff:g> се споделува преку Bluetooth"</string>
@@ -1632,8 +1637,8 @@
     <string name="sms_change_default_dialog_title" msgid="6301260161969667578">"Избери апликација за SMS"</string>
     <string name="sms_change_default_dialog_text" msgid="8275088077930942680">"Да се користи <xliff:g id="NEW_APP">%1$s</xliff:g> наместо <xliff:g id="CURRENT_APP">%2$s</xliff:g> како SMS-апликација?"</string>
     <string name="sms_change_default_no_previous_dialog_text" msgid="4680224695080527907">"Користи <xliff:g id="NEW_APP">%s</xliff:g> како SMS-апликација?"</string>
-    <string name="network_scorer_picker_title" msgid="1691073966560952916">"Оператор за оценување мрежа"</string>
-    <string name="network_scorer_picker_none_preference" msgid="6448280557733231737">"Ниедно"</string>
+    <string name="network_scorer_picker_title" msgid="1691073966560952916">"Оценувач на мрежата"</string>
+    <string name="network_scorer_picker_none_preference" msgid="6448280557733231737">"Нема"</string>
     <string name="network_scorer_change_active_dialog_title" msgid="4274159562371475090">"Да се промени помошникот за Wi‑Fi?"</string>
     <string name="network_scorer_change_active_dialog_text" msgid="4264089809189760730">"Да се користи <xliff:g id="NEW_APP">%1$s</xliff:g> наместо <xliff:g id="CURRENT_APP">%2$s</xliff:g> за управување со мрежните врски?"</string>
     <string name="network_scorer_change_active_no_previous_dialog_text" msgid="6394483538843474495">"Да се користи <xliff:g id="NEW_APP">%s</xliff:g> за управување на вашите мрежни врски?"</string>
@@ -1651,7 +1656,7 @@
     </plurals>
     <string name="location_category_recent_location_access" msgid="286059523360285026">"Неодамнешен пристап до локацијата"</string>
     <string name="location_recent_location_access_view_details" msgid="2051602261436245905">"Прикажи ги деталите"</string>
-    <string name="location_no_recent_apps" msgid="77502059586413278">"Нема апликации што скоро побарале локација"</string>
+    <string name="location_no_recent_apps" msgid="77502059586413278">"Нема апликации што неодамна побарале утврдување на локацијата"</string>
     <string name="location_no_recent_accesses" msgid="6289916310397279890">"Ниедна апликација нема пристапено до локацијата неодамна"</string>
     <string name="location_high_battery_use" msgid="7177199869979522663">"Голема искористеност на бат."</string>
     <string name="location_low_battery_use" msgid="5030448574501435888">"Мала искористеност на бат."</string>
@@ -1712,7 +1717,7 @@
     <string name="lockpassword_confirm_your_pattern_header" msgid="7137526922696316545">"Потврдете ја шемата"</string>
     <string name="lockpassword_confirm_your_pin_header" msgid="4335593948303036343">"Внесете го PIN-кодот повторно"</string>
     <string name="lockpassword_confirm_passwords_dont_match" msgid="1783767008133345784">"Лозинките не се совпаѓаат"</string>
-    <string name="lockpassword_confirm_pins_dont_match" msgid="5444357293637748942">"PIN-овите не се совпаѓаат"</string>
+    <string name="lockpassword_confirm_pins_dont_match" msgid="5444357293637748942">"PIN-кодовите не се совпаѓаат"</string>
     <string name="lockpassword_draw_your_pattern_again_header" msgid="9017394036814402348">"Нацртајте ја шемата повторно"</string>
     <string name="lockpassword_choose_lock_generic_header" msgid="4418423132980560119">"Избери начин на отклучување"</string>
     <string name="lockpassword_password_set_toast" msgid="601928982984489868">"Лозинката е поставена"</string>
@@ -1737,7 +1742,7 @@
     <string name="lockpassword_confirm_your_pin_details_frp" msgid="6849889353126558761">"Телефонот е ресетиран на фабрички поставки. За да го користите, внесете го претходниот PIN."</string>
     <string name="lockpassword_confirm_your_password_details_frp" msgid="3239944795659418737">"Телефонот е ресетиран на фабрички поставки. За да го користите, внесете ја претходната лозинка."</string>
     <string name="lockpassword_confirm_your_pattern_header_frp" msgid="3290569334665839860">"Потврдете ја шемата"</string>
-    <string name="lockpassword_confirm_your_pin_header_frp" msgid="8520474869079710782">"Потврди PIN"</string>
+    <string name="lockpassword_confirm_your_pin_header_frp" msgid="8520474869079710782">"Потврдете го PIN-от"</string>
     <string name="lockpassword_confirm_your_password_header_frp" msgid="7326670978891793470">"Потврдете ја лозинката"</string>
     <string name="lockpassword_invalid_pin" msgid="3059022215815900137">"Погрешен PIN"</string>
     <string name="lockpassword_invalid_password" msgid="8374331995318204099">"Погрешна лозинка"</string>
@@ -1745,12 +1750,12 @@
     <string name="lock_settings_title" msgid="233657584969886812">"Безбедност на уред"</string>
     <string name="lockpattern_change_lock_pattern_label" msgid="333149762562581510">"Промени шема на отклучување"</string>
     <string name="lockpattern_change_lock_pin_label" msgid="3435796032210265723">"Промени PIN за отклучување"</string>
-    <string name="lockpattern_recording_intro_header" msgid="2262005028838969839">"Нацртајте ја шемата за отклучување"</string>
+    <string name="lockpattern_recording_intro_header" msgid="2262005028838969839">"Нацртајте шема за отклучување"</string>
     <string name="lockpattern_recording_intro_footer" msgid="5426745740754065099">"Притисни „Мени“ за помош."</string>
     <string name="lockpattern_recording_inprogress" msgid="4060818382176523671">"Отпуштете го прстот кога ќе завршите"</string>
     <string name="lockpattern_recording_incorrect_too_short" msgid="6374760294545431845">"Поврзете најмалку <xliff:g id="NUMBER">%d</xliff:g> точки. Обидете се повторно."</string>
     <string name="lockpattern_pattern_entered_header" msgid="2108106638322637851">"Шемата е снимена"</string>
-    <string name="lockpattern_need_to_confirm" msgid="4079482507985867389">"Употреби ја шемата повторно за потврда"</string>
+    <string name="lockpattern_need_to_confirm" msgid="4079482507985867389">"Нацртајте ја шемата повторно за потврда"</string>
     <string name="lockpattern_pattern_confirmed_header" msgid="5603156929428721407">"Вашата нова шема за отклучување"</string>
     <string name="lockpattern_confirm_button_text" msgid="7059311304112902598">"Потврди"</string>
     <string name="lockpattern_restart_button_text" msgid="4322968353922529868">"Измени"</string>
@@ -1787,7 +1792,7 @@
     <string name="install_applications" msgid="7745902974984889179">"Непознати извори"</string>
     <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="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="device" msgid="9141585291103603515">"Вашиот уред и личните податоци се повеќе подложни на напади од непознати апликации. Ако инсталирате апликации од изворов, се согласувате дека сте одговорни за каква било штета на уредот или губење податоци што може да произлезат од користењето на апликациите."</string>
@@ -1800,7 +1805,7 @@
     <string name="screen_compatibility_label" msgid="3638271673726075815">"Компатибилност на екран"</string>
     <string name="permissions_label" msgid="7341733648403464213">"Дозволи"</string>
     <string name="cache_header_label" msgid="3202284481380361966">"Кеш"</string>
-    <string name="clear_cache_btn_text" msgid="107507684844780651">"Исчисти кеш"</string>
+    <string name="clear_cache_btn_text" msgid="107507684844780651">"Избриши кеш"</string>
     <string name="cache_size_label" msgid="6205173678102220499">"Кеш"</string>
     <plurals name="uri_permissions_text" formatted="false" msgid="8938478333743197020">
       <item quantity="one">%d ставка</item>
@@ -1812,7 +1817,7 @@
     <string name="total_size_label" msgid="3929917501176594692">"Вкупно"</string>
     <string name="application_size_label" msgid="175357855490253032">"Големина на апликација"</string>
     <string name="external_code_size_label" msgid="3434421216268309411">"Апликација за USB меморија"</string>
-    <string name="data_size_label" msgid="7790201846922671662">"Податоци на корисникот"</string>
+    <string name="data_size_label" msgid="7790201846922671662">"Кориснички податоци"</string>
     <string name="external_data_size_label" product="nosdcard" msgid="8004991551882573479">"Податоци на USB меморија"</string>
     <string name="external_data_size_label" product="default" msgid="1097584278225902734">"СД картичка"</string>
     <string name="uninstall_text" msgid="4859715815689705801">"Деинсталирај"</string>
@@ -1820,7 +1825,7 @@
     <string name="install_text" msgid="2798092278891807849">"Инсталирај"</string>
     <string name="disable_text" msgid="5065834603951474397">"Оневозможи"</string>
     <string name="enable_text" msgid="7179141636849225884">"Овозможи"</string>
-    <string name="clear_user_data_text" msgid="8894073247302821764">"Исчисти ја меморијата"</string>
+    <string name="clear_user_data_text" msgid="8894073247302821764">"Ослободи простор"</string>
     <string name="app_factory_reset" msgid="8718986000278776272">"Деинсталирај ажурирања"</string>
     <string name="auto_launch_enable_text" msgid="3372898942144027341">"Избравте оваа апликација да се стартува стандардно за некои дејства."</string>
     <string name="always_allow_bind_appwidgets_text" msgid="2286211654774611037">"Сте одбрале да ѝ дозволите за апликацијата да создава виџети и да пристапува кон нивните податоци."</string>
@@ -1837,8 +1842,8 @@
     <string name="show_running_services" msgid="1895994322704667543">"Прикажи активни услуги"</string>
     <string name="show_background_processes" msgid="88012264528093617">"Прикажи кеширани процеси"</string>
     <string name="default_emergency_app" msgid="286530070173495823">"Апликација за итност"</string>
-    <string name="reset_app_preferences" msgid="1426500030595212077">"Ресет. парам. на аплик."</string>
-    <string name="reset_app_preferences_title" msgid="792909865493673598">"Ресетирај параметри на апликација?"</string>
+    <string name="reset_app_preferences" msgid="1426500030595212077">"Ресетирај ги поставките за апликациите"</string>
+    <string name="reset_app_preferences_title" msgid="792909865493673598">"Да се ресетираат поставките за апликациите?"</string>
     <string name="reset_app_preferences_desc" msgid="7935273005301096031">"Со ова се ресетираат сите параметри за:\n\n"<li>"оневозможени апликации"</li>\n<li>"оневозможени известувања на апликација"</li>\n<li>"стандардни апликации за дејства"</li>\n<li>"ограничувања за податоци во заднина за апликации"</li>\n<li>"сите ограничувања за дозволи"</li>\n\n" Нема да изгубите никакви податоци од апликациите."</string>
     <string name="reset_app_preferences_button" msgid="2041894727477934656">"Ресетирај апликации"</string>
     <string name="manage_space_text" msgid="6166469422303124302">"Управувај со простор"</string>
@@ -2033,7 +2038,7 @@
     <string name="accessibility_settings_title" msgid="1687226556576913576">"Поставки на пристапност"</string>
     <string name="accessibility_settings_summary" msgid="5742379519336396561">"Читачи на екран, екран, контроли за интеракција"</string>
     <string name="vision_settings_title" msgid="7315352351051423944">"Визуелна пристапност"</string>
-    <string name="vision_settings_description" msgid="3476589459009287332">"Уредот може да го приспособите да одговара на вашите потреби. Овие карактеристики за пристапност може да ги смените подоцна во Поставки."</string>
+    <string name="vision_settings_description" msgid="3476589459009287332">"Уредот може да го приспособите да одговара на вашите потреби. Овие функции за пристапност може да ги смените подоцна во Поставки."</string>
     <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"Променете ја големината на фонтот"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"Читачи на екран"</string>
     <string name="audio_and_captions_category_title" msgid="6140472938769619212">"Аудио и текст на екранот"</string>
@@ -2078,8 +2083,8 @@
     <string name="accessibility_timeout_2mins" msgid="4124259290444829477">"2 минути"</string>
     <string name="accessibility_content_timeout_preference_title" msgid="5160746882250939464">"Време за читање"</string>
     <string name="accessibility_control_timeout_preference_title" msgid="2771808346038759474">"Време за преземање дејство"</string>
-    <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"Изберете колку долго да се прикажуваат пораките што треба да ги прочитате, но се видливи само привремено.\n\nНе сите апликации ја поддржуваат оваа поставка."</string>
-    <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"Изберете колку долго да се прикажуваат пораките што бараат да преземете дејство, но се видливи само привремено.\n\nНе сите апликации ја поддржуваат оваа поставка."</string>
+    <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"Изберете колку долго да се прикажуваат пораките што треба да ги прочитате, но се видливи само привремено.\n\nНекои апликации не ја поддржуваат оваа поставка."</string>
+    <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"Изберете колку долго да се прикажуваат пораките што бараат да преземете дејство, но се видливи само привремено.\n\nНекои апликации не ја поддржуваат оваа поставка."</string>
     <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"Должина на допир и задржување"</string>
     <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"Инверзија на бои"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"Може да влијае на изведбата"</string>
@@ -2105,7 +2110,7 @@
       <item quantity="other"><xliff:g id="NUMBER_DEVICE_COUNT_1">%1$d</xliff:g> зачувани слушни помагала</item>
     </plurals>
     <string name="accessibility_summary_state_enabled" msgid="7357731696603247963">"Вклучен"</string>
-    <string name="accessibility_summary_state_disabled" msgid="9197369047683087620">"Исклучен"</string>
+    <string name="accessibility_summary_state_disabled" msgid="9197369047683087620">"Исклучено"</string>
     <string name="accessibility_summary_state_stopped" msgid="3170264683616172746">"Не работи. Допрете за информации."</string>
     <string name="accessibility_description_state_stopped" msgid="7666178628053039493">"Услугава е дефектна."</string>
     <string name="enable_quick_setting" msgid="1580451877998661255">"Прикажи во „Брзи поставки“"</string>
@@ -2235,7 +2240,7 @@
     <string name="background_activity_warning_dialog_title" msgid="2170790412855899678">"Да се ограничи активноста во заднина?"</string>
     <string name="background_activity_warning_dialog_text" msgid="8242749826732375096">"Апликацијата може да се однесува необично ако ја ограничите нејзината активност во заднина"</string>
     <string name="background_activity_disabled_dialog_text" msgid="4234598000779459640">"Апликацијава не е оптимизирана и не може да се ограничи.\n\nЗа да ја ограничите, прво вклучете оптимизација на батеријата."</string>
-    <string name="device_screen_usage" msgid="4470485475363132750">"Искористеност на екранот по целосно полнење"</string>
+    <string name="device_screen_usage" msgid="4470485475363132750">"Користење на екранот по целосно полнење"</string>
     <string name="power_usage_list_summary" msgid="4314438658308211057">"Искористеност на батеријата по целосното полнење"</string>
     <string name="screen_usage_summary" msgid="263396144684078341">"Време на активен екран по целосно полнење"</string>
     <string name="device_usage_list_summary" msgid="8299017481332816368">"Искористеност на уредот по целосно полнење"</string>
@@ -2256,7 +2261,7 @@
     <string name="awake" msgid="8956720170442161285">"Време на активност на уред"</string>
     <string name="wifi_on_time" msgid="2487820618265936068">"Wi-Fi на време"</string>
     <string name="bluetooth_on_time" msgid="6400569492287292639">"Wi-Fi на време"</string>
-    <string name="advanced_battery_title" msgid="5026866913848464170">"Користење на батеријата"</string>
+    <string name="advanced_battery_title" msgid="5026866913848464170">"Искористеност на батеријата"</string>
     <string name="history_details_title" msgid="8608193822257799936">"Детали на историја"</string>
     <string name="battery_details_title" msgid="5358230551490703067">"Искористеност на батеријата"</string>
     <string name="details_subtitle" msgid="7279638828004951382">"Користи детали"</string>
@@ -2331,7 +2336,7 @@
     <string name="battery_auto_restriction_title" msgid="488905332794794076">"Користење управник со батерија"</string>
     <string name="battery_auto_restriction_summary" msgid="1638072655581821837">"Откријте кога апликациите ја трошат батеријата"</string>
     <string name="battery_manager_on" msgid="5626982529932239656">"Вклучено/Се открива кога апликациите ја трошат батеријата"</string>
-    <string name="battery_manager_off" msgid="9114027524232450371">"Исклучен"</string>
+    <string name="battery_manager_off" msgid="9114027524232450371">"Исклучено"</string>
     <plurals name="battery_manager_app_restricted" formatted="false" msgid="6721813588142691216">
       <item quantity="one">%1$d апликација е ограничена</item>
       <item quantity="other">%1$d апликации се ограничени</item>
@@ -2424,7 +2429,7 @@
     <string name="battery_detail_since_full_charge" msgid="3814176986148084378">"Детали по последното целосно полнење"</string>
     <string name="battery_last_full_charge" msgid="5624033030647170717">"Последно целосно полнење"</string>
     <string name="battery_full_charge_last" msgid="4614554109170251301">"Целосното полнење трае околу"</string>
-    <string name="battery_footer_summary" msgid="4828444679643906943">"Податоците за батеријата се приближни и може да се променат според употребата"</string>
+    <string name="battery_footer_summary" msgid="4828444679643906943">"Податоците за батеријата се приближни и може да се менуваат зависно од користењето"</string>
     <string name="battery_detail_foreground" msgid="6616408559186553085">"Во активна употреба"</string>
     <string name="battery_detail_background" msgid="7938146832943604280">"Употреба во заднина"</string>
     <string name="battery_detail_power_usage" msgid="3606930232257489212">"Искористеност на батеријата"</string>
@@ -2450,7 +2455,7 @@
     <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"Ќе се вклучи на <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"Поставете распоред"</string>
     <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"Исклучи кога е целосно полна"</string>
-    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"„Штедачот на батерија“ ќе се исклучи кога нивото на батеријата на телефонот ќе биде на <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
+    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"„Штедачот на батерија“ ќе се исклучи кога нивото на батеријата на телефонот ќе биде <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <string name="battery_saver_sticky_description_new" product="tablet" msgid="3284967694001857194">"„Штедачот на батерија“ ќе се исклучи кога нивото на батеријата на таблетот ќе биде на <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <string name="battery_saver_sticky_description_new" product="device" msgid="5056520668081504111">"„Штедачот на батерија“ ќе се исклучи кога нивото на батеријата на уредот ќе биде на <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <!-- no translation found for battery_saver_seekbar_title (7607123201469333645) -->
@@ -2522,11 +2527,11 @@
     <string name="credentials_install" product="default" msgid="8997183776710118353">"Инсталирај од СД картичка"</string>
     <string name="credentials_install_summary" product="nosdcard" msgid="3426661965567059596">"Инсталирај сертификати од меморија"</string>
     <string name="credentials_install_summary" product="default" msgid="4943897416156671633">"Инсталирај сертификати од СД картичка"</string>
-    <string name="credentials_reset" msgid="355080737664731678">"Исчисти акредитиви"</string>
+    <string name="credentials_reset" msgid="355080737664731678">"Избриши акредитиви"</string>
     <string name="credentials_reset_summary" msgid="7622528359699428555">"Отстрани ги сите акредитиви"</string>
     <string name="trusted_credentials" msgid="6989242522455395200">"Доверливи акредитиви"</string>
     <string name="trusted_credentials_summary" msgid="7411781319056251582">"Прикажи доверливи CA сертификати"</string>
-    <string name="user_credentials" msgid="8365731467650306757">"Акредитиви на корисникот"</string>
+    <string name="user_credentials" msgid="8365731467650306757">"Кориснички акредитиви"</string>
     <string name="user_credentials_summary" msgid="7350223899317423252">"Прегледајте и изменете ги зачуваните акредитиви"</string>
     <string name="advanced_security_title" msgid="286883005673855845">"Напредни"</string>
     <string name="credential_storage_type" msgid="2585337320206095255">"Тип меморија"</string>
@@ -2535,7 +2540,7 @@
     <string name="credentials_settings_not_available" msgid="5490259681690183274">"Акредитивите не се достапни за овој корисник"</string>
     <string name="credential_for_vpn_and_apps" msgid="2462642486949593841">"Инсталиран за VPN и апликации"</string>
     <string name="credential_for_wifi" msgid="2903295786961726388">"Инсталиран за Wi-Fi"</string>
-    <string name="credentials_reset_hint" msgid="3484350477764088169">"Отстрани ги сите содржини?"</string>
+    <string name="credentials_reset_hint" msgid="3484350477764088169">"Да се отстранат сите содржини?"</string>
     <string name="credentials_erased" msgid="7287088033523869085">"Меморијата на акредитиви е избришана."</string>
     <string name="credentials_not_erased" msgid="9137227570738627637">"Мемо за. акредит. не се брише."</string>
     <string name="usage_access_title" msgid="7981321142726540574">"Апликации со пристап до корис."</string>
@@ -2560,8 +2565,8 @@
     <string name="fullbackup_erase_dialog_message" msgid="2588536036471144070">"Дали да се престане со создавање резервна копија на податоците за уредот (како што се лозинки за Wi-Fi и историја на повици) и податоците за апликациите (како што се поставки и датотеки што ги складирале апликациите) и да се избришат сите копии на далечински сервери?"</string>
     <string name="fullbackup_data_summary" msgid="406274198094268556">"Автоматски создајте резервна копија на податоците на уредот (како што се лозинки за Wi-Fi и историја на повици) и податоците за апликациите (како што се поставки и датотеки кои ги складирале апликациите) од далечина.\n\nОткако ќе вклучите автоматско создавање резервна копија, податоците за уредот и апликациите повремено се зачувуваат на далечина. Податоците за апликацијата може да бидат секакви податоци кои ги зачувала апликацијата (според поставките на програмерот), вклучувајќи потенцијално чувствителни податоци како што се контакти, пораки и фотографии."</string>
     <string name="device_admin_settings_title" msgid="2074319456047334589">"Поставки за администраторот на уредот"</string>
-    <string name="active_device_admin_msg" msgid="6929247869516924549">"Апликација на администраторот на уредот"</string>
-    <string name="remove_device_admin" msgid="4413438593788336400">"Деактивирај ја апликацијата на администраторот на уредот"</string>
+    <string name="active_device_admin_msg" msgid="6929247869516924549">"Апликација за администраторот на уредот"</string>
+    <string name="remove_device_admin" msgid="4413438593788336400">"Деактивирај ја апликацијата за администраторот на уредот"</string>
     <string name="uninstall_device_admin" msgid="9017499299961719830">"Деинсталирај ја апликацијата"</string>
     <string name="remove_and_uninstall_device_admin" msgid="5607703579731496253">"Деактивирај и деинсталирај"</string>
     <string name="select_device_admin_msg" msgid="4173769638399075387">"Апликации за администраторот"</string>
@@ -2571,18 +2576,18 @@
     <string name="sms_access_restriction_enabled" msgid="3006320256764718303">"Ограничи пристап до SMS и евиденцијата на повици"</string>
     <string name="sms_access_restriction_enabled_summary" msgid="9011946580977780063">"Само стандардните апликации за телефон и пораки имаат дозволи за SMS и евиденција на повици"</string>
     <string name="no_trust_agents" msgid="5757792915019113084">"Нема достапни агенти од доверба"</string>
-    <string name="add_device_admin_msg" msgid="3573765823476931173">"Да се активира аплик. на администратор?"</string>
-    <string name="add_device_admin" msgid="1621152410207260584">"Активирај ја апликацијата на администраторот на уредот"</string>
+    <string name="add_device_admin_msg" msgid="3573765823476931173">"Да се активира аплик. за администратор?"</string>
+    <string name="add_device_admin" msgid="1621152410207260584">"Активирај ја апликацијата за администраторот на уредот"</string>
     <string name="device_admin_add_title" msgid="6097881332139146897">"Администратор на уредот"</string>
-    <string name="device_admin_warning" msgid="4421817419326480449">"Со активирање на апликацијата на администраторот ќе се дозволи апликацијата „<xliff:g id="APP_NAME">%1$s</xliff:g>“ да ги извршува следните операции:"</string>
-    <string name="device_admin_status" msgid="5424944611789040723">"Апликацијата на администраторот е активна и дозволува апликацијата „<xliff:g id="APP_NAME">%1$s</xliff:g>“ да ги извршува следните операции:"</string>
+    <string name="device_admin_warning" msgid="4421817419326480449">"Со активирање на апликацијата за администраторот ќе се дозволи апликацијата <xliff:g id="APP_NAME">%1$s</xliff:g> да ги извршува следниве операции:"</string>
+    <string name="device_admin_status" msgid="5424944611789040723">"Апликацијата за администраторот е активна и дозволува апликацијата <xliff:g id="APP_NAME">%1$s</xliff:g> да ги извршува следниве операции:"</string>
     <string name="profile_owner_add_title" msgid="735805919754362791">"Да се активира Управникот со профил?"</string>
     <string name="adding_profile_owner_warning" msgid="1284541194547382194">"Ако продолжите, администраторот ќе управува со вашиот корисник, а ќе може и да складира поврзани податоци, заедно со вашите лични податоци.\n\nАдминистраторот може да ги следи поставките, пристапот, апликациите и податоците поврзани со овој корисник и да управува со нив, како и со мрежната активност и информациите за локацијата на уредот."</string>
     <string name="admin_disabled_other_options" msgid="8097063307730025707">"Другите опции се оневозможени од администраторот"</string>
     <string name="admin_more_details" msgid="1719819589822345585">"Повеќе детали"</string>
     <string name="notification_log_title" msgid="4200467765474474753">"Дневник за известувања"</string>
     <string name="sound_category_call_ringtone_vibrate_title" msgid="4678065664534722153">"Мелодија на повик и вибрации"</string>
-    <string name="wifi_setup_detail" msgid="3551227109377008779">"Детали за мрежа"</string>
+    <string name="wifi_setup_detail" msgid="3551227109377008779">"Детали за мрежата"</string>
     <string name="accessibility_sync_enabled" msgid="4620153705473448002">"Синхронизација е овозможена"</string>
     <string name="accessibility_sync_disabled" msgid="3810092470274708197">"Синхронизацијата е оневозможена"</string>
     <string name="accessibility_sync_in_progress" msgid="440606222479878898">"Се синхронизира"</string>
@@ -2591,7 +2596,7 @@
     <string name="sync_active" msgid="1112604707180806364">"Синхронизирањето е активно"</string>
     <string name="account_sync_settings_title" msgid="3344538161552327748">"Синхронизирај"</string>
     <string name="sync_is_failing" msgid="8284618104132302644">"Во моментов има проблеми со синхронизацијата. Ќе се среди наскоро."</string>
-    <string name="add_account_label" msgid="4461298847239641874">"Додај сметка"</string>
+    <string name="add_account_label" msgid="4461298847239641874">"Додајте сметка"</string>
     <string name="managed_profile_not_available_label" msgid="8784246681719821917">"Работниот профил уште не е достапен"</string>
     <string name="work_mode_label" msgid="6845849194740195757">"Работен профил"</string>
     <string name="work_mode_on_summary" msgid="1682781113156323592">"Управувано од вашата организација"</string>
@@ -2622,8 +2627,8 @@
     <string name="preference_change_password_title" msgid="7243527448378789274">"Смени лозинка"</string>
     <string name="header_account_settings" msgid="8586173964125512219">"Поставки на сметка"</string>
     <string name="remove_account_label" msgid="5885425720323823387">"Отстрани сметка"</string>
-    <string name="header_add_an_account" msgid="8482614556580804956">"Додај сметка"</string>
-    <string name="really_remove_account_title" msgid="4166512362915154319">"Отстрани сметка?"</string>
+    <string name="header_add_an_account" msgid="8482614556580804956">"Додајте сметка"</string>
+    <string name="really_remove_account_title" msgid="4166512362915154319">"Да се отстрани сметката?"</string>
     <string name="really_remove_account_message" product="tablet" msgid="7403843371045856719">"Со отстранување на оваа сметка ќе се избришат сите нејзини пораки, контакти и другите податоци од таблетот!"</string>
     <string name="really_remove_account_message" product="default" msgid="8951224626153163914">"Со отстранување на оваа сметка ќе се избришат сите нејзини пораки, контакти и другите податоци од телефонот!"</string>
     <string name="really_remove_account_message" product="device" msgid="3751798556257519916">"Со отстранување на оваа сметка ќе се избришат сите нејзини пораки, контакти и другите податоци од уредот!"</string>
@@ -2700,7 +2705,7 @@
     <string name="data_usage_restrict_denied_dialog" msgid="18928292832775805">"Ограничување на интернет во заднина е можно само откога ќе поставите ограничување за мобилен интернет."</string>
     <string name="data_usage_auto_sync_on_dialog_title" msgid="2342323408229702005">"Вклучи авто синхрон. на подат.?"</string>
     <string name="data_usage_auto_sync_on_dialog" product="tablet" msgid="4935430284683238901">"Сите промени што ги правите на вашите сметки на интернет автоматски ќе се копираат на вашиот таблет.\n\nНекои сметки може и автоматски да ги копираат сите промени направени на телефонот на интернет. Сметката на Google го прави тоа."</string>
-    <string name="data_usage_auto_sync_on_dialog" product="default" msgid="5004823486046340090">"Сите промени што ќе ги направите на вашите сметки на интернет автоматски ќе се ископираат на телефонот.\n\nНекои сметки можеби автоматски ќе ги ископираат и промените што ги правите од телефонот на интернет. Сметката на Google го прави тоа."</string>
+    <string name="data_usage_auto_sync_on_dialog" product="default" msgid="5004823486046340090">"Сите промени што ќе ги направите на вашите сметки на интернет автоматски ќе се ископираат на телефонот.\n\nНекои сметки можеби автоматски ќе ги ископираат и промените што ги вршите од телефонот на интернет. Сметката на Google го прави тоа."</string>
     <string name="data_usage_auto_sync_off_dialog_title" msgid="7105334544291643305">"Исклучи авто синхрон. на подат.?"</string>
     <string name="data_usage_auto_sync_off_dialog" msgid="4057984234450947964">"Ова ќе ви заштеди интернет и батерија, но секоја сметка ќе треба да ја синхронизирате рачно за да се соберат најновите информации. Освен тоа, нема да добивате известувања за ажурирања."</string>
     <string name="data_usage_cycle_editor_title" msgid="4967309390043599889">"Датум на ресетирање циклус на употреба"</string>
@@ -2865,7 +2870,7 @@
     <string name="user_add_user_item_title" msgid="6835385073795492410">"Корисник"</string>
     <string name="user_add_profile_item_title" msgid="4932743891449790664">"Ограничен профил"</string>
     <string name="user_add_user_title" msgid="2320897397066676472">"Да се додаде нов корисник?"</string>
-    <string name="user_add_user_message_long" msgid="686637203224195465">"Уредов може да го споделувате со други лица преку создавање дополнителни корисници. Секој корисник има сопствен простор што може да го приспособува со апликации, тапети и слично. Корисниците може да приспособуваат и поставки на уредот, како на пр., Wi‑Fi, што се однесуваат на сите.\n\nКога додавате нов корисник, тоа лице треба да го постави својот простор.\n\nСекој корисник може да ажурира апликации за сите други корисници. Поставките и услугите за пристапност не може да се префрлат на новиот корисник."</string>
+    <string name="user_add_user_message_long" msgid="686637203224195465">"Уредов може да го споделувате со други лица ако додадете дополнителни корисници. Секој корисник има сопствен простор што може да го приспособува со апликации, тапети и слично. Корисниците може да приспособуваат и поставки за уредот, како на пр., Wi‑Fi, што важат за сите.\n\nКога додавате нов корисник, тоа лице треба да го постави својот простор.\n\nСекој корисник може да ажурира апликации за сите други корисници. Поставките и услугите за пристапност не може да се префрлат на новиот корисник."</string>
     <string name="user_add_user_message_short" msgid="1802594476285458254">"Кога додавате нов корисник, тоа лице треба да го постави својот простор.\n\nСекој корисник може да ажурира апликации за сите други корисници."</string>
     <string name="user_setup_dialog_title" msgid="6748950002206392396">"Ќе поставите корисник сега?"</string>
     <string name="user_setup_dialog_message" msgid="2988559933258353919">"Проверете дали лицето е достапно да го земе уредот и да го постави својот простор"</string>
@@ -2877,7 +2882,7 @@
     <string name="user_cannot_add_accounts_message" msgid="5993561303748749097">"Ограничените профили не можат да додаваат сметки"</string>
     <string name="user_remove_user_menu" msgid="3505139157217459864">"Избриши го <xliff:g id="USER_NAME">%1$s</xliff:g> од тука"</string>
     <string name="user_lockscreen_settings" msgid="3820813814848394568">"Поставки на екранот за заклучување"</string>
-    <string name="user_add_on_lockscreen_menu" msgid="5211604808199585774">"Додајте корисници од заклучен екран"</string>
+    <string name="user_add_on_lockscreen_menu" msgid="5211604808199585774">"Додавање корисници од заклучен екран"</string>
     <string name="user_new_user_name" msgid="3880395219777884838">"Нов корисник"</string>
     <string name="user_new_profile_name" msgid="3074939718101489937">"Нов профил"</string>
     <string name="user_confirm_remove_self_title" msgid="6739480453680217543">"Избриши се себеси?"</string>
@@ -2904,15 +2909,15 @@
     <string name="user_enable_calling_confirm_message" msgid="2490126715153125970">"Историјата на повици ќе се сподели со овој корисник."</string>
     <string name="user_enable_calling_and_sms_confirm_title" msgid="4153856398523366976">"Вклучи телефонски повици и SMS?"</string>
     <string name="user_enable_calling_and_sms_confirm_message" msgid="3278802798876095734">"Историјата на повици и пораки ќе се сподели со овој корисник."</string>
-    <string name="emergency_info_title" msgid="1522609271881425375">"Информации за итни случаи"</string>
-    <string name="emergency_info_summary" msgid="7280464759837387342">"Информации и контакти за <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="emergency_info_title" msgid="1522609271881425375">"Податоци за итни случаи"</string>
+    <string name="emergency_info_summary" msgid="7280464759837387342">"Податоци и контакти за <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="application_restrictions" msgid="6871981013736536763">"Дозволи апликации и содржина"</string>
     <string name="apps_with_restrictions_header" msgid="8656739605673756176">"Апликации со ограничувања"</string>
     <string name="apps_with_restrictions_settings_button" msgid="5065896213467171744">"Прошири поставки за апликација"</string>
     <string name="nfc_payment_settings_title" msgid="5070077706735415291">"Допри и плати"</string>
     <string name="nfc_payment_how_it_works" msgid="7607901964687787177">"Како функционира"</string>
     <string name="nfc_payment_no_apps" msgid="8844440783395420860">"Плаќајте со телефонот во продавници"</string>
-    <string name="nfc_payment_default" msgid="7869273092463612271">"Стандард за плаќање"</string>
+    <string name="nfc_payment_default" msgid="7869273092463612271">"Стандардна апликација за плаќање"</string>
     <string name="nfc_payment_default_not_set" msgid="955804193510335338">"Не е поставено"</string>
     <string name="nfc_payment_app_and_desc" msgid="102312684211458190">"<xliff:g id="APP">%1$s</xliff:g> - <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="nfc_payment_use_default" msgid="3098724195746409476">"Користи ја стандардната"</string>
@@ -2920,7 +2925,7 @@
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Освен кога е отворена друга апликација за плаќање"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"На терминалот Допри и плати плаќајте со:"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Плаќање на терминалот"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Поставете апликација за плаќање. Потоа само држете ја задната страна на телефонот до кој било терминал со симболот без допир."</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Поставете апликација за плаќање. Потоа само задржете ја задната страна на телефонот до кој било терминал означен со симболот за плаќање без контакт."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"Разбрав"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"Повеќе..."</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"Постави како свој параметар?"</string>
@@ -2976,8 +2981,8 @@
     <string name="wizard_back" msgid="223654213898117594">"Назад"</string>
     <string name="wizard_next" msgid="5239664512608113542">"Следно"</string>
     <string name="wizard_finish" msgid="3742102879981212094">"Заврши"</string>
-    <string name="user_image_take_photo" msgid="2000247510236178111">"Фотографирај"</string>
-    <string name="user_image_choose_photo" msgid="4920315415203051898">"Избери слика"</string>
+    <string name="user_image_take_photo" msgid="2000247510236178111">"Фотографирајте"</string>
+    <string name="user_image_choose_photo" msgid="4920315415203051898">"Изберете слика"</string>
     <string name="user_image_photo_selector" msgid="8429694590849882411">"Избери фотографија"</string>
     <string name="regulatory_info_text" msgid="9112993912873512834"></string>
     <string name="sim_setup_wizard_title" msgid="77627575294867180">"SIM-картички"</string>
@@ -3118,7 +3123,7 @@
     <string name="keywords_assist_input" msgid="8392362788794886564">"стандарден, помошник"</string>
     <string name="keywords_default_payment_app" msgid="845369409578423996">"плаќање, стандарден"</string>
     <string name="keywords_ambient_display" msgid="8835182491798487184">"дојдовно известување"</string>
-    <string name="keywords_hotspot_tethering" msgid="1723591462602613867">"врзување преку USB, врзување преку Bluetooth, Wi-Fi точка на пристап"</string>
+    <string name="keywords_hotspot_tethering" msgid="1723591462602613867">"интернет преку USB, интернет преку Bluetooth, Wi-Fi точка на пристап"</string>
     <string name="keywords_touch_vibration" msgid="2081175517528255224">"повратни информации со допир, вибрации, чувствителност"</string>
     <string name="keywords_ring_vibration" msgid="4210509151866460210">"повратни информации со допир, вибрации, телефон, повик, чувствителност, ѕвонење"</string>
     <string name="keywords_notification_vibration" msgid="1077515502086745166">"повратни информации со допир, вибрации, чувствителност"</string>
@@ -3156,7 +3161,7 @@
     <string name="emergency_tone_alert" msgid="907868135091891015">"Тонови"</string>
     <string name="emergency_tone_vibrate" msgid="5020068066905681181">"Вибрации"</string>
     <string name="boot_sounds_title" msgid="7583926202411353620">"Вклучете ги звуците"</string>
-    <string name="live_caption_title" msgid="7926591158657997051">"Титли во живо"</string>
+    <string name="live_caption_title" msgid="7926591158657997051">"Автоматски титлови"</string>
     <string name="live_caption_summary" msgid="9064771862352393125">"Автоматски титлови за аудиовизуелни содржини"</string>
     <string name="zen_mode_settings_summary_off" msgid="6929319200478424962">"Никогаш"</string>
     <plurals name="zen_mode_settings_summary_on" formatted="false" msgid="6061723291126091396">
@@ -3211,7 +3216,7 @@
     <string name="zen_mode_block_effect_light" msgid="8679333758037487644">"Не трепкај со светлото"</string>
     <string name="zen_mode_block_effect_peek" msgid="6075662813575910221">"Без скокачки известувања на екранот"</string>
     <string name="zen_mode_block_effect_status" msgid="6516614225115681068">"Сокриј ги иконите на статусната лента на врвот од екранот"</string>
-    <string name="zen_mode_block_effect_badge" msgid="3891743027347075136">"Сокриј точки за известување на иконите на апликацијата"</string>
+    <string name="zen_mode_block_effect_badge" msgid="3891743027347075136">"Сокриј точки за известување во иконите за апликациите"</string>
     <string name="zen_mode_block_effect_ambient" msgid="6382013125863616197">"Не прикажувај известувања"</string>
     <string name="zen_mode_block_effect_list" msgid="6081548478844912181">"Сокриј од списокот со известувања"</string>
     <string name="zen_mode_block_effect_summary_none" msgid="7166175186759564510">"Никогаш"</string>
@@ -3355,7 +3360,7 @@
     <string name="notifications_sent_daily" msgid="6874886521964822824">"околу <xliff:g id="NUMBER">%1$s</xliff:g> дневно"</string>
     <string name="notifications_sent_weekly" msgid="5859675428990259432">"околу <xliff:g id="NUMBER">%1$s</xliff:g> неделно"</string>
     <string name="notifications_sent_never" msgid="237997329598144638">"Никогаш"</string>
-    <string name="manage_notification_access_title" msgid="5348743662189787547">"Пристап до известување"</string>
+    <string name="manage_notification_access_title" msgid="5348743662189787547">"Пристап до известувања"</string>
     <string name="work_profile_notification_access_blocked_summary" msgid="8148871282484870576">"Пристапот до известувањата на работниот профил е блокиран"</string>
     <string name="manage_notification_access_summary_zero" msgid="236809421271593016">"Апликациите не можат да читаат известувања"</string>
     <plurals name="manage_notification_access_summary_nonzero" formatted="false" msgid="8496218948429646792">
@@ -3438,7 +3443,7 @@
     <string name="zen_mode_add_time_rule" msgid="5999467757140524729">"Додај распоред за време"</string>
     <string name="zen_mode_delete_rule" msgid="2292933835997203801">"Избришете го распоредот"</string>
     <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"Изберете тип распоред"</string>
-    <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"Избриши правило за „<xliff:g id="RULE">%1$s</xliff:g>“?"</string>
+    <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"Да се избрише правилото „<xliff:g id="RULE">%1$s</xliff:g>“?"</string>
     <string name="zen_mode_delete_rule_button" msgid="611058106279881991">"Избриши"</string>
     <string name="zen_mode_rule_type_unknown" msgid="2819480113355191421">"Непознато"</string>
     <string name="zen_mode_app_set_behavior" msgid="8597398780262575571">"Поставкиве не може да се променат во моментов. Дадена апликација (<xliff:g id="APP_NAME">%1$s</xliff:g>) го вклучи режимот „Не вознемирувај“ автоматски со приспособено однесување."</string>
@@ -3504,7 +3509,7 @@
     <string name="zen_mode_reminders_list" msgid="7347061314032326677">"потсетници"</string>
     <string name="zen_mode_events" msgid="5784076928339534984">"Дозволи настани"</string>
     <string name="zen_mode_bypassing_apps" msgid="3080739479028713449">"Дозволете апликациите да занемаруваат"</string>
-    <string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"Исклучоци на апликацијата"</string>
+    <string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"Исклучоци за апликации"</string>
     <plurals name="zen_mode_bypassing_apps_subtext" formatted="false" msgid="8723144434730871572">
       <item quantity="one">Известувања од <xliff:g id="NUMBER">%1$d</xliff:g> апликација може да ја занемарат „Не вознемирувај“</item>
       <item quantity="other">Известувања од <xliff:g id="NUMBER">%1$d</xliff:g> апликации може да ја занемарат „Не вознемирувај“</item>
@@ -3599,7 +3604,7 @@
     <string name="notifications_label" msgid="2792398288062643318">"Известувања"</string>
     <string name="notifications_enabled" msgid="439339392141736137">"Вклучено"</string>
     <string name="notifications_enabled_with_info" msgid="7706460489443809452">"<xliff:g id="NOTIFICATIONS_SENT">%1$s</xliff:g>/<xliff:g id="NOTIFICATIONS_CATEGORIES_OFF">%2$s</xliff:g>"</string>
-    <string name="notifications_disabled" msgid="316658185757688983">"Исклучи"</string>
+    <string name="notifications_disabled" msgid="316658185757688983">"Исклучено"</string>
     <string name="notifications_partly_blocked" msgid="6330451240669068819">"<xliff:g id="COUNT_0">%1$d</xliff:g> од <xliff:g id="COUNT_1">%2$d</xliff:g> категории се исклучени"</string>
     <string name="notifications_silenced" msgid="538923056987616372">"Стишено"</string>
     <string name="notifications_redacted" msgid="308836040236690014">"Без чувствителни содржини на заклучен екран"</string>
@@ -3640,14 +3645,14 @@
     <string name="advanced_apps" msgid="6643869089344883537">"Напредни"</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" msgid="3215958256821756086">"Управувач со дозволи"</string>
     <string name="app_permissions_summary" msgid="8785798165776061594">"Апликации што користат <xliff:g id="APPS">%1$s</xliff:g>"</string>
     <string name="tap_to_wake" msgid="1902991239401652323">"Допрете за будење"</string>
     <string name="tap_to_wake_summary" msgid="8485222120721006793">"Допрете двапати каде било на екранот за да го разбудите уредот"</string>
     <string name="domain_urls_title" msgid="7939209950373945367">"За отворање линкови"</string>
     <string name="domain_urls_summary_none" msgid="5401203416941265109">"Не отворај поддржани линкови"</string>
     <string name="domain_urls_summary_one" msgid="3893975485064803435">"Отвори <xliff:g id="DOMAIN">%s</xliff:g>"</string>
-    <string name="domain_urls_summary_some" msgid="2130534984153210797">"Отворете <xliff:g id="DOMAIN">%s</xliff:g> и други URL-адреси"</string>
+    <string name="domain_urls_summary_some" msgid="2130534984153210797">"Отворај <xliff:g id="DOMAIN">%s</xliff:g> и други URL-адреси"</string>
     <string name="domain_urls_apps_summary_off" msgid="1110203970617922543">"Ниедна апликација не отвора поддржани линкови"</string>
     <plurals name="domain_urls_apps_summary_on" formatted="false" msgid="3571309605151815405">
       <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> апликација отвора поддржани линкови</item>
@@ -3707,7 +3712,7 @@
     <string name="high_power_system" msgid="739584574711292753">"Оптимизација на батеријата не е достапна"</string>
     <string name="high_power_desc" msgid="333756885680362741">"Не применувајте оптимизација на батеријата. Може побрзо да ја истроши вашата батерија."</string>
     <string name="high_power_prompt_title" msgid="2805745781720454052">"Да се извршува во заднина?"</string>
-    <string name="high_power_prompt_body" msgid="8067395096053552289">"Ако дозволите <xliff:g id="APP_NAME">%1$s</xliff:g> секогаш да се извршува во заднина, тоа може да ја намали трајноста на батеријата. \n\nТоа може да го промените подоцна во Поставки &gt; Апликации и известувања."</string>
+    <string name="high_power_prompt_body" msgid="8067395096053552289">"Ако дозволите <xliff:g id="APP_NAME">%1$s</xliff:g> секогаш да се извршува во заднина, тоа може да го намали траењето на батеријата. \n\nОва може да го промените подоцна во „Поставки &gt; Апликации и известувања“."</string>
     <string name="battery_summary" msgid="4345690800899981339">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> употреба од последното целосно полнење"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"Управување со напојувањето"</string>
     <string name="no_battery_summary" msgid="4105932628367471314">"Нема употреба на батерија од последното целосно полнење"</string>
@@ -3728,7 +3733,7 @@
     <string name="usb_use_file_transfers_desc" msgid="6953866660041189580">"Пренесете ги датотеките на друг уред"</string>
     <string name="usb_use_photo_transfers" msgid="5974236250197451257">"PTP"</string>
     <string name="usb_use_photo_transfers_desc" msgid="2325112887316125320">"Пренесувај фотографии или датотеки ако не е подржан MTP (PTP)"</string>
-    <string name="usb_use_tethering" msgid="4250626730173163846">"Врзување преку USB"</string>
+    <string name="usb_use_tethering" msgid="4250626730173163846">"Интернет преку USB"</string>
     <string name="usb_use_MIDI" msgid="4710632870781041401">"MIDI"</string>
     <string name="usb_use_MIDI_desc" msgid="1770966187150010947">"Користете го уредов како MIDI"</string>
     <string name="usb_use" msgid="8940500223316278632">"Користи USB за"</string>
@@ -3744,11 +3749,11 @@
     <string name="usb_summary_charging_only" msgid="4118449308708872339">"Полнење на уредот"</string>
     <string name="usb_summary_power_only" msgid="3552240122641051107">"Се полни поврзаниот уред"</string>
     <string name="usb_summary_file_transfers" msgid="7805342797099821502">"Пренос на датотеки"</string>
-    <string name="usb_summary_tether" msgid="778845069037366883">"Врзување преку USB"</string>
+    <string name="usb_summary_tether" msgid="778845069037366883">"Интернет преку USB"</string>
     <string name="usb_summary_photo_transfers" msgid="4743028167400644354">"PTP"</string>
     <string name="usb_summary_MIDI" msgid="5540604166270861247">"MIDI"</string>
     <string name="usb_summary_file_transfers_power" msgid="1684501026426766867">"Пренос на датотеки и полнење уред"</string>
-    <string name="usb_summary_tether_power" msgid="5684170912136320002">"Врзување преку USB и полнење уред"</string>
+    <string name="usb_summary_tether_power" msgid="5684170912136320002">"Интернет преку USB и полнење уред"</string>
     <string name="usb_summary_photo_transfers_power" msgid="4424106272137720464">"PTP и полнење уред"</string>
     <string name="usb_summary_MIDI_power" msgid="7685597621357005180">"MIDI и полнење уред"</string>
     <string name="background_check_pref" msgid="664081406854758392">"Проверка на заднината"</string>
@@ -3798,7 +3803,7 @@
     <string name="system_alert_window_settings" msgid="3024330223417646567">"Приказ врз други апликации"</string>
     <string name="system_alert_window_apps_title" msgid="9188448296493699566">"Апликации"</string>
     <string name="system_alert_window_access_title" msgid="5187343732185369675">"Приказ врз други апликации"</string>
-    <string name="permit_draw_overlay" msgid="9039092257052422344">"Дозволи прикажување врз други апликации"</string>
+    <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>
@@ -3808,14 +3813,14 @@
     <string name="app_permission_summary_allowed" msgid="6458476982015518778">"Дозволено"</string>
     <string name="app_permission_summary_not_allowed" msgid="1171642541675462584">"Не е дозволено"</string>
     <string name="keywords_install_other_apps" msgid="5383559540695847668">"инсталирање апликации непознати извори"</string>
-    <string name="write_settings" msgid="9009040811145552108">"Менување поставки на системот"</string>
+    <string name="write_settings" msgid="9009040811145552108">"Менување системски поставки"</string>
     <string name="keywords_write_settings" msgid="3450405263390246293">"пишувај менувај поставки на системот"</string>
     <string name="write_settings_summary" msgid="4650251358459404247">"<xliff:g id="COUNT_0">%1$d</xliff:g> од <xliff:g id="COUNT_1">%2$d</xliff:g> апликации имаат дозвола да менуваат поставки на систем"</string>
     <string name="financial_apps_sms_access_title" msgid="3422655018008259655">"Пристап до SMS за финансиски апликации"</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>
+    <string name="write_system_settings" msgid="20450765210832463">"Менување системски поставки"</string>
     <string name="permit_write_settings" msgid="4198491281216818756">"Дозволи менување на поставките на системот"</string>
     <string name="write_settings_description" msgid="2536706293042882500">"Оваа дозвола овозможува апликацијата да менува поставки на системот."</string>
     <string name="write_settings_on" msgid="7328986337962635118">"Да"</string>
@@ -3873,7 +3878,7 @@
     <string name="disabled_by_policy_title_camera" msgid="3741138901926111197">"Камерата не е дозволена"</string>
     <string name="disabled_by_policy_title_screen_capture" msgid="1856835333536274665">"Слика од екранот не е дозволена"</string>
     <string name="disabled_by_policy_title_suspend_packages" msgid="4254714213391802322">"Апликацијава не може да се отвори"</string>
-    <string name="default_admin_support_msg" msgid="5789424433689798637">"Ако имате прашања, контактирајте со администраторот за информатичка технологија"</string>
+    <string name="default_admin_support_msg" msgid="5789424433689798637">"Ако имате прашања, контактирајте со IT-администраторот"</string>
     <string name="admin_support_more_info" msgid="8737842638087863477">"Повеќе детали"</string>
     <string name="admin_profile_owner_message" msgid="3199544166281052845">"Администраторот може да ги следи и да управува со апликациите и податоците поврзани со вашиот работен профил, заедно со поставките, дозволите, корпоративниот пристап, мрежната активност и информациите за локацијата на уредот."</string>
     <string name="admin_profile_owner_user_message" msgid="2991249382056855531">"Администраторот може да ги следи и да управува со апликациите и податоците поврзани со корисников, заедно со поставките, дозволите, корпоративниот пристап, мрежната активност и информациите за локацијата на уредот."</string>
@@ -3930,7 +3935,7 @@
     <string name="usage" msgid="9172908720164431622">"Користење"</string>
     <string name="cellular_data_usage" msgid="1236562234207782386">"Потрошен мобилен интернет"</string>
     <string name="app_cellular_data_usage" msgid="8499761516172121957">"Потрошен сообраќај на апликациите"</string>
-    <string name="wifi_data_usage" msgid="275569900562265895">"Потрошен Wi-Fi сообраќај"</string>
+    <string name="wifi_data_usage" msgid="275569900562265895">"Сообраќај преку Wi-Fi"</string>
     <string name="ethernet_data_usage" msgid="747614925362556718">"Потрошен етернет сообраќај"</string>
     <string name="wifi" msgid="1586738489862966138">"Wi-Fi"</string>
     <string name="ethernet" msgid="2365753635113154667">"Етернет"</string>
@@ -3941,7 +3946,7 @@
     <string name="app_usage_cycle" msgid="213483325132959663">"Циклус потрошен сообраќај од апликации"</string>
     <string name="cell_data_warning" msgid="8902740337286652689">"Предупредување за потрошен сообраќај: <xliff:g id="ID_1">^1</xliff:g>"</string>
     <string name="cell_data_limit" msgid="3175933829235314233">"Ограничување на сообраќајот: <xliff:g id="ID_1">^1</xliff:g>"</string>
-    <string name="cell_data_warning_and_limit" msgid="3846150001253927594">"Предупредување за потрошен сообраќај: <xliff:g id="ID_1">^1</xliff:g>/Ограничување на сообраќајот:<xliff:g id="ID_2">^2</xliff:g>"</string>
+    <string name="cell_data_warning_and_limit" msgid="3846150001253927594">"Предупредување за потрошен сообраќај: <xliff:g id="ID_1">^1</xliff:g>/Ограничување на сообраќајот: <xliff:g id="ID_2">^2</xliff:g>"</string>
     <string name="billing_cycle_fragment_summary" msgid="4926047002107855543">"На <xliff:g id="ID_1">%1$s</xliff:g> секој месец"</string>
     <string name="network_restrictions" msgid="196294262243618198">"Ограничувања на мрежата"</string>
     <plurals name="network_restrictions_summary" formatted="false" msgid="1664494781594839837">
@@ -3959,8 +3964,8 @@
     <string name="configure" msgid="8232696842838580549">"Конфигурирај"</string>
     <string name="data_usage_other_apps" msgid="7002491980141402084">"Други апликации вклучени во употребата"</string>
     <plurals name="data_saver_unrestricted_summary" formatted="false" msgid="6046013861315713697">
-      <item quantity="one"><xliff:g id="COUNT">%1$d</xliff:g> апликација има дозвола да користи неограничен интернет кога е вклучен „Штедачот на интернет“</item>
-      <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> апликации имаат дозвола да користат неограничен интернет кога е вклучен „Штедачот на интернет“</item>
+      <item quantity="one"><xliff:g id="COUNT">%1$d</xliff:g> апликација има дозвола да користи неограничен мобилен интернет кога е вклучен „Штедачот на интернет“</item>
+      <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> апликации имаат дозвола да користат неограничен мобилен интернет кога е вклучен „Штедачот на интернет“</item>
     </plurals>
     <string name="data_usage_title" msgid="7874606430902201083">"Примарни податоци"</string>
     <string name="data_usage_wifi_title" msgid="7161828479387766556">"Wi‑Fi-сообраќај"</string>
@@ -3981,7 +3986,7 @@
     <string name="launch_mdp_app_text" msgid="9186559496664208252">"Прикажи план"</string>
     <string name="launch_wifi_text" msgid="317820210431682605">"Прикажи ги деталите"</string>
     <string name="data_saver_title" msgid="7903308134514179256">"Штедач на интернет"</string>
-    <string name="unrestricted_data_saver" msgid="9139401849550738720">"Неограничен интернет"</string>
+    <string name="unrestricted_data_saver" msgid="9139401849550738720">"Неограничен мобилен интернет"</string>
     <string name="restrict_background_blacklisted" msgid="7158991683849067124">"Исклучен сообраќај во заднина"</string>
     <string name="data_saver_on" msgid="7281809065420480881">"Вклучено"</string>
     <string name="data_saver_off" msgid="7439439787358504018">"Исклучено"</string>
@@ -3999,7 +4004,7 @@
     <string name="battery_saver_on_summary" msgid="6841062406467435672">"Вклучено"</string>
     <string name="battery_saver_off_scheduled_summary" msgid="3740414764069188669">"Ќе се вклучи на <xliff:g id="BATTERY_PERCENTAGE">%1$s</xliff:g>"</string>
     <string name="battery_saver_off_summary" msgid="8736555723004299721">"Исклучено"</string>
-    <string name="battery_saver_button_turn_on" msgid="3748696527267573793">"Вклучи го сега"</string>
+    <string name="battery_saver_button_turn_on" msgid="3748696527267573793">"Вклучи сега"</string>
     <string name="battery_saver_button_turn_off" msgid="2912950982503267828">"Исклучи сега"</string>
     <string name="not_battery_optimizing" msgid="2616044774307734160">"Не се користи оптимизација на батеријата"</string>
     <string name="lockscreen_remote_input" msgid="3363310613165354434">"Ако уредот е заклучен, спречете внесување одговори или друг текст во известувања"</string>
@@ -4049,8 +4054,8 @@
     <string name="overlay_toast_failed_to_apply" msgid="5692251825129250040">"Не успеа да се примени прекривка"</string>
     <string name="special_access" msgid="1453926335914696206">"Посебни пристапи"</string>
     <plurals name="special_access_summary" formatted="false" msgid="5182092345063909346">
-      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> апликација може да користи неограничен интернет</item>
-      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> апликации може да користат неограничен интернет</item>
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> апликација може да користи неограничен мобилен интернет</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> апликации може да користат неограничен мобилен интернет</item>
     </plurals>
     <string name="special_access_more" msgid="7086690625048471400">"Видете повеќе"</string>
     <string name="confirm_convert_to_fbe_warning" msgid="4972595831034280189">"Навистина ли да се избришат податоците за корисникот и да се конвертираат во шифрирана датотека?"</string>
@@ -4065,7 +4070,7 @@
     <string name="premium_sms_none" msgid="940723020871007898">"Ниедна од инсталираните апликации не побара пристап до премиум SMS"</string>
     <string name="premium_sms_warning" msgid="7604011651486294515">"Премиум SMS може да ве чини пари, а сумата ќе се додаде на сметките од операторот. Ако овозможите дозвола за апликацијата, ќе може да испраќате премиум SMS со неа."</string>
     <string name="premium_sms_access" msgid="4550027460595822851">"Пристап до премиум SMS"</string>
-    <string name="bluetooth_disabled" msgid="6588102116819268238">"Исклучен"</string>
+    <string name="bluetooth_disabled" msgid="6588102116819268238">"Исклучено"</string>
     <string name="bluetooth_connected_summary" msgid="439920840053965217">"Поврзан со <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="bluetooth_connected_multiple_devices_summary" msgid="596205630653123250">"Поврзан со повеќе уреди"</string>
     <string name="demo_mode" msgid="3831081808592541104">"Демо-режим на кориснички интерфејс на систем"</string>
@@ -4108,29 +4113,29 @@
     <string name="gesture_preference_summary" product="device" msgid="7792199669106960922">"Брзи движења за контролирање на уредот"</string>
     <string name="double_tap_power_for_camera_title" msgid="5480829329052517484">"Префрли на камера"</string>
     <string name="double_tap_power_for_camera_summary" msgid="6591026425496323965">"За брзо отворање на камерата, притиснете го копчето за вклучување двапати. Работи од секој екран."</string>
-    <string name="double_tap_power_for_camera_suggestion_title" msgid="509078029429865036">"Отворајте ја камерата набрзина"</string>
+    <string name="double_tap_power_for_camera_suggestion_title" msgid="509078029429865036">"Брзо отворање на камерата"</string>
     <string name="double_twist_for_camera_mode_title" msgid="2606032140297556018">"Смени ја камерата"</string>
     <string name="double_twist_for_camera_mode_summary" msgid="8979914206876018137"></string>
     <string name="double_twist_for_camera_suggestion_title" msgid="5932411386316771246">"Направете селфи-фотографии побрзо"</string>
     <string name="swipe_up_to_switch_apps_summary" msgid="4644068184114154787">"За да префрлате апликации, повлечете нагоре на копчето „Почеток“. Повлечете нагоре уште еднаш за да ги видите сите апликации. Ова функционира од секој екран. Повеќе нема да имате копче „Преглед“ во долниот десен дел од екранот."</string>
     <string name="swipe_up_to_switch_apps_suggestion_title" msgid="7641846365137536128">"Пробајте го новото копче за Почеток"</string>
     <string name="swipe_up_to_switch_apps_suggestion_summary" msgid="7338653224520387852">"Вклучете го новото движење за да префрлате апликации"</string>
-    <string name="ambient_display_title" product="default" msgid="6785677099744344088">"Допрете двапати за да го проверите телефонот"</string>
-    <string name="ambient_display_title" product="tablet" msgid="1106285490888683613">"Допрете двапати за да го проверите таблетот"</string>
-    <string name="ambient_display_title" product="device" msgid="5064644474876041478">"Допрете двапати за да го проверите уредот"</string>
+    <string name="ambient_display_title" product="default" msgid="6785677099744344088">"Допрете двапати за проверка на телефонот"</string>
+    <string name="ambient_display_title" product="tablet" msgid="1106285490888683613">"Допрете двапати за проверка на таблетот"</string>
+    <string name="ambient_display_title" product="device" msgid="5064644474876041478">"Допрете двапати за проверка на уредот"</string>
     <string name="ambient_display_summary" msgid="4882910328216411109">"За да ги проверите времето, известувањата и другите информации, допрете двапати на екранот."</string>
-    <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"Подигни за проверка"</string>
+    <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"Подигни за проверка на телефонот"</string>
     <string name="ambient_display_pickup_title" product="tablet" msgid="1555456400210301959">"Подигнете за да го проверите таблетот"</string>
     <string name="ambient_display_pickup_title" product="device" msgid="2480126522988135037">"Подигнете за да го проверите уредот"</string>
     <string name="ambient_display_wake_screen_title" msgid="3376988352851077102">"Екран за будење"</string>
     <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"За да ги проверите времето, известувањата и другите информации, земете го телефонот."</string>
     <string name="ambient_display_pickup_summary" product="tablet" msgid="1077745287100012928">"За да ги проверите времето, известувањата и другите информации, земете го таблетот."</string>
     <string name="ambient_display_pickup_summary" product="device" msgid="404199660076598026">"За да ги проверите времето, известувањата и другите информации, земете го уредот."</string>
-    <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"Допрете за да го проверите телефонот"</string>
+    <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"Допри за проверка на телефонот"</string>
     <string name="ambient_display_tap_screen_title" product="tablet" msgid="6434521782016864148">"Допрете за да го проверите таблетот"</string>
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"Допрете за да го проверите уредот"</string>
     <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"За да ги проверите времето, известувањата и другите информации, допрете го екранот."</string>
-    <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"Повлечи отпечаток за известувања"</string>
+    <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"Повлечете отпечаток за известувања"</string>
     <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"Повлечете отпечаток"</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"За да ги проверите известувањата, повлечете надолу на сензорот за отпечатоци на задната страна на телефонот."</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="tablet" msgid="3480057984564476283">"За да ги проверите известувањата, повлечете надолу на сензорот за отпечатоци на задната страна на таблетот."</string>
@@ -4242,7 +4247,7 @@
     <string name="clear_instant_app_confirmation" msgid="1778553115373698061">"Дали сакате да ја отстраните оваа инстант апликација?"</string>
     <string name="launch_instant_app" msgid="5251693061228352333">"Отвори"</string>
     <string name="game_storage_settings" msgid="6856911551799175914">"Игри"</string>
-    <string name="audio_files_title" msgid="3073879661731363935">"Аудио датотеки"</string>
+    <string name="audio_files_title" msgid="3073879661731363935">"Аудиодатотеки"</string>
     <string name="app_info_storage_title" msgid="6643391804949509308">"Искористен простор"</string>
     <string name="webview_uninstalled_for_user" msgid="3407952144444040557">"(деинсталирано за корисникот <xliff:g id="USER">%s</xliff:g>)"</string>
     <string name="webview_disabled_for_user" msgid="8057805373224993504">"(оневозможено за корисникот <xliff:g id="USER">%s</xliff:g>)"</string>
@@ -4260,7 +4265,7 @@
     <string name="show_operator_name_title" msgid="5056163028128447308">"Име на мрежата"</string>
     <string name="show_operator_name_summary" msgid="6352180285743777497">"Прикажи го името на мрежата во статусната лента"</string>
     <string name="storage_manager_indicator" msgid="4255140732848476875">"„Управник со меморија“: <xliff:g id="STATUS">^1</xliff:g>"</string>
-    <string name="storage_manager_indicator_off" msgid="6404056007102580777">"Исклучен"</string>
+    <string name="storage_manager_indicator_off" msgid="6404056007102580777">"Исклучено"</string>
     <string name="storage_manager_indicator_on" msgid="5295306384982062320">"Вклучен"</string>
     <string name="install_type_instant" msgid="6248487669862821874">"Инстант апликација"</string>
     <string name="automatic_storage_manager_deactivation_warning" msgid="7867793739491286374">"Да се исклучи управникот со меморијата?"</string>
@@ -4301,17 +4306,17 @@
     <string name="disabled_dependent_setting_summary" msgid="7668590009599010842">"Зависи од друга поставка"</string>
     <string name="unknown_unavailability_setting_summary" msgid="5785931810977403534">"Поставката е недостапна"</string>
     <string name="my_device_info_account_preference_title" msgid="7965847995028952373">"Сметка"</string>
-    <string name="my_device_info_device_name_preference_title" msgid="7384446683248009296">"Име на уред"</string>
+    <string name="my_device_info_device_name_preference_title" msgid="7384446683248009296">"Име на уредот"</string>
     <string name="change_wifi_state_title" msgid="5140754955787584174">"Контрола на Wi-Fi"</string>
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"Дозволете апликацијата да контролира Wi-Fi"</string>
     <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"Дозволете апликацијава да вклучува или исклучува Wi-Fi, да скенира и да се поврзува на Wi-Fi мрежи, да додава или отстранува мрежи или да започне локална точка на пристап"</string>
-    <string name="media_output_title" msgid="8710632337456601848">"Пуштање содржина на"</string>
+    <string name="media_output_title" msgid="8710632337456601848">"Пуштај содржини на"</string>
     <string name="media_output_default_summary" msgid="3159237976830415584">"Овој уред"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"Телефон"</string>
     <string name="media_output_summary" product="tablet" msgid="6672024060360538526">"Таблет"</string>
     <string name="media_output_summary" product="device" msgid="5132223072593052660">"Уред"</string>
     <string name="media_out_summary_ongoing_call_state" msgid="3081034548396491775">"Недостапно за време на повици"</string>
-    <string name="media_output_summary_unavailable" msgid="6629338032551086053">"Недостапен"</string>
+    <string name="media_output_summary_unavailable" msgid="6629338032551086053">"Недостапно"</string>
     <string name="take_call_on_title" msgid="6570776899869030724">"Прифатете повик на"</string>
     <string name="cannot_change_apn_toast" msgid="5405823369239466817">"Ова APN не може да се промени."</string>
     <string name="battery_suggestion_title" product="tablet" msgid="10172199242166440">"Подобрете го траењето на батеријата"</string>
@@ -4322,19 +4327,19 @@
     <string name="gesture_prevent_ringing_title" msgid="8827963588425673557">"Притиснете ги копчињата за напојување и зголемување на јачината на звукот заедно за"</string>
     <string name="gesture_prevent_ringing_sound_title" msgid="8642330448721033641">"Кратенка за спречување на ѕвонењето"</string>
     <string name="prevent_ringing_option_vibrate" msgid="6456505293904544108">"Вибрации"</string>
-    <string name="prevent_ringing_option_mute" msgid="53662688921253613">"Исклучи звук"</string>
+    <string name="prevent_ringing_option_mute" msgid="53662688921253613">"Исклучен звук"</string>
     <string name="prevent_ringing_option_none" msgid="1450985763137666231">"Не прави ништо"</string>
     <string name="prevent_ringing_option_vibrate_summary" msgid="7961818570574683926">"Вклучено (вибрации)"</string>
     <string name="prevent_ringing_option_mute_summary" msgid="3509459199090688328">"Вклучено (исклучен звук)"</string>
     <string name="prevent_ringing_option_none_summary" msgid="5152618221093037451">"Исклучено"</string>
-    <string name="pref_title_network_details" msgid="3971074015034595956">"Детали за мрежа"</string>
+    <string name="pref_title_network_details" msgid="3971074015034595956">"Детали за мрежата"</string>
     <string name="about_phone_device_name_warning" msgid="9088572775969880106">"Името на уредот е видливо за апликациите на телефонот. Може да го видат и други луѓе кога ќе се поврзете со уреди со Bluetooth или кога ќе поставите Wi-Fi точка на пристап."</string>
     <string name="devices_title" msgid="4768432575951993648">"Уреди"</string>
     <string name="homepage_all_settings" msgid="3201220879559136116">"Сите поставки"</string>
     <string name="homepage_personal_settings" msgid="7472638597249114564">"Предлози"</string>
     <string name="choose_network_title" msgid="3213314359630522396">"Изберете мрежа"</string>
     <string name="network_disconnected" msgid="8677203031237141594">"Исклучена"</string>
-    <string name="network_connected" msgid="8197627827976712053">"Поврзана"</string>
+    <string name="network_connected" msgid="8197627827976712053">"Поврзано"</string>
     <string name="network_connecting" msgid="8798611458457547110">"Се поврзува…"</string>
     <string name="network_could_not_connect" msgid="552874922030763713">"Не може да се поврзе"</string>
     <string name="empty_networks_list" msgid="5170020017144403884">"Не се најдени мрежи."</string>
@@ -4440,7 +4445,7 @@
     <string name="mobile_network_mode_error" msgid="6818434186286086554">"Неважечки режим на мрежа <xliff:g id="NETWORKMODEID">%1$d</xliff:g>. Игнорирајте."</string>
     <string name="mobile_network_apn_title" msgid="5628635067747404382">"Имиња на пристапни точки"</string>
     <string name="manual_mode_disallowed_summary" msgid="799800630000340665">"Недостапно кога сте поврзани на <xliff:g id="CARRIER">%1$s</xliff:g>"</string>
-    <string name="emergency_info_contextual_card_summary" msgid="5541444321969803486">"Медицински информации, контакти за итни случаи"</string>
+    <string name="emergency_info_contextual_card_summary" msgid="5541444321969803486">"Медицински податоци, контакти за итни случаи"</string>
     <string name="see_more" msgid="7463940160389802632">"Видете повеќе"</string>
     <string name="see_less" msgid="3718892257002813387">"Види помалку"</string>
     <string name="network_connection_request_dialog_title" msgid="3150489262902506588">"Уред за користење со <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
@@ -4460,7 +4465,7 @@
     <string name="settings_panel_title" msgid="8181989386118232534">"Табла за поставки"</string>
     <string name="internet_connectivity_panel_title" msgid="341712994620215750">"Интернет-врска"</string>
     <string name="volume_connectivity_panel_title" msgid="4998755371496690971">"Јачина на звук"</string>
-    <string name="mobile_data_ap_mode_disabled" msgid="2452716524753472885">"Недостапен во авионски режим"</string>
+    <string name="mobile_data_ap_mode_disabled" msgid="2452716524753472885">"Недостапно во авионски режим"</string>
     <string name="force_desktop_mode" msgid="6973100177551040740">"Наметни режим на работна површина"</string>
     <string name="force_desktop_mode_summary" msgid="8865007610266954719">"Наметнете го експерименталниот режим на работна површина на секундарните екрани"</string>
     <string name="hwui_force_dark_title" msgid="3744825212652331461">"Отфрли го наметнувањето темен режим"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ml/arrays.xml b/tests/CarDeveloperOptions/res/values-ml/arrays.xml
index 933d78c..6fbe7e4 100644
--- a/tests/CarDeveloperOptions/res/values-ml/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-ml/arrays.xml
@@ -38,7 +38,16 @@
     <item msgid="5827960506924849753">"10 മിനിറ്റ്"</item>
     <item msgid="6677424950124253938">"30 മിനിറ്റ്"</item>
   </string-array>
-    <!-- no translation found for dream_timeout_entries:7 (8271452751594598661) -->
+  <string-array name="dream_timeout_entries">
+    <item msgid="6487043225269853023">"ഒരിക്കലും വേണ്ട"</item>
+    <item msgid="2517785806387977252">"15 സെക്കൻഡ്"</item>
+    <item msgid="6347954399441173672">"30 സെക്കൻഡ്"</item>
+    <item msgid="4858305253279921789">"ഒരു മിനിറ്റ്"</item>
+    <item msgid="8109273437140044073">"2 മിനിറ്റ്"</item>
+    <item msgid="2788593551142462622">"5 മിനിറ്റ്"</item>
+    <item msgid="8012672183888404961">"10 മിനിറ്റ്"</item>
+    <item msgid="8271452751594598661">"30 മിനിറ്റ്"</item>
+  </string-array>
   <string-array name="lock_after_timeout_entries">
     <item msgid="2232921187970351881">"ഉടന്‍"</item>
     <item msgid="2038544972632026612">"5 സെക്കൻഡ്"</item>
@@ -50,17 +59,47 @@
     <item msgid="811192536981678974">"10 മിനിറ്റ്"</item>
     <item msgid="7258394417241706272">"30 മിനിറ്റ്"</item>
   </string-array>
-    <!-- no translation found for entries_font_size:0 (2340391964816059553) -->
-    <!-- no translation found for entries_font_size:0 (6490061470416867723) -->
-    <!-- no translation found for entries_font_size:2 (1714184661981538355) -->
-    <!-- no translation found for entries_font_size:2 (1678068858001018666) -->
-    <!-- no translation found for wifi_status:3 (5848277343965362748) -->
-    <!-- no translation found for wifi_status_with_ssid:1 (6816207058895999545) -->
-    <!-- no translation found for wifi_status_with_ssid:3 (7547609081339573756) -->
-    <!-- no translation found for wifi_status_with_ssid:4 (5145158315060185414) -->
+  <string-array name="entries_font_size">
+    <item msgid="2340391964816059553">"ചെറുത്"</item>
+    <item msgid="591935967183159581">"ഡിഫോൾട്ട്"</item>
+    <item msgid="1714184661981538355">"വലുത്"</item>
+    <item msgid="6195563047686707484">"ഏറ്റവും വലുത്"</item>
+  </string-array>
+  <string-array name="wifi_status">
+    <item msgid="1304883790721412351"></item>
+    <item msgid="4157625910392775808">"സ്‌കാൻചെയ്യുന്നു..."</item>
+    <item msgid="5597394826455877834">"കണക്‌റ്റുചെയ്യുന്നു..."</item>
+    <item msgid="5848277343965362748">"പരിശോധിച്ചുറപ്പിക്കുന്നു…"</item>
+    <item msgid="3391238031431440676">"IP വിലാസം നേടുന്നു..."</item>
+    <item msgid="5257597310494000224">"കണക്‌റ്റ് ചെയ്‌തു"</item>
+    <item msgid="8472497592913050396">"താൽക്കാലികമായി നിർത്തി"</item>
+    <item msgid="1228072488815999109">"വിച്‌ഛേദിക്കുന്നു..."</item>
+    <item msgid="7253087004422991731">"വിച്ഛേദിച്ചു"</item>
+    <item msgid="4169850917304751227">"പരാജയപ്പെട്ടു"</item>
+    <item msgid="6266658166690831131">"തടഞ്ഞു"</item>
+    <item msgid="4517230805854909775">"മോശം കണക്ഷൻ താൽക്കാലികമായി ഒഴിവാക്കുന്നു"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="4853670665485437464"></item>
+    <item msgid="6816207058895999545">"സ്‌കാൻ ചെയ്യുന്നു…"</item>
+    <item msgid="8058143476674427024">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> എന്നതിലേക്ക് കണക്‌റ്റുചെയ്യുന്നു..."</item>
+    <item msgid="7547609081339573756">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> മുഖേന പരിശോധിച്ചുറപ്പിക്കുന്നു…"</item>
+    <item msgid="5145158315060185414">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> എന്നതിൽ നിന്ന് IP വിലാസം നേടുന്നു…"</item>
+    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> എന്നതിൽ കണക്‌റ്റുചെയ്‌തു"</item>
+    <item msgid="6600156231416890902">"താൽക്കാലികമായി നിർത്തി"</item>
+    <item msgid="4133290864821295785">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> എന്നതിൽ നിന്ന് വിച്‌ഛേദിക്കുന്നു..."</item>
+    <item msgid="3980154971187953257">"വിച്ഛേദിച്ചു"</item>
+    <item msgid="2847316776634969068">"പരാജയപ്പെട്ടു"</item>
+    <item msgid="4390990424746035383">"തടഞ്ഞു"</item>
+    <item msgid="3618248791367063949">"മോശം കണക്ഷൻ താൽക്കാലികമായി ഒഴിവാക്കുന്നു"</item>
+  </string-array>
     <!-- no translation found for wifi_tether_security:0 (5586343370515598801) -->
     <!-- no translation found for wifi_tether_security:1 (6136336549994615745) -->
-    <!-- no translation found for wifi_p2p_wps_setup:0 (5390235347963255303) -->
+  <string-array name="wifi_p2p_wps_setup">
+    <item msgid="5390235347963255303">"പുഷ് ബട്ടൺ"</item>
+    <item msgid="7401896200768713930">"പിയർ ഉപകരണത്തിൽ നിന്നുള്ള പിൻ"</item>
+    <item msgid="4526848028011846710">"ഈ ഉപകരണത്തിൽ നിന്നുള്ള പിൻ"</item>
+  </string-array>
   <string-array name="wifi_p2p_status">
     <item msgid="8741947238021758201">"കണക്‌റ്റ് ചെയ്‌തു"</item>
     <item msgid="983792611851499732">"ക്ഷണിച്ചു"</item>
@@ -82,8 +121,13 @@
     <item msgid="1644506614010085798">"4"</item>
     <item msgid="3132506679404897150">"5"</item>
   </string-array>
-    <!-- no translation found for wifi_signal:1 (7882129634982603782) -->
-    <!-- no translation found for wifi_signal:4 (999948812884919584) -->
+  <string-array name="wifi_signal">
+    <item msgid="1709949377823900951">"മോശം"</item>
+    <item msgid="7882129634982603782">"മോശം"</item>
+    <item msgid="6457357501905996224">"തൃപ്‌തികരം"</item>
+    <item msgid="405271628162918841">"നല്ലത്"</item>
+    <item msgid="999948812884919584">"മികച്ചത്"</item>
+  </string-array>
   <string-array name="data_usage_data_range">
     <item msgid="8986775481492954015">"കഴിഞ്ഞ 30 ദിവസം"</item>
     <item msgid="3211287705232736964">"ഉപയോഗ സൈക്കിൾ സജ്ജമാക്കുക..."</item>
@@ -119,7 +163,10 @@
     <item msgid="7330627471456865502">"MSCHAPV2"</item>
     <item msgid="6255179395132581882">"GTC"</item>
   </string-array>
-    <!-- no translation found for wifi_ip_settings:1 (4377002609760712163) -->
+  <string-array name="wifi_ip_settings">
+    <item msgid="2717196390555072244">"DHCP"</item>
+    <item msgid="4377002609760712163">"സ്‌റ്റാറ്റിക്ക്"</item>
+  </string-array>
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"ഒന്നുമില്ല"</item>
     <item msgid="1464741437353223198">"മാനുവൽ"</item>
@@ -239,11 +286,73 @@
     <item msgid="1165623660533024666">"പശ്ചാത്തലത്തിൽ റൺ ചെയ്യുക"</item>
     <item msgid="6423861043647911030">"ഉപയോഗസഹായി വോളിയം"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:3 (7836406246005211990) -->
-    <!-- no translation found for app_ops_labels:4 (3951439024549922598) -->
-    <!-- no translation found for app_ops_labels:8 (3597797992398484655) -->
-    <!-- no translation found for app_ops_labels:20 (3037159047591081136) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"ലൊക്കേഷൻ"</item>
+    <item msgid="6656077694190491067">"ലൊക്കേഷൻ"</item>
+    <item msgid="8790228218278477369">"ലൊക്കേഷൻ"</item>
+    <item msgid="7836406246005211990">"വൈബ്രേറ്റ് ചെയ്യുക"</item>
+    <item msgid="3951439024549922598">"കോൺടാക്റ്റുകൾ റീഡ് ചെയ്യുക"</item>
+    <item msgid="8802152411647068">"കോൺടാക്റ്റുകൾ പരിഷ്‌ക്കരിക്കുക"</item>
+    <item msgid="229544934599698735">"കോൾ ചരിത്രം റീഡ് ചെയ്യുക"</item>
+    <item msgid="7396102294405899613">"കോൾ ചരിത്രം പരിഷ്‌ക്കരിക്കുക"</item>
+    <item msgid="3597797992398484655">"കലണ്ടർ റീഡ് ചെയ്യുക"</item>
+    <item msgid="2705975774250907343">"കലണ്ടർ പരിഷ്‌ക്കരിക്കുക"</item>
+    <item msgid="4668747371441932697">"ലൊക്കേഷൻ"</item>
+    <item msgid="1487578921720243646">"അറിയിപ്പ് പോസ്റ്റുചെയ്യുക"</item>
+    <item msgid="4636080349724146638">"ലൊക്കേഷൻ"</item>
+    <item msgid="673510900286463926">"ഫോണ്‍ വിളിക്കുക"</item>
+    <item msgid="542083422784609790">"SMS/MMS വായിക്കുക"</item>
+    <item msgid="1033780373029588436">"SMS/MMS എഴുതുക"</item>
+    <item msgid="5647111115517787488">"SMS/MMS നേടുക"</item>
+    <item msgid="8591105601108455893">"SMS/MMS നേടുക"</item>
+    <item msgid="7730995008517841903">"SMS/MMS നേടുക"</item>
+    <item msgid="2613033109026626086">"SMS/MMS നേടുക"</item>
+    <item msgid="3037159047591081136">"SMS/MMS അയയ്‌ക്കുക"</item>
+    <item msgid="4726682243833913568">"SMS/MMS വായിക്കുക"</item>
+    <item msgid="6555678522277865572">"SMS/MMS എഴുതുക"</item>
+    <item msgid="6981734935578130884">"ക്രമീകരണങ്ങൾ പരിഷ്‌ക്കരിക്കുക"</item>
+    <item msgid="8705854389991425629">"മുകളിൽ ഡ്രോ ചെയ്യുക"</item>
+    <item msgid="5861356020344153651">"ആക്‌സസ്സ് അറിയിപ്പുകൾ"</item>
+    <item msgid="78432174621628659">"ക്യാമറ"</item>
+    <item msgid="3986116419882154794">"ഓഡിയോ റെക്കോർഡുചെയ്യുക"</item>
+    <item msgid="4516840825756409490">"ഓഡിയോ പ്ലേ ചെയ്യുക"</item>
+    <item msgid="6811712502798183957">"ക്ലിപ്പ്ബോർഡ് റീഡുചെയ്യുക"</item>
+    <item msgid="2780369012602289114">"ക്ലിപ്പ്ബോർഡ് പരിഷ്‌ക്കരിക്കുക"</item>
+    <item msgid="2331359440170850868">"മീഡിയ ബട്ടണുകൾ"</item>
+    <item msgid="6133599737122751231">"ഓഡിയോ ഫോക്കസ്"</item>
+    <item msgid="6844485713404805301">"മൊത്തം വോളിയം"</item>
+    <item msgid="1600379420669104929">"വോയ്‌സ് വോളിയം"</item>
+    <item msgid="6296768210470214866">"റിംഗ് വോളിയം"</item>
+    <item msgid="510690696071629241">"മീഡിയാ വോളിയം"</item>
+    <item msgid="406861638631430109">"അലാറം വോളിയം"</item>
+    <item msgid="4715864795872233884">"അറിയിപ്പ് വോളിയം"</item>
+    <item msgid="2311478519251301183">"ബ്ലൂടൂത്ത് വോളിയം"</item>
+    <item msgid="5133991377896747027">"സജീവമായി തുടരുക"</item>
+    <item msgid="2464189519136248621">"ലൊക്കേഷൻ"</item>
+    <item msgid="2062677934050803037">"ലൊക്കേഷൻ"</item>
+    <item msgid="1735171933192715957">"ഉപയോഗ സ്ഥിതിവിവരക്കണക്കുകൾ നേടുക"</item>
+    <item msgid="1014093788778383554">"മൈക്രോഫോൺ മ്യൂട്ടുചെയ്യുക/അൺമ്യൂട്ടുചെയ്യുക"</item>
+    <item msgid="4199297950608622850">"ടോസ്റ്റ് കാണിക്കുക"</item>
+    <item msgid="2527962435313398821">"പ്രോജക്‌റ്റ് മീഡിയ"</item>
+    <item msgid="5117506254221861929">"VPN സജീവമാക്കുക"</item>
+    <item msgid="8291198322681891160">"വാൾപേപ്പർ എഴുതുക"</item>
+    <item msgid="7106921284621230961">"അസിസ്റ്റ് ഘടന"</item>
+    <item msgid="4496533640894624799">"അസിസ്റ്റ് സ്‌ക്രീൻഷോട്ട്"</item>
+    <item msgid="2598847264853993611">"ഫോൺ നില വായിക്കുക"</item>
+    <item msgid="9215610846802973353">"വോയ്‌സ്‌മെയിൽ ചേർക്കുക"</item>
+    <item msgid="9186411956086478261">"sip ഉപയോഗിക്കുക"</item>
+    <item msgid="6884763100104539558">"ഔട്ട്‌ഗോയിംഗ് കോൾ പ്രോസസ്സുചെയ്യുക"</item>
+    <item msgid="125513972170580692">"ഫിംഗർപ്രിന്റ്"</item>
+    <item msgid="2556071024281275619">"ബോഡി സെൻസറുകൾ"</item>
+    <item msgid="617168514928339387">"സെൽ ബ്രോഡ്‌കാസ്റ്റുകൾ വായിക്കുക"</item>
+    <item msgid="7134693570516523585">"മോക്ക് ലൊക്കേഷൻ"</item>
+    <item msgid="7224489175375229399">"സ്റ്റോറേജ് വായിക്കുക"</item>
+    <item msgid="8472735063903258202">"സ്റ്റോറേജ് എഴുതുക"</item>
+    <item msgid="4069276819909595110">"സ്ക്രീൻ ഓണാക്കുക"</item>
+    <item msgid="1228338896751121025">"അക്കൗണ്ടുകൾ സ്വന്തമാക്കുക"</item>
+    <item msgid="3181581793459233672">"പശ്ചാത്തലത്തിൽ റൺ ചെയ്യുക"</item>
+    <item msgid="2340936043025374076">"ഉപയോഗസഹായി വോളിയം"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"ഹ്രസ്വം"</item>
     <item msgid="4816511817309094890">"ഇടത്തരം"</item>
@@ -260,7 +369,13 @@
     <item msgid="4627069151979553527">"കൂട്ടെഴുത്ത്"</item>
     <item msgid="6896773537705206194">"ചെറിയ കാപ്പിറ്റലുകൾ"</item>
   </string-array>
-    <!-- no translation found for captioning_font_size_selector_titles:3 (2784236342175159295) -->
+  <string-array name="captioning_font_size_selector_titles">
+    <item msgid="1680223634161592855">"തീരെ ചെറുത്"</item>
+    <item msgid="5091603983404027034">"ചെറുത്"</item>
+    <item msgid="176844712416932112">"സാധാരണം"</item>
+    <item msgid="2784236342175159295">"വലുത്"</item>
+    <item msgid="218913203203160606">"വളരെ വലുത്"</item>
+  </string-array>
   <string-array name="captioning_edge_type_selector_titles">
     <item msgid="3865198759294188069">"ഡിഫോൾട്ട്"</item>
     <item msgid="6488643537808152001">"ഒന്നുമില്ല"</item>
@@ -275,7 +390,14 @@
     <item msgid="1874668269931014581">"75%"</item>
     <item msgid="6462911487571123954">"100%"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"സ്ഥിര ആപ്പ് ഉപയോഗിക്കൂ"</item>
+    <item msgid="8611890312638868524">"കറുപ്പിൽ വെളുപ്പ്"</item>
+    <item msgid="5891360837786277638">"വെളുപ്പിൽ കറുപ്പ്"</item>
+    <item msgid="2798457065945456853">"കറുപ്പിൽ മഞ്ഞ"</item>
+    <item msgid="5799049811524553967">"നീലയിൽ മഞ്ഞ"</item>
+    <item msgid="3673930830658169860">"ഇഷ്ടാനുസൃതം"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"PPTP VPN"</item>
     <item msgid="1349760781118368659">"മുമ്പ് പങ്കിട്ട കീകൾ ഉപയോഗിക്കുന്ന L2TP/IPSec VPN"</item>
@@ -288,15 +410,32 @@
     <item msgid="2958623927055120839">"ഒന്നുമില്ല"</item>
     <item msgid="1157046369795346308">"മാനുവൽ"</item>
   </string-array>
-    <!-- no translation found for vpn_states:4 (9135049670787351881) -->
+  <string-array name="vpn_states">
+    <item msgid="5408915841694583740">"വിച്ഛേദിച്ചു"</item>
+    <item msgid="8754480102834556765">"സമാരംഭിക്കുന്നു..."</item>
+    <item msgid="3351334355574270250">"കണക്‌റ്റുചെയ്യുന്നു..."</item>
+    <item msgid="8303882153995748352">"കണക്‌റ്റ് ചെയ്‌തു"</item>
+    <item msgid="9135049670787351881">"ടൈംഔട്ട്"</item>
+    <item msgid="2124868417182583926">"പരാജയപ്പെട്ടു"</item>
+  </string-array>
   <string-array name="security_settings_premium_sms_values">
     <item msgid="1164265643455394443">"ചോദിക്കുക"</item>
     <item msgid="7718817231348607934">"ഒരിക്കലുമനുവദിക്കരുത്"</item>
     <item msgid="8184570120217958741">"എല്ലായ്‌പ്പോഴും അനുവദിക്കുക"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"സാധാരണം"</item>
+    <item msgid="5101233285497327432">"ഇടത്തരം"</item>
+    <item msgid="1555861583162930714">"കുറഞ്ഞത്"</item>
+    <item msgid="1719683776264798117">"കഴിയാറായി"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"സാധാരണം"</item>
+    <item msgid="6107138933849816768">"ഇടത്തരം"</item>
+    <item msgid="182695359839047859">"കുറഞ്ഞത്"</item>
+    <item msgid="8577246509202964244">"കഴിയാറായി"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"നിരന്തരമായ"</item>
     <item msgid="167418068739176448">"മികച്ച പ്രവർത്തനം"</item>
@@ -334,8 +473,8 @@
   </string-array>
   <string-array name="wifi_metered_entries">
     <item msgid="4329206416008519163">"സ്വയമേവ കണ്ടെത്തുക"</item>
-    <item msgid="773943026484148895">"മീറ്റർ-മാപകമായി കണക്കാക്കുക"</item>
-    <item msgid="1008268820118852416">"മീറ്റർ മാപകമല്ലാത്തതായി കണക്കാക്കുക"</item>
+    <item msgid="773943026484148895">"മീറ്റർ ചെയ്തതായി കണക്കാക്കുക"</item>
+    <item msgid="1008268820118852416">"മീറ്റർ ചെയ്യാത്തതായി കണക്കാക്കുക"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
     <item msgid="6545683814310036454">"ക്രമരഹിതമാക്കിയ MAC ഉപയോഗിക്കുക (ഡിഫോൾട്ട്)"</item>
diff --git a/tests/CarDeveloperOptions/res/values-ml/config.xml b/tests/CarDeveloperOptions/res/values-ml/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-ml/config.xml
+++ b/tests/CarDeveloperOptions/res/values-ml/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-ml/strings.xml b/tests/CarDeveloperOptions/res/values-ml/strings.xml
index 620e35c..f068854 100644
--- a/tests/CarDeveloperOptions/res/values-ml/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ml/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"സ്ക്രീനിലെ ടെക്സ്റ്റ് ചെറുതോ വലുതോ ആക്കുക."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"ചെറുതാക്കുക"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"വലുതാക്കുക"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"സാമ്പിൾ ടെക്‌സ്റ്റ്"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"ഓസ് നഗരത്തിലെ അതിശയിപ്പിക്കുന്ന മന്ത്രവാദി"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"അധ്യായം 11: ഓസ് എന്ന അത്ഭുതകരമായ മരതകനഗരം"</string>
@@ -208,7 +207,7 @@
     <string name="proxy_error_empty_port" msgid="8034561724923076215">"നിങ്ങൾ പോർട്ട് ഫീൽഡ് പൂർത്തിയാക്കേണ്ടതുണ്ട്."</string>
     <string name="proxy_error_empty_host_set_port" msgid="8471455809508588255">"ഹോസ്‌റ്റ് ഫീൽഡ് ശൂന്യമാണെങ്കിൽ പോർട്ട് ഫീൽഡും ശൂന്യമായിരിക്കണം."</string>
     <string name="proxy_error_invalid_port" msgid="4046559920586100637">"നിങ്ങൾ ടൈപ്പുചെയ്‌ത പോർട്ട് സാധുവായതല്ല."</string>
-    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"ബ്രൗസർ HTTP പ്രോക്‌സി ഉപയോഗിക്കുന്നുവെങ്കിലും മറ്റ് അപ്ലിക്കേഷനുകൾ ഉപയോഗിക്കാനിടയില്ല."</string>
+    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"ബ്രൗസർ HTTP പ്രോക്‌സി ഉപയോഗിക്കുന്നുവെങ്കിലും മറ്റ് ആപ്പുകൾ ഉപയോഗിക്കാനിടയില്ല."</string>
     <string name="proxy_url_title" msgid="882042361706435904">"PAC URL: "</string>
     <string name="radio_info_dl_kbps" msgid="2903778264453410272">"DL ബാന്‍ഡ്‍വിത്ത് (kbps):"</string>
     <string name="radio_info_ul_kbps" msgid="3802245899811732716">"UL ബാന്‍ഡ്‍വിത്ത് (kbps):"</string>
@@ -419,7 +418,7 @@
     <string name="security_settings_face_enroll_done" msgid="5409739233373490971">"പൂർത്തിയായി"</string>
     <string name="security_settings_face_settings_use_face_category" msgid="1586532139528115416">"മുഖം ഉപയോഗിക്കേണ്ടത്"</string>
     <string name="security_settings_face_settings_use_face_unlock_phone" msgid="318274519126401671">"ഉപകരണം അൺലോക്ക് ചെയ്യൽ"</string>
-    <string name="security_settings_face_settings_use_face_for_apps" msgid="5479369083370664351">"സൈൻ ഇൻ ചെയ്യലും പണമടയ്ക്കലും"</string>
+    <string name="security_settings_face_settings_use_face_for_apps" msgid="5479369083370664351">"ആപ്പ് സൈൻ ഇൻ, പേയ്മെന്റുകൾ"</string>
     <string name="security_settings_face_settings_require_attention" msgid="2755140150841557225">"അൺലോക്ക് ചെയ്യാൻ കണ്ണുകൾ തുറന്നിരിക്കണം"</string>
     <string name="security_settings_face_settings_require_attention_details" msgid="2557060433599942587">"മുഖം പരിശോധിച്ചുറപ്പിക്കുമ്പോൾ, കണ്ണുകൾ തുറന്നിരിക്കണം"</string>
     <string name="security_settings_face_settings_require_confirmation" msgid="7312024271060416438">"എപ്പോഴും സ്ഥിരീകരണം ആവശ്യമാണ്"</string>
@@ -456,7 +455,7 @@
     <string name="lock_screen_intro_skip_dialog_text" product="tablet" msgid="7572334562915795226">"ഉപകരണ പരിരക്ഷാ ഫീച്ചറുകൾ ഓണാക്കില്ല. ഈ ടാബ്‌ലെറ്റ് നഷ്ടപ്പെടുകയോ മോഷ്ടിക്കപ്പെടുകയോ ചെയ്താൽ, ടാബ്‌ലെറ്റ് ഉപയോഗിക്കുന്നതിൽ നിന്ന് മറ്റുള്ളവരെ തടയാൻ നിങ്ങൾക്കാവില്ല."</string>
     <string name="lock_screen_intro_skip_dialog_text" product="device" msgid="3819285334459763813">"ഉപകരണ പരിരക്ഷാ ഫീച്ചറുകൾ ഓണാക്കില്ല. ഈ ഉപകരണം നഷ്ടപ്പെടുകയോ മോഷ്ടിക്കപ്പെടുകയോ ചെയ്താൽ, ഉപകരണം ഉപയോഗിക്കുന്നതിൽ നിന്ന് മറ്റുള്ളവരെ തടയാൻ നിങ്ങൾക്കാവില്ല."</string>
     <string name="lock_screen_intro_skip_dialog_text" product="default" msgid="5361573789585652826">"ഉപകരണ പരിരക്ഷാ ഫീച്ചറുകൾ ഓണാക്കില്ല. ഈ ഫോൺ നഷ്ടപ്പെടുകയോ മോഷ്ടിക്കപ്പെടുകയോ ചെയ്താൽ, ഫോൺ ഉപയോഗിക്കുന്നതിൽ നിന്ന് മറ്റുള്ളവരെ തടയാൻ നിങ്ങൾക്കാവില്ല."</string>
-    <string name="skip_anyway_button_label" msgid="4437815969645175429">"ഏതുവിധേനയും ഒഴിവാക്കുക"</string>
+    <string name="skip_anyway_button_label" msgid="4437815969645175429">"എന്തായാലും ഒഴിവാക്കുക"</string>
     <string name="go_back_button_label" msgid="7310586887969860472">"തിരിച്ചുപോവുക"</string>
     <string name="skip_lock_screen_dialog_button_label" msgid="6706047245716780006">"ഒഴിവാക്കുക"</string>
     <string name="cancel_lock_screen_dialog_button_label" msgid="2534925227627658819">"റദ്ദാക്കുക"</string>
@@ -468,7 +467,7 @@
     <string name="security_settings_fingerprint_enroll_dialog_delete" msgid="4312297515772004580">"ഇല്ലാതാക്കുക"</string>
     <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"സെൻസർ സ്പർശിക്കുക"</string>
     <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"സെൻസറിൽ വിരൽ വച്ച് വൈബ്രേഷൻ അനുഭവപ്പെട്ട ശേഷം വിരൽ മാറ്റുക."</string>
-    <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"ഉയർത്തുക, വീണ്ടും സ്പർശിക്കുക"</string>
+    <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"വിരലെടുക്കുക, വീണ്ടും സ്പർശിക്കുക"</string>
     <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"നിങ്ങളുടെ ഫിംഗർപ്രിന്റിന്റെ വ്യത്യസ്ത ഭാഗങ്ങൾ ചേർക്കുന്നതിന് നിങ്ങളുടെ വിരൽ ഉയർത്തിക്കൊണ്ടിരിക്കുക"</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"ഫിംഗർപ്രിന്റ് ചേർത്തു"</string>
     <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"നിങ്ങൾ ഈ ഐക്കൺ കാണുമ്പോൾ, തിരിച്ചറിയലിനോ വാങ്ങലിന് അംഗീകാരം നൽകാനോ നിങ്ങളുടെ ഫിംഗർപ്രിന്‍റ് ഉപയോഗിക്കുക"</string>
@@ -668,7 +667,6 @@
       <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> അക്കങ്ങളേക്കാൾ കുറവായിരിക്കണം</item>
       <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> അക്കത്തിനേക്കാൾ കുറവായിരിക്കണം</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"0 മുതൽ 9 വരെയുള്ള അക്കങ്ങൾ മാത്രം അടങ്ങിയിരിക്കണം"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"ഉപകരണ അഡ്‌മിൻ സമീപകാലത്തുള്ള പിൻ ഉപയോഗിക്കുന്നത് അനുവദിക്കുന്നില്ല"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"നിങ്ങളുടെ ഐടി അഡ്‌മിൻ സാധാരണ പിന്നുകൾ ബ്ലോക്ക് ചെയ്‌തിട്ടുണ്ട്. മറ്റൊരു പിൻ പരീക്ഷിക്കുക."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"ഇതിൽ അസാധുവായൊരു പ്രതീകം ഉണ്ടായിരിക്കാൻ പാടില്ല"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">കുറഞ്ഞത് അക്ഷരമല്ലാത്ത <xliff:g id="COUNT">%d</xliff:g> പ്രതീകങ്ങളെങ്കിലും അടങ്ങിയിരിക്കണം</item>
       <item quantity="one">കുറഞ്ഞത് അക്ഷരമല്ലാത്ത ഒരു പ്രതീകമെങ്കിലും അടങ്ങിയിരിക്കണം</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">കുറഞ്ഞത് സംഖ്യയല്ലാത്ത <xliff:g id="COUNT">%d</xliff:g> പ്രതീകങ്ങളെങ്കിലും അടങ്ങിയിരിക്കണം</item>
+      <item quantity="one">കുറഞ്ഞത് സംഖ്യയല്ലാത്ത ഒരു പ്രതീകമെങ്കിലും അടങ്ങിയിരിക്കണം</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"ഒരു സമീപകാല പാസ്‌വേഡ് ഉപയോഗിക്കാൻ ഉപകരണ അഡ്‌മിൻ അനുവദിക്കുന്നില്ല"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"നിങ്ങളുടെ IT അഡ്‌മിൻ സാധാരണ പാസ്‍വേഡുകൾ ബ്ലോക്ക് ചെയ്‌തിട്ടുണ്ട്. മറ്റൊരു പാസ്‍വേഡ് പരീക്ഷിക്കുക."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"അക്കങ്ങൾ ആരോഹണ ക്രമത്തിലോ അവരോഹണ ക്രമത്തിലോ അനുക്രമമായോ നൽകുന്നത് അനുവദനീയമല്ല"</string>
@@ -855,7 +857,7 @@
     <string name="wifi_poor_network_detection_summary" msgid="5539951465985614590">"മികച്ച ഇന്‍റർനെറ്റ് കണക്ഷൻ ഉണ്ടാകുന്നതുവരെ വൈഫൈ നെറ്റ്‌വർക്ക് ഉപയോഗിക്കരുത്"</string>
     <string name="wifi_avoid_poor_network_detection_summary" msgid="1976503191780928104">"മികച്ച ഇന്‍റർനെറ്റ് കണക്ഷനുള്ള നെറ്റ്‌വർക്കുകൾ മാത്രം ഉപയോഗിക്കുക"</string>
     <string name="use_open_wifi_automatically_title" msgid="3084513215481454350">"ഓപ്പൺ നെറ്റ്‌വർക്കിലേക്ക് കണക്റ്റ് ചെയ്യുക"</string>
-    <string name="use_open_wifi_automatically_summary" msgid="8338020172673161754">"ഉയർന്ന ഗുണമേന്മയുള്ള പബ്ലിക് നെറ്റ്‌വർക്കുകളിലേക്ക് സ്വയമേവ കണക്റ്റ് ചെയ്യുക"</string>
+    <string name="use_open_wifi_automatically_summary" msgid="8338020172673161754">"ഉയർന്ന നിലവാരമുള്ള പൊതു നെറ്റ്‌വർക്കുകളിലേക്ക് സ്വയമേവ കണക്റ്റ് ചെയ്യുക"</string>
     <string name="use_open_wifi_automatically_summary_scoring_disabled" msgid="1559329344492373028">"ഉപയോഗിക്കാനായി, ഒരു നെറ്റ്‌വർക്ക് റേറ്റിംഗ് ദാതാവിനെ തിരഞ്ഞെടുക്കുക"</string>
     <string name="use_open_wifi_automatically_summary_scorer_unsupported_disabled" msgid="1123080670578756834">"ഉപയോഗിക്കാനായി, അനുയോജ്യമായ ഒരു നെറ്റ്‌വർക്ക് റേറ്റിംഗ് ദാതാവിനെ തിരഞ്ഞെടുക്കുക"</string>
     <string name="wifi_install_credentials" msgid="5650088113710858289">"സർട്ടിഫിക്കറ്റുകൾ ഇൻസ്റ്റാളുചെയ്യുക"</string>
@@ -903,7 +905,7 @@
     <string name="wifi_ssid_hint" msgid="5010024648106585165">"SSID നൽകുക"</string>
     <string name="wifi_security" msgid="9136702039496152831">"സുരക്ഷ"</string>
     <string name="wifi_hidden_network" msgid="6647772204699776833">"മറയ്‌ക്കപ്പെട്ട നെറ്റ്‌വർക്ക്"</string>
-    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"നിങ്ങളുടെ റൂട്ടർ ഒരു നെറ്റ്‍വര്‍ക്ക് ഐഡി പ്രക്ഷേപണം ചെയ്യുന്നില്ലെങ്കിൽ, എന്നാൽ ഭാവിയിൽ നിങ്ങൾ ഇതിലേക്ക് കണക്‌റ്റ് ചെയ്യാൻ ആഗ്രഹിക്കുന്നെങ്കിൽ, നെറ്റ്‍വര്‍ക്ക് അദൃശ്യമാക്കി സജ്ജീകരിക്കാനാവും.\n\nനെറ്റ്‍വര്‍ക്ക് കണ്ടെത്താനായി നിങ്ങളുടെ ഫോൺ അതിന്റെ സിഗ്‌നലുകളെ പതിവായി പ്രക്ഷേപണം ചെയ്യും എന്നതിനാൽ ഇത് സുരക്ഷയുമായി ബന്ധപ്പെട്ട അപകടസാധ്യത സൃഷ്‌ടിക്കാൻ സാധ്യതയുണ്ട്.\n\nനെറ്റ്‍വര്‍ക്ക് അദൃശ്യമായി ക്രമീകരിക്കുന്നത്, നിങ്ങളുടെ റൂട്ടർ ക്രമീകരണം മാറ്റില്ല."</string>
+    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"നിങ്ങളുടെ റൂട്ടർ ഒരു നെറ്റ്‍വര്‍ക്ക് ഐഡി പ്രക്ഷേപണം ചെയ്യുന്നില്ല,എന്നാൽ ഭാവിയിൽ നിങ്ങൾ ഇതിലേക്ക് കണക്‌റ്റ് ചെയ്യാൻ ആഗ്രഹിക്കുന്നു എങ്കിൽ, നെറ്റ്‍വര്‍ക്ക് മറയ്ക്കപ്പെട്ടതായി സജ്ജീകരിക്കാനാവും.\n\nനെറ്റ്‍വര്‍ക്ക് കണ്ടെത്താനായി നിങ്ങളുടെ ഫോൺ അതിന്റെ സിഗ്‌നലുകളെ പതിവായി പ്രക്ഷേപണം ചെയ്യും എന്നതിനാൽ ഇത് സുരക്ഷാ ഭീഷണി സൃഷ്‌ടിച്ചേക്കും.\n\nനെറ്റ്‍വര്‍ക്ക് മറയ്ക്കപ്പെട്ടതായി ക്രമീകരിക്കുന്നത്, നിങ്ങളുടെ റൂട്ടർ ക്രമീകരണം മാറ്റില്ല."</string>
     <string name="wifi_signal" msgid="696548364467704808">"സിഗ്‌നൽ ശക്തി"</string>
     <string name="wifi_status" msgid="3439931558930689940">"നില"</string>
     <string name="tx_wifi_speed" msgid="2571810085003261073">"പ്രക്ഷേപണ ലിങ്കിന്റെ വേഗത"</string>
@@ -913,7 +915,7 @@
     <string name="passpoint_label" msgid="7429247462404128615">"ഇതുവഴി സംരക്ഷിച്ചു"</string>
     <string name="passpoint_content" msgid="340527524510304327">"<xliff:g id="NAME">%1$s</xliff:g> ക്രെഡൻഷ്യലുകൾ"</string>
     <string name="wifi_eap_method" msgid="3752116941487485859">"EAP രീതി"</string>
-    <string name="please_select_phase2" msgid="5848080896810435677">"ഘട്ടം 2 പ്രമാണീകരണം"</string>
+    <string name="please_select_phase2" msgid="5848080896810435677">"രണ്ടാം ഘട്ട പരിശോധിച്ചുറപ്പിക്കൽ"</string>
     <string name="wifi_eap_ca_cert" msgid="1496395241849383785">"CA സർട്ടിഫിക്കറ്റ്"</string>
     <string name="wifi_eap_domain" msgid="3298302320003640130">"ഡൊമെയ്ൻ"</string>
     <string name="wifi_eap_user_cert" msgid="6786839531765719173">"ഉപയോക്തൃ സർട്ടിഫിക്കറ്റ്"</string>
@@ -925,7 +927,7 @@
     <string name="wifi_ap_choose_auto" msgid="7927637960569365785">"സ്വമേധയാ"</string>
     <string name="wifi_ap_choose_2G" msgid="43198403259714736">"2.4 GHz ബാൻഡ്"</string>
     <string name="wifi_ap_choose_5G" msgid="2624859713183683146">"5.0 GHz ബാൻഡ്"</string>
-    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"5.0 GHz ബാൻഡ് തിരഞ്ഞെടുത്തു"</string>
+    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"5.0 GHz ബാൻഡിന് മുൻഗണന"</string>
     <string name="wifi_ap_2G" msgid="5793110086517338494">"2.4 GHz"</string>
     <string name="wifi_ap_5G" msgid="4584892544393675403">"5.0 GHz"</string>
     <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"വൈഫൈ ഹോട്ട്‌സ്‌പോട്ടിനായി കുറഞ്ഞത് ഒരു ബാൻഡ് എങ്കിലും തിരഞ്ഞെടുക്കുക:"</string>
@@ -936,14 +938,14 @@
     <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"“<xliff:g id="SSID">%1$s</xliff:g>” എന്നതിലേക്ക് ഉപകരണം ചേർക്കാൻ,  ചുവടെയുള്ള QR കോഡിലേക്ക് കേന്ദ്രീകരിക്കുക"</string>
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"QR കോഡ് സ്‌കാൻ ചെയ്യുക"</string>
     <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"“<xliff:g id="SSID">%1$s</xliff:g>” എന്നതിലേക്ക് കണക്‌റ്റ് ചെയ്യാൻ,  ചുവടെയുള്ള QR കോഡിലേക്ക് കേന്ദ്രീകരിക്കുക"</string>
-    <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"QR കോഡ് പരിശോധിച്ച് വൈഫൈയിൽ ചേരുക"</string>
+    <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"QR കോഡ് സ്‍കാൻ ചെയ്ത് വൈഫൈയിൽ ചേരുക"</string>
     <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"വൈഫൈ പങ്കിടുക"</string>
     <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"“<xliff:g id="SSID">%1$s</xliff:g>” എന്നതിലേക്ക് കണക്‌റ്റ് ചെയ്യാൻ ഈ QR കോഡ് സ്‌കാൻ ചെയ്യുകയും പാസ്‌വേഡ് പങ്കിടുകയും ചെയ്യുക"</string>
     <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"“<xliff:g id="SSID">%1$s</xliff:g>\" എന്നതിലേക്ക് കണക്‌റ്റ് ചെയ്യാൻ ഈ QR കോഡ് സ്‌കാൻ ചെയ്യുക"</string>
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"QR കോഡ് റീഡ് ചെയ്യാനായില്ല. കോഡ് വീണ്ടും മധ്യത്തിലാക്കി വീണ്ടും ശ്രമിക്കുക"</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"വീണ്ടും ശ്രമിക്കുക. പ്രശ്‌നം തുടരുകയാണെങ്കിൽ, ഉപകരണ നിർമ്മാതാവിനെ ബന്ധപ്പെടുക"</string>
     <string name="wifi_dpp_failure_not_compatible" msgid="4320027179973678283">"എന്തോ കുഴപ്പമുണ്ടായി"</string>
-    <string name="wifi_dpp_failure_timeout" msgid="5060065168142109420">"ഉപകരണം പ്ലഗിൻ ചെയ്‌തെന്നും, ചാർജ്ജ് ചെയ്‌തെന്നും, ഓണാണെന്നും ഉറപ്പാക്കുക"</string>
+    <string name="wifi_dpp_failure_timeout" msgid="5060065168142109420">"ഉപകരണം പ്ലഗിൻ ചെയ്‌തിട്ടുണ്ടെന്നും ചാർജ്ജ് ചെയ്‌തിട്ടുണ്ടെന്നും ഓണാണെന്നും ഉറപ്പാക്കുക"</string>
     <string name="wifi_dpp_failure_generic" msgid="7840142544736640189">"ഉപകരണം പ്ലഗിൻ ചെയ്‌തെന്നും, ചാർജ്ജ് ചെയ്‌തെന്നും, ഓണാണെന്നും ഉറപ്പാക്കുക. പ്രശ്‌നം തുടരുകയാണെങ്കിൽ, ഉപകരണ നിർമ്മാതാവിനെ ബന്ധപ്പെടുക"</string>
     <string name="wifi_dpp_failure_not_supported" msgid="111779621766171626">"ഈ ഉപകരണം \"<xliff:g id="SSID">%1$s</xliff:g>\" ചേർക്കുന്നതിനെ പിന്തുണയ്ക്കുന്നില്ല"</string>
     <string name="wifi_dpp_check_connection_try_again" msgid="7144663015219170999">"കണക്ഷൻ പരിശോധിച്ച് വീണ്ടും ശ്രമിക്കുക"</string>
@@ -970,7 +972,7 @@
     <string name="wifi_multiple_cert_added" msgid="7986200585749147204">"(ഒന്നിലധികം സർട്ടിഫിക്കറ്റുകൾ ചേർത്തു)"</string>
     <string name="wifi_use_system_certs" msgid="4794489370929885022">"സിസ്റ്റം സർട്ടിഫിക്കറ്റുകൾ ഉപയോഗിക്കുക"</string>
     <string name="wifi_do_not_provide_eap_user_cert" msgid="4044301449482425250">"നൽകരുത്"</string>
-    <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"മൂല്യനിർണ്ണയം ചെയ്യരുത്"</string>
+    <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"സാധൂകരിക്കരുത്"</string>
     <string name="wifi_do_not_validate_eap_server_warning" msgid="3895397996759837323">"സർട്ടിഫിക്കറ്റൊന്നും വ്യക്തമാക്കിയിട്ടില്ല. നിങ്ങളുടെ കണക്ഷൻ സ്വകാര്യമായിരിക്കുകയില്ല."</string>
     <string name="wifi_ssid_too_long" msgid="34911971389775920">"നെറ്റ്‌വർക്കിന്റെ പേര് ദൈർഘ്യമേറിയതാണ്."</string>
     <string name="wifi_no_domain_warning" msgid="735859919311067606">"ഒരു ഡൊമെയ്ൻ വ്യക്തമാക്കിയിരിക്കണം."</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"വൈഫൈ"</item>
+    <item msgid="2271962426654621656">"മൊബൈൽ"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"വൈഫൈ ലഭ്യമല്ലെങ്കിൽ, മൊബൈൽ നെറ്റ്‌വർക്ക് ഉപയോഗിക്കുക"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"മൊബൈൽ നെറ്റ്‌വർക്ക് ലഭ്യമല്ലെങ്കിൽ, വൈഫൈ ഉപയോഗിക്കുക"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"വൈഫൈ മുഖേനയുള്ള കോൾ. വൈഫൈ നഷ്‌ടപ്പെട്ടാൽ, കോൾ അവസാനിക്കും."</string>
@@ -1676,11 +1681,11 @@
     <string name="location_access_summary" msgid="6919495149026354355">"നിങ്ങളുടെ അനുമതി ആവശ്യപ്പെട്ട അപ്ലിക്കേഷനുകളെ ലൊക്കേഷൻ വിവരങ്ങൾ ഉപയോഗിക്കാൻ അനുവദിക്കുക"</string>
     <string name="location_sources_heading" msgid="8526658357120282741">"ലൊക്കേഷൻ ഉറവിടങ്ങൾ"</string>
     <string name="about_settings" product="tablet" msgid="4869626690708456341">"ടാബ്‌ലെ‌റ്റിന് ഒരാമുഖം"</string>
-    <string name="about_settings" product="default" msgid="6019547763377294261">"ഫോണിന് ഒരാമുഖം"</string>
+    <string name="about_settings" product="default" msgid="6019547763377294261">"ഫോണിനെക്കുറിച്ച്"</string>
     <string name="about_settings" product="device" msgid="1770438316234693655">"ഉപകരണ വിവരം"</string>
     <string name="about_settings" product="emulator" msgid="4497482494770487014">"എമുലേറ്റഡ് ഉപകരണത്തെ കുറിച്ച്"</string>
     <string name="about_settings_summary" msgid="4506081667462281647">"നിയമ വിവരം, നില, സോഫ്‌റ്റ്‌വെയർ പതിപ്പ് എന്നിവ കാണുക"</string>
-    <string name="legal_information" msgid="2374267257615182139">"നിയമപരമായ വിവരം"</string>
+    <string name="legal_information" msgid="2374267257615182139">"നിയമപരമായ വിവരങ്ങൾ"</string>
     <string name="contributors_title" msgid="6800028420806884340">"സംഭാവകർ"</string>
     <string name="manual" msgid="5431859421432581357">"മാനുവൽ"</string>
     <string name="regulatory_labels" msgid="380968489247381025">"റെഗുലേറ്ററി ലേബലുകൾ"</string>
@@ -1763,7 +1768,7 @@
     <string name="lockpattern_settings_enable_visible_pattern_title_profile" msgid="5338893138982642228">"പ്രൊഫൈൽ പാറ്റേൺ ദൃശ്യമാക്കുക"</string>
     <string name="lockpattern_settings_enable_tactile_feedback_title" msgid="3203621862806531947">"ടാപ്പുചെയ്യുമ്പോൾ വൈബ്രേറ്റുചെയ്യൂ"</string>
     <string name="lockpattern_settings_enable_power_button_instantly_locks" msgid="5890335732200257777">"പവർബട്ടൺ ഉടൻ ലോക്കാകുന്നു"</string>
-    <string name="lockpattern_settings_power_button_instantly_locks_summary" msgid="1279989004145567840">"<xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g> അൺലോക്കുചെയ്‌തിരിക്കുമ്പോൾ ഒഴികെ"</string>
+    <string name="lockpattern_settings_power_button_instantly_locks_summary" msgid="1279989004145567840">"<xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g> അൺലോക്ക് ചെയ്‌തിരിക്കുമ്പോൾ ഒഴികെ"</string>
     <string name="lockpattern_settings_choose_lock_pattern" msgid="9042142745571386381">"അൺലോക്ക് പാറ്റേൺ സജ്ജീകരിക്കുക"</string>
     <string name="lockpattern_settings_change_lock_pattern" msgid="1456643060737114885">"അൺലോക്ക് പാറ്റേൺ മാറ്റുക"</string>
     <string name="lockpattern_settings_help_how_to_record" msgid="6037403647312543908">"ഒരു അൺലോക്ക് പാറ്റേൺ വരയ്‌ക്കേണ്ടതെങ്ങനെ"</string>
@@ -1980,7 +1985,7 @@
     <string name="keyboard_layout_dialog_switch_hint" msgid="138516114253502182">"മാറാൻ, Control-Spacebar അമർത്തുക"</string>
     <string name="keyboard_layout_default_label" msgid="8368579311667189793">"സ്ഥിരമായത്"</string>
     <string name="keyboard_layout_picker_title" msgid="6958831599253031987">"കീബോർഡ് ലേഔട്ടുകൾ"</string>
-    <string name="user_dict_settings_title" msgid="1415462066249818756">"വ്യക്തിഗത നിഘണ്ടു"</string>
+    <string name="user_dict_settings_title" msgid="1415462066249818756">"വ്യക്തിപരമായ നിഘണ്ടു"</string>
     <string name="user_dict_settings_for_work_title" msgid="3995828731001225748">"ജോലിക്കായുള്ള വ്യക്തിഗത നിഘണ്ഡു"</string>
     <string name="user_dict_settings_summary" msgid="3131259534814181196"></string>
     <string name="user_dict_settings_add_menu_title" msgid="1553743292556229909">"ചേര്‍ക്കുക"</string>
@@ -2031,8 +2036,8 @@
     <string name="usage_time_label" msgid="5615725415876461039">"ഉപയോഗ സമയം"</string>
     <string name="accessibility_settings" msgid="9140621093888234485">"ഉപയോഗസഹായി"</string>
     <string name="accessibility_settings_title" msgid="1687226556576913576">"ഉപയോഗസഹായി ക്രമീകരണങ്ങൾ"</string>
-    <string name="accessibility_settings_summary" msgid="5742379519336396561">"സ്‌ക്രീൻ റീഡറുകൾ, ‌ഡിസ്‌പ്ലേ, ഇന്‍ററാക്ഷൻ നിയന്ത്രണങ്ങൾ"</string>
-    <string name="vision_settings_title" msgid="7315352351051423944">"വീക്ഷണ ക്രമീകരണം"</string>
+    <string name="accessibility_settings_summary" msgid="5742379519336396561">"സ്‌ക്രീൻ റീഡറുകൾ, ‌ഡിസ്‌പ്ലേ, ഇടപെടൽ നിയന്ത്രണങ്ങൾ"</string>
+    <string name="vision_settings_title" msgid="7315352351051423944">"കാഴ്‍ചാ ക്രമീകരണം"</string>
     <string name="vision_settings_description" msgid="3476589459009287332">"ആവശ്യങ്ങൾക്ക് അനുസരിച്ച് നിങ്ങൾക്ക് ഈ ഉപകരണം ഇഷ്ടാനുസൃതമാക്കാം. ഈ ഉപയോഗസഹായി ഫീച്ചറുകൾ പിന്നീട് ക്രമീകരണത്തിൽ മാറ്റാവുന്നതാണ്."</string>
     <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"ഫോണ്ട് വലുപ്പം മാറ്റുക"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"സ്‌ക്രീൻ റീഡറുകൾ"</string>
@@ -2304,7 +2309,7 @@
       <item quantity="other">%1$d ആപ്പുകളെ നിയന്ത്രിക്കണോ?</item>
       <item quantity="one">ആപ്പിനെ നിയന്ത്രിക്കണോ?</item>
     </plurals>
-    <string name="battery_tip_restrict_app_dialog_message" msgid="6905822297507947381">"ബാറ്ററി ലാഭിക്കാൻ, പശ്ചാത്തലത്തിൽ <xliff:g id="APP">%1$s</xliff:g>-ന്റെ ബാറ്ററി ഉപഭോഗം നിർത്തുക. ഈ ആപ്പ് ശരിയായ രീതിയിൽ പ്രവർത്തിക്കാതിരിക്കുകയും അറിയിപ്പുകൾ വൈകുകയും ചെയ്‌തേക്കാം."</string>
+    <string name="battery_tip_restrict_app_dialog_message" msgid="6905822297507947381">"ബാറ്ററി ലാഭിക്കാൻ, <xliff:g id="APP">%1$s</xliff:g> എന്നതിനെ പശ്ചാത്തലത്തിൽ ബാറ്ററി ഉപഭോഗിക്കുന്നതിൽ നിന്നും തടയുക. ഈ ആപ്പ് ശരിയായ രീതിയിൽ പ്രവർത്തിക്കാതിരിക്കുകയും അറിയിപ്പുകൾ വൈകുകയും ചെയ്‌തേക്കാം."</string>
     <string name="battery_tip_restrict_apps_less_than_5_dialog_message" msgid="4225881888543582456">"ബാറ്ററി ലാഭിക്കാൻ, പശ്ചാത്തലത്തിൽ ഈ ആപ്പുകളുടെ ബാറ്ററി ഉപഭോഗം നിർത്തുക. നിയന്ത്രിത ആപ്പുകൾ ശരിയായ രീതിയിൽ പ്രവർത്തിക്കാതിരിക്കുകയും അറിയിപ്പുകൾ വൈകുകയും ചെയ്‌തേക്കാം.\n\nആപ്പുകൾ:"</string>
     <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"ബാറ്ററി ലാഭിക്കാൻ, പശ്ചാത്തലത്തിൽ ഈ ആപ്പുകളുടെ ബാറ്ററി ഉപഭോഗം നിർത്തുക. നിയന്ത്രിത ആപ്പുകൾ ശരിയായ രീതിയിൽ പ്രവർത്തിക്കാതിരിക്കുകയും അറിയിപ്പുകൾ വൈകുകയും ചെയ്‌തേക്കാം.\n\nആപ്പുകൾ:\n<xliff:g id="APP_LIST">%1$s</xliff:g>."</string>
     <string name="battery_tip_restrict_app_dialog_ok" msgid="2573410775701913487">"നിയന്ത്രിക്കുക"</string>
@@ -2450,7 +2455,7 @@
     <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"<xliff:g id="PERCENT">%1$s</xliff:g>-ത്തിൽ ഇത് ഓണാകും"</string>
     <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"ഷെഡ്യൂള്‍‌ സജ്ജീകരിക്കൂ"</string>
     <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"മുഴുവൻ ചാർജായാൽ ഓഫാക്കുക"</string>
-    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"നിങ്ങളുടെ ഫോൺ <xliff:g id="PERCENT">%1$s</xliff:g> എത്തുമ്പോൾ ബാറ്ററി ലാഭിക്കൽ ഓഫാവും"</string>
+    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"നിങ്ങളുടെ ഫോൺ <xliff:g id="PERCENT">%1$s</xliff:g>-ത്തിൽ എത്തുമ്പോൾ ബാറ്ററി ലാഭിക്കൽ ഓഫാകും"</string>
     <string name="battery_saver_sticky_description_new" product="tablet" msgid="3284967694001857194">"നിങ്ങളുടെ ടാബ്‌ലെറ്റ് <xliff:g id="PERCENT">%1$s</xliff:g> എത്തുമ്പോൾ ബാറ്ററി ലാഭിക്കൽ ഓഫാവും"</string>
     <string name="battery_saver_sticky_description_new" product="device" msgid="5056520668081504111">"നിങ്ങളുടെ ഉപകരണം <xliff:g id="PERCENT">%1$s</xliff:g> എത്തുമ്പോൾ ബാറ്ററി ലാഭിക്കൽ ഓഫാവും"</string>
     <!-- no translation found for battery_saver_seekbar_title (7607123201469333645) -->
@@ -2486,7 +2491,7 @@
     <string name="menu_duration_6h" msgid="6169009210638008417">"6 മണിക്കൂർ"</string>
     <string name="menu_duration_12h" msgid="1435242738163843797">"12 മണിക്കൂർ"</string>
     <string name="menu_duration_1d" msgid="6476370834372352174">"ഒരു ദിവസം"</string>
-    <string name="menu_show_system" msgid="6315865548558708248">"സിസ്റ്റം ദൃശ്യമാക്കുക"</string>
+    <string name="menu_show_system" msgid="6315865548558708248">"സിസ്റ്റം കാണിക്കുക"</string>
     <string name="menu_hide_system" msgid="8457027118873733782">"സിസ്റ്റം മറയ്‌ക്കുക"</string>
     <string name="menu_show_percentage" msgid="6983272380729890884">"ശതമാനങ്ങൾ കാണിക്കുക"</string>
     <string name="menu_use_uss" msgid="3765054705208926803">"Uss ഉപയോഗിക്കുക"</string>
@@ -2524,7 +2529,7 @@
     <string name="credentials_install_summary" product="default" msgid="4943897416156671633">"SD കാർഡിൽ നിന്ന് സർട്ടിഫിക്കറ്റുകൾ ഇൻസ്റ്റാൾ ചെയ്യുക"</string>
     <string name="credentials_reset" msgid="355080737664731678">"ക്രെഡൻഷ്യലുകൾ മായ്ക്കുക"</string>
     <string name="credentials_reset_summary" msgid="7622528359699428555">"എല്ലാം നീക്കംചെയ്യുക"</string>
-    <string name="trusted_credentials" msgid="6989242522455395200">"വിശ്വസ്‍ത ക്രെഡൻഷ്യൽ"</string>
+    <string name="trusted_credentials" msgid="6989242522455395200">"വിശ്വസ്‍ത ക്രെഡൻഷ്യലുകൾ"</string>
     <string name="trusted_credentials_summary" msgid="7411781319056251582">"വിശ്വസ്‌ത CA സർട്ടിഫിക്കറ്റുകൾ പ്രദർശിപ്പിക്കുക"</string>
     <string name="user_credentials" msgid="8365731467650306757">"ഉപയോക്തൃ ക്രെഡന്‍ഷ്യലുകൾ"</string>
     <string name="user_credentials_summary" msgid="7350223899317423252">"സംഭരിച്ച ക്രെഡന്‍ഷ്യലുകൾ കാണുക, പരിഷ്ക്കരിക്കുക"</string>
@@ -2561,7 +2566,7 @@
     <string name="fullbackup_data_summary" msgid="406274198094268556">"ഉപകരണ വിവരവും (വൈഫൈ പാസ്‌വേഡുകളും കോൾ ചരിത്രവും പോലുള്ളവ) ആപ്പ് വിവരവും (ക്രമീകരണവും ആപ്പുകൾ സംഭരിച്ച ഫയലുകളും പോലുള്ളവ) വിദൂരമായി സ്വയമേവ ബാക്കപ്പെടുക്കുന്നു.\n\nനിങ്ങൾ സ്വയമേയുള്ള ബാക്കപ്പ് ഓണാക്കുമ്പോൾ, ഉപകരണ, ആപ്പ് വിവരം ഇടയ്‌ക്കിടെ വിദൂരമായി സംരക്ഷിക്കും. ആപ്പ് വിവരം എന്നത് കോൺടാക്റ്റുകൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ എന്നിവ പോലുള്ള രഹസ്യസ്വഭാവമുള്ളവ ഉൾപ്പെടെ ആപ്പ് സംരക്ഷിച്ചിട്ടുള്ള ഏതൊരു വിവരവും (ഡെവലപ്പർ ക്രമീകരണം അടിസ്ഥാനമാക്കി) ആകാം."</string>
     <string name="device_admin_settings_title" msgid="2074319456047334589">"ഉപകരണ അഡ്‌മിൻ ക്രമീകരണം"</string>
     <string name="active_device_admin_msg" msgid="6929247869516924549">"ഉപകരണ അഡ്‌മിൻ ആപ്പ്"</string>
-    <string name="remove_device_admin" msgid="4413438593788336400">"ഈ ഉപകരണ അഡ്‌മിൻ ആപ്പ് നിർജീവമാക്കുക"</string>
+    <string name="remove_device_admin" msgid="4413438593788336400">"ഈ ഉപകരണ അഡ്‌മിൻ ആപ്പ് നിഷ്ക്രിയമാക്കുക"</string>
     <string name="uninstall_device_admin" msgid="9017499299961719830">"ആപ്പ് അൺഇൻസ്റ്റാളുചെയ്യുക"</string>
     <string name="remove_and_uninstall_device_admin" msgid="5607703579731496253">"നിർജീവമാക്കി അൺഇൻസ്‌റ്റാൾ ചെയ്യുക"</string>
     <string name="select_device_admin_msg" msgid="4173769638399075387">"ഉപകരണ അഡ്‌മിൻ ആപ്പുകൾ"</string>
@@ -2665,7 +2670,7 @@
     <string name="data_usage_menu_sim_cards" msgid="8508154611676507088">"സിം കാർഡുകൾ"</string>
     <string name="data_usage_cellular_data_summary" msgid="9162777397135709280">"പരിധിയിൽ തൽക്കാലം നിർത്തി"</string>
     <string name="account_settings_menu_auto_sync" msgid="2673669556006027506">"ഡാറ്റ സ്വയമേ സമന്വയിപ്പിക്കൂ"</string>
-    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"വ്യക്തിഗത ഡാറ്റ സ്വയമേവ സമന്വയിപ്പിക്കുക"</string>
+    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"വ്യക്തിപരമായ ഡാറ്റ സ്വയമേവ സമന്വയിപ്പിക്കുക"</string>
     <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"ഔദ്യോഗിക ഡാറ്റ സ്വയമേവ സമന്വയിപ്പിക്കുക"</string>
     <string name="data_usage_change_cycle" msgid="447761920472170031">"സൈക്കിൾ മാറ്റുക..."</string>
     <string name="data_usage_pick_cycle_day" msgid="6319750879145917066">"ഡാറ്റ ഉപയോഗ സൈക്കിൾ പുനഃസജ്ജീകരിക്കുന്നതിനുള്ള മാസത്തിലെ ദിവസം:"</string>
@@ -2729,7 +2734,7 @@
     <string name="data_usage_metered_wifi" msgid="2955256408132426720">"മീറ്റർ-മാപക വൈഫൈ നെറ്റ്‌വർക്ക്"</string>
     <string name="data_usage_metered_wifi_disabled" msgid="5771083253782103415">"മീറ്റർ-മാപക നെറ്റ്‌വർക്കുകൾ തിരഞ്ഞെടുക്കാൻ വൈഫൈ ഓണാക്കുക."</string>
     <string name="data_usage_metered_auto" msgid="7924116401382629319">"സ്വയമേവ"</string>
-    <string name="data_usage_metered_yes" msgid="7333744880035386073">"മീറ്റർചെയ്ത"</string>
+    <string name="data_usage_metered_yes" msgid="7333744880035386073">"മീറ്റർ ചെയ്തത്"</string>
     <string name="data_usage_metered_no" msgid="1961524615778610008">"മീറ്റർമാപകം"</string>
     <string name="data_usage_disclaimer" msgid="4683321532922590425">"കാരിയർ ഡാറ്റ കണക്കാക്കുന്നത് ഉപകരണത്തിൽ നിന്നും വ്യത്യാസപ്പെട്ടിരിക്കാം."</string>
     <string name="cryptkeeper_emergency_call" msgid="4625420047524693116">"അടിയന്തര കോൾ"</string>
@@ -2931,7 +2936,7 @@
     <string name="restriction_menu_change_pin" msgid="592512748243421101">"പിൻ മാറ്റുക"</string>
     <string name="app_notifications_switch_label" msgid="670683308275498821">"അറിയിപ്പുകൾ ദൃശ്യമാക്കുക"</string>
     <string name="help_label" msgid="1296484776243905646">"സഹായവും ഫീഡ്‌ബാക്കും"</string>
-    <string name="support_summary" msgid="3278943815956130740">"സഹായ ലേഖനങ്ങൾ, ഫോൺ, ചാറ്റ് എന്നിവ ആരംഭിക്കുക"</string>
+    <string name="support_summary" msgid="3278943815956130740">"സഹായ ലേഖനങ്ങൾ, ഫോൺ, ചാറ്റ്, ആരംഭിക്കൽ"</string>
     <string name="user_account_title" msgid="2108666882630552859">"ഉള്ളടക്കത്തിനുള്ള അക്കൗണ്ട്"</string>
     <string name="user_picture_title" msgid="6664602422948159123">"ഫോട്ടോ ഐഡി"</string>
     <string name="extreme_threats_title" msgid="1405820547540456436">"അതീവ ഗുരുതരമായ ഭീഷണികൾ"</string>
@@ -3089,7 +3094,7 @@
     <string name="keywords_lockscreen" msgid="4936846554280830394">"അൺലോക്കുചെയ്യാൻ സ്ലൈഡുചെയ്യുക, പാസ്‌വേഡ്, പാറ്റേൺ, പിൻ"</string>
     <string name="keywords_profile_challenge" msgid="8653718001253979611">"ഔദ്യോഗിക വെല്ലുവിളി, ഔദ്യോഗികം, പ്രൊഫൈൽ"</string>
     <string name="keywords_unification" msgid="2020759909366983593">"ഔദ്യോഗിക പ്രൊഫൈൽ, മാനേജുചെയ്യപ്പെടുന്ന പ്രൊഫൈൽ, ഏകീകരിക്കുക, ഏകീകരിക്കൽ, ഔദ്യോഗികം, പ്രൊഫൈൽ"</string>
-    <string name="keywords_gesture" msgid="5031323247529869644">"ജെസ്‌റ്ററുകൾ"</string>
+    <string name="keywords_gesture" msgid="5031323247529869644">"ജെസ്‌ചറുകൾ"</string>
     <string name="keywords_payment_settings" msgid="4745023716567666052">"പണമടയ്ക്കുക. ടാപ്പുചെയ്യുക, പേയ്‌മെന്റുകൾ"</string>
     <string name="keywords_backup" msgid="7433356270034921627">"ബാക്കപ്പ് ചെയ്യൂ"</string>
     <string name="keywords_assist_gesture_launch" msgid="2711433664837843513">"വിരൽചലനം"</string>
@@ -3100,7 +3105,7 @@
     <string name="keywords_android_version" msgid="4842749998088987740">"android സുരക്ഷാ പാച്ച് നില, ബേസ്‌ബാൻഡ് പതിപ്പ്, കെർണൽ പതിപ്പ്"</string>
     <string name="keywords_dark_ui_mode" msgid="1027966176887770318">"തീം, പ്രകാശം, ഇരുണ്ട മോഡ്"</string>
     <string name="keywords_financial_apps_sms_access" msgid="3236014691838121857">"സാമ്പത്തിക ആപ്പ്, SMS, അനുമതി"</string>
-    <string name="keywords_systemui_theme" msgid="9150908170417305866">"ഇരുണ്ട തീം"</string>
+    <string name="keywords_systemui_theme" msgid="9150908170417305866">"ഡാർക്ക് തീം"</string>
     <string name="keywords_device_feedback" msgid="6948977907405738490">"ബഗ്"</string>
     <string name="keywords_ambient_display_screen" msgid="5873935693887583428">"പാതിമയക്ക ഡിസ്‌പ്ലേ, ലോക്ക് സ്‌ക്രീൻ ഡിസ്‌പ്ലേ"</string>
     <string name="keywords_lock_screen_notif" msgid="4914337222856805463">"ലോക്ക് സ്‌ക്രീൻ അറിയിപ്പ്, അറിയിപ്പുകൾ"</string>
@@ -3212,7 +3217,7 @@
     <string name="zen_mode_block_effect_peek" msgid="6075662813575910221">"സ്‌ക്രീനിൽ അറിയിപ്പുകൾ പോപ്പ് ചെയ്യരുത്"</string>
     <string name="zen_mode_block_effect_status" msgid="6516614225115681068">"സ്‌ക്രീനിന്റെ മുകളിലുള്ള സ്‌റ്റാറ്റസ് ബാർ ഐക്കണുകൾ അദൃശ്യമാക്കുക"</string>
     <string name="zen_mode_block_effect_badge" msgid="3891743027347075136">"ആപ്പ് ഐക്കണുകളിൽ അറിയിപ്പ് ഡോട്ടുകൾ അദൃശ്യമാക്കുക"</string>
-    <string name="zen_mode_block_effect_ambient" msgid="6382013125863616197">"അറിയിപ്പുകൾക്കായി സജീവമാക്കരുത്"</string>
+    <string name="zen_mode_block_effect_ambient" msgid="6382013125863616197">"അറിയിപ്പുകൾ വരുമ്പോൾ സജീവമാക്കരുത്"</string>
     <string name="zen_mode_block_effect_list" msgid="6081548478844912181">"അറിയിപ്പ് ലിസ്‌റ്റിൽ നിന്നും അദൃശ്യമാക്കുക"</string>
     <string name="zen_mode_block_effect_summary_none" msgid="7166175186759564510">"ഒരിക്കലും വേണ്ട"</string>
     <string name="zen_mode_block_effect_summary_screen_off" msgid="2985086455557755722">"സ്ക്രീൻ ഓഫായിരിക്കുമ്പോൾ"</string>
@@ -3291,7 +3296,7 @@
     <string name="other_sound_category_preference_title" msgid="2045757472469840859">"മറ്റ് ശബ്ദങ്ങളും വൈബ്രേഷനുകളും"</string>
     <string name="configure_notification_settings" msgid="291914315140851270">"അറിയിപ്പുകൾ"</string>
     <string name="recent_notifications" msgid="8125865995065032049">"അടുത്തിടെ അയച്ചവ"</string>
-    <string name="recent_notifications_see_all_title" msgid="4089007770442871469">"അവസാന 7 ദിവസങ്ങളിൽ നിന്ന് എല്ലാം കാണുക"</string>
+    <string name="recent_notifications_see_all_title" msgid="4089007770442871469">"കഴിഞ്ഞ 7 ദിവസത്തെ എല്ലാം കാണുക"</string>
     <string name="advanced_section_header" msgid="984680389373090015">"വിപുലമായത്"</string>
     <string name="profile_section_header" msgid="5471479005472037417">"ഔദ്യോഗിക അറിയിപ്പുകൾ"</string>
     <string name="asst_capability_prioritizer_title" msgid="3488284760645922160">"സ്വയമേവയുള്ള അറിയിപ്പ് മുൻഗണന നൽകൽ"</string>
@@ -3316,7 +3321,7 @@
     <string name="notification_pulse_title" msgid="4861418327614907116">"ലൈറ്റ് മിന്നുക"</string>
     <string name="lock_screen_notifications_title" msgid="6889072265118747835">"ലോക്ക് സ്‌ക്രീനിൽ"</string>
     <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"ഔദ്യോഗിക പ്രൊഫൈൽ ലോക്ക് ചെയ്‌തിരിക്കുമ്പോൾ"</string>
-    <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"അറിയിപ്പുകളിലെ ഉള്ളടക്കം പൂർണമായി കാണിക്കുക"</string>
+    <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"എല്ലാ അറിയിപ്പുകളും ഉള്ളടക്കം സഹിതം കാണിക്കുക"</string>
     <string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"രഹസ്യാത്മകമായ ഉള്ളടക്കം അദൃശ്യമാക്കുക"</string>
     <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"ഒരു അറിയിപ്പും കാണിക്കരുത്"</string>
     <string name="lock_screen_notifications_interstitial_message" msgid="4230189215124387818">"നിങ്ങളുടെ ഉപകരണം ലോക്ക് ചെയ്തിരിക്കുമ്പോൾ, അറിയിപ്പുകൾ എങ്ങനെയാണ് കാണിക്കേണ്ടത്?"</string>
@@ -3463,7 +3468,7 @@
     <string name="zen_mode_schedule_rule_days" msgid="220627703673691816">"ദിവസം"</string>
     <string name="zen_mode_schedule_rule_days_none" msgid="6011716195119389956">"ഒന്നുമില്ല"</string>
     <string name="zen_mode_schedule_rule_days_all" msgid="8814173364016139675">"എല്ലാ ദിവസവും"</string>
-    <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"അലാറമിന് അവസാനിക്കുന്ന സമയം അസാധുവാക്കാൻ കഴിയും"</string>
+    <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"അലാറത്തിന് അവസാനിക്കുന്ന സമയം അസാധുവാക്കാൻ കഴിയും"</string>
     <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"ഒരു അലാറം റിംഗ് ചെയ്യുമ്പോൾ, ഷെഡ്യൂൾ ഓഫാകുന്നു"</string>
     <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"\'ശല്യപ്പെടുത്തരുത്\' എന്ന് അർത്ഥമാക്കുന്ന പെരുമാറ്റം"</string>
     <string name="zen_mode_custom_behavior_summary_default" msgid="3509865340195397447">"ഡിഫോൾട്ട് ക്രമീകരണം ഉപയോഗിക്കുക"</string>
@@ -3584,7 +3589,7 @@
     <string name="imei_information_summary" msgid="716516316022275083">"IMEI അനുബന്ധ വിവരങ്ങൾ"</string>
     <string name="slot_number" msgid="785422579177068698">"(സ്ലോട്ട്<xliff:g id="SLOT_NUM">%1$d</xliff:g>)"</string>
     <string name="launch_by_default" msgid="6106985160202769725">"സ്ഥിരമായി തുറക്കുക"</string>
-    <string name="app_launch_domain_links_title" msgid="2987289657348349133">"ലിങ്കുകൾ തുറക്കുന്നു"</string>
+    <string name="app_launch_domain_links_title" msgid="2987289657348349133">"ലിങ്കുകൾ തുറക്കൽ"</string>
     <string name="app_launch_open_domain_urls_title" msgid="8595126859922391331">"പിന്തുണയ്‌ക്കുന്ന ലിങ്കുകൾ തുറക്കുക"</string>
     <string name="app_launch_open_domain_urls_summary" msgid="6803029846855502366">"ആവശ്യപ്പെടാതെ തുറക്കുക"</string>
     <string name="app_launch_supported_domain_urls_title" msgid="503976327533974142">"പിന്തുണയ്‌ക്കുന്ന ലിങ്കുകൾ"</string>
@@ -3644,7 +3649,7 @@
     <string name="app_permissions_summary" msgid="8785798165776061594">"<xliff:g id="APPS">%1$s</xliff:g> ഉപയോഗിക്കുന്ന ആപ്പുകൾ"</string>
     <string name="tap_to_wake" msgid="1902991239401652323">"സജീവമാക്കാൻ ടാപ്പുചെയ്യുക"</string>
     <string name="tap_to_wake_summary" msgid="8485222120721006793">"ഉപകരണം സജീവമാക്കാൻ സ്‌ക്രീനിലെവിടെയെങ്കിലും രണ്ടുതവണ ടാപ്പുചെയ്യുക"</string>
-    <string name="domain_urls_title" msgid="7939209950373945367">"ലിങ്കുകൾ തുറക്കുന്നു"</string>
+    <string name="domain_urls_title" msgid="7939209950373945367">"ലിങ്കുകൾ തുറക്കൽ"</string>
     <string name="domain_urls_summary_none" msgid="5401203416941265109">"പിന്തുണയ്‌ക്കുന്ന ലിങ്കുകൾ തുറക്കരുത്"</string>
     <string name="domain_urls_summary_one" msgid="3893975485064803435">"<xliff:g id="DOMAIN">%s</xliff:g> തുറക്കുക"</string>
     <string name="domain_urls_summary_some" msgid="2130534984153210797">"<xliff:g id="DOMAIN">%s</xliff:g> ഡൊമെയ്‌നും മറ്റ് URL-കളും തുറക്കുക"</string>
@@ -3707,10 +3712,10 @@
     <string name="high_power_system" msgid="739584574711292753">"ബാറ്ററി ഓപ്റ്റിമൈസേഷൻ ലഭ്യമല്ല"</string>
     <string name="high_power_desc" msgid="333756885680362741">"ബാറ്ററി ഒപ്റ്റിമൈസേഷൻ പ്രയോഗിക്കരുത്. ഇത് ബാറ്ററിയെ വേഗത്തിൽ തീർത്തേക്കാം."</string>
     <string name="high_power_prompt_title" msgid="2805745781720454052">"ആപ്പിനെ എല്ലായ്‌പ്പോഴും പശ്ചാത്തലത്തിൽ റൺ ചെയ്യാൻ അനുവദിക്കണോ?"</string>
-    <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g> ആപ്പിനെ എല്ലായ്‌പ്പോഴും പശ്ചാത്തലത്തിൽ റൺ ചെയ്യാൻ അനുവദിക്കുന്നത് ബാറ്ററി ലൈഫ് കുറയ്‌ക്കാനിടയാക്കും. \n\nനിങ്ങൾക്ക്, ക്രമീകരണം &gt; ആപ്പുകളും അറിയിപ്പുകളും എന്നതിൽ നിന്ന് ‌പിന്നീട് ഇത് മാറ്റാവുന്നതാണ്."</string>
+    <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g> ആപ്പിനെ എല്ലായ്‌പ്പോഴും പശ്ചാത്തലത്തിൽ റൺ ചെയ്യാൻ അനുവദിക്കുന്നത് ബാറ്ററി ലൈഫ് കുറയ്‌ക്കാനിടയാക്കും. \n\nനിങ്ങൾക്ക്, ക്രമീകരണം &gt; ആപ്പുകളും അറിയിപ്പുകളും എന്നതിൽ പിന്നീട് ഇത് മാറ്റാവുന്നതാണ്."</string>
     <string name="battery_summary" msgid="4345690800899981339">"അവസാനം പൂർണ്ണമായി ചാർജ് ആയതിനുശേഷം <xliff:g id="PERCENTAGE">%1$s</xliff:g> ഉപയോഗം"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"ഊർജ്ജ ഉപഭോഗ നിയന്ത്രണം"</string>
-    <string name="no_battery_summary" msgid="4105932628367471314">"അവസാനമായി പൂർണ്ണ ചാർജ് ആയതിനുശേഷം ബാറ്ററി ഉപയോഗമില്ല"</string>
+    <string name="no_battery_summary" msgid="4105932628367471314">"അവസാനമായി ഫുൾ ചാർജ് ചെയ്തത് മുതൽ ബാറ്ററി ഉപയോഗമൊന്നുമില്ല"</string>
     <string name="app_notification_preferences" msgid="5154466638524523201">"ആപ്പ് ക്രമീകരണം"</string>
     <string name="system_ui_settings" msgid="6751165163665775447">"SystemUI ട്യൂണർ കാണിക്കുക"</string>
     <string name="additional_permissions" msgid="3142290772324571654">"അധിക അനുമതികൾ"</string>
@@ -3798,7 +3803,7 @@
     <string name="system_alert_window_settings" msgid="3024330223417646567">"മറ്റ് ആപ്പുകൾക്ക് മുകളിൽ പ്രദർശിപ്പിക്കുക"</string>
     <string name="system_alert_window_apps_title" msgid="9188448296493699566">"ആപ്സ്"</string>
     <string name="system_alert_window_access_title" msgid="5187343732185369675">"മറ്റ് ആപ്പുകൾക്ക് മുകളിൽ പ്രദർശിപ്പിക്കുക"</string>
-    <string name="permit_draw_overlay" msgid="9039092257052422344">"മറ്റ് ആപ്‌സിന് മുകളിൽ പ്രദർശിക്കുന്നത് അനുവദിക്കുക"</string>
+    <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>
@@ -3959,7 +3964,7 @@
     <string name="configure" msgid="8232696842838580549">"കോൺഫിഗർ ചെയ്യുക"</string>
     <string name="data_usage_other_apps" msgid="7002491980141402084">"ഉപയോഗത്തിൽ ഉൾപ്പെട്ട മറ്റ് ആപ്‌സ്"</string>
     <plurals name="data_saver_unrestricted_summary" formatted="false" msgid="6046013861315713697">
-      <item quantity="other">ഡാറ്റ സേവർ ഓണായിരിക്കുമ്പോൾ, പരിധിയില്ലാതെ ഡാറ്റ ഉപയോഗിക്കുന്നതിന് <xliff:g id="COUNT">%1$d</xliff:g> ആപ്‌സിനെ അനുവദിച്ചു</item>
+      <item quantity="other">ഡാറ്റ സേവർ ഓണായിരിക്കുമ്പോൾ, പരിധിയില്ലാതെ ഡാറ്റ ഉപയോഗിക്കുന്നതിന് <xliff:g id="COUNT">%1$d</xliff:g> ആപ്പുകളെ അനുവദിച്ചു</item>
       <item quantity="one">ഡാറ്റ സേവർ ഓണായിരിക്കുമ്പോൾ, പരിധിയില്ലാതെ ഡാറ്റ ഉപയോഗിക്കുന്നതിന് ഒരു ആപ്പിനെ അനുവദിച്ചു</item>
     </plurals>
     <string name="data_usage_title" msgid="7874606430902201083">"പ്രാഥമിക ഡാറ്റ"</string>
@@ -3997,7 +4002,7 @@
     <string name="suggestion_additional_fingerprints" msgid="3434467207282466411">"മറ്റൊരു ഫിംഗർപ്രിന്റ് ചേർക്കുക"</string>
     <string name="suggestion_additional_fingerprints_summary" msgid="1916547587832484196">"മറ്റൊരു വിരൽ ഉപയോഗിച്ച് അൺലോക്കുചെയ്യുക"</string>
     <string name="battery_saver_on_summary" msgid="6841062406467435672">"ഓണാണ്"</string>
-    <string name="battery_saver_off_scheduled_summary" msgid="3740414764069188669">"<xliff:g id="BATTERY_PERCENTAGE">%1$s</xliff:g>-ത്തിൽ ഇത് ഓണാക്കും"</string>
+    <string name="battery_saver_off_scheduled_summary" msgid="3740414764069188669">"<xliff:g id="BATTERY_PERCENTAGE">%1$s</xliff:g>-ത്തിൽ ഇത് ഓണാകും"</string>
     <string name="battery_saver_off_summary" msgid="8736555723004299721">"ഓഫാണ്"</string>
     <string name="battery_saver_button_turn_on" msgid="3748696527267573793">"ഇപ്പോൾ ഓണാക്കുക"</string>
     <string name="battery_saver_button_turn_off" msgid="2912950982503267828">"ഇപ്പോൾ ഓഫാക്കുക"</string>
@@ -4047,7 +4052,7 @@
     <string name="display_cutout_emulation_keywords" msgid="6795671536772871439">"ഡിസ്പ്ലേ കട്ടൗട്ട്, നോച്ച്"</string>
     <string name="overlay_option_device_default" msgid="165508753381657697">"ഉപകരണ ഡിഫോള്‍ട്ട്"</string>
     <string name="overlay_toast_failed_to_apply" msgid="5692251825129250040">"ഓവർലേ പ്രയോഗിക്കുന്നതിൽ പരാജയപ്പെട്ടു"</string>
-    <string name="special_access" msgid="1453926335914696206">"പ്രത്യേക ആപ്പ് ആക്‌സസ്സ്"</string>
+    <string name="special_access" msgid="1453926335914696206">"പ്രത്യേക ആപ്പ് ആക്‌സസ്"</string>
     <plurals name="special_access_summary" formatted="false" msgid="5182092345063909346">
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ആപ്പുകൾക്ക് നിയന്ത്രണമില്ലാതെ ഡാറ്റ ഉപയോഗിക്കാം</item>
       <item quantity="one">1 ആപ്പിന് നിയന്ത്രണമില്ലാതെ ഡാറ്റ ഉപയോഗിക്കാം</item>
@@ -4102,7 +4107,7 @@
     <string name="deletion_helper_automatic_title" msgid="4370975149425263205">"സ്വയമേവ"</string>
     <string name="deletion_helper_manual_title" msgid="1011785013431162078">"മാനുവൽ"</string>
     <string name="deletion_helper_preference_title" msgid="797270307034242206">"ഇപ്പോൾ ഇടം സൃഷ്ടിക്കുക"</string>
-    <string name="gesture_preference_title" msgid="583646591518373785">"ജെസ്‌റ്ററുകൾ"</string>
+    <string name="gesture_preference_title" msgid="583646591518373785">"ജെസ്‌ചറുകൾ"</string>
     <string name="gesture_preference_summary" product="default" msgid="2990736567599191163">"നിങ്ങളുടെ ഫോൺ നിയന്ത്രിക്കുന്നതിനുള്ള ദ്രുത ജെസ്റ്ററുകൾ"</string>
     <string name="gesture_preference_summary" product="tablet" msgid="8303793594714075580">"നിങ്ങളുടെ ടാബ്‌ലെറ്റ് നിയന്ത്രിക്കുന്നതിനുള്ള അതിവേഗ ജെസ്റ്ററുകൾ"</string>
     <string name="gesture_preference_summary" product="device" msgid="7792199669106960922">"നിങ്ങളുടെ ഉപകരണം നിയന്ത്രിക്കുന്നതിനുള്ള അതിവേഗ ജെസ്റ്ററുകൾ"</string>
@@ -4119,7 +4124,7 @@
     <string name="ambient_display_title" product="tablet" msgid="1106285490888683613">"ടാബ്‌ലെറ്റ് പരിശോധിക്കുന്നതിന്, രണ്ടുതവണ ടാപ്പുചെയ്യുക"</string>
     <string name="ambient_display_title" product="device" msgid="5064644474876041478">"ഉപകരണം പരിശോധിക്കുന്നതിന്, രണ്ടുതവണ ടാപ്പുചെയ്യുക"</string>
     <string name="ambient_display_summary" msgid="4882910328216411109">"സമയവും അറിയിപ്പുകളും മറ്റ് വിവരങ്ങളും പരിശോധിക്കുന്നതിന്, നിങ്ങളുടെ സ്ക്രീനിൽ രണ്ട് തവണ ടാപ്പ് ചെയ്യുക."</string>
-    <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"പരിശോധിക്കാൻ ഫോണുയർത്തുക"</string>
+    <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"പരിശോധിക്കാൻ ഫോണെടുക്കുക"</string>
     <string name="ambient_display_pickup_title" product="tablet" msgid="1555456400210301959">"പരിശോധിക്കുന്നതിന് ടാബ്‌ലെറ്റ് എടുത്തുയർത്തുക"</string>
     <string name="ambient_display_pickup_title" product="device" msgid="2480126522988135037">"പരിശോധിക്കുന്നതിന് ഉപകരണം എടുത്തുയർത്തുക"</string>
     <string name="ambient_display_wake_screen_title" msgid="3376988352851077102">"ഡിസ്‌പ്ലേ സജീവമാക്കുക"</string>
@@ -4150,7 +4155,7 @@
     <string name="instant_apps_settings" msgid="879003203555847537">"ഇൻസ്‌റ്റന്‍റ് ആപ്പ് മുൻഗണനകൾ"</string>
     <string name="domain_url_section_title" msgid="206403507921518321">"ഇൻസ്‌റ്റാൾ ചെയ്‍തിട്ടുള്ള ആപ്പുകൾ"</string>
     <string name="automatic_storage_manager_activation_warning" msgid="2630083316417707308">"നിങ്ങളുടെ സ്റ്റോറേജ് ഇപ്പോൾ മാനേജുചെയ്യുന്നത് സ്റ്റോറേജ് ​​മാനേജരാണ്"</string>
-    <string name="account_for_section_header" msgid="5975241715840642563">"<xliff:g id="USER_NAME">%1$s</xliff:g> എന്ന ഉപയോക്താവിന്റെ അക്കൗണ്ടുകൾ"</string>
+    <string name="account_for_section_header" msgid="5975241715840642563">"<xliff:g id="USER_NAME">%1$s</xliff:g> എന്നയാളുടെ അക്കൗണ്ടുകൾ"</string>
     <string name="configure_section_header" msgid="6988981883075615136">"ക്രമീകരിക്കുക"</string>
     <string name="auto_sync_account_title" msgid="2394463123733529506">"ഡാറ്റ സ്വയം സമന്വയിപ്പിക്കുക"</string>
     <string name="auto_sync_personal_account_title" msgid="6844465157916100655">"വ്യക്തിഗത ഡാറ്റ സ്വയം സമന്വയിപ്പിക്കുക"</string>
@@ -4234,7 +4239,7 @@
     <string name="storage_music_audio" msgid="3661289086715297149">"സംഗീതവും ഓഡിയോയും"</string>
     <string name="storage_games" msgid="7740038143749092373">"ഗെയിമുകള്‍"</string>
     <string name="storage_other_apps" msgid="3202407095387420842">"മറ്റ് ആപ്പുകൾ"</string>
-    <string name="storage_files" msgid="2087824267937487880">"ഫയലുകള്‍"</string>
+    <string name="storage_files" msgid="2087824267937487880">"Files"</string>
     <string name="storage_size_large_alternate" msgid="1317796542509105857">"<xliff:g id="NUMBER">^1</xliff:g>"<small>" "<font size="20">"<xliff:g id="UNIT">^2</xliff:g>"</font></small>""</string>
     <string name="storage_volume_total" msgid="5021484171514159913">"<xliff:g id="TOTAL">%1$s</xliff:g> ഉപയോഗിച്ചു"</string>
     <string name="storage_percent_full" msgid="6924662861545958442">"ഉപയോഗിച്ചു"</string>
@@ -4305,8 +4310,8 @@
     <string name="change_wifi_state_title" msgid="5140754955787584174">"വൈഫൈ നിയന്ത്രണം"</string>
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"വൈഫൈയെ നിയന്ത്രിക്കാൻ ആപ്പിനെ അനുവദിക്കുക"</string>
     <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"വൈഫൈ ഓണോ ഓഫോ ആക്കാനോ വൈഫൈ നെറ്റ്‌വർക്കുകൾ സ്കാൻ ചെയ്യാനോ അവയിലേക്ക് കണക്‌റ്റ് ചെയ്യാനോ നെറ്റ്‌വർക്കുകൾ ചേർക്കാനോ നീക്കം ചെയ്യാനോ ഉപകരണം ഉള്ളിടത്ത് മാത്രം പ്രവർത്തിക്കുന്ന ഒരു ഹോട്ട്‌സ്പോട്ട് ആരംഭിക്കാനോ ഈ ആപ്പിനെ അനുവദിക്കുക"</string>
-    <string name="media_output_title" msgid="8710632337456601848">"ഇതിലേക്ക് മീഡിയ പ്ലേ ചെയ്യുക"</string>
-    <string name="media_output_default_summary" msgid="3159237976830415584">"ഈ ഉപകരണം"</string>
+    <string name="media_output_title" msgid="8710632337456601848">"മീഡിയ പ്ലേ ചെയ്യുക:"</string>
+    <string name="media_output_default_summary" msgid="3159237976830415584">"ഈ ഉപകരണത്തിൽ"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"ഫോൺ"</string>
     <string name="media_output_summary" product="tablet" msgid="6672024060360538526">"ടാബ്‌ലെറ്റ്"</string>
     <string name="media_output_summary" product="device" msgid="5132223072593052660">"ഉപകരണം"</string>
@@ -4318,9 +4323,9 @@
     <string name="battery_suggestion_title" product="device" msgid="765005476863631528">"ഉപകരണത്തിന്റെ ബാറ്ററി ലൈഫ് മെച്ചപ്പെടുത്തുക"</string>
     <string name="battery_suggestion_title" product="default" msgid="3295786171830183688">"ഫോണിന്റെ ബാറ്ററി ലൈഫ് മെച്ചപ്പെടുത്തുക"</string>
     <string name="battery_suggestion_summary" msgid="2669070349482656490"></string>
-    <string name="gesture_prevent_ringing_screen_title" msgid="4173494225145223638">"റിംഗിംഗ് തടയുക"</string>
+    <string name="gesture_prevent_ringing_screen_title" msgid="4173494225145223638">"റിംഗ് ചെയ്യുന്നത് തടയുക"</string>
     <string name="gesture_prevent_ringing_title" msgid="8827963588425673557">"പവറും ശബ്‌ദം കൂട്ടുന്ന ബട്ടണും ഒരുമിച്ച് ഇനിപ്പറയുന്നതിനായി, അമർത്തുക"</string>
-    <string name="gesture_prevent_ringing_sound_title" msgid="8642330448721033641">"റിംഗ് ചെയ്യുന്നത് തടയാൻ കുറുക്കുവഴി"</string>
+    <string name="gesture_prevent_ringing_sound_title" msgid="8642330448721033641">"റിംഗ് ചെയ്യുന്നത് തടയാനുള്ള കുറുക്കുവഴി"</string>
     <string name="prevent_ringing_option_vibrate" msgid="6456505293904544108">"വൈബ്രേറ്റ് ചെയ്യുക"</string>
     <string name="prevent_ringing_option_mute" msgid="53662688921253613">"മ്യൂട്ട് ചെയ്യുക"</string>
     <string name="prevent_ringing_option_none" msgid="1450985763137666231">"ഒന്നും ചെയ്യരുത്"</string>
diff --git a/tests/CarDeveloperOptions/res/values-mn/arrays.xml b/tests/CarDeveloperOptions/res/values-mn/arrays.xml
index 815dcbc..41cc6ae 100644
--- a/tests/CarDeveloperOptions/res/values-mn/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-mn/arrays.xml
@@ -85,7 +85,7 @@
     <item msgid="8058143476674427024">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> руу холбогдож байна…"</item>
     <item msgid="7547609081339573756">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>-тай гэрчилж байна…"</item>
     <item msgid="5145158315060185414">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>-с IP хаягийг авч байна…"</item>
-    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> руу холбогдсон"</item>
+    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>-д холбогдсон"</item>
     <item msgid="6600156231416890902">"Түр хаасан"</item>
     <item msgid="4133290864821295785">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>-с салгагдаж байна…"</item>
     <item msgid="3980154971187953257">"Салгагдсан"</item>
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"дэвсгэрт ажиллуулах"</item>
     <item msgid="6423861043647911030">"хүртээмжийн дууны түвшин"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Байршил"</item>
+    <item msgid="6656077694190491067">"Байршил"</item>
+    <item msgid="8790228218278477369">"Байршил"</item>
+    <item msgid="7836406246005211990">"Чичиргээ"</item>
+    <item msgid="3951439024549922598">"Харилцагчдыг унших"</item>
+    <item msgid="8802152411647068">"Харилцагчдыг өөрчлөх"</item>
+    <item msgid="229544934599698735">"Дуудлагын жагсаалтыг унших"</item>
+    <item msgid="7396102294405899613">"Дуудлагын жагсаалтыг өөрчлөх"</item>
+    <item msgid="3597797992398484655">"Хуанли унших"</item>
+    <item msgid="2705975774250907343">"Календарийг өөрчлөх"</item>
+    <item msgid="4668747371441932697">"Байршил"</item>
+    <item msgid="1487578921720243646">"Пост мэдэгдэл"</item>
+    <item msgid="4636080349724146638">"Байршил"</item>
+    <item msgid="673510900286463926">"Утас руу залгах"</item>
+    <item msgid="542083422784609790">"SMS/MMS унших"</item>
+    <item msgid="1033780373029588436">"SMS/MMS бичих"</item>
+    <item msgid="5647111115517787488">"SMS/MMS хүлээн авах"</item>
+    <item msgid="8591105601108455893">"SMS/MMS хүлээн авах"</item>
+    <item msgid="7730995008517841903">"SMS/MMS хүлээн авах"</item>
+    <item msgid="2613033109026626086">"SMS/MMS хүлээн авах"</item>
+    <item msgid="3037159047591081136">"SMS/MMS илгээх"</item>
+    <item msgid="4726682243833913568">"SMS/MMS унших"</item>
+    <item msgid="6555678522277865572">"SMS/MMS бичих"</item>
+    <item msgid="6981734935578130884">"Тохиргоог өөрчлөх"</item>
+    <item msgid="8705854389991425629">"Дээр нь нээх"</item>
+    <item msgid="5861356020344153651">"Хандалтын мэдэгдэл"</item>
+    <item msgid="78432174621628659">"Камер"</item>
+    <item msgid="3986116419882154794">"Аудио бичих"</item>
+    <item msgid="4516840825756409490">"Аудио тоглуулах"</item>
+    <item msgid="6811712502798183957">"Түр санах ойг унших"</item>
+    <item msgid="2780369012602289114">"Түр санах ойг өөрчлөх"</item>
+    <item msgid="2331359440170850868">"Медиа товч"</item>
+    <item msgid="6133599737122751231">"Аудио фокус"</item>
+    <item msgid="6844485713404805301">"Үндсэн дууны хэмжээ"</item>
+    <item msgid="1600379420669104929">"Хоолойн дууны хэмжээ"</item>
+    <item msgid="6296768210470214866">"Хонхны дууны түвшин"</item>
+    <item msgid="510690696071629241">"Медиа дууны түвшин"</item>
+    <item msgid="406861638631430109">"Сэрүүлгийн дууны түвшин"</item>
+    <item msgid="4715864795872233884">"Мэдэгдлийн дууны хэмжээ"</item>
+    <item msgid="2311478519251301183">"Блютүүтийн хэмжээ"</item>
+    <item msgid="5133991377896747027">"Сэрүүн байлгах"</item>
+    <item msgid="2464189519136248621">"Байршил"</item>
+    <item msgid="2062677934050803037">"Байршил"</item>
+    <item msgid="1735171933192715957">"Ашиглалтын статистик авах"</item>
+    <item msgid="1014093788778383554">"Микрофон хаах/нээх"</item>
+    <item msgid="4199297950608622850">"toast харуулах"</item>
+    <item msgid="2527962435313398821">"Төслийн медиа"</item>
+    <item msgid="5117506254221861929">"VPN идэвхжүүлэх"</item>
+    <item msgid="8291198322681891160">"Ханын зураг бичих"</item>
+    <item msgid="7106921284621230961">"Бүтцийг өөрчлөх"</item>
+    <item msgid="4496533640894624799">"Дэлгэцийн агшинг өөрчлөх"</item>
+    <item msgid="2598847264853993611">"Гар утасны төлөвийг унших"</item>
+    <item msgid="9215610846802973353">"Дуут шуудан нэмэх"</item>
+    <item msgid="9186411956086478261">"Sip-г ашиглах"</item>
+    <item msgid="6884763100104539558">"Залгах дуудлагыг боловсруулах"</item>
+    <item msgid="125513972170580692">"Хурууны хээ"</item>
+    <item msgid="2556071024281275619">"Биеийн мэдрэгч"</item>
+    <item msgid="617168514928339387">"Үүрэн нэвтрүүлгийг унших"</item>
+    <item msgid="7134693570516523585">"Хуурамч байршил"</item>
+    <item msgid="7224489175375229399">"Санах ойг унших"</item>
+    <item msgid="8472735063903258202">"Санах ойг бичих"</item>
+    <item msgid="4069276819909595110">"Дэлгэцийг асаах"</item>
+    <item msgid="1228338896751121025">"Бүртгэл авах"</item>
+    <item msgid="3181581793459233672">"Дэвсгэрт ажиллуулах"</item>
+    <item msgid="2340936043025374076">"Хүртээмжийн дууны түвшин"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Богино"</item>
     <item msgid="4816511817309094890">"Дунд"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Хэзээ ч зөвшөөрөхгүй"</item>
     <item msgid="8184570120217958741">"Байнга зөвшөөрөх"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Хэвийн"</item>
+    <item msgid="5101233285497327432">"Дундаж"</item>
+    <item msgid="1555861583162930714">"Бага"</item>
+    <item msgid="1719683776264798117">"Эгзэгтэй"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Хэвийн"</item>
+    <item msgid="6107138933849816768">"Дундаж"</item>
+    <item msgid="182695359839047859">"Бага"</item>
+    <item msgid="8577246509202964244">"Эгзэгтэй"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Тогтвортой"</item>
     <item msgid="167418068739176448">"Топ үйлдэл"</item>
@@ -377,7 +453,7 @@
     <item msgid="6248998242443333892">"Кеш хийгдсэн (хоосон)"</item>
   </string-array>
   <string-array name="color_picker">
-    <item msgid="3151827842194201728">"Усан цэнхэр"</item>
+    <item msgid="3151827842194201728">"Ногоон цэнхэр"</item>
     <item msgid="3228505970082457852">"Цэнхэр"</item>
     <item msgid="6590260735734795647">"Индиго"</item>
     <item msgid="3521763377357218577">"Ягаан"</item>
diff --git a/tests/CarDeveloperOptions/res/values-mn/config.xml b/tests/CarDeveloperOptions/res/values-mn/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-mn/config.xml
+++ b/tests/CarDeveloperOptions/res/values-mn/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-mn/strings.xml b/tests/CarDeveloperOptions/res/values-mn/strings.xml
index 6fa3996..9ba616e 100644
--- a/tests/CarDeveloperOptions/res/values-mn/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-mn/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Дэлгэц дээрх текстийг томруулах, жижигрүүлэх."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Жижигрүүлэх"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Томруулах"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Жишээ текст"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Озын Гайхамшигт шидтэн"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Бүлэг 11: Озын Гайхамшигт Маргад эрдэнийн хот"</string>
@@ -208,7 +207,7 @@
     <string name="proxy_error_empty_port" msgid="8034561724923076215">"Та порт талбарыг гүйцээх шаардлагатай."</string>
     <string name="proxy_error_empty_host_set_port" msgid="8471455809508588255">"Хостын талбар хоосон байгаа бол портын талбар хоосон байх шаардлагатай."</string>
     <string name="proxy_error_invalid_port" msgid="4046559920586100637">"Таны оруулсан порт буруу байна."</string>
-    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"HTTP проксиг хөтөч ашиглаж байгаа боловч бусад апп-ууд ашиглахгүй байж магадгүй."</string>
+    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"HTTP проксиг хөтөч ашиглаж байгаа боловч бусад апп ашиглахгүй байж магадгүй."</string>
     <string name="proxy_url_title" msgid="882042361706435904">"PAC URL: "</string>
     <string name="radio_info_dl_kbps" msgid="2903778264453410272">"DL Зурвасын өргөн (kbps):"</string>
     <string name="radio_info_ul_kbps" msgid="3802245899811732716">"UL Зурвасын өргөн (kbps):"</string>
@@ -668,7 +667,6 @@
       <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g>-с цөөн цифртэй байх ёстой</item>
       <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g>-с цөөн цифртэй байх ёстой</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Зөвхөн 0-9 хүртэлх цифр агуулах шаардлагатай"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Төхөөрөмжийн админ саяхны ПИН-г ашиглахыг зөвшөөрдөггүй"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Таны IT админ түгээмэл ПИН-г блоклосон байна. Өөр ПИН оруулна уу."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Үүнд хүчингүй тэмдэгт агуулах боломжгүй"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Хамгийн багадаа <xliff:g id="COUNT">%d</xliff:g> тэмдэгт агуулах шаардлагатай</item>
       <item quantity="one">Хамгийн багадаа 1 тэмдэгт агуулах шаардлагатай</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Хамгийн багадаа тоон бус <xliff:g id="COUNT">%d</xliff:g> тэмдэгт агуулах ёстой</item>
+      <item quantity="one">Хамгийн багадаа тоон бус 1 тэмдэгт агуулах ёстой</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Төхөөрөмжийн админ саяхны нууц үгийг ашиглахыг зөвшөөрдөггүй"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Таны IT админ түгээмэл нууц үгийг блоклосон байна. Өөр нууц үг оруулна уу."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Цифр өсөх, буурах, давхцахыг зөвшөөрдөггүй"</string>
@@ -847,7 +849,7 @@
     <string name="wifi_notify_open_networks" msgid="4782239203624619655">"Сүлжээний мэдэгдлийг нээх"</string>
     <string name="wifi_notify_open_networks_summary" msgid="1383681260705466715">"Өндөр чанарын нийтийн сүлжээ боломжтой үед мэдэгдэх"</string>
     <string name="wifi_wakeup" msgid="4963732992164721548">"Wi‑Fi-г автоматаар асаах"</string>
-    <string name="wifi_wakeup_summary" msgid="1152699417411690">"Wi‑Fi таны гэрийн сүлжээ зэрэг ойролцоох хадгалсан өндөр чанарын сүлжээнд буцаж асах болно."</string>
+    <string name="wifi_wakeup_summary" msgid="1152699417411690">"Wi‑Fi таны гэрийн сүлжээ зэрэг ойролцоох хадгалсан өндөр чанартай сүлжээнд буцаж асах болно."</string>
     <string name="wifi_wakeup_summary_no_location" msgid="3007457288587966962">"Байршил унтраалттай байгаа тул боломжгүй байна. "<annotation id="link">"Байршлыг"</annotation>" асаана уу."</string>
     <string name="wifi_wakeup_summary_scanning_disabled" msgid="6820040651529910914">"Wi‑Fi сканыг унтраасан тул боломжгүй байна"</string>
     <string name="wifi_wakeup_summary_scoring_disabled" msgid="7067018832237903151">"Ашиглахын тулд сүлжээний үнэлгээ үзүүлэгчийг сонгоно уу"</string>
@@ -903,7 +905,7 @@
     <string name="wifi_ssid_hint" msgid="5010024648106585165">"SSID оруулна уу"</string>
     <string name="wifi_security" msgid="9136702039496152831">"Аюулгүй байдал"</string>
     <string name="wifi_hidden_network" msgid="6647772204699776833">"Нуугдсан сүлжээ"</string>
-    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Хэрэв таны чиглүүлэгч сүлжээний ID-г дамжуулахгүй байгаа хэдий ч та цаашдаа үүнд холбогдох хүсэлтэй байвал сүлжээг нуусан гэж тохируулах боломжтой.\n\nТаны утас сүлжээ олохын тулд дохиогоо тогтмол дамжуулах тул энэ нь аюулгүй байдлын эрсдэл үүсгэж болзошгүй.\n\nСүлжээг нуусан гэж тохируулах нь таны чиглүүлэгчийн тохиргоог өөрчлөхгүй."</string>
+    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Хэрэв таны рүүтэр сүлжээний ID-г дамжуулахгүй байгаа хэдий ч та цаашдаа үүнд холбогдох хүсэлтэй байвал сүлжээг нуусан гэж тохируулах боломжтой.\n\nТаны утас сүлжээ олохын тулд дохиогоо тогтмол дамжуулах тул энэ нь аюулгүй байдлын эрсдэл үүсгэж болзошгүй.\n\nСүлжээг нуусан гэж тохируулах нь таны рүүтэрийн тохиргоог өөрчлөхгүй."</string>
     <string name="wifi_signal" msgid="696548364467704808">"Сигналын хүч"</string>
     <string name="wifi_status" msgid="3439931558930689940">"Статус"</string>
     <string name="tx_wifi_speed" msgid="2571810085003261073">"Дамжуулах холбоосны хурд"</string>
@@ -943,8 +945,8 @@
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"Хурдан хариу үйлдлийн кодыг уншиж чадсангүй. Кодыг дахин голлуулаад дахин оролдоно уу"</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"Дахин оролдоно уу. Хэрэв асуудал үргэлжилсээр байвал төхөөрөмжийн үйлдвэрлэгчтэй холбогдоно уу"</string>
     <string name="wifi_dpp_failure_not_compatible" msgid="4320027179973678283">"Алдаа гарлаа"</string>
-    <string name="wifi_dpp_failure_timeout" msgid="5060065168142109420">"Төхөөрөмжийг залгасан, цэнэглэсэн бөгөөд асаасан эсэхийг шалгана уу"</string>
-    <string name="wifi_dpp_failure_generic" msgid="7840142544736640189">"Төхөөрөмжийг залгасан, цэнэглэсэн бөгөөд асаасан эсэхийг шалгана уу. Хэрэв асуудал үргэлжилсээр байвал төхөөрөмжийн үйлдвэрлэгчтэй холбогдоно уу"</string>
+    <string name="wifi_dpp_failure_timeout" msgid="5060065168142109420">"Төхөөрөмжийг залгасан, цэнэглэсэн, асаасан эсэхийг шалгана уу"</string>
+    <string name="wifi_dpp_failure_generic" msgid="7840142544736640189">"Төхөөрөмжийг залгасан, цэнэглэсэн, асаасан эсэхийг шалгана уу. Хэрэв асуудал үргэлжилсээр байвал төхөөрөмжийн үйлдвэрлэгчтэй холбогдоно уу"</string>
     <string name="wifi_dpp_failure_not_supported" msgid="111779621766171626">"Энэ төхөөрөмж “<xliff:g id="SSID">%1$s</xliff:g>”-г нэмэхийг дэмжээгүй байна"</string>
     <string name="wifi_dpp_check_connection_try_again" msgid="7144663015219170999">"Холболтыг шалгаад дахин оролдоно уу"</string>
     <string name="wifi_dpp_choose_network" msgid="6251424431594491691">"Сүлжээ сонгох"</string>
@@ -970,7 +972,7 @@
     <string name="wifi_multiple_cert_added" msgid="7986200585749147204">"(Олон сертификат нэмсэн)"</string>
     <string name="wifi_use_system_certs" msgid="4794489370929885022">"Системийн гэрчилгээ ашигла"</string>
     <string name="wifi_do_not_provide_eap_user_cert" msgid="4044301449482425250">"\"Бүү олго\""</string>
-    <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"Хүчин төгөлдөр бүү болго"</string>
+    <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"Бүү хүчин төгөлдөр болго"</string>
     <string name="wifi_do_not_validate_eap_server_warning" msgid="3895397996759837323">"Ямар ч сертификат заагаагүй байна. Таны холболт хувийн биш байх болно."</string>
     <string name="wifi_ssid_too_long" msgid="34911971389775920">"Сүлжээний нэр хэтэрхий урт байна."</string>
     <string name="wifi_no_domain_warning" msgid="735859919311067606">"Домэйн зааж өгөх шаардлагатай."</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Мобайл"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Хэрэв Wi‑Fi боломжгүй бол мобайл сүлжээ ашиглана уу"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Хэрэв мобайл сүлжээ боломжгүй байвал Wi-Fi-г ашиглана уу"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Wi‑Fi-р залгана. Wi‑Fi салсан тохиолдолд залгахаа болино."</string>
@@ -1210,7 +1215,7 @@
     <string name="night_display_auto_mode_title" msgid="8493573087102481588">"Хуваарь"</string>
     <string name="night_display_auto_mode_never" msgid="2897444637217807088">"Аль нь ч биш"</string>
     <string name="night_display_auto_mode_custom" msgid="1400891076453963151">"Тохируулсан хугацаанд асна"</string>
-    <string name="night_display_auto_mode_twilight" msgid="4000162110017520674">"Нар мандахаас жаргах хүртэл асна"</string>
+    <string name="night_display_auto_mode_twilight" msgid="4000162110017520674">"Нар жаргахаас мандах хүртэл асна"</string>
     <string name="night_display_start_time_title" msgid="1069255169673371077">"Эхлэх цаг"</string>
     <string name="night_display_end_time_title" msgid="2760793157124245911">"Дуусах цаг"</string>
     <string name="night_display_status_title" msgid="1727020934735770319">"Төлөв"</string>
@@ -1419,9 +1424,9 @@
     <string name="usb_mtp_title" msgid="6893938968831995500">"Медиа төхөөрөмж (MTP)"</string>
     <string name="usb_mtp_summary" msgid="4427354560399094322">"Windows дээр медиа файлуудыг дамжуулах буюу Андройд Файл Дамжуулагчийг Mac дээр ашиглах боломж олгоно (www.android.com/filetransfer харна уу)"</string>
     <string name="usb_ptp_title" msgid="6629335976394685361">"Камер (PTP)"</string>
-    <string name="usb_ptp_summary" msgid="460425275251168189">"Танд камерын програм ашиглан зураг дамжуулах, компьютер дээрээс MTP-г дэмждэггүй ямар ч файлыг дамжуулах боломж олгоно"</string>
+    <string name="usb_ptp_summary" msgid="460425275251168189">"Танд камерын программ ашиглан зураг дамжуулах, компьютер дээрээс MTP-г дэмждэггүй ямар ч файлыг дамжуулах боломж олгоно"</string>
     <string name="usb_midi_title" msgid="8626512517313340943">"MIDI"</string>
-    <string name="usb_midi_summary" msgid="3607444815743771712">"MIDI-г идэвхжүүлсэн програмуудыг өөрийн компьютер дээрх MIDI програм хангамжийг USB дээр ажиллуулах."</string>
+    <string name="usb_midi_summary" msgid="3607444815743771712">"MIDI-г идэвхжүүлсэн программуудыг өөрийн компьютер дээрх MIDI программ хангамжийг USB дээр ажиллуулах."</string>
     <string name="storage_other_users" msgid="1055693465220962928">"Бусад хэрэглэгчид"</string>
     <string name="storage_internal_title" msgid="7969898703086593200">"Төхөөрөмжийн хадгалах сан"</string>
     <string name="storage_external_title" msgid="3308178326521953306">"Зөөврийн санах ой"</string>
@@ -1586,7 +1591,7 @@
     <string name="master_clear_other_users_present" product="default" msgid="5993259656117566767">\n\n"Энэ төхөөрөмж дээр өөр хэрэглэгчид байна.\n"</string>
     <string name="master_clear_desc_also_erases_external" msgid="3947303501615091903"><li>"Хөгжим"</li>\n<li>"Зураг"</li>\n<li>"Бусад хэрэглэгчийн өгөгдөл"</li></string>
     <string name="master_clear_desc_also_erases_esim" msgid="4497260499055258773"><li>"eSIM-үүд"</li></string>
-    <string name="master_clear_desc_no_cancel_mobile_plan" msgid="6072668588881679461">\n\n"Энэ нь таны мобайл үйлчилгээний төлөвлөгөөг цуцлахгүй."</string>
+    <string name="master_clear_desc_no_cancel_mobile_plan" msgid="6072668588881679461">\n\n"Энэ нь таны мобайл үйлчилгээний багцыг цуцлахгүй."</string>
     <string name="master_clear_desc_erase_external_storage" product="nosdcard" msgid="2723272952715259307">\n\n"Хөгжим, зураг болон бусад хэрэглэгчийн өгөгдлийг цэвэрлэхийн тулд "<b>"USB санг"</b>" арилгах шаардлагатай."</string>
     <string name="master_clear_desc_erase_external_storage" product="default" msgid="9003555775524798797">\n\n"Хөгжим, зураг болон бусад хэрэглэгчийн өгөгдлийг цэвэрлэхийн тулд "<b>"SD картыг"</b>" арилгах шаардлагатай."</string>
     <string name="erase_external_storage" product="nosdcard" msgid="8989746770347525207">"USB санг арилгах"</string>
@@ -1679,7 +1684,7 @@
     <string name="about_settings" product="default" msgid="6019547763377294261">"Утасны тухай"</string>
     <string name="about_settings" product="device" msgid="1770438316234693655">"Төхөөрөмжийн тухай"</string>
     <string name="about_settings" product="emulator" msgid="4497482494770487014">"Утасны мэдээллийн дэлгэц"</string>
-    <string name="about_settings_summary" msgid="4506081667462281647">"Хууль эрх зүйн мэдээлэл, статус, програмын хувилбарыг харах"</string>
+    <string name="about_settings_summary" msgid="4506081667462281647">"Хууль эрх зүйн мэдээлэл, статус, программын хувилбарыг харах"</string>
     <string name="legal_information" msgid="2374267257615182139">"Хууль эрх зүйн мэдээлэл"</string>
     <string name="contributors_title" msgid="6800028420806884340">"Хувь оруулагчид"</string>
     <string name="manual" msgid="5431859421432581357">"Гар ажиллагаатай"</string>
@@ -1795,7 +1800,7 @@
     <string name="advanced_settings_summary" msgid="5912237062506771716">"Өөр тохиргоо сонголтыг идэвхжүүлнэ үү"</string>
     <string name="application_info_label" msgid="3886253474964599105">"Апп мэдээлэл"</string>
     <string name="storage_label" msgid="1109537840103290384">"Хадгалах сан"</string>
-    <string name="auto_launch_label" msgid="47089737922907379">"Стандарт нээх утга"</string>
+    <string name="auto_launch_label" msgid="47089737922907379">"Өгөгдмөлөөр нээх"</string>
     <string name="auto_launch_label_generic" msgid="7865828543459493308">"Үндсэн тохиргоо"</string>
     <string name="screen_compatibility_label" msgid="3638271673726075815">"Дэлгэцийн нийцэл"</string>
     <string name="permissions_label" msgid="7341733648403464213">"Зөвшөөрөл"</string>
@@ -1951,7 +1956,7 @@
     <string name="auto_caps" msgid="5566082723106296847">"Автоматаар томруулах"</string>
     <string name="auto_caps_summary" msgid="8505254799874525084">"Өгүүлбэрийн эхний үсгийг томруулах"</string>
     <string name="auto_punctuate" msgid="8386007107100525931">"Авто-цэг таслал"</string>
-    <string name="hardkeyboard_category" msgid="5937171470391551627">"Бодит гарын тохиргоо"</string>
+    <string name="hardkeyboard_category" msgid="5937171470391551627">"Биет гарын тохиргоо"</string>
     <string name="auto_punctuate_summary" msgid="245694025030386370">"Зай авах товчийг хоёр удаа дарж \".\" оруулна"</string>
     <string name="show_password" msgid="620964020348073739">"Нууц үг харуулах"</string>
     <string name="show_password_summary" msgid="1403805089582258620">"Бичих явцад тэмдэгтийг товчхон харуулах"</string>
@@ -1963,9 +1968,9 @@
     <string name="available_virtual_keyboard_category" msgid="2211375533762470875">"Боломжит виртуал гар"</string>
     <string name="add_virtual_keyboard" msgid="490638727157806209">"Гарыг удирдах"</string>
     <string name="keyboard_assistance_category" msgid="2276351807419818125">"Гарын тусламж"</string>
-    <string name="physical_keyboard_title" msgid="3508591962962814313">"Бодит гар"</string>
+    <string name="physical_keyboard_title" msgid="3508591962962814313">"Биет гар"</string>
     <string name="show_ime" msgid="7322620473198763563">"Виртуал гарыг харуулах"</string>
-    <string name="show_ime_summary" msgid="3246628154011464373">"Бодит гар идэвхтэй үед үүнийг дэлгэцэд харуулна уу"</string>
+    <string name="show_ime_summary" msgid="3246628154011464373">"Биет гар идэвхтэй үед үүнийг дэлгэцэд харуулна уу"</string>
     <string name="keyboard_shortcuts_helper" msgid="6574386807271399788">"Гарын товчлолын туслагч"</string>
     <string name="keyboard_shortcuts_helper_summary" msgid="8024313306403779742">"Боломжтой товчлолыг харуулах"</string>
     <string name="language_and_input_for_work_category_title" msgid="2053255944038892588">"Ажлын профайлын гар &amp; хэрэгсэл"</string>
@@ -2016,8 +2021,8 @@
     <string name="input_methods_settings_label_format" msgid="5927400388781960176">"<xliff:g id="IME_NAME">%1$s</xliff:g> тохиргоо"</string>
     <string name="input_methods_and_subtype_enabler_title" msgid="75557930915149416">"Идэвхтэй оруулах аргыг сонгоно уу"</string>
     <string name="onscreen_keyboard_settings_summary" msgid="148763210673670769">"Дэлгэцэн дээрх гарын тохиргоо"</string>
-    <string name="builtin_keyboard_settings_title" msgid="3683883402326039724">"Бодит гар"</string>
-    <string name="builtin_keyboard_settings_summary" msgid="6498739864479285932">"Бодит гарын тохиргоо"</string>
+    <string name="builtin_keyboard_settings_title" msgid="3683883402326039724">"Биет гар"</string>
+    <string name="builtin_keyboard_settings_summary" msgid="6498739864479285932">"Биет гарын тохиргоо"</string>
     <string name="gadget_picker_title" msgid="9146981887780645322">"Гаджет сонгоно уу"</string>
     <string name="widget_picker_title" msgid="5424689728810684439">"Виджет сонгох"</string>
     <string name="allow_bind_app_widget_activity_allow_bind_title" msgid="8168110035319637326">"Виджэт үүсгээд хандалт хийхийг зөвшөөрөх үү?"</string>
@@ -2043,7 +2048,7 @@
     <string name="experimental_category_title" msgid="3797000069740110717">"Туршилтын"</string>
     <string name="feature_flags_dashboard_title" msgid="3153034144122754381">"Онцлогийн дарцаг"</string>
     <string name="talkback_title" msgid="3717960404234260050">"Talkback"</string>
-    <string name="talkback_summary" msgid="6602857105831641574">"Дэлгэц уншигчийг ерөнхийдөө сохор буюу харааны гажигтай хүмүүст зориулсан"</string>
+    <string name="talkback_summary" msgid="6602857105831641574">"Дэлгэц уншигчийг ерөнхийдөө хараагүй болон сул хараатай хүмүүст зориулсан"</string>
     <string name="select_to_speak_summary" msgid="7514180457557735421">"Дэлгэц дээрх зүйлсийг чанга уншуулахын тулд дарна уу"</string>
     <string name="accessibility_captioning_title" msgid="5878371993023439642">"Тайлбар"</string>
     <string name="accessibility_screen_magnification_title" msgid="7250949681883917360">"Томруулах"</string>
@@ -2081,7 +2086,7 @@
     <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"Та унших шаардлагатай хэдий ч зөвхөн түр хугацаанд харагддаг мессежийг хэр удаан харуулахыг сонгоно уу.\n\nЗарим апп энэ тохиргоог дэмждэггүй."</string>
     <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"Танаас үйлдэл хийхийг шаарддаг хэдий ч зөвхөн түр хугацаанд харагддаг зурвасыг хэр удаан хугацаагаар харуулахыг сонгоно уу.\n\nЗарим апп энэ тохиргоог дэмждэггүй."</string>
     <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"Хүрээд &amp; барьж хүлээх"</string>
-    <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"Өнгө урвуулалт"</string>
+    <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"Өнгө хувиргалт"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"Үзүүлбэрт нөлөөлж болзошгүй"</string>
     <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"Тодорхой хугацаа"</string>
     <string name="accessibility_autoclick_description" msgid="5492414927846407499">"Хэрэв та хулгана ашиглаж байвал тодорхой хугацааны туршид хөдлөхөө болсон үед нь автоматаар үйлдэл хийхийн тулд курсорыг тохируулах боломжтой."</string>
@@ -2095,7 +2100,7 @@
     <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"Тайлбар ашиглах"</string>
     <string name="accessibility_hearingaid_instruction_continue_button" msgid="4650111296711466691">"Үргэлжлүүлэх"</string>
     <string name="accessibility_hearingaid_title" msgid="3700978781235124891">"Сонсголын төхөөрөмжүүд"</string>
-    <string name="accessibility_hearingaid_not_connected_summary" msgid="634573930469952213">"Холбогдсон сонсголын төхөөрөмжүүд алга"</string>
+    <string name="accessibility_hearingaid_not_connected_summary" msgid="634573930469952213">"Холбогдсон сонсголын төхөөрөмж алга"</string>
     <string name="accessibility_hearingaid_adding_summary" msgid="4139031880828714300">"Сонсголын төхөөрөмж нэмэх"</string>
     <string name="accessibility_hearingaid_pair_instructions_first_message" msgid="2671518890909750740">"Сонсголын төхөөрөмжүүдээ холбохын тулд төхөөрөмжөө дараагийн дэлгэцээс олж товшино уу."</string>
     <string name="accessibility_hearingaid_pair_instructions_second_message" msgid="1584538735488464991">"Таны сонсголын төхөөрөмжүүд холболтын горимд байгаа эсэхийг шалгана уу."</string>
@@ -2272,8 +2277,8 @@
     <string name="battery_tip_smart_battery_title" product="tablet" msgid="203494973250969040">"Таблетынхаа батарейн ажиллах хугацааг нэмэгдүүлэх"</string>
     <string name="battery_tip_smart_battery_title" product="device" msgid="7419448992583346364">"Төхөөрөмжийнхөө батарейн ажиллах хугацааг нэмэгдүүлэх"</string>
     <string name="battery_tip_smart_battery_summary" msgid="5344821856478265778">"Батерейны менежерийг асаах"</string>
-    <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Тэжээл хэмнэгчийг асаах"</string>
-    <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Батерей ердийнхөөс хурдан дуусаж болзошгүй"</string>
+    <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Батарей хэмнэгчийг асаах"</string>
+    <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Батарей ердийн үеийнхээс хурдан дуусаж болзошгүй"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Тэжээл хэмнэгч асаалттай байна"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Зарим онцлогийг хязгаарласан байж болзошгүй"</string>
     <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Утсыг ердийнхөөс их хэмжээгээр ашигласан"</string>
@@ -2293,8 +2298,8 @@
       <item quantity="one">%1$s-г саяхан хязгаарласан</item>
     </plurals>
     <plurals name="battery_tip_restrict_summary" formatted="false" msgid="984148373944071669">
-      <item quantity="other">%2$d аппын батерейг цаана ашиглах түвшин өндөр байна</item>
-      <item quantity="one">%1$s-н батерейг цаана ашиглах түвшин өндөр байна</item>
+      <item quantity="other">%2$d аппын батарейг цаана ашиглах түвшин өндөр байна</item>
+      <item quantity="one">%1$s-н батарейг цаана ашиглах түвшин өндөр байна</item>
     </plurals>
     <plurals name="battery_tip_restrict_handled_summary" formatted="false" msgid="469696766640020557">
       <item quantity="other">Эдгээр аппыг цаана ажиллуулах боломжгүй байна</item>
@@ -2531,7 +2536,7 @@
     <string name="advanced_security_title" msgid="286883005673855845">"Дэлгэрэнгүй"</string>
     <string name="credential_storage_type" msgid="2585337320206095255">"Хадгалах сангийн төрөл"</string>
     <string name="credential_storage_type_hardware" msgid="5054143224259023600">"Техник хангамжаар дэмжигдсэн"</string>
-    <string name="credential_storage_type_software" msgid="1335905150062717150">"Зөвхөн програм"</string>
+    <string name="credential_storage_type_software" msgid="1335905150062717150">"Зөвхөн программ"</string>
     <string name="credentials_settings_not_available" msgid="5490259681690183274">"Энэ хэрэглэгчид итгэмжлэл байхгүй байна"</string>
     <string name="credential_for_vpn_and_apps" msgid="2462642486949593841">"VPN, апп-д суулгасан"</string>
     <string name="credential_for_wifi" msgid="2903295786961726388">"Wi-Fi-д суулгасан"</string>
@@ -2596,7 +2601,7 @@
     <string name="work_mode_label" msgid="6845849194740195757">"Ажлын профайл"</string>
     <string name="work_mode_on_summary" msgid="1682781113156323592">"Танай байгууллагаас удирддаг"</string>
     <string name="work_mode_off_summary" msgid="1688885392211178315">"Апп болон мэдэгдэл унтраалттай байна"</string>
-    <string name="remove_managed_profile_label" msgid="4625542553784793536">"Ажлын профайлыг арилгах"</string>
+    <string name="remove_managed_profile_label" msgid="4625542553784793536">"Ажлын профайлыг хасах"</string>
     <string name="background_data" msgid="8275750862371471171">"Далд өгөгдөл"</string>
     <string name="background_data_summary" msgid="799640633948841990">"Аппууд өгөгдлийг ямар ч үед синк хийж, илгээж, хүлээж авч болно"</string>
     <string name="background_data_dialog_title" msgid="8306650658158895976">"Далд өгөгдлийг идэвхгүйжүүлэх үү?"</string>
@@ -2625,7 +2630,7 @@
     <string name="header_add_an_account" msgid="8482614556580804956">"Бүртгэл нэмэх"</string>
     <string name="really_remove_account_title" msgid="4166512362915154319">"Бүртгэлийг арилгах уу?"</string>
     <string name="really_remove_account_message" product="tablet" msgid="7403843371045856719">"Энэ акаунтыг арилгаснаас үүний бүх зурвас, харилцагчид болон бусад өгөгдлүүдийг таблетаас устгах болно!"</string>
-    <string name="really_remove_account_message" product="default" msgid="8951224626153163914">"Энэ акаунтыг арилгаснаар үүний бүх зурвас, харилцагчид, бусад өгөгдлүүдийг утаснаас устгах болно!"</string>
+    <string name="really_remove_account_message" product="default" msgid="8951224626153163914">"Энэ бүртгэлийг хассанаар үүний бүх зурвас, харилцагчид, бусад өгөгдлийг утаснаас устгах болно!"</string>
     <string name="really_remove_account_message" product="device" msgid="3751798556257519916">"Энэ бүртгэлийг устгаснаар үүний бүх зурвас, харилцагч болон бусад өгөгдлийг төхөөрөмжөөс устгана!"</string>
     <string name="remove_account_failed" msgid="491458185327106966">"Энэ өөрчлөлтийг таны админ зөвшөөрөөгүй байна"</string>
     <string name="cant_sync_dialog_title" msgid="5483419398223189881">"Гараар синк хийх боломжгүй"</string>
@@ -2665,8 +2670,8 @@
     <string name="data_usage_menu_sim_cards" msgid="8508154611676507088">"SIM карт"</string>
     <string name="data_usage_cellular_data_summary" msgid="9162777397135709280">"Хязгаарт хүрмэгц зогсоосон"</string>
     <string name="account_settings_menu_auto_sync" msgid="2673669556006027506">"Датаг автоматаар синклэх"</string>
-    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"Хувийн датаг автоматаар синк хийх"</string>
-    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Ажлын датаг автоматаар синк хийх"</string>
+    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"Хувийн өгөгдлийг автоматаар синк хийх"</string>
+    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Ажлын өгөгдлийг автоматаар синк хийх"</string>
     <string name="data_usage_change_cycle" msgid="447761920472170031">"Циклийг өөрчлөх…"</string>
     <string name="data_usage_pick_cycle_day" msgid="6319750879145917066">"Дата ашиглалтын циклийг шинэчлэх сарын өдөр:"</string>
     <string name="data_usage_empty" msgid="7981405723435034032">"Энэ хугацаанд дата ашигласан апп байхгүй."</string>
@@ -2770,7 +2775,7 @@
     <string name="vpn_disconnect_confirm" msgid="3505111947735651082">"Энэ VPN-г салгах уу?"</string>
     <string name="vpn_disconnect" msgid="4625914562388652486">"Салгах"</string>
     <string name="vpn_version" msgid="2006792987077940456">"Хувилбар <xliff:g id="VERSION">%s</xliff:g>"</string>
-    <string name="vpn_forget_long" msgid="8457511440635534478">"VPN мартсан"</string>
+    <string name="vpn_forget_long" msgid="8457511440635534478">"VPN-г мартах"</string>
     <string name="vpn_replace_vpn_title" msgid="8517436922021598103">"Энэ VPN-г солих уу?"</string>
     <string name="vpn_set_vpn_title" msgid="6483554732067951052">"VPN-г тогтмол асаалттайгаар тохируулах уу?"</string>
     <string name="vpn_first_always_on_vpn_message" msgid="7050017738816963855">"Энэ тохиргоо асаалттай үед та VPN-г амжилттай холбох хүртэл интернетэд холбогдохгүй"</string>
@@ -2865,8 +2870,8 @@
     <string name="user_add_user_item_title" msgid="6835385073795492410">"Хэрэглэгч"</string>
     <string name="user_add_profile_item_title" msgid="4932743891449790664">"Хязгаарлагдсан профайл"</string>
     <string name="user_add_user_title" msgid="2320897397066676472">"Шинэ хэрэглэгч нэмэх үү?"</string>
-    <string name="user_add_user_message_long" msgid="686637203224195465">"Та нэмэлт хэрэглэгч үүсгэх замаар бусад хүмүүстэй энэ төхөөрөмжийг хуваалцаж болно. Хэрэглэгч тус бүр апп, ханын цаас болон бусад зүйлээ өөрчлөх боломжтой хувийн орон зайтай байдаг. Түүнчлэн хэрэглэгч нь бүх хэрэглэгчид нөлөөлөх боломжтой Wi-Fi зэрэг төхөөрөмжийн тохиргоог өөрчлөх боломжтой.\n\nХэрэв та шинэ хэрэглэгч нэмэх бол тухайн хүн хувийн орон зайгаа бүрдүүлэх ёстой.\n\nХэрэглэгч бүр бусад бүх хэрэглэгчийн өмнөөс апп шинэчилж болно. Хүртээмжийн тохиргоо болон үйлчилгээг шинэ хэрэглэгчид шилжүүлэх боломжгүй байж болзошгүй."</string>
-    <string name="user_add_user_message_short" msgid="1802594476285458254">"Та шинэ хэрэглэгч нэмбэл тухайн хүн өөрийн профайлыг тохируулах шаардлагатай.\n\nАль ч хэрэглэгч бүх хэрэглэгчийн апп-уудыг шинэчлэх боломжтой."</string>
+    <string name="user_add_user_message_long" msgid="686637203224195465">"Та нэмэлт хэрэглэгч үүсгэх замаар бусад хүнтэй энэ төхөөрөмжийг хуваалцаж болно. Хэрэглэгч тус бүр апп, ханын цаас болон бусад зүйлээ өөрчлөх боломжтой хувийн орон зайтай байдаг. Түүнчлэн хэрэглэгч нь бүх хэрэглэгчид нөлөөлөх боломжтой Wi-Fi зэрэг төхөөрөмжийн тохиргоог өөрчлөх боломжтой.\n\nХэрэв та шинэ хэрэглэгч нэмэх бол тухайн хүн хувийн орон зайгаа тохируулах ёстой.\n\nХэрэглэгч бүр бусад бүх хэрэглэгчийн өмнөөс апп шинэчилж болно. Хандалтын тохиргоо болон үйлчилгээг шинэ хэрэглэгчид шилжүүлэх боломжгүй байж болзошгүй."</string>
+    <string name="user_add_user_message_short" msgid="1802594476285458254">"Та шинэ хэрэглэгч нэмбэл тухайн хүн өөрийн профайлыг тохируулах шаардлагатай.\n\nАль ч хэрэглэгч бүх хэрэглэгчийн аппуудыг шинэчлэх боломжтой."</string>
     <string name="user_setup_dialog_title" msgid="6748950002206392396">"Хэрэглэгчийг одоо тохируулах уу?"</string>
     <string name="user_setup_dialog_message" msgid="2988559933258353919">"Хэрэглэгч төхөөрөмжийг авч өөрийн профайлыг тохируулах боломжтой эсэхийг шалгана уу"</string>
     <string name="user_setup_profile_dialog_message" msgid="7611900802824048526">"Профайлыг одоо тохируулах уу?"</string>
@@ -2883,7 +2888,7 @@
     <string name="user_confirm_remove_self_title" msgid="6739480453680217543">"Өөрийгөө устгах уу?"</string>
     <string name="user_confirm_remove_title" msgid="1034498514019462084">"Энэ хэрэглэгчийг устгах уу?"</string>
     <string name="user_profile_confirm_remove_title" msgid="6138684743385947063">"Энэ профайлыг устгах уу?"</string>
-    <string name="work_profile_confirm_remove_title" msgid="3168910958076735800">"Ажлын профайлыг арилгах"</string>
+    <string name="work_profile_confirm_remove_title" msgid="3168910958076735800">"Ажлын профайлыг хасах уу?"</string>
     <string name="user_confirm_remove_self_message" product="tablet" msgid="2889456786320157545">"Та энэ таблет дээрх өөрийн зай болон өгөгдлийг алдах болно. Та энэ үйлдлийг буцаах боломжгүй."</string>
     <string name="user_confirm_remove_self_message" product="default" msgid="8441729423565705183">"Та энэ утсан дээрх өөрийн зай болон өгөгдлийг алдах болно. Та энэ үйлдлийг буцаах боломжгүй."</string>
     <string name="user_confirm_remove_message" msgid="5202150470271756013">"Бүх апп болон дата устах болно."</string>
@@ -2911,7 +2916,7 @@
     <string name="apps_with_restrictions_settings_button" msgid="5065896213467171744">"Аппликейшний тохиргоог дэлгэх"</string>
     <string name="nfc_payment_settings_title" msgid="5070077706735415291">"Товшоод төлөөрэй"</string>
     <string name="nfc_payment_how_it_works" msgid="7607901964687787177">"Энэ хэрхэн ажилладаг вэ"</string>
-    <string name="nfc_payment_no_apps" msgid="8844440783395420860">"Дэлгүүрийн тооцоог утсаа ашиглан хийх"</string>
+    <string name="nfc_payment_no_apps" msgid="8844440783395420860">"Дэлгүүрт утсаараа тооцоо хийх"</string>
     <string name="nfc_payment_default" msgid="7869273092463612271">"Төлбөр төлөх стандарт апп"</string>
     <string name="nfc_payment_default_not_set" msgid="955804193510335338">"Тохируулаагүй"</string>
     <string name="nfc_payment_app_and_desc" msgid="102312684211458190">"<xliff:g id="APP">%1$s</xliff:g> - <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
@@ -2920,7 +2925,7 @@
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Өөр төлбөрийн апп нээлттэй байхаас бусад үед"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"\"Товшиж төлөх\" дээр төлөх:"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Tерминалаар тооцоо хийж байна"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Төлбөрийн апп-г тохируулаарай. Холбоoгүй тэмдэг бүхий терминалд утасныхаа ард талыг бариарай."</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Төлбөрийн аппыг тохируулаарай. Зайнаас уншуулах тэмдэг бүхий терминалд утасныхаа ар талыг бариарай."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"Ойлголоо"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"Илүү..."</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"Таны тохируулга болгох уу?"</string>
@@ -3196,7 +3201,7 @@
     <string name="zen_mode_restrict_notifications_mute_footer" msgid="3049522809520549054">"Мэдэгдэл ирэх үед таны утас ямар нэгэн дуу гаргахгүй буюу эсвэл чичрэхгүй."</string>
     <string name="zen_mode_restrict_notifications_hide" msgid="3296933643539682552">"Мэдэгдэл харагдахгүй бөгөөд дуугарахгүй"</string>
     <string name="zen_mode_restrict_notifications_hide_summary" msgid="1449301153755270168">"Та мэдэгдлийг харахгүй бөгөөд сонсохгүй"</string>
-    <string name="zen_mode_restrict_notifications_hide_footer" msgid="7617688597593946765">"Таны утас шинэ эсвэл хуучин мэдэгдлийг харуулахгүйгээс гадна чичрэхгүй бөгөөд дуугарахгүй. Утасны үйл ажиллагаа болон статусын чухал шинэчлэлт гарч ирсэн хэвээр байх болно гэдгийг анхаарна уу.\n\nТа Бүү саад бол горимыг унтраасан үедээ дэлгэцийнхээ дээд хэсгээс доош шударч, аваагүй мэдэгдлээ олоорой."</string>
+    <string name="zen_mode_restrict_notifications_hide_footer" msgid="7617688597593946765">"Таны утас шинэ эсвэл хуучин мэдэгдлийг харуулахгүйгээс гадна чичрэхгүй, дуугарахгүй. Утасны үйл ажиллагаа болон статустай холбоотой чухал мэдэгдлүүд харагдсан хэвээр байх болно гэдгийг анхаарна уу.\n\nТа Бүү саад бол горимыг унтраасан үедээ дэлгэцийнхээ дээд хэсгээс доош шударч, аваагүй мэдэгдлээ олоорой."</string>
     <string name="zen_mode_restrict_notifications_custom" msgid="3167252482570424133">"Захиалгат"</string>
     <string name="zen_mode_restrict_notifications_enable_custom" msgid="6376983315529894440">"Захиалгат тохиргоог идэвхжүүлэх"</string>
     <string name="zen_mode_restrict_notifications_disable_custom" msgid="8004212081465043044">"Захиалгат тохиргоог устгах"</string>
@@ -3550,7 +3555,7 @@
     <string name="screen_pinning_title" msgid="578020318289781102">"Дэлгэц тогтоох"</string>
     <string name="screen_pinning_description" msgid="3814537379086412278">"Энэ тохиргоо асаалттай үед та одоогийн дэлгэцийг тогтоохоо болих хүртлээ үргэлжлүүлэн харуулахын тулд дэлгэц тогтоох онцлогийг ашиглах боломжтой.\n\nДэлгэц тогтоох онцлогийг ашиглахын тулд:\n\n1. Дэлгэц тогтоох онцлог асаалттай эсэхийг шалгах\n\n2. Тоймыг нээх\n\n3. Дэлгэцийн дээд хэсгийн аппын дүрс тэмдгийг товшиж Тогтоох гэснийг товшино уу"</string>
     <string name="screen_pinning_unlock_pattern" msgid="1060334707088339444">"Тогтоосныг суллахаас өмнө түгжээ тайлах хээ асуух"</string>
-    <string name="screen_pinning_unlock_pin" msgid="1441705536015645023">"Тогтоосныг суллахаас өмнө PIN асуух"</string>
+    <string name="screen_pinning_unlock_pin" msgid="1441705536015645023">"Бэхэлснийг болиулахаасаа өмнө PIN асуух"</string>
     <string name="screen_pinning_unlock_password" msgid="1017776884000170841">"Тогтоосныг суллахаас өмнө нууц үг асуух"</string>
     <string name="screen_pinning_unlock_none" msgid="9183040569733226911">"Unpinning хийх үед төхөөрөмжийг түгжинэ"</string>
     <string name="opening_paragraph_delete_profile_unknown_company" msgid="2350380017136403670">"Энэ ажлын профайлыг удирдагч нь:"</string>
@@ -3581,7 +3586,7 @@
     <string name="imei_information_title" msgid="7666097743700170757">"IMEI мэдээлэл"</string>
     <string name="imei_information_summary" msgid="716516316022275083">"IMEI хамаарах мэдээлэл"</string>
     <string name="slot_number" msgid="785422579177068698">"(Слот<xliff:g id="SLOT_NUM">%1$d</xliff:g>)"</string>
-    <string name="launch_by_default" msgid="6106985160202769725">"Стандарт нээх утга"</string>
+    <string name="launch_by_default" msgid="6106985160202769725">"Өгөгдмөлөөр нээх"</string>
     <string name="app_launch_domain_links_title" msgid="2987289657348349133">"Холбоосыг нээх"</string>
     <string name="app_launch_open_domain_urls_title" msgid="8595126859922391331">"Дэмждэг холбоосыг нээх"</string>
     <string name="app_launch_open_domain_urls_summary" msgid="6803029846855502366">"Асуулгүйгээр нээх"</string>
@@ -3702,13 +3707,13 @@
     <string name="high_power_filter_on" msgid="5294209328473386403">"Оновчлоогүй"</string>
     <string name="high_power_on" msgid="3573501822510580334">"Оновчлоогүй"</string>
     <string name="high_power_off" msgid="5906679734326490426">"Батарей ашиглалтыг оновчилж байна"</string>
-    <string name="high_power_system" msgid="739584574711292753">"Тэжээлийн оновчлолыг ашиглах боломжгүй байна"</string>
+    <string name="high_power_system" msgid="739584574711292753">"Батарейн оновчлолыг ашиглах боломжгүй байна"</string>
     <string name="high_power_desc" msgid="333756885680362741">"Тэжээлийн оновчлол ашиглах шаардлагагүй. Учир нь тэжээлийг илүү түргэн дуусгаж болох юм."</string>
     <string name="high_power_prompt_title" msgid="2805745781720454052">"Аппыг цаана тогтмол ажиллуулахыг зөвшөөрөх үү?"</string>
-    <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г цаана ажиллуулахаар зөвшөөрсөн тохиолдолд батерейны түвшинг багасгах болно. \n\nТа үүнийг дараа нь Тохиргоо, Апп, мэдэгдэл хэсэгт өөрчлөх боломжтой."</string>
+    <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г байнга цаана ажиллуулахаар зөвшөөрсөн тохиолдолд батарейны түвшинг багасгах болно. \n\nТа үүнийг дараа нь Тохиргоо, Апп, мэдэгдэл хэсэгт өөрчлөх боломжтой."</string>
     <string name="battery_summary" msgid="4345690800899981339">"Сүүлд бүрэн цэнэглэснээс хойш <xliff:g id="PERCENTAGE">%1$s</xliff:g>-г ашигласан"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"Цэнэгний менежмент"</string>
-    <string name="no_battery_summary" msgid="4105932628367471314">"Сүүлийн бүрэн цэнэглэлтээс хойш тэжээл огт ашиглаагүй"</string>
+    <string name="no_battery_summary" msgid="4105932628367471314">"Сүүлийн бүрэн цэнэглэлтээс хойш батарей огт ашиглаагүй"</string>
     <string name="app_notification_preferences" msgid="5154466638524523201">"Апп-ийн тохиргоо"</string>
     <string name="system_ui_settings" msgid="6751165163665775447">"SystemUI Tuner харуулах"</string>
     <string name="additional_permissions" msgid="3142290772324571654">"Нэмэлт зөвшөөрөл"</string>
@@ -3757,7 +3762,7 @@
     <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Туслах апп-ийг дэлгэцийн зурагт хандахыг зөвшөөрөх"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"Дэлгэц гэрэлтэх"</string>
     <string name="assist_flash_summary" msgid="6697095786317559129">"Дэлгэц эсвэл дэлгэцийн зургаас текст рүү туслах апп хандах үед дэлгэцийн ирмэг гэрэлтэх"</string>
-    <string name="assist_footer" msgid="7030121180457472165">"Туслах апп нь таны харж байгаа дэлгэцийн мэдээлэл дээр тулгуурлан танд туслах боломжтой. Зарим апп нь танд нэгдсэн тусламжийн үйлчилгээ үзүүлэх үүднээс эхлүүлэгч болон дуун оролтыг дэмждэг."</string>
+    <string name="assist_footer" msgid="7030121180457472165">"Туслах апп нь таны харж байгаа дэлгэцийн мэдээлэлд тулгуурлан танд туслах боломжтой. Зарим апп нь танд нэгдсэн тусламжийн үйлчилгээ үзүүлэх үүднээс эхлүүлэгч болон дуун оролтыг дэмждэг."</string>
     <string name="average_memory_use" msgid="5333366040118953945">"Санах ой дундаж ашиглалт"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"Санах ойн хамгийн хэрэглээ"</string>
     <string name="memory_usage" msgid="7963253555330830906">"Санах ойн ашиглалт"</string>
@@ -3797,7 +3802,7 @@
     <string name="system_alert_window_apps_title" msgid="9188448296493699566">"Апп"</string>
     <string name="system_alert_window_access_title" msgid="5187343732185369675">"Бусад апп дээр харуулах"</string>
     <string name="permit_draw_overlay" msgid="9039092257052422344">"Бусад апп дээр харуулахыг зөвшөөрөх"</string>
-    <string name="allow_overlay_description" msgid="6669524816705082807">"Энэ аппыг ашиглаж буй бусад аппын дээр харуулахыг зөвшөөрнө үү. Ингэснээр таны бусад аппын ашиглалт эсвэл тэдгээрийн харагдац, ажиллагаанд өөрчлөлт орж болзошгүй."</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="overlay_settings" msgid="3325154759946433666">"Бусад апп дээр харуулах"</string>
@@ -4003,7 +4008,7 @@
     <string name="lockscreen_remote_input" msgid="3363310613165354434">"Төхөөрөмж түгжээтэй үед хариу бичих, бусад текстийг мэдэгдлээр ирэх эсэхийг тохируулна уу."</string>
     <string name="default_spell_checker" msgid="8636661093243189533">"Өгөгдмөл алдаа шалгагч"</string>
     <string name="choose_spell_checker" msgid="7619860861923582868">"Алдаа шалгагч сонгох"</string>
-    <string name="spell_checker_master_switch_title" msgid="5712693172227400668">"Зөв бичгийн алдаа шалгагчийг ашиглах"</string>
+    <string name="spell_checker_master_switch_title" msgid="5712693172227400668">"Зөв бичгийн алдаа шалгагч ашиглах"</string>
     <string name="spell_checker_not_selected" msgid="331034541988255137">"Сонгоогүй"</string>
     <string name="notification_log_no_title" msgid="3668232437235348628">"(байхгүй)"</string>
     <string name="notification_log_details_delimiter" msgid="5485526744689532908">": "</string>
@@ -4153,7 +4158,7 @@
     <string name="auto_sync_account_title" msgid="2394463123733529506">"Өгөгдлийг автоматаар синк хийх"</string>
     <string name="auto_sync_personal_account_title" msgid="6844465157916100655">"Хувийн өгөгдлийг автоматаар синк хийх"</string>
     <string name="auto_sync_work_account_title" msgid="2403222633447522376">"Ажлын өгөгдлийг автоматаар синк хийх"</string>
-    <string name="auto_sync_account_summary" msgid="6316230976974033772">"Өгөгдлийг автоматаар дахин боловсруулахыг апп-д зөвшөөрөх"</string>
+    <string name="auto_sync_account_summary" msgid="6316230976974033772">"Өгөгдлийг автоматаар дахин боловсруулахыг аппад зөвшөөрөх"</string>
     <string name="account_sync_title" msgid="1570164819114297154">"Бүртгэл синк хийх"</string>
     <string name="account_sync_summary_some_on" msgid="1934556869158274053">"<xliff:g id="ID_2">%2$d</xliff:g>-с <xliff:g id="ID_1">%1$d</xliff:g> зүйлд синк асаалттай"</string>
     <string name="account_sync_summary_all_on" msgid="3634161204232431700">"Бүх зүйлд синк асаалттай"</string>
@@ -4161,7 +4166,7 @@
     <string name="enterprise_privacy_settings" msgid="2777101678653072889">"Удирдсан төхөөрөмжийн мэдээлэл"</string>
     <string name="enterprise_privacy_settings_summary_generic" msgid="5557859169062703683">"Таны байгууллагын удирдсан тохиргооны өөрчлөлт"</string>
     <string name="enterprise_privacy_settings_summary_with_name" msgid="4884479123751308407">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>-н удирдсан тохиргооны өөрчлөлт"</string>
-    <string name="enterprise_privacy_header" msgid="2680588186952421841">"Ажлынхаа өгөгдөлд хандах зөвшөөрлийг олгохын тулд таны байгууллага төхөөрөмжийн тохиргоог өөрчилж, програм хангамжийг суулгах шаардлагатай. \n\nДэлгэрэнгүй мэдээлэл авахын тулд байгууллагынхаа админтай холбогдоно уу."</string>
+    <string name="enterprise_privacy_header" msgid="2680588186952421841">"Ажлынхаа өгөгдөлд хандах зөвшөөрлийг олгохын тулд таны байгууллага төхөөрөмжийн тохиргоог өөрчилж, программ хангамжийг суулгах шаардлагатай. \n\nДэлгэрэнгүй мэдээлэл авахын тулд байгууллагынхаа админтай холбогдоно уу."</string>
     <string name="enterprise_privacy_exposure_category" msgid="4474576266043636753">"Таны байгууллага харах боломжтой мэдээллийн төрөл"</string>
     <string name="enterprise_privacy_exposure_changes_category" msgid="1877045221796512001">"Таны байгууллагын админы хийсэн өөрчлөлт"</string>
     <string name="enterprise_privacy_device_access_category" msgid="2967602674816237833">"Таны энэ төхөөрөмж дэх хандалт"</string>
@@ -4467,7 +4472,7 @@
     <string name="privacy_dashboard_summary" msgid="7916431309860824945">"Зөвшөөрөл, бүртгэлийн үйл ажиллагаа, хувийн өгөгдөл"</string>
     <string name="contextual_card_dismiss_remove" msgid="1750420285615827309">"Хасах"</string>
     <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"Хадгалах"</string>
-    <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"Энэ саналыг устгах уу?"</string>
+    <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"Энэ саналыг хасах уу?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"Зөвлөмжийг устгасан"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"Болих"</string>
     <string name="low_storage_summary" msgid="4562224870189133400">"Хадгалах сангийн багтаамж бага байна. <xliff:g id="PERCENTAGE">%1$s</xliff:g>-г ашигласан - <xliff:g id="FREE_SPACE">%2$s</xliff:g> сул"</string>
diff --git a/tests/CarDeveloperOptions/res/values-mr/arrays.xml b/tests/CarDeveloperOptions/res/values-mr/arrays.xml
index 66a7810..55fda50 100644
--- a/tests/CarDeveloperOptions/res/values-mr/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-mr/arrays.xml
@@ -38,7 +38,16 @@
     <item msgid="5827960506924849753">"10 मिनिटे"</item>
     <item msgid="6677424950124253938">"30 मिनिटे"</item>
   </string-array>
-    <!-- no translation found for dream_timeout_entries:7 (8271452751594598661) -->
+  <string-array name="dream_timeout_entries">
+    <item msgid="6487043225269853023">"कधीही नाही"</item>
+    <item msgid="2517785806387977252">"15 सेकंद"</item>
+    <item msgid="6347954399441173672">"३० सेकंद"</item>
+    <item msgid="4858305253279921789">"एक मिनिट"</item>
+    <item msgid="8109273437140044073">"दोन मिनिटे"</item>
+    <item msgid="2788593551142462622">"5 मिनिटे"</item>
+    <item msgid="8012672183888404961">"10 मिनिटे"</item>
+    <item msgid="8271452751594598661">"३० मिनिटे"</item>
+  </string-array>
   <string-array name="lock_after_timeout_entries">
     <item msgid="2232921187970351881">"तत्काळ"</item>
     <item msgid="2038544972632026612">"5 सेकंद"</item>
@@ -50,17 +59,47 @@
     <item msgid="811192536981678974">"10 मिनिटे"</item>
     <item msgid="7258394417241706272">"30 मिनिटे"</item>
   </string-array>
-    <!-- no translation found for entries_font_size:0 (2340391964816059553) -->
-    <!-- no translation found for entries_font_size:0 (6490061470416867723) -->
-    <!-- no translation found for entries_font_size:2 (1714184661981538355) -->
-    <!-- no translation found for entries_font_size:2 (1678068858001018666) -->
-    <!-- no translation found for wifi_status:3 (5848277343965362748) -->
-    <!-- no translation found for wifi_status_with_ssid:1 (6816207058895999545) -->
-    <!-- no translation found for wifi_status_with_ssid:3 (7547609081339573756) -->
-    <!-- no translation found for wifi_status_with_ssid:4 (5145158315060185414) -->
+  <string-array name="entries_font_size">
+    <item msgid="2340391964816059553">"लहान"</item>
+    <item msgid="591935967183159581">"डीफॉल्ट"</item>
+    <item msgid="1714184661981538355">"मोठा"</item>
+    <item msgid="6195563047686707484">"सर्वात मोठा"</item>
+  </string-array>
+  <string-array name="wifi_status">
+    <item msgid="1304883790721412351"></item>
+    <item msgid="4157625910392775808">"स्कॅन करत आहे…"</item>
+    <item msgid="5597394826455877834">"कनेक्ट करत आहे..."</item>
+    <item msgid="5848277343965362748">"ऑथेंटिकेट करत आहे…"</item>
+    <item msgid="3391238031431440676">"IP पत्ता मिळवत आहे…"</item>
+    <item msgid="5257597310494000224">"कनेक्ट केलेले आहे"</item>
+    <item msgid="8472497592913050396">"निलंबित"</item>
+    <item msgid="1228072488815999109">"डिस्कनेक्ट करत आहे..."</item>
+    <item msgid="7253087004422991731">"डिस्कनेक्ट केले"</item>
+    <item msgid="4169850917304751227">"अयशस्वी"</item>
+    <item msgid="6266658166690831131">"अवरोधित"</item>
+    <item msgid="4517230805854909775">"तात्पुरते खराब कनेक्शन टाळत आहे"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="4853670665485437464"></item>
+    <item msgid="6816207058895999545">"स्कॅन करत आहे…"</item>
+    <item msgid="8058143476674427024">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> वर कनेक्ट करत आहे…"</item>
+    <item msgid="7547609081339573756">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> सह ऑथेंटिकेट करत आहे…"</item>
+    <item msgid="5145158315060185414">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> वरून आयपी अ‍ॅड्रेस मिळवत आहे…"</item>
+    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> वर कनेक्ट केले आहे"</item>
+    <item msgid="6600156231416890902">"निलंबित"</item>
+    <item msgid="4133290864821295785">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> वरून डिस्कनेक्ट करत आहे…"</item>
+    <item msgid="3980154971187953257">"डिस्कनेक्ट केले"</item>
+    <item msgid="2847316776634969068">"अयशस्वी"</item>
+    <item msgid="4390990424746035383">"अवरोधित"</item>
+    <item msgid="3618248791367063949">"तात्पुरते खराब कनेक्शन टाळत आहे"</item>
+  </string-array>
     <!-- no translation found for wifi_tether_security:0 (5586343370515598801) -->
     <!-- no translation found for wifi_tether_security:1 (6136336549994615745) -->
-    <!-- no translation found for wifi_p2p_wps_setup:0 (5390235347963255303) -->
+  <string-array name="wifi_p2p_wps_setup">
+    <item msgid="5390235347963255303">"पुश बटण"</item>
+    <item msgid="7401896200768713930">"पीअर डिव्हाइसवरील पिन"</item>
+    <item msgid="4526848028011846710">"या डिव्हाइसवरील पिन"</item>
+  </string-array>
   <string-array name="wifi_p2p_status">
     <item msgid="8741947238021758201">"कनेक्ट केलेले आहे"</item>
     <item msgid="983792611851499732">"आमंत्रित केले"</item>
@@ -82,8 +121,13 @@
     <item msgid="1644506614010085798">"४"</item>
     <item msgid="3132506679404897150">"५"</item>
   </string-array>
-    <!-- no translation found for wifi_signal:1 (7882129634982603782) -->
-    <!-- no translation found for wifi_signal:4 (999948812884919584) -->
+  <string-array name="wifi_signal">
+    <item msgid="1709949377823900951">"खराब"</item>
+    <item msgid="7882129634982603782">"वाईट"</item>
+    <item msgid="6457357501905996224">"चांगले"</item>
+    <item msgid="405271628162918841">"उत्तम"</item>
+    <item msgid="999948812884919584">"उत्कृष्ट"</item>
+  </string-array>
   <string-array name="data_usage_data_range">
     <item msgid="8986775481492954015">"अंतिम 30 दिवस"</item>
     <item msgid="3211287705232736964">"वापर चक्र सेट करा..."</item>
@@ -119,7 +163,10 @@
     <item msgid="7330627471456865502">"MSCHAPV2"</item>
     <item msgid="6255179395132581882">"GTC"</item>
   </string-array>
-    <!-- no translation found for wifi_ip_settings:1 (4377002609760712163) -->
+  <string-array name="wifi_ip_settings">
+    <item msgid="2717196390555072244">"DHCP"</item>
+    <item msgid="4377002609760712163">"स्थिर"</item>
+  </string-array>
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"काहीही नाही"</item>
     <item msgid="1464741437353223198">"व्यक्तिचलित"</item>
@@ -234,16 +281,78 @@
     <item msgid="2633626056029384366">"बनावट स्थान"</item>
     <item msgid="8356842191824684631">"वाचण्‍याचा स्टोरेज"</item>
     <item msgid="5671906070163291500">"लिहिण्‍याचा स्टोरेज"</item>
-    <item msgid="2791955098549340418">"स्क्रीन चालू करा"</item>
+    <item msgid="2791955098549340418">"स्क्रीन सुरू करा"</item>
     <item msgid="5599435119609178367">"खाती मिळवा"</item>
     <item msgid="1165623660533024666">"पार्श्वभूमीमध्ये चालवा"</item>
     <item msgid="6423861043647911030">"प्रवेशयोग्यता आकारमान"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:3 (7836406246005211990) -->
-    <!-- no translation found for app_ops_labels:4 (3951439024549922598) -->
-    <!-- no translation found for app_ops_labels:8 (3597797992398484655) -->
-    <!-- no translation found for app_ops_labels:20 (3037159047591081136) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"स्थान"</item>
+    <item msgid="6656077694190491067">"स्थान"</item>
+    <item msgid="8790228218278477369">"स्थान"</item>
+    <item msgid="7836406246005211990">"व्हायब्रेट"</item>
+    <item msgid="3951439024549922598">"संपर्क वाचा"</item>
+    <item msgid="8802152411647068">"संपर्क सुधारित करा"</item>
+    <item msgid="229544934599698735">"कॉल लॉग वाचा"</item>
+    <item msgid="7396102294405899613">"कॉल लॉग सुधारित करा"</item>
+    <item msgid="3597797992398484655">"कॅलेंडर वाचा"</item>
+    <item msgid="2705975774250907343">"कॅलेंडर सुधारित करा"</item>
+    <item msgid="4668747371441932697">"स्थान"</item>
+    <item msgid="1487578921720243646">"पोस्ट सूचना"</item>
+    <item msgid="4636080349724146638">"स्थान"</item>
+    <item msgid="673510900286463926">"फोनवर कॉल करा"</item>
+    <item msgid="542083422784609790">"SMS/MMS वाचा"</item>
+    <item msgid="1033780373029588436">"SMS/MMS लिहा"</item>
+    <item msgid="5647111115517787488">"SMS/MMS प्राप्त करा"</item>
+    <item msgid="8591105601108455893">"SMS/MMS प्राप्त करा"</item>
+    <item msgid="7730995008517841903">"SMS/MMS प्राप्त करा"</item>
+    <item msgid="2613033109026626086">"SMS/MMS प्राप्त करा"</item>
+    <item msgid="3037159047591081136">"एसएमएस/MMS पाठवा"</item>
+    <item msgid="4726682243833913568">"SMS/MMS वाचा"</item>
+    <item msgid="6555678522277865572">"SMS/MMS लिहा"</item>
+    <item msgid="6981734935578130884">"सेटिंग्ज सुधारित करा"</item>
+    <item msgid="8705854389991425629">"शीर्षस्थानी रेखांकित करा"</item>
+    <item msgid="5861356020344153651">"सूचना अ‍ॅक्सेस करा"</item>
+    <item msgid="78432174621628659">"कॅमेरा"</item>
+    <item msgid="3986116419882154794">"ऑडिओ रेकॉर्ड करा"</item>
+    <item msgid="4516840825756409490">"ऑडिओ प्ले करा"</item>
+    <item msgid="6811712502798183957">"क्लिपबोर्ड वाचा"</item>
+    <item msgid="2780369012602289114">"क्लिपबोर्ड सुधारित करा"</item>
+    <item msgid="2331359440170850868">"मीडिया बटणे"</item>
+    <item msgid="6133599737122751231">"ऑडिओ फोकस"</item>
+    <item msgid="6844485713404805301">"प्रमुख व्हॉल्यूम"</item>
+    <item msgid="1600379420669104929">"आवाज व्हॉल्यूम"</item>
+    <item msgid="6296768210470214866">"रिंग व्हॉल्यूम"</item>
+    <item msgid="510690696071629241">"मीडिया व्हॉल्यूम"</item>
+    <item msgid="406861638631430109">"अलार्म व्हॉल्यूम"</item>
+    <item msgid="4715864795872233884">"सूचना व्हॉल्यूम"</item>
+    <item msgid="2311478519251301183">"ब्लूटूथ व्हॉल्यूम"</item>
+    <item msgid="5133991377896747027">"सक्रिय ठेवा"</item>
+    <item msgid="2464189519136248621">"स्थान"</item>
+    <item msgid="2062677934050803037">"स्थान"</item>
+    <item msgid="1735171933192715957">"वापर आकडेवारी मिळवा"</item>
+    <item msgid="1014093788778383554">"मायक्रोफोन निःशब्द/सशब्द करा"</item>
+    <item msgid="4199297950608622850">"टोस्ट दर्शवा"</item>
+    <item msgid="2527962435313398821">"प्रोजेक्‍ट मीडिया"</item>
+    <item msgid="5117506254221861929">"VPN सक्रिय करा"</item>
+    <item msgid="8291198322681891160">"लिहिण्याचा वॉलपेपर"</item>
+    <item msgid="7106921284621230961">"सहाय्य रचना"</item>
+    <item msgid="4496533640894624799">"सहाय्य स्क्रीनशॉट"</item>
+    <item msgid="2598847264853993611">"फोन स्थिती वाचा"</item>
+    <item msgid="9215610846802973353">"व्हॉइसमेल जोडा"</item>
+    <item msgid="9186411956086478261">"सिप वापरा"</item>
+    <item msgid="6884763100104539558">"केल्या जाणार्‍या कॉलवर प्रक्रिया करत आहे"</item>
+    <item msgid="125513972170580692">"फिंगरप्रिंट"</item>
+    <item msgid="2556071024281275619">"शरीर सेन्सर"</item>
+    <item msgid="617168514928339387">"सेल ब्रॉडकास्ट वाचा"</item>
+    <item msgid="7134693570516523585">"बनावट स्थान"</item>
+    <item msgid="7224489175375229399">"वाचण्‍याचा स्टोरेज"</item>
+    <item msgid="8472735063903258202">"लिहिण्‍याचा स्टोरेज"</item>
+    <item msgid="4069276819909595110">"स्क्रीन सुरू करा"</item>
+    <item msgid="1228338896751121025">"खाती मिळवा"</item>
+    <item msgid="3181581793459233672">"पार्श्वभूमीमध्ये चालवा"</item>
+    <item msgid="2340936043025374076">"प्रवेशयोग्यता आकारमान"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"लघु"</item>
     <item msgid="4816511817309094890">"मध्‍यम"</item>
@@ -260,7 +369,13 @@
     <item msgid="4627069151979553527">"Cursive"</item>
     <item msgid="6896773537705206194">"Small capitals"</item>
   </string-array>
-    <!-- no translation found for captioning_font_size_selector_titles:3 (2784236342175159295) -->
+  <string-array name="captioning_font_size_selector_titles">
+    <item msgid="1680223634161592855">"खूप लहान"</item>
+    <item msgid="5091603983404027034">"लहान"</item>
+    <item msgid="176844712416932112">"सामान्य"</item>
+    <item msgid="2784236342175159295">"मोठा"</item>
+    <item msgid="218913203203160606">"खूप मोठा"</item>
+  </string-array>
   <string-array name="captioning_edge_type_selector_titles">
     <item msgid="3865198759294188069">"डीफॉल्ट"</item>
     <item msgid="6488643537808152001">"काहीही नाही"</item>
@@ -275,7 +390,14 @@
     <item msgid="1874668269931014581">"75%"</item>
     <item msgid="6462911487571123954">"१००%"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"अ‍ॅप डीफॉल्ट वापरा"</item>
+    <item msgid="8611890312638868524">"काळ्‍यावर पांढरे"</item>
+    <item msgid="5891360837786277638">"पांढर्‍यावर काळे"</item>
+    <item msgid="2798457065945456853">"काळ्यावर पिवळे"</item>
+    <item msgid="5799049811524553967">"निळ्यावर पिवळे"</item>
+    <item msgid="3673930830658169860">"कस्टम"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"PPTP VPN"</item>
     <item msgid="1349760781118368659">"पूर्व-शेअर की सह L2TP/IPSec VPN"</item>
@@ -288,15 +410,32 @@
     <item msgid="2958623927055120839">"काहीही नाही"</item>
     <item msgid="1157046369795346308">"व्यक्तिचलित"</item>
   </string-array>
-    <!-- no translation found for vpn_states:4 (9135049670787351881) -->
+  <string-array name="vpn_states">
+    <item msgid="5408915841694583740">"डिस्कनेक्ट केले"</item>
+    <item msgid="8754480102834556765">"प्रारंभ करत आहे…"</item>
+    <item msgid="3351334355574270250">"कनेक्ट करत आहे..."</item>
+    <item msgid="8303882153995748352">"कनेक्ट केलेले आहे"</item>
+    <item msgid="9135049670787351881">"टाइमआउट"</item>
+    <item msgid="2124868417182583926">"अयशस्वी"</item>
+  </string-array>
   <string-array name="security_settings_premium_sms_values">
     <item msgid="1164265643455394443">"विचारा"</item>
     <item msgid="7718817231348607934">"कधीही अनुमती देऊ नका"</item>
     <item msgid="8184570120217958741">"नेहमी अनुमती द्या"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"सामान्य"</item>
+    <item msgid="5101233285497327432">"मध्यम"</item>
+    <item msgid="1555861583162930714">"कमी"</item>
+    <item msgid="1719683776264798117">"जटिल"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"सामान्य"</item>
+    <item msgid="6107138933849816768">"मध्यम"</item>
+    <item msgid="182695359839047859">"कमी"</item>
+    <item msgid="8577246509202964244">"गंभीर"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"कायम"</item>
     <item msgid="167418068739176448">"आघाडीच्या ॲक्टिव्हिटी"</item>
@@ -309,9 +448,9 @@
     <item msgid="6610439017684111046">"प्राप्तकर्ता"</item>
     <item msgid="7367606086319921117">"होम"</item>
     <item msgid="3344660712396741826">"शेवटच्या ॲक्टिव्हिटी"</item>
-    <item msgid="5006559348883303865">"कॅशे केलेली (ॲक्टिव्हिटी)"</item>
-    <item msgid="8633480732468137525">"कॅशे केलेला (ॲक्टिव्हिटी क्लायंट)"</item>
-    <item msgid="6248998242443333892">"कॅश   केलेला (रिक्त)"</item>
+    <item msgid="5006559348883303865">"कॅशे  केलेली (ॲक्टिव्हिटी)"</item>
+    <item msgid="8633480732468137525">"कॅशे  केलेला (ॲक्टिव्हिटी क्लायंट)"</item>
+    <item msgid="6248998242443333892">"कॅशे    केलेला (रिक्त)"</item>
   </string-array>
   <string-array name="color_picker">
     <item msgid="3151827842194201728">"हिरवट निळा"</item>
diff --git a/tests/CarDeveloperOptions/res/values-mr/config.xml b/tests/CarDeveloperOptions/res/values-mr/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-mr/config.xml
+++ b/tests/CarDeveloperOptions/res/values-mr/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-mr/strings.xml b/tests/CarDeveloperOptions/res/values-mr/strings.xml
index 674ed48..ca87602 100644
--- a/tests/CarDeveloperOptions/res/values-mr/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-mr/strings.xml
@@ -23,11 +23,11 @@
     <string name="deny" msgid="3998166389989144025">"नकार द्या"</string>
     <string name="device_info_default" msgid="1548919563979154348">"अज्ञात"</string>
     <plurals name="show_dev_countdown" formatted="false" msgid="3953785659137161981">
-      <item quantity="other">तुम्ही आता विकासक बनण्यापासून <xliff:g id="STEP_COUNT_1">%1$d</xliff:g> चरणे दूर आहात.</item>
-      <item quantity="one">तुम्ही आता विकासक बनण्यापासून <xliff:g id="STEP_COUNT_0">%1$d</xliff:g> चरण दूर आहात.</item>
+      <item quantity="other">तुम्ही आता डेव्हलपर बनण्यापासून <xliff:g id="STEP_COUNT_1">%1$d</xliff:g> पायऱ्या दूर आहात.</item>
+      <item quantity="one">तुम्ही आता डेव्हलपर बनण्यापासून <xliff:g id="STEP_COUNT_0">%1$d</xliff:g> पायरी दूर आहात.</item>
     </plurals>
-    <string name="show_dev_on" msgid="9075712234786224065">"आता तुम्ही एक विकासक आहात!"</string>
-    <string name="show_dev_already" msgid="7665948832405148689">"आवश्यकता नाही, तुम्ही आधीपासून एक विकासक आहात."</string>
+    <string name="show_dev_on" msgid="9075712234786224065">"आता तुम्ही एक डेव्हलपर आहात!"</string>
+    <string name="show_dev_already" msgid="7665948832405148689">"आवश्यकता नाही, तुम्ही आधीपासून एक डेव्हलपर आहात."</string>
     <string name="dev_settings_disabled_warning" msgid="3198732189395396721">"कृपया सर्वात आधी डेव्हलपर पर्याय सुरू करा."</string>
     <string name="header_category_wireless_networks" msgid="8968405993937795898">"वायरलेस आणि नेटवर्क"</string>
     <string name="header_category_system" msgid="4045988717359334410">"सिस्टम"</string>
@@ -38,7 +38,7 @@
     <string name="wfc_provisioned_switch_string" msgid="5446697646596639516">"वायफाय कॉलिंगची तरतूद केली"</string>
     <string name="eab_provisioned_switch_string" msgid="3921103790584572430">"EAB/उपस्थितीची तरतूद आहे"</string>
     <string name="cbrs_data_switch_string" msgid="9120919504831536183">"Cbrs डेटा"</string>
-    <string name="dsds_switch_string" msgid="2606482598327613264">"DSDS सुरु करा"</string>
+    <string name="dsds_switch_string" msgid="2606482598327613264">"DSDS सुरू करा"</string>
     <string name="dsds_dialog_title" msgid="3279829304547130217">"डिव्हाइस रीस्टार्ट करायचे का?"</string>
     <string name="dsds_dialog_message" msgid="571197076181853304">"ही सेटिंग बदलण्यासाठी तुम्ही तुमचे डिव्हाइस रीस्टार्ट करणे आवश्यक आहे."</string>
     <string name="dsds_dialog_confirm" msgid="4858826679303698086">"रीस्टार्ट"</string>
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"स्क्रीन वरील मजकूर आणखी लहान किंवा आणखी मोठा करा."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"आणखी लहान करा"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"आणखी मोठे करा"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"नमुना मजकूर"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Oz चा अद्भूत जादूगार"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"अध्याय 11: Oz चे अद्भूत पाचूंचे शहर"</string>
@@ -124,15 +123,15 @@
     <string name="bluetooth_device" msgid="3170974107364990008">"नाव नसलेले ब्लूटूथ डिव्हाइस"</string>
     <string name="progress_scanning" msgid="633923400401041181">"शोधत आहे"</string>
     <string name="bluetooth_no_devices_found" msgid="4396050022213494322">"जवळपास ब्लूटूथ डिव्हाइस आढळली नाहीत."</string>
-    <string name="bluetooth_notif_ticker" msgid="8398481099943141819">"ब्लूटूथ पेअरींग विनंती"</string>
-    <string name="bluetooth_notif_title" msgid="5090288898529286011">"पेअरींग विनंती"</string>
+    <string name="bluetooth_notif_ticker" msgid="8398481099943141819">"ब्लूटूथ पेअरिंग विनंती"</string>
+    <string name="bluetooth_notif_title" msgid="5090288898529286011">"पेअरिंग विनंती"</string>
     <string name="bluetooth_notif_message" msgid="6612367890895077938">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> सह जोडण्यासाठी टॅप करा."</string>
-    <string name="bluetooth_show_received_files" msgid="5060846395852236652">"मिळालेल्या फायली"</string>
-    <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"फायली ब्लूटूथद्वारे मिळाल्या आहेत"</string>
+    <string name="bluetooth_show_received_files" msgid="5060846395852236652">"मिळालेल्या फाइल"</string>
+    <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"फाइल ब्लूटूथद्वारे मिळाल्या आहेत"</string>
     <string name="device_picker" msgid="8345264486071697705">"ब्लूटूथ डिव्हाइस निवडा"</string>
-    <string name="bluetooth_ask_enablement" msgid="8716802066127746062">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्लूटूथ चालू करू इच्छितो"</string>
+    <string name="bluetooth_ask_enablement" msgid="8716802066127746062">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्लूटूथ सुरू करू इच्छितो"</string>
     <string name="bluetooth_ask_disablement" msgid="7125319551097350783">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्लूटूथ बंद करू इच्छितो"</string>
-    <string name="bluetooth_ask_enablement_no_name" msgid="6105893027185475233">"अ‍ॅप ब्लूटूथ चालू करु इच्छित आहे"</string>
+    <string name="bluetooth_ask_enablement_no_name" msgid="6105893027185475233">"अ‍ॅप ब्लूटूथ सुरू करु इच्छित आहे"</string>
     <string name="bluetooth_ask_disablement_no_name" msgid="8648888502291681310">"अ‍ॅप ब्लूटूथ बंद करू इच्छितो"</string>
     <string name="bluetooth_ask_discovery" product="tablet" msgid="6871595755186170115">"<xliff:g id="APP_NAME">%1$s</xliff:g> तुमचा टॅबलेट अन्य ब्लूटूथ डीव्हाइससाठी <xliff:g id="TIMEOUT">%2$d</xliff:g> सेकंदांसाठी दृश्यमान करू इच्छितो."</string>
     <string name="bluetooth_ask_discovery" product="default" msgid="3388041479101348095">"<xliff:g id="APP_NAME">%1$s</xliff:g> तुमचा फोन अन्य ब्लूटूथ डीव्हाइससाठी <xliff:g id="TIMEOUT">%2$d</xliff:g> सेकंदांसाठी दृश्यमान करू इच्छितो."</string>
@@ -142,15 +141,15 @@
     <string name="bluetooth_ask_lasting_discovery" product="default" msgid="7796723473397303412">"<xliff:g id="APP_NAME">%1$s</xliff:g> तुमचा फोन इतर ब्लूटूथ डीव्हाइससाठी दृश्‍यमान करू इच्छित आहे. तुम्ही ब्लूटूथ सेटिंग्जमध्ये नंतर हे बदलू शकता."</string>
     <string name="bluetooth_ask_lasting_discovery_no_name" product="tablet" msgid="5961921359655434504">"अ‍ॅप तुमचा टॅबलेट इतर ब्लूटूथ डीव्हाइससाठी दृश्‍यमान करू इच्छित आहे. तुम्ही ब्लूटूथ सेटिंग्जमध्ये नंतर हे बदलू शकता."</string>
     <string name="bluetooth_ask_lasting_discovery_no_name" product="default" msgid="3585910858758443872">"अ‍ॅप तुमचा फोन इतर ब्लूटूथ डीव्हाइससाठी दृश्‍यमान करू इच्छित आहे. तुम्ही ब्लूटूथ सेटिंग्जमध्ये नंतर हे बदलू शकता."</string>
-    <string name="bluetooth_ask_enablement_and_discovery" product="tablet" msgid="5676466923424941153">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्लूटूथ चालू करू इच्छितो आणि <xliff:g id="TIMEOUT">%2$d</xliff:g> सेकंदांसाठी तुमचा टॅबलेट अन्य डीव्हाइससाठी दृश्‍यमान करू इच्छितो."</string>
-    <string name="bluetooth_ask_enablement_and_discovery" product="default" msgid="507088376226791063">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्लूटूथ चालू करू इच्छितो आणि <xliff:g id="TIMEOUT">%2$d</xliff:g> सेकंदांसाठी तुमचा फोन अन्य डीव्हाइससाठी दृश्‍यमान करू इच्छितो."</string>
-    <string name="bluetooth_ask_enablement_and_discovery_no_name" product="tablet" msgid="1164681893121736219">"अ‍ॅप ब्लूटूथ चालू करु इच्छित आहे आणि इतर डीव्हाइससाठी <xliff:g id="TIMEOUT">%1$d</xliff:g> सेकंदांकरिता तुमचा टॅबलेट दृश्यमान बनवू इच्छित आहे."</string>
-    <string name="bluetooth_ask_enablement_and_discovery_no_name" product="default" msgid="2542247690119921188">"अ‍ॅप ब्लूटूथ चालू करु इच्छित आहे आणि इतर डीव्हाइससाठी <xliff:g id="TIMEOUT">%1$d</xliff:g> सेकंदांकरिता तुमचा फोन दृश्यमान बनवू इच्छित आहे."</string>
-    <string name="bluetooth_ask_enablement_and_lasting_discovery" product="tablet" msgid="7118362102769177771">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्लूटूथ चालू करु इच्छित आहे आणि तुमचा टॅबलेट इतर डीव्हाइससाठी दृश्‍यमान करू इच्छित आहे. तुम्ही ब्लूटूथ सेटिंग्जमध्ये नंतर हे बदलू शकता."</string>
-    <string name="bluetooth_ask_enablement_and_lasting_discovery" product="default" msgid="2577488464813970727">"<xliff:g id="APP_NAME">%1$s</xliff:g> अ‍ॅप ब्लूटूथ चालू करु इच्छित आहे आणि तुमचा फोन इतर डीव्हाइससाठी दृश्‍यमान करू इच्छित आहे. तुम्ही ब्लूटूथ सेटिंग्जमध्ये नंतर हे बदलू शकता."</string>
-    <string name="bluetooth_ask_enablement_and_lasting_discovery_no_name" product="tablet" msgid="7083038132794842691">"अ‍ॅप ब्लूटूथ चालू करु इच्छित आहे आणि तुमचा टॅबलेट इतर डीव्हाइससाठी दृश्‍यमान करू इच्छित आहे. तुम्ही ब्लूटूथ सेटिंग्जमध्ये नंतर हे बदलू शकता."</string>
-    <string name="bluetooth_ask_enablement_and_lasting_discovery_no_name" product="default" msgid="3541668604020109525">"अ‍ॅप ब्लूटूथ चालू करु इच्छित आहे आणि तुमचा फोन इतर डीव्हाइससाठी दृश्‍यमान करू इच्छित आहे. तुम्ही ब्लूटूथ सेटिंग्जमध्ये नंतर हे बदलू शकता."</string>
-    <string name="bluetooth_turning_on" msgid="6935183036449748493">"ब्लूटूथ चालू करत आहे…"</string>
+    <string name="bluetooth_ask_enablement_and_discovery" product="tablet" msgid="5676466923424941153">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्लूटूथ सुरू करू इच्छितो आणि <xliff:g id="TIMEOUT">%2$d</xliff:g> सेकंदांसाठी तुमचा टॅबलेट अन्य डीव्हाइससाठी दृश्‍यमान करू इच्छितो."</string>
+    <string name="bluetooth_ask_enablement_and_discovery" product="default" msgid="507088376226791063">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्लूटूथ सुरू करू इच्छितो आणि <xliff:g id="TIMEOUT">%2$d</xliff:g> सेकंदांसाठी तुमचा फोन अन्य डीव्हाइससाठी दृश्‍यमान करू इच्छितो."</string>
+    <string name="bluetooth_ask_enablement_and_discovery_no_name" product="tablet" msgid="1164681893121736219">"अ‍ॅप ब्लूटूथ सुरू करु इच्छित आहे आणि इतर डीव्हाइससाठी <xliff:g id="TIMEOUT">%1$d</xliff:g> सेकंदांकरिता तुमचा टॅबलेट दृश्यमान बनवू इच्छित आहे."</string>
+    <string name="bluetooth_ask_enablement_and_discovery_no_name" product="default" msgid="2542247690119921188">"अ‍ॅप ब्लूटूथ सुरू करु इच्छित आहे आणि इतर डीव्हाइससाठी <xliff:g id="TIMEOUT">%1$d</xliff:g> सेकंदांकरिता तुमचा फोन दृश्यमान बनवू इच्छित आहे."</string>
+    <string name="bluetooth_ask_enablement_and_lasting_discovery" product="tablet" msgid="7118362102769177771">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्लूटूथ सुरू करु इच्छित आहे आणि तुमचा टॅबलेट इतर डीव्हाइससाठी दृश्‍यमान करू इच्छित आहे. तुम्ही ब्लूटूथ सेटिंग्जमध्ये नंतर हे बदलू शकता."</string>
+    <string name="bluetooth_ask_enablement_and_lasting_discovery" product="default" msgid="2577488464813970727">"<xliff:g id="APP_NAME">%1$s</xliff:g> अ‍ॅप ब्लूटूथ सुरू करु इच्छित आहे आणि तुमचा फोन इतर डीव्हाइससाठी दृश्‍यमान करू इच्छित आहे. तुम्ही ब्लूटूथ सेटिंग्जमध्ये नंतर हे बदलू शकता."</string>
+    <string name="bluetooth_ask_enablement_and_lasting_discovery_no_name" product="tablet" msgid="7083038132794842691">"अ‍ॅप ब्लूटूथ सुरू करु इच्छित आहे आणि तुमचा टॅबलेट इतर डीव्हाइससाठी दृश्‍यमान करू इच्छित आहे. तुम्ही ब्लूटूथ सेटिंग्जमध्ये नंतर हे बदलू शकता."</string>
+    <string name="bluetooth_ask_enablement_and_lasting_discovery_no_name" product="default" msgid="3541668604020109525">"अ‍ॅप ब्लूटूथ सुरू करु इच्छित आहे आणि तुमचा फोन इतर डीव्हाइससाठी दृश्‍यमान करू इच्छित आहे. तुम्ही ब्लूटूथ सेटिंग्जमध्ये नंतर हे बदलू शकता."</string>
+    <string name="bluetooth_turning_on" msgid="6935183036449748493">"ब्लूटूथ सुरू करत आहे…"</string>
     <string name="bluetooth_turning_off" msgid="9214026723789756620">"ब्लूटूथ बंद करत आहे…"</string>
     <string name="bluetooth_connection_permission_request" msgid="2382506002340643398">"ब्लूटूथ कनेक्शन विनंती"</string>
     <string name="bluetooth_connection_notif_message" msgid="6824654400460127108">"\"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\" शी कनेक्ट करण्यासाठी टॅप करा."</string>
@@ -164,7 +163,7 @@
     <string name="bluetooth_sap_request" msgid="6318039677671263261">"सिम प्रवेश विनंती"</string>
     <string name="bluetooth_sap_acceptance_dialog_text" msgid="1909352413109340355">"<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g> आपल्या सिम कार्डवर प्रवेश करू इच्छित आहे. सिम कार्डवर प्रवेश मंजूर केल्यामुळे कनेक्शनच्या कालावधीसाठी आपल्या डिव्हाइसवरील डेटा कनेक्टिव्हिटी अक्षम होईल. <xliff:g id="DEVICE_NAME_1">%2$s?</xliff:g> वर प्रवेश द्या"</string>
     <string name="bluetooth_device_name_summary" msgid="8661066392056595005">"इतर डिव्‍हाइसना \'<xliff:g id="DEVICE_NAME">^1</xliff:g>\' म्‍हणून दिसत आहे"</string>
-    <string name="bluetooth_off_footer" msgid="7658444560543730571">"इतर डिव्हाइसशी कनेक्ट करण्यासाठी ब्लूटूथ चालू करा."</string>
+    <string name="bluetooth_off_footer" msgid="7658444560543730571">"इतर डिव्हाइसशी कनेक्ट करण्यासाठी ब्लूटूथ सुरू करा."</string>
     <string name="bluetooth_paired_device_title" msgid="8361860197780425286">"तुमचे डिव्हाइस"</string>
     <string name="bluetooth_pairing_page_title" msgid="9053463656712597709">"नवीन डिव्हाइस जोडा"</string>
     <string name="bluetooth_pref_summary" product="tablet" msgid="3601662966604648212">"तुमच्या टॅबलेटला जवळपासच्या ब्लूटूथ डिव्हाइसशी संवाद साधण्याची अनुमती द्या"</string>
@@ -313,7 +312,7 @@
     <string name="roaming_enable" msgid="2108142024297441116">"रोमिंग असताना डेटा सेवांवर कनेक्ट करा"</string>
     <string name="roaming_disable" msgid="1915440242079953809">"रोमिंगमध्ये असताना डेटा सेवांना कनेक्ट करा"</string>
     <string name="roaming_reenable_message" msgid="8388505868655113258">"तुम्ही डेटा रोमिंग बंद करून तुमचे होम नेटवर्क सोडल्यामुळे तुम्ही डेटा कनेक्टिव्हिटी गमावली आहे."</string>
-    <string name="roaming_turn_it_on_button" msgid="4370846458830537578">"हे चालू करा"</string>
+    <string name="roaming_turn_it_on_button" msgid="4370846458830537578">"हे सुरू करा"</string>
     <string name="roaming_warning" msgid="5488050911277592868">"तुम्हाला बर्‍याच प्रमाणात शुल्‍क लागू शकते."</string>
     <string name="roaming_warning_multiuser" product="tablet" msgid="7090388691615686893">"जेव्हा तुम्ही डेटा रोमिंगला अनुमती देता, तेव्हा तुम्हाला महत्त्वाचे रोमिंग शुल्क आकारले जाऊ शकते!\n\nही सेटिंग या टॅब्लेटवरील सर्व वापरकर्ते प्रभावित करते."</string>
     <string name="roaming_warning_multiuser" product="default" msgid="6999819541078827556">"जेव्हा तुम्ही डेटा रोमिंगला अनुमती देता, तेव्हा आपल्याकडून महत्त्वाचे रोमिंग शुल्क आकारले जाऊ शकते!\n\nही सेटिंग या फोनवरील सर्व वापरकर्ते प्रभावित करते."</string>
@@ -444,13 +443,13 @@
     <string name="security_settings_fingerprint_enroll_introduction_message_unlock_disabled" msgid="1640839304679275468">"फोन अनलॉक करण्यासाठी किंवा खरेदींना मंजूरी देण्यासाठी तुमचे फिंगरप्रिंट वापरा.\n\nटीप: तुम्ही हे डिव्हाइस अनलॉक करण्यासाठी तुम्‍ही तुमचे फिंगरप्रिंट वापरू शकत नाही. अधिक माहितीसाठी संस्थेच्या प्रशासकाशी संपर्क साधा."</string>
     <string name="security_settings_fingerprint_enroll_introduction_message_setup" msgid="6734490666593320711">"फोन अनलॉक करण्यासाठी किंवा खरेदीला मंजुरी देण्यासाठी तुमची फिंगरप्रिंट वापरा.\n\nटीप: क्लिष्ट पॅटर्न किंवा पिनच्या तुलनेत तुमची फिंगरप्रिंट ही कमी सुरक्षित असू शकते."</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel" msgid="9168637333731599827">"रद्द करा"</string>
-    <string name="security_settings_fingerprint_enroll_introduction_continue" msgid="271662150372486535">"सुरु ठेवा"</string>
+    <string name="security_settings_fingerprint_enroll_introduction_continue" msgid="271662150372486535">"सुरू ठेवा"</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel_setup" msgid="756928427429893070">"वगळा"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue_setup" msgid="4125977169169671144">"पुढील"</string>
     <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"फिंगरप्रिंट पायरी वगळायची?"</string>
     <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"फिंगरप्रिंट सेटअपला फक्त एक किंवा दोन मिनिटे लागतात. ही पायरी वगळली तरी तुम्ही नंतर सेटिंग्जमध्ये जाऊन तुमची फिंगरप्रिंट जोडू शकता."</string>
     <string name="lock_screen_intro_skip_title" msgid="5307431665496346914">"स्क्रीन लॉक वगळायचे?"</string>
-    <string name="lock_screen_intro_skip_dialog_text_frp" product="tablet" msgid="7553945981266845264">"डिव्हाइस संरक्षण वैशिष्ट्ये चालू होणार नाहीत. हा टॅब्लेट हरवल्यास, चोरी झाल्यास किंवा रीसेट केल्यास तुम्ही इतरांना तो वापरण्यापासून रोखू शकणार नाही."</string>
+    <string name="lock_screen_intro_skip_dialog_text_frp" product="tablet" msgid="7553945981266845264">"डिव्हाइस संरक्षण वैशिष्ट्ये सुरू होणार नाहीत. हा टॅब्लेट हरवल्यास, चोरी झाल्यास किंवा रीसेट केल्यास तुम्ही इतरांना तो वापरण्यापासून रोखू शकणार नाही."</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="device" msgid="1378243257238015603">"डिव्हाइस संरक्षण वैशिष्ट्ये सुरू होणार नाहीत. हे डिव्हाइस हरवल्यास, चोरी झाल्यास किंवा रीसेट केल्यास तुम्ही इतरांना तो वापरण्यापासून रोखू शकणार नाही."</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="default" msgid="8395540117461339748">"डिव्हाइस संरक्षण वैशिष्ट्ये सुरू होणार नाहीत. हा फोन हरवल्यास, चोरी झाल्यास किंवा रीसेट केल्यास तुम्ही इतरांना तो वापरण्यापासून रोखू शकणार नाही."</string>
     <string name="lock_screen_intro_skip_dialog_text" product="tablet" msgid="7572334562915795226">"डिव्हाइस संरक्षण वैशिष्ट्ये सुरू होणार नाहीत. हा टॅब्लेट हरवल्यास किंवा चोरी झाल्यास तुम्ही इतरांना तो वापरण्यापासून रोखू शकणार नाही."</string>
@@ -509,14 +508,14 @@
     <string name="crypt_keeper_encrypt_title" product="tablet" msgid="2292129135369853167">"टॅबलेट एंक्रिप्ट करा"</string>
     <string name="crypt_keeper_encrypt_title" product="default" msgid="3110852053238357832">"फोन एंक्रिप्ट करा"</string>
     <string name="crypt_keeper_encrypted_summary" msgid="2438498691741626642">"एंक्रिप्ट केले"</string>
-    <string name="crypt_keeper_desc" product="tablet" msgid="9142792050252407734">"तुम्ही तुमची खाती, सेटिंग्ज, डाउनलोड केलेले अ‍ॅप्स आणि त्यांचा डेटा, मीडिया आणि इतर फायली एंक्रिप्ट करू शकता. तुम्ही तुमचा टॅब्लेट एंक्रिप्ट केल्यानंतर, तुम्ही स्क्रीन लॉक (म्हणजे, एक पॅटर्न किंवा अंकीय पिन किंवा पासवर्ड) सेट केला आहे हे गृहित धरून, प्रत्येकवेळी तुम्ही टॅब्लेट चालू करता तेव्हा त्याचे एंक्रिप्ट करण्‍यासाठी आपल्‍याला स्क्रीन अनलॉक करण्‍याची आवश्यकता असेल. एंक्रिप्ट करण्‍याचा अन्य एकमेव मार्ग तुमचा सर्व डेटा मिटवून, फॅक्‍टरी डेटा रीसेट करणे हा होय.\n\nएंक्रिप्शनला एक तास किंवा अधिक वेळ लागू शकतो. तुम्ही संपूर्ण प्रक्रियेत चार्ज केलेल्या बॅटरीसह प्रारंभ करणे आणि तुमचा टॅब्लेट प्लग इन केलेला ठेवणे आवश्यक आहे. तुम्ही त्यात व्यत्यय आणल्यास, तुम्ही तुमचा काही किंवा सर्व डेटा गमवाल."</string>
-    <string name="crypt_keeper_desc" product="default" msgid="1996334685607444282">"तुम्ही तुमची खाती, सेटिंग्ज, डाउनलोड केलेली अ‍ॅप्स आणि त्यांचा डेटा, मीडिया आणि इतर फायली एंक्रिप्ट करू शकता. तुम्ही तुमचा फोन एंक्रिप्ट केल्यानंतर, तुम्ही स्क्रीन लॉक (म्हणजे, एक पॅटर्न किंवा अंकीय पिन किंवा पासवर्ड) सेट केला आहे हे गृहित धरून, प्रत्येकवेळी तुम्ही फोन चालू करता तेव्हा त्याचे एंक्रिप्ट करण्‍यासाठी आपल्‍याला स्क्रीन अनलॉक करण्‍याची आवश्यकता असेल. एंक्रिप्ट करण्‍याचा अन्य एकमेव मार्ग तुमचा सर्व डेटा मिटवून, फॅक्‍टरी डेटा रीसेट करणे हा होय.\n\nएंक्रिप्टीकरणास एक तास किंवा अधिक वेळ लागू शकतो. तुम्ही संपूर्ण प्रक्रियेत चार्ज केलेल्या बॅटरीसह प्रारंभ करणे आणि तुमचा फोन प्लग इन केलेला ठेवणे आवश्यक आहे. तुम्ही त्यात व्यत्यय आणल्यास, तुम्ही तुमचा काही किंवा सर्व डेटा गमवाल."</string>
+    <string name="crypt_keeper_desc" product="tablet" msgid="9142792050252407734">"तुम्ही तुमची खाती, सेटिंग्ज, डाउनलोड केलेले अ‍ॅप्स आणि त्यांचा डेटा, मीडिया आणि इतर फाइल एंक्रिप्ट करू शकता. तुम्ही तुमचा टॅब्लेट एंक्रिप्ट केल्यानंतर, तुम्ही स्क्रीन लॉक (म्हणजे, एक पॅटर्न किंवा अंकीय पिन किंवा पासवर्ड) सेट केला आहे हे गृहित धरून, प्रत्येकवेळी तुम्ही टॅब्लेट सुरू करता तेव्हा त्याचे एंक्रिप्ट करण्‍यासाठी आपल्‍याला स्क्रीन अनलॉक करण्‍याची आवश्यकता असेल. एंक्रिप्ट करण्‍याचा अन्य एकमेव मार्ग तुमचा सर्व डेटा मिटवून, फॅक्‍टरी डेटा रीसेट करणे हा होय.\n\nएंक्रिप्शनला एक तास किंवा अधिक वेळ लागू शकतो. तुम्ही संपूर्ण प्रक्रियेत चार्ज केलेल्या बॅटरीसह प्रारंभ करणे आणि तुमचा टॅब्लेट प्लग इन केलेला ठेवणे आवश्यक आहे. तुम्ही त्यात व्यत्यय आणल्यास, तुम्ही तुमचा काही किंवा सर्व डेटा गमवाल."</string>
+    <string name="crypt_keeper_desc" product="default" msgid="1996334685607444282">"तुम्ही तुमची खाती, सेटिंग्ज, डाउनलोड केलेली अ‍ॅप्स आणि त्यांचा डेटा, मीडिया आणि इतर फाइल एंक्रिप्ट करू शकता. तुम्ही तुमचा फोन एंक्रिप्ट केल्यानंतर, तुम्ही स्क्रीन लॉक (म्हणजे, एक पॅटर्न किंवा अंकीय पिन किंवा पासवर्ड) सेट केला आहे हे गृहित धरून, प्रत्येकवेळी तुम्ही फोन सुरू करता तेव्हा त्याचे एंक्रिप्ट करण्‍यासाठी आपल्‍याला स्क्रीन अनलॉक करण्‍याची आवश्यकता असेल. एंक्रिप्ट करण्‍याचा अन्य एकमेव मार्ग तुमचा सर्व डेटा मिटवून, फॅक्‍टरी डेटा रीसेट करणे हा होय.\n\nएंक्रिप्टीकरणास एक तास किंवा अधिक वेळ लागू शकतो. तुम्ही संपूर्ण प्रक्रियेत चार्ज केलेल्या बॅटरीसह प्रारंभ करणे आणि तुमचा फोन प्लग इन केलेला ठेवणे आवश्यक आहे. तुम्ही त्यात व्यत्यय आणल्यास, तुम्ही तुमचा काही किंवा सर्व डेटा गमवाल."</string>
     <string name="crypt_keeper_button_text" product="tablet" msgid="7918671468758813824">"टॅबलेट एंक्रिप्ट करा"</string>
     <string name="crypt_keeper_button_text" product="default" msgid="8737394386627318489">"फोन एंक्रिप्ट करा"</string>
     <string name="crypt_keeper_low_charge_text" msgid="1422879728632636311">"तुमची बॅटरी चार्ज करा आणि पुन्हा प्रयत्न करा."</string>
     <string name="crypt_keeper_unplugged_text" msgid="6597684068340036200">"तुमचा चार्जर प्लग इन करा आणि पुन्हा प्रयत्न करा."</string>
     <string name="crypt_keeper_dialog_need_password_title" msgid="8532211509636340535">"कोणताही लॉक स्क्रीन पिन किंवा पासवर्ड नाही"</string>
-    <string name="crypt_keeper_dialog_need_password_message" msgid="1341590897367808702">"तुम्ही एनक्रिप्शन सुरु करण्यापूर्वी तुम्हाला एक लॉक स्क्रीन पिन ‍किंवा पासवर्ड सेट करण्याची आवश्यकता आहे."</string>
+    <string name="crypt_keeper_dialog_need_password_message" msgid="1341590897367808702">"तुम्ही एनक्रिप्शन सुरू करण्यापूर्वी तुम्हाला एक लॉक स्क्रीन पिन ‍किंवा पासवर्ड सेट करण्याची आवश्यकता आहे."</string>
     <string name="crypt_keeper_confirm_title" msgid="8884417036062084547">"एंक्रिप्ट करायचे?"</string>
     <string name="crypt_keeper_final_desc" product="tablet" msgid="2713708841024805586">"एंक्रिप्शन कार्य परत न करता येणारे आहे आणि तुम्ही त्यात व्यत्यय आणल्यास, तुमचा डेटा गमावेल. एंक्रिप्शनला एखादा तास किंवा जास्त वेळ लागतो, यादरम्यान टॅबलेट कित्येक वेळा रीस्टार्ट होईल."</string>
     <string name="crypt_keeper_final_desc" product="default" msgid="2483549885938505746">"एंक्रिप्शन कार्य परत न करता येणारे आहे आणि तुम्ही त्यात व्यत्यय आणल्यास, तुमचा डेटा गमावेल. एंक्रिप्शनला एखादा तास किंवा जास्त वेळ लागतो, यादरम्यान फोन कित्येक वेळा रीस्टार्ट होईल."</string>
@@ -525,16 +524,16 @@
     <string name="crypt_keeper_setup_description" product="default" msgid="3391750289253411494">"तुमचा फोन एंक्रिप्ट केला जात असताना प्रतीक्षा करा. <xliff:g id="PERCENT">^1</xliff:g>% पूर्ण."</string>
     <string name="crypt_keeper_setup_time_remaining" product="tablet" msgid="7841271240063858796">"तुमचा टॅब्लेट एंक्रिप्ट केला जात असताना प्रतीक्षा करा. शिल्लक वेळ: <xliff:g id="DURATION">^1</xliff:g>"</string>
     <string name="crypt_keeper_setup_time_remaining" product="default" msgid="8049188590821796173">"तुमचा फोन एंक्रिप्ट केला जात असताना प्रतीक्षा करा. शिल्लक वेळ: <xliff:g id="DURATION">^1</xliff:g>"</string>
-    <string name="crypt_keeper_force_power_cycle" product="tablet" msgid="9168213181845231795">"तुमचा टॅबलेट अनलॉक करण्‍यासाठी, तो बंद करा आणि नंतर चालू करा."</string>
+    <string name="crypt_keeper_force_power_cycle" product="tablet" msgid="9168213181845231795">"तुमचा टॅबलेट अनलॉक करण्‍यासाठी, तो बंद करा आणि नंतर सुरू करा."</string>
     <string name="crypt_keeper_force_power_cycle" product="default" msgid="1182690469082263666">"तुमचा फोन अनलॉक करण्‍यासाठी, तो बंद करा आणि नंतर सुरू करा."</string>
     <string name="crypt_keeper_warn_wipe" msgid="700814581500057050">"चेतावणी: अनलॉक करण्‍याच्या आणखी <xliff:g id="COUNT">^1</xliff:g> अयशस्‍वी प्रयत्नांनंतर तुमचे डिव्हाइस पुसले जाईल."</string>
     <string name="crypt_keeper_enter_password" msgid="726933635335219421">"तुमचा पासवर्ड टाइप करा"</string>
     <string name="crypt_keeper_failed_title" msgid="1906382607060855782">"एंक्रिप्शन अयशस्वी"</string>
-    <string name="crypt_keeper_failed_summary" product="tablet" msgid="7844833877734529625">"कूटबद्धीकरणात व्यत्यय आला आणि हे पूर्ण होऊ शकत नाही. परिणामस्वरूप, आपल्या टॅबलेटवरील डेटा यापुढे प्रवेशयोग्य राहणार नाही. \n\n तुमचा टॅबलेट वापरून पुन्हा सुरु करण्यासाठी, तुम्हाला फॅक्टरी रीसेट करण्याची आवश्यकता आहे. रीसेट केल्यानंतर तुम्ही तुमचा टॅबलेट सेट करता, तेव्हा आपल्याकडे आपल्या Google खात्यावर बॅकअप घेतलेला कोणताही डेटा रीस्टोअर करण्याची संधी असेल."</string>
-    <string name="crypt_keeper_failed_summary" product="default" msgid="2895589681839090312">"कूटबद्धीकरणात व्यत्यय आला आणि पूर्ण होऊ शकत नाही. परिणामस्वरूप, आपल्या फोनवरील डेटा यापुढे प्रवेशयोग्य नाही.\n\nतुमचा फोन वापरणे पुन्हा सुरु करण्यासाठी, तुम्हाला फॅक्टरी रीसेट करण्याची आवश्यकता आहे. रीसेट केल्यानंतर जेव्हा तुम्ही तुमचा फोन सेट करता, तेव्हा आपल्याकडे आपल्या Google खात्यावर बॅकअप घेतलेला कोणताही डेटा रीस्टोअर करण्याची संधी असेल."</string>
+    <string name="crypt_keeper_failed_summary" product="tablet" msgid="7844833877734529625">"कूटबद्धीकरणात व्यत्यय आला आणि हे पूर्ण होऊ शकत नाही. परिणामस्वरूप, आपल्या टॅबलेटवरील डेटा यापुढे प्रवेशयोग्य राहणार नाही. \n\n तुमचा टॅबलेट वापरून पुन्हा सुरू करण्यासाठी, तुम्हाला फॅक्टरी रीसेट करण्याची आवश्यकता आहे. रीसेट केल्यानंतर तुम्ही तुमचा टॅबलेट सेट करता, तेव्हा आपल्याकडे आपल्या Google खात्यावर बॅकअप घेतलेला कोणताही डेटा रीस्टोअर करण्याची संधी असेल."</string>
+    <string name="crypt_keeper_failed_summary" product="default" msgid="2895589681839090312">"कूटबद्धीकरणात व्यत्यय आला आणि पूर्ण होऊ शकत नाही. परिणामस्वरूप, आपल्या फोनवरील डेटा यापुढे प्रवेशयोग्य नाही.\n\nतुमचा फोन वापरणे पुन्हा सुरू करण्यासाठी, तुम्हाला फॅक्टरी रीसेट करण्याची आवश्यकता आहे. रीसेट केल्यानंतर जेव्हा तुम्ही तुमचा फोन सेट करता, तेव्हा आपल्याकडे आपल्या Google खात्यावर बॅकअप घेतलेला कोणताही डेटा रीस्टोअर करण्याची संधी असेल."</string>
     <string name="crypt_keeper_data_corrupt_title" msgid="6561535293845985713">"विकूटन अयशस्वी"</string>
-    <string name="crypt_keeper_data_corrupt_summary" product="tablet" msgid="7018748502706237323">"तुम्ही एंटर केलेला पासवर्ड चुकीचा आहे, परंतु दुर्दैवाने तुमचा डेटा दूषित आहे. \n\nतुमचा टॅबलेट वापरणे पुनः सुरु करण्यासाठी, तुम्हाला फॅक्टरी रीसेट करणे आवश्यक आहे. रीसेट केल्यानंतर तुम्ही तुमचा टॅबलेट सेट करता, तेव्हा तुम्हाला आपल्या Google खात्यावर बॅक अप घेतलेला कोणताही डेटा रीस्टोअर करण्याची संधी असेल."</string>
-    <string name="crypt_keeper_data_corrupt_summary" product="default" msgid="5798580588985326937">"तुम्ही एंटर केलेला पासवर्ड बरोबर आहे, परंतु दुर्दैवाने तुमचा डेटा दूषित आहे. \n\nतुमचा फोन वापरणे पुनः सुरु करण्यासाठी, तुम्हाला फॅक्टरी रीसेट करणे आवश्यक आहे. रीसेट केल्यानंतर तुम्ही तुमचा फोन सेट करता, तेव्हा तुम्हाला आपल्या Google खात्यावर बॅक अप घेतलेला कोणताही डेटा रीस्टोअर करण्याची संधी असेल."</string>
+    <string name="crypt_keeper_data_corrupt_summary" product="tablet" msgid="7018748502706237323">"तुम्ही एंटर केलेला पासवर्ड चुकीचा आहे, परंतु दुर्दैवाने तुमचा डेटा दूषित आहे. \n\nतुमचा टॅबलेट वापरणे पुनः सुरू करण्यासाठी, तुम्हाला फॅक्टरी रीसेट करणे आवश्यक आहे. रीसेट केल्यानंतर तुम्ही तुमचा टॅबलेट सेट करता, तेव्हा तुम्हाला आपल्या Google खात्यावर बॅक अप घेतलेला कोणताही डेटा रीस्टोअर करण्याची संधी असेल."</string>
+    <string name="crypt_keeper_data_corrupt_summary" product="default" msgid="5798580588985326937">"तुम्ही एंटर केलेला पासवर्ड बरोबर आहे, परंतु दुर्दैवाने तुमचा डेटा दूषित आहे. \n\nतुमचा फोन वापरणे पुनः सुरू करण्यासाठी, तुम्हाला फॅक्टरी रीसेट करणे आवश्यक आहे. रीसेट केल्यानंतर तुम्ही तुमचा फोन सेट करता, तेव्हा तुम्हाला आपल्या Google खात्यावर बॅक अप घेतलेला कोणताही डेटा रीस्टोअर करण्याची संधी असेल."</string>
     <string name="crypt_keeper_switch_input_method" msgid="4744137470890459582">"इनपुट पद्धत स्विच करा"</string>
     <string name="suggested_lock_settings_title" msgid="1518155558803371661">"तुमचा फोन सुरक्षित ठेवा"</string>
     <string name="suggested_lock_settings_summary" product="tablet" msgid="1861066918594412519">"टॅबलेटचे संरक्षण करण्‍यासाठी स्‍क्रीन लॉक सेट करा"</string>
@@ -579,7 +578,7 @@
     <string name="fingerprint_unlock_set_unlock_pattern" msgid="132337696546315927">"फिंगरप्रिंट + पॅटर्न"</string>
     <string name="fingerprint_unlock_set_unlock_pin" msgid="886426673328906002">"फिंगरप्रिंट + पिन"</string>
     <string name="fingerprint_unlock_set_unlock_password" msgid="3325527833422156515">"फिंगरप्रिंट + पासवर्ड"</string>
-    <string name="fingerprint_unlock_skip_fingerprint" msgid="2063700014903801639">"फिंगरप्रिंट न वापरता सुरु ठेवा"</string>
+    <string name="fingerprint_unlock_skip_fingerprint" msgid="2063700014903801639">"फिंगरप्रिंट न वापरता सुरू ठेवा"</string>
     <string name="fingerprint_unlock_title" msgid="8009992449332532869">"तुम्ही आपल्या फिंगरप्रिंटचा वापर करून तुमचा फोन अनलॉक करू शकता. सुरक्षिततेसाठी, या पर्यायाकरिता एक बॅक अप स्क्रीन लॉक आवश्यक आहे."</string>
     <string name="face_unlock_set_unlock_pattern" msgid="3748596996869406905">"फेस ऑथेंटिकेशन + पॅटर्न"</string>
     <string name="face_unlock_set_unlock_pin" msgid="3320824093518497476">"फेस ऑथेंटिकेशन + पिन"</string>
@@ -659,7 +658,7 @@
       <item quantity="other">पिन किमान <xliff:g id="COUNT_1">%d</xliff:g> अंकी असणे आवश्यक आहे</item>
       <item quantity="one">पिनमध्ये किमान <xliff:g id="COUNT_0">%d</xliff:g> अंक असणे आवश्यक आहे</item>
     </plurals>
-    <string name="lockpassword_continue_label" msgid="7279261861924400655">"सुरु ठेवा"</string>
+    <string name="lockpassword_continue_label" msgid="7279261861924400655">"सुरू ठेवा"</string>
     <plurals name="lockpassword_password_too_long" formatted="false" msgid="7994068708438608179">
       <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> वर्णांपेक्षा कमी असणे आवश्यक आहे</item>
       <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> वर्णापेक्षा कमी असणे आवश्यक आहे</item>
@@ -668,7 +667,6 @@
       <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> अंकांपेक्षा कमी असणे आवश्यक आहे</item>
       <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> अंकापेक्षा कमी असणे आवश्यक आहे</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"केवळ 0-9 अंक असणे आवश्यक आहे"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"डिव्हाइस प्रशासक अलीकडील पिन वापरण्याची अनुमती देत नाही"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"सामान्यत: वापरले जाणारे पिन तुमच्या IT प्रशासनाने ब्लॉक केलेले आहेत. दुसरा एखादा पिन वापरून पाहा."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"यामध्ये अवैध वर्ण समाविष्ट असू शकत नाही"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">किमान <xliff:g id="COUNT">%d</xliff:g> अक्षर नसलेले वर्ण असणे आवश्यक आहे</item>
       <item quantity="one">किमान 1 अक्षर नसलेला वर्ण असणे आवश्यक आहे</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">किमान <xliff:g id="COUNT">%d</xliff:g> अंक नसलेले वर्ण असणे आवश्यक आहे</item>
+      <item quantity="one">किमान एक अंक नसलेला वर्ण असणे आवश्यक आहे</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"डिव्हाइस प्रशासक अलीकडील पासवर्ड वापरण्याची अनुमती देत नाही"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"सामान्यत: वापरले जाणारे पासवर्ड तुमच्या IT प्रशासनाने ब्लॉक केलेले आहेत. दुसरा एखादा पासवर्ड वापरून पाहा."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"अंकांच्या चढत्या, उतरत्या किंवा पुनरावृत्त क्रमाला अनुमती नाही"</string>
@@ -709,7 +711,7 @@
     <string name="lockpattern_tutorial_cancel_label" msgid="450401426127674369">"रद्द करा"</string>
     <string name="lockpattern_tutorial_continue_label" msgid="8474690922559443018">"पुढील"</string>
     <string name="lock_setup" msgid="8710689848703935088">"सेटअप पूर्ण झाले आहे"</string>
-    <string name="manage_device_admin" msgid="322047441168191695">"डिव्हाइस अ‍ॅडमिन ॲप्‍स"</string>
+    <string name="manage_device_admin" msgid="322047441168191695">"डिव्हाइस अ‍ॅडमिन अ‍ॅप्स"</string>
     <string name="number_of_device_admins_none" msgid="8519193548630223132">"सक्रिय अ‍ॅप्स नाहीत"</string>
     <plurals name="number_of_device_admins" formatted="false" msgid="6445613288828151224">
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> सक्रिय अ‍ॅप्‍स</item>
@@ -723,13 +725,13 @@
       <item quantity="one">1 सक्रिय विश्वासू एजंट</item>
     </plurals>
     <string name="bluetooth_quick_toggle_title" msgid="7410319268406112792">"ब्लूटूथ"</string>
-    <string name="bluetooth_quick_toggle_summary" msgid="3951769568065428093">"ब्लूटूथ चालू करा"</string>
+    <string name="bluetooth_quick_toggle_summary" msgid="3951769568065428093">"ब्लूटूथ सुरू करा"</string>
     <string name="bluetooth_settings" msgid="5228032727293770389">"ब्लूटूथ"</string>
     <string name="bluetooth_settings_title" msgid="7261244857456521825">"ब्लूटूथ"</string>
     <string name="bluetooth_settings_summary" msgid="1221689092429277887">"कनेक्शन व्यवस्थापित करा, डिव्हाइस नाव आणि शोधयोग्यता सेट करा"</string>
     <string name="bluetooth_pairing_request" msgid="7221745525632573125">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> सह जोडायचे?"</string>
-    <string name="bluetooth_pairing_key_msg" msgid="1139230917419961975">"ब्लूटूथ पेअरींग कोड"</string>
-    <string name="bluetooth_enter_passkey_msg" msgid="6205151011298670207">"पेअरींग कोड टाइप करा नंतर Return किंवा Enter दाबा"</string>
+    <string name="bluetooth_pairing_key_msg" msgid="1139230917419961975">"ब्लूटूथ पेअरिंग कोड"</string>
+    <string name="bluetooth_enter_passkey_msg" msgid="6205151011298670207">"पेअरिंग कोड टाइप करा नंतर Return किंवा Enter दाबा"</string>
     <string name="bluetooth_enable_alphanumeric_pin" msgid="9138308197078115672">"पिन मध्ये अक्षरे किंवा प्रतीके आहेत"</string>
     <string name="bluetooth_pin_values_hint" msgid="8044671726261326240">"सामान्यतः 0000 किंवा 1234"</string>
     <string name="bluetooth_pin_values_hint_16_digits" msgid="2665983525706661525">"16 अंक असणे आवश्यक आहे"</string>
@@ -738,7 +740,7 @@
     <string name="bluetooth_confirm_passkey_msg" msgid="7094455604290076371">"यासह जोडण्यासाठी:&lt;br&gt;&lt;b&gt;<xliff:g id="DEVICE_NAME">%1$s</xliff:g>&lt;/b&gt;&lt;br&gt;&lt;br&gt;हे ही पासकी दर्शवत असल्याचे सुनिश्चित करा:&lt;br&gt;&lt;b&gt;<xliff:g id="PASSKEY">%2$s</xliff:g>&lt;/b&gt;"</string>
     <string name="bluetooth_incoming_pairing_msg" msgid="940451919337185024">"यावरून:&lt;br&gt;&lt;b&gt;<xliff:g id="DEVICE_NAME">%1$s</xliff:g>&lt;/b&gt;&lt;br&gt;&lt;br&gt;हे डिव्हाइस जोडायचे?"</string>
     <string name="bluetooth_display_passkey_pin_msg" msgid="5909423849232791647">"यासह जोडण्यासाठी:<xliff:g id="BOLD1_0">&lt;br&gt;&lt;b&gt;</xliff:g><xliff:g id="DEVICE_NAME">%1$s</xliff:g><xliff:g id="END_BOLD1">&lt;/b&gt;&lt;br&gt;&lt;br&gt;</xliff:g>यावर टाइप करा:<xliff:g id="BOLD2_1">&lt;br&gt;&lt;b&gt;</xliff:g><xliff:g id="PASSKEY">%2$s</xliff:g><xliff:g id="END_BOLD2">&lt;/b&gt;</xliff:g>, नंतर Return किंवा Enter दाबा."</string>
-    <string name="bluetooth_pairing_shares_phonebook" msgid="7474404818877079813">"तुमच्या संपर्क आणि कॉल इतिहासातील अ‍ॅक्सेसची अनुमती द्या"</string>
+    <string name="bluetooth_pairing_shares_phonebook" msgid="7474404818877079813">"तुमचे संपर्क आणि कॉल इतिहास अ‍ॅक्सेस करण्याची अनुमती द्या"</string>
     <string name="bluetooth_error_title" msgid="5718761586633101960"></string>
     <string name="bluetooth_connecting_error_message" msgid="8473359363469518478">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> सह कनेक्ट करणे शक्य झाले नाही."</string>
     <string name="bluetooth_preference_scan_title" msgid="457781003962324807">"डिव्हाइसेससाठी स्कॅन करा"</string>
@@ -763,8 +765,8 @@
     <string name="bluetooth_device_context_connect_advanced" msgid="423463405499392444">"पर्याय…"</string>
     <string name="bluetooth_menu_advanced" msgid="7566858513372603652">"प्रगत"</string>
     <string name="bluetooth_advanced_titlebar" msgid="6459469494039004784">"प्रगत ब्लूटूथ"</string>
-    <string name="bluetooth_empty_list_bluetooth_off" msgid="6255367297830430459">"ब्लूटूथ चालू असते तेव्हा, तुमचे डिव्हाइस इतर जवळच्या ब्लूटूथ डिव्हाइस सह संवाद करु शकते."</string>
-    <string name="bluetooth_scanning_on_info_message" msgid="5460370815156050550">"ब्‍लूटूथ सुरू असताना, तुमचे डिव्‍हाइस इतर जवळपासच्‍या ब्‍लूटूथ डिव्‍हाइसशी संवाद साधू शकते.\n\nडिव्‍हाइस अनुभव सुधारण्‍यासाठी, ॲप्‍स आणि सेवा ब्‍लूटूथ सुरू असताना देखील, अजूनही जवळपासचे डिव्‍हाइस कधीही स्‍कॅन करू शकते. उदाहरणार्थ, याचा वापर स्‍थानावर आधारित वैशिष्‍ट्ये आणि सेवा सुधारण्‍यात केला जाऊ शकतो. तुम्‍ही हे "<annotation id="link">"स्‍कॅनिंग सेटिंग्‍ज"</annotation>" मध्‍ये जाऊन बदलू शकता."</string>
+    <string name="bluetooth_empty_list_bluetooth_off" msgid="6255367297830430459">"ब्लूटूथ सुरू असते तेव्हा, तुमचे डिव्हाइस इतर जवळच्या ब्लूटूथ डिव्हाइस सह संवाद करु शकते."</string>
+    <string name="bluetooth_scanning_on_info_message" msgid="5460370815156050550">"ब्‍लूटूथ सुरू असताना, तुमचे डिव्‍हाइस इतर जवळपासच्‍या ब्‍लूटूथ डिव्‍हाइसशी संवाद साधू शकते.\n\nडिव्‍हाइस अनुभव सुधारण्‍यासाठी, अ‍ॅप्स आणि सेवा ब्‍लूटूथ सुरू असताना देखील, अजूनही जवळपासचे डिव्‍हाइस कधीही स्‍कॅन करू शकते. उदाहरणार्थ, याचा वापर स्‍थानावर आधारित वैशिष्‍ट्ये आणि सेवा सुधारण्‍यात केला जाऊ शकतो. तुम्‍ही हे "<annotation id="link">"स्‍कॅनिंग सेटिंग्‍ज"</annotation>" मध्‍ये जाऊन बदलू शकता."</string>
     <string name="ble_scan_notify_text" msgid="6290170236546386932">"स्‍थान अचूकता सुधारण्‍यासाठी, सिस्टम अ‍ॅप्स आणि सेवा अद्याप ब्लूटूथ डिव्हाइस शोधू शकतात. तुम्ही हे <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>स्कॅनिंग सेटिंग्ज<xliff:g id="LINK_END_1">LINK_END</xliff:g> मध्‍ये बदलू शकता."</string>
     <string name="bluetooth_connect_failed" msgid="1151234676456333786">"कनेक्ट होऊ शकत नाही. पुन्हा प्रयत्न करा."</string>
     <string name="device_details_title" msgid="726517818032923222">"डिव्हाइस तपशील"</string>
@@ -814,14 +816,14 @@
     <string name="wifi_tap_to_sign_in" msgid="1075925570550560453">"नेटवर्कवर साइन इन करण्यासाठी येथे टॅप करा"</string>
     <string name="tx_link_speed" msgid="4557508597788146162">"<xliff:g id="TRANSMIT_LINK_SPEED">%1$d</xliff:g> Mbps"</string>
     <string name="rx_link_speed" msgid="3735337600274627581">"<xliff:g id="RECEIVE_LINK_SPEED">%1$d</xliff:g> Mbps"</string>
-    <string name="wifi_ask_enable" msgid="925862998663619616">"<xliff:g id="REQUESTER">%s</xliff:g> वाय-फाय चालू करू इच्छित आहे"</string>
+    <string name="wifi_ask_enable" msgid="925862998663619616">"<xliff:g id="REQUESTER">%s</xliff:g> वाय-फाय सुरू करू इच्छित आहे"</string>
     <string name="wifi_ask_disable" msgid="2146839060110412974">"<xliff:g id="REQUESTER">%s</xliff:g> वाय-फाय बंद करू इच्छित आहे"</string>
     <string name="art_verifier_for_debuggable_title" msgid="5223835619409464642">"डीबग करण्यायोग्य ॲप्सच्या बाइटकोडची पडताळणी करा"</string>
     <string name="art_verifier_for_debuggable_summary" msgid="2204242476996701111">"डीबग करण्यायोग्य ॲप्ससाठी बाइटकोडची पडताळणी करण्यासाठी ART ला अनुमती द्या"</string>
     <string name="nfc_quick_toggle_title" msgid="4990697912813795002">"NFC"</string>
     <string name="nfc_quick_toggle_summary" product="tablet" msgid="983451155092850657">"टॅबलेट दुसर्‍या डिव्हाइसला स्पर्श करतो तेव्हा डेटा अदलाबदलीस अनुमती द्या"</string>
     <string name="nfc_quick_toggle_summary" product="default" msgid="7141056939052895142">"फोन दुसर्‍या डिव्हाइसला स्पर्श करतो तेव्हा डेटा अदलाबदलीस अनुमती द्या"</string>
-    <string name="nfc_disclaimer_title" msgid="4860231267351602970">"NFC चालू करा"</string>
+    <string name="nfc_disclaimer_title" msgid="4860231267351602970">"NFC सुरू करा"</string>
     <string name="nfc_disclaimer_content" msgid="3066113577854565782">"NFC हे डिव्हाइस आणि दुसरे जवळपासचे डिव्हाइस किंवा पेमेंट टर्मिनल, ॲक्सेस रीडर आणि सुसंवादी जाहिराती किंवा टॅग यासारख्या लक्ष्यांमधील डेटाची अदलाबदल करते."</string>
     <string name="nfc_secure_settings_title" msgid="5153751163174916581">"NFC चे संरक्षण करा"</string>
     <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"स्क्रीन अनलॉक केल्यावर NFC पेमेंट आणि फक्त परिवहन वापरासाठीला अनुमती द्या"</string>
@@ -830,16 +832,16 @@
     <string name="android_beam_off_summary" msgid="7365818039159364600">"बंद"</string>
     <string name="nfc_disabled_summary" msgid="2181777971122724361">"NFC बंद असल्यामुळे उपलब्ध नाही"</string>
     <string name="android_beam_label" msgid="5340299879556025708">"Android बीम"</string>
-    <string name="android_beam_explained" msgid="4501176353247859329">"जेव्हा हे वैशिष्ट्य चालू केलेले असते तेव्हा, तुम्ही डिव्हाइस एकत्र जवळ धरून दुसर्‍या NFC-सक्षम डिव्हाइस वर अ‍ॅपचा आशय बीम करू शकता. उदाहरणार्थ, तुम्ही वेब पेज, YouTube व्हिडिओ, संपर्क आणि बरेच काही बीम करू शकता.\n\nफक्त डिव्हाइस एकत्र आणा (विशेषतः पाठोपाठ) आणि नंतर स्क्रीन टॅप करा. काय बीम केले जाते हे अ‍ॅप निर्धारित करते."</string>
+    <string name="android_beam_explained" msgid="4501176353247859329">"जेव्हा हे वैशिष्ट्य सुरू केलेले असते तेव्हा, तुम्ही डिव्हाइस एकत्र जवळ धरून दुसर्‍या NFC-सक्षम डिव्हाइस वर अ‍ॅपचा आशय बीम करू शकता. उदाहरणार्थ, तुम्ही वेब पेज, YouTube व्हिडिओ, संपर्क आणि बरेच काही बीम करू शकता.\n\nफक्त डिव्हाइस एकत्र आणा (विशेषतः पाठोपाठ) आणि नंतर स्क्रीन टॅप करा. काय बीम केले जाते हे अ‍ॅप निर्धारित करते."</string>
     <string name="wifi_quick_toggle_title" msgid="7935778388625246184">"वाय-फाय"</string>
-    <string name="wifi_quick_toggle_summary" msgid="2879870570547594266">"वाय-फाय चालू करा"</string>
+    <string name="wifi_quick_toggle_summary" msgid="2879870570547594266">"वाय-फाय सुरू करा"</string>
     <string name="wifi_settings" msgid="7486492317310514109">"वाय-फाय"</string>
     <string name="wifi_settings_master_switch_title" msgid="3917916944694253946">"वाय-फाय वापरा"</string>
     <string name="wifi_settings_category" msgid="9094716747565527901">"वाय-फाय सेटिंग्ज"</string>
     <string name="wifi_settings_title" msgid="5265554991622344805">"वाय-फाय"</string>
     <string name="wifi_settings_summary" msgid="7117267255799892820">"वायरलेस प्रवेश बिंदू सेट करा आणि  व्यवस्थापित करा"</string>
     <string name="wifi_select_network" msgid="2541598480767312831">"वाय-फाय निवडा"</string>
-    <string name="wifi_starting" msgid="1299466156783469023">"वाय-फाय चालू करत आहे..."</string>
+    <string name="wifi_starting" msgid="1299466156783469023">"वाय-फाय सुरू करत आहे..."</string>
     <string name="wifi_stopping" msgid="413711069039939520">"वाय-फाय बंद करत आहे…"</string>
     <string name="wifi_error" msgid="5605801874484465557">"एरर"</string>
     <string name="wifi_sap_no_channel_error" msgid="6881796988574851628">"या देशात 5 GHz बँड उपलब्‍ध नाही"</string>
@@ -860,21 +862,21 @@
     <string name="use_open_wifi_automatically_summary_scorer_unsupported_disabled" msgid="1123080670578756834">"वापरण्‍यासाठी, सुसंगत नेटवर्क रेटिंग पुरवठादार निवडा"</string>
     <string name="wifi_install_credentials" msgid="5650088113710858289">"प्रमाणपत्रे इंस्टॉल करा"</string>
     <string name="wifi_scan_notify_text" msgid="7614101215028336927">"स्थान अचूकता सुधारण्यासाठी अ‍ॅप्स आणि सेवा वाय-फाय बंद असतानाही कधीही वाय-फाय नेटवर्क शोधण्यासाठी स्कॅन करू शकतात. स्थानाधारित वैशिष्ट्ये आणि सेवांमध्ये सुधारणा करण्यासाठी हे वापरले जाऊ शकते. तुम्ही हे <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>स्कॅनिंग सेटिंग्ज<xliff:g id="LINK_END_1">LINK_END</xliff:g> मध्ये बदलू शकता."</string>
-    <string name="wifi_scan_notify_text_scanning_off" msgid="723796963816095410">"स्थान अचूकता वाढवण्यासाठी, <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>स्कॅनिंग सेटिंग्ज<xliff:g id="LINK_END_1">LINK_END</xliff:g> मध्ये वाय-फाय स्कॅनिंग चालू करा."</string>
+    <string name="wifi_scan_notify_text_scanning_off" msgid="723796963816095410">"स्थान अचूकता वाढवण्यासाठी, <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>स्कॅनिंग सेटिंग्ज<xliff:g id="LINK_END_1">LINK_END</xliff:g> मध्ये वाय-फाय स्कॅनिंग सुरू करा."</string>
     <string name="wifi_scan_notify_remember_choice" msgid="1235445971400237444">"पुन्हा दर्शवू नका"</string>
-    <string name="wifi_setting_sleep_policy_title" msgid="2120785188625932076">"निष्क्रिय असताना वाय-फाय चालू ठेवा"</string>
-    <string name="wifi_setting_on_during_sleep_title" msgid="856670183023402715">"निष्क्रिय करा दरम्यान वाय-फाय चालू"</string>
+    <string name="wifi_setting_sleep_policy_title" msgid="2120785188625932076">"निष्क्रिय असताना वाय-फाय सुरू ठेवा"</string>
+    <string name="wifi_setting_on_during_sleep_title" msgid="856670183023402715">"निष्क्रिय करा दरम्यान वाय-फाय सुरू"</string>
     <string name="wifi_setting_sleep_policy_error" msgid="9029652631829560733">"सेटिंग बदलताना समस्या आली"</string>
     <string name="wifi_suspend_efficiency_title" msgid="5292408676086580527">"कार्यक्षमतेत सुधारणा करा"</string>
     <string name="wifi_suspend_optimizations" msgid="8826033336622472222">"वाय-फाय ऑप्टिमायझेशन"</string>
-    <string name="wifi_suspend_optimizations_summary" msgid="2375789014394339008">"वाय-फाय चालू असताना बॅटरी वापर कमी करा"</string>
+    <string name="wifi_suspend_optimizations_summary" msgid="2375789014394339008">"वाय-फाय सुरू असताना बॅटरी वापर कमी करा"</string>
     <string name="wifi_limit_optimizations_summary" msgid="1192849485764156570">"वाय-फाय द्वारे वापरलेल्या बॅटरीवर मर्यादा घाला"</string>
     <string name="wifi_switch_away_when_unvalidated" msgid="2418577764071293971">"वाय-फायला इंटरनेट ॲक्सेस नसल्यास मोबाइल डेटावर स्विच करा."</string>
     <string name="wifi_cellular_data_fallback_title" msgid="5067241930716252665">"मोबाइल डेटावर स्‍वयंचलितपणे स्विच करा"</string>
     <string name="wifi_cellular_data_fallback_summary" msgid="2721467405851519769">"वाय-फायवरून इंटरनेट ॲक्सेस नसताना मोबाइल डेटा वापरा. डेटा वापर शुल्क लागू शकते."</string>
     <string name="wifi_add_network" msgid="4094957940791876640">"नेटवर्क जोडा"</string>
     <string name="wifi_configure_settings_preference_title" msgid="2678534679408777268">"वाय-फाय प्राधान्ये"</string>
-    <string name="wifi_configure_settings_preference_summary_wakeup_on" msgid="5714892572614655675">"वाय-फाय आपोआप परत चालू होते"</string>
+    <string name="wifi_configure_settings_preference_summary_wakeup_on" msgid="5714892572614655675">"वाय-फाय आपोआप परत सुरू होते"</string>
     <string name="wifi_configure_settings_preference_summary_wakeup_off" msgid="286904094152909651">"वाय-फाय आपोआप परत सुरू होत नाही"</string>
     <string name="wifi_access_points" msgid="1647976498906871869">"वाय-फाय नेटवर्क"</string>
     <string name="wifi_menu_more_options" msgid="8318269834264035524">"अधिक पर्याय"</string>
@@ -886,7 +888,7 @@
     <string name="wifi_menu_remember" msgid="717257200269700641">"नेटवर्क लक्षात ठेवा"</string>
     <string name="wifi_menu_forget" msgid="7561140554450163075">"नेटवर्क विसरा"</string>
     <string name="wifi_menu_modify" msgid="4080178040721021101">"नेटवर्क सुधारित करा"</string>
-    <string name="wifi_empty_list_wifi_off" msgid="272877164691346240">"उपलब्ध नेटवर्क पाहण्यासाठी, वाय-फाय चालू करा."</string>
+    <string name="wifi_empty_list_wifi_off" msgid="272877164691346240">"उपलब्ध नेटवर्क पाहण्यासाठी, वाय-फाय सुरू करा."</string>
     <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"वाय-फाय नेटवर्क शोधत आहे…"</string>
     <string name="wifi_empty_list_user_restricted" msgid="2341613007817352431">"तुम्हाला वाय-फाय नेटवर्क बदलण्याची परवानगी नाही."</string>
     <string name="wifi_more" msgid="3538241640407382185">"अधिक"</string>
@@ -978,7 +980,7 @@
     <string name="wifi_wps_available_second_item" msgid="5703265526619705185">" (WPS उपलब्ध)"</string>
     <string name="wifi_carrier_connect" msgid="7202618367339982884">"वाहक वाय-फाय नेटवर्क"</string>
     <string name="wifi_carrier_content" msgid="3467402515071949783">"<xliff:g id="NAME">%1$s</xliff:g> ने कनेक्ट करा"</string>
-    <string name="wifi_scan_always_turnon_message" msgid="7811846312032594248">"स्थान अचूकता सुधारण्यासाठी आणि इतर हेतूंसाठी, <xliff:g id="APP_NAME">%1$s</xliff:g> ला नेटवर्क स्कॅनिंग चालू करण्याची आवश्यकता आहे, वाय-फाय बंद असताना देखील.\n\nस्कॅन करू इच्छित सर्व ॲप्सना अनुमती द्यायची?"</string>
+    <string name="wifi_scan_always_turnon_message" msgid="7811846312032594248">"स्थान अचूकता सुधारण्यासाठी आणि इतर हेतूंसाठी, <xliff:g id="APP_NAME">%1$s</xliff:g> ला नेटवर्क स्कॅनिंग सुरू करण्याची आवश्यकता आहे, वाय-फाय बंद असताना देखील.\n\nस्कॅन करू इच्छित सर्व ॲप्सना अनुमती द्यायची?"</string>
     <string name="wifi_scan_always_turnoff_message" msgid="556993843641750002">"हे बंद करण्यासाठी, ओव्हरफ्लो मेनू मधील प्रगत वर जा."</string>
     <string name="wifi_scan_always_confirm_allow" msgid="8857664849515496237">"अनुमती द्या"</string>
     <string name="wifi_scan_always_confirm_deny" msgid="6190909841125369403">"नकार द्या"</string>
@@ -991,7 +993,7 @@
     <string name="lost_internet_access_title" msgid="1061916948695946130">"वाय-फाय इंटरनेटशी कनेक्ट केलेले नाही"</string>
     <string name="lost_internet_access_text" msgid="8962010031520731813">"वाय-फायचे कनेक्शन खराब असताना तुम्ही मोबाइल नेटवर्कवर स्विच करू शकता. डेटा वापर शुल्क लागू होऊ शकते."</string>
     <string name="lost_internet_access_switch" msgid="9218006455779873700">"मोबाइलवर स्विच करा"</string>
-    <string name="lost_internet_access_cancel" msgid="6577871064062518744">"वाय‑फाय वर सुरु ठेवा"</string>
+    <string name="lost_internet_access_cancel" msgid="6577871064062518744">"वाय‑फाय वर सुरू ठेवा"</string>
     <string name="lost_internet_access_persist" msgid="6368659013482055611">"पुन्हा कधीही दर्शवू नका"</string>
     <string name="wifi_connect" msgid="5653612760223533650">"कनेक्ट करा"</string>
     <string name="wifi_turned_on_message" msgid="3377779146238242894">"वाय-फाय सुरू केले आहे"</string>
@@ -1043,7 +1045,7 @@
     <string name="wifi_p2p_persist_network" msgid="1110453878886476660">"हे कनेक्शन लक्षात ठेवा"</string>
     <string name="wifi_p2p_menu_search" msgid="8207638860263805291">"डिव्हाइसेस शोधा"</string>
     <string name="wifi_p2p_menu_searching" msgid="7443249001543208106">"शोधत आहे..."</string>
-    <string name="wifi_p2p_menu_rename" msgid="2129974878377065488">"डीव्हाइसला पुन्हा नाव द्या"</string>
+    <string name="wifi_p2p_menu_rename" msgid="2129974878377065488">"डिव्हाइसला पुन्हा नाव द्या"</string>
     <string name="wifi_p2p_peer_devices" msgid="8232126067045093382">"पीअर डिव्हाइसेस"</string>
     <string name="wifi_p2p_remembered_groups" msgid="1356458238836730346">"लक्षात ठेवलेले समूह"</string>
     <string name="wifi_p2p_failed_connect_message" msgid="6103436959132424093">"कनेक्ट करु शकलो नाही"</string>
@@ -1058,10 +1060,10 @@
     <string name="wifi_hotspot_off_subtext" msgid="6177054857136221058">"इतर डिव्हाइससोबत इंटरनेट किंवा आशय शेअर करत नाही"</string>
     <string name="wifi_hotspot_tethering_on_subtext" product="tablet" msgid="71421730039785897">"या टॅबलेटचे इंटरनेट कनेक्शन हॉटस्पॉटने शेअर करत आहे"</string>
     <string name="wifi_hotspot_tethering_on_subtext" product="default" msgid="8914285514605049879">"या फोनचे इंटरनेट कनेक्शन हॉटस्पॉटने शेअर करत आहे"</string>
-    <string name="wifi_hotspot_on_local_only_subtext" msgid="7415381343846704553">"अ‍ॅप आशय शेअर करत आहे. इंटरनेट कनेक्शन शेअर करण्यासाठी, हॉटस्‍पॉट बंद करा, नंतर चालू करा"</string>
+    <string name="wifi_hotspot_on_local_only_subtext" msgid="7415381343846704553">"अ‍ॅप आशय शेअर करत आहे. इंटरनेट कनेक्शन शेअर करण्यासाठी, हॉटस्‍पॉट बंद करा, नंतर सुरू करा"</string>
     <string name="wifi_hotspot_no_password_subtext" msgid="5400500962974373706">"पासवर्ड सेट केलेला नाही"</string>
     <string name="wifi_hotspot_name_title" msgid="6572202165400226127">"हॉटस्पॉट नाव"</string>
-    <string name="wifi_hotspot_name_summary_connecting" msgid="5176787959408511889">"<xliff:g id="WIFI_HOTSPOT_NAME">%1$s</xliff:g> चालू करत आहे..."</string>
+    <string name="wifi_hotspot_name_summary_connecting" msgid="5176787959408511889">"<xliff:g id="WIFI_HOTSPOT_NAME">%1$s</xliff:g> सुरू करत आहे..."</string>
     <string name="wifi_hotspot_name_summary_connected" msgid="8387768642326756749">"इतर डिव्हाइस <xliff:g id="WIFI_HOTSPOT_NAME">%1$s</xliff:g>शी कनेक्ट होऊ शकतात"</string>
     <string name="wifi_hotspot_password_title" msgid="4289338152595154889">"हॉटस्पॉट पासवर्ड"</string>
     <string name="wifi_hotspot_ap_band_title" msgid="3485744480410441949">"AP बॅंड"</string>
@@ -1069,7 +1071,7 @@
     <string name="wifi_hotspot_footer_info_local_only" msgid="3339582350894639261">"जवळपासच्या डिव्हाइससोबत आशय शेअर करण्यासाठी अ‍ॅप्स हॉटस्पॉट तयार करू शकतात."</string>
     <string name="wifi_hotspot_auto_off_title" msgid="7416022590415189590">"हॉटस्पॉट आपोआप बंद करा"</string>
     <string name="wifi_hotspot_auto_off_summary" msgid="3866769400624802105">"कुठलीही डिव्हाइस कनेक्ट केली नसल्यास, वाय-फाय हॉटस्पॉट बंद होईल"</string>
-    <string name="wifi_tether_starting" msgid="7676952148471297900">"हॉटस्पॉट चालू करत आहे…"</string>
+    <string name="wifi_tether_starting" msgid="7676952148471297900">"हॉटस्पॉट सुरू करत आहे…"</string>
     <string name="wifi_tether_stopping" msgid="7478561853791953349">"हॉटस्पॉट बंद करत आहे…"</string>
     <string name="wifi_tether_enabled_subtext" msgid="7534760116478734006">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> सक्रिय आहे"</string>
     <string name="wifi_tether_failed_subtext" msgid="3501001612207106">"पोर्टेबल वाय-फाय हॉटस्पॉट एरर"</string>
@@ -1100,11 +1102,14 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"वाय-फाय"</item>
+    <item msgid="2271962426654621656">"मोबाइल"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"वाय-फाय उपलब्ध नसल्यास, मोबाइल नेटवर्क वापरा"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"मोबाइल नेटवर्क उपलब्ध नसल्यास, वाय-फाय वापरा"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"वाय-फायवरून कॉल करा. वाय-फाय गमावल्यास, कॉल संपेल."</string>
-    <string name="wifi_calling_off_explanation" msgid="1653424723742898015">"वाय-फाय कॉलिंग चालू असताना, तुमचा फोन तुमच्या प्राधान्यावर आणि कोणता सिग्नल मजबूत आहे याच्या आधारावर, वाय-फाय नेटवर्क किंवा तुमच्या वाहकाच्या नेटवर्कद्वारे कॉल राउट करू शकतो. हे वैशिष्ट्य सुरू करण्यापूर्वी, फी आणि इतर तपशीलांच्या संबंधात तुमच्या वाहकास विचारा. <xliff:g id="ADDITIONAL_TEXT">%1$s</xliff:g>"</string>
+    <string name="wifi_calling_off_explanation" msgid="1653424723742898015">"वाय-फाय कॉलिंग सुरू असताना, तुमचा फोन तुमच्या प्राधान्यावर आणि कोणता सिग्नल मजबूत आहे याच्या आधारावर, वाय-फाय नेटवर्क किंवा तुमच्या वाहकाच्या नेटवर्कद्वारे कॉल राउट करू शकतो. हे वैशिष्ट्य सुरू करण्यापूर्वी, फी आणि इतर तपशीलांच्या संबंधात तुमच्या वाहकास विचारा. <xliff:g id="ADDITIONAL_TEXT">%1$s</xliff:g>"</string>
     <string name="wifi_calling_off_explanation_2" msgid="8648609693875720408"></string>
     <string name="emergency_address_title" msgid="5779915349686787024">"संकटकालीन पत्ता"</string>
     <string name="emergency_address_summary" msgid="478668478569851714">"तुम्ही वाय-फाय वरून आणीबाणी कॉल केल्यावर हे तुमचे स्थान असल्याचे दाखवले जाते"</string>
@@ -1177,7 +1182,7 @@
     <string name="accelerometer_summary_on" product="default" msgid="6454733048264875491">"फोन फिरवताना ओरिएंटेशन आपोआप स्विच करा"</string>
     <string name="accelerometer_summary_off" product="tablet" msgid="2663240868158338608">"टॅब्लेट फिरवताना ओरिएंटेशन आपोआप स्विच करा"</string>
     <string name="accelerometer_summary_off" product="default" msgid="3366996018631557687">"फोन फिरवताना ओरिएंटेशन आपोआप स्विच करा"</string>
-    <string name="brightness" msgid="7309120144111305275">"चकाकी स्तर"</string>
+    <string name="brightness" msgid="7309120144111305275">"ब्राइटनेस पातळी"</string>
     <string name="brightness_title" msgid="5660190946911149690">"चकाकी"</string>
     <string name="brightness_summary" msgid="8687101964451818730">"स्क्रीनची चकाकी समायोजित करा"</string>
     <string name="auto_brightness_title" msgid="908511534369820426">"अ‍ॅडॅप्टिव्ह ब्राइटनेस"</string>
@@ -1197,7 +1202,7 @@
     <string name="auto_brightness_subtitle" msgid="8516999348793100665">"तुम्ही प्राधान्य दिलेला उज्ज्वलता स्तर"</string>
     <string name="auto_brightness_off_summary" msgid="6162650416289359104">"उपलब्ध प्रकाशासाठी समायोजित करू नका"</string>
     <string name="auto_brightness_very_high_summary" msgid="7202032980509583918">"वाढलेला बॅटरी वापर"</string>
-    <string name="auto_brightness_disclaimer" msgid="5416696351199148809">"उपलब्ध प्रकाशासाठी उज्ज्वलता स्तर अनुकूल करा. हे वैशिष्ट्य चालू असताना, तुम्ही तरीही उज्ज्वलता तात्पुरती समायोजित करू शकता."</string>
+    <string name="auto_brightness_disclaimer" msgid="5416696351199148809">"उपलब्ध प्रकाशासाठी उज्ज्वलता स्तर अनुकूल करा. हे वैशिष्ट्य सुरू असताना, तुम्ही तरीही उज्ज्वलता तात्पुरती समायोजित करू शकता."</string>
     <string name="auto_brightness_description" msgid="8209140379089535411">"तुमच्या स्क्रीनचा ब्राइटनेस तुमच्या वातावरण आणि ॲक्टिव्हिटीशी आपोआप अ‍ॅडजस्ट होईल. अ‍ॅडॅप्टिव्ह ब्राइटनेसला तुमची प्राधान्ये जाणून घेण्यात मदत करण्यासाठी तुम्ही स्लाइडर मॅन्युअली हलवू शकता."</string>
     <string name="display_white_balance_title" msgid="5747260735311935143">"व्हाइट बॅलन्स डिस्प्ले करा"</string>
     <string name="adaptive_sleep_title" msgid="3237620948260957018">"स्क्रीन अवेअर"</string>
@@ -1209,7 +1214,7 @@
     <string name="night_display_text" msgid="5330502493684652527">"रात्रीचा प्रकाश तुमच्या स्क्रीनला पिवळसर तपकिरी छटा देतो. यामुळे मंद प्रकाशात तुमची स्क्रीन पाहणे किंवा वाचणे सोपे होते आणि तुम्हाला झोप येण्यात मदत होऊ शकते."</string>
     <string name="night_display_auto_mode_title" msgid="8493573087102481588">"शेड्युल"</string>
     <string name="night_display_auto_mode_never" msgid="2897444637217807088">"काहीही नाही"</string>
-    <string name="night_display_auto_mode_custom" msgid="1400891076453963151">"ठराविक वेळी सुरू होतो"</string>
+    <string name="night_display_auto_mode_custom" msgid="1400891076453963151">"ठरावीक वेळी सुरू होतो"</string>
     <string name="night_display_auto_mode_twilight" msgid="4000162110017520674">"सूर्यास्त-सूर्योदय सुरू राहतो"</string>
     <string name="night_display_start_time_title" msgid="1069255169673371077">"सुरू होण्याची वेळ"</string>
     <string name="night_display_end_time_title" msgid="2760793157124245911">"संपण्याची वेळ"</string>
@@ -1217,9 +1222,9 @@
     <string name="night_display_temperature_title" msgid="8375126629902616296">"तीव्रता"</string>
     <string name="night_display_summary_off" msgid="8850539785332228069">"बंद / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="night_display_summary_off_auto_mode_never" msgid="8618824386434992487">"आपोआप कधीही सुरू होणार नाही"</string>
-    <string name="night_display_summary_off_auto_mode_custom" msgid="596847003171394411">"<xliff:g id="ID_1">%1$s</xliff:g> वाजता आपोआप चालू होईल"</string>
-    <string name="night_display_summary_off_auto_mode_twilight" msgid="4071750976585359952">"सूर्यास्ताच्या वेळी आपोआप चालू होईल"</string>
-    <string name="night_display_summary_on" msgid="6580571388791426596">"चालू / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="night_display_summary_off_auto_mode_custom" msgid="596847003171394411">"<xliff:g id="ID_1">%1$s</xliff:g> वाजता आपोआप सुरू होईल"</string>
+    <string name="night_display_summary_off_auto_mode_twilight" msgid="4071750976585359952">"सूर्यास्ताच्या वेळी आपोआप सुरू होईल"</string>
+    <string name="night_display_summary_on" msgid="6580571388791426596">"सुरू / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="night_display_summary_on_auto_mode_never" msgid="5461580863060506687">"आपोआप कधीही बंद होणार नाही"</string>
     <string name="night_display_summary_on_auto_mode_custom" msgid="2200631112239399233">"<xliff:g id="ID_1">%1$s</xliff:g> वाजता आपोआप बंद होईल"</string>
     <string name="night_display_summary_on_auto_mode_twilight" msgid="8386769601369289561">"सूर्योदयाच्या वेळी आपोआप बंद होईल"</string>
@@ -1247,9 +1252,9 @@
     <string name="screensaver_settings_summary_dock" msgid="6297808146601570196">"डॉक केलेले असताना"</string>
     <string name="screensaver_settings_summary_never" msgid="3995259444981620707">"कधीही नाही"</string>
     <string name="screensaver_settings_summary_off" msgid="6119947316484763131">"बंद"</string>
-    <string name="screensaver_settings_disabled_prompt" msgid="1897518064782596947">"फोन डॉक केलेला असताना आणि/किंवा निष्क्रिय असताना काय होते हे नियंत्रित करण्यासाठी स्क्रीन सेव्हर चालू करा."</string>
+    <string name="screensaver_settings_disabled_prompt" msgid="1897518064782596947">"फोन डॉक केलेला असताना आणि/किंवा निष्क्रिय असताना काय होते हे नियंत्रित करण्यासाठी स्क्रीन सेव्हर सुरू करा."</string>
     <string name="screensaver_settings_when_to_dream" msgid="3763052013516826348">"कधी सुरू करायचे"</string>
-    <string name="screensaver_settings_current" msgid="4017556173596361672">"सद्य स्क्रीन सेव्हर"</string>
+    <string name="screensaver_settings_current" msgid="4017556173596361672">"सध्याचा स्क्रीन सेव्हर"</string>
     <string name="screensaver_settings_dream_start" msgid="3772227299054662550">"आता सुरू करा"</string>
     <string name="screensaver_settings_button" msgid="4662384378821837589">"सेटिंग्ज"</string>
     <string name="automatic_brightness" msgid="8663792987774126192">"स्वयंचलित चकाकी"</string>
@@ -1349,10 +1354,10 @@
     <string name="status_data_state" msgid="4538705798873861963">"मोबाईल नेटवर्क स्थिती"</string>
     <string name="status_esim_id" msgid="9201767073386770286">"EID"</string>
     <string name="status_service_state" msgid="4406215321296496234">"सेवा स्थिती"</string>
-    <string name="status_signal_strength" msgid="4302597886933728789">"सिग्नल स्ट्रेंथ"</string>
+    <string name="status_signal_strength" msgid="4302597886933728789">"सिग्नल सामर्थ्य"</string>
     <string name="status_roaming" msgid="5191044997355099561">"रोमिंग"</string>
     <string name="status_operator" msgid="6017986100643755390">"नेटवर्क"</string>
-    <string name="status_wifi_mac_address" msgid="3868452167971295995">"वाय-फाय MAC पत्ता"</string>
+    <string name="status_wifi_mac_address" msgid="3868452167971295995">"वाय-फाय MAC अ‍ॅड्रेस"</string>
     <string name="status_bt_address" msgid="460568179311735657">"ब्लूटूथ पत्ता"</string>
     <string name="status_serial_number" msgid="8257722124627415159">"सिरीअल नंबर"</string>
     <string name="status_up_time" msgid="77128395333934087">"सुरू असल्याचा कालावधी"</string>
@@ -1369,8 +1374,8 @@
     <string name="memory_downloads_usage" msgid="7039979723012065168">"डाउनलोड"</string>
     <string name="memory_dcim_usage" msgid="599009211606524732">"चित्रे, व्हिडिओ"</string>
     <string name="memory_music_usage" msgid="809605300042546279">"ऑडिओ (संगीत, रिंगटोन, पॉडकास्ट इ.)"</string>
-    <string name="memory_media_misc_usage" msgid="6258827529046910705">"इतर फायली"</string>
-    <string name="memory_media_cache_usage" msgid="1307620682751377717">"कॅश केलेला डेटा"</string>
+    <string name="memory_media_misc_usage" msgid="6258827529046910705">"इतर फाइल"</string>
+    <string name="memory_media_cache_usage" msgid="1307620682751377717">"कॅशे  केलेला डेटा"</string>
     <string name="sd_eject" product="nosdcard" msgid="3016608823130472449">"शेअर केलेले संचयन अनमाउंट करा"</string>
     <string name="sd_eject" product="default" msgid="4943338855474925396">"SD कार्ड अनमाउंट करा"</string>
     <string name="sd_eject_summary" product="nosdcard" msgid="8571017212318899178">"अंतर्गत USB स्टोरेज अनमाउंट करा"</string>
@@ -1385,8 +1390,8 @@
     <string name="sd_format" product="default" msgid="1346245995138883960">"SD कार्ड मिटवा"</string>
     <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_title" msgid="4306793268129306684">"कॅशे    केलेला डेटा साफ करायचा?"</string>
+    <string name="memory_clear_cache_message" msgid="6723120398411410031">"हे सर्व ॲप्ससाठी कॅशे    केलेला डेटा साफ करेल."</string>
     <string name="mtp_ptp_mode_summary" msgid="6074099855478444183">"MTP किंवा TP कार्य सक्रिय आहे"</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>
@@ -1417,9 +1422,9 @@
     <string name="storage_title_usb" msgid="2015671467177303099">"USB कॉंप्युटर कनेक्शन"</string>
     <string name="usb_connection_category" msgid="2888975803638116041">"म्हणून कनेक्ट करा"</string>
     <string name="usb_mtp_title" msgid="6893938968831995500">"मीडिया डिव्हाइस (MTP)"</string>
-    <string name="usb_mtp_summary" msgid="4427354560399094322">"Windows वरील मीडिया फायली वापरून किंवा Mac वरील Android फाईल स्थानांतरण वापरून तुम्हाला मीडिया फायली स्थानांतरण करू देते (www.android.com/filetransfer पहा)"</string>
+    <string name="usb_mtp_summary" msgid="4427354560399094322">"Windows वरील मीडिया फाइल वापरून किंवा Mac वरील Android फाईल स्थानांतरण वापरून तुम्हाला मीडिया फाइल स्थानांतरण करू देते (www.android.com/filetransfer पहा)"</string>
     <string name="usb_ptp_title" msgid="6629335976394685361">"कॅमेरा (PTP)"</string>
-    <string name="usb_ptp_summary" msgid="460425275251168189">"तुम्हाला कॅमेरा सॉफ्टवेअर वापरून फोटो स्थानांतर आणि MTP वर समर्थित नसलेल्या संगणकावर कोणत्याही फायली स्थानांतर करू देते"</string>
+    <string name="usb_ptp_summary" msgid="460425275251168189">"तुम्हाला कॅमेरा सॉफ्टवेअर वापरून फोटो स्थानांतर आणि MTP वर समर्थित नसलेल्या संगणकावर कोणत्याही फाइल स्थानांतर करू देते"</string>
     <string name="usb_midi_title" msgid="8626512517313340943">"MIDI"</string>
     <string name="usb_midi_summary" msgid="3607444815743771712">"MIDI सक्षम असलेल्या अनुप्रयोगांना आपल्या संगणकावर MIDI सॉफ्टवेअरसह USB वर कार्य करू द्या."</string>
     <string name="storage_other_users" msgid="1055693465220962928">"इतर वापरकर्ते"</string>
@@ -1439,8 +1444,8 @@
     <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>"फोटो आणि इतर मीडियाचा बॅकअप घ्‍या"</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_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>"फोटो आणि इतर मीडियाचा बॅकअप घ्‍या"</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_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>
@@ -1448,11 +1453,11 @@
     <string name="storage_detail_images" msgid="6996202225684468964">"इमेज"</string>
     <string name="storage_detail_videos" msgid="6030983354721080849">"व्हिडिओ"</string>
     <string name="storage_detail_audio" msgid="6011098436589663944">"ऑडिओ"</string>
-    <string name="storage_detail_cached" msgid="5761648455067920683">"कॅश केलेला डेटा"</string>
+    <string name="storage_detail_cached" msgid="5761648455067920683">"कॅशे  केलेला डेटा"</string>
     <string name="storage_detail_other" msgid="9164851767437306618">"इतर"</string>
     <string name="storage_detail_system" msgid="6784247618772153283">"सिस्टम"</string>
     <string name="storage_detail_explore" msgid="8206900269596580264">"<xliff:g id="NAME">^1</xliff:g> एक्सप्लोर करा"</string>
-    <string name="storage_detail_dialog_other" msgid="5073511663616043370">"इतर गोष्टींमध्ये अ‍ॅप्सवरून सेव्ह करून शेअर केलेल्या फायली, इंटरनेट किंवा ब्लूटूथ वरून डाउनलोड केलेल्या फायली, Android फायली आणि इत्यादीचा समावेश असतो. \n\n<xliff:g id="NAME">^1</xliff:g> चा दिसणाराा आशय पाहण्यासाठी, एक्सप्लोर करा वर टॅप करा."</string>
+    <string name="storage_detail_dialog_other" msgid="5073511663616043370">"इतर गोष्टींमध्ये अ‍ॅप्सवरून सेव्ह करून शेअर केलेल्या फाइल, इंटरनेट किंवा ब्लूटूथ वरून डाउनलोड केलेल्या फाइल, Android फाइल आणि इत्यादीचा समावेश असतो. \n\n<xliff:g id="NAME">^1</xliff:g> चा दिसणाराा आशय पाहण्यासाठी, एक्सप्लोर करा वर टॅप करा."</string>
     <string name="storage_detail_dialog_system" msgid="1472572861360014226">"सिस्टममध्ये Android व्हर्जन <xliff:g id="VERSION">%s</xliff:g> रन करण्यासाठी वापरल्या जाणाऱ्या फायलींचा समावेश आहे"</string>
     <string name="storage_detail_dialog_user" msgid="1663117417635010371">"<xliff:g id="USER_0">^1</xliff:g> कडे <xliff:g id="SIZE">^2</xliff:g> स्टोरेज वापरणारे, सेव्ह केलेले फोटो, संगीत, अ‍ॅप्स किंवा इतर डेटा असू शकतो. \n\nतपशील पाहण्यासाठी, <xliff:g id="USER_1">^1</xliff:g> वर स्विच करा."</string>
     <string name="storage_wizard_init_title" msgid="3407283236421089014">"तुमचे <xliff:g id="NAME">^1</xliff:g> सेट करा"</string>
@@ -1468,7 +1473,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>
@@ -1478,32 +1483,32 @@
     <string name="storage_wizard_migrate_details" msgid="4269509141637554985">"हलवण्‍यादरम्यान: \n• <xliff:g id="NAME">^1</xliff:g>काढू नका. \n• काही अ‍ॅप्स योग्यरीत्या कार्य करणार नाहीत. \n• डिव्हाइस चार्ज केलेले ठेवा."</string>
     <string name="storage_wizard_ready_title" msgid="4905921139763520341">"तुमचे <xliff:g id="NAME">^1</xliff:g> वापरण्यासाठी तयार आहे"</string>
     <string name="storage_wizard_ready_external_body" msgid="8785407468656286236">"तुमचे <xliff:g id="NAME">^1</xliff:g> फोटो आणि इतर मीडियासह वापरण्‍यासाठी तयार आहे."</string>
-    <string name="storage_wizard_ready_internal_body" msgid="2258287496678469217">"तुमचे नवीन <xliff:g id="NAME">^1</xliff:g> कार्य करत आहे. \n\nया डिव्‍हाइसवर फोटो, फायली आणि अ‍ॅप डेटा हलविण्‍यासाठी, सेटिंग्ज &gt; संचयनावर जा."</string>
+    <string name="storage_wizard_ready_internal_body" msgid="2258287496678469217">"तुमचे नवीन <xliff:g id="NAME">^1</xliff:g> कार्य करत आहे. \n\nया डिव्‍हाइसवर फोटो, फाइल आणि अ‍ॅप डेटा हलविण्‍यासाठी, सेटिंग्ज &gt; संचयनावर जा."</string>
     <string name="storage_wizard_move_confirm_title" msgid="7362472162039287488">"<xliff:g id="APP">^1</xliff:g> हलवा"</string>
     <string name="storage_wizard_move_confirm_body" msgid="502315190416551319">"<xliff:g id="APP">^1</xliff:g> आणि त्याचा डेटा <xliff:g id="NAME_0">^2</xliff:g> वर हलविण्‍यास केवळ काही क्षण लागतील. हलविणे पूर्ण होईपर्यंत तुम्ही अ‍ॅप वापरण्‍यास सक्षम असणार नाहीत. \n\nहलविण्‍यादरम्यान <xliff:g id="NAME_1">^2</xliff:g> काढू नका."</string>
     <string name="storage_wizard_move_unlock" msgid="7978193904519827600">"डेटा हलवण्यासाठी तुम्हाला <xliff:g id="APP">^1</xliff:g> या वापरकर्त्याला अनलॉक करावे लागेल."</string>
     <string name="storage_wizard_move_progress_title" msgid="5250929161803336592">"<xliff:g id="APP">^1</xliff:g> हलवित आहे…"</string>
     <string name="storage_wizard_move_progress_body" msgid="1713792142250410169">"हलविण्‍यादरम्यान <xliff:g id="NAME">^1</xliff:g> काढू नका. \n\nहलविणे पूर्ण होईपर्यंत या डिव्‍हाइसवरील <xliff:g id="APP">^2</xliff:g> अ‍ॅप उपलब्‍ध नसेल."</string>
     <string name="storage_wizard_move_progress_cancel" msgid="9047521329704060401">"हलविणे रद्द करा"</string>
-    <string name="storage_wizard_slow_body" msgid="2307974936036261069">"हे <xliff:g id="NAME_0">^1</xliff:g> धीमे असल्याचे दिसते. \n\nतुम्ही सुरु ठेवू शकता परंतु या स्थानावर हलविलेल्या अ‍ॅप्समध्‍ये अडथळा येऊ शकतो आणि डेटा स्थानांतरणास बराच वेळ लागू शकतो. \n\nअधिक चांगल्या कार्यप्रदर्शनासाठी आणखी जलद <xliff:g id="NAME_1">^1</xliff:g> वापरण्‍याचा विचार करा."</string>
+    <string name="storage_wizard_slow_body" msgid="2307974936036261069">"हे <xliff:g id="NAME_0">^1</xliff:g> धीमे असल्याचे दिसते. \n\nतुम्ही सुरू ठेवू शकता परंतु या स्थानावर हलविलेल्या अ‍ॅप्समध्‍ये अडथळा येऊ शकतो आणि डेटा स्थानांतरणास बराच वेळ लागू शकतो. \n\nअधिक चांगल्या कार्यप्रदर्शनासाठी आणखी जलद <xliff:g id="NAME_1">^1</xliff:g> वापरण्‍याचा विचार करा."</string>
     <string name="storage_wizard_init_v2_title" msgid="7408910177547901960">"तुम्ही हे <xliff:g id="NAME">^1</xliff:g> कसे वापराल?"</string>
     <string name="storage_wizard_init_v2_internal_title" product="tablet" msgid="7948795312504302810">"अतिरिक्त टॅबलेट स्टोरेजसाठी वापरा"</string>
-    <string name="storage_wizard_init_v2_internal_summary" product="tablet" msgid="6237770506398410172">"फक्त या टॅबलेटवरील अ‍ॅप्स, फायली आणि मीडियासाठी"</string>
+    <string name="storage_wizard_init_v2_internal_summary" product="tablet" msgid="6237770506398410172">"फक्त या टॅबलेटवरील अ‍ॅप्स, फाइल आणि मीडियासाठी"</string>
     <string name="storage_wizard_init_v2_internal_action" product="tablet" msgid="1016850267330050231">"टॅब्लेट स्टोरेज"</string>
     <string name="storage_wizard_init_v2_internal_title" product="default" msgid="2782907833711627804">"अतिरिक्त फोन स्टोरेजसाठी वापरा"</string>
-    <string name="storage_wizard_init_v2_internal_summary" product="default" msgid="6352521760027924000">"फक्त या फोनवरील अ‍ॅप्स, फायली आणि मीडियासाठी"</string>
+    <string name="storage_wizard_init_v2_internal_summary" product="default" msgid="6352521760027924000">"फक्त या फोनवरील अ‍ॅप्स, फाइल आणि मीडियासाठी"</string>
     <string name="storage_wizard_init_v2_internal_action" product="default" msgid="3383888882755852046">"फोन स्टोरेज"</string>
     <string name="storage_wizard_init_v2_or" msgid="883906565226069620">"किंवा"</string>
     <string name="storage_wizard_init_v2_external_title" msgid="7009571510941803101">"पोर्टेबल स्टोरेजसाठी वापरा"</string>
-    <string name="storage_wizard_init_v2_external_summary" msgid="825409811302836460">"डिव्हाइसमध्ये फायली आणि मीडिया स्थानांतरित करण्यासाठी"</string>
+    <string name="storage_wizard_init_v2_external_summary" msgid="825409811302836460">"डिव्हाइसमध्ये फाइल आणि मीडिया स्थानांतरित करण्यासाठी"</string>
     <string name="storage_wizard_init_v2_external_action" msgid="4649591913020218098">"पोर्टेबल स्टोरेज"</string>
     <string name="storage_wizard_init_v2_later" msgid="2605006907172213466">"नंतर सेट करा"</string>
     <string name="storage_wizard_format_confirm_v2_title" msgid="1884699177320256159">"<xliff:g id="NAME">^1</xliff:g> हे फॉरमॅट करायचे का?"</string>
     <string name="storage_wizard_format_confirm_v2_body" msgid="977657376082074305">"अ‍ॅप्स, फाइल्स आणि मीडिया स्टोर करण्यासाठी <xliff:g id="NAME_0">^1</xliff:g> ला फॉरमॅट करणे आवश्यक आहे. \n\nफॉरमॅट केल्यामुळे <xliff:g id="NAME_1">^2</xliff:g> वरील विद्यमान डेटा मिटवला जाईल. आशय गमावणे टाळण्यासाठी, दुसऱ्या <xliff:g id="NAME_2">^3</xliff:g> वर किंवा डिव्हाइसवर त्याचा बॅकअप घ्या."</string>
     <string name="storage_wizard_format_confirm_v2_action" msgid="5576917958786300415">"<xliff:g id="NAME">^1</xliff:g> फॉरमॅट करा"</string>
     <string name="storage_wizard_migrate_v2_title" msgid="6728034411587320249">"<xliff:g id="NAME">^1</xliff:g> वर आशय हलवायचा का?"</string>
-    <string name="storage_wizard_migrate_v2_body" product="tablet" msgid="6943007011251294950">"तुम्ही या <xliff:g id="NAME">^1</xliff:g> मध्ये फायली, मिडिया आणि विशिष्ट अ‍ॅप्स हलवू शकता. \n\nहे तुमच्या टॅबलेटच्या स्टोरेजमधून <xliff:g id="SIZE">^2</xliff:g> जागा मोकळी करेल आणि त्यासाठी अंदाजे <xliff:g id="DURATION">^3</xliff:g> कालावधी लागेल."</string>
-    <string name="storage_wizard_migrate_v2_body" product="default" msgid="3211214309775524554">"तुम्ही या <xliff:g id="NAME">^1</xliff:g> मध्ये फायली, मिडिया आणि विशिष्ट अ‍ॅप्स हलवू शकता. \n\nहे तुमच्या फोनच्या स्टोरेजमधून <xliff:g id="SIZE">^2</xliff:g> जागा मोकळी करेल आणि त्यासाठी अंदाजे <xliff:g id="DURATION">^3</xliff:g> कालावधी लागेल."</string>
+    <string name="storage_wizard_migrate_v2_body" product="tablet" msgid="6943007011251294950">"तुम्ही या <xliff:g id="NAME">^1</xliff:g> मध्ये फाइल, मिडिया आणि विशिष्ट अ‍ॅप्स हलवू शकता. \n\nहे तुमच्या टॅबलेटच्या स्टोरेजमधून <xliff:g id="SIZE">^2</xliff:g> जागा मोकळी करेल आणि त्यासाठी अंदाजे <xliff:g id="DURATION">^3</xliff:g> कालावधी लागेल."</string>
+    <string name="storage_wizard_migrate_v2_body" product="default" msgid="3211214309775524554">"तुम्ही या <xliff:g id="NAME">^1</xliff:g> मध्ये फाइल, मिडिया आणि विशिष्ट अ‍ॅप्स हलवू शकता. \n\nहे तुमच्या फोनच्या स्टोरेजमधून <xliff:g id="SIZE">^2</xliff:g> जागा मोकळी करेल आणि त्यासाठी अंदाजे <xliff:g id="DURATION">^3</xliff:g> कालावधी लागेल."</string>
     <string name="storage_wizard_migrate_v2_checklist" msgid="6283777617014793600">"हलविण्याच्या दरम्यान:"</string>
     <string name="storage_wizard_migrate_v2_checklist_media" msgid="4626548613088549096">"<xliff:g id="NAME">^1</xliff:g> काढून टाकू नका"</string>
     <string name="storage_wizard_migrate_v2_checklist_apps" msgid="6041914027863793837">"काही अ‍ॅप्स काम करू शकणार नाहीत"</string>
@@ -1515,7 +1520,7 @@
     <string name="storage_wizard_slow_v2_title" msgid="4662009769135525740">"हळू <xliff:g id="NAME">^1</xliff:g>"</string>
     <string name="storage_wizard_slow_v2_body" msgid="4443996335261861797">"तुम्ही तरीही <xliff:g id="NAME_0">^1</xliff:g> वापरू शकता, परंतु ते हळू असू शकते. \n\nया <xliff:g id="NAME_1">^2</xliff:g> वर स्टोअर केलेली अ‍ॅप्स योग्यरित्या काम करू शकणार नाहीत आणि आशय ट्रांसफरसाठी जास्त वेळ लागू शकतो. \n\n जलद <xliff:g id="NAME_2">^3</xliff:g> वापरण्याचा प्रयत्न करा, किंवा त्याऐवजी पोर्टेबल स्टोरेजसाठी <xliff:g id="NAME_3">^4</xliff:g> वापरा."</string>
     <string name="storage_wizard_slow_v2_start_over" msgid="1686964124972424100">"पुन्हा सुरू करा"</string>
-    <string name="storage_wizard_slow_v2_continue" msgid="2320238517431613392">"सुरु ठेवा"</string>
+    <string name="storage_wizard_slow_v2_continue" msgid="2320238517431613392">"सुरू ठेवा"</string>
     <string name="storage_wizard_ready_v2_external_body" msgid="5803422587027895664">"तुम्‍ही <xliff:g id="NAME">^1</xliff:g> मध्‍ये आशय हलवू शकता"</string>
     <!-- syntax error in translation for storage_wizard_ready_v2_internal_body (678829432420351228) org.xmlpull.v1.XmlPullParserException: expected: /string read: b (position:END_TAG </b>@1:142 in     <string name="storage_wizard_ready_v2_internal_body" msgid="678829432420351228">"<xliff:g id="NAME">^1</xliff:g> वर आशय हलवण्यासाठी, "</b>"सेटिंग्ज &gt; स्टोरेज"<b>" वर जा"</string>
 )  -->
@@ -1566,10 +1571,10 @@
     <string name="restore_default_apn_completed" msgid="5671734152740058937">"डीफॉल्ट APN सेटिंग्ज रीसेट करणे पूर्ण झाले."</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"रीसेट पर्याय"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"नेटवर्क, अ‍ॅप्स आणि डिव्हाइस रीसेट केले जाऊ शकतात"</string>
-    <string name="reset_network_title" msgid="8944059136930806211">"वायफाय मोबाइल आणि ब्लूटूथ रीसेट करा"</string>
+    <string name="reset_network_title" msgid="8944059136930806211">"वाय-फाय, मोबाइल आणि ब्लूटूथ रीसेट करा"</string>
     <string name="reset_network_desc" msgid="4982633363916261109">"हे यांसह सर्व नेटवर्क सेटिंग्‍ज रीसेट करेल:\n\n"<li>"वाय‑फाय"</li>\n<li>"मोबाइल डेटा"</li>\n<li>"ब्लूटुथ"</li></string>
     <string name="reset_esim_title" msgid="7630781767040831893">"डाउनलोड केलेली सिम मिटवा"</string>
-    <string name="reset_esim_desc" msgid="433226911566802">"बदली सिम डाउनलोड करण्यासाठी, तुमच्या वाहकाशी संपर्क साधा. हे कोणतेही मोबाइल सेवा प्लॅन रद्द करणार नाही."</string>
+    <string name="reset_esim_desc" msgid="433226911566802">"बदली सिम डाउनलोड करण्यासाठी तुमच्या वाहकाशी संपर्क साधा. हे केल्याने कोणतेही मोबाइल सेवा प्लॅन रद्द होणार नाहीत."</string>
     <string name="reset_network_button_text" msgid="4293271046867912819">"सेटिंग्ज रीसेट करा"</string>
     <string name="reset_network_final_desc" msgid="2463817067048751373">"सर्व नेटवर्क सेटिंग्ज रीसेट करायची? तुम्ही ही कृती पहिल्यासारखी करू शकत नाही."</string>
     <string name="reset_network_final_desc_esim" msgid="4676436976372555750">"सर्व नेटवर्क सेटिंग्ज रीसेट करायची आणि डाउनलोड केलेली सिम मिटवायची? तुम्ही ही कृती पहिल्यासारखी करू शकत नाही."</string>
@@ -1582,12 +1587,12 @@
     <string name="master_clear_title" msgid="1560712943955904673">"सर्व डेटा मिटवा (फॅक्टरी रीसेट)"</string>
     <string name="master_clear_short_title" msgid="919098101581335101">"सर्व डेटा मिटवा (फॅक्टरी रीसेट)"</string>
     <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"हे तुमच्या टॅबलेटच्या "<b>"अंतर्गत स्टोरेज"</b>" वरील सर्व डेटा मिटवेल, यासह:\n\n"<li>"तुमचे Google खाते"</li>\n<li>"सिस्टम आणि ॲप डेटा आणि सेटिंग्ज"</li>\n<li>"डाउनलोड केलेली अ‍ॅप्स"</li></string>
-    <string name="master_clear_desc" product="default" msgid="8765543541962866697">"हे तुमच्या फोनच्या "<b>"अंतर्गत स्टोरेज"</b>" वरील सर्व डेटा मिटवेल, यासह:\n\n"<li>"तुमचे Google खाते"</li>\n<li>"सिस्टम आणि अ‍ॅप डेटा सेटिंग्ज"</li>\n<li>"डाउनलोड केलेली अ‍ॅप्स"</li></string>
+    <string name="master_clear_desc" product="default" msgid="8765543541962866697">"हे खालील ठिकाणी तुमच्या फोनच्या "<b>"अंतर्गत स्टोरेज"</b>" वरील सर्व डेटा मिटवेल:\n\n"<li>"तुमचे Google खाते"</li>\n<li>"सिस्टम आणि अ‍ॅप डेटा सेटिंग्ज"</li>\n<li>"डाउनलोड केलेली अ‍ॅप्स"</li></string>
     <string name="master_clear_accounts" product="default" msgid="3432884235445405376">\n\n"तुम्ही खालील खात्यांवर सध्या साइन इन केले आहे:\n"</string>
     <string name="master_clear_other_users_present" product="default" msgid="5993259656117566767">\n\n"या डिव्‍हाइसवर इतर वापरकर्ते उपस्‍थित आहेत.\n"</string>
     <string name="master_clear_desc_also_erases_external" msgid="3947303501615091903"><li>"संगीत"</li>\n<li>"फोटो"</li>\n<li>"अन्य वापरकर्ता डेटा"</li></string>
     <string name="master_clear_desc_also_erases_esim" msgid="4497260499055258773"><li>"eSIM"</li></string>
-    <string name="master_clear_desc_no_cancel_mobile_plan" msgid="6072668588881679461">\n\n"असे केल्‍याने तुमचा मोबाइल सेवा प्‍लॅन रद्द होणार नाही."</string>
+    <string name="master_clear_desc_no_cancel_mobile_plan" msgid="6072668588881679461">\n\n"हे केल्‍याने तुमचा मोबाइल सेवा प्‍लॅन रद्द होणार नाही."</string>
     <string name="master_clear_desc_erase_external_storage" product="nosdcard" msgid="2723272952715259307">\n\n"संगीत, चित्रे आणि अन्य वापरकर्ता डेटा साफ करण्यासाठी, "<b>"USB स्टोरेज"</b>" मिटविणे आवश्यक आहे."</string>
     <string name="master_clear_desc_erase_external_storage" product="default" msgid="9003555775524798797">\n\n"संगीत, चित्रे आणि अन्य वापरकर्ता डेटा साफ करण्यासाठी, "<b>"SD कार्ड"</b>" पुसण्याची आवश्यकता आहे."</string>
     <string name="erase_external_storage" product="nosdcard" msgid="8989746770347525207">"USB स्टोरेज मिटवा"</string>
@@ -1611,10 +1616,10 @@
     <string name="tether_settings_title_bluetooth" msgid="1999590158102569959">"ब्लूटूथ टेदरिंग"</string>
     <string name="tether_settings_title_usb_bluetooth" msgid="1159128764162788159">"टेदरिंग"</string>
     <string name="tether_settings_title_all" msgid="6935843543433954181">"हॉटस्‍पॉट आणि टेदरिंग"</string>
-    <string name="tether_settings_summary_hotspot_on_tether_on" msgid="1289593649526514499">"हॉटस्पॉट चालू, टेदरिंग करत आहे"</string>
-    <string name="tether_settings_summary_hotspot_on_tether_off" msgid="8010689354668285422">"हॉटस्पॉट चालू"</string>
+    <string name="tether_settings_summary_hotspot_on_tether_on" msgid="1289593649526514499">"हॉटस्पॉट सुरू, टेदरिंग करत आहे"</string>
+    <string name="tether_settings_summary_hotspot_on_tether_off" msgid="8010689354668285422">"हॉटस्पॉट सुरू"</string>
     <string name="tether_settings_summary_hotspot_off_tether_on" msgid="1349909238672649877">"टेदरिंग"</string>
-    <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"डेटा सेव्हर चालू असताना टिथर करू शकत नाही किंवा पोर्टेबल हॉटस्पॉटचा वापर करू शकत नाही"</string>
+    <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"डेटा सेव्हर सुरू असताना टिथर करू शकत नाही किंवा पोर्टेबल हॉटस्पॉटचा वापर करू शकत नाही"</string>
     <string name="usb_title" msgid="7480927657535578688">"USB"</string>
     <string name="usb_tethering_button_text" msgid="6242228383142012332">"USB टेदरिंग"</string>
     <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"फोनचे इंटरनेट कनेक्शन USB ने शेअर करा"</string>
@@ -1643,7 +1648,7 @@
     <string name="mobile_insert_sim_card" msgid="7594550403454243732">"कृपया सिम कार्ड घाला आणि रीस्टार्ट करा"</string>
     <string name="mobile_connect_to_internet" msgid="6031886097365170913">"कृपया इंटरनेटशी कनेक्ट करा"</string>
     <string name="location_title" msgid="8664674161765477168">"माझे स्थान"</string>
-    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"कार्य प्रोफाईलसाठी स्थान"</string>
+    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"कार्य प्रोफाइलसाठी स्थान"</string>
     <string name="location_app_level_permissions" msgid="1298041503927632960">"अ‍ॅप परवानगी"</string>
     <string name="location_app_permission_summary_location_off" msgid="541372845344796336">"स्‍थान बंद आहे"</string>
     <plurals name="location_app_permission_summary_location_on" formatted="false" msgid="7904821382328758218">
@@ -1652,7 +1657,7 @@
     </plurals>
     <string name="location_category_recent_location_access" msgid="286059523360285026">"अलीकडील स्थान अ‍ॅक्सेस"</string>
     <string name="location_recent_location_access_view_details" msgid="2051602261436245905">"तपशील पहा"</string>
-    <string name="location_no_recent_apps" msgid="77502059586413278">"अलीकडे कोणत्याही ॲप्सने स्थानाची विनंती केलेली नाही"</string>
+    <string name="location_no_recent_apps" msgid="77502059586413278">"अलीकडे कोणत्याही अ‍ॅप्सनी स्थानाची विनंती केलेली नाही"</string>
     <string name="location_no_recent_accesses" msgid="6289916310397279890">"अलीकडे अ‍ॅक्सेस केलेल्या अ‍ॅप्सचे स्थान नाही"</string>
     <string name="location_high_battery_use" msgid="7177199869979522663">"उच्च बॅटरी वापर"</string>
     <string name="location_low_battery_use" msgid="5030448574501435888">"अल्प बॅटरी वापर"</string>
@@ -1722,12 +1727,12 @@
     <string name="lockpassword_choose_your_password_header_for_face" msgid="8823110536502072216">"फेस ऑथेंटिकेशन वापरण्यासाठी, पासवर्ड सेट करा"</string>
     <string name="lockpassword_choose_your_pattern_header_for_face" msgid="5563793748503883666">"फेस ऑथेंटिकेशन वापरण्यासाठी, पॅटर्न सेट करा"</string>
     <string name="lockpassword_choose_your_pin_header_for_face" msgid="7238352632535405068">"फेस ऑथेंटिकेशन वापरण्यासाठी, पिन सेट करा"</string>
-    <string name="lockpassword_confirm_your_pattern_generic" msgid="6146545393074070916">"सुरु ठेवण्यासाठी तुमच्या डिव्हाइस पॅटर्नचा वापर करा"</string>
-    <string name="lockpassword_confirm_your_pin_generic" msgid="8732268389177735264">"सुरु ठेवण्यासाठी तुमचे डिव्हाइस पिन एंटर करा"</string>
-    <string name="lockpassword_confirm_your_password_generic" msgid="6304552647060899594">"सुरु ठेवण्यासाठी तुमचे डिव्हाइस पासवर्ड एंटर करा"</string>
-    <string name="lockpassword_confirm_your_pattern_generic_profile" msgid="3074250084050465513">"सुरु ठेवण्यासाठी आपल्या कार्य नमुन्याचा वापर करा"</string>
-    <string name="lockpassword_confirm_your_pin_generic_profile" msgid="6037908971086439523">"सुरु ठेवण्यासाठी तुमचा कार्य पिन एंटर करा"</string>
-    <string name="lockpassword_confirm_your_password_generic_profile" msgid="2646162490703489685">"सुरु ठेवण्यासाठी तुमचा कार्य पासवर्ड एंटर करा"</string>
+    <string name="lockpassword_confirm_your_pattern_generic" msgid="6146545393074070916">"सुरू ठेवण्यासाठी तुमच्या डिव्हाइस पॅटर्नचा वापर करा"</string>
+    <string name="lockpassword_confirm_your_pin_generic" msgid="8732268389177735264">"सुरू ठेवण्यासाठी तुमचे डिव्हाइस पिन एंटर करा"</string>
+    <string name="lockpassword_confirm_your_password_generic" msgid="6304552647060899594">"सुरू ठेवण्यासाठी तुमचे डिव्हाइस पासवर्ड एंटर करा"</string>
+    <string name="lockpassword_confirm_your_pattern_generic_profile" msgid="3074250084050465513">"सुरू ठेवण्यासाठी आपल्या कार्य नमुन्याचा वापर करा"</string>
+    <string name="lockpassword_confirm_your_pin_generic_profile" msgid="6037908971086439523">"सुरू ठेवण्यासाठी तुमचा कार्य पिन एंटर करा"</string>
+    <string name="lockpassword_confirm_your_password_generic_profile" msgid="2646162490703489685">"सुरू ठेवण्यासाठी तुमचा कार्य पासवर्ड एंटर करा"</string>
     <string name="lockpassword_strong_auth_required_device_pattern" msgid="1014214190135045781">"वाढीव सुरक्षिततेसाठी, तुमच्या डीव्हाइसचा पॅटर्न वापरा"</string>
     <string name="lockpassword_strong_auth_required_device_pin" msgid="24030584350601016">"वाढीव सुरक्षिततेसाठी, तुमच्या डिव्हाइसचा पिन टाका"</string>
     <string name="lockpassword_strong_auth_required_device_password" msgid="7746588206458754598">"वाढीव सुरक्षिततेसाठी, तुमच्या डिव्हाइसचा पासवर्ड टाका"</string>
@@ -1751,12 +1756,12 @@
     <string name="lockpattern_recording_inprogress" msgid="4060818382176523671">"पूर्ण झाल्यावर बोट सोडा"</string>
     <string name="lockpattern_recording_incorrect_too_short" msgid="6374760294545431845">"कमीत कमी <xliff:g id="NUMBER">%d</xliff:g> बिंदू कनेक्ट करा. पुन्हा प्रयत्न करा."</string>
     <string name="lockpattern_pattern_entered_header" msgid="2108106638322637851">"पॅटर्न रेकॉर्ड झाला"</string>
-    <string name="lockpattern_need_to_confirm" msgid="4079482507985867389">"पुष्टी करण्यासाठी पुन्हा नमूना रेखांकित करा"</string>
+    <string name="lockpattern_need_to_confirm" msgid="4079482507985867389">"खात्री करण्यासाठी पॅटर्न पुन्हा एकदा काढा"</string>
     <string name="lockpattern_pattern_confirmed_header" msgid="5603156929428721407">"तुमचा नवीन अनलॉक पॅटर्न"</string>
     <string name="lockpattern_confirm_button_text" msgid="7059311304112902598">"निश्चित करा"</string>
     <string name="lockpattern_restart_button_text" msgid="4322968353922529868">"पुन्हा रेखाटा"</string>
     <string name="lockpattern_retry_button_text" msgid="5473976578241534298">"साफ करा"</string>
-    <string name="lockpattern_continue_button_text" msgid="3328913552656376892">"सुरु ठेवा"</string>
+    <string name="lockpattern_continue_button_text" msgid="3328913552656376892">"सुरू ठेवा"</string>
     <string name="lockpattern_settings_title" msgid="5152005866870766842">"पॅटर्न अनलॉक करा"</string>
     <string name="lockpattern_settings_enable_title" msgid="8508410891939268080">"आवश्यक पॅटर्न"</string>
     <string name="lockpattern_settings_enable_summary" msgid="8027605503917737512">"स्क्रीन अनलॉक करण्यासाठी पॅटर्न रेखाटणे आवश्यक आहे"</string>
@@ -1800,9 +1805,9 @@
     <string name="auto_launch_label_generic" msgid="7865828543459493308">"डीफॉल्ट"</string>
     <string name="screen_compatibility_label" msgid="3638271673726075815">"स्क्रीन सुसंगतता"</string>
     <string name="permissions_label" msgid="7341733648403464213">"परवानग्या"</string>
-    <string name="cache_header_label" msgid="3202284481380361966">"कॅश"</string>
-    <string name="clear_cache_btn_text" msgid="107507684844780651">"कॅश साफ करा"</string>
-    <string name="cache_size_label" msgid="6205173678102220499">"कॅश"</string>
+    <string name="cache_header_label" msgid="3202284481380361966">"कॅशे"</string>
+    <string name="clear_cache_btn_text" msgid="107507684844780651">"कॅशे  साफ करा"</string>
+    <string name="cache_size_label" msgid="6205173678102220499">"कॅशे"</string>
     <plurals name="uri_permissions_text" formatted="false" msgid="8938478333743197020">
       <item quantity="other">%d आयटम</item>
       <item quantity="one"> 1 आयटम</item>
@@ -1835,11 +1840,11 @@
     <string name="sort_order_size" msgid="3167376197248713027">"आकारानुसार क्रमवारी लावा"</string>
     <string name="sort_order_recent_notification" msgid="5592496977404445941">"सर्वात अलीकडील"</string>
     <string name="sort_order_frequent_notification" msgid="5640245013098010347">"सर्वाधिक"</string>
-    <string name="show_running_services" msgid="1895994322704667543">"चालू सेवा दर्शवा"</string>
-    <string name="show_background_processes" msgid="88012264528093617">"कॅश   केलेल्या प्रक्रिया दर्शवा"</string>
+    <string name="show_running_services" msgid="1895994322704667543">"सुरू सेवा दर्शवा"</string>
+    <string name="show_background_processes" msgid="88012264528093617">"कॅशे    केलेल्या प्रक्रिया दर्शवा"</string>
     <string name="default_emergency_app" msgid="286530070173495823">"आणीबाणी अ‍ॅप"</string>
     <string name="reset_app_preferences" msgid="1426500030595212077">"अ‍ॅप प्राधान्ये रीसेट करा"</string>
-    <string name="reset_app_preferences_title" msgid="792909865493673598">"अ‍ॅप प्राधान्ये रीसेट करायचे?"</string>
+    <string name="reset_app_preferences_title" msgid="792909865493673598">"अ‍ॅप प्राधान्ये रीसेट करायची?"</string>
     <string name="reset_app_preferences_desc" msgid="7935273005301096031">"हे यासाठी सर्व प्राधान्ये रीसेट करेल:\n\n "<li>"बंद केलेली अ‍ॅप्स"</li>\n" "<li>"बंद केलेल्या अ‍ॅप्स सूचना"</li>\n" "<li>"क्रियांसाठी डीफॉल्ट अ‍ॅप्लिकेशन्स"</li>\n" "<li>"अ‍ॅप्ससाठी पार्श्वभूमीवरील डेटा प्रतिबंध"</li>\n" "<li>"कोणतेही परवानगी प्रतिबंध"</li>\n\n" तुम्ही कोणताही अ‍ॅप डेटा गमावणार नाही."</string>
     <string name="reset_app_preferences_button" msgid="2041894727477934656">"अ‍ॅप्स रीसेट करा"</string>
     <string name="manage_space_text" msgid="6166469422303124302">"जागा व्यवस्थापित करा"</string>
@@ -1848,7 +1853,7 @@
     <string name="filter_apps_all" msgid="3938077534861382701">"सर्व अ‍ॅप्स"</string>
     <string name="filter_apps_disabled" msgid="5394488790555678117">"बंद केलेले अ‍ॅप्स"</string>
     <string name="filter_apps_third_party" msgid="3985794876813232322">"डाउनलोड केले"</string>
-    <string name="filter_apps_running" msgid="6852975378502426359">"चालू आहे"</string>
+    <string name="filter_apps_running" msgid="6852975378502426359">"सुरू आहे"</string>
     <string name="filter_apps_onsdcard" product="nosdcard" msgid="3501701148760911442">"USB स्टोरेज"</string>
     <string name="filter_apps_onsdcard" product="default" msgid="135989136394672864">"SD कार्डवर"</string>
     <string name="not_installed" msgid="6432131218496140253">"या वापरकर्त्यासाठी इंस्टॉल केले नाही"</string>
@@ -1857,7 +1862,7 @@
     <string name="internal_storage" msgid="7392373600013294853">"अंतर्गत स्टोरेज"</string>
     <string name="recompute_size" msgid="4290692197892743928">"आकाराचे पुनर्संगणन करत आहे…"</string>
     <string name="clear_data_dlg_title" msgid="7388024498687029597">"अ‍ॅप डेटा हटवायचा?"</string>
-    <string name="clear_data_dlg_text" msgid="6849657743695013414">"या अ‍ॅपचा सर्व डेटा कायमचा हटवला जाईल. यात सर्व फायली, सेटिंग्ज, खाती, डेटाबेस इ. समाविष्ट असेल."</string>
+    <string name="clear_data_dlg_text" msgid="6849657743695013414">"या अ‍ॅपचा सर्व डेटा कायमचा हटवला जाईल. यात सर्व फाइल, सेटिंग्ज, खाती, डेटाबेस इ. समाविष्ट असेल."</string>
     <string name="dlg_ok" msgid="4666570206507476557">"ठीक"</string>
     <string name="dlg_cancel" msgid="2434951039156262467">"रद्द करा"</string>
     <string name="app_not_found_dlg_title" msgid="394147475018718483"></string>
@@ -1890,13 +1895,13 @@
     <string name="app_install_details_title" msgid="6954953384372934881">"अ‍ॅप तपशील"</string>
     <string name="app_install_details_summary" msgid="6612222941121363940">"अ‍ॅप <xliff:g id="APP_STORE">%1$s</xliff:g> मधून इंस्टॉल केला"</string>
     <string name="instant_app_details_summary" msgid="6384264315914966114">"<xliff:g id="APP_STORE">%1$s</xliff:g> ची अधिक माहिती"</string>
-    <string name="app_ops_running" msgid="6378418969742957805">"चालू आहे"</string>
+    <string name="app_ops_running" msgid="6378418969742957805">"सुरू आहे"</string>
     <string name="app_ops_never_used" msgid="8305262378162525813">"(कधीही न वापरलेले)"</string>
     <string name="no_default_apps" msgid="4519038578011412532">"कोणतेही डीफॉल्‍ट अ‍ॅप्स नाहीत."</string>
     <string name="storageuse_settings_title" msgid="3390798597982116048">"संचयन वापर"</string>
     <string name="storageuse_settings_summary" msgid="3013328092465903687">"ॲप्सद्वारे वापरलेले संचयन पहा"</string>
     <string name="service_restarting" msgid="1190995225643385568">"रीस्टार्ट करत आहे"</string>
-    <string name="cached" msgid="4019482949725020855">"पार्श्वभूमी प्रक्रिया कॅश   केली"</string>
+    <string name="cached" msgid="4019482949725020855">"पार्श्वभूमी प्रक्रिया कॅशे    केली"</string>
     <string name="no_running_services" msgid="618823924559385173">"काहीही चालत नाही."</string>
     <string name="service_started_by_app" msgid="6906027340122215035">"अ‍ॅप द्वारे प्रारंभ केला."</string>
     <!-- no translation found for service_client_name (7083258170099389413) -->
@@ -1918,9 +1923,9 @@
     <string name="running_processes_header_apps_prefix" msgid="4024980745400903746">"अ‍ॅप्स"</string>
     <string name="running_processes_header_free_prefix" msgid="1092348393136753031">"मोकळी"</string>
     <string name="running_processes_header_used_prefix" msgid="2984090414986096084">"वापरलेली"</string>
-    <string name="running_processes_header_cached_prefix" msgid="8398315634778729026">"कॅश   केलेले"</string>
+    <string name="running_processes_header_cached_prefix" msgid="8398315634778729026">"कॅशे    केलेले"</string>
     <string name="running_processes_header_ram" msgid="3867954556214535588">"RAM चे <xliff:g id="RAM_0">%1$s</xliff:g>"</string>
-    <string name="runningservicedetails_settings_title" msgid="7075556369123578372">"चालू अ‍ॅप"</string>
+    <string name="runningservicedetails_settings_title" msgid="7075556369123578372">"सुरू अ‍ॅप"</string>
     <string name="no_services" msgid="2085012960886321920">"सक्रिय नाहीत"</string>
     <string name="runningservicedetails_services_title" msgid="5890094559748633615">"सेवा"</string>
     <string name="runningservicedetails_processes_title" msgid="5496507383850423763">"प्रक्रिया"</string>
@@ -1934,8 +1939,8 @@
     <string name="process_service_in_use_description" msgid="2253782391122637651">"<xliff:g id="COMP_NAME">%1$s</xliff:g> सेवा वापरात आहे."</string>
     <string name="process_provider_in_use_description" msgid="7841332986505618569">"<xliff:g id="COMP_NAME">%1$s</xliff:g> प्रदाता वापरात आहे."</string>
     <string name="runningservicedetails_stop_dlg_title" msgid="6022380394950336262">"सिस्टम सेवा थांबवायची?"</string>
-    <string name="runningservicedetails_stop_dlg_text" product="tablet" msgid="7619909495973395025">"तुम्ही ही सेवा थांबविल्यास, तुम्ही तीचा पॉवर बंद करून पुन्हा चालू करेपर्यंत आपल्या टॅब्लेटची काही वैशिष्ट्ये योग्यरितीने कार्य करणे थांबवू शकतात."</string>
-    <string name="runningservicedetails_stop_dlg_text" product="default" msgid="8168850859827213988">"तुम्ही ही सेवा थांबविल्यास, तुम्ही तीचा पॉवर बंद करून पुन्हा चालू करेपर्यंत आपल्या टॅब्लेटची काही वैशिष्ट्ये योग्यरितीने कार्य करणे थांबवू शकतात."</string>
+    <string name="runningservicedetails_stop_dlg_text" product="tablet" msgid="7619909495973395025">"तुम्ही ही सेवा थांबविल्यास, तुम्ही तीचा पॉवर बंद करून पुन्हा सुरू करेपर्यंत आपल्या टॅब्लेटची काही वैशिष्ट्ये योग्यरितीने कार्य करणे थांबवू शकतात."</string>
+    <string name="runningservicedetails_stop_dlg_text" product="default" msgid="8168850859827213988">"तुम्ही ही सेवा थांबविल्यास, तुम्ही तीचा पॉवर बंद करून पुन्हा सुरू करेपर्यंत आपल्या टॅब्लेटची काही वैशिष्ट्ये योग्यरितीने कार्य करणे थांबवू शकतात."</string>
     <string name="language_input_gesture_title" msgid="7547999017999159601">"भाषा, इनपुट आणि जेश्चर"</string>
     <string name="language_input_gesture_summary_on_with_assist" msgid="315262339899294132"></string>
     <string name="language_input_gesture_summary_on_non_assist" msgid="6054599939153669225"></string>
@@ -2047,7 +2052,7 @@
     <string name="talkback_summary" msgid="6602857105831641574">"स्क्रीन रीडर प्रामुख्याने दृष्टीहीन किंवा कमी दृष्टी असलेल्या लोकांसाठी आहे"</string>
     <string name="select_to_speak_summary" msgid="7514180457557735421">"आयटमना मोठ्याने ऐकण्यासाठी स्क्रीनवरील आयटमवर टॅप करा"</string>
     <string name="accessibility_captioning_title" msgid="5878371993023439642">"मथळे"</string>
-    <string name="accessibility_screen_magnification_title" msgid="7250949681883917360">"मोठे करणे"</string>
+    <string name="accessibility_screen_magnification_title" msgid="7250949681883917360">"मॅग्निफिकेशन"</string>
     <string name="accessibility_screen_magnification_gestures_title" msgid="9199287875401817974">"तीन वेळा टॅप करून मोठे करा"</string>
     <string name="accessibility_screen_magnification_navbar_title" msgid="400655612610761242">"बटणासह मोठे करा"</string>
     <string name="accessibility_screen_magnification_state_navbar_gesture" msgid="1863831350878995600">"बटण आणि तीन वेळा टॅप करून मोठे करा"</string>
@@ -2055,12 +2060,12 @@
     <string name="accessibility_screen_magnification_short_summary" msgid="5698545174944494486">"झूम करण्यासाठी 3 वेळा टॅप करा"</string>
     <string name="accessibility_screen_magnification_navbar_short_summary" msgid="5418767043532322397">"झूम करण्यासाठी बटणावर टॅप करा"</string>
     <string name="accessibility_screen_magnification_summary" msgid="3363006902079431772"><b>"झूम करण्यासाठी"</b>", स्क्रीनवर 3 वेळा पटपट टॅप करा.\n"<ul><li>"स्क्रोल करण्यासाठी 2 किंवा अधिक बोटांनी ड्रॅग करा"</li>\n<li>"झूम ॲडजस्ट करण्यासाठी 2 किंवा अधिक बोटांनी पिंच करा"</li></ul>\n\n<b>"तात्पुरते झूम करण्यासाठी"</b>", स्क्रीनवर 3 वेळा पटपट टॅप करा आणि तिसर्‍या टॅपवर तुमचे बोट धरून ठेवा.\n"<ul><li>"स्क्रीनवर इथेतिथे जाण्यासाठी ड्रॅग करा"</li>\n<li>"झूम कमी करण्यासाठी बोट उचला"</li></ul>\n\n"तुम्ही कीबोर्ड किंवा नेव्हिगेशन बारचा झूम वाढवू शकत नाही."</string>
-    <string name="accessibility_screen_magnification_navbar_summary" msgid="4726360285256503132">"मोठे करणे चालू केले असताना, त्वरित मोठे करण्यासाठी, स्क्रीनच्या तळाशी असलेले प्रवेशयोग्यता बटण वापरा.\n\n"<b>"झूम करण्यासाठी"</b>", प्रवेशयोग्यता बटण टॅप करा, नंतर स्क्रीनवर कुठेही टॅप करा.\n"<ul><li>"स्क्रोल करण्यासाठी 2 किंवा अधिक बोटे ड्रॅग करा"</li>\n<li>"झूम समायोजित करण्यासाठी 2 किंवा अधिक बोटे पिंच करा"</li></ul>\n\n<b>"तात्पुरते झूम करण्यासाठी"</b>", प्रवेशयोग्यता बटण दाबा, नंतर स्क्रीनवर कुठेही स्पर्श करा आणि धरून ठेवा.\n"<ul><li>"स्क्रीनवर अवतीभवती हलवण्यासाठी ड्रॅग करा"</li>\n<li>"झूम कमी करण्यासाठी बोट उचला"</li></ul>\n\n"आपण कीबोर्ड किंवा नेव्हिगेशन बारचा झूम वाढवू शकत नाही."</string>
-    <string name="accessibility_screen_magnification_navbar_configuration_warning" msgid="6477234309484795550">"प्रवेशयोग्यता बटण <xliff:g id="SERVICE">%1$s</xliff:g> वर सेट केले आहे. मोठे करणे वापरण्यासाठी, प्रवेशयोग्यता बटणाला स्पर्श करा आणि धरून ठेवा, नंतर मोठे करणे निवडा."</string>
+    <string name="accessibility_screen_magnification_navbar_summary" msgid="4726360285256503132">"मॅग्निफिकेशन सुरू केले असताना, त्वरित मोठे करण्यासाठी, स्क्रीनच्या तळाशी असलेले प्रवेशयोग्यता बटण वापरा.\n\n"<b>"झूम करण्यासाठी"</b>", प्रवेशयोग्यता बटण टॅप करा, नंतर स्क्रीनवर कुठेही टॅप करा.\n"<ul><li>"स्क्रोल करण्यासाठी 2 किंवा अधिक बोटे ड्रॅग करा"</li>\n<li>"झूम समायोजित करण्यासाठी 2 किंवा अधिक बोटे पिंच करा"</li></ul>\n\n<b>"तात्पुरते झूम करण्यासाठी"</b>", प्रवेशयोग्यता बटण दाबा, नंतर स्क्रीनवर कुठेही स्पर्श करा आणि धरून ठेवा.\n"<ul><li>"स्क्रीनवर अवतीभवती हलवण्यासाठी ड्रॅग करा"</li>\n<li>"झूम कमी करण्यासाठी बोट उचला"</li></ul>\n\n"आपण कीबोर्ड किंवा नेव्हिगेशन बारचा झूम वाढवू शकत नाही."</string>
+    <string name="accessibility_screen_magnification_navbar_configuration_warning" msgid="6477234309484795550">"प्रवेशयोग्यता बटण <xliff:g id="SERVICE">%1$s</xliff:g> वर सेट केले आहे. मॅग्निफिकेशन वापरण्यासाठी, प्रवेशयोग्यता बटणाला स्पर्श करा आणि धरून ठेवा, नंतर मॅग्निफिकेशन निवडा."</string>
     <string name="accessibility_global_gesture_preference_title" msgid="3842279082831426816">"आवाज की शॉर्टकट"</string>
     <string name="accessibility_shortcut_service_title" msgid="3516052294376744060">"शॉर्टकट सेवा"</string>
     <string name="accessibility_shortcut_service_on_lock_screen_title" msgid="1279441617927949980">"लॉक स्‍क्रीनवरून अनुमती द्या"</string>
-    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"शॉर्टकट चालू असताना, प्रवेशयोग्यता वैशिष्ट्य सुरू करण्यासाठी तुम्ही आवाज बटणे 3 सेकंद दाबू शकता."</string>
+    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"शॉर्टकट सुरू असताना, प्रवेशयोग्यता वैशिष्ट्य सुरू करण्यासाठी तुम्ही आवाज बटणे 3 सेकंद दाबू शकता."</string>
     <string name="accessibility_toggle_high_text_contrast_preference_title" msgid="5652244684961877255">"उच्च कॉंट्रास्ट मजकूर"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"स्क्रीन विस्तृतीकरण स्वयं अद्ययावत करा"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"अ‍ॅप संक्रमणांवर स्क्रीन विस्तृतीकरण अद्ययावत करा"</string>
@@ -2078,11 +2083,11 @@
     <string name="accessibility_timeout_1min" msgid="5019003178551730551">"एक मिनिट"</string>
     <string name="accessibility_timeout_2mins" msgid="4124259290444829477">"दोन मिनिटे"</string>
     <string name="accessibility_content_timeout_preference_title" msgid="5160746882250939464">"वाचण्यासाठी वेळ"</string>
-    <string name="accessibility_control_timeout_preference_title" msgid="2771808346038759474">"कृती करण्यासाठी लागणारा वेळ"</string>
+    <string name="accessibility_control_timeout_preference_title" msgid="2771808346038759474">"कृतीसाठी लागणारा वेळ"</string>
     <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"तात्पुरता दृश्यमान असेल असा तुम्हाला वाचायचा असलेला मेसेज किती वेळ दाखवायचा ते निवडा.\n\nसर्व अ‍ॅप्स यासेटिंगला सपोर्ट करत नाहीत."</string>
     <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"तुम्हाला कृती करण्यास सांगणारे, परंतु केवळ तात्पुरते दृश्यमान असलेले मेसेज किती वेळ दाखवले जावेत ते निवडा.\n\nया सेटिंगला सर्व अ‍ॅप्समध्ये सपोर्ट असेल असे नाही."</string>
     <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"स्पर्श आणि धरण्याचा विलंब"</string>
-    <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"रंग व्युत्क्रम"</string>
+    <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"कलर इन्व्हर्जन"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"कार्यप्रदर्शन प्रभावित करू शकते"</string>
     <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"थांबल्याची वेळ"</string>
     <string name="accessibility_autoclick_description" msgid="5492414927846407499">"तुम्ही माउस वापरत असल्यास, जेव्हा कर्सर काही वेळासाठी हलणे थांबवतो तेव्हा तुम्ही तो आपोआप कृती करण्यासाठी सेट करू शकता."</string>
@@ -2095,17 +2100,17 @@
     <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"रंग सुधारणा वापरा"</string>
     <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"कॅप्शन वापरा"</string>
     <string name="accessibility_hearingaid_instruction_continue_button" msgid="4650111296711466691">"सुरू ठेवा"</string>
-    <string name="accessibility_hearingaid_title" msgid="3700978781235124891">"श्रवण यंत्रे"</string>
-    <string name="accessibility_hearingaid_not_connected_summary" msgid="634573930469952213">"कोणतीही श्रवण यंत्रे जोडलेली नाहीत"</string>
-    <string name="accessibility_hearingaid_adding_summary" msgid="4139031880828714300">"श्रवण यंत्रे जोडा"</string>
-    <string name="accessibility_hearingaid_pair_instructions_first_message" msgid="2671518890909750740">"तुमची श्रवण यंत्रे पेअर करण्यासाठी पुढील स्क्रीनवर तुमचे डिव्हाइस शोधा आणि त्यावर टॅप करा."</string>
-    <string name="accessibility_hearingaid_pair_instructions_second_message" msgid="1584538735488464991">"तुमची श्रवण यंत्रे पेअरिंग मोडमध्ये असल्याची खात्री करा."</string>
+    <string name="accessibility_hearingaid_title" msgid="3700978781235124891">"श्रवणयंत्रे"</string>
+    <string name="accessibility_hearingaid_not_connected_summary" msgid="634573930469952213">"कोणतीही श्रवणयंत्रे जोडलेली नाहीत"</string>
+    <string name="accessibility_hearingaid_adding_summary" msgid="4139031880828714300">"श्रवणयंत्रे जोडा"</string>
+    <string name="accessibility_hearingaid_pair_instructions_first_message" msgid="2671518890909750740">"तुमची श्रवणयंत्रे पेअर करण्यासाठी पुढील स्क्रीनवर तुमचे डिव्हाइस शोधा आणि त्यावर टॅप करा."</string>
+    <string name="accessibility_hearingaid_pair_instructions_second_message" msgid="1584538735488464991">"तुमची श्रवणयंत्रे पेअरिंग मोडमध्ये असल्याची खात्री करा."</string>
     <string name="accessibility_hearingaid_active_device_summary" msgid="6081382497207168885">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> सुरू आहे"</string>
     <plurals name="show_number_hearingaid_count" formatted="false" msgid="7906547154695855096">
-      <item quantity="other"> सेव्ह केलेली <xliff:g id="NUMBER_DEVICE_COUNT_1">%1$d</xliff:g> श्रवण यंत्रे</item>
-      <item quantity="one"> सेव्ह केलेले <xliff:g id="NUMBER_DEVICE_COUNT_0">%1$d</xliff:g> श्रवण यंत्र</item>
+      <item quantity="other"> सेव्ह केलेली <xliff:g id="NUMBER_DEVICE_COUNT_1">%1$d</xliff:g> श्रवणयंत्रे</item>
+      <item quantity="one"> सेव्ह केलेले <xliff:g id="NUMBER_DEVICE_COUNT_0">%1$d</xliff:g> श्रवणयंत्र</item>
     </plurals>
-    <string name="accessibility_summary_state_enabled" msgid="7357731696603247963">"चालू"</string>
+    <string name="accessibility_summary_state_enabled" msgid="7357731696603247963">"सुरू"</string>
     <string name="accessibility_summary_state_disabled" msgid="9197369047683087620">"बंद"</string>
     <string name="accessibility_summary_state_stopped" msgid="3170264683616172746">"काम करत नाही आहे. माहितीसाठी टॅप करा."</string>
     <string name="accessibility_description_state_stopped" msgid="7666178628053039493">"या सेवेमध्ये बिघाड आहे."</string>
@@ -2176,11 +2181,11 @@
     <string name="enable_service_title" msgid="2746143093464928251">"<xliff:g id="SERVICE">%1$s</xliff:g> वापरायचे?"</string>
     <string name="capabilities_list_title" msgid="8177719542886123788">"यासाठी <xliff:g id="SERVICE">%1$s</xliff:g> आवश्यक आहे:"</string>
     <string name="touch_filtered_warning" msgid="3072665526993043879">"अ‍ॅप परवानगी विनंती अस्पष्‍ट करीत असल्‍याने, सेटिंग्ज आपल्या प्रतिसादाची पडताळणी करू शकत नाहीत."</string>
-    <string name="enable_service_encryption_warning" msgid="3580275420826492351">"तुम्ही <xliff:g id="SERVICE">%1$s</xliff:g> चालू केल्‍यास, तुमचे डिव्हाइस डेटा एंक्रिप्शन वर्धित करण्‍यासाठी तुमचे स्क्रीन लॉक वापरणार नाही."</string>
-    <string name="secure_lock_encryption_warning" msgid="8724670910924531152">"तुम्ही ॲक्सेसयोग्यता सेवा चालू केली असल्‍यामुळे, तुमचे डिव्हाइस डेटा एंक्रिप्शन वर्धित करण्‍यासाठी तुमचे स्क्रीन लॉक वापरणार नाही."</string>
-    <string name="enable_service_pattern_reason" msgid="7415969807374459848">"<xliff:g id="SERVICE">%1$s</xliff:g> चालू करण्यामुळे डेटा एंक्रिप्शनवर परिणाम होतो, तुम्हाला तुमच्या पॅटर्नची पुष्टी करण्याची आवश्यकता आहे."</string>
-    <string name="enable_service_pin_reason" msgid="2899057249007636608">"<xliff:g id="SERVICE">%1$s</xliff:g> चालू करण्याने एंक्रिप्शन डेटा प्रभावित होतो, तुम्हाला तुमच्या पिन ची पुष्टी करण्याची आवश्यकता आहे."</string>
-    <string name="enable_service_password_reason" msgid="5210815233227388083">"<xliff:g id="SERVICE">%1$s</xliff:g> चालू करण्यामुळे डेटा एंक्रिप्शनवर परिणाम होतो, तुम्हाला तुमच्या पासवर्डची पुष्टी करण्याची आवश्यकता आहे."</string>
+    <string name="enable_service_encryption_warning" msgid="3580275420826492351">"तुम्ही <xliff:g id="SERVICE">%1$s</xliff:g> सुरू केल्‍यास, तुमचे डिव्हाइस डेटा एंक्रिप्शन वर्धित करण्‍यासाठी तुमचे स्क्रीन लॉक वापरणार नाही."</string>
+    <string name="secure_lock_encryption_warning" msgid="8724670910924531152">"तुम्ही ॲक्सेसयोग्यता सेवा सुरू केली असल्‍यामुळे, तुमचे डिव्हाइस डेटा एंक्रिप्शन वर्धित करण्‍यासाठी तुमचे स्क्रीन लॉक वापरणार नाही."</string>
+    <string name="enable_service_pattern_reason" msgid="7415969807374459848">"<xliff:g id="SERVICE">%1$s</xliff:g> सुरू करण्यामुळे डेटा एंक्रिप्शनवर परिणाम होतो, तुम्हाला तुमच्या पॅटर्नची पुष्टी करण्याची आवश्यकता आहे."</string>
+    <string name="enable_service_pin_reason" msgid="2899057249007636608">"<xliff:g id="SERVICE">%1$s</xliff:g> सुरू करण्याने एंक्रिप्शन डेटा प्रभावित होतो, तुम्हाला तुमच्या पिन ची पुष्टी करण्याची आवश्यकता आहे."</string>
+    <string name="enable_service_password_reason" msgid="5210815233227388083">"<xliff:g id="SERVICE">%1$s</xliff:g> सुरू करण्यामुळे डेटा एंक्रिप्शनवर परिणाम होतो, तुम्हाला तुमच्या पासवर्डची पुष्टी करण्याची आवश्यकता आहे."</string>
     <string name="accessibility_service_warning" msgid="345702253188068806">"<xliff:g id="SERVICE">%1$s</xliff:g>या डिव्हाइसच्या पूर्ण नियंत्रणासाठी विनंती करत आहे. सेवा स्क्रीन रीड करू शकते आणि अ‍ॅक्सेसिबिलिटीच्या गरजा असलेल्या वापरकर्त्यांच्या वतीने कृती करू शकते. नियंत्रणाची ही पातळी बहुतांश अ‍ॅप्ससाठी योग्य नाही."</string>
     <string name="disable_service_title" msgid="6234243399949005825">"<xliff:g id="SERVICE">%1$s</xliff:g> थांबवायचे?"</string>
     <string name="disable_service_message" msgid="4250593674885651779">"ठीक आहेवर टॅप करण्यामुळे <xliff:g id="SERVICE">%1$s</xliff:g> थांबेल."</string>
@@ -2191,8 +2196,8 @@
     <string name="print_settings" msgid="7886184656544483072">"प्रिंट"</string>
     <string name="print_settings_summary_no_service" msgid="634173687975841526">"बंद"</string>
     <plurals name="print_settings_summary" formatted="false" msgid="7580293760281445137">
-      <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> प्रिंट सेवा चालू</item>
-      <item quantity="one">1 प्रिंट सेवा चालू</item>
+      <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> प्रिंट सेवा सुरू</item>
+      <item quantity="one">1 प्रिंट सेवा सुरू</item>
     </plurals>
     <plurals name="print_jobs_summary" formatted="false" msgid="6180308415569432845">
       <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> प्रिंट कार्ये</item>
@@ -2238,25 +2243,25 @@
     <string name="background_activity_disabled_dialog_text" msgid="4234598000779459640">"हे अ‍ॅप बॅटरी ऑप्टिमाइझ करण्यासाठी सेट केलेले नसल्याने, तुम्ही ते प्रतिबंधित करू शकत नाही.\n\nअ‍ॅप प्रतिबंधित करण्यासाठी, प्रथम बॅटरी ऑप्टिमायझेशन सुरू करा"</string>
     <string name="device_screen_usage" msgid="4470485475363132750">"पूर्ण चार्ज झाल्यानंतरचा स्क्रीन वापर"</string>
     <string name="power_usage_list_summary" msgid="4314438658308211057">"पूर्ण चार्ज केल्यापासूनचा बॅटरी वापर"</string>
-    <string name="screen_usage_summary" msgid="263396144684078341">"पूर्ण चार्जपासून स्क्रीन चालू असण्याच्या वेळाचे प्रमाण"</string>
+    <string name="screen_usage_summary" msgid="263396144684078341">"पूर्ण चार्जपासून स्क्रीन सुरू असण्याच्या वेळाचे प्रमाण"</string>
     <string name="device_usage_list_summary" msgid="8299017481332816368">"शेवटच्या पूर्ण चार्जपासून डिव्हाइस वापर"</string>
     <string name="battery_since_unplugged" msgid="6486555910264026856">"अनप्लग केल्यापासून बॅटरी वापर"</string>
     <string name="battery_since_reset" msgid="4747587791838336661">"रीसेट केल्यापासून बॅटरी वापर"</string>
     <string name="battery_stats_on_battery" msgid="2644055304085279716">"बॅटरीवरील <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="battery_stats_duration" msgid="4867858933068728005">"अनप्लग केल्यापासून <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="battery_stats_charging_label" msgid="3156586822576998231">"चार्ज होत आहे"</string>
-    <string name="battery_stats_screen_on_label" msgid="1223495366609581497">"स्क्रीन चालू"</string>
-    <string name="battery_stats_gps_on_label" msgid="3944533098574423359">"GPS चालू"</string>
-    <string name="battery_stats_camera_on_label" msgid="557892808497848886">"कॅमेरा चालू"</string>
-    <string name="battery_stats_flashlight_on_label" msgid="162279812156241905">"फ्लॅशलाइट चालू"</string>
+    <string name="battery_stats_screen_on_label" msgid="1223495366609581497">"स्क्रीन सुरू"</string>
+    <string name="battery_stats_gps_on_label" msgid="3944533098574423359">"GPS सुरू"</string>
+    <string name="battery_stats_camera_on_label" msgid="557892808497848886">"कॅमेरा सुरू"</string>
+    <string name="battery_stats_flashlight_on_label" msgid="162279812156241905">"फ्लॅशलाइट सुरू"</string>
     <string name="battery_stats_wifi_running_label" msgid="3223557320252465826">"वाय-फाय"</string>
     <string name="battery_stats_wake_lock_label" msgid="670884103452713535">"सक्रिय"</string>
     <string name="battery_stats_phone_signal_label" msgid="2502589944816260503">"मोबाईल नेटवर्क सिग्नल"</string>
     <!-- no translation found for battery_stats_last_duration (8190573267292309839) -->
     <skip />
     <string name="awake" msgid="8956720170442161285">"डिव्हाइस ॲक्टिव्हेट होण्याची वेळ"</string>
-    <string name="wifi_on_time" msgid="2487820618265936068">"वाय-फाय चालू केल्याची वेळ"</string>
-    <string name="bluetooth_on_time" msgid="6400569492287292639">"वाय-फाय चालू केल्याची वेळ"</string>
+    <string name="wifi_on_time" msgid="2487820618265936068">"वाय-फाय सुरू केल्याची वेळ"</string>
+    <string name="bluetooth_on_time" msgid="6400569492287292639">"वाय-फाय सुरू केल्याची वेळ"</string>
     <string name="advanced_battery_title" msgid="5026866913848464170">"बॅटरी वापर"</string>
     <string name="history_details_title" msgid="8608193822257799936">"इतिहास तपशील"</string>
     <string name="battery_details_title" msgid="5358230551490703067">"बॅटरी वापर"</string>
@@ -2272,10 +2277,10 @@
     <string name="battery_tip_smart_battery_title" product="default" msgid="5517122075918038665">"तुमच्या फोनचे बॅटरी लाइफ सुधारा"</string>
     <string name="battery_tip_smart_battery_title" product="tablet" msgid="203494973250969040">"तुमच्या टॅबलेटचे बॅटरी लाइफ सुधारा"</string>
     <string name="battery_tip_smart_battery_title" product="device" msgid="7419448992583346364">"तुमच्या डिव्हाइसचे बॅटरी लाइफ सुधारा"</string>
-    <string name="battery_tip_smart_battery_summary" msgid="5344821856478265778">"बॅटरी व्यवस्थापक चालू करा"</string>
-    <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"बॅटरी सेव्हर चालू करा"</string>
+    <string name="battery_tip_smart_battery_summary" msgid="5344821856478265778">"बॅटरी व्यवस्थापक सुरू करा"</string>
+    <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"बॅटरी सेव्हर सुरू करा"</string>
     <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"बॅटरी नेहमीपेक्षा लवकर संपू शकते"</string>
-    <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"बॅटरी सेव्हर चालू आहे"</string>
+    <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"बॅटरी सेव्हर सुरू आहे"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"काही वैशिष्ट्ये मर्यादित असू शकतात"</string>
     <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"फोन नेहमीपेक्षा जास्त वापरला गेला"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"टॅबलेट नेहमीपेक्षा जास्त वापरले गेला"</string>
@@ -2298,8 +2303,8 @@
       <item quantity="one">%1$s चा बॅकग्राउंड बॅटरी वापर जास्त आहे</item>
     </plurals>
     <plurals name="battery_tip_restrict_handled_summary" formatted="false" msgid="469696766640020557">
-      <item quantity="other">ही अ‍ॅप्स बॅकग्राउंडमध्ये चालू शकत नाहीत</item>
-      <item quantity="one">हे अ‍ॅप बॅकग्राउंडमध्ये चालू शकत नाही</item>
+      <item quantity="other">ही अ‍ॅप्स बॅकग्राउंडमध्ये सुरू शकत नाहीत</item>
+      <item quantity="one">हे अ‍ॅप बॅकग्राउंडमध्ये सुरू शकत नाही</item>
     </plurals>
     <plurals name="battery_tip_restrict_app_dialog_title" formatted="false" msgid="3042021435866172168">
       <item quantity="other">%1$d अ‍ॅप्स प्रतिबंधित करायची?</item>
@@ -2383,7 +2388,7 @@
     <string name="usage_type_video" msgid="8161701367674306793">"व्हिडिओ"</string>
     <string name="usage_type_camera" msgid="2276450385733155264">"कॅमेरा"</string>
     <string name="usage_type_flashlight" msgid="954750302897154167">"फ्लॅशलाइट"</string>
-    <string name="usage_type_on_time" msgid="4622180623970638221">"वेळ चालू"</string>
+    <string name="usage_type_on_time" msgid="4622180623970638221">"वेळ सुरू"</string>
     <string name="usage_type_no_coverage" msgid="6032663899998431817">"सिग्नलशिवायची वेळ"</string>
     <string name="usage_type_total_battery_capacity" msgid="1954889791720119945">"एकूण बॅटरी क्षमता"</string>
     <string name="usage_type_computed_power" msgid="2594890316149868151">"गणना केलेला पॉवर वापर"</string>
@@ -2427,7 +2432,7 @@
     <string name="battery_full_charge_last" msgid="4614554109170251301">"पूर्ण चार्ज सुमारे इतका वेळ टिकते"</string>
     <string name="battery_footer_summary" msgid="4828444679643906943">"बॅटरी वापर डेटा अंदाजे आहे आणि वापराच्या आधारे बदलू शकतो"</string>
     <string name="battery_detail_foreground" msgid="6616408559186553085">"सक्रिय वापरात असताना"</string>
-    <string name="battery_detail_background" msgid="7938146832943604280">"पार्श्वभूमीत असताना"</string>
+    <string name="battery_detail_background" msgid="7938146832943604280">"बॅकग्राउंडमध्ये असताना"</string>
     <string name="battery_detail_power_usage" msgid="3606930232257489212">"बॅटरी वापर"</string>
     <string name="battery_detail_info_title" msgid="4617514228447481336">"पूर्ण चार्जपासून"</string>
     <string name="battery_detail_manage_title" msgid="745194290572617507">"बॅटरी वापर व्यवस्थापित करा"</string>
@@ -2443,7 +2448,7 @@
     <string name="process_mediaserver_label" msgid="8591722404282619153">"मीडियासर्व्हर"</string>
     <string name="process_dex2oat_label" msgid="8249082119748556085">"अ‍ॅप ऑप्टिमायझेशन"</string>
     <string name="battery_saver" msgid="3989710213758938398">"बॅटरी सेव्‍हर"</string>
-    <string name="battery_saver_auto_title" msgid="4158659069641849952">"आपोआप चालू करा"</string>
+    <string name="battery_saver_auto_title" msgid="4158659069641849952">"आपोआप सुरू करा"</string>
     <string name="battery_saver_auto_no_schedule" msgid="739814529432092706">"कोणतेही शेड्युल नाही"</string>
     <string name="battery_saver_auto_routine" msgid="886514412067906980">"तुमच्या दिनक्रमावर आधारित"</string>
     <string name="battery_saver_auto_percentage" msgid="5791982309331921556">"टक्केवारीवर आधारित"</string>
@@ -2458,7 +2463,7 @@
     <skip />
     <string name="battery_saver_seekbar_title_placeholder" msgid="2321082163892561703">"सुरू करा"</string>
     <string name="battery_saver_master_switch_title" msgid="8241862826825517212">"बॅटरी सेव्हर वापरा"</string>
-    <string name="battery_saver_turn_on_automatically_title" msgid="7316920304024245838">"स्वयंचलितपणे चालू करा"</string>
+    <string name="battery_saver_turn_on_automatically_title" msgid="7316920304024245838">"स्वयंचलितपणे सुरू करा"</string>
     <string name="battery_saver_turn_on_automatically_never" msgid="2623381258359775227">"कधीही नाही"</string>
     <string name="battery_saver_turn_on_automatically_pct" msgid="434270432432390307">"<xliff:g id="PERCENT">%1$s</xliff:g>बॅटरीवर"</string>
     <string name="battery_percentage" msgid="7782252476471033843">"बॅटरी टक्‍केवारी"</string>
@@ -2470,12 +2475,12 @@
     <string name="process_stats_total_duration_percentage" msgid="737215062610178960">"<xliff:g id="TIMEDURATION">%2$s</xliff:g> पासून <xliff:g id="PERCENT">%1$s</xliff:g> रॅम वापरली"</string>
     <string name="process_stats_type_background" msgid="7867552451658035199">"पार्श्वभूमी"</string>
     <string name="process_stats_type_foreground" msgid="9185538008409818577">"पुरोभाग"</string>
-    <string name="process_stats_type_cached" msgid="6774816751826613732">"कॅश   केलेले"</string>
+    <string name="process_stats_type_cached" msgid="6774816751826613732">"कॅशे    केलेले"</string>
     <string name="process_stats_os_label" msgid="2866711070924260440">"Android OS"</string>
     <string name="process_stats_os_native" msgid="8971193568864959041">"मूळ"</string>
     <string name="process_stats_os_kernel" msgid="496627624157605578">"कर्नेल"</string>
     <string name="process_stats_os_zram" msgid="5654662484619165424">"Z-Ram"</string>
-    <string name="process_stats_os_cache" msgid="5662578472981137018">"कॅश"</string>
+    <string name="process_stats_os_cache" msgid="5662578472981137018">"कॅशे"</string>
     <string name="process_stats_ram_use" msgid="7064754065505886755">"RAM वापर"</string>
     <string name="process_stats_bg_ram_use" msgid="1489397892092393257">"RAM वापर (पार्श्वभूमी)"</string>
     <string name="process_stats_run_time" msgid="4961296157434073261">"चालण्याचा कालावधी"</string>
@@ -2494,7 +2499,7 @@
     <string name="menu_proc_stats_type" msgid="2680179749566186247">"आकडेवारी प्रकार"</string>
     <string name="menu_proc_stats_type_background" msgid="1898036847606845052">"पार्श्वभूमी"</string>
     <string name="menu_proc_stats_type_foreground" msgid="8244384283966204023">"पुरोभाग"</string>
-    <string name="menu_proc_stats_type_cached" msgid="8238824117399683217">"कॅश केलेले"</string>
+    <string name="menu_proc_stats_type_cached" msgid="8238824117399683217">"कॅशे  केलेले"</string>
     <string name="voice_input_output_settings" msgid="2180337183089517667">"आवाज इनपुट आणि आउटपुट"</string>
     <string name="voice_input_output_settings_title" msgid="7080213653518526025">"आवाज इनपुट आणि आउटपुट सेटिंग्ज"</string>
     <string name="voice_search_settings_title" msgid="4999026024622014272">"व्हॉइस शोध"</string>
@@ -2504,7 +2509,7 @@
     <string name="voice_service_preference_section_title" msgid="2984112696100778038">"व्‍हॉइस इनपुट सेवा"</string>
     <string name="voice_interactor_preference_summary" msgid="7321365727286121067">"पूर्ण हॉटवर्ड आणि परस्परसंवाद"</string>
     <string name="voice_recognizer_preference_summary" msgid="3681161319745912594">"मजकूर पाठविण्यासाठी सोपे उच्चारण"</string>
-    <string name="voice_interaction_security_warning" msgid="4986261746316889768">"आपल्या वतीने व्हॉइस परीक्षण नेहमी-चालू कार्यप्रदर्शन करण्यासाठी आणि व्हॉइस सक्षम ॲप्लिकेशन नियंत्रित करण्यासाठी व्हॉइस इनपुट सेवा सक्षम असेल. हे <xliff:g id="VOICE_INPUT_SERVICE_APP_NAME">%s</xliff:g> ॲप्लिकेशनावरून येते. या सेवेचा वापर सक्षम करायचा?"</string>
+    <string name="voice_interaction_security_warning" msgid="4986261746316889768">"आपल्या वतीने व्हॉइस परीक्षण नेहमी-सुरू कार्यप्रदर्शन करण्यासाठी आणि व्हॉइस सक्षम ॲप्लिकेशन नियंत्रित करण्यासाठी व्हॉइस इनपुट सेवा सक्षम असेल. हे <xliff:g id="VOICE_INPUT_SERVICE_APP_NAME">%s</xliff:g> ॲप्लिकेशनावरून येते. या सेवेचा वापर सक्षम करायचा?"</string>
     <string name="tts_engine_preference_title" msgid="1183116842356275061">"प्राधान्य इंजिन"</string>
     <string name="tts_engine_settings_title" msgid="4079757915136562358">"इंजिन सेटिंग्ज"</string>
     <string name="tts_sliders_title" msgid="1927481069989092278">"भाषण गती आणि पिच"</string>
@@ -2558,8 +2563,8 @@
     <string name="backup_configure_account_default_summary" msgid="5718298066335006412">"कोणतेही खाते सध्या बॅक अप घेतलेला डेटा स्टोअर करत नाहीये"</string>
     <string name="backup_erase_dialog_title" msgid="8178424339104463014"></string>
     <string name="backup_erase_dialog_message" msgid="8767843355330070902">"Google सर्व्हरवरील आपल्या वाय-फाय पासवर्ड, बुकमार्क, इतर सेटिंग्ज आणि अ‍ॅप डेटाचा बॅक अप घेणे थांबवायचे तसेच सर्व प्रती मिटवायच्या?"</string>
-    <string name="fullbackup_erase_dialog_message" msgid="2588536036471144070">"डिव्हाइस डेटाचा (जसे की वाय-फाय पासवर्ड आणि कॉल इतिहास) आणि (अ‍ॅप्सद्वारे स्टोअर केलेल्या सेटिंग्ज आणि फायली यासारख्या) अ‍ॅप डेटाचा बॅकअप घेणे थांबवायचे, तसेच दूरस्थ सर्व्हर वरील सर्व प्रती मिटवायच्या?"</string>
-    <string name="fullbackup_data_summary" msgid="406274198094268556">"आपोआप डिव्हाइस डेटाचा (जसे की वाय-फाय पासवर्ड आणि कॉल इतिहास) आणि अ‍ॅप डेटाचा (जसे की अ‍ॅप्‍स द्वारे स्टोअर केलेल्या सेटिंग्ज आणि फायली) दूरस्‍थपणे बॅकअप घ्‍या.\n\nतुम्ही स्वयंचलित बॅकअप चालू करता तेव्‍हा, डिव्हाइस आणि अ‍ॅप डेटा ठराविक कालावधीने दूरस्‍थपणे सेव्ह केला जातो. अ‍ॅप डेटा हा संपर्क, मेसेज आणि फोटो यासारख्‍या संभाव्य संवेदनशील डेटासह अ‍ॅपने सेव्ह केलेला (डेव्हलपरच्या सेटिंग्जवर आधारित) कोणताही डेटा असू शकतो."</string>
+    <string name="fullbackup_erase_dialog_message" msgid="2588536036471144070">"डिव्हाइस डेटाचा (जसे की वाय-फाय पासवर्ड आणि कॉल इतिहास) आणि (अ‍ॅप्सद्वारे स्टोअर केलेल्या सेटिंग्ज आणि फाइल यासारख्या) अ‍ॅप डेटाचा बॅकअप घेणे थांबवायचे, तसेच दूरस्थ सर्व्हर वरील सर्व प्रती मिटवायच्या?"</string>
+    <string name="fullbackup_data_summary" msgid="406274198094268556">"आपोआप डिव्हाइस डेटाचा (जसे की वाय-फाय पासवर्ड आणि कॉल इतिहास) आणि अ‍ॅप डेटाचा (जसे की अ‍ॅप्‍स द्वारे स्टोअर केलेल्या सेटिंग्ज आणि फाइल) दूरस्‍थपणे बॅकअप घ्‍या.\n\nतुम्ही स्वयंचलित बॅकअप सुरू करता तेव्‍हा, डिव्हाइस आणि अ‍ॅप डेटा ठराविक कालावधीने दूरस्‍थपणे सेव्ह केला जातो. अ‍ॅप डेटा हा संपर्क, मेसेज आणि फोटो यासारख्‍या संभाव्य संवेदनशील डेटासह अ‍ॅपने सेव्ह केलेला (डेव्हलपरच्या सेटिंग्जवर आधारित) कोणताही डेटा असू शकतो."</string>
     <string name="device_admin_settings_title" msgid="2074319456047334589">"डिव्हाइस प्रशासक सेटिंग्ज"</string>
     <string name="active_device_admin_msg" msgid="6929247869516924549">"डिव्हाइस प्रशासक अ‍ॅप"</string>
     <string name="remove_device_admin" msgid="4413438593788336400">"हे डिव्हाइस अ‍ॅडमिन अ‍ॅप बंद करा"</string>
@@ -2603,7 +2608,7 @@
     <string name="background_data_dialog_title" msgid="8306650658158895976">"पार्श्वभूमीवरील डेटा अक्षम करायचा?"</string>
     <string name="background_data_dialog_message" msgid="8126774244911656527">"पार्श्वभूमीवरील डेटा बंद केल्याने बॅटरी लाइफ वाढते आणि डेटा वापर कमी होतो. तरीही, काही अ‍ॅप्स पार्श्वभूमीवर डेटा कनेक्शन वापरतात."</string>
     <string name="sync_automatically" msgid="5746117156896468099">"अ‍ॅप डेटा स्वयं-संकालित करा"</string>
-    <string name="sync_enabled" msgid="535172627223336983">"सिंक चालू आहे"</string>
+    <string name="sync_enabled" msgid="535172627223336983">"सिंक सुरू आहे"</string>
     <string name="sync_disabled" msgid="713721807204805062">"सिंक बंद आहे"</string>
     <string name="sync_error" msgid="988155155932442765">"सिंक एरर"</string>
     <string name="last_synced" msgid="4511434057768999129">"अंतिम सिंक केले: <xliff:g id="LAST_SYNC_TIME">%1$s</xliff:g>"</string>
@@ -2630,7 +2635,7 @@
     <string name="really_remove_account_message" product="device" msgid="3751798556257519916">"हे खाते काढल्याने त्याचे सर्व मेसेज, संपर्क आणि डिव्हाइसवरील इतर डेटा हटवला जाईल!"</string>
     <string name="remove_account_failed" msgid="491458185327106966">"या बदलाला आपल्या प्रशासकाद्वारे अनुमती नाही"</string>
     <string name="cant_sync_dialog_title" msgid="5483419398223189881">"व्यक्तिचलितपणे सिंक करू शकत नाही"</string>
-    <string name="cant_sync_dialog_message" msgid="3467126947262857534">"या आयटमसाठी सध्या सिंक अक्षम केले आहे. हे सेटिंग बदलण्यासाठी, पार्श्वभूमीवरील डेटा आणि आपोआप होणारे सिंक तात्पुरते चालू करा."</string>
+    <string name="cant_sync_dialog_message" msgid="3467126947262857534">"या आयटमसाठी सध्या सिंक अक्षम केले आहे. हे सेटिंग बदलण्यासाठी, पार्श्वभूमीवरील डेटा आणि आपोआप होणारे सिंक तात्पुरते सुरू करा."</string>
     <string name="enter_password" msgid="2963496904625715235">"Android प्रारंभ करण्‍यासाठी, तुमचा पासवर्ड प्रविष्‍ट करा"</string>
     <string name="enter_pin" msgid="7140938268709546890">"Android प्रारंभ करण्‍यासाठी, तुमचा पिन प्रविष्‍ट करा"</string>
     <string name="enter_pattern" msgid="1653841963422825336">"Android प्रारंभ करण्‍यासाठी, आपल्या नमुन्याची रेखाटणी करा"</string>
@@ -2640,7 +2645,7 @@
     <string name="checking_decryption" msgid="5927759912073053101">"तपासत आहे..."</string>
     <string name="starting_android" msgid="4774187626261253089">"Android प्रारंभ करत आहोत..."</string>
     <string name="delete" msgid="2325292565700865366">"हटवा"</string>
-    <string name="misc_files" msgid="1012397035001764693">"संकीर्ण फायली"</string>
+    <string name="misc_files" msgid="1012397035001764693">"संकीर्ण फाइल"</string>
     <string name="misc_files_selected_count" msgid="1434146080729502726">"<xliff:g id="TOTAL">%2$d</xliff:g> पैकी <xliff:g id="NUMBER">%1$d</xliff:g> निवडले"</string>
     <string name="misc_files_selected_count_bytes" msgid="3752262902203465861">"<xliff:g id="TOTAL">%2$s</xliff:g> पैकी <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
     <string name="select_all" msgid="452240217913675728">"सर्व निवडा"</string>
@@ -2728,7 +2733,7 @@
     <string name="data_usage_metered_body" msgid="1342905101297753439">"पार्श्वभूमीवरील डेटा प्रतिबंधित असताना मीटर केलेली नेटवर्क मोबाइल नेटवर्कप्रमाणे वापरली जातात. मोठ्‍या डाउनलोडसाठी ही नेटवर्क वापरण्‍यापूर्वी अ‍ॅप्‍सकडून चेतावणी मिळू शकते."</string>
     <string name="data_usage_metered_mobile" msgid="3675591449158207593">"मोबाईल नेटवर्क"</string>
     <string name="data_usage_metered_wifi" msgid="2955256408132426720">"मीटर केलेली वाय-फाय नेटवर्क"</string>
-    <string name="data_usage_metered_wifi_disabled" msgid="5771083253782103415">"मीटर केलेली नेटवर्क निवडण्‍यासाठी, वाय-फाय चालू करा."</string>
+    <string name="data_usage_metered_wifi_disabled" msgid="5771083253782103415">"मीटर केलेली नेटवर्क निवडण्‍यासाठी, वाय-फाय सुरू करा."</string>
     <string name="data_usage_metered_auto" msgid="7924116401382629319">"स्वयंचलित"</string>
     <string name="data_usage_metered_yes" msgid="7333744880035386073">"मर्यादित डेटा वापराचे नेटवर्क"</string>
     <string name="data_usage_metered_no" msgid="1961524615778610008">"मीटरने मोजले नाही"</string>
@@ -2756,10 +2761,10 @@
     <string name="vpn_no_ca_cert" msgid="486605757354800838">"(सर्व्हर सत्यापित करू नका)"</string>
     <string name="vpn_no_server_cert" msgid="679622228649855629">"(सर्व्हरवरुन प्राप्त झालेले)"</string>
     <string name="vpn_always_on_invalid_reason_type" msgid="165810330614905489">"हा VPN प्रकार सर्व वेळी कनेक्ट केलेला राहू शकत नाही"</string>
-    <string name="vpn_always_on_invalid_reason_server" msgid="3864424127328210700">"नेहमी-चालू VPN केवळ अंकीय सर्व्हर पत्त्यांना समर्थित करतात"</string>
-    <string name="vpn_always_on_invalid_reason_no_dns" msgid="3814114757059738225">"नेहमी-चालू VPN साठी DNS सर्व्हर नमूद करणे आवश्यक आहे"</string>
-    <string name="vpn_always_on_invalid_reason_dns" msgid="501388894176868973">"नेहमी-चालू VPN साठी DNS सर्व्हर पत्ते अंकीय असणे आवश्यक आहे"</string>
-    <string name="vpn_always_on_invalid_reason_other" msgid="8504512156730364447">"एंटर केलेली माहिती नेहमी-चालू VPN ला समर्थित करत नाही"</string>
+    <string name="vpn_always_on_invalid_reason_server" msgid="3864424127328210700">"नेहमी-सुरू VPN केवळ अंकीय सर्व्हर पत्त्यांना समर्थित करतात"</string>
+    <string name="vpn_always_on_invalid_reason_no_dns" msgid="3814114757059738225">"नेहमी-सुरू VPN साठी DNS सर्व्हर नमूद करणे आवश्यक आहे"</string>
+    <string name="vpn_always_on_invalid_reason_dns" msgid="501388894176868973">"नेहमी-सुरू VPN साठी DNS सर्व्हर पत्ते अंकीय असणे आवश्यक आहे"</string>
+    <string name="vpn_always_on_invalid_reason_other" msgid="8504512156730364447">"एंटर केलेली माहिती नेहमी-सुरू VPN ला समर्थित करत नाही"</string>
     <string name="vpn_cancel" msgid="440645172381062337">"रद्द करा"</string>
     <string name="vpn_done" msgid="6314426362224527349">"डिसमिस करा"</string>
     <string name="vpn_save" msgid="1332625259182278316">"सेव्ह करा"</string>
@@ -2773,14 +2778,14 @@
     <string name="vpn_version" msgid="2006792987077940456">"आवृत्ती <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="8457511440635534478">"VPN विसरा"</string>
     <string name="vpn_replace_vpn_title" msgid="8517436922021598103">"विद्यमान VPN पुनर्स्थित करायचे?"</string>
-    <string name="vpn_set_vpn_title" msgid="6483554732067951052">"नेहमी-चालू VPN सेट करायचे?"</string>
-    <string name="vpn_first_always_on_vpn_message" msgid="7050017738816963855">"हे सेटिंग चालू असताना, VPN यशस्वीरीत्या कनेक्ट करेपर्यंत तुमच्याकडे इंटरनेट कनेक्शन असणार नाही"</string>
+    <string name="vpn_set_vpn_title" msgid="6483554732067951052">"नेहमी-सुरू VPN सेट करायचे?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="7050017738816963855">"हे सेटिंग सुरू असताना, VPN यशस्वीरीत्या कनेक्ट करेपर्यंत तुमच्याकडे इंटरनेट कनेक्शन असणार नाही"</string>
     <string name="vpn_replace_always_on_vpn_enable_message" msgid="4149931501300203205">"तुमचे सद्य VPN बदलले जाईल आणि VPN यशस्वीरित्या कनेक्ट करेपर्यंत तुमच्याकडे इंटरनेट कनेक्शन असणार नाही"</string>
-    <string name="vpn_replace_always_on_vpn_disable_message" msgid="4924947523200883088">"तुम्ही आधीपासून नेहमी-चालू VPN शी कनेक्ट केले आहे. तुम्ही एका भिन्न VPN शी कनेक्ट केल्यास, तुमचे विद्यमान VPN पुनर्स्थित केले जाईल आणि नेहमी-चालू मोड बंद होईल."</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="4924947523200883088">"तुम्ही आधीपासून नेहमी-सुरू VPN शी कनेक्ट केले आहे. तुम्ही एका भिन्न VPN शी कनेक्ट केल्यास, तुमचे विद्यमान VPN पुनर्स्थित केले जाईल आणि नेहमी-सुरू मोड बंद होईल."</string>
     <string name="vpn_replace_vpn_message" msgid="8009433728523145393">"तुम्ही आधीपासून एका VPN शी कनेक्ट केले आहे. तुम्ही भिन्न VPN शी कनेक्ट केल्यास, तुमचे विद्यमान VPN बदलले जाईल."</string>
-    <string name="vpn_turn_on" msgid="2334736319093953055">"चालू करा"</string>
+    <string name="vpn_turn_on" msgid="2334736319093953055">"सुरू करा"</string>
     <string name="vpn_cant_connect_title" msgid="5803347131129293771">"<xliff:g id="VPN_NAME">%1$s</xliff:g> कनेक्ट करू शकत नाही"</string>
-    <string name="vpn_cant_connect_message" msgid="7729125036551401236">"हे अ‍ॅप नेहमी-चालू VPN ला समर्थित करत नाही"</string>
+    <string name="vpn_cant_connect_message" msgid="7729125036551401236">"हे अ‍ॅप नेहमी-सुरू VPN ला समर्थित करत नाही"</string>
     <string name="vpn_title" msgid="7801918186865029203">"VPN"</string>
     <string name="vpn_create" msgid="2477570636472897359">"VPN प्रोफाइल जोडा"</string>
     <string name="vpn_menu_edit" msgid="8061437799373333593">"प्रोफाईल संपादित करा"</string>
@@ -2789,12 +2794,12 @@
     <string name="vpn_no_vpns_added" msgid="6616183541896197147">"कोणतेही VPN जोडलेले नाहीत"</string>
     <string name="vpn_always_on_summary" msgid="3639994551631437397">"VPN शी नेहमी कनेक्ट केलेले रहा"</string>
     <string name="vpn_always_on_summary_not_supported" msgid="9077720997795965133">"या ॲपद्वारे समर्थित नाही"</string>
-    <string name="vpn_always_on_summary_active" msgid="8962619701962239088">"नेहमी-चालू सक्रिय"</string>
+    <string name="vpn_always_on_summary_active" msgid="8962619701962239088">"नेहमी-सुरू सक्रिय"</string>
     <string name="vpn_require_connection" msgid="5413746839457797350">"VPN शिवायची कनेक्शन ब्लॉक करा"</string>
     <string name="vpn_require_connection_title" msgid="8361434328767853717">"VPN कनेक्शन आवश्यक आहे?"</string>
     <string name="vpn_lockdown_summary" msgid="6770030025737770861">"नेहमी कनेक्ट केलेले राहण्यासाठी एक VPN प्रोफाईल निवडा. केवळ या VPN शी कनेक्ट केलेले असताना नेटवर्क रहदारीला अनुमती दिली जाईल."</string>
     <string name="vpn_lockdown_none" msgid="3789288793603394679">"काहीही नाही"</string>
-    <string name="vpn_lockdown_config_error" msgid="8761770968704589885">"नेहमी चालू असलेल्या VPN ला सर्व्हर आणि DNS दोन्हीसाठी एका IP पत्त्याची आवश्यकता आहे."</string>
+    <string name="vpn_lockdown_config_error" msgid="8761770968704589885">"नेहमी सुरू असलेल्या VPN ला सर्व्हर आणि DNS दोन्हीसाठी एका IP पत्त्याची आवश्यकता आहे."</string>
     <string name="vpn_no_network" msgid="8313250136194588023">"कोणतेही नेटवर्क कनेक्शन नाही. कृपया नंतर पुन्हा प्रयत्न करा."</string>
     <string name="vpn_disconnected" msgid="4597953053220332539">"VPN पासून डिस्कनेक्ट झाले"</string>
     <string name="vpn_disconnected_summary" msgid="3784118965271376808">"काहीही नाही"</string>
@@ -2846,7 +2851,7 @@
     <string name="user_settings_title" msgid="7917598650933179545">"एकाहून अधिक वापरकर्ते"</string>
     <string name="user_settings_footer_text" product="device" msgid="4573858247439190545">"नवीन वापरकर्त्यांना जोडून तुमचे डिव्हाइस शेअर करा. प्रत्येक वापरकर्त्याला कस्टम होम स्क्रीन, खाती, अ‍ॅप्स, सेटिंग्ज आणि बर्‍याच गोष्टीसाठी तुमच्या डिव्हाइसवर वैयक्तिक जागा आहे."</string>
     <string name="user_settings_footer_text" product="tablet" msgid="780018221428132918">"नवीन वापरकर्त्यांना जोडून तुमचा टॅबलेट शेअर करा. प्रत्येक वापरकर्त्याला कस्टम होम स्क्रीन, खाती अ‍ॅप्स, सेटिंग्ज आणि बर्‍याच गोष्टीसाठी तुमच्या टॅबलेटवर वैयक्तिक जागा आहे."</string>
-    <string name="user_settings_footer_text" product="default" msgid="1470859614968237491">"नवीन वापरकर्त्यांना जोडून तुमचा फोन शेअर करा. प्रत्येक वापरकर्त्याला कस्टम होम स्क्रीन, खाती अ‍ॅप्स, सेटिंग्ज आणि बर्‍याच गोष्टीसाठी तुमच्या फोनवर वैयक्तिक जागा आहे."</string>
+    <string name="user_settings_footer_text" product="default" msgid="1470859614968237491">"नवीन वापरकर्त्यांना जोडून तुमचा फोन शेअर करा. प्रत्येक वापरकर्त्याला कस्टम होम स्क्रीन, खाती, अ‍ॅप्स, सेटिंग्ज आणि बर्‍याच गोष्टीसाठी तुमच्या फोनवर वैयक्तिक जागा आहे."</string>
     <string name="user_list_title" msgid="6670258645246192324">"वापरकर्ते आणि प्रोफाईल्स"</string>
     <string name="user_add_user_or_profile_menu" msgid="4220679989900149336">"वापरकर्ता किंवा प्रोफाइल जोडा"</string>
     <string name="user_add_user_menu" msgid="9006572936456324794">"वापरकर्ता जोडा"</string>
@@ -2866,10 +2871,10 @@
     <string name="user_add_user_item_title" msgid="6835385073795492410">"वापरकर्ता"</string>
     <string name="user_add_profile_item_title" msgid="4932743891449790664">"प्रतिबंधित प्रोफाईल"</string>
     <string name="user_add_user_title" msgid="2320897397066676472">"नवीन वापरकर्ता जोडायचा?"</string>
-    <string name="user_add_user_message_long" msgid="686637203224195465">"अतिरिक्त वापरकर्ते तयार करून तुम्ही इतर लोकांसोबत हे डिव्हाइस शेअर करू शकता. प्रत्येक वापरकर्त्यास त्यांची स्वतःची स्पेस असते, जी ते अ‍ॅप्स, वॉलपेपर आणि यासारख्या गोष्टींनी कस्टमाइझ करू शकतात. वापरकर्ते प्रत्येकाला प्रभावित करणाऱ्या वाय-फाय सारख्या डिव्हाइस सेटिंग्ज अ‍ॅडजस्ट देखील करू शकतात.\n\nतुम्ही एक नवीन वापरकर्ता जोडता, तेव्हा त्या व्यक्तीला त्याची स्पेस सेट अप करण्याची आवश्यकता असते.\n\nकोणताही वापरकर्ता इतर सर्व वापरकर्त्यांसाठी अ‍ॅप अपडेट करू शकतो. ॲक्सेसिबिलिटी सेटिंग्ज आणि सेवा नवीन वापरकर्त्याला कदाचित ट्रान्सफर होणार नाहीत."</string>
+    <string name="user_add_user_message_long" msgid="686637203224195465">"अतिरिक्त वापरकर्ते तयार करून तुम्ही इतर लोकांसोबत हे डिव्हाइस शेअर करू शकता. प्रत्येक वापरकर्त्यास त्यांची स्वतःची स्पेस असते, जी ते अ‍ॅप्स, वॉलपेपर आणि यासारख्या गोष्टींनी कस्टमाइझ करू शकतात. वापरकर्ते प्रत्येकाला प्रभावित करणारी वाय-फाय सारखी डिव्हाइस सेटिंग्ज अ‍ॅडजस्ट देखील करू शकतात.\n\nतुम्ही एक नवीन वापरकर्ता जोडता, तेव्हा त्या व्यक्तीला त्याची स्पेस सेट अप करण्याची आवश्यकता असते.\n\nकोणताही वापरकर्ता इतर सर्व वापरकर्त्यांसाठी अ‍ॅप अपडेट करू शकतो. अ‍ॅक्सेसिबिलिटी सेटिंग्ज आणि सेवा नवीन वापरकर्त्याला कदाचित ट्रान्सफर होणार नाहीत."</string>
     <string name="user_add_user_message_short" msgid="1802594476285458254">"तुम्ही एक नवीन वापरकर्ता जोडता तेव्हा, त्या व्यक्तीस त्यांचे स्थान सेट करण्याची आवश्यकता असते.\n\nकोणताही वापरकर्ता इतर सर्व वापरकर्त्यांसाठी अ‍ॅप्स अपडेट करू शकतो."</string>
     <string name="user_setup_dialog_title" msgid="6748950002206392396">"आता वापरकर्ता सेट करायचा?"</string>
-    <string name="user_setup_dialog_message" msgid="2988559933258353919">"डिव्हाइस घेण्यासाठी आणि त्यांचे स्थान सेट करण्यासाठी व्यक्ती उपलब्ध असल्याची खात्री करा"</string>
+    <string name="user_setup_dialog_message" msgid="2988559933258353919">"तो वापरकर्ता डिव्हाइसजवळ आहे आणि त्याचे स्थान सेट करण्यासाठी उपलब्ध आहे याची खात्री करा"</string>
     <string name="user_setup_profile_dialog_message" msgid="7611900802824048526">"आता प्रोफाईल सेट करायचा?"</string>
     <string name="user_setup_button_setup_now" msgid="4941459406266856176">"आता सेट करा"</string>
     <string name="user_setup_button_setup_later" msgid="6596031428556518752">"आत्ता नाही"</string>
@@ -2888,7 +2893,7 @@
     <string name="user_confirm_remove_self_message" product="tablet" msgid="2889456786320157545">"तुम्ही या टॅब्लेटवरील तुमचे स्थान आणि डेटा गमवाल. तुम्ही ही क्रिया पूर्ववत करु शकत नाही."</string>
     <string name="user_confirm_remove_self_message" product="default" msgid="8441729423565705183">"तुम्ही या फोनवरील तुमचे स्थान आणि डेटा गमवाल. तुम्ही ही क्रिया पूर्ववत करु शकत नाही."</string>
     <string name="user_confirm_remove_message" msgid="5202150470271756013">"सर्व अ‍ॅप्स आणि डेटा हटवला जाईल."</string>
-    <string name="work_profile_confirm_remove_message" msgid="1220672284385083128">"तुम्ही सुरु ठेवल्यास या प्रोफाईलमधील सर्व अ‍ॅप्स आणि डेटा हटवला जाईल."</string>
+    <string name="work_profile_confirm_remove_message" msgid="1220672284385083128">"तुम्ही सुरू ठेवल्यास या प्रोफाईलमधील सर्व अ‍ॅप्स आणि डेटा हटवला जाईल."</string>
     <string name="user_profile_confirm_remove_message" msgid="8376289888144561545">"सर्व अ‍ॅप्स आणि डेटा हटवला जाईल."</string>
     <string name="user_adding_new_user" msgid="381717945749193417">"नवीन वापरकर्त्यास जोडत आहे…"</string>
     <string name="user_delete_user_description" msgid="3627684990761268859">"वापरकर्ता हटवा"</string>
@@ -2899,7 +2904,7 @@
     <string name="user_exit_guest_confirm_message" msgid="6955182181145748919">"या सत्रातील सर्व अ‍ॅप्स आणि डेटा हटवला जाईल."</string>
     <string name="user_exit_guest_dialog_remove" msgid="1878866060881115716">"काढा"</string>
     <string name="user_enable_calling" msgid="864760054792249503">"फोन कॉल सुरू करा"</string>
-    <string name="user_enable_calling_sms" msgid="3450252891736718793">"फोन कॉल आणि SMS चालू करा"</string>
+    <string name="user_enable_calling_sms" msgid="3450252891736718793">"फोन कॉल आणि SMS सुरू करा"</string>
     <string name="user_remove_user" msgid="3687544420125911166">"वापरकर्ता हटवा"</string>
     <string name="user_enable_calling_confirm_title" msgid="1141612415529158542">"फोन कॉल सुरू करायचे?"</string>
     <string name="user_enable_calling_confirm_message" msgid="2490126715153125970">"या वापरकर्त्याशी कॉल इतिहास शेअर केला जाईल."</string>
@@ -2918,7 +2923,7 @@
     <string name="nfc_payment_app_and_desc" msgid="102312684211458190">"<xliff:g id="APP">%1$s</xliff:g> - <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="nfc_payment_use_default" msgid="3098724195746409476">"डीफॉल्ट वापरा"</string>
     <string name="nfc_payment_favor_default" msgid="7555356982142464260">"नेहमी"</string>
-    <string name="nfc_payment_favor_open" msgid="3739055715000436749">"दुसरा पेमेंट अ‍ॅप खुला असतो तेव्हा त्यास वगळून"</string>
+    <string name="nfc_payment_favor_open" msgid="3739055715000436749">"दुसरे पेमेंट अ‍ॅप खुले असते तेव्हा त्यास वगळून"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"टॅप आणि पे टर्मिनलवर, यासह पे करा:"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"टर्मिनलवर पेमेंट करा"</string>
     <string name="nfc_how_it_works_content" msgid="9174575836302449343">"पेमेंट अ‍ॅप सेट करा. त्यानंतर संपर्करहित आयकन असलेल्या कोणत्याही टर्मिनलवर आपल्‍या फोनची मागील बाजू धरा."</string>
@@ -2932,7 +2937,7 @@
     <string name="restriction_menu_change_pin" msgid="592512748243421101">"पिन बदला"</string>
     <string name="app_notifications_switch_label" msgid="670683308275498821">"सूचना दर्शवा"</string>
     <string name="help_label" msgid="1296484776243905646">"मदत आणि अभिप्राय"</string>
-    <string name="support_summary" msgid="3278943815956130740">"मदत लेख, फोन आणि चॅट, सुरूवात करणे"</string>
+    <string name="support_summary" msgid="3278943815956130740">"मदत लेख, फोन आणि चॅट, सुरुवात करणे"</string>
     <string name="user_account_title" msgid="2108666882630552859">"सामग्रीसाठी खाते"</string>
     <string name="user_picture_title" msgid="6664602422948159123">"फोटो आयडी"</string>
     <string name="extreme_threats_title" msgid="1405820547540456436">"अत्याधिक धोके"</string>
@@ -3044,7 +3049,7 @@
     <string name="app_default_dashboard_title" msgid="6575301028225232193">"डीफॉल्ट अ‍ॅप्स"</string>
     <string name="system_dashboard_summary" msgid="6582464466735779394">"भाषा, जेश्चर, वेळ, बॅकअप"</string>
     <string name="search_results_title" msgid="4160717656435503940">"सेटिंग्ज"</string>
-    <string name="keywords_wifi" msgid="8477688080895466846">"वायफाय, वाय-फाय, नेटवर्क कनेक्शन, इंटरनेट, वायरलेस, डेटा, वाय फाय"</string>
+    <string name="keywords_wifi" msgid="8477688080895466846">"वायफाय, वाय-फाय, नेटवर्क कनेक्शन, इंटरनेट, वायरलेस, डेटा, वाय-फाय"</string>
     <string name="keywords_wifi_notify_open_networks" msgid="1031260564121854773">"वाय-फाय सूचना, वायफाय सूचना"</string>
     <string name="keywords_auto_brightness" msgid="5007188989783072428">"ऑटो ब्राइटनेस"</string>
     <string name="keywords_vibrate_on_touch" msgid="3615173661462446877">"व्हायब्रेशन थांबवा, टॅप करा, कीबोर्ड"</string>
@@ -3113,7 +3118,7 @@
     <string name="keywords_system_update_settings" msgid="4419971277998986067">"अपग्रेड करा, Android"</string>
     <string name="keywords_zen_mode_settings" msgid="4103819458182535493">"डीएनडी, शेड्यूल, सूचना, ब्लॉक, शांतता, व्हायब्रेट, झोप, काम, फोकस, ध्वनी, म्यूट, दिवस, कार्य दिवस, शनिवार व रविवार, आठवड्याची शेवटची रात्र, इव्हेंट"</string>
     <string name="keywords_screen_timeout" msgid="4328381362313993666">"स्क्रीन, लॉक टाइम, कालबाह्य, लॉकस्क्रीन"</string>
-    <string name="keywords_storage_settings" msgid="6422454520424236476">"मेमरी, कॅशे, डेटा, हटवा, साफ करा, मोकळी करा, जागा"</string>
+    <string name="keywords_storage_settings" msgid="6422454520424236476">"मेमरी, कॅशे , डेटा, हटवा, साफ करा, मोकळी करा, जागा"</string>
     <string name="keywords_bluetooth_settings" msgid="1152229891590622822">"कनेक्ट केलेले, डिव्हाइस, हेडफोन, हेडसेट, स्पीकर, वायरलेस, पेअर, इयरबड, संगीत, मीडिया"</string>
     <string name="keywords_wallpaper" msgid="7665778626293643625">"पार्श्वभूमी, स्क्रीन, लॉकस्क्रीन, थीम"</string>
     <string name="keywords_assist_input" msgid="8392362788794886564">"डीफॉल्ट, सहाय्यक"</string>
@@ -3141,11 +3146,11 @@
     <string name="notification_unknown_sound_title" msgid="8043718667804838398">"ॲपने प्रदान केलेला ध्वनी"</string>
     <string name="notification_sound_default" msgid="2664544380802426260">"डीफॉल्ट सूचना ध्वनी"</string>
     <string name="alarm_ringtone_title" msgid="6411326147408635902">"डीफॉल्ट अलार्म ध्वनी"</string>
-    <string name="vibrate_when_ringing_title" msgid="2757996559847126952">"कॉलसाठी कंपन सुरू करा"</string>
+    <string name="vibrate_when_ringing_title" msgid="2757996559847126952">"कॉलसाठी व्हायब्रेट करा"</string>
     <string name="other_sound_settings" msgid="5250376066099818676">"इतर ध्वनी"</string>
     <string name="dial_pad_tones_title" msgid="8877212139988655769">"डायल पॅड टोन"</string>
     <string name="screen_locking_sounds_title" msgid="4407110895465866809">"स्‍क्रीन लॉक करणारे ध्वनी"</string>
-    <string name="charging_sounds_title" msgid="5070437987230894287">"आवाज आणि कंपन चार्ज होत आहे"</string>
+    <string name="charging_sounds_title" msgid="5070437987230894287">"चार्जिंगचा आवाज आणि व्हायब्रेशन"</string>
     <string name="docking_sounds_title" msgid="2573137471605541366">"डॉकिंग ध्वनी"</string>
     <string name="touch_sounds_title" msgid="165237488496165652">"स्पर्श ध्वनी"</string>
     <string name="vibrate_on_touch_title" msgid="6360155469279157684">"स्पर्श व्हायब्रेट"</string>
@@ -3156,7 +3161,7 @@
     <string name="emergency_tone_silent" msgid="804809075282717882">"शांतता"</string>
     <string name="emergency_tone_alert" msgid="907868135091891015">"टोन"</string>
     <string name="emergency_tone_vibrate" msgid="5020068066905681181">"स्पंदने"</string>
-    <string name="boot_sounds_title" msgid="7583926202411353620">"ध्वनी चालू करा"</string>
+    <string name="boot_sounds_title" msgid="7583926202411353620">"ध्वनी सुरू करा"</string>
     <string name="live_caption_title" msgid="7926591158657997051">"लाइव्ह कॅप्शन"</string>
     <string name="live_caption_summary" msgid="9064771862352393125">"मीडियाला आपोआप सबटायटल द्या"</string>
     <string name="zen_mode_settings_summary_off" msgid="6929319200478424962">"कधीही नाही"</string>
@@ -3165,7 +3170,7 @@
       <item quantity="one">एक सुरू केले</item>
     </plurals>
     <string name="zen_mode_settings_title" msgid="3425263414594779244">"व्यत्यय आणू नका"</string>
-    <string name="zen_mode_settings_turn_on_dialog_title" msgid="3062548369931058282">"व्यत्यय आणू नका चालू करा"</string>
+    <string name="zen_mode_settings_turn_on_dialog_title" msgid="3062548369931058282">"व्यत्यय आणू नका सुरू करा"</string>
     <string name="zen_mode_behavior_settings_title" msgid="423125904296667490">"अपवाद"</string>
     <string name="zen_mode_duration_settings_title" msgid="5522668871014735728">"डीफॉल्ट कालावधी"</string>
     <string name="zen_mode_behavior_allow_title" msgid="2440627647424280842">"यांचे ध्वनी आणि व्हायब्रेशन राहू द्या"</string>
@@ -3205,7 +3210,7 @@
     <string name="zen_mode_restrict_notifications_summary_custom" msgid="4982187708274505748">"अंशतः लपवलेले"</string>
     <string name="zen_mode_restrict_notifications_summary_hidden" msgid="7637206880685474111">"सूचना आल्यावर व्हिज्युअल किंवा आवाज नाही"</string>
     <string name="zen_mode_what_to_block_title" msgid="2142809942549840800">"कस्टम प्रतिबंध"</string>
-    <string name="zen_mode_block_effects_screen_on" msgid="1042489123800404560">"स्क्रीन चालू असताना"</string>
+    <string name="zen_mode_block_effects_screen_on" msgid="1042489123800404560">"स्क्रीन सुरू असताना"</string>
     <string name="zen_mode_block_effects_screen_off" msgid="6380935819882837552">"स्क्रीन बंद असताना"</string>
     <string name="zen_mode_block_effect_sound" msgid="1499243540186357631">"ध्वनी आणि व्हायब्रेट म्यूट करा"</string>
     <string name="zen_mode_block_effect_intent" msgid="5666951244667422668">"स्क्रीन सुरू करू नका"</string>
@@ -3217,7 +3222,7 @@
     <string name="zen_mode_block_effect_list" msgid="6081548478844912181">"सूचना सूचीमधून लपवा"</string>
     <string name="zen_mode_block_effect_summary_none" msgid="7166175186759564510">"कधीही नाही"</string>
     <string name="zen_mode_block_effect_summary_screen_off" msgid="2985086455557755722">"स्क्रीन बंद असताना"</string>
-    <string name="zen_mode_block_effect_summary_screen_on" msgid="6183282342145215594">"स्क्रीन चालू असताना"</string>
+    <string name="zen_mode_block_effect_summary_screen_on" msgid="6183282342145215594">"स्क्रीन सुरू असताना"</string>
     <string name="zen_mode_block_effect_summary_sound" msgid="4907185880913861880">"ध्वनी आणि व्हायब्रेट"</string>
     <string name="zen_mode_block_effect_summary_some" msgid="6035118904496072665">"ध्वनी, व्हायब्रेट आणि काही व्हिज्युअल चिन्हांच्या काही सूचना"</string>
     <string name="zen_mode_block_effect_summary_all" msgid="2830443565687247759">"सूचनांचा ध्वनी, व्हायब्रेट आणि व्हिज्युअल चिन्ह"</string>
@@ -3225,13 +3230,13 @@
     <string name="zen_mode_no_exceptions" msgid="3099578343994492857">"काहीही नाही"</string>
     <string name="zen_mode_other_options" msgid="7216192179063769057">"इतर पर्याय"</string>
     <string name="zen_mode_add" msgid="2533484377786927366">"जोडा"</string>
-    <string name="zen_mode_enable_dialog_turn_on" msgid="6396050543542026184">"चालू करा"</string>
+    <string name="zen_mode_enable_dialog_turn_on" msgid="6396050543542026184">"सुरू करा"</string>
     <string name="zen_mode_button_turn_on" msgid="1097964136225943415">"आता सुरू करा"</string>
     <string name="zen_mode_button_turn_off" msgid="3990967728457149454">"आता बंद करा"</string>
-    <string name="zen_mode_settings_dnd_manual_end_time" msgid="4307574188962071429">"व्यत्यय आणू नका <xliff:g id="FORMATTED_TIME">%s</xliff:g> पर्यंत चालू असणार आहे"</string>
+    <string name="zen_mode_settings_dnd_manual_end_time" msgid="4307574188962071429">"व्यत्यय आणू नका <xliff:g id="FORMATTED_TIME">%s</xliff:g> पर्यंत सुरू असणार आहे"</string>
     <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"तुम्ही बंद करेपर्यंत व्यत्यय आणू नका सुरू राहील"</string>
     <string name="zen_mode_settings_dnd_automatic_rule" msgid="2843297614114625408">"(<xliff:g id="RULE_NAME">%s</xliff:g>) शेड्युलने व्यत्यय आणू नका आपोआप सुरू केले"</string>
-    <string name="zen_mode_settings_dnd_automatic_rule_app" msgid="5103454923160912313">"<xliff:g id="APP_NAME">%s</xliff:g> या ॲपने व्यत्यय आणू नका आपोआप चालू केले"</string>
+    <string name="zen_mode_settings_dnd_automatic_rule_app" msgid="5103454923160912313">"<xliff:g id="APP_NAME">%s</xliff:g> या ॲपने व्यत्यय आणू नका आपोआप सुरू केले"</string>
     <string name="zen_mode_settings_dnd_custom_settings_footer" msgid="6335108298640066560">"<xliff:g id="RULE_NAMES">%s</xliff:g>साठी व्यत्यय आणू नका कस्टम सेटिंग्ज सह सुरू आहे."</string>
     <string name="zen_mode_settings_dnd_custom_settings_footer_link" msgid="4007974052885089379"><annotation id="link">" कस्टम सेटिंग्ज पाहा"</annotation></string>
     <string name="zen_interruption_level_priority" msgid="9178419297408319234">"केवळ प्राधान्य"</string>
@@ -3369,7 +3374,7 @@
     <string name="notification_assistant_security_warning_title" msgid="4190584438086738496">"<xliff:g id="SERVICE">%1$s</xliff:g> ला सूचना अ‍ॅक्सेस करण्याची अनुमती द्यायची का?"</string>
     <string name="notification_assistant_security_warning_summary" msgid="6924513399671031930">"संपर्क नावे आणि तुम्हाला येणारे एसएमएस यासारख्या वैयक्तिक माहितीच्या समावेशासह <xliff:g id="NOTIFICATION_ASSISTANT_NAME">%1$s</xliff:g> सर्व सूचना पाहू शकेल. ते त्यांच्यामधील सूचनांमध्ये बदल करू शकेल किंवा त्यांना डिसमिस करू शकेल अथवा त्यामध्ये असलेली अ‍ॅक्शन बटणे ट्रिगर करू शकेल. \n\nयामुळे ॲपला व्यत्यय आणू नका सुरू किंवा बंद करता येईल आणि संबंधित सेटिंग्ज बदलता येतील."</string>
     <string name="notification_listener_security_warning_title" msgid="4902253246428777797">"<xliff:g id="SERVICE">%1$s</xliff:g> साठी सूचना प्रवेशास अनुमती द्यायची?"</string>
-    <string name="notification_listener_security_warning_summary" msgid="4454702907350100288">"<xliff:g id="NOTIFICATION_LISTENER_NAME">%1$s</xliff:g> तुम्ही प्राप्त करता ती संपर्क नावे आणि मजकूर मेसेज यासारख्या वैयक्तिक माहितीसह सर्व सूचना वाचण्यात सक्षम असेल. तो सूचना डिसमिस करण्यात किंवा त्यामध्ये असलेली क्रिया बटणे ट्रिगर करण्यात देखील सक्षम असेल. \n\nहे ॲपला व्यत्यय आणू नका चालू किंवा बंद करण्याची आणि सबंधित सेटिंग्ज बदलण्याची क्षमता देखील देईल."</string>
+    <string name="notification_listener_security_warning_summary" msgid="4454702907350100288">"<xliff:g id="NOTIFICATION_LISTENER_NAME">%1$s</xliff:g> तुम्ही प्राप्त करता ती संपर्क नावे आणि मजकूर मेसेज यासारख्या वैयक्तिक माहितीसह सर्व सूचना वाचण्यात सक्षम असेल. तो सूचना डिसमिस करण्यात किंवा त्यामध्ये असलेली क्रिया बटणे ट्रिगर करण्यात देखील सक्षम असेल. \n\nहे ॲपला व्यत्यय आणू नका सुरू किंवा बंद करण्याची आणि सबंधित सेटिंग्ज बदलण्याची क्षमता देखील देईल."</string>
     <string name="notification_listener_disable_warning_summary" msgid="162165151519082978">"तुम्ही <xliff:g id="NOTIFICATION_LISTENER_NAME">%1$s</xliff:g> साठी सूचनांमधील प्रवेश बंद केल्यास, व्यत्यय आणू नका मधील प्रवेश देखील बंद केला जाऊ शकतो."</string>
     <string name="notification_listener_disable_warning_confirm" msgid="7863495391671154188">"बंद करा"</string>
     <string name="notification_listener_disable_warning_cancel" msgid="6264631825225298458">"रद्द करा"</string>
@@ -3410,7 +3415,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> वर्गवाऱ्या हटवल्या</item>
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> वर्गवारी हटवली</item>
     </plurals>
-    <string name="notification_toggle_on" msgid="5119816745741139542">"चालू"</string>
+    <string name="notification_toggle_on" msgid="5119816745741139542">"सुरू"</string>
     <string name="notification_toggle_off" msgid="5289843670514922751">"बंद"</string>
     <string name="app_notification_block_title" msgid="7898269373875294367">"सर्व ब्लॉक करा"</string>
     <string name="app_notification_block_summary" msgid="4502146897785692336">"या सूचना कधीही दर्शवू नका"</string>
@@ -3442,13 +3447,13 @@
     <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"\"<xliff:g id="RULE">%1$s</xliff:g>\" नियम हटवायचा?"</string>
     <string name="zen_mode_delete_rule_button" msgid="611058106279881991">"हटवा"</string>
     <string name="zen_mode_rule_type_unknown" msgid="2819480113355191421">"अज्ञात"</string>
-    <string name="zen_mode_app_set_behavior" msgid="8597398780262575571">"या सेटिंग्ज आत्ता बदलता येणार नाहीत. एका (<xliff:g id="APP_NAME">%1$s</xliff:g>) अ‍ॅपने कस्टम वर्तनासह व्यत्यय आणू नका आपोआप चालू केलेले आहे."</string>
-    <string name="zen_mode_unknown_app_set_behavior" msgid="5666462954329932302">"या सेटिंग्ज आत्ता बदलता येणार नाहीत. एका अ‍ॅपने व्यत्यय आणू नका हे कस्टम वर्तनासह आपोआप चालू केले."</string>
-    <string name="zen_mode_qs_set_behavior" msgid="788646569296973998">"या सेटिंग्ज आत्ता बदलता येणार नाहीत. व्यत्यय आणू नका हे मॅन्युअली कस्टम वर्तनासह चालू करण्यात आले."</string>
+    <string name="zen_mode_app_set_behavior" msgid="8597398780262575571">"या सेटिंग्ज आत्ता बदलता येणार नाहीत. एका (<xliff:g id="APP_NAME">%1$s</xliff:g>) अ‍ॅपने कस्टम वर्तनासह व्यत्यय आणू नका आपोआप सुरू केलेले आहे."</string>
+    <string name="zen_mode_unknown_app_set_behavior" msgid="5666462954329932302">"या सेटिंग्ज आत्ता बदलता येणार नाहीत. एका अ‍ॅपने व्यत्यय आणू नका हे कस्टम वर्तनासह आपोआप सुरू केले."</string>
+    <string name="zen_mode_qs_set_behavior" msgid="788646569296973998">"या सेटिंग्ज आत्ता बदलता येणार नाहीत. व्यत्यय आणू नका हे मॅन्युअली कस्टम वर्तनासह सुरू करण्यात आले."</string>
     <string name="zen_schedule_rule_type_name" msgid="4516851728113801329">"वेळ"</string>
-    <string name="zen_schedule_rule_enabled_toast" msgid="1742354493045049048">"निर्दिष्‍ट केलेल्या कालावधींसाठी व्यत्यय आणू नका चालू करण्याकरिता स्वयंचलित नियम सेट केला"</string>
+    <string name="zen_schedule_rule_enabled_toast" msgid="1742354493045049048">"निर्दिष्‍ट केलेल्या कालावधींसाठी व्यत्यय आणू नका सुरू करण्याकरिता स्वयंचलित नियम सेट केला"</string>
     <string name="zen_event_rule_type_name" msgid="7467729997336583342">"इव्‍हेंट"</string>
-    <string name="zen_event_rule_enabled_toast" msgid="7087368268966855976">"निर्दिष्‍ट केलेल्या इव्हेंटसाठी व्यत्यय आणू नका चालू करण्याकरिता स्वयंचलित नियम सेट केला"</string>
+    <string name="zen_event_rule_enabled_toast" msgid="7087368268966855976">"निर्दिष्‍ट केलेल्या इव्हेंटसाठी व्यत्यय आणू नका सुरू करण्याकरिता स्वयंचलित नियम सेट केला"</string>
     <string name="zen_mode_event_rule_calendar" msgid="6088077103908487442">"यासाठी इव्हेंट दरम्यान"</string>
     <string name="zen_mode_event_rule_summary_calendar_template" msgid="4027207992040792657">"<xliff:g id="CALENDAR">%1$s</xliff:g> साठी इव्हेंट दरम्यान"</string>
     <string name="zen_mode_event_rule_summary_any_calendar" msgid="7590085295784895885">"कोणतेही कॅलेंडर"</string>
@@ -3459,7 +3464,7 @@
     <string name="zen_mode_event_rule_reply_yes_or_maybe" msgid="5042234361937256329">"होय किंवा कदाचित"</string>
     <string name="zen_mode_event_rule_reply_yes" msgid="7039756546321205552">"होय"</string>
     <string name="zen_mode_rule_not_found_text" msgid="6553855397424553685">"नियम आढळला नाही."</string>
-    <string name="zen_mode_rule_summary_enabled_combination" msgid="8269105393636454359">"चालू / <xliff:g id="MODE">%1$s</xliff:g>"</string>
+    <string name="zen_mode_rule_summary_enabled_combination" msgid="8269105393636454359">"सुरू / <xliff:g id="MODE">%1$s</xliff:g>"</string>
     <string name="zen_mode_rule_summary_provider_combination" msgid="8674730656585528193">"<xliff:g id="PACKAGE">%1$s</xliff:g>\n<xliff:g id="SUMMARY">%2$s</xliff:g>"</string>
     <string name="zen_mode_schedule_rule_days" msgid="220627703673691816">"दिवस"</string>
     <string name="zen_mode_schedule_rule_days_none" msgid="6011716195119389956">"काहीही नाही"</string>
@@ -3521,7 +3526,7 @@
     <string name="zen_mode_calls_summary_two" msgid="9017678770532673578">"<xliff:g id="CALLER_TYPE">%1$s</xliff:g> आणि <xliff:g id="CALLERT_TPYE">%2$s</xliff:g> कडून अनुमती द्या"</string>
     <string name="zen_mode_repeat_callers_summary" msgid="1752513516040525545">"एकाच व्यक्तीने <xliff:g id="MINUTES">%d</xliff:g> मिनिटांच्या आत दुसर्‍यांदा कॉल केल्यास"</string>
     <string name="zen_mode_behavior_summary_custom" msgid="3909532602640130841">"कस्टम"</string>
-    <string name="zen_mode_when" msgid="7835420687948416255">"स्वयंचलितपणे चालू करा"</string>
+    <string name="zen_mode_when" msgid="7835420687948416255">"स्वयंचलितपणे सुरू करा"</string>
     <string name="zen_mode_when_never" msgid="4506296396609224524">"कधीही नाही"</string>
     <string name="zen_mode_when_every_night" msgid="3942151668791426194">"प्रत्येक रात्री"</string>
     <string name="zen_mode_when_weeknights" msgid="2412709309122408474">"आठवड्याच्या रात्री"</string>
@@ -3539,11 +3544,11 @@
     </plurals>
     <string name="zen_mode_summary_alarms_only_by_time" msgid="2462898862757904560">"केवळ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> पर्यंत अलार्मवर बदला"</string>
     <string name="zen_mode_summary_always" msgid="2703276042913200837">"नेहमी व्‍यत्यय आणा वर बदला"</string>
-    <string name="zen_mode_screen_on" msgid="7098470659072167219">"स्क्रीन चालू असताना"</string>
+    <string name="zen_mode_screen_on" msgid="7098470659072167219">"स्क्रीन सुरू असताना"</string>
     <string name="zen_mode_screen_on_summary" msgid="8275416649295357524">"सूचनांना स्क्रीनवरील व्यत्यय आणू नका पॉपने शांत होऊ द्या, आणि एक स्टेटस बार आयकॉन दाखवू द्या"</string>
     <string name="zen_mode_screen_off" msgid="84211490206459038">"स्क्रीन बंद असताना"</string>
-    <string name="zen_mode_screen_off_summary" msgid="8592179073243001267">"व्यत्यय आणू नका ने स्क्रीन चालू करून लाइटची उघडझाप करू द्या आणि सूचनांना मूक होऊ द्या"</string>
-    <string name="zen_mode_screen_off_summary_no_led" msgid="7255874108150630145">"व्यत्यय आणू नका ने स्क्रीन चालू करा आणि सूचनांना मूक होऊ द्या"</string>
+    <string name="zen_mode_screen_off_summary" msgid="8592179073243001267">"व्यत्यय आणू नका ने स्क्रीन सुरू करून लाइटची उघडझाप करू द्या आणि सूचनांना मूक होऊ द्या"</string>
+    <string name="zen_mode_screen_off_summary_no_led" msgid="7255874108150630145">"व्यत्यय आणू नका ने स्क्रीन सुरू करा आणि सूचनांना मूक होऊ द्या"</string>
     <string name="notification_app_settings_button" msgid="3651180424198580907">"सूचना सेटिंग्ज"</string>
     <string name="suggestion_button_text" msgid="5783566542423813847">"ठीक"</string>
     <string name="device_feedback" msgid="4042352891448769818">"या डिव्हाइस बद्दल अभिप्राय पाठवा"</string>
@@ -3560,7 +3565,7 @@
     <string name="managing_admin" msgid="3212584016377581608">"<xliff:g id="ADMIN_APP_LABEL">%s</xliff:g> द्वारे व्यवस्थापित"</string>
     <string name="experimental_preference" msgid="5903223408406906322">"(प्रायोगिक)"</string>
     <string name="encryption_interstitial_header" msgid="3298397268731647519">"सुरक्षित प्रारंभ"</string>
-    <string name="encryption_continue_button" msgid="2808797091460167842">"सुरु ठेवा"</string>
+    <string name="encryption_continue_button" msgid="2808797091460167842">"सुरू ठेवा"</string>
     <string name="encryption_interstitial_message_pin" msgid="6592265582286340307">"सुरू होण्यापूर्वी तुमचा पिन आवश्यक करून तुम्ही हे डिव्हाइस अधिक संरक्षित करू शकता. डिव्हाइस सुरू होईपर्यंत, ते कॉल, मेसेज किंवा अलार्मसह सूचना प्राप्त करू शकत नाही. \n\nयामुळे हरवलेल्या किंवा चोरीला गेलेल्या डिव्हाइस वरील डेटाचे संरक्षण करण्यात मदत होते. तुमचे डिव्हाइस सुरू करण्यासाठी पिन हवा?"</string>
     <string name="encryption_interstitial_message_pattern" msgid="5620724295995735120">"सुरू होण्यापूर्वी तुमचा पॅटर्न आवश्यक करून तुम्ही हे डिव्हाइस अधिक संरक्षित करू शकता. डिव्हाइस सुरू होईपर्यंत, ते कॉल, मेसेज किंवा अलार्मसह सूचना प्राप्त करू शकत नाही. \n\nयामुळे हरवलेल्या किंवा चोरीला गेलेल्या डिव्हाइस वरील डेटाचे संरक्षण करण्यात मदत होते. तुमचे डिव्हाइस सुरू करण्यासाठी पॅटर्न हवा?"</string>
     <string name="encryption_interstitial_message_password" msgid="7236688467386126401">"सुरू होण्यापूर्वी तुमचा पासवर्ड आवश्यक करून तुम्ही हे डिव्हाइस अधिक संरक्षित करू शकता. डिव्हाइस सुरू होईपर्यंत, ते कॉल, मेसेज किंवा अलार्मसह सूचना प्राप्त करू शकत नाही. \n\nयामुळे हरवलेल्या किंवा चोरीला गेलेल्या डिव्हाइस वरील डेटाचे संरक्षण करण्यात मदत होते. तुमचे डिव्हाइस सुरू करण्यासाठी पासवर्ड हवा?"</string>
@@ -3707,8 +3712,8 @@
     <string name="high_power_off" msgid="5906679734326490426">"बॅटरी वापर ऑप्टिमाइझ करत आहे"</string>
     <string name="high_power_system" msgid="739584574711292753">"बॅटरी ऑप्टिमायझेशन उपलब्ध नाही"</string>
     <string name="high_power_desc" msgid="333756885680362741">"बॅटरी ऑप्टिमायझेशन वापरू नका. तुमची बॅटरी अधिक द्रुतपणे संपवू शकते."</string>
-    <string name="high_power_prompt_title" msgid="2805745781720454052">"अ‍ॅप नेहमी पार्श्वभूमीत चालू द्यायचे?"</string>
-    <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g> नेहमी पार्श्वभूमीमध्ये चालू दिल्याने बॅटरीचे आयुर्मान कमी होऊ शकते. \n\nतुम्ही हे नंतर सेटिंग्ज &gt; अ‍ॅप्स आणि सूचना मधून बदलू शकता."</string>
+    <string name="high_power_prompt_title" msgid="2805745781720454052">"अ‍ॅप नेहमी पार्श्वभूमीत सुरू द्यायचे?"</string>
+    <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g> नेहमी पार्श्वभूमीमध्ये सुरू दिल्याने बॅटरीचे आयुर्मान कमी होऊ शकते. \n\nतुम्ही हे नंतर सेटिंग्ज &gt; अ‍ॅप्स आणि सूचना मधून बदलू शकता."</string>
     <string name="battery_summary" msgid="4345690800899981339">"शेवटच्या पूर्ण चार्जनंतर <xliff:g id="PERCENTAGE">%1$s</xliff:g> वापर"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"ऊर्जा व्यवस्थापन"</string>
     <string name="no_battery_summary" msgid="4105932628367471314">"पूर्ण चार्ज झाल्यानंतर बॅटरी वापर नाही"</string>
@@ -3726,9 +3731,9 @@
     <string name="usb_use_charging_only_desc" msgid="3283518562582478950">"फक्त हे डिव्हाइस चार्ज करा"</string>
     <string name="usb_use_power_only" msgid="6595783381323810697">"कनेक्ट केलेले डिव्हाइस चार्ज करा"</string>
     <string name="usb_use_file_transfers" msgid="6153021302176151884">"फाइल ट्रान्सफर"</string>
-    <string name="usb_use_file_transfers_desc" msgid="6953866660041189580">"दुसऱ्या डिव्हाइसवर फायली स्थानांतरित करा"</string>
+    <string name="usb_use_file_transfers_desc" msgid="6953866660041189580">"दुसऱ्या डिव्हाइसवर फाइल स्थानांतरित करा"</string>
     <string name="usb_use_photo_transfers" msgid="5974236250197451257">"PTP"</string>
-    <string name="usb_use_photo_transfers_desc" msgid="2325112887316125320">"MTP (PTP) समर्थित नसल्‍यास फोटो किंवा फायली स्थानांतरित  करा"</string>
+    <string name="usb_use_photo_transfers_desc" msgid="2325112887316125320">"MTP (PTP) समर्थित नसल्‍यास फोटो किंवा फाइल स्थानांतरित  करा"</string>
     <string name="usb_use_tethering" msgid="4250626730173163846">"USB टेदरिंग"</string>
     <string name="usb_use_MIDI" msgid="4710632870781041401">"MIDI"</string>
     <string name="usb_use_MIDI_desc" msgid="1770966187150010947">"या डिव्हाइसचा MIDI म्हणून वापर करा"</string>
@@ -3783,8 +3788,8 @@
     <string name="memory_maximum_usage" msgid="4734981118293469479">"कमाल वापर"</string>
     <string name="no_data_usage" msgid="903383745620135746">"डेटा वापरला गेलेला नाही"</string>
     <string name="zen_access_warning_dialog_title" msgid="7704910289810337055">"<xliff:g id="APP">%1$s</xliff:g> वर व्यत्यय आणू नका ला ॲक्सेस द्यायचा का?"</string>
-    <string name="zen_access_warning_dialog_summary" msgid="2717755746850874577">"व्यत्यय आणू नका चालू/बंद करण्‍यात आणि संबंधित स्‍ट्रिंगमध्‍ये बदल करण्‍यात अ‍ॅप सक्षम असेल."</string>
-    <string name="zen_access_disabled_package_warning" msgid="7086237569177576966">"सूचना प्रवेश चालू असल्याने चालू केलेले ठेवणे आवश्यक आहे"</string>
+    <string name="zen_access_warning_dialog_summary" msgid="2717755746850874577">"व्यत्यय आणू नका सुरू/बंद करण्‍यात आणि संबंधित स्‍ट्रिंगमध्‍ये बदल करण्‍यात अ‍ॅप सक्षम असेल."</string>
+    <string name="zen_access_disabled_package_warning" msgid="7086237569177576966">"सूचना प्रवेश सुरू असल्याने सुरू केलेले ठेवणे आवश्यक आहे"</string>
     <string name="zen_access_revoke_warning_dialog_title" msgid="6850994585577513299">"<xliff:g id="APP">%1$s</xliff:g> साठी व्यत्यय आणू नका मध्‍ये प्रवेश करणे रद्द करायचे?"</string>
     <string name="zen_access_revoke_warning_dialog_summary" msgid="3487422193181311403">"या ॲपने तयार केलेले सर्व व्यत्यय आणू नका नियम काढले जातील."</string>
     <string name="ignore_optimizations_on" msgid="4373971641328943551">"ऑप्टिमाइझ करू नका"</string>
@@ -3851,7 +3856,7 @@
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> अ‍ॅप्ससाठी बंद</item>
       <item quantity="one">1 अ‍ॅपसाठी बंद</item>
     </plurals>
-    <string name="notification_summary_none" msgid="5003043219430054784">"सर्व ॲप्ससाठी चालू"</string>
+    <string name="notification_summary_none" msgid="5003043219430054784">"सर्व ॲप्ससाठी सुरू"</string>
     <string name="apps_summary" msgid="8355759446490212195">"<xliff:g id="COUNT">%1$d</xliff:g> अ‍ॅप्स इंस्टॉल केले"</string>
     <string name="apps_summary_example" msgid="3011143598675185269">"24 अ‍ॅप्स इंस्टॉल केली"</string>
     <string name="storage_summary" msgid="4835916510511133784">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> वापरले - <xliff:g id="FREE_SPACE">%2$s</xliff:g> मोकळे"</string>
@@ -3880,16 +3885,16 @@
     <string name="admin_profile_owner_user_message" msgid="2991249382056855531">"तुमचा प्रशासक सेटिंग्ज, परवानग्या, कॉर्पोरेट ॲक्सेस, नेटवर्क ॲक्टिव्हिटी आणि डीव्हाइसची स्थान माहिती यांसह तुमच्या कार्य प्रोफाइलशी संबधित ॲप्सचे आणि डेटाचे परीक्षण व व्यवस्थापन करू शकतो."</string>
     <string name="admin_device_owner_message" msgid="1823477572459610869">"तुमच्या प्रशासकाकडे तुमच्या नेटवर्क ॲक्टिव्हिटी तसेच या डीव्हाइसशी संबधित सेटिंग्ज, कॉर्पोरेट ॲक्सेस, परवानग्या यांसह अ‍ॅप्स आणि डेटा यांचे परीक्षण आणि व्यवस्थापन करण्याची क्षमता आहे."</string>
     <string name="condition_turn_off" msgid="4395150881365143558">"बंद करा"</string>
-    <string name="condition_turn_on" msgid="1699088245481841159">"चालू करा"</string>
+    <string name="condition_turn_on" msgid="1699088245481841159">"सुरू करा"</string>
     <string name="condition_expand_show" msgid="4118818022763913777">"दर्शवा"</string>
     <string name="condition_expand_hide" msgid="1112721783024332643">"लपवा"</string>
     <string name="condition_hotspot_title" msgid="4143299802283098506">"हॉटस्पॉट अ‍ॅक्टिव्ह आहे"</string>
-    <string name="condition_airplane_title" msgid="8484582712516148433">"विमान मोड चालू आहे"</string>
+    <string name="condition_airplane_title" msgid="8484582712516148433">"विमान मोड सुरू आहे"</string>
     <string name="condition_airplane_summary" msgid="3021193218494740742">"नेटवर्क उपलब्ध नाही"</string>
-    <string name="condition_zen_title" msgid="2128184708916052585">"व्यत्यय आणू नका चालू आहे"</string>
+    <string name="condition_zen_title" msgid="2128184708916052585">"व्यत्यय आणू नका सुरू आहे"</string>
     <string name="condition_zen_summary_phone_muted" msgid="4396050395522974654">"फोन म्यूट केला आहे"</string>
     <string name="condition_zen_summary_with_exceptions" msgid="3435216391993785818">"अपवादांसह"</string>
-    <string name="condition_battery_title" msgid="6704870010912986274">"बॅटरी बचतकर्ता चालू आहे"</string>
+    <string name="condition_battery_title" msgid="6704870010912986274">"बॅटरी सेव्हर सुरू आहे"</string>
     <string name="condition_battery_summary" msgid="1236078243905690620">"वैशिष्ट्ये प्रतिबंधित केलेली आहेत"</string>
     <string name="condition_cellular_title" msgid="6605277435894307935">"मोबाइल डेटा बंद आहे"</string>
     <string name="condition_cellular_summary" msgid="3607459310548343777">"इंटरनेट फक्त वाय-फायद्वारे उपलब्ध आहे"</string>
@@ -3904,7 +3909,7 @@
     <string name="condition_device_vibrate_summary" msgid="9073880731894828604">"कॉल आणि सूचनांसाठी"</string>
     <string name="night_display_suggestion_title" msgid="4222839610992282188">"रात्रीच्या प्रकाशाचे वेळापत्रक सेट करा"</string>
     <string name="night_display_suggestion_summary" msgid="1754361016383576916">"दररोज रात्री स्क्रीन आपोआप टिंट करा"</string>
-    <string name="condition_night_display_title" msgid="9171491784857160135">"रात्रीचा प्रकाश चालू आहे"</string>
+    <string name="condition_night_display_title" msgid="9171491784857160135">"रात्रीचा प्रकाश सुरू आहे"</string>
     <string name="condition_night_display_summary" msgid="7885776986937527558">"स्क्रीनची छटा मंद पिवळसर केली आहे"</string>
     <string name="condition_grayscale_title" msgid="1226351649203551299">"ग्रेस्केल"</string>
     <string name="condition_grayscale_summary" msgid="749172886527349546">"फक्त ग्रे रंगात दाखवा"</string>
@@ -3960,11 +3965,11 @@
     <string name="configure" msgid="8232696842838580549">"कॉन्फिगर करा"</string>
     <string name="data_usage_other_apps" msgid="7002491980141402084">"वापरामध्ये समाविष्‍ट केलेली इतर अ‍ॅप्स"</string>
     <plurals name="data_saver_unrestricted_summary" formatted="false" msgid="6046013861315713697">
-      <item quantity="other">डेटा सेव्हर चालू असताना <xliff:g id="COUNT">%1$d</xliff:g> अनुप्रयोगांना अनिर्बंध डेटा वापरण्याची अनुमती दिली</item>
-      <item quantity="one"> डेटा सेव्हर चालू असताना 1 अनुप्रयोगास अनिर्बंध डेटा वापरण्याची अनुमती दिली</item>
+      <item quantity="other">डेटा सेव्हर सुरू असताना <xliff:g id="COUNT">%1$d</xliff:g> अ‍ॅप्सना अनिर्बंध डेटा वापरण्याची अनुमती दिली</item>
+      <item quantity="one"> डेटा सेव्हर सुरू असताना 1 अ‍ॅपला अनिर्बंध डेटा वापरण्याची अनुमती दिली</item>
     </plurals>
     <string name="data_usage_title" msgid="7874606430902201083">"प्राथमिक डेटा"</string>
-    <string name="data_usage_wifi_title" msgid="7161828479387766556">"वाय फाय डेटा"</string>
+    <string name="data_usage_wifi_title" msgid="7161828479387766556">"वाय-फाय डेटा"</string>
     <string name="data_used" msgid="1063553292806661784">"<xliff:g id="ID_1">^1</xliff:g> वापरला"</string>
     <string name="data_used_formatted" msgid="9150356955895106822">"<xliff:g id="ID_1">^1</xliff:g> <xliff:g id="ID_2">^2</xliff:g> वापरला"</string>
     <string name="data_overusage" msgid="1570432641791021533">"<xliff:g id="ID_1">^1</xliff:g> मर्यादा संपली"</string>
@@ -3988,7 +3993,7 @@
     <string name="data_saver_off" msgid="7439439787358504018">"बंद"</string>
     <string name="data_saver_switch_title" msgid="8244008132112735207">"डेटा सेव्हर वापरा"</string>
     <string name="unrestricted_app_title" msgid="4390661122069905122">"अनिर्बंध डेटा वापर"</string>
-    <string name="unrestricted_app_summary" msgid="2829141815077800483">"डेटा सेव्हर चालू असताना अनिर्बंध डेटा प्रवेशास अनुमती द्या"</string>
+    <string name="unrestricted_app_summary" msgid="2829141815077800483">"डेटा सेव्हर सुरू असताना अनिर्बंध डेटा प्रवेशास अनुमती द्या"</string>
     <string name="home_app" msgid="3695063566006954160">"होम अ‍ॅप"</string>
     <string name="no_default_home" msgid="1518949210961918497">"डीफॉल्ट होम नाही"</string>
     <string name="lockpattern_settings_require_cred_before_startup" msgid="63693894094570367">"सुरक्षित प्रारंभ"</string>
@@ -4137,7 +4142,7 @@
     <string name="fingerprint_swipe_for_notifications_summary" product="tablet" msgid="3480057984564476283">"तुमच्या सूचना तपासण्यासाठी, तुमच्या टॅबलेटच्या मागे फिंगरप्रिंट सेन्सरवर खाली स्वाइप करा."</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="device" msgid="7950264130913070035">"आपल्या सूचना तपासण्यासाठी, आपल्या डिव्हाइसच्या मागे फिंगरप्रिंट सेन्सरवर खाली स्वाइप करा."</string>
     <string name="fingerprint_swipe_for_notifications_suggestion_title" msgid="948946491233738823">"सूचना पटकन पहा"</string>
-    <string name="gesture_setting_on" msgid="7573680730101327866">"चालू"</string>
+    <string name="gesture_setting_on" msgid="7573680730101327866">"सुरू"</string>
     <string name="gesture_setting_off" msgid="2540159841716890511">"बंद"</string>
     <string name="oem_unlock_enable_disabled_summary_bootloader_unlocked" msgid="7233244080078311793">"बुटलोडर आधीपासून अनलॉक केले"</string>
     <string name="oem_unlock_enable_disabled_summary_connectivity" msgid="262986780389836168">"अगोदर इंटरनेटशी कनेक्ट करा"</string>
@@ -4191,9 +4196,9 @@
     </plurals>
     <string name="enterprise_privacy_input_method" msgid="5885916325874284011">"डीफॉल्ट कीबोर्ड"</string>
     <string name="enterprise_privacy_input_method_name" msgid="439610095825218563">"<xliff:g id="APP_LABEL">%s</xliff:g> वर सेट करा"</string>
-    <string name="enterprise_privacy_always_on_vpn_device" msgid="2022700916516458213">"नेहमी VPN चालू असणे सक्रिय आहे"</string>
-    <string name="enterprise_privacy_always_on_vpn_personal" msgid="5644065780843002044">"आपल्‍या वैयक्तिक प्रोफाइलमध्‍ये नेहमी VPN चालू असणे सक्रिय आहे"</string>
-    <string name="enterprise_privacy_always_on_vpn_work" msgid="6443089897985373564">"आपल्‍या कार्य प्रोफाइलमध्‍ये नेहमी VPN चालू असणे सक्रिय आहे"</string>
+    <string name="enterprise_privacy_always_on_vpn_device" msgid="2022700916516458213">"नेहमी VPN सुरू असणे सक्रिय आहे"</string>
+    <string name="enterprise_privacy_always_on_vpn_personal" msgid="5644065780843002044">"आपल्‍या वैयक्तिक प्रोफाइलमध्‍ये नेहमी VPN सुरू असणे सक्रिय आहे"</string>
+    <string name="enterprise_privacy_always_on_vpn_work" msgid="6443089897985373564">"आपल्‍या कार्य प्रोफाइलमध्‍ये नेहमी VPN सुरू असणे सक्रिय आहे"</string>
     <string name="enterprise_privacy_global_http_proxy" msgid="3862135895716080830">"जागतिक HTTP प्रॉक्‍सी सेट आहे"</string>
     <string name="enterprise_privacy_ca_certs_device" msgid="7715658848470643878">"विश्वसनीय क्रेडेंशिअल"</string>
     <string name="enterprise_privacy_ca_certs_personal" msgid="1356447417193483802">"तुमच्‍या खाजगी प्रोफाइलमधील विश्वसनीय क्रेडेंशिअल"</string>
@@ -4235,7 +4240,7 @@
     <string name="storage_music_audio" msgid="3661289086715297149">"संगीत आणि ऑडिओ"</string>
     <string name="storage_games" msgid="7740038143749092373">"गेम"</string>
     <string name="storage_other_apps" msgid="3202407095387420842">"अन्य अ‍ॅप्स"</string>
-    <string name="storage_files" msgid="2087824267937487880">"फायली"</string>
+    <string name="storage_files" msgid="2087824267937487880">"Files"</string>
     <string name="storage_size_large_alternate" msgid="1317796542509105857">"<xliff:g id="NUMBER">^1</xliff:g>"<small>" "<font size="20">"<xliff:g id="UNIT">^2</xliff:g>"</font></small>""</string>
     <string name="storage_volume_total" msgid="5021484171514159913">"<xliff:g id="TOTAL">%1$s</xliff:g> पैकी वापरले"</string>
     <string name="storage_percent_full" msgid="6924662861545958442">"वापरली"</string>
@@ -4243,7 +4248,7 @@
     <string name="clear_instant_app_confirmation" msgid="1778553115373698061">"तुम्हाला हे इन्स्टंट अ‍ॅप काढायचे आहे का?"</string>
     <string name="launch_instant_app" msgid="5251693061228352333">"उघडा"</string>
     <string name="game_storage_settings" msgid="6856911551799175914">"गेम"</string>
-    <string name="audio_files_title" msgid="3073879661731363935">"ऑडिओ फायली"</string>
+    <string name="audio_files_title" msgid="3073879661731363935">"ऑडिओ फाइल"</string>
     <string name="app_info_storage_title" msgid="6643391804949509308">"वापरलेली जागा"</string>
     <string name="webview_uninstalled_for_user" msgid="3407952144444040557">"(<xliff:g id="USER">%s</xliff:g> वापरकर्त्‍यासाठी विस्‍थापित)"</string>
     <string name="webview_disabled_for_user" msgid="8057805373224993504">"(<xliff:g id="USER">%s</xliff:g> वापरकर्त्‍यासाठी अक्षम केले)"</string>
@@ -4262,7 +4267,7 @@
     <string name="show_operator_name_summary" msgid="6352180285743777497">"स्टेटस बारमध्ये नेटवर्क नाव प्रदर्शित करा"</string>
     <string name="storage_manager_indicator" msgid="4255140732848476875">"स्टोरेज व्यवस्थापक: <xliff:g id="STATUS">^1</xliff:g>"</string>
     <string name="storage_manager_indicator_off" msgid="6404056007102580777">"बंद"</string>
-    <string name="storage_manager_indicator_on" msgid="5295306384982062320">"चालू"</string>
+    <string name="storage_manager_indicator_on" msgid="5295306384982062320">"सुरू"</string>
     <string name="install_type_instant" msgid="6248487669862821874">"इन्सटंट अ‍ॅप"</string>
     <string name="automatic_storage_manager_deactivation_warning" msgid="7867793739491286374">"स्टोरेज व्यवस्थापक बंद करायचा?"</string>
     <string name="storage_movies_tv" msgid="7282484273991655296">"चित्रपट आणि टीव्ही अ‍ॅप्स"</string>
@@ -4305,8 +4310,8 @@
     <string name="my_device_info_device_name_preference_title" msgid="7384446683248009296">"डिव्हाइसचे नाव"</string>
     <string name="change_wifi_state_title" msgid="5140754955787584174">"वाय-फाय नियंत्रण"</string>
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"ॲपला वाय-फाय नियंत्रित करू द्या"</string>
-    <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"या ॲपला वाय-फाय चालू किंवा बंद करू द्या, वाय-फाय नेटवर्क स्कॅन करू द्या आणि त्याच्याशी कनेक्ट करू द्या, नेटवर्क जोडू किंवा काढू द्या किंवा केवळ-स्थानिक हॉटस्पॉट सुरू करू द्या"</string>
-    <string name="media_output_title" msgid="8710632337456601848">"मीडिया प्‍ले करा"</string>
+    <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"या ॲपला वाय-फाय सुरू किंवा बंद करू द्या, वाय-फाय नेटवर्क स्कॅन करू द्या आणि त्याच्याशी कनेक्ट करू द्या, नेटवर्क जोडू किंवा काढू द्या किंवा केवळ-स्थानिक हॉटस्पॉट सुरू करू द्या"</string>
+    <string name="media_output_title" msgid="8710632337456601848">"मीडिया यावर प्‍ले करा"</string>
     <string name="media_output_default_summary" msgid="3159237976830415584">"हे डिव्हाइस"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"फोन"</string>
     <string name="media_output_summary" product="tablet" msgid="6672024060360538526">"टॅबलेट"</string>
@@ -4470,7 +4475,7 @@
     <string name="privacy_dashboard_summary" msgid="7916431309860824945">"परवानग्या, खाते अ‍ॅक्टिव्हिटी, वैयक्तिक डेटा"</string>
     <string name="contextual_card_dismiss_remove" msgid="1750420285615827309">"काढून टाका"</string>
     <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"ठेवा"</string>
-    <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"ही सुचाना काढून टाकायची आहे का?"</string>
+    <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"ही सूचना काढून टाकायची आहे का?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"सूचना काढली"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"पहिल्यासारखे करा"</string>
     <string name="low_storage_summary" msgid="4562224870189133400">"स्टोरेज कमी आहे. <xliff:g id="PERCENTAGE">%1$s</xliff:g> वापरले - <xliff:g id="FREE_SPACE">%2$s</xliff:g> मोकळे"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ms/arrays.xml b/tests/CarDeveloperOptions/res/values-ms/arrays.xml
index e7eead6..bc4c748 100644
--- a/tests/CarDeveloperOptions/res/values-ms/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-ms/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"jalankan di latar belakang"</item>
     <item msgid="6423861043647911030">"kelantangan kebolehaksesan"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Lokasi"</item>
+    <item msgid="6656077694190491067">"Lokasi"</item>
+    <item msgid="8790228218278477369">"Lokasi"</item>
+    <item msgid="7836406246005211990">"Getar"</item>
+    <item msgid="3951439024549922598">"Baca kenalan"</item>
+    <item msgid="8802152411647068">"Ubah suai kenalan"</item>
+    <item msgid="229544934599698735">"Baca log panggilan"</item>
+    <item msgid="7396102294405899613">"Ubah suai log panggilan"</item>
+    <item msgid="3597797992398484655">"Baca kalendar"</item>
+    <item msgid="2705975774250907343">"Ubah suai kalendar"</item>
+    <item msgid="4668747371441932697">"Lokasi"</item>
+    <item msgid="1487578921720243646">"Siarkan pemberitahuan"</item>
+    <item msgid="4636080349724146638">"Lokasi"</item>
+    <item msgid="673510900286463926">"Hubungi telefon"</item>
+    <item msgid="542083422784609790">"Baca SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Tulis SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Terima SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Terima SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Terima SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Terima SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Hantar SMS/MMS"</item>
+    <item msgid="4726682243833913568">"Baca SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Tulis SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Ubah suai tetapan"</item>
+    <item msgid="8705854389991425629">"Lukiskan di atas"</item>
+    <item msgid="5861356020344153651">"Pemberitahuan akses"</item>
+    <item msgid="78432174621628659">"Kamera"</item>
+    <item msgid="3986116419882154794">"Rakam audio"</item>
+    <item msgid="4516840825756409490">"Mainkan audio"</item>
+    <item msgid="6811712502798183957">"Baca papan keratan"</item>
+    <item msgid="2780369012602289114">"Ubah suai papan keratan"</item>
+    <item msgid="2331359440170850868">"Butang media"</item>
+    <item msgid="6133599737122751231">"Tumpuan audio"</item>
+    <item msgid="6844485713404805301">"Kelantangan utama"</item>
+    <item msgid="1600379420669104929">"Kelantangan suara"</item>
+    <item msgid="6296768210470214866">"Kelantangan deringan"</item>
+    <item msgid="510690696071629241">"Kelantangan media"</item>
+    <item msgid="406861638631430109">"Kelantangan penggera"</item>
+    <item msgid="4715864795872233884">"Kelantangan pemberitahuan"</item>
+    <item msgid="2311478519251301183">"Kelantangan Bluetooth"</item>
+    <item msgid="5133991377896747027">"Kekal berjaga"</item>
+    <item msgid="2464189519136248621">"Lokasi"</item>
+    <item msgid="2062677934050803037">"Lokasi"</item>
+    <item msgid="1735171933192715957">"Dapatkan statistik penggunaan"</item>
+    <item msgid="1014093788778383554">"Redam/nyahredam mikrofon"</item>
+    <item msgid="4199297950608622850">"Tunjukkan toast"</item>
+    <item msgid="2527962435313398821">"Tayangkan media"</item>
+    <item msgid="5117506254221861929">"Aktifkan VPN"</item>
+    <item msgid="8291198322681891160">"Tulis kertas dinding"</item>
+    <item msgid="7106921284621230961">"Bantu struktur"</item>
+    <item msgid="4496533640894624799">"Bantu tangkapan skrin"</item>
+    <item msgid="2598847264853993611">"Baca keadaan telefon"</item>
+    <item msgid="9215610846802973353">"Tambahkan mel suara"</item>
+    <item msgid="9186411956086478261">"Gunakan sip"</item>
+    <item msgid="6884763100104539558">"Proses panggilan keluar"</item>
+    <item msgid="125513972170580692">"Cap jari"</item>
+    <item msgid="2556071024281275619">"Penderia badan"</item>
+    <item msgid="617168514928339387">"Baca siaran sel"</item>
+    <item msgid="7134693570516523585">"Lokasi palsu"</item>
+    <item msgid="7224489175375229399">"Baca storan"</item>
+    <item msgid="8472735063903258202">"Tulis storan"</item>
+    <item msgid="4069276819909595110">"Hidupkan skrin"</item>
+    <item msgid="1228338896751121025">"Dapatkan akaun"</item>
+    <item msgid="3181581793459233672">"Jalankan di latar belakang"</item>
+    <item msgid="2340936043025374076">"Kelantangan kebolehaksesan"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Pendek"</item>
     <item msgid="4816511817309094890">"Sederhana"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Jangan benarkan"</item>
     <item msgid="8184570120217958741">"Sentiasa benarkan"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Biasa"</item>
+    <item msgid="5101233285497327432">"Sederhana"</item>
+    <item msgid="1555861583162930714">"Rendah"</item>
+    <item msgid="1719683776264798117">"Kritikal"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Biasa"</item>
+    <item msgid="6107138933849816768">"Sederhana"</item>
+    <item msgid="182695359839047859">"Rendah"</item>
+    <item msgid="8577246509202964244">"Kritikal"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Berterusan"</item>
     <item msgid="167418068739176448">"Aktiviti popular"</item>
diff --git a/tests/CarDeveloperOptions/res/values-ms/config.xml b/tests/CarDeveloperOptions/res/values-ms/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-ms/config.xml
+++ b/tests/CarDeveloperOptions/res/values-ms/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-ms/strings.xml b/tests/CarDeveloperOptions/res/values-ms/strings.xml
index f21e428..0590a74 100644
--- a/tests/CarDeveloperOptions/res/values-ms/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ms/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Kecilkan atau besarkan teks pada skrin."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Kecilkan"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Besarkan"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Teks contoh"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Ahli Sihir Oz yang Menakjubkan"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Bab 11: Oz, Kota Zamrud yang Menakjubkan"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Mesti kurang daripada <xliff:g id="NUMBER_1">%d</xliff:g> digit</item>
       <item quantity="one">Mesti kurang daripada <xliff:g id="NUMBER_0">%d</xliff:g> digit</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Mesti mengandungi angka 0-9 sahaja"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Pentadbir peranti tidak membenarkan penggunaan PIN terbaharu"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"PIN lazim disekat oleh pentadbir IT anda. Cuba PIN yang lain."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Tidak boleh menyertakan aksara yang tidak sah"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Mesti mengandungi sekurang-kurangnya <xliff:g id="COUNT">%d</xliff:g> aksara bukan huruf</item>
       <item quantity="one">Mesti mengandungi sekurang-kurangnya 1 aksara bukan huruf</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Mesti mengandungi sekurang-kurangnya <xliff:g id="COUNT">%d</xliff:g> aksara bukan angka</item>
+      <item quantity="one">Mesti mengandungi sekurang-kurangnya 1 aksara bukan angka</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Pentadbir peranti tidak membenarkan penggunaan kata laluan terbaharu"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Kata laluan lazim disekat oleh pentadbir IT anda. Cuba kata laluan yang lain."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Angka menaik, menurun atau jujukan berulang tidak dibenarkan"</string>
@@ -847,7 +849,7 @@
     <string name="wifi_notify_open_networks" msgid="4782239203624619655">"Pemberitahuan rangkaian terbuka"</string>
     <string name="wifi_notify_open_networks_summary" msgid="1383681260705466715">"Beritahu apabila rangkaian awam berkualiti tinggi tersedia"</string>
     <string name="wifi_wakeup" msgid="4963732992164721548">"Hidupkan Wi-Fi secara automatik"</string>
-    <string name="wifi_wakeup_summary" msgid="1152699417411690">"Wi-Fi akan dihidupkan kembali berdekatan dengan rangkaian disimpan yang berkualiti tinggi, seperti rangkaian rumah"</string>
+    <string name="wifi_wakeup_summary" msgid="1152699417411690">"Wi-Fi akan dihidupkan kembali apabila berdekatan dengan rangkaian disimpan yang berkualiti tinggi, seperti rangkaian rumah"</string>
     <string name="wifi_wakeup_summary_no_location" msgid="3007457288587966962">"Tidak tersedia kerana lokasi dimatikan. Hidupkan "<annotation id="link">"lokasi"</annotation>"."</string>
     <string name="wifi_wakeup_summary_scanning_disabled" msgid="6820040651529910914">"Tidak tersedia kerana pengimbasan Wi-Fi dimatikan"</string>
     <string name="wifi_wakeup_summary_scoring_disabled" msgid="7067018832237903151">"Untuk menggunakan ciri, pilih pembekal penilaian rangkaian"</string>
@@ -878,7 +880,7 @@
     <string name="wifi_configure_settings_preference_summary_wakeup_off" msgid="286904094152909651">"Wi-Fi tidak dihidupkan kembali secara automatik"</string>
     <string name="wifi_access_points" msgid="1647976498906871869">"Rangkaian Wi-Fi"</string>
     <string name="wifi_menu_more_options" msgid="8318269834264035524">"Lagi pilihan"</string>
-    <string name="wifi_menu_p2p" msgid="4945665601551289791">"Wi-Fi Langsung"</string>
+    <string name="wifi_menu_p2p" msgid="4945665601551289791">"Wi-Fi Direct"</string>
     <string name="wifi_menu_scan" msgid="9082691677803181629">"Imbas"</string>
     <string name="wifi_menu_advanced" msgid="5984484498045511072">"Terperinci"</string>
     <string name="wifi_menu_configure" msgid="52192491120701266">"Konfigurasikan"</string>
@@ -925,7 +927,7 @@
     <string name="wifi_ap_choose_auto" msgid="7927637960569365785">"Automatik"</string>
     <string name="wifi_ap_choose_2G" msgid="43198403259714736">"Jalur 2.4 GHz"</string>
     <string name="wifi_ap_choose_5G" msgid="2624859713183683146">"Jalur 5.0 GHz"</string>
-    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"Lajur 5.0 GHz diutamakan"</string>
+    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"Jalur 5.0 GHz diutamakan"</string>
     <string name="wifi_ap_2G" msgid="5793110086517338494">"2.4 GHz"</string>
     <string name="wifi_ap_5G" msgid="4584892544393675403">"5.0 GHz"</string>
     <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"Pilih sekurang-kurangnya satu jalur untuk tempat liputan Wi-Fi:"</string>
@@ -1038,7 +1040,7 @@
     <string name="wifi_dns2" msgid="1905876166783761641">"DNS 2"</string>
     <string name="wifi_gateway" msgid="7455334454444443397">"Get laluan"</string>
     <string name="wifi_network_prefix_length" msgid="1941206966133010633">"Panjang awalan rangkaian"</string>
-    <string name="wifi_p2p_settings_title" msgid="3213180637906683308">"Wi-Fi Langsung"</string>
+    <string name="wifi_p2p_settings_title" msgid="3213180637906683308">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_device_info" msgid="4717490498956029237">"Maklumat peranti"</string>
     <string name="wifi_p2p_persist_network" msgid="1110453878886476660">"Ingat sambungan ini"</string>
     <string name="wifi_p2p_menu_search" msgid="8207638860263805291">"Mencari peranti"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mudah alih"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Jika Wi-Fi tidak tersedia, gunakan rangkaian mudah alih"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Jika rangkaian mudah alih tidak tersedia, gunakan Wi-Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Panggil melalui Wi‑Fi. Jika Wi-Fi terputus, panggilan akan ditamatkan."</string>
@@ -2044,7 +2049,7 @@
     <string name="feature_flags_dashboard_title" msgid="3153034144122754381">"Bendera ciri"</string>
     <string name="talkback_title" msgid="3717960404234260050">"Talkback"</string>
     <string name="talkback_summary" msgid="6602857105831641574">"Pembaca skrin terutamanya untuk orang yang buta dan rabun"</string>
-    <string name="select_to_speak_summary" msgid="7514180457557735421">"Ketik item pada skrn anda untuk mendengar item itu dibaca"</string>
+    <string name="select_to_speak_summary" msgid="7514180457557735421">"Ketik item pada skrin anda untuk mendengar item itu dibaca"</string>
     <string name="accessibility_captioning_title" msgid="5878371993023439642">"Kapsyen"</string>
     <string name="accessibility_screen_magnification_title" msgid="7250949681883917360">"Pembesaran"</string>
     <string name="accessibility_screen_magnification_gestures_title" msgid="9199287875401817974">"Besarkan dengan tiga ketikan"</string>
@@ -3157,7 +3162,7 @@
     <string name="emergency_tone_vibrate" msgid="5020068066905681181">"Getaran"</string>
     <string name="boot_sounds_title" msgid="7583926202411353620">"Bunyi semasa kuasa dihidupkan"</string>
     <string name="live_caption_title" msgid="7926591158657997051">"Sari Kata Langsung"</string>
-    <string name="live_caption_summary" msgid="9064771862352393125">"Kapsyen media automatik"</string>
+    <string name="live_caption_summary" msgid="9064771862352393125">"Sari kata media automatik"</string>
     <string name="zen_mode_settings_summary_off" msgid="6929319200478424962">"Jangan sekali-kali"</string>
     <plurals name="zen_mode_settings_summary_on" formatted="false" msgid="6061723291126091396">
       <item quantity="other"><xliff:g id="ON_COUNT">%d</xliff:g> didayakan</item>
@@ -4469,7 +4474,7 @@
     <string name="privacy_dashboard_summary" msgid="7916431309860824945">"Kebenaran, aktiviti akaun, data peribadi"</string>
     <string name="contextual_card_dismiss_remove" msgid="1750420285615827309">"Alih keluar"</string>
     <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"Simpan"</string>
-    <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"Alih keluarkan cadangan ini?"</string>
+    <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"Alih keluar cadangan ini?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"Cadangan dialih keluar"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"Buat asal"</string>
     <string name="low_storage_summary" msgid="4562224870189133400">"Storan tinggal sedikit. <xliff:g id="PERCENTAGE">%1$s</xliff:g> digunakan - <xliff:g id="FREE_SPACE">%2$s</xliff:g> kosong"</string>
diff --git a/tests/CarDeveloperOptions/res/values-my/arrays.xml b/tests/CarDeveloperOptions/res/values-my/arrays.xml
index c87c35c..9fbddfa 100644
--- a/tests/CarDeveloperOptions/res/values-my/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-my/arrays.xml
@@ -29,8 +29,25 @@
     <item msgid="5194868215515664953">"ပစိဖိတ်"</item>
     <item msgid="7044520255415007865">"အားလုံး"</item>
   </string-array>
-    <!-- no translation found for screen_timeout_entries:0 (8596143519087753804) -->
-    <!-- no translation found for dream_timeout_entries:7 (8271452751594598661) -->
+  <string-array name="screen_timeout_entries">
+    <item msgid="8596143519087753804">"၁၅ စက္ကန့်"</item>
+    <item msgid="772029947136115322">"စက္ကန့် ၃၀"</item>
+    <item msgid="8743663928349474087">"၁ မိနစ်"</item>
+    <item msgid="1506508631223164814">"၂ မိနစ်"</item>
+    <item msgid="8664703938127907662">"၅ မိနစ်"</item>
+    <item msgid="5827960506924849753">"၁၀ မိနစ်"</item>
+    <item msgid="6677424950124253938">"၃၀ မိနစ်"</item>
+  </string-array>
+  <string-array name="dream_timeout_entries">
+    <item msgid="6487043225269853023">"ဘယ်တော့မှ"</item>
+    <item msgid="2517785806387977252">"၁၅ စက္ကန့်"</item>
+    <item msgid="6347954399441173672">"စက္ကန့် ၃၀"</item>
+    <item msgid="4858305253279921789">"၁ မိနစ်"</item>
+    <item msgid="8109273437140044073">"၂ မိနစ်"</item>
+    <item msgid="2788593551142462622">"၅ မိနစ်"</item>
+    <item msgid="8012672183888404961">"၁၀ မိနစ်"</item>
+    <item msgid="8271452751594598661">"မိနစ် ၃၀"</item>
+  </string-array>
   <string-array name="lock_after_timeout_entries">
     <item msgid="2232921187970351881">"ချက်ချင်း"</item>
     <item msgid="2038544972632026612">"၅ စက္ကန့်"</item>
@@ -42,17 +59,47 @@
     <item msgid="811192536981678974">"၁၀ မိနစ်"</item>
     <item msgid="7258394417241706272">"၃၀ မိနစ်"</item>
   </string-array>
-    <!-- no translation found for entries_font_size:0 (2340391964816059553) -->
-    <!-- no translation found for entries_font_size:0 (6490061470416867723) -->
-    <!-- no translation found for entries_font_size:2 (1714184661981538355) -->
-    <!-- no translation found for entries_font_size:2 (1678068858001018666) -->
-    <!-- no translation found for wifi_status:3 (5848277343965362748) -->
-    <!-- no translation found for wifi_status_with_ssid:1 (6816207058895999545) -->
-    <!-- no translation found for wifi_status_with_ssid:3 (7547609081339573756) -->
-    <!-- no translation found for wifi_status_with_ssid:4 (5145158315060185414) -->
+  <string-array name="entries_font_size">
+    <item msgid="2340391964816059553">"သေး"</item>
+    <item msgid="591935967183159581">"မူရင်း"</item>
+    <item msgid="1714184661981538355">"ကြီး"</item>
+    <item msgid="6195563047686707484">"အကြီးဆုံး"</item>
+  </string-array>
+  <string-array name="wifi_status">
+    <item msgid="1304883790721412351"></item>
+    <item msgid="4157625910392775808">"စကင်ပြုလုပ်နေပြီ"</item>
+    <item msgid="5597394826455877834">"ချိတ်ဆက်နေသည်"</item>
+    <item msgid="5848277343965362748">"အထောက်အထားစိစစ်နေသည်…"</item>
+    <item msgid="3391238031431440676">"အိုင်ပီလိပ်စာရယူနေသည်"</item>
+    <item msgid="5257597310494000224">"ချိတ်ဆက်ထားသည်"</item>
+    <item msgid="8472497592913050396">"ဆိုင်းငံ့ထားသည်"</item>
+    <item msgid="1228072488815999109">"အဆက်အသွယ်ဖြတ်တောက်သည်"</item>
+    <item msgid="7253087004422991731">"ချိတ်ဆက်မှုပြတ်တောက်သည်"</item>
+    <item msgid="4169850917304751227">"မအောင်မြင်ပါ"</item>
+    <item msgid="6266658166690831131">"ပိတ်ဆို့ထား"</item>
+    <item msgid="4517230805854909775">"နှေးကွေးသောဆက်သွယ်မှုကို ယာယီရှောင်ရှားထားသည်"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="4853670665485437464"></item>
+    <item msgid="6816207058895999545">"ရှာဖွေနေသည်…"</item>
+    <item msgid="8058143476674427024">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> နှင့် ဆက်သွယ်နေပါသည်"</item>
+    <item msgid="7547609081339573756">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ဖြင့် အထောက်အထားစိစစ်နေသည်…"</item>
+    <item msgid="5145158315060185414">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> မှ အိုင်ပီလိပ်စာကို ရယူနေသည်…"</item>
+    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> နှင့် ဆက်သွယ်ထားပြီး"</item>
+    <item msgid="6600156231416890902">"ဆိုင်းငံ့ထားသည်"</item>
+    <item msgid="4133290864821295785">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>မှ ဆက်သွယ်မှုဖြတ်တောက်သွားသည်"</item>
+    <item msgid="3980154971187953257">"ချိတ်ဆက်မှုပြတ်တောက်သည်"</item>
+    <item msgid="2847316776634969068">"မအောင်မြင်ပါ"</item>
+    <item msgid="4390990424746035383">"ပိတ်ဆို့ထား"</item>
+    <item msgid="3618248791367063949">"နှေးကွေးသောဆက်သွယ်မှုကို ယာယီရှောင်ရှားထားသည်"</item>
+  </string-array>
     <!-- no translation found for wifi_tether_security:0 (5586343370515598801) -->
     <!-- no translation found for wifi_tether_security:1 (6136336549994615745) -->
-    <!-- no translation found for wifi_p2p_wps_setup:0 (5390235347963255303) -->
+  <string-array name="wifi_p2p_wps_setup">
+    <item msgid="5390235347963255303">"နှိပ်ရန်ခလုတ်"</item>
+    <item msgid="7401896200768713930">"တန်းတူစက်ပစ္စည်းမှပင်နံပါတ်"</item>
+    <item msgid="4526848028011846710">"ဤစက်မှပင်နံပါတ်"</item>
+  </string-array>
   <string-array name="wifi_p2p_status">
     <item msgid="8741947238021758201">"ချိတ်ဆက်ထားသည်"</item>
     <item msgid="983792611851499732">"ဖိတ်ခေါ်ထားပြီး"</item>
@@ -60,7 +107,12 @@
     <item msgid="4646663015449312554">"အသုံးပြုနိုင်သည်"</item>
     <item msgid="3230556734162006146">"စက်ကွင်းပြင်ပ"</item>
   </string-array>
-    <!-- no translation found for bluetooth_visibility_timeout_entries:1 (2759776603549270587) -->
+  <string-array name="bluetooth_visibility_timeout_entries">
+    <item msgid="8247986727324120082">"၂ မိနစ်"</item>
+    <item msgid="2759776603549270587">"၅ မိနစ်"</item>
+    <item msgid="167772676068860015">"၁ နာရီ"</item>
+    <item msgid="5985477119043628504">"ဘယ်တော့မှ ပိတ်မပစ်ရန်"</item>
+  </string-array>
   <string-array name="bluetooth_max_connected_audio_devices">
     <item msgid="3800257971619063588">"စနစ်မူရင်းကို အသုံးပြုရန်− <xliff:g id="DEFAULT_BLUETOOTH_MAX_CONNECTED_AUDIO_DEVICES">%1$d</xliff:g>"</item>
     <item msgid="8572230405241423895">"၁"</item>
@@ -69,8 +121,13 @@
     <item msgid="1644506614010085798">"၄"</item>
     <item msgid="3132506679404897150">"၅"</item>
   </string-array>
-    <!-- no translation found for wifi_signal:1 (7882129634982603782) -->
-    <!-- no translation found for wifi_signal:4 (999948812884919584) -->
+  <string-array name="wifi_signal">
+    <item msgid="1709949377823900951">"ညံ့သည်"</item>
+    <item msgid="7882129634982603782">"ညံ့သည်"</item>
+    <item msgid="6457357501905996224">"အတန်အသင့်"</item>
+    <item msgid="405271628162918841">"ကောင်းသည်"</item>
+    <item msgid="999948812884919584">"အလွန်ကောင်းသည်"</item>
+  </string-array>
   <string-array name="data_usage_data_range">
     <item msgid="8986775481492954015">"နောက်ဆုံး ရက် ၃၀"</item>
     <item msgid="3211287705232736964">"သုံးစွဲမှု စက်ဝန်း သတ်မှတ်ရန်..."</item>
@@ -106,7 +163,10 @@
     <item msgid="7330627471456865502">"MSCHAPV2"</item>
     <item msgid="6255179395132581882">"GTC"</item>
   </string-array>
-    <!-- no translation found for wifi_ip_settings:1 (4377002609760712163) -->
+  <string-array name="wifi_ip_settings">
+    <item msgid="2717196390555072244">"DHCP"</item>
+    <item msgid="4377002609760712163">"ပုံသေ"</item>
+  </string-array>
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"မရှိ"</item>
     <item msgid="1464741437353223198">"ကိုယ်တိုင်ထည့်သွင်းခြင်း"</item>
@@ -226,11 +286,73 @@
     <item msgid="1165623660533024666">"နောက်ခံမှာ အလုပ်လုပ်ပါ"</item>
     <item msgid="6423861043647911030">"အများသုံးစွဲနိုင်မှု အသံ"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:3 (7836406246005211990) -->
-    <!-- no translation found for app_ops_labels:4 (3951439024549922598) -->
-    <!-- no translation found for app_ops_labels:8 (3597797992398484655) -->
-    <!-- no translation found for app_ops_labels:20 (3037159047591081136) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"တည်နေရာ"</item>
+    <item msgid="6656077694190491067">"တည်နေရာ"</item>
+    <item msgid="8790228218278477369">"တည်နေရာ"</item>
+    <item msgid="7836406246005211990">"တုန်ခါရန်"</item>
+    <item msgid="3951439024549922598">"အဆက်အသွယ်များ ဖတ်ရန်"</item>
+    <item msgid="8802152411647068">"အဆက်အသွယ်များပြင်ဆင်ရန်"</item>
+    <item msgid="229544934599698735">"ခေါ်ဆိုထားသော မှတ်တမ်းကိုဖတ်ရန်"</item>
+    <item msgid="7396102294405899613">"ခေါ်ဆိုထားသော မှတ်တမ်းကို ပြင်ဆင်ရန်"</item>
+    <item msgid="3597797992398484655">"ပြက္ခဒိန်ကို ဖတ်ရန်"</item>
+    <item msgid="2705975774250907343">"ပြက္ခဒိန်ပြင်ဆင်ရန်"</item>
+    <item msgid="4668747371441932697">"တည်နေရာ"</item>
+    <item msgid="1487578921720243646">"အကြောင်းကြားစာကို တင်ရန်"</item>
+    <item msgid="4636080349724146638">"တည်နေရာ"</item>
+    <item msgid="673510900286463926">"ဖုန်းခေါ်ရန်"</item>
+    <item msgid="542083422784609790">"စာတို/ရုပ်သံစာ ဖတ်ရန်"</item>
+    <item msgid="1033780373029588436">"စာတို/ရုပ်သံစာ ရေးရန်"</item>
+    <item msgid="5647111115517787488">"စာတို/ရုပ်သံစာ လက်ခံရန်"</item>
+    <item msgid="8591105601108455893">"စာတို/ရုပ်သံစာ လက်ခံရန်"</item>
+    <item msgid="7730995008517841903">"စာတို/ရုပ်သံစာ လက်ခံရန်"</item>
+    <item msgid="2613033109026626086">"စာတို/ရုပ်သံစာ လက်ခံရန်"</item>
+    <item msgid="3037159047591081136">"SMS/MMS ပို့ရန်"</item>
+    <item msgid="4726682243833913568">"စာတို/ရုပ်သံစာ ဖတ်ရန်"</item>
+    <item msgid="6555678522277865572">"စာတို/ရုပ်သံစာ ရေးရန်"</item>
+    <item msgid="6981734935578130884">"ဆက်တင်များ ပြင်ဆင်ရန်"</item>
+    <item msgid="8705854389991425629">"အပေါ်မှ ဆွဲရန်"</item>
+    <item msgid="5861356020344153651">"အကြောင်းကြားချက်များအား အသုံးပြုခွင့်"</item>
+    <item msgid="78432174621628659">"ကင်မရာ"</item>
+    <item msgid="3986116419882154794">"အသံဖမ်းရန်"</item>
+    <item msgid="4516840825756409490">"အသံဖွင့်ရန်"</item>
+    <item msgid="6811712502798183957">"နောက်ခံမှတ်တမ်း ဖတ်ရန်"</item>
+    <item msgid="2780369012602289114">"နောက်ခံမှတ်တမ်းပြင်ဆင်ရန်"</item>
+    <item msgid="2331359440170850868">"မီဒီယာခလုတ်များ"</item>
+    <item msgid="6133599737122751231">"အသံပြတ်သားအောင်ချိန်ရန်"</item>
+    <item msgid="6844485713404805301">"ပင်မအသံအတိုးအကျယ်"</item>
+    <item msgid="1600379420669104929">"စကားသံအတိုးအကျယ်"</item>
+    <item msgid="6296768210470214866">"ဖုန်းမြည်သံ အတိုးအကျယ်"</item>
+    <item msgid="510690696071629241">"မီဒီယာ အသံအတိုးအကျယ်"</item>
+    <item msgid="406861638631430109">"နှိုးစက်အသံ အတိုးအကျယ်"</item>
+    <item msgid="4715864795872233884">"အကြောင်းကြားချက်သံ ပမာဏ"</item>
+    <item msgid="2311478519251301183">"ဘလူးတုသ်သံအတိုးအကျယ်"</item>
+    <item msgid="5133991377896747027">"ဖွင့်လျှက်ထားရှိရန်"</item>
+    <item msgid="2464189519136248621">"တည်နေရာ"</item>
+    <item msgid="2062677934050803037">"တည်နေရာ"</item>
+    <item msgid="1735171933192715957">"သုံးစွဲမှု စာရင်းအင်းများကို ရယူရန်"</item>
+    <item msgid="1014093788778383554">"မိုက်ခရိုဖုန်း အသံတိတ်/မတိတ်ရန်"</item>
+    <item msgid="4199297950608622850">"အမည်ကို ပြပါ"</item>
+    <item msgid="2527962435313398821">"ပရိုဂျက် မီဒီယာ"</item>
+    <item msgid="5117506254221861929">"VPN ကို စဖွင့်သုံးပါ"</item>
+    <item msgid="8291198322681891160">"နောက်ခံရေးပါ"</item>
+    <item msgid="7106921284621230961">"ဖွဲ့စည်းပုံကို ကူညီပါ"</item>
+    <item msgid="4496533640894624799">"မျက်နှာပြင်ကို ကူညီပါ"</item>
+    <item msgid="2598847264853993611">"ဖုန်း အခြေအနေကို ဖတ်ပါ"</item>
+    <item msgid="9215610846802973353">"အသံမေးလ် ထည့်ပါ"</item>
+    <item msgid="9186411956086478261">"ငုံခြင်းကို သုံးပါ"</item>
+    <item msgid="6884763100104539558">"အထွက် ခေါ်ဆိုမှုများကို စီမံဆောင်ရွက်ပါ"</item>
+    <item msgid="125513972170580692">"လက်ဗွေ"</item>
+    <item msgid="2556071024281275619">"ခန္ဓာကိုယ် အာရုံခံကိရိယာများ"</item>
+    <item msgid="617168514928339387">"ဆဲလ် ထုတ်လွှင့်မှုများကို ဖတ်ပါ"</item>
+    <item msgid="7134693570516523585">"တည်နေရာကို အတုဖန်တီးပါ"</item>
+    <item msgid="7224489175375229399">"သိုလှောင်ခန်းကို ဖတ်ပါ"</item>
+    <item msgid="8472735063903258202">"သိုလှောင်ခန်းကို ရေးပါ"</item>
+    <item msgid="4069276819909595110">"မျက်နှာပြင်ကို ဖွင့်ပါ"</item>
+    <item msgid="1228338896751121025">"အကောင့်များကို ရယူပါ"</item>
+    <item msgid="3181581793459233672">"နောက်ခံမှာ အလုပ်လုပ်ပါ"</item>
+    <item msgid="2340936043025374076">"အများသုံးစွဲနိုင်မှု အသံ"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"အတို"</item>
     <item msgid="4816511817309094890">"အတော်အသင့်"</item>
@@ -247,7 +369,13 @@
     <item msgid="4627069151979553527">"Cursiv"</item>
     <item msgid="6896773537705206194">"စာလုံးကြီး ဆိုဒ်သေးများ"</item>
   </string-array>
-    <!-- no translation found for captioning_font_size_selector_titles:3 (2784236342175159295) -->
+  <string-array name="captioning_font_size_selector_titles">
+    <item msgid="1680223634161592855">"အလွန်သေးရန်"</item>
+    <item msgid="5091603983404027034">"သေး"</item>
+    <item msgid="176844712416932112">"ပုံမှန်"</item>
+    <item msgid="2784236342175159295">"ကြီး"</item>
+    <item msgid="218913203203160606">"အလွန်ကြီးရန်"</item>
+  </string-array>
   <string-array name="captioning_edge_type_selector_titles">
     <item msgid="3865198759294188069">"မူရင်း"</item>
     <item msgid="6488643537808152001">"မရှိ"</item>
@@ -262,7 +390,14 @@
     <item msgid="1874668269931014581">"၇၅%"</item>
     <item msgid="6462911487571123954">"၁၀၀%"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"အက်ပ်ပုံသေများကို သုံးရန်"</item>
+    <item msgid="8611890312638868524">"အမည်းပေါ်အဖြူ"</item>
+    <item msgid="5891360837786277638">"အဖြူပေါ်အမည်း"</item>
+    <item msgid="2798457065945456853">"အမည်းပေါ်အဝါ"</item>
+    <item msgid="5799049811524553967">"အပြာပေါ်အဝါ"</item>
+    <item msgid="3673930830658169860">"စိတ်ကြိုက်"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"PPTP VPN"</item>
     <item msgid="1349760781118368659">"ကြိုတင် ပေးထားတဲ့ ကီးပါရှိသောL2TP/IPSec VPN"</item>
@@ -275,15 +410,32 @@
     <item msgid="2958623927055120839">"မရှိ"</item>
     <item msgid="1157046369795346308">"ကိုယ်တိုင်ထည့်သွင်းခြင်း"</item>
   </string-array>
-    <!-- no translation found for vpn_states:4 (9135049670787351881) -->
+  <string-array name="vpn_states">
+    <item msgid="5408915841694583740">"ချိတ်ဆက်မှုပြတ်တောက်သည်"</item>
+    <item msgid="8754480102834556765">"စတင်နေသည်"</item>
+    <item msgid="3351334355574270250">"ချိတ်ဆက်နေသည်"</item>
+    <item msgid="8303882153995748352">"ချိတ်ဆက်ထားသည်"</item>
+    <item msgid="9135049670787351881">"အချိန်ကုန်ပါပြီ"</item>
+    <item msgid="2124868417182583926">"မအောင်မြင်ပါ"</item>
+  </string-array>
   <string-array name="security_settings_premium_sms_values">
     <item msgid="1164265643455394443">"မေးပါ"</item>
     <item msgid="7718817231348607934">"ဘယ်တော့မှခွင့်မပြုပါ"</item>
     <item msgid="8184570120217958741">"အမြဲခွင့်ပြုပါ"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"ပုံမှန်"</item>
+    <item msgid="5101233285497327432">"အတော်အသင့်"</item>
+    <item msgid="1555861583162930714">"နိမ့်"</item>
+    <item msgid="1719683776264798117">"အရေးပါ"</item>
+    <item msgid="1567326459340152525">"။"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"ပုံမှန်"</item>
+    <item msgid="6107138933849816768">"အတော်အသင့်"</item>
+    <item msgid="182695359839047859">"နိမ့်"</item>
+    <item msgid="8577246509202964244">"အရေးကြီး"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"တချိန်လုံး"</item>
     <item msgid="167418068739176448">"အသုံး အများဆုံး"</item>
diff --git a/tests/CarDeveloperOptions/res/values-my/config.xml b/tests/CarDeveloperOptions/res/values-my/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-my/config.xml
+++ b/tests/CarDeveloperOptions/res/values-my/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-my/strings.xml b/tests/CarDeveloperOptions/res/values-my/strings.xml
index d7c0f31..3716e91 100644
--- a/tests/CarDeveloperOptions/res/values-my/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-my/strings.xml
@@ -19,7 +19,7 @@
     <string name="yes" msgid="39117354665111159">"Yes"</string>
     <string name="no" msgid="4709057267400907161">"No"</string>
     <string name="create" msgid="5131953868544187847">"ဖန်တီးရန်"</string>
-    <string name="allow" msgid="128867119174713893">"ခွင့်ပြုပါ"</string>
+    <string name="allow" msgid="128867119174713893">"ခွင့်ပြုရန်"</string>
     <string name="deny" msgid="3998166389989144025">"ငြင်းပယ်ရန်"</string>
     <string name="device_info_default" msgid="1548919563979154348">"မသိ"</string>
     <plurals name="show_dev_countdown" formatted="false" msgid="3953785659137161981">
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"မျက်နှာပြင်ပေါ်ရှိ စာလုံးကို ပိုသေးအောင် သို့မဟုတ် ပိုကြီးအောင် လုပ်ပါ။"</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"ပိုသေးအောင် ပြုလုပ်ပါ"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"ပိုကြီးအောင် ပြုလုပ်ပါ"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"နမူနာ စာသား"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Oz ၏အံ့ဖွယ်ဝိဇ္ဇာ"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"အခန်းကြီး ၁၁ − Oz ၏အံ့ဖွယ် မြစိမ်းရောင်မြို့တော်"</string>
@@ -324,7 +323,7 @@
     <string name="date_and_time_settings_title_setup_wizard" msgid="1573030770187844365">"ရက်စွဲနှင့် အချိန် သတ်မှတ်ရန်"</string>
     <string name="date_and_time_settings_summary" msgid="4617979434474713417">"ရက်စွဲ အချိန် အချိန်ဇုန်နှင့် ပုံစံများအား သတ်မှတ်ရန်"</string>
     <string name="date_time_auto" msgid="2679132152303750218">"ကွန်ရက်က ပြသောအချိန် သုံးပါ"</string>
-    <string name="zone_auto_title" msgid="5500880975376882488">"ကွန်ရက်ကပြသော စံတော်ချိန် သုံးပါ"</string>
+    <string name="zone_auto_title" msgid="5500880975376882488">"ကွန်ရက်က ဖော်ပြထားသောအချိန်ဇုန်ကို အသုံးပြုရန်"</string>
     <string name="date_time_24hour_auto" msgid="7499659679134962547">"အသုံးပြုမည့် ဒေသဘာသာစကား၏စနစ်ကို သုံးရန်"</string>
     <string name="date_time_24hour_title" msgid="6209923858891621283">"၂၄-နာရီပုံစံ"</string>
     <string name="date_time_24hour" msgid="1265706705061608742">"၂၄-နာရီပုံစံကို အသုံးပြုမည်"</string>
@@ -364,7 +363,7 @@
     <string name="owner_info_settings_summary" msgid="4208702251226725583">"မရှိ"</string>
     <string name="owner_info_settings_status" msgid="8049975536717685126">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="COUNT_1">%2$d</xliff:g>"</string>
     <string name="owner_info_settings_edit_text_hint" msgid="2250029417257939706">"ဥပမာ၊ Joe ၏ Android"</string>
-    <string name="user_info_settings_title" msgid="1125111518759995748">"သုံးစွဲသူအကြောင်း"</string>
+    <string name="user_info_settings_title" msgid="1125111518759995748">"အသုံးပြုသူအကြောင်း"</string>
     <string name="show_profile_info_on_lockscreen_label" msgid="5204282771893683026">"သော့ခတ်ထားသောမျက်နှာပြင်ပေါ်သုံးစွဲသူ၏အကြောင်းပြရန်"</string>
     <string name="profile_info_settings_title" msgid="4855892878512562551">"ကိုယ်ရေးအချက်အလက်"</string>
     <string name="Accounts_settings_title" msgid="7901374987121953746">"အကောင့်များ"</string>
@@ -489,7 +488,7 @@
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"အိုး။ ဒါ အာရုံခံကိရိယာမဟုတ်ဘူး"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"သင့်ဖုန်း ကျောဘက်ရှိ အာရုံခံကိရိယာကို ထိပါ။ လက်ညှိုးကို အသုံးပြုပါ။"</string>
     <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"စာရင်းသွင်းမှု မပြီးစီးခဲ့ပါ"</string>
-    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"လက်ဗွေ ပေးသွင်းမှု ကန့်သတ်ချိန် ကုန်သွားပြီ။ ထပ်စမ်းကြည့်ပါ။"</string>
+    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"လက်ဗွေစာရင်းသွင်းမှု ကန့်သတ်ချိန် ကုန်သွားပြီ။ ထပ်စမ်းကြည့်ပါ။"</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"လက်ဗွေထည့်သွင်းမှု အဆင်မပြေပါ။ အခြားလက်ချောင်းကို သုံးပါ သို့မဟုတ် ထပ်စမ်းကြည့်ပါ။"</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"နောက်တစ်ခု ထည့်ရန်"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"ရှေ့သို့"</string>
@@ -544,7 +543,7 @@
     <string name="suggested_fingerprint_lock_settings_summary" product="tablet" msgid="8114514312665251311"></string>
     <string name="suggested_fingerprint_lock_settings_summary" product="device" msgid="8114514312665251311"></string>
     <string name="suggested_fingerprint_lock_settings_summary" product="default" msgid="8114514312665251311"></string>
-    <string name="lock_settings_picker_title" msgid="1034741644461982205">"မျက်နှာပြင်လော့ခ်ချနည်းရွေးရန်"</string>
+    <string name="lock_settings_picker_title" msgid="1034741644461982205">"ဖန်သားပြင်လော့ခ်"</string>
     <string name="lock_settings_picker_title_profile" msgid="5086594364428782115">"အလုပ် လော့ခ်ချခြင်းကို ရွေးပါ"</string>
     <string name="setup_lock_settings_picker_title" product="tablet" msgid="2429667472335773519">"သင့်တက်ဘလက်ကို ကာကွယ်ပါ"</string>
     <string name="setup_lock_settings_picker_title" product="device" msgid="4739290104106645233">"သင့်စက်ပစ္စည်းကို ကာကွယ်ပါ"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">ဂဏန်း <xliff:g id="NUMBER_1">%d</xliff:g> လုံးထက် နည်းရမည်</item>
       <item quantity="one">ဂဏန်း <xliff:g id="NUMBER_0">%d</xliff:g> လုံးထက် နည်းရမည်</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"ဂဏန်း ၀−၉ အထိသာ ပါဝင်ရပါမည်"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"စက်ပစ္စည်း၏ စီမံခန့်ခွဲသူသည် မကြာသေးမီက အသုံးပြုခဲ့သည့် ပင်နံပါတ်ကို သုံးခွင့်မပြုပါ"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"အသုံးပြုလေ့ရှိသော PIN များကို သင်၏ IT စီမံခန့်ခွဲသူက ပိတ်ထားသည်။ အခြား PIN တစ်ခုဖြင့် စမ်းကြည့်ပါ။"</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"၎င်းတွင် မမှန်ကန်သည့်စကားလုံးများ ပါဝင်၍မရပါ"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">အနည်းဆုံး စာလုံးငယ် <xliff:g id="COUNT">%d</xliff:g> လုံးပါဝင်ရမည်</item>
       <item quantity="one">အနည်းဆုံး စာလုံးငယ် ၁ လုံးပါဝင်ရမည်</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">ဂဏန်းမဟုတ်သော အက္ခရာ အနည်းဆုံး <xliff:g id="COUNT">%d</xliff:g> လုံးပါရမည်</item>
+      <item quantity="one">ဂဏန်းမဟုတ်သော အက္ခရာ အနည်းဆုံး ၁ လုံးပါရမည်</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"စက်ပစ္စည်းစီမံခန့်ခွဲသူသည် မကြာသေးမီက အသုံးပြုခဲ့သည့် စကားဝှက်ကို သုံးခွင့်မပြုပါ"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"အသုံးပြုလေ့ရှိသော စကားဝှက်များကို သင်၏ IT စီမံခန့်ခွဲသူက ပိတ်ထားသည်။ အခြား စကားဝှက်တစ်ခုဖြင့် စမ်းကြည့်ပါ။"</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"အစဉ်လိုက်ဖြစ်နေသော ဂဏန်း အငယ်မှအကြီး၊ အကြီးမှအငယ် သို့မဟုတ် ထပ်နေသည့် နံပါတ်စဉ်များကို ခွင့်မပြုပါ"</string>
@@ -887,7 +889,7 @@
     <string name="wifi_menu_forget" msgid="7561140554450163075">"ကွန်ရက်အား မေ့ရန်"</string>
     <string name="wifi_menu_modify" msgid="4080178040721021101">"ကွန်ယက်အား ပြင်ရန်"</string>
     <string name="wifi_empty_list_wifi_off" msgid="272877164691346240">"ရနိုင်သည့်ကွန်ရက်များကို မြင်ရန် Wi-Fi ဖွင့်ပါ"</string>
-    <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"ဝိုင်ဖိုင်ကွန်ယက်များရှာဖွေနေသည်"</string>
+    <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"Wi-Fi ကွန်ရက်များ ရှာဖွေနေသည်…"</string>
     <string name="wifi_empty_list_user_restricted" msgid="2341613007817352431">"သင့်မှာ Wi-Fi  ကွန်ရက်ကို ပြောင်းလဲရန် ခွင့်ပြုချက် မရှိပါ။"</string>
     <string name="wifi_more" msgid="3538241640407382185">"နောက်ထပ်"</string>
     <string name="wifi_setup_wps" msgid="6730131677695521321">"အလိုအလျောက် အစီအမံ (WPS)"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"မိုဘိုင်း"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Wi‑Fi မရနိုင်လျှင် မိုဘိုင်းကွန်ရက် သုံးပါ"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"မိုဘိုင်းကွန်ရက် မရနိုင်လျှင် Wi‑Fi သုံးပါ"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Wi-Fi သုံး၍ ခေါ်ဆိုသည်။ Wi‑Fi မရတော့လျှင် ခေါ်ဆိုမှု ပြီးသွားပါမည်။"</string>
@@ -1320,7 +1325,7 @@
     <string name="device_status" msgid="395318738663800026">"အခြေအနေ"</string>
     <string name="device_status_summary" product="tablet" msgid="8975790197766171710">"ဘက်ထရီ၊ ကွန်ယက်နှင့် တစ်ခြားအချက်အလက်၏ အခြေအနေများ"</string>
     <string name="device_status_summary" product="default" msgid="8282235230720651642">"ဖုန်းနံပါတ်၊ ထုတ်လွင့်မှု စသည်"</string>
-    <string name="storage_settings" msgid="7009733301485139652">"သိုလှောင်မှုများ"</string>
+    <string name="storage_settings" msgid="7009733301485139652">"သိုလှောင်ခန်း"</string>
     <string name="storage_settings_for_app" msgid="3028887232073069965">"သိုလှောင်ခန်းနှင့် ကက်ရှ်"</string>
     <string name="storage_usb_settings" msgid="4470138799276333403">"သိုလှောင်ခန်း"</string>
     <string name="storage_settings_title" msgid="7348362600789024415">"သိုလှောင်မှု ဆက်တင်များ"</string>
@@ -1701,7 +1706,7 @@
     <string name="settings_safetylegal_activity_unreachable" msgid="3541894966476445833">"သင့်တွင်ဒေတာချိတ်ဆက်မှု မရှိပါ။ ဤအချက်အလက်ကိုကြည့်ရန် အင်တာနက်ချိတ်ဆက်မှုရှိသည့် မည်သည့်ကွန်ပျူတာမှမဆို %s ထံသို့ သွားပါ။"</string>
     <string name="settings_safetylegal_activity_loading" msgid="7680998654145172">"ဖွင့်နေဆဲ…"</string>
     <string name="confirm_device_credential_use_alternate_method" msgid="1279869272895739941">"အခြားနည်းလမ်း သုံးရန်"</string>
-    <string name="lockpassword_choose_your_screen_lock_header" msgid="6283518876031424798">"မျက်နှာပြင်လော့ခ် သတ်မှတ်ခြင်း"</string>
+    <string name="lockpassword_choose_your_screen_lock_header" msgid="6283518876031424798">"ဖန်သားပြင်လော့ခ် သတ်မှတ်ခြင်း"</string>
     <string name="lockpassword_choose_your_password_message" msgid="2838273977481046536">"လုံခြုံရေးအတွက် စကားဝှက် သတ်မှတ်ပါ"</string>
     <string name="lockpassword_choose_your_password_header_for_fingerprint" msgid="4921343500484160894">"လက်ဗွေသုံးရန် စကားဝှက်သတ်မှတ်ပါ"</string>
     <string name="lockpassword_choose_your_pattern_header_for_fingerprint" msgid="314870151462139417">"လက်ဗွေသုံးရန် ပုံစံသတ်မှတ်ပါ"</string>
@@ -1794,7 +1799,7 @@
     <string name="advanced_settings" msgid="6282069364060968122">"အဆင့်မြင့်အပြင်အဆင်များ"</string>
     <string name="advanced_settings_summary" msgid="5912237062506771716">"ပိုမိုပြီးရွေးချယ်နိုင်သော အပြင်အဆင်များ ရရှိခြင်း"</string>
     <string name="application_info_label" msgid="3886253474964599105">"အက်ပ်အချက်အလက်များ"</string>
-    <string name="storage_label" msgid="1109537840103290384">"သိုလှောင်မှုများ"</string>
+    <string name="storage_label" msgid="1109537840103290384">"သိုလှောင်ခန်း"</string>
     <string name="auto_launch_label" msgid="47089737922907379">"မူရင်းအတိုင်းဖွင့်ရန်"</string>
     <string name="auto_launch_label_generic" msgid="7865828543459493308">"မူရင်းအတိုင်း"</string>
     <string name="screen_compatibility_label" msgid="3638271673726075815">"ဖန်သားပြင် လိုက်ဖက်မှု"</string>
@@ -1824,7 +1829,7 @@
     <string name="app_factory_reset" msgid="8718986000278776272">"အဆင့်မြင့်မှုများကိုဖယ်ထုတ်မည်လား?"</string>
     <string name="auto_launch_enable_text" msgid="3372898942144027341">"မူလကတည်းမှ တစ်ချို့လုပ်ဆောင်ချက်များအတွက် ဤအပလီကေးရှင်းကို ဖွင့်ရန်သင်ရွေး ချယ်ထားပြီးသားဖြစ်သည်"</string>
     <string name="always_allow_bind_appwidgets_text" msgid="2286211654774611037">"၀ဒ်ဂျက်များ ဖန်တီးရန်နှင့် ၎င်းတို့၏ အချက်အလက်များရယူရန် ဤအပလီကေးရှင်းကို ခွင့်ပြုကြောင်း သင်ရွေးချယ်ထားသည်။"</string>
-    <string name="auto_launch_disable_text" msgid="8560921288036801416">"မူရင်း သတ်မှတ်ထားခြင်းမရှိ"</string>
+    <string name="auto_launch_disable_text" msgid="8560921288036801416">"မူရင်း သတ်မှတ်မထားပါ။"</string>
     <string name="clear_activities" msgid="2068014972549235347">"မူရင်းများကို ရှင်းလင်းခြင်း"</string>
     <string name="screen_compatibility_text" msgid="1768064020294301496">"သင့်ဖန်သားပြင်အတွက် ဤအပ်ပလီကေးရှင်းမှာ လိုက်ဖက်အောင် လုပ်ထားခြင်း မရှိနိုင်ပါ။ ဤနေရာတွင် သင့်ဖန်သားပြင်နှင့်ကိုက်ညီအောင် ထိန်းချုပ်နိုင်ပါသည်။"</string>
     <string name="ask_compatibility" msgid="6687958195768084807">"ဖွင့်သည့်အခါ မေးမြန်းရန်။"</string>
@@ -1997,7 +2002,7 @@
     <string name="user_dict_settings_edit_dialog_title" msgid="6492621665762797309">"စာလုံးကို ပြင်ဆင်မည်"</string>
     <string name="user_dict_settings_context_menu_edit_title" msgid="4577283176672181497">"ပြင်ဆင်ရန်"</string>
     <string name="user_dict_settings_context_menu_delete_title" msgid="670470172230144069">"ဖျက်ရန်"</string>
-    <string name="user_dict_settings_empty_text" msgid="2774939221998982609">"အသုံးပြုသူအဘိဓာန်တွင် သင့်စကားလုံးများမရှိပါ။ စကားလုံးတစ်ခု ပေါင်းထည့်ရန်၊ (+) ခလုတ်ကိုနှိပ်ပါ။"</string>
+    <string name="user_dict_settings_empty_text" msgid="2774939221998982609">"အသုံးပြုသူအဘိဓာန်တွင် စကားလုံးများမရှိပါ။ စကားလုံးတစ်ခု ပေါင်းထည့်ရန်၊ (+) ခလုတ်ကိုနှိပ်ပါ။"</string>
     <string name="user_dict_settings_all_languages" msgid="8839702015353418176">"ဘာသာစကားအားလုံးအတွက်"</string>
     <string name="user_dict_settings_more_languages" msgid="8345984308635521364">"ဘာသာစကားပိုများများ…"</string>
     <string name="testing" msgid="4255916838792186365">"စမ်းသပ်မှု"</string>
@@ -2077,7 +2082,7 @@
     <string name="accessibility_timeout_1min" msgid="5019003178551730551">"၁ မိနစ်"</string>
     <string name="accessibility_timeout_2mins" msgid="4124259290444829477">"၂ မိနစ်"</string>
     <string name="accessibility_content_timeout_preference_title" msgid="5160746882250939464">"ဖတ်ရန် အချိန်"</string>
-    <string name="accessibility_control_timeout_preference_title" msgid="2771808346038759474">"တစ်ခုခုလုပ်ဆောင်ရန် အချိန်"</string>
+    <string name="accessibility_control_timeout_preference_title" msgid="2771808346038759474">"လုပ်ဆောင်ရန် အချိန်"</string>
     <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"သင် ဖတ်ရှုရမည့် မက်ဆေ့ဂျ်များအား ပြရမည့် ကြာချိန် ရွေးပါ။ သို့သော်လည်း ယာယီသာ မြင်ရပါမည်။\n\nဤဆက်တင်ကို အက်ပ်အားလုံးတွင် အသုံးမပြုနိုင်ပါ။"</string>
     <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"တစ်ခုခုလုပ်ဆောင်ရန် မေးသည့် မက်ဆေ့ဂျ်များ ပြရမည့်ကြာချိန် ရွေးပါ၊ သို့သော်လည်း ယာယီသာ မြင်ရပါမည်။\n\nအက်ပ်အားလုံးတွင် ဤဆက်တင် အသုံးမပြုနိုင်ပါ။"</string>
     <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"ထိထားရန် လိုအပ်ချိန်"</string>
@@ -2273,13 +2278,13 @@
     <string name="battery_tip_smart_battery_title" product="device" msgid="7419448992583346364">"စက်ပစ္စည်း၏ ဘက်ထရီသက်တမ်းကို ပိုကောင်းလာအောင်လုပ်ခြင်း"</string>
     <string name="battery_tip_smart_battery_summary" msgid="5344821856478265778">"\'ဘက်ထရီ စီမံခန့်ခွဲမှုစနစ်\' ကို ဖွင့်ပါ"</string>
     <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"\'ဘက်ထရီ အားထိန်း\' ကို ဖွင့်ရန်"</string>
-    <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"ဘက်ထရီသည် ပုံမှန်ထက် စောလျင်စွာ ကုန်နိုင်ပါသည်"</string>
+    <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"ပုံမှန်ထက် ဘက်ထရီ အကုန်မြန်နိုင်သည်"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"\'ဘက်ထရီ အားထိန်း\' ကို ဖွင့်ထားသည်"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"အချို့သော ဝန်ဆောင်မှုများကို ကန့်သတ်ထားနိုင်ပါသည်"</string>
     <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"ဖုန်းကို ပုံမှန်ထက် ပိုသုံးထားသည်"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"တက်ဘလက်ကို ပုံမှန်ထက် ပိုသုံးထားသည်"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"စက်ပစ္စည်းကို ပုံမှန်ထက် ပိုသုံးထားသည်"</string>
-    <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"ဘက်ထရီသည် ပုံမှန်ထက် စောလျင်စွာ ကုန်နိုင်ပါသည်"</string>
+    <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"ပုံမှန်ထက် ဘက်ထရီ အကုန်မြန်နိုင်သည်"</string>
     <string name="battery_tip_dialog_message" product="default" msgid="8453700079047810964">"သင့်ဖုန်းကို ပုံမှန်ထက် ပိုသုံးထားသည်။ သင့်ဘက်ထရီသည် ခန့်မှန်းထားသည်ထက် စောလျင်စွာ ကုန်နိုင်ပါသည်။\n\nအားအပြည့်သွင်းပြီးသည့် အချိန်မှစ၍ သင် အသုံးအများဆုံးအက်ပ်−"</string>
     <string name="battery_tip_dialog_message" product="tablet" msgid="6489981050645444068">"သင့်တက်ဘလက်ကို ပုံမှန်ထက် ပိုသုံးထားသည်။ သင့်ဘက်ထရီသည် ခန့်မှန်းထားသည်ထက် စောလျင်စွာ ကုန်နိုင်ပါသည်။\n\nအားအပြည့်သွင်းပြီးသည့် အချိန်မှစ၍ သင် အသုံးအများဆုံးအက်ပ်−"</string>
     <string name="battery_tip_dialog_message" product="device" msgid="6348123094674390337">"သင့်စက်ပစ္စည်းကို ပုံမှန်ထက် ပိုသုံးထားသည်။ သင့်ဘက်ထရီသည် ခန့်မှန်းထားသည်ထက် စောလျင်စွာ ကုန်နိုင်ပါသည်။\n\nအားအပြည့်သွင်းပြီးသည့် အချိန်မှစ၍ သင် အသုံးအများဆုံးအက်ပ်−"</string>
@@ -2596,7 +2601,7 @@
     <string name="work_mode_label" msgid="6845849194740195757">"အလုပ်ပရိုဖိုင်"</string>
     <string name="work_mode_on_summary" msgid="1682781113156323592">"သင်၏ အဖွဲ့အစည်းက စီမံခန့်ခွဲထားပါသည်"</string>
     <string name="work_mode_off_summary" msgid="1688885392211178315">"အက်ပ်နှင့် အကြောင်းကြားချက်များကို ပိတ်ထားသည်"</string>
-    <string name="remove_managed_profile_label" msgid="4625542553784793536">"အလုပ် ပရိုဖိုင်ကို ဖယ်ရှားပစ်ရန်"</string>
+    <string name="remove_managed_profile_label" msgid="4625542553784793536">"အလုပ်ပရိုဖိုင် ဖယ်ရှားရန်"</string>
     <string name="background_data" msgid="8275750862371471171">"နောက်ခံတွင်အသုံးပြုသောဒေတာ"</string>
     <string name="background_data_summary" msgid="799640633948841990">"အက်ပ်များက ဒေတာ ပို့၊ လက်ခံ၊ စင့်ခ် အချိန်မရွေးလုပ်နိုင်သည်"</string>
     <string name="background_data_dialog_title" msgid="8306650658158895976">"နောက်ခံဒေတာဖျက်မလား"</string>
@@ -2883,7 +2888,7 @@
     <string name="user_confirm_remove_self_title" msgid="6739480453680217543">"သင့်ကို ဖယ်ရှားမလား။"</string>
     <string name="user_confirm_remove_title" msgid="1034498514019462084">"ဤအသုံးပြုသူကို ဖျက်မလား။"</string>
     <string name="user_profile_confirm_remove_title" msgid="6138684743385947063">"ဒီပရိုဖိုင်ကို ဖယ်ရှားရမလား?"</string>
-    <string name="work_profile_confirm_remove_title" msgid="3168910958076735800">"အလုပ်ပရိုဖိုင် ဖယ်မည်လား?"</string>
+    <string name="work_profile_confirm_remove_title" msgid="3168910958076735800">"အလုပ်ပရိုဖိုင် ဖယ်ရှားမလား။"</string>
     <string name="user_confirm_remove_self_message" product="tablet" msgid="2889456786320157545">"ဤ တက်ဘလက်ပေါ်မှ သင့်နေရာနှင့် အချက်အလက်များသည် ပျောက်သွားလိမ့်မည်။ ဤလုပ်ဆောင်ချက်ကို သင် နောက်ပြန်သွား၍ မရနိုင်ပါ။"</string>
     <string name="user_confirm_remove_self_message" product="default" msgid="8441729423565705183">"ဤဖုန်းပေါ်မှ သင့်နေရာနှင့် အချက်အလက်များသည် ပျောက်သွားလိမ့်မည်။ ဤလုပ်ဆောင်ချက်ကို သင် နောက်ပြန်သွား၍ မရနိုင်ပါ။"</string>
     <string name="user_confirm_remove_message" msgid="5202150470271756013">"အက်ပ်များ အားလုံး နှင့် ဒေတာကို ဖျက်သွားမည်။"</string>
@@ -2919,8 +2924,8 @@
     <string name="nfc_payment_favor_default" msgid="7555356982142464260">"အမြဲတမ်း"</string>
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"အခြား ငွေပေးချေရေး အက်ပ်ပွင့်နေချိန်မှ လွဲပြီး"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"တို့ထိပြီးပေးရန် နေရာတွင် အောက်ပါနည်းဖြင့် ပေးပါ-"</string>
-    <string name="nfc_how_it_works_title" msgid="6531433737926327904">"မှတ်တိုင်တွင် ငွေချေခြင်း"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"ငွေပေးချေရေး အက်ပ်ကို သတ်မှတ်ပေးပါ။ ၎င်းနောက်မှာ သင့်ဖုန်း၏ နောက်ကျောကို ချိတ်ဆက်ရန် မလိုသည့် သင်္ကေတ ပါရှိသော တာမီနယ် တခုခုဆီသို့ ကပ်ပေးလိုက်ရုံပါပဲ။"</string>
+    <string name="nfc_how_it_works_title" msgid="6531433737926327904">"ငွေချေစက်တွင် ငွေပေးချေခြင်း"</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"ငွေပေးချေရေး အက်ပ်ကို သတ်မှတ်ပါ။ ၎င်းနောက် သင့်ဖုန်း၏ ကျောဘက်ကို ချိတ်ဆက်ရန် မလိုသင်္ကေတပါ ငွေချေစက် တစ်ခုဆီသို့ ကပ်လိုက်ပါ။"</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"ရပါပြီ"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"နောက်ထပ်..."</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"သင်၏ ဦးစားပေးချက်များ သတ်မှတ်မည်လား?"</string>
@@ -3157,7 +3162,7 @@
     <string name="emergency_tone_vibrate" msgid="5020068066905681181">"တုန်ခါမှုများ"</string>
     <string name="boot_sounds_title" msgid="7583926202411353620">"အသံများ ဖွင့်ထားပါ"</string>
     <string name="live_caption_title" msgid="7926591158657997051">"တိုက်ရိုက်စာတန်းထိုး"</string>
-    <string name="live_caption_summary" msgid="9064771862352393125">"အလိုလို မီဒီယာ စာတန်းထိုးရန်"</string>
+    <string name="live_caption_summary" msgid="9064771862352393125">"အလိုအလျောက် စာတန်းထိုးရန်"</string>
     <string name="zen_mode_settings_summary_off" msgid="6929319200478424962">"ဘယ်တော့မှ"</string>
     <plurals name="zen_mode_settings_summary_on" formatted="false" msgid="6061723291126091396">
       <item quantity="other"><xliff:g id="ON_COUNT">%d</xliff:g> ခု ဖွင့်ထားသည်</item>
@@ -3313,7 +3318,7 @@
     <string name="swipe_direction_title" msgid="7535031630668873009">"ပွတ်ဆွဲ လုပ်ဆောင်ချက်များ"</string>
     <string name="swipe_direction_ltr" msgid="944932514821822709">"ပယ်ရန် ညာသို့၊ မီနူးပြရန် ဘယ်သို့ ပွတ်ဆွဲပါ"</string>
     <string name="swipe_direction_rtl" msgid="4521416787262888813">"ပယ်ရန် ဘယ်သို့၊ မီနူးပြရန် ညာသို့ ပွတ်ဆွဲပါ"</string>
-    <string name="notification_pulse_title" msgid="4861418327614907116">"မီး မှိတ်တုတ်မှိတ်တုတ်လုပ်ရန်"</string>
+    <string name="notification_pulse_title" msgid="4861418327614907116">"မီး မှိတ်တုတ်မှိတ်တုတ်လုပ်ပါ"</string>
     <string name="lock_screen_notifications_title" msgid="6889072265118747835">"လော့ခ်ချချိန် မျက်နှာပြင်တွင်"</string>
     <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"အလုပ်ပရိုဖိုင်လော့ခ်ချထားချိန်"</string>
     <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"အကြောင်းကြားချက်ပါ အရာအားလုံး ပြပါ"</string>
@@ -3327,7 +3332,7 @@
     <string name="lock_screen_notifications_interstitial_title_profile" msgid="4043621508889929254">"ပရိုဖိုင်သတိပေးချက်များ"</string>
     <string name="notifications_title" msgid="8334011924253810654">"အကြောင်းကြားချက်များ"</string>
     <string name="app_notifications_title" msgid="1141791221581312325">"အက်ပ် အကြောင်းကြားချက်များ"</string>
-    <string name="notification_channel_title" msgid="6637705960909690229">"အသိပေးချက် အမျိုးအစား"</string>
+    <string name="notification_channel_title" msgid="6637705960909690229">"အကြောင်းကြားချက် အမျိုးအစား"</string>
     <string name="notification_group_title" msgid="6105337987437608590">"အကြောင်းကြားချက် အုပ်စုအမျိုးအစား"</string>
     <string name="notification_importance_title" msgid="4131979083408000545">"အပြုအမူ"</string>
     <string name="notification_importance_unspecified" msgid="2515778981253707724">"အသံကို ခွင့်ပြုရန်"</string>
@@ -3672,7 +3677,7 @@
     <string name="default_app" msgid="8861276008866619872">"(မူသေ)"</string>
     <string name="system_app" msgid="4111402206594443265">"(စနစ်)"</string>
     <string name="system_default_app" msgid="1454719098589351197">"(စနစ်မူလ)"</string>
-    <string name="apps_storage" msgid="5658466038269046038">"အက်ပ်များ သိုလှောင်မှု"</string>
+    <string name="apps_storage" msgid="5658466038269046038">"အက်ပ်များ သိုလှောင်ခန်း"</string>
     <string name="usage_access" msgid="2023443456361489516">"သုံးစွဲမှုကို ကြည့်ရှုနိုင်ခြင်း"</string>
     <string name="permit_usage_access" msgid="3321727608629752758">"ဝင်ရောက်သုံးစွဲမှုအား ခွင့့်ပြုရန်"</string>
     <string name="app_usage_preference" msgid="5691545073101551727">"အက်ပ်သုံးစွဲမှု ရွေးချယ်စရာများ"</string>
@@ -4130,7 +4135,7 @@
     <string name="ambient_display_tap_screen_title" product="tablet" msgid="6434521782016864148">"တက်ဘလက်ကို စစ်ဆေးရန် တို့ပါ"</string>
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"စက်ပစ္စည်းကို စစ်ဆေးရန် တို့ပါ"</string>
     <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"အချိန်၊ အကြောင်းကြားချက်များနှင့် အခြားအချက်အလက်များကို စစ်ဆေးရန် သင့်ဖန်သားပြင်ကို တို့ပါ။"</string>
-    <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"သတိပေးချက်အတွက် လက်ဗွေပွတ်ဆွဲပါ"</string>
+    <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"သတိပေးချက်အတွက် လက်ဗွေပွတ်ဆွဲခြင်း"</string>
     <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"လက်ဗွေပွတ်ဆွဲခြင်း"</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"အကြောင်းကြားချက်များကို ကြည့်ရန် ဖုန်း၏ နောက်ကျောဘက်ရှိ လက်ဗွေ အာရုံခံကိရိယာပေါ်တွင် အောက်သို့ ပွတ်ဆွဲပါ။"</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="tablet" msgid="3480057984564476283">"အကြောင်းကြားချက်များကို ကြည့်ရန် တက်ဘလက်၏ နောက်ကျောဘက်ရှိ လက်ဗွေ အာရုံခံကိရိယာပေါ်တွင် အောက်သို့ ပွတ်ဆွဲပါ။"</string>
diff --git a/tests/CarDeveloperOptions/res/values-nb/arrays.xml b/tests/CarDeveloperOptions/res/values-nb/arrays.xml
index 04b22b6..1719b05 100644
--- a/tests/CarDeveloperOptions/res/values-nb/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-nb/arrays.xml
@@ -392,8 +392,8 @@
   </string-array>
   <string-array name="captioning_preset_selector_titles">
     <item msgid="326819345272910536">"Bruk appens standardvalg"</item>
-    <item msgid="8611890312638868524">"Hvitt på svart"</item>
-    <item msgid="5891360837786277638">"Svart på hvitt"</item>
+    <item msgid="8611890312638868524">"Hvit på svart"</item>
+    <item msgid="5891360837786277638">"Svart på hvit"</item>
     <item msgid="2798457065945456853">"Gult på svart"</item>
     <item msgid="5799049811524553967">"Gult på blått"</item>
     <item msgid="3673930830658169860">"Tilpasset"</item>
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"Aldri tillat"</item>
     <item msgid="8184570120217958741">"Alltid tillat"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Moderat"</item>
+    <item msgid="1555861583162930714">"Lav"</item>
+    <item msgid="1719683776264798117">"Kritisk"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normal"</item>
+    <item msgid="6107138933849816768">"Moderat"</item>
+    <item msgid="182695359839047859">"Lav"</item>
+    <item msgid="8577246509202964244">"Kritisk"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Vedvarende"</item>
     <item msgid="167418068739176448">"Høyeste aktivitet"</item>
@@ -467,7 +477,7 @@
     <item msgid="1008268820118852416">"Behandle som uten datamåling"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
-    <item msgid="6545683814310036454">"Bruk tilfeldig valgt MAC-adresse (standard)"</item>
+    <item msgid="6545683814310036454">"Bruk tilfeldig MAC-adresse (standard)"</item>
     <item msgid="214234417308375326">"Bruk enhetens MAC-adresse"</item>
   </string-array>
   <string-array name="wifi_hidden_entries">
diff --git a/tests/CarDeveloperOptions/res/values-nb/config.xml b/tests/CarDeveloperOptions/res/values-nb/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-nb/config.xml
+++ b/tests/CarDeveloperOptions/res/values-nb/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-nb/strings.xml b/tests/CarDeveloperOptions/res/values-nb/strings.xml
index 2e57216..6830cd7 100644
--- a/tests/CarDeveloperOptions/res/values-nb/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-nb/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Gjør teksten på skjermen større eller mindre."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Gjør mindre"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Gjør større"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Eksempeltekst"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Trollmannen fra Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Kapittel 11: Den vidunderlige smaragdbyen Oz"</string>
@@ -470,7 +469,7 @@
     <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Plassér fingeren på sensoren, og løft den når du kjenner en vibrasjon"</string>
     <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"Løft fingeren og berør igjen"</string>
     <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Løft fingeren gjentatte ganger for å legge til de forskjellige delene av fingeravtrykket ditt"</string>
-    <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"Fingeravtrykk lagt til"</string>
+    <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"Fingeravtrykket er lagt til"</string>
     <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"Når du ser dette ikonet, kan du bruke fingeravtrykket ditt til å identifisere deg eller godkjenne kjøp"</string>
     <string name="security_settings_fingerprint_enroll_enrolling_skip" msgid="1473280156532146933">"Gjør det senere"</string>
     <string name="setup_fingerprint_enroll_enrolling_skip_title" msgid="2816424026528101690">"Vil du hoppe over fingeravtrykk-konfig.?"</string>
@@ -488,7 +487,7 @@
     <string name="security_settings_fingerprint_enroll_done" msgid="4111289529758845926">"Ferdig"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"Ops, det er ikke sensoren"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"Berør sensoren på baksiden av telefonen. Bruk pekefingeren."</string>
-    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"Registrering er ikke fullført"</string>
+    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"Registreringen er ikke fullført"</string>
     <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Tidsgrensen for registrering av fingeravtrykk er nådd. Prøv på nytt."</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"Registrering av fingeravtrykket mislyktes. Prøv på nytt, eller bruk en annen finger."</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"Legg til ett til"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Må inneholde færre enn <xliff:g id="NUMBER_1">%d</xliff:g> sifre</item>
       <item quantity="one">Må inneholde færre enn <xliff:g id="NUMBER_0">%d</xliff:g> siffer</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Kan bare inneholde tall fra 0 til 9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Enhetsadministratoren forbyr nylig brukt PIN-kode"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Vanlige PIN-koder er blokkert av IT-administratoren din. Prøv en annen PIN-kode."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Dette kan ikke inkludere et ugyldig tegn"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Må inneholde minst <xliff:g id="COUNT">%d</xliff:g> andre tegn enn bokstaver</item>
       <item quantity="one">Må inneholde minst ett annet tegn enn bokstaver</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Må inneholde minst <xliff:g id="COUNT">%d</xliff:g> tegn som ikke er tall</item>
+      <item quantity="one">Må inneholde minst 1 tegn som ikke er et tall</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Enhetsadministratoren forbyr nylig brukte passord"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Vanlige passord er blokkert av IT-administratoren din. Prøv et annet passord."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"En sekvens av stigende, synkende eller like sifre er ikke tillatt"</string>
@@ -844,7 +846,7 @@
     <string name="wifi_error" msgid="5605801874484465557">"Feil"</string>
     <string name="wifi_sap_no_channel_error" msgid="6881796988574851628">"5 GHz-bånd er ikke tilgjengelig i dette landet"</string>
     <string name="wifi_in_airplane_mode" msgid="4729571191578262246">"I flymodus"</string>
-    <string name="wifi_notify_open_networks" msgid="4782239203624619655">"Varsel om åpent nettverk"</string>
+    <string name="wifi_notify_open_networks" msgid="4782239203624619655">"Varsel om åpne nettverk"</string>
     <string name="wifi_notify_open_networks_summary" msgid="1383681260705466715">"Varsle når et offentlig nettverk av høy kvalitet er tilgjengelig"</string>
     <string name="wifi_wakeup" msgid="4963732992164721548">"Slå på Wi‑Fi automatisk"</string>
     <string name="wifi_wakeup_summary" msgid="1152699417411690">"Wi‑Fi slås på igjen i nærheten av lagrede nettverk av høy kvalitet, for eksempel hjemmenettverket ditt"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mobil"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Bruk mobilnettverk hvis Wi-Fi er utilgjengelig"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Bruk Wi-Fi hvis mobilnettverket er utilgjengelig"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Ring via Wi‑Fi. Samtalen avsluttes hvis du mister Wi‑Fi-tilkoblingen."</string>
@@ -1632,7 +1637,7 @@
     <string name="sms_change_default_dialog_title" msgid="6301260161969667578">"Vil du bytte SMS-app?"</string>
     <string name="sms_change_default_dialog_text" msgid="8275088077930942680">"Vil du bruke <xliff:g id="NEW_APP">%1$s</xliff:g> i stedet for <xliff:g id="CURRENT_APP">%2$s</xliff:g> for SMS?"</string>
     <string name="sms_change_default_no_previous_dialog_text" msgid="4680224695080527907">"Vil du bruke <xliff:g id="NEW_APP">%s</xliff:g> som SMS-app?"</string>
-    <string name="network_scorer_picker_title" msgid="1691073966560952916">"Nettverksvurdering levert av"</string>
+    <string name="network_scorer_picker_title" msgid="1691073966560952916">"Leverandør av nettverksvurdering"</string>
     <string name="network_scorer_picker_none_preference" msgid="6448280557733231737">"Ingen"</string>
     <string name="network_scorer_change_active_dialog_title" msgid="4274159562371475090">"Vil du endre Wi-Fi-assistent?"</string>
     <string name="network_scorer_change_active_dialog_text" msgid="4264089809189760730">"Vil du bruke <xliff:g id="NEW_APP">%1$s</xliff:g> i stedet for <xliff:g id="CURRENT_APP">%2$s</xliff:g> til å administrere nettverkstilkoblingene?"</string>
@@ -1702,7 +1707,7 @@
     <string name="settings_safetylegal_activity_loading" msgid="7680998654145172">"Laster inn …"</string>
     <string name="confirm_device_credential_use_alternate_method" msgid="1279869272895739941">"Bruk en annen metode"</string>
     <string name="lockpassword_choose_your_screen_lock_header" msgid="6283518876031424798">"Angi skjermlås"</string>
-    <string name="lockpassword_choose_your_password_message" msgid="2838273977481046536">"Angi et passord for sikkerheten"</string>
+    <string name="lockpassword_choose_your_password_message" msgid="2838273977481046536">"Angi et passord av hensyn til sikkerheten"</string>
     <string name="lockpassword_choose_your_password_header_for_fingerprint" msgid="4921343500484160894">"Angi passord for å bruke fingeravtrykk"</string>
     <string name="lockpassword_choose_your_pattern_header_for_fingerprint" msgid="314870151462139417">"Angi mønster for å bruke fingeravtrykk"</string>
     <string name="lockpassword_choose_your_pin_message" msgid="8942598950627277885">"Angi en PIN-kode for sikkerheten"</string>
@@ -1747,7 +1752,7 @@
     <string name="lockpattern_change_lock_pin_label" msgid="3435796032210265723">"Endre PIN-kode for opplåsning"</string>
     <string name="lockpattern_recording_intro_header" msgid="2262005028838969839">"Tegn et opplåsingsmønster"</string>
     <string name="lockpattern_recording_intro_footer" msgid="5426745740754065099">"Trykk menyknappen for hjelp."</string>
-    <string name="lockpattern_recording_inprogress" msgid="4060818382176523671">"Slipp opp fingeren når du er ferdig."</string>
+    <string name="lockpattern_recording_inprogress" msgid="4060818382176523671">"Løft fingeren når du er ferdig."</string>
     <string name="lockpattern_recording_incorrect_too_short" msgid="6374760294545431845">"Berør minst <xliff:g id="NUMBER">%d</xliff:g> punkter. Prøv på nytt."</string>
     <string name="lockpattern_pattern_entered_header" msgid="2108106638322637851">"Mønsteret er registrert"</string>
     <string name="lockpattern_need_to_confirm" msgid="4079482507985867389">"Tegn mønsteret på nytt for å bekrefte"</string>
@@ -2084,7 +2089,7 @@
     <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"Fargeinvertering"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"Kan påvirke ytelsen"</string>
     <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"Holdetid"</string>
-    <string name="accessibility_autoclick_description" msgid="5492414927846407499">"Hvis du bruker en mus, kan du stille musepekeren til å klikke automatisk når den slutter å bevege seg i en bestemt periode."</string>
+    <string name="accessibility_autoclick_description" msgid="5492414927846407499">"Hvis du bruker en mus, kan du stille musepekeren til å klikke automatisk etter at den har stått i ro en viss tid."</string>
     <string name="accessibility_autoclick_delay_preference_title" msgid="8303022510942147049">"Forsinkelse før klikk"</string>
     <string name="accessibility_vibration_settings_title" msgid="1902649657883159406">"Vibrasjon"</string>
     <string name="accessibility_notification_vibration_title" msgid="1005799039440510298">"Varselvibrering"</string>
@@ -2789,7 +2794,7 @@
     <string name="vpn_always_on_summary" msgid="3639994551631437397">"La enheten være tilkoblet VPN hele tiden"</string>
     <string name="vpn_always_on_summary_not_supported" msgid="9077720997795965133">"Støttes ikke av denne appen"</string>
     <string name="vpn_always_on_summary_active" msgid="8962619701962239088">"Alltid på er aktiv"</string>
-    <string name="vpn_require_connection" msgid="5413746839457797350">"Blokker tilkoblinger uten VPN"</string>
+    <string name="vpn_require_connection" msgid="5413746839457797350">"Blokkér tilkoblinger uten VPN"</string>
     <string name="vpn_require_connection_title" msgid="8361434328767853717">"Vil du kreve VPN-tilkobling?"</string>
     <string name="vpn_lockdown_summary" msgid="6770030025737770861">"Velg en VPN-profil du vil forbli tilkoblet til. Nettverkstrafikk blir bare tillatt når du er tilkoblet denne VPN-en."</string>
     <string name="vpn_lockdown_none" msgid="3789288793603394679">"Ingen"</string>
@@ -2911,7 +2916,7 @@
     <string name="apps_with_restrictions_settings_button" msgid="5065896213467171744">"Utvidelsesinnstillinger for appen"</string>
     <string name="nfc_payment_settings_title" msgid="5070077706735415291">"Berøringsbetaling"</string>
     <string name="nfc_payment_how_it_works" msgid="7607901964687787177">"Slik fungerer det"</string>
-    <string name="nfc_payment_no_apps" msgid="8844440783395420860">"Betal med telefonen din i butikker"</string>
+    <string name="nfc_payment_no_apps" msgid="8844440783395420860">"Betal med telefonen i butikker"</string>
     <string name="nfc_payment_default" msgid="7869273092463612271">"Standardapp for betaling"</string>
     <string name="nfc_payment_default_not_set" msgid="955804193510335338">"Ikke angitt"</string>
     <string name="nfc_payment_app_and_desc" msgid="102312684211458190">"<xliff:g id="APP">%1$s</xliff:g> – <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
@@ -2920,7 +2925,7 @@
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Unntatt når en annen betalingsapp er åpen"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"På betalingsterminaler med berøringsfunksjonalitet vil du betale med"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Betaling ved terminaler"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Konfigurer en betalingsapp. Deretter holder du baksiden av telefonen din mot en terminal som har symbolet for kontaktløs betaling."</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Konfigurer en betalingsapp. Deretter holder du baksiden av telefonen mot en terminal som har symbolet for kontaktløs betaling."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"Skjønner"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"Mr"</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"Angi som foretrukket?"</string>
@@ -3156,8 +3161,8 @@
     <string name="emergency_tone_alert" msgid="907868135091891015">"Toner"</string>
     <string name="emergency_tone_vibrate" msgid="5020068066905681181">"Vibrasjoner"</string>
     <string name="boot_sounds_title" msgid="7583926202411353620">"Lyder ved oppstart"</string>
-    <string name="live_caption_title" msgid="7926591158657997051">"Liveteksting"</string>
-    <string name="live_caption_summary" msgid="9064771862352393125">"Automatisk teksting av media"</string>
+    <string name="live_caption_title" msgid="7926591158657997051">"Direkteteksting"</string>
+    <string name="live_caption_summary" msgid="9064771862352393125">"Automatisk medieteksting"</string>
     <string name="zen_mode_settings_summary_off" msgid="6929319200478424962">"Aldri"</string>
     <plurals name="zen_mode_settings_summary_on" formatted="false" msgid="6061723291126091396">
       <item quantity="other"><xliff:g id="ON_COUNT">%d</xliff:g> er slått på</item>
diff --git a/tests/CarDeveloperOptions/res/values-ne/arrays.xml b/tests/CarDeveloperOptions/res/values-ne/arrays.xml
index aad8f88..1d1b779 100644
--- a/tests/CarDeveloperOptions/res/values-ne/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-ne/arrays.xml
@@ -62,8 +62,8 @@
   <string-array name="entries_font_size">
     <item msgid="2340391964816059553">"सानो"</item>
     <item msgid="591935967183159581">"पूर्वनिर्धारित"</item>
-    <item msgid="1714184661981538355">"ठूलो"</item>
-    <item msgid="6195563047686707484">"सबैभन्दा ठूलो"</item>
+    <item msgid="1714184661981538355">"ठुलो"</item>
+    <item msgid="6195563047686707484">"सबैभन्दा ठुलो"</item>
   </string-array>
   <string-array name="wifi_status">
     <item msgid="1304883790721412351"></item>
@@ -85,7 +85,7 @@
     <item msgid="8058143476674427024">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>सँग जडान हुँदै..."</item>
     <item msgid="7547609081339573756">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>का साथ प्रमाणीकरण गर्दै..."</item>
     <item msgid="5145158315060185414">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>बाट IP ठेगाना प्राप्त गर्दै..."</item>
-    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>सँग जडित"</item>
+    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> मा जोडिएको छ"</item>
     <item msgid="6600156231416890902">"निलम्बित"</item>
     <item msgid="4133290864821295785">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>बाट विच्छेदन गर्दै..."</item>
     <item msgid="3980154971187953257">"जडान विच्छेद भयो"</item>
@@ -135,7 +135,7 @@
   <string-array name="usage_stats_display_order_types">
     <item msgid="1266031014388516303">"उपयोग समय"</item>
     <item msgid="2784401352592276015">"पछिल्लो समय प्रयोग गरिएको"</item>
-    <item msgid="249854287216326349">"अनुप्रयोगको नाम"</item>
+    <item msgid="249854287216326349">"एपको नाम"</item>
   </string-array>
   <string-array name="wifi_eap_entries">
     <item msgid="5538816743897530343">"PEAP"</item>
@@ -170,7 +170,7 @@
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"कुनै पनि होइन"</item>
     <item msgid="1464741437353223198">"म्यानुअल"</item>
-    <item msgid="5793600062487886090">"प्रोक्सी स्वतः समायोजन"</item>
+    <item msgid="5793600062487886090">"प्रोक्सी अटो-कन्फिगुरेसन"</item>
   </string-array>
   <string-array name="apn_auth_entries">
     <item msgid="7099647881902405997">"कुनै पनि होइन"</item>
@@ -256,8 +256,8 @@
     <item msgid="7565226799008076833">"मास्टर ध्वनि मात्रा"</item>
     <item msgid="5420704980305018295">"वाणी मात्रा"</item>
     <item msgid="5797363115508970204">"घन्टी मात्रा"</item>
-    <item msgid="8233154098550715999">"मिडियाको आवाजको मात्रा"</item>
-    <item msgid="5196715605078153950">"अलार्मको आवाजको मात्रा"</item>
+    <item msgid="8233154098550715999">"मिडियाको भोल्युम"</item>
+    <item msgid="5196715605078153950">"अलार्मको भोल्युम"</item>
     <item msgid="394030698764284577">"सूचना मात्रा"</item>
     <item msgid="8952898972491680178">"ब्लुटुथ मात्रा"</item>
     <item msgid="8506227454543690851">"जागा रहनुहोस्"</item>
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"पृष्ठभूमिमा सञ्चालन गर्नुहोस्"</item>
     <item msgid="6423861043647911030">"पहुँचको मात्रा"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"स्थान"</item>
+    <item msgid="6656077694190491067">"स्थान"</item>
+    <item msgid="8790228218278477369">"स्थान"</item>
+    <item msgid="7836406246005211990">"भाइब्रेट गर्नुहोस्"</item>
+    <item msgid="3951439024549922598">"सम्पर्कहरू पढ्नुहोस्"</item>
+    <item msgid="8802152411647068">"सम्पर्कहरू परिमार्जन गर्नुहोस्"</item>
+    <item msgid="229544934599698735">"कल लग पढ्नुहोस्"</item>
+    <item msgid="7396102294405899613">"कल लग परिमार्जन गर्नुहोस्"</item>
+    <item msgid="3597797992398484655">"पात्रो पढ्नुहोस्"</item>
+    <item msgid="2705975774250907343">"पात्रो परिमार्जन गर्नुहोस्"</item>
+    <item msgid="4668747371441932697">"स्थान"</item>
+    <item msgid="1487578921720243646">"सूचना पोस्ट गर्नुहोस्"</item>
+    <item msgid="4636080349724146638">"स्थान"</item>
+    <item msgid="673510900286463926">"कल फोन"</item>
+    <item msgid="542083422784609790">"SMS/MMS पढ्नुहोस्"</item>
+    <item msgid="1033780373029588436">"SMS/MMS लेख्नुहोस्"</item>
+    <item msgid="5647111115517787488">"SMS/MMS प्राप्त गर्नुहोस्"</item>
+    <item msgid="8591105601108455893">"SMS/MMS प्राप्त गर्नुहोस्"</item>
+    <item msgid="7730995008517841903">"SMS/MMS प्राप्त गर्नुहोस्"</item>
+    <item msgid="2613033109026626086">"SMS/MMS प्राप्त गर्नुहोस्"</item>
+    <item msgid="3037159047591081136">"SMS/MMS पठाउनुहोस्"</item>
+    <item msgid="4726682243833913568">"SMS/MMS पढ्नुहोस्"</item>
+    <item msgid="6555678522277865572">"SMS/MMS लेख्नुहोस्"</item>
+    <item msgid="6981734935578130884">"सेटिङ परिमार्जन गर्नुहोस्"</item>
+    <item msgid="8705854389991425629">"शीर्षमा कोर्नुहोस्"</item>
+    <item msgid="5861356020344153651">"सूचनाहरू पहुँच गर्नुहोस्"</item>
+    <item msgid="78432174621628659">"क्यामेरा"</item>
+    <item msgid="3986116419882154794">"अडियो रेकर्ड गर्नुहोस्"</item>
+    <item msgid="4516840825756409490">"अडियो बजाउनुहोस्"</item>
+    <item msgid="6811712502798183957">"क्लिपबोर्ड पढ्नुहोस्"</item>
+    <item msgid="2780369012602289114">"क्लिपबोर्ड परिमार्जन गर्नुहोस्"</item>
+    <item msgid="2331359440170850868">"मिडिया बटनहरू"</item>
+    <item msgid="6133599737122751231">"श्रब्य फोकस"</item>
+    <item msgid="6844485713404805301">"मास्टर ध्वनि मात्रा"</item>
+    <item msgid="1600379420669104929">"वाणीको मात्रा"</item>
+    <item msgid="6296768210470214866">"घन्टीको भोल्युम"</item>
+    <item msgid="510690696071629241">"मिडियाको भोल्युम"</item>
+    <item msgid="406861638631430109">"अलार्मको भोल्युम"</item>
+    <item msgid="4715864795872233884">"ध्वनी सूचना"</item>
+    <item msgid="2311478519251301183">"ब्लुटुथ भोल्युम"</item>
+    <item msgid="5133991377896747027">"जागा रहनुहोस्"</item>
+    <item msgid="2464189519136248621">"स्थान"</item>
+    <item msgid="2062677934050803037">"स्थान"</item>
+    <item msgid="1735171933192715957">"तथ्याङ्क उपयोग प्राप्त गर्नुहोस्"</item>
+    <item msgid="1014093788778383554">"माइक्रोफोनको आवाज बन्द्/खुला गर्नुहोस्"</item>
+    <item msgid="4199297950608622850">"टोस्ट देखाउनुहोस्"</item>
+    <item msgid="2527962435313398821">"मिडिया प्रोजेक्ट गर्नुहोस्"</item>
+    <item msgid="5117506254221861929">"VPN सक्रिय पार्नुहोस्"</item>
+    <item msgid="8291198322681891160">"वालपेपर लेख्नुहोस्"</item>
+    <item msgid="7106921284621230961">"संरचनालाई मद्दत गर्नुहोस्"</item>
+    <item msgid="4496533640894624799">"स्क्रिनसटलाई मद्दत गर्नुहोस्"</item>
+    <item msgid="2598847264853993611">"फोन अवस्था पढ्नुहोस्"</item>
+    <item msgid="9215610846802973353">"भ्वाइसमेल थप्नुहोस्"</item>
+    <item msgid="9186411956086478261">"SIP प्रयोग गर्नुहोस्"</item>
+    <item msgid="6884763100104539558">"बहिर्गमन कललाई प्रशोधन गर्नुहोस्"</item>
+    <item msgid="125513972170580692">"फिंगरप्रिन्ट"</item>
+    <item msgid="2556071024281275619">"शारीरिक सेन्सर"</item>
+    <item msgid="617168514928339387">"सेल प्रसारणहरू पढ्नुहोस्"</item>
+    <item msgid="7134693570516523585">"स्थानको नक्कल गर्नुहोस्"</item>
+    <item msgid="7224489175375229399">"भण्डारण पढ्नुहोस्"</item>
+    <item msgid="8472735063903258202">"भण्डारण लेख्नहोस्"</item>
+    <item msgid="4069276819909595110">"स्क्रिन सक्रिय गर्नुहोस्"</item>
+    <item msgid="1228338896751121025">"खाताहरू प्राप्त गर्नुहोस्"</item>
+    <item msgid="3181581793459233672">"पृष्ठभूमिमा सञ्चालन गर्नुहोस्"</item>
+    <item msgid="2340936043025374076">"पहुँचको मात्रा"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"छोटो"</item>
     <item msgid="4816511817309094890">"सामान्य"</item>
@@ -307,8 +373,8 @@
     <item msgid="1680223634161592855">"ज्यादै साना"</item>
     <item msgid="5091603983404027034">"सानो"</item>
     <item msgid="176844712416932112">"सामान्य"</item>
-    <item msgid="2784236342175159295">"ठूलो"</item>
-    <item msgid="218913203203160606">"ज्यादै ठूलो"</item>
+    <item msgid="2784236342175159295">"ठुलो"</item>
+    <item msgid="218913203203160606">"ज्यादै ठुलो"</item>
   </string-array>
   <string-array name="captioning_edge_type_selector_titles">
     <item msgid="3865198759294188069">"पूर्वनिर्धारित"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"कहिल्यै पनि अनुमति नदिनुहोस्"</item>
     <item msgid="8184570120217958741">"सधैँ अनुमति दिनुहोस्"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"मेमोरीको स्थिति सामान्य छ"</item>
+    <item msgid="5101233285497327432">"मध्यम"</item>
+    <item msgid="1555861583162930714">"न्यून"</item>
+    <item msgid="1719683776264798117">"चिन्ताजनक"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"सामान्य"</item>
+    <item msgid="6107138933849816768">"मध्यम"</item>
+    <item msgid="182695359839047859">"न्यून"</item>
+    <item msgid="8577246509202964244">"मेमोरी अत्यन्त कम छ"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"लगातार"</item>
     <item msgid="167418068739176448">"उच्च गतिविधि"</item>
@@ -378,16 +454,16 @@
   </string-array>
   <string-array name="color_picker">
     <item msgid="3151827842194201728">"टिल"</item>
-    <item msgid="3228505970082457852">"नीलो"</item>
+    <item msgid="3228505970082457852">"निलो"</item>
     <item msgid="6590260735734795647">"इन्डिगो"</item>
     <item msgid="3521763377357218577">"बैजनी"</item>
     <item msgid="5932337981182999919">"गुलाबी"</item>
     <item msgid="5642914536624000094">"रातो"</item>
   </string-array>
   <string-array name="automatic_storage_management_days">
-    <item msgid="2860293514533486236">"३० दिनभन्दा बढी पुरानो"</item>
-    <item msgid="8699273238891265610">"६० दिनभन्दा बढी पुरानो"</item>
-    <item msgid="8346279419423837266">"९० दिनभन्दा बढी पुरानो"</item>
+    <item msgid="2860293514533486236">"कम्तीमा ३० दिन पुरानो"</item>
+    <item msgid="8699273238891265610">"कम्तीमा ६० दिन पुरानो"</item>
+    <item msgid="8346279419423837266">"कम्तीमा ९० दिन पुरानो"</item>
   </string-array>
     <!-- no translation found for swipe_direction_titles:0 (6583090603341402282) -->
     <!-- no translation found for swipe_direction_titles:1 (4965730704403236310) -->
@@ -398,7 +474,7 @@
   <string-array name="wifi_metered_entries">
     <item msgid="4329206416008519163">"स्वतः पत्ता लगाउनुहोस्"</item>
     <item msgid="773943026484148895">"शुल्क लाग्ने वाइफाइका रूपमा लिनुहोस्"</item>
-    <item msgid="1008268820118852416">"मिटर नगरिएको रूपमा व्यवहार गर्नुहोस्"</item>
+    <item msgid="1008268820118852416">"नि:शुल्क वाइफाइको रूपमा व्यवहार गर्नुहोस्"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
     <item msgid="6545683814310036454">"क्रमरहित MAC प्रयोग गर्नुहोस् (पूर्वनिर्धारित)"</item>
diff --git a/tests/CarDeveloperOptions/res/values-ne/config.xml b/tests/CarDeveloperOptions/res/values-ne/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-ne/config.xml
+++ b/tests/CarDeveloperOptions/res/values-ne/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-ne/strings.xml b/tests/CarDeveloperOptions/res/values-ne/strings.xml
index e7fccc0..e838045 100644
--- a/tests/CarDeveloperOptions/res/values-ne/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ne/strings.xml
@@ -80,11 +80,10 @@
     <string name="sdcard_format" product="default" msgid="4831611387627849108">"SD कार्ड मेटाउनुहोस्"</string>
     <string name="preview_pager_content_description" msgid="5731599395893090038">"पूर्वावलोकन"</string>
     <string name="preview_page_indicator_content_description" msgid="3192955679074998362">"पूर्वावलोकन, <xliff:g id="NUM_PAGES">%2$d</xliff:g> मध्ये पृष्ठ <xliff:g id="CURRENT_PAGE">%1$d</xliff:g>"</string>
-    <string name="font_size_summary" msgid="9120023206321191067">"स्क्रिनमा भएको पाठलाई अझै सानो वा ठूलो बनाउनुहोस्।"</string>
+    <string name="font_size_summary" msgid="9120023206321191067">"स्क्रिनमा भएको पाठलाई अझै सानो वा ठुलो बनाउनुहोस्।"</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"अझ सानो बनाउनुहोस्"</string>
-    <string name="font_size_make_larger_desc" msgid="2907824418252785875">"अझ ठूलो बनाउनुहोस्"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_make_larger_desc" msgid="2907824418252785875">"अझ ठुलो बनाउनुहोस्"</string>
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"नमूना पाठ"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"दि वन्डरफुल विजार्ड अफ ओज"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"अध्याय ११: दि वन्डरफुल एमरल्ड सिटी अफ ओज"</string>
@@ -128,28 +127,28 @@
     <string name="bluetooth_notif_title" msgid="5090288898529286011">"जोडी पार्ने अनुरोध"</string>
     <string name="bluetooth_notif_message" msgid="6612367890895077938">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>सँग जोड्न ट्याप गर्नुहोस्।"</string>
     <string name="bluetooth_show_received_files" msgid="5060846395852236652">"प्राप्त गरिएका फाइलहरू"</string>
-    <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"ब्लुटुथमार्फत फाइलहरू प्राप्त गरियो"</string>
+    <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"ब्लुटुथमार्फत प्राप्त फाइलहरू"</string>
     <string name="device_picker" msgid="8345264486071697705">"ब्लुटुथ उपकरण छान्नुहोस्"</string>
     <string name="bluetooth_ask_enablement" msgid="8716802066127746062">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्लुटुथ सक्रिय गर्न चाहन्छ"</string>
     <string name="bluetooth_ask_disablement" msgid="7125319551097350783">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्लुटुथ निष्क्रिय पार्न चाहन्छ"</string>
-    <string name="bluetooth_ask_enablement_no_name" msgid="6105893027185475233">"एउटा अनुप्रयोग ब्लुटुथ सक्रिय गर्न चाहन्छ"</string>
-    <string name="bluetooth_ask_disablement_no_name" msgid="8648888502291681310">"एउटा अनुप्रयोग ब्लुटुथ निष्क्रिय पार्न चाहन्छ"</string>
+    <string name="bluetooth_ask_enablement_no_name" msgid="6105893027185475233">"एउटा एप ब्लुटुथ सक्रिय गर्न चाहन्छ"</string>
+    <string name="bluetooth_ask_disablement_no_name" msgid="8648888502291681310">"एउटा एप ब्लुटुथ निष्क्रिय पार्न चाहन्छ"</string>
     <string name="bluetooth_ask_discovery" product="tablet" msgid="6871595755186170115">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="TIMEOUT">%2$d</xliff:g> सेकेन्डसम्म अन्य ब्लुटुथ यन्त्रहरूले तपाईँको ट्याब्लेट देख्न सक्ने बनाउन चाहन्छ।"</string>
     <string name="bluetooth_ask_discovery" product="default" msgid="3388041479101348095">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="TIMEOUT">%2$d</xliff:g> सेकेन्डसम्म अन्य ब्लुटुथ यन्त्रहरूले तपाईँको फोन देख्न सक्ने बनाउन चाहन्छ।"</string>
-    <string name="bluetooth_ask_discovery_no_name" product="tablet" msgid="1472358802231150345">"एउटा अनुप्रयोग <xliff:g id="TIMEOUT">%1$d</xliff:g> सेकेन्डसम्म अन्य ब्लुटुथ यन्त्रहरूले तपाईँको ट्याब्लेट देख्न सक्ने बनाउन चाहन्छ।"</string>
-    <string name="bluetooth_ask_discovery_no_name" product="default" msgid="6195796094297507404">"एउटा अनुप्रयोग <xliff:g id="TIMEOUT">%1$d</xliff:g> सेकेन्डसम्म अन्य ब्लुटुथ यन्त्रहरूले तपाईँको फोन देख्न सक्ने बनाउन चाहन्छ।"</string>
+    <string name="bluetooth_ask_discovery_no_name" product="tablet" msgid="1472358802231150345">"एउटा एप <xliff:g id="TIMEOUT">%1$d</xliff:g> सेकेन्डसम्म अन्य ब्लुटुथ यन्त्रहरूले तपाईँको ट्याब्लेट देख्न सक्ने बनाउन चाहन्छ।"</string>
+    <string name="bluetooth_ask_discovery_no_name" product="default" msgid="6195796094297507404">"एउटा एप <xliff:g id="TIMEOUT">%1$d</xliff:g> सेकेन्डसम्म अन्य ब्लुटुथ यन्त्रहरूले तपाईँको फोन देख्न सक्ने बनाउन चाहन्छ।"</string>
     <string name="bluetooth_ask_lasting_discovery" product="tablet" msgid="2702942027812132427">"<xliff:g id="APP_NAME">%1$s</xliff:g> अन्य ब्लुटुथ यन्त्रहरूले तपाईंको ट्याब्लेट देख्न सक्ने बनाउन चाहन्छ। तपाईं पछि ब्लुटुथ सम्बन्धी सेटिङहरूमा गई यसलाई परिवर्तन गर्न सक्नुहुन्छ।"</string>
     <string name="bluetooth_ask_lasting_discovery" product="default" msgid="7796723473397303412">"<xliff:g id="APP_NAME">%1$s</xliff:g> अन्य ब्लुटुथ यन्त्रहरूले तपाईंको फोन देख्न सक्ने बनाउन चाहन्छ। तपाईं पछि ब्लुटुथ सम्बन्धी सेटिङहरूमा गई यसलाई परिवर्तन गर्न सक्नुहुन्छ।"</string>
-    <string name="bluetooth_ask_lasting_discovery_no_name" product="tablet" msgid="5961921359655434504">"एउटा अनुप्रयोग अन्य ब्लुटुथ यन्त्रहरूले तपाईंको ट्याब्लेट देख्न सक्ने बनाउन चाहन्छ। तपाईं पछि ब्लुटुथ सम्बन्धी सेटिङहरूमा गई यसलाई परिवर्तन गर्न सक्नुहुन्छ।"</string>
-    <string name="bluetooth_ask_lasting_discovery_no_name" product="default" msgid="3585910858758443872">"एउटा अनुप्रयोग अन्य ब्लुटुथ यन्त्रहरूले तपाईंको फोन देख्न सक्ने बनाउन चाहन्छ। तपाईं पछि ब्लुटुथ सम्बन्धी सेटिङहरूमा गई यसलाई परिवर्तन गर्न सक्नुहुन्छ।"</string>
+    <string name="bluetooth_ask_lasting_discovery_no_name" product="tablet" msgid="5961921359655434504">"एउटा एप अन्य ब्लुटुथ यन्त्रहरूले तपाईंको ट्याब्लेट देख्न सक्ने बनाउन चाहन्छ। तपाईं पछि ब्लुटुथ सम्बन्धी सेटिङहरूमा गई यसलाई परिवर्तन गर्न सक्नुहुन्छ।"</string>
+    <string name="bluetooth_ask_lasting_discovery_no_name" product="default" msgid="3585910858758443872">"एउटा एप अन्य ब्लुटुथ यन्त्रहरूले तपाईंको फोन देख्न सक्ने बनाउन चाहन्छ। तपाईं पछि ब्लुटुथ सम्बन्धी सेटिङहरूमा गई यसलाई परिवर्तन गर्न सक्नुहुन्छ।"</string>
     <string name="bluetooth_ask_enablement_and_discovery" product="tablet" msgid="5676466923424941153">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्लुटुथ सक्रिय गर्न र <xliff:g id="TIMEOUT">%2$d</xliff:g> सेकेन्डसम्म अन्य यन्त्रहरूले तपाईँको ट्याब्लेट देख्न सक्ने बनाउन चाहन्छ।"</string>
     <string name="bluetooth_ask_enablement_and_discovery" product="default" msgid="507088376226791063">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्लुटुथ सक्रिय गर्न र <xliff:g id="TIMEOUT">%2$d</xliff:g> सेकेन्डसम्म अन्य यन्त्रहरूले तपाईँको फोन देख्न सक्ने बनाउन चाहन्छ।"</string>
-    <string name="bluetooth_ask_enablement_and_discovery_no_name" product="tablet" msgid="1164681893121736219">"एउटा अनुप्रयोग ब्लुटुथ सक्रिय गर्न र <xliff:g id="TIMEOUT">%1$d</xliff:g> सेकेन्डसम्म अन्य यन्त्रहरूले तपाईँको ट्याब्लेट देख्न सक्ने बनाउन चाहन्छ।"</string>
-    <string name="bluetooth_ask_enablement_and_discovery_no_name" product="default" msgid="2542247690119921188">"एउटा अनुप्रयोग ब्लुटुथ सक्रिय गर्न र <xliff:g id="TIMEOUT">%1$d</xliff:g> सेकेन्डसम्म अन्य यन्त्रहरूले तपाईँको फोन देख्न सक्ने बनाउन चाहन्छ।"</string>
+    <string name="bluetooth_ask_enablement_and_discovery_no_name" product="tablet" msgid="1164681893121736219">"एउटा एप ब्लुटुथ सक्रिय गर्न र <xliff:g id="TIMEOUT">%1$d</xliff:g> सेकेन्डसम्म अन्य यन्त्रहरूले तपाईँको ट्याब्लेट देख्न सक्ने बनाउन चाहन्छ।"</string>
+    <string name="bluetooth_ask_enablement_and_discovery_no_name" product="default" msgid="2542247690119921188">"एउटा एप ब्लुटुथ सक्रिय गर्न र <xliff:g id="TIMEOUT">%1$d</xliff:g> सेकेन्डसम्म अन्य यन्त्रहरूले तपाईँको फोन देख्न सक्ने बनाउन चाहन्छ।"</string>
     <string name="bluetooth_ask_enablement_and_lasting_discovery" product="tablet" msgid="7118362102769177771">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्लुटुथ सक्रिय गर्न र अन्य यन्त्रहरूले तपाईंको ट्याब्लेट देख्न सक्ने बनाउन चाहन्छ। तपाईं पछि ब्लुटुथ सम्बन्धी सेटिङहरूमा गई यसलाई परिवर्तन गर्न सक्नुहुन्छ।"</string>
     <string name="bluetooth_ask_enablement_and_lasting_discovery" product="default" msgid="2577488464813970727">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्लुटुथ सक्रिय गर्न र अन्य यन्त्रहरूले तपाईंको फोन देख्न सक्ने बनाउन चाहन्छ। तपाईं पछि ब्लुटुथ सम्बन्धी सेटिङहरूमा गई यसलाई परिवर्तन गर्न सक्नुहुन्छ।"</string>
-    <string name="bluetooth_ask_enablement_and_lasting_discovery_no_name" product="tablet" msgid="7083038132794842691">"एउटा अनुप्रयोग ब्लुटुथ सक्रिय गर्न र अन्य यन्त्रहरूले तपाईंको ट्याब्लेट देख्न सक्ने बनाउन चाहन्छ। तपाईं पछि ब्लुटुथ सम्बन्धी सेटिङहरूमा गई यसलाई परिवर्तन गर्न सक्नुहुन्छ।"</string>
-    <string name="bluetooth_ask_enablement_and_lasting_discovery_no_name" product="default" msgid="3541668604020109525">"एउटा अनुप्रयोग ब्लुटुथ सक्रिय गर्न र अन्य यन्त्रहरूले तपाईंको फोन देख्न सक्ने बनाउन चाहन्छ। तपाईं पछि ब्लुटुथ सम्बन्धी सेटिङहरूमा गई यसलाई परिवर्तन गर्न सक्नुहुन्छ।"</string>
+    <string name="bluetooth_ask_enablement_and_lasting_discovery_no_name" product="tablet" msgid="7083038132794842691">"एउटा एप ब्लुटुथ सक्रिय गर्न र अन्य यन्त्रहरूले तपाईंको ट्याब्लेट देख्न सक्ने बनाउन चाहन्छ। तपाईं पछि ब्लुटुथ सम्बन्धी सेटिङहरूमा गई यसलाई परिवर्तन गर्न सक्नुहुन्छ।"</string>
+    <string name="bluetooth_ask_enablement_and_lasting_discovery_no_name" product="default" msgid="3541668604020109525">"एउटा एप ब्लुटुथ सक्रिय गर्न र अन्य यन्त्रहरूले तपाईंको फोन देख्न सक्ने बनाउन चाहन्छ। तपाईं पछि ब्लुटुथ सम्बन्धी सेटिङहरूमा गई यसलाई परिवर्तन गर्न सक्नुहुन्छ।"</string>
     <string name="bluetooth_turning_on" msgid="6935183036449748493">"ब्लुटुथ खुल्दै..."</string>
     <string name="bluetooth_turning_off" msgid="9214026723789756620">"ब्लुटुथ बन्द हुँदैछ..."</string>
     <string name="bluetooth_connection_permission_request" msgid="2382506002340643398">"ब्लुटुथ जडान अनुरोध"</string>
@@ -180,7 +179,7 @@
     <string name="connected_device_connected_title" msgid="6255107326608785482">"हाल जडान अवस्थामा छ"</string>
     <string name="connected_device_saved_title" msgid="8270136893488475163">"सुरक्षित गरिएका यन्त्रहरू"</string>
     <string name="connected_device_add_device_summary" msgid="7960491471270158891">"जोडा बनाउनका लागि ब्लुटुथ सक्रिय हुने छ"</string>
-    <string name="connected_device_connections_title" msgid="9205000271382018428">"जडानसम्बन्धी प्राथमिकताहरू"</string>
+    <string name="connected_device_connections_title" msgid="9205000271382018428">"कनेक्सनका प्राथमिकताहरू"</string>
     <string name="connected_device_previously_connected_title" msgid="225918223397410428">"यसअघि जडान भएका यन्त्रहरू"</string>
     <string name="connected_device_previously_connected_screen_title" msgid="2018789662358162716">"यसअघि जडान भएका यन्त्रहरू"</string>
     <string name="connected_device_bluetooth_turned_on_toast" msgid="4652326177920814476">"ब्लुटुथ सक्रिय गरियो"</string>
@@ -208,7 +207,7 @@
     <string name="proxy_error_empty_port" msgid="8034561724923076215">"तपाईँले पोर्टक्षेत्र पूरा गर्नु जरुरी छ।"</string>
     <string name="proxy_error_empty_host_set_port" msgid="8471455809508588255">"यदि होस्ट फिल्ड खाली छ भने पोर्ट फिल्ड पनि खाली हुनु पर्छ।"</string>
     <string name="proxy_error_invalid_port" msgid="4046559920586100637">"तपाईंले टाइप गर्नुभएको पोर्ट मान्य छैन।"</string>
-    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"HTTP प्रोक्सी ब्राउजरद्वारा प्रयोग गरिन्छ तर अन्य अनुप्रयोगहरूद्वारा प्रयोग गर्न नसकिने पनि हुन सक्छ।"</string>
+    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"ब्राउजरले HTTP प्रोक्सी प्रयोग गर्छ तर अन्य अनुप्रयोगले यसको प्रयोग नगर्न पनि सक्छन्।"</string>
     <string name="proxy_url_title" msgid="882042361706435904">"PAC URL: "</string>
     <string name="radio_info_dl_kbps" msgid="2903778264453410272">"DL ब्यान्डविथ (kbps):"</string>
     <string name="radio_info_ul_kbps" msgid="3802245899811732716">"UL व्यान्डविथ (kbps):"</string>
@@ -238,7 +237,7 @@
     <string name="radio_info_http_client_test" msgid="781411599778629953">"HTTP क्लाइन्टको परीक्षण:"</string>
     <string name="ping_test_label" msgid="4759194831308897624">"पिङ सम्बन्धी परीक्षण सञ्चालन गर्नुहोस्"</string>
     <string name="radio_info_smsc_label" msgid="4561160340649588034">"SMSC:"</string>
-    <string name="radio_info_smsc_update_label" msgid="3992739670219389246">"अद्यावधिक गर्नुहोस्"</string>
+    <string name="radio_info_smsc_update_label" msgid="3992739670219389246">"अपडेट गर्नुहोस्"</string>
     <string name="radio_info_smsc_refresh_label" msgid="5343925292858337909">"पुनःताजा गर्नुहोस्"</string>
     <string name="radio_info_toggle_dns_check_label" msgid="3058615074503857400">"DNS को जाँचलाई टगल गर्नुहोस्"</string>
     <string name="oem_radio_info_label" msgid="8679815523111164378">"OEM-विशिष्ट जानकारी/सेटिङहरू"</string>
@@ -248,13 +247,13 @@
     <string name="band_mode_failed" msgid="8350123391471974137">"असफल"</string>
     <string name="band_mode_succeeded" msgid="5516613616395402809">"सफलता"</string>
     <string name="sdcard_changes_instructions" msgid="4138217393448114001">"जब USB तार पुन|जडित हुन्छ तब परिवर्तनहरू प्रभावकारी हुन्छन्।"</string>
-    <string name="sdcard_settings_screen_mass_storage_text" msgid="7486030250999007641">"USB ठूलो भण्डारण सक्रिय गर्नुहोस्"</string>
+    <string name="sdcard_settings_screen_mass_storage_text" msgid="7486030250999007641">"USB ठुलो भण्डारण सक्रिय गर्नुहोस्"</string>
     <string name="sdcard_settings_total_bytes_label" msgid="6461741874400909157">"कूल बाइट्स:"</string>
     <string name="sdcard_settings_not_present_status" product="nosdcard" msgid="5419085128792417589">"USB भण्डारण माउन्ट गरिएको छैन।"</string>
     <string name="sdcard_settings_not_present_status" product="default" msgid="5831286239151349794">"कुनै SD कार्ड छैन।"</string>
     <string name="sdcard_settings_available_bytes_label" msgid="2392868635606041278">"उपलब्ध बाइटहरू:"</string>
-    <string name="sdcard_settings_mass_storage_status" product="nosdcard" msgid="5888349723543445382">"USB भण्डारण एउटा ठूलो भण्डारण उपकरणको रूपमा प्रयोग भएको छ।"</string>
-    <string name="sdcard_settings_mass_storage_status" product="default" msgid="637014061735266364">"SD कार्डलाई एउटा ठूलो भण्डारण उपकरणको रूपमा प्रयोग गरिरहिएको छ।"</string>
+    <string name="sdcard_settings_mass_storage_status" product="nosdcard" msgid="5888349723543445382">"USB भण्डारण एउटा ठुलो भण्डारण उपकरणको रूपमा प्रयोग भएको छ।"</string>
+    <string name="sdcard_settings_mass_storage_status" product="default" msgid="637014061735266364">"SD कार्डलाई एउटा ठुलो भण्डारण उपकरणको रूपमा प्रयोग गरिरहिएको छ।"</string>
     <string name="sdcard_settings_unmounted_status" product="nosdcard" msgid="1489916516292644696">"अब USB भण्डारण मेटाउन सुरक्षित छ।"</string>
     <string name="sdcard_settings_unmounted_status" product="default" msgid="6250598657624241686">"अब SD कार्ड हटाउन सुरक्षित छ।"</string>
     <string name="sdcard_settings_bad_removal_status" product="nosdcard" msgid="4694941967864756404">"अझै प्रयोग भइरहेको बेलामा USB भण्डारण हटाइएयो।"</string>
@@ -276,7 +275,7 @@
     <string name="dlg_remove_locales_message" msgid="5179370688876343176">"पाठ अर्को भाषामा प्रदर्शन हुनेछ।"</string>
     <string name="dlg_remove_locales_error_title" msgid="9090578326002163975">"सबै भाषाहरूलाई हटाउन सक्दैन"</string>
     <string name="dlg_remove_locales_error_message" msgid="6799897638891903618">"कम्तीमा एउटा रुचाइएको भाषालाई राख्नुहोस्"</string>
-    <string name="locale_not_translated" msgid="7943669576006420058">"केही अनुप्रयोगहरूमा उपलब्ध नहुन सक्छ"</string>
+    <string name="locale_not_translated" msgid="7943669576006420058">"केही एपहरूमा उपलब्ध नहुन सक्छ"</string>
     <string name="action_drag_label_move_up" msgid="2074064283966078352">"माथि सार्नुहोस्"</string>
     <string name="action_drag_label_move_down" msgid="1367989732445492291">"तल सार्नुहोस्"</string>
     <string name="action_drag_label_move_top" msgid="2033098833739345957">"माथिल्लो भागमा सार्नुहोस्"</string>
@@ -296,7 +295,7 @@
     <string name="save" msgid="3418211178410498517">"सुरक्षित गर्नुहोस्"</string>
     <string name="done" msgid="5143229467535372339">"सम्पन्न भयो"</string>
     <string name="apply" msgid="951230399613164126">"लागू गर्नुहोस्"</string>
-    <string name="share" msgid="3567029787293158575">"आदान प्रदान गर्नुहोस्"</string>
+    <string name="share" msgid="3567029787293158575">"सेयर गर्नुहोस्"</string>
     <string name="add" msgid="903114118076816060">"थप्नुहोस्"</string>
     <string name="settings_label" msgid="7263237773415875813">"सेटिङहरू"</string>
     <string name="settings_label_launcher" msgid="500627679902923496">"सेटिङहरू"</string>
@@ -365,14 +364,14 @@
     <string name="owner_info_settings_status" msgid="8049975536717685126">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="COUNT_1">%2$d</xliff:g>"</string>
     <string name="owner_info_settings_edit_text_hint" msgid="2250029417257939706">"उदाहरण, Joe को Android।"</string>
     <string name="user_info_settings_title" msgid="1125111518759995748">"प्रयोगकर्ता जानकारी"</string>
-    <string name="show_profile_info_on_lockscreen_label" msgid="5204282771893683026">"लक स्क्रिनमा प्रोफाइल जानकारी देखाउनुहोस्"</string>
-    <string name="profile_info_settings_title" msgid="4855892878512562551">"प्रोफाइल जानकारी"</string>
+    <string name="show_profile_info_on_lockscreen_label" msgid="5204282771893683026">"लक स्क्रिनमा प्रोफाइलको जानकारी देखाउनुहोस्"</string>
+    <string name="profile_info_settings_title" msgid="4855892878512562551">"प्रोफाइलको जानकारी"</string>
     <string name="Accounts_settings_title" msgid="7901374987121953746">"खाताहरू"</string>
     <string name="location_settings_title" msgid="2707201457572301030">"स्थान"</string>
     <string name="location_settings_master_switch_title" msgid="3108016866082816733">"स्थान प्रयोग गर्नुहोस्"</string>
     <string name="location_settings_summary_location_off" msgid="5563530256978372978">"निष्क्रिय"</string>
     <plurals name="location_settings_summary_location_on" formatted="false" msgid="7893342914540884818">
-      <item quantity="other">सक्रिय - <xliff:g id="COUNT_1">%1$d</xliff:g> अनुप्रयोगहरूले स्थानमाथि पहुँच राख्न सक्छन्‌</item>
+      <item quantity="other">सक्रिय - <xliff:g id="COUNT_1">%1$d</xliff:g> एपहरूले स्थानमाथि पहुँच राख्न सक्छन्‌</item>
       <item quantity="one">सक्रिय - <xliff:g id="COUNT_0">%1$d</xliff:g> अनुप्रयोगले स्थानमाथि पहुँच राख्न सक्छ</item>
     </plurals>
     <string name="location_settings_loading_app_permission_stats" msgid="7818169326621327628">"लोड गर्दै…"</string>
@@ -402,16 +401,16 @@
     <string name="security_settings_face_enroll_introduction_cancel" msgid="4190924649721437238">"रद्द गर्नुहोस्"</string>
     <string name="security_settings_face_enroll_introduction_title" msgid="6073249653318265486">"आफ्नो अनुहारमार्फत अनलक गर्नु…"</string>
     <string name="security_settings_face_enroll_introduction_title_unlock_disabled" msgid="9223270521083202896">"प्रमाणीकरण गर्न आफ्नो अनुहार प्रयोग गर्नु…"</string>
-    <string name="security_settings_face_enroll_introduction_message" msgid="484806903869220184">"आफ्नो फोन अनलक गर्न, खरिद अधिकार दिन वा अनुप्रयोगहरूमा साइन इन गर्न आफ्नो अनुहार प्रयोग गर्नुहोस्।"</string>
+    <string name="security_settings_face_enroll_introduction_message" msgid="484806903869220184">"आफ्नो फोन अनलक गर्न, खरिद अधिकार दिन वा एपहरूमा साइन इन गर्न आफ्नो अनुहार प्रयोग गर्नुहोस्।"</string>
     <string name="security_settings_face_enroll_introduction_message_unlock_disabled" msgid="2850101281254663082">"तपाईंको फोन अनलक वा खरिदहरूको अनुमोदन गर्न आफ्ना अनुहारको प्रयोग गर्नुहोस्।\n\nटिपोट: तपाईं यो यन्त्र अनलक गर्न आफ्नो अनुहारको प्रयोग गर्न सक्नुहुन्न। थप जानकारीका लागि आफ्नो सङ्गठनको प्रशासकसँग सम्पर्क गर्नुहोस्।"</string>
-    <string name="security_settings_face_enroll_introduction_message_setup" msgid="4533297059466270074">"आफ्नो फोन अनलक गर्न, खरिद अधिकार दिन वा अनुप्रयोगहरूमा साइन इन गर्न आफ्नो अनुहार प्रयोग गर्नुहोस्"</string>
+    <string name="security_settings_face_enroll_introduction_message_setup" msgid="4533297059466270074">"आफ्नो फोन अनलक गर्न, खरिद अधिकार दिन वा एपहरूमा साइन इन गर्न आफ्नो अनुहार प्रयोग गर्नुहोस्"</string>
     <string name="security_settings_face_enroll_introduction_footer_message" msgid="7764021721107723266"></string>
     <string name="security_settings_face_enroll_repeat_title" msgid="2507710348140837875">"आफ्नो अनुहार वृतको बिचमा पार्नुहोस्"</string>
     <string name="security_settings_face_enroll_enrolling_skip" msgid="4346077260378772613">"यो कार्य पछि गर्नुहोस्‌"</string>
     <string name="face_add_max" msgid="8870899421165189413">"तपाईं अधिकतम <xliff:g id="COUNT">%d</xliff:g> अनुहारहरू थप्न सक्नुहुन्छ"</string>
     <string name="face_intro_error_max" msgid="4024147799079828937">"तपाईंले थप्न मिल्ने अधिकतम सङ्ख्या बराबरका अनुहारहरू थप्नुभएको छ"</string>
     <string name="face_intro_error_unknown" msgid="3241592604198351134">"थप अनुहारहरू थप्न सकिँदैन"</string>
-    <string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"दर्ता गर्ने कार्य पूर्ण भएन"</string>
+    <string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"फिंगरप्रिन्ट सेभ भइसकेको छैन"</string>
     <string name="security_settings_face_enroll_dialog_ok" msgid="1078348922734845090">"ठिक छ"</string>
     <string name="security_settings_face_enroll_error_timeout_dialog_message" msgid="4917894418448325405">"अनुहार दर्ताको समय सीमा पुग्यो। फेरि प्रयास गर्नुहोस्।"</string>
     <string name="security_settings_face_enroll_error_generic_dialog_message" msgid="5160473187142616862">"अनुहार दर्ता गर्ने प्रक्रियाले काम गरेन।"</string>
@@ -419,15 +418,15 @@
     <string name="security_settings_face_enroll_done" msgid="5409739233373490971">"सम्पन्न भयो"</string>
     <string name="security_settings_face_settings_use_face_category" msgid="1586532139528115416">"निम्न प्रयोजनमा आफ्नो अनुहार प्रयोग गर्नु…"</string>
     <string name="security_settings_face_settings_use_face_unlock_phone" msgid="318274519126401671">"तपाईंको यन्त्र अनलक गर्दै"</string>
-    <string name="security_settings_face_settings_use_face_for_apps" msgid="5479369083370664351">"अनुप्रयोगको साइन इन र भुक्तानी"</string>
+    <string name="security_settings_face_settings_use_face_for_apps" msgid="5479369083370664351">"एपको साइन इन र भुक्तानी"</string>
     <string name="security_settings_face_settings_require_attention" msgid="2755140150841557225">"अनलक गर्न आँखा खुल्ला छन्"</string>
     <string name="security_settings_face_settings_require_attention_details" msgid="2557060433599942587">"अनुहारको प्रमाणीकरण प्रयोग गर्दा तपाईंका आँखा खुल्ला हुनै पर्छ"</string>
     <string name="security_settings_face_settings_require_confirmation" msgid="7312024271060416438">"सधैँ पुष्टि गर्न आवश्यक पर्छ"</string>
-    <string name="security_settings_face_settings_require_confirmation_details" msgid="8740564864091803429">"अनुप्रयोगहरूमा प्रमाणीकरण गर्दा सधैँ पुष्टि गर्न आवश्यक पर्छ"</string>
+    <string name="security_settings_face_settings_require_confirmation_details" msgid="8740564864091803429">"एपहरूमा प्रमाणीकरण गर्दा सधैँ पुष्टि गर्न आवश्यक पर्छ"</string>
     <string name="security_settings_face_settings_remove_face_data" msgid="2821359954483136239">"अनुहारसम्बन्धी डेटा हटाउनुहोस्"</string>
     <string name="security_settings_face_settings_footer" msgid="4627175759990550715">"तपाईंको यन्त्र अनलक गर्न र अनुप्रयोगहरूमाथि पहुँच राख्न तपाईंको अनुहार प्रयोग गर्न सकिन्छ। "<annotation id="url">"थप जान्नुहोस्"</annotation></string>
     <string name="security_settings_face_settings_remove_dialog_title" msgid="5675319895815271094">"अनुहारसम्बन्धी डेटा मेट्ने हो?"</string>
-    <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"फेस अनलक गर्ने सुविधामार्फत रेकर्ड गरिएको डेटा स्थायी रूपमा र सुरक्षित रूपमा मेटिने छ। हटाइसकेपछि, आफ्नो फोन अनलक गर्न, अनुप्रयोगहरूमा साइन इन गर्न र भुक्तानी पुष्टि गर्न तपाईंसँग आफ्नो PIN, ढाँचा वा पासवर्ड हुनु पर्ने छ।"</string>
+    <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"फेस अनलक गर्ने सुविधामार्फत रेकर्ड गरिएको डेटा स्थायी रूपमा र सुरक्षित रूपमा मेटिने छ। हटाइसकेपछि, आफ्नो फोन अनलक गर्न, एपहरूमा साइन इन गर्न र भुक्तानी पुष्टि गर्न तपाईंसँग आफ्नो PIN, ढाँचा वा पासवर्ड हुनु पर्ने छ।"</string>
     <string name="security_settings_fingerprint_preference_title" msgid="4177132225930582928">"औंठाछाप"</string>
     <string name="fingerprint_manage_category_title" msgid="1463406696801542090">"औंठाछापहरू व्यवस्थापन गर्नुहोस्"</string>
     <string name="fingerprint_usage_category_title" msgid="7298369141954599706">"निम्नको लागि औठाछाप प्रयोग गर्नुहोस्"</string>
@@ -440,7 +439,7 @@
     <string name="security_settings_fingerprint_preference_summary_none" msgid="3613424536269750172"></string>
     <string name="security_settings_fingerprint_enroll_introduction_title" msgid="889558002683900544">"फिंगरप्रिन्टमार्फत अनलक"</string>
     <string name="security_settings_fingerprint_enroll_introduction_title_unlock_disabled" msgid="7915504118657864429">"आफ्नो फिंगरप्रिन्टको प्रयोग गर्नुहोस्"</string>
-    <string name="security_settings_fingerprint_enroll_introduction_message" msgid="5586198131986682472">"आफ्नो फोन अनलक गर्न, खरिदहरूका लागि अनुमति दिन वा अनुप्रयोगहरूमा साइन इन गर्न फिंगरप्रिन्ट सेन्सरलाई केवल छुनुहोस्। तपाईं कसका फिंगरप्रिन्टहरू थप्दै हुनुहुन्छ भन्ने कुरामा सावधान रहनुहोस्। थपिएको एउटै फिंगरप्रिन्टले यी मध्ये कुनै कुरा गर्न सक्छ।\n\nतपाईंको फिंगरप्रिन्ट कुनै बलियो ढाँचा वा PIN भन्दा कम सुरक्षित हुन सक्छ।"</string>
+    <string name="security_settings_fingerprint_enroll_introduction_message" msgid="5586198131986682472">"आफ्नो फोन अनलक गर्न, खरिदहरूका लागि अनुमति दिन वा एपहरूमा साइन इन गर्न फिंगरप्रिन्ट सेन्सरलाई केवल छुनुहोस्। तपाईं कसका फिंगरप्रिन्टहरू थप्दै हुनुहुन्छ भन्ने कुरामा सावधान रहनुहोस्। थपिएको एउटै फिंगरप्रिन्टले यी मध्ये कुनै कुरा गर्न सक्छ।\n\nतपाईंको फिंगरप्रिन्ट कुनै बलियो ढाँचा वा PIN भन्दा कम सुरक्षित हुन सक्छ।"</string>
     <string name="security_settings_fingerprint_enroll_introduction_message_unlock_disabled" msgid="1640839304679275468">"तपाईंको फोन अनलक वा खरिदहरूको अनुमोदन गर्न आफ्ना फिंगरप्रिन्टहरूको प्रयोग गर्नुहोस्।\n\nटिपोट: तपाईं यो यन्त्र अनलक गर्न आफ्नो फिंगरप्रिन्टको प्रयोग गर्न सक्नुहुन्न। थप जानकारीका लागि आफ्नो संगठनको प्रशासकलाई सम्पर्क गर्नुहोस्।"</string>
     <string name="security_settings_fingerprint_enroll_introduction_message_setup" msgid="6734490666593320711">"तपाईंको फोन अनलक वा खरिदहरूको अनुमोदन गर्न आफ्नो फिंगरप्रिन्ट प्रयोग गर्नुहोस्।\n\nटिपोट: तपाईंको फिंगरप्रिन्ट भरपर्दो ढाँचा वा PIN भन्दा कम सुरक्षित हुनसक्छ।"</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel" msgid="9168637333731599827">"रद्द गर्नुहोस्"</string>
@@ -471,7 +470,7 @@
     <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"औंला उठाई फेरि छुनुहोस्"</string>
     <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"तपाईंको फिंगरप्रिन्टका फरक-फरक भागहरू थप्न आफ्नो औंलालाई उठाउँदै राख्दै गर्नुहोस्"</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"फिंगरप्रिन्ट थपियो"</string>
-    <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"तपाईंले यस आइकनलाई देख्नुहुँदा पहिचानका लागि वा खरिदहरूको अनुमोदन गर्न आफ्नो फिंगरप्रिन्ट प्रयोग गर्नुहोस्‌"</string>
+    <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"यो आइकन देख्दा आफ्नो पहिचान दिन वा खरिदहरूको अनुमोदन गर्न आफ्नो फिंगरप्रिन्ट प्रयोग गर्नुहोस्‌"</string>
     <string name="security_settings_fingerprint_enroll_enrolling_skip" msgid="1473280156532146933">"यसलाई पछि गर्नुहोस्‌"</string>
     <string name="setup_fingerprint_enroll_enrolling_skip_title" msgid="2816424026528101690">"फिंगरप्रिन्ट सेटअप छोड्न चाहनुहुन्छ?"</string>
     <string name="setup_fingerprint_enroll_enrolling_skip_message" msgid="8139299964344809780">"तपाईँले आफ्नो फोन अनलक गर्ने एक तरिका रूपमा फिंगरप्रिन्ट छान्‍नुभएको छ। यदि तपाईँले अहिले छोड्नु भएमा पछि पुन: सेटअप गर्न पर्नेछ। सेटअप गर्न मात्र केहि मिनेट लाग्‍नेछ।"</string>
@@ -488,12 +487,12 @@
     <string name="security_settings_fingerprint_enroll_done" msgid="4111289529758845926">"सम्पन्न भयो"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"आच्यौं, त्यो सेन्सर होइन नि त"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"तपाईंको फोनको पछाडि भागमा रहेको सेन्सरमा छुनुहोस्। चोर औंला प्रयोग गर्नुहोस्‌।"</string>
-    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"दर्ता पूर्ण भएको थिएन"</string>
+    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"फिंगरप्रिन्ट सेभ भइसकेको छैन"</string>
     <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"फिंगरप्रिन्ट दर्ताको समय सीमा पुग्यो। पुन: प्रयास गर्नुहोस्।"</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"फिंगरप्रिन्ट दर्ताले काम गरेन। पुन: प्रयास गर्नुहोस् वा अरू औँलाको प्रयोग गर्नुहोस्।"</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"अर्को थप्नुहोस्"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"अर्को"</string>
-    <string name="security_settings_fingerprint_enroll_disclaimer" msgid="5831834311961551423">"तपाईँले आफ्नो फोन खोल्नका अतिरिक्त खरिद र अनुप्रयोग पहुँच प्राधिकरण गर्नाका लागि पनि आफ्नो फिंगरप्रिन्ट प्रयोग गर्न सक्नुहुन्छ। "<annotation id="url">"थप जान्नुहोस्"</annotation></string>
+    <string name="security_settings_fingerprint_enroll_disclaimer" msgid="5831834311961551423">"तपाईँले आफ्नो फोन खोल्नका अतिरिक्त खरिद र एप पहुँच प्राधिकरण गर्नाका लागि पनि आफ्नो फिंगरप्रिन्ट प्रयोग गर्न सक्नुहुन्छ। "<annotation id="url">"थप जान्नुहोस्"</annotation></string>
     <string name="security_settings_fingerprint_enroll_disclaimer_lockscreen_disabled" msgid="7954742554236652690">" स्क्रिन लकको विकल्प असक्षम पारिएको छ। थप जान्नलाई आफ्नो सङ्गठनको प्रशासकलाई सम्पर्क गर्नुहोस्। "<annotation id="admin_details">"थप विवरणहरू"</annotation>\n\n"तपाईं खरिदहरूलाई अधिकार दिन र अनुप्रयोगमाथि पहुँच पाउनका लागि आफ्नो फिंगरप्रिन्ट समेत प्रयोग गर्न सक्नुहुन्छ। "<annotation id="url">"थप जान्नुहोस्"</annotation></string>
     <string name="security_settings_fingerprint_enroll_lift_touch_again" msgid="1670703069782212223">"औँला उठाई, फेरि सेंसर छुनुहोस्"</string>
     <string name="fingerprint_add_max" msgid="2939393314646115661">"तपाईं <xliff:g id="COUNT">%d</xliff:g> सम्म फिंगरप्रिन्टहरू थप्न सक्नुहुन्छ"</string>
@@ -502,15 +501,15 @@
     <string name="fingerprint_last_delete_title" msgid="3104596858161269635">"सबै फिंगरप्रिन्टहरू हटाउने हो?"</string>
     <string name="fingerprint_delete_title" msgid="3120894112324235536">"\'<xliff:g id="FINGERPRINT_ID">%1$s</xliff:g>\' हटाउनुहोस्‌"</string>
     <string name="fingerprint_delete_message" msgid="5895802741486967970">"तपाईं यो फिंगरप्रिन्ट मेट्न चाहनुहुन्छ?"</string>
-    <string name="fingerprint_last_delete_message" msgid="3346252479778971442">"तपाईं फोन अनलक गर्न, खरिद अधिकार प्रदान गर्न वा तिनीहरूमार्फत अनुप्रयोगहरूमा साइन इन गर्नाका लागि तपाईं आफ्नो फिंगरप्रिन्टहरूको प्रयोग गर्न सक्षम हुनु हुने छैन।"</string>
-    <string name="fingerprint_last_delete_message_profile_challenge" msgid="5385095150532247025">"तपाईं आफ्नो कार्य प्रोफाइल अनलक गर्न, खरिद गर्ने अनुमति दिन, वा कार्यसँग सम्बन्धित अनुप्रयोगहरूमा साइन इन गर्नाका लागि आफ्नो फिंगरप्रिन्ट प्रयोग गर्न सक्नुहुने छैन।"</string>
+    <string name="fingerprint_last_delete_message" msgid="3346252479778971442">"फोन अनलक गर्न, खरिद अधिकार प्रदान गर्न वा एपहरूमा साइन इन गर्न तपाईं आफ्ना फिंगरप्रिन्टहरूको प्रयोग गर्न सक्नु हुने छैन।"</string>
+    <string name="fingerprint_last_delete_message_profile_challenge" msgid="5385095150532247025">"तपाईं आफ्नो कार्य प्रोफाइल अनलक गर्न, खरिद गर्ने अनुमति दिन, वा कार्यसँग सम्बन्धित एपहरूमा साइन इन गर्नाका लागि आफ्नो फिंगरप्रिन्ट प्रयोग गर्न सक्नुहुने छैन।"</string>
     <string name="fingerprint_last_delete_confirm" msgid="7984595457589664004">"हो, हटाउनुहोस्"</string>
     <string name="crypt_keeper_settings_title" msgid="839783588093862748">"एन्क्रिप्सन"</string>
     <string name="crypt_keeper_encrypt_title" product="tablet" msgid="2292129135369853167">"इन्क्रिप्ट ट्याब्लेट"</string>
     <string name="crypt_keeper_encrypt_title" product="default" msgid="3110852053238357832">"फोन इन्क्रिप्ट गर्नुहोस्"</string>
     <string name="crypt_keeper_encrypted_summary" msgid="2438498691741626642">"इन्क्रिप्ट गरिएको"</string>
-    <string name="crypt_keeper_desc" product="tablet" msgid="9142792050252407734">"तपाईं आफ्नो खाताहरू, सेटिङहरू, डाउनलोड गरिएका अनुप्रयोगहरू र तिनीहरूको डेटा, मिडिया, र अन्य फाइलहरू इन्क्रिप्ट गर्न सक्नुहुन्छ। आफ्नो ट्याब्लेट इन्क्रिप्ट गरेपछि, स्क्रिन लक सेट गरिएको मानेर (यो कि, नमुना वा संख्यात्मक PIN वा पासवर्ड), तपाईंले संचालन गर्दा हरेक समय ट्याब्लेटको इन्क्रिप्ट उल्टाइ बन्द खोल्न आवश्यक छ। इन्क्रिप्ट उल्टाउने मात्र अन्य तरिका, आफ्नो सबै डेटा मेटाएर फ्याक्ट्री डेटा रिसेट गर्नुपर्छ।\n\nइन्क्रिप्ट गर्न एक घन्टा वा बढी समय लाग्छ। प्रक्रिया अवधिभरमा ट्याब्लेट तपाईंले चार्ज भएको ब्याट्रिको साथ सुरु गरि र प्लग इन गरिराख्नुपर्छ। यदि कार्यमा अवरोध भयो भने तपाईंले केही वा सबै डेटा गुमाउनुहुन्छ।"</string>
-    <string name="crypt_keeper_desc" product="default" msgid="1996334685607444282">"तपाईं आफ्नो खाताहरू, सेटिङहरू, डाउनलोड गरिएका अनुप्रयोगहरू र तिनीहरूको डेटा, मिडिया, र अन्य फाइलहरू इन्क्रिप्ट गर्न सक्नुहुन्छ। आफ्नो फोन इन्क्रिप्ट गरेपछि, स्क्रिन लक सेट गरिएको मानेर (यो कि, नमुना वा संख्यात्मक PIN वा पासवर्ड), तपाईंले संचालन गर्दा हरेक समय फोनको इन्क्रिप्ट उल्टाइ बन्द खोल्न आवश्यक छ। इन्क्रिप्ट उल्टाउने मात्र अन्य तरिका, आफ्नो सबै डेटा मेटाएर फ्याक्ट्री डेटा रिसेट गर्नुपर्छ।\n\nइन्क्रिप्ट गर्न एक घन्टा वा बढी समय लाग्छ। प्रक्रिया अवधिभरमा फोन तपाईंले चार्ज भएको ब्याट्रिको साथ सुरुगरि र प्लग इन गरि राख्नुपर्छ। यदि कार्यमा अवरोध भयो भने तपाईंले केही वा सबै डेटा गुमाउनुहुन्छ।"</string>
+    <string name="crypt_keeper_desc" product="tablet" msgid="9142792050252407734">"तपाईं आफ्नो खाताहरू, सेटिङहरू, डाउनलोड गरिएका एपहरू र तिनीहरूको डेटा, मिडिया, र अन्य फाइलहरू इन्क्रिप्ट गर्न सक्नुहुन्छ। आफ्नो ट्याब्लेट इन्क्रिप्ट गरेपछि, स्क्रिन लक सेट गरिएको मानेर (यो कि, नमुना वा संख्यात्मक PIN वा पासवर्ड), तपाईंले संचालन गर्दा हरेक समय ट्याब्लेटको इन्क्रिप्ट उल्टाइ बन्द खोल्न आवश्यक छ। इन्क्रिप्ट उल्टाउने मात्र अन्य तरिका, आफ्नो सबै डेटा मेटाएर फ्याक्ट्री डेटा रिसेट गर्नुपर्छ।\n\nइन्क्रिप्ट गर्न एक घन्टा वा बढी समय लाग्छ। प्रक्रिया अवधिभरमा ट्याब्लेट तपाईंले चार्ज भएको ब्याट्रिको साथ सुरु गरि र प्लग इन गरिराख्नुपर्छ। यदि कार्यमा अवरोध भयो भने तपाईंले केही वा सबै डेटा गुमाउनुहुन्छ।"</string>
+    <string name="crypt_keeper_desc" product="default" msgid="1996334685607444282">"तपाईं आफ्नो खाताहरू, सेटिङहरू, डाउनलोड गरिएका एपहरू र तिनीहरूको डेटा, मिडिया, र अन्य फाइलहरू इन्क्रिप्ट गर्न सक्नुहुन्छ। आफ्नो फोन इन्क्रिप्ट गरेपछि, स्क्रिन लक सेट गरिएको मानेर (यो कि, नमुना वा संख्यात्मक PIN वा पासवर्ड), तपाईंले संचालन गर्दा हरेक समय फोनको इन्क्रिप्ट उल्टाइ बन्द खोल्न आवश्यक छ। इन्क्रिप्ट उल्टाउने मात्र अन्य तरिका, आफ्नो सबै डेटा मेटाएर फ्याक्ट्री डेटा रिसेट गर्नुपर्छ।\n\nइन्क्रिप्ट गर्न एक घन्टा वा बढी समय लाग्छ। प्रक्रिया अवधिभरमा फोन तपाईंले चार्ज भएको ब्याट्रिको साथ सुरुगरि र प्लग इन गरि राख्नुपर्छ। यदि कार्यमा अवरोध भयो भने तपाईंले केही वा सबै डेटा गुमाउनुहुन्छ।"</string>
     <string name="crypt_keeper_button_text" product="tablet" msgid="7918671468758813824">"ट्याब्लेट इन्क्रिप्ट गर्नुहोस्"</string>
     <string name="crypt_keeper_button_text" product="default" msgid="8737394386627318489">"फोन इन्क्रिप्ट गर्नुहोस्"</string>
     <string name="crypt_keeper_low_charge_text" msgid="1422879728632636311">"तपाईँको ब्याट्री चार्ज गरी पुनःप्रयास गर्नुहोस्।"</string>
@@ -530,8 +529,8 @@
     <string name="crypt_keeper_warn_wipe" msgid="700814581500057050">"चेतावनी: खुला गर्न <xliff:g id="COUNT">^1</xliff:g> भन्दा बढी असफल प्रयासहरू पछि तपाईँको उपकरण पुछिने छ!"</string>
     <string name="crypt_keeper_enter_password" msgid="726933635335219421">"तपाईँको पासवर्ड टाइप गर्नुहोस्"</string>
     <string name="crypt_keeper_failed_title" msgid="1906382607060855782">"इन्क्रिप्सन असफल"</string>
-    <string name="crypt_keeper_failed_summary" product="tablet" msgid="7844833877734529625">"इन्क्रिप्सन अवरूद्ध भयो र पूरा हुन सक्दैन। परिणामस्वरूप तपाईंको ट्याब्लेटको डेटा अब पहुँचयोग्य हुँदैन।\n \n तपाईंको ट्याब्लेटको प्रयोग सुरु गर्नाका लागि तपाईंले कारखाना पुनःसेट गर्नु  पर्छ। जब पुनःसेट हुन्छ तब तपाईं ट्याब्लेट सेट गर्नुहुन्छ, तपाईंको Google खातामा जगेडा गरिएको कुनै पनि डेटा पुनर्स्थापना गर्ने अवसर तपाईंलाई हुने छ।"</string>
-    <string name="crypt_keeper_failed_summary" product="default" msgid="2895589681839090312">"एन्क्रिप्सन रोकिएको थियो र पूरा हुन सकेन। नतिजाको रूपमा तपाईंको फोनमा डेटा पहुँच यग्य छैन। \n\nतपाईंको फोनको उपयोग फरि सुरु गर्नको लागि तपाईंले एउटा फ्याक्ट्रि पुनःसेट गर्न जरुरी छ। जब तपाईं पुनःसेटपछि तपाईंको फोन सेटअप गर्नु हुन्छ भने  कुनै पनि डेटा जुन तपाईंको Google खातामा ब्याकअप गरिएको थियो तपाईंलाई पुनःप्राप्त गर्ने अवसर हुने छ।"</string>
+    <string name="crypt_keeper_failed_summary" product="tablet" msgid="7844833877734529625">"इन्क्रिप्सन अवरूद्ध भयो र पूरा हुन सक्दैन। परिणामस्वरूप तपाईंको ट्याब्लेटको डेटा अब पहुँचयोग्य हुँदैन।\n \n तपाईंको ट्याब्लेटको प्रयोग सुरु गर्नाका लागि तपाईंले कारखाना रिसेट गर्नु  पर्छ। जब रिसेट हुन्छ तब तपाईं ट्याब्लेट सेट गर्नुहुन्छ, तपाईंको Google खातामा जगेडा गरिएको कुनै पनि डेटा पुनर्स्थापना गर्ने अवसर तपाईंलाई हुने छ।"</string>
+    <string name="crypt_keeper_failed_summary" product="default" msgid="2895589681839090312">"एन्क्रिप्सन रोकिएको थियो र पूरा हुन सकेन। नतिजाको रूपमा तपाईंको फोनमा डेटा पहुँच यग्य छैन। \n\nतपाईंको फोनको उपयोग फरि सुरु गर्नको लागि तपाईंले एउटा फ्याक्ट्रि रिसेट गर्न जरुरी छ। जब तपाईं रिसेटपछि तपाईंको फोन सेटअप गर्नु हुन्छ भने  कुनै पनि डेटा जुन तपाईंको Google खातामा ब्याकअप गरिएको थियो तपाईंलाई पुनःप्राप्त गर्ने अवसर हुने छ।"</string>
     <string name="crypt_keeper_data_corrupt_title" msgid="6561535293845985713">"गुप्तिकरण उल्टाउन असफल"</string>
     <string name="crypt_keeper_data_corrupt_summary" product="tablet" msgid="7018748502706237323">"तपाईँले प्रविष्ट गर्नुभएको पासवर्ड ठिक छ, तर दुर्भाग्यबश तपाईँको डेटा बिग्रिएको छ।\n\n तपाईँको ट्याब्लेट पुन: प्रयोग गर्न फ्याक्ट्री रिसेट गर्न पर्छ। रिसेट गरे पश्चात जब तपाई आफ्नो ट्याब्लेट सेटअप गर्नुहुन्छ तपाईँले Google खातामा ब्याकअप भए सम्मका डेटा पुनर्स्थापना गर्ने अवसर प्राप्त गर्नु हुनेछ।"</string>
     <string name="crypt_keeper_data_corrupt_summary" product="default" msgid="5798580588985326937">"तपाईंले प्रविष्ट गर्नुभएको पासवर्ड ठिक छ, तर दुर्भाग्यबश तपाईंको डेटा बिग्रिएको छ।\n\n तपाईंको फोन पुन: प्रयोग गर्न फ्याक्ट्री रिसेट गर्न पर्छ। रिसेट गरे पश्चात जब तपाईं आफ्नो फोन सेटअप गर्नुहुन्छ तपाईंले Google खातामा ब्याकअप भए सम्मका डेटा पुनर्स्थापना गर्ने अवसर प्राप्त गर्नु हुनेछ।"</string>
@@ -599,35 +598,35 @@
     <string name="unlock_disable_frp_warning_content_pattern" msgid="1843950215687159135">"यन्त्र सुरक्षा सुविधाहरू तपाईँको ढाँचा बिना काम गर्ने छैनन्।"</string>
     <string name="unlock_disable_frp_warning_content_pattern_fingerprint" msgid="8846957650251741548">"यन्त्रका सुरक्षासम्बन्धी सुविधाहरूले तपाईंको ढाँचाबिना काम गर्ने छैनन्। <xliff:g id="EMPTY_LINE">
 
-</xliff:g> यस यन्त्रबाट तपाईंका सुरक्षित गरिएका फिंगरप्रिन्टहरू पनि हटाइने छन् र तपाईं तिनीहरूमार्फत आफ्नो फोन अनलक गर्ने, खरिदसम्बन्धी आधिकार प्रदान गर्ने वा अनुप्रयोगहरूमा साइन इन गर्ने कार्यहरू गर्न सक्नुहुनेछैन।"</string>
+</xliff:g> यस यन्त्रबाट तपाईंका सुरक्षित गरिएका फिंगरप्रिन्टहरू पनि हटाइने छन् र तपाईं तिनीहरूमार्फत आफ्नो फोन अनलक गर्ने, खरिदसम्बन्धी आधिकार प्रदान गर्ने वा एपहरूमा साइन इन गर्ने कार्यहरू गर्न सक्नुहुनेछैन।"</string>
     <string name="unlock_disable_frp_warning_content_pin" msgid="6760473271034592796">"यन्त्र सुरक्षा सुविधाहरू तपाईँको PIN बिना काम गर्ने छैनन्।"</string>
     <string name="unlock_disable_frp_warning_content_pin_fingerprint" msgid="4384632309103635233">"यन्त्रका सुरक्षासम्बन्धी सुविधाहरूले तपाईंको PIN बिना काम गर्ने छैनन्। <xliff:g id="EMPTY_LINE">
 
-</xliff:g>यस यन्त्रबाट तपाईंका सुरक्षित गरिएका फिंगरप्रिन्टहरू पनि हटाइने छन् र तपाईं तिनीहरूमार्फत आफ्नो फोन अनलक गर्ने, खरिदसम्बन्धी आधिकार प्रदान गर्ने वा अनुप्रयोगहरूमा साइन इन गर्ने कार्यहरू गर्न सक्नुहुनेछैन।"</string>
+</xliff:g>यस यन्त्रबाट तपाईंका सुरक्षित गरिएका फिंगरप्रिन्टहरू पनि हटाइने छन् र तपाईं तिनीहरूमार्फत आफ्नो फोन अनलक गर्ने, खरिदसम्बन्धी आधिकार प्रदान गर्ने वा एपहरूमा साइन इन गर्ने कार्यहरू गर्न सक्नुहुनेछैन।"</string>
     <string name="unlock_disable_frp_warning_content_password" msgid="854665587186358170">"यन्त्र सुरक्षा सुविधाहरू तपाईँको पासवर्ड बिना काम गर्ने छैनन्।"</string>
     <string name="unlock_disable_frp_warning_content_password_fingerprint" msgid="218143910981979545">"यन्त्रका सुरक्षासम्बन्धी सुविधाहरूले तपाईंको पासवर्डबिना काम गर्ने छैनन्। <xliff:g id="EMPTY_LINE">
 
-</xliff:g> यस यन्त्रबाट तपाईंका सुरक्षित गरिएका फिंगरप्रिन्टहरू पनि हटाइने छन् र तपाईं तिनीहरूमार्फत आफ्नो फोन अनलक गर्ने, खरिदसम्बन्धी आधिकार प्रदान गर्ने वा अनुप्रयोगहरूमा साइन इन गर्ने कार्यहरू गर्न सक्नुहुनेछैन।"</string>
+</xliff:g> यस यन्त्रबाट तपाईंका सुरक्षित गरिएका फिंगरप्रिन्टहरू पनि हटाइने छन् र तपाईं तिनीहरूमार्फत आफ्नो फोन अनलक गर्ने, खरिदसम्बन्धी आधिकार प्रदान गर्ने वा एपहरूमा साइन इन गर्ने कार्यहरू गर्न सक्नुहुनेछैन।"</string>
     <string name="unlock_disable_frp_warning_content_unknown" msgid="3570135744390201244">"यन्त्र सुरक्षा सुविधाहरू तपाईँको स्क्रिन लक बिना काम गर्ने छैनन्।"</string>
     <string name="unlock_disable_frp_warning_content_unknown_fingerprint" msgid="5775815077478538855">"यन्त्रका सुरक्षासम्बन्धी सुविधाहरूले तपाईंको स्क्रिन लकबिना काम गर्ने छैनन्। <xliff:g id="EMPTY_LINE">
 
-</xliff:g>यस यन्त्रबाट तपाईंका सुरक्षित गरिएका फिंगरप्रिन्टहरू पनि हटाइने छन् र तपाईं तिनीहरूमार्फत आफ्नो फोन अनलक गर्ने, खरिदसम्बन्धी आधिकार प्रदान गर्ने वा अनुप्रयोगहरूमा साइन इन गर्ने कार्यहरू गर्न सक्नुहुनेछैन।"</string>
+</xliff:g>यस यन्त्रबाट तपाईंका सुरक्षित गरिएका फिंगरप्रिन्टहरू पनि हटाइने छन् र तपाईं तिनीहरूमार्फत आफ्नो फोन अनलक गर्ने, खरिदसम्बन्धी आधिकार प्रदान गर्ने वा एपहरूमा साइन इन गर्ने कार्यहरू गर्न सक्नुहुनेछैन।"</string>
     <string name="unlock_disable_frp_warning_content_pattern_profile" msgid="2369992898062808499">"प्रोफाइल सुरक्षा विशेषताहरूले तपाईँको ढाँचा बिना काम गर्नेछैनन्।"</string>
     <string name="unlock_disable_frp_warning_content_pattern_fingerprint_profile" msgid="8511105093090018735">"प्रोफाइलका सुरक्षासम्बन्धी सुविधाहरूले तपाईंको ढाँचाबिना काम गर्ने छैनन्।<xliff:g id="EMPTY_LINE">
 
-</xliff:g>यस प्रोफाइलबाट तपाईंका सुरक्षित गरिएका फिंगरप्रिन्टहरू पनि हटाइने छन् र तपाईं तिनीहरूमार्फत आफ्नो प्रोफाइल अनलक गर्ने, खरिदसम्बन्धी अधिकार प्रदान गर्ने वा अनुप्रयोगहरूमा साइन इन गर्ने कार्यहरू सक्नुहुनेछैन।"</string>
+</xliff:g>यस प्रोफाइलबाट तपाईंका सुरक्षित गरिएका फिंगरप्रिन्टहरू पनि हटाइने छन् र तपाईं तिनीहरूमार्फत आफ्नो प्रोफाइल अनलक गर्ने, खरिदसम्बन्धी अधिकार प्रदान गर्ने वा एपहरूमा साइन इन गर्ने कार्यहरू सक्नुहुनेछैन।"</string>
     <string name="unlock_disable_frp_warning_content_pin_profile" msgid="7114165651000498040">"प्रोफाइल सुरक्षा विशेषताहरूले तपाईँको PIN बिना काम गर्नेछैनन्।"</string>
     <string name="unlock_disable_frp_warning_content_pin_fingerprint_profile" msgid="5118210431544156122">"प्रोफाइलका सुरक्षासम्बन्धी सुविधाहरूले तपाईंको PIN बिना काम गर्ने छैनन्।<xliff:g id="EMPTY_LINE">
 
-</xliff:g>यस प्रोफाइलबाट तपाईंका सुरक्षित गरिएका फिंगरप्रिन्टहरू पनि हटाइने छन् र तपाईं तिनीहरूमार्फत आफ्नो प्रोफाइल अनलक गर्ने, खरिदसम्बन्धी अधिकार प्रदान गर्ने वा अनुप्रयोगहरूमा साइन इन गर्ने कार्यहरू गर्न सक्नुहुनेछैन।"</string>
+</xliff:g>यस प्रोफाइलबाट तपाईंका सुरक्षित गरिएका फिंगरप्रिन्टहरू पनि हटाइने छन् र तपाईं तिनीहरूमार्फत आफ्नो प्रोफाइल अनलक गर्ने, खरिदसम्बन्धी अधिकार प्रदान गर्ने वा एपहरूमा साइन इन गर्ने कार्यहरू गर्न सक्नुहुनेछैन।"</string>
     <string name="unlock_disable_frp_warning_content_password_profile" msgid="3989497526180082037">"प्रोफाइल सुरक्षा विशेषताहरूले तपाईँको पासवर्ड बिना काम गर्नेछैनन्।"</string>
     <string name="unlock_disable_frp_warning_content_password_fingerprint_profile" msgid="8360485354164416198">"प्रोफाइलका सुरक्षासम्बन्धी सुविधाहरूले तपाईंको पासवर्डबिना काम गर्ने छैनन्।<xliff:g id="EMPTY_LINE">
 
-</xliff:g>यस प्रोफाइलबाट तपाईंका सुरक्षित गरिएका फिंगरप्रिन्टहरू पनि हटाइने छन् र तपाईं तिनीहरूमार्फत आफ्नो फोन अनलक गर्ने, खरिदसम्बन्धी आधिकार प्रदान गर्ने वा अनुप्रयोगहरूमा साइन इन गर्ने कार्यहरू गर्न सक्नुहुनेछैन।"</string>
+</xliff:g>यस प्रोफाइलबाट तपाईंका सुरक्षित गरिएका फिंगरप्रिन्टहरू पनि हटाइने छन् र तपाईं तिनीहरूमार्फत आफ्नो फोन अनलक गर्ने, खरिदसम्बन्धी आधिकार प्रदान गर्ने वा एपहरूमा साइन इन गर्ने कार्यहरू गर्न सक्नुहुनेछैन।"</string>
     <string name="unlock_disable_frp_warning_content_unknown_profile" msgid="4066001421137974082">"प्रोफाइल सुरक्षा विशेषताहरूले तपाईँको स्क्रिन लक बिना काम गर्नेछैनन्।"</string>
     <string name="unlock_disable_frp_warning_content_unknown_fingerprint_profile" msgid="1201259228331105948">"प्रोफाइलका सुरक्षासम्बन्धी सुविधाहरूले तपाईंको स्क्रिन लकबिना काम गर्ने छैनन्।<xliff:g id="EMPTY_LINE">
 
-</xliff:g>यस प्रोफाइलबाट तपाईंका सुरक्षित गरिएका फिंगरप्रिन्टहरू पनि हटाइने छन् र तपाईं तिनीहरूमार्फत आफ्नो प्रोफाइल अनलक गर्ने, खरिदसम्बन्धी अधिकार प्रदान गर्ने वा अनुप्रयोगहरूमा साइन इन गर्ने कार्यहरू गर्न सक्नुहुनेछैन।"</string>
+</xliff:g>यस प्रोफाइलबाट तपाईंका सुरक्षित गरिएका फिंगरप्रिन्टहरू पनि हटाइने छन् र तपाईं तिनीहरूमार्फत आफ्नो प्रोफाइल अनलक गर्ने, खरिदसम्बन्धी अधिकार प्रदान गर्ने वा एपहरूमा साइन इन गर्ने कार्यहरू गर्न सक्नुहुनेछैन।"</string>
     <string name="unlock_disable_frp_warning_ok" msgid="2373890505202766456">"हो, हटाउनुहोस्"</string>
     <string name="unlock_change_lock_pattern_title" msgid="7622476883851319877">"अनलक ढाँचा बदल्नुहोस्"</string>
     <string name="unlock_change_lock_pin_title" msgid="6671224158800812238">"अनलक PIN परिवर्तन गर्नुहोस्"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">अनिवार्य रूपमा <xliff:g id="NUMBER_1">%d</xliff:g> अङ्कहरू भन्दा कम हुनु पर्छ</item>
       <item quantity="one">अनिवार्य रूपमा <xliff:g id="NUMBER_0">%d</xliff:g> अङ्क भन्दा कम हुनु पर्छ</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"अनिवार्य रूपमा ० देखि ९ सम्मका अङ्कहरू मात्र समावेश हुनु पर्छ"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"यन्त्र प्रशासकले पछिल्लो PIN प्रयोग गर्न अनुमति दिँदैन"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"तपाईंकसे IT व्यवस्थापकले धेरै प्रयोग हुने PIN हरूमाथि रोक लगाउनु भएको छ। कुनै फरक PIN प्रयोग गरी हेर्नुहोस्।"</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"यसमा अमान्य वर्ण समावेश गर्न सकिँदैन"</string>
@@ -685,7 +683,7 @@
     </plurals>
     <plurals name="lockpassword_password_requires_uppercase" formatted="false" msgid="6026476732572657588">
       <item quantity="other">कम्तीमा पनि <xliff:g id="COUNT">%d</xliff:g> वटा ठूला अक्षर हुनु अनिवार्य छ</item>
-      <item quantity="one">कम्तीमा पनि एउटा ठूलो अक्षर हुनु अनिवार्य छ</item>
+      <item quantity="one">कम्तीमा पनि एउटा ठुलो अक्षर हुनु अनिवार्य छ</item>
     </plurals>
     <plurals name="lockpassword_password_requires_numeric" formatted="false" msgid="5072581827825645338">
       <item quantity="other">कम्तीमा पनि <xliff:g id="COUNT">%d</xliff:g> वटा संख्यात्मक अङ्क हुनु अनिवार्य छ</item>
@@ -699,6 +697,10 @@
       <item quantity="other">कम्तीमा पनि <xliff:g id="COUNT">%d</xliff:g> वटा गैर-अक्षर वर्ण हुनु अनिवार्य छ</item>
       <item quantity="one">कम्तीमा पनि एउटा गैर-अक्षर वर्ण हुनु अनिवार्य छ</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">कम्तीमा पनि <xliff:g id="COUNT">%d</xliff:g> गैर-सङ्ख्यात्मक वर्ण हुनु अनिवार्य छ</item>
+      <item quantity="one">कम्तीमा पनि १ गैर-सङ्ख्यात्मक वर्ण हुनु अनिवार्य छ</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"यन्त्रको प्रशासकले पछिल्लो पासवर्ड प्रयोग गर्ने अनुमति दिँदैन"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"तपाईंकसे IT व्यवस्थापकले धेरै प्रयोग हुने पासवर्डहरूमाथि रोक लगाउनु भएको छ। कुनै फरक पासवर्ड प्रयोग गरी हेर्नुहोस्।"</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"बढ्दो, घट्दो वा दोहोरिएका अङ्कहरूको अनुक्रमलाई निषेध गरिएको छ"</string>
@@ -709,14 +711,14 @@
     <string name="lockpattern_tutorial_cancel_label" msgid="450401426127674369">"रद्द गर्नुहोस्"</string>
     <string name="lockpattern_tutorial_continue_label" msgid="8474690922559443018">"अर्को"</string>
     <string name="lock_setup" msgid="8710689848703935088">"सेटअप पूरा भयो।"</string>
-    <string name="manage_device_admin" msgid="322047441168191695">"यन्त्रका प्रशासकीय अनुप्रयोगहरू"</string>
-    <string name="number_of_device_admins_none" msgid="8519193548630223132">"कुनै सक्रिय अनुप्रयोगहरू छैनन्"</string>
+    <string name="manage_device_admin" msgid="322047441168191695">"यन्त्रका प्रशासकीय एपहरू"</string>
+    <string name="number_of_device_admins_none" msgid="8519193548630223132">"कुनै सक्रिय एपहरू छैनन्"</string>
     <plurals name="number_of_device_admins" formatted="false" msgid="6445613288828151224">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> सक्रिय अनुप्रयोगहरू</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> सक्रिय अनुप्रयोग</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> सक्रिय एपहरू</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> सक्रिय एप</item>
     </plurals>
     <string name="manage_trust_agents" msgid="8129970926213142261">"विश्वसनीय प्रतिनिधि"</string>
-    <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"प्रयोग गर्न, पहिले स्क्रिन लक सेट गर्नुहोस्"</string>
+    <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"यो सेवा प्रयोग गर्न, पहिले स्क्रिन लक सेट गर्नुहोस्"</string>
     <string name="manage_trust_agents_summary" msgid="2023116850759962248">"कुनै पनि होइन"</string>
     <plurals name="manage_trust_agents_summary_on" formatted="false" msgid="5550538038916606097">
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> वटा सक्रिय विश्वसनीय एजेन्ट</item>
@@ -764,8 +766,8 @@
     <string name="bluetooth_menu_advanced" msgid="7566858513372603652">"जटिल"</string>
     <string name="bluetooth_advanced_titlebar" msgid="6459469494039004784">"जटिल ब्लुटुथ"</string>
     <string name="bluetooth_empty_list_bluetooth_off" msgid="6255367297830430459">"ब्लुटुथ खोलेको बेला तपाईँको उपकरणले नजिकैका अन्य ब्लुटुथ उपकरणहरूसँग संचार गर्न सक्छन्।"</string>
-    <string name="bluetooth_scanning_on_info_message" msgid="5460370815156050550">"ब्लुटुथ सक्रिय गरिएको बेला तपाईंको यन्त्र वरपरका अन्य ब्लुटुथ यन्त्रहरूसँग सञ्चार गर्न सक्नुहुन्छ।, \n\nअनुभवमा सुधार गर्न अनुप्रयोग तथा सेवाहरू अझै पनि जुनसुकै बेला (ब्लुटुथ निष्क्रिय भएको बेलामा पनि) वरपरका यन्त्रहरू स्क्यान गर्न सक्छन्। यसलाई स्थानमा आधारित सुविधा तथा सेवाहरू सुधार गर्ने जस्ता कार्यहरू गर्नका लागि प्रयोग गर्न सकिन्छ। तपाईं "<annotation id="link">"स्क्यानिङसम्बन्धी सेटिङहरू"</annotation>" मा गई यसलाई परिवर्तन गर्न सक्नुहुन्छ।"</string>
-    <string name="ble_scan_notify_text" msgid="6290170236546386932">"स्थान पहिचान सामर्थ्यतामा सुधार गर्न, प्रणाली अनुप्रयोगहरू र सेवाहरूले अझै पनि ब्लुटुथ यन्त्रहरूलाई पहिचान गर्न सक्छन्। तपाईँले यसलाई  <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g> स्क्यानिङ सेटिङहरू <xliff:g id="LINK_END_1">LINK_END</xliff:g> मा परिवर्तन गर्न सक्नुहुन्छ।"</string>
+    <string name="bluetooth_scanning_on_info_message" msgid="5460370815156050550">"ब्लुटुथ सक्रिय गरिएको बेला तपाईंको यन्त्र वरपरका अन्य ब्लुटुथ यन्त्रहरूसँग सञ्चार गर्न सक्नुहुन्छ।, \n\nअनुभवमा सुधार गर्न एप तथा सेवाहरू अझै पनि जुनसुकै बेला (ब्लुटुथ निष्क्रिय भएको बेलामा पनि) वरपरका यन्त्रहरू स्क्यान गर्न सक्छन्। यसलाई स्थानमा आधारित सुविधा तथा सेवाहरू सुधार गर्ने जस्ता कार्यहरू गर्नका लागि प्रयोग गर्न सकिन्छ। तपाईं "<annotation id="link">"स्क्यानिङसम्बन्धी सेटिङहरू"</annotation>" मा गई यसलाई परिवर्तन गर्न सक्नुहुन्छ।"</string>
+    <string name="ble_scan_notify_text" msgid="6290170236546386932">"स्थान पहिचान सामर्थ्यतामा सुधार गर्न, प्रणाली एपहरू र सेवाहरूले अझै पनि ब्लुटुथ यन्त्रहरूलाई पहिचान गर्न सक्छन्। तपाईँले यसलाई  <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g> स्क्यानिङ सेटिङहरू <xliff:g id="LINK_END_1">LINK_END</xliff:g> मा परिवर्तन गर्न सक्नुहुन्छ।"</string>
     <string name="bluetooth_connect_failed" msgid="1151234676456333786">"जडान गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
     <string name="device_details_title" msgid="726517818032923222">"यन्त्रसम्बन्धी विवरणहरू"</string>
     <string name="bluetooth_device_mac_address" msgid="5328203122581150405">"यन्त्रको ब्लुटुथ ठेगाना: <xliff:g id="ADDRESS">%1$s</xliff:g>"</string>
@@ -820,17 +822,17 @@
     <string name="art_verifier_for_debuggable_summary" msgid="2204242476996701111">"ART लाई डिबग गर्न मिल्ने अनुप्रयोगहरूको बाइटकोड पुष्टि गर्न दिनुहोस्"</string>
     <string name="nfc_quick_toggle_title" msgid="4990697912813795002">"NFC"</string>
     <string name="nfc_quick_toggle_summary" product="tablet" msgid="983451155092850657">"ट्याब्लेटले कुनै अन्य उपकरणलाई छुँदा डेटा विनिमयको अनुमति दिनुहोस्।"</string>
-    <string name="nfc_quick_toggle_summary" product="default" msgid="7141056939052895142">"फोनले अर्को उपकरणलाई छुँदा डेटा विनिमयलाई अनुमति दिनुहोस्"</string>
+    <string name="nfc_quick_toggle_summary" product="default" msgid="7141056939052895142">"फोनले अर्को उपकरणलाई छुँदा डेटा एक अर्कामा सर्ने अनुमति दिनुहोस्"</string>
     <string name="nfc_disclaimer_title" msgid="4860231267351602970">"NFC सक्रिय गर्नुहोस्"</string>
     <string name="nfc_disclaimer_content" msgid="3066113577854565782">"NFC ले यो यन्त्र र भुक्तानीको टर्मिनल, पहुँच सम्बन्धी रिडर र अन्तरक्रियात्मक विज्ञापन वा ट्यागहरू जस्ता अन्य नजिकका यन्त्र वा लक्ष्यहरू बीच डेटा आदानप्रदान गर्छ।"</string>
     <string name="nfc_secure_settings_title" msgid="5153751163174916581">"NFC सुरक्षित पार्नुहोस्"</string>
     <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"स्क्रिन अनलक भएका बेलामा मात्र NFC भुक्तानी र ट्रान्जिटको प्रयोगलाई अनुमति दिनुहोस्"</string>
     <string name="android_beam_settings_title" msgid="3083436415873738389">"एन्ड्रोइड बिम"</string>
-    <string name="android_beam_on_summary" msgid="8068287225180474199">"NFCको माध्यमबाट अनुप्रयोग सामग्री प्रसारित गर्नको लागि तयार"</string>
+    <string name="android_beam_on_summary" msgid="8068287225180474199">"NFCको माध्यमबाट एप सामग्री प्रसारित गर्नको लागि तयार"</string>
     <string name="android_beam_off_summary" msgid="7365818039159364600">"बन्द"</string>
     <string name="nfc_disabled_summary" msgid="2181777971122724361">"NFC निष्क्रिय पारिएका कारण उपलब्ध छैन"</string>
     <string name="android_beam_label" msgid="5340299879556025708">"एन्ड्रोइड बिम"</string>
-    <string name="android_beam_explained" msgid="4501176353247859329">"यो सुविधा सक्रिय पारिएको बेला तपाईं यन्त्रहरूलाई आपसमा नजिक राखेर अनुप्रयोगको सामग्री अर्को NFC सक्षम यन्त्रमा बिम गर्न सक्नुहुन्छ। उदाहरणका लागि तपाईं वेबपृष्ठ, YouTube का भिडियो, सम्पर्क र अरू थुप्रै कुराहरू बिम गर्न सक्नुहुन्छ।\n\nयसको लागि केवल यन्त्रहरूलाई (सामान्यता दुवै यन्त्रको पछाडिको भाग) आपसमा नजिक ल्याउनुहोस् र त्यसपछि आफ्नो यन्त्रको स्क्रिनमा ट्याप गर्नुहोस्। बिम हुने कुरा अनुप्रयोगले निर्धारण गर्दछ।"</string>
+    <string name="android_beam_explained" msgid="4501176353247859329">"यो सुविधा सक्रिय पारिएको बेला तपाईं यन्त्रहरूलाई आपसमा नजिक राखेर एपको सामग्री अर्को NFC सक्षम यन्त्रमा बिम गर्न सक्नुहुन्छ। उदाहरणका लागि तपाईं वेबपृष्ठ, YouTube का भिडियो, सम्पर्क र अरू थुप्रै कुराहरू बिम गर्न सक्नुहुन्छ।\n\nयसको लागि केवल यन्त्रहरूलाई (सामान्यता दुवै यन्त्रको पछाडिको भाग) आपसमा नजिक ल्याउनुहोस् र त्यसपछि आफ्नो यन्त्रको स्क्रिनमा ट्याप गर्नुहोस्। बिम हुने कुरा अनुप्रयोगले निर्धारण गर्दछ।"</string>
     <string name="wifi_quick_toggle_title" msgid="7935778388625246184">"Wi-Fi"</string>
     <string name="wifi_quick_toggle_summary" msgid="2879870570547594266">"Wi-Fi खोल्नुहोस्"</string>
     <string name="wifi_settings" msgid="7486492317310514109">"Wi-Fi"</string>
@@ -855,11 +857,11 @@
     <string name="wifi_poor_network_detection_summary" msgid="5539951465985614590">"Wi-Fi नेटवर्कमा राम्रो इन्टरनेट जडान उपलब्ध नभएसम्म प्रयोग नगर्नुहोस्"</string>
     <string name="wifi_avoid_poor_network_detection_summary" msgid="1976503191780928104">"राम्रो इन्टरनेट जडान हुने नेटवर्क मात्र प्रयोग गर्नुहोस्"</string>
     <string name="use_open_wifi_automatically_title" msgid="3084513215481454350">"खुला नेटवर्कहरूमा जडान गर्नुहोस्"</string>
-    <string name="use_open_wifi_automatically_summary" msgid="8338020172673161754">"उच्च गुणस्तरको सार्वजनिक नेटवर्कहरूमा स्वतः जडान गर्नुहोस्"</string>
+    <string name="use_open_wifi_automatically_summary" msgid="8338020172673161754">"द्रूत इन्टरनेट भएका सार्वजनिक नेटवर्कहरूमा स्वतः कनेक्ट गर्नुहोस्"</string>
     <string name="use_open_wifi_automatically_summary_scoring_disabled" msgid="1559329344492373028">"प्रयोग गर्न कुनै नेटवर्क मूल्याङ्कनसम्बन्धी प्रदायक चयन गर्नुहोस्"</string>
     <string name="use_open_wifi_automatically_summary_scorer_unsupported_disabled" msgid="1123080670578756834">"प्रयेाग गर्न कुनै उपयुक्त नेटवर्क मूल्याङ्कनसम्बन्धी प्रदायक चयन गर्नुहोस्"</string>
     <string name="wifi_install_credentials" msgid="5650088113710858289">"प्रमाणपत्रहरू स्थापना गर्नुहोस्"</string>
-    <string name="wifi_scan_notify_text" msgid="7614101215028336927">"स्थानको सटीकतामा सुधार गर्न, अनुप्रयोग तथा सेवाहरूले अझै पनि जुनसुकै बेला (Wi‑Fi निष्क्रिय भएको बेलामा पनि) Wi‑Fi नेटवर्क स्क्यान गर्न सक्छ। यसलाई स्थानमा आधारित सुविधा तथा सेवाहरूमा सुधार गर्ने जस्ता कार्यहरू गर्नाका लागि प्रयोग गर्न सकिन्छ। तपाईं यसलाई <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>स्क्यानिङ सेटिङहरू<xliff:g id="LINK_END_1">LINK_END</xliff:g> मा परिवर्तन गर्न सक्नुहुन्छ।"</string>
+    <string name="wifi_scan_notify_text" msgid="7614101215028336927">"स्थानको सटीकतामा सुधार गर्न, एप तथा सेवाहरूले अझै पनि जुनसुकै बेला (Wi‑Fi निष्क्रिय भएको बेलामा पनि) Wi‑Fi नेटवर्क स्क्यान गर्न सक्छन्। यसलाई स्थानमा आधारित सुविधा तथा सेवाहरूमा सुधार गर्ने जस्ता कार्यहरू गर्नका लागि प्रयोग गर्न सकिन्छ। तपाईं यसलाई <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>स्क्यानिङ सेटिङहरू<xliff:g id="LINK_END_1">LINK_END</xliff:g> मा परिवर्तन गर्न सक्नुहुन्छ।"</string>
     <string name="wifi_scan_notify_text_scanning_off" msgid="723796963816095410">"स्थानसम्बन्धी सटीकतामा सुधार गर्न <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>स्क्यानिङ सम्बन्धी सेटिङहरू<xliff:g id="LINK_END_1">LINK_END</xliff:g> मा गई Wi-Fi स्क्यान गर्ने सेवालाई सक्रिय गर्नुहोस्।"</string>
     <string name="wifi_scan_notify_remember_choice" msgid="1235445971400237444">"फेरि नदेखाउनुहोस्"</string>
     <string name="wifi_setting_sleep_policy_title" msgid="2120785188625932076">"सुतेको बेलामा Wi-Fi खुला राख्नुहोस्"</string>
@@ -878,7 +880,7 @@
     <string name="wifi_configure_settings_preference_summary_wakeup_off" msgid="286904094152909651">"Wi‑Fi स्वत: पुनः सक्रिय हुँदैन"</string>
     <string name="wifi_access_points" msgid="1647976498906871869">"Wi-Fi नेटवर्कहरू"</string>
     <string name="wifi_menu_more_options" msgid="8318269834264035524">"थप विकल्पहरू"</string>
-    <string name="wifi_menu_p2p" msgid="4945665601551289791">"Wi-Fi प्रत्यक्ष"</string>
+    <string name="wifi_menu_p2p" msgid="4945665601551289791">"Wi-fi Direct"</string>
     <string name="wifi_menu_scan" msgid="9082691677803181629">"स्क्यान"</string>
     <string name="wifi_menu_advanced" msgid="5984484498045511072">"जटिल"</string>
     <string name="wifi_menu_configure" msgid="52192491120701266">"कन्फिगर गर्नुहोस्"</string>
@@ -887,26 +889,26 @@
     <string name="wifi_menu_forget" msgid="7561140554450163075">"सञ्जाल बिर्सनुहोस्"</string>
     <string name="wifi_menu_modify" msgid="4080178040721021101">"नेटवर्क परिमार्जन गर्नुहोस्"</string>
     <string name="wifi_empty_list_wifi_off" msgid="272877164691346240">"उपलब्ध नेटवर्कहरू हेर्नको लागि Wi-Fi खुला गर्नुहोस्।"</string>
-    <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"Wi-Fi सञ्जालका लागि खोज्दै ..."</string>
+    <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">" Wi-Fi नेटवर्क खोज्दै ..."</string>
     <string name="wifi_empty_list_user_restricted" msgid="2341613007817352431">"Wi-Fi सञ्जाल बदल्न तपाईँसँग अनुमति छैन।"</string>
     <string name="wifi_more" msgid="3538241640407382185">"बढी"</string>
     <string name="wifi_setup_wps" msgid="6730131677695521321">"स्वचालित सेटअप (WPS)"</string>
     <string name="wifi_settings_scanning_required_title" msgid="3593457187659922490">"Wi‑Fi स्क्यान गर्ने सुविधा सक्रिय गर्ने हो?"</string>
     <string name="wifi_settings_scanning_required_summary" msgid="7469610959462708782">"Wi‑Fi स्वतः सक्रिय गर्न तपाईंले सर्वप्रथम Wi‑Fi स्क्यान गर्ने सुविधालाई सक्रिय गर्नु पर्ने हुन्छ।"</string>
-    <string name="wifi_settings_scanning_required_info" msgid="5913535073390607386">"Wi-Fi स्क्यान गर्ने सुविधाले अनुप्रयोग र सेवाहरूलाई Wi‑Fi निष्क्रिय भएको बेलालगायत जुनसुकै बेला वरपरका Wi-Fi नेटवर्कहरू स्क्यान गर्ने अनुमति दिन्छ। उदाहरणका लागि यसलाई स्थानमा आधारित सुविधा तथा सेवाहरूको सुधार गर्नका लागि प्रयोग गर्न सकिन्छ।"</string>
+    <string name="wifi_settings_scanning_required_info" msgid="5913535073390607386">"Wi-Fi स्क्यान गर्ने सुविधाले एप र सेवाहरूलाई Wi‑Fi निष्क्रिय भएको बेलालगायत जुनसुकै बेला वरपरका Wi-Fi नेटवर्कहरू स्क्यान गर्ने अनुमति दिन्छ। उदाहरणका लागि यसलाई स्थानमा आधारित सुविधा तथा सेवाहरूको सुधार गर्नका लागि प्रयोग गर्न सकिन्छ।"</string>
     <string name="wifi_settings_scanning_required_turn_on" msgid="4327570180594277049">"सक्रिय गर्नुहोस्"</string>
     <string name="wifi_settings_scanning_required_enabled" msgid="3336102100425307040">"Wi‑Fi स्क्यान गर्ने सेवा सक्रिय छ"</string>
     <string name="wifi_show_advanced" msgid="8199779277168030597">"उन्नत विकल्पहरू"</string>
     <string name="wifi_advanced_toggle_description_expanded" msgid="1506697245302596510">"ड्रप डाउन सूचीका उन्नत विकल्पहरू। संक्षिप्त गर्न डबल-ट्याप गर्नुहोस्।"</string>
     <string name="wifi_advanced_toggle_description_collapsed" msgid="3014965593695454879">"ड्रप डाउन सूचीका उन्नत विकल्पहरू। विस्तृत गर्न डबल-ट्याप गर्नुहोस्।"</string>
-    <string name="wifi_ssid" msgid="6746270925975522641">"सञ्जाल नाम"</string>
+    <string name="wifi_ssid" msgid="6746270925975522641">"नेटवर्कको नाम"</string>
     <string name="wifi_ssid_hint" msgid="5010024648106585165">"SSID प्रविष्टि गर्नुहोस्"</string>
     <string name="wifi_security" msgid="9136702039496152831">"सुरक्षा"</string>
     <string name="wifi_hidden_network" msgid="6647772204699776833">"लुकाइएको नेटवर्क"</string>
     <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"यदि तपाईंको राउटरले कुनै नेटवर्कको ID प्रसारण गरिरहेको छैन तर तपाईं भविष्यमा यसमा जडान गर्न चाहनुहुन्छ भने, तपाईं उक्त नेटवर्कलाई लुकाइएको रूपमा सेट गर्न सक्नुहुन्छ।\n\n तपाईंको फोनले नेटवर्क फेला पार्नका लागि नियमित रूपमा आफ्नो सिग्नल प्रसारण गर्ने हुँदा यसले सुरक्षासम्बन्धी जोखिम सिर्जना गर्न सक्छ।\n\nनेटवर्कलाई लुकाइएको रूपमा सेट गर्नुले तपाईंको राउटरको सेटिङ परिवर्तन गर्ने छैन।"</string>
-    <string name="wifi_signal" msgid="696548364467704808">"सङ्केत क्षमता"</string>
+    <string name="wifi_signal" msgid="696548364467704808">"सिग्नलको क्षमता"</string>
     <string name="wifi_status" msgid="3439931558930689940">"वस्तुस्थिति"</string>
-    <string name="tx_wifi_speed" msgid="2571810085003261073">"लिंकको गति ट्रान्समिट गर्नुहोस्"</string>
+    <string name="tx_wifi_speed" msgid="2571810085003261073">"लिंक पठाउने गति"</string>
     <string name="rx_wifi_speed" msgid="7392873246110937187">"लिंक प्राप्त गर्ने गति"</string>
     <string name="wifi_frequency" msgid="6132852924995724246">"आवृत्ति"</string>
     <string name="wifi_ip_address" msgid="5572539114989914831">"IP ठेगाना"</string>
@@ -917,7 +919,7 @@
     <string name="wifi_eap_ca_cert" msgid="1496395241849383785">"CA प्रमाणपत्र"</string>
     <string name="wifi_eap_domain" msgid="3298302320003640130">"डोमेन"</string>
     <string name="wifi_eap_user_cert" msgid="6786839531765719173">"प्रयोगकर्ता प्रमाणपत्र"</string>
-    <string name="wifi_eap_identity" msgid="5280457017705738773">"पहिचान गर्नुहोस्"</string>
+    <string name="wifi_eap_identity" msgid="5280457017705738773">"पहिचान"</string>
     <string name="wifi_eap_anonymous" msgid="6352344972490839958">"अज्ञात पहिचान"</string>
     <string name="wifi_password" msgid="6942983531275177771">"पासवर्ड:"</string>
     <string name="wifi_show_password" msgid="7878398590772942202">"पासवर्ड देखाउनुहोस्"</string>
@@ -925,7 +927,7 @@
     <string name="wifi_ap_choose_auto" msgid="7927637960569365785">"स्वतः निर्धारित"</string>
     <string name="wifi_ap_choose_2G" msgid="43198403259714736">"2.4 GHz ब्यान्ड"</string>
     <string name="wifi_ap_choose_5G" msgid="2624859713183683146">"५.० GHz ब्यान्ड"</string>
-    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"५.० GHz ब्यान्ड रुचाइयो"</string>
+    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"५.० GHz ब्यान्ड भए राम्रो"</string>
     <string name="wifi_ap_2G" msgid="5793110086517338494">"२.४ GHz"</string>
     <string name="wifi_ap_5G" msgid="4584892544393675403">"५.० GHz"</string>
     <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"Wi‑Fi हटस्पटका लागि कम्तीमा एक ब्यान्ड छनौट गर्नुहोस्:"</string>
@@ -933,12 +935,12 @@
     <string name="wifi_privacy_settings" msgid="4462092795794247809">"गोपनीयता"</string>
     <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"अनियमित MAC"</string>
     <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"कुनै यन्त्र थप्नुहोस्"</string>
-    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"उक्त यन्त्रलाई “<xliff:g id="SSID">%1$s</xliff:g>” मा यन्त्र थप्न तलको QR कोडलाई मध्य भागमा राख्नुहोस्"</string>
+    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"उक्त यन्त्रलाई “<xliff:g id="SSID">%1$s</xliff:g>” मा थप्न तलको QR कोडलाई मध्य भागमा पार्नुहोस्"</string>
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"QR कोड स्क्यान गर्नुहोस्"</string>
     <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"“<xliff:g id="SSID">%1$s</xliff:g>” मा जडान गर्न तलको QR कोडलाई मध्य भागमा राख्नुहोस्"</string>
-    <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"QR कोड स्क्यान गरी Wi‑Fi मा सामेल हुनुहोस्"</string>
-    <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Wi‑Fi साझा रूपमा प्रयोग गर्नुहोस्"</string>
-    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"“<xliff:g id="SSID">%1$s</xliff:g>” मा जडान गर्न यो QR कोड स्क्यान गर्नुहोस् र पासवर्ड आदान प्रदान गर्नुहोस्"</string>
+    <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">" Wi‑Fi जोड्न QR कोड स्क्यान गर्नुहोस्"</string>
+    <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Wi‑Fi सेयर गर्नुहोस्"</string>
+    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"“<xliff:g id="SSID">%1$s</xliff:g>” मा कनेक्ट गर्न र पासवर्ड सेयर गर्न यो QR कोड स्क्यान गर्नुहोस्"</string>
     <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"“<xliff:g id="SSID">%1$s</xliff:g>” मा जडान गर्न QR कोड स्क्यान गर्नुहोस्"</string>
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"QR कोड पढ्न सकिएन। कोडलाई पुनः केन्द्रमा ल्याउनुहोस् र फेरि प्रयास गर्नुहोस्"</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"फेरि प्रयास गर्नुहोस्। समस्या यथावत् रहिरहेमा यन्त्रका निर्मातासँग सम्पर्क गर्नुहोस्"</string>
@@ -957,14 +959,14 @@
     <string name="wifi_dpp_device_found" msgid="6488461467496850841">"यन्त्र भेटियो"</string>
     <string name="wifi_dpp_sharing_wifi_with_this_device" msgid="2540529164687476827">"यो सेवामार्फत Wi‑Fi आदान प्रदान गर्दै…"</string>
     <string name="wifi_dpp_connecting" msgid="4229290407210299897">"जडान गर्दै…"</string>
-    <string name="wifi_dpp_share_hotspot" msgid="847987212473038179">"हटस्पट आदान प्रदान गर्नुहोस्"</string>
+    <string name="wifi_dpp_share_hotspot" msgid="847987212473038179">"हटस्पट सेयर गर्नुहोस्"</string>
     <string name="wifi_dpp_lockscreen_title" msgid="3910665850075275963">"यो तपाईं नै हो भन्ने पुष्टि गर्नुहोस्"</string>
     <string name="wifi_dpp_wifi_password" msgid="8007558344032612455">"Wi-Fi को पासवर्ड: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
     <string name="wifi_dpp_hotspot_password" msgid="6172326289042241924">"हटस्पटको पासवर्ड: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
     <string name="wifi_dpp_add_device" msgid="1347056725253936358">"यन्त्र थप्नुहोस्"</string>
     <string name="wifi_dpp_connect_network_using_qr_code" msgid="115993715600532357">"कुनै QR कोड प्रयोग गरी यस नेटवर्कमा जोड्नुहोस्"</string>
     <string name="retry" msgid="8500839563577344702">"पुनः प्रयास गर्नु…"</string>
-    <string name="wifi_shared" msgid="5054256778276524960">"अन्य यन्त्र प्रयोगकर्ताहरूसँग साझेदारी गर्नुहोस्"</string>
+    <string name="wifi_shared" msgid="5054256778276524960">"अन्य यन्त्र प्रयोगकर्ताहरूसँग सेयर गर्नुहोस्"</string>
     <string name="wifi_unchanged" msgid="6804964646942333992">"(अपरिवर्तित)"</string>
     <string name="wifi_unspecified" msgid="893491188483500809">"कृपया चयन गर्नुहोस्"</string>
     <string name="wifi_multiple_cert_added" msgid="7986200585749147204">"(बहु प्रमाणपत्रहरू थपिए)"</string>
@@ -973,7 +975,7 @@
     <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"प्रमाणित नगर्नुहोस्"</string>
     <string name="wifi_do_not_validate_eap_server_warning" msgid="3895397996759837323">"कुनै प्रमाणपत्र निर्दिष्ट गरिएको छैन। तपाईंको जडान निजी हुने छैन।"</string>
     <string name="wifi_ssid_too_long" msgid="34911971389775920">"नेटवर्कको नाम धेरै लामो भयो।"</string>
-    <string name="wifi_no_domain_warning" msgid="735859919311067606">"डोमेन निर्दिष्ट गर्नुपर्छ"</string>
+    <string name="wifi_no_domain_warning" msgid="735859919311067606">"डोमेन तोक्नु पर्छ"</string>
     <string name="wifi_wps_available_first_item" msgid="3221671453930485243">"WPS उपलब्ध छ"</string>
     <string name="wifi_wps_available_second_item" msgid="5703265526619705185">" (WPS उपलब्ध)"</string>
     <string name="wifi_carrier_connect" msgid="7202618367339982884">"सेवा प्रदायकको Wi‑Fi नेटवर्क"</string>
@@ -986,9 +988,9 @@
     <string name="wifi_hotspot_message" msgid="6762452611090766607">"<xliff:g id="APP_NAME">%1$s</xliff:g> सञ्जाल जड्न पहिले अनलाइनमा हस्ताक्षर गर्न आवश्यक।"</string>
     <string name="wifi_hotspot_connect" msgid="409079339360849653">"CONNECT"</string>
     <string name="no_internet_access_text" msgid="7093326244145734504">"यो नेटवर्कसँग इन्टरनेटमाथि पहुँच छैन। जडान भइरहने हो?"</string>
-    <string name="partial_connectivity_text" msgid="2142157808079235684">"इन्टरनेट जडान सीमित हुँदा कतिपय अनुप्रयोग तथा सेवाहरूले काम नगर्न सक्छन्। अघि बढ्नुहोस्"</string>
+    <string name="partial_connectivity_text" msgid="2142157808079235684">"इन्टरनेट जडान सीमित हुँदा कतिपय एप तथा सेवाहरूले काम नगर्न सक्छन्। अघि बढ्नुहोस्"</string>
     <string name="no_internet_access_remember" msgid="1368137189939004202">"यस नेटवर्कको लागि फेरि नसोध्नुहोस्"</string>
-    <string name="lost_internet_access_title" msgid="1061916948695946130">"Wi-Fi इन्टरनेटमा जडान भएको छैन"</string>
+    <string name="lost_internet_access_title" msgid="1061916948695946130">"Wi-Fi इन्टरनेटमा कनेक्ट भएको छैन"</string>
     <string name="lost_internet_access_text" msgid="8962010031520731813">"Wi-Fi को जडान खराब हुँदा तपाईं मोबाइल नेटवर्कमा स्विच गर्न सक्नुहुन्छ। डेटा उपयोग शुल्कहरू लाग्न सक्छन्।"</string>
     <string name="lost_internet_access_switch" msgid="9218006455779873700">"मोबाइलमा स्विच गर्नुहोस्"</string>
     <string name="lost_internet_access_cancel" msgid="6577871064062518744">"Wi‑Fi मा कायम रहनुहोस्"</string>
@@ -1018,11 +1020,11 @@
     <string name="wifi_advanced_ssid_title" msgid="4229741334913894856">"SSID"</string>
     <string name="wifi_advanced_mac_address_title" msgid="1162782083754021737">"म्याक ठेगाना"</string>
     <string name="wifi_advanced_ip_address_title" msgid="2708185994512829071">"IP ठेगाना"</string>
-    <string name="wifi_details_title" msgid="2164042631550920157">"नेटवर्कसम्बन्धी विवरणहरू"</string>
+    <string name="wifi_details_title" msgid="2164042631550920157">"नेटवर्कको विवरण"</string>
     <string name="wifi_details_subnet_mask" msgid="53396707004763012">"सबनेट मास्क"</string>
     <string name="wifi_details_dns" msgid="1118251455740116559">"DNS"</string>
     <string name="wifi_details_ipv6_address_header" msgid="1642310137145363299">"IPv6 ठेगानाहरू"</string>
-    <string name="wifi_saved_access_points_label" msgid="3790693285928292563">"सुरक्षित सञ्जालहरू"</string>
+    <string name="wifi_saved_access_points_label" msgid="3790693285928292563">"सेभ गरिएका नेटवर्कहरू"</string>
     <string name="wifi_subscribed_access_points_tab" msgid="7498765485953257229">"सदस्यताहरू"</string>
     <!-- no translation found for wifi_saved_access_points_tab (4677730543624191122) -->
     <skip />
@@ -1038,7 +1040,7 @@
     <string name="wifi_dns2" msgid="1905876166783761641">"DNS 2"</string>
     <string name="wifi_gateway" msgid="7455334454444443397">"गेटवे"</string>
     <string name="wifi_network_prefix_length" msgid="1941206966133010633">"नेटवर्क उपसर्ग लम्बाइ"</string>
-    <string name="wifi_p2p_settings_title" msgid="3213180637906683308">"Wi-Fi प्रत्यक्ष"</string>
+    <string name="wifi_p2p_settings_title" msgid="3213180637906683308">"Wi-fi Direct"</string>
     <string name="wifi_p2p_device_info" msgid="4717490498956029237">"उपकरण जानकारी"</string>
     <string name="wifi_p2p_persist_network" msgid="1110453878886476660">"यस जडानलाई सम्झनुहोस्"</string>
     <string name="wifi_p2p_menu_search" msgid="8207638860263805291">"उपकरणहरू खोजी गर्नुहोस्"</string>
@@ -1066,8 +1068,8 @@
     <string name="wifi_hotspot_password_title" msgid="4289338152595154889">"हटस्पटको पासवर्ड"</string>
     <string name="wifi_hotspot_ap_band_title" msgid="3485744480410441949">"AP ब्यान्ड"</string>
     <string name="wifi_hotspot_footer_info_regular" msgid="3876006922622827363">"आफ्ना अन्य यन्त्रहरूका लागि Wi‑Fi नेटवर्क सिर्जना गर्न हटस्पट प्रयोग गर्नुहोस्। हटस्पटले तपाईंको मोबाइल डेटा जडान प्रयोग गरेर इन्टरनेट प्रदान गर्दछ। अतिरिक्त मोबाइल डेटाको शुल्क लाग्न सक्छ।"</string>
-    <string name="wifi_hotspot_footer_info_local_only" msgid="3339582350894639261">"अनुप्रयोगहरूले नजिकैका यन्त्रहरूसँग सामग्री आदान प्रदान गर्न एउटा हटस्पट सिर्जना गर्न सक्छन्।"</string>
-    <string name="wifi_hotspot_auto_off_title" msgid="7416022590415189590">"Wi‑Fi हटस्पट स्वतः निष्क्रिय पार्नुहोस्"</string>
+    <string name="wifi_hotspot_footer_info_local_only" msgid="3339582350894639261">"एपहरूले नजिकैका यन्त्रहरूसँग सामग्री आदान प्रदान गर्न एउटा हटस्पट सिर्जना गर्न सक्छन्।"</string>
+    <string name="wifi_hotspot_auto_off_title" msgid="7416022590415189590">"स्वतः Wi‑Fi हटस्पट अफ गर्नुहोस्"</string>
     <string name="wifi_hotspot_auto_off_summary" msgid="3866769400624802105">"कुनै पनि यन्त्र जडान नहुँदा Wi‑Fi हटस्पट स्वतः निष्क्रिय हुनेछ"</string>
     <string name="wifi_tether_starting" msgid="7676952148471297900">"हटस्पट खुल्दै..."</string>
     <string name="wifi_tether_stopping" msgid="7478561853791953349">"हटस्पट बन्द गरिँदै..."</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"मोबाइल"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Wi‑Fi उपलब्ध छैन भने मोबाइल नेटवर्क प्रयोग गर्नुहोस्"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"मोबाइल नेटवर्क उपलब्ध नभएमा Wi‑Fi प्रयोग गर्नुहोस्"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Wi‑Fi मार्फत कल गर्नुहोस्। Wi‑Fi नेटवर्कले काम गरेन भने सम्पर्क विच्छेद हुने छ।"</string>
@@ -1169,7 +1174,7 @@
     <string name="color_mode_title" msgid="8164858320869449142">"रङहरू"</string>
     <string name="color_mode_option_natural" msgid="1292837781836645320">"प्राकृतिक"</string>
     <string name="color_mode_option_boosted" msgid="453557938434778933">"बुस्ट गरिएको"</string>
-    <string name="color_mode_option_saturated" msgid="7758384943407859851">"परिपूर्ण पारिएको"</string>
+    <string name="color_mode_option_saturated" msgid="7758384943407859851">"स्याचुरेटेड"</string>
     <string name="color_mode_option_automatic" msgid="6572718611315165117">"अनुकूलनीय"</string>
     <string name="color_mode_summary_natural" msgid="1247153893843263340">"सही रङहरू मात्र प्रयोग गर्नुहोस्"</string>
     <string name="color_mode_summary_automatic" msgid="6066740785261330514">"स्पष्ट र सही रङहरूबीच समायोजन गर्नुहोस्"</string>
@@ -1224,7 +1229,7 @@
     <string name="night_display_summary_on_auto_mode_custom" msgid="2200631112239399233">"<xliff:g id="ID_1">%1$s</xliff:g> मा स्वतः निष्क्रिय हुनेछ"</string>
     <string name="night_display_summary_on_auto_mode_twilight" msgid="8386769601369289561">"सूर्योदयको बेला स्वतः निष्क्रिय हुनेछ"</string>
     <string name="night_display_activation_on_manual" msgid="8379477527072027346">"अहिले नै सक्रिय गर्नुहोस्"</string>
-    <string name="night_display_activation_off_manual" msgid="7776082151269794201">"अहिले नै निष्क्रिय पार्नुहोस्"</string>
+    <string name="night_display_activation_off_manual" msgid="7776082151269794201">"अहिले नै अफ गर्नुहोस्"</string>
     <string name="night_display_activation_on_twilight" msgid="5610294051700287249">"सूर्योदयसम्म सक्रिय गर्नुहोस्"</string>
     <string name="night_display_activation_off_twilight" msgid="6846727701281556110">"सूर्यास्तसम्म निष्क्रिय पार्नुहोस्"</string>
     <string name="night_display_activation_on_custom" msgid="4761140206778957611">"<xliff:g id="ID_1">%1$s</xliff:g> सम्म सक्रिय गर्नुहोस्"</string>
@@ -1244,7 +1249,7 @@
     <string name="screensaver_settings_summary_either_long" msgid="6078038506795498288">"चार्ज वा डक गरिरहँदा"</string>
     <string name="screensaver_settings_summary_either_short" msgid="2453772128682850053">"कुनै"</string>
     <string name="screensaver_settings_summary_sleep" msgid="6097363596749362692">"चार्ज हुँदा"</string>
-    <string name="screensaver_settings_summary_dock" msgid="6297808146601570196">"डक भएको बेला"</string>
+    <string name="screensaver_settings_summary_dock" msgid="6297808146601570196">"डक गरिएको बेला"</string>
     <string name="screensaver_settings_summary_never" msgid="3995259444981620707">"कहिल्यै पनि होइन"</string>
     <string name="screensaver_settings_summary_off" msgid="6119947316484763131">"बन्द"</string>
     <string name="screensaver_settings_disabled_prompt" msgid="1897518064782596947">"फोन डकमा र/वा शयन अवस्थामा हुँदा हुने कुरालाई नियन्त्रण गर्न स्क्रिन सेभरलाई सक्रिय गर्नुहोस्।"</string>
@@ -1261,7 +1266,7 @@
     <string name="doze_always_on_title" msgid="8555184965031789941">"सधैँ सक्रिय"</string>
     <string name="doze_always_on_summary" msgid="7654436900436328950">"समय, सूचनाका आइकनहरू र अन्य जानकारी देखाउनुहोस्। ब्याट्रीको बढेको उपयोग।"</string>
     <string name="title_font_size" msgid="5021464556860010851">"फन्ट आकार"</string>
-    <string name="short_summary_font_size" msgid="4141077908728522946">"पाठ सन्देश अझ ठूलो वा सानो पार्नुहोस्"</string>
+    <string name="short_summary_font_size" msgid="4141077908728522946">"पाठ सन्देश अझ ठुलो वा सानो पार्नुहोस्"</string>
     <string name="sim_lock_settings" msgid="1986924650622642189">"SIM कार्ड लक सेटिङहरू"</string>
     <string name="sim_lock_settings_category" msgid="1126759898277681516">"सिमकार्ड लक"</string>
     <string name="sim_lock_settings_summary_off" msgid="348656447968142307">"निष्क्रिय छ"</string>
@@ -1349,7 +1354,7 @@
     <string name="status_data_state" msgid="4538705798873861963">"मोबाइल सञ्जाल वस्तुस्थिति"</string>
     <string name="status_esim_id" msgid="9201767073386770286">"EID"</string>
     <string name="status_service_state" msgid="4406215321296496234">"सेवा स्थिति"</string>
-    <string name="status_signal_strength" msgid="4302597886933728789">"सङ्केत क्षमता"</string>
+    <string name="status_signal_strength" msgid="4302597886933728789">"सिग्नलको क्षमता"</string>
     <string name="status_roaming" msgid="5191044997355099561">"रोमिङ"</string>
     <string name="status_operator" msgid="6017986100643755390">"सञ्जाल"</string>
     <string name="status_wifi_mac_address" msgid="3868452167971295995">"Wi-Fi म्याक ठेगाना"</string>
@@ -1364,7 +1369,7 @@
     <string name="memory_available_read_only" msgid="9125440204248584531">"उपलब्ध (केवल पढ्नका लागि मात्र)"</string>
     <string name="memory_size" msgid="6637939229251056764">"जम्मा ठाउँ"</string>
     <string name="memory_calculating_size" msgid="8407591625479256510">"गणना गर्दै ..."</string>
-    <string name="memory_apps_usage" msgid="1886814780760368266">"अनुप्रयोग &amp; अनुप्रयोग डेटा"</string>
+    <string name="memory_apps_usage" msgid="1886814780760368266">"एप &amp; एप डेटा"</string>
     <string name="memory_media_usage" msgid="2744652206722240527">"मिडिया"</string>
     <string name="memory_downloads_usage" msgid="7039979723012065168">"डाउनलोडहरू"</string>
     <string name="memory_dcim_usage" msgid="599009211606524732">"तस्बिरहरू, भिडियोहरू"</string>
@@ -1384,14 +1389,14 @@
     <string name="sd_format" product="nosdcard" msgid="918370986254863144">"USB भण्डारण मेटाउनुहोस्"</string>
     <string name="sd_format" product="default" msgid="1346245995138883960">"SD कार्ड मेटाउनुहोस्"</string>
     <string name="sd_format_summary" product="nosdcard" msgid="1179857727779521920">"आन्तरिक USB भण्डारणमा सम्पूर्ण डेटाहरू मेटाउँछ, जस्तै सङ्गीत र तस्बिरहरू"</string>
-    <string name="sd_format_summary" product="default" msgid="4284028411908176234">"SD कार्डमा सबै डेटा जस्तै सङ्गीत र फोटाहरू मेटाउँछ"</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="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>
-    <string name="dlg_confirm_unmount_text" product="nosdcard" msgid="1423648405874813948">"यदि तपाईँले USB भण्डारण अनमाउन्ट गर्नु भयो भने फेरि तपाईँले USB भण्डारण पुनः माउन्ट नगरेसम्म  तपाईँले चलाउनु भएका केही अनुप्रयोगहरू अनुपलब्ध हुन सक्छन्।"</string>
-    <string name="dlg_confirm_unmount_text" product="default" msgid="4099391737780732622">"यदि तपाईँले SD कार्ड अनमाउन्ट गर्नु भयो भने फेरि तपाईँले SD कार्ड पुनःमाउन्ट नगरेसम्म  तपाईँले चलाउनु भएका केही अनुप्रयोगहरू अनुपलब्ध हुन सक्छन्।"</string>
+    <string name="dlg_confirm_unmount_text" product="nosdcard" msgid="1423648405874813948">"यदि तपाईँले USB भण्डारण अनमाउन्ट गर्नु भयो भने फेरि तपाईँले USB भण्डारण पुनः माउन्ट नगरेसम्म  तपाईँले चलाउनु भएका केही एपहरू अनुपलब्ध हुन सक्छन्।"</string>
+    <string name="dlg_confirm_unmount_text" product="default" msgid="4099391737780732622">"यदि तपाईँले SD कार्ड अनमाउन्ट गर्नु भयो भने फेरि तपाईँले SD कार्ड पुनःमाउन्ट नगरेसम्म  तपाईँले चलाउनु भएका केही एपहरू अनुपलब्ध हुन सक्छन्।"</string>
     <string name="dlg_error_unmount_title" product="nosdcard" msgid="3132640848329117857"></string>
     <string name="dlg_error_unmount_title" product="default" msgid="3132640848329117857"></string>
     <string name="dlg_error_unmount_text" product="nosdcard" msgid="4710773826053117136">"USB भण्डारण अनमाउन्ट गर्न सकेन। पछि फेरि प्रयास गर्नुहोस्।"</string>
@@ -1401,7 +1406,7 @@
     <string name="sd_ejecting_title" msgid="595074246815112145">"अनमाउन्ट गरिंदै"</string>
     <string name="sd_ejecting_summary" msgid="5708943172014003213">"अनमाउन्ट प्रगतिमा"</string>
     <string name="storage_low_title" msgid="6957178208426099592">"भण्डारण ठाउँ सकिँदै छ"</string>
-    <string name="storage_low_summary" msgid="4475275204869514141">"केही प्रणाली प्रकार्यहरू जस्तै सिंक गर्ने, ठिकसँग काम नगर्न सक्छ। वस्तुहरू जस्तै अनुप्रयोग वा मिडिया सामग्री मेटाएर वा पिन हटाएर ठाउँ खाली बनाउनुहोस् ।"</string>
+    <string name="storage_low_summary" msgid="4475275204869514141">"केही प्रणाली प्रकार्यहरू जस्तै सिंक गर्ने, ठिकसँग काम नगर्न सक्छ। वस्तुहरू जस्तै एप वा मिडिया सामग्री मेटाएर वा पिन हटाएर ठाउँ खाली बनाउनुहोस् ।"</string>
     <string name="storage_menu_rename" msgid="3731682449294417745">"पुन: नामाकरण गर्नुहोस्"</string>
     <string name="storage_menu_mount" msgid="6395893560780365473">"माउन्ट गर्नुहोस्"</string>
     <string name="storage_menu_unmount" msgid="5041360076873514189">"निकाल्नुहोस्"</string>
@@ -1419,7 +1424,7 @@
     <string name="usb_mtp_title" msgid="6893938968831995500">"मिडिया उपकरण (MTP)"</string>
     <string name="usb_mtp_summary" msgid="4427354560399094322">"तपाईँलाई विन्डोजमा मिडिया फाइलहरू सार्न वा म्याकमा एन्ड्रोइड फाइल सार्न अनुमति दिन्छ (हेर्नुहोस् (www.android.com/filetransfer)"</string>
     <string name="usb_ptp_title" msgid="6629335976394685361">"क्यामेरा (PTP)"</string>
-    <string name="usb_ptp_summary" msgid="460425275251168189">"तपाईँलाई क्यामेरा सफ्टवेयर प्रयोग गरेर फोटाहरू स्थानान्तरण गर्न, र MTP समर्थन नगर्ने कम्प्युटरमा कुनै पनि फाइलहरू स्थानान्तरण दिन्छ।"</string>
+    <string name="usb_ptp_summary" msgid="460425275251168189">"तपाईँलाई क्यामेरा सफ्टवेयर प्रयोग गरेर फोटोहरू स्थानान्तरण गर्न, र MTP समर्थन नगर्ने कम्प्युटरमा कुनै पनि फाइलहरू स्थानान्तरण दिन्छ।"</string>
     <string name="usb_midi_title" msgid="8626512517313340943">"MIDI"</string>
     <string name="usb_midi_summary" msgid="3607444815743771712">"MIDI द्वारा सक्रिय अनुप्रयोगहरूलाई तपाईंको कम्प्युटरमा USB मार्फत MIDI सफ्टवेयरसँग काम गर्न दिन्छ।"</string>
     <string name="storage_other_users" msgid="1055693465220962928">"अन्य प्रयोगकर्ताहरू"</string>
@@ -1439,12 +1444,12 @@
     <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>"तस्बिर तथा अन्य मिडिया ब्याकअप गर्नुहोस्"</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_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>"तस्बिर तथा अन्य मिडिया ब्याकअप गर्नुहोस्"</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_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>
+    <string name="storage_internal_forget_confirm" msgid="3052483375203727176">"यो <xliff:g id="NAME">^1</xliff:g> मा भण्डारण गरिएका सबै एपहरू, तस्बिरहरू, र डेटा सधैंका लागि नष्ट हुनेछन्।"</string>
+    <string name="storage_detail_apps" msgid="8154648512504196820">"एपहरू"</string>
     <string name="storage_detail_images" msgid="6996202225684468964">"छविहरू"</string>
     <string name="storage_detail_videos" msgid="6030983354721080849">"भिडियोहरू"</string>
     <string name="storage_detail_audio" msgid="6011098436589663944">"अडियो"</string>
@@ -1452,14 +1457,14 @@
     <string name="storage_detail_other" msgid="9164851767437306618">"अन्य"</string>
     <string name="storage_detail_system" msgid="6784247618772153283">"प्रणाली"</string>
     <string name="storage_detail_explore" msgid="8206900269596580264">"<xliff:g id="NAME">^1</xliff:g> अन्वेषण गर्नुहोस्"</string>
-    <string name="storage_detail_dialog_other" msgid="5073511663616043370">"अन्यमा अनुप्रयोगहरूले सुरक्षित गेरका साझा फाइल, इन्टरनेट वा ब्लुटुथबाट डाउनलोड गरिएका फाइल, Android का फाइलहरू र यस्तै थप कुराहरू पर्छन्। \n\nयो <xliff:g id="NAME">^1</xliff:g> का देख्न सकिने सामग्रीहरू हेर्न अन्वेषण गर्नुहोस् नामक विकल्पमा ट्याप गर्नुहोस्।"</string>
-    <string name="storage_detail_dialog_system" msgid="1472572861360014226">"Android संस्करण <xliff:g id="VERSION">%s</xliff:g> चलाउनका लागि प्रयोग भएका फाइलहरू प्रणालीमा समावेश छन्"</string>
-    <string name="storage_detail_dialog_user" msgid="1663117417635010371">"<xliff:g id="USER_0">^1</xliff:g> ले तस्बिर, सङ्गीत, अनुप्रयोग वा अन्य डेटा सुरक्षित गर्नुभएको हुनसक्छ, जसले <xliff:g id="SIZE">^2</xliff:g> भण्डारण ओगटिरहेको छ। \n\nविवरणहरू हेर्न <xliff:g id="USER_1">^1</xliff:g> मा स्विच गर्नुहोस्।"</string>
+    <string name="storage_detail_dialog_other" msgid="5073511663616043370">"अन्यमा एपहरूले सुरक्षित गेरका साझा फाइल, इन्टरनेट वा ब्लुटुथबाट डाउनलोड गरिएका फाइल, Android का फाइलहरू र यस्तै थप कुराहरू पर्छन्। \n\nयो <xliff:g id="NAME">^1</xliff:g> का देख्न सकिने सामग्रीहरू हेर्न अन्वेषण गर्नुहोस् नामक विकल्पमा ट्याप गर्नुहोस्।"</string>
+    <string name="storage_detail_dialog_system" msgid="1472572861360014226">"प्रणालीमा Android संस्करण <xliff:g id="VERSION">%s</xliff:g> चलाउनका लागि प्रयोग भएका फाइलहरू समावेश छन्"</string>
+    <string name="storage_detail_dialog_user" msgid="1663117417635010371">"<xliff:g id="USER_0">^1</xliff:g> ले तस्बिर, सङ्गीत, एप वा अन्य डेटा सुरक्षित गर्नुभएको हुनसक्छ, जसले <xliff:g id="SIZE">^2</xliff:g> भण्डारण ओगटिरहेको छ। \n\nविवरणहरू हेर्न <xliff:g id="USER_1">^1</xliff:g> मा स्विच गर्नुहोस्।"</string>
     <string name="storage_wizard_init_title" msgid="3407283236421089014">"तपाईँको <xliff:g id="NAME">^1</xliff:g> सेट गर्नुहोस्"</string>
     <string name="storage_wizard_init_external_title" msgid="6853250619674645478">"पोर्टेबल भण्डारणको रूपमा प्रयोग गर्नुहोस्"</string>
     <string name="storage_wizard_init_external_summary" msgid="6993815290050489327">"यन्त्रहरू बीच तस्बिर र अन्य मिडिया सार्नका लागि।"</string>
     <string name="storage_wizard_init_internal_title" msgid="8750856962785644870">"आन्तरिक भण्डारणको रूपमा प्रयोग गर्नुहोस्"</string>
-    <string name="storage_wizard_init_internal_summary" msgid="4510546464921608029">"यस यन्त्रमा मात्र कुनै पनि चिज, अनुप्रयोग र तस्बिरहरू  भण्डारण गर्नाका लागि। यसलाई ढाँचा मिलाउन आवश्यक हुन्छ जसले अर्का यन्त्रहरूसँग काम गर्नबाट रोक्छ।"</string>
+    <string name="storage_wizard_init_internal_summary" msgid="4510546464921608029">"यस यन्त्रमा मात्र कुनै पनि चिज, एप र तस्बिरहरू  भण्डारण गर्नाका लागि। यसलाई ढाँचा मिलाउन आवश्यक हुन्छ जसले अर्का यन्त्रहरूसँग काम गर्नबाट रोक्छ।"</string>
     <string name="storage_wizard_format_confirm_title" msgid="7785358616068633439">"आन्तरिक भण्डारणको रुपमा ढाँचा गर्नुहोस्"</string>
     <string name="storage_wizard_format_confirm_body" msgid="4107762933332992624">"यो सुरक्षित बनाउन यसलाई <xliff:g id="NAME_0">^1</xliff:g> ढाँचा बनाउन आवश्यकता छ। \n\nढाँचामा मिलाएपछि, यो यन्त्रमा यसले <xliff:g id="NAME_1">^1</xliff:g> मात्र काम गर्ने छ। \n\n"<b>" ढाँचा मिलाउँदा <xliff:g id="NAME_2">^1</xliff:g> मा हालैका भण्डारित सबै डेटा मेटिन्छ।"</b>" डेटा गुमाउनुपर्ने बाट जोगिन, यसको ब्याकअप राख्ने बारे विचार गर्नुहोस्।"</string>
     <string name="storage_wizard_format_confirm_public_title" msgid="5866830103788091426">"पोर्टेबल भण्डारणका रूपमा फरम्याट गर्नुहोस्"</string>
@@ -1468,30 +1473,30 @@
     <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>
     <string name="storage_wizard_migrate_confirm_body" msgid="7297723787416643076"><b>"कार्यले करिब <xliff:g id="TIME">^1</xliff:g> लिन्छ। यसले <xliff:g id="NAME">^3</xliff:g> मा <xliff:g id="SIZE">^2</xliff:g> खाली गर्छ।"</b></string>
     <string name="storage_wizard_migrate_confirm_next" msgid="6539804689462991087">"सार्नुहोस्"</string>
     <string name="storage_wizard_migrate_progress_title" msgid="7542196688665109833">"डेटा सार्दै..."</string>
-    <string name="storage_wizard_migrate_details" msgid="4269509141637554985">"सार्दाको समयमा: \n• <xliff:g id="NAME">^1</xliff:g> नहटाउनुहोस्। \n• केही अनुप्रयोगहरूले सही काम गर्ने छैन। \n• यन्त्र चार्जमा राख्नुहोस्।"</string>
+    <string name="storage_wizard_migrate_details" msgid="4269509141637554985">"सार्दाको समयमा: \n• <xliff:g id="NAME">^1</xliff:g> नहटाउनुहोस्। \n• केही एपहरूले सही काम गर्ने छैन। \n• यन्त्र चार्जमा राख्नुहोस्।"</string>
     <string name="storage_wizard_ready_title" msgid="4905921139763520341">"तपाईंको <xliff:g id="NAME">^1</xliff:g> प्रयोगका लागि तयार छ"</string>
     <string name="storage_wizard_ready_external_body" msgid="8785407468656286236">"तपाईँको <xliff:g id="NAME">^1</xliff:g> तस्बिर र अन्य मिडिया प्रयोग गर्न सबै सेट छ।"</string>
-    <string name="storage_wizard_ready_internal_body" msgid="2258287496678469217">"तपाईँको नयाँ <xliff:g id="NAME">^1</xliff:g> ले काम गर्दैछ। \n\n यो यन्त्रमा तस्बिरहरू, फाइलहरू, र अनुप्रयोग डेटा सार्न, सेटिङ &amp;gt मा जानुहोस्; भण्डारण गर्नुहोस्।"</string>
+    <string name="storage_wizard_ready_internal_body" msgid="2258287496678469217">"तपाईँको नयाँ <xliff:g id="NAME">^1</xliff:g> ले काम गर्दैछ। \n\n यो यन्त्रमा तस्बिरहरू, फाइलहरू, र एप डेटा सार्न, सेटिङ &amp;gt मा जानुहोस्; भण्डारण गर्नुहोस्।"</string>
     <string name="storage_wizard_move_confirm_title" msgid="7362472162039287488">"सार्नुहोस् <xliff:g id="APP">^1</xliff:g>"</string>
-    <string name="storage_wizard_move_confirm_body" msgid="502315190416551319">"<xliff:g id="NAME_0">^2</xliff:g> मा <xliff:g id="APP">^1</xliff:g> र यसको डेटा सार्न केही बेर मात्र लिनेछ। तपाईं सार्ने क्रम पूरा नहुन्जेल अनुप्रयोग प्रयोग गर्न सक्नुहुने छैन। \n\n सार्ने क्रममा <xliff:g id="NAME_1">^2</xliff:g> नहटाउनुहोस्।"</string>
+    <string name="storage_wizard_move_confirm_body" msgid="502315190416551319">"<xliff:g id="NAME_0">^2</xliff:g> मा <xliff:g id="APP">^1</xliff:g> र यसको डेटा सार्न केही बेर मात्र लिनेछ। तपाईं सार्ने क्रम पूरा नहुन्जेल एप प्रयोग गर्न सक्नुहुने छैन। \n\n सार्ने क्रममा <xliff:g id="NAME_1">^2</xliff:g> नहटाउनुहोस्।"</string>
     <string name="storage_wizard_move_unlock" msgid="7978193904519827600">"डेटा सार्न तपाईंले प्रयोगकर्ताको <xliff:g id="APP">^1</xliff:g> अनलक गर्नु पर्ने हुन्छ।"</string>
     <string name="storage_wizard_move_progress_title" msgid="5250929161803336592">"सार्दै <xliff:g id="APP">^1</xliff:g>..."</string>
-    <string name="storage_wizard_move_progress_body" msgid="1713792142250410169">"सार्ने क्रममा <xliff:g id="NAME">^1</xliff:g> नहटाउनुहोस्। \n\nसार्ने क्रम पूरा नहुन्जेल सम्म यो यन्त्रको<xliff:g id="APP">^2</xliff:g> अनुप्रयोग उपलब्ध हुने छैन।"</string>
+    <string name="storage_wizard_move_progress_body" msgid="1713792142250410169">"सार्ने क्रममा <xliff:g id="NAME">^1</xliff:g> नहटाउनुहोस्। \n\nसार्ने क्रम पूरा नहुन्जेल सम्म यो यन्त्रको<xliff:g id="APP">^2</xliff:g> एप उपलब्ध हुने छैन।"</string>
     <string name="storage_wizard_move_progress_cancel" msgid="9047521329704060401">"सार्ने कार्य रद्द गर्नुहोस्"</string>
-    <string name="storage_wizard_slow_body" msgid="2307974936036261069">"यो <xliff:g id="NAME_0">^1</xliff:g> सुस्त जस्तो देखिन्छ। \n\n तपाईं जारी राख्न सक्नुहुन्छ, तर यस स्थानमा सारिएका अनुप्रयोगहरू अड्किन सक्छ र डेटा स्थानान्तरणले लामो समय लिन सक्छ। \n\nराम्रो प्रदर्शनको लागि थप छिटो <xliff:g id="NAME_1">^1</xliff:g> प्रयोग गर्ने विचार गर्नुहोस्।"</string>
+    <string name="storage_wizard_slow_body" msgid="2307974936036261069">"यो <xliff:g id="NAME_0">^1</xliff:g> सुस्त जस्तो देखिन्छ। \n\n तपाईं जारी राख्न सक्नुहुन्छ, तर यस स्थानमा सारिएका एपहरू अड्किन सक्छ र डेटा स्थानान्तरणले लामो समय लिन सक्छ। \n\nराम्रो प्रदर्शनको लागि थप छिटो <xliff:g id="NAME_1">^1</xliff:g> प्रयोग गर्ने विचार गर्नुहोस्।"</string>
     <string name="storage_wizard_init_v2_title" msgid="7408910177547901960">"तपाईं यो <xliff:g id="NAME">^1</xliff:g> कसरी प्रयोग गर्नुहुन्छ?"</string>
     <string name="storage_wizard_init_v2_internal_title" product="tablet" msgid="7948795312504302810">"ट्याब्लेटको अतिरिक्त भण्डारणका रूपमा प्रयोग गर्नुहोस्"</string>
-    <string name="storage_wizard_init_v2_internal_summary" product="tablet" msgid="6237770506398410172">"केवल यो ट्याब्लेटका अनुप्रयोग, फाइल तथा मिडियाका लागि"</string>
+    <string name="storage_wizard_init_v2_internal_summary" product="tablet" msgid="6237770506398410172">"केवल यो ट्याब्लेटका एप, फाइल तथा मिडियाका लागि"</string>
     <string name="storage_wizard_init_v2_internal_action" product="tablet" msgid="1016850267330050231">"ट्याब्लेटको भण्डारण"</string>
     <string name="storage_wizard_init_v2_internal_title" product="default" msgid="2782907833711627804">"फोनको अतिरिक्त भण्डारणका रूपमा प्रयोग गर्नुहोस्"</string>
-    <string name="storage_wizard_init_v2_internal_summary" product="default" msgid="6352521760027924000">"केवल यो फोनका अनुप्रयोग, फाइल तथा मिडियाका लागि"</string>
+    <string name="storage_wizard_init_v2_internal_summary" product="default" msgid="6352521760027924000">"केवल यो फोनका एप, फाइल तथा मिडियाका लागि"</string>
     <string name="storage_wizard_init_v2_internal_action" product="default" msgid="3383888882755852046">"फोनको भण्डारण"</string>
     <string name="storage_wizard_init_v2_or" msgid="883906565226069620">"वा"</string>
     <string name="storage_wizard_init_v2_external_title" msgid="7009571510941803101">"पोर्टेबल भण्डारणका रूपमा प्रयोग गर्नु…"</string>
@@ -1499,21 +1504,21 @@
     <string name="storage_wizard_init_v2_external_action" msgid="4649591913020218098">"पोर्टेबल भण्डारण"</string>
     <string name="storage_wizard_init_v2_later" msgid="2605006907172213466">"पछि सेटअप गर्नुहोस्"</string>
     <string name="storage_wizard_format_confirm_v2_title" msgid="1884699177320256159">"यो <xliff:g id="NAME">^1</xliff:g> फर्म्याट गर्ने हो?"</string>
-    <string name="storage_wizard_format_confirm_v2_body" msgid="977657376082074305">"अनुप्रयोग, फाइल तथा मिडिया भण्डारण गर्नका लागि यो <xliff:g id="NAME_0">^1</xliff:g> लाई फर्म्याट गर्नु पर्ने हुन्छ। \n\nफर्म्याट गर्नुले <xliff:g id="NAME_1">^2</xliff:g> मा हाल विद्यमान रहेका सामग्री मेट्नेछ। सामग्री गुमाउनबाट बच्न त्यसलाई कुनै अर्को <xliff:g id="NAME_2">^3</xliff:g> वा यन्त्रमा ब्याकअप गर्नुहोस्।"</string>
+    <string name="storage_wizard_format_confirm_v2_body" msgid="977657376082074305">"एप, फाइल तथा मिडिया भण्डारण गर्नका लागि यो <xliff:g id="NAME_0">^1</xliff:g> लाई फर्म्याट गर्नु पर्ने हुन्छ। \n\nफर्म्याट गर्नुले <xliff:g id="NAME_1">^2</xliff:g> मा हाल विद्यमान रहेका सामग्री मेट्नेछ। सामग्री गुमाउनबाट बच्न त्यसलाई कुनै अर्को <xliff:g id="NAME_2">^3</xliff:g> वा यन्त्रमा ब्याकअप गर्नुहोस्।"</string>
     <string name="storage_wizard_format_confirm_v2_action" msgid="5576917958786300415">"<xliff:g id="NAME">^1</xliff:g> फर्म्याट गर्नु…"</string>
     <string name="storage_wizard_migrate_v2_title" msgid="6728034411587320249">"सामग्रीलाई <xliff:g id="NAME">^1</xliff:g> मा सार्ने हो?"</string>
-    <string name="storage_wizard_migrate_v2_body" product="tablet" msgid="6943007011251294950">"तपाईं यो <xliff:g id="NAME">^1</xliff:g> मा फाइल, मिडिया र निश्चित अनुप्रयोगहरू सार्न सक्नुहुन्छ। \n\nयस कार्यले तपाईंको ट्याब्लेटको भण्डारणबाट <xliff:g id="SIZE">^2</xliff:g> खाली गर्ने छ र यसो गर्न लगभग <xliff:g id="DURATION">^3</xliff:g> लाग्छ।"</string>
-    <string name="storage_wizard_migrate_v2_body" product="default" msgid="3211214309775524554">"तपाईं यो <xliff:g id="NAME">^1</xliff:g> मा फाइल, मिडिया र निश्चित अनुप्रयोगहरू सार्न सक्नुहुन्छ। \n\nयस कार्यले तपाईंको फोनको भण्डारणबाट <xliff:g id="SIZE">^2</xliff:g> खाली गर्ने छ र यसो गर्न लगभग <xliff:g id="DURATION">^3</xliff:g> लाग्छ।"</string>
+    <string name="storage_wizard_migrate_v2_body" product="tablet" msgid="6943007011251294950">"तपाईं यो <xliff:g id="NAME">^1</xliff:g> मा फाइल, मिडिया र निश्चित एपहरू सार्न सक्नुहुन्छ। \n\nयस कार्यले तपाईंको ट्याब्लेटको भण्डारणबाट <xliff:g id="SIZE">^2</xliff:g> खाली गर्ने छ र यसो गर्न लगभग <xliff:g id="DURATION">^3</xliff:g> लाग्छ।"</string>
+    <string name="storage_wizard_migrate_v2_body" product="default" msgid="3211214309775524554">"तपाईं यो <xliff:g id="NAME">^1</xliff:g> मा फाइल, मिडिया र निश्चित एपहरू सार्न सक्नुहुन्छ। \n\nयस कार्यले तपाईंको फोनको भण्डारणबाट <xliff:g id="SIZE">^2</xliff:g> खाली गर्ने छ र यसो गर्न लगभग <xliff:g id="DURATION">^3</xliff:g> लाग्छ।"</string>
     <string name="storage_wizard_migrate_v2_checklist" msgid="6283777617014793600">"सार्ने क्रममा:"</string>
     <string name="storage_wizard_migrate_v2_checklist_media" msgid="4626548613088549096">"<xliff:g id="NAME">^1</xliff:g> लाई नहटाउनुहोस्"</string>
-    <string name="storage_wizard_migrate_v2_checklist_apps" msgid="6041914027863793837">"केही अनुप्रयोगहरूले काम गर्ने छैनन"</string>
+    <string name="storage_wizard_migrate_v2_checklist_apps" msgid="6041914027863793837">"केही एपहरूले काम गर्ने छैनन"</string>
     <string name="storage_wizard_migrate_v2_checklist_battery" product="tablet" msgid="5086689918108465503">"यो ट्याब्लेटलाई चार्जमा राख्नुहोस्"</string>
     <string name="storage_wizard_migrate_v2_checklist_battery" product="default" msgid="7801835366851130972">"यो फोनलाई चार्जमा राख्नुहोस्"</string>
     <string name="storage_wizard_migrate_v2_now" msgid="6818811520564682413">"सामग्री सार्नुहोस्"</string>
     <string name="storage_wizard_migrate_v2_later" msgid="4909412563144649085">"सामग्री पछि सार्नुहोस्"</string>
     <string name="storage_wizard_migrate_progress_v2_title" msgid="1796255772658203586">"सामग्री सार्दै…"</string>
     <string name="storage_wizard_slow_v2_title" msgid="4662009769135525740">"<xliff:g id="NAME">^1</xliff:g> ढिलो छ"</string>
-    <string name="storage_wizard_slow_v2_body" msgid="4443996335261861797">"तपाईं अझै यो <xliff:g id="NAME_0">^1</xliff:g> प्रयोग गर्न सक्नुहुन्छ तर यो निकै ढिलो हुन सक्छ। \n\nयो <xliff:g id="NAME_1">^2</xliff:g> मा सुरक्षित गरिएका अनुप्रयोगहरूले राम्ररी काम नगर्न सक्छन् र सामग्री स्थानान्तरण गर्दा लामो समय लाग्न सक्छ। \n\nकुनै अझ छिटो <xliff:g id="NAME_2">^3</xliff:g> प्रयोग गरी हेर्नुहोस् वा पोर्टेबल भण्डारणका लागि यसको साटो <xliff:g id="NAME_3">^4</xliff:g> प्रयोग गर्नुहोस्।"</string>
+    <string name="storage_wizard_slow_v2_body" msgid="4443996335261861797">"तपाईं अझै यो <xliff:g id="NAME_0">^1</xliff:g> प्रयोग गर्न सक्नुहुन्छ तर यो निकै ढिलो हुन सक्छ। \n\nयो <xliff:g id="NAME_1">^2</xliff:g> मा सुरक्षित गरिएका एपहरूले राम्ररी काम नगर्न सक्छन् र सामग्री स्थानान्तरण गर्दा लामो समय लाग्न सक्छ। \n\nकुनै अझ छिटो <xliff:g id="NAME_2">^3</xliff:g> प्रयोग गरी हेर्नुहोस् वा पोर्टेबल भण्डारणका लागि यसको साटो <xliff:g id="NAME_3">^4</xliff:g> प्रयोग गर्नुहोस्।"</string>
     <string name="storage_wizard_slow_v2_start_over" msgid="1686964124972424100">"फेरि सुरु गर्नुहोस्"</string>
     <string name="storage_wizard_slow_v2_continue" msgid="2320238517431613392">"जारी राख्नुहोस्"</string>
     <string name="storage_wizard_ready_v2_external_body" msgid="5803422587027895664">"तपाईं सामग्रीलाई <xliff:g id="NAME">^1</xliff:g> मा सार्न सक्नुहुन्छ"</string>
@@ -1561,14 +1566,14 @@
     <string name="error_mnc_not23" msgid="6738398924368729180">"MNC क्षेत्रमा २ वा ३ अंकहरू हुनुपर्दछ"</string>
     <string name="error_adding_apn_type" msgid="671634520340569678">"सेवा प्रदायकले %s प्रकारका APN हरू थप्ने अनुमति दिँदैन।"</string>
     <string name="restore_default_apn" msgid="7195266404077471007">"पूर्वनिर्धारित APN सेटिङहरू पुनःप्राप्त गर्दै।"</string>
-    <string name="menu_restore" msgid="3799288817317293115">"पूर्वनिर्धारितमा पुनःसेट गर्नुहोस्"</string>
-    <string name="restore_default_apn_completed" msgid="5671734152740058937">"पूर्वनिर्धारित APN सेटिङहरू पुनःसेट पुरा भयो।"</string>
+    <string name="menu_restore" msgid="3799288817317293115">"पूर्वनिर्धारितमा रिसेट गर्नुहोस्"</string>
+    <string name="restore_default_apn_completed" msgid="5671734152740058937">"पूर्वनिर्धारित APN सेटिङहरू रिसेट पुरा भयो।"</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"रिसेटका विकल्पहरू"</string>
-    <string name="reset_dashboard_summary" msgid="8778383341461126642">"नेटवर्क, अनुप्रयोगहरू वा यन्त्रलाई रिसेट गर्न सकिन्छ"</string>
+    <string name="reset_dashboard_summary" msgid="8778383341461126642">"नेटवर्क, एपहरू वा यन्त्रलाई रिसेट गर्न सकिन्छ"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"Wi-Fi, मोबाइल र ब्लुटुथ रिसेट गर्नुहोस्"</string>
     <string name="reset_network_desc" msgid="4982633363916261109">"यसले निम्न सेटिङहरू लगायत सम्पूर्ण नेटवर्क सम्बन्धी सेटिहरूलाई रिसेट गर्ने छ:\n\n"<li>"Wi‑Fi"</li>\n<li>"मोबाइल डेटा"</li>\n<li>"ब्लुटुथ"</li></string>
     <string name="reset_esim_title" msgid="7630781767040831893">"डाउनलोड गरिएका SIM हरू मेट्नुहोस्"</string>
-    <string name="reset_esim_desc" msgid="433226911566802">"प्रतिस्थापनका लागि SIM हरू डाउनलोड गर्न आफ्ना सेवा प्रदायकसँग सम्पर्क गर्नुहोस्। यसले मोबाइल सेवासम्बन्धी कुनै पनि योजना रद्द गर्ने छैन।"</string>
+    <string name="reset_esim_desc" msgid="433226911566802">"प्रतिस्थापनका लागि SIM हरू डाउनलोड गर्न आफ्ना सेवा प्रदायकसँग सम्पर्क गर्नुहोस्। यसले मोबाइल सेवाको कुनै पनि योजना रद्द गर्ने छैन।"</string>
     <string name="reset_network_button_text" msgid="4293271046867912819">"सेटिङहरू रिसेट गर्नुहोस्"</string>
     <string name="reset_network_final_desc" msgid="2463817067048751373">"नेटवर्कसम्बन्धी सबै सेटिङहरू रिसेट गर्ने हो? तपाईं यो कार्य उल्टाउन सक्नुहुन्न।"</string>
     <string name="reset_network_final_desc_esim" msgid="4676436976372555750">"नेटवर्कसम्बन्धी सबै सेटिङहरू रिसेट गर्ने र डाउनलोड गरिएका SIM हरू मेटाउने हो? तपाईं यस कार्यलाई अन्डू गर्न सक्नुहुन्न!"</string>
@@ -1580,8 +1585,8 @@
     <string name="reset_esim_error_msg" msgid="4716366079119742235">"कुनै त्रुटि भएका कारण डाउनलोड गरिएका SIM हरू मेटाउन सकिएन।\n\nआफ्नो यन्त्र पुनः सुरु गरी फेरि प्रयास गर्नुहोस्।"</string>
     <string name="master_clear_title" msgid="1560712943955904673">"सबै डेटा मेटाउनुहोस् (फ्याक्ट्री रिसेट गर्नुहोस्)"</string>
     <string name="master_clear_short_title" msgid="919098101581335101">"सबै डेटा मेटाउनुहोस् (फ्याक्ट्री रिसेट गर्नुहोस्)"</string>
-    <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"यसले निम्नलगायतका सबै डेटा तपाईंको "<b>"आन्तरिक भण्डारणबाट मेटाउँदछ"</b>":\n\n"<li>"तपाईंको Google खाता"</li>\n<li>"प्रणाली र अनुप्रयोग डेटा र सेटिङहरू"</li>\n<li>"डाउनलोड गरिएका अनुप्रयोगहरू"</li></string>
-    <string name="master_clear_desc" product="default" msgid="8765543541962866697">"यस कार्यले तपाईंको यन्त्रको "<b>"आन्तरिक भण्डारण"</b>" बाट सम्पूर्ण डेटा मेटाउँछ, जसमा निम्न कुराहरू पर्दछन्:\n\n"<li>"तपाईंको Google खाता"</li>\n<li>"प्रणाली र अनुप्रयोगका डेटा तथा सेटिङहरू"</li>\n<li>"डाउनलोड गरिएका अनुप्रयोगहरू"</li></string>
+    <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"यसले निम्नलगायतका सबै डेटा तपाईंको "<b>"आन्तरिक भण्डारणबाट मेटाउँदछ"</b>":\n\n"<li>"तपाईंको Google खाता"</li>\n<li>"प्रणाली र एप डेटा र सेटिङहरू"</li>\n<li>"डाउनलोड गरिएका एपहरू"</li></string>
+    <string name="master_clear_desc" product="default" msgid="8765543541962866697">"यस कार्यले तपाईंको यन्त्रको "<b>"आन्तरिक भण्डारण"</b>" बाट सम्पूर्ण डेटा मेटाउँछ, जसमा निम्न कुराहरू पर्दछन्:\n\n"<li>"तपाईंको Google खाता"</li>\n<li>"प्रणाली र अनुप्रयोगका डेटा तथा सेटिङहरू"</li>\n<li>"डाउनलोड गरिएका एपहरू"</li></string>
     <string name="master_clear_accounts" product="default" msgid="3432884235445405376">\n" \nतपाईं अहिले निम्न खाताहरूमा साइन इन हुनुहुन्छ:\n"</string>
     <string name="master_clear_other_users_present" product="default" msgid="5993259656117566767">\n\n" यस यन्त्रमा हाल अन्य प्रयोगकर्ताहरु छन्। \n"</string>
     <string name="master_clear_desc_also_erases_external" msgid="3947303501615091903"><li>"संगीत"</li>\n<li>"तस्बिरहरू"</li>\n<li>"अन्य उपयोगकर्ता डेटा"</li></string>
@@ -1591,16 +1596,16 @@
     <string name="master_clear_desc_erase_external_storage" product="default" msgid="9003555775524798797">\n" \n सङ्गीत, तस्वीरहरू, र अन्य प्रयोगकर्ता डेटा मेटाउनका लागि, "<b>" SD कार्ड "</b>" मेटाउनु पर्छ।"</string>
     <string name="erase_external_storage" product="nosdcard" msgid="8989746770347525207">"USB भण्डारण मेटाउनुहोस्"</string>
     <string name="erase_external_storage" product="default" msgid="194249742376770215">"SD कार्ड मेटाउनुहोस्"</string>
-    <string name="erase_external_storage_description" product="nosdcard" msgid="8020275102431496261">"आन्तरिक USB भण्डारणमा सबै डेटा मेटाउनुहोस्, जस्तै सङ्गीत वा फोटाहरू"</string>
-    <string name="erase_external_storage_description" product="default" msgid="5029355708082861798">"SD कार्डबाट सबै डाटाहरू जस्तै सङ्गीत वा फोटाहरू मेटाउनुहोस्"</string>
+    <string name="erase_external_storage_description" product="nosdcard" msgid="8020275102431496261">"आन्तरिक USB भण्डारणमा सबै डेटा मेटाउनुहोस्, जस्तै सङ्गीत वा फोटोहरू"</string>
+    <string name="erase_external_storage_description" product="default" msgid="5029355708082861798">"SD कार्डबाट सबै डाटाहरू जस्तै सङ्गीत वा फोटोहरू मेटाउनुहोस्"</string>
     <string name="master_clear_button_text" product="tablet" msgid="8000547818499182920">"सबै डेटा मेट्नुहोस्"</string>
     <string name="master_clear_button_text" product="default" msgid="8000547818499182920">"सबै डेटा मेट्नुहोस्"</string>
-    <string name="master_clear_final_desc" msgid="5189365498015339294">"तपाईंका सबै व्यक्तिगत जानकारी र डाउनलोड गरिएका अनुप्रयोगहरू मेटिने छन्। तपाईं यस कार्यलाई अन्डू गर्न सक्नुहुन्न!"</string>
-    <string name="master_clear_final_desc_esim" msgid="3058919823436953662">"तपाईंका डाउनलोड गरिएका अनुप्रयोग तथा SIM हरू लगायत सबै निजी जानकारी मेटाइने छन्। तपाईं यस कार्यलाई अन्डू गर्न सक्नुहुन्न!"</string>
+    <string name="master_clear_final_desc" msgid="5189365498015339294">"तपाईंका सबै व्यक्तिगत जानकारी र डाउनलोड गरिएका एपहरू मेटिने छन्। तपाईं यस कार्यलाई अन्डू गर्न सक्नुहुन्न!"</string>
+    <string name="master_clear_final_desc_esim" msgid="3058919823436953662">"तपाईंका डाउनलोड गरिएका एप तथा SIM हरू लगायत सबै निजी जानकारी मेटाइने छन्। तपाईं यस कार्यलाई अन्डू गर्न सक्नुहुन्न!"</string>
     <string name="master_clear_final_button_text" msgid="866772743886027768">"सबै मेटाउनुहोस्"</string>
-    <string name="master_clear_failed" msgid="7588397453984229892">"कुनै पुनःसेट हुन सकेन किनभने सिस्टम क्लिएर सेवा उपलब्ध छैन।"</string>
+    <string name="master_clear_failed" msgid="7588397453984229892">"कुनै रिसेट हुन सकेन किनभने सिस्टम क्लिएर सेवा उपलब्ध छैन।"</string>
     <string name="master_clear_confirm_title" msgid="698328669893512402">"सबै डेटा मेट्ने हो?"</string>
-    <string name="master_clear_not_available" msgid="4676613348163652454">"यस प्रयोगकर्ताको लागि कारखाना पुनःसेट गर्ने उपलब्ध छैन"</string>
+    <string name="master_clear_not_available" msgid="4676613348163652454">"यस प्रयोगकर्ताको लागि कारखाना रिसेट गर्ने उपलब्ध छैन"</string>
     <string name="master_clear_progress_title" msgid="378953167274114857">"मेटाउँदै"</string>
     <string name="master_clear_progress_text" msgid="5418958116008976218">"कृपया प्रतीक्षा गर्नुहोला..."</string>
     <string name="call_settings_title" msgid="5033906789261282752">"कल सेटिङहरू"</string>
@@ -1616,22 +1621,22 @@
     <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"डेटा सेभर अन हुँदा टेदरिङ वा पोर्टेबल हटस्पटहरूको प्रयोग गर्न सक्दैन"</string>
     <string name="usb_title" msgid="7480927657535578688">"USB"</string>
     <string name="usb_tethering_button_text" msgid="6242228383142012332">"USB टेदर गर्दै"</string>
-    <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"USB मार्फत फोनको इन्टरनेट जडान साझा गर्नुहोस्"</string>
+    <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"USB मार्फत फोनको इन्टरनेट सेयर गर्नुहोस्"</string>
     <string name="usb_tethering_subtext" product="tablet" msgid="154536000235361034">"USB मार्फत ट्याब्लेटको इन्टरनेट जडान साझा गर्नुहोस्"</string>
     <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"ब्लुटुथ टेथर गर्दै"</string>
     <string name="bluetooth_tethering_subtext" product="tablet" msgid="6868756914621131635">"ब्लुटुथमार्फत ट्याब्लेटको इन्टरनेट जडान सझा गर्नुहोस्‌"</string>
-    <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"ब्लुटुथमार्फत फोनको इन्टरनेट जडान साझा गर्नुहोस्‌"</string>
+    <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"ब्लुटुथमार्फत फोनको इन्टरनेट सेयर गर्नुहोस्‌"</string>
     <string name="bluetooth_tethering_off_subtext_config" msgid="3981528184780083266">"ब्लुटुथमार्फत यो <xliff:g id="DEVICE_NAME">%1$d</xliff:g> को इन्टरनेट जडान साझा गर्दै"</string>
     <string name="bluetooth_tethering_overflow_error" msgid="6946561351369376943">"<xliff:g id="MAXCONNECTION">%1$d</xliff:g> उपकरणहरूभन्दा बढीसँग टेदर गर्न सक्दैन।"</string>
     <string name="bluetooth_untether_blank" msgid="5428300773782256084">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> अनटेथर गरिने छ।"</string>
-    <string name="tethering_footer_info" msgid="8019555174339154124">"आफ्नो मोबाइल डेटा जडानमार्फत अन्य यन्त्रहरूलाई इन्टरनेट उपलब्ध गराउन हटस्पट र टेदरिङ प्रयोग गर्नुहोस्। नजिकैका यन्त्रहरूसँग सामग्री आदान प्रदान गर्नाका निम्ति अनुप्रयोगहरूले हटस्पट सिर्जना गर्न पनि सक्छन्।"</string>
+    <string name="tethering_footer_info" msgid="8019555174339154124">"आफ्नो मोबाइल डेटा जडानमार्फत अन्य यन्त्रहरूलाई इन्टरनेट उपलब्ध गराउन हटस्पट र टेदरिङ प्रयोग गर्नुहोस्। नजिकैका यन्त्रहरूसँग सामग्री आदान प्रदान गर्नाका निम्ति एपहरूले हटस्पट सिर्जना गर्न पनि सक्छन्।"</string>
     <string name="tethering_help_button_text" msgid="7653022000284543996">"मद्दत"</string>
     <string name="network_settings_title" msgid="8516526011407061679">"मोबाइल नेटवर्क"</string>
     <string name="manage_mobile_plan_title" msgid="3312016665522553062">"मोबाईल योजना"</string>
-    <string name="sms_application_title" msgid="7815840568119334679">"SMS अनुप्रयोग"</string>
-    <string name="sms_change_default_dialog_title" msgid="6301260161969667578">"SMS अनुप्रयोग परिवर्तन गर्ने हो?"</string>
-    <string name="sms_change_default_dialog_text" msgid="8275088077930942680">"तपाईँको <xliff:g id="CURRENT_APP">%2$s</xliff:g> SMS अनुप्रयोगको सट्टामा <xliff:g id="NEW_APP">%1$s</xliff:g> प्रयोग गर्नुहुन्छ?"</string>
-    <string name="sms_change_default_no_previous_dialog_text" msgid="4680224695080527907">"<xliff:g id="NEW_APP">%s</xliff:g>लाई SMS अनुप्रयोगको रूपमा प्रयोग गर्नुहुन्छ?"</string>
+    <string name="sms_application_title" msgid="7815840568119334679">"SMS एप"</string>
+    <string name="sms_change_default_dialog_title" msgid="6301260161969667578">"SMS एप परिवर्तन गर्ने हो?"</string>
+    <string name="sms_change_default_dialog_text" msgid="8275088077930942680">"तपाईँको <xliff:g id="CURRENT_APP">%2$s</xliff:g> SMS एपको सट्टामा <xliff:g id="NEW_APP">%1$s</xliff:g> प्रयोग गर्नुहुन्छ?"</string>
+    <string name="sms_change_default_no_previous_dialog_text" msgid="4680224695080527907">"<xliff:g id="NEW_APP">%s</xliff:g>लाई SMS एपको रूपमा प्रयोग गर्नुहुन्छ?"</string>
     <string name="network_scorer_picker_title" msgid="1691073966560952916">"नेटवर्कको दर्जा प्रदायक"</string>
     <string name="network_scorer_picker_none_preference" msgid="6448280557733231737">"कुनै पनि होइन"</string>
     <string name="network_scorer_change_active_dialog_title" msgid="4274159562371475090">"Wi-Fi सहायक परिवर्तन गर्नुहुन्छ?"</string>
@@ -1643,7 +1648,7 @@
     <string name="mobile_connect_to_internet" msgid="6031886097365170913">"कृपया इन्टरनेटसँग जोड्नुहोस्"</string>
     <string name="location_title" msgid="8664674161765477168">"मेरो स्थान"</string>
     <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"काम प्रोफाइलका लागि स्थान"</string>
-    <string name="location_app_level_permissions" msgid="1298041503927632960">"अनुप्रयोगको अनुमति"</string>
+    <string name="location_app_level_permissions" msgid="1298041503927632960">"एपको अनुमति"</string>
     <string name="location_app_permission_summary_location_off" msgid="541372845344796336">"स्थान निष्क्रिय छ"</string>
     <plurals name="location_app_permission_summary_location_on" formatted="false" msgid="7904821382328758218">
       <item quantity="other"> <xliff:g id="TOTAL_LOCATION_APP_COUNT_3">%2$d</xliff:g> मध्ये <xliff:g id="BACKGROUND_LOCATION_APP_COUNT_2">%1$d</xliff:g> अनुप्रयोगहरूमाथिको असीमित पहुँच छ</item>
@@ -1651,22 +1656,22 @@
     </plurals>
     <string name="location_category_recent_location_access" msgid="286059523360285026">"हालसालै राखिएको स्थानमाथिको पहुँच"</string>
     <string name="location_recent_location_access_view_details" msgid="2051602261436245905">"विवरणहरू हेर्नुहोस्"</string>
-    <string name="location_no_recent_apps" msgid="77502059586413278">"हाल कुनै पनि अनुप्रयोगहरूले स्थान अनुरोध गरिएका छैनन्"</string>
+    <string name="location_no_recent_apps" msgid="77502059586413278">"अहिले कुनै पनि एपहरूले स्थानको जानकारी मागेका छैनन्"</string>
     <string name="location_no_recent_accesses" msgid="6289916310397279890">"कुनै पनि अनुप्रयोगले हाल स्थानमाथि पहुँच गरेको छैन"</string>
     <string name="location_high_battery_use" msgid="7177199869979522663">"उच्च ब्याट्री प्रयोग"</string>
     <string name="location_low_battery_use" msgid="5030448574501435888">"कम ब्याट्री प्रयोग"</string>
     <string name="location_scanning_screen_title" msgid="7663329319689413454">"Wi‑Fi तथा ब्लुटुथ स्क्यान गर्दै"</string>
     <string name="location_scanning_wifi_always_scanning_title" msgid="6750542206763112172">"Wi-Fi स्क्यान गर्दै"</string>
-    <string name="location_scanning_wifi_always_scanning_description" msgid="4956048135941851712">"अनुप्रयोग र सेवाहरूलाई जुनसुकै बेला (Wi‑Fi निष्क्रिय भएको बेलामा पनि) वरपरका Wi-Fi नेटवर्कहरू स्क्यान गर्न अनुमति दिनुहोस्। यसलाई स्थानमा आधारित सुविधा तथा सेवाहरू सुधार गर्ने जस्ता कार्यहरू गर्नाका लागि प्रयोग गर्न सकिन्छ।"</string>
+    <string name="location_scanning_wifi_always_scanning_description" msgid="4956048135941851712">"एप र सेवाहरूलाई जुनसुकै बेला (Wi‑Fi निष्क्रिय भएको बेलामा पनि) वरपरका Wi-Fi नेटवर्कहरू स्क्यान गर्न अनुमति दिनुहोस्। यसलाई स्थानमा आधारित सुविधा तथा सेवाहरू सुधार गर्ने जस्ता कार्यहरू गर्नाका लागि प्रयोग गर्न सकिन्छ।"</string>
     <string name="location_scanning_bluetooth_always_scanning_title" msgid="196241746742607453">"ब्लुटुथ स्क्यान हुँदै"</string>
-    <string name="location_scanning_bluetooth_always_scanning_description" msgid="3796673798637848690">"अनुप्रयोग तथा सेवाहरूलाई जुनसुकै बेला (ब्लुटुथ निष्क्रिय भएको बेलामा पनि) वरपरका यन्त्रहरू स्क्यान गर्न अनुमति दिनुहोस्‌। यसलाई स्थानमा आधारित सुविधा तथा सेवाहरू सुधार गर्ने जस्ता कार्यहरू गर्नाका लागि प्रयोग गर्न सकिन्छ।"</string>
+    <string name="location_scanning_bluetooth_always_scanning_description" msgid="3796673798637848690">"एप तथा सेवाहरूलाई जुनसुकै बेला (ब्लुटुथ निष्क्रिय भएको बेलामा पनि) वरपरका यन्त्रहरू स्क्यान गर्न अनुमति दिनुहोस्‌। यसलाई स्थानमा आधारित सुविधा तथा सेवाहरू सुधार गर्ने जस्ता कार्यहरू गर्नाका लागि प्रयोग गर्न सकिन्छ।"</string>
     <string name="managed_profile_location_services" msgid="224925483299159541">"कार्यस्थलका स्थानसम्बन्धी सेवाहरू"</string>
     <string name="location_network_based" msgid="1535812159327454835">"Wi-Fi; मोबाइल नेटवर्क स्थान"</string>
     <string name="location_neighborhood_level" msgid="8459352741296587916">"तपाईँको स्थानलाई सीघ्र अनुमान गर्न अनुप्रयोगहरूलाई Google स्थान सेवा प्रयोग गर्न अनुमति दिनुहोस्। बेनामी स्थान डेटा भेला गरिने छ र Googleमा पठाइने छ।"</string>
     <string name="location_neighborhood_level_wifi" msgid="6120133551482003840">"वाइ-फाइद्वारा निर्धारित स्थान"</string>
     <string name="location_gps" msgid="688049341158297763">"GPS सेटेलाइट"</string>
-    <string name="location_street_level" product="tablet" msgid="4459804798444296650">"तपाईँको स्थान इङ्गित गर्नको लागि तपाईँको ट्याब्लेटमा अनुप्रयोगलाई GPS को प्रयोग गर्न दिनुहोस्"</string>
-    <string name="location_street_level" product="default" msgid="7407688345675450051">"तपाईँको स्थान इङ्गित गर्नको लागि तपाईँको फोनमा अनुप्रयोगलाई GPS को प्रयोग गर्न दिनुहोस्"</string>
+    <string name="location_street_level" product="tablet" msgid="4459804798444296650">"तपाईँको स्थान इङ्गित गर्नको लागि तपाईँको ट्याब्लेटमा एपलाई GPS को प्रयोग गर्न दिनुहोस्"</string>
+    <string name="location_street_level" product="default" msgid="7407688345675450051">"तपाईँको स्थान इङ्गित गर्नको लागि तपाईँको फोनमा एपलाई GPS को प्रयोग गर्न दिनुहोस्"</string>
     <string name="assisted_gps" msgid="5411780261117055175">"सहायोगी GPSको प्रयोग गर्नुहोस्"</string>
     <string name="assisted_gps_enabled" msgid="2561022181775725369">"GPS लाई सहयोग पुर्‍याउन सर्भरको प्रयोग गर्नुहोस् (सञ्जाल प्रयोग घटाउन अनचेक गर्नुहोस्)"</string>
     <string name="assisted_gps_disabled" msgid="6448758788217415937">"GPS लाई मद्दत पुर्याउन सर्भर प्रयोग गर्नुहोस् (GPS कार्यसम्पादन सुधार्न अनचेक गर्नुहोस्)"</string>
@@ -1704,16 +1709,16 @@
     <string name="lockpassword_choose_your_screen_lock_header" msgid="6283518876031424798">"स्क्रिन लक सेट गर्नुहोस्"</string>
     <string name="lockpassword_choose_your_password_message" msgid="2838273977481046536">"सुरक्षाका लागि पासवर्ड सेट गर्नुहोस्"</string>
     <string name="lockpassword_choose_your_password_header_for_fingerprint" msgid="4921343500484160894">"फिंगरप्रिन्ट प्रयोग गर्न पासवर्ड सेट गर्नुहोस्"</string>
-    <string name="lockpassword_choose_your_pattern_header_for_fingerprint" msgid="314870151462139417">"फिंगरप्रिन्ट प्रयोग गर्न ढाँचा सेट गर्नुहोस्"</string>
+    <string name="lockpassword_choose_your_pattern_header_for_fingerprint" msgid="314870151462139417">"फिंगरप्रिन्ट प्रयोग गर्न प्याटर्न सेट गर्नुहोस्"</string>
     <string name="lockpassword_choose_your_pin_message" msgid="8942598950627277885">"सुरक्षाका ला‍गि PIN सेट गर्नुहोस्"</string>
     <string name="lockpassword_choose_your_pin_header_for_fingerprint" msgid="1102927520952116303">"फिंगरप्रिन्ट प्रयोग गर्न PIN सेट गर्नुहोस्"</string>
-    <string name="lockpassword_choose_your_pattern_message" msgid="1503075455752279687">"सुरक्षाका लागि ढाँचा सेट गर्नुहोस्"</string>
+    <string name="lockpassword_choose_your_pattern_message" msgid="1503075455752279687">"सुरक्षाका लागि प्याटर्न सेट गर्नुहोस्"</string>
     <string name="lockpassword_confirm_your_password_header" msgid="9055242184126838887">"आफ्नो पासवर्ड पुन: प्रविष्टि गर्नुहोस्"</string>
     <string name="lockpassword_confirm_your_pattern_header" msgid="7137526922696316545">"तपाईँको ढाँचा निश्चित गर्नुहोस्"</string>
     <string name="lockpassword_confirm_your_pin_header" msgid="4335593948303036343">"आफ्नो PIN पुन: प्रविष्टि गर्नुहोस्"</string>
     <string name="lockpassword_confirm_passwords_dont_match" msgid="1783767008133345784">"पासवर्ड मेल खाँदैन"</string>
     <string name="lockpassword_confirm_pins_dont_match" msgid="5444357293637748942">"PIN मिल्दैन"</string>
-    <string name="lockpassword_draw_your_pattern_again_header" msgid="9017394036814402348">"आफ्नो ढाँचा फेरि कोर्नुहोस्‌"</string>
+    <string name="lockpassword_draw_your_pattern_again_header" msgid="9017394036814402348">"प्याटर्न फेरि बनाउनुहोस्"</string>
     <string name="lockpassword_choose_lock_generic_header" msgid="4418423132980560119">"चयन अनलक गर्नुहोस्"</string>
     <string name="lockpassword_password_set_toast" msgid="601928982984489868">"पासवर्ड सेट भएको छ"</string>
     <string name="lockpassword_pin_set_toast" msgid="172594825722240059">"PIN सेट भएको छ।"</string>
@@ -1741,17 +1746,17 @@
     <string name="lockpassword_confirm_your_password_header_frp" msgid="7326670978891793470">"पासवर्ड पुष्टि गर्नुहोस्"</string>
     <string name="lockpassword_invalid_pin" msgid="3059022215815900137">"गलत PIN"</string>
     <string name="lockpassword_invalid_password" msgid="8374331995318204099">"गलत पासवर्ड"</string>
-    <string name="lockpattern_need_to_unlock_wrong" msgid="1328670466959377948">"गलत ढाँचा"</string>
+    <string name="lockpattern_need_to_unlock_wrong" msgid="1328670466959377948">"प्याटर्न मिलेन"</string>
     <string name="lock_settings_title" msgid="233657584969886812">"यन्त्र सुरक्षा"</string>
     <string name="lockpattern_change_lock_pattern_label" msgid="333149762562581510">"अनलक ढाँचा परिवर्तन गर्नुहोस्"</string>
     <string name="lockpattern_change_lock_pin_label" msgid="3435796032210265723">"PIN अनलक बदल्नुहोस्"</string>
-    <string name="lockpattern_recording_intro_header" msgid="2262005028838969839">"एउटा अनलक ढाँचा कोर्नुहोस्"</string>
+    <string name="lockpattern_recording_intro_header" msgid="2262005028838969839">"अनलक प्याटर्न बनाउनुहोस्"</string>
     <string name="lockpattern_recording_intro_footer" msgid="5426745740754065099">"मद्दतका लागि मेनुमा थिच्नुहोस्।"</string>
     <string name="lockpattern_recording_inprogress" msgid="4060818382176523671">"सकिएपछि औँला उचाल्नुहोस्।"</string>
     <string name="lockpattern_recording_incorrect_too_short" msgid="6374760294545431845">"कम्तीमा <xliff:g id="NUMBER">%d</xliff:g>वटा थोप्लाहरू जोड्नुहोस्। फेरि प्रयास गर्नुहोस्:"</string>
     <string name="lockpattern_pattern_entered_header" msgid="2108106638322637851">"ढाँचा रेकर्ड भयो।"</string>
-    <string name="lockpattern_need_to_confirm" msgid="4079482507985867389">"पुष्टि गर्नको लागि ढाँचा पुन: कोर्नुहोस्"</string>
-    <string name="lockpattern_pattern_confirmed_header" msgid="5603156929428721407">"तपाईँको नयाँ अनलक ढाँचा:"</string>
+    <string name="lockpattern_need_to_confirm" msgid="4079482507985867389">"पुष्टि गर्न प्याटर्न फेरि बनाउनुहोस्"</string>
+    <string name="lockpattern_pattern_confirmed_header" msgid="5603156929428721407">"नयाँ अनलक प्याटर्न:"</string>
     <string name="lockpattern_confirm_button_text" msgid="7059311304112902598">"निश्चित गर्नुहोस्"</string>
     <string name="lockpattern_restart_button_text" msgid="4322968353922529868">"पुनःचित्रण गर्नुहोस्"</string>
     <string name="lockpattern_retry_button_text" msgid="5473976578241534298">"खाली गर्नुहोस्"</string>
@@ -1763,12 +1768,12 @@
     <string name="lockpattern_settings_enable_visible_pattern_title_profile" msgid="5338893138982642228">"प्रोफाइलको ढाँचालाई देखिने बनाउनुहोस्"</string>
     <string name="lockpattern_settings_enable_tactile_feedback_title" msgid="3203621862806531947">"ट्याप गर्दा भाइब्रेट गर्नुहोस्"</string>
     <string name="lockpattern_settings_enable_power_button_instantly_locks" msgid="5890335732200257777">"पावर बटनले तुरुन्त लक गर्दछ"</string>
-    <string name="lockpattern_settings_power_button_instantly_locks_summary" msgid="1279989004145567840">"<xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g> द्वारा जब अनलक गर्ने बाहेक"</string>
+    <string name="lockpattern_settings_power_button_instantly_locks_summary" msgid="1279989004145567840">"<xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g> जे अनलक अवस्थामा राखेका बेला बाहेक"</string>
     <string name="lockpattern_settings_choose_lock_pattern" msgid="9042142745571386381">"अनलक ढाँचा सेट गर्नुहोस्"</string>
     <string name="lockpattern_settings_change_lock_pattern" msgid="1456643060737114885">"अनलक ढाँचा बदल्नुहोस्"</string>
     <string name="lockpattern_settings_help_how_to_record" msgid="6037403647312543908">"अनलक ढाँचा कसरी कोर्ने?"</string>
     <string name="lockpattern_too_many_failed_confirmation_attempts" msgid="3043127997770535921">"अत्यन्तै धेरै गलत प्रयास। <xliff:g id="NUMBER">%d</xliff:g> सेकेन्ड पछि पुन: प्रयास गर्नुहोस्।"</string>
-    <string name="activity_not_found" msgid="3492413375341165453">"अनुप्रयोग तपाईँको फोनमा स्थापना गरिएको छैन।"</string>
+    <string name="activity_not_found" msgid="3492413375341165453">"एप तपाईँको फोनमा स्थापना गरिएको छैन।"</string>
     <string name="lock_settings_profile_title" msgid="3928992050074556160">"कार्य प्रोफाइलको सुरक्षा"</string>
     <string name="lock_settings_profile_screen_lock_title" msgid="285267471459162203">"कार्य प्रोफाइलको स्क्रिन लक"</string>
     <string name="lock_settings_profile_unification_title" msgid="2629698644191935287">"एउटै लकको प्रयोग गर्नुहोस्"</string>
@@ -1779,21 +1784,21 @@
     <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="applications_settings" msgid="368331725658793179">"अनुप्रयोगको जानकारी"</string>
-    <string name="applications_settings_summary" msgid="8888258399577123906">"अनुप्रयोगहरू प्रबन्ध गर्नुहोस्, छिटो लन्च सर्टकटहरू सेटअप गर्नुहोस्"</string>
-    <string name="applications_settings_header" msgid="3766501606045211098">"अनुप्रयोग सेटिङहरू"</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>
     <string name="install_applications" msgid="7745902974984889179">"अज्ञात स्रोतहरू"</string>
-    <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_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="device" msgid="9141585291103603515">"तपाईंको यन्त्र र व्यक्तिगत डेटा अज्ञात अनुप्रयोगहरूबाट हुने आक्रमणमा पर्न सक्ने जोखिम अझ बढी हुन्छ। यो स्रोतबाट प्राप्त हुने अनुप्रयोगहरूको स्थापना गरेर, तिनीहरूको प्रयोगबाट फोनमा हुनसक्ने क्षति वा डेटाको नोक्सानीको जिम्मेवार तपाईं आफैँ हुनुहुन्छ भन्ने कुरामा तपाईं सहमत हुनुहुन्छ।"</string>
     <string name="advanced_settings" msgid="6282069364060968122">"जटिल सेटिङहरू"</string>
     <string name="advanced_settings_summary" msgid="5912237062506771716">"थप सेटिङ विकल्पहरू सक्षम पार्नुहोस्"</string>
-    <string name="application_info_label" msgid="3886253474964599105">"अनुप्रयोग जानकारी"</string>
+    <string name="application_info_label" msgid="3886253474964599105">"एपको जानकारी"</string>
     <string name="storage_label" msgid="1109537840103290384">"भण्डारण"</string>
     <string name="auto_launch_label" msgid="47089737922907379">"पूर्वनिर्धारितद्वारा खोल्नुहोस्"</string>
     <string name="auto_launch_label_generic" msgid="7865828543459493308">"पूर्वनिर्धारितहरू"</string>
@@ -1810,8 +1815,8 @@
     <string name="controls_label" msgid="5609285071259457221">"नियन्त्रणहरू"</string>
     <string name="force_stop" msgid="9213858124674772386">"जबरजस्ती रोक्नुहोस्"</string>
     <string name="total_size_label" msgid="3929917501176594692">"कूल"</string>
-    <string name="application_size_label" msgid="175357855490253032">"अनुप्रयोगको आकार"</string>
-    <string name="external_code_size_label" msgid="3434421216268309411">"USB भण्डारण अनुप्रयोग"</string>
+    <string name="application_size_label" msgid="175357855490253032">"एपको आकार"</string>
+    <string name="external_code_size_label" msgid="3434421216268309411">"USB भण्डारण एप"</string>
     <string name="data_size_label" msgid="7790201846922671662">"प्रयोगकर्ताको डेटा"</string>
     <string name="external_data_size_label" product="nosdcard" msgid="8004991551882573479">"USB भण्डारण डेटा"</string>
     <string name="external_data_size_label" product="default" msgid="1097584278225902734">"SD कार्ड"</string>
@@ -1822,45 +1827,45 @@
     <string name="enable_text" msgid="7179141636849225884">"सक्रिय गर्नुहोस्"</string>
     <string name="clear_user_data_text" msgid="8894073247302821764">"भण्डारण खाली गर्नुहोस्"</string>
     <string name="app_factory_reset" msgid="8718986000278776272">"अद्यावधिकहरू अस्थापना गर्नुहोस्"</string>
-    <string name="auto_launch_enable_text" msgid="3372898942144027341">"केही कारवाहीका लागि पूर्वनिर्धारतिबाट यो अनुप्रयोग सुरु गर्न तपाईँले छान्नु भयो।"</string>
-    <string name="always_allow_bind_appwidgets_text" msgid="2286211654774611037">"तपाईंले यो अनुप्रयोगलाई विजेटहरू सिर्जना गर्न र तिनीहरूको डेटा पहुँच गर्न अनुमतिको लागि छान्नुभयो।"</string>
+    <string name="auto_launch_enable_text" msgid="3372898942144027341">"केही कारवाहीका लागि पूर्वनिर्धारतिबाट यो एप सुरु गर्न तपाईँले छान्नु भयो।"</string>
+    <string name="always_allow_bind_appwidgets_text" msgid="2286211654774611037">"तपाईंले यो एपलाई विजेटहरू सिर्जना गर्न र तिनीहरूको डेटा पहुँच गर्न अनुमतिको लागि छान्नुभयो।"</string>
     <string name="auto_launch_disable_text" msgid="8560921288036801416">"कुनै पूर्वनिर्धारित सेट गरिएको छैन।"</string>
     <string name="clear_activities" msgid="2068014972549235347">"पूर्वनिर्धारितहरू मेटाउनुहोस्"</string>
-    <string name="screen_compatibility_text" msgid="1768064020294301496">"तपाईंको स्क्रिनका लागि यस अनुप्रयोग डिजाइन नहुन सक्छ। तपाईंको स्क्रिनमा कसरी मिल्छ तपाईं यहाँ नियन्त्रण गर्न सक्नु हुन्छ।"</string>
+    <string name="screen_compatibility_text" msgid="1768064020294301496">"तपाईंको स्क्रिनका लागि यस एप डिजाइन नहुन सक्छ। तपाईंको स्क्रिनमा कसरी मिल्छ तपाईं यहाँ नियन्त्रण गर्न सक्नु हुन्छ।"</string>
     <string name="ask_compatibility" msgid="6687958195768084807">"सुरु भइसकेपछि सोध्नुहोस्"</string>
-    <string name="enable_compatibility" msgid="1754177974320410195">"स्केल अनुप्रयोग"</string>
+    <string name="enable_compatibility" msgid="1754177974320410195">"स्केल एप"</string>
     <string name="unknown" msgid="2780743426415501227">"अज्ञात"</string>
     <string name="sort_order_alpha" msgid="6689698854460261212">"नामबाट क्रमबद्ध गर्नुहोस्"</string>
     <string name="sort_order_size" msgid="3167376197248713027">"आकारद्वारा क्रमबद्ध गर्नुहोस्"</string>
-    <string name="sort_order_recent_notification" msgid="5592496977404445941">"सबैभन्दा हालसालैका"</string>
-    <string name="sort_order_frequent_notification" msgid="5640245013098010347">"प्रायः"</string>
+    <string name="sort_order_recent_notification" msgid="5592496977404445941">"नवीनतम"</string>
+    <string name="sort_order_frequent_notification" msgid="5640245013098010347">"प्रायःजसो प्रयोग हुने"</string>
     <string name="show_running_services" msgid="1895994322704667543">"चालु सेवाहरू देखाउनुहोस्"</string>
     <string name="show_background_processes" msgid="88012264528093617">"केस गरिएका प्रक्रियाहरू"</string>
-    <string name="default_emergency_app" msgid="286530070173495823">"आपतकालीन अनुप्रयोग"</string>
-    <string name="reset_app_preferences" msgid="1426500030595212077">"अनुप्रयोग प्राथमिकताहरू पुनःसेट गर्नुहोस्"</string>
-    <string name="reset_app_preferences_title" msgid="792909865493673598">"अनुप्रयोगका प्राथमिकताहरू पुनःसेट गर्ने हो?"</string>
-    <string name="reset_app_preferences_desc" msgid="7935273005301096031">"यसले सबै  प्राथमिकताहरूलाई पुनःसेट गर्ने छ:\n\n "<li>"असक्षम पारिएका अनुप्रयोगहरू"</li>\n" "<li>"असक्षम पारिएका अनुप्रयोग सूचनाहरू"</li>\n" "<li>"कार्यका लागि पूर्वनिर्धारित अनुप्रयोगहरू"</li>\n" "<li>"अनुप्रयोगहरूको लागि पृष्ठभूमि डेटा प्रतिबन्धहरू"</li>\n" "<li>"कुनै अनुमति प्रतिबन्धहरू"</li>\n\n" तपाईँले कुनै पनि अनुप्रयोग डेटा गुमाउनु हुने छैन।"</string>
-    <string name="reset_app_preferences_button" msgid="2041894727477934656">"अनुप्रयोगहरू पुनःसेट गर्नुहोस्"</string>
+    <string name="default_emergency_app" msgid="286530070173495823">"आपतकालीन एप"</string>
+    <string name="reset_app_preferences" msgid="1426500030595212077">"अनुप्रयोगका प्राथमिकताहरू रिसेट गर्नुहोस् रिसेट गर्नुहोस्"</string>
+    <string name="reset_app_preferences_title" msgid="792909865493673598">"अनुप्रयोगका अनुप्रयोगका प्राथमिकताहरू रिसेट गर्ने हो?"</string>
+    <string name="reset_app_preferences_desc" msgid="7935273005301096031">"यसले सबै  प्राथमिकताहरूलाई रिसेट गर्ने छ:\n\n "<li>"असक्षम पारिएका एपहरू"</li>\n" "<li>"असक्षम पारिएका एप सूचनाहरू"</li>\n" "<li>"कार्यका लागि पूर्वनिर्धारित एपहरू"</li>\n" "<li>"एपहरूको लागि पृष्ठभूमि डेटा प्रतिबन्धहरू"</li>\n" "<li>"कुनै अनुमति प्रतिबन्धहरू"</li>\n\n" तपाईँले कुनै पनि एप डेटा गुमाउनु हुने छैन।"</string>
+    <string name="reset_app_preferences_button" msgid="2041894727477934656">"एपहरू रिसेट गर्नुहोस्"</string>
     <string name="manage_space_text" msgid="6166469422303124302">"ठाउँको प्रबन्ध गर्नुहोस्"</string>
     <string name="filter" msgid="2426943916212457962">"फिल्टर गर्नुहोस्"</string>
     <string name="filter_dlg_title" msgid="115313222190512670">"फिल्टर विकल्पहरू छान्नुहोस्"</string>
-    <string name="filter_apps_all" msgid="3938077534861382701">"सबै अनुप्रयोगहरू"</string>
-    <string name="filter_apps_disabled" msgid="5394488790555678117">"असक्षम पारिएका अनुप्रयोगहरू"</string>
+    <string name="filter_apps_all" msgid="3938077534861382701">"सबै एपहरू"</string>
+    <string name="filter_apps_disabled" msgid="5394488790555678117">"असक्षम पारिएका एपहरू"</string>
     <string name="filter_apps_third_party" msgid="3985794876813232322">"डाउनलोड गरियो"</string>
     <string name="filter_apps_running" msgid="6852975378502426359">"चालु"</string>
     <string name="filter_apps_onsdcard" product="nosdcard" msgid="3501701148760911442">"USB भण्डारण"</string>
     <string name="filter_apps_onsdcard" product="default" msgid="135989136394672864">"SD कार्डमा"</string>
     <string name="not_installed" msgid="6432131218496140253">"यो प्रयोगकर्ताको लागि स्थापित गरिएको छैन"</string>
     <string name="installed" msgid="4824212968888080451">"स्थापना गरियो"</string>
-    <string name="no_applications" msgid="6811396016303576024">"कुनै अनुप्रयोगहरू छैनन्"</string>
+    <string name="no_applications" msgid="6811396016303576024">"कुनै एपहरू छैनन्"</string>
     <string name="internal_storage" msgid="7392373600013294853">"आन्तरिक भण्डारण"</string>
     <string name="recompute_size" msgid="4290692197892743928">"आकार पुनःगणना गर्दै ..."</string>
-    <string name="clear_data_dlg_title" msgid="7388024498687029597">"अनुप्रयोग डेटा मेटाउन चाहनुहुन्छ?"</string>
+    <string name="clear_data_dlg_title" msgid="7388024498687029597">"एप डेटा मेटाउन चाहनुहुन्छ?"</string>
     <string name="clear_data_dlg_text" msgid="6849657743695013414">"यस अनुप्रयोगका सम्पूर्ण डेटाहरू स्थायी रूपमा मेटाइने छ। यसमा सम्पूर्ण फाइल, सेटिङ, खाताहरू, डेटाबेस आदि पर्दछन्।"</string>
     <string name="dlg_ok" msgid="4666570206507476557">"ठिक छ"</string>
     <string name="dlg_cancel" msgid="2434951039156262467">"रद्द गर्नुहोस्"</string>
     <string name="app_not_found_dlg_title" msgid="394147475018718483"></string>
-    <string name="app_not_found_dlg_text" msgid="8807428608938210212">"स्थापित अनुप्रयोगको सूचीमा अनुप्रयोग भेटिएन।"</string>
+    <string name="app_not_found_dlg_text" msgid="8807428608938210212">"स्थापित एपको सूचीमा एप भेटिएन।"</string>
     <string name="clear_failed_dlg_text" msgid="8072859778950498232">"अनुप्रयोगका लागि भण्डारण खाली गर्न सकिएन।"</string>
     <string name="join_two_items" msgid="3833831843199356403">"<xliff:g id="FIRST_ITEM">%1$s</xliff:g> र <xliff:g id="SECOND_ITEM">%2$s</xliff:g>"</string>
     <string name="join_two_unrelated_items" msgid="8257688498236358394">"<xliff:g id="FIRST_ITEM">%1$s</xliff:g>, <xliff:g id="SECOND_ITEM">%2$s</xliff:g>"</string>
@@ -1874,24 +1879,24 @@
     <string name="move_app_to_sdcard" product="default" msgid="2348845109583354505">"SD कार्डमा सार्नुहोस्"</string>
     <string name="another_migration_already_in_progress" msgid="3159694008286196454">"अर्को माइग्रेसन पहिलेदेखि नै जारी छ।"</string>
     <string name="insufficient_storage" msgid="7089626244018569405">"पर्याप्त भण्डारण ठाउँ छैन।"</string>
-    <string name="does_not_exist" msgid="4821267479183197109">"अनुप्रयोग छैन"</string>
+    <string name="does_not_exist" msgid="4821267479183197109">"एप छैन"</string>
     <string name="invalid_location" msgid="8057409982223429673">"स्थापना स्थान वैध छैन।"</string>
     <string name="system_package" msgid="1824541892695233351">"प्रणाली अपडेटहरू बाह्य मिडियामा स्थापित गर्न सकिँदैनन्।"</string>
-    <string name="move_error_device_admin" msgid="6640501923867066901">"बाह्य मिडियामा यन्त्र प्रशासक अनुप्रयोगलाई स्थापना गर्न सकिँदैन"</string>
+    <string name="move_error_device_admin" msgid="6640501923867066901">"बाह्य मिडियामा यन्त्र प्रशासक एपलाई स्थापना गर्न सकिँदैन"</string>
     <string name="force_stop_dlg_title" msgid="8822779487097246675">"बलपूर्वक रोक्ने हो?"</string>
-    <string name="force_stop_dlg_text" msgid="7435245769456493398">"यदि तपाईँले अनुप्रयोगलाई जबर्जस्ती रोक्नु भएको खण्डमा त्यसले चाहेअनुसार काम नगर्न सक्छ।"</string>
+    <string name="force_stop_dlg_text" msgid="7435245769456493398">"यदि तपाईँले एपलाई जबर्जस्ती रोक्नु भएको खण्डमा त्यसले चाहेअनुसार काम नगर्न सक्छ।"</string>
     <string name="app_install_location_title" msgid="5121617802063021720">"मन परेको स्थापना स्थान"</string>
     <string name="app_install_location_summary" msgid="109719780117187797">"नयाँ अनुप्रयोगका लागि रुचाइएको स्थापना स्थान बदल्नुहोस्"</string>
-    <string name="app_disable_dlg_positive" msgid="5508828271100168073">"अनुप्रयोग असक्षम गर्नुहोस्"</string>
-    <string name="app_disable_dlg_text" msgid="9221864774943530281">"तपाईंले यो अनुप्रयोगलाई असक्षम पार्नुभयो भने Android र अन्य अनुप्रयोगहरूले अब उप्रान्त अपेक्षाअनुसार कार्य नगर्न सक्छन्। स्मरण रहोस्, तपाईं यो अनुप्रयोग तपाईंको यन्त्रसँग पहिल्यै स्थापना भएर आएको हुँदा तपाईं यसलाई मेट्न सक्नुहुन्न। यो अनुप्रयोग असक्षम पारेर, तपाईं यसलाई निष्क्रिय पार्नुहुन्छ र यसलाई आफ्नो यन्त्रमा लुकाउनुहुन्छ।"</string>
+    <string name="app_disable_dlg_positive" msgid="5508828271100168073">"एप असक्षम गर्नुहोस्"</string>
+    <string name="app_disable_dlg_text" msgid="9221864774943530281">"तपाईंले यो एपलाई असक्षम पार्नुभयो भने Android र अन्य एपहरूले अब उप्रान्त अपेक्षाअनुसार कार्य नगर्न सक्छन्। स्मरण रहोस्, तपाईं यो एप तपाईंको यन्त्रसँग पहिल्यै स्थापना भएर आएको हुँदा तपाईं यसलाई मेट्न सक्नुहुन्न। यो एप असक्षम पारेर, तपाईं यसलाई निष्क्रिय पार्नुहुन्छ र यसलाई आफ्नो यन्त्रमा लुकाउनुहुन्छ।"</string>
     <string name="app_disable_notifications_dlg_title" msgid="699530661413553928">"सूचनाहरू बन्द गर्नुहोस्?"</string>
     <string name="app_install_details_group_title" msgid="2909597319422976921">"स्टोर"</string>
-    <string name="app_install_details_title" msgid="6954953384372934881">"अनुप्रयोग बारे विवरणहरू"</string>
-    <string name="app_install_details_summary" msgid="6612222941121363940">"<xliff:g id="APP_STORE">%1$s</xliff:g> बाट स्थापना गरिएको अनुप्रयोग"</string>
+    <string name="app_install_details_title" msgid="6954953384372934881">"एप बारे विवरणहरू"</string>
+    <string name="app_install_details_summary" msgid="6612222941121363940">"<xliff:g id="APP_STORE">%1$s</xliff:g> बाट स्थापना गरिएको एप"</string>
     <string name="instant_app_details_summary" msgid="6384264315914966114">"<xliff:g id="APP_STORE">%1$s</xliff:g> मा थप जानकारी छ"</string>
     <string name="app_ops_running" msgid="6378418969742957805">"चालु भइरहेको"</string>
     <string name="app_ops_never_used" msgid="8305262378162525813">"(कहिल्यै प्रयोग नभएको)"</string>
-    <string name="no_default_apps" msgid="4519038578011412532">"कुनै पूर्वनिर्धारित अनुप्रयोगहरू छैनन्"</string>
+    <string name="no_default_apps" msgid="4519038578011412532">"कुनै पूर्वनिर्धारित एपहरू छैनन्"</string>
     <string name="storageuse_settings_title" msgid="3390798597982116048">"भण्डारण प्रयोग"</string>
     <string name="storageuse_settings_summary" msgid="3013328092465903687">"अनुप्रयोगद्वारा प्रयोग गरिएको भण्डारण हेर्नुहोस्"</string>
     <string name="service_restarting" msgid="1190995225643385568">"पुनःसुरु हुँदै"</string>
@@ -1912,22 +1917,22 @@
     <string name="running_processes_item_description_p_s" msgid="707216865096533078">"<xliff:g id="NUMPROCESS">%1$d</xliff:g> प्रक्रियाहरू र <xliff:g id="NUMSERVICES">%2$d</xliff:g> सेवा"</string>
     <string name="running_processes_item_description_p_p" msgid="8039478314818162001">"<xliff:g id="NUMPROCESS">%1$d</xliff:g> प्रक्रियाहरू र <xliff:g id="NUMSERVICES">%2$d</xliff:g> सेवाहरू"</string>
     <string name="running_processes_header_title" msgid="6505983796524910467">"यन्त्रको मेमोरी"</string>
-    <string name="running_processes_header_footer" msgid="6365963816942632771">"अनुप्रयोग RAM उपयोग"</string>
+    <string name="running_processes_header_footer" msgid="6365963816942632771">"एप RAM उपयोग"</string>
     <string name="running_processes_header_system_prefix" msgid="3812089317725567449">"प्रणाली"</string>
-    <string name="running_processes_header_apps_prefix" msgid="4024980745400903746">"अनुप्रयोगहरू"</string>
+    <string name="running_processes_header_apps_prefix" msgid="4024980745400903746">"एपहरू"</string>
     <string name="running_processes_header_free_prefix" msgid="1092348393136753031">"नि:शुल्क"</string>
     <string name="running_processes_header_used_prefix" msgid="2984090414986096084">"प्रयोग भयो"</string>
     <string name="running_processes_header_cached_prefix" msgid="8398315634778729026">"क्यास्ड"</string>
     <string name="running_processes_header_ram" msgid="3867954556214535588">"RAM को <xliff:g id="RAM_0">%1$s</xliff:g>"</string>
-    <string name="runningservicedetails_settings_title" msgid="7075556369123578372">"चालु अनुप्रयोग"</string>
+    <string name="runningservicedetails_settings_title" msgid="7075556369123578372">"चालु एप"</string>
     <string name="no_services" msgid="2085012960886321920">"सक्रिय छैन"</string>
     <string name="runningservicedetails_services_title" msgid="5890094559748633615">"सेवाहरू"</string>
     <string name="runningservicedetails_processes_title" msgid="5496507383850423763">"प्रक्रियाहरू"</string>
     <string name="service_stop" msgid="8812777462903125191">"रोक्नुहोस्"</string>
     <string name="service_manage" msgid="7045214643721276662">"सेटिङहरू"</string>
-    <string name="service_stop_description" msgid="4184180745938573707">"सेवा यसको अनुप्रयोगले सुरु गरेको हो। यसलाई रोक्दा अनुप्रयोग विफल हुन सक्छ।"</string>
-    <string name="heavy_weight_stop_description" msgid="7444148811046611463">"यो अनुप्रयोग सुरक्षित तरिकाले रोक्न मिल्दैन। यदि तपाईंले यसलाई रोक्नुभयो भने तपाईंले हालको केही काम हराउन सक्नु हुने छ"</string>
-    <string name="background_process_stop_description" msgid="8971810208873038109">"यो पुरानो अनुप्रयोग प्रक्रिया हो जुन अझैं चलिरहेको छ, यो कुनै पनि बेला चाहिन सक्छ। सामान्यतया: यसलाई रोक्नु पर्ने कुनै कारण छैन।"</string>
+    <string name="service_stop_description" msgid="4184180745938573707">"सेवा यसको एपले सुरु गरेको हो। यसलाई रोक्दा एप विफल हुन सक्छ।"</string>
+    <string name="heavy_weight_stop_description" msgid="7444148811046611463">"यो एप सुरक्षित तरिकाले रोक्न मिल्दैन। यदि तपाईंले यसलाई रोक्नुभयो भने तपाईंले हालको केही काम हराउन सक्नु हुने छ"</string>
+    <string name="background_process_stop_description" msgid="8971810208873038109">"यो पुरानो एप प्रक्रिया हो जुन अझैं चलिरहेको छ, यो कुनै पनि बेला चाहिन सक्छ। सामान्यतया: यसलाई रोक्नु पर्ने कुनै कारण छैन।"</string>
     <string name="service_manage_description" msgid="8058123524402833082">"<xliff:g id="CLIENT_NAME">%1$s</xliff:g>: अहिले प्रयोगमा छ। यसलाई नियन्त्रण गर्न सेटिङमा ट्याप गर्नुहोस्।"</string>
     <string name="main_running_process_description" msgid="7733268956566861797">"मुख्य प्रक्रिया प्रयोगमा।"</string>
     <string name="process_service_in_use_description" msgid="2253782391122637651">"सेवा <xliff:g id="COMP_NAME">%1$s</xliff:g> प्रयोगमा छ।"</string>
@@ -1949,7 +1954,7 @@
     <string name="auto_replace" msgid="4908063993127848521">"स्वतः परिवर्तन"</string>
     <string name="auto_replace_summary" msgid="5484123340142696252">"गलत टाइप गरिएका शब्दहरू सच्याउनुहोस्"</string>
     <string name="auto_caps" msgid="5566082723106296847">"स्वतः क्यापटिल"</string>
-    <string name="auto_caps_summary" msgid="8505254799874525084">"वाक्यहरूको पहिलो अक्षर ठूलो पार्नुहोस्"</string>
+    <string name="auto_caps_summary" msgid="8505254799874525084">"वाक्यहरूको पहिलो अक्षर ठुलो पार्नुहोस्"</string>
     <string name="auto_punctuate" msgid="8386007107100525931">"अटो-पङ्चुएट"</string>
     <string name="hardkeyboard_category" msgid="5937171470391551627">"वास्तविक किबोर्ड सेटिङहरू"</string>
     <string name="auto_punctuate_summary" msgid="245694025030386370">"\".\" सम्मिलित गर्न दुई पटक स्पेस कुञ्जी थिच्नुहोस्"</string>
@@ -2026,7 +2031,7 @@
     <string name="usage_stats_label" msgid="3128999956478977035">"उपयोग तथ्याङ्क"</string>
     <string name="testing_usage_stats" msgid="704965692323956976">"प्रयोग तथ्याङ्क"</string>
     <string name="display_order_text" msgid="2973620313510295873">"बाट क्रमबद्घ:"</string>
-    <string name="app_name_label" msgid="2258469951312794816">"अनुप्रयोग"</string>
+    <string name="app_name_label" msgid="2258469951312794816">"एप"</string>
     <string name="last_time_used_label" msgid="1119322667349666930">"पछिल्लो समय प्रयोग गरिएको"</string>
     <string name="usage_time_label" msgid="5615725415876461039">"उपयोग समय"</string>
     <string name="accessibility_settings" msgid="9140621093888234485">"पहुँच"</string>
@@ -2044,7 +2049,7 @@
     <string name="feature_flags_dashboard_title" msgid="3153034144122754381">"विशेष फ्ल्यागहरू"</string>
     <string name="talkback_title" msgid="3717960404234260050">"Talkback"</string>
     <string name="talkback_summary" msgid="6602857105831641574">"मुख्तया दृष्टिविहीन र कम दृष्टि भएका व्यक्तिहरूको लागि स्क्रिन रिडर"</string>
-    <string name="select_to_speak_summary" msgid="7514180457557735421">"ठूलो आवाजमा सुन्न आफ्नो स्क्रिनमा भएका वस्तुहरूमा ट्याप गर्नुहोस्"</string>
+    <string name="select_to_speak_summary" msgid="7514180457557735421">"ठुलो आवाजमा सुन्न आफ्नो स्क्रिनमा भएका वस्तुहरूमा ट्याप गर्नुहोस्"</string>
     <string name="accessibility_captioning_title" msgid="5878371993023439642">"क्याप्सन"</string>
     <string name="accessibility_screen_magnification_title" msgid="7250949681883917360">"म्याग्निफिकेसन"</string>
     <string name="accessibility_screen_magnification_gestures_title" msgid="9199287875401817974">"तीन ट्यापमा म्याग्निफाइ गर्नुहोस्"</string>
@@ -2060,11 +2065,11 @@
     <string name="accessibility_shortcut_service_title" msgid="3516052294376744060">"सर्टकट सेवा"</string>
     <string name="accessibility_shortcut_service_on_lock_screen_title" msgid="1279441617927949980">"लक स्क्रिनबाट अनुमति दिनुहोस्"</string>
     <string name="accessibility_shortcut_description" msgid="1427049334225166395">"सर्टकट सक्रिय हुँदा पहुँचसम्बन्धी सुविधा सुरु गर्न तपाईं दुवै भोल्युम कुञ्जीहरूलाई ३ सेकेन्डसम्म थिच्न सक्नुहुन्छ।"</string>
-    <string name="accessibility_toggle_high_text_contrast_preference_title" msgid="5652244684961877255">"उच्च विपरीत पाठ"</string>
-    <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"स्क्रिन आवर्धन स्वतः अद्यावधिक गर्नुहोस्"</string>
-    <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"अनुप्रयोग ट्रान्जिसनहरूमा स्क्रिन आवर्धन अद्यावधिक गर्नुहोस्"</string>
-    <string name="accessibility_power_button_ends_call_prerefence_title" msgid="6172987104538172869">"पावर बटनले कल समाप्त गर्दछ"</string>
-    <string name="accessibility_toggle_large_pointer_icon_title" msgid="9127905775116570565">"ठूलो माउस पोइन्टर"</string>
+    <string name="accessibility_toggle_high_text_contrast_preference_title" msgid="5652244684961877255">"हाइ कन्ट्रास्ट पाठ"</string>
+    <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"स्क्रिन आवर्धन स्वतः अपडेट गर्नुहोस्"</string>
+    <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"एप ट्रान्जिसनहरूमा स्क्रिन आवर्धन अपडेट गर्नुहोस्"</string>
+    <string name="accessibility_power_button_ends_call_prerefence_title" msgid="6172987104538172869">"पावर बटनले कल काट्छ"</string>
+    <string name="accessibility_toggle_large_pointer_icon_title" msgid="9127905775116570565">"ठुलो माउस पोइन्टर"</string>
     <string name="accessibility_disable_animations" msgid="8378441317115710009">"एनिमेसनहरू हटाउनुहोस्"</string>
     <string name="accessibility_toggle_master_mono_title" msgid="899550848196702565">"मोनो अडियो"</string>
     <string name="accessibility_toggle_master_mono_summary" msgid="3847052868469033235">"अडियो प्ले गर्दा च्यानलहरूलाई संयोजन गर्नुहोस्"</string>
@@ -2078,10 +2083,10 @@
     <string name="accessibility_timeout_2mins" msgid="4124259290444829477">"२ मिनेट"</string>
     <string name="accessibility_content_timeout_preference_title" msgid="5160746882250939464">"पढ्ने समय"</string>
     <string name="accessibility_control_timeout_preference_title" msgid="2771808346038759474">"कारबाही गर्ने समय"</string>
-    <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"तपाईंले पढ्नु पर्ने तर अस्थायी रूपमा मात्र देखिने सन्देशहरू देखाइने समय छनौट गर्नुहोस्।\n\nयो सेटिङले सबै अनुप्रयोगहरूमा काम गर्दैन।"</string>
-    <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"तपाईंलाई कारबाही गर्न लगाउने तर अस्थायी रूपमा मात्र देखिने सन्देशहरू देखाइने समय छनौट गर्नुहोस्।\n\nसबै अनुप्रयोगहरूले यो सेटिङ समर्थन गर्दैनन्।"</string>
-    <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"छुनुहोस् र केहीबेर समाउनुहोस्"</string>
-    <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"रंग इन्भर्सन"</string>
+    <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"तपाईंले पढ्नु पर्ने तर अस्थायी रूपमा मात्र देखिने सन्देशहरू देखाइने समय छनौट गर्नुहोस्।\n\nयो सेटिङले सबै एपहरूमा काम गर्दैन।"</string>
+    <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"तपाईंलाई कारबाही गर्न लगाउँदै अस्थायी रूपमा देखिने सन्देशहरू कति बेर देखाइनु पर्छ भन्ने कुरा छान्नुहोस्।\n\nयो सेटिङले सबै अनुप्रयोगमा काम गर्दैन।"</string>
+    <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"टच एण्ड होल्डको ढिलाइ"</string>
+    <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"रङ्ग उल्टाउनुहोस्"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"कार्यसम्पादनमा असर पार्न सक्छ"</string>
     <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"कुनै वस्तुमा कर्सर रहने अवधि"</string>
     <string name="accessibility_autoclick_description" msgid="5492414927846407499">"तपाईं माउस प्रयोग गर्दै हुनुहुन्छ भने कुनै स्थानमा निश्चित अवधिसम्मका लागि रोकिएको कर्सर स्वत: चल्न थाल्ने गरी सेट गर्न सक्नुहुन्छ।"</string>
@@ -2091,7 +2096,7 @@
     <string name="accessibility_ring_vibration_title" msgid="7943341443551359985">"कम्पनसहितको घन्टी"</string>
     <string name="accessibility_touch_vibration_title" msgid="285890135612038092">"छुवाइसम्बन्धी कम्पन"</string>
     <string name="accessibility_service_master_switch_title" msgid="2734791644475782924">"सुविधा प्रयोग गर्नुहोस्"</string>
-    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"रङ सुधार गर्ने सुविधा प्रयोग गर्नुहोस्"</string>
+    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"रङ्ग सुधार गर्ने सुविधा प्रयोग गर्नुहोस्"</string>
     <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"क्याप्सनहरू प्रयोग गर्नुहोस्"</string>
     <string name="accessibility_hearingaid_instruction_continue_button" msgid="4650111296711466691">"जारी राख्नुहोस्"</string>
     <string name="accessibility_hearingaid_title" msgid="3700978781235124891">"श्रवण यन्त्रहरू"</string>
@@ -2168,7 +2173,7 @@
     <string name="color_black" msgid="5766435778956454652">"कालो"</string>
     <string name="color_red" msgid="7426040122729897596">"रातो"</string>
     <string name="color_green" msgid="3432648781089648971">"हरियो"</string>
-    <string name="color_blue" msgid="4055855996393833996">"नीलो"</string>
+    <string name="color_blue" msgid="4055855996393833996">"निलो"</string>
     <string name="color_cyan" msgid="7669317410901991453">"सायन"</string>
     <string name="color_yellow" msgid="8847327436896180799">"पहेँलो"</string>
     <string name="color_magenta" msgid="721976999611563071">"म्याजेन्टा"</string>
@@ -2187,11 +2192,11 @@
     <string name="accessibility_no_service_selected" msgid="3909390566736834080">"कुनै पनि सेवा चयन गरिएको छैन"</string>
     <string name="accessibility_service_default_description" msgid="857921874644864502">"वर्णन प्रदान गरिएको छैन।"</string>
     <string name="settings_button" msgid="8557747862035866953">"सेटिङहरू"</string>
-    <string name="print_settings" msgid="7886184656544483072">"मुद्रण"</string>
+    <string name="print_settings" msgid="7886184656544483072">"प्रिन्टिङ"</string>
     <string name="print_settings_summary_no_service" msgid="634173687975841526">"निष्क्रिय छ"</string>
     <plurals name="print_settings_summary" formatted="false" msgid="7580293760281445137">
-      <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> वटा छाप्ने सेवा खुला छन्</item>
-      <item quantity="one">१ वटा छाप्ने सेवा खुला छ</item>
+      <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> वटा प्रिन्टर खुला छन्</item>
+      <item quantity="one">१ वटा प्रिन्टर खुला छ</item>
     </plurals>
     <plurals name="print_jobs_summary" formatted="false" msgid="6180308415569432845">
       <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> छपाइ कार्यहरू</item>
@@ -2229,18 +2234,18 @@
     <string name="power_discharge_remaining" msgid="3461915627093471868">"<xliff:g id="REMAIN">%1$s</xliff:g> बाँकी"</string>
     <string name="power_charge_remaining" msgid="2730510256218879651">"<xliff:g id="UNTIL_CHARGED">%1$s</xliff:g> चार्जमा"</string>
     <string name="background_activity_title" msgid="7207836362312111483">"पृष्ठभूमिको प्रतिबन्ध"</string>
-    <string name="background_activity_summary" msgid="582372194738538145">"अनुप्रयोगलाई पृष्ठभूमिमा चल्न अनुमति दिनुहोस्"</string>
-    <string name="background_activity_summary_disabled" msgid="457944930942085876">"अनुप्रयोगलाई पृष्ठभूमिमा चल्न दिइएको छैन"</string>
+    <string name="background_activity_summary" msgid="582372194738538145">"एपलाई पृष्ठभूमिमा चल्न अनुमति दिनुहोस्"</string>
+    <string name="background_activity_summary_disabled" msgid="457944930942085876">"एपलाई पृष्ठभूमिमा चल्न दिइएको छैन"</string>
     <string name="background_activity_summary_whitelisted" msgid="4713321059375873828">"पृष्ठभूमिको प्रयोगमा प्रतिबन्ध लगाउन सकिँदैन"</string>
     <string name="background_activity_warning_dialog_title" msgid="2170790412855899678">"पृष्ठभूमिको गतिविधिलाई सीमित गर्ने हो?"</string>
-    <string name="background_activity_warning_dialog_text" msgid="8242749826732375096">"तपाईंले कुनै अनुप्रयोगको पृष्ठभूमिको गतिविधिलाई सीमित गर्नुभयो भने यसले सही तरिकाले काम नगर्न सक्छ"</string>
-    <string name="background_activity_disabled_dialog_text" msgid="4234598000779459640">"यो अनुप्रयोगलाई ब्याट्री अप्टिमाइज गर्न भनी सेट नगरिएको हुनाले तपाईं यसमा बन्देज लगाउन सक्नुहुन्न।\n\nअनुप्रयोगमा बन्देज लगाउन पहिले ब्याट्री अप्टिमाइजेसन सुविधा सक्रिय गर्नुहोस्।"</string>
+    <string name="background_activity_warning_dialog_text" msgid="8242749826732375096">"तपाईंले कुनै एपको पृष्ठभूमिको गतिविधिलाई सीमित गर्नुभयो भने यसले सही तरिकाले काम नगर्न सक्छ"</string>
+    <string name="background_activity_disabled_dialog_text" msgid="4234598000779459640">"यो एपलाई ब्याट्री अप्टिमाइज गर्न भनी सेट नगरिएको हुनाले तपाईं यसमा बन्देज लगाउन सक्नुहुन्न।\n\nअनुप्रयोगमा बन्देज लगाउन पहिले ब्याट्री अप्टिमाइजेसन सुविधा सक्रिय गर्नुहोस्।"</string>
     <string name="device_screen_usage" msgid="4470485475363132750">"पूर्ण चार्ज भएदेखि स्क्रिनको प्रयोग"</string>
     <string name="power_usage_list_summary" msgid="4314438658308211057">"पूर्ण चार्ज भएदेखि ब्याट्रीको प्रयोग"</string>
     <string name="screen_usage_summary" msgid="263396144684078341">"पूर्ण चार्ज भएदेखि स्क्रिन सक्रिय रहेको समय"</string>
     <string name="device_usage_list_summary" msgid="8299017481332816368">"पूर्ण चार्ज भएदेखि यन्त्रको प्रयोग"</string>
     <string name="battery_since_unplugged" msgid="6486555910264026856">"अनप्लग भएदेखि ब्याट्री प्रयोग"</string>
-    <string name="battery_since_reset" msgid="4747587791838336661">"पुनःसेट गरेदेखि ब्याट्री प्रयोग"</string>
+    <string name="battery_since_reset" msgid="4747587791838336661">"रिसेट गरेदेखि ब्याट्री प्रयोग"</string>
     <string name="battery_stats_on_battery" msgid="2644055304085279716">"<xliff:g id="TIME">%1$s</xliff:g> ब्याट्रिमा"</string>
     <string name="battery_stats_duration" msgid="4867858933068728005">"<xliff:g id="TIME">%1$s</xliff:g> प्लग छुटाइएपछि"</string>
     <string name="battery_stats_charging_label" msgid="3156586822576998231">"चार्ज हुँदै"</string>
@@ -2262,10 +2267,10 @@
     <string name="details_subtitle" msgid="7279638828004951382">"विवरणहरू प्रयोग गर्नुहोस्"</string>
     <string name="controls_subtitle" msgid="6920199888882834620">"उर्जा प्रयोग मिलाउनुहोस्"</string>
     <string name="packages_subtitle" msgid="6506269487892204413">"सम्मिलित प्याकेजहरू"</string>
-    <string name="battery_tip_summary_title" msgid="2750922152518825526">"अनुप्रयोगहरू सामान्य रूपमा चलिरहेका छन्"</string>
-    <string name="battery_tip_summary_summary" product="default" msgid="6294900413896440006">"फोनले पृष्ठभूमिमा ब्याट्री सामान्य खपत गरेको छ"</string>
-    <string name="battery_tip_summary_summary" product="tablet" msgid="5280099016800644130">"ट्याब्लेटले पृष्ठभूमिमा ब्याट्री सामान्य खपत गरेको छ"</string>
-    <string name="battery_tip_summary_summary" product="device" msgid="4459840492610842705">"यन्त्रले पृष्ठभूमिमा ब्याट्री सामान्य खपत गरेको छ"</string>
+    <string name="battery_tip_summary_title" msgid="2750922152518825526">"एपहरू सामान्य रूपमा चलिरहेका छन्"</string>
+    <string name="battery_tip_summary_summary" product="default" msgid="6294900413896440006">"फोनले पृष्ठभूमिमा सदाको जति नै ब्याट्री खपत गरेको छ"</string>
+    <string name="battery_tip_summary_summary" product="tablet" msgid="5280099016800644130">"ट्याब्लेटले पृष्ठभूमिमा सदाको जति नै ब्याट्री खपत गरेको छ"</string>
+    <string name="battery_tip_summary_summary" product="device" msgid="4459840492610842705">"यन्त्रले पृष्ठभूमिमा सदाको जति नै ब्याट्री खपत गरेको छ"</string>
     <string name="battery_tip_low_battery_title" msgid="6784043681672161175">"ब्याट्रीको कम चार्ज क्षमता"</string>
     <string name="battery_tip_low_battery_summary" msgid="9151355911381188604">"ब्याट्रीको चार्ज स्तर बढी समयसम्म कायम रहन सक्दैन"</string>
     <string name="battery_tip_smart_battery_title" product="default" msgid="5517122075918038665">"आफ्नो फोनको ब्याट्रीको आयुमा सुधार गर्नुहोस्"</string>
@@ -2274,15 +2279,15 @@
     <string name="battery_tip_smart_battery_summary" msgid="5344821856478265778">"ब्याट्री प्रबन्धकलाई सक्रिय गर्नुहोस्‌"</string>
     <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"ब्याट्री सेभर सक्रिय गर्नुहोस्"</string>
     <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"ब्याट्री सामान्यभन्दा पहिले सकिन सक्छ"</string>
-    <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"ब्याट्री सेभर सक्रिय छ"</string>
+    <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"ब्याट्री सेभर अन छ"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"केही सुविधाहरू सीमित हुन सक्छन्‌"</string>
     <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"फोन सामान्यभन्दा बढी प्रयोग भयो"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"ट्याब्लेट सामान्यभन्दा बढी प्रयोग भयो"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"यन्त्रलाई सामान्यभन्दा बढी प्रयोग भयो"</string>
     <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"ब्याट्री अरू बेलाभन्दा छिटै सकिन सक्छ"</string>
-    <string name="battery_tip_dialog_message" product="default" msgid="8453700079047810964">"तपाईंको फोन असामान्य ढङ्गले धेरै पटक प्रयोग गरिएको छ। तपाईंको ब्याट्रीको चार्ज अपेक्षा गरिएभन्दा चाँडो सकिने छ।\n \n चार्ज पूरा भएपछि सबैभन्दा बढी प्रयोग गरिएका अनुप्रयोगहरू:"</string>
-    <string name="battery_tip_dialog_message" product="tablet" msgid="6489981050645444068">"तपाईंको ट्याब्लेट असामान्य ढङ्गले धेरै पटक प्रयोग गरिएको छ। तपाईंको ब्याट्रीको चार्ज अपेक्षा गरिएभन्दा चाँडो सकिने छ।\n \n चार्ज पूरा भएपछि सबैभन्दा बढी प्रयोग गरिएका अनुप्रयोगहरू:"</string>
-    <string name="battery_tip_dialog_message" product="device" msgid="6348123094674390337">"तपाईंको यन्त्र असामान्य ढङ्गले धेरै पटक प्रयोग गरिएको छ। तपाईंको ब्याट्रीको चार्ज अपेक्षा गरिएभन्दा चाँडो सकिने छ।\n \n चार्ज पूरा भएपछि सबैभन्दा बढी प्रयोग गरिएका अनुप्रयोगहरू:"</string>
+    <string name="battery_tip_dialog_message" product="default" msgid="8453700079047810964">"तपाईंको फोन असामान्य ढङ्गले धेरै पटक प्रयोग गरिएको छ। तपाईंको ब्याट्रीको चार्ज अपेक्षा गरिएभन्दा चाँडो सकिने छ।\n \n चार्ज पूरा भएपछि सबैभन्दा बढी प्रयोग गरिएका एपहरू:"</string>
+    <string name="battery_tip_dialog_message" product="tablet" msgid="6489981050645444068">"तपाईंको ट्याब्लेट असामान्य ढङ्गले धेरै पटक प्रयोग गरिएको छ। तपाईंको ब्याट्रीको चार्ज अपेक्षा गरिएभन्दा चाँडो सकिने छ।\n \n चार्ज पूरा भएपछि सबैभन्दा बढी प्रयोग गरिएका एपहरू:"</string>
+    <string name="battery_tip_dialog_message" product="device" msgid="6348123094674390337">"तपाईंको यन्त्र असामान्य ढङ्गले धेरै पटक प्रयोग गरिएको छ। तपाईंको ब्याट्रीको चार्ज अपेक्षा गरिएभन्दा चाँडो सकिने छ।\n \n चार्ज पूरा भएपछि सबैभन्दा बढी प्रयोग गरिएका एपहरू:"</string>
     <string name="battery_tip_dialog_message_footer" msgid="1118827395267487197">"यसले उच्च क्षमतायुक्त पृष्ठभूमिको गतिविधि समावेश गर्दछ"</string>
     <plurals name="battery_tip_restrict_title" formatted="false" msgid="7140926804142734420">
       <item quantity="other">%1$d अनुप्रयोगहरूमाथि बन्देज लगाउनुहोस्</item>
@@ -2293,67 +2298,67 @@
       <item quantity="one">%1$s माथि हालसालै बन्देज लगाइयो</item>
     </plurals>
     <plurals name="battery_tip_restrict_summary" formatted="false" msgid="984148373944071669">
-      <item quantity="other">%2$d अनुप्रयोगहरूले पृष्ठभूमिमा धेरै ब्याट्री खपत गरेको छ</item>
+      <item quantity="other">%2$d एपहरूले पृष्ठभूमिमा धेरै ब्याट्री खपत गरेको छ</item>
       <item quantity="one">%1$s ले पृष्ठभूमिमा धेरै ब्याट्री खपत गरेको छ</item>
     </plurals>
     <plurals name="battery_tip_restrict_handled_summary" formatted="false" msgid="469696766640020557">
-      <item quantity="other">यी अनुप्रयोगहरू पृष्ठभूमिमा चल्न सक्दैनन्</item>
-      <item quantity="one">यो अनुप्रयोग पृष्ठभूमिमा चल्न सक्दैन</item>
+      <item quantity="other">यी एपहरू पृष्ठभूमिमा चल्न सक्दैनन्</item>
+      <item quantity="one">यो एप पृष्ठभूमिमा चल्न सक्दैन</item>
     </plurals>
     <plurals name="battery_tip_restrict_app_dialog_title" formatted="false" msgid="3042021435866172168">
       <item quantity="other">%1$d अनुप्रयोगमाथि बन्देज लगाउने हो?</item>
       <item quantity="one">अनुप्रयोगमाथि बन्देज लगाउने हो?</item>
     </plurals>
     <string name="battery_tip_restrict_app_dialog_message" msgid="6905822297507947381">"ब्याट्री जोगाउन, <xliff:g id="APP">%1$s</xliff:g> लाई पृष्ठभूमिमा ब्याट्री प्रयोग गर्नबाट रोक्नुहोस्। यो अनुप्रयोगले सही किसिमले काम नगर्न सक्छ र सूचनाहरू आइपुग्न ढिलाइ हुन सक्छ।"</string>
-    <string name="battery_tip_restrict_apps_less_than_5_dialog_message" msgid="4225881888543582456">"ब्याट्री जोगाउन, यी अनुप्रयोगहरूलाई पृष्ठभूमिमा ब्याट्री प्रयोग गर्नबाट रोक्नुहोस्। प्रतिबन्ध लगाइएका अनुप्रयोगहरूले सही किसिमले काम नगर्न सक्छन् र सूचनाहरू आइपुग्न ढिलाइ हुन सक्छ।\n\nअनुप्रयोगहरू:"</string>
-    <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"ब्याट्री जोगाउन, यी अनुप्रयोगहरूलाई पृष्ठभूमिमा ब्याट्री प्रयोग गर्नबाट रोक्नुहोस्। प्रतिबन्ध लगाइएका अनुप्रयोगहरूले सही किसिमले काम नगर्न सक्छन् र सूचनाहरू आइपुग्न ढिलाइ हुन सक्छ।\n\nअनुप्रयोगहरू:\n<xliff:g id="APP_LIST">%1$s</xliff:g>।"</string>
+    <string name="battery_tip_restrict_apps_less_than_5_dialog_message" msgid="4225881888543582456">"ब्याट्री जोगाउन, यी एपहरूलाई पृष्ठभूमिमा ब्याट्री प्रयोग गर्नबाट रोक्नुहोस्। प्रतिबन्ध लगाइएका एपहरूले सही किसिमले काम नगर्न सक्छन् र सूचनाहरू आइपुग्न ढिलाइ हुन सक्छ।\n\nएपहरू:"</string>
+    <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"ब्याट्री जोगाउन, यी एपहरूलाई पृष्ठभूमिमा ब्याट्री प्रयोग गर्नबाट रोक्नुहोस्। प्रतिबन्ध लगाइएका एपहरूले सही किसिमले काम नगर्न सक्छन् र सूचनाहरू आइपुग्न ढिलाइ हुन सक्छ।\n\nएपहरू:\n<xliff:g id="APP_LIST">%1$s</xliff:g>।"</string>
     <string name="battery_tip_restrict_app_dialog_ok" msgid="2573410775701913487">"बन्देज लगाउनुहोस्"</string>
     <string name="battery_tip_unrestrict_app_dialog_title" msgid="812458516399125710">"प्रतिबन्ध हटाउने हो?"</string>
-    <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"यो अनुप्रयोग पृष्ठभूमिमा ब्याट्रीको प्रयोग गर्न सक्षम हुने छ। तपाईंको ब्याट्री अपेक्षा गरेभन्दा चाँडै सकिन सक्छ।"</string>
+    <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"यो एप पृष्ठभूमिमा ब्याट्रीको प्रयोग गर्न सक्षम हुने छ। तपाईंको ब्याट्री अपेक्षा गरेभन्दा चाँडै सकिन सक्छ।"</string>
     <string name="battery_tip_unrestrict_app_dialog_ok" msgid="9154938931448151479">"हटाउनुहोस्"</string>
     <string name="battery_tip_unrestrict_app_dialog_cancel" msgid="7331148618292397166">"रद्द गर्नुहोस्"</string>
-    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"तपाईंका अनुप्रयोगहरूले सामान्य मात्रामा ब्याट्रीको प्रयोग गर्दै छन्‌। अनुप्रयोगहरूले अत्यन्त धेरै ब्याट्रीको प्रयोग गरेको खण्डमा तपाईंको फोनले कारबाहीको सुझाव दिन्छ। \n\nतपाईंको ब्याट्री कम हुँदै गएको छ भने तपाईंले सधैँ ब्याट्री सेभर सक्रिय पार्न सक्नुहुन्छ।"</string>
-    <string name="battery_tip_dialog_summary_message" product="tablet" msgid="1721081030632329647">"तपाईंका अनुप्रयोगहरूले सामान्य मात्रामा ब्याट्रीको प्रयोग गर्दै छन्‌। अनुप्रयोगहरूले अत्यन्त धेरै ब्याट्रीको प्रयोग गरेको खण्डमा तपाईंको ट्याब्लेटले कारबाहीको सुझाव दिन्छ। \n\nतपाईंको ब्याट्री कम हुँदै गएको छ भने तपाईंले सधैँ ब्याट्री सेभर सक्रिय पार्न सक्नुहुन्छ।"</string>
-    <string name="battery_tip_dialog_summary_message" product="device" msgid="146872407040848465">"तपाईंका अनुप्रयोगहरूले सामान्य मात्रामा ब्याट्रीको प्रयोग गर्दै छन्‌। अनुप्रयोगहरूले अत्यन्त धेरै ब्याट्रीको प्रयोग गरेको खण्डमा तपाईंको यन्त्रले कारबाहीको सुझाव दिन्छ। \n\nतपाईंको ब्याट्री कम हुँदै गएको छ भने तपाईंले सधैँ ब्याट्री सेभर सक्रिय पार्न सक्नुहुन्छ।"</string>
+    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"तपाईंका एपहरूले सामान्य मात्रामा ब्याट्रीको प्रयोग गर्दै छन्‌। एपहरूले अत्यन्त धेरै ब्याट्रीको प्रयोग गरेको खण्डमा तपाईंको फोनले कारबाहीको सुझाव दिन्छ। \n\nतपाईंको ब्याट्री कम हुँदै गएको छ भने तपाईंले सधैँ ब्याट्री सेभर सक्रिय पार्न सक्नुहुन्छ।"</string>
+    <string name="battery_tip_dialog_summary_message" product="tablet" msgid="1721081030632329647">"तपाईंका एपहरूले सामान्य मात्रामा ब्याट्रीको प्रयोग गर्दै छन्‌। एपहरूले अत्यन्त धेरै ब्याट्रीको प्रयोग गरेको खण्डमा तपाईंको ट्याब्लेटले कारबाहीको सुझाव दिन्छ। \n\nतपाईंको ब्याट्री कम हुँदै गएको छ भने तपाईंले सधैँ ब्याट्री सेभर सक्रिय पार्न सक्नुहुन्छ।"</string>
+    <string name="battery_tip_dialog_summary_message" product="device" msgid="146872407040848465">"तपाईंका एपहरूले सामान्य मात्रामा ब्याट्रीको प्रयोग गर्दै छन्‌। एपहरूले अत्यन्त धेरै ब्याट्रीको प्रयोग गरेको खण्डमा तपाईंको यन्त्रले कारबाहीको सुझाव दिन्छ। \n\nतपाईंको ब्याट्री कम हुँदै गएको छ भने तपाईंले सधैँ ब्याट्री सेभर सक्रिय पार्न सक्नुहुन्छ।"</string>
     <string name="smart_battery_manager_title" msgid="5744035036663849515">"ब्याट्री प्रबन्धक"</string>
     <string name="smart_battery_title" msgid="4919670408532804351">"अनुप्रयोगहरूलाई स्वतः व्यवस्थित गर्नुहोस्"</string>
-    <string name="smart_battery_summary" msgid="640027046471198174">"तपाईंले प्रायः प्रयोग नगर्ने अनुप्रयोगहरूमा ब्याट्री सीमित गर्नुहोस्"</string>
-    <string name="smart_battery_footer" product="default" msgid="3971715848890205632">"ब्याट्री प्रबन्धकले अनुप्रयोगहरूले ब्याट्री खर्च गरिरहेको पता लगाउँदा, तपाईंसँग यी अनुप्रयोगहरूलाई प्रतिबन्धित गर्ने विकल्प हुन्छ। प्रतिबन्धित अनुप्रयोगहरूले सही किसिमले काम नगर्न सक्छन् र सूचनाहरू आउन ढिलाइ हुन सक्छ।"</string>
-    <string name="smart_battery_footer" product="tablet" msgid="3971715848890205632">"ब्याट्री प्रबन्धकले अनुप्रयोगहरूले ब्याट्री खर्च गरिरहेको पता लगाउँदा, तपाईंसँग यी अनुप्रयोगहरूलाई प्रतिबन्धित गर्ने विकल्प हुन्छ। प्रतिबन्धित अनुप्रयोगहरूले सही किसिमले काम नगर्न सक्छन् र सूचनाहरू आउन ढिलाइ हुन सक्छ।"</string>
-    <string name="smart_battery_footer" product="device" msgid="3971715848890205632">"ब्याट्री प्रबन्धकले अनुप्रयोगहरूले ब्याट्री खर्च गरिरहेको पता लगाउँदा, तपाईंसँग यी अनुप्रयोगहरूलाई प्रतिबन्धित गर्ने विकल्प हुन्छ। प्रतिबन्धित अनुप्रयोगहरूले सही किसिमले काम नगर्न सक्छन् र सूचनाहरू आउन ढिलाइ हुन सक्छ।"</string>
-    <string name="restricted_app_title" msgid="4957644700640127606">"प्रतिबन्धित अनुप्रयोगहरू"</string>
+    <string name="smart_battery_summary" msgid="640027046471198174">"तपाईंले प्रायः प्रयोग नगर्ने एपहरूमा ब्याट्री सीमित गर्नुहोस्"</string>
+    <string name="smart_battery_footer" product="default" msgid="3971715848890205632">"ब्याट्री प्रबन्धकले एपहरूले ब्याट्री खर्च गरिरहेको पता लगाउँदा, तपाईंसँग यी अनुप्रयोगहरूलाई प्रतिबन्धित गर्ने विकल्प हुन्छ। प्रतिबन्धित एपहरूले सही किसिमले काम नगर्न सक्छन् र सूचनाहरू आउन ढिलाइ हुन सक्छ।"</string>
+    <string name="smart_battery_footer" product="tablet" msgid="3971715848890205632">"ब्याट्री प्रबन्धकले एपहरूले ब्याट्री खर्च गरिरहेको पता लगाउँदा, तपाईंसँग यी अनुप्रयोगहरूलाई प्रतिबन्धित गर्ने विकल्प हुन्छ। प्रतिबन्धित एपहरूले सही किसिमले काम नगर्न सक्छन् र सूचनाहरू आउन ढिलाइ हुन सक्छ।"</string>
+    <string name="smart_battery_footer" product="device" msgid="3971715848890205632">"ब्याट्री प्रबन्धकले एपहरूले ब्याट्री खर्च गरिरहेको पता लगाउँदा, तपाईंसँग यी अनुप्रयोगहरूलाई प्रतिबन्धित गर्ने विकल्प हुन्छ। प्रतिबन्धित एपहरूले सही किसिमले काम नगर्न सक्छन् र सूचनाहरू आउन ढिलाइ हुन सक्छ।"</string>
+    <string name="restricted_app_title" msgid="4957644700640127606">"प्रतिबन्धित एपहरू"</string>
     <plurals name="restricted_app_summary" formatted="false" msgid="7609538735465186040">
-      <item quantity="other">ब्याट्रीको प्रयोग %1$d अनुप्रयोगहरूमा सीमित पार्दै</item>
-      <item quantity="one">ब्याट्रीको प्रयोग %1$d अनुप्रयोगहरूमा सीमित पार्दै</item>
+      <item quantity="other">ब्याट्रीको प्रयोग %1$d एपहरूमा सीमित पार्दै</item>
+      <item quantity="one">ब्याट्रीको प्रयोग %1$d एपहरूमा सीमित पार्दै</item>
     </plurals>
     <string name="restricted_app_time_summary" msgid="5205881852523135226">"<xliff:g id="TIME">%1$s</xliff:g> बजे बन्देज लगाइएको"</string>
-    <string name="restricted_app_detail_footer" msgid="482460517275754465">"यी अनुप्रयोगहरूले पृष्ठभूमिमा ब्याट्री प्रयोग गरिरहेका छन्‌। प्रतिबन्ध लगाइएका अनुप्रयोगहरूले सही किसिमले काम नगर्न सक्छन् र सूचनाहरू आइपुग्न ढिलाइ हुन सक्छ।"</string>
+    <string name="restricted_app_detail_footer" msgid="482460517275754465">"यी एपहरूले पृष्ठभूमिमा ब्याट्री प्रयोग गरिरहेका छन्‌। प्रतिबन्ध लगाइएका एपहरूले सही किसिमले काम नगर्न सक्छन् र सूचनाहरू आइपुग्न ढिलाइ हुन सक्छ।"</string>
     <string name="battery_auto_restriction_title" msgid="488905332794794076">"ब्याट्री प्रबन्धकको प्रयोग गर्नुहोस्"</string>
-    <string name="battery_auto_restriction_summary" msgid="1638072655581821837">"अनुप्रयोगहरूले ब्याट्रीको चार्ज घटाउँदा थाहा पाउनुहोस्"</string>
-    <string name="battery_manager_on" msgid="5626982529932239656">"सक्रिय छ / अनुप्रयोगहरूले ब्याट्रीको चार्ज घटाउने समय पत्ता लगाउँदै"</string>
+    <string name="battery_auto_restriction_summary" msgid="1638072655581821837">"एपहरूले ब्याट्रीको चार्ज घटाउँदा थाहा पाउनुहोस्"</string>
+    <string name="battery_manager_on" msgid="5626982529932239656">"सक्रिय छ / एपहरूले ब्याट्रीको चार्ज घटाउने समय पत्ता लगाउँदै"</string>
     <string name="battery_manager_off" msgid="9114027524232450371">"निष्क्रिय छ"</string>
     <plurals name="battery_manager_app_restricted" formatted="false" msgid="6721813588142691216">
-      <item quantity="other">%1$d अनुप्रयोगहरूमा प्रतिबन्ध लगाइयो</item>
+      <item quantity="other">%1$d एपहरूमा प्रतिबन्ध लगाइयो</item>
       <item quantity="one">%1$d अनुप्रयोगमा प्रतिबन्ध लगाइयो</item>
     </plurals>
     <string name="battery_header_title_alternate" msgid="1161081105263761743">"<xliff:g id="NUMBER">^1</xliff:g>"<small>" "<font size="20">"<xliff:g id="UNIT">%</xliff:g>"</font></small>""</string>
-    <string name="dialog_stop_title" msgid="4354544579084434590">"अनुप्रयोगलाई रोक्ने हो?"</string>
-    <string name="dialog_stop_message" product="default" msgid="1361660290824872555">"<xliff:g id="APP">%1$s</xliff:g> ले तपाईंको फोनलाई सक्रिय गरिरहने हुनाले तपाईंको यन्त्रले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्याको समाधान गर्ने प्रयास गर्न तपाईं उक्त अनुप्रयोगलाई रोक्न सक्नुहुन्छ।\n\nयो समस्या भइरहेमा ब्याट्रीको कार्यसम्पादनमा सुधार गर्न तपाईंले उक्त अनुप्रयोगको स्थापना रद्द गर्नु पर्ने हुन सक्छ।"</string>
-    <string name="dialog_stop_message" product="tablet" msgid="8948358625588034303">"<xliff:g id="APP">%1$s</xliff:g> ले तपाईंको ट्याब्लेटलाई सक्रिय गरिरहने हुनाले तपाईंको यन्त्रले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्याको समाधान गर्ने प्रयास गर्न तपाईं उक्त अनुप्रयोगलाई रोक्न सक्नुहुन्छ।\n\nयो समस्या भइरहेमा ब्याट्रीको कार्यसम्पादनमा सुधार गर्न तपाईंले उक्त अनुप्रयोगको स्थापना रद्द गर्नु पर्ने हुन सक्छ।"</string>
-    <string name="dialog_stop_message" product="device" msgid="3550459274584461359">"<xliff:g id="APP">%1$s</xliff:g> ले तपाईंको यन्त्रलाई सक्रिय गरिरहने हुनाले तपाईंको यन्त्रले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्याको समाधान गर्ने प्रयास गर्न तपाईं उक्त अनुप्रयोगलाई रोक्न सक्नुहुन्छ।\n\nयो समस्या भइरहेमा ब्याट्रीको कार्यसम्पादनमा सुधार गर्न तपाईंले उक्त अनुप्रयोगको स्थापना रद्द गर्नु पर्ने हुन सक्छ।"</string>
-    <string name="dialog_stop_message_wakeup_alarm" product="default" msgid="5361295199859282104">"<xliff:g id="APP_0">%1$s</xliff:g>ले तपाईंको फोनलाई सक्रिय गरिरहने हुनाले तपाईंको फोनले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्या समाधान गर्ने प्रयास गर्न तपाईं <xliff:g id="APP_1">%1$s</xliff:g>लाई रोक्न सक्नुहुन्छ।\n\nयो समस्या भइरहेमा ब्याट्रीको कार्यसम्पादनमा सुधार गर्न तपाईंले उक्त अनुप्रयोगको स्थापना रद्द गर्नु पर्ने हुन सक्छ।"</string>
-    <string name="dialog_stop_message_wakeup_alarm" product="tablet" msgid="3270887403788487776">"<xliff:g id="APP_0">%1$s</xliff:g>ले तपाईंको ट्याब्लेटलाई सक्रिय गरिरहने हुनाले तपाईंको ट्याब्लेटले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्या समाधान गर्ने प्रयास गर्न तपाईं <xliff:g id="APP_1">%1$s</xliff:g>लाई रोक्न सक्नुहुन्छ।\n\nयो समस्या भइरहेमा ब्याट्रीको कार्यसम्पादनमा सुधार गर्न तपाईंले उक्त अनुप्रयोगको स्थापना रद्द गर्नु पर्ने हुन सक्छ।"</string>
-    <string name="dialog_stop_message_wakeup_alarm" product="device" msgid="6577512995315373362">"<xliff:g id="APP_0">%1$s</xliff:g>ले तपाईंको यन्त्रलाई सक्रिय गरिरहने हुनाले तपाईंको यन्त्रले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्या समाधान गर्ने प्रयास गर्न तपाईं <xliff:g id="APP_1">%1$s</xliff:g>लाई रोक्न सक्नुहुन्छ।\n\nयो समस्या भइरहेमा ब्याट्रीको कार्यसम्पादनमा सुधार गर्न तपाईंले उक्त अनुप्रयोगको स्थापना रद्द गर्नु पर्ने हुन सक्छ।"</string>
-    <string name="dialog_stop_ok" msgid="5809052504018242928">"अनुप्रयोगलाई रोक्नुहोस्"</string>
-    <string name="dialog_background_check_title" msgid="6289139150963983470">"पृष्ठभूमिको प्रयोग निष्क्रिय पार्ने र अनुप्रयोगलाई रोक्ने हो?"</string>
+    <string name="dialog_stop_title" msgid="4354544579084434590">"एपलाई रोक्ने हो?"</string>
+    <string name="dialog_stop_message" product="default" msgid="1361660290824872555">"<xliff:g id="APP">%1$s</xliff:g> ले तपाईंको फोनलाई सक्रिय गरिरहने हुनाले तपाईंको यन्त्रले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्याको समाधान गर्ने प्रयास गर्न तपाईं उक्त एपलाई रोक्न सक्नुहुन्छ।\n\nयो समस्या भइरहेमा ब्याट्रीको कार्यसम्पादनमा सुधार गर्न तपाईंले उक्त एपको स्थापना रद्द गर्नु पर्ने हुन सक्छ।"</string>
+    <string name="dialog_stop_message" product="tablet" msgid="8948358625588034303">"<xliff:g id="APP">%1$s</xliff:g> ले तपाईंको ट्याब्लेटलाई सक्रिय गरिरहने हुनाले तपाईंको यन्त्रले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्याको समाधान गर्ने प्रयास गर्न तपाईं उक्त एपलाई रोक्न सक्नुहुन्छ।\n\nयो समस्या भइरहेमा ब्याट्रीको कार्यसम्पादनमा सुधार गर्न तपाईंले उक्त एपको स्थापना रद्द गर्नु पर्ने हुन सक्छ।"</string>
+    <string name="dialog_stop_message" product="device" msgid="3550459274584461359">"<xliff:g id="APP">%1$s</xliff:g> ले तपाईंको यन्त्रलाई सक्रिय गरिरहने हुनाले तपाईंको यन्त्रले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्याको समाधान गर्ने प्रयास गर्न तपाईं उक्त एपलाई रोक्न सक्नुहुन्छ।\n\nयो समस्या भइरहेमा ब्याट्रीको कार्यसम्पादनमा सुधार गर्न तपाईंले उक्त एपको स्थापना रद्द गर्नु पर्ने हुन सक्छ।"</string>
+    <string name="dialog_stop_message_wakeup_alarm" product="default" msgid="5361295199859282104">"<xliff:g id="APP_0">%1$s</xliff:g>ले तपाईंको फोनलाई सक्रिय गरिरहने हुनाले तपाईंको फोनले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्या समाधान गर्ने प्रयास गर्न तपाईं <xliff:g id="APP_1">%1$s</xliff:g>लाई रोक्न सक्नुहुन्छ।\n\nयो समस्या भइरहेमा ब्याट्रीको कार्यसम्पादनमा सुधार गर्न तपाईंले उक्त एपको स्थापना रद्द गर्नु पर्ने हुन सक्छ।"</string>
+    <string name="dialog_stop_message_wakeup_alarm" product="tablet" msgid="3270887403788487776">"<xliff:g id="APP_0">%1$s</xliff:g>ले तपाईंको ट्याब्लेटलाई सक्रिय गरिरहने हुनाले तपाईंको ट्याब्लेटले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्या समाधान गर्ने प्रयास गर्न तपाईं <xliff:g id="APP_1">%1$s</xliff:g>लाई रोक्न सक्नुहुन्छ।\n\nयो समस्या भइरहेमा ब्याट्रीको कार्यसम्पादनमा सुधार गर्न तपाईंले उक्त एपको स्थापना रद्द गर्नु पर्ने हुन सक्छ।"</string>
+    <string name="dialog_stop_message_wakeup_alarm" product="device" msgid="6577512995315373362">"<xliff:g id="APP_0">%1$s</xliff:g>ले तपाईंको यन्त्रलाई सक्रिय गरिरहने हुनाले तपाईंको यन्त्रले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्या समाधान गर्ने प्रयास गर्न तपाईं <xliff:g id="APP_1">%1$s</xliff:g>लाई रोक्न सक्नुहुन्छ।\n\nयो समस्या भइरहेमा ब्याट्रीको कार्यसम्पादनमा सुधार गर्न तपाईंले उक्त एपको स्थापना रद्द गर्नु पर्ने हुन सक्छ।"</string>
+    <string name="dialog_stop_ok" msgid="5809052504018242928">"एपलाई रोक्नुहोस्"</string>
+    <string name="dialog_background_check_title" msgid="6289139150963983470">"पृष्ठभूमिको प्रयोग निष्क्रिय पार्ने र एपलाई रोक्ने हो?"</string>
     <string name="dialog_background_check_message" product="default" msgid="944264053032952679">"<xliff:g id="APP_0">%1$s</xliff:g> ले तपाईंको फोनलाई सक्रिय गरिरहने हुनाले तपाईंको फोनले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्या समाधान गर्ने प्रयासस्वरूप तपाईं <xliff:g id="APP_1">%1$s</xliff:g> लाई रोक्न र यसलाई पृष्ठभूमिमा चल्नबाट रोक्न सक्नुहुन्छ।"</string>
     <string name="dialog_background_check_message" product="tablet" msgid="5246650726585461386">"<xliff:g id="APP_0">%1$s</xliff:g> ले तपाईंको ट्याब्लेटलाई सक्रिय गरिरहने हुनाले तपाईंको ट्याब्लेटले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्या समाधान गर्ने प्रयासस्वरूप, तपाईं <xliff:g id="APP_1">%1$s</xliff:g> लाई रोक्न र यसलाई पृष्ठभूमिमा चल्नबाट रोक्न सक्नुहुन्छ।"</string>
     <string name="dialog_background_check_message" product="device" msgid="2746413739802588979">"<xliff:g id="APP_0">%1$s</xliff:g> ले तपाईंको यन्त्रलाई सक्रिय गरिरहने हुनाले तपाईंको यन्त्रले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्या समाधान गर्ने प्रयासस्वरूप तपाईं <xliff:g id="APP_1">%1$s</xliff:g> लाई रोक्न र यसलाई पृष्ठभूमिमा चल्नबाट रोक्न सक्नुहुन्छ।"</string>
     <string name="dialog_background_check_ok" msgid="6916102434734525591">"निष्क्रिय पार्नुहोस्"</string>
     <string name="dialog_location_title" msgid="8070185060438751995">"स्थानसम्बन्धी जानकारीलाई निष्क्रिय पार्ने हो?"</string>
-    <string name="dialog_location_message" product="default" msgid="2445581202508387558">"<xliff:g id="APP">%1$s</xliff:g> ले तपाईं उक्त अनुप्रयोग प्रयोग नगरिरहनुभएको बेलामा पनि स्थानसम्बन्धी जानकारी प्राप्त गर्न अनुरोध गरिरहने भएकोले तपाईंको फोनले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्याको समाधान गर्न तपाईं यस फोनको स्थानसम्बन्धी जानकारी नामक विकल्पलाई निष्क्रिय पार्न सक्नुहुन्छ।"</string>
-    <string name="dialog_location_message" product="tablet" msgid="4012891295493865096">"<xliff:g id="APP">%1$s</xliff:g> ले तपाईं उक्त अनुप्रयोग प्रयोग नगरिरहनुभएको बेलामा पनि स्थानसम्बन्धी जानकारी प्राप्त गर्न अनुरोध गरिरहने भएकोले तपाईंको ट्याब्लेटले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्याको समाधान गर्न तपाईं यस ट्याब्लेटको स्थानसम्बन्धी जानकारी नामक विकल्पलाई निष्क्रिय पार्नसक्नुहुन्छ।"</string>
-    <string name="dialog_location_message" product="device" msgid="1454451610289205965">"<xliff:g id="APP">%1$s</xliff:g> ले तपाईं उक्त अनुप्रयोग प्रयोग नगरिरहनुभएको बेलामा पनि स्थानसम्बन्धी जानकारी प्राप्त गर्न अनुरोध गरिरहने भएकोले तपाईंको यन्त्रले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्याको समाधान गर्न तपाईं यस यन्त्रको स्थानसम्बन्धी जानकारी नामक विकल्पलाई निष्क्रिय पार्न सक्नुहुन्छ।"</string>
+    <string name="dialog_location_message" product="default" msgid="2445581202508387558">"<xliff:g id="APP">%1$s</xliff:g> ले तपाईं उक्त एप प्रयोग नगरिरहनुभएको बेलामा पनि स्थानसम्बन्धी जानकारी प्राप्त गर्न अनुरोध गरिरहने भएकोले तपाईंको फोनले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्याको समाधान गर्न तपाईं यस फोनको स्थानसम्बन्धी जानकारी नामक विकल्पलाई निष्क्रिय पार्न सक्नुहुन्छ।"</string>
+    <string name="dialog_location_message" product="tablet" msgid="4012891295493865096">"<xliff:g id="APP">%1$s</xliff:g> ले तपाईं उक्त एप प्रयोग नगरिरहनुभएको बेलामा पनि स्थानसम्बन्धी जानकारी प्राप्त गर्न अनुरोध गरिरहने भएकोले तपाईंको ट्याब्लेटले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्याको समाधान गर्न तपाईं यस ट्याब्लेटको स्थानसम्बन्धी जानकारी नामक विकल्पलाई निष्क्रिय पार्नसक्नुहुन्छ।"</string>
+    <string name="dialog_location_message" product="device" msgid="1454451610289205965">"<xliff:g id="APP">%1$s</xliff:g> ले तपाईं उक्त एप प्रयोग नगरिरहनुभएको बेलामा पनि स्थानसम्बन्धी जानकारी प्राप्त गर्न अनुरोध गरिरहने भएकोले तपाईंको यन्त्रले सामान्य रूपमा ब्याट्रीको व्यवस्थापन गर्न सक्दैन।\n\nयो समस्याको समाधान गर्न तपाईं यस यन्त्रको स्थानसम्बन्धी जानकारी नामक विकल्पलाई निष्क्रिय पार्न सक्नुहुन्छ।"</string>
     <string name="dialog_location_ok" msgid="1893773880878134342">"निष्क्रिय पार्नुहोस्"</string>
     <string name="power_screen" msgid="8581228752332223154">"स्क्रिन"</string>
     <string name="power_flashlight" msgid="6939780588882301575">"फ्ल्यासलाइट"</string>
@@ -2388,8 +2393,8 @@
     <string name="usage_type_computed_power" msgid="2594890316149868151">"शक्ति प्रयोगको हिसाब गरियो"</string>
     <string name="usage_type_actual_power" msgid="8067253427718526111">"शक्ति प्रयोग अवलोकन गरियो"</string>
     <string name="battery_action_stop" msgid="1866624019460630143">"जबरजस्ती रोक्नुहोस्"</string>
-    <string name="battery_action_app_details" msgid="1077011181969550402">"अनुप्रयोगको जानकारी"</string>
-    <string name="battery_action_app_settings" msgid="587998773852488539">"अनुप्रयोग सेटिङहरू"</string>
+    <string name="battery_action_app_details" msgid="1077011181969550402">"एपको जानकारी"</string>
+    <string name="battery_action_app_settings" msgid="587998773852488539">"एप सेटिङहरू"</string>
     <string name="battery_action_display" msgid="4887913003634317465">"स्क्रिन सेटिङहरू"</string>
     <string name="battery_action_wifi" msgid="7123520587925323824">"Wi-Fi सेटिङहरू"</string>
     <string name="battery_action_bluetooth" msgid="718594420017519807">"ब्लुटुथ सेटिङहरू"</string>
@@ -2408,7 +2413,7 @@
     <string name="battery_sugg_bluetooth_basic" msgid="6353294067057749310">"तपाईँले प्रयोग नगर्दा ब्लुटुथ बन्द गर्नुहोस्"</string>
     <string name="battery_sugg_bluetooth_headset" msgid="2421931037149315202">"एउटा फरक ब्लुटुथ उपकरणसँग जोड्ने प्रयास गर्नुहोस्"</string>
     <string name="battery_desc_apps" msgid="6826726880149226823">"अनुप्रयोगद्वारा प्रयोग गरिएको ब्याट्री"</string>
-    <string name="battery_sugg_apps_info" msgid="9175761965559743977">"अनुप्रयोग बन्द गर्नुहोस् वा स्थापना रद्द गर्नुहोस्"</string>
+    <string name="battery_sugg_apps_info" msgid="9175761965559743977">"एप बन्द गर्नुहोस् वा स्थापना रद्द गर्नुहोस्"</string>
     <string name="battery_sugg_apps_gps" msgid="489694612870772770">"ब्याट्री बचत मोड चयन गर्नुहोस्"</string>
     <string name="battery_sugg_apps_settings" msgid="20465932930350295">"अनुप्रयोगले ब्याट्रिको प्रयोग कम गर्नाका लागि सेटिङहरू प्रस्ताव गर्न सक्छ"</string>
     <string name="battery_desc_users" msgid="3736510265433457165">"प्रयोगकर्ताद्वारा प्रयोग गरिको ब्याट्री"</string>
@@ -2440,19 +2445,19 @@
     <string name="menu_stats_refresh" msgid="9017362786647223203">"पुनःताजा गर्नुहोस्"</string>
     <string name="process_kernel_label" msgid="4175060316414593760">"एन्ड्रोइड OS"</string>
     <string name="process_mediaserver_label" msgid="8591722404282619153">"मिडिया सर्भर"</string>
-    <string name="process_dex2oat_label" msgid="8249082119748556085">"अनुप्रयोग आफू अनुकूल"</string>
+    <string name="process_dex2oat_label" msgid="8249082119748556085">"एप आफू अनुकूल"</string>
     <string name="battery_saver" msgid="3989710213758938398">"ब्याट्री सेभर"</string>
     <string name="battery_saver_auto_title" msgid="4158659069641849952">"स्वतः सक्रिय गर्नुहोस्"</string>
     <string name="battery_saver_auto_no_schedule" msgid="739814529432092706">"कुनै पनि समयतालिका छैन"</string>
-    <string name="battery_saver_auto_routine" msgid="886514412067906980">"तपाईंको दिनचर्यामा आधारित"</string>
+    <string name="battery_saver_auto_routine" msgid="886514412067906980">"तपाईंको दिनचर्याको आधारमा"</string>
     <string name="battery_saver_auto_percentage" msgid="5791982309331921556">"प्रतिशतमा आधारित"</string>
     <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"तपाईंले सामान्यतया ब्याट्री चार्ज गर्ने आगामी समयअगावै ब्याट्री सकिने सम्भावना भएमा ब्याट्री सेभर सुविधा सक्रिय हुन्छ"</string>
     <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"<xliff:g id="PERCENT">%1$s</xliff:g> हुँदा सक्रिय हुने छ"</string>
     <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"समयतालिका सेट गर्नुहोस्‌"</string>
     <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"चार्ज पूरा भएपछि निष्क्रिय पार्नुहोस्"</string>
-    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"तपाईंको फोन <xliff:g id="PERCENT">%1$s</xliff:g> भएपछि ब्याट्री सेभर निष्क्रिय हुन्छ"</string>
-    <string name="battery_saver_sticky_description_new" product="tablet" msgid="3284967694001857194">"तपाईंको ट्याब्लेटको चार्ज <xliff:g id="PERCENT">%1$s</xliff:g> भएपछि ब्याट्री सेभर निष्क्रिय हुन्छ"</string>
-    <string name="battery_saver_sticky_description_new" product="device" msgid="5056520668081504111">"तपाईंको यन्त्र <xliff:g id="PERCENT">%1$s</xliff:g> भएपछि ब्याट्री सेभर निष्क्रिय हुन्छ"</string>
+    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"तपाईंको फोन <xliff:g id="PERCENT">%1$s</xliff:g> भएपछि ब्याट्री सेभर अफ हुन्छ"</string>
+    <string name="battery_saver_sticky_description_new" product="tablet" msgid="3284967694001857194">"तपाईंको ट्याब्लेटको चार्ज <xliff:g id="PERCENT">%1$s</xliff:g> भएपछि ब्याट्री सेभर अफ हुन्छ"</string>
+    <string name="battery_saver_sticky_description_new" product="device" msgid="5056520668081504111">"तपाईंको यन्त्र <xliff:g id="PERCENT">%1$s</xliff:g> भएपछि ब्याट्री सेभर अफ हुन्छ"</string>
     <!-- no translation found for battery_saver_seekbar_title (7607123201469333645) -->
     <skip />
     <string name="battery_saver_seekbar_title_placeholder" msgid="2321082163892561703">"सक्रिय गर्नुहोस्"</string>
@@ -2461,7 +2466,7 @@
     <string name="battery_saver_turn_on_automatically_never" msgid="2623381258359775227">"कहिले पनि होइन"</string>
     <string name="battery_saver_turn_on_automatically_pct" msgid="434270432432390307">"<xliff:g id="PERCENT">%1$s</xliff:g> ब्याट्री हुँदा"</string>
     <string name="battery_percentage" msgid="7782252476471033843">"ब्याट्रीको प्रतिशत"</string>
-    <string name="battery_percentage_description" msgid="9219875229166700610">"वस्तुस्थिति पट्टीमा ब्याट्रीको प्रतिशत देखाउनुहोस्"</string>
+    <string name="battery_percentage_description" msgid="9219875229166700610">"स्टाटस बारमा ब्याट्रीको प्रतिशत देखाउनुहोस्"</string>
     <string name="process_stats_summary_title" msgid="9189588417488537954">"प्रक्रिया तथ्याङ्क"</string>
     <string name="process_stats_summary" msgid="8077998499161221885">"चालु रहने प्रक्रियाहरूको बारेको geeky तथ्याङ्क"</string>
     <string name="app_memory_use" msgid="5126237308545653706">"मेमोरी प्रयोग"</string>
@@ -2512,9 +2517,9 @@
     <string name="tts_spoken_language" msgid="8057256621711361944">"बोलीचालीको भाषा"</string>
     <string name="tts_install_voices_title" msgid="363811937643579286">"आवाजहरू स्थापना गर्नुहोस्"</string>
     <string name="tts_install_voices_text" msgid="7464832428439739995">"आवाजहरू स्थापना गर्न  <xliff:g id="TTS_APP_NAME">%s</xliff:g> अनुप्रयोगतर्फ अघि बढिरहनुहोस्"</string>
-    <string name="tts_install_voices_open" msgid="686776451008134790">"अनुप्रयोग खोल्नुहोस्"</string>
+    <string name="tts_install_voices_open" msgid="686776451008134790">"एप खोल्नुहोस्"</string>
     <string name="tts_install_voices_cancel" msgid="1622512922523479646">"रद्द गर्नुहोस्"</string>
-    <string name="tts_reset" msgid="8864073594540705579">"पुनःसेट गर्नुहोस्"</string>
+    <string name="tts_reset" msgid="8864073594540705579">"रिसेट गर्नुहोस्"</string>
     <string name="tts_play" msgid="9023430029380675514">"प्ले गर्नुहोस्"</string>
     <string name="vpn_settings_title" msgid="7008219502396889192">"VPN"</string>
     <string name="credentials_title" msgid="7119207354982673965">"प्रमाण संग्रहण"</string>
@@ -2538,7 +2543,7 @@
     <string name="credentials_reset_hint" msgid="3484350477764088169">"सम्पूर्ण सामग्री हटाउने हो?"</string>
     <string name="credentials_erased" msgid="7287088033523869085">"प्रमाण संग्रहण मेटियो।"</string>
     <string name="credentials_not_erased" msgid="9137227570738627637">"प्रामाणिक डेटा भण्डारण मेटाउन सकिएन।"</string>
-    <string name="usage_access_title" msgid="7981321142726540574">"उपयोग पहुँचसहितका अनुप्रयोग"</string>
+    <string name="usage_access_title" msgid="7981321142726540574">"उपयोग पहुँचसहितका एप"</string>
     <string name="emergency_tone_title" msgid="130211364025984428">"इमर्जेन्सी डाइलिङसम्बन्धी सङ्केत"</string>
     <string name="emergency_tone_summary" msgid="8035940153401622240">"आपातकालीन कल राखिएको बेलाको व्यवहार सेट गर्नुहोस्"</string>
     <string name="privacy_settings_title" msgid="3573891462732375772">"ब्याकअप"</string>
@@ -2547,37 +2552,37 @@
     <string name="backup_section_title" msgid="8177209731777904656">"ब्याकअप र पुनःस्थापना गर्नुहोस्"</string>
     <string name="personal_data_section_title" msgid="9161854418510071558">"व्यक्तिगत डेटा"</string>
     <string name="backup_data_title" msgid="4461508563849583624">"मेरो डेटा ब्याकअप गर्नुहोस्।"</string>
-    <string name="backup_data_summary" msgid="555459891017933746">"अनुप्रयोग डेटा, Wi-Fi पासवर्डहरू र Google सर्भरहरूका अन्य सेटिङहरूको ब्याकअप गर्नुहोस्"</string>
+    <string name="backup_data_summary" msgid="555459891017933746">"एप डेटा, Wi-Fi पासवर्डहरू र Google सर्भरहरूका अन्य सेटिङहरूको ब्याकअप गर्नुहोस्"</string>
     <string name="backup_configure_account_title" msgid="1534734650559070294">"ब्याकअप खाता"</string>
     <string name="backup_data_management_title" msgid="6299288795610243508">"ब्याकअप खाता व्यवस्थित गर्नुहोस्"</string>
-    <string name="include_app_data_title" msgid="6117211611131913293">"अनुप्रयोग डेटा समावेश"</string>
+    <string name="include_app_data_title" msgid="6117211611131913293">"एप डेटा समावेश"</string>
     <string name="auto_restore_title" msgid="8367486774010915221">"स्वतः पुनःप्राप्त"</string>
-    <string name="auto_restore_summary" msgid="1941047568966428377">"जब अनुप्रयोग पुनर्स्थापित गर्दा ब्याक अप गरिएका सेटिङहरू र डेटा पुनःप्राप्त गर्नुहोस्"</string>
+    <string name="auto_restore_summary" msgid="1941047568966428377">"जब एप पुनर्स्थापित गर्दा ब्याक अप गरिएका सेटिङहरू र डेटा पुनःप्राप्त गर्नुहोस्"</string>
     <string name="backup_inactive_title" msgid="5513496915638307750">"ब्याकअप सेवा सक्रिय छैन"</string>
     <string name="backup_configure_account_default_summary" msgid="5718298066335006412">"कुनै पनि खाताले ब्याकअप गरिएका डेटा हाल भण्डारण गरिरहेको छैन"</string>
     <string name="backup_erase_dialog_title" msgid="8178424339104463014"></string>
-    <string name="backup_erase_dialog_message" msgid="8767843355330070902">"तपाईँको Wi-Fi पासवर्डहरू, बुकमार्क, अन्य सेटिङहरू, र अनुप्रयोग डेटाको जगेडा राख्न बन्द गर्ने र Google सर्भरबाट सम्पूर्ण प्रतिलिपिहरू मेटाउने हो?"</string>
-    <string name="fullbackup_erase_dialog_message" msgid="2588536036471144070">"के यन्त्र डेटा (जस्तै Wi-Fi पासवर्डहरू र इतिहास कल) र अनुप्रयोग डेटा (जस्तै अनुप्रयोगहरू द्वारा भण्डारण सेटिङहरू र फाइलहरू) को ब्याकअपलाई रोक्ने, र थप रिमोट सर्भरहरूमा सबै प्रतिलिपिहरू मेटाउन चाहनु हुन्छ?"</string>
-    <string name="fullbackup_data_summary" msgid="406274198094268556">"यन्त्र डेटा (जस्तै Wi-Fi पासवर्डहरू र कल इतिहास) र अनुप्रयोग डेटा (जस्तै अनुप्रयोगहरूद्वारा भण्डारित सेटिङहरू र फाइलहरू) टाढाबाट स्वचालित रुपमा ब्याकअप गर्नुहोस्। \n\nजब तपाईं स्वचालित ब्याकअप यन्त्र सक्षम गर्नुहुन्छ, यन्त्र र अनुप्रयोग डेटा आवधिक रूपमा टाढाबाट सुरक्षित गरिएको छ। सम्पर्क, सन्देशहरू, र तस्बिरहरू जस्तै सम्भावित संवेदनशील डेटा सहित, अनुप्रयोग डेटा कुनै पनि डेटा हुनसक्छ जुन अनुप्रयोगले (विकासकर्ता सेटिङहरूमा आधारित) सुरक्षित गरेको छ।"</string>
+    <string name="backup_erase_dialog_message" msgid="8767843355330070902">"तपाईँको Wi-Fi पासवर्डहरू, बुकमार्क, अन्य सेटिङहरू, र एप डेटाको जगेडा राख्न बन्द गर्ने र Google सर्भरबाट सम्पूर्ण प्रतिलिपिहरू मेटाउने हो?"</string>
+    <string name="fullbackup_erase_dialog_message" msgid="2588536036471144070">"के यन्त्र डेटा (जस्तै Wi-Fi पासवर्डहरू र इतिहास कल) र एप डेटा (जस्तै एपहरू द्वारा भण्डारण सेटिङहरू र फाइलहरू) को ब्याकअपलाई रोक्ने, र थप रिमोट सर्भरहरूमा सबै प्रतिलिपिहरू मेटाउन चाहनु हुन्छ?"</string>
+    <string name="fullbackup_data_summary" msgid="406274198094268556">"यन्त्र डेटा (जस्तै Wi-Fi पासवर्डहरू र कल इतिहास) र एप डेटा (जस्तै एपहरूद्वारा भण्डारित सेटिङहरू र फाइलहरू) टाढाबाट स्वचालित रुपमा ब्याकअप गर्नुहोस्। \n\nजब तपाईं स्वचालित ब्याकअप यन्त्र सक्षम गर्नुहुन्छ, यन्त्र र एप डेटा आवधिक रूपमा टाढाबाट सुरक्षित गरिएको छ। सम्पर्क, सन्देशहरू, र तस्बिरहरू जस्तै सम्भावित संवेदनशील डेटा सहित, एप डेटा कुनै पनि डेटा हुनसक्छ जुन एपले (विकासकर्ता सेटिङहरूमा आधारित) सुरक्षित गरेको छ।"</string>
     <string name="device_admin_settings_title" msgid="2074319456047334589">"यन्त्रका प्रशासक सम्बन्धी सेटिङहरू"</string>
-    <string name="active_device_admin_msg" msgid="6929247869516924549">"यन्त्रको प्रशासन सम्बन्धी अनुप्रयोग"</string>
-    <string name="remove_device_admin" msgid="4413438593788336400">"यो यन्त्रको प्रशासकीय अनुप्रयोगलाई निष्क्रिय पार्नुहोस्"</string>
-    <string name="uninstall_device_admin" msgid="9017499299961719830">"अनुप्रयोगको स्थापना रद्द गर्नुहोस्"</string>
+    <string name="active_device_admin_msg" msgid="6929247869516924549">"यन्त्रको प्रशासन सम्बन्धी एप"</string>
+    <string name="remove_device_admin" msgid="4413438593788336400">"यो यन्त्रको प्रशासकीय एपलाई निष्क्रिय पार्नुहोस्"</string>
+    <string name="uninstall_device_admin" msgid="9017499299961719830">"एपको स्थापना रद्द गर्नुहोस्"</string>
     <string name="remove_and_uninstall_device_admin" msgid="5607703579731496253">"निष्क्रिय पार्नुहोस् तथा स्थापना रद्द गर्नुहोस्"</string>
-    <string name="select_device_admin_msg" msgid="4173769638399075387">"यन्त्रका प्रशासकीय अनुप्रयोगहरू"</string>
-    <string name="no_device_admins" msgid="4129231900385977460">"यन्त्रका प्रशासकीय अनुप्रयोगहरू उपलब्ध छैनन्"</string>
+    <string name="select_device_admin_msg" msgid="4173769638399075387">"यन्त्रका प्रशासकीय एपहरू"</string>
+    <string name="no_device_admins" msgid="4129231900385977460">"यन्त्रका प्रशासकीय एपहरू उपलब्ध छैनन्"</string>
     <string name="personal_device_admin_title" msgid="759440849188565661">"व्यक्तिगत"</string>
     <string name="managed_device_admin_title" msgid="8021522755492551726">"काम"</string>
     <string name="sms_access_restriction_enabled" msgid="3006320256764718303">"Restrict SMS तथा कलका लगहरूमाथिका पहुँचमा प्रतिबन्ध लगाउनुहोस्‌"</string>
     <string name="sms_access_restriction_enabled_summary" msgid="9011946580977780063">"पूर्वनिर्धारित फोन र सन्देश अनुप्रयोगहरूसँग मात्र SMS र कल लग अनुमति हुन्छ"</string>
     <string name="no_trust_agents" msgid="5757792915019113084">"विश्वस्त प्रतिनिधि उपलब्ध छैन"</string>
-    <string name="add_device_admin_msg" msgid="3573765823476931173">"यन्त्रको प्रशासन सम्बन्धी अनुप्रयोगलाई सक्रिय गर्ने हो?"</string>
-    <string name="add_device_admin" msgid="1621152410207260584">"यन्त्रको प्रशासन सम्बन्धी यो अनुप्रयोगलाई सक्रिय गर्नुहोस्"</string>
+    <string name="add_device_admin_msg" msgid="3573765823476931173">"यन्त्रको प्रशासन सम्बन्धी एपलाई सक्रिय गर्ने हो?"</string>
+    <string name="add_device_admin" msgid="1621152410207260584">"यन्त्रको प्रशासन सम्बन्धी यो एपलाई सक्रिय गर्नुहोस्"</string>
     <string name="device_admin_add_title" msgid="6097881332139146897">"यन्त्रको प्रशासक"</string>
-    <string name="device_admin_warning" msgid="4421817419326480449">"यस प्रशासक अनुप्रयोगलाई सक्रिय गर्नुले अनुप्रयोग <xliff:g id="APP_NAME">%1$s</xliff:g> लाई निम्न कार्यहरू गर्न दिनेछ:"</string>
-    <string name="device_admin_status" msgid="5424944611789040723">"यो प्रशासक सक्रिय छ र अनुप्रयोग <xliff:g id="APP_NAME">%1$s</xliff:g> लाई  निम्न कार्यहरू गर्न दिन्छ:"</string>
+    <string name="device_admin_warning" msgid="4421817419326480449">"यस प्रशासक एपलाई सक्रिय गर्नुले एप <xliff:g id="APP_NAME">%1$s</xliff:g> लाई निम्न कार्यहरू गर्न दिनेछ:"</string>
+    <string name="device_admin_status" msgid="5424944611789040723">"यो प्रशासक सक्रिय छ र एप <xliff:g id="APP_NAME">%1$s</xliff:g> लाई  निम्न कार्यहरू गर्न दिन्छ:"</string>
     <string name="profile_owner_add_title" msgid="735805919754362791">"प्रोफाइल प्रबन्धक सक्रिय गर्नुहुन्छ?"</string>
-    <string name="adding_profile_owner_warning" msgid="1284541194547382194">"अगाडि बढेर, तपाईंको प्रयोगकर्तालाई तपाईंको प्रशासकले व्यवस्थित गर्ने छ, जसले तपाईंको व्यक्तिगत डेटाका साथै सम्बन्धित डेटा समेत भण्डारण गर्न सक्छ।\n\nतपाईंको प्रशासकसँग यो प्रयोगकर्तासँग सम्बन्धित सेटिङ, पहुँच, अनुप्रयोग, र डेटाका साथै नेटवर्क गतिविधि र तपाईंको यन्त्रका स्थानसम्बन्धी जानकारीहरूको अनुगमन र व्यवस्थापन गर्ने क्षमता छ।"</string>
+    <string name="adding_profile_owner_warning" msgid="1284541194547382194">"अगाडि बढेर, तपाईंको प्रयोगकर्तालाई तपाईंको प्रशासकले व्यवस्थित गर्ने छ, जसले तपाईंको व्यक्तिगत डेटाका साथै सम्बन्धित डेटा समेत भण्डारण गर्न सक्छ।\n\nतपाईंको प्रशासकसँग यो प्रयोगकर्तासँग सम्बन्धित सेटिङ, पहुँच, एप, र डेटाका साथै नेटवर्क गतिविधि र तपाईंको यन्त्रका स्थानसम्बन्धी जानकारीहरूको अनुगमन र व्यवस्थापन गर्ने क्षमता छ।"</string>
     <string name="admin_disabled_other_options" msgid="8097063307730025707">"अन्य विकल्पहरूलाई तपाईंको प्रशासकले असक्षम पार्नुभएको छ"</string>
     <string name="admin_more_details" msgid="1719819589822345585">"थप विवरणहरू"</string>
     <string name="notification_log_title" msgid="4200467765474474753">"अधिसूचना लग"</string>
@@ -2595,13 +2600,13 @@
     <string name="managed_profile_not_available_label" msgid="8784246681719821917">"कार्य प्रोफाइल अझै उपलब्ध भएको छैन"</string>
     <string name="work_mode_label" msgid="6845849194740195757">"कार्य प्रोफाइल"</string>
     <string name="work_mode_on_summary" msgid="1682781113156323592">"तपाईंको सङ्गठनले व्यवस्थापन गरेको"</string>
-    <string name="work_mode_off_summary" msgid="1688885392211178315">"अनुप्रयोग तथा सूचनाहरू निष्क्रिय छन्‌"</string>
-    <string name="remove_managed_profile_label" msgid="4625542553784793536">"कार्य प्रोफाइल हटाउनुहोस्"</string>
+    <string name="work_mode_off_summary" msgid="1688885392211178315">"एप तथा सूचनाहरू निष्क्रिय छन्‌"</string>
+    <string name="remove_managed_profile_label" msgid="4625542553784793536">"कार्यालयसम्बन्धी प्रोफाइल हटाउनुहोस्"</string>
     <string name="background_data" msgid="8275750862371471171">"पृष्ठभूमि डेटा"</string>
-    <string name="background_data_summary" msgid="799640633948841990">"अनुप्रयोगहरूले कुनै पनि समयमा डेटा सिंक गर्न पठाउन र प्राप्त गर्न सक्दछन्"</string>
+    <string name="background_data_summary" msgid="799640633948841990">"एपहरूले कुनै पनि समयमा डेटा सिंक गर्न पठाउन र प्राप्त गर्न सक्दछन्"</string>
     <string name="background_data_dialog_title" msgid="8306650658158895976">"पृष्ठभूमि डेटा असक्षम पार्ने हो?"</string>
-    <string name="background_data_dialog_message" msgid="8126774244911656527">"पृष्ठभूमि डेटा असक्षम पार्नाले ब्याट्रिको जीवनकाल बढाउदछ र डेटाको प्रयोग घटाउदछ, केही अनुप्रयोगहरूले अझैं पनि पृष्ठभूमि डेटा जडान प्रयोग गर्न सक्छ।"</string>
-    <string name="sync_automatically" msgid="5746117156896468099">"अटो-सिंक अनुप्रयोग डेटा"</string>
+    <string name="background_data_dialog_message" msgid="8126774244911656527">"पृष्ठभूमि डेटा असक्षम पार्नाले ब्याट्रिको जीवनकाल बढाउदछ र डेटाको प्रयोग घटाउदछ, केही एपहरूले अझैं पनि पृष्ठभूमि डेटा जडान प्रयोग गर्न सक्छ।"</string>
+    <string name="sync_automatically" msgid="5746117156896468099">"अटो-सिंक एप डेटा"</string>
     <string name="sync_enabled" msgid="535172627223336983">"सिंक खुला छ"</string>
     <string name="sync_disabled" msgid="713721807204805062">"सिंक बन्द छ"</string>
     <string name="sync_error" msgid="988155155932442765">"सिंक त्रुटि"</string>
@@ -2617,7 +2622,7 @@
     <string name="sync_calendar" msgid="6573708019827519372">"पात्रो"</string>
     <string name="sync_contacts" msgid="5687434785723746534">"सम्पर्कहरू"</string>
     <string name="sync_plug" msgid="6703804441408427257"><font fgcolor="#ffffffff">"Google सिंकमा स्वागत छ!"</font>\n" तपाईंका सम्पर्कहरू, भेट्ने समयहरू, र तपाईं जहाँ भए पनि अरू बढी पहुँच दिनको लागि डेटा सिंक गर्न अनुमतिका लागि एउटा Google दृष्टिकोण।"</string>
-    <string name="header_application_sync_settings" msgid="4581847153669774489">"अनुप्रयोग सिंक सेटिङहरू"</string>
+    <string name="header_application_sync_settings" msgid="4581847153669774489">"एप सिंक सेटिङहरू"</string>
     <string name="header_data_and_synchronization" msgid="400831816068697286">"डेटा र सिङ्क्रोनाइजेसन"</string>
     <string name="preference_change_password_title" msgid="7243527448378789274">"पासवर्ड बदल्नुहोस्"</string>
     <string name="header_account_settings" msgid="8586173964125512219">"खाता सेटिङहरू"</string>
@@ -2633,7 +2638,7 @@
     <string name="enter_password" msgid="2963496904625715235">"Android सुरु गर्न, आफ्नो पासवर्ड प्रविष्टि गर्नुहोस्"</string>
     <string name="enter_pin" msgid="7140938268709546890">"Android सुरु गर्न, आफ्नो पिन प्रविष्टि गर्नुहोस्"</string>
     <string name="enter_pattern" msgid="1653841963422825336">"Android सुरु गर्न, आफ्नो ढाँचा कोर्नुहोस्"</string>
-    <string name="cryptkeeper_wrong_pattern" msgid="4580105105385125467">"गलत ढाँचा"</string>
+    <string name="cryptkeeper_wrong_pattern" msgid="4580105105385125467">"प्याटर्न मिलेन"</string>
     <string name="cryptkeeper_wrong_password" msgid="1709534330303983166">"गलत पासवर्ड"</string>
     <string name="cryptkeeper_wrong_pin" msgid="857757190077859245">"गलत PIN"</string>
     <string name="checking_decryption" msgid="5927759912073053101">"जाँच गर्दै..."</string>
@@ -2646,12 +2651,12 @@
     <string name="data_usage_summary_title" msgid="7288431048564861043">"डेटाको प्रयोग"</string>
     <string name="data_usage_app_summary_title" msgid="8277327968906074983">"मोबाइल डेटा तथा Wi‑Fi"</string>
     <string name="data_usage_accounting" msgid="4681642832010140640">"वाहक डेटा लेखा तपाईँको उपकरणबाट फरक हुन सक्छ।"</string>
-    <string name="data_usage_app" msgid="4995297799363021198">"अनुप्रयोग उपयोग"</string>
+    <string name="data_usage_app" msgid="4995297799363021198">"एप उपयोग"</string>
     <string name="data_usage_app_info_label" msgid="5358288895158910477">"APP INFO"</string>
     <string name="data_usage_cellular_data" msgid="3509117353455285808">"मोबाइल डेटा"</string>
     <string name="data_usage_data_limit" msgid="4070740691087063670">"डेटा सीमा सेट गर्नुहोस्"</string>
     <string name="data_usage_cycle" msgid="1877235461828192940">"डेटाको प्रयोग चक्र"</string>
-    <string name="data_usage_app_items_header_text" msgid="5396134508509913851">"अनुप्रयोग उपयोग"</string>
+    <string name="data_usage_app_items_header_text" msgid="5396134508509913851">"एप उपयोग"</string>
     <string name="data_usage_menu_roaming" msgid="6933555994416977198">"डेटा रोमिङ"</string>
     <string name="data_usage_menu_restrict_background" msgid="3539289148113800518">"पृष्ठभूमि डेटा प्रतिबन्धि गर्नुहोस्"</string>
     <string name="data_usage_menu_allow_background" msgid="2874898501715368528">"पृष्ठभूमि डेटालाई अनुमति"</string>
@@ -2665,10 +2670,10 @@
     <string name="data_usage_menu_sim_cards" msgid="8508154611676507088">"SIM कार्डहरू"</string>
     <string name="data_usage_cellular_data_summary" msgid="9162777397135709280">"सीमामा रोकिएको"</string>
     <string name="account_settings_menu_auto_sync" msgid="2673669556006027506">"डेटा स्वत: सिंक गर्नुहोस्"</string>
-    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"व्यक्तिगत डेटा स्वचालित सिंक"</string>
-    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"कार्य डेटा स्वचालित सिंक"</string>
+    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"व्यक्तिगत डेटा स्वतः सिंक गरियोस् सिंक"</string>
+    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"कार्यालयको डेटाको अटोसिंक सिंक"</string>
     <string name="data_usage_change_cycle" msgid="447761920472170031">"साइकल परिवर्तन गर्नुहोस्..."</string>
-    <string name="data_usage_pick_cycle_day" msgid="6319750879145917066">"महिनाको दिनमा डेटाको प्रयोग चक्र पुनःसेट गर्ने:"</string>
+    <string name="data_usage_pick_cycle_day" msgid="6319750879145917066">"महिनाको दिनमा डेटाको प्रयोग चक्र रिसेट गर्ने:"</string>
     <string name="data_usage_empty" msgid="7981405723435034032">"यस समयमा कुनै अनुप्रयोगले डेटाको प्रयोग गरेन।"</string>
     <string name="data_usage_label_foreground" msgid="2471091128648754601">"अग्रभूमि"</string>
     <string name="data_usage_label_background" msgid="1618794447370396845">"पृष्ठभूमि"</string>
@@ -2691,19 +2696,19 @@
     <string name="data_roaming_enable_mobile" msgid="5886394350890765947">"रोमिङ"</string>
     <string name="data_usage_forground_label" msgid="8992577451178005406">"अग्रभूमि:"</string>
     <string name="data_usage_background_label" msgid="8460891123904985128">"पृष्ठभूमि:"</string>
-    <string name="data_usage_app_settings" msgid="3276444867375694809">"अनुप्रयोग सेटिङहरू"</string>
+    <string name="data_usage_app_settings" msgid="3276444867375694809">"एप सेटिङहरू"</string>
     <string name="data_usage_app_restrict_background" msgid="649167881583859169">"पृष्ठभूमि डेटा"</string>
     <string name="data_usage_app_restrict_background_summary" msgid="2703967920234671881">"पृष्ठभूमिमा मोबाइल डेटाको उपयोग सक्षम गर्नुहोस्"</string>
-    <string name="data_usage_app_restrict_background_summary_disabled" msgid="7211921499365814638">"यस अनुप्रयोगलाई पृष्ठभूमि डेटामा सीमित गराउन पहिले मोबाइल डेटा सीमा सेट गर्नुहोस्।"</string>
+    <string name="data_usage_app_restrict_background_summary_disabled" msgid="7211921499365814638">"यस एपलाई पृष्ठभूमि डेटामा सीमित गराउन पहिले मोबाइल डेटा सीमा सेट गर्नुहोस्।"</string>
     <string name="data_usage_app_restrict_dialog_title" msgid="750037964591673167">"पृष्ठभूमि डेटा प्रतिबन्ध गर्ने हो?"</string>
-    <string name="data_usage_app_restrict_dialog" msgid="4022530391896478031">"यस फिचरले पृष्ठभूमि डेटामा निर्भर अनुप्रयोगलाई मोबाइल सञ्जाल उपलब्ध हुने समयमा मात्र काम नगर्ने बनाउन सक्छ। \n \n यस अनुप्रयोग भित्रको सेटिङमा तपाईँले थप उपयुक्त डेटाको प्रयोग नियन्त्रणहरू भेट्टाउन सक्नुहुन्छ।"</string>
+    <string name="data_usage_app_restrict_dialog" msgid="4022530391896478031">"यस फिचरले पृष्ठभूमि डेटामा निर्भर एपलाई मोबाइल सञ्जाल उपलब्ध हुने समयमा मात्र काम नगर्ने बनाउन सक्छ। \n \n यस एप भित्रको सेटिङमा तपाईँले थप उपयुक्त डेटाको प्रयोग नियन्त्रणहरू भेट्टाउन सक्नुहुन्छ।"</string>
     <string name="data_usage_restrict_denied_dialog" msgid="18928292832775805">"तपाईंले मोबाइल डेटाको सीमा सेट गर्नुभएको बेलामा मात्र पृष्ठभूमिको डेटालाई सीमित गर्न सम्भव हुन्छ।"</string>
     <string name="data_usage_auto_sync_on_dialog_title" msgid="2342323408229702005">"डेटा स्वचालित सिंक खोल्ने हो?"</string>
     <string name="data_usage_auto_sync_on_dialog" product="tablet" msgid="4935430284683238901">"तपाईंले वेबमा आफ्नो खातामा गर्न हुने कुनै पनि परिवर्तनहरू स्वचालित रूपमा तपाईँको ट्याब्लेटमा प्रतिलिपि गरिने छ।\n\nकेही खाता पनि स्वचालित वेब ट्याब्लेटमा तपाईंले बनाउने कुनै पनि परिवर्तनहरू प्रतिलिपि हुनसक्छ। Google खाताले यसरी कार्य गर्दछ।"</string>
     <string name="data_usage_auto_sync_on_dialog" product="default" msgid="5004823486046340090">"तपाईंले वेबमा आफ्नो खातामा गर्न हुने कुनै पनि परिवर्तनहरू स्वचालित रूपमा तपाईँको फोनमा प्रतिलिपि गरिने छ।\n\nकेही खाता पनि स्वचालित वेब फोनमा तपाईंले बनाउने कुनै पनि परिवर्तनहरू प्रतिलिपि हुनसक्छ। Google खाताले यसरी कार्य गर्दछ।"</string>
     <string name="data_usage_auto_sync_off_dialog_title" msgid="7105334544291643305">"डेटा स्वतः सिंक हुने कार्य बन्द गर्ने हो?"</string>
     <string name="data_usage_auto_sync_off_dialog" msgid="4057984234450947964">"यस कार्यले डेटा र ब्याट्री प्रयोगको बचत गर्दछ, तर तपाईंले प्रत्येक खाता म्यानुअल तरिकाले हालसालको जानकारी भेला पार्नु पर्ने हुन्छ। र तपाईंले अद्यावधिक हुने बेलामा सूचना प्राप्त गर्नु हुन्न।"</string>
-    <string name="data_usage_cycle_editor_title" msgid="4967309390043599889">"प्रयोग चक्र पुनःसेट गर्ने मिति"</string>
+    <string name="data_usage_cycle_editor_title" msgid="4967309390043599889">"प्रयोग चक्र रिसेट गर्ने मिति"</string>
     <string name="data_usage_cycle_editor_subtitle" msgid="6043098041946166597">"प्रत्येक महिनाको मिति:"</string>
     <string name="data_usage_cycle_editor_positive" msgid="9155752056537811646">"सेट गर्नुहोस्"</string>
     <string name="data_usage_warning_editor_title" msgid="1431385383278389290">"डेटा उपयोगबारे चेतावनी सेट गर्नुहोस्"</string>
@@ -2712,24 +2717,24 @@
     <string name="data_usage_limit_dialog_mobile" product="tablet" msgid="2000713577999830647">"तपाईंको ट्याब्लेट तपाईंले सेट गर्नुभएको अधिकतम डेटा प्रयोगको सीमामा पुगेपछि यसले मोबाइल डेटालाई निष्क्रिय पार्नेछ।\n\nतपाईंको ट्याब्लेटले र तपाईंको सेवा प्रदायकले फरक तरिकाले डेटा प्रयोगको मापन गर्न सक्ने हुनाले विवेकपूर्ण तरिकाले यसको सीमा सेट गर्ने बारे विचार गर्नुहोस्।"</string>
     <string name="data_usage_limit_dialog_mobile" product="default" msgid="943546278705619205">"तपाईंको फोन तपाईंले सेट गर्नुभएको अधिकतम डेटा प्रयोगको सीमामा पुगेपछि यसले मोबाइल डेटालाई निष्क्रिय पार्नेछ।\n\nतपाईंको फोनले र तपाईंको सेवा प्रदायकले फरक तरिकाले डेटा प्रयोगको मापन गर्न सक्ने हुनाले विवेकपूर्ण तरिकाले यसको सीमा सेट गर्ने बारे विचार गर्नुहोस्।"</string>
     <string name="data_usage_restrict_background_title" msgid="3568746530413220844">"पृष्ठभूमि डेटा प्रतिबन्ध गर्न चाहनुहुन्छ?"</string>
-    <string name="data_usage_restrict_background" msgid="995811034744808575">"तपाईंले पृष्ठभूमिको मोबाइल डेटालाई सीमित गर्नुहुन्छ भने केही अनुप्रयोग र सेवाहरूले तपाईं Wi‑Fi मा जडान नहुँदासम्म काम गर्ने छैनन्।"</string>
-    <string name="data_usage_restrict_background_multiuser" product="tablet" msgid="6032810839234864814">"तपाईंले पृष्ठभूमिको मोबाइल डेटालाई सीमित गर्नुहुन्छ भने केही अनुप्रयोग र सेवाहरूले तपाईं Wi‑Fi मा जडान नहुँदासम्म काम गर्ने छैनन्।\n\nयस सेटिङले यस ट्याब्लेटमा भएका सबै प्रयोगकर्ताहरूलाई प्रभाव पार्दछ।"</string>
-    <string name="data_usage_restrict_background_multiuser" product="default" msgid="6846901756455789858">"तपाईंले पृष्ठभूमिको मोबाइल डेटालाई सीमित गर्नुहुन्छ भने केही अनुप्रयोग र सेवाहरूले तपाईं Wi‑Fi मा जडान नहुँदासम्म काम गर्ने छैनन्।\n\nयस सेटिङले यस फोनमा भएका सबै प्रयोगकर्ताहरूलाई प्रभाव पार्दछ।"</string>
+    <string name="data_usage_restrict_background" msgid="995811034744808575">"तपाईंले पृष्ठभूमिको मोबाइल डेटालाई सीमित गर्नुहुन्छ भने केही एप र सेवाहरूले तपाईं Wi‑Fi मा जडान नहुँदासम्म काम गर्ने छैनन्।"</string>
+    <string name="data_usage_restrict_background_multiuser" product="tablet" msgid="6032810839234864814">"तपाईंले पृष्ठभूमिको मोबाइल डेटालाई सीमित गर्नुहुन्छ भने केही एप र सेवाहरूले तपाईं Wi‑Fi मा जडान नहुँदासम्म काम गर्ने छैनन्।\n\nयस सेटिङले यस ट्याब्लेटमा भएका सबै प्रयोगकर्ताहरूलाई प्रभाव पार्दछ।"</string>
+    <string name="data_usage_restrict_background_multiuser" product="default" msgid="6846901756455789858">"तपाईंले पृष्ठभूमिको मोबाइल डेटालाई सीमित गर्नुहुन्छ भने केही एप र सेवाहरूले तपाईं Wi‑Fi मा जडान नहुँदासम्म काम गर्ने छैनन्।\n\nयस सेटिङले यस फोनमा भएका सबै प्रयोगकर्ताहरूलाई प्रभाव पार्दछ।"</string>
     <string name="data_usage_sweep_warning" msgid="4646401408698778092"><font size="18">" <xliff:g id="NUMBER">^1</xliff:g> "</font>" "<font size="9">" <xliff:g id="UNIT">^2</xliff:g> "</font>" \n "<font size="12">" चेतावनी "</font></string>
     <string name="data_usage_sweep_limit" msgid="6101105504557548269"><font size="18">" <xliff:g id="NUMBER">^1</xliff:g> "</font>" "<font size="9">" <xliff:g id="UNIT">^2</xliff:g> "</font>" \n "<font size="12">" सीमा "</font></string>
-    <string name="data_usage_uninstalled_apps" msgid="4152786786140875769">"हटाइएका अनुप्रयोगहरू"</string>
-    <string name="data_usage_uninstalled_apps_users" msgid="61092462416505112">"अनुप्रयोगहरू र प्रयोगकर्ताहरू हटाइयो।"</string>
+    <string name="data_usage_uninstalled_apps" msgid="4152786786140875769">"हटाइएका एपहरू"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="61092462416505112">"एपहरू र प्रयोगकर्ताहरू हटाइयो।"</string>
     <string name="data_usage_received_sent" msgid="5532467049487334656">"<xliff:g id="RECEIVED">%1$s</xliff:g> प्राप्त गरियो, <xliff:g id="SENT">%2$s</xliff:g> पठाइयो"</string>
     <string name="data_usage_total_during_range" msgid="7307562900020512747">"<xliff:g id="RANGE">%2$s</xliff:g>: करिब <xliff:g id="TOTAL">%1$s</xliff:g> प्रयोग भएको।"</string>
     <string name="data_usage_total_during_range_mobile" product="tablet" msgid="366118962920532455">"<xliff:g id="RANGE">%2$s</xliff:g>: को बारेमा <xliff:g id="TOTAL">%1$s</xliff:g> तपाईँको ट्याब्लेटले नापे जस्तो रूपमा प्रयोग भयो। तपाईँको ढुवानीको डेटा उपयोग लेखा सायद भिन्न हुन सक्छ।"</string>
     <string name="data_usage_total_during_range_mobile" product="default" msgid="3504412681869806383">"<xliff:g id="RANGE">%2$s</xliff:g>: करिब<xliff:g id="TOTAL">%1$s</xliff:g> प्रयोग भएको, तपाईँको फोनले मापन गरेअनुसार। तपाईँको डेटाको प्रयोग बाहकको खाता अनुसार फरक पर्न सक्छ।"</string>
     <string name="data_usage_metered_title" msgid="6827619643999794429">"सञ्जाल प्रतिबन्धहरू"</string>
-    <string name="data_usage_metered_body" msgid="1342905101297753439">"पृष्ठभूमिको डेटा सीमित गरिएको बेला सीमित नेटवर्कहरूलाई मोबाइल डेटा जस्तै मानिन्छ। ठूला फाइलहरू डाउनलोड गर्नाका लागि यी नेटवर्कहरूको प्रयोग गर्नुअघि अनुप्रयोगहरूले चेतावनी दिन सक्छन्।"</string>
+    <string name="data_usage_metered_body" msgid="1342905101297753439">"पृष्ठभूमिको डेटा सीमित गरिएको बेला सीमित नेटवर्कहरूलाई मोबाइल डेटा जस्तै मानिन्छ। ठूला फाइलहरू डाउनलोड गर्नाका लागि यी नेटवर्कहरूको प्रयोग गर्नुअघि एपहरूले चेतावनी दिन सक्छन्।"</string>
     <string name="data_usage_metered_mobile" msgid="3675591449158207593">"मोबाइल नेटवर्क"</string>
     <string name="data_usage_metered_wifi" msgid="2955256408132426720">"मिटर राखिएका Wi-Fi सञ्जालहरू"</string>
     <string name="data_usage_metered_wifi_disabled" msgid="5771083253782103415">"मिटर राखिएका सञ्जालहरू चयन गर्न, Wi-Fi खोल्नुहोस्।"</string>
     <string name="data_usage_metered_auto" msgid="7924116401382629319">"स्वचालित"</string>
-    <string name="data_usage_metered_yes" msgid="7333744880035386073">"मिटर चल्ने बनाइएको छ"</string>
+    <string name="data_usage_metered_yes" msgid="7333744880035386073">"शुल्क लाग्ने"</string>
     <string name="data_usage_metered_no" msgid="1961524615778610008">"शुल्क लाग्ने प्रावधान तय नगरिसकिएको"</string>
     <string name="data_usage_disclaimer" msgid="4683321532922590425">"वाहक डेटा लेखाकृत गर्ने तपाईँको उपकरणबाट फरक हुन सक्छ।"</string>
     <string name="cryptkeeper_emergency_call" msgid="4625420047524693116">"आपतकालीन कल"</string>
@@ -2830,27 +2835,27 @@
       <item quantity="one">प्रमाणपत्रलाई विश्वास गर्नुहोस् वा हटाउनुहोस्</item>
     </plurals>
     <plurals name="ssl_ca_cert_info_message_device_owner" formatted="false" msgid="9046046586061880100">
-      <item quantity="other"><xliff:g id="MANAGING_DOMAIN_1">%s</xliff:g> ले तपाईँको यन्त्रमा प्रमाणपत्र अख्तियारीहरूलाई स्थापना गरेको छ जसले त्यसलाई इमेल, अनुप्रयोग र सुरक्षित वेबसाइटहरू लगायत तपाईँको यन्त्रको नेटवर्क सम्बन्धी गतिविधिलाई अनुगमन गर्न अनुमति दिन सक्छ।\n\nयी प्रमाणपत्रहरू बारे थप जानकारीका लागि आफ्नो प्रशासकलाई सम्पर्क गर्नुहोस्।</item>
-      <item quantity="one"><xliff:g id="MANAGING_DOMAIN_0">%s</xliff:g> ले तपाईँको यन्त्रमा प्रमाणपत्र अख्तियारीलाई स्थापना गरेको छ जसले त्यसलाई इमेल, अनुप्रयोग र सुरक्षित वेबसाइटहरू लगायत तपाईँको यन्त्रको नेटवर्क सम्बन्धी गतिविधिलाई अनुगमन गर्न अनुमति दिन सक्छ।\n\nयस प्रमाणपत्र बारे थप जानकारीका लागि आफ्नो प्रशासकलाई सम्पर्क गर्नुहोस्।</item>
+      <item quantity="other"><xliff:g id="MANAGING_DOMAIN_1">%s</xliff:g> ले तपाईँको यन्त्रमा प्रमाणपत्र अख्तियारीहरूलाई स्थापना गरेको छ जसले त्यसलाई इमेल, एप र सुरक्षित वेबसाइटहरू लगायत तपाईँको यन्त्रको नेटवर्क सम्बन्धी गतिविधिलाई अनुगमन गर्न अनुमति दिन सक्छ।\n\nयी प्रमाणपत्रहरू बारे थप जानकारीका लागि आफ्नो प्रशासकलाई सम्पर्क गर्नुहोस्।</item>
+      <item quantity="one"><xliff:g id="MANAGING_DOMAIN_0">%s</xliff:g> ले तपाईँको यन्त्रमा प्रमाणपत्र अख्तियारीलाई स्थापना गरेको छ जसले त्यसलाई इमेल, एप र सुरक्षित वेबसाइटहरू लगायत तपाईँको यन्त्रको नेटवर्क सम्बन्धी गतिविधिलाई अनुगमन गर्न अनुमति दिन सक्छ।\n\nयस प्रमाणपत्र बारे थप जानकारीका लागि आफ्नो प्रशासकलाई सम्पर्क गर्नुहोस्।</item>
     </plurals>
     <plurals name="ssl_ca_cert_info_message" formatted="false" msgid="8271858091418779584">
-      <item quantity="other"><xliff:g id="MANAGING_DOMAIN_1">%s</xliff:g> ले तपाईँको कार्य प्रोफाइलका लागि प्रमाणपत्र अख्तियारीहरूलाई स्थापना गरेको छ जसले त्यसलाई इमेल, अनुप्रयोग र सुरक्षित वेबसाइटहरू लगायत कार्य प्रोफाइलको नेटवर्क सम्बन्धी गतिविधिलाई अनुगमन गर्न अनुमति दिन सक्छ।\n\nयी प्रमाणपत्रहरू बारे थप जानकारीका लागि आफ्नो प्रशासकलाई सम्पर्क गर्नुहोस्।</item>
-      <item quantity="one"><xliff:g id="MANAGING_DOMAIN_0">%s</xliff:g> ले तपाईँको कार्य प्रोफाइलका लागि प्रमाणपत्र अख्तियारीलाई स्थापना गरेको छ जसले त्यसलाई इमेल, अनुप्रयोग र सुरक्षित वेबसाइटहरू लगायत कार्य प्रोफाइलको नेटवर्क सम्बन्धी गतिविधिलाई अनुगमन गर्न अनुमति दिन सक्छ।\n\nयस प्रमाणपत्र बारे थप जानकारीका लागि आफ्नो प्रशासकलाई सम्पर्क गर्नुहोस्।</item>
+      <item quantity="other"><xliff:g id="MANAGING_DOMAIN_1">%s</xliff:g> ले तपाईँको कार्य प्रोफाइलका लागि प्रमाणपत्र अख्तियारीहरूलाई स्थापना गरेको छ जसले त्यसलाई इमेल, एप र सुरक्षित वेबसाइटहरू लगायत कार्य प्रोफाइलको नेटवर्क सम्बन्धी गतिविधिलाई अनुगमन गर्न अनुमति दिन सक्छ।\n\nयी प्रमाणपत्रहरू बारे थप जानकारीका लागि आफ्नो प्रशासकलाई सम्पर्क गर्नुहोस्।</item>
+      <item quantity="one"><xliff:g id="MANAGING_DOMAIN_0">%s</xliff:g> ले तपाईँको कार्य प्रोफाइलका लागि प्रमाणपत्र अख्तियारीलाई स्थापना गरेको छ जसले त्यसलाई इमेल, एप र सुरक्षित वेबसाइटहरू लगायत कार्य प्रोफाइलको नेटवर्क सम्बन्धी गतिविधिलाई अनुगमन गर्न अनुमति दिन सक्छ।\n\nयस प्रमाणपत्र बारे थप जानकारीका लागि आफ्नो प्रशासकलाई सम्पर्क गर्नुहोस्।</item>
     </plurals>
-    <string name="ssl_ca_cert_warning_message" msgid="8692156828262606685">"तपाईँको सञ्जाल गतिविधिको साथ इमेल, अनुप्रयोग र सुरक्षित वेबसाइटहरू सहितको अनुगमन गर्न तेस्रो पक्ष सक्षम छ। \n \n तपाईँको उपकरणमा स्थापित भएको बिश्वस्त गोप्य डेटाले गर्दा यो सम्भव भएको हो।"</string>
+    <string name="ssl_ca_cert_warning_message" msgid="8692156828262606685">"तपाईँको सञ्जाल गतिविधिको साथ इमेल, एप र सुरक्षित वेबसाइटहरू सहितको अनुगमन गर्न तेस्रो पक्ष सक्षम छ। \n \n तपाईँको उपकरणमा स्थापित भएको बिश्वस्त गोप्य डेटाले गर्दा यो सम्भव भएको हो।"</string>
     <plurals name="ssl_ca_cert_settings_button" formatted="false" msgid="3227175122066058245">
       <item quantity="other">प्रमाणपत्रहरूलाई जाँच गर्नुहोस्</item>
       <item quantity="one">प्रमाणपत्रलाई जाँच गर्नुहोस्</item>
     </plurals>
     <string name="user_settings_title" msgid="7917598650933179545">"बहु प्रयोगकर्ताहरू"</string>
-    <string name="user_settings_footer_text" product="device" msgid="4573858247439190545">"नयाँ प्रयोगकर्ताहरू थपेर आफ्नो यन्त्र आदान प्रदान गर्नुहोस्। प्रत्येक प्रयोगकर्तासँग आफू अनुकूल गृह स्क्रिन, खाता, अनुप्रयोग, सेटिङ र थप कुराहरूका लागि तपाईंको यन्त्रमा व्यक्तिगत स्थान हुन्छ।"</string>
-    <string name="user_settings_footer_text" product="tablet" msgid="780018221428132918">"नयाँ प्रयोगकर्ताहरू थपेर आफ्नो ट्याब्लेट आदान प्रदान गर्नुहोस्। प्रत्येक प्रयोगकर्तासँग आफू अनुकूल गृह स्क्रिन, खाता, अनुप्रयोग, सेटिङ र थप कुराहरूका लागि तपाईंको ट्याब्लेटमा व्यक्तिगत स्थान हुन्छ।"</string>
-    <string name="user_settings_footer_text" product="default" msgid="1470859614968237491">"नयाँ प्रयोगकर्ताहरू थपेर आफ्नो फोनआदान प्रदान गर्नुहोस्। प्रत्येक प्रयोगकर्तासँग आफू अनुकूल गृह स्क्रिन, खाता, अनुप्रयोग, सेटिङ र थप कुराहरूका लागि तपाईंको फोनमा व्यक्तिगत स्थान हुन्छ।"</string>
+    <string name="user_settings_footer_text" product="device" msgid="4573858247439190545">"नयाँ प्रयोगकर्ताहरू थपेर आफ्नो यन्त्र सेयर गर्नुहोस्। प्रत्येक प्रयोगकर्तासँग आफू अनुकूल गृह स्क्रिन, खाता, एप, सेटिङ र थप कुराहरूका लागि तपाईंको यन्त्रमा व्यक्तिगत स्थान हुन्छ।"</string>
+    <string name="user_settings_footer_text" product="tablet" msgid="780018221428132918">"नयाँ प्रयोगकर्ताहरू थपेर आफ्नो ट्याब्लेट सेयर गर्नुहोस्। प्रत्येक प्रयोगकर्तासँग आफू अनुकूल गृह स्क्रिन, खाता, एप, सेटिङ र थप कुराहरूका लागि तपाईंको ट्याब्लेटमा व्यक्तिगत स्थान हुन्छ।"</string>
+    <string name="user_settings_footer_text" product="default" msgid="1470859614968237491">"नयाँ प्रयोगकर्ताहरू थपेर आफ्नो फोन सेयर गर्नुहोस्। प्रत्येक प्रयोगकर्तासँग आफू अनुकूल गृह स्क्रिन, खाता, एप, सेटिङ र थप कुराहरूका लागि तपाईंको फोनमा व्यक्तिगत स्थान हुन्छ।"</string>
     <string name="user_list_title" msgid="6670258645246192324">"प्रयोगकर्ता र प्रोफाइलहरू"</string>
     <string name="user_add_user_or_profile_menu" msgid="4220679989900149336">"प्रयोगकर्ता वा प्रोफाइल थप गर्नुहोस्"</string>
     <string name="user_add_user_menu" msgid="9006572936456324794">"प्रयोगकर्ता थप्नुहोस्"</string>
     <string name="user_summary_restricted_profile" msgid="5214838615043574917">"निषेध गरिएको प्रोफाइल"</string>
-    <string name="user_need_lock_message" msgid="3421243467724322311">"निषेधयुक्त प्रोफाइल बनाउनु अघि तपाईँको अनुप्रयोग र व्यक्तिगत डेटा सुरक्षा गर्नाका लागि तपाईँले स्क्रिन लक सेटअप गर्नु पर्दछ ।"</string>
+    <string name="user_need_lock_message" msgid="3421243467724322311">"निषेधयुक्त प्रोफाइल बनाउनु अघि तपाईँको एप र व्यक्तिगत डेटा सुरक्षा गर्नाका लागि तपाईँले स्क्रिन लक सेटअप गर्नु पर्दछ ।"</string>
     <string name="user_set_lock_button" msgid="4660971133148866612">"लक सेट गर्नुहोस्"</string>
     <string name="user_summary_not_set_up" msgid="6436691939044332679">"सेटअप छैन"</string>
     <string name="user_summary_restricted_not_set_up" msgid="896552290436689508">"सेट भएको छैन - सीमित प्रोफाइल"</string>
@@ -2860,15 +2865,15 @@
     <string name="user_nickname" msgid="1088216221559125529">"उपनाम"</string>
     <string name="user_add_user_type_title" msgid="8672326434351387845">"थप्नुहोस्"</string>
     <string name="user_add_max_count" msgid="4524573950126500416">"तपाईँले <xliff:g id="USER_COUNT">%1$d</xliff:g> जना प्रयोगकर्ता सम्म थप्न सक्नुहुनेछ"</string>
-    <string name="user_add_user_item_summary" msgid="6114355152711455716">"प्रयोगकर्ताहरूसँग आफ्नै अनुप्रयोगहरू र सामग्री हुन्छ"</string>
-    <string name="user_add_profile_item_summary" msgid="6386283837789573755">"तपाईं आफ्नो खाताबाट अनुप्रयोगहरू र सामग्रीहरूको पहुँचलाई प्रतिबन्ध गर्न सक्नुहुन्छ"</string>
+    <string name="user_add_user_item_summary" msgid="6114355152711455716">"प्रयोगकर्ताहरूसँग आफ्नै एपहरू र सामग्री हुन्छ"</string>
+    <string name="user_add_profile_item_summary" msgid="6386283837789573755">"तपाईं आफ्नो खाताबाट एपहरू र सामग्रीहरूको पहुँचलाई प्रतिबन्ध गर्न सक्नुहुन्छ"</string>
     <string name="user_add_user_item_title" msgid="6835385073795492410">"प्रयोगकर्ता"</string>
     <string name="user_add_profile_item_title" msgid="4932743891449790664">"प्रतिबन्धित प्रोफाइल"</string>
     <string name="user_add_user_title" msgid="2320897397066676472">"नयाँ प्रयोगकर्ता थप्ने हो?"</string>
-    <string name="user_add_user_message_long" msgid="686637203224195465">"तपाईं थप प्रयोगकर्ताहरू सिर्जना गरेर यो यन्त्र अन्य मान्छेहरूसँग साझा रूपमा प्रयोग गर्न सक्नुहुन्छ। हरेक प्रयोगकर्ताको आफ्नै ठाउँ हुन्छ, जसलाई उनीहरू अनुप्रयोग, वालपेपर इत्यादिमार्फत आफू अनुकूल पार्न सक्छन्। प्रयोगकर्ताहरू सबैजनालाई असर पार्ने Wi-Fi जस्ता यन्त्रका सेटिङहरू पनि समायोजन गर्न सक्छन्।\n\nतपाईंले नयाँ प्रयोगकर्ता थप्दा उक्त व्यक्तिले आफ्नो ठाउँ सेटअप गर्नु पर्ने हुन्छ।\n\nकुनै पनि प्रयोगकर्ताले अन्य सबै प्रयोगकर्ताहरूका लागि अनुप्रयोगहरू अद्यावधिक गर्न सक्छन्। पहुँचसम्बन्धी सेटिङ तथा सेवाहरू नयाँ प्रयोगकर्तामा स्थानान्तरण नहुन सक्छन्।"</string>
-    <string name="user_add_user_message_short" msgid="1802594476285458254">"जब तपाईंले नयाँ प्रयोगकर्ता थप्नुहुन्छ, त्यो व्यक्तिले आफ्नो ठाउँ सेट गर्न आवश्यक छ।\n\nकुनै पनि प्रयोगकर्ताले सबै अन्य प्रयोगकर्ताहरूका लागि अनुप्रयोगहरू अद्यावधिक गर्न सक्छन्।"</string>
+    <string name="user_add_user_message_long" msgid="686637203224195465">"तपाईं थप प्रयोगकर्ताहरू सिर्जना गरेर ती प्रयोगकर्तालाई यो यन्त्र प्रयोग गर्न दिन सक्नुहुन्छ। हरेक प्रयोगकर्ताको आफ्नै ठाउँ हुन्छ। उनीहरू यो ठाउँमा आफ्नै एप, वालपेपर आदिका लागि प्रयोग गर्न सक्छन्। उनीहरू सबैजनालाई असर पार्ने Wi-Fi जस्ता यन्त्रका सेटिङहरू पनि परिवर्तन गर्न सक्छन्।\n\nतपाईंले नयाँ प्रयोगकर्ता थप्दा उक्त व्यक्तिले आफ्नो ठाउँ सेटअप गर्नु पर्ने हुन्छ।\n\nसबै प्रयोगकर्ता अन्य सबै प्रयोगकर्ताले प्रयोग गर्ने एपहरू अद्यावधिक गर्न सक्छन्। तर पहुँचसम्बन्धी सेटिङ तथा सेवाहरू नयाँ प्रयोगकर्तामा नसर्न सक्छ।"</string>
+    <string name="user_add_user_message_short" msgid="1802594476285458254">"जब तपाईंले नयाँ प्रयोगकर्ता थप्नुहुन्छ, त्यो व्यक्तिले आफ्नो ठाउँ सेट गर्न आवश्यक छ।\n\nकुनै पनि प्रयोगकर्ताले सबै अन्य प्रयोगकर्ताहरूका लागि एपहरू अद्यावधिक गर्न सक्छन्।"</string>
     <string name="user_setup_dialog_title" msgid="6748950002206392396">"अहिले प्रयोगकर्ता सेटअप गर्ने हो?"</string>
-    <string name="user_setup_dialog_message" msgid="2988559933258353919">"यन्त्र लिन र आफ्नो ठाउँ बनाउन व्यक्ति उपलब्ध छ भन्ने कुराको निश्चित गर्नुहोस्"</string>
+    <string name="user_setup_dialog_message" msgid="2988559933258353919">"यी व्यक्ति यन्त्र यो यन्त्र चलाउन र आफ्नो ठाउँ सेट गर्न उपलब्ध छन् भन्ने कुरा सुनिश्चित गर्नुहोस्"</string>
     <string name="user_setup_profile_dialog_message" msgid="7611900802824048526">"अहिले प्रोफाइल सेटअप गर्ने हो?"</string>
     <string name="user_setup_button_setup_now" msgid="4941459406266856176">"अब सेटअप गर्नुहोस्"</string>
     <string name="user_setup_button_setup_later" msgid="6596031428556518752">"अहिले होइन"</string>
@@ -2886,18 +2891,18 @@
     <string name="work_profile_confirm_remove_title" msgid="3168910958076735800">"कार्य प्रोफाइल हटाउने?"</string>
     <string name="user_confirm_remove_self_message" product="tablet" msgid="2889456786320157545">"तपाईं यस ट्याब्लेटमा आफ्नो ठाउँ र डेटा हराउनु हुने छ। तपाईं यो कार्यलाई अन्डु गर्न सक्नुहुन्न।"</string>
     <string name="user_confirm_remove_self_message" product="default" msgid="8441729423565705183">"तपाईं यस फोनमा आफ्नो ठाउँ र डेटा गुमाउनु हुनेछ। तपाईं यो कार्य पूर्ववत गर्न हुन्न।"</string>
-    <string name="user_confirm_remove_message" msgid="5202150470271756013">"सबै अनुप्रयोगहरू र डेटा मेटाइनेछन्।"</string>
-    <string name="work_profile_confirm_remove_message" msgid="1220672284385083128">"यदि तपाईँले जारी राख्नुभयो भने यो प्रोफाइलका सबै अनुप्रयोगहरू र डेटा मेटाइने छन्।"</string>
-    <string name="user_profile_confirm_remove_message" msgid="8376289888144561545">"सबै अनुप्रयोगहरू र डेटा मेटाइने छन्।"</string>
+    <string name="user_confirm_remove_message" msgid="5202150470271756013">"सबै एपहरू र डेटा मेटाइनेछन्।"</string>
+    <string name="work_profile_confirm_remove_message" msgid="1220672284385083128">"यदि तपाईँले जारी राख्नुभयो भने यो प्रोफाइलका सबै एपहरू र डेटा मेटाइने छन्।"</string>
+    <string name="user_profile_confirm_remove_message" msgid="8376289888144561545">"सबै एपहरू र डेटा मेटाइने छन्।"</string>
     <string name="user_adding_new_user" msgid="381717945749193417">"नयाँ प्रयोगकर्ता थप गरिँदै..."</string>
     <string name="user_delete_user_description" msgid="3627684990761268859">"प्रयोगकर्ता मेटाउनुहोस्"</string>
     <string name="user_delete_button" msgid="6747802570634772774">"मेट्नुहोस्"</string>
     <string name="user_guest" msgid="6226240869459683235">"अतिथि"</string>
     <string name="user_exit_guest_title" msgid="7279886200373071797">"अतिथि हटाउनुहोस्"</string>
     <string name="user_exit_guest_confirm_title" msgid="4767911571671099844">"अतिथि हटाउने हो?"</string>
-    <string name="user_exit_guest_confirm_message" msgid="6955182181145748919">"यस सत्रमा सबै अनुप्रयोगहरू र डेटा मेटाइनेछ।"</string>
+    <string name="user_exit_guest_confirm_message" msgid="6955182181145748919">"यस सत्रमा सबै एपहरू र डेटा मेटाइनेछ।"</string>
     <string name="user_exit_guest_dialog_remove" msgid="1878866060881115716">"हटाउनुहोस्"</string>
-    <string name="user_enable_calling" msgid="864760054792249503">"फोन कलहरू सक्षम पार्नुहोस्"</string>
+    <string name="user_enable_calling" msgid="864760054792249503">"फोन गर्ने सेवा सक्रिय गर्नुहोस्"</string>
     <string name="user_enable_calling_sms" msgid="3450252891736718793">"फोन कल तथा SMS सक्षम पार्नुहोस्"</string>
     <string name="user_remove_user" msgid="3687544420125911166">"प्रयोगकर्ता मेटाउनुहोस्"</string>
     <string name="user_enable_calling_confirm_title" msgid="1141612415529158542">"फोन कलहरू सक्षम गर्ने हो?"</string>
@@ -2906,21 +2911,21 @@
     <string name="user_enable_calling_and_sms_confirm_message" msgid="3278802798876095734">"कल र SMS इतिहास यो प्रयोगकर्तासँग साझेदारी गरिने छ।"</string>
     <string name="emergency_info_title" msgid="1522609271881425375">"आपतकालीन सूचना"</string>
     <string name="emergency_info_summary" msgid="7280464759837387342">"<xliff:g id="USER_NAME">%1$s</xliff:g> का बारेमा जानकारी र सम्पर्क ठेगानाहरू"</string>
-    <string name="application_restrictions" msgid="6871981013736536763">"अनुप्रयोगहरू र सामग्री अनुमति दिनुहोस्"</string>
-    <string name="apps_with_restrictions_header" msgid="8656739605673756176">"प्रतिबन्धको साथ अनुप्रयोगहरू"</string>
-    <string name="apps_with_restrictions_settings_button" msgid="5065896213467171744">"अनुप्रयोगको लागि सेटिङहरू विस्तार गर्नुहोस्"</string>
+    <string name="application_restrictions" msgid="6871981013736536763">"एपहरू र सामग्री अनुमति दिनुहोस्"</string>
+    <string name="apps_with_restrictions_header" msgid="8656739605673756176">"प्रतिबन्धको साथ एपहरू"</string>
+    <string name="apps_with_restrictions_settings_button" msgid="5065896213467171744">"एपको लागि सेटिङहरू विस्तार गर्नुहोस्"</string>
     <string name="nfc_payment_settings_title" msgid="5070077706735415291">"ट्याप गरी भुक्तानी गर्नुहोस्"</string>
     <string name="nfc_payment_how_it_works" msgid="7607901964687787177">"यसले कसरी काम गर्दछ"</string>
     <string name="nfc_payment_no_apps" msgid="8844440783395420860">"स्टोरहरूमा तपाईँको फोनमार्फत भुक्तानी गर्नुहोस्।"</string>
-    <string name="nfc_payment_default" msgid="7869273092463612271">"पूर्वनिर्धारित भुक्तानी"</string>
+    <string name="nfc_payment_default" msgid="7869273092463612271">"पूर्वनिर्धारित भुक्तानी विधि"</string>
     <string name="nfc_payment_default_not_set" msgid="955804193510335338">"सेट गरिएको छैन"</string>
     <string name="nfc_payment_app_and_desc" msgid="102312684211458190">"<xliff:g id="APP">%1$s</xliff:g> - <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
-    <string name="nfc_payment_use_default" msgid="3098724195746409476">"पूर्वनिर्धारित प्रयोग गर्नुहोस्"</string>
+    <string name="nfc_payment_use_default" msgid="3098724195746409476">"पूर्वनिर्धारित विधि प्रयोग गर्नुहोस्"</string>
     <string name="nfc_payment_favor_default" msgid="7555356982142464260">"सधैँ"</string>
-    <string name="nfc_payment_favor_open" msgid="3739055715000436749">"अर्को भुक्तानी अनुप्रयोग खुला भएको बेला बाहेक"</string>
+    <string name="nfc_payment_favor_open" msgid="3739055715000436749">"अर्को भुक्तानी एप खुला भएको बेला बाहेक"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"ट्याप गरेर भुक्तानी गर्ने टर्मिनलमा यसमार्फत भुक्तानी गर्नुहोस्:"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"टर्मिनलमा भुक्तानी"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"एउटा भुक्तानी अनुप्रयोग सेटअप गर्नुहोस्। त्यसपछि तपाईँको फोनको पछाडिको भाग सम्पर्कविहीन सङ्केतमार्फत कुनै टर्मिनलमा होल्ड गर्नुहोस्।"</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"एउटा भुक्तानी एप सेटअप गर्नुहोस्। त्यसपछि आफ्नो फोनको पछाडिको भाग कन्ट्याक्टलेस सङ्केतभएको कुनै टर्मिनलले पहिचान गर्ने गरी होल्ड गर्नुहोस्।"</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"बुझेँ"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"थप..."</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"तपाईँको प्राथमिकताको रूपमा सेट गर्ने हो?"</string>
@@ -2957,9 +2962,9 @@
     <string name="preferred_network_type_title" msgid="1980819233332592332">"सञ्जाल प्रकार रुचाइएको"</string>
     <string name="preferred_network_type_summary" msgid="8828375904939960006">"LTE (सिफारिस गरिएको)"</string>
     <string name="work_sim_title" msgid="2885654516046971985">"कार्य SIM"</string>
-    <string name="user_restrictions_title" msgid="6454305007320972740">"अनुप्रयोग र सामग्री पहुँच"</string>
+    <string name="user_restrictions_title" msgid="6454305007320972740">"एप र सामग्री पहुँच"</string>
     <string name="user_rename" msgid="5624446289379780361">"पुनःनामाकरण गर्नुहोस्"</string>
-    <string name="app_restrictions_custom_label" msgid="8791627858467265176">"अनुप्रयोग प्रतिबन्धहरू सेट गर्नुहोस्"</string>
+    <string name="app_restrictions_custom_label" msgid="8791627858467265176">"एप प्रतिबन्धहरू सेट गर्नुहोस्"</string>
     <string name="user_restrictions_controlled_by" msgid="3442508299902131033">"<xliff:g id="APP">%1$s</xliff:g>द्वारा नियन्त्रित"</string>
     <string name="app_sees_restricted_accounts" msgid="2210750497683265281">"यो अनुप्रयोगले तपाईंको खाताहरू पहुँच गर्न सक्दैन।"</string>
     <string name="app_sees_restricted_accounts_and_controlled_by" msgid="5028333644657350816">"यो अनुप्रयोगले तपाईंका खाताहरू पहुँच गर्न सक्छ। <xliff:g id="APP">%1$s</xliff:g> द्वारा नियन्त्रित"</string>
@@ -2969,8 +2974,8 @@
     <string name="restriction_bluetooth_config_summary" msgid="5304900222614952895">"ब्लुटुथ जोडा बाँध्ने कार्य र सेटिङहरूलाई अनुमति दिनुहोस्।"</string>
     <string name="restriction_nfc_enable_title" msgid="5146674482590550598">"NFC"</string>
     <string name="restriction_nfc_enable_summary_config" msgid="405349698260328073">"जब यो <xliff:g id="DEVICE_NAME">%1$s</xliff:g> अर्को NFC उपकरणले छुन्छ डेटा विनिमयको अनुमति दिनुहोस्"</string>
-    <string name="restriction_nfc_enable_summary" product="tablet" msgid="3292205836938064931">"ट्याब्लेटले अर्को उपकरण छुँदा डेटा विनिमयलाई अनुमति दिनुहोस्"</string>
-    <string name="restriction_nfc_enable_summary" product="default" msgid="226439584043333608">"फोनले अर्को उपकरण छुँदा डेटा विनिमयलाई अनुमति दिनुहोस्"</string>
+    <string name="restriction_nfc_enable_summary" product="tablet" msgid="3292205836938064931">"ट्याब्लेटले अर्को उपकरण छुँदा डेटा एक अर्कामा सर्ने अनुमति दिनुहोस्"</string>
+    <string name="restriction_nfc_enable_summary" product="default" msgid="226439584043333608">"फोनले अर्को उपकरण छुँदा डेटा एक अर्कामा सर्ने अनुमति दिनुहोस्"</string>
     <string name="restriction_location_enable_title" msgid="358506740636434856">"स्थान"</string>
     <string name="restriction_location_enable_summary" msgid="4159500201124004463">"अनुप्रयोगहरुलाई तपाईँको स्थान जानकारी प्रयोग गर्न दिनुहोस्"</string>
     <string name="wizard_back" msgid="223654213898117594">"पछाडि जानुहोस्"</string>
@@ -3000,7 +3005,7 @@
     <string name="sim_editor_title" msgid="2303147682835318920">"SIM स्लट %1$d"</string>
     <string name="sim_editor_carrier" msgid="8860370077829961512">"वाहक"</string>
     <string name="sim_editor_number" msgid="1757338150165234970">"संख्या"</string>
-    <string name="sim_editor_color" msgid="373059962306191123">"SIM रङ"</string>
+    <string name="sim_editor_color" msgid="373059962306191123">"SIM रङ्ग"</string>
     <string name="sim_card_select_title" msgid="4925862525985187946">"सिम कार्ड चयन गर्नुहोस्"</string>
     <string name="color_orange" msgid="3159707916066563431">"ओरेन्ज"</string>
     <string name="color_purple" msgid="4391440966734810713">"बैजनी"</string>
@@ -3011,9 +3016,9 @@
     <string name="sim_outgoing_call_title" msgid="4683645160838507363">"बहिर्गमन कलको लागि SIM"</string>
     <string name="sim_other_call_settings" msgid="5656672788293240519">"अन्य कल सेटिङहरू"</string>
     <string name="preferred_network_offload_title" msgid="341815233467695133">"सञ्जाल अफलोड गर्न रुचाइयो"</string>
-    <string name="preferred_network_offload_header" msgid="7101507079686660843">"सञ्जाल नाम प्रसारण असक्षम"</string>
-    <string name="preferred_network_offload_footer" msgid="7454087782004987490">"आफ्नो सञ्जाल जानकारी तेस्रो दलको पहुँचबाट सञ्जाल नाम प्रसारण जोगाउने कार्य असक्षम पार्नुहोस्।"</string>
-    <string name="preferred_network_offload_popup" msgid="204626698006378960">"सञ्जाल नाम प्रसारणले लुकेका सञ्जालहरू स्वचालित जडान हुनमा रोक्ने असक्षम पार्दै।"</string>
+    <string name="preferred_network_offload_header" msgid="7101507079686660843">"नेटवर्कको नाम प्रसारण असक्षम"</string>
+    <string name="preferred_network_offload_footer" msgid="7454087782004987490">"आफ्नो सञ्जाल जानकारी तेस्रो दलको पहुँचबाट नेटवर्कको नाम प्रसारण जोगाउने कार्य असक्षम पार्नुहोस्।"</string>
+    <string name="preferred_network_offload_popup" msgid="204626698006378960">"नेटवर्कको नाम प्रसारणले लुकेका सञ्जालहरू स्वचालित जडान हुनमा रोक्ने असक्षम पार्दै।"</string>
     <string name="sim_signal_strength" msgid="6426261068520364170">"<xliff:g id="DBM">%1$d</xliff:g> dBm <xliff:g id="ASU">%2$d</xliff:g> asu"</string>
     <string name="sim_notification_title" msgid="2457890173055955672">"SIM कार्डहरू परिवर्तन गरिए।"</string>
     <string name="sim_notification_summary" msgid="6421556454979313850">"सेटअप गर्न ट्याप गर्नुहोस्"</string>
@@ -3030,17 +3035,17 @@
     <string name="network_dashboard_summary_mobile" msgid="5560545061217580626">"मोबाइल"</string>
     <string name="network_dashboard_summary_data_usage" msgid="4695629715072542102">"डेटाको प्रयोग"</string>
     <string name="network_dashboard_summary_hotspot" msgid="3928610802321995214">"हटस्पट"</string>
-    <string name="connected_devices_dashboard_title" msgid="7795222675849060444">"जडान गरिएका यन्त्रहरू"</string>
+    <string name="connected_devices_dashboard_title" msgid="7795222675849060444">"जोडिएका यन्त्रहरू"</string>
     <string name="connected_devices_dashboard_summary" msgid="1072664369515033179">"ब्लुटुथ, ड्राइभिङ मोड, NFC"</string>
     <string name="connected_devices_dashboard_no_nfc_summary" msgid="2610085597733526722">"ब्लुटुथ, ड्राइभिङ मोड"</string>
     <string name="connected_devices_dashboard_no_driving_mode_summary" msgid="3524409078596318803">"ब्लुटुथ, NFC"</string>
     <string name="connected_devices_dashboard_no_driving_mode_no_nfc_summary" msgid="7881286613528299400">"ब्लुटुथ"</string>
-    <string name="app_and_notification_dashboard_title" msgid="8448096608058843730">"अनुप्रयोग तथा सूचनाहरू"</string>
-    <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"सहायक, हालैका अनुप्रयोगहरू, पूर्वनिर्धारित अनुप्रयोगहरू"</string>
+    <string name="app_and_notification_dashboard_title" msgid="8448096608058843730">"एप तथा सूचनाहरू"</string>
+    <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"सहायक, हालैका एपहरू, पूर्वनिर्धारित एपहरू"</string>
     <string name="notification_settings_work_profile" msgid="7190550347842400029">"कार्य प्रोफाइलका अनुप्रयोगहरूको सूचनामाथि पहुँच छैन।"</string>
     <string name="account_dashboard_title" msgid="4734300939532555885">"खाताहरू"</string>
     <string name="account_dashboard_default_summary" msgid="6822549669771936206">"कुनै पनि खाता थप गरिएन"</string>
-    <string name="app_default_dashboard_title" msgid="6575301028225232193">"पूर्वनिर्धारित अनुप्रयोगहरू"</string>
+    <string name="app_default_dashboard_title" msgid="6575301028225232193">"पूर्वनिर्धारित एपहरू"</string>
     <string name="system_dashboard_summary" msgid="6582464466735779394">"भाषाहरू, इसाराहरू, समय, ब्याकअप"</string>
     <string name="search_results_title" msgid="4160717656435503940">"सेटिङहरू"</string>
     <string name="keywords_wifi" msgid="8477688080895466846">"wifi, wi-fi, नेटवर्क जडान, इन्टरनेट, वायरलेस, डेटा, wi fi"</string>
@@ -3050,7 +3055,7 @@
     <string name="keywords_time_format" msgid="8265826377023617424">"२४-घन्टे ढाँचा प्रयोग गर्नुहोस्"</string>
     <string name="keywords_storage_files" msgid="1995055540202216399">"डाउनलोड"</string>
     <string name="keywords_app_default" msgid="1265502485415708667">"निम्नमार्फत खोल्नुहोस्"</string>
-    <string name="keywords_applications_settings" msgid="2078776051110952597">"अनुप्रयोगहरू"</string>
+    <string name="keywords_applications_settings" msgid="2078776051110952597">"एपहरू"</string>
     <string name="keywords_time_zone" msgid="1571973084865023954">"समय क्षेत्र"</string>
     <string name="keywords_draw_overlay" msgid="3855954419750744775">"कुराकानीको हेड"</string>
     <string name="keywords_flashlight" msgid="7733996050628473024">"फ्ल्यासलाइट, बत्ती, टर्च"</string>
@@ -3059,7 +3064,7 @@
     <string name="keywords_wifi_calling" msgid="3554052148729818521">"wifi, wi-fi, कल गर्नुहोस्, कल गर्दै"</string>
     <string name="keywords_display" msgid="355147521915213375">"स्क्रिन, टचस्क्रिन"</string>
     <string name="keywords_display_brightness_level" msgid="7649410848561920512">"मधुरो स्क्रिन, टचस्क्रिन, ब्याट्री, चहकिलो"</string>
-    <string name="keywords_display_night_display" msgid="3647370193110044967">"मधुरो स्क्रिन, रात, टिन्ट, रात्रि ड्युटी, उज्यालोपन, स्क्रिनको रङ, रङ"</string>
+    <string name="keywords_display_night_display" msgid="3647370193110044967">"मधुरो स्क्रिन, रात, टिन्ट, रात्रि ड्युटी, उज्यालोपन, स्क्रिनको रङ्ग, रङ्ग"</string>
     <string name="keywords_display_wallpaper" msgid="1202089324795933197">"पृष्ठभूमि, निजीकृत गर्नुहोस्, प्रदर्शन आफू अनुकूल गर्नुहोस्"</string>
     <string name="keywords_display_font_size" msgid="1496431330244040196">"पाठको आकार"</string>
     <string name="keywords_display_cast_screen" msgid="5744566533025100355">"परियोजना, कास्ट, स्क्रिनको प्रतिविम्ब बनाउने, स्क्रिन आदान प्रदान गर्ने, प्रतिविम्ब बनाउने, स्क्रिन आदान प्रदान, स्क्रिन कास्टिङ"</string>
@@ -3080,12 +3085,12 @@
     <string name="keywords_users" msgid="5880705776023155640">"प्रतिबन्ध, प्रतिबन्ध लगाउनुहोस्, प्रतिबन्धित"</string>
     <string name="keywords_keyboard_and_ime" msgid="3327265741354129990">"पाठ सच्याइ, सही, ध्वनि, कम्पन, स्वतः, भाषा, इसारा, सुझाव दिनु, सुझाव, विषयवस्तु, अपमानजनक, शब्द, प्रकार, इमोजी, अन्तर्राष्ट्रिय"</string>
     <string name="keywords_reset_apps" msgid="2645701455052020435">"रिसेट गर्नुहोस्, प्राथमिकताहरू, पूर्वनिर्धारित"</string>
-    <string name="keywords_all_apps" msgid="846444448435698930">"अनुप्रयोगहरू, डाउनलोड, अनुप्रयोगहरू, प्रणाली"</string>
-    <string name="keywords_app_permissions" msgid="8539841019997048500">"अनुप्रयोगहरू, अनुमतिहरू, सुरक्षा"</string>
-    <string name="keywords_default_apps" msgid="7435952699323965532">"अनुप्रयोगहरू, पूर्वनिर्धारित"</string>
-    <string name="keywords_ignore_optimizations" msgid="9127632532176249438">"अनुकूलनहरूलाई बेवास्ता गर्नुहोस्, डोज, अनुप्रयोग स्ट्यान्डबाइ"</string>
-    <string name="keywords_color_mode" msgid="8893345199519181751">"चम्किलो RGB, sRGB, रङ, प्राकृतिक, मानक"</string>
-    <string name="keywords_color_temperature" msgid="2255253972992035046">"रङ, तापक्रम, D65, D73, सेतो, पहेँलो, नीलो, न्यानो, शीतल"</string>
+    <string name="keywords_all_apps" msgid="846444448435698930">"एपहरू, डाउनलोड, एपहरू, प्रणाली"</string>
+    <string name="keywords_app_permissions" msgid="8539841019997048500">"एपहरू, अनुमतिहरू, सुरक्षा"</string>
+    <string name="keywords_default_apps" msgid="7435952699323965532">"एपहरू, पूर्वनिर्धारित"</string>
+    <string name="keywords_ignore_optimizations" msgid="9127632532176249438">"अनुकूलनहरूलाई बेवास्ता गर्नुहोस्, डोज, एप स्ट्यान्डबाइ"</string>
+    <string name="keywords_color_mode" msgid="8893345199519181751">"चम्किलो RGB, sRGB, रङ्ग, प्राकृतिक, मानक"</string>
+    <string name="keywords_color_temperature" msgid="2255253972992035046">"रङ्ग, तापक्रम, D65, D73, सेतो, पहेँलो, निलो, न्यानो, शीतल"</string>
     <string name="keywords_lockscreen" msgid="4936846554280830394">"अनलक गर्न स्लाइड गर्नुहोस्, पासवर्ड, ढाँचा, PIN"</string>
     <string name="keywords_profile_challenge" msgid="8653718001253979611">"कार्य चुनौती, कार्य, प्रोफाइल"</string>
     <string name="keywords_unification" msgid="2020759909366983593">"कार्यको प्रोफाइल, व्यवस्थापन गरिएको प्रोफाइल, एकरूपता ल्याउनु, एकरूपता, कार्य, प्रोफाइल"</string>
@@ -3099,8 +3104,8 @@
     <string name="keywords_model_and_hardware" msgid="2743197096210895251">"क्रम संख्या, हार्डवेयरको संस्करण"</string>
     <string name="keywords_android_version" msgid="4842749998088987740">"android को सुरक्षासम्बन्धी प्याचको स्तर, बेसब्यान्ड संस्करण, कर्नेल संस्करण"</string>
     <string name="keywords_dark_ui_mode" msgid="1027966176887770318">"विषयवस्तु, उज्यालो, अँध्यारो, मोड"</string>
-    <string name="keywords_financial_apps_sms_access" msgid="3236014691838121857">"वित्तीय अनुप्रयोग, sms, अनुमति"</string>
-    <string name="keywords_systemui_theme" msgid="9150908170417305866">"अँध्यारो विषयवस्तु"</string>
+    <string name="keywords_financial_apps_sms_access" msgid="3236014691838121857">"वित्तीय एप, sms, अनुमति"</string>
+    <string name="keywords_systemui_theme" msgid="9150908170417305866">"अँध्यारो थिम"</string>
     <string name="keywords_device_feedback" msgid="6948977907405738490">"बग"</string>
     <string name="keywords_ambient_display_screen" msgid="5873935693887583428">"परिवेशको प्रदर्शन, लक स्क्रिनको प्रदर्शन"</string>
     <string name="keywords_lock_screen_notif" msgid="4914337222856805463">"लक स्क्रिनसम्बन्धी सूचना, सूचनाहरू"</string>
@@ -3129,11 +3134,11 @@
     <string name="sound_settings_summary_vibrate" msgid="2194491116884798590">"घन्टी बजाउनेलाई कम्पनमा सेट गरिएको छ"</string>
     <string name="sound_settings_summary_silent" msgid="899823817462768876">"घन्टी बजाउनेलाई मौनमा सेट गरिएको छ"</string>
     <string name="sound_settings_example_summary" msgid="2091822107298841827">"८०% मा सेट गरिँदा घन्टीको भोल्युम"</string>
-    <string name="media_volume_option_title" msgid="3553411883305505682">"मिडियाको आवाजको मात्रा"</string>
+    <string name="media_volume_option_title" msgid="3553411883305505682">"मिडियाको भोल्युम"</string>
     <string name="remote_media_volume_option_title" msgid="6355710054191873836">"भोल्युम cast गर्नुहोस्"</string>
     <string name="call_volume_option_title" msgid="5028003296631037334">"कलको भोल्युम"</string>
-    <string name="alarm_volume_option_title" msgid="3184076022438477047">"अलार्मको आवाजको मात्रा"</string>
-    <string name="ring_volume_option_title" msgid="2038924918468372264">"घन्टीको आवाजको मात्रा"</string>
+    <string name="alarm_volume_option_title" msgid="3184076022438477047">"अलार्मको भोल्युम"</string>
+    <string name="ring_volume_option_title" msgid="2038924918468372264">"घन्टीको भोल्युम"</string>
     <string name="notification_volume_option_title" msgid="1358512611511348260">"ध्वनी सूचना"</string>
     <string name="ringtone_title" msgid="1409086028485922583">"फोनको रिङटोन"</string>
     <string name="notification_ringtone_title" msgid="2932960620843976285">"सूचना सम्बन्धी पूर्वनिर्धारित ध्वनि"</string>
@@ -3157,7 +3162,7 @@
     <string name="emergency_tone_vibrate" msgid="5020068066905681181">"कम्पनहरू"</string>
     <string name="boot_sounds_title" msgid="7583926202411353620">"यन्त्र सक्रिय हुँदाका ध्वनिहरू"</string>
     <string name="live_caption_title" msgid="7926591158657997051">"लाइभ क्याप्सन"</string>
-    <string name="live_caption_summary" msgid="9064771862352393125">"स्वचालित क्याप्सनहरूसम्बन्धी मिडिया"</string>
+    <string name="live_caption_summary" msgid="9064771862352393125">"मिडियाको स्वत: क्याप्सन बनाउनुहोस्"</string>
     <string name="zen_mode_settings_summary_off" msgid="6929319200478424962">"कहिल्यै होइन"</string>
     <plurals name="zen_mode_settings_summary_on" formatted="false" msgid="6061723291126091396">
       <item quantity="other"><xliff:g id="ON_COUNT">%d</xliff:g> समयतालिकाहरू सक्षम पारिए</item>
@@ -3191,28 +3196,28 @@
     <string name="zen_mode_visual_signals_settings_subtitle" msgid="6608239691864638854">"सङ्केतहरूलाई देखिन दिनुहोस्"</string>
     <string name="zen_mode_settings_category" msgid="5601680733422424922">"जब बाधा नपुर्‍याउनुहोस् सक्रिय छ"</string>
     <string name="zen_mode_restrict_notifications_title" msgid="7486753018073540477">"सूचनाहरूलाई प्रतिबन्ध लगाउनुहोस्"</string>
-    <string name="zen_mode_restrict_notifications_mute" msgid="2673665450311184875">"सूचनाहरूको कुनै पनि ध्वनि छैन"</string>
+    <string name="zen_mode_restrict_notifications_mute" msgid="2673665450311184875">"सूचना आउँदा साउन्ड नआओस्"</string>
     <string name="zen_mode_restrict_notifications_mute_summary" msgid="1696217042353376674">"तपाईं आफ्नो स्क्रिनमा सूचनाहरू देख्नु हुने छ"</string>
     <string name="zen_mode_restrict_notifications_mute_footer" msgid="3049522809520549054">"सूचनाहरू आउँदा तपाईंको फोनले आवाज निकाल्ने वा कम्पन गर्ने छैन।"</string>
-    <string name="zen_mode_restrict_notifications_hide" msgid="3296933643539682552">"सूचनाहरूको कुनै पनि भिजुअल वा ध्वनि छैन"</string>
+    <string name="zen_mode_restrict_notifications_hide" msgid="3296933643539682552">" सूचना आउँदा भिजुअल वा साउन्ड नआओस्"</string>
     <string name="zen_mode_restrict_notifications_hide_summary" msgid="1449301153755270168">"तपाईं सूचनाहरू देख्न वा सुन्न सक्नु हुने छैन।"</string>
     <string name="zen_mode_restrict_notifications_hide_footer" msgid="7617688597593946765">"तपाईंको फोनले नयाँ वा विद्यमान सूचनाहरूका हकमा उक्त सूचना देखाउने, कम्पन गर्ने वा घन्टी बजाउने कार्य गर्ने छैन। फोनको क्रियाकलाप वा स्थितिसम्बन्धी महत्त्वपूर्ण सूचनाहरू देखिने क्रम भने जारी नै रहने छ भन्ने कुरा ख्याल गर्नुहोस्।\n\nतपाईंले बाधा नपुऱ्याउनुहोस् नामक सुविधा निष्क्रिय पार्नुभएका बेला आफ्नो स्क्रिनको सिरानबाट फेदतर्फ स्क्रोल गरी छुटेका सूचनाहरू फेला पार्न सक्नुहुन्छ।"</string>
     <string name="zen_mode_restrict_notifications_custom" msgid="3167252482570424133">"आफू अनुकूल"</string>
     <string name="zen_mode_restrict_notifications_enable_custom" msgid="6376983315529894440">"आफू अनुकूल सेटिङ सक्षम पार्नुहोस्‌"</string>
     <string name="zen_mode_restrict_notifications_disable_custom" msgid="8004212081465043044">"आफू अनुकूल सेटिङ हटाउनुहोस्‌"</string>
-    <string name="zen_mode_restrict_notifications_summary_muted" msgid="1075196788469381282">"सूचनाहरूको कुनै पनि ध्वनि छैन"</string>
+    <string name="zen_mode_restrict_notifications_summary_muted" msgid="1075196788469381282">"सूचना आउँदा साउन्ड नआओस्"</string>
     <string name="zen_mode_restrict_notifications_summary_custom" msgid="4982187708274505748">"आंशिक रूपमा लुकेको"</string>
-    <string name="zen_mode_restrict_notifications_summary_hidden" msgid="7637206880685474111">"सूचनाहरूको कुनै पनि भिजुअल वा ध्वनि छैन"</string>
+    <string name="zen_mode_restrict_notifications_summary_hidden" msgid="7637206880685474111">" सूचना आउँदा भिजुअल वा साउन्ड नआओस्"</string>
     <string name="zen_mode_what_to_block_title" msgid="2142809942549840800">"आफू अनुकूल बन्देजहरू"</string>
     <string name="zen_mode_block_effects_screen_on" msgid="1042489123800404560">"स्क्रिन सक्रिय रहेको अवस्थामा"</string>
     <string name="zen_mode_block_effects_screen_off" msgid="6380935819882837552">"स्क्रिन निष्क्रिय रहेको अवस्थामा"</string>
     <string name="zen_mode_block_effect_sound" msgid="1499243540186357631">"ध्वनि र कम्पनलाई म्यूट गर्नुहोस्"</string>
     <string name="zen_mode_block_effect_intent" msgid="5666951244667422668">"स्क्रिन सक्रिय नगर्नुहोस्‌"</string>
     <string name="zen_mode_block_effect_light" msgid="8679333758037487644">"बत्तीलाई धिपधिपाउन नदिनुहोस्"</string>
-    <string name="zen_mode_block_effect_peek" msgid="6075662813575910221">"स्क्रिनमा सूचनाहरू पप गर्न नदिनुहोस्"</string>
+    <string name="zen_mode_block_effect_peek" msgid="6075662813575910221">"स्क्रिनमा सूचनाहरू  स्क्रिनमा सूचनाहरू देखिन नदिनुहोस्"</string>
     <string name="zen_mode_block_effect_status" msgid="6516614225115681068">"स्क्रीनको शीर्षमा वस्तुस्थिति पट्टीका आइकनहरू लुकाउनुहोस्"</string>
-    <string name="zen_mode_block_effect_badge" msgid="3891743027347075136">"अनुप्रयोग आइकनमा सूचनाको प्रतीक जनाउने थोप्लो लुकाउनुहोस्‌"</string>
-    <string name="zen_mode_block_effect_ambient" msgid="6382013125863616197">"सूचनाहरूका लागि सक्रिय नगर्नुहोस्‌"</string>
+    <string name="zen_mode_block_effect_badge" msgid="3891743027347075136">"एप आइकनमा सूचनाको प्रतीक जनाउने थोप्लो लुकाउनुहोस्‌"</string>
+    <string name="zen_mode_block_effect_ambient" msgid="6382013125863616197">"सूचना आउँदा सक्रिय नहोस्‌"</string>
     <string name="zen_mode_block_effect_list" msgid="6081548478844912181">"सूचनाको सूचीबाट लुकाउनुहोस्"</string>
     <string name="zen_mode_block_effect_summary_none" msgid="7166175186759564510">"कहिल्यै होइन"</string>
     <string name="zen_mode_block_effect_summary_screen_off" msgid="2985086455557755722">"स्क्रिन निष्क्रिय रहेको अवस्थामा"</string>
@@ -3220,17 +3225,17 @@
     <string name="zen_mode_block_effect_summary_sound" msgid="4907185880913861880">"ध्वनि र कम्पन"</string>
     <string name="zen_mode_block_effect_summary_some" msgid="6035118904496072665">"सुचनाहरूका ध्वनि, कम्पन र केही भिजुअल संकेतहरू"</string>
     <string name="zen_mode_block_effect_summary_all" msgid="2830443565687247759">"सुचनाहरूका ध्वनि, कम्पन र भिजुअल संकेतहरू"</string>
-    <string name="zen_mode_blocked_effects_footer" msgid="4375156159613413924">"सामान्य फोन गतिविधिको सूचना आवश्यक हुन्छ र स्थिति कहिल्यै लुक्ने छैन"</string>
+    <string name="zen_mode_blocked_effects_footer" msgid="4375156159613413924">"फोन सामान्य रूपले चल्न आवश्यक क्रियाकलाप र स्टाटस कहिलै पनि लुकाइँदैन"</string>
     <string name="zen_mode_no_exceptions" msgid="3099578343994492857">"कुनै पनि होइन"</string>
     <string name="zen_mode_other_options" msgid="7216192179063769057">"अन्य विकल्पहरू"</string>
     <string name="zen_mode_add" msgid="2533484377786927366">"थप्नुहोस्"</string>
     <string name="zen_mode_enable_dialog_turn_on" msgid="6396050543542026184">"सक्रिय गर्नुहोस्"</string>
     <string name="zen_mode_button_turn_on" msgid="1097964136225943415">"अहिले नै सक्रिय गर्नुहोस्"</string>
-    <string name="zen_mode_button_turn_off" msgid="3990967728457149454">"अहिले नै निष्क्रिय पार्नुहोस्"</string>
+    <string name="zen_mode_button_turn_off" msgid="3990967728457149454">"अहिले नै अफ गर्नुहोस्"</string>
     <string name="zen_mode_settings_dnd_manual_end_time" msgid="4307574188962071429">"<xliff:g id="FORMATTED_TIME">%s</xliff:g> सम्म बाधा नपुर्‍याउनुहोस् नामक मोड सक्रिय हुन्छ"</string>
     <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"तपाईंले निष्क्रिय नपारेसम्म बाधा नपुर्‍याउनुहोस् नामक मोड सक्रिय रहनेछ"</string>
     <string name="zen_mode_settings_dnd_automatic_rule" msgid="2843297614114625408">"(<xliff:g id="RULE_NAME">%s</xliff:g>) नामक समयतालिकाले बाधा नपुर्‍याउनुहोस् नामक मोडलाई स्वतः सक्रिय गरेको थियो"</string>
-    <string name="zen_mode_settings_dnd_automatic_rule_app" msgid="5103454923160912313">"कुनै अनुप्रयोग <xliff:g id="APP_NAME">%s</xliff:g> ले बाधा नपुर्‍याउनुहोस् नामक मोडलाई स्वतः सक्रिय गर्‍यो"</string>
+    <string name="zen_mode_settings_dnd_automatic_rule_app" msgid="5103454923160912313">"कुनै एप <xliff:g id="APP_NAME">%s</xliff:g> ले बाधा नपुर्‍याउनुहोस् नामक मोडलाई स्वतः सक्रिय गर्‍यो"</string>
     <string name="zen_mode_settings_dnd_custom_settings_footer" msgid="6335108298640066560">"बाधा नपुऱ्याउनुहोस् नामक मोड आफू अनुकूल सेटिङहरू भएका <xliff:g id="RULE_NAMES">%s</xliff:g> का लागि सक्रिय छ।"</string>
     <string name="zen_mode_settings_dnd_custom_settings_footer_link" msgid="4007974052885089379"><annotation id="link">" आफू अनुकूल सेटिङहरू हेर्नुहोस्"</annotation></string>
     <string name="zen_interruption_level_priority" msgid="9178419297408319234">"प्राथमिकता मात्र"</string>
@@ -3270,8 +3275,8 @@
     <string name="zen_msg_event_reminder_footer" msgid="164400918479831580">"बाधा नपुर्‍याउनुहोस् मोड सक्रिय भएका बेला तपाईंले माथि अनुमति दिनुभएका वस्तुहरूबाहेक सन्देश, रिमाइन्डर तथा कार्यक्रमहरूलाई म्युट गरिने छ। तपाईं आफ्ना साथीभाइ, परिवारजन वा अन्य सम्पर्कहरूलाई आफूसँग सम्पर्क राख्न दिने गरी सन्देशसम्बन्धी सेटिङहरू समायोजन गर्न सक्नुहुन्छ।"</string>
     <string name="zen_onboarding_ok" msgid="6403635918125323678">"सम्पन्न भयो"</string>
     <string name="zen_onboarding_settings" msgid="1416466597876383322">"सेटिङहरू"</string>
-    <string name="zen_onboarding_new_setting_title" msgid="3622673375041304362">"सूचनाहरूको कुनै पनि भिजुअल वा ध्वनि छैन"</string>
-    <string name="zen_onboarding_current_setting_title" msgid="2560330551761407563">"सूचनाहरूको कुनै पनि ध्वनि छैन"</string>
+    <string name="zen_onboarding_new_setting_title" msgid="3622673375041304362">" सूचना आउँदा भिजुअल वा साउन्ड नआओस्"</string>
+    <string name="zen_onboarding_current_setting_title" msgid="2560330551761407563">"सूचना आउँदा साउन्ड नआओस्"</string>
     <string name="zen_onboarding_new_setting_summary" msgid="8264430315983860075">"तपाईं सूचनाहरू देख्न वा सुन्न सक्नु हुने छैन। ताराङ्कित सम्पर्क ठेगाना तथा बारम्बार कल गर्ने व्यक्तिका कलहरू।"</string>
     <string name="zen_onboarding_current_setting_summary" msgid="3569246708507270821">"(हालको सेटिङ)"</string>
     <string name="zen_onboarding_dnd_visual_disturbances_header" msgid="7584229011611927613">"बाधा नपुर्याउनुहोस् नामक मोडका सूचनासम्बन्धी सेटिङहरू बदल्ने हो?"</string>
@@ -3290,7 +3295,7 @@
     <string name="ringtones_category_preference_title" msgid="4491932700769815470">"रिङटोनहरू"</string>
     <string name="other_sound_category_preference_title" msgid="2045757472469840859">"ध्वनि र कम्पन सम्बन्धी अन्य कुराहरू"</string>
     <string name="configure_notification_settings" msgid="291914315140851270">"सूचनाहरू"</string>
-    <string name="recent_notifications" msgid="8125865995065032049">"हालै पठाइएका अनुप्रयोगहरू"</string>
+    <string name="recent_notifications" msgid="8125865995065032049">"हालै पठाइएका एपहरू"</string>
     <string name="recent_notifications_see_all_title" msgid="4089007770442871469">"विगत ७ दिनयताका सबै हेर्नुहोस्"</string>
     <string name="advanced_section_header" msgid="984680389373090015">"उन्‍नत"</string>
     <string name="profile_section_header" msgid="5471479005472037417">"कार्यका सूचनाहरू"</string>
@@ -3299,7 +3304,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>
@@ -3307,7 +3312,7 @@
     <string name="bubbles_app_toggle_title" msgid="6401217027603326439">"बबलहरू"</string>
     <string name="bubbles_app_toggle_summary" msgid="7707611139796553855">"<xliff:g id="APP_NAME">%1$s</xliff:g> लाई केही सूचनाहरू बबलका रूपमा देखाउन दिनुहोस्"</string>
     <string name="bubbles_feature_disabled_dialog_title" msgid="3375452386012079293">"बबलहरू सक्रिय पार्नुहोस्"</string>
-    <string name="bubbles_feature_disabled_dialog_text" msgid="326945485806386477">"यस अनुप्रयोगमा बबल सक्रिय गर्न सर्वप्रथम तपाईंले आफ्नो यन्त्रमा तिनीहरूलाई सक्रिय गर्नु पर्ने हुन्छ यस कार्यले तपाईंले यसअघि बबलहरू सक्रिय गर्नुभएका अन्य अनुप्रयोगहरूमा प्रभाव पार्छ।"</string>
+    <string name="bubbles_feature_disabled_dialog_text" msgid="326945485806386477">"यस अनुप्रयोगमा बबल सक्रिय गर्न सर्वप्रथम तपाईंले आफ्नो यन्त्रमा तिनीहरूलाई सक्रिय गर्नु पर्ने हुन्छ यस कार्यले तपाईंले यसअघि बबलहरू सक्रिय गर्नुभएका अन्य एपहरूमा प्रभाव पार्छ।"</string>
     <string name="bubbles_feature_disabled_button_approve" msgid="6661464849674493351">"यन्त्रमा सक्रिय गर्नुहोस्"</string>
     <string name="bubbles_feature_disabled_button_cancel" msgid="4807286844588486198">"रद्द गर्नुहोस्"</string>
     <string name="swipe_direction_title" msgid="7535031630668873009">"कारबाहीहरू स्वाइप गर्नुहोस्"</string>
@@ -3316,7 +3321,7 @@
     <string name="notification_pulse_title" msgid="4861418327614907116">"झिम झिम गर्ने बत्ती"</string>
     <string name="lock_screen_notifications_title" msgid="6889072265118747835">"लक स्क्रिनमा"</string>
     <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"कार्य प्रोफाइल लक हुँदा"</string>
-    <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"सबै सूचना सामग्री देखाउनुहोस्"</string>
+    <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"सबै सूचना देखाउनुहोस्"</string>
     <string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"संवेदनशील सामग्री लुकाउनुहोस्"</string>
     <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"कुनै सूचनाहरू नदेखाउनुहोस्"</string>
     <string name="lock_screen_notifications_interstitial_message" msgid="4230189215124387818">"तपाईंको उपकरण बन्द हुँदा, तपाईं कसरी सूचनाहरू देखाउन चाहनुहुन्छ?"</string>
@@ -3345,7 +3350,7 @@
     <string name="notification_silence_title" msgid="6959637402003838093">"मौन रूपमा देखाउनुहोस्"</string>
     <string name="notification_alert_title" msgid="750683027055192648">"अलर्ट"</string>
     <string name="allow_interruption" msgid="3548841026410702850">"अवरोधहरूहरूलाई अनुमति दिनुहोस्"</string>
-    <string name="allow_interruption_summary" msgid="5207637026831135377">"अनुप्रयोगलाई बज्न, कम्पन गर्न र/वा स्क्रिनमा सूचनाहरू पप गर्न दिनुहोस्"</string>
+    <string name="allow_interruption_summary" msgid="5207637026831135377">"एपलाई बज्न, कम्पन गर्न र/वा स्क्रिनमा सूचनाहरू पप गर्न दिनुहोस्"</string>
     <string name="notification_channel_summary_min" msgid="8646305539478179811">"न्यून महत्त्वको सूचना"</string>
     <string name="notification_channel_summary_low" msgid="7753266237705850510">"सामान्य महत्वको सूचना"</string>
     <string name="notification_channel_summary_default" msgid="7529537115678964164">"उच्च महत्त्वको सूचना"</string>
@@ -3357,38 +3362,38 @@
     <string name="notifications_sent_never" msgid="237997329598144638">"कहिल्यै होइन"</string>
     <string name="manage_notification_access_title" msgid="5348743662189787547">"सूचनासम्बन्धी पहुँच"</string>
     <string name="work_profile_notification_access_blocked_summary" msgid="8148871282484870576">"कार्य प्रोफाइलमाथिका पहुँच सम्बन्धी सूचनाहरूलाई बन्द गरिएको छ"</string>
-    <string name="manage_notification_access_summary_zero" msgid="236809421271593016">"अनुप्रयोगहरूले सूचनाहरू पढ्न सक्दैन"</string>
+    <string name="manage_notification_access_summary_zero" msgid="236809421271593016">"एपहरूले सूचनाहरू पढ्न सक्दैन"</string>
     <plurals name="manage_notification_access_summary_nonzero" formatted="false" msgid="8496218948429646792">
-      <item quantity="other">%d अनुप्रयोगहरूले सूचनाहरू पढ्न सक्छन्</item>
+      <item quantity="other">%d एपहरूले सूचनाहरू पढ्न सक्छन्</item>
       <item quantity="one">%d अनुप्रयोगले सूचनाहरू पढ्न सक्छ</item>
     </plurals>
     <string name="notification_assistant_title" msgid="8216604031352764011">"सूचनासम्बन्धी सहायक सेवा"</string>
     <string name="no_notification_assistant" msgid="9140123568386413264">"सहायकसम्बन्धी कुनै सेवा छैन"</string>
-    <string name="no_notification_listeners" msgid="1366386609506834717">"कुनै स्थापित अनुप्रयोगहरूले सूचना पहुँच अनुरोध गरेका छैनन्।"</string>
+    <string name="no_notification_listeners" msgid="1366386609506834717">"कुनै स्थापित एपहरूले सूचना पहुँच अनुरोध गरेका छैनन्।"</string>
     <string name="notification_assistant_security_warning_title" msgid="4190584438086738496">"<xliff:g id="SERVICE">%1$s</xliff:g> लाई सूचनामाथि पहुँच राख्ने अनुमति दिने हो?"</string>
-    <string name="notification_assistant_security_warning_summary" msgid="6924513399671031930">"<xliff:g id="NOTIFICATION_ASSISTANT_NAME">%1$s</xliff:g> ले सम्पर्कको नाम र तपाईंले प्राप्त गर्नुभएका पाठ सन्देशहरू जस्ता व्यक्तिगत जानकारीलगायत सबै सूचनाहरू पढ्न सक्ने छ। यसले सूचनाहरू परिमार्जन गर्न वा खारेज गर्न वा तिनमा रहेका कारबाहीमूलक बटनहरू ट्रिगर गर्न पनि सक्ने छ। \n\nयसले उक्त अनुप्रयोगलाई बाधा नपुऱ्याउनुहोस् नामक मोड सक्रिय गर्ने वा निष्क्रिय पार्ने र सम्बन्धित सेटिङहरू परिवर्तन गर्ने क्षमता पनि प्रदान गर्ने छ।"</string>
+    <string name="notification_assistant_security_warning_summary" msgid="6924513399671031930">"<xliff:g id="NOTIFICATION_ASSISTANT_NAME">%1$s</xliff:g> ले सम्पर्कको नाम र तपाईंले प्राप्त गर्नुभएका पाठ सन्देशहरू जस्ता व्यक्तिगत जानकारीलगायत सबै सूचनाहरू पढ्न सक्ने छ। यसले सूचनाहरू परिमार्जन गर्न वा खारेज गर्न वा तिनमा रहेका कारबाहीमूलक बटनहरू ट्रिगर गर्न पनि सक्ने छ। \n\nयसले उक्त एपलाई बाधा नपुऱ्याउनुहोस् नामक मोड सक्रिय गर्ने वा निष्क्रिय पार्ने र सम्बन्धित सेटिङहरू परिवर्तन गर्ने क्षमता पनि प्रदान गर्ने छ।"</string>
     <string name="notification_listener_security_warning_title" msgid="4902253246428777797">"<xliff:g id="SERVICE">%1$s</xliff:g> का लागि सूचना पहुँच अनुमति दिने हो?"</string>
-    <string name="notification_listener_security_warning_summary" msgid="4454702907350100288">"<xliff:g id="NOTIFICATION_LISTENER_NAME">%1$s</xliff:g> तपाईँले पाउनुहुने सन्देशहरूका सम्पर्कका नाम र पाठ जस्ता व्यक्तिगत जानकारी लगायत सबै सूचनाहरूलाई पढ्न सक्षम हुनेछ। यसले सूचनाहरूलाई खारेज गर्न वा तिनीहरूमा रहेका कारबाही सम्बन्धी बटनहरूलाई ट्रिगर गर्न पनि सक्नेछ। \n\nयसले अनुप्रयोगलाई बाधा नपुर्याउनुहोस् मोडलाई सक्रिय वा निष्क्रिय पार्ने र सम्बन्धित सेटिङहरूलाई परिवर्तन गर्ने क्षमता पनि दिनेछ।"</string>
+    <string name="notification_listener_security_warning_summary" msgid="4454702907350100288">"<xliff:g id="NOTIFICATION_LISTENER_NAME">%1$s</xliff:g> तपाईँले पाउनुहुने सन्देशहरूका सम्पर्कका नाम र पाठ जस्ता व्यक्तिगत जानकारी लगायत सबै सूचनाहरूलाई पढ्न सक्षम हुनेछ। यसले सूचनाहरूलाई खारेज गर्न वा तिनीहरूमा रहेका कारबाही सम्बन्धी बटनहरूलाई ट्रिगर गर्न पनि सक्नेछ। \n\nयसले एपलाई बाधा नपुर्याउनुहोस् मोडलाई सक्रिय वा निष्क्रिय पार्ने र सम्बन्धित सेटिङहरूलाई परिवर्तन गर्ने क्षमता पनि दिनेछ।"</string>
     <string name="notification_listener_disable_warning_summary" msgid="162165151519082978">"यदि तपाईं <xliff:g id="NOTIFICATION_LISTENER_NAME">%1$s</xliff:g> का लागि सूचना सम्बन्धी पहुँचलाई निष्क्रिय पार्नुहुन्छ भने बाधा नपुर्याउनुहोस् सम्बन्धी पहुँच पनि निष्क्रिय हुन सक्छ।"</string>
     <string name="notification_listener_disable_warning_confirm" msgid="7863495391671154188">"निष्क्रिय पार्नुहोस्"</string>
     <string name="notification_listener_disable_warning_cancel" msgid="6264631825225298458">"रद्द गर्नुहोस्"</string>
     <string name="vr_listeners_title" msgid="511483902408792832">"VR का सहायक सेवाहरू"</string>
-    <string name="no_vr_listeners" msgid="7675484190394450979">"कुनै पनि स्थापित अनुप्रयोगहरूले VR का सहायक सेवाहरूको रूपमा चल्नका लागि अनुरोध गरेका छैनन्।"</string>
+    <string name="no_vr_listeners" msgid="7675484190394450979">"कुनै पनि स्थापित एपहरूले VR का सहायक सेवाहरूको रूपमा चल्नका लागि अनुरोध गरेका छैनन्।"</string>
     <string name="vr_listener_security_warning_title" msgid="7019322246707645361">"<xliff:g id="SERVICE">%1$s</xliff:g> लाई VR को सेवामा पहुँचका लागि अनुमति दिने हो?"</string>
     <string name="vr_listener_security_warning_summary" msgid="5093225583584522067">"तपाईँले अनुप्रयोगहरूलाई भर्चुअल रियालिटी मोडमा प्रयोग गरिरहेको बेला <xliff:g id="VR_LISTENER_NAME">%1$s</xliff:g> चल्नका लागि सक्षम हुनेछ।"</string>
     <string name="display_vr_pref_title" msgid="1088464812293416981">"यन्त्र VR मा हुँदा"</string>
     <string name="display_vr_pref_low_persistence" msgid="3132583929174794245">"अस्पष्टता कम पार्नुहोस् (सिफारिस गरिएको)"</string>
     <string name="display_vr_pref_off" msgid="4681320968818852691">"स्क्रिन झिलमिलाउने प्रभाव कम गर्नुहोस्"</string>
     <string name="picture_in_picture_title" msgid="4960733106166035448">"Picture-in-picture"</string>
-    <string name="picture_in_picture_empty_text" msgid="8664071475324685241">"स्थापना गरिएका कुनै पनि अनुप्रयोगहरूले Picture-in-picture मोडलाई समर्थन गर्दैनन्"</string>
+    <string name="picture_in_picture_empty_text" msgid="8664071475324685241">"स्थापना गरिएका कुनै पनि एपहरूले Picture-in-picture मोडलाई समर्थन गर्दैनन्"</string>
     <string name="picture_in_picture_keywords" msgid="7326958702002259262">"तस्बिरमा तस्बिर मोडमा तस्बिर"</string>
     <string name="picture_in_picture_app_detail_title" msgid="3916189052657425936">"Picture-in-picture"</string>
     <string name="picture_in_picture_app_detail_switch" msgid="747422998967185418">"Picture-in-picture लाई अनुमति दिनुहोस्"</string>
-    <string name="picture_in_picture_app_detail_summary" msgid="918632751775525347">"यो अनुप्रयोग खुला रहेको अवस्थामा वा तपाईंले यसलाई छाड्नुभएपछि (उदाहरणका लागि, भिडियो हेर्ने कार्य जारी राख्न) यस अनुप्रयोगलाई picture-in-picture विन्डो सिर्जना गर्न अनुमति दिनुहोस्। यो विन्डो तपाईंले प्रयोग गरिरहनुभएका अन्य अनुप्रयोगहरूको शीर्ष भागमा देखिन्छ।"</string>
-    <string name="manage_zen_access_title" msgid="3058206309728524196">"पहुँचमा बाधा नपुर्‍यानुहोस्"</string>
+    <string name="picture_in_picture_app_detail_summary" msgid="918632751775525347">"यो एप खुला रहेको अवस्थामा वा तपाईंले यसलाई छाड्नुभएपछि (उदाहरणका लागि, भिडियो हेर्ने कार्य जारी राख्न) यस एपलाई picture-in-picture विन्डो सिर्जना गर्न अनुमति दिनुहोस्। यो विन्डो तपाईंले प्रयोग गरिरहनुभएका अन्य एपहरूको शीर्ष भागमा देखिन्छ।"</string>
+    <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="zen_access_empty_text" msgid="7667538993781607731">"कुनै पनि स्थापित एपहरू द्वारा बाधा नपुर्‍यानुहोस् पहुँच को माग गरेका छैनन्"</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>
@@ -3400,7 +3405,7 @@
     </plurals>
     <string name="no_channels" msgid="8884254729302501652">"यो अनुप्रयोगले कुनै पनि सूचना पोस्ट गरेको छैन"</string>
     <string name="app_settings_link" msgid="8465287765715790984">"अनुप्रयोगका अतिरिक्त सेटिङहरू"</string>
-    <string name="app_notification_listing_summary_zero" msgid="4047782719487686699">"सबै अनुप्रयोगहरूमा सक्रिय छ"</string>
+    <string name="app_notification_listing_summary_zero" msgid="4047782719487686699">"सबै एपहरूमा सक्रिय छ"</string>
     <plurals name="app_notification_listing_summary_others" formatted="false" msgid="1161774065480666519">
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> अनुप्रयोगहरूका लागि निष्क्रिय पारिएका छन्‌</item>
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> अनुप्रयोगका लागि निष्क्रिय परिएको छ</item>
@@ -3484,7 +3489,7 @@
     <string name="zen_mode_messages" msgid="2908722562188394107">"पाठ सन्देशलाई अनुमति दिनुहोस्‌"</string>
     <string name="zen_mode_messages_footer" msgid="5048951937714668561">"अनुमति दिइएका सन्देशहरू आउँदा घन्टी बज्छ भन्ने कुरा सुनिश्चित गर्न आफ्नो यन्त्रलाई घन्टी बज्ने, कम्पन हुने वा मौन रहनेमध्ये कुन चाहिँ विकल्पमा सेट गरिएको छ भन्ने कुरा जाँच गर्नुहोस्।"</string>
     <string name="zen_mode_custom_messages_footer" msgid="5566007423100361691">"‘<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>’ का आगमन पाठ सन्देशहरूलाई रोक लगाइएको छ। तपाईं आफ्ना साथीभाइ, परिवारजन वा अन्य सम्पर्कहरूलाई आफूसँग सम्पर्क राख्न दिने गरी सेटिङहरू समायोजन गर्न सक्नुहुन्छ।"</string>
-    <string name="zen_mode_messages_title" msgid="786261471294055181">"SMS, MMS र सन्देश प्रवाह गर्ने अनुप्रयोग"</string>
+    <string name="zen_mode_messages_title" msgid="786261471294055181">"SMS, MMS र सन्देश प्रवाह गर्ने एप"</string>
     <string name="zen_mode_from_anyone" msgid="7778836826814131083">"कसैबाट"</string>
     <string name="zen_mode_from_contacts" msgid="267034158294332688">"मात्र सम्पर्कहरूबाट"</string>
     <string name="zen_mode_from_starred" msgid="7349984569117392260">"ताराङ्कित सम्पर्कहरूबाट मात्र"</string>
@@ -3499,12 +3504,12 @@
     <string name="zen_mode_media" msgid="3701280649874724055">"मिडियाका ध्वनिहरू प्ले गर्नुहोस्"</string>
     <string name="zen_mode_media_list" msgid="509327580522287125">"मिडिया"</string>
     <string name="zen_mode_system" msgid="597437265986355038">"छुवाइसम्बन्धी ध्वनि अनुमति दिनुहोस्‌"</string>
-    <string name="zen_mode_system_list" msgid="480192458506838077">"छुवाइसम्बन्धी ध्वनि"</string>
+    <string name="zen_mode_system_list" msgid="480192458506838077">"टच गर्दा आउने आवाज"</string>
     <string name="zen_mode_reminders" msgid="7560664194610054038">"रिमाइन्डरहरूलाई अनुमति दिनुहोस्"</string>
     <string name="zen_mode_reminders_list" msgid="7347061314032326677">"रिमाइन्डरहरू"</string>
     <string name="zen_mode_events" msgid="5784076928339534984">"कार्यक्रमहरूलाई अनुमति दिनुहोस्"</string>
     <string name="zen_mode_bypassing_apps" msgid="3080739479028713449">"अनुप्रयोगहरूलाई ओभरराइड गर्ने अनुमति दिनुहोस्"</string>
-    <string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"अनुप्रयोगका अपवादहरू"</string>
+    <string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"यो सेटिङ लागू हुने एप"</string>
     <plurals name="zen_mode_bypassing_apps_subtext" formatted="false" msgid="8723144434730871572">
       <item quantity="other"><xliff:g id="NUMBER">%1$d</xliff:g> अनुप्रयोगका सूचनाहरूले बाधा नपुऱ्याउनुहोस्‌ नामक मोडलाई ओभरराइड गर्न सक्छन्</item>
       <item quantity="one">१ अनुप्रयोगका सूचनाहरूले बाधा नपुऱ्याउनुहोस्‌ नामक मोडलाई ओभरराइड गर्न सक्छन्</item>
@@ -3514,8 +3519,8 @@
     <string name="zen_mode_contacts_callers" msgid="3116829245339716399">"सम्पर्क ठेगानाहरू"</string>
     <string name="zen_mode_starred_callers" msgid="1317376207713013472">"ताराङ्कित सम्पर्कहरू"</string>
     <string name="zen_mode_repeat_callers" msgid="1435309867554692340">"कलरहरू दोरोर्‍याउनुहोस्"</string>
-    <string name="zen_mode_repeat_callers_list" msgid="2750270907597457279">"कलरहरू दोहोर्‍याउनुहोस्"</string>
-    <string name="zen_mode_repeat_callers_title" msgid="7192952181541813487">"दोहोरिएका कल गर्ने व्यक्तिहरूलाई अनुमति दिनुहोस्"</string>
+    <string name="zen_mode_repeat_callers_list" msgid="2750270907597457279">"धेरै कल गर्ने व्यक्तिहरू"</string>
+    <string name="zen_mode_repeat_callers_title" msgid="7192952181541813487">"धेरै कल गर्ने व्यक्तिहरू"</string>
     <string name="zen_mode_calls_summary_one" msgid="8327371053236689649">"<xliff:g id="CALLER_TYPE">%1$s</xliff:g> का कललाई अनुमति दिनुहोस्‌"</string>
     <string name="zen_mode_calls_summary_two" msgid="9017678770532673578">"<xliff:g id="CALLER_TYPE">%1$s</xliff:g> र <xliff:g id="CALLERT_TPYE">%2$s</xliff:g> का कललाई अनुमति दिनुहोस्‌"</string>
     <string name="zen_mode_repeat_callers_summary" msgid="1752513516040525545">"एउटै व्यक्तिले <xliff:g id="MINUTES">%d</xliff:g> मिनेटको अवधिमा दोस्रो पटक कल गरेको खण्डमा"</string>
@@ -3550,7 +3555,7 @@
     <string name="switch_on_text" msgid="7100491749799298324">"सक्रिय"</string>
     <string name="switch_off_text" msgid="3539551289454353555">"निष्क्रिय"</string>
     <string name="screen_pinning_title" msgid="578020318289781102">"पर्दा पिन गर्दै"</string>
-    <string name="screen_pinning_description" msgid="3814537379086412278">"यो सेटिङ सक्रिय गर्दा, हालको स्क्रिनलाई तपाईंले अनपिन नगरुन्जेल दृश्य अवस्थामा राख्न स्क्रिन पिनिङ प्रयोग गर्न सक्नुहुन्छ।\n\nस्क्रिन पिनिङ सुविधा प्रयोग गर्न:\n\n१. स्क्रिन पिनिङ सक्रिय रहेको सुनिश्चित गर्नुहोस् \n\n२. ओभरभ्यू खोल्नुहोस्\n\n३. स्क्रिनको सिरानमा रहेको अनुप्रयोग आइकनमा ट्याप गरी  पिनमा ट्याप गर्नुहोस्"</string>
+    <string name="screen_pinning_description" msgid="3814537379086412278">"यो सेटिङ सक्रिय गर्दा, हालको स्क्रिनलाई तपाईंले अनपिन नगरुन्जेल दृश्य अवस्थामा राख्न स्क्रिन पिनिङ प्रयोग गर्न सक्नुहुन्छ।\n\nस्क्रिन पिनिङ सुविधा प्रयोग गर्न:\n\n१. स्क्रिन पिनिङ सक्रिय रहेको सुनिश्चित गर्नुहोस् \n\n२. ओभरभ्यू खोल्नुहोस्\n\n३. स्क्रिनको सिरानमा रहेको एप आइकनमा ट्याप गरी  पिनमा ट्याप गर्नुहोस्"</string>
     <string name="screen_pinning_unlock_pattern" msgid="1060334707088339444">"पिन निकाल्नुअघि खोल्ने ढाँचा सोध्नुहोस्"</string>
     <string name="screen_pinning_unlock_pin" msgid="1441705536015645023">"पिन निकाल्नुअघि PIN सोध्नुहोस्"</string>
     <string name="screen_pinning_unlock_password" msgid="1017776884000170841">"पिन निकाल्नुअघि पासवर्ड सोध्नुहोस्"</string>
@@ -3579,7 +3584,7 @@
     <string name="encrypt_talkback_dialog_message_pin" msgid="1912533826818077891">"यो उपकरण सुरु गर्न जब तपाईँले आफ्नो PIN प्रविष्टि गर्नुहुन्छ, पहुँच सेवा जस्तै <xliff:g id="SERVICE">%1$s</xliff:g> अझै उपलब्ध हुने छैन।"</string>
     <string name="encrypt_talkback_dialog_message_pattern" msgid="4415837749933863432">"यो उपकरण सुरु गर्न जब तपाईँले आफ्नो ढाँचा प्रविष्टि गर्नुहुन्छ, पहुँच सेवा जस्तै <xliff:g id="SERVICE">%1$s</xliff:g> अझै उपलब्ध हुने छैन।"</string>
     <string name="encrypt_talkback_dialog_message_password" msgid="4276703366120881008">"यो उपकरण सुरु गर्न जब तपाईँले आफ्नो पासवर्ड प्रविष्टि गर्नुहुन्छ, पहुँच सेवा <xliff:g id="SERVICE">%1$s</xliff:g> जस्तो अझै उपलब्ध हुने छैन।"</string>
-    <string name="direct_boot_unaware_dialog_message" msgid="5253248227337914350">"टिपोट: तपाईंले आफ्नो फोन पुनः सुरु गर्नुभयो र त्यसमा स्क्रिन लक सेट गरिएको छ भने तपाईंले आफ्नो फोन अनलक नगरून्जेल यो अनुप्रयोग सुरु हुन सक्दैन"</string>
+    <string name="direct_boot_unaware_dialog_message" msgid="5253248227337914350">"टिपोट: तपाईंले आफ्नो फोन पुनः सुरु गर्नुभयो र त्यसमा स्क्रिन लक सेट गरिएको छ भने तपाईंले आफ्नो फोन अनलक नगरून्जेल यो एप सुरु हुन सक्दैन"</string>
     <string name="imei_information_title" msgid="7666097743700170757">"IMEI जानकारी"</string>
     <string name="imei_information_summary" msgid="716516316022275083">"IMEI सान्दर्भिक जानकारी"</string>
     <string name="slot_number" msgid="785422579177068698">"(घेरा<xliff:g id="SLOT_NUM">%1$d</xliff:g>)"</string>
@@ -3626,29 +3631,29 @@
     </plurals>
     <string name="runtime_permissions_summary_no_permissions_granted" msgid="3477934429220828771">"कुनै अनुमतिहरू प्रदान गरिएको छैन"</string>
     <string name="runtime_permissions_summary_no_permissions_requested" msgid="3901636077467389637">"कुनै अनुमतिहरू अनुरोध गरिएको छैन"</string>
-    <string name="filter_all_apps" msgid="4042756539846043675">"सबै अनुप्रयोगहरू"</string>
-    <string name="filter_enabled_apps" msgid="5888459261768538489">"स्थापना गरिएका अनुप्रयोगहरू"</string>
-    <string name="filter_instant_apps" msgid="8087483282854072366">"तात्कालिक अनुप्रयोगहरू"</string>
+    <string name="filter_all_apps" msgid="4042756539846043675">"सबै एपहरू"</string>
+    <string name="filter_enabled_apps" msgid="5888459261768538489">"स्थापना गरिएका एपहरू"</string>
+    <string name="filter_instant_apps" msgid="8087483282854072366">"तात्कालिक एपहरू"</string>
     <string name="filter_personal_apps" msgid="3473268022652904457">"व्यक्तिगत"</string>
     <string name="filter_work_apps" msgid="4202483998339465542">"कार्य"</string>
-    <string name="filter_notif_all_apps" msgid="1862666327228804896">"अनुप्रयोगहरू: सबै"</string>
+    <string name="filter_notif_all_apps" msgid="1862666327228804896">"एपहरू: सबै"</string>
     <string name="filter_notif_blocked_apps" msgid="5694956954776028202">"निष्क्रिय पारियो"</string>
     <string name="filter_notif_urgent_channels" msgid="5000735867167027148">"प्रकारहरू: अत्यन्तै महत्त्वका"</string>
     <string name="filter_notif_low_channels" msgid="6859599463135775287">"प्रकारहरू: कम महत्त्वका"</string>
     <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="unknown_app" msgid="2312052973570376877">"अज्ञात अनुप्रयोग"</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>
+    <string name="app_permissions_summary" msgid="8785798165776061594">"<xliff:g id="APPS">%1$s</xliff:g> प्रयोग गरिरहेका एपहरू"</string>
     <string name="tap_to_wake" msgid="1902991239401652323">"सक्रिय पार्न ट्याप गर्नुहोस्"</string>
     <string name="tap_to_wake_summary" msgid="8485222120721006793">"यन्त्र सक्रिय पार्न स्क्रिनको जहाँसुकै दुई पटक ट्याप गर्नुहोस्"</string>
     <string name="domain_urls_title" msgid="7939209950373945367">"लिंकहरू खोल्दै"</string>
     <string name="domain_urls_summary_none" msgid="5401203416941265109">"समर्थित लिंकहरू नखोल्नुहोस्"</string>
     <string name="domain_urls_summary_one" msgid="3893975485064803435">"<xliff:g id="DOMAIN">%s</xliff:g> खोल्नुहोस्"</string>
     <string name="domain_urls_summary_some" msgid="2130534984153210797">"<xliff:g id="DOMAIN">%s</xliff:g> र अन्य URL हरूलाई खोल्नुहोस्"</string>
-    <string name="domain_urls_apps_summary_off" msgid="1110203970617922543">"समर्थित लिंकहरू खोल्न सक्ने अनुप्रयोग छैन"</string>
+    <string name="domain_urls_apps_summary_off" msgid="1110203970617922543">"समर्थित लिंकहरू खोल्न सक्ने एप छैन"</string>
     <plurals name="domain_urls_apps_summary_on" formatted="false" msgid="3571309605151815405">
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> अनुप्रयोगले समर्थित लिंकहरू खोल्न सक्छन्</item>
       <item quantity="one">एउटा अनुप्रयोगले समर्थित लिंकहरू खोल्न सक्छ</item>
@@ -3659,25 +3664,25 @@
     <string name="default_apps_title" msgid="3848048391400989931">"पूर्वनिर्धारित"</string>
     <string name="default_for_work" msgid="7290411716804495366">"कार्यका लागि पूर्वनिर्धारित"</string>
     <string name="assist_and_voice_input_title" msgid="324148194703846130">"सहायक तथा आवाजको इनपुट"</string>
-    <string name="default_assist_title" msgid="2060846994203235317">"सहायक अनुप्रयोग"</string>
+    <string name="default_assist_title" msgid="2060846994203235317">"सहायक एप"</string>
     <string name="assistant_security_warning_title" msgid="8014460924169723059">"<xliff:g id="ASSISTANT_APP_NAME">%s</xliff:g>लाई आफ्नो सहायक बनाउन चाहनुहुन्छ?"</string>
-    <string name="assistant_security_warning" msgid="1304057692847069938">"तपाईँको स्क्रिनमा देखिने वा अनुप्रयोगहरू भित्र पहुँचयोग्य जानकारी लगायत यो सहायकले तपाईँको प्रणालीमा प्रयोगमा रहेका अनुप्रयोगहरूकाबारे जानकारी पढ्न सक्षम हुनेछ।"</string>
+    <string name="assistant_security_warning" msgid="1304057692847069938">"तपाईँको स्क्रिनमा देखिने वा एपहरू भित्र पहुँचयोग्य जानकारी लगायत यो सहायकले तपाईँको प्रणालीमा प्रयोगमा रहेका एपहरूकाबारे जानकारी पढ्न सक्षम हुनेछ।"</string>
     <string name="assistant_security_warning_agree" msgid="5105692801460137289">"सहमत छु"</string>
     <string name="assistant_security_warning_disagree" msgid="4217490999193100459">"असहमत छु"</string>
     <string name="choose_voice_input_title" msgid="5369311838580756359">"आवाज इनपुट रोज्नुहोस्"</string>
-    <string name="default_browser_title" msgid="4933937500898014977">"ब्राउजर अनुप्रयोग"</string>
+    <string name="default_browser_title" msgid="4933937500898014977">"ब्राउजर एप"</string>
     <string name="default_browser_title_none" msgid="46431244274747124">"कुनै पूर्वनिर्धारित ब्राउजर छैन"</string>
-    <string name="default_phone_title" msgid="6038690021912575740">"फोन अनुप्रयोग"</string>
+    <string name="default_phone_title" msgid="6038690021912575740">"फोन एप"</string>
     <string name="roles_title" msgid="2825063787446244357">"भूमिकाहरू"</string>
     <string name="default_app" msgid="8861276008866619872">"(पूर्वनिर्धारित)"</string>
     <string name="system_app" msgid="4111402206594443265">"(प्रणाली)"</string>
     <string name="system_default_app" msgid="1454719098589351197">"(प्रणालीको पूर्वनिर्धारित)"</string>
-    <string name="apps_storage" msgid="5658466038269046038">"अनुप्रयोग भण्डारण"</string>
+    <string name="apps_storage" msgid="5658466038269046038">"एप भण्डारण"</string>
     <string name="usage_access" msgid="2023443456361489516">"प्रयोगसम्बन्धी पहुँच"</string>
     <string name="permit_usage_access" msgid="3321727608629752758">"प्रयोग पहुँचलाई अनुमति दिनुहोस्"</string>
-    <string name="app_usage_preference" msgid="5691545073101551727">"अनुप्रयोग प्रयोग प्राथमिकताहरू"</string>
+    <string name="app_usage_preference" msgid="5691545073101551727">"एप प्रयोग प्राथमिकताहरू"</string>
     <string name="time_spent_in_app_pref_title" msgid="2803186835902798451">"यन्त्रमा हेरेर बिताउने समय"</string>
-    <string name="usage_access_description" msgid="2178083292760305207">"प्रयोग पहुँचले अनुप्रयोगलाई तपाईंले तपाईँको वाहक, भाषा सेटिङहरू, र अन्य विवरणहरू सहित के अन्य अनुप्रयोगहरू प्रयोग गरिरहनु भएको छ र कत्तिको गर्नुभएको छ भनेर ट्र्याक गर्न अनुमति दिन्छ।"</string>
+    <string name="usage_access_description" msgid="2178083292760305207">"प्रयोग पहुँचले एपलाई तपाईंले तपाईँको वाहक, भाषा सेटिङहरू, र अन्य विवरणहरू सहित के अन्य एपहरू प्रयोग गरिरहनु भएको छ र कत्तिको गर्नुभएको छ भनेर ट्र्याक गर्न अनुमति दिन्छ।"</string>
     <string name="memory_settings_title" msgid="7867148522014070721">"मेमोरी"</string>
     <string name="memory_details_title" msgid="6364825184513396865">"मेमोरीका विवरणहरू"</string>
     <string name="always_running" msgid="5320183445080208766">"सधैं चलिरहेको (<xliff:g id="PERCENTAGE">%s</xliff:g>)"</string>
@@ -3692,9 +3697,9 @@
     <string name="high_power_apps" msgid="2518319744362028920">"ब्याट्रीको अप्टिमाइजेसन"</string>
     <string name="additional_battery_info" msgid="6877663897819271203">"ब्याट्रीको प्रयोग सम्बन्धी अलर्ट"</string>
     <string name="show_all_apps" msgid="5442552004569634846">"यन्त्रको पूर्ण प्रयोग देखाउनुहोस्"</string>
-    <string name="hide_extra_apps" msgid="6798261081113299441">"अनुप्रयोगको प्रयोग देखाउनुहोस्"</string>
+    <string name="hide_extra_apps" msgid="6798261081113299441">"एपको प्रयोग देखाउनुहोस्"</string>
     <plurals name="power_high_usage_summary" formatted="false" msgid="4658343710126205199">
-      <item quantity="other"><xliff:g id="NUMBER">%2$d</xliff:g> अनुप्रयोगहरूले असामान्य व्यवहार देखाउँदैछन्</item>
+      <item quantity="other"><xliff:g id="NUMBER">%2$d</xliff:g> एपहरूले असामान्य व्यवहार देखाउँदैछन्</item>
       <item quantity="one"><xliff:g id="APP">%1$s</xliff:g> ले असामान्य व्यवहार देखाउँदैछ</item>
     </plurals>
     <plurals name="power_high_usage_title" formatted="false" msgid="63134064262760835">
@@ -3706,20 +3711,20 @@
     <string name="high_power_off" msgid="5906679734326490426">"ब्याट्री प्रयोग आफू अनुकूल गर्दै"</string>
     <string name="high_power_system" msgid="739584574711292753">"ब्याट्री आफू अनुकूल उपलब्ध छैन"</string>
     <string name="high_power_desc" msgid="333756885680362741">"ब्याट्री आफू अनुकूल लागू नगर्नुहोस्। तपाईँको ब्याट्री निकै छिटो सिध्याउन सक्छ।"</string>
-    <string name="high_power_prompt_title" msgid="2805745781720454052">"अनुप्रयोगलाई सधैँ पृष्ठभूमिमा चल्न दिने हो?"</string>
-    <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g> लाई सधैँ पृष्ठभूमिमा चल्न दिनुले ब्याट्रीको आयु घट्न सक्छ। \n\nयसलाई तपाईं पछि सेटिङ&gt; अनुप्रयोगहरू&gt; सूचनाहरूबाट हटाउन सक्नुहुन्छ।"</string>
+    <string name="high_power_prompt_title" msgid="2805745781720454052">"एपलाई सधैँ पृष्ठभूमिमा चल्न दिने हो?"</string>
+    <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g> लाई सधैँ पृष्ठभूमिका चल्न दिनुभयो भने ब्याट्रीको आयु घट्न सक्छ। \n\nयसलाई तपाईं पछि सेटिङ&gt; एपहरू&gt; सूचनाहरूबाट हटाउन सक्नुहुन्छ।"</string>
     <string name="battery_summary" msgid="4345690800899981339">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> पछिल्‍लो पटक पूरा चार्ज भएदेखिको प्रयोग"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"पावर व्यवस्थापन"</string>
     <string name="no_battery_summary" msgid="4105932628367471314">"पछिल्लो पूरा चार्ज देखि ब्याट्रीको प्रयोग गरिएको छैन"</string>
-    <string name="app_notification_preferences" msgid="5154466638524523201">"अनुप्रयोग सेटिङहरू"</string>
+    <string name="app_notification_preferences" msgid="5154466638524523201">"एप सेटिङहरू"</string>
     <string name="system_ui_settings" msgid="6751165163665775447">"SystemUI Tuner देखाउनुहोस्"</string>
     <string name="additional_permissions" msgid="3142290772324571654">"अतिरिक्त अनुमतिहरू"</string>
     <string name="additional_permissions_more" msgid="714264060348056246">"<xliff:g id="COUNT">%1$d</xliff:g> थप"</string>
     <string name="share_remote_bugreport_dialog_title" msgid="1390719492733882678">"बग रिपोर्टलाई साझेदारी गर्ने हो?"</string>
-    <string name="share_remote_bugreport_dialog_message_finished" msgid="5133489230646384192">"तपाईँको IT प्रशासकले यस यन्त्रको समस्या निवारण गर्नमा मद्दत गर्न बग रिपोर्टका लागि अनुरोध गर्नुभएको छ। अनुप्रयोग र डेटा साझेदारी हुन सक्छ।"</string>
-    <string name="share_remote_bugreport_dialog_message" msgid="6680361103125933760">"तपाईँको IT प्रशासकले यस यन्त्रको समस्या निवारण गर्नमा मद्दत गर्न बग रिपोर्टका लागि अनुरोध गर्नुभएको छ। अनुप्रयोग र डेटा साझेदारी हुन सक्छ र तपाईँको यन्त्र अस्थायी रूपमा सुस्त हुन सक्छ।"</string>
+    <string name="share_remote_bugreport_dialog_message_finished" msgid="5133489230646384192">"तपाईँको IT एडमिनले यस यन्त्रको समस्या निवारण गर्नमा मद्दत गर्न बग रिपोर्टका लागि अनुरोध गर्नुभएको छ। एप र डेटा साझेदारी हुन सक्छ।"</string>
+    <string name="share_remote_bugreport_dialog_message" msgid="6680361103125933760">"तपाईँको IT एडमिनले यस यन्त्रको समस्या निवारण गर्नमा मद्दत गर्न बग रिपोर्टका लागि अनुरोध गर्नुभएको छ। एप र डेटा साझेदारी हुन सक्छ र तपाईँको यन्त्र अस्थायी रूपमा सुस्त हुन सक्छ।"</string>
     <string name="sharing_remote_bugreport_dialog_message" msgid="3814787466701526359">"यो बग रिपोर्ट तपाईँको IT प्रशासकसँग साझेदारी भइरहेको छ। थप विवरणहरूका लागि प्रशासकलाई सम्पर्क गर्नुहोस्।"</string>
-    <string name="share_remote_bugreport_action" msgid="8600797271670537888">"साझेदारी गर्नुहोस्"</string>
+    <string name="share_remote_bugreport_action" msgid="8600797271670537888">"सेयर गर्नुहोस्"</string>
     <string name="decline_remote_bugreport_action" msgid="706319275774199033">"अस्वीकार गर्नुहोस्"</string>
     <string name="usb_use_charging_only" msgid="2344625733377110164">"डेटा स्थानान्तरण गरिँदैन"</string>
     <string name="usb_use_charging_only_desc" msgid="3283518562582478950">"केवल यो यन्त्र चार्ज गर्नुहोस्"</string>
@@ -3753,17 +3758,17 @@
     <string name="usb_summary_MIDI_power" msgid="7685597621357005180">"MIDI र विद्युत् आपूर्ति"</string>
     <string name="background_check_pref" msgid="664081406854758392">"पृष्ठभूमि जाँच"</string>
     <string name="background_check_title" msgid="4136736684290307970">"पूर्ण पृष्ठभूमि पहुँच"</string>
-    <string name="assist_access_context_title" msgid="2274614501747710439">"स्क्रिनबाट पाठ प्रयोग गर्नुहोस्"</string>
-    <string name="assist_access_context_summary" msgid="5867997494395842785">"स्क्रिन सामग्रीहरूलाई पाठको रूपमा पहुँच गर्न सहायक अनुप्रयोगलाई अनुमति दिनुहोस्"</string>
+    <string name="assist_access_context_title" msgid="2274614501747710439">"स्क्रिनको पाठ प्रयोग गर्नुहोस्"</string>
+    <string name="assist_access_context_summary" msgid="5867997494395842785">"स्क्रिन सामग्रीहरूलाई पाठको रूपमा प्रयोग गर्न सहायक एपलाई अनुमति दिनुहोस्"</string>
     <string name="assist_access_screenshot_title" msgid="1991014038776117688">"स्क्रिसट प्रयोग गर्नुहोस्"</string>
-    <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"स्क्रिनको एउटा छवि पहुँच गर्न सहायक अनुप्रयोगलाई अनुमति दिनुहोस्"</string>
+    <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"स्क्रिनको एउटा सट लिन सहायक एपलाई अनुमति दिनुहोस्"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"स्क्रिन झिमझिम पार्नुहोस्"</string>
-    <string name="assist_flash_summary" msgid="6697095786317559129">"सहायक अनुप्रयोगले स्क्रिन वा स्क्रिनसटबाट पाठमाथि पहुँच राख्दा स्क्रिनका किनाराहरू झिमझिम पार्नुहोस्"</string>
-    <string name="assist_footer" msgid="7030121180457472165">"सहायक अनुप्रयोगहरूले तपाईंले हेर्दै गर्नुभएको स्क्रिनबाट प्राप्त जानकारीमा आधारित भई तपाईंलाई मद्दत गर्न सक्छन्।केही अनुप्रयोगहरूले तपाईंलाई एकीकृत सहायता दिन दुवै लन्चर र आवाज संलग्न इनपुट सेवाहरूलाई समर्थन गर्दछन्।"</string>
+    <string name="assist_flash_summary" msgid="6697095786317559129">"सहायक अनुप्रयोगले स्क्रिन वा स्क्रिनसटबाट पाठ प्रयोग गर्दा स्क्रिनका किनाराहरू झिमझिम पार्नुहोस्"</string>
+    <string name="assist_footer" msgid="7030121180457472165">"सहायक एपहरूले तपाईंले हेर्दै गर्नुभएको स्क्रिनबाट प्राप्त जानकारीमा आधारित भई तपाईंलाई मद्दत गर्न सक्छन्।केही एपहरूले तपाईंलाई एकीकृत सहायता दिन दुवै लन्चर र आवाज संलग्न इनपुट सेवाहरूलाई समर्थन गर्दछन्।"</string>
     <string name="average_memory_use" msgid="5333366040118953945">"औसत मेमोरी प्रयोग"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"अधिकतम मेमोरी प्रयोग"</string>
     <string name="memory_usage" msgid="7963253555330830906">"मेमोरी प्रयोग"</string>
-    <string name="app_list_memory_use" msgid="356095943215944031">"अनुप्रयोग उपयोग"</string>
+    <string name="app_list_memory_use" msgid="356095943215944031">"एप उपयोग"</string>
     <string name="memory_details" msgid="5165105904103664110">"विवरणहरू"</string>
     <string name="memory_use_summary" msgid="7676311343819965850">"पछिल्लो ३ घण्टामा <xliff:g id="SIZE">%1$s</xliff:g> औसत मेमोरी प्रयोग गरियो"</string>
     <string name="no_memory_use_summary" msgid="3966550113388917978">"पछिल्लो ३ घण्टामा कुनै मेमोरी प्रयोग गरिएन"</string>
@@ -3775,7 +3780,7 @@
     <string name="free_memory" msgid="4758919141048544927">"उपलब्ध"</string>
     <string name="memory_usage_apps" msgid="2839241373381152354">"अनुप्रयोगहरूद्वारा प्रयोग गरिएको मेमोरी"</string>
     <plurals name="memory_usage_apps_summary" formatted="false" msgid="1235024908546944704">
-      <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> अनुप्रयोगहरूले पछिल्लो <xliff:g id="DURATION_1">%2$s</xliff:g> मा मेमोरी प्रयोग गर्‍यो</item>
+      <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> एपहरूले पछिल्लो <xliff:g id="DURATION_1">%2$s</xliff:g> मा मेमोरी प्रयोग गर्‍यो</item>
       <item quantity="one">१ अनुप्रयोगले पछिल्लो <xliff:g id="DURATION_0">%2$s</xliff:g> मा मेमोरी प्रयोग गर्‍यो</item>
     </plurals>
     <string name="running_frequency" msgid="7545170806968474449">"आवृत्ति"</string>
@@ -3788,50 +3793,50 @@
     <string name="zen_access_revoke_warning_dialog_summary" msgid="3487422193181311403">"यस अनुप्रयोगले बनाएका सबै बाधा नपुर्याउनुहोस् नियम हटाइने छ।"</string>
     <string name="ignore_optimizations_on" msgid="4373971641328943551">"आफू अनुकूल नगर्नुहोस्"</string>
     <string name="ignore_optimizations_off" msgid="4372289432580282870">"अनुकुलन गर्नुहोस्"</string>
-    <string name="ignore_optimizations_on_desc" msgid="2904484569799521559">"यसले तपाईंको ब्याट्रीको चार्ज चाँडै घटाउन सक्छ। अनुप्रयोगलाई अब उप्रान्त पृष्ठभूमिमा ब्याट्री प्रयोग गर्न प्रतिबन्ध लगाइने छैन।"</string>
+    <string name="ignore_optimizations_on_desc" msgid="2904484569799521559">"यसले तपाईंको ब्याट्रीको चार्ज चाँडै घटाउन सक्छ। एपलाई अब उप्रान्त पृष्ठभूमिमा ब्याट्री प्रयोग गर्न प्रतिबन्ध लगाइने छैन।"</string>
     <string name="ignore_optimizations_off_desc" msgid="5598702251817814289">"अझ टिकाउयुक्त ब्याट्रीका लागि सिफारिस गरिएको"</string>
     <string name="ignore_optimizations_title" msgid="7924345545276166305">"<xliff:g id="APP">%s</xliff:g> लाई ब्याट्री आफू अनुकूल बेवास्ता गर्नै अनुमति दिने हो?"</string>
     <string name="app_list_preference_none" msgid="7100409177446935028">"कुनै पनि होइन"</string>
-    <string name="work_profile_usage_access_warning" msgid="403208064382097510">"यो अनुप्रयोगको प्रयोगको पहुँचलाई निष्क्रिय पार्नुले तपाईंको प्रशासकलाई तपाईंको कार्य प्रोफाइलमा रहेका अनुप्रयोगहरूको डेटा प्रयोगलाई ट्र्याक गर्नबाट रोक्दैन"</string>
+    <string name="work_profile_usage_access_warning" msgid="403208064382097510">"यो एपको प्रयोगको पहुँचलाई निष्क्रिय पार्नुले तपाईंको प्रशासकलाई तपाईंको कार्य प्रोफाइलमा रहेका अनुप्रयोगहरूको डेटा प्रयोगलाई ट्र्याक गर्नबाट रोक्दैन"</string>
     <string name="accessibility_lock_screen_progress" msgid="8242917828598820049">"<xliff:g id="COUNT_1">%2$d</xliff:g> को <xliff:g id="COUNT_0">%1$d</xliff:g> वर्णहरू प्रयोग गरिए"</string>
     <string name="draw_overlay" msgid="2878665072530660668">"अन्य एपहरूको माथिपट्टि देखाउनु"</string>
-    <string name="system_alert_window_settings" msgid="3024330223417646567">"अन्य अनुप्रयोगहरूको माथिपट्टि देखाउनुहोस्"</string>
-    <string name="system_alert_window_apps_title" msgid="9188448296493699566">"अनुप्रयोगहरू"</string>
-    <string name="system_alert_window_access_title" msgid="5187343732185369675">"अन्य अनुप्रयोगहरूको माथिपट्टि देखाउनुहोस्"</string>
-    <string name="permit_draw_overlay" msgid="9039092257052422344">"अन्य एपहरूको माथिपट्टि देखिने अनुमति दिनुहोस्"</string>
-    <string name="allow_overlay_description" msgid="6669524816705082807">"यो अनुप्रयोगलाई तपाईंले प्रयोग गरिरहनुभएका अन्य अनुप्रयोगहरूको माथिपट्टि देखिन अनुमति दिनुहोस्। यसले तपाईंले गर्ने ती अनुप्रयोगहरूको प्रयोगमा हस्तक्षेप गर्न वा तिनीहरू देखा पर्ने वा तिनीहरूले काम गर्ने तरिकालाई परिवर्तन गर्न सक्छ।"</string>
+    <string name="system_alert_window_settings" msgid="3024330223417646567">"अन्य अनुप्रयोगमा देखाउनुहोस्"</string>
+    <string name="system_alert_window_apps_title" msgid="9188448296493699566">"एपहरू"</string>
+    <string name="system_alert_window_access_title" msgid="5187343732185369675">"अन्य अनुप्रयोगमा देखाउनुहोस्"</string>
+    <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="filter_overlay_apps" msgid="6336897660213304743">"अनुमतिसहित अनुप्रयोगहरू"</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>
-    <string name="keywords_install_other_apps" msgid="5383559540695847668">"अज्ञात स्रोतहरूबाट प्राप्त हुने अनुप्रयोगहरू स्थापना गर्नुहोस्‌"</string>
-    <string name="write_settings" msgid="9009040811145552108">"प्रणाली सेटिङहरू परिमार्जन"</string>
+    <string name="keywords_install_other_apps" msgid="5383559540695847668">"अज्ञात स्रोतहरूबाट प्राप्त हुने एपहरू स्थापना गर्नुहोस्‌"</string>
+    <string name="write_settings" msgid="9009040811145552108">"प्रणालीका सेटिङ बदल्नुहोस्"</string>
     <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">"वित्तीय अनुप्रयोगको Sms माथिको पहुँच"</string>
-    <string name="filter_install_sources_apps" msgid="4519839764020866701">"अन्य अनुप्रयोगहरू स्थापना गर्न सक्छ"</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">"वित्तीय एपको Sms माथिको पहुँच"</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>
     <string name="permit_write_settings" msgid="4198491281216818756">"प्रणालीका सेटिङहरू परिमार्जन गर्न दिनुहोस्"</string>
-    <string name="write_settings_description" msgid="2536706293042882500">"यस अनुमतिले अनुप्रयोगलाई प्रणाली सेटिङहरू परिमार्जन गर्न दिन्छ।"</string>
+    <string name="write_settings_description" msgid="2536706293042882500">"यस अनुमतिले एपलाई प्रणाली सेटिङहरू परिमार्जन गर्न दिन्छ।"</string>
     <string name="write_settings_on" msgid="7328986337962635118">"हो"</string>
     <string name="write_settings_off" msgid="5708257434958406202">"होइन"</string>
     <string name="external_source_switch_title" msgid="5947220058496373178">"यो स्रोतबाट अनुमति दिनुहोस्‌"</string>
     <string name="camera_gesture_title" msgid="899403310746415135">"क्यामेराका लागि दुई पटक बटार्नुहोस्"</string>
-    <string name="camera_gesture_desc" msgid="7751841175916789527">"दुई पटक आफ्नो नारी बटारेर क्यामेरा अनुप्रयोग खोल्नुहोस्"</string>
+    <string name="camera_gesture_desc" msgid="7751841175916789527">"दुई पटक आफ्नो नारी बटारेर क्यामेरा एप खोल्नुहोस्"</string>
     <string name="camera_double_tap_power_gesture_title" msgid="8874747801078147525">"क्यामेराका लागि दुई पटक पावर बटन थिच्नुहोस्"</string>
     <string name="camera_double_tap_power_gesture_desc" msgid="6166349645433682873">"स्क्रिन अनलक नगरी क्यामेरा चाँडै खोल्नुहोस्"</string>
     <string name="screen_zoom_title" msgid="164369086350486104">"प्रदर्शन हुने आकार"</string>
-    <string name="screen_zoom_short_summary" msgid="5508079362742276703">"स्क्रिनमा भएको वस्तुहरूलाई अझ ठूलो वा सानो पार्नुहोस्"</string>
+    <string name="screen_zoom_short_summary" msgid="5508079362742276703">"स्क्रिनमा भएको वस्तुहरूलाई अझ ठुलो वा सानो पार्नुहोस्"</string>
     <string name="screen_zoom_keywords" msgid="8358462497896524092">"घनत्व प्रदर्शन गर्नुहोस्, स्क्रिन जुम, स्केल, स्केलिङ"</string>
-    <string name="screen_zoom_summary" msgid="5294003755961312560">"तपाईंको स्क्रिनमा भएको वस्तुहरूलाई अझ सानो वा ठूलो पार्नुहोस्। तपाईंको स्क्रिनमा भएको केही अनुप्रयोगहरूको स्थिति परिवर्तन हुनसक्छ।"</string>
+    <string name="screen_zoom_summary" msgid="5294003755961312560">"तपाईंको स्क्रिनमा भएको वस्तुहरूलाई अझ सानो वा ठुलो पार्नुहोस्। तपाईंको स्क्रिनमा भएको केही अनुप्रयोगहरूको स्थिति परिवर्तन हुनसक्छ।"</string>
     <string name="screen_zoom_preview_title" msgid="2924312934036753091">"पूर्वावलोकन"</string>
     <string name="screen_zoom_make_smaller_desc" msgid="1374501139722916729">"सानो बनाउनुहोस्"</string>
-    <string name="screen_zoom_make_larger_desc" msgid="5306684807895846141">"ठूलो बनाउनुहोस्"</string>
+    <string name="screen_zoom_make_larger_desc" msgid="5306684807895846141">"ठुलो बनाउनुहोस्"</string>
     <string name="screen_zoom_conversation_icon_alex" msgid="2733983340094411661">"A"</string>
     <string name="screen_zoom_conversation_icon_pete" msgid="4990733893088820204">"P"</string>
     <string name="screen_zoom_conversation_message_1" msgid="7215516160541988278">"नमस्कार पिट!"</string>
@@ -3842,8 +3847,8 @@
     <string name="screen_zoom_conversation_timestamp_2" msgid="816265985618121370">"मंगलबार बेलुका ६.०१ बजे"</string>
     <string name="screen_zoom_conversation_timestamp_3" msgid="7346540212221792932">"मंगलबार बेलुका ६.०२ बजे"</string>
     <string name="screen_zoom_conversation_timestamp_4" msgid="1452374487089625022">"मंगलबार बेलुका ६.०३ बजे"</string>
-    <string name="disconnected" msgid="4088439352761747084">"जडान भएको छैन"</string>
-    <string name="keyboard_disconnected" msgid="3068615097201531871">"जडान भएको छैन"</string>
+    <string name="disconnected" msgid="4088439352761747084">"कनेक्ट भएको छैन"</string>
+    <string name="keyboard_disconnected" msgid="3068615097201531871">"कनेक्ट भएको छैन"</string>
     <string name="data_usage_summary_format" msgid="7788095271598602797">"डेटाको <xliff:g id="AMOUNT">%1$s</xliff:g> प्रयोग गरियो"</string>
     <string name="data_usage_wifi_format" msgid="9028934101966264710">"Wi‑Fi मा प्रयोग भएको <xliff:g id="AMOUNT">^1</xliff:g>"</string>
     <plurals name="notification_summary" formatted="false" msgid="761061343339229103">
@@ -3851,8 +3856,8 @@
       <item quantity="one">१ अनुप्रयोगका लागि निष्क्रिय पारिएको छ</item>
     </plurals>
     <string name="notification_summary_none" msgid="5003043219430054784">"सबै अनुप्रयोगहरूका लागि खुला"</string>
-    <string name="apps_summary" msgid="8355759446490212195">"<xliff:g id="COUNT">%1$d</xliff:g> अनुप्रयोगहरू स्थापना गरियो"</string>
-    <string name="apps_summary_example" msgid="3011143598675185269">"२४ अनुप्रयोगहरू स्थापित गरियो"</string>
+    <string name="apps_summary" msgid="8355759446490212195">"<xliff:g id="COUNT">%1$d</xliff:g> एपहरू स्थापना गरियो"</string>
+    <string name="apps_summary_example" msgid="3011143598675185269">"२४ एपहरू स्थापित गरियो"</string>
     <string name="storage_summary" msgid="4835916510511133784">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> प्रयोग भएको - खाली <xliff:g id="FREE_SPACE">%2$s</xliff:g>"</string>
     <string name="storage_summary_with_sdcard" msgid="8742907204848352697">"आन्तरिक भण्डारण: <xliff:g id="PERCENTAGE">%1$s</xliff:g> प्रयोग गरिएको - <xliff:g id="FREE_SPACE">%2$s</xliff:g> खाली"</string>
     <string name="display_summary" msgid="5725269449657325797">"<xliff:g id="TIMEOUT_DESCRIPTION">%1$s</xliff:g> को निष्क्रियता पछिको शयन"</string>
@@ -3866,18 +3871,18 @@
     <string name="backup_disabled" msgid="6941165814784765643">"ब्याकअप असक्षम गरियो"</string>
     <string name="android_version_summary" msgid="2192751442789395445">"Android <xliff:g id="VERSION">%1$s</xliff:g> मा अद्यावधिक गरियो"</string>
     <string name="android_version_pending_update_summary" msgid="3554543810520655076">"अद्यावधिक उपलब्ध छ"</string>
-    <string name="disabled_by_policy_title" msgid="1238318274952958846">"कार्यलाई अनुमति छैन"</string>
+    <string name="disabled_by_policy_title" msgid="1238318274952958846">"यो कार्य गर्न मिल्दैन"</string>
     <string name="disabled_by_policy_title_adjust_volume" msgid="7094547090629203316">"भोल्युम परिवर्तन गर्न सकिँदैन"</string>
     <string name="disabled_by_policy_title_outgoing_calls" msgid="3805836913095496278">"कल गर्न अनुमति छैन"</string>
     <string name="disabled_by_policy_title_sms" msgid="1453236584236681105">"SMS लाई अनुमति छैन"</string>
     <string name="disabled_by_policy_title_camera" msgid="3741138901926111197">"यो क्यामेरालाई अनुमति छैन"</string>
     <string name="disabled_by_policy_title_screen_capture" msgid="1856835333536274665">"स्क्रिनसटलाई अनुमति छैन"</string>
-    <string name="disabled_by_policy_title_suspend_packages" msgid="4254714213391802322">"यो अनुप्रयोग खोल्न सकिँदैन"</string>
+    <string name="disabled_by_policy_title_suspend_packages" msgid="4254714213391802322">"यो एप खोल्न सकिँदैन"</string>
     <string name="default_admin_support_msg" msgid="5789424433689798637">"तपाईंसँग प्रश्नहरू छन् भने आफ्नो IT प्रशासकलाई सम्पर्क गर्नुहोस्"</string>
     <string name="admin_support_more_info" msgid="8737842638087863477">"थप विवरणहरु"</string>
-    <string name="admin_profile_owner_message" msgid="3199544166281052845">"तपाईंको प्रशासकले तपाईंको कार्य प्रोफाइलसँग सम्बन्धित अनुप्रयोग र डेटाका साथै सेटिङ। अनुमति, संस्थागत पहुँच, नेटवर्क सम्बन्धी गतिविधि र यस यन्त्रको स्थानसम्बन्धी जानकारीको अनुगमन र व्यवस्थापन गर्न सक्छ।"</string>
-    <string name="admin_profile_owner_user_message" msgid="2991249382056855531">"तपाईंको प्रशासकले यस प्रयोगकर्तासँग सम्बन्धित अनुप्रयोग तथा डेटाका साथै सेटिङ, अनुमति, संस्थागत पहुँच, नेटवर्क सम्बन्धी गतिविधि र यस यन्त्रको स्थानसम्बन्धी जानकारीको अनुगमन र व्यवस्थापन गर्न सक्छ।"</string>
-    <string name="admin_device_owner_message" msgid="1823477572459610869">"तपाईंको प्रशासकले यस यन्त्रसँग सम्बन्धित अनुप्रयोग र डेटाका साथै सेटिङ, अनुमति, संस्थागत पहुँच, नेटवर्क सम्बन्धी गतिविधि, र यस यन्त्रको स्थानसम्बन्धी जानकारीको अनुगमन र व्यवस्थापन गर्न सक्छ।"</string>
+    <string name="admin_profile_owner_message" msgid="3199544166281052845">"तपाईंको प्रशासकले तपाईंको कार्य प्रोफाइलसँग सम्बन्धित एप र डेटाका साथै सेटिङ। अनुमति, संस्थागत पहुँच, नेटवर्क सम्बन्धी गतिविधि र यस यन्त्रको स्थानसम्बन्धी जानकारीको अनुगमन र व्यवस्थापन गर्न सक्छ।"</string>
+    <string name="admin_profile_owner_user_message" msgid="2991249382056855531">"तपाईंको प्रशासकले यस प्रयोगकर्तासँग सम्बन्धित एप तथा डेटाका साथै सेटिङ, अनुमति, संस्थागत पहुँच, नेटवर्क सम्बन्धी गतिविधि र यस यन्त्रको स्थानसम्बन्धी जानकारीको अनुगमन र व्यवस्थापन गर्न सक्छ।"</string>
+    <string name="admin_device_owner_message" msgid="1823477572459610869">"तपाईंको प्रशासकले यस यन्त्रसँग सम्बन्धित एप र डेटाका साथै सेटिङ, अनुमति, संस्थागत पहुँच, नेटवर्क सम्बन्धी गतिविधि, र यस यन्त्रको स्थानसम्बन्धी जानकारीको अनुगमन र व्यवस्थापन गर्न सक्छ।"</string>
     <string name="condition_turn_off" msgid="4395150881365143558">"बन्द गर्नुहोस्"</string>
     <string name="condition_turn_on" msgid="1699088245481841159">"सक्रिय गर्नुहोस्"</string>
     <string name="condition_expand_show" msgid="4118818022763913777">"देखाउनुहोस्"</string>
@@ -3895,16 +3900,16 @@
     <string name="condition_bg_data_title" msgid="184684435298857712">"डेटा सेभर"</string>
     <string name="condition_bg_data_summary" msgid="5194942860807136682">"सुविधाहरूलाई बन्देज लगाइएका छन्"</string>
     <string name="condition_work_title" msgid="9046811302347490371">"कार्यको प्रोफाइल बन्द छ"</string>
-    <string name="condition_work_summary" msgid="5586134491975748565">"अनुप्रयोग तथा सूचनाहरूका लागि"</string>
+    <string name="condition_work_summary" msgid="5586134491975748565">"एप तथा सूचनाहरूका लागि"</string>
     <string name="condition_device_muted_action_turn_on_sound" msgid="5849285946804815263">"आवाज सक्रिय गर्नुहोस्"</string>
     <string name="condition_device_muted_title" msgid="3930542786434609976">"रिङ्गर म्युट गरियो"</string>
     <string name="condition_device_muted_summary" msgid="3101055117680109021">"कल तथा सूचनाहरूका लागि"</string>
     <string name="condition_device_vibrate_title" msgid="5712659354868872338">"कम्पन मात्र"</string>
     <string name="condition_device_vibrate_summary" msgid="9073880731894828604">"कल तथा सूचनाहरूका लागि"</string>
     <string name="night_display_suggestion_title" msgid="4222839610992282188">"रात्रि प्रकाशको समय तालिका सेट गर्नुहोस्"</string>
-    <string name="night_display_suggestion_summary" msgid="1754361016383576916">"प्रत्येक रात स्क्रिनको रङ स्वतः परिवर्तन गर्नुहोस्‌"</string>
+    <string name="night_display_suggestion_summary" msgid="1754361016383576916">"प्रत्येक रात स्क्रिनको रङ्ग स्वतः परिवर्तन गर्नुहोस्‌"</string>
     <string name="condition_night_display_title" msgid="9171491784857160135">"रात्रिको प्रकाश सक्रिय छ"</string>
-    <string name="condition_night_display_summary" msgid="7885776986937527558">"स्क्रिन रङ मधुरो गरियो"</string>
+    <string name="condition_night_display_summary" msgid="7885776986937527558">"स्क्रिन रङ्ग मधुरो गरियो"</string>
     <string name="condition_grayscale_title" msgid="1226351649203551299">"ग्रेस्केल"</string>
     <string name="condition_grayscale_summary" msgid="749172886527349546">"खरानी रङमा मात्र प्रदर्शन गर्नुहोस्"</string>
     <string name="homepage_condition_footer_content_description" msgid="3563606465924396342">"संक्षिप्त गर्नुहोस्"</string>
@@ -3938,7 +3943,7 @@
     <string name="wifi_data_template" msgid="3146090439147042068">"<xliff:g id="AMOUNT">^1</xliff:g> Wi-Fi को डेटा"</string>
     <string name="ethernet_data_template" msgid="6414118030827090119">"<xliff:g id="AMOUNT">^1</xliff:g> इथरनेटको डेटा"</string>
     <string name="billing_cycle" msgid="5740717948341713190">"डेटासम्बन्धी चेतावनी तथा सीमा"</string>
-    <string name="app_usage_cycle" msgid="213483325132959663">"अनुप्रयोगको डेटा प्रयोगको चक्र"</string>
+    <string name="app_usage_cycle" msgid="213483325132959663">"एपको डेटा प्रयोगको चक्र"</string>
     <string name="cell_data_warning" msgid="8902740337286652689">"डेटासम्बन्धी चेतावनी: <xliff:g id="ID_1">^1</xliff:g>"</string>
     <string name="cell_data_limit" msgid="3175933829235314233">"डेटाको सीमा: <xliff:g id="ID_1">^1</xliff:g>"</string>
     <string name="cell_data_warning_and_limit" msgid="3846150001253927594">"डेटासम्बन्धी चेतावनी: <xliff:g id="ID_1">^1</xliff:g> / डेटाको सीमा: <xliff:g id="ID_2">^2</xliff:g>"</string>
@@ -3948,7 +3953,7 @@
       <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> वटा बन्देजहरू</item>
       <item quantity="one">१ वटा बन्देज</item>
     </plurals>
-    <string name="operator_warning" msgid="4676042739221117031">"वाहकको डेटाको हिसाब-किताब राख्ने कार्य तपाईँको यन्त्रको हिसाब-किताब राख्ने कार्य भन्दा फरक हुन सक्छ"</string>
+    <string name="operator_warning" msgid="4676042739221117031">"डेटाको प्रयोगसम्बन्धी वाहकले राखेको हिसाब-किताब र तपाईंको यन्त्रले राखेको हिसाब-किताब फरक हुन सक्छ"</string>
     <string name="data_used_template" msgid="761605393453849477">"<xliff:g id="ID_1">%1$s</xliff:g> प्रयोग गरियो"</string>
     <string name="set_data_warning" msgid="8115980184415563941">"डेटाबारे चेतावनी सेट गर्नुहोस्"</string>
     <string name="data_warning" msgid="2699207195535036240">"डेटाबारे चेतावनी"</string>
@@ -3957,10 +3962,10 @@
     <string name="data_limit" msgid="5793521160051596228">"डेटाको सीमा"</string>
     <string name="data_usage_template" msgid="6848274347956096882">"<xliff:g id="ID_2">%2$s</xliff:g> सम्म <xliff:g id="ID_1">%1$s</xliff:g> प्रयोग गरियो"</string>
     <string name="configure" msgid="8232696842838580549">"कन्फिगर गर्नुहोस्"</string>
-    <string name="data_usage_other_apps" msgid="7002491980141402084">"प्रयोगमा समावेश गरिएका अन्य अनुप्रयोगहरू"</string>
+    <string name="data_usage_other_apps" msgid="7002491980141402084">"प्रयोगमा समावेश गरिएका अन्य एपहरू"</string>
     <plurals name="data_saver_unrestricted_summary" formatted="false" msgid="6046013861315713697">
       <item quantity="other">डेटा सेभर अन हुँदा <xliff:g id="COUNT">%1$d</xliff:g> अनुप्रयोगहरूलाई असीमित डेटाको प्रयोग गर्न अनुमति दिइयो</item>
-      <item quantity="one">डेटा सेभर अन हुँदा १ अनुप्रयोगलाई असीमित डेटाको प्रयोग गर्न अनुमति दिइयो</item>
+      <item quantity="one">डेटा सेभर अन हुँदा १ एपलाई असीमित डेटाको प्रयोग गर्न अनुमति दिइयो</item>
     </plurals>
     <string name="data_usage_title" msgid="7874606430902201083">"प्राथमिक डेटा"</string>
     <string name="data_usage_wifi_title" msgid="7161828479387766556">"Wi‑Fi डेटा"</string>
@@ -3988,7 +3993,7 @@
     <string name="data_saver_switch_title" msgid="8244008132112735207">"डेटा सेभर प्रयोग गर्नुहोस्"</string>
     <string name="unrestricted_app_title" msgid="4390661122069905122">"असीमित डेटाको प्रयोग"</string>
     <string name="unrestricted_app_summary" msgid="2829141815077800483">"डेटा सेभर अन हुँदा असीमित डेटाको पहुँचलाई अनुमति दिनुहोस्"</string>
-    <string name="home_app" msgid="3695063566006954160">"घरेलु अनुप्रयोग"</string>
+    <string name="home_app" msgid="3695063566006954160">"घरेलु एप"</string>
     <string name="no_default_home" msgid="1518949210961918497">"पूर्वनिर्धारित गृहपृष्ठ छैन"</string>
     <string name="lockpattern_settings_require_cred_before_startup" msgid="63693894094570367">"स्टार्ट-अप सुरक्षित गर्नुहोस्"</string>
     <string name="lockpattern_settings_require_pattern_before_startup_summary" msgid="2330543541999937953">"तपाईंको यन्त्रलाई सुरुवात गर्न ढाँचा आवश्यक छ। यन्त्र बन्द हुँदा, यसले कल, सन्देश, सूचना, वा अलार्महरू प्राप्त गर्न सक्दैन।"</string>
@@ -3997,10 +4002,10 @@
     <string name="suggestion_additional_fingerprints" msgid="3434467207282466411">"अर्को फिंगरप्रिन्ट थप्नुहोस्"</string>
     <string name="suggestion_additional_fingerprints_summary" msgid="1916547587832484196">"अर्को औँलाको प्रयोग गरी अनलक गर्नुहोस्"</string>
     <string name="battery_saver_on_summary" msgid="6841062406467435672">"सक्रिय"</string>
-    <string name="battery_saver_off_scheduled_summary" msgid="3740414764069188669">"<xliff:g id="BATTERY_PERCENTAGE">%1$s</xliff:g> मा सक्रिय हुने छ"</string>
+    <string name="battery_saver_off_scheduled_summary" msgid="3740414764069188669">"<xliff:g id="BATTERY_PERCENTAGE">%1$s</xliff:g> मा अन हुने छ"</string>
     <string name="battery_saver_off_summary" msgid="8736555723004299721">"निष्क्रिय"</string>
     <string name="battery_saver_button_turn_on" msgid="3748696527267573793">"अहिले नै सक्रिय गर्नुहोस्"</string>
-    <string name="battery_saver_button_turn_off" msgid="2912950982503267828">"अहिले नै निष्क्रिय पार्नुहोस्"</string>
+    <string name="battery_saver_button_turn_off" msgid="2912950982503267828">"अहिले नै अफ गर्नुहोस्"</string>
     <string name="not_battery_optimizing" msgid="2616044774307734160">"ब्याट्री आफू अनुकूल प्रयोग गरिएको छैन"</string>
     <string name="lockscreen_remote_input" msgid="3363310613165354434">"यदि यन्त्रलाई लक गरिएको छ भने सूचनाहरूमा जवाफ वा अन्य पाठ टाइप गर्न रोक लगाउनुहोस्"</string>
     <string name="default_spell_checker" msgid="8636661093243189533">"पूर्वनिर्धारित हिज्जे परीक्षक"</string>
@@ -4039,7 +4044,7 @@
     <string name="notification_log_details_ranking_null" msgid="3907234749871463339">"वर्गीकरण सम्बन्धी वस्तु उपलब्ध छैन।"</string>
     <string name="notification_log_details_ranking_none" msgid="3687243721168608404">"वर्गीकरण सम्बन्धी वस्तुमा यो साँचो छैन।"</string>
     <string name="theme_customization_category" msgid="4043457940936660368">"विषयवस्तु"</string>
-    <string name="theme_customization_accent_color_title" msgid="3949108608589133216">"एक्सेन्टको रङ"</string>
+    <string name="theme_customization_accent_color_title" msgid="3949108608589133216">"एक्सेन्टको रङ्ग"</string>
     <string name="theme_customization_font_title" msgid="309728559821356597">"शीर्षक / मुख्य भागको फन्ट"</string>
     <string name="theme_customization_icon_shape_title" msgid="4603248388639328322">"आइकनको आकार"</string>
     <string name="theme_customization_device_default" msgid="7188874258500934312">"पूर्वनिर्धारित यन्त्र"</string>
@@ -4047,7 +4052,7 @@
     <string name="display_cutout_emulation_keywords" msgid="6795671536772871439">"प्रदर्शनसम्बन्धी कटआउट, नच"</string>
     <string name="overlay_option_device_default" msgid="165508753381657697">"पूर्वनिर्धारित यन्त्र"</string>
     <string name="overlay_toast_failed_to_apply" msgid="5692251825129250040">"ओभरले लागू गर्न सकिएन"</string>
-    <string name="special_access" msgid="1453926335914696206">"विशेष अनुप्रयोगको पहुँच"</string>
+    <string name="special_access" msgid="1453926335914696206">"विशेष एपको पहुँच"</string>
     <plurals name="special_access_summary" formatted="false" msgid="5182092345063909346">
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> अनुप्रयोगले असीमित डेटा प्रयोग गर्न सक्छन्</item>
       <item quantity="one">१ अनुप्रयोगले असीमित डेटा प्रयोग गर्न सक्छ</item>
@@ -4062,21 +4067,21 @@
     <string name="page_tab_title_summary" msgid="4824744863994538006">"सबै"</string>
     <string name="page_tab_title_support" msgid="5569262185010367870">"सुझाव तथा सहायता"</string>
     <string name="developer_smallest_width" msgid="2603134476228805075">"सबैभन्दा सानो चौडाइ"</string>
-    <string name="premium_sms_none" msgid="940723020871007898">"स्थापना गरिएका कुनै पनि अनुप्रयोगहरूले प्रिमियम SMS माथि पहुँचका लागि अनुरोध गरेका छैनन्"</string>
-    <string name="premium_sms_warning" msgid="7604011651486294515">"प्रिमियम SMS सक्रिय गर्नाले तपाईंलाई पैसा लाग्न सक्छ र उक्त रकम तपाईंको वाहकलाई तिर्नु पर्ने बिलमा जोडिनेछ। यदि तपाईं अनुप्रयोगको लागि अनुमति सक्रिय गर्नुहुन्छ भने तपाईं त्यस अनुप्रयोगको प्रयोग गरेर प्रिमियम SMS पठाउन सक्नुहुनेछ।"</string>
+    <string name="premium_sms_none" msgid="940723020871007898">"स्थापना गरिएका कुनै पनि एपहरूले प्रिमियम SMS माथि पहुँचका लागि अनुरोध गरेका छैनन्"</string>
+    <string name="premium_sms_warning" msgid="7604011651486294515">"प्रिमियम SMS सक्रिय गर्नाले तपाईंलाई पैसा लाग्न सक्छ र उक्त रकम तपाईंको वाहकलाई तिर्नु पर्ने बिलमा जोडिनेछ। यदि तपाईं एपको लागि अनुमति सक्रिय गर्नुहुन्छ भने तपाईं त्यस एपको प्रयोग गरेर प्रिमियम SMS पठाउन सक्नुहुनेछ।"</string>
     <string name="premium_sms_access" msgid="4550027460595822851">"प्रिमियम SMS माथि पहुँच"</string>
     <string name="bluetooth_disabled" msgid="6588102116819268238">"निष्क्रिय छ"</string>
-    <string name="bluetooth_connected_summary" msgid="439920840053965217">"<xliff:g id="ID_1">%1$s</xliff:g> मा जडान गरियो"</string>
+    <string name="bluetooth_connected_summary" msgid="439920840053965217">"<xliff:g id="ID_1">%1$s</xliff:g> मा कनेक्ट गरियो"</string>
     <string name="bluetooth_connected_multiple_devices_summary" msgid="596205630653123250">"धेरै यन्त्रहरूमा जडान गरियो"</string>
     <string name="demo_mode" msgid="3831081808592541104">"प्रणालीको UI को प्रदर्शन मोड"</string>
     <string name="dark_ui_mode" msgid="703844190192599217">"विषयवस्तु"</string>
     <string name="dark_ui_mode_title" msgid="8774932716427742413">"विषयवस्तु छनौट गर्नुहोस्"</string>
-    <string name="dark_ui_settings_light_summary" msgid="5219102347744462812">"यो सेटिङ अनुप्रयोगहरूमा पनि लागू हुन्छ"</string>
-    <string name="dark_ui_settings_dark_summary" msgid="7042737828943784289">"समर्थन गरिएका अनुप्रयोगहरू पनि बदलिएर गाढा विषयवस्तुमा जाने छन्"</string>
+    <string name="dark_ui_settings_light_summary" msgid="5219102347744462812">"यो सेटिङ एपहरूमा पनि लागू हुन्छ"</string>
+    <string name="dark_ui_settings_dark_summary" msgid="7042737828943784289">"समर्थन गरिएका एपहरू पनि बदलिएर गाढा विषयवस्तुमा जाने छन्"</string>
     <string name="quick_settings_developer_tiles" msgid="7423485925757678719">"द्रुत सेटिङहरू सम्बन्धी विकासकर्ताका टाइलहरू"</string>
     <string name="winscope_trace_quick_settings_title" msgid="940971040388411374">"Winscope को ट्रेस"</string>
     <string name="sensors_off_quick_settings_title" msgid="3655699045300438902">"सेन्सरहरू निष्क्रिय पार्नु…"</string>
-    <string name="managed_profile_settings_title" msgid="4340409321523532402">"कार्य प्रोफाइलका सेटिङहरू"</string>
+    <string name="managed_profile_settings_title" msgid="4340409321523532402">"कार्यालयसम्बन्धी प्रोफाइलका सेटिङ"</string>
     <string name="managed_profile_contact_search_title" msgid="7337225196804457095">"सम्पर्कको खोजी"</string>
     <string name="managed_profile_contact_search_summary" msgid="7278267480246726951">"कलर र सम्पर्कहरूको पहिचान गर्न तपाईँको संगठन अनुसार गरिने सम्पर्कका खोजीहरूलाई अनुमति दिनुहोस्"</string>
     <string name="cross_profile_calendar_title" msgid="2351605904015067145">"अन्तरप्रोफाइल पात्रो"</string>
@@ -4112,25 +4117,25 @@
     <string name="double_twist_for_camera_mode_title" msgid="2606032140297556018">"क्यामेरा फ्लिप गर्ने"</string>
     <string name="double_twist_for_camera_mode_summary" msgid="8979914206876018137"></string>
     <string name="double_twist_for_camera_suggestion_title" msgid="5932411386316771246">"अझ छिटो सेल्फी लिनुहोस्‌"</string>
-    <string name="swipe_up_to_switch_apps_summary" msgid="4644068184114154787">"अनुप्रयोगहरू बदल्न, गृह बटनमा माथि स्वाइप गर्नुहोस्। सबै अनुप्रयोगहरू हेर्न फेरि माथि स्वाइप गर्नुहोस्। कुनै पनि स्क्रिनबाट काम गर्छ। अब उप्रान्त तपाईंको स्क्रिनको तल्लो भागको दायाँमा परिदृश्य बटन हुने छैन।"</string>
+    <string name="swipe_up_to_switch_apps_summary" msgid="4644068184114154787">"एपहरू बदल्न, गृह बटनमा माथि स्वाइप गर्नुहोस्। सबै एपहरू हेर्न फेरि माथि स्वाइप गर्नुहोस्। कुनै पनि स्क्रिनबाट काम गर्छ। अब उप्रान्त तपाईंको स्क्रिनको तल्लो भागको दायाँमा परिदृश्य बटन हुने छैन।"</string>
     <string name="swipe_up_to_switch_apps_suggestion_title" msgid="7641846365137536128">"नयाँ गृह बटन प्रयास गर्नुहोस्‌"</string>
-    <string name="swipe_up_to_switch_apps_suggestion_summary" msgid="7338653224520387852">"अनुप्रयोगहरू बदल्न नयाँ इसारा सक्रिय गर्नुहोस्‌"</string>
+    <string name="swipe_up_to_switch_apps_suggestion_summary" msgid="7338653224520387852">"एपहरू बदल्न नयाँ इसारा सक्रिय गर्नुहोस्‌"</string>
     <string name="ambient_display_title" product="default" msgid="6785677099744344088">"फोनको जाँच गर्न डबल-ट्याप गर्नुहोस्"</string>
     <string name="ambient_display_title" product="tablet" msgid="1106285490888683613">"ट्याब्लेटको जाँच गर्न डबल-ट्याप गर्नुहोस्"</string>
     <string name="ambient_display_title" product="device" msgid="5064644474876041478">"यन्त्रको जाँच गर्न डबल-ट्याप गर्नुहोस्"</string>
-    <string name="ambient_display_summary" msgid="4882910328216411109">"समय, सूचना र अन्य जानकारीको जाँच गर्न आफ्नो यन्त्रको स्क्रिनमा डबल ट्याप गर्नुहोस्।"</string>
+    <string name="ambient_display_summary" msgid="4882910328216411109">"समय, सूचना र अन्य जानकारी हेर्न आफ्नो यन्त्रको स्क्रिनमा डबल ट्याप गर्नुहोस्।"</string>
     <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"फोनको जाँच गर्न उठाउनुहोस्"</string>
     <string name="ambient_display_pickup_title" product="tablet" msgid="1555456400210301959">"ट्याब्लेटको जाँच गर्न उठाउनुहोस्"</string>
     <string name="ambient_display_pickup_title" product="device" msgid="2480126522988135037">"यन्त्रको जाँच गर्न उठाउनुहोस्"</string>
     <string name="ambient_display_wake_screen_title" msgid="3376988352851077102">"सञ्चालन गर्नका लागि डिस्प्ले"</string>
-    <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"समय, सूचना र अन्य जानकारीको जाँच गर्न आफ्नो फोन उठाउनुहोस्।"</string>
-    <string name="ambient_display_pickup_summary" product="tablet" msgid="1077745287100012928">"समय, सूचना र अन्य जानकारीको जाँच गर्न आफ्नो ट्याब्लेट उठाउनुहोस्।"</string>
-    <string name="ambient_display_pickup_summary" product="device" msgid="404199660076598026">"समय, सूचना तथा अन्य जानकारीको जाँच गर्न आफ्नो यन्त्र उठाउनुहोस्।"</string>
+    <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"समय, सूचना र अन्य जानकारी हेर्न आफ्नो फोन उठाउनुहोस्।"</string>
+    <string name="ambient_display_pickup_summary" product="tablet" msgid="1077745287100012928">"समय, सूचना र अन्य जानकारी हेर्न आफ्नो ट्याब्लेट उठाउनुहोस्।"</string>
+    <string name="ambient_display_pickup_summary" product="device" msgid="404199660076598026">"समय, सूचना तथा अन्य जानकारी हेर्न आफ्नो यन्त्र उठाउनुहोस्।"</string>
     <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"फोनको जाँच गर्न ट्याप गर्नुहोस्"</string>
     <string name="ambient_display_tap_screen_title" product="tablet" msgid="6434521782016864148">"ट्याब्लेटको जाँच गर्न ट्याप गर्नुहोस्"</string>
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"यन्त्रको जाँच गर्न ट्याप गर्नुहोस्"</string>
-    <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"समय, सूचना र अन्य जानकारीको जाँच गर्न आफ्नो यन्त्रको स्क्रिनमा ट्याप गर्नुहोस्।"</string>
-    <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"सूचनाहरू प्राप्त गर्न फिंगरप्रिन्ट स्वाइप गर्नुहोस्"</string>
+    <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"समय, सूचना र अन्य जानकारी हेर्न आफ्नो यन्त्रको स्क्रिनमा ट्याप गर्नुहोस्।"</string>
+    <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"सूचनाहरू हेर्न फिंगरप्रिन्ट स्वाइप गर्नुहोस्"</string>
     <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"फिंगरप्रिन्ट स्वाइप गर्नु"</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"अफ्ना सूचनाहरूको जाँच गर्न आफ्नो फोनको पछाडिको भागमा रहेको फिंगरप्रिन्ट सेन्सरमा तलतिर स्वाइप गर्नुहोस्।"</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="tablet" msgid="3480057984564476283">"अफ्ना सूचनाहरूको जाँच गर्न आफ्नो ट्याब्लेटको पछाडिको भागमा रहेको फिंगरप्रिन्ट सेन्सरमा तलतिर स्वाइप गर्नुहोस्।"</string>
@@ -4144,18 +4149,18 @@
     <string name="oem_unlock_enable_disabled_summary_sim_locked_device" msgid="5223278198179877704">"वाहकद्वारा लक गरिएका यन्त्रहरूमा उपलब्ध छैन"</string>
     <string name="oem_lock_info_message" msgid="5090850412279403901">"यन्त्रको सुरक्षासम्बन्धी सुविधा सक्षम पार्न कृपया यन्त्र पुनः सुरु गर्नुहोस्।"</string>
     <string name="automatic_storage_manager_freed_bytes" msgid="7360443072390107772">"कुल उपलब्ध गराइएको <xliff:g id="SIZE">%1$s</xliff:g>\n\nपछिल्लो पटक <xliff:g id="DATE">%2$s</xliff:g> मा सञ्चालन गरिएको"</string>
-    <string name="web_action_enable_title" msgid="4462106633708675959">"तात्कालिक अनुप्रयोगहरू"</string>
+    <string name="web_action_enable_title" msgid="4462106633708675959">"तात्कालिक एपहरू"</string>
     <string name="web_action_enable_summary" msgid="1729016644691793085">"अनुप्रयोगहरूको स्थापना नगरिए तापनि लिंकहरूलाई तिनीहरूमा खोल्नुहोस्"</string>
-    <string name="web_action_section_title" msgid="5563229447734734662">"तात्कालिक अनुप्रयोगहरू"</string>
+    <string name="web_action_section_title" msgid="5563229447734734662">"तात्कालिक एपहरू"</string>
     <string name="instant_apps_settings" msgid="879003203555847537">"तात्कालिक अनुप्रयोगका प्राथमिकताहरू"</string>
-    <string name="domain_url_section_title" msgid="206403507921518321">"स्थापना गरिएका अनुप्रयोगहरू"</string>
+    <string name="domain_url_section_title" msgid="206403507921518321">"स्थापना गरिएका एपहरू"</string>
     <string name="automatic_storage_manager_activation_warning" msgid="2630083316417707308">"तपाईंको भण्डारण अहिले भण्डारण प्रबन्धकद्वारा व्यवस्थापन भइरहेको छ"</string>
     <string name="account_for_section_header" msgid="5975241715840642563">"<xliff:g id="USER_NAME">%1$s</xliff:g> का खाताहरू"</string>
     <string name="configure_section_header" msgid="6988981883075615136">"कन्फिगर गर्नुहोस्"</string>
     <string name="auto_sync_account_title" msgid="2394463123733529506">"स्वत: डेटा सिंक गर्नुहोस्"</string>
     <string name="auto_sync_personal_account_title" msgid="6844465157916100655">"व्यक्तिगत डेटा स्वत: सिंक गर्नुहोस्"</string>
     <string name="auto_sync_work_account_title" msgid="2403222633447522376">"कार्य सम्बन्धी डेटा स्वत: सिंक गर्नुहोस्"</string>
-    <string name="auto_sync_account_summary" msgid="6316230976974033772">"अनुप्रयोगहरूलाई स्वत: डेटालाई ताजा पार्न दिनुहोस्"</string>
+    <string name="auto_sync_account_summary" msgid="6316230976974033772">"अनुप्रयोगहरूलाई स्वत: डेटा रिफ्रेस गर्न दिनुहोस्"</string>
     <string name="account_sync_title" msgid="1570164819114297154">"खाताको सिंक"</string>
     <string name="account_sync_summary_some_on" msgid="1934556869158274053">"<xliff:g id="ID_2">%2$d</xliff:g> मध्ये <xliff:g id="ID_1">%1$d</xliff:g> वस्तुहरूका लागि सिंक गर्ने सेवा सक्रिय छ"</string>
     <string name="account_sync_summary_all_on" msgid="3634161204232431700">"सबै वस्तुहरूका लागि सिंक गर्ने सेवा सक्रिय छ"</string>
@@ -4174,19 +4179,19 @@
     <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 Store भन्दा बाहिरबाट स्थापना गरिएका अनुप्रयोगहरूलाई यसले नसमेट्न सक्छ।"</string>
+    <string name="enterprise_privacy_enterprise_installed_packages" msgid="6575025134782391212">"एपहरू स्थापना गरियो"</string>
+    <string name="enterprise_privacy_apps_count_estimation_info" msgid="5020730108878608500">"एपको संख्या अनुमानित हो। Play Store भन्दा बाहिरबाट स्थापना गरिएका अनुप्रयोगहरूलाई यसले नसमेट्न सक्छ।"</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>
+      <item quantity="other">न्यूनतम <xliff:g id="COUNT_1">%d</xliff:g> एप</item>
+      <item quantity="one">न्यूनतम <xliff:g id="COUNT_0">%d</xliff:g> एप</item>
     </plurals>
     <string name="enterprise_privacy_location_access" msgid="110406267468274216">"स्थानसम्बन्धी अनुमतिहरू"</string>
     <string name="enterprise_privacy_microphone_access" msgid="4586428105675460207">"माइक्रोफोनसम्बन्धी अनुमतिहरू"</string>
     <string name="enterprise_privacy_camera_access" msgid="2366392786153103482">"क्यामेरा सम्बन्धी अनुमतिहरू"</string>
-    <string name="enterprise_privacy_enterprise_set_default_apps" msgid="6142937923758931242">"पूर्वनिर्धारित अनुप्रयोगहरू"</string>
+    <string name="enterprise_privacy_enterprise_set_default_apps" msgid="6142937923758931242">"पूर्वनिर्धारित एपहरू"</string>
     <plurals name="enterprise_privacy_number_packages" formatted="false" msgid="1480745164313890415">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> अनुप्रयोगहरू</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> अनुप्रयोग</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> एपहरू</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> एप</item>
     </plurals>
     <string name="enterprise_privacy_input_method" msgid="5885916325874284011">"पूर्वनिर्धारित किबोर्ड"</string>
     <string name="enterprise_privacy_input_method_name" msgid="439610095825218563">"<xliff:g id="APP_LABEL">%s</xliff:g> मा सेट गरिएको छ"</string>
@@ -4214,18 +4219,18 @@
     <string name="do_disclosure_learn_more_separator" msgid="702345537118848010">" "</string>
     <string name="learn_more" msgid="6844160787130206258">"थप जान्नुहोस्"</string>
     <plurals name="default_camera_app_title" formatted="false" msgid="8762954032197483848">
-      <item quantity="other">क्यामेरा अनुप्रयोगहरू</item>
+      <item quantity="other">क्यामेरा एपहरू</item>
       <item quantity="one">क्यामेरा अनुप्रयोग</item>
     </plurals>
-    <string name="default_calendar_app_title" msgid="6484001237347739255">"पात्रो अनुप्रयोग"</string>
-    <string name="default_contacts_app_title" msgid="1050372162465746272">"सम्पर्क अनुप्रयोग"</string>
+    <string name="default_calendar_app_title" msgid="6484001237347739255">"पात्रो एप"</string>
+    <string name="default_contacts_app_title" msgid="1050372162465746272">"सम्पर्क एप"</string>
     <plurals name="default_email_app_title" formatted="false" msgid="6875559046625447168">
-      <item quantity="other">इमेल क्लाइन्ट अनुप्रयोगहरू</item>
+      <item quantity="other">इमेल क्लाइन्ट एपहरू</item>
       <item quantity="one">इमेल क्लाइन्ट अनुप्रयोग</item>
     </plurals>
-    <string name="default_map_app_title" msgid="6919751358166607185">"नक्सा अनुप्रयोग"</string>
+    <string name="default_map_app_title" msgid="6919751358166607185">"नक्सा एप"</string>
     <plurals name="default_phone_app_title" formatted="false" msgid="7593838689002912108">
-      <item quantity="other">फोन अनुप्रयोगहरू</item>
+      <item quantity="other">फोन एपहरू</item>
       <item quantity="one">फोन अनुप्रयोग</item>
     </plurals>
     <string name="app_names_concatenation_template_2" msgid="8267577900046506189">"<xliff:g id="FIRST_APP_NAME">%1$s</xliff:g>, <xliff:g id="SECOND_APP_NAME">%2$s</xliff:g>"</string>
@@ -4233,13 +4238,13 @@
     <string name="storage_photos_videos" msgid="1890829312367477559">"तस्बिर र भिडियोहरू"</string>
     <string name="storage_music_audio" msgid="3661289086715297149">"सङ्गीत तथा अडियो"</string>
     <string name="storage_games" msgid="7740038143749092373">"खेलहरू"</string>
-    <string name="storage_other_apps" msgid="3202407095387420842">"अन्य अनुप्रयोगहरू"</string>
+    <string name="storage_other_apps" msgid="3202407095387420842">"अन्य एपहरू"</string>
     <string name="storage_files" msgid="2087824267937487880">"फाइलहरू"</string>
     <string name="storage_size_large_alternate" msgid="1317796542509105857">"<xliff:g id="NUMBER">^1</xliff:g>"<small>" "<font size="20">"<xliff:g id="UNIT">^2</xliff:g>"</font></small>""</string>
     <string name="storage_volume_total" msgid="5021484171514159913">"<xliff:g id="TOTAL">%1$s</xliff:g> मध्ये प्रयोग भएको"</string>
     <string name="storage_percent_full" msgid="6924662861545958442">"प्रयोग भयो"</string>
-    <string name="clear_instant_app_data" msgid="3673669086522890405">"अनुप्रयोगको डेटा खाली गर्नुहोस्"</string>
-    <string name="clear_instant_app_confirmation" msgid="1778553115373698061">"तपाईं यो तात्कालिक अनुप्रयोगलाई हटाउन चाहनुहुन्छ?"</string>
+    <string name="clear_instant_app_data" msgid="3673669086522890405">"एपको डेटा खाली गर्नुहोस्"</string>
+    <string name="clear_instant_app_confirmation" msgid="1778553115373698061">"तपाईं यो तात्कालिक एपलाई हटाउन चाहनुहुन्छ?"</string>
     <string name="launch_instant_app" msgid="5251693061228352333">"खोल्नुहोस्"</string>
     <string name="game_storage_settings" msgid="6856911551799175914">"खेलहरू"</string>
     <string name="audio_files_title" msgid="3073879661731363935">"अडियो फाइलहरू"</string>
@@ -4258,16 +4263,16 @@
     <string name="device_theme" msgid="8992291311481135893">"यन्त्रको विषयवस्तु"</string>
     <string name="default_theme" msgid="5986996377385956138">"पूर्वनिर्धारित"</string>
     <string name="show_operator_name_title" msgid="5056163028128447308">"नेटवर्कको नाम"</string>
-    <string name="show_operator_name_summary" msgid="6352180285743777497">"वस्तुस्थिति पट्टीमा नेटवर्कको नाम देखाउनुहोस्"</string>
+    <string name="show_operator_name_summary" msgid="6352180285743777497">"स्टाटस बारमा नेटवर्कको नाम देखाउनुहोस्"</string>
     <string name="storage_manager_indicator" msgid="4255140732848476875">"भण्डारणको प्रबन्धक: <xliff:g id="STATUS">^1</xliff:g>"</string>
     <string name="storage_manager_indicator_off" msgid="6404056007102580777">"निष्क्रिय"</string>
     <string name="storage_manager_indicator_on" msgid="5295306384982062320">"सक्रिय"</string>
-    <string name="install_type_instant" msgid="6248487669862821874">"तात्कालिक अनुप्रयोग"</string>
+    <string name="install_type_instant" msgid="6248487669862821874">"तात्कालिक एप"</string>
     <string name="automatic_storage_manager_deactivation_warning" msgid="7867793739491286374">"भण्डारण व्यवस्थापक निष्क्रिय पार्ने हो?"</string>
-    <string name="storage_movies_tv" msgid="7282484273991655296">"चलचित्र तथा TV अनुप्रयोगहरू"</string>
+    <string name="storage_movies_tv" msgid="7282484273991655296">"चलचित्र तथा टिभी एपहरू"</string>
     <string name="carrier_provisioning" msgid="3309125279191534469">"सेवा प्रदायकको प्रावधान सम्बन्धी जानकारी"</string>
     <string name="trigger_carrier_provisioning" msgid="6284005970057901477">"सेवा प्रदायकको प्रावधानलाई ट्रिगर गर्नुहोस्"</string>
-    <string name="zen_suggestion_title" msgid="2134699720214231950">"बाधा नपुर्‍याउनुहोस्‌ नामक सेवालाई अद्यावधिक गर्नुहोस्‌"</string>
+    <string name="zen_suggestion_title" msgid="2134699720214231950">"बाधा नपुर्‍याउनुहोस्‌ नामक सेवालाई अपडेट गर्नुहोस्‌"</string>
     <string name="zen_suggestion_summary" msgid="4041062903237952737">"केन्द्रित रहन सूचनाहरू पज गर्नुहोस्"</string>
     <string name="disabled_low_ram_device" msgid="4958060232123741721">"यस यन्त्रमा यो सुविधा उपलब्ध छैन"</string>
     <string name="disabled_feature" msgid="3747549387387702365">"यो सुविधा उपलब्ध छैन"</string>
@@ -4279,10 +4284,10 @@
     <string name="allow_background_activity_starts" msgid="6754016668813082728">"पृष्ठभूमिको क्रियाकलाप सुरु हुने अनुमति दिनुहोस्"</string>
     <string name="allow_background_activity_starts_summary" msgid="8170749270869606692">"पृष्ठभूमिका सबै क्रियाकलाप सुरु हुने अनुमति दिनुहोस्"</string>
     <string name="show_first_crash_dialog" msgid="3682063068903692710">"सधैँ क्र्याससम्बन्धी संवाद देखाउनुस्"</string>
-    <string name="show_first_crash_dialog_summary" msgid="8197987550025401754">"प्रत्येकपटक अनुप्रयोग क्र्यास हुँदा संवाद देखाउनुहोस्‌"</string>
-    <string name="angle_enabled_app" msgid="4359266182151708733">"कोण सक्षम पारिएको अनुप्रयोग चयन गर्नुहोस्"</string>
-    <string name="angle_enabled_app_not_set" msgid="7428910515748621910">"कोण सक्षम पारिएको कुनै पनि अनुप्रयोग सेट गरिएको छैन"</string>
-    <string name="angle_enabled_app_set" msgid="7313088703610569320">"कोण सक्षम पारिएको अनुप्रयोग: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="show_first_crash_dialog_summary" msgid="8197987550025401754">"प्रत्येकपटक एप क्र्यास हुँदा संवाद देखाउनुहोस्‌"</string>
+    <string name="angle_enabled_app" msgid="4359266182151708733">"कोण सक्षम पारिएको एप चयन गर्नुहोस्"</string>
+    <string name="angle_enabled_app_not_set" msgid="7428910515748621910">"कोण सक्षम पारिएको कुनै पनि एप सेट गरिएको छैन"</string>
+    <string name="angle_enabled_app_set" msgid="7313088703610569320">"कोण सक्षम पारिएको एप: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="game_driver_dashboard_title" msgid="219443350404091201">"गेम ड्राइभरका प्राथमिकताहरू"</string>
     <string name="game_driver_dashboard_summary" msgid="1500674075618790528">"गेम ड्राइभरका सेटिङहरू परिमार्जन गर्नुहोस्"</string>
     <string name="game_driver_footer_text" msgid="1540158284161797913">"गेम ड्राइभर सक्रिय गरिँदा, तपाईं यस यन्त्रमा स्थापना गरिएका अनुप्रयोगहरूका हकमा अद्यावधिक गरिएको ग्राफिक्स ड्राइभर प्रयोग गर्ने विकल्प छनौट गर्न सक्नुहुन्छ।"</string>
@@ -4303,8 +4308,8 @@
     <string name="my_device_info_account_preference_title" msgid="7965847995028952373">"खाता"</string>
     <string name="my_device_info_device_name_preference_title" msgid="7384446683248009296">"यन्त्रको नाम"</string>
     <string name="change_wifi_state_title" msgid="5140754955787584174">"Wi-Fi को नियन्त्रण"</string>
-    <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"अनुप्रयोगलाई Wi-Fi नियन्त्रण गर्ने अनुमति दिनुहोस्"</string>
-    <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"यो अनुप्रयोगलाई Wi-Fi सक्रिय गर्ने वा निष्क्रिय पार्ने अनुमति दिनुहोस्, स्क्यान गरी Wi-Fi नेटवर्कमा जडान गर्नुहोस्, नेटवर्कहरू थप्नुहोस् वा हटाउनुहोस्, वा स्थानीय रूपमा मात्र प्रयोग गर्न मिल्ने हटस्पट सुरु गर्नुहोस्"</string>
+    <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"एपलाई Wi-Fi नियन्त्रण गर्ने अनुमति दिनुहोस्"</string>
+    <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"यो एपलाई Wi-Fi सक्रिय गर्ने वा निष्क्रिय पार्ने अनुमति दिनुहोस्, स्क्यान गरी Wi-Fi नेटवर्कमा जडान गर्नुहोस्, नेटवर्कहरू थप्नुहोस् वा हटाउनुहोस्, वा स्थानीय रूपमा मात्र प्रयोग गर्न मिल्ने हटस्पट सुरु गर्नुहोस्"</string>
     <string name="media_output_title" msgid="8710632337456601848">"मिडिया यसमा प्ले गर्नुहोस्"</string>
     <string name="media_output_default_summary" msgid="3159237976830415584">"यो यन्त्र"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"फोन"</string>
@@ -4318,7 +4323,7 @@
     <string name="battery_suggestion_title" product="device" msgid="765005476863631528">"यन्त्रको ब्याट्रीको आयुमा सुधार गर्नुहोस्"</string>
     <string name="battery_suggestion_title" product="default" msgid="3295786171830183688">"फोनको ब्याट्रीको आयुमा सुधार गर्नुहोस्"</string>
     <string name="battery_suggestion_summary" msgid="2669070349482656490"></string>
-    <string name="gesture_prevent_ringing_screen_title" msgid="4173494225145223638">"घन्टी बज्नबाट रोक्नुहोस्‌"</string>
+    <string name="gesture_prevent_ringing_screen_title" msgid="4173494225145223638">"घन्टी बज्न नदिनुहोस्‌"</string>
     <string name="gesture_prevent_ringing_title" msgid="8827963588425673557">"पावर तथा भोल्युम बढाउने बटन एकैपटक थिच्नुहोस्‌"</string>
     <string name="gesture_prevent_ringing_sound_title" msgid="8642330448721033641">"घन्टी बज्ने कार्य रोक्न सर्टकट"</string>
     <string name="prevent_ringing_option_vibrate" msgid="6456505293904544108">"कम्पन"</string>
@@ -4327,8 +4332,8 @@
     <string name="prevent_ringing_option_vibrate_summary" msgid="7961818570574683926">"सक्रिय (कम्पन)"</string>
     <string name="prevent_ringing_option_mute_summary" msgid="3509459199090688328">"सक्रिय (म्युट)"</string>
     <string name="prevent_ringing_option_none_summary" msgid="5152618221093037451">"निष्क्रिय"</string>
-    <string name="pref_title_network_details" msgid="3971074015034595956">"नेटवर्कसम्बन्धी विवरणहरू"</string>
-    <string name="about_phone_device_name_warning" msgid="9088572775969880106">"तपाईंको फोनमा रहेका अनुप्रयोगहरूले तपाईंको यन्त्रको नाम देख्न सक्छन्। तपाईंले ब्लुटुथ यन्त्रहरूमा जडान गर्दा वा कुनै Wi-Fi हटस्पट सेटअप गर्दा अरू मान्छेहरू पनि यसलाई देख्न सक्छन्।"</string>
+    <string name="pref_title_network_details" msgid="3971074015034595956">"नेटवर्कको विवरण"</string>
+    <string name="about_phone_device_name_warning" msgid="9088572775969880106">"तपाईंको फोनमा रहेका एपहरूले तपाईंको यन्त्रको नाम देख्न सक्छन्। तपाईंले ब्लुटुथ यन्त्रहरूमा जडान गर्दा वा कुनै Wi-Fi हटस्पट सेटअप गर्दा अरू मान्छेहरू पनि यसलाई देख्न सक्छन्।"</string>
     <string name="devices_title" msgid="4768432575951993648">"यन्त्रहरू"</string>
     <string name="homepage_all_settings" msgid="3201220879559136116">"सबै सेटिङहरू"</string>
     <string name="homepage_personal_settings" msgid="7472638597249114564">"सुझावहरू"</string>
@@ -4436,7 +4441,7 @@
     <string name="register_automatically" msgid="1858081641661493109">"स्वतः दर्ता…"</string>
     <string name="roaming_alert_title" msgid="1849237823113454475">"डेटा रोमिङलाई अनुमति दिने हो?"</string>
     <string name="roaming_check_price_warning" msgid="5883499714594419439">"मूल्यसम्बन्धी जानकारीका लागि आफ्नो नेटवर्क प्रदायकलाई सोध्नुहोस्।"</string>
-    <string name="mobile_data_usage_title" msgid="2376358672434990037">"अनुप्रयोगको डेटाको प्रयोग"</string>
+    <string name="mobile_data_usage_title" msgid="2376358672434990037">"एपको डेटाको प्रयोग"</string>
     <string name="mobile_network_mode_error" msgid="6818434186286086554">"अमान्य नेटवर्क मोड <xliff:g id="NETWORKMODEID">%1$d</xliff:g>। बेवास्ता गर्नुहोस्।"</string>
     <string name="mobile_network_apn_title" msgid="5628635067747404382">"एक्सेस पोइन्ट नामहरू"</string>
     <string name="manual_mode_disallowed_summary" msgid="799800630000340665">"<xliff:g id="CARRIER">%1$s</xliff:g> मा जडान हुँदा उपलब्ध छैन"</string>
@@ -4481,22 +4486,22 @@
     <string name="permission_bar_chart_title" msgid="874145405516650073">"पछिल्लो २४ घन्टामा गरिएको अनुमतिको प्रयोग"</string>
     <string name="permission_bar_chart_details" msgid="942094334321073927">"ड्यासबोर्डमा सबै कुरा हेर्नुहोस्"</string>
     <plurals name="permission_bar_chart_label" formatted="false" msgid="2831305719356562097">
-      <item quantity="other"><xliff:g id="NUMBER">%s</xliff:g> अनुप्रयोगहरू</item>
-      <item quantity="one">१ अनुप्रयोग</item>
+      <item quantity="other"><xliff:g id="NUMBER">%s</xliff:g> एपहरू</item>
+      <item quantity="one">१ एप</item>
     </plurals>
     <string name="accessibility_usage_title" msgid="3920601240120963611">"पहुँचसम्बन्धी सेवाहरूको प्रयोग"</string>
     <plurals name="accessibility_usage_summary" formatted="false" msgid="2604152087205501644">
-      <item quantity="other"><xliff:g id="SERVICE_COUNT">%1$d</xliff:g> अनुप्रयोगहरूले तपाईंको यन्त्रमाथि पूर्ण रूपमा पहुँच राख्न सक्छन्</item>
+      <item quantity="other"><xliff:g id="SERVICE_COUNT">%1$d</xliff:g> एपहरूले तपाईंको यन्त्रमाथि पूर्ण रूपमा पहुँच राख्न सक्छन्</item>
       <item quantity="one">१ अनुप्रयोगले तपाईंको यन्त्रमाथि पूर्ण रूपमा पहुँच राख्न सक्छ</item>
     </plurals>
     <string name="manage_app_notification" msgid="9072118910762792295">"<xliff:g id="APP_NAME">%1$s</xliff:g> सम्बन्धी सूचनाहरूको व्यवस्थापन गर्नुहोस्"</string>
-    <string name="no_suggested_app" msgid="509257628685025383">"सिफारिस गरिएको कुनै पनि अनुप्रयोग छैन"</string>
+    <string name="no_suggested_app" msgid="509257628685025383">"सिफारिस गरिएको कुनै पनि एप छैन"</string>
     <plurals name="notification_few_channel_count_summary" formatted="false" msgid="5165639207390218085">
       <item quantity="other">सूचनाका <xliff:g id="NOTIFICATION_CHANNEL_COUNT_1">%1$d</xliff:g> च्यानलहरू।</item>
       <item quantity="one">सूचनाको <xliff:g id="NOTIFICATION_CHANNEL_COUNT_0">%1$d</xliff:g> च्यानल।</item>
     </plurals>
     <string name="notification_many_channel_count_summary" msgid="9205641731142529086">"सूचनाका <xliff:g id="NOTIFICATION_CHANNEL_COUNT">%1$d</xliff:g> च्यानलहरू। सबैको व्यवस्थापन गर्न ट्याप गर्नुहोस्।"</string>
-    <string name="recently_installed_app" msgid="6491959945747808096">"तपाईंले हालसालै यो अनुप्रयोग स्थापना गर्नुभयो।"</string>
+    <string name="recently_installed_app" msgid="6491959945747808096">"तपाईंले हालसालै यो एप स्थापना गर्नुभयो।"</string>
     <string name="media_output_panel_title" msgid="8429272102437211530">"आउटपुट बदल्नुहोस्"</string>
     <string name="media_output_panel_summary_of_playing_device" msgid="7425231720911606911">"हाल <xliff:g id="DEVICE_NAME">%1$s</xliff:g> मा प्ले भइरहेको"</string>
     <string name="wfc_disclaimer_title_text" msgid="3245793509743182243">"महत्त्वपूर्ण जानकारी"</string>
diff --git a/tests/CarDeveloperOptions/res/values-nl/arrays.xml b/tests/CarDeveloperOptions/res/values-nl/arrays.xml
index bb696eb..0e77dbd 100644
--- a/tests/CarDeveloperOptions/res/values-nl/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-nl/arrays.xml
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"Nooit toestaan"</item>
     <item msgid="8184570120217958741">"Altijd toestaan"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normaal"</item>
+    <item msgid="5101233285497327432">"Gemiddeld"</item>
+    <item msgid="1555861583162930714">"Laag"</item>
+    <item msgid="1719683776264798117">"Kritiek"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normaal"</item>
+    <item msgid="6107138933849816768">"Gemiddeld"</item>
+    <item msgid="182695359839047859">"Laag"</item>
+    <item msgid="8577246509202964244">"Kritiek"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Permanent"</item>
     <item msgid="167418068739176448">"Topactiviteit"</item>
diff --git a/tests/CarDeveloperOptions/res/values-nl/config.xml b/tests/CarDeveloperOptions/res/values-nl/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-nl/config.xml
+++ b/tests/CarDeveloperOptions/res/values-nl/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-nl/strings.xml b/tests/CarDeveloperOptions/res/values-nl/strings.xml
index 8d5a612..a901631 100644
--- a/tests/CarDeveloperOptions/res/values-nl/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-nl/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Maak de tekst op het scherm kleiner of groter."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Verkleinen"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Vergroten"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Voorbeeldtekst"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"De tovenaar van Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Hoofdstuk 11: De prachtige Smaragden Stad van Oz"</string>
@@ -128,7 +127,7 @@
     <string name="bluetooth_notif_title" msgid="5090288898529286011">"Koppelingsverzoek"</string>
     <string name="bluetooth_notif_message" msgid="6612367890895077938">"Tik om te koppelen met <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="bluetooth_show_received_files" msgid="5060846395852236652">"Ontvangen bestanden"</string>
-    <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"Bestanden ontvangen via Bluetooth"</string>
+    <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"Bestanden ontvangen via bluetooth"</string>
     <string name="device_picker" msgid="8345264486071697705">"Bluetooth-apparaat kiezen"</string>
     <string name="bluetooth_ask_enablement" msgid="8716802066127746062">"<xliff:g id="APP_NAME">%1$s</xliff:g> wil Bluetooth inschakelen"</string>
     <string name="bluetooth_ask_disablement" msgid="7125319551097350783">"<xliff:g id="APP_NAME">%1$s</xliff:g> wil Bluetooth uitschakelen"</string>
@@ -209,7 +208,7 @@
     <string name="proxy_error_empty_host_set_port" msgid="8471455809508588255">"Het poortveld moet leeg zijn als het hostveld leeg is."</string>
     <string name="proxy_error_invalid_port" msgid="4046559920586100637">"De poort die je hebt ingevoerd, is ongeldig."</string>
     <string name="proxy_warning_limited_support" msgid="9026539134219095768">"De HTTP-proxy wordt gebruikt door de browser, maar mogelijk niet door de andere apps."</string>
-    <string name="proxy_url_title" msgid="882042361706435904">"PAC URL: "</string>
+    <string name="proxy_url_title" msgid="882042361706435904">"PAC-URL: "</string>
     <string name="radio_info_dl_kbps" msgid="2903778264453410272">"DL-bandbreedte (kbps):"</string>
     <string name="radio_info_ul_kbps" msgid="3802245899811732716">"UL-bandbreedte (kbps):"</string>
     <string name="radio_info_signal_location_label" msgid="6788144906873498013">"Mobiele locatiegegevens (beëindigd):"</string>
@@ -356,7 +355,7 @@
     <string name="security_enable_widgets_title" msgid="1701510007926738088">"Widgets inschakelen"</string>
     <string name="security_enable_widgets_disabled_summary" msgid="4408176087132339331">"Uitgeschakeld door beheerder"</string>
     <string name="lockdown_settings_title" msgid="4534779922580115990">"Lockdown-optie weergeven"</string>
-    <string name="lockdown_settings_summary" msgid="7270756909878256174">"Optie voor aan/uit-knop weergeven waarmee Smart Lock, ontgrendeling via vingerafdruk en meldingen op het vergrendelingsscherm worden uitgeschakeld."</string>
+    <string name="lockdown_settings_summary" msgid="7270756909878256174">"Optie voor aan/uit-knop weergeven waarmee Smart Lock, ontgrendeling via vingerafdruk en meldingen op het vergrendelscherm worden uitgeschakeld."</string>
     <string name="trust_agents_extend_unlock_title" msgid="3582017561316089951">"Ontgrendelen verlengen voor trust agents"</string>
     <string name="trust_agents_extend_unlock_summary" msgid="3543997596586078084">"Indien ingeschakeld houden trust agents je apparaat langer ontgrendeld, maar hiermee kan een vergrendeld apparaat niet meer worden ontgrendeld."</string>
     <string name="trust_lost_locks_screen_title" msgid="3094736590690459372">"Scherm vergr. als vertrouwen kwijt is"</string>
@@ -365,7 +364,7 @@
     <string name="owner_info_settings_status" msgid="8049975536717685126">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="COUNT_1">%2$d</xliff:g>"</string>
     <string name="owner_info_settings_edit_text_hint" msgid="2250029417257939706">"Bijvoorbeeld \'Android van Jan\'."</string>
     <string name="user_info_settings_title" msgid="1125111518759995748">"Gebruikersgegevens"</string>
-    <string name="show_profile_info_on_lockscreen_label" msgid="5204282771893683026">"Profielinfo weergeven op vergrendelingsscherm"</string>
+    <string name="show_profile_info_on_lockscreen_label" msgid="5204282771893683026">"Profielinfo weergeven op vergrendelscherm"</string>
     <string name="profile_info_settings_title" msgid="4855892878512562551">"Profielinfo"</string>
     <string name="Accounts_settings_title" msgid="7901374987121953746">"Accounts"</string>
     <string name="location_settings_title" msgid="2707201457572301030">"Locatie"</string>
@@ -383,7 +382,7 @@
     <string name="decryption_settings_summary" product="default" msgid="7401802133199522441">"Telefoon niet gecodeerd"</string>
     <string name="encryption_and_credential_settings_summary" product="tablet" msgid="8170667308598998791">"Apparaat versleuteld"</string>
     <string name="decryption_settings_summary" product="tablet" msgid="7524119945312453569">"Apparaat niet gecodeerd"</string>
-    <string name="lockscreen_settings_title" msgid="1221505938891948413">"Weergave op vergrendelingsscherm"</string>
+    <string name="lockscreen_settings_title" msgid="1221505938891948413">"Weergave op vergrendelscherm"</string>
     <string name="lockscreen_settings_what_to_show_category" msgid="3133378945821488654">"Wat wordt weergegeven"</string>
     <string name="security_settings_summary" msgid="5210109100643223686">"\'Mijn locatie\', schermontgrendeling, sim- en certificaatopslagvergrendeling instellen"</string>
     <string name="cdma_security_settings_summary" msgid="1783066617800041869">"\'Mijn locatie\' instellen, scherm ontgrendelen, certificaatopslag vergrendelen"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Moet minder dan <xliff:g id="NUMBER_1">%d</xliff:g> cijfers bevatten</item>
       <item quantity="one">Moet minder dan <xliff:g id="NUMBER_0">%d</xliff:g> cijfer bevatten</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Mag alleen de cijfers 0-9 bevatten"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Apparaatbeheer staat het gebruik van een recente pincode niet toe"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Veelvoorkomende pincodes worden geblokkeerd door je IT-beheerder. Probeer een andere pincode."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Mag geen ongeldig teken bevatten"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Moet ten minste <xliff:g id="COUNT">%d</xliff:g> tekens bevatten die geen letters zijn</item>
       <item quantity="one">Moet ten minste één teken bevatten dat geen letter is</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Moet ten minste <xliff:g id="COUNT">%d</xliff:g> niet-numerieke tekens bevatten</item>
+      <item quantity="one">Moet ten minste 1 niet-numeriek teken bevatten</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Apparaatbeheer staat het gebruik van een recent wachtwoord niet toe"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Veelvoorkomende wachtwoorden worden geblokkeerd door je IT-beheerder. Probeer een ander wachtwoord."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Een oplopende, aflopende of herhaalde reeks cijfers is niet toegestaan"</string>
@@ -752,7 +754,7 @@
     <string name="bluetooth_pairing_dialog_title" msgid="7900515495932064945">"Koppelen met dit apparaat?"</string>
     <string name="bluetooth_pairing_dialog_sharing_phonebook_title" msgid="7395493311980018460">"Telefoonboek delen?"</string>
     <string name="bluetooth_pairing_dialog_contants_request" msgid="2103132762434487717">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> wil toegang tot je contacten en gespreksgeschiedenis."</string>
-    <string name="bluetooth_pairing_dialog_paring_request" msgid="5513953935086446387">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> wil koppelen via Bluetooth. Na verbinding heeft het toegang tot je contacten en gespreksgeschiedenis."</string>
+    <string name="bluetooth_pairing_dialog_paring_request" msgid="5513953935086446387">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> wil koppelen via bluetooth. Na verbinding heeft het toegang tot je contacten en gespreksgeschiedenis."</string>
     <string name="bluetooth_preference_found_media_devices" msgid="5748539613567836379">"Beschikbare apparaten"</string>
     <string name="bluetooth_preference_no_found_devices" msgid="4190090666412408576">"Geen apparaten beschikbaar"</string>
     <string name="bluetooth_device_context_connect" msgid="1812090541371432890">"Verbinden"</string>
@@ -763,8 +765,8 @@
     <string name="bluetooth_device_context_connect_advanced" msgid="423463405499392444">"Opties..."</string>
     <string name="bluetooth_menu_advanced" msgid="7566858513372603652">"Geavanceerd"</string>
     <string name="bluetooth_advanced_titlebar" msgid="6459469494039004784">"Geavanceerde Bluetooth"</string>
-    <string name="bluetooth_empty_list_bluetooth_off" msgid="6255367297830430459">"Als Bluetooth is ingeschakeld, kan je apparaat communiceren met andere Bluetooth-apparaten in de buurt."</string>
-    <string name="bluetooth_scanning_on_info_message" msgid="5460370815156050550">"Als Bluetooth is ingeschakeld, kan je apparaat communiceren met andere Bluetooth-apparaten in de buurt.\n\nApps en services kunnen nog steeds op elk gewenst moment naar apparaten in de buurt scannen om de apparaatfunctionaliteit te verbeteren, zelfs als Bluetooth is uitgeschakeld. Dit kan worden gebruikt om bijvoorbeeld locatiegebaseerde functies en services te verbeteren. Je kunt dit wijzigen in de "<annotation id="link">"scaninstellingen"</annotation>"."</string>
+    <string name="bluetooth_empty_list_bluetooth_off" msgid="6255367297830430459">"Als bluetooth is ingeschakeld, kan je apparaat communiceren met andere bluetooth-apparaten in de buurt."</string>
+    <string name="bluetooth_scanning_on_info_message" msgid="5460370815156050550">"Als bluetooth is ingeschakeld, kan je apparaat communiceren met andere bluetooth-apparaten in de buurt.\n\nApps en services kunnen nog steeds op elk gewenst moment naar apparaten in de buurt scannen om de apparaatfunctionaliteit te verbeteren, zelfs als bluetooth is uitgeschakeld. Dit kan worden gebruikt om bijvoorbeeld locatiegebaseerde functies en services te verbeteren. Je kunt dit wijzigen in de "<annotation id="link">"scaninstellingen"</annotation>"."</string>
     <string name="ble_scan_notify_text" msgid="6290170236546386932">"Systeem-apps en -services kunnen nog steeds Bluetooth-apparaten detecteren om de nauwkeurigheid van locaties te verbeteren. Je kunt dit wijzigen in de <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>instellingen voor scannen<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
     <string name="bluetooth_connect_failed" msgid="1151234676456333786">"Kan geen verbinding maken. Probeer het opnieuw."</string>
     <string name="device_details_title" msgid="726517818032923222">"Apparaatgegevens"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wifi"</item>
+    <item msgid="2271962426654621656">"Mobiel"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Mobiel netwerk gebruiken als er geef wifi beschikbaar is"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Gebruik wifi als er geen mobiel netwerk beschikbaar is"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Bellen via wifi. Zonder wifi-signaal wordt het gesprek beëindigd."</string>
@@ -1340,7 +1345,7 @@
     <string name="scanning_status_text_wifi_on_ble_on" msgid="6370507836346838473">"Zowel wifi-scannen als Bluetooth-scannen zijn ingeschakeld"</string>
     <string name="scanning_status_text_wifi_on_ble_off" msgid="8205014713732412608">"Wifi-scannen is ingeschakeld en Bluetooth-scannen is uitgeschakeld"</string>
     <string name="scanning_status_text_wifi_off_ble_on" msgid="7400522456303307057">"Bluetooth-scannen is ingeschakeld en wifi-scannen is uitgeschakeld"</string>
-    <string name="scanning_status_text_wifi_off_ble_off" msgid="8575026386237481457">"Zowel wifi-scannen als Bluetooth-scannen zijn uitgeschakeld"</string>
+    <string name="scanning_status_text_wifi_off_ble_off" msgid="8575026386237481457">"Zowel wifi-scannen als bluetooth-scannen zijn uitgeschakeld"</string>
     <string name="status_meid_number" msgid="8756271256760479835">"MEID"</string>
     <string name="status_icc_id" msgid="9191847562997702709">"ICCID"</string>
     <string name="status_data_network_type" msgid="2344720457353394909">"Type mobiele-datanetwerk"</string>
@@ -1452,7 +1457,7 @@
     <string name="storage_detail_other" msgid="9164851767437306618">"Overige"</string>
     <string name="storage_detail_system" msgid="6784247618772153283">"Systeem"</string>
     <string name="storage_detail_explore" msgid="8206900269596580264">"<xliff:g id="NAME">^1</xliff:g> verkennen"</string>
-    <string name="storage_detail_dialog_other" msgid="5073511663616043370">"Overig omvat gedeelde bestanden die zijn opgeslagen door apps, bestanden die zijn gedownload van internet of via Bluetooth, Android-bestanden, enzovoort. \n\nAls je de zichtbare content van deze <xliff:g id="NAME">^1</xliff:g> wilt bekijken, tik je op Verkennen."</string>
+    <string name="storage_detail_dialog_other" msgid="5073511663616043370">"Overig omvat gedeelde bestanden die zijn opgeslagen door apps, bestanden die zijn gedownload van internet of via bluetooth, Android-bestanden, enzovoort. \n\nAls je de zichtbare content van deze <xliff:g id="NAME">^1</xliff:g> wilt bekijken, tik je op Verkennen."</string>
     <string name="storage_detail_dialog_system" msgid="1472572861360014226">"Systeem omvat bestanden die worden gebruikt om Android-versie <xliff:g id="VERSION">%s</xliff:g> uit te voeren"</string>
     <string name="storage_detail_dialog_user" msgid="1663117417635010371">"<xliff:g id="USER_0">^1</xliff:g> kan <xliff:g id="SIZE">^2</xliff:g> van de opslag hebben gebruikt voor foto\'s, muziek, apps of andere gegevens. \n\nSchakel over naar <xliff:g id="USER_1">^1</xliff:g> voor meer informatie."</string>
     <string name="storage_wizard_init_title" msgid="3407283236421089014">"Je <xliff:g id="NAME">^1</xliff:g> configureren"</string>
@@ -1553,7 +1558,7 @@
     <string name="menu_delete" msgid="8646081395424055735">"APN verwijderen"</string>
     <string name="menu_new" msgid="7529219814721969024">"Nieuwe APN"</string>
     <string name="menu_save" msgid="7310230314430623215">"Opslaan"</string>
-    <string name="menu_cancel" msgid="1292949233623397786">"Weggooien"</string>
+    <string name="menu_cancel" msgid="1292949233623397786">"Niet opslaan"</string>
     <string name="error_title" msgid="6595678722641187629"></string>
     <string name="error_name_empty" msgid="4638536651499727722">"Het veld \'Naam\' mag niet leeg zijn."</string>
     <string name="error_apn_empty" msgid="4849569239327147849">"De APN mag niet leeg zijn."</string>
@@ -1565,8 +1570,8 @@
     <string name="restore_default_apn_completed" msgid="5671734152740058937">"Herstellen van standaard-APN-instellingen voltooid."</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"Opties voor resetten"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"Netwerk, apps of apparaat kunnen worden gereset"</string>
-    <string name="reset_network_title" msgid="8944059136930806211">"Wifi, mobiel en Bluetooth resetten"</string>
-    <string name="reset_network_desc" msgid="4982633363916261109">"Hiermee worden alle netwerkinstellingen gereset, waaronder:\n\n"<li>"wifi"</li>\n<li>"mobiele data"</li>\n<li>"Bluetooth"</li></string>
+    <string name="reset_network_title" msgid="8944059136930806211">"Wifi, mobiel en bluetooth resetten"</string>
+    <string name="reset_network_desc" msgid="4982633363916261109">"Hiermee worden alle netwerkinstellingen gereset, waaronder:\n\n"<li>"wifi"</li>\n<li>"mobiele data"</li>\n<li>"bluetooth"</li></string>
     <string name="reset_esim_title" msgid="7630781767040831893">"Gedownloade simkaarten wissen"</string>
     <string name="reset_esim_desc" msgid="433226911566802">"Neem contact op met je provider als je vervangende simkaarten wilt downloaden. Hiermee worden geen mobiele abonnementen opgezegd."</string>
     <string name="reset_network_button_text" msgid="4293271046867912819">"Instellingen resetten"</string>
@@ -1619,9 +1624,9 @@
     <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"Internetverbinding van telefoon delen via USB"</string>
     <string name="usb_tethering_subtext" product="tablet" msgid="154536000235361034">"Internetverbinding van tablet delen via USB"</string>
     <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"Bluetooth-tethering"</string>
-    <string name="bluetooth_tethering_subtext" product="tablet" msgid="6868756914621131635">"Internetverbinding van deze tablet delen via Bluetooth"</string>
-    <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"Internetverbinding van deze telefoon delen via Bluetooth"</string>
-    <string name="bluetooth_tethering_off_subtext_config" msgid="3981528184780083266">"Internetverbinding van deze <xliff:g id="DEVICE_NAME">%1$d</xliff:g> delen via Bluetooth"</string>
+    <string name="bluetooth_tethering_subtext" product="tablet" msgid="6868756914621131635">"Internetverbinding van deze tablet delen via bluetooth"</string>
+    <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"Internetverbinding van deze telefoon delen via bluetooth"</string>
+    <string name="bluetooth_tethering_off_subtext_config" msgid="3981528184780083266">"Internetverbinding van deze <xliff:g id="DEVICE_NAME">%1$d</xliff:g> delen via bluetooth"</string>
     <string name="bluetooth_tethering_overflow_error" msgid="6946561351369376943">"Kan niet meer dan <xliff:g id="MAXCONNECTION">%1$d</xliff:g> apparaten tetheren."</string>
     <string name="bluetooth_untether_blank" msgid="5428300773782256084">"Tethering van <xliff:g id="DEVICE_NAME">%1$s</xliff:g> wordt opgeheven."</string>
     <string name="tethering_footer_info" msgid="8019555174339154124">"Gebruik hotspot en tethering om internet aan andere apparaten te leveren via je mobiele dataverbinding. Apps kunnen ook hotspots maken om content te delen met apparaten in de buurt."</string>
@@ -1651,15 +1656,15 @@
     </plurals>
     <string name="location_category_recent_location_access" msgid="286059523360285026">"Recente locatietoegang"</string>
     <string name="location_recent_location_access_view_details" msgid="2051602261436245905">"Details weergeven"</string>
-    <string name="location_no_recent_apps" msgid="77502059586413278">"Er zijn geen apps die je locatie onlangs hebben aangevraagd"</string>
+    <string name="location_no_recent_apps" msgid="77502059586413278">"Er zijn geen apps die je locatie onlangs hebben opgevraagd"</string>
     <string name="location_no_recent_accesses" msgid="6289916310397279890">"Er zijn geen apps die recent toegang hebben gehad tot je locatie"</string>
     <string name="location_high_battery_use" msgid="7177199869979522663">"Hoog accugebruik"</string>
     <string name="location_low_battery_use" msgid="5030448574501435888">"Laag batterijgebruik"</string>
-    <string name="location_scanning_screen_title" msgid="7663329319689413454">"Scannen via wifi en Bluetooth"</string>
+    <string name="location_scanning_screen_title" msgid="7663329319689413454">"Scannen via wifi en bluetooth"</string>
     <string name="location_scanning_wifi_always_scanning_title" msgid="6750542206763112172">"Wifi-scannen"</string>
     <string name="location_scanning_wifi_always_scanning_description" msgid="4956048135941851712">"Apps en services toestaan altijd te scannen naar wifi-netwerken in de buurt, zelfs als wifi is uitgeschakeld. Dit kan worden gebruikt om bijvoorbeeld locatiegebaseerde functies en services te verbeteren."</string>
     <string name="location_scanning_bluetooth_always_scanning_title" msgid="196241746742607453">"Bluetooth-scannen"</string>
-    <string name="location_scanning_bluetooth_always_scanning_description" msgid="3796673798637848690">"Apps en services toestaan altijd te scannen naar apparaten in de buurt, zelfs als Bluetooth is uitgeschakeld. Dit kan worden gebruikt om bijvoorbeeld locatiegebaseerde functies en services te verbeteren."</string>
+    <string name="location_scanning_bluetooth_always_scanning_description" msgid="3796673798637848690">"Apps en services toestaan altijd te scannen naar apparaten in de buurt, zelfs als bluetooth is uitgeschakeld. Dit kan worden gebruikt om bijvoorbeeld locatiegebaseerde functies en services te verbeteren."</string>
     <string name="managed_profile_location_services" msgid="224925483299159541">"Locatieservices voor het werk"</string>
     <string name="location_network_based" msgid="1535812159327454835">"Wifi en mobiele netwerklocatie"</string>
     <string name="location_neighborhood_level" msgid="8459352741296587916">"Apps toestaan de locatieservice van Google te gebruiken om je locatie sneller te schatten. Anonieme locatiegegevens worden verzameld en verzonden naar Google."</string>
@@ -1701,7 +1706,7 @@
     <string name="settings_safetylegal_activity_unreachable" msgid="3541894966476445833">"Je hebt geen gegevensverbinding. Als je deze informatie nu wilt weergeven, ga je op een computer met internetverbinding naar %s."</string>
     <string name="settings_safetylegal_activity_loading" msgid="7680998654145172">"Laden..."</string>
     <string name="confirm_device_credential_use_alternate_method" msgid="1279869272895739941">"Andere methode gebruiken"</string>
-    <string name="lockpassword_choose_your_screen_lock_header" msgid="6283518876031424798">"Stel je schermvergrendeling in"</string>
+    <string name="lockpassword_choose_your_screen_lock_header" msgid="6283518876031424798">"Schermvergrendeling instellen"</string>
     <string name="lockpassword_choose_your_password_message" msgid="2838273977481046536">"Stel een wachtwoord in voor betere beveiliging"</string>
     <string name="lockpassword_choose_your_password_header_for_fingerprint" msgid="4921343500484160894">"Stel wachtwoord in voor gebruik van vingerafdruk"</string>
     <string name="lockpassword_choose_your_pattern_header_for_fingerprint" msgid="314870151462139417">"Stel patroon in voor gebruik van vingerafdruk"</string>
@@ -2111,16 +2116,16 @@
     <string name="enable_quick_setting" msgid="1580451877998661255">"Weergeven in Snelle instellingen"</string>
     <string name="daltonizer_type" msgid="6890356081036026791">"Correctiemodus"</string>
     <plurals name="accessibilty_autoclick_preference_subtitle_extremely_short_delay" formatted="false" msgid="3810676455925024813">
-      <item quantity="other">Extreem korte vertraging (<xliff:g id="CLICK_DELAY_LABEL_1">%1$d</xliff:g> ms)</item>
-      <item quantity="one">Extreem korte vertraging (<xliff:g id="CLICK_DELAY_LABEL_0">%1$d</xliff:g> ms)</item>
+      <item quantity="other">Extreem kleine vertraging (<xliff:g id="CLICK_DELAY_LABEL_1">%1$d</xliff:g> ms)</item>
+      <item quantity="one">Extreem kleine vertraging (<xliff:g id="CLICK_DELAY_LABEL_0">%1$d</xliff:g> ms)</item>
     </plurals>
     <plurals name="accessibilty_autoclick_preference_subtitle_very_short_delay" formatted="false" msgid="8720846747098057703">
-      <item quantity="other">Zeer korte vertraging (<xliff:g id="CLICK_DELAY_LABEL_1">%1$d</xliff:g> ms)</item>
-      <item quantity="one">Zeer korte vertraging (<xliff:g id="CLICK_DELAY_LABEL_0">%1$d</xliff:g> ms)</item>
+      <item quantity="other">Zeer kleine vertraging (<xliff:g id="CLICK_DELAY_LABEL_1">%1$d</xliff:g> ms)</item>
+      <item quantity="one">Zeer kleine vertraging (<xliff:g id="CLICK_DELAY_LABEL_0">%1$d</xliff:g> ms)</item>
     </plurals>
     <plurals name="accessibilty_autoclick_preference_subtitle_short_delay" formatted="false" msgid="4311889107742293108">
-      <item quantity="other">Korte vertraging (<xliff:g id="CLICK_DELAY_LABEL_1">%1$d</xliff:g> ms)</item>
-      <item quantity="one">Korte vertraging (<xliff:g id="CLICK_DELAY_LABEL_0">%1$d</xliff:g> ms)</item>
+      <item quantity="other">Kleine vertraging (<xliff:g id="CLICK_DELAY_LABEL_1">%1$d</xliff:g> ms)</item>
+      <item quantity="one">Kleine vertraging (<xliff:g id="CLICK_DELAY_LABEL_0">%1$d</xliff:g> ms)</item>
     </plurals>
     <plurals name="accessibilty_autoclick_preference_subtitle_long_delay" formatted="false" msgid="285663535113656440">
       <item quantity="other">Lange vertraging (<xliff:g id="CLICK_DELAY_LABEL_1">%1$d</xliff:g> ms)</item>
@@ -2276,7 +2281,7 @@
     <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Batterij is mogelijk eerder leeg dan normaal"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Batterijbesparing aan"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Sommige functies zijn mogelijk beperkt"</string>
-    <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Telefoon heeft meer verbruikt dan normaal"</string>
+    <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Meer verbruikt dan normaal"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"Tablet heeft meer verbruikt dan normaal"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"Apparaat heeft meer verbruikt dan normaal"</string>
     <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"Batterij is mogelijk eerder leeg dan normaal"</string>
@@ -2556,7 +2561,7 @@
     <string name="backup_inactive_title" msgid="5513496915638307750">"Back-upservice is niet actief"</string>
     <string name="backup_configure_account_default_summary" msgid="5718298066335006412">"Er is momenteel geen account ingesteld voor het opslaan van back-upgegevens"</string>
     <string name="backup_erase_dialog_title" msgid="8178424339104463014"></string>
-    <string name="backup_erase_dialog_message" msgid="8767843355330070902">"Weet je zeker dat je het maken van back-ups van je wifi-wachtwoorden, bladwijzers, andere instellingen en app-gegevens wilt stoppen en alle kopieën op Google-servers wilt wissen?"</string>
+    <string name="backup_erase_dialog_message" msgid="8767843355330070902">"Weet je zeker dat je het maken van back-ups van je wifi-wachtwoorden, bookmarks, andere instellingen en app-gegevens wilt stoppen en alle kopieën op Google-servers wilt wissen?"</string>
     <string name="fullbackup_erase_dialog_message" msgid="2588536036471144070">"Wil je stoppen met het maken van back-ups van apparaatgegevens (zoals wifi-wachtwoorden en gespreksgeschiedenis) en app-gegevens (zoals instellingen en bestanden opgeslagen door apps), en alle kopieën op externe servers wissen?"</string>
     <string name="fullbackup_data_summary" msgid="406274198094268556">"Automatisch op afstand een back-up maken van apparaatgegevens (zoals wifi-wachtwoorden en gespreksgeschiedenis) en app-gegevens (zoals instellingen en bestanden opgeslagen door apps).\n\nAls je de functie voor automatische back-ups inschakelt, worden apparaat- en app-gegevens periodiek op afstand opgeslagen. App-gegevens kunnen gegevens omvatten die een app heeft opgeslagen (op basis van de instellingen van de ontwikkelaar), waaronder potentieel gevoelige gegevens als contacten, berichten en foto\'s."</string>
     <string name="device_admin_settings_title" msgid="2074319456047334589">"Instellingen voor apparaatbeheer"</string>
@@ -2704,7 +2709,7 @@
     <string name="data_usage_auto_sync_off_dialog_title" msgid="7105334544291643305">"Auto-synchr. uitschakelen?"</string>
     <string name="data_usage_auto_sync_off_dialog" msgid="4057984234450947964">"Hiermee beperk je data- en batterijgebruik. Je moet elk account echter handmatig synchroniseren om recente informatie te verzamelen. Je ontvangt geen meldingen wanneer er updates zijn."</string>
     <string name="data_usage_cycle_editor_title" msgid="4967309390043599889">"Datum voor resetten gebruikscyclus"</string>
-    <string name="data_usage_cycle_editor_subtitle" msgid="6043098041946166597">"Datum van elke maand:"</string>
+    <string name="data_usage_cycle_editor_subtitle" msgid="6043098041946166597">"Dag van elke maand:"</string>
     <string name="data_usage_cycle_editor_positive" msgid="9155752056537811646">"Instellen"</string>
     <string name="data_usage_warning_editor_title" msgid="1431385383278389290">"Waarschuwing voor datagebruik instellen"</string>
     <string name="data_usage_limit_editor_title" msgid="1687908662154108293">"Limiet voor dataverbruik instellen"</string>
@@ -2876,8 +2881,8 @@
     <string name="user_cannot_manage_message" product="default" msgid="915260531390608092">"Alleen de eigenaar van de telefoon kan gebruikers beheren."</string>
     <string name="user_cannot_add_accounts_message" msgid="5993561303748749097">"Beperkte profielen kunnen geen accounts toevoegen"</string>
     <string name="user_remove_user_menu" msgid="3505139157217459864">"<xliff:g id="USER_NAME">%1$s</xliff:g> verwijderen van dit apparaat"</string>
-    <string name="user_lockscreen_settings" msgid="3820813814848394568">"Instellingen voor vergrendelingsscherm"</string>
-    <string name="user_add_on_lockscreen_menu" msgid="5211604808199585774">"Gebruikers toevoegen vanaf vergrendelingsscherm"</string>
+    <string name="user_lockscreen_settings" msgid="3820813814848394568">"Instellingen voor vergrendelscherm"</string>
+    <string name="user_add_on_lockscreen_menu" msgid="5211604808199585774">"Gebruikers toevoegen vanaf vergrendelscherm"</string>
     <string name="user_new_user_name" msgid="3880395219777884838">"Nieuwe gebruiker"</string>
     <string name="user_new_profile_name" msgid="3074939718101489937">"Nieuw profiel"</string>
     <string name="user_confirm_remove_self_title" msgid="6739480453680217543">"Wil je jezelf verwijderen?"</string>
@@ -3102,8 +3107,8 @@
     <string name="keywords_financial_apps_sms_access" msgid="3236014691838121857">"financiële app, sms, toegang, recht, toestemming"</string>
     <string name="keywords_systemui_theme" msgid="9150908170417305866">"donker thema"</string>
     <string name="keywords_device_feedback" msgid="6948977907405738490">"bug"</string>
-    <string name="keywords_ambient_display_screen" msgid="5873935693887583428">"Inactief scherm, vergrendelingsscherm"</string>
-    <string name="keywords_lock_screen_notif" msgid="4914337222856805463">"melding, meldingen op vergrendelingsscherm"</string>
+    <string name="keywords_ambient_display_screen" msgid="5873935693887583428">"Inactief scherm, vergrendelscherm"</string>
+    <string name="keywords_lock_screen_notif" msgid="4914337222856805463">"melding, meldingen op vergrendelscherm"</string>
     <string name="keywords_face_settings" msgid="4117345666006836599">"gezicht"</string>
     <string name="keywords_fingerprint_settings" msgid="902902368701134163">"vingerafdruk, vingerafdruk toevoegen"</string>
     <string name="keywords_display_auto_brightness" msgid="1810596220466483996">"scherm dimmen, touchscreen, batterij, slimme helderheid, dynamische helderheid"</string>
@@ -3111,10 +3116,10 @@
     <string name="keywords_auto_rotate" msgid="4320791369951647513">"roteren, draaien, omdraaien, rotatie, portret, landschap, oriëntatie, verticaal, horizontaal, staand, liggend"</string>
     <string name="keywords_system_update_settings" msgid="4419971277998986067">"upgrade, android"</string>
     <string name="keywords_zen_mode_settings" msgid="4103819458182535493">"dnd, schema, meldingen, blokkeren, stil, trillen, slapen, werken, focus, geluid, dempen, dag, weekdag, weekend, doordeweekse avond, evenement, afspraak"</string>
-    <string name="keywords_screen_timeout" msgid="4328381362313993666">"scherm, vergrendelingstijd, time-out, vergrendelingsscherm"</string>
+    <string name="keywords_screen_timeout" msgid="4328381362313993666">"scherm, vergrendelingstijd, time-out, vergrendelscherm"</string>
     <string name="keywords_storage_settings" msgid="6422454520424236476">"geheugen, cache, gegevens, wissen, verwijderen, vrij, vrijmaken, ruimte"</string>
     <string name="keywords_bluetooth_settings" msgid="1152229891590622822">"verbonden, apparaat, hoofdtelefoon, koptelefoon, headset, speaker, luidspreker, draadloos, koppelen, oordoppen, oordopjes, muziek, media"</string>
-    <string name="keywords_wallpaper" msgid="7665778626293643625">"achtergrond, scherm, vergrendelingsscherm, thema"</string>
+    <string name="keywords_wallpaper" msgid="7665778626293643625">"achtergrond, scherm, vergrendelscherm, thema"</string>
     <string name="keywords_assist_input" msgid="8392362788794886564">"standaard, assistent"</string>
     <string name="keywords_default_payment_app" msgid="845369409578423996">"betaling, standaard"</string>
     <string name="keywords_ambient_display" msgid="8835182491798487184">"binnenkomende melding"</string>
@@ -3314,7 +3319,7 @@
     <string name="swipe_direction_ltr" msgid="944932514821822709">"Veeg naar rechts om te sluiten of naar links voor het menu"</string>
     <string name="swipe_direction_rtl" msgid="4521416787262888813">"Veeg naar links om te sluiten of naar rechts voor het menu"</string>
     <string name="notification_pulse_title" msgid="4861418327614907116">"Knipperlicht"</string>
-    <string name="lock_screen_notifications_title" msgid="6889072265118747835">"Op vergrendelingsscherm"</string>
+    <string name="lock_screen_notifications_title" msgid="6889072265118747835">"Op vergrendelscherm"</string>
     <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"Als werkprofiel is vergrendeld"</string>
     <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Content van alle meldingen weergeven"</string>
     <string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"Gevoelige content verbergen"</string>
@@ -3419,7 +3424,7 @@
     <string name="notification_channel_badge_title" msgid="8228215248332054612">"Meldingsstipje weergeven"</string>
     <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"\'Niet storen\' negeren"</string>
     <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"Deze meldingen nog steeds ontvangen, ook wanneer \'Niet storen\' is ingeschakeld"</string>
-    <string name="app_notification_visibility_override_title" msgid="2349335170165637672">"Op vergrendelingsscherm"</string>
+    <string name="app_notification_visibility_override_title" msgid="2349335170165637672">"Op vergrendelscherm"</string>
     <string name="app_notification_row_banned" msgid="2079325338122151677">"Geblokkeerd"</string>
     <string name="app_notification_row_priority" msgid="432299064888787236">"Prioriteit"</string>
     <string name="app_notification_row_sensitive" msgid="4919671519227722958">"Gevoelig"</string>
@@ -3602,8 +3607,8 @@
     <string name="notifications_disabled" msgid="316658185757688983">"Uit"</string>
     <string name="notifications_partly_blocked" msgid="6330451240669068819">"<xliff:g id="COUNT_0">%1$d</xliff:g> van <xliff:g id="COUNT_1">%2$d</xliff:g> categorieën uit"</string>
     <string name="notifications_silenced" msgid="538923056987616372">"Zonder geluid"</string>
-    <string name="notifications_redacted" msgid="308836040236690014">"Gevoelige content niet op vergrendelingsscherm"</string>
-    <string name="notifications_hidden" msgid="3665505522897010205">"Niet op vergrendelingsscherm"</string>
+    <string name="notifications_redacted" msgid="308836040236690014">"Gevoelige content niet op vergrendelscherm"</string>
+    <string name="notifications_hidden" msgid="3665505522897010205">"Niet op vergrendelscherm"</string>
     <string name="notifications_priority" msgid="8849045645983017929">"\'Niet storen\' overschreven"</string>
     <string name="notifications_summary_divider" msgid="3148951310482572028">" / "</string>
     <string name="notification_summary_level" msgid="309162160355022027">"Niveau %d"</string>
@@ -3703,7 +3708,7 @@
     </plurals>
     <string name="high_power_filter_on" msgid="5294209328473386403">"Niet geoptimaliseerd"</string>
     <string name="high_power_on" msgid="3573501822510580334">"Niet geoptimaliseerd"</string>
-    <string name="high_power_off" msgid="5906679734326490426">"Accuverbruik optimaliseren"</string>
+    <string name="high_power_off" msgid="5906679734326490426">"Batterijverbruik optimaliseren"</string>
     <string name="high_power_system" msgid="739584574711292753">"Batterijoptimalisatie niet beschikbaar"</string>
     <string name="high_power_desc" msgid="333756885680362741">"Batterijoptimalisatie niet toepassen. Hierdoor kan je batterijverbruik toenemen."</string>
     <string name="high_power_prompt_title" msgid="2805745781720454052">"App altijd uitvoeren op de achtergrond?"</string>
@@ -4057,7 +4062,7 @@
     <string name="button_confirm_convert_fbe" msgid="419832223125147297">"Wissen en converteren"</string>
     <string name="reset_shortcut_manager_throttling" msgid="1912184636360233397">"Rate limiting van ShortcutManager resetten"</string>
     <string name="reset_shortcut_manager_throttling_complete" msgid="2932990541160593632">"De rate limiting van ShortcutManager is gereset."</string>
-    <string name="notification_suggestion_title" msgid="3292107671498148560">"Informatie op vergrendelingsscherm beheren"</string>
+    <string name="notification_suggestion_title" msgid="3292107671498148560">"Informatie op vergrendelscherm beheren"</string>
     <string name="notification_suggestion_summary" msgid="6516827892359614597">"Content van meldingen weergeven of verbergen"</string>
     <string name="page_tab_title_summary" msgid="4824744863994538006">"Alle"</string>
     <string name="page_tab_title_support" msgid="5569262185010367870">"Tips en ondersteuning"</string>
diff --git a/tests/CarDeveloperOptions/res/values-or/arrays.xml b/tests/CarDeveloperOptions/res/values-or/arrays.xml
index 518431f..58fa092 100644
--- a/tests/CarDeveloperOptions/res/values-or/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-or/arrays.xml
@@ -29,9 +29,25 @@
     <item msgid="5194868215515664953">"ପେସିଫିକ୍‌"</item>
     <item msgid="7044520255415007865">"ସମସ୍ତ"</item>
   </string-array>
-    <!-- no translation found for screen_timeout_entries:0 (8596143519087753804) -->
-    <!-- no translation found for screen_timeout_entries:5 (5827960506924849753) -->
-    <!-- no translation found for dream_timeout_entries:7 (8271452751594598661) -->
+  <string-array name="screen_timeout_entries">
+    <item msgid="8596143519087753804">"15 ସେକେଣ୍ଡ"</item>
+    <item msgid="772029947136115322">"30 ସେକେଣ୍ଡ"</item>
+    <item msgid="8743663928349474087">"1 ମିନିଟ୍"</item>
+    <item msgid="1506508631223164814">"2 ମିନିଟ୍"</item>
+    <item msgid="8664703938127907662">"5 ମିନିଟ୍‍"</item>
+    <item msgid="5827960506924849753">"10 ମିନିଟ୍"</item>
+    <item msgid="6677424950124253938">"30 ମିନିଟ୍‌"</item>
+  </string-array>
+  <string-array name="dream_timeout_entries">
+    <item msgid="6487043225269853023">"ଆଦୌ ନୁହେଁ"</item>
+    <item msgid="2517785806387977252">"15 ସେକେଣ୍ଡ"</item>
+    <item msgid="6347954399441173672">"30 ସେକେଣ୍ଡ"</item>
+    <item msgid="4858305253279921789">"1 ମିନିଟ୍"</item>
+    <item msgid="8109273437140044073">"2 ମିନିଟ୍"</item>
+    <item msgid="2788593551142462622">"ମିନିଟ୍"</item>
+    <item msgid="8012672183888404961">"10 ମିନିଟ୍"</item>
+    <item msgid="8271452751594598661">"30 ମିନିଟ୍"</item>
+  </string-array>
   <string-array name="lock_after_timeout_entries">
     <item msgid="2232921187970351881">"ତୁରନ୍ତ"</item>
     <item msgid="2038544972632026612">"5 ସେକେଣ୍ଡ"</item>
@@ -43,17 +59,47 @@
     <item msgid="811192536981678974">"10 ମିନିଟ୍"</item>
     <item msgid="7258394417241706272">"30 ମିନିଟ୍"</item>
   </string-array>
-    <!-- no translation found for entries_font_size:0 (2340391964816059553) -->
-    <!-- no translation found for entries_font_size:0 (6490061470416867723) -->
-    <!-- no translation found for entries_font_size:2 (1714184661981538355) -->
-    <!-- no translation found for entries_font_size:2 (1678068858001018666) -->
-    <!-- no translation found for wifi_status:3 (5848277343965362748) -->
-    <!-- no translation found for wifi_status_with_ssid:1 (6816207058895999545) -->
-    <!-- no translation found for wifi_status_with_ssid:3 (7547609081339573756) -->
-    <!-- no translation found for wifi_status_with_ssid:4 (5145158315060185414) -->
+  <string-array name="entries_font_size">
+    <item msgid="2340391964816059553">"ଛୋଟ"</item>
+    <item msgid="591935967183159581">"ଡିଫଲ୍ଟ"</item>
+    <item msgid="1714184661981538355">"ବହୁତ ବଡ଼"</item>
+    <item msgid="6195563047686707484">"ବୃହତ୍ତମ"</item>
+  </string-array>
+  <string-array name="wifi_status">
+    <item msgid="1304883790721412351"></item>
+    <item msgid="4157625910392775808">"ସ୍କାନ୍‌ କରୁଛି…"</item>
+    <item msgid="5597394826455877834">"ସଂଯୋଗ କରାଯାଉଛି…"</item>
+    <item msgid="5848277343965362748">"ପ୍ରାମାଣିକରଣ କରାଯାଉଛି…"</item>
+    <item msgid="3391238031431440676">"IP ଠିକଣା ପ୍ରାପ୍ତ କରୁଛି…"</item>
+    <item msgid="5257597310494000224">"ସଂଯୋଗ ହୋଇଛି"</item>
+    <item msgid="8472497592913050396">"ସସ୍ପେଣ୍ଡ ହୋଇଛି"</item>
+    <item msgid="1228072488815999109">"ବିଚ୍ଛିନ୍ନ କରୁଛି…"</item>
+    <item msgid="7253087004422991731">"ବିଛିନ୍ନ"</item>
+    <item msgid="4169850917304751227">"ଅସଫଳ"</item>
+    <item msgid="6266658166690831131">"ଅବରୋଧିତ"</item>
+    <item msgid="4517230805854909775">"ସାମୟିକ ଭାବେ ଖରାପ ସଂଯୋଜନାକୁ ଏଡାଉଛି"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="4853670665485437464"></item>
+    <item msgid="6816207058895999545">"ସ୍କାନ୍ ହେଉଛି…"</item>
+    <item msgid="8058143476674427024">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>କୁ ସଂଯୋଗ କରାଯାଉଛି…"</item>
+    <item msgid="7547609081339573756">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ମାଧ୍ୟମରେ ପ୍ରାମାଣିକରଣ କରାଯାଉଛି…"</item>
+    <item msgid="5145158315060185414">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ରୁ IP ଠିକଣା ହାସଲ କରୁଛି…"</item>
+    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ସହ ସଂଯୁକ୍ତ"</item>
+    <item msgid="6600156231416890902">"ସସ୍ପେଣ୍ଡ ହୋଇଛି"</item>
+    <item msgid="4133290864821295785">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ରୁ ବିଚ୍ଛିନ୍ନ ହେଉଛି…"</item>
+    <item msgid="3980154971187953257">"ବିଛିନ୍ନ"</item>
+    <item msgid="2847316776634969068">"ଅସଫଳ"</item>
+    <item msgid="4390990424746035383">"ଅବରୋଧିତ"</item>
+    <item msgid="3618248791367063949">"ଦୁର୍ବଳ ସଂଯୋଗକୂ ସାମୟିକ ଭାବେ ଏଡ଼ାଉଛି"</item>
+  </string-array>
     <!-- no translation found for wifi_tether_security:0 (5586343370515598801) -->
     <!-- no translation found for wifi_tether_security:1 (6136336549994615745) -->
-    <!-- no translation found for wifi_p2p_wps_setup:0 (5390235347963255303) -->
+  <string-array name="wifi_p2p_wps_setup">
+    <item msgid="5390235347963255303">"ପୁଶ୍ ବଟନ୍"</item>
+    <item msgid="7401896200768713930">"ପୀଅର୍‌ ଡିଭାଇସ୍‌ରୁ PIN‌"</item>
+    <item msgid="4526848028011846710">"ଏହି ଡିଭାଇସ୍‌ରୁ PIN"</item>
+  </string-array>
   <string-array name="wifi_p2p_status">
     <item msgid="8741947238021758201">"ସଂଯୋଗ ହୋଇଛି"</item>
     <item msgid="983792611851499732">"ଆମନ୍ତ୍ରିତ"</item>
@@ -61,7 +107,12 @@
     <item msgid="4646663015449312554">"ଉପଲବ୍ଧ"</item>
     <item msgid="3230556734162006146">"ପରିସୀମା ବାହାରେ"</item>
   </string-array>
-    <!-- no translation found for bluetooth_visibility_timeout_entries:1 (2759776603549270587) -->
+  <string-array name="bluetooth_visibility_timeout_entries">
+    <item msgid="8247986727324120082">"2 ମିନିଟ୍"</item>
+    <item msgid="2759776603549270587">"5 ମିନିଟ୍"</item>
+    <item msgid="167772676068860015">"1 ଘଣ୍ଟା"</item>
+    <item msgid="5985477119043628504">"କେବେବି ବନ୍ଦ କରନାହିଁ"</item>
+  </string-array>
   <string-array name="bluetooth_max_connected_audio_devices">
     <item msgid="3800257971619063588">"ସିଷ୍ଟମ୍ ଡିଫଲ୍ଟ ବ୍ୟବହାର କରନ୍ତୁ: <xliff:g id="DEFAULT_BLUETOOTH_MAX_CONNECTED_AUDIO_DEVICES">%1$d</xliff:g>"</item>
     <item msgid="8572230405241423895">"୧"</item>
@@ -70,8 +121,13 @@
     <item msgid="1644506614010085798">"4"</item>
     <item msgid="3132506679404897150">"5"</item>
   </string-array>
-    <!-- no translation found for wifi_signal:1 (7882129634982603782) -->
-    <!-- no translation found for wifi_signal:4 (999948812884919584) -->
+  <string-array name="wifi_signal">
+    <item msgid="1709949377823900951">"ଖରାପ"</item>
+    <item msgid="7882129634982603782">"ଦୁର୍ବଳ"</item>
+    <item msgid="6457357501905996224">"ଠିକଠାକ"</item>
+    <item msgid="405271628162918841">"ଭଲ"</item>
+    <item msgid="999948812884919584">"ସର୍ବୋତ୍ତମ"</item>
+  </string-array>
   <string-array name="data_usage_data_range">
     <item msgid="8986775481492954015">"ଗତ 30 ଦିନ"</item>
     <item msgid="3211287705232736964">"ବ୍ୟବହାରର ଚକ୍ର ସେଟ୍‌ କରନ୍ତୁ…"</item>
@@ -107,7 +163,10 @@
     <item msgid="7330627471456865502">"MSCHAPV2"</item>
     <item msgid="6255179395132581882">"GTC"</item>
   </string-array>
-    <!-- no translation found for wifi_ip_settings:1 (4377002609760712163) -->
+  <string-array name="wifi_ip_settings">
+    <item msgid="2717196390555072244">"DHCP"</item>
+    <item msgid="4377002609760712163">"ଷ୍ଟାଟିକ୍"</item>
+  </string-array>
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"କିଛି ନୁହେଁ"</item>
     <item msgid="1464741437353223198">"ମାନୁଆଲ୍‌"</item>
@@ -124,8 +183,24 @@
     <item msgid="9148582221081416020">"IPv6"</item>
     <item msgid="4094895508821270572">"IPv4/IPv6"</item>
   </string-array>
-    <!-- no translation found for bearer_entries:0 (5231094118929435723) -->
-    <!-- no translation found for bearer_entries:9 (7246853278334311652) -->
+  <string-array name="bearer_entries">
+    <item msgid="5231094118929435723">"ଅନିର୍ଦ୍ଦିଷ୍ଟ"</item>
+    <item msgid="2740477081395679090">"LTE"</item>
+    <item msgid="1807866878276630064">"HSPAP"</item>
+    <item msgid="7945352669463358624">"HSPA"</item>
+    <item msgid="4152166097223929133">"HSUPA"</item>
+    <item msgid="5134662517319988296">"HSDPA"</item>
+    <item msgid="4997539146036732961">"UMTS"</item>
+    <item msgid="4910169712073083585">"EDGE"</item>
+    <item msgid="3505904588897578792">"GPRS"</item>
+    <item msgid="7246853278334311652">"eHRPD"</item>
+    <item msgid="7037248100126710307">"EVDO_B"</item>
+    <item msgid="3440758673769932256">"EVDO_A"</item>
+    <item msgid="1782525731958596741">"EVDO_0"</item>
+    <item msgid="1819765960790884441">"1xRTT"</item>
+    <item msgid="3148192102183107944">"IS95B"</item>
+    <item msgid="3778273775365258534">"IS95A"</item>
+  </string-array>
   <string-array name="mvno_type_entries">
     <item msgid="6984770764726663331">"କିଛି ନୁହେଁ"</item>
     <item msgid="1469208769491004112">"SPN"</item>
@@ -144,28 +219,185 @@
     <item msgid="8563996233342430477">"ମିଡିଆ"</item>
     <item msgid="5323851085993963783">"ଡିଭାଇସ୍"</item>
   </string-array>
-    <!-- no translation found for app_ops_summaries:46 (4933375960222609935) -->
-    <!-- no translation found for app_ops_labels:3 (7836406246005211990) -->
-    <!-- no translation found for app_ops_labels:4 (3951439024549922598) -->
-    <!-- no translation found for app_ops_labels:8 (3597797992398484655) -->
-    <!-- no translation found for app_ops_labels:20 (3037159047591081136) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
-    <!-- no translation found for app_ops_labels:48 (8291198322681891160) -->
+  <string-array name="app_ops_summaries">
+    <item msgid="2585253854462134715">"ଆନୁମାନିକ ଲୋକେସନ୍‌"</item>
+    <item msgid="1830619568689922920">"ଫାଇନ୍‌ ଲୋକେସନ୍‌"</item>
+    <item msgid="3317274469481923141">"GPS"</item>
+    <item msgid="8931785990160383356">"କମ୍ପନ"</item>
+    <item msgid="8632513128515114092">"ଯୋଗାଯୋଗଗୁଡ଼ିକୁ ପଢ଼ନ୍ତୁ"</item>
+    <item msgid="3741042113569620272">"ଯୋଗାଯୋଗଗୁଡିକ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</item>
+    <item msgid="4204420969709009931">"କଲ୍‌ ଲଗ୍‌ ପଢ଼ନ୍ତୁ"</item>
+    <item msgid="2260380357119423209">"କଲ୍‌ ଲଗ୍‌ ସଂଶୋଧନ କରନ୍ତୁ"</item>
+    <item msgid="6550710385014530934">"କ୍ୟାଲେଣ୍ଡର ପଢ଼ନ୍ତୁ"</item>
+    <item msgid="3575906174264853951">"କ୍ୟାଲେଣ୍ଡର ସଂଶୋଧନ"</item>
+    <item msgid="4319843242568057174">"ୱାଇ-ଫାଇ ସ୍କାନ୍"</item>
+    <item msgid="2981791890467303819">"ବିଜ୍ଞପ୍ତି"</item>
+    <item msgid="6617825156152476692">"ସେଲ୍‌ ସ୍କାନ୍‌"</item>
+    <item msgid="8865260890611559753">"ଫୋନ୍‌ ନମ୍ବର୍‌ କଲ୍‌ କରନ୍ତୁ"</item>
+    <item msgid="3254999273961542982">"SMS ପଢ଼ନ୍ତୁ"</item>
+    <item msgid="7711446453028825171">"SMS ଲେଖନ୍ତୁ"</item>
+    <item msgid="6123238544099198034">"SMS ଗ୍ରହଣ"</item>
+    <item msgid="838342167431596036">"ଜରୁରୀକାଳୀନ SMS ପାଆନ୍ତୁ"</item>
+    <item msgid="8554432731560956686">"MMS ପାଆନ୍ତୁ"</item>
+    <item msgid="7464863464299515059">"ୱାପ୍‌ ପୁଶ୍‌ ପ୍ରାପ୍ତ କରନ୍ତୁ"</item>
+    <item msgid="310463075729606765">"SMS ପଠାନ୍ତୁ"</item>
+    <item msgid="7338021933527689514">"ICC SMS ପଢ଼ନ୍ତୁ"</item>
+    <item msgid="6130369335466613036">"ICC SMS ଲେଖନ୍ତୁ"</item>
+    <item msgid="6536865581421670942">"ସେଟିଙ୍ଗରେ ସଂଶୋଧନ କରନ୍ତୁ"</item>
+    <item msgid="4547203129183558973">"ସ୍କ୍ରୀନ୍‌ର ଉପର ଭାଗରେ ଆଙ୍କନ୍ତୁ"</item>
+    <item msgid="9080347512916542840">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଆକ୍‌ସେସ୍‌ କରନ୍ତୁ"</item>
+    <item msgid="5332718516635907742">"କ୍ୟାମେରା"</item>
+    <item msgid="6098422447246167852">"ଅଡିଓ ରେକର୍ଡ କରନ୍ତୁ"</item>
+    <item msgid="9182794235292595296">"ଅଡିଓ ବଜାନ୍ତୁ"</item>
+    <item msgid="8760743229597702019">"କ୍ଲିପବୋର୍ଡ ପଢନ୍ତୁ"</item>
+    <item msgid="2266923698240538544">"କ୍ଲିପ୍‌ବୋର୍ଡ ବଦଳାନ୍ତୁ"</item>
+    <item msgid="1801619438618539275">"ମିଡିଆର ବଟନ୍‌"</item>
+    <item msgid="31588119965784465">"ଅଡିଓ ଫୋକସ୍‌"</item>
+    <item msgid="7565226799008076833">"ମାଷ୍ଟର୍ ଭଲ୍ୟୁମ୍"</item>
+    <item msgid="5420704980305018295">"ଭଏସ ଭଲ୍ୟୁମ"</item>
+    <item msgid="5797363115508970204">"ରିଙ୍ଗ ଭଲ୍ୟୁମ୍"</item>
+    <item msgid="8233154098550715999">"ମିଡିଆ ଭଲ୍ୟୁମ୍‌"</item>
+    <item msgid="5196715605078153950">"ଆଲାର୍ମର ଭଲ୍ୟୁମ୍‌"</item>
+    <item msgid="394030698764284577">"ବିଜ୍ଞପ୍ତି ଭଲ୍ୟୁମ୍"</item>
+    <item msgid="8952898972491680178">"ବ୍ଲୁଟୂଥ୍‍‌ ଭଲ୍ୟୁମ୍‌"</item>
+    <item msgid="8506227454543690851">"ଜାଗ୍ରତ ରଖନ୍ତୁ"</item>
+    <item msgid="1108160036049727420">"ଜାଗା ଖୋଜନ୍ତୁ"</item>
+    <item msgid="1496205959751719491">"ମଜବୁତ ସିଗ୍ନାଲ୍‌ ଥିବା ଜାଗା ଖୋଜନ୍ତୁ"</item>
+    <item msgid="3776296279910987380">"ଉପଯୋଗର ହିସାବ ପାଆନ୍ତୁ"</item>
+    <item msgid="8827100324471975602">"ମାଇକ୍ରୋଫୋନ୍‌ର ସାଉଣ୍ଡ ବନ୍ଦ/ଚାଲୁ କରନ୍ତୁ"</item>
+    <item msgid="6880736730520126864">"ଟୋଷ୍ଟ୍‌ ଦେଖାନ୍ତୁ"</item>
+    <item msgid="4933375960222609935">"ପ୍ରୋଜେକ୍ଟ ମିଡିଆ"</item>
+    <item msgid="8357907018938895462">"VPN ସକ୍ରିୟ କରନ୍ତୁ"</item>
+    <item msgid="8143812849911310973">"ୱାଲପେପର୍‌ ଯୋଡ଼ନ୍ତୁ"</item>
+    <item msgid="6266277260961066535">"ସହାୟତାର ସଂରଚନା"</item>
+    <item msgid="7715498149883482300">"ସହାୟକ ସ୍କ୍ରିନ୍‌ସଟ୍‍"</item>
+    <item msgid="4046679376726313293">"ଫୋନ୍‌ର ସ୍ଥିତି ଜାଣନ୍ତୁ"</item>
+    <item msgid="6329507266039719587">"ଭଏସ୍‌ମେଲ୍‌ ଯୋଡ଼ନ୍ତୁ"</item>
+    <item msgid="7692440726415391408">"sip ବ୍ୟବହାର କରନ୍ତୁ"</item>
+    <item msgid="8572453398128326267">"ଆଉଟ୍‌ଗୋଇଙ୍ଗ କଲ୍ କରନ୍ତୁ"</item>
+    <item msgid="7775674394089376306">"ଆଙ୍ଗୁଠି ଚିହ୍ନ"</item>
+    <item msgid="3182815133441738779">"ବଡୀ ସେନ୍ସର୍"</item>
+    <item msgid="2793100005496829513">"ସେଲ୍‌ ବ୍ରଡକାଷ୍ଟ ପଢନ୍ତୁ"</item>
+    <item msgid="2633626056029384366">"ନକଲି ଅବସ୍ଥାନ"</item>
+    <item msgid="8356842191824684631">"ଷ୍ଟୋରେଜ୍‌ରୁ ଡାଟା ପଢ଼ିବାର ଅନୁମତି"</item>
+    <item msgid="5671906070163291500">"ଷ୍ଟୋରେଜ୍‌ରେ ଡାଟା ରଖିବାର ଅନୁମତି"</item>
+    <item msgid="2791955098549340418">"ସ୍କ୍ରୀନ୍‌ ଅନ୍‌ କରନ୍ତୁ"</item>
+    <item msgid="5599435119609178367">"ଆକାଉଣ୍ଟଗୁଡିକ ପ୍ରାପ୍ତ କରନ୍ତୁ"</item>
+    <item msgid="1165623660533024666">"ବ୍ୟାକ୍‌ଗ୍ରାଉଣ୍ଡରେ ଚଲାନ୍ତୁ"</item>
+    <item msgid="6423861043647911030">"ଆକ୍‌ସେସିବିଲିଟୀ ଭଲ୍ୟୁମ୍"</item>
+  </string-array>
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"ଅବସ୍ଥାନ"</item>
+    <item msgid="6656077694190491067">"ଅବସ୍ଥାନ"</item>
+    <item msgid="8790228218278477369">"ଅବସ୍ଥାନ"</item>
+    <item msgid="7836406246005211990">"ଭାଇବ୍ରେଟ୍"</item>
+    <item msgid="3951439024549922598">"ଯୋଗାଯୋଗଗୁଡ଼ିକ ପଢ଼ନ୍ତୁ"</item>
+    <item msgid="8802152411647068">"ଯୋଗାଯୋଗ ବଦଳାନ୍ତୁ"</item>
+    <item msgid="229544934599698735">"କଲ୍‌ ଲଗ୍‌ ପଢ଼ନ୍ତୁ"</item>
+    <item msgid="7396102294405899613">"କଲ୍‌ ଲଗ୍‌ ସଂଶୋଧନ କରନ୍ତୁ"</item>
+    <item msgid="3597797992398484655">"କ୍ୟାଲେଣ୍ଡର ପଢ଼ନ୍ତୁ"</item>
+    <item msgid="2705975774250907343">"କ୍ୟାଲେଣ୍ଡରରେ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</item>
+    <item msgid="4668747371441932697">"ଅବସ୍ଥାନ"</item>
+    <item msgid="1487578921720243646">"ପୋଷ୍ଟ ବିଜ୍ଞପ୍ତି"</item>
+    <item msgid="4636080349724146638">"ଲୋକେସନ୍"</item>
+    <item msgid="673510900286463926">"ଫୋନ୍‌କୁ କଲ୍‌ କରନ୍ତୁ"</item>
+    <item msgid="542083422784609790">"SMS/MMS ପଢ଼ନ୍ତୁ"</item>
+    <item msgid="1033780373029588436">"SMS/MMS ଲେଖନ୍ତୁ"</item>
+    <item msgid="5647111115517787488">"SMS/MMS ପାଆନ୍ତୁ"</item>
+    <item msgid="8591105601108455893">"SMS/MMS ପାଆନ୍ତୁ"</item>
+    <item msgid="7730995008517841903">"SMS/MMS ପାଆନ୍ତୁ"</item>
+    <item msgid="2613033109026626086">"SMS/MMS ପାଆନ୍ତୁ"</item>
+    <item msgid="3037159047591081136">"SMS/MMS ପଠାନ୍ତୁ"</item>
+    <item msgid="4726682243833913568">"SMS/MMS ପଢ଼ନ୍ତୁ"</item>
+    <item msgid="6555678522277865572">"SMS/MMS ଲେଖନ୍ତୁ"</item>
+    <item msgid="6981734935578130884">"ସେଟିଙ୍ଗଗୁଡ଼ିକ ବଦଳାନ୍ତୁ"</item>
+    <item msgid="8705854389991425629">"ଉପର ଭାଗରେ ଆଙ୍କନ୍ତୁ"</item>
+    <item msgid="5861356020344153651">"ବିଜ୍ଞପ୍ତି ଆକସେସ୍‌ କରନ୍ତୁ"</item>
+    <item msgid="78432174621628659">"କ୍ୟାମେରା"</item>
+    <item msgid="3986116419882154794">"ଅଡିଓ ରେକର୍ଡ କରନ୍ତୁ"</item>
+    <item msgid="4516840825756409490">"ଅଡିଓ ଚଲାନ୍ତୁ"</item>
+    <item msgid="6811712502798183957">"କ୍ଲିପ୍‌ବୋର୍ଡକୁ ପଢ଼ନ୍ତୁ"</item>
+    <item msgid="2780369012602289114">"କ୍ଲିପ୍‌ବୋର୍ଡରେ ସଂଶୋଧନ କରନ୍ତୁ"</item>
+    <item msgid="2331359440170850868">"ମିଡିଆ ବଟନ୍‌"</item>
+    <item msgid="6133599737122751231">"ଅଡିଓ ଫୋକସ୍‌"</item>
+    <item msgid="6844485713404805301">"ମାଷ୍ଟର୍‌ ଭଲ୍ୟୁମ୍"</item>
+    <item msgid="1600379420669104929">"ଭଏସ୍ ଭଲ୍ୟୁମ୍"</item>
+    <item msgid="6296768210470214866">"ରିଙ୍ଗ ଭଲ୍ୟୁମ୍‌"</item>
+    <item msgid="510690696071629241">"ମିଡିଆ ଭଲ୍ୟୁମ୍‌"</item>
+    <item msgid="406861638631430109">"ଆଲାର୍ମର ଭଲ୍ୟୁମ୍‌"</item>
+    <item msgid="4715864795872233884">"ସୂଚନା ଭଲ୍ୟୁମ"</item>
+    <item msgid="2311478519251301183">"ବ୍ଲୁଟୂଥ୍‍‌ ଭଲ୍ୟୁମ୍‌"</item>
+    <item msgid="5133991377896747027">"ଜାଗ୍ରତ କରି ରଖାଯାଉ"</item>
+    <item msgid="2464189519136248621">"ଲୋକେସନ୍"</item>
+    <item msgid="2062677934050803037">"ଅବସ୍ଥିତି"</item>
+    <item msgid="1735171933192715957">"ବ୍ୟବହାର ହିସାବ ପାଆନ୍ତୁ"</item>
+    <item msgid="1014093788778383554">"ମାଇକ୍ରୋଫୋନ୍‌କୁ ବନ୍ଦ କରନ୍ତୁ/ଖୋଲନ୍ତୁ"</item>
+    <item msgid="4199297950608622850">"ଟୋଷ୍ଟ ଦେଖାନ୍ତୁ"</item>
+    <item msgid="2527962435313398821">"ପ୍ରୋଜେକ୍ଟ ମିଡିଆ"</item>
+    <item msgid="5117506254221861929">"VPN ସକ୍ରିୟ କରନ୍ତୁ"</item>
+    <item msgid="8291198322681891160">"ୱାଲପେପର୍ ଲେଖନ୍ତୁ"</item>
+    <item msgid="7106921284621230961">"ସହାୟକ ସଂରଚନା"</item>
+    <item msgid="4496533640894624799">"ସହାୟତା ସ୍କ୍ରିନ୍‌ସଟ୍‌"</item>
+    <item msgid="2598847264853993611">"ଫୋନ୍‌ର ସ୍ଥିତି ଜାଣନ୍ତୁ"</item>
+    <item msgid="9215610846802973353">"ଭଏସ୍‌ମେଲ୍‌ ଯୋଡ଼ନ୍ତୁ"</item>
+    <item msgid="9186411956086478261">"ସିପ୍‌ ବ୍ୟବହାର କରନ୍ତୁ"</item>
+    <item msgid="6884763100104539558">"ଆଉଟ୍‌ଗୋଇଙ୍ଗ କଲ୍‌ ପ୍ରୋସେସ୍‌ କରନ୍ତୁ"</item>
+    <item msgid="125513972170580692">"ଆଙ୍ଗୁଠି ଚିହ୍ନ"</item>
+    <item msgid="2556071024281275619">"ବଡୀ ସେନ୍ସର୍"</item>
+    <item msgid="617168514928339387">"ସେଲ୍‌ର ସମ୍ପ୍ରସାରଣକୁ ପଢ଼ନ୍ତୁ"</item>
+    <item msgid="7134693570516523585">"ନକଲି ଲୋକେସନ୍‌"</item>
+    <item msgid="7224489175375229399">"ପଠନ ଷ୍ଟୋରେଜ୍‌"</item>
+    <item msgid="8472735063903258202">"ଷ୍ଟୋରେଜ୍‌ରେ ଡାଟା ରଖିବାର ଅନୁମତି"</item>
+    <item msgid="4069276819909595110">"ସ୍କ୍ରୀନ୍‌କୁ ଅନ୍‌ କରନ୍ତୁ"</item>
+    <item msgid="1228338896751121025">"ଆକାଉଣ୍ଟଗୁଡିକ ପ୍ରାପ୍ତ କରନ୍ତୁ"</item>
+    <item msgid="3181581793459233672">"ବ୍ୟାକ୍‌ଗ୍ରାଊଣ୍ଡରେ ଚଲାନ୍ତୁ"</item>
+    <item msgid="2340936043025374076">"ଦିବ୍ୟାଙ୍ଗମାନଙ୍କ ପାଇଁ ସୁବିଧାଗୁଡ଼ିକର ଭଲ୍ୟୁମ୍‌"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"କମ୍"</item>
     <item msgid="4816511817309094890">"ମଧ୍ୟମ"</item>
     <item msgid="8305084671259331134">"ଲମ୍ଵା"</item>
   </string-array>
-    <!-- no translation found for captioning_typeface_selector_titles:4 (1487203730637617924) -->
-    <!-- no translation found for captioning_font_size_selector_titles:3 (2784236342175159295) -->
-    <!-- no translation found for captioning_edge_type_selector_titles:4 (8019330250538856521) -->
+  <string-array name="captioning_typeface_selector_titles">
+    <item msgid="6928465258504250174">"ଡିଫଲ୍ଟ"</item>
+    <item msgid="4147246073737933622">"ସାନ୍ସ-ସେରିଫ୍‌"</item>
+    <item msgid="3117680749167407907">"ସାନ୍ସ-ସେରିଫ୍ କଣ୍ଡେନ୍ସଡ୍"</item>
+    <item msgid="6529379119163117545">"ସାନ୍ସ-ସେରିଫ୍‍ ମୋନୋସ୍ପେସ୍"</item>
+    <item msgid="1487203730637617924">"Serif"</item>
+    <item msgid="4937790671987480464">"Serif monospace"</item>
+    <item msgid="4448481989108928248">"ସାଧାରଣ"</item>
+    <item msgid="4627069151979553527">"କର୍ସିଭ"</item>
+    <item msgid="6896773537705206194">"ଛୋଟ ଆକାରର ଅକ୍ଷର"</item>
+  </string-array>
+  <string-array name="captioning_font_size_selector_titles">
+    <item msgid="1680223634161592855">"ବହୁତ ଛୋଟ"</item>
+    <item msgid="5091603983404027034">"ଛୋଟ"</item>
+    <item msgid="176844712416932112">"ସାଧାରଣ"</item>
+    <item msgid="2784236342175159295">"ବହୁତ ବଡ଼"</item>
+    <item msgid="218913203203160606">"ବହୁତ ବଡ଼"</item>
+  </string-array>
+  <string-array name="captioning_edge_type_selector_titles">
+    <item msgid="3865198759294188069">"ଡିଫଲ୍ଟ"</item>
+    <item msgid="6488643537808152001">"କିଛି ନୁହେଁ"</item>
+    <item msgid="552332815156010137">"ଆଉଟ୍‌ଲାଇନ୍‌"</item>
+    <item msgid="7187891159463789272">"ଡ୍ରପ୍‌ ଛାୟା"</item>
+    <item msgid="8019330250538856521">"ଉପରକୁ ଟିକିଏ ଉଠିଥିବା"</item>
+    <item msgid="8987385315647049787">"ସଂକ୍ଷିପ୍ତ"</item>
+  </string-array>
   <string-array name="captioning_opacity_selector_titles">
     <item msgid="313003243371588365">"25%"</item>
     <item msgid="4665048002584838262">"50%"</item>
     <item msgid="1874668269931014581">"75%"</item>
     <item msgid="6462911487571123954">"100%"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"ଆପ୍‌ର ପୂର୍ବ-ନିର୍ଦ୍ଧାରିତ ସେଟିଙ୍ଗ ବ୍ୟବହାର କରନ୍ତୁ"</item>
+    <item msgid="8611890312638868524">"କଳା ଉପରେ ଧଳା"</item>
+    <item msgid="5891360837786277638">"ଧଳା ଉପରେ କଳା"</item>
+    <item msgid="2798457065945456853">"କଳା ଉପରେ ହଳଦିଆ"</item>
+    <item msgid="5799049811524553967">"ନୀଳ ଉପରେ ହଳଦିଆ"</item>
+    <item msgid="3673930830658169860">"କଷ୍ଟମ"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"PPTP VPN"</item>
     <item msgid="1349760781118368659">"ପୂର୍ବରୁ ସେୟାର୍‌ ହୋଇଥିବା କୀଗୁଡ଼ିକ ସହ L2TP/IPSec VPN"</item>
@@ -174,16 +406,36 @@
     <item msgid="3319427315593649917">"ସର୍ଟିଫିକେଟ୍‌ ଏବଂ Xauth ପ୍ରାମାଣିକୀକରଣ ସହ IPSec VPN"</item>
     <item msgid="8258927774145391041">"ସର୍ଟିଫିକେଟ୍‌ ଓ ହାଇବ୍ରିଡ୍‌ ସତ୍ୟାପନ ସହ IPSec VPN"</item>
   </string-array>
-    <!-- no translation found for vpn_proxy_settings:0 (2958623927055120839) -->
-    <!-- no translation found for vpn_states:4 (9135049670787351881) -->
+  <string-array name="vpn_proxy_settings">
+    <item msgid="2958623927055120839">"କିଛି ନାହିଁ"</item>
+    <item msgid="1157046369795346308">"ମାନୁଆଲ୍‌"</item>
+  </string-array>
+  <string-array name="vpn_states">
+    <item msgid="5408915841694583740">"ବିଛିନ୍ନ"</item>
+    <item msgid="8754480102834556765">"ଆରମ୍ଭ କରୁଛି…"</item>
+    <item msgid="3351334355574270250">"ସଂଯୋଗ କରାଯାଉଛି…"</item>
+    <item msgid="8303882153995748352">"ସଂଯୋଗ ହୋଇଛି"</item>
+    <item msgid="9135049670787351881">"ସମୟ ସମାପ୍ତ"</item>
+    <item msgid="2124868417182583926">"ଅସଫଳ"</item>
+  </string-array>
   <string-array name="security_settings_premium_sms_values">
     <item msgid="1164265643455394443">"ପଚାରନ୍ତୁ"</item>
     <item msgid="7718817231348607934">"ଆଦୌ ଅନୁମତି ଦିଅନାହିଁ"</item>
     <item msgid="8184570120217958741">"ସର୍ବଦା ଅନୁମତି ଦିଅନ୍ତୁ"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"ସାଧାରଣ"</item>
+    <item msgid="5101233285497327432">"ମଧ୍ୟମ ଧରଣର"</item>
+    <item msgid="1555861583162930714">"କମ୍"</item>
+    <item msgid="1719683776264798117">"ଜଟିଳ"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"ସାଧାରଣ"</item>
+    <item msgid="6107138933849816768">"ମଧ୍ୟମ"</item>
+    <item msgid="182695359839047859">"କମ୍"</item>
+    <item msgid="8577246509202964244">"ଜଟିଳ"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"ନିରନ୍ତର"</item>
     <item msgid="167418068739176448">"ଶ୍ରେଷ୍ଠ ଗତିବିଧି"</item>
@@ -245,7 +497,31 @@
     <item msgid="8444727359525554695">"କେବଳ ହୋମ୍ ନେଟ୍‌ୱର୍କ"</item>
     <item msgid="1161026694891024702">"ସ୍ଵତଃଚାଳିତ"</item>
   </string-array>
-    <!-- no translation found for preferred_network_mode_choices:11 (5713723042183940349) -->
+  <string-array name="preferred_network_mode_choices">
+    <item msgid="1823884522189328861">"GSM/WCDMA ପସନ୍ଦ କରାଯାଇଛି"</item>
+    <item msgid="7581481130337402578">"କେବଳ GSM"</item>
+    <item msgid="8579197487913425819">"କେବଳ WCDMA"</item>
+    <item msgid="8465243227505412498">"GSM/WCDMA ଅଟୋ"</item>
+    <item msgid="9107479914166352132">"CDMA/EvDo ଅଟୋ"</item>
+    <item msgid="4219607161971472471">"EvDo ବିନା CDMA"</item>
+    <item msgid="7278975240951052041">"କେବଳ EvDo"</item>
+    <item msgid="2295969832276827854">"CDMA/EvDo/GSM/WCDMA"</item>
+    <item msgid="9059227943989034424">"CDMA + LTE/EvDo"</item>
+    <item msgid="463168068025354541">"GSM/WCDMA/LTE"</item>
+    <item msgid="1770755308983338311">"ଗ୍ଲୋବାଲ୍"</item>
+    <item msgid="5713723042183940349">"LTE"</item>
+    <item msgid="8600184258612405670">"LTE / WCDMA"</item>
+    <item msgid="5638632460322750180">"କେବଳ TDSCDMA"</item>
+    <item msgid="4346392996298714633">"TDSCDMA/WCDMA"</item>
+    <item msgid="5004811216708487615">"LTE/TDSCDMA"</item>
+    <item msgid="9191730167201068525">"TDSCDMA/GSM"</item>
+    <item msgid="5874623229495009031">"LTE/TDSCDMA/GSM"</item>
+    <item msgid="5096480046347789213">"TDSCDMA/GSM/WCDMA"</item>
+    <item msgid="2075445917638134012">"LTE/TDSCDMA/WCDMA"</item>
+    <item msgid="3353351554070857366">"LTE/TDSCDMA/GSM/WCDMA"</item>
+    <item msgid="2067289929099567494">"TDSCDMA/CDMA/EVDO/GSM/WCDMA"</item>
+    <item msgid="4959483620561891661">"LTE/TDSCDMA/CDMA/EVDO/GSM/WCDMA"</item>
+  </string-array>
   <string-array name="cdma_subscription_choices">
     <item msgid="7691437408632563841">"RUIM/SIM"</item>
     <item msgid="6219184455685527822">"NV"</item>
diff --git a/tests/CarDeveloperOptions/res/values-or/config.xml b/tests/CarDeveloperOptions/res/values-or/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-or/config.xml
+++ b/tests/CarDeveloperOptions/res/values-or/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-or/strings.xml b/tests/CarDeveloperOptions/res/values-or/strings.xml
index 08c5173..f03cb53 100644
--- a/tests/CarDeveloperOptions/res/values-or/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-or/strings.xml
@@ -117,7 +117,7 @@
     <string name="bluetooth_is_visible_message" msgid="6341088682252805612">"ବ୍ଲୁଟୂଥ୍‍‌ ସେଟିଙ୍ଗ ଖୋଲା ଥିବାବେଳେ ଆଖପାଖ ଡିଭାଇସ୍‌ଗୁଡ଼ିକୁ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ଦେଖାଦେଉଛି।"</string>
     <string name="bluetooth_footer_mac_message" product="default" msgid="335341476746836260">"ଫୋନ୍‌ର ବ୍ଲୁଟୂଥ୍‍‌ ଠିକଣା ହେଉଛି: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
     <string name="bluetooth_footer_mac_message" product="tablet" msgid="6033609611245782463">"ଟାବ୍‌ଲେଟ୍‌ର ବ୍ଲୁଟୂଥ୍‍‌ ଠିକଣା ହେଉଛି: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
-    <string name="bluetooth_footer_mac_message" product="device" msgid="7639919867088358038">"ଡିଭାଇସ୍‌ର ବ୍ଲୁଟୂଥ୍‍‌ ଠିକଣା ହେଉଛି: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="bluetooth_footer_mac_message" product="device" msgid="7639919867088358038">"ଡିଭାଇସ୍‌ର ବ୍ଲୁଟୁଥ ଠିକଣା ହେଉଛି: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
     <string name="bluetooth_is_disconnect_question" msgid="6180709281434591654">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>କୁ ବିଚ୍ଛିନ୍ନ କରିବେ?"</string>
     <string name="bluetooth_broadcasting" msgid="8926408584599563760">"ବ୍ରଡ୍‌କାଷ୍ଟିଙ୍ଗ"</string>
     <string name="bluetooth_device" msgid="3170974107364990008">"ନାମହୀନ ବ୍ଲୁଟୂଥ୍‍‌ ଡିଭାଇସ୍‌"</string>
@@ -425,7 +425,7 @@
     <string name="security_settings_face_settings_require_confirmation_details" msgid="8740564864091803429">"ଆପ୍ସରେ ପ୍ରମାଣିକରଣ କରିବା ସମୟରେ, ସବୁବେଳେ ସୁନିଶ୍ଚିତକରଣ ଆବଶ୍ୟକ ହୋଇଥାଏ"</string>
     <string name="security_settings_face_settings_remove_face_data" msgid="2821359954483136239">"ମୁହଁ ଡାଟା କାଢ଼ନ୍ତୁ"</string>
     <string name="security_settings_face_settings_footer" msgid="4627175759990550715">"ଆପଣଙ୍କର ଡିଭାଇସ୍‍ ଅନ୍‍ଲକ୍‍ ଏବଂ ଆପ୍ସ ଆକ୍ସେସ୍‍ କରିବାକୁ ଆପଣଙ୍କ ମୁହଁକୁ ବ୍ୟବହାର କରି ହେବ। "<annotation id="url">"ଅଧିକ ଜାଣନ୍ତୁ"</annotation></string>
-    <string name="security_settings_face_settings_remove_dialog_title" msgid="5675319895815271094">"ମୁହଁର ଡାଟା ଡିଲିଟ୍ କରିବେ?"</string>
+    <string name="security_settings_face_settings_remove_dialog_title" msgid="5675319895815271094">"ଫେସ୍ ଡାଟା ଡିଲିଟ୍ କରିବେ?"</string>
     <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"ମୁହଁ ଅନ୍‌ଲକ୍ ଦ୍ୱାରା ରେକର୍ଡ କରାଯାଇଥିବା ଡାଟା ସ୍ଥାୟୀ ଏବଂ ସୁରକ୍ଷିତ ରୂପେ ଡିଲିଟ୍ ହୋ‌ଇଯିବ। କାଢ଼ିଦେବା ପରେ, ଆପଣଙ୍କର ଫୋନ୍‌କୁ ଅନ୍‌ଲକ୍, ଆପ୍ସକୁ ସାଇନ୍ ଇନ୍, ଏବଂ ପେମେଣ୍ଟକୁ ସୁନିଶ୍ଚିତ କରିବାକୁ ଆପଣଙ୍କୁ PIN, ପେଟର୍ଣ୍ଣ, କିମ୍ବା ପାସ୍‌ୱର୍ଡର ଆବଶ୍ୟକ ହେବ।"</string>
     <string name="security_settings_fingerprint_preference_title" msgid="4177132225930582928">"ଆଙ୍ଗୁଠି ଚିହ୍ନ"</string>
     <string name="fingerprint_manage_category_title" msgid="1463406696801542090">"ଆଙ୍ଗୁଠି ଚିହ୍ନଗୁଡ଼ିକର ପରିଚାଳନା କରନ୍ତୁ"</string>
@@ -447,7 +447,7 @@
     <string name="security_settings_fingerprint_enroll_introduction_cancel_setup" msgid="756928427429893070">"ଛାଡିଦିଅନ୍ତୁ"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue_setup" msgid="4125977169169671144">"ପରବର୍ତ୍ତୀ"</string>
     <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ସେଟ୍‌ଅପ୍‌ କରିବାର ପଦକ୍ଷେପଟି ଏଡ଼ାଇ ଯିବେ?"</string>
-    <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"ଟିପଚିହ୍ନ ସେଟଅପ୍‌ କେବଳ ଏକ ମିନିଟ୍ କିମ୍ବା ଦୁଇ ମିନିଟ୍‌ ସମୟ ନିଏ। ଯଦି ଆପଣ ଏହା ଛାଡି ଦିଅନ୍ତି, ଆପଣ ପରେ ସେଟିଙ୍ଗରେ ନିଜର ଟିପଚିହ୍ନ ଯୋଡିପାରିବେ।"</string>
+    <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"ଟିପଚିହ୍ନ ସେଟଅପ୍‌ କେବଳ ଏକ ମିନିଟ୍ କିମ୍ବା ଦୁଇ ମିନିଟ୍‌ ସମୟ ନିଏ। ଯଦି ଆପଣ ଏହାକୁ ବାଦ୍ ଦିଅନ୍ତି, ଆପଣ ପରେ ସେଟିଂସରେ ନିଜର ଟିପଚିହ୍ନ ଯୋଗ କରିପାରିବେ।"</string>
     <string name="lock_screen_intro_skip_title" msgid="5307431665496346914">"ସ୍କ୍ରୀନ୍‌ ଲକ୍‌ ଛାଡ଼ିଦେବେ?"</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="tablet" msgid="7553945981266845264">"ଡିଭାଇସ ସୁରକ୍ଷା ବୈଶିଷ୍ଟ୍ୟ ଚାଲୁ ହୋଇପାରିବ ନାହିଁ। ଏହି ଟାବ୍‌ଲେଟ୍‌ ଯଦି ଚୋରି ହୋଇଯାଏ, ହଜିଯାଏ କିମ୍ୱା ରିସେଟ୍‌ କରାଯାଏ, ତେବେ ଆପଣ ଏହାକୁ ବ୍ୟବହାର କରିବାରୁ ଅନ୍ୟମାନଙ୍କୁ ରୋକିପାରିବେ ନାହିଁ।"</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="device" msgid="1378243257238015603">"ଡିଭାଇସ୍‌ ସୁରକ୍ଷା ବୈଶିଷ୍ଟ୍ୟ ଅନ୍‍ ହେବନାହିଁ। ଏହି ଡିଭାଇସ୍‍ ହଜିଲେ କିମ୍ୱା ଚୋରି ହୋଇଗଲେ, ଅନ୍ୟମାନଙ୍କୁ ଏହାକୁ ବ୍ୟବହାର କରିବାରୁ ଆପଣ ରୋକିପାରିବେ ନାହିଁ।"</string>
@@ -455,7 +455,7 @@
     <string name="lock_screen_intro_skip_dialog_text" product="tablet" msgid="7572334562915795226">"ଡିଭାଇସ ସୁରକ୍ଷା ବୈଶିଷ୍ଟ୍ୟ ଅନ୍‌ ହୋଇପାରିବ ନାହିଁ। ଏହି ଟାବଲେଟ୍‌ ଯଦି ଚୋରି ହୋଇଯାଏ କିମ୍ୱା ହଜିଯାଏ, ତେବେ ଆପଣ ଏହାକୁ ବ୍ୟବହାର କରିବାରେ ଅନ୍ୟମାନଙ୍କୁ ପ୍ରତିରୋଧ କରିପାରିବେ ନାହିଁ।"</string>
     <string name="lock_screen_intro_skip_dialog_text" product="device" msgid="3819285334459763813">"ଡିଭାଇସ୍‌ର ସୁରକ୍ଷା ବୈଶିଷ୍ଟ୍ୟ ଚାଲୁ ହେବନାହିଁ। ଯଦି ଏହି ଡିଭାଇସ୍‌ ଚୋରି ହୋଇଯାଏ କିମ୍ୱା ହଜିଯାଏ, ତେବେ ଆପଣ ଏହାକୁ ବ୍ୟବହାର କରିବାରୁ ଅନ୍ୟମାନଙ୍କୁ ରୋକିପାରିବେ ନାହିଁ।"</string>
     <string name="lock_screen_intro_skip_dialog_text" product="default" msgid="5361573789585652826">"ଡିଭାଇସ ସୁରକ୍ଷା ବୈଶିଷ୍ଟ୍ୟ ଚାଲୁ ହୋଇପାରିବ ନାହିଁ। ଯଦି ଏହି ଫୋନ୍‌ ଚୋରି ହୋଇଯାଏ କିମ୍ୱା ହଜିଯାଏ, ତେବେ ଆପଣ ଏହାକୁ ବ୍ୟବହାର କରିବାରୁ ଅନ୍ୟମାନଙ୍କୁ ରୋକିପାରିବେ ନାହିଁ।"</string>
-    <string name="skip_anyway_button_label" msgid="4437815969645175429">"ତଥାପି ଆଗକୁ ବଢ଼ନ୍ତୁ"</string>
+    <string name="skip_anyway_button_label" msgid="4437815969645175429">"ଯେ କୌଣସି ଭାବେ ବାଦ୍ ଦିଅନ୍ତୁ"</string>
     <string name="go_back_button_label" msgid="7310586887969860472">"ପଛକୁ ଫେରନ୍ତୁ"</string>
     <string name="skip_lock_screen_dialog_button_label" msgid="6706047245716780006">"ବାଦ୍ ଦିଅନ୍ତୁ"</string>
     <string name="cancel_lock_screen_dialog_button_label" msgid="2534925227627658819">"ବାତିଲ୍"</string>
@@ -468,8 +468,8 @@
     <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"ସେନ୍ସର୍‌କୁ ଛୁଅଁନ୍ତୁ"</string>
     <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"ନିଜ ଆଙ୍ଗୁଠିକୁ ସେନ୍ସର୍ ଉପରେ ରଖନ୍ତୁ ଏବଂ ଏକ କମ୍ପନ ଅନୁଭବ କରିବା ପରେ ଉଠାଇଦିଅନ୍ତୁ"</string>
     <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"ଉଠାନ୍ତୁ, ତା\'ପରେ ପୁଣି ଛୁଅଁନ୍ତୁ"</string>
-    <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"ନିଜ ଟିପଚିହ୍ନର ବିଭିନ୍ନ ଅଂଶ ଯୋଡ଼ିବା ପାଇଁ ଆଙ୍ଗୁଠି ଉଠାଉଥାନ୍ତୁ"</string>
-    <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"ଟିପଚିହ୍ନ ଯୋଡ଼ାଗଲା"</string>
+    <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"ନିଜ ଟିପଚିହ୍ନର ବିଭିନ୍ନ ଅଂଶ ଯୋଗ କରିବା ପାଇଁ ଆଙ୍ଗୁଠି ଉଠାଉଥାନ୍ତୁ"</string>
+    <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"ଟିପଚିହ୍ନ ଯୋଗ କରାଗଲା"</string>
     <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"ଆପଣ ଯେତେବେଳେ ଏହି ଆଇକନ୍‌‌କୁ ଦେଖିବେ, ପରିଚୟ ପାଇଁ କିମ୍ବା କ୍ରୟଗୁଡିକର ମଞ୍ଜୁରୀ ଦେବା ପାଇଁ ଆପଣଙ୍କ ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string>
     <string name="security_settings_fingerprint_enroll_enrolling_skip" msgid="1473280156532146933">"ଏହାକୁ ପରେ କରନ୍ତୁ"</string>
     <string name="setup_fingerprint_enroll_enrolling_skip_title" msgid="2816424026528101690">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ସେଟଅପ ଛାଡ଼ିଦେବେ?"</string>
@@ -490,7 +490,7 @@
     <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"ନାମାଙ୍କନ ସମ୍ପୂର୍ଣ୍ଣ ହୋଇନାହିଁ"</string>
     <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ନାମାଙ୍କନର ସମୟ ସମାପ୍ତ ହୋଇଯାଇଛି। ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ନାମାଙ୍କନ ହୋଇପାରିଲା ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ କିମ୍ବା ଭିନ୍ନ ଏକ ଆଙ୍ଗୁଠି ବ୍ୟବହାର କରନ୍ତୁ।"</string>
-    <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"ଆଉ ଗୋଟିଏ ଯୋଡ଼ନ୍ତୁ"</string>
+    <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"ଆଉ ଗୋଟିଏ ଯୋଗ କରନ୍ତୁ"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"ପରବର୍ତ୍ତୀ"</string>
     <string name="security_settings_fingerprint_enroll_disclaimer" msgid="5831834311961551423">"ଆପଣଙ୍କ ଫୋନ୍‌ ଅନଲକ୍‌ କରିବା ସହ, କ୍ରୟ କରିବାକୁ ଏବଂ ଆପ୍‌ ଆକ୍ସେସ୍‌ ସ୍ୱୀକୃତି ଦେବାକୁ ଆପଣଙ୍କ ଟିପଚିହ୍ନ ମଧ୍ୟ ବ୍ୟବହାର କରିପାରିବେ। "<annotation id="url">"ଅଧିକ ଜାଣନ୍ତୁ"</annotation></string>
     <string name="security_settings_fingerprint_enroll_disclaimer_lockscreen_disabled" msgid="7954742554236652690">" ସ୍କ୍ରୀନ୍‌ ଲକ୍‌ ବିକଳ୍ପ ଅକ୍ଷମ ହୋଇଛି। ଅଧିକ ଜାଣିବା ପାଇଁ ନିଜ ସଂସ୍ଥାର ଆଡ୍‌ମିନ୍‌ଙ୍କୁ ସମ୍ପର୍କ କରନ୍ତୁ। "<annotation id="admin_details">"ଅଧିକ ବିବରଣୀ"</annotation>\n\n"କିଣାକିଣିକୁ ଆଧିକୃତ ଓ ଆପ୍‌ ଆକ୍ସେସ୍‌ ପାଇଁ ନିଜ ଆଙ୍ଗୁଠି ଚିହ୍ନକୁ ଆପଣ ତଥାପି ବ୍ୟବହାର କରିପାରିବେ। "<annotation id="url">"ଅଧିକ ଜାଣନ୍ତୁ"</annotation></string>
@@ -555,7 +555,7 @@
     <string name="lock_settings_picker_fingerprint_message" msgid="1344567476145156885">"ନିଜର ବ୍ୟାକ୍‌ଅପ୍‌ ସ୍କ୍ରୀନ୍‌ ଲକ୍‌ ପଦ୍ଧତି ବାଛନ୍ତୁ"</string>
     <string name="lock_settings_picker_face_message" msgid="6413145626861812959">"ନିଜର ବ୍ୟାକଅପ୍‌ ସ୍କ୍ରୀନ୍‌ ଲକ୍‌ ପଦ୍ଧତି ବାଛନ୍ତୁ"</string>
     <string name="setup_lock_settings_options_button_label" msgid="4197315143877977385">"ସ୍କ୍ରିନ୍‌ ଲକ୍‌ର ବିକଳ୍ପଗୁଡ଼ିକ"</string>
-    <string name="setup_lock_settings_options_dialog_title" msgid="5241946349173768827">"ସ୍କ୍ରୀନ୍‌ ଲକ୍‌ ବିକଳ୍ପ"</string>
+    <string name="setup_lock_settings_options_dialog_title" msgid="5241946349173768827">"ସ୍କ୍ରିନ୍‌ ଲକ୍‌ ବିକଳ୍ପ"</string>
     <string name="unlock_set_unlock_launch_picker_title" msgid="2731152716948003853">"ସ୍କ୍ରୀନ୍‌ ଲକ୍‌"</string>
     <string name="unlock_set_unlock_launch_picker_summary_lock_immediately" msgid="5596186270725220642">"<xliff:g id="UNLOCK_METHOD">%1$s</xliff:g> / ସୁପ୍ତାବସ୍ଥାର ତୁରନ୍ତ ପରେ"</string>
     <string name="unlock_set_unlock_launch_picker_summary_lock_after_timeout" msgid="3861167251234952373">"<xliff:g id="UNLOCK_METHOD">%1$s</xliff:g> / <xliff:g id="TIMEOUT_STRING">%2$s</xliff:g> ସୁପ୍ତାବସ୍ଥା ପରେ"</string>
@@ -595,7 +595,7 @@
     <string name="unlock_disable_lock_title" msgid="3508492427073600294">"ସ୍କ୍ରୀନ ଲକକୁ ବନ୍ଦ କର"</string>
     <string name="unlock_disable_frp_warning_title" msgid="5858589970505254193">"ଡିଭାଇସ୍‌ ସୁରକ୍ଷାକୁ କାଢ଼ିଦେବେ?"</string>
     <string name="unlock_disable_frp_warning_title_profile" msgid="3814123014295965266">"ପ୍ରୋଫାଇଲ୍‌ ସୁରକ୍ଷା କାଢ଼ିଦେବେ?"</string>
-    <string name="unlock_disable_frp_warning_content_pattern" msgid="1843950215687159135">"ଆପଣଙ୍କ ପାଟର୍ନ ବିନା ଡିଭାଇସ୍‌ର ସୁରକ୍ଷା ବୈଶିଷ୍ଟ୍ୟ କାମ କରିବ ନାହିଁ।"</string>
+    <string name="unlock_disable_frp_warning_content_pattern" msgid="1843950215687159135">"ଆପଣଙ୍କ ପାଟର୍ନ ବିନା ଡିଭାଇସ୍‌ର ସୁରକ୍ଷା ଫିଚରଗୁଡ଼ିକ କାମ କରିବ ନାହିଁ।"</string>
     <string name="unlock_disable_frp_warning_content_pattern_fingerprint" msgid="8846957650251741548">"ଆପଣଙ୍କ ପାଟର୍ନ ବିନା ଡିଭାଇସ ସୁରକ୍ଷା ବୈଶିଷ୍ଟ୍ୟ କାମ କରିବ ନାହିଁ।<xliff:g id="EMPTY_LINE">
 
 </xliff:g>ଆପଣଙ୍କର ସେଭ ହୋଇଥିବା ଆଙ୍ଗୁଠି ଚିହ୍ନଗୁଡ଼ିକ ମଧ୍ୟ ଏହି ଡିଭାଇସରୁ ଉଡ଼ାଇଦିଆଯିବ ଏବଂ ଆପଣ ନିଜ ଫୋନକୁ ଅନଲକ କରିପାରିବେ ନାହିଁ, କିଣାକିଣି କରିପାରିବେ ନାହିଁ କିମ୍ୱା ତାହା ଦ୍ୱାରା ଏପଗୁଡ଼ିକରେ ସାଇନ ଇନ କରିପାରିବେ ନାହିଁ।"</string>
@@ -667,7 +667,6 @@
       <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> ଅଙ୍କରୁ କମ୍‌ ହେବା ଦରକାର</item>
       <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> ଅଙ୍କରୁ କମ୍‌ ହେବା ଦରକାର</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"କେବଳ 0-9 ସଂଖ୍ୟା ହିଁ ରହିବା ଦରକାର"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"ଏକ ସାମ୍ପ୍ରତିକ ପିନ୍‌ର ବ୍ୟବହାରକୁ ଡିଭାଇସ୍‌ ଆଡ୍‌ମିନ୍‌ ଅନୁମତି ଦେବନାହିଁ"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"ସାଧାରଣ PINଗୁଡିକ ଆପଣଙ୍କ IT ଆଡମିନ୍‌ଙ୍କ ଦ୍ୱାରା ଅବରୋଧ କରିଦିଆଯାଇଛି। ଭିନ୍ନ PIN ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"ଏକ ଭୁଲ ଅକ୍ଷରକୁ ଏହା ମିଶାଇ ପାରିବନାହିଁ"</string>
@@ -698,6 +697,10 @@
       <item quantity="other">ଅତିକମ୍‌ରେ <xliff:g id="COUNT">%d</xliff:g>ଟି ବିଶେଷ ଅକ୍ଷର କିମ୍ୱା ସଂଖ୍ୟା ଆବଶ୍ୟକ</item>
       <item quantity="one">ଅତିକମ୍‌ରେ 1ଟି ବିଶେଷ ଅକ୍ଷର କିମ୍ୱା ସଂଖ୍ୟା ଆବଶ୍ୟକ</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">ଅତିକମ୍‌ରେ <xliff:g id="COUNT">%d</xliff:g>ଟି ଅକ୍ଷର ହେବା ନିହାତି ଆବଶ୍ୟକ ଯାହା ସଂଖ୍ୟା ହୋଇନଥିବା</item>
+      <item quantity="one">ଅତିକମ୍‌ରେ 1ଟି ଅକ୍ଷର ହେବା ନିହାତି ଆବଶ୍ୟକ ଯାହା ସଂଖ୍ୟା ହୋଇନଥିବା</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"ଏକ ସମ୍ପ୍ରତି ପାସ୍‌ୱର୍ଡ ବ୍ୟବହାର କରିବାକୁ ଡିଭାଇସ୍‌ ଆଡମିନ୍‌ ଅନୁମତି ଦିଅନ୍ତି ନାହିଁ"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"ଆପଣଙ୍କର ଆଇଟି ଆଡ୍‌ମିନ୍‌ ଦ୍ୱାରା ସାଧାରଣ ପାସ୍‌ୱର୍ଡଗୁଡ଼ିକୁ ରୋକିଦିଆଯାଇଛି। ଏକ ଭିନ୍ନ ପାସ୍‌ୱର୍ଡ ଦିଅନ୍ତୁ।"</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"ସଂଖ୍ୟାର କ୍ରମବୃଦ୍ଧି, କ୍ରମହ୍ରାସ, କିମ୍ବା ପୁନରାବୃତ୍ତ କ୍ରମ ଅନୁମୋଦିତ ନୁହେଁ"</string>
@@ -727,7 +730,7 @@
     <string name="bluetooth_settings_title" msgid="7261244857456521825">"ବ୍ଲୁଟୂଥ୍‍‌"</string>
     <string name="bluetooth_settings_summary" msgid="1221689092429277887">"ସଂଯୋଗଗୁଡ଼ିକର ପରିଚାଳନା, ଡିଭାଇସ୍‌ ନାମ ଓ ଖୋଜିବାଯୋଗ୍ୟତା ସେଟ୍‍ କରନ୍ତୁ"</string>
     <string name="bluetooth_pairing_request" msgid="7221745525632573125">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ସହ ପେୟାର୍‌ କରିବେ?"</string>
-    <string name="bluetooth_pairing_key_msg" msgid="1139230917419961975">"ବ୍ଲୁଟୂଥ୍‍‌ ପେୟାରିଂ କୋଡ୍"</string>
+    <string name="bluetooth_pairing_key_msg" msgid="1139230917419961975">"ବ୍ଲୁଟୁଥ ପେୟାରିଂ କୋଡ୍"</string>
     <string name="bluetooth_enter_passkey_msg" msgid="6205151011298670207">"ପେୟାରିଂ କୋଡ୍ ଟାଇପ୍‌ କରନ୍ତୁ ତାପରେ ଫେରନ୍ତୁ କିମ୍ବା ପ୍ରବେଶ ଦବାନ୍ତୁ"</string>
     <string name="bluetooth_enable_alphanumeric_pin" msgid="9138308197078115672">"ପିନ୍‌ରେ ଅକ୍ଷର କିମ୍ୱା ସଙ୍କେତ ରହିଥାଏ"</string>
     <string name="bluetooth_pin_values_hint" msgid="8044671726261326240">"ସାଧାରଣତଃ 0000 କିମ୍ବା 1234"</string>
@@ -737,7 +740,7 @@
     <string name="bluetooth_confirm_passkey_msg" msgid="7094455604290076371">"ଏହା ସହ ପେୟାର୍‌ କରିବାକୁ:&lt;br&gt;&lt;b&gt;<xliff:g id="DEVICE_NAME">%1$s</xliff:g>&lt;/b&gt;&lt;br&gt;&lt;br&gt;ନିଶ୍ଚିତ କରନ୍ତୁ ଏହା ଦେଖାଉଛି ପାସ୍‌‌କୀ:&lt;br&gt;&lt;b&gt;<xliff:g id="PASSKEY">%2$s</xliff:g>&lt;/b&gt;"</string>
     <string name="bluetooth_incoming_pairing_msg" msgid="940451919337185024">"ଏହାଙ୍କ ପାଖରୁ:&lt;br&gt;&lt;b&gt;<xliff:g id="DEVICE_NAME">%1$s</xliff:g>&lt;/b&gt;&lt;br&gt;&lt;br&gt;ଏହି ଡିଭାଇସ୍‌ ସହ ପେୟାର୍‌ କରିବେ?"</string>
     <string name="bluetooth_display_passkey_pin_msg" msgid="5909423849232791647">"ପେୟାର୍‌ କରିବା ପାଇଁ:<xliff:g id="BOLD1_0">&lt;br&gt;&lt;b&gt;</xliff:g><xliff:g id="DEVICE_NAME">%1$s</xliff:g><xliff:g id="END_BOLD1">&lt;/b&gt;&lt;br&gt;&lt;br&gt;</xliff:g>ଏହା ଉପରେ ଟାଇପ୍ କରନ୍ତୁ:<xliff:g id="BOLD2_1">&lt;br&gt;&lt;b&gt;</xliff:g><xliff:g id="PASSKEY">%2$s</xliff:g><xliff:g id="END_BOLD2">&lt;/b&gt;</xliff:g>, ତା’ପରେ ରିଟର୍ନ କିମ୍ୱା ଏଣ୍ଟର୍ ଦାବନ୍ତୁ।"</string>
-    <string name="bluetooth_pairing_shares_phonebook" msgid="7474404818877079813">"ଆପଣଙ୍କ ଯୋଗାଯୋଗ ଓ କଲ୍‌ ହିଷ୍ଟୋରୀକୁ ଆକସେସ୍‌ ଦିଅନ୍ତୁ"</string>
+    <string name="bluetooth_pairing_shares_phonebook" msgid="7474404818877079813">"ଆପଣଙ୍କ ଯୋଗାଯୋଗ ଓ କଲ୍‌ ଇତିହାସକୁ ଆକସେସ୍‌ ଦିଅନ୍ତୁ"</string>
     <string name="bluetooth_error_title" msgid="5718761586633101960"></string>
     <string name="bluetooth_connecting_error_message" msgid="8473359363469518478">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ସହ ସଂଯୋଗ ସ୍ଥାପନା କରିପାରୁନାହିଁ।"</string>
     <string name="bluetooth_preference_scan_title" msgid="457781003962324807">"ଡିଭାଇସ୍‌ଗୁଡ଼ିକୁ ଖୋଜ"</string>
@@ -767,7 +770,7 @@
     <string name="ble_scan_notify_text" msgid="6290170236546386932">"ଲୋକେସନ୍‌ ସଠିକତାକୁ ଉନ୍ନତ କରିବା ପାଇଁ, ସିଷ୍ଟମ୍‌ ଆପ୍‍ ଓ ସେବାଗୁଡ଼ିକ ବ୍ଲୁଟୂଥ୍‍‌ ଡିଭାଇସ୍‌ଗୁଡ଼ିକୁ ଚିହ୍ନଟ କରିପାରିବେ। ଆପଣ ଏହାକୁ <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>ଖୋଜିବା ସେଟିଙ୍ଗରେ<xliff:g id="LINK_END_1">LINK_END</xliff:g>ବଦଳାଇପାରିବେ।"</string>
     <string name="bluetooth_connect_failed" msgid="1151234676456333786">"ସଂଯୋଗ କରିପାରୁନାହିଁ। ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
     <string name="device_details_title" msgid="726517818032923222">"ଡିଭାଇସ୍‌ର ବିବରଣୀ"</string>
-    <string name="bluetooth_device_mac_address" msgid="5328203122581150405">"ଡିଭାଇସ୍‌ର ବ୍ଲୁଟୂଥ୍‍‌ ଠିକଣା ହେଉଛି: <xliff:g id="ADDRESS">%1$s</xliff:g>"</string>
+    <string name="bluetooth_device_mac_address" msgid="5328203122581150405">"ଡିଭାଇସ୍‌ର ବ୍ଲୁଟୁଥ ଠିକଣା ହେଉଛି: <xliff:g id="ADDRESS">%1$s</xliff:g>"</string>
     <string name="bluetooth_unpair_dialog_title" msgid="3669848977755142047">"ଡିଭାଇସ୍‌ଟିକୁ ଭୁଲିଯିବେ?"</string>
     <string name="bluetooth_unpair_dialog_body" product="default" msgid="5998071227980078077">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ସହିତ ଆପଣଙ୍କ ଫୋନ୍‌ ଆଉ ପେୟାର୍‌ ହେବନାହିଁ"</string>
     <string name="bluetooth_unpair_dialog_body" product="tablet" msgid="4696157463230518866">"ଆପଣଙ୍କ ଟାବଲେଟ୍‌ ଏବେ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ସହ ପେୟାର୍‌ ହୋଇ ରହିବନାହିଁ"</string>
@@ -901,7 +904,7 @@
     <string name="wifi_ssid" msgid="6746270925975522641">"ନେଟ୍‌ୱାର୍କର ନାମ"</string>
     <string name="wifi_ssid_hint" msgid="5010024648106585165">"SSID ଲେଖନ୍ତୁ"</string>
     <string name="wifi_security" msgid="9136702039496152831">"ସୁରକ୍ଷା"</string>
-    <string name="wifi_hidden_network" msgid="6647772204699776833">"ଲୁଚିଥିବା ନେଟ୍‌ୱର୍କ"</string>
+    <string name="wifi_hidden_network" msgid="6647772204699776833">"ଲୁକ୍କାୟିତ ନେଟୱାର୍କ"</string>
     <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"ଯଦି ଆପଣଙ୍କ ରାଉଟର୍ ଗୋଟିଏ ନେଟ୍‌ୱର୍କ IDକୁ ପ୍ରସାରଣ ନକରେ କିନ୍ତୁ ଭବିଷ୍ୟତରେ ଆପଣ ତାହା ସହିତ କନେକ୍ଟ କରିବାକୁ ଚାହୁଁଛନ୍ତି, ତେବେ ଆପଣ ନେଟ୍‌ୱର୍କକୁ ଲୁକ୍କାୟିତ ଭାବେ ସେଟ୍ କରିପାରିବେ। \n\n ଏହା ଗୋଟିଏ ସୁରକ୍ଷା ପ୍ରଶ୍ନବାଚୀ ସୃଷ୍ଟି କରିପାରେ, କାରଣ ଆପଣଙ୍କ ଫୋନ୍ ନେଟ୍‌ୱର୍କ ପ୍ରାପ୍ତ କରିବା ପାଇଁ ନିୟମିତ ଭାବେ ନିଜର ସିଗନାଲ୍‌କୁ ପ୍ରସାରିତ କରିବ। \n\nଲୁକ୍କାୟିତ ଭାବେ ନେଟୱର୍କକୁ ସେଟ୍ କରିବା ଦ୍ଵାରା ରାଉଟର୍‌ର ସେଟିଙ୍ଗ ବଦଳିବ ନାହିଁ।"</string>
     <string name="wifi_signal" msgid="696548364467704808">"ସିଗନାଲର ଦକ୍ଷତା"</string>
     <string name="wifi_status" msgid="3439931558930689940">"ସ୍ଥିତି"</string>
@@ -912,23 +915,23 @@
     <string name="passpoint_label" msgid="7429247462404128615">"ମାଧ୍ୟମରେ ସେଭ୍‌ ହୋଇଛି"</string>
     <string name="passpoint_content" msgid="340527524510304327">"<xliff:g id="NAME">%1$s</xliff:g> କ୍ରେଡେନ୍ସିଆଲ୍‌"</string>
     <string name="wifi_eap_method" msgid="3752116941487485859">"EAP ପଦ୍ଧତି"</string>
-    <string name="please_select_phase2" msgid="5848080896810435677">"2ୟ ପର୍ଯ୍ୟାୟ ସତ୍ୟାପନ"</string>
+    <string name="please_select_phase2" msgid="5848080896810435677">"2ୟ ପର୍ଯ୍ୟାୟ ପ୍ରମାଣୀକରଣ"</string>
     <string name="wifi_eap_ca_cert" msgid="1496395241849383785">"CA ସାର୍ଟିଫିକେଟ୍‌"</string>
     <string name="wifi_eap_domain" msgid="3298302320003640130">"ଡୋମେନ୍"</string>
-    <string name="wifi_eap_user_cert" msgid="6786839531765719173">"ଉପଯୋଗକର୍ତ୍ତା ସର୍ଟିଫିକେଟ୍‌"</string>
+    <string name="wifi_eap_user_cert" msgid="6786839531765719173">"ଉପଯୋଗକର୍ତ୍ତା ସାର୍ଟିଫିକେଟ୍‌"</string>
     <string name="wifi_eap_identity" msgid="5280457017705738773">"ପରିଚୟ"</string>
     <string name="wifi_eap_anonymous" msgid="6352344972490839958">"ଅଜ୍ଞାତ ପରିଚୟ"</string>
     <string name="wifi_password" msgid="6942983531275177771">"ପାସ୍‌ୱର୍ଡ"</string>
-    <string name="wifi_show_password" msgid="7878398590772942202">"ପାସ୍‍ୱର୍ଡ ଦେଖାନ୍ତୁ"</string>
+    <string name="wifi_show_password" msgid="7878398590772942202">"ପାସୱାର୍ଡ ଦେଖାନ୍ତୁ"</string>
     <string name="wifi_ap_band_config" msgid="6565016368079288433">"AP ବ୍ୟାଣ୍ଡ ବାଛନ୍ତୁ"</string>
     <string name="wifi_ap_choose_auto" msgid="7927637960569365785">"ସ୍ୱତଃ"</string>
     <string name="wifi_ap_choose_2G" msgid="43198403259714736">"2.4 GHz ବ୍ୟାଣ୍ଡ"</string>
     <string name="wifi_ap_choose_5G" msgid="2624859713183683146">"5 GHz ବ୍ୟାଣ୍ଡ"</string>
-    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"5.0 GHz ବ୍ୟାଣ୍ଡ ପ୍ରାଥମିକତା ଦିଆଗଲା"</string>
+    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"5.0 GHz ବ୍ୟାଣ୍ଡକୁ ପ୍ରାଥମିକତା ଦିଆଯାଇଛି"</string>
     <string name="wifi_ap_2G" msgid="5793110086517338494">"2.4 GHz"</string>
     <string name="wifi_ap_5G" msgid="4584892544393675403">"2.4 GHz"</string>
     <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"ୱାଇ-ଫାଇ ହଟସ୍ପଟ୍ ପାଇଁ ଅତିକମ୍‌ରେ ଗୋଟିଏ ବ୍ୟାଣ୍ଡକୁ ଚୟନ କରନ୍ତୁ:"</string>
-    <string name="wifi_ip_settings" msgid="4636102290236116946">"IP ସେଟିଙ୍ଗ"</string>
+    <string name="wifi_ip_settings" msgid="4636102290236116946">"IP ସେଟିଂସ୍"</string>
     <string name="wifi_privacy_settings" msgid="4462092795794247809">"ଗୋପନୀୟତା"</string>
     <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"ଅନିୟମିତ MAC"</string>
     <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"ଏକ ଡିଭାଇସ୍‍ ଯୋଗ କରନ୍ତୁ"</string>
@@ -959,7 +962,7 @@
     <string name="wifi_dpp_share_hotspot" msgid="847987212473038179">"ହଟସ୍ପଟ୍‌ ସେୟାର୍ କରନ୍ତୁ"</string>
     <string name="wifi_dpp_lockscreen_title" msgid="3910665850075275963">"ସୁନିଶ୍ଚିତ କରାନ୍ତୁ ଏହା ଆପଣ ଅଟନ୍ତି"</string>
     <string name="wifi_dpp_wifi_password" msgid="8007558344032612455">"ୱାଇ-ଫାଇ ପାସ୍‍ୱର୍ଡ: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
-    <string name="wifi_dpp_hotspot_password" msgid="6172326289042241924">"ହଟସ୍ପଟ୍ ପାସ୍‌ୱର୍ଡ: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
+    <string name="wifi_dpp_hotspot_password" msgid="6172326289042241924">"ହଟସ୍ପଟ୍ ପାସୱାର୍ଡ: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
     <string name="wifi_dpp_add_device" msgid="1347056725253936358">"ଡିଭାଇସ୍‌ ଯୋଗ କରନ୍ତୁ"</string>
     <string name="wifi_dpp_connect_network_using_qr_code" msgid="115993715600532357">"ଏକ QR କୋଡ୍ ବ୍ୟବହାର କରି ଏହି ନେଟ୍‌ୱର୍କ ସହ ସଂଯୋଗ କରନ୍ତୁ"</string>
     <string name="retry" msgid="8500839563577344702">"ପୁନଃଚେଷ୍ଟା କରନ୍ତୁ"</string>
@@ -967,7 +970,7 @@
     <string name="wifi_unchanged" msgid="6804964646942333992">"(ଅପରିବର୍ତ୍ତିତ)"</string>
     <string name="wifi_unspecified" msgid="893491188483500809">"ଦୟାକରି ଚୟନ କରନ୍ତୁ"</string>
     <string name="wifi_multiple_cert_added" msgid="7986200585749147204">"(ଅନେକ ପ୍ରମାଣପତ୍ର ଯୋଡ଼ାଗଲା)"</string>
-    <string name="wifi_use_system_certs" msgid="4794489370929885022">"ସିଷ୍ଟମ୍‌ ସର୍ଟିଫିକେଟ୍‌ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+    <string name="wifi_use_system_certs" msgid="4794489370929885022">"ସିଷ୍ଟମ୍‌ ସାର୍ଟିଫିକେଟ ବ୍ୟବହାର କରନ୍ତୁ"</string>
     <string name="wifi_do_not_provide_eap_user_cert" msgid="4044301449482425250">"ପ୍ରଦାନ କରନ୍ତୁ ନାହିଁ"</string>
     <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"ବୈଧ କରନ୍ତୁ ନାହିଁ"</string>
     <string name="wifi_do_not_validate_eap_server_warning" msgid="3895397996759837323">"କୌଣସି ସର୍ଟିଫିକେଟ୍‌ ଦର୍ଶାଯାଇନାହିଁ। ଆପଣଙ୍କ ସଂଯୋଗ ଗୋପନ ରହିବ ନାହିଁ।"</string>
@@ -1025,7 +1028,7 @@
     <string name="wifi_subscribed_access_points_tab" msgid="7498765485953257229">"ସଦସ୍ୟତା"</string>
     <!-- no translation found for wifi_saved_access_points_tab (4677730543624191122) -->
     <skip />
-    <string name="wifi_advanced_settings_label" msgid="9147669851658738784">"IP ସେଟିଙ୍ଗ"</string>
+    <string name="wifi_advanced_settings_label" msgid="9147669851658738784">"IP ସେଟିଂସ୍"</string>
     <string name="wifi_advanced_not_available" msgid="5751084989400195009">"ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ୱାଇ-ଫାଇ ଉନ୍ନତ ସେଟିଙ୍ଗ ଉପଲବ୍ଧ ନାହିଁ"</string>
     <string name="wifi_ip_settings_menu_save" msgid="6557330818360425933">"ସେଭ୍‌ କରନ୍ତୁ"</string>
     <string name="wifi_ip_settings_menu_cancel" msgid="8098696509412462494">"କ୍ୟାନ୍ସଲ୍‌ କରନ୍ତୁ"</string>
@@ -1043,7 +1046,7 @@
     <string name="wifi_p2p_menu_search" msgid="8207638860263805291">"ଡିଭାଇସ୍‌ଗୁଡିକ ସନ୍ଧାନ କରନ୍ତୁ"</string>
     <string name="wifi_p2p_menu_searching" msgid="7443249001543208106">"ଖୋଜୁଛି..."</string>
     <string name="wifi_p2p_menu_rename" msgid="2129974878377065488">"ଡିଭାଇସ୍‌କୁ ଅନ୍ୟ ନାମ ଦିଅନ୍ତୁ"</string>
-    <string name="wifi_p2p_peer_devices" msgid="8232126067045093382">"ପୀର୍‌ ଡିଭାଇସ୍‌ଗୁଡିକ"</string>
+    <string name="wifi_p2p_peer_devices" msgid="8232126067045093382">"ପିଅର୍ ଡିଭାଇସ୍‌"</string>
     <string name="wifi_p2p_remembered_groups" msgid="1356458238836730346">"ସୁପାରିସକୃତ ଗ୍ରୁପ୍ସ"</string>
     <string name="wifi_p2p_failed_connect_message" msgid="6103436959132424093">"ସଂଯୋଗ କରିପାରିଲା ନାହିଁ।"</string>
     <string name="wifi_p2p_failed_rename_message" msgid="638656605352538706">"ଡିଭାଇସ୍‌କୁ ରିନେମ୍‌ କରିବାରେ ବିଫଳ"</string>
@@ -1099,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"ମୋବାଇଲ୍‌"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"ଯଦି ୱାଇ-ଫାଇ ଉପଲବ୍ଧ ନାହିଁ, ତେବେ ମୋବାଇଲ୍ ନେଟ୍‌ୱର୍କ ବ୍ୟବହାର କରନ୍ତୁ"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"ଯଦି ମୋବାଇଲ୍ ନେଟ୍‌ୱର୍କ ଉପଲବ୍ଧ ନାହିଁ, ତେବେ ୱାଇ-ଫାଇ ବ୍ୟବହାର କରନ୍ତୁ"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"ୱାଇ-ଫାଇ ମାଧ୍ୟମରେ କଲ୍ କରନ୍ତୁ ଯଦି ୱାଇ-ଫାଇ ରହିବ ନାହିଁ, ତେବେ କଲ୍ ସମାପ୍ତ ହୋଇଯିବ।"</string>
@@ -1164,7 +1170,7 @@
     <string name="accessibility_personal_account_title" msgid="7251761883688839354">"ବ୍ୟକ୍ତିଗତ ଆକାଉଣ୍ଟ - <xliff:g id="MANAGED_BY">%s</xliff:g>"</string>
     <string name="search_settings" msgid="5809250790214921377">"ସନ୍ଧାନ"</string>
     <string name="display_settings" msgid="1045535829232307190">"ଡିସ୍‌ପ୍ଲେ"</string>
-    <string name="accelerometer_title" msgid="2427487734964971453">"ଅଟୋ-ରୋଟେଟ୍‌ ସ୍କ୍ରୀନ୍‍"</string>
+    <string name="accelerometer_title" msgid="2427487734964971453">"ଅଟୋ-ରୋଟେଟ୍‌ ସ୍କ୍ରିନ୍"</string>
     <string name="color_mode_title" msgid="8164858320869449142">"ରଙ୍ଗ"</string>
     <string name="color_mode_option_natural" msgid="1292837781836645320">"ପ୍ରାକୃତିକ"</string>
     <string name="color_mode_option_boosted" msgid="453557938434778933">"ବର୍ଦ୍ଧିତ"</string>
@@ -1191,7 +1197,7 @@
     <string name="auto_brightness_very_low_title" msgid="8716493755125824074">"ବହୁତ ନିମ୍ନ"</string>
     <string name="auto_brightness_low_title" msgid="5005479920075366970">"ନିମ୍ନ"</string>
     <string name="auto_brightness_default_title" msgid="5446692891470912829">"ପୂର୍ବ-ନିର୍ଦ୍ଧାରିତ"</string>
-    <string name="auto_brightness_high_title" msgid="7653379331939225750">"ଅଧିକ"</string>
+    <string name="auto_brightness_high_title" msgid="7653379331939225750">"ଉଚ୍ଚ"</string>
     <string name="auto_brightness_very_high_title" msgid="6649896560889239565">"ବହୁ ଉଚ୍ଚ"</string>
     <string name="auto_brightness_subtitle" msgid="8516999348793100665">"ଆପଣଙ୍କ ପସନ୍ଦର ଉଜ୍ଜ୍ୱଳତା ସ୍ତର"</string>
     <string name="auto_brightness_off_summary" msgid="6162650416289359104">"ଉପଲବ୍ଧ ଆଲୋକ ପାଇଁ ଆଡ୍‌ଜଷ୍ଟ କରନ୍ତୁ ନାହିଁ"</string>
@@ -1215,7 +1221,7 @@
     <string name="night_display_status_title" msgid="1727020934735770319">"ସ୍ଥିତି"</string>
     <string name="night_display_temperature_title" msgid="8375126629902616296">"ତୀବ୍ରତା"</string>
     <string name="night_display_summary_off" msgid="8850539785332228069">"ବନ୍ଦ‌ / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
-    <string name="night_display_summary_off_auto_mode_never" msgid="8618824386434992487">"ଆଦୌ ସ୍ୱଚାଳିତ ଭାବେ ଅନ୍‌ ହେବନାହିଁ"</string>
+    <string name="night_display_summary_off_auto_mode_never" msgid="8618824386434992487">"ଆଦୌ ସ୍ୱଚାଳିତ ଭାବେ ଚାଲୁ ହେବ ନାହିଁ"</string>
     <string name="night_display_summary_off_auto_mode_custom" msgid="596847003171394411">"<xliff:g id="ID_1">%1$s</xliff:g> ରେ ସ୍ୱଚାଳିତ ଭାବେ ଅନ୍‌ ହେବ।"</string>
     <string name="night_display_summary_off_auto_mode_twilight" msgid="4071750976585359952">"ସୂର୍ଯ୍ୟାସ୍ତରେ ସ୍ୱଚାଳିତ ଭାବେ ଅନ୍‌ ହେବ।"</string>
     <string name="night_display_summary_on" msgid="6580571388791426596">"ଅନ୍‌ / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
@@ -1233,7 +1239,7 @@
     <string name="screen_timeout_title" msgid="150117777762864112">"ସ୍କ୍ରୀନ୍‌ ବନ୍ଦ‌ ହୁଏ"</string>
     <string name="screen_timeout_summary" msgid="8644192861778491060">"ନିଷ୍କ୍ରିୟତାର <xliff:g id="TIMEOUT_DESCRIPTION">%1$s</xliff:g> ପରେ"</string>
     <string name="wallpaper_settings_title" msgid="347390905813529607">"ୱାଲପେପର୍"</string>
-    <string name="style_and_wallpaper_settings_title" msgid="8898539141152705754">"ଶୈଳୀ ଏବଂ ୱାଲ୍‍‍ପେପର୍"</string>
+    <string name="style_and_wallpaper_settings_title" msgid="8898539141152705754">"ଷ୍ଟାଇଲ୍ ଏବଂ ୱାଲ୍‍‍ପେପର୍"</string>
     <string name="wallpaper_settings_summary_default" msgid="2626880032742784599">"ପୂର୍ବ-ନିର୍ଦ୍ଧାରିତ"</string>
     <string name="wallpaper_settings_summary_custom" msgid="8950504698015331202">"କଷ୍ଟମ୍‌"</string>
     <string name="wallpaper_suggestion_title" msgid="3012130414886743201">"ୱାଲପେପର୍‌ ବଦଳାନ୍ତୁ"</string>
@@ -1580,7 +1586,7 @@
     <string name="master_clear_title" msgid="1560712943955904673">"ସମସ୍ତ ଡାଟା ଖାଲି କରିଦିଅନ୍ତୁ (ଫ୍ୟାକ୍ଟୋରୀ ରିସେଟ୍‌)"</string>
     <string name="master_clear_short_title" msgid="919098101581335101">"ସମସ୍ତ ଡାଟା ଖାଲି କରିଦିଅନ୍ତୁ (ଫ୍ୟାକ୍ଟୋରୀ ରିସେଟ୍‌)"</string>
     <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"ଏହା, ଆପଣଙ୍କ ଟାବ୍‍‍ଲେଟ୍‍ର "<b>"ଇଣ୍ଟର୍ନଲ୍ ଷ୍ଟୋରେଜ୍‍‍"</b>"ରେ ଥିବା ସମସ୍ତ ଡାଟାକୁ ଖାଲି କରିଦେବ, ଯେପରିକି:\n\n"<li>"ଆପଣଙ୍କ Google ଆକାଉଣ୍ଟ"</li>\n<li>"ସିଷ୍ଟମ ଓ ଆପ୍ ଡାଟା ଓ ସେଟିଂସ୍"</li>\n<li>"ଡାଉନ୍‌ଲୋଡ୍‌ ହୋଇଥିବା ଆପ୍ "</li></string>
-    <string name="master_clear_desc" product="default" msgid="8765543541962866697">"ଏହା, ଆପଣଙ୍କ ଫୋନ୍‍ର "<b>"ଇଣ୍ଟର୍ନଲ୍ ଷ୍ଟୋରେଜ୍"</b>"ରେ ଥିବା ସମସ୍ତ ଡାଟାକୁ ଖାଲି କରିଦେବ, ଯେପରିକି:\n\n"<li>"ଆପଣଙ୍କ Google ଆକାଉଣ୍ଟ"</li>\n<li>"ସିଷ୍ଟମ ଓ ଆପ୍ ଡାଟା ଓ ସେଟିଂସ୍"</li>\n<li>"ଡାଉନ୍‌ଲୋଡ୍‌ ହୋଇଥିବା ଆପ୍"</li></string>
+    <string name="master_clear_desc" product="default" msgid="8765543541962866697">"ଏହା ଆପଣଙ୍କ ଫୋନ୍‍ର "<b>"ଇଣ୍ଟର୍ନଲ୍ ଷ୍ଟୋରେଜ୍"</b>"ରେ ଥିବା ସମସ୍ତ ଡାଟା ସହିତ ଏସବୁକୁ ଖାଲି କରିଦେବ:\n\n"<li>"ଆପଣଙ୍କ Google ଆକାଉଣ୍ଟ"</li>\n<li>"ସିଷ୍ଟମ ଓ ଆପ୍ ଡାଟା ଓ ସେଟିଂସ୍"</li>\n<li>"ଡାଉନ୍‌ଲୋଡ୍‌ ହୋଇଥିବା ଆପ୍"</li></string>
     <string name="master_clear_accounts" product="default" msgid="3432884235445405376">\n\n"ଆପଣ ବର୍ତ୍ତମାନ ନିମ୍ନ ଆକାଉଣ୍ଟଗୁଡ଼ିକରେ ସାଇନ୍‌ ଇନ୍‌ କରିଛନ୍ତି:\n"</string>
     <string name="master_clear_other_users_present" product="default" msgid="5993259656117566767">\n\n"ଏହି ଡିଭାଇସ୍‌ରେ ଅନ୍ୟ ଉପଯୋଗକର୍ତ୍ତାମାନେ ଅଛନ୍ତି।\n"</string>
     <string name="master_clear_desc_also_erases_external" msgid="3947303501615091903"><li>"ମ୍ୟୁଜିକ୍‌"</li>\n<li>"ଫଟୋ"</li>\n<li>"ଅନ୍ୟାନ୍ୟ ବ୍ୟବହାରକର୍ତ୍ତାଙ୍କ ଡାଟା"</li></string>
@@ -1602,24 +1608,24 @@
     <string name="master_clear_not_available" msgid="4676613348163652454">"ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଫ୍ୟାକ୍ଟୋରୀ ରିସେଟ୍‌ ଉପଲବ୍ଧ ନାହିଁ"</string>
     <string name="master_clear_progress_title" msgid="378953167274114857">"ଲିଭାଉଛି"</string>
     <string name="master_clear_progress_text" msgid="5418958116008976218">"ଦୟାକରି ଅପେକ୍ଷା କରନ୍ତୁ..."</string>
-    <string name="call_settings_title" msgid="5033906789261282752">"କଲ୍‌ ସେଟିଙ୍ଗ"</string>
+    <string name="call_settings_title" msgid="5033906789261282752">"କଲ୍‌ ସେଟିଂସ୍"</string>
     <string name="call_settings_summary" msgid="2119161087671450035">"ଭଏସ୍‌ମେଲ୍‌, କଲ୍‌ ଫର୍‌ୱାର୍ଡିଙ୍ଗ, କଲ୍‌ ୱେଟିଙ୍ଗ, କଲର୍‌ ID ସେଟ୍‌ କରନ୍ତୁ"</string>
-    <string name="tether_settings_title_usb" msgid="4265582654602420357">"USB ଟିଥରିଙ୍ଗ"</string>
+    <string name="tether_settings_title_usb" msgid="4265582654602420357">"USB ଟିଥରିଂ"</string>
     <string name="tether_settings_title_wifi" msgid="2060965130234484613">"ପୋର୍ଟବଲ୍‌ ହଟସ୍ପଟ୍‌"</string>
-    <string name="tether_settings_title_bluetooth" msgid="1999590158102569959">"ବ୍ଲୁଟୂଥ ଟିଥରିଙ୍ଗ"</string>
-    <string name="tether_settings_title_usb_bluetooth" msgid="1159128764162788159">"ଟିଥର୍‌ କରୁଛି"</string>
-    <string name="tether_settings_title_all" msgid="6935843543433954181">"ହଟସ୍ପଟ୍‌ ଓ ଟିଥରିଙ୍ଗ"</string>
+    <string name="tether_settings_title_bluetooth" msgid="1999590158102569959">"ବ୍ଲୁଟୁଥ ଟିଥରିଂ"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="1159128764162788159">"ଟିଥରିଂ"</string>
+    <string name="tether_settings_title_all" msgid="6935843543433954181">"ହଟସ୍ପଟ୍‌ ଓ ଟିଥରିଂ"</string>
     <string name="tether_settings_summary_hotspot_on_tether_on" msgid="1289593649526514499">"Hotspot ଅନ୍‌ ଅଛି, ଟିଥର୍‌ କରୁଛି"</string>
     <string name="tether_settings_summary_hotspot_on_tether_off" msgid="8010689354668285422">"ହଟସ୍ପଟ୍‌ ଅନ୍‌"</string>
-    <string name="tether_settings_summary_hotspot_off_tether_on" msgid="1349909238672649877">"ଟିଥର୍‌ କରୁଛି"</string>
+    <string name="tether_settings_summary_hotspot_off_tether_on" msgid="1349909238672649877">"ଟିଥରିଂ"</string>
     <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"ଡାଟା ସେଭର୍‌ ଅନ୍‌ ଥିବାବେଳେ ଟିଥର୍‌ କିମ୍ୱା ପୋର୍ଟେବଲ୍‌ ହଟ୍‌ସ୍ପଟ୍‌ ବ୍ୟବହାର କରିପାରିବ ନାହିଁ"</string>
     <string name="usb_title" msgid="7480927657535578688">"USB"</string>
-    <string name="usb_tethering_button_text" msgid="6242228383142012332">"USB ଟିଥରିଙ୍ଗ୍‌"</string>
-    <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"USB ମାଧ୍ୟମରେ ଫୋନ୍‌ର ଇଣ୍ଟରନେଟ୍‌ କନେକ୍ସନ୍ ସେୟାର୍‌ କରନ୍ତୁ"</string>
+    <string name="usb_tethering_button_text" msgid="6242228383142012332">"USB ଟିଥରିଂ"</string>
+    <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"USB ମାଧ୍ୟମରେ ଫୋନ୍‌ର ଇଣ୍ଟରନେଟ୍‌ ସଂଯୋଗ ସେୟାର୍‌ କରନ୍ତୁ"</string>
     <string name="usb_tethering_subtext" product="tablet" msgid="154536000235361034">"USB ମାଧ୍ୟମରେ ଟାବ୍‌ଲେଟ୍‌ର ଇଣ୍ଟର୍‌ନେଟ୍‌ ସଂଯୋଗ ସେୟାର୍‌ କରନ୍ତୁ"</string>
-    <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"ବ୍ଲୁଟୂଥ୍‍ ଟିଥରିଙ୍ଗ"</string>
+    <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"ବ୍ଲୁଟୁଥ ଟିଥରିଂ"</string>
     <string name="bluetooth_tethering_subtext" product="tablet" msgid="6868756914621131635">"ବ୍ଲୁଟୂଥ୍‍‍ ମାଧ୍ୟରେ ଟାବ୍‌ଲେଟ୍‌ର ଇଣ୍ଟରନେଟ୍‌ ସଂଯୋଗ ସେୟାର୍ କରନ୍ତୁ"</string>
-    <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"ବ୍ଲୁଟୂଥ୍‌ ମାଧ୍ୟମରେ ଫୋନ୍‌ର ଇଣ୍ଟରନେଟ୍‌ ସଂଯୋଗ ସେୟାର୍‌ କରନ୍ତୁ"</string>
+    <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"ବ୍ଲୁଟୁଥ ମାଧ୍ୟମରେ ଫୋନ୍‌ର ଇଣ୍ଟରନେଟ୍‌ ସଂଯୋଗ ସେୟାର୍‌ କରନ୍ତୁ"</string>
     <string name="bluetooth_tethering_off_subtext_config" msgid="3981528184780083266">"ବ୍ଲୁଟୂଥ୍‍‌ ମାଧ୍ୟମରେ ଏହି <xliff:g id="DEVICE_NAME">%1$d</xliff:g>ର ଇଣ୍ଟରନେଟ୍‌ ସଂଯୋଗ ସେୟାର୍‌ କରୁଛି"</string>
     <string name="bluetooth_tethering_overflow_error" msgid="6946561351369376943">"<xliff:g id="MAXCONNECTION">%1$d</xliff:g> ଡିଭାଇସ୍‌ଠାରୁ ଅଧିକ ସହ ଟିଥର୍‌ କରିପାରିବ ନାହିଁ।"</string>
     <string name="bluetooth_untether_blank" msgid="5428300773782256084">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>କୁ ଅନ୍‌ଟିଥର୍ କରାଯିବ"</string>
@@ -1657,8 +1663,8 @@
     <string name="location_scanning_screen_title" msgid="7663329319689413454">"ୱାଇ-ଫାଇ ଏବଂ ବ୍ଲୁଟୁଥ୍‌ ସ୍କାନିଂ"</string>
     <string name="location_scanning_wifi_always_scanning_title" msgid="6750542206763112172">"ୱାଇ-ଫାଇ ସ୍କାନିଂ"</string>
     <string name="location_scanning_wifi_always_scanning_description" msgid="4956048135941851712">"ଆପ୍ ଓ ସେବାଗୁଡ଼ିକୁ ଯେକୌଣସି ସମୟରେ ୱାଇ-ଫାଇ ନେଟ୍‌ୱର୍କ ଖୋଜିବାକୁ ଦିଅନ୍ତୁ, ଏପରିକି ୱାଇ-ଫାଇ ଅଫ୍‌ ଥିଲେ ମଧ୍ୟ। ଏହାକୁ ଲୋକେସନ୍‌ ଆଧାରିତ ଫିଚର୍ ଓ ସେବା ଇତ୍ୟାଦିକୁ ଉନ୍ନତ କରିବା ପାଇଁ ବ୍ୟବହାର କରାଯାଇପାରେ।"</string>
-    <string name="location_scanning_bluetooth_always_scanning_title" msgid="196241746742607453">"ବ୍ଲୁଟୂଥ୍‍‌ ସ୍କାନିଙ୍ଗ"</string>
-    <string name="location_scanning_bluetooth_always_scanning_description" msgid="3796673798637848690">"ଆପ୍ ଓ ସେବାଗୁଡ଼ିକୁ ଯେକୌଣସି ସମୟରେ ଆଖପାଖରେ ଥିବା ଡିଭାଇସ୍‌ ଖୋଜିବାକୁ ଦିଅନ୍ତୁ, ଏପରିକି ବ୍ଲୁଟୂଥ୍‍‌ ଅଫ୍‌ ଥିଲେ ମଧ୍ୟ। ଏହାକୁ ଲୋକେସନ୍‌ ଆଧାରିତ ଫିଚର୍ ଓ ସେବା ଇତ୍ୟାଦିକୁ ଉନ୍ନତ କରିବା ପାଇଁ ବ୍ୟବହାର କରାଯାଇପାରେ।"</string>
+    <string name="location_scanning_bluetooth_always_scanning_title" msgid="196241746742607453">"ବ୍ଲୁଟୁୁଥ ସ୍କାନିଂ"</string>
+    <string name="location_scanning_bluetooth_always_scanning_description" msgid="3796673798637848690">"ଆପ୍ ଓ ସେବାଗୁଡ଼ିକୁ ଯେ କୌଣସି ସମୟରେ ଆଖପାଖରେ ଥିବା ଡିଭାଇସଗୁଡ଼ିକୁ ସ୍କାନ୍ କରିବାକୁ ଦିଅନ୍ତୁ, ଏପରିକି ବ୍ଲୁଟୁଥ ବନ୍ଦ ଥିଲେ ମଧ୍ୟ। ଏହାକୁ ଲୋକେସନ୍‌ ଆଧାରିତ ଫିଚର୍ ଓ ସେବା ଇତ୍ୟାଦିକୁ ଉନ୍ନତ କରିବା ପାଇଁ ବ୍ୟବହାର କରାଯାଇପାରେ।"</string>
     <string name="managed_profile_location_services" msgid="224925483299159541">"କାର୍ଯ୍ୟ ପାଇଁ ଲୋକେସନ୍ ସମ୍ପର୍କିତ ସେବା"</string>
     <string name="location_network_based" msgid="1535812159327454835">"ୱାଇ-ଫାଇ ଓ ମୋବାଇଲ୍‌ ନେଟ୍‌ୱର୍କ ଲୋକେସନ୍‌"</string>
     <string name="location_neighborhood_level" msgid="8459352741296587916">"ଆପଣଙ୍କର ଲୋକେସନ୍‌କୁ ଶୀଘ୍ର ଜାଣିବା ପାଇଁ, ଆପ୍‌ଗୁଡ଼ିକୁ Googleର ଲୋକେସନ୍‌ ସେବାର ବ୍ୟବହାର କରିବାକୁ ଦିଅନ୍ତୁ। ଅଜଣା ଲୋକେସନ୍‌ର ତଥ୍ୟ ସଂଗ୍ରହ କରାଯାଇ Googleକୁ ପଠାଯିବ।"</string>
@@ -1700,7 +1706,7 @@
     <string name="settings_safetylegal_activity_unreachable" msgid="3541894966476445833">"ଆପଣଙ୍କ ପାଖରେ ଡାଟା ସଂଯୋଗ ନାହିଁ। ଏହି ସୂଚନାକୁ ଏବେ ଦେଖିବା ପାଇଁ, ଇଣ୍ଟରନେଟ୍‌ ସହ ସଂଯୁକ୍ତ ଥିବା ଯେକୌଣସି କମ୍ପ୍ୟୁଟର୍‌ରୁ %sକୁ ଯାଆନ୍ତୁ।"</string>
     <string name="settings_safetylegal_activity_loading" msgid="7680998654145172">"ଲୋଡ୍ କରୁଛି…"</string>
     <string name="confirm_device_credential_use_alternate_method" msgid="1279869272895739941">"ବୈକଳ୍ପିକ ପଦ୍ଧତି ବ୍ୟବହାର କରନ୍ତୁ"</string>
-    <string name="lockpassword_choose_your_screen_lock_header" msgid="6283518876031424798">"ସ୍କ୍ରୀନ୍‌ ଲକ୍‌ ସେଟ୍‌ କରନ୍ତୁ"</string>
+    <string name="lockpassword_choose_your_screen_lock_header" msgid="6283518876031424798">"ସ୍କ୍ରିନ୍‌ ଲକ୍‌ ସେଟ୍‌ କରନ୍ତୁ"</string>
     <string name="lockpassword_choose_your_password_message" msgid="2838273977481046536">"ସୁରକ୍ଷା ପାଇଁ ପାସ୍‌ୱର୍ଡ ସେଟ୍ କରନ୍ତୁ"</string>
     <string name="lockpassword_choose_your_password_header_for_fingerprint" msgid="4921343500484160894">"ଟିପଚିହ୍ନ ବ୍ୟବହାର କରିବା ପାଇଁ ପାସ୍‌ୱାର୍ଡ ସେଟ୍‌ କରନ୍ତୁ"</string>
     <string name="lockpassword_choose_your_pattern_header_for_fingerprint" msgid="314870151462139417">"ଟିପଚିହ୍ନ ବ୍ୟବହାର କରିବା ପାଇଁ ପାଟର୍ନ ସେଟ୍‌ କରନ୍ତୁ"</string>
@@ -1996,7 +2002,7 @@
     <string name="user_dict_settings_edit_dialog_title" msgid="6492621665762797309">"ଶବ୍ବ ସମ୍ପାଦନ କରନ୍ତୁ"</string>
     <string name="user_dict_settings_context_menu_edit_title" msgid="4577283176672181497">"ସମ୍ପାଦନ"</string>
     <string name="user_dict_settings_context_menu_delete_title" msgid="670470172230144069">"ଡିଲିଟ୍‌ କରନ୍ତୁ"</string>
-    <string name="user_dict_settings_empty_text" msgid="2774939221998982609">"ୟୁଜର୍ ଶବ୍ଦକୋଷରେ ଆପଣ କୌଣସି ଶବ୍ଦ ଯୋଡ଼ିନାହାନ୍ତି। ଶବ୍ଦ ଯୋଡ଼ିବା ପାଇଁ \"ଯୋଡ଼ନ୍ତୁ (+)\" ବଟନ୍‌ରେ ଟାପ୍‌ କରନ୍ତୁ।"</string>
+    <string name="user_dict_settings_empty_text" msgid="2774939221998982609">"ଉପଯୋଗକର୍ତ୍ତା ଶବ୍ଦକୋଷରେ ଆପଣ କୌଣସି ଶବ୍ଦ ଯୋଗ କରିନାହାଁନ୍ତି। ଶବ୍ଦ ଯୋଗ କରିବା ପାଇଁ \"ଯୋଗ(+)\" ବଟନ୍‌ରେ ଟାପ୍‌ କରନ୍ତୁ।"</string>
     <string name="user_dict_settings_all_languages" msgid="8839702015353418176">"ସମସ୍ତ ଭାଷାଗୁଡିକ ପାଇଁ"</string>
     <string name="user_dict_settings_more_languages" msgid="8345984308635521364">"ଆହୁରି ଭାଷାମାନ…"</string>
     <string name="testing" msgid="4255916838792186365">"ପରୀକ୍ଷା କରୁଛି"</string>
@@ -2030,26 +2036,26 @@
     <string name="usage_time_label" msgid="5615725415876461039">"ବ୍ୟବହାର ସମୟ"</string>
     <string name="accessibility_settings" msgid="9140621093888234485">"ଆକ୍ସେସିବିଲିଟୀ"</string>
     <string name="accessibility_settings_title" msgid="1687226556576913576">"ଆକ୍ସେସିବିଲିଟୀ ସେଟିଙ୍ଗ"</string>
-    <string name="accessibility_settings_summary" msgid="5742379519336396561">"ସ୍କ୍ରୀନ୍‌ ରିଡର୍‌, ପ୍ରଦର୍ଶନ, ଇଣ୍ଟରାକସନ କଣ୍ଟ୍ରୋଲ୍"</string>
-    <string name="vision_settings_title" msgid="7315352351051423944">"ଭିଜନ୍‌ ସେଟିଙ୍ଗ"</string>
-    <string name="vision_settings_description" msgid="3476589459009287332">"ନିଜର ଆବଶ୍ୟକତ ଅନୁସାରେ ଏହି ଡିଭାଇସ୍‌କୁ କଷ୍ଟମାଇଜ୍‌ କରିପାରିବେ। ଏହି ଦିବ୍ୟାଙ୍ଗମାନଙ୍କ ପାଇଁ ସୁବିଧାକୁ ପରେ ସେଟିଙ୍ଗରେ ବଦଳାଇହେବ।"</string>
+    <string name="accessibility_settings_summary" msgid="5742379519336396561">"ସ୍କ୍ରିନ୍ ରିଡର୍‌, ଡିସପ୍ଲେ, ଇଣ୍ଟରାକସନ କଣ୍ଟ୍ରୋଲ୍"</string>
+    <string name="vision_settings_title" msgid="7315352351051423944">"ଭିଜନ୍‌ ସେଟିଂସ୍"</string>
+    <string name="vision_settings_description" msgid="3476589459009287332">"ନିଜର ଆବଶ୍ୟକତା ଅନୁସାରେ ଆପଣ ଏହି ଡିଭାଇସ୍‌କୁ କଷ୍ଟମାଇଜ୍‌ କରିପାରିବେ। ଏଇ ଆକ୍ସେସିବିଲିଟୀ ଫିଚରଗୁଡ଼ିକୁ ପରେ ସେଟିଂସରେ ବଦଳା ଯାଇପାରିବ।"</string>
     <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"ଫଣ୍ଟ ସାଇଜ୍ ବଦଳାନ୍ତୁ"</string>
-    <string name="screen_reader_category_title" msgid="6300714148519645544">"ସ୍କ୍ରୀନ୍‌ ପାଠକ"</string>
-    <string name="audio_and_captions_category_title" msgid="6140472938769619212">"ଅଡିଓ ଓ ଅନ୍-ସ୍କ୍ରୀନ୍ ଟେକ୍ସଟ୍"</string>
+    <string name="screen_reader_category_title" msgid="6300714148519645544">"ସ୍କ୍ରିନ୍‌ ରିଡର୍"</string>
+    <string name="audio_and_captions_category_title" msgid="6140472938769619212">"ଅଡିଓ ଓ ଅନ୍-ସ୍କ୍ରିନ୍ ଟେକ୍ସଟ୍"</string>
     <string name="display_category_title" msgid="545168481672250195">"ଡିସ୍‌ପ୍ଲେ"</string>
     <string name="interaction_control_category_title" msgid="8775039211811947683">"ଇଣ୍ଟରାକସନ୍‌ ନିୟନ୍ତ୍ରଣ"</string>
     <string name="user_installed_services_category_title" msgid="4288689493753221319">"ଡାଉନ୍‌ଲୋଡ୍ ହୋଇଥିବା ସେବାଗୁଡିକ"</string>
     <string name="experimental_category_title" msgid="3797000069740110717">"ପରୀକ୍ଷାମୂଳକ"</string>
     <string name="feature_flags_dashboard_title" msgid="3153034144122754381">"ଫିଚର୍ ଫ୍ଲାଗ୍"</string>
     <string name="talkback_title" msgid="3717960404234260050">"Talkback"</string>
-    <string name="talkback_summary" msgid="6602857105831641574">"ଅନ୍ଧ କିମ୍ବା କମ୍‌ ଦୃଷ୍ଟି ଶକ୍ତିଥିବା ଲୋକଙ୍କ ପାଇଁ ମୁଖ୍ୟତଃ ସ୍କ୍ରିନ୍‌ ରିଡର୍‌ ଅଟେ"</string>
-    <string name="select_to_speak_summary" msgid="7514180457557735421">"ଜୋରରେ ପଢ଼ିବା ପାଇଁ ସ୍କ୍ରୀନ୍‌ ଉପରେ ଥିବା ଆଇଟମଗୁଡ଼ିକ ଉପରେ ଟାପ୍‌ କରନ୍ତୁ"</string>
+    <string name="talkback_summary" msgid="6602857105831641574">"ଦୃଷ୍ଟିହୀନ କିମ୍ବା କମ୍‌ ଦୃଷ୍ଟି ଶକ୍ତିଥିବା ଲୋକଙ୍କ ପାଇଁ ମୁଖ୍ୟତଃ ସ୍କ୍ରିନ୍‌ ରିଡର୍‌ ଅଟେ"</string>
+    <string name="select_to_speak_summary" msgid="7514180457557735421">"ଜୋରରେ ଶୁଣିବା ପାଇଁ ସ୍କ୍ରିନ୍‌ ଉପରେ ଥିବା ଆଇଟମଗୁଡ଼ିକ ଉପରେ ଟାପ୍‌ କରନ୍ତୁ"</string>
     <string name="accessibility_captioning_title" msgid="5878371993023439642">"କ୍ୟାପଶନ୍‌"</string>
     <string name="accessibility_screen_magnification_title" msgid="7250949681883917360">"ବଡ଼ କରିବା"</string>
     <string name="accessibility_screen_magnification_gestures_title" msgid="9199287875401817974">"ଟ୍ରିପଲ୍‌-ଟାପ୍‌ ଦ୍ୱାରା ମାଗ୍ନିଫାଏ କରନ୍ତୁ"</string>
     <string name="accessibility_screen_magnification_navbar_title" msgid="400655612610761242">"ବଟନ ସହ ବଡ଼ କରନ୍ତୁ"</string>
     <string name="accessibility_screen_magnification_state_navbar_gesture" msgid="1863831350878995600">"ବଟନ୍‌ ଓ ଟ୍ରିପଲ୍‌-ଟାପ୍‌ ଦ୍ଵାରା ମ୍ୟାଗ୍ନିଫାଏ କରନ୍ତୁ"</string>
-    <string name="accessibility_preference_magnification_summary" msgid="753307741814376312">"ସ୍କ୍ରୀନ୍‌ ଉପରେ ଜୁମ୍‌ ଇନ୍‌ କରନ୍ତୁ"</string>
+    <string name="accessibility_preference_magnification_summary" msgid="753307741814376312">"ସ୍କ୍ରିନ୍‌ ଉପରେ ଜୁମ୍‌ ଇନ୍‌ କରନ୍ତୁ"</string>
     <string name="accessibility_screen_magnification_short_summary" msgid="5698545174944494486">"ଜୁମ୍‌ କରିବାକୁ 3ଥର ଟାପ୍‌ କରନ୍ତୁ"</string>
     <string name="accessibility_screen_magnification_navbar_short_summary" msgid="5418767043532322397">"ଜୁମ୍‌ କରିବା ପାଇଁ ଗୋଟିଏ ବଟନ୍‌ ଉପରେ ଟାପ୍‌ କରନ୍ତୁ"</string>
     <string name="accessibility_screen_magnification_summary" msgid="3363006902079431772"><b>"ଜୁମ୍‌ କରିବାକୁ"</b>", ସ୍କ୍ରିନ୍‌ 3 ଥର ଦ୍ରୁତ ଭାବେ ଟାପ୍‌ କରନ୍ତୁ।\n"<ul><li>"ସ୍କ୍ରୋଲ୍‌ କରିବାକୁ 2 କିମ୍ବା ଅଧିକ ଆଙ୍ଗୁଠି ଟାଣନ୍ତୁ"</li>\n<li>"ଜୁମ୍‌ ଆଡଜଷ୍ଟ କରିବାକୁ 2 କିମ୍ବା ଅଧିକ ଆଙ୍ଗୁଠି ଚିମୁଟା ପରି ବ୍ୟବହାର କରନ୍ତୁ"</li></ul>\n\n<b>"ସାମୟିକ ଭାବେ ଜୁମ୍‌ କରିବାକୁ"</b>", ସ୍କ୍ରିନ୍‌ 3 ଥର ଦ୍ରୁତ ଭାବେ ଟାପ୍‌ କରନ୍ତୁ ଏବଂ 3 ନମ୍ବର ଟାପ୍‌ରେ ଆପଣଙ୍କ ଆଙ୍ଗୁଠିକୁ ତଳକୁ କରି ରଖନ୍ତୁ।\n"<ul><li>"ସ୍କ୍ରିନ୍ ଚାରିପାଖେ ବୁଲିବାକୁ ଡ୍ରାଗ୍‌ କରନ୍ତୁ"</li>\n<li>"ଜୁମ୍‌ ଆଉଟ୍‌ କରିବାକୁ ଆଙ୍ଗୁଠି ବାହାର କରି ଦିଅନ୍ତୁ"</li></ul>\n\n"କୀବୋର୍ଡ କିମ୍ବା ନେଭିଗେସନ୍‌ ବାର୍‌ରେ ଆପଣ ଜୁମ୍‌ ଇନ୍‌ କରିପାରିବେ ନାହିଁ।"</string>
@@ -2064,7 +2070,7 @@
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"ଆପ୍‌ ବଦଳିବାବେଳେ ସ୍କ୍ରୀନ୍‌କୁ ବଡ଼ କର"</string>
     <string name="accessibility_power_button_ends_call_prerefence_title" msgid="6172987104538172869">"ପାୱର୍‌ ବଟନ୍‌ କଲ୍‌ ସମାପ୍ତ କରେ"</string>
     <string name="accessibility_toggle_large_pointer_icon_title" msgid="9127905775116570565">"ବହୁତ ବଡ଼ ମାଉସ୍‌ ପଏଣ୍ଟର୍"</string>
-    <string name="accessibility_disable_animations" msgid="8378441317115710009">"ଆନିମେଶନ୍‌ଗୁଡ଼ିକୁ କାଢ଼ିଦିଅନ୍ତୁ"</string>
+    <string name="accessibility_disable_animations" msgid="8378441317115710009">"ଆନିମେସନ୍‌ଗୁଡ଼ିକୁ କାଢ଼ିଦିଅନ୍ତୁ"</string>
     <string name="accessibility_toggle_master_mono_title" msgid="899550848196702565">"ମୋନୋ ଅଡିଓ"</string>
     <string name="accessibility_toggle_master_mono_summary" msgid="3847052868469033235">"ଅଡିଓ ଚାଲୁଥିବା ସମ‍ୟରେ ଚାନେଲ୍‌ଗୁଡ଼ିକୁ ଯୋଡ଼ନ୍ତୁ"</string>
     <string name="accessibility_toggle_master_balance_title" msgid="8723492001092647562">"ଅଡିଓ ବ୍ୟାଲେନ୍ସ"</string>
@@ -2284,8 +2290,8 @@
     <string name="battery_tip_dialog_message" product="device" msgid="6348123094674390337">"ଆପଣଙ୍କ ଡିଭାଇସ୍ ସାଧାରଣ ତୁଳନାରେ ଅଧିକ ବ୍ୟବହାର କରାଯାଇଛି। ଆଶା କରାଯାଉଥିବା ସମୟଠାରୁ ଆପଣଙ୍କ ବ୍ୟାଟେରୀ ଶୀଘ୍ର ସରି ଯାଇପାରେ।\n\nପୂର୍ଣ୍ଣ ଚାର୍ଜ ହେବା ପରଠାରୁ ଅଧିକ ବ୍ୟବହୃତ ଆପ୍ସ।"</string>
     <string name="battery_tip_dialog_message_footer" msgid="1118827395267487197">"ଉଚ୍ଚ-ଶକ୍ତି ପୃଷ୍ଟଭୂମୀ କାର୍ଯ୍ୟ ଅନ୍ତର୍ଭୁକ୍ତ କରେ"</string>
     <plurals name="battery_tip_restrict_title" formatted="false" msgid="7140926804142734420">
-      <item quantity="other">%1$dଟି ଆପ୍‌କୁ ଅବରୋଧ କରନ୍ତୁ</item>
-      <item quantity="one">%1$dଟି ଆପ୍‌କୁ ଅବରୋଧ କରନ୍ତୁ</item>
+      <item quantity="other">%1$dଟି ଆପ୍‌କୁ ପ୍ରତିବନ୍ଧିତ କରନ୍ତୁ</item>
+      <item quantity="one">%1$dଟି ଆପ୍‌କୁ ପ୍ରତିବନ୍ଧିତ କରନ୍ତୁ</item>
     </plurals>
     <plurals name="battery_tip_restrict_handled_title" formatted="false" msgid="5509363095891806748">
       <item quantity="other">%2$dଟି ଆପ୍‌କୁ ସମ୍ପ୍ରତି ପ୍ରତିବନ୍ଧିତ କରାଯାଇଛି</item>
@@ -2311,7 +2317,7 @@
     <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"ଏହି ଆପ୍‌ ବ୍ୟାକ୍‌ଗ୍ରାଉଣ୍ଡରେ ବ୍ୟାଟେରୀ ବ୍ୟବହାର କରି ପାରିବ। ଆପଣଙ୍କ ବ୍ୟାଟେରୀ ଅନୁମାନ କରିଥିବା ସମୟର ପୂର୍ବରୁହିଁ ସରିଯାଇପାରେ।"</string>
     <string name="battery_tip_unrestrict_app_dialog_ok" msgid="9154938931448151479">"କାଢ଼ିଦିଅନ୍ତୁ"</string>
     <string name="battery_tip_unrestrict_app_dialog_cancel" msgid="7331148618292397166">"କ୍ୟାନ୍ସଲ୍"</string>
-    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"ଆପଣଙ୍କର ଆପ୍ ସାଧାରଣ ଭାବେ ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କରୁଛି। ଯଦି ଆପ୍ ଅଧିକ ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କରନ୍ତି, ତେବେ ଆପଣଙ୍କ ଫୋନ୍ ପଦକ୍ଷେପ ନେବା ପାଇଁ ଆପଣଙ୍କୁ ପରାମର୍ଶ ଦେବ। \n\n ବ୍ୟାଟେରୀ ଅଧିକ ଖର୍ଚ୍ଚ ହେଉଥିଲେ ଆପଣ ସର୍ବଦା ବ୍ୟାଟେରୀ ସେଭର୍‌କୁ ଚାଲୁ କରିପାରିବେ।"</string>
+    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"ଆପଣଙ୍କର ଆପ୍ସ ସାଧାରଣ ଭାବେ ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କରୁଛି। ଯଦି ଆପ୍ସ ଅଧିକ ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କରେ, ତେବେ ଆପଣଙ୍କ ଫୋନ୍ ପଦକ୍ଷେପ ନେବା ପାଇଁ ଆପଣଙ୍କୁ ପରାମର୍ଶ ଦେବ। \n\n ବ୍ୟାଟେରୀ ଅଧିକ ଖର୍ଚ୍ଚ ହେଉଥିଲେ ଆପଣ ସର୍ବଦା ବ୍ୟାଟେରୀ ସେଭର୍‌କୁ ଚାଲୁ କରିପାରିବେ।"</string>
     <string name="battery_tip_dialog_summary_message" product="tablet" msgid="1721081030632329647">"ଆପଣଙ୍କର ଆପ୍ ସାଧାରଣ ଭାବେ ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କରୁଛି। ଯଦି ଆପ୍ ଅଧିକ ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କରନ୍ତି, ତେବେ ଆପଣଙ୍କ ଟାବଲେଟ୍ ପଦକ୍ଷେପ ନେବା ପାଇଁ ଆପଣଙ୍କୁ ପରାମର୍ଶ ଦେବ। \n\n ବ୍ୟାଟେରୀ ଅଧିକ ଖର୍ଚ୍ଚ ହେଉଥିଲେ ଆପଣ ସର୍ବଦା ବ୍ୟାଟେରୀ ସେଭର୍‌କୁ ଚାଲୁ କରିପାରିବେ।"</string>
     <string name="battery_tip_dialog_summary_message" product="device" msgid="146872407040848465">"ଆପଣଙ୍କର ଆପ୍ ସାଧାରଣ ଭାବେ ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କରୁଛି। ଯଦି ଆପ୍ ଅଧିକ ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କରନ୍ତି, ତେବେ ଡିଭାଇସ୍ ପଦକ୍ଷେପ ନେବା ପାଇଁ ଆପଣଙ୍କୁ ପରାମର୍ଶ ଦେବ। \n\n ବ୍ୟାଟେରୀ ଅଧିକ ଖର୍ଚ୍ଚ ହେଉଥିଲେ ଆପଣ ସର୍ବଦା ବ୍ୟାଟେରୀ ସେଭର୍‌କୁ ଚାଲୁ କରିପାରିବେ।"</string>
     <string name="smart_battery_manager_title" msgid="5744035036663849515">"ବ୍ୟାଟେରୀ ମ୍ୟାନେଜର୍‌"</string>
@@ -2909,7 +2915,7 @@
     <string name="apps_with_restrictions_header" msgid="8656739605673756176">"ପ୍ରତିବନ୍ଧକ ସହ ଆପ୍ଲିକେଶନ୍‌ଗୁଡିକ"</string>
     <string name="apps_with_restrictions_settings_button" msgid="5065896213467171744">"ଆପ୍ଲିକେଶନ୍‌ ପାଇଁ ସେଟିଙ୍ଗ ସମ୍ପ୍ରସାରଣ କରନ୍ତୁ"</string>
     <string name="nfc_payment_settings_title" msgid="5070077706735415291">"ଟାପ୍‌ କରି ପୈଠ କରନ୍ତୁ"</string>
-    <string name="nfc_payment_how_it_works" msgid="7607901964687787177">"ଏହା ଏହିପରି କାମ କରେ"</string>
+    <string name="nfc_payment_how_it_works" msgid="7607901964687787177">"ଏହା କିପରି କାମ କରେ"</string>
     <string name="nfc_payment_no_apps" msgid="8844440783395420860">"ଷ୍ଟୋର୍‌ରେ ନିଜ ଫୋନ୍ ଦ୍ୱାରା ପୈଠ କରନ୍ତୁ"</string>
     <string name="nfc_payment_default" msgid="7869273092463612271">"ଡିଫଲ୍ଟ ପେମେଣ୍ଟ"</string>
     <string name="nfc_payment_default_not_set" msgid="955804193510335338">"ସେଟ୍ ହୋଇ ନାହିଁ"</string>
@@ -2930,7 +2936,7 @@
     <string name="restriction_menu_change_pin" msgid="592512748243421101">"PIN ବଦଳାନ୍ତୁ"</string>
     <string name="app_notifications_switch_label" msgid="670683308275498821">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ"</string>
     <string name="help_label" msgid="1296484776243905646">"ସହାୟତା ଓ ମତାମତ"</string>
-    <string name="support_summary" msgid="3278943815956130740">"ସହାୟତା ନିବନ୍ଧ, ଫୋନ୍‌ ଓ ଚାଟ୍‌, ଆରମ୍ଭ କରିବା"</string>
+    <string name="support_summary" msgid="3278943815956130740">"ସହାୟତା ଆର୍ଟିକିଲ, ଫୋନ୍‌ ଓ ଚାଟ୍‌, ଆରମ୍ଭ କରିବା"</string>
     <string name="user_account_title" msgid="2108666882630552859">"କଣ୍ଟେଣ୍ଟ ପାଇଁ ଆକାଉଣ୍ଟ"</string>
     <string name="user_picture_title" msgid="6664602422948159123">"ଫଟୋ ଆଇଡି"</string>
     <string name="extreme_threats_title" msgid="1405820547540456436">"ଗୁରୁତର ବିପଦ"</string>
@@ -3032,13 +3038,13 @@
     <string name="connected_devices_dashboard_title" msgid="7795222675849060444">"ସଂଯୁକ୍ତ ଡିଭାଇସଗୁଡ଼ିକ"</string>
     <string name="connected_devices_dashboard_summary" msgid="1072664369515033179">"ବ୍ଲୁଟୂଥ୍‍‌, ଡ୍ରାଇଭିଙ୍ଗ ମୋଡ୍, NFC"</string>
     <string name="connected_devices_dashboard_no_nfc_summary" msgid="2610085597733526722">"ବ୍ଲୁଟୂଥ୍‍‌, ଡ୍ରାଇଭିଙ୍ଗ ମୋଡ୍"</string>
-    <string name="connected_devices_dashboard_no_driving_mode_summary" msgid="3524409078596318803">"ବ୍ଲୁଟୂଥ୍‍‌,NFC"</string>
+    <string name="connected_devices_dashboard_no_driving_mode_summary" msgid="3524409078596318803">"ବ୍ଲୁଟୁଥ,NFC"</string>
     <string name="connected_devices_dashboard_no_driving_mode_no_nfc_summary" msgid="7881286613528299400">"ବ୍ଲୁଟୂଥ୍‍‌"</string>
     <string name="app_and_notification_dashboard_title" msgid="8448096608058843730">"ଆପ୍‌ ଓ ବିଜ୍ଞପ୍ତି"</string>
     <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"Assistant,କିଛିସମୟ ପୂର୍ବରୁ ବ୍ୟବହୃତ ଆପ୍ସ,ଡିଫଲ୍ଟ ଆପ୍ସ"</string>
     <string name="notification_settings_work_profile" msgid="7190550347842400029">"ୱାର୍କ ପ୍ରୋଫାଇଲ୍‍ରେ ଆପ୍‍ସ ପାଇଁ ବିଜ୍ଞପ୍ତି ଆକ୍ସେସ ଉପଲବ୍ଧ ନାହିଁ."</string>
     <string name="account_dashboard_title" msgid="4734300939532555885">"ଆକାଉଣ୍ଟ"</string>
-    <string name="account_dashboard_default_summary" msgid="6822549669771936206">"କୌଣସି ଆକାଉଣ୍ଟ ଯୋଡ଼ାଯାଇନାହିଁ"</string>
+    <string name="account_dashboard_default_summary" msgid="6822549669771936206">"କୌଣସି ଆକାଉଣ୍ଟ ଯୋଗ କରାଯାଇନାହିଁ"</string>
     <string name="app_default_dashboard_title" msgid="6575301028225232193">"ଡିଫଲ୍ଟ ଆପ୍‌"</string>
     <string name="system_dashboard_summary" msgid="6582464466735779394">"ଭାଷା, ଜେଶ୍ଚର, ସମୟ, ବ୍ୟାକଅପ୍‌"</string>
     <string name="search_results_title" msgid="4160717656435503940">"ସେଟିଙ୍ଗ"</string>
@@ -3141,13 +3147,13 @@
     <string name="alarm_ringtone_title" msgid="6411326147408635902">"ଡିଫଲ୍ଟ ଆଲାର୍ମ ସାଉଣ୍ଡ"</string>
     <string name="vibrate_when_ringing_title" msgid="2757996559847126952">"କଲ୍‍ ପାଇଁ ଭାଇବ୍ରେଟ୍‍ କରନ୍ତୁ"</string>
     <string name="other_sound_settings" msgid="5250376066099818676">"ଅନ୍ୟାନ୍ୟ ଶବ୍ଦ"</string>
-    <string name="dial_pad_tones_title" msgid="8877212139988655769">"ଡାୟଲ୍‌ ପ୍ୟାଡ୍‌ ଟୋନ୍‍"</string>
+    <string name="dial_pad_tones_title" msgid="8877212139988655769">"ଡାଏଲ୍‌ ପ୍ୟାଡ୍‌ ଟୋନ୍‍"</string>
     <string name="screen_locking_sounds_title" msgid="4407110895465866809">"ସ୍କ୍ରୀନ୍‌ ଲକ୍‌ କରିବା ସାଉଣ୍ଡ"</string>
     <string name="charging_sounds_title" msgid="5070437987230894287">"ସାଉଣ୍ଡ ଓ ଭାଇବ୍ରେସନ୍ ଚାର୍ଜ ହେଉଛି"</string>
     <string name="docking_sounds_title" msgid="2573137471605541366">"ଡକ୍‌ କରିବା ଧ୍ୱନୀ"</string>
     <string name="touch_sounds_title" msgid="165237488496165652">"ସ୍ପର୍ଶ ଶବ୍ଦ"</string>
-    <string name="vibrate_on_touch_title" msgid="6360155469279157684">"ସ୍ପର୍ଶଜନିତ ଭାଇବ୍ରେଶନ୍"</string>
-    <string name="vibrate_on_touch_summary" msgid="5504424764028676043">"ଟ୍ୟାପ୍‌, କୀ-ବୋର୍ଡ ଓ ଆହୁରି ଅଧିକ ପାଇଁ ସ୍ପର୍ଶ ମାଧ୍ୟମରେ ମତାମତ"</string>
+    <string name="vibrate_on_touch_title" msgid="6360155469279157684">"ସ୍ପର୍ଶ ଭାଇବ୍ରେସନ୍"</string>
+    <string name="vibrate_on_touch_summary" msgid="5504424764028676043">"ଟ୍ୟାପ୍‌, କୀ-ବୋର୍ଡ ଓ ଆହୁରି ଅଧିକ ପାଇଁ ହେପଟିକ୍ ମତାମତ"</string>
     <string name="dock_audio_media_title" msgid="1859521680502040781">"ଡକ୍‌ ସ୍ପିକର୍‌ ବାଜିବ"</string>
     <string name="dock_audio_media_disabled" msgid="4300752306178486302">"ସମସ୍ତ ଅଡିଓ"</string>
     <string name="dock_audio_media_enabled" msgid="2873275045878628153">"କେବଳ ମିଡିଆ ଅଡିଓ"</string>
@@ -3162,7 +3168,7 @@
       <item quantity="other"><xliff:g id="ON_COUNT">%d</xliff:g>ଥର ସକ୍ଷମ କରାଯାଇଛି</item>
       <item quantity="one">1ଟି ସକ୍ଷମ କରାଯାଇଛି</item>
     </plurals>
-    <string name="zen_mode_settings_title" msgid="3425263414594779244">"ବିରକ୍ତ କର ନାହିଁ"</string>
+    <string name="zen_mode_settings_title" msgid="3425263414594779244">"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ"</string>
     <string name="zen_mode_settings_turn_on_dialog_title" msgid="3062548369931058282">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅନ୍ କରନ୍ତୁ"</string>
     <string name="zen_mode_behavior_settings_title" msgid="423125904296667490">"ବ୍ୟତିକ୍ରମ"</string>
     <string name="zen_mode_duration_settings_title" msgid="5522668871014735728">"ଡିଫଲ୍ଟ୍ ଅବଧି"</string>
@@ -3195,22 +3201,22 @@
     <string name="zen_mode_restrict_notifications_mute_footer" msgid="3049522809520549054">"ଯେତେବେଳେ ବିଜ୍ଞପ୍ତି ଦେଖାଦେବ, ଆପଣଙ୍କର ଫୋନରେ ସାଉଣ୍ଡ କିମ୍ବା ଭାଇବ୍ରେଟ୍ ହେବନାହିଁ।"</string>
     <string name="zen_mode_restrict_notifications_hide" msgid="3296933643539682552">"ବିଜ୍ଞପ୍ତି ଆସିଲେ କୌଣସି ଭିଜୁଆଲ୍ ଦେଖାଯିବ ନାହିଁ କିମ୍ବା ସାଉଣ୍ଡ୍‍ ବାହାରିବ ନାହିଁ"</string>
     <string name="zen_mode_restrict_notifications_hide_summary" msgid="1449301153755270168">"ଆପଣ ବିଜ୍ଞପ୍ତିଗୁଡିକୁ ଦେଖିପାରିବେ ନାହିଁ କିମ୍ବା ଶୁଣିପାରିବେ ନାହିଁ"</string>
-    <string name="zen_mode_restrict_notifications_hide_footer" msgid="7617688597593946765">"ଆପଣଙ୍କର ଫୋନ୍ ନୂଆ କିମ୍ବା ବିଦ୍ୟମାନ ଥିବା ବିଜ୍ଞପ୍ତିକୁ ପ୍ରଦର୍ଶନ କରିବ ନାହିଁ ତଥା ସେଥିପାଇଁ ଭାଇବ୍ରେଟ୍ ହେବ ନାହିଁ କିମ୍ବା ସାଉଣ୍ଡ କରିବ ନାହିଁ । ମନେରଖନ୍ତୁ ଯେ, ଫୋନ୍ କାର୍ଯ୍ୟକଳାପ ଏବଂ ସ୍ଥିତି ପାଇଁ ଗୁରୁତର ବିଜ୍ଞପ୍ତି ତଥାପି ଦୃଶ୍ୟମାନ ହେଉଥିବ।\n\nଆପଣ \'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\' ବନ୍ଦ କରିବା ସମୟରେ ସ୍କ୍ରିନ୍‌ର ଉପରୁ ତଳକୁ ସ୍ୱାଇପ୍‍ କରି ଛାଡ଼ି ଯାଇଥିବା ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଦେଖିପାରିବେ।"</string>
+    <string name="zen_mode_restrict_notifications_hide_footer" msgid="7617688597593946765">"ଆପଣଙ୍କର ଫୋନ୍ ନୂଆ କିମ୍ବା ବିଦ୍ୟମାନ ଥିବା ବିଜ୍ଞପ୍ତିକୁ ପ୍ରଦର୍ଶନ କରିବ ନାହିଁ ତଥା ସେଥିପାଇଁ ଭାଇବ୍ରେଟ୍ ହେବ ନାହିଁ କିମ୍ବା ସାଉଣ୍ଡ କରିବ ନାହିଁ । ମନେରଖନ୍ତୁ ଯେ, ଫୋନ୍ କାର୍ଯ୍ୟକଳାପ ଏବଂ ସ୍ଥିତି ପାଇଁ ଗୁରୁତ୍ୱପୂର୍ଣ୍ଣ ବିଜ୍ଞପ୍ତି ତଥାପି ଦେଖାଯିବ।\n\nଆପଣ \'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\' ବନ୍ଦ କରିବା ସମୟରେ ସ୍କ୍ରିନ୍‌ର ଉପରୁ ତଳକୁ ସ୍ୱାଇପ୍‍ କରି ଛାଡ଼ି ଯାଇଥିବା ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଦେଖିପାରିବେ।"</string>
     <string name="zen_mode_restrict_notifications_custom" msgid="3167252482570424133">"କଷ୍ଟମ"</string>
     <string name="zen_mode_restrict_notifications_enable_custom" msgid="6376983315529894440">"କଷ୍ଟମ ସେଟିଙ୍ଗକୁ ସକ୍ଷମ କରନ୍ତୁ"</string>
     <string name="zen_mode_restrict_notifications_disable_custom" msgid="8004212081465043044">"କଷ୍ଟମ ସେଟିଙ୍ଗକୁ କାଢ଼ିଦିଅନ୍ତୁ"</string>
     <string name="zen_mode_restrict_notifications_summary_muted" msgid="1075196788469381282">"ବିଜ୍ଞପ୍ତି ଆସିଲେ କୌଣସି ସାଉଣ୍ଡ ନାହିଁ"</string>
     <string name="zen_mode_restrict_notifications_summary_custom" msgid="4982187708274505748">"ଆଶିଂକ ଭାବେ ଲୁଚିଯାଇଛି"</string>
     <string name="zen_mode_restrict_notifications_summary_hidden" msgid="7637206880685474111">"ବିଜ୍ଞପ୍ତି ଆସିଲେ କୌଣସି ଭିଜୁଆଲ୍ ଦେଖାଯିବ ନାହିଁ କିମ୍ବା ସାଉଣ୍ଡ୍‍ ବାହାରିବ ନାହିଁ"</string>
-    <string name="zen_mode_what_to_block_title" msgid="2142809942549840800">"କଷ୍ଟମ୍ ସୀମାବଦ୍ଧତା"</string>
-    <string name="zen_mode_block_effects_screen_on" msgid="1042489123800404560">"ସ୍କ୍ରୀନ୍‌ ଅନ୍ ଥିବାବେଳେ"</string>
-    <string name="zen_mode_block_effects_screen_off" msgid="6380935819882837552">"ସ୍କ୍ରୀନ୍‌ ଅଫ୍ ଥିବାବେଳେ"</string>
+    <string name="zen_mode_what_to_block_title" msgid="2142809942549840800">"କଷ୍ଟମ୍ ରେଷ୍ଟ୍ରିକସନ୍"</string>
+    <string name="zen_mode_block_effects_screen_on" msgid="1042489123800404560">"ସ୍କ୍ରିନ୍‌ ଚାଲୁଥିବା ବେଳେ"</string>
+    <string name="zen_mode_block_effects_screen_off" msgid="6380935819882837552">"ସ୍କ୍ରିନ୍‌ ବନ୍ଦ ଥିବାବେଳେ"</string>
     <string name="zen_mode_block_effect_sound" msgid="1499243540186357631">"ସାଉଣ୍ଡ ଓ ଭାଇବ୍ରେଶନ୍‌କୁ ମ୍ୟୁଟ୍ କରନ୍ତୁ"</string>
-    <string name="zen_mode_block_effect_intent" msgid="5666951244667422668">"ସ୍କ୍ରୀନ୍ ଚାଲୁ କରନ୍ତୁ ନାହିଁ"</string>
+    <string name="zen_mode_block_effect_intent" msgid="5666951244667422668">"ସ୍କ୍ରିନ୍ ଚାଲୁ କରନ୍ତୁ ନାହିଁ"</string>
     <string name="zen_mode_block_effect_light" msgid="8679333758037487644">"ଆଲୋକ ଧପଧପ କରନ୍ତୁ ନାହିଁ"</string>
-    <string name="zen_mode_block_effect_peek" msgid="6075662813575910221">"ସ୍କ୍ରୀନ୍ ଉପରେ ବିଜ୍ଞପ୍ତି ଦେଖାନ୍ତୁ ନାହିଁ"</string>
+    <string name="zen_mode_block_effect_peek" msgid="6075662813575910221">"ସ୍କ୍ରିନ୍ ଉପରେ ବିଜ୍ଞପ୍ତି ଦେଖାନ୍ତୁ ନାହିଁ"</string>
     <string name="zen_mode_block_effect_status" msgid="6516614225115681068">"ସ୍କ୍ରିନ୍‌ର ଉପର ପାର୍ଶ୍ୱରେ ଦିଆଯାଇଥିବା ଷ୍ଟାଟସ୍‌ ବାର୍‌ ଆଇକନ୍‌ଗୁଡ଼ିକୁ ଲୁଚାନ୍ତୁ"</string>
-    <string name="zen_mode_block_effect_badge" msgid="3891743027347075136">"ଆପ୍‌ ଆଇକନ୍‌ଗୁଡ଼ିକରେ ବିନ୍ଦୁଗୁଡ଼ିକ ଦ୍ୱାରା ଚିହ୍ନିତ ବିଜ୍ଞପ୍ତିକୁ ଲୁଚାନ୍ତୁ"</string>
+    <string name="zen_mode_block_effect_badge" msgid="3891743027347075136">"ଆପ୍‌ ଆଇକନ୍‌ଗୁଡ଼ିକରେ ବିଜ୍ଞପ୍ତି ବିନ୍ଦୁଗୁଡ଼ିକୁ ଲୁଚାନ୍ତୁ"</string>
     <string name="zen_mode_block_effect_ambient" msgid="6382013125863616197">"ବିଜ୍ଞପ୍ତି ପାଇଁ ଜଗାନ୍ତୁ ନାହିଁ"</string>
     <string name="zen_mode_block_effect_list" msgid="6081548478844912181">"ବିଜ୍ଞପ୍ତି ତାଲିକାଠାରୁ ଲୁଚାନ୍ତୁ"</string>
     <string name="zen_mode_block_effect_summary_none" msgid="7166175186759564510">"ଆଦୌ ନୁହେଁ"</string>
@@ -3219,7 +3225,7 @@
     <string name="zen_mode_block_effect_summary_sound" msgid="4907185880913861880">"ଶବ୍ଦ ଓ କମ୍ପନ"</string>
     <string name="zen_mode_block_effect_summary_some" msgid="6035118904496072665">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ଶବ୍ଦ, କମ୍ପନ ଓ ଦୃଶ୍ୟ ସଂକେତ"</string>
     <string name="zen_mode_block_effect_summary_all" msgid="2830443565687247759">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ଶବ୍ଦ, ଦୃଶ୍ୟ ସଂକେତ"</string>
-    <string name="zen_mode_blocked_effects_footer" msgid="4375156159613413924">"ମୌଳିକ ଫୋନ୍ କାର୍ଯ୍ୟ ପାଇଁ ବିଜ୍ଞପ୍ତି ଆବଶ୍ୟକ ଏବଂ ଷ୍ଟାଟସ୍‌କୁ ଆଦୌ ଲୁଚାଇହେବ ନାହିଁ"</string>
+    <string name="zen_mode_blocked_effects_footer" msgid="4375156159613413924">"ମୌଳିକ ଫୋନ୍ କାର୍ଯ୍ୟ ଏବଂ ସ୍ଥିତି ପାଇଁ ଆବଶ୍ୟକ ବିଜ୍ଞପ୍ତି ଆଦୌ ଲୁଚାଇହେବ ନାହିଁ"</string>
     <string name="zen_mode_no_exceptions" msgid="3099578343994492857">"କିଛି ନୁହେଁ"</string>
     <string name="zen_mode_other_options" msgid="7216192179063769057">"ଅନ୍ୟାନ୍ୟ ବିକଲ୍ପ"</string>
     <string name="zen_mode_add" msgid="2533484377786927366">"ଯୋଡନ୍ତୁ"</string>
@@ -3227,7 +3233,7 @@
     <string name="zen_mode_button_turn_on" msgid="1097964136225943415">"ଏବେ ଅନ୍‌ କରନ୍ତୁ"</string>
     <string name="zen_mode_button_turn_off" msgid="3990967728457149454">"ବର୍ତ୍ତମାନ ବନ୍ଦ କରନ୍ତୁ"</string>
     <string name="zen_mode_settings_dnd_manual_end_time" msgid="4307574188962071429">"<xliff:g id="FORMATTED_TIME">%s</xliff:g> ପର୍ଯ୍ୟନ୍ତ \"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅନ୍‌ ରହିବ"</string>
-    <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"ଆପଣ ବନ୍ଦ ନକକରିବା ପର୍ଯ୍ୟନ୍ତ \'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\' ଅନ୍‌ ରହିବ"</string>
+    <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"ଆପଣ ବନ୍ଦ ନକରିବା ପର୍ଯ୍ୟନ୍ତ \'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\' ଚାଲୁ‌ ରହିବ"</string>
     <string name="zen_mode_settings_dnd_automatic_rule" msgid="2843297614114625408">"ଏକ (<xliff:g id="RULE_NAME">%s</xliff:g>) ନିୟମ ଦ୍ୱାରା ବିରକ୍ତ କର ନାହିଁ ସ୍ୱଚାଳିତ ଭାବେ ଚାଲୁ ହୋଇଗଲା"</string>
     <string name="zen_mode_settings_dnd_automatic_rule_app" msgid="5103454923160912313">"ଏକ ଆପ୍‌ (<xliff:g id="APP_NAME">%s</xliff:g>) ଦ୍ୱାରା ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ ସ୍ୱଚାଳିତ ଭାବେ ଅନ୍‌ ହେଲା"</string>
     <string name="zen_mode_settings_dnd_custom_settings_footer" msgid="6335108298640066560">"କଷ୍ଟମ୍ ସେଟିଂସ୍ ଥିବା <xliff:g id="RULE_NAMES">%s</xliff:g> ପାଇଁଁ ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଚାଲୁ ଅଛି।"</string>
@@ -3287,7 +3293,7 @@
     <string name="ringtones_install_custom_sound_title" msgid="210551218424553671">"କଷ୍ଟମ୍‌ ସାଉଣ୍ଡ ଯୋଡ଼ିବେ?"</string>
     <string name="ringtones_install_custom_sound_content" msgid="6683649115132255452">"<xliff:g id="FOLDER_NAME">%s</xliff:g> ଫୋଲ୍ଡର୍‌କୁ ଏହି ଫାଇଲ୍‌ କପୀ କରାଯିବ"</string>
     <string name="ringtones_category_preference_title" msgid="4491932700769815470">"ରିଙ୍ଗଟୋନ୍‌"</string>
-    <string name="other_sound_category_preference_title" msgid="2045757472469840859">"ଅନ୍ୟାନ୍ୟ ସାଉଣ୍ଡ ଓ ଭାଇବ୍ରେଶନ୍"</string>
+    <string name="other_sound_category_preference_title" msgid="2045757472469840859">"ଅନ୍ୟ ସାଉଣ୍ଡ ଓ ଭାଇବ୍ରେସନ୍"</string>
     <string name="configure_notification_settings" msgid="291914315140851270">"ବିଜ୍ଞପ୍ତି"</string>
     <string name="recent_notifications" msgid="8125865995065032049">"କିଛି ସମୟ ପୂର୍ବରୁ ବିଜ୍ଞପ୍ତି ପଠାଇଥିବା ଆପ୍"</string>
     <string name="recent_notifications_see_all_title" msgid="4089007770442871469">"ବିଗତ 7 ଦିନରୁ ସବୁଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ"</string>
@@ -3335,11 +3341,11 @@
     <string name="notification_importance_low" msgid="7609797151662295364">"ନିରବରେ ଦେଖାନ୍ତୁ"</string>
     <string name="notification_importance_default" msgid="4091563759103917166">"ଶବ୍ଦ କର"</string>
     <string name="notification_importance_high" msgid="7973764540402436656">"ଶବ୍ଦ କର ଓ ସ୍କ୍ରୀନ୍‌ ଉପରେ ଦେଖାଅ"</string>
-    <string name="notification_importance_high_silent" msgid="3177662759865661155">"ସ୍କ୍ରୀନ୍‌ ଉପରକୁ ଚାଲିଆସୁ"</string>
+    <string name="notification_importance_high_silent" msgid="3177662759865661155">"ସ୍କ୍ରିନ୍‌ ଉପରେ ଦେଖାନ୍ତୁ"</string>
     <string name="notification_importance_min_title" msgid="705872537330744154">"ଛୋଟ କରନ୍ତୁ"</string>
     <string name="notification_importance_low_title" msgid="2956199021781786232">"ମଧ୍ୟମ"</string>
     <string name="notification_importance_default_title" msgid="7985549807203332482">"ଉଚ୍ଚ"</string>
-    <string name="notification_importance_high_title" msgid="7258373094258585858">"ସ୍କ୍ରୀନ୍‌ରେ ଦେଖାନ୍ତୁ"</string>
+    <string name="notification_importance_high_title" msgid="7258373094258585858">"ସ୍କ୍ରିନ୍‌ ଉପରେ ଦେଖାନ୍ତୁ"</string>
     <string name="notification_block_title" msgid="2570364198866886906">"ବ୍ଲକ୍ କରନ୍ତୁ"</string>
     <string name="notification_silence_title" msgid="6959637402003838093">"ନିରବରେ ଦେଖାନ୍ତୁ"</string>
     <string name="notification_alert_title" msgid="750683027055192648">"ଆଲର୍ଟ"</string>
@@ -3378,10 +3384,10 @@
     <string name="display_vr_pref_title" msgid="1088464812293416981">"VRରେ ଡିଭାଇସ୍‌ ଥିବାବେଳେ"</string>
     <string name="display_vr_pref_low_persistence" msgid="3132583929174794245">"ବ୍ଲର୍ କମ କରନ୍ତୁ (ପ୍ରସ୍ତାବିତ)"</string>
     <string name="display_vr_pref_off" msgid="4681320968818852691">"ଫ୍ଲିକର୍‌କୁ କମ୍‌ କରନ୍ତୁ"</string>
-    <string name="picture_in_picture_title" msgid="4960733106166035448">"ଛବି-ଭିତରେ-ଛବି"</string>
+    <string name="picture_in_picture_title" msgid="4960733106166035448">"ପିକଚର୍-ଇନ୍-ପିକଚର୍"</string>
     <string name="picture_in_picture_empty_text" msgid="8664071475324685241">"ଛବି-ଭିତରେ-ଛବିକୁ ଇନ୍‌ଷ୍ଟଲ୍‌ ହୋଇଥିବା କୌଣସି ଆପ୍‌ ସପୋର୍ଟ କରୁନାହିଁ"</string>
     <string name="picture_in_picture_keywords" msgid="7326958702002259262">"ପିପ୍‌ ପିକଚର୍‌ ଇନ୍‌"</string>
-    <string name="picture_in_picture_app_detail_title" msgid="3916189052657425936">"ଛବି-ରେ-ଛବି"</string>
+    <string name="picture_in_picture_app_detail_title" msgid="3916189052657425936">"ପିକଚର୍-ଇନ୍-ପିକଚର୍"</string>
     <string name="picture_in_picture_app_detail_switch" msgid="747422998967185418">"ପିକଚର୍-ଇନ୍-ପିକଚରର ଅନୁମତି ଦିଅନ୍ତୁ"</string>
     <string name="picture_in_picture_app_detail_summary" msgid="918632751775525347">"ଏପ ଖୋଲା ଥିବାବେଳେ କିମ୍ୱା ଏହାକୁ ଆପଣ ଛାଡ଼ିବା ପରେ (ଉଦାହରଣସ୍ୱରୂପ, ଏକ ଭିଡିଓ ଦେଖିବା ଜାରି ରଖିବାକୁ) ଏକ ଛବି-ଭିତରେ-ଛବି ୱିଣ୍ଡୋ ତିଆରି କରିବା ପାଇଁ ଏହି ଏପକୁ ଅନୁମତି ଦିଅନ୍ତୁ। ଏହି ୱିଣ୍ଡୋ, ଆପଣ ବ୍ୟବହାର କରୁଥିବା ଅନ୍ୟ ଏପଗୁଡ଼ିକ ଉପରେ ଦେଖାଦେବ।"</string>
     <string name="manage_zen_access_title" msgid="3058206309728524196">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଆକ୍ସେସ୍"</string>
@@ -3417,7 +3423,7 @@
     <string name="notification_badge_title" msgid="8989086619255666442">"ବିଜ୍ଞପ୍ତି ଡଟ୍‌ର ଅନୁମତି ଦିଅନ୍ତୁ"</string>
     <string name="notification_channel_badge_title" msgid="8228215248332054612">"ବିଜ୍ଞପ୍ତି ଡଟ୍‌ ଦେଖାନ୍ତୁ"</string>
     <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"ବିରକ୍ତ କରନାହିଁ ଓଭରରାଇଡ"</string>
-    <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"’ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ’ ଅନ୍ ଥିବାବେଳେ ଏହି ବିଜ୍ଞପ୍ତିର ବାଧା ଦେବା ପ୍ରକ୍ରିୟାକୁ ଜାରି ରଖନ୍ତୁ"</string>
+    <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"\'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\' ଚାଲୁଥିବା ବେଳେ ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ବାଧା ଦେବା ପ୍ରକ୍ରିୟାକୁ ଜାରି ରଖନ୍ତୁ"</string>
     <string name="app_notification_visibility_override_title" msgid="2349335170165637672">"ଲକ୍ ସ୍କ୍ରୀନ୍ ଉପରେ"</string>
     <string name="app_notification_row_banned" msgid="2079325338122151677">"ଅବରୋଧିତ"</string>
     <string name="app_notification_row_priority" msgid="432299064888787236">"ପ୍ରାଥମିକତା"</string>
@@ -3700,13 +3706,13 @@
       <item quantity="other">ଆପ୍‌ଗୁଡ଼ିକ ବ୍ୟାଟେରୀ ସାରୁଛନ୍ତି</item>
       <item quantity="one"><xliff:g id="APP">%1$s</xliff:g> ବ୍ୟାଟେରୀ ସାରୁଛି</item>
     </plurals>
-    <string name="high_power_filter_on" msgid="5294209328473386403">"ଅନୁକୂଳିତ ନୁହେଁ"</string>
-    <string name="high_power_on" msgid="3573501822510580334">"ଅନୁକୁଳିତ ନୁହେଁ"</string>
+    <string name="high_power_filter_on" msgid="5294209328473386403">"ଅପ୍ଟିମାଇଜ୍ ହୋଇନାହିଁ"</string>
+    <string name="high_power_on" msgid="3573501822510580334">"ଅପ୍ଟିମାଇଜ୍ ହୋଇନାହିଁ"</string>
     <string name="high_power_off" msgid="5906679734326490426">"ଅପ୍ଟିମାଇଜିଂ ବ୍ୟାଟେରୀ ବ୍ୟବହାର"</string>
     <string name="high_power_system" msgid="739584574711292753">"ବ୍ୟାଟେରୀ ଅପ୍ଟିମାଇଜେସନ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
     <string name="high_power_desc" msgid="333756885680362741">"ବ୍ୟାଟେରୀ ଅପ୍ଟିମାଇଜେସନ୍ ଲାଗୁ କରନ୍ତୁ ନାହିଁ। ଏହା ଆପଣଙ୍କ ବ୍ୟାଟେରୀକୁ ଖୁବ ଶୀଘ୍ର ସାରିଦେଇପାରେ।"</string>
     <string name="high_power_prompt_title" msgid="2805745781720454052">"ଆପ୍‌ଟି ବ୍ୟାକ୍‌ଗ୍ରାଉଣ୍ଡରେ ସର୍ବଦା ଚାଲୁଥିବ କି?"</string>
-    <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g> କୁ ବ୍ୟାକ୍‌ଗ୍ରାଉଣ୍ଡରେ ଚାଲିବାକୁ ଦେବା ଦ୍ୱାରା ବ୍ୟାଟେରୀ ଜୀବନ କମ୍‌ ହୋଇପାରେ। \n\nଆପଣ ଏହାକୁ ପରେ ସେଟିଙ୍ଗ &gt; ଆପ୍‌ଗୁଡ଼ିକ ଓ ବିଜ୍ଞପ୍ତିସମୂହରେ ବଦଳାଇପାରିବେ।"</string>
+    <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g> କୁ ପୃଷ୍ଠପଟରେ ଚାଲିବାକୁ ଦେବା ଦ୍ୱାରା ବ୍ୟାଟେରୀ ଜୀବନ ହ୍ରାସ‌ ହୋଇପାରେ। \n\nଆପଣ ଏହାକୁ ପରେ ସେଟିଂସ୍ &gt; ଆପ୍‌ଗୁଡ଼ିକ ଓ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକରେ ବଦଳାଇପାରିବେ।"</string>
     <string name="battery_summary" msgid="4345690800899981339">"ଗତଥର ସମ୍ପୂର୍ଣ୍ଣ ଚାର୍ଜ ହେବା ପରଠାରୁ <xliff:g id="PERCENTAGE">%1$s</xliff:g> ବ୍ୟବହୃତ"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"ପାୱର ପରିଚାଳନା"</string>
     <string name="no_battery_summary" msgid="4105932628367471314">"ଶେଷ ଥରକ ପୂର୍ଣ୍ଣ ଚାର୍ଜ ହେବା ପରଠାରୁ ବ୍ୟାଟେରୀର କୌଣସି ବ୍ୟବହାର ହୋଇନାହିଁ"</string>
@@ -3727,7 +3733,7 @@
     <string name="usb_use_file_transfers_desc" msgid="6953866660041189580">"ଅନ୍ୟଏକ ଡିଭାଇସ୍‌କୁ ଫାଇଲ୍‌ ଟ୍ରାନ୍ସଫର୍‌ କରନ୍ତୁ"</string>
     <string name="usb_use_photo_transfers" msgid="5974236250197451257">"PTP"</string>
     <string name="usb_use_photo_transfers_desc" msgid="2325112887316125320">"ଯଦି MTP ସପୋର୍ଟ ହେଉନଥିବ, ତେବେ ଫୋଟୋ କିମ୍ୱା ଫାଇଲ୍‌ ଟ୍ରାନ୍ସଫର୍‌ କରନ୍ତୁ (PTP)"</string>
-    <string name="usb_use_tethering" msgid="4250626730173163846">"USB ଟିଥରିଙ୍ଗ"</string>
+    <string name="usb_use_tethering" msgid="4250626730173163846">"USB ଟିଥରିଂ"</string>
     <string name="usb_use_MIDI" msgid="4710632870781041401">"MIDI"</string>
     <string name="usb_use_MIDI_desc" msgid="1770966187150010947">"MIDI ଭାବରେ ଏହି ଡିଭାଇସ୍‌କୁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
     <string name="usb_use" msgid="8940500223316278632">"ଏହା ପାଇଁ USB ବ୍ୟବହାର କରନ୍ତୁ"</string>
@@ -3743,7 +3749,7 @@
     <string name="usb_summary_charging_only" msgid="4118449308708872339">"ଏହି ଡିଭାଇସ୍‌ ଚାର୍ଜ ହେଉଛି"</string>
     <string name="usb_summary_power_only" msgid="3552240122641051107">"କନେକ୍ଟ ହୋଇଥିବା ଡିଭାଇସ୍‍ ଚାର୍ଜ ହେଉଛି"</string>
     <string name="usb_summary_file_transfers" msgid="7805342797099821502">"ଫାଇଲ୍‌ ଟ୍ରାନ୍ସଫର୍‌"</string>
-    <string name="usb_summary_tether" msgid="778845069037366883">"USB ଟିଥରିଙ୍ଗ"</string>
+    <string name="usb_summary_tether" msgid="778845069037366883">"USB ଟିଥରିଂ"</string>
     <string name="usb_summary_photo_transfers" msgid="4743028167400644354">"PTP"</string>
     <string name="usb_summary_MIDI" msgid="5540604166270861247">"MIDI"</string>
     <string name="usb_summary_file_transfers_power" msgid="1684501026426766867">"ଫାଇଲ୍ ଟ୍ରାନ୍ସଫର୍ ଏବଂ ଯୋଗାଉଥିବା ପାୱର୍"</string>
@@ -3752,13 +3758,13 @@
     <string name="usb_summary_MIDI_power" msgid="7685597621357005180">"MIDI ଓ ଯୋଗାଉଥିବା ପାୱର୍"</string>
     <string name="background_check_pref" msgid="664081406854758392">"ବ୍ୟାକ୍‌ଗ୍ରାଉଣ୍ଡ ଯାଞ୍ଚ"</string>
     <string name="background_check_title" msgid="4136736684290307970">"ସମ୍ପୂର୍ଣ୍ଣ ବ୍ୟାକ୍‌ଗ୍ରାଉଣ୍ଡ ଆକସେସ୍‌"</string>
-    <string name="assist_access_context_title" msgid="2274614501747710439">"ସ୍କ୍ରୀନ୍‌ରୁ ଟେକ୍ସଟ୍‌ ବ୍ୟବହାର କର"</string>
-    <string name="assist_access_context_summary" msgid="5867997494395842785">"ସ୍କ୍ରୀନ୍‌ କଣ୍ଟେଣ୍ଟଗୁଡ଼ିକୁ ଟେକ୍ସଟ୍‌ ଭଳି ଆକ୍ସେସ୍‌ କରିବା ପାଇଁ ସହାୟକ ଆପ୍‌କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
-    <string name="assist_access_screenshot_title" msgid="1991014038776117688">"ସ୍କ୍ରୀନସଟ୍‌ ବ୍ୟବହାର କରନ୍ତୁ"</string>
-    <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"ସହାୟକ ଆପ୍‌କୁ ସ୍କ୍ରୀନ୍‌ର ଏକ ଇମେଜ୍‌ ଆକସେସ୍ କରିବାକୁ ଦିଅନ୍ତୁ"</string>
-    <string name="assist_flash_title" msgid="8852484250748551092">"ଫ୍ଲାଶ୍‌ ସ୍କ୍ରୀନ୍‌"</string>
-    <string name="assist_flash_summary" msgid="6697095786317559129">"ସ୍କ୍ରୀନ୍‌ କିମ୍ୱା ସ୍କ୍ରୀନଶଟ୍‌ରୁ ଯେତେବେଳେ ସହାୟକ ଆପ୍‌ ଟେକ୍ସଟ୍‌ ଆକ୍ସେସ୍‌ କରେ, ସ୍କ୍ରୀନ୍‌ର ଧାର ଫ୍ଲାଶ୍ ହେଉ"</string>
-    <string name="assist_footer" msgid="7030121180457472165">"ଆପଣ ଦେଖୁଥିବା ସ୍କ୍ରୀନ୍‌ ସୂଚନାକୁ ଆଧାର କରି ସହାୟକ ଆପ୍‌ ଆପଣଙ୍କୁ ସାହାଯ୍ୟ କରିପାରିବ। କେତେକ ଆପ୍‌,ଆପଣଙ୍କୁ ଉତ୍ତମ ସହାୟତା ଦେବାପାଇଁ, ଉଭୟ ଲଞ୍ଚର୍ ଓ ଭଏସ୍‍ ଇନପୁଟ୍‍ ସେବାକୁ ସମର୍ଥନ କରନ୍ତି।"</string>
+    <string name="assist_access_context_title" msgid="2274614501747710439">"ସ୍କ୍ରିନ୍‌ରୁ ଟେକ୍ସଟ୍‌ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+    <string name="assist_access_context_summary" msgid="5867997494395842785">"ସ୍କ୍ରିନ୍‌ ବିଷୟବସ୍ତୁଗୁଡ଼ିକୁ ଟେକ୍ସଟ୍‌ ଭଳି ଆକ୍ସେସ୍‌ କରିବା ପାଇଁ ସହାୟକ ଆପ୍‌କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+    <string name="assist_access_screenshot_title" msgid="1991014038776117688">"ସ୍କ୍ରିନସଟ୍‌ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+    <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"ସହାୟକ ଆପ୍‌କୁ ସ୍କ୍ରିନ୍‌ର ଏକ ଇମେଜ୍‌ ଆକସେସ୍ କରିବାକୁ ଦିଅନ୍ତୁ"</string>
+    <string name="assist_flash_title" msgid="8852484250748551092">"ଫ୍ଲାସ୍ ସ୍କ୍ରିନ୍‌"</string>
+    <string name="assist_flash_summary" msgid="6697095786317559129">"ସ୍କ୍ରିନ୍‌ କିମ୍ୱା ସ୍କ୍ରିନସଟ୍‌ରୁ ଯେତେବେଳେ ସହାୟକ ଆପ୍‌ ଟେକ୍ସଟ୍‌ ଆକ୍ସେସ୍‌ କରେ, ସ୍କ୍ରିନ୍‌ର ଧାର ଫ୍ଲାସ୍ କରନ୍ତୁ"</string>
+    <string name="assist_footer" msgid="7030121180457472165">"ଆପଣ ଦେଖୁଥିବା ସ୍କ୍ରିନ୍‌ ସୂଚନାକୁ ଆଧାର କରି ସହାୟକ ଆପ୍‌ ଆପଣଙ୍କୁ ସାହାଯ୍ୟ କରିପାରିବ। କେତେକ ଆପ୍‌,ଆପଣଙ୍କୁ ଉତ୍ତମ ସହାୟତା ଦେବାପାଇଁ, ଉଭୟ ଲଞ୍ଚର୍ ଓ ଭଏସ୍‍ ଇନପୁଟ୍‍ ସେବାକୁ ସମର୍ଥନ କରନ୍ତି।"</string>
     <string name="average_memory_use" msgid="5333366040118953945">"ହାରାହାରି ମେମୋରୀ ବ୍ୟବହାର"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"ସର୍ବାଧିକ ମେମୋରୀ ବ୍ୟବହାର"</string>
     <string name="memory_usage" msgid="7963253555330830906">"ମେମୋରୀ ବ୍ୟବହାର"</string>
@@ -3807,14 +3813,14 @@
     <string name="app_permission_summary_allowed" msgid="6458476982015518778">"ଅନୁମତିପ୍ରାପ୍ତ"</string>
     <string name="app_permission_summary_not_allowed" msgid="1171642541675462584">"ଅନୁମୋଦିତ ନୁହେଁ"</string>
     <string name="keywords_install_other_apps" msgid="5383559540695847668">"ଅଜଣ ଉତ୍ସରୁ ଆପ୍‌ଗୁଡ଼ିକୁ ଇନ୍‌ଷ୍ଟଲ୍‌ କରନ୍ତୁ"</string>
-    <string name="write_settings" msgid="9009040811145552108">"ସିଷ୍ଟମ୍‌ ସେଟିଙ୍ଗ ବଦଳାନ୍ତୁ"</string>
+    <string name="write_settings" msgid="9009040811145552108">"ସିଷ୍ଟମ୍‌ ସେଟିଂସ ବଦଳାନ୍ତୁ"</string>
     <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">"ଆର୍ଥିକ ଆପ୍ସ Smsର ଆକ୍ସେସ୍"</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>
+    <string name="write_system_settings" msgid="20450765210832463">"ସିଷ୍ଟମ୍‌ ସେଟିଂସ ବଦଳାନ୍ତୁ"</string>
     <string name="permit_write_settings" msgid="4198491281216818756">"ସିଷ୍ଟମ୍‌ ସେଟିଙ୍ଗ ବଦଳାଇବାକୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
     <string name="write_settings_description" msgid="2536706293042882500">"ଏହି ଅନୁମତି ଦ୍ୱାରା ଗୋଟିଏ ଏପ, ସିଷ୍ଟମ ସେଟିଙ୍ଗରେ ସଂଶୋଧନ କରିଥାଏ।"</string>
     <string name="write_settings_on" msgid="7328986337962635118">"ହଁ"</string>
@@ -3825,7 +3831,7 @@
     <string name="camera_double_tap_power_gesture_title" msgid="8874747801078147525">"କ୍ୟାମେରା ପାଇଁ ପାୱର୍‌ ବଟନ୍‌କୁ ଦୁଇଥର ଦବାନ୍ତୁ"</string>
     <string name="camera_double_tap_power_gesture_desc" msgid="6166349645433682873">"ନିଜ ଫୋନ୍‌କୁ ଅନ୍‌ଲକ୍‌ ନକରି ଶୀଘ୍ର କ୍ୟାମେରା ଖୋଲନ୍ତୁ"</string>
     <string name="screen_zoom_title" msgid="164369086350486104">"ଡିସ୍‌ପ୍ଲେ ସାଇଜ୍"</string>
-    <string name="screen_zoom_short_summary" msgid="5508079362742276703">"ସ୍କ୍ରୀନ୍‌ ଉପରେ ଥିବା ଆଇଟମ୍‌ଗୁଡ଼ିକୁ ବଡ଼ କିମ୍ୱା ଛୋଟ କରନ୍ତୁ"</string>
+    <string name="screen_zoom_short_summary" msgid="5508079362742276703">"ସ୍କ୍ରିନ୍‌ ଉପରେ ଥିବା ଆଇଟମ୍‌ଗୁଡ଼ିକୁ ବଡ଼ କିମ୍ୱା ଛୋଟ କରନ୍ତୁ"</string>
     <string name="screen_zoom_keywords" msgid="8358462497896524092">"ପ୍ରଦର୍ଶନ ଘନତ୍ତ୍ୱ, ସ୍କ୍ରିନ୍‌ ଜୁମ, ସ୍କେଲ୍, ସ୍କେଲିଂ"</string>
     <string name="screen_zoom_summary" msgid="5294003755961312560">"ଆଇଟମଟି ଆପଣଙ୍କ ସ୍କ୍ରୀନ୍‌ରେ ଛୋଟ କିମ୍ବା ବଡ କରନ୍ତୁ। ଆପଣଙ୍କ ସ୍କ୍ରୀନ୍‌ରେ କିଛି ଆପ୍ ସ୍ଥାନ ପରିବର୍ତ୍ତନ କରିପାରନ୍ତି।"</string>
     <string name="screen_zoom_preview_title" msgid="2924312934036753091">"ପ୍ରିଭ୍ୟୁ"</string>
@@ -3856,7 +3862,7 @@
     <string name="storage_summary_with_sdcard" msgid="8742907204848352697">"ଇଣ୍ଟର୍‌ନାଲ୍‌ ଷ୍ଟୋରେଜ୍‌: <xliff:g id="PERCENTAGE">%1$s</xliff:g> ବ୍ୟବହୃତ - <xliff:g id="FREE_SPACE">%2$s</xliff:g> ଖାଲି"</string>
     <string name="display_summary" msgid="5725269449657325797">"ନିଷ୍କ୍ରିୟତାର <xliff:g id="TIMEOUT_DESCRIPTION">%1$s</xliff:g> ପରେ ସୁପ୍ତାବସ୍ଥା"</string>
     <string name="display_dashboard_summary" msgid="7678566148167010682">"ୱାଲ୍‌ପେପର୍‌, ସୁପ୍ତ, ଫଣ୍ଟ ସାଇଜ୍‌"</string>
-    <string name="display_dashboard_summary_with_style" msgid="8981059474501210956">"ଶୈଳୀ ଏବଂ ୱାଲ୍‍ପେପର୍, ସ୍ଲିପ୍, ଫଣ୍ଟ ଆକାର"</string>
+    <string name="display_dashboard_summary_with_style" msgid="8981059474501210956">"ଷ୍ଟାଇଲ୍ ଏବଂ ୱାଲପେପର୍, ସ୍ଲିପ୍, ଫଣ୍ଟ ଆକାର"</string>
     <string name="display_dashboard_nowallpaper_summary" msgid="8612534364908229000">"ସ୍ଲିପ୍‍, ଫଣ୍ଟ ସାଇଜ୍"</string>
     <string name="display_summary_example" msgid="4555020581960719296">"କାମ ନ କରିବାର ୧୦ ମିନିଟ ପରେ ଶୁଆଇଦିଅ"</string>
     <string name="memory_summary" msgid="9121871336058042600">"<xliff:g id="TOTAL_MEMORY">%2$s</xliff:g> ମେମୋରୀର ହାରାହାରି <xliff:g id="USED_MEMORY">%1$s</xliff:g> ବ୍ୟବହୃତ"</string>
@@ -4004,7 +4010,7 @@
     <string name="lockscreen_remote_input" msgid="3363310613165354434">"ଯଦି ଡିଭାଇସ୍‌ ଲକ୍‌ ହୋଇଥାଏ, ବିଜ୍ଞପ୍ତିରେ ପ୍ରତ୍ୟୁତ୍ତର କିମ୍ବା ଅନ୍ୟାନ୍ୟ ଟେକ୍ସଟ୍‌ ଟାଇପ କରିବା ପ୍ରତିରୋଧ କରେ"</string>
     <string name="default_spell_checker" msgid="8636661093243189533">"ଡିଫଲ୍ଟ ବନାନ ଯାଞ୍ଚକାରୀ"</string>
     <string name="choose_spell_checker" msgid="7619860861923582868">"ବନାନ ଯାଞ୍ଚକାରୀ ବାଛନ୍ତୁ"</string>
-    <string name="spell_checker_master_switch_title" msgid="5712693172227400668">"ବନାନ୍ ଯାଞ୍ଚ କରୁଥିବା ଟୂଲ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+    <string name="spell_checker_master_switch_title" msgid="5712693172227400668">"ବନାନ ଯାଞ୍ଚକାରୀ ଟୁଲ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
     <string name="spell_checker_not_selected" msgid="331034541988255137">"ଚୟନ କରାଯାଇନାହିଁ"</string>
     <string name="notification_log_no_title" msgid="3668232437235348628">"(କିଛି ନାହିଁ)"</string>
     <string name="notification_log_details_delimiter" msgid="5485526744689532908">": "</string>
@@ -4131,7 +4137,7 @@
     <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"ସମୟ, ବିଜ୍ଞପ୍ତି, ଏବଂ ଅନ୍ୟ ସୂଚନାର ଯାଞ୍ଚ କରିବା ପାଇଁ, ଆପଣଙ୍କ ସ୍କ୍ରିନ୍‌କୁ ଟାପ୍ କରନ୍ତୁ।"</string>
     <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"ବିଜ୍ଞପ୍ତି ପାଇଁ ଟିପଚିହ୍ନ ସ୍ୱାଇପ୍‌ କରନ୍ତୁ"</string>
     <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"ଟିପଚିହ୍ନ ସ୍ୱାଇପ୍‌ କରନ୍ତୁ"</string>
-    <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଦେଖିବା ପାଇଁ, ନିଜ ଫୋନ୍‌ ପଛପଟେ ଥିବା ଆଙ୍ଗୁଠି ଚିହ୍ନ ସେନ୍ସର୍‌ ଉପରେ ଆଙ୍ଗୁଠି ରଖି ତଳକୁ ସ୍ୱାଇପ୍‌ କରନ୍ତୁ।"</string>
+    <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଦେଖିବା ପାଇଁ, ନିଜ ଫୋନ୍‌ ପଛପଟେ ଥିବା ଫିଙ୍ଗରପ୍ରିଣ୍ଟ ସେନ୍ସର୍‌ ଉପରେ ଆଙ୍ଗୁଠି ରଖି ତଳକୁ ସ୍ୱାଇପ୍‌ କରନ୍ତୁ।"</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="tablet" msgid="3480057984564476283">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଦେଖିବା ପାଇଁ, ନିଜ ଡିଭାଇସ୍‌ ପଛପଟେ ଥିବା ଆଙ୍ଗୁଠି ଚିହ୍ନ ସେନ୍ସର୍‌ ଉପରେ ଆଙ୍ଗୁଠି ରଖି ତଳକୁ ସ୍ୱାଇପ୍‌ କରନ୍ତୁ।"</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="device" msgid="7950264130913070035">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଦେଖିବା ପାଇଁ, ନିଜ ଫୋନ୍‌ ପଛପଟେ ଥିବା ଟିପଚିହ୍ନ ସେନ୍ସର୍‌ ଉପରେ ଆଙ୍ଗୁଠି ରଖି ତଳକୁ ସ୍ୱାଇପ୍‌ କରନ୍ତୁ।"</string>
     <string name="fingerprint_swipe_for_notifications_suggestion_title" msgid="948946491233738823">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ତୁରନ୍ତ ଦେଖନ୍ତୁ"</string>
@@ -4229,11 +4235,11 @@
     </plurals>
     <string name="app_names_concatenation_template_2" msgid="8267577900046506189">"<xliff:g id="FIRST_APP_NAME">%1$s</xliff:g>, <xliff:g id="SECOND_APP_NAME">%2$s</xliff:g>"</string>
     <string name="app_names_concatenation_template_3" msgid="5129064036161862327">"<xliff:g id="FIRST_APP_NAME">%1$s</xliff:g>, <xliff:g id="SECOND_APP_NAME">%2$s</xliff:g>, <xliff:g id="THIRD_APP_NAME">%3$s</xliff:g>"</string>
-    <string name="storage_photos_videos" msgid="1890829312367477559">"ଫଟୋ ଓ ଭିଡ଼ିଓ"</string>
+    <string name="storage_photos_videos" msgid="1890829312367477559">"ଫଟୋ ଓ ଭିଡିଓ"</string>
     <string name="storage_music_audio" msgid="3661289086715297149">"ମ୍ୟୁଜିକ୍‌ ଓ ଅଡିଓ"</string>
     <string name="storage_games" msgid="7740038143749092373">"ଗେମ୍‌"</string>
-    <string name="storage_other_apps" msgid="3202407095387420842">"ଅନ୍ୟାନ୍ୟ ଆପ୍‌"</string>
-    <string name="storage_files" msgid="2087824267937487880">"ଫାଇଲ୍"</string>
+    <string name="storage_other_apps" msgid="3202407095387420842">"ଅନ୍ୟ ଆପ୍ସ‌"</string>
+    <string name="storage_files" msgid="2087824267937487880">"Files"</string>
     <string name="storage_size_large_alternate" msgid="1317796542509105857">"<xliff:g id="NUMBER">^1</xliff:g>"<small>" "<font size="20">"<xliff:g id="UNIT">^2</xliff:g>"</font></small>""</string>
     <string name="storage_volume_total" msgid="5021484171514159913">"<xliff:g id="TOTAL">%1$s</xliff:g>ରୁ ବ୍ୟବହୃତ ହୋଇଛି"</string>
     <string name="storage_percent_full" msgid="6924662861545958442">"ବ୍ୟବହୃତ"</string>
@@ -4304,7 +4310,7 @@
     <string name="change_wifi_state_title" msgid="5140754955787584174">"ୱାଇ-ଫାଇର ନିୟନ୍ତ୍ରଣ"</string>
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"ୱାଇ-ଫାଇକୁ ନିୟନ୍ତ୍ରଣ କରିବା ପାଇଁ ଆପ୍‌କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
     <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"ୱାଇ-ଫାଇକୁ ଚାଲୁ କରିବା କିମ୍ବା ବନ୍ଦ କରିବା, ୱାଇ-ଫାଇ ନେଟୱର୍କକୁ ଖୋଜିବା ଓ କନେକ୍ଟ କରିବା, ନେଟୱର୍କକୁ ଯୋଡ଼ିବା କିମ୍ବା କାଢ଼ିଦେବା କିମ୍ବା କେବଳ ସୀମିତ କ୍ଷେତ୍ରରେ କାମ କରୁଥିବା ହଟସ୍ପଟ୍‌କୁ ଚାଲୁ କରିବା ପାଇଁ ଏହି ଆପ୍‌କୁ ଅନୁମତି ଦେବା"</string>
-    <string name="media_output_title" msgid="8710632337456601848">"ମିଡିଆ ଚଲାନ୍ତୁ"</string>
+    <string name="media_output_title" msgid="8710632337456601848">"ଏଥିରେ ମିଡିଆ ଚଲାନ୍ତୁ"</string>
     <string name="media_output_default_summary" msgid="3159237976830415584">"ଏହି ଡିଭାଇସ୍‍"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"ଫୋନ୍"</string>
     <string name="media_output_summary" product="tablet" msgid="6672024060360538526">"ଟାବଲେଟ୍‌"</string>
@@ -4323,8 +4329,8 @@
     <string name="prevent_ringing_option_vibrate" msgid="6456505293904544108">"କମ୍ପନ"</string>
     <string name="prevent_ringing_option_mute" msgid="53662688921253613">"ମ୍ୟୁଟ୍ କରନ୍ତୁ"</string>
     <string name="prevent_ringing_option_none" msgid="1450985763137666231">"କିଛି କରନ୍ତୁ ନାହିଁ"</string>
-    <string name="prevent_ringing_option_vibrate_summary" msgid="7961818570574683926">"(ଭାଇବ୍ରେଟ୍) ଅନ୍ ଅଛି"</string>
-    <string name="prevent_ringing_option_mute_summary" msgid="3509459199090688328">"(ମ୍ୟୁଟ୍) ଅନ୍ ଅଛି"</string>
+    <string name="prevent_ringing_option_vibrate_summary" msgid="7961818570574683926">"ଚାଲୁ (ଭାଇବ୍ରେଟ୍)"</string>
+    <string name="prevent_ringing_option_mute_summary" msgid="3509459199090688328">"ଚାଲୁ (ମ୍ୟୁଟ୍)"</string>
     <string name="prevent_ringing_option_none_summary" msgid="5152618221093037451">"ଅଫ୍"</string>
     <string name="pref_title_network_details" msgid="3971074015034595956">"ନେଟୱାର୍କ୍‌ ବିବରଣୀ"</string>
     <string name="about_phone_device_name_warning" msgid="9088572775969880106">"ଆପଣଙ୍କ ଡିଭାଇସ୍‌ରେ ଥିବା ଆପ୍‌ଗୁଡ଼ିକୁ ଆପଣଙ୍କର ଡିଭାଇସ୍‍ ନାମ ଦେଖାଯାଉଛି। ବ୍ଲୁଟୂଥ୍‍ ଡିଭାଇସ୍‍ ସହ ଯୋଡ଼ି ହେବାବେଳେ କିମ୍ୱା ଏକ ୱାଇ-ଫାଇ ହଟସ୍ପଟ୍ ସେଟ୍ କରିବା ସମୟରେ, ଏହା ଅନ୍ୟ ଲୋକମାନଙ୍କୁ ମଧ୍ୟ ଦେଖାଦେଇପାରେ।"</string>
@@ -4467,7 +4473,7 @@
     <string name="privacy_dashboard_title" msgid="8764930992456607513">"ଗୋପନୀୟତା"</string>
     <string name="privacy_dashboard_summary" msgid="7916431309860824945">"ଅନୁମତିଗୁଡ଼ିକ, ଆକାଉଣ୍ଟ କାର୍ଯ୍ୟକଳାପ, ବ୍ୟକ୍ତିଗତ ଡାଟା"</string>
     <string name="contextual_card_dismiss_remove" msgid="1750420285615827309">"କାଢ଼ିଦିଅନ୍ତୁ"</string>
-    <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"ରଖନ୍ତୁ"</string>
+    <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"Keep"</string>
     <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"ଏହି ମତାମତ କାଢ଼ିଦେବେ?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"ସୁପାରିଶକୁ କାଢ଼ି ଦିଆଯାଇଛି"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"ପୂର୍ବବତ୍ କରନ୍ତୁ"</string>
diff --git a/tests/CarDeveloperOptions/res/values-pa/arrays.xml b/tests/CarDeveloperOptions/res/values-pa/arrays.xml
index 4dba94f..fc6f1e9 100644
--- a/tests/CarDeveloperOptions/res/values-pa/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-pa/arrays.xml
@@ -29,8 +29,25 @@
     <item msgid="5194868215515664953">"ਪ੍ਰਸ਼ਾਂਤ"</item>
     <item msgid="7044520255415007865">"ਸਭ"</item>
   </string-array>
-    <!-- no translation found for screen_timeout_entries:0 (8596143519087753804) -->
-    <!-- no translation found for dream_timeout_entries:7 (8271452751594598661) -->
+  <string-array name="screen_timeout_entries">
+    <item msgid="8596143519087753804">"15 ਸਕਿੰਟ"</item>
+    <item msgid="772029947136115322">"30 ਸਕਿੰਟ"</item>
+    <item msgid="8743663928349474087">"1 ਮਿੰਟ"</item>
+    <item msgid="1506508631223164814">"2 ਮਿੰਟ"</item>
+    <item msgid="8664703938127907662">"5 ਮਿੰਟ"</item>
+    <item msgid="5827960506924849753">"10 ਮਿੰਟ"</item>
+    <item msgid="6677424950124253938">"30 ਮਿੰਟ"</item>
+  </string-array>
+  <string-array name="dream_timeout_entries">
+    <item msgid="6487043225269853023">"ਕਦੇ ਵੀ ਨਹੀਂ"</item>
+    <item msgid="2517785806387977252">"15 ਸਕਿੰਟ"</item>
+    <item msgid="6347954399441173672">"30 ਸਕਿੰਟ"</item>
+    <item msgid="4858305253279921789">"1 ਮਿੰਟ"</item>
+    <item msgid="8109273437140044073">"2 ਮਿੰਟ"</item>
+    <item msgid="2788593551142462622">"5 ਮਿੰਟ"</item>
+    <item msgid="8012672183888404961">"10 ਮਿੰਟ"</item>
+    <item msgid="8271452751594598661">"30 ਮਿੰਟ"</item>
+  </string-array>
   <string-array name="lock_after_timeout_entries">
     <item msgid="2232921187970351881">"ਤੁਰੰਤ"</item>
     <item msgid="2038544972632026612">"5 ਸਕਿੰਟ"</item>
@@ -42,17 +59,47 @@
     <item msgid="811192536981678974">"10 ਮਿੰਟ"</item>
     <item msgid="7258394417241706272">"30 ਮਿੰਟ"</item>
   </string-array>
-    <!-- no translation found for entries_font_size:0 (2340391964816059553) -->
-    <!-- no translation found for entries_font_size:0 (6490061470416867723) -->
-    <!-- no translation found for entries_font_size:2 (1714184661981538355) -->
-    <!-- no translation found for entries_font_size:2 (1678068858001018666) -->
-    <!-- no translation found for wifi_status:3 (5848277343965362748) -->
-    <!-- no translation found for wifi_status_with_ssid:1 (6816207058895999545) -->
-    <!-- no translation found for wifi_status_with_ssid:3 (7547609081339573756) -->
-    <!-- no translation found for wifi_status_with_ssid:4 (5145158315060185414) -->
+  <string-array name="entries_font_size">
+    <item msgid="2340391964816059553">"ਛੋਟਾ"</item>
+    <item msgid="591935967183159581">"ਪੂਰਵ-ਨਿਰਧਾਰਤ"</item>
+    <item msgid="1714184661981538355">"ਵੱਡਾ"</item>
+    <item msgid="6195563047686707484">"ਸਭ ਤੋਂ ਵੱਡੀ"</item>
+  </string-array>
+  <string-array name="wifi_status">
+    <item msgid="1304883790721412351"></item>
+    <item msgid="4157625910392775808">"ਸਕੈਨ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ..."</item>
+    <item msgid="5597394826455877834">"ਕਨੈਕਟ ਕਰ ਰਿਹਾ ਹੈ…"</item>
+    <item msgid="5848277343965362748">"ਪ੍ਰਮਾਣਿਤ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</item>
+    <item msgid="3391238031431440676">"IP ਪਤਾ ਪ੍ਰਾਪਤ ਕਰ ਰਿਹਾ ਹੈ..."</item>
+    <item msgid="5257597310494000224">"ਕਨੈਕਟ ਹੈ"</item>
+    <item msgid="8472497592913050396">"ਮੁਅੱਤਲ ਕੀਤਾ"</item>
+    <item msgid="1228072488815999109">"ਡਿਸਕਨੈਕਟ ਕਰ ਰਿਹਾ ਹੈ..."</item>
+    <item msgid="7253087004422991731">"ਡਿਸਕਨੈਕਟ ਕੀਤਾ"</item>
+    <item msgid="4169850917304751227">"ਅਸਫਲ"</item>
+    <item msgid="6266658166690831131">"ਬਲੌਕ ਕੀਤੀਆਂ"</item>
+    <item msgid="4517230805854909775">"ਅਸਥਾਈ ਤੌਰ ਤੇ ਖ਼ਰਾਬ ਕਨੈਕਸ਼ਨ ਤੋਂ ਬਚਣ ਲਈ"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="4853670665485437464"></item>
+    <item msgid="6816207058895999545">"ਸਕੈਨ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</item>
+    <item msgid="8058143476674427024">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕਰ ਰਿਹਾ ਹੈ…"</item>
+    <item msgid="7547609081339573756">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ਨਾਲ ਪ੍ਰਮਾਣਿਤ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</item>
+    <item msgid="5145158315060185414">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ਤੋਂ IP ਪਤਾ ਪ੍ਰਾਪਤ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</item>
+    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</item>
+    <item msgid="6600156231416890902">"ਮੁਅੱਤਲ ਕੀਤਾ"</item>
+    <item msgid="4133290864821295785">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ਤੋਂ ਡਿਸਕਨੈਕਟ ਕਰ ਰਿਹਾ ਹੈ…"</item>
+    <item msgid="3980154971187953257">"ਡਿਸਕਨੈਕਟ ਕੀਤਾ"</item>
+    <item msgid="2847316776634969068">"ਅਸਫਲ"</item>
+    <item msgid="4390990424746035383">"ਬਲੌਕ ਕੀਤੀਆਂ"</item>
+    <item msgid="3618248791367063949">"ਅਸਥਾਈ ਤੌਰ ਤੇ ਖ਼ਰਾਬ ਕਨੈਕਸ਼ਨ ਤੋਂ ਬਚਣ ਲਈ"</item>
+  </string-array>
     <!-- no translation found for wifi_tether_security:0 (5586343370515598801) -->
     <!-- no translation found for wifi_tether_security:1 (6136336549994615745) -->
-    <!-- no translation found for wifi_p2p_wps_setup:0 (5390235347963255303) -->
+  <string-array name="wifi_p2p_wps_setup">
+    <item msgid="5390235347963255303">"ਪੁਸ਼ ਬਟਨ"</item>
+    <item msgid="7401896200768713930">"ਪੀਅਰ ਡੀਵਾਈਸ ਤੋਂ ਪਿੰਨ"</item>
+    <item msgid="4526848028011846710">"ਇਸ ਡੀਵਾਈਸ ਤੋਂ ਪਿੰਨ"</item>
+  </string-array>
   <string-array name="wifi_p2p_status">
     <item msgid="8741947238021758201">"ਕਨੈਕਟ ਹੈ"</item>
     <item msgid="983792611851499732">"ਸੱਦੇ ਗਏ"</item>
@@ -60,7 +107,12 @@
     <item msgid="4646663015449312554">"ਉਪਲਬਧ"</item>
     <item msgid="3230556734162006146">"ਰੇਂਜ-ਤੋਂ-ਬਾਹਰ"</item>
   </string-array>
-    <!-- no translation found for bluetooth_visibility_timeout_entries:1 (2759776603549270587) -->
+  <string-array name="bluetooth_visibility_timeout_entries">
+    <item msgid="8247986727324120082">"2 ਮਿੰਟ"</item>
+    <item msgid="2759776603549270587">"5 ਮਿੰਟ"</item>
+    <item msgid="167772676068860015">"1 ਘੰਟਾ"</item>
+    <item msgid="5985477119043628504">"ਕਦੇ ਵੀ ਸਮਾਂ ਸਮਾਪਤ ਨਹੀਂ"</item>
+  </string-array>
   <string-array name="bluetooth_max_connected_audio_devices">
     <item msgid="3800257971619063588">"ਸਿਸਟਮ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਮੁੱਲ ਵਰਤੋ: <xliff:g id="DEFAULT_BLUETOOTH_MAX_CONNECTED_AUDIO_DEVICES">%1$d</xliff:g>"</item>
     <item msgid="8572230405241423895">"1"</item>
@@ -69,8 +121,13 @@
     <item msgid="1644506614010085798">"4"</item>
     <item msgid="3132506679404897150">"5"</item>
   </string-array>
-    <!-- no translation found for wifi_signal:1 (7882129634982603782) -->
-    <!-- no translation found for wifi_signal:4 (999948812884919584) -->
+  <string-array name="wifi_signal">
+    <item msgid="1709949377823900951">"ਕਮਜ਼ੋਰ"</item>
+    <item msgid="7882129634982603782">"ਕਮਜ਼ੋਰ"</item>
+    <item msgid="6457357501905996224">"ਠੀਕ-ਠਾਕ"</item>
+    <item msgid="405271628162918841">"ਵਧੀਆ"</item>
+    <item msgid="999948812884919584">"ਸ਼ਾਨਦਾਰ"</item>
+  </string-array>
   <string-array name="data_usage_data_range">
     <item msgid="8986775481492954015">"ਪਿਛਲੇ 30 ਦਿਨ"</item>
     <item msgid="3211287705232736964">"ਵਰਤੋਂ ਸਾਈਕਲ ਸੈੱਟ ਕਰੋ..."</item>
@@ -106,11 +163,14 @@
     <item msgid="7330627471456865502">"MSCHAPV2"</item>
     <item msgid="6255179395132581882">"GTC"</item>
   </string-array>
-    <!-- no translation found for wifi_ip_settings:1 (4377002609760712163) -->
+  <string-array name="wifi_ip_settings">
+    <item msgid="2717196390555072244">"DHCP"</item>
+    <item msgid="4377002609760712163">"ਸਥਿਰ"</item>
+  </string-array>
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"ਕੋਈ ਨਹੀਂ"</item>
     <item msgid="1464741437353223198">"ਮੈਨੁਅਲ"</item>
-    <item msgid="5793600062487886090">"ਪ੍ਰੌਕਸੀ ਆਟੋ-ਕੌਂਫਿਗਰ"</item>
+    <item msgid="5793600062487886090">"ਪ੍ਰੌਕਸੀ ਸਵੈ-ਸੰਰੂਪਣ"</item>
   </string-array>
   <string-array name="apn_auth_entries">
     <item msgid="7099647881902405997">"ਕੋਈ ਨਹੀਂ"</item>
@@ -226,11 +286,73 @@
     <item msgid="1165623660533024666">"ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚਲਾਓ"</item>
     <item msgid="6423861043647911030">"ਪਹੁੰਚਯੋਗਤਾ ਅਵਾਜ਼"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:3 (7836406246005211990) -->
-    <!-- no translation found for app_ops_labels:4 (3951439024549922598) -->
-    <!-- no translation found for app_ops_labels:8 (3597797992398484655) -->
-    <!-- no translation found for app_ops_labels:20 (3037159047591081136) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"ਟਿਕਾਣਾ"</item>
+    <item msgid="6656077694190491067">"ਟਿਕਾਣਾ"</item>
+    <item msgid="8790228218278477369">"ਟਿਕਾਣਾ"</item>
+    <item msgid="7836406246005211990">"ਥਰਥਰਾਹਟ"</item>
+    <item msgid="3951439024549922598">"ਸੰਪਰਕ ਪੜ੍ਹੋ"</item>
+    <item msgid="8802152411647068">"ਸੰਪਰਕ ਸੰਸ਼ੋਧਿਤ ਕਰੋ"</item>
+    <item msgid="229544934599698735">"ਕਾਲ ਲੌਗ ਪੜ੍ਹੋ"</item>
+    <item msgid="7396102294405899613">"ਕਾਲ ਲੌਗ ਸੰਸ਼ੋਧਿਤ ਕਰੋ"</item>
+    <item msgid="3597797992398484655">"ਕੈਲੰਡਰ ਪੜ੍ਹੋ"</item>
+    <item msgid="2705975774250907343">"ਕੈਲੰਡਰ ਸੰਸ਼ੋਧਿਤ ਕਰੋੇ"</item>
+    <item msgid="4668747371441932697">"ਟਿਕਾਣਾ"</item>
+    <item msgid="1487578921720243646">"ਸੂਚਨਾ ਪੋਸਟ ਕਰੋ"</item>
+    <item msgid="4636080349724146638">"ਟਿਕਾਣਾ"</item>
+    <item msgid="673510900286463926">"ਫ਼ੋਨ ਤੇ ਕਾਲ ਕਰੋ"</item>
+    <item msgid="542083422784609790">"SMS/MMS ਪੜ੍ਹੋ"</item>
+    <item msgid="1033780373029588436">"SMS/MMS ਲਿਖੋ"</item>
+    <item msgid="5647111115517787488">"SMS/MMS ਪ੍ਰਾਪਤ ਕਰੋ"</item>
+    <item msgid="8591105601108455893">"SMS/MMS ਪ੍ਰਾਪਤ ਕਰੋ"</item>
+    <item msgid="7730995008517841903">"SMS/MMS ਪ੍ਰਾਪਤ ਕਰੋ"</item>
+    <item msgid="2613033109026626086">"SMS/MMS ਪ੍ਰਾਪਤ ਕਰੋ"</item>
+    <item msgid="3037159047591081136">"SMS/MMS ਭੇਜੋ"</item>
+    <item msgid="4726682243833913568">"SMS/MMS ਪੜ੍ਹੋ"</item>
+    <item msgid="6555678522277865572">"SMS/MMS ਲਿਖੋ"</item>
+    <item msgid="6981734935578130884">"ਸੈਟਿੰਗਾਂ ਬਦਲੋ"</item>
+    <item msgid="8705854389991425629">"ਟੌਪ ਤੇ ਡ੍ਰਾ ਕਰੋ"</item>
+    <item msgid="5861356020344153651">"ਪਹੁੰਚ ਸੂਚਨਾਵਾਂ"</item>
+    <item msgid="78432174621628659">"ਕੈਮਰਾ"</item>
+    <item msgid="3986116419882154794">" ਆਡੀਓ  ਰਿਕਾਰਡ ਕਰੋ"</item>
+    <item msgid="4516840825756409490">" ਆਡੀਓ  ਪਲੇ ਕਰੋ"</item>
+    <item msgid="6811712502798183957">"ਕਲਿਪਬੋਰਡ ਪੜ੍ਹੋ"</item>
+    <item msgid="2780369012602289114">"ਕਲਿਪਬੋਰਡ ਬਦਲੋ"</item>
+    <item msgid="2331359440170850868">"ਮੀਡੀਆ ਬਟਨ"</item>
+    <item msgid="6133599737122751231">" ਆਡੀਓ  ਫੋਕਸ"</item>
+    <item msgid="6844485713404805301">"ਮਾਸਟਰ ਵੌਲਿਊਮ"</item>
+    <item msgid="1600379420669104929">"ਵੌਇਸ ਵੌਲਿਊਮ"</item>
+    <item msgid="6296768210470214866">"ਰਿੰਗ ਦੀ ਅਵਾਜ਼"</item>
+    <item msgid="510690696071629241">"ਮੀਡੀਆ ਦੀ ਅਵਾਜ਼"</item>
+    <item msgid="406861638631430109">"ਅਲਾਰਮ ਦੀ ਅਵਾਜ਼"</item>
+    <item msgid="4715864795872233884">"ਸੂਚਨਾ ਵੌਲਿਊਮ"</item>
+    <item msgid="2311478519251301183">"Bluetooth ਵੌਲਿਊਮ"</item>
+    <item msgid="5133991377896747027">"ਸਕਿਰਿਆ ਰੱਖੋ"</item>
+    <item msgid="2464189519136248621">"ਟਿਕਾਣਾ"</item>
+    <item msgid="2062677934050803037">"ਟਿਕਾਣਾ"</item>
+    <item msgid="1735171933192715957">"ਵਰਤੋਂ ਸਟੈਟਸ ਪ੍ਰਾਪਤ ਕਰੋ"</item>
+    <item msgid="1014093788778383554">"ਮਾਈਕ੍ਰੋਫੋਨ ਨੂੰ ਮਿਊਟ/ਅਨਮਿਊਟ ਕਰੋ"</item>
+    <item msgid="4199297950608622850">"ਟੋਸਟ  ਦਿਖਾਓ"</item>
+    <item msgid="2527962435313398821">"ਪ੍ਰੋਜੈਕਟ ਮੀਡੀਆ"</item>
+    <item msgid="5117506254221861929">"VPN ਨੂੰ ਸਰਗਰਮ ਕਰੋ"</item>
+    <item msgid="8291198322681891160">"ਵਾਲਪੇਪਰ ਲਿਖੋ"</item>
+    <item msgid="7106921284621230961">"ਸਹਾਇਕ ਬਣਤਰ"</item>
+    <item msgid="4496533640894624799">"ਸਹਾਇਕ ਸਕਰੀਨਸ਼ਾਟ"</item>
+    <item msgid="2598847264853993611">"ਫ਼ੋਨ ਸਥਿਤੀ ਪੜ੍ਹੋ"</item>
+    <item msgid="9215610846802973353">"ਵੌਇਸਮੇਲ ਸ਼ਾਮਲ ਕਰੋ"</item>
+    <item msgid="9186411956086478261">"SIP ਵਰਤੋ"</item>
+    <item msgid="6884763100104539558">"ਆਊਟਗੋਇੰਗ ਕਾਲ \'ਤੇ ਪ੍ਰਕਿਰਿਆ ਕਰੋ"</item>
+    <item msgid="125513972170580692">"ਫਿੰਗਰਪ੍ਰਿੰਟ"</item>
+    <item msgid="2556071024281275619">"ਸਰੀਰ ਸੰਵੇਦਕ"</item>
+    <item msgid="617168514928339387">"ਸੈਲ ਪ੍ਰਸਾਰਨਾਂ ਨੂੰ ਪੜ੍ਹੋ"</item>
+    <item msgid="7134693570516523585">"ਬਣਾਉਟੀ ਟਿਕਾਣਾ"</item>
+    <item msgid="7224489175375229399">"ਸਟੋਰੇਜ ਪੜ੍ਹੋ"</item>
+    <item msgid="8472735063903258202">"ਸਟੋਰੇਜ ਲਿਖੋ"</item>
+    <item msgid="4069276819909595110">"ਸਕਰੀਨ ਚਾਲੂ ਕਰੋ"</item>
+    <item msgid="1228338896751121025">"ਖਾਤੇ ਲਓ"</item>
+    <item msgid="3181581793459233672">"ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚਲਾਓ"</item>
+    <item msgid="2340936043025374076">"ਪਹੁੰਚਯੋਗਤਾ ਅਵਾਜ਼"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"ਘੱਟ"</item>
     <item msgid="4816511817309094890">"ਔਸਤ"</item>
@@ -247,15 +369,35 @@
     <item msgid="4627069151979553527">"ਪ੍ਰਵਾਹੀ ਲਿਖਤ"</item>
     <item msgid="6896773537705206194">"ਛੋਟੇ ਕੈਪੀਟਲਸ"</item>
   </string-array>
-    <!-- no translation found for captioning_font_size_selector_titles:3 (2784236342175159295) -->
-    <!-- no translation found for captioning_edge_type_selector_titles:4 (8019330250538856521) -->
+  <string-array name="captioning_font_size_selector_titles">
+    <item msgid="1680223634161592855">"ਬਹੁਤ ਛੋਟਾ"</item>
+    <item msgid="5091603983404027034">"ਛੋਟਾ"</item>
+    <item msgid="176844712416932112">"ਸਧਾਰਨ"</item>
+    <item msgid="2784236342175159295">"ਵੱਡਾ"</item>
+    <item msgid="218913203203160606">"ਬਹੁਤ ਵੱਡਾ"</item>
+  </string-array>
+  <string-array name="captioning_edge_type_selector_titles">
+    <item msgid="3865198759294188069">"ਪੂਰਵ-ਨਿਰਧਾਰਤ"</item>
+    <item msgid="6488643537808152001">"ਕੋਈ ਨਹੀਂ"</item>
+    <item msgid="552332815156010137">"ਰੂਪਰੇਖਾ"</item>
+    <item msgid="7187891159463789272">"ਡ੍ਰੌਪ ਸ਼ੈਡੋ"</item>
+    <item msgid="8019330250538856521">"ਉਭਰੇ ਹੋਏ ਕਿਨਾਰੇ"</item>
+    <item msgid="8987385315647049787">"ਨਿਰਾਸ਼"</item>
+  </string-array>
   <string-array name="captioning_opacity_selector_titles">
     <item msgid="313003243371588365">"25%"</item>
     <item msgid="4665048002584838262">"50%"</item>
     <item msgid="1874668269931014581">"75%"</item>
     <item msgid="6462911487571123954">"100%"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"ਐਪ ਵੱਲੋਂ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਵਰਤੋ"</item>
+    <item msgid="8611890312638868524">"ਕਾਲੇ \'ਤੇ ਸਫ਼ੈਦ"</item>
+    <item msgid="5891360837786277638">"ਸਫ਼ੈਦ ਉੱਤੇ ਕਾਲਾ"</item>
+    <item msgid="2798457065945456853">"ਕਾਲੇ \'ਤੇ ਪੀਲਾ"</item>
+    <item msgid="5799049811524553967">"ਨੀਲੇ \'ਤੇ ਪੀਲਾ"</item>
+    <item msgid="3673930830658169860">"ਵਿਉਂਤੀ"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"PPTP VPN"</item>
     <item msgid="1349760781118368659">"ਪ੍ਰੀ-ਸ਼ੇਅਰ ਕੀਤੀਆਂ ਕੁੰਜੀਆਂ ਨਾਲ L2TP/IPSec VPN"</item>
@@ -264,16 +406,36 @@
     <item msgid="3319427315593649917">"ਸਰਟੀਫਿਕੇਟਾਂ ਨਾਲ IPSec VPN ਅਤੇ Xauth ਪ੍ਰਮਾਣੀਕਰਨ"</item>
     <item msgid="8258927774145391041">"ਸਰਟੀਫਿਕੇਟਾਂ ਅਤੇ ਹਾਈਬ੍ਰਿਡ ਪ੍ਰਮਾਣੀਕਰਨ ਨਾਲ IPSec VPN"</item>
   </string-array>
-    <!-- no translation found for vpn_proxy_settings:0 (2958623927055120839) -->
-    <!-- no translation found for vpn_states:4 (9135049670787351881) -->
+  <string-array name="vpn_proxy_settings">
+    <item msgid="2958623927055120839">"ਕੋਈ ਨਹੀਂ"</item>
+    <item msgid="1157046369795346308">"ਮੈਨੁਅਲ"</item>
+  </string-array>
+  <string-array name="vpn_states">
+    <item msgid="5408915841694583740">"ਡਿਸਕਨੈਕਟ ਕੀਤਾ"</item>
+    <item msgid="8754480102834556765">"ਅਰੰਭ ਕਰ ਰਿਹਾ ਹੈ..."</item>
+    <item msgid="3351334355574270250">"ਕਨੈਕਟ ਕਰ ਰਿਹਾ ਹੈ…"</item>
+    <item msgid="8303882153995748352">"ਕਨੈਕਟ ਹੈ"</item>
+    <item msgid="9135049670787351881">"ਸਮਾਂ ਸਮਾਪਤ"</item>
+    <item msgid="2124868417182583926">"ਅਸਫਲ"</item>
+  </string-array>
   <string-array name="security_settings_premium_sms_values">
     <item msgid="1164265643455394443">"ਪੁੱਛੋ"</item>
     <item msgid="7718817231348607934">"ਕਦੇ ਵੀ ਆਗਿਆ ਨਾ ਦਿਓ"</item>
     <item msgid="8184570120217958741">"ਹਮੇਸ਼ਾਂ ਆਗਿਆ ਦਿਓ"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"ਸਧਾਰਨ"</item>
+    <item msgid="5101233285497327432">"ਮੱਧ"</item>
+    <item msgid="1555861583162930714">"ਘੱਟ"</item>
+    <item msgid="1719683776264798117">"ਸਮਾਲੋਚਨਾਤਮਿਕ"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"ਸਧਾਰਨ"</item>
+    <item msgid="6107138933849816768">"ਮੱਧ"</item>
+    <item msgid="182695359839047859">"ਘੱਟ"</item>
+    <item msgid="8577246509202964244">"ਸਮਾਲੋਚਨਾਤਮਿਕ"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"ਸਥਿਰ"</item>
     <item msgid="167418068739176448">"ਟੌਪ ਗਤੀਵਿਧੀ"</item>
@@ -291,9 +453,9 @@
     <item msgid="6248998242443333892">"ਕੈਚ ਕੀਤੀ (ਖਾਲੀ)"</item>
   </string-array>
   <string-array name="color_picker">
-    <item msgid="3151827842194201728">"Teal"</item>
+    <item msgid="3151827842194201728">"ਟੀਲ"</item>
     <item msgid="3228505970082457852">"ਨੀਲਾ"</item>
-    <item msgid="6590260735734795647">"Indigo"</item>
+    <item msgid="6590260735734795647">"ਗੂੜ੍ਹਾ ਨੀਲਾ"</item>
     <item msgid="3521763377357218577">"ਜਾਮਨੀ"</item>
     <item msgid="5932337981182999919">"ਗੁਲਾਬੀ"</item>
     <item msgid="5642914536624000094">"ਲਾਲ"</item>
diff --git a/tests/CarDeveloperOptions/res/values-pa/config.xml b/tests/CarDeveloperOptions/res/values-pa/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-pa/config.xml
+++ b/tests/CarDeveloperOptions/res/values-pa/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-pa/strings.xml b/tests/CarDeveloperOptions/res/values-pa/strings.xml
index 2dde26c..c85ecaa 100644
--- a/tests/CarDeveloperOptions/res/values-pa/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-pa/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"ਸਕ੍ਰੀਨ \'ਤੇ ਦਿਖਦੀ ਲਿਖਤ ਨੂੰ ਛੋਟਾ ਜਾਂ ਵੱਡਾ ਕਰੋ।"</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"ਛੋਟਾ ਕਰੋ"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"ਵੱਡਾ ਕਰੋ"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"ਨਮੂਨਾ ਲਿਖਤ"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"ਔਜ਼ ਦਾ ਨਿਰਾਲਾ ਵਿਜ਼ਾਰਡ"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"ਪਾਠ 11: ਔਜ਼ ਦਾ ਹੀਰਿਆਂ-ਪੰਨਿਆਂ ਵਾਲਾ ਨਿਰਾਲਾ ਸ਼ਹਿਰ"</string>
@@ -100,7 +99,7 @@
     <string name="bluetooth_visibility_timeout" msgid="4804679276398564496">"ਦ੍ਰਿਸ਼ਟਤਾ ਦਾ ਸਮਾਂ ਸਮਾਪਤ"</string>
     <string name="bluetooth_lock_voice_dialing" msgid="1600385868298081015">" ਲਾਕ  ਵੌਇਸ ਡਾਇਲਿੰਗ"</string>
     <string name="bluetooth_lock_voice_dialing_summary" msgid="5005776616112427980">"ਜਦੋਂ ਸਕ੍ਰੀਨ  ਲਾਕ  ਕੀਤੀ ਹੋਵੇ ਤਾਂ bluetooth ਡਾਇਲਰ ਦੀ ਵਰਤੋਂ ਰੋਕੋ"</string>
-    <string name="bluetooth_devices" msgid="4143880830505625666">"ਬਲੂਟੁੱਥ ਡਿਵਾਈਸਾਂ"</string>
+    <string name="bluetooth_devices" msgid="4143880830505625666">"ਬਲੂਟੁੱਥ ਡੀਵਾਈਸਾਂ"</string>
     <string name="bluetooth_device_name" msgid="3682016026866302981">"ਡੀਵਾਈਸ ਦਾ ਨਾਮ"</string>
     <string name="bluetooth_device_details" msgid="2500840679106321361">"ਡੀਵਾਈਸ ਸੈਟਿੰਗਾਂ"</string>
     <string name="bluetooth_profile_details" msgid="1785505059738682493">"ਪ੍ਰੋਫਾਈਲ ਸੈਟਿੰਗਾਂ"</string>
@@ -195,7 +194,7 @@
     <string name="intent_sender_resource_label" msgid="8002433688075847091">"<xliff:g id="RESOURCE">Resource</xliff:g>:"</string>
     <string name="intent_sender_account_label" msgid="7904284551281213567">"ਖਾਤਾ:"</string>
     <string name="proxy_settings_title" msgid="6014901859338211713">"ਪ੍ਰੌਕਸੀ"</string>
-    <string name="proxy_clear_text" msgid="498317431076294101">"ਹਟਾਓ"</string>
+    <string name="proxy_clear_text" msgid="498317431076294101">"ਕਲੀਅਰ ਕਰੋ"</string>
     <string name="proxy_port_label" msgid="8285157632538848509">"ਪ੍ਰੌਕਸੀ ਪੋਰਟ"</string>
     <string name="proxy_exclusionlist_label" msgid="8179084955547941904">"ਇਸ ਲਈ ਪ੍ਰੌਕਸੀ ਬਾਈਪਾਸ ਕਰੋ"</string>
     <string name="proxy_defaultView_text" msgid="5785775257042403261">"ਡਿਫੌਲਟਸ ਰੀਸਟੋਰ ਕਰੋ"</string>
@@ -364,7 +363,7 @@
     <string name="owner_info_settings_summary" msgid="4208702251226725583">"ਕੋਈ ਨਹੀਂ"</string>
     <string name="owner_info_settings_status" msgid="8049975536717685126">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="COUNT_1">%2$d</xliff:g>"</string>
     <string name="owner_info_settings_edit_text_hint" msgid="2250029417257939706">"ਉਦਾਹਰਨ ਵਜੋਂ, ਜੋਏ ਦਾ Android."</string>
-    <string name="user_info_settings_title" msgid="1125111518759995748">"ਉਪਭੋਗਤਾ ਜਾਣਕਾਰੀ"</string>
+    <string name="user_info_settings_title" msgid="1125111518759995748">"ਵਰਤੋਂਕਾਰ ਜਾਣਕਾਰੀ"</string>
     <string name="show_profile_info_on_lockscreen_label" msgid="5204282771893683026">" ਲਾਕ  ਸਕ੍ਰੀਨ ਤੇ ਪ੍ਰੋਫਾਈਲ ਜਾਣਕਾਰੀ ਦਿਖਾਓ"</string>
     <string name="profile_info_settings_title" msgid="4855892878512562551">"ਪ੍ਰੋਫਾਈਲ ਜਾਣਕਾਰੀ"</string>
     <string name="Accounts_settings_title" msgid="7901374987121953746">"ਖਾਤੇ"</string>
@@ -448,7 +447,7 @@
     <string name="security_settings_fingerprint_enroll_introduction_cancel_setup" msgid="756928427429893070">"ਛੱਡੋ"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue_setup" msgid="4125977169169671144">"ਅੱਗੇ"</string>
     <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"ਕੀ ਫਿੰਗਰਪ੍ਰਿੰਟ ਛੱਡਣਾ ਹੈ?"</string>
-    <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈੱਟਅੱਪ ਵਿੱਚ ਸਿਰਫ਼ ਇੱਕ ਜਾਂ ਦੋ ਮਿੰਟ ਲੱਗਦੇ ਹਨ। ਜੇਕਰ ਤੁਸੀਂ ਇਸ ਨੂੰ ਛੱਡ ਦਿੰਦੇ ਹੋ, ਤਾਂ ਤੁਸੀਂ ਬਾਅਦ ਵਿੱਚ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਆਪਣੇ ਫਿੰਗਰਪ੍ਰਿੰਟ ਸ਼ਾਮਲ ਕਰ ਸਕਦੇ ਹੋ।"</string>
+    <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈੱਟਅੱਪ ਵਿੱਚ ਸਿਰਫ਼ ਇੱਕ ਜਾਂ ਦੋ ਮਿੰਟ ਲੱਗਦੇ ਹਨ। ਜੇਕਰ ਤੁਸੀਂ ਇਸ ਨੂੰ ਛੱਡ ਦਿੰਦੇ ਹੋ, ਤਾਂ ਤੁਸੀਂ ਬਾਅਦ ਵਿੱਚ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਆਪਣਾ ਫਿੰਗਰਪ੍ਰਿੰਟ ਸ਼ਾਮਲ ਕਰ ਸਕਦੇ ਹੋ।"</string>
     <string name="lock_screen_intro_skip_title" msgid="5307431665496346914">"ਕੀ ਸਕ੍ਰੀਨ ਲਾਕ ਨੂੰ ਛੱਡਣਾ ਹੈ?"</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="tablet" msgid="7553945981266845264">"ਡੀਵਾਈਸ ਸੁਰੱਖਿਆ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਚਾਲੂ ਨਹੀਂ ਕੀਤੀਆਂ ਜਾਣਗੀਆਂ। ਜੇਕਰ ਤੁਹਾਡਾ ਟੈਬਲੈੱਟ ਗੁੰਮ ਹੋ ਜਾਂਦਾ ਹੈ, ਚੋਰੀ ਹੋ ਜਾਂਦਾ ਹੈ ਜਾਂ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾਂਦਾ ਹੈ ਤਾਂ ਤੁਸੀਂ ਹੋਰਾਂ ਨੂੰ ਇਸਦੀ ਵਰਤੋਂ ਕਰਨ ਤੋਂ ਰੋਕਣ ਵਿੱਚ ਅਸਮਰੱਥ ਹੋੋਵੋਗੇ।"</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="device" msgid="1378243257238015603">"ਡੀਵਾਈਸ ਸੁਰੱਖਿਆ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਚਾਲੂ ਨਹੀਂ ਕੀਤੀਆਂ ਜਾਣਗੀਆਂ। ਜੇਕਰ ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਗੁੰਮ, ਚੋਰੀ ਹੋ ਜਾਂਦਾ ਹੈ ਜਾਂ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾਂਦਾ ਹੈ ਤਾਂ ਤੁਸੀਂ ਹੋਰਾਂ ਨੂੰ ਇਸਦੀ ਵਰਤੋਂ ਕਰਨ ਤੋਂ ਰੋਕਣ ਵਿੱਚ ਅਸਮਰੱਥ ਹੋੋਵੋਗੇ।"</string>
@@ -460,15 +459,15 @@
     <string name="go_back_button_label" msgid="7310586887969860472">"ਵਾਪਸ ਜਾਓ"</string>
     <string name="skip_lock_screen_dialog_button_label" msgid="6706047245716780006">"ਛੱਡੋ"</string>
     <string name="cancel_lock_screen_dialog_button_label" msgid="2534925227627658819">"ਰੱਦ ਕਰੋ"</string>
-    <string name="security_settings_fingerprint_enroll_find_sensor_title" msgid="8909829699273726469">"ਸੈਂਸਰ ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ"</string>
+    <string name="security_settings_fingerprint_enroll_find_sensor_title" msgid="8909829699273726469">"ਸੈਂਸਰ ਨੂੰ ਸਪਰਸ਼ ਕਰੋ"</string>
     <string name="security_settings_fingerprint_enroll_find_sensor_message" msgid="581120963079780740">"ਇਹ ਤੁਹਾਡੇ ਫ਼ੋਨ ਦੇ ਪਿਛਲੇ ਪਾਸੇ ਹੈ। ਆਪਣੀ ਪਹਿਲੀ ਉਂਗਲ ਦੀ ਵਰਤੋਂ ਕਰੋ।"</string>
     <string name="security_settings_fingerprint_enroll_find_sensor_content_description" msgid="7835824123269738540">"ਡੀਵਾਈਸ ਵਾਲੀ ਤਸਵੀਰ ਅਤੇ ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਟਿਕਾਣਾ"</string>
     <string name="security_settings_fingerprint_enroll_dialog_name_label" msgid="3519748398694308901">"ਨਾਮ"</string>
     <string name="security_settings_fingerprint_enroll_dialog_ok" msgid="3428927518029038956">"ਠੀਕ"</string>
     <string name="security_settings_fingerprint_enroll_dialog_delete" msgid="4312297515772004580">"ਮਿਟਾਓ"</string>
-    <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"ਸੈਂਸਰ ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ"</string>
+    <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"ਸੈਂਸਰ ਨੂੰ ਸਪਰਸ਼ ਕਰੋ"</string>
     <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"ਆਪਣੀ ਉਂਗਲ ਨੂੰ ਸੈਂਸਰ ’ਤੇ ਰੱਖੋ ਅਤੇ ਇੱਕ ਥਰਥਰਾਹਟ ਮਹਿਸੂਸ ਹੋਣ ਤੋਂ ਬਾਅਦ ਚੁੱਕ ਲਵੋ"</string>
-    <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"ਚੁੱਕੋ, ਫਿਰ ਦੁਬਾਰਾ ਸਪੱਰਸ਼ ਕਰੋ"</string>
+    <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"ਚੁੱਕੋ, ਫਿਰ ਦੁਬਾਰਾ ਸਪਰਸ਼ ਕਰੋ"</string>
     <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"ਆਪਣੇ ਫਿੰਗਰਪ੍ਰਿੰਟ ਦੇ ਵੱਖ-ਵੱਖ ਭਾਗਾਂ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਆਪਣੀ ਉਂਗਲ ਨੂੰ ਰੱਖਣਾ-ਚੁੱਕਣਾ ਜਾਰੀ ਰੱਖੋ"</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸ਼ਾਮਲ ਹੋ ਗਿਆ"</string>
     <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"ਜਦ ਤੁਹਾਨੂੰ ਇਹ ਪ੍ਰਤੀਕ ਦਿਖਾਈ ਦਿੰਦਾ ਹੈ, ਤਾਂ ਪਛਾਣ ਵਾਸਤੇ ਜਾਂ ਖਰੀਦਾਂ ਨੂੰ ਮਨਜ਼ੂਰ ਕਰਨ ਲਈ ਆਪਣੇ ਫਿੰਗਰਪ੍ਰਿੰਟ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
@@ -488,21 +487,21 @@
     <string name="security_settings_fingerprint_enroll_done" msgid="4111289529758845926">"ਹੋ ਗਿਆ"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"ਓਹੋ, ਉਹ ਸੈਂਸਰ ਨਹੀਂ ਹੈ"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"ਫ਼ੋਨ ਦੇ ਪਿਛਲੇ ਪਾਸੇ ਸੈਂਸਰ ਨੂੰ ਸਪਰਸ਼ ਕਰੋ। ਪਹਿਲੀ ਉਂਗਲ ਵਰਤੋ।"</string>
-    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"ਦਾਖਲਾ ਪੂਰਾ ਨਾ ਕੀਤਾ ਗਿਆ"</string>
+    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"ਦਾਖਲਾ ਪੂਰਾ ਨਹੀਂ ਹੋਇਆ"</string>
     <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦਾਖ਼ਲੇ ਦੀ ਸਮਾਂ ਸੀਮਾ ਪੂਰੀ ਹੋ ਗਈ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦਾਖ਼ਲੇ ਨੇ ਕੰਮ ਨਹੀਂ ਕੀਤਾ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ ਜਾਂ ਕੋਈ ਵੱਖਰੀ ਉਂਗਲ ਉਪਯੋਗ ਕਰੋ।"</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"ਇੱਕ ਹੋਰ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"ਅੱਗੇ"</string>
     <string name="security_settings_fingerprint_enroll_disclaimer" msgid="5831834311961551423">"ਤੁਹਾਡੇ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਤੋਂ ਇਲਾਵਾ, ਤੁਸੀਂ ਖਰੀਦਾਰੀਆਂ ਅਤੇ ਐਪ ਪਹੁੰਚ ਨੂੰ ਪ੍ਰਮਾਣਿਤ ਕਰਨ ਲਈ ਆਪਣੇ ਫਿੰਗਰਪ੍ਰਿੰਟ ਦੀ ਵਰਤੋਂ ਵੀ ਕਰ ਸਕਦੇ ਹੋ। "<annotation id="url">"ਹੋਰ ਜਾਣੋ"</annotation></string>
     <string name="security_settings_fingerprint_enroll_disclaimer_lockscreen_disabled" msgid="7954742554236652690">" ਸਕ੍ਰੀਨ ਲਾਕ ਵਿਕਲਪ ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ। ਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੀ ਸੰਸਥਾ ਦੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ। "<annotation id="admin_details">"ਹੋਰ ਵੇਰਵੇ"</annotation>\n\n"ਤੁਸੀਂ ਖਰੀਦਾਂ ਨੂੰ ਅਧਿਕਾਰਿਤ ਕਰਨ ਅਤੇ ਐਪ \'ਤੇ ਪਹੁੰਚ ਕਰਨ ਲਈ ਹਾਲੇ ਵੀ ਆਪਣੇ ਫਿੰਗਰਪ੍ਰਿੰਟ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੇ ਹੋ। "<annotation id="url">"ਹੋਰ ਜਾਣੋ"</annotation></string>
-    <string name="security_settings_fingerprint_enroll_lift_touch_again" msgid="1670703069782212223">"ਉਂਗਲ ਚੁੱਕੋ, ਫਿਰ ਦੁਬਾਰਾ ਸੈਂਸਰ ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ"</string>
+    <string name="security_settings_fingerprint_enroll_lift_touch_again" msgid="1670703069782212223">"ਉਂਗਲ ਚੁੱਕੋ, ਫਿਰ ਦੁਬਾਰਾ ਸੈਂਸਰ ਨੂੰ ਸਪਰਸ਼ ਕਰੋ"</string>
     <string name="fingerprint_add_max" msgid="2939393314646115661">"ਤੁਸੀਂ <xliff:g id="COUNT">%d</xliff:g> ਤੱਕ ਫਿੰਗਰਪ੍ਰਿੰਟ ਸ਼ਾਮਲ ਕਰ ਸਕਦੇ ਹੋ"</string>
     <string name="fingerprint_intro_error_max" msgid="3247720976621039437">"ਤੁਸੀਂ ਫਿੰਗਰਪ੍ਰਿੰਟਾਂ ਦੀ ਅਧਿਕਤਮ ਸੰਖਿਆ ਨੂੰ ਸ਼ਾਮਲ ਕੀਤਾ ਹੋਇਆ ਹੈ"</string>
     <string name="fingerprint_intro_error_unknown" msgid="3975674268256524015">"ਹੋਰ ਫਿੰਗਰਪ੍ਰਿੰਟਾਂ ਨੂੰ ਸ਼ਾਮਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
     <string name="fingerprint_last_delete_title" msgid="3104596858161269635">"ਕੀ ਸਾਰੇ ਫਿੰਗਰਪ੍ਰਿੰਟ ਹਟਾਉਣੇ ਹਨ?"</string>
     <string name="fingerprint_delete_title" msgid="3120894112324235536">"\'<xliff:g id="FINGERPRINT_ID">%1$s</xliff:g>\' ਨੂੰ ਹਟਾਓ"</string>
     <string name="fingerprint_delete_message" msgid="5895802741486967970">"ਕੀ ਤੁਸੀਂ ਇਸ ਫਿੰਗਰਪ੍ਰਿੰਟ ਨੂੰ ਮਿਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
-    <string name="fingerprint_last_delete_message" msgid="3346252479778971442">"ਤੁਸੀਂ ਆਪਣੇ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ, ਖਰੀਦਾਂ ਨੂੰ ਅਧਿਕਾਰਿਤ ਕਰਨ ਜਾਂ ਉਹਨਾਂ ਨਾਲ ਐਪਾਂ \'ਤੇ ਸਾਈਨ-ਇਨ ਕਰਨ ਲਈ ਆਪਣੇ ਫਿੰਗਰਪ੍ਰਿੰਟਾਂ ਦੀ ਵਰਤੋਂ ਨਹੀਂ ਕਰ ਸਕੋਗੇ"</string>
+    <string name="fingerprint_last_delete_message" msgid="3346252479778971442">"ਤੁਸੀਂ ਆਪਣੇ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ, ਖਰੀਦਾਂ ਨੂੰ ਅਧਿਕਾਰਿਤ ਕਰਨ ਜਾਂ ਐਪਾਂ \'ਤੇ ਸਾਈਨ-ਇਨ ਕਰਨ ਲਈ ਆਪਣੇ ਫਿੰਗਰਪ੍ਰਿੰਟਾਂ ਦੀ ਵਰਤੋਂ ਨਹੀਂ ਕਰ ਸਕੋਗੇ"</string>
     <string name="fingerprint_last_delete_message_profile_challenge" msgid="5385095150532247025">"ਤੁਸੀਂ ਆਪਣੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਨੂੰ ਅਣਲਾਕ ਕਰਨ, ਖਰੀਦਾਂ ਨੂੰ ਅਧਿਕਾਰਿਤ ਕਰਨ ਜਾਂ ਕਾਰਜ ਐਪਾਂ \'ਤੇ ਸਾਈਨ-ਇਨ ਕਰਨ ਲਈ ਆਪਣੇ ਫਿੰਗਰਪ੍ਰਿੰਟਾਂ ਦੀ ਵਰਤੋਂ ਨਹੀਂ ਕਰ ਸਕੋਂਗੇ"</string>
     <string name="fingerprint_last_delete_confirm" msgid="7984595457589664004">"ਹਾਂ, ਹਟਾਓ"</string>
     <string name="crypt_keeper_settings_title" msgid="839783588093862748">"ਇਨਕ੍ਰਿਪਸ਼ਨ"</string>
@@ -668,7 +667,6 @@
       <item quantity="one"><xliff:g id="NUMBER_1">%d</xliff:g> ਤੋਂ ਘੱਟ ਅੰਕ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ</item>
       <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> ਤੋਂ ਵਧੇਰੇ ਘੱਟ ਅੰਕ ਹੋਣੇ ਚਾਹੀਦੇ ਹਨ</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"ਸਿਰਫ਼ 0-9 ਤੱਕ ਅੰਕ ਸ਼ਾਮਲ ਹੋਣੇ ਲਾਜ਼ਮੀ ਹਨ"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"ਡੀਵਾਈਸ ਪ੍ਰਸ਼ਾਸਕ ਇੱਕ ਹਾਲੀਆ ਪਿੰਨ ਵਰਤਣ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੰਦਾ ਹੈ"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"ਆਮ ਪਿੰਨ ਤੁਹਾਡੇ IT ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਬਲਾਕ ਕੀਤੇ ਗਏ ਹਨ। ਕੋਈ ਵੱਖਰਾ ਪਿੰਨ ਵਰਤੋ।"</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"ਇਸ ਵਿੱਚ ਇੱਕ ਅਵੈਧ ਅੱਖਰ-ਚਿੰਨ੍ਹ ਸ਼ਾਮਲ ਨਹੀਂ ਹੋ ਸਕਦਾ"</string>
@@ -699,6 +697,10 @@
       <item quantity="one">ਘੱਟੋ-ਘੱਟ <xliff:g id="COUNT">%d</xliff:g> ਗੈਰ-ਅੱਖਰੀ ਅੱਖਰ-ਚਿੰਨ੍ਹ ਸ਼ਾਮਲ ਕਰਨਾ ਲਾਜ਼ਮੀ ਹੈ</item>
       <item quantity="other">ਘੱਟੋ-ਘੱਟ <xliff:g id="COUNT">%d</xliff:g> ਗੈਰ-ਅੱਖਰੀ ਅੱਖਰ-ਚਿੰਨ੍ਹ ਸ਼ਾਮਲ ਕਰਨਾ ਲਾਜ਼ਮੀ ਹੈ</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">ਘੱਟੋ-ਘੱਟ <xliff:g id="COUNT">%d</xliff:g> ਗੈਰ-ਸੰਖਿਆਵਾਚੀ ਅੱਖਰ-ਚਿੰਨ੍ਹ ਸ਼ਾਮਲ ਕਰਨਾ ਲਾਜ਼ਮੀ ਹੈ</item>
+      <item quantity="other">ਘੱਟੋ-ਘੱਟ <xliff:g id="COUNT">%d</xliff:g> ਗੈਰ-ਸੰਖਿਆਵਾਚੀ ਅੱਖਰ-ਚਿੰਨ੍ਹ ਸ਼ਾਮਲ ਕਰਨੇ ਲਾਜ਼ਮੀ ਹਨ</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"ਡੀਵਾਈਸ ਪ੍ਰਸ਼ਾਸਕ ਇੱਕ ਹਾਲੀਆ ਪਾਸਵਰਡ ਵਰਤਣ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੰਦਾ ਹੈ।"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"ਆਮ ਪਾਸਵਰਡ ਤੁਹਾਡੇ IT ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਬਲਾਕ ਕੀਤੇ ਗਏ ਹਨ। ਕੋਈ ਵੱਖਰਾ ਪਾਸਵਰਡ ਵਰਤੋ।"</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"ਅੰਕਾਂ ਦਾ ਵਧਦਾ ਕ੍ਰਮ, ਘਟਦਾ ਕ੍ਰਮ, ਜਾਂ ਦੁਹਰਾਈ ਗਈ ਲੜੀ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ"</string>
@@ -727,7 +729,7 @@
     <string name="bluetooth_settings" msgid="5228032727293770389">"ਬਲੂਟੁੱਥ"</string>
     <string name="bluetooth_settings_title" msgid="7261244857456521825">"ਬਲੂਟੁੱਥ"</string>
     <string name="bluetooth_settings_summary" msgid="1221689092429277887">"ਕਨੈਕਸ਼ਨ ਵਿਵਸਥਿਤ ਕਰੋ, ਡੀਵਾਈਸ ਨਾਮ ਅਤੇ ਖੋਜਯੋਗਤਾ ਸੈੱਟ ਕਰੋ"</string>
-    <string name="bluetooth_pairing_request" msgid="7221745525632573125">"ਕੀ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਦੇ ਨਾਲ ਜੋੜੀ ਬਣਾਉਣੀ ਹੈ?"</string>
+    <string name="bluetooth_pairing_request" msgid="7221745525632573125">"ਕੀ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਦੇ ਨਾਲ ਜੋੜਾਬੱਧ ਕਰਨਾ ਹੈ?"</string>
     <string name="bluetooth_pairing_key_msg" msgid="1139230917419961975">"ਬਲੂਟੁੱਥ ਜੋੜਾਬੱਧਕਰਨ ਕੋਡ"</string>
     <string name="bluetooth_enter_passkey_msg" msgid="6205151011298670207">"ਜੋੜਾਬੱਧ ਕਰਨ ਦਾ ਕੋਡ ਟਾਈਪ ਕਰੋ ਫਿਰ ਵਾਪਸ ਜਾਓ ਜਾਂ ਦਾਖਲ ਕਰੋ ਨੂੰ ਦਬਾਓ"</string>
     <string name="bluetooth_enable_alphanumeric_pin" msgid="9138308197078115672">"ਪਿੰਨ ਵਿੱਚ ਅੱਖਰ ਜਾਂ ਚਿੰਨ੍ਹ ਹਨ"</string>
@@ -796,7 +798,7 @@
     <string name="bluetooth_dock_settings_remember" msgid="5512957564380371067">"ਸੈਟਿੰਗਾਂ ਯਾਦ ਰੱਖੋ"</string>
     <string name="bluetooth_max_connected_audio_devices_string" msgid="6799012540303500020">"ਵੱਧ ਤੋਂ ਵੱਧ ਕਨੈਕਟ ਕੀਤੇ ਬਲੂਟੁੱਥ ਆਡੀਓ ਡੀਵਾਈਸ"</string>
     <string name="bluetooth_max_connected_audio_devices_dialog_title" msgid="6049527354499590314">"ਵੱਧ ਤੋਂ ਵੱਧ ਕਨੈਕਟ ਕੀਤੇ ਬਲੂਟੁੱਥ ਆਡੀਓ ਡੀਵਾਈਸ ਚੁਣੋ"</string>
-    <string name="wifi_display_settings_title" msgid="8718182672694575456">"ਕਾਸਟ"</string>
+    <string name="wifi_display_settings_title" msgid="8718182672694575456">"ਕਾਸਟ ਕਰੋ"</string>
     <string name="wifi_display_enable_menu_item" msgid="4578340247147692250">"ਵਾਇਰਲੈਸ ਡਿਸਪਲੇ ਚਾਲੂ ਕਰੋ"</string>
     <string name="wifi_display_no_devices_found" msgid="186501729518830451">"ਨੇੜੇ ਕੋਈ ਡੀਵਾਈਸ ਨਹੀਂ ਮਿਲਿਆ।"</string>
     <string name="wifi_display_status_connecting" msgid="3799827425457383349">"ਕਨੈਕਟ ਕਰ ਰਿਹਾ ਹੈ"</string>
@@ -846,7 +848,7 @@
     <string name="wifi_in_airplane_mode" msgid="4729571191578262246">"ਏਅਰਪਲੇਨ ਮੋਡ ਵਿੱਚ"</string>
     <string name="wifi_notify_open_networks" msgid="4782239203624619655">"ਖੁੱਲ੍ਹੇ ਨੈੱਟਵਰਕ ਦੀ ਸੂਚਨਾ"</string>
     <string name="wifi_notify_open_networks_summary" msgid="1383681260705466715">"ਉੱਚ ਗੁਣਵੱਤਾ ਵਾਲਾ ਕੋਈ ਜਨਤਕ ਨੈੱਟਵਰਕ ਉਪਲਬਧ ਹੋਣ \'ਤੇ ਸੂਚਿਤ ਕਰੋ"</string>
-    <string name="wifi_wakeup" msgid="4963732992164721548">"ਆਪਣੇ ਆਪ ਵਾਈ‑ਫਾਈ ਚਾਲੂ ਕਰੋ"</string>
+    <string name="wifi_wakeup" msgid="4963732992164721548">"ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਵਾਈ‑ਫਾਈ ਚਾਲੂ ਕਰੋ"</string>
     <string name="wifi_wakeup_summary" msgid="1152699417411690">"ਤੁਹਾਡੇ ਘਰੇਲੂ ਨੈੱਟਵਰਕ ਵਰਗੇ ਵਧੀਆ ਕੁਆਲਿਟੀ ਵਾਲੇ ਰੱਖਿਅਤ ਕੀਤੇ ਨੈੱਟਵਰਕਾਂ ਦੇ ਨੇੜੇ ਹੋਣ \'ਤੇ ਵਾਈ-ਫਾਈ ਦੁਬਾਰਾ ਚਾਲੂ ਹੋ ਜਾਵੇਗਾ"</string>
     <string name="wifi_wakeup_summary_no_location" msgid="3007457288587966962">"ਅਣਉਪਲਬਧ ਕਿਉਂਕਿ ਟਿਕਾਣਾ ਬੰਦ ਹੈ। "<annotation id="link">"ਟਿਕਾਣਾ"</annotation>" ਚਾਲੂ ਕਰੋ।"</string>
     <string name="wifi_wakeup_summary_scanning_disabled" msgid="6820040651529910914">"ਅਣਉਪਲਬਧ, ਕਿਉਂਕਿ ਵਾਈ‑ਫਾਈ ਸਕੈਨਿੰਗ ਬੰਦ ਹੈ"</string>
@@ -855,11 +857,11 @@
     <string name="wifi_poor_network_detection_summary" msgid="5539951465985614590">"ਜਦ ਤੱਕ ਤੁਹਾਡੇ ਕੋਲ ਇੱਕ ਚੰਗਾ ਇੰਟਰਨੈੱਟ ਕਨੈਕਸ਼ਨ ਨਾ ਹੋਵੇ ਤਦ ਤੱਕ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਨਾ ਵਰਤੋ"</string>
     <string name="wifi_avoid_poor_network_detection_summary" msgid="1976503191780928104">"ਸਿਰਫ਼ ਉਹ ਨੈੱਟਵਰਕ ਵਰਤੋ ਜਿਨ੍ਹਾਂ ਕੋਲ ਇੱਕ ਚੰਗਾ ਇੰਟਰਨੈੱਟ ਕਨੈਕਸ਼ਨ ਹੈ"</string>
     <string name="use_open_wifi_automatically_title" msgid="3084513215481454350">"ਖੁੱਲ੍ਹੇ ਨੈੱਟਵਰਕਾਂ ਨਾਲ ਕਨੈਕਟ ਕਰੋ"</string>
-    <string name="use_open_wifi_automatically_summary" msgid="8338020172673161754">"ਆਪਣੇ ਆਪ ਵਧੀਆ ਕੁਆਲਿਟੀ ਵਾਲੇ ਜਨਤਕ ਨੈੱਟਵਰਕਾਂ ਨਾਲ ਕਨੈਕਟ ਕਰੋ"</string>
+    <string name="use_open_wifi_automatically_summary" msgid="8338020172673161754">"ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਵਧੀਆ ਕੁਆਲਿਟੀ ਵਾਲੇ ਜਨਤਕ ਨੈੱਟਵਰਕਾਂ ਨਾਲ ਕਨੈਕਟ ਕਰੋ"</string>
     <string name="use_open_wifi_automatically_summary_scoring_disabled" msgid="1559329344492373028">"ਵਰਤਣ ਲਈ, ਕੋਈ ਨੈੱਟਵਰਕ ਰੇਟਿੰਗ ਪ੍ਰਦਾਨਕ ਚੁਣੋ"</string>
     <string name="use_open_wifi_automatically_summary_scorer_unsupported_disabled" msgid="1123080670578756834">"ਵਰਤਣ ਲਈ, ਕੋਈ ਅਨੁਰੂਪ ਨੈੱਟਵਰਕ ਰੇਟਿੰਗ ਪ੍ਰਦਾਨਕ ਚੁਣੋ"</string>
     <string name="wifi_install_credentials" msgid="5650088113710858289">"ਪ੍ਰਮਾਣ-ਪੱਤਰ ਸਥਾਪਤ ਕਰੋ"</string>
-    <string name="wifi_scan_notify_text" msgid="7614101215028336927">"ਟਿਕਾਣਾ ਸਟੀਕਤਾ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ, ਕਿਸੇ ਵੇਲੇ ਵੀ ਐਪਾਂ ਅਤੇ ਸੇਵਾਵਾਂ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕਾਂ ਨੂੰ ਹਾਲੇ ਵੀ ਸਕੈਨ ਕਰ ਸਕਦੀਆਂ ਹਨ, ਭਾਵੇਂ ਵਾਈ-ਫਾਈ ਬੰਦ ਹੋਵੇ। ਇਸ ਦੀ ਵਰਤੋਂ ਟਿਕਾਣਾ-ਆਧਾਰਿਤ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਅਤੇ ਸੇਵਾਵਾਂ ਵਰਗੀਆਂ ਚੀਜ਼ਾਂ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ। ਤੁਸੀਂ ਇਸ ਨੂੰ <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>ਸਕੈਨਿੰਗ ਸੈਟਿੰਗਾਂ<xliff:g id="LINK_END_1">LINK_END</xliff:g> ਵਿੱਚ ਬਦਲ ਸਕਦੇ ਹੋ।"</string>
+    <string name="wifi_scan_notify_text" msgid="7614101215028336927">"ਟਿਕਾਣਾ ਸਟੀਕਤਾ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ, ਹਾਲੇ ਵੀ ਐਪਾਂ ਅਤੇ ਸੇਵਾਵਾਂ ਕਿਸੇ ਵੀ ਵੇਲੇ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕਾਂ ਨੂੰ  ਸਕੈਨ ਕਰ ਸਕਦੀਆਂ ਹਨ, ਭਾਵੇਂ ਵਾਈ-ਫਾਈ ਬੰਦ ਹੀ ਕਿਉਂ ਨਾ ਹੋਵੇ। ਇਸ ਦੀ ਵਰਤੋਂ ਟਿਕਾਣਾ-ਆਧਾਰਿਤ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਅਤੇ ਸੇਵਾਵਾਂ ਵਰਗੀਆਂ ਚੀਜ਼ਾਂ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ। ਤੁਸੀਂ ਇਸ ਨੂੰ <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>ਸਕੈਨਿੰਗ ਸੈਟਿੰਗਾਂ<xliff:g id="LINK_END_1">LINK_END</xliff:g> ਵਿੱਚ ਬਦਲ ਸਕਦੇ ਹੋ।"</string>
     <string name="wifi_scan_notify_text_scanning_off" msgid="723796963816095410">"ਟਿਕਾਣੇ ਦੀ ਸਟੀਕਤਾ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ, <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>ਸਕੈਨਿੰਗ ਸੈਟਿੰਗਾਂ<xliff:g id="LINK_END_1">LINK_END</xliff:g> ਵਿੱਚ ਵਾਈ-ਫਾਈ ਸਕੈਨਿੰਗ ਨੂੰ ਚਾਲੂ ਕਰੋ।"</string>
     <string name="wifi_scan_notify_remember_choice" msgid="1235445971400237444">"ਦੁਬਾਰਾ ਨਾ ਦਿਖਾਓ"</string>
     <string name="wifi_setting_sleep_policy_title" msgid="2120785188625932076">"ਨਿਸ਼ਕਿਰਿਆ ਹੋਣ ਦੇ ਦੌਰਾਨ ਵਾਈ‑ਫਾਈ ਚਾਲੂ ਰੱਖੋ"</string>
@@ -875,7 +877,7 @@
     <string name="wifi_add_network" msgid="4094957940791876640">"ਨੈੱਟਵਰਕ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="wifi_configure_settings_preference_title" msgid="2678534679408777268">"ਵਾਈ‑ਫਾਈ ਤਰਜੀਹਾਂ"</string>
     <string name="wifi_configure_settings_preference_summary_wakeup_on" msgid="5714892572614655675">"ਵਾਈ‑ਫਾਈ ਆਪਣੇ ਆਪ ਦੁਬਾਰਾ ਚਾਲੂ ਹੁੰਦਾ ਹੈ"</string>
-    <string name="wifi_configure_settings_preference_summary_wakeup_off" msgid="286904094152909651">"ਵਾਈ‑ਫਾਈ ਆਪਣੇ ਆਪ ਦੁਬਾਰਾ ਚਾਲੂ ਨਹੀਂ ਹੁੰਦਾ ਹੈ"</string>
+    <string name="wifi_configure_settings_preference_summary_wakeup_off" msgid="286904094152909651">"ਵਾਈ‑ਫਾਈ ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਦੁਬਾਰਾ ਚਾਲੂ ਨਹੀਂ ਹੁੰਦਾ ਹੈ"</string>
     <string name="wifi_access_points" msgid="1647976498906871869">"ਵਾਈ‑ਫਾਈ ਨੈੱਟਵਰਕ"</string>
     <string name="wifi_menu_more_options" msgid="8318269834264035524">"ਹੋਰ ਚੋਣਾਂ"</string>
     <string name="wifi_menu_p2p" msgid="4945665601551289791">"ਵਾਈ‑ਫਾਈ ਡਾਇਰੈਕਟ"</string>
@@ -896,19 +898,19 @@
     <string name="wifi_settings_scanning_required_info" msgid="5913535073390607386">"ਵਾਈ-ਫਾਈ ਸਕੈਨਿੰਗ ਐਪਾਂ ਅਤੇ ਸੇਵਾਵਾਂ ਨੂੰ ਕਿਸੇ ਵੇਲੇ ਵੀ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕਾਂ ਲਈ ਸਕੈਨ ਕਰਨ ਦਿੰਦੀ ਹੈ, ਭਾਵੇਂ ਵਾਈ-ਫਾਈ ਬੰਦ ਹੋਵੇ। ਜਿਵੇਂ ਕਿ, ਇਸਦੀ ਵਰਤੋਂ ਕਰਕੇ ਟਿਕਾਣਾ-ਆਧਾਰਿਤ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਅਤੇ ਸੇਵਾਵਾਂ ਵਰਗੀਆਂ ਚੀਜ਼ਾਂ ਨੂੰ ਬਿਹਤਰ ਬਣਾਇਆ ਜਾ ਸਕਦਾ ਹੈ।"</string>
     <string name="wifi_settings_scanning_required_turn_on" msgid="4327570180594277049">"ਚਾਲੂ ਕਰੋ"</string>
     <string name="wifi_settings_scanning_required_enabled" msgid="3336102100425307040">"ਵਾਈ-ਫਾਈ ਸਕੈਨਿੰਗ ਚਾਲੂ ਕੀਤੀ ਗਈ ਹੈ"</string>
-    <string name="wifi_show_advanced" msgid="8199779277168030597">"ਵਿਕਸਿਤ ਵਿਕਲਪ"</string>
+    <string name="wifi_show_advanced" msgid="8199779277168030597">"ਉਨੱਤ ਵਿਕਲਪ"</string>
     <string name="wifi_advanced_toggle_description_expanded" msgid="1506697245302596510">"ਡ੍ਰੌਪ-ਡਾਊਨ ਸੂਚੀ ਉੱਨਤ ਵਿਕਲਪ। ਸੰਖਿਪਤ ਲਈ ਡਬਲ ਟੈਪ ਕਰੋ।"</string>
     <string name="wifi_advanced_toggle_description_collapsed" msgid="3014965593695454879">"ਡ੍ਰੌਪ-ਡਾਊਨ ਸੂਚੀ ਉੱਨਤ ਵਿਕਲਪ। ਵਿਸਤਾਰ ਕਰਨ ਲਈ ਡਬਲ ਟੈਪ ਕਰੋ।"</string>
     <string name="wifi_ssid" msgid="6746270925975522641">"ਨੈੱਟਵਰਕ ਦਾ ਨਾਮ"</string>
     <string name="wifi_ssid_hint" msgid="5010024648106585165">"SSID ਦਾਖਲ ਕਰੋ"</string>
     <string name="wifi_security" msgid="9136702039496152831">"ਸੁਰੱਖਿਆ"</string>
     <string name="wifi_hidden_network" msgid="6647772204699776833">"ਲੁਕਿਆ ਨੈੱਟਵਰਕ"</string>
-    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"ਜੇਕਰ ਤੁਹਾਡਾ ਰੂਟਰ ਕਿਸੇ ਨੈੱਟਵਰਕ ਆਈ.ਡੀ. ਦਾ ਪ੍ਰਸਾਰਣ ਨਹੀਂ ਕਰ ਰਿਹਾ ਹੈ, ਪਰ ਤੁਸੀਂ ਭਵਿੱਖ ਵਿੱਚ ਇਸ ਨਾਲ ਕਨੈਕਟ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ, ਤਾਂ ਤੁਸੀਂ ਲੁਕੇ ਹੋਏ ਵਜੋਂ ਨੈੱਟਵਰਕ ਨੂੰ ਸੈੱਟ ਕਰ ਸਕਦੇ ਹੋ।\n\nਇਹ ਇੱਕ ਸੁਰੱਖਿਆ ਖਤਰਾ ਬਣਾ ਸਕਦਾ ਹੈ ਕਿਉਂਕਿ ਤੁਹਾਡਾ ਫ਼ੋਨ ਲਗਾਤਾਰ ਨੈੱਟਵਰਕ ਲੱਭਣ ਲਈ ਉਸਦੇ ਸਿਗਨਲ ਨੂੰ ਪ੍ਰਸਾਰਿਤ ਕਰੇਗਾ।\n\nਨੈੱਟਵਰਕ ਨੂੰ ਲੁਕੇ ਵਜੋਂ ਸੈੱਟ ਕਰਨ ਨਾਲ ਤੁਹਾਡੀਆਂ ਰੂਟਰ ਸੈਟਿੰਗਾਂ ਨਹੀਂ ਬਦਲਣਗੀਆਂ।"</string>
+    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"ਜੇਕਰ ਤੁਹਾਡਾ ਰਾਊਟਰ ਕਿਸੇ ਨੈੱਟਵਰਕ ਆਈਡੀ ਦਾ ਪ੍ਰਸਾਰਣ ਨਹੀਂ ਕਰ ਰਿਹਾ ਹੈ, ਪਰ ਤੁਸੀਂ ਭਵਿੱਖ ਵਿੱਚ ਇਸ ਨਾਲ ਕਨੈਕਟ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ, ਤਾਂ ਤੁਸੀਂ ਉਸ ਨੈੱਟਵਰਕ ਨੂੰ ਲੁਕੇ ਹੋਏ ਵਜੋਂ ਸੈੱਟ ਕਰ ਸਕਦੇ ਹੋ।\n\nਇਹ ਇੱਕ ਸੁਰੱਖਿਆ ਖਤਰਾ ਬਣਾ ਸਕਦਾ ਹੈ ਕਿਉਂਕਿ ਤੁਹਾਡਾ ਫ਼ੋਨ ਲਗਾਤਾਰ ਨੈੱਟਵਰਕ ਲੱਭਣ ਲਈ ਸਿਗਨਲ ਨੂੰ ਪ੍ਰਸਾਰਿਤ ਕਰੇਗਾ।\n\nਨੈੱਟਵਰਕ ਨੂੰ ਲੁਕੇ ਵਜੋਂ ਸੈੱਟ ਕਰਨ ਨਾਲ ਤੁਹਾਡੀਆਂ ਰਾਊਟਰ ਸੈਟਿੰਗਾਂ ਨਹੀਂ ਬਦਲਣਗੀਆਂ।"</string>
     <string name="wifi_signal" msgid="696548364467704808">"ਸਿਗਨਲ ਦੀ ਤੀਬਰਤਾ"</string>
     <string name="wifi_status" msgid="3439931558930689940">"ਅਵਸਥਾ"</string>
     <string name="tx_wifi_speed" msgid="2571810085003261073">"ਭੇਜਣ ਸੰਬੰਧੀ ਲਿੰਕ ਦੀ ਗਤੀ"</string>
     <string name="rx_wifi_speed" msgid="7392873246110937187">"ਪ੍ਰਾਪਤ ਹੋਣ ਸੰਬੰਧੀ ਲਿੰਕ ਦੀ ਗਤੀ"</string>
-    <string name="wifi_frequency" msgid="6132852924995724246">"ਬਾਰੰਬਾਰਤਾ"</string>
+    <string name="wifi_frequency" msgid="6132852924995724246">"ਵਾਰਵਾਰਤਾ"</string>
     <string name="wifi_ip_address" msgid="5572539114989914831">"IP ਪਤਾ"</string>
     <string name="passpoint_label" msgid="7429247462404128615">"ਇਸ ਰਾਹੀਂ ਸੁਰੱਖਿਅਤ ਕੀਤਾ ਗਿਆ"</string>
     <string name="passpoint_content" msgid="340527524510304327">"<xliff:g id="NAME">%1$s</xliff:g> ਕ੍ਰੀਡੈਂਸ਼ੀਅਲ"</string>
@@ -943,7 +945,7 @@
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"QR ਕੋਡ ਪੜ੍ਹਿਆ ਨਹੀਂ ਜਾ ਸਕਿਆ। ਕੋਡ ਮੁੜ-ਕੇਂਦਰਿਤ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ। ਜੇ ਸਮੱਸਿਆ ਜਾਰੀ ਰਹਿੰਦੀ ਹੈ, ਤਾਂ ਡੀਵਾਈਸ ਉਤਪਾਦਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ"</string>
     <string name="wifi_dpp_failure_not_compatible" msgid="4320027179973678283">"ਕੋਈ ਗੜਬੜ ਹੋਈ"</string>
-    <string name="wifi_dpp_failure_timeout" msgid="5060065168142109420">"ਪੱਕਾ ਕਰੋ ਕਿ ਡੀਵਾਈਸ ਦਾ ਪਲੱਗ ਲੱਗਾ ਹੋਇਆ ਹੈ, ਚਾਰਜ ਕੀਤਾ ਹੋਇਆ ਅਤੇ ਚਾਲੂ ਹੈ"</string>
+    <string name="wifi_dpp_failure_timeout" msgid="5060065168142109420">"ਪੱਕਾ ਕਰੋ ਕਿ ਡੀਵਾਈਸ ਪਲੱਗ-ਇਨ ਕੀਤਾ ਹੋਇਆ ਹੈ, ਚਾਰਜ ਹੋ ਚੁੱਕਿਆ ਹੈ ਅਤੇ ਚਾਲੂ ਹੈ"</string>
     <string name="wifi_dpp_failure_generic" msgid="7840142544736640189">"ਪੱਕਾ ਕਰੋ ਕਿ ਡੀਵਾਈਸ ਦਾ ਪਲੱਗ ਲੱਗਾ ਹੋਇਆ ਹੈ, ਚਾਰਜ ਕੀਤਾ ਹੋਇਆ ਅਤੇ ਚਾਲੂ ਹੈ। ਜੇ ਸਮੱਸਿਆ ਜਾਰੀ ਰਹਿੰਦੀ ਹੈ, ਤਾਂ ਡੀਵਾਈਸ ਉਤਪਾਦਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ"</string>
     <string name="wifi_dpp_failure_not_supported" msgid="111779621766171626">"ਇਸ ਡੀਵਾਈਸ ਰਾਹੀਂ “<xliff:g id="SSID">%1$s</xliff:g>” ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਦੀ ਸਹੂਲਤ ਨਹੀਂ ਹੈ"</string>
     <string name="wifi_dpp_check_connection_try_again" msgid="7144663015219170999">"ਕਨੈਕਸ਼ਨ ਦੀ ਜਾਂਚ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
@@ -1043,7 +1045,7 @@
     <string name="wifi_p2p_persist_network" msgid="1110453878886476660">"ਇਹ ਕਨੈਕਸ਼ਨ ਯਾਦ ਰੱਖੋ"</string>
     <string name="wifi_p2p_menu_search" msgid="8207638860263805291">"ਡੀਵਾਈਸਾਂ ਖੋਜੋ"</string>
     <string name="wifi_p2p_menu_searching" msgid="7443249001543208106">"ਖੋਜ ਰਿਹਾ ਹੈ..."</string>
-    <string name="wifi_p2p_menu_rename" msgid="2129974878377065488">"ਡੀਵਾਈਸ ਨੂੰ ਮੁੜ-ਨਾਮ ਦਿਓ"</string>
+    <string name="wifi_p2p_menu_rename" msgid="2129974878377065488">"ਡੀਵਾਈਸ ਦਾ ਨਾਮ ਬਦਲੋ"</string>
     <string name="wifi_p2p_peer_devices" msgid="8232126067045093382">"ਪੀਅਰ ਡੀਵਾਈਸ"</string>
     <string name="wifi_p2p_remembered_groups" msgid="1356458238836730346">"ਯਾਦ ਰੱਖੇ ਗਏ ਸਮੂਹ"</string>
     <string name="wifi_p2p_failed_connect_message" msgid="6103436959132424093">"ਕਨੈਕਟ ਨਹੀਂ ਕਰ ਸਕਿਆ।"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"ਵਾਈ-ਫਾਈ"</item>
+    <item msgid="2271962426654621656">"ਮੋਬਾਈਲ"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"ਵਾਈ-ਫਾਈ ਉਪਲਬਧ ਨਾ ਹੋਣ \'ਤੇ ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ ਵਰਤੋ"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ ਉਪਲਬਧ ਨਾ ਹੋਣ \'ਤੇ ਵਾਈ-ਫਾਈ ਵਰਤੋ"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"ਵਾਈ-ਫਾਈ \'ਤੇ ਕਾਲ ਕਰੋ। ਵਾਈ-ਫਾਈ ਕਨੈਕਸ਼ਨ ਟੁੱਟਣ \'ਤੇ ਕਾਲ ਸਮਾਪਤ ਹੋ ਜਾਵੇਗੀ।"</string>
@@ -1165,7 +1170,7 @@
     <string name="accessibility_personal_account_title" msgid="7251761883688839354">"ਨਿੱਜੀ ਖਾਤਾ - <xliff:g id="MANAGED_BY">%s</xliff:g>"</string>
     <string name="search_settings" msgid="5809250790214921377">"ਖੋਜੋ"</string>
     <string name="display_settings" msgid="1045535829232307190">"ਡਿਸਪਲੇ"</string>
-    <string name="accelerometer_title" msgid="2427487734964971453">"ਸਕ੍ਰੀਨ ਆਪਣੇ-ਆਪ ਘੁੰਮਾਓ"</string>
+    <string name="accelerometer_title" msgid="2427487734964971453">"ਸਕ੍ਰੀਨ ਸਵੈ-ਘੁਮਾਓ"</string>
     <string name="color_mode_title" msgid="8164858320869449142">"ਰੰਗ"</string>
     <string name="color_mode_option_natural" msgid="1292837781836645320">"ਕੁਦਰਤੀ"</string>
     <string name="color_mode_option_boosted" msgid="453557938434778933">"ਵਧਾਇਆ ਗਿਆ"</string>
@@ -1249,7 +1254,7 @@
     <string name="screensaver_settings_summary_off" msgid="6119947316484763131">"ਬੰਦ"</string>
     <string name="screensaver_settings_disabled_prompt" msgid="1897518064782596947">"ਇਹ ਕੰਟਰੋਲ ਕਰਨ ਲਈ ਕਿ ਜਦੋਂ ਫ਼ੋਨ ਡੌਕ ਕੀਤਾ ਅਤੇ/ਜਾਂ ਸਲੀਪ ਮੋਡ ਵਿੱਚ ਹੁੰਦਾ ਹੈ ਉਦੋਂ ਕੀ ਹੁੰਦਾ ਹੈ, ਸਕ੍ਰੀਨ ਸੇਵਰ ਚਾਲੂ ਕਰੋ।"</string>
     <string name="screensaver_settings_when_to_dream" msgid="3763052013516826348">"ਕਦੋਂ ਸ਼ੁਰੂ ਕਰਨਾ ਹੈ"</string>
-    <string name="screensaver_settings_current" msgid="4017556173596361672">"ਵਰਤਮਾਨ ਸਕ੍ਰੀਨ ਸੇਵਰ"</string>
+    <string name="screensaver_settings_current" msgid="4017556173596361672">"ਮੌਜੂਦਾ ਸਕ੍ਰੀਨ ਸੇਵਰ"</string>
     <string name="screensaver_settings_dream_start" msgid="3772227299054662550">"ਹੁਣੇ ਚਾਲੂ ਕਰੋ"</string>
     <string name="screensaver_settings_button" msgid="4662384378821837589">"ਸੈਟਿੰਗਾਂ"</string>
     <string name="automatic_brightness" msgid="8663792987774126192">"ਸਵੈਚਲਿਤ ਚਮਕ"</string>
@@ -1312,7 +1317,7 @@
     <string name="hardware_revision" msgid="3315744162524354246">"ਹਾਰਡਵੇਅਰ ਵਰਜਨ"</string>
     <string name="fcc_equipment_id" msgid="8681995718533066093">"ਉਪਕਰਨ ਆਈ.ਡੀ."</string>
     <string name="baseband_version" msgid="9115560821840757786">"ਬੇਸਬੈਂਡ ਵਰਜਨ"</string>
-    <string name="kernel_version" msgid="8226014277756019297">"Kernel ਵਰਜਨ"</string>
+    <string name="kernel_version" msgid="8226014277756019297">"ਕਰਨਲ ਵਰਜਨ"</string>
     <string name="build_number" msgid="8648447688306248633">"ਬਿਲਡ ਨੰਬਰ"</string>
     <string name="module_version" msgid="1127871672527968730">"ਮੁੱਖ ਮਾਡਿਊਲ ਵਰਜਨ"</string>
     <string name="device_info_not_available" msgid="3762481874992799474">"ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
@@ -1355,7 +1360,7 @@
     <string name="status_wifi_mac_address" msgid="3868452167971295995">"ਵਾਈ‑ਫਾਈ MAC ਪਤਾ"</string>
     <string name="status_bt_address" msgid="460568179311735657">"ਬਲੂਟੁੱਥ ਪਤਾ"</string>
     <string name="status_serial_number" msgid="8257722124627415159">"ਸੀਰੀਅਲ ਨੰਬਰ"</string>
-    <string name="status_up_time" msgid="77128395333934087">"ਅੱਪ ਟਾਈਮ"</string>
+    <string name="status_up_time" msgid="77128395333934087">"ਚਾਲੂ ਰਹਿਣ ਦਾ ਸਮਾਂ"</string>
     <string name="status_awake_time" msgid="1251959094010776954">"ਸਕਿਰਿਆ ਸਮਾਂ"</string>
     <string name="internal_memory" msgid="8632841998435408869">"ਅੰਦਰੂਨੀ ਸਟੋਰੇਜ"</string>
     <string name="sd_memory" product="nosdcard" msgid="1377713983817298275">"USB ਸਟੋਰੇਜ"</string>
@@ -1521,7 +1526,7 @@
     <string name="storage_wizard_ready_v2_internal_moved_body" msgid="4133133596316768033">"ਤੁਹਾਡੀ ਸਮੱਗਰੀ <xliff:g id="NAME_0">^1</xliff:g> ਵਿੱਚ ਲਿਜਾਈ ਗਈ। \n\nਇਸ <xliff:g id="NAME_1">^2</xliff:g> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ, "<b>"ਸੈਟਿੰਗਾਂ &gt; ਸਟੋਰੇਜ"</b>" \'ਤੇ ਜਾਓ।"</string>
     <string name="battery_status_title" msgid="8731200319740671905">"ਬੈਟਰੀ ਸਥਿਤੀ"</string>
     <string name="battery_level_title" msgid="5207775387973771646">"ਬੈਟਰੀ ਪੱਧਰ"</string>
-    <string name="apn_settings" msgid="8130776653826271664">"APNs"</string>
+    <string name="apn_settings" msgid="8130776653826271664">"APN"</string>
     <string name="apn_edit" msgid="4350571070853305357">"ਪਹੁੰਚ ਬਿੰਦੂ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
     <string name="apn_not_set" msgid="5344235604466825691">"ਸੈੱਟ ਨਹੀਂ ਕੀਤਾ"</string>
     <string name="apn_name" msgid="8431432886706852226">"ਨਾਮ"</string>
@@ -1536,20 +1541,20 @@
     <string name="apn_mms_port" msgid="6606572282014819299">"MMS ਪੋਰਟ"</string>
     <string name="apn_mcc" msgid="9138301167194779180">"MCC"</string>
     <string name="apn_mnc" msgid="1276161191283274976">"MNC"</string>
-    <string name="apn_auth_type" msgid="4286147728662523362">"ਪ੍ਰਮਾਣੀਕਰਨ ਪ੍ਰਕਾਰ"</string>
+    <string name="apn_auth_type" msgid="4286147728662523362">"ਪ੍ਰਮਾਣੀਕਰਨ ਦੀ ਕਿਸਮ"</string>
     <string name="apn_auth_type_none" msgid="3679273936413404046">"ਕੋਈ ਨਹੀਂ"</string>
     <string name="apn_auth_type_pap" msgid="6155876141679480864">"PAP"</string>
     <string name="apn_auth_type_chap" msgid="5484031368454788686">"CHAP"</string>
     <string name="apn_auth_type_pap_chap" msgid="2977833804460109203">"PAP ਜਾਂ CHAP"</string>
-    <string name="apn_type" msgid="6725346490902871146">"APN ਪ੍ਰਕਾਰ"</string>
+    <string name="apn_type" msgid="6725346490902871146">"APN ਦੀ ਕਿਸਮ"</string>
     <string name="apn_protocol" msgid="1240197323563960912">"APN ਪ੍ਰੋਟੋਕੋਲ"</string>
     <string name="apn_roaming_protocol" msgid="6913336248771263497">"APN ਰੋਮਿੰਗ ਪ੍ਰੋਟੋਕੋਲ"</string>
     <string name="carrier_enabled" msgid="1819916725305365581">"APN ਚਾਲੂ/ਬੰਦ"</string>
     <string name="carrier_enabled_summaryOn" msgid="6219221535461945771">"APN ਸਮਰਥਿਤ"</string>
     <string name="carrier_enabled_summaryOff" msgid="4093019532796386622">"APN ਅਸਮਰਥਿਤ"</string>
-    <string name="bearer" msgid="4378444317087536401">"ਬੀਅਰਰ"</string>
-    <string name="mvno_type" msgid="3150755279048149624">"MVNO ਪ੍ਰਕਾਰ"</string>
-    <string name="mvno_match_data" msgid="629287305803195245">"MVNO ਵੈਲਯੂ"</string>
+    <string name="bearer" msgid="4378444317087536401">"ਧਾਰਕ"</string>
+    <string name="mvno_type" msgid="3150755279048149624">"MVNO ਦੀ ਕਿਸਮ"</string>
+    <string name="mvno_match_data" msgid="629287305803195245">"MVNO ਮੁੱਲ"</string>
     <string name="menu_delete" msgid="8646081395424055735">"APN ਮਿਟਾਓ"</string>
     <string name="menu_new" msgid="7529219814721969024">"ਨਵਾਂ APN"</string>
     <string name="menu_save" msgid="7310230314430623215">"ਰੱਖਿਅਤ ਕਰੋ"</string>
@@ -1651,7 +1656,7 @@
     </plurals>
     <string name="location_category_recent_location_access" msgid="286059523360285026">"ਹਾਲੀਆ ਟਿਕਾਣਾ ਪਹੁੰਚ"</string>
     <string name="location_recent_location_access_view_details" msgid="2051602261436245905">"ਵੇਰਵੇ ਦੇਖੋ"</string>
-    <string name="location_no_recent_apps" msgid="77502059586413278">"ਕਿਸੇ ਐਪਸ ਨੇ ਹਾਲ ਵਿੱਚ ਹੀ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਦੀ ਬੇਨਤੀ ਨਹੀਂ ਕੀਤੀ ਹੈ"</string>
+    <string name="location_no_recent_apps" msgid="77502059586413278">"ਕਿਸੇ ਐਪ ਨੇ ਵੀ ਹਾਲ ਵਿੱਚ ਟਿਕਾਣੇ ਦੀ ਬੇਨਤੀ ਨਹੀਂ ਕੀਤੀ ਹੈ"</string>
     <string name="location_no_recent_accesses" msgid="6289916310397279890">"ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਵਾਲੀਆਂ ਕੋਈ ਐਪਾਂ ਨਹੀਂ"</string>
     <string name="location_high_battery_use" msgid="7177199869979522663">"ਉੱਚ ਬੈਟਰੀ ਵਰਤੋਂ"</string>
     <string name="location_low_battery_use" msgid="5030448574501435888">"ਘੱਟ ਬੈਟਰੀ ਵਰਤੋਂ"</string>
@@ -1690,7 +1695,7 @@
     <string name="terms_title" msgid="1804549588198223771">"ਨਿਯਮ ਅਤੇ ਸ਼ਰਤਾਂ"</string>
     <string name="webview_license_title" msgid="8244960025549725051">"ਸਿਸਟਮ WebView ਲਾਇਸੰਸ"</string>
     <string name="wallpaper_attributions" msgid="2941987966332943253">"ਵਾਲਪੇਪਰ"</string>
-    <string name="wallpaper_attributions_values" msgid="4461979853894606323">"ਸੈਟੇਲਾਈਟ ਇਮੇਜਰੀ ਪ੍ਰਦਾਤਾ:\n©2014 CNES / Astrium, DigitalGlobe, Bluesky"</string>
+    <string name="wallpaper_attributions_values" msgid="4461979853894606323">"ਉਪਗ੍ਰਹਿ ਇਮੇਜਰੀ ਪ੍ਰਦਾਤਾ:\n©2014 CNES / Astrium, DigitalGlobe, Bluesky"</string>
     <string name="settings_manual_activity_title" msgid="7599911755054286789">"ਮੈਨੁਅਲ"</string>
     <string name="settings_manual_activity_unavailable" msgid="4872502775018655343">"ਮੈਨੁਅਲ ਲੋਡ ਕਰਨ ਵਿੱਚ ਇੱਕ ਸਮੱਸਿਆ ਹੋਈ ਸੀ।"</string>
     <string name="settings_license_activity_title" msgid="1099045216283677608">"ਤੀਜੀ-ਧਿਰ ਦੇ ਲਾਇਸੰਸ"</string>
@@ -1741,7 +1746,7 @@
     <string name="lockpassword_confirm_your_password_header_frp" msgid="7326670978891793470">"Verify password"</string>
     <string name="lockpassword_invalid_pin" msgid="3059022215815900137">"ਗਲਤ ਪਿੰਨ"</string>
     <string name="lockpassword_invalid_password" msgid="8374331995318204099">"ਗਲਤ ਪਾਸਵਰਡ"</string>
-    <string name="lockpattern_need_to_unlock_wrong" msgid="1328670466959377948">"ਗ਼ਲਤ ਪੈਟਰਨ"</string>
+    <string name="lockpattern_need_to_unlock_wrong" msgid="1328670466959377948">"ਗਲਤ ਪੈਟਰਨ"</string>
     <string name="lock_settings_title" msgid="233657584969886812">"ਡੀਵਾਈਸ ਸੁਰੱਖਿਆ"</string>
     <string name="lockpattern_change_lock_pattern_label" msgid="333149762562581510">"ਅਣਲਾਕ ਪੈਟਰਨ ਬਦਲੋ"</string>
     <string name="lockpattern_change_lock_pin_label" msgid="3435796032210265723">"ਅਣਲਾਕ ਪਿੰਨ ਬਦਲੋ"</string>
@@ -1754,7 +1759,7 @@
     <string name="lockpattern_pattern_confirmed_header" msgid="5603156929428721407">"ਤੁਹਾਡਾ ਨਵਾਂ ਅਣਲਾਕ ਪੈਟਰਨ"</string>
     <string name="lockpattern_confirm_button_text" msgid="7059311304112902598">"ਪੁਸ਼ਟੀ ਕਰੋ"</string>
     <string name="lockpattern_restart_button_text" msgid="4322968353922529868">"ਰੀਡ੍ਰਾ ਕਰੋ"</string>
-    <string name="lockpattern_retry_button_text" msgid="5473976578241534298">"ਹਟਾਓ"</string>
+    <string name="lockpattern_retry_button_text" msgid="5473976578241534298">"ਕਲੀਅਰ ਕਰੋ"</string>
     <string name="lockpattern_continue_button_text" msgid="3328913552656376892">"ਜਾਰੀ ਰੱਖੋ"</string>
     <string name="lockpattern_settings_title" msgid="5152005866870766842">"ਪੈਟਰਨ ਅਣਲਾਕ ਕਰੋ"</string>
     <string name="lockpattern_settings_enable_title" msgid="8508410891939268080">"ਲੁੜੀਂਦਾ ਪੈਟਰਨ"</string>
@@ -1800,7 +1805,7 @@
     <string name="screen_compatibility_label" msgid="3638271673726075815">"ਸਕ੍ਰੀਨ ਅਨੁਰੂਪਤਾ"</string>
     <string name="permissions_label" msgid="7341733648403464213">"ਇਜਾਜ਼ਤਾਂ"</string>
     <string name="cache_header_label" msgid="3202284481380361966">"ਕੈਸ਼ੇ"</string>
-    <string name="clear_cache_btn_text" msgid="107507684844780651">"ਕੈਸ਼ੇ ਹਟਾਓ"</string>
+    <string name="clear_cache_btn_text" msgid="107507684844780651">"ਕੈਸ਼ੇ ਕਲੀਅਰ ਕਰੋ"</string>
     <string name="cache_size_label" msgid="6205173678102220499">"ਕੈਸ਼ੇ"</string>
     <plurals name="uri_permissions_text" formatted="false" msgid="8938478333743197020">
       <item quantity="one">%d ਆਈਟਮਾਂ</item>
@@ -1824,7 +1829,7 @@
     <string name="app_factory_reset" msgid="8718986000278776272">"ਅੱਪਡੇਟਾਂ ਅਣਸਥਾਪਤ ਕਰੋ"</string>
     <string name="auto_launch_enable_text" msgid="3372898942144027341">"ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਕੁਝ ਕਾਰਵਾਈਆਂ ਲਈ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਤੌਰ \'ਤੇ ਲਾਂਚ ਕਰਨ ਦੀ ਚੋਣ ਕੀਤੀ ਹੈ।"</string>
     <string name="always_allow_bind_appwidgets_text" msgid="2286211654774611037">"ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਵਿਜੇਟ ਬਣਾਉਣ ਲਈ ਅਤੇ ਉਹਨਾਂ ਦੇ ਡਾਟਾ ਤੱਕ ਪਹੁੰਚ ਦੀ ਆਗਿਆ ਦੇਣ ਦੀ ਚੋਣ ਕੀਤੀ ਹੈ।"</string>
-    <string name="auto_launch_disable_text" msgid="8560921288036801416">"ਕੋਈ ਡਿਫੌਲਟਸ ਸੈਟ ਨਹੀਂ ਕੀਤੇ"</string>
+    <string name="auto_launch_disable_text" msgid="8560921288036801416">"ਕੋਈ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਸੈੱਟ ਨਹੀਂ ਕੀਤੇ"</string>
     <string name="clear_activities" msgid="2068014972549235347">"ਡਿਫੌਲਟਸ ਹਟਾਓ"</string>
     <string name="screen_compatibility_text" msgid="1768064020294301496">"ਇਹ ਐਪ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਲਈ ਡਿਜਾਈਨ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ। ਤੁਸੀਂ ਇਸਤੇ ਨਿਯੰਤਰਣ ਪਾ ਸਕਦੇ ਹੋ ਕਿ ਇਹ ਇੱਥੇ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਕਿਵੇਂ ਵਿਵਸਥਿਤ ਕਰੇ।"</string>
     <string name="ask_compatibility" msgid="6687958195768084807">"ਜਦੋਂ ਲੌਂਚ ਕੀਤਾ ਹੋਵੇ ਤਾਂ ਪੁੱਛੋ"</string>
@@ -1833,7 +1838,7 @@
     <string name="sort_order_alpha" msgid="6689698854460261212">"ਨਾਮ ਮੁਤਾਬਕ ਕ੍ਰਮ-ਬੱਧ ਕਰੋ"</string>
     <string name="sort_order_size" msgid="3167376197248713027">"ਆਕਾਰ ਮੁਤਾਬਕ ਕ੍ਰਮ-ਬੱਧ ਕਰੋ"</string>
     <string name="sort_order_recent_notification" msgid="5592496977404445941">"ਸਭ ਤੋਂ ਹਾਲੀਆ"</string>
-    <string name="sort_order_frequent_notification" msgid="5640245013098010347">"ਅਕਸਰ"</string>
+    <string name="sort_order_frequent_notification" msgid="5640245013098010347">"ਅਕਸਰ ਵਰਤੀਆਂ ਜਾਣ ਵਾਲੀਆਂ"</string>
     <string name="show_running_services" msgid="1895994322704667543">"ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ ਦਿਖਾਓ"</string>
     <string name="show_background_processes" msgid="88012264528093617">"ਕੈਸ਼ ਕੀਤੀਆਂ ਪ੍ਰਕਿਰਿਆਵਾਂ ਦਿਖਾਓ"</string>
     <string name="default_emergency_app" msgid="286530070173495823">"ਆਪਾਤਕਾਲ ਐਪ"</string>
@@ -2529,7 +2534,7 @@
     <string name="user_credentials" msgid="8365731467650306757">"ਵਰਤੋਂਕਾਰ ਕ੍ਰੀਡੈਂਸ਼ੀਅਲ"</string>
     <string name="user_credentials_summary" msgid="7350223899317423252">"ਸਟੋਰ ਕੀਤੇ ਕ੍ਰੀਡੈਂਸ਼ੀਅਲ ਦੇਖੋ ਅਤੇ ਸੋਧੋ"</string>
     <string name="advanced_security_title" msgid="286883005673855845">"ਵਿਕਸਿਤ"</string>
-    <string name="credential_storage_type" msgid="2585337320206095255">"ਸਟੋਰੇਜ ਦਾ ਪ੍ਰਕਾਰ"</string>
+    <string name="credential_storage_type" msgid="2585337320206095255">"ਸਟੋਰੇਜ ਦੀ ਕਿਸਮ"</string>
     <string name="credential_storage_type_hardware" msgid="5054143224259023600">"ਹਾਰਡਵੇਅਰ-ਸਮਰਥਿਤ"</string>
     <string name="credential_storage_type_software" msgid="1335905150062717150">"ਕੇਵਲ ਸਾਫਟਵੇਅਰ"</string>
     <string name="credentials_settings_not_available" msgid="5490259681690183274">"ਇਸ ਵਰਤੋਂਕਾਰ ਲਈ ਕ੍ਰੀਡੈਂਸ਼ੀਅਲ ਉਪਲਬਧ ਨਹੀਂ ਹਨ"</string>
@@ -2567,14 +2572,14 @@
     <string name="select_device_admin_msg" msgid="4173769638399075387">"ਡੀਵਾਈਸ ਪ੍ਰਸ਼ਾਸਕ ਐਪਾਂ"</string>
     <string name="no_device_admins" msgid="4129231900385977460">"ਕੋਈ ਵੀ ਡੀਵਾਈਸ ਪ੍ਰਸ਼ਾਸਕ ਐਪਾਂ ਉਪਲਬਧ ਨਹੀਂ ਹਨ"</string>
     <string name="personal_device_admin_title" msgid="759440849188565661">"ਨਿੱਜੀ"</string>
-    <string name="managed_device_admin_title" msgid="8021522755492551726">"ਦਫ਼ਤਰ"</string>
+    <string name="managed_device_admin_title" msgid="8021522755492551726">"ਕਾਰਜ-ਸਥਾਨ"</string>
     <string name="sms_access_restriction_enabled" msgid="3006320256764718303">"SMS ਅਤੇ ਕਾਲ ਲੌਗ ਤੱਕ ਪਹੁੰਚ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਓ"</string>
     <string name="sms_access_restriction_enabled_summary" msgid="9011946580977780063">"ਸਿਰਫ਼ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਫ਼ੋਨ ਅਤੇ ਸੁਨੇਹੇ ਐਪਾਂ ਨੂੰ SMS ਅਤੇ ਕਾਲ ਲੌਗ ਇਜਾਜ਼ਤਾਂ ਹਨ"</string>
     <string name="no_trust_agents" msgid="5757792915019113084">"ਕੋਈ ਉਪਲਬਧ ਭਰੋਸੇਯੋਗ ਏਜੰਟ ਨਹੀਂ"</string>
-    <string name="add_device_admin_msg" msgid="3573765823476931173">"ਡੀਵਾਈਸ ਪ੍ਰਸ਼ਾਸਕ ਐਪ ਨੂੰ ਸਰਗਰਮ ਕਰੀਏ?"</string>
-    <string name="add_device_admin" msgid="1621152410207260584">"ਇਸ ਡੀਵਾਈਸ ਪ੍ਰਸ਼ਾਸਕ ਐਪ ਨੂੰ ਸਰਗਰਮ ਕਰੋ"</string>
+    <string name="add_device_admin_msg" msgid="3573765823476931173">"ਡੀਵਾਈਸ ਪ੍ਰਸ਼ਾਸਕ ਐਪ ਨੂੰ ਕਿਰਿਆਸ਼ੀਲ ਕਰੀਏ?"</string>
+    <string name="add_device_admin" msgid="1621152410207260584">"ਇਸ ਡੀਵਾਈਸ ਪ੍ਰਸ਼ਾਸਕ ਐਪ ਨੂੰ ਕਿਰਿਆਸ਼ੀਲ ਕਰੋ"</string>
     <string name="device_admin_add_title" msgid="6097881332139146897">"ਡੀਵਾਈਸ ਪ੍ਰਸ਼ਾਸਕ"</string>
-    <string name="device_admin_warning" msgid="4421817419326480449">"ਇਸ ਪ੍ਰਸ਼ਾਸਕ ਐਪ ਨੂੰ ਸਰਗਰਮ ਕਰਨ ਨਾਲ <xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਨੂੰ ਅੱਗੇ ਦਿੱਤੀਆਂ ਕਾਰਵਾਈਆਂ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮਿਲਦੀ ਹੈ:"</string>
+    <string name="device_admin_warning" msgid="4421817419326480449">"ਇਸ ਪ੍ਰਸ਼ਾਸਕ ਐਪ ਨੂੰ ਕਿਰਿਆਸ਼ੀਲ ਕਰਨ ਨਾਲ <xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਨੂੰ ਅੱਗੇ ਦਿੱਤੀਆਂ ਕਾਰਵਾਈਆਂ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮਿਲਦੀ ਹੈ:"</string>
     <string name="device_admin_status" msgid="5424944611789040723">"ਇਹ ਪ੍ਰਸ਼ਾਸਕ ਐਪ ਕਿਰਿਆਸ਼ੀਲ ਹੈ ਅਤੇ <xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਨੂੰ ਅੱਗੇ ਦਿੱਤੀਆਂ ਕਾਰਵਾਈਆਂ ਨੂੰ ਕਰਨ ਲਈ ਇਜਾਜ਼ਤ ਦਿੰਦੀ ਹੈ:"</string>
     <string name="profile_owner_add_title" msgid="735805919754362791">"ਕੀ ਪ੍ਰੋਫਾਈਲ ਮੈਨੇਜਰ ਨੂੰ ਕਿਰਿਆਸ਼ੀਲ ਬਣਾਉਣਾ ਹੈ?"</string>
     <string name="adding_profile_owner_warning" msgid="1284541194547382194">"ਜਾਰੀ ਰੱਖਣ ਦੁਆਰਾ, ਤੁਹਾਡੇ ਵਰਤੋਂਕਾਰ ਨੂੰ ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਦੁਆਰਾ ਪ੍ਰਬੰਧਿਤ ਕੀਤਾ ਜਾਏਗਾ ਜੋ ਕਿ ਤੁਹਾਡੇ ਨਿੱਜੀ ਡਾਟੇ ਤੋਂ ਇਲਾਵਾ, ਸੰਬੰਧਿਤ ਡਾਟੇ ਨੂੰ ਸਟੋਰ ਕਰਨ ਦੇ ਵੀ ਯੋਗ ਹੋ ਸਕਦਾ ਹੈ।\n\n ਤੁਹਾਡਾ ਪ੍ਰਸ਼ਾਸਕ ਇਸ ਵਰਤੋਂਕਾਰ ਨਾਲ ਸੰਬੰਧਿਤ ਸੈਟਿੰਗਾਂ, ਪਹੁੰਚ, ਐਪਾਂ, ਅਤੇ ਡਾਟੇ ਦੀ ਨਿਗਰਾਨੀ ਅਤੇ ਪ੍ਰਬੰਧਨ ਕਰ ਸਕਦਾ ਹੈ, ਜਿਸ ਵਿੱਚ ਨੈੱਟਵਰਕ ਕਿਰਿਆਸ਼ੀਲਤਾ ਅਤੇ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀ ਟਿਕਾਣਾ ਜਾਣਕਾਰੀ ਵੀ ਸ਼ਾਮਲ ਹੈ।"</string>
@@ -2665,8 +2670,8 @@
     <string name="data_usage_menu_sim_cards" msgid="8508154611676507088">"SIM ਕਾਰਡ"</string>
     <string name="data_usage_cellular_data_summary" msgid="9162777397135709280">"ਸੀਮਾ ਤੇ ਰੋਕਿਆ"</string>
     <string name="account_settings_menu_auto_sync" msgid="2673669556006027506">" ਡਾਟਾ  ਸਵੈ-ਸਮਕਾਲੀਕਿਰਤ ਕਰੋ"</string>
-    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"ਨਿੱਜੀ  ਡਾਟਾ  ਆਟੋ-ਸਿੰਕ ਕਰੋ"</string>
-    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"ਕੰਮ  ਡਾਟਾ  ਆਟੋ-ਸਿੰਕ ਕਰੋ"</string>
+    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"ਨਿੱਜੀ ਡਾਟਾ ਸਵੈ-ਸਮਕਾਲੀਕਿਰਤ ਕਰੋ"</string>
+    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"ਕੰਮ ਦਾ ਡਾਟਾ ਸਵੈ-ਸਮਕਾਲੀਕਿਰਤ ਕਰੋ"</string>
     <string name="data_usage_change_cycle" msgid="447761920472170031">"ਸਾਈਕਲ ਬਦਲੋ..."</string>
     <string name="data_usage_pick_cycle_day" msgid="6319750879145917066">"ਡਾਟਾ ਵਰਤੋਂ ਸਾਈਕਲ ਰੀਸੈੱਟ ਕਰਨ ਲਈ ਮਹੀਨੇ ਦਾ ਦਿਨ:"</string>
     <string name="data_usage_empty" msgid="7981405723435034032">"ਇਸ ਮਿਆਦ ਦੇ ਦੌਰਾਨ ਕਿਸੇ ਐਪਸ ਨੇ  ਡਾਟਾ  ਨਹੀਂ ਵਰਤਿਆ।"</string>
@@ -2710,7 +2715,7 @@
     <string name="data_usage_limit_editor_title" msgid="1687908662154108293">"ਡਾਟਾ ਵਰਤੋਂ ਸੀਮਾ ਸੈੱਟ ਕਰੋ"</string>
     <string name="data_usage_limit_dialog_title" msgid="8804760847110131518">"ਡਾਟਾ ਵਰਤੋਂ ਸੀਮਤ ਕਰਨਾ"</string>
     <string name="data_usage_limit_dialog_mobile" product="tablet" msgid="2000713577999830647">"ਤੁਹਾਡਾ ਟੈਬਲੈੱਟ ਤੁਹਾਡੇ ਵੱਲੋਂ ਸੈੱਟ ਕੀਤੀ ਮੋਬਾਈਲ ਡਾਟੇ ਦੀ ਸੀਮਾ ਉੱਤੇ ਪਹੁੰਚਣ \'ਤੇ ਮੋਬਾਈਲ ਡਾਟਾ ਬੰਦ ਕਰ ਦੇਵੇਗਾ।\n\nਕਿਉਂਕਿ ਡਾਟਾ ਵਰਤੋਂ ਤੁਹਾਡੇ ਟੈਬਲੈੱਟ ਵੱਲੋਂ ਮਾਪੀ ਜਾਂਦੀ ਹੈ ਅਤੇ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਤੁਹਾਡਾ ਕੈਰੀਅਰ ਵਰਤੋਂ ਦਾ ਹਿਸਾਬ ਵੱਖਰੇ ਢੰਗ ਨਾਲ ਲਗਾਵੇ, ਇਸ ਕਰਕੇ ਕੋਈ ਕੰਜੂਸੀਕਾਰੀ ਸੀਮਾ ਸੈੱਟ ਕਰਨ ਬਾਰੇ ਵਿਚਾਰ ਕਰੋ।"</string>
-    <string name="data_usage_limit_dialog_mobile" product="default" msgid="943546278705619205">"ਤੁਹਾਡਾ ਫ਼ੋਨ ਤੁਹਾਡੇ ਵੱਲੋਂ ਸੈੱਟ ਕੀਤੀ ਮੋਬਾਈਲ ਡਾਟੇ ਦੀ ਸੀਮਾ ਉੱਤੇ ਪਹੁੰਚਣ \'ਤੇ ਮੋਬਾਈਲ ਡਾਟਾ ਬੰਦ ਕਰ ਦੇਵੇਗਾ।\n\nਕਿਉਂਕਿ ਡਾਟਾ ਵਰਤੋਂ ਤੁਹਾਡੇ ਫ਼ੋਨ ਵੱਲੋਂ ਮਾਪਿਆ ਜਾਂਦਾ ਹੈ ਅਤੇ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਤੁਹਾਡਾ ਕੈਰੀਅਰ ਵਰਤੋਂ ਦਾ ਹਿਸਾਬ ਵੱਖਰੇ ਢੰਗ ਨਾਲ ਲਗਾਵੇ, ਇਸ ਕਰਕੇ ਕੋਈ ਕੰਜੂਸੀਕਾਰੀ ਸੀਮਾ ਸੈੱਟ ਕਰਨ ਬਾਰੇ ਵਿਚਾਰ ਕਰੋ।"</string>
+    <string name="data_usage_limit_dialog_mobile" product="default" msgid="943546278705619205">"ਤੁਹਾਡਾ ਫ਼ੋਨ ਤੁਹਾਡੇ ਵੱਲੋਂ ਸੈੱਟ ਕੀਤੀ ਮੋਬਾਈਲ ਡਾਟੇ ਦੀ ਸੀਮਾ ਉੱਤੇ ਪਹੁੰਚਣ \'ਤੇ ਮੋਬਾਈਲ ਡਾਟਾ ਬੰਦ ਕਰ ਦੇਵੇਗਾ।\n\nਕਿਉਂਕਿ ਡਾਟਾ ਵਰਤੋਂ ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਵੱਲੋਂ ਮਾਪਿਆ ਜਾਂਦਾ ਹੈ ਅਤੇ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਤੁਹਾਡਾ ਕੈਰੀਅਰ ਵਰਤੋਂ ਦਾ ਹਿਸਾਬ ਵੱਖਰੇ ਢੰਗ ਨਾਲ ਲਗਾਵੇ, ਇਸ ਕਰਕੇ ਕੋਈ ਦਰਮਿਆਨੀ ਸੀਮਾ ਸੈੱਟ ਕਰਨ ਬਾਰੇ ਵਿਚਾਰ ਕਰੋ।"</string>
     <string name="data_usage_restrict_background_title" msgid="3568746530413220844">"ਕੀ ਪਿਛੋਕੜ  ਡਾਟਾ  ਤੇ ਪ੍ਰਤਿਬੰਧ ਲਾਉਣਾ ਹੈ?"</string>
     <string name="data_usage_restrict_background" msgid="995811034744808575">"ਜੇਕਰ ਤੁਸੀਂ ਬੈਕਗ੍ਰਾਊਂਡ ਮੋਬਾਈਲ ਡਾਟੇ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦੇ ਹੋ, ਤਾਂ ਕੁਝ ਐਪਾਂ ਅਤੇ ਸੇਵਾਵਾਂ ਉਦੋਂ ਤੱਕ ਕੰਮ ਨਹੀਂ ਕਰਨਗੀਆਂ ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਵਾਈ‑ਫਾਈ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਹੁੰਦੇ।"</string>
     <string name="data_usage_restrict_background_multiuser" product="tablet" msgid="6032810839234864814">"ਜੇਕਰ ਤੁਸੀਂ ਬੈਕਗ੍ਰਾਊਂਡ ਮੋਬਾਈਲ ਡਾਟੇ \'ਤੇ ਪ੍ਰਤੀਬੰਧ ਲਗਾਉਂਦੇ ਹੋ, ਤਾਂ ਕੁਝ ਐਪਾਂ ਅਤੇ ਸੇਵਾਵਾਂ ਉਦੋਂ ਤੱਕ ਕੰਮ ਨਹੀਂ ਕਰਨਗੀਆਂ ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਵਾਈ‑ਫਾਈ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਹੁੰਦੇ।\n\nਇਹ ਸੈਟਿੰਗ ਇਸ ਟੈਬਲੈੱਟ \'ਤੇ ਸਾਰੇ ਵਰਤੋਂਕਾਰਾਂ ਨੂੰ ਪ੍ਰਭਾਵਿਤ ਕਰਦੀ ਹੈ।"</string>
@@ -2735,7 +2740,7 @@
     <string name="cryptkeeper_emergency_call" msgid="4625420047524693116">"ਸੰਕਟਕਾਲੀਨ ਕਾਲ"</string>
     <string name="cryptkeeper_return_to_call" msgid="4433942821196822815">"ਕਾਲ \'ਤੇ ਵਾਪਸ ਜਾਓ"</string>
     <string name="vpn_name" msgid="3538818658670774080">"ਨਾਮ"</string>
-    <string name="vpn_type" msgid="6389116710008658550">"ਪ੍ਰਕਾਰ"</string>
+    <string name="vpn_type" msgid="6389116710008658550">"ਕਿਸਮ"</string>
     <string name="vpn_server" msgid="5216559017318406820">"ਸਰਵਰ ਦਾ ਪਤਾ"</string>
     <string name="vpn_mppe" msgid="4027660356538086985">"PPP ਇਨਕ੍ਰਿਪਸ਼ਨ (MPPE)"</string>
     <string name="vpn_l2tp_secret" msgid="8500633072482638606">"L2TP ਗੁਪਤ"</string>
@@ -2747,7 +2752,7 @@
     <string name="vpn_show_options" msgid="7672984921872882859">"ਵਿਕਸਿਤ ਵਿਕਲਪ ਦਿਖਾਓ"</string>
     <string name="vpn_search_domains" msgid="8469394307693909080">"DNS ਖੋਜ ਡੋਮੇਨ"</string>
     <string name="vpn_dns_servers" msgid="3017453300909321239">"DNS ਸਰਵਰ (ਉਦਾਹਰਨ ਵਜੋਂ 8.8.8.8)"</string>
-    <string name="vpn_routes" msgid="3393989650778663742">"ਫਾਰਵਰਡਿੰਗ ਰੂਟਸ (ਉਦਾਹਰਨ ਵਜੋਂ 10.0.0.0/8)"</string>
+    <string name="vpn_routes" msgid="3393989650778663742">"ਫਾਰਵਰਡਿੰਗ ਰੂਟ (ਉਦਾਹਰਨ ਵਜੋਂ 10.0.0.0/8)"</string>
     <string name="vpn_username" msgid="5357878823189445042">"ਵਰਤੋਂਕਾਰ ਨਾਮ"</string>
     <string name="vpn_password" msgid="5325943601523662246">"ਪਾਸਵਰਡ"</string>
     <string name="vpn_save_login" msgid="6215503139606646915">"ਖਾਤਾ ਜਾਣਕਾਰੀ ਰੱਖਿਅਤ ਕਰੋ"</string>
@@ -2770,7 +2775,7 @@
     <string name="vpn_disconnect_confirm" msgid="3505111947735651082">"ਇਹ VPN ਡਿਸਕਨੈਕਟ ਕਰੀਏ?"</string>
     <string name="vpn_disconnect" msgid="4625914562388652486">"ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
     <string name="vpn_version" msgid="2006792987077940456">"ਵਰਜਨ <xliff:g id="VERSION">%s</xliff:g>"</string>
-    <string name="vpn_forget_long" msgid="8457511440635534478">"VPN ਨੂੰ ਛੱਡੋ"</string>
+    <string name="vpn_forget_long" msgid="8457511440635534478">"VPN ਨੂੰ ਭੁੱਲ ਜਾਓ"</string>
     <string name="vpn_replace_vpn_title" msgid="8517436922021598103">"ਕੀ ਮੌਜੂਦਾ VPN ਨੂੰ ਤਬਦੀਲ ਕਰਨਾ ਹੈ?"</string>
     <string name="vpn_set_vpn_title" msgid="6483554732067951052">"ਕੀ ਹਮੇਸ਼ਾ-ਚਾਲੂ VPN ਨੂੰ ਸੈੱਟ ਕਰਨਾ ਹੈ?"</string>
     <string name="vpn_first_always_on_vpn_message" msgid="7050017738816963855">"ਜਦੋਂ ਇਹ ਸੈਟਿੰਗ ਚਾਲੂ ਹੁੰਦੀ ਹੈ, ਤਾਂ ਤੁਹਾਡੇ ਕੋਲ ਇੱਕ ਇੰਟਰਨੈੱਟ ਕਨੈਕਸ਼ਨ ਤਦ ਤੱਕ ਨਹੀਂ ਹੋਵੇਗਾ ਜਦ ਤੱਕ VPN ਸਫ਼ਲਤਾਪੂਰਵਕ ਕਨੈਕਟ ਨਹੀਂ ਹੋ ਜਾਂਦਾ"</string>
@@ -2919,8 +2924,8 @@
     <string name="nfc_payment_favor_default" msgid="7555356982142464260">"ਹਮੇਸ਼ਾਂ"</string>
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"ਸਿਵਾਏ ਇਸਦੇ ਜਦੋਂ ਦੂਜਾ ਭੁਗਤਾਨ ਐਪ ਖੁੱਲ੍ਹਾ ਹੋਵੇ"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"ਟੈਪ ਕਰੋ ਅਤੇ ਭੁਗਤਾਨ ਕਰੋ ਟਰਮੀਨਲ ਵਿਖੇ, ਇਸਦੇ ਨਾਲ ਭੁਗਤਾਨ ਕਰੋ:"</string>
-    <string name="nfc_how_it_works_title" msgid="6531433737926327904">"ਟਰਮੀਨਲ ਤੇ ਭੁਗਤਾਨ ਕਰ ਰਿਹਾ ਹੈ"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"ਇੱਕ ਭੁਗਤਾਨ ਐਪ ਸੈੱਟ ਅੱਪ ਕਰੋ। ਫਿਰ ਕੰਟੈਕਟਲੈਸ ਚਿੰਨ੍ਹ ਨਾਲ ਕਿਸੇ ਵੀ ਟਰਮੀਨਲ ਤੱਕ ਆਪਣੇ ਫ਼ੋਨ ਦੇ ਪਿੱਛੇ ਕੇਵਲ ਹੋਲਡ ਕਰੋ।"</string>
+    <string name="nfc_how_it_works_title" msgid="6531433737926327904">"ਟਰਮੀਨਲ \'ਤੇ ਭੁਗਤਾਨ ਕਰਨਾ"</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"ਇੱਕ ਭੁਗਤਾਨ ਐਪ ਸੈੱਟ ਅੱਪ ਕਰੋ। ਫਿਰ ਸੰਪਰਕ-ਰਹਿਤ ਚਿੰਨ੍ਹ ਵਾਲੇ ਕਿਸੇ ਵੀ ਟਰਮੀਨਲ ਵੱਲ ਨੂੰ ਆਪਣੇ ਫ਼ੋਨ ਦਾ ਪਿਛਲਾ ਪਾਸਾ ਸਿਰਫ਼ ਫੜ੍ਹ ਕੇ ਰੱਖੋ।"</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"ਸਮਝ ਲਿਆ"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"ਹੋਰ..."</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"ਕੀ ਆਪਣੀ ਤਰਜੀਹਾਂ ਦੇ ਤੌਰ ਤੇ ਸੈਟ ਕਰਨਾ ਹੈ?"</string>
@@ -3089,7 +3094,7 @@
     <string name="keywords_lockscreen" msgid="4936846554280830394">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਸਲਾਈਡ ਕਰੋ, ਪਾਸਵਰਡ, ਪੈਟਰਨ, ਪਿੰਨ ਦਾਖਲ ਕਰੋ"</string>
     <string name="keywords_profile_challenge" msgid="8653718001253979611">"ਕਾਰਜ ਚੁਣੌਤੀ, ਕਾਰਜ, ਪ੍ਰੋਫਾਈਲ"</string>
     <string name="keywords_unification" msgid="2020759909366983593">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ, ਪ੍ਰਬੰਧਿਤ ਕੀਤੀ ਗਈ ਪ੍ਰੋਫਾਈਲ, ਇਕਰੂਪ ਕਰਨਾ, ਏਕੀਕਰਨ, ਕੰਮ, ਪ੍ਰੋਫਾਈਲ"</string>
-    <string name="keywords_gesture" msgid="5031323247529869644">"ਸੰਕੇਤ"</string>
+    <string name="keywords_gesture" msgid="5031323247529869644">"ਇਸ਼ਾਰੇ"</string>
     <string name="keywords_payment_settings" msgid="4745023716567666052">"ਭੁਗਤਾਨ ਕਰੋ, ਟੈਪ ਕਰੋ, ਭੁਗਤਾਨ"</string>
     <string name="keywords_backup" msgid="7433356270034921627">"ਬੈਕਅੱਪ, ਬੈਕ ਅੱਪ"</string>
     <string name="keywords_assist_gesture_launch" msgid="2711433664837843513">"ਸੰਕੇਤ"</string>
@@ -3625,12 +3630,12 @@
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ਵਾਧੂ ਅਨੁਮਤੀਆਂ</item>
     </plurals>
     <string name="runtime_permissions_summary_no_permissions_granted" msgid="3477934429220828771">"ਕੋਈ ਅਨੁਮਤੀਆਂ ਨਹੀਂ ਦਿੱਤੀਆਂ"</string>
-    <string name="runtime_permissions_summary_no_permissions_requested" msgid="3901636077467389637">"ਕਿਸੇ ਅਨੁਮਤੀਆਂ ਦੀ ਬੇਨਤੀ ਨਹੀਂ ਕੀਤੀ"</string>
+    <string name="runtime_permissions_summary_no_permissions_requested" msgid="3901636077467389637">"ਕਿਸੇ ਇਜਾਜ਼ਤਾਂ ਦੀ ਬੇਨਤੀ ਨਹੀਂ ਕੀਤੀ ਗਈ"</string>
     <string name="filter_all_apps" msgid="4042756539846043675">"ਸਾਰੀਆਂ ਐਪਾਂ"</string>
     <string name="filter_enabled_apps" msgid="5888459261768538489">"ਸਥਾਪਤ ਐਪਾਂ"</string>
     <string name="filter_instant_apps" msgid="8087483282854072366">"ਤਤਕਾਲ ਐਪਾਂ"</string>
     <string name="filter_personal_apps" msgid="3473268022652904457">"ਨਿੱਜੀ"</string>
-    <string name="filter_work_apps" msgid="4202483998339465542">"ਦਫ਼ਤਰ"</string>
+    <string name="filter_work_apps" msgid="4202483998339465542">"ਕਾਰਜ-ਸਥਾਨ"</string>
     <string name="filter_notif_all_apps" msgid="1862666327228804896">"ਐਪਾਂ: ਸਾਰੀਆਂ"</string>
     <string name="filter_notif_blocked_apps" msgid="5694956954776028202">"ਬੰਦ ਕੀਤੀਆਂ ਗਈਆਂ"</string>
     <string name="filter_notif_urgent_channels" msgid="5000735867167027148">"ਸ਼੍ਰੇਣੀਆਂ: ਜ਼ਰੂਰੀ ਮਹੱਤਵ"</string>
@@ -3689,7 +3694,7 @@
     <string name="memory_avg_desc" msgid="1200185697910086968">"ਔਸਤ <xliff:g id="MEMORY">%1$s</xliff:g>"</string>
     <string name="memory_use_running_format" msgid="3741170402563292232">"<xliff:g id="MEMORY">%1$s</xliff:g> / <xliff:g id="RUNNING">%2$s</xliff:g>"</string>
     <string name="process_format" msgid="8575347150598564509">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="COUNT">%2$d</xliff:g>)"</string>
-    <string name="high_power_apps" msgid="2518319744362028920">"ਬੈਟਰੀ ਸੁਯੋਗਤਾ"</string>
+    <string name="high_power_apps" msgid="2518319744362028920">"ਬੈਟਰੀ ਸੁਯੋਗਕਰਨ"</string>
     <string name="additional_battery_info" msgid="6877663897819271203">"ਵਰਤੋਂ ਬਾਰੇ ਸੁਚੇਤਨਾਵਾਂ"</string>
     <string name="show_all_apps" msgid="5442552004569634846">"ਡੀਵਾਈਸ ਦੀ ਪੂਰੀ ਵਰਤੋਂ ਦਿਖਾਓ"</string>
     <string name="hide_extra_apps" msgid="6798261081113299441">"ਐਪ ਵਰਤੋਂ ਦਿਖਾਓ"</string>
@@ -3706,7 +3711,7 @@
     <string name="high_power_off" msgid="5906679734326490426">"ਬੈਟਰੀ ਵਰਤੋਂ ਨੂੰ ਸੁਯੋਗ ਕਰਨਾ"</string>
     <string name="high_power_system" msgid="739584574711292753">"ਬੈਟਰੀ ਸੁਯੋਗਤਾ ਉਪਲਬਧ ਨਹੀਂ"</string>
     <string name="high_power_desc" msgid="333756885680362741">"ਬੈਟਰੀ ਅਨੁਕੂਲਤਾ ਨੂੰ ਲਾਗੂ ਨਾ ਕਰੋ। ਤੁਹਾਡੀ ਬਟਰੀ ਨੂੰ ਹੋਰ ਵੀ ਛੇਤੀ ਖ਼ਤਮ ਕਰ ਸਕਦਾ ਹੈ।"</string>
-    <string name="high_power_prompt_title" msgid="2805745781720454052">"ਐਪ ਨੂੰ ਹਮੇਸ਼ਾ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚੱਲਣ ਦੇਈਏ?"</string>
+    <string name="high_power_prompt_title" msgid="2805745781720454052">"ਕੀ ਐਪ ਨੂੰ ਹਮੇਸ਼ਾ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚੱਲਣ ਦੇਣਾ ਹੈ?"</string>
     <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਹਮੇਸ਼ਾ ਚਾਲੂ ਰੱਖਣ ਦੀ ਇਜਾਜ਼ਤ ਦੇਣ ਨਾਲ ਬੈਟਰੀ ਦਾ ਕਾਰਜ-ਕਾਲ ਘਟ ਸਕਦਾ ਹੈ। \n\nਤੁਸੀਂ ਇਸਨੂੰ ਬਾਅਦ ਵਿੱਚ ਸੈਟਿੰਗਾਂ &gt; ਐਪਾਂ ਅਤੇ ਸੂਚਨਾਵਾਂ ਵਿੱਚੋਂ ਬਦਲ ਸਕਦੇ ਹੋ।"</string>
     <string name="battery_summary" msgid="4345690800899981339">"ਪਿਛਲੀ ਵਾਰ ਪੂਰਾ ਚਾਰਜ ਕਰਨ ਤੋਂ ਬਾਅਦ ਬੈਟਰੀ ਦੀ <xliff:g id="PERCENTAGE">%1$s</xliff:g> ਵਰਤੋਂ ਹੋਈ"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"ਪਾਵਰ ਪ੍ਰਬੰਧਨ"</string>
@@ -3778,7 +3783,7 @@
       <item quantity="one"><xliff:g id="COUNT">%1$d</xliff:g> ਐਪ ਵੱਲੋਂ ਪਿਛਲੇ <xliff:g id="DURATION_1">%2$s</xliff:g> ਵਿੱਚ ਵਰਤੀ ਗਈ ਮੈਮਰੀ</item>
       <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> ਐਪਾਂ ਵੱਲੋਂ ਪਿਛਲੇ <xliff:g id="DURATION_1">%2$s</xliff:g> ਵਿੱਚ ਵਰਤੀ ਗਈ ਮੈਮਰੀ</item>
     </plurals>
-    <string name="running_frequency" msgid="7545170806968474449">"ਬਾਰੰਬਾਰਤਾ"</string>
+    <string name="running_frequency" msgid="7545170806968474449">"ਵਾਰਵਾਰਤਾ"</string>
     <string name="memory_maximum_usage" msgid="4734981118293469479">"ਅਧਿਕਤਮ ਵਰਤੋਂ"</string>
     <string name="no_data_usage" msgid="903383745620135746">"ਕੋਈ ਡਾਟਾ ਨਹੀਂ ਵਰਤਿਆ"</string>
     <string name="zen_access_warning_dialog_title" msgid="7704910289810337055">"ਕੀ <xliff:g id="APP">%1$s</xliff:g> ਨੂੰ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ ਤੱਕ ਪਹੁੰਚ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
@@ -4042,10 +4047,10 @@
     <string name="theme_customization_accent_color_title" msgid="3949108608589133216">"ਐਕਸੈਂਟ ਰੰਗ"</string>
     <string name="theme_customization_font_title" msgid="309728559821356597">"ਸੁਰਖੀ / ਮੁੱਖ ਹਿੱਸੇ ਦਾ ਫੌਂਟ"</string>
     <string name="theme_customization_icon_shape_title" msgid="4603248388639328322">"ਪ੍ਰਤੀਕ ਦਾ ਆਕਾਰ"</string>
-    <string name="theme_customization_device_default" msgid="7188874258500934312">"ਪੂਰਵ-ਨਿਰਧਾਰਤ ਡੀਵਾਈਸ"</string>
+    <string name="theme_customization_device_default" msgid="7188874258500934312">"ਡੀਵਾਈਸ ਪੂਰਵ-ਨਿਰਧਾਰਤ"</string>
     <string name="display_cutout_emulation" msgid="288975763151891685">"ਡਿਸਪਲੇ ਕੱਟਆਊਟ"</string>
     <string name="display_cutout_emulation_keywords" msgid="6795671536772871439">"ਡਿਸਪਲੇ ਕੱਟਆਊਟ, ਨੌਚ"</string>
-    <string name="overlay_option_device_default" msgid="165508753381657697">"ਪੂਰਵ-ਨਿਰਧਾਰਤ ਡੀਵਾਈਸ"</string>
+    <string name="overlay_option_device_default" msgid="165508753381657697">"ਡੀਵਾਈਸ ਪੂਰਵ-ਨਿਰਧਾਰਤ"</string>
     <string name="overlay_toast_failed_to_apply" msgid="5692251825129250040">"ਓਵਰਲੇ ਨੂੰ ਲਾਗੂ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
     <string name="special_access" msgid="1453926335914696206">"ਵਿਸ਼ੇਸ਼ ਐਪ ਪਹੁੰਚ"</string>
     <plurals name="special_access_summary" formatted="false" msgid="5182092345063909346">
@@ -4102,7 +4107,7 @@
     <string name="deletion_helper_automatic_title" msgid="4370975149425263205">"ਸਵੈਚਾਲਿਤ"</string>
     <string name="deletion_helper_manual_title" msgid="1011785013431162078">"ਦਸਤੀ"</string>
     <string name="deletion_helper_preference_title" msgid="797270307034242206">"ਹੁਣੇ ਜਗ੍ਹਾ ਖਾਲੀ ਕਰੋ"</string>
-    <string name="gesture_preference_title" msgid="583646591518373785">"ਸੰਕੇਤ"</string>
+    <string name="gesture_preference_title" msgid="583646591518373785">"ਇਸ਼ਾਰੇ"</string>
     <string name="gesture_preference_summary" product="default" msgid="2990736567599191163">"ਤੁਹਾਡੇ ਫ਼ੋਨ ਨੂੰ ਕੰਟਰੋਲ ਕਰਨ ਲਈ ਤੁਰੰਤ ਸੰਕੇਤ"</string>
     <string name="gesture_preference_summary" product="tablet" msgid="8303793594714075580">"ਤੁਹਾਡੇ ਟੈਬਲੈੱਟ ਨੂੰ ਕੰਟਰੋਲ ਕਰਨ ਲਈ ਤੁਰੰਤ ਸੰਕੇਤ"</string>
     <string name="gesture_preference_summary" product="device" msgid="7792199669106960922">"ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਨੂੰ ਕੰਟਰੋਲ ਕਰਨ ਲਈ ਤੁਰੰਤ ਸੰਕੇਤ"</string>
@@ -4119,14 +4124,14 @@
     <string name="ambient_display_title" product="tablet" msgid="1106285490888683613">"ਸੂਚਨਾਵਾਂ ਦੇਖਣ ਲਈ ਟੈਬਲੈੱਟ \'ਤੇ ਦੋ ਵਾਰ ਟੈਪ ਕਰੋ"</string>
     <string name="ambient_display_title" product="device" msgid="5064644474876041478">"ਸੂਚਨਾਵਾਂ ਦੇਖਣ ਲਈ ਡੀਵਾਈਸ \'ਤੇ ਦੋ ਵਾਰ ਟੈਪ ਕਰੋ"</string>
     <string name="ambient_display_summary" msgid="4882910328216411109">"ਸਮਾਂ, ਸੂਚਨਾਵਾਂ ਅਤੇ ਹੋਰ ਜਾਣਕਾਰੀ ਦੇਖਣ ਲਈ ਆਪਣੀ ਸਕ੍ਰੀਨ \'ਤੇ ਡਬਲ ਟੈਪ ਕਰੋ।"</string>
-    <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"ਫ਼ੋਨ ਚੈੱਕ ਕਰਨ ਲਈ ਚੁੱਕੋ"</string>
+    <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"ਫ਼ੋਨ ਦੇਖਣ ਲਈ ਚੁੱਕੋ"</string>
     <string name="ambient_display_pickup_title" product="tablet" msgid="1555456400210301959">"ਸੂਚਨਾਵਾਂ ਦੇਖਣ ਲਈ ਟੈਬਲੈੱਟ ਨੂੰ ਚੁੱਕੋ"</string>
     <string name="ambient_display_pickup_title" product="device" msgid="2480126522988135037">"ਸੂਚਨਾਵਾਂ ਦੇਖਣ ਲਈ ਡੀਵਾਈਸ ਨੂੰ ਚੁੱਕੋ"</string>
     <string name="ambient_display_wake_screen_title" msgid="3376988352851077102">"ਡਿਸਪਲੇ ਕਿਰਿਆਸ਼ੀਲ ਕਰੋ"</string>
     <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"ਸਮਾਂ, ਸੂਚਨਾਵਾਂ ਅਤੇ ਹੋਰ ਜਾਣਕਾਰੀ ਦੇਖਣ ਲਈ ਆਪਣੇ ਫ਼ੋਨ ਨੂੰ ਚੁੱਕੋ।"</string>
     <string name="ambient_display_pickup_summary" product="tablet" msgid="1077745287100012928">"ਸਮਾਂ, ਸੂਚਨਾਵਾਂ ਅਤੇ ਹੋਰ ਜਾਣਕਾਰੀ ਦੇਖਣ ਲਈ ਆਪਣੇ ਟੈਬਲੈੱਟ ਨੂੰ ਚੁੱਕੋ।"</string>
     <string name="ambient_display_pickup_summary" product="device" msgid="404199660076598026">"ਸਮਾਂ, ਸੂਚਨਾਵਾਂ ਅਤੇ ਹੋਰ ਜਾਣਕਾਰੀ ਦੇਖਣ ਲਈ ਆਪਣੇ ਡੀਵਾਈਸ ਨੂੰ ਚੁੱਕੋ।"</string>
-    <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"ਫੋਨ ਦੇਖਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
+    <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"ਫ਼ੋਨ ਦੇਖਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="ambient_display_tap_screen_title" product="tablet" msgid="6434521782016864148">"ਟੈਬਲੈੱਟ ਦੇਖਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"ਡੀਵਾਈਸ ਦੇਖਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"ਸਮਾਂ, ਸੂਚਨਾਵਾਂ ਅਤੇ ਹੋਰ ਜਾਣਕਾਰੀ ਦੇਖਣ ਲਈ ਆਪਣੀ ਸਕ੍ਰੀਨ \'ਤੇ ਟੈਪ ਕਰੋ।"</string>
@@ -4234,7 +4239,7 @@
     <string name="storage_music_audio" msgid="3661289086715297149">"ਸੰਗੀਤ ਅਤੇ ਆਡੀਓ"</string>
     <string name="storage_games" msgid="7740038143749092373">"ਗੇਮਾਂ"</string>
     <string name="storage_other_apps" msgid="3202407095387420842">"ਹੋਰ ਐਪਾਂ"</string>
-    <string name="storage_files" msgid="2087824267937487880">"ਫ਼ਾਈਲਾਂ"</string>
+    <string name="storage_files" msgid="2087824267937487880">"Files"</string>
     <string name="storage_size_large_alternate" msgid="1317796542509105857">"<xliff:g id="NUMBER">^1</xliff:g>"<small>" "<font size="20">"<xliff:g id="UNIT">^2</xliff:g>"</font></small>""</string>
     <string name="storage_volume_total" msgid="5021484171514159913">"<xliff:g id="TOTAL">%1$s</xliff:g> ਵਿੱਚੋਂ ਵਰਤਿਆ"</string>
     <string name="storage_percent_full" msgid="6924662861545958442">"ਵਰਤੀ ਗਈ"</string>
diff --git a/tests/CarDeveloperOptions/res/values-pl/arrays.xml b/tests/CarDeveloperOptions/res/values-pl/arrays.xml
index 1e1dc78..eff7e2a 100644
--- a/tests/CarDeveloperOptions/res/values-pl/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-pl/arrays.xml
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"Nigdy nie zezwalaj"</item>
     <item msgid="8184570120217958741">"Zawsze zezwalaj"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normalny"</item>
+    <item msgid="5101233285497327432">"Średni"</item>
+    <item msgid="1555861583162930714">"Niska"</item>
+    <item msgid="1719683776264798117">"Krytyczny"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normalny"</item>
+    <item msgid="6107138933849816768">"Umiarkowany"</item>
+    <item msgid="182695359839047859">"Niska"</item>
+    <item msgid="8577246509202964244">"Krytyczny"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Niezmienny"</item>
     <item msgid="167418068739176448">"Najczęstsza aktywność"</item>
@@ -462,13 +472,13 @@
     <item msgid="3118234477029486741">"0"</item>
   </string-array>
   <string-array name="wifi_metered_entries">
-    <item msgid="4329206416008519163">"Wykryj automatycznie"</item>
+    <item msgid="4329206416008519163">"Wykrywaj automatycznie"</item>
     <item msgid="773943026484148895">"Traktuj jako sieć z pomiarem użycia danych"</item>
     <item msgid="1008268820118852416">"Traktuj jako sieć bez pomiaru użycia danych"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
     <item msgid="6545683814310036454">"Używaj randomizowanego adresu MAC (domyślnie)"</item>
-    <item msgid="214234417308375326">"Użyj adresu MAC urządzenia"</item>
+    <item msgid="214234417308375326">"Używaj adresu MAC urządzenia"</item>
   </string-array>
   <string-array name="wifi_hidden_entries">
     <item msgid="7426878022650940844">"Nie"</item>
diff --git a/tests/CarDeveloperOptions/res/values-pl/config.xml b/tests/CarDeveloperOptions/res/values-pl/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-pl/config.xml
+++ b/tests/CarDeveloperOptions/res/values-pl/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-pl/strings.xml b/tests/CarDeveloperOptions/res/values-pl/strings.xml
index 947a908..231b22b 100644
--- a/tests/CarDeveloperOptions/res/values-pl/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-pl/strings.xml
@@ -85,8 +85,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Powiększ lub pomniejsz tekst na ekranie."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Pomniejsz"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Powiększ"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Zażółć gęślą jaźń."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Przykładowy tekst"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Czarnoksiężnik z Krainy Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Rozdział 11: Szmaragdowe Miasto"</string>
@@ -368,7 +367,7 @@
     <string name="owner_info_settings_summary" msgid="4208702251226725583">"Brak"</string>
     <string name="owner_info_settings_status" msgid="8049975536717685126">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="COUNT_1">%2$d</xliff:g>"</string>
     <string name="owner_info_settings_edit_text_hint" msgid="2250029417257939706">"Np. Android Jurka."</string>
-    <string name="user_info_settings_title" msgid="1125111518759995748">"Użytkownik – informacje"</string>
+    <string name="user_info_settings_title" msgid="1125111518759995748">"Informacje o użytkowniku"</string>
     <string name="show_profile_info_on_lockscreen_label" msgid="5204282771893683026">"Pokaż informacje o profilu na ekranie blokady"</string>
     <string name="profile_info_settings_title" msgid="4855892878512562551">"Informacje o profilu"</string>
     <string name="Accounts_settings_title" msgid="7901374987121953746">"Konta"</string>
@@ -684,7 +683,6 @@
       <item quantity="other">Musi mieć mniej niż <xliff:g id="NUMBER_1">%d</xliff:g> cyfry</item>
       <item quantity="one">Musi mieć mniej niż <xliff:g id="NUMBER_0">%d</xliff:g> cyfrę</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Musi zawierać tylko cyfry 0-9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Administrator urządzenia nie zezwala na ustawianie niedawno używanego kodu PIN"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Popularne kody PIN zostały zablokowane przez administratora. Spróbuj użyć innego kodu PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Nie może zawierać nieprawidłowego znaku"</string>
@@ -727,6 +725,12 @@
       <item quantity="other">Musi zawierać co najmniej <xliff:g id="COUNT">%d</xliff:g> znaku niebędącego literą</item>
       <item quantity="one">Musi zawierać co najmniej 1 znak niebędący literą</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="few">Musi zawierać co najmniej <xliff:g id="COUNT">%d</xliff:g> znaki niebędące cyframi</item>
+      <item quantity="many">Musi zawierać co najmniej <xliff:g id="COUNT">%d</xliff:g> znaków niebędących cyframi</item>
+      <item quantity="other">Musi zawierać co najmniej <xliff:g id="COUNT">%d</xliff:g> znaku niebędącego cyfrą</item>
+      <item quantity="one">Musi zawierać co najmniej 1 znak niebędący cyfrą</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Administrator urządzenia nie zezwala na ustawianie niedawno używanego hasła"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Popularne hasła zostały zablokowane przez administratora. Spróbuj użyć innego hasła."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Ciąg cyfr rosnących, malejących lub powtarzających się jest niedozwolony"</string>
@@ -887,7 +891,7 @@
     <string name="wifi_poor_network_detection_summary" msgid="5539951465985614590">"Nie korzystaj z sieci Wi-Fi, jeśli nie ma dobrego połączenia z internetem"</string>
     <string name="wifi_avoid_poor_network_detection_summary" msgid="1976503191780928104">"Używaj tylko sieci z dobrym połączeniem z internetem"</string>
     <string name="use_open_wifi_automatically_title" msgid="3084513215481454350">"Łącz się z otwartymi sieciami"</string>
-    <string name="use_open_wifi_automatically_summary" msgid="8338020172673161754">"Automatycznie łącz się z publicznymi sieciami wysokiej jakości"</string>
+    <string name="use_open_wifi_automatically_summary" msgid="8338020172673161754">"Automatycznie łącz się z sieciami publicznymi wysokiej jakości"</string>
     <string name="use_open_wifi_automatically_summary_scoring_disabled" msgid="1559329344492373028">"Aby użyć tej funkcji, wybierz dostawcę ocen jakości sieci"</string>
     <string name="use_open_wifi_automatically_summary_scorer_unsupported_disabled" msgid="1123080670578756834">"Aby użyć tej funkcji, wybierz zgodnego dostawcę ocen jakości sieci"</string>
     <string name="wifi_install_credentials" msgid="5650088113710858289">"Instaluj certyfikaty"</string>
@@ -1134,7 +1138,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Komórkowe"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Jeśli sieć Wi-Fi jest niedostępna, użyj sieci komórkowej"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Jeśli sieć komórkowa jest niedostępna, użyj Wi-Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Rozmowa przez Wi-Fi. Po utracie połączenia z Wi-Fi zostanie przerwana."</string>
@@ -1288,7 +1295,7 @@
     <string name="screensaver_settings_button" msgid="4662384378821837589">"Ustawienia"</string>
     <string name="automatic_brightness" msgid="8663792987774126192">"Automatyczna"</string>
     <string name="lift_to_wake_title" msgid="5523752279947392868">"Podnieś, by wybudzić"</string>
-    <string name="ambient_display_screen_title" msgid="2632871676917956691">"Ekran zgodny z otoczeniem"</string>
+    <string name="ambient_display_screen_title" msgid="2632871676917956691">"Wygaszacz z powiadomieniami"</string>
     <string name="ambient_display_category_triggers" msgid="3496111745340047504">"Kiedy wyświetlać"</string>
     <string name="doze_title" msgid="235269029233857546">"Nowe powiadomienia"</string>
     <string name="doze_summary" msgid="6762274282827831706">"Włącz ekran po otrzymaniu powiadomień"</string>
@@ -1601,7 +1608,7 @@
     <string name="restore_default_apn_completed" msgid="5671734152740058937">"Przywrócono domyślne ustawienia APN."</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"Opcje resetowania"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"Można zresetować sieć, aplikacje lub urządzenie"</string>
-    <string name="reset_network_title" msgid="8944059136930806211">"Reset Wi-Fi, transmisji i Bluetootha"</string>
+    <string name="reset_network_title" msgid="8944059136930806211">"Resetuj Wi-Fi, transmisję i Bluetootha"</string>
     <string name="reset_network_desc" msgid="4982633363916261109">"Spowoduje to usunięcie wszystkich ustawień sieciowych, w tym:\n\n"<li>"Wi‑Fi"</li>\n<li>"mobilnej transmisji danych"</li>\n<li>"Bluetooth"</li></string>
     <string name="reset_esim_title" msgid="7630781767040831893">"Usuń pobrane karty SIM"</string>
     <string name="reset_esim_desc" msgid="433226911566802">"Aby pobrać zastępczą kartę SIM, skontaktuj się z operatorem. Nie anuluje to Twoich abonamentów."</string>
@@ -1739,7 +1746,7 @@
     <string name="settings_safetylegal_activity_unreachable" msgid="3541894966476445833">"Brak połączenia do transmisji danych. Aby wyświetlić te informacje teraz, otwórz stronę %s na dowolnym komputerze połączonym z internetem."</string>
     <string name="settings_safetylegal_activity_loading" msgid="7680998654145172">"Wczytuję..."</string>
     <string name="confirm_device_credential_use_alternate_method" msgid="1279869272895739941">"Użyj innej metody"</string>
-    <string name="lockpassword_choose_your_screen_lock_header" msgid="6283518876031424798">"Ustawianie blokady ekranu"</string>
+    <string name="lockpassword_choose_your_screen_lock_header" msgid="6283518876031424798">"Ustaw blokadę ekranu"</string>
     <string name="lockpassword_choose_your_password_message" msgid="2838273977481046536">"Ze względów bezpieczeństwa ustaw hasło"</string>
     <string name="lockpassword_choose_your_password_header_for_fingerprint" msgid="4921343500484160894">"Aby korzystać z odcisku palca, ustaw hasło"</string>
     <string name="lockpassword_choose_your_pattern_header_for_fingerprint" msgid="314870151462139417">"Aby korzystać z odcisku palca, ustaw wzór"</string>
@@ -1800,7 +1807,7 @@
     <string name="lockpattern_settings_enable_visible_pattern_title" msgid="4935583222709647096">"Wzór jest widoczny"</string>
     <string name="lockpattern_settings_enable_visible_pattern_title_profile" msgid="5338893138982642228">"Pokazuj wzór dla profilu"</string>
     <string name="lockpattern_settings_enable_tactile_feedback_title" msgid="3203621862806531947">"Wibracja przy dotknięciu"</string>
-    <string name="lockpattern_settings_enable_power_button_instantly_locks" msgid="5890335732200257777">"Blokada przyciskiem zasilania"</string>
+    <string name="lockpattern_settings_enable_power_button_instantly_locks" msgid="5890335732200257777">"Blokuj przyciskiem zasilania"</string>
     <string name="lockpattern_settings_power_button_instantly_locks_summary" msgid="1279989004145567840">"Z wyjątkiem sytuacji, gdy blokadę anuluje <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g>"</string>
     <string name="lockpattern_settings_choose_lock_pattern" msgid="9042142745571386381">"Ustaw wzór odblokowania"</string>
     <string name="lockpattern_settings_change_lock_pattern" msgid="1456643060737114885">"Zmień wzór odblokowania"</string>
@@ -2530,7 +2537,7 @@
     <string name="battery_saver_turn_on_automatically_title" msgid="7316920304024245838">"Włącz automatycznie"</string>
     <string name="battery_saver_turn_on_automatically_never" msgid="2623381258359775227">"Nigdy"</string>
     <string name="battery_saver_turn_on_automatically_pct" msgid="434270432432390307">"przy <xliff:g id="PERCENT">%1$s</xliff:g> baterii"</string>
-    <string name="battery_percentage" msgid="7782252476471033843">"Poziom naładowania baterii w procentach"</string>
+    <string name="battery_percentage" msgid="7782252476471033843">"Procent naładowania baterii"</string>
     <string name="battery_percentage_description" msgid="9219875229166700610">"Pokazuj procentowy poziom naładowania baterii na pasku stanu"</string>
     <string name="process_stats_summary_title" msgid="9189588417488537954">"Statystyki procesów"</string>
     <string name="process_stats_summary" msgid="8077998499161221885">"Rozbudowane statystyki uruchomionych procesów"</string>
@@ -2635,7 +2642,7 @@
     <string name="uninstall_device_admin" msgid="9017499299961719830">"Odinstaluj aplikację"</string>
     <string name="remove_and_uninstall_device_admin" msgid="5607703579731496253">"Dezaktywuj i odinstaluj"</string>
     <string name="select_device_admin_msg" msgid="4173769638399075387">"Aplikacje do zarządzania urządzeniem"</string>
-    <string name="no_device_admins" msgid="4129231900385977460">"Brak dostępnych aplikacji do administrowania urządzeniem"</string>
+    <string name="no_device_admins" msgid="4129231900385977460">"Brak dostępnych aplikacji do zarządzania urządzeniem"</string>
     <string name="personal_device_admin_title" msgid="759440849188565661">"Osobiste"</string>
     <string name="managed_device_admin_title" msgid="8021522755492551726">"Praca"</string>
     <string name="sms_access_restriction_enabled" msgid="3006320256764718303">"Ogranicz dostęp do SMS-ów i rejestru połączeń"</string>
@@ -2799,7 +2806,7 @@
     <string name="data_usage_metered_wifi" msgid="2955256408132426720">"Sieci Wi‑Fi z pomiarem"</string>
     <string name="data_usage_metered_wifi_disabled" msgid="5771083253782103415">"Aby wybrać sieci z pomiarem, włącz Wi-Fi."</string>
     <string name="data_usage_metered_auto" msgid="7924116401382629319">"Automatycznie"</string>
-    <string name="data_usage_metered_yes" msgid="7333744880035386073">"Użycie danych jest mierzone"</string>
+    <string name="data_usage_metered_yes" msgid="7333744880035386073">"Pomiar użycia danych"</string>
     <string name="data_usage_metered_no" msgid="1961524615778610008">"Użycie danych nie jest mierzone"</string>
     <string name="data_usage_disclaimer" msgid="4683321532922590425">"Operator komórkowy może obliczać ilość przesłanych danych inaczej niż urządzenie."</string>
     <string name="cryptkeeper_emergency_call" msgid="4625420047524693116">"Połączenie alarmowe"</string>
@@ -2946,7 +2953,7 @@
     <string name="user_add_user_message_long" msgid="686637203224195465">"Z tego urządzenia możesz korzystać wraz z innymi osobami, dodając na nim konta użytkowników. Każdy użytkownik ma własne miejsce na swoje aplikacje, tapety i inne dane. Może też zmieniać ustawienia, które wpływają na wszystkich użytkowników urządzenia (np. Wi‑Fi).\n\nGdy dodasz nowego użytkownika, musi on skonfigurować swoje miejsce na dane.\n\nKażdy użytkownik może aktualizować aplikacje w imieniu wszystkich pozostałych użytkowników. Ułatwienia dostępu i usługi mogą nie zostać przeniesione na konto nowego użytkownika."</string>
     <string name="user_add_user_message_short" msgid="1802594476285458254">"Gdy dodasz nowego użytkownika, musi on skonfigurować swoją przestrzeń.\n\nKażdy użytkownik może aktualizować aplikacje wszystkich innych użytkowników."</string>
     <string name="user_setup_dialog_title" msgid="6748950002206392396">"Skonfigurować ustawienia dla użytkownika?"</string>
-    <string name="user_setup_dialog_message" msgid="2988559933258353919">"Upewnij się, że ta osoba jest w pobliżu i może skonfigurować swój profil."</string>
+    <string name="user_setup_dialog_message" msgid="2988559933258353919">"Upewnij się, że ta osoba jest w pobliżu i może skonfigurować swój profil"</string>
     <string name="user_setup_profile_dialog_message" msgid="7611900802824048526">"Skonfigurować teraz profil?"</string>
     <string name="user_setup_button_setup_now" msgid="4941459406266856176">"Skonfiguruj"</string>
     <string name="user_setup_button_setup_later" msgid="6596031428556518752">"Nie teraz"</string>
@@ -2997,8 +3004,8 @@
     <string name="nfc_payment_favor_default" msgid="7555356982142464260">"Zawsze"</string>
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Z wyjątkiem, gdy jest otwarta inna aplikacja płatnicza"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"Na terminalu „Zbliż i zapłać” płać przy użyciu:"</string>
-    <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Płacenie przy terminalu"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Skonfiguruj aplikację płatniczą, a później przyłóż tylną część telefonu do terminala z symbolem płatności zbliżeniowej."</string>
+    <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Płacenie na terminalu"</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Skonfiguruj aplikację płatniczą, a później przyłóż tylną część telefonu do terminala z symbolem płatności zbliżeniowej."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"OK"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"Więcej..."</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"Ustawić jako Twoją preferencję?"</string>
@@ -3182,7 +3189,7 @@
     <string name="keywords_financial_apps_sms_access" msgid="3236014691838121857">"aplikacja finansowa, SMS, uprawnienia"</string>
     <string name="keywords_systemui_theme" msgid="9150908170417305866">"tryb ciemny"</string>
     <string name="keywords_device_feedback" msgid="6948977907405738490">"błąd"</string>
-    <string name="keywords_ambient_display_screen" msgid="5873935693887583428">"Ekran dostosowany do otoczenia, ekran blokady"</string>
+    <string name="keywords_ambient_display_screen" msgid="5873935693887583428">"Wygaszacz z powiadomieniami, ekran blokady"</string>
     <string name="keywords_lock_screen_notif" msgid="4914337222856805463">"powiadomienia na ekranie blokady, powiadomienia"</string>
     <string name="keywords_face_settings" msgid="4117345666006836599">"twarz"</string>
     <string name="keywords_fingerprint_settings" msgid="902902368701134163">"odcisk palca, dodawanie odcisków palców"</string>
@@ -3302,7 +3309,7 @@
     <string name="zen_mode_block_effect_summary_sound" msgid="4907185880913861880">"Dźwięk i wibracje"</string>
     <string name="zen_mode_block_effect_summary_some" msgid="6035118904496072665">"Dźwięk, wibracje i niektóre rodzaje wizualnej sygnalizacji powiadomień"</string>
     <string name="zen_mode_block_effect_summary_all" msgid="2830443565687247759">"Dźwięk, wibracje i wizualna sygnalizacja powiadomień"</string>
-    <string name="zen_mode_blocked_effects_footer" msgid="4375156159613413924">"Powiadomienia wymagane przez podstawowe funkcje telefonu oraz stan nigdy nie będą ukryte"</string>
+    <string name="zen_mode_blocked_effects_footer" msgid="4375156159613413924">"Powiadomienia wymagane przez podstawowe funkcje i stan telefonu nigdy nie będą ukryte"</string>
     <string name="zen_mode_no_exceptions" msgid="3099578343994492857">"Brak"</string>
     <string name="zen_mode_other_options" msgid="7216192179063769057">"inne opcje"</string>
     <string name="zen_mode_add" msgid="2533484377786927366">"Dodaj"</string>
@@ -3389,7 +3396,7 @@
     <string name="notification_badging_title" msgid="6311699476970264712">"Zezwól na plakietki z powiadomieniami"</string>
     <string name="notification_bubbles_title" msgid="9196562435741861317">"Dymki"</string>
     <string name="notification_bubbles_summary" msgid="4624512775901949578">"Szybki dostęp do zawartości aplikacji z dowolnego miejsca dzięki pływającym skrótom"</string>
-    <string name="bubbles_feature_education" msgid="8979109826818881018">"Niektóre powiadomienia i inne treści mogą pojawiać się jako dymki na ekranie. Aby otworzyć dymek, kliknij go. Aby zamknąć, przeciągnij go w dół ekranu."</string>
+    <string name="bubbles_feature_education" msgid="8979109826818881018">"Niektóre powiadomienia i inne treści mogą pojawiać się jako dymki na ekranie. Aby otworzyć dymek, kliknij go. Aby zamknąć, przeciągnij go na dół ekranu."</string>
     <string name="bubbles_app_toggle_title" msgid="6401217027603326439">"Dymki"</string>
     <string name="bubbles_app_toggle_summary" msgid="7707611139796553855">"Zezwól aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g> na pokazywanie niektórych powiadomień jako dymków"</string>
     <string name="bubbles_feature_disabled_dialog_title" msgid="3375452386012079293">"Włącz dymki"</string>
@@ -3783,7 +3790,7 @@
     <string name="roles_title" msgid="2825063787446244357">"Role"</string>
     <string name="default_app" msgid="8861276008866619872">"(Domyślna)"</string>
     <string name="system_app" msgid="4111402206594443265">"(Systemowa)"</string>
-    <string name="system_default_app" msgid="1454719098589351197">"(Domyślna aplikacja systemu)"</string>
+    <string name="system_default_app" msgid="1454719098589351197">"(Domyślna aplikacja systemowa)"</string>
     <string name="apps_storage" msgid="5658466038269046038">"Magazyn aplikacji"</string>
     <string name="usage_access" msgid="2023443456361489516">"Dostęp do danych o użyciu"</string>
     <string name="permit_usage_access" msgid="3321727608629752758">"Zezwól na dostęp do danych o użyciu"</string>
@@ -3993,7 +4000,7 @@
     <string name="disabled_by_policy_title_camera" msgid="3741138901926111197">"Brak uprawnień do aparatu"</string>
     <string name="disabled_by_policy_title_screen_capture" msgid="1856835333536274665">"Brak uprawnień do tworzenia zrzutów ekranu"</string>
     <string name="disabled_by_policy_title_suspend_packages" msgid="4254714213391802322">"Nie można otworzyć tej aplikacji"</string>
-    <string name="default_admin_support_msg" msgid="5789424433689798637">"Jeśli masz pytania, skontaktuj się z administratorem"</string>
+    <string name="default_admin_support_msg" msgid="5789424433689798637">"Jeśli masz pytania, skontaktuj się z administratorem IT"</string>
     <string name="admin_support_more_info" msgid="8737842638087863477">"Więcej szczegółów"</string>
     <string name="admin_profile_owner_message" msgid="3199544166281052845">"Administrator może monitorować aplikacje i dane powiązane z Twoim profilem do pracy (w tym ustawienia, uprawnienia, firmowe uprawnienia dostępu, aktywność w sieci i informacje o lokalizacji urządzenia) oraz nimi zarządzać."</string>
     <string name="admin_profile_owner_user_message" msgid="2991249382056855531">"Administrator może monitorować aplikacje i dane powiązane z tym użytkownikiem (w tym ustawienia, uprawnienia, firmowe uprawnienia dostępu, aktywność w sieci i informacje o lokalizacji urządzenia) oraz nimi zarządzać."</string>
@@ -4288,7 +4295,7 @@
     <string name="instant_apps_settings" msgid="879003203555847537">"Ustawienia aplikacji błyskawicznych"</string>
     <string name="domain_url_section_title" msgid="206403507921518321">"Zainstalowane aplikacje"</string>
     <string name="automatic_storage_manager_activation_warning" msgid="2630083316417707308">"Pamięcią zarządza teraz menedżer miejsca"</string>
-    <string name="account_for_section_header" msgid="5975241715840642563">"Konta użytkownika <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="account_for_section_header" msgid="5975241715840642563">"Konta użytkownika: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="configure_section_header" msgid="6988981883075615136">"Konfiguracja"</string>
     <string name="auto_sync_account_title" msgid="2394463123733529506">"Automatycznie synchronizuj dane"</string>
     <string name="auto_sync_personal_account_title" msgid="6844465157916100655">"Automatycznie synchronizuj dane osobiste"</string>
diff --git a/tests/CarDeveloperOptions/res/values-pt-rPT/arrays.xml b/tests/CarDeveloperOptions/res/values-pt-rPT/arrays.xml
index 28db34e..90734bb 100644
--- a/tests/CarDeveloperOptions/res/values-pt-rPT/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-pt-rPT/arrays.xml
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"Nunca permitir"</item>
     <item msgid="8184570120217958741">"Permitir sempre"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Moderada"</item>
+    <item msgid="1555861583162930714">"Baixa"</item>
+    <item msgid="1719683776264798117">"Crítica"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normal"</item>
+    <item msgid="6107138933849816768">"Moderada"</item>
+    <item msgid="182695359839047859">"Baixa"</item>
+    <item msgid="8577246509202964244">"Crítica"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Persistente"</item>
     <item msgid="167418068739176448">"Principal atividade"</item>
diff --git a/tests/CarDeveloperOptions/res/values-pt-rPT/config.xml b/tests/CarDeveloperOptions/res/values-pt-rPT/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-pt-rPT/config.xml
+++ b/tests/CarDeveloperOptions/res/values-pt-rPT/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-pt-rPT/strings.xml b/tests/CarDeveloperOptions/res/values-pt-rPT/strings.xml
index bab92d6..d7b618f 100644
--- a/tests/CarDeveloperOptions/res/values-pt-rPT/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-pt-rPT/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Aumente ou diminua o texto no ecrã."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Diminuir"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Aumentar"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Exemplo de texto"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"O Maravilhoso Feiticeiro de Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Capítulo 11: A Maravilhosa Cidade Esmeralda de Oz"</string>
@@ -270,8 +269,8 @@
     <string name="locale_remove_menu" msgid="3395565699934985486">"Remover"</string>
     <string name="add_a_language" msgid="4103889327406274800">"Adicionar um idioma"</string>
     <plurals name="dlg_remove_locales_title" formatted="false" msgid="7362450618787242592">
-      <item quantity="other">Pretende remover os idiomas selecionados?</item>
-      <item quantity="one">Pretende remover o idioma selecionado?</item>
+      <item quantity="other">Remover os idiomas selecionados?</item>
+      <item quantity="one">Remover o idioma selecionado?</item>
     </plurals>
     <string name="dlg_remove_locales_message" msgid="5179370688876343176">"O texto será apresentado noutro idioma."</string>
     <string name="dlg_remove_locales_error_title" msgid="9090578326002163975">"Não é possível remover todos os idiomas"</string>
@@ -390,7 +389,7 @@
     <string name="security_passwords_title" msgid="6853942836045862315">"Privacidade"</string>
     <string name="disabled_by_administrator_summary" msgid="6099821045360491127">"Desativada pelo gestor"</string>
     <string name="security_status_title" msgid="1261960357751754428">"Estado de segurança"</string>
-    <string name="security_dashboard_summary_face" msgid="2536136110153593745">"Bloqueio de ecrã, Desbloqueio Através do Rosto"</string>
+    <string name="security_dashboard_summary_face" msgid="2536136110153593745">"Bloqueio de ecrã, Desbloqueio facial"</string>
     <string name="security_dashboard_summary" msgid="4048877125766167227">"Bloqueio de ecrã, impressão digital"</string>
     <string name="security_dashboard_summary_no_fingerprint" msgid="8861903321053490658">"Bloqueio de ecrã"</string>
     <string name="security_settings_face_preference_summary" msgid="4437701024542221434">"Rosto adicionado."</string>
@@ -419,7 +418,7 @@
     <string name="security_settings_face_enroll_done" msgid="5409739233373490971">"Concluído"</string>
     <string name="security_settings_face_settings_use_face_category" msgid="1586532139528115416">"Utilize o rosto para"</string>
     <string name="security_settings_face_settings_use_face_unlock_phone" msgid="318274519126401671">"Desbloq. dispositivo"</string>
-    <string name="security_settings_face_settings_use_face_for_apps" msgid="5479369083370664351">"Início de sessão e pagamentos na aplicação"</string>
+    <string name="security_settings_face_settings_use_face_for_apps" msgid="5479369083370664351">"Início de sessão e pagamentos na app"</string>
     <string name="security_settings_face_settings_require_attention" msgid="2755140150841557225">"Olhos abertos para desbloquear"</string>
     <string name="security_settings_face_settings_require_attention_details" msgid="2557060433599942587">"Para utilizar a autenticação facial, os olhos têm de estar abertos."</string>
     <string name="security_settings_face_settings_require_confirmation" msgid="7312024271060416438">"Solicitar sempre confirmação"</string>
@@ -427,7 +426,7 @@
     <string name="security_settings_face_settings_remove_face_data" msgid="2821359954483136239">"Remover dados rosto"</string>
     <string name="security_settings_face_settings_footer" msgid="4627175759990550715">"Pode utilizar o seu rosto para desbloquear o dispositivo e aceder a aplicações. "<annotation id="url">"Saiba mais"</annotation></string>
     <string name="security_settings_face_settings_remove_dialog_title" msgid="5675319895815271094">"Eliminar os dados do rosto?"</string>
-    <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"Os dados gravados pelo Desbloqueio Através do Rosto serão eliminados permanentemente e em segurança. Após a remoção, precisará do PIN, do padrão ou da palavra-passe para desbloquear o telemóvel, iniciar sessão nas aplicações e confirmar pagamentos."</string>
+    <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"Os dados gravados pelo Desbloqueio facial serão eliminados permanentemente e em segurança. Após a remoção, precisará do PIN, do padrão ou da palavra-passe para desbloquear o telemóvel, iniciar sessão nas aplicações e confirmar pagamentos."</string>
     <string name="security_settings_fingerprint_preference_title" msgid="4177132225930582928">"Impressão digital"</string>
     <string name="fingerprint_manage_category_title" msgid="1463406696801542090">"Gerir impressões dig."</string>
     <string name="fingerprint_usage_category_title" msgid="7298369141954599706">"Usar impr. dig. para"</string>
@@ -467,11 +466,11 @@
     <string name="security_settings_fingerprint_enroll_dialog_ok" msgid="3428927518029038956">"OK"</string>
     <string name="security_settings_fingerprint_enroll_dialog_delete" msgid="4312297515772004580">"Eliminar"</string>
     <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"Toque no sensor"</string>
-    <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Coloque o dedo sobre o sensor e levante-o depois de sentir uma vibração"</string>
+    <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Coloque o dedo sobre o sensor e levante-o depois de sentir uma vibração."</string>
     <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"Levante e toque novamente"</string>
-    <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Vá levantando o dedo para adicionar as diferentes partes da sua impressão digital"</string>
+    <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Vá levantando o dedo para adicionar as diferentes partes da sua impressão digital."</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"Impressão digital adicionada"</string>
-    <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"Quando vir este ícone, pode utilizar a sua impressão digital para identificação ou para autorizar compras"</string>
+    <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"Quando vir este ícone, pode utilizar a sua impressão digital para identificação ou para autorizar compras."</string>
     <string name="security_settings_fingerprint_enroll_enrolling_skip" msgid="1473280156532146933">"Fazer isto mais tarde"</string>
     <string name="setup_fingerprint_enroll_enrolling_skip_title" msgid="2816424026528101690">"Ignorar configur. de impressão digital?"</string>
     <string name="setup_fingerprint_enroll_enrolling_skip_message" msgid="8139299964344809780">"Optou por utilizar a sua impressão digital como uma forma de desbloquear o telemóvel. Se ignorar agora, terá de configurar esta opção mais tarde. A configuração demora apenas alguns minutos."</string>
@@ -494,12 +493,12 @@
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"Adicionar outra"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"Seguinte"</string>
     <string name="security_settings_fingerprint_enroll_disclaimer" msgid="5831834311961551423">"Para além de desbloquear o telemóvel, também pode utilizar a sua impressão digital para autorizar compras e o acesso de aplicações. "<annotation id="url">"Saiba mais"</annotation></string>
-    <string name="security_settings_fingerprint_enroll_disclaimer_lockscreen_disabled" msgid="7954742554236652690">" A opção de bloqueio do ecrã está desativada. Para saber mais, contacte o gestor da sua entidade. "<annotation id="admin_details">"Mais detalhes"</annotation>\n\n"Pode continuar a utilizar a impressão digital para autorizar compras e o acesso a aplicações. "<annotation id="url">"Saiba mais"</annotation></string>
+    <string name="security_settings_fingerprint_enroll_disclaimer_lockscreen_disabled" msgid="7954742554236652690">" A opção de bloqueio do ecrã está desativada. Para saber mais, contacte o gestor da sua entidade. "<annotation id="admin_details">"Mais detalhes"</annotation>\n\n"Pode continuar a utilizar a impressão digital para autorizar compras e o acesso a apps. "<annotation id="url">"Saiba mais"</annotation></string>
     <string name="security_settings_fingerprint_enroll_lift_touch_again" msgid="1670703069782212223">"Levante o dedo e toque no sensor novamente"</string>
     <string name="fingerprint_add_max" msgid="2939393314646115661">"Pode adicionar até <xliff:g id="COUNT">%d</xliff:g> impressões digitais"</string>
     <string name="fingerprint_intro_error_max" msgid="3247720976621039437">"Adicionou o número máximo de impressões digitais"</string>
     <string name="fingerprint_intro_error_unknown" msgid="3975674268256524015">"Não é possível adicionar mais impressões digitais"</string>
-    <string name="fingerprint_last_delete_title" msgid="3104596858161269635">"Pretende remover todas as impressões digitais?"</string>
+    <string name="fingerprint_last_delete_title" msgid="3104596858161269635">"Remover todas as impressões digitais?"</string>
     <string name="fingerprint_delete_title" msgid="3120894112324235536">"Remover \"<xliff:g id="FINGERPRINT_ID">%1$s</xliff:g>\""</string>
     <string name="fingerprint_delete_message" msgid="5895802741486967970">"Pretende eliminar esta impressão digital?"</string>
     <string name="fingerprint_last_delete_message" msgid="3346252479778971442">"Não poderá utilizar as impressões digitais para desbloquear o telemóvel, autorizar compras ou iniciar sessão em aplicações."</string>
@@ -594,8 +593,8 @@
     <string name="unlock_set_unlock_mode_password" msgid="397703731925549447">"Palavra-passe"</string>
     <string name="unlock_setup_wizard_fingerprint_details" msgid="6515136915205473675">"Assim que configurar um bloqueio de ecrã, também pode configurar a sua impressão digital em Definições &gt; Segurança."</string>
     <string name="unlock_disable_lock_title" msgid="3508492427073600294">"Desativar bloqueio do ecrã"</string>
-    <string name="unlock_disable_frp_warning_title" msgid="5858589970505254193">"Pretende remover a proteção do dispositivo?"</string>
-    <string name="unlock_disable_frp_warning_title_profile" msgid="3814123014295965266">"Pretende remover a proteção do perfil?"</string>
+    <string name="unlock_disable_frp_warning_title" msgid="5858589970505254193">"Remover a proteção do dispositivo?"</string>
+    <string name="unlock_disable_frp_warning_title_profile" msgid="3814123014295965266">"Remover a proteção do perfil?"</string>
     <string name="unlock_disable_frp_warning_content_pattern" msgid="1843950215687159135">"As funcionalidades de proteção do dispositivo não funcionam sem o padrão."</string>
     <string name="unlock_disable_frp_warning_content_pattern_fingerprint" msgid="8846957650251741548">"As funcionalidades de proteção do dispositivo não funcionam sem o padrão.<xliff:g id="EMPTY_LINE">
 
@@ -668,7 +667,6 @@
       <item quantity="other">Tem de ter menos de <xliff:g id="NUMBER_1">%d</xliff:g> dígitos.</item>
       <item quantity="one">Tem de ter menos de <xliff:g id="NUMBER_0">%d</xliff:g> dígito.</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Tem de incluir apenas dígitos de 0 a 9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"O gestor do dispositivo não permite utilizar um PIN recente"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Os PINs comuns estão bloqueados pelo seu gestor de TI. Experimente outro PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Não pode incluir um caráter inválido"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Tem de incluir, pelo menos, <xliff:g id="COUNT">%d</xliff:g> carateres que não sejam letras</item>
       <item quantity="one">Tem de incluir, pelo menos, 1 caráter que não seja uma letra</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Tem de incluir, pelo menos, <xliff:g id="COUNT">%d</xliff:g> carateres que não sejam números.</item>
+      <item quantity="one">Tem de incluir, pelo menos, 1 caráter que não seja um número.</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"O admin. do disp. não permite a utilização de uma palavra-passe recente"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"As palavras-passe comuns estão bloqueadas pelo seu gestor de TI. Experimente outra palavra-passe."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Não é permitida uma sequência de dígitos ascendente, descendente ou repetida"</string>
@@ -727,7 +729,7 @@
     <string name="bluetooth_settings" msgid="5228032727293770389">"Bluetooth"</string>
     <string name="bluetooth_settings_title" msgid="7261244857456521825">"Bluetooth"</string>
     <string name="bluetooth_settings_summary" msgid="1221689092429277887">"Gerir ligações, definir nome e detectabilidade do dispositivo"</string>
-    <string name="bluetooth_pairing_request" msgid="7221745525632573125">"Pretende sincronizar com o dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>?"</string>
+    <string name="bluetooth_pairing_request" msgid="7221745525632573125">"Sincronizar com o dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>?"</string>
     <string name="bluetooth_pairing_key_msg" msgid="1139230917419961975">"Código de sincronização Bluetooth"</string>
     <string name="bluetooth_enter_passkey_msg" msgid="6205151011298670207">"Introduza o código de sincronização e, em seguida, prima Return ou Enter"</string>
     <string name="bluetooth_enable_alphanumeric_pin" msgid="9138308197078115672">"O PIN contém letras ou símbolos"</string>
@@ -859,7 +861,7 @@
     <string name="use_open_wifi_automatically_summary_scoring_disabled" msgid="1559329344492373028">"Para utilizar, selecionar um fornecedor de classificação de rede"</string>
     <string name="use_open_wifi_automatically_summary_scorer_unsupported_disabled" msgid="1123080670578756834">"Para utilizar, selecionar um fornecedor de classificação de rede compatível"</string>
     <string name="wifi_install_credentials" msgid="5650088113710858289">"Instalar certificados"</string>
-    <string name="wifi_scan_notify_text" msgid="7614101215028336927">"Para melhorar a precisão da localização, as aplicações e os serviços podem continuar a procurar redes Wi-Fi em qualquer altura, mesmo quando o Wi-Fi está desativado. Pode utilizar esta opção, por exemplo, para melhorar as funcionalidades e os serviços baseados na localização. Pode alterar esta opção nas <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>definições de análise<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
+    <string name="wifi_scan_notify_text" msgid="7614101215028336927">"Para melhorar a precisão da localização, as apps e os serviços podem continuar a procurar redes Wi-Fi em qualquer altura, mesmo quando o Wi-Fi está desativado. Pode utilizar esta opção, por exemplo, para melhorar as funcionalidades e os serviços baseados na localização. Pode alterar esta opção nas <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>definições de análise<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
     <string name="wifi_scan_notify_text_scanning_off" msgid="723796963816095410">"Para melhorar a precisão da localização, ative a procura de redes Wi-Fi nas <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>definições de análise<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
     <string name="wifi_scan_notify_remember_choice" msgid="1235445971400237444">"Não mostrar de novo"</string>
     <string name="wifi_setting_sleep_policy_title" msgid="2120785188625932076">"Manter Wi-Fi ligada durante suspensão"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Rede móvel"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Se o Wi‑Fi não estiver disponível, utilize a rede móvel."</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Se a rede móvel não estiver disponível, utilizar Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Chamada por Wi‑Fi. Se o Wi‑Fi for perdido, a chamada é terminada."</string>
@@ -1708,7 +1713,7 @@
     <string name="lockpassword_choose_your_pin_message" msgid="8942598950627277885">"Por motivos de segurança, defina um PIN."</string>
     <string name="lockpassword_choose_your_pin_header_for_fingerprint" msgid="1102927520952116303">"Defina PIN para usar impressão digital"</string>
     <string name="lockpassword_choose_your_pattern_message" msgid="1503075455752279687">"Por motivos de segurança, defina um padrão."</string>
-    <string name="lockpassword_confirm_your_password_header" msgid="9055242184126838887">"Reintroduzir a palavra-passe"</string>
+    <string name="lockpassword_confirm_your_password_header" msgid="9055242184126838887">"Reintroduza a palavra-passe"</string>
     <string name="lockpassword_confirm_your_pattern_header" msgid="7137526922696316545">"Confirmar o padrão"</string>
     <string name="lockpassword_confirm_your_pin_header" msgid="4335593948303036343">"Reintroduza o PIN"</string>
     <string name="lockpassword_confirm_passwords_dont_match" msgid="1783767008133345784">"As palavras-passe não correspondem"</string>
@@ -1887,7 +1892,7 @@
     <string name="app_disable_notifications_dlg_title" msgid="699530661413553928">"Desativar notificações?"</string>
     <string name="app_install_details_group_title" msgid="2909597319422976921">"Loja"</string>
     <string name="app_install_details_title" msgid="6954953384372934881">"Detalhes da aplicação"</string>
-    <string name="app_install_details_summary" msgid="6612222941121363940">"Aplicação instalada a partir da <xliff:g id="APP_STORE">%1$s</xliff:g>"</string>
+    <string name="app_install_details_summary" msgid="6612222941121363940">"App instalada a partir da <xliff:g id="APP_STORE">%1$s</xliff:g>"</string>
     <string name="instant_app_details_summary" msgid="6384264315914966114">"Mais informações sobre <xliff:g id="APP_STORE">%1$s</xliff:g>"</string>
     <string name="app_ops_running" msgid="6378418969742957805">"Em execução"</string>
     <string name="app_ops_never_used" msgid="8305262378162525813">"(Nunca utilizado)"</string>
@@ -2067,7 +2072,7 @@
     <string name="accessibility_toggle_large_pointer_icon_title" msgid="9127905775116570565">"Ponteiro do rato grande"</string>
     <string name="accessibility_disable_animations" msgid="8378441317115710009">"Remover animações"</string>
     <string name="accessibility_toggle_master_mono_title" msgid="899550848196702565">"Áudio mono"</string>
-    <string name="accessibility_toggle_master_mono_summary" msgid="3847052868469033235">"Combinar canais ao reproduzir áudio"</string>
+    <string name="accessibility_toggle_master_mono_summary" msgid="3847052868469033235">"Combine canais ao reproduzir áudio"</string>
     <string name="accessibility_toggle_master_balance_title" msgid="8723492001092647562">"Equilíbrio de áudio"</string>
     <string name="accessibility_toggle_master_balance_left_label" msgid="8531986342666527970">"Esquerda"</string>
     <string name="accessibility_toggle_master_balance_right_label" msgid="7757024572140589558">"Direita"</string>
@@ -2301,14 +2306,14 @@
       <item quantity="one">Não é possível executar esta aplicação em segundo plano.</item>
     </plurals>
     <plurals name="battery_tip_restrict_app_dialog_title" formatted="false" msgid="3042021435866172168">
-      <item quantity="other">Pretende restringir %1$d aplicações?</item>
-      <item quantity="one">Pretende restringir a aplicação?</item>
+      <item quantity="other">Restringir %1$d aplicações?</item>
+      <item quantity="one">Restringir a aplicação?</item>
     </plurals>
     <string name="battery_tip_restrict_app_dialog_message" msgid="6905822297507947381">"Para poupar bateria, impeça que a aplicação <xliff:g id="APP">%1$s</xliff:g> consuma bateria em segundo plano. Esta aplicação poderá não funcionar corretamente e as notificações poderão sofrer atrasos."</string>
     <string name="battery_tip_restrict_apps_less_than_5_dialog_message" msgid="4225881888543582456">"Para poupar bateria, impeça estas aplicações de consumir bateria em segundo plano. As aplicações restringidas poderão não funcionar corretamente e as notificações poderão sofrer atrasos.\n\nAplicações:"</string>
     <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"Para poupar bateria, impeça que estas aplicações consumam bateria em segundo plano. As aplicações restringidas poderão não funcionar corretamente e as notificações poderão sofrer atrasos.\n\nAplicações:\n<xliff:g id="APP_LIST">%1$s</xliff:g>."</string>
     <string name="battery_tip_restrict_app_dialog_ok" msgid="2573410775701913487">"Restringir"</string>
-    <string name="battery_tip_unrestrict_app_dialog_title" msgid="812458516399125710">"Pretende remover a restrição?"</string>
+    <string name="battery_tip_unrestrict_app_dialog_title" msgid="812458516399125710">"Remover a restrição?"</string>
     <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"Esta aplicação poderá utilizar a bateria em segundo plano e, por conseguinte, pode ficar sem bateria mais cedo do que o esperado."</string>
     <string name="battery_tip_unrestrict_app_dialog_ok" msgid="9154938931448151479">"Remover"</string>
     <string name="battery_tip_unrestrict_app_dialog_cancel" msgid="7331148618292397166">"Cancelar"</string>
@@ -2503,7 +2508,7 @@
     <string name="voice_service_preference_section_title" msgid="2984112696100778038">"Serviços de entrada de texto por voz"</string>
     <string name="voice_interactor_preference_summary" msgid="7321365727286121067">"Palavra de ativação e interação completas"</string>
     <string name="voice_recognizer_preference_summary" msgid="3681161319745912594">"Serviço simples de voz para texto"</string>
-    <string name="voice_interaction_security_warning" msgid="4986261746316889768">"Este serviço de entrada de texto por voz poderá efetuar monitorização de voz permanente e controlar aplicações ativadas por voz em seu nome. É proveniente da aplicação <xliff:g id="VOICE_INPUT_SERVICE_APP_NAME">%s</xliff:g>. Pretende permitir a utilização deste serviço?"</string>
+    <string name="voice_interaction_security_warning" msgid="4986261746316889768">"Este serviço de entrada de texto por voz poderá efetuar monitorização de voz permanente e controlar aplicações ativadas por voz em seu nome. É proveniente da aplicação <xliff:g id="VOICE_INPUT_SERVICE_APP_NAME">%s</xliff:g>. Permitir a utilização deste serviço?"</string>
     <string name="tts_engine_preference_title" msgid="1183116842356275061">"Motor preferido"</string>
     <string name="tts_engine_settings_title" msgid="4079757915136562358">"Definições do motor"</string>
     <string name="tts_sliders_title" msgid="1927481069989092278">"Taxa e tom de voz"</string>
@@ -2535,7 +2540,7 @@
     <string name="credentials_settings_not_available" msgid="5490259681690183274">"As credenciais não estão disponíveis para este utilizador"</string>
     <string name="credential_for_vpn_and_apps" msgid="2462642486949593841">"Instalada para VPN e aplicações"</string>
     <string name="credential_for_wifi" msgid="2903295786961726388">"Instalada para Wi-Fi"</string>
-    <string name="credentials_reset_hint" msgid="3484350477764088169">"Pretende remover todo o conteúdo?"</string>
+    <string name="credentials_reset_hint" msgid="3484350477764088169">"Remover todo o conteúdo?"</string>
     <string name="credentials_erased" msgid="7287088033523869085">"Armaz. credenciais apagado."</string>
     <string name="credentials_not_erased" msgid="9137227570738627637">"Não foi possível apagar o armazenamento de credenciais."</string>
     <string name="usage_access_title" msgid="7981321142726540574">"Apps com acesso de utilização"</string>
@@ -2550,7 +2555,7 @@
     <string name="backup_data_summary" msgid="555459891017933746">"Fazer cópia de segurança de dados da aplicação, palavras-passe Wi-Fi e outras definições para os servidores da Google"</string>
     <string name="backup_configure_account_title" msgid="1534734650559070294">"Cópia de segurança da conta"</string>
     <string name="backup_data_management_title" msgid="6299288795610243508">"Gerir a conta de cópia de segurança"</string>
-    <string name="include_app_data_title" msgid="6117211611131913293">"Incluir dados de aplicações"</string>
+    <string name="include_app_data_title" msgid="6117211611131913293">"Incluir dados de apps"</string>
     <string name="auto_restore_title" msgid="8367486774010915221">"Restauro automático"</string>
     <string name="auto_restore_summary" msgid="1941047568966428377">"Ao reinstalar uma aplicação, restaurar definições e dados da cópia de segurança"</string>
     <string name="backup_inactive_title" msgid="5513496915638307750">"O serviço de cópia de segurança não está ativo"</string>
@@ -2623,7 +2628,7 @@
     <string name="header_account_settings" msgid="8586173964125512219">"Definições da conta"</string>
     <string name="remove_account_label" msgid="5885425720323823387">"Remover conta"</string>
     <string name="header_add_an_account" msgid="8482614556580804956">"Adicionar uma conta"</string>
-    <string name="really_remove_account_title" msgid="4166512362915154319">"Pretende remover a conta?"</string>
+    <string name="really_remove_account_title" msgid="4166512362915154319">"Remover a conta?"</string>
     <string name="really_remove_account_message" product="tablet" msgid="7403843371045856719">"A remoção desta conta elimina todas as mensagens, contactos e outros dados do tablet!"</string>
     <string name="really_remove_account_message" product="default" msgid="8951224626153163914">"A remoção desta conta elimina todas as mensagens, contactos e outros dados do telemóvel!"</string>
     <string name="really_remove_account_message" product="device" msgid="3751798556257519916">"A remoção desta conta elimina todas as mensagens, os contactos e outros dados do dispositivo."</string>
@@ -2894,7 +2899,7 @@
     <string name="user_delete_button" msgid="6747802570634772774">"Eliminar"</string>
     <string name="user_guest" msgid="6226240869459683235">"Convidado"</string>
     <string name="user_exit_guest_title" msgid="7279886200373071797">"Remover convidado"</string>
-    <string name="user_exit_guest_confirm_title" msgid="4767911571671099844">"Pretende remover o convidado?"</string>
+    <string name="user_exit_guest_confirm_title" msgid="4767911571671099844">"Remover o convidado?"</string>
     <string name="user_exit_guest_confirm_message" msgid="6955182181145748919">"Todas as aplicações e dados desta sessão serão eliminados."</string>
     <string name="user_exit_guest_dialog_remove" msgid="1878866060881115716">"Remover"</string>
     <string name="user_enable_calling" msgid="864760054792249503">"Ativar chamadas telefónicas"</string>
@@ -3036,10 +3041,10 @@
     <string name="connected_devices_dashboard_no_driving_mode_summary" msgid="3524409078596318803">"Bluetooth, NFC"</string>
     <string name="connected_devices_dashboard_no_driving_mode_no_nfc_summary" msgid="7881286613528299400">"Bluetooth"</string>
     <string name="app_and_notification_dashboard_title" msgid="8448096608058843730">"Apps e notificações"</string>
-    <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"Assistente, aplicações recentes, aplicações predefinidas"</string>
+    <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"Assistente, apps recentes, apps predefinidas"</string>
     <string name="notification_settings_work_profile" msgid="7190550347842400029">"O acesso às notificações não está disponível para aplicações no perfil de trabalho."</string>
     <string name="account_dashboard_title" msgid="4734300939532555885">"Contas"</string>
-    <string name="account_dashboard_default_summary" msgid="6822549669771936206">"Nenhuma conta adicionada."</string>
+    <string name="account_dashboard_default_summary" msgid="6822549669771936206">"Nenhuma conta adicionada"</string>
     <string name="app_default_dashboard_title" msgid="6575301028225232193">"Aplicações predefinidas"</string>
     <string name="system_dashboard_summary" msgid="6582464466735779394">"Idiomas, gestos, hora, cópia de segurança"</string>
     <string name="search_results_title" msgid="4160717656435503940">"Definições"</string>
@@ -3083,7 +3088,7 @@
     <string name="keywords_all_apps" msgid="846444448435698930">"aplicações, transferência, aplicações, sistema"</string>
     <string name="keywords_app_permissions" msgid="8539841019997048500">"aplicações, autorizações, segurança"</string>
     <string name="keywords_default_apps" msgid="7435952699323965532">"aplicações, predefinição"</string>
-    <string name="keywords_ignore_optimizations" msgid="9127632532176249438">"ignorar otimizações, soneca, modo de espera das aplicações"</string>
+    <string name="keywords_ignore_optimizations" msgid="9127632532176249438">"ignorar otimizações, soneca, modo de espera das apps"</string>
     <string name="keywords_color_mode" msgid="8893345199519181751">"vibrante, RGB, sRGB, cor, natural, padrão"</string>
     <string name="keywords_color_temperature" msgid="2255253972992035046">"temperatura de cor, D65, D73, branco, amarelo, azul, quente, frio"</string>
     <string name="keywords_lockscreen" msgid="4936846554280830394">"deslizar lentamente para desbloquear, palavra-passe, padrão, PIN"</string>
@@ -3211,7 +3216,7 @@
     <string name="zen_mode_block_effect_light" msgid="8679333758037487644">"Não emitir luz intermitente"</string>
     <string name="zen_mode_block_effect_peek" msgid="6075662813575910221">"Não apresentar notificações no ecrã"</string>
     <string name="zen_mode_block_effect_status" msgid="6516614225115681068">"Ocultar ícones da barra de estado na parte superior do ecrã"</string>
-    <string name="zen_mode_block_effect_badge" msgid="3891743027347075136">"Ocultar pontos de notificação nos ícones das aplicações"</string>
+    <string name="zen_mode_block_effect_badge" msgid="3891743027347075136">"Ocultar pontos de notificação nos ícones das apps"</string>
     <string name="zen_mode_block_effect_ambient" msgid="6382013125863616197">"Não ativar para notificações"</string>
     <string name="zen_mode_block_effect_list" msgid="6081548478844912181">"Ocultar da lista de notificações"</string>
     <string name="zen_mode_block_effect_summary_none" msgid="7166175186759564510">"Nunca"</string>
@@ -3364,30 +3369,30 @@
     </plurals>
     <string name="notification_assistant_title" msgid="8216604031352764011">"Assistente de notificações"</string>
     <string name="no_notification_assistant" msgid="9140123568386413264">"Nenhum assistente"</string>
-    <string name="no_notification_listeners" msgid="1366386609506834717">"Nenhuma aplicação instalada solicitou acesso a notificações"</string>
-    <string name="notification_assistant_security_warning_title" msgid="4190584438086738496">"Pretende permitir o acesso a notificações do <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
+    <string name="no_notification_listeners" msgid="1366386609506834717">"Nenhuma app instalada solicitou acesso a notificações"</string>
+    <string name="notification_assistant_security_warning_title" msgid="4190584438086738496">"Permitir o acesso a notificações do <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="notification_assistant_security_warning_summary" msgid="6924513399671031930">"O <xliff:g id="NOTIFICATION_ASSISTANT_NAME">%1$s</xliff:g> consegue ler todas as notificações, incluindo informações pessoais como nomes de contactos e o texto das mensagens recebidas. Também consegue modificar ou ignorar notificações, assim como acionar botões de ação que estas contenham. \n\nDeste modo, a aplicação também pode ativar ou desativar o modo Não incomodar e alterar as definições relacionadas."</string>
-    <string name="notification_listener_security_warning_title" msgid="4902253246428777797">"Pretende permitir o acesso a notificações do <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
+    <string name="notification_listener_security_warning_title" msgid="4902253246428777797">"Permitir o acesso a notificações do <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="notification_listener_security_warning_summary" msgid="4454702907350100288">"O <xliff:g id="NOTIFICATION_LISTENER_NAME">%1$s</xliff:g> consegue ler todas as notificações, incluindo informações pessoais como nomes de contactos e o texto das mensagens recebidas. Também consegue ignorar notificações ou acionar botões de ação que estas contenham. \n\nDeste modo, a aplicação também pode ativar ou desativar o modo Não incomodar e alterar as definições relacionadas."</string>
     <string name="notification_listener_disable_warning_summary" msgid="162165151519082978">"Se desativar o acesso às notificações para <xliff:g id="NOTIFICATION_LISTENER_NAME">%1$s</xliff:g>, é possível que o acesso ao modo Não incomodar seja igualmente desativado."</string>
     <string name="notification_listener_disable_warning_confirm" msgid="7863495391671154188">"Desativar"</string>
     <string name="notification_listener_disable_warning_cancel" msgid="6264631825225298458">"Cancelar"</string>
     <string name="vr_listeners_title" msgid="511483902408792832">"Serviços de assistente de RV"</string>
-    <string name="no_vr_listeners" msgid="7675484190394450979">"Nenhuma aplicação instalada pediu para ser executada como serviço de assistente de RV."</string>
-    <string name="vr_listener_security_warning_title" msgid="7019322246707645361">"Pretende permitir que o serviço de RV tenha acesso a <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
+    <string name="no_vr_listeners" msgid="7675484190394450979">"Nenhuma app instalada pediu para ser executada como serviço de assistente de RV."</string>
+    <string name="vr_listener_security_warning_title" msgid="7019322246707645361">"Permitir que o serviço de RV tenha acesso a <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="vr_listener_security_warning_summary" msgid="5093225583584522067">"Será possível executar o <xliff:g id="VR_LISTENER_NAME">%1$s</xliff:g> quando estiver a utilizar aplicações no modo de realidade virtual."</string>
     <string name="display_vr_pref_title" msgid="1088464812293416981">"Com o dispositivo no modo RV"</string>
     <string name="display_vr_pref_low_persistence" msgid="3132583929174794245">"Reduzir a desfocagem (recomendado)"</string>
     <string name="display_vr_pref_off" msgid="4681320968818852691">"Reduzir a cintilação"</string>
     <string name="picture_in_picture_title" msgid="4960733106166035448">"Imagem na imagem"</string>
-    <string name="picture_in_picture_empty_text" msgid="8664071475324685241">"Nenhuma aplicação instalada é compatível com Imagem na imagem"</string>
+    <string name="picture_in_picture_empty_text" msgid="8664071475324685241">"Nenhuma app instalada é compatível com Imagem na imagem"</string>
     <string name="picture_in_picture_keywords" msgid="7326958702002259262">"pip picture in"</string>
     <string name="picture_in_picture_app_detail_title" msgid="3916189052657425936">"Imagem na imagem"</string>
     <string name="picture_in_picture_app_detail_switch" msgid="747422998967185418">"Permitir imagem na imagem"</string>
     <string name="picture_in_picture_app_detail_summary" msgid="918632751775525347">"Permita que esta aplicação crie uma janela de ecrã no ecrã enquanto a aplicação está aberta ou depois de sair da mesma (por exemplo, para continuar a ver um vídeo). Esta janela é apresentada sobre as outras aplicações que estiver a utilizar."</string>
     <string name="manage_zen_access_title" msgid="3058206309728524196">"Acesso Não incomodar"</string>
     <string name="zen_access_detail_switch" msgid="8706332327904974500">"Permitir o modo Não incomodar"</string>
-    <string name="zen_access_empty_text" msgid="7667538993781607731">"Nenhuma aplicação instalada solicitou acesso Não incomodar"</string>
+    <string name="zen_access_empty_text" msgid="7667538993781607731">"Nenhuma app instalada solicitou acesso Não incomodar"</string>
     <string name="loading_notification_apps" msgid="1978345231934072091">"A carregar aplicações..."</string>
     <string name="app_notifications_off_desc" msgid="3904090905748895146">"A seu pedido, o Android está a bloquear a apresentação das notificações desta aplicação neste dispositivo."</string>
     <string name="channel_notifications_off_desc" msgid="8005444443218306611">"A seu pedido, o Android está a bloquear a apresentação desta categoria de notificações neste dispositivo."</string>
@@ -3504,7 +3509,7 @@
     <string name="zen_mode_reminders_list" msgid="7347061314032326677">"lembretes"</string>
     <string name="zen_mode_events" msgid="5784076928339534984">"Permitir eventos"</string>
     <string name="zen_mode_bypassing_apps" msgid="3080739479028713449">"Permitir que as aplicações substituam"</string>
-    <string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"Exceções de aplicações"</string>
+    <string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"Exceções de apps"</string>
     <plurals name="zen_mode_bypassing_apps_subtext" formatted="false" msgid="8723144434730871572">
       <item quantity="other">As notificações de <xliff:g id="NUMBER">%1$d</xliff:g> aplicações podem substituir o modo Não incomodar</item>
       <item quantity="one">As notificações de 1 aplicação podem substituir o modo Não incomodar</item>
@@ -3545,7 +3550,7 @@
     <string name="zen_mode_screen_off_summary_no_led" msgid="7255874108150630145">"Permitir que as notificações silenciadas pelo modo Não incomodar liguem o ecrã"</string>
     <string name="notification_app_settings_button" msgid="3651180424198580907">"Definições de notificações"</string>
     <string name="suggestion_button_text" msgid="5783566542423813847">"Ok"</string>
-    <string name="device_feedback" msgid="4042352891448769818">"Enviar comentários do dispositivo"</string>
+    <string name="device_feedback" msgid="4042352891448769818">"Enviar feedback do dispositivo"</string>
     <string name="restr_pin_enter_admin_pin" msgid="8577847751493521230">"Introduzir o PIN do gestor"</string>
     <string name="switch_on_text" msgid="7100491749799298324">"Ativado"</string>
     <string name="switch_off_text" msgid="3539551289454353555">"Desativado"</string>
@@ -3628,7 +3633,7 @@
     <string name="runtime_permissions_summary_no_permissions_requested" msgid="3901636077467389637">"Nenhuma permissão solicitada"</string>
     <string name="filter_all_apps" msgid="4042756539846043675">"Todas as aplicações"</string>
     <string name="filter_enabled_apps" msgid="5888459261768538489">"Aplicações instaladas"</string>
-    <string name="filter_instant_apps" msgid="8087483282854072366">"Aplicações instantâneas"</string>
+    <string name="filter_instant_apps" msgid="8087483282854072366">"Apps instantâneas"</string>
     <string name="filter_personal_apps" msgid="3473268022652904457">"Pessoais"</string>
     <string name="filter_work_apps" msgid="4202483998339465542">"De trabalho"</string>
     <string name="filter_notif_all_apps" msgid="1862666327228804896">"Aplicações: todas"</string>
@@ -3659,7 +3664,7 @@
     <string name="default_apps_title" msgid="3848048391400989931">"Predefinição"</string>
     <string name="default_for_work" msgid="7290411716804495366">"Predefinição para o trabalho"</string>
     <string name="assist_and_voice_input_title" msgid="324148194703846130">"Assistência e entrada por voz"</string>
-    <string name="default_assist_title" msgid="2060846994203235317">"Aplicação de assistência"</string>
+    <string name="default_assist_title" msgid="2060846994203235317">"App de assistência"</string>
     <string name="assistant_security_warning_title" msgid="8014460924169723059">"Pretende tornar <xliff:g id="ASSISTANT_APP_NAME">%s</xliff:g> o seu assistente?"</string>
     <string name="assistant_security_warning" msgid="1304057692847069938">"O assistente pode ler informações sobre aplicações utilizadas no seu sistema, incluindo informações visíveis no ecrã ou acessíveis nas aplicações."</string>
     <string name="assistant_security_warning_agree" msgid="5105692801460137289">"Aceitar"</string>
@@ -3754,12 +3759,12 @@
     <string name="background_check_pref" msgid="664081406854758392">"Verificação em segundo plano"</string>
     <string name="background_check_title" msgid="4136736684290307970">"Acesso completo em segundo plano"</string>
     <string name="assist_access_context_title" msgid="2274614501747710439">"Utilizar o texto do ecrã"</string>
-    <string name="assist_access_context_summary" msgid="5867997494395842785">"Permitir que a aplicação de assistência aceda ao conteúdo do ecrã como texto"</string>
+    <string name="assist_access_context_summary" msgid="5867997494395842785">"Permitir que a app de assistência aceda ao conteúdo do ecrã como texto"</string>
     <string name="assist_access_screenshot_title" msgid="1991014038776117688">"Utilizar captura de ecrã"</string>
-    <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Permitir que a aplicação de assistência aceda a uma imagem do ecrã"</string>
+    <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Permitir que a app de assistência aceda a uma imagem do ecrã"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"Fazer piscar o ecrã"</string>
-    <string name="assist_flash_summary" msgid="6697095786317559129">"Fazer piscar os limites do ecrã quando a aplicação de assistência acede a texto do ecrã ou de capturas de ecrã"</string>
-    <string name="assist_footer" msgid="7030121180457472165">"As aplicações de assistência podem ajudá-lo com base em informações do ecrã que está a ver. Algumas aplicações são compatíveis com serviços de iniciação e de entrada de texto por voz para oferecer assistência integrada."</string>
+    <string name="assist_flash_summary" msgid="6697095786317559129">"Fazer piscar os limites do ecrã quando a app de assistência acede a texto do ecrã ou de capturas de ecrã"</string>
+    <string name="assist_footer" msgid="7030121180457472165">"As apps de assistência podem ajudá-lo com base em informações do ecrã que está a ver. Algumas apps são compatíveis com serviços de iniciação e de entrada de texto por voz para oferecer assistência integrada."</string>
     <string name="average_memory_use" msgid="5333366040118953945">"Utilização média da memória"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"Utilização máxima da memória"</string>
     <string name="memory_usage" msgid="7963253555330830906">"Utilização da memória"</string>
@@ -3781,7 +3786,7 @@
     <string name="running_frequency" msgid="7545170806968474449">"Frequência"</string>
     <string name="memory_maximum_usage" msgid="4734981118293469479">"Utilização máxima"</string>
     <string name="no_data_usage" msgid="903383745620135746">"Sem dados utilizados"</string>
-    <string name="zen_access_warning_dialog_title" msgid="7704910289810337055">"Pretende permitir o acesso a Não incomodar para <xliff:g id="APP">%1$s</xliff:g>?"</string>
+    <string name="zen_access_warning_dialog_title" msgid="7704910289810337055">"Permitir o acesso a Não incomodar para <xliff:g id="APP">%1$s</xliff:g>?"</string>
     <string name="zen_access_warning_dialog_summary" msgid="2717755746850874577">"A aplicação conseguirá ligar e desligar o modo Não incomodar e efetuar alterações nas definições relacionadas."</string>
     <string name="zen_access_disabled_package_warning" msgid="7086237569177576966">"Tem de permanecer ativado porque o acesso às notificações está ativado"</string>
     <string name="zen_access_revoke_warning_dialog_title" msgid="6850994585577513299">"Pretende revogar o acesso a Não incomodar do <xliff:g id="APP">%1$s</xliff:g>?"</string>
@@ -3792,7 +3797,7 @@
     <string name="ignore_optimizations_off_desc" msgid="5598702251817814289">"Recomendado para aumentar a duração da bateria"</string>
     <string name="ignore_optimizations_title" msgid="7924345545276166305">"Permitir que <xliff:g id="APP">%s</xliff:g> ignore as otimizações da bateria?"</string>
     <string name="app_list_preference_none" msgid="7100409177446935028">"Nenhuma"</string>
-    <string name="work_profile_usage_access_warning" msgid="403208064382097510">"Se desativar o acesso de utilização desta aplicação, não impede que o gestor monitorize a utilização de dados de aplicações no seu perfil de trabalho."</string>
+    <string name="work_profile_usage_access_warning" msgid="403208064382097510">"Se desativar o acesso de utilização desta aplicação, não impede que o gestor monitorize a utilização de dados de apps no seu perfil de trabalho."</string>
     <string name="accessibility_lock_screen_progress" msgid="8242917828598820049">"<xliff:g id="COUNT_0">%1$d</xliff:g> de <xliff:g id="COUNT_1">%2$d</xliff:g> carateres utilizados"</string>
     <string name="draw_overlay" msgid="2878665072530660668">"Sobrepor a outras aplicações"</string>
     <string name="system_alert_window_settings" msgid="3024330223417646567">"Sobrepor a outras aplicações"</string>
@@ -3850,7 +3855,7 @@
       <item quantity="other">Desativadas para <xliff:g id="COUNT">%d</xliff:g> aplicações</item>
       <item quantity="one">Desativadas para 1 aplicação</item>
     </plurals>
-    <string name="notification_summary_none" msgid="5003043219430054784">"Ativadas para todas as aplicações"</string>
+    <string name="notification_summary_none" msgid="5003043219430054784">"Ativadas para todas as apps"</string>
     <string name="apps_summary" msgid="8355759446490212195">"<xliff:g id="COUNT">%1$d</xliff:g> aplicações instaladas"</string>
     <string name="apps_summary_example" msgid="3011143598675185269">"24 aplicações instaladas"</string>
     <string name="storage_summary" msgid="4835916510511133784">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> utilizado – <xliff:g id="FREE_SPACE">%2$s</xliff:g> livre(s)"</string>
@@ -4062,7 +4067,7 @@
     <string name="page_tab_title_summary" msgid="4824744863994538006">"Todas"</string>
     <string name="page_tab_title_support" msgid="5569262185010367870">"Sugestões e apoio técnico"</string>
     <string name="developer_smallest_width" msgid="2603134476228805075">"A menor largura"</string>
-    <string name="premium_sms_none" msgid="940723020871007898">"Nenhuma aplicação instalada solicitou acesso a SMS premium"</string>
+    <string name="premium_sms_none" msgid="940723020871007898">"Nenhuma app instalada solicitou acesso a SMS premium"</string>
     <string name="premium_sms_warning" msgid="7604011651486294515">"O serviço de SMS premium pode custar dinheiro e, nesse caso, será adicionado às faturas do seu operador. Se ativar a autorização para uma aplicação, poderá enviar SMS premium através da mesma."</string>
     <string name="premium_sms_access" msgid="4550027460595822851">"Acesso a SMS premium"</string>
     <string name="bluetooth_disabled" msgid="6588102116819268238">"Desativado"</string>
@@ -4144,10 +4149,10 @@
     <string name="oem_unlock_enable_disabled_summary_sim_locked_device" msgid="5223278198179877704">"Indisponível em dispositivos vinculados ao operador"</string>
     <string name="oem_lock_info_message" msgid="5090850412279403901">"Reinicie o dispositivo para ativar a funcionalidade de proteção do mesmo."</string>
     <string name="automatic_storage_manager_freed_bytes" msgid="7360443072390107772">"Foi disponibilizado um total de <xliff:g id="SIZE">%1$s</xliff:g>\n\nÚltima execução: <xliff:g id="DATE">%2$s</xliff:g>"</string>
-    <string name="web_action_enable_title" msgid="4462106633708675959">"Aplicações instantâneas"</string>
+    <string name="web_action_enable_title" msgid="4462106633708675959">"Apps instantâneas"</string>
     <string name="web_action_enable_summary" msgid="1729016644691793085">"Abrir links nas aplicações, mesmo que não estejam instaladas"</string>
-    <string name="web_action_section_title" msgid="5563229447734734662">"Aplicações instantâneas"</string>
-    <string name="instant_apps_settings" msgid="879003203555847537">"Preferências das Aplicações instantâneas"</string>
+    <string name="web_action_section_title" msgid="5563229447734734662">"Apps instantâneas"</string>
+    <string name="instant_apps_settings" msgid="879003203555847537">"Preferências das Apps instantâneas"</string>
     <string name="domain_url_section_title" msgid="206403507921518321">"Aplicações instaladas"</string>
     <string name="automatic_storage_manager_activation_warning" msgid="2630083316417707308">"O seu armazenamento está agora a ser gerido pelo gestor de armazenamento"</string>
     <string name="account_for_section_header" msgid="5975241715840642563">"Contas de <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
@@ -4239,7 +4244,7 @@
     <string name="storage_volume_total" msgid="5021484171514159913">"utilizados de <xliff:g id="TOTAL">%1$s</xliff:g>"</string>
     <string name="storage_percent_full" msgid="6924662861545958442">"utilizado"</string>
     <string name="clear_instant_app_data" msgid="3673669086522890405">"Limpar aplicação"</string>
-    <string name="clear_instant_app_confirmation" msgid="1778553115373698061">"Pretende remover esta aplicação instantânea?"</string>
+    <string name="clear_instant_app_confirmation" msgid="1778553115373698061">"Remover esta app instantânea?"</string>
     <string name="launch_instant_app" msgid="5251693061228352333">"Abrir"</string>
     <string name="game_storage_settings" msgid="6856911551799175914">"Jogos"</string>
     <string name="audio_files_title" msgid="3073879661731363935">"Ficheiros de áudio"</string>
@@ -4262,7 +4267,7 @@
     <string name="storage_manager_indicator" msgid="4255140732848476875">"Gestor de armazenamento: <xliff:g id="STATUS">^1</xliff:g>"</string>
     <string name="storage_manager_indicator_off" msgid="6404056007102580777">"Desativado"</string>
     <string name="storage_manager_indicator_on" msgid="5295306384982062320">"Ativado"</string>
-    <string name="install_type_instant" msgid="6248487669862821874">"Aplicação instantânea"</string>
+    <string name="install_type_instant" msgid="6248487669862821874">"App instantânea"</string>
     <string name="automatic_storage_manager_deactivation_warning" msgid="7867793739491286374">"Pretende desativar o gestor de armazenamento?"</string>
     <string name="storage_movies_tv" msgid="7282484273991655296">"Aplicações de filmes e TV"</string>
     <string name="carrier_provisioning" msgid="3309125279191534469">"Informações de fornecimento do operador"</string>
@@ -4305,7 +4310,7 @@
     <string name="change_wifi_state_title" msgid="5140754955787584174">"Controlo do Wi-Fi"</string>
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"Permitir à aplicação controlar o Wi-Fi"</string>
     <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"Permitir a esta aplicação ativar ou desativar o Wi-Fi, procurar e estabelecer ligação a redes Wi-Fi, adicionar ou remover redes, assim como iniciar uma zona Wi-Fi apenas local."</string>
-    <string name="media_output_title" msgid="8710632337456601848">"Reproduzir multimédia em"</string>
+    <string name="media_output_title" msgid="8710632337456601848">"Reproduzir multimédia:"</string>
     <string name="media_output_default_summary" msgid="3159237976830415584">"Este dispositivo"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"Telemóvel"</string>
     <string name="media_output_summary" product="tablet" msgid="6672024060360538526">"Tablet"</string>
@@ -4434,7 +4439,7 @@
     <string name="cdma_subscription_summary" msgid="2298861419202726628">"Alternar entre RUIM/SIM e NV"</string>
     <string name="cdma_subscription_dialogtitle" msgid="232485231569225126">"subscrição"</string>
     <string name="register_automatically" msgid="1858081641661493109">"Registo automático…"</string>
-    <string name="roaming_alert_title" msgid="1849237823113454475">"Pretende permitir roaming de dados?"</string>
+    <string name="roaming_alert_title" msgid="1849237823113454475">"Permitir roaming de dados?"</string>
     <string name="roaming_check_price_warning" msgid="5883499714594419439">"Consulte o seu fornecedor de serviços de rede para obter preços."</string>
     <string name="mobile_data_usage_title" msgid="2376358672434990037">"Utilização de dados da aplicação"</string>
     <string name="mobile_network_mode_error" msgid="6818434186286086554">"Modo de rede inválido: <xliff:g id="NETWORKMODEID">%1$d</xliff:g>. Ignore."</string>
@@ -4469,11 +4474,11 @@
     <string name="privacy_dashboard_summary" msgid="7916431309860824945">"Autorizações, atividade da conta, dados pessoais"</string>
     <string name="contextual_card_dismiss_remove" msgid="1750420285615827309">"Remover"</string>
     <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"Manter"</string>
-    <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"Pretende remover esta sugestão?"</string>
+    <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"Remover esta sugestão?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"Sugestão removida"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"Anular"</string>
     <string name="low_storage_summary" msgid="4562224870189133400">"Tem pouco espaço de armazenamento. <xliff:g id="PERCENTAGE">%1$s</xliff:g> utilizados – <xliff:g id="FREE_SPACE">%2$s</xliff:g> livres."</string>
-    <string name="contextual_card_feedback_send" msgid="8698649023854350623">"Enviar comentários"</string>
+    <string name="contextual_card_feedback_send" msgid="8698649023854350623">"Enviar feedback"</string>
     <string name="contextual_card_feedback_confirm_message" msgid="3987973028353264878">"Pretende enviar-nos comentários acerca desta sugestão?"</string>
     <string name="copyable_slice_toast" msgid="1357518174923789947">"<xliff:g id="COPY_CONTENT">%1$s</xliff:g> copiado para a área de transferência."</string>
     <string name="search_bar_account_avatar_content_description" msgid="947628881535053409"></string>
diff --git a/tests/CarDeveloperOptions/res/values-pt/arrays.xml b/tests/CarDeveloperOptions/res/values-pt/arrays.xml
index 2a5f2f6..2ae29a0 100644
--- a/tests/CarDeveloperOptions/res/values-pt/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-pt/arrays.xml
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"Nunca permitir"</item>
     <item msgid="8184570120217958741">"Sempre permitir"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Moderada"</item>
+    <item msgid="1555861583162930714">"Baixa"</item>
+    <item msgid="1719683776264798117">"Crítico"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normal"</item>
+    <item msgid="6107138933849816768">"Moderado"</item>
+    <item msgid="182695359839047859">"Baixa"</item>
+    <item msgid="8577246509202964244">"Crítica"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Persistente"</item>
     <item msgid="167418068739176448">"Principal atividade"</item>
diff --git a/tests/CarDeveloperOptions/res/values-pt/config.xml b/tests/CarDeveloperOptions/res/values-pt/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-pt/config.xml
+++ b/tests/CarDeveloperOptions/res/values-pt/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-pt/strings.xml b/tests/CarDeveloperOptions/res/values-pt/strings.xml
index 0de3591..1f678e4 100644
--- a/tests/CarDeveloperOptions/res/values-pt/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-pt/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Tornar o texto na tela menor ou maior."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Tornar menor"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Tornar maior"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Texto de amostra"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"O Mágico de Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Capítulo 11: A maravilhosa Cidade das Esmeraldas de Oz"</string>
@@ -200,7 +199,7 @@
     <string name="proxy_exclusionlist_label" msgid="8179084955547941904">"Evitar proxy para"</string>
     <string name="proxy_defaultView_text" msgid="5785775257042403261">"Restaurar padrões"</string>
     <string name="proxy_action_text" msgid="814511434843981413">"Concluído"</string>
-    <string name="proxy_hostname_label" msgid="6798891831427287847">"Hostname do proxy"</string>
+    <string name="proxy_hostname_label" msgid="6798891831427287847">"Nome do host do proxy"</string>
     <string name="proxy_error" msgid="5036164133669802299">"Atenção"</string>
     <string name="proxy_error_dismiss" msgid="883805570485635650">"OK"</string>
     <string name="proxy_error_invalid_host" msgid="5430640241353307223">"O nome de host digitado não é válido."</string>
@@ -489,7 +488,7 @@
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"Opa, este não é o sensor"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"Toque no sensor na parte traseira do smartphone. Use o dedo indicador."</string>
     <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"O registro não foi concluído"</string>
-    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Prazo de registro de impressões digitais atingido. Tente novamente."</string>
+    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"O tempo limite para o registro de impressões digitais foi atingido. Tente novamente."</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"O registro da impressão digital não funcionou. Tente novamente ou use um dedo diferente."</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"Adicionar outra"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"Próxima"</string>
@@ -544,7 +543,7 @@
     <string name="suggested_fingerprint_lock_settings_summary" product="tablet" msgid="8114514312665251311"></string>
     <string name="suggested_fingerprint_lock_settings_summary" product="device" msgid="8114514312665251311"></string>
     <string name="suggested_fingerprint_lock_settings_summary" product="default" msgid="8114514312665251311"></string>
-    <string name="lock_settings_picker_title" msgid="1034741644461982205">"Escolher bloqueio de tela"</string>
+    <string name="lock_settings_picker_title" msgid="1034741644461982205">"Bloqueio de tela"</string>
     <string name="lock_settings_picker_title_profile" msgid="5086594364428782115">"Escolher bloq de trab."</string>
     <string name="setup_lock_settings_picker_title" product="tablet" msgid="2429667472335773519">"Proteger o tablet"</string>
     <string name="setup_lock_settings_picker_title" product="device" msgid="4739290104106645233">"Proteger o dispositivo"</string>
@@ -668,7 +667,6 @@
       <item quantity="one">Precisa ter menos de <xliff:g id="NUMBER_1">%d</xliff:g> dígito</item>
       <item quantity="other">Precisa ter menos de <xliff:g id="NUMBER_1">%d</xliff:g> dígitos</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Precisa ter apenas dígitos de 0 a 9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"O administrador do dispositivo não permite o uso de um PIN recente"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"PINs comuns foram bloqueados pelo seu administrador de TI. Tente um PIN diferente."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Não pode incluir um caractere inválido"</string>
@@ -699,6 +697,10 @@
       <item quantity="one">Precisa ter pelo menos <xliff:g id="COUNT">%d</xliff:g> caractere que não seja letra</item>
       <item quantity="other">Precisa ter pelo menos <xliff:g id="COUNT">%d</xliff:g> caracteres que não sejam letras</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">Precisa ter pelo menos <xliff:g id="COUNT">%d</xliff:g> caractere não numérico</item>
+      <item quantity="other">Precisa ter pelo menos <xliff:g id="COUNT">%d</xliff:g> caracteres não numéricos</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"O administrador do dispositivo não permite usar uma senha recente"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Senhas comuns foram bloqueadas pelo seu administrador de TI. Tente uma senha diferente."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Não é permitido usar uma sequência de dígitos em ordem crescente, decrescente ou repetidos"</string>
@@ -891,7 +893,7 @@
     <string name="wifi_empty_list_user_restricted" msgid="2341613007817352431">"Você não tem permissão para alterar a rede Wi-Fi."</string>
     <string name="wifi_more" msgid="3538241640407382185">"Mais"</string>
     <string name="wifi_setup_wps" msgid="6730131677695521321">"Configuração automática (WPS)"</string>
-    <string name="wifi_settings_scanning_required_title" msgid="3593457187659922490">"Ativar a Busca por Wi‑Fi?"</string>
+    <string name="wifi_settings_scanning_required_title" msgid="3593457187659922490">"Ativar a \"busca por Wi‑Fi\"?"</string>
     <string name="wifi_settings_scanning_required_summary" msgid="7469610959462708782">"Para ativar o Wi‑Fi automaticamente, primeiro você precisa ativar a Busca por Wi‑Fi."</string>
     <string name="wifi_settings_scanning_required_info" msgid="5913535073390607386">"A Busca por Wi-Fi permite que apps e serviços procurem redes Wi‑Fi a qualquer momento, mesmo quando o Wi‑Fi está desativado. Essa configuração pode ser usada, por exemplo, para melhorar recursos e serviços baseados na localização."</string>
     <string name="wifi_settings_scanning_required_turn_on" msgid="4327570180594277049">"Ativar"</string>
@@ -903,7 +905,7 @@
     <string name="wifi_ssid_hint" msgid="5010024648106585165">"Digite o SSID"</string>
     <string name="wifi_security" msgid="9136702039496152831">"Segurança"</string>
     <string name="wifi_hidden_network" msgid="6647772204699776833">"Rede oculta"</string>
-    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Se seu roteador não estiver transmitindo um código de rede, mas você quiser se conectar a ele no futuro, configure a rede como oculta.\n\nIsso pode gerar um risco à segurança, porque seu smartphone transmitirá regularmente o próprio sinal para encontrar a rede.\n\nA configuração da rede como oculta não altera as configurações do seu roteador."</string>
+    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Se seu roteador não estiver transmitindo o ID da rede, mas você quiser se conectar a ela no futuro, configure a rede como oculta.\n\nIsso pode gerar um risco à segurança, porque seu smartphone transmitirá regularmente o próprio sinal para encontrar a rede.\n\nA configuração da rede como oculta não altera as configurações do seu roteador."</string>
     <string name="wifi_signal" msgid="696548364467704808">"Potência do sinal"</string>
     <string name="wifi_status" msgid="3439931558930689940">"Status"</string>
     <string name="tx_wifi_speed" msgid="2571810085003261073">"Velocidade do link de transmissão"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Celular"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Se o Wi‑Fi estiver indisponível, use a rede móvel"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Se a rede móvel estiver indisponível, use Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Chamar via Wi-Fi. Sem sinal do Wi‑Fi, a chamada será encerrada."</string>
@@ -1578,7 +1583,7 @@
     <string name="reset_network_complete_toast" msgid="128225929536005495">"As configurações de rede foram redefinidas"</string>
     <string name="reset_esim_error_title" msgid="4728931209471875632">"Não é possível limpar chips"</string>
     <string name="reset_esim_error_msg" msgid="4716366079119742235">"Os chips transferidos por download não podem ser limpos devido a um erro.\n\nReinicie o dispositivo e tente novamente."</string>
-    <string name="master_clear_title" msgid="1560712943955904673">"Limpar todos os dados (redefinição para configuração original)"</string>
+    <string name="master_clear_title" msgid="1560712943955904673">"Limpar todos os dados (redefinir para a configuração original)"</string>
     <string name="master_clear_short_title" msgid="919098101581335101">"Limpar todos os dados"</string>
     <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"Essa ação limpará todos os dados do "<b>"armazenamento interno"</b>" do seu tablet, incluindo:\n\n"<li>"sua Conta do Google;"</li>\n<li>"configurações e dados do sistema e dos apps;"</li>\n<li>"apps transferidos."</li></string>
     <string name="master_clear_desc" product="default" msgid="8765543541962866697">"Essa ação limpará todos os dados do "<b>"armazenamento interno"</b>" do seu smartphone, incluindo:\n\n"<li>"Sua Conta do Google"</li>\n<li>"Configurações e dados do sistema e dos apps"</li>\n<li>"Apps transferidos"</li></string>
@@ -2044,7 +2049,7 @@
     <string name="feature_flags_dashboard_title" msgid="3153034144122754381">"Sinalizações de recursos"</string>
     <string name="talkback_title" msgid="3717960404234260050">"Talkback"</string>
     <string name="talkback_summary" msgid="6602857105831641574">"Leitor de tela, usado principalmente para pessoas com deficiência visual total ou parcial"</string>
-    <string name="select_to_speak_summary" msgid="7514180457557735421">"Tocar nos itens exibidos na tela para ouvir a leitura deles em voz alta"</string>
+    <string name="select_to_speak_summary" msgid="7514180457557735421">"Tocar nos itens da tela para ouvir a leitura em voz alta"</string>
     <string name="accessibility_captioning_title" msgid="5878371993023439642">"Legendas"</string>
     <string name="accessibility_screen_magnification_title" msgid="7250949681883917360">"Ampliação"</string>
     <string name="accessibility_screen_magnification_gestures_title" msgid="9199287875401817974">"Ampliar com toque triplo"</string>
@@ -2276,7 +2281,7 @@
     <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"A bateria pode acabar antes do normal"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Economia de bateria ativada"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Alguns recursos podem ser limitados"</string>
-    <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Smartphone usado além do normal"</string>
+    <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Smartphone usado mais que o normal"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"Tablet usado além do normal"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"Dispositivo usado além do normal"</string>
     <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"A bateria pode acabar antes do esperado"</string>
@@ -2425,7 +2430,7 @@
     <string name="battery_last_full_charge" msgid="5624033030647170717">"Última carga completa"</string>
     <string name="battery_full_charge_last" msgid="4614554109170251301">"A carga completa dura cerca de"</string>
     <string name="battery_footer_summary" msgid="4828444679643906943">"Os dados de uso da bateria são aproximados e podem mudar conforme o uso"</string>
-    <string name="battery_detail_foreground" msgid="6616408559186553085">"Ativo"</string>
+    <string name="battery_detail_foreground" msgid="6616408559186553085">"Durante o uso"</string>
     <string name="battery_detail_background" msgid="7938146832943604280">"Em segundo plano"</string>
     <string name="battery_detail_power_usage" msgid="3606930232257489212">"Uso da bateria"</string>
     <string name="battery_detail_info_title" msgid="4617514228447481336">"Desde a carga completa"</string>
@@ -2666,7 +2671,7 @@
     <string name="data_usage_cellular_data_summary" msgid="9162777397135709280">"Pausa no limite"</string>
     <string name="account_settings_menu_auto_sync" msgid="2673669556006027506">"Sincron. dados automaticamente"</string>
     <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"Sinc. autom. dados pessoais"</string>
-    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Autossincronizar dados de trabalho"</string>
+    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Sincronizar dados de trabalho automaticamente"</string>
     <string name="data_usage_change_cycle" msgid="447761920472170031">"Alterar ciclo..."</string>
     <string name="data_usage_pick_cycle_day" msgid="6319750879145917066">"Dia do mês para redefinir o ciclo de uso dos dados:"</string>
     <string name="data_usage_empty" msgid="7981405723435034032">"Nenhum app usou dados durante o período."</string>
@@ -2868,7 +2873,7 @@
     <string name="user_add_user_message_long" msgid="686637203224195465">"Você pode compartilhar este dispositivo com outras pessoas, adicionando usuários. Cada usuário tem o próprio espaço, que pode ser personalizado com apps, planos de fundo, etc. Os usuários também podem ajustar as configurações do dispositivo, como o Wi‑Fi, que afetam a todos.\n\nQuando você adiciona um novo usuário, essa pessoa precisa configurar o próprio espaço.\n\nQualquer usuário pode atualizar apps para todos os outros. Serviços e configurações de acessibilidade podem não ser transferidos para novos usuários."</string>
     <string name="user_add_user_message_short" msgid="1802594476285458254">"Quando você adiciona um novo usuário, essa pessoa precisa configurar o próprio espaço.\n\nQualquer usuário pode atualizar apps para os demais usuários."</string>
     <string name="user_setup_dialog_title" msgid="6748950002206392396">"Configurar o usuário agora?"</string>
-    <string name="user_setup_dialog_message" msgid="2988559933258353919">"Certifique-se de que a pessoa está disponível para acessar o dispositivo e fazer as próprias configurações"</string>
+    <string name="user_setup_dialog_message" msgid="2988559933258353919">"Verifique se a pessoa está disponível para acessar o dispositivo e fazer as próprias configurações"</string>
     <string name="user_setup_profile_dialog_message" msgid="7611900802824048526">"Configurar perfil agora?"</string>
     <string name="user_setup_button_setup_now" msgid="4941459406266856176">"Configurar agora"</string>
     <string name="user_setup_button_setup_later" msgid="6596031428556518752">"Agora não"</string>
@@ -3026,7 +3031,7 @@
       <item quantity="one">Mostrar %d item oculto</item>
       <item quantity="other">Mostrar %d itens ocultos</item>
     </plurals>
-    <string name="network_dashboard_title" msgid="8288134139584687806">"Rede e internet"</string>
+    <string name="network_dashboard_title" msgid="8288134139584687806">"Rede e Internet"</string>
     <string name="network_dashboard_summary_mobile" msgid="5560545061217580626">"rede móvel"</string>
     <string name="network_dashboard_summary_data_usage" msgid="4695629715072542102">"uso de dados"</string>
     <string name="network_dashboard_summary_hotspot" msgid="3928610802321995214">"ponto de acesso"</string>
@@ -3156,7 +3161,7 @@
     <string name="emergency_tone_alert" msgid="907868135091891015">"Tons"</string>
     <string name="emergency_tone_vibrate" msgid="5020068066905681181">"Vibrações"</string>
     <string name="boot_sounds_title" msgid="7583926202411353620">"Ativar sons"</string>
-    <string name="live_caption_title" msgid="7926591158657997051">"Transcrição Instantânea"</string>
+    <string name="live_caption_title" msgid="7926591158657997051">"Legenda Instantânea"</string>
     <string name="live_caption_summary" msgid="9064771862352393125">"Transcrição automática"</string>
     <string name="zen_mode_settings_summary_off" msgid="6929319200478424962">"Nunca"</string>
     <plurals name="zen_mode_settings_summary_on" formatted="false" msgid="6061723291126091396">
@@ -3228,7 +3233,7 @@
     <string name="zen_mode_button_turn_on" msgid="1097964136225943415">"Ativar agora"</string>
     <string name="zen_mode_button_turn_off" msgid="3990967728457149454">"Desativar agora"</string>
     <string name="zen_mode_settings_dnd_manual_end_time" msgid="4307574188962071429">"O modo \"Não perturbe\" fica ativado até <xliff:g id="FORMATTED_TIME">%s</xliff:g>"</string>
-    <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"O modo Não perturbe ficará ativado até que você o desative"</string>
+    <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"O modo \"Não perturbe\" ficará ativado até que você o desative"</string>
     <string name="zen_mode_settings_dnd_automatic_rule" msgid="2843297614114625408">"O \"Não perturbe\" foi ativado automaticamente por uma programação (<xliff:g id="RULE_NAME">%s</xliff:g>)"</string>
     <string name="zen_mode_settings_dnd_automatic_rule_app" msgid="5103454923160912313">"O modo \"Não perturbe\" foi ativado automaticamente por um app (<xliff:g id="APP_NAME">%s</xliff:g>)"</string>
     <string name="zen_mode_settings_dnd_custom_settings_footer" msgid="6335108298640066560">"O \"Não perturbe\" está ativado para <xliff:g id="RULE_NAMES">%s</xliff:g> com configurações personalizadas."</string>
@@ -3418,7 +3423,7 @@
     <string name="notification_badge_title" msgid="8989086619255666442">"Permitir ponto de notificação"</string>
     <string name="notification_channel_badge_title" msgid="8228215248332054612">"Mostrar ponto de notificação"</string>
     <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"Ignorar o Não perturbe"</string>
-    <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"Permitir que essas notificações sejam mostradas mesmo quando o Não perturbe estiver ativado"</string>
+    <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"Permitir que as notificações sejam mostradas mesmo quando o Não perturbe estiver ativado"</string>
     <string name="app_notification_visibility_override_title" msgid="2349335170165637672">"Na tela de bloqueio"</string>
     <string name="app_notification_row_banned" msgid="2079325338122151677">"Bloqueadas"</string>
     <string name="app_notification_row_priority" msgid="432299064888787236">"Prioridade"</string>
@@ -3706,7 +3711,7 @@
     <string name="high_power_off" msgid="5906679734326490426">"Utilização otimizada da bateria"</string>
     <string name="high_power_system" msgid="739584574711292753">"A otimização de bateria não está disponível"</string>
     <string name="high_power_desc" msgid="333756885680362741">"Não aplicar a otimização de bateria. Isso pode esgotar sua bateria mais rapidamente."</string>
-    <string name="high_power_prompt_title" msgid="2805745781720454052">"Permitir que o app sempre esteja em execução em segundo plano?"</string>
+    <string name="high_power_prompt_title" msgid="2805745781720454052">"Permitir execução contínua do app em segundo plano?"</string>
     <string name="high_power_prompt_body" msgid="8067395096053552289">"A execução contínua do app <xliff:g id="APP_NAME">%1$s</xliff:g> em segundo plano pode reduzir a duração da bateria. \n\nVocê poderá alterar essa opção mais tarde em \"Configurar\" &gt; \"Apps e notificações\"."</string>
     <string name="battery_summary" msgid="4345690800899981339">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> de uso desde a última carga completa"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"Gerenciamento de energia"</string>
@@ -3959,8 +3964,8 @@
     <string name="configure" msgid="8232696842838580549">"Configurar"</string>
     <string name="data_usage_other_apps" msgid="7002491980141402084">"Outros apps inclusos no uso"</string>
     <plurals name="data_saver_unrestricted_summary" formatted="false" msgid="6046013861315713697">
-      <item quantity="one"><xliff:g id="COUNT">%1$d</xliff:g> app autorizado a usar dados irrestritos quando a Economia de dados estiver ativada</item>
-      <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> apps autorizados a usar dados irrestritos quando a Economia de dados estiver ativada</item>
+      <item quantity="one"><xliff:g id="COUNT">%1$d</xliff:g> app autorizado a usar dados ilimitados quando a Economia de dados estiver ativada</item>
+      <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> apps autorizados a usar dados ilimitados quando a Economia de dados estiver ativada</item>
     </plurals>
     <string name="data_usage_title" msgid="7874606430902201083">"Dados primários"</string>
     <string name="data_usage_wifi_title" msgid="7161828479387766556">"Dados Wi‑Fi"</string>
@@ -3981,12 +3986,12 @@
     <string name="launch_mdp_app_text" msgid="9186559496664208252">"Ver plano"</string>
     <string name="launch_wifi_text" msgid="317820210431682605">"Ver detalhes"</string>
     <string name="data_saver_title" msgid="7903308134514179256">"Economia de dados"</string>
-    <string name="unrestricted_data_saver" msgid="9139401849550738720">"Dados irrestritos"</string>
+    <string name="unrestricted_data_saver" msgid="9139401849550738720">"Dados ilimitados"</string>
     <string name="restrict_background_blacklisted" msgid="7158991683849067124">"Os dados em segundo plano estão desativados"</string>
     <string name="data_saver_on" msgid="7281809065420480881">"Ativada"</string>
     <string name="data_saver_off" msgid="7439439787358504018">"Desativada"</string>
     <string name="data_saver_switch_title" msgid="8244008132112735207">"Usar o recurso Economia de dados"</string>
-    <string name="unrestricted_app_title" msgid="4390661122069905122">"Uso irrestrito de dados"</string>
+    <string name="unrestricted_app_title" msgid="4390661122069905122">"Uso ilimitado de dados"</string>
     <string name="unrestricted_app_summary" msgid="2829141815077800483">"Permitir acesso irrestrito a dados quando a Economia de dados estiver ativada"</string>
     <string name="home_app" msgid="3695063566006954160">"App de início"</string>
     <string name="no_default_home" msgid="1518949210961918497">"Nenhuma Página inicial padrão"</string>
@@ -4049,8 +4054,8 @@
     <string name="overlay_toast_failed_to_apply" msgid="5692251825129250040">"Falha ao aplicar sobreposição"</string>
     <string name="special_access" msgid="1453926335914696206">"Acesso especial a apps"</string>
     <plurals name="special_access_summary" formatted="false" msgid="5182092345063909346">
-      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> app pode usar dados irrestritos</item>
-      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> apps podem usar dados irrestritos</item>
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> app pode usar dados ilimitados</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> apps podem usar dados ilimitados</item>
     </plurals>
     <string name="special_access_more" msgid="7086690625048471400">"Ver mais"</string>
     <string name="confirm_convert_to_fbe_warning" msgid="4972595831034280189">"Quer mesmo limpar dados do usuário e converter em criptografia de arquivos?"</string>
@@ -4126,7 +4131,7 @@
     <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"Para verificar a hora, as notificações e outras informações, pegue o smartphone."</string>
     <string name="ambient_display_pickup_summary" product="tablet" msgid="1077745287100012928">"Para verificar a hora, as notificações e outras informações, pegue o tablet."</string>
     <string name="ambient_display_pickup_summary" product="device" msgid="404199660076598026">"Para verificar a hora, as notificações e outras informações, pegue o dispositivo."</string>
-    <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"Tocar para verificar o smartphone"</string>
+    <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"Tocar na tela para verificar smartphone"</string>
     <string name="ambient_display_tap_screen_title" product="tablet" msgid="6434521782016864148">"Tocar para verificar o tablet"</string>
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"Tocar para verificar o dispositivo"</string>
     <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"Para verificar a hora, as notificações e outras informações, toque na tela."</string>
@@ -4145,7 +4150,7 @@
     <string name="oem_lock_info_message" msgid="5090850412279403901">"Reinicie o dispositivo para ativar o recurso de proteção para dispositivo."</string>
     <string name="automatic_storage_manager_freed_bytes" msgid="7360443072390107772">"Total de <xliff:g id="SIZE">%1$s</xliff:g> disponibilizado\n\nÚltima execução em <xliff:g id="DATE">%2$s</xliff:g>"</string>
     <string name="web_action_enable_title" msgid="4462106633708675959">"Apps instantâneos"</string>
-    <string name="web_action_enable_summary" msgid="1729016644691793085">"Abrir links em apps, mesmo que eles não estejam instalados"</string>
+    <string name="web_action_enable_summary" msgid="1729016644691793085">"Abre links de apps, mesmo que eles não estejam instalados"</string>
     <string name="web_action_section_title" msgid="5563229447734734662">"Apps instantâneos"</string>
     <string name="instant_apps_settings" msgid="879003203555847537">"Preferências do Instant Apps"</string>
     <string name="domain_url_section_title" msgid="206403507921518321">"Apps instalados"</string>
@@ -4155,7 +4160,7 @@
     <string name="auto_sync_account_title" msgid="2394463123733529506">"Sincronizar dados automaticamente"</string>
     <string name="auto_sync_personal_account_title" msgid="6844465157916100655">"Sincronizar dados pessoais automaticamente"</string>
     <string name="auto_sync_work_account_title" msgid="2403222633447522376">"Sincronizar dados de trabalho automaticamente"</string>
-    <string name="auto_sync_account_summary" msgid="6316230976974033772">"Permitir que os apps atualizem dados automaticamente"</string>
+    <string name="auto_sync_account_summary" msgid="6316230976974033772">"Permite que os apps atualizem dados automaticamente"</string>
     <string name="account_sync_title" msgid="1570164819114297154">"Sincronização da conta"</string>
     <string name="account_sync_summary_some_on" msgid="1934556869158274053">"Sincronização ativada para <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g> itens"</string>
     <string name="account_sync_summary_all_on" msgid="3634161204232431700">"Sincronização ativada para todos os itens"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ro/arrays.xml b/tests/CarDeveloperOptions/res/values-ro/arrays.xml
index 39d046b..06c74ea 100644
--- a/tests/CarDeveloperOptions/res/values-ro/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-ro/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"rulează în fundal"</item>
     <item msgid="6423861043647911030">"volum accesibilitate"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Locație"</item>
+    <item msgid="6656077694190491067">"Locație"</item>
+    <item msgid="8790228218278477369">"Locație"</item>
+    <item msgid="7836406246005211990">"Vibrare"</item>
+    <item msgid="3951439024549922598">"Citește agenda"</item>
+    <item msgid="8802152411647068">"Modifică agenda"</item>
+    <item msgid="229544934599698735">"Citește jurnalul de apeluri"</item>
+    <item msgid="7396102294405899613">"Modifică jurnalul de apeluri"</item>
+    <item msgid="3597797992398484655">"Citire calendar"</item>
+    <item msgid="2705975774250907343">"Modifică calendarul"</item>
+    <item msgid="4668747371441932697">"Locație"</item>
+    <item msgid="1487578921720243646">"Postează o notificare"</item>
+    <item msgid="4636080349724146638">"Locație"</item>
+    <item msgid="673510900286463926">"Apelează un telefon"</item>
+    <item msgid="542083422784609790">"Citiți mesaje SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Scrieți mesaje SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Primește mesaje SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Primește mesaje SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Primește mesaje SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Primește mesaje SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Trimite mesaje SMS/MMS"</item>
+    <item msgid="4726682243833913568">"Citiți mesaje SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Scrieți mesaje SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Modifică setările"</item>
+    <item msgid="8705854389991425629">"Desenează deasupra"</item>
+    <item msgid="5861356020344153651">"Accesează notificări"</item>
+    <item msgid="78432174621628659">"Cameră foto"</item>
+    <item msgid="3986116419882154794">"Înregistrează conținut audio"</item>
+    <item msgid="4516840825756409490">"Redă conținut audio"</item>
+    <item msgid="6811712502798183957">"Citește clipboardul"</item>
+    <item msgid="2780369012602289114">"Modifică clipboardul"</item>
+    <item msgid="2331359440170850868">"Butoane media"</item>
+    <item msgid="6133599737122751231">"Focalizare audio"</item>
+    <item msgid="6844485713404805301">"Volum principal"</item>
+    <item msgid="1600379420669104929">"Volum voce"</item>
+    <item msgid="6296768210470214866">"Volumul soneriei"</item>
+    <item msgid="510690696071629241">"Volum media"</item>
+    <item msgid="406861638631430109">"Volumul alarmei"</item>
+    <item msgid="4715864795872233884">"Volumul notificărilor"</item>
+    <item msgid="2311478519251301183">"Volum Bluetooth"</item>
+    <item msgid="5133991377896747027">"Păstrare în activitate"</item>
+    <item msgid="2464189519136248621">"Locație"</item>
+    <item msgid="2062677934050803037">"Locație"</item>
+    <item msgid="1735171933192715957">"Obțineți statistici de utilizare"</item>
+    <item msgid="1014093788778383554">"Activați/dezactivați microfonul"</item>
+    <item msgid="4199297950608622850">"Afișează semnalarea"</item>
+    <item msgid="2527962435313398821">"Proiectează conținutul media"</item>
+    <item msgid="5117506254221861929">"Activează serviciul VPN"</item>
+    <item msgid="8291198322681891160">"Scrie imaginea de fundal"</item>
+    <item msgid="7106921284621230961">"Structură de asistență"</item>
+    <item msgid="4496533640894624799">"Captură de ecran de asistență"</item>
+    <item msgid="2598847264853993611">"Citește starea telefonului"</item>
+    <item msgid="9215610846802973353">"Adaugă mesaje vocale"</item>
+    <item msgid="9186411956086478261">"Folosește SIP"</item>
+    <item msgid="6884763100104539558">"Procesează apelul de ieșire"</item>
+    <item msgid="125513972170580692">"Amprentă"</item>
+    <item msgid="2556071024281275619">"Senzori corporali"</item>
+    <item msgid="617168514928339387">"Citește transmisiile celulare"</item>
+    <item msgid="7134693570516523585">"Locație de testare"</item>
+    <item msgid="7224489175375229399">"Citește spațiul de stocare"</item>
+    <item msgid="8472735063903258202">"Scrie spațiul de stocare"</item>
+    <item msgid="4069276819909595110">"Activează ecranul"</item>
+    <item msgid="1228338896751121025">"Preia conturile"</item>
+    <item msgid="3181581793459233672">"Rulează în fundal"</item>
+    <item msgid="2340936043025374076">"Volum accesibilitate"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Scurtă"</item>
     <item msgid="4816511817309094890">"Medie"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Nu permiteți niciodată"</item>
     <item msgid="8184570120217958741">"Permiteți întotdeauna"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normală"</item>
+    <item msgid="5101233285497327432">"Moderată"</item>
+    <item msgid="1555861583162930714">"Scăzută"</item>
+    <item msgid="1719683776264798117">"Critică"</item>
+    <item msgid="1567326459340152525">"Necunoscută"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normală"</item>
+    <item msgid="6107138933849816768">"Moderată"</item>
+    <item msgid="182695359839047859">"Scăzută"</item>
+    <item msgid="8577246509202964244">"Critică"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Permanent"</item>
     <item msgid="167418068739176448">"Activitate principală"</item>
diff --git a/tests/CarDeveloperOptions/res/values-ro/config.xml b/tests/CarDeveloperOptions/res/values-ro/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-ro/config.xml
+++ b/tests/CarDeveloperOptions/res/values-ro/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-ro/strings.xml b/tests/CarDeveloperOptions/res/values-ro/strings.xml
index 721a81a..c91c306 100644
--- a/tests/CarDeveloperOptions/res/values-ro/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ro/strings.xml
@@ -84,8 +84,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Măriți sau micșorați textul de pe ecran."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Micșorați"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Măriți"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Exemplu de text"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Minunatul Vrăjitor din Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Capitolul 11: Minunatul Oraș de Smarald Oz"</string>
@@ -676,7 +675,6 @@
       <item quantity="other">Trebuie să conțină mai puțin de <xliff:g id="NUMBER_1">%d</xliff:g> de cifre</item>
       <item quantity="one">Trebuie să conțină mai puțin de <xliff:g id="NUMBER_0">%d</xliff:g> cifră</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Trebuie să conțină numai cifre de la 0 la 9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Administratorul dispozitivului nu permite utilizarea unui PIN recent"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Codurile PIN sunt blocate de administratorul dvs. IT. Încercați alt cod PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Aceasta nu poate include un caracter nevalid"</string>
@@ -713,6 +711,11 @@
       <item quantity="other">Trebuie să conțină cel puțin <xliff:g id="COUNT">%d</xliff:g> de caractere care să nu fie litere</item>
       <item quantity="one">Trebuie să conțină cel puțin un caracter care să nu fie literă</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="few">Trebuie să conțină cel puțin <xliff:g id="COUNT">%d</xliff:g> caractere care să nu fie cifre</item>
+      <item quantity="other">Trebuie să conțină cel puțin <xliff:g id="COUNT">%d</xliff:g> de caractere care să nu fie cifre</item>
+      <item quantity="one">Trebuie să conțină cel puțin un caracter care să nu fie cifră</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Administratorul dispozitivului nu permite utilizarea unei parole recente"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Parolele obișnuite sunt blocate de administratorul dvs. IT. Încercați altă parolă."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Șirurile de cifre ascendente, descendente sau repetate nu sunt permise"</string>
@@ -1117,7 +1120,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Date mobile"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Dacă rețeaua Wi‑Fi nu este disponibilă, folosiți rețeaua mobilă"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Dacă rețeaua mobilă nu este disponibilă, folosiți Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Apelați prin Wi‑Fi. Dacă pierdeți conexiunea Wi-Fi, apelul se încheie."</string>
@@ -3230,7 +3236,7 @@
     <string name="zen_mode_summary_combination" msgid="6960111215170691605">"<xliff:g id="MODE">%1$s</xliff:g>: <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
     <string name="zen_mode_visual_interruptions_settings_title" msgid="8378266552787406849">"Blocați întreruperile vizuale"</string>
     <string name="zen_mode_visual_signals_settings_subtitle" msgid="6608239691864638854">"Permiteți semnale vizuale"</string>
-    <string name="zen_mode_settings_category" msgid="5601680733422424922">"Când funcția „Nu deranja” este activată"</string>
+    <string name="zen_mode_settings_category" msgid="5601680733422424922">"Când modul Nu deranja este activat"</string>
     <string name="zen_mode_restrict_notifications_title" msgid="7486753018073540477">"Restricționați notificările"</string>
     <string name="zen_mode_restrict_notifications_mute" msgid="2673665450311184875">"Fără sunet de la notificări"</string>
     <string name="zen_mode_restrict_notifications_mute_summary" msgid="1696217042353376674">"Veți vedea notificările pe ecran"</string>
@@ -3269,7 +3275,7 @@
     <string name="zen_mode_button_turn_on" msgid="1097964136225943415">"Activați acum"</string>
     <string name="zen_mode_button_turn_off" msgid="3990967728457149454">"Dezactivați acum"</string>
     <string name="zen_mode_settings_dnd_manual_end_time" msgid="4307574188962071429">"Funcția Nu deranja este activată până la <xliff:g id="FORMATTED_TIME">%s</xliff:g>"</string>
-    <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"Funcția Nu deranja rămâne activă până când o dezactivați"</string>
+    <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"Modul Nu deranja rămâne activ până îl dezactivați"</string>
     <string name="zen_mode_settings_dnd_automatic_rule" msgid="2843297614114625408">"Modul Nu deranja a fost activat automat de un program (<xliff:g id="RULE_NAME">%s</xliff:g>)"</string>
     <string name="zen_mode_settings_dnd_automatic_rule_app" msgid="5103454923160912313">"Funcția Nu deranja a fost activată automat de o aplicație (<xliff:g id="APP_NAME">%s</xliff:g>)"</string>
     <string name="zen_mode_settings_dnd_custom_settings_footer" msgid="6335108298640066560">"Modul Nu deranja este activat pentru <xliff:g id="RULE_NAMES">%s</xliff:g> cu setări personalizate."</string>
@@ -3552,7 +3558,7 @@
     <string name="zen_mode_reminders_list" msgid="7347061314032326677">"mementouri"</string>
     <string name="zen_mode_events" msgid="5784076928339534984">"Permiteți evenimente"</string>
     <string name="zen_mode_bypassing_apps" msgid="3080739479028713449">"Permiteți aplicațiilor să ignore"</string>
-    <string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"Excepțiile aplicației"</string>
+    <string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"Excepții de aplicații"</string>
     <plurals name="zen_mode_bypassing_apps_subtext" formatted="false" msgid="8723144434730871572">
       <item quantity="few">Notificările de la <xliff:g id="NUMBER">%1$d</xliff:g> aplicații pot modifica modul Nu deranja</item>
       <item quantity="other">Notificările de la <xliff:g id="NUMBER">%1$d</xliff:g> de aplicații pot modifica modul Nu deranja</item>
@@ -3680,7 +3686,7 @@
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> permisiune suplimentară</item>
     </plurals>
     <string name="runtime_permissions_summary_no_permissions_granted" msgid="3477934429220828771">"Nicio permisiune acordată"</string>
-    <string name="runtime_permissions_summary_no_permissions_requested" msgid="3901636077467389637">"Nicio permisiunea solicitată"</string>
+    <string name="runtime_permissions_summary_no_permissions_requested" msgid="3901636077467389637">"Nicio permisiune solicitată"</string>
     <string name="filter_all_apps" msgid="4042756539846043675">"Toate aplicațiile"</string>
     <string name="filter_enabled_apps" msgid="5888459261768538489">"Aplicații instalate"</string>
     <string name="filter_instant_apps" msgid="8087483282854072366">"Aplicații instantanee"</string>
@@ -3764,8 +3770,8 @@
     <string name="high_power_off" msgid="5906679734326490426">"Se optimizează utilizarea bateriei"</string>
     <string name="high_power_system" msgid="739584574711292753">"Optimizarea bateriei nu este disponibilă"</string>
     <string name="high_power_desc" msgid="333756885680362741">"Nu aplicați optimizarea bateriei. Bateria se poate descărca mai rapid."</string>
-    <string name="high_power_prompt_title" msgid="2805745781720454052">"Permiteți aplicației să ruleze continuu în fundal?"</string>
-    <string name="high_power_prompt_body" msgid="8067395096053552289">"Dacă permiteți aplicației <xliff:g id="APP_NAME">%1$s</xliff:g> să ruleze continuu în fundal, autonomia bateriei poate scădea. \n\nPuteți modifica opțiunea ulterior din Setări &gt; Aplicații și notificări."</string>
+    <string name="high_power_prompt_title" msgid="2805745781720454052">"Permiteți aplicației să ruleze încontinuu în fundal?"</string>
+    <string name="high_power_prompt_body" msgid="8067395096053552289">"Dacă permiteți aplicației <xliff:g id="APP_NAME">%1$s</xliff:g> să ruleze încontinuu în fundal, autonomia bateriei poate scădea. \n\nPuteți modifica opțiunea ulterior din Setări &gt; Aplicații și notificări."</string>
     <string name="battery_summary" msgid="4345690800899981339">"Utilizare de la ultima încărcare completă: <xliff:g id="PERCENTAGE">%1$s</xliff:g>"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"Gestionarea consumului de energie"</string>
     <string name="no_battery_summary" msgid="4105932628367471314">"Bateria nu a fost folosită de la ultima încărcare completă"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ru/arrays.xml b/tests/CarDeveloperOptions/res/values-ru/arrays.xml
index 8993349..6565854 100644
--- a/tests/CarDeveloperOptions/res/values-ru/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-ru/arrays.xml
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"Не разрешать"</item>
     <item msgid="8184570120217958741">"Разрешать всегда"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Нормальное"</item>
+    <item msgid="5101233285497327432">"Пока хватает"</item>
+    <item msgid="1555861583162930714">"Низкая"</item>
+    <item msgid="1719683776264798117">"Высокое"</item>
+    <item msgid="1567326459340152525">"Неизвестно"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Нормальное"</item>
+    <item msgid="6107138933849816768">"Умеренное"</item>
+    <item msgid="182695359839047859">"Низкая"</item>
+    <item msgid="8577246509202964244">"Критическое"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Стабильное"</item>
     <item msgid="167418068739176448">"Наиболее частое действие"</item>
diff --git a/tests/CarDeveloperOptions/res/values-ru/config.xml b/tests/CarDeveloperOptions/res/values-ru/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-ru/config.xml
+++ b/tests/CarDeveloperOptions/res/values-ru/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-ru/strings.xml b/tests/CarDeveloperOptions/res/values-ru/strings.xml
index 817026d..50e4d34 100644
--- a/tests/CarDeveloperOptions/res/values-ru/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ru/strings.xml
@@ -85,8 +85,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Сделайте текст на экране мельче или крупнее."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Уменьшить"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Увеличить"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Принесите мне, пожалуйста, чашку кофе."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Пример текста"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Удивительный волшебник из страны Оз"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Глава 11. Изумрудный город страны Оз"</string>
@@ -497,7 +496,7 @@
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"Мимо! Это не сканер отпечатков пальцев..."</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"Найдите сканер на задней панели и коснитесь его указательным пальцем."</string>
     <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"Отпечаток не добавлен"</string>
-    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Превышен срок ожидания. Повторите попытку"</string>
+    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Превышен срок ожидания. Повторите попытку."</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"Не удалось добавить отпечаток. Повторите попытку или попробуйте сохранить отпечаток другого пальца."</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"Добавить ещё"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"Далее"</string>
@@ -684,7 +683,6 @@
       <item quantity="many">PIN-код должен содержать менее <xliff:g id="NUMBER_1">%d</xliff:g> цифр</item>
       <item quantity="other">PIN-код должен содержать менее <xliff:g id="NUMBER_1">%d</xliff:g> цифры</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"PIN-код должен содержать только цифры"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Использовать недавний PIN-код запрещено"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"ИТ-администратор заблокировал простые PIN-коды. Выберите более сложную комбинацию."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Недопустимые символы"</string>
@@ -727,6 +725,12 @@
       <item quantity="many">Используйте как минимум <xliff:g id="COUNT">%d</xliff:g> небуквенных символов</item>
       <item quantity="other">Используйте как минимум <xliff:g id="COUNT">%d</xliff:g> небуквенного символа</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">Пароль должен содержать как минимум <xliff:g id="COUNT">%d</xliff:g> нечисловой символ.</item>
+      <item quantity="few">Пароль должен содержать как минимум <xliff:g id="COUNT">%d</xliff:g> нечисловых символа.</item>
+      <item quantity="many">Пароль должен содержать как минимум <xliff:g id="COUNT">%d</xliff:g> нечисловых символов.</item>
+      <item quantity="other">Пароль должен содержать как минимум <xliff:g id="COUNT">%d</xliff:g> нечислового символа.</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Использовать недавний пароль запрещено"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"ИТ-администратор заблокировал простые пароли. Выберите более сложную комбинацию."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Нельзя использовать последовательности из идущих подряд или повторяющихся цифр"</string>
@@ -891,7 +895,7 @@
     <string name="use_open_wifi_automatically_summary_scoring_disabled" msgid="1559329344492373028">"Чтобы использовать эту функцию, выберите источник рейтинга сетей"</string>
     <string name="use_open_wifi_automatically_summary_scorer_unsupported_disabled" msgid="1123080670578756834">"Чтобы использовать эту функцию, выберите поддерживаемый источник рейтинга сетей"</string>
     <string name="wifi_install_credentials" msgid="5650088113710858289">"Установка сертификатов"</string>
-    <string name="wifi_scan_notify_text" msgid="7614101215028336927">"Чтобы точнее определять ваше местонахождение, сервисы и приложения могут искать доступные беспроводные сети, даже когда Wi-Fi отключен. Этот режим позволяет улучшить работу функций, связанных с геолокацией. Отключить его можно в разделе <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>настроек поиска сетей Wi-Fi<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
+    <string name="wifi_scan_notify_text" msgid="7614101215028336927">"Чтобы точнее определять ваше местонахождение, сервисы и приложения могут искать доступные беспроводные сети, даже когда Wi-Fi отключен. Этот режим позволяет улучшить работу функций, связанных с геолокацией. Отключить его можно в <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>настройках поиска сетей Wi-Fi<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
     <string name="wifi_scan_notify_text_scanning_off" msgid="723796963816095410">"Чтобы повысить точность определения местоположения, включите поиск сетей Wi-Fi в <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>настройках<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
     <string name="wifi_scan_notify_remember_choice" msgid="1235445971400237444">"Больше не показывать"</string>
     <string name="wifi_setting_sleep_policy_title" msgid="2120785188625932076">"Wi-Fi в спящем режиме"</string>
@@ -950,7 +954,7 @@
     <string name="wifi_eap_domain" msgid="3298302320003640130">"Домен"</string>
     <string name="wifi_eap_user_cert" msgid="6786839531765719173">"Сертификат пользователя"</string>
     <string name="wifi_eap_identity" msgid="5280457017705738773">"Пользователь"</string>
-    <string name="wifi_eap_anonymous" msgid="6352344972490839958">"Неизвестный"</string>
+    <string name="wifi_eap_anonymous" msgid="6352344972490839958">"Анонимный пользователь"</string>
     <string name="wifi_password" msgid="6942983531275177771">"Пароль"</string>
     <string name="wifi_show_password" msgid="7878398590772942202">"Показать пароль"</string>
     <string name="wifi_ap_band_config" msgid="6565016368079288433">"Диапазон частот Wi-Fi"</string>
@@ -985,7 +989,7 @@
     <string name="wifi_dpp_wifi_shared_with_device" msgid="5713765471758272471">"Устройство подключено к Wi‑Fi"</string>
     <string name="wifi_dpp_add_another_device" msgid="3698441567235301565">"Подключить другое устройство"</string>
     <string name="wifi_dpp_choose_different_network" msgid="128515107488187050">"Выбрать другую сеть Wi-Fi"</string>
-    <string name="wifi_dpp_could_not_add_device" msgid="4966109556543584813">"Не удалось добавить устройство."</string>
+    <string name="wifi_dpp_could_not_add_device" msgid="4966109556543584813">"Не удалось добавить устройство"</string>
     <string name="wifi_dpp_device_found" msgid="6488461467496850841">"Устройство найдено"</string>
     <string name="wifi_dpp_sharing_wifi_with_this_device" msgid="2540529164687476827">"Предоставление доступа к сети Wi‑Fi…"</string>
     <string name="wifi_dpp_connecting" msgid="4229290407210299897">"Подключение…"</string>
@@ -1134,7 +1138,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Мобильный Интернет"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Использовать мобильную сеть, если сеть Wi‑Fi недоступна."</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Использовать Wi‑Fi, если мобильная сеть недоступна."</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Звонки по Wi‑Fi. Если подключение прервется, звонок будет завершен."</string>
@@ -1239,8 +1246,8 @@
     <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"Отключено"</string>
     <string name="adaptive_sleep_description" msgid="812673735459170009">"Экран не будет отключаться, если вы смотрите на него."</string>
     <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Когда адаптивный спящий режим включен, устройство использует фронтальную камеру, чтобы отслеживать, смотрит ли кто-то на экран. Эта функция работает только на вашем устройстве: собранные данные не сохраняются и не отправляются в Google."</string>
-    <string name="night_display_title" msgid="1305002424893349814">"Ночной режим"</string>
-    <string name="night_display_text" msgid="5330502493684652527">"В ночном режиме экран приобретает желтоватый оттенок. Это снижает напряжение глаз при тусклом свете и может помочь вам быстрее заснуть."</string>
+    <string name="night_display_title" msgid="1305002424893349814">"Ночная подсветка"</string>
+    <string name="night_display_text" msgid="5330502493684652527">"С ночной подсветкой экран приобретает желтоватый оттенок. Это снижает напряжение глаз при тусклом свете и может помочь вам быстрее заснуть."</string>
     <string name="night_display_auto_mode_title" msgid="8493573087102481588">"Расписание"</string>
     <string name="night_display_auto_mode_never" msgid="2897444637217807088">"Нет"</string>
     <string name="night_display_auto_mode_custom" msgid="1400891076453963151">"В выбранное время"</string>
@@ -1263,7 +1270,7 @@
     <string name="night_display_activation_off_twilight" msgid="6846727701281556110">"Отключить до заката"</string>
     <string name="night_display_activation_on_custom" msgid="4761140206778957611">"Включить до <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="night_display_activation_off_custom" msgid="4207238846687792731">"Отключить до <xliff:g id="ID_1">%1$s</xliff:g>"</string>
-    <string name="night_display_not_currently_on" msgid="1436588493764429281">"Ночной режим сейчас выключен"</string>
+    <string name="night_display_not_currently_on" msgid="1436588493764429281">"Ночная подсветка сейчас выключена"</string>
     <string name="screen_timeout" msgid="1700950247634525588">"Спящий режим"</string>
     <string name="screen_timeout_title" msgid="150117777762864112">"Отключение экрана"</string>
     <string name="screen_timeout_summary" msgid="8644192861778491060">"После <xliff:g id="TIMEOUT_DESCRIPTION">%1$s</xliff:g> бездействия"</string>
@@ -1278,7 +1285,7 @@
     <string name="screensaver_settings_summary_either_long" msgid="6078038506795498288">"Во время зарядки или при подключении к док-станции"</string>
     <string name="screensaver_settings_summary_either_short" msgid="2453772128682850053">"Всегда"</string>
     <string name="screensaver_settings_summary_sleep" msgid="6097363596749362692">"Во время зарядки"</string>
-    <string name="screensaver_settings_summary_dock" msgid="6297808146601570196">"В док-станции"</string>
+    <string name="screensaver_settings_summary_dock" msgid="6297808146601570196">"На док-станции"</string>
     <string name="screensaver_settings_summary_never" msgid="3995259444981620707">"Никогда"</string>
     <string name="screensaver_settings_summary_off" msgid="6119947316484763131">"Отключено"</string>
     <string name="screensaver_settings_disabled_prompt" msgid="1897518064782596947">"Чтобы настроить поведение телефона при подключении к док-станции и в спящем режиме, включите заставку."</string>
@@ -1344,7 +1351,7 @@
     <string name="security_patch" msgid="483709031051932208">"Последнее обновление системы безопасности"</string>
     <string name="model_info" msgid="1729765474260797594">"Модель"</string>
     <string name="model_summary" msgid="8781425868254352168">"Модель: %1$s"</string>
-    <string name="hardware_info" msgid="174270144950621815">"Модель и оборудование"</string>
+    <string name="hardware_info" msgid="174270144950621815">"Модель и аппаратное обеспечение"</string>
     <string name="hardware_revision" msgid="3315744162524354246">"Версия аппаратного обеспечения"</string>
     <string name="fcc_equipment_id" msgid="8681995718533066093">"Идентификатор оборудования"</string>
     <string name="baseband_version" msgid="9115560821840757786">"Прошивка модуля связи"</string>
@@ -1728,7 +1735,7 @@
     <string name="terms_title" msgid="1804549588198223771">"Условия использования"</string>
     <string name="webview_license_title" msgid="8244960025549725051">"Системная лицензия WebView"</string>
     <string name="wallpaper_attributions" msgid="2941987966332943253">"Обои"</string>
-    <string name="wallpaper_attributions_values" msgid="4461979853894606323">"Спутниковые фотографии:\n© CNES 2014/Astrium, DigitalGlobe, Bluesky"</string>
+    <string name="wallpaper_attributions_values" msgid="4461979853894606323">"Спутниковые фотографии:\n© 2014 CNES/Astrium, DigitalGlobe, Bluesky"</string>
     <string name="settings_manual_activity_title" msgid="7599911755054286789">"Руководство пользователя"</string>
     <string name="settings_manual_activity_unavailable" msgid="4872502775018655343">"Не удалось загрузить руководство пользователя."</string>
     <string name="settings_license_activity_title" msgid="1099045216283677608">"Лицензии третьих сторон"</string>
@@ -1769,7 +1776,7 @@
     <string name="lockpassword_strong_auth_required_device_pin" msgid="24030584350601016">"Введите PIN-код"</string>
     <string name="lockpassword_strong_auth_required_device_password" msgid="7746588206458754598">"Введите пароль устройства"</string>
     <string name="lockpassword_strong_auth_required_work_pattern" msgid="6861154706098327320">"Укажите графический ключ от рабочего профиля"</string>
-    <string name="lockpassword_strong_auth_required_work_pin" msgid="6306902249365524526">"Введите PIN-код рабочего профиля"</string>
+    <string name="lockpassword_strong_auth_required_work_pin" msgid="6306902249365524526">"Для дополнительной защиты введите PIN-код рабочего профиля."</string>
     <string name="lockpassword_strong_auth_required_work_password" msgid="2917338218971012776">"Введите пароль от рабочего профиля"</string>
     <string name="lockpassword_confirm_your_pattern_details_frp" msgid="1085862410379709928">"Настройки вашего телефона были сброшены. Чтобы использовать его, введите свой прежний графический ключ."</string>
     <string name="lockpassword_confirm_your_pin_details_frp" msgid="6849889353126558761">"Настройки вашего телефона были сброшены. Чтобы использовать его, введите свой прежний PIN-код."</string>
@@ -1786,7 +1793,7 @@
     <string name="lockpattern_recording_intro_header" msgid="2262005028838969839">"Начертите ключ разблокировки"</string>
     <string name="lockpattern_recording_intro_footer" msgid="5426745740754065099">"Для справки нажмите \"Меню\"."</string>
     <string name="lockpattern_recording_inprogress" msgid="4060818382176523671">"По завершении отпустите палец"</string>
-    <string name="lockpattern_recording_incorrect_too_short" msgid="6374760294545431845">"Соедините не менее <xliff:g id="NUMBER">%d</xliff:g> точек"</string>
+    <string name="lockpattern_recording_incorrect_too_short" msgid="6374760294545431845">"Соедините не менее <xliff:g id="NUMBER">%d</xliff:g> точек."</string>
     <string name="lockpattern_pattern_entered_header" msgid="2108106638322637851">"Графический ключ сохранен"</string>
     <string name="lockpattern_need_to_confirm" msgid="4079482507985867389">"Начертите ключ ещё раз"</string>
     <string name="lockpattern_pattern_confirmed_header" msgid="5603156929428721407">"Ваш новый ключ разблокировки"</string>
@@ -2335,7 +2342,7 @@
     <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Телефон используется больше, чем обычно"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"Планшет используется больше, чем обычно"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"Устройство используется больше, чем обычно"</string>
-    <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"Заряд батареи расходуется быстрее, чем обычно."</string>
+    <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"Заряд батареи расходуется быстрее, чем обычно"</string>
     <string name="battery_tip_dialog_message" product="default" msgid="8453700079047810964">"Телефон используется больше, чем обычно. Батарея скоро разрядится.\n\nС момента последней зарядки активнее всего использовались следующие приложения с высоким потреблением энергии:"</string>
     <string name="battery_tip_dialog_message" product="tablet" msgid="6489981050645444068">"Планшет используется больше, чем обычно. Батарея скоро разрядится.\n\nС момента последней зарядки активнее всего использовались следующие приложения с высоким потреблением энергии:"</string>
     <string name="battery_tip_dialog_message" product="device" msgid="6348123094674390337">"Устройство используется больше, чем обычно. Батарея скоро разрядится.\n\nС момента последней зарядки активнее всего использовались следующие приложения с высоким потреблением энергии:"</string>
@@ -2518,7 +2525,7 @@
     <string name="battery_saver_auto_percentage" msgid="5791982309331921556">"С учетом уровня заряда"</string>
     <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"Включать, если высока вероятность, что уровня заряда не хватит до подзарядки"</string>
     <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"Включать при уровне заряда <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
-    <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"Создать расписание"</string>
+    <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"Задать расписание"</string>
     <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"Выключать при полном заряде"</string>
     <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"Режим энергосбережения отключается, когда уровень заряда достигает <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <string name="battery_saver_sticky_description_new" product="tablet" msgid="3284967694001857194">"Режим энергосбережения отключается, когда уровень заряда достигает <xliff:g id="PERCENT">%1$s</xliff:g>."</string>
@@ -2636,8 +2643,8 @@
     <string name="remove_and_uninstall_device_admin" msgid="5607703579731496253">"Отключить и удалить"</string>
     <string name="select_device_admin_msg" msgid="4173769638399075387">"Приложения администратора"</string>
     <string name="no_device_admins" msgid="4129231900385977460">"Нет доступных приложений администратора устройства"</string>
-    <string name="personal_device_admin_title" msgid="759440849188565661">"Личный"</string>
-    <string name="managed_device_admin_title" msgid="8021522755492551726">"Рабочий"</string>
+    <string name="personal_device_admin_title" msgid="759440849188565661">"Личные"</string>
+    <string name="managed_device_admin_title" msgid="8021522755492551726">"Рабочие"</string>
     <string name="sms_access_restriction_enabled" msgid="3006320256764718303">"Ограничение доступа к SMS и списку вызовов"</string>
     <string name="sms_access_restriction_enabled_summary" msgid="9011946580977780063">"Доступ к SMS и списку вызовов есть только у приложений для звонков и обмена сообщениями, используемых по умолчанию"</string>
     <string name="no_trust_agents" msgid="5757792915019113084">"Нет агентов доверия."</string>
@@ -3656,7 +3663,7 @@
     <string name="screen_pinning_unlock_pattern" msgid="1060334707088339444">"Запрашивать графический ключ"</string>
     <string name="screen_pinning_unlock_pin" msgid="1441705536015645023">"Запрашивать PIN-код"</string>
     <string name="screen_pinning_unlock_password" msgid="1017776884000170841">"Запрашивать пароль"</string>
-    <string name="screen_pinning_unlock_none" msgid="9183040569733226911">"Блокировать устройство при откл. блокировки в приложении"</string>
+    <string name="screen_pinning_unlock_none" msgid="9183040569733226911">"Блокировать устройство при отключении функции"</string>
     <string name="opening_paragraph_delete_profile_unknown_company" msgid="2350380017136403670">"Профилем управляет"</string>
     <string name="managing_admin" msgid="3212584016377581608">"Управляется <xliff:g id="ADMIN_APP_LABEL">%s</xliff:g>"</string>
     <string name="experimental_preference" msgid="5903223408406906322">"(экспериментальная настройка)"</string>
@@ -3826,7 +3833,7 @@
     <string name="high_power_prompt_body" msgid="8067395096053552289">"Если приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" сможет запускаться в фоновом режиме, это увеличит расход заряда батареи.\n\nЭту функцию можно отключить, открыв Настройки &gt; Приложения и уведомления."</string>
     <string name="battery_summary" msgid="4345690800899981339">"Использовано с момента последней полной зарядки: <xliff:g id="PERCENTAGE">%1$s</xliff:g>"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"Управление питанием"</string>
-    <string name="no_battery_summary" msgid="4105932628367471314">"Батарея с момента последней полной зарядки не расходовалась"</string>
+    <string name="no_battery_summary" msgid="4105932628367471314">"С момента последней полной зарядки батарея не использовалась"</string>
     <string name="app_notification_preferences" msgid="5154466638524523201">"Настройки приложения"</string>
     <string name="system_ui_settings" msgid="6751165163665775447">"Показать SystemUI Tuner"</string>
     <string name="additional_permissions" msgid="3142290772324571654">"Ещё разрешения"</string>
@@ -3898,7 +3905,7 @@
     </plurals>
     <string name="running_frequency" msgid="7545170806968474449">"Как часто используется"</string>
     <string name="memory_maximum_usage" msgid="4734981118293469479">"Макс. памяти использовано"</string>
-    <string name="no_data_usage" msgid="903383745620135746">"Нет использованного трафика"</string>
+    <string name="no_data_usage" msgid="903383745620135746">"Трафик не расходовался"</string>
     <string name="zen_access_warning_dialog_title" msgid="7704910289810337055">"Разрешить приложению \"<xliff:g id="APP">%1$s</xliff:g>\" доступ к настройкам режима \"Не беспокоить\"?"</string>
     <string name="zen_access_warning_dialog_summary" msgid="2717755746850874577">"Приложение сможет включать и отключать режим \"Не беспокоить\", а также изменять соответствующие настройки."</string>
     <string name="zen_access_disabled_package_warning" msgid="7086237569177576966">"Должно быть включено, поскольку разрешен доступ к уведомлениям"</string>
@@ -3960,7 +3967,7 @@
     <string name="screen_zoom_conversation_timestamp_2" msgid="816265985618121370">"Вт, 18:01"</string>
     <string name="screen_zoom_conversation_timestamp_3" msgid="7346540212221792932">"Вт, 18:02"</string>
     <string name="screen_zoom_conversation_timestamp_4" msgid="1452374487089625022">"Вт, 18:03"</string>
-    <string name="disconnected" msgid="4088439352761747084">"Нет подключения"</string>
+    <string name="disconnected" msgid="4088439352761747084">"Не подключено"</string>
     <string name="keyboard_disconnected" msgid="3068615097201531871">"Не подключено"</string>
     <string name="data_usage_summary_format" msgid="7788095271598602797">"Использовано трафика: <xliff:g id="AMOUNT">%1$s</xliff:g>"</string>
     <string name="data_usage_wifi_format" msgid="9028934101966264710">"<xliff:g id="AMOUNT">^1</xliff:g> передано через Wi‑Fi"</string>
@@ -4021,9 +4028,9 @@
     <string name="condition_device_muted_summary" msgid="3101055117680109021">"Для звонков и уведомлений"</string>
     <string name="condition_device_vibrate_title" msgid="5712659354868872338">"Только вибрация"</string>
     <string name="condition_device_vibrate_summary" msgid="9073880731894828604">"Для звонков и уведомлений"</string>
-    <string name="night_display_suggestion_title" msgid="4222839610992282188">"Расписание ночного режима"</string>
+    <string name="night_display_suggestion_title" msgid="4222839610992282188">"Расписание ночной подсветки"</string>
     <string name="night_display_suggestion_summary" msgid="1754361016383576916">"Автоматически изменять оттенок экрана по вечерам."</string>
-    <string name="condition_night_display_title" msgid="9171491784857160135">"Ночной режим включен"</string>
+    <string name="condition_night_display_title" msgid="9171491784857160135">"Ночная подсветка включена"</string>
     <string name="condition_night_display_summary" msgid="7885776986937527558">"Экран имеет желтый оттенок"</string>
     <string name="condition_grayscale_title" msgid="1226351649203551299">"Оттенки серого"</string>
     <string name="condition_grayscale_summary" msgid="749172886527349546">"Показывать только в серых тонах"</string>
@@ -4179,10 +4186,10 @@
     <string name="overlay_toast_failed_to_apply" msgid="5692251825129250040">"Не удалось применить наложение"</string>
     <string name="special_access" msgid="1453926335914696206">"Специальный доступ"</string>
     <plurals name="special_access_summary" formatted="false" msgid="5182092345063909346">
-      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> приложение без ограничений мобильного Интернета</item>
-      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> приложения без ограничений мобильного Интернета</item>
-      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> приложений без ограничений мобильного Интернета</item>
-      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> приложения без ограничений мобильного Интернета</item>
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> приложение без ограничений на мобильный Интернет</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> приложения без ограничений на мобильный Интернет</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> приложений без ограничений на мобильный Интернет</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> приложения без ограничений на мобильный Интернет</item>
     </plurals>
     <string name="special_access_more" msgid="7086690625048471400">"Ещё"</string>
     <string name="confirm_convert_to_fbe_warning" msgid="4972595831034280189">"Удалить пользовательские данные и перейти к шифрованию?"</string>
@@ -4628,7 +4635,7 @@
     <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"Удалить эту подсказку?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"Подсказка удалена."</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"Отменить"</string>
-    <string name="low_storage_summary" msgid="4562224870189133400">"В хранилище заканчивается пространство. Занято: <xliff:g id="PERCENTAGE">%1$s</xliff:g>, свободно: <xliff:g id="FREE_SPACE">%2$s</xliff:g>."</string>
+    <string name="low_storage_summary" msgid="4562224870189133400">"В хранилище заканчивается место. Занято: <xliff:g id="PERCENTAGE">%1$s</xliff:g>, свободно: <xliff:g id="FREE_SPACE">%2$s</xliff:g>."</string>
     <string name="contextual_card_feedback_send" msgid="8698649023854350623">"Отправить отзыв"</string>
     <string name="contextual_card_feedback_confirm_message" msgid="3987973028353264878">"Поделитесь мнением об этой подсказке."</string>
     <string name="copyable_slice_toast" msgid="1357518174923789947">"Контент (<xliff:g id="COPY_CONTENT">%1$s</xliff:g>) скопирован в буфер обмена"</string>
diff --git a/tests/CarDeveloperOptions/res/values-si/arrays.xml b/tests/CarDeveloperOptions/res/values-si/arrays.xml
index e348b4c..c845711 100644
--- a/tests/CarDeveloperOptions/res/values-si/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-si/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"පසුබිමෙහි ධාවනය"</item>
     <item msgid="6423861043647911030">"ප්‍රවේශ්‍යතා හඬ පරිමාව"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"ස්ථානය"</item>
+    <item msgid="6656077694190491067">"ස්ථානය"</item>
+    <item msgid="8790228218278477369">"ස්ථානය"</item>
+    <item msgid="7836406246005211990">"කම්පනය වීම"</item>
+    <item msgid="3951439024549922598">"සම්බන්ධතා කියවන්න"</item>
+    <item msgid="8802152411647068">"සම්බන්ධතා වෙනස් කරන්න"</item>
+    <item msgid="229544934599698735">"ඇමතුම් ලොගය කියවන්න"</item>
+    <item msgid="7396102294405899613">"ඇමතුම් ලොගය වෙනස් කරන්න"</item>
+    <item msgid="3597797992398484655">"දින දර්ශනය කියවන්න"</item>
+    <item msgid="2705975774250907343">"දින දර්ශනය වෙනස් කරන්න"</item>
+    <item msgid="4668747371441932697">"ස්ථානය"</item>
+    <item msgid="1487578921720243646">"පසු දැනුම්දීම"</item>
+    <item msgid="4636080349724146638">"ස්ථානය"</item>
+    <item msgid="673510900286463926">"දුරකතනය අමතන්න"</item>
+    <item msgid="542083422784609790">"SMS/MMS කියවන්න"</item>
+    <item msgid="1033780373029588436">"SMS/MMS ලියන්න"</item>
+    <item msgid="5647111115517787488">"SMS/MMS ලැබීම"</item>
+    <item msgid="8591105601108455893">"SMS/MMS ලැබීම"</item>
+    <item msgid="7730995008517841903">"SMS/MMS ලැබීම"</item>
+    <item msgid="2613033109026626086">"SMS/MMS ලැබීම"</item>
+    <item msgid="3037159047591081136">"SMS/MMS යවන්න"</item>
+    <item msgid="4726682243833913568">"SMS/MMS කියවන්න"</item>
+    <item msgid="6555678522277865572">"SMS/MMS ලියන්න"</item>
+    <item msgid="6981734935578130884">"සැකසුම් වෙනස් කරන්න"</item>
+    <item msgid="8705854389991425629">"උඩ අඳින්න"</item>
+    <item msgid="5861356020344153651">"ප්‍රවේශ දැනුම්දීම්"</item>
+    <item msgid="78432174621628659">"කැමරාව"</item>
+    <item msgid="3986116419882154794">"ශ්‍රව්‍ය තැටිගත කරන්න"</item>
+    <item msgid="4516840825756409490">"ශ්‍රව්‍ය ධාවනය කරන්න"</item>
+    <item msgid="6811712502798183957">"පසුරු පුවරුව කියවන්න"</item>
+    <item msgid="2780369012602289114">"පසුරු පුවරුව වෙනස්කරන්න"</item>
+    <item msgid="2331359440170850868">"මාධ්‍ය බොත්තම"</item>
+    <item msgid="6133599737122751231">"ශ්‍රව්‍ය අවධානය"</item>
+    <item msgid="6844485713404805301">"උසස් ශබ්දය"</item>
+    <item msgid="1600379420669104929">"හඬ ශබ්දය"</item>
+    <item msgid="6296768210470214866">"නාද ශබ්දය"</item>
+    <item msgid="510690696071629241">"මාධ්‍ය ශබ්දය"</item>
+    <item msgid="406861638631430109">"සීනුවේ ශබ්දය"</item>
+    <item msgid="4715864795872233884">"දැනුම්දීමේ ශබ්ද ත්‍රීවතාව"</item>
+    <item msgid="2311478519251301183">"බ්ලූටූත් ශබ්දය"</item>
+    <item msgid="5133991377896747027">"අවදිව සිටින්න"</item>
+    <item msgid="2464189519136248621">"ස්ථානය"</item>
+    <item msgid="2062677934050803037">"ස්ථානය"</item>
+    <item msgid="1735171933192715957">"භාවිත කිරීමේ තත්ත්ව ලබාගන්න"</item>
+    <item msgid="1014093788778383554">"මයික්‍රෝෆෝනය නිශ්ශබ්ද/නිශ්ශබ්ද නැති කරන්න"</item>
+    <item msgid="4199297950608622850">"ටෝස්ට් පෙන්වීම"</item>
+    <item msgid="2527962435313398821">"මාධ්‍ය ව්‍යාපෘතිය"</item>
+    <item msgid="5117506254221861929">"VPN සක්‍රිය කරන්න"</item>
+    <item msgid="8291198322681891160">"වෝල්පේපරය ලියන්න"</item>
+    <item msgid="7106921284621230961">"ව්‍යුහයට සහාය"</item>
+    <item msgid="4496533640894624799">"තිර රුවට සහාය"</item>
+    <item msgid="2598847264853993611">"දුරකථන තත්ත්වය කියවීම"</item>
+    <item msgid="9215610846802973353">"හඬ තැපෑල එක් කිරීම"</item>
+    <item msgid="9186411956086478261">"SIP භාවිතය"</item>
+    <item msgid="6884763100104539558">"පිටතට යන ඇමතුම් ක්‍රියාවලිය"</item>
+    <item msgid="125513972170580692">"ඇඟිලි සලකුණ"</item>
+    <item msgid="2556071024281275619">"ශරීර සංවේදක"</item>
+    <item msgid="617168514928339387">"සෙල් විකාශන කියවීම"</item>
+    <item msgid="7134693570516523585">"ව්‍යාජ ස්ථාන"</item>
+    <item msgid="7224489175375229399">"ගබඩාව කියවීම"</item>
+    <item msgid="8472735063903258202">"ගබඩාව ලිවීම"</item>
+    <item msgid="4069276819909595110">"තිරය ක්‍රියාත්මක කිරීම"</item>
+    <item msgid="1228338896751121025">"ගිණුම් ලබා ගැනීම"</item>
+    <item msgid="3181581793459233672">"පසුබිමෙහි ධාවනය"</item>
+    <item msgid="2340936043025374076">"ප්‍රවේශ්‍යතා හඬ පරිමාව"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"කොට"</item>
     <item msgid="4816511817309094890">"මධ්‍යම"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"කිසිවිටෙකත් අවසර නොදෙන්න"</item>
     <item msgid="8184570120217958741">"සැමවිටම ඉඩ දෙන්න"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"සාමාන්‍ය"</item>
+    <item msgid="5101233285497327432">"මධ්‍යම"</item>
+    <item msgid="1555861583162930714">"අඩු"</item>
+    <item msgid="1719683776264798117">"අවදානම්"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"සාමාන්‍ය"</item>
+    <item msgid="6107138933849816768">"මධ්‍යම"</item>
+    <item msgid="182695359839047859">"අඩු"</item>
+    <item msgid="8577246509202964244">"අවදානම්"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"ස්ථාවර"</item>
     <item msgid="167418068739176448">"උඩම ක්‍රියාකාරකම"</item>
diff --git a/tests/CarDeveloperOptions/res/values-si/config.xml b/tests/CarDeveloperOptions/res/values-si/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-si/config.xml
+++ b/tests/CarDeveloperOptions/res/values-si/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-si/strings.xml b/tests/CarDeveloperOptions/res/values-si/strings.xml
index 21e056c..1861fb5 100644
--- a/tests/CarDeveloperOptions/res/values-si/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-si/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"තිරය මත පෙළ වඩාත් කුඩා හෝ විශාල කරන්න."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"වඩා කුඩා කරන්න"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"වඩා විශාල කරන්න"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"ආදර්ශ පෙළ"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"The Wonderful Wizard of Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"11වන පරිච්ඡේදය: The Wonderful Emerald City of Oz"</string>
@@ -378,7 +377,7 @@
     <string name="location_settings_loading_app_permission_stats" msgid="7818169326621327628">"පූරණය වේ…"</string>
     <string name="account_settings_title" msgid="7870321267198486578">"ගිණුම්"</string>
     <string name="security_settings_title" msgid="8228075165942416425">"ආරක්ෂාව"</string>
-    <string name="encryption_and_credential_settings_title" msgid="6911729638397745353">"සංකේතනය සහ අක්තපත්‍ර"</string>
+    <string name="encryption_and_credential_settings_title" msgid="6911729638397745353">"සංකේතනය, අක්තපත්‍ර"</string>
     <string name="encryption_and_credential_settings_summary" product="default" msgid="468749700109808546">"දුරකතනය සංකේතනය කර ඇත"</string>
     <string name="decryption_settings_summary" product="default" msgid="7401802133199522441">"දුරකතනය සංකේතනය කර නැත"</string>
     <string name="encryption_and_credential_settings_summary" product="tablet" msgid="8170667308598998791">"උපාංගය සංකේතිතයි"</string>
@@ -668,7 +667,6 @@
       <item quantity="one">ඉලක්කම් <xliff:g id="NUMBER_1">%d</xliff:g>කට වඩා අඩු විය යුතුය</item>
       <item quantity="other">ඉලක්කම් <xliff:g id="NUMBER_1">%d</xliff:g>කට වඩා අඩු විය යුතුය</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"0-9 දක්වා ඉලක්කම් පමණක් අඩංගු විය යුතුය"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"උපාංග පරිපාලක මෑත PIN එකක් භාවිතා කිරීමට අවසර නොදේ"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"ඔබගේ IT පරිපාලක විසින් සුලබ PIN අවහිර කරනු ලැබේ. වෙනත් PIN එකක් උත්සාහ කරන්න."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"මෙහි වලංගු නොවන අනුලකුණක් ඇතුළත් විය නොහැකිය"</string>
@@ -699,6 +697,10 @@
       <item quantity="one">අඩු තරමින් අකුරු නොවන අනුලකුණු <xliff:g id="COUNT">%d</xliff:g>ක් අඩංගු විය යුතුය</item>
       <item quantity="other">අඩු තරමින් අකුරු නොවන අනුලකුණු <xliff:g id="COUNT">%d</xliff:g>ක් අඩංගු විය යුතුය</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">අඩු තරමින් සංඛ්‍යාත්මක-නොවන අනුලකුණු <xliff:g id="COUNT">%d</xliff:g>ක් අඩංගු විය යුතුය</item>
+      <item quantity="other">අඩු තරමින් සංඛ්‍යාත්මක-නොවන අනුලකුණු <xliff:g id="COUNT">%d</xliff:g>ක් අඩංගු විය යුතුය</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"උපාංග පරිපාලක මෑත මුරපදයක් භාවිතා කිරීමට අවසර නොදේ."</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"ඔබගේ IT පරිපාලක විසින් සුලබ මුරපද අවහිර කරනු ලැබේ. වෙනත් මුරපදයක් උත්සාහ කරන්න."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"ආරෝහණ, අවරෝහණ හෝ ප්‍රනරාවර්ත අනුක්‍රමයේ අංක වෙත අවසර නැත"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"ජංගම"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Wi‑Fi නොලැබේ නම්, ජංගම ජාලය භාවිත කරන්න"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"ජංගම ජාලය නොලැබේ නම්, Wi-Fi භාවිත කරන්න"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Wi‑Fi ඔස්සේ ඇමතුම. Wi‑Fi අහිමි වූයේ නම්, ඇමතුම අවසන් වෙයි."</string>
@@ -2571,7 +2576,7 @@
     <string name="sms_access_restriction_enabled" msgid="3006320256764718303">"SMS සහ ඇමතුම් ලොග ප්‍රවේශය සීමා කරන්න"</string>
     <string name="sms_access_restriction_enabled_summary" msgid="9011946580977780063">"පෙරනිමි දුරකථන සහ පණිවිඩකරණ යෙදුම්වලට පමණක් SMS සහ ඇමතුම් ලොග අවසර ඇත"</string>
     <string name="no_trust_agents" msgid="5757792915019113084">"විශ්වාසනීය ඒජන්තවරුන් නැත"</string>
-    <string name="add_device_admin_msg" msgid="3573765823476931173">"උපාංගය පරිපාලක යෙදුම සක්‍රිය කරන්නද?"</string>
+    <string name="add_device_admin_msg" msgid="3573765823476931173">"උපාංග පරිපාලක යෙදුම සක්‍රිය කර.?"</string>
     <string name="add_device_admin" msgid="1621152410207260584">"මෙම උපාංගය පරිපාලක යෙදුම සක්‍රිය කරන්න"</string>
     <string name="device_admin_add_title" msgid="6097881332139146897">"උපාංග පරිපාලක"</string>
     <string name="device_admin_warning" msgid="4421817419326480449">"මෙම පරිපාලකයා සක්‍රිය කිරීමෙන් <xliff:g id="APP_NAME">%1$s</xliff:g> යෙදුමට පහත ක්‍රියාවන් සිදුකිරීමට අවස්තාව ලබාදේ:"</string>
diff --git a/tests/CarDeveloperOptions/res/values-sk/arrays.xml b/tests/CarDeveloperOptions/res/values-sk/arrays.xml
index fb66e63..2789ee1 100644
--- a/tests/CarDeveloperOptions/res/values-sk/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-sk/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"spustenie na pozadí"</item>
     <item msgid="6423861043647911030">"objem aplikácií dostupnosti"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Poloha"</item>
+    <item msgid="6656077694190491067">"Poloha"</item>
+    <item msgid="8790228218278477369">"Poloha"</item>
+    <item msgid="7836406246005211990">"Vibrovanie"</item>
+    <item msgid="3951439024549922598">"Čítanie kontaktov"</item>
+    <item msgid="8802152411647068">"Úprava kontaktov"</item>
+    <item msgid="229544934599698735">"Čítanie denníka hovorov"</item>
+    <item msgid="7396102294405899613">"Úprava denníka hovorov"</item>
+    <item msgid="3597797992398484655">"Čítanie kalendára"</item>
+    <item msgid="2705975774250907343">"Úprava kalendára"</item>
+    <item msgid="4668747371441932697">"Poloha"</item>
+    <item msgid="1487578921720243646">"Upozornenie na príspevok"</item>
+    <item msgid="4636080349724146638">"Poloha"</item>
+    <item msgid="673510900286463926">"Volanie na telefón"</item>
+    <item msgid="542083422784609790">"Čítanie SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Písanie SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Príjem SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Príjem SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Príjem SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Príjem SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Odosielanie SMS/MMS"</item>
+    <item msgid="4726682243833913568">"Čítanie SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Písanie SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Úprava nastavení"</item>
+    <item msgid="8705854389991425629">"Vykreslenie navrch"</item>
+    <item msgid="5861356020344153651">"Prístup k upozorneniam"</item>
+    <item msgid="78432174621628659">"Fotoaparát"</item>
+    <item msgid="3986116419882154794">"Nahrávať zvuk"</item>
+    <item msgid="4516840825756409490">"Prehrať zvuk"</item>
+    <item msgid="6811712502798183957">"Načítať schránku"</item>
+    <item msgid="2780369012602289114">"Upraviť schránku"</item>
+    <item msgid="2331359440170850868">"Tlačidlá médií"</item>
+    <item msgid="6133599737122751231">"Zameranie zvuku"</item>
+    <item msgid="6844485713404805301">"Hlavná hlasitosť"</item>
+    <item msgid="1600379420669104929">"Hlasitosť hlasu"</item>
+    <item msgid="6296768210470214866">"Hlasitosť zvonenia"</item>
+    <item msgid="510690696071629241">"Hlasitosť médií"</item>
+    <item msgid="406861638631430109">"Hlasitosť budíkov"</item>
+    <item msgid="4715864795872233884">"Hlasitosť upozornení"</item>
+    <item msgid="2311478519251301183">"Hlasitosť zariadenia Bluetooth"</item>
+    <item msgid="5133991377896747027">"Zakázať režim spánku"</item>
+    <item msgid="2464189519136248621">"Umiestnenie"</item>
+    <item msgid="2062677934050803037">"Poloha"</item>
+    <item msgid="1735171933192715957">"Získanie štatistiky využívania"</item>
+    <item msgid="1014093788778383554">"Stlmenie alebo zrušenie stlmenia mikrofónu"</item>
+    <item msgid="4199297950608622850">"Zobrazenie oznamu"</item>
+    <item msgid="2527962435313398821">"Projekcia médií"</item>
+    <item msgid="5117506254221861929">"Aktivácia VPN"</item>
+    <item msgid="8291198322681891160">"Zápis tapety"</item>
+    <item msgid="7106921284621230961">"Asistujúca štruktúra"</item>
+    <item msgid="4496533640894624799">"Asistujúca snímka obrazovky"</item>
+    <item msgid="2598847264853993611">"Čítanie stavu telefónu"</item>
+    <item msgid="9215610846802973353">"Pridanie hlasovej schránky"</item>
+    <item msgid="9186411956086478261">"Používanie volania SIP"</item>
+    <item msgid="6884763100104539558">"Spracovanie odchádzajúcich hovorov"</item>
+    <item msgid="125513972170580692">"Odtlačok prsta"</item>
+    <item msgid="2556071024281275619">"Telesné senzory"</item>
+    <item msgid="617168514928339387">"Čítať správy informačných služieb"</item>
+    <item msgid="7134693570516523585">"Napodobnenie miesta"</item>
+    <item msgid="7224489175375229399">"Čítanie úložiska"</item>
+    <item msgid="8472735063903258202">"Zápis do úložiska"</item>
+    <item msgid="4069276819909595110">"Zapnutie obrazovky"</item>
+    <item msgid="1228338896751121025">"Získanie účtov"</item>
+    <item msgid="3181581793459233672">"Spustenie na pozadí"</item>
+    <item msgid="2340936043025374076">"Objem aplikácií dostupnosti"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Krátke"</item>
     <item msgid="4816511817309094890">"Stredná"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Nikdy nepovoliť"</item>
     <item msgid="8184570120217958741">"Vždy povoliť"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normálne"</item>
+    <item msgid="5101233285497327432">"Stredný"</item>
+    <item msgid="1555861583162930714">"Nízka"</item>
+    <item msgid="1719683776264798117">"Kritický"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normálny"</item>
+    <item msgid="6107138933849816768">"Stredný"</item>
+    <item msgid="182695359839047859">"Nízka"</item>
+    <item msgid="8577246509202964244">"Kritické"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Pretrvávajúci"</item>
     <item msgid="167418068739176448">"Najčastejšia aktivita"</item>
@@ -401,8 +477,8 @@
     <item msgid="1008268820118852416">"Považovať za nemeranú sieť"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
-    <item msgid="6545683814310036454">"Používať randomizovanú adresu MAC (predvolené)"</item>
-    <item msgid="214234417308375326">"Použiť adresu MAC zariadenia"</item>
+    <item msgid="6545683814310036454">"Použiť náhodnú MAC (predvolené)"</item>
+    <item msgid="214234417308375326">"Používať adresu MAC zariadenia"</item>
   </string-array>
   <string-array name="wifi_hidden_entries">
     <item msgid="7426878022650940844">"Nie"</item>
diff --git a/tests/CarDeveloperOptions/res/values-sk/config.xml b/tests/CarDeveloperOptions/res/values-sk/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-sk/config.xml
+++ b/tests/CarDeveloperOptions/res/values-sk/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-sk/strings.xml b/tests/CarDeveloperOptions/res/values-sk/strings.xml
index 8b68658..6787582 100644
--- a/tests/CarDeveloperOptions/res/values-sk/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-sk/strings.xml
@@ -85,8 +85,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Zväčšite alebo zmenšite text na obrazovke."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Zmenšiť"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Zväčšiť"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Ukážkový text"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Čarodejník z krajiny Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"11. kapitola: Nádherné smaragdové mesto"</string>
@@ -455,8 +454,8 @@
     <string name="security_settings_fingerprint_enroll_introduction_continue" msgid="271662150372486535">"Pokračovať"</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel_setup" msgid="756928427429893070">"Preskočiť"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue_setup" msgid="4125977169169671144">"Ďalej"</string>
-    <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"Preskočiť odtlačok prsta?"</string>
-    <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"Nastavenie odtlačku prsta trvá približne minútu. Ak tento krok preskočíte, môžete si odtlačok prsta pridať neskôr v Nastaveniach."</string>
+    <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"Preskočiť nastavenie odtlačku prsta?"</string>
+    <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"Nastavenie odtlačku prsta trvá asi minútu. Ak tento krok preskočíte, môžete si odtlačok prsta pridať neskôr v nastaveniach."</string>
     <string name="lock_screen_intro_skip_title" msgid="5307431665496346914">"Preskočiť zámku obrazovky?"</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="tablet" msgid="7553945981266845264">"Funkcie ochrany zariadenia sa nezapnú. V prípade straty, krádeže alebo obnovenia nebudete môcť cudzím osobám zabrániť v používaní tohto tabletu."</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="device" msgid="1378243257238015603">"Funkcie ochrany zariadenia sa nezapnú. V prípade straty, krádeže alebo obnovenia nebudete môcť cudzím osobám zabrániť v používaní tohto zariadenia."</string>
@@ -644,7 +643,7 @@
     <string name="unlock_footer_medium_complexity_requested" msgid="5004825329461874633">"<xliff:g id="APP_NAME">%1$s</xliff:g> odporúča nový kód PIN alebo heslo, bez ktorého nemusí fungovať podľa očakávaní"</string>
     <string name="unlock_footer_low_complexity_requested" msgid="513212093196833566">"<xliff:g id="APP_NAME">%1$s</xliff:g> odporúča nový vzor, PIN alebo heslo, bez ktorého nemusí fungovať podľa očakávaní"</string>
     <string name="unlock_footer_none_complexity_requested" msgid="1669550050597044896">"<xliff:g id="APP_NAME">%1$s</xliff:g> odporúča nová zámku obrazovky"</string>
-    <string name="lock_failed_attempts_before_wipe" msgid="7565412834122130877">"Skúste to znova. Pokus <xliff:g id="CURRENT_ATTEMPTS">%1$d</xliff:g> z <xliff:g id="TOTAL_ATTEMPTS">%2$d</xliff:g>."</string>
+    <string name="lock_failed_attempts_before_wipe" msgid="7565412834122130877">"Skúste to znova. <xliff:g id="CURRENT_ATTEMPTS">%1$d</xliff:g>. z <xliff:g id="TOTAL_ATTEMPTS">%2$d</xliff:g> pokusov."</string>
     <string name="lock_last_attempt_before_wipe_warning_title" msgid="7853820095898368793">"Vaše dáta budú odstránené"</string>
     <string name="lock_last_pattern_attempt_before_wipe_device" msgid="1021644947949306054">"Ak pri ďalšom pokuse zadáte nesprávny vzor, dáta tohto zariadenia budú odstránené"</string>
     <string name="lock_last_pin_attempt_before_wipe_device" msgid="3823600293847594141">"Ak pri ďalšom pokuse zadáte nesprávny kód PIN, dáta tohto zariadenia budú odstránené"</string>
@@ -653,7 +652,7 @@
     <string name="lock_last_pin_attempt_before_wipe_user" msgid="7833852187363499906">"Ak pri ďalšom pokuse zadáte nesprávny kód PIN, tento používateľ bude odstránený"</string>
     <string name="lock_last_password_attempt_before_wipe_user" msgid="8979742220140001204">"Ak pri ďalšom pokuse zadáte nesprávne heslo, tento používateľ bude odstránený"</string>
     <string name="lock_last_pattern_attempt_before_wipe_profile" msgid="3877613047631174576">"Ak pri ďalšom pokuse zadáte nesprávny vzor, váš pracovný profil a jeho dáta budú odstránené"</string>
-    <string name="lock_last_pin_attempt_before_wipe_profile" msgid="8132438288175428168">"Ak pri ďalšom pokuse zadáte nesprávny kód PIN, váš pracovný profil a jeho dáta budú odstránené."</string>
+    <string name="lock_last_pin_attempt_before_wipe_profile" msgid="8132438288175428168">"Ak pri ďalšom pokuse zadáte nesprávny PIN, váš pracovný profil a jeho dáta budú odstránené"</string>
     <string name="lock_last_password_attempt_before_wipe_profile" msgid="1535128774464384305">"Ak pri ďalšom pokuse zadáte nesprávne heslo, váš pracovný profil a jeho dáta budú odstránené"</string>
     <string name="lock_failed_attempts_now_wiping_device" msgid="8662360098784762828">"Príliš veľa chybných pokusov. Dáta tohto zariadenia budú odstránené."</string>
     <string name="lock_failed_attempts_now_wiping_user" msgid="3793513796171561873">"Príliš veľa chybných pokusov. Tento používateľ bude odstránený."</string>
@@ -684,7 +683,6 @@
       <item quantity="other">Musí mať menej ako <xliff:g id="NUMBER_1">%d</xliff:g> číslic</item>
       <item quantity="one">Musí mať menej ako <xliff:g id="NUMBER_0">%d</xliff:g> číslicu</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Musí obsahovať len číslice 0 až 9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Správca zariadenia neumožňuje používať nedávny kód PIN"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Bežné kódy PIN zablokoval váš správca IT. Skúste iný PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Musí obsahovať iba platné znaky"</string>
@@ -727,6 +725,12 @@
       <item quantity="other">Musí obsahovať aspoň <xliff:g id="COUNT">%d</xliff:g> znakov, ktoré nie sú písmená</item>
       <item quantity="one">Musí obsahovať aspoň 1 znak, ktorý nie je písmeno</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="few">Musí obsahovať aspoň <xliff:g id="COUNT">%d</xliff:g> znaky, ktoré nie sú písmená</item>
+      <item quantity="many">Must contain at least <xliff:g id="COUNT">%d</xliff:g> non-numerical characters</item>
+      <item quantity="other">Musí obsahovať aspoň <xliff:g id="COUNT">%d</xliff:g> znakov, ktoré nie sú písmená</item>
+      <item quantity="one">Musí obsahovať aspoň jeden znak, ktorý nie je písmeno</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Správca zariadenia neumožňuje používať nedávne heslo"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Bežné heslá zablokoval váš správca IT. Skúste iné heslo."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Vzostupná, zostupná alebo opakovaná sekvencia čísiel nie je povolená"</string>
@@ -762,7 +766,7 @@
     <string name="bluetooth_pairing_request" msgid="7221745525632573125">"Spárovať so zariadením <xliff:g id="DEVICE_NAME">%1$s</xliff:g>?"</string>
     <string name="bluetooth_pairing_key_msg" msgid="1139230917419961975">"Párovací kód Bluetooth"</string>
     <string name="bluetooth_enter_passkey_msg" msgid="6205151011298670207">"Zadajte párovací kód a potom stlačte tlačidlo Return alebo Enter"</string>
-    <string name="bluetooth_enable_alphanumeric_pin" msgid="9138308197078115672">"Kód PIN obsahuje písmená alebo symboly"</string>
+    <string name="bluetooth_enable_alphanumeric_pin" msgid="9138308197078115672">"PIN obsahuje písmená či symboly"</string>
     <string name="bluetooth_pin_values_hint" msgid="8044671726261326240">"Obvykle 0000 alebo 1234"</string>
     <string name="bluetooth_pin_values_hint_16_digits" msgid="2665983525706661525">"Musí obsahovať 16 číslic"</string>
     <string name="bluetooth_enter_pin_other_device" msgid="1727015949040507621">"Tento kód PIN bude možno treba zadať aj na druhom zariadení."</string>
@@ -938,14 +942,14 @@
     <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Ak váš smerovač nevysiela ID určitej siete, ale chcete sa k nej pripojiť v budúcnosti, môžete ju nastaviť ako skrytú.\n\nMôže tým vzniknúť bezpečnostné riziko, pretože váš telefón bude pravidelne vysielať signál, aby sieť našiel.\n\nNastavením danej siete ako skrytej nezmeníte nastavenia smerovača."</string>
     <string name="wifi_signal" msgid="696548364467704808">"Sila signálu"</string>
     <string name="wifi_status" msgid="3439931558930689940">"Stav"</string>
-    <string name="tx_wifi_speed" msgid="2571810085003261073">"Rýchlosť prenosu dát"</string>
-    <string name="rx_wifi_speed" msgid="7392873246110937187">"Rýchlosť pripojenia (prijímanie)"</string>
+    <string name="tx_wifi_speed" msgid="2571810085003261073">"Rýchlosť posielania dát"</string>
+    <string name="rx_wifi_speed" msgid="7392873246110937187">"Rýchlosť prijímania dát"</string>
     <string name="wifi_frequency" msgid="6132852924995724246">"Frekvencia"</string>
     <string name="wifi_ip_address" msgid="5572539114989914831">"Adresa IP"</string>
     <string name="passpoint_label" msgid="7429247462404128615">"Uložené prostredníctvom siete"</string>
     <string name="passpoint_content" msgid="340527524510304327">"Poverenia: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_eap_method" msgid="3752116941487485859">"Metóda EAP"</string>
-    <string name="please_select_phase2" msgid="5848080896810435677">"Overenie – 2. fáza"</string>
+    <string name="please_select_phase2" msgid="5848080896810435677">"Druhá fáza overenia"</string>
     <string name="wifi_eap_ca_cert" msgid="1496395241849383785">"Certifikát CA"</string>
     <string name="wifi_eap_domain" msgid="3298302320003640130">"Doména"</string>
     <string name="wifi_eap_user_cert" msgid="6786839531765719173">"Certifikát používateľa"</string>
@@ -969,20 +973,20 @@
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"Skenovanie QR kódu"</string>
     <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"Ak sa chcete pripojiť k sieti <xliff:g id="SSID">%1$s</xliff:g>, vycentrujte QR kód nižšie"</string>
     <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"Pripojte sa k sieti Wi‑Fi naskenovaním QR kódu"</string>
-    <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Zdieľanie Wi‑Fi"</string>
+    <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Zdieľať Wi‑Fi"</string>
     <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"Ak sa chcete pripojiť k sieti <xliff:g id="SSID">%1$s</xliff:g> a zdieľať heslo, naskenujte tento QR kód"</string>
     <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"Ak sa chcete pripojiť k sieti <xliff:g id="SSID">%1$s</xliff:g>, naskenujte tento QR kód"</string>
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"QR kód sa nepodarilo prečítať. Opätovne ho vycentrujte a skúste to znova."</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"Skúste to znova. Ak problém pretrváva, kontaktujte výrobcu zariadenia."</string>
     <string name="wifi_dpp_failure_not_compatible" msgid="4320027179973678283">"Vyskytol sa problém"</string>
-    <string name="wifi_dpp_failure_timeout" msgid="5060065168142109420">"Uistite, sa či je zariadenie zapojené do zásuvky, nabité a zapnuté"</string>
-    <string name="wifi_dpp_failure_generic" msgid="7840142544736640189">"Uistite, sa či je zariadenie zapojené do zásuvky, nabité a zapnuté. Ak problém pretrváva, kontaktujte výrobcu zariadenia."</string>
+    <string name="wifi_dpp_failure_timeout" msgid="5060065168142109420">"Skontrolujte, či je zariadenie zapojené, nabité a zapnuté"</string>
+    <string name="wifi_dpp_failure_generic" msgid="7840142544736640189">"Skontrolujte, či je zariadenie zapojené, nabité a zapnuté. Ak problém pretrváva, kontaktujte výrobcu zariadenia."</string>
     <string name="wifi_dpp_failure_not_supported" msgid="111779621766171626">"Toto zariadenie nepodporuje pridanie siete <xliff:g id="SSID">%1$s</xliff:g>"</string>
     <string name="wifi_dpp_check_connection_try_again" msgid="7144663015219170999">"Skontrolujte pripojenie a skúste to znova"</string>
     <string name="wifi_dpp_choose_network" msgid="6251424431594491691">"Výber siete"</string>
     <string name="wifi_dpp_choose_network_to_connect_device" msgid="6385259857886784285">"Ak chcete pripojiť svoje zariadenie, vyberte sieť"</string>
     <string name="wifi_dpp_add_device_to_wifi" msgid="6454198064645462446">"Pridať toto zariadenie do siete <xliff:g id="SSID">%1$s</xliff:g>?"</string>
-    <string name="wifi_dpp_wifi_shared_with_device" msgid="5713765471758272471">"So zariadením bola zdieľaná sieť Wi‑Fi"</string>
+    <string name="wifi_dpp_wifi_shared_with_device" msgid="5713765471758272471">"Wi‑Fi sa zdieľa so zariadením"</string>
     <string name="wifi_dpp_add_another_device" msgid="3698441567235301565">"Pridať ďalšie zariadenie"</string>
     <string name="wifi_dpp_choose_different_network" msgid="128515107488187050">"Vybrať inú sieť"</string>
     <string name="wifi_dpp_could_not_add_device" msgid="4966109556543584813">"Zariadenie sa nepodarilo pridať"</string>
@@ -1098,10 +1102,10 @@
     <string name="wifi_hotspot_name_summary_connecting" msgid="5176787959408511889">"Zapína sa hotspot <xliff:g id="WIFI_HOTSPOT_NAME">%1$s</xliff:g>…"</string>
     <string name="wifi_hotspot_name_summary_connected" msgid="8387768642326756749">"Iné zariadenia sa môžu pripojiť k hotspotu <xliff:g id="WIFI_HOTSPOT_NAME">%1$s</xliff:g>"</string>
     <string name="wifi_hotspot_password_title" msgid="4289338152595154889">"Heslo hotspotu"</string>
-    <string name="wifi_hotspot_ap_band_title" msgid="3485744480410441949">"Pásmo pre prístupový bod"</string>
+    <string name="wifi_hotspot_ap_band_title" msgid="3485744480410441949">"Pásmo prístup. bodu"</string>
     <string name="wifi_hotspot_footer_info_regular" msgid="3876006922622827363">"Použite hotspot na vytvorenie siete Wi‑Fi pre ostatné zariadenia. Hotspot poskytuje internet pomocou mobilného dátového pripojenia. Môžu vám byť účtované ďalšie poplatky za mobilné dáta."</string>
     <string name="wifi_hotspot_footer_info_local_only" msgid="3339582350894639261">"Aplikácie tiež môžu vytvoriť hostpot na zdieľanie obsahu so zariadeniami v okolí."</string>
-    <string name="wifi_hotspot_auto_off_title" msgid="7416022590415189590">"Automatické vypínanie hotspotu"</string>
+    <string name="wifi_hotspot_auto_off_title" msgid="7416022590415189590">"Hotspot automaticky vypínať"</string>
     <string name="wifi_hotspot_auto_off_summary" msgid="3866769400624802105">"Ak nebudú pripojené žiadne zariadenia, hotspot Wi‑Fi sa vypne"</string>
     <string name="wifi_tether_starting" msgid="7676952148471297900">"Prebieha zapínanie hotspotu..."</string>
     <string name="wifi_tether_stopping" msgid="7478561853791953349">"Prebieha vypínanie hotspotu..."</string>
@@ -1134,7 +1138,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi‑Fi"</item>
+    <item msgid="2271962426654621656">"Mobilné dáta"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"V prípade nedostupnosti siete Wi‑Fi použiť mobilnú sieť"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"V prípade nedostupnosti mobilnej siete použiť Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Volanie cez Wi‑Fi. Keď sa Wi‑Fi preruší, hovor sa ukončí."</string>
@@ -1244,7 +1251,7 @@
     <string name="night_display_auto_mode_title" msgid="8493573087102481588">"Časový plán"</string>
     <string name="night_display_auto_mode_never" msgid="2897444637217807088">"Nikdy"</string>
     <string name="night_display_auto_mode_custom" msgid="1400891076453963151">"Zapnuté vo vybranom čase"</string>
-    <string name="night_display_auto_mode_twilight" msgid="4000162110017520674">"Zapnuté od západu do východu slnka"</string>
+    <string name="night_display_auto_mode_twilight" msgid="4000162110017520674">"Od západu do východu slnka"</string>
     <string name="night_display_start_time_title" msgid="1069255169673371077">"Čas začatia"</string>
     <string name="night_display_end_time_title" msgid="2760793157124245911">"Čas ukončenia"</string>
     <string name="night_display_status_title" msgid="1727020934735770319">"Stav"</string>
@@ -1327,7 +1334,7 @@
     <string name="sim_multi_sims_summary" msgid="8237021982527032257">"Vyberte preferovanú SIM kartu na mobilné dáta."</string>
     <string name="sim_change_data_title" msgid="2512227368681250054">"Používať <xliff:g id="CARRIER">%1$s</xliff:g> na mobilné dáta?"</string>
     <string name="sim_change_data_message" msgid="51004703157782900">"Používate mobilné dáta od operátora <xliff:g id="CARRIER2_0">%2$s</xliff:g>. Ak prepnete na <xliff:g id="CARRIER1">%1$s</xliff:g>, <xliff:g id="CARRIER2_1">%2$s</xliff:g> sa už nebude používať na mobilné dáta."</string>
-    <string name="sim_change_data_ok" msgid="7491552537317573235">"Použiť <xliff:g id="CARRIER">%1$s</xliff:g>"</string>
+    <string name="sim_change_data_ok" msgid="7491552537317573235">"Používať <xliff:g id="CARRIER">%1$s</xliff:g>"</string>
     <string name="sim_preferred_title" msgid="3389680276182899407">"Aktualizovať pref. SIM kartu?"</string>
     <string name="sim_preferred_message" msgid="3751011329746359050">"<xliff:g id="NEW_SIM">%1$s</xliff:g> je jediná SIM karta v zariadení. Chcete ju použiť na mobilné dáta, hovory a správy SMS?"</string>
     <string name="wrong_pin_code_pukked" msgid="3214670264775760428">"Nesprávny kód PIN SIM karty. Teraz musíte kontaktovať svojho operátora, aby vám odomkol zariadenie."</string>
@@ -1660,7 +1667,7 @@
     <string name="bluetooth_tethering_off_subtext_config" msgid="3981528184780083266">"Internetové pripojenie zariadenia <xliff:g id="DEVICE_NAME">%1$d</xliff:g> sa zdieľa cez Bluetooth"</string>
     <string name="bluetooth_tethering_overflow_error" msgid="6946561351369376943">"Maximálny počet zariadení na zdieľanie dátového pripojenia: <xliff:g id="MAXCONNECTION">%1$d</xliff:g>."</string>
     <string name="bluetooth_untether_blank" msgid="5428300773782256084">"Ukončí sa zdieľané dát. pripojenie zariad. <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
-    <string name="tethering_footer_info" msgid="8019555174339154124">"Hotspot a tethering umožňujú poskytovať internet iným zariadeniam prostredníctvom mobilného dátového pripojenia. Aplikácie tiež môžu vytvoriť hostpot na zdieľanie obsahu so zariadeniami v okolí."</string>
+    <string name="tethering_footer_info" msgid="8019555174339154124">"Hotspot a tethering umožňujú poskytovať internet iným zariadeniam prostredníctvom vášho mobilného dátového pripojenia. Aplikácie tiež môžu vytvárať hotspot na zdieľanie obsahu so zariadeniami v okolí."</string>
     <string name="tethering_help_button_text" msgid="7653022000284543996">"Pomocník"</string>
     <string name="network_settings_title" msgid="8516526011407061679">"Mobilná sieť"</string>
     <string name="manage_mobile_plan_title" msgid="3312016665522553062">"Mobilný plán"</string>
@@ -1763,7 +1770,7 @@
     <string name="lockpassword_confirm_your_pin_generic" msgid="8732268389177735264">"Ak chcete pokračovať, zadajte PIN zariadenia"</string>
     <string name="lockpassword_confirm_your_password_generic" msgid="6304552647060899594">"Ak chcete pokračovať, zadajte heslo zariadenia"</string>
     <string name="lockpassword_confirm_your_pattern_generic_profile" msgid="3074250084050465513">"Ak chcete pokračovať, použite pracovný bezpečnostný vzor"</string>
-    <string name="lockpassword_confirm_your_pin_generic_profile" msgid="6037908971086439523">"Ak chcete pokračovať, zadajte pracovný kód PIN"</string>
+    <string name="lockpassword_confirm_your_pin_generic_profile" msgid="6037908971086439523">"Pre pokračovanie zadajte svoj pracovný PIN"</string>
     <string name="lockpassword_confirm_your_password_generic_profile" msgid="2646162490703489685">"Ak chcete pokračovať, zadajte pracovné heslo"</string>
     <string name="lockpassword_strong_auth_required_device_pattern" msgid="1014214190135045781">"Zadajte bezpečnostný vzor zariadenia a získajte vyššiu mieru zabezpečenia"</string>
     <string name="lockpassword_strong_auth_required_device_pin" msgid="24030584350601016">"Zadajte kód PIN zariadenia a získajte vyššiu mieru zabezpečenia"</string>
@@ -1805,7 +1812,7 @@
     <string name="lockpattern_settings_choose_lock_pattern" msgid="9042142745571386381">"Nastaviť bezpečnostný vzor"</string>
     <string name="lockpattern_settings_change_lock_pattern" msgid="1456643060737114885">"Zmena bezpečnostného vzoru"</string>
     <string name="lockpattern_settings_help_how_to_record" msgid="6037403647312543908">"Bezpečnostný vzor obrazovky nakreslite takto"</string>
-    <string name="lockpattern_too_many_failed_confirmation_attempts" msgid="3043127997770535921">"Príliš veľa nesprávnych pokusov. Skúste to znova o <xliff:g id="NUMBER">%d</xliff:g> s."</string>
+    <string name="lockpattern_too_many_failed_confirmation_attempts" msgid="3043127997770535921">"Príliš veľa chybných pokusov. Skúste to znova o <xliff:g id="NUMBER">%d</xliff:g> s."</string>
     <string name="activity_not_found" msgid="3492413375341165453">"Aplikácia nie je v telefóne nainštalovaná."</string>
     <string name="lock_settings_profile_title" msgid="3928992050074556160">"Zabezpečenie pracovného profilu"</string>
     <string name="lock_settings_profile_screen_lock_title" msgid="285267471459162203">"Zámka obrazovky pre pracovný profil"</string>
@@ -2071,14 +2078,14 @@
     <string name="usage_time_label" msgid="5615725415876461039">"Doba použitia"</string>
     <string name="accessibility_settings" msgid="9140621093888234485">"Dostupnosť"</string>
     <string name="accessibility_settings_title" msgid="1687226556576913576">"Nastavenia dostupnosti"</string>
-    <string name="accessibility_settings_summary" msgid="5742379519336396561">"Čítačky obrazovky, obrazovka, ovládacie prvky"</string>
+    <string name="accessibility_settings_summary" msgid="5742379519336396561">"Čítačky obrazovky, obrazovka, doplnkové ovládanie"</string>
     <string name="vision_settings_title" msgid="7315352351051423944">"Pre slabozrakých"</string>
     <string name="vision_settings_description" msgid="3476589459009287332">"Zariadenie môžete prispôsobiť, aby zodpovedalo vašim potrebám. Tieto funkcie dostupnosti môžete neskôr zmeniť v Nastaveniach."</string>
     <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"Zmeniť veľkosť písma"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"Čítačky obrazovky"</string>
     <string name="audio_and_captions_category_title" msgid="6140472938769619212">"Zvuk a text na obrazovke"</string>
     <string name="display_category_title" msgid="545168481672250195">"Zobrazenie"</string>
-    <string name="interaction_control_category_title" msgid="8775039211811947683">"Interaktívne ovládanie"</string>
+    <string name="interaction_control_category_title" msgid="8775039211811947683">"Doplnkové ovládanie"</string>
     <string name="user_installed_services_category_title" msgid="4288689493753221319">"Stiahnuté služby"</string>
     <string name="experimental_category_title" msgid="3797000069740110717">"Experimentálne"</string>
     <string name="feature_flags_dashboard_title" msgid="3153034144122754381">"Experimentálne funkcie"</string>
@@ -2086,7 +2093,7 @@
     <string name="talkback_summary" msgid="6602857105831641574">"Čítačka obrazovky je určená hlavne pre nevidiacich a slabozrakých ľudí"</string>
     <string name="select_to_speak_summary" msgid="7514180457557735421">"Položky na obrazovke si môžete vypočuť nahlas klepnutím"</string>
     <string name="accessibility_captioning_title" msgid="5878371993023439642">"Titulky"</string>
-    <string name="accessibility_screen_magnification_title" msgid="7250949681883917360">"Priblíženie"</string>
+    <string name="accessibility_screen_magnification_title" msgid="7250949681883917360">"Zväčšenie"</string>
     <string name="accessibility_screen_magnification_gestures_title" msgid="9199287875401817974">"Priblíženie trojitým klepnutím"</string>
     <string name="accessibility_screen_magnification_navbar_title" msgid="400655612610761242">"Priblíženie tlačidlom"</string>
     <string name="accessibility_screen_magnification_state_navbar_gesture" msgid="1863831350878995600">"Priblíženie tlačidlom a trojitým klepnutím"</string>
@@ -2353,10 +2360,10 @@
       <item quantity="one">%1$s aplikácia bola nedávno obmedzená</item>
     </plurals>
     <plurals name="battery_tip_restrict_summary" formatted="false" msgid="984148373944071669">
-      <item quantity="few">%2$d aplikácie majú vysokú spotrebu batérie na pozadí</item>
-      <item quantity="many">%2$d aplikácie má vysokú spotrebu batérie na pozadí</item>
-      <item quantity="other">%2$d aplikácií má vysokú spotrebu batérie na pozadí</item>
-      <item quantity="one">%1$s aplikácia má vysokú spotrebu batérie na pozadí</item>
+      <item quantity="few">%2$d aplikácie majú vysokú spotrebu batérie na pozadí</item>
+      <item quantity="many">%2$d apps have high background battery usage</item>
+      <item quantity="other">%2$d aplikácií má vysokú spotrebu batérie na pozadí</item>
+      <item quantity="one">Aplikácia %1$s má vysokú spotrebu batérie na pozadí</item>
     </plurals>
     <plurals name="battery_tip_restrict_handled_summary" formatted="false" msgid="469696766640020557">
       <item quantity="few">Tieto aplikácie sa nedajú spustiť na pozadí</item>
@@ -3236,7 +3243,7 @@
     <string name="emergency_tone_alert" msgid="907868135091891015">"Tóny"</string>
     <string name="emergency_tone_vibrate" msgid="5020068066905681181">"Vibrovanie"</string>
     <string name="boot_sounds_title" msgid="7583926202411353620">"Zvuky pri spustení"</string>
-    <string name="live_caption_title" msgid="7926591158657997051">"Okamžité titulky"</string>
+    <string name="live_caption_title" msgid="7926591158657997051">"Živý prepis"</string>
     <string name="live_caption_summary" msgid="9064771862352393125">"Automaticky pridávať titulky k médiám"</string>
     <string name="zen_mode_settings_summary_off" msgid="6929319200478424962">"Nikdy"</string>
     <plurals name="zen_mode_settings_summary_on" formatted="false" msgid="6061723291126091396">
@@ -3290,11 +3297,11 @@
     <string name="zen_mode_block_effects_screen_off" msgid="6380935819882837552">"Keď je obrazovka vypnutá"</string>
     <string name="zen_mode_block_effect_sound" msgid="1499243540186357631">"Stlmiť zvuk a vibrácie"</string>
     <string name="zen_mode_block_effect_intent" msgid="5666951244667422668">"Nezapínať obrazovku"</string>
-    <string name="zen_mode_block_effect_light" msgid="8679333758037487644">"Neblikať svetlom"</string>
+    <string name="zen_mode_block_effect_light" msgid="8679333758037487644">"Neblikať"</string>
     <string name="zen_mode_block_effect_peek" msgid="6075662813575910221">"Nezobrazovať upozornenia na obrazovke"</string>
-    <string name="zen_mode_block_effect_status" msgid="6516614225115681068">"Skryť ikony stavového riadka v hornej časti obrazovky"</string>
+    <string name="zen_mode_block_effect_status" msgid="6516614225115681068">"Skryť ikony stavového riadka hore na obrazovke"</string>
     <string name="zen_mode_block_effect_badge" msgid="3891743027347075136">"Skryť bodky upozornení na ikonách aplikácií"</string>
-    <string name="zen_mode_block_effect_ambient" msgid="6382013125863616197">"V prípade upozornení nebudiť"</string>
+    <string name="zen_mode_block_effect_ambient" msgid="6382013125863616197">"Pri upozorneniach nebudiť"</string>
     <string name="zen_mode_block_effect_list" msgid="6081548478844912181">"Skryť v zozname upozornení"</string>
     <string name="zen_mode_block_effect_summary_none" msgid="7166175186759564510">"Nikdy"</string>
     <string name="zen_mode_block_effect_summary_screen_off" msgid="2985086455557755722">"Keď je obrazovka vypnutá"</string>
@@ -3561,7 +3568,7 @@
     <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"Plán sa vypne, keď zazvoní budík"</string>
     <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"Správanie režimu bez vyrušení"</string>
     <string name="zen_mode_custom_behavior_summary_default" msgid="3509865340195397447">"Použiť predvolené nastavenia"</string>
-    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"Vytvorte si vlastné nastavenia tohto plánu"</string>
+    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"Vytvoriť si vlastné nastavenia tohto plánu"</string>
     <string name="zen_mode_custom_behavior_category_title" msgid="7451686525113262087">"V rámci plánu <xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>"</string>
     <string name="summary_divider_text" msgid="4780683204694442666">", "</string>
     <string name="summary_range_symbol_combination" msgid="6038631664844488406">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
@@ -3600,7 +3607,7 @@
     <string name="zen_mode_reminders_list" msgid="7347061314032326677">"pripomenutia"</string>
     <string name="zen_mode_events" msgid="5784076928339534984">"Povoliť udalosti"</string>
     <string name="zen_mode_bypassing_apps" msgid="3080739479028713449">"Povoľte aplikáciám prekonávať nastavenia"</string>
-    <string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"Výnimky aplikácie"</string>
+    <string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"Výnimky pre aplikácie"</string>
     <plurals name="zen_mode_bypassing_apps_subtext" formatted="false" msgid="8723144434730871572">
       <item quantity="few">Režim bez vyrušení môžu prekonať <xliff:g id="NUMBER">%1$d</xliff:g> aplikácie</item>
       <item quantity="many">Notifications from <xliff:g id="NUMBER">%1$d</xliff:g> apps can override Do Not Disturb</item>
@@ -3612,7 +3619,7 @@
     <string name="zen_mode_contacts_callers" msgid="3116829245339716399">"kontaktov"</string>
     <string name="zen_mode_starred_callers" msgid="1317376207713013472">"kontaktov s hviezdičkou"</string>
     <string name="zen_mode_repeat_callers" msgid="1435309867554692340">"Opakované volania"</string>
-    <string name="zen_mode_repeat_callers_list" msgid="2750270907597457279">"opakujúcich sa volajúcich"</string>
+    <string name="zen_mode_repeat_callers_list" msgid="2750270907597457279">"opakované volania"</string>
     <string name="zen_mode_repeat_callers_title" msgid="7192952181541813487">"Povoliť opakované volania"</string>
     <string name="zen_mode_calls_summary_one" msgid="8327371053236689649">"Povoliť od <xliff:g id="CALLER_TYPE">%1$s</xliff:g>"</string>
     <string name="zen_mode_calls_summary_two" msgid="9017678770532673578">"Povoliť od <xliff:g id="CALLER_TYPE">%1$s</xliff:g> a <xliff:g id="CALLERT_TPYE">%2$s</xliff:g>"</string>
@@ -3954,7 +3961,7 @@
     <string name="screen_zoom_conversation_icon_pete" msgid="4990733893088820204">"P"</string>
     <string name="screen_zoom_conversation_message_1" msgid="7215516160541988278">"Servus, Peter!"</string>
     <string name="screen_zoom_conversation_message_2" msgid="5409482621887655034">"Nezájdeme dnes na kávu?"</string>
-    <string name="screen_zoom_conversation_message_3" msgid="2471777953578052296">"Dobre, poznám tu jedno skvelé miesto."</string>
+    <string name="screen_zoom_conversation_message_3" msgid="2471777953578052296">"Poďme. Poznám tu blízko jeden super podnik."</string>
     <string name="screen_zoom_conversation_message_4" msgid="8258817329742550137">"Výborne!"</string>
     <string name="screen_zoom_conversation_timestamp_1" msgid="8011637725391996769">"Ut 18:00"</string>
     <string name="screen_zoom_conversation_timestamp_2" msgid="816265985618121370">"Ut 18:01"</string>
@@ -3973,7 +3980,7 @@
     <string name="notification_summary_none" msgid="5003043219430054784">"Zapnuté pre všetky aplikácie"</string>
     <string name="apps_summary" msgid="8355759446490212195">"<xliff:g id="COUNT">%1$d</xliff:g> nainštalovaných aplikácií"</string>
     <string name="apps_summary_example" msgid="3011143598675185269">"24 nainštalovaných aplikácií"</string>
-    <string name="storage_summary" msgid="4835916510511133784">"Využité: <xliff:g id="PERCENTAGE">%1$s</xliff:g> – voľné: <xliff:g id="FREE_SPACE">%2$s</xliff:g>"</string>
+    <string name="storage_summary" msgid="4835916510511133784">"Využité: <xliff:g id="PERCENTAGE">%1$s</xliff:g>, voľné: <xliff:g id="FREE_SPACE">%2$s</xliff:g>"</string>
     <string name="storage_summary_with_sdcard" msgid="8742907204848352697">"Vnútorné úložisko: využité <xliff:g id="PERCENTAGE">%1$s</xliff:g> – voľné <xliff:g id="FREE_SPACE">%2$s</xliff:g>"</string>
     <string name="display_summary" msgid="5725269449657325797">"Režim spánku sa spustí po <xliff:g id="TIMEOUT_DESCRIPTION">%1$s</xliff:g> nečinnosti"</string>
     <string name="display_dashboard_summary" msgid="7678566148167010682">"Tapeta, režim spánku, veľkosť písma"</string>
@@ -3993,7 +4000,7 @@
     <string name="disabled_by_policy_title_camera" msgid="3741138901926111197">"Použitie fotoaparátu je zakázané"</string>
     <string name="disabled_by_policy_title_screen_capture" msgid="1856835333536274665">"Snímky obrazovky sú zakázané"</string>
     <string name="disabled_by_policy_title_suspend_packages" msgid="4254714213391802322">"Táto aplikácia sa nedá otvoriť"</string>
-    <string name="default_admin_support_msg" msgid="5789424433689798637">"V prípade otázok kontaktujte správcu IT."</string>
+    <string name="default_admin_support_msg" msgid="5789424433689798637">"Ak máte nejaké otázky, obráťte sa na svojho správcu IT"</string>
     <string name="admin_support_more_info" msgid="8737842638087863477">"Ďalšie podrobnosti"</string>
     <string name="admin_profile_owner_message" msgid="3199544166281052845">"Správca môže sledovať a spravovať aplikácie a údaje priradené k vášmu pracovnému profilu vrátane nastavení, povolení, firemného prístupu, aktivity siete a informácií o polohe zariadenia."</string>
     <string name="admin_profile_owner_user_message" msgid="2991249382056855531">"Správca môže sledovať a spravovať aplikácie a údaje priradené k tomuto používateľovi vrátane nastavení, povolení, firemného prístupu, aktivity siete a informácií o polohe zariadenia."</string>
@@ -4268,7 +4275,7 @@
     <string name="ambient_display_tap_screen_title" product="tablet" msgid="6434521782016864148">"Klepnutím skontrolujete tablet"</string>
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"Klepnutím skontrolujete zariadenie"</string>
     <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"Ak chcete zistiť čas, skontrolovať upozornenia a získať ďalšie informácie, klepnite na obrazovku."</string>
-    <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"Upozornenia potiahnutím prsta"</string>
+    <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"Upozornenia odtlačkom prsta"</string>
     <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"Potiahnutie prstom"</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"Upozornenia zobrazíte potiahnutím nadol po senzore odtlačkov prstov na zadnej strane telefónu."</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="tablet" msgid="3480057984564476283">"Upozornenia zobrazíte potiahnutím nadol po senzore odtlačkov prstov na zadnej strane tabletu."</string>
@@ -4470,7 +4477,7 @@
     <string name="battery_suggestion_title" product="device" msgid="765005476863631528">"Predĺženie výdrže batérie zariadenia"</string>
     <string name="battery_suggestion_title" product="default" msgid="3295786171830183688">"Predĺženie výdrže batérie telefónu"</string>
     <string name="battery_suggestion_summary" msgid="2669070349482656490"></string>
-    <string name="gesture_prevent_ringing_screen_title" msgid="4173494225145223638">"Blokovanie zvonenia"</string>
+    <string name="gesture_prevent_ringing_screen_title" msgid="4173494225145223638">"Vypnutie zvonenia"</string>
     <string name="gesture_prevent_ringing_title" msgid="8827963588425673557">"Stlačením vypínača a tlač. zvýšenia hlas. zapnete možnosť:"</string>
     <string name="gesture_prevent_ringing_sound_title" msgid="8642330448721033641">"Skratka na vypnutie zvonenia"</string>
     <string name="prevent_ringing_option_vibrate" msgid="6456505293904544108">"Vibrovať"</string>
diff --git a/tests/CarDeveloperOptions/res/values-sl/arrays.xml b/tests/CarDeveloperOptions/res/values-sl/arrays.xml
index 6ac10d1..914e370 100644
--- a/tests/CarDeveloperOptions/res/values-sl/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-sl/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"izvajanje v ozadju"</item>
     <item msgid="6423861043647911030">"glasnost za funkcije za ljudi s posebnimi potrebami"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Lokacija"</item>
+    <item msgid="6656077694190491067">"Lokacija"</item>
+    <item msgid="8790228218278477369">"Lokacija"</item>
+    <item msgid="7836406246005211990">"Vibriranje"</item>
+    <item msgid="3951439024549922598">"Branje stikov"</item>
+    <item msgid="8802152411647068">"Spreminjanje stikov"</item>
+    <item msgid="229544934599698735">"Branje dnevnika klicev"</item>
+    <item msgid="7396102294405899613">"Spreminjanje dnevnika klicev"</item>
+    <item msgid="3597797992398484655">"Branje koledarja"</item>
+    <item msgid="2705975774250907343">"Spreminjanje koledarja"</item>
+    <item msgid="4668747371441932697">"Lokacija"</item>
+    <item msgid="1487578921720243646">"Objava obvestila"</item>
+    <item msgid="4636080349724146638">"Lokacija"</item>
+    <item msgid="673510900286463926">"Klicanje telefonske številke"</item>
+    <item msgid="542083422784609790">"Branje sporočil SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Pisanje sporočil SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Prejemanje sporočil SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Prejemanje sporočil SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Prejemanje sporočil SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Prejemanje sporočil SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Pošiljanje sporočil SMS/MMS"</item>
+    <item msgid="4726682243833913568">"Branje sporočil SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Pisanje sporočil SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Spreminjanje nastavitev"</item>
+    <item msgid="8705854389991425629">"Vlečenje na vrh"</item>
+    <item msgid="5861356020344153651">"Dostop do obvestil"</item>
+    <item msgid="78432174621628659">"Fotoaparat"</item>
+    <item msgid="3986116419882154794">"Snemanje zvoka"</item>
+    <item msgid="4516840825756409490">"Predvajanje zvoka"</item>
+    <item msgid="6811712502798183957">"Preberi odložišče"</item>
+    <item msgid="2780369012602289114">"Spremeni odložišče"</item>
+    <item msgid="2331359440170850868">"Gumbi za predstavnosti"</item>
+    <item msgid="6133599737122751231">"Osredotočenost zvoka"</item>
+    <item msgid="6844485713404805301">"Glavna glasnost"</item>
+    <item msgid="1600379420669104929">"Glasnost glasu"</item>
+    <item msgid="6296768210470214866">"Glasnost zvonjenja"</item>
+    <item msgid="510690696071629241">"Glasnost predstavnosti"</item>
+    <item msgid="406861638631430109">"Glasnost alarma"</item>
+    <item msgid="4715864795872233884">"Glasnost obvestila"</item>
+    <item msgid="2311478519251301183">"Glasnost Bluetootha"</item>
+    <item msgid="5133991377896747027">"Ohrani odklenjen zaslon"</item>
+    <item msgid="2464189519136248621">"Lokacija"</item>
+    <item msgid="2062677934050803037">"Lokacija"</item>
+    <item msgid="1735171933192715957">"Pridobivanje statističnih podatkov o uporabi"</item>
+    <item msgid="1014093788778383554">"Izklop/vklop mikrofona"</item>
+    <item msgid="4199297950608622850">"Prikaz obvestila"</item>
+    <item msgid="2527962435313398821">"Predstavnost projektov"</item>
+    <item msgid="5117506254221861929">"Aktiviranje omrežja VPN"</item>
+    <item msgid="8291198322681891160">"Ozadje pisanja"</item>
+    <item msgid="7106921284621230961">"Struktura pomoči"</item>
+    <item msgid="4496533640894624799">"Posnetek zaslona pomoči"</item>
+    <item msgid="2598847264853993611">"Branje stanja telefona"</item>
+    <item msgid="9215610846802973353">"Dodajanje odzivnika"</item>
+    <item msgid="9186411956086478261">"Uporaba protokola SIP"</item>
+    <item msgid="6884763100104539558">"Obdelava odhodnega klica"</item>
+    <item msgid="125513972170580692">"Prstni odtis"</item>
+    <item msgid="2556071024281275619">"Tipala tel. funkcij"</item>
+    <item msgid="617168514928339387">"Branje oddaj v celici"</item>
+    <item msgid="7134693570516523585">"Lažna lokacija"</item>
+    <item msgid="7224489175375229399">"Branje shrambe"</item>
+    <item msgid="8472735063903258202">"Pisanje v shrambo"</item>
+    <item msgid="4069276819909595110">"Vklop zaslona"</item>
+    <item msgid="1228338896751121025">"Pridobivanje računov"</item>
+    <item msgid="3181581793459233672">"Izvajanje v ozadju"</item>
+    <item msgid="2340936043025374076">"Glasnost za funkcije za ljudi s posebnimi potrebami"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Kratko"</item>
     <item msgid="4816511817309094890">"Srednja pomembnost"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Nikoli ne dovoli"</item>
     <item msgid="8184570120217958741">"Vedno dovoli"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Običajno"</item>
+    <item msgid="5101233285497327432">"Zmerno"</item>
+    <item msgid="1555861583162930714">"Nizko"</item>
+    <item msgid="1719683776264798117">"Resno"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Običajno"</item>
+    <item msgid="6107138933849816768">"Zmerno"</item>
+    <item msgid="182695359839047859">"Nizko"</item>
+    <item msgid="8577246509202964244">"Resno"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Trajno"</item>
     <item msgid="167418068739176448">"Najpogostejša dejavnost"</item>
diff --git a/tests/CarDeveloperOptions/res/values-sl/config.xml b/tests/CarDeveloperOptions/res/values-sl/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-sl/config.xml
+++ b/tests/CarDeveloperOptions/res/values-sl/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-sl/strings.xml b/tests/CarDeveloperOptions/res/values-sl/strings.xml
index 7151979..59d5c2e 100644
--- a/tests/CarDeveloperOptions/res/values-sl/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-sl/strings.xml
@@ -85,8 +85,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Pomanjšava ali povečava besedila na zaslonu"</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Pomanjšanje"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Povečanje"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Vzorčno besedilo"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Čudoviti čarovnik iz Oza"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"11. poglavje: Čudovito Smaragdno mesto"</string>
@@ -210,7 +209,7 @@
     <string name="proxy_error_empty_port" msgid="8034561724923076215">"Izpolniti morate polje vrat."</string>
     <string name="proxy_error_empty_host_set_port" msgid="8471455809508588255">"Če je polje za gostitelja prazno, mora biti prazno tudi polje za vrata."</string>
     <string name="proxy_error_invalid_port" msgid="4046559920586100637">"Vtipkana številka vrat je neveljavna."</string>
-    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"Proxy HTTP lahko uporablja brskalnik, druge aplikacije pa ne."</string>
+    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"Proxy za HTTP lahko uporablja brskalnik, druge aplikacije pa ne."</string>
     <string name="proxy_url_title" msgid="882042361706435904">"URL datoteke PAC: "</string>
     <string name="radio_info_dl_kbps" msgid="2903778264453410272">"Pasovna širina za prenos (kbps):"</string>
     <string name="radio_info_ul_kbps" msgid="3802245899811732716">"Pasovna širina za nalaganje (kbps):"</string>
@@ -455,7 +454,7 @@
     <string name="security_settings_fingerprint_enroll_introduction_continue" msgid="271662150372486535">"Naprej"</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel_setup" msgid="756928427429893070">"Preskoči"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue_setup" msgid="4125977169169671144">"Naprej"</string>
-    <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"Preskok nast. prstnega odtisa?"</string>
+    <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"Brez prstnega odtisa?"</string>
     <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"Nastavitev prstnega odtisa vam bo vzela le minuto ali dve. Če nastavitev preskočite, lahko prstni odtis dodate pozneje v nastavitvah."</string>
     <string name="lock_screen_intro_skip_title" msgid="5307431665496346914">"Preskok zaklepanja zaslona?"</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="tablet" msgid="7553945981266845264">"Funkcije za zaščito naprave ne bodo vklopljene. Če tablični računalnik izgubite, vam ga ukradejo ali ponastavijo na tovarniške nastavitve, drugim osebam ne boste mogli preprečiti njegove uporabe."</string>
@@ -684,7 +683,6 @@
       <item quantity="few">Vsebovati mora manj kot <xliff:g id="NUMBER_1">%d</xliff:g> števke</item>
       <item quantity="other">Vsebovati mora manj kot <xliff:g id="NUMBER_1">%d</xliff:g> števk</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Vsebovati sme samo števke od 0 do 9."</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Skrbnik naprave ne dovoli uporabe nedavne kode PIN."</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Skrbnik za IT je blokiral pogoste kode PIN. Poskusite z drugo kodo PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Ne sme vsebovati neveljavnih znakov."</string>
@@ -727,6 +725,12 @@
       <item quantity="few">Vsebovati mora vsaj <xliff:g id="COUNT">%d</xliff:g> znake, ki niso črka</item>
       <item quantity="other">Vsebovati mora vsaj <xliff:g id="COUNT">%d</xliff:g> znakov, ki niso črka</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">Vsebovati mora vsaj <xliff:g id="COUNT">%d</xliff:g> znak, ki ni števka</item>
+      <item quantity="two">Vsebovati mora vsaj <xliff:g id="COUNT">%d</xliff:g> znaka, ki nista števki</item>
+      <item quantity="few">Vsebovati mora vsaj <xliff:g id="COUNT">%d</xliff:g> znake, ki niso števke</item>
+      <item quantity="other">Vsebovati mora vsaj <xliff:g id="COUNT">%d</xliff:g> znakov, ki niso števke</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Skrbnik naprave ne dovoli uporabe nedavnega gesla."</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Skrbnik za IT je blokiral pogosta gesla. Poskusite z drugim geslom."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Naraščajoč, padajoč ali ponavljajoč se niz števk je prepovedan."</string>
@@ -957,7 +961,7 @@
     <string name="wifi_ap_choose_auto" msgid="7927637960569365785">"Samodejno"</string>
     <string name="wifi_ap_choose_2G" msgid="43198403259714736">"2,4-GHz pas"</string>
     <string name="wifi_ap_choose_5G" msgid="2624859713183683146">"5,0-GHz pas"</string>
-    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"Prednostno 5,0-GHz pas"</string>
+    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"5,0-GHz pas (prednostno)"</string>
     <string name="wifi_ap_2G" msgid="5793110086517338494">"2,4 GHz"</string>
     <string name="wifi_ap_5G" msgid="4584892544393675403">"5,0 GHz"</string>
     <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"Izberite vsaj en pas za dostopno točko Wi‑Fi:"</string>
@@ -969,8 +973,8 @@
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"Branje kode QR"</string>
     <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"Kodo QR spodaj nastavite na sredino, da vzpostavite povezavo z omrežjem »<xliff:g id="SSID">%1$s</xliff:g>«."</string>
     <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"Če se želite pridružiti omrežju Wi‑Fi, preberite kodo QR"</string>
-    <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Skupna raba omrežja Wi‑Fi"</string>
-    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"Če želite vzpostaviti povezavo z omrežjem »<xliff:g id="SSID">%1$s</xliff:g>« in dati geslo v skupno rabo, preberite to kodo QR"</string>
+    <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"Deljenje omrežja Wi‑Fi"</string>
+    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"Če želite vzpostaviti povezavo z omrežjem »<xliff:g id="SSID">%1$s</xliff:g>« in deliti geslo z drugimi, preberite to kodo QR"</string>
     <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"Če želite vzpostaviti povezavo z omrežjem »<xliff:g id="SSID">%1$s</xliff:g>«, preberite to kodo QR"</string>
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"Kode QR ni bilo mogoče prebrati. Kodo nastavite na sredino in poskusite znova."</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"Poskusite znova. Če se težava ponavlja, se obrnite na proizvajalca naprave."</string>
@@ -989,7 +993,7 @@
     <string name="wifi_dpp_device_found" msgid="6488461467496850841">"Najdena je bila naprava"</string>
     <string name="wifi_dpp_sharing_wifi_with_this_device" msgid="2540529164687476827">"Skupna raba povezave Wi‑Fi s to napravo …"</string>
     <string name="wifi_dpp_connecting" msgid="4229290407210299897">"Povezovanje …"</string>
-    <string name="wifi_dpp_share_hotspot" msgid="847987212473038179">"Skupna raba dostopne točke"</string>
+    <string name="wifi_dpp_share_hotspot" msgid="847987212473038179">"Deljenje dostopne točke"</string>
     <string name="wifi_dpp_lockscreen_title" msgid="3910665850075275963">"Potrdite, da ste res vi"</string>
     <string name="wifi_dpp_wifi_password" msgid="8007558344032612455">"Geslo za Wi-Fi: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
     <string name="wifi_dpp_hotspot_password" msgid="6172326289042241924">"Geslo za dostopno točko: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
@@ -1002,7 +1006,7 @@
     <string name="wifi_multiple_cert_added" msgid="7986200585749147204">"(Dodanih je bilo več potrdil)"</string>
     <string name="wifi_use_system_certs" msgid="4794489370929885022">"Uporabi sistemska potrdila"</string>
     <string name="wifi_do_not_provide_eap_user_cert" msgid="4044301449482425250">"Ne posreduj"</string>
-    <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"Ne potrdi"</string>
+    <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"Ne preverjaj"</string>
     <string name="wifi_do_not_validate_eap_server_warning" msgid="3895397996759837323">"Ni navedenih potrdil. Povezava ne bo zasebna."</string>
     <string name="wifi_ssid_too_long" msgid="34911971389775920">"Ime omrežja je predolgo."</string>
     <string name="wifi_no_domain_warning" msgid="735859919311067606">"Določiti morate domeno."</string>
@@ -1134,7 +1138,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mobilno"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Uporaba mobilnega omrežja, če omrežje Wi-Fi ni dosegljivo"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Uporaba omrežja Wi-Fi, če mobilno omrežje ni dosegljivo"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Klic prek omrežja Wi-Fi. Če izgubite povezavo Wi-Fi, bo klic končan."</string>
@@ -1652,12 +1659,12 @@
     <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"Dokler je vklopljeno varčevanje s podatki, ni mogoče vzpostaviti povezave z internetom prek mobilnega telefona ali uporabljati prenosnih dostopnih točk."</string>
     <string name="usb_title" msgid="7480927657535578688">"USB"</string>
     <string name="usb_tethering_button_text" msgid="6242228383142012332">"Internetna povezava prek USB-ja"</string>
-    <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"Skupna raba internetne povezave telefona prek USB-ja"</string>
-    <string name="usb_tethering_subtext" product="tablet" msgid="154536000235361034">"Skupna raba internetne povezave tabličnega računalnika prek USB-ja"</string>
+    <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"Deljenje internetne povezave telefona prek USB-ja"</string>
+    <string name="usb_tethering_subtext" product="tablet" msgid="154536000235361034">"Deljenje internetne povezave tabličnega računalnika prek USB-ja"</string>
     <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"Internet prek Bluetootha"</string>
-    <string name="bluetooth_tethering_subtext" product="tablet" msgid="6868756914621131635">"Skupna raba internetne povezave tabličnega računalnika prek Bluetootha"</string>
-    <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"Skupna raba internetne povezave telefona prek Bluetootha"</string>
-    <string name="bluetooth_tethering_off_subtext_config" msgid="3981528184780083266">"Skupna raba internetne povezave naprave <xliff:g id="DEVICE_NAME">%1$d</xliff:g> prek Bluetootha"</string>
+    <string name="bluetooth_tethering_subtext" product="tablet" msgid="6868756914621131635">"Deljenje internetne povezave tabličnega računalnika prek Bluetootha"</string>
+    <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"Deljenje internetne povezave telefona prek Bluetootha"</string>
+    <string name="bluetooth_tethering_off_subtext_config" msgid="3981528184780083266">"Deljenje internetne povezave naprave <xliff:g id="DEVICE_NAME">%1$d</xliff:g> prek Bluetootha"</string>
     <string name="bluetooth_tethering_overflow_error" msgid="6946561351369376943">"Internetna povezava ni mogoča z več kot <xliff:g id="MAXCONNECTION">%1$d</xliff:g> naprav."</string>
     <string name="bluetooth_untether_blank" msgid="5428300773782256084">"Internetna povezava z napravo <xliff:g id="DEVICE_NAME">%1$s</xliff:g> bo prekinjena."</string>
     <string name="tethering_footer_info" msgid="8019555174339154124">"Uporabite dostopno točko in povezavo z internetom prek mobilnega telefona, da zagotovite internet drugim napravam prek svoje mobilne podatkovne povezave. Tudi aplikacije lahko ustvarijo dostopno točko za skupno rabo vsebin z napravami v bližini."</string>
@@ -1678,7 +1685,7 @@
     <string name="mobile_insert_sim_card" msgid="7594550403454243732">"Vstavite SIM in znova zaženite"</string>
     <string name="mobile_connect_to_internet" msgid="6031886097365170913">"Vzpostavite internetno povezavo"</string>
     <string name="location_title" msgid="8664674161765477168">"Moja lokacija"</string>
-    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"Mesto za delovni profil"</string>
+    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"Lokacija za delovni profil"</string>
     <string name="location_app_level_permissions" msgid="1298041503927632960">"Dovoljenje za aplikacije"</string>
     <string name="location_app_permission_summary_location_off" msgid="541372845344796336">"Zaznavanje lokacije je izklopljeno"</string>
     <plurals name="location_app_permission_summary_location_on" formatted="false" msgid="7904821382328758218">
@@ -1695,7 +1702,7 @@
     <string name="location_low_battery_use" msgid="5030448574501435888">"Nizka poraba akumulatorja"</string>
     <string name="location_scanning_screen_title" msgid="7663329319689413454">"Iskanje omrežij Wi‑Fi in naprav Bluetooth"</string>
     <string name="location_scanning_wifi_always_scanning_title" msgid="6750542206763112172">"Iskanje omrežij Wi‑Fi"</string>
-    <string name="location_scanning_wifi_always_scanning_description" msgid="4956048135941851712">"Aplikacijam in storitvam omogoči, da kadar koli iščejo omrežja Wi-Fi v bližini, tudi ko je Wi-Fi izklopljen. To funkcijo lahko na primer uporabite, če želite izboljšati funkcije in storitve, ki pri delovanju uporabljajo lokacijo."</string>
+    <string name="location_scanning_wifi_always_scanning_description" msgid="4956048135941851712">"Aplikacijam in storitvam omogoči, da kadar koli iščejo omrežja Wi-Fi, tudi ko je Wi-Fi izklopljen. To funkcijo lahko na primer uporabite, če želite izboljšati funkcije in storitve, ki pri delovanju uporabljajo lokacijo."</string>
     <string name="location_scanning_bluetooth_always_scanning_title" msgid="196241746742607453">"Iskanje naprav Bluetooth"</string>
     <string name="location_scanning_bluetooth_always_scanning_description" msgid="3796673798637848690">"Aplikacijam in storitvam omogoči, da kadar koli iščejo naprave v bližini, tudi ko je Bluetooth izklopljen. To funkcijo lahko na primer uporabite, če želite izboljšati funkcije in storitve, ki pri delovanju uporabljajo lokacijo."</string>
     <string name="managed_profile_location_services" msgid="224925483299159541">"Lokacijske storitve za službo"</string>
@@ -1722,7 +1729,7 @@
     <string name="contributors_title" msgid="6800028420806884340">"Sodelavci"</string>
     <string name="manual" msgid="5431859421432581357">"Ročno"</string>
     <string name="regulatory_labels" msgid="380968489247381025">"Zakonsko predpisane oznake"</string>
-    <string name="safety_and_regulatory_info" msgid="7113766428000920132">"Priročnik z varn. in zak. predpis. inf."</string>
+    <string name="safety_and_regulatory_info" msgid="7113766428000920132">"Varnostne in zakonsko predpisane inform."</string>
     <string name="copyright_title" msgid="3847703367689932190">"Avtorska pravica"</string>
     <string name="license_title" msgid="7582145947873528540">"Licenca"</string>
     <string name="terms_title" msgid="1804549588198223771">"Določila in pogoji"</string>
@@ -2329,8 +2336,8 @@
     <string name="battery_tip_smart_battery_title" product="device" msgid="7419448992583346364">"Izboljšajte čas delovanja akumulatorja naprave"</string>
     <string name="battery_tip_smart_battery_summary" msgid="5344821856478265778">"Vklopite varčevanje z energijo akumulatorja"</string>
     <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Vklop varčevanja z energijo akumulatorja"</string>
-    <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Akumulator se bo morda izpraznil prej kot običajno"</string>
-    <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Varčevanje z energijo akumulatorja je vklopljeno"</string>
+    <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Baterija se lahko izprazni prej kot običajno"</string>
+    <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Varčevanje z energijo baterije je vklopljeno"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Nekatere funkcije bodo morda omejene"</string>
     <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Telefon uporabljate več kot običajno"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"Tablični računalnik uporabljate več kot običajno"</string>
@@ -3215,7 +3222,7 @@
     <string name="alarm_volume_option_title" msgid="3184076022438477047">"Glasnost alarma"</string>
     <string name="ring_volume_option_title" msgid="2038924918468372264">"Glasnost zvonjenja"</string>
     <string name="notification_volume_option_title" msgid="1358512611511348260">"Glasnost obvestila"</string>
-    <string name="ringtone_title" msgid="1409086028485922583">"Melodija zvonjenja telefona"</string>
+    <string name="ringtone_title" msgid="1409086028485922583">"Ton zvonjenja telefona"</string>
     <string name="notification_ringtone_title" msgid="2932960620843976285">"Privzeti zvok obvestila"</string>
     <string name="notification_unknown_sound_title" msgid="8043718667804838398">"Zvok iz aplikacije"</string>
     <string name="notification_sound_default" msgid="2664544380802426260">"Privzeti zvok obvestila"</string>
@@ -3224,7 +3231,7 @@
     <string name="other_sound_settings" msgid="5250376066099818676">"Drugi zvoki"</string>
     <string name="dial_pad_tones_title" msgid="8877212139988655769">"Toni tipkovnice"</string>
     <string name="screen_locking_sounds_title" msgid="4407110895465866809">"Zvoki ob zaklepanju zaslona"</string>
-    <string name="charging_sounds_title" msgid="5070437987230894287">"Zvoki in vibrir. ob polnjenju"</string>
+    <string name="charging_sounds_title" msgid="5070437987230894287">"Zvoki in vibriranje ob polnjenju"</string>
     <string name="docking_sounds_title" msgid="2573137471605541366">"Zvok ob odlaganju v nosilec"</string>
     <string name="touch_sounds_title" msgid="165237488496165652">"Zvoki dotikov"</string>
     <string name="vibrate_on_touch_title" msgid="6360155469279157684">"Vibriranje ob dotiku"</string>
@@ -3512,7 +3519,7 @@
     <string name="notification_badge_title" msgid="8989086619255666442">"Dovoli obvestilno piko"</string>
     <string name="notification_channel_badge_title" msgid="8228215248332054612">"Pokaži obvestilno piko"</string>
     <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"Preglasitev načina »Ne moti«"</string>
-    <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"Dovoli prikazovanje teh obvestil tudi, ko je vklopljen način »ne moti«"</string>
+    <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"Dovoli prikazovanje teh obvestil tudi, ko je vklopljen način »Ne moti«"</string>
     <string name="app_notification_visibility_override_title" msgid="2349335170165637672">"Na zaklenjenem zaslonu"</string>
     <string name="app_notification_row_banned" msgid="2079325338122151677">"Blokirano"</string>
     <string name="app_notification_row_priority" msgid="432299064888787236">"Prednost"</string>
@@ -3917,13 +3924,13 @@
     <string name="system_alert_window_apps_title" msgid="9188448296493699566">"Aplikacije"</string>
     <string name="system_alert_window_access_title" msgid="5187343732185369675">"Prekrivanje drugih aplikacij"</string>
     <string name="permit_draw_overlay" msgid="9039092257052422344">"Dovoli prekrivanje drugih aplikacij"</string>
-    <string name="allow_overlay_description" msgid="6669524816705082807">"Omogočite tej aplikaciji, da prekrije druge aplikacije, ki jih uporabljate. To lahko vpliva na uporabo teh aplikacij ali spremeni njihov običajen videz ali delovanje."</string>
+    <string name="allow_overlay_description" msgid="6669524816705082807">"Omogočite tej aplikaciji, da na zaslonu prekrije druge aplikacije, ki jih uporabljate. To lahko vpliva na uporabo teh aplikacij ali spremeni njihov običajen videz ali delovanje."</string>
     <string name="keywords_vr_listener" msgid="5312633527788917750">"vr navidezna resničnost poslušalec stereo storitev za pomoč"</string>
     <string name="keywords_system_alert_window" msgid="3936658600272194599">"sistemsko opozorilo pogovorno okno prikaz s prekrivanjem drugih aplikacij"</string>
     <string name="overlay_settings" msgid="3325154759946433666">"Prekrivanje drugih aplikacij"</string>
     <string name="system_alert_window_summary" msgid="7703582115861844158">"<xliff:g id="COUNT_0">%1$d</xliff:g> od <xliff:g id="COUNT_1">%2$d</xliff:g> aplikacij, ki lahko prekrivajo druge aplikacije"</string>
     <string name="filter_overlay_apps" msgid="6336897660213304743">"Aplikacije z dovoljenjem"</string>
-    <string name="app_permission_summary_allowed" msgid="6458476982015518778">"Dovoljene"</string>
+    <string name="app_permission_summary_allowed" msgid="6458476982015518778">"Dovoljeno"</string>
     <string name="app_permission_summary_not_allowed" msgid="1171642541675462584">"Ni dovoljeno"</string>
     <string name="keywords_install_other_apps" msgid="5383559540695847668">"nameščanje aplikacij neznani viri"</string>
     <string name="write_settings" msgid="9009040811145552108">"Spreminjanje sist. nastavitev"</string>
@@ -4008,7 +4015,7 @@
     <string name="condition_zen_title" msgid="2128184708916052585">"Način »ne moti« je vklopljen"</string>
     <string name="condition_zen_summary_phone_muted" msgid="4396050395522974654">"Zvok telefona je izklopljen"</string>
     <string name="condition_zen_summary_with_exceptions" msgid="3435216391993785818">"Z izjemami"</string>
-    <string name="condition_battery_title" msgid="6704870010912986274">"Varč. z energijo akum. je vkl."</string>
+    <string name="condition_battery_title" msgid="6704870010912986274">"Varč. z energijo bat. je vkl."</string>
     <string name="condition_battery_summary" msgid="1236078243905690620">"Funkcije so omejene"</string>
     <string name="condition_cellular_title" msgid="6605277435894307935">"Mobilni podatki so izklopljeni"</string>
     <string name="condition_cellular_summary" msgid="3607459310548343777">"Dostop do interneta je na voljo le prek omrežja Wi‑Fi"</string>
@@ -4065,7 +4072,7 @@
     <string name="app_usage_cycle" msgid="213483325132959663">"Cikel porabe podatkov aplikacije"</string>
     <string name="cell_data_warning" msgid="8902740337286652689">"Opozorilo ob preneseni količini podatkov <xliff:g id="ID_1">^1</xliff:g>"</string>
     <string name="cell_data_limit" msgid="3175933829235314233">"Omejitev prenosa podatkov pri <xliff:g id="ID_1">^1</xliff:g>"</string>
-    <string name="cell_data_warning_and_limit" msgid="3846150001253927594">"Opozorilo ob preneseni količini podatkov <xliff:g id="ID_1">^1</xliff:g>/omejitev prenosa podatkov pri <xliff:g id="ID_2">^2</xliff:g>"</string>
+    <string name="cell_data_warning_and_limit" msgid="3846150001253927594">"Opozorilo pri <xliff:g id="ID_1">^1</xliff:g> prenesenih podatkov/omejitev prenosa podatkov pri <xliff:g id="ID_2">^2</xliff:g>"</string>
     <string name="billing_cycle_fragment_summary" msgid="4926047002107855543">"Mesečno na dan <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="network_restrictions" msgid="196294262243618198">"Omejitve omrežja"</string>
     <plurals name="network_restrictions_summary" formatted="false" msgid="1664494781594839837">
@@ -4458,7 +4465,7 @@
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"Tej aplikaciji omogočite, da upravlja povezavo Wi-Fi"</string>
     <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"Tej aplikacij omogočite, da vklopi ali izklopi povezavo Wi-Fi, išče omrežja Wi-Fi in se z njimi poveže, doda ali odstrani omrežja ali pa zažene lokalno dostopno točko"</string>
     <string name="media_output_title" msgid="8710632337456601848">"Predvajaj predstavnost v"</string>
-    <string name="media_output_default_summary" msgid="3159237976830415584">"ta naprava"</string>
+    <string name="media_output_default_summary" msgid="3159237976830415584">"Ta naprava"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"Telefon"</string>
     <string name="media_output_summary" product="tablet" msgid="6672024060360538526">"Tablični računalnik"</string>
     <string name="media_output_summary" product="device" msgid="5132223072593052660">"Naprava"</string>
diff --git a/tests/CarDeveloperOptions/res/values-sq/arrays.xml b/tests/CarDeveloperOptions/res/values-sq/arrays.xml
index 11c7d80..96b8e7e 100644
--- a/tests/CarDeveloperOptions/res/values-sq/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-sq/arrays.xml
@@ -29,8 +29,25 @@
     <item msgid="5194868215515664953">"Oqeani Paqësor"</item>
     <item msgid="7044520255415007865">"Të gjitha"</item>
   </string-array>
-    <!-- no translation found for screen_timeout_entries:0 (8596143519087753804) -->
-    <!-- no translation found for dream_timeout_entries:7 (8271452751594598661) -->
+  <string-array name="screen_timeout_entries">
+    <item msgid="8596143519087753804">"15 sekonda"</item>
+    <item msgid="772029947136115322">"30 sekonda"</item>
+    <item msgid="8743663928349474087">"1 minutë"</item>
+    <item msgid="1506508631223164814">"2 minuta"</item>
+    <item msgid="8664703938127907662">"5 min."</item>
+    <item msgid="5827960506924849753">"10 min."</item>
+    <item msgid="6677424950124253938">"30 min."</item>
+  </string-array>
+  <string-array name="dream_timeout_entries">
+    <item msgid="6487043225269853023">"Asnjëherë"</item>
+    <item msgid="2517785806387977252">"15 sek."</item>
+    <item msgid="6347954399441173672">"30 sekonda"</item>
+    <item msgid="4858305253279921789">"1 minutë"</item>
+    <item msgid="8109273437140044073">"2 minuta"</item>
+    <item msgid="2788593551142462622">"5 min."</item>
+    <item msgid="8012672183888404961">"10 min."</item>
+    <item msgid="8271452751594598661">"30 minuta"</item>
+  </string-array>
   <string-array name="lock_after_timeout_entries">
     <item msgid="2232921187970351881">"Menjëherë"</item>
     <item msgid="2038544972632026612">"5 sek."</item>
@@ -42,17 +59,47 @@
     <item msgid="811192536981678974">"10 min."</item>
     <item msgid="7258394417241706272">"30 min."</item>
   </string-array>
-    <!-- no translation found for entries_font_size:0 (2340391964816059553) -->
-    <!-- no translation found for entries_font_size:0 (6490061470416867723) -->
-    <!-- no translation found for entries_font_size:2 (1714184661981538355) -->
-    <!-- no translation found for entries_font_size:2 (1678068858001018666) -->
-    <!-- no translation found for wifi_status:3 (5848277343965362748) -->
-    <!-- no translation found for wifi_status_with_ssid:1 (6816207058895999545) -->
-    <!-- no translation found for wifi_status_with_ssid:3 (7547609081339573756) -->
-    <!-- no translation found for wifi_status_with_ssid:4 (5145158315060185414) -->
+  <string-array name="entries_font_size">
+    <item msgid="2340391964816059553">"I vogël"</item>
+    <item msgid="591935967183159581">"E parazgjedhur"</item>
+    <item msgid="1714184661981538355">"I madh"</item>
+    <item msgid="6195563047686707484">"Më i madhi"</item>
+  </string-array>
+  <string-array name="wifi_status">
+    <item msgid="1304883790721412351"></item>
+    <item msgid="4157625910392775808">"Po skanon..."</item>
+    <item msgid="5597394826455877834">"Po lidhet..."</item>
+    <item msgid="5848277343965362748">"Po vërtetohet…"</item>
+    <item msgid="3391238031431440676">"Po merr adresën IP…"</item>
+    <item msgid="5257597310494000224">"Lidhur"</item>
+    <item msgid="8472497592913050396">"I pezulluar"</item>
+    <item msgid="1228072488815999109">"Po shkëputet..."</item>
+    <item msgid="7253087004422991731">"I shkëputur"</item>
+    <item msgid="4169850917304751227">"Pa sukses"</item>
+    <item msgid="6266658166690831131">"I bllokuar"</item>
+    <item msgid="4517230805854909775">"Po shmang përkohësisht lidhje të dobët"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="4853670665485437464"></item>
+    <item msgid="6816207058895999545">"Po skanon…"</item>
+    <item msgid="8058143476674427024">"Po lidhet me <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7547609081339573756">"Po kryen vërtetimin me <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="5145158315060185414">"Po merr adresën IP nga <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="3283243151651124831">"I lidhur me <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="6600156231416890902">"I pezulluar"</item>
+    <item msgid="4133290864821295785">"I shkëputur nga <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="3980154971187953257">"I shkëputur"</item>
+    <item msgid="2847316776634969068">"Pa sukses"</item>
+    <item msgid="4390990424746035383">"I bllokuar"</item>
+    <item msgid="3618248791367063949">"Përkohësisht duke shmangur një lidhje të dobët"</item>
+  </string-array>
     <!-- no translation found for wifi_tether_security:0 (5586343370515598801) -->
     <!-- no translation found for wifi_tether_security:1 (6136336549994615745) -->
-    <!-- no translation found for wifi_p2p_wps_setup:0 (5390235347963255303) -->
+  <string-array name="wifi_p2p_wps_setup">
+    <item msgid="5390235347963255303">"Butoni me shtypje"</item>
+    <item msgid="7401896200768713930">"Kodi PIN nga pajisja homologe"</item>
+    <item msgid="4526848028011846710">"PIN-i nga pajisja"</item>
+  </string-array>
   <string-array name="wifi_p2p_status">
     <item msgid="8741947238021758201">"Lidhur"</item>
     <item msgid="983792611851499732">"I ftuar"</item>
@@ -60,7 +107,12 @@
     <item msgid="4646663015449312554">"Në shitje"</item>
     <item msgid="3230556734162006146">"Jashtë rrezes"</item>
   </string-array>
-    <!-- no translation found for bluetooth_visibility_timeout_entries:1 (2759776603549270587) -->
+  <string-array name="bluetooth_visibility_timeout_entries">
+    <item msgid="8247986727324120082">"2 minuta"</item>
+    <item msgid="2759776603549270587">"5 minuta"</item>
+    <item msgid="167772676068860015">"1 orë"</item>
+    <item msgid="5985477119043628504">"Skadim të kohës së veprimit, asnjëherë!"</item>
+  </string-array>
   <string-array name="bluetooth_max_connected_audio_devices">
     <item msgid="3800257971619063588">"Përdor parazgjedhjen e sistemit: <xliff:g id="DEFAULT_BLUETOOTH_MAX_CONNECTED_AUDIO_DEVICES">%1$d</xliff:g>"</item>
     <item msgid="8572230405241423895">"1"</item>
@@ -69,8 +121,13 @@
     <item msgid="1644506614010085798">"4"</item>
     <item msgid="3132506679404897150">"5"</item>
   </string-array>
-    <!-- no translation found for wifi_signal:1 (7882129634982603782) -->
-    <!-- no translation found for wifi_signal:4 (999948812884919584) -->
+  <string-array name="wifi_signal">
+    <item msgid="1709949377823900951">"I dobët"</item>
+    <item msgid="7882129634982603782">"I dobët"</item>
+    <item msgid="6457357501905996224">"Pak i dobët"</item>
+    <item msgid="405271628162918841">"I mirë"</item>
+    <item msgid="999948812884919584">"I shkëlqyer"</item>
+  </string-array>
   <string-array name="data_usage_data_range">
     <item msgid="8986775481492954015">"30 ditët e fundit"</item>
     <item msgid="3211287705232736964">"Cakto ciklin e përdorimit..."</item>
@@ -106,7 +163,10 @@
     <item msgid="7330627471456865502">"MSCHAPV2"</item>
     <item msgid="6255179395132581882">"GTC"</item>
   </string-array>
-    <!-- no translation found for wifi_ip_settings:1 (4377002609760712163) -->
+  <string-array name="wifi_ip_settings">
+    <item msgid="2717196390555072244">"DHCP"</item>
+    <item msgid="4377002609760712163">"Statike"</item>
+  </string-array>
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"Asnjë"</item>
     <item msgid="1464741437353223198">"Manuale"</item>
@@ -226,11 +286,73 @@
     <item msgid="1165623660533024666">"ekzekuto në sfond"</item>
     <item msgid="6423861043647911030">"volumi i qasshmërisë"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:3 (7836406246005211990) -->
-    <!-- no translation found for app_ops_labels:4 (3951439024549922598) -->
-    <!-- no translation found for app_ops_labels:8 (3597797992398484655) -->
-    <!-- no translation found for app_ops_labels:20 (3037159047591081136) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Vendndodhja"</item>
+    <item msgid="6656077694190491067">"Vendndodhja"</item>
+    <item msgid="8790228218278477369">"Vendndodhja"</item>
+    <item msgid="7836406246005211990">"Dridhje"</item>
+    <item msgid="3951439024549922598">"Lexo kontaktet"</item>
+    <item msgid="8802152411647068">"Modifiko kontaktet"</item>
+    <item msgid="229544934599698735">"Lexo ditarin e telefonatave"</item>
+    <item msgid="7396102294405899613">"Modifiko ditarin e telefonatave"</item>
+    <item msgid="3597797992398484655">"Lexo kalendarin"</item>
+    <item msgid="2705975774250907343">"Modifiko kalendarin"</item>
+    <item msgid="4668747371441932697">"Vendndodhja"</item>
+    <item msgid="1487578921720243646">"Posto njoftimin"</item>
+    <item msgid="4636080349724146638">"Vendndodhja"</item>
+    <item msgid="673510900286463926">"Telefono telefonin"</item>
+    <item msgid="542083422784609790">"Lexo SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Shkruaj SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Prano SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Merr SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Merr SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Merr SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Dërgo SMS/MMS"</item>
+    <item msgid="4726682243833913568">"Lexo SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Shkruaj SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Modifiko cilësimet"</item>
+    <item msgid="8705854389991425629">"Vizato sipër"</item>
+    <item msgid="5861356020344153651">"Qasu te njoftimet"</item>
+    <item msgid="78432174621628659">"Kamera"</item>
+    <item msgid="3986116419882154794">"Regjistro audio"</item>
+    <item msgid="4516840825756409490">"Luaj audio"</item>
+    <item msgid="6811712502798183957">"Lexo memorien e fragmenteve"</item>
+    <item msgid="2780369012602289114">"Modifiko memorien e fragmenteve"</item>
+    <item msgid="2331359440170850868">"Butonat e \"medias\""</item>
+    <item msgid="6133599737122751231">"Përqendrimi i audios"</item>
+    <item msgid="6844485713404805301">"Kontrollo volumin"</item>
+    <item msgid="1600379420669104929">"Volumi i zërit"</item>
+    <item msgid="6296768210470214866">"Volumi i ziles"</item>
+    <item msgid="510690696071629241">"Volumi i medias"</item>
+    <item msgid="406861638631430109">"Volumi i alarmit"</item>
+    <item msgid="4715864795872233884">"Volumi i njoftimit"</item>
+    <item msgid="2311478519251301183">"Volumi i \"Bluetooth-it\""</item>
+    <item msgid="5133991377896747027">"Mbaje të zgjuar"</item>
+    <item msgid="2464189519136248621">"Vendndodhja"</item>
+    <item msgid="2062677934050803037">"Vendndodhja"</item>
+    <item msgid="1735171933192715957">"Gjej statistika të përdorimit"</item>
+    <item msgid="1014093788778383554">"Çaktivizo/aktivizo mikrofonin"</item>
+    <item msgid="4199297950608622850">"Shfaq kodin toast"</item>
+    <item msgid="2527962435313398821">"Projekto median"</item>
+    <item msgid="5117506254221861929">"Aktivizo rrjetin VPN"</item>
+    <item msgid="8291198322681891160">"Shkruaj në imazhin e sfondit"</item>
+    <item msgid="7106921284621230961">"Ndihmo strukturën"</item>
+    <item msgid="4496533640894624799">"Ndihmo pamjen e ekranit"</item>
+    <item msgid="2598847264853993611">"Lexo gjendjen e telefonit"</item>
+    <item msgid="9215610846802973353">"Shto postë zanore"</item>
+    <item msgid="9186411956086478261">"Përdor kodin sip"</item>
+    <item msgid="6884763100104539558">"Përpuno thirrjen dalëse"</item>
+    <item msgid="125513972170580692">"Gjurma e gishtit"</item>
+    <item msgid="2556071024281275619">"Sensorët e trupit"</item>
+    <item msgid="617168514928339387">"Lexo transmetimet celulare"</item>
+    <item msgid="7134693570516523585">"Vendndodhja e simuluar"</item>
+    <item msgid="7224489175375229399">"Lexo hapësirën ruajtëse"</item>
+    <item msgid="8472735063903258202">"Shkruaj hapësirën ruajtëse"</item>
+    <item msgid="4069276819909595110">"Ndiz ekranin"</item>
+    <item msgid="1228338896751121025">"Merr llogaritë"</item>
+    <item msgid="3181581793459233672">"Ekzekuto në sfond"</item>
+    <item msgid="2340936043025374076">"Volumi i qasshmërisë"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"E shkurtër"</item>
     <item msgid="4816511817309094890">"Mesatare"</item>
@@ -247,15 +369,35 @@
     <item msgid="4627069151979553527">"I pjerrët"</item>
     <item msgid="6896773537705206194">"Shkronja të mëdha të minimizuara"</item>
   </string-array>
-    <!-- no translation found for captioning_font_size_selector_titles:3 (2784236342175159295) -->
-    <!-- no translation found for captioning_edge_type_selector_titles:4 (8019330250538856521) -->
+  <string-array name="captioning_font_size_selector_titles">
+    <item msgid="1680223634161592855">"Shumë e vogël"</item>
+    <item msgid="5091603983404027034">"E vogël"</item>
+    <item msgid="176844712416932112">"Normale"</item>
+    <item msgid="2784236342175159295">"I madh"</item>
+    <item msgid="218913203203160606">"Shumë e madhe"</item>
+  </string-array>
+  <string-array name="captioning_edge_type_selector_titles">
+    <item msgid="3865198759294188069">"E parazgjedhur"</item>
+    <item msgid="6488643537808152001">"Asnjë"</item>
+    <item msgid="552332815156010137">"Kontur"</item>
+    <item msgid="7187891159463789272">"Me hijezim"</item>
+    <item msgid="8019330250538856521">"I ngritur"</item>
+    <item msgid="8987385315647049787">"I ulur"</item>
+  </string-array>
   <string-array name="captioning_opacity_selector_titles">
     <item msgid="313003243371588365">"25%"</item>
     <item msgid="4665048002584838262">"50%"</item>
     <item msgid="1874668269931014581">"75%"</item>
     <item msgid="6462911487571123954">"100%"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"E parazgjedhur"</item>
+    <item msgid="8611890312638868524">"E bardhë mbi të zezë"</item>
+    <item msgid="5891360837786277638">"E zezë mbi të bardhë"</item>
+    <item msgid="2798457065945456853">"E verdhë mbi të zezë"</item>
+    <item msgid="5799049811524553967">"E verdhë mbi të kaltër"</item>
+    <item msgid="3673930830658169860">"Personalizo"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"VPN PPTP"</item>
     <item msgid="1349760781118368659">"Rrjeti VPN L2TP/IPSec me çelësat e ndarë paraprakisht"</item>
@@ -264,16 +406,36 @@
     <item msgid="3319427315593649917">"Rrjeti VPN IPSec me certifikata dhe me verifikimin Xauth"</item>
     <item msgid="8258927774145391041">"Rrjeti VPN IPSec me certifikata dhe me vërtetim hibrid"</item>
   </string-array>
-    <!-- no translation found for vpn_proxy_settings:0 (2958623927055120839) -->
-    <!-- no translation found for vpn_states:4 (9135049670787351881) -->
+  <string-array name="vpn_proxy_settings">
+    <item msgid="2958623927055120839">"Asnjë"</item>
+    <item msgid="1157046369795346308">"Manuale"</item>
+  </string-array>
+  <string-array name="vpn_states">
+    <item msgid="5408915841694583740">"I shkëputur"</item>
+    <item msgid="8754480102834556765">"Po fillon..."</item>
+    <item msgid="3351334355574270250">"Po lidhet..."</item>
+    <item msgid="8303882153995748352">"Lidhur"</item>
+    <item msgid="9135049670787351881">"Koha e pritjes"</item>
+    <item msgid="2124868417182583926">"Pa sukses"</item>
+  </string-array>
   <string-array name="security_settings_premium_sms_values">
     <item msgid="1164265643455394443">"Pyet"</item>
     <item msgid="7718817231348607934">"Mos lejo asnjëherë"</item>
     <item msgid="8184570120217958741">"Lejo gjithmonë"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normale"</item>
+    <item msgid="5101233285497327432">"E moderuar"</item>
+    <item msgid="1555861583162930714">"I ulët"</item>
+    <item msgid="1719683776264798117">"Kritik"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normale"</item>
+    <item msgid="6107138933849816768">"E moderuar"</item>
+    <item msgid="182695359839047859">"I ulët"</item>
+    <item msgid="8577246509202964244">"Kritike"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Pa ndalim"</item>
     <item msgid="167418068739176448">"Aktiviteti kryesor"</item>
diff --git a/tests/CarDeveloperOptions/res/values-sq/config.xml b/tests/CarDeveloperOptions/res/values-sq/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-sq/config.xml
+++ b/tests/CarDeveloperOptions/res/values-sq/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-sq/strings.xml b/tests/CarDeveloperOptions/res/values-sq/strings.xml
index ef73ea6..ac2c3bc 100644
--- a/tests/CarDeveloperOptions/res/values-sq/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-sq/strings.xml
@@ -23,8 +23,8 @@
     <string name="deny" msgid="3998166389989144025">"Refuzo"</string>
     <string name="device_info_default" msgid="1548919563979154348">"I panjohur"</string>
     <plurals name="show_dev_countdown" formatted="false" msgid="3953785659137161981">
-      <item quantity="other">Tani je <xliff:g id="STEP_COUNT_1">%1$d</xliff:g> hapa larg të qenët programues.</item>
-      <item quantity="one">Tani je <xliff:g id="STEP_COUNT_0">%1$d</xliff:g> hap larg të qenët programues.</item>
+      <item quantity="other">Tani të duhen edhe <xliff:g id="STEP_COUNT_1">%1$d</xliff:g> hapa për t\'u bërë zhvillues.</item>
+      <item quantity="one">Tani të duhet edhe <xliff:g id="STEP_COUNT_0">%1$d</xliff:g> hap për t\'u bërë zhvillues.</item>
     </plurals>
     <string name="show_dev_on" msgid="9075712234786224065">"Tani je zhvillues!"</string>
     <string name="show_dev_already" msgid="7665948832405148689">"Nuk ka nevojë, ti je programues tashmë!"</string>
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Bëje tekstin në ekran më të vogël ose më të madh."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Zvogëlo"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Zmadho"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Teksti shembull"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Magjistari i mrekullueshëm i Ozit"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Kapitulli 11: Qyteti i mrekullueshëm i smeraldtë i Ozit"</string>
@@ -419,7 +418,7 @@
     <string name="security_settings_face_enroll_done" msgid="5409739233373490971">"U krye"</string>
     <string name="security_settings_face_settings_use_face_category" msgid="1586532139528115416">"Përdor fytyrën për"</string>
     <string name="security_settings_face_settings_use_face_unlock_phone" msgid="318274519126401671">"Shkyçja e pajisjes"</string>
-    <string name="security_settings_face_settings_use_face_for_apps" msgid="5479369083370664351">"Identifikimi dhe pagesat e aplikacionit"</string>
+    <string name="security_settings_face_settings_use_face_for_apps" msgid="5479369083370664351">"Identifikim në aplikacion dhe pagesa"</string>
     <string name="security_settings_face_settings_require_attention" msgid="2755140150841557225">"Hap sytë për të shkyçur"</string>
     <string name="security_settings_face_settings_require_attention_details" msgid="2557060433599942587">"Kur përdor vërtetimin me fytyrë, sytë duhet të jenë të hapur"</string>
     <string name="security_settings_face_settings_require_confirmation" msgid="7312024271060416438">"Kërko gjithmonë konfirmimin"</string>
@@ -596,7 +595,7 @@
     <string name="unlock_disable_lock_title" msgid="3508492427073600294">"Çakt. kyçjen e ekranit"</string>
     <string name="unlock_disable_frp_warning_title" msgid="5858589970505254193">"Të hiqet mbrojtja e pajisjes?"</string>
     <string name="unlock_disable_frp_warning_title_profile" msgid="3814123014295965266">"Të hiqet mbrojtja e profilit?"</string>
-    <string name="unlock_disable_frp_warning_content_pattern" msgid="1843950215687159135">"Funksionet e mbrojtjes së pajisjes nuk do të funksionojnë pa motivin tënd."</string>
+    <string name="unlock_disable_frp_warning_content_pattern" msgid="1843950215687159135">"Veçoritë e mbrojtjes së pajisjes nuk do të funksionojnë pa motivin tënd."</string>
     <string name="unlock_disable_frp_warning_content_pattern_fingerprint" msgid="8846957650251741548">"Funksionet e mbrojtjes së pajisjes nuk do të funksionojnë pa motivin tënd.<xliff:g id="EMPTY_LINE">
 
 </xliff:g>Gjurmët e gishtave të ruajtura do të hiqen nga kjo pajisje dhe nuk do të jesh në gjendje të shkyçësh telefonin, të autorizosh blerjet apo të identifikohesh në aplikacione me to."</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Duhet të ketë më pak se <xliff:g id="NUMBER_1">%d</xliff:g> shifra</item>
       <item quantity="one">Duhet të ketë më pak se <xliff:g id="NUMBER_0">%d</xliff:g> shifër</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Duhet të përmbajë vetëm shifrat 0-9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Administratori i pajisjes nuk e lejon përdorimin e një kodi PIN të përdorur së fundi"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Kodet e zakonshme PIN janë bllokuar nga administratori i TI-së. Provo një kod tjetër PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Kjo nuk mund të përfshijë një karakter të pavlefshëm"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Duhet të përmbajë të paktën <xliff:g id="COUNT">%d</xliff:g> karaktere që nuk janë shkronja</item>
       <item quantity="one">Duhet të përmbajë të paktën 1 karakter që nuk është shkronjë</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Duhet të përmbajë të paktën <xliff:g id="COUNT">%d</xliff:g> karaktere jonumerike</item>
+      <item quantity="one">Duhet të përmbajë të paktën 1 karakter jonumerik</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Administratori i pajisjes nuk e lejon përdorimin e një fjalëkalimi të përdorur së fundi"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Fjalëkalimet e zakonshme janë bllokuar nga administratori i TI-së. Provo një fjalëkalim tjetër."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Nuk lejohet një sekuencë shifrash në rritje, në zbritje ose me përsëritje"</string>
@@ -847,7 +849,7 @@
     <string name="wifi_notify_open_networks" msgid="4782239203624619655">"Hap njoftimin e rrjetit"</string>
     <string name="wifi_notify_open_networks_summary" msgid="1383681260705466715">"Njofto kur ofrohet një rrjet publik me cilësi të lartë"</string>
     <string name="wifi_wakeup" msgid="4963732992164721548">"Aktivizo automatikisht Wi‑Fi"</string>
-    <string name="wifi_wakeup_summary" msgid="1152699417411690">"Wi-Fi do të aktivizohet përsëri në afërsi të rrjeteve të ruajtura me cilësi të lartë, si p.sh. rrjetin e shtëpisë"</string>
+    <string name="wifi_wakeup_summary" msgid="1152699417411690">"Wi-Fi do të aktivizohet përsëri në afërsi të rrjeteve të ruajtura me cilësi të lartë, si p.sh. rrjeti i shtëpisë"</string>
     <string name="wifi_wakeup_summary_no_location" msgid="3007457288587966962">"Nuk ofrohet sepse vendndodhja është e çaktivizuar. Aktivizo "<annotation id="link">"vendndodhjen"</annotation>"."</string>
     <string name="wifi_wakeup_summary_scanning_disabled" msgid="6820040651529910914">"Nuk ofrohet sepse skanimi i Wi-Fi është çaktivizuar"</string>
     <string name="wifi_wakeup_summary_scoring_disabled" msgid="7067018832237903151">"Për ta përdorur, zgjidh një ofrues të vlerësimit të rrjetit"</string>
@@ -903,7 +905,7 @@
     <string name="wifi_ssid_hint" msgid="5010024648106585165">"Fut SSID-në"</string>
     <string name="wifi_security" msgid="9136702039496152831">"Siguria"</string>
     <string name="wifi_hidden_network" msgid="6647772204699776833">"Rrjet i fshehur"</string>
-    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Nëse rrugëzuesi nuk po transmeton një ID rrjeti, por dëshiron të lidhesh me të në të ardhmen, mund ta caktosh rrjetin si të fshehur.\n\nKjo mund të krijojë një rrezik për sigurinë pasi telefoni yt do të transmetojë rregullisht sinjalin e tij për të gjetur rrjetin.\n\nCaktimi i rrjetit si të fshehur nuk do të ndryshojë cilësimet e router-it."</string>
+    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Nëse router-i nuk po transmeton një ID rrjeti, por dëshiron të lidhesh me të në të ardhmen, mund ta caktosh rrjetin si të fshehur.\n\nKjo mund të krijojë një rrezik për sigurinë pasi telefoni yt do të transmetojë rregullisht sinjalin e tij për të gjetur rrjetin.\n\nCaktimi i rrjetit si të fshehur nuk do të ndryshojë cilësimet e router-it."</string>
     <string name="wifi_signal" msgid="696548364467704808">"Fuqia e sinjalit"</string>
     <string name="wifi_status" msgid="3439931558930689940">"Statusi"</string>
     <string name="tx_wifi_speed" msgid="2571810085003261073">"Shpejtësia e lidhjes së transmetimit"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Celular"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Nëse Wi‑Fi nuk ofrohet, përdor rrjetin celular"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Nëse rrjeti celular nuk ofrohet, përdor Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Telefono nëpërmjet Wi-Fi. Nëse humb Wi‑Fi, telefonata do të mbyllet."</string>
@@ -1120,7 +1125,7 @@
     <string name="musicfx_title" msgid="6456079041566773649">"Efektet e muzikës"</string>
     <string name="ring_volume_title" msgid="5874791723449821646">"Volumi i ziles"</string>
     <string name="vibrate_in_silent_title" msgid="2314667015729841220">"Dridhje kur është \"në heshtje\""</string>
-    <string name="notification_sound_title" msgid="6812164482799723931">"Zëri i parazgjedhur i njoftimit"</string>
+    <string name="notification_sound_title" msgid="6812164482799723931">"Tingulli i parazgjedhur i njoftimit"</string>
     <string name="incoming_call_volume_title" msgid="4736570528754310450">"Toni i ziles"</string>
     <string name="notification_volume_title" msgid="6022562909288085275">"Njoftimi"</string>
     <string name="checkbox_notification_same_as_incoming_call" msgid="7312942422655861175">"Përdor volumin e telefonatës hyrëse për njoftime"</string>
@@ -1304,7 +1309,7 @@
     <string name="pin_failed" msgid="4877356137480446727">"Operac. kodit PIN të kartës SIM dështoi!"</string>
     <string name="system_update_settings_list_item_title" msgid="1907497454722790033">"Përditësimet e sistemit"</string>
     <string name="system_update_settings_list_item_summary" msgid="3497456690691907873"></string>
-    <string name="firmware_version" msgid="547095584029938749">"Versioni i Android-it"</string>
+    <string name="firmware_version" msgid="547095584029938749">"Versioni i Android"</string>
     <string name="security_patch" msgid="483709031051932208">"Niveli i korrigjimit të sigurisë së Android"</string>
     <string name="model_info" msgid="1729765474260797594">"Modeli"</string>
     <string name="model_summary" msgid="8781425868254352168">"Modeli: %1$s"</string>
@@ -1939,9 +1944,9 @@
     <string name="language_input_gesture_summary_on_with_assist" msgid="315262339899294132"></string>
     <string name="language_input_gesture_summary_on_non_assist" msgid="6054599939153669225"></string>
     <string name="language_input_gesture_summary_off" msgid="4108509077072348546"></string>
-    <string name="language_settings" msgid="3551012802762495835">"Gjuhët dhe të dhënat"</string>
+    <string name="language_settings" msgid="3551012802762495835">"Gjuhët dhe metodat e hyrjes"</string>
     <string name="language_empty_list_user_restricted" msgid="3837176532474949716">"Nuk ke leje të ndryshosh gjuhën e pajisjes."</string>
-    <string name="language_keyboard_settings_title" msgid="2672573191605298938">"Gjuhët dhe të dhënat"</string>
+    <string name="language_keyboard_settings_title" msgid="2672573191605298938">"Gjuhët dhe metodat e hyrjes"</string>
     <string name="input_assistance" msgid="6442646949054057707">"Veglat"</string>
     <string name="keyboard_settings_category" msgid="5857591390023852850">"Tastiera dhe metodat e hyrjes"</string>
     <string name="phone_language" msgid="8471728119195198790">"Gjuhët"</string>
@@ -2033,7 +2038,7 @@
     <string name="accessibility_settings_title" msgid="1687226556576913576">"Cilësimet e qasjes"</string>
     <string name="accessibility_settings_summary" msgid="5742379519336396561">"Lexues ekrani, ekran, kontrolle ndërveprimi"</string>
     <string name="vision_settings_title" msgid="7315352351051423944">"Cilësimet e shikimit"</string>
-    <string name="vision_settings_description" msgid="3476589459009287332">"Mund ta personalizosh këtë pajisje për t\'iu përshtatur nevojave të tua. Këto funksione të qasjes mund të ndryshohen më vonë te \"Cilësimet\"."</string>
+    <string name="vision_settings_description" msgid="3476589459009287332">"Mund ta personalizosh këtë pajisje për t\'iu përshtatur nevojave të tua. Këto veçori të qasshmërisë mund të ndryshohen më vonë te \"Cilësimet\"."</string>
     <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"Ndrysho madhësinë e shkrimit"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"Lexuesit e ekranit"</string>
     <string name="audio_and_captions_category_title" msgid="6140472938769619212">"Audioja dhe teksti në ekran"</string>
@@ -2275,7 +2280,7 @@
     <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Aktivizo \"Kursyesin e baterisë\""</string>
     <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Bateria mund të mbarojë më herët se zakonisht"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"\"Kursyesi i baterisë\" është i aktivizuar"</string>
-    <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Disa funksione mund të jenë të kufizuara"</string>
+    <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Disa veçori mund të jenë të kufizuara"</string>
     <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Telefoni është përdorur më shumë se zakonisht"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"Tableti është përdorur më shumë se zakonisht"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"Pajisja është përdorur më shumë se zakonisht"</string>
@@ -2916,11 +2921,11 @@
     <string name="nfc_payment_default_not_set" msgid="955804193510335338">"Nuk është caktuar"</string>
     <string name="nfc_payment_app_and_desc" msgid="102312684211458190">"<xliff:g id="APP">%1$s</xliff:g> - <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="nfc_payment_use_default" msgid="3098724195746409476">"Përdor opsionin e parazgjedhur"</string>
-    <string name="nfc_payment_favor_default" msgid="7555356982142464260">"Gjithmonë!"</string>
+    <string name="nfc_payment_favor_default" msgid="7555356982142464260">"Gjithmonë"</string>
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Përveçse kur është i hapur një aplikacion tjetër pagese"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"Në terminalin \"Prek dhe paguaj\", paguaj me:"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Pagesa në terminal"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Konfiguro një aplikacion pagese. Më pas thjesht mbaj shtypur pjesën e pasme të telefonit me një terminal me simbolin e pagesave pa kontakt."</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Konfiguro një aplikacion pagese. Më pas thjesht mbaje pjesën e pasme të telefonit te një terminal me simbolin e pagesave pa kontakt."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"E kuptova!"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"Më shumë..."</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"Të caktohet si preferencë?"</string>
@@ -3002,7 +3007,7 @@
     <string name="sim_editor_number" msgid="1757338150165234970">"Numri"</string>
     <string name="sim_editor_color" msgid="373059962306191123">"Ngjyra e kartës SIM"</string>
     <string name="sim_card_select_title" msgid="4925862525985187946">"Zgjidh kartën SIM"</string>
-    <string name="color_orange" msgid="3159707916066563431">"portokalli"</string>
+    <string name="color_orange" msgid="3159707916066563431">"Portokalli"</string>
     <string name="color_purple" msgid="4391440966734810713">"Vjollcë"</string>
     <string name="sim_no_inserted_msg" msgid="1197884607569714609">"Nuk janë futur karta SIM"</string>
     <string name="sim_status_title" msgid="4483653750844520871">"Statusi i kartës SIM"</string>
@@ -3039,7 +3044,7 @@
     <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"Asistenti, aplikacionet së fundi, aplikacionet e parazgjedhura"</string>
     <string name="notification_settings_work_profile" msgid="7190550347842400029">"Qasja te njoftimet nuk ofrohet për aplikacionet në profilin e punës."</string>
     <string name="account_dashboard_title" msgid="4734300939532555885">"Llogaritë"</string>
-    <string name="account_dashboard_default_summary" msgid="6822549669771936206">"Nuk u shtua asnjë llogari"</string>
+    <string name="account_dashboard_default_summary" msgid="6822549669771936206">"Nuk është shtuar asnjë llogari"</string>
     <string name="app_default_dashboard_title" msgid="6575301028225232193">"Apl. e parazgjedhura"</string>
     <string name="system_dashboard_summary" msgid="6582464466735779394">"Gjuhët, gjestet, koha, rezervimi"</string>
     <string name="search_results_title" msgid="4160717656435503940">"Cilësimet"</string>
@@ -3123,7 +3128,7 @@
     <string name="keywords_ring_vibration" msgid="4210509151866460210">"prekje, dridhje, telefon, telefonatë, ndjeshmëri, zile"</string>
     <string name="keywords_notification_vibration" msgid="1077515502086745166">"prekje, dridhje, ndjeshmëri"</string>
     <string name="keywords_battery_saver_sticky" msgid="8733804259716284872">"kursyesi i baterisë, i ngjitur, vazhdoj, kursyesi i energjisë, bateria"</string>
-    <string name="default_sound" msgid="6675629744816442953">"Zëri i parazgjedhur"</string>
+    <string name="default_sound" msgid="6675629744816442953">"Tingulli i parazgjedhur"</string>
     <string name="sound_settings_summary" msgid="8467549670633195109">"Volumi i ziles në <xliff:g id="PERCENTAGE">%1$s</xliff:g>"</string>
     <string name="sound_dashboard_summary" msgid="5187301919242823508">"Volum, dridhje, \"Mos shqetëso\""</string>
     <string name="sound_settings_summary_vibrate" msgid="2194491116884798590">"Zilja u caktua me dridhje"</string>
@@ -3136,7 +3141,7 @@
     <string name="ring_volume_option_title" msgid="2038924918468372264">"Volumi i ziles"</string>
     <string name="notification_volume_option_title" msgid="1358512611511348260">"Volumi i njoftimit"</string>
     <string name="ringtone_title" msgid="1409086028485922583">"Zilja e telefonit"</string>
-    <string name="notification_ringtone_title" msgid="2932960620843976285">"Zëri i parazgjedhur i njoftimit"</string>
+    <string name="notification_ringtone_title" msgid="2932960620843976285">"Tingulli i parazgjedhur i njoftimit"</string>
     <string name="notification_unknown_sound_title" msgid="8043718667804838398">"Tingulli i dhënë nga aplikacioni"</string>
     <string name="notification_sound_default" msgid="2664544380802426260">"Tingulli i parazgjedhur i njoftimit"</string>
     <string name="alarm_ringtone_title" msgid="6411326147408635902">"Tingulli i parazgjedhur i alarmit"</string>
@@ -3550,7 +3555,7 @@
     <string name="switch_on_text" msgid="7100491749799298324">"Aktivizuar"</string>
     <string name="switch_off_text" msgid="3539551289454353555">"Joaktiv"</string>
     <string name="screen_pinning_title" msgid="578020318289781102">"Gozhdimi i ekranit"</string>
-    <string name="screen_pinning_description" msgid="3814537379086412278">"Kur ky funksion është i aktivizuar, mund të përdorësh gozhdimin e ekranit për të mbajtur pamjen aktuale të ekranit deri sa ta anulosh gozhdimin.\n\nPër të përdorur gozhdimin e ekranit:\n\n1. Sigurohu që gozhdimi i ekranit është i aktivizuar\n\n2. Hap \"Përmbledhja\"\n\n3. Trokit tek ikona e aplikacionit në krye të ekranit dhe më pas trokit te \"Gozhdo\""</string>
+    <string name="screen_pinning_description" msgid="3814537379086412278">"Kur ky cilësim është i aktivizuar, mund të përdorësh gozhdimin e ekranit për të mbajtur pamjen aktuale të ekranit deri sa ta anulosh gozhdimin.\n\nPër të përdorur gozhdimin e ekranit:\n\n1. Sigurohu që gozhdimi i ekranit është i aktivizuar\n\n2. Hap \"Përmbledhja\"\n\n3. Trokit tek ikona e aplikacionit në krye të ekranit dhe më pas trokit te \"Gozhdo\""</string>
     <string name="screen_pinning_unlock_pattern" msgid="1060334707088339444">"Kërko motivin e shkyçjes para anulimit të mbërthimit"</string>
     <string name="screen_pinning_unlock_pin" msgid="1441705536015645023">"Zhgozhdimi kërkon PIN-in"</string>
     <string name="screen_pinning_unlock_password" msgid="1017776884000170841">"Kërko fjalëkalim para heqjes nga gozhdimi"</string>
diff --git a/tests/CarDeveloperOptions/res/values-sr/arrays.xml b/tests/CarDeveloperOptions/res/values-sr/arrays.xml
index e6f117a..9ba8c58 100644
--- a/tests/CarDeveloperOptions/res/values-sr/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-sr/arrays.xml
@@ -214,7 +214,7 @@
   </string-array>
   <string-array name="app_ops_categories">
     <item msgid="1102693344156734891">"Локација"</item>
-    <item msgid="6842381562497597649">"Лични"</item>
+    <item msgid="6842381562497597649">"Лично"</item>
     <item msgid="3966700236695683444">"Размена порука"</item>
     <item msgid="8563996233342430477">"Медији"</item>
     <item msgid="5323851085993963783">"Уређај"</item>
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"рад у позадини"</item>
     <item msgid="6423861043647911030">"јачина звука за приступачност"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Локација"</item>
+    <item msgid="6656077694190491067">"Локација"</item>
+    <item msgid="8790228218278477369">"Локација"</item>
+    <item msgid="7836406246005211990">"Вибрација"</item>
+    <item msgid="3951439024549922598">"Читање контаката"</item>
+    <item msgid="8802152411647068">"Мењање контаката"</item>
+    <item msgid="229544934599698735">"Читање евиденције позива"</item>
+    <item msgid="7396102294405899613">"Мењање евиденције позива"</item>
+    <item msgid="3597797992398484655">"Читање календара"</item>
+    <item msgid="2705975774250907343">"Мењање календара"</item>
+    <item msgid="4668747371441932697">"Локација"</item>
+    <item msgid="1487578921720243646">"Постављање обавештења"</item>
+    <item msgid="4636080349724146638">"Локација"</item>
+    <item msgid="673510900286463926">"Позивање телефона"</item>
+    <item msgid="542083422784609790">"Читање SMS/MMS порука"</item>
+    <item msgid="1033780373029588436">"Писање SMS/MMS порука"</item>
+    <item msgid="5647111115517787488">"Пријем SMS/MMS порука"</item>
+    <item msgid="8591105601108455893">"Пријем SMS/MMS порука"</item>
+    <item msgid="7730995008517841903">"Пријем SMS/MMS порука"</item>
+    <item msgid="2613033109026626086">"Пријем SMS/MMS порука"</item>
+    <item msgid="3037159047591081136">"Слање SMS/MMS порука"</item>
+    <item msgid="4726682243833913568">"Читање SMS/MMS порука"</item>
+    <item msgid="6555678522277865572">"Писање SMS/MMS порука"</item>
+    <item msgid="6981734935578130884">"Мењање подешавања"</item>
+    <item msgid="8705854389991425629">"Повлачење на врх"</item>
+    <item msgid="5861356020344153651">"Приступ обавештењима"</item>
+    <item msgid="78432174621628659">"Камера"</item>
+    <item msgid="3986116419882154794">"Снимање аудио записа"</item>
+    <item msgid="4516840825756409490">"Пуштање аудио записа"</item>
+    <item msgid="6811712502798183957">"Читање меморије"</item>
+    <item msgid="2780369012602289114">"Мењање меморије"</item>
+    <item msgid="2331359440170850868">"Дугмад за медије"</item>
+    <item msgid="6133599737122751231">"Аудио фокус"</item>
+    <item msgid="6844485713404805301">"Главна јачина звука"</item>
+    <item msgid="1600379420669104929">"Јачина звука гласа"</item>
+    <item msgid="6296768210470214866">"Јачина звука звона"</item>
+    <item msgid="510690696071629241">"Јачина звука медија"</item>
+    <item msgid="406861638631430109">"Јачина звука аларма"</item>
+    <item msgid="4715864795872233884">"Јачина звука за обавештења"</item>
+    <item msgid="2311478519251301183">"Јачина звука Bluetooth-а"</item>
+    <item msgid="5133991377896747027">"Задржи ван стања спавања"</item>
+    <item msgid="2464189519136248621">"Локација"</item>
+    <item msgid="2062677934050803037">"Локација"</item>
+    <item msgid="1735171933192715957">"Преузми статистику о коришћењу"</item>
+    <item msgid="1014093788778383554">"Искључи/укључи звук микрофона"</item>
+    <item msgid="4199297950608622850">"Приказивање искачућих пoрука"</item>
+    <item msgid="2527962435313398821">"Медији за пројекат"</item>
+    <item msgid="5117506254221861929">"Активирање VPN-а"</item>
+    <item msgid="8291198322681891160">"Упис на позадину"</item>
+    <item msgid="7106921284621230961">"Структура помоћи"</item>
+    <item msgid="4496533640894624799">"Снимак екрана помоћи"</item>
+    <item msgid="2598847264853993611">"Читање стања телефона"</item>
+    <item msgid="9215610846802973353">"Додавање говорне поште"</item>
+    <item msgid="9186411956086478261">"Коришћење SIP-а"</item>
+    <item msgid="6884763100104539558">"Обрада одлазног позива"</item>
+    <item msgid="125513972170580692">"Отисак прста"</item>
+    <item msgid="2556071024281275619">"Сензори за тело"</item>
+    <item msgid="617168514928339387">"Читање порука за мобилне уређаје на локалитету"</item>
+    <item msgid="7134693570516523585">"Лажна локација"</item>
+    <item msgid="7224489175375229399">"Читање меморијског простора"</item>
+    <item msgid="8472735063903258202">"Упис података у меморијски простор"</item>
+    <item msgid="4069276819909595110">"Укључивање екрана"</item>
+    <item msgid="1228338896751121025">"Приступ налозима"</item>
+    <item msgid="3181581793459233672">"Рад у позадини"</item>
+    <item msgid="2340936043025374076">"Јачина звука за приступачност"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Кратко"</item>
     <item msgid="4816511817309094890">"Средњи"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Никада не дозволи"</item>
     <item msgid="8184570120217958741">"Увек дозволи"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Нормално"</item>
+    <item msgid="5101233285497327432">"Умерено"</item>
+    <item msgid="1555861583162930714">"Ниска"</item>
+    <item msgid="1719683776264798117">"Критична"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Нормална"</item>
+    <item msgid="6107138933849816768">"Умерена"</item>
+    <item msgid="182695359839047859">"Ниска"</item>
+    <item msgid="8577246509202964244">"Критично"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Непрекидна"</item>
     <item msgid="167418068739176448">"Највећа активност"</item>
diff --git a/tests/CarDeveloperOptions/res/values-sr/config.xml b/tests/CarDeveloperOptions/res/values-sr/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-sr/config.xml
+++ b/tests/CarDeveloperOptions/res/values-sr/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-sr/strings.xml b/tests/CarDeveloperOptions/res/values-sr/strings.xml
index 699cf07..cf41c11 100644
--- a/tests/CarDeveloperOptions/res/values-sr/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-sr/strings.xml
@@ -84,8 +84,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Омогућава да текст на екрану буде мањи или већи."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Умањи"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Увећај"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Пример текста"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Чаробњак из Оза"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Поглавље 11: Чудесни Смарагдни град Оза"</string>
@@ -507,7 +506,7 @@
     <string name="fingerprint_delete_title" msgid="3120894112324235536">"Уклоните „<xliff:g id="FINGERPRINT_ID">%1$s</xliff:g>“"</string>
     <string name="fingerprint_delete_message" msgid="5895802741486967970">"Желите ли да избришете овај отисак прста?"</string>
     <string name="fingerprint_last_delete_message" msgid="3346252479778971442">"Нећете моћи да откључавате телефон, одобравате куповине нити да се пријављујете у апликације помоћу отисака прстију"</string>
-    <string name="fingerprint_last_delete_message_profile_challenge" msgid="5385095150532247025">"Нећете моћи да откључавате профил за Work, одобравате куповине нити да се пријављујете у апликације за Work помоћу отисака прстију"</string>
+    <string name="fingerprint_last_delete_message_profile_challenge" msgid="5385095150532247025">"Нећете моћи да откључавате пословни профил, одобравате куповине нити да се пријављујете у пословне апликације помоћу отисака прстију"</string>
     <string name="fingerprint_last_delete_confirm" msgid="7984595457589664004">"Да, уклони"</string>
     <string name="crypt_keeper_settings_title" msgid="839783588093862748">"Шифровање"</string>
     <string name="crypt_keeper_encrypt_title" product="tablet" msgid="2292129135369853167">"Шифруј таблет"</string>
@@ -549,7 +548,7 @@
     <string name="suggested_fingerprint_lock_settings_summary" product="device" msgid="8114514312665251311"></string>
     <string name="suggested_fingerprint_lock_settings_summary" product="default" msgid="8114514312665251311"></string>
     <string name="lock_settings_picker_title" msgid="1034741644461982205">"Закључавање екрана"</string>
-    <string name="lock_settings_picker_title_profile" msgid="5086594364428782115">"Изаберите закључавање за Work"</string>
+    <string name="lock_settings_picker_title_profile" msgid="5086594364428782115">"Изаберите закључавање за посао"</string>
     <string name="setup_lock_settings_picker_title" product="tablet" msgid="2429667472335773519">"Заштитите таблет"</string>
     <string name="setup_lock_settings_picker_title" product="device" msgid="4739290104106645233">"Заштитите уређај"</string>
     <string name="setup_lock_settings_picker_title" product="default" msgid="3911582328576859628">"Заштитите телефон"</string>
@@ -564,7 +563,7 @@
     <string name="unlock_set_unlock_launch_picker_title" msgid="2731152716948003853">"Закључавање екрана"</string>
     <string name="unlock_set_unlock_launch_picker_summary_lock_immediately" msgid="5596186270725220642">"<xliff:g id="UNLOCK_METHOD">%1$s</xliff:g>/одмах после спавања"</string>
     <string name="unlock_set_unlock_launch_picker_summary_lock_after_timeout" msgid="3861167251234952373">"<xliff:g id="UNLOCK_METHOD">%1$s</xliff:g>/<xliff:g id="TIMEOUT_STRING">%2$s</xliff:g> после спавања"</string>
-    <string name="unlock_set_unlock_launch_picker_title_profile" msgid="7976345264630422921">"Закључавање профила за Work"</string>
+    <string name="unlock_set_unlock_launch_picker_title_profile" msgid="7976345264630422921">"Закључавање пословног профила"</string>
     <string name="unlock_set_unlock_launch_picker_change_title" msgid="32310692507029407">"Промена закључ. екрана"</string>
     <string name="unlock_set_unlock_launch_picker_change_summary" msgid="2072792784866320522">"Мењање или онемогућавање шаблона, PIN кода или безбедности лозинке"</string>
     <string name="unlock_set_unlock_launch_picker_enable_summary" msgid="9070847611379078795">"Изаберите метод закључавања екрана"</string>
@@ -648,12 +647,12 @@
     <string name="lock_last_pattern_attempt_before_wipe_user" msgid="5194192938934564218">"Ако у следећем покушају унесете нетачан шаблон, избрисаћемо овог корисника"</string>
     <string name="lock_last_pin_attempt_before_wipe_user" msgid="7833852187363499906">"Ако у следећем покушају унесете нетачан PIN, избрисаћемо овог корисника"</string>
     <string name="lock_last_password_attempt_before_wipe_user" msgid="8979742220140001204">"Ако у следећем покушају унесете нетачну лозинку, избрисаћемо овог корисника"</string>
-    <string name="lock_last_pattern_attempt_before_wipe_profile" msgid="3877613047631174576">"Ако у следећем покушају унесете нетачан шаблон, избрисаћемо профил за Work и његове податке"</string>
-    <string name="lock_last_pin_attempt_before_wipe_profile" msgid="8132438288175428168">"Ако у следећем покушају унесете нетачан PIN, избрисаћемо профил за Work и његове податке"</string>
-    <string name="lock_last_password_attempt_before_wipe_profile" msgid="1535128774464384305">"Ако у следећем покушају унесете нетачну лозинку, избрисаћемо профил за Work и његове податке"</string>
+    <string name="lock_last_pattern_attempt_before_wipe_profile" msgid="3877613047631174576">"Ако у следећем покушају унесете нетачан шаблон, избрисаћемо пословни профил и његове податке"</string>
+    <string name="lock_last_pin_attempt_before_wipe_profile" msgid="8132438288175428168">"Ако у следећем покушају унесете нетачан PIN, избрисаћемо пословни профил и његове податке"</string>
+    <string name="lock_last_password_attempt_before_wipe_profile" msgid="1535128774464384305">"Ако у следећем покушају унесете нетачну лозинку, избрисаћемо пословни профил и његове податке"</string>
     <string name="lock_failed_attempts_now_wiping_device" msgid="8662360098784762828">"Превише нетачних покушаја. Избрисаћемо податке са овог уређаја."</string>
     <string name="lock_failed_attempts_now_wiping_user" msgid="3793513796171561873">"Превише нетачних покушаја. Избрисаћемо овог корисника."</string>
-    <string name="lock_failed_attempts_now_wiping_profile" msgid="5347108525299038285">"Превише нетачних покушаја. Избрисаћемо овај профил за Work и његове податке."</string>
+    <string name="lock_failed_attempts_now_wiping_profile" msgid="5347108525299038285">"Превише нетачних покушаја. Избрисаћемо овај пословни профил и његове податке."</string>
     <string name="lock_failed_attempts_now_wiping_dialog_dismiss" msgid="3950582268749037318">"Одбаци"</string>
     <plurals name="lockpassword_password_too_short" formatted="false" msgid="694091983183310827">
       <item quantity="one">Мора да садржи најмање <xliff:g id="COUNT_1">%d</xliff:g> знак</item>
@@ -676,7 +675,6 @@
       <item quantity="few">Мора да садржи мање од <xliff:g id="NUMBER_1">%d</xliff:g> цифре</item>
       <item quantity="other">Мора да садржи мање од <xliff:g id="NUMBER_1">%d</xliff:g> цифара</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Мора да садржи само цифре 0–9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Администратор уређаја не дозвољава употребу недавно коришћеног PIN-а"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"ИТ администратор блокира честе PIN-ове. Изаберите други PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Не сме да обухвата неважећи знак"</string>
@@ -713,6 +711,11 @@
       <item quantity="few">Мора да садржи најмање <xliff:g id="COUNT">%d</xliff:g> знака који нису словa</item>
       <item quantity="other">Мора да садржи најмање <xliff:g id="COUNT">%d</xliff:g> знакова који нису словa</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">Мора да садржи најмање <xliff:g id="COUNT">%d</xliff:g> знак који није број</item>
+      <item quantity="few">Мора да садржи најмање <xliff:g id="COUNT">%d</xliff:g> знака који нису бројеви</item>
+      <item quantity="other">Мора да садржи најмање <xliff:g id="COUNT">%d</xliff:g> знакова који нису бројеви</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Администратор уређаја не дозвољава употребу недавно коришћене лозинке"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"ИТ администратор блокира честе лозинке. Изаберите другу лозинку."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Растући, опадајући или поновљени низ цифара није дозвољен"</string>
@@ -743,7 +746,7 @@
     <string name="bluetooth_settings" msgid="5228032727293770389">"Bluetooth"</string>
     <string name="bluetooth_settings_title" msgid="7261244857456521825">"Bluetooth"</string>
     <string name="bluetooth_settings_summary" msgid="1221689092429277887">"Управљање везама, подешавање назива и видљивости уређаја"</string>
-    <string name="bluetooth_pairing_request" msgid="7221745525632573125">"Упарити са уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>?"</string>
+    <string name="bluetooth_pairing_request" msgid="7221745525632573125">"Желите да упарите са <xliff:g id="DEVICE_NAME">%1$s</xliff:g>?"</string>
     <string name="bluetooth_pairing_key_msg" msgid="1139230917419961975">"Кôд за упаривање са Bluetooth уређајем"</string>
     <string name="bluetooth_enter_passkey_msg" msgid="6205151011298670207">"Унесите кôд за упаривање, па притисните Return или Enter"</string>
     <string name="bluetooth_enable_alphanumeric_pin" msgid="9138308197078115672">"PIN садржи слова или симболе"</string>
@@ -941,7 +944,7 @@
     <string name="wifi_ap_choose_auto" msgid="7927637960569365785">"Аутоматски"</string>
     <string name="wifi_ap_choose_2G" msgid="43198403259714736">"Опсег од 2,4 GHz"</string>
     <string name="wifi_ap_choose_5G" msgid="2624859713183683146">"Опсег од 5,0 GHz"</string>
-    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"Предност се даје опсегу од 5.0 GHz"</string>
+    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"Предност има опсег од 5,0 GHz"</string>
     <string name="wifi_ap_2G" msgid="5793110086517338494">"2,4 GHz"</string>
     <string name="wifi_ap_5G" msgid="4584892544393675403">"5,0 GHz"</string>
     <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"Изаберите барем један опсег за Wi‑Fi хотспот:"</string>
@@ -959,8 +962,8 @@
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"Читање QR кода није успело. Поново центрирајте кôд, па пробајте поново"</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"Пробајте поново. Ако се проблем настави, контактирајте произвођача уређаја"</string>
     <string name="wifi_dpp_failure_not_compatible" msgid="4320027179973678283">"Дошло је до грешке"</string>
-    <string name="wifi_dpp_failure_timeout" msgid="5060065168142109420">"Уверите се да је уређај прикључен на извор напајања, напуњен и укључен"</string>
-    <string name="wifi_dpp_failure_generic" msgid="7840142544736640189">"Уверите се да је уређај прикључен на извор напајања, напуњен и укључен. Ако се проблем настави, контактирајте произвођача уређаја"</string>
+    <string name="wifi_dpp_failure_timeout" msgid="5060065168142109420">"Уверите се да је уређај прикључен на струју, напуњен и укључен"</string>
+    <string name="wifi_dpp_failure_generic" msgid="7840142544736640189">"Уверите се да је уређај прикључен на струју, напуњен и укључен. Ако се проблем настави, контактирајте произвођача уређаја"</string>
     <string name="wifi_dpp_failure_not_supported" msgid="111779621766171626">"Овај уређај не подржава додавање мреже „<xliff:g id="SSID">%1$s</xliff:g>“"</string>
     <string name="wifi_dpp_check_connection_try_again" msgid="7144663015219170999">"Проверите везу и пробајте поново"</string>
     <string name="wifi_dpp_choose_network" msgid="6251424431594491691">"Одаберите мрежу"</string>
@@ -977,7 +980,7 @@
     <string name="wifi_dpp_lockscreen_title" msgid="3910665850075275963">"Потврдите да сте то ви"</string>
     <string name="wifi_dpp_wifi_password" msgid="8007558344032612455">"Лозинка за Wi-Fi: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
     <string name="wifi_dpp_hotspot_password" msgid="6172326289042241924">"Лозинка хотспота: <xliff:g id="PASSWORD">%1$s</xliff:g>"</string>
-    <string name="wifi_dpp_add_device" msgid="1347056725253936358">"Додајте уређај"</string>
+    <string name="wifi_dpp_add_device" msgid="1347056725253936358">"Додај уређај"</string>
     <string name="wifi_dpp_connect_network_using_qr_code" msgid="115993715600532357">"Повежите се на ову мрежу помоћу QR кода"</string>
     <string name="retry" msgid="8500839563577344702">"Пробај поново"</string>
     <string name="wifi_shared" msgid="5054256778276524960">"Дели са другим корисницима уређаја"</string>
@@ -1117,7 +1120,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Мобилни подаци"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Ако је Wi‑Fi недоступан, користите мобилну мрежу"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Ако мобилна мрежа није доступна, користи Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Позивање преко Wi-Fi-ја. Ако се Wi‑Fi веза изгуби, позив ће се завршити."</string>
@@ -1431,7 +1437,7 @@
     <string name="storage_menu_set_up" msgid="2849170579745958513">"Подеси"</string>
     <string name="storage_menu_explore" msgid="3733439525636202662">"Истражи"</string>
     <string name="storage_menu_free" msgid="6586253660759145508">"Ослободите простор"</string>
-    <string name="storage_menu_manage" msgid="461380717863926516">"Управљај складиштењем"</string>
+    <string name="storage_menu_manage" msgid="461380717863926516">"Управљај меморијским простором"</string>
     <string name="storage_title_usb" msgid="2015671467177303099">"USB уређај је повезан са рачунаром"</string>
     <string name="usb_connection_category" msgid="2888975803638116041">"Повежи као"</string>
     <string name="usb_mtp_title" msgid="6893938968831995500">"Медијски уређај (MTP)"</string>
@@ -1580,7 +1586,7 @@
     <string name="error_adding_apn_type" msgid="671634520340569678">"Мобилни оператер не дозвољава називе приступних тачака типа %s."</string>
     <string name="restore_default_apn" msgid="7195266404077471007">"Враћање подразумеваних подешавања назива приступне тачке."</string>
     <string name="menu_restore" msgid="3799288817317293115">"Ресетуј на подразумевано"</string>
-    <string name="restore_default_apn_completed" msgid="5671734152740058937">"Поновно постављање подразумеваних подешавања назива приступне тачке је завршено"</string>
+    <string name="restore_default_apn_completed" msgid="5671734152740058937">"Поновно постављање подразумеваних подешавања назива приступне тачке је завршено."</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"Опције за ресетовање"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"Мрежа, апликацијe или уређај могу да се ресетују"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"Ресетуј Wi-Fi, мобилну мрежу и Bluetooth"</string>
@@ -1623,17 +1629,17 @@
     <string name="master_clear_progress_text" msgid="5418958116008976218">"Сачекајте..."</string>
     <string name="call_settings_title" msgid="5033906789261282752">"Подешавања позива"</string>
     <string name="call_settings_summary" msgid="2119161087671450035">"Подешавање гласовне поште, преусмеравања позива, стављања позива на чекање, ИД-а позиваоца"</string>
-    <string name="tether_settings_title_usb" msgid="4265582654602420357">"USB Интернет повезивање"</string>
+    <string name="tether_settings_title_usb" msgid="4265582654602420357">"USB привезивање"</string>
     <string name="tether_settings_title_wifi" msgid="2060965130234484613">"Преносни хотспот"</string>
     <string name="tether_settings_title_bluetooth" msgid="1999590158102569959">"Bluetooth привезивање"</string>
-    <string name="tether_settings_title_usb_bluetooth" msgid="1159128764162788159">"Повезивање са интернетом"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="1159128764162788159">"Привезивање"</string>
     <string name="tether_settings_title_all" msgid="6935843543433954181">"Хотспот и привезивање"</string>
     <string name="tether_settings_summary_hotspot_on_tether_on" msgid="1289593649526514499">"Хотспот је укључен, привезивање"</string>
     <string name="tether_settings_summary_hotspot_on_tether_off" msgid="8010689354668285422">"Хотспот је укључен"</string>
     <string name="tether_settings_summary_hotspot_off_tether_on" msgid="1349909238672649877">"Привезивање"</string>
     <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"Није могуће привезивање нити коришћење преносивих хотспотова док је Уштеда података укључена"</string>
     <string name="usb_title" msgid="7480927657535578688">"USB"</string>
-    <string name="usb_tethering_button_text" msgid="6242228383142012332">"USB повезивање"</string>
+    <string name="usb_tethering_button_text" msgid="6242228383142012332">"USB привезивање"</string>
     <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"Дељење интернет везе телефона преко USB-а"</string>
     <string name="usb_tethering_subtext" product="tablet" msgid="154536000235361034">"Дељење интернет везе таблета преко USB-а"</string>
     <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"Bluetooth привезивање"</string>
@@ -1652,7 +1658,7 @@
     <string name="sms_change_default_no_previous_dialog_text" msgid="4680224695080527907">"Желите ли да користите <xliff:g id="NEW_APP">%s</xliff:g> као апликацију за SMS?"</string>
     <string name="network_scorer_picker_title" msgid="1691073966560952916">"Добављач оцене мреже"</string>
     <string name="network_scorer_picker_none_preference" msgid="6448280557733231737">"Ништа"</string>
-    <string name="network_scorer_change_active_dialog_title" msgid="4274159562371475090">"Желите да промените Wi‑Fi assistant-а?"</string>
+    <string name="network_scorer_change_active_dialog_title" msgid="4274159562371475090">"Желите да промените Wi‑Fi помоћник?"</string>
     <string name="network_scorer_change_active_dialog_text" msgid="4264089809189760730">"Желите ли да користите апликацију <xliff:g id="NEW_APP">%1$s</xliff:g> уместо апликације <xliff:g id="CURRENT_APP">%2$s</xliff:g> за управљање мрежним везама?"</string>
     <string name="network_scorer_change_active_no_previous_dialog_text" msgid="6394483538843474495">"Желите ли да користите апликацију <xliff:g id="NEW_APP">%s</xliff:g> за управљање мрежним везама?"</string>
     <string name="mobile_unknown_sim_operator" msgid="872589370085135817">"Непознати SIM оператер"</string>
@@ -1670,7 +1676,7 @@
     </plurals>
     <string name="location_category_recent_location_access" msgid="286059523360285026">"Недавни приступ локацији"</string>
     <string name="location_recent_location_access_view_details" msgid="2051602261436245905">"Прикажи детаље"</string>
-    <string name="location_no_recent_apps" msgid="77502059586413278">"Ниједна апликација није скоро тражила локацију"</string>
+    <string name="location_no_recent_apps" msgid="77502059586413278">"Ниједна апликација није недавно тражила локацију"</string>
     <string name="location_no_recent_accesses" msgid="6289916310397279890">"Ниједна апликација није недавно приступила локацији"</string>
     <string name="location_high_battery_use" msgid="7177199869979522663">"Велика потрошња батерије"</string>
     <string name="location_low_battery_use" msgid="5030448574501435888">"Мала потрошња батерије"</string>
@@ -1743,15 +1749,15 @@
     <string name="lockpassword_confirm_your_pattern_generic" msgid="6146545393074070916">"Употребите шаблон за уређај да бисте наставили"</string>
     <string name="lockpassword_confirm_your_pin_generic" msgid="8732268389177735264">"Унесите PIN уређаја да бисте наставили"</string>
     <string name="lockpassword_confirm_your_password_generic" msgid="6304552647060899594">"Унесите лозинку уређаја да бисте наставили"</string>
-    <string name="lockpassword_confirm_your_pattern_generic_profile" msgid="3074250084050465513">"Употребите шаблон за профил за Work да бисте наставили"</string>
-    <string name="lockpassword_confirm_your_pin_generic_profile" msgid="6037908971086439523">"Унесите PIN за профил за Work да бисте наставили"</string>
-    <string name="lockpassword_confirm_your_password_generic_profile" msgid="2646162490703489685">"Унесите лозинку за профил за Work да бисте наставили"</string>
+    <string name="lockpassword_confirm_your_pattern_generic_profile" msgid="3074250084050465513">"Употребите шаблон за пословни профил да бисте наставили"</string>
+    <string name="lockpassword_confirm_your_pin_generic_profile" msgid="6037908971086439523">"Унесите PIN за пословни профил да бисте наставили"</string>
+    <string name="lockpassword_confirm_your_password_generic_profile" msgid="2646162490703489685">"Унесите лозинку за пословни профил да бисте наставили"</string>
     <string name="lockpassword_strong_auth_required_device_pattern" msgid="1014214190135045781">"Ради веће безбедности користите шаблон за уређај"</string>
     <string name="lockpassword_strong_auth_required_device_pin" msgid="24030584350601016">"Ради веће безбедности унесите PIN за уређај"</string>
     <string name="lockpassword_strong_auth_required_device_password" msgid="7746588206458754598">"Ради веће безбедности унесите лозинку за уређај"</string>
-    <string name="lockpassword_strong_auth_required_work_pattern" msgid="6861154706098327320">"Ради веће безбедности користите шаблон за Work"</string>
-    <string name="lockpassword_strong_auth_required_work_pin" msgid="6306902249365524526">"Ради веће безбедности унесите PIN за Work"</string>
-    <string name="lockpassword_strong_auth_required_work_password" msgid="2917338218971012776">"Ради веће безбедности унесите лозинку за Work"</string>
+    <string name="lockpassword_strong_auth_required_work_pattern" msgid="6861154706098327320">"Ради веће безбедности користите шаблон за посао"</string>
+    <string name="lockpassword_strong_auth_required_work_pin" msgid="6306902249365524526">"Ради веће безбедности унесите пословни PIN"</string>
+    <string name="lockpassword_strong_auth_required_work_password" msgid="2917338218971012776">"Ради веће безбедности унесите пословну лозинку"</string>
     <string name="lockpassword_confirm_your_pattern_details_frp" msgid="1085862410379709928">"Телефон је ресетован на фабричка подешавања. Да бисте га користили, унесите претходни шаблон."</string>
     <string name="lockpassword_confirm_your_pin_details_frp" msgid="6849889353126558761">"Телефон је ресетован на фабричка подешавања. Да бисте га користили, унесите претходни PIN."</string>
     <string name="lockpassword_confirm_your_password_details_frp" msgid="3239944795659418737">"Телефон је ресетован на фабричка подешавања. Да бисте га користили, унесите претходну лозинку."</string>
@@ -1788,13 +1794,13 @@
     <string name="lockpattern_settings_help_how_to_record" msgid="6037403647312543908">"Како нацртати шаблон за откључавање"</string>
     <string name="lockpattern_too_many_failed_confirmation_attempts" msgid="3043127997770535921">"Превише нетачних покушаја. Пробајте поново за <xliff:g id="NUMBER">%d</xliff:g> сек."</string>
     <string name="activity_not_found" msgid="3492413375341165453">"Апликација није инсталирана на телефону."</string>
-    <string name="lock_settings_profile_title" msgid="3928992050074556160">"Безбедност профила за Work"</string>
-    <string name="lock_settings_profile_screen_lock_title" msgid="285267471459162203">"Закључавање екрана за профил за Work"</string>
+    <string name="lock_settings_profile_title" msgid="3928992050074556160">"Безбедност пословног профила"</string>
+    <string name="lock_settings_profile_screen_lock_title" msgid="285267471459162203">"Закључавање екрана за пословни профил"</string>
     <string name="lock_settings_profile_unification_title" msgid="2629698644191935287">"Користи једно закључавање"</string>
-    <string name="lock_settings_profile_unification_summary" msgid="4797188229308317207">"Користите једно закључавање екрана за профил за Work и уређај"</string>
+    <string name="lock_settings_profile_unification_summary" msgid="4797188229308317207">"Користите једно закључавање екрана за пословни профил и уређај"</string>
     <string name="lock_settings_profile_unification_dialog_title" msgid="1690211342491067179">"Желите ли да користите једно закључавање?"</string>
-    <string name="lock_settings_profile_unification_dialog_body" msgid="8629158560032603101">"Уређај ће користити закључавање екрана за Work профил. Смернице за Work ће се примењивати на оба закључавања."</string>
-    <string name="lock_settings_profile_unification_dialog_uncompliant_body" msgid="1217609779267643474">"Закључавање екрана за профил за Work није у складу са безбедносним захтевима ваше организације. Можете да користите исто закључавање екрана за уређај и профил за Work, али ће се примењивати све смернице за закључавање екрана за Work."</string>
+    <string name="lock_settings_profile_unification_dialog_body" msgid="8629158560032603101">"Уређај ће користити закључавање екрана за пословни профил. Смернице за посао ће се примењивати на оба закључавања."</string>
+    <string name="lock_settings_profile_unification_dialog_uncompliant_body" msgid="1217609779267643474">"Закључавање екрана за пословни профил није у складу са безбедносним захтевима ваше организације. Можете да користите исто закључавање екрана за уређај и пословни профил, али ће се примењивати све смернице за закључавање екрана за посао."</string>
     <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>
@@ -1988,7 +1994,7 @@
     <string name="show_ime_summary" msgid="3246628154011464373">"Задржи је на екрану док је физичка тастатура активна"</string>
     <string name="keyboard_shortcuts_helper" msgid="6574386807271399788">"Помоћ за тастерске пречице"</string>
     <string name="keyboard_shortcuts_helper_summary" msgid="8024313306403779742">"Приказ доступних пречица"</string>
-    <string name="language_and_input_for_work_category_title" msgid="2053255944038892588">"Тастатуре и алатке за профил за Work"</string>
+    <string name="language_and_input_for_work_category_title" msgid="2053255944038892588">"Тастатуре и алатке за пословни профил"</string>
     <string name="virtual_keyboards_for_work_title" msgid="3968291646938204523">"Виртуелна тастатура за посао"</string>
     <string name="default_keyboard_layout" msgid="9171704064451242230">"Подразумевано"</string>
     <string name="pointer_speed" msgid="800691982011350432">"Брзина показивача"</string>
@@ -2300,7 +2306,7 @@
     <string name="battery_tip_smart_battery_title" product="tablet" msgid="203494973250969040">"Продужите трајање батерије таблета"</string>
     <string name="battery_tip_smart_battery_title" product="device" msgid="7419448992583346364">"Продужите трајање батерије уређаја"</string>
     <string name="battery_tip_smart_battery_summary" msgid="5344821856478265778">"Укључите менаџер батерије"</string>
-    <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Укључи уштеду батерије"</string>
+    <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Укључите уштеду батерије"</string>
     <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Батерија може да се испразни раније него обично"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Уштеда батерије је укључена"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Неке функције могу да буду ограничене"</string>
@@ -2595,7 +2601,7 @@
     <string name="fullbackup_erase_dialog_message" msgid="2588536036471144070">"Желите ли да зауставите прављење резервних копија података уређаја (попут Wi-Fi лозинки и историје позива) и података апликација (попут подешавања и датотека сачуваних у апликацијама) и избришете све копије на удаљеним серверима?"</string>
     <string name="fullbackup_data_summary" msgid="406274198094268556">"Аутоматски правите резервне копије података уређаја (попут Wi-Fi лозинки и историје позива) и података апликација (попут подешавања и датотека сачуваних у апликацијама) даљински.\n\nКада укључите аутоматско прављење резервних копија, подаци уређаја и апликација се повремено чувају даљински. Подаци апликација могу да буду било који подаци које је апликација сачувала (на основу подешавања програмера), укључујући потенцијално осетљиве податке као што су контакти, поруке и слике."</string>
     <string name="device_admin_settings_title" msgid="2074319456047334589">"Подешавања администратора уређаја"</string>
-    <string name="active_device_admin_msg" msgid="6929247869516924549">"Апликација за администраторе уређаја"</string>
+    <string name="active_device_admin_msg" msgid="6929247869516924549">"Апликација за администратора уређаја"</string>
     <string name="remove_device_admin" msgid="4413438593788336400">"Деактивирај ову апликацију за администратора уређаја"</string>
     <string name="uninstall_device_admin" msgid="9017499299961719830">"Деинсталирај апликацију"</string>
     <string name="remove_and_uninstall_device_admin" msgid="5607703579731496253">"Деактивирај и деинсталирај"</string>
@@ -2610,7 +2616,7 @@
     <string name="add_device_admin" msgid="1621152410207260584">"Активирај ову апликацију за администраторе уређаја"</string>
     <string name="device_admin_add_title" msgid="6097881332139146897">"Администратор уређаја"</string>
     <string name="device_admin_warning" msgid="4421817419326480449">"Активирање ове апликације за администраторе омогућиће апликацији <xliff:g id="APP_NAME">%1$s</xliff:g> да обави следеће операције:"</string>
-    <string name="device_admin_status" msgid="5424944611789040723">"Ова апликација за администраторе је активна и омогућава апликацији <xliff:g id="APP_NAME">%1$s</xliff:g> да обави следеће операције:"</string>
+    <string name="device_admin_status" msgid="5424944611789040723">"Ова апликација за администратора је активна и омогућава апликацији <xliff:g id="APP_NAME">%1$s</xliff:g> да обави следеће операције:"</string>
     <string name="profile_owner_add_title" msgid="735805919754362791">"Активирати Менаџера профила?"</string>
     <string name="adding_profile_owner_warning" msgid="1284541194547382194">"Ако наставите, корисником ће управљати администратор, који ће можда моћи да чува и повезане податке, поред личних података.\n\nАдминистратор може да прати подешавања, приступ, апликације и податке повезане са овим корисником, укључујући активности на мрежи и информације о локацији уређаја, као и да управља њима."</string>
     <string name="admin_disabled_other_options" msgid="8097063307730025707">"Администратор је онемогућио друге опције"</string>
@@ -2628,10 +2634,10 @@
     <string name="sync_is_failing" msgid="8284618104132302644">"Синхронизација тренутно има проблема. Ускоро ће се вратити."</string>
     <string name="add_account_label" msgid="4461298847239641874">"Додај налог"</string>
     <string name="managed_profile_not_available_label" msgid="8784246681719821917">"Пословни профил још увек није доступан"</string>
-    <string name="work_mode_label" msgid="6845849194740195757">"Профил за Work"</string>
+    <string name="work_mode_label" msgid="6845849194740195757">"Пословни профил"</string>
     <string name="work_mode_on_summary" msgid="1682781113156323592">"Овим управља организација"</string>
     <string name="work_mode_off_summary" msgid="1688885392211178315">"Апликације и обавештења су искључени"</string>
-    <string name="remove_managed_profile_label" msgid="4625542553784793536">"Уклони профил за посао"</string>
+    <string name="remove_managed_profile_label" msgid="4625542553784793536">"Уклони пословни профил"</string>
     <string name="background_data" msgid="8275750862371471171">"Подаци о позадини"</string>
     <string name="background_data_summary" msgid="799640633948841990">"Апликације увек могу да синхронизују, шаљу и примају податке"</string>
     <string name="background_data_dialog_title" msgid="8306650658158895976">"Желите да онемогућите позадинске податке?"</string>
@@ -2871,7 +2877,7 @@
       <item quantity="other"><xliff:g id="MANAGING_DOMAIN_1">%s</xliff:g> су инсталирала ауторитете за издавање сертификата на уређају, што може да им омогући да прате активности уређаја на мрежи, укључујући имејлове, апликације и безбедне веб-сајтове.\n\nКонтактирајте администратора да бисте добили више информација о овим сертификатима.</item>
     </plurals>
     <plurals name="ssl_ca_cert_info_message" formatted="false" msgid="8271858091418779584">
-      <item quantity="one"><xliff:g id="MANAGING_DOMAIN_1">%s</xliff:g> је инсталирао ауторитете за издавање сертификата за профил за Work, што може да му омогући да прати активности на пословној мрежи, укључујући имејлове, апликације и безбедне веб-сајтове.\n\nКонтактирајте администратора да бисте добили више информација о овим сертификатима.</item>
+      <item quantity="one"><xliff:g id="MANAGING_DOMAIN_1">%s</xliff:g> је инсталирао ауторитете за издавање сертификата за пословни профил, што може да му омогући да прати активности на пословној мрежи, укључујући имејлове, апликације и безбедне веб-сајтове.\n\nКонтактирајте администратора да бисте добили више информација о овим сертификатима.</item>
       <item quantity="few"><xliff:g id="MANAGING_DOMAIN_1">%s</xliff:g> су инсталирала ауторитете за издавање сертификата на уређају, што може да им омогући да прате активности уређаја на мрежи, укључујући имејлове, апликације и безбедне веб-сајтове.\n\nКонтактирајте администратора да бисте добили више информација о овим сертификатима.</item>
       <item quantity="other"><xliff:g id="MANAGING_DOMAIN_1">%s</xliff:g> су инсталирала ауторитете за издавање сертификата на уређају, што може да им омогући да прате активности уређаја на мрежи, укључујући имејлове, апликације и безбедне веб-сајтове.\n\nКонтактирајте администратора да бисте добили више информација о овим сертификатима.</item>
     </plurals>
@@ -3128,7 +3134,7 @@
     <string name="keywords_color_temperature" msgid="2255253972992035046">"боја, температура, D65, D73, бела, жута, плава, топла, хладна"</string>
     <string name="keywords_lockscreen" msgid="4936846554280830394">"превлачење за откључавање, лозинка, шаблон, PIN"</string>
     <string name="keywords_profile_challenge" msgid="8653718001253979611">"work изазов, work, профил"</string>
-    <string name="keywords_unification" msgid="2020759909366983593">"профил за Work, профил којим се управља, обједини, обједињавање, Work, профил"</string>
+    <string name="keywords_unification" msgid="2020759909366983593">"пословни профил, профил којим се управља, обједини, обједињавање, посао, профил"</string>
     <string name="keywords_gesture" msgid="5031323247529869644">"покрети"</string>
     <string name="keywords_payment_settings" msgid="4745023716567666052">"платите, додирните, плаћања"</string>
     <string name="keywords_backup" msgid="7433356270034921627">"резервна копија, правити резервну копију"</string>
@@ -3184,7 +3190,7 @@
     <string name="other_sound_settings" msgid="5250376066099818676">"Други звукови"</string>
     <string name="dial_pad_tones_title" msgid="8877212139988655769">"Тонови нумеричке тастатуре"</string>
     <string name="screen_locking_sounds_title" msgid="4407110895465866809">"Звукови закључавања екрана"</string>
-    <string name="charging_sounds_title" msgid="5070437987230894287">"Мењајући звуци и вибрација"</string>
+    <string name="charging_sounds_title" msgid="5070437987230894287">"Звукови и вибрација пуњења"</string>
     <string name="docking_sounds_title" msgid="2573137471605541366">"Звукови монтирања"</string>
     <string name="touch_sounds_title" msgid="165237488496165652">"Звукови при додиру"</string>
     <string name="vibrate_on_touch_title" msgid="6360155469279157684">"Вибрација при додиру"</string>
@@ -3249,10 +3255,10 @@
     <string name="zen_mode_block_effects_screen_off" msgid="6380935819882837552">"Када је екран искључен"</string>
     <string name="zen_mode_block_effect_sound" msgid="1499243540186357631">"Искључи звук и вибрацију"</string>
     <string name="zen_mode_block_effect_intent" msgid="5666951244667422668">"Не укључуј екран"</string>
-    <string name="zen_mode_block_effect_light" msgid="8679333758037487644">"Не користи треперење лампице"</string>
+    <string name="zen_mode_block_effect_light" msgid="8679333758037487644">"Не трепери лампицом"</string>
     <string name="zen_mode_block_effect_peek" msgid="6075662813575910221">"Не приказуј искачућа обавештења на екрану"</string>
     <string name="zen_mode_block_effect_status" msgid="6516614225115681068">"Сакриј иконе статусне траке у врху"</string>
-    <string name="zen_mode_block_effect_badge" msgid="3891743027347075136">"Сакриј тачке за обав. на иконама апл."</string>
+    <string name="zen_mode_block_effect_badge" msgid="3891743027347075136">"Сакриј тачке за обавештења на иконама апликација"</string>
     <string name="zen_mode_block_effect_ambient" msgid="6382013125863616197">"Не буди због обавештења"</string>
     <string name="zen_mode_block_effect_list" msgid="6081548478844912181">"Не приказуј на листи обавештења"</string>
     <string name="zen_mode_block_effect_summary_none" msgid="7166175186759564510">"Никад"</string>
@@ -3310,7 +3316,7 @@
     <string name="zen_custom_settings_notifications_header" msgid="7469592764589354302">"Обавештења"</string>
     <string name="zen_custom_settings_duration_header" msgid="1806465684026300942">"Трајање"</string>
     <string name="zen_msg_event_reminder_title" msgid="8685224436389816905">"Поруке, догађаји и подсетници"</string>
-    <string name="zen_msg_event_reminder_footer" msgid="164400918479831580">"Када је укључен режим Не узнемиравај, звукови обавештења за поруке, подсетнике и догађаје ће бити искључени, осим за ставке које сте дозволили изнад. Можете да прилагодите подешавања да бисте дозволили пријатељима, члановима породице или другим контактима да вас контактирају."</string>
+    <string name="zen_msg_event_reminder_footer" msgid="164400918479831580">"Када је укључен режим Не узнемиравај, звукови обавештења за поруке, подсетнике и догађаје ће бити искључени, осим за ставке које сте дозволили изнад. Можете да прилагодите подешавања и дозволите пријатељима, члановима породице или другим контактима да допру до вас."</string>
     <string name="zen_onboarding_ok" msgid="6403635918125323678">"Готово"</string>
     <string name="zen_onboarding_settings" msgid="1416466597876383322">"Подешавања"</string>
     <string name="zen_onboarding_new_setting_title" msgid="3622673375041304362">"Без звучног сигнала или визуелног обавештења"</string>
@@ -3318,16 +3324,16 @@
     <string name="zen_onboarding_new_setting_summary" msgid="8264430315983860075">"Нећете видети нити чути обавештења. Позиви од контаката са звездицом и поновних позивалаца су дозвољени."</string>
     <string name="zen_onboarding_current_setting_summary" msgid="3569246708507270821">"(тренутно подешавање)"</string>
     <string name="zen_onboarding_dnd_visual_disturbances_header" msgid="7584229011611927613">"Желите ли да промените подешавања обавештења за режим Не узнемиравај?"</string>
-    <string name="sound_work_settings" msgid="4140215240360927923">"Звуци за профил за Work"</string>
+    <string name="sound_work_settings" msgid="4140215240360927923">"Звуци за пословни профил"</string>
     <string name="work_use_personal_sounds_title" msgid="531727195073003599">"Користи звуке личног профила"</string>
-    <string name="work_use_personal_sounds_summary" msgid="2886871383995187441">"Звукови профила за Work су исти као и звукови за личне профиле"</string>
-    <string name="work_ringtone_title" msgid="5499360583947410224">"Мелодија звона за телефон за Work"</string>
+    <string name="work_use_personal_sounds_summary" msgid="2886871383995187441">"Звукови пословног профила су исти као и звукови за личне профиле"</string>
+    <string name="work_ringtone_title" msgid="5499360583947410224">"Мелодија звона пословног телефона"</string>
     <string name="work_notification_ringtone_title" msgid="8059159087214025757">"Подразумевани звук обавештења за посао"</string>
     <string name="work_alarm_ringtone_title" msgid="5328487181385375130">"Подразумевани звук аларма за посао"</string>
     <string name="work_sound_same_as_personal" msgid="7728560881697159758">"Исто као и за лични профил"</string>
     <string name="work_sync_dialog_title" msgid="4799120971202956837">"Желите ли да замените звукове?"</string>
     <string name="work_sync_dialog_yes" msgid="2110726233746476066">"Замени"</string>
-    <string name="work_sync_dialog_message" msgid="944233463059129156">"Звуци са личног профила ће се користити за профил за Work"</string>
+    <string name="work_sync_dialog_message" msgid="944233463059129156">"Звуци са личног профила ће се користити за пословни профил"</string>
     <string name="ringtones_install_custom_sound_title" msgid="210551218424553671">"Додати прилагођени звук?"</string>
     <string name="ringtones_install_custom_sound_content" msgid="6683649115132255452">"Ова датотека ће бити копирана у директоријум <xliff:g id="FOLDER_NAME">%s</xliff:g>"</string>
     <string name="ringtones_category_preference_title" msgid="4491932700769815470">"Мелодије звона"</string>
@@ -3336,7 +3342,7 @@
     <string name="recent_notifications" msgid="8125865995065032049">"Недавно послато"</string>
     <string name="recent_notifications_see_all_title" msgid="4089007770442871469">"Погледајте све из последњих 7 дана"</string>
     <string name="advanced_section_header" msgid="984680389373090015">"Напредна"</string>
-    <string name="profile_section_header" msgid="5471479005472037417">"Обавештења за Work"</string>
+    <string name="profile_section_header" msgid="5471479005472037417">"Пословна обавештења"</string>
     <string name="asst_capability_prioritizer_title" msgid="3488284760645922160">"Аутоматско давање приоритета за обавештења"</string>
     <string name="asst_capability_prioritizer_summary" msgid="3525640645743790796">"Аутоматски искључује звук и поставља на дно мање важна обавештења"</string>
     <string name="asst_capabilities_actions_replies_title" msgid="3929395108744251338">"Паметне радње и одговори"</string>
@@ -3358,14 +3364,14 @@
     <string name="swipe_direction_rtl" msgid="4521416787262888813">"Превуците улево да бисте одбацили, удесно да би се приказао мени"</string>
     <string name="notification_pulse_title" msgid="4861418327614907116">"Укључи треперење лампице"</string>
     <string name="lock_screen_notifications_title" msgid="6889072265118747835">"На закључаном екрану"</string>
-    <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"Када је профил за Work закључан"</string>
+    <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"Када је пословни профил закључан"</string>
     <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Прикажи сав садржај обавештења"</string>
     <string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"Сакриј осетљив садржај"</string>
     <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"Не приказуј никаква обавештења"</string>
     <string name="lock_screen_notifications_interstitial_message" msgid="4230189215124387818">"Када је уређај закључан, како желите да се обавештења приказују?"</string>
     <string name="lock_screen_notifications_interstitial_title" msgid="2832587379332443505">"Обавештења"</string>
-    <string name="lock_screen_notifications_summary_show_profile" msgid="8908775469657073273">"Приказуј сав садржај обавештења о профилу за Work"</string>
-    <string name="lock_screen_notifications_summary_hide_profile" msgid="7898086300511010591">"Сакриј осетљив садржај профила за Work"</string>
+    <string name="lock_screen_notifications_summary_show_profile" msgid="8908775469657073273">"Приказуј сав садржај обавештења о пословном профилу"</string>
+    <string name="lock_screen_notifications_summary_hide_profile" msgid="7898086300511010591">"Сакриј осетљив садржај пословног профила"</string>
     <string name="lock_screen_notifications_interstitial_message_profile" msgid="3324187664458600354">"Када је уређај закључан, како желите да се приказују обавештења о профилу?"</string>
     <string name="lock_screen_notifications_interstitial_title_profile" msgid="4043621508889929254">"Обавештења о профилу"</string>
     <string name="notifications_title" msgid="8334011924253810654">"Обавештења"</string>
@@ -3399,7 +3405,7 @@
     <string name="notifications_sent_weekly" msgid="5859675428990259432">"~<xliff:g id="NUMBER">%1$s</xliff:g> недељно"</string>
     <string name="notifications_sent_never" msgid="237997329598144638">"Никад"</string>
     <string name="manage_notification_access_title" msgid="5348743662189787547">"Приступ обавештењима"</string>
-    <string name="work_profile_notification_access_blocked_summary" msgid="8148871282484870576">"Приступ обавештењима профила за Work је блокиран"</string>
+    <string name="work_profile_notification_access_blocked_summary" msgid="8148871282484870576">"Приступ обавештењима пословног профила је блокиран"</string>
     <string name="manage_notification_access_summary_zero" msgid="236809421271593016">"Апликације не могу да читају обавештења"</string>
     <plurals name="manage_notification_access_summary_nonzero" formatted="false" msgid="8496218948429646792">
       <item quantity="one">%d апликација може да чита обавештења</item>
@@ -3485,7 +3491,7 @@
     <string name="zen_mode_add_time_rule" msgid="5999467757140524729">"Додајте временски распоред"</string>
     <string name="zen_mode_delete_rule" msgid="2292933835997203801">"Избриши распоред"</string>
     <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"Одаберите тип распореда"</string>
-    <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"Желите ли да избришете правило „<xliff:g id="RULE">%1$s</xliff:g>“?"</string>
+    <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"Желите да избришете правило „<xliff:g id="RULE">%1$s</xliff:g>“?"</string>
     <string name="zen_mode_delete_rule_button" msgid="611058106279881991">"Избриши"</string>
     <string name="zen_mode_rule_type_unknown" msgid="2819480113355191421">"Непознато"</string>
     <string name="zen_mode_app_set_behavior" msgid="8597398780262575571">"Ова подешавања тренутно не могу да се мењају. Апликација (<xliff:g id="APP_NAME">%1$s</xliff:g>) је аутоматски укључила режим Не узнемиравај са прилагођеним понашањем."</string>
@@ -3522,7 +3528,7 @@
     <string name="zen_mode_calls" msgid="1844534357711539325">"Дозволи позиве"</string>
     <string name="zen_mode_calls_title" msgid="2024387562355793661">"Позиви"</string>
     <string name="zen_mode_calls_footer" msgid="6319824006810688433">"Да бисте били сигурни да ће се дозвољени позиви чути, проверите да ли је уређај подешен да звони, вибрира или је у нечујном режиму."</string>
-    <string name="zen_mode_custom_calls_footer" msgid="7329231648477682337">"Долазни позиви су блокирани за „<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>“. Можете да прилагодите подешавања да бисте дозволили пријатељима, члановима породице или другим контактима да вас контактирају."</string>
+    <string name="zen_mode_custom_calls_footer" msgid="7329231648477682337">"Долазни позиви су блокирани за „<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>“. Можете да прилагодите подешавања и дозволите пријатељима, члановима породице или другим контактима да допру до вас."</string>
     <string name="zen_mode_starred_contacts_title" msgid="7099621384597127058">"Контакти са звездицом"</string>
     <plurals name="zen_mode_starred_contacts_summary_additional_contacts" formatted="false" msgid="1904181007981570805">
       <item quantity="one">Још <xliff:g id="NUM_PEOPLE">%d</xliff:g> особа</item>
@@ -3531,7 +3537,7 @@
     </plurals>
     <string name="zen_mode_messages" msgid="2908722562188394107">"Дозволи поруке"</string>
     <string name="zen_mode_messages_footer" msgid="5048951937714668561">"Да бисте били сигурни да ће се дозвољене поруке чути, проверите да ли је уређај подешен да звони, вибрира или је у нечујном режиму."</string>
-    <string name="zen_mode_custom_messages_footer" msgid="5566007423100361691">"Долазне поруке су блокиране за „<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>“. Можете да прилагодите подешавања да бисте дозволили пријатељима, члановима породице или другим контактима да вас контактирају."</string>
+    <string name="zen_mode_custom_messages_footer" msgid="5566007423100361691">"Долазне поруке су блокиране за „<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>“. Можете да прилагодите подешавања и дозволите пријатељима, члановима породице или другим контактима да допру до вас."</string>
     <string name="zen_mode_messages_title" msgid="786261471294055181">"SMS, MMS и апликације за размену порука"</string>
     <string name="zen_mode_from_anyone" msgid="7778836826814131083">"Од било кога"</string>
     <string name="zen_mode_from_contacts" msgid="267034158294332688">"Само од контаката"</string>
@@ -3539,7 +3545,7 @@
     <string name="zen_calls_summary_starred_repeat" msgid="9191394641577678207">"Од контаката са звездицом и поновних позивалаца"</string>
     <string name="zen_calls_summary_contacts_repeat" msgid="7747592096431111510">"Од контаката и поновних позивалаца"</string>
     <string name="zen_calls_summary_repeat_only" msgid="8839703337232747964">"Само од поновних позивалаца"</string>
-    <string name="zen_mode_from_none" msgid="7683889985618637010">"Ни од кога"</string>
+    <string name="zen_mode_from_none" msgid="7683889985618637010">"Нико"</string>
     <string name="zen_mode_from_none_calls" msgid="2967739140346917546">"Не дозволи позиве"</string>
     <string name="zen_mode_from_none_messages" msgid="9069143820057833634">"Не дозвољавај никакве поруке"</string>
     <string name="zen_mode_alarms" msgid="5528707742250954290">"Дозволи аларме"</string>
@@ -3606,7 +3612,7 @@
     <string name="screen_pinning_unlock_pin" msgid="1441705536015645023">"Тражи PIN пре откачињања"</string>
     <string name="screen_pinning_unlock_password" msgid="1017776884000170841">"Тражи лозинку пре откачињања"</string>
     <string name="screen_pinning_unlock_none" msgid="9183040569733226911">"Закључај уређај пре откачињања"</string>
-    <string name="opening_paragraph_delete_profile_unknown_company" msgid="2350380017136403670">"Овим профилом за Work управља:"</string>
+    <string name="opening_paragraph_delete_profile_unknown_company" msgid="2350380017136403670">"Овим пословним профилом управља:"</string>
     <string name="managing_admin" msgid="3212584016377581608">"Управља <xliff:g id="ADMIN_APP_LABEL">%s</xliff:g>"</string>
     <string name="experimental_preference" msgid="5903223408406906322">"(Експериментално)"</string>
     <string name="encryption_interstitial_header" msgid="3298397268731647519">"Безбедно покретање"</string>
@@ -3764,8 +3770,8 @@
     <string name="high_power_off" msgid="5906679734326490426">"Оптимизација коришћења батерије"</string>
     <string name="high_power_system" msgid="739584574711292753">"Оптимизација батерије није доступна"</string>
     <string name="high_power_desc" msgid="333756885680362741">"Не примењујте оптимизацију батерије. Може брже да испразни батерију."</string>
-    <string name="high_power_prompt_title" msgid="2805745781720454052">"Желите ли да дозволите да апликација увек буде активна у позадини?"</string>
-    <string name="high_power_prompt_body" msgid="8067395096053552289">"Ако дозволите да апликација <xliff:g id="APP_NAME">%1$s</xliff:g> увек буде активна у позадини, то може да смањи трајање батерије. \n\nКасније можете то да промените у одељку Подешавања &gt; Апликације и обавештења."</string>
+    <string name="high_power_prompt_title" msgid="2805745781720454052">"Дозвољавате да апликација увек буде активна у позадини?"</string>
+    <string name="high_power_prompt_body" msgid="8067395096053552289">"Ако дозволите да апликација <xliff:g id="APP_NAME">%1$s</xliff:g> увек буде активна у позадини, то може да скрати трајање батерије. \n\nКасније можете то да промените у одељку Подешавања &gt; Апликације и обавештења."</string>
     <string name="battery_summary" msgid="4345690800899981339">"Потрошено је <xliff:g id="PERCENTAGE">%1$s</xliff:g> од последњег потпуног пуњења"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"Управљање напајањем"</string>
     <string name="no_battery_summary" msgid="4105932628367471314">"Батерија није коришћена од последњег потпуног пуњења"</string>
@@ -3851,7 +3857,7 @@
     <string name="ignore_optimizations_off_desc" msgid="5598702251817814289">"Препоручено за дуже трајање батерије"</string>
     <string name="ignore_optimizations_title" msgid="7924345545276166305">"Желите ли да дозволите апликацији <xliff:g id="APP">%s</xliff:g> да игнорише оптимизације батерије?"</string>
     <string name="app_list_preference_none" msgid="7100409177446935028">"Ништа"</string>
-    <string name="work_profile_usage_access_warning" msgid="403208064382097510">"Искључивање приступа коришћењу за ову апликацију не спречава администратора да прати потрошњу података за апликације на профилу за Work"</string>
+    <string name="work_profile_usage_access_warning" msgid="403208064382097510">"Искључивање приступа коришћењу за ову апликацију не спречава администратора да прати потрошњу података за апликације на пословном профилу"</string>
     <string name="accessibility_lock_screen_progress" msgid="8242917828598820049">"Употребљени знакови: <xliff:g id="COUNT_0">%1$d</xliff:g> од <xliff:g id="COUNT_1">%2$d</xliff:g>"</string>
     <string name="draw_overlay" msgid="2878665072530660668">"Приказ преко других апликација"</string>
     <string name="system_alert_window_settings" msgid="3024330223417646567">"Приказ преко других апликација"</string>
@@ -3935,7 +3941,7 @@
     <string name="disabled_by_policy_title_suspend_packages" msgid="4254714213391802322">"Не можете да отворите ову апликацију"</string>
     <string name="default_admin_support_msg" msgid="5789424433689798637">"Ако имате питања, обратите се ИТ администратору"</string>
     <string name="admin_support_more_info" msgid="8737842638087863477">"Још детаља"</string>
-    <string name="admin_profile_owner_message" msgid="3199544166281052845">"Администратор може да надгледа апликације и податке повезане са профилом за Work, укључујући подешавања, дозволе, корпоративни приступ, активности на мрежи и информације о локацији уређаја, као и да управља њима."</string>
+    <string name="admin_profile_owner_message" msgid="3199544166281052845">"Администратор може да надгледа апликације и податке повезане са пословним профилом, укључујући подешавања, дозволе, корпоративни приступ, активности на мрежи и информације о локацији уређаја, као и да управља њима."</string>
     <string name="admin_profile_owner_user_message" msgid="2991249382056855531">"Администратор може да надгледа апликације и податке повезане са овим корисником, укључујући подешавања, дозволе, корпоративни приступ, активности на мрежи и информације о локацији уређаја, као и да управља њима."</string>
     <string name="admin_device_owner_message" msgid="1823477572459610869">"Администратор може да прати апликације и податке повезане са овим уређајем, укључујући подешавања, дозволе, корпоративни приступ, активности на мрежи и информације о локацији уређаја, као и да управља њима."</string>
     <string name="condition_turn_off" msgid="4395150881365143558">"Искључи"</string>
@@ -3954,7 +3960,7 @@
     <string name="condition_cellular_summary" msgid="3607459310548343777">"Интернет је доступан само преко Wi‑Fi мреже"</string>
     <string name="condition_bg_data_title" msgid="184684435298857712">"Уштеда података"</string>
     <string name="condition_bg_data_summary" msgid="5194942860807136682">"Функције су ограничене"</string>
-    <string name="condition_work_title" msgid="9046811302347490371">"Профил за Work је искључен"</string>
+    <string name="condition_work_title" msgid="9046811302347490371">"Пословни профил је искључен"</string>
     <string name="condition_work_summary" msgid="5586134491975748565">"За апликације и обавештења"</string>
     <string name="condition_device_muted_action_turn_on_sound" msgid="5849285946804815263">"Укључи звук"</string>
     <string name="condition_device_muted_title" msgid="3930542786434609976">"Звук звона је искључен"</string>
@@ -4013,7 +4019,7 @@
     </plurals>
     <string name="operator_warning" msgid="4676042739221117031">"Обрачун података код мобилног оператера се можда разликује од обрачуна уређаја."</string>
     <string name="data_used_template" msgid="761605393453849477">"Потрошили сте <xliff:g id="ID_1">%1$s</xliff:g>"</string>
-    <string name="set_data_warning" msgid="8115980184415563941">"Подешавање упозорења о подацима"</string>
+    <string name="set_data_warning" msgid="8115980184415563941">"Подеси упозорење о подацима"</string>
     <string name="data_warning" msgid="2699207195535036240">"Упозорење за потрошњу података"</string>
     <string name="data_warning_footnote" msgid="965724845580257305">"Упозорење за потрошњу података и ограничење потрошње података активира мерење уређаја. То може да се разликује од мерења мобилног оператера."</string>
     <string name="set_data_limit" msgid="5043770023229990674">"Подеси ограничење за податке"</string>
@@ -4263,11 +4269,11 @@
     <string name="enterprise_privacy_input_method_name" msgid="439610095825218563">"Подешено је на <xliff:g id="APP_LABEL">%s</xliff:g>"</string>
     <string name="enterprise_privacy_always_on_vpn_device" msgid="2022700916516458213">"Стално укључен VPN је укључен"</string>
     <string name="enterprise_privacy_always_on_vpn_personal" msgid="5644065780843002044">"Стално укључен VPN је укључен на личном профилу"</string>
-    <string name="enterprise_privacy_always_on_vpn_work" msgid="6443089897985373564">"Стално укључен VPN је укључен на профилу за Work"</string>
+    <string name="enterprise_privacy_always_on_vpn_work" msgid="6443089897985373564">"Стално укључен VPN је укључен на пословном профилу"</string>
     <string name="enterprise_privacy_global_http_proxy" msgid="3862135895716080830">"Глобални HTTP прокси је подешен"</string>
     <string name="enterprise_privacy_ca_certs_device" msgid="7715658848470643878">"Поуздани акредитиви"</string>
     <string name="enterprise_privacy_ca_certs_personal" msgid="1356447417193483802">"Поуздани акредитиви на личном профилу"</string>
-    <string name="enterprise_privacy_ca_certs_work" msgid="836419648894546893">"Поуздани акредитиви на профилу за Work"</string>
+    <string name="enterprise_privacy_ca_certs_work" msgid="836419648894546893">"Поуздани акредитиви на пословном профилу"</string>
     <plurals name="enterprise_privacy_number_ca_certs" formatted="false" msgid="7953528945502561752">
       <item quantity="one">Најмање <xliff:g id="COUNT_1">%d</xliff:g> CA сертификат</item>
       <item quantity="few">Најмање <xliff:g id="COUNT_1">%d</xliff:g> CA сертификата</item>
@@ -4276,7 +4282,7 @@
     <string name="enterprise_privacy_lock_device" msgid="1533125067038409945">"Администратор може да закључава уређај и ресетује лозинку"</string>
     <string name="enterprise_privacy_wipe_device" msgid="7555287990273929922">"Администратор може да брише све податке са уређаја"</string>
     <string name="enterprise_privacy_failed_password_wipe_device" msgid="4101502079202483156">"Неуспели покушаји уноса лозинке пре брисања свих података са уређаја"</string>
-    <string name="enterprise_privacy_failed_password_wipe_work" msgid="2881646286634693392">"Неуспели покушаји уноса лозинке пре брисања података са профила за Work"</string>
+    <string name="enterprise_privacy_failed_password_wipe_work" msgid="2881646286634693392">"Неуспели покушаји уноса лозинке пре брисања података са пословног профила"</string>
     <plurals name="enterprise_privacy_number_failed_password_wipe" formatted="false" msgid="562550414712223382">
       <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> покушај</item>
       <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> покушаја</item>
@@ -4550,7 +4556,7 @@
     <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"Желите ли да уклоните овај предлог?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"Предлог је уклоњен"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"Опозови"</string>
-    <string name="low_storage_summary" msgid="4562224870189133400">"Преостало је мало слободног меморијског простора. <xliff:g id="PERCENTAGE">%1$s</xliff:g> је искоришћено – <xliff:g id="FREE_SPACE">%2$s</xliff:g> је слободно"</string>
+    <string name="low_storage_summary" msgid="4562224870189133400">"Нема много простора. <xliff:g id="PERCENTAGE">%1$s</xliff:g> је искоришћено – <xliff:g id="FREE_SPACE">%2$s</xliff:g> је слободно"</string>
     <string name="contextual_card_feedback_send" msgid="8698649023854350623">"Пошаљите повратне информације"</string>
     <string name="contextual_card_feedback_confirm_message" msgid="3987973028353264878">"Желите ли да нам пошаљете повратне информације за овај предлог?"</string>
     <string name="copyable_slice_toast" msgid="1357518174923789947">"Копирано је у привремену меморију: <xliff:g id="COPY_CONTENT">%1$s</xliff:g>"</string>
diff --git a/tests/CarDeveloperOptions/res/values-sv/arrays.xml b/tests/CarDeveloperOptions/res/values-sv/arrays.xml
index 8b5cdd4..d416ac4 100644
--- a/tests/CarDeveloperOptions/res/values-sv/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-sv/arrays.xml
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"Tillåt aldrig"</item>
     <item msgid="8184570120217958741">"Tillåt alltid"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Medel"</item>
+    <item msgid="1555861583162930714">"Låg"</item>
+    <item msgid="1719683776264798117">"Kritisk"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normal"</item>
+    <item msgid="6107138933849816768">"Måttlig"</item>
+    <item msgid="182695359839047859">"Låg"</item>
+    <item msgid="8577246509202964244">"Kritisk"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Ihållande"</item>
     <item msgid="167418068739176448">"Toppaktivitet"</item>
diff --git a/tests/CarDeveloperOptions/res/values-sv/config.xml b/tests/CarDeveloperOptions/res/values-sv/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-sv/config.xml
+++ b/tests/CarDeveloperOptions/res/values-sv/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-sv/strings.xml b/tests/CarDeveloperOptions/res/values-sv/strings.xml
index df5d7ac..e17d281 100644
--- a/tests/CarDeveloperOptions/res/values-sv/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-sv/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Gör texten på skärmen större eller mindre."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Förminska"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Förstora"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Exempeltext"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Den fantastiska trollkarlen från Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Kapitel 11: Den underbara Smaragdstaden i Oz"</string>
@@ -116,7 +115,7 @@
     <string name="bluetooth_empty_list_user_restricted" msgid="3616298363281495777">"Du saknar behörighet att ändra Bluetooth-inställningarna."</string>
     <string name="bluetooth_pairing_pref_title" msgid="2904954138013884029">"Parkoppla en ny enhet"</string>
     <string name="bluetooth_is_visible_message" msgid="6341088682252805612">"Enheter i närheten kan se <xliff:g id="DEVICE_NAME">%1$s</xliff:g> när Bluetooth är på."</string>
-    <string name="bluetooth_footer_mac_message" product="default" msgid="335341476746836260">"Mobilens Bluetooth-adress: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="bluetooth_footer_mac_message" product="default" msgid="335341476746836260">"Telefonens Bluetooth-adress: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
     <string name="bluetooth_footer_mac_message" product="tablet" msgid="6033609611245782463">"Surfplattans Bluetooth-adress: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
     <string name="bluetooth_footer_mac_message" product="device" msgid="7639919867088358038">"Enhetens Bluetooth-adress: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
     <string name="bluetooth_is_disconnect_question" msgid="6180709281434591654">"Vill du koppla från <xliff:g id="DEVICE_NAME">%1$s</xliff:g>?"</string>
@@ -364,9 +363,9 @@
     <string name="owner_info_settings_summary" msgid="4208702251226725583">"Inget"</string>
     <string name="owner_info_settings_status" msgid="8049975536717685126">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="COUNT_1">%2$d</xliff:g>"</string>
     <string name="owner_info_settings_edit_text_hint" msgid="2250029417257939706">"T.ex. Jockes Android."</string>
-    <string name="user_info_settings_title" msgid="1125111518759995748">"Användarinfo"</string>
+    <string name="user_info_settings_title" msgid="1125111518759995748">"Användarinformation"</string>
     <string name="show_profile_info_on_lockscreen_label" msgid="5204282771893683026">"Visa profilinfo på den låsta skärmen"</string>
-    <string name="profile_info_settings_title" msgid="4855892878512562551">"Profilinfo"</string>
+    <string name="profile_info_settings_title" msgid="4855892878512562551">"Profilinformation"</string>
     <string name="Accounts_settings_title" msgid="7901374987121953746">"Konton"</string>
     <string name="location_settings_title" msgid="2707201457572301030">"Plats"</string>
     <string name="location_settings_master_switch_title" msgid="3108016866082816733">"Använd plats"</string>
@@ -441,13 +440,13 @@
     <string name="security_settings_fingerprint_enroll_introduction_title" msgid="889558002683900544">"Lås upp med fingeravtryck"</string>
     <string name="security_settings_fingerprint_enroll_introduction_title_unlock_disabled" msgid="7915504118657864429">"Använda ditt fingeravtryck"</string>
     <string name="security_settings_fingerprint_enroll_introduction_message" msgid="5586198131986682472">"Tryck bara på fingeravtryckssensorn när du vill låsa upp mobilen, auktorisera köp eller logga in i appar. Tänk efter innan du lägger till någons fingeravtryck, eftersom alla som du lägger till kan utföra alla dessa åtgärder.\n\nObs! Fingeravtryck kan vara mindre säkra än ett säkert grafiskt lösenord eller en pinkod."</string>
-    <string name="security_settings_fingerprint_enroll_introduction_message_unlock_disabled" msgid="1640839304679275468">"Använd fingeravtrycket för att låsa upp mobilen eller godkänna köp.\n\nObs! Du kan inte använda fingeravtrycket för att låsa upp den här enheten. Kontakta organisationens administratör om du vill veta mer."</string>
+    <string name="security_settings_fingerprint_enroll_introduction_message_unlock_disabled" msgid="1640839304679275468">"Använd ditt fingeravtryck för att låsa upp telefonen eller godkänna köp.\n\nObs! Du kan inte använda fingeravtrycket för att låsa upp den här enheten. Kontakta organisationens administratör om du vill veta mer."</string>
     <string name="security_settings_fingerprint_enroll_introduction_message_setup" msgid="6734490666593320711">"Använd fingeravtrycket för att låsa upp mobilen eller godkänna köp.\n\nObs! Fingeravtrycket kan vara mindre säkert än ett starkt grafiskt lösenord eller en bra pinkod."</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel" msgid="9168637333731599827">"Avbryt"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue" msgid="271662150372486535">"Fortsätt"</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel_setup" msgid="756928427429893070">"Hoppa över"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue_setup" msgid="4125977169169671144">"Nästa"</string>
-    <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"Ska fingeravtryck hoppas över?"</string>
+    <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"Vill du hoppa över fingeravtryck?"</string>
     <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"Det tar bara ett par minuter att konfigurera fingeravtrycket. Hoppar du över det kan du lägga till fingeravtryck i inställningarna senare."</string>
     <string name="lock_screen_intro_skip_title" msgid="5307431665496346914">"Vill du hoppa över skärmlås?"</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="tablet" msgid="7553945981266845264">"Enhetens skyddsfunktioner aktiveras inte. Du kan inte hindra andra från att använda surfplattan om den blir stulen, tappas bort eller återställs."</string>
@@ -461,13 +460,13 @@
     <string name="skip_lock_screen_dialog_button_label" msgid="6706047245716780006">"Hoppa över"</string>
     <string name="cancel_lock_screen_dialog_button_label" msgid="2534925227627658819">"Avbryt"</string>
     <string name="security_settings_fingerprint_enroll_find_sensor_title" msgid="8909829699273726469">"Tryck på sensorn"</string>
-    <string name="security_settings_fingerprint_enroll_find_sensor_message" msgid="581120963079780740">"Den sitter på mobilens baksida. Använd pekfingret."</string>
+    <string name="security_settings_fingerprint_enroll_find_sensor_message" msgid="581120963079780740">"Den sitter på telefonens baksida. Använd pekfingret."</string>
     <string name="security_settings_fingerprint_enroll_find_sensor_content_description" msgid="7835824123269738540">"Illustration med enheten och fingeravtryckssensorns plats"</string>
     <string name="security_settings_fingerprint_enroll_dialog_name_label" msgid="3519748398694308901">"Namn"</string>
     <string name="security_settings_fingerprint_enroll_dialog_ok" msgid="3428927518029038956">"OK"</string>
     <string name="security_settings_fingerprint_enroll_dialog_delete" msgid="4312297515772004580">"Radera"</string>
     <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"Tryck på sensorn"</string>
-    <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Lägg fingret på sensorn och ta bort det när den vibrerar till"</string>
+    <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Lägg fingret på sensorn och ta bort det när du känner en vibration"</string>
     <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"Lyft och tryck sedan igen"</string>
     <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Lyft fingret flera gånger för att lägga till hela fingeravtrycket"</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"Fingeravtrycket är tillagt"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Får inte innehålla fler än <xliff:g id="NUMBER_1">%d</xliff:g> siffror</item>
       <item quantity="one">Får inte innehålla fler än <xliff:g id="NUMBER_0">%d</xliff:g> siffra</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Får endast innehålla siffrorna 0–9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Enhetsadministratören tillåter inte att en pinkod som använts nyligen används igen"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"IT-adminstratören har blockerat de vanligaste pinkoderna. Testa en annan pinkod."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Får inte innehålla ogiltiga tecken"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Lösenordet måste innehålla minst <xliff:g id="COUNT">%d</xliff:g> tecken som inte är bokstäver</item>
       <item quantity="one">Lösenordet måste innehålla minst ett tecken som inte är en bokstav</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Lösenordet måste innehålla minst <xliff:g id="COUNT">%d</xliff:g> tecken som inte är en siffra</item>
+      <item quantity="one">Lösenordet måste innehålla minst ett tecken som inte är en siffra</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Enhetsadministratören tillåter inte att ett lösenord som använts nyligen används igen"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"IT-adminstratören har blockerat de vanligaste lösenorden. Testa ett annat lösenord."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"En stigande, fallande eller upprepad siffersekvens är inte tillåten"</string>
@@ -824,7 +826,7 @@
     <string name="nfc_disclaimer_title" msgid="4860231267351602970">"Aktivera NFC"</string>
     <string name="nfc_disclaimer_content" msgid="3066113577854565782">"NFC skickar och tar emot data till och från denna enhet samt andra enheter eller mål i närheten, t.ex. betalningsterminaler, tillgänglighetsläsare och interaktiva annonser eller taggar."</string>
     <string name="nfc_secure_settings_title" msgid="5153751163174916581">"Säker NFC"</string>
-    <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"Tillåt endast betalningar och överföringar via NFC när skärmen är upplåst"</string>
+    <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"Tillåt endast användning i kollektivtrafiken och överföringar via NFC när skärmen är upplåst"</string>
     <string name="android_beam_settings_title" msgid="3083436415873738389">"Android Beam"</string>
     <string name="android_beam_on_summary" msgid="8068287225180474199">"Redo att överföra appinnehåll via NFC"</string>
     <string name="android_beam_off_summary" msgid="7365818039159364600">"Av"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mobil enhet"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Använd mobilnätverk om Wi‑Fi inte är tillgängligt"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Använd Wi‑Fi om mobilnätverket inte är tillgängligt"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Ring via Wi‑Fi. Samtalet avslutas om Wi-Fi-anslutningen Wi-Fi bryts."</string>
@@ -1616,11 +1621,11 @@
     <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"Det går inte att använda internetdelning eller trådlösa surfzoner när Databesparing är aktiverat."</string>
     <string name="usb_title" msgid="7480927657535578688">"USB"</string>
     <string name="usb_tethering_button_text" msgid="6242228383142012332">"Delning via USB"</string>
-    <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"Dela mobilens internetanslutning via USB"</string>
+    <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"Dela telefonens internetanslutning via USB"</string>
     <string name="usb_tethering_subtext" product="tablet" msgid="154536000235361034">"Dela surfplattans internetanslutning via USB"</string>
     <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"Delning via Bluetooth"</string>
     <string name="bluetooth_tethering_subtext" product="tablet" msgid="6868756914621131635">"Dela surfplattans internetanslutning via Bluetooth"</string>
-    <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"Dela mobilens internetanslutning via Bluetooth"</string>
+    <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"Dela telefonens internetanslutning via Bluetooth"</string>
     <string name="bluetooth_tethering_off_subtext_config" msgid="3981528184780083266">"<xliff:g id="DEVICE_NAME">%1$d</xliff:g>s internetanslutning delas via Bluetooth"</string>
     <string name="bluetooth_tethering_overflow_error" msgid="6946561351369376943">"Det går inte att dela med mer än <xliff:g id="MAXCONNECTION">%1$d</xliff:g> enheter."</string>
     <string name="bluetooth_untether_blank" msgid="5428300773782256084">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> kopplas från."</string>
@@ -1837,7 +1842,7 @@
     <string name="show_running_services" msgid="1895994322704667543">"Visa tjänster som körs"</string>
     <string name="show_background_processes" msgid="88012264528093617">"Visa cachade processer"</string>
     <string name="default_emergency_app" msgid="286530070173495823">"App för nödsituationer"</string>
-    <string name="reset_app_preferences" msgid="1426500030595212077">"Återställ inställningarna"</string>
+    <string name="reset_app_preferences" msgid="1426500030595212077">"Återställ appinställningarna"</string>
     <string name="reset_app_preferences_title" msgid="792909865493673598">"Vill du återställa?"</string>
     <string name="reset_app_preferences_desc" msgid="7935273005301096031">"Detta återställer alla inställningar för:\n\n "<li>"inaktiverade appar"</li>\n" "<li>"inaktiverade appaviseringar"</li>\n" "<li>"standardappar för åtgärder"</li>\n" "<li>"begränsningar i bakgrundsdata för appar"</li>\n" "<li>"begränsningar för alla behörigheter."</li>\n\n" Ingen appdata kommer att försvinna."</string>
     <string name="reset_app_preferences_button" msgid="2041894727477934656">"Återställ appar"</string>
@@ -2263,7 +2268,7 @@
     <string name="controls_subtitle" msgid="6920199888882834620">"Justera strömförbrukningen"</string>
     <string name="packages_subtitle" msgid="6506269487892204413">"Inkluderade paket"</string>
     <string name="battery_tip_summary_title" msgid="2750922152518825526">"Appar körs som vanligt"</string>
-    <string name="battery_tip_summary_summary" product="default" msgid="6294900413896440006">"Batteriförbrukningen i bakgrunden är normal på mobilen"</string>
+    <string name="battery_tip_summary_summary" product="default" msgid="6294900413896440006">"Batteriförbrukningen i bakgrunden är normal på telefonen"</string>
     <string name="battery_tip_summary_summary" product="tablet" msgid="5280099016800644130">"Batteriförbrukningen i bakgrunden är normal på surfplattan"</string>
     <string name="battery_tip_summary_summary" product="device" msgid="4459840492610842705">"Batteriförbrukningen i bakgrunden är normal på enheten"</string>
     <string name="battery_tip_low_battery_title" msgid="6784043681672161175">"Låg batterikapacitet"</string>
@@ -2276,7 +2281,7 @@
     <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Batteriet kan ta slut snabbare än vanligt"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Batterisparläget är aktiverat"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Vissa funktioner kan begränsas"</string>
-    <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Mobilen används mer än vanligt"</string>
+    <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Telefonen används mer än vanligt"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"Surfplattan används mer än vanligt"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"Enheten används mer än vanligt"</string>
     <string name="battery_tip_high_usage_summary" msgid="5514749872957528189">"Batteriet kan ta slut snabbare än vanligt"</string>
@@ -2312,7 +2317,7 @@
     <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"Den här appen kan dra batteri i bakgrunden. Batteriet kan ta slut snabbare än beräknat."</string>
     <string name="battery_tip_unrestrict_app_dialog_ok" msgid="9154938931448151479">"Ta bort"</string>
     <string name="battery_tip_unrestrict_app_dialog_cancel" msgid="7331148618292397166">"Avbryt"</string>
-    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"Batteriförbrukningen för apparna är normal. Om apparnas batteriförbrukning är för hög visas förslag på mobilen om åtgärder du kan vidta.\n\nOm batteriet börjar ta slut kan du aktivera batterisparläget."</string>
+    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"Batteriförbrukningen för apparna är normal. Om apparnas batteriförbrukning är för hög visas förslag på telefonen om åtgärder du kan vidta.\n\nOm batteriet börjar ta slut kan du aktivera batterisparläget."</string>
     <string name="battery_tip_dialog_summary_message" product="tablet" msgid="1721081030632329647">"Batteriförbrukningen för apparna är normal. Om apparnas batteriförbrukning är för hög visas förslag på surfplattan om åtgärder du kan vidta.\n\nOm batteriet börjar ta slut kan du aktivera batterisparläget."</string>
     <string name="battery_tip_dialog_summary_message" product="device" msgid="146872407040848465">"Batteriförbrukningen för apparna är normal. Om apparnas batteriförbrukning är för hög visas förslag på enheten om åtgärder du kan vidta.\n\nOm batteriet börjar ta slut kan du aktivera batterisparläget."</string>
     <string name="smart_battery_manager_title" msgid="5744035036663849515">"Battery Manager"</string>
@@ -2673,7 +2678,7 @@
     <string name="data_usage_label_foreground" msgid="2471091128648754601">"Förgrund"</string>
     <string name="data_usage_label_background" msgid="1618794447370396845">"Bakgrund"</string>
     <string name="data_usage_app_restricted" msgid="7569077654579299326">"begränsad"</string>
-    <string name="data_usage_disable_mobile" msgid="4125335076749119451">"Vill du inaktivera mobildatan?"</string>
+    <string name="data_usage_disable_mobile" msgid="4125335076749119451">"Vill du inaktivera mobildata?"</string>
     <string name="data_usage_disable_mobile_limit" msgid="1937796699758613667">"Ange gräns för mobildata"</string>
     <string name="data_usage_disable_4g_limit" msgid="7131367986548147266">"Ange gräns för data via 4G"</string>
     <string name="data_usage_disable_3g_limit" msgid="6746819313032692220">"Ange gräns för data via 2G-3G"</string>
@@ -2710,7 +2715,7 @@
     <string name="data_usage_limit_editor_title" msgid="1687908662154108293">"Ange gräns för dataanvändning"</string>
     <string name="data_usage_limit_dialog_title" msgid="8804760847110131518">"Begränsa dataanvändningen"</string>
     <string name="data_usage_limit_dialog_mobile" product="tablet" msgid="2000713577999830647">"När mobildatan når den gräns du har angett inaktiveras den av surfplattan.\n\nVi föreslår att du anger en något lägre gräns eftersom dataanvändningen mäts med din surfplatta och din leverantör kan mäta användningen på ett annat sätt."</string>
-    <string name="data_usage_limit_dialog_mobile" product="default" msgid="943546278705619205">"När mobildatan når den gräns du har angett inaktiveras den av mobilen.\n\nVi föreslår att du anger en något lägre gräns eftersom dataanvändningen mäts med din mobil och din leverantör kan mäta användningen på ett annat sätt."</string>
+    <string name="data_usage_limit_dialog_mobile" product="default" msgid="943546278705619205">"När mobildatan når den gräns du har angett inaktiveras den av telefonen.\n\nVi föreslår att du anger en något lägre gräns eftersom dataanvändningen mäts med din telefon och din leverantör kan mäta användningen på ett annat sätt."</string>
     <string name="data_usage_restrict_background_title" msgid="3568746530413220844">"Vill du begränsa bakgrundsdata?"</string>
     <string name="data_usage_restrict_background" msgid="995811034744808575">"Om du begränsar mobildatan i bakgrunden fungerar vissa appar och tjänster endast när du är ansluten till ett Wi-Fi-nätverk."</string>
     <string name="data_usage_restrict_background_multiuser" product="tablet" msgid="6032810839234864814">"Om du begränsar mobildatan i bakgrunden fungerar vissa appar och tjänster endast när du är ansluten till ett Wi-Fi-nätverk.\n\nAlla användare på den här surfplattan påverkas av inställningen."</string>
@@ -2845,7 +2850,7 @@
     <string name="user_settings_title" msgid="7917598650933179545">"Flera användare"</string>
     <string name="user_settings_footer_text" product="device" msgid="4573858247439190545">"Dela enheten genom att lägga till nya användare. Varje användare får ett personligt utrymme på enheten med egna startskärmar, konton, appar, inställningar med mera."</string>
     <string name="user_settings_footer_text" product="tablet" msgid="780018221428132918">"Dela surfplattan genom att lägga till nya användare. Varje användare får ett personligt utrymme på surfplattan med egna startskärmar, konton, appar, inställningar med mera."</string>
-    <string name="user_settings_footer_text" product="default" msgid="1470859614968237491">"Dela mobilen genom att lägga till nya användare. Varje användare får ett personligt utrymme på mobilen med egna startskärmar, konton, appar, inställningar med mera."</string>
+    <string name="user_settings_footer_text" product="default" msgid="1470859614968237491">"Dela telefonen genom att lägga till nya användare. Varje användare får ett personligt utrymme på telefonen med egna startskärmar, konton, appar, inställningar med mera."</string>
     <string name="user_list_title" msgid="6670258645246192324">"Användare och profiler"</string>
     <string name="user_add_user_or_profile_menu" msgid="4220679989900149336">"Lägg till användare eller profil"</string>
     <string name="user_add_user_menu" msgid="9006572936456324794">"Lägg till användare"</string>
@@ -2911,7 +2916,7 @@
     <string name="apps_with_restrictions_settings_button" msgid="5065896213467171744">"Utöka appens inställningar"</string>
     <string name="nfc_payment_settings_title" msgid="5070077706735415291">"Tryck och betala"</string>
     <string name="nfc_payment_how_it_works" msgid="7607901964687787177">"Så fungerar det"</string>
-    <string name="nfc_payment_no_apps" msgid="8844440783395420860">"Betala med mobilen i butiker"</string>
+    <string name="nfc_payment_no_apps" msgid="8844440783395420860">"Betala med telefonen i butiker"</string>
     <string name="nfc_payment_default" msgid="7869273092463612271">"Standardapp för betalning"</string>
     <string name="nfc_payment_default_not_set" msgid="955804193510335338">"Har inte angetts"</string>
     <string name="nfc_payment_app_and_desc" msgid="102312684211458190">"<xliff:g id="APP">%1$s</xliff:g> – <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
@@ -2920,7 +2925,7 @@
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Förutom när en annan betalningsapp är öppen"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"Vid en Tryck och betala-terminal betalar du med:"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Betala vid en kassaterminal"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Konfigurera en betalningsapp. Sedan behöver du bara hålla mobilens baksida mot terminaler med symbolen för kontaktlös överföring."</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Konfigurera en betalningsapp. Sedan behöver du bara hålla telefonens baksida mot terminaler med symbolen för kontaktlös överföring."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"OK"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"Mer ..."</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"Vill du ange den här som standard?"</string>
@@ -3144,7 +3149,7 @@
     <string name="other_sound_settings" msgid="5250376066099818676">"Andra ljud"</string>
     <string name="dial_pad_tones_title" msgid="8877212139988655769">"Knappsatsljud"</string>
     <string name="screen_locking_sounds_title" msgid="4407110895465866809">"Ljud vid skärmlåsning"</string>
-    <string name="charging_sounds_title" msgid="5070437987230894287">"Laddningsljud- och vibration"</string>
+    <string name="charging_sounds_title" msgid="5070437987230894287">"Laddningsljud och -vibration"</string>
     <string name="docking_sounds_title" msgid="2573137471605541366">"Ljud via dockningsstationen"</string>
     <string name="touch_sounds_title" msgid="165237488496165652">"Ljud vid tryck"</string>
     <string name="vibrate_on_touch_title" msgid="6360155469279157684">"Vibration vid tryck"</string>
@@ -3156,7 +3161,7 @@
     <string name="emergency_tone_alert" msgid="907868135091891015">"Signaler"</string>
     <string name="emergency_tone_vibrate" msgid="5020068066905681181">"Vibrationer"</string>
     <string name="boot_sounds_title" msgid="7583926202411353620">"Ljud vid uppstart"</string>
-    <string name="live_caption_title" msgid="7926591158657997051">"Realtidstextning"</string>
+    <string name="live_caption_title" msgid="7926591158657997051">"Live Caption"</string>
     <string name="live_caption_summary" msgid="9064771862352393125">"Texta media automatiskt"</string>
     <string name="zen_mode_settings_summary_off" msgid="6929319200478424962">"Aldrig"</string>
     <plurals name="zen_mode_settings_summary_on" formatted="false" msgid="6061723291126091396">
@@ -3178,10 +3183,10 @@
     <string name="zen_mode_rule_name_edit" msgid="5479435215341745578">"Redigera"</string>
     <string name="zen_mode_automation_settings_page_title" msgid="3001783354881078983">"Scheman"</string>
     <string name="zen_mode_automatic_rule_settings_page_title" msgid="5272888746413504692">"Schema"</string>
-    <string name="zen_mode_schedule_category_title" msgid="1936785755444711221">"Schemaläggning"</string>
+    <string name="zen_mode_schedule_category_title" msgid="1936785755444711221">"Schemalägg"</string>
     <string name="zen_mode_automation_suggestion_title" msgid="4921779962633710347">"Stäng av mobilljud vid vissa tider"</string>
     <string name="zen_mode_automation_suggestion_summary" msgid="2709837472884371037">"Ange regler för Stör ej"</string>
-    <string name="zen_mode_schedule_title" msgid="5275268813192802631">"Schemaläggning"</string>
+    <string name="zen_mode_schedule_title" msgid="5275268813192802631">"Schemalägg"</string>
     <string name="zen_mode_use_automatic_rule" msgid="446326253915861824">"Använd schema"</string>
     <string name="zen_mode_option_important_interruptions" msgid="5173944276846940149">"Bara prioriterade"</string>
     <string name="zen_mode_option_alarms" msgid="4843278125235203076">"Endast alarm"</string>
@@ -3196,7 +3201,7 @@
     <string name="zen_mode_restrict_notifications_mute_footer" msgid="3049522809520549054">"Inga ljud eller vibrationer används när du tar emot aviseringar på mobilen."</string>
     <string name="zen_mode_restrict_notifications_hide" msgid="3296933643539682552">"Inga synliga eller hörbara aviseringar"</string>
     <string name="zen_mode_restrict_notifications_hide_summary" msgid="1449301153755270168">"Aviseringar varken syns eller hörs"</string>
-    <string name="zen_mode_restrict_notifications_hide_footer" msgid="7617688597593946765">"Mobilen visar inte nya eller befintliga aviseringar och varken vibrerar eller låter. Viktiga aviseringar för aktivitet och status för mobilen visas fortfarande.\n\nNär du inaktiverar Stör ej kan du visa dina aviseringar genom att svepa nedåt från skärmens överkant."</string>
+    <string name="zen_mode_restrict_notifications_hide_footer" msgid="7617688597593946765">"Telefonen visar inte nya eller befintliga aviseringar och varken vibrerar eller låter. Viktiga aviseringar för aktivitet och status för telefonen visas fortfarande.\n\nNär du inaktiverar Stör ej kan du visa dina aviseringar genom att svepa nedåt från skärmens överkant."</string>
     <string name="zen_mode_restrict_notifications_custom" msgid="3167252482570424133">"Anpassa"</string>
     <string name="zen_mode_restrict_notifications_enable_custom" msgid="6376983315529894440">"Aktivera anpassad inställning"</string>
     <string name="zen_mode_restrict_notifications_disable_custom" msgid="8004212081465043044">"Ta bort anpassad inställning"</string>
@@ -3515,7 +3520,7 @@
     <string name="zen_mode_starred_callers" msgid="1317376207713013472">"stjärnmärkta kontakter"</string>
     <string name="zen_mode_repeat_callers" msgid="1435309867554692340">"Återuppringning"</string>
     <string name="zen_mode_repeat_callers_list" msgid="2750270907597457279">"när någon ringer flera gånger"</string>
-    <string name="zen_mode_repeat_callers_title" msgid="7192952181541813487">"Tillåt återuppringning"</string>
+    <string name="zen_mode_repeat_callers_title" msgid="7192952181541813487">"Tillåt upprepade samtal"</string>
     <string name="zen_mode_calls_summary_one" msgid="8327371053236689649">"Tillåt från <xliff:g id="CALLER_TYPE">%1$s</xliff:g>"</string>
     <string name="zen_mode_calls_summary_two" msgid="9017678770532673578">"Tillåt från <xliff:g id="CALLER_TYPE">%1$s</xliff:g> och <xliff:g id="CALLERT_TPYE">%2$s</xliff:g>"</string>
     <string name="zen_mode_repeat_callers_summary" msgid="1752513516040525545">"Om samma person ringer en gång till inom en tidsperiod på <xliff:g id="MINUTES">%d</xliff:g> minuter"</string>
@@ -3552,7 +3557,7 @@
     <string name="screen_pinning_title" msgid="578020318289781102">"Fästa skärmen"</string>
     <string name="screen_pinning_description" msgid="3814537379086412278">"När den här inställningen är aktiverad kan du fästa skärmen om du vill att den aktuella skärmen ska visas tills du lossar den.\n\nSå här fäster du skärmen:\n\n1. Kontrollera att funktionen för att fästa skärmen är på.\n\n2. Öppna översikten\n\n3. Tryck på appikonen högst upp på skärmen och sedan på Fäst."</string>
     <string name="screen_pinning_unlock_pattern" msgid="1060334707088339444">"Kräv grafiskt lösenordet innan skärmen lossas"</string>
-    <string name="screen_pinning_unlock_pin" msgid="1441705536015645023">"Be om pinkod innan skärmen lossas"</string>
+    <string name="screen_pinning_unlock_pin" msgid="1441705536015645023">"Be om pinkod innan appen lossas"</string>
     <string name="screen_pinning_unlock_password" msgid="1017776884000170841">"Be om lösenord innan skärmen lossas"</string>
     <string name="screen_pinning_unlock_none" msgid="9183040569733226911">"Lås enheten när skärmen lossas"</string>
     <string name="opening_paragraph_delete_profile_unknown_company" msgid="2350380017136403670">"Den här jobbprofilen hanteras av:"</string>
@@ -3630,7 +3635,7 @@
     <string name="filter_enabled_apps" msgid="5888459261768538489">"Installerade appar"</string>
     <string name="filter_instant_apps" msgid="8087483282854072366">"Snabbappar"</string>
     <string name="filter_personal_apps" msgid="3473268022652904457">"Personligt"</string>
-    <string name="filter_work_apps" msgid="4202483998339465542">"Arbetet"</string>
+    <string name="filter_work_apps" msgid="4202483998339465542">"Arbete"</string>
     <string name="filter_notif_all_apps" msgid="1862666327228804896">"Appar: alla"</string>
     <string name="filter_notif_blocked_apps" msgid="5694956954776028202">"Inaktiverade"</string>
     <string name="filter_notif_urgent_channels" msgid="5000735867167027148">"Kategorier: brådskande avisering"</string>
@@ -3754,7 +3759,7 @@
     <string name="background_check_pref" msgid="664081406854758392">"Bakgrundskontroll"</string>
     <string name="background_check_title" msgid="4136736684290307970">"Fullständig bakgrundsåtkomst"</string>
     <string name="assist_access_context_title" msgid="2274614501747710439">"Använda text från skärmen"</string>
-    <string name="assist_access_context_summary" msgid="5867997494395842785">"Tillåt att assistentappen får åtkomst till innehåll på skärmen, till exempel text"</string>
+    <string name="assist_access_context_summary" msgid="5867997494395842785">"Tillåt att assistentappen får åtkomst till innehåll på skärmen som text"</string>
     <string name="assist_access_screenshot_title" msgid="1991014038776117688">"Använda skärmdump"</string>
     <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Tillåt att assistentappen får åtkomst till en bild på skärmen"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"Lys upp skärmen"</string>
@@ -4047,7 +4052,7 @@
     <string name="display_cutout_emulation_keywords" msgid="6795671536772871439">"urklipp av skärm, flärp"</string>
     <string name="overlay_option_device_default" msgid="165508753381657697">"Enhetens standardinställning"</string>
     <string name="overlay_toast_failed_to_apply" msgid="5692251825129250040">"Det gick inte att använda överlagring"</string>
-    <string name="special_access" msgid="1453926335914696206">"Särskild åtkomst för app"</string>
+    <string name="special_access" msgid="1453926335914696206">"Särskild appåtkomst"</string>
     <plurals name="special_access_summary" formatted="false" msgid="5182092345063909346">
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> appar får använda obegränsad data</item>
       <item quantity="one">1 app får använda obegränsad data</item>
@@ -4115,24 +4120,24 @@
     <string name="swipe_up_to_switch_apps_summary" msgid="4644068184114154787">"Svep uppåt från hemknappen om du vill byta app. Svep uppåt igen om du vill se alla appar. Du kan göra detta oavsett vilken skärm som är öppen. Det finns inte längre någon knapp för översikt nere till höger på skärmen."</string>
     <string name="swipe_up_to_switch_apps_suggestion_title" msgid="7641846365137536128">"Testa den nya hemknappen"</string>
     <string name="swipe_up_to_switch_apps_suggestion_summary" msgid="7338653224520387852">"Aktivera den nya rörelsen för att byta mellan appar"</string>
-    <string name="ambient_display_title" product="default" msgid="6785677099744344088">"Tryck snabbt två gånger för att kolla mobilen"</string>
+    <string name="ambient_display_title" product="default" msgid="6785677099744344088">"Tryck snabbt två gånger för att kolla telefonen"</string>
     <string name="ambient_display_title" product="tablet" msgid="1106285490888683613">"Tryck snabbt två gånger för att kolla surfplattan"</string>
     <string name="ambient_display_title" product="device" msgid="5064644474876041478">"Tryck snabbt två gånger för att kolla enheten"</string>
     <string name="ambient_display_summary" msgid="4882910328216411109">"Visa tid, aviseringar och annan information genom att trycka snabbt två gånger på skärmen."</string>
-    <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"Lyft för att kolla mobilen"</string>
+    <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"Lyft för att kolla telefonen"</string>
     <string name="ambient_display_pickup_title" product="tablet" msgid="1555456400210301959">"Plocka upp för att kolla surfplattan"</string>
     <string name="ambient_display_pickup_title" product="device" msgid="2480126522988135037">"Plocka upp för att kolla enheten"</string>
     <string name="ambient_display_wake_screen_title" msgid="3376988352851077102">"Skrämväckning"</string>
-    <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"Visa tid, aviseringar och annan information genom att plocka upp mobilen."</string>
+    <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"Visa tid, aviseringar och annan information genom att plocka upp telefonen."</string>
     <string name="ambient_display_pickup_summary" product="tablet" msgid="1077745287100012928">"Visa tid, aviseringar och annan information genom att plocka upp surfplattan."</string>
     <string name="ambient_display_pickup_summary" product="device" msgid="404199660076598026">"Visa tid, aviseringar och annan information genom att plocka upp enheten."</string>
-    <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"Tryck för att kolla mobilen"</string>
+    <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"Tryck för att kolla telefonen"</string>
     <string name="ambient_display_tap_screen_title" product="tablet" msgid="6434521782016864148">"Tryck för att kolla surfplattan"</string>
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"Tryck för att kolla enheten"</string>
     <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"Visa tid, aviseringar och annan information genom att trycka på skärmen."</string>
     <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"Svep över fingeravtryckssensorn för aviseringar"</string>
     <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"Svep över fingeravtryckssensorn"</string>
-    <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"Visa aviseringar genom att svepa nedåt på fingeravtryckssensorn på baksidan av mobilen."</string>
+    <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"Visa aviseringar genom att svepa nedåt på fingeravtryckssensorn på baksidan av telefonen."</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="tablet" msgid="3480057984564476283">"Visa aviseringar genom att svepa nedåt på fingeravtryckssensorn på baksidan av surfplattan."</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="device" msgid="7950264130913070035">"Visa aviseringar genom att svepa nedåt på fingeravtryckssensorn på baksidan av enheten."</string>
     <string name="fingerprint_swipe_for_notifications_suggestion_title" msgid="948946491233738823">"Visa aviseringar snabbt"</string>
diff --git a/tests/CarDeveloperOptions/res/values-sw/arrays.xml b/tests/CarDeveloperOptions/res/values-sw/arrays.xml
index 1d26443..0bfc1db 100644
--- a/tests/CarDeveloperOptions/res/values-sw/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-sw/arrays.xml
@@ -85,7 +85,7 @@
     <item msgid="8058143476674427024">"Inaunganisha kwa <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
     <item msgid="7547609081339573756">"Uhalalishaji kwa <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
     <item msgid="5145158315060185414">"Kupata anwani ya IP kutoka <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
-    <item msgid="3283243151651124831">" Umeunganishwa kwa<xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="3283243151651124831">"Umeunganishwa kwenye <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
     <item msgid="6600156231416890902">"Imetanguliwa"</item>
     <item msgid="4133290864821295785">"inakatisha muunganisho kutoka <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
     <item msgid="3980154971187953257">"Haijaunganishwa"</item>
@@ -276,7 +276,7 @@
     <item msgid="7692440726415391408">"tumia sip"</item>
     <item msgid="8572453398128326267">"chakata simu uliyopiga"</item>
     <item msgid="7775674394089376306">"alama ya kidole"</item>
-    <item msgid="3182815133441738779">"vihisi vya mwili"</item>
+    <item msgid="3182815133441738779">"vitambua shughuli za mwili"</item>
     <item msgid="2793100005496829513">"soma matangazo ya simu"</item>
     <item msgid="2633626056029384366">"eneo la jaribio"</item>
     <item msgid="8356842191824684631">"soma hifadhi"</item>
@@ -343,7 +343,7 @@
     <item msgid="9186411956086478261">"Tumia sip"</item>
     <item msgid="6884763100104539558">"Chakata simu uliyopiga"</item>
     <item msgid="125513972170580692">"Alama ya kidole"</item>
-    <item msgid="2556071024281275619">"Vihisi vya mwili"</item>
+    <item msgid="2556071024281275619">"Vitambua shughuli za mwili"</item>
     <item msgid="617168514928339387">"Soma matangazo ya simu"</item>
     <item msgid="7134693570516523585">"Eneo la jaribio"</item>
     <item msgid="7224489175375229399">"Soma hifadhi"</item>
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"Usiruhusu kamwe"</item>
     <item msgid="8184570120217958741">"Ruhusu kila wakati"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Kawaida"</item>
+    <item msgid="5101233285497327432">"Ya wastani"</item>
+    <item msgid="1555861583162930714">"Chini"</item>
+    <item msgid="1719683776264798117">"Imepungua sana"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Kawaida"</item>
+    <item msgid="6107138933849816768">"Wastani"</item>
+    <item msgid="182695359839047859">"Chini"</item>
+    <item msgid="8577246509202964244">"Imepungua sana"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Endelevu"</item>
     <item msgid="167418068739176448">"Shughuli maarufu"</item>
@@ -445,7 +455,7 @@
   <string-array name="color_picker">
     <item msgid="3151827842194201728">"Kijani"</item>
     <item msgid="3228505970082457852">"Samawati"</item>
-    <item msgid="6590260735734795647">"Bluu"</item>
+    <item msgid="6590260735734795647">"Nili"</item>
     <item msgid="3521763377357218577">"Zambarau"</item>
     <item msgid="5932337981182999919">"Waridi"</item>
     <item msgid="5642914536624000094">"Nyekundu"</item>
@@ -467,7 +477,7 @@
     <item msgid="1008268820118852416">"Tumia kama mtandao usiopima data"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
-    <item msgid="6545683814310036454">"Anwani ya MAC bila utaratibu wowote (chaguomsingi)"</item>
+    <item msgid="6545683814310036454">"Anwani ya MAC ya nasibu (chaguomsingi)"</item>
     <item msgid="214234417308375326">"Tumia anwani ya MAC ya kifaa"</item>
   </string-array>
   <string-array name="wifi_hidden_entries">
diff --git a/tests/CarDeveloperOptions/res/values-sw/config.xml b/tests/CarDeveloperOptions/res/values-sw/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-sw/config.xml
+++ b/tests/CarDeveloperOptions/res/values-sw/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-sw/strings.xml b/tests/CarDeveloperOptions/res/values-sw/strings.xml
index 4eceb54..6a8d648 100644
--- a/tests/CarDeveloperOptions/res/values-sw/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-sw/strings.xml
@@ -80,11 +80,10 @@
     <string name="sdcard_format" product="default" msgid="4831611387627849108">"Futa kadi ya SD"</string>
     <string name="preview_pager_content_description" msgid="5731599395893090038">"Kagua kwanza"</string>
     <string name="preview_page_indicator_content_description" msgid="3192955679074998362">"Onyesho la kuchungulia, ukurasa wa <xliff:g id="CURRENT_PAGE">%1$d</xliff:g> kati ya <xliff:g id="NUM_PAGES">%2$d</xliff:g>"</string>
-    <string name="font_size_summary" msgid="9120023206321191067">"Kuongeza au kupunguza ukubwa wa maandishi kwenye skrini."</string>
+    <string name="font_size_summary" msgid="9120023206321191067">"Ongeza au upunguze ukubwa wa maandishi kwenye skrini."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Punguza"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Kuza"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Sampuli ya maandishi"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Wachawi wa Ajabu kutoka Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Sura ya 11: Mji wa Ajabu wa Johari wa Oz"</string>
@@ -197,7 +196,7 @@
     <string name="proxy_settings_title" msgid="6014901859338211713">"Seva mbadala"</string>
     <string name="proxy_clear_text" msgid="498317431076294101">"Futa"</string>
     <string name="proxy_port_label" msgid="8285157632538848509">"Mlango wa seva mbadala"</string>
-    <string name="proxy_exclusionlist_label" msgid="8179084955547941904">"Proksi ya Bypass ya"</string>
+    <string name="proxy_exclusionlist_label" msgid="8179084955547941904">"Seva mbadala ya kando ya"</string>
     <string name="proxy_defaultView_text" msgid="5785775257042403261">"Rejesha kwa chaguo misingi"</string>
     <string name="proxy_action_text" msgid="814511434843981413">"Nimemaliza"</string>
     <string name="proxy_hostname_label" msgid="6798891831427287847">"Jina la mpangishaji wa seva mbadala"</string>
@@ -325,7 +324,7 @@
     <string name="date_and_time_settings_summary" msgid="4617979434474713417">"Weka tarehe, saa, saa za eneo na fomati"</string>
     <string name="date_time_auto" msgid="2679132152303750218">"Tumia saa ya mtandao"</string>
     <string name="zone_auto_title" msgid="5500880975376882488">"Tumia saa za eneo kutoka kwenye mtandao"</string>
-    <string name="date_time_24hour_auto" msgid="7499659679134962547">"Tumia lugha chaguomsingi"</string>
+    <string name="date_time_24hour_auto" msgid="7499659679134962547">"Tumia chaguomsingi la eneo"</string>
     <string name="date_time_24hour_title" msgid="6209923858891621283">"Mfumo wa saa 24"</string>
     <string name="date_time_24hour" msgid="1265706705061608742">"Tumia mpangilio wa saa 24"</string>
     <string name="date_time_set_time_title" msgid="7116850506333406367">"Saa"</string>
@@ -411,10 +410,10 @@
     <string name="face_add_max" msgid="8870899421165189413">"Unaweza kuongeza hadi nyuso <xliff:g id="COUNT">%d</xliff:g>"</string>
     <string name="face_intro_error_max" msgid="4024147799079828937">"Umeongeza idadi ya juu inayoruhusiwa ya nyuso"</string>
     <string name="face_intro_error_unknown" msgid="3241592604198351134">"Imeshindwa kuongeza nyuso zaidi"</string>
-    <string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"Hukukamilisha kujiandikishaji"</string>
+    <string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"Hukukamilisha kujiandikisha"</string>
     <string name="security_settings_face_enroll_dialog_ok" msgid="1078348922734845090">"Sawa"</string>
     <string name="security_settings_face_enroll_error_timeout_dialog_message" msgid="4917894418448325405">"Muda wa kuandikisha uso umefikia kikomo. Jaribu tena."</string>
-    <string name="security_settings_face_enroll_error_generic_dialog_message" msgid="5160473187142616862">"Imeshindwa kuandikisha uso."</string>
+    <string name="security_settings_face_enroll_error_generic_dialog_message" msgid="5160473187142616862">"Imeshindwa kusajili uso."</string>
     <string name="security_settings_face_enroll_finish_title" msgid="6800717857394410769">"Tayari kabisa. Safi."</string>
     <string name="security_settings_face_enroll_done" msgid="5409739233373490971">"Nimemaliza"</string>
     <string name="security_settings_face_settings_use_face_category" msgid="1586532139528115416">"Tumia uso wako kwa"</string>
@@ -426,7 +425,7 @@
     <string name="security_settings_face_settings_require_confirmation_details" msgid="8740564864091803429">"Iombe uthibitishaji kila wakati unapothibitisha katika programu"</string>
     <string name="security_settings_face_settings_remove_face_data" msgid="2821359954483136239">"Ondoa data ya uso"</string>
     <string name="security_settings_face_settings_footer" msgid="4627175759990550715">"Unaweza kutumia uso wako kufungua kifaa chako na kufikia programu. "<annotation id="url">"Pata maelezo zaidi"</annotation></string>
-    <string name="security_settings_face_settings_remove_dialog_title" msgid="5675319895815271094">"Je, ungependa kufuta data ya uso?"</string>
+    <string name="security_settings_face_settings_remove_dialog_title" msgid="5675319895815271094">"Ungependa kufuta data ya uso?"</string>
     <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"Data iliyorekodiwa na kipengele cha kufungua kwa uso itafutwa kabisa kwa njia salama. Ikishafutwa, utahitaji PIN, mchoro au nenosiri lako ili kufungua simu yako, kuingia kwenye akaunti za programu na kuthibitisha malipo."</string>
     <string name="security_settings_fingerprint_preference_title" msgid="4177132225930582928">"Kitambulisho"</string>
     <string name="fingerprint_manage_category_title" msgid="1463406696801542090">"Dhibiti vitambulisho"</string>
@@ -467,7 +466,7 @@
     <string name="security_settings_fingerprint_enroll_dialog_ok" msgid="3428927518029038956">"SAWA"</string>
     <string name="security_settings_fingerprint_enroll_dialog_delete" msgid="4312297515772004580">"Futa"</string>
     <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"Gusa kitambua alama ya kidole"</string>
-    <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Weka kidole chako juu ya kitambuzi kisha ukiinue baada ya kuhisi mtetemo"</string>
+    <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Weka kidole chako juu ya kitambua alama kisha ukiinue baada ya kuhisi mtetemo"</string>
     <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"Inua, kisha uguse tena"</string>
     <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Endelea kuinua kidole chako ili uongeze sehemu tofauti za alama ya kidole chako"</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"Alama ya kidole imeongezwa"</string>
@@ -488,7 +487,7 @@
     <string name="security_settings_fingerprint_enroll_done" msgid="4111289529758845926">"Nimemaliza"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"Lo, hicho si kitambuzi"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"Gusa kitambua alama ya kidole kilicho nyuma ya simu yako. Tumia kidole chako cha shahada."</string>
-    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"Hukukamilisha kujiandikishaji"</string>
+    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"Hukukamilisha kujiandikisha"</string>
     <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Muda wa uandikishaji wa kitambulisho umefikia kikomo. Jaribu tena."</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"Uandikishaji wa kitambulisho haukufanya kazi. Jaribu tena au utumie kitambulisho tofauti."</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"Ongeza kingine"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Lazima iwe na chini ya tarakimu <xliff:g id="NUMBER_1">%d</xliff:g></item>
       <item quantity="one">Lazima iwe na chini ya tarakimu <xliff:g id="NUMBER_0">%d</xliff:g></item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Ni lazima iwe na tarakimu 0-9 pekee"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Msimamizi wa kifaa haruhusu utumie PIN uliyotumia hivi majuzi"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"PIN zinazotumika zaidi zimezuiwa na msimamizi wako wa Tehama. Jaribu PIN tofauti."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Hali hii haiwezi kujumuisha kibambo kisichoruhusiwa"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Ni lazima liwe na angalau vibambo <xliff:g id="COUNT">%d</xliff:g> ambavyo si herufi</item>
       <item quantity="one">Ni lazima liwe na angalau kibambo 1 ambacho si herufi</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Ni lazima liwe na angalau herufi <xliff:g id="COUNT">%d</xliff:g> ambazo si tarakimu</item>
+      <item quantity="one">Ni lazima liwe na angalau herufi moja ambayo si tarakimu</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Msimamizi wa kifaa haruhusu kutumia nenosiri ulilotumia hivi majuzi"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Manenosiri yanayotumika sana yamezuiwa na msimamizi wako wa Tehama. Jaribu nenosiri tofauti."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Haturuhusi mpangilio wa kupanda, kushuka au kujirudia kwa tarakimu"</string>
@@ -824,7 +826,7 @@
     <string name="nfc_disclaimer_title" msgid="4860231267351602970">"Washa NFC"</string>
     <string name="nfc_disclaimer_content" msgid="3066113577854565782">"NFC hubadilisha data kati ya kifaa hiki na malengo au vifaa vingine vya karibu nawe, kama vile vituo vya malipo, visomaji vya data ya kadi na lebo au matangazo yanayoshirikisha mtumiaji."</string>
     <string name="nfc_secure_settings_title" msgid="5153751163174916581">"Imarisha usalama wa NFC"</string>
-    <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"Ruhusu tu matumizi katika Usafiri wa Umma na Malipo ya NFC wakati skrini imefunguliwa"</string>
+    <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"Ruhusu matumizi katika Usafiri wa Umma na Malipo ya NFC wakati tu skrini imefunguliwa"</string>
     <string name="android_beam_settings_title" msgid="3083436415873738389">"Android Beam"</string>
     <string name="android_beam_on_summary" msgid="8068287225180474199">"Programu iko tayari kusambaza maudhui kupitia NFC"</string>
     <string name="android_beam_off_summary" msgid="7365818039159364600">"Imezimwa"</string>
@@ -844,7 +846,7 @@
     <string name="wifi_error" msgid="5605801874484465557">"Hitilafu"</string>
     <string name="wifi_sap_no_channel_error" msgid="6881796988574851628">"Mitabendi ya GHz 5 haipatikani katika nchi hii"</string>
     <string name="wifi_in_airplane_mode" msgid="4729571191578262246">"Hali ya ndegeni imewashwa"</string>
-    <string name="wifi_notify_open_networks" msgid="4782239203624619655">"Fungua arifa za mtandao"</string>
+    <string name="wifi_notify_open_networks" msgid="4782239203624619655">"Arifu kuhusu mitandao wazi"</string>
     <string name="wifi_notify_open_networks_summary" msgid="1383681260705466715">"Tuma arifa wakati mtandao wenye ubora wa juu unapatikana"</string>
     <string name="wifi_wakeup" msgid="4963732992164721548">"Washa Wi‑Fi kiotomatiki"</string>
     <string name="wifi_wakeup_summary" msgid="1152699417411690">"Wi-Fi itaanza kutumika tena mitandao iliyohifadhiwa ya ubora wa juu itakapopatikana, kama vile mtandao wa nyumbani"</string>
@@ -913,7 +915,7 @@
     <string name="passpoint_label" msgid="7429247462404128615">"Imehifadhiwa kupitia"</string>
     <string name="passpoint_content" msgid="340527524510304327">"Kitambulisho cha <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_eap_method" msgid="3752116941487485859">"Mtindo wa EAP"</string>
-    <string name="please_select_phase2" msgid="5848080896810435677">"Uhalalishaji wa awamu ya 2"</string>
+    <string name="please_select_phase2" msgid="5848080896810435677">"Uthibitisho wa awamu ya pili"</string>
     <string name="wifi_eap_ca_cert" msgid="1496395241849383785">"Cheti cha CA"</string>
     <string name="wifi_eap_domain" msgid="3298302320003640130">"Kikoa"</string>
     <string name="wifi_eap_user_cert" msgid="6786839531765719173">"Cheti cha mtumiaji"</string>
@@ -925,7 +927,7 @@
     <string name="wifi_ap_choose_auto" msgid="7927637960569365785">"Otomatiki"</string>
     <string name="wifi_ap_choose_2G" msgid="43198403259714736">"Bendi ya GHz 2.4"</string>
     <string name="wifi_ap_choose_5G" msgid="2624859713183683146">"Bendi ya GHz 5.0"</string>
-    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"Imechagua Bendi ya GHz 5.0"</string>
+    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"Bendi ya GHz 5.0 (inapendelewa)"</string>
     <string name="wifi_ap_2G" msgid="5793110086517338494">"GHz 2.4"</string>
     <string name="wifi_ap_5G" msgid="4584892544393675403">"GHz 5.0"</string>
     <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"Chagua angalau bendi moja ya mtandaopepe wa Wi‑Fi:"</string>
@@ -943,8 +945,8 @@
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"Imeshindwa kusoma msimbo wa QR. Weka msimbo upya kisha ujaribu tena"</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"Jaribu tena. Tatizo hili likiendelea, wasiliana na kampuni iliyotengeneza kifaa"</string>
     <string name="wifi_dpp_failure_not_compatible" msgid="4320027179973678283">"Hitilafu fulani imetokea"</string>
-    <string name="wifi_dpp_failure_timeout" msgid="5060065168142109420">"Hakikisha kuwa umechomeka kifaa, umechaji na umekiwasha"</string>
-    <string name="wifi_dpp_failure_generic" msgid="7840142544736640189">"Hakikisha kuwa umechomeka kifaa, umechaji na umekiwasha. Tatizo hili likiendelea, wasiliana na kampuni iliyotengeneza kifaa"</string>
+    <string name="wifi_dpp_failure_timeout" msgid="5060065168142109420">"Hakikisha kuwa umechomeka kifaa, umekichaji na umekiwasha"</string>
+    <string name="wifi_dpp_failure_generic" msgid="7840142544736640189">"Hakikisha kuwa umechomeka kifaa, umekichaji na umekiwasha. Tatizo hili likiendelea, wasiliana na kampuni iliyotengeneza kifaa"</string>
     <string name="wifi_dpp_failure_not_supported" msgid="111779621766171626">"Huwezi kuongeza “<xliff:g id="SSID">%1$s</xliff:g>” kwenye kifaa hiki"</string>
     <string name="wifi_dpp_check_connection_try_again" msgid="7144663015219170999">"Angalia muunganisho na ujaribu tena"</string>
     <string name="wifi_dpp_choose_network" msgid="6251424431594491691">"Chagua mtandao"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mtandao wa simu"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Ikiwa Wi-Fi haipatikani, tumia mtandao wa simu"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Ikiwa mtandao wa simu haupatikani, tumia Wi-Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Piga simu kupitia WI-FI. Ikiwa Wi-Fi haipatikani, simu itakatika."</string>
@@ -1204,15 +1209,15 @@
     <string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"Imewashwa / Skrini haitazima ikiwa unaiangalia"</string>
     <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"Imezimwa"</string>
     <string name="adaptive_sleep_description" msgid="812673735459170009">"Huzuia skrini yako kuzima ikiwa unaiangalia."</string>
-    <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Kipengele cha utashi wa skrini kinatumia kamera ya mbele ili kuona ikiwa kuna mtu anayeangalia skrini. Hufanya kazi kwenye kifaa na picha hazihifadhiwi wala kutumwa kwa Google."</string>
+    <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Kipengele cha utashi wa skrini kinatumia kamera ya mbele ili kuona ikiwa kuna mtu anayeangalia skrini. Kipengele hiki hufanya kazi kwenye kifaa na picha hazihifadhiwi wala kutumwa kwa Google."</string>
     <string name="night_display_title" msgid="1305002424893349814">"Mwanga wa Usiku"</string>
     <string name="night_display_text" msgid="5330502493684652527">"Mwanga wa Usiku hugeuza rangi ya skrini yako kuwa manjano. Hali hii hufanya iwe rahisi kuangalia skrini yako au kusoma katika mwangaza hafifu na inaweza kukusaidia ulale kwa urahisi zaidi."</string>
     <string name="night_display_auto_mode_title" msgid="8493573087102481588">"Ratiba"</string>
     <string name="night_display_auto_mode_never" msgid="2897444637217807088">"Hamna"</string>
     <string name="night_display_auto_mode_custom" msgid="1400891076453963151">"Iwake wakati maalum"</string>
     <string name="night_display_auto_mode_twilight" msgid="4000162110017520674">"Iwake usiku kucha"</string>
-    <string name="night_display_start_time_title" msgid="1069255169673371077">"Itawashwa"</string>
-    <string name="night_display_end_time_title" msgid="2760793157124245911">"Itazimwa"</string>
+    <string name="night_display_start_time_title" msgid="1069255169673371077">"Kuwaka"</string>
+    <string name="night_display_end_time_title" msgid="2760793157124245911">"Kuzima"</string>
     <string name="night_display_status_title" msgid="1727020934735770319">"Hali"</string>
     <string name="night_display_temperature_title" msgid="8375126629902616296">"Ukolezaji"</string>
     <string name="night_display_summary_off" msgid="8850539785332228069">"Imezimwa. <xliff:g id="ID_1">%1$s</xliff:g>"</string>
@@ -1241,7 +1246,7 @@
     <string name="wallpaper_suggestion_summary" msgid="4247262938988875842">"Weka mapendeleo ya skrini yako"</string>
     <string name="wallpaper_settings_fragment_title" msgid="1503701065297188901">"Chagua mandhari kutoka"</string>
     <string name="screensaver_settings_title" msgid="7720091234133721021">"Taswira ya skrini"</string>
-    <string name="screensaver_settings_summary_either_long" msgid="6078038506795498288">"Inapochaji au imeunganishwa na kifaa kingine"</string>
+    <string name="screensaver_settings_summary_either_long" msgid="6078038506795498288">"Wakati imeunganishwa na kifaa kingine au inapochaji"</string>
     <string name="screensaver_settings_summary_either_short" msgid="2453772128682850053">"Yoyote kati ya hizi mbili"</string>
     <string name="screensaver_settings_summary_sleep" msgid="6097363596749362692">"Inapochaji"</string>
     <string name="screensaver_settings_summary_dock" msgid="6297808146601570196">"Wakati imeunganishwa na kifaa kingine"</string>
@@ -1261,7 +1266,7 @@
     <string name="doze_always_on_title" msgid="8555184965031789941">"Ikae ikiwa imewashwa"</string>
     <string name="doze_always_on_summary" msgid="7654436900436328950">"Onyesha saa, aikoni za arifa na maelezo mengine. Inatumia chaji nyingi."</string>
     <string name="title_font_size" msgid="5021464556860010851">"Ukubwa wa fonti"</string>
-    <string name="short_summary_font_size" msgid="4141077908728522946">"Kuongeza au kupunguza ukubwa wa maandishi"</string>
+    <string name="short_summary_font_size" msgid="4141077908728522946">"Ongeza au upunguze ukubwa wa maandishi"</string>
     <string name="sim_lock_settings" msgid="1986924650622642189">"Mipangilio ya kufunga SIM"</string>
     <string name="sim_lock_settings_category" msgid="1126759898277681516">"Kufunga SIM kadi"</string>
     <string name="sim_lock_settings_summary_off" msgid="348656447968142307">"Imezimwa"</string>
@@ -1526,7 +1531,7 @@
     <string name="apn_not_set" msgid="5344235604466825691">"Haijawekwa"</string>
     <string name="apn_name" msgid="8431432886706852226">"Jina"</string>
     <string name="apn_apn" msgid="190519449579357696">"APN"</string>
-    <string name="apn_http_proxy" msgid="8816906767987944465">"Ndogo"</string>
+    <string name="apn_http_proxy" msgid="8816906767987944465">"Seva mbadala"</string>
     <string name="apn_http_port" msgid="5789193688960075486">"Mlango"</string>
     <string name="apn_user" msgid="6979724587671704006">"Jina la mtumiaji"</string>
     <string name="apn_password" msgid="7140724726108226386">"Nenosiri"</string>
@@ -1536,17 +1541,17 @@
     <string name="apn_mms_port" msgid="6606572282014819299">"Mlango wa  MMS"</string>
     <string name="apn_mcc" msgid="9138301167194779180">"MCC"</string>
     <string name="apn_mnc" msgid="1276161191283274976">"MNC"</string>
-    <string name="apn_auth_type" msgid="4286147728662523362">"Aina ya uhalalishaji"</string>
+    <string name="apn_auth_type" msgid="4286147728662523362">"Aina ya uthibitishaji"</string>
     <string name="apn_auth_type_none" msgid="3679273936413404046">"Hamna"</string>
     <string name="apn_auth_type_pap" msgid="6155876141679480864">"PAP"</string>
     <string name="apn_auth_type_chap" msgid="5484031368454788686">"CHAP"</string>
     <string name="apn_auth_type_pap_chap" msgid="2977833804460109203">"PAP au CHAP"</string>
     <string name="apn_type" msgid="6725346490902871146">"Aina ya APN"</string>
     <string name="apn_protocol" msgid="1240197323563960912">"Itifaki ya APN"</string>
-    <string name="apn_roaming_protocol" msgid="6913336248771263497">"Itifaki ya urandaji ya APN"</string>
-    <string name="carrier_enabled" msgid="1819916725305365581">"APN Wezesha/Lemaza"</string>
-    <string name="carrier_enabled_summaryOn" msgid="6219221535461945771">"APN imewezeshwa"</string>
-    <string name="carrier_enabled_summaryOff" msgid="4093019532796386622">"APN imelemazwa"</string>
+    <string name="apn_roaming_protocol" msgid="6913336248771263497">"Itifaki ya APN: mitandao ya nga\'ambo"</string>
+    <string name="carrier_enabled" msgid="1819916725305365581">"APN washa/zima"</string>
+    <string name="carrier_enabled_summaryOn" msgid="6219221535461945771">"APN imewashwa"</string>
+    <string name="carrier_enabled_summaryOff" msgid="4093019532796386622">"APN imezimwa"</string>
     <string name="bearer" msgid="4378444317087536401">"Mwenye"</string>
     <string name="mvno_type" msgid="3150755279048149624">"Aina ya MVNO"</string>
     <string name="mvno_match_data" msgid="629287305803195245">"Thamani ya MVNO"</string>
@@ -1566,8 +1571,8 @@
     <string name="reset_dashboard_title" msgid="7084966342252178530">"Chaguo za kubadilisha mipangilio"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"Unaweza kubadilisha mipangilio ya mtandao, programu au kifaa"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"Badilisha mipangilio ya Wi-Fi, data ya simu na Bluetooth"</string>
-    <string name="reset_network_desc" msgid="4982633363916261109">"Hatua hii itabadilisha mipangilio yote ya mtandao ikiwa ni pamoja:\n\n"<li>"Wi‑Fi"</li>\n<li>"Data ya simu"</li>\n<li>"Bluetooth"</li></string>
-    <string name="reset_esim_title" msgid="7630781767040831893">"Futa data iliyopakuliwa kwenye SIMs"</string>
+    <string name="reset_network_desc" msgid="4982633363916261109">"Hatua hii itabadilisha mipangilio yote ya mtandao ikiwa ni pamoja na:\n\n"<li>"Wi‑Fi"</li>\n<li>"Data ya simu"</li>\n<li>"Bluetooth"</li></string>
+    <string name="reset_esim_title" msgid="7630781767040831893">"Futa SIM zilizopakuliwa"</string>
     <string name="reset_esim_desc" msgid="433226911566802">"Ili upakue SIM za kubadilisha, wasiliana na mtoa huduma wako. Hatua hii haitaghairi mipango yoyote ya huduma za simu."</string>
     <string name="reset_network_button_text" msgid="4293271046867912819">"Badilisha mipangilio"</string>
     <string name="reset_network_final_desc" msgid="2463817067048751373">"Je, ungependa kubadilisha mipangilio yote ya mtandao? Huwezi kutendua kitendo hiki."</string>
@@ -1642,7 +1647,7 @@
     <string name="mobile_insert_sim_card" msgid="7594550403454243732">"Tafadhali weka SIM kadi kisha uzime na uwashe"</string>
     <string name="mobile_connect_to_internet" msgid="6031886097365170913">"Tafadhali unganisha kwenye Intaneti"</string>
     <string name="location_title" msgid="8664674161765477168">"Mahali pangu"</string>
-    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"Eneo la wasifu wa kazini"</string>
+    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"Wasifu wa kazi kutambua mahali"</string>
     <string name="location_app_level_permissions" msgid="1298041503927632960">"Ruhusa ya programu"</string>
     <string name="location_app_permission_summary_location_off" msgid="541372845344796336">"Utambuzi wa mahali umezimwa"</string>
     <plurals name="location_app_permission_summary_location_on" formatted="false" msgid="7904821382328758218">
@@ -1659,7 +1664,7 @@
     <string name="location_scanning_wifi_always_scanning_title" msgid="6750542206763112172">"Kutafuta Wi-Fi"</string>
     <string name="location_scanning_wifi_always_scanning_description" msgid="4956048135941851712">"Ruhusu programu na huduma zitafute mitandao ya Wi-Fi wakati wowote, hata wakati umezima Wi-Fi. Hali hii inaweza kutumika, kwa mfano, kuboresha huduma na vipengele vinavyohusiana na mahali."</string>
     <string name="location_scanning_bluetooth_always_scanning_title" msgid="196241746742607453">"Kutafuta Bluetooth"</string>
-    <string name="location_scanning_bluetooth_always_scanning_description" msgid="3796673798637848690">"Ruhusu programu na huduma itafute vifaa vilivyo karibu wakati wowote, hata wakati umezima Bluetooth. Hali hii inaweza kutumika, kwa mfano, kuboresha huduma na vipengele vinavyohusiana na mahali."</string>
+    <string name="location_scanning_bluetooth_always_scanning_description" msgid="3796673798637848690">"Ruhusu programu na huduma zitafute vifaa vilivyo karibu wakati wowote, hata wakati umezima Bluetooth. Hali hii inaweza kutumika, kwa mfano, kuboresha huduma na vipengele vinavyohusiana na mahali."</string>
     <string name="managed_profile_location_services" msgid="224925483299159541">"Huduma za Mahali za kazini"</string>
     <string name="location_network_based" msgid="1535812159327454835">"Eneo la mtandao wa Wi-Fi na wa simu"</string>
     <string name="location_neighborhood_level" msgid="8459352741296587916">"Ruhusu programu zitumie huduma ya Google ya mahali ili kukadiria ulipo kwa haraka. Data ya mahali isiyokutambulisha itakusanywa na kutumwa kwa Google."</string>
@@ -1800,7 +1805,7 @@
     <string name="screen_compatibility_label" msgid="3638271673726075815">"Utangamanifu wa skrini"</string>
     <string name="permissions_label" msgid="7341733648403464213">"Ruhusa"</string>
     <string name="cache_header_label" msgid="3202284481380361966">"Akiba"</string>
-    <string name="clear_cache_btn_text" msgid="107507684844780651">"Futa akiba"</string>
+    <string name="clear_cache_btn_text" msgid="107507684844780651">"Futa data iliyoakibishwa"</string>
     <string name="cache_size_label" msgid="6205173678102220499">"Akiba"</string>
     <plurals name="uri_permissions_text" formatted="false" msgid="8938478333743197020">
       <item quantity="other">Vipengee %d</item>
@@ -1820,7 +1825,7 @@
     <string name="install_text" msgid="2798092278891807849">"Weka"</string>
     <string name="disable_text" msgid="5065834603951474397">"Zima"</string>
     <string name="enable_text" msgid="7179141636849225884">"Washa"</string>
-    <string name="clear_user_data_text" msgid="8894073247302821764">"Futa hifadhi"</string>
+    <string name="clear_user_data_text" msgid="8894073247302821764">"Futa data ya hifadhi"</string>
     <string name="app_factory_reset" msgid="8718986000278776272">"Ondoa masasisho"</string>
     <string name="auto_launch_enable_text" msgid="3372898942144027341">"Umechagua kuzindua programu hii kwa mbadala kwa baadhi ya vitendo."</string>
     <string name="always_allow_bind_appwidgets_text" msgid="2286211654774611037">"Umechagua kuruhusu programu hii kuunda wijeti na kufikia data yao."</string>
@@ -1955,7 +1960,7 @@
     <string name="auto_punctuate_summary" msgid="245694025030386370">"Bonyeza kibonye cha \'Space\' mara mbili ili uweke \".\""</string>
     <string name="show_password" msgid="620964020348073739">"Onyesha manenosiri"</string>
     <string name="show_password_summary" msgid="1403805089582258620">"Onyesha herufi kwa muda mfupi unapoandika"</string>
-    <string name="spellchecker_security_warning" msgid="792070474432612097">"Kisasishaji hiki kinaweza kukusanya maandishi yote wakati unaangika, pamoja na data za kibinafsi kama nenosiri na namari za kadi ya mkopo. Inatoka kwa programu <xliff:g id="SPELLCHECKER_APPLICATION_NAME">%1$s</xliff:g>. Tumia kisasishaji hiki?"</string>
+    <string name="spellchecker_security_warning" msgid="792070474432612097">"Kikagua tahajia hiki kinaweza kukusanya maandishi yote wakati unaandika, ikiwemo data ya binafsi kama nenosiri na nambari za kadi za mikopo. Kinatoka kwa programu ya <xliff:g id="SPELLCHECKER_APPLICATION_NAME">%1$s</xliff:g>. Ungependa kutumia kikagua tahajia hiki?"</string>
     <string name="spellchecker_quick_settings" msgid="5193036510190696655">"Mipangilio"</string>
     <string name="spellchecker_language" msgid="5168501692418112444">"Lugha"</string>
     <string name="keyboard_and_input_methods_category" msgid="5870292843201629800">"Kibodi"</string>
@@ -2079,7 +2084,7 @@
     <string name="accessibility_content_timeout_preference_title" msgid="5160746882250939464">"Wakati wa kusoma"</string>
     <string name="accessibility_control_timeout_preference_title" msgid="2771808346038759474">"Wakati wa kuchukua hatua"</string>
     <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"Chagua muda ambao ungependa kuonyesha ujumbe unaohitaji kusoma, lakini unaonekana kwa muda mfupi. \n\nBaadhi ya programu hazitumii mipangilio hii."</string>
-    <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"Chagua muda ambao ungependa kuonyesha ujumbe unaokuomba uchukue hatua, lakini utaonekana kwa muda mfupi.\n\nBaadhi ya programu hazitumii mipangilio hii."</string>
+    <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"Chagua muda ambao ungependa kuonyesha ujumbe unaokuomba uchukue hatua, unaoonekana kwa muda mfupi.\n\nBaadhi ya programu hazitumii mipangilio hii."</string>
     <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"Muda wa kugusa na kushikilia"</string>
     <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"Ugeuzaji rangi"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"Huenda ikaathiri utendaji"</string>
@@ -2089,7 +2094,7 @@
     <string name="accessibility_vibration_settings_title" msgid="1902649657883159406">"Mtetemo"</string>
     <string name="accessibility_notification_vibration_title" msgid="1005799039440510298">"Mtetemo wa arifa"</string>
     <string name="accessibility_ring_vibration_title" msgid="7943341443551359985">"Mtetemo wa mlio"</string>
-    <string name="accessibility_touch_vibration_title" msgid="285890135612038092">"Mtetemo wa mguso"</string>
+    <string name="accessibility_touch_vibration_title" msgid="285890135612038092">"Mtetemo inapoguswa"</string>
     <string name="accessibility_service_master_switch_title" msgid="2734791644475782924">"Tumia huduma"</string>
     <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Tumia usahihishaji wa rangi"</string>
     <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"Tumia manukuu"</string>
@@ -2275,7 +2280,7 @@
     <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"Washa Kiokoa Betri"</string>
     <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"Huenda chaji ikaisha haraka zaidi"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"Kiokoa Betri kimewashwa"</string>
-    <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Huenda ikadhibiti baadhi ya vipengele"</string>
+    <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"Huenda baadhi ya vipengele vimedhibitiwa"</string>
     <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"Simu imetumika sana kuliko kawaida"</string>
     <string name="battery_tip_high_usage_title" product="tablet" msgid="1019583260005768965">"Kompyuta kibao imetumika sana kuliko kawaida"</string>
     <string name="battery_tip_high_usage_title" product="device" msgid="8304138287288309490">"Kifaa kimetumika sana kuliko kawaida"</string>
@@ -2309,7 +2314,7 @@
     <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"Ili uokoe betri, zuia programu hizi zisitumie chaji chinichini. Huenda programu zilizozuiliwa zisifanye kazi vizuri na huenda arifa zikachelewa.\n\nProgramu:\n<xliff:g id="APP_LIST">%1$s</xliff:g>."</string>
     <string name="battery_tip_restrict_app_dialog_ok" msgid="2573410775701913487">"Zuia"</string>
     <string name="battery_tip_unrestrict_app_dialog_title" msgid="812458516399125710">"Ungependa kuondoa kizuizi?"</string>
-    <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"Programu hii itatumia chaji chinichini. Hali hii inaweza kusababisha chaji ya betri iishe haraka."</string>
+    <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"Programu hii itatumia chaji chinichini. Hali hii inaweza kufanya chaji ya betri iishe haraka."</string>
     <string name="battery_tip_unrestrict_app_dialog_ok" msgid="9154938931448151479">"Ondoa"</string>
     <string name="battery_tip_unrestrict_app_dialog_cancel" msgid="7331148618292397166">"Ghairi"</string>
     <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"Programu zako zinatumia kiwango cha kawaida cha betri. Programu zikitumia kiwango cha juu zaidi cha betri, simu yako itapendekeza hatua unazoweza kuchukua.\n\nUnaweza kuwasha Kiokoa Betri wakati wowote, kama chaji ya betri yako inakaribia kuisha."</string>
@@ -2447,10 +2452,10 @@
     <string name="battery_saver_auto_routine" msgid="886514412067906980">"Kulingana na ratiba yako"</string>
     <string name="battery_saver_auto_percentage" msgid="5791982309331921556">"Kulingana na asilimia"</string>
     <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"Kiokoa betri huwashwa kama betri yako inakaribia kuisha kabla ya muda wako wa kawaida wa kuchaji"</string>
-    <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"Itawashwa ikiwa <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
+    <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"Kitawaka ikifika <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"Weka ratiba"</string>
     <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"Zima kiokoa betri inapojazwa chaji"</string>
-    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"Kiokoa betri hujizima simu yako inapokuwa na <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
+    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"Kiokoa betri hujizima simu yako inapofika <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <string name="battery_saver_sticky_description_new" product="tablet" msgid="3284967694001857194">"Kiokoa betri hujizima kompyuta yako kibao inapokuwa na <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <string name="battery_saver_sticky_description_new" product="device" msgid="5056520668081504111">"Kiokoa betri hujizima kifaa chako kinapokuwa na <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <!-- no translation found for battery_saver_seekbar_title (7607123201469333645) -->
@@ -2709,8 +2714,8 @@
     <string name="data_usage_warning_editor_title" msgid="1431385383278389290">"Weka onyo kwa matumizi ya data"</string>
     <string name="data_usage_limit_editor_title" msgid="1687908662154108293">"Weka kikomo cha matumizi ya data"</string>
     <string name="data_usage_limit_dialog_title" msgid="8804760847110131518">"Kupunguza matumizi ya data"</string>
-    <string name="data_usage_limit_dialog_mobile" product="tablet" msgid="2000713577999830647">"Kompyuta kibao yako itazima data ya mtandao wa simu pindi itakapofikia kikomo cha matumizi ulichoweka.\n\nKwa kuwa kompyuta kibao yako ndiyo huwa inapima matumizi ya data, na kampuni inayokupa huduma za mtandao huenda ikahesabu matumizi kwa njia tofauti, unashauriwa kuweka kikomo kisicho kamili sana."</string>
-    <string name="data_usage_limit_dialog_mobile" product="default" msgid="943546278705619205">"Simu yako itazima data ya mtandao wa simu pindi itakapofikia kikomo cha matumizi ya data ulichoweka. \n\nKwa kuwa simu yako ndiyo huwa inapima matumizi ya data, na kampuni inayokupa huduma za mtandao huenda ikahesabu matumizi kwa njia tofauti, unashauriwa kuweka kikomo kisicho kamili sana."</string>
+    <string name="data_usage_limit_dialog_mobile" product="tablet" msgid="2000713577999830647">"Kompyuta kibao yako itazima data ya mtandao wa simu pindi itakapofikia kikomo cha matumizi ulichoweka.\n\nKwa kuwa kompyuta kibao yako ndiyo huwa inapima matumizi ya data, na kampuni inayokupa huduma za mtandao huenda ikahesabu matumizi kwa njia tofauti, unashauriwa kuweka kikomo cha wastani."</string>
+    <string name="data_usage_limit_dialog_mobile" product="default" msgid="943546278705619205">"Simu yako itazima data ya mtandao wa simu pindi itakapofikia kikomo cha matumizi ya data ulichoweka. \n\nKwa kuwa simu yako ndiyo huwa inapima matumizi ya data, na kampuni inayokupa huduma za mtandao huenda ikahesabu matumizi kwa njia tofauti, unashauriwa kuweka kikomo cha wastani."</string>
     <string name="data_usage_restrict_background_title" msgid="3568746530413220844">"Zuia data ya mandhari nyuma?"</string>
     <string name="data_usage_restrict_background" msgid="995811034744808575">"Ukidhibiti matumizi ya chini chini ya data ya mitandao ya simu, baadhi ya programu na huduma hazitafanya kazi mpaka uunganishe kwenye Wi-Fi tena."</string>
     <string name="data_usage_restrict_background_multiuser" product="tablet" msgid="6032810839234864814">"Ukidhibiti matumizi ya chini chini ya data ya mtandao wa simu, baadhi ya programu na huduma hazitafanya kazi mpaka uunganishe kwenye Wi-Fi.\n\nMipangilio hii itaathiri watumiaji wote wa kompyuta kibao hii."</string>
@@ -2816,7 +2821,7 @@
     <string name="user_credential_removed" msgid="6243576567538844852">"Imeondoa kitambulisho: <xliff:g id="CREDENTIAL_NAME">%s</xliff:g>"</string>
     <string name="user_credential_none_installed" msgid="4129252817676332368">"Hakuna kitambulisho cha mtumiaji kilichowekwa"</string>
     <string name="spellcheckers_settings_title" msgid="1687210427248364327">"Kikagua maendelezo"</string>
-    <string name="spellcheckers_settings_for_work_title" msgid="7461318390801573022">"Kikagua maendelezo cha kazini"</string>
+    <string name="spellcheckers_settings_for_work_title" msgid="7461318390801573022">"Kikagua tahajia cha kazini"</string>
     <string name="current_backup_pw_prompt" msgid="8914812770233159610">"Andika nenosiri unalotumia kuhifadhi nakala kamili"</string>
     <string name="new_backup_pw_prompt" msgid="4949729756223335850">"Andika nenosiri jipya la kuhifadhi nakala kamili"</string>
     <string name="confirm_new_backup_pw_prompt" msgid="3357847425183550770">"Andika tena nenosiri lako la kuhifadhi nakala kamili"</string>
@@ -2865,7 +2870,7 @@
     <string name="user_add_user_item_title" msgid="6835385073795492410">"Mtumiaji"</string>
     <string name="user_add_profile_item_title" msgid="4932743891449790664">"Wasifu uliozuiwa"</string>
     <string name="user_add_user_title" msgid="2320897397066676472">"Ungependa kuongeza mtumiaji?"</string>
-    <string name="user_add_user_message_long" msgid="686637203224195465">"Unaweza kutumia kifaa hiki pamoja na watu wengine kwa kuongeza watumiaji wa ziada. Kila mtumiaji ana nafasi yake mwenyewe, ambayo anaweza kuweka programu, mandhari na vipengee vingine anavyopenda. Watumiaji pia wanaweza kurekebisha mipangilio ya kifaa inayoathiri kila mtu kama vile Wi-Fi.\n\nUnapomwongeza mtumiaji mpya, mtu huyo anahitaji kujitayarishia nafasi yake.\n\nMtumiaji yeyote anaweza kuwasasishia watumiaji wengine wote programu. Huenda mipangilio na huduma za walio na matatizo ya kuona na kusikia zisihamishiwe mtumiaji mgeni."</string>
+    <string name="user_add_user_message_long" msgid="686637203224195465">"Unaweza kutumia kifaa hiki pamoja na watu wengine kwa kuongeza watumiaji wa ziada. Kila mtumiaji ana nafasi yake mwenyewe, ambayo anaweza kuweka programu, mandhari na vipengee vingine anavyopenda. Watumiaji pia wanaweza kurekebisha mipangilio ya kifaa inayoathiri kila mtu kama vile Wi-Fi.\n\nUnapomwongeza mtumiaji mpya, mtu huyo anahitaji kujitayarishia nafasi yake.\n\nMtumiaji yeyote anaweza kuwasasishia watumiaji wengine wote programu. Huenda mipangilio na huduma za ufikivu zisihamishiwe mtumiaji mgeni."</string>
     <string name="user_add_user_message_short" msgid="1802594476285458254">"Mtumiaji mpya utakayemwongeza atahitaji kuongeza akaunti yake.\n\nMtumiaji yoyote anaweza kusasisha programu kwa niaba ya wengine wote."</string>
     <string name="user_setup_dialog_title" msgid="6748950002206392396">"Mtumiaji aongezwe sasa?"</string>
     <string name="user_setup_dialog_message" msgid="2988559933258353919">"Hakikisha kuwa mtu huyu anaweza kuchukua kifaa na kuweka mapendeleo yake"</string>
@@ -2920,7 +2925,7 @@
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Isipokuwa wakati programu nyingine ya malipo imefunguliwa"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"Unapolipa ukitumia chaguo la Gusisha ili ulipe, tumia:"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Kulipa katika kituo"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Sanidi programu ya malipo. Shikilia tu upande wa nyuma wa simu yako kwenye kituo chochote cha malipo chenye alama ya kulipa bila kugusa."</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Sanidi programu ya malipo. Kisha elekeza upande wa nyuma wa simu yako kwenye kituo chochote cha malipo chenye alama ya kulipa kwa njia za kielektroniki."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"Nimeelewa"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"Zaidi..."</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"Ungependa kuweka kama mapendeleo yako?"</string>
@@ -3147,7 +3152,7 @@
     <string name="charging_sounds_title" msgid="5070437987230894287">"Sauti za kuchaji na mtetemo"</string>
     <string name="docking_sounds_title" msgid="2573137471605541366">"Kuambatisha sauti"</string>
     <string name="touch_sounds_title" msgid="165237488496165652">"Sauti inapoguswa"</string>
-    <string name="vibrate_on_touch_title" msgid="6360155469279157684">"Mtetemo wa mguso"</string>
+    <string name="vibrate_on_touch_title" msgid="6360155469279157684">"Mtetemo inapoguswa"</string>
     <string name="vibrate_on_touch_summary" msgid="5504424764028676043">"Majibu unayoweza kuhisi kwa kugusa, kibodi na mengineyo"</string>
     <string name="dock_audio_media_title" msgid="1859521680502040781">"Cheza kutumia spika ya kituo"</string>
     <string name="dock_audio_media_disabled" msgid="4300752306178486302">"Sauti zote"</string>
@@ -3156,7 +3161,7 @@
     <string name="emergency_tone_alert" msgid="907868135091891015">"Milio"</string>
     <string name="emergency_tone_vibrate" msgid="5020068066905681181">"Mitetemo"</string>
     <string name="boot_sounds_title" msgid="7583926202411353620">"Washa sauti"</string>
-    <string name="live_caption_title" msgid="7926591158657997051">"Nukuu Papo Hapo"</string>
+    <string name="live_caption_title" msgid="7926591158657997051">"Manukuu Papo Hapo"</string>
     <string name="live_caption_summary" msgid="9064771862352393125">"Wekea maudhui manukuu kiotomatiki"</string>
     <string name="zen_mode_settings_summary_off" msgid="6929319200478424962">"Kamwe usiwashe"</string>
     <plurals name="zen_mode_settings_summary_on" formatted="false" msgid="6061723291126091396">
@@ -3316,7 +3321,7 @@
     <string name="notification_pulse_title" msgid="4861418327614907116">"Mwangaza umemeteke"</string>
     <string name="lock_screen_notifications_title" msgid="6889072265118747835">"Wakati skrini imefungwa"</string>
     <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"Wakati umefunga wasifu wa kazini"</string>
-    <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Onyesha arifa za maudhui yote"</string>
+    <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Onyesha maudhui yote ya arifa"</string>
     <string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"Ficha maudhui nyeti"</string>
     <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"Usionyeshe arifa zozote"</string>
     <string name="lock_screen_notifications_interstitial_message" msgid="4230189215124387818">"Je, ungependa arifa zipi zionyeshwe wakati kifaa kimefungwa?"</string>
@@ -3336,11 +3341,11 @@
     <string name="notification_importance_low" msgid="7609797151662295364">"Onyesha chinichini"</string>
     <string name="notification_importance_default" msgid="4091563759103917166">"Toa sauti"</string>
     <string name="notification_importance_high" msgid="7973764540402436656">"Toa sauti na ibukizi kwenye skrini"</string>
-    <string name="notification_importance_high_silent" msgid="3177662759865661155">"Ichomoze kwenye skrini"</string>
+    <string name="notification_importance_high_silent" msgid="3177662759865661155">"Zionekane kwenye skrini"</string>
     <string name="notification_importance_min_title" msgid="705872537330744154">"Punguza"</string>
     <string name="notification_importance_low_title" msgid="2956199021781786232">"Wastani"</string>
     <string name="notification_importance_default_title" msgid="7985549807203332482">"Juu"</string>
-    <string name="notification_importance_high_title" msgid="7258373094258585858">"Ichomoze kwenye skrini"</string>
+    <string name="notification_importance_high_title" msgid="7258373094258585858">"Zionekane kwenye skrini"</string>
     <string name="notification_block_title" msgid="2570364198866886906">"Zuia"</string>
     <string name="notification_silence_title" msgid="6959637402003838093">"Ionyeshe bila kutoa sauti"</string>
     <string name="notification_alert_title" msgid="750683027055192648">"Arifa"</string>
@@ -3514,7 +3519,7 @@
     <string name="zen_mode_contacts_callers" msgid="3116829245339716399">"anwani"</string>
     <string name="zen_mode_starred_callers" msgid="1317376207713013472">"anwani zenye nyota"</string>
     <string name="zen_mode_repeat_callers" msgid="1435309867554692340">"Wanaorudia kupiga simu"</string>
-    <string name="zen_mode_repeat_callers_list" msgid="2750270907597457279">"waliopiga simu mara kadhaa"</string>
+    <string name="zen_mode_repeat_callers_list" msgid="2750270907597457279">"wanaorudia kupiga simu"</string>
     <string name="zen_mode_repeat_callers_title" msgid="7192952181541813487">"Ruhusu wanaorudia kupiga simu"</string>
     <string name="zen_mode_calls_summary_one" msgid="8327371053236689649">"Ruhusu kutoka kwa <xliff:g id="CALLER_TYPE">%1$s</xliff:g>"</string>
     <string name="zen_mode_calls_summary_two" msgid="9017678770532673578">"Ruhusu kutoka kwa <xliff:g id="CALLER_TYPE">%1$s</xliff:g> na <xliff:g id="CALLERT_TPYE">%2$s</xliff:g>"</string>
@@ -3691,7 +3696,7 @@
     <string name="process_format" msgid="8575347150598564509">"<xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="COUNT">%2$d</xliff:g>)"</string>
     <string name="high_power_apps" msgid="2518319744362028920">"Kuboresha matumizi ya betri"</string>
     <string name="additional_battery_info" msgid="6877663897819271203">"Arifa za matumizi"</string>
-    <string name="show_all_apps" msgid="5442552004569634846">"Onyesha matumizi ya kifaa kilichojaa"</string>
+    <string name="show_all_apps" msgid="5442552004569634846">"Onyesha matumizi kamili ya kifaa"</string>
     <string name="hide_extra_apps" msgid="6798261081113299441">"Onyesha matumizi ya programu"</string>
     <plurals name="power_high_usage_summary" formatted="false" msgid="4658343710126205199">
       <item quantity="other">Programu <xliff:g id="NUMBER">%2$d</xliff:g> hazifanyi kazi vizuri</item>
@@ -3710,7 +3715,7 @@
     <string name="high_power_prompt_body" msgid="8067395096053552289">"Ukiruhusu <xliff:g id="APP_NAME">%1$s</xliff:g> kutumika chini chini, unaweza kupunguza muda wa matumizi ya betri. \n\nUnaweza kubadilisha hali hii baadaye katika Mipangilio &gt; Programu na arifa."</string>
     <string name="battery_summary" msgid="4345690800899981339">"Imetumia <xliff:g id="PERCENTAGE">%1$s</xliff:g> tangu mwisho ilipojazwa chaji"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"Udhibiti wa betri"</string>
-    <string name="no_battery_summary" msgid="4105932628367471314">"Hakuna matumizi ya betri tangu ijazwe chaji mara ya mwisho"</string>
+    <string name="no_battery_summary" msgid="4105932628367471314">"Betri haijatumika tangu mwisho ilipojazwa chaji"</string>
     <string name="app_notification_preferences" msgid="5154466638524523201">"Mipangilio ya programu"</string>
     <string name="system_ui_settings" msgid="6751165163665775447">"Onyesha Kipokea Ishara cha SystemUI"</string>
     <string name="additional_permissions" msgid="3142290772324571654">"Ruhusa za ziada"</string>
@@ -3731,7 +3736,7 @@
     <string name="usb_use_tethering" msgid="4250626730173163846">"Kusambaza mtandao kupitia USB"</string>
     <string name="usb_use_MIDI" msgid="4710632870781041401">"MIDI"</string>
     <string name="usb_use_MIDI_desc" msgid="1770966187150010947">"Tumia kifaa hiki kama MIDI"</string>
-    <string name="usb_use" msgid="8940500223316278632">"Tumia USB kwa ajili ya"</string>
+    <string name="usb_use" msgid="8940500223316278632">"Tumia USB"</string>
     <string name="usb_default_label" msgid="7471316635263936101">"Mipangilio chaguomsingi ya USB"</string>
     <string name="usb_default_info" msgid="953775292571786528">"Wakati kifaa kingine kimeunganishwa na simu yako imefunguliwa, mipangilio hii itatumika. Unganisha kwenye vifaa unavyoamini pekee."</string>
     <string name="usb_pref" msgid="6194821550693495068">"USB"</string>
@@ -3826,9 +3831,9 @@
     <string name="camera_double_tap_power_gesture_title" msgid="8874747801078147525">"Bonyeza kitufe cha kuwasha/kuzima mara mbili ili utumie kamera"</string>
     <string name="camera_double_tap_power_gesture_desc" msgid="6166349645433682873">"Fungua kamera kwa haraka bila kufungua skrini yako"</string>
     <string name="screen_zoom_title" msgid="164369086350486104">"Ukubwa wa vipengee"</string>
-    <string name="screen_zoom_short_summary" msgid="5508079362742276703">"Kuongeza au kupunguza ukubwa wa vipengee kwenye skrini"</string>
+    <string name="screen_zoom_short_summary" msgid="5508079362742276703">"Ongeza au upunguze ukubwa wa vipengee kwenye skrini"</string>
     <string name="screen_zoom_keywords" msgid="8358462497896524092">"onyesha uzito, kukuza skrini, kipimo, kupima"</string>
-    <string name="screen_zoom_summary" msgid="5294003755961312560">"Ongeza au upunguze ukubwa wa vipengee kwenye skrini yako. Baadhi ya programu kwenye skrini yako huenda zikabadilisha mahali zilipo."</string>
+    <string name="screen_zoom_summary" msgid="5294003755961312560">"Ongeza au upunguze ukubwa wa vipengee kwenye skrini yako. Huenda baadhi ya programu kwenye skrini yako zikabadilisha mahali zilipo."</string>
     <string name="screen_zoom_preview_title" msgid="2924312934036753091">"Kagua kwanza"</string>
     <string name="screen_zoom_make_smaller_desc" msgid="1374501139722916729">"Punguza"</string>
     <string name="screen_zoom_make_larger_desc" msgid="5306684807895846141">"Kuza"</string>
@@ -3861,7 +3866,7 @@
     <string name="display_dashboard_nowallpaper_summary" msgid="8612534364908229000">"Hali tuli, ukubwa wa fonti"</string>
     <string name="display_summary_example" msgid="4555020581960719296">"Iweke katika hali tuli baada ya dakika 10 za kutokuwa na shughuli"</string>
     <string name="memory_summary" msgid="9121871336058042600">"Takriban <xliff:g id="USED_MEMORY">%1$s</xliff:g> kati ya <xliff:g id="TOTAL_MEMORY">%2$s</xliff:g> za hifadhi zimetumika"</string>
-    <string name="users_summary" msgid="6693338169439092387">"Umeingia katika akaunti ukitumia <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="users_summary" msgid="6693338169439092387">"Umeingia katika akaunti kama <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> ni chaguomsingi"</string>
     <string name="backup_disabled" msgid="6941165814784765643">"Kipengee cha kuhifadhi nakala kimezimwa"</string>
     <string name="android_version_summary" msgid="2192751442789395445">"Imesasishwa na inatumia Android <xliff:g id="VERSION">%1$s</xliff:g>"</string>
@@ -3937,7 +3942,7 @@
     <string name="cell_data_template" msgid="5473177306229738078">"Data ya mtandao wa simu <xliff:g id="AMOUNT">^1</xliff:g>"</string>
     <string name="wifi_data_template" msgid="3146090439147042068">"Data ya Wi-Fi <xliff:g id="AMOUNT">^1</xliff:g>"</string>
     <string name="ethernet_data_template" msgid="6414118030827090119">"Data ya ethaneti <xliff:g id="AMOUNT">^1</xliff:g>"</string>
-    <string name="billing_cycle" msgid="5740717948341713190">"Onyo la upeo na matumizi ya data"</string>
+    <string name="billing_cycle" msgid="5740717948341713190">"Onyo la kikomo na matumizi ya data"</string>
     <string name="app_usage_cycle" msgid="213483325132959663">"Awamu ya matumizi ya data ya programu"</string>
     <string name="cell_data_warning" msgid="8902740337286652689">"Onyo la matumizi ya data: <xliff:g id="ID_1">^1</xliff:g>"</string>
     <string name="cell_data_limit" msgid="3175933829235314233">"Kikomo cha data: <xliff:g id="ID_1">^1</xliff:g>"</string>
@@ -3948,7 +3953,7 @@
       <item quantity="other">Vizuizi <xliff:g id="COUNT">%1$d</xliff:g></item>
       <item quantity="one">Kizuizi 1</item>
     </plurals>
-    <string name="operator_warning" msgid="4676042739221117031">"Huenda hesabu ya data ya mtoa huduma ikawa tofauti na ya kifaa chako."</string>
+    <string name="operator_warning" msgid="4676042739221117031">"Huenda hesabu ya data ya mtoa huduma ikawa tofauti na ya kifaa chako"</string>
     <string name="data_used_template" msgid="761605393453849477">"<xliff:g id="ID_1">%1$s</xliff:g> zimetumika"</string>
     <string name="set_data_warning" msgid="8115980184415563941">"Weka onyo la matumizi ya data"</string>
     <string name="data_warning" msgid="2699207195535036240">"Onyo kuhusu data"</string>
@@ -3983,7 +3988,7 @@
     <string name="data_saver_title" msgid="7903308134514179256">"Kiokoa Data"</string>
     <string name="unrestricted_data_saver" msgid="9139401849550738720">"Data bila kipimo"</string>
     <string name="restrict_background_blacklisted" msgid="7158991683849067124">"Data ya chini chini imezimwa"</string>
-    <string name="data_saver_on" msgid="7281809065420480881">"Kimewashwa"</string>
+    <string name="data_saver_on" msgid="7281809065420480881">"Imewashwa"</string>
     <string name="data_saver_off" msgid="7439439787358504018">"Kimezimwa"</string>
     <string name="data_saver_switch_title" msgid="8244008132112735207">"Tumia Kiokoa Data"</string>
     <string name="unrestricted_app_title" msgid="4390661122069905122">"Matumizi ya data bila vikwazo"</string>
@@ -4004,8 +4009,8 @@
     <string name="not_battery_optimizing" msgid="2616044774307734160">"Haitumii kipengele cha kuboresha matumizi ya betri"</string>
     <string name="lockscreen_remote_input" msgid="3363310613165354434">"Ikiwa kifaa kimefungwa, usiruhusu uchapaji wa majibu au maandishi mengine kwenye arifa"</string>
     <string name="default_spell_checker" msgid="8636661093243189533">"Kikagua tahajia chaguomsingi"</string>
-    <string name="choose_spell_checker" msgid="7619860861923582868">"Chagua kikagua maendelezo"</string>
-    <string name="spell_checker_master_switch_title" msgid="5712693172227400668">"Tumia kikagua maendelezo"</string>
+    <string name="choose_spell_checker" msgid="7619860861923582868">"Chagua kikagua tahajia"</string>
+    <string name="spell_checker_master_switch_title" msgid="5712693172227400668">"Tumia kikagua tahajia"</string>
     <string name="spell_checker_not_selected" msgid="331034541988255137">"Hakijachaguliwa"</string>
     <string name="notification_log_no_title" msgid="3668232437235348628">"(hamna)"</string>
     <string name="notification_log_details_delimiter" msgid="5485526744689532908">": "</string>
@@ -4435,7 +4440,7 @@
     <string name="cdma_subscription_summary" msgid="2298861419202726628">"Badilisha kati ya RUIM/SIM na NV"</string>
     <string name="cdma_subscription_dialogtitle" msgid="232485231569225126">"usajili"</string>
     <string name="register_automatically" msgid="1858081641661493109">"Usajili wa kiotomatiki…"</string>
-    <string name="roaming_alert_title" msgid="1849237823113454475">"Ungependa kuruhusu matumizi ya mitandao ya ng\'ambo?"</string>
+    <string name="roaming_alert_title" msgid="1849237823113454475">"Data itumike kwenye mitandao ya ng\'ambo?"</string>
     <string name="roaming_check_price_warning" msgid="5883499714594419439">"Wasiliana na mtoa huduma za mtandao kwa maelezo kuhusu bei."</string>
     <string name="mobile_data_usage_title" msgid="2376358672434990037">"Matumizi ya data ya programu"</string>
     <string name="mobile_network_mode_error" msgid="6818434186286086554">"Hali ya Mtandao Isiyo sahihi <xliff:g id="NETWORKMODEID">%1$d</xliff:g>. Puuza"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ta/arrays.xml b/tests/CarDeveloperOptions/res/values-ta/arrays.xml
index 291f762..94d834c 100644
--- a/tests/CarDeveloperOptions/res/values-ta/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-ta/arrays.xml
@@ -38,7 +38,16 @@
     <item msgid="5827960506924849753">"10 நிமிடங்கள்"</item>
     <item msgid="6677424950124253938">"30 நிமிடங்கள்"</item>
   </string-array>
-    <!-- no translation found for dream_timeout_entries:7 (8271452751594598661) -->
+  <string-array name="dream_timeout_entries">
+    <item msgid="6487043225269853023">"ஒருபோதும் வேண்டாம்"</item>
+    <item msgid="2517785806387977252">"15 வினாடிகள்"</item>
+    <item msgid="6347954399441173672">"30 விநாடிகள்"</item>
+    <item msgid="4858305253279921789">"1 நிமிடம்"</item>
+    <item msgid="8109273437140044073">"2 நிமிடங்கள்"</item>
+    <item msgid="2788593551142462622">"5 நிமிடங்கள்"</item>
+    <item msgid="8012672183888404961">"10 நிமிடங்கள்"</item>
+    <item msgid="8271452751594598661">"30 நிமிடங்கள்"</item>
+  </string-array>
   <string-array name="lock_after_timeout_entries">
     <item msgid="2232921187970351881">"உடனடியாக"</item>
     <item msgid="2038544972632026612">"5 வினாடிகள்"</item>
@@ -50,17 +59,47 @@
     <item msgid="811192536981678974">"10 நிமிடங்கள்"</item>
     <item msgid="7258394417241706272">"30 நிமிடங்கள்"</item>
   </string-array>
-    <!-- no translation found for entries_font_size:0 (2340391964816059553) -->
-    <!-- no translation found for entries_font_size:0 (6490061470416867723) -->
-    <!-- no translation found for entries_font_size:2 (1714184661981538355) -->
-    <!-- no translation found for entries_font_size:2 (1678068858001018666) -->
-    <!-- no translation found for wifi_status:3 (5848277343965362748) -->
-    <!-- no translation found for wifi_status_with_ssid:1 (6816207058895999545) -->
-    <!-- no translation found for wifi_status_with_ssid:3 (7547609081339573756) -->
-    <!-- no translation found for wifi_status_with_ssid:4 (5145158315060185414) -->
+  <string-array name="entries_font_size">
+    <item msgid="2340391964816059553">"சிறிது"</item>
+    <item msgid="591935967183159581">"இயல்பு"</item>
+    <item msgid="1714184661981538355">"பெரியது"</item>
+    <item msgid="6195563047686707484">"மிகப் பெரியது"</item>
+  </string-array>
+  <string-array name="wifi_status">
+    <item msgid="1304883790721412351"></item>
+    <item msgid="4157625910392775808">"தேடுகிறது..."</item>
+    <item msgid="5597394826455877834">"இணைக்கிறது..."</item>
+    <item msgid="5848277343965362748">"அங்கீகரிக்கிறது…"</item>
+    <item msgid="3391238031431440676">"IP முகவரியைப் பெறுகிறது…"</item>
+    <item msgid="5257597310494000224">"இணைக்கப்பட்டது"</item>
+    <item msgid="8472497592913050396">"இடைநீக்கப்பட்டது"</item>
+    <item msgid="1228072488815999109">"துண்டிக்கிறது..."</item>
+    <item msgid="7253087004422991731">"தொடர்பு துண்டிக்கப்பட்டது"</item>
+    <item msgid="4169850917304751227">"தோல்வி"</item>
+    <item msgid="6266658166690831131">"தடுக்கப்பட்டது"</item>
+    <item msgid="4517230805854909775">"வேகம் குறைந்த இணைப்பைத் தற்காலிகமாகத் தவிர்க்கிறது"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="4853670665485437464"></item>
+    <item msgid="6816207058895999545">"தேடுகிறது…"</item>
+    <item msgid="8058143476674427024">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> இல் இணைக்கிறது…"</item>
+    <item msgid="7547609081339573756">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> மூலம் அங்கீகரிக்கிறது…"</item>
+    <item msgid="5145158315060185414">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> இலிருந்து IP முகவரியைப் பெறுகிறது…"</item>
+    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> உடன் இணைக்கப்பட்டது"</item>
+    <item msgid="6600156231416890902">"இடைநீக்கப்பட்டது"</item>
+    <item msgid="4133290864821295785">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> இலிருந்து தொடர்பு துண்டிக்கப்படுகிறது…"</item>
+    <item msgid="3980154971187953257">"தொடர்பு துண்டிக்கப்பட்டது"</item>
+    <item msgid="2847316776634969068">"தோல்வி"</item>
+    <item msgid="4390990424746035383">"தடுக்கப்பட்டது"</item>
+    <item msgid="3618248791367063949">"வேகம் குறைந்த இணைப்பைத் தற்காலிகமாகத் தவிர்க்கிறது"</item>
+  </string-array>
     <!-- no translation found for wifi_tether_security:0 (5586343370515598801) -->
     <!-- no translation found for wifi_tether_security:1 (6136336549994615745) -->
-    <!-- no translation found for wifi_p2p_wps_setup:0 (5390235347963255303) -->
+  <string-array name="wifi_p2p_wps_setup">
+    <item msgid="5390235347963255303">"புஷ் பட்டன்"</item>
+    <item msgid="7401896200768713930">"பியர் சாதனத்திலிருந்து பின்"</item>
+    <item msgid="4526848028011846710">"இந்தச் சாதனத்தில் உள்ள பின்"</item>
+  </string-array>
   <string-array name="wifi_p2p_status">
     <item msgid="8741947238021758201">"இணைக்கப்பட்டது"</item>
     <item msgid="983792611851499732">"அழைக்கப்பட்டது"</item>
@@ -82,8 +121,13 @@
     <item msgid="1644506614010085798">"4"</item>
     <item msgid="3132506679404897150">"5"</item>
   </string-array>
-    <!-- no translation found for wifi_signal:1 (7882129634982603782) -->
-    <!-- no translation found for wifi_signal:4 (999948812884919584) -->
+  <string-array name="wifi_signal">
+    <item msgid="1709949377823900951">"மோசம்"</item>
+    <item msgid="7882129634982603782">"மோசம்"</item>
+    <item msgid="6457357501905996224">"சுமார்"</item>
+    <item msgid="405271628162918841">"நன்று"</item>
+    <item msgid="999948812884919584">"பிரமாதம்"</item>
+  </string-array>
   <string-array name="data_usage_data_range">
     <item msgid="8986775481492954015">"கடந்த 30 நாட்கள்"</item>
     <item msgid="3211287705232736964">"பயன்பாட்டு சுழற்சியை அமை..."</item>
@@ -119,7 +163,10 @@
     <item msgid="7330627471456865502">"MSCHAPV2"</item>
     <item msgid="6255179395132581882">"GTC"</item>
   </string-array>
-    <!-- no translation found for wifi_ip_settings:1 (4377002609760712163) -->
+  <string-array name="wifi_ip_settings">
+    <item msgid="2717196390555072244">"DHCP"</item>
+    <item msgid="4377002609760712163">"நிலையானது"</item>
+  </string-array>
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"ஏதுமில்லை"</item>
     <item msgid="1464741437353223198">"கைமுறை"</item>
@@ -239,11 +286,73 @@
     <item msgid="1165623660533024666">"பின்புலத்தில் இயங்கு"</item>
     <item msgid="6423861043647911030">"அணுகல்தன்மைக்கான ஒலியளவு"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:3 (7836406246005211990) -->
-    <!-- no translation found for app_ops_labels:4 (3951439024549922598) -->
-    <!-- no translation found for app_ops_labels:8 (3597797992398484655) -->
-    <!-- no translation found for app_ops_labels:20 (3037159047591081136) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"இருப்பிடம்"</item>
+    <item msgid="6656077694190491067">"இருப்பிடம்"</item>
+    <item msgid="8790228218278477369">"இருப்பிடம்"</item>
+    <item msgid="7836406246005211990">"அதிர்வு"</item>
+    <item msgid="3951439024549922598">"தொடர்புகளைப் படி"</item>
+    <item msgid="8802152411647068">"தொடர்புகளை மாற்று"</item>
+    <item msgid="229544934599698735">"அழைப்புப் பதிவைப் படி"</item>
+    <item msgid="7396102294405899613">"அழைப்புப் பதிவை மாற்று"</item>
+    <item msgid="3597797992398484655">"கேலெண்டரைப் படி"</item>
+    <item msgid="2705975774250907343">"கேலெண்டரை மாற்று"</item>
+    <item msgid="4668747371441932697">"இருப்பிடம்"</item>
+    <item msgid="1487578921720243646">"அறிவிப்பை இடுகையிடு"</item>
+    <item msgid="4636080349724146638">"இருப்பிடம்"</item>
+    <item msgid="673510900286463926">"தொலைபேசியில் அழை"</item>
+    <item msgid="542083422784609790">"SMS/MMS ஐப் படி"</item>
+    <item msgid="1033780373029588436">"SMS/MMS எழுது"</item>
+    <item msgid="5647111115517787488">"SMS/MMS பெறு"</item>
+    <item msgid="8591105601108455893">"SMS/MMS பெறு"</item>
+    <item msgid="7730995008517841903">"SMS/MMS பெறு"</item>
+    <item msgid="2613033109026626086">"SMS/MMS பெறு"</item>
+    <item msgid="3037159047591081136">"SMS/MMS அனுப்பு"</item>
+    <item msgid="4726682243833913568">"SMS/MMS ஐப் படி"</item>
+    <item msgid="6555678522277865572">"SMS/MMS எழுது"</item>
+    <item msgid="6981734935578130884">"அமைப்புகளை மாற்று"</item>
+    <item msgid="8705854389991425629">"மேலே வரை"</item>
+    <item msgid="5861356020344153651">"அறிவிப்புகளை அணுகு"</item>
+    <item msgid="78432174621628659">"கேமரா"</item>
+    <item msgid="3986116419882154794">"ஆடியோவைப் பதிவுசெய்"</item>
+    <item msgid="4516840825756409490">"ஆடியோவை இயக்கு"</item>
+    <item msgid="6811712502798183957">"கிளிப்போர்டைப் படி"</item>
+    <item msgid="2780369012602289114">"கிளிப்போர்ட்டை மாற்று"</item>
+    <item msgid="2331359440170850868">"மீடியா பொத்தான்கள்"</item>
+    <item msgid="6133599737122751231">"ஆடியோவை மையப்படுத்து"</item>
+    <item msgid="6844485713404805301">"முதன்மை ஒலியளவு"</item>
+    <item msgid="1600379420669104929">"குரல் ஒலியளவு"</item>
+    <item msgid="6296768210470214866">"அழைப்பு - ஒலியளவு"</item>
+    <item msgid="510690696071629241">"மீடியா ஒலியளவு"</item>
+    <item msgid="406861638631430109">"அலார ஒலியளவு"</item>
+    <item msgid="4715864795872233884">"அறிவிப்பின் ஒலியளவு"</item>
+    <item msgid="2311478519251301183">"புளூடூத் ஒலியளவு"</item>
+    <item msgid="5133991377896747027">"எப்போதும் விழிப்பில்"</item>
+    <item msgid="2464189519136248621">"இருப்பிடம்"</item>
+    <item msgid="2062677934050803037">"இருப்பிடம்"</item>
+    <item msgid="1735171933192715957">"பயன்பாட்டு புள்ளிவிவரத்தைப் பெறுக"</item>
+    <item msgid="1014093788778383554">"மைக்ரோஃபோனை முடக்கு/இயக்கு"</item>
+    <item msgid="4199297950608622850">"டோஸ்ட்டைக் காட்டு"</item>
+    <item msgid="2527962435313398821">"மீடியாவை புராஜக்ட் செய்"</item>
+    <item msgid="5117506254221861929">"VPNஐ இயக்கு"</item>
+    <item msgid="8291198322681891160">"வால்பேப்பரை எழுது"</item>
+    <item msgid="7106921284621230961">"கட்டமைப்புக்கு உதவு"</item>
+    <item msgid="4496533640894624799">"ஸ்கிரீன்ஷாட்டுக்கு உதவு"</item>
+    <item msgid="2598847264853993611">"ஃபோன் நிலையைப் படி"</item>
+    <item msgid="9215610846802973353">"குரலஞ்சலைச் சேர்"</item>
+    <item msgid="9186411956086478261">"sipஐப் பயன்படுத்து"</item>
+    <item msgid="6884763100104539558">"வெளிச்செல்லும் அழைப்பைச் செயலாக்கு"</item>
+    <item msgid="125513972170580692">"கைரேகை"</item>
+    <item msgid="2556071024281275619">"உடல் சென்சார்கள்"</item>
+    <item msgid="617168514928339387">"செல் பிராட்காஸ்ட்களைப் படி"</item>
+    <item msgid="7134693570516523585">"போலியான இருப்பிடம்"</item>
+    <item msgid="7224489175375229399">"சேமிப்பகத்தைப் படி"</item>
+    <item msgid="8472735063903258202">"சேமிப்பகத்தை எழுது"</item>
+    <item msgid="4069276819909595110">"திரையை இயக்கு"</item>
+    <item msgid="1228338896751121025">"கணக்குகளைப் பெறு"</item>
+    <item msgid="3181581793459233672">"பின்புலத்தில் இயங்கு"</item>
+    <item msgid="2340936043025374076">"அணுகல்தன்மைக்கான ஒலியளவு"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"குறுகியது"</item>
     <item msgid="4816511817309094890">"நடுத்தர முக்கியத்துவம்"</item>
@@ -260,7 +369,13 @@
     <item msgid="4627069151979553527">"இணைவெழுத்து முறை"</item>
     <item msgid="6896773537705206194">"சிறிய எழுத்துகள்"</item>
   </string-array>
-    <!-- no translation found for captioning_font_size_selector_titles:3 (2784236342175159295) -->
+  <string-array name="captioning_font_size_selector_titles">
+    <item msgid="1680223634161592855">"மிகச் சிறியது"</item>
+    <item msgid="5091603983404027034">"சிறியது"</item>
+    <item msgid="176844712416932112">"சராசரி"</item>
+    <item msgid="2784236342175159295">"பெரியது"</item>
+    <item msgid="218913203203160606">"மிகப் பெரியது"</item>
+  </string-array>
   <string-array name="captioning_edge_type_selector_titles">
     <item msgid="3865198759294188069">"இயல்பு"</item>
     <item msgid="6488643537808152001">"ஏதுமில்லை"</item>
@@ -275,7 +390,14 @@
     <item msgid="1874668269931014581">"75%"</item>
     <item msgid="6462911487571123954">"100%"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"ஆப்ஸ் இயல்புகளை பயன்படுத்து"</item>
+    <item msgid="8611890312638868524">"கருப்பில் வெண்மை"</item>
+    <item msgid="5891360837786277638">"வெண்மையில் கருப்பு"</item>
+    <item msgid="2798457065945456853">"கருப்பில் மஞ்சள்"</item>
+    <item msgid="5799049811524553967">"நீலத்தில் மஞ்சள்"</item>
+    <item msgid="3673930830658169860">"பிரத்தியேகமானது"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"PPTP VPN"</item>
     <item msgid="1349760781118368659">"பாதுகாப்பு விசைகளுடன் கூடிய L2TP/IPSec VPN"</item>
@@ -288,15 +410,32 @@
     <item msgid="2958623927055120839">"ஏதுமில்லை"</item>
     <item msgid="1157046369795346308">"கைமுறை"</item>
   </string-array>
-    <!-- no translation found for vpn_states:4 (9135049670787351881) -->
+  <string-array name="vpn_states">
+    <item msgid="5408915841694583740">"தொடர்பு துண்டிக்கப்பட்டது"</item>
+    <item msgid="8754480102834556765">"தொடங்குகிறது..."</item>
+    <item msgid="3351334355574270250">"இணைக்கிறது..."</item>
+    <item msgid="8303882153995748352">"இணைக்கப்பட்டது"</item>
+    <item msgid="9135049670787351881">"நேரம் முடிந்தது"</item>
+    <item msgid="2124868417182583926">"தோல்வி"</item>
+  </string-array>
   <string-array name="security_settings_premium_sms_values">
     <item msgid="1164265643455394443">"கேள்"</item>
     <item msgid="7718817231348607934">"ஒருபோதும் அனுமதிக்காதே"</item>
     <item msgid="8184570120217958741">"எப்போதும் அனுமதி"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"இயல்பானது"</item>
+    <item msgid="5101233285497327432">"நடுத்தரம்"</item>
+    <item msgid="1555861583162930714">"குறைவு"</item>
+    <item msgid="1719683776264798117">"நெருக்கடி"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"இயல்பு"</item>
+    <item msgid="6107138933849816768">"நடுத்தரம்"</item>
+    <item msgid="182695359839047859">"குறைவு"</item>
+    <item msgid="8577246509202964244">"மிகவும் குறைவு"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"தொடர்நிலை"</item>
     <item msgid="167418068739176448">"அதிக செயல்பாடு"</item>
diff --git a/tests/CarDeveloperOptions/res/values-ta/config.xml b/tests/CarDeveloperOptions/res/values-ta/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-ta/config.xml
+++ b/tests/CarDeveloperOptions/res/values-ta/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-ta/strings.xml b/tests/CarDeveloperOptions/res/values-ta/strings.xml
index 4393875..ce10d08 100644
--- a/tests/CarDeveloperOptions/res/values-ta/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ta/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"திரையில் காட்டப்படும் உரையைச் சிறிதாக்கும் அல்லது பெரிதாக்கும்."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"சிறிதாக்கு"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"பெரிதாக்கு"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"மாதிரி உரை"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"தி விசார்ட் ஆஃப் ஓஸ்"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"அத்தியாயம் 11: ஓஸின் அற்புதமான மரகத நகரம்"</string>
@@ -440,9 +439,9 @@
     <string name="security_settings_fingerprint_preference_summary_none" msgid="3613424536269750172"></string>
     <string name="security_settings_fingerprint_enroll_introduction_title" msgid="889558002683900544">"கைரேகை மூலம் திறக்கலாம்"</string>
     <string name="security_settings_fingerprint_enroll_introduction_title_unlock_disabled" msgid="7915504118657864429">"கைரேகையைப் பயன்படுத்தவும்"</string>
-    <string name="security_settings_fingerprint_enroll_introduction_message" msgid="5586198131986682472">"மொபைலைத் திறக்க, வாங்குவதை அங்கீகரிக்க அல்லது பயன்பாடுகளில் உள்நுழைய, கைரேகை சென்சாரைத் தொட்டால் போதும். கைரேகையைப் பயன்படுத்தி மேலே குறிப்பிட்டுள்ளவற்றைச் செய்ய முடியும் என்பதால், அனைவரின் கைரேகைகளையும் இதில் சேர்க்க வேண்டாம்.\n\nகுறிப்பு: எளிதில் ஊகிக்க முடியாத வடிவம் அல்லது பின்னைப் பயன்படுத்தும் போது கிடைக்கும் பாதுகாப்பை விட, கைரேகையைப் பயன்படுத்தும் போது குறைவான பாதுகாப்பே கிடைக்கும்."</string>
+    <string name="security_settings_fingerprint_enroll_introduction_message" msgid="5586198131986682472">"மொபைலைத் திறக்க, வாங்குவதை அங்கீகரிக்க அல்லது பயன்பாடுகளில் உள்நுழைய, கைரேகை சென்சாரைத் தொட்டால் போதும். கைரேகையைப் பயன்படுத்தி மேலே குறிப்பிட்டுள்ளவற்றைச் செய்ய முடியும் என்பதால், அனைவரின் கைரேகைகளையும் இதில் சேர்க்க வேண்டாம்.\n\nகுறிப்பு: எளிதில் ஊகிக்க முடியாத பேட்டர்ன் அல்லது பின்னைப் பயன்படுத்தும் போது கிடைக்கும் பாதுகாப்பை விட, கைரேகையைப் பயன்படுத்தும் போது குறைவான பாதுகாப்பே கிடைக்கும்."</string>
     <string name="security_settings_fingerprint_enroll_introduction_message_unlock_disabled" msgid="1640839304679275468">"மொபைலைத் திறக்க அல்லது வாங்குவதை அங்கீகரிக்க, உங்கள் கைரேகையைப் பயன்படுத்தவும்.\n\n குறிப்பு: இந்தச் சாதனத்தைத் திறக்க, கைரேகையைப் பயன்படுத்த முடியாது. மேலும் தகவலுக்கு, உங்கள் நிறுவனத்தின் நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
-    <string name="security_settings_fingerprint_enroll_introduction_message_setup" msgid="6734490666593320711">"மொபைலைத் திறக்க அல்லது வாங்குவதை அங்கீகரிக்க, உங்கள் கைரேகையைப் பயன்படுத்தவும்.\nகுறிப்பு: எளிதில் ஊகிக்க முடியாத வடிவம் அல்லது பின்னைப் பயன்படுத்தும் போது கிடைக்கும் பாதுகாப்பை விட, கைரேகையைப் பயன்படுத்தும் போது குறைவான பாதுகாப்பே கிடைக்கும்.\n"</string>
+    <string name="security_settings_fingerprint_enroll_introduction_message_setup" msgid="6734490666593320711">"மொபைலைத் திறக்க அல்லது வாங்குவதை அங்கீகரிக்க, உங்கள் கைரேகையைப் பயன்படுத்தவும்.\nகுறிப்பு: எளிதில் ஊகிக்க முடியாத பேட்டர்ன் அல்லது பின்னைப் பயன்படுத்தும் போது கிடைக்கும் பாதுகாப்பை விட, கைரேகையைப் பயன்படுத்தும் போது குறைவான பாதுகாப்பே கிடைக்கும்.\n"</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel" msgid="9168637333731599827">"ரத்துசெய்"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue" msgid="271662150372486535">"தொடரவும்"</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel_setup" msgid="756928427429893070">"தவிர்"</string>
@@ -509,8 +508,8 @@
     <string name="crypt_keeper_encrypt_title" product="tablet" msgid="2292129135369853167">"டேப்லெட்டை என்க்ரிப்ட் செய்"</string>
     <string name="crypt_keeper_encrypt_title" product="default" msgid="3110852053238357832">"மொபைலை என்க்ரிப்ட் செய்"</string>
     <string name="crypt_keeper_encrypted_summary" msgid="2438498691741626642">"என்க்ரிப்ட் செய்யப்பட்டது"</string>
-    <string name="crypt_keeper_desc" product="tablet" msgid="9142792050252407734">"உங்கள் கணக்குகள், அமைப்புகள், பதிவிறக்கிய ஆப்ஸ் மற்றும் அவற்றின் தரவு, மீடியா மற்றும் பிற கோப்புகள் என அனைத்தையும் என்க்ரிப்ட் செய்யலாம். உங்கள் டேப்லெட்டை என்க்ரிப்ட் செய்த பிறகு, திரைப்பூட்டை (அதாவது வடிவம் அல்லது பின் அல்லது கடவுச்சொல்) அமைத்திருந்தால், ஒவ்வொரு முறையும் டேப்லெட்டை இயக்கும்போது குறிநீக்குவதற்கு திரையைத் திறக்க வேண்டும். உங்களின் எல்லா தரவையும் அழித்து, ஆரம்ப நிலைக்கு மீட்டமைப்பதே குறிநீக்குவதற்கான மற்றொரு வழியாகும்.\n\nஎன்க்ரிப்ட் செய்வதற்கு ஒரு மணிநேரம் அல்லது அதற்கு மேல் ஆகலாம். சார்ஜ் செய்த பேட்டரியுடன் தொடங்கி, செயல் முடியும் வரை சார்ஜ் ஆகும் நிலையிலேயே வைக்கவும். செயலில் குறுக்கிட்டால், உங்கள் தரவில் சிலவற்றை அல்லது மொத்தத்தையும் இழப்பீர்கள்."</string>
-    <string name="crypt_keeper_desc" product="default" msgid="1996334685607444282">"உங்கள் கணக்குகள், அமைப்புகள், பதிவிறக்கிய ஆப்ஸ் மற்றும் அவற்றின் தரவு, மீடியா மற்றும் பிற கோப்புகள் என அனைத்தையும் என்க்ரிப்ட் செய்யலாம். உங்கள் மொபைலை என்க்ரிப்ட் செய்த பிறகு, திரைப்பூட்டை (அதாவது வடிவம் அல்லது பின் அல்லது கடவுச்சொல்) அமைத்திருந்தால், ஒவ்வொரு முறையும் மொபைலை இயக்கும்போது குறிநீக்குவதற்கு திரையைத் திறக்க வேண்டும். உங்களின் எல்லா தரவையும் அழித்து, ஆரம்ப நிலைக்கு மீட்டமைப்பதே குறிநீக்குவதற்கான மற்றொரு வழியாகும்.\n\nஎன்க்ரிப்ட் செய்வதற்கு ஒரு மணிநேரம் அல்லது அதற்கு மேல் ஆகலாம். சார்ஜ் செய்த பேட்டரியுடன் தொடங்கி, செயல் முடியும் வரை சார்ஜ் ஆகும் நிலையிலேயே வைக்கவும். செயலில் குறுக்கிட்டால், உங்கள் தரவில் சிலவற்றை அல்லது மொத்தத்தையும் இழப்பீர்கள்."</string>
+    <string name="crypt_keeper_desc" product="tablet" msgid="9142792050252407734">"உங்கள் கணக்குகள், அமைப்புகள், பதிவிறக்கிய ஆப்ஸ் மற்றும் அவற்றின் தரவு, மீடியா மற்றும் பிற கோப்புகள் என அனைத்தையும் என்க்ரிப்ட் செய்யலாம். உங்கள் டேப்லெட்டை என்க்ரிப்ட் செய்த பிறகு, திரைப்பூட்டை (அதாவது பேட்டர்ன் அல்லது பின் அல்லது கடவுச்சொல்) அமைத்திருந்தால், ஒவ்வொரு முறையும் டேப்லெட்டை இயக்கும்போது குறிநீக்குவதற்கு திரையைத் திறக்க வேண்டும். உங்களின் எல்லா தரவையும் அழித்து, ஆரம்ப நிலைக்கு மீட்டமைப்பதே குறிநீக்குவதற்கான மற்றொரு வழியாகும்.\n\nஎன்க்ரிப்ட் செய்வதற்கு ஒரு மணிநேரம் அல்லது அதற்கு மேல் ஆகலாம். சார்ஜ் செய்த பேட்டரியுடன் தொடங்கி, செயல் முடியும் வரை சார்ஜ் ஆகும் நிலையிலேயே வைக்கவும். செயலில் குறுக்கிட்டால், உங்கள் தரவில் சிலவற்றை அல்லது மொத்தத்தையும் இழப்பீர்கள்."</string>
+    <string name="crypt_keeper_desc" product="default" msgid="1996334685607444282">"உங்கள் கணக்குகள், அமைப்புகள், பதிவிறக்கிய ஆப்ஸ் மற்றும் அவற்றின் தரவு, மீடியா மற்றும் பிற கோப்புகள் என அனைத்தையும் என்க்ரிப்ட் செய்யலாம். உங்கள் மொபைலை என்க்ரிப்ட் செய்த பிறகு, திரைப்பூட்டை (அதாவது பேட்டர்ன் அல்லது பின் அல்லது கடவுச்சொல்) அமைத்திருந்தால், ஒவ்வொரு முறையும் மொபைலை இயக்கும்போது குறிநீக்குவதற்கு திரையைத் திறக்க வேண்டும். உங்களின் எல்லா தரவையும் அழித்து, ஆரம்ப நிலைக்கு மீட்டமைப்பதே குறிநீக்குவதற்கான மற்றொரு வழியாகும்.\n\nஎன்க்ரிப்ட் செய்வதற்கு ஒரு மணிநேரம் அல்லது அதற்கு மேல் ஆகலாம். சார்ஜ் செய்த பேட்டரியுடன் தொடங்கி, செயல் முடியும் வரை சார்ஜ் ஆகும் நிலையிலேயே வைக்கவும். செயலில் குறுக்கிட்டால், உங்கள் தரவில் சிலவற்றை அல்லது மொத்தத்தையும் இழப்பீர்கள்."</string>
     <string name="crypt_keeper_button_text" product="tablet" msgid="7918671468758813824">"டேப்லெட்டை என்க்ரிப்ட் செய்"</string>
     <string name="crypt_keeper_button_text" product="default" msgid="8737394386627318489">"மொபைலை என்க்ரிப்ட் செய்"</string>
     <string name="crypt_keeper_low_charge_text" msgid="1422879728632636311">"உங்கள் பேட்டரியை சார்ஜ் செய்து மீண்டும் முயற்சிக்கவும்."</string>
@@ -562,13 +561,13 @@
     <string name="unlock_set_unlock_launch_picker_summary_lock_after_timeout" msgid="3861167251234952373">"<xliff:g id="UNLOCK_METHOD">%1$s</xliff:g> / உறக்கத்திற்குப் பின் <xliff:g id="TIMEOUT_STRING">%2$s</xliff:g>"</string>
     <string name="unlock_set_unlock_launch_picker_title_profile" msgid="7976345264630422921">"பணிச் சுயவிவரப் பூட்டு"</string>
     <string name="unlock_set_unlock_launch_picker_change_title" msgid="32310692507029407">"லாக் ஸ்கிரீனை மாற்றவும்"</string>
-    <string name="unlock_set_unlock_launch_picker_change_summary" msgid="2072792784866320522">"வடிவம், பின் அல்லது கடவுச்சொல் பாதுகாப்பை மாற்றவும் அல்லது முடக்கவும்."</string>
+    <string name="unlock_set_unlock_launch_picker_change_summary" msgid="2072792784866320522">"பேட்டர்ன், பின் அல்லது கடவுச்சொல் பாதுகாப்பை மாற்றவும் அல்லது முடக்கவும்."</string>
     <string name="unlock_set_unlock_launch_picker_enable_summary" msgid="9070847611379078795">"திரையைப் பூட்டுவதற்கான முறையைத் தேர்வுசெய்யவும்"</string>
     <string name="unlock_set_unlock_off_title" msgid="5049876793411416079">"ஏதுமில்லை"</string>
     <string name="unlock_set_unlock_off_summary" msgid="3997346045783359119"></string>
     <string name="unlock_set_unlock_none_title" msgid="1922027966983146392">"ஸ்வைப்"</string>
     <string name="unlock_set_unlock_none_summary" msgid="4044529413627659031">"பாதுகாப்பு இல்லை"</string>
-    <string name="unlock_set_unlock_pattern_title" msgid="7533759994999423587">"வடிவம்"</string>
+    <string name="unlock_set_unlock_pattern_title" msgid="7533759994999423587">"பேட்டர்ன்"</string>
     <string name="unlock_set_unlock_pattern_summary" msgid="8858697834522201333">"மிதமான பாதுகாப்பு"</string>
     <string name="unlock_set_unlock_pin_title" msgid="361479901761948207">"பின்"</string>
     <string name="unlock_set_unlock_pin_summary" msgid="8076921768675948228">"மிதமானது முதல் அதிக பாதுகாப்பு"</string>
@@ -576,7 +575,7 @@
     <string name="unlock_set_unlock_password_summary" msgid="7042787631866059147">"அதிகப் பாதுகாப்பு"</string>
     <string name="unlock_set_do_later_title" msgid="2939110070503695956">"இப்போது வேண்டாம்"</string>
     <string name="current_screen_lock" msgid="398328543694154510">"தற்போதைய திரைப் பூட்டு"</string>
-    <string name="fingerprint_unlock_set_unlock_pattern" msgid="132337696546315927">"கைரேகை + வடிவம்"</string>
+    <string name="fingerprint_unlock_set_unlock_pattern" msgid="132337696546315927">"கைரேகை + பேட்டர்ன்"</string>
     <string name="fingerprint_unlock_set_unlock_pin" msgid="886426673328906002">"கைரேகை + பின்"</string>
     <string name="fingerprint_unlock_set_unlock_password" msgid="3325527833422156515">"கைரேகை + கடவுச்சொல்"</string>
     <string name="fingerprint_unlock_skip_fingerprint" msgid="2063700014903801639">"கைரேகையின்றி தொடர்க"</string>
@@ -589,14 +588,14 @@
     <string name="unlock_set_unlock_disabled_summary" msgid="1713159782896140817">"நிர்வாகி, என்கிரிப்ஷன் பாலிசி/நற்சான்று சேமிப்பகம் காரணமாக முடக்கப்பட்டது"</string>
     <string name="unlock_set_unlock_mode_off" msgid="2950701212659081973">"ஏதுமில்லை"</string>
     <string name="unlock_set_unlock_mode_none" msgid="3441605629077912292">"ஸ்வைப்"</string>
-    <string name="unlock_set_unlock_mode_pattern" msgid="8564909572968419459">"வடிவம்"</string>
+    <string name="unlock_set_unlock_mode_pattern" msgid="8564909572968419459">"பேட்டர்ன்"</string>
     <string name="unlock_set_unlock_mode_pin" msgid="7828354651668392875">"பின்"</string>
     <string name="unlock_set_unlock_mode_password" msgid="397703731925549447">"கடவுச்சொல்"</string>
     <string name="unlock_setup_wizard_fingerprint_details" msgid="6515136915205473675">"திரைப் பூட்டு அமைத்ததும், அமைப்புகள் &gt; பாதுகாப்பு என்பதற்குச் சென்று கைரேகையை அமைக்கலாம்."</string>
     <string name="unlock_disable_lock_title" msgid="3508492427073600294">"திரைப் பூட்டை முடக்கு"</string>
     <string name="unlock_disable_frp_warning_title" msgid="5858589970505254193">"சாதனப் பாதுகாப்பை அகற்றவா?"</string>
     <string name="unlock_disable_frp_warning_title_profile" msgid="3814123014295965266">"சுயவிவரப் பாதுகாப்பை அகற்றவா?"</string>
-    <string name="unlock_disable_frp_warning_content_pattern" msgid="1843950215687159135">"வடிவம் இல்லாமல் சாதனப் பாதுகாப்பு அம்சங்கள் செயல்படாது."</string>
+    <string name="unlock_disable_frp_warning_content_pattern" msgid="1843950215687159135">"பேட்டர்ன் இல்லாமல் சாதனப் பாதுகாப்பு அம்சங்கள் செயல்படாது."</string>
     <string name="unlock_disable_frp_warning_content_pattern_fingerprint" msgid="8846957650251741548">"பேட்டர்ன் இல்லாமல் சாதனப் பாதுகாப்பு அம்சங்கள் செயல்படாது.<xliff:g id="EMPTY_LINE">
 
 </xliff:g>சேமிக்கப்பட்டிருக்கும் கைரேகைகளும் இந்தச் சாதனத்திலிருந்து அகற்றப்படும். எனவே அவற்றின் மூலம் உங்களால் மொபைலைத் திறக்கவோ, வாங்குவதை அங்கீகரிக்கவோ அல்லது பயன்பாடுகளில் உள்நுழையவோ முடியாது."</string>
@@ -612,7 +611,7 @@
     <string name="unlock_disable_frp_warning_content_unknown_fingerprint" msgid="5775815077478538855">"திரைப் பூட்டு இல்லாமல் சாதனப் பாதுகாப்பு அம்சங்கள் செயல்படாது.<xliff:g id="EMPTY_LINE">
 
 </xliff:g>சேமிக்கப்பட்டிருக்கும் கைரேகைகளும் இந்தச் சாதனத்திலிருந்து அகற்றப்படும். எனவே அவற்றின் மூலம் உங்களால் மொபைலைத் திறக்கவோ, வாங்குவதை அங்கீகரிக்கவோ அல்லது பயன்பாடுகளில் உள்நுழையவோ முடியாது."</string>
-    <string name="unlock_disable_frp_warning_content_pattern_profile" msgid="2369992898062808499">"வடிவம் இல்லாமல் சுயவிவரப் பாதுகாப்பு அம்சங்கள் செயல்படாது."</string>
+    <string name="unlock_disable_frp_warning_content_pattern_profile" msgid="2369992898062808499">"பேட்டர்ன் இல்லாமல் சுயவிவரப் பாதுகாப்பு அம்சங்கள் செயல்படாது."</string>
     <string name="unlock_disable_frp_warning_content_pattern_fingerprint_profile" msgid="8511105093090018735">"பேட்டர்ன் இல்லாமல் சுயவிவரப் பாதுகாப்பு அம்சங்கள் செயல்படாது.<xliff:g id="EMPTY_LINE">
 
 </xliff:g>சேமிக்கப்பட்டிருக்கும் கைரேகைகளும் இந்தச் சுயவிவரத்திலிருந்து அகற்றப்படும். எனவே அவற்றின் மூலம் உங்களால் சுயவிவரத்தைத் திறக்கவோ, வாங்குவதை அங்கீகரிக்கவோ அல்லது பயன்பாடுகளில் உள்நுழையவோ முடியாது."</string>
@@ -649,7 +648,7 @@
     <string name="lock_last_password_attempt_before_wipe_profile" msgid="1535128774464384305">"அடுத்த முறை தவறான கடவுச்சொல்லை உள்ளிட்டால், உங்கள் பணி விவரமும் அதன் தரவும் நீக்கப்படும்"</string>
     <string name="lock_failed_attempts_now_wiping_device" msgid="8662360098784762828">"பலமுறை தவறாக முயன்றதால், சாதனத்தின் தரவு நீக்கப்படும்."</string>
     <string name="lock_failed_attempts_now_wiping_user" msgid="3793513796171561873">"பலமுறை தவறாக முயன்றதால், இந்தப் பயனர் நீக்கப்படுவார்."</string>
-    <string name="lock_failed_attempts_now_wiping_profile" msgid="5347108525299038285">"பலமுறை தவறாக முயன்றதால், இந்தப் பணி விவரமும் அதன் தரவும் நீக்கப்படும்."</string>
+    <string name="lock_failed_attempts_now_wiping_profile" msgid="5347108525299038285">"பலமுறை தவறாக முயன்றதால், இந்தப் பணிக் கணக்கும் அதன் தரவும் நீக்கப்படும்"</string>
     <string name="lock_failed_attempts_now_wiping_dialog_dismiss" msgid="3950582268749037318">"நிராகரி"</string>
     <plurals name="lockpassword_password_too_short" formatted="false" msgid="694091983183310827">
       <item quantity="other">குறைந்தது <xliff:g id="COUNT_1">%d</xliff:g> எழுத்துகள் இருக்க வேண்டும்</item>
@@ -668,7 +667,6 @@
       <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> இலக்கங்களை விடக் குறைவாக இருக்க வேண்டும்</item>
       <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> இலக்கத்தை விடக் குறைவாக இருக்க வேண்டும்</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"0-9 இலக்கங்கள் மட்டுமே இருக்க வேண்டும்"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"சாதன நிர்வாகி சமீபத்திய பின்னை பயன்படுத்துவதை அனுமதிக்கவில்லை"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"IT நிர்வாகியால், பொதுவான பின்கள் தடை செய்யப்பட்டுள்ளன. வேறொரு பின்னை முயலவும்."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"இதில் தவறான எழுத்துக்குறி இருக்கக்கூடாது"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">குறைந்தது எழுத்து அல்லாத <xliff:g id="COUNT">%d</xliff:g> குறிகள் இருக்க வேண்டும்</item>
       <item quantity="one">குறைந்தது எழுத்து அல்லாத 1 குறி இருக்க வேண்டும்</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">குறைந்தது எண் அல்லாத <xliff:g id="COUNT">%d</xliff:g> எழுத்துகளாவது இருக்க வேண்டும்</item>
+      <item quantity="one">குறைந்தது எண் அல்லாத 1 எழுத்தாவது இருக்க வேண்டும்</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"சாதன நிர்வாகி சமீபத்திய கடவுச்சொல்லைப் பயன்படுத்துவதை அனுமதிக்கவில்லை"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"IT நிர்வாகியால், பொதுவான கடவுச்சொற்கள் தடை செய்யப்பட்டுள்ளன. வேறொரு கடவுச்சொல்லை முயலவும்."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"இலக்கங்கள் ஏறுவரிசையில், இறங்குவரிசையில் அல்லது ஒரே இலக்கத்தைப் பயன்படுத்துவது அனுமதிக்கப்படவில்லை"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"வைஃபை"</item>
+    <item msgid="2271962426654621656">"மொபைல்"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"வைஃபை இணைப்பு இல்லை எனில் மொபைல் நெட்வொர்க்கைப் பயன்படுத்தும்"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"மொபைல் நெட்வொர்க் இல்லை எனில் வைஃபை இணைப்பைப் பயன்படுத்தும்"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"வைஃபை மூலம் அழை. வைஃபை இணைப்பை இழந்தால் அழைப்பும் துண்டிக்கப்படும்."</string>
@@ -1651,7 +1656,7 @@
     </plurals>
     <string name="location_category_recent_location_access" msgid="286059523360285026">"சமீபத்திய இருப்பிட அணுகல்"</string>
     <string name="location_recent_location_access_view_details" msgid="2051602261436245905">"விவரங்களைக் காட்டு"</string>
-    <string name="location_no_recent_apps" msgid="77502059586413278">"எந்தப் பயன்பாடுகளும் சமீபத்தில் இருப்பிடத்தைக் கோரவில்லை"</string>
+    <string name="location_no_recent_apps" msgid="77502059586413278">"எந்த ஆப்ஸும் சமீபத்தில் இருப்பிடத்தைக் கோரவில்லை"</string>
     <string name="location_no_recent_accesses" msgid="6289916310397279890">"சமீபத்தில் எந்த ஆப்ஸும் இருப்பிடத்தை அணுகவில்லை"</string>
     <string name="location_high_battery_use" msgid="7177199869979522663">"அதிகப் பேட்டரி பயன்பாடு"</string>
     <string name="location_low_battery_use" msgid="5030448574501435888">"குறைவான பேட்டரி பயன்பாடு"</string>
@@ -1717,7 +1722,7 @@
     <string name="lockpassword_choose_lock_generic_header" msgid="4418423132980560119">"எப்படித் திறக்க வேண்டும்?"</string>
     <string name="lockpassword_password_set_toast" msgid="601928982984489868">"கடவுச்சொல் அமைக்கப்பட்டது"</string>
     <string name="lockpassword_pin_set_toast" msgid="172594825722240059">"பின் அமைக்கப்பட்டது"</string>
-    <string name="lockpassword_pattern_set_toast" msgid="6923260369475481406">"வடிவம் அமைக்கப்பட்டது"</string>
+    <string name="lockpassword_pattern_set_toast" msgid="6923260369475481406">"பேட்டர்ன் அமைக்கப்பட்டது"</string>
     <string name="lockpassword_choose_your_password_header_for_face" msgid="8823110536502072216">"முக அங்கீகாரத்துக்கு, கடவுச்சொல்லை அமை"</string>
     <string name="lockpassword_choose_your_pattern_header_for_face" msgid="5563793748503883666">"முக அங்கீகாரத்துக்கு, பேட்டர்னை அமை"</string>
     <string name="lockpassword_choose_your_pin_header_for_face" msgid="7238352632535405068">"முக அங்கீகாரத்துக்கு, பின்னை அமை"</string>
@@ -1731,7 +1736,7 @@
     <string name="lockpassword_strong_auth_required_device_pin" msgid="24030584350601016">"கூடுதல் பாதுகாப்பிற்கு, சாதனப் பின்னை உள்ளிடவும்"</string>
     <string name="lockpassword_strong_auth_required_device_password" msgid="7746588206458754598">"கூடுதல் பாதுகாப்பிற்கு, சாதனக் கடவுச்சொல்லை உள்ளிடவும்"</string>
     <string name="lockpassword_strong_auth_required_work_pattern" msgid="6861154706098327320">"கூடுதல் பாதுகாப்பிற்கு, பணிப் பேட்டர்னை வரையவும்"</string>
-    <string name="lockpassword_strong_auth_required_work_pin" msgid="6306902249365524526">"கூடுதல் பாதுகாப்பிற்கு, பணிப் பின்னை உள்ளிடவும்"</string>
+    <string name="lockpassword_strong_auth_required_work_pin" msgid="6306902249365524526">"கூடுதல் பாதுகாப்பிற்கு, பணிக்கான பின்னை உள்ளிடவும்"</string>
     <string name="lockpassword_strong_auth_required_work_password" msgid="2917338218971012776">"கூடுதல் பாதுகாப்பிற்கு, பணிக் கடவுச்சொல்லை உள்ளிடவும்"</string>
     <string name="lockpassword_confirm_your_pattern_details_frp" msgid="1085862410379709928">"ஆரம்பநிலை அமைப்புகளுக்கு மீட்டமைக்கப்பட்டது. மொபைலைப் பயன்படுத்த, முந்தைய பேட்டர்னை உள்ளிடவும்."</string>
     <string name="lockpassword_confirm_your_pin_details_frp" msgid="6849889353126558761">"ஆரம்பநிலை அமைப்புகளுக்கு மீட்டமைக்கப்பட்டது. மொபைலைப் பயன்படுத்த, முந்தைய பின்னை உள்ளிடவும்."</string>
@@ -1741,23 +1746,23 @@
     <string name="lockpassword_confirm_your_password_header_frp" msgid="7326670978891793470">"கடவுச்சொல்லைச் சரிபார்க்கவும்"</string>
     <string name="lockpassword_invalid_pin" msgid="3059022215815900137">"தவறான பின்"</string>
     <string name="lockpassword_invalid_password" msgid="8374331995318204099">"தவறான கடவுச்சொல்"</string>
-    <string name="lockpattern_need_to_unlock_wrong" msgid="1328670466959377948">"தவறான வடிவம்"</string>
+    <string name="lockpattern_need_to_unlock_wrong" msgid="1328670466959377948">"தவறான பேட்டர்ன்"</string>
     <string name="lock_settings_title" msgid="233657584969886812">"சாதனப் பாதுகாப்பு"</string>
     <string name="lockpattern_change_lock_pattern_label" msgid="333149762562581510">"திறக்கும் வடிவத்தை மாற்று"</string>
     <string name="lockpattern_change_lock_pin_label" msgid="3435796032210265723">"திறப்பதற்கான பின்னை மாற்று"</string>
-    <string name="lockpattern_recording_intro_header" msgid="2262005028838969839">"திறப்பதற்கான வடிவத்தை வரைக"</string>
+    <string name="lockpattern_recording_intro_header" msgid="2262005028838969839">"திறப்பதற்கான பேட்டர்னை வரைக"</string>
     <string name="lockpattern_recording_intro_footer" msgid="5426745740754065099">"உதவிக்கு மெனுவை அழுத்தவும்."</string>
     <string name="lockpattern_recording_inprogress" msgid="4060818382176523671">"முடிந்ததும் விரலை எடுக்கவும்"</string>
     <string name="lockpattern_recording_incorrect_too_short" msgid="6374760294545431845">"குறைந்தது <xliff:g id="NUMBER">%d</xliff:g> புள்ளிகளை இணைக்கவும். மீண்டும் முயற்சிக்கவும்."</string>
-    <string name="lockpattern_pattern_entered_header" msgid="2108106638322637851">"வடிவம் பதிவுசெய்யப்பட்டது"</string>
+    <string name="lockpattern_pattern_entered_header" msgid="2108106638322637851">"பேட்டர்ன் பதிவுசெய்யப்பட்டது"</string>
     <string name="lockpattern_need_to_confirm" msgid="4079482507985867389">"உறுதிப்படுத்துவதற்கு வடிவத்தை மீண்டும் வரையவும்"</string>
-    <string name="lockpattern_pattern_confirmed_header" msgid="5603156929428721407">"திறப்பதற்கான புதிய வடிவம்"</string>
+    <string name="lockpattern_pattern_confirmed_header" msgid="5603156929428721407">"திறப்பதற்கான புதிய பேட்டர்ன்"</string>
     <string name="lockpattern_confirm_button_text" msgid="7059311304112902598">"உறுதிசெய்க"</string>
     <string name="lockpattern_restart_button_text" msgid="4322968353922529868">"மீண்டும் வரைக"</string>
     <string name="lockpattern_retry_button_text" msgid="5473976578241534298">"அழி"</string>
     <string name="lockpattern_continue_button_text" msgid="3328913552656376892">"தொடர்க"</string>
-    <string name="lockpattern_settings_title" msgid="5152005866870766842">"திறப்பதற்கான வடிவம்"</string>
-    <string name="lockpattern_settings_enable_title" msgid="8508410891939268080">"வடிவம் தேவை"</string>
+    <string name="lockpattern_settings_title" msgid="5152005866870766842">"திறப்பதற்கான பேட்டர்ன்"</string>
+    <string name="lockpattern_settings_enable_title" msgid="8508410891939268080">"பேட்டர்ன் தேவை"</string>
     <string name="lockpattern_settings_enable_summary" msgid="8027605503917737512">"திரையைத் திறப்பதற்கான வடிவத்தை வரைய வேண்டும்"</string>
     <string name="lockpattern_settings_enable_visible_pattern_title" msgid="4935583222709647096">"வடிவத்தைக் காணும்படி செய்"</string>
     <string name="lockpattern_settings_enable_visible_pattern_title_profile" msgid="5338893138982642228">"சுயவிவரப் பேட்டர்னை வரையும் போது காட்டு"</string>
@@ -2081,7 +2086,7 @@
     <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"நீங்கள் வாசிக்க விரும்பும், தற்காலிகமாகத் தெரியும் மெசேஜ்கள் எவ்வளவு நேரம் காட்டப்பட வேண்டும் என்பதைத் தேர்வுசெய்யலாம்.\n\nஇந்த அமைப்பு அனைத்து ஆப்ஸிலும் ஆதரிக்கப்படாது."</string>
     <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"உங்களைச் செயல்படும்படி கூறும் மெசேஜ்களை எவ்வளவு நேரம் காட்டலாம் என்பதைத் தேர்வுசெய்யவும். இவை சற்று நேரத்திற்கு மட்டுமே காட்டப்படும்.\n\nஇந்த அமைப்பு அனைத்து ஆப்ஸாலும் ஆதரிக்கப்படாது."</string>
     <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"தொட்டுப் பிடித்தல் தாமதம்"</string>
-    <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"வண்ணத்தின் நேர்மாறான முறை"</string>
+    <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"கலர் இன்வெர்ஷன்"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"செயல்திறனைப் பாதிக்கலாம்"</string>
     <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"இருப்பு நேரம்"</string>
     <string name="accessibility_autoclick_description" msgid="5492414927846407499">"நீங்கள் மவுஸைப் பயன்படுத்துகிறீர்கள் எனில், ஒரு குறிப்பிட்ட நேரத்திற்குக் கர்சர் நகராமல் இருக்கும்போது, அது தானாகவே என்ன செய்யவேண்டுமென அமைத்துக்கொள்ளலாம்."</string>
@@ -2304,7 +2309,7 @@
       <item quantity="other">%1$d ஆப்ஸைக் கட்டுப்படுத்தவா?</item>
       <item quantity="one">பயன்பாட்டைக் கட்டுப்படுத்தவா?</item>
     </plurals>
-    <string name="battery_tip_restrict_app_dialog_message" msgid="6905822297507947381">"பேட்டரியைச் சேமிக்க, பின்னணியில் பேட்டரியை உபயோகிப்பதிலிருந்து <xliff:g id="APP">%1$s</xliff:g> பயன்பாட்டைத் தடுக்கவும். இந்த ஆப்ஸ் சரியாகச் செயல்படாமல் இருக்கலாம், அத்துடன் இதற்கான அறிவிப்புகளும் தாமதமாக வரலாம்."</string>
+    <string name="battery_tip_restrict_app_dialog_message" msgid="6905822297507947381">"பேட்டரியைச் சேமிக்க, பின்னணியில் பேட்டரியை உபயோகிப்பதிலிருந்து <xliff:g id="APP">%1$s</xliff:g> ஆப்ஸைத் தடுக்கவும். இந்த ஆப்ஸ் சரியாகச் செயல்படாமல் இருக்கலாம், அத்துடன் இதற்கான அறிவிப்புகளும் தாமதமாக வரலாம்."</string>
     <string name="battery_tip_restrict_apps_less_than_5_dialog_message" msgid="4225881888543582456">"பேட்டரியைச் சேமிக்க, பின்னணியில் பேட்டரியைப் பயன்படுத்துவதிலிருந்து இந்த ஆப்ஸைத் தடுக்கவும். தடுக்கப்பட்ட ஆப்ஸ் சரியாகச் செயல்படாமல் இருக்கலாம், அத்துடன் இவற்றுக்கான அறிவிப்புகளும் தாமதமாக வரலாம்.\n\nஆப்ஸ்:"</string>
     <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"பேட்டரியைச் சேமிக்க, பின்னணியில் பேட்டரியைப் பயன்படுத்துவதிலிருந்து இந்த ஆப்ஸைத் தடுக்கவும். தடுக்கப்பட்ட ஆப்ஸ் சரியாகச் செயல்படாமல் இருக்கலாம். அத்துடன் இவற்றுக்கான அறிவிப்புகளும் தாமதமாக வரலாம்.\n\nஆப்ஸ்:\n<xliff:g id="APP_LIST">%1$s</xliff:g>."</string>
     <string name="battery_tip_restrict_app_dialog_ok" msgid="2573410775701913487">"கட்டுப்படுத்து"</string>
@@ -2633,7 +2638,7 @@
     <string name="enter_password" msgid="2963496904625715235">"Androidஐத் தொடங்க, கடவுச்சொல்லை உள்ளிடவும்"</string>
     <string name="enter_pin" msgid="7140938268709546890">"Androidஐத் தொடங்க, PINஐ உள்ளிடவும்"</string>
     <string name="enter_pattern" msgid="1653841963422825336">"Androidஐத் தொடங்க, வடிவத்தை வரையவும்"</string>
-    <string name="cryptkeeper_wrong_pattern" msgid="4580105105385125467">"தவறான வடிவம்"</string>
+    <string name="cryptkeeper_wrong_pattern" msgid="4580105105385125467">"தவறான பேட்டர்ன்"</string>
     <string name="cryptkeeper_wrong_password" msgid="1709534330303983166">"தவறான கடவுச்சொல்"</string>
     <string name="cryptkeeper_wrong_pin" msgid="857757190077859245">"தவறான பின்"</string>
     <string name="checking_decryption" msgid="5927759912073053101">"சரிபார்க்கிறது..."</string>
@@ -2877,7 +2882,7 @@
     <string name="user_cannot_add_accounts_message" msgid="5993561303748749097">"வரையறுக்கப்பட்ட சுயவிவரங்களால் கணக்குகளைச் சேர்க்க முடியாது"</string>
     <string name="user_remove_user_menu" msgid="3505139157217459864">"சாதனத்திலிருந்து <xliff:g id="USER_NAME">%1$s</xliff:g> ஐ நீக்கு"</string>
     <string name="user_lockscreen_settings" msgid="3820813814848394568">"லாக் ஸ்கிரீன் அமைப்புகள்"</string>
-    <string name="user_add_on_lockscreen_menu" msgid="5211604808199585774">"லாக் ஸ்கிரீனிலிருந்து பயனர்களைச் சேர்"</string>
+    <string name="user_add_on_lockscreen_menu" msgid="5211604808199585774">"பூட்டுத் திரையிலிருந்து பயனர்களைச் சேர்"</string>
     <string name="user_new_user_name" msgid="3880395219777884838">"புதியவர்"</string>
     <string name="user_new_profile_name" msgid="3074939718101489937">"புதிய சுயவிவரம்"</string>
     <string name="user_confirm_remove_self_title" msgid="6739480453680217543">"உங்களை நீக்கவா?"</string>
@@ -3036,7 +3041,7 @@
     <string name="connected_devices_dashboard_no_driving_mode_summary" msgid="3524409078596318803">"புளூடூத், NFC"</string>
     <string name="connected_devices_dashboard_no_driving_mode_no_nfc_summary" msgid="7881286613528299400">"புளூடூத்"</string>
     <string name="app_and_notification_dashboard_title" msgid="8448096608058843730">"ஆப்ஸ் &amp; அறிவிப்புகள்"</string>
-    <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"அசிஸ்டண்ட், சமீபத்திய ஆப்ஸ், இயல்பான ஆப்ஸ்"</string>
+    <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"Assistant, சமீபத்திய ஆப்ஸ், இயல்பான ஆப்ஸ்"</string>
     <string name="notification_settings_work_profile" msgid="7190550347842400029">"பணிக் கணக்கில், ஆப்ஸுற்கான அறிவிப்பு அணுகல் இல்லை."</string>
     <string name="account_dashboard_title" msgid="4734300939532555885">"கணக்குகள்"</string>
     <string name="account_dashboard_default_summary" msgid="6822549669771936206">"கணக்குகள் எதுவும் சேர்க்கப்படவில்லை"</string>
@@ -3086,7 +3091,7 @@
     <string name="keywords_ignore_optimizations" msgid="9127632532176249438">"மேம்படுத்தல்களைத் தவிர்த்தல், பேட்டரியைக் குறைவாகப் பயன்படுத்துதல், ஆப்ஸ் காத்திருப்பு நிலை"</string>
     <string name="keywords_color_mode" msgid="8893345199519181751">"அதிர்வு, RGB, sRGB, வண்ணம், இயற்கை, நிலையானது"</string>
     <string name="keywords_color_temperature" msgid="2255253972992035046">"வண்ணம், வண்ண வெப்பநிலை, D65, D73, வெள்ளை, மஞ்சள், நீலம், அடர், வெளிர்"</string>
-    <string name="keywords_lockscreen" msgid="4936846554280830394">"திறப்பதற்கு ஸ்லைடு செய்தல், கடவுச்சொல், வடிவம், பின்"</string>
+    <string name="keywords_lockscreen" msgid="4936846554280830394">"திறப்பதற்கு ஸ்லைடு செய்தல், கடவுச்சொல், பேட்டர்ன், பின்"</string>
     <string name="keywords_profile_challenge" msgid="8653718001253979611">"பணிச்சுமை, பணி, சுயவிவரம்"</string>
     <string name="keywords_unification" msgid="2020759909366983593">"பணிக் கணக்கு, நிர்வகிக்கப்படும் சுயவிவரம், ஒருங்கிணை, ஒருங்கிணைத்தல், பணி, சுயவிவரம்"</string>
     <string name="keywords_gesture" msgid="5031323247529869644">"சைகைகள்"</string>
@@ -3564,7 +3569,7 @@
     <string name="encryption_interstitial_message_pattern" msgid="5620724295995735120">"இந்தச் சாதனத்தைத் துவக்கும் முன், பேட்டர்ன் தேவைப்படுமாறு அமைத்து, மேலும் பாதுகாக்கலாம். சாதனம் துவங்கும் வரை, அழைப்புகள், செய்திகள் அல்லது அலாரங்கள் உள்ளிட்ட அறிவிப்புகளை இதில் பெற முடியாது. \n\nஉங்கள் சாதனம் தொலைந்து போனாலோ திருடப்பட்டாலோ, அதில் உள்ள உங்கள் டேட்டாவைப் பாதுகாக்க இதைக் கடைபிடிக்கலாம். சாதனத்தைத் தொடங்கும் போது, பேட்டர்னைக் கேட்பதை அமைக்கவா?"</string>
     <string name="encryption_interstitial_message_password" msgid="7236688467386126401">"இந்தச் சாதனத்தைத் துவக்கும் முன், கடவுச்சொல் தேவைப்படுமாறு அமைத்து, மேலும் பாதுகாக்கலாம். சாதனம் துவங்கும் வரை, அழைப்புகள், செய்திகள் அல்லது அலாரங்கள் உள்ளிட்ட அறிவிப்புகளை இதில் பெற முடியாது. \n\nஉங்கள் சாதனம் தொலைந்து போனாலோ திருடப்பட்டாலோ, அதில் உள்ள உங்கள் டேட்டாவைப் பாதுகாக்க இதைக் கடைபிடிக்கலாம். சாதனத்தைத் தொடங்கும் போது, கடவுச்சொல்லைக் கேட்பதை அமைக்கவா?"</string>
     <string name="encryption_interstitial_message_pin_for_fingerprint" msgid="3706009740537484517">"சாதனத்தைத் திறக்க கைரேகையைப் பயன்படுத்துவதுடன் சேர்த்து, பின் தேவைப்படுமாறு அமைத்து உங்கள் சாதனத்திற்குக் கூடுதல் பாதுகாப்பு வழங்கிடலாம். சாதனம் துவங்கும் வரை, அழைப்புகள், செய்திகள் அல்லது அலாரங்கள் உள்ளிட்ட அறிவிப்புகளை இதில் பெற முடியாது. \n\nஉங்கள் சாதனம் தொலைந்து போனாலோ திருடப்பட்டாலோ, அதில் உள்ள உங்கள் டேட்டாவைப் பாதுகாக்க இதைக் கடைபிடிக்கலாம். சாதனத்தைத் தொடங்கும் போது, பின்னைக் கேட்பதை அமைக்கவா?"</string>
-    <string name="encryption_interstitial_message_pattern_for_fingerprint" msgid="5230877866699023998">"சாதனத்தைத் திறக்க கைரேகையைப் பயன்படுத்துவதுடன் சேர்த்து, வடிவம் தேவைப்படுமாறு அமைத்து உங்கள் சாதனத்திற்குக் கூடுதல் பாதுகாப்பு வழங்கிடலாம். சாதனம் துவங்கும் வரை, அழைப்புகள், செய்திகள் அல்லது அலாரங்கள் உள்ளிட்ட அறிவிப்புகளை இதில் பெற முடியாது. \n\nஉங்கள் சாதனம் தொலைந்து போனாலோ திருடப்பட்டாலோ, அதில் உள்ள உங்கள் டேட்டாவைப் பாதுகாக்க இதைக் கடைபிடிக்கலாம். சாதனத்தைத் தொடங்கும் போது, பேட்டர்னைக் கேட்பதை அமைக்கவா?"</string>
+    <string name="encryption_interstitial_message_pattern_for_fingerprint" msgid="5230877866699023998">"சாதனத்தைத் திறக்க கைரேகையைப் பயன்படுத்துவதுடன் சேர்த்து, பேட்டர்ன் தேவைப்படுமாறு அமைத்து உங்கள் சாதனத்திற்குக் கூடுதல் பாதுகாப்பு வழங்கிடலாம். சாதனம் துவங்கும் வரை, அழைப்புகள், செய்திகள் அல்லது அலாரங்கள் உள்ளிட்ட அறிவிப்புகளை இதில் பெற முடியாது. \n\nஉங்கள் சாதனம் தொலைந்து போனாலோ திருடப்பட்டாலோ, அதில் உள்ள உங்கள் டேட்டாவைப் பாதுகாக்க இதைக் கடைபிடிக்கலாம். சாதனத்தைத் தொடங்கும் போது, பேட்டர்னைக் கேட்பதை அமைக்கவா?"</string>
     <string name="encryption_interstitial_message_password_for_fingerprint" msgid="8451977276748128814">"சாதனத்தைத் திறக்க கைரேகையைப் பயன்படுத்துவதுடன் சேர்த்து, கடவுச்சொல் தேவைப்படுமாறு அமைத்து உங்கள் சாதனத்திற்குக் கூடுதல் பாதுகாப்பு வழங்கிடலாம். சாதனம் தொடங்கும் வரை, அழைப்புகள், செய்திகள் அல்லது அலாரங்கள் உள்ளிட்ட அறிவிப்புகளை இதில் பெற முடியாது. \n\nஉங்கள் சாதனம் தொலைந்து போனாலோ திருடப்பட்டாலோ, அதில் உள்ள உங்கள் டேட்டாவைப் பாதுகாக்க இதைக் கடைபிடிக்கலாம். சாதனத்தைத் தொடங்கும் போது, கடவுச்சொல்லைக் கேட்பதை அமைக்கவா?"</string>
     <string name="encryption_interstitial_message_pin_for_face" msgid="7469243836881325172">"சாதனத்தைத் திறப்பதற்கு உங்கள் முகத்தைப் பயன்படுத்துவது மட்டுமல்லாமல், சாதனம் தொடங்கும் முன்பாக, பின்னை உள்ளிடும்படி அமைத்து, கூடுதல் பாதுகாப்பை வழங்கலாம். சாதனம் தொடங்கும்வரை, அழைப்புகள், மெசேஜ்கள், அலாரங்கள் உள்ளிட்ட எவற்றையும் சாதனத்தால் பெற இயலாது.\n\nசாதனம் தொலைந்துவிட்டாலோ திருடப்பட்டாலோ, அதிலுள்ள தரவைப் பாதுகாக்க இது உதவும். சாதனத்தைத் தொடங்கும்போது கடவுச்சொல்லைக் கேட்குமாறு அமைக்கவா?"</string>
     <string name="encryption_interstitial_message_pattern_for_face" msgid="9221235885895441797">"சாதனத்தைத் திறப்பதற்கு உங்கள் முகத்தைப் பயன்படுத்துவது மட்டுமல்லாமல், சாதனம் தொடங்கும் முன்பாக, பேட்டர்னை உள்ளிடும்படி அமைத்து, கூடுதல் பாதுகாப்பை வழங்கலாம். சாதனம் தொடங்கும்வரை, அழைப்புகள், மெசேஜ்கள், அலாரங்கள் உள்ளிட்ட எவற்றையும் சாதனத்தால் பெற இயலாது. \n\nசாதனம் தொலைந்துவிட்டாலோ திருடப்பட்டாலோ, அதிலுள்ள தரவைப் பாதுகாக்க இது உதவும். சாதனத்தைத் தொடங்கும்போது கடவுச்சொல்லைக் கேட்குமாறு அமைக்கவா?"</string>
@@ -3574,7 +3579,7 @@
     <string name="restricted_true_label" msgid="1545180379083441282">"கட்டுப்படுத்தியது"</string>
     <string name="restricted_false_label" msgid="4512495920090068495">"ஆப்ஸ் கட்டுப்படுத்தப்படவில்லை"</string>
     <string name="encrypt_talkback_dialog_require_pin" msgid="2781758476498571031">"பின் தேவையா?"</string>
-    <string name="encrypt_talkback_dialog_require_pattern" msgid="8705104812047332411">"வடிவம் தேவையா?"</string>
+    <string name="encrypt_talkback_dialog_require_pattern" msgid="8705104812047332411">"பேட்டர்ன் தேவையா?"</string>
     <string name="encrypt_talkback_dialog_require_password" msgid="5070710417271353306">"கடவுச்சொல் தேவையா?"</string>
     <string name="encrypt_talkback_dialog_message_pin" msgid="1912533826818077891">"இந்தச் சாதனத்தைத் துவக்க பின்னை நீங்கள் பயன்படுத்தினால், <xliff:g id="SERVICE">%1$s</xliff:g> போன்ற அணுகல்தன்மை சேவைகள் கிடைக்காது."</string>
     <string name="encrypt_talkback_dialog_message_pattern" msgid="4415837749933863432">"இந்தச் சாதனத்தைத் துவக்க வடிவத்தை நீங்கள் பயன்படுத்தினால், <xliff:g id="SERVICE">%1$s</xliff:g> போன்ற அணுகல்தன்மை சேவைகள் கிடைக்காது."</string>
@@ -3758,7 +3763,7 @@
     <string name="assist_access_screenshot_title" msgid="1991014038776117688">"ஸ்கிரீன் ஷாட்டைப் பயன்படுத்து"</string>
     <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"திரையின் படத்தை அணுக, அசிஸ்ட் ஆப்ஸை அனுமதிக்கும்"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"திரையில் ஃபிளாஷ்"</string>
-    <string name="assist_flash_summary" msgid="6697095786317559129">"அசிஸ்ட் பயன்பாடானது திரை அல்லது ஸ்கிரீன் ஷாட்டிலிருந்து உரையை அணுகும் போது, திரையில் ஃபிளாஷ் மின்னும்"</string>
+    <string name="assist_flash_summary" msgid="6697095786317559129">"அசிஸ்ட் ஆப்ஸானது திரை அல்லது ஸ்கிரீன் ஷாட்டிலிருந்து உரையை அணுகும் போது, திரையில் ஃபிளாஷ் மின்னும்"</string>
     <string name="assist_footer" msgid="7030121180457472165">"நீங்கள் பார்க்கும் திரையில் உள்ள தகவலின் அடிப்படையில் அசிஸ்ட் ஆப்ஸ் உங்களுக்கு உதவும். ஒருங்கிணைந்த உதவியைப் பெறுவதற்காக சில ஆப்ஸ்களில், துவக்கி மற்றும் குரல் உள்ளீட்டுச் சேவைகள் ஆகிய இரண்டையும் பயன்படுத்தலாம்."</string>
     <string name="average_memory_use" msgid="5333366040118953945">"சராசரி நினைவக உபயோகம்"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"அதிகபட்ச நினைவக உபயோகம்"</string>
@@ -3991,7 +3996,7 @@
     <string name="home_app" msgid="3695063566006954160">"முகப்பு"</string>
     <string name="no_default_home" msgid="1518949210961918497">"இயல்பு முகப்பு இல்லை"</string>
     <string name="lockpattern_settings_require_cred_before_startup" msgid="63693894094570367">"பாதுகாப்பான தொடக்கம்"</string>
-    <string name="lockpattern_settings_require_pattern_before_startup_summary" msgid="2330543541999937953">"சாதனத்தைத் தொடங்க, வடிவம் தேவை. முடக்கப்பட்டிருக்கும் போது, இந்தச் சாதனம் அழைப்புகள், செய்திகள், அறிவிப்புகள் அல்லது அலாரங்கள் ஆகியவற்றைப் பெற முடியாது."</string>
+    <string name="lockpattern_settings_require_pattern_before_startup_summary" msgid="2330543541999937953">"சாதனத்தைத் தொடங்க, பேட்டர்ன் தேவை. முடக்கப்பட்டிருக்கும் போது, இந்தச் சாதனம் அழைப்புகள், செய்திகள், அறிவிப்புகள் அல்லது அலாரங்கள் ஆகியவற்றைப் பெற முடியாது."</string>
     <string name="lockpattern_settings_require_pin_before_startup_summary" msgid="1058173991832208485">"சாதனத்தைத் தொடங்க, பின் தேவை. முடக்கப்பட்டிருக்கும் போது, இந்தச் சாதனம் அழைப்புகள், செய்திகள், அறிவிப்புகள் அல்லது அலாரங்கள் ஆகியவற்றைப் பெற முடியாது."</string>
     <string name="lockpattern_settings_require_password_before_startup_summary" msgid="1266300087760553585">"சாதனத்தைத் தொடங்க, கடவுச்சொல் தேவை. முடக்கப்பட்டிருக்கும் போது, இந்தச் சாதனம் அழைப்புகள், செய்திகள், அறிவிப்புகள் அல்லது அலாரங்கள் ஆகியவற்றைப் பெற முடியாது."</string>
     <string name="suggestion_additional_fingerprints" msgid="3434467207282466411">"மற்றொரு கைரேகையைச் சேர்க்கவும்"</string>
diff --git a/tests/CarDeveloperOptions/res/values-te/arrays.xml b/tests/CarDeveloperOptions/res/values-te/arrays.xml
index c616699..1ae209a 100644
--- a/tests/CarDeveloperOptions/res/values-te/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-te/arrays.xml
@@ -38,7 +38,16 @@
     <item msgid="5827960506924849753">"10 నిమిషాలు"</item>
     <item msgid="6677424950124253938">"30 నిమిషాలు"</item>
   </string-array>
-    <!-- no translation found for dream_timeout_entries:7 (8271452751594598661) -->
+  <string-array name="dream_timeout_entries">
+    <item msgid="6487043225269853023">"ఎప్పటికీ వద్దు"</item>
+    <item msgid="2517785806387977252">"15 సెకన్లు"</item>
+    <item msgid="6347954399441173672">"30 సెకన్లు"</item>
+    <item msgid="4858305253279921789">"1 నిమిషం"</item>
+    <item msgid="8109273437140044073">"2 నిమిషాలు"</item>
+    <item msgid="2788593551142462622">"5 నిమిషాలు"</item>
+    <item msgid="8012672183888404961">"10 నిమిషాలు"</item>
+    <item msgid="8271452751594598661">"30 నిమిషాలు"</item>
+  </string-array>
   <string-array name="lock_after_timeout_entries">
     <item msgid="2232921187970351881">"తక్షణమే"</item>
     <item msgid="2038544972632026612">"5 సెకన్లు"</item>
@@ -50,17 +59,47 @@
     <item msgid="811192536981678974">"10 నిమిషాలు"</item>
     <item msgid="7258394417241706272">"30 నిమిషాలు"</item>
   </string-array>
-    <!-- no translation found for entries_font_size:0 (2340391964816059553) -->
-    <!-- no translation found for entries_font_size:0 (6490061470416867723) -->
-    <!-- no translation found for entries_font_size:2 (1714184661981538355) -->
-    <!-- no translation found for entries_font_size:2 (1678068858001018666) -->
-    <!-- no translation found for wifi_status:3 (5848277343965362748) -->
-    <!-- no translation found for wifi_status_with_ssid:1 (6816207058895999545) -->
-    <!-- no translation found for wifi_status_with_ssid:3 (7547609081339573756) -->
-    <!-- no translation found for wifi_status_with_ssid:4 (5145158315060185414) -->
+  <string-array name="entries_font_size">
+    <item msgid="2340391964816059553">"చిన్నది"</item>
+    <item msgid="591935967183159581">"డిఫాల్ట్"</item>
+    <item msgid="1714184661981538355">"పెద్దది"</item>
+    <item msgid="6195563047686707484">"అతి పెద్దగా"</item>
+  </string-array>
+  <string-array name="wifi_status">
+    <item msgid="1304883790721412351"></item>
+    <item msgid="4157625910392775808">"స్కాన్ చేస్తోంది…"</item>
+    <item msgid="5597394826455877834">"కనెక్ట్ చేస్తోంది..."</item>
+    <item msgid="5848277343965362748">"ప్రామాణీకరిస్తోంది…"</item>
+    <item msgid="3391238031431440676">"IP చిరునామాను పొందుతోంది…"</item>
+    <item msgid="5257597310494000224">"కనెక్ట్ అయింది"</item>
+    <item msgid="8472497592913050396">"తాత్కాలికంగా రద్దు చేయబడింది"</item>
+    <item msgid="1228072488815999109">"డిస్‌కనెక్ట్ చేస్తోంది..."</item>
+    <item msgid="7253087004422991731">"డిస్‌కనెక్ట్ చేయబడింది"</item>
+    <item msgid="4169850917304751227">"విఫలమైంది"</item>
+    <item msgid="6266658166690831131">"బ్లాక్ చేయబడింది"</item>
+    <item msgid="4517230805854909775">"బలహీన కనెక్షన్‌ను తాత్కాలికంగా నివారిస్తోంది"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="4853670665485437464"></item>
+    <item msgid="6816207058895999545">"స్కాన్ చేస్తోంది…"</item>
+    <item msgid="8058143476674427024">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>కి కనెక్ట్ చేస్తోంది…"</item>
+    <item msgid="7547609081339573756">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>తో ప్రామాణీకరిస్తోంది…"</item>
+    <item msgid="5145158315060185414">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> నుండి IP చిరునామాను పొందుతోంది…"</item>
+    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>కి కనెక్ట్ చేయబడింది"</item>
+    <item msgid="6600156231416890902">"తాత్కాలికంగా రద్దు చేయబడింది"</item>
+    <item msgid="4133290864821295785">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> నుండి డిస్‌కనెక్ట్ చేస్తోంది…"</item>
+    <item msgid="3980154971187953257">"డిస్‌కనెక్ట్ చేయబడింది"</item>
+    <item msgid="2847316776634969068">"విఫలమైంది"</item>
+    <item msgid="4390990424746035383">"బ్లాక్ చేయబడింది"</item>
+    <item msgid="3618248791367063949">"బలహీన కనెక్షన్‌ను తాత్కాలికంగా నివారిస్తోంది"</item>
+  </string-array>
     <!-- no translation found for wifi_tether_security:0 (5586343370515598801) -->
     <!-- no translation found for wifi_tether_security:1 (6136336549994615745) -->
-    <!-- no translation found for wifi_p2p_wps_setup:0 (5390235347963255303) -->
+  <string-array name="wifi_p2p_wps_setup">
+    <item msgid="5390235347963255303">"పుష్ బటన్"</item>
+    <item msgid="7401896200768713930">"పీర్ డివైజ్ నుండి పిన్‌"</item>
+    <item msgid="4526848028011846710">"ఈ డివైజ్ నుండి పిన్‌"</item>
+  </string-array>
   <string-array name="wifi_p2p_status">
     <item msgid="8741947238021758201">"కనెక్ట్ అయింది"</item>
     <item msgid="983792611851499732">"ఆహ్వానించబడింది"</item>
@@ -82,8 +121,13 @@
     <item msgid="1644506614010085798">"4"</item>
     <item msgid="3132506679404897150">"5"</item>
   </string-array>
-    <!-- no translation found for wifi_signal:1 (7882129634982603782) -->
-    <!-- no translation found for wifi_signal:4 (999948812884919584) -->
+  <string-array name="wifi_signal">
+    <item msgid="1709949377823900951">"బాగాలేదు"</item>
+    <item msgid="7882129634982603782">"బాగాలేదు"</item>
+    <item msgid="6457357501905996224">"ఫర్వాలేదు"</item>
+    <item msgid="405271628162918841">"బాగుంది"</item>
+    <item msgid="999948812884919584">"అద్భుతం"</item>
+  </string-array>
   <string-array name="data_usage_data_range">
     <item msgid="8986775481492954015">"గత 30 రోజులు"</item>
     <item msgid="3211287705232736964">"విని. పునరా. సెట్ చేయి..."</item>
@@ -119,7 +163,10 @@
     <item msgid="7330627471456865502">"MSCHAPV2"</item>
     <item msgid="6255179395132581882">"GTC"</item>
   </string-array>
-    <!-- no translation found for wifi_ip_settings:1 (4377002609760712163) -->
+  <string-array name="wifi_ip_settings">
+    <item msgid="2717196390555072244">"DHCP"</item>
+    <item msgid="4377002609760712163">"స్థిరం"</item>
+  </string-array>
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"ఏదీ వద్దు"</item>
     <item msgid="1464741437353223198">"మాన్యువల్"</item>
@@ -239,11 +286,73 @@
     <item msgid="1165623660533024666">"నేపథ్యంలో అమలు చేయడం"</item>
     <item msgid="6423861043647911030">"యాక్సెస్ సామర్థ్య వాల్యూమ్"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:3 (7836406246005211990) -->
-    <!-- no translation found for app_ops_labels:4 (3951439024549922598) -->
-    <!-- no translation found for app_ops_labels:8 (3597797992398484655) -->
-    <!-- no translation found for app_ops_labels:20 (3037159047591081136) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"స్థానం"</item>
+    <item msgid="6656077694190491067">"స్థానం"</item>
+    <item msgid="8790228218278477369">"స్థానం"</item>
+    <item msgid="7836406246005211990">"వైబ్రేట్"</item>
+    <item msgid="3951439024549922598">"కాంటాక్ట్‌లను చదవండి"</item>
+    <item msgid="8802152411647068">"పరిచయాలను సవరించండి"</item>
+    <item msgid="229544934599698735">"కాల్ లాగ్‌ను చదవండి"</item>
+    <item msgid="7396102294405899613">"కాల్ లాగ్‌ను సవరించండి"</item>
+    <item msgid="3597797992398484655">"క్యాలెండర్‌ను చదవండి"</item>
+    <item msgid="2705975774250907343">"క్యాలెండర్‌ను సవరించండి"</item>
+    <item msgid="4668747371441932697">"స్థానం"</item>
+    <item msgid="1487578921720243646">"నోటిఫికేషన్‌ను పోస్ట్ చేయండి"</item>
+    <item msgid="4636080349724146638">"స్థానం"</item>
+    <item msgid="673510900286463926">"ఫోన్‌కు కాల్ చేయండి"</item>
+    <item msgid="542083422784609790">"SMS/MMSను చదవండి"</item>
+    <item msgid="1033780373029588436">"SMS/MMSను వ్రాయండి"</item>
+    <item msgid="5647111115517787488">"SMS/MMSను స్వీకరించండి"</item>
+    <item msgid="8591105601108455893">"SMS/MMSను స్వీకరించండి"</item>
+    <item msgid="7730995008517841903">"SMS/MMSను స్వీకరించండి"</item>
+    <item msgid="2613033109026626086">"SMS/MMSను స్వీకరించండి"</item>
+    <item msgid="3037159047591081136">"SMS/MMSను పంపండి"</item>
+    <item msgid="4726682243833913568">"SMS/MMSను చదవండి"</item>
+    <item msgid="6555678522277865572">"SMS/MMSను వ్రాయండి"</item>
+    <item msgid="6981734935578130884">"సెట్టింగ్‌లను సవరించండి"</item>
+    <item msgid="8705854389991425629">"పైభాగంలో గీయండి"</item>
+    <item msgid="5861356020344153651">"నోటిఫికేషన్‌లను యాక్సెస్ చేయండి"</item>
+    <item msgid="78432174621628659">"కెమెరా"</item>
+    <item msgid="3986116419882154794">"ఆడియోను రికార్డ్ చేయండి"</item>
+    <item msgid="4516840825756409490">"ఆడియో ప్లే చేయండి"</item>
+    <item msgid="6811712502798183957">"క్లిప్‌బోర్డ్‌ను చదవండి"</item>
+    <item msgid="2780369012602289114">"క్లిప్‌బోర్డ్‌ను సవరించండి"</item>
+    <item msgid="2331359440170850868">"మీడియా బటన్‌లు"</item>
+    <item msgid="6133599737122751231">"ఆడియో కేంద్రీకరణ"</item>
+    <item msgid="6844485713404805301">"మాస్టర్ వాల్యూమ్"</item>
+    <item msgid="1600379420669104929">"వాయిస్ వాల్యూమ్"</item>
+    <item msgid="6296768210470214866">"రింగ్ వాల్యూమ్"</item>
+    <item msgid="510690696071629241">"మీడియా వాల్యూమ్"</item>
+    <item msgid="406861638631430109">"అలారం వాల్యూమ్"</item>
+    <item msgid="4715864795872233884">"నోటిఫికేషన్ వాల్యూమ్"</item>
+    <item msgid="2311478519251301183">"బ్లూటూత్ వాల్యూమ్"</item>
+    <item msgid="5133991377896747027">"సక్రియంగా ఉంచండి"</item>
+    <item msgid="2464189519136248621">"లొకేషన్"</item>
+    <item msgid="2062677934050803037">"స్థానం"</item>
+    <item msgid="1735171933192715957">"వినియోగ గణాంకాలను పొందండి"</item>
+    <item msgid="1014093788778383554">"మైక్రోఫోన్‌ను మ్యూట్ చేయండి/అన్‌మ్యూట్ చేయండి"</item>
+    <item msgid="4199297950608622850">"టోస్ట్‌ను చూపడం"</item>
+    <item msgid="2527962435313398821">"మీడియాని ప్రొజెక్ట్ చేయడం"</item>
+    <item msgid="5117506254221861929">"VPNని సక్రియం చేయడం"</item>
+    <item msgid="8291198322681891160">"వాల్‌పేపర్ వ్రాయండి"</item>
+    <item msgid="7106921284621230961">"నిర్మాణంలో సహాయం"</item>
+    <item msgid="4496533640894624799">"స్క్రీన్‌షాట్‌కు సహాయం"</item>
+    <item msgid="2598847264853993611">"ఫోన్ స్థితిని చదవడం"</item>
+    <item msgid="9215610846802973353">"వాయిస్ మెయిల్‌ను జోడించడం"</item>
+    <item msgid="9186411956086478261">"sipని ఉపయోగించడం"</item>
+    <item msgid="6884763100104539558">"వెళ్లే కాల్‌ను ప్రాసెస్ చేయడం"</item>
+    <item msgid="125513972170580692">"వేలిముద్ర"</item>
+    <item msgid="2556071024281275619">"శరీర సెన్సార్‌లు"</item>
+    <item msgid="617168514928339387">"సెల్ ప్రసారాలను చదవడం"</item>
+    <item msgid="7134693570516523585">"స్థానాన్ని నకిలీ చేయడం"</item>
+    <item msgid="7224489175375229399">"నిల్వను చదవడం"</item>
+    <item msgid="8472735063903258202">"నిల్వలో వ్రాయడం"</item>
+    <item msgid="4069276819909595110">"స్క్రీన్‌ను ఆన్ చేయడం"</item>
+    <item msgid="1228338896751121025">"ఖాతాలను పొందడం"</item>
+    <item msgid="3181581793459233672">"నేపథ్యంలో అమలు చేయడం"</item>
+    <item msgid="2340936043025374076">"యాక్సెస్ సామర్థ్య వాల్యూమ్"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"తక్కువ సేపు"</item>
     <item msgid="4816511817309094890">"మధ్యస్థం"</item>
@@ -260,7 +369,13 @@
     <item msgid="4627069151979553527">"కర్సివ్"</item>
     <item msgid="6896773537705206194">"చిన్న క్యాపిటల్‌లు"</item>
   </string-array>
-    <!-- no translation found for captioning_font_size_selector_titles:3 (2784236342175159295) -->
+  <string-array name="captioning_font_size_selector_titles">
+    <item msgid="1680223634161592855">"చాలా చిన్నది"</item>
+    <item msgid="5091603983404027034">"చిన్నది"</item>
+    <item msgid="176844712416932112">"సాధారణం"</item>
+    <item msgid="2784236342175159295">"పెద్దది"</item>
+    <item msgid="218913203203160606">"చాలా పెద్దది"</item>
+  </string-array>
   <string-array name="captioning_edge_type_selector_titles">
     <item msgid="3865198759294188069">"డిఫాల్ట్"</item>
     <item msgid="6488643537808152001">"ఏదీ వద్దు"</item>
@@ -275,7 +390,14 @@
     <item msgid="1874668269931014581">"75%"</item>
     <item msgid="6462911487571123954">"100%"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"యాప్‌ ఢిఫాల్ట్‌లను ఉపయోగించు"</item>
+    <item msgid="8611890312638868524">"నలుపు నేపథ్యంలో తెలుపు రంగు"</item>
+    <item msgid="5891360837786277638">"తెలుపు మీద నలుపు"</item>
+    <item msgid="2798457065945456853">"నలుపు నేపథ్యంలో పసుపు రంగు"</item>
+    <item msgid="5799049811524553967">"నీలి నేపథ్యంలో పసుపు రంగు"</item>
+    <item msgid="3673930830658169860">"అనుకూలం"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"PPTP VPN"</item>
     <item msgid="1349760781118368659">"పూర్వ-భాగస్వామ్య కీలతో L2TP/IPSec VPN"</item>
@@ -288,15 +410,32 @@
     <item msgid="2958623927055120839">"ఏదీ వద్దు"</item>
     <item msgid="1157046369795346308">"మాన్యువల్"</item>
   </string-array>
-    <!-- no translation found for vpn_states:4 (9135049670787351881) -->
+  <string-array name="vpn_states">
+    <item msgid="5408915841694583740">"డిస్‌కనెక్ట్ చేయబడింది"</item>
+    <item msgid="8754480102834556765">"ప్రారంభిస్తోంది..."</item>
+    <item msgid="3351334355574270250">"కనెక్ట్ చేస్తోంది..."</item>
+    <item msgid="8303882153995748352">"కనెక్ట్ అయింది"</item>
+    <item msgid="9135049670787351881">"గడువు ముగింపు"</item>
+    <item msgid="2124868417182583926">"విఫలమైంది"</item>
+  </string-array>
   <string-array name="security_settings_premium_sms_values">
     <item msgid="1164265643455394443">"అడగండి"</item>
     <item msgid="7718817231348607934">"ఎప్పటికీ అనుమతించవద్దు"</item>
     <item msgid="8184570120217958741">"ఎల్లప్పుడూ అనుమతించు"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"సాధారణం"</item>
+    <item msgid="5101233285497327432">"మధ్యస్థం"</item>
+    <item msgid="1555861583162930714">"తక్కువ"</item>
+    <item msgid="1719683776264798117">"క్లిష్టం"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"సాధారణం"</item>
+    <item msgid="6107138933849816768">"మధ్యస్థం"</item>
+    <item msgid="182695359839047859">"తక్కువ"</item>
+    <item msgid="8577246509202964244">"క్లిష్టం"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"స్థిరం"</item>
     <item msgid="167418068739176448">"ప్రముఖ కార్యకలాపం"</item>
@@ -338,7 +477,7 @@
     <item msgid="1008268820118852416">"గణించబడనిదిగా పరిగణించండి"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
-    <item msgid="6545683814310036454">"యాదృచ్ఛిక MAC అడ్రస్‌ని ఉపయోగించండి (డిఫాల్ట్)"</item>
+    <item msgid="6545683814310036454">"ర్యాండ‌మ్‌గా రూపొందించిన MAC అడ్రస్‌ను ఉపయోగించండి (ఆటోమేటిక్‌)"</item>
     <item msgid="214234417308375326">"MAC పరికరాన్ని ఉపయోగించండి"</item>
   </string-array>
   <string-array name="wifi_hidden_entries">
diff --git a/tests/CarDeveloperOptions/res/values-te/config.xml b/tests/CarDeveloperOptions/res/values-te/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-te/config.xml
+++ b/tests/CarDeveloperOptions/res/values-te/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-te/strings.xml b/tests/CarDeveloperOptions/res/values-te/strings.xml
index 51bb24d..6e54dda 100644
--- a/tests/CarDeveloperOptions/res/values-te/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-te/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"స్క్రీన్‌పై ఉండే వచనాన్ని చిన్నదిగా లేదా పెద్దదిగా చేస్తుంది."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"చిన్నదిగా చేస్తుంది"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"పెద్దదిగా చేస్తుంది"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"నమూనా వచనం"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"ది వండర్‌ఫుల్ విజర్డ్ ఆఫ్ ఆజ్"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"అధ్యాయం 11: ది వండర్‌ఫుల్ ఎమరాల్డ్ సిటీ ఆఫ్ ఆజ్"</string>
@@ -128,7 +127,7 @@
     <string name="bluetooth_notif_title" msgid="5090288898529286011">"జత చేయడానికి అభ్యర్థన"</string>
     <string name="bluetooth_notif_message" msgid="6612367890895077938">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>తో జత చేయడానికి నొక్కండి."</string>
     <string name="bluetooth_show_received_files" msgid="5060846395852236652">"స్వీకరించిన ఫైల్‌లు"</string>
-    <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"బ్లూటూత్ ద్వారా ఫైల్‌లు స్వీకరించబడ్డాయి"</string>
+    <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"బ్లూటూత్ ద్వారా అందుకున్న ఫైల్‌లు"</string>
     <string name="device_picker" msgid="8345264486071697705">"బ్లూటూత్ పరికరాన్ని ఎంచుకోండి"</string>
     <string name="bluetooth_ask_enablement" msgid="8716802066127746062">"<xliff:g id="APP_NAME">%1$s</xliff:g> బ్లూటూత్‌ను ఆన్ చేయాలనుకుంటోంది"</string>
     <string name="bluetooth_ask_disablement" msgid="7125319551097350783">"<xliff:g id="APP_NAME">%1$s</xliff:g> బ్లూటూత్‌ను ఆఫ్ చేయాలనుకుంటోంది"</string>
@@ -208,7 +207,7 @@
     <string name="proxy_error_empty_port" msgid="8034561724923076215">"మీరు పోర్ట్ ఫీల్డ్‌ను పూర్తి చేయాల్సి ఉంటుంది."</string>
     <string name="proxy_error_empty_host_set_port" msgid="8471455809508588255">"హోస్ట్ ఫీల్డ్ ఖాళీగా ఉంటే పోర్ట్ ఫీల్డ్ తప్పనిసరిగా ఖాళీగా ఉండాలి."</string>
     <string name="proxy_error_invalid_port" msgid="4046559920586100637">"మీరు టైప్ చేసిన పోర్ట్ చెల్లదు."</string>
-    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"HTTP ప్రాక్సీని బ్రౌజరే ఉపయోగిస్తుంది, ఇతర అనువర్తనాల ఉపయోగించకపోవచ్చు."</string>
+    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"బ్రౌజ‌ర్, HTTP ప్రాక్సీని ఉపయోగిస్తుంది కానీ ఇతర యాప్‌లు ఉపయోగించకపోవచ్చు."</string>
     <string name="proxy_url_title" msgid="882042361706435904">"PAC URL: "</string>
     <string name="radio_info_dl_kbps" msgid="2903778264453410272">"DL బ్యాండ్‌విడ్త్ (kbps):"</string>
     <string name="radio_info_ul_kbps" msgid="3802245899811732716">"UL బ్యాండ్‌విడ్త్ (kbps):"</string>
@@ -354,7 +353,7 @@
     <string name="show_owner_info_on_lockscreen_label" msgid="4510756693837171575">"లాక్ స్క్రీన్‌లో యజమాని సమాచారాన్ని చూపు"</string>
     <string name="owner_info_settings_title" msgid="2537966178998339896">"లాక్ స్క్రీన్ సందేశం"</string>
     <string name="security_enable_widgets_title" msgid="1701510007926738088">"విడ్జెట్‌లను ప్రారంభించు"</string>
-    <string name="security_enable_widgets_disabled_summary" msgid="4408176087132339331">"నిర్వాహకులు నిలిపివేసారు"</string>
+    <string name="security_enable_widgets_disabled_summary" msgid="4408176087132339331">"అడ్మిన్ డిజేబుల్ చేశారు"</string>
     <string name="lockdown_settings_title" msgid="4534779922580115990">"అన్నీ లాక్ చేయి ఎంపికను చూపు"</string>
     <string name="lockdown_settings_summary" msgid="7270756909878256174">"Smart Lock, వేలిముద్ర అన్‌లాకింగ్ మరియు లాక్ స్క్రీన్‌లో నోటిఫికేషన్‌లను ఆఫ్ చేసే పవర్ బటన్ ఎంపికను ప్రదర్శించు"</string>
     <string name="trust_agents_extend_unlock_title" msgid="3582017561316089951">"విశ్వ‌స‌నీయ ఏజెంట్లు మాత్ర‌మే అన్‌లాక్‌ను పొడిగిస్తాయి"</string>
@@ -388,7 +387,7 @@
     <string name="security_settings_summary" msgid="5210109100643223686">"నా స్థానాన్ని, స్క్రీన్ అన్‌లాక్‌ను, సిమ్ కార్డు లాక్‌ను, ఆధారాల నిల్వ లాక్‌ను సెట్ చేయి"</string>
     <string name="cdma_security_settings_summary" msgid="1783066617800041869">"నా స్థానాన్ని, స్క్రీన్ అన్‌లాక్‌ను, ఆధారాల నిల్వ లాక్‌ను సెట్ చేయండి"</string>
     <string name="security_passwords_title" msgid="6853942836045862315">"గోప్యత"</string>
-    <string name="disabled_by_administrator_summary" msgid="6099821045360491127">"నిర్వాహకులు నిలిపివేసారు"</string>
+    <string name="disabled_by_administrator_summary" msgid="6099821045360491127">"అడ్మిన్ డిజేబుల్ చేశారు"</string>
     <string name="security_status_title" msgid="1261960357751754428">"భద్రత స్థితి"</string>
     <string name="security_dashboard_summary_face" msgid="2536136110153593745">"స్క్రీన్ లాక్, ముఖం అన్‌లాక్"</string>
     <string name="security_dashboard_summary" msgid="4048877125766167227">"స్క్రీన్ లాక్, వేలిముద్ర"</string>
@@ -414,7 +413,7 @@
     <string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"నమోదు పూర్తి కాలేదు"</string>
     <string name="security_settings_face_enroll_dialog_ok" msgid="1078348922734845090">"సరే"</string>
     <string name="security_settings_face_enroll_error_timeout_dialog_message" msgid="4917894418448325405">"ముఖ నమోదు సమయ పరిమితి చేరుకుంది. మళ్లీ ప్రయత్నించండి."</string>
-    <string name="security_settings_face_enroll_error_generic_dialog_message" msgid="5160473187142616862">"ముఖ నమోదు పని చేయలేదు."</string>
+    <string name="security_settings_face_enroll_error_generic_dialog_message" msgid="5160473187142616862">"ఫేస్ నమోదు పని చేయలేదు."</string>
     <string name="security_settings_face_enroll_finish_title" msgid="6800717857394410769">"మొత్తం పూర్తయింది. చూడడానికి భాగుంది."</string>
     <string name="security_settings_face_enroll_done" msgid="5409739233373490971">"పూర్తయింది"</string>
     <string name="security_settings_face_settings_use_face_category" msgid="1586532139528115416">"ముఖాన్ని వాడండి"</string>
@@ -668,7 +667,6 @@
       <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> కంటే తక్కువ అంకెలు తప్పక ఉండాలి</item>
       <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> కంటే తక్కువ అంకె తప్పక ఉండాలి</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"తప్పనిసరిగా 0-9 అంకెలను మాత్రమే కలిగి ఉండాలి"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"ఇటీవలి పిన్‌ని ఉపయోగించడానికి డివైజ్ నిర్వాహకులు అనుమతించరు"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"సాధారణ PINలను మా IT నిర్వాహకుడు బ్లాక్ చేసారు. వేరే PINని ప్రయత్నించండి."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"ఇందులో చెల్లని అక్షరం ఉండకూడదు"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">తప్పనిసరిగా కనీసం <xliff:g id="COUNT">%d</xliff:g> వర్ణమాల యేతర అక్షరాలను కలిగి ఉండాలి</item>
       <item quantity="one">తప్పనిసరిగా కనీసం 1 వర్ణమాల యేతర అక్షరాన్ని కలిగి ఉండాలి</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">తప్పనిసరిగా కనీసం <xliff:g id="COUNT">%d</xliff:g> సంఖ్యేతర అక్షరాలను కలిగి ఉండాలి</item>
+      <item quantity="one">తప్పనిసరిగా కనీసం 1 సంఖ్యేతర అక్షరాన్ని కలిగి ఉండాలి</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"ఇటీవలి పాస్‌వర్డ్‌ను ఉపయోగించడానికి పరికర నిర్వాహకులు అనుమతించరు"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"సాధారణ పాస్‌వర్డ్‌లను మా IT నిర్వాహకుడు బ్లాక్ చేసారు. వేరే పాస్‌వర్డ్‌ని ప్రయత్నించండి."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"అంకెలను ఆరోహణ, అవరోహణ క్రమంలో లేదా ఒకే అంకెను వరుసగా పునరావృతంగా ఉపయోగించకూడదు"</string>
@@ -916,7 +918,7 @@
     <string name="please_select_phase2" msgid="5848080896810435677">"2వ దశ ప్రామాణీకరణ"</string>
     <string name="wifi_eap_ca_cert" msgid="1496395241849383785">"CA సర్టిఫికెట్"</string>
     <string name="wifi_eap_domain" msgid="3298302320003640130">"డొమైన్"</string>
-    <string name="wifi_eap_user_cert" msgid="6786839531765719173">"వినియోగదారు సర్టిఫికెట్"</string>
+    <string name="wifi_eap_user_cert" msgid="6786839531765719173">"యూజర్ సర్టిఫికెట్"</string>
     <string name="wifi_eap_identity" msgid="5280457017705738773">"గుర్తింపు"</string>
     <string name="wifi_eap_anonymous" msgid="6352344972490839958">"అనామక గుర్తింపు"</string>
     <string name="wifi_password" msgid="6942983531275177771">"పాస్‌వర్డ్"</string>
@@ -1037,7 +1039,7 @@
     <string name="wifi_dns1" msgid="5250809981658822505">"DNS 1"</string>
     <string name="wifi_dns2" msgid="1905876166783761641">"DNS 2"</string>
     <string name="wifi_gateway" msgid="7455334454444443397">"గేట్‌వే"</string>
-    <string name="wifi_network_prefix_length" msgid="1941206966133010633">"నెట్‌వర్క్ ఆదిప్రత్యయం పొడవు"</string>
+    <string name="wifi_network_prefix_length" msgid="1941206966133010633">"నెట్‌వర్క్ ప్రిఫిక్స్ పొడవు"</string>
     <string name="wifi_p2p_settings_title" msgid="3213180637906683308">"Wi‑Fi Direct"</string>
     <string name="wifi_p2p_device_info" msgid="4717490498956029237">"పరికర సమాచారం"</string>
     <string name="wifi_p2p_persist_network" msgid="1110453878886476660">"ఈ కనెక్షన్‌ను గుర్తుంచుకో"</string>
@@ -1067,7 +1069,7 @@
     <string name="wifi_hotspot_ap_band_title" msgid="3485744480410441949">"AP బ్యాండ్"</string>
     <string name="wifi_hotspot_footer_info_regular" msgid="3876006922622827363">"మీ ఇతర పరికరాల కోసం Wi-Fi నెట్‌వర్క్‌ని సృష్టించడానికి హాట్‌స్పాట్‌ని ఉపయోగించండి. హాట్‌స్పాట్ అనేది మీ మొబైల్ డేటా కనెక్షన్‌ని ఉపయోగించి ఇంటర్నెట్‌ని అందిస్తుంది. అదనపు మొబైల్ డేటా ఛార్జీలు చెల్లించాల్సి రావచ్చు."</string>
     <string name="wifi_hotspot_footer_info_local_only" msgid="3339582350894639261">"యాప్‌లు సమీప పరికరాలతో కంటెంట్‌ని షేర్ చేయడం కోసం హాట్‌స్పాట్‌ని సృష్టించవచ్చు."</string>
-    <string name="wifi_hotspot_auto_off_title" msgid="7416022590415189590">"హాట్‌స్పాట్‌ని ఆటోమేటిక్‌గా ఆఫ్ చేయి"</string>
+    <string name="wifi_hotspot_auto_off_title" msgid="7416022590415189590">"హాట్‌స్పాట్‌ను ఆటోమేటిక్‌గా ఆఫ్ చేయి"</string>
     <string name="wifi_hotspot_auto_off_summary" msgid="3866769400624802105">"పరికరాలు ఏవీ కనెక్ట్ కాకపోతే Wi‑Fi హాట్‌స్పాట్‌ ఆఫ్ అవుతుంది"</string>
     <string name="wifi_tether_starting" msgid="7676952148471297900">"హాట్‌స్పాట్‌ను ప్రారంభిస్తోంది…"</string>
     <string name="wifi_tether_stopping" msgid="7478561853791953349">"హాట్‌స్పాట్‌ను ఆపివేస్తోంది…"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"మొబైల్"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Wi‑Fi అందుబాటులో లేకుంటే, మొబైల్ నెట్‌వర్క్‌ను ఉపయోగిస్తుంది"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"మొబైల్ నెట్‌వర్క్ అందుబాటులో లేకపోతే, Wi‑Fiని ఉపయోగించు"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Wi‑Fi ద్వారా కాల్ చేయగలరు. Wi‑Fiని కోల్పోతే, కాల్ ముగిసిపోతుంది."</string>
@@ -1564,7 +1569,7 @@
     <string name="menu_restore" msgid="3799288817317293115">"డిఫాల్ట్‌కు రీసెట్ చేయి"</string>
     <string name="restore_default_apn_completed" msgid="5671734152740058937">"డిఫాల్ట్ APN సెట్టింగ్‌లను రీసెట్ చేయడం పూర్తయింది."</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"రీసెట్ ఎంపికలు"</string>
-    <string name="reset_dashboard_summary" msgid="8778383341461126642">"నెట్‌వర్క్, యాప్‌లు లేదా పరికరాన్ని రీసెట్ చేయవచ్చు"</string>
+    <string name="reset_dashboard_summary" msgid="8778383341461126642">"నెట్‌వర్క్, యాప్‌లు లేదా డివైజ్‌ను రీసెట్ చేయవచ్చు"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"Wi-Fi, మొబైల్ &amp; బ్లూటూత్‌ని రీసెట్ చేయండి"</string>
     <string name="reset_network_desc" msgid="4982633363916261109">"ఇది అన్ని నెట్‌వర్క్ సెట్టింగ్‌లను రీసెట్ చేస్తుంది, వీటితో సహా:\n\n"<li>"Wi‑Fi"</li>\n<li>"మొబైల్ డేటా"</li>\n<li>"బ్లూటూత్"</li></string>
     <string name="reset_esim_title" msgid="7630781767040831893">"డౌన్‌లోడ్ చేసిన SIMలు తొలగించు"</string>
@@ -1642,7 +1647,7 @@
     <string name="mobile_insert_sim_card" msgid="7594550403454243732">"దయచేసి సిమ్ కార్డును చొప్పించి, పునఃప్రారంభించండి"</string>
     <string name="mobile_connect_to_internet" msgid="6031886097365170913">"దయచేసి ఇంటర్నెట్‌కు కనెక్ట్ చేయండి"</string>
     <string name="location_title" msgid="8664674161765477168">"నా స్థానం"</string>
-    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"కార్యాలయ ప్రొఫైల్ యొక్క స్థానం"</string>
+    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"ఆఫీస్ ప్రొఫైల్ కోసం లొకేషన్"</string>
     <string name="location_app_level_permissions" msgid="1298041503927632960">"యాప్ అనుమతి"</string>
     <string name="location_app_permission_summary_location_off" msgid="541372845344796336">"స్థానం ఆఫ్‌లో ఉంది"</string>
     <plurals name="location_app_permission_summary_location_on" formatted="false" msgid="7904821382328758218">
@@ -1651,7 +1656,7 @@
     </plurals>
     <string name="location_category_recent_location_access" msgid="286059523360285026">"ఇటీవలి స్థాన యాక్సెస్"</string>
     <string name="location_recent_location_access_view_details" msgid="2051602261436245905">"వివరాలను చూడండి"</string>
-    <string name="location_no_recent_apps" msgid="77502059586413278">"స్థానాన్ని ఇటీవల అనువర్తనాలు ఏవీ అభ్యర్థించలేదు"</string>
+    <string name="location_no_recent_apps" msgid="77502059586413278">"యాప్‌లు ఏవీ లొకేషన్‌ను ఇటీవల అభ్యర్థించలేదు"</string>
     <string name="location_no_recent_accesses" msgid="6289916310397279890">"యాప్‌లు ఏవీ స్థానాన్ని ఇటీవల యాక్సెస్ చేయలేదు"</string>
     <string name="location_high_battery_use" msgid="7177199869979522663">"అధిక బ్యాటరీ వినియోగం"</string>
     <string name="location_low_battery_use" msgid="5030448574501435888">"తక్కువ బ్యాటరీ వినియోగం"</string>
@@ -1690,7 +1695,7 @@
     <string name="terms_title" msgid="1804549588198223771">"నిబంధనలు మరియు షరతులు"</string>
     <string name="webview_license_title" msgid="8244960025549725051">"సిస్టమ్ వెబ్‌వ్యూ లైసెన్స్"</string>
     <string name="wallpaper_attributions" msgid="2941987966332943253">"వాల్‌పేపర్‌లు"</string>
-    <string name="wallpaper_attributions_values" msgid="4461979853894606323">"ఉపగ్రహ చిత్రాల ప్రదాతలు:\n©2014 CNES / Astrium, DigitalGlobe, Bluesky"</string>
+    <string name="wallpaper_attributions_values" msgid="4461979853894606323">"ఉపగ్రహ ఫోటోలను అందించినవారు:\n©2014 CNES / Astrium, DigitalGlobe, Bluesky"</string>
     <string name="settings_manual_activity_title" msgid="7599911755054286789">"మాన్యువల్"</string>
     <string name="settings_manual_activity_unavailable" msgid="4872502775018655343">"మాన్యువల్‌ను లోడ్ చేయడంలో సమస్య ఏర్పడింది."</string>
     <string name="settings_license_activity_title" msgid="1099045216283677608">"మూడవ పక్షం లైసెన్స్‌లు"</string>
@@ -1795,7 +1800,7 @@
     <string name="advanced_settings_summary" msgid="5912237062506771716">"మరిన్ని సెట్టింగ్‌ల ఎంపికలను ప్రారంభించు"</string>
     <string name="application_info_label" msgid="3886253474964599105">"యాప్ సమాచారం"</string>
     <string name="storage_label" msgid="1109537840103290384">"నిల్వ"</string>
-    <string name="auto_launch_label" msgid="47089737922907379">"డిఫాల్ట్‌గా తెరువు"</string>
+    <string name="auto_launch_label" msgid="47089737922907379">"ఆటోమేటిక్‌గా తెరువు"</string>
     <string name="auto_launch_label_generic" msgid="7865828543459493308">"డిఫాల్ట్‌లు"</string>
     <string name="screen_compatibility_label" msgid="3638271673726075815">"స్క్రీన్ అనుకూలత"</string>
     <string name="permissions_label" msgid="7341733648403464213">"అనుమతులు"</string>
@@ -2081,7 +2086,7 @@
     <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"మీరు చదవాల్సిన సందేశాలను స్క్రీన్‌పై తాత్కాలికంగా ఎంతసేపు చూపాలనేది ఎంచుకోవచ్చు.\n\nఈ సెట్టింగ్‌కు అన్ని యాప్‌లలో మద్దతు ఉండదు."</string>
     <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"మిమ్మల్ని ఏదో ఒక చర్యని తీసుకోమంటూ, తాత్కాలికంగా స్క్రీన్‌పై కనిపించే సందేశాలు ఎంతసేపు అలాగే ఉండాలనేది ఎంచుకోవచ్చు.\n\nఈ సెట్టింగ్‌కు అన్ని యాప్‌లలో మద్దతు ఉండదు."</string>
     <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"తాకి ఉంచాల్సిన సమయం"</string>
-    <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"వర్ణ విలోమం"</string>
+    <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"కలర్ మార్పిడి"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"పనితీరుపై ప్రభావం చూపవచ్చు"</string>
     <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"డ్వెల్ టైమింగ్"</string>
     <string name="accessibility_autoclick_description" msgid="5492414927846407499">"మీరు మౌస్‌ని ఉపయోగిస్తున్నట్లయితే, కర్సర్ నిర్దిష్ట సమయం పాటు కదలడం ఆగిపోయినప్పుడు అది ఆటోమేటిక్‌గా చర్య తీసుకునే విధంగా దానిని సెట్ చేయండి."</string>
@@ -2318,9 +2323,9 @@
     <string name="smart_battery_manager_title" msgid="5744035036663849515">"బ్యాటరీ మేనేజర్"</string>
     <string name="smart_battery_title" msgid="4919670408532804351">"యాప్‌లను ఆటోమేటిక్‌గా నిర్వహించండి"</string>
     <string name="smart_battery_summary" msgid="640027046471198174">"మీరు తరచుగా ఉపయోగించని యాప్‌ల కోసం బ్యాటరీని పరిమితం చేయండి"</string>
-    <string name="smart_battery_footer" product="default" msgid="3971715848890205632">"యాప్‌లు బ్యాటరీ శక్తిని హరిస్తున్నయని బ్యాటరీ మేనేజర్ గుర్తించినప్పుడు, ఈ యాప్‌లను పరిమితం చేసే ఎంపిక మీకు ఉంటుంది. పరిమితం చేయబడిన యాప్‌లు సరిగ్గా పనిచేయకపోవచ్చు మరియు నోటిఫికేషన్‌లు రావడానికి ఆలస్యం కావచ్చు."</string>
-    <string name="smart_battery_footer" product="tablet" msgid="3971715848890205632">"యాప్‌లు బ్యాటరీ శక్తిని హరిస్తున్నయని బ్యాటరీ మేనేజర్ గుర్తించినప్పుడు, ఈ యాప్‌లను పరిమితం చేసే ఎంపిక మీకు ఉంటుంది. పరిమితం చేయబడిన యాప్‌లు సరిగ్గా పనిచేయకపోవచ్చు మరియు నోటిఫికేషన్‌లు రావడానికి ఆలస్యం కావచ్చు."</string>
-    <string name="smart_battery_footer" product="device" msgid="3971715848890205632">"యాప్‌లు బ్యాటరీ శక్తిని హరిస్తున్నయని బ్యాటరీ మేనేజర్ గుర్తించినప్పుడు, ఈ యాప్‌లను పరిమితం చేసే ఎంపిక మీకు ఉంటుంది. పరిమితం చేయబడిన యాప్‌లు సరిగ్గా పనిచేయకపోవచ్చు మరియు నోటిఫికేషన్‌లు రావడానికి ఆలస్యం కావచ్చు."</string>
+    <string name="smart_battery_footer" product="default" msgid="3971715848890205632">"ఏవైనా యాప్‌లు బ్యాటరీని అధికంగా వాడుతున్నాయని బ్యాటరీ మేనేజర్ గుర్తించినప్పుడు, ఆ యాప్‌లను పరిమితం చేసే ఎంపిక మీకు ఉంటుంది. పరిమితం చేయబడిన యాప్‌లు సరిగ్గా పనిచేయకపోవచ్చు, వాటి నోటిఫికేషన్‌లు రావడానికి ఆలస్యం కావచ్చు."</string>
+    <string name="smart_battery_footer" product="tablet" msgid="3971715848890205632">"ఏవైనా యాప్‌లు బ్యాటరీని అధికంగా వాడుతున్నాయని బ్యాటరీ మేనేజర్ గుర్తించినప్పుడు, ఆ యాప్‌లను పరిమితం చేసే ఎంపిక మీకు ఉంటుంది. పరిమితం చేయబడిన యాప్‌లు సరిగ్గా పనిచేయకపోవచ్చు, వాటి నోటిఫికేషన్‌లు రావడానికి ఆలస్యం కావచ్చు."</string>
+    <string name="smart_battery_footer" product="device" msgid="3971715848890205632">"ఏవైనా యాప్‌లు బ్యాటరీని అధికంగా వాడుతున్నాయని బ్యాటరీ మేనేజర్ గుర్తించినప్పుడు, ఆ యాప్‌లను పరిమితం చేసే ఎంపిక మీకు ఉంటుంది. పరిమితం చేయబడిన యాప్‌లు సరిగ్గా పనిచేయకపోవచ్చు, వాటి నోటిఫికేషన్‌లు రావడానికి ఆలస్యం కావచ్చు."</string>
     <string name="restricted_app_title" msgid="4957644700640127606">"నియంత్రించబడిన యాప్‌లు"</string>
     <plurals name="restricted_app_summary" formatted="false" msgid="7609538735465186040">
       <item quantity="other">%1$d యాప్‌ల కోసం బ్యాటరీ వినియోగాన్ని పరిమితం చేయడం</item>
@@ -2571,7 +2576,7 @@
     <string name="sms_access_restriction_enabled" msgid="3006320256764718303">"SMS &amp; కాల్ లాగ్ యాక్సెస్‌ను పరిమితం చేయండి"</string>
     <string name="sms_access_restriction_enabled_summary" msgid="9011946580977780063">"కేవలం డిఫాల్ట్ ఫోన్ మరియు సందేశ యాప్‌లు మాత్రమే SMS &amp; లాగ్ అనుమతులను కలిగి ఉన్నాయి"</string>
     <string name="no_trust_agents" msgid="5757792915019113084">"విశ్వసనీయ ఏజెంట్‌లు అందుబాటులో లేరు"</string>
-    <string name="add_device_admin_msg" msgid="3573765823476931173">"పరికర నిర్వాహకుల యాప్‌ను యాక్టివేట్‌ చేయాలా?"</string>
+    <string name="add_device_admin_msg" msgid="3573765823476931173">"డివైజ్ నిర్వాహకుల యాప్‌ను యాక్టివేట్‌ చేయాలా?"</string>
     <string name="add_device_admin" msgid="1621152410207260584">"ఈ పరికరం నిర్వాహకుల యాప్‌ను యాక్టివేట్‌ చేయి"</string>
     <string name="device_admin_add_title" msgid="6097881332139146897">"పరికర నిర్వాహకులు"</string>
     <string name="device_admin_warning" msgid="4421817419326480449">"ఈ \'నిర్వాహకుల యాప్‌\'ను యాక్టివేట్‌ చేస్తే, కింది చర్యలను చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> యాప్ అనుమతించబడుతుంది:"</string>
@@ -2665,8 +2670,8 @@
     <string name="data_usage_menu_sim_cards" msgid="8508154611676507088">"సిమ్ కార్డులు"</string>
     <string name="data_usage_cellular_data_summary" msgid="9162777397135709280">"పరిమితి చేరు. పాజ్ చేయబ."</string>
     <string name="account_settings_menu_auto_sync" msgid="2673669556006027506">"డేటా స్వీయ-సమకాలీకరణ"</string>
-    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"వ్యక్తిగత డేటాను స్వయంచాలకంగా సమకాలీకరించు"</string>
-    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"కార్యాలయ డేటాను స్వయంచాలకంగా సమకాలీకరించు"</string>
+    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"వ్యక్తిగత డేటా ఆటో-సింక్"</string>
+    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"ఆఫీస్ డేటాను ఆటో-సింక్ చేయి"</string>
     <string name="data_usage_change_cycle" msgid="447761920472170031">"సైకిల్‌ను మార్చు…"</string>
     <string name="data_usage_pick_cycle_day" msgid="6319750879145917066">"డేటా వినియోగ సైకిల్‌ను రీసెట్ చేయాల్సిన నెలలోని రోజు:"</string>
     <string name="data_usage_empty" msgid="7981405723435034032">"ఈ వ్యవధిలో డేటాను ఏ అనువర్తనాలు ఉపయోగించలేదు."</string>
@@ -2865,7 +2870,7 @@
     <string name="user_add_user_item_title" msgid="6835385073795492410">"వినియోగదారు"</string>
     <string name="user_add_profile_item_title" msgid="4932743891449790664">"పరిమితం చేయబడిన ప్రొఫైల్"</string>
     <string name="user_add_user_title" msgid="2320897397066676472">"కొత్త వినియోగదారుని జోడించాలా?"</string>
-    <string name="user_add_user_message_long" msgid="686637203224195465">"అదనపు వినియోగదారులను సృష్టించడం ద్వారా మీరు ఈ పరికరాన్ని ఇతరులతో షేర్ చేయవచ్చు. ప్రతి వినియోగదారుకు వారికంటూ ప్రత్యేక స్థలం ఉంటుంది, వారు ఆ స్థలాన్ని యాప్‌లు, వాల్‌పేపర్ మొదలైనవాటితో అనుకూలీకరించవచ్చు. వినియోగదారులు ప్రతి ఒక్కరిపై ప్రభావం చూపే Wi‑Fi వంటి పరికర సెట్టింగ్‌లను కూడా సర్దుబాటు చేయవచ్చు.\n\nమీరు కొత్త వినియోగదారును జోడించినప్పుడు, ఆ వ్యక్తి వారికంటూ స్వంత స్థలం సెట్ చేసుకోవాలి.\n\nఏ వినియోగదారు అయినా మిగిలిన అందరు వినియోగదారుల కోసం యాప్‌లను అప్‌డేట్ చేయవచ్చు. యాక్సెస్ సామర్ధ్యం సెట్టింగ్‌లు మరియు సేవలు కొత్త వినియోగదారుకి బదిలీ కాకపోవచ్చు."</string>
+    <string name="user_add_user_message_long" msgid="686637203224195465">"అదనపు యూజర్‌లను సృష్టించడం ద్వారా మీరు ఈ దేవైజ్‌ను ఇతరులతో షేర్ చేయవచ్చు. ప్రతి యూజర్‌కు వారికంటూ ప్రత్యేక స్థలం ఉంటుంది, వారు ఆ స్థలాన్ని యాప్‌లు, వాల్‌పేపర్ మొదలైనవాటితో అనుకూలీకరించవచ్చు. యూజర్‌లు ప్రతి ఒక్కరిపై ప్రభావం చూపే Wi‑Fi వంటి పరికర సెట్టింగ్‌లను కూడా సర్దుబాటు చేయవచ్చు.\n\nమీరు కొత్త యూజర్‌ను జోడించినప్పుడు, ఆ వ్యక్తి వారికంటూ స్వంత స్థలం సెట్ చేసుకోవాలి.\n\nఏ యూజర్‌ అయినా మిగిలిన అందరు వినియోగదారుల కోసం యాప్‌లను అప్‌డేట్ చేయవచ్చు. యాక్సెస్ సామర్ధ్యం సెట్టింగ్‌లు మరియు సేవలు కొత్త యూజర్‌కి బదిలీ కాకపోవచ్చు."</string>
     <string name="user_add_user_message_short" msgid="1802594476285458254">"మీరు కొత్త వినియోగదారుని జోడించినప్పుడు, ఆ వ్యక్తి తన స్థలాన్ని సెటప్ చేసుకోవాలి.\n\nఏ వినియోగదారు అయినా మిగతా అందరు వినియోగదారుల కోసం యాప్‌లను అప్‌డేట్‌ చేయగలరు."</string>
     <string name="user_setup_dialog_title" msgid="6748950002206392396">"ఇప్పుడు వినియోగదారుని సెటప్ చేయాలా?"</string>
     <string name="user_setup_dialog_message" msgid="2988559933258353919">"పరికరాన్ని తీసుకోవడానికి వ్యక్తి అందుబాటులో ఉన్నారని నిర్ధారించుకొని, ఆపై వారికి నిల్వ స్థలాన్ని సెటప్ చేయండి"</string>
@@ -2877,7 +2882,7 @@
     <string name="user_cannot_add_accounts_message" msgid="5993561303748749097">"పరిమిత ప్రొఫైల్‌లు ఖాతాలను జోడించడం సాధ్యపడదు"</string>
     <string name="user_remove_user_menu" msgid="3505139157217459864">"ఈ పరికరం నుండి <xliff:g id="USER_NAME">%1$s</xliff:g>ని తొలగించు"</string>
     <string name="user_lockscreen_settings" msgid="3820813814848394568">"లాక్ స్క్రీన్ సెట్టింగ్‌లు"</string>
-    <string name="user_add_on_lockscreen_menu" msgid="5211604808199585774">"లాక్ స్క్రీన్ నుండి వినియోగదారులను జోడించండి"</string>
+    <string name="user_add_on_lockscreen_menu" msgid="5211604808199585774">"లాక్ స్క్రీన్ నుండి యూజ‌ర్‌ల‌ను జోడించండి"</string>
     <string name="user_new_user_name" msgid="3880395219777884838">"కొత్త వినియోగదారు"</string>
     <string name="user_new_profile_name" msgid="3074939718101489937">"కొత్త ప్రొఫైల్"</string>
     <string name="user_confirm_remove_self_title" msgid="6739480453680217543">"మిమ్మల్ని తొలగించాలా?"</string>
@@ -2905,7 +2910,7 @@
     <string name="user_enable_calling_and_sms_confirm_title" msgid="4153856398523366976">"ఫోన్ కాల్‌లు &amp; SMSను ఆన్ చేయాలా?"</string>
     <string name="user_enable_calling_and_sms_confirm_message" msgid="3278802798876095734">"కాల్, SMS చరిత్ర ఈ వినియోగదారుతో షేర్ చేయబడుతుంది."</string>
     <string name="emergency_info_title" msgid="1522609271881425375">"అత్యవసర సమాచారం"</string>
-    <string name="emergency_info_summary" msgid="7280464759837387342">"<xliff:g id="USER_NAME">%1$s</xliff:g> కోసం సమాచారం &amp; పరిచయాలు"</string>
+    <string name="emergency_info_summary" msgid="7280464759837387342">"<xliff:g id="USER_NAME">%1$s</xliff:g> సంబంధిత సమాచారం &amp; కాంటాక్ట్‌లు"</string>
     <string name="application_restrictions" msgid="6871981013736536763">"అనువర్తనాలు మరియు కంటెంట్‌ను అనుమతించండి"</string>
     <string name="apps_with_restrictions_header" msgid="8656739605673756176">"పరిమితులు గల అనువర్తనాలు"</string>
     <string name="apps_with_restrictions_settings_button" msgid="5065896213467171744">"అనువర్తన సెట్టిం. విస్తరింపజేయి"</string>
@@ -3036,7 +3041,7 @@
     <string name="connected_devices_dashboard_no_driving_mode_summary" msgid="3524409078596318803">"బ్లూటూత్, NFC"</string>
     <string name="connected_devices_dashboard_no_driving_mode_no_nfc_summary" msgid="7881286613528299400">"బ్లూటూత్"</string>
     <string name="app_and_notification_dashboard_title" msgid="8448096608058843730">"యాప్‌లు &amp; నోటిఫికేషన్‌లు"</string>
-    <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"అసిస్టెంట్, ఇటీవలి యాప్‌లు, డిఫాల్ట్ యాప్‌లు"</string>
+    <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"Assistant, ఇటీవలి యాప్‌లు, డిఫాల్ట్ యాప్‌లు"</string>
     <string name="notification_settings_work_profile" msgid="7190550347842400029">"కార్యాలయ ప్రొఫైల్‌లో ఉన్న యాప్‌లకు సంబంధించి నోటిఫికేషన్ యాక్సెస్ అందుబాటులో లేదు."</string>
     <string name="account_dashboard_title" msgid="4734300939532555885">"ఖాతాలు"</string>
     <string name="account_dashboard_default_summary" msgid="6822549669771936206">"ఖాతాలు జోడించబడలేదు"</string>
@@ -3377,7 +3382,7 @@
     <string name="vr_listener_security_warning_title" msgid="7019322246707645361">"<xliff:g id="SERVICE">%1$s</xliff:g> కోసం VR సేవ ప్రాప్యతను అనుమతించాలా?"</string>
     <string name="vr_listener_security_warning_summary" msgid="5093225583584522067">"మీరు వర్చువల్ రియాలిటీ మోడ్‌లో అనువర్తనాలను ఉపయోగిస్తున్నప్పుడు <xliff:g id="VR_LISTENER_NAME">%1$s</xliff:g> అమలు కాగలదు."</string>
     <string name="display_vr_pref_title" msgid="1088464812293416981">"పరికరం VRలో ఉన్నప్పుడు"</string>
-    <string name="display_vr_pref_low_persistence" msgid="3132583929174794245">"అస్పష్టతను తగ్గించు (సిఫార్సు చేయబడింది)"</string>
+    <string name="display_vr_pref_low_persistence" msgid="3132583929174794245">"బ్లర్ తగ్గించు (సిఫార్సు చేయబడింది)"</string>
     <string name="display_vr_pref_off" msgid="4681320968818852691">"ప్ర‌కాశంలో అస్థిర‌త‌ను త‌గ్గించు"</string>
     <string name="picture_in_picture_title" msgid="4960733106166035448">"చిత్రంలో చిత్రం"</string>
     <string name="picture_in_picture_empty_text" msgid="8664071475324685241">"చిత్రంలో చిత్రానికి మద్దతిచ్చే అనువర్తనాలు ఏవీ ఇన్‌స్టాల్ చేయబడలేదు"</string>
@@ -3585,7 +3590,7 @@
     <string name="imei_information_title" msgid="7666097743700170757">"IMEI సమాచారం"</string>
     <string name="imei_information_summary" msgid="716516316022275083">"IMEI సంబంధిత సమాచారం"</string>
     <string name="slot_number" msgid="785422579177068698">"(స్లాట్<xliff:g id="SLOT_NUM">%1$d</xliff:g>)"</string>
-    <string name="launch_by_default" msgid="6106985160202769725">"డిఫాల్ట్‌గా తెరువు"</string>
+    <string name="launch_by_default" msgid="6106985160202769725">"ఆటోమేటిక్‌గా తెరువు"</string>
     <string name="app_launch_domain_links_title" msgid="2987289657348349133">"లింక్‌లను తెరవడం"</string>
     <string name="app_launch_open_domain_urls_title" msgid="8595126859922391331">"మద్దతిచ్చే లింక్‌లను తెరవండి"</string>
     <string name="app_launch_open_domain_urls_summary" msgid="6803029846855502366">"అడగకుండానే తెరవాలి"</string>
@@ -3755,7 +3760,7 @@
     <string name="usb_summary_MIDI_power" msgid="7685597621357005180">"MIDI మరియు విద్యుత్తు శక్తి సరఫరా"</string>
     <string name="background_check_pref" msgid="664081406854758392">"బ్యాక్‌గ్రౌండ్ తనిఖీ"</string>
     <string name="background_check_title" msgid="4136736684290307970">"పూర్తి నేపథ్య యాక్సెస్"</string>
-    <string name="assist_access_context_title" msgid="2274614501747710439">"స్క్రీన్‌లోని వచనాన్ని ఉపయోగించండి"</string>
+    <string name="assist_access_context_title" msgid="2274614501747710439">"స్క్రీన్‌లోని టెక్స్ట్‌ను ఉపయోగించండి"</string>
     <string name="assist_access_context_summary" msgid="5867997494395842785">"స్క్రీన్ కంటెంట్‌లను వచన రూపంలో యాక్సెస్ చేయడానికి సహాయక యాప్‌ను అనుమతిస్తుంది"</string>
     <string name="assist_access_screenshot_title" msgid="1991014038776117688">"స్క్రీన్‌షాట్‌ను ఉపయోగించండి"</string>
     <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"స్క్రీన్ చిత్రాన్ని యాక్సెస్ చేయడానికి సహాయక యాప్‌ను అనుమతిస్తుంది"</string>
@@ -4236,7 +4241,7 @@
     <string name="storage_music_audio" msgid="3661289086715297149">"సంగీతం &amp; ఆడియో"</string>
     <string name="storage_games" msgid="7740038143749092373">"గేమ్‌లు"</string>
     <string name="storage_other_apps" msgid="3202407095387420842">"ఇతర యాప్‌లు"</string>
-    <string name="storage_files" msgid="2087824267937487880">"ఫైల్‌లు"</string>
+    <string name="storage_files" msgid="2087824267937487880">"ఫైల్స్"</string>
     <string name="storage_size_large_alternate" msgid="1317796542509105857">"<xliff:g id="NUMBER">^1</xliff:g>"<small>" "<font size="20">"<xliff:g id="UNIT">^2</xliff:g>"</font></small>""</string>
     <string name="storage_volume_total" msgid="5021484171514159913">"<xliff:g id="TOTAL">%1$s</xliff:g>లో ఉపయోగించబడింది"</string>
     <string name="storage_percent_full" msgid="6924662861545958442">"ఉపయోగించబడింది"</string>
@@ -4468,10 +4473,10 @@
     <string name="hwui_force_dark_title" msgid="3744825212652331461">"ఫోర్స్‌-డార్క్‌ను అధిగ‌మించ‌డం"</string>
     <string name="hwui_force_dark_summary" msgid="2051891908674765817">"ఫోర్స్‌-డార్క్ ఫీచ‌ర్‌ను అధిగ‌మించ‌డం ఎల్ల‌ప్పుడూ ఆన్‌లో ఉండాలి"</string>
     <string name="privacy_dashboard_title" msgid="8764930992456607513">"గోప్యత"</string>
-    <string name="privacy_dashboard_summary" msgid="7916431309860824945">"అనుమతులు, ఖాతా కార్యకలాపం, వ్యక్తిగత డేటా"</string>
+    <string name="privacy_dashboard_summary" msgid="7916431309860824945">"అనుమతులు, ఖాతా యాక్టివిటీ, వ్యక్తిగత డేటా"</string>
     <string name="contextual_card_dismiss_remove" msgid="1750420285615827309">"తీసివేయి"</string>
-    <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"ఉంచండి"</string>
-    <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"ఈ సూచనని తీసివేయలా?"</string>
+    <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"Keep"</string>
+    <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"ఈ సూచనని తీసేయాలా?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"సూచన తీసివేయబడింది"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"చర్యరద్దు"</string>
     <string name="low_storage_summary" msgid="4562224870189133400">"నిల్వ తక్కువగా ఉంది: <xliff:g id="PERCENTAGE">%1$s</xliff:g> వినియోగించబడింది - <xliff:g id="FREE_SPACE">%2$s</xliff:g> ఖాళీగా ఉంది"</string>
diff --git a/tests/CarDeveloperOptions/res/values-th/arrays.xml b/tests/CarDeveloperOptions/res/values-th/arrays.xml
index b0bf1de..5803dc8 100644
--- a/tests/CarDeveloperOptions/res/values-th/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-th/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"ทำงานในพื้นหลัง"</item>
     <item msgid="6423861043647911030">"ระดับเสียงการเข้าถึง"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"ตำแหน่ง"</item>
+    <item msgid="6656077694190491067">"ตำแหน่ง"</item>
+    <item msgid="8790228218278477369">"ตำแหน่ง"</item>
+    <item msgid="7836406246005211990">"สั่น"</item>
+    <item msgid="3951439024549922598">"อ่านรายชื่อติดต่อ"</item>
+    <item msgid="8802152411647068">"แก้ไขรายชื่อติดต่อ"</item>
+    <item msgid="229544934599698735">"อ่านประวัติการโทร"</item>
+    <item msgid="7396102294405899613">"แก้ไขประวัติการโทร"</item>
+    <item msgid="3597797992398484655">"อ่านปฏิทิน"</item>
+    <item msgid="2705975774250907343">"แก้ไขปฏิทิน"</item>
+    <item msgid="4668747371441932697">"ตำแหน่ง"</item>
+    <item msgid="1487578921720243646">"การแจ้งเตือนโพสต์"</item>
+    <item msgid="4636080349724146638">"ตำแหน่ง"</item>
+    <item msgid="673510900286463926">"โทรเข้าโทรศัพท์"</item>
+    <item msgid="542083422784609790">"อ่าน SMS/MMS"</item>
+    <item msgid="1033780373029588436">"เขียน SMS/MMS"</item>
+    <item msgid="5647111115517787488">"รับ SMS/MMS"</item>
+    <item msgid="8591105601108455893">"รับ SMS/MMS"</item>
+    <item msgid="7730995008517841903">"รับ SMS/MMS"</item>
+    <item msgid="2613033109026626086">"รับ SMS/MMS"</item>
+    <item msgid="3037159047591081136">"ส่ง SMS/MMS"</item>
+    <item msgid="4726682243833913568">"อ่าน SMS/MMS"</item>
+    <item msgid="6555678522277865572">"เขียน SMS/MMS"</item>
+    <item msgid="6981734935578130884">"แก้ไขการตั้งค่า"</item>
+    <item msgid="8705854389991425629">"วาดด้านบน"</item>
+    <item msgid="5861356020344153651">"เข้าถึงการแจ้งเตือน"</item>
+    <item msgid="78432174621628659">"กล้องถ่ายรูป"</item>
+    <item msgid="3986116419882154794">"บันทึกเสียง"</item>
+    <item msgid="4516840825756409490">"เล่นเสียง"</item>
+    <item msgid="6811712502798183957">"อ่านคลิปบอร์ด"</item>
+    <item msgid="2780369012602289114">"แก้ไขคลิปบอร์ด"</item>
+    <item msgid="2331359440170850868">"ปุ่มสื่อ"</item>
+    <item msgid="6133599737122751231">"โฟกัสอัตโนมัติ"</item>
+    <item msgid="6844485713404805301">"ระดับเสียงหลัก"</item>
+    <item msgid="1600379420669104929">"ระดับเสียงสนทนา"</item>
+    <item msgid="6296768210470214866">"ระดับเสียงเรียกเข้า"</item>
+    <item msgid="510690696071629241">"ระดับเสียงของสื่อ"</item>
+    <item msgid="406861638631430109">"ระดับเสียงปลุก"</item>
+    <item msgid="4715864795872233884">"ระดับเสียงของการแจ้งเตือน"</item>
+    <item msgid="2311478519251301183">"ระดับบลูทูธ"</item>
+    <item msgid="5133991377896747027">"ทำงานตลอดเวลา"</item>
+    <item msgid="2464189519136248621">"ตำแหน่ง"</item>
+    <item msgid="2062677934050803037">"ตำแหน่ง"</item>
+    <item msgid="1735171933192715957">"ดูสถิติการใช้งาน"</item>
+    <item msgid="1014093788778383554">"ปิด/เปิดเสียงไมโครโฟน"</item>
+    <item msgid="4199297950608622850">"แสดงข้อความโทสต์"</item>
+    <item msgid="2527962435313398821">"สื่อของโครงการ"</item>
+    <item msgid="5117506254221861929">"เปิดใช้งาน VPN"</item>
+    <item msgid="8291198322681891160">"เขียนวอลเปเปอร์"</item>
+    <item msgid="7106921284621230961">"สนับสนุนโครงสร้าง"</item>
+    <item msgid="4496533640894624799">"สนับสนุนภาพหน้าจอ"</item>
+    <item msgid="2598847264853993611">"อ่านสถานะโทรศัพท์"</item>
+    <item msgid="9215610846802973353">"เพิ่มข้อความเสียง"</item>
+    <item msgid="9186411956086478261">"ใช้ SIP"</item>
+    <item msgid="6884763100104539558">"โทรออก"</item>
+    <item msgid="125513972170580692">"ลายนิ้วมือ"</item>
+    <item msgid="2556071024281275619">"เซ็นเซอร์ร่างกาย"</item>
+    <item msgid="617168514928339387">"อ่านการส่งข้อมูลเตือนภัยทางมือถือ (CB)"</item>
+    <item msgid="7134693570516523585">"จำลองสถานที่"</item>
+    <item msgid="7224489175375229399">"อ่านพื้นที่เก็บข้อมูล"</item>
+    <item msgid="8472735063903258202">"เขียนพื้นที่เก็บข้อมูล"</item>
+    <item msgid="4069276819909595110">"เปิดหน้าจอ"</item>
+    <item msgid="1228338896751121025">"สร้างบัญชี"</item>
+    <item msgid="3181581793459233672">"ทำงานในพื้นหลัง"</item>
+    <item msgid="2340936043025374076">"ระดับเสียงการเข้าถึง"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"สั้น"</item>
     <item msgid="4816511817309094890">"ปานกลาง"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"ไม่อนุญาตเลย"</item>
     <item msgid="8184570120217958741">"อนุญาตเสมอ"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"ปกติ"</item>
+    <item msgid="5101233285497327432">"ปานกลาง"</item>
+    <item msgid="1555861583162930714">"ต่ำ"</item>
+    <item msgid="1719683776264798117">"วิกฤต"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"ปกติ"</item>
+    <item msgid="6107138933849816768">"ปานกลาง"</item>
+    <item msgid="182695359839047859">"ต่ำ"</item>
+    <item msgid="8577246509202964244">"วิกฤต"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"ต่อเนื่อง"</item>
     <item msgid="167418068739176448">"กิจกรรมแรก"</item>
diff --git a/tests/CarDeveloperOptions/res/values-th/config.xml b/tests/CarDeveloperOptions/res/values-th/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-th/config.xml
+++ b/tests/CarDeveloperOptions/res/values-th/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-th/strings.xml b/tests/CarDeveloperOptions/res/values-th/strings.xml
index eb3a613..7211a87 100644
--- a/tests/CarDeveloperOptions/res/values-th/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-th/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"ปรับขนาดข้อความบนหน้าจอให้เล็กลงหรือใหญ่ขึ้น"</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"ทำให้เล็กลง"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"ทำให้ใหญ่ขึ้น"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"ข้อความตัวอย่าง"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"พ่อมดมหัศจรรย์แห่งออซ"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"บทที่ 11: เมืองมรกตมหัศจรรย์แห่งออซ"</string>
@@ -356,7 +355,7 @@
     <string name="security_enable_widgets_title" msgid="1701510007926738088">"เปิดใช้งานวิดเจ็ต"</string>
     <string name="security_enable_widgets_disabled_summary" msgid="4408176087132339331">"ปิดใช้โดยผู้ดูแลระบบ"</string>
     <string name="lockdown_settings_title" msgid="4534779922580115990">"แสดงตัวเลือกการปิดล็อก"</string>
-    <string name="lockdown_settings_summary" msgid="7270756909878256174">"แสดงตัวเลือกปุ่มเปิด/ปิดที่จะปิด Smart Lock การปลดล็อกด้วยลายนิ้วมือ และการแจ้งเตือนในหน้าจอล็อก"</string>
+    <string name="lockdown_settings_summary" msgid="7270756909878256174">"แสดงตัวเลือกปุ่มเปิด/ปิดที่จะปิด Smart Lock, การปลดล็อกด้วยลายนิ้วมือ และการแจ้งเตือนในหน้าจอล็อก"</string>
     <string name="trust_agents_extend_unlock_title" msgid="3582017561316089951">"เอเจนต์ความน่าเชื่อถือขยายเฉพาะการปลดล็อก"</string>
     <string name="trust_agents_extend_unlock_summary" msgid="3543997596586078084">"หากเปิดใช้ เอเจนต์ความน่าเชื่อถือจะปลดล็อกอุปกรณ์ค้างไว้นานขึ้น แต่จะปลดล็อกอุปกรณ์ที่ล็อกอยู่ไม่ได้อีกต่อไป"</string>
     <string name="trust_lost_locks_screen_title" msgid="3094736590690459372">"หน้าจอล็อกเมื่อสภาพแวดล้อมไม่น่าเชื่อถือ"</string>
@@ -378,7 +377,7 @@
     <string name="location_settings_loading_app_permission_stats" msgid="7818169326621327628">"กำลังโหลด…"</string>
     <string name="account_settings_title" msgid="7870321267198486578">"บัญชี"</string>
     <string name="security_settings_title" msgid="8228075165942416425">"ความปลอดภัย"</string>
-    <string name="encryption_and_credential_settings_title" msgid="6911729638397745353">"การเข้ารหัสลับและข้อมูลรับรอง"</string>
+    <string name="encryption_and_credential_settings_title" msgid="6911729638397745353">"การเข้ารหัสและข้อมูลเข้าสู่ระบบ"</string>
     <string name="encryption_and_credential_settings_summary" product="default" msgid="468749700109808546">"โทรศัพท์ที่เข้ารหัส"</string>
     <string name="decryption_settings_summary" product="default" msgid="7401802133199522441">"โทรศัพท์ไม่ได้เข้ารหัส"</string>
     <string name="encryption_and_credential_settings_summary" product="tablet" msgid="8170667308598998791">"อุปกรณ์ที่เข้ารหัส"</string>
@@ -390,7 +389,7 @@
     <string name="security_passwords_title" msgid="6853942836045862315">"ความเป็นส่วนตัว"</string>
     <string name="disabled_by_administrator_summary" msgid="6099821045360491127">"ปิดใช้โดยผู้ดูแลระบบ"</string>
     <string name="security_status_title" msgid="1261960357751754428">"สถานะความปลอดภัย"</string>
-    <string name="security_dashboard_summary_face" msgid="2536136110153593745">"ล็อกหน้าจอ, Face Unlock"</string>
+    <string name="security_dashboard_summary_face" msgid="2536136110153593745">"ล็อกหน้าจอ, ปลดล็อกด้วยใบหน้า"</string>
     <string name="security_dashboard_summary" msgid="4048877125766167227">"ล็อกหน้าจอ ลายนิ้วมือ"</string>
     <string name="security_dashboard_summary_no_fingerprint" msgid="8861903321053490658">"ล็อกหน้าจอ"</string>
     <string name="security_settings_face_preference_summary" msgid="4437701024542221434">"เพิ่มใบหน้าแล้ว"</string>
@@ -427,7 +426,7 @@
     <string name="security_settings_face_settings_remove_face_data" msgid="2821359954483136239">"นำข้อมูลใบหน้าออก"</string>
     <string name="security_settings_face_settings_footer" msgid="4627175759990550715">"ใช้ใบหน้าของคุณเพื่อปลดล็อกอุปกรณ์และเข้าถึงแอปได้ "<annotation id="url">"ดูข้อมูลเพิ่มเติม"</annotation></string>
     <string name="security_settings_face_settings_remove_dialog_title" msgid="5675319895815271094">"ลบข้อมูลใบหน้าไหม"</string>
-    <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"ระบบจะลบข้อมูลที่ Face Unlock บันทึกไว้อย่างถาวรและปลอดภัย หลักจากที่นำออกแล้ว คุณจะต้องใช้ PIN รูปแบบ หรือรหัสผ่านเพื่อปลดล็อกโทรศัพท์ ลงชื่อเข้าใช้แอป และยืนยันการชำระเงิน"</string>
+    <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"ระบบจะลบข้อมูลที่การปลดล็อกด้วยใบหน้าบันทึกไว้อย่างถาวรและปลอดภัย หลักจากที่นำออกแล้ว คุณจะต้องใช้ PIN รูปแบบ หรือรหัสผ่านเพื่อปลดล็อกโทรศัพท์ ลงชื่อเข้าใช้แอป และยืนยันการชำระเงิน"</string>
     <string name="security_settings_fingerprint_preference_title" msgid="4177132225930582928">"ลายนิ้วมือ"</string>
     <string name="fingerprint_manage_category_title" msgid="1463406696801542090">"จัดการลายนิ้วมือ"</string>
     <string name="fingerprint_usage_category_title" msgid="7298369141954599706">"ใช้ลายนิ้วมือเพื่อ"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">ต้องมีตัวเลขไม่เกิน <xliff:g id="NUMBER_1">%d</xliff:g> ตัว</item>
       <item quantity="one">ต้องมีตัวเลขไม่เกิน <xliff:g id="NUMBER_0">%d</xliff:g> ตัว</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"ต้องมีตัวเลข 0-9 เท่านั้น"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"ผู้ดูแลระบบอุปกรณ์ไม่อนุญาตให้ใช้ PIN ที่เพิ่งใช้ไป"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"ผู้ดูแลระบบไอทีบล็อก PIN ที่ไม่รัดกุม ลอง PIN อื่น"</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"ต้องใช้อักขระที่ใช้ได้ทั้งหมด"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">ต้องมีอักขระที่ไม่ใช่ตัวอักษรอย่างน้อย <xliff:g id="COUNT">%d</xliff:g> ตัว</item>
       <item quantity="one">ต้องมีอักขระที่ไม่ใช่ตัวอักษรอย่างน้อย 1 ตัว</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">ต้องมีอักขระที่ไม่ใช่ตัวเลขอย่างน้อย <xliff:g id="COUNT">%d</xliff:g> ตัว</item>
+      <item quantity="one">ต้องมีอักขระที่ไม่ใช่ตัวเลขอย่างน้อย 1 ตัว</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"ผู้ดูแลระบบอุปกรณ์ไม่อนุญาตให้ใช้รหัสผ่านที่เพิ่งใช้ไป"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"ผู้ดูแลระบบไอทีบล็อกรหัสผ่านที่ไม่รัดกุม ลองรหัสผ่านอื่น"</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"ไม่อนุญาตให้เรียงจากน้อยไปมาก จากมากไปน้อย หรือเรียงลำดับตัวเลขที่ซ้ำกัน"</string>
@@ -878,7 +880,7 @@
     <string name="wifi_configure_settings_preference_summary_wakeup_off" msgid="286904094152909651">"ไม่เปิด Wi‑Fi อีกครั้งโดยอัตโนมัติ"</string>
     <string name="wifi_access_points" msgid="1647976498906871869">"เครือข่าย Wi-Fi"</string>
     <string name="wifi_menu_more_options" msgid="8318269834264035524">"ตัวเลือกอื่น"</string>
-    <string name="wifi_menu_p2p" msgid="4945665601551289791">"WiFi Direct"</string>
+    <string name="wifi_menu_p2p" msgid="4945665601551289791">"Wi-Fi Direct"</string>
     <string name="wifi_menu_scan" msgid="9082691677803181629">"สแกน"</string>
     <string name="wifi_menu_advanced" msgid="5984484498045511072">"ขั้นสูง"</string>
     <string name="wifi_menu_configure" msgid="52192491120701266">"กำหนดค่า"</string>
@@ -912,7 +914,7 @@
     <string name="wifi_ip_address" msgid="5572539114989914831">"ที่อยู่ IP"</string>
     <string name="passpoint_label" msgid="7429247462404128615">"บันทึกผ่านทาง"</string>
     <string name="passpoint_content" msgid="340527524510304327">"ข้อมูลรับรองของ <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_eap_method" msgid="3752116941487485859">"วิธีการ EAP"</string>
+    <string name="wifi_eap_method" msgid="3752116941487485859">"เมธอด EAP"</string>
     <string name="please_select_phase2" msgid="5848080896810435677">"การตรวจสอบสิทธิ์เฟส 2"</string>
     <string name="wifi_eap_ca_cert" msgid="1496395241849383785">"ใบรับรอง CA"</string>
     <string name="wifi_eap_domain" msgid="3298302320003640130">"โดเมน"</string>
@@ -933,13 +935,13 @@
     <string name="wifi_privacy_settings" msgid="4462092795794247809">"ความเป็นส่วนตัว"</string>
     <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"MAC แบบสุ่ม"</string>
     <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"เพิ่มอุปกรณ์"</string>
-    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"ถือให้โค้ด QR อยู่กลางช่องด้านล่างเพื่อเพิ่มอุปกรณ์ไปยัง “<xliff:g id="SSID">%1$s</xliff:g>”"</string>
+    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"ให้คิวอาร์โค้ดอยู่กลางช่องด้านล่างเพื่อเพิ่มอุปกรณ์ไปยัง “<xliff:g id="SSID">%1$s</xliff:g>”"</string>
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"สแกนคิวอาร์โค้ด"</string>
-    <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"ถือให้โค้ด QR อยู่กลางช่องด้านล่างเพื่อเชื่อมต่อไปยัง “<xliff:g id="SSID">%1$s</xliff:g>”"</string>
-    <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"เข้าร่วม Wi‑Fi โดยการสแกนคิวอาร์โค้ด"</string>
+    <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"ให้คิวอาร์โค้ดอยู่กลางช่องด้านล่างเพื่อเชื่อมต่อไปยัง “<xliff:g id="SSID">%1$s</xliff:g>”"</string>
+    <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"ร่วมใช้ Wi‑Fi โดยการสแกนคิวอาร์โค้ด"</string>
     <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"แชร์ Wi‑Fi"</string>
-    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"สแกนโค้ด QR นี้เพื่อเชื่อมต่อกับ “<xliff:g id="SSID">%1$s</xliff:g>” และแชร์รหัสผ่าน"</string>
-    <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"สแกนโค้ด QR นี้เพื่อเชื่อมต่อกับ “<xliff:g id="SSID">%1$s</xliff:g>”"</string>
+    <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"สแกนคิวอาร์โค้ดนี้เพื่อเชื่อมต่อกับ “<xliff:g id="SSID">%1$s</xliff:g>” และแชร์รหัสผ่าน"</string>
+    <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"สแกนคิวอาร์โค้ดนี้เพื่อเชื่อมต่อกับ “<xliff:g id="SSID">%1$s</xliff:g>”"</string>
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"อ่านโค้ด QR ไม่ได้ เล็งให้โค้ดอยู่กึ่งกลางอีกครั้งแล้วลองใหม่"</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"ลองอีกครั้ง หากยังแก้ปัญหาไม่ได้ ให้ติดต่อผู้ผลิตอุปกรณ์"</string>
     <string name="wifi_dpp_failure_not_compatible" msgid="4320027179973678283">"มีข้อผิดพลาดเกิดขึ้น"</string>
@@ -1038,7 +1040,7 @@
     <string name="wifi_dns2" msgid="1905876166783761641">"DNS 2"</string>
     <string name="wifi_gateway" msgid="7455334454444443397">"เกตเวย์"</string>
     <string name="wifi_network_prefix_length" msgid="1941206966133010633">"ความยาวรหัสนำเครือข่าย"</string>
-    <string name="wifi_p2p_settings_title" msgid="3213180637906683308">"WiFi Direct"</string>
+    <string name="wifi_p2p_settings_title" msgid="3213180637906683308">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_device_info" msgid="4717490498956029237">"ข้อมูลอุปกรณ์"</string>
     <string name="wifi_p2p_persist_network" msgid="1110453878886476660">"จำการเชื่อมต่อนี้"</string>
     <string name="wifi_p2p_menu_search" msgid="8207638860263805291">"ค้นหาอุปกรณ์"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"อินเทอร์เน็ตมือถือ"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"ใช้เครือข่ายมือถือหาก Wi-Fi ไม่พร้อมใช้งาน"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"ใช้ Wi‑Fi หากเครือข่ายมือถือไม่พร้อมใช้งาน"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"โทรผ่าน Wi-Fi สายจะตัดหากสัญญาณ Wi‑Fi ขาดหาย"</string>
@@ -1210,7 +1215,7 @@
     <string name="night_display_auto_mode_title" msgid="8493573087102481588">"กำหนดเวลา"</string>
     <string name="night_display_auto_mode_never" msgid="2897444637217807088">"ไม่มี"</string>
     <string name="night_display_auto_mode_custom" msgid="1400891076453963151">"เปิดในเวลาที่กำหนด"</string>
-    <string name="night_display_auto_mode_twilight" msgid="4000162110017520674">"เปิดตั้งแต่อาทิตย์ตกจนขึ้น"</string>
+    <string name="night_display_auto_mode_twilight" msgid="4000162110017520674">"เปิดตั้งแต่พระอาทิตย์ตกจนขึ้น"</string>
     <string name="night_display_start_time_title" msgid="1069255169673371077">"เวลาเริ่มต้น"</string>
     <string name="night_display_end_time_title" msgid="2760793157124245911">"เวลาสิ้นสุด"</string>
     <string name="night_display_status_title" msgid="1727020934735770319">"สถานะ"</string>
@@ -1241,7 +1246,7 @@
     <string name="wallpaper_suggestion_summary" msgid="4247262938988875842">"ปรับเปลี่ยนหน้าจอในแบบของคุณ"</string>
     <string name="wallpaper_settings_fragment_title" msgid="1503701065297188901">"เลือกวอลเปเปอร์จาก"</string>
     <string name="screensaver_settings_title" msgid="7720091234133721021">"โปรแกรมรักษาหน้าจอ"</string>
-    <string name="screensaver_settings_summary_either_long" msgid="6078038506795498288">"ขณะชาร์จหรือเสียบกับแท่นชาร์จ"</string>
+    <string name="screensaver_settings_summary_either_long" msgid="6078038506795498288">"ขณะชาร์จหรือวางอยู่บนแท่นชาร์จ"</string>
     <string name="screensaver_settings_summary_either_short" msgid="2453772128682850053">"แบบใดก็ได้"</string>
     <string name="screensaver_settings_summary_sleep" msgid="6097363596749362692">"ขณะที่ชาร์จ"</string>
     <string name="screensaver_settings_summary_dock" msgid="6297808146601570196">"ขณะวางอยู่บนแท่นชาร์จ"</string>
@@ -1332,7 +1337,7 @@
     <string name="status_number_sim_slot" product="tablet" msgid="4518232285651165459">"MDN (ช่องซิม %1$d)"</string>
     <string name="status_number_sim_slot" product="default" msgid="3660851494421332328">"หมายเลขโทรศัพท์ (ช่องซิม %1$d)"</string>
     <string name="status_number_sim_status" product="tablet" msgid="8069693515860290952">"MDN ในซิม"</string>
-    <string name="status_number_sim_status" product="default" msgid="6602562692270457610">"หมายเลขโทรศัพท์ในซิม"</string>
+    <string name="status_number_sim_status" product="default" msgid="6602562692270457610">"หมายเลขโทรศัพท์ของซิม"</string>
     <string name="status_min_number" msgid="8346889546673707777">"นาที"</string>
     <string name="status_msid_number" msgid="7808175928664357661">"MSID"</string>
     <string name="status_prl_version" msgid="5634561205739199042">"รุ่น PRL"</string>
@@ -1547,7 +1552,7 @@
     <string name="carrier_enabled" msgid="1819916725305365581">"เปิด/ปิดใช้งาน APN"</string>
     <string name="carrier_enabled_summaryOn" msgid="6219221535461945771">"เปิดใช้งาน APN แล้ว"</string>
     <string name="carrier_enabled_summaryOff" msgid="4093019532796386622">"ปิดใช้งาน APN แล้ว"</string>
-    <string name="bearer" msgid="4378444317087536401">"ผู้ถือ"</string>
+    <string name="bearer" msgid="4378444317087536401">"Bearer"</string>
     <string name="mvno_type" msgid="3150755279048149624">"ประเภท MVNO"</string>
     <string name="mvno_match_data" msgid="629287305803195245">"ค่า MVNO"</string>
     <string name="menu_delete" msgid="8646081395424055735">"ลบ APN"</string>
@@ -1565,8 +1570,8 @@
     <string name="restore_default_apn_completed" msgid="5671734152740058937">"รีเซ็ตการตั้งค่า APN กลับเป็นค่าเริ่มต้นเรียบร้อยแล้ว"</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"ตัวเลือกการรีเซ็ต"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"สามารถรีเซ็ตเครือข่าย แอป หรืออุปกรณ์ได้"</string>
-    <string name="reset_network_title" msgid="8944059136930806211">"รีเซ็ต Wi-Fi, เน็ตมือถือ และบลูทูธ"</string>
-    <string name="reset_network_desc" msgid="4982633363916261109">"การดำเนินการนี้จะรีเซ็ตการตั้งค่าเครือข่ายทั้งหมด รวมถึง:\n\n"<li>"Wi‑Fi"</li>\n<li>"อินเทอร์เน็ตมือถือ"</li>\n<li>"บลูทูธ"</li></string>
+    <string name="reset_network_title" msgid="8944059136930806211">"รีเซ็ต Wi-Fi เน็ตมือถือ และบลูทูธ"</string>
+    <string name="reset_network_desc" msgid="4982633363916261109">"การดำเนินการนี้จะรีเซ็ตการตั้งค่าเครือข่ายทั้งหมด ได้แก่\n\n"<li>"Wi‑Fi"</li>\n<li>"อินเทอร์เน็ตมือถือ"</li>\n<li>"บลูทูธ"</li></string>
     <string name="reset_esim_title" msgid="7630781767040831893">"ลบซิมที่ดาวน์โหลด"</string>
     <string name="reset_esim_desc" msgid="433226911566802">"โปรดติดต่อผู้ให้บริการเพื่อดาวน์โหลดซิมทดแทน การดำเนินการนี้จะไม่ยกเลิกแพ็กเกจอินเทอร์เน็ตมือถือของคุณ"</string>
     <string name="reset_network_button_text" msgid="4293271046867912819">"รีเซ็ตการตั้งค่า"</string>
@@ -1642,7 +1647,7 @@
     <string name="mobile_insert_sim_card" msgid="7594550403454243732">"โปรดใส่ซิมการ์ดและรีสตาร์ท"</string>
     <string name="mobile_connect_to_internet" msgid="6031886097365170913">"โปรดเชื่อมต่ออินเทอร์เน็ต"</string>
     <string name="location_title" msgid="8664674161765477168">"ตำแหน่งของฉัน"</string>
-    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"สถานที่สำหรับโปรไฟล์งาน"</string>
+    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"ตำแหน่งสำหรับโปรไฟล์งาน"</string>
     <string name="location_app_level_permissions" msgid="1298041503927632960">"สิทธิ์ของแอป"</string>
     <string name="location_app_permission_summary_location_off" msgid="541372845344796336">"ตำแหน่งปิดอยู่"</string>
     <plurals name="location_app_permission_summary_location_on" formatted="false" msgid="7904821382328758218">
@@ -1651,7 +1656,7 @@
     </plurals>
     <string name="location_category_recent_location_access" msgid="286059523360285026">"การเข้าถึงตำแหน่งล่าสุด"</string>
     <string name="location_recent_location_access_view_details" msgid="2051602261436245905">"ดูรายละเอียด"</string>
-    <string name="location_no_recent_apps" msgid="77502059586413278">"ไม่มีแอปใดทำการขอตำแหน่งเมื่อเร็วๆ นี้"</string>
+    <string name="location_no_recent_apps" msgid="77502059586413278">"ไม่มีแอปใดขอตำแหน่งเมื่อเร็วๆ นี้"</string>
     <string name="location_no_recent_accesses" msgid="6289916310397279890">"ไม่มีแอปที่เข้าถึงตำแหน่งเมื่อเร็วๆ นี้"</string>
     <string name="location_high_battery_use" msgid="7177199869979522663">"ใช้แบตเตอรี่มาก"</string>
     <string name="location_low_battery_use" msgid="5030448574501435888">"ใช้แบตเตอรี่น้อย"</string>
@@ -2033,7 +2038,7 @@
     <string name="accessibility_settings_title" msgid="1687226556576913576">"การตั้งค่าการเข้าถึง"</string>
     <string name="accessibility_settings_summary" msgid="5742379519336396561">"โปรแกรมอ่านหน้าจอ การแสดงผล ส่วนควบคุมการโต้ตอบ"</string>
     <string name="vision_settings_title" msgid="7315352351051423944">"การตั้งค่าการมองเห็น"</string>
-    <string name="vision_settings_description" msgid="3476589459009287332">"คุณสามารถปรับแต่งอุปกรณ์นี้ให้ตรงกับความต้องการของคุณ และเปลี่ยนฟีเจอร์การเข้าถึงเหล่านี้ได้ภายหลังในการตั้งค่า"</string>
+    <string name="vision_settings_description" msgid="3476589459009287332">"คุณปรับแต่งอุปกรณ์นี้ให้ตรงกับความต้องการได้ และเปลี่ยนฟีเจอร์การช่วยเหลือพิเศษเหล่านี้ได้ภายหลังในการตั้งค่า"</string>
     <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"เปลี่ยนขนาดแบบอักษร"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"โปรแกรมอ่านหน้าจอ"</string>
     <string name="audio_and_captions_category_title" msgid="6140472938769619212">"เสียงและข้อความบนหน้าจอ"</string>
@@ -2043,7 +2048,7 @@
     <string name="experimental_category_title" msgid="3797000069740110717">"ทดสอบ"</string>
     <string name="feature_flags_dashboard_title" msgid="3153034144122754381">"แฟล็กฟีเจอร์"</string>
     <string name="talkback_title" msgid="3717960404234260050">"TalkBack"</string>
-    <string name="talkback_summary" msgid="6602857105831641574">"โปรแกรมอ่านหน้าจอที่ใช้สำหรับคนตาบอดหรือผู้มีสายตาบกพร่อง"</string>
+    <string name="talkback_summary" msgid="6602857105831641574">"โปรแกรมอ่านหน้าจอที่ใช้สำหรับคนตาบอดหรือผู้มีสายตาบกพร่องเป็นหลัก"</string>
     <string name="select_to_speak_summary" msgid="7514180457557735421">"แตะรายการบนหน้าจอเพื่อฟังการอ่านออกเสียง"</string>
     <string name="accessibility_captioning_title" msgid="5878371993023439642">"คำบรรยาย"</string>
     <string name="accessibility_screen_magnification_title" msgid="7250949681883917360">"การขยาย"</string>
@@ -2083,7 +2088,7 @@
     <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"การหน่วงเวลาด้วยการแตะค้างไว้"</string>
     <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"การกลับสี"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"อาจส่งผลกระทบต่อประสิทธิภาพ"</string>
-    <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"ระยะเวลาที่ไม่ขยับเมาส์"</string>
+    <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"เวลาที่ไม่มีการขยับเมาส์"</string>
     <string name="accessibility_autoclick_description" msgid="5492414927846407499">"หากใช้เมาส์อยู่ คุณตั้งค่าเคอร์เซอร์ให้ดำเนินการโดยอัตโนมัติเมื่อเมาส์หยุดเคลื่อนที่ครู่หนึ่งได้"</string>
     <string name="accessibility_autoclick_delay_preference_title" msgid="8303022510942147049">"หน่วงเวลาก่อนคลิก"</string>
     <string name="accessibility_vibration_settings_title" msgid="1902649657883159406">"การสั่น"</string>
@@ -2094,15 +2099,15 @@
     <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"ใช้การแก้สี"</string>
     <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"ใช้คำบรรยาย"</string>
     <string name="accessibility_hearingaid_instruction_continue_button" msgid="4650111296711466691">"ต่อไป"</string>
-    <string name="accessibility_hearingaid_title" msgid="3700978781235124891">"เครื่องช่วยการได้ยิน"</string>
-    <string name="accessibility_hearingaid_not_connected_summary" msgid="634573930469952213">"ไม่ได้เชื่อมต่อเครื่องช่วยการได้ยิน"</string>
-    <string name="accessibility_hearingaid_adding_summary" msgid="4139031880828714300">"เพิ่มเครื่องช่วยการได้ยิน"</string>
-    <string name="accessibility_hearingaid_pair_instructions_first_message" msgid="2671518890909750740">"หากต้องการจับคู่กับเครื่องช่วยการได้ยิน ให้ค้นหาและแตะอุปกรณ์ในหน้าจอถัดไป"</string>
-    <string name="accessibility_hearingaid_pair_instructions_second_message" msgid="1584538735488464991">"ตรวจสอบว่าเครื่องช่วยการได้ยินอยู่ในโหมดการจับคู่"</string>
+    <string name="accessibility_hearingaid_title" msgid="3700978781235124891">"เครื่องช่วยฟัง"</string>
+    <string name="accessibility_hearingaid_not_connected_summary" msgid="634573930469952213">"ไม่ได้เชื่อมต่อเครื่องช่วยฟัง"</string>
+    <string name="accessibility_hearingaid_adding_summary" msgid="4139031880828714300">"เพิ่มเครื่องช่วยฟัง"</string>
+    <string name="accessibility_hearingaid_pair_instructions_first_message" msgid="2671518890909750740">"หากต้องการจับคู่กับเครื่องช่วยฟัง ให้ค้นหาและแตะอุปกรณ์ในหน้าจอถัดไป"</string>
+    <string name="accessibility_hearingaid_pair_instructions_second_message" msgid="1584538735488464991">"ตรวจสอบว่าเครื่องช่วยฟังอยู่ในโหมดการจับคู่"</string>
     <string name="accessibility_hearingaid_active_device_summary" msgid="6081382497207168885">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ใช้งานอยู่"</string>
     <plurals name="show_number_hearingaid_count" formatted="false" msgid="7906547154695855096">
-      <item quantity="other">บันทึกเครื่องช่วยการได้ยิน <xliff:g id="NUMBER_DEVICE_COUNT_1">%1$d</xliff:g> เครื่องแล้ว</item>
-      <item quantity="one">บันทึกเครื่องช่วยการได้ยิน <xliff:g id="NUMBER_DEVICE_COUNT_0">%1$d</xliff:g> เครื่องแล้ว</item>
+      <item quantity="other">บันทึกเครื่องช่วยฟัง <xliff:g id="NUMBER_DEVICE_COUNT_1">%1$d</xliff:g> เครื่องแล้ว</item>
+      <item quantity="one">บันทึกเครื่องช่วยฟัง <xliff:g id="NUMBER_DEVICE_COUNT_0">%1$d</xliff:g> เครื่องแล้ว</item>
     </plurals>
     <string name="accessibility_summary_state_enabled" msgid="7357731696603247963">"เปิด"</string>
     <string name="accessibility_summary_state_disabled" msgid="9197369047683087620">"ปิด"</string>
@@ -2146,7 +2151,7 @@
     <string name="captioning_standard_options_title" msgid="4124898413348084226">"ตัวเลือกมาตรฐาน"</string>
     <string name="captioning_locale" msgid="4734464353806207943">"ภาษา"</string>
     <string name="captioning_text_size" msgid="1707122517246408084">"ขนาดข้อความ"</string>
-    <string name="captioning_preset" msgid="7429888317480872337">"รูปแบบคำบรรยายภาพ"</string>
+    <string name="captioning_preset" msgid="7429888317480872337">"รูปแบบคำบรรยาย"</string>
     <string name="captioning_custom_options_title" msgid="4530479671071326732">"ตัวเลือกที่กำหนดเอง"</string>
     <string name="captioning_background_color" msgid="2434458880326292180">"สีพื้นหลัง"</string>
     <string name="captioning_background_opacity" msgid="8178926599201811936">"ความทึบแสงของพื้นหลัง"</string>
@@ -2157,7 +2162,7 @@
     <string name="captioning_edge_color" msgid="4330622137047993780">"สีขอบ"</string>
     <string name="captioning_edge_type" msgid="4414946407430588162">"ชนิดขอบ"</string>
     <string name="captioning_typeface" msgid="7893208796949341767">"ชุดแบบอักษร"</string>
-    <string name="captioning_preview_text" msgid="4877753964772618049">"คำอธิบายภาพจะมีหน้าตาแบบนี้"</string>
+    <string name="captioning_preview_text" msgid="4877753964772618049">"คำบรรยายจะมีหน้าตาแบบนี้"</string>
     <string name="captioning_preview_characters" msgid="6469599599352973561">"Aa"</string>
     <string name="locale_default" msgid="910074908458214054">"ค่าเริ่มต้น"</string>
     <string name="color_title" msgid="132875486061816584">"สี"</string>
@@ -2190,8 +2195,8 @@
     <string name="print_settings" msgid="7886184656544483072">"การพิมพ์"</string>
     <string name="print_settings_summary_no_service" msgid="634173687975841526">"ปิด"</string>
     <plurals name="print_settings_summary" formatted="false" msgid="7580293760281445137">
-      <item quantity="other">บริการการพิมพ์เปิดอยู่ <xliff:g id="COUNT">%1$d</xliff:g> รายการ</item>
-      <item quantity="one">บริการการพิมพ์เปิดอยู่ 1 รายการ</item>
+      <item quantity="other">บริการพิมพ์เปิดอยู่ <xliff:g id="COUNT">%1$d</xliff:g> รายการ</item>
+      <item quantity="one">บริการพิมพ์เปิดอยู่ 1 รายการ</item>
     </plurals>
     <plurals name="print_jobs_summary" formatted="false" msgid="6180308415569432845">
       <item quantity="other">งานพิมพ์ <xliff:g id="COUNT">%1$d</xliff:g> รายการ</item>
@@ -2228,7 +2233,7 @@
     <string name="power_usage_level_and_status" msgid="8873534076894160727">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATUS">%2$s</xliff:g>"</string>
     <string name="power_discharge_remaining" msgid="3461915627093471868">"เหลืออีก <xliff:g id="REMAIN">%1$s</xliff:g>"</string>
     <string name="power_charge_remaining" msgid="2730510256218879651">"อีก <xliff:g id="UNTIL_CHARGED">%1$s</xliff:g> จะชาร์จเต็ม"</string>
-    <string name="background_activity_title" msgid="7207836362312111483">"การจำกัดการใช้งานในพื้นหลัง"</string>
+    <string name="background_activity_title" msgid="7207836362312111483">"การจำกัดการทำงานในเบื้องหลัง"</string>
     <string name="background_activity_summary" msgid="582372194738538145">"อนุญาตให้แอปทำงานในเบื้องหลัง"</string>
     <string name="background_activity_summary_disabled" msgid="457944930942085876">"ไม่อนุญาตให้แอปทำงานในพื้นหลัง"</string>
     <string name="background_activity_summary_whitelisted" msgid="4713321059375873828">"จำกัดการใช้งานในพื้นหลังไม่ได้"</string>
@@ -2236,7 +2241,7 @@
     <string name="background_activity_warning_dialog_text" msgid="8242749826732375096">"แอปอาจทำงานผิดพลาดหากคุณจำกัดกิจกรรมในพื้นหลัง"</string>
     <string name="background_activity_disabled_dialog_text" msgid="4234598000779459640">"เนื่องจากแอปนี้ไม่ได้ตั้งค่าให้เพิ่มประสิทธิภาพแบตเตอรี่ คุณจึงจำกัดการใช้งานไม่ได้\n\nหากต้องการจำกัด ให้เปิดการเพิ่มประสิทธิภาพแบตเตอรี่ก่อน"</string>
     <string name="device_screen_usage" msgid="4470485475363132750">"การใช้งานหน้าจอตั้งแต่ชาร์จจนเต็ม"</string>
-    <string name="power_usage_list_summary" msgid="4314438658308211057">"การใช้งานแบตเตอรี่ตั้งแต่ชาร์จจนเต็ม"</string>
+    <string name="power_usage_list_summary" msgid="4314438658308211057">"การใช้งานแบตเตอรี่ตั้งแต่ชาร์จเต็ม"</string>
     <string name="screen_usage_summary" msgid="263396144684078341">"ระยะเวลาที่หน้าจอเปิดตั้งแต่ชาร์จจนเต็ม"</string>
     <string name="device_usage_list_summary" msgid="8299017481332816368">"การใช้งานอุปกรณ์ตั้งแต่ชาร์จจนเต็ม"</string>
     <string name="battery_since_unplugged" msgid="6486555910264026856">"การใช้แบตเตอรี่ตั้งแต่ถอดปลั๊ก"</string>
@@ -2294,7 +2299,7 @@
     </plurals>
     <plurals name="battery_tip_restrict_summary" formatted="false" msgid="984148373944071669">
       <item quantity="other">แอป %2$d แอปใช้แบตเตอรี่ในเบื้องหลังเปลือง</item>
-      <item quantity="one">แอป %1$s แอปใช้แบตเตอรี่ในเบื้องหลังเปลือง</item>
+      <item quantity="one">%1$s ใช้แบตเตอรี่ในเบื้องหลังเปลือง</item>
     </plurals>
     <plurals name="battery_tip_restrict_handled_summary" formatted="false" msgid="469696766640020557">
       <item quantity="other">แอปเหล่านี้ทำงานในเบื้องหลังไม่ได้</item>
@@ -2304,9 +2309,9 @@
       <item quantity="other">จำกัดแอป %1$d แอปใช่ไหม</item>
       <item quantity="one">จำกัดแอปใช่ไหม</item>
     </plurals>
-    <string name="battery_tip_restrict_app_dialog_message" msgid="6905822297507947381">"หากต้องการประหยัดแบตเตอรี่ ต้องไม่ให้แอป <xliff:g id="APP">%1$s</xliff:g> ใช้งานแบตเตอรี่ในพื้นหลัง แอปนี้อาจไม่ทำงานตามปกติและการแจ้งเตือนอาจล่าช้า"</string>
-    <string name="battery_tip_restrict_apps_less_than_5_dialog_message" msgid="4225881888543582456">"หากต้องการประหยัดแบตเตอรี่ ต้องไม่ให้แอปเหล่านี้ใช้งานแบตเตอรี่ในพื้นหลัง แอปที่ถูกจำกัดอาจไม่ทำงานตามปกติและการแจ้งเตือนอาจล่าช้า\n\nแอปดังกล่าวได้แก่"</string>
-    <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"หากต้องการประหยัดแบตเตอรี่ ต้องไม่ให้แอปเหล่านี้ใช้งานแบตเตอรี่ในพื้นหลัง แอปที่ถูกจำกัดอาจไม่ทำงานตามปกติและการแจ้งเตือนอาจล่าช้า\n\nแอปดังกล่าวได้แก่\n<xliff:g id="APP_LIST">%1$s</xliff:g>"</string>
+    <string name="battery_tip_restrict_app_dialog_message" msgid="6905822297507947381">"หากต้องการประหยัดแบตเตอรี่ ต้องไม่ให้แอป <xliff:g id="APP">%1$s</xliff:g> ใช้งานแบตเตอรี่ในเบื้องหลัง แอปนี้อาจไม่ทำงานตามปกติและการแจ้งเตือนอาจล่าช้า"</string>
+    <string name="battery_tip_restrict_apps_less_than_5_dialog_message" msgid="4225881888543582456">"หากต้องการประหยัดแบตเตอรี่ ต้องไม่ให้แอปเหล่านี้ใช้งานแบตเตอรี่ในเบื้องหลัง แอปที่ถูกจำกัดอาจไม่ทำงานตามปกติและการแจ้งเตือนอาจล่าช้า\n\nแอปดังกล่าวได้แก่"</string>
+    <string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"หากต้องการประหยัดแบตเตอรี่ ต้องไม่ให้แอปเหล่านี้ใช้งานแบตเตอรี่ในเบื้องหลัง แอปที่ถูกจำกัดอาจไม่ทำงานตามปกติและการแจ้งเตือนอาจล่าช้า\n\nแอปดังกล่าวได้แก่\n<xliff:g id="APP_LIST">%1$s</xliff:g>"</string>
     <string name="battery_tip_restrict_app_dialog_ok" msgid="2573410775701913487">"จำกัด"</string>
     <string name="battery_tip_unrestrict_app_dialog_title" msgid="812458516399125710">"นำการจำกัดออกใช่ไหม"</string>
     <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"แอปนี้จะใช้แบตเตอรี่ในเบื้องหลังได้ แบตเตอรี่จึงอาจจะหมดเร็วกว่าที่คาดไว้"</string>
@@ -2323,11 +2328,11 @@
     <string name="smart_battery_footer" product="device" msgid="3971715848890205632">"เมื่อตัวจัดการแบตเตอรี่ตรวจพบว่าแอปทำให้แบตเตอรี่หมดเร็ว คุณจะมีตัวเลือกในการจำกัดแอปเหล่านี้ แอปที่ถูกจำกัดอาจไม่ทำงานตามปกติและการแจ้งเตือนอาจล่าช้า"</string>
     <string name="restricted_app_title" msgid="4957644700640127606">"แอปที่ถูกจำกัด"</string>
     <plurals name="restricted_app_summary" formatted="false" msgid="7609538735465186040">
-      <item quantity="other">การจำกัดการใช้งานแบตเตอรี่ของแอป %1$d</item>
-      <item quantity="one">การจำกัดการใช้งานแบตเตอรี่ของแอป %1$d</item>
+      <item quantity="other">การจำกัดการใช้งานแบตเตอรี่ของแอป %1$d แอป</item>
+      <item quantity="one">การจำกัดการใช้งานแบตเตอรี่ของแอป %1$d แอป</item>
     </plurals>
     <string name="restricted_app_time_summary" msgid="5205881852523135226">"จำกัดเมื่อ <xliff:g id="TIME">%1$s</xliff:g>"</string>
-    <string name="restricted_app_detail_footer" msgid="482460517275754465">"แอปเหล่านี้ใช้งานแบตเตอรี่ในพื้นหลัง แอปที่ถูกจำกัดอาจไม่ทำงานตามปกติและการแจ้งเตือนอาจล่าช้า"</string>
+    <string name="restricted_app_detail_footer" msgid="482460517275754465">"แอปเหล่านี้ใช้งานแบตเตอรี่ในเบื้องหลัง แอปที่ถูกจำกัดอาจไม่ทำงานตามปกติและการแจ้งเตือนอาจล่าช้า"</string>
     <string name="battery_auto_restriction_title" msgid="488905332794794076">"ใช้ตัวจัดการแบตเตอรี่"</string>
     <string name="battery_auto_restriction_summary" msgid="1638072655581821837">"ตรวจจับเมื่อแอปทำให้แบตเตอรี่หมดเร็ว"</string>
     <string name="battery_manager_on" msgid="5626982529932239656">"เปิด/ตรวจจับเมื่อแอปทำให้แบตเตอรี่หมดเร็ว"</string>
@@ -2443,14 +2448,14 @@
     <string name="process_dex2oat_label" msgid="8249082119748556085">"การเพิ่มประสิทธิภาพแอป"</string>
     <string name="battery_saver" msgid="3989710213758938398">"โหมดประหยัดแบตเตอรี่"</string>
     <string name="battery_saver_auto_title" msgid="4158659069641849952">"เปิดอัตโนมัติ"</string>
-    <string name="battery_saver_auto_no_schedule" msgid="739814529432092706">"ไม่มีกำหนดเวลา"</string>
+    <string name="battery_saver_auto_no_schedule" msgid="739814529432092706">"ไม่มีกำหนดการ"</string>
     <string name="battery_saver_auto_routine" msgid="886514412067906980">"อิงตามกิจวัตรของคุณ"</string>
     <string name="battery_saver_auto_percentage" msgid="5791982309331921556">"อิงตามเปอร์เซ็นต์แบตเตอรี่"</string>
     <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"โหมดประหยัดแบตเตอรี่จะเปิดเมื่อมีแนวโน้มว่าแบตเตอรี่จะหมดก่อนถึงเวลาที่คุณจะชาร์จอุปกรณ์เป็นประจำ"</string>
     <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"จะเปิดเมื่อเหลือแบตเตอรี่ <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
-    <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"ตั้งกำหนดเวลา"</string>
-    <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"ปิดเมื่อชาร์จเต็ม"</string>
-    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"โหมดประหยัดแบตเตอรี่จะปิดเมื่อแบตเตอรี่โทรศัพท์อยู่ที่ <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
+    <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"ตั้งกำหนดการ"</string>
+    <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"ปิดเมื่อชาร์จเต็มแล้ว"</string>
+    <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"โหมดประหยัดแบตเตอรี่จะปิดเมื่อมีแบตเตอรี่โทรศัพท์อยู่ที่ <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <string name="battery_saver_sticky_description_new" product="tablet" msgid="3284967694001857194">"โหมดประหยัดแบตเตอรี่จะปิดเมื่อแบตเตอรี่แท็บเล็ตอยู่ที่ <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <string name="battery_saver_sticky_description_new" product="device" msgid="5056520668081504111">"โหมดประหยัดแบตเตอรี่จะปิดเมื่อแบตเตอรี่อุปกรณ์อยู่ที่ <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
     <!-- no translation found for battery_saver_seekbar_title (7607123201469333645) -->
@@ -2919,8 +2924,8 @@
     <string name="nfc_payment_favor_default" msgid="7555356982142464260">"ทุกครั้ง"</string>
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"ยกเว้นเมื่อแอปการชำระเงินอื่นเปิดอยู่"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"ที่เครื่องแตะและจ่าย ให้ชำระเงินด้วย:"</string>
-    <string name="nfc_how_it_works_title" msgid="6531433737926327904">"การชำระเงินที่เครื่องเทอร์มินัล"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"ตั้งค่าแอปการชำระเงิน แล้วแตะด้านหลังของโทรศัพท์กับเทอร์มินัลเครื่องใดก็ได้ที่มีสัญลักษณ์ \"ไร้สัมผัส\""</string>
+    <string name="nfc_how_it_works_title" msgid="6531433737926327904">"การชำระเงินที่เครื่องชำระเงิน"</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"ตั้งค่าแอปการชำระเงิน แล้วแตะด้านหลังของโทรศัพท์กับเครื่องชำระเงินเครื่องใดก็ได้ที่มีสัญลักษณ์ \"ไม่ต้องสัมผัส\""</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"รับทราบ"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"เพิ่มเติม..."</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"ตั้งเป็นค่ากำหนดของคุณไหม"</string>
@@ -2938,7 +2943,7 @@
     <string name="extreme_threats_summary" msgid="4967919167246852181">"รับการแจ้งเตือนภัยคุกคามต่อชีวิตและทรัพย์สินระดับสูงสุด"</string>
     <string name="severe_threats_title" msgid="1987698359027211862">"ภัยคุกคามที่ร้ายแรง"</string>
     <string name="severe_threats_summary" msgid="1148147804181873835">"รับการแจ้งเตือนภัยคุกคามที่ร้ายแรงต่อชีวิตและทรัพย์สิน"</string>
-    <string name="amber_alerts_title" msgid="8274651933750533271">"การแจ้งเตือน AMBER Alert"</string>
+    <string name="amber_alerts_title" msgid="8274651933750533271">"การแจ้งเตือน AMBER"</string>
     <string name="amber_alerts_summary" msgid="7570943549000256418">"รับกระดานข่าวสารเกี่ยวกับการลักพาตัวเด็ก"</string>
     <string name="repeat_title" msgid="507090203366188931">"เล่นซ้ำ"</string>
     <string name="call_manager_enable_title" msgid="6345443572463650308">"เปิดใช้ Call Manager"</string>
@@ -3031,7 +3036,7 @@
     <string name="network_dashboard_summary_data_usage" msgid="4695629715072542102">"ปริมาณการใช้อินเทอร์เน็ต"</string>
     <string name="network_dashboard_summary_hotspot" msgid="3928610802321995214">"ฮอตสปอต"</string>
     <string name="connected_devices_dashboard_title" msgid="7795222675849060444">"อุปกรณ์ที่เชื่อมต่อ"</string>
-    <string name="connected_devices_dashboard_summary" msgid="1072664369515033179">"บลูทูธ, โหมดขับรถ, NFC"</string>
+    <string name="connected_devices_dashboard_summary" msgid="1072664369515033179">"บลูทูธ โหมดขับรถ NFC"</string>
     <string name="connected_devices_dashboard_no_nfc_summary" msgid="2610085597733526722">"บลูทูธ, โหมดขับรถ"</string>
     <string name="connected_devices_dashboard_no_driving_mode_summary" msgid="3524409078596318803">"บลูทูธ, NFC"</string>
     <string name="connected_devices_dashboard_no_driving_mode_no_nfc_summary" msgid="7881286613528299400">"บลูทูธ"</string>
@@ -3156,7 +3161,7 @@
     <string name="emergency_tone_alert" msgid="907868135091891015">"มีเสียง"</string>
     <string name="emergency_tone_vibrate" msgid="5020068066905681181">"การสั่น"</string>
     <string name="boot_sounds_title" msgid="7583926202411353620">"เสียงเปิดเครื่อง"</string>
-    <string name="live_caption_title" msgid="7926591158657997051">"คำบรรยายภาพสด"</string>
+    <string name="live_caption_title" msgid="7926591158657997051">"คำบรรยายสด"</string>
     <string name="live_caption_summary" msgid="9064771862352393125">"แสดงคำบรรยายสื่อโดยอัตโนมัติ"</string>
     <string name="zen_mode_settings_summary_off" msgid="6929319200478424962">"ไม่เลย"</string>
     <plurals name="zen_mode_settings_summary_on" formatted="false" msgid="6061723291126091396">
@@ -3182,7 +3187,7 @@
     <string name="zen_mode_automation_suggestion_title" msgid="4921779962633710347">"ปิดเสียงโทรศัพท์ในบางช่วงเวลา"</string>
     <string name="zen_mode_automation_suggestion_summary" msgid="2709837472884371037">"ตั้งกฎห้ามรบกวน"</string>
     <string name="zen_mode_schedule_title" msgid="5275268813192802631">"กำหนดเวลา"</string>
-    <string name="zen_mode_use_automatic_rule" msgid="446326253915861824">"ใช้กำหนดเวลา"</string>
+    <string name="zen_mode_use_automatic_rule" msgid="446326253915861824">"ใช้กำหนดการ"</string>
     <string name="zen_mode_option_important_interruptions" msgid="5173944276846940149">"เฉพาะเรื่องสำคัญ"</string>
     <string name="zen_mode_option_alarms" msgid="4843278125235203076">"เฉพาะปลุกเท่านั้น"</string>
     <string name="zen_mode_option_no_interruptions" msgid="4723700274519260852">"ปิดเสียงทั้งหมด"</string>
@@ -3301,10 +3306,10 @@
     <string name="hide_silent_icons_title" msgid="1070905516921542662">"ซ่อนไอคอนสถานะการแจ้งเตือนแบบไม่มีเสียง"</string>
     <string name="hide_silent_icons_summary" msgid="2624346914488256888">"ซ่อนไอคอนสำหรับการแจ้งเตือนแบบไม่มีเสียงในแถบสถานะ"</string>
     <string name="notification_badging_title" msgid="6311699476970264712">"อนุญาตให้ใช้จุดแจ้งเตือน"</string>
-    <string name="notification_bubbles_title" msgid="9196562435741861317">"ลูกโป่ง"</string>
+    <string name="notification_bubbles_title" msgid="9196562435741861317">"บับเบิล"</string>
     <string name="notification_bubbles_summary" msgid="4624512775901949578">"เข้าถึงเนื้อหาแอปอย่างรวดเร็วได้จากทุกที่โดยใช้ทางลัดแบบลอย"</string>
     <string name="bubbles_feature_education" msgid="8979109826818881018">"การแจ้งเตือนบางรายการและเนื้อหาอื่นอาจแสดงเป็นลูกโป่งในหน้าจอได้ แตะลูกโป่งเพื่อเปิด ลากลูกโป่งลงไปที่ด้านล่างของหน้าจอเพื่อปิด"</string>
-    <string name="bubbles_app_toggle_title" msgid="6401217027603326439">"ลูกโป่ง"</string>
+    <string name="bubbles_app_toggle_title" msgid="6401217027603326439">"บับเบิล"</string>
     <string name="bubbles_app_toggle_summary" msgid="7707611139796553855">"อนุญาตให้ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" แสดงการแจ้งเตือนบางรายการเป็นลูกโป่ง"</string>
     <string name="bubbles_feature_disabled_dialog_title" msgid="3375452386012079293">"เปิดลูกโป่ง"</string>
     <string name="bubbles_feature_disabled_dialog_text" msgid="326945485806386477">"หากต้องการเปิดลูกโป่งของแอปนี้ คุณต้องเปิดลูกโป่งของอุปกรณ์ก่อน การดำเนินการนี้จะส่งผลต่อแอปอื่นๆ ที่คุณเปิดลูกโป่งไว้ก่อนหน้านี้"</string>
@@ -3430,14 +3435,14 @@
     <string name="notification_channel_sound_title" msgid="7635366839003304745">"เสียง"</string>
     <string name="zen_mode_rule_delete_button" msgid="6763486487220471193">"ลบ"</string>
     <string name="zen_mode_rule_rename_button" msgid="1428130397306726792">"เปลี่ยนชื่อ"</string>
-    <string name="zen_mode_rule_name" msgid="8583652780885724670">"ชื่อกำหนดเวลา"</string>
-    <string name="zen_mode_rule_name_hint" msgid="6569877315858105901">"ระบุชื่อกำหนดเวลา"</string>
-    <string name="zen_mode_rule_name_warning" msgid="4773465816059587512">"มีการใช้ชื่อกำหนดเวลานี้แล้ว"</string>
+    <string name="zen_mode_rule_name" msgid="8583652780885724670">"ชื่อกำหนดการ"</string>
+    <string name="zen_mode_rule_name_hint" msgid="6569877315858105901">"ระบุชื่อกำหนดการ"</string>
+    <string name="zen_mode_rule_name_warning" msgid="4773465816059587512">"มีการใช้ชื่อกำหนดการนี้แล้ว"</string>
     <string name="zen_mode_add_rule" msgid="7200004557856029928">"เพิ่มอีก"</string>
     <string name="zen_mode_add_event_rule" msgid="1398181272397489506">"เพิ่มกำหนดการตามกิจกรรม"</string>
     <string name="zen_mode_add_time_rule" msgid="5999467757140524729">"เพิ่มกำหนดการตามเวลา"</string>
     <string name="zen_mode_delete_rule" msgid="2292933835997203801">"ลบกำหนดเวลา"</string>
-    <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"เลือกประเภทกำหนดเวลา"</string>
+    <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"เลือกประเภทกำหนดการ"</string>
     <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"ลบกฎ \"<xliff:g id="RULE">%1$s</xliff:g>\" ใช่ไหม"</string>
     <string name="zen_mode_delete_rule_button" msgid="611058106279881991">"ลบ"</string>
     <string name="zen_mode_rule_type_unknown" msgid="2819480113355191421">"ไม่ทราบ"</string>
@@ -3463,11 +3468,11 @@
     <string name="zen_mode_schedule_rule_days" msgid="220627703673691816">"วัน"</string>
     <string name="zen_mode_schedule_rule_days_none" msgid="6011716195119389956">"ไม่มี"</string>
     <string name="zen_mode_schedule_rule_days_all" msgid="8814173364016139675">"ทุกวัน"</string>
-    <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"เวลาปลุกจะแทนที่เวลาสิ้นสุดได้"</string>
-    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"กำหนดเวลาจะปิดเมื่อนาฬิกาปลุกดังขึ้น"</string>
+    <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"การปลุกจะแทนที่เวลาสิ้นสุดได้"</string>
+    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"กำหนดการจะปิดเมื่อนาฬิกาปลุกดังขึ้น"</string>
     <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"ลักษณะการทำงานของโหมดห้ามรบกวน"</string>
     <string name="zen_mode_custom_behavior_summary_default" msgid="3509865340195397447">"ใช้การตั้งค่าเริ่มต้น"</string>
-    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"สร้างการตั้งค่าที่กำหนดเองสำหรับกำหนดเวลานี้"</string>
+    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"สร้างการตั้งค่าที่กำหนดเองสำหรับกำหนดการนี้"</string>
     <string name="zen_mode_custom_behavior_category_title" msgid="7451686525113262087">"สำหรับ \"<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>\""</string>
     <string name="summary_divider_text" msgid="4780683204694442666">", "</string>
     <string name="summary_range_symbol_combination" msgid="6038631664844488406">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
@@ -3645,7 +3650,7 @@
     <string name="tap_to_wake" msgid="1902991239401652323">"แตะเพื่อปลุก"</string>
     <string name="tap_to_wake_summary" msgid="8485222120721006793">"แตะที่ใดก็ได้บนหน้าจอ 2 ครั้งเพื่อปลุกอุปกรณ์"</string>
     <string name="domain_urls_title" msgid="7939209950373945367">"การเปิดลิงก์"</string>
-    <string name="domain_urls_summary_none" msgid="5401203416941265109">"อย่าเปิดลิงก์ที่สนับสนุน"</string>
+    <string name="domain_urls_summary_none" msgid="5401203416941265109">"อย่าเปิดลิงก์ที่รองรับ"</string>
     <string name="domain_urls_summary_one" msgid="3893975485064803435">"เปิด <xliff:g id="DOMAIN">%s</xliff:g>"</string>
     <string name="domain_urls_summary_some" msgid="2130534984153210797">"เปิด <xliff:g id="DOMAIN">%s</xliff:g> และ URL อื่นๆ"</string>
     <string name="domain_urls_apps_summary_off" msgid="1110203970617922543">"ไม่มีแอปใดเปิดลิงก์ที่รองรับได้เลย"</string>
@@ -3707,7 +3712,7 @@
     <string name="high_power_system" msgid="739584574711292753">"การเพิ่มประสิทธิภาพแบตเตอรี่ไม่พร้อมใช้งาน"</string>
     <string name="high_power_desc" msgid="333756885680362741">"ไม่ใช้การเพิ่มประสิทธิภาพแบตเตอรี่ อาจทำให้แบตเตอรี่หมดเร็วยิ่งขึ้น"</string>
     <string name="high_power_prompt_title" msgid="2805745781720454052">"ให้แอปทำงานในพื้นหลังทุกครั้งไหม"</string>
-    <string name="high_power_prompt_body" msgid="8067395096053552289">"การอนุญาตให้ <xliff:g id="APP_NAME">%1$s</xliff:g> ทำงานในพื้นหลังทุกครั้งอาจลดอายุการใช้งานแบตเตอรี่ \n\nคุณสามารถเปลี่ยนการตั้งค่านี้ได้ในภายหลังจากการตั้งค่า &gt; แอปและการแจ้งเตือน"</string>
+    <string name="high_power_prompt_body" msgid="8067395096053552289">"การอนุญาตให้ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" ทำงานอยู่เบื้องหลังทุกครั้งอาจลดอายุการใช้งานแบตเตอรี่ \n\nคุณเปลี่ยนการตั้งค่านี้ได้ในภายหลังจากการตั้งค่า &gt; แอปและการแจ้งเตือน"</string>
     <string name="battery_summary" msgid="4345690800899981339">"ใช้ <xliff:g id="PERCENTAGE">%1$s</xliff:g> ตั้งแต่ชาร์จจนเต็มครั้งล่าสุด"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"การจัดการพลังงาน"</string>
     <string name="no_battery_summary" msgid="4105932628367471314">"ไม่มีการใช้แบตเตอรี่ตั้งแต่การชาร์จเต็มครั้งล่าสุด"</string>
@@ -3825,7 +3830,7 @@
     <string name="camera_gesture_desc" msgid="7751841175916789527">"เปิดแอปกล้องถ่ายรูปโดยบิดข้อมือ 2 ครั้ง"</string>
     <string name="camera_double_tap_power_gesture_title" msgid="8874747801078147525">"กดปุ่มเปิด/ปิด 2 ครั้งสำหรับกล้อง"</string>
     <string name="camera_double_tap_power_gesture_desc" msgid="6166349645433682873">"เปิดกล้องอย่างรวดเร็วโดยไม่ต้องปลดล็อกหน้าจอ"</string>
-    <string name="screen_zoom_title" msgid="164369086350486104">"ขนาดที่แสดง"</string>
+    <string name="screen_zoom_title" msgid="164369086350486104">"ขนาดการแสดงผล"</string>
     <string name="screen_zoom_short_summary" msgid="5508079362742276703">"ทำให้รายการบนหน้าจอมีขนาดใหญ่ขึ้นหรือเล็กลง"</string>
     <string name="screen_zoom_keywords" msgid="8358462497896524092">"ความหนาแน่นในการแสดงผล, ซูมหน้าจอ, ระดับ, การปรับระดับ"</string>
     <string name="screen_zoom_summary" msgid="5294003755961312560">"ปรับขนาดข้อความบนหน้าจอให้เล็กลงหรือใหญ่ขึ้น แอปบางส่วนบนหน้าจออาจเปลี่ยนตำแหน่ง"</string>
@@ -3948,7 +3953,7 @@
       <item quantity="other">ข้อจำกัด <xliff:g id="COUNT">%1$d</xliff:g> ข้อ</item>
       <item quantity="one">ข้อจำกัด 1 ข้อ</item>
     </plurals>
-    <string name="operator_warning" msgid="4676042739221117031">"การบันทึกบัญชีข้อมูลของผู้ให้บริการอาจแตกต่างจากการบันทึกบัญชีของอุปกรณ์"</string>
+    <string name="operator_warning" msgid="4676042739221117031">"การบันทึกการใช้อินเทอร์เน็ตของผู้ให้บริการอาจแตกต่างไปจากการบันทึกในอุปกรณ์"</string>
     <string name="data_used_template" msgid="761605393453849477">"ใช้ไป <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="set_data_warning" msgid="8115980184415563941">"ตั้งค่าเตือนการใช้อินเทอร์เน็ต"</string>
     <string name="data_warning" msgid="2699207195535036240">"เตือนปริมาณอินเทอร์เน็ต"</string>
@@ -4246,7 +4251,7 @@
     <string name="app_info_storage_title" msgid="6643391804949509308">"พื้นที่ที่ใช้ไป"</string>
     <string name="webview_uninstalled_for_user" msgid="3407952144444040557">"(ถอนการติดตั้งแล้วสำหรับ <xliff:g id="USER">%s</xliff:g>)"</string>
     <string name="webview_disabled_for_user" msgid="8057805373224993504">"(ปิดใช้อยู่สำหรับ <xliff:g id="USER">%s</xliff:g>)"</string>
-    <string name="autofill_app" msgid="3990765434980280073">"บริการป้อนอัตโนมัติ"</string>
+    <string name="autofill_app" msgid="3990765434980280073">"บริการป้อนข้อความอัตโนมัติ"</string>
     <string name="autofill_keywords" msgid="7717726766232862218">"ป้อน, อัตโนมัติ, ป้อนอัตโนมัติ"</string>
     <string name="autofill_confirmation_message" msgid="1385894598730361304">"&lt;b&gt;ตรวจดูว่าคุณเชื่อถือแอปนี้ได้&lt;/b&gt; &lt;br/&gt; &lt;br/&gt; &lt;xliff:g id=app_name example=Google ป้อนอัตโนมัติ&gt;%1$s&lt;/xliff:g&gt; ใช้สิ่งที่อยู่บนหน้าจอเพื่อดูว่าจะป้อนข้อมูลใดโดยอัตโนมัติได้บ้าง"</string>
     <string name="debug_autofill_category" msgid="6262526615416295645">"ป้อนอัตโนมัติ"</string>
diff --git a/tests/CarDeveloperOptions/res/values-tl/arrays.xml b/tests/CarDeveloperOptions/res/values-tl/arrays.xml
index 87099a2..de090b6 100644
--- a/tests/CarDeveloperOptions/res/values-tl/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-tl/arrays.xml
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"patakbuhin sa background"</item>
     <item msgid="6423861043647911030">"dami ng pagiging naa-access"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Lokasyon"</item>
+    <item msgid="6656077694190491067">"Lokasyon"</item>
+    <item msgid="8790228218278477369">"Lokasyon"</item>
+    <item msgid="7836406246005211990">"Pag-vibrate"</item>
+    <item msgid="3951439024549922598">"Magbasa ng mga contact"</item>
+    <item msgid="8802152411647068">"Baguhin ang mga contact"</item>
+    <item msgid="229544934599698735">"Basahin ang log ng tawag"</item>
+    <item msgid="7396102294405899613">"Baguhin ang log ng tawag"</item>
+    <item msgid="3597797992398484655">"Magbasa ng kalendaryo"</item>
+    <item msgid="2705975774250907343">"Baguhin ang kalendaryo"</item>
+    <item msgid="4668747371441932697">"Lokasyon"</item>
+    <item msgid="1487578921720243646">"Mag-post ng notification"</item>
+    <item msgid="4636080349724146638">"Lokasyon"</item>
+    <item msgid="673510900286463926">"Tumawag sa telepono"</item>
+    <item msgid="542083422784609790">"Magbasa ng SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Magsulat ng SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Tumanggap ng SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Tumanggap ng SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Tumanggap ng SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Tumanggap ng SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Magpadala ng SMS/MMS"</item>
+    <item msgid="4726682243833913568">"Magbasa ng SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Magsulat ng SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Baguhin ang mga setting"</item>
+    <item msgid="8705854389991425629">"Gumuhit sa tuktok"</item>
+    <item msgid="5861356020344153651">"I-access ang mga notification"</item>
+    <item msgid="78432174621628659">"Camera"</item>
+    <item msgid="3986116419882154794">"I-record ang audio"</item>
+    <item msgid="4516840825756409490">"I-play ang audio"</item>
+    <item msgid="6811712502798183957">"Basahin ang clipboard"</item>
+    <item msgid="2780369012602289114">"Baguhin ang clipboard"</item>
+    <item msgid="2331359440170850868">"Mga media button"</item>
+    <item msgid="6133599737122751231">"Focus ng audio"</item>
+    <item msgid="6844485713404805301">"Master volume"</item>
+    <item msgid="1600379420669104929">"Volume ng boses"</item>
+    <item msgid="6296768210470214866">"Volume ng pag-ring"</item>
+    <item msgid="510690696071629241">"Volume ng media"</item>
+    <item msgid="406861638631430109">"Volume ng alarm"</item>
+    <item msgid="4715864795872233884">"Volume ng notification"</item>
+    <item msgid="2311478519251301183">"Volume ng Bluetooth"</item>
+    <item msgid="5133991377896747027">"Panatilihing bukas"</item>
+    <item msgid="2464189519136248621">"Lokasyon"</item>
+    <item msgid="2062677934050803037">"Lokasyon"</item>
+    <item msgid="1735171933192715957">"Kumuha ng stats sa paggamit"</item>
+    <item msgid="1014093788778383554">"I-mute/i-unmute ang mikropono"</item>
+    <item msgid="4199297950608622850">"Ipakita ang toast"</item>
+    <item msgid="2527962435313398821">"I-project ang media"</item>
+    <item msgid="5117506254221861929">"I-activate ang VPN"</item>
+    <item msgid="8291198322681891160">"Write wallpaper"</item>
+    <item msgid="7106921284621230961">"Assist structure"</item>
+    <item msgid="4496533640894624799">"Assist screenshot"</item>
+    <item msgid="2598847264853993611">"Basahin ang katayuan ng telepono"</item>
+    <item msgid="9215610846802973353">"Magdagdag ng voicemail"</item>
+    <item msgid="9186411956086478261">"Gamitin ang sip"</item>
+    <item msgid="6884763100104539558">"Iproseso ang papalabas na tawag"</item>
+    <item msgid="125513972170580692">"Fingerprint"</item>
+    <item msgid="2556071024281275619">"Mga sensor ng katawan"</item>
+    <item msgid="617168514928339387">"Basahin ang mga cell broadcast"</item>
+    <item msgid="7134693570516523585">"Kunwaring lokasyon"</item>
+    <item msgid="7224489175375229399">"Basahin ang storage"</item>
+    <item msgid="8472735063903258202">"I-write ang storage"</item>
+    <item msgid="4069276819909595110">"I-on ang screen"</item>
+    <item msgid="1228338896751121025">"Kunin ang mga account"</item>
+    <item msgid="3181581793459233672">"Patakbuhin sa background"</item>
+    <item msgid="2340936043025374076">"Dami ng pagiging naa-access"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Maikli"</item>
     <item msgid="4816511817309094890">"Katamtaman"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Huwag kailanman payagan"</item>
     <item msgid="8184570120217958741">"Palaging payagan"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Katamtaman"</item>
+    <item msgid="1555861583162930714">"Mababa"</item>
+    <item msgid="1719683776264798117">"Kritikal"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normal"</item>
+    <item msgid="6107138933849816768">"Katamtaman"</item>
+    <item msgid="182695359839047859">"Mababa"</item>
+    <item msgid="8577246509202964244">"Kritikal"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Tuluy-tuloy"</item>
     <item msgid="167418068739176448">"Nangungunang gawain"</item>
diff --git a/tests/CarDeveloperOptions/res/values-tl/config.xml b/tests/CarDeveloperOptions/res/values-tl/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-tl/config.xml
+++ b/tests/CarDeveloperOptions/res/values-tl/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-tl/strings.xml b/tests/CarDeveloperOptions/res/values-tl/strings.xml
index 0a405bc..f46701f 100644
--- a/tests/CarDeveloperOptions/res/values-tl/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-tl/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Gawing mas maliit o mas malaki ang text sa screen."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Paliitin"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Palakihin"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Sample na text"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"The Wonderful Wizard of Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Kabanata 11: The Wonderful Emerald City of Oz"</string>
@@ -489,7 +488,7 @@
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"Naku, hindi iyan ang sensor"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"Pindutin ang sensor sa likod ng iyong telepono. Gamitin ang hintuturo mo."</string>
     <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"Hindi nakumpleto ang pagpapatala"</string>
-    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Naabot na ang limitasyon sa oras ng pagpapatala ng fingerprint. Subukang muli."</string>
+    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Naabot na ang limitasyon sa oras ng pag-enroll ng fingerprint. Subukan ulit."</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"Hindi gumana ang pagpapatala ng fingerprint. Subukang muli o gumamit ng ibang daliri."</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"Magdagdag ng isa pa"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"Susunod"</string>
@@ -668,7 +667,6 @@
       <item quantity="one">Dapat ay wala pang <xliff:g id="NUMBER_1">%d</xliff:g> digit</item>
       <item quantity="other">Dapat ay wala pang <xliff:g id="NUMBER_1">%d</xliff:g> na digit</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Maglaman lang dapat ng mga digit na 0-9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Hindi pinapayagan ng admin ng device ang paggamit ng kamakailang PIN"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Bina-block ng iyong IT admin ang mga pangkaraniwang PIN. Sumubok ng ibang PIN."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Hindi ito maaaring magsama ng di-wastong character"</string>
@@ -699,6 +697,10 @@
       <item quantity="one">Dapat na maglaman ng kahit <xliff:g id="COUNT">%d</xliff:g> hindi titik na character lang</item>
       <item quantity="other">Dapat na maglaman ng kahit <xliff:g id="COUNT">%d</xliff:g> na hindi titik na character lang</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">Dapat ay may kahit <xliff:g id="COUNT">%d</xliff:g> hindi numerong character</item>
+      <item quantity="other">Dapat ay may kahit <xliff:g id="COUNT">%d</xliff:g> na hindi numerong character</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Hindi pinapayagan ng admin ng device ang paggamit ng kamakailang password"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Bina-block ng iyong IT admin ang mga pangkaraniwang password. Sumubok ng ibang password."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Hindi pinapayagan ang pataas, pababa, o paulit-ulit na pagkakasunod-sunod ng mga digit"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mobile"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Kung hindi available ang Wi‑Fi, gamitin ang mobile network"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Kung hindi available ang mobile network, gamitin ang Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Tumawag gamit ang Wi‑Fi. Kung mawawala ang Wi‑Fi, matatapos ang tawag."</string>
@@ -2091,7 +2096,7 @@
     <string name="accessibility_ring_vibration_title" msgid="7943341443551359985">"Pag-vibrate kapag nag-ring"</string>
     <string name="accessibility_touch_vibration_title" msgid="285890135612038092">"Pag-vibrate sa pagpindot"</string>
     <string name="accessibility_service_master_switch_title" msgid="2734791644475782924">"Gamitin ang serbisyo"</string>
-    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Gumamit ng pagwawasto ng kulay"</string>
+    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Gumamit ng pagtatama ng kulay"</string>
     <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"Gumamit ng mga caption"</string>
     <string name="accessibility_hearingaid_instruction_continue_button" msgid="4650111296711466691">"Magpatuloy"</string>
     <string name="accessibility_hearingaid_title" msgid="3700978781235124891">"Mga hearing aid"</string>
diff --git a/tests/CarDeveloperOptions/res/values-tr/arrays.xml b/tests/CarDeveloperOptions/res/values-tr/arrays.xml
index af817b5..6b1d63c 100644
--- a/tests/CarDeveloperOptions/res/values-tr/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-tr/arrays.xml
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"Asla izin verme"</item>
     <item msgid="8184570120217958741">"Her zaman izin ver"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Orta"</item>
+    <item msgid="1555861583162930714">"Düşük"</item>
+    <item msgid="1719683776264798117">"Kritik düzeyde"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normal"</item>
+    <item msgid="6107138933849816768">"Orta"</item>
+    <item msgid="182695359839047859">"Düşük"</item>
+    <item msgid="8577246509202964244">"Kritik düzeyde"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Kalıcı"</item>
     <item msgid="167418068739176448">"En üstteki etkinlik"</item>
@@ -463,8 +473,8 @@
   </string-array>
   <string-array name="wifi_metered_entries">
     <item msgid="4329206416008519163">"Otomatik olarak algıla"</item>
-    <item msgid="773943026484148895">"Sınırlı olarak ele al"</item>
-    <item msgid="1008268820118852416">"Sınırsız olarak ele al"</item>
+    <item msgid="773943026484148895">"Sınırlı gibi kullan"</item>
+    <item msgid="1008268820118852416">"Sınırsız gibi kullan"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
     <item msgid="6545683814310036454">"Rastgele MAC kullan (varsayılan)"</item>
diff --git a/tests/CarDeveloperOptions/res/values-tr/config.xml b/tests/CarDeveloperOptions/res/values-tr/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-tr/config.xml
+++ b/tests/CarDeveloperOptions/res/values-tr/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-tr/strings.xml b/tests/CarDeveloperOptions/res/values-tr/strings.xml
index 7e4ef2c..80fd9b1 100644
--- a/tests/CarDeveloperOptions/res/values-tr/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-tr/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Ekrandaki metni daha küçük veya daha büyük yapın."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Küçült"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Büyüt"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Örnek metin"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Muhteşem Oz Büyücüsü"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"11. Bölüm: Oz\'un Muhteşem Zümrüt Kenti"</string>
@@ -422,7 +421,7 @@
     <string name="security_settings_face_settings_use_face_for_apps" msgid="5479369083370664351">"Uygulamada oturum açma ve ödemeler"</string>
     <string name="security_settings_face_settings_require_attention" msgid="2755140150841557225">"Kilidi açmak için gözler açık"</string>
     <string name="security_settings_face_settings_require_attention_details" msgid="2557060433599942587">"Yüzle kimlik doğrulamayı kullanırken gözleriniz açık olmalıdır"</string>
-    <string name="security_settings_face_settings_require_confirmation" msgid="7312024271060416438">"Her zaman onay gerektir"</string>
+    <string name="security_settings_face_settings_require_confirmation" msgid="7312024271060416438">"Her zaman onay gerekli"</string>
     <string name="security_settings_face_settings_require_confirmation_details" msgid="8740564864091803429">"Uygulamalarda kimlik doğrulaması yapılırken her zaman onay gerektir"</string>
     <string name="security_settings_face_settings_remove_face_data" msgid="2821359954483136239">"Yüz verisini kaldır"</string>
     <string name="security_settings_face_settings_footer" msgid="4627175759990550715">"Yüzünüzü kullanarak cihazınızın kilidini açabilir ve uygulamalara erişebilirsiniz. "<annotation id="url">"Daha fazla bilgi"</annotation></string>
@@ -668,7 +667,6 @@
       <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> basamaktan az olmalıdır</item>
       <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> basamaktan az olmalıdır</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Yalnızca 0-9 arasındaki rakamları içermelidir"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Cihaz yöneticisi yakın zamanda kullanılan bir PIN\'e izin vermiyor"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Yaygın olarak kullanılan PIN\'ler BT yöneticiniz tarafından engellendi. Farklı bir PIN deneyin."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Burada geçersiz bir karakter kullanılamaz"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Harf olmayan en az <xliff:g id="COUNT">%d</xliff:g> karakter içermelidir</item>
       <item quantity="one">Harf olmayan en az 1 karakter içermelidir</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Rakam olmayan en az <xliff:g id="COUNT">%d</xliff:g> karakter içermelidir</item>
+      <item quantity="one">Rakam olmayan en az 1 karakter içermelidir</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Cihaz yöneticisi yakın zamanda kullanılan bir şifreye izin vermiyor"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Yaygın olarak kullanılan şifreler BT yöneticiniz tarafından engellendi. Farklı bir şifre deneyin."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Artan, azalan veya tekrar eden rakam dizisine izin verilmiyor"</string>
@@ -846,7 +848,7 @@
     <string name="wifi_in_airplane_mode" msgid="4729571191578262246">"Uçak modunda"</string>
     <string name="wifi_notify_open_networks" msgid="4782239203624619655">"Açık ağ bildirimi"</string>
     <string name="wifi_notify_open_networks_summary" msgid="1383681260705466715">"Herkese açık yüksek kaliteli bir ağ kullanılabilir olduğunda bildir"</string>
-    <string name="wifi_wakeup" msgid="4963732992164721548">"Kablosuz özelliğini otomatik olarak aç"</string>
+    <string name="wifi_wakeup" msgid="4963732992164721548">"Kablosuz ağı otomatik olarak aç"</string>
     <string name="wifi_wakeup_summary" msgid="1152699417411690">"Ev ağınız gibi yüksek kaliteli kayıtlı ağların yakınında olduğunuzda kablosuz özelliği tekrar açılır"</string>
     <string name="wifi_wakeup_summary_no_location" msgid="3007457288587966962">"Konum kapalı olduğundan kullanılamıyor. "<annotation id="link">"Konum"</annotation>"\'u açın."</string>
     <string name="wifi_wakeup_summary_scanning_disabled" msgid="6820040651529910914">"Kablosuz ağ taraması kapalı olduğu için kullanılamıyor"</string>
@@ -875,7 +877,7 @@
     <string name="wifi_add_network" msgid="4094957940791876640">"Ağ ekle"</string>
     <string name="wifi_configure_settings_preference_title" msgid="2678534679408777268">"Kablosuz tercihleri"</string>
     <string name="wifi_configure_settings_preference_summary_wakeup_on" msgid="5714892572614655675">"Kablosuz özelliği otomatik olarak tekrar açılır"</string>
-    <string name="wifi_configure_settings_preference_summary_wakeup_off" msgid="286904094152909651">"Kablosuz özelliği otomatik olarak tekrar açılmaz"</string>
+    <string name="wifi_configure_settings_preference_summary_wakeup_off" msgid="286904094152909651">"Kablosuz ağ otomatik olarak tekrar açılmaz"</string>
     <string name="wifi_access_points" msgid="1647976498906871869">"Kablosuz ağlar"</string>
     <string name="wifi_menu_more_options" msgid="8318269834264035524">"Diğer seçenekler"</string>
     <string name="wifi_menu_p2p" msgid="4945665601551289791">"Kablosuz Doğrudan Bağlantı"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Kablosuz"</item>
+    <item msgid="2271962426654621656">"Mobil"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Kablosuz ağ bağlantısı kullanılamıyorsa mobil ağı kullanın"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Mobil ağ kullanılamıyorsa kablosuz ağı kullan"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Kablosuz ağ üzerinden çağrı. Kablosuz ağ bağlantısı kesilirse çağrı sonlandırılır."</string>
@@ -2293,8 +2298,8 @@
       <item quantity="one">%1$s yakın zamanda kısıtlandı</item>
     </plurals>
     <plurals name="battery_tip_restrict_summary" formatted="false" msgid="984148373944071669">
-      <item quantity="other">%2$d uygulama yüksek düzeyde arka plan pil kullanımına yol açıyor</item>
-      <item quantity="one">%1$s yüksek düzeyde arka plan pil kullanımına yol açıyor</item>
+      <item quantity="other">%2$d uygulama arka planda yüksek düzeyde pil kullanıyor</item>
+      <item quantity="one">%1$s arka planda yüksek düzeyde pil kullanıyor</item>
     </plurals>
     <plurals name="battery_tip_restrict_handled_summary" formatted="false" msgid="469696766640020557">
       <item quantity="other">Bu uygulamalar arka planda çalışamaz</item>
@@ -2447,7 +2452,7 @@
     <string name="battery_saver_auto_routine" msgid="886514412067906980">"Rutininize göre"</string>
     <string name="battery_saver_auto_percentage" msgid="5791982309331921556">"Yüzdeye göre"</string>
     <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"Piliniz, genellikle şarj ettiğiniz saatten önce bitecek gibiyse Pil Tasarrufu etkinleştirilir"</string>
-    <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"<xliff:g id="PERCENT">%1$s</xliff:g> düzeyinde açılacak"</string>
+    <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"Pil <xliff:g id="PERCENT">%1$s</xliff:g> olduğunda açılacak"</string>
     <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"Bir plan belirleyin"</string>
     <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"Tam olarak şarj edildiğinde kapat"</string>
     <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"Pil Tasarrufu, telefonunuzun gücü <xliff:g id="PERCENT">%1$s</xliff:g> olduğunda kapanır"</string>
@@ -2865,7 +2870,7 @@
     <string name="user_add_user_item_title" msgid="6835385073795492410">"Kullanıcı"</string>
     <string name="user_add_profile_item_title" msgid="4932743891449790664">"Kısıtlı profil"</string>
     <string name="user_add_user_title" msgid="2320897397066676472">"Yeni kullanıcı eklensin mi?"</string>
-    <string name="user_add_user_message_long" msgid="686637203224195465">"Ek kullanıcılar oluşturarak bu cihazı başkalarıyla paylaşabilirsiniz. Her kullanıcının uygulamalarla, duvar kağıdıyla ve başka ayarlarla özelleştirebileceği kendi alanı olur. Kullanıcılar ayrıca kablosuz ağ gibi herkesi etkileyen cihaz ayarlarını değiştirebilirler.\n\nYeni bir kullanıcı eklediğinizde, ilgili kişinin kendi alanını ayarlaması gerekir.\n\nHer kullanıcı diğer tüm kullanıcılar için uygulamaları güncelleyebilir."</string>
+    <string name="user_add_user_message_long" msgid="686637203224195465">"Ek kullanıcılar oluşturarak bu cihazı başkalarıyla paylaşabilirsiniz. Her kullanıcının uygulamalarla, duvar kağıdıyla ve başka ayarlarla özelleştirebileceği kendi alanı olur. Kullanıcılar ayrıca kablosuz ağ gibi herkesi etkileyen cihaz ayarlarını değiştirebilirler.\n\nYeni bir kullanıcı eklediğinizde, ilgili kişinin kendi alanını ayarlaması gerekir.\n\nHer kullanıcı diğer tüm kullanıcılar için uygulamaları güncelleyebilir. Erişilebilirlik ayarları ve hizmetleri yeni kullanıcıya aktarılamayabilir."</string>
     <string name="user_add_user_message_short" msgid="1802594476285458254">"Yeni bir kullanıcı eklediğinizde, bu kişinin kendi alanını ayarlaması gerekir.\n\nHerhangi bir kullanıcı, diğer tüm kullanıcılar için uygulamaları güncelleyebilir."</string>
     <string name="user_setup_dialog_title" msgid="6748950002206392396">"Kullanıcı şimdi ayarlansın mı?"</string>
     <string name="user_setup_dialog_message" msgid="2988559933258353919">"İlgili kişinin cihazı almak ve kendi alanını ayarlamak için müsait olduğundan emin olun"</string>
@@ -3706,7 +3711,7 @@
     <string name="high_power_off" msgid="5906679734326490426">"Pil kullanımı optimize ediliyor"</string>
     <string name="high_power_system" msgid="739584574711292753">"Pil optimizasyonu kullanılamıyor"</string>
     <string name="high_power_desc" msgid="333756885680362741">"Pil optimizasyonu uygulanmasın. Bu seçenek, pilinizi daha hızlı tüketebilir."</string>
-    <string name="high_power_prompt_title" msgid="2805745781720454052">"Uygulamanın her zaman arka planda çalıştırılmasına izin verilsin mi?"</string>
+    <string name="high_power_prompt_title" msgid="2805745781720454052">"Uygulama arka planda çalışmaya devam etsin mi?"</string>
     <string name="high_power_prompt_body" msgid="8067395096053552289">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasının her zaman arka planda çalıştırılmasına izin vermeniz pil ömrünü kısaltabilir. \n\nBunu daha sonra Ayarlar &gt; Uygulamalar ve bildirimler seçeneğinden değiştirebilirsiniz."</string>
     <string name="battery_summary" msgid="4345690800899981339">"Son kez tamamen şarj olduktan sonra <xliff:g id="PERCENTAGE">%1$s</xliff:g> kullanıldı"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"Güç yönetimi"</string>
@@ -4318,7 +4323,7 @@
     <string name="battery_suggestion_title" product="device" msgid="765005476863631528">"Cihazın pil ömrünü uzatın"</string>
     <string name="battery_suggestion_title" product="default" msgid="3295786171830183688">"Telefonun pil ömrünü uzatın"</string>
     <string name="battery_suggestion_summary" msgid="2669070349482656490"></string>
-    <string name="gesture_prevent_ringing_screen_title" msgid="4173494225145223638">"Zilin çalmasını önle"</string>
+    <string name="gesture_prevent_ringing_screen_title" msgid="4173494225145223638">"Zilin çalmasını engelle"</string>
     <string name="gesture_prevent_ringing_title" msgid="8827963588425673557">"Güç ve Sesi Artırma düğmelerine birlikte basın:"</string>
     <string name="gesture_prevent_ringing_sound_title" msgid="8642330448721033641">"Zilin çalmasını engelleme kısayolu"</string>
     <string name="prevent_ringing_option_vibrate" msgid="6456505293904544108">"Titret"</string>
diff --git a/tests/CarDeveloperOptions/res/values-uk/arrays.xml b/tests/CarDeveloperOptions/res/values-uk/arrays.xml
index 2409764..912df33 100644
--- a/tests/CarDeveloperOptions/res/values-uk/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-uk/arrays.xml
@@ -125,7 +125,7 @@
     <item msgid="1709949377823900951">"Слабкий"</item>
     <item msgid="7882129634982603782">"Слабкий"</item>
     <item msgid="6457357501905996224">"Задовільний"</item>
-    <item msgid="405271628162918841">"Добрий"</item>
+    <item msgid="405271628162918841">"Хороший"</item>
     <item msgid="999948812884919584">"Відмінний"</item>
   </string-array>
   <string-array name="data_usage_data_range">
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"працювати у фоновому режимі"</item>
     <item msgid="6423861043647911030">"спеціальні можливості: гучність"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Місцезнаходження"</item>
+    <item msgid="6656077694190491067">"Місцезнаходження"</item>
+    <item msgid="8790228218278477369">"Місцезнаходження"</item>
+    <item msgid="7836406246005211990">"Вібросигнал"</item>
+    <item msgid="3951439024549922598">"Читати контакти"</item>
+    <item msgid="8802152411647068">"Змінювати контакти"</item>
+    <item msgid="229544934599698735">"Читати журнал викликів"</item>
+    <item msgid="7396102294405899613">"Змінювати журнал викликів"</item>
+    <item msgid="3597797992398484655">"Перегляд календаря"</item>
+    <item msgid="2705975774250907343">"Змінювати календар"</item>
+    <item msgid="4668747371441932697">"Місцезнаходження"</item>
+    <item msgid="1487578921720243646">"Публікувати сповіщення"</item>
+    <item msgid="4636080349724146638">"Місцезнаходження"</item>
+    <item msgid="673510900286463926">"Телефонувати"</item>
+    <item msgid="542083422784609790">"Читати SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Писати SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Отримувати SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Отримувати SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Отримувати SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Отримувати SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Надсилати SMS/MMS"</item>
+    <item msgid="4726682243833913568">"Читати SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Писати SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Змінювати налаштування"</item>
+    <item msgid="8705854389991425629">"Відображати зверху"</item>
+    <item msgid="5861356020344153651">"Отримувати доступ до сповіщень"</item>
+    <item msgid="78432174621628659">"Камера"</item>
+    <item msgid="3986116419882154794">"Записувати аудіо"</item>
+    <item msgid="4516840825756409490">"Відтворювати аудіо"</item>
+    <item msgid="6811712502798183957">"Читати буфер обміну"</item>
+    <item msgid="2780369012602289114">"Змінювати буфер обміну"</item>
+    <item msgid="2331359440170850868">"Кнопки медіа"</item>
+    <item msgid="6133599737122751231">"Активізація звуку"</item>
+    <item msgid="6844485713404805301">"Загальна гучність"</item>
+    <item msgid="1600379420669104929">"Гучність голосу"</item>
+    <item msgid="6296768210470214866">"Гучність дзвінка"</item>
+    <item msgid="510690696071629241">"Гучність медіа"</item>
+    <item msgid="406861638631430109">"Гучність будильника"</item>
+    <item msgid="4715864795872233884">"Гучність сповіщень"</item>
+    <item msgid="2311478519251301183">"Гучність Bluetooth"</item>
+    <item msgid="5133991377896747027">"Залишати активним"</item>
+    <item msgid="2464189519136248621">"Місцезнаходження"</item>
+    <item msgid="2062677934050803037">"Місцезнаходження"</item>
+    <item msgid="1735171933192715957">"Отримати статистику використання"</item>
+    <item msgid="1014093788778383554">"Вимкнути або ввімкнути мікрофон"</item>
+    <item msgid="4199297950608622850">"Показувати підказки"</item>
+    <item msgid="2527962435313398821">"Транслювати вміст"</item>
+    <item msgid="5117506254221861929">"Активувати VPN"</item>
+    <item msgid="8291198322681891160">"Написаний фоновий малюнок"</item>
+    <item msgid="7106921284621230961">"Допоміжна структура"</item>
+    <item msgid="4496533640894624799">"Допоміжний знімок екрана"</item>
+    <item msgid="2598847264853993611">"Переглядати статус телефона"</item>
+    <item msgid="9215610846802973353">"Додавати голосову пошту"</item>
+    <item msgid="9186411956086478261">"Використовувати протокол SIP"</item>
+    <item msgid="6884763100104539558">"Обробляти вихідні виклики"</item>
+    <item msgid="125513972170580692">"Відбиток пальця"</item>
+    <item msgid="2556071024281275619">"Датчики на тілі"</item>
+    <item msgid="617168514928339387">"Переглядати повідомлення Cell Broadcast"</item>
+    <item msgid="7134693570516523585">"Фіктивне місцезнаходження"</item>
+    <item msgid="7224489175375229399">"Переглядати дані про пам’ять"</item>
+    <item msgid="8472735063903258202">"Додавати дані в пам’ять і змінювати їх"</item>
+    <item msgid="4069276819909595110">"Вмикати екран"</item>
+    <item msgid="1228338896751121025">"Отримувати дані облікових записів"</item>
+    <item msgid="3181581793459233672">"Працювати у фоновому режимі"</item>
+    <item msgid="2340936043025374076">"Спеціальні можливості: гучність"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Коротка"</item>
     <item msgid="4816511817309094890">"Звичайне сповіщення"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Ніколи не дозволяти"</item>
     <item msgid="8184570120217958741">"Завжди дозволяти"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Звичайний"</item>
+    <item msgid="5101233285497327432">"Прийнятно"</item>
+    <item msgid="1555861583162930714">"Низька"</item>
+    <item msgid="1719683776264798117">"Критичний"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Нормальний"</item>
+    <item msgid="6107138933849816768">"Середній"</item>
+    <item msgid="182695359839047859">"Низька"</item>
+    <item msgid="8577246509202964244">"Критичний"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Постійний"</item>
     <item msgid="167418068739176448">"Перші дії"</item>
diff --git a/tests/CarDeveloperOptions/res/values-uk/config.xml b/tests/CarDeveloperOptions/res/values-uk/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-uk/config.xml
+++ b/tests/CarDeveloperOptions/res/values-uk/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-uk/strings.xml b/tests/CarDeveloperOptions/res/values-uk/strings.xml
index b166589..19a4068 100644
--- a/tests/CarDeveloperOptions/res/values-uk/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-uk/strings.xml
@@ -85,8 +85,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Збільшуйте або зменшуйте текст на екрані."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Зменшити"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Збільшити"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Зразок тексту"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Чарівник країни Оз"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Глава 11. Дивовижне Смарагдове місто країни Оз"</string>
@@ -425,7 +424,7 @@
     <string name="security_settings_face_enroll_done" msgid="5409739233373490971">"Готово"</string>
     <string name="security_settings_face_settings_use_face_category" msgid="1586532139528115416">"Налаштування за обличчям"</string>
     <string name="security_settings_face_settings_use_face_unlock_phone" msgid="318274519126401671">"Пристрій розблоковується"</string>
-    <string name="security_settings_face_settings_use_face_for_apps" msgid="5479369083370664351">"Вхід у додатки та платежі"</string>
+    <string name="security_settings_face_settings_use_face_for_apps" msgid="5479369083370664351">"Вхід у додатки й оплата"</string>
     <string name="security_settings_face_settings_require_attention" msgid="2755140150841557225">"Розблоковувати, коли очі відкриті"</string>
     <string name="security_settings_face_settings_require_attention_details" msgid="2557060433599942587">"Використовуючи автентифікацію облич, відкрийте очі"</string>
     <string name="security_settings_face_settings_require_confirmation" msgid="7312024271060416438">"Завжди просити підтвердження"</string>
@@ -684,7 +683,6 @@
       <item quantity="many">Може містити до <xliff:g id="NUMBER_1">%d</xliff:g> цифр</item>
       <item quantity="other">Може містити до <xliff:g id="NUMBER_1">%d</xliff:g> цифри</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Має містити лише цифри від 0 до 9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Адміністратор пристрою не дозволяє використовувати останній PIN-код"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"IT-адміністратор заблокував загальні PIN-коди. Введіть інший PIN-код."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Не може містити недійсних символів"</string>
@@ -727,6 +725,12 @@
       <item quantity="many">Має містити принаймні <xliff:g id="COUNT">%d</xliff:g> символів, які не є літерами</item>
       <item quantity="other">Має містити принаймні <xliff:g id="COUNT">%d</xliff:g> символу, які не є літерами</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">Має містити, окрім цифр, принаймні <xliff:g id="COUNT">%d</xliff:g> інший символ</item>
+      <item quantity="few">Має містити, окрім цифр, принаймні <xliff:g id="COUNT">%d</xliff:g> інші символи</item>
+      <item quantity="many">Має містити, окрім цифр, принаймні <xliff:g id="COUNT">%d</xliff:g> інших символів</item>
+      <item quantity="other">Має містити, окрім цифр, принаймні <xliff:g id="COUNT">%d</xliff:g> іншого символу</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Адміністратор пристрою не дозволяє використовувати останній пароль"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"IT-адміністратор заблокував загальні паролі. Введіть інший пароль."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Цифри в порядку зростання чи спадання та повторювані цифри заборонені"</string>
@@ -831,7 +835,7 @@
     <string name="wifi_display_settings_title" msgid="8718182672694575456">"Трансляція"</string>
     <string name="wifi_display_enable_menu_item" msgid="4578340247147692250">"Увімкнути бездротовий екран"</string>
     <string name="wifi_display_no_devices_found" msgid="186501729518830451">"Не знайдено пристроїв поблизу."</string>
-    <string name="wifi_display_status_connecting" msgid="3799827425457383349">"Під’єднуються"</string>
+    <string name="wifi_display_status_connecting" msgid="3799827425457383349">"Підключення"</string>
     <string name="wifi_display_status_connected" msgid="85692409327461403">"Під’єднані"</string>
     <string name="wifi_display_status_in_use" msgid="7646114501132773174">"Використовується"</string>
     <string name="wifi_display_status_not_available" msgid="5600448733204688205">"Недоступно"</string>
@@ -948,16 +952,16 @@
     <string name="please_select_phase2" msgid="5848080896810435677">"Друга фаза автентифікації"</string>
     <string name="wifi_eap_ca_cert" msgid="1496395241849383785">"Сертифікат ЦС"</string>
     <string name="wifi_eap_domain" msgid="3298302320003640130">"Домен"</string>
-    <string name="wifi_eap_user_cert" msgid="6786839531765719173">"Сертиф. корист-ча"</string>
-    <string name="wifi_eap_identity" msgid="5280457017705738773">"Ідентифік."</string>
-    <string name="wifi_eap_anonymous" msgid="6352344972490839958">"Анонімна ідентиф-ція"</string>
+    <string name="wifi_eap_user_cert" msgid="6786839531765719173">"Сертифікат користувача"</string>
+    <string name="wifi_eap_identity" msgid="5280457017705738773">"Ідентифікація"</string>
+    <string name="wifi_eap_anonymous" msgid="6352344972490839958">"Анонімна ідентифікація"</string>
     <string name="wifi_password" msgid="6942983531275177771">"Пароль"</string>
     <string name="wifi_show_password" msgid="7878398590772942202">"Показати пароль"</string>
     <string name="wifi_ap_band_config" msgid="6565016368079288433">"Виберіть діапазон частот точки доступу"</string>
     <string name="wifi_ap_choose_auto" msgid="7927637960569365785">"Автоматично"</string>
     <string name="wifi_ap_choose_2G" msgid="43198403259714736">"Діапазон 2,4 ГГц"</string>
     <string name="wifi_ap_choose_5G" msgid="2624859713183683146">"Діапазон 5 ГГц"</string>
-    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"Бажано використовувати діапазон 5,0 ГГц"</string>
+    <string name="wifi_ap_prefer_5G" msgid="8339172330471170142">"Діапазон 5,0 ГГц (рекомендовано)"</string>
     <string name="wifi_ap_2G" msgid="5793110086517338494">"2,4 ГГц"</string>
     <string name="wifi_ap_5G" msgid="4584892544393675403">"5 ГГц"</string>
     <string name="wifi_ap_band_select_one" msgid="4409754936554360355">"Виберіть принаймні один діапазон для точки доступу Wi-Fi:"</string>
@@ -1134,7 +1138,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Мобільні"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Використовувати мобільну мережу, коли немає Wi-Fi"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Використовувати Wi-Fi, якщо немає мобільної мережі"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Телефонувати через Wi-Fi. У разі втрати з’єднання з Wi-Fi виклик буде завершено."</string>
@@ -1142,7 +1149,7 @@
     <string name="wifi_calling_off_explanation_2" msgid="8648609693875720408"></string>
     <string name="emergency_address_title" msgid="5779915349686787024">"Екстрена адреса"</string>
     <string name="emergency_address_summary" msgid="478668478569851714">"Використовується як адреса, коли ви телефонуєте в екстрені служби через Wi-Fi"</string>
-    <string name="private_dns_help_message" msgid="7633526525131196650"><annotation id="url">"Докладніше"</annotation>" про функції приватної DNS"</string>
+    <string name="private_dns_help_message" msgid="7633526525131196650"><annotation id="url">"Докладніше"</annotation>" про приватний DNS-сервер"</string>
     <string name="wifi_calling_pref_managed_by_carrier" msgid="5458050015417972072">"Налаштуванням керує оператор"</string>
     <string name="wifi_calling_settings_activation_instructions" msgid="2863642668648110908">"Активувати дзвінки через Wi-Fi"</string>
     <string name="wifi_calling_turn_on" msgid="1212277809455062043">"Увімкнути дзвінки через Wi-Fi"</string>
@@ -1239,7 +1246,7 @@
     <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"Вимкнено"</string>
     <string name="adaptive_sleep_description" msgid="812673735459170009">"Не дає екрану вимикатись, якщо ви на нього дивитесь."</string>
     <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Розпізнавання уваги за допомогою передньої камери визначає, чи дивиться користувач на екран. Ця функція працює лише на пристрої, не зберігає зображень і не надсилає їх у Google."</string>
-    <string name="night_display_title" msgid="1305002424893349814">"Нічний режим"</string>
+    <string name="night_display_title" msgid="1305002424893349814">"Нічний екран"</string>
     <string name="night_display_text" msgid="5330502493684652527">"У нічному режимі екран набуває бурштинового відтінку. Це знімає напруження очей при тьмяному освітленні та допомагає легше заснути."</string>
     <string name="night_display_auto_mode_title" msgid="8493573087102481588">"Розклад"</string>
     <string name="night_display_auto_mode_never" msgid="2897444637217807088">"Ніколи"</string>
@@ -1263,7 +1270,7 @@
     <string name="night_display_activation_off_twilight" msgid="6846727701281556110">"Вимкнути до заходу сонця"</string>
     <string name="night_display_activation_on_custom" msgid="4761140206778957611">"Увімкнути до <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="night_display_activation_off_custom" msgid="4207238846687792731">"Вимкнути до <xliff:g id="ID_1">%1$s</xliff:g>"</string>
-    <string name="night_display_not_currently_on" msgid="1436588493764429281">"Нічний режим не ввімкнено"</string>
+    <string name="night_display_not_currently_on" msgid="1436588493764429281">"Нічний екран не ввімкнено"</string>
     <string name="screen_timeout" msgid="1700950247634525588">"Режим сну"</string>
     <string name="screen_timeout_title" msgid="150117777762864112">"Вимикати екран"</string>
     <string name="screen_timeout_summary" msgid="8644192861778491060">"Коли минає <xliff:g id="TIMEOUT_DESCRIPTION">%1$s</xliff:g> бездіяльності"</string>
@@ -1678,8 +1685,8 @@
     <string name="mobile_insert_sim_card" msgid="7594550403454243732">"Вставте SIM-карту та перезапустіть"</string>
     <string name="mobile_connect_to_internet" msgid="6031886097365170913">"Під’єднайтеся до Інтернету"</string>
     <string name="location_title" msgid="8664674161765477168">"Моє місцезнах."</string>
-    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"Місцезнах.для робочого профілю"</string>
-    <string name="location_app_level_permissions" msgid="1298041503927632960">"Дозвіл додаткам"</string>
+    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"Геодані для робочого профілю"</string>
+    <string name="location_app_level_permissions" msgid="1298041503927632960">"Дозвіл для додатків"</string>
     <string name="location_app_permission_summary_location_off" msgid="541372845344796336">"Передавання геоданих вимкнено"</string>
     <plurals name="location_app_permission_summary_location_on" formatted="false" msgid="7904821382328758218">
       <item quantity="one">Додатків із необмеженим доступом: <xliff:g id="BACKGROUND_LOCATION_APP_COUNT_2">%1$d</xliff:g> з <xliff:g id="TOTAL_LOCATION_APP_COUNT_3">%2$d</xliff:g></item>
@@ -1689,7 +1696,7 @@
     </plurals>
     <string name="location_category_recent_location_access" msgid="286059523360285026">"Доступ до останніх геоданих"</string>
     <string name="location_recent_location_access_view_details" msgid="2051602261436245905">"Переглянути деталі"</string>
-    <string name="location_no_recent_apps" msgid="77502059586413278">"Жодна програма не запитувала місцезнаходження останнім часом"</string>
+    <string name="location_no_recent_apps" msgid="77502059586413278">"Останнім часом додатки не запитували доступ до геоданих"</string>
     <string name="location_no_recent_accesses" msgid="6289916310397279890">"Немає додатків, які нещодавно отримували доступ до геоданих"</string>
     <string name="location_high_battery_use" msgid="7177199869979522663">"Значне використання заряду"</string>
     <string name="location_low_battery_use" msgid="5030448574501435888">"Низьке використання заряду"</string>
@@ -1800,7 +1807,7 @@
     <string name="lockpattern_settings_enable_visible_pattern_title" msgid="4935583222709647096">"Зробити ключ видимим"</string>
     <string name="lockpattern_settings_enable_visible_pattern_title_profile" msgid="5338893138982642228">"Зробити ключ профілю видимим"</string>
     <string name="lockpattern_settings_enable_tactile_feedback_title" msgid="3203621862806531947">"Вібрація під час дотику"</string>
-    <string name="lockpattern_settings_enable_power_button_instantly_locks" msgid="5890335732200257777">"Блокування кнопкою живлення"</string>
+    <string name="lockpattern_settings_enable_power_button_instantly_locks" msgid="5890335732200257777">"Блокувати кнопкою живлення"</string>
     <string name="lockpattern_settings_power_button_instantly_locks_summary" msgid="1279989004145567840">"Якщо <xliff:g id="TRUST_AGENT_NAME">%1$s</xliff:g> не запобігає блокуванню"</string>
     <string name="lockpattern_settings_choose_lock_pattern" msgid="9042142745571386381">"Налашт. ключ розблок."</string>
     <string name="lockpattern_settings_change_lock_pattern" msgid="1456643060737114885">"Змінити ключ розблокув."</string>
@@ -2666,7 +2673,7 @@
     <string name="work_mode_label" msgid="6845849194740195757">"Робочий профіль"</string>
     <string name="work_mode_on_summary" msgid="1682781113156323592">"Профілем керує ваша організація"</string>
     <string name="work_mode_off_summary" msgid="1688885392211178315">"Додатки й сповіщення вимкнено"</string>
-    <string name="remove_managed_profile_label" msgid="4625542553784793536">"Видалити службовий профіль"</string>
+    <string name="remove_managed_profile_label" msgid="4625542553784793536">"Видалити робочий профіль"</string>
     <string name="background_data" msgid="8275750862371471171">"Фонові дані"</string>
     <string name="background_data_summary" msgid="799640633948841990">"Програми можуть будь-коли синхроніз., надсил. й отрим. дані"</string>
     <string name="background_data_dialog_title" msgid="8306650658158895976">"Вимкн. фонові дані?"</string>
@@ -2987,7 +2994,7 @@
     <string name="application_restrictions" msgid="6871981013736536763">"Дозволи для програм і вмісту"</string>
     <string name="apps_with_restrictions_header" msgid="8656739605673756176">"Програми з обмеженнями"</string>
     <string name="apps_with_restrictions_settings_button" msgid="5065896213467171744">"Розгорнути налаштув. програм"</string>
-    <string name="nfc_payment_settings_title" msgid="5070077706735415291">"Натиснути й оплатити"</string>
+    <string name="nfc_payment_settings_title" msgid="5070077706735415291">"Експрес-платежі"</string>
     <string name="nfc_payment_how_it_works" msgid="7607901964687787177">"Як це працює"</string>
     <string name="nfc_payment_no_apps" msgid="8844440783395420860">"Оплачуйте покупки за допомогою телефона"</string>
     <string name="nfc_payment_default" msgid="7869273092463612271">"Додаток для платежів за умовчанням"</string>
@@ -4021,9 +4028,9 @@
     <string name="condition_device_muted_summary" msgid="3101055117680109021">"Для викликів і сповіщень"</string>
     <string name="condition_device_vibrate_title" msgid="5712659354868872338">"Лише вібрація"</string>
     <string name="condition_device_vibrate_summary" msgid="9073880731894828604">"Для викликів і сповіщень"</string>
-    <string name="night_display_suggestion_title" msgid="4222839610992282188">"Налаштувати графік нічного режиму"</string>
+    <string name="night_display_suggestion_title" msgid="4222839610992282188">"Налаштувати графік функції \"Нічний екран\""</string>
     <string name="night_display_suggestion_summary" msgid="1754361016383576916">"Автоматично відтіняти екран щовечора"</string>
-    <string name="condition_night_display_title" msgid="9171491784857160135">"Нічне освітлення ввімкнено"</string>
+    <string name="condition_night_display_title" msgid="9171491784857160135">"Нічний екран увімкнено"</string>
     <string name="condition_night_display_summary" msgid="7885776986937527558">"Відтінок екрана змінено на бурштиновий"</string>
     <string name="condition_grayscale_title" msgid="1226351649203551299">"Відтінки сірого"</string>
     <string name="condition_grayscale_summary" msgid="749172886527349546">"Відображати все в сірому кольорі"</string>
@@ -4233,10 +4240,10 @@
       <item quantity="other"><xliff:g id="NUMBER">%s</xliff:g> секунди</item>
     </plurals>
     <string name="automatic_storage_manager_settings" msgid="2403621409625820182">"Керувати сховищем"</string>
-    <string name="automatic_storage_manager_text" msgid="4270379105066667493">"Щоб звільнити місце, диспетчер пам’яті видаляє з пристрою резервні копії фото й відео."</string>
+    <string name="automatic_storage_manager_text" msgid="4270379105066667493">"Щоб звільнити місце, менеджер сховища видаляє з пристрою фото й відео, для яких є резервні копії."</string>
     <string name="automatic_storage_manager_days_title" msgid="1783767804707813799">"Видалити фото й відео"</string>
-    <string name="automatic_storage_manager_preference_title" msgid="4668642150512639466">"Диспетчер пам’яті"</string>
-    <string name="automatic_storage_manager_master_switch_title" msgid="1456978117739582562">"Використовувати диспетчер пам’яті"</string>
+    <string name="automatic_storage_manager_preference_title" msgid="4668642150512639466">"Менеджер сховища"</string>
+    <string name="automatic_storage_manager_master_switch_title" msgid="1456978117739582562">"Використовувати менеджер сховища"</string>
     <string name="deletion_helper_automatic_title" msgid="4370975149425263205">"Автоматично"</string>
     <string name="deletion_helper_manual_title" msgid="1011785013431162078">"Вручну"</string>
     <string name="deletion_helper_preference_title" msgid="797270307034242206">"Звільнити місце"</string>
@@ -4269,7 +4276,7 @@
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"Торкніться, щоб перевірити пристрій"</string>
     <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"Щоб перевірити час, сповіщення та іншу інформацію, торкніться екрана."</string>
     <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"Використовувати відбиток для перегляду сповіщень"</string>
-    <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"Гортання сканером"</string>
+    <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"Сканер відбитків"</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"Щоб переглянути сповіщення, проведіть пальцем униз по сканеру відбитків на задній панелі телефона."</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="tablet" msgid="3480057984564476283">"Щоб переглянути сповіщення, проведіть пальцем униз по сканеру відбитків на задній панелі планшета."</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="device" msgid="7950264130913070035">"Щоб переглянути сповіщення, проведіть пальцем униз по сканеру відбитків на задній панелі пристрою."</string>
@@ -4287,7 +4294,7 @@
     <string name="web_action_section_title" msgid="5563229447734734662">"Додатки з миттєвим запуском"</string>
     <string name="instant_apps_settings" msgid="879003203555847537">"Параметри додатків із миттєвим запуском"</string>
     <string name="domain_url_section_title" msgid="206403507921518321">"Установлені додатки"</string>
-    <string name="automatic_storage_manager_activation_warning" msgid="2630083316417707308">"Зараз пам’яттю керує диспетчер пам’яті"</string>
+    <string name="automatic_storage_manager_activation_warning" msgid="2630083316417707308">"Пам’ять пристрою тепер керується менеджером сховища"</string>
     <string name="account_for_section_header" msgid="5975241715840642563">"Облікові записи (<xliff:g id="USER_NAME">%1$s</xliff:g>)"</string>
     <string name="configure_section_header" msgid="6988981883075615136">"Налаштування"</string>
     <string name="auto_sync_account_title" msgid="2394463123733529506">"Автоматично синхронізувати дані"</string>
@@ -4411,11 +4418,11 @@
     <string name="default_theme" msgid="5986996377385956138">"За умовчанням"</string>
     <string name="show_operator_name_title" msgid="5056163028128447308">"Назва мережі"</string>
     <string name="show_operator_name_summary" msgid="6352180285743777497">"Показувати назву мережі в рядку стану"</string>
-    <string name="storage_manager_indicator" msgid="4255140732848476875">"Диспетчер пам’яті: <xliff:g id="STATUS">^1</xliff:g>"</string>
+    <string name="storage_manager_indicator" msgid="4255140732848476875">"Менеджер сховища: <xliff:g id="STATUS">^1</xliff:g>"</string>
     <string name="storage_manager_indicator_off" msgid="6404056007102580777">"Вимкнено"</string>
     <string name="storage_manager_indicator_on" msgid="5295306384982062320">"Увімкнено"</string>
     <string name="install_type_instant" msgid="6248487669862821874">"Додаток із миттєвим запуском"</string>
-    <string name="automatic_storage_manager_deactivation_warning" msgid="7867793739491286374">"Вимкнути диспетчер пам’яті?"</string>
+    <string name="automatic_storage_manager_deactivation_warning" msgid="7867793739491286374">"Вимкнути менеджер сховища?"</string>
     <string name="storage_movies_tv" msgid="7282484273991655296">"Фільми й серіали"</string>
     <string name="carrier_provisioning" msgid="3309125279191534469">"Інформація про ініціалізацію оператора"</string>
     <string name="trigger_carrier_provisioning" msgid="6284005970057901477">"Активатор ініціалізації оператора"</string>
@@ -4457,7 +4464,7 @@
     <string name="change_wifi_state_title" msgid="5140754955787584174">"Керування Wi-Fi"</string>
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"Дозволити додатку керувати Wi-Fi"</string>
     <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"Дозволити цьому додатку вмикати чи вимикати Wi-Fi, шукати мережі Wi-Fi та підключатися до них, додавати або видаляти мережі чи запускати лише локальну точку доступу"</string>
-    <string name="media_output_title" msgid="8710632337456601848">"Відтворювати медіа-вміст у додатку"</string>
+    <string name="media_output_title" msgid="8710632337456601848">"Відтворення медіаконтенту"</string>
     <string name="media_output_default_summary" msgid="3159237976830415584">"Цей пристрій"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"Телефон"</string>
     <string name="media_output_summary" product="tablet" msgid="6672024060360538526">"Планшет"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ur/arrays.xml b/tests/CarDeveloperOptions/res/values-ur/arrays.xml
index e35712a..6c63b7b 100644
--- a/tests/CarDeveloperOptions/res/values-ur/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-ur/arrays.xml
@@ -38,7 +38,16 @@
     <item msgid="5827960506924849753">"10 منٹ"</item>
     <item msgid="6677424950124253938">"30 منٹ"</item>
   </string-array>
-    <!-- no translation found for dream_timeout_entries:7 (8271452751594598661) -->
+  <string-array name="dream_timeout_entries">
+    <item msgid="6487043225269853023">"کبھی نہیں"</item>
+    <item msgid="2517785806387977252">"15 سیکنڈ"</item>
+    <item msgid="6347954399441173672">"30 سیکنڈ"</item>
+    <item msgid="4858305253279921789">"1 منٹ"</item>
+    <item msgid="8109273437140044073">"2 منٹ"</item>
+    <item msgid="2788593551142462622">"5 منٹ"</item>
+    <item msgid="8012672183888404961">"10 منٹ"</item>
+    <item msgid="8271452751594598661">"30 منٹ"</item>
+  </string-array>
   <string-array name="lock_after_timeout_entries">
     <item msgid="2232921187970351881">"فوری طور پر"</item>
     <item msgid="2038544972632026612">"5 سیکنڈ"</item>
@@ -50,17 +59,47 @@
     <item msgid="811192536981678974">"10 منٹ"</item>
     <item msgid="7258394417241706272">"30 منٹ"</item>
   </string-array>
-    <!-- no translation found for entries_font_size:0 (2340391964816059553) -->
-    <!-- no translation found for entries_font_size:0 (6490061470416867723) -->
-    <!-- no translation found for entries_font_size:2 (1714184661981538355) -->
-    <!-- no translation found for entries_font_size:2 (1678068858001018666) -->
-    <!-- no translation found for wifi_status:3 (5848277343965362748) -->
-    <!-- no translation found for wifi_status_with_ssid:1 (6816207058895999545) -->
-    <!-- no translation found for wifi_status_with_ssid:3 (7547609081339573756) -->
-    <!-- no translation found for wifi_status_with_ssid:4 (5145158315060185414) -->
+  <string-array name="entries_font_size">
+    <item msgid="2340391964816059553">"چھوٹا"</item>
+    <item msgid="591935967183159581">"ڈیفالٹ"</item>
+    <item msgid="1714184661981538355">"بڑا"</item>
+    <item msgid="6195563047686707484">"سب سے بڑا"</item>
+  </string-array>
+  <string-array name="wifi_status">
+    <item msgid="1304883790721412351"></item>
+    <item msgid="4157625910392775808">"اسکین کر رہا ہے…"</item>
+    <item msgid="5597394826455877834">"مربوط ہو رہا ہے…"</item>
+    <item msgid="5848277343965362748">"توثیق ہو رہی ہے…"</item>
+    <item msgid="3391238031431440676">"IP پتہ حاصل کر رہا ہے…"</item>
+    <item msgid="5257597310494000224">"منسلک"</item>
+    <item msgid="8472497592913050396">"معطل شدہ"</item>
+    <item msgid="1228072488815999109">"منقطع کیا جارہا ہے…"</item>
+    <item msgid="7253087004422991731">"منقطع"</item>
+    <item msgid="4169850917304751227">"ناکام"</item>
+    <item msgid="6266658166690831131">"مسدود ہے"</item>
+    <item msgid="4517230805854909775">"عارضی طور پر خراب کنکشن سے اجتناب کر رہا ہے"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="4853670665485437464"></item>
+    <item msgid="6816207058895999545">"اسکین ہو رہا ہے…"</item>
+    <item msgid="8058143476674427024">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> سے مربوط ہو رہا ہے…"</item>
+    <item msgid="7547609081339573756">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> کے ساتھ توثیق ہو رہی ہے…"</item>
+    <item msgid="5145158315060185414">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> سے IP پتہ حاصل کر رہا ہے…"</item>
+    <item msgid="3283243151651124831">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> سے مربوط ہو گیا"</item>
+    <item msgid="6600156231416890902">"معطل شدہ"</item>
+    <item msgid="4133290864821295785">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> سے منقطع ہو رہا ہے…"</item>
+    <item msgid="3980154971187953257">"منقطع"</item>
+    <item msgid="2847316776634969068">"ناکام"</item>
+    <item msgid="4390990424746035383">"مسدود ہے"</item>
+    <item msgid="3618248791367063949">"عارضی طور پر خراب کنکشن سے اجتناب کر رہا ہے"</item>
+  </string-array>
     <!-- no translation found for wifi_tether_security:0 (5586343370515598801) -->
     <!-- no translation found for wifi_tether_security:1 (6136336549994615745) -->
-    <!-- no translation found for wifi_p2p_wps_setup:0 (5390235347963255303) -->
+  <string-array name="wifi_p2p_wps_setup">
+    <item msgid="5390235347963255303">"پش بٹن"</item>
+    <item msgid="7401896200768713930">"ہمسر آلہ سے PIN"</item>
+    <item msgid="4526848028011846710">"اس آلہ سے PIN"</item>
+  </string-array>
   <string-array name="wifi_p2p_status">
     <item msgid="8741947238021758201">"منسلک"</item>
     <item msgid="983792611851499732">"مدعو"</item>
@@ -82,8 +121,13 @@
     <item msgid="1644506614010085798">"4"</item>
     <item msgid="3132506679404897150">"5"</item>
   </string-array>
-    <!-- no translation found for wifi_signal:1 (7882129634982603782) -->
-    <!-- no translation found for wifi_signal:4 (999948812884919584) -->
+  <string-array name="wifi_signal">
+    <item msgid="1709949377823900951">"ناقص"</item>
+    <item msgid="7882129634982603782">"کمزور"</item>
+    <item msgid="6457357501905996224">"مناسب"</item>
+    <item msgid="405271628162918841">"اچھا"</item>
+    <item msgid="999948812884919584">"عمدہ"</item>
+  </string-array>
   <string-array name="data_usage_data_range">
     <item msgid="8986775481492954015">"آخری 30 دن"</item>
     <item msgid="3211287705232736964">"استعمال کا دور سیٹ کریں…"</item>
@@ -119,7 +163,10 @@
     <item msgid="7330627471456865502">"MSCHAPV2"</item>
     <item msgid="6255179395132581882">"GTC"</item>
   </string-array>
-    <!-- no translation found for wifi_ip_settings:1 (4377002609760712163) -->
+  <string-array name="wifi_ip_settings">
+    <item msgid="2717196390555072244">"DHCP"</item>
+    <item msgid="4377002609760712163">"جامد"</item>
+  </string-array>
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"کوئی نہیں"</item>
     <item msgid="1464741437353223198">"مینوئل"</item>
@@ -239,11 +286,73 @@
     <item msgid="1165623660533024666">"پس منظر میں چلائیں"</item>
     <item msgid="6423861043647911030">"ایکسیسبیلٹی والیوم"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:3 (7836406246005211990) -->
-    <!-- no translation found for app_ops_labels:4 (3951439024549922598) -->
-    <!-- no translation found for app_ops_labels:8 (3597797992398484655) -->
-    <!-- no translation found for app_ops_labels:20 (3037159047591081136) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"مقام"</item>
+    <item msgid="6656077694190491067">"مقام"</item>
+    <item msgid="8790228218278477369">"مقام"</item>
+    <item msgid="7836406246005211990">"وائبریٹ"</item>
+    <item msgid="3951439024549922598">"رابطوں کو پڑھیں"</item>
+    <item msgid="8802152411647068">"رابطوں میں ترمیم کریں"</item>
+    <item msgid="229544934599698735">"کال لاگ پڑھیں"</item>
+    <item msgid="7396102294405899613">"کال لاگ میں ترمیم کریں"</item>
+    <item msgid="3597797992398484655">"کیلنڈر پڑھیں"</item>
+    <item msgid="2705975774250907343">"کیلنڈر میں ترمیم کریں"</item>
+    <item msgid="4668747371441932697">"مقام"</item>
+    <item msgid="1487578921720243646">"اطلاع شائع کریں"</item>
+    <item msgid="4636080349724146638">"مقام"</item>
+    <item msgid="673510900286463926">"فون پر کال کریں"</item>
+    <item msgid="542083422784609790">"SMS/MMS پڑھیں"</item>
+    <item msgid="1033780373029588436">"SMS/MMS لکھیں"</item>
+    <item msgid="5647111115517787488">"SMS/MMS وصول کریں"</item>
+    <item msgid="8591105601108455893">"SMS/MMS وصول کریں"</item>
+    <item msgid="7730995008517841903">"SMS/MMS وصول کریں"</item>
+    <item msgid="2613033109026626086">"SMS/MMS وصول کریں"</item>
+    <item msgid="3037159047591081136">"SMS/MMS بھیجیں"</item>
+    <item msgid="4726682243833913568">"SMS/MMS پڑھیں"</item>
+    <item msgid="6555678522277865572">"SMS/MMS لکھیں"</item>
+    <item msgid="6981734935578130884">"ترتیبات میں ترمیم کریں"</item>
+    <item msgid="8705854389991425629">"سب سے اوپر ڈرا کریں"</item>
+    <item msgid="5861356020344153651">"اطلاعات تک رسائی حاصل کریں"</item>
+    <item msgid="78432174621628659">"کیمرا"</item>
+    <item msgid="3986116419882154794">"آڈیو ریکارڈ کریں"</item>
+    <item msgid="4516840825756409490">"آڈیو چلائیں"</item>
+    <item msgid="6811712502798183957">"کلپ بورڈ پڑھیں"</item>
+    <item msgid="2780369012602289114">"کلپ بورڈ میں ترمیم کریں"</item>
+    <item msgid="2331359440170850868">"میڈیا بٹنز"</item>
+    <item msgid="6133599737122751231">"آڈیو فوکس"</item>
+    <item msgid="6844485713404805301">"ماسٹر والیوم"</item>
+    <item msgid="1600379420669104929">"صوتی والیوم"</item>
+    <item msgid="6296768210470214866">"رنگ والیوم"</item>
+    <item msgid="510690696071629241">"میڈیا والیوم"</item>
+    <item msgid="406861638631430109">"الارم والیوم"</item>
+    <item msgid="4715864795872233884">"اطلاع کا والیوم"</item>
+    <item msgid="2311478519251301183">"بلوٹوتھ کا والیوم"</item>
+    <item msgid="5133991377896747027">"بیدار رکھیں"</item>
+    <item msgid="2464189519136248621">"مقام"</item>
+    <item msgid="2062677934050803037">"مقام"</item>
+    <item msgid="1735171933192715957">"استعمال کے اعداد و شمار حاصل کریں"</item>
+    <item msgid="1014093788778383554">"مائیکروفون کو خاموش کریں/اس کی آواز چلائیں"</item>
+    <item msgid="4199297950608622850">"ٹوسٹ دکھائیں"</item>
+    <item msgid="2527962435313398821">"میڈیا پروجیکٹ کریں"</item>
+    <item msgid="5117506254221861929">"VPN کو فعال کریں"</item>
+    <item msgid="8291198322681891160">"لکھنے کا وال پیپر"</item>
+    <item msgid="7106921284621230961">"اسٹرکچر اسسٹ کریں"</item>
+    <item msgid="4496533640894624799">"اسکرین شاٹ اسسٹ کریں"</item>
+    <item msgid="2598847264853993611">"فون اسٹیٹ پڑھیں"</item>
+    <item msgid="9215610846802973353">"صوتی میل شامل کریں"</item>
+    <item msgid="9186411956086478261">"سِپ استعمال کریں"</item>
+    <item msgid="6884763100104539558">"باہر جانے والی کال پر کاروائی کریں"</item>
+    <item msgid="125513972170580692">"فنگر پرنٹ"</item>
+    <item msgid="2556071024281275619">"باڈی سینسرز"</item>
+    <item msgid="617168514928339387">"سیل نشریات پڑھیں"</item>
+    <item msgid="7134693570516523585">"مقام فرضی بنائیں"</item>
+    <item msgid="7224489175375229399">"اسٹوریج پڑھیں"</item>
+    <item msgid="8472735063903258202">"اسٹوریج لکھیں"</item>
+    <item msgid="4069276819909595110">"اسکرین آن کریں"</item>
+    <item msgid="1228338896751121025">"اکاؤنٹس حاصل کریں"</item>
+    <item msgid="3181581793459233672">"پس منظر میں چلائیں"</item>
+    <item msgid="2340936043025374076">"ایکسیسبیلٹی والیوم"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"مختصر"</item>
     <item msgid="4816511817309094890">"متوسط"</item>
@@ -260,7 +369,13 @@
     <item msgid="4627069151979553527">"Cursive"</item>
     <item msgid="6896773537705206194">"بڑے حروف چھوٹے سائز میں"</item>
   </string-array>
-    <!-- no translation found for captioning_font_size_selector_titles:3 (2784236342175159295) -->
+  <string-array name="captioning_font_size_selector_titles">
+    <item msgid="1680223634161592855">"بہت چھوٹا"</item>
+    <item msgid="5091603983404027034">"چھوٹا"</item>
+    <item msgid="176844712416932112">"عام"</item>
+    <item msgid="2784236342175159295">"بڑا"</item>
+    <item msgid="218913203203160606">"بہت بڑا"</item>
+  </string-array>
   <string-array name="captioning_edge_type_selector_titles">
     <item msgid="3865198759294188069">"ڈیفالٹ"</item>
     <item msgid="6488643537808152001">"کوئی نہیں"</item>
@@ -275,7 +390,14 @@
     <item msgid="1874668269931014581">"75%"</item>
     <item msgid="6462911487571123954">"100%"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"ایپ کے ڈیفالٹس استعمال کریں"</item>
+    <item msgid="8611890312638868524">"سیاہ پر سفید"</item>
+    <item msgid="5891360837786277638">"سفید پر سیاہ"</item>
+    <item msgid="2798457065945456853">"سیاہ پر پیلا"</item>
+    <item msgid="5799049811524553967">"نیلے پر پیلا"</item>
+    <item msgid="3673930830658169860">"حسب ضرورت"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"PPTP VPN"</item>
     <item msgid="1349760781118368659">"پہلے سے اشتراک کردہ کلیدوں کے ساتھ L2TP/IPSec VPN"</item>
@@ -288,15 +410,32 @@
     <item msgid="2958623927055120839">"کوئی نہیں"</item>
     <item msgid="1157046369795346308">"مینوئل"</item>
   </string-array>
-    <!-- no translation found for vpn_states:4 (9135049670787351881) -->
+  <string-array name="vpn_states">
+    <item msgid="5408915841694583740">"منقطع"</item>
+    <item msgid="8754480102834556765">"آغاز کیا جا رہا ہے…"</item>
+    <item msgid="3351334355574270250">"مربوط ہو رہا ہے…"</item>
+    <item msgid="8303882153995748352">"منسلک"</item>
+    <item msgid="9135049670787351881">"ٹائم آؤٹ"</item>
+    <item msgid="2124868417182583926">"ناکام"</item>
+  </string-array>
   <string-array name="security_settings_premium_sms_values">
     <item msgid="1164265643455394443">"پوچھیں"</item>
     <item msgid="7718817231348607934">"کبھی اجازت نہ دیں"</item>
     <item msgid="8184570120217958741">"ہمیشہ اجازت دیں"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"عام"</item>
+    <item msgid="5101233285497327432">"معتدل"</item>
+    <item msgid="1555861583162930714">"کم"</item>
+    <item msgid="1719683776264798117">"انتہائی کم"</item>
+    <item msgid="1567326459340152525">"؟"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"عام"</item>
+    <item msgid="6107138933849816768">"متوسط"</item>
+    <item msgid="182695359839047859">"کم"</item>
+    <item msgid="8577246509202964244">"انتہائی کم"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"استقلال پذیر"</item>
     <item msgid="167418068739176448">"سرفہرست سرگرمی"</item>
diff --git a/tests/CarDeveloperOptions/res/values-ur/config.xml b/tests/CarDeveloperOptions/res/values-ur/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-ur/config.xml
+++ b/tests/CarDeveloperOptions/res/values-ur/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-ur/strings.xml b/tests/CarDeveloperOptions/res/values-ur/strings.xml
index fb8ff24..4a881ea 100644
--- a/tests/CarDeveloperOptions/res/values-ur/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ur/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"اسکرین پر موجود متن کو چھوٹا یا بڑا کریں۔"</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"چھوٹا کریں"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"بڑا کریں"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis.‎"</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"نمونہ متن"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"اوز کا شاندار جادوگر"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"گیارھواں باب: اوز کا شاندار زمردی شہر"</string>
@@ -208,7 +207,7 @@
     <string name="proxy_error_empty_port" msgid="8034561724923076215">"آپ کو پورٹ فیلڈ مکمل کرنے کی ضرورت ہے۔"</string>
     <string name="proxy_error_empty_host_set_port" msgid="8471455809508588255">"اگر میزبان فیلڈ خالی ہے تو پورٹ فیلڈ لازمی طور پر خالی ہونی چاہیے۔"</string>
     <string name="proxy_error_invalid_port" msgid="4046559920586100637">"آپ کے ذریعے ٹائپ کردہ پورٹ درست نہیں ہے۔"</string>
-    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"HTTP پراکسی کا استعمال براؤزر کے ذریعے ہوتا ہے لیکن ممکن ہے دوسری ایپس اسے استعمال نہ کریں۔"</string>
+    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"براؤزر HTTP پراکسی کا استعمال کرتا ہے لیکن ممکن ہے دوسری ایپس اسے استعمال نہ کریں۔"</string>
     <string name="proxy_url_title" msgid="882042361706435904">"PAC URL:‎ "</string>
     <string name="radio_info_dl_kbps" msgid="2903778264453410272">"DL بینڈ وڈتھ (kbps):"</string>
     <string name="radio_info_ul_kbps" msgid="3802245899811732716">"UL بینڈ وڈتھ (kbps):"</string>
@@ -411,7 +410,7 @@
     <string name="face_add_max" msgid="8870899421165189413">"آپ <xliff:g id="COUNT">%d</xliff:g> چہروں تک شامل کر سکتے ہیں"</string>
     <string name="face_intro_error_max" msgid="4024147799079828937">"آپ چہروں کی زیادہ سے زیادہ تعداد شامل کر چکے ہیں"</string>
     <string name="face_intro_error_unknown" msgid="3241592604198351134">"مزید چہرے شامل نہیں کر سکتے"</string>
-    <string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"اندراج مکمل نہیں ہوا تھا"</string>
+    <string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"اندراج مکمل نہیں ہوا"</string>
     <string name="security_settings_face_enroll_dialog_ok" msgid="1078348922734845090">"ٹھیک ہے"</string>
     <string name="security_settings_face_enroll_error_timeout_dialog_message" msgid="4917894418448325405">"چہرے کے اندراج کی حدِ وقت پوری ہو گئی۔ دوبارہ کوشش کریں۔"</string>
     <string name="security_settings_face_enroll_error_generic_dialog_message" msgid="5160473187142616862">"چہرے کا اندراج نہیں ہوا۔"</string>
@@ -440,7 +439,7 @@
     <string name="security_settings_fingerprint_preference_summary_none" msgid="3613424536269750172"></string>
     <string name="security_settings_fingerprint_enroll_introduction_title" msgid="889558002683900544">"فنگر پرنٹ کے ساتھ غیر مقفل کریں"</string>
     <string name="security_settings_fingerprint_enroll_introduction_title_unlock_disabled" msgid="7915504118657864429">"اپنا فنگر پرنٹ استعمال کریں"</string>
-    <string name="security_settings_fingerprint_enroll_introduction_message" msgid="5586198131986682472">"اپنا فون غیر مقفل کرنے، خریداریوں کی اجازت دینے یا ایپس میں سائن ان کرنے کیلئے بس فنگر پرنٹ سنسر کو ٹچ کریں۔ کسی کے فنگر پرنٹس شامل کرتے وقت احتیاط برتیں۔ بس ایک شامل کردہ فنگر پرنٹ سے یہ سارے کام کئے جا سکتے ہیں۔\n\nنوٹ: ایک طاقتور پیٹرن یا PIN کی نسبت آپ کا فنگر پرنٹ شاید کم محفوظ ہو۔"</string>
+    <string name="security_settings_fingerprint_enroll_introduction_message" msgid="5586198131986682472">"اپنا فون غیر مقفل کرنے، خریداریوں کی اجازت دینے یا ایپس میں سائن ان کرنے کیلئے بس فنگر پرنٹ سینسر کو ٹچ کریں۔ کسی کے فنگر پرنٹس شامل کرتے وقت احتیاط برتیں۔ بس ایک شامل کردہ فنگر پرنٹ سے یہ سارے کام کئے جا سکتے ہیں۔\n\nنوٹ: ایک طاقتور پیٹرن یا PIN کی نسبت آپ کا فنگر پرنٹ شاید کم محفوظ ہو۔"</string>
     <string name="security_settings_fingerprint_enroll_introduction_message_unlock_disabled" msgid="1640839304679275468">"اپنا فون غیرمقفل کرنے یا خریداریاں منظور کرنے کے لیے اپنے فنگرپرنٹ کا استعمال کریں۔\n\nنوٹ: آپ اس آلہ کو غیرمقفل کرنے کے لیے اپنا فنگرپرنٹ استعمال نہیں کر سکتے۔ مزید معلومات کے لیے، اپنی تنظیم کے منتظم سے رابطہ کریں۔"</string>
     <string name="security_settings_fingerprint_enroll_introduction_message_setup" msgid="6734490666593320711">"اپنا فون غیرمقفل کرنے یا خریداریاں منظور کرنے کے لیے اپنے فنگرپرنٹ کا استعمال کریں۔\n\nنوٹ: ایک طاقتور پیٹرن یا PIN کی بنسبت آپ کا فنگر پرنٹ شاید کم محفوظ ہو۔"</string>
     <string name="security_settings_fingerprint_enroll_introduction_cancel" msgid="9168637333731599827">"منسوخ کریں"</string>
@@ -460,14 +459,14 @@
     <string name="go_back_button_label" msgid="7310586887969860472">"پیچھے جائیں"</string>
     <string name="skip_lock_screen_dialog_button_label" msgid="6706047245716780006">"نظر انداز کریں"</string>
     <string name="cancel_lock_screen_dialog_button_label" msgid="2534925227627658819">"منسوخ کریں"</string>
-    <string name="security_settings_fingerprint_enroll_find_sensor_title" msgid="8909829699273726469">"سنسر کو ٹچ کریں"</string>
+    <string name="security_settings_fingerprint_enroll_find_sensor_title" msgid="8909829699273726469">"سینسر کو ٹچ کریں"</string>
     <string name="security_settings_fingerprint_enroll_find_sensor_message" msgid="581120963079780740">"یہ آپ کے فون کے پشت پر ہے۔ اپنی انڈیکس فنگر کا استعمال کریں۔"</string>
     <string name="security_settings_fingerprint_enroll_find_sensor_content_description" msgid="7835824123269738540">"آلہ اور فنگر پرنٹ سینسر کے مقام کا خاکہ"</string>
     <string name="security_settings_fingerprint_enroll_dialog_name_label" msgid="3519748398694308901">"نام"</string>
     <string name="security_settings_fingerprint_enroll_dialog_ok" msgid="3428927518029038956">"ٹھیک ہے"</string>
     <string name="security_settings_fingerprint_enroll_dialog_delete" msgid="4312297515772004580">"حذف کریں"</string>
-    <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"سنسر کو ٹچ کریں"</string>
-    <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"اپنی انگلی سنسر پر رکھیں اور ارتعاش محسوس ہونے کے بعد اٹھا لیں"</string>
+    <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"سینسر کو ٹچ کریں"</string>
+    <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"اپنی انگلی سینسر پر رکھیں اور ارتعاش محسوس ہونے کے بعد اٹھا لیں"</string>
     <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"اٹھائیں، پھر دوبارہ ٹچ کریں"</string>
     <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"اپنے فنگرپرنٹ کے مختلف حصوں کو شامل کرنے کے لیے اپنی انگلی کو اٹھاتے رہیں"</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"فنگر پرنٹ شامل ہو گیا"</string>
@@ -488,8 +487,8 @@
     <string name="security_settings_fingerprint_enroll_done" msgid="4111289529758845926">"ہوگیا"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"افوہ، یہ سینسر نہیں ہے"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"اپنے فون کے پشت پر سینسر کو ٹچ کریں۔ اپنی انڈیکس فنگر کا استعمال کریں۔"</string>
-    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"اندراج مکمل نہیں ہوا تھا"</string>
-    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"فنگر پرنٹ اندراج کی حدِ وقت پوری ہو گئی۔ دوبارہ کوشش کریں۔"</string>
+    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"اندراج مکمل نہیں ہوا"</string>
+    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"فنگر پرنٹ اندراج کی وقت کی حد پوری ہو گئی۔ دوبارہ کوشش کریں۔"</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"فنگر پرنٹ اندراج نہیں ہوا۔ دوبارہ کوشش کریں یا مختلف انگلی استعمال کریں۔"</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"کوئی دوسرا شامل کریں"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"آگے جائیں"</string>
@@ -668,7 +667,6 @@
       <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g>ہندسوں سے کم ہونے چاہئیں</item>
       <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> ہندسے سے کم ہونا چاہیے</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"صرف ‎0-9 ہندسے شامل ہونے چاہئیں"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"آلہ کا منتظم ایک حالیہ PIN استعمال کرنے کی اجازت نہیں دیتا ہے"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"آپ کے IT منتظم نے عمومی PINs کو مسدود کر دیا ہے۔ کوئی دوسرا PIN آزمائیں۔"</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"اس میں غلط کریکٹر شامل نہیں ہو سکتا"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">کم از کم <xliff:g id="COUNT">%d</xliff:g> غیر حرفی علامتوں پر مشتمل ہونا چاہیے</item>
       <item quantity="one">کم از کم ایک ایسے کریکٹر پر مشتمل ہونا چاہیئے جو حرف نہ ہو</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">کم از کم <xliff:g id="COUNT">%d</xliff:g> غیر عددی حروف پر مشتمل ہونا چاہیے</item>
+      <item quantity="one">کم از کم 1 غیر عددی حرف ہونا چاہیے</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"آلے کا منتظم ایک حالیہ پاس ورڈ کا استعمال کرنے کی اجازت نہیں دیتا ہے"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"آپ کے IT منتظم نے عمومی پاس ورڈز کو مسدود کر دیا ہے۔ کوئی دوسرا پاس ورڈ آزمائیں۔"</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"ہندسوں کی صعودی، نزولی یا مکرر ترتیب کی اجازت نہیں ہے"</string>
@@ -907,8 +909,8 @@
     <string name="wifi_signal" msgid="696548364467704808">"سگنل کی قوت"</string>
     <string name="wifi_status" msgid="3439931558930689940">"اسٹیٹس"</string>
     <string name="tx_wifi_speed" msgid="2571810085003261073">"ترسیل کے لنک کی رفتار"</string>
-    <string name="rx_wifi_speed" msgid="7392873246110937187">"لنک کی رفتار وصول کریں"</string>
-    <string name="wifi_frequency" msgid="6132852924995724246">"تعدد"</string>
+    <string name="rx_wifi_speed" msgid="7392873246110937187">"وصولی کے لنک کی رفتار"</string>
+    <string name="wifi_frequency" msgid="6132852924995724246">"فریکوئنسی"</string>
     <string name="wifi_ip_address" msgid="5572539114989914831">"IP پتہ"</string>
     <string name="passpoint_label" msgid="7429247462404128615">"محفوظ کردہ بذریعہ"</string>
     <string name="passpoint_content" msgid="340527524510304327">"<xliff:g id="NAME">%1$s</xliff:g> اسنادات"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"‎@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"‎@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"موبائل"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"اگر Wi‑Fi دستیاب نہیں ہے تو موبائل نیٹ ورک استعمال کریں"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"اگر موبائل نیٹ ورک دستیاب نہ ہو تو Wi‑Fi استعمال کریں"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Wi‑Fi پر کال کریں۔ اگر Wi‑Fi منقطع ہو جاتا ہے تو کال ختم ہو جائے گی۔"</string>
@@ -1123,7 +1128,7 @@
     <string name="notification_sound_title" msgid="6812164482799723931">"ڈیفالٹ اطلاع کی آواز"</string>
     <string name="incoming_call_volume_title" msgid="4736570528754310450">"رنگ ٹون"</string>
     <string name="notification_volume_title" msgid="6022562909288085275">"اطلاع"</string>
-    <string name="checkbox_notification_same_as_incoming_call" msgid="7312942422655861175">"اطلاعات کیلئے آنے والی کال کا والیوم استعمال کریں"</string>
+    <string name="checkbox_notification_same_as_incoming_call" msgid="7312942422655861175">"اطلاعات کیلئے اِن کمنگ کال کا والیوم استعمال کریں"</string>
     <string name="home_work_profile_not_supported" msgid="6137073723297076818">"کام کے پروفائلز کا تعاون نہیں کرتا ہے"</string>
     <string name="notification_sound_dialog_title" msgid="6653341809710423276">"ڈیفالٹ اطلاع کی آواز"</string>
     <string name="media_volume_title" msgid="1030438549497800914">"میڈیا"</string>
@@ -1216,7 +1221,7 @@
     <string name="night_display_status_title" msgid="1727020934735770319">"اسٹیٹس"</string>
     <string name="night_display_temperature_title" msgid="8375126629902616296">"شدت"</string>
     <string name="night_display_summary_off" msgid="8850539785332228069">"آف / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
-    <string name="night_display_summary_off_auto_mode_never" msgid="8618824386434992487">"کبھی بھی خودکار طور پر آن نہیں ہوگا"</string>
+    <string name="night_display_summary_off_auto_mode_never" msgid="8618824386434992487">"کبھی بھی خودکار طور پر آن نہیں ہو گی"</string>
     <string name="night_display_summary_off_auto_mode_custom" msgid="596847003171394411">"<xliff:g id="ID_1">%1$s</xliff:g> پر خودکار طور پر آن ہو جائے گا"</string>
     <string name="night_display_summary_off_auto_mode_twilight" msgid="4071750976585359952">"غروب آفتاب پر خودکار طور پر آن ہو جائے گا"</string>
     <string name="night_display_summary_on" msgid="6580571388791426596">"آن / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
@@ -1684,7 +1689,7 @@
     <string name="contributors_title" msgid="6800028420806884340">"معاونین"</string>
     <string name="manual" msgid="5431859421432581357">"مینوئل"</string>
     <string name="regulatory_labels" msgid="380968489247381025">"ریگولیٹری لیبلز"</string>
-    <string name="safety_and_regulatory_info" msgid="7113766428000920132">"حفاظتی اور انضباطی مینوئل"</string>
+    <string name="safety_and_regulatory_info" msgid="7113766428000920132">"حفاظتی اور ریگولیٹری مینوئل"</string>
     <string name="copyright_title" msgid="3847703367689932190">"کاپی رائٹ"</string>
     <string name="license_title" msgid="7582145947873528540">"لائسنس"</string>
     <string name="terms_title" msgid="1804549588198223771">"شرائط و ضوابط"</string>
@@ -1840,7 +1845,7 @@
     <string name="reset_app_preferences" msgid="1426500030595212077">"ایپ کی ترجیحات کو ری سیٹ کریں"</string>
     <string name="reset_app_preferences_title" msgid="792909865493673598">"ایپ کی ترجیحات کو ری سیٹ کریں؟"</string>
     <string name="reset_app_preferences_desc" msgid="7935273005301096031">"اس سے مندرجہ ذیل کیلئے تمام ترجیحات ری سیٹ ہو جائیں گی:\n\n "<li>"غیر فعال ایپس"</li>\n" "<li>"غیر فعال ایپس کی اطلاعات"</li>\n" "<li>"کارروائیوں کیلئے ڈیفالٹ ایپلیکیشنز"</li>\n" "<li>"ایپس کیلئے پس منظر کے ڈیٹا کی پابندیاں"</li>\n" "<li>"کوئی اجازتی پابندیاں"</li>\n\n" آپ کسی ایپ کے ڈیٹا سے محروم نہیں ہوں گے۔"</string>
-    <string name="reset_app_preferences_button" msgid="2041894727477934656">"ایپس کو دوبارہ ترتیب دیں"</string>
+    <string name="reset_app_preferences_button" msgid="2041894727477934656">"ایپس کو ری سیٹ کریں"</string>
     <string name="manage_space_text" msgid="6166469422303124302">"خالی جگہ کا نظم کریں"</string>
     <string name="filter" msgid="2426943916212457962">"فلٹر"</string>
     <string name="filter_dlg_title" msgid="115313222190512670">"فلٹر کے اختیارات منتخب کریں"</string>
@@ -2032,7 +2037,7 @@
     <string name="accessibility_settings" msgid="9140621093888234485">"ایکسیسبیلٹی"</string>
     <string name="accessibility_settings_title" msgid="1687226556576913576">"ایکسیسبیلٹی ترتیبات"</string>
     <string name="accessibility_settings_summary" msgid="5742379519336396561">"اسکرین قارئین، ڈسپلے، تعامل کے کنٹرولز"</string>
-    <string name="vision_settings_title" msgid="7315352351051423944">"بصارتی ترتیبات"</string>
+    <string name="vision_settings_title" msgid="7315352351051423944">"بصری ترتیبات"</string>
     <string name="vision_settings_description" msgid="3476589459009287332">"آپ اس آلہ کو اپنی ضروریات کے مطابق حسب ضرورت بنا سکتے ہیں۔ یہ ایکسیسبیلٹی خصوصیات بعد میں ترتیبات میں تبدیل ہو سکتی ہیں۔"</string>
     <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"فونٹ سائز تبدیل کریں"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"اسکرین ریڈرز"</string>
@@ -2067,7 +2072,7 @@
     <string name="accessibility_toggle_large_pointer_icon_title" msgid="9127905775116570565">"بڑا ماؤس پوائنٹر"</string>
     <string name="accessibility_disable_animations" msgid="8378441317115710009">"اینیمیشنز ہٹائیں"</string>
     <string name="accessibility_toggle_master_mono_title" msgid="899550848196702565">"مونو آڈیو"</string>
-    <string name="accessibility_toggle_master_mono_summary" msgid="3847052868469033235">"آڈیو چلاتے وقت چینلز آپس میں ملائیں"</string>
+    <string name="accessibility_toggle_master_mono_summary" msgid="3847052868469033235">"آڈیو چلاتے وقت چینلز یکجا کریں"</string>
     <string name="accessibility_toggle_master_balance_title" msgid="8723492001092647562">"آڈیو بیلنس"</string>
     <string name="accessibility_toggle_master_balance_left_label" msgid="8531986342666527970">"بائیں"</string>
     <string name="accessibility_toggle_master_balance_right_label" msgid="7757024572140589558">"دائیں"</string>
@@ -2870,7 +2875,7 @@
     <string name="user_setup_dialog_title" msgid="6748950002206392396">"صارف کو ابھی سیٹ اپ کریں؟"</string>
     <string name="user_setup_dialog_message" msgid="2988559933258353919">"یقینی بنائیں کہ وہ شخص آلہ لینے اور اپنی جگہ کو سیٹ اپ کرنے کیلئے دستیاب ہے"</string>
     <string name="user_setup_profile_dialog_message" msgid="7611900802824048526">"پروفائل کو ابھی ترتیب دیں؟"</string>
-    <string name="user_setup_button_setup_now" msgid="4941459406266856176">"ابھی ترتیب دیں"</string>
+    <string name="user_setup_button_setup_now" msgid="4941459406266856176">"ابھی سیٹ اپ کریں"</string>
     <string name="user_setup_button_setup_later" msgid="6596031428556518752">"ابھی نہیں"</string>
     <string name="user_cannot_manage_message" product="tablet" msgid="7108992906553210763">"صرف ٹیبلٹ کا مالک صارفین کا نظم کر سکتا ہے۔"</string>
     <string name="user_cannot_manage_message" product="default" msgid="915260531390608092">"صرف فون کا مالک صارفین کا نظم کر سکتا ہے۔"</string>
@@ -2920,7 +2925,7 @@
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"علاوہ اس کے کہ کوئی دوسری ادائیگی ایپ کھلی ہو"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"تھپتھپائیں اور ادائیگی کریں ٹرمینل پر، اس کے ساتھ ادائیگی کریں:"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"ٹرمینل پر ادا کرنا"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"ادائیگی ایپ سیٹ اپ کریں۔ پھر بس اپنے فون کے پچھلے حصے کو کسی بھی بغیر رابطے والی علامت کے ٹرمینل سے لگائیں۔"</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"ادائیگی کی ایپ سیٹ اپ کریں۔ پھر بس اپنے فون کے پچھلے حصے کو کسی بھی بغیر رابطے والی علامت کے ٹرمینل کے پاس پکڑ کر رکھیں۔"</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"سمجھ آ گئی"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"مزید…"</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"اپنی ترجیح کے بطور سیٹ کریں؟"</string>
@@ -3155,7 +3160,7 @@
     <string name="emergency_tone_vibrate" msgid="5020068066905681181">"وائبریشنز"</string>
     <string name="boot_sounds_title" msgid="7583926202411353620">"آوازیں آن کریں"</string>
     <string name="live_caption_title" msgid="7926591158657997051">"لائیو کیپشن"</string>
-    <string name="live_caption_summary" msgid="9064771862352393125">"خودکار طور پر کیپشن میڈیا"</string>
+    <string name="live_caption_summary" msgid="9064771862352393125">"خودکار طور پر میڈیا پر کیپشن لگائیں"</string>
     <string name="zen_mode_settings_summary_off" msgid="6929319200478424962">"کبھی نہیں"</string>
     <plurals name="zen_mode_settings_summary_on" formatted="false" msgid="6061723291126091396">
       <item quantity="other"><xliff:g id="ON_COUNT">%d</xliff:g> فعال ہے</item>
@@ -3396,7 +3401,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> زمرے</item>
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> زمرہ</item>
     </plurals>
-    <string name="no_channels" msgid="8884254729302501652">"اس ایپ نے کوئی اطلاعات شائع نہیں کیا ہے"</string>
+    <string name="no_channels" msgid="8884254729302501652">"اس ایپ نے کوئی اطلاعات شائع نہیں کی ہیں"</string>
     <string name="app_settings_link" msgid="8465287765715790984">"ایپ میں اضافی ترتیبات"</string>
     <string name="app_notification_listing_summary_zero" msgid="4047782719487686699">"سبھی ایپس کے لیے آن ہے"</string>
     <plurals name="app_notification_listing_summary_others" formatted="false" msgid="1161774065480666519">
@@ -3701,7 +3706,7 @@
     </plurals>
     <string name="high_power_filter_on" msgid="5294209328473386403">"بہترین بنائی گئی نہیں ہیں"</string>
     <string name="high_power_on" msgid="3573501822510580334">"بہترین بنائی گئی نہیں ہیں"</string>
-    <string name="high_power_off" msgid="5906679734326490426">"بیٹری استعمال کو بہترین بنا رہی ہے"</string>
+    <string name="high_power_off" msgid="5906679734326490426">"بیٹری استعمال کو بہتر بنایا جا رہا ہے"</string>
     <string name="high_power_system" msgid="739584574711292753">"بیٹری بہترین بنانا دستیاب نہیں ہے"</string>
     <string name="high_power_desc" msgid="333756885680362741">"بیٹری بہترین بنانا لاگو مت کریں۔ ممکن ہے یہ آپ کی بیٹری مزید تیزی سے ختم کر دے۔"</string>
     <string name="high_power_prompt_title" msgid="2805745781720454052">"ایپ کو ہمیشہ پس منظر میں چلنے دیں؟"</string>
@@ -4064,7 +4069,7 @@
     <string name="premium_sms_warning" msgid="7604011651486294515">"ہو سکتا ہے آپ کو پریمیم SMS کے پیسے ادا کرنا پڑیں اور یہ آپ کے کیرئیر بلز میں شامل ہو جائیں گے۔ اگر آپ ایک ایپ کیلئے اجازت فعال کرتے ہیں تو آپ اس ایپ کو استعمال کرکے آپ پریمیم SMS بھیج پائیں گے۔"</string>
     <string name="premium_sms_access" msgid="4550027460595822851">"پریمیم SMS رسائی"</string>
     <string name="bluetooth_disabled" msgid="6588102116819268238">"آف"</string>
-    <string name="bluetooth_connected_summary" msgid="439920840053965217">"<xliff:g id="ID_1">%1$s</xliff:g> سے منسلک کردہ"</string>
+    <string name="bluetooth_connected_summary" msgid="439920840053965217">"‫<xliff:g id="ID_1">%1$s</xliff:g> سے منسلک کردہ"</string>
     <string name="bluetooth_connected_multiple_devices_summary" msgid="596205630653123250">"متعدد آلات سے منسلک کردہ"</string>
     <string name="demo_mode" msgid="3831081808592541104">"سسٹم UI ڈیمو موڈ"</string>
     <string name="dark_ui_mode" msgid="703844190192599217">"تھیم"</string>
diff --git a/tests/CarDeveloperOptions/res/values-uz/arrays.xml b/tests/CarDeveloperOptions/res/values-uz/arrays.xml
index 2dfcf75..8c3e21c 100644
--- a/tests/CarDeveloperOptions/res/values-uz/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-uz/arrays.xml
@@ -29,8 +29,25 @@
     <item msgid="5194868215515664953">"Tinch okeani"</item>
     <item msgid="7044520255415007865">"Hammasi"</item>
   </string-array>
-    <!-- no translation found for screen_timeout_entries:0 (8596143519087753804) -->
-    <!-- no translation found for dream_timeout_entries:7 (8271452751594598661) -->
+  <string-array name="screen_timeout_entries">
+    <item msgid="8596143519087753804">"15 soniya"</item>
+    <item msgid="772029947136115322">"30 soniya"</item>
+    <item msgid="8743663928349474087">"1 daqiqa"</item>
+    <item msgid="1506508631223164814">"2 daqiqa"</item>
+    <item msgid="8664703938127907662">"5 daqiqa"</item>
+    <item msgid="5827960506924849753">"10 daqiqa"</item>
+    <item msgid="6677424950124253938">"30 daqiqa"</item>
+  </string-array>
+  <string-array name="dream_timeout_entries">
+    <item msgid="6487043225269853023">"Hech qachon"</item>
+    <item msgid="2517785806387977252">"15 soniya"</item>
+    <item msgid="6347954399441173672">"30 soniya"</item>
+    <item msgid="4858305253279921789">"1 daqiqa"</item>
+    <item msgid="8109273437140044073">"2 daqiqa"</item>
+    <item msgid="2788593551142462622">"5 daqiqa"</item>
+    <item msgid="8012672183888404961">"10 daqiqa"</item>
+    <item msgid="8271452751594598661">"30 daqiqa"</item>
+  </string-array>
   <string-array name="lock_after_timeout_entries">
     <item msgid="2232921187970351881">"Darhol"</item>
     <item msgid="2038544972632026612">"5 soniya"</item>
@@ -42,17 +59,47 @@
     <item msgid="811192536981678974">"10 daqiqa"</item>
     <item msgid="7258394417241706272">"30 daqiqa"</item>
   </string-array>
-    <!-- no translation found for entries_font_size:0 (2340391964816059553) -->
-    <!-- no translation found for entries_font_size:0 (6490061470416867723) -->
-    <!-- no translation found for entries_font_size:2 (1714184661981538355) -->
-    <!-- no translation found for entries_font_size:2 (1678068858001018666) -->
-    <!-- no translation found for wifi_status:3 (5848277343965362748) -->
-    <!-- no translation found for wifi_status_with_ssid:1 (6816207058895999545) -->
-    <!-- no translation found for wifi_status_with_ssid:3 (7547609081339573756) -->
-    <!-- no translation found for wifi_status_with_ssid:4 (5145158315060185414) -->
+  <string-array name="entries_font_size">
+    <item msgid="2340391964816059553">"Kichik"</item>
+    <item msgid="591935967183159581">"Asosiy"</item>
+    <item msgid="1714184661981538355">"Katta"</item>
+    <item msgid="6195563047686707484">"Maksimal"</item>
+  </string-array>
+  <string-array name="wifi_status">
+    <item msgid="1304883790721412351"></item>
+    <item msgid="4157625910392775808">"Qidiruv…"</item>
+    <item msgid="5597394826455877834">"Ulanmoqda…"</item>
+    <item msgid="5848277343965362748">"Autentifikatsiya qilinmoqda…"</item>
+    <item msgid="3391238031431440676">"IP manzil o‘zlashtirilmoqda…"</item>
+    <item msgid="5257597310494000224">"Ulandi"</item>
+    <item msgid="8472497592913050396">"Muzlatildi"</item>
+    <item msgid="1228072488815999109">"Uzilyapti…"</item>
+    <item msgid="7253087004422991731">"Uzildi"</item>
+    <item msgid="4169850917304751227">"Muvaffaqiyatsiz"</item>
+    <item msgid="6266658166690831131">"Bloklangan"</item>
+    <item msgid="4517230805854909775">"Sifatsiz ulanishdan vaqtinchalik chetlashish"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="4853670665485437464"></item>
+    <item msgid="6816207058895999545">"Qidirilmoqda…"</item>
+    <item msgid="8058143476674427024">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> tarmog‘iga ulanilmoqda…"</item>
+    <item msgid="7547609081339573756">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> nomli tarmoqqa ulanmoqda…"</item>
+    <item msgid="5145158315060185414">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> nomli tarmoqdan IP manzil olinmoqda…"</item>
+    <item msgid="3283243151651124831">"Bunga ulangan: <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="6600156231416890902">"Muzlatildi"</item>
+    <item msgid="4133290864821295785">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> tarmog‘idan uzilmoqda…"</item>
+    <item msgid="3980154971187953257">"Uzildi"</item>
+    <item msgid="2847316776634969068">"Muvaffaqiyatsiz"</item>
+    <item msgid="4390990424746035383">"Bloklangan"</item>
+    <item msgid="3618248791367063949">"Sifatsiz ulanishdan vaqtinchalik chetlashish"</item>
+  </string-array>
     <!-- no translation found for wifi_tether_security:0 (5586343370515598801) -->
     <!-- no translation found for wifi_tether_security:1 (6136336549994615745) -->
-    <!-- no translation found for wifi_p2p_wps_setup:0 (5390235347963255303) -->
+  <string-array name="wifi_p2p_wps_setup">
+    <item msgid="5390235347963255303">"Push tugmasi"</item>
+    <item msgid="7401896200768713930">"ulashma qurilmadagi PIN-kod"</item>
+    <item msgid="4526848028011846710">"Ushbu qurilmaning PIN kodi"</item>
+  </string-array>
   <string-array name="wifi_p2p_status">
     <item msgid="8741947238021758201">"Ulandi"</item>
     <item msgid="983792611851499732">"Taklif qilingan"</item>
@@ -60,7 +107,12 @@
     <item msgid="4646663015449312554">"Mavjud"</item>
     <item msgid="3230556734162006146">"Chegaradan tashqari"</item>
   </string-array>
-    <!-- no translation found for bluetooth_visibility_timeout_entries:1 (2759776603549270587) -->
+  <string-array name="bluetooth_visibility_timeout_entries">
+    <item msgid="8247986727324120082">"2 daqiqa"</item>
+    <item msgid="2759776603549270587">"5 daqiqa"</item>
+    <item msgid="167772676068860015">"1 soat"</item>
+    <item msgid="5985477119043628504">"Doim yoniq tursin"</item>
+  </string-array>
   <string-array name="bluetooth_max_connected_audio_devices">
     <item msgid="3800257971619063588">"Standart tizim parametrlaridan foydalanish: <xliff:g id="DEFAULT_BLUETOOTH_MAX_CONNECTED_AUDIO_DEVICES">%1$d</xliff:g>"</item>
     <item msgid="8572230405241423895">"1"</item>
@@ -69,8 +121,13 @@
     <item msgid="1644506614010085798">"4"</item>
     <item msgid="3132506679404897150">"5"</item>
   </string-array>
-    <!-- no translation found for wifi_signal:1 (7882129634982603782) -->
-    <!-- no translation found for wifi_signal:4 (999948812884919584) -->
+  <string-array name="wifi_signal">
+    <item msgid="1709949377823900951">"Juda past"</item>
+    <item msgid="7882129634982603782">"Juda past"</item>
+    <item msgid="6457357501905996224">"Past"</item>
+    <item msgid="405271628162918841">"Yaxshi"</item>
+    <item msgid="999948812884919584">"Aʼlo"</item>
+  </string-array>
   <string-array name="data_usage_data_range">
     <item msgid="8986775481492954015">"So‘nggi 30 kun"</item>
     <item msgid="3211287705232736964">"Internetdan foyd-sh davri…"</item>
@@ -106,7 +163,10 @@
     <item msgid="7330627471456865502">"MSCHAPV2"</item>
     <item msgid="6255179395132581882">"GTC"</item>
   </string-array>
-    <!-- no translation found for wifi_ip_settings:1 (4377002609760712163) -->
+  <string-array name="wifi_ip_settings">
+    <item msgid="2717196390555072244">"DHCP"</item>
+    <item msgid="4377002609760712163">"Statik"</item>
+  </string-array>
   <string-array name="wifi_proxy_settings">
     <item msgid="9032900195127165132">"Tarmoq yo‘q"</item>
     <item msgid="1464741437353223198">"Qo‘llanma"</item>
@@ -226,11 +286,73 @@
     <item msgid="1165623660533024666">"fonda ishga tushirish"</item>
     <item msgid="6423861043647911030">"maxsus imkoniyatlar ovozi balandligi"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:3 (7836406246005211990) -->
-    <!-- no translation found for app_ops_labels:4 (3951439024549922598) -->
-    <!-- no translation found for app_ops_labels:8 (3597797992398484655) -->
-    <!-- no translation found for app_ops_labels:20 (3037159047591081136) -->
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Joylashuv"</item>
+    <item msgid="6656077694190491067">"Joylashuv"</item>
+    <item msgid="8790228218278477369">"Joylashuv"</item>
+    <item msgid="7836406246005211990">"Tebranish"</item>
+    <item msgid="3951439024549922598">"Kontaktlarga oid axborotni oʻqish"</item>
+    <item msgid="8802152411647068">"Kontaktlarni o‘zgartirish"</item>
+    <item msgid="229544934599698735">"Qo‘ng‘iroqlar jurnalini ko‘rib chiqish"</item>
+    <item msgid="7396102294405899613">"Qo‘ng‘iroqlar jurnalini o‘zgartirish"</item>
+    <item msgid="3597797992398484655">"Taqvimga oid axborotni oʻqish"</item>
+    <item msgid="2705975774250907343">"Taqvimni o‘zgartirish"</item>
+    <item msgid="4668747371441932697">"Joylashuv"</item>
+    <item msgid="1487578921720243646">"Post qoldirish"</item>
+    <item msgid="4636080349724146638">"Joylashuv"</item>
+    <item msgid="673510900286463926">"Telefonga qo‘ng‘iroq qilish"</item>
+    <item msgid="542083422784609790">"SMS/MMS xabarlarini o‘qish"</item>
+    <item msgid="1033780373029588436">"SMS/MMS xabarlarini yozish"</item>
+    <item msgid="5647111115517787488">"SMS/MMS xabarlarini qabul qilish"</item>
+    <item msgid="8591105601108455893">"SMS/MMS xabarlarini qabul qilish"</item>
+    <item msgid="7730995008517841903">"SMS/MMS xabarlarini qabul qilish"</item>
+    <item msgid="2613033109026626086">"SMS/MMS xabarlarini qabul qilish"</item>
+    <item msgid="3037159047591081136">"SMS/MMS yuborish"</item>
+    <item msgid="4726682243833913568">"SMS/MMS xabarlarini o‘qish"</item>
+    <item msgid="6555678522277865572">"SMS/MMS yozish"</item>
+    <item msgid="6981734935578130884">"Sozlamalarni o‘zgartirish"</item>
+    <item msgid="8705854389991425629">"Ustiga chizish"</item>
+    <item msgid="5861356020344153651">"Xabarnomalarga kirish"</item>
+    <item msgid="78432174621628659">"Kamera"</item>
+    <item msgid="3986116419882154794">"Ovoz yozib olish"</item>
+    <item msgid="4516840825756409490">"Audioqaydni ijro etish"</item>
+    <item msgid="6811712502798183957">"Vaqtinchalik xotira ma‘lumotini o‘qish"</item>
+    <item msgid="2780369012602289114">"Vaqtinchalik xotirani o‘zgartirish"</item>
+    <item msgid="2331359440170850868">"Multimedia tugmalari"</item>
+    <item msgid="6133599737122751231">"Audio fokus"</item>
+    <item msgid="6844485713404805301">"Umumiy tovush balandligi"</item>
+    <item msgid="1600379420669104929">"Ovoz balandligi"</item>
+    <item msgid="6296768210470214866">"Jiringlash tovushi"</item>
+    <item msgid="510690696071629241">"Multimedia tovushi"</item>
+    <item msgid="406861638631430109">"Signal tovushi"</item>
+    <item msgid="4715864795872233884">"Bildirishnomalar ovozi"</item>
+    <item msgid="2311478519251301183">"Bluetooth tovush balandligi"</item>
+    <item msgid="5133991377896747027">"Uyg‘oq turish"</item>
+    <item msgid="2464189519136248621">"Joylashuv"</item>
+    <item msgid="2062677934050803037">"Joylashuv"</item>
+    <item msgid="1735171933192715957">"Foydalanish statistikasini ko‘rish"</item>
+    <item msgid="1014093788778383554">"Mikrofonni o‘chirish/yoqish"</item>
+    <item msgid="4199297950608622850">"Toast dasturini ko‘rsatish"</item>
+    <item msgid="2527962435313398821">"Kontentni translatsiya qilish"</item>
+    <item msgid="5117506254221861929">"VPN tarmog‘ini faollashtirish"</item>
+    <item msgid="8291198322681891160">"Orqa fon rasmiga yozish"</item>
+    <item msgid="7106921284621230961">"Yordam tuzilishi"</item>
+    <item msgid="4496533640894624799">"Yordam ekran rasmi"</item>
+    <item msgid="2598847264853993611">"Telefon holatini o‘qish"</item>
+    <item msgid="9215610846802973353">"Ovozli xabar qo‘shish"</item>
+    <item msgid="9186411956086478261">"SIPdan foydalanish"</item>
+    <item msgid="6884763100104539558">"Chiquvchi qo‘ng‘iroq jarayoni"</item>
+    <item msgid="125513972170580692">"Barmoq izi"</item>
+    <item msgid="2556071024281275619">"Tana sezgichlari"</item>
+    <item msgid="617168514928339387">"Tarqatma xabarlarni o‘qish"</item>
+    <item msgid="7134693570516523585">"Soxta joylashuv"</item>
+    <item msgid="7224489175375229399">"Xotirani o‘qish"</item>
+    <item msgid="8472735063903258202">"Xotiraga yozish"</item>
+    <item msgid="4069276819909595110">"Ekranni yoqish"</item>
+    <item msgid="1228338896751121025">"Hisoblarni olish"</item>
+    <item msgid="3181581793459233672">"Fonda ishga tushirish"</item>
+    <item msgid="2340936043025374076">"Maxsus imkoniyatlar ovozi balandligi"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Qisqa"</item>
     <item msgid="4816511817309094890">"O‘rtacha"</item>
@@ -247,7 +369,13 @@
     <item msgid="4627069151979553527">"Qiya"</item>
     <item msgid="6896773537705206194">"Kichik bosh harflar"</item>
   </string-array>
-    <!-- no translation found for captioning_font_size_selector_titles:3 (2784236342175159295) -->
+  <string-array name="captioning_font_size_selector_titles">
+    <item msgid="1680223634161592855">"Juda kichik"</item>
+    <item msgid="5091603983404027034">"Kichik"</item>
+    <item msgid="176844712416932112">"Normal"</item>
+    <item msgid="2784236342175159295">"Katta"</item>
+    <item msgid="218913203203160606">"Juda katta"</item>
+  </string-array>
   <string-array name="captioning_edge_type_selector_titles">
     <item msgid="3865198759294188069">"Asosiy"</item>
     <item msgid="6488643537808152001">"Tarmoq yo‘q"</item>
@@ -262,7 +390,14 @@
     <item msgid="1874668269931014581">"75%"</item>
     <item msgid="6462911487571123954">"100%"</item>
   </string-array>
-    <!-- no translation found for captioning_preset_selector_titles:2 (5891360837786277638) -->
+  <string-array name="captioning_preset_selector_titles">
+    <item msgid="326819345272910536">"Standart"</item>
+    <item msgid="8611890312638868524">"Qora ustida oq"</item>
+    <item msgid="5891360837786277638">"Oq ustida qora"</item>
+    <item msgid="2798457065945456853">"Qora ustida sariq"</item>
+    <item msgid="5799049811524553967">"Ko‘k ustida sariq"</item>
+    <item msgid="3673930830658169860">"Maxsus"</item>
+  </string-array>
   <string-array name="vpn_types_long">
     <item msgid="6566768880689730097">"PPTP VPN"</item>
     <item msgid="1349760781118368659">"L2TP/IPSec VPN avval ulashilgan kalitlar bilan"</item>
@@ -275,15 +410,32 @@
     <item msgid="2958623927055120839">"Hech biri"</item>
     <item msgid="1157046369795346308">"Qo‘llanma"</item>
   </string-array>
-    <!-- no translation found for vpn_states:4 (9135049670787351881) -->
+  <string-array name="vpn_states">
+    <item msgid="5408915841694583740">"Uzildi"</item>
+    <item msgid="8754480102834556765">"Ishga tushirilmoqda…"</item>
+    <item msgid="3351334355574270250">"Ulanmoqda…"</item>
+    <item msgid="8303882153995748352">"Ulandi"</item>
+    <item msgid="9135049670787351881">"Vaqt tugadi"</item>
+    <item msgid="2124868417182583926">"Muvaffaqiyatsiz"</item>
+  </string-array>
   <string-array name="security_settings_premium_sms_values">
     <item msgid="1164265643455394443">"So‘rash"</item>
     <item msgid="7718817231348607934">"Hech qachon ruxsat berilmasin"</item>
     <item msgid="8184570120217958741">"Har doim ruxsat berilsin"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Normal"</item>
+    <item msgid="5101233285497327432">"Hozircha yetarli"</item>
+    <item msgid="1555861583162930714">"Past"</item>
+    <item msgid="1719683776264798117">"Jiddiy"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Normal"</item>
+    <item msgid="6107138933849816768">"Qoniqarli"</item>
+    <item msgid="182695359839047859">"Past"</item>
+    <item msgid="8577246509202964244">"Jiddiy"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Barqaror"</item>
     <item msgid="167418068739176448">"Eng mashhur harakat"</item>
@@ -303,8 +455,8 @@
   <string-array name="color_picker">
     <item msgid="3151827842194201728">"Moviy"</item>
     <item msgid="3228505970082457852">"Ko‘k"</item>
-    <item msgid="6590260735734795647">"To‘q ko‘k"</item>
-    <item msgid="3521763377357218577">"Binafsharang"</item>
+    <item msgid="6590260735734795647">"Indigo"</item>
+    <item msgid="3521763377357218577">"Siyohrang"</item>
     <item msgid="5932337981182999919">"Pushti"</item>
     <item msgid="5642914536624000094">"Qizil"</item>
   </string-array>
diff --git a/tests/CarDeveloperOptions/res/values-uz/config.xml b/tests/CarDeveloperOptions/res/values-uz/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-uz/config.xml
+++ b/tests/CarDeveloperOptions/res/values-uz/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-uz/strings.xml b/tests/CarDeveloperOptions/res/values-uz/strings.xml
index 6b347a5..f2fb286 100644
--- a/tests/CarDeveloperOptions/res/values-uz/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-uz/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Ekrandagi matnni kattalashtirish yoki kichiklashtirish."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Kichiklashtirish"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Kattalashtirish"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Namunaviy matn"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Oz mamlakati sehrgari"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"11-bob: Oz mamlakatining zumrad shahri"</string>
@@ -484,7 +483,7 @@
     <string name="lock_screen_pin_skip_title" msgid="8217519439213393785">"PIN kod kerak emasmi?"</string>
     <string name="lock_screen_password_skip_title" msgid="3725788215672959827">"Parol kerak emasmi?"</string>
     <string name="lock_screen_pattern_skip_title" msgid="4237030500353932005">"Grafik kalit kerak emasmi?"</string>
-    <string name="security_settings_fingerprint_enroll_setup_screen_lock" msgid="9036983528330627756">"Ekranni qulfini sozlash"</string>
+    <string name="security_settings_fingerprint_enroll_setup_screen_lock" msgid="9036983528330627756">"Ekran qulfini sozlash"</string>
     <string name="security_settings_fingerprint_enroll_done" msgid="4111289529758845926">"Tayyor"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"Obbo, bu sensor emas."</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"Telefonning orqasida joylashgan sensorga tegining. Ko‘rsatkich barmog‘ingizdan foydalaning."</string>
@@ -545,7 +544,7 @@
     <string name="suggested_fingerprint_lock_settings_summary" product="device" msgid="8114514312665251311"></string>
     <string name="suggested_fingerprint_lock_settings_summary" product="default" msgid="8114514312665251311"></string>
     <string name="lock_settings_picker_title" msgid="1034741644461982205">"Ekran qulfini tanlang"</string>
-    <string name="lock_settings_picker_title_profile" msgid="5086594364428782115">"Ishchi profil qulfini tanlang"</string>
+    <string name="lock_settings_picker_title_profile" msgid="5086594364428782115">"Ish profili qulfini tanlang"</string>
     <string name="setup_lock_settings_picker_title" product="tablet" msgid="2429667472335773519">"Planshetingizni himoyalang"</string>
     <string name="setup_lock_settings_picker_title" product="device" msgid="4739290104106645233">"Qurilmangizni himoyalang"</string>
     <string name="setup_lock_settings_picker_title" product="default" msgid="3911582328576859628">"Telefoningizni himoyalang"</string>
@@ -560,7 +559,7 @@
     <string name="unlock_set_unlock_launch_picker_title" msgid="2731152716948003853">"Ekran qulfi"</string>
     <string name="unlock_set_unlock_launch_picker_summary_lock_immediately" msgid="5596186270725220642">"<xliff:g id="UNLOCK_METHOD">%1$s</xliff:g> / uyqu rejimidan keyinoq"</string>
     <string name="unlock_set_unlock_launch_picker_summary_lock_after_timeout" msgid="3861167251234952373">"<xliff:g id="UNLOCK_METHOD">%1$s</xliff:g> / uyqu rejimidan <xliff:g id="TIMEOUT_STRING">%2$s</xliff:g>dan keyin"</string>
-    <string name="unlock_set_unlock_launch_picker_title_profile" msgid="7976345264630422921">"Ishchi profil qulfi"</string>
+    <string name="unlock_set_unlock_launch_picker_title_profile" msgid="7976345264630422921">"Ish profili qulfi"</string>
     <string name="unlock_set_unlock_launch_picker_change_title" msgid="32310692507029407">"Ekran qulfini o‘zgartirish"</string>
     <string name="unlock_set_unlock_launch_picker_change_summary" msgid="2072792784866320522">"Grafik kalit, PIN kod va himoya parolini o‘zgartirish yoki o‘chirib qo‘yish"</string>
     <string name="unlock_set_unlock_launch_picker_enable_summary" msgid="9070847611379078795">"Ekranni qulflash usulini tanlang"</string>
@@ -644,12 +643,12 @@
     <string name="lock_last_pattern_attempt_before_wipe_user" msgid="5194192938934564218">"Agar grafik kalitni xato kiritsangiz, bu foydalanuvchi o‘chirib tashlanadi"</string>
     <string name="lock_last_pin_attempt_before_wipe_user" msgid="7833852187363499906">"Agar PIN kodni xato kiritsangiz, bu foydalanuvchi o‘chirib tashlanadi"</string>
     <string name="lock_last_password_attempt_before_wipe_user" msgid="8979742220140001204">"Agar parolni xato kiritsangiz, bu foydalanuvchi o‘chirib tashlanadi"</string>
-    <string name="lock_last_pattern_attempt_before_wipe_profile" msgid="3877613047631174576">"Agar grafik kalitni xato kiritsangiz, ishchi profil va undagi ma’lumotlar o‘chirib tashlanadi"</string>
-    <string name="lock_last_pin_attempt_before_wipe_profile" msgid="8132438288175428168">"Agar PIN kodni xato kiritsangiz, ishchi profil va undagi ma’lumotlar o‘chirib tashlanadi"</string>
-    <string name="lock_last_password_attempt_before_wipe_profile" msgid="1535128774464384305">"Agar parolni xato kiritsangiz, ishchi profil va undagi ma’lumotlar o‘chirib tashlanadi"</string>
+    <string name="lock_last_pattern_attempt_before_wipe_profile" msgid="3877613047631174576">"Agar grafik kalitni xato kiritsangiz, ish profili va undagi ma’lumotlar o‘chirib tashlanadi"</string>
+    <string name="lock_last_pin_attempt_before_wipe_profile" msgid="8132438288175428168">"Agar PIN kodni xato kiritsangiz, ish profili va undagi ma’lumotlar o‘chirib tashlanadi"</string>
+    <string name="lock_last_password_attempt_before_wipe_profile" msgid="1535128774464384305">"Agar parolni xato kiritsangiz, ish profili va undagi ma’lumotlar o‘chirib tashlanadi"</string>
     <string name="lock_failed_attempts_now_wiping_device" msgid="8662360098784762828">"Juda ko‘p marta muvaffaqiyatsiz urinishlar amalga oshirildi. Bu qurilmadagi ma’lumotlar o‘chirib tashlanadi."</string>
     <string name="lock_failed_attempts_now_wiping_user" msgid="3793513796171561873">"Juda ko‘p marta muvaffaqiyatsiz urinishlar amalga oshirildi. Bu foydalanuvchi o‘chirib tashlanadi."</string>
-    <string name="lock_failed_attempts_now_wiping_profile" msgid="5347108525299038285">"Juda ko‘p marta muvaffaqiyatsiz urinishlar amalga oshirildi. Bu ishchi profil va undagi ma’lumotlar o‘chirib tashlanadi."</string>
+    <string name="lock_failed_attempts_now_wiping_profile" msgid="5347108525299038285">"Juda ko‘p marta muvaffaqiyatsiz urinishlar amalga oshirildi. Bu ish profili va undagi ma’lumotlar o‘chirib tashlanadi."</string>
     <string name="lock_failed_attempts_now_wiping_dialog_dismiss" msgid="3950582268749037318">"Yopish"</string>
     <plurals name="lockpassword_password_too_short" formatted="false" msgid="694091983183310827">
       <item quantity="other">Kamida <xliff:g id="COUNT_1">%d</xliff:g> ta belgi</item>
@@ -668,7 +667,6 @@
       <item quantity="other">Maksimum <xliff:g id="NUMBER_1">%d</xliff:g> ta raqam</item>
       <item quantity="one">Maksimum <xliff:g id="NUMBER_0">%d</xliff:g> ta raqam</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"PIN kod faqat 0-9 raqamlaridan iborat bo‘lishi lozim"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Qurilma administratori oxirgi PIN koddan yana foydalanishga ruxsat bermaydi"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Oddiy PIN kodlar AT admini tomonidan bloklangan. Murakkabroq PIN kod tanlang."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Parol yaroqsiz belgidan iborat bo‘lmasligi lozim"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Parol tarkibida kamida <xliff:g id="COUNT">%d</xliff:g> ta harf bo‘lmagan belgi bo‘lishi lozim</item>
       <item quantity="one">Parol tarkibida kamida 1 ta harf bo‘lmagan belgi bo‘lishi lozim</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Kamida <xliff:g id="COUNT">%d</xliff:g> ta raqam boʻlmagan belgi boʻlishi lozim</item>
+      <item quantity="one">Kamida 1 ta raqam boʻlmagan belgi boʻlishi lozim</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Qurilma administratori yaqinda foydalanilgan paroldan yana foydalanishga ruxsat bermaydi"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Oddiy parollar AT admini tomonidan bloklangan. Murakkabroq parol tanlang."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Oshib boruvchi, kamayib boruvchi yoki qaytarilgan ketma-ket raqamlarga ruxsat berilmaydi"</string>
@@ -730,7 +732,7 @@
     <string name="bluetooth_pairing_request" msgid="7221745525632573125">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> qurilmasiga ulansinmi?"</string>
     <string name="bluetooth_pairing_key_msg" msgid="1139230917419961975">"Bluetooth orqali ulanish kodi"</string>
     <string name="bluetooth_enter_passkey_msg" msgid="6205151011298670207">"Ulanish kodini kiriting va keyin “Return” yoki “Enter” tugmasini bosing"</string>
-    <string name="bluetooth_enable_alphanumeric_pin" msgid="9138308197078115672">"PIN-kod harflar va belgilardan iborat bo‘ladi"</string>
+    <string name="bluetooth_enable_alphanumeric_pin" msgid="9138308197078115672">"Harflar yoki maxsus belgilardan iborat PIN kod"</string>
     <string name="bluetooth_pin_values_hint" msgid="8044671726261326240">"Odatda 0000 yoki 1234"</string>
     <string name="bluetooth_pin_values_hint_16_digits" msgid="2665983525706661525">"16 ta raqam bo‘lishi lozim"</string>
     <string name="bluetooth_enter_pin_other_device" msgid="1727015949040507621">"Ushbu PIN kodni boshqa qurilmada ham terish lozim bo‘lishi mumkin."</string>
@@ -887,7 +889,7 @@
     <string name="wifi_menu_forget" msgid="7561140554450163075">"Tarmoqni o‘chirish"</string>
     <string name="wifi_menu_modify" msgid="4080178040721021101">"Tarmoqni o‘zgartirish"</string>
     <string name="wifi_empty_list_wifi_off" msgid="272877164691346240">"Mavjud tarmoqlarni ko‘rish uchun Wi‑Fi aloqasini yoqing."</string>
-    <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"Wi‑Fi tarmoqlarini qidirmoqda…"</string>
+    <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"Wi‑Fi tarmoqlar qidirilmoqda…"</string>
     <string name="wifi_empty_list_user_restricted" msgid="2341613007817352431">"Sizda Wi‑Fi tarmog‘ini o‘zgartirishga ruxsatingiz yo‘q."</string>
     <string name="wifi_more" msgid="3538241640407382185">"Yana"</string>
     <string name="wifi_setup_wps" msgid="6730131677695521321">"Avtomatik ravishda sozlash (WPS)"</string>
@@ -973,7 +975,7 @@
     <string name="wifi_do_not_validate_eap_server" msgid="1892537559682474878">"Tasdiqlanmasin"</string>
     <string name="wifi_do_not_validate_eap_server_warning" msgid="3895397996759837323">"Birorta ham sertifikat ko‘rsatilmagan. Aloqangiz ochiq bo‘ladi."</string>
     <string name="wifi_ssid_too_long" msgid="34911971389775920">"Tarmoq nomi juda uzun."</string>
-    <string name="wifi_no_domain_warning" msgid="735859919311067606">"Domenni ko‘rsating."</string>
+    <string name="wifi_no_domain_warning" msgid="735859919311067606">"Domenni kiriting."</string>
     <string name="wifi_wps_available_first_item" msgid="3221671453930485243">"WPS mavjud"</string>
     <string name="wifi_wps_available_second_item" msgid="5703265526619705185">" (WPS mavjud)"</string>
     <string name="wifi_carrier_connect" msgid="7202618367339982884">"Aloqa operatorining Wi‑Fi tarmog‘i"</string>
@@ -1064,7 +1066,7 @@
     <string name="wifi_hotspot_name_summary_connecting" msgid="5176787959408511889">"<xliff:g id="WIFI_HOTSPOT_NAME">%1$s</xliff:g> yoqilmoqda…"</string>
     <string name="wifi_hotspot_name_summary_connected" msgid="8387768642326756749">"Boshqa qurilmalar <xliff:g id="WIFI_HOTSPOT_NAME">%1$s</xliff:g> tarmog‘iga ulanishi mumkin"</string>
     <string name="wifi_hotspot_password_title" msgid="4289338152595154889">"Hotspot paroli"</string>
-    <string name="wifi_hotspot_ap_band_title" msgid="3485744480410441949">"Wi-Fi chastotalari diapazoni"</string>
+    <string name="wifi_hotspot_ap_band_title" msgid="3485744480410441949">"Wi-Fi diapazoni"</string>
     <string name="wifi_hotspot_footer_info_regular" msgid="3876006922622827363">"Boshqa qurilmalaringiz uchun Wi-Fi tarmoq yaratish uchun hotspotdan foydalaning. Hotspot mobil internetingizni tarqatadi. Mobil internet uchun qo‘shimcha to‘lovlar olinishi mumkin."</string>
     <string name="wifi_hotspot_footer_info_local_only" msgid="3339582350894639261">"Ilovalar yaqin-atrofdagi qurilmalarga kontent ulashish uchun hotspot yarata oladi."</string>
     <string name="wifi_hotspot_auto_off_title" msgid="7416022590415189590">"Hotspotni avtomatik faolsizlantirish"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Mobil"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Agar Wi‑Fi ishlamasa, mobil tarmoqdan foydalaning"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Agar mobil tarmoq ishlamasa, Wi-Fi ishlating"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Wi‑Fi orqali chaqiruv. Agar Wi‑Fi oʻchsa, chaqiruv tugatiladi."</string>
@@ -1159,7 +1164,7 @@
     <string name="dock_sounds_enable_summary_off" product="tablet" msgid="2125391395745266946">"Planshetni dokga ulash yoki dokdan chiqarish paytida ovoz yangramasin"</string>
     <string name="dock_sounds_enable_summary_off" product="default" msgid="9075438702849896866">"Telefonni dokka ulash yoki dokdan uzish paytida ovoz chiqarilmasin"</string>
     <string name="account_settings" msgid="1937600532993930396">"Hisoblar"</string>
-    <string name="accessibility_category_work" msgid="2808942060489460727">"Ishchi profil hisoblari – <xliff:g id="MANAGED_BY">%s</xliff:g>"</string>
+    <string name="accessibility_category_work" msgid="2808942060489460727">"Ish profili hisoblari – <xliff:g id="MANAGED_BY">%s</xliff:g>"</string>
     <string name="accessibility_category_personal" msgid="1423427301759058762">"Shaxsiy profil hisoblari"</string>
     <string name="accessibility_work_account_title" msgid="3195468574776888011">"Ishchi hisob – <xliff:g id="MANAGED_BY">%s</xliff:g>"</string>
     <string name="accessibility_personal_account_title" msgid="7251761883688839354">"Shaxsiy hisob – <xliff:g id="MANAGED_BY">%s</xliff:g>"</string>
@@ -1237,7 +1242,7 @@
     <string name="style_and_wallpaper_settings_title" msgid="8898539141152705754">"Mavzu va fon rasmlari"</string>
     <string name="wallpaper_settings_summary_default" msgid="2626880032742784599">"Standart"</string>
     <string name="wallpaper_settings_summary_custom" msgid="8950504698015331202">"Maxsus"</string>
-    <string name="wallpaper_suggestion_title" msgid="3012130414886743201">"Fon rasmini o‘zgartirish"</string>
+    <string name="wallpaper_suggestion_title" msgid="3012130414886743201">"Fon rasmini almashtiring"</string>
     <string name="wallpaper_suggestion_summary" msgid="4247262938988875842">"Ekran uchun fon rasmini tanlang"</string>
     <string name="wallpaper_settings_fragment_title" msgid="1503701065297188901">"Fon rasmi qayerdan tanlansin"</string>
     <string name="screensaver_settings_title" msgid="7720091234133721021">"Ekran lavhasi"</string>
@@ -1305,7 +1310,7 @@
     <string name="system_update_settings_list_item_title" msgid="1907497454722790033">"Tizimni yangilash"</string>
     <string name="system_update_settings_list_item_summary" msgid="3497456690691907873"></string>
     <string name="firmware_version" msgid="547095584029938749">"Android versiyasi"</string>
-    <string name="security_patch" msgid="483709031051932208">"Tizim xavfsizligi uchun yangilanish"</string>
+    <string name="security_patch" msgid="483709031051932208">"Android tizim xavfsizligi yangilanishi"</string>
     <string name="model_info" msgid="1729765474260797594">"Model"</string>
     <string name="model_summary" msgid="8781425868254352168">"Model: %1$s"</string>
     <string name="hardware_info" msgid="174270144950621815">"Model va qurilma"</string>
@@ -1597,7 +1602,7 @@
     <string name="master_clear_button_text" product="default" msgid="8000547818499182920">"Hamma narsani tozalash"</string>
     <string name="master_clear_final_desc" msgid="5189365498015339294">"Barcha shaxsiy maʼlumotlaringiz va yuklab olingan ilovalar tozalab tashlanadi. Bu amalni ortga qaytara olmaysiz."</string>
     <string name="master_clear_final_desc_esim" msgid="3058919823436953662">"Barcha shaxsiy maʼlumotlaringiz, jumladan, yuklab olingan ilovalar va SIM kartalar axboroti tozalab tashlanadi. Bu amalni ortga qaytara olmaysiz."</string>
-    <string name="master_clear_final_button_text" msgid="866772743886027768">"Barchasini o‘chirish"</string>
+    <string name="master_clear_final_button_text" msgid="866772743886027768">"Hammasini tozalash"</string>
     <string name="master_clear_failed" msgid="7588397453984229892">"Dastlabki sozlamalarni qaytarib bo\'lmadi, chunki Tizimni tozalash xizmati javob bermayapti."</string>
     <string name="master_clear_confirm_title" msgid="698328669893512402">"Hamma narsa tozalansinmi?"</string>
     <string name="master_clear_not_available" msgid="4676613348163652454">"Ushbu foydalanuvchiga sozlamalarni zavod holatiga qaytarishga ruxsat berilmagan"</string>
@@ -1642,7 +1647,7 @@
     <string name="mobile_insert_sim_card" msgid="7594550403454243732">"SIM karta solib, qurilmani qayta ishga tushiring"</string>
     <string name="mobile_connect_to_internet" msgid="6031886097365170913">"Iltimos, Internetga ulaning"</string>
     <string name="location_title" msgid="8664674161765477168">"Mening joylashuvim"</string>
-    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"Ishchi profil joyi"</string>
+    <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"Ish profili uchun joy"</string>
     <string name="location_app_level_permissions" msgid="1298041503927632960">"Ilovalar uchun ruxsatlar"</string>
     <string name="location_app_permission_summary_location_off" msgid="541372845344796336">"Joylashuv xizmati yoqilmagan"</string>
     <plurals name="location_app_permission_summary_location_on" formatted="false" msgid="7904821382328758218">
@@ -1651,7 +1656,7 @@
     </plurals>
     <string name="location_category_recent_location_access" msgid="286059523360285026">"Oxirgi joylashuv axboroti"</string>
     <string name="location_recent_location_access_view_details" msgid="2051602261436245905">"Tafsilotlar"</string>
-    <string name="location_no_recent_apps" msgid="77502059586413278">"Hech qanday ilova yaqin vaqtda joylashuv ma‘lumotini so‘ramadi"</string>
+    <string name="location_no_recent_apps" msgid="77502059586413278">"Yaqin-orada hech qanday ilova joylashuv axborotini talab qilmadi"</string>
     <string name="location_no_recent_accesses" msgid="6289916310397279890">"Hech qanday ilova yaqinda joylashuv axborotidan foydalanmagan"</string>
     <string name="location_high_battery_use" msgid="7177199869979522663">"Yuqori batareya sarfi"</string>
     <string name="location_low_battery_use" msgid="5030448574501435888">"Batareya sarfi kam"</string>
@@ -1684,7 +1689,7 @@
     <string name="contributors_title" msgid="6800028420806884340">"Hissa qo‘shganlar"</string>
     <string name="manual" msgid="5431859421432581357">"Qo‘llanma"</string>
     <string name="regulatory_labels" msgid="380968489247381025">"Sertifikat yorliqlari"</string>
-    <string name="safety_and_regulatory_info" msgid="7113766428000920132">"Xavfsizlik va sertifikat qo‘llanmasi"</string>
+    <string name="safety_and_regulatory_info" msgid="7113766428000920132">"Xavfsizlik va standartlarga muvofiqlik"</string>
     <string name="copyright_title" msgid="3847703367689932190">"Mualliflik huquqi"</string>
     <string name="license_title" msgid="7582145947873528540">"Litsenziya"</string>
     <string name="terms_title" msgid="1804549588198223771">"Foydalanish shartlari"</string>
@@ -1701,7 +1706,7 @@
     <string name="settings_safetylegal_activity_unreachable" msgid="3541894966476445833">"Qurilma internetga ulanmagan. Bu ma’lumotni ko‘rish uchun internetga ulangan istalgan kompyuterda %s sahifasini oching."</string>
     <string name="settings_safetylegal_activity_loading" msgid="7680998654145172">"Yuklanmoqda…"</string>
     <string name="confirm_device_credential_use_alternate_method" msgid="1279869272895739941">"Muqobil usuldan foydalanish"</string>
-    <string name="lockpassword_choose_your_screen_lock_header" msgid="6283518876031424798">"Ekranni qulfini sozlash"</string>
+    <string name="lockpassword_choose_your_screen_lock_header" msgid="6283518876031424798">"Ekran qulfini sozlash"</string>
     <string name="lockpassword_choose_your_password_message" msgid="2838273977481046536">"Xavfsizlik uchun parol o‘rnating"</string>
     <string name="lockpassword_choose_your_password_header_for_fingerprint" msgid="4921343500484160894">"Barmoq izidan foydalanish uchun parol o‘rnating"</string>
     <string name="lockpassword_choose_your_pattern_header_for_fingerprint" msgid="314870151462139417">"Avval grafik kalit yarating"</string>
@@ -1730,9 +1735,9 @@
     <string name="lockpassword_strong_auth_required_device_pattern" msgid="1014214190135045781">"Grafik kalitni kiriting"</string>
     <string name="lockpassword_strong_auth_required_device_pin" msgid="24030584350601016">"Qurilma PIN kodini kiriting"</string>
     <string name="lockpassword_strong_auth_required_device_password" msgid="7746588206458754598">"Qurilma parolini kiriting"</string>
-    <string name="lockpassword_strong_auth_required_work_pattern" msgid="6861154706098327320">"Ishchi profil grafik kalitini kiriting"</string>
-    <string name="lockpassword_strong_auth_required_work_pin" msgid="6306902249365524526">"Ishchi profil PIN kodini kiriting"</string>
-    <string name="lockpassword_strong_auth_required_work_password" msgid="2917338218971012776">"Ishchi profil parolini kiriting"</string>
+    <string name="lockpassword_strong_auth_required_work_pattern" msgid="6861154706098327320">"Ish profili grafik kalitini kiriting"</string>
+    <string name="lockpassword_strong_auth_required_work_pin" msgid="6306902249365524526">"Ish profili PIN kodini kiriting"</string>
+    <string name="lockpassword_strong_auth_required_work_password" msgid="2917338218971012776">"Ish profili parolini kiriting"</string>
     <string name="lockpassword_confirm_your_pattern_details_frp" msgid="1085862410379709928">"Telefoningiz zavod sozlamalariga qaytarildi. Bu telefondan foydalanish uchun avvalgi grafik kalitni kiriting."</string>
     <string name="lockpassword_confirm_your_pin_details_frp" msgid="6849889353126558761">"Telefoningiz zavod sozlamalariga qaytarildi. Bu telefondan foydalanish uchun avvalgi PIN kodni kiriting."</string>
     <string name="lockpassword_confirm_your_password_details_frp" msgid="3239944795659418737">"Telefoningiz zavod sozlamalariga qaytarildi. Bu telefondan foydalanish uchun avvalgi parolni kiriting."</string>
@@ -1769,13 +1774,13 @@
     <string name="lockpattern_settings_help_how_to_record" msgid="6037403647312543908">"Grafik kalit qanday chiziladi"</string>
     <string name="lockpattern_too_many_failed_confirmation_attempts" msgid="3043127997770535921">"Juda ko‘p noto‘g‘ri urinishlar bo‘ldi! <xliff:g id="NUMBER">%d</xliff:g> soniyadan so‘ng qayta urinib ko‘ring."</string>
     <string name="activity_not_found" msgid="3492413375341165453">"Ilova telefoningizga o‘rnatilmagan."</string>
-    <string name="lock_settings_profile_title" msgid="3928992050074556160">"Ishchi profil xavfsizligi"</string>
-    <string name="lock_settings_profile_screen_lock_title" msgid="285267471459162203">"Ishchi profil ekran qulfi"</string>
+    <string name="lock_settings_profile_title" msgid="3928992050074556160">"Ish profili xavfsizligi"</string>
+    <string name="lock_settings_profile_screen_lock_title" msgid="285267471459162203">"Ish profili ekran qulfi"</string>
     <string name="lock_settings_profile_unification_title" msgid="2629698644191935287">"Bitta qulfdan foydalanish"</string>
-    <string name="lock_settings_profile_unification_summary" msgid="4797188229308317207">"Ishchi profil va qurilma ekrani uchun bitta qulfdan foydalanish"</string>
+    <string name="lock_settings_profile_unification_summary" msgid="4797188229308317207">"Ish profili va qurilma ekrani uchun bitta qulfdan foydalanish"</string>
     <string name="lock_settings_profile_unification_dialog_title" msgid="1690211342491067179">"Bitta qulfdan foydalanilsinmi?"</string>
-    <string name="lock_settings_profile_unification_dialog_body" msgid="8629158560032603101">"Qurilmangiz ishchi profilingiz ekran qulfidan foydalanadi. Ishchi profil qulfi qoidalari ikkala qulfga ham qo‘llaniladi."</string>
-    <string name="lock_settings_profile_unification_dialog_uncompliant_body" msgid="1217609779267643474">"Ishchi profilning ekran qulfi sozlamalari tashkilotingiz xavfsizlik qoidalariga mos kelmaydi. Qurilma ekrani va ishchi profil uchun bitta qulfdan foydalanishingiz mumkin. Lekin har qanday ishchi profil qulfi qoidalari qo‘llaniladi."</string>
+    <string name="lock_settings_profile_unification_dialog_body" msgid="8629158560032603101">"Qurilmangiz ishchi profilingiz ekran qulfidan foydalanadi. Ish profili qulfi qoidalari ikkala qulfga ham qo‘llaniladi."</string>
+    <string name="lock_settings_profile_unification_dialog_uncompliant_body" msgid="1217609779267643474">"Ish profilining ekran qulfi sozlamalari tashkilotingiz xavfsizlik qoidalariga mos kelmaydi. Qurilma ekrani va ish profili uchun bitta qulfdan foydalanishingiz mumkin. Lekin har qanday ish profili qulfi qoidalari qo‘llaniladi."</string>
     <string name="lock_settings_profile_unification_dialog_confirm" msgid="888942752619181804">"Bitta qulfdan foydalanish"</string>
     <string name="lock_settings_profile_unification_dialog_uncompliant_confirm" msgid="8046452284593057185">"Bitta qulfdan foydalanish"</string>
     <string name="lock_settings_profile_unified_summary" msgid="5347244550751740962">"Qurilmaning qulflash usulidan foydalanish"</string>
@@ -1795,7 +1800,7 @@
     <string name="advanced_settings_summary" msgid="5912237062506771716">"Qo‘shimcha sozlamalar tanlamalarini yoqib qo‘yish"</string>
     <string name="application_info_label" msgid="3886253474964599105">"Ilova haqida"</string>
     <string name="storage_label" msgid="1109537840103290384">"Xotira"</string>
-    <string name="auto_launch_label" msgid="47089737922907379">"Odatiy tarzda ochish"</string>
+    <string name="auto_launch_label" msgid="47089737922907379">"Birlamchi sifatida ochish"</string>
     <string name="auto_launch_label_generic" msgid="7865828543459493308">"Birlamchi"</string>
     <string name="screen_compatibility_label" msgid="3638271673726075815">"Ekrandagi moslashuv"</string>
     <string name="permissions_label" msgid="7341733648403464213">"Ruxsatlar"</string>
@@ -1824,7 +1829,7 @@
     <string name="app_factory_reset" msgid="8718986000278776272">"Yangilanishlarni o‘chirish"</string>
     <string name="auto_launch_enable_text" msgid="3372898942144027341">"Ushbu ilovaning ba’zi andoza harakatlarini tanladingiz."</string>
     <string name="always_allow_bind_appwidgets_text" msgid="2286211654774611037">"Ushbu ilova vidjetlar yaratish va ularning ma‘lumotlariga kirishiga ruxsat berishni tanladingiz."</string>
-    <string name="auto_launch_disable_text" msgid="8560921288036801416">"Birlamchi sozlamalar o‘rnatilmagan."</string>
+    <string name="auto_launch_disable_text" msgid="8560921288036801416">"Birlamchi sozlamalar belgilanmagan."</string>
     <string name="clear_activities" msgid="2068014972549235347">"Birlamchilarni tozalash"</string>
     <string name="screen_compatibility_text" msgid="1768064020294301496">"Ushbu ilova siznikidaqa ekranlar uchun mos qilib chiqarilmagan. Ekraningiz moslamalarini mana bu yerda o‘zgartirishingiz mumkin."</string>
     <string name="ask_compatibility" msgid="6687958195768084807">"Ishga tushirilganda so‘rash"</string>
@@ -1968,7 +1973,7 @@
     <string name="show_ime_summary" msgid="3246628154011464373">"Jismoniy klaviatura ulanganida ekranda chiqib turadi"</string>
     <string name="keyboard_shortcuts_helper" msgid="6574386807271399788">"Tezkor tugmalar"</string>
     <string name="keyboard_shortcuts_helper_summary" msgid="8024313306403779742">"Tezkor tugmalarni ekranga chiqarish"</string>
-    <string name="language_and_input_for_work_category_title" msgid="2053255944038892588">"Ishchi profil klaviaturalari va vositalari"</string>
+    <string name="language_and_input_for_work_category_title" msgid="2053255944038892588">"Ish profili klaviaturalari va vositalari"</string>
     <string name="virtual_keyboards_for_work_title" msgid="3968291646938204523">"Ish uchun virtual klaviatura"</string>
     <string name="default_keyboard_layout" msgid="9171704064451242230">"Standart"</string>
     <string name="pointer_speed" msgid="800691982011350432">"Kursor tezligi"</string>
@@ -2034,7 +2039,7 @@
     <string name="accessibility_settings_summary" msgid="5742379519336396561">"Ekran suxandoni, displey, boshqaruv elementlari"</string>
     <string name="vision_settings_title" msgid="7315352351051423944">"Maxsus imkoniyatlar"</string>
     <string name="vision_settings_description" msgid="3476589459009287332">"Qurilmangizdan qulay foydalanish uchun maxsus imkoniyatlardan foydalaning. Bu parametrlarni keyinroq sozlamalar orqali o‘zgartirish mumkin."</string>
-    <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"Shrift o‘lchamini o‘zgartirish"</string>
+    <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"Shrift o‘lchamini o‘zgartiring"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"Ekrandan o‘qish vositalari"</string>
     <string name="audio_and_captions_category_title" msgid="6140472938769619212">"Audio va ekrandagi matn"</string>
     <string name="display_category_title" msgid="545168481672250195">"Ekran"</string>
@@ -2083,7 +2088,7 @@
     <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"Bosganda va bosib turganda kechikish"</string>
     <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"Ranglarni akslantirish"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"Unumdorligiga ta’sir qilishi mumkin"</string>
-    <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"Kutish vaqti"</string>
+    <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"Kechikish vaqti"</string>
     <string name="accessibility_autoclick_description" msgid="5492414927846407499">"Agar sichqoncha ishlatsangiz, muayyan vaqtdan keyin kursor harakatlanishdan to‘xtaganda u avtomatik ishlashini sozlashingiz mumkin."</string>
     <string name="accessibility_autoclick_delay_preference_title" msgid="8303022510942147049">"Bosishdan oldin biroz kuting"</string>
     <string name="accessibility_vibration_settings_title" msgid="1902649657883159406">"Tebranish"</string>
@@ -2091,7 +2096,7 @@
     <string name="accessibility_ring_vibration_title" msgid="7943341443551359985">"Jiringlaganda tebranish"</string>
     <string name="accessibility_touch_vibration_title" msgid="285890135612038092">"Sensor tebranishi"</string>
     <string name="accessibility_service_master_switch_title" msgid="2734791644475782924">"Xizmatdan foydalanish"</string>
-    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Rangni tuzatish funksiyasidan foydalanish"</string>
+    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Rangni tuzatishdan foydalanish"</string>
     <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"Taglavhalardan foydalanish"</string>
     <string name="accessibility_hearingaid_instruction_continue_button" msgid="4650111296711466691">"Davom etish"</string>
     <string name="accessibility_hearingaid_title" msgid="3700978781235124891">"Eshitish apparatlari"</string>
@@ -2146,7 +2151,7 @@
     <string name="captioning_standard_options_title" msgid="4124898413348084226">"Standart sozlamalar"</string>
     <string name="captioning_locale" msgid="4734464353806207943">"Til"</string>
     <string name="captioning_text_size" msgid="1707122517246408084">"Matn o‘lchami"</string>
-    <string name="captioning_preset" msgid="7429888317480872337">"Taglavhalar ko‘rinishi"</string>
+    <string name="captioning_preset" msgid="7429888317480872337">"Taglavhalar uslubi"</string>
     <string name="captioning_custom_options_title" msgid="4530479671071326732">"Buyurtmali tanlamalar"</string>
     <string name="captioning_background_color" msgid="2434458880326292180">"Fon rangi"</string>
     <string name="captioning_background_opacity" msgid="8178926599201811936">"Fon yarim tiniqligi"</string>
@@ -2157,7 +2162,7 @@
     <string name="captioning_edge_color" msgid="4330622137047993780">"Qirra rangi"</string>
     <string name="captioning_edge_type" msgid="4414946407430588162">"Qirra turi"</string>
     <string name="captioning_typeface" msgid="7893208796949341767">"Shriftlar oilasi"</string>
-    <string name="captioning_preview_text" msgid="4877753964772618049">"Taglavlahar shunday ko‘rinadi"</string>
+    <string name="captioning_preview_text" msgid="4877753964772618049">"Taglavhalar shunday chiqadi"</string>
     <string name="captioning_preview_characters" msgid="6469599599352973561">"Aa"</string>
     <string name="locale_default" msgid="910074908458214054">"Birlamchi"</string>
     <string name="color_title" msgid="132875486061816584">"Rang"</string>
@@ -2169,7 +2174,7 @@
     <string name="color_red" msgid="7426040122729897596">"Qizil"</string>
     <string name="color_green" msgid="3432648781089648971">"Yashil"</string>
     <string name="color_blue" msgid="4055855996393833996">"Ko‘k"</string>
-    <string name="color_cyan" msgid="7669317410901991453">"Moviy"</string>
+    <string name="color_cyan" msgid="7669317410901991453">"Zangori"</string>
     <string name="color_yellow" msgid="8847327436896180799">"Sariq"</string>
     <string name="color_magenta" msgid="721976999611563071">"Pushtirang"</string>
     <string name="enable_service_title" msgid="2746143093464928251">"<xliff:g id="SERVICE">%1$s</xliff:g> yoqilsinmi?"</string>
@@ -2607,12 +2612,12 @@
     <string name="sync_active" msgid="1112604707180806364">"Sinxronlash faol"</string>
     <string name="account_sync_settings_title" msgid="3344538161552327748">"Sinxronlash"</string>
     <string name="sync_is_failing" msgid="8284618104132302644">"Sinxronizatsiyada muammo bor. Tez orada qayta tiklanadi."</string>
-    <string name="add_account_label" msgid="4461298847239641874">"Hisob qo‘shish"</string>
-    <string name="managed_profile_not_available_label" msgid="8784246681719821917">"Ishchi profil hali mavjud emas"</string>
-    <string name="work_mode_label" msgid="6845849194740195757">"Ishchi profil"</string>
+    <string name="add_account_label" msgid="4461298847239641874">"Hisob kiritish"</string>
+    <string name="managed_profile_not_available_label" msgid="8784246681719821917">"Ish profili hali mavjud emas"</string>
+    <string name="work_mode_label" msgid="6845849194740195757">"Ish profili"</string>
     <string name="work_mode_on_summary" msgid="1682781113156323592">"Tashkilotingiz tomonidan boshqariladi"</string>
     <string name="work_mode_off_summary" msgid="1688885392211178315">"Ilovalar va bildirishnomalar o‘chiq"</string>
-    <string name="remove_managed_profile_label" msgid="4625542553784793536">"Ishchi profilni o‘chirish"</string>
+    <string name="remove_managed_profile_label" msgid="4625542553784793536">"Ish profilini olib tashlash"</string>
     <string name="background_data" msgid="8275750862371471171">"Ma’lumotlarni fonda yuklash"</string>
     <string name="background_data_summary" msgid="799640633948841990">"Ilovalar sinxronlanishi, ma’lumotlarni istalgan paytda jo‘natishi va qabul qilishi mumkin"</string>
     <string name="background_data_dialog_title" msgid="8306650658158895976">"Ma’lumotlarni fonda yuklash to‘xtatilsinmi?"</string>
@@ -2639,7 +2644,7 @@
     <string name="header_account_settings" msgid="8586173964125512219">"Hisob sozlamalari"</string>
     <string name="remove_account_label" msgid="5885425720323823387">"Hisobni olib tashlash"</string>
     <string name="header_add_an_account" msgid="8482614556580804956">"Hisob kiriting"</string>
-    <string name="really_remove_account_title" msgid="4166512362915154319">"Hisobni olib tashlansinmi?"</string>
+    <string name="really_remove_account_title" msgid="4166512362915154319">"Hisob olib tashlansinmi?"</string>
     <string name="really_remove_account_message" product="tablet" msgid="7403843371045856719">"Ushbu hisob bilan bog‘liq barcha xabarlar, kontaktlar va boshqa ma’lumotlar telefondan o‘chib ketadi."</string>
     <string name="really_remove_account_message" product="default" msgid="8951224626153163914">"Ushbu hisob bilan bog‘liq barcha xabarlar, kontaktlar va boshqa ma’lumotlar telefondan o‘chib ketadi."</string>
     <string name="really_remove_account_message" product="device" msgid="3751798556257519916">"Ushbu hisob o‘chirilganda unga bog‘liq barcha xabar, kontakt va boshqa ma’lumotlar qurilmadan o‘chib ketadi."</string>
@@ -2681,8 +2686,8 @@
     <string name="data_usage_menu_sim_cards" msgid="8508154611676507088">"SIM kartalar"</string>
     <string name="data_usage_cellular_data_summary" msgid="9162777397135709280">"To‘xtatildi (limit)"</string>
     <string name="account_settings_menu_auto_sync" msgid="2673669556006027506">"Avto-sinxronizatsiya"</string>
-    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"Avto-sinxronizatsiya (shaxsiy)"</string>
-    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Avto-sinxronizatsiya (ishchi)"</string>
+    <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"Avtomatik sinxronlash (shaxsiy)"</string>
+    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Avtomatik sinxronlash (ish)"</string>
     <string name="data_usage_change_cycle" msgid="447761920472170031">"O‘zgartirish…"</string>
     <string name="data_usage_pick_cycle_day" msgid="6319750879145917066">"Oyning qaysi kunida trafik sarfi davri yangilansin:"</string>
     <string name="data_usage_empty" msgid="7981405723435034032">"Ushbu vaqt oralig‘ida hech qanday ilova trafik sarflamadi."</string>
@@ -2749,7 +2754,7 @@
     <string name="data_usage_metered_no" msgid="1961524615778610008">"Bepul"</string>
     <string name="data_usage_disclaimer" msgid="4683321532922590425">"Aloqa operatorining hisob-kitobi qurilmanikidan farq qilishi mumkin."</string>
     <string name="cryptkeeper_emergency_call" msgid="4625420047524693116">"Favqulodda chaqiruv"</string>
-    <string name="cryptkeeper_return_to_call" msgid="4433942821196822815">"Chaqiruvga qaytish"</string>
+    <string name="cryptkeeper_return_to_call" msgid="4433942821196822815">"Suhbatga qaytish"</string>
     <string name="vpn_name" msgid="3538818658670774080">"Tarmoq nomi"</string>
     <string name="vpn_type" msgid="6389116710008658550">"Turi"</string>
     <string name="vpn_server" msgid="5216559017318406820">"Server manzili"</string>
@@ -2870,7 +2875,7 @@
     <string name="user_set_lock_button" msgid="4660971133148866612">"Qulf o‘rnatish"</string>
     <string name="user_summary_not_set_up" msgid="6436691939044332679">"Sozlanmagan"</string>
     <string name="user_summary_restricted_not_set_up" msgid="896552290436689508">"Sozlanmagan - Cheklangan profil"</string>
-    <string name="user_summary_managed_profile_not_set_up" msgid="3032986082684011281">"Ishchi profil – sozlanmagan"</string>
+    <string name="user_summary_managed_profile_not_set_up" msgid="3032986082684011281">"Ish profili – sozlanmagan"</string>
     <string name="user_admin" msgid="805802526361071709">"Administrator"</string>
     <string name="user_you" msgid="8212549708652717106">"Siz (<xliff:g id="NAME">%s</xliff:g>)"</string>
     <string name="user_nickname" msgid="1088216221559125529">"Nik nomi"</string>
@@ -2899,7 +2904,7 @@
     <string name="user_confirm_remove_self_title" msgid="6739480453680217543">"Profilingiz o‘chirilsinmi?"</string>
     <string name="user_confirm_remove_title" msgid="1034498514019462084">"Olib tashlansinmi?"</string>
     <string name="user_profile_confirm_remove_title" msgid="6138684743385947063">"Profil o‘chirilsinmi?"</string>
-    <string name="work_profile_confirm_remove_title" msgid="3168910958076735800">"Profil o‘chirilsinmi?"</string>
+    <string name="work_profile_confirm_remove_title" msgid="3168910958076735800">"Ish profili olib tashlansinmi?"</string>
     <string name="user_confirm_remove_self_message" product="tablet" msgid="2889456786320157545">"Ushbu planshetda saqlangan ma’lumotlaringiz o‘chib ketadi. Bu amalni ortga qaytarib bo‘lmaydi."</string>
     <string name="user_confirm_remove_self_message" product="default" msgid="8441729423565705183">"Ushbu telefonda saqlangan ma’lumotlaringiz o‘chib ketadi. Bu amalni ortga qaytarib bo‘lmaydi."</string>
     <string name="user_confirm_remove_message" msgid="5202150470271756013">"Barcha ilovalar va ma’lumotlar o‘chirib tashlanadi."</string>
@@ -2931,11 +2936,11 @@
     <string name="nfc_payment_default" msgid="7869273092463612271">"Birlamchi to‘lov vositasi"</string>
     <string name="nfc_payment_default_not_set" msgid="955804193510335338">"Tanlanmagan"</string>
     <string name="nfc_payment_app_and_desc" msgid="102312684211458190">"<xliff:g id="APP">%1$s</xliff:g> – <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
-    <string name="nfc_payment_use_default" msgid="3098724195746409476">"Birlamchi ilovadan foydalanilsin"</string>
+    <string name="nfc_payment_use_default" msgid="3098724195746409476">"Birlamchi ilovadan foydalanish"</string>
     <string name="nfc_payment_favor_default" msgid="7555356982142464260">"Har doim"</string>
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Boshqa to‘lov ilovasi ochiq holat bundan mustasno"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"Kontaktsiz to‘lovda bundan foydalanilsin:"</string>
-    <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Terminal orqali to‘lash"</string>
+    <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Qanday toʻlanadi"</string>
     <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Avval to‘lov ilovasini sozlang. Keyin telefoningiz orqa tomonini kontaktsiz to‘lov belgisi tushirilgan terminalga yaqinlashtiring."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"OK"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"Yana…"</string>
@@ -3018,8 +3023,8 @@
     <string name="sim_editor_number" msgid="1757338150165234970">"Raqam"</string>
     <string name="sim_editor_color" msgid="373059962306191123">"SIM karta rangi"</string>
     <string name="sim_card_select_title" msgid="4925862525985187946">"SIM kartani tanlang"</string>
-    <string name="color_orange" msgid="3159707916066563431">"To‘q sariq"</string>
-    <string name="color_purple" msgid="4391440966734810713">"Binafsharang"</string>
+    <string name="color_orange" msgid="3159707916066563431">"Apelsinrang"</string>
+    <string name="color_purple" msgid="4391440966734810713">"Siyohrang"</string>
     <string name="sim_no_inserted_msg" msgid="1197884607569714609">"SIM karta solinmagan"</string>
     <string name="sim_status_title" msgid="4483653750844520871">"SIM karta holati"</string>
     <string name="sim_status_title_sim_slot" msgid="416005570947546124">"SIM karta holati (%1$d-SIM uyasi)"</string>
@@ -3104,7 +3109,7 @@
     <string name="keywords_color_temperature" msgid="2255253972992035046">"rang, harorat, D65, D73, oq, sariq, ko‘k, iliq, salqin"</string>
     <string name="keywords_lockscreen" msgid="4936846554280830394">"qulfni ochish uchun surish, parol, grafik kalit, PIN kod"</string>
     <string name="keywords_profile_challenge" msgid="8653718001253979611">"ish vazifasi, ish, profil"</string>
-    <string name="keywords_unification" msgid="2020759909366983593">"ishchi profil, boshqariluvchi profil, birlashtirish, birlashuv, ish, profil"</string>
+    <string name="keywords_unification" msgid="2020759909366983593">"ish profili, boshqariluvchi profil, birlashtirish, birlashuv, ish, profil"</string>
     <string name="keywords_gesture" msgid="5031323247529869644">"imo-ishoralar"</string>
     <string name="keywords_payment_settings" msgid="4745023716567666052">"to‘lash, bosish, to‘lovlar"</string>
     <string name="keywords_backup" msgid="7433356270034921627">"zaxira, zaxira nusxa olish"</string>
@@ -3173,7 +3178,7 @@
     <string name="emergency_tone_vibrate" msgid="5020068066905681181">"Tebranishlar"</string>
     <string name="boot_sounds_title" msgid="7583926202411353620">"Ovozni yoqish"</string>
     <string name="live_caption_title" msgid="7926591158657997051">"Jonli izoh"</string>
-    <string name="live_caption_summary" msgid="9064771862352393125">"Avtomatik taglavha mediasi"</string>
+    <string name="live_caption_summary" msgid="9064771862352393125">"Avtomatik taglavha yaratish"</string>
     <string name="zen_mode_settings_summary_off" msgid="6929319200478424962">"Hech qachon"</string>
     <plurals name="zen_mode_settings_summary_on" formatted="false" msgid="6061723291126091396">
       <item quantity="other"><xliff:g id="ON_COUNT">%d</xliff:g> ta yoqilgan</item>
@@ -3291,7 +3296,7 @@
     <string name="zen_onboarding_new_setting_summary" msgid="8264430315983860075">"Bildirishnomalar chiqmaydi yoki eshittirilmaydi. Yulduzchali kontaktlardan chaqiruvlar va qayta chaqiruvlarga ruxsat berilgan."</string>
     <string name="zen_onboarding_current_setting_summary" msgid="3569246708507270821">"(Joriy parametr)"</string>
     <string name="zen_onboarding_dnd_visual_disturbances_header" msgid="7584229011611927613">"Bezovta qilinmasin rejimining bildirishnomalar sozlamalari o‘zgartirilsinmi?"</string>
-    <string name="sound_work_settings" msgid="4140215240360927923">"Ishchi profil ovozlari"</string>
+    <string name="sound_work_settings" msgid="4140215240360927923">"Ish profili ovozlari"</string>
     <string name="work_use_personal_sounds_title" msgid="531727195073003599">"Shaxsiy profil ovozlaridan foydalanish"</string>
     <string name="work_use_personal_sounds_summary" msgid="2886871383995187441">"Tovushlar ishchi va shaxsiy profillar uchun bir xil"</string>
     <string name="work_ringtone_title" msgid="5499360583947410224">"Ishchi telefon ringtoni"</string>
@@ -3300,7 +3305,7 @@
     <string name="work_sound_same_as_personal" msgid="7728560881697159758">"Shaxsiy profilniki bilan bir xil"</string>
     <string name="work_sync_dialog_title" msgid="4799120971202956837">"Tovushlar almashtirilsinmi?"</string>
     <string name="work_sync_dialog_yes" msgid="2110726233746476066">"Almashtirish"</string>
-    <string name="work_sync_dialog_message" msgid="944233463059129156">"Joriy ishchi profil tovushlaridan ishchi profilingizda foydalaniladi"</string>
+    <string name="work_sync_dialog_message" msgid="944233463059129156">"Joriy ish profili tovushlaridan ish profiliingizda foydalaniladi"</string>
     <string name="ringtones_install_custom_sound_title" msgid="210551218424553671">"Maxsus ovoz qo‘shilsinmi?"</string>
     <string name="ringtones_install_custom_sound_content" msgid="6683649115132255452">"Bu fayldan <xliff:g id="FOLDER_NAME">%s</xliff:g> jildiga nusxalanadi"</string>
     <string name="ringtones_category_preference_title" msgid="4491932700769815470">"Ringtonlar"</string>
@@ -3331,14 +3336,14 @@
     <string name="swipe_direction_rtl" msgid="4521416787262888813">"Yopish uchun chapga, menyuni ochish uchun oʻngga suring"</string>
     <string name="notification_pulse_title" msgid="4861418327614907116">"Indikator"</string>
     <string name="lock_screen_notifications_title" msgid="6889072265118747835">"Qulflangan ekranda"</string>
-    <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"Ishchi profil qulflanganda"</string>
+    <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"Ish profili qulflanganda"</string>
     <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Bildirishnomalar butun chiqsin"</string>
     <string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"Maxfiy axborotlar berkitilsin"</string>
     <string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"Bildirishnomalar chiqmasin"</string>
     <string name="lock_screen_notifications_interstitial_message" msgid="4230189215124387818">"Qurilmangiz qulflanganda, bildirishnomalar qanday chiqsin?"</string>
     <string name="lock_screen_notifications_interstitial_title" msgid="2832587379332443505">"Bildirishnomalar"</string>
     <string name="lock_screen_notifications_summary_show_profile" msgid="8908775469657073273">"Ishchi bildirishnomalar butun chiqsin"</string>
-    <string name="lock_screen_notifications_summary_hide_profile" msgid="7898086300511010591">"Ishchi profil ma’lumotlari berkitilsin"</string>
+    <string name="lock_screen_notifications_summary_hide_profile" msgid="7898086300511010591">"Ish profili ma’lumotlari berkitilsin"</string>
     <string name="lock_screen_notifications_interstitial_message_profile" msgid="3324187664458600354">"Qurilmangiz qulflanganda, profil bildirishnomalari qanday chiqsin?"</string>
     <string name="lock_screen_notifications_interstitial_title_profile" msgid="4043621508889929254">"Profil bildirishnomalari"</string>
     <string name="notifications_title" msgid="8334011924253810654">"Bildirishnomalar"</string>
@@ -3372,7 +3377,7 @@
     <string name="notifications_sent_weekly" msgid="5859675428990259432">"Haftasiga ~<xliff:g id="NUMBER">%1$s</xliff:g>"</string>
     <string name="notifications_sent_never" msgid="237997329598144638">"Hech qachon"</string>
     <string name="manage_notification_access_title" msgid="5348743662189787547">"Bildirishnomalarga kirish"</string>
-    <string name="work_profile_notification_access_blocked_summary" msgid="8148871282484870576">"Ishchi profil bildirishnomalariga kirish taqiqlangan"</string>
+    <string name="work_profile_notification_access_blocked_summary" msgid="8148871282484870576">"Ish profili bildirishnomalariga kirish taqiqlangan"</string>
     <string name="manage_notification_access_summary_zero" msgid="236809421271593016">"Ilovalar bildirishnomalarni ko‘ra olmaydi"</string>
     <plurals name="manage_notification_access_summary_nonzero" formatted="false" msgid="8496218948429646792">
       <item quantity="other">%d ilova bildirishnomalarni o‘qishi mumkin</item>
@@ -3571,7 +3576,7 @@
     <string name="screen_pinning_unlock_pin" msgid="1441705536015645023">"Yechishda PIN kod talab qilinsin"</string>
     <string name="screen_pinning_unlock_password" msgid="1017776884000170841">"Yechishdan oldin parol so‘ralsin"</string>
     <string name="screen_pinning_unlock_none" msgid="9183040569733226911">"Yechish vaqtida qurilma qulflansin"</string>
-    <string name="opening_paragraph_delete_profile_unknown_company" msgid="2350380017136403670">"Bu ishchi profil quyidagi tomonidan boshqariladi:"</string>
+    <string name="opening_paragraph_delete_profile_unknown_company" msgid="2350380017136403670">"Bu ish profili quyidagi tomonidan boshqariladi:"</string>
     <string name="managing_admin" msgid="3212584016377581608">"<xliff:g id="ADMIN_APP_LABEL">%s</xliff:g> tomonidan boshqariladi"</string>
     <string name="experimental_preference" msgid="5903223408406906322">"(Tajribaviy)"</string>
     <string name="encryption_interstitial_header" msgid="3298397268731647519">"Xavfsiz ishga tushirish"</string>
@@ -3599,7 +3604,7 @@
     <string name="imei_information_title" msgid="7666097743700170757">"IMEI kod ma’lumotlari"</string>
     <string name="imei_information_summary" msgid="716516316022275083">"IMEI raqamiga aloqador ma’lumotlar"</string>
     <string name="slot_number" msgid="785422579177068698">"(<xliff:g id="SLOT_NUM">%1$d</xliff:g>-uya)"</string>
-    <string name="launch_by_default" msgid="6106985160202769725">"Odatiy tarzda ochish"</string>
+    <string name="launch_by_default" msgid="6106985160202769725">"Birlamchi sifatida ochish"</string>
     <string name="app_launch_domain_links_title" msgid="2987289657348349133">"Havolalarni ochish"</string>
     <string name="app_launch_open_domain_urls_title" msgid="8595126859922391331">"Mos havolalarni ochish"</string>
     <string name="app_launch_open_domain_urls_summary" msgid="6803029846855502366">"Avtomatik ochilsin"</string>
@@ -3646,7 +3651,7 @@
     <string name="filter_enabled_apps" msgid="5888459261768538489">"Oʻrnatilgan ilovalar"</string>
     <string name="filter_instant_apps" msgid="8087483282854072366">"Darhol ochiladigan ilovalar"</string>
     <string name="filter_personal_apps" msgid="3473268022652904457">"Shaxsiy"</string>
-    <string name="filter_work_apps" msgid="4202483998339465542">"Ishga oid"</string>
+    <string name="filter_work_apps" msgid="4202483998339465542">"Ish"</string>
     <string name="filter_notif_all_apps" msgid="1862666327228804896">"Ilovalar: hammasi"</string>
     <string name="filter_notif_blocked_apps" msgid="5694956954776028202">"Bildirishnoma kelmaydigan"</string>
     <string name="filter_notif_urgent_channels" msgid="5000735867167027148">"Turkumlar: favqulodda muhim"</string>
@@ -3728,9 +3733,7 @@
     <!-- no translation found for battery_summary (4345690800899981339) -->
     <skip />
     <string name="battery_power_management" msgid="2853925857548647969">"Quvvat boshqaruvi"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for no_battery_summary (4105932628367471314) -->
-    <skip />
+    <string name="no_battery_summary" msgid="4105932628367471314">"Toʻliq quvvatlanganidan beri quvvat sarflanmadi"</string>
     <string name="app_notification_preferences" msgid="5154466638524523201">"Ilova sozlamalari"</string>
     <string name="system_ui_settings" msgid="6751165163665775447">"SystemUI Tuner ko‘rsatilsin"</string>
     <string name="additional_permissions" msgid="3142290772324571654">"Qo‘shimcha ruxsatlar"</string>
@@ -3914,7 +3917,7 @@
     <string name="condition_cellular_summary" msgid="3607459310548343777">"Internet faqat Wi‑Fi orqali ishlaydi"</string>
     <string name="condition_bg_data_title" msgid="184684435298857712">"Trafik tejash"</string>
     <string name="condition_bg_data_summary" msgid="5194942860807136682">"Ayrim funksiyalar cheklangan"</string>
-    <string name="condition_work_title" msgid="9046811302347490371">"Ishchi profil o‘chirilgan"</string>
+    <string name="condition_work_title" msgid="9046811302347490371">"Ish profili o‘chirilgan"</string>
     <string name="condition_work_summary" msgid="5586134491975748565">"Ilova va bildirishnomalarga"</string>
     <string name="condition_device_muted_action_turn_on_sound" msgid="5849285946804815263">"Ovozni yoqish"</string>
     <string name="condition_device_muted_title" msgid="3930542786434609976">"Ovozsiz qilindi"</string>
@@ -4096,7 +4099,7 @@
     <string name="quick_settings_developer_tiles" msgid="7423485925757678719">"Tezkor sozlamalarning dasturchi tugmalari"</string>
     <string name="winscope_trace_quick_settings_title" msgid="940971040388411374">"Winscope trassirovkasi"</string>
     <string name="sensors_off_quick_settings_title" msgid="3655699045300438902">"Sensorlar nofaol"</string>
-    <string name="managed_profile_settings_title" msgid="4340409321523532402">"Ishchi profil sozlamalari"</string>
+    <string name="managed_profile_settings_title" msgid="4340409321523532402">"Ish profili sozlamalari"</string>
     <string name="managed_profile_contact_search_title" msgid="7337225196804457095">"Kontaktlarni qidirish"</string>
     <string name="managed_profile_contact_search_summary" msgid="7278267480246726951">"Tashkilot nomi bo‘yicha qidiruvda qo‘ng‘iroq qiluvchi abonent va uning kontaktini aniqlashga ruxsat berish"</string>
     <string name="cross_profile_calendar_title" msgid="2351605904015067145">"Taqvimlarni sinxronlash"</string>
@@ -4137,7 +4140,7 @@
     <string name="swipe_up_to_switch_apps_suggestion_summary" msgid="7338653224520387852">"Ilovalarni almashtirish uchun yangi ishorani yoqing"</string>
     <string name="ambient_display_title" product="default" msgid="6785677099744344088">"Ekranga ikki marta bosib tekshirish"</string>
     <string name="ambient_display_title" product="tablet" msgid="1106285490888683613">"Ekranga ikki marta bosib tekshirish"</string>
-    <string name="ambient_display_title" product="device" msgid="5064644474876041478">"Ekranga ikki marta bosib tekshirish"</string>
+    <string name="ambient_display_title" product="device" msgid="5064644474876041478">"Ekranga ikki marta teginish"</string>
     <string name="ambient_display_summary" msgid="4882910328216411109">"Vaqt, bildirishnoma va boshqa axborotlarni tekshirish uchun ekranga ikki marta bosing."</string>
     <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"Telefonni olib tekshirish"</string>
     <string name="ambient_display_pickup_title" product="tablet" msgid="1555456400210301959">"Planshetni olib tekshirish"</string>
@@ -4150,7 +4153,7 @@
     <string name="ambient_display_tap_screen_title" product="tablet" msgid="6434521782016864148">"Planshetni tekshirish uchun bosing"</string>
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"Qurilmani tekshirish uchun bosing"</string>
     <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"Vaqt, bildirishnoma va boshqa axborotni tekshirish uchun ekranni bosing."</string>
-    <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"Bildirishnomalarni ochish uchun barmoq izi skaneridan foydalanish"</string>
+    <string name="fingerprint_swipe_for_notifications_title" msgid="3676002930672489760">"Bildirishnomalarni barmoq izi bilan ochish"</string>
     <string name="fingerprint_gesture_screen_title" msgid="8638932855807473479">"Barmoq izi skaneri"</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="default" msgid="4347999905190477310">"Bildirishnomalarni tekshirish uchun telefon orqasidagi barmoq izi skaneri ustida pastga suring"</string>
     <string name="fingerprint_swipe_for_notifications_summary" product="tablet" msgid="3480057984564476283">"Bildirishnomalarni tekshirish uchun planshet orqasidagi barmoq izi skaneri ustida pastga suring"</string>
@@ -4224,7 +4227,7 @@
     <string name="enterprise_privacy_lock_device" msgid="1533125067038409945">"Administrator qurilmani qulflashi va parolni o‘zgartirishi mumkin"</string>
     <string name="enterprise_privacy_wipe_device" msgid="7555287990273929922">"Administrator barcha qurilma ma’lumotlarini o‘chirib tashlashi mumkin"</string>
     <string name="enterprise_privacy_failed_password_wipe_device" msgid="4101502079202483156">"Qurilmadagi barcha ma’lumotlar o‘chirib tashlanishi uchun necha marta parol xato kiritilishi kerak"</string>
-    <string name="enterprise_privacy_failed_password_wipe_work" msgid="2881646286634693392">"Ishchi profil ma’lumotlari o‘chirib tashlanishi uchun necha marta parol xato kiritilishi kerak"</string>
+    <string name="enterprise_privacy_failed_password_wipe_work" msgid="2881646286634693392">"Ish profili ma’lumotlari o‘chirib tashlanishi uchun necha marta parol xato kiritilishi kerak"</string>
     <plurals name="enterprise_privacy_number_failed_password_wipe" formatted="false" msgid="562550414712223382">
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ta urinish</item>
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ta urinish</item>
@@ -4488,7 +4491,7 @@
     <string name="privacy_dashboard_title" msgid="8764930992456607513">"Maxfiylik"</string>
     <string name="privacy_dashboard_summary" msgid="7916431309860824945">"Ruxsatlar, hisobdagi harakatlar, shaxsiy axborotlar"</string>
     <string name="contextual_card_dismiss_remove" msgid="1750420285615827309">"Olib tashlansin"</string>
-    <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"Saqlansin"</string>
+    <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"Saqlab qolinsin"</string>
     <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"Bu tavsiya olib tashlansinmi?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"Taklif olib tashlandi"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"Qaytarish"</string>
diff --git a/tests/CarDeveloperOptions/res/values-vi/arrays.xml b/tests/CarDeveloperOptions/res/values-vi/arrays.xml
index a34ad55..e04d389 100644
--- a/tests/CarDeveloperOptions/res/values-vi/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-vi/arrays.xml
@@ -256,8 +256,8 @@
     <item msgid="7565226799008076833">"âm lượng chính"</item>
     <item msgid="5420704980305018295">"âm lượng thoại"</item>
     <item msgid="5797363115508970204">"âm lượng chuông"</item>
-    <item msgid="8233154098550715999">"âm lượng phương tiện"</item>
-    <item msgid="5196715605078153950">"âm lượng báo thức"</item>
+    <item msgid="8233154098550715999">"âm lượng nội dung nghe nhìn"</item>
+    <item msgid="5196715605078153950">"âm lượng chuông báo"</item>
     <item msgid="394030698764284577">"âm lượng thông báo"</item>
     <item msgid="8952898972491680178">"âm lượng bluetooth"</item>
     <item msgid="8506227454543690851">"không khóa màn hình"</item>
@@ -286,7 +286,73 @@
     <item msgid="1165623660533024666">"chạy trong nền"</item>
     <item msgid="6423861043647911030">"âm lượng hỗ trợ tiếp cận"</item>
   </string-array>
-    <!-- no translation found for app_ops_labels:41 (2464189519136248621) -->
+  <string-array name="app_ops_labels">
+    <item msgid="7892361636570580123">"Vị trí"</item>
+    <item msgid="6656077694190491067">"Vị trí"</item>
+    <item msgid="8790228218278477369">"Vị trí"</item>
+    <item msgid="7836406246005211990">"Rung"</item>
+    <item msgid="3951439024549922598">"Đọc danh sách liên hệ"</item>
+    <item msgid="8802152411647068">"Sửa đổi danh sách liên hệ"</item>
+    <item msgid="229544934599698735">"Đọc nhật ký cuộc gọi"</item>
+    <item msgid="7396102294405899613">"Sửa đổi nhật ký cuộc gọi"</item>
+    <item msgid="3597797992398484655">"Đọc lịch"</item>
+    <item msgid="2705975774250907343">"Sửa đổi lịch"</item>
+    <item msgid="4668747371441932697">"Vị trí"</item>
+    <item msgid="1487578921720243646">"Đăng thông báo"</item>
+    <item msgid="4636080349724146638">"Vị trí"</item>
+    <item msgid="673510900286463926">"Gọi điện thoại"</item>
+    <item msgid="542083422784609790">"Đọc SMS/MMS"</item>
+    <item msgid="1033780373029588436">"Viết SMS/MMS"</item>
+    <item msgid="5647111115517787488">"Nhận SMS/MMS"</item>
+    <item msgid="8591105601108455893">"Nhận SMS/MMS"</item>
+    <item msgid="7730995008517841903">"Nhận SMS/MMS"</item>
+    <item msgid="2613033109026626086">"Nhận SMS/MMS"</item>
+    <item msgid="3037159047591081136">"Gửi SMS/MMS"</item>
+    <item msgid="4726682243833913568">"Đọc SMS/MMS"</item>
+    <item msgid="6555678522277865572">"Viết SMS/MMS"</item>
+    <item msgid="6981734935578130884">"Sửa đổi cài đặt"</item>
+    <item msgid="8705854389991425629">"Vẽ lên trên"</item>
+    <item msgid="5861356020344153651">"Truy cập thông báo"</item>
+    <item msgid="78432174621628659">"Máy ảnh"</item>
+    <item msgid="3986116419882154794">"Ghi âm"</item>
+    <item msgid="4516840825756409490">"Phát âm thanh"</item>
+    <item msgid="6811712502798183957">"Đọc khay nhớ tạm"</item>
+    <item msgid="2780369012602289114">"Sửa đổi khay nhớ tạm"</item>
+    <item msgid="2331359440170850868">"Các nút phương tiện"</item>
+    <item msgid="6133599737122751231">"Tập trung âm thanh"</item>
+    <item msgid="6844485713404805301">"Âm lượng chính"</item>
+    <item msgid="1600379420669104929">"Âm lượng thoại"</item>
+    <item msgid="6296768210470214866">"Âm lượng chuông"</item>
+    <item msgid="510690696071629241">"Âm lượng nội dung nghe nhìn"</item>
+    <item msgid="406861638631430109">"Âm lượng chuông báo"</item>
+    <item msgid="4715864795872233884">"Âm lượng thông báo"</item>
+    <item msgid="2311478519251301183">"Âm lượng bluetooth"</item>
+    <item msgid="5133991377896747027">"Không khóa màn hình"</item>
+    <item msgid="2464189519136248621">"Vị trí"</item>
+    <item msgid="2062677934050803037">"Vị trí"</item>
+    <item msgid="1735171933192715957">"Tải thống kê sử dụng"</item>
+    <item msgid="1014093788778383554">"Tắt/bật micrô"</item>
+    <item msgid="4199297950608622850">"Hiển thị thông báo nhanh"</item>
+    <item msgid="2527962435313398821">"Chiếu phương tiện"</item>
+    <item msgid="5117506254221861929">"Kích hoạt VPN"</item>
+    <item msgid="8291198322681891160">"Hình nền ghi"</item>
+    <item msgid="7106921284621230961">"Cấu trúc hỗ trợ"</item>
+    <item msgid="4496533640894624799">"Ảnh chụp màn hình hỗ trợ"</item>
+    <item msgid="2598847264853993611">"Đọc trạng thái điện thoại"</item>
+    <item msgid="9215610846802973353">"Thêm thư thoại"</item>
+    <item msgid="9186411956086478261">"Sử dụng SIP"</item>
+    <item msgid="6884763100104539558">"Xử lý cuộc gọi đi"</item>
+    <item msgid="125513972170580692">"Vân tay"</item>
+    <item msgid="2556071024281275619">"Cảm biến cơ thể"</item>
+    <item msgid="617168514928339387">"Đọc truyền phát trên di động"</item>
+    <item msgid="7134693570516523585">"Vị trí mô phỏng"</item>
+    <item msgid="7224489175375229399">"Bộ nhớ đọc"</item>
+    <item msgid="8472735063903258202">"Bộ nhớ ghi"</item>
+    <item msgid="4069276819909595110">"Bật màn hình"</item>
+    <item msgid="1228338896751121025">"Nhận tài khoản"</item>
+    <item msgid="3181581793459233672">"Chạy trong nền"</item>
+    <item msgid="2340936043025374076">"Âm lượng hỗ trợ tiếp cận"</item>
+  </string-array>
   <string-array name="long_press_timeout_selector_titles">
     <item msgid="8950313530602254787">"Ngắn"</item>
     <item msgid="4816511817309094890">"Trung bình"</item>
@@ -357,9 +423,19 @@
     <item msgid="7718817231348607934">"Không bao giờ cho phép"</item>
     <item msgid="8184570120217958741">"Luôn cho phép"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Bình thường"</item>
+    <item msgid="5101233285497327432">"Trung bình"</item>
+    <item msgid="1555861583162930714">"Thấp"</item>
+    <item msgid="1719683776264798117">"Quan trọng"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Bình thường"</item>
+    <item msgid="6107138933849816768">"Trung bình"</item>
+    <item msgid="182695359839047859">"Thấp"</item>
+    <item msgid="8577246509202964244">"Cực thấp"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Liên tục"</item>
     <item msgid="167418068739176448">"Hoạt động hàng đầu"</item>
diff --git a/tests/CarDeveloperOptions/res/values-vi/config.xml b/tests/CarDeveloperOptions/res/values-vi/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-vi/config.xml
+++ b/tests/CarDeveloperOptions/res/values-vi/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-vi/strings.xml b/tests/CarDeveloperOptions/res/values-vi/strings.xml
index 7024a6f..9a09843 100644
--- a/tests/CarDeveloperOptions/res/values-vi/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-vi/strings.xml
@@ -29,12 +29,12 @@
     <string name="show_dev_on" msgid="9075712234786224065">"Bạn đã là nhà phát triển!"</string>
     <string name="show_dev_already" msgid="7665948832405148689">"Không cần, bạn đã là nhà phát triển."</string>
     <string name="dev_settings_disabled_warning" msgid="3198732189395396721">"Vui lòng bật tùy chọn của nhà phát triển trước."</string>
-    <string name="header_category_wireless_networks" msgid="8968405993937795898">"Mạng không dây và mạng"</string>
+    <string name="header_category_wireless_networks" msgid="8968405993937795898">"Không dây và mạng"</string>
     <string name="header_category_system" msgid="4045988717359334410">"Hệ thống"</string>
     <string name="radio_info_data_connection_enable" msgid="2554249462719717119">"Bật kết nối dữ liệu"</string>
     <string name="radio_info_data_connection_disable" msgid="2430609627397999371">"Tắt kết nối dữ liệu"</string>
     <string name="volte_provisioned_switch_string" msgid="6326756678226686704">"Đã cấp phép VoLTE"</string>
-    <string name="vt_provisioned_switch_string" msgid="7458479879009293613">"Đã cấp phép gọi điện video"</string>
+    <string name="vt_provisioned_switch_string" msgid="7458479879009293613">"Đã cấp phép gọi video"</string>
     <string name="wfc_provisioned_switch_string" msgid="5446697646596639516">"Đã cấp phép gọi điện qua Wi-Fi"</string>
     <string name="eab_provisioned_switch_string" msgid="3921103790584572430">"Đã cấp phép hiện diện/EAB"</string>
     <string name="cbrs_data_switch_string" msgid="9120919504831536183">"Dữ liệu Cbrs"</string>
@@ -53,7 +53,7 @@
     <string name="radio_info_ims_reg_status_not_registered" msgid="1286050699734226077">"Chưa được đăng ký"</string>
     <string name="radio_info_ims_feature_status_available" msgid="2040629393134756058">"Khả dụng"</string>
     <string name="radio_info_ims_feature_status_unavailable" msgid="3348223769202693596">"Không khả dụng"</string>
-    <string name="radio_info_ims_reg_status" msgid="4771711884059371514">"Đăng ký IMS: <xliff:g id="STATUS">%1$s</xliff:g>\nThoại trên nền LTE: <xliff:g id="AVAILABILITY_0">%2$s</xliff:g>\nThoại qua Wi-Fi: <xliff:g id="AVAILABILITY_1">%3$s</xliff:g>\nGọi điện video: <xliff:g id="AVAILABILITY_2">%4$s</xliff:g>\nGiao diện UT: <xliff:g id="AVAILABILITY_3">%5$s</xliff:g>"</string>
+    <string name="radio_info_ims_reg_status" msgid="4771711884059371514">"Đăng ký IMS: <xliff:g id="STATUS">%1$s</xliff:g>\nThoại trên nền LTE: <xliff:g id="AVAILABILITY_0">%2$s</xliff:g>\nThoại qua Wi-Fi: <xliff:g id="AVAILABILITY_1">%3$s</xliff:g>\nGọi video: <xliff:g id="AVAILABILITY_2">%4$s</xliff:g>\nGiao diện UT: <xliff:g id="AVAILABILITY_3">%5$s</xliff:g>"</string>
     <string name="radioInfo_service_in" msgid="1297020186765943857">"Đang sử dụng"</string>
     <string name="radioInfo_service_out" msgid="8460363463722476510">"Không có dịch vụ"</string>
     <string name="radioInfo_service_emergency" msgid="7674989004735662599">"Chỉ cuộc gọi khẩn cấp"</string>
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Thu nhỏ hoặc phóng to văn bản trên màn hình."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Thu nhỏ"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Phóng to"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Văn bản mẫu"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"Phù thủy xứ Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Chương 11: Thành phố ngọc lục bảo của xứ Oz"</string>
@@ -208,7 +207,7 @@
     <string name="proxy_error_empty_port" msgid="8034561724923076215">"Bạn cần hoàn tất trường cổng."</string>
     <string name="proxy_error_empty_host_set_port" msgid="8471455809508588255">"Trường cổng phải trống nếu trường máy chủ lưu trữ trống."</string>
     <string name="proxy_error_invalid_port" msgid="4046559920586100637">"Cổng bạn đã nhập không hợp lệ."</string>
-    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"Proxy HTTP được sử dụng bởi trình duyệt nhưng có thể không được sử dụng bởi các ứng dụng khác."</string>
+    <string name="proxy_warning_limited_support" msgid="9026539134219095768">"Trình duyệt sẽ sử dụng proxy HTTP, nhưng các ứng dụng khác có thể không."</string>
     <string name="proxy_url_title" msgid="882042361706435904">"URL PAC: "</string>
     <string name="radio_info_dl_kbps" msgid="2903778264453410272">"Băng thông DL (kb/giây):"</string>
     <string name="radio_info_ul_kbps" msgid="3802245899811732716">"Băng thông UL (kb/giây):"</string>
@@ -302,7 +301,7 @@
     <string name="settings_label_launcher" msgid="500627679902923496">"Cài đặt"</string>
     <string name="settings_shortcut" msgid="4503714880251502167">"Lối tắt cài đặt"</string>
     <string name="airplane_mode" msgid="4508870277398231073">"Chế độ trên máy bay"</string>
-    <string name="wireless_networks_settings_title" msgid="4298430520189173949">"Không dây &amp; mạng"</string>
+    <string name="wireless_networks_settings_title" msgid="4298430520189173949">"Không dây và mạng"</string>
     <string name="radio_controls_summary" msgid="4596981962167684814">"Quản lý Wi-Fi, Bluetooth, chế độ trên máy bay, mạng di động và VPN"</string>
     <string name="cellular_data_title" msgid="7909624119432695022">"Dữ liệu di động"</string>
     <string name="calls_title" msgid="875693497825736550">"Cho phép cuộc gọi"</string>
@@ -323,7 +322,7 @@
     <string name="date_and_time_settings_title" msgid="7827088656940910631">"Ngày &amp; giờ"</string>
     <string name="date_and_time_settings_title_setup_wizard" msgid="1573030770187844365">"Đặt ngày giờ"</string>
     <string name="date_and_time_settings_summary" msgid="4617979434474713417">"Đặt ngày, giờ, múi giờ &amp; định dạng"</string>
-    <string name="date_time_auto" msgid="2679132152303750218">"Sử dụng thời gian do mạng cung cấp"</string>
+    <string name="date_time_auto" msgid="2679132152303750218">"Sử dụng ngày và giờ do mạng cung cấp"</string>
     <string name="zone_auto_title" msgid="5500880975376882488">"Sử dụng múi giờ do mạng cung cấp"</string>
     <string name="date_time_24hour_auto" msgid="7499659679134962547">"Sử dụng định dạng của địa phương"</string>
     <string name="date_time_24hour_title" msgid="6209923858891621283">"Định dạng 24 giờ"</string>
@@ -354,7 +353,7 @@
     <string name="show_owner_info_on_lockscreen_label" msgid="4510756693837171575">"Hiển thị thông tin chủ sở hữu trên màn hình khóa"</string>
     <string name="owner_info_settings_title" msgid="2537966178998339896">"Thông điệp trên màn hình khóa"</string>
     <string name="security_enable_widgets_title" msgid="1701510007926738088">"Bật tiện ích"</string>
-    <string name="security_enable_widgets_disabled_summary" msgid="4408176087132339331">"Bị quản trị viên vô hiệu hóa"</string>
+    <string name="security_enable_widgets_disabled_summary" msgid="4408176087132339331">"Đã bị quản trị viên vô hiệu hóa"</string>
     <string name="lockdown_settings_title" msgid="4534779922580115990">"Hiện tùy chọn khóa"</string>
     <string name="lockdown_settings_summary" msgid="7270756909878256174">"Hiển thị tùy chọn nút nguồn để tắt tính năng Smart Lock, mở khóa bằng vân tay, và thông báo trên màn hình khóa"</string>
     <string name="trust_agents_extend_unlock_title" msgid="3582017561316089951">"Tác nhân tin cậy chỉ kéo dài thời gian mở khóa"</string>
@@ -388,7 +387,7 @@
     <string name="security_settings_summary" msgid="5210109100643223686">"Đặt Vị trí của tôi, mở khóa màn hình, khóa thẻ SIM, khóa bộ nhớ thông tin xác thực"</string>
     <string name="cdma_security_settings_summary" msgid="1783066617800041869">"Đặt Vị trí của tôi, mở khóa màn hình, khóa bộ nhớ thông tin xác thực"</string>
     <string name="security_passwords_title" msgid="6853942836045862315">"Bảo mật"</string>
-    <string name="disabled_by_administrator_summary" msgid="6099821045360491127">"Bị quản trị viên vô hiệu hóa"</string>
+    <string name="disabled_by_administrator_summary" msgid="6099821045360491127">"Đã bị quản trị viên vô hiệu hóa"</string>
     <string name="security_status_title" msgid="1261960357751754428">"Trạng thái bảo mật"</string>
     <string name="security_dashboard_summary_face" msgid="2536136110153593745">"Phương thức khóa màn hình, mở khóa bằng khuôn mặt"</string>
     <string name="security_dashboard_summary" msgid="4048877125766167227">"Phương thức khóa màn hình, vân tay"</string>
@@ -411,10 +410,10 @@
     <string name="face_add_max" msgid="8870899421165189413">"Bạn có thể thêm tới <xliff:g id="COUNT">%d</xliff:g> khuôn mặt"</string>
     <string name="face_intro_error_max" msgid="4024147799079828937">"Bạn đã thêm số khuôn mặt tối đa"</string>
     <string name="face_intro_error_unknown" msgid="3241592604198351134">"Không thể thêm khuôn mặt khác nữa"</string>
-    <string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"Đăng ký chưa hoàn tất"</string>
+    <string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"Chưa đăng ký được"</string>
     <string name="security_settings_face_enroll_dialog_ok" msgid="1078348922734845090">"OK"</string>
     <string name="security_settings_face_enroll_error_timeout_dialog_message" msgid="4917894418448325405">"Đã đến giới hạn thời gian đăng ký khuôn mặt. Hãy thử lại."</string>
-    <string name="security_settings_face_enroll_error_generic_dialog_message" msgid="5160473187142616862">"Đăng ký khuôn mặt không hoạt động."</string>
+    <string name="security_settings_face_enroll_error_generic_dialog_message" msgid="5160473187142616862">"Quy trình đăng ký khuôn mặt không hoạt động."</string>
     <string name="security_settings_face_enroll_finish_title" msgid="6800717857394410769">"Đã hoàn tất. Trông rất ổn."</string>
     <string name="security_settings_face_enroll_done" msgid="5409739233373490971">"Xong"</string>
     <string name="security_settings_face_settings_use_face_category" msgid="1586532139528115416">"Sử dụng khuôn mặt để"</string>
@@ -448,7 +447,7 @@
     <string name="security_settings_fingerprint_enroll_introduction_cancel_setup" msgid="756928427429893070">"Bỏ qua"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue_setup" msgid="4125977169169671144">"Tiếp theo"</string>
     <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"Bạn muốn bỏ qua vân tay?"</string>
-    <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"Bạn chỉ mất một hoặc hai phút để thiết lập vân tay. Nếu bỏ qua bước này, bạn có thể thêm vân tay vào lúc khác trong cài đặt."</string>
+    <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"Bạn chỉ mất một hoặc hai phút để thiết lập vân tay. Nếu bỏ qua bước này, bạn có thể thêm vân tay vào lúc khác trong phần cài đặt."</string>
     <string name="lock_screen_intro_skip_title" msgid="5307431665496346914">"Bạn muốn bỏ qua phương thức khóa màn hình?"</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="tablet" msgid="7553945981266845264">"Các tính năng bảo vệ thiết bị sẽ không được bật. Bạn sẽ không thể ngăn người khác sử dụng máy tính bảng này nếu máy tính bảng bị mất, bị đánh cắp hoặc bị đặt lại."</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="device" msgid="1378243257238015603">"Các tính năng bảo vệ thiết bị sẽ không được bật. Bạn sẽ không thể ngăn người khác sử dụng thiết bị này nếu thiết bị bị mất, bị đánh cắp hoặc bị đặt lại."</string>
@@ -469,7 +468,7 @@
     <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"Chạm vào cảm biến"</string>
     <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"Đặt ngón tay lên cảm biến và nhấc lên sau khi cảm thấy rung"</string>
     <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"Nhấc ngón tay lên rồi chạm lại"</string>
-    <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Tiếp tục nhấc ngón tay để thêm các phần khác nhau của vân tay"</string>
+    <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Chạm liên tục trên cảm biến để thêm các phần khác của ngón tay"</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"Đã thêm vân tay"</string>
     <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"Khi bạn nhìn thấy biểu tượng này, hãy sử dụng vân tay của mình để nhận dạng hoặc phê duyệt hoạt động mua hàng"</string>
     <string name="security_settings_fingerprint_enroll_enrolling_skip" msgid="1473280156532146933">"Thực hiện sau"</string>
@@ -488,8 +487,8 @@
     <string name="security_settings_fingerprint_enroll_done" msgid="4111289529758845926">"Xong"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"Rất tiếc, đó không phải là cảm biến"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"Chạm vào cảm biến ở mặt sau điện thoại. Dùng ngón tay trỏ."</string>
-    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"Đăng ký chưa hoàn tất"</string>
-    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Đã đến giới hạn thời gian đăng ký dấu vân tay. Hãy thử lại."</string>
+    <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"Chưa đăng ký được"</string>
+    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"Thời gian đăng ký vân tay đã hết hạn. Hãy thử lại."</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"Đăng ký dấu vân tay không hoạt động. Hãy thử lại hoặc sử dụng ngón tay khác."</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"Thêm vân tay khác"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"Tiếp theo"</string>
@@ -568,7 +567,7 @@
     <string name="unlock_set_unlock_off_summary" msgid="3997346045783359119"></string>
     <string name="unlock_set_unlock_none_title" msgid="1922027966983146392">"Vuốt"</string>
     <string name="unlock_set_unlock_none_summary" msgid="4044529413627659031">"Không có bảo mật"</string>
-    <string name="unlock_set_unlock_pattern_title" msgid="7533759994999423587">"Hình"</string>
+    <string name="unlock_set_unlock_pattern_title" msgid="7533759994999423587">"Hình mở khóa"</string>
     <string name="unlock_set_unlock_pattern_summary" msgid="8858697834522201333">"Mức độ bảo mật trung bình"</string>
     <string name="unlock_set_unlock_pin_title" msgid="361479901761948207">"Mã PIN"</string>
     <string name="unlock_set_unlock_pin_summary" msgid="8076921768675948228">"Mức độ bảo mật từ trung bình đến cao"</string>
@@ -589,7 +588,7 @@
     <string name="unlock_set_unlock_disabled_summary" msgid="1713159782896140817">"Do quản trị viên tắt, c.sách mã hóa hay vùng l.trữ t.tin xác thực"</string>
     <string name="unlock_set_unlock_mode_off" msgid="2950701212659081973">"Không"</string>
     <string name="unlock_set_unlock_mode_none" msgid="3441605629077912292">"Vuốt"</string>
-    <string name="unlock_set_unlock_mode_pattern" msgid="8564909572968419459">"Hình"</string>
+    <string name="unlock_set_unlock_mode_pattern" msgid="8564909572968419459">"Hình mở khóa"</string>
     <string name="unlock_set_unlock_mode_pin" msgid="7828354651668392875">"Mã PIN"</string>
     <string name="unlock_set_unlock_mode_password" msgid="397703731925549447">"Mật khẩu"</string>
     <string name="unlock_setup_wizard_fingerprint_details" msgid="6515136915205473675">"Sau khi thiết lập khóa màn hình, bạn cũng có thể thiết lập vân tay của mình trong Cài đặt và bảo mật."</string>
@@ -668,7 +667,6 @@
       <item quantity="other">Phải có ít hơn <xliff:g id="NUMBER_1">%d</xliff:g> chữ số</item>
       <item quantity="one">Phải có ít hơn <xliff:g id="NUMBER_0">%d</xliff:g> chữ số</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Chỉ được chứa các chữ số 0-9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Quản trị viên thiết bị không cho phép dùng mã PIN gần đây"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Quản vị viên CNTT đã chặn những mã PIN phổ biến. Hãy thử mã PIN khác."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Mật khẩu này không được bao gồm ký tự không hợp lệ"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">Phải chứa ít nhất <xliff:g id="COUNT">%d</xliff:g> ký tự không phải chữ cái</item>
       <item quantity="one">Phải chứa ít nhất 1 ký tự không phải chữ cái</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">Phải có ít nhất <xliff:g id="COUNT">%d</xliff:g> ký tự không phải là số</item>
+      <item quantity="one">Phải có ít nhất 1 ký tự không phải là số</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Quản trị viên thiết bị không cho phép sử dụng mật khẩu gần đây"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Quản vị viên CNTT đã chặn những mật khẩu phổ biến. Hãy thử mật khẩu khác."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Không cho phép thứ tự chữ số tăng dần, giảm dần hoặc lặp lại"</string>
@@ -798,7 +800,7 @@
     <string name="bluetooth_max_connected_audio_devices_dialog_title" msgid="6049527354499590314">"Chọn số thiết bị âm thanh được kết nối qua Bluetooth tối đa"</string>
     <string name="wifi_display_settings_title" msgid="8718182672694575456">"Truyền"</string>
     <string name="wifi_display_enable_menu_item" msgid="4578340247147692250">"Bật hiển thị không dây"</string>
-    <string name="wifi_display_no_devices_found" msgid="186501729518830451">"Không tìm thấy thiết bị lân cận nào."</string>
+    <string name="wifi_display_no_devices_found" msgid="186501729518830451">"Không tìm thấy thiết bị nào ở gần."</string>
     <string name="wifi_display_status_connecting" msgid="3799827425457383349">"Đang kết nối"</string>
     <string name="wifi_display_status_connected" msgid="85692409327461403">"Đã kết nối"</string>
     <string name="wifi_display_status_in_use" msgid="7646114501132773174">"Đang được sử dụng"</string>
@@ -824,7 +826,7 @@
     <string name="nfc_disclaimer_title" msgid="4860231267351602970">"Bật NFC"</string>
     <string name="nfc_disclaimer_content" msgid="3066113577854565782">"NFC trao đổi dữ liệu giữa thiết bị này với các thiết bị hoặc thiết bị đích lân cận khác, chẳng hạn như trạm thanh toán, trình đọc truy cập và các quảng cáo hoặc thẻ tương tác."</string>
     <string name="nfc_secure_settings_title" msgid="5153751163174916581">"Bảo mật NFC"</string>
-    <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"Chỉ cho phép sử dụng Thanh toán bằng NFC và Phương tiện công cộng khi màn hình đang mở khóa"</string>
+    <string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"Chỉ cho phép sử dụng tính năng Thanh toán bằng NFC và Phương tiện công cộng khi màn hình đang mở khóa"</string>
     <string name="android_beam_settings_title" msgid="3083436415873738389">"Android Beam"</string>
     <string name="android_beam_on_summary" msgid="8068287225180474199">"Sẵn sàng truyền tải nội dung ứng dụng qua NFC"</string>
     <string name="android_beam_off_summary" msgid="7365818039159364600">"Đang tắt"</string>
@@ -859,8 +861,8 @@
     <string name="use_open_wifi_automatically_summary_scoring_disabled" msgid="1559329344492373028">"Để sử dụng, hãy chọn một nhà cung cấp dịch vụ xếp hạng mạng"</string>
     <string name="use_open_wifi_automatically_summary_scorer_unsupported_disabled" msgid="1123080670578756834">"Để sử dụng, hãy chọn một nhà cung cấp dịch vụ xếp hạng mạng tương thích"</string>
     <string name="wifi_install_credentials" msgid="5650088113710858289">"Cài đặt chứng chỉ"</string>
-    <string name="wifi_scan_notify_text" msgid="7614101215028336927">"Để nâng cao độ chính xác của vị trí, các ứng dụng và dịch vụ có thể vẫn quét tìm mạng Wi‑Fi bất kỳ lúc nào, ngay cả khi Wi-Fi bị tắt. Chẳng hạn, bạn có thể sử dụng cài đặt này để cải thiện các tính năng và dịch vụ dựa trên vị trí. Bạn có thể thay đổi cài đặt này trong phần <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>cài đặt quét<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
-    <string name="wifi_scan_notify_text_scanning_off" msgid="723796963816095410">"Để nâng cao độ chính xác về vị trí, hãy bật quét tìm Wi-Fi trong <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>cài đặt quét<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
+    <string name="wifi_scan_notify_text" msgid="7614101215028336927">"Để nâng cao độ chính xác của vị trí, các ứng dụng và dịch vụ có thể vẫn quét tìm mạng Wi‑Fi bất kỳ lúc nào, ngay cả khi Wi-Fi bị tắt. Chẳng hạn, bạn có thể sử dụng tùy chọn cài đặt này để cải thiện các tính năng và dịch vụ dựa trên vị trí. Bạn có thể thay đổi tùy chọn này trong phần <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>cài đặt quét<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
+    <string name="wifi_scan_notify_text_scanning_off" msgid="723796963816095410">"Để nâng cao độ chính xác về vị trí, hãy bật tính năng quét tìm Wi-Fi trong phần <xliff:g id="LINK_BEGIN_0">LINK_BEGIN</xliff:g>cài đặt quét<xliff:g id="LINK_END_1">LINK_END</xliff:g>."</string>
     <string name="wifi_scan_notify_remember_choice" msgid="1235445971400237444">"Không hiển thị nữa"</string>
     <string name="wifi_setting_sleep_policy_title" msgid="2120785188625932076">"Bật Wi-Fi khi ở chế độ ngủ"</string>
     <string name="wifi_setting_on_during_sleep_title" msgid="856670183023402715">"Bật Wi-Fi khi ở chế độ ngủ"</string>
@@ -903,11 +905,11 @@
     <string name="wifi_ssid_hint" msgid="5010024648106585165">"Nhập SSID"</string>
     <string name="wifi_security" msgid="9136702039496152831">"Bảo mật"</string>
     <string name="wifi_hidden_network" msgid="6647772204699776833">"Mạng ẩn"</string>
-    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Nếu bộ định tuyến của bạn không phát ID mạng nhưng bạn muốn kết nối với mạng này trong tương lai, thì bạn có thể đặt mạng ẩn.\n\nĐiều này có thể gây rủi ro bảo mật vì điện thoại của bạn sẽ thường xuyên phát tín hiệu để tìm mạng.\n\nViệc đặt mạng ẩn sẽ không thay đổi các cài đặt của bộ định tuyến."</string>
+    <string name="wifi_hidden_network_warning" msgid="8182333050353796473">"Nếu bộ định tuyến của bạn không phát ra một tên mạng nhưng bạn muốn kết nối với mạng này trong tương lai, thì bạn có thể đặt mạng này là mạng ẩn.\n\nĐiều này có thể gây rủi ro bảo mật vì điện thoại của bạn sẽ thường xuyên phát tín hiệu để tìm mạng.\n\nViệc đặt mạng này là mạng ẩn sẽ không thay đổi các tùy chọn cài đặt của bộ định tuyến."</string>
     <string name="wifi_signal" msgid="696548364467704808">"Cường độ tín hiệu"</string>
     <string name="wifi_status" msgid="3439931558930689940">"Trạng thái"</string>
-    <string name="tx_wifi_speed" msgid="2571810085003261073">"Tốc độ của liên kết truyền"</string>
-    <string name="rx_wifi_speed" msgid="7392873246110937187">"Tốc độ nhận đường dẫn liên kết"</string>
+    <string name="tx_wifi_speed" msgid="2571810085003261073">"Tốc độ truyền"</string>
+    <string name="rx_wifi_speed" msgid="7392873246110937187">"Tốc độ nhận"</string>
     <string name="wifi_frequency" msgid="6132852924995724246">"Tần số"</string>
     <string name="wifi_ip_address" msgid="5572539114989914831">"Địa chỉa IP"</string>
     <string name="passpoint_label" msgid="7429247462404128615">"Đã lưu thông qua"</string>
@@ -917,7 +919,7 @@
     <string name="wifi_eap_ca_cert" msgid="1496395241849383785">"Chứng chỉ CA"</string>
     <string name="wifi_eap_domain" msgid="3298302320003640130">"Miền"</string>
     <string name="wifi_eap_user_cert" msgid="6786839531765719173">"Chứng chỉ người dùng"</string>
-    <string name="wifi_eap_identity" msgid="5280457017705738773">"Nhận dạng"</string>
+    <string name="wifi_eap_identity" msgid="5280457017705738773">"Danh tính"</string>
     <string name="wifi_eap_anonymous" msgid="6352344972490839958">"Danh tính ẩn danh"</string>
     <string name="wifi_password" msgid="6942983531275177771">"Mật khẩu"</string>
     <string name="wifi_show_password" msgid="7878398590772942202">"Hiển thị mật khẩu"</string>
@@ -932,8 +934,8 @@
     <string name="wifi_ip_settings" msgid="4636102290236116946">"Cài đặt IP"</string>
     <string name="wifi_privacy_settings" msgid="4462092795794247809">"Quyền riêng tư"</string>
     <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"Địa chỉ MAC gán ngẫu nhiên"</string>
-    <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"Thêm một thiết bị"</string>
-    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"Căn giữa mã QR dưới đây để thêm thiết bị vào “<xliff:g id="SSID">%1$s</xliff:g>”"</string>
+    <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"Thêm thiết bị"</string>
+    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"Đưa mã QR vào giữa khung bên dưới để thêm thiết bị vào “<xliff:g id="SSID">%1$s</xliff:g>”"</string>
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"Quét mã QR"</string>
     <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"Căn giữa mã QR dưới đây để kết nối với “<xliff:g id="SSID">%1$s</xliff:g>”"</string>
     <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"Kết nối với Wi‑Fi bằng cách quét mã QR"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Di động"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Nếu không có Wi‑Fi, hãy dùng mạng di động"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Nếu không có mạng di động, hãy dùng Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Gọi qua Wi‑Fi. Nếu mất Wi‑Fi, cuộc gọi sẽ kết thúc."</string>
@@ -1210,7 +1215,7 @@
     <string name="night_display_auto_mode_title" msgid="8493573087102481588">"Lịch biểu"</string>
     <string name="night_display_auto_mode_never" msgid="2897444637217807088">"Không có"</string>
     <string name="night_display_auto_mode_custom" msgid="1400891076453963151">"Bật vào thời gian tùy chỉnh"</string>
-    <string name="night_display_auto_mode_twilight" msgid="4000162110017520674">"Bật từ hoàng hôn đến bình minh"</string>
+    <string name="night_display_auto_mode_twilight" msgid="4000162110017520674">"Bật từ lúc mặt trời lặn đến lúc mặt trời mọc"</string>
     <string name="night_display_start_time_title" msgid="1069255169673371077">"Thời gian bắt đầu"</string>
     <string name="night_display_end_time_title" msgid="2760793157124245911">"Thời gian kết thúc"</string>
     <string name="night_display_status_title" msgid="1727020934735770319">"Trạng thái"</string>
@@ -1225,7 +1230,7 @@
     <string name="night_display_summary_on_auto_mode_twilight" msgid="8386769601369289561">"Sẽ tự động tắt lúc bình minh"</string>
     <string name="night_display_activation_on_manual" msgid="8379477527072027346">"Bật ngay"</string>
     <string name="night_display_activation_off_manual" msgid="7776082151269794201">"Tắt ngay"</string>
-    <string name="night_display_activation_on_twilight" msgid="5610294051700287249">"Bật cho đến bình minh"</string>
+    <string name="night_display_activation_on_twilight" msgid="5610294051700287249">"Bật cho đến lúc mặt trời mọc"</string>
     <string name="night_display_activation_off_twilight" msgid="6846727701281556110">"Tắt cho đến hoàng hôn"</string>
     <string name="night_display_activation_on_custom" msgid="4761140206778957611">"Bật cho đến <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="night_display_activation_off_custom" msgid="4207238846687792731">"Tắt cho đến <xliff:g id="ID_1">%1$s</xliff:g>"</string>
@@ -1547,7 +1552,7 @@
     <string name="carrier_enabled" msgid="1819916725305365581">"Bật/tắt APN"</string>
     <string name="carrier_enabled_summaryOn" msgid="6219221535461945771">"Đã bật APN"</string>
     <string name="carrier_enabled_summaryOff" msgid="4093019532796386622">"Đã tắt APN"</string>
-    <string name="bearer" msgid="4378444317087536401">"Trình chuyển"</string>
+    <string name="bearer" msgid="4378444317087536401">"Sóng mang"</string>
     <string name="mvno_type" msgid="3150755279048149624">"Kiểu MVNO"</string>
     <string name="mvno_match_data" msgid="629287305803195245">"Giá trị MVNO"</string>
     <string name="menu_delete" msgid="8646081395424055735">"Xóa APN"</string>
@@ -1562,7 +1567,7 @@
     <string name="error_adding_apn_type" msgid="671634520340569678">"Nhà cung cấp dịch vụ không cho phép thêm APN thuộc loại %s."</string>
     <string name="restore_default_apn" msgid="7195266404077471007">"Đang khôi phục cài đặt APN mặc định."</string>
     <string name="menu_restore" msgid="3799288817317293115">"Đặt lại về mặc định"</string>
-    <string name="restore_default_apn_completed" msgid="5671734152740058937">"Đặt lại cài đặt APN mặc định đã hoàn tất."</string>
+    <string name="restore_default_apn_completed" msgid="5671734152740058937">"Đã đặt lại xong các tùy chọn cài đặt APN mặc định về trạng thái ban đầu."</string>
     <string name="reset_dashboard_title" msgid="7084966342252178530">"Tùy chọn đặt lại"</string>
     <string name="reset_dashboard_summary" msgid="8778383341461126642">"Có thể đặt lại mạng, ứng dụng hoặc thiết bị"</string>
     <string name="reset_network_title" msgid="8944059136930806211">"Đặt lại Wi-Fi, di động và Bluetooth"</string>
@@ -1580,8 +1585,8 @@
     <string name="reset_esim_error_msg" msgid="4716366079119742235">"Không thể xóa SIM đã tải xuống do lỗi.\n\nHãy khởi động lại thiết bị của bạn rồi thử lại."</string>
     <string name="master_clear_title" msgid="1560712943955904673">"Xóa mọi dữ liệu (đặt lại thiết bị)"</string>
     <string name="master_clear_short_title" msgid="919098101581335101">"Xóa mọi dữ liệu (đặt lại thiết bị)"</string>
-    <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"Hành động này sẽ xóa tất cả dữ liệu khỏi "<b>"bộ nhớ trong"</b>" của máy tính bảng, bao gồm cả:\n\n"<li>"Tài khoản Google của bạn"</li>\n<li>"Dữ liệu cũng như các tùy chọn cài đặt của hệ thống và ứng dụng"</li>\n<li>"Ứng dụng đã tải xuống"</li></string>
-    <string name="master_clear_desc" product="default" msgid="8765543541962866697">"Hành động này sẽ xóa tất cả dữ liệu khỏi "<b>"bộ nhớ trong"</b>" của điện thoại, bao gồm cả:\n\n"<li>"Tài khoản Google của bạn"</li>\n<li>"Dữ liệu cũng như các tùy chọn cài đặt hệ thống và ứng dụng"</li>\n<li>"Ứng dụng đã tải xuống"</li></string>
+    <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"Thao tác này sẽ xóa tất cả dữ liệu trong "<b>"bộ nhớ trong"</b>" của máy tính bảng, bao gồm:\n\n"<li>"Tài khoản Google của bạn"</li>\n<li>"Dữ liệu và các tùy chọn cài đặt của hệ thống và ứng dụng"</li>\n<li>"Ứng dụng đã tải xuống"</li></string>
+    <string name="master_clear_desc" product="default" msgid="8765543541962866697">"Thao tác này sẽ xóa tất cả dữ liệu trong "<b>"bộ nhớ trong"</b>" của điện thoại, bao gồm:\n\n"<li>"Tài khoản Google của bạn"</li>\n<li>"Dữ liệu và các tùy chọn cài đặt của hệ thống và ứng dụng"</li>\n<li>"Ứng dụng đã tải xuống"</li></string>
     <string name="master_clear_accounts" product="default" msgid="3432884235445405376">\n\n"Bạn hiện đã đăng nhập vào các tài khoản sau đây:\n"</string>
     <string name="master_clear_other_users_present" product="default" msgid="5993259656117566767">\n\n"Có người dùng khác trên thiết bị này.\n"</string>
     <string name="master_clear_desc_also_erases_external" msgid="3947303501615091903"><li>"Nhạc"</li>\n<li>"Ảnh"</li>\n<li>"Dữ liệu người dùng khác"</li></string>
@@ -1605,26 +1610,26 @@
     <string name="master_clear_progress_text" msgid="5418958116008976218">"Vui lòng chờ..."</string>
     <string name="call_settings_title" msgid="5033906789261282752">"Cài đặt cuộc gọi"</string>
     <string name="call_settings_summary" msgid="2119161087671450035">"Thiết lập thư thoại, chuyển tiếp cuộc gọi, chờ cuộc gọi, Số gọi đến"</string>
-    <string name="tether_settings_title_usb" msgid="4265582654602420357">"Chia sẻ kết nối Internet qua USB"</string>
+    <string name="tether_settings_title_usb" msgid="4265582654602420357">"Chia sẻ Internet qua USB"</string>
     <string name="tether_settings_title_wifi" msgid="2060965130234484613">"Điểm phát sóng di động"</string>
-    <string name="tether_settings_title_bluetooth" msgid="1999590158102569959">"Chia sẻ kết nối Internet qua Bluetooth"</string>
-    <string name="tether_settings_title_usb_bluetooth" msgid="1159128764162788159">"Đang dùng làm điểm truy cập Internet"</string>
-    <string name="tether_settings_title_all" msgid="6935843543433954181">"Điểm phát sóng và chia sẻ kết nối"</string>
-    <string name="tether_settings_summary_hotspot_on_tether_on" msgid="1289593649526514499">"Điểm phát sóng bật, chia sẻ kết nối"</string>
+    <string name="tether_settings_title_bluetooth" msgid="1999590158102569959">"Chia sẻ Internet qua Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="1159128764162788159">"Chia sẻ Internet"</string>
+    <string name="tether_settings_title_all" msgid="6935843543433954181">"Điểm phát sóng và chia sẻ Internet"</string>
+    <string name="tether_settings_summary_hotspot_on_tether_on" msgid="1289593649526514499">"Điểm phát sóng đang bật, đang chia sẻ Internet"</string>
     <string name="tether_settings_summary_hotspot_on_tether_off" msgid="8010689354668285422">"Điểm phát sóng bật"</string>
-    <string name="tether_settings_summary_hotspot_off_tether_on" msgid="1349909238672649877">"Chia sẻ kết nối"</string>
+    <string name="tether_settings_summary_hotspot_off_tether_on" msgid="1349909238672649877">"Chia sẻ Internet"</string>
     <string name="tether_settings_disabled_on_data_saver" msgid="3682544845899910726">"Không thể chia sẻ kết nối hoặc sử dụng điểm phát sóng di động khi Trình tiết kiệm dữ liệu đang bật"</string>
     <string name="usb_title" msgid="7480927657535578688">"USB"</string>
-    <string name="usb_tethering_button_text" msgid="6242228383142012332">"Chia sẻ kết nối Internet qua USB"</string>
+    <string name="usb_tethering_button_text" msgid="6242228383142012332">"Chia sẻ Internet qua USB"</string>
     <string name="usb_tethering_subtext" product="default" msgid="1573513260339548671">"Chia sẻ kết nối Internet của điện thoại qua USB"</string>
     <string name="usb_tethering_subtext" product="tablet" msgid="154536000235361034">"Chia sẻ kết nối Internet của máy tính bảng qua USB"</string>
-    <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"Chia sẻ kết nối Internet qua Bluetooth"</string>
+    <string name="bluetooth_tether_checkbox_text" msgid="7257293066139372774">"Chia sẻ Internet qua Bluetooth"</string>
     <string name="bluetooth_tethering_subtext" product="tablet" msgid="6868756914621131635">"Chia sẻ kết nối Internet của máy tính bảng qua Bluetooth"</string>
     <string name="bluetooth_tethering_subtext" product="default" msgid="9167912297565425178">"Chia sẻ kết nối Internet của điện thoại qua Bluetooth"</string>
     <string name="bluetooth_tethering_off_subtext_config" msgid="3981528184780083266">"Chia sẻ kết nối Internet của <xliff:g id="DEVICE_NAME">%1$d</xliff:g> này qua Bluetooth"</string>
     <string name="bluetooth_tethering_overflow_error" msgid="6946561351369376943">"Không thể dùng làm điểm truy cập Internet cho hơn <xliff:g id="MAXCONNECTION">%1$d</xliff:g> thiết bị."</string>
     <string name="bluetooth_untether_blank" msgid="5428300773782256084">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> sẽ được tháo."</string>
-    <string name="tethering_footer_info" msgid="8019555174339154124">"Sử dụng điểm phát sóng và chia sẻ kết nối để cung cấp kết nối Internet cho thiết bị khác thông qua kết nối dữ liệu di động. Các ứng dụng cũng có thể tạo điểm phát sóng để chia sẻ nội dung với thiết bị lân cận."</string>
+    <string name="tethering_footer_info" msgid="8019555174339154124">"Sử dụng tính năng điểm phát sóng và chia sẻ Internet để cho phép các thiết bị khác kết nối với Internet thông qua dữ liệu di động của bạn. Các ứng dụng cũng có thể tạo điểm phát sóng để chia sẻ nội dung với thiết bị ở gần."</string>
     <string name="tethering_help_button_text" msgid="7653022000284543996">"Trợ giúp"</string>
     <string name="network_settings_title" msgid="8516526011407061679">"Mạng di động"</string>
     <string name="manage_mobile_plan_title" msgid="3312016665522553062">"Gói dịch vụ di động"</string>
@@ -1643,7 +1648,7 @@
     <string name="mobile_connect_to_internet" msgid="6031886097365170913">"Vui lòng kết nối internet"</string>
     <string name="location_title" msgid="8664674161765477168">"Vị trí của tôi"</string>
     <string name="managed_profile_location_switch_title" msgid="8157384427925389680">"Vị trí của hồ sơ công việc"</string>
-    <string name="location_app_level_permissions" msgid="1298041503927632960">"Quyền truy cập ứng dụng"</string>
+    <string name="location_app_level_permissions" msgid="1298041503927632960">"Quyền truy cập của ứng dụng"</string>
     <string name="location_app_permission_summary_location_off" msgid="541372845344796336">"Vị trí đang tắt"</string>
     <plurals name="location_app_permission_summary_location_on" formatted="false" msgid="7904821382328758218">
       <item quantity="other"> <xliff:g id="BACKGROUND_LOCATION_APP_COUNT_2">%1$d</xliff:g>/<xliff:g id="TOTAL_LOCATION_APP_COUNT_3">%2$d</xliff:g> ứng dụng có quyền truy cập không giới hạn</item>
@@ -1651,7 +1656,7 @@
     </plurals>
     <string name="location_category_recent_location_access" msgid="286059523360285026">"Quyền truy cập vị trí gần đây"</string>
     <string name="location_recent_location_access_view_details" msgid="2051602261436245905">"Xem chi tiết"</string>
-    <string name="location_no_recent_apps" msgid="77502059586413278">"Không có ứng dụng nào yêu cầu vị trí gần đây"</string>
+    <string name="location_no_recent_apps" msgid="77502059586413278">"Không có ứng dụng nào gần đây yêu cầu vị trí"</string>
     <string name="location_no_recent_accesses" msgid="6289916310397279890">"Gần đây, không có ứng dụng nào truy cập vào vị trí"</string>
     <string name="location_high_battery_use" msgid="7177199869979522663">"Mức sử dụng pin cao"</string>
     <string name="location_low_battery_use" msgid="5030448574501435888">"Mức sử dụng pin thấp"</string>
@@ -1741,7 +1746,7 @@
     <string name="lockpassword_confirm_your_password_header_frp" msgid="7326670978891793470">"Xác minh mật khẩu"</string>
     <string name="lockpassword_invalid_pin" msgid="3059022215815900137">"Mã PIN sai"</string>
     <string name="lockpassword_invalid_password" msgid="8374331995318204099">"Mật khẩu sai"</string>
-    <string name="lockpattern_need_to_unlock_wrong" msgid="1328670466959377948">"Hình không chính xác"</string>
+    <string name="lockpattern_need_to_unlock_wrong" msgid="1328670466959377948">"Hình mở khóa không chính xác"</string>
     <string name="lock_settings_title" msgid="233657584969886812">"Bảo mật thiết bị"</string>
     <string name="lockpattern_change_lock_pattern_label" msgid="333149762562581510">"Thay đổi hình mở khóa"</string>
     <string name="lockpattern_change_lock_pin_label" msgid="3435796032210265723">"Thay đổi mã PIN mở khóa"</string>
@@ -1821,7 +1826,7 @@
     <string name="disable_text" msgid="5065834603951474397">"Tắt"</string>
     <string name="enable_text" msgid="7179141636849225884">"Bật"</string>
     <string name="clear_user_data_text" msgid="8894073247302821764">"Xóa bộ nhớ"</string>
-    <string name="app_factory_reset" msgid="8718986000278776272">"Gỡ cài đặt cập nhật"</string>
+    <string name="app_factory_reset" msgid="8718986000278776272">"Gỡ cài đặt bản cập nhật"</string>
     <string name="auto_launch_enable_text" msgid="3372898942144027341">"Bạn đã chọn chạy ứng dụng này theo mặc định cho một số tác vụ."</string>
     <string name="always_allow_bind_appwidgets_text" msgid="2286211654774611037">"Bạn đã chọn cho phép ứng dụng này tạo các tiện ích và truy cập dữ liệu của chúng."</string>
     <string name="auto_launch_disable_text" msgid="8560921288036801416">"Chưa đặt mặc định."</string>
@@ -2032,8 +2037,8 @@
     <string name="accessibility_settings" msgid="9140621093888234485">"Hỗ trợ tiếp cận"</string>
     <string name="accessibility_settings_title" msgid="1687226556576913576">"Cài đặt hỗ trợ tiếp cận"</string>
     <string name="accessibility_settings_summary" msgid="5742379519336396561">"Trình đọc màn hình, hiển thị, điều khiển tương tác"</string>
-    <string name="vision_settings_title" msgid="7315352351051423944">"Cài đặt hiển thị"</string>
-    <string name="vision_settings_description" msgid="3476589459009287332">"Bạn có thể tùy chỉnh thiết bị này cho phù hợp với nhu cầu của mình. Bạn có thể thay đổi các tính năng hỗ trợ tiếp cận trong Cài đặt."</string>
+    <string name="vision_settings_title" msgid="7315352351051423944">"Cài đặt thị giác"</string>
+    <string name="vision_settings_description" msgid="3476589459009287332">"Bạn có thể tùy chỉnh thiết bị này cho phù hợp với nhu cầu của mình. Bạn có thể thay đổi các tính năng hỗ trợ tiếp cận này trong phần Cài đặt."</string>
     <string name="vision_settings_suggestion_title" msgid="7268661419110951128">"Thay đổi cỡ chữ"</string>
     <string name="screen_reader_category_title" msgid="6300714148519645544">"Trình đọc màn hình"</string>
     <string name="audio_and_captions_category_title" msgid="6140472938769619212">"Âm thanh và văn bản trên màn hình"</string>
@@ -2044,7 +2049,7 @@
     <string name="feature_flags_dashboard_title" msgid="3153034144122754381">"Cờ tính năng"</string>
     <string name="talkback_title" msgid="3717960404234260050">"Talkback"</string>
     <string name="talkback_summary" msgid="6602857105831641574">"Trình đọc màn hình chủ yếu dành cho những người khiếm thị và thị lực kém"</string>
-    <string name="select_to_speak_summary" msgid="7514180457557735421">"Nhấn vào mục trên màn hình của bạn để nghe mục được đọc to"</string>
+    <string name="select_to_speak_summary" msgid="7514180457557735421">"Nhấn vào các mục trên màn hình để nghe hệ thống đọc to những mục đó"</string>
     <string name="accessibility_captioning_title" msgid="5878371993023439642">"Phụ đề"</string>
     <string name="accessibility_screen_magnification_title" msgid="7250949681883917360">"Phóng to"</string>
     <string name="accessibility_screen_magnification_gestures_title" msgid="9199287875401817974">"Phóng to bằng cách nhấn 3 lần"</string>
@@ -2080,7 +2085,7 @@
     <string name="accessibility_control_timeout_preference_title" msgid="2771808346038759474">"Thời gian thực hiện hành động"</string>
     <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"Chọn thời lượng hiển thị thông báo mà bạn cần đọc nhưng chỉ hiển thị tạm thời.\n\nKhông phải tất cả ứng dụng đều hỗ trợ tùy chọn cài đặt này."</string>
     <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"Chọn thời lượng hiển thị thông báo yêu cầu bạn thực hiện hành động nhưng chỉ hiển thị tạm thời.\n\nKhông phải tất cả ứng dụng đều hỗ trợ tùy chọn cài đặt này."</string>
-    <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"Thời gian chờ cho chạm và giữ"</string>
+    <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"Thời gian chờ cho cử chỉ chạm và giữ"</string>
     <string name="accessibility_display_inversion_preference_title" msgid="3852635518618938998">"Đảo màu"</string>
     <string name="accessibility_display_inversion_preference_subtitle" msgid="69291255322175323">"Có thể ảnh hưởng đến hiệu suất"</string>
     <string name="accessibility_autoclick_preference_title" msgid="9164599088410340405">"Thời gian dừng"</string>
@@ -2091,7 +2096,7 @@
     <string name="accessibility_ring_vibration_title" msgid="7943341443551359985">"Rung khi đổ chuông"</string>
     <string name="accessibility_touch_vibration_title" msgid="285890135612038092">"Rung khi chạm"</string>
     <string name="accessibility_service_master_switch_title" msgid="2734791644475782924">"Sử dụng dịch vụ"</string>
-    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Sử dụng tính năng sửa màu"</string>
+    <string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Sử dụng tính năng chỉnh màu"</string>
     <string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"Sử dụng phụ đề"</string>
     <string name="accessibility_hearingaid_instruction_continue_button" msgid="4650111296711466691">"Tiếp tục"</string>
     <string name="accessibility_hearingaid_title" msgid="3700978781235124891">"Thiết bị trợ thính"</string>
@@ -2109,7 +2114,7 @@
     <string name="accessibility_summary_state_stopped" msgid="3170264683616172746">"Dịch vụ không hoạt động. Hãy nhấn để xem thông tin."</string>
     <string name="accessibility_description_state_stopped" msgid="7666178628053039493">"Dịch vụ này đang hoạt động không bình thường."</string>
     <string name="enable_quick_setting" msgid="1580451877998661255">"Hiển thị trong Cài đặt nhanh"</string>
-    <string name="daltonizer_type" msgid="6890356081036026791">"Chế độ sửa"</string>
+    <string name="daltonizer_type" msgid="6890356081036026791">"Chế độ chỉnh"</string>
     <plurals name="accessibilty_autoclick_preference_subtitle_extremely_short_delay" formatted="false" msgid="3810676455925024813">
       <item quantity="other">Độ trễ cực kỳ ngắn (<xliff:g id="CLICK_DELAY_LABEL_1">%1$d</xliff:g> mili giây)</item>
       <item quantity="one">Độ trễ cực kỳ ngắn (<xliff:g id="CLICK_DELAY_LABEL_0">%1$d</xliff:g> mili giây)</item>
@@ -2294,7 +2299,7 @@
     </plurals>
     <plurals name="battery_tip_restrict_summary" formatted="false" msgid="984148373944071669">
       <item quantity="other">%2$d ứng dụng có mức sử dụng pin nền cao</item>
-      <item quantity="one">%1$s có mức sử dụng pin nền cao</item>
+      <item quantity="one">%1$s ứng dụng có mức sử dụng pin nền cao</item>
     </plurals>
     <plurals name="battery_tip_restrict_handled_summary" formatted="false" msgid="469696766640020557">
       <item quantity="other">Những ứng dụng này không thể chạy trong nền</item>
@@ -2633,7 +2638,7 @@
     <string name="enter_password" msgid="2963496904625715235">"Để bắt đầu sử dụng thiết bị Android, hãy nhập mật khẩu của bạn"</string>
     <string name="enter_pin" msgid="7140938268709546890">"Để bắt đầu sử dụng thiết bị Android, hãy nhập mã PIN của bạn"</string>
     <string name="enter_pattern" msgid="1653841963422825336">"Để bắt đầu sử dụng thiết bị Android, hãy vẽ hình mẫu của bạn"</string>
-    <string name="cryptkeeper_wrong_pattern" msgid="4580105105385125467">"Hình không chính xác"</string>
+    <string name="cryptkeeper_wrong_pattern" msgid="4580105105385125467">"Hình mở khóa không chính xác"</string>
     <string name="cryptkeeper_wrong_password" msgid="1709534330303983166">"Mật khẩu sai"</string>
     <string name="cryptkeeper_wrong_pin" msgid="857757190077859245">"Mã PIN sai"</string>
     <string name="checking_decryption" msgid="5927759912073053101">"Đang kiểm tra…"</string>
@@ -2666,7 +2671,7 @@
     <string name="data_usage_cellular_data_summary" msgid="9162777397135709280">"Tạm dừng khi đạt giới hạn"</string>
     <string name="account_settings_menu_auto_sync" msgid="2673669556006027506">"Tự động đồng bộ hóa dữ liệu"</string>
     <string name="account_settings_menu_auto_sync_personal" msgid="3235831897309033754">"T.động ĐB hóa dữ liệu cá nhân"</string>
-    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"T.động ĐB hóa d.liệu công việc"</string>
+    <string name="account_settings_menu_auto_sync_work" msgid="5721442464286552815">"Tự động đồng bộ hóa dữ liệu công việc"</string>
     <string name="data_usage_change_cycle" msgid="447761920472170031">"Thay đổi chu kỳ..."</string>
     <string name="data_usage_pick_cycle_day" msgid="6319750879145917066">"Ngày trong tháng để đặt lại chu kỳ sử dụng dữ liệu:"</string>
     <string name="data_usage_empty" msgid="7981405723435034032">"Không ứng dụng nào sử dụng dữ liệu lúc này."</string>
@@ -2789,7 +2794,7 @@
     <string name="vpn_always_on_summary" msgid="3639994551631437397">"Luôn kết nối với VPN mọi lúc"</string>
     <string name="vpn_always_on_summary_not_supported" msgid="9077720997795965133">"Không được ứng dụng này hỗ trợ"</string>
     <string name="vpn_always_on_summary_active" msgid="8962619701962239088">"Luôn bật đang hoạt động"</string>
-    <string name="vpn_require_connection" msgid="5413746839457797350">"Chặn kết nối khối mà không cần VPN"</string>
+    <string name="vpn_require_connection" msgid="5413746839457797350">"Chặn các đường kết nối không qua VPN"</string>
     <string name="vpn_require_connection_title" msgid="8361434328767853717">"Yêu cầu kết nối VPN?"</string>
     <string name="vpn_lockdown_summary" msgid="6770030025737770861">"Chọn một cấu hình VPN để luôn giữ kết nối. Lưu lượng truy cập mạng sẽ chỉ được cho phép khi kết nối với VPN này."</string>
     <string name="vpn_lockdown_none" msgid="3789288793603394679">"Không có"</string>
@@ -2911,16 +2916,16 @@
     <string name="apps_with_restrictions_settings_button" msgid="5065896213467171744">"Mở rộng cài đặt cho ứng dụng"</string>
     <string name="nfc_payment_settings_title" msgid="5070077706735415291">"Nhấn và thanh toán"</string>
     <string name="nfc_payment_how_it_works" msgid="7607901964687787177">"Cách thức hoạt động"</string>
-    <string name="nfc_payment_no_apps" msgid="8844440783395420860">"Thanh toán bằng điện thoại của bạn trong cửa hàng"</string>
-    <string name="nfc_payment_default" msgid="7869273092463612271">"Mặc định thanh toán"</string>
+    <string name="nfc_payment_no_apps" msgid="8844440783395420860">"Dùng điện thoại của bạn để thanh toán tại các cửa hàng"</string>
+    <string name="nfc_payment_default" msgid="7869273092463612271">"Ứng dụng thanh toán mặc định"</string>
     <string name="nfc_payment_default_not_set" msgid="955804193510335338">"Chưa đặt"</string>
     <string name="nfc_payment_app_and_desc" msgid="102312684211458190">"<xliff:g id="APP">%1$s</xliff:g> - <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
-    <string name="nfc_payment_use_default" msgid="3098724195746409476">"Sử dụng mặc định"</string>
+    <string name="nfc_payment_use_default" msgid="3098724195746409476">"Sử dụng ứng dụng mặc định"</string>
     <string name="nfc_payment_favor_default" msgid="7555356982142464260">"Luôn luôn"</string>
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"Trừ khi một ứng dụng thanh toán khác đang mở"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"Ở một cổng Nhấn và thanh toán, thanh toán bằng:"</string>
-    <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Thanh toán tại thiết bị đầu cuối"</string>
-    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Thiết lập ứng dụng thanh toán. Sau đó chỉ cần giữ mặt sau điện thoại của bạn gần với thiết bị đầu cuối bất kỳ có biểu tượng không tiếp xúc."</string>
+    <string name="nfc_how_it_works_title" msgid="6531433737926327904">"Thanh toán trên thiết bị thanh toán"</string>
+    <string name="nfc_how_it_works_content" msgid="9174575836302449343">"Thiết lập ứng dụng thanh toán. Sau đó chỉ cần hướng mặt sau của điện thoại vào thiết bị thanh toán có biểu tượng không tiếp xúc."</string>
     <string name="nfc_how_it_works_got_it" msgid="2432535672153247411">"OK"</string>
     <string name="nfc_more_title" msgid="2825856411836382264">"Thêm..."</string>
     <string name="nfc_payment_set_default_label" msgid="3997927342761454042">"Đặt làm tùy chọn của bạn?"</string>
@@ -3041,7 +3046,7 @@
     <string name="account_dashboard_title" msgid="4734300939532555885">"Tài khoản"</string>
     <string name="account_dashboard_default_summary" msgid="6822549669771936206">"Chưa thêm tài khoản nào"</string>
     <string name="app_default_dashboard_title" msgid="6575301028225232193">"Ứng dụng mặc định"</string>
-    <string name="system_dashboard_summary" msgid="6582464466735779394">"Ngôn ngữ, cử chỉ, thời gian, bản sao lưu"</string>
+    <string name="system_dashboard_summary" msgid="6582464466735779394">"Ngôn ngữ, cử chỉ, ngày giờ, bản sao lưu"</string>
     <string name="search_results_title" msgid="4160717656435503940">"Cài đặt"</string>
     <string name="keywords_wifi" msgid="8477688080895466846">"wifi, wi-fi, kết nối mạng, internet, không dây, dữ liệu, wi fi"</string>
     <string name="keywords_wifi_notify_open_networks" msgid="1031260564121854773">"thông báo về Wi‑Fi, thông báo wifi"</string>
@@ -3129,10 +3134,10 @@
     <string name="sound_settings_summary_vibrate" msgid="2194491116884798590">"Đã đặt chuông thành rung"</string>
     <string name="sound_settings_summary_silent" msgid="899823817462768876">"Đã đặt chuông thành im lặng"</string>
     <string name="sound_settings_example_summary" msgid="2091822107298841827">"Âm lượng chuông ở mức 80%"</string>
-    <string name="media_volume_option_title" msgid="3553411883305505682">"Âm lượng phương tiện"</string>
+    <string name="media_volume_option_title" msgid="3553411883305505682">"Âm lượng nội dung nghe nhìn"</string>
     <string name="remote_media_volume_option_title" msgid="6355710054191873836">"Âm lượng truyền"</string>
     <string name="call_volume_option_title" msgid="5028003296631037334">"Âm lượng cuộc gọi"</string>
-    <string name="alarm_volume_option_title" msgid="3184076022438477047">"Âm lượng báo thức"</string>
+    <string name="alarm_volume_option_title" msgid="3184076022438477047">"Âm lượng chuông báo"</string>
     <string name="ring_volume_option_title" msgid="2038924918468372264">"Âm lượng chuông"</string>
     <string name="notification_volume_option_title" msgid="1358512611511348260">"Âm lượng thông báo"</string>
     <string name="ringtone_title" msgid="1409086028485922583">"Nhạc chuông điện thoại"</string>
@@ -3228,7 +3233,7 @@
     <string name="zen_mode_button_turn_on" msgid="1097964136225943415">"Bật ngay"</string>
     <string name="zen_mode_button_turn_off" msgid="3990967728457149454">"Tắt ngay bây giờ"</string>
     <string name="zen_mode_settings_dnd_manual_end_time" msgid="4307574188962071429">"Chế độ Không làm phiền được bật đến <xliff:g id="FORMATTED_TIME">%s</xliff:g>"</string>
-    <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"Không làm phiền vẫn được bật cho đến khi bạn tắt chế độ này"</string>
+    <string name="zen_mode_settings_dnd_manual_indefinite" msgid="3701005376825238752">"Chế độ Không làm phiền vẫn được bật cho đến khi bạn tắt chế độ này"</string>
     <string name="zen_mode_settings_dnd_automatic_rule" msgid="2843297614114625408">"Chế độ Không làm phiền được tự động bật theo lịch biểu (<xliff:g id="RULE_NAME">%s</xliff:g>)"</string>
     <string name="zen_mode_settings_dnd_automatic_rule_app" msgid="5103454923160912313">"Chế độ Không làm phiền đã được một ứng dụng (<xliff:g id="APP_NAME">%s</xliff:g>) bật tự động"</string>
     <string name="zen_mode_settings_dnd_custom_settings_footer" msgid="6335108298640066560">"Chế độ Không làm phiền đang bật đối với <xliff:g id="RULE_NAMES">%s</xliff:g> với các mục cài đặt tùy chỉnh."</string>
@@ -3398,8 +3403,8 @@
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> loại</item>
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> loại</item>
     </plurals>
-    <string name="no_channels" msgid="8884254729302501652">"Ứng dụng chưa đăng bất kỳ thông báo nào"</string>
-    <string name="app_settings_link" msgid="8465287765715790984">"Cài đặt bổ sung trong ứng dụng"</string>
+    <string name="no_channels" msgid="8884254729302501652">"Ứng dụng này chưa đăng bất kỳ thông báo nào"</string>
+    <string name="app_settings_link" msgid="8465287765715790984">"Tùy chọn cài đặt bổ sung trong ứng dụng"</string>
     <string name="app_notification_listing_summary_zero" msgid="4047782719487686699">"Đang bật cho tất cả ứng dụng"</string>
     <plurals name="app_notification_listing_summary_others" formatted="false" msgid="1161774065480666519">
       <item quantity="other">Tắt cho <xliff:g id="COUNT_1">%d</xliff:g> ứng dụng</item>
@@ -3417,7 +3422,7 @@
     <string name="notification_content_block_summary" msgid="2743896875255591743">"Không bao giờ hiển thị thông báo trong ngăn thông báo hoặc trên thiết bị ngoại vi"</string>
     <string name="notification_badge_title" msgid="8989086619255666442">"Cho phép dấu chấm thông báo"</string>
     <string name="notification_channel_badge_title" msgid="8228215248332054612">"Hiển thị dấu chấm thông báo"</string>
-    <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"Ghi đè Không làm phiền"</string>
+    <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"Vô hiệu hóa chế độ Không làm phiền"</string>
     <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"Cho phép những thông báo này tiếp tục làm gián đoạn khi chế độ Không làm phiền đang bật"</string>
     <string name="app_notification_visibility_override_title" msgid="2349335170165637672">"Trên màn hình khóa"</string>
     <string name="app_notification_row_banned" msgid="2079325338122151677">"Bị chặn"</string>
@@ -3463,9 +3468,9 @@
     <string name="zen_mode_schedule_rule_days" msgid="220627703673691816">"Ngày"</string>
     <string name="zen_mode_schedule_rule_days_none" msgid="6011716195119389956">"Không có"</string>
     <string name="zen_mode_schedule_rule_days_all" msgid="8814173364016139675">"Hàng ngày"</string>
-    <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"Báo thức có thể ghi đè thời gian kết thúc"</string>
-    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"Lịch biểu tắt khi lịch báo thức đổ chuông"</string>
-    <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"Hành vi Không làm phiền"</string>
+    <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"Đồng hồ báo thức có thể vô hiệu hóa thời gian kết thúc"</string>
+    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"Lịch biểu tắt khi một đồng hồ báo thức đổ chuông"</string>
+    <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"Hoạt động ở chế độ Không làm phiền"</string>
     <string name="zen_mode_custom_behavior_summary_default" msgid="3509865340195397447">"Sử dụng các tùy chọn cài đặt mặc định"</string>
     <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"Tạo các mục cài đặt tùy chỉnh cho lịch biểu này"</string>
     <string name="zen_mode_custom_behavior_category_title" msgid="7451686525113262087">"Dành cho ‘<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>’"</string>
@@ -3497,17 +3502,17 @@
     <string name="zen_mode_alarms" msgid="5528707742250954290">"Cho phép chuông báo thức"</string>
     <string name="zen_mode_alarms_list" msgid="9162210238533665593">"báo thức"</string>
     <string name="zen_mode_media" msgid="3701280649874724055">"Phát âm thanh nội dung nghe nhìn"</string>
-    <string name="zen_mode_media_list" msgid="509327580522287125">"nội dung phương tiện"</string>
+    <string name="zen_mode_media_list" msgid="509327580522287125">"nội dung nghe nhìn"</string>
     <string name="zen_mode_system" msgid="597437265986355038">"Cho phép âm chạm"</string>
     <string name="zen_mode_system_list" msgid="480192458506838077">"âm chạm"</string>
     <string name="zen_mode_reminders" msgid="7560664194610054038">"Cho phép lời nhắc"</string>
     <string name="zen_mode_reminders_list" msgid="7347061314032326677">"lời nhắc"</string>
     <string name="zen_mode_events" msgid="5784076928339534984">"Cho phép sự kiện"</string>
     <string name="zen_mode_bypassing_apps" msgid="3080739479028713449">"Cho phép ứng dụng ghi đè"</string>
-    <string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"Ngoại lệ ứng dụng"</string>
+    <string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"Ứng dụng ngoại lệ"</string>
     <plurals name="zen_mode_bypassing_apps_subtext" formatted="false" msgid="8723144434730871572">
-      <item quantity="other">Thông báo từ <xliff:g id="NUMBER">%1$d</xliff:g> ứng dụng có thể ghi đè chế độ Không làm phiền</item>
-      <item quantity="one">Thông báo từ 1 ứng dụng có thể ghi đè chế độ Không làm phiền</item>
+      <item quantity="other">Thông báo từ <xliff:g id="NUMBER">%1$d</xliff:g> ứng dụng có thể vô hiệu hóa chế độ Không làm phiền</item>
+      <item quantity="one">Thông báo từ 1 ứng dụng có thể vô hiệu hóa chế độ Không làm phiền</item>
     </plurals>
     <string name="zen_mode_events_list" msgid="8578102701815684873">"sự kiện"</string>
     <string name="zen_mode_all_callers" msgid="4455039040077343838">"bất kỳ ai"</string>
@@ -3707,10 +3712,10 @@
     <string name="high_power_system" msgid="739584574711292753">"Không tối ưu hóa pin"</string>
     <string name="high_power_desc" msgid="333756885680362741">"Không áp dụng tối ưu hóa pin. Pin của bạn có thể hết nhanh hơn."</string>
     <string name="high_power_prompt_title" msgid="2805745781720454052">"Cho phép ứng dụng luôn chạy trong nền?"</string>
-    <string name="high_power_prompt_body" msgid="8067395096053552289">"Cho phép <xliff:g id="APP_NAME">%1$s</xliff:g> luôn chạy trong nền có thể làm giảm thời lượng pin. \n\nBạn có thể thay đổi cài đặt này từ Cài đặt &gt; Ứng dụng và thông báo."</string>
+    <string name="high_power_prompt_body" msgid="8067395096053552289">"Cho phép <xliff:g id="APP_NAME">%1$s</xliff:g> luôn chạy trong nền có thể làm giảm thời lượng pin. \n\nBạn có thể thay đổi tùy chọn này trong phần Cài đặt &gt; Ứng dụng và thông báo."</string>
     <string name="battery_summary" msgid="4345690800899981339">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> sử dụng kể từ lần sạc đầy gần đây nhất"</string>
     <string name="battery_power_management" msgid="2853925857548647969">"Quản lý nguồn"</string>
-    <string name="no_battery_summary" msgid="4105932628367471314">"Không sử dụng pin kể từ lần sạc đầy cuối cùng"</string>
+    <string name="no_battery_summary" msgid="4105932628367471314">"Không sử dụng pin kể từ lần sạc đầy gần đây nhất"</string>
     <string name="app_notification_preferences" msgid="5154466638524523201">"Cài đặt ứng dụng"</string>
     <string name="system_ui_settings" msgid="6751165163665775447">"Hiện Bộ điều chỉnh SystemUI"</string>
     <string name="additional_permissions" msgid="3142290772324571654">"Quyền khác"</string>
@@ -3728,7 +3733,7 @@
     <string name="usb_use_file_transfers_desc" msgid="6953866660041189580">"Truyền tệp sang thiết bị khác"</string>
     <string name="usb_use_photo_transfers" msgid="5974236250197451257">"PTP"</string>
     <string name="usb_use_photo_transfers_desc" msgid="2325112887316125320">"Chuyển ảnh hoặc tệp nếu MTP không được hỗ trợ (PTP)"</string>
-    <string name="usb_use_tethering" msgid="4250626730173163846">"Chia sẻ kết nối qua USB"</string>
+    <string name="usb_use_tethering" msgid="4250626730173163846">"Chia sẻ Interent qua USB"</string>
     <string name="usb_use_MIDI" msgid="4710632870781041401">"MIDI"</string>
     <string name="usb_use_MIDI_desc" msgid="1770966187150010947">"Sử dụng thiết bị này làm MIDI"</string>
     <string name="usb_use" msgid="8940500223316278632">"Sử dụng USB cho"</string>
@@ -3744,22 +3749,22 @@
     <string name="usb_summary_charging_only" msgid="4118449308708872339">"Đang sạc thiết bị này"</string>
     <string name="usb_summary_power_only" msgid="3552240122641051107">"Sạc thiết bị được kết nối"</string>
     <string name="usb_summary_file_transfers" msgid="7805342797099821502">"Truyền tệp"</string>
-    <string name="usb_summary_tether" msgid="778845069037366883">"Chia sẻ kết nối qua USB"</string>
+    <string name="usb_summary_tether" msgid="778845069037366883">"Chia sẻ Interent qua USB"</string>
     <string name="usb_summary_photo_transfers" msgid="4743028167400644354">"PTP"</string>
     <string name="usb_summary_MIDI" msgid="5540604166270861247">"MIDI"</string>
     <string name="usb_summary_file_transfers_power" msgid="1684501026426766867">"Truyền tệp và cấp điện"</string>
-    <string name="usb_summary_tether_power" msgid="5684170912136320002">"Chia sẻ kết nối qua USB và cấp điện"</string>
+    <string name="usb_summary_tether_power" msgid="5684170912136320002">"Chia sẻ Internet và cấp điện qua USB"</string>
     <string name="usb_summary_photo_transfers_power" msgid="4424106272137720464">"PTP và cấp điện"</string>
     <string name="usb_summary_MIDI_power" msgid="7685597621357005180">"MIDI và cấp điện"</string>
     <string name="background_check_pref" msgid="664081406854758392">"Kiểm tra nền"</string>
     <string name="background_check_title" msgid="4136736684290307970">"Toàn quyền truy cập nền"</string>
-    <string name="assist_access_context_title" msgid="2274614501747710439">"Sử dụng văn bản từ màn hình"</string>
+    <string name="assist_access_context_title" msgid="2274614501747710439">"Sử dụng văn bản trên màn hình"</string>
     <string name="assist_access_context_summary" msgid="5867997494395842785">"Cho phép ứng dụng trợ lý truy cập nội dung trên màn hình dưới dạng văn bản"</string>
     <string name="assist_access_screenshot_title" msgid="1991014038776117688">"Sử dụng ảnh chụp màn hình"</string>
     <string name="assist_access_screenshot_summary" msgid="3010943864000489424">"Cho phép ứng dụng trợ lý truy cập hình ảnh màn hình"</string>
     <string name="assist_flash_title" msgid="8852484250748551092">"Màn hình nháy"</string>
     <string name="assist_flash_summary" msgid="6697095786317559129">"Nhấp nháy các cạnh màn hình khi ứng dụng trợ lý truy cập văn bản từ màn hình hoặc ảnh chụp màn hình"</string>
-    <string name="assist_footer" msgid="7030121180457472165">"Ứng dụng trợ lý có thể giúp bạn dựa trên thông tin từ màn hình bạn đang xem. Một số ứng dụng hỗ trợ cả dịch vụ nhập bằng giọng nói và trình khởi chạy để cung cấp cho bạn khả năng hỗ trợ được tích hợp."</string>
+    <string name="assist_footer" msgid="7030121180457472165">"Các ứng dụng trợ lý có thể dựa vào thông tin trên màn hình bạn đang xem để giúp bạn làm nhiều việc. Một số ứng dụng hỗ trợ cả dịch vụ nhập bằng giọng nói và trình chạy để hỗ trợ bạn toàn diện hơn."</string>
     <string name="average_memory_use" msgid="5333366040118953945">"Sử dụng bộ nhớ trung bình"</string>
     <string name="maximum_memory_use" msgid="6509872438499846077">"Sử dụng bộ nhớ tối đa"</string>
     <string name="memory_usage" msgid="7963253555330830906">"Sử dụng bộ nhớ"</string>
@@ -3808,9 +3813,9 @@
     <string name="app_permission_summary_allowed" msgid="6458476982015518778">"Được phép"</string>
     <string name="app_permission_summary_not_allowed" msgid="1171642541675462584">"Không được phép"</string>
     <string name="keywords_install_other_apps" msgid="5383559540695847668">"cài đặt ứng dụng từ nguồn không xác định"</string>
-    <string name="write_settings" msgid="9009040811145552108">"Sửa đổi cài đặt hệ thống"</string>
-    <string name="keywords_write_settings" msgid="3450405263390246293">"ghi/sửa đổi cài đặt hệ thống"</string>
-    <string name="write_settings_summary" msgid="4650251358459404247">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="COUNT_1">%2$d</xliff:g> được phép sửa đổi cài đặt hệ thống"</string>
+    <string name="write_settings" msgid="9009040811145552108">"Sửa đổi các tùy chọn cài đặt hệ thống"</string>
+    <string name="keywords_write_settings" msgid="3450405263390246293">"ghi/sửa đổi các tùy chọn cài đặt hệ thống"</string>
+    <string name="write_settings_summary" msgid="4650251358459404247">"<xliff:g id="COUNT_0">%1$d</xliff:g> / <xliff:g id="COUNT_1">%2$d</xliff:g> được phép sửa đổi các tùy chọn cài đặt hệ thống"</string>
     <string name="financial_apps_sms_access_title" msgid="3422655018008259655">"Truy cập SMS của ứng dụng tài chính"</string>
     <string name="filter_install_sources_apps" msgid="4519839764020866701">"Có thể cài đặt ứng dụng khác"</string>
     <string name="filter_write_settings_apps" msgid="6864144615530081121">"Có thể sửa đổi các tùy chọn cài đặt hệ thống"</string>
@@ -3821,7 +3826,7 @@
     <string name="write_settings_on" msgid="7328986337962635118">"Có"</string>
     <string name="write_settings_off" msgid="5708257434958406202">"Không"</string>
     <string name="external_source_switch_title" msgid="5947220058496373178">"Cho phép từ nguồn này"</string>
-    <string name="camera_gesture_title" msgid="899403310746415135">"Xoắn đúp cho camera"</string>
+    <string name="camera_gesture_title" msgid="899403310746415135">"Xoay cổ tay hai lần để mở máy ảnh"</string>
     <string name="camera_gesture_desc" msgid="7751841175916789527">"Mở ứng dụng camera bằng cách vặn cổ tay hai lần"</string>
     <string name="camera_double_tap_power_gesture_title" msgid="8874747801078147525">"Nhấn nút nguồn hai lần để mở máy ảnh"</string>
     <string name="camera_double_tap_power_gesture_desc" msgid="6166349645433682873">"Mở nhanh máy ảnh mà không cần mở khóa màn hình của bạn"</string>
@@ -3866,14 +3871,14 @@
     <string name="backup_disabled" msgid="6941165814784765643">"Đã tắt sao lưu"</string>
     <string name="android_version_summary" msgid="2192751442789395445">"Đã cập nhật lên Android <xliff:g id="VERSION">%1$s</xliff:g>"</string>
     <string name="android_version_pending_update_summary" msgid="3554543810520655076">"Đã có bản cập nhật"</string>
-    <string name="disabled_by_policy_title" msgid="1238318274952958846">"Tác vụ này không được cho phép"</string>
+    <string name="disabled_by_policy_title" msgid="1238318274952958846">"Thao tác này không được phép"</string>
     <string name="disabled_by_policy_title_adjust_volume" msgid="7094547090629203316">"Không thể thay đổi âm lượng"</string>
     <string name="disabled_by_policy_title_outgoing_calls" msgid="3805836913095496278">"Không cho phép gọi"</string>
     <string name="disabled_by_policy_title_sms" msgid="1453236584236681105">"Không cho phép SMS"</string>
     <string name="disabled_by_policy_title_camera" msgid="3741138901926111197">"Không cho phép máy ảnh"</string>
     <string name="disabled_by_policy_title_screen_capture" msgid="1856835333536274665">"Không cho phép ảnh chụp màn hình"</string>
     <string name="disabled_by_policy_title_suspend_packages" msgid="4254714213391802322">"Không thể mở ứng dụng này"</string>
-    <string name="default_admin_support_msg" msgid="5789424433689798637">"Nếu bạn có câu hỏi, hãy liên hệ với quản trị viên CNTT"</string>
+    <string name="default_admin_support_msg" msgid="5789424433689798637">"Nếu bạn có câu hỏi, hãy liên hệ với quản trị viên CNTT của bạn"</string>
     <string name="admin_support_more_info" msgid="8737842638087863477">"Thông tin chi tiết khác"</string>
     <string name="admin_profile_owner_message" msgid="3199544166281052845">"Quản trị viên của bạn có thể giám sát và quản lý các ứng dụng cũng như dữ liệu được liên kết với hồ sơ công việc của bạn, bao gồm cài đặt, quyền, quyền truy cập vào dữ liệu công ty, hoạt động mạng và thông tin vị trí của thiết bị."</string>
     <string name="admin_profile_owner_user_message" msgid="2991249382056855531">"Quản trị viên của bạn có thể giám sát và quản lý các ứng dụng cũng như dữ liệu được liên kết với người dùng này, bao gồm cài đặt, quyền, quyền truy cập vào dữ liệu công ty, hoạt động mạng và thông tin vị trí của thiết bị."</string>
@@ -3928,7 +3933,7 @@
     <string name="ota_disable_automatic_update" msgid="7630249692207340986">"Cập nhật hệ thống tự động"</string>
     <string name="ota_disable_automatic_update_summary" msgid="5650682441097227162">"Áp dụng bản cập nhật khi thiết bị khởi động lại"</string>
     <string name="usage" msgid="9172908720164431622">"Sử dụng"</string>
-    <string name="cellular_data_usage" msgid="1236562234207782386">"Sử dụng dữ liệu di động"</string>
+    <string name="cellular_data_usage" msgid="1236562234207782386">"Mức sử dụng dữ liệu di động"</string>
     <string name="app_cellular_data_usage" msgid="8499761516172121957">"Mức sử dụng dữ liệu của ứng dụng"</string>
     <string name="wifi_data_usage" msgid="275569900562265895">"Mức sử dụng dữ liệu Wi-Fi"</string>
     <string name="ethernet_data_usage" msgid="747614925362556718">"Sử dụng dữ liệu ethernet"</string>
@@ -3939,9 +3944,9 @@
     <string name="ethernet_data_template" msgid="6414118030827090119">"<xliff:g id="AMOUNT">^1</xliff:g> dữ liệu ethernet"</string>
     <string name="billing_cycle" msgid="5740717948341713190">"Hạn mức và cảnh báo dữ liệu"</string>
     <string name="app_usage_cycle" msgid="213483325132959663">"Chu kỳ sử dụng dữ liệu của ứng dụng"</string>
-    <string name="cell_data_warning" msgid="8902740337286652689">"Cảnh báo dữ liệu: <xliff:g id="ID_1">^1</xliff:g>"</string>
+    <string name="cell_data_warning" msgid="8902740337286652689">"Cảnh báo dữ liệu khi dùng đến <xliff:g id="ID_1">^1</xliff:g>"</string>
     <string name="cell_data_limit" msgid="3175933829235314233">"Hạn mức dữ liệu <xliff:g id="ID_1">^1</xliff:g>"</string>
-    <string name="cell_data_warning_and_limit" msgid="3846150001253927594">"Cảnh báo dữ liệu <xliff:g id="ID_1">^1</xliff:g>/Hạn mức dữ liệu <xliff:g id="ID_2">^2</xliff:g>"</string>
+    <string name="cell_data_warning_and_limit" msgid="3846150001253927594">"Cảnh báo dữ liệu khi dùng đến <xliff:g id="ID_1">^1</xliff:g>/Hạn mức dữ liệu là <xliff:g id="ID_2">^2</xliff:g>"</string>
     <string name="billing_cycle_fragment_summary" msgid="4926047002107855543">"Hàng tháng vào ngày <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="network_restrictions" msgid="196294262243618198">"Hạn chế của mạng"</string>
     <plurals name="network_restrictions_summary" formatted="false" msgid="1664494781594839837">
@@ -3997,7 +4002,7 @@
     <string name="suggestion_additional_fingerprints" msgid="3434467207282466411">"Thêm một vân tay khác"</string>
     <string name="suggestion_additional_fingerprints_summary" msgid="1916547587832484196">"Mở khóa bằng vân tay khác"</string>
     <string name="battery_saver_on_summary" msgid="6841062406467435672">"Bật"</string>
-    <string name="battery_saver_off_scheduled_summary" msgid="3740414764069188669">"Sẽ bật lúc pin ở mức <xliff:g id="BATTERY_PERCENTAGE">%1$s</xliff:g>"</string>
+    <string name="battery_saver_off_scheduled_summary" msgid="3740414764069188669">"Sẽ bật khi pin ở mức <xliff:g id="BATTERY_PERCENTAGE">%1$s</xliff:g>"</string>
     <string name="battery_saver_off_summary" msgid="8736555723004299721">"Đang tắt"</string>
     <string name="battery_saver_button_turn_on" msgid="3748696527267573793">"Bật ngay"</string>
     <string name="battery_saver_button_turn_off" msgid="2912950982503267828">"Tắt ngay bây giờ"</string>
@@ -4042,10 +4047,10 @@
     <string name="theme_customization_accent_color_title" msgid="3949108608589133216">"Màu nhấn"</string>
     <string name="theme_customization_font_title" msgid="309728559821356597">"Phông chữ tiêu đề / nội dung"</string>
     <string name="theme_customization_icon_shape_title" msgid="4603248388639328322">"Hình dạng biểu tượng"</string>
-    <string name="theme_customization_device_default" msgid="7188874258500934312">"Theo mặc định của thiết bị"</string>
+    <string name="theme_customization_device_default" msgid="7188874258500934312">"Theo giá trị mặc định của thiết bị"</string>
     <string name="display_cutout_emulation" msgid="288975763151891685">"Vết cắt trên màn hình"</string>
     <string name="display_cutout_emulation_keywords" msgid="6795671536772871439">"cắt hiển thị, vết cắt"</string>
-    <string name="overlay_option_device_default" msgid="165508753381657697">"Theo mặc định của thiết bị"</string>
+    <string name="overlay_option_device_default" msgid="165508753381657697">"Theo giá trị mặc định của thiết bị"</string>
     <string name="overlay_toast_failed_to_apply" msgid="5692251825129250040">"Không áp dụng được lớp phủ"</string>
     <string name="special_access" msgid="1453926335914696206">"Quyền truy cập đặc biệt"</string>
     <plurals name="special_access_summary" formatted="false" msgid="5182092345063909346">
@@ -4066,14 +4071,14 @@
     <string name="premium_sms_warning" msgid="7604011651486294515">"Tin nhắn dịch vụ có thể làm bạn mất tiền và sẽ tính thêm vào hóa đơn nhà mạng của bạn. Nếu bạn bật quyền cho một ứng dụng, bạn sẽ có thể gửi Tin nhắn dịch vụ bằng ứng dụng đó."</string>
     <string name="premium_sms_access" msgid="4550027460595822851">"Truy cập Tin nhắn dịch vụ"</string>
     <string name="bluetooth_disabled" msgid="6588102116819268238">"Tắt"</string>
-    <string name="bluetooth_connected_summary" msgid="439920840053965217">"Được kết nối với <xliff:g id="ID_1">%1$s</xliff:g>"</string>
-    <string name="bluetooth_connected_multiple_devices_summary" msgid="596205630653123250">"Được kết nối với nhiều thiết bị"</string>
+    <string name="bluetooth_connected_summary" msgid="439920840053965217">"Đã kết nối với <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="bluetooth_connected_multiple_devices_summary" msgid="596205630653123250">"Đã kết nối với nhiều thiết bị"</string>
     <string name="demo_mode" msgid="3831081808592541104">"Chế độ thử nghiệm giao diện người dùng hệ thống"</string>
     <string name="dark_ui_mode" msgid="703844190192599217">"Giao diện"</string>
     <string name="dark_ui_mode_title" msgid="8774932716427742413">"Chọn giao diện"</string>
     <string name="dark_ui_settings_light_summary" msgid="5219102347744462812">"Tùy chọn cài đặt này cũng áp dụng cho các ứng dụng"</string>
     <string name="dark_ui_settings_dark_summary" msgid="7042737828943784289">"Các ứng dụng được hỗ trợ cũng sẽ chuyển sang giao diện tối"</string>
-    <string name="quick_settings_developer_tiles" msgid="7423485925757678719">"Ô nhà phát triển cài đặt nhanh"</string>
+    <string name="quick_settings_developer_tiles" msgid="7423485925757678719">"Ô cài đặt nhanh dành cho nhà phát triển"</string>
     <string name="winscope_trace_quick_settings_title" msgid="940971040388411374">"Dấu vết Winscope"</string>
     <string name="sensors_off_quick_settings_title" msgid="3655699045300438902">"Tắt cảm biến"</string>
     <string name="managed_profile_settings_title" msgid="4340409321523532402">"Cài đặt hồ sơ công việc"</string>
@@ -4305,7 +4310,7 @@
     <string name="change_wifi_state_title" msgid="5140754955787584174">"Kiểm soát Wi-Fi"</string>
     <string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"Cho phép ứng dụng kiểm soát Wi-Fi"</string>
     <string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"Cho phép ứng dụng này bật/tắt Wi-Fi, quét và kết nối với mạng Wi-Fi, thêm/xóa mạng hoặc bắt đầu một điểm phát sóng chỉ cục bộ"</string>
-    <string name="media_output_title" msgid="8710632337456601848">"Phát phương tiện tới"</string>
+    <string name="media_output_title" msgid="8710632337456601848">"Phát nội dung nghe nhìn tới"</string>
     <string name="media_output_default_summary" msgid="3159237976830415584">"Thiết bị này"</string>
     <string name="media_output_summary" product="default" msgid="6294261435613551178">"Điện thoại"</string>
     <string name="media_output_summary" product="tablet" msgid="6672024060360538526">"Máy tính bảng"</string>
diff --git a/tests/CarDeveloperOptions/res/values-zh-rCN/arrays.xml b/tests/CarDeveloperOptions/res/values-zh-rCN/arrays.xml
index c6c525e..d2cb99c 100644
--- a/tests/CarDeveloperOptions/res/values-zh-rCN/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-zh-rCN/arrays.xml
@@ -272,7 +272,7 @@
     <item msgid="6266277260961066535">"辅助结构"</item>
     <item msgid="7715498149883482300">"辅助屏幕截图"</item>
     <item msgid="4046679376726313293">"读取手机状态"</item>
-    <item msgid="6329507266039719587">"添加语音邮件"</item>
+    <item msgid="6329507266039719587">"添加语音信息"</item>
     <item msgid="7692440726415391408">"使用 SIP"</item>
     <item msgid="8572453398128326267">"处理拨出电话"</item>
     <item msgid="7775674394089376306">"指纹"</item>
@@ -339,7 +339,7 @@
     <item msgid="7106921284621230961">"辅助结构"</item>
     <item msgid="4496533640894624799">"辅助屏幕截图"</item>
     <item msgid="2598847264853993611">"读取手机状态"</item>
-    <item msgid="9215610846802973353">"添加语音邮件"</item>
+    <item msgid="9215610846802973353">"添加语音信息"</item>
     <item msgid="9186411956086478261">"使用 SIP"</item>
     <item msgid="6884763100104539558">"处理拨出电话"</item>
     <item msgid="125513972170580692">"指纹"</item>
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"永不允许"</item>
     <item msgid="8184570120217958741">"始终允许"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"正常"</item>
+    <item msgid="5101233285497327432">"中等"</item>
+    <item msgid="1555861583162930714">"低"</item>
+    <item msgid="1719683776264798117">"严重不足"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"正常"</item>
+    <item msgid="6107138933849816768">"中等"</item>
+    <item msgid="182695359839047859">"低"</item>
+    <item msgid="8577246509202964244">"严重"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"常驻"</item>
     <item msgid="167418068739176448">"顶层 Activity"</item>
diff --git a/tests/CarDeveloperOptions/res/values-zh-rCN/config.xml b/tests/CarDeveloperOptions/res/values-zh-rCN/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-zh-rCN/config.xml
+++ b/tests/CarDeveloperOptions/res/values-zh-rCN/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-zh-rCN/strings.xml b/tests/CarDeveloperOptions/res/values-zh-rCN/strings.xml
index a2c5369..cf03f82 100644
--- a/tests/CarDeveloperOptions/res/values-zh-rCN/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-zh-rCN/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"缩小或放大屏幕上的文字。"</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"缩小"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"放大"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"示例文本"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"绿野仙踪"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"第 11 章:奥兹国神奇的翡翠城"</string>
@@ -209,7 +208,7 @@
     <string name="proxy_error_empty_host_set_port" msgid="8471455809508588255">"如果主机字段为空,则端口字段必须为空。"</string>
     <string name="proxy_error_invalid_port" msgid="4046559920586100637">"您键入的端口无效。"</string>
     <string name="proxy_warning_limited_support" msgid="9026539134219095768">"浏览器会使用 HTTP 代理,但其他应用可能不会使用。"</string>
-    <string name="proxy_url_title" msgid="882042361706435904">"PAC网址: "</string>
+    <string name="proxy_url_title" msgid="882042361706435904">"PAC 网址: "</string>
     <string name="radio_info_dl_kbps" msgid="2903778264453410272">"DL 带宽 (kbps):"</string>
     <string name="radio_info_ul_kbps" msgid="3802245899811732716">"UL 带宽 (kbps):"</string>
     <string name="radio_info_signal_location_label" msgid="6788144906873498013">"移动网络位置信息(已弃用):"</string>
@@ -312,12 +311,12 @@
     <string name="roaming" msgid="8860308342135146004">"漫游"</string>
     <string name="roaming_enable" msgid="2108142024297441116">"漫游时连接到移动数据网络服务"</string>
     <string name="roaming_disable" msgid="1915440242079953809">"漫游时连接到移动数据网络服务"</string>
-    <string name="roaming_reenable_message" msgid="8388505868655113258">"移动数据网络连接已断开,因为您已离开本地网络并关闭了移动数据网络漫游功能。"</string>
+    <string name="roaming_reenable_message" msgid="8388505868655113258">"移动数据网络连接已断开,因为您已离开本地网络并关闭了数据漫游功能。"</string>
     <string name="roaming_turn_it_on_button" msgid="4370846458830537578">"将其启用"</string>
     <string name="roaming_warning" msgid="5488050911277592868">"这可能会产生高额费用。"</string>
     <string name="roaming_warning_multiuser" product="tablet" msgid="7090388691615686893">"如果允许数据漫游,您可能需要支付高昂的漫游费用!\n\n此设置会影响这部平板电脑上的所有用户。"</string>
     <string name="roaming_warning_multiuser" product="default" msgid="6999819541078827556">"如果允许数据漫游,您可能需要支付高昂的漫游费用!\n\n此设置会影响这部手机上的所有用户。"</string>
-    <string name="roaming_reenable_title" msgid="6985082191178297921">"允许移动数据网络漫游吗?"</string>
+    <string name="roaming_reenable_title" msgid="6985082191178297921">"允许数据漫游?"</string>
     <string name="networks" msgid="3073876464102136771">"运营商选择"</string>
     <string name="sum_carrier_select" msgid="8964744180598499121">"选择网络运营商"</string>
     <string name="date_and_time_settings_title" msgid="7827088656940910631">"日期和时间"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">必须少于 <xliff:g id="NUMBER_1">%d</xliff:g> 位数</item>
       <item quantity="one">必须少于 <xliff:g id="NUMBER_0">%d</xliff:g> 位数</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"只能包含 0-9 的数字"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"设备管理员不允许使用最近用过的 PIN 码"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"常用 PIN 码已被您的 IT 管理员屏蔽。请尝试一个不同的 PIN 码。"</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"密码不得包含无效字符"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">必须包含至少 <xliff:g id="COUNT">%d</xliff:g> 个非字母字符</item>
       <item quantity="one">必须包含至少 1 个非字母字符</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">必须包含至少 <xliff:g id="COUNT">%d</xliff:g> 个非数字字符</item>
+      <item quantity="one">必须包含至少 1 个非数字字符</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"设备管理员不允许使用最近用过的密码"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"常用密码已被您的 IT 管理员屏蔽。请尝试一个不同的密码。"</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"不允许使用以升序、降序或重复序列进行排列的一串数字"</string>
@@ -716,7 +718,7 @@
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> 个应用正在运行</item>
     </plurals>
     <string name="manage_trust_agents" msgid="8129970926213142261">"可信代理"</string>
-    <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"要开始使用,请先设置屏幕锁定方式"</string>
+    <string name="disabled_because_no_backup_security" msgid="8127039979909203528">"需先设置屏幕锁定方式才能使用"</string>
     <string name="manage_trust_agents_summary" msgid="2023116850759962248">"无"</string>
     <plurals name="manage_trust_agents_summary_on" formatted="false" msgid="5550538038916606097">
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> 个可信代理正在运行</item>
@@ -887,7 +889,7 @@
     <string name="wifi_menu_forget" msgid="7561140554450163075">"取消保存网络"</string>
     <string name="wifi_menu_modify" msgid="4080178040721021101">"修改网络"</string>
     <string name="wifi_empty_list_wifi_off" msgid="272877164691346240">"要查看可用网络,请打开 WLAN。"</string>
-    <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"正在搜索WLAN网络…"</string>
+    <string name="wifi_empty_list_wifi_on" msgid="881478805041020600">"正在搜索 WLAN 网络…"</string>
     <string name="wifi_empty_list_user_restricted" msgid="2341613007817352431">"您无权更改WLAN网络。"</string>
     <string name="wifi_more" msgid="3538241640407382185">"更多"</string>
     <string name="wifi_setup_wps" msgid="6730131677695521321">"自动设置 (WPS)"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"WLAN"</item>
+    <item msgid="2271962426654621656">"移动数据"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"如果无法连接到 WLAN,请使用移动网络"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"如果移动网络不可用,请使用 WLAN"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"通过 WLAN 进行通话。如果 WLAN 连接中断,通话将会结束。"</string>
@@ -1205,8 +1210,8 @@
     <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"关闭"</string>
     <string name="adaptive_sleep_description" msgid="812673735459170009">"避免屏幕在您查看它时关闭。"</string>
     <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"屏幕感知功能会通过前置摄像头来确定是否有人正在看屏幕。这个功能只会在设备上运行,系统决不会存储图片或将图片发送给 Google。"</string>
-    <string name="night_display_title" msgid="1305002424893349814">"夜间模式"</string>
-    <string name="night_display_text" msgid="5330502493684652527">"夜间模式会将您的屏幕色调调为琥珀色,可让您在光线昏暗的环境下更舒适地查看屏幕或阅读文字,并有助您入睡。"</string>
+    <string name="night_display_title" msgid="1305002424893349814">"护眼模式"</string>
+    <string name="night_display_text" msgid="5330502493684652527">"护眼模式会将您的屏幕色调调为琥珀色,可让您在光线昏暗的环境下更舒适地查看屏幕或阅读文字,并有助您入睡。"</string>
     <string name="night_display_auto_mode_title" msgid="8493573087102481588">"设定时间"</string>
     <string name="night_display_auto_mode_never" msgid="2897444637217807088">"无"</string>
     <string name="night_display_auto_mode_custom" msgid="1400891076453963151">"在设定的时间开启"</string>
@@ -1227,8 +1232,8 @@
     <string name="night_display_activation_off_manual" msgid="7776082151269794201">"立即关闭"</string>
     <string name="night_display_activation_on_twilight" msgid="5610294051700287249">"开启,直到日出"</string>
     <string name="night_display_activation_off_twilight" msgid="6846727701281556110">"关闭,直到日落"</string>
-    <string name="night_display_activation_on_custom" msgid="4761140206778957611">"保持开启状态,直到<xliff:g id="ID_1">%1$s</xliff:g>"</string>
-    <string name="night_display_activation_off_custom" msgid="4207238846687792731">"保持关闭状态,直到<xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="night_display_activation_on_custom" msgid="4761140206778957611">"开启,直到<xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="night_display_activation_off_custom" msgid="4207238846687792731">"关闭,直到<xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="night_display_not_currently_on" msgid="1436588493764429281">"目前未开启护眼模式"</string>
     <string name="screen_timeout" msgid="1700950247634525588">"休眠"</string>
     <string name="screen_timeout_title" msgid="150117777762864112">"屏幕关闭"</string>
@@ -1725,7 +1730,7 @@
     <string name="lockpassword_confirm_your_pin_generic" msgid="8732268389177735264">"请输入您的设备 PIN 码以继续"</string>
     <string name="lockpassword_confirm_your_password_generic" msgid="6304552647060899594">"请输入您的设备密码以继续"</string>
     <string name="lockpassword_confirm_your_pattern_generic_profile" msgid="3074250084050465513">"请绘制您的工作解锁图案以继续"</string>
-    <string name="lockpassword_confirm_your_pin_generic_profile" msgid="6037908971086439523">"请输入您的工作 PIN 码以继续"</string>
+    <string name="lockpassword_confirm_your_pin_generic_profile" msgid="6037908971086439523">"需输入您的工作资料 PIN 码才能继续"</string>
     <string name="lockpassword_confirm_your_password_generic_profile" msgid="2646162490703489685">"请输入您的工作密码以继续"</string>
     <string name="lockpassword_strong_auth_required_device_pattern" msgid="1014214190135045781">"为了提升安全性,请绘制您的设备解锁图案"</string>
     <string name="lockpassword_strong_auth_required_device_pin" msgid="24030584350601016">"为了提升安全性,请输入您的设备 PIN 码"</string>
@@ -1824,7 +1829,7 @@
     <string name="app_factory_reset" msgid="8718986000278776272">"卸载更新"</string>
     <string name="auto_launch_enable_text" msgid="3372898942144027341">"您已选择默认使用此应用处理某些操作。"</string>
     <string name="always_allow_bind_appwidgets_text" msgid="2286211654774611037">"您已选择允许该应用创建微件并查看其数据。"</string>
-    <string name="auto_launch_disable_text" msgid="8560921288036801416">"没有默认操作。"</string>
+    <string name="auto_launch_disable_text" msgid="8560921288036801416">"无默认设置。"</string>
     <string name="clear_activities" msgid="2068014972549235347">"清除默认操作"</string>
     <string name="screen_compatibility_text" msgid="1768064020294301496">"此应用可能不是针对您的屏幕设计的。您可以在此处调整其显示尺寸/比例,让它适合您的屏幕。"</string>
     <string name="ask_compatibility" msgid="6687958195768084807">"启动时确认"</string>
@@ -2077,7 +2082,7 @@
     <string name="accessibility_timeout_1min" msgid="5019003178551730551">"1 分钟"</string>
     <string name="accessibility_timeout_2mins" msgid="4124259290444829477">"2 分钟"</string>
     <string name="accessibility_content_timeout_preference_title" msgid="5160746882250939464">"阅读时间"</string>
-    <string name="accessibility_control_timeout_preference_title" msgid="2771808346038759474">"操作执行时长"</string>
+    <string name="accessibility_control_timeout_preference_title" msgid="2771808346038759474">"等待操作的时长"</string>
     <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"请选择您需要阅读的消息的显示时间(只会暂时显示)。\n\n只有部分应用支持这项设置。"</string>
     <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"请选择提示您执行操作的消息的显示时间(只会暂时显示)。\n\n部分应用可能不支持这项设置。"</string>
     <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"轻触并按住的延迟时间"</string>
@@ -2273,7 +2278,7 @@
     <string name="battery_tip_smart_battery_title" product="device" msgid="7419448992583346364">"延长设备的电池续航时间"</string>
     <string name="battery_tip_smart_battery_summary" msgid="5344821856478265778">"开启电池管理器"</string>
     <string name="battery_tip_early_heads_up_title" msgid="707163785378746813">"开启省电模式"</string>
-    <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"电池电量可能会比平时更早耗尽"</string>
+    <string name="battery_tip_early_heads_up_summary" msgid="4231489566422395156">"电池电量可能会比平时更快耗尽"</string>
     <string name="battery_tip_early_heads_up_done_title" msgid="112550885882648429">"省电模式已开启"</string>
     <string name="battery_tip_early_heads_up_done_summary" msgid="8692257022962771181">"部分功能可能会受到限制"</string>
     <string name="battery_tip_high_usage_title" product="default" msgid="4103005178310487352">"手机的使用强度比平时高"</string>
@@ -2652,7 +2657,7 @@
     <string name="data_usage_data_limit" msgid="4070740691087063670">"设置流量上限"</string>
     <string name="data_usage_cycle" msgid="1877235461828192940">"流量消耗重置周期"</string>
     <string name="data_usage_app_items_header_text" msgid="5396134508509913851">"应用数据流量"</string>
-    <string name="data_usage_menu_roaming" msgid="6933555994416977198">"移动数据网络漫游"</string>
+    <string name="data_usage_menu_roaming" msgid="6933555994416977198">"数据漫游"</string>
     <string name="data_usage_menu_restrict_background" msgid="3539289148113800518">"限制后台流量"</string>
     <string name="data_usage_menu_allow_background" msgid="2874898501715368528">"允许使用后台流量"</string>
     <string name="data_usage_menu_split_4g" msgid="2264683155484246409">"单独显示4G流量"</string>
@@ -2754,7 +2759,7 @@
     <string name="vpn_not_used" msgid="2889520789132261454">"(未使用)"</string>
     <string name="vpn_no_ca_cert" msgid="486605757354800838">"(不验证服务器)"</string>
     <string name="vpn_no_server_cert" msgid="679622228649855629">"(来自服务器)"</string>
-    <string name="vpn_always_on_invalid_reason_type" msgid="165810330614905489">"此 VPN 类型无法随时保持连接"</string>
+    <string name="vpn_always_on_invalid_reason_type" msgid="165810330614905489">"此类型的 VPN 无法随时保持连接"</string>
     <string name="vpn_always_on_invalid_reason_server" msgid="3864424127328210700">"始终开启的 VPN 仅支持数字格式的服务器地址"</string>
     <string name="vpn_always_on_invalid_reason_no_dns" msgid="3814114757059738225">"必须为始终开启的 VPN 指定 DNS 服务器"</string>
     <string name="vpn_always_on_invalid_reason_dns" msgid="501388894176868973">"DNS 服务器地址必须为数字才能使用始终开启的 VPN"</string>
@@ -2787,7 +2792,7 @@
     <string name="vpn_menu_lockdown" msgid="6951452279924808089">"始终开启的 VPN"</string>
     <string name="vpn_no_vpns_added" msgid="6616183541896197147">"尚未添加任何 VPN"</string>
     <string name="vpn_always_on_summary" msgid="3639994551631437397">"随时和 VPN 保持连接"</string>
-    <string name="vpn_always_on_summary_not_supported" msgid="9077720997795965133">"不受此应用支持"</string>
+    <string name="vpn_always_on_summary_not_supported" msgid="9077720997795965133">"此应用不支持"</string>
     <string name="vpn_always_on_summary_active" msgid="8962619701962239088">"已启用“始终开启”模式"</string>
     <string name="vpn_require_connection" msgid="5413746839457797350">"屏蔽未使用 VPN 的所有连接"</string>
     <string name="vpn_require_connection_title" msgid="8361434328767853717">"需要连接 VPN?"</string>
@@ -2845,7 +2850,7 @@
     <string name="user_settings_title" msgid="7917598650933179545">"多用户"</string>
     <string name="user_settings_footer_text" product="device" msgid="4573858247439190545">"通过添加新用户来共享您的设备。每个用户都将在您的设备上拥有个人空间,以便使用自定义的主屏幕、帐号、应用和设置等。"</string>
     <string name="user_settings_footer_text" product="tablet" msgid="780018221428132918">"通过添加新用户来共享您的平板电脑。每个用户都将在您的平板电脑上拥有个人空间,以便使用自定义的主屏幕、帐号、应用和设置等。"</string>
-    <string name="user_settings_footer_text" product="default" msgid="1470859614968237491">"通过添加新用户来共享您的手机。每个用户都将在您的手机上拥有个人空间,以便使用自定义的主屏幕、帐号、应用和设置等。"</string>
+    <string name="user_settings_footer_text" product="default" msgid="1470859614968237491">"通过添加新用户,您可以与他人共用一部手机。每个用户都将在您的手机上拥有个人空间,并可自行设定主屏幕、帐号、应用和设置等。"</string>
     <string name="user_list_title" msgid="6670258645246192324">"用户和个人资料"</string>
     <string name="user_add_user_or_profile_menu" msgid="4220679989900149336">"添加用户或个人资料"</string>
     <string name="user_add_user_menu" msgid="9006572936456324794">"添加用户"</string>
@@ -2910,7 +2915,7 @@
     <string name="apps_with_restrictions_header" msgid="8656739605673756176">"受限应用"</string>
     <string name="apps_with_restrictions_settings_button" msgid="5065896213467171744">"展开应用设置"</string>
     <string name="nfc_payment_settings_title" msgid="5070077706735415291">"触碰付款"</string>
-    <string name="nfc_payment_how_it_works" msgid="7607901964687787177">"工作原理"</string>
+    <string name="nfc_payment_how_it_works" msgid="7607901964687787177">"工作方式"</string>
     <string name="nfc_payment_no_apps" msgid="8844440783395420860">"使用手机在商店内付款"</string>
     <string name="nfc_payment_default" msgid="7869273092463612271">"默认付款应用"</string>
     <string name="nfc_payment_default_not_set" msgid="955804193510335338">"未设置"</string>
@@ -3140,7 +3145,7 @@
     <string name="notification_unknown_sound_title" msgid="8043718667804838398">"应用提供的提示音"</string>
     <string name="notification_sound_default" msgid="2664544380802426260">"默认通知提示音"</string>
     <string name="alarm_ringtone_title" msgid="6411326147408635902">"默认闹钟提示音"</string>
-    <string name="vibrate_when_ringing_title" msgid="2757996559847126952">"有来电时振动"</string>
+    <string name="vibrate_when_ringing_title" msgid="2757996559847126952">"来电振动"</string>
     <string name="other_sound_settings" msgid="5250376066099818676">"其他提示音"</string>
     <string name="dial_pad_tones_title" msgid="8877212139988655769">"拨号键盘提示音"</string>
     <string name="screen_locking_sounds_title" msgid="4407110895465866809">"屏幕锁定提示音"</string>
@@ -3157,14 +3162,14 @@
     <string name="emergency_tone_vibrate" msgid="5020068066905681181">"振动"</string>
     <string name="boot_sounds_title" msgid="7583926202411353620">"开机音效"</string>
     <string name="live_caption_title" msgid="7926591158657997051">"实时字幕"</string>
-    <string name="live_caption_summary" msgid="9064771862352393125">"自动字幕媒体"</string>
+    <string name="live_caption_summary" msgid="9064771862352393125">"自动生成媒体字幕"</string>
     <string name="zen_mode_settings_summary_off" msgid="6929319200478424962">"永不"</string>
     <plurals name="zen_mode_settings_summary_on" formatted="false" msgid="6061723291126091396">
       <item quantity="other">已启用 <xliff:g id="ON_COUNT">%d</xliff:g> 个</item>
       <item quantity="one">已启用 1 个</item>
     </plurals>
     <string name="zen_mode_settings_title" msgid="3425263414594779244">"勿扰模式"</string>
-    <string name="zen_mode_settings_turn_on_dialog_title" msgid="3062548369931058282">"开启“勿扰”模式"</string>
+    <string name="zen_mode_settings_turn_on_dialog_title" msgid="3062548369931058282">"开启勿扰模式"</string>
     <string name="zen_mode_behavior_settings_title" msgid="423125904296667490">"例外情况"</string>
     <string name="zen_mode_duration_settings_title" msgid="5522668871014735728">"默认时长"</string>
     <string name="zen_mode_behavior_allow_title" msgid="2440627647424280842">"允许以下类型的提示音和振动:"</string>
@@ -3196,7 +3201,7 @@
     <string name="zen_mode_restrict_notifications_mute_footer" msgid="3049522809520549054">"手机在收到通知时既不会发出提示音也不会振动。"</string>
     <string name="zen_mode_restrict_notifications_hide" msgid="3296933643539682552">"不显示通知,也不发出通知提示音"</string>
     <string name="zen_mode_restrict_notifications_hide_summary" msgid="1449301153755270168">"您将不会看到通知或听到通知提示音"</string>
-    <string name="zen_mode_restrict_notifications_hide_footer" msgid="7617688597593946765">"您的手机将不会显示任何新通知或现有通知,也不会因此发出振动或提示音。请注意,系统仍会显示与手机活动和状态相关的重要通知。\n\n关闭“勿扰”模式后,您可以通过从屏幕顶部向下滑动来查找错过的通知。"</string>
+    <string name="zen_mode_restrict_notifications_hide_footer" msgid="7617688597593946765">"您的手机将不会显示任何新通知或现有通知,也不会因此发出振动或提示音。请注意,系统仍会显示与手机活动和状态相关的重要通知。\n\n关闭勿扰模式后,只要从屏幕顶部向下滑动即可查看错过的通知。"</string>
     <string name="zen_mode_restrict_notifications_custom" msgid="3167252482570424133">"自定义"</string>
     <string name="zen_mode_restrict_notifications_enable_custom" msgid="6376983315529894440">"启用自定义设置"</string>
     <string name="zen_mode_restrict_notifications_disable_custom" msgid="8004212081465043044">"移除自定义设置"</string>
@@ -3504,7 +3509,7 @@
     <string name="zen_mode_reminders_list" msgid="7347061314032326677">"提醒"</string>
     <string name="zen_mode_events" msgid="5784076928339534984">"允许活动"</string>
     <string name="zen_mode_bypassing_apps" msgid="3080739479028713449">"允许应用覆盖"</string>
-    <string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"应用例外情况"</string>
+    <string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"例外应用"</string>
     <plurals name="zen_mode_bypassing_apps_subtext" formatted="false" msgid="8723144434730871572">
       <item quantity="other">有 <xliff:g id="NUMBER">%1$d</xliff:g> 个应用的通知可以覆盖“勿扰”设置</item>
       <item quantity="one">有 1 个应用的通知可以覆盖“勿扰”设置</item>
@@ -3515,7 +3520,7 @@
     <string name="zen_mode_starred_callers" msgid="1317376207713013472">"已加星标的联系人"</string>
     <string name="zen_mode_repeat_callers" msgid="1435309867554692340">"重复来电者"</string>
     <string name="zen_mode_repeat_callers_list" msgid="2750270907597457279">"重复来电者"</string>
-    <string name="zen_mode_repeat_callers_title" msgid="7192952181541813487">"允许显示重复来电者"</string>
+    <string name="zen_mode_repeat_callers_title" msgid="7192952181541813487">"不屏蔽重复来电者"</string>
     <string name="zen_mode_calls_summary_one" msgid="8327371053236689649">"允许<xliff:g id="CALLER_TYPE">%1$s</xliff:g>的来电"</string>
     <string name="zen_mode_calls_summary_two" msgid="9017678770532673578">"允许下列对象来电:<xliff:g id="CALLER_TYPE">%1$s</xliff:g>和<xliff:g id="CALLERT_TPYE">%2$s</xliff:g>"</string>
     <string name="zen_mode_repeat_callers_summary" msgid="1752513516040525545">"如果同一个人在 <xliff:g id="MINUTES">%d</xliff:g> 分钟内第二次来电"</string>
@@ -3589,7 +3594,7 @@
     <string name="app_launch_open_domain_urls_summary" msgid="6803029846855502366">"无需询问即可打开"</string>
     <string name="app_launch_supported_domain_urls_title" msgid="503976327533974142">"支持的链接"</string>
     <string name="app_launch_other_defaults_title" msgid="2986685757258232543">"其他默认设置"</string>
-    <string name="storage_summary_format" msgid="2166430500147022935">"<xliff:g id="STORAGE_TYPE">%2$s</xliff:g>已使用 <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+    <string name="storage_summary_format" msgid="2166430500147022935">"已使用 <xliff:g id="SIZE">%1$s</xliff:g> <xliff:g id="STORAGE_TYPE">%2$s</xliff:g>"</string>
     <string name="storage_type_internal" msgid="4434212376539293892">"内部存储空间"</string>
     <string name="storage_type_external" msgid="8827468573685648108">"外部存储空间"</string>
     <string name="data_summary_format" msgid="5022135392347814271">"自 <xliff:g id="DATE">%2$s</xliff:g>以来已使用 <xliff:g id="SIZE">%1$s</xliff:g>"</string>
@@ -3901,9 +3906,9 @@
     <string name="condition_device_muted_summary" msgid="3101055117680109021">"通话和通知"</string>
     <string name="condition_device_vibrate_title" msgid="5712659354868872338">"仅振动"</string>
     <string name="condition_device_vibrate_summary" msgid="9073880731894828604">"通话和通知"</string>
-    <string name="night_display_suggestion_title" msgid="4222839610992282188">"设置“夜间模式”时间安排"</string>
+    <string name="night_display_suggestion_title" msgid="4222839610992282188">"设置“护眼模式”时间表"</string>
     <string name="night_display_suggestion_summary" msgid="1754361016383576916">"每晚自动调节屏幕色调"</string>
-    <string name="condition_night_display_title" msgid="9171491784857160135">"“夜间模式”已开启"</string>
+    <string name="condition_night_display_title" msgid="9171491784857160135">"“护眼模式”已开启"</string>
     <string name="condition_night_display_summary" msgid="7885776986937527558">"已将屏幕调为琥珀色"</string>
     <string name="condition_grayscale_title" msgid="1226351649203551299">"灰度模式"</string>
     <string name="condition_grayscale_summary" msgid="749172886527349546">"仅以灰色显示"</string>
@@ -4434,7 +4439,7 @@
     <string name="cdma_subscription_summary" msgid="2298861419202726628">"在 RUIM/SIM 和 NV 之间切换"</string>
     <string name="cdma_subscription_dialogtitle" msgid="232485231569225126">"订阅"</string>
     <string name="register_automatically" msgid="1858081641661493109">"自动注册…"</string>
-    <string name="roaming_alert_title" msgid="1849237823113454475">"要允许数据网络漫游吗?"</string>
+    <string name="roaming_alert_title" msgid="1849237823113454475">"允许数据漫游?"</string>
     <string name="roaming_check_price_warning" msgid="5883499714594419439">"请与您的网络服务提供商联系以了解定价。"</string>
     <string name="mobile_data_usage_title" msgid="2376358672434990037">"应用的流量使用情况"</string>
     <string name="mobile_network_mode_error" msgid="6818434186286086554">"无效的网络模式<xliff:g id="NETWORKMODEID">%1$d</xliff:g>。忽略。"</string>
@@ -4469,7 +4474,7 @@
     <string name="privacy_dashboard_summary" msgid="7916431309860824945">"权限、帐号活动、个人数据"</string>
     <string name="contextual_card_dismiss_remove" msgid="1750420285615827309">"移除"</string>
     <string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"保留"</string>
-    <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"要移除这项推荐内容吗?"</string>
+    <string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"要移除这项建议吗?"</string>
     <string name="contextual_card_removed_message" msgid="4047307820743366876">"已移除建议"</string>
     <string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"撤消"</string>
     <string name="low_storage_summary" msgid="4562224870189133400">"存储空间不足。已使用 <xliff:g id="PERCENTAGE">%1$s</xliff:g>,还剩 <xliff:g id="FREE_SPACE">%2$s</xliff:g>"</string>
diff --git a/tests/CarDeveloperOptions/res/values-zh-rHK/arrays.xml b/tests/CarDeveloperOptions/res/values-zh-rHK/arrays.xml
index b91281c..bf81e93 100644
--- a/tests/CarDeveloperOptions/res/values-zh-rHK/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-zh-rHK/arrays.xml
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"永不允許"</item>
     <item msgid="8184570120217958741">"永遠允許"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"正常"</item>
+    <item msgid="5101233285497327432">"中等"</item>
+    <item msgid="1555861583162930714">"低"</item>
+    <item msgid="1719683776264798117">"嚴重不足"</item>
+    <item msgid="1567326459340152525">"不明"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"正常"</item>
+    <item msgid="6107138933849816768">"中"</item>
+    <item msgid="182695359839047859">"低"</item>
+    <item msgid="8577246509202964244">"嚴重不足"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"持續"</item>
     <item msgid="167418068739176448">"重大活動"</item>
@@ -463,8 +473,8 @@
   </string-array>
   <string-array name="wifi_metered_entries">
     <item msgid="4329206416008519163">"自動偵測"</item>
-    <item msgid="773943026484148895">"設定為按用量收費"</item>
-    <item msgid="1008268820118852416">"設定為非按用量收費"</item>
+    <item msgid="773943026484148895">"視為按用量收費"</item>
+    <item msgid="1008268820118852416">"視為非按用量收費"</item>
   </string-array>
   <string-array name="wifi_privacy_entries">
     <item msgid="6545683814310036454">"使用隨機 MAC (預設)"</item>
diff --git a/tests/CarDeveloperOptions/res/values-zh-rHK/config.xml b/tests/CarDeveloperOptions/res/values-zh-rHK/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-zh-rHK/config.xml
+++ b/tests/CarDeveloperOptions/res/values-zh-rHK/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-zh-rHK/strings.xml b/tests/CarDeveloperOptions/res/values-zh-rHK/strings.xml
index 96b8fef..91a5f32 100644
--- a/tests/CarDeveloperOptions/res/values-zh-rHK/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-zh-rHK/strings.xml
@@ -23,8 +23,8 @@
     <string name="deny" msgid="3998166389989144025">"拒絕"</string>
     <string name="device_info_default" msgid="1548919563979154348">"未知"</string>
     <plurals name="show_dev_countdown" formatted="false" msgid="3953785659137161981">
-      <item quantity="other">您只需完成 <xliff:g id="STEP_COUNT_1">%1$d</xliff:g> 個步驟,即可成為開發人員。</item>
-      <item quantity="one">您只需完成 <xliff:g id="STEP_COUNT_0">%1$d</xliff:g> 個步驟,即可成為開發人員。</item>
+      <item quantity="other">尚餘 <xliff:g id="STEP_COUNT_1">%1$d</xliff:g> 個步驟,您就可以成為開發人員。</item>
+      <item quantity="one">尚餘 <xliff:g id="STEP_COUNT_0">%1$d</xliff:g> 個步驟,您就可以成為開發人員。</item>
     </plurals>
     <string name="show_dev_on" msgid="9075712234786224065">"您現已成為開發人員!"</string>
     <string name="show_dev_already" msgid="7665948832405148689">"不需要了,您已經是開發人員。"</string>
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"縮小或放大畫面上的文字。"</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"縮小"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"放大"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"範例文字"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"《綠野仙蹤》"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"第 11 章:奧茲國的奇妙翡翠城"</string>
@@ -276,7 +275,7 @@
     <string name="dlg_remove_locales_message" msgid="5179370688876343176">"文字將以其他語言顯示。"</string>
     <string name="dlg_remove_locales_error_title" msgid="9090578326002163975">"無法移除所有語言"</string>
     <string name="dlg_remove_locales_error_message" msgid="6799897638891903618">"請至少保留一種偏好語言"</string>
-    <string name="locale_not_translated" msgid="7943669576006420058">"部分應用程式可能不提供支援"</string>
+    <string name="locale_not_translated" msgid="7943669576006420058">"部分應用程式可能不支援"</string>
     <string name="action_drag_label_move_up" msgid="2074064283966078352">"向上移"</string>
     <string name="action_drag_label_move_down" msgid="1367989732445492291">"向下移"</string>
     <string name="action_drag_label_move_top" msgid="2033098833739345957">"移至頂端"</string>
@@ -426,7 +425,7 @@
     <string name="security_settings_face_settings_require_confirmation_details" msgid="8740564864091803429">"在應用程式內驗證時,每次都要確認"</string>
     <string name="security_settings_face_settings_remove_face_data" msgid="2821359954483136239">"移除臉容資料"</string>
     <string name="security_settings_face_settings_footer" msgid="4627175759990550715">"您的臉容可以用來解鎖裝置和存取應用程式。"<annotation id="url">"瞭解詳情"</annotation></string>
-    <string name="security_settings_face_settings_remove_dialog_title" msgid="5675319895815271094">"是否刪除臉容資料?"</string>
+    <string name="security_settings_face_settings_remove_dialog_title" msgid="5675319895815271094">"是否刪除臉孔資料?"</string>
     <string name="security_settings_face_settings_remove_dialog_details" msgid="3754494807169276107">"臉孔解鎖功能記錄的資料將以安全方式永久刪除。移除後,您將需使用 PIN、圖案或密碼解鎖手機、登入應用程式及確認付款。"</string>
     <string name="security_settings_fingerprint_preference_title" msgid="4177132225930582928">"指紋"</string>
     <string name="fingerprint_manage_category_title" msgid="1463406696801542090">"管理指紋"</string>
@@ -448,7 +447,7 @@
     <string name="security_settings_fingerprint_enroll_introduction_cancel_setup" msgid="756928427429893070">"略過"</string>
     <string name="security_settings_fingerprint_enroll_introduction_continue_setup" msgid="4125977169169671144">"繼續"</string>
     <string name="setup_fingerprint_enroll_skip_title" msgid="763018850721691594">"要略過指紋設定程序嗎?"</string>
-    <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"指紋設定程序只需一至兩分鐘。如果您略過此程序,稍後可以在設定中自行新增您的指紋。"</string>
+    <string name="setup_fingerprint_enroll_skip_after_adding_lock_text" msgid="8849928362049018680">"指紋設定程序只需一至兩分鐘。如略過此步驟,您可於稍後在設定中加入指紋。"</string>
     <string name="lock_screen_intro_skip_title" msgid="5307431665496346914">"要略過螢幕鎖定設定程序嗎?"</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="tablet" msgid="7553945981266845264">"系統將不會開啟裝置保護功能。如果您的平板電腦遺失、被盜或被重設,您將無法防止他人使用此平板電腦。"</string>
     <string name="lock_screen_intro_skip_dialog_text_frp" product="device" msgid="1378243257238015603">"系統將不會開啟裝置保護功能。如果您的裝置遺失、被盜或被重設,您將無法防止他人使用此裝置。"</string>
@@ -467,7 +466,7 @@
     <string name="security_settings_fingerprint_enroll_dialog_ok" msgid="3428927518029038956">"確定"</string>
     <string name="security_settings_fingerprint_enroll_dialog_delete" msgid="4312297515772004580">"刪除"</string>
     <string name="security_settings_fingerprint_enroll_start_title" msgid="1346287821809975177">"輕觸感應器"</string>
-    <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"手指放在感應器上,感到震動時移開"</string>
+    <string name="security_settings_fingerprint_enroll_start_message" msgid="750040530347336376">"請將手指放在感應器上,並在感到震動時移開"</string>
     <string name="security_settings_fingerprint_enroll_repeat_title" msgid="1764145704166303842">"移開手指,然後再次輕觸"</string>
     <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"手指重覆按壓,記錄指紋各個部分"</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"已加入指紋"</string>
@@ -489,7 +488,7 @@
     <string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"糟糕,這不是感應器"</string>
     <string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"請使用食指輕觸位於手機背面的感應器。"</string>
     <string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"尚未完成註冊"</string>
-    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"已達到指紋註冊次數上限,請重試。"</string>
+    <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"註冊指紋過程逾時,請重新嘗試。"</string>
     <string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"無法註冊指紋,請重試或使用另一隻手指。"</string>
     <string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"新增其他"</string>
     <string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"下一步"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">必須少於 <xliff:g id="NUMBER_1">%d</xliff:g> 個數字</item>
       <item quantity="one">必須少於 <xliff:g id="NUMBER_0">%d</xliff:g> 個數字</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"只可包含數字 0-9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"裝置管理員不允許使用最近用過的 PIN 碼"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"您的 IT 管理員已禁止使用常用的 PIN 碼,請嘗試輸入另一個 PIN 碼。"</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"您不可使用無效字元"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">必須包含最少 <xliff:g id="COUNT">%d</xliff:g> 個非字母字元</item>
       <item quantity="one">必須包含最少 1 個非字母字元</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">必須包含至少 <xliff:g id="COUNT">%d</xliff:g> 個非數字字元</item>
+      <item quantity="one">必須包含至少 1 個非數字字元</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"裝置管理員不允許使用最近用過的密碼"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"您的 IT 管理員已禁止使用常用的密碼,請嘗試輸入另一個密碼。"</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"不可使用依遞增或遞減順序排列或重複的連續數字"</string>
@@ -893,7 +895,7 @@
     <string name="wifi_setup_wps" msgid="6730131677695521321">"自動設定 (WPS)"</string>
     <string name="wifi_settings_scanning_required_title" msgid="3593457187659922490">"要開啟 Wi-Fi 掃瞄功能嗎?"</string>
     <string name="wifi_settings_scanning_required_summary" msgid="7469610959462708782">"您必須先開啟 Wi-Fi 掃瞄功能,才能自動開啟 Wi-Fi。"</string>
-    <string name="wifi_settings_scanning_required_info" msgid="5913535073390607386">"Wi-Fi 掃瞄功能允許應用程式和服務隨時掃瞄 Wi-Fi 網絡 (即使 Wi-Fi 已關閉)。此功能可用作改善行動定位功能和服務"</string>
+    <string name="wifi_settings_scanning_required_info" msgid="5913535073390607386">"Wi-Fi 掃瞄功能允許應用程式和服務隨時掃瞄 Wi-Fi 網絡 (即使 Wi-Fi 已關閉)。此功能可用於改善根據位置運作的功能和服務等等。"</string>
     <string name="wifi_settings_scanning_required_turn_on" msgid="4327570180594277049">"開啟"</string>
     <string name="wifi_settings_scanning_required_enabled" msgid="3336102100425307040">"已開啟 Wi‑Fi 掃瞄功能"</string>
     <string name="wifi_show_advanced" msgid="8199779277168030597">"進階選項"</string>
@@ -933,13 +935,13 @@
     <string name="wifi_privacy_settings" msgid="4462092795794247809">"私隱"</string>
     <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"隨機化處理 MAC"</string>
     <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"新增裝置"</string>
-    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"相機對準以下二維條碼,即可將裝置新增至「<xliff:g id="SSID">%1$s</xliff:g>」"</string>
+    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"將下方方框對準二維條碼,即可將裝置加到「<xliff:g id="SSID">%1$s</xliff:g>」"</string>
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"掃瞄二維條碼"</string>
     <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"將二維條碼置於下方中間,即可連接至「<xliff:g id="SSID">%1$s</xliff:g>」"</string>
     <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"掃瞄二維條碼以加入 Wi-Fi"</string>
     <string name="wifi_dpp_share_wifi" msgid="1724161216219646284">"分享 Wi‑Fi"</string>
     <string name="wifi_dpp_scan_qr_code_with_another_device" msgid="4357387474444884759">"掃瞄此二維條碼即可連線至「<xliff:g id="SSID">%1$s</xliff:g>」並分享密碼"</string>
-    <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"掃描此二維條碼即可連線至「<xliff:g id="SSID">%1$s</xliff:g>」"</string>
+    <string name="wifi_dpp_scan_open_network_qr_code_with_another_device" msgid="572011882416511818">"掃描此二維條碼,即可連接「<xliff:g id="SSID">%1$s</xliff:g>」"</string>
     <string name="wifi_dpp_could_not_detect_valid_qr_code" msgid="27667719861826438">"無法讀取二維條碼。重新將二維條碼放在正中,然後再試一次"</string>
     <string name="wifi_dpp_failure_authentication_or_configuration" msgid="9142051662156233679">"請再試一次。如果仍有問題,請聯絡裝置製造商"</string>
     <string name="wifi_dpp_failure_not_compatible" msgid="4320027179973678283">"發生問題"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"流動網絡"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"如果無法使用 Wi‑Fi,請使用流動網絡"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"如果無法使用流動網絡,請使用 Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"使用 Wi-Fi 通話。如果 Wi‑Fi 斷線,通話便會結束。"</string>
@@ -2313,7 +2318,7 @@
     <string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"此應用程式會在背景使用電量。您的電池電量可能會比預期更快耗盡。"</string>
     <string name="battery_tip_unrestrict_app_dialog_ok" msgid="9154938931448151479">"移除"</string>
     <string name="battery_tip_unrestrict_app_dialog_cancel" msgid="7331148618292397166">"取消"</string>
-    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"您的應用程式目前的耗電量正常。如果應用程式耗電過多,手機會建議您進行一些操作。\n\n如果電量不足,您隨時都可以開啟「省電模式」。"</string>
+    <string name="battery_tip_dialog_summary_message" product="default" msgid="7244950433272770280">"您的應用程式目前的耗電量正常。如果應用程式耗電過多,手機會建議您執行一些操作。\n\n如果電量不足,您隨時都可以開啟「省電模式」。"</string>
     <string name="battery_tip_dialog_summary_message" product="tablet" msgid="1721081030632329647">"您的應用程式目前的耗電量正常。如果應用程式耗電過多,平板電腦將會為您提供操作建議。\n\n如果電量較低,您可以隨時開啟省電模式。"</string>
     <string name="battery_tip_dialog_summary_message" product="device" msgid="146872407040848465">"您的應用程式目前的耗電量正常。如果應用程式耗電過多,裝置將會為您提供操作建議。\n\n如果電量較低,您可以隨時開啟省電模式。"</string>
     <string name="smart_battery_manager_title" msgid="5744035036663849515">"電池管理工具"</string>
@@ -2449,7 +2454,7 @@
     <string name="battery_saver_auto_percentage" msgid="5791982309331921556">"根據百分比"</string>
     <string name="battery_saver_auto_routine_summary" msgid="9182044424547482889">"如果電量很可能在下次慣常充電時間之前耗盡,「省電模式」就會自動開啟"</string>
     <string name="battery_saver_auto_percentage_summary" msgid="2036128588460338677">"將會在電量剩餘 <xliff:g id="PERCENT">%1$s</xliff:g> 時開啟"</string>
-    <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"設定時間"</string>
+    <string name="battery_saver_schedule_settings_title" msgid="574233428557678128">"設定時間表"</string>
     <string name="battery_saver_sticky_title_new" msgid="5328707297110866082">"充滿電後關閉"</string>
     <string name="battery_saver_sticky_description_new" product="default" msgid="3406582427270935879">"當您的手機電量達到 <xliff:g id="PERCENT">%1$s</xliff:g> 時,省電模式會關閉"</string>
     <string name="battery_saver_sticky_description_new" product="tablet" msgid="3284967694001857194">"當您的平板電腦電量達到 <xliff:g id="PERCENT">%1$s</xliff:g> 時,省電模式會關閉"</string>
@@ -2843,7 +2848,7 @@
       <item quantity="other">檢查憑證</item>
       <item quantity="one">檢查憑證</item>
     </plurals>
-    <string name="user_settings_title" msgid="7917598650933179545">"多個使用者"</string>
+    <string name="user_settings_title" msgid="7917598650933179545">"複數使用者"</string>
     <string name="user_settings_footer_text" product="device" msgid="4573858247439190545">"新增使用者即可分享您的裝置。每位使用者在您的裝置上都有個人空間,以自訂主畫面、帳戶、應用程式、設定等。"</string>
     <string name="user_settings_footer_text" product="tablet" msgid="780018221428132918">"新增使用者即可分享您的平板電腦。每位使用者在您的平板電腦上都有個人空間,以自訂主畫面、帳戶、應用程式、設定等。"</string>
     <string name="user_settings_footer_text" product="default" msgid="1470859614968237491">"您可以新增使用者來分享這部手機。每位使用者在您的手機上都有個人空間,可以自訂主畫面、帳戶、應用程式、設定等等。"</string>
@@ -2878,7 +2883,7 @@
     <string name="user_cannot_add_accounts_message" msgid="5993561303748749097">"限制存取的個人檔案無法新增帳戶"</string>
     <string name="user_remove_user_menu" msgid="3505139157217459864">"將 <xliff:g id="USER_NAME">%1$s</xliff:g> 從這部裝置中刪除"</string>
     <string name="user_lockscreen_settings" msgid="3820813814848394568">"上鎖畫面設定"</string>
-    <string name="user_add_on_lockscreen_menu" msgid="5211604808199585774">"在上鎖畫面上新增使用者"</string>
+    <string name="user_add_on_lockscreen_menu" msgid="5211604808199585774">"在上鎖畫面加入使用者"</string>
     <string name="user_new_user_name" msgid="3880395219777884838">"新使用者"</string>
     <string name="user_new_profile_name" msgid="3074939718101489937">"新個人檔案"</string>
     <string name="user_confirm_remove_self_title" msgid="6739480453680217543">"您要刪除自己嗎?"</string>
@@ -2917,7 +2922,7 @@
     <string name="nfc_payment_default_not_set" msgid="955804193510335338">"未設定"</string>
     <string name="nfc_payment_app_and_desc" msgid="102312684211458190">"<xliff:g id="APP">%1$s</xliff:g> - <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="nfc_payment_use_default" msgid="3098724195746409476">"使用預設應用程式"</string>
-    <string name="nfc_payment_favor_default" msgid="7555356982142464260">"永遠"</string>
+    <string name="nfc_payment_favor_default" msgid="7555356982142464260">"一律使用"</string>
     <string name="nfc_payment_favor_open" msgid="3739055715000436749">"其他付款應用程式已開啟除外"</string>
     <string name="nfc_payment_pay_with" msgid="8412558374792061266">"於 Tap &amp; Pay 終端機使用的付款方式:"</string>
     <string name="nfc_how_it_works_title" msgid="6531433737926327904">"在收款機付款"</string>
@@ -3173,17 +3178,17 @@
     <string name="zen_mode_behavior_total_silence" msgid="371498357539257671">"完全靜音"</string>
     <string name="zen_mode_behavior_no_sound_except" msgid="8894465423364103198">"不發出音效 (<xliff:g id="CATEGORIES">%1$s</xliff:g>除外)"</string>
     <string name="zen_mode_behavior_alarms_only" msgid="8406622989983047562">"不發出音效 (鬧鐘和媒體除外)"</string>
-    <string name="zen_mode_automation_settings_title" msgid="3916960043054489008">"預定時間"</string>
+    <string name="zen_mode_automation_settings_title" msgid="3916960043054489008">"時間表"</string>
     <string name="zen_mode_delete_automatic_rules" msgid="2455264581527305755">"刪除日程表"</string>
     <string name="zen_mode_schedule_delete" msgid="7786092652527516740">"刪除"</string>
     <string name="zen_mode_rule_name_edit" msgid="5479435215341745578">"編輯"</string>
-    <string name="zen_mode_automation_settings_page_title" msgid="3001783354881078983">"預定時間"</string>
+    <string name="zen_mode_automation_settings_page_title" msgid="3001783354881078983">"時間表"</string>
     <string name="zen_mode_automatic_rule_settings_page_title" msgid="5272888746413504692">"預定時間"</string>
     <string name="zen_mode_schedule_category_title" msgid="1936785755444711221">"預定時間"</string>
     <string name="zen_mode_automation_suggestion_title" msgid="4921779962633710347">"在特定時間將手機設為靜音"</string>
     <string name="zen_mode_automation_suggestion_summary" msgid="2709837472884371037">"設定「請勿騷擾」規則"</string>
     <string name="zen_mode_schedule_title" msgid="5275268813192802631">"預定時間"</string>
-    <string name="zen_mode_use_automatic_rule" msgid="446326253915861824">"使用日程表"</string>
+    <string name="zen_mode_use_automatic_rule" msgid="446326253915861824">"使用時間表"</string>
     <string name="zen_mode_option_important_interruptions" msgid="5173944276846940149">"只限優先"</string>
     <string name="zen_mode_option_alarms" msgid="4843278125235203076">"只限鬧鐘"</string>
     <string name="zen_mode_option_no_interruptions" msgid="4723700274519260852">"完全靜音"</string>
@@ -3418,7 +3423,7 @@
     <string name="notification_content_block_summary" msgid="2743896875255591743">"永不在通知欄或周邊裝置上顯示通知"</string>
     <string name="notification_badge_title" msgid="8989086619255666442">"允許通知圓點"</string>
     <string name="notification_channel_badge_title" msgid="8228215248332054612">"顯示通知圓點"</string>
-    <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"蓋過「請勿騷擾」設定"</string>
+    <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"忽略「請勿騷擾」設定"</string>
     <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"「請勿騷擾」模式開啟時繼續接收這些通知"</string>
     <string name="app_notification_visibility_override_title" msgid="2349335170165637672">"在上鎖畫面上"</string>
     <string name="app_notification_row_banned" msgid="2079325338122151677">"已封鎖"</string>
@@ -3431,14 +3436,14 @@
     <string name="notification_channel_sound_title" msgid="7635366839003304745">"音效"</string>
     <string name="zen_mode_rule_delete_button" msgid="6763486487220471193">"刪除"</string>
     <string name="zen_mode_rule_rename_button" msgid="1428130397306726792">"重新命名"</string>
-    <string name="zen_mode_rule_name" msgid="8583652780885724670">"日程表名稱"</string>
+    <string name="zen_mode_rule_name" msgid="8583652780885724670">"時間表名稱"</string>
     <string name="zen_mode_rule_name_hint" msgid="6569877315858105901">"輸入日程表名稱"</string>
     <string name="zen_mode_rule_name_warning" msgid="4773465816059587512">"日程表名稱已使用"</string>
     <string name="zen_mode_add_rule" msgid="7200004557856029928">"加入更多"</string>
     <string name="zen_mode_add_event_rule" msgid="1398181272397489506">"加入日程表 (活動)"</string>
     <string name="zen_mode_add_time_rule" msgid="5999467757140524729">"加入日程表 (時間)"</string>
     <string name="zen_mode_delete_rule" msgid="2292933835997203801">"刪除日程表"</string>
-    <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"選擇日程表類型"</string>
+    <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"選擇時間表類型"</string>
     <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"要刪除規則「<xliff:g id="RULE">%1$s</xliff:g>」嗎?"</string>
     <string name="zen_mode_delete_rule_button" msgid="611058106279881991">"刪除"</string>
     <string name="zen_mode_rule_type_unknown" msgid="2819480113355191421">"未知"</string>
@@ -3468,7 +3473,7 @@
     <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"鬧鐘響起時,系統會關閉日程表"</string>
     <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"「請勿騷擾」行為"</string>
     <string name="zen_mode_custom_behavior_summary_default" msgid="3509865340195397447">"使用預設設定"</string>
-    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"為此日程表建立自訂設定"</string>
+    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"為此時間表建立自訂設定"</string>
     <string name="zen_mode_custom_behavior_category_title" msgid="7451686525113262087">"時段:「<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>」"</string>
     <string name="summary_divider_text" msgid="4780683204694442666">"、 "</string>
     <string name="summary_range_symbol_combination" msgid="6038631664844488406">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
@@ -3507,8 +3512,8 @@
     <string name="zen_mode_bypassing_apps" msgid="3080739479028713449">"允許應用程式取代「請勿騷擾」"</string>
     <string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"應用程式例外情況"</string>
     <plurals name="zen_mode_bypassing_apps_subtext" formatted="false" msgid="8723144434730871572">
-      <item quantity="other"><xliff:g id="NUMBER">%1$d</xliff:g> 個應用程式的通知可蓋過「請勿騷擾」設定</item>
-      <item quantity="one">1 個應用程式的通知可蓋過「請勿騷擾」設定</item>
+      <item quantity="other"><xliff:g id="NUMBER">%1$d</xliff:g> 個應用程式的通知可忽略「請勿騷擾」設定</item>
+      <item quantity="one">1 個應用程式的通知可忽略「請勿騷擾」設定</item>
     </plurals>
     <string name="zen_mode_events_list" msgid="8578102701815684873">"活動"</string>
     <string name="zen_mode_all_callers" msgid="4455039040077343838">"任何人"</string>
@@ -3829,7 +3834,7 @@
     <string name="screen_zoom_title" msgid="164369086350486104">"顯示大小"</string>
     <string name="screen_zoom_short_summary" msgid="5508079362742276703">"放大或縮小畫面上的項目"</string>
     <string name="screen_zoom_keywords" msgid="8358462497896524092">"顯示密度, 螢幕縮放, 比例, 按比例"</string>
-    <string name="screen_zoom_summary" msgid="5294003755961312560">"縮小或放大畫面上的項目。畫面上部分應用程式可能會移位。"</string>
+    <string name="screen_zoom_summary" msgid="5294003755961312560">"縮小或放大畫面上的項目。畫面上有部分應用程式可能會移位。"</string>
     <string name="screen_zoom_preview_title" msgid="2924312934036753091">"預覽"</string>
     <string name="screen_zoom_make_smaller_desc" msgid="1374501139722916729">"縮小"</string>
     <string name="screen_zoom_make_larger_desc" msgid="5306684807895846141">"放大"</string>
@@ -3950,7 +3955,7 @@
       <item quantity="one">1 個限制</item>
     </plurals>
     <string name="operator_warning" msgid="4676042739221117031">"流動網絡供應商的數據計算方式可能與裝置有所不同"</string>
-    <string name="data_used_template" msgid="761605393453849477">"已用 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="data_used_template" msgid="761605393453849477">"已使用 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="set_data_warning" msgid="8115980184415563941">"設定數據用量警告"</string>
     <string name="data_warning" msgid="2699207195535036240">"數據用量警告"</string>
     <string name="data_warning_footnote" msgid="965724845580257305">"您的裝置會自行計算數據用量警告和數據用量上限。這可能會與流動網絡供應商的計算結果不同。"</string>
@@ -3982,7 +3987,7 @@
     <string name="launch_mdp_app_text" msgid="9186559496664208252">"查看數據計劃"</string>
     <string name="launch_wifi_text" msgid="317820210431682605">"查看詳情"</string>
     <string name="data_saver_title" msgid="7903308134514179256">"數據節省模式"</string>
-    <string name="unrestricted_data_saver" msgid="9139401849550738720">"無限制數據用量"</string>
+    <string name="unrestricted_data_saver" msgid="9139401849550738720">"不限制數據用量"</string>
     <string name="restrict_background_blacklisted" msgid="7158991683849067124">"背景數據已關閉"</string>
     <string name="data_saver_on" msgid="7281809065420480881">"開啟"</string>
     <string name="data_saver_off" msgid="7439439787358504018">"關閉"</string>
@@ -4116,18 +4121,18 @@
     <string name="swipe_up_to_switch_apps_summary" msgid="4644068184114154787">"如要切換應用程式,請在主按鈕上向上滑動。再次向上滑動即可查看所有應用程式。此操作適用於任何畫面。您的畫面右下方將不再有 [概覽] 按鈕。"</string>
     <string name="swipe_up_to_switch_apps_suggestion_title" msgid="7641846365137536128">"試按新版主按鈕"</string>
     <string name="swipe_up_to_switch_apps_suggestion_summary" msgid="7338653224520387852">"啟用新手勢即可切換應用程式"</string>
-    <string name="ambient_display_title" product="default" msgid="6785677099744344088">"輕按兩下以查看手機"</string>
+    <string name="ambient_display_title" product="default" msgid="6785677099744344088">"輕按兩下顯示畫面"</string>
     <string name="ambient_display_title" product="tablet" msgid="1106285490888683613">"輕按兩下即可查看平板電腦"</string>
     <string name="ambient_display_title" product="device" msgid="5064644474876041478">"輕按兩下即可查看裝置"</string>
     <string name="ambient_display_summary" msgid="4882910328216411109">"輕按螢幕兩下即可查看時間、通知和其他資訊。"</string>
-    <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"拿起即可查看手機"</string>
+    <string name="ambient_display_pickup_title" product="default" msgid="7141652156907066938">"拿起手機顯示畫面"</string>
     <string name="ambient_display_pickup_title" product="tablet" msgid="1555456400210301959">"拿起即可查看平板電腦"</string>
     <string name="ambient_display_pickup_title" product="device" msgid="2480126522988135037">"拿起即可查看裝置"</string>
     <string name="ambient_display_wake_screen_title" msgid="3376988352851077102">"喚醒顯示屏"</string>
     <string name="ambient_display_pickup_summary" product="default" msgid="8798915340594367449">"拿起您的手機即可查看時間、通知和其他資訊。"</string>
     <string name="ambient_display_pickup_summary" product="tablet" msgid="1077745287100012928">"拿起您的平板電腦即可查看時間、通知和其他資訊。"</string>
     <string name="ambient_display_pickup_summary" product="device" msgid="404199660076598026">"拿起您的裝置即可查看時間、通知和其他資訊。"</string>
-    <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"輕按即可查看手機"</string>
+    <string name="ambient_display_tap_screen_title" product="default" msgid="2784322628239960695">"輕按一下顯示畫面"</string>
     <string name="ambient_display_tap_screen_title" product="tablet" msgid="6434521782016864148">"輕按即可查看平板電腦"</string>
     <string name="ambient_display_tap_screen_title" product="device" msgid="4396793721852647356">"輕按即可查看裝置"</string>
     <string name="ambient_display_tap_screen_summary" msgid="7869039870571925213">"輕按螢幕即可查看時間、通知和其他資訊。"</string>
diff --git a/tests/CarDeveloperOptions/res/values-zh-rTW/arrays.xml b/tests/CarDeveloperOptions/res/values-zh-rTW/arrays.xml
index 7901b7d..65c98c5 100644
--- a/tests/CarDeveloperOptions/res/values-zh-rTW/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-zh-rTW/arrays.xml
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"一律不允許"</item>
     <item msgid="8184570120217958741">"一律允許"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"一般"</item>
+    <item msgid="5101233285497327432">"略為偏低"</item>
+    <item msgid="1555861583162930714">"低"</item>
+    <item msgid="1719683776264798117">"嚴重不足"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"正常"</item>
+    <item msgid="6107138933849816768">"中"</item>
+    <item msgid="182695359839047859">"低"</item>
+    <item msgid="8577246509202964244">"最高"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"持續"</item>
     <item msgid="167418068739176448">"重大活動"</item>
diff --git a/tests/CarDeveloperOptions/res/values-zh-rTW/config.xml b/tests/CarDeveloperOptions/res/values-zh-rTW/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-zh-rTW/config.xml
+++ b/tests/CarDeveloperOptions/res/values-zh-rTW/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-zh-rTW/strings.xml b/tests/CarDeveloperOptions/res/values-zh-rTW/strings.xml
index b61af3b..1ea9dfb 100644
--- a/tests/CarDeveloperOptions/res/values-zh-rTW/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-zh-rTW/strings.xml
@@ -23,10 +23,10 @@
     <string name="deny" msgid="3998166389989144025">"拒絕"</string>
     <string name="device_info_default" msgid="1548919563979154348">"不明"</string>
     <plurals name="show_dev_countdown" formatted="false" msgid="3953785659137161981">
-      <item quantity="other">你只需完成剩餘的 <xliff:g id="STEP_COUNT_1">%1$d</xliff:g> 個步驟,即可成為開發人員。</item>
-      <item quantity="one">你只需完成剩餘的 <xliff:g id="STEP_COUNT_0">%1$d</xliff:g> 個步驟,即可成為開發人員。</item>
+      <item quantity="other">只要再 <xliff:g id="STEP_COUNT_1">%1$d</xliff:g> 個步驟即可啟用開發人員設定。</item>
+      <item quantity="one">只要再 <xliff:g id="STEP_COUNT_0">%1$d</xliff:g> 個步驟即可啟用開發人員設定。</item>
     </plurals>
-    <string name="show_dev_on" msgid="9075712234786224065">"你現在已成為開發人員!"</string>
+    <string name="show_dev_on" msgid="9075712234786224065">"開發人員設定已啟用!"</string>
     <string name="show_dev_already" msgid="7665948832405148689">"不需要了,你已經是開發人員。"</string>
     <string name="dev_settings_disabled_warning" msgid="3198732189395396721">"請先啟用開發人員選項。"</string>
     <string name="header_category_wireless_networks" msgid="8968405993937795898">"無線與網路"</string>
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"縮小或放大畫面上的文字。"</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"縮小"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"放大"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"範例文字"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"綠野仙蹤"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"第 11 章:奧茲國的翡翠城"</string>
@@ -668,7 +667,6 @@
       <item quantity="other">長度必須少於 <xliff:g id="NUMBER_1">%d</xliff:g> 個數字</item>
       <item quantity="one">長度必須少於 <xliff:g id="NUMBER_0">%d</xliff:g> 個數字</item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"只能包含數字 0 到 9"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"裝置管理員不允許使用最近用過的 PIN"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"你的 IT 管理員已封鎖常見 PIN 碼,請改用其他 PIN 碼。"</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"密碼不得包含無效字元"</string>
@@ -699,6 +697,10 @@
       <item quantity="other">必須包含至少 <xliff:g id="COUNT">%d</xliff:g> 個非字母的字元</item>
       <item quantity="one">必須包含至少 1 個非字母的字元</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="other">至少必須包含 <xliff:g id="COUNT">%d</xliff:g> 個非數值字元</item>
+      <item quantity="one">至少必須包含 1 個非數值字元</item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"裝置管理員不允許使用最近用過的密碼"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"你的 IT 管理員已封鎖常見密碼,請改用其他密碼。"</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"不允許使用依遞增或遞減順序排列或是重複的一串數字"</string>
@@ -893,7 +895,7 @@
     <string name="wifi_setup_wps" msgid="6730131677695521321">"自動設定 (WPS)"</string>
     <string name="wifi_settings_scanning_required_title" msgid="3593457187659922490">"要開啟掃描 Wi-Fi 功能嗎?"</string>
     <string name="wifi_settings_scanning_required_summary" msgid="7469610959462708782">"必須先開啟掃描 Wi-Fi 功能,才能自動開啟 Wi‑Fi。"</string>
-    <string name="wifi_settings_scanning_required_info" msgid="5913535073390607386">"掃描 Wi-Fi 功能可讓應用程式和服務隨時掃描 Wi‑Fi 網路 (即使 Wi‑Fi 功能處於關閉狀態)。這可以用來改善適地性功能和服務。"</string>
+    <string name="wifi_settings_scanning_required_info" msgid="5913535073390607386">"掃描 Wi-Fi 功能可在 Wi‑Fi 關閉時,讓應用程式和服務隨時掃描 Wi‑Fi 網路。此功能可用來改善適地性等功能和服務。"</string>
     <string name="wifi_settings_scanning_required_turn_on" msgid="4327570180594277049">"開啟"</string>
     <string name="wifi_settings_scanning_required_enabled" msgid="3336102100425307040">"已開啟掃描 Wi-Fi 功能"</string>
     <string name="wifi_show_advanced" msgid="8199779277168030597">"進階選項"</string>
@@ -933,7 +935,7 @@
     <string name="wifi_privacy_settings" msgid="4462092795794247809">"隱私權"</string>
     <string name="wifi_privacy_settings_ephemeral_summary" msgid="2411375348287064283">"已隨機化的 MAC"</string>
     <string name="wifi_dpp_add_device_to_network" msgid="8871041525483253430">"新增裝置"</string>
-    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"將 QR 圖碼置於相機正下方,即可將這個裝置新增至「<xliff:g id="SSID">%1$s</xliff:g>」"</string>
+    <string name="wifi_dpp_center_qr_code" msgid="3826108361797476758">"將下面的視窗對準 QR 圖碼,即可將這個裝置新增至「<xliff:g id="SSID">%1$s</xliff:g>」"</string>
     <string name="wifi_dpp_scan_qr_code" msgid="6021600592661235546">"掃描 QR 圖碼"</string>
     <string name="wifi_dpp_scan_qr_code_join_network" msgid="3085162928804379545">"將 QR 圖碼置於相機正下方即可連線到「<xliff:g id="SSID">%1$s</xliff:g>」"</string>
     <string name="wifi_dpp_scan_qr_code_join_unknown_network" msgid="5682308317067290738">"掃描 QR 圖碼即可加入 Wi‑Fi"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"Wi-Fi"</item>
+    <item msgid="2271962426654621656">"行動網路"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"如果無法連上 Wi‑Fi,請使用行動網路"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"如果無法連上行動網路,請使用 Wi‑Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"透過 Wi-Fi 進行通話。如果 Wi‑Fi 連線中斷,通話即會結束。"</string>
@@ -2077,7 +2082,7 @@
     <string name="accessibility_timeout_1min" msgid="5019003178551730551">"1 分鐘"</string>
     <string name="accessibility_timeout_2mins" msgid="4124259290444829477">"2 分鐘"</string>
     <string name="accessibility_content_timeout_preference_title" msgid="5160746882250939464">"可閱讀的時間"</string>
-    <string name="accessibility_control_timeout_preference_title" msgid="2771808346038759474">"操作等待時間"</string>
+    <string name="accessibility_control_timeout_preference_title" msgid="2771808346038759474">"提示顯示時間"</string>
     <string name="accessibility_content_timeout_preference_summary" msgid="853829064617918179">"選擇你需要閱讀的訊息會暫時顯示多久。\n\n只有部分應用程式支援這項設定。"</string>
     <string name="accessibility_control_timeout_preference_summary" msgid="8582212299606932160">"選擇提示你進行操作的訊息會暫時顯示多久。\n\n只有部分應用程式支援這項設定。"</string>
     <string name="accessibility_long_press_timeout_preference_title" msgid="5029685114164868477">"輕觸並按住的延遲時間"</string>
@@ -3728,7 +3733,7 @@
     <string name="usb_use_file_transfers_desc" msgid="6953866660041189580">"將檔案轉移到另一個裝置"</string>
     <string name="usb_use_photo_transfers" msgid="5974236250197451257">"PTP"</string>
     <string name="usb_use_photo_transfers_desc" msgid="2325112887316125320">"如果 MTP 不受支援,則轉移相片或檔案 (PTP)"</string>
-    <string name="usb_use_tethering" msgid="4250626730173163846">"USB 數據連線"</string>
+    <string name="usb_use_tethering" msgid="4250626730173163846">"USB 網路共用"</string>
     <string name="usb_use_MIDI" msgid="4710632870781041401">"MIDI"</string>
     <string name="usb_use_MIDI_desc" msgid="1770966187150010947">"將這個裝置用做 MIDI"</string>
     <string name="usb_use" msgid="8940500223316278632">"USB 用途"</string>
@@ -3748,7 +3753,7 @@
     <string name="usb_summary_photo_transfers" msgid="4743028167400644354">"PTP"</string>
     <string name="usb_summary_MIDI" msgid="5540604166270861247">"MIDI"</string>
     <string name="usb_summary_file_transfers_power" msgid="1684501026426766867">"檔案傳輸和供電"</string>
-    <string name="usb_summary_tether_power" msgid="5684170912136320002">"USB 數據連線和供電"</string>
+    <string name="usb_summary_tether_power" msgid="5684170912136320002">"USB 網路共用和供電"</string>
     <string name="usb_summary_photo_transfers_power" msgid="4424106272137720464">"PTP 和供電"</string>
     <string name="usb_summary_MIDI_power" msgid="7685597621357005180">"MIDI 模式和供電"</string>
     <string name="background_check_pref" msgid="664081406854758392">"背景檢查"</string>
@@ -4095,10 +4100,10 @@
       <item quantity="one">1 秒</item>
     </plurals>
     <string name="automatic_storage_manager_settings" msgid="2403621409625820182">"管理儲存空間"</string>
-    <string name="automatic_storage_manager_text" msgid="4270379105066667493">"儲存空間管理員會將已備份的相片和影片從裝置中移除,藉此釋出儲存空間。"</string>
+    <string name="automatic_storage_manager_text" msgid="4270379105066667493">"儲存空間管理工具會將已備份的相片和影片從裝置中移除,藉此釋出儲存空間。"</string>
     <string name="automatic_storage_manager_days_title" msgid="1783767804707813799">"移除相片和影片"</string>
-    <string name="automatic_storage_manager_preference_title" msgid="4668642150512639466">"儲存空間管理員"</string>
-    <string name="automatic_storage_manager_master_switch_title" msgid="1456978117739582562">"使用儲存空間管理員"</string>
+    <string name="automatic_storage_manager_preference_title" msgid="4668642150512639466">"儲存空間管理工具"</string>
+    <string name="automatic_storage_manager_master_switch_title" msgid="1456978117739582562">"使用儲存空間管理工具"</string>
     <string name="deletion_helper_automatic_title" msgid="4370975149425263205">"自動"</string>
     <string name="deletion_helper_manual_title" msgid="1011785013431162078">"手動"</string>
     <string name="deletion_helper_preference_title" msgid="797270307034242206">"立即釋出空間"</string>
@@ -4149,7 +4154,7 @@
     <string name="web_action_section_title" msgid="5563229447734734662">"免安裝應用程式"</string>
     <string name="instant_apps_settings" msgid="879003203555847537">"免安裝應用程式偏好設定"</string>
     <string name="domain_url_section_title" msgid="206403507921518321">"已安裝的應用程式"</string>
-    <string name="automatic_storage_manager_activation_warning" msgid="2630083316417707308">"你的儲存空間目前是由儲存空間管理員管理"</string>
+    <string name="automatic_storage_manager_activation_warning" msgid="2630083316417707308">"你的儲存空間目前是由儲存空間管理工具管理"</string>
     <string name="account_for_section_header" msgid="5975241715840642563">"<xliff:g id="USER_NAME">%1$s</xliff:g>的帳戶"</string>
     <string name="configure_section_header" msgid="6988981883075615136">"設定"</string>
     <string name="auto_sync_account_title" msgid="2394463123733529506">"自動同步處理資料"</string>
@@ -4259,11 +4264,11 @@
     <string name="default_theme" msgid="5986996377385956138">"預設"</string>
     <string name="show_operator_name_title" msgid="5056163028128447308">"網路名稱"</string>
     <string name="show_operator_name_summary" msgid="6352180285743777497">"在狀態列顯示網路名稱"</string>
-    <string name="storage_manager_indicator" msgid="4255140732848476875">"儲存空間管理員:<xliff:g id="STATUS">^1</xliff:g>"</string>
+    <string name="storage_manager_indicator" msgid="4255140732848476875">"儲存空間管理工具:<xliff:g id="STATUS">^1</xliff:g>"</string>
     <string name="storage_manager_indicator_off" msgid="6404056007102580777">"關閉"</string>
     <string name="storage_manager_indicator_on" msgid="5295306384982062320">"開啟"</string>
     <string name="install_type_instant" msgid="6248487669862821874">"免安裝應用程式"</string>
-    <string name="automatic_storage_manager_deactivation_warning" msgid="7867793739491286374">"要停用儲存空間管理員嗎?"</string>
+    <string name="automatic_storage_manager_deactivation_warning" msgid="7867793739491286374">"要停用儲存空間管理工具嗎?"</string>
     <string name="storage_movies_tv" msgid="7282484273991655296">"影視應用程式"</string>
     <string name="carrier_provisioning" msgid="3309125279191534469">"電信業者佈建資訊"</string>
     <string name="trigger_carrier_provisioning" msgid="6284005970057901477">"觸發電信業者佈建程序"</string>
diff --git a/tests/CarDeveloperOptions/res/values-zu/arrays.xml b/tests/CarDeveloperOptions/res/values-zu/arrays.xml
index 60b6f45..a6000db 100644
--- a/tests/CarDeveloperOptions/res/values-zu/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-zu/arrays.xml
@@ -34,7 +34,7 @@
     <item msgid="772029947136115322">"30 amasekhondi"</item>
     <item msgid="8743663928349474087">"1 iminithi"</item>
     <item msgid="1506508631223164814">"2 amaminithi"</item>
-    <item msgid="8664703938127907662">"5 amaminithi"</item>
+    <item msgid="8664703938127907662">"amaminithi ama-5"</item>
     <item msgid="5827960506924849753">"10 amaminithi"</item>
     <item msgid="6677424950124253938">"30 amaminithi"</item>
   </string-array>
@@ -56,7 +56,7 @@
     <item msgid="227647485917789272">"1 iminithi"</item>
     <item msgid="3367011891231217504">"2 amaminithi"</item>
     <item msgid="4376575879222393045">"5 amaminithi"</item>
-    <item msgid="811192536981678974">"10 amaminithi"</item>
+    <item msgid="811192536981678974">"amaminithi ayi-10"</item>
     <item msgid="7258394417241706272">"30 amaminithi"</item>
   </string-array>
   <string-array name="entries_font_size">
@@ -423,9 +423,19 @@
     <item msgid="7718817231348607934">"Ungavumeli"</item>
     <item msgid="8184570120217958741">"Vumela njalo?"</item>
   </string-array>
-    <!-- no translation found for ram_states:0 (708247372474061274) -->
-    <!-- no translation found for ram_states:4 (1567326459340152525) -->
-    <!-- no translation found for proc_stats_memory_states:3 (8577246509202964244) -->
+  <string-array name="ram_states">
+    <item msgid="708247372474061274">"Ivamile"</item>
+    <item msgid="5101233285497327432">"Maphakathi"</item>
+    <item msgid="1555861583162930714">"Phansi"</item>
+    <item msgid="1719683776264798117">"Bucayi"</item>
+    <item msgid="1567326459340152525">"?"</item>
+  </string-array>
+  <string-array name="proc_stats_memory_states">
+    <item msgid="3474232046138139454">"Okujwayelekile"</item>
+    <item msgid="6107138933849816768">"Maphakathi"</item>
+    <item msgid="182695359839047859">"Phansi"</item>
+    <item msgid="8577246509202964244">"Bucayi"</item>
+  </string-array>
   <string-array name="proc_stats_process_states">
     <item msgid="7560955722349181440">"Qhubekayo"</item>
     <item msgid="167418068739176448">"Umsebenzi ophezulu"</item>
diff --git a/tests/CarDeveloperOptions/res/values-zu/config.xml b/tests/CarDeveloperOptions/res/values-zu/config.xml
index b05e073..04c8bf8 100644
--- a/tests/CarDeveloperOptions/res/values-zu/config.xml
+++ b/tests/CarDeveloperOptions/res/values-zu/config.xml
@@ -17,5 +17,4 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_backup_settings_label" msgid="5230713622702899641"></string>
-    <string name="config_grayscale_settings_intent" msgid="7661066612238245852"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values-zu/strings.xml b/tests/CarDeveloperOptions/res/values-zu/strings.xml
index 6aec398..febfd3c 100644
--- a/tests/CarDeveloperOptions/res/values-zu/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-zu/strings.xml
@@ -83,8 +83,7 @@
     <string name="font_size_summary" msgid="9120023206321191067">"Yenza umbhalo okusikrini ube mncane noma mkhulu."</string>
     <string name="font_size_make_smaller_desc" msgid="5780829318985556969">"Yenza kube kuncane"</string>
     <string name="font_size_make_larger_desc" msgid="2907824418252785875">"Yenza kube kukhulu"</string>
-    <!-- no translation found for font_size_preview_text (360019784926073822) -->
-    <skip />
+    <string name="font_size_preview_text" msgid="360019784926073822">"Servez à ce monsieur une bière et des kiwis."</string>
     <string name="font_size_preview_text_headline" msgid="8038650525913995091">"Isampuli yombhalo"</string>
     <string name="font_size_preview_text_title" msgid="2593520249400910305">"I-The Wonderful Wizard of Oz"</string>
     <string name="font_size_preview_text_subtitle" msgid="6106782964143379331">"Isahluko 11: The Wonderful Emerald City of Oz"</string>
@@ -668,7 +667,6 @@
       <item quantity="one">Kufanele kube amadijithi angaphansi kuka-<xliff:g id="NUMBER_1">%d</xliff:g></item>
       <item quantity="other">Kufanele kube amadijithi angaphansi kuka-<xliff:g id="NUMBER_1">%d</xliff:g></item>
     </plurals>
-    <string name="lockpassword_pin_contains_non_digits" msgid="1501729742023195556">"Kumele iqukathe amadijithi angu-0-9 kuphela"</string>
     <string name="lockpassword_pin_recently_used" msgid="5556148774911741103">"Umlawuli wedivayisi akavumeli ukusebenzisa iphinikhodi yakamuva"</string>
     <string name="lockpassword_pin_blacklisted_by_admin" msgid="2752037810571200697">"Ama-PIN avamile avinjelwe umlawuli wakho we-IT. Zama i-PIN ehlukile."</string>
     <string name="lockpassword_illegal_character" msgid="3577712947676261351">"Lokhu akukwazi ukufana uhlamvu olungavumelekile"</string>
@@ -699,6 +697,10 @@
       <item quantity="one">Kumele iqukathe okungenani okungu-<xliff:g id="COUNT">%d</xliff:g> okungezona izinhlamvu</item>
       <item quantity="other">Kumele iqukathe okungenani okungu-<xliff:g id="COUNT">%d</xliff:g> okungezona izinhlamvu</item>
     </plurals>
+    <plurals name="lockpassword_password_requires_nonnumerical" formatted="false" msgid="6943707011152180150">
+      <item quantity="one">Kumele iqukathe okungenani izinhlamvu ezingasizo izinombolo ezingu-<xliff:g id="COUNT">%d</xliff:g></item>
+      <item quantity="other">Kumele iqukathe okungenani izinhlamvu ezingasizo izinombolo ezingu-<xliff:g id="COUNT">%d</xliff:g></item>
+    </plurals>
     <string name="lockpassword_password_recently_used" msgid="6944729699375087431">"Umlawuli wedivayisi akavumeli ukusebenzisa iphasiwedi yakamuva"</string>
     <string name="lockpassword_password_blacklisted_by_admin" msgid="4988166770148440755">"Amaphasiwedi avamile avinjelwe umlawuli wakho we-IT. Zama iphasiwedi ehlukile."</string>
     <string name="lockpassword_pin_no_sequential_digits" msgid="3902387296149848324">"Ukwenyuka, ukwehla, noma uchungechunge olwehlayo lamadijithi alivunyewe"</string>
@@ -1100,7 +1102,10 @@
     <item msgid="3658897985297386665">"@*android:string/wfc_mode_wifi_preferred_summary"</item>
     <item msgid="4191802193352447215">"@*android:string/wfc_mode_cellular_preferred_summary"</item>
   </string-array>
-    <!-- no translation found for wifi_calling_mode_choices_v2_without_wifi_only:0 (6452246499629557266) -->
+  <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
+    <item msgid="6452246499629557266">"I-Wi-Fi"</item>
+    <item msgid="2271962426654621656">"Iselula"</item>
+  </string-array>
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Uma i-Wi-Fi ingatholakali, sebenzisa inethiwekhi yeselula"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Uma inethiwekhi yeselula ingatholakali, sebenzisa i-Wi-Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Shaya nge-Wi-Fi. Uma i-Wi-Fi ilahleka, ikholi izophela."</string>
@@ -3302,7 +3307,7 @@
     <string name="hide_silent_icons_title" msgid="1070905516921542662">"Fihla izithonjana ezithulile zesimo sokwazisa"</string>
     <string name="hide_silent_icons_summary" msgid="2624346914488256888">"Fihla izithonjana zezaziso ezithulile kubha yesimo"</string>
     <string name="notification_badging_title" msgid="6311699476970264712">"Vumela amachashazi esaziso"</string>
-    <string name="notification_bubbles_title" msgid="9196562435741861317">"Amabhamu"</string>
+    <string name="notification_bubbles_title" msgid="9196562435741861317">"Amabhamuza"</string>
     <string name="notification_bubbles_summary" msgid="4624512775901949578">"Finyelela ngokushesha okuqukethwe kohlelo lokusebenza kusuka noma yikuphi usebenzisa izinqamuleli ezintantayo"</string>
     <string name="bubbles_feature_education" msgid="8979109826818881018">"Ezinye izaziso nokunye okuqukethwe kungavela njengamabhamuza kusikrini. Ukuze uvule ibhamuza, lithephe. Ukuze ulicashise, lidonsele phansi kusikrini."</string>
     <string name="bubbles_app_toggle_title" msgid="6401217027603326439">"Amabhamuza"</string>
diff --git a/tests/CarDeveloperOptions/res/values/arrays.xml b/tests/CarDeveloperOptions/res/values/arrays.xml
index 1a36aa8..70c22a4 100644
--- a/tests/CarDeveloperOptions/res/values/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values/arrays.xml
@@ -221,7 +221,7 @@
     <!-- Values for security type for wireless tether -->
     <string-array name="wifi_tether_security_values" translatable="false">
         <!-- Do not translate. -->
-        <item>4</item>
+        <item>1</item>
         <!-- Do not translate. -->
         <item>0</item>
     </string-array>
@@ -246,24 +246,15 @@
         <item>PWD</item>
     </string-array>
 
-   <!-- Wi-Fi AP band settings.  Either Auto, 2.4GHz or 5GHz. -->
+   <!-- Wi-Fi AP band settings.  Either 2.4GHz or (2.4G|5GHz). -->
    <!-- Note that adding/removing/moving the items will need wifi settings code change. -->
-    <string-array translatable="false" name="wifi_ap_band_config_full">
-        <item>0</item>
+
+    <string-array translatable="false" name="wifi_ap_band">
         <item>1</item>
+        <item>3</item>
     </string-array>
 
-    <string-array translatable="false" name="wifi_ap_band_summary_full">
-        <item>@string/wifi_ap_choose_2G</item>
-        <item>@string/wifi_ap_choose_5G</item>
-    </string-array>
-
-    <string-array translatable="false" name="wifi_ap_band_dual_mode">
-        <item>0</item>
-        <item>-1</item>
-    </string-array>
-
-    <string-array translatable="false" name="wifi_ap_band_dual_mode_summary">
+    <string-array translatable="false" name="wifi_ap_band_summary">
         <item>@string/wifi_ap_choose_2G</item>
         <item>@string/wifi_ap_prefer_5G</item>
     </string-array>
diff --git a/tests/CarDeveloperOptions/res/values/config.xml b/tests/CarDeveloperOptions/res/values/config.xml
index c54d50e..8e08012 100755
--- a/tests/CarDeveloperOptions/res/values/config.xml
+++ b/tests/CarDeveloperOptions/res/values/config.xml
@@ -362,5 +362,5 @@
     <string name="config_nearby_devices_slice_uri" translatable="false">content://com.google.android.gms.nearby.fastpair/device_status_list_item</string>
 
     <!-- Grayscale settings intent -->
-    <string name="config_grayscale_settings_intent" translate="false"></string>
+    <string name="config_grayscale_settings_intent" translatable="false"></string>
 </resources>
diff --git a/tests/CarDeveloperOptions/res/values/strings.xml b/tests/CarDeveloperOptions/res/values/strings.xml
index 130cfb9..a8c38f4 100644
--- a/tests/CarDeveloperOptions/res/values/strings.xml
+++ b/tests/CarDeveloperOptions/res/values/strings.xml
@@ -1529,9 +1529,6 @@
         <item quantity="other">Must be fewer than <xliff:g id="number" example="17">%d</xliff:g> digits</item>
     </plurals>
 
-    <!-- Error shown when in PIN mode and user enters a non-digit -->
-    <string name="lockpassword_pin_contains_non_digits">Must contain only digits 0-9</string>
-
     <!-- Error shown when in PIN mode and PIN has been used recently. Please keep this string short! -->
     <string name="lockpassword_pin_recently_used">Device admin doesn\'t allow using a recent PIN</string>
 
@@ -1586,6 +1583,12 @@
         <item quantity="other">Must contain at least <xliff:g id="count" example="3">%d</xliff:g> non-letter characters</item>
     </plurals>
 
+    <!-- Error shown when in PASSWORD mode and password doesn't contain the required number of non-numerical characters -->
+    <plurals name="lockpassword_password_requires_nonnumerical">
+        <item quantity="one">Must contain at least 1 non-numerical character</item>
+        <item quantity="other">Must contain at least <xliff:g id="count" example="3">%d</xliff:g> non-numerical characters</item>
+    </plurals>
+
     <!-- Error shown when in PASSWORD mode and password has been used recently. Please keep this string short! -->
     <string name="lockpassword_password_recently_used">Device admin doesn\'t allow using a recent
         password</string>
diff --git a/tests/CarDeveloperOptions/res/xml/accessibility_autoclick_settings.xml b/tests/CarDeveloperOptions/res/xml/accessibility_autoclick_settings.xml
index 7dd88cb..7ec174d 100644
--- a/tests/CarDeveloperOptions/res/xml/accessibility_autoclick_settings.xml
+++ b/tests/CarDeveloperOptions/res/xml/accessibility_autoclick_settings.xml
@@ -16,6 +16,7 @@
 
 <PreferenceScreen
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:key="autoclick_preference_screen"
     android:title="@string/accessibility_autoclick_preference_title">
 
@@ -24,4 +25,9 @@
         android:key="autoclick_delay"
         android:title="@string/accessibility_autoclick_delay_preference_title" />
 
+    <com.android.settingslib.widget.FooterPreference
+        android:key="autoclick_footer"
+        android:title="@string/accessibility_autoclick_description"
+        android:selectable="false"
+        settings:searchable="false"/>
 </PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/accessibility_daltonizer_settings.xml b/tests/CarDeveloperOptions/res/xml/accessibility_daltonizer_settings.xml
index 38b830c..5b8811f 100644
--- a/tests/CarDeveloperOptions/res/xml/accessibility_daltonizer_settings.xml
+++ b/tests/CarDeveloperOptions/res/xml/accessibility_daltonizer_settings.xml
@@ -16,6 +16,7 @@
 
 <PreferenceScreen
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:key="daltonizer_preference_screen"
     android:title="@string/accessibility_display_daltonizer_preference_title">
 
@@ -27,4 +28,9 @@
         android:title="@string/daltonizer_type"
         android:icon="@drawable/ic_accessibility_illustration_colorblind" />
 
+    <com.android.settingslib.widget.FooterPreference
+        android:key="daltonizer_footer"
+        android:title="@string/accessibility_display_daltonizer_preference_subtitle"
+        android:selectable="false"
+        settings:searchable="false"/>
 </PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/accessibility_settings.xml b/tests/CarDeveloperOptions/res/xml/accessibility_settings.xml
index b170ca0..3c98a00 100644
--- a/tests/CarDeveloperOptions/res/xml/accessibility_settings.xml
+++ b/tests/CarDeveloperOptions/res/xml/accessibility_settings.xml
@@ -21,11 +21,6 @@
         android:title="@string/accessibility_settings"
         android:persistent="true">
 
-    <Preference
-            android:key="accessibility_shortcut_preference"
-            android:fragment="com.android.car.developeroptions.accessibility.AccessibilityShortcutPreferenceFragment"
-            android:title="@string/accessibility_global_gesture_preference_title"/>
-
     <PreferenceCategory
             android:key="user_installed_services_category"
             android:title="@string/user_installed_services_category_title">
diff --git a/tests/CarDeveloperOptions/res/xml/accessibility_shortcut_settings.xml b/tests/CarDeveloperOptions/res/xml/accessibility_shortcut_settings.xml
index 66ae3e8..872c8ca 100644
--- a/tests/CarDeveloperOptions/res/xml/accessibility_shortcut_settings.xml
+++ b/tests/CarDeveloperOptions/res/xml/accessibility_shortcut_settings.xml
@@ -14,6 +14,7 @@
      limitations under the License.
 -->
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+                  xmlns:settings="http://schemas.android.com/apk/res-auto"
                   android:title="@string/accessibility_global_gesture_preference_title" >
 
     <Preference
@@ -24,4 +25,10 @@
     <SwitchPreference
             android:key="accessibility_shortcut_on_lock_screen"
             android:title="@string/accessibility_shortcut_service_on_lock_screen_title"/>
-</PreferenceScreen>
\ No newline at end of file
+
+    <com.android.settingslib.widget.FooterPreference
+        android:key="accessibility_shortcut_footer"
+        android:title="@string/accessibility_shortcut_description"
+        android:selectable="false"
+        settings:searchable="false"/>
+</PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/adaptive_sleep_detail.xml b/tests/CarDeveloperOptions/res/xml/adaptive_sleep_detail.xml
index da9281c..24d8542 100644
--- a/tests/CarDeveloperOptions/res/xml/adaptive_sleep_detail.xml
+++ b/tests/CarDeveloperOptions/res/xml/adaptive_sleep_detail.xml
@@ -38,4 +38,11 @@
         settings:useAdminDisabledSummary="true"
         settings:allowDividerAbove="true" />
 
-</PreferenceScreen>
\ No newline at end of file
+    <com.android.settingslib.widget.FooterPreference
+        android:key="adaptive_sleep_footer"
+        android:title="@string/adaptive_sleep_privacy"
+        android:icon="@drawable/ic_privacy_shield_24dp"
+        android:selectable="false"
+        settings:searchable="false" />
+
+</PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/add_account_settings.xml b/tests/CarDeveloperOptions/res/xml/add_account_settings.xml
index 57e0eba..002c290 100644
--- a/tests/CarDeveloperOptions/res/xml/add_account_settings.xml
+++ b/tests/CarDeveloperOptions/res/xml/add_account_settings.xml
@@ -19,4 +19,11 @@
     xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:key="add_account_screen"
     android:title="@string/header_add_an_account"
-    settings:controller="com.android.car.developeroptions.accounts.ChooseAccountPreferenceController" />
+    settings:controller="com.android.car.developeroptions.accounts.ChooseAccountPreferenceController" >
+
+    <com.android.settingslib.widget.FooterPreference
+        android:key="add_account_enterprise_disclosure_footer"
+        android:selectable="false"
+        settings:searchable="false"
+        settings:controller="com.android.car.developeroptions.accounts.EnterpriseDisclosurePreferenceController"/>
+</PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/app_bubble_notification_settings.xml b/tests/CarDeveloperOptions/res/xml/app_bubble_notification_settings.xml
deleted file mode 100644
index 8d97f8f..0000000
--- a/tests/CarDeveloperOptions/res/xml/app_bubble_notification_settings.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?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.
--->
-
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
-                  xmlns:settings="http://schemas.android.com/apk/res-auto"
-                  android:title="@string/bubbles_app_toggle_title"
-                  android:key="app_bubble_notification_settings">
-        <com.android.settingslib.widget.LayoutPreference
-            android:key="pref_app_header"
-            android:layout="@layout/settings_entity_header"/>
-
-        <com.android.settingslib.RestrictedSwitchPreference
-            android:key="bubble_pref"
-            android:title="@string/notification_bubbles_title"/>
-
-        <com.android.settingslib.widget.FooterPreference
-            android:key="notification_bubbles_footer"
-            android:title="@string/bubbles_feature_education"
-            android:selectable="false" />
-
-</PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/auto_brightness_detail.xml b/tests/CarDeveloperOptions/res/xml/auto_brightness_detail.xml
index dfa4105..6232873 100644
--- a/tests/CarDeveloperOptions/res/xml/auto_brightness_detail.xml
+++ b/tests/CarDeveloperOptions/res/xml/auto_brightness_detail.xml
@@ -38,4 +38,10 @@
         settings:userRestriction="no_config_brightness"
         settings:allowDividerAbove="true" />
 
-</PreferenceScreen>
\ No newline at end of file
+    <com.android.settingslib.widget.FooterPreference
+        android:key="auto_brightness_footer"
+        android:title="@string/auto_brightness_description"
+        android:selectable="false"
+        settings:searchable="false" />
+
+</PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/billing_cycle.xml b/tests/CarDeveloperOptions/res/xml/billing_cycle.xml
index 365fb1d..4b44c65 100644
--- a/tests/CarDeveloperOptions/res/xml/billing_cycle.xml
+++ b/tests/CarDeveloperOptions/res/xml/billing_cycle.xml
@@ -16,6 +16,7 @@
 
 <PreferenceScreen
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:key="billing_cycle_settings"
     android:title="@string/billing_cycle">
 
@@ -39,4 +40,10 @@
         android:key="data_limit"
         android:title="@string/data_limit" />
 
+    <com.android.settingslib.widget.FooterPreference
+        android:key="billing_cycle_footer"
+        android:title="@string/data_warning_footnote"
+        android:selectable="false"
+        settings:searchable="false"/>
+
 </PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/bluetooth_device_details_fragment.xml b/tests/CarDeveloperOptions/res/xml/bluetooth_device_details_fragment.xml
index e8eae7c..72d6d61 100644
--- a/tests/CarDeveloperOptions/res/xml/bluetooth_device_details_fragment.xml
+++ b/tests/CarDeveloperOptions/res/xml/bluetooth_device_details_fragment.xml
@@ -46,4 +46,10 @@
     <PreferenceCategory
         android:key="bluetooth_profiles"/>
 
-</PreferenceScreen>
\ No newline at end of file
+    <com.android.settingslib.widget.FooterPreference
+        android:key="device_details_footer"
+        android:selectable="false"
+        settings:searchable="false"
+        settings:controller="com.android.car.developeroptions.bluetooth.BluetoothDetailsMacAddressController"/>
+
+</PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/bluetooth_screen.xml b/tests/CarDeveloperOptions/res/xml/bluetooth_screen.xml
index a36704f..8821999 100644
--- a/tests/CarDeveloperOptions/res/xml/bluetooth_screen.xml
+++ b/tests/CarDeveloperOptions/res/xml/bluetooth_screen.xml
@@ -36,4 +36,8 @@
         settings:useAdminDisabledSummary="true"
         settings:controller="com.android.car.developeroptions.connecteddevice.AddDevicePreferenceController"/>
 
-</PreferenceScreen>
\ No newline at end of file
+    <com.android.settingslib.widget.FooterPreference
+        android:key="bluetooth_screen_footer"
+        android:selectable="false"
+        settings:searchable="false"/>
+</PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/bubble_notification_settings.xml b/tests/CarDeveloperOptions/res/xml/bubble_notification_settings.xml
deleted file mode 100644
index 982b9cc..0000000
--- a/tests/CarDeveloperOptions/res/xml/bubble_notification_settings.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?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.
--->
-
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
-                  xmlns:settings="http://schemas.android.com/apk/res-auto"
-                  android:title="@string/bubbles_app_toggle_title"
-                  android:key="bubble_notification_settings">
-        <!-- Notification bubbles -->
-        <SwitchPreference
-            android:key="global_notification_bubbles"
-            android:title="@string/notification_bubbles_title"
-            android:summary="@string/notification_bubbles_summary"
-            settings:controller="com.android.car.developeroptions.notification.BubbleNotificationPreferenceController"/>
-
-        <com.android.settingslib.widget.FooterPreference
-            android:key="notification_bubbles_footer"
-            android:title="@string/bubbles_feature_education"
-            android:selectable="false" />
-
-</PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/connected_devices.xml b/tests/CarDeveloperOptions/res/xml/connected_devices.xml
index 56b9139..88421be 100644
--- a/tests/CarDeveloperOptions/res/xml/connected_devices.xml
+++ b/tests/CarDeveloperOptions/res/xml/connected_devices.xml
@@ -67,4 +67,11 @@
         settings:allowDividerAbove="true"
         settings:controller="com.android.car.developeroptions.connecteddevice.AdvancedConnectedDeviceController"/>
 
+    <com.android.settingslib.widget.FooterPreference
+        android:key="discoverable_footer"
+        android:title="@string/bluetooth_off_footer"
+        android:selectable="false"
+        settings:controller="com.android.car.developeroptions.connecteddevice.DiscoverableFooterPreferenceController">
+    </com.android.settingslib.widget.FooterPreference>
+
 </PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/data_saver.xml b/tests/CarDeveloperOptions/res/xml/data_saver.xml
index 614b079..6903642 100644
--- a/tests/CarDeveloperOptions/res/xml/data_saver.xml
+++ b/tests/CarDeveloperOptions/res/xml/data_saver.xml
@@ -27,4 +27,10 @@
         android:fragment="com.android.car.developeroptions.datausage.UnrestrictedDataAccess"
         settings:controller="com.android.car.developeroptions.applications.specialaccess.DataSaverController" />
 
+    <com.android.settingslib.widget.FooterPreference
+        android:key="data_saver_footer"
+        android:title="@*android:string/data_saver_description"
+        android:selectable="false"
+        settings:searchable="false"/>
+
 </PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/device_admin_settings.xml b/tests/CarDeveloperOptions/res/xml/device_admin_settings.xml
index b77ed81..fc54c90 100644
--- a/tests/CarDeveloperOptions/res/xml/device_admin_settings.xml
+++ b/tests/CarDeveloperOptions/res/xml/device_admin_settings.xml
@@ -20,4 +20,11 @@
     xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:title="@string/manage_device_admin"
     android:key="device_admin_settings"
-    settings:controller="com.android.car.developeroptions.applications.specialaccess.deviceadmin.DeviceAdminListPreferenceController" />
\ No newline at end of file
+    settings:controller="com.android.car.developeroptions.applications.specialaccess.deviceadmin.DeviceAdminListPreferenceController">
+
+    <com.android.settingslib.widget.FooterPreference
+        android:key="device_admin_footer"
+        android:title="@string/no_device_admins"
+        android:selectable="false"
+        settings:searchable="false"/>
+</PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/feature_flags_settings.xml b/tests/CarDeveloperOptions/res/xml/feature_flags_settings.xml
index e194795..6b90bee 100644
--- a/tests/CarDeveloperOptions/res/xml/feature_flags_settings.xml
+++ b/tests/CarDeveloperOptions/res/xml/feature_flags_settings.xml
@@ -25,4 +25,10 @@
         android:layout="@layout/preference_category_no_label"
         android:title="@string/summary_placeholder"
         settings:controller="com.android.car.developeroptions.development.featureflags.FeatureFlagsPreferenceController" />
+
+    <com.android.settingslib.widget.FooterPreference
+        android:key="feature_flag_footer"
+        android:title="@string/experimental_category_title"
+        android:selectable="false"
+        settings:searchable="false"/>
 </PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/game_driver_settings.xml b/tests/CarDeveloperOptions/res/xml/game_driver_settings.xml
index bb847da..52d0ab2 100644
--- a/tests/CarDeveloperOptions/res/xml/game_driver_settings.xml
+++ b/tests/CarDeveloperOptions/res/xml/game_driver_settings.xml
@@ -34,7 +34,7 @@
     </PreferenceCategory>
 
     <com.android.settingslib.widget.FooterPreference
-        android:key="footer_preference"
+        android:key="game_driver_footer"
         android:title="@string/game_driver_footer_text"
         android:selectable="false"
         settings:controller="com.android.car.developeroptions.development.gamedriver.GameDriverFooterPreferenceController">
diff --git a/tests/CarDeveloperOptions/res/xml/manage_assist.xml b/tests/CarDeveloperOptions/res/xml/manage_assist.xml
index 46917cb..56837b5 100644
--- a/tests/CarDeveloperOptions/res/xml/manage_assist.xml
+++ b/tests/CarDeveloperOptions/res/xml/manage_assist.xml
@@ -53,4 +53,10 @@
         android:title="@string/voice_input_settings_title"
         android:fragment="com.android.car.developeroptions.applications.assist.DefaultVoiceInputPicker" />
 
+    <com.android.settingslib.widget.FooterPreference
+        android:key="manage_assist_footer"
+        android:title="@string/assist_footer"
+        android:selectable="false"
+        settings:searchable="false"/>
+
 </PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/night_display_settings.xml b/tests/CarDeveloperOptions/res/xml/night_display_settings.xml
index f1d8d9e..4b7855d 100644
--- a/tests/CarDeveloperOptions/res/xml/night_display_settings.xml
+++ b/tests/CarDeveloperOptions/res/xml/night_display_settings.xml
@@ -49,11 +49,15 @@
         android:title="@string/night_display_title"
         android:selectable="false"
         android:layout="@layout/night_display_activation_button"
+        settings:allowDividerBelow="true"
         settings:keywords="@string/keywords_display_night_display"
         settings:controller="com.android.car.developeroptions.display.NightDisplayActivationPreferenceController" />
 
-    <PreferenceCategory android:key="night_display_footer_category">
-        <com.android.settingslib.widget.FooterPreference />
-    </PreferenceCategory>
+    <com.android.settingslib.widget.FooterPreference
+        android:key="night_display_footer"
+        android:title="@string/night_display_text"
+        android:selectable="false"
+        settings:allowDividerAbove="true"
+        settings:controller="com.android.car.developeroptions.display.NightDisplayFooterPreferenceController"/>
 
-</PreferenceScreen>
\ No newline at end of file
+</PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/power_usage_summary.xml b/tests/CarDeveloperOptions/res/xml/power_usage_summary.xml
index 5f67488..9dd54db 100644
--- a/tests/CarDeveloperOptions/res/xml/power_usage_summary.xml
+++ b/tests/CarDeveloperOptions/res/xml/power_usage_summary.xml
@@ -64,4 +64,9 @@
         android:title="@string/device_screen_usage"
         android:selectable="false" />
 
+    <com.android.settingslib.widget.FooterPreference
+        android:key="power_usage_footer"
+        android:title="@string/battery_footer_summary"
+        android:selectable="false"
+        settings:searchable="false"/>
 </PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/restricted_apps_detail.xml b/tests/CarDeveloperOptions/res/xml/restricted_apps_detail.xml
index eea9de8..6b6404c 100644
--- a/tests/CarDeveloperOptions/res/xml/restricted_apps_detail.xml
+++ b/tests/CarDeveloperOptions/res/xml/restricted_apps_detail.xml
@@ -16,9 +16,15 @@
 
 <PreferenceScreen
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:title="@string/restricted_app_title">
 
     <PreferenceCategory
         android:key="restrict_app_list"/>
 
+    <com.android.settingslib.widget.FooterPreference
+        android:key="restricted_app_footer"
+        android:title="@string/restricted_app_detail_footer"
+        android:selectable="false"
+        settings:searchable="false"/>
 </PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/security_settings_picker.xml b/tests/CarDeveloperOptions/res/xml/security_settings_picker.xml
index 070b657..af4cfe7 100644
--- a/tests/CarDeveloperOptions/res/xml/security_settings_picker.xml
+++ b/tests/CarDeveloperOptions/res/xml/security_settings_picker.xml
@@ -15,6 +15,7 @@
 -->
 
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+                  xmlns:settings="http://schemas.android.com/apk/res-auto"
         android:title="@string/lock_settings_picker_title"
         android:key="lock_settings_picker">
 
@@ -57,4 +58,9 @@
             android:title="@string/face_unlock_skip_face"
             android:persistent="false"/>
 
+    <com.android.settingslib.widget.FooterPreference
+            android:key="lock_settings_footer"
+            android:selectable="false"
+            settings:searchable="false"/>
+
 </PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/smart_battery_detail.xml b/tests/CarDeveloperOptions/res/xml/smart_battery_detail.xml
index fa71e1a..8c2ea1f 100644
--- a/tests/CarDeveloperOptions/res/xml/smart_battery_detail.xml
+++ b/tests/CarDeveloperOptions/res/xml/smart_battery_detail.xml
@@ -45,4 +45,9 @@
         android:key="restricted_app"
         android:title="@string/restricted_app_title"/>
 
-</PreferenceScreen>
\ No newline at end of file
+    <com.android.settingslib.widget.FooterPreference
+        android:key="smart_battery_detail_footer"
+        android:title="@string/smart_battery_footer"
+        android:selectable="false"
+        settings:searchable="false"/>
+</PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/tether_prefs.xml b/tests/CarDeveloperOptions/res/xml/tether_prefs.xml
index 3267115..aa85314 100644
--- a/tests/CarDeveloperOptions/res/xml/tether_prefs.xml
+++ b/tests/CarDeveloperOptions/res/xml/tether_prefs.xml
@@ -44,4 +44,10 @@
         android:summary="@string/tether_settings_disabled_on_data_saver"
         android:selectable="false"
         settings:allowDividerAbove="true" />
+
+    <com.android.settingslib.widget.FooterPreference
+        android:key="tether_prefs_footer"
+        android:title="@string/tethering_footer_info"
+        android:selectable="false"
+        settings:searchable="false"/>
 </PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/time_zone_prefs.xml b/tests/CarDeveloperOptions/res/xml/time_zone_prefs.xml
index dba42bf..30e52ce 100644
--- a/tests/CarDeveloperOptions/res/xml/time_zone_prefs.xml
+++ b/tests/CarDeveloperOptions/res/xml/time_zone_prefs.xml
@@ -31,7 +31,7 @@
             android:title="@string/date_time_set_timezone_title"
             android:summary="@string/summary_placeholder" />
         <com.android.settingslib.widget.FooterPreference
-            android:key="footer_preference"
+            android:key="timezone_footer"
             settings:controller="com.android.car.developeroptions.datetime.timezone.TimeZoneInfoPreferenceController" />
     </PreferenceCategory>
 
diff --git a/tests/CarDeveloperOptions/res/xml/user_settings.xml b/tests/CarDeveloperOptions/res/xml/user_settings.xml
index d2b7d46..bdc8b4d 100644
--- a/tests/CarDeveloperOptions/res/xml/user_settings.xml
+++ b/tests/CarDeveloperOptions/res/xml/user_settings.xml
@@ -40,4 +40,11 @@
         android:order="105"
         settings:allowDividerAbove="true"/>
 
+    <com.android.settingslib.widget.FooterPreference
+        android:key="multiuser_footer"
+        android:title="@string/user_settings_footer_text"
+        android:selectable="false"
+        settings:searchable="false"
+        settings:controller="com.android.car.developeroptions.users.MultiUserFooterPreferenceController"/>
+
 </PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/res/xml/wifi_configure_settings.xml b/tests/CarDeveloperOptions/res/xml/wifi_configure_settings.xml
index c4e4485..2f02f7d 100644
--- a/tests/CarDeveloperOptions/res/xml/wifi_configure_settings.xml
+++ b/tests/CarDeveloperOptions/res/xml/wifi_configure_settings.xml
@@ -48,10 +48,12 @@
     <Preference
         android:key="install_credentials"
         android:title="@string/wifi_install_credentials">
-        <intent android:action="android.credentials.INSTALL_AS_USER"
-                android:targetPackage="com.android.certinstaller"
-                android:targetClass="com.android.certinstaller.CertInstallerMain">
-            <extra android:name="install_as_uid" android:value="1010" />
+        <intent
+            android:action="android.credentials.INSTALL"
+            android:targetPackage="com.android.certinstaller"
+            android:targetClass="com.android.certinstaller.CertInstallerMain">
+            <!-- Same value as CERTIFICATE_USAGE_WIFI in keystore/java/android/security/Credentials.java -->
+            <extra android:name="certificate_install_usage" android:value="wifi"/>
         </intent>
     </Preference>
 
diff --git a/tests/CarDeveloperOptions/res/xml/zen_mode_block_settings.xml b/tests/CarDeveloperOptions/res/xml/zen_mode_block_settings.xml
index e290842..2aa43f0 100644
--- a/tests/CarDeveloperOptions/res/xml/zen_mode_block_settings.xml
+++ b/tests/CarDeveloperOptions/res/xml/zen_mode_block_settings.xml
@@ -17,6 +17,7 @@
 
 <PreferenceScreen
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:key="zen_mode_block_settings_page"
     android:title="@string/zen_mode_what_to_block_title">
 
@@ -57,4 +58,10 @@
            android:title="@string/zen_mode_block_effect_list" />
    </PreferenceCategory>
 
+    <com.android.settingslib.widget.FooterPreference
+        android:key="zen_mode_block_footer"
+        android:title="@string/zen_mode_blocked_effects_footer"
+        android:selectable="false"
+        settings:searchable="false"/>
+
 </PreferenceScreen>
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/AirplaneModeEnabler.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/AirplaneModeEnabler.java
index 6b7e912..1e82aa9 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/AirplaneModeEnabler.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/AirplaneModeEnabler.java
@@ -17,29 +17,27 @@
 package com.android.car.developeroptions;
 
 import android.app.settings.SettingsEnums;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.database.ContentObserver;
 import android.os.Handler;
 import android.os.Looper;
-import android.os.Message;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.sysprop.TelephonyProperties;
 
-import com.android.internal.telephony.PhoneStateIntentReceiver;
-import com.android.internal.telephony.TelephonyProperties;
 import com.android.settingslib.WirelessUtils;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
-public class AirplaneModeEnabler {
+public class AirplaneModeEnabler  extends BroadcastReceiver {
 
     private static final int EVENT_SERVICE_STATE_CHANGED = 3;
 
     private final Context mContext;
     private final MetricsFeatureProvider mMetricsFeatureProvider;
-
-    private PhoneStateIntentReceiver mPhoneStateReceiver;
+    private IntentFilter mFilter;
 
     private OnAirplaneModeChangedListener mOnAirplaneModeChangedListener;
 
@@ -52,17 +50,6 @@
         void onAirplaneModeChanged(boolean isAirplaneModeOn);
     }
 
-    private Handler mHandler = new Handler(Looper.getMainLooper()) {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case EVENT_SERVICE_STATE_CHANGED:
-                    onAirplaneModeChanged();
-                    break;
-            }
-        }
-    };
-
     private ContentObserver mAirplaneModeObserver = new ContentObserver(
             new Handler(Looper.getMainLooper())) {
         @Override
@@ -78,19 +65,18 @@
         mMetricsFeatureProvider = metricsFeatureProvider;
         mOnAirplaneModeChangedListener = listener;
 
-        mPhoneStateReceiver = new PhoneStateIntentReceiver(mContext, mHandler);
-        mPhoneStateReceiver.notifyServiceState(EVENT_SERVICE_STATE_CHANGED);
+        mFilter = new IntentFilter(Intent.ACTION_SERVICE_STATE);
     }
 
     public void resume() {
-        mPhoneStateReceiver.registerIntent();
+        mContext.registerReceiver(this, mFilter);
         mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
                 mAirplaneModeObserver);
     }
 
     public void pause() {
-        mPhoneStateReceiver.unregisterIntent();
+        mContext.unregisterReceiver(this);
         mContext.getContentResolver().unregisterContentObserver(mAirplaneModeObserver);
     }
 
@@ -125,8 +111,7 @@
     }
 
     public void setAirplaneMode(boolean isAirplaneModeOn) {
-        if (Boolean.parseBoolean(
-                SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
+        if (TelephonyProperties.in_ecm_mode().orElse(false)) {
             // In ECM mode, do not update database at this point
         } else {
             mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_AIRPLANE_TOGGLE,
@@ -148,4 +133,13 @@
     public boolean isAirplaneModeOn() {
         return WirelessUtils.isAirplaneModeOn(mContext);
     }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+
+        if (Intent.ACTION_SERVICE_STATE.equals(action)) {
+            onAirplaneModeChanged();
+        }
+    }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/CryptKeeper.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/CryptKeeper.java
index bafe467..2727507 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/CryptKeeper.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/CryptKeeper.java
@@ -60,12 +60,11 @@
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
-import com.android.internal.telephony.PhoneConstants;
+import com.android.car.developeroptions.widget.ImeAwareEditText;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockPatternView;
 import com.android.internal.widget.LockPatternView.Cell;
 import com.android.internal.widget.LockPatternView.DisplayMode;
-import com.android.car.developeroptions.widget.ImeAwareEditText;
 
 import java.util.List;
 
@@ -727,7 +726,7 @@
         public void onPatternDetected(List<LockPatternView.Cell> pattern) {
             mLockPatternView.setEnabled(false);
             if (pattern.size() >= MIN_LENGTH_BEFORE_REPORT) {
-                new DecryptTask().execute(LockPatternUtils.patternToString(pattern));
+                new DecryptTask().execute(new String(LockPatternUtils.patternToByteArray(pattern)));
             } else {
                 // Allow user to make as many of these as they want.
                 fakeUnlockAttempt(mLockPatternView);
@@ -916,9 +915,7 @@
      *    phone that has no encryption.
      */
     private final void setAirplaneModeIfNecessary() {
-        final boolean isLteDevice =
-                getTelephonyManager().getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE;
-        if (!isLteDevice) {
+        if (!getTelephonyManager().isLteCdmaEvdoGsmWcdmaEnabled()) {
             Log.d(TAG, "Going into airplane mode.");
             Settings.Global.putInt(getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
             final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
@@ -964,7 +961,7 @@
     }
 
     private boolean isEmergencyCallCapable() {
-        return getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);
+        return getTelephonyManager().isVoiceCapable();
     }
 
     private void takeEmergencyCallAction() {
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/CryptKeeperConfirm.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/CryptKeeperConfirm.java
index fcdbd1b..e0ff5c6 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/CryptKeeperConfirm.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/CryptKeeperConfirm.java
@@ -35,8 +35,8 @@
 import android.view.ViewGroup;
 import android.widget.Button;
 
-import com.android.internal.widget.LockPatternUtils;
 import com.android.car.developeroptions.core.InstrumentedFragment;
+import com.android.internal.widget.LockPatternUtils;
 
 import java.util.Arrays;
 import java.util.Locale;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/DateTimeSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/DateTimeSettings.java
index f64debd..035a8d3 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/DateTimeSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/DateTimeSettings.java
@@ -34,9 +34,9 @@
 import com.android.car.developeroptions.datetime.TimePreferenceController;
 import com.android.car.developeroptions.datetime.TimeZonePreferenceController;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.datetime.ZoneGetter;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/DisplaySettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/DisplaySettings.java
index a449e8a..35e9d71 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/DisplaySettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/DisplaySettings.java
@@ -33,9 +33,9 @@
 import com.android.car.developeroptions.display.TimeoutPreferenceController;
 import com.android.car.developeroptions.display.VrDisplayPreferenceController;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/IccLockSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/IccLockSettings.java
index 443fb85..0eff1c0 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/IccLockSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/IccLockSettings.java
@@ -37,6 +37,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowInsets.Type;
 import android.view.WindowManager;
 import android.widget.EditText;
 import android.widget.ListView;
@@ -516,6 +517,7 @@
         params.format = PixelFormat.TRANSLUCENT;
         params.windowAnimations = com.android.internal.R.style.Animation_Toast;
         params.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
+        params.setFitInsetsTypes(params.getFitInsetsTypes() & ~Type.statusBars());
         params.setTitle(errorMessage);
         params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/LegalSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/LegalSettings.java
index 0c1c150..e0cf6d7 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/LegalSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/LegalSettings.java
@@ -22,7 +22,7 @@
 
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.Arrays;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/RadioInfo.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/RadioInfo.java
index 5187c91..73f12f7 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/RadioInfo.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/RadioInfo.java
@@ -170,6 +170,7 @@
     private static final int EVENT_SET_PREFERRED_TYPE_DONE = 1001;
     private static final int EVENT_QUERY_SMSC_DONE = 1005;
     private static final int EVENT_UPDATE_SMSC_DONE = 1006;
+    private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 1007;
 
     private static final int MENU_ITEM_SELECT_BAND  = 0;
     private static final int MENU_ITEM_VIEW_ADN     = 1;
@@ -313,12 +314,6 @@
             updateImsProvisionedState();
         }
 
-        @Override
-        public void onPhysicalChannelConfigurationChanged(
-                List<PhysicalChannelConfig> configs) {
-            updatePhysicalChannelConfiguration(configs);
-        }
-
     };
 
     private void updatePhysicalChannelConfiguration(List<PhysicalChannelConfig> configs) {
@@ -381,6 +376,13 @@
                         smsc.setText("update error");
                     }
                     break;
+                case EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED:
+                    ar = (AsyncResult) msg.obj;
+                    if (ar.exception != null) {
+                        mPhyChanConfig.setText(("update error"));
+                    }
+                    updatePhysicalChannelConfiguration((List<PhysicalChannelConfig>) ar.result);
+                    break;
                 default:
                     super.handleMessage(msg);
                     break;
@@ -574,8 +576,9 @@
                 | PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
                 | PhoneStateListener.LISTEN_CELL_INFO
                 | PhoneStateListener.LISTEN_SERVICE_STATE
-                | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
-                | PhoneStateListener.LISTEN_PHYSICAL_CHANNEL_CONFIGURATION);
+                | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
+        phone.registerForPhysicalChannelConfig(mHandler,
+            EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED, null);
 
         mConnectivityManager.registerNetworkCallback(
                 mDefaultNetworkRequest, mNetworkCallback, mHandler);
@@ -592,7 +595,7 @@
         mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
         mTelephonyManager.setCellInfoListRate(CELL_INFO_LIST_RATE_DISABLED);
         mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
-
+        phone.unregisterForPhysicalChannelConfig(mHandler);
     }
 
     private void restoreFromBundle(Bundle b) {
@@ -1526,8 +1529,10 @@
     };
 
     boolean isCbrsSupported() {
-        return getResources().getBoolean(
-              com.android.internal.R.bool.config_cbrs_supported);
+        // No longer possible to access com.android.internal.R.bool.config_cbrs_supported, so
+        // returning false for now.
+        // TODO: This needs to be cleaned up in future CL.
+        return false;
     }
 
     void updateCbrsDataState(boolean state) {
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/Settings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/Settings.java
index c8dc44c..ca9fd6a 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/Settings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/Settings.java
@@ -113,7 +113,6 @@
     public static class ZenModeEventRuleSettingsActivity extends SettingsActivity { /* empty */ }
     public static class SoundSettingsActivity extends SettingsActivity { /* empty */ }
     public static class ConfigureNotificationSettingsActivity extends SettingsActivity { /* empty */ }
-    public static class AppBubbleNotificationSettingsActivity extends SettingsActivity { /* empty */ }
     public static class NotificationAssistantSettingsActivity extends SettingsActivity{ /* empty */ }
     public static class NotificationAppListActivity extends SettingsActivity { /* empty */ }
     public static class AppNotificationSettingsActivity extends SettingsActivity { /* empty */ }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/SettingsActivity.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/SettingsActivity.java
index 1471ebb..b84b749 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/SettingsActivity.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/SettingsActivity.java
@@ -28,6 +28,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources.Theme;
+import android.graphics.drawable.Icon;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.UserHandle;
@@ -480,7 +481,7 @@
 
     @Override
     public void setTaskDescription(ActivityManager.TaskDescription taskDescription) {
-        taskDescription.setIcon(R.drawable.ic_launcher_settings);
+        taskDescription.setIcon(Icon.createWithResource(this, R.drawable.ic_launcher_settings));
         super.setTaskDescription(taskDescription);
     }
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/SettingsPreferenceFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/SettingsPreferenceFragment.java
index 480800d..fd72461 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/SettingsPreferenceFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/SettingsPreferenceFragment.java
@@ -44,7 +44,6 @@
 
 import com.android.car.developeroptions.core.InstrumentedPreferenceFragment;
 import com.android.car.developeroptions.core.instrumentation.InstrumentedDialogFragment;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.search.actionbar.SearchMenuController;
 import com.android.car.developeroptions.support.actionbar.HelpMenuController;
 import com.android.car.developeroptions.support.actionbar.HelpResourceProvider;
@@ -53,7 +52,7 @@
 import com.android.settingslib.CustomDialogPreferenceCompat;
 import com.android.settingslib.CustomEditTextPreferenceCompat;
 import com.android.settingslib.core.instrumentation.Instrumentable;
-import com.android.settingslib.widget.FooterPreferenceMixinCompat;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.widget.LayoutPreference;
 
 import java.util.UUID;
@@ -68,9 +67,6 @@
 
     private static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted";
 
-    protected final FooterPreferenceMixinCompat mFooterPreferenceMixin =
-            new FooterPreferenceMixinCompat(this, getSettingsLifecycle());
-
 
     private static final int ORDER_FIRST = -1;
 
@@ -310,8 +306,7 @@
         if (getPreferenceScreen() != null) {
             final View listContainer = getActivity().findViewById(android.R.id.list_container);
             boolean show = (getPreferenceScreen().getPreferenceCount()
-                    - (mHeader != null ? 1 : 0)
-                    - (mFooterPreferenceMixin.hasFooter() ? 1 : 0)) <= 0
+                    - (mHeader != null ? 1 : 0)) <= 0
                     || (listContainer != null && listContainer.getVisibility() != View.VISIBLE);
             mEmptyView.setVisibility(show ? View.VISIBLE : View.GONE);
         } else {
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/TetherSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/TetherSettings.java
index 2a26947..186d188 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/TetherSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/TetherSettings.java
@@ -28,7 +28,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.PackageManager;
 import android.hardware.usb.UsbManager;
 import android.net.ConnectivityManager;
 import android.os.Bundle;
@@ -43,9 +42,9 @@
 
 import com.android.car.developeroptions.datausage.DataSaverBackend;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.wifi.tether.WifiTetherPreferenceController;
 import com.android.settingslib.TetherUtil;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.lang.ref.WeakReference;
@@ -120,9 +119,6 @@
         super.onCreate(icicle);
 
         addPreferencesFromResource(R.xml.tether_prefs);
-        mFooterPreferenceMixin.createFooterPreference()
-            .setTitle(R.string.tethering_footer_info);
-
         mDataSaverBackend = new DataSaverBackend(getContext());
         mDataSaverEnabled = mDataSaverBackend.isDataSaverEnabled();
         mDataSaverFooter = findPreference(KEY_DATA_SAVER_FOOTER);
@@ -376,25 +372,6 @@
         }
     }
 
-    public static boolean isProvisioningNeededButUnavailable(Context context) {
-        return (TetherUtil.isProvisioningNeeded(context)
-                && !isIntentAvailable(context));
-    }
-
-    private static boolean isIntentAvailable(Context context) {
-        String[] provisionApp = context.getResources().getStringArray(
-                com.android.internal.R.array.config_mobile_hotspot_provision_app);
-        if (provisionApp.length < 2) {
-            return false;
-        }
-        final PackageManager packageManager = context.getPackageManager();
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.setClassName(provisionApp[0], provisionApp[1]);
-
-        return (packageManager.queryIntentActivities(intent,
-                PackageManager.MATCH_DEFAULT_ONLY).size() > 0);
-    }
-
     private void startTethering(int choice) {
         if (choice == TETHERING_BLUETOOTH) {
             // Turn on Bluetooth first.
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/AccessibilitySettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/AccessibilitySettings.java
index df096bd..0c8b62c 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/AccessibilitySettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/AccessibilitySettings.java
@@ -52,16 +52,16 @@
 import androidx.preference.PreferenceScreen;
 import androidx.preference.SwitchPreference;
 
-import com.android.internal.accessibility.AccessibilityShortcutController;
-import com.android.internal.content.PackageMonitor;
-import com.android.internal.view.RotationPolicy;
-import com.android.internal.view.RotationPolicy.RotationPolicyListener;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.SettingsPreferenceFragment;
 import com.android.car.developeroptions.Utils;
 import com.android.car.developeroptions.display.DarkUIPreferenceController;
 import com.android.car.developeroptions.display.ToggleFontSizePreferenceFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
+import com.android.internal.accessibility.AccessibilityShortcutController;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.view.RotationPolicy;
+import com.android.internal.view.RotationPolicy.RotationPolicyListener;
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 import com.android.settingslib.RestrictedLockUtilsInternal;
 import com.android.settingslib.RestrictedPreference;
@@ -236,7 +236,6 @@
     private Preference mDisplayMagnificationPreferenceScreen;
     private Preference mFontSizePreferenceScreen;
     private Preference mAutoclickPreferenceScreen;
-    private Preference mAccessibilityShortcutPreferenceScreen;
     private Preference mDisplayDaltonizerPreferenceScreen;
     private Preference mHearingAidPreference;
     private Preference mVibrationPreferenceScreen;
@@ -514,9 +513,6 @@
         // Display color adjustments.
         mDisplayDaltonizerPreferenceScreen = findPreference(DISPLAY_DALTONIZER_PREFERENCE_SCREEN);
 
-        // Accessibility shortcut.
-        mAccessibilityShortcutPreferenceScreen = findPreference(ACCESSIBILITY_SHORTCUT_PREFERENCE);
-
         // Vibrations.
         mVibrationPreferenceScreen = findPreference(VIBRATION_PREFERENCE_SCREEN);
 
@@ -759,8 +755,6 @@
 
         updateAutoclickSummary(mAutoclickPreferenceScreen);
 
-        updateAccessibilityShortcut(mAccessibilityShortcutPreferenceScreen);
-
         updateAccessibilityTimeoutSummary(getContentResolver(),
                 findPreference(ACCESSIBILITY_CONTENT_TIMEOUT_PREFERENCE));
         updateAccessibilityTimeoutSummary(getContentResolver(),
@@ -936,23 +930,6 @@
         mToggleMasterMonoPreference.setChecked(masterMono);
     }
 
-    private void updateAccessibilityShortcut(Preference preference) {
-        if (AccessibilityManager.getInstance(getActivity())
-                .getInstalledAccessibilityServiceList().isEmpty()) {
-            mAccessibilityShortcutPreferenceScreen
-                    .setSummary(getString(R.string.accessibility_no_services_installed));
-            mAccessibilityShortcutPreferenceScreen.setEnabled(false);
-        } else {
-            mAccessibilityShortcutPreferenceScreen.setEnabled(true);
-            boolean shortcutEnabled =
-                    AccessibilityUtils.isShortcutEnabled(getContext(), UserHandle.myUserId());
-            CharSequence summary = shortcutEnabled
-                    ? AccessibilityShortcutPreferenceFragment.getServiceName(getContext())
-                    : getString(R.string.accessibility_feature_state_off);
-            mAccessibilityShortcutPreferenceScreen.setSummary(summary);
-        }
-    }
-
     private static void configureMagnificationPreferenceIfNeeded(Preference preference) {
         // Some devices support only a single magnification mode. In these cases, we redirect to
         // the magnification mode's UI directly, rather than showing a PreferenceScreen with a
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/AccessibilityShortcutPreferenceFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/AccessibilityShortcutPreferenceFragment.java
deleted file mode 100644
index 22fdab7..0000000
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/AccessibilityShortcutPreferenceFragment.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.car.developeroptions.accessibility;
-
-import android.accessibilityservice.AccessibilityServiceInfo;
-import android.annotation.Nullable;
-import android.app.settings.SettingsEnums;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.view.accessibility.AccessibilityManager;
-import android.widget.Switch;
-
-import androidx.preference.Preference;
-import androidx.preference.SwitchPreference;
-
-import com.android.internal.accessibility.AccessibilityShortcutController;
-import com.android.car.developeroptions.R;
-import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
-import com.android.settingslib.accessibility.AccessibilityUtils;
-import com.android.settingslib.search.SearchIndexable;
-
-/**
- * Settings page for accessibility shortcut
- */
-@SearchIndexable
-public class AccessibilityShortcutPreferenceFragment extends ToggleFeaturePreferenceFragment
-        implements Indexable {
-
-    public static final String SHORTCUT_SERVICE_KEY = "accessibility_shortcut_service";
-    public static final String ON_LOCK_SCREEN_KEY = "accessibility_shortcut_on_lock_screen";
-
-    private Preference mServicePreference;
-    private SwitchPreference mOnLockScreenSwitchPreference;
-    private final ContentObserver mContentObserver = new ContentObserver(new Handler()) {
-        @Override
-        public void onChange(boolean selfChange) {
-            updatePreferences();
-        }
-    };
-
-    @Override
-    public int getMetricsCategory() {
-        return SettingsEnums.ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE;
-    }
-
-    @Override
-    public int getHelpResource() {
-        return R.string.help_url_accessibility_shortcut;
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        mServicePreference = findPreference(SHORTCUT_SERVICE_KEY);
-        mOnLockScreenSwitchPreference = (SwitchPreference) findPreference(ON_LOCK_SCREEN_KEY);
-        mOnLockScreenSwitchPreference.setOnPreferenceChangeListener((Preference p, Object o) -> {
-            Settings.Secure.putInt(getContentResolver(),
-                    Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN,
-                    ((Boolean) o) ? 1 : 0);
-            return true;
-        });
-        mFooterPreferenceMixin.createFooterPreference()
-                .setTitle(R.string.accessibility_shortcut_description);
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        updatePreferences();
-        getContentResolver().registerContentObserver(
-                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN),
-                false, mContentObserver);
-    }
-
-    @Override
-    public void onPause() {
-        getContentResolver().unregisterContentObserver(mContentObserver);
-        super.onPause();
-    }
-
-    @Override
-    protected int getPreferenceScreenResId() {
-        return R.xml.accessibility_shortcut_settings;
-    }
-
-    @Override
-    protected void onInstallSwitchBarToggleSwitch() {
-        super.onInstallSwitchBarToggleSwitch();
-        mSwitchBar.addOnSwitchChangeListener((Switch switchView, boolean enabled) -> {
-            Context context = getContext();
-            if (enabled && !shortcutFeatureAvailable(context)) {
-                // If no service is configured, we'll disable the shortcut shortly. Give the
-                // user a chance to select a service. We'll update the preferences when we resume.
-                Settings.Secure.putInt(
-                        getContentResolver(), Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 1);
-                mServicePreference.setEnabled(true);
-                mServicePreference.performClick();
-            } else {
-                onPreferenceToggled(Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, enabled);
-            }
-        });
-    }
-
-    @Override
-    protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
-        Settings.Secure.putInt(getContentResolver(), preferenceKey, enabled ? 1 : 0);
-        updatePreferences();
-    }
-
-    private void updatePreferences() {
-        ContentResolver cr = getContentResolver();
-        Context context = getContext();
-        mServicePreference.setSummary(getServiceName(context));
-        if (!shortcutFeatureAvailable(context)) {
-            // If no service is configured, make sure the overall shortcut is turned off
-            Settings.Secure.putInt(
-                    getContentResolver(), Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 0);
-        }
-        boolean isEnabled = Settings.Secure
-                .getInt(cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 1) == 1;
-        mSwitchBar.setChecked(isEnabled);
-        // The shortcut is enabled by default on the lock screen as long as the user has
-        // enabled the shortcut with the warning dialog
-        final int dialogShown = Settings.Secure.getInt(
-                cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
-        final boolean enabledFromLockScreen = Settings.Secure.getInt(
-                cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, dialogShown) == 1;
-        mOnLockScreenSwitchPreference.setChecked(enabledFromLockScreen);
-        // Only enable changing the service and lock screen behavior if the shortcut is on
-        mServicePreference.setEnabled(mToggleSwitch.isChecked());
-        mOnLockScreenSwitchPreference.setEnabled(mToggleSwitch.isChecked());
-    }
-
-    /**
-     * Get the user-visible name of the service currently selected for the shortcut.
-     *
-     * @param context The current context
-     * @return The name of the service or a string saying that none is selected.
-     */
-    public static CharSequence getServiceName(Context context) {
-        if (!shortcutFeatureAvailable(context)) {
-            return context.getString(R.string.accessibility_no_service_selected);
-        }
-        AccessibilityServiceInfo shortcutServiceInfo = getServiceInfo(context);
-        if (shortcutServiceInfo != null) {
-            return shortcutServiceInfo.getResolveInfo().loadLabel(context.getPackageManager());
-        }
-        return AccessibilityShortcutController.getFrameworkShortcutFeaturesMap()
-                .get(getShortcutComponent(context)).getLabel(context);
-    }
-
-    private static AccessibilityServiceInfo getServiceInfo(Context context) {
-        return AccessibilityManager.getInstance(context)
-                .getInstalledServiceInfoWithComponentName(getShortcutComponent(context));
-    }
-
-    private static boolean shortcutFeatureAvailable(Context context) {
-        ComponentName shortcutFeature = getShortcutComponent(context);
-        if (shortcutFeature == null) return false;
-
-        if (AccessibilityShortcutController.getFrameworkShortcutFeaturesMap()
-                .containsKey(shortcutFeature)) {
-            return true;
-        }
-        return getServiceInfo(context) != null;
-    }
-
-    private static @Nullable ComponentName getShortcutComponent(Context context) {
-        String componentNameString = AccessibilityUtils.getShortcutTargetServiceComponentNameString(
-                context, UserHandle.myUserId());
-        if (componentNameString == null) return null;
-        return ComponentName.unflattenFromString(componentNameString);
-    }
-
-    public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
-            new BaseSearchIndexProvider() {
-                // This fragment is for details of the shortcut. Only the shortcut itself needs
-                // to be indexed.
-                protected boolean isPageSearchEnabled(Context context) {
-                    return false;
-                }
-            };
-}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/MagnificationPreferenceFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/MagnificationPreferenceFragment.java
index bbc5b68..a7ba6c6 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/MagnificationPreferenceFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/MagnificationPreferenceFragment.java
@@ -34,9 +34,9 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.search.actionbar.SearchMenuController;
 import com.android.car.developeroptions.support.actionbar.HelpResourceProvider;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.Arrays;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/ToggleAccessibilityServicePreferenceFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/ToggleAccessibilityServicePreferenceFragment.java
index 217267a..1b8e5cd 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/ToggleAccessibilityServicePreferenceFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/ToggleAccessibilityServicePreferenceFragment.java
@@ -38,11 +38,11 @@
 
 import androidx.appcompat.app.AlertDialog;
 
-import com.android.internal.widget.LockPatternUtils;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.password.ConfirmDeviceCredentialActivity;
 import com.android.car.developeroptions.widget.ToggleSwitch;
 import com.android.car.developeroptions.widget.ToggleSwitch.OnBeforeCheckedChangeListener;
+import com.android.internal.widget.LockPatternUtils;
 import com.android.settingslib.accessibility.AccessibilityUtils;
 
 import java.util.List;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/ToggleAutoclickPreferenceFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/ToggleAutoclickPreferenceFragment.java
index db0ddb2..1fa01e6 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/ToggleAutoclickPreferenceFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/ToggleAutoclickPreferenceFragment.java
@@ -29,9 +29,9 @@
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.widget.SeekBarPreference;
 import com.android.car.developeroptions.widget.SwitchBar;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
@@ -136,8 +136,6 @@
         mDelay.setMax(delayToSeekBarProgress(MAX_AUTOCLICK_DELAY));
         mDelay.setProgress(delayToSeekBarProgress(delay));
         mDelay.setOnPreferenceChangeListener(this);
-        mFooterPreferenceMixin.createFooterPreference()
-                .setTitle(R.string.accessibility_autoclick_description);
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/ToggleDaltonizerPreferenceFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/ToggleDaltonizerPreferenceFragment.java
index 3c7685f..71fb3c9 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/ToggleDaltonizerPreferenceFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/ToggleDaltonizerPreferenceFragment.java
@@ -30,8 +30,8 @@
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.widget.SwitchBar;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
@@ -43,6 +43,7 @@
     private static final String ENABLED = Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED;
     private static final String TYPE = Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER;
     private static final int DEFAULT_TYPE = AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY;
+    private static final String KEY_DALTONIZER_FOOTER = "daltonizer_footer";
 
     private ListPreference mType;
 
@@ -62,10 +63,8 @@
 
         mType = (ListPreference) findPreference("type");
 
-        if (!ColorDisplayManager.isColorTransformAccelerated(getActivity())) {
-            mFooterPreferenceMixin.createFooterPreference().setTitle(
-                    R.string.accessibility_display_daltonizer_preference_subtitle);
-        }
+        final Preference footer = findPreference(KEY_DALTONIZER_FOOTER);
+        footer.setVisible(!ColorDisplayManager.isColorTransformAccelerated(getActivity()));
         initPreferences();
     }
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/ToggleFeaturePreferenceFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/ToggleFeaturePreferenceFragment.java
index 04a9713..5bc26d7 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/ToggleFeaturePreferenceFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accessibility/ToggleFeaturePreferenceFragment.java
@@ -29,6 +29,7 @@
 import com.android.car.developeroptions.SettingsPreferenceFragment;
 import com.android.car.developeroptions.widget.SwitchBar;
 import com.android.car.developeroptions.widget.ToggleSwitch;
+import com.android.settingslib.widget.FooterPreference;
 
 public abstract class ToggleFeaturePreferenceFragment extends SettingsPreferenceFragment {
 
@@ -138,11 +139,17 @@
         // Summary.
         if (arguments.containsKey(AccessibilitySettings.EXTRA_SUMMARY_RES)) {
             final int summary = arguments.getInt(AccessibilitySettings.EXTRA_SUMMARY_RES);
-            mFooterPreferenceMixin.createFooterPreference().setTitle(summary);
+            createFooterPreference(getText(summary));
         } else if (arguments.containsKey(AccessibilitySettings.EXTRA_SUMMARY)) {
             final CharSequence summary = arguments.getCharSequence(
                     AccessibilitySettings.EXTRA_SUMMARY);
-            mFooterPreferenceMixin.createFooterPreference().setTitle(summary);
+            createFooterPreference(summary);
         }
     }
+
+    private void createFooterPreference(CharSequence title) {
+        final PreferenceScreen preferenceScreen = getPreferenceScreen();
+        preferenceScreen.addPreference(new FooterPreference.Builder(getActivity()).setTitle(
+                title).build());
+    }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/AccountPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/AccountPreferenceController.java
index e2fbd75..9646cfc 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/AccountPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/AccountPreferenceController.java
@@ -54,7 +54,6 @@
 import com.android.car.developeroptions.core.PreferenceControllerMixin;
 import com.android.car.developeroptions.core.SubSettingLauncher;
 import com.android.car.developeroptions.overlay.FeatureFactory;
-import com.android.car.developeroptions.search.SearchIndexableRaw;
 import com.android.settingslib.RestrictedPreference;
 import com.android.settingslib.accounts.AuthenticatorHelper;
 import com.android.settingslib.core.AbstractPreferenceController;
@@ -62,6 +61,7 @@
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.core.lifecycle.events.OnPause;
 import com.android.settingslib.core.lifecycle.events.OnResume;
+import com.android.settingslib.search.SearchIndexableRaw;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/AccountSyncSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/AccountSyncSettings.java
index 5680f76..fc0f272 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/AccountSyncSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/AccountSyncSettings.java
@@ -48,6 +48,7 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.Utils;
 import com.android.car.developeroptions.widget.EntityHeaderController;
+import com.android.settingslib.widget.FooterPreference;
 
 import com.google.android.collect.Lists;
 
@@ -458,8 +459,8 @@
             syncPref.setChecked(oneTimeSyncMode || syncEnabled);
         }
         if (syncIsFailing) {
-            mFooterPreferenceMixin.createFooterPreference()
-                    .setTitle(R.string.sync_is_failing);
+            getPreferenceScreen().addPreference(new FooterPreference.Builder(
+                    getActivity()).setTitle(R.string.sync_is_failing).build());
         }
     }
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/ChooseAccountFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/ChooseAccountFragment.java
index 48c7aeb..3c055db 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/ChooseAccountFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/ChooseAccountFragment.java
@@ -20,23 +20,14 @@
 import android.content.Context;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.provider.SearchIndexableResource;
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.Utils;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
-import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
-import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.search.SearchIndexable;
-
-import java.util.ArrayList;
-import java.util.List;
 
 /**
  * Activity asking a user to select an account to be set up.
  */
-@SearchIndexable
 public class ChooseAccountFragment extends DashboardFragment {
 
     private static final String TAG = "ChooseAccountFragment";
@@ -60,8 +51,6 @@
 
         use(ChooseAccountPreferenceController.class).initialize(authorities, accountTypesFilter,
                 userHandle, getActivity());
-        use(EnterpriseDisclosurePreferenceController.class).setFooterPreferenceMixin(
-                mFooterPreferenceMixin);
     }
 
     @Override
@@ -73,35 +62,4 @@
     protected String getLogTag() {
         return TAG;
     }
-
-    @Override
-    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
-        return buildControllers(context);
-    }
-
-    private static List<AbstractPreferenceController> buildControllers(Context context) {
-        final List<AbstractPreferenceController> controllers = new ArrayList<>();
-        controllers.add(new EnterpriseDisclosurePreferenceController(context));
-        return controllers;
-    }
-
-    public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
-            new BaseSearchIndexProvider() {
-                @Override
-                public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
-                        boolean enabled) {
-                    final ArrayList<SearchIndexableResource> result = new ArrayList<>();
-
-                    final SearchIndexableResource sir = new SearchIndexableResource(context);
-                    sir.xmlResId = R.xml.add_account_settings;
-                    result.add(sir);
-                    return result;
-                }
-
-                @Override
-                public List<AbstractPreferenceController> createPreferenceControllers(
-                        Context context) {
-                    return buildControllers(context);
-                }
-            };
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/EmergencyInfoPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/EmergencyInfoPreferenceController.java
index f4d1c71..ee0216f 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/EmergencyInfoPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/EmergencyInfoPreferenceController.java
@@ -28,7 +28,7 @@
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.core.BasePreferenceController;
-import com.android.car.developeroptions.search.SearchIndexableRaw;
+import com.android.settingslib.search.SearchIndexableRaw;
 
 import java.util.List;
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/EnterpriseDisclosurePreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/EnterpriseDisclosurePreferenceController.java
index 18d5a90..889baf0 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/EnterpriseDisclosurePreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/EnterpriseDisclosurePreferenceController.java
@@ -19,32 +19,23 @@
 import android.content.Context;
 
 import androidx.annotation.VisibleForTesting;
-import androidx.preference.PreferenceScreen;
+import androidx.preference.Preference;
 
 import com.android.car.developeroptions.core.BasePreferenceController;
 import com.android.car.developeroptions.enterprise.EnterprisePrivacyFeatureProvider;
 import com.android.car.developeroptions.overlay.FeatureFactory;
-import com.android.settingslib.widget.FooterPreference;
-import com.android.settingslib.widget.FooterPreferenceMixinCompat;
 
 public class EnterpriseDisclosurePreferenceController extends BasePreferenceController {
 
     private final EnterprisePrivacyFeatureProvider mFeatureProvider;
-    private FooterPreferenceMixinCompat mFooterPreferenceMixin;
-    private PreferenceScreen mScreen;
 
-    public EnterpriseDisclosurePreferenceController(Context context) {
+    public EnterpriseDisclosurePreferenceController(Context context, String key) {
         // Preference key doesn't matter as we are creating the preference in code.
-        super(context, "add_account_enterprise_disclosure_footer");
-
+        super(context, key);
         mFeatureProvider = FeatureFactory.getFactory(mContext)
                 .getEnterprisePrivacyFeatureProvider(mContext);
     }
 
-    public void setFooterPreferenceMixin(FooterPreferenceMixinCompat footerPreferenceMixin) {
-        mFooterPreferenceMixin = footerPreferenceMixin;
-    }
-
     @Override
     public int getAvailabilityStatus() {
         if (getDisclosure() == null) {
@@ -53,27 +44,17 @@
         return AVAILABLE;
     }
 
-    @Override
-    public void displayPreference(PreferenceScreen screen) {
-        super.displayPreference(screen);
-        mScreen = screen;
-        addEnterpriseDisclosure();
-    }
-
     @VisibleForTesting
     CharSequence getDisclosure() {
         return mFeatureProvider.getDeviceOwnerDisclosure();
     }
 
-    private void addEnterpriseDisclosure() {
+    @Override
+    public void updateState(Preference preference) {
         final CharSequence disclosure = getDisclosure();
         if (disclosure == null) {
             return;
         }
-        final FooterPreference enterpriseDisclosurePreference =
-                mFooterPreferenceMixin.createFooterPreference();
-        enterpriseDisclosurePreference.setSelectable(false);
-        enterpriseDisclosurePreference.setTitle(disclosure);
-        mScreen.addPreference(enterpriseDisclosurePreference);
+        preference.setTitle(disclosure);
     }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/ManagedProfileSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/ManagedProfileSettings.java
index 65d99a6..c9fbaf3 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/ManagedProfileSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/accounts/ManagedProfileSettings.java
@@ -31,7 +31,7 @@
 import com.android.car.developeroptions.Utils;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/AppStorageSizesController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/AppStorageSizesController.java
index 5654239..5f3841d 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/AppStorageSizesController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/AppStorageSizesController.java
@@ -23,9 +23,10 @@
 import androidx.annotation.StringRes;
 import androidx.preference.Preference;
 
-import com.android.internal.util.Preconditions;
 import com.android.settingslib.applications.StorageStatsSource;
 
+import java.util.Objects;
+
 /**
  * Handles setting the sizes for the app info screen.
  */
@@ -173,10 +174,10 @@
 
         public AppStorageSizesController build() {
             return new AppStorageSizesController(
-                    Preconditions.checkNotNull(mTotalSize),
-                    Preconditions.checkNotNull(mAppSize),
-                    Preconditions.checkNotNull(mDataSize),
-                    Preconditions.checkNotNull(mCacheSize),
+                    Objects.requireNonNull(mTotalSize),
+                    Objects.requireNonNull(mAppSize),
+                    Objects.requireNonNull(mDataSize),
+                    Objects.requireNonNull(mCacheSize),
                     mComputing,
                     mError);
         }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/FetchPackageStorageAsyncLoader.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/FetchPackageStorageAsyncLoader.java
index a4713df..ca86b68 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/FetchPackageStorageAsyncLoader.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/FetchPackageStorageAsyncLoader.java
@@ -23,12 +23,12 @@
 import android.os.UserHandle;
 import android.util.Log;
 
-import com.android.internal.util.Preconditions;
 import com.android.settingslib.applications.StorageStatsSource;
 import com.android.settingslib.applications.StorageStatsSource.AppStorageStats;
 import com.android.settingslib.utils.AsyncLoaderCompat;
 
 import java.io.IOException;
+import java.util.Objects;
 
 /**
  * Fetches the storage stats using the StorageStatsManager for a given package and user tuple.
@@ -42,7 +42,7 @@
     public FetchPackageStorageAsyncLoader(Context context, @NonNull StorageStatsSource source,
             @NonNull ApplicationInfo info, @NonNull UserHandle user) {
         super(context);
-        mSource = Preconditions.checkNotNull(source);
+        mSource = Objects.requireNonNull(source);
         mInfo = info;
         mUser = user;
     }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/appops/AppOpsState.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/appops/AppOpsState.java
index 45f2975..0573320 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/appops/AppOpsState.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/appops/AppOpsState.java
@@ -28,6 +28,7 @@
 import android.os.Parcelable;
 import android.text.format.DateUtils;
 import android.util.Log;
+import android.util.Pair;
 import android.util.SparseArray;
 
 import com.android.car.developeroptions.R;
@@ -618,7 +619,8 @@
 
                         }
                         AppOpsManager.OpEntry opEntry = new AppOpsManager.OpEntry(
-                                permOps.get(k), AppOpsManager.MODE_ALLOWED);
+                                permOps.get(k), AppOpsManager.MODE_ALLOWED,
+                                Collections.emptyMap());
                         dummyOps.add(opEntry);
                         addOp(entries, pkgOps, appEntry, opEntry, packageName == null,
                                 packageName == null ? 0 : opToOrder[opEntry.getOp()]);
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/assist/ManageAssist.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/assist/ManageAssist.java
index ece7643..e86f21f 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/assist/ManageAssist.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/assist/ManageAssist.java
@@ -24,9 +24,9 @@
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.gestures.AssistGestureSettingsPreferenceController;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
@@ -68,14 +68,6 @@
         use(AssistGestureSettingsPreferenceController.class).setAssistOnly(true);
     }
 
-    @Override
-    public void onResume() {
-        super.onResume();
-
-        mFooterPreferenceMixin.createFooterPreference()
-                .setTitle(R.string.assist_footer);
-    }
-
     private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
             Lifecycle lifecycle) {
         final List<AbstractPreferenceController> controllers = new ArrayList<>();
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/defaultapps/AutofillPicker.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/defaultapps/AutofillPicker.java
index 8d63e1c..fc01ba6 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/defaultapps/AutofillPicker.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/defaultapps/AutofillPicker.java
@@ -23,8 +23,8 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.Arrays;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/managedomainurls/ManageDomainUrls.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/managedomainurls/ManageDomainUrls.java
index 28314d7..7559b50 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/managedomainurls/ManageDomainUrls.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/managedomainurls/ManageDomainUrls.java
@@ -25,7 +25,7 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/SpecialAccessSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/SpecialAccessSettings.java
index c1b35a7..6cc6bc9 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/SpecialAccessSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/SpecialAccessSettings.java
@@ -23,7 +23,7 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java
index 0d65f1b..8e559d0 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java
@@ -45,13 +45,11 @@
 import androidx.preference.PreferenceScreen;
 import androidx.preference.SwitchPreference;
 
-import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.core.BasePreferenceController;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.core.lifecycle.events.OnStart;
 import com.android.settingslib.core.lifecycle.events.OnStop;
 import com.android.settingslib.widget.FooterPreference;
-import com.android.settingslib.widget.FooterPreferenceMixinCompat;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -67,6 +65,7 @@
 
     private static final IntentFilter FILTER = new IntentFilter();
     private static final String TAG = "DeviceAdminListPrefCtrl";
+    private static final String KEY_DEVICE_ADMIN_FOOTER = "device_admin_footer";
 
     private final DevicePolicyManager mDPM;
     private final UserManager mUm;
@@ -91,7 +90,7 @@
     };
 
     private PreferenceGroup mPreferenceGroup;
-    private FooterPreferenceMixinCompat mFooterPreferenceMixin;
+    private FooterPreference mFooterPreference;
 
     static {
         FILTER.addAction(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
@@ -105,12 +104,6 @@
         mIPackageManager = AppGlobals.getPackageManager();
     }
 
-    public DeviceAdminListPreferenceController setFooterPreferenceMixin(
-            FooterPreferenceMixinCompat mixin) {
-        mFooterPreferenceMixin = mixin;
-        return this;
-    }
-
     @Override
     public int getAvailabilityStatus() {
         return AVAILABLE;
@@ -120,6 +113,7 @@
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
         mPreferenceGroup = screen.findPreference(getPreferenceKey());
+        mFooterPreference = mPreferenceGroup.findPreference(KEY_DEVICE_ADMIN_FOOTER);
     }
 
     @Override
@@ -167,10 +161,8 @@
         if (mPreferenceGroup == null) {
             return;
         }
-        if (mFooterPreferenceMixin != null) {
-            final FooterPreference footer = mFooterPreferenceMixin.createFooterPreference();
-            footer.setTitle(R.string.no_device_admins);
-            footer.setVisible(mAdmins.isEmpty());
+        if (mFooterPreference != null) {
+            mFooterPreference.setVisible(mAdmins.isEmpty());
         }
         final Map<String, SwitchPreference> preferenceCache = new ArrayMap<>();
         final Context prefContext = mPreferenceGroup.getContext();
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/deviceadmin/DeviceAdminSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/deviceadmin/DeviceAdminSettings.java
index 5e5b704..2a1b37b 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/deviceadmin/DeviceAdminSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/deviceadmin/DeviceAdminSettings.java
@@ -23,7 +23,7 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
@@ -38,13 +38,6 @@
     }
 
     @Override
-    public void onAttach(Context context) {
-        super.onAttach(context);
-        use(DeviceAdminListPreferenceController.class).setFooterPreferenceMixin(
-                mFooterPreferenceMixin);
-    }
-
-    @Override
     protected int getPreferenceScreenResId() {
         return R.xml.device_admin_settings;
     }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/financialapps/FinancialAppsSmsAccess.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/financialapps/FinancialAppsSmsAccess.java
index dbc5cea..058c132 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/financialapps/FinancialAppsSmsAccess.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/financialapps/FinancialAppsSmsAccess.java
@@ -23,7 +23,7 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/pictureinpicture/PictureInPictureSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/pictureinpicture/PictureInPictureSettings.java
index faf4841..9643354 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/pictureinpicture/PictureInPictureSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/pictureinpicture/PictureInPictureSettings.java
@@ -41,8 +41,8 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.applications.AppInfoBase;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.widget.EmptyTextSettings;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 import com.android.settingslib.widget.apppreference.AppPreference;
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/premiumsms/PremiumSmsAccess.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/premiumsms/PremiumSmsAccess.java
index d44196e..0f042ca 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/premiumsms/PremiumSmsAccess.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/premiumsms/PremiumSmsAccess.java
@@ -31,20 +31,20 @@
 import androidx.preference.PreferenceScreen;
 import androidx.preference.PreferenceViewHolder;
 
-import com.android.internal.telephony.SmsUsageMonitor;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.applications.AppStateBaseBridge.Callback;
 import com.android.car.developeroptions.applications.AppStateSmsPremBridge;
 import com.android.car.developeroptions.applications.AppStateSmsPremBridge.SmsState;
 import com.android.car.developeroptions.overlay.FeatureFactory;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.widget.EmptyTextSettings;
+import com.android.internal.telephony.SmsUsageMonitor;
 import com.android.settingslib.applications.ApplicationsState;
 import com.android.settingslib.applications.ApplicationsState.AppEntry;
 import com.android.settingslib.applications.ApplicationsState.Callbacks;
 import com.android.settingslib.applications.ApplicationsState.Session;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 import com.android.settingslib.widget.FooterPreference;
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/vrlistener/VrListenerSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/vrlistener/VrListenerSettings.java
index acf4885..bd946fa 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/vrlistener/VrListenerSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/applications/specialaccess/vrlistener/VrListenerSettings.java
@@ -27,9 +27,9 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.overlay.FeatureFactory;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.utils.ManagedServiceSettings;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/backup/BackupSettingsFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/backup/BackupSettingsFragment.java
index ef377fa..304cf6f 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/backup/BackupSettingsFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/backup/BackupSettingsFragment.java
@@ -23,8 +23,8 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/backup/UserBackupSettingsActivity.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/backup/UserBackupSettingsActivity.java
index 9c72d48..b88362b 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/backup/UserBackupSettingsActivity.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/backup/UserBackupSettingsActivity.java
@@ -28,9 +28,9 @@
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
-import com.android.car.developeroptions.search.SearchIndexableRaw;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
+import com.android.settingslib.search.SearchIndexableRaw;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/biometrics/fingerprint/FingerprintSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/biometrics/fingerprint/FingerprintSettings.java
index d3fc8de..4149228 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/biometrics/fingerprint/FingerprintSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/biometrics/fingerprint/FingerprintSettings.java
@@ -132,6 +132,7 @@
         private boolean mLaunchedConfirm;
         private Drawable mHighlightDrawable;
         private int mUserId;
+        private CharSequence mFooterTitle;
 
         private static final String TAG_AUTHENTICATE_SIDECAR = "authenticate_sidecar";
         private static final String TAG_REMOVAL_SIDECAR = "removal_sidecar";
@@ -320,7 +321,6 @@
                 launchChooseOrConfirmLock();
             }
 
-            final FooterPreference pref = mFooterPreferenceMixin.createFooterPreference();
             final EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
                     activity, DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT, mUserId);
             final AnnotationSpan.LinkInfo adminLinkInfo = new AnnotationSpan.LinkInfo(
@@ -331,11 +331,11 @@
                     activity, getString(getHelpResource()), activity.getClass().getName());
             final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo(
                     activity, ANNOTATION_URL, helpIntent);
-            pref.setTitle(AnnotationSpan.linkify(getText(admin != null
+            mFooterTitle = AnnotationSpan.linkify(getText(admin != null
                             ? R.string
                             .security_settings_fingerprint_enroll_disclaimer_lockscreen_disabled
                             : R.string.security_settings_fingerprint_enroll_disclaimer),
-                    linkInfo, adminLinkInfo));
+                    linkInfo, adminLinkInfo);
         }
 
         protected void removeFingerprintPreference(int fingerprintId) {
@@ -397,6 +397,7 @@
             root.addPreference(addPreference);
             addPreference.setOnPreferenceChangeListener(this);
             updateAddPreference();
+            createFooterPreference(root);
         }
 
         private void updateAddPreference() {
@@ -416,6 +417,15 @@
             addPreference.setEnabled(!tooMany && !removalInProgress);
         }
 
+        private void createFooterPreference(PreferenceGroup root) {
+            final Context context = getActivity();
+            if (context == null) {
+                return;
+            }
+            root.addPreference(new FooterPreference.Builder(context).setTitle(
+                    mFooterTitle).build());
+        }
+
         private static String genKey(int id) {
             return KEY_FINGERPRINT_ITEM_PREFIX + "_" + id;
         }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/bluetooth/BluetoothDetailsMacAddressController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/bluetooth/BluetoothDetailsMacAddressController.java
new file mode 100644
index 0000000..5f47f1b
--- /dev/null
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/bluetooth/BluetoothDetailsMacAddressController.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.developeroptions.bluetooth;
+
+import android.content.Context;
+
+import androidx.preference.PreferenceFragmentCompat;
+import androidx.preference.PreferenceScreen;
+
+import com.android.car.developeroptions.R;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.widget.FooterPreference;
+
+/**
+ * This class adds the device MAC address to a footer.
+ */
+public class BluetoothDetailsMacAddressController extends BluetoothDetailsController {
+    public static final String KEY_DEVICE_DETAILS_FOOTER = "device_details_footer";
+
+    private FooterPreference mFooterPreference;
+
+    public BluetoothDetailsMacAddressController(Context context,
+            PreferenceFragmentCompat fragment,
+            CachedBluetoothDevice device,
+            Lifecycle lifecycle) {
+        super(context, fragment, device, lifecycle);
+    }
+
+    @Override
+    protected void init(PreferenceScreen screen) {
+        mFooterPreference = screen.findPreference(KEY_DEVICE_DETAILS_FOOTER);
+        mFooterPreference.setTitle(mContext.getString(
+                R.string.bluetooth_device_mac_address, mCachedDevice.getAddress()));
+    }
+
+    @Override
+    protected void refresh() {
+        mFooterPreference.setTitle(mContext.getString(
+                R.string.bluetooth_device_mac_address, mCachedDevice.getAddress()));
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_DEVICE_DETAILS_FOOTER;
+    }
+}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/bluetooth/BluetoothPairingController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/bluetooth/BluetoothPairingController.java
index b016b8c..9073e4a 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/bluetooth/BluetoothPairingController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/bluetooth/BluetoothPairingController.java
@@ -294,8 +294,7 @@
         if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY) {
             mDevice.setPairingConfirmation(true);
         } else if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN) {
-            byte[] pinBytes = BluetoothDevice.convertPinToBytes(mPasskeyFormatted);
-            mDevice.setPin(pinBytes);
+            mDevice.setPin(mPasskeyFormatted);
         }
     }
 
@@ -391,17 +390,9 @@
         switch (mType) {
             case BluetoothDevice.PAIRING_VARIANT_PIN:
             case BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS:
-                byte[] pinBytes = BluetoothDevice.convertPinToBytes(passkey);
-                if (pinBytes == null) {
-                    return;
-                }
-                mDevice.setPin(pinBytes);
+                mDevice.setPin(passkey);
                 break;
 
-            case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
-                int pass = Integer.parseInt(passkey);
-                mDevice.setPasskey(pass);
-                break;
 
             case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION:
             case BluetoothDevice.PAIRING_VARIANT_CONSENT:
@@ -410,11 +401,9 @@
 
             case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY:
             case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN:
-                // Do nothing.
-                break;
-
             case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT:
-                mDevice.setRemoteOutOfBandData();
+            case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
+                // Do nothing.
                 break;
 
             default:
@@ -428,7 +417,7 @@
      */
     public void onCancel() {
         Log.d(TAG, "Pairing dialog canceled");
-        mDevice.cancelPairingUserInput();
+        mDevice.cancelPairing();
     }
 
     /**
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/bluetooth/BluetoothPairingDetail.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/bluetooth/BluetoothPairingDetail.java
index 4759453..ee66d4d 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/bluetooth/BluetoothPairingDetail.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/bluetooth/BluetoothPairingDetail.java
@@ -29,9 +29,9 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.car.developeroptions.R;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.bluetooth.BluetoothDeviceFilter;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.widget.FooterPreference;
 
 /**
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/bluetooth/BluetoothPairingService.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/bluetooth/BluetoothPairingService.java
index 7b2d4b0..5801e2c 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/bluetooth/BluetoothPairingService.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/bluetooth/BluetoothPairingService.java
@@ -85,7 +85,7 @@
             } else if (action.equals(ACTION_DISMISS_PAIRING)) {
                 Log.d(TAG, "Notification cancel " + mDevice.getAddress() + " (" +
                         mDevice.getName() + ")");
-                mDevice.cancelPairingUserInput();
+                mDevice.cancelPairing();
             } else {
                 int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
                         BluetoothDevice.ERROR);
@@ -141,7 +141,7 @@
         String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
         if (TextUtils.isEmpty(name)) {
             BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-            name = device != null ? device.getAliasName() : res.getString(android.R.string.unknownName);
+            name = device != null ? device.getAlias() : res.getString(android.R.string.unknownName);
         }
 
         Log.d(TAG, "Show pairing notification for " + mDevice.getAddress() + " (" + name + ")");
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/bluetooth/Utils.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/bluetooth/Utils.java
index 49b2d88..de7e391 100755
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/bluetooth/Utils.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/bluetooth/Utils.java
@@ -95,7 +95,8 @@
     @VisibleForTesting
     static void showConnectingError(Context context, String name, LocalBluetoothManager manager) {
         FeatureFactory.getFactory(context).getMetricsFeatureProvider().visible(context,
-            SettingsEnums.PAGE_UNKNOWN, SettingsEnums.ACTION_SETTINGS_BLUETOOTH_CONNECT_ERROR);
+                SettingsEnums.PAGE_UNKNOWN, SettingsEnums.ACTION_SETTINGS_BLUETOOTH_CONNECT_ERROR,
+                0);
         showError(context, name, R.string.bluetooth_connecting_error_message, manager);
     }
 
@@ -127,7 +128,7 @@
     }
 
     public static String createRemoteName(Context context, BluetoothDevice device) {
-        String mRemoteName = device != null ? device.getAliasName() : null;
+        String mRemoteName = device != null ? device.getAlias() : null;
 
         if (mRemoteName == null) {
             mRemoteName = context.getString(R.string.unknown);
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/BluetoothDashboardFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/BluetoothDashboardFragment.java
index ed2ec98..de09849 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/BluetoothDashboardFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/BluetoothDashboardFragment.java
@@ -28,11 +28,11 @@
 import com.android.car.developeroptions.core.TogglePreferenceController;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.SearchIndexableRaw;
 import com.android.car.developeroptions.widget.SwitchBar;
 import com.android.car.developeroptions.widget.SwitchBarController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.search.SearchIndexable;
+import com.android.settingslib.search.SearchIndexableRaw;
 import com.android.settingslib.widget.FooterPreference;
 
 import java.util.ArrayList;
@@ -46,6 +46,7 @@
 public class BluetoothDashboardFragment extends DashboardFragment {
 
     private static final String TAG = "BluetoothDashboardFrag";
+    private static final String KEY_BLUETOOTH_SCREEN_FOOTER = "bluetooth_screen_footer";
     public static final String KEY_BLUETOOTH_SCREEN = "bluetooth_switchbar_screen";
 
     private FooterPreference mFooterPreference;
@@ -75,7 +76,7 @@
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
-        mFooterPreference = mFooterPreferenceMixin.createFooterPreference();
+        mFooterPreference = findPreference(KEY_BLUETOOTH_SCREEN_FOOTER);
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/ConnectedDeviceDashboardFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/ConnectedDeviceDashboardFragment.java
index 1f0985c..279224f 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/ConnectedDeviceDashboardFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/ConnectedDeviceDashboardFragment.java
@@ -26,11 +26,8 @@
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
 import com.android.car.developeroptions.slices.SlicePreferenceController;
-import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.search.SearchIndexable;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
@@ -65,31 +62,11 @@
     }
 
     @Override
-    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
-        return buildPreferenceControllers(context, getSettingsLifecycle());
-    }
-
-    private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
-            Lifecycle lifecycle) {
-        final List<AbstractPreferenceController> controllers = new ArrayList<>();
-        final DiscoverableFooterPreferenceController discoverableFooterPreferenceController =
-                new DiscoverableFooterPreferenceController(context);
-        controllers.add(discoverableFooterPreferenceController);
-
-        if (lifecycle != null) {
-            lifecycle.addObserver(discoverableFooterPreferenceController);
-        }
-
-        return controllers;
-    }
-
-    @Override
     public void onAttach(Context context) {
         super.onAttach(context);
         use(AvailableMediaDeviceGroupController.class).init(this);
         use(ConnectedDeviceGroupController.class).init(this);
         use(PreviouslyConnectedDevicePreferenceController.class).init(this);
-        use(DiscoverableFooterPreferenceController.class).init(this);
         use(SlicePreferenceController.class).setSliceUri(
                 Uri.parse(getString(R.string.config_nearby_devices_slice_uri)));
     }
@@ -106,11 +83,5 @@
                     sir.xmlResId = R.xml.connected_devices;
                     return Arrays.asList(sir);
                 }
-
-                @Override
-                public List<AbstractPreferenceController> createPreferenceControllers(Context
-                        context) {
-                    return buildPreferenceControllers(context, null /* lifecycle */);
-                }
             };
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/DiscoverableFooterPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/DiscoverableFooterPreferenceController.java
index 088ab38..0f8f38e 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/DiscoverableFooterPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/DiscoverableFooterPreferenceController.java
@@ -32,32 +32,29 @@
 import com.android.car.developeroptions.bluetooth.AlwaysDiscoverable;
 import com.android.car.developeroptions.bluetooth.Utils;
 import com.android.car.developeroptions.core.BasePreferenceController;
-import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnPause;
-import com.android.settingslib.core.lifecycle.events.OnResume;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
 import com.android.settingslib.widget.FooterPreference;
-import com.android.settingslib.widget.FooterPreferenceMixinCompat;
 
 /**
  * Controller that shows and updates the bluetooth device name
  */
 public class DiscoverableFooterPreferenceController extends BasePreferenceController
-        implements LifecycleObserver, OnResume, OnPause {
+        implements LifecycleObserver, OnStart, OnStop {
     private static final String KEY = "discoverable_footer_preference";
 
     @VisibleForTesting
     BroadcastReceiver mBluetoothChangedReceiver;
     @VisibleForTesting
     LocalBluetoothManager mLocalManager;
-    private FooterPreferenceMixinCompat mFooterPreferenceMixin;
-    private FooterPreference mPreference;
     private BluetoothAdapter mBluetoothAdapter;
     private AlwaysDiscoverable mAlwaysDiscoverable;
+    private FooterPreference mPreference;
 
-    public DiscoverableFooterPreferenceController(Context context) {
-        super(context, KEY);
+    public DiscoverableFooterPreferenceController(Context context, String key) {
+        super(context, key);
         mLocalManager = Utils.getLocalBtManager(context);
         if (mLocalManager == null) {
             return;
@@ -67,53 +64,21 @@
         initReceiver();
     }
 
-    private void initReceiver() {
-        mBluetoothChangedReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
-                    final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
-                            BluetoothAdapter.ERROR);
-                    updateFooterPreferenceTitle(state);
-                }
-            }
-        };
-    }
-
-    public void init(DashboardFragment fragment) {
-        mFooterPreferenceMixin = new FooterPreferenceMixinCompat(fragment,
-                fragment.getSettingsLifecycle());
-    }
-
-    @VisibleForTesting
-    void init(FooterPreferenceMixinCompat footerPreferenceMixin, FooterPreference preference,
-            AlwaysDiscoverable alwaysDiscoverable) {
-        mFooterPreferenceMixin = footerPreferenceMixin;
-        mPreference = preference;
-        mAlwaysDiscoverable = alwaysDiscoverable;
-    }
-
     @Override
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
-        addFooterPreference(screen);
+        mPreference = screen.findPreference(getPreferenceKey());
     }
 
     @Override
     public int getAvailabilityStatus() {
         return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)
-                ? AVAILABLE
+                ? AVAILABLE_UNSEARCHABLE
                 : UNSUPPORTED_ON_DEVICE;
     }
 
-    private void addFooterPreference(PreferenceScreen screen) {
-        mPreference = mFooterPreferenceMixin.createFooterPreference();
-        mPreference.setKey(KEY);
-        screen.addPreference(mPreference);
-    }
-
     @Override
-    public void onResume() {
+    public void onStart() {
         if (mLocalManager == null) {
             return;
         }
@@ -124,7 +89,7 @@
     }
 
     @Override
-    public void onPause() {
+    public void onStop() {
         if (mLocalManager == null) {
             return;
         }
@@ -132,7 +97,7 @@
         mAlwaysDiscoverable.stop();
     }
 
-    private void updateFooterPreferenceTitle (int bluetoothState) {
+    private void updateFooterPreferenceTitle(int bluetoothState) {
         if (bluetoothState == BluetoothAdapter.STATE_ON) {
             mPreference.setTitle(getPreferenceTitle());
         } else {
@@ -150,4 +115,17 @@
                 mContext.getText(R.string.bluetooth_device_name_summary),
                 BidiFormatter.getInstance().unicodeWrap(deviceName));
     }
-}
\ No newline at end of file
+
+    private void initReceiver() {
+        mBluetoothChangedReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
+                    final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
+                            BluetoothAdapter.ERROR);
+                    updateFooterPreferenceTitle(state);
+                }
+            }
+        };
+    }
+}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/PreviouslyConnectedDeviceDashboardFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/PreviouslyConnectedDeviceDashboardFragment.java
index 924c9b2..a776476 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/PreviouslyConnectedDeviceDashboardFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/PreviouslyConnectedDeviceDashboardFragment.java
@@ -22,8 +22,8 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.SearchIndexableRaw;
 import com.android.settingslib.search.SearchIndexable;
+import com.android.settingslib.search.SearchIndexableRaw;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/usb/UsbDefaultFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/usb/UsbDefaultFragment.java
index 411153c..2b823ce 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/usb/UsbDefaultFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/usb/UsbDefaultFragment.java
@@ -32,7 +32,6 @@
 import com.android.car.developeroptions.widget.RadioButtonPickerFragment;
 import com.android.settingslib.widget.CandidateInfo;
 import com.android.settingslib.widget.FooterPreference;
-import com.android.settingslib.widget.FooterPreferenceMixinCompat;
 
 import com.google.android.collect.Lists;
 
@@ -61,10 +60,8 @@
     @Override
     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
         super.onCreatePreferences(savedInstanceState, rootKey);
-        FooterPreferenceMixinCompat footer = new FooterPreferenceMixinCompat(this,
-                this.getSettingsLifecycle());
-        FooterPreference pref = footer.createFooterPreference();
-        pref.setTitle(R.string.usb_default_info);
+        getPreferenceScreen().addPreference(new FooterPreference.Builder(getActivity()).setTitle(
+                R.string.usb_default_info).build());
     }
 
     @Override
@@ -149,4 +146,4 @@
             updateCandidates();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/usb/UsbDetailsFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/usb/UsbDetailsFragment.java
index ff58f89..1c90cf0 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/usb/UsbDetailsFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/connecteddevice/usb/UsbDetailsFragment.java
@@ -25,8 +25,8 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import com.google.android.collect.Lists;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/core/BasePreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/core/BasePreferenceController.java
index 73f735c..fc51221 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/core/BasePreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/core/BasePreferenceController.java
@@ -21,10 +21,10 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
-import com.android.car.developeroptions.search.SearchIndexableRaw;
 import com.android.car.developeroptions.slices.SliceData;
 import com.android.car.developeroptions.slices.Sliceable;
 import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.search.SearchIndexableRaw;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/core/PreferenceControllerMixin.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/core/PreferenceControllerMixin.java
index bc1b7a6..30df488 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/core/PreferenceControllerMixin.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/core/PreferenceControllerMixin.java
@@ -18,8 +18,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import com.android.car.developeroptions.search.SearchIndexableRaw;
 import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.search.SearchIndexableRaw;
 
 import java.util.List;
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/core/instrumentation/SettingsIntelligenceLogWriter.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/core/instrumentation/SettingsIntelligenceLogWriter.java
index 6112713..ae28c96 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/core/instrumentation/SettingsIntelligenceLogWriter.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/core/instrumentation/SettingsIntelligenceLogWriter.java
@@ -61,21 +61,21 @@
     }
 
     @Override
-    public void visible(Context context, int attribution, int pageId) {
-        action(attribution /* attribution */,
+    public void visible(Context context, int attribution, int pageId, int latency) {
+        action(attribution /* from pageId */,
                 SettingsEnums.PAGE_VISIBLE /* action */,
-                pageId /* pageId */,
+                pageId /* target pageId */,
                 "" /* changedPreferenceKey */,
-                0 /* changedPreferenceIntValue */);
+                latency /* changedPreferenceIntValue */);
     }
 
     @Override
-    public void hidden(Context context, int pageId) {
+    public void hidden(Context context, int pageId, int visibleTime) {
         action(SettingsEnums.PAGE_UNKNOWN /* attribution */,
                 SettingsEnums.PAGE_HIDE /* action */,
                 pageId /* pageId */,
                 "" /* changedPreferenceKey */,
-                0 /* changedPreferenceIntValue */);
+                visibleTime /* changedPreferenceIntValue */);
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/core/instrumentation/StatsLogWriter.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/core/instrumentation/StatsLogWriter.java
index ae0dbeb..61a1f44 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/core/instrumentation/StatsLogWriter.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/core/instrumentation/StatsLogWriter.java
@@ -19,30 +19,30 @@
 import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.util.Pair;
-import android.util.StatsLog;
 
+import com.android.settings.core.instrumentation.SettingsStatsLog;
 import com.android.settingslib.core.instrumentation.LogWriter;
 
 public class StatsLogWriter implements LogWriter {
 
     @Override
-    public void visible(Context context, int attribution, int pageId) {
-        StatsLog.write(StatsLog.SETTINGS_UI_CHANGED /* Atom name */,
-                attribution,
+    public void visible(Context context, int attribution, int pageId, int latency) {
+        SettingsStatsLog.write(SettingsStatsLog.SETTINGS_UI_CHANGED /* Atom name */,
+                attribution, /* from pageId */
                 SettingsEnums.PAGE_VISIBLE /* action */,
-                pageId,
-                null /* changedPreferenceKey */,
-                0 /* changedPreferenceIntValue */);
+                pageId, /* target pageId */
+                "" /* changedPreferenceKey */,
+                latency /* changedPreferenceIntValue */);
     }
 
     @Override
-    public void hidden(Context context, int pageId) {
-        StatsLog.write(StatsLog.SETTINGS_UI_CHANGED /* Atom name */,
+    public void hidden(Context context, int pageId, int visibleTime) {
+        SettingsStatsLog.write(SettingsStatsLog.SETTINGS_UI_CHANGED /* Atom name */,
                 SettingsEnums.PAGE_UNKNOWN /* attribution */,
                 SettingsEnums.PAGE_HIDE /* action */,
                 pageId,
-                null /* changedPreferenceKey */,
-                0 /* changedPreferenceIntValue */);
+                "" /* changedPreferenceKey */,
+                visibleTime /* changedPreferenceIntValue */);
     }
 
     @Override
@@ -83,7 +83,7 @@
 
     @Override
     public void action(int attribution, int action, int pageId, String key, int value) {
-        StatsLog.write(StatsLog.SETTINGS_UI_CHANGED /* atomName */,
+        SettingsStatsLog.write(SettingsStatsLog.SETTINGS_UI_CHANGED /* atomName */,
                 attribution,
                 action,
                 pageId,
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/dashboard/DashboardFeatureProviderImpl.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/dashboard/DashboardFeatureProviderImpl.java
index db6efbf..de184cf 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/dashboard/DashboardFeatureProviderImpl.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/dashboard/DashboardFeatureProviderImpl.java
@@ -18,6 +18,8 @@
 
 import static android.content.Intent.EXTRA_USER;
 
+import static com.android.settingslib.drawer.SwitchesProvider.METHOD_GET_DYNAMIC_SUMMARY;
+import static com.android.settingslib.drawer.SwitchesProvider.METHOD_GET_PROVIDER_ICON;
 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_URI;
 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY;
 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY_URI;
@@ -30,6 +32,7 @@
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -180,7 +183,8 @@
 
             ThreadUtils.postOnBackgroundThread(() -> {
                 final Map<String, IContentProvider> providerMap = new ArrayMap<>();
-                final String uri = tile.getMetaData().getString(META_DATA_PREFERENCE_SUMMARY_URI);
+                final Uri uri = TileUtils.getCompleteUri(tile, META_DATA_PREFERENCE_SUMMARY_URI,
+                        METHOD_GET_DYNAMIC_SUMMARY);
                 final String summaryFromUri = TileUtils.getTextFromUri(
                         mContext, uri, providerMap, META_DATA_PREFERENCE_SUMMARY);
                 ThreadUtils.postOnMainThread(() -> preference.setSummary(summaryFromUri));
@@ -214,7 +218,8 @@
                     packageName = intent.getComponent().getPackageName();
                 }
                 final Map<String, IContentProvider> providerMap = new ArrayMap<>();
-                final String uri = tile.getMetaData().getString(META_DATA_PREFERENCE_ICON_URI);
+                final Uri uri = TileUtils.getCompleteUri(tile, META_DATA_PREFERENCE_ICON_URI,
+                        METHOD_GET_PROVIDER_ICON);
                 final Pair<String, Integer> iconInfo = TileUtils.getIconFromUri(
                         mContext, packageName, uri, providerMap);
                 if (iconInfo == null) {
@@ -238,16 +243,15 @@
         ProfileSelectDialog.updateUserHandlesIfNeeded(mContext, tile);
 
         if (tile.userHandle == null || tile.isPrimaryProfileOnly()) {
-            mMetricsFeatureProvider.logDashboardStartIntent(mContext, intent, sourceMetricCategory);
+            mMetricsFeatureProvider.logStartedIntent(intent, sourceMetricCategory);
             activity.startActivityForResult(intent, 0);
         } else if (tile.userHandle.size() == 1) {
-            mMetricsFeatureProvider.logDashboardStartIntent(mContext, intent, sourceMetricCategory);
+            mMetricsFeatureProvider.logStartedIntent(intent, sourceMetricCategory);
             activity.startActivityForResultAsUser(intent, 0, tile.userHandle.get(0));
         } else {
             final UserHandle userHandle = intent.getParcelableExtra(EXTRA_USER);
             if (userHandle != null && tile.userHandle.contains(userHandle)) {
-                mMetricsFeatureProvider.logDashboardStartIntent(
-                    mContext, intent, sourceMetricCategory);
+                mMetricsFeatureProvider.logStartedIntent(intent, sourceMetricCategory);
                 activity.startActivityForResultAsUser(intent, 0, userHandle);
             } else {
                 ProfileSelectDialog.show(activity.getSupportFragmentManager(), tile);
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/dashboard/DashboardFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/dashboard/DashboardFragment.java
index e7323c6..a08ad0f 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/dashboard/DashboardFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/dashboard/DashboardFragment.java
@@ -35,12 +35,12 @@
 import com.android.car.developeroptions.core.PreferenceControllerListHelper;
 import com.android.car.developeroptions.core.SettingsBaseActivity;
 import com.android.car.developeroptions.overlay.FeatureFactory;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.drawer.DashboardCategory;
 import com.android.settingslib.drawer.Tile;
+import com.android.settingslib.search.Indexable;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -197,8 +197,7 @@
         Collection<List<AbstractPreferenceController>> controllers =
                 mPreferenceControllers.values();
         // If preference contains intent, log it before handling.
-        mMetricsFeatureProvider.logDashboardStartIntent(
-                getContext(), preference.getIntent(), getMetricsCategory());
+        mMetricsFeatureProvider.logStartedIntent(preference.getIntent(), getMetricsCategory());
         // Give all controllers a chance to handle click.
         for (List<AbstractPreferenceController> controllerList : controllers) {
             for (AbstractPreferenceController controller : controllerList) {
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datausage/BillingCycleSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datausage/BillingCycleSettings.java
index 1b648a9..51dbcb9 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datausage/BillingCycleSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datausage/BillingCycleSettings.java
@@ -26,7 +26,6 @@
 import android.net.NetworkTemplate;
 import android.os.Bundle;
 import android.provider.SearchIndexableResource;
-import android.text.format.Time;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -43,13 +42,14 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.core.instrumentation.InstrumentedDialogFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.NetworkPolicyEditor;
 import com.android.settingslib.net.DataUsageController;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.TimeZone;
 
 @SearchIndexable
 public class BillingCycleSettings extends DataUsageBaseFragment implements
@@ -118,8 +118,6 @@
         mEnableDataLimit = (SwitchPreference) findPreference(KEY_SET_DATA_LIMIT);
         mEnableDataLimit.setOnPreferenceChangeListener(this);
         mDataLimit = findPreference(KEY_DATA_LIMIT);
-
-        mFooterPreferenceMixin.createFooterPreference().setTitle(R.string.data_warning_footnote);
     }
 
     @Override
@@ -405,7 +403,7 @@
             mCycleDayPicker.clearFocus();
 
             final int cycleDay = mCycleDayPicker.getValue();
-            final String cycleTimezone = new Time().timezone;
+            final String cycleTimezone = TimeZone.getDefault().getID();
             editor.setPolicyCycleDay(template, cycleDay, cycleTimezone);
             target.updateDataUsage();
         }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datausage/DataSaverSummary.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datausage/DataSaverSummary.java
index 081347f..901b869 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datausage/DataSaverSummary.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datausage/DataSaverSummary.java
@@ -30,13 +30,13 @@
 import com.android.car.developeroptions.applications.AppStateBaseBridge.Callback;
 import com.android.car.developeroptions.datausage.DataSaverBackend.Listener;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.widget.SwitchBar;
 import com.android.car.developeroptions.widget.SwitchBar.OnSwitchChangeListener;
 import com.android.settingslib.applications.ApplicationsState;
 import com.android.settingslib.applications.ApplicationsState.AppEntry;
 import com.android.settingslib.applications.ApplicationsState.Callbacks;
 import com.android.settingslib.applications.ApplicationsState.Session;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
@@ -63,8 +63,6 @@
         super.onCreate(icicle);
 
         addPreferencesFromResource(R.xml.data_saver);
-        mFooterPreferenceMixin.createFooterPreference()
-                .setTitle(com.android.internal.R.string.data_saver_description);
         mUnrestrictedAccess = findPreference(KEY_UNRESTRICTED_ACCESS);
         mApplicationsState = ApplicationsState.getInstance(
                 (Application) getContext().getApplicationContext());
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datausage/DataUsageSummary.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datausage/DataUsageSummary.java
index 0e78bce..61aeab2 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datausage/DataUsageSummary.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datausage/DataUsageSummary.java
@@ -38,10 +38,10 @@
 import com.android.car.developeroptions.Utils;
 import com.android.car.developeroptions.dashboard.SummaryLoader;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.NetworkPolicyEditor;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.net.DataUsageController;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datausage/DataUsageSummaryPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datausage/DataUsageSummaryPreferenceController.java
index b2576f7..bccb280 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datausage/DataUsageSummaryPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datausage/DataUsageSummaryPreferenceController.java
@@ -19,8 +19,11 @@
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.INetworkPolicyManager;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkTemplate;
+import android.os.ServiceManager;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionPlan;
@@ -34,11 +37,11 @@
 import androidx.preference.PreferenceFragmentCompat;
 import androidx.recyclerview.widget.RecyclerView;
 
-import com.android.internal.util.CollectionUtils;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.core.BasePreferenceController;
 import com.android.car.developeroptions.core.PreferenceControllerMixin;
 import com.android.car.developeroptions.widget.EntityHeaderController;
+import com.android.internal.util.CollectionUtils;
 import com.android.settingslib.NetworkPolicyEditor;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -297,12 +300,51 @@
                 mSnapshotTime = primaryPlan.getDataUsageTime();
             }
         }
-        mManageSubscriptionIntent =
-                mSubscriptionManager.createManageSubscriptionIntent(mSubscriptionId);
+        mManageSubscriptionIntent = createManageSubscriptionIntent(mSubscriptionId);
         Log.i(TAG, "Have " + mDataplanCount + " plans, dflt sub-id " + mSubscriptionId
                 + ", intent " + mManageSubscriptionIntent);
     }
 
+    /**
+     * Create an {@link Intent} that can be launched towards the carrier app
+     * that is currently defining the billing relationship plan through
+     * {@link INetworkPolicyManager#setSubscriptionPlans(int, SubscriptionPlan [], String)}.
+     *
+     * @return ready to launch Intent targeted towards the carrier app, or
+     *         {@code null} if no carrier app is defined, or if the defined
+     *         carrier app provides no management activity.
+     */
+    private Intent createManageSubscriptionIntent(int subId) {
+        INetworkPolicyManager networkPolicyManager = INetworkPolicyManager.Stub.asInterface(
+                ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
+        String owner = "";
+        try {
+            owner = networkPolicyManager.getSubscriptionPlansOwner(subId);
+        } catch (Exception ex) {
+            Log.w("Fail to get subscription plan owner for subId " + subId, ex);
+        }
+
+        if (TextUtils.isEmpty(owner)) {
+            return null;
+        }
+
+        List<SubscriptionPlan> plans = mSubscriptionManager.getSubscriptionPlans(subId);
+        if (plans.isEmpty()) {
+            return null;
+        }
+
+        Intent intent = new Intent(SubscriptionManager.ACTION_MANAGE_SUBSCRIPTION_PLANS);
+        intent.setPackage(owner);
+        intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
+
+        if (mContext.getPackageManager().queryIntentActivities(intent,
+                PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) {
+            return null;
+        }
+
+        return intent;
+    }
+
     public static SubscriptionPlan getPrimaryPlan(SubscriptionManager subManager, int primaryId) {
         List<SubscriptionPlan> plans = subManager.getSubscriptionPlans(primaryId);
         if (CollectionUtils.isEmpty(plans)) {
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datausage/UnrestrictedDataAccess.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datausage/UnrestrictedDataAccess.java
index 9f1e7b7..f0f8c46 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datausage/UnrestrictedDataAccess.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datausage/UnrestrictedDataAccess.java
@@ -26,9 +26,9 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.applications.ApplicationsState;
 import com.android.settingslib.applications.ApplicationsState.AppFilter;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/AutoTimePreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/AutoTimePreferenceController.java
index 6bf6d2d..cdac6ac 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/AutoTimePreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/AutoTimePreferenceController.java
@@ -17,6 +17,8 @@
 package com.android.car.developeroptions.datetime;
 
 import android.content.Context;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 
 import androidx.preference.Preference;
@@ -75,6 +77,7 @@
     }
 
     private RestrictedLockUtils.EnforcedAdmin getEnforcedAdminProperty() {
-        return RestrictedLockUtilsInternal.checkIfAutoTimeRequired(mContext);
+        return RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
+                mContext, UserManager.DISALLOW_CONFIG_DATE_TIME, UserHandle.myUserId());
     }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/DatePreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/DatePreferenceController.java
index 2434f1b..99625d7 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/DatePreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/DatePreferenceController.java
@@ -17,8 +17,9 @@
 package com.android.car.developeroptions.datetime;
 
 import android.app.Activity;
-import android.app.AlarmManager;
 import android.app.DatePickerDialog;
+import android.app.timedetector.ManualTimeSuggestion;
+import android.app.timedetector.TimeDetector;
 import android.content.Context;
 import android.text.TextUtils;
 import android.text.format.DateFormat;
@@ -119,7 +120,10 @@
         long when = Math.max(c.getTimeInMillis(), DatePreferenceHost.MIN_DATE);
 
         if (when / 1000 < Integer.MAX_VALUE) {
-            ((AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE)).setTime(when);
+            TimeDetector timeDetector = mContext.getSystemService(TimeDetector.class);
+            ManualTimeSuggestion manualTimeSuggestion =
+                    TimeDetector.createManualTimeSuggestion(when, "Settings: Set date");
+            timeDetector.suggestManualTime(manualTimeSuggestion);
         }
     }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/TimePreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/TimePreferenceController.java
index aeabc6e..ef0e7a9 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/TimePreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/TimePreferenceController.java
@@ -17,8 +17,9 @@
 package com.android.car.developeroptions.datetime;
 
 import android.app.Activity;
-import android.app.AlarmManager;
 import android.app.TimePickerDialog;
+import android.app.timedetector.ManualTimeSuggestion;
+import android.app.timedetector.TimeDetector;
 import android.content.Context;
 import android.text.TextUtils;
 import android.text.format.DateFormat;
@@ -117,7 +118,10 @@
         long when = Math.max(c.getTimeInMillis(), TimePreferenceHost.MIN_DATE);
 
         if (when / 1000 < Integer.MAX_VALUE) {
-            ((AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE)).setTime(when);
+            TimeDetector timeDetector = mContext.getSystemService(TimeDetector.class);
+            ManualTimeSuggestion manualTimeSuggestion =
+                    TimeDetector.createManualTimeSuggestion(when, "Settings: Set time");
+            timeDetector.suggestManualTime(manualTimeSuggestion);
         }
     }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/timezone/TimeZoneInfoPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/timezone/TimeZoneInfoPreferenceController.java
index e31136a..abc2f0e 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/timezone/TimeZoneInfoPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/timezone/TimeZoneInfoPreferenceController.java
@@ -26,23 +26,21 @@
 import android.icu.util.TimeZoneTransition;
 
 import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
 
 import com.android.car.developeroptions.R;
-import com.android.settingslib.widget.FooterPreference;
+import com.android.car.developeroptions.core.BasePreferenceController;
 
 import java.util.Date;
 
-public class TimeZoneInfoPreferenceController extends BaseTimeZonePreferenceController {
+public class TimeZoneInfoPreferenceController extends BasePreferenceController {
 
-    private static final String PREFERENCE_KEY = FooterPreference.KEY_FOOTER;
     @VisibleForTesting
     Date mDate;
     private TimeZoneInfo mTimeZoneInfo;
     private final DateFormat mDateFormat;
 
-    public TimeZoneInfoPreferenceController(Context context) {
-        super(context, PREFERENCE_KEY);
+    public TimeZoneInfoPreferenceController(Context context, String key) {
+        super(context, key);
         mDateFormat = DateFormat.getDateInstance(SimpleDateFormat.LONG);
         mDateFormat.setContext(DisplayContext.CAPITALIZATION_NONE);
         mDate = new Date();
@@ -50,24 +48,18 @@
 
     @Override
     public int getAvailabilityStatus() {
-        return AVAILABLE;
+        return mTimeZoneInfo != null ? AVAILABLE_UNSEARCHABLE : UNSUPPORTED_ON_DEVICE;
     }
 
     @Override
-    public void updateState(Preference preference) {
-        CharSequence formattedTimeZone = mTimeZoneInfo == null ? "" : formatInfo(mTimeZoneInfo);
-        preference.setTitle(formattedTimeZone);
-        preference.setVisible(mTimeZoneInfo != null);
+    public CharSequence getSummary() {
+        return mTimeZoneInfo == null ? "" : formatInfo(mTimeZoneInfo);
     }
 
     public void setTimeZoneInfo(TimeZoneInfo timeZoneInfo) {
         mTimeZoneInfo = timeZoneInfo;
     }
 
-    public TimeZoneInfo getTimeZoneInfo() {
-        return mTimeZoneInfo;
-    }
-
     private CharSequence formatOffsetAndName(TimeZoneInfo item) {
         String name = item.getGenericName();
         if (name == null) {
@@ -130,5 +122,4 @@
         } while (transition != null);
         return transition;
     }
-
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/timezone/TimeZoneSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/timezone/TimeZoneSettings.java
index 4f43cd3..481e6ba 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/timezone/TimeZoneSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/timezone/TimeZoneSettings.java
@@ -17,8 +17,9 @@
 package com.android.car.developeroptions.datetime.timezone;
 
 import android.app.Activity;
-import android.app.AlarmManager;
 import android.app.settings.SettingsEnums;
+import android.app.timezonedetector.ManualTimeZoneSuggestion;
+import android.app.timezonedetector.TimeZoneDetector;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
@@ -270,7 +271,10 @@
             editor.putString(PREF_KEY_REGION, regionId);
         }
         editor.apply();
-        getActivity().getSystemService(AlarmManager.class).setTimeZone(tzId);
+        TimeZoneDetector timeZoneDetector = getActivity().getSystemService(TimeZoneDetector.class);
+        ManualTimeZoneSuggestion suggestion = TimeZoneDetector.createManualTimeZoneSuggestion(
+                tzId, "Settings: Set time zone");
+        timeZoneDetector.suggestManualTimeZone(suggestion);
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/timezone/model/FilteredCountryTimeZones.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/timezone/model/FilteredCountryTimeZones.java
index b8a56c6..48f7ab3 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/timezone/model/FilteredCountryTimeZones.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/datetime/timezone/model/FilteredCountryTimeZones.java
@@ -48,9 +48,10 @@
         mCountryTimeZones = countryTimeZones;
         List<String> timeZoneIds = countryTimeZones.getTimeZoneMappings().stream()
                 .filter(timeZoneMapping ->
-                        timeZoneMapping.showInPicker && (timeZoneMapping.notUsedAfter == null
-                                || timeZoneMapping.notUsedAfter >= MIN_USE_DATE_OF_TIMEZONE))
-                .map(timeZoneMapping -> timeZoneMapping.timeZoneId)
+                        timeZoneMapping.isShownInPicker()
+                                && (timeZoneMapping.getNotUsedAfter() == null
+                                || timeZoneMapping.getNotUsedAfter() >= MIN_USE_DATE_OF_TIMEZONE))
+                .map(timeZoneMapping -> timeZoneMapping.getTimeZoneId())
                 .collect(Collectors.toList());
         mTimeZoneIds = Collections.unmodifiableList(timeZoneIds);
     }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deletionhelper/AutomaticStorageManagerSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deletionhelper/AutomaticStorageManagerSettings.java
index 6ff0fb9..93edf9f 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deletionhelper/AutomaticStorageManagerSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deletionhelper/AutomaticStorageManagerSettings.java
@@ -34,9 +34,9 @@
 import com.android.car.developeroptions.Utils;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.widget.SwitchBar;
 import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deletionhelper/AutomaticStorageManagerSwitchBarController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deletionhelper/AutomaticStorageManagerSwitchBarController.java
index 342e44f..a46c7b1 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deletionhelper/AutomaticStorageManagerSwitchBarController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deletionhelper/AutomaticStorageManagerSwitchBarController.java
@@ -25,11 +25,12 @@
 import androidx.fragment.app.FragmentManager;
 import androidx.preference.Preference;
 
-import com.android.internal.util.Preconditions;
 import com.android.car.developeroptions.widget.SwitchBar;
 import com.android.settingslib.Utils;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
+import java.util.Objects;
+
 /** Handles the logic for flipping the storage management toggle on a {@link SwitchBar}. */
 public class AutomaticStorageManagerSwitchBarController
         implements SwitchBar.OnSwitchChangeListener {
@@ -48,11 +49,11 @@
             MetricsFeatureProvider metrics,
             Preference daysToRetainPreference,
             FragmentManager fragmentManager) {
-        mContext = Preconditions.checkNotNull(context);
-        mSwitchBar = Preconditions.checkNotNull(switchBar);
-        mMetrics = Preconditions.checkNotNull(metrics);
-        mDaysToRetainPreference = Preconditions.checkNotNull(daysToRetainPreference);
-        mFragmentManager = Preconditions.checkNotNull(fragmentManager);
+        mContext = Objects.requireNonNull(context);
+        mSwitchBar = Objects.requireNonNull(switchBar);
+        mMetrics = Objects.requireNonNull(metrics);
+        mDaysToRetainPreference = Objects.requireNonNull(daysToRetainPreference);
+        mFragmentManager = Objects.requireNonNull(fragmentManager);
 
         initializeCheckedStatus();
     }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/AbstractBluetoothA2dpPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/AbstractBluetoothA2dpPreferenceController.java
index d4afe48..441ea56 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/AbstractBluetoothA2dpPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/AbstractBluetoothA2dpPreferenceController.java
@@ -83,7 +83,10 @@
         final BluetoothCodecConfig codecConfig = mBluetoothA2dpConfigStore.createCodecConfig();
         synchronized (mBluetoothA2dpConfigStore) {
             if (mBluetoothA2dp != null) {
-                setCodecConfigPreference(null, codecConfig);    // Use current active device
+                BluetoothDevice activeDevice = mBluetoothA2dp.getActiveDevice();
+                if (activeDevice != null) {
+                    setCodecConfigPreference(mBluetoothA2dp.getActiveDevice(), codecConfig);
+                }
             }
         }
         // Because the setting is not persisted into permanent storage, we cannot call update state
@@ -102,13 +105,17 @@
 
     @Override
     public void updateState(Preference preference) {
-        if (getCodecConfig(null) == null || mPreference == null) { // Use current active device
+        if (mBluetoothA2dp == null) {
+            return;
+        }
+        BluetoothDevice activeDevice = mBluetoothA2dp.getActiveDevice();
+        if (activeDevice == null || getCodecConfig(activeDevice) == null || mPreference == null) {
             return;
         }
 
         BluetoothCodecConfig codecConfig;
         synchronized (mBluetoothA2dpConfigStore) {
-            codecConfig = getCodecConfig(null);         // Use current active device
+            codecConfig = getCodecConfig(activeDevice);         // Use current active device
         }
 
         final int index = getCurrentA2dpSettingIndex(codecConfig);
@@ -178,13 +185,22 @@
     @VisibleForTesting
     void setCodecConfigPreference(BluetoothDevice device,
             BluetoothCodecConfig config) {
-        mBluetoothA2dp.setCodecConfigPreference(device, config);
+        BluetoothDevice bluetoothDevice =
+                (device != null) ? device : mBluetoothA2dp.getActiveDevice();
+        if (bluetoothDevice != null) {
+            mBluetoothA2dp.setCodecConfigPreference(bluetoothDevice, config);
+        }
     }
 
     @VisibleForTesting
     BluetoothCodecConfig getCodecConfig(BluetoothDevice device) {
         if (mBluetoothA2dp != null) {
-            BluetoothCodecStatus codecStatus = mBluetoothA2dp.getCodecStatus(device);
+            BluetoothDevice bluetoothDevice =
+                    (device != null) ? device : mBluetoothA2dp.getActiveDevice();
+            if (bluetoothDevice == null) {
+                return null;
+            }
+            BluetoothCodecStatus codecStatus = mBluetoothA2dp.getCodecStatus(bluetoothDevice);
             if (codecStatus != null) {
                 return codecStatus.getCodecConfig();
             }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/BluetoothAudioCodecPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/BluetoothAudioCodecPreferenceController.java
index 5cf9adc..74858b6 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/BluetoothAudioCodecPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/BluetoothAudioCodecPreferenceController.java
@@ -17,6 +17,7 @@
 package com.android.car.developeroptions.development;
 
 import android.bluetooth.BluetoothCodecConfig;
+import android.bluetooth.BluetoothDevice;
 import android.content.Context;
 
 import com.android.car.developeroptions.R;
@@ -109,14 +110,20 @@
             case 6:
                 synchronized (mBluetoothA2dpConfigStore) {
                     if (mBluetoothA2dp != null) {
-                        mBluetoothA2dp.enableOptionalCodecs(null); // Use current active device
+                        BluetoothDevice activeDevice = mBluetoothA2dp.getActiveDevice();
+                        if (activeDevice != null) {
+                            mBluetoothA2dp.enableOptionalCodecs(activeDevice);
+                        }
                     }
                 }
                 return;
             case 7:
                 synchronized (mBluetoothA2dpConfigStore) {
                     if (mBluetoothA2dp != null) {
-                        mBluetoothA2dp.disableOptionalCodecs(null); // Use current active device
+                        BluetoothDevice activeDevice = mBluetoothA2dp.getActiveDevice();
+                        if (activeDevice != null) {
+                            mBluetoothA2dp.disableOptionalCodecs(activeDevice);
+                        }
                     }
                 }
                 return;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/DevelopmentSettingsDashboardFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/DevelopmentSettingsDashboardFragment.java
index 33bd3ca..0f0c313 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/DevelopmentSettingsDashboardFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/DevelopmentSettingsDashboardFragment.java
@@ -45,13 +45,13 @@
 import com.android.car.developeroptions.development.autofill.AutofillLoggingLevelPreferenceController;
 import com.android.car.developeroptions.development.autofill.AutofillResetOptionsPreferenceController;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.widget.SwitchBar;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.development.DeveloperOptionsPreferenceController;
 import com.android.settingslib.development.DevelopmentSettingsEnabler;
 import com.android.settingslib.development.SystemPropPoker;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/VerifyAppsOverUsbPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/VerifyAppsOverUsbPreferenceController.java
index 5f6e572..2554b2a 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/VerifyAppsOverUsbPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/VerifyAppsOverUsbPreferenceController.java
@@ -146,19 +146,11 @@
                 == AdbPreferenceController.ADB_SETTING_OFF) {
             return false;
         }
-        if (Settings.Global.getInt(cr, Settings.Global.PACKAGE_VERIFIER_ENABLE, SETTING_VALUE_ON)
-                == SETTING_VALUE_OFF) {
-            return false;
-        } else {
-            final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
-            verification.setType(PACKAGE_MIME_TYPE);
-            verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-            final List<ResolveInfo> receivers = mPackageManager.queryBroadcastReceivers(
-                    verification, 0 /* flags */);
-            if (receivers.size() == 0) {
-                return false;
-            }
-        }
-        return true;
+        final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
+        verification.setType(PACKAGE_MIME_TYPE);
+        verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        final List<ResolveInfo> receivers = mPackageManager.queryBroadcastReceivers(
+                verification, 0 /* flags */);
+        return receivers.size() != 0;
     }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/WifiVerboseLoggingPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/WifiVerboseLoggingPreferenceController.java
index b717bfb..101779b 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/WifiVerboseLoggingPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/WifiVerboseLoggingPreferenceController.java
@@ -52,13 +52,13 @@
     @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         final boolean isEnabled = (Boolean) newValue;
-        mWifiManager.enableVerboseLogging(isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
+        mWifiManager.setVerboseLoggingEnabled(isEnabled);
         return true;
     }
 
     @Override
     public void updateState(Preference preference) {
-        final boolean enabled = mWifiManager.getVerboseLoggingLevel() > 0;
+        final boolean enabled = mWifiManager.isVerboseLoggingEnabled();
         ((SwitchPreference) mPreference).setChecked(enabled);
 
     }
@@ -66,7 +66,7 @@
     @Override
     protected void onDeveloperOptionsSwitchDisabled() {
         super.onDeveloperOptionsSwitchDisabled();
-        mWifiManager.enableVerboseLogging(SETTING_VALUE_OFF);
+        mWifiManager.setVerboseLoggingEnabled(false);
         ((SwitchPreference) mPreference).setChecked(false);
     }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/featureflags/FeatureFlagFooterPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/featureflags/FeatureFlagFooterPreferenceController.java
deleted file mode 100644
index 36b8d9c..0000000
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/featureflags/FeatureFlagFooterPreferenceController.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.developeroptions.development.featureflags;
-
-import android.content.Context;
-
-import com.android.car.developeroptions.R;
-import com.android.car.developeroptions.core.BasePreferenceController;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnStart;
-import com.android.settingslib.widget.FooterPreferenceMixinCompat;
-
-public class FeatureFlagFooterPreferenceController extends BasePreferenceController
-        implements LifecycleObserver, OnStart {
-
-    private FooterPreferenceMixinCompat mFooterMixin;
-
-    public FeatureFlagFooterPreferenceController(Context context) {
-        super(context, "feature_flag_footer_pref");
-    }
-
-    public void setFooterMixin(FooterPreferenceMixinCompat mixin) {
-        mFooterMixin = mixin;
-    }
-
-    @Override
-    public int getAvailabilityStatus() {
-        return AVAILABLE;
-    }
-
-    @Override
-    public void onStart() {
-        mFooterMixin.createFooterPreference()
-                .setTitle(R.string.experimental_category_title);
-    }
-}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/featureflags/FeatureFlagsDashboard.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/featureflags/FeatureFlagsDashboard.java
index 933aaf3..021342b 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/featureflags/FeatureFlagsDashboard.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/featureflags/FeatureFlagsDashboard.java
@@ -23,10 +23,8 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
-import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.development.DevelopmentSettingsEnabler;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
@@ -55,7 +53,6 @@
     @Override
     public void onAttach(Context context) {
         super.onAttach(context);
-        use(FeatureFlagFooterPreferenceController.class).setFooterMixin(mFooterPreferenceMixin);
     }
 
     @Override
@@ -63,23 +60,6 @@
         return 0;
     }
 
-    @Override
-    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
-        return buildPrefControllers(context, getSettingsLifecycle());
-    }
-
-    private static List<AbstractPreferenceController> buildPrefControllers(Context context,
-            Lifecycle lifecycle) {
-        final List<AbstractPreferenceController> controllers = new ArrayList<>();
-        final FeatureFlagFooterPreferenceController footerController =
-                new FeatureFlagFooterPreferenceController(context);
-        if (lifecycle != null) {
-            lifecycle.addObserver(footerController);
-        }
-        controllers.add(footerController);
-        return controllers;
-    }
-
     public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
             new BaseSearchIndexProvider() {
                 @Override
@@ -97,11 +77,5 @@
                 protected boolean isPageSearchEnabled(Context context) {
                     return DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(context);
                 }
-
-                @Override
-                public List<AbstractPreferenceController> createPreferenceControllers(
-                        Context context) {
-                    return buildPrefControllers(context, null /* lifecycle */);
-                }
             };
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/gamedriver/GameDriverDashboard.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/gamedriver/GameDriverDashboard.java
index 8606b95..11b1486 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/gamedriver/GameDriverDashboard.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/gamedriver/GameDriverDashboard.java
@@ -25,10 +25,10 @@
 import com.android.car.developeroptions.SettingsActivity;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.widget.SwitchBar;
 import com.android.car.developeroptions.widget.SwitchBarController;
 import com.android.settingslib.development.DevelopmentSettingsEnabler;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/gamedriver/GameDriverFooterPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/gamedriver/GameDriverFooterPreferenceController.java
index 1469907..11b963e 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/gamedriver/GameDriverFooterPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/gamedriver/GameDriverFooterPreferenceController.java
@@ -26,7 +26,6 @@
 import android.provider.Settings;
 
 import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
 import com.android.car.developeroptions.core.BasePreferenceController;
@@ -48,8 +47,8 @@
 
     private FooterPreference mPreference;
 
-    public GameDriverFooterPreferenceController(Context context) {
-        super(context, FooterPreference.KEY_FOOTER);
+    public GameDriverFooterPreferenceController(Context context, String key) {
+        super(context, key);
         mContentResolver = context.getContentResolver();
         mGameDriverContentObserver =
                 new GameDriverContentObserver(new Handler(Looper.getMainLooper()), this);
@@ -81,11 +80,6 @@
     }
 
     @Override
-    public void updateState(Preference preference) {
-        preference.setVisible(isAvailable());
-    }
-
-    @Override
     public void onGameDriverContentChanged() {
         updateState(mPreference);
     }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/qstile/DevelopmentTileConfigFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/qstile/DevelopmentTileConfigFragment.java
index ae492d0..e2aaeb9 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/qstile/DevelopmentTileConfigFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/development/qstile/DevelopmentTileConfigFragment.java
@@ -23,8 +23,8 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.development.DevelopmentSettingsEnabler;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/PrivateVolumeSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/PrivateVolumeSettings.java
index 31d13c3..3cd45c5 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/PrivateVolumeSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/PrivateVolumeSettings.java
@@ -762,7 +762,7 @@
         public Dialog onCreateDialog(Bundle savedInstanceState) {
             return new AlertDialog.Builder(getActivity())
                     .setMessage(getContext().getString(R.string.storage_detail_dialog_system,
-                            Build.VERSION.RELEASE))
+                            Build.VERSION.RELEASE_OR_CODENAME))
                     .setPositiveButton(android.R.string.ok, null)
                     .create();
         }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/PublicVolumeSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/PublicVolumeSettings.java
index 7dda240..94176f0 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/PublicVolumeSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/PublicVolumeSettings.java
@@ -39,7 +39,6 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
-import com.android.internal.util.Preconditions;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.SettingsPreferenceFragment;
 import com.android.car.developeroptions.deviceinfo.StorageSettings.MountTask;
@@ -109,7 +108,7 @@
         }
 
         mDisk = mStorageManager.findDiskById(mVolume.getDiskId());
-        Preconditions.checkNotNull(mDisk);
+        Objects.requireNonNull(mDisk);
 
         mVolumeId = mVolume.getId();
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/StorageDashboardFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/StorageDashboardFragment.java
index 0f6c4a6..c6b740f 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/StorageDashboardFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/StorageDashboardFragment.java
@@ -46,12 +46,12 @@
 import com.android.car.developeroptions.deviceinfo.storage.UserIconLoader;
 import com.android.car.developeroptions.deviceinfo.storage.VolumeSizesLoader;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.widget.EntityHeaderController;
 import com.android.settingslib.applications.StorageStatsSource;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.deviceinfo.PrivateStorageInfo;
 import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/StorageSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/StorageSettings.java
index d83af2f..c00fc35 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/StorageSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/StorageSettings.java
@@ -50,13 +50,13 @@
 import com.android.car.developeroptions.core.SubSettingLauncher;
 import com.android.car.developeroptions.core.instrumentation.InstrumentedDialogFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
-import com.android.car.developeroptions.search.SearchIndexableRaw;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedLockUtilsInternal;
 import com.android.settingslib.deviceinfo.PrivateStorageInfo;
 import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
+import com.android.settingslib.search.SearchIndexableRaw;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceController.java
index 24b1e29..4ee76b8 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceController.java
@@ -70,7 +70,7 @@
 
     @Override
     public CharSequence getSummary() {
-        return Build.VERSION.RELEASE;
+        return Build.VERSION.RELEASE_OR_CODENAME;
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/firmwareversion/FirmwareVersionPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/firmwareversion/FirmwareVersionPreferenceController.java
index e9f70e6..789d047 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/firmwareversion/FirmwareVersionPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/firmwareversion/FirmwareVersionPreferenceController.java
@@ -34,6 +34,6 @@
 
     @Override
     public CharSequence getSummary() {
-        return Build.VERSION.RELEASE;
+        return Build.VERSION.RELEASE_OR_CODENAME;
     }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/firmwareversion/FirmwareVersionSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/firmwareversion/FirmwareVersionSettings.java
index da7339d..8200b53 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/firmwareversion/FirmwareVersionSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/firmwareversion/FirmwareVersionSettings.java
@@ -23,7 +23,7 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/hardwareinfo/HardwareInfoFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/hardwareinfo/HardwareInfoFragment.java
index 4455221..f9aaac9 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/hardwareinfo/HardwareInfoFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/hardwareinfo/HardwareInfoFragment.java
@@ -23,7 +23,7 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/imei/ImeiInfoDialogController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/imei/ImeiInfoDialogController.java
index 303eaa0..01b4883 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/imei/ImeiInfoDialogController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/imei/ImeiInfoDialogController.java
@@ -30,7 +30,6 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 
-import com.android.internal.telephony.PhoneConstants;
 import com.android.car.developeroptions.R;
 
 import java.util.List;
@@ -142,8 +141,7 @@
 
     @VisibleForTesting
     boolean isCdmaLteEnabled() {
-        return mTelephonyManager.getLteOnCdmaMode(mSubscriptionInfo.getSubscriptionId())
-                == PhoneConstants.LTE_ON_CDMA_TRUE;
+        return mTelephonyManager.isLteCdmaEvdoGsmWcdmaEnabled();
     }
 
     @VisibleForTesting
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/simstatus/SimStatusDialogController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/simstatus/SimStatusDialogController.java
index e0c47b5..946d986 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/simstatus/SimStatusDialogController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/simstatus/SimStatusDialogController.java
@@ -19,6 +19,7 @@
 import static android.content.Context.CARRIER_CONFIG_SERVICE;
 import static android.content.Context.EUICC_SERVICE;
 import static android.content.Context.TELEPHONY_SERVICE;
+import static android.content.Context.TELEPHONY_SUBSCRIPTION_SERVICE;
 
 import android.Manifest;
 import android.content.BroadcastReceiver;
@@ -30,10 +31,10 @@
 import android.os.PersistableBundle;
 import android.os.UserHandle;
 import android.telephony.CarrierConfigManager;
-import android.telephony.CellBroadcastMessage;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
+import android.telephony.SmsCbMessage;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -102,6 +103,7 @@
     private final SubscriptionInfo mSubscriptionInfo;
     private final TelephonyManager mTelephonyManager;
     private final CarrierConfigManager mCarrierConfigManager;
+    private final SubscriptionManager mSubscriptionManager;
     private final EuiccManager mEuiccManager;
     private final Resources mRes;
     private final Context mContext;
@@ -117,11 +119,16 @@
                 if (extras == null) {
                     return;
                 }
-                final CellBroadcastMessage cbMessage = (CellBroadcastMessage) extras.get("message");
-                if (cbMessage != null
-                        && mSubscriptionInfo.getSubscriptionId() == cbMessage.getSubId()) {
-                    final String latestAreaInfo = cbMessage.getMessageBody();
-                    mDialog.setText(OPERATOR_INFO_VALUE_ID, latestAreaInfo);
+                final SmsCbMessage cbMessage = (SmsCbMessage) extras.get("message");
+                if (cbMessage != null) {
+                    int[] subIds = mSubscriptionManager.getSubscriptionIds(
+                            cbMessage.getSlotIndex());
+                    int subId = (subIds == null || subIds.length == 0)
+                            ? SubscriptionManager.INVALID_SUBSCRIPTION_ID : subIds[0];
+                    if (mSubscriptionInfo.getSubscriptionId() == subId) {
+                        final String latestAreaInfo = cbMessage.getMessageBody();
+                        mDialog.setText(OPERATOR_INFO_VALUE_ID, latestAreaInfo);
+                    }
                 }
             }
         }
@@ -139,6 +146,8 @@
         mCarrierConfigManager = (CarrierConfigManager) mContext.getSystemService(
                 CARRIER_CONFIG_SERVICE);
         mEuiccManager = (EuiccManager) mContext.getSystemService(EUICC_SERVICE);
+        mSubscriptionManager = (SubscriptionManager) mContext.getSystemService(
+                TELEPHONY_SUBSCRIPTION_SERVICE);
 
         mRes = mContext.getResources();
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/storage/UserIconLoader.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/storage/UserIconLoader.java
index 4540824..c8a7606 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/storage/UserIconLoader.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/storage/UserIconLoader.java
@@ -22,10 +22,11 @@
 import android.os.UserManager;
 import android.util.SparseArray;
 
-import com.android.internal.util.Preconditions;
 import com.android.car.developeroptions.Utils;
 import com.android.settingslib.utils.AsyncLoaderCompat;
 
+import java.util.Objects;
+
 /**
  * Fetches a user icon as a loader using a given icon loading lambda.
  */
@@ -48,7 +49,7 @@
 
     public UserIconLoader(Context context, FetchUserIconTask task) {
         super(context);
-        mTask = Preconditions.checkNotNull(task);
+        mTask = Objects.requireNonNull(task);
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/storage/UserProfileController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/storage/UserProfileController.java
index 9b19647..0ac9285 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/storage/UserProfileController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/deviceinfo/storage/UserProfileController.java
@@ -27,7 +27,6 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
-import com.android.internal.util.Preconditions;
 import com.android.car.developeroptions.Utils;
 import com.android.car.developeroptions.core.PreferenceControllerMixin;
 import com.android.car.developeroptions.core.SubSettingLauncher;
@@ -35,6 +34,8 @@
 import com.android.car.developeroptions.deviceinfo.StorageProfileFragment;
 import com.android.settingslib.core.AbstractPreferenceController;
 
+import java.util.Objects;
+
 /**
  * Defines a {@link AbstractPreferenceController} which handles a single profile of the primary
  * user.
@@ -50,7 +51,7 @@
 
     public UserProfileController(Context context, UserInfo info, int preferenceOrder) {
         super(context);
-        mUser = Preconditions.checkNotNull(info);
+        mUser = Objects.requireNonNull(info);
         mPreferenceOrder = preferenceOrder;
     }
 
@@ -94,7 +95,7 @@
 
     @Override
     public void handleResult(SparseArray<StorageAsyncLoader.AppsStorageResult> stats) {
-        Preconditions.checkNotNull(stats);
+        Objects.requireNonNull(stats);
 
         int userId = mUser.id;
         StorageAsyncLoader.AppsStorageResult result = stats.get(userId);
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/AdaptiveSleepSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/AdaptiveSleepSettings.java
index 26cdab0..b80bea4 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/AdaptiveSleepSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/AdaptiveSleepSettings.java
@@ -25,7 +25,6 @@
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
 import com.android.settingslib.search.SearchIndexable;
-import com.android.settingslib.widget.FooterPreference;
 
 import java.util.Arrays;
 import java.util.List;
@@ -38,10 +37,6 @@
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
-        final FooterPreference footerPreference =
-                mFooterPreferenceMixin.createFooterPreference();
-        footerPreference.setIcon(R.drawable.ic_privacy_shield_24dp);
-        footerPreference.setTitle(R.string.adaptive_sleep_privacy);
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/AutoBrightnessSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/AutoBrightnessSettings.java
index 60095ef..d0fca24 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/AutoBrightnessSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/AutoBrightnessSettings.java
@@ -37,8 +37,6 @@
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
-        mFooterPreferenceMixin.createFooterPreference()
-                .setTitle(R.string.auto_brightness_description);
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/ColorModePreferenceFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/ColorModePreferenceFragment.java
index 2786974..e33fd25 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/ColorModePreferenceFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/ColorModePreferenceFragment.java
@@ -23,15 +23,15 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.provider.SearchIndexableResource;
-
 import android.provider.Settings.Secure;
+
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.PreferenceScreen;
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.widget.RadioButtonPickerFragment;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 import com.android.settingslib.widget.CandidateInfo;
 import com.android.settingslib.widget.LayoutPreference;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/DarkUISettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/DarkUISettings.java
index f58928e..ed880c9 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/DarkUISettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/DarkUISettings.java
@@ -21,15 +21,18 @@
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.provider.SearchIndexableResource;
+
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
+
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.widget.RadioButtonPickerFragment;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 import com.android.settingslib.widget.CandidateInfo;
 import com.android.settingslib.widget.FooterPreference;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/NightDisplayFooterPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/NightDisplayFooterPreferenceController.java
index 3c75fd2..2e417d4 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/NightDisplayFooterPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/NightDisplayFooterPreferenceController.java
@@ -19,26 +19,17 @@
 import android.content.Context;
 import android.hardware.display.ColorDisplayManager;
 
-import androidx.preference.Preference;
-
-import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.core.BasePreferenceController;
-import com.android.settingslib.widget.FooterPreference;
 
 public class NightDisplayFooterPreferenceController extends BasePreferenceController {
 
-    public NightDisplayFooterPreferenceController(Context context) {
-        super(context, FooterPreference.KEY_FOOTER);
+    public NightDisplayFooterPreferenceController(Context context, String key) {
+        super(context, key);
     }
 
     @Override
     public int getAvailabilityStatus() {
-        return ColorDisplayManager.isNightDisplayAvailable(mContext) ? AVAILABLE
-                : UNSUPPORTED_ON_DEVICE;
-    }
-
-    @Override
-    public void updateState(Preference preference) {
-        preference.setTitle(R.string.night_display_text);
+        return ColorDisplayManager.isNightDisplayAvailable(mContext)
+                ? AVAILABLE_UNSEARCHABLE : UNSUPPORTED_ON_DEVICE;
     }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/NightDisplaySettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/NightDisplaySettings.java
index 56cef42..8d2389c 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/NightDisplaySettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/NightDisplaySettings.java
@@ -30,8 +30,7 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
-import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.time.LocalTime;
@@ -176,17 +175,6 @@
         return TAG;
     }
 
-    @Override
-    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
-        return buildPreferenceControllers(context);
-    }
-
-    private static List<AbstractPreferenceController> buildPreferenceControllers(Context context) {
-        final List<AbstractPreferenceController> controllers = new ArrayList<>(1);
-        controllers.add(new NightDisplayFooterPreferenceController(context));
-        return controllers;
-    }
-
     public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
             new BaseSearchIndexProvider() {
                 @Override
@@ -203,11 +191,5 @@
                 protected boolean isPageSearchEnabled(Context context) {
                     return ColorDisplayManager.isNightDisplayAvailable(context);
                 }
-
-                @Override
-                public List<AbstractPreferenceController> createPreferenceControllers(
-                        Context context) {
-                    return buildPreferenceControllers(context);
-                }
             };
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/ScreenZoomSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/ScreenZoomSettings.java
index b2eade8..df60fa8 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/ScreenZoomSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/ScreenZoomSettings.java
@@ -26,10 +26,10 @@
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
-import com.android.car.developeroptions.search.SearchIndexableRaw;
 import com.android.settingslib.display.DisplayDensityUtils;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
+import com.android.settingslib.search.SearchIndexableRaw;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/ToggleFontSizePreferenceFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/ToggleFontSizePreferenceFragment.java
index 894f2ce..c6221b1 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/ToggleFontSizePreferenceFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/display/ToggleFontSizePreferenceFragment.java
@@ -27,9 +27,9 @@
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
-import com.android.car.developeroptions.search.SearchIndexableRaw;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
+import com.android.settingslib.search.SearchIndexableRaw;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/flashlight/FlashlightHandleActivity.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/flashlight/FlashlightHandleActivity.java
index d2a30b4..669a779 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/flashlight/FlashlightHandleActivity.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/flashlight/FlashlightHandleActivity.java
@@ -24,9 +24,9 @@
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
-import com.android.car.developeroptions.search.SearchIndexableRaw;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
+import com.android.settingslib.search.SearchIndexableRaw;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/BatteryBroadcastReceiver.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/BatteryBroadcastReceiver.java
index f3dfa23..bf1f3fd 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/BatteryBroadcastReceiver.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/BatteryBroadcastReceiver.java
@@ -102,7 +102,7 @@
             if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
                 final String batteryLevel = Utils.getBatteryPercentage(intent);
                 final String batteryStatus = Utils.getBatteryStatus(
-                        mContext.getResources(), intent);
+                        mContext, intent);
                 if (forceUpdate) {
                     mBatteryListener.onBatteryChanged(BatteryUpdateType.MANUAL);
                 } else if(!batteryLevel.equals(mBatteryLevel)) {
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/BatteryInfo.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/BatteryInfo.java
index e87e539..1172e99 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/BatteryInfo.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/BatteryInfo.java
@@ -30,9 +30,9 @@
 import androidx.annotation.WorkerThread;
 
 import com.android.internal.os.BatteryStatsHelper;
-import com.android.car.developeroptions.Utils;
 import com.android.car.developeroptions.overlay.FeatureFactory;
 import com.android.car.developeroptions.widget.UsageView;
+import com.android.car.developeroptions.Utils;
 import com.android.settingslib.R;
 import com.android.settingslib.utils.PowerUtil;
 import com.android.settingslib.utils.StringUtil;
@@ -229,9 +229,8 @@
         info.batteryPercentString = Utils.formatPercentage(info.batteryLevel);
         info.mCharging = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
         info.averageTimeToDischarge = estimate.averageDischargeTime;
-        final Resources resources = context.getResources();
 
-        info.statusLabel = Utils.getBatteryStatus(resources, batteryBroadcast);
+        info.statusLabel = Utils.getBatteryStatus(context, batteryBroadcast);
         if (!info.mCharging) {
             updateBatteryInfoDischarging(context, shortString, estimate, info);
         } else {
@@ -258,8 +257,7 @@
                     R.string.power_remaining_charging_duration_only, timeString);
             info.chargeLabel = context.getString(resId, info.batteryPercentString, timeString);
         } else {
-            final String chargeStatusLabel = resources.getString(
-                    R.string.battery_info_status_charging_lower);
+            final String chargeStatusLabel = Utils.getBatteryStatus(context, batteryBroadcast);
             info.remainingLabel = null;
             info.chargeLabel = info.batteryLevel == 100 ? info.batteryPercentString :
                     resources.getString(R.string.power_charging, info.batteryPercentString,
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/BatterySaverReceiver.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/BatterySaverReceiver.java
index a7bd096..a75b37d 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/BatterySaverReceiver.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/BatterySaverReceiver.java
@@ -39,7 +39,7 @@
     public void onReceive(Context context, Intent intent) {
         if (DEBUG) Log.d(TAG, "Received " + intent.getAction());
         String action = intent.getAction();
-        if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGING.equals(action)) {
+        if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
             if (mBatterySaverListener != null) {
                 mBatterySaverListener.onPowerSaveModeChanged();
             }
@@ -55,7 +55,7 @@
     public void setListening(boolean listening) {
         if (listening && !mRegistered) {
             final IntentFilter ifilter = new IntentFilter();
-            ifilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING);
+            ifilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
             ifilter.addAction(Intent.ACTION_BATTERY_CHANGED);
             mContext.registerReceiver(this, ifilter);
             mRegistered = true;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/BatteryWifiParser.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/BatteryWifiParser.java
index d6677bf..c228254 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/BatteryWifiParser.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/BatteryWifiParser.java
@@ -14,8 +14,8 @@
 
 package com.android.car.developeroptions.fuelgauge;
 
-import android.os.BatteryStats;
 import android.os.BatteryStats.HistoryItem;
+import android.os.BatteryStatsManager;
 
 public class BatteryWifiParser extends BatteryFlagParser {
 
@@ -27,12 +27,12 @@
     protected boolean isSet(HistoryItem record) {
         switch ((record.states2 & HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK)
                 >> HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT) {
-            case BatteryStats.WIFI_SUPPL_STATE_DISCONNECTED:
-            case BatteryStats.WIFI_SUPPL_STATE_DORMANT:
-            case BatteryStats.WIFI_SUPPL_STATE_INACTIVE:
-            case BatteryStats.WIFI_SUPPL_STATE_INTERFACE_DISABLED:
-            case BatteryStats.WIFI_SUPPL_STATE_INVALID:
-            case BatteryStats.WIFI_SUPPL_STATE_UNINITIALIZED:
+            case BatteryStatsManager.WIFI_SUPPL_STATE_DISCONNECTED:
+            case BatteryStatsManager.WIFI_SUPPL_STATE_DORMANT:
+            case BatteryStatsManager.WIFI_SUPPL_STATE_INACTIVE:
+            case BatteryStatsManager.WIFI_SUPPL_STATE_INTERFACE_DISABLED:
+            case BatteryStatsManager.WIFI_SUPPL_STATE_INVALID:
+            case BatteryStatsManager.WIFI_SUPPL_STATE_UNINITIALIZED:
                 return false;
         }
         return true;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/PowerUsageSummary.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/PowerUsageSummary.java
index 37c6aef..e2efb2c 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/PowerUsageSummary.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/PowerUsageSummary.java
@@ -215,7 +215,6 @@
         mScreenUsagePref = (PowerGaugePreference) findPreference(KEY_SCREEN_USAGE);
         mLastFullChargePref = (PowerGaugePreference) findPreference(
                 KEY_TIME_SINCE_LAST_FULL_CHARGE);
-        mFooterPreferenceMixin.createFooterPreference().setTitle(R.string.battery_footer_summary);
         mBatteryUtils = BatteryUtils.getInstance(getContext());
 
         restartBatteryInfoLoader();
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/RestrictedAppDetails.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/RestrictedAppDetails.java
index fb09ddc..d04c2c6 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/RestrictedAppDetails.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/RestrictedAppDetails.java
@@ -47,7 +47,6 @@
 import com.android.car.developeroptions.widget.AppCheckBoxPreference;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.utils.StringUtil;
-import com.android.settingslib.widget.FooterPreferenceMixinCompat;
 
 import java.util.List;
 
@@ -76,8 +75,6 @@
     PackageManager mPackageManager;
     @VisibleForTesting
     BatteryDatabaseManager mBatteryDatabaseManager;
-    private final FooterPreferenceMixinCompat mFooterPreferenceMixin =
-            new FooterPreferenceMixinCompat(this, getSettingsLifecycle());
 
     public static void startRestrictedAppDetails(InstrumentedPreferenceFragment fragment,
             List<AppInfo> appInfos) {
@@ -97,8 +94,6 @@
         super.onCreate(icicle);
         final Context context = getContext();
 
-        mFooterPreferenceMixin.createFooterPreference().setTitle(
-                R.string.restricted_app_detail_footer);
         mRestrictedAppListGroup = (PreferenceGroup) findPreference(KEY_PREF_RESTRICTED_APP_LIST);
         mAppInfos = getArguments().getParcelableArrayList(EXTRA_APP_INFO_LIST);
         mPackageManager = context.getPackageManager();
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/SmartBatterySettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/SmartBatterySettings.java
index 0db35f4..2f0e0df 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/SmartBatterySettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/SmartBatterySettings.java
@@ -18,7 +18,6 @@
 
 import android.app.settings.SettingsEnums;
 import android.content.Context;
-import android.os.Bundle;
 import android.provider.SearchIndexableResource;
 
 import com.android.car.developeroptions.R;
@@ -41,12 +40,6 @@
     public static final String TAG = "SmartBatterySettings";
 
     @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        mFooterPreferenceMixin.createFooterPreference().setTitle(R.string.smart_battery_footer);
-    }
-
-    @Override
     public int getMetricsCategory() {
         return SettingsEnums.FUELGAUGE_SMART_BATTERY;
     }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/batterysaver/BatterySaverSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/batterysaver/BatterySaverSettings.java
index 4772142..d9f73e8 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/batterysaver/BatterySaverSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/fuelgauge/batterysaver/BatterySaverSettings.java
@@ -24,7 +24,7 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.Arrays;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/gestures/TapScreenGestureSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/gestures/TapScreenGestureSettings.java
index c1c77d3..4cf2c3a 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/gestures/TapScreenGestureSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/gestures/TapScreenGestureSettings.java
@@ -21,13 +21,13 @@
 import android.hardware.display.AmbientDisplayConfiguration;
 import android.provider.SearchIndexableResource;
 
-import com.android.internal.logging.nano.MetricsProto;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.dashboard.suggestions.SuggestionFeatureProvider;
 import com.android.car.developeroptions.overlay.FeatureFactory;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.Arrays;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/homepage/contextualcards/conditional/ConditionContextualCardRenderer.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/homepage/contextualcards/conditional/ConditionContextualCardRenderer.java
index 3f3c37d..ccbdb50 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/homepage/contextualcards/conditional/ConditionContextualCardRenderer.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/homepage/contextualcards/conditional/ConditionContextualCardRenderer.java
@@ -65,7 +65,7 @@
                 mContext).getMetricsFeatureProvider();
 
         metricsFeatureProvider.visible(mContext, SettingsEnums.SETTINGS_HOMEPAGE,
-                card.getMetricsConstant());
+                card.getMetricsConstant(), 0);
         initializePrimaryClick(view, card, metricsFeatureProvider);
         initializeView(view, card);
         initializeActionButton(view, card, metricsFeatureProvider);
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/homepage/contextualcards/conditional/HotspotConditionController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/homepage/contextualcards/conditional/HotspotConditionController.java
index 69f7885..775a696 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/homepage/contextualcards/conditional/HotspotConditionController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/homepage/contextualcards/conditional/HotspotConditionController.java
@@ -26,6 +26,7 @@
 import android.net.wifi.WifiManager;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.Log;
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.TetherSettings;
@@ -37,6 +38,7 @@
 import java.util.Objects;
 
 public class HotspotConditionController implements ConditionalCardController {
+    static final String TAG = "HotspotConditionController";
     static final int ID = Objects.hash("HotspotConditionController");
 
     private static final IntentFilter WIFI_AP_STATE_FILTER =
@@ -116,8 +118,9 @@
     private CharSequence getSsid() {
         WifiConfiguration wifiConfig = mWifiManager.getWifiApConfiguration();
         if (wifiConfig == null) {
-            return mAppContext.getText(
-                    com.android.internal.R.string.wifi_tether_configure_ssid_default);
+            Log.e(TAG, "Ap config null unexpectedly");
+            // should never happen.
+            return "";
         } else {
             return wifiConfig.SSID;
         }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/homepage/contextualcards/deviceinfo/EmergencyInfoSlice.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/homepage/contextualcards/deviceinfo/EmergencyInfoSlice.java
index d7ef7cd..5454a68 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/homepage/contextualcards/deviceinfo/EmergencyInfoSlice.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/homepage/contextualcards/deviceinfo/EmergencyInfoSlice.java
@@ -27,6 +27,7 @@
 import androidx.slice.builders.SliceAction;
 
 import com.android.car.developeroptions.R;
+import com.android.car.developeroptions.Utils;
 import com.android.car.developeroptions.accounts.EmergencyInfoPreferenceController;
 import com.android.car.developeroptions.slices.CustomSliceRegistry;
 import com.android.car.developeroptions.slices.CustomSliceable;
@@ -61,7 +62,8 @@
 
     @Override
     public Intent getIntent() {
-        return new Intent(EmergencyInfoPreferenceController.getIntentAction(mContext));
+        return new Intent(EmergencyInfoPreferenceController.getIntentAction(mContext))
+                .setPackage(Utils.SETTINGS_PACKAGE_NAME);
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/homepage/contextualcards/slices/NotificationChannelSlice.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/homepage/contextualcards/slices/NotificationChannelSlice.java
index 73b9d28..93213db 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/homepage/contextualcards/slices/NotificationChannelSlice.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/homepage/contextualcards/slices/NotificationChannelSlice.java
@@ -465,7 +465,7 @@
                 return true;
             }
 
-            return channel.isBlockableSystem()
+            return channel.isBlockable()
                     || channel.getImportance() == IMPORTANCE_NONE;
         }
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/inputmethod/PhysicalKeyboardFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/inputmethod/PhysicalKeyboardFragment.java
index 45b7404..6131fa4 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/inputmethod/PhysicalKeyboardFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/inputmethod/PhysicalKeyboardFragment.java
@@ -40,12 +40,11 @@
 import androidx.preference.PreferenceScreen;
 import androidx.preference.SwitchPreference;
 
-import com.android.internal.util.Preconditions;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.Settings;
 import com.android.car.developeroptions.SettingsPreferenceFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 import com.android.settingslib.utils.ThreadUtils;
 
@@ -77,12 +76,12 @@
 
     @Override
     public void onCreatePreferences(Bundle bundle, String s) {
-        Activity activity = Preconditions.checkNotNull(getActivity());
+        Activity activity = Objects.requireNonNull(getActivity());
         addPreferencesFromResource(R.xml.physical_keyboard_settings);
-        mIm = Preconditions.checkNotNull(activity.getSystemService(InputManager.class));
-        mKeyboardAssistanceCategory = Preconditions.checkNotNull(
+        mIm = Objects.requireNonNull(activity.getSystemService(InputManager.class));
+        mKeyboardAssistanceCategory = Objects.requireNonNull(
                 (PreferenceCategory) findPreference(KEYBOARD_ASSISTANCE_CATEGORY));
-        mShowVirtualKeyboardSwitch = Preconditions.checkNotNull(
+        mShowVirtualKeyboardSwitch = Objects.requireNonNull(
                 (SwitchPreference) mKeyboardAssistanceCategory.findPreference(
                         SHOW_VIRTUAL_KEYBOARD_SWITCH));
         findPreference(KEYBOARD_SHORTCUTS_HELPER).setOnPreferenceClickListener(
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/inputmethod/SpellCheckerForWorkPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/inputmethod/SpellCheckerForWorkPreferenceController.java
index 9d4aac6..5418131 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/inputmethod/SpellCheckerForWorkPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/inputmethod/SpellCheckerForWorkPreferenceController.java
@@ -18,7 +18,6 @@
 
 import android.app.settings.SettingsEnums;
 import android.content.Context;
-import android.view.inputmethod.InputMethodSystemProperty;
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.core.WorkProfilePreferenceController;
@@ -42,8 +41,7 @@
     @AvailabilityStatus
     @Override
     public int getAvailabilityStatus() {
-        if (!mContext.getResources().getBoolean(R.bool.config_show_spellcheckers_settings)
-                || !InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
+        if (!mContext.getResources().getBoolean(R.bool.config_show_spellcheckers_settings)) {
             return UNSUPPORTED_ON_DEVICE;
         }
         return super.getAvailabilityStatus();
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/inputmethod/UserDictionaryList.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/inputmethod/UserDictionaryList.java
index 26926ab..2049aab 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/inputmethod/UserDictionaryList.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/inputmethod/UserDictionaryList.java
@@ -25,7 +25,7 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/inputmethod/VirtualKeyboardForWorkPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/inputmethod/VirtualKeyboardForWorkPreferenceController.java
index 78a5853..d6c2d40 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/inputmethod/VirtualKeyboardForWorkPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/inputmethod/VirtualKeyboardForWorkPreferenceController.java
@@ -18,7 +18,6 @@
 
 import android.app.settings.SettingsEnums;
 import android.content.Context;
-import android.view.inputmethod.InputMethodSystemProperty;
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.core.WorkProfilePreferenceController;
@@ -39,8 +38,7 @@
     @AvailabilityStatus
     @Override
     public int getAvailabilityStatus() {
-        if (!mContext.getResources().getBoolean(R.bool.config_show_virtual_keyboard_pref)
-                || !InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
+        if (!mContext.getResources().getBoolean(R.bool.config_show_virtual_keyboard_pref)) {
             return UNSUPPORTED_ON_DEVICE;
         }
         return super.getAvailabilityStatus();
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/inputmethod/VirtualKeyboardFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/inputmethod/VirtualKeyboardFragment.java
index 2b186cf..0e048e9 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/inputmethod/VirtualKeyboardFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/inputmethod/VirtualKeyboardFragment.java
@@ -30,19 +30,19 @@
 
 import androidx.preference.Preference;
 
-import com.android.internal.util.Preconditions;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.SettingsPreferenceFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.inputmethod.InputMethodAndSubtypeUtilCompat;
 import com.android.settingslib.inputmethod.InputMethodPreference;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 
 @SearchIndexable
 public final class VirtualKeyboardFragment extends SettingsPreferenceFragment implements Indexable {
@@ -57,11 +57,11 @@
 
     @Override
     public void onCreatePreferences(Bundle bundle, String s) {
-        Activity activity = Preconditions.checkNotNull(getActivity());
+        Activity activity = Objects.requireNonNull(getActivity());
         addPreferencesFromResource(R.xml.virtual_keyboard_settings);
-        mImm = Preconditions.checkNotNull(activity.getSystemService(InputMethodManager.class));
-        mDpm = Preconditions.checkNotNull(activity.getSystemService(DevicePolicyManager.class));
-        mAddVirtualKeyboardScreen = Preconditions.checkNotNull(
+        mImm = Objects.requireNonNull(activity.getSystemService(InputMethodManager.class));
+        mDpm = Objects.requireNonNull(activity.getSystemService(DevicePolicyManager.class));
+        mAddVirtualKeyboardScreen = Objects.requireNonNull(
                 findPreference(ADD_VIRTUAL_KEYBOARD_SCREEN));
     }
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/language/UserDictionaryForWorkPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/language/UserDictionaryForWorkPreferenceController.java
index 68e89c1..c647561 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/language/UserDictionaryForWorkPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/language/UserDictionaryForWorkPreferenceController.java
@@ -18,7 +18,6 @@
 
 import android.app.settings.SettingsEnums;
 import android.content.Context;
-import android.view.inputmethod.InputMethodSystemProperty;
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.core.WorkProfilePreferenceController;
@@ -39,13 +38,4 @@
     protected int getSourceMetricsCategory() {
         return SettingsEnums.SETTINGS_LANGUAGE_CATEGORY;
     }
-
-    @AvailabilityStatus
-    @Override
-    public int getAvailabilityStatus() {
-        if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
-            return UNSUPPORTED_ON_DEVICE;
-        }
-        return super.getAvailabilityStatus();
-    }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/location/LocationFooterPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/location/LocationFooterPreferenceController.java
index 424bf7d..4828cad 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/location/LocationFooterPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/location/LocationFooterPreferenceController.java
@@ -13,7 +13,6 @@
  */
 package com.android.car.developeroptions.location;
 
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -24,13 +23,9 @@
 import android.location.LocationManager;
 import android.util.Log;
 
-import androidx.annotation.VisibleForTesting;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceCategory;
 
-import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnPause;
 import com.android.settingslib.widget.FooterPreference;
 
 import java.util.ArrayList;
@@ -41,24 +36,19 @@
 /**
  * Preference controller for location footer preference category
  */
-public class LocationFooterPreferenceController extends LocationBasePreferenceController
-        implements LifecycleObserver, OnPause {
+public class LocationFooterPreferenceController extends LocationBasePreferenceController {
     private static final String TAG = "LocationFooter";
     private static final String KEY_LOCATION_FOOTER = "location_footer";
     private static final Intent INJECT_INTENT =
             new Intent(LocationManager.SETTINGS_FOOTER_DISPLAYED_ACTION);
-    private final Context mContext;
-    private final PackageManager mPackageManager;
-    private Collection<ComponentName> mFooterInjectors;
 
-    public LocationFooterPreferenceController(Context context, Lifecycle lifecycle) {
-        super(context, lifecycle);
-        mContext = context;
+    private final PackageManager mPackageManager;
+
+    public LocationFooterPreferenceController(Context context) {
+        // we don't care location mode changes, so pass in a null lifecycle to disable listening
+        super(context, null);
+
         mPackageManager = mContext.getPackageManager();
-        mFooterInjectors = new ArrayList<>();
-        if (lifecycle != null) {
-            lifecycle.addObserver(this);
-        }
     }
 
     @Override
@@ -67,37 +57,30 @@
     }
 
     /**
-     * Insert footer preferences. Send a {@link LocationManager#SETTINGS_FOOTER_DISPLAYED_ACTION}
-     * broadcast to receivers who have injected a footer
+     * Insert footer preferences.
      */
     @Override
     public void updateState(Preference preference) {
         PreferenceCategory category = (PreferenceCategory) preference;
         category.removeAll();
-        mFooterInjectors.clear();
         Collection<FooterData> footerData = getFooterData();
         for (FooterData data : footerData) {
-            // Generate a footer preference with the given text
-            FooterPreference footerPreference = new FooterPreference(preference.getContext());
-            String footerString;
             try {
-                footerString =
+                String footerString =
                         mPackageManager
                                 .getResourcesForApplication(data.applicationInfo)
                                 .getString(data.footerStringRes);
+
+                // Generate a footer preference with the given text
+                FooterPreference footerPreference = new FooterPreference(preference.getContext());
+                footerPreference.setTitle(footerString);
+                category.addPreference(footerPreference);
             } catch (NameNotFoundException exception) {
                 Log.w(
                         TAG,
                         "Resources not found for application "
                                 + data.applicationInfo.packageName);
-                continue;
             }
-            footerPreference.setTitle(footerString);
-            // Inject the footer
-            category.addPreference(footerPreference);
-            // Send broadcast to the injector announcing a footer has been injected
-            sendBroadcastFooterDisplayed(data.componentName);
-            mFooterInjectors.add(data.componentName);
         }
     }
 
@@ -117,36 +100,11 @@
     }
 
     /**
-     * Send a {@link LocationManager#SETTINGS_FOOTER_REMOVED_ACTION} broadcast to footer injectors
-     * when LocationFragment is on pause
-     */
-    @Override
-    public void onPause() {
-        // Send broadcast to the footer injectors. Notify them the footer is not visible.
-        for (ComponentName componentName : mFooterInjectors) {
-            final Intent intent = new Intent(LocationManager.SETTINGS_FOOTER_REMOVED_ACTION);
-            intent.setComponent(componentName);
-            mContext.sendBroadcast(intent);
-        }
-    }
-
-    /**
-     * Send a {@link LocationManager#SETTINGS_FOOTER_DISPLAYED_ACTION} broadcast to a footer
-     * injector.
-     */
-    @VisibleForTesting
-    void sendBroadcastFooterDisplayed(ComponentName componentName) {
-        Intent intent = new Intent(LocationManager.SETTINGS_FOOTER_DISPLAYED_ACTION);
-        intent.setComponent(componentName);
-        mContext.sendBroadcast(intent);
-    }
-
-    /**
      * Return a list of strings with text provided by ACTION_INJECT_FOOTER broadcast receivers.
      */
-    private Collection<FooterData> getFooterData() {
+    private List<FooterData> getFooterData() {
         // Fetch footer text from system apps
-        final List<ResolveInfo> resolveInfos =
+        List<ResolveInfo> resolveInfos =
                 mPackageManager.queryBroadcastReceivers(
                         INJECT_INTENT, PackageManager.GET_META_DATA);
         if (resolveInfos == null) {
@@ -158,10 +116,10 @@
             Log.d(TAG, "Found broadcast receivers: " + resolveInfos);
         }
 
-        final Collection<FooterData> footerDataList = new ArrayList<>(resolveInfos.size());
+        List<FooterData> footerDataList = new ArrayList<>(resolveInfos.size());
         for (ResolveInfo resolveInfo : resolveInfos) {
-            final ActivityInfo activityInfo = resolveInfo.activityInfo;
-            final ApplicationInfo appInfo = activityInfo.applicationInfo;
+            ActivityInfo activityInfo = resolveInfo.activityInfo;
+            ApplicationInfo appInfo = activityInfo.applicationInfo;
 
             // If a non-system app tries to inject footer, ignore it
             if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
@@ -187,11 +145,7 @@
                                 + LocationManager.METADATA_SETTINGS_FOOTER_STRING);
                 continue;
             }
-            footerDataList.add(
-                    new FooterData(
-                            footerTextRes,
-                            appInfo,
-                            new ComponentName(activityInfo.packageName, activityInfo.name)));
+            footerDataList.add(new FooterData(footerTextRes, appInfo));
         }
         return footerDataList;
     }
@@ -207,14 +161,9 @@
         // Application info of receiver injecting this footer
         final ApplicationInfo applicationInfo;
 
-        // The component that injected the footer. It must be a receiver of broadcast
-        // LocationManager.SETTINGS_FOOTER_DISPLAYED_ACTION
-        final ComponentName componentName;
-
-        FooterData(int footerRes, ApplicationInfo appInfo, ComponentName componentName) {
+        FooterData(int footerRes, ApplicationInfo appInfo) {
             this.footerStringRes = footerRes;
             this.applicationInfo = appInfo;
-            this.componentName = componentName;
         }
     }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/location/LocationScanningPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/location/LocationScanningPreferenceController.java
index 48deffd..66b14cc 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/location/LocationScanningPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/location/LocationScanningPreferenceController.java
@@ -17,6 +17,7 @@
 package com.android.car.developeroptions.location;
 
 import android.content.Context;
+import android.net.wifi.WifiManager;
 import android.provider.Settings;
 
 import androidx.annotation.VisibleForTesting;
@@ -28,16 +29,17 @@
 public class LocationScanningPreferenceController extends BasePreferenceController {
     @VisibleForTesting static final String KEY_LOCATION_SCANNING = "location_scanning";
     private final Context mContext;
+    private final WifiManager mWifiManager;
 
     public LocationScanningPreferenceController(Context context) {
         super(context, KEY_LOCATION_SCANNING);
         mContext = context;
+        mWifiManager = context.getSystemService(WifiManager.class);
     }
 
     @Override
     public CharSequence getSummary() {
-        final boolean wifiScanOn = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1;
+        final boolean wifiScanOn = mWifiManager.isScanAlwaysAvailable();
         final boolean bleScanOn = Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0) == 1;
         int resId;
@@ -59,4 +61,4 @@
                 ? AVAILABLE
                 : UNSUPPORTED_ON_DEVICE;
     }
-}
\ No newline at end of file
+}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/location/LocationSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/location/LocationSettings.java
index 7b0377f..ce82261 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/location/LocationSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/location/LocationSettings.java
@@ -29,11 +29,11 @@
 import com.android.car.developeroptions.SettingsActivity;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.widget.SwitchBar;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.location.RecentLocationAccesses;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
@@ -121,7 +121,7 @@
         controllers.add(new RecentLocationAccessPreferenceController(context));
         controllers.add(new LocationScanningPreferenceController(context));
         controllers.add(new LocationServicePreferenceController(context, fragment, lifecycle));
-        controllers.add(new LocationFooterPreferenceController(context, lifecycle));
+        controllers.add(new LocationFooterPreferenceController(context));
         return controllers;
     }
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/location/ScanningSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/location/ScanningSettings.java
index 112cc06..8416d72 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/location/ScanningSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/location/ScanningSettings.java
@@ -23,8 +23,8 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/location/WifiScanningPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/location/WifiScanningPreferenceController.java
index 53df4e5..0f76eac 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/location/WifiScanningPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/location/WifiScanningPreferenceController.java
@@ -14,7 +14,7 @@
 package com.android.car.developeroptions.location;
 
 import android.content.Context;
-import android.provider.Settings;
+import android.net.wifi.WifiManager;
 
 import androidx.preference.Preference;
 import androidx.preference.SwitchPreference;
@@ -26,9 +26,11 @@
         implements PreferenceControllerMixin {
 
     private static final String KEY_WIFI_SCAN_ALWAYS_AVAILABLE = "wifi_always_scanning";
+    private final WifiManager mWifiManager;
 
     public WifiScanningPreferenceController(Context context) {
         super(context);
+        mWifiManager = context.getSystemService(WifiManager.class);
     }
 
     @Override
@@ -43,17 +45,13 @@
 
     @Override
     public void updateState(Preference preference) {
-        ((SwitchPreference) preference).setChecked(
-                Settings.Global.getInt(mContext.getContentResolver(),
-                        Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1);
+        ((SwitchPreference) preference).setChecked(mWifiManager.isScanAlwaysAvailable());
     }
 
     @Override
     public boolean handlePreferenceTreeClick(Preference preference) {
         if (KEY_WIFI_SCAN_ALWAYS_AVAILABLE.equals(preference.getKey())) {
-            Settings.Global.putInt(mContext.getContentResolver(),
-                    Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE,
-                    ((SwitchPreference) preference).isChecked() ? 1 : 0);
+            mWifiManager.setScanAlwaysAvailable(((SwitchPreference) preference).isChecked());
             return true;
         }
         return false;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/media/MediaOutputIndicatorSlice.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/media/MediaOutputIndicatorSlice.java
index 06cc9de..cd36723 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/media/MediaOutputIndicatorSlice.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/media/MediaOutputIndicatorSlice.java
@@ -31,10 +31,10 @@
 import androidx.slice.builders.ListBuilder;
 import androidx.slice.builders.SliceAction;
 
-import com.android.internal.util.CollectionUtils;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.Utils;
 import com.android.car.developeroptions.slices.CustomSliceable;
+import com.android.internal.util.CollectionUtils;
 import com.android.settingslib.bluetooth.A2dpProfile;
 import com.android.settingslib.bluetooth.HearingAidProfile;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -143,14 +143,14 @@
         // Return Hearing Aid device name if it is active
         BluetoothDevice activeDevice = findActiveHearingAidDevice();
         if (activeDevice != null) {
-            return activeDevice.getAliasName();
+            return activeDevice.getAlias();
         }
         // Return A2DP device name if it is active
         final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
         if (a2dpProfile != null) {
             activeDevice = a2dpProfile.getActiveDevice();
             if (activeDevice != null) {
-                return activeDevice.getAliasName();
+                return activeDevice.getAlias();
             }
         }
         // No active device, return default summary
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/AirplaneModePreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/AirplaneModePreferenceController.java
index 17c1dcd..8bff680 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/AirplaneModePreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/AirplaneModePreferenceController.java
@@ -20,19 +20,18 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.os.SystemProperties;
+import android.sysprop.TelephonyProperties;
 
 import androidx.fragment.app.Fragment;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 import androidx.preference.SwitchPreference;
 
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
 import com.android.car.developeroptions.AirplaneModeEnabler;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.core.TogglePreferenceController;
 import com.android.car.developeroptions.overlay.FeatureFactory;
+import com.android.internal.telephony.TelephonyIntents;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.core.lifecycle.events.OnPause;
@@ -63,8 +62,8 @@
 
     @Override
     public boolean handlePreferenceTreeClick(Preference preference) {
-        if (KEY_AIRPLANE_MODE.equals(preference.getKey()) && Boolean.parseBoolean(
-                SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
+        if (KEY_AIRPLANE_MODE.equals(preference.getKey())
+                && TelephonyProperties.in_ecm_mode().orElse(false)) {
             // In ECM mode launch ECM app dialog
             if (mFragment != null) {
                 mFragment.startActivityForResult(
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/TetherPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/TetherPreferenceController.java
index 53542b4..8150d9c 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/TetherPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/TetherPreferenceController.java
@@ -39,7 +39,6 @@
 import androidx.preference.PreferenceScreen;
 
 import com.android.car.developeroptions.R;
-import com.android.car.developeroptions.TetherSettings;
 import com.android.car.developeroptions.core.PreferenceControllerMixin;
 import com.android.settingslib.TetherUtil;
 import com.android.settingslib.core.AbstractPreferenceController;
@@ -106,9 +105,6 @@
         if (mPreference != null && !mAdminDisallowedTetherConfig) {
             mPreference.setTitle(
                     com.android.settingslib.Utils.getTetheringLabel(mConnectivityManager));
-
-            // Grey out if provisioning is not available.
-            mPreference.setEnabled(!TetherSettings.isProvisioningNeededButUnavailable(mContext));
         }
     }
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/TetherProvisioningActivity.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/TetherProvisioningActivity.java
index 3ffe0f6..5b699f1 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/TetherProvisioningActivity.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/TetherProvisioningActivity.java
@@ -19,16 +19,12 @@
 import android.app.Activity;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.content.res.Resources;
 import android.net.ConnectivityManager;
 import android.os.Bundle;
 import android.os.ResultReceiver;
 import android.os.UserHandle;
-import android.telephony.SubscriptionManager;
 import android.util.Log;
 
-import com.android.car.developeroptions.Utils;
-
 /**
  * Activity which acts as a proxy to the tether provisioning app for sanity checks and permission
  * restrictions. Specifically, the provisioning apps require
@@ -41,6 +37,8 @@
     private static final String EXTRA_TETHER_TYPE = "TETHER_TYPE";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private ResultReceiver mResultReceiver;
+    public static final String EXTRA_TETHER_UI_PROVISIONING_APP_NAME =
+            "android.net.extra.TETHER_UI_PROVISIONING_APP_NAME";
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -51,10 +49,12 @@
 
         int tetherType = getIntent().getIntExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE,
                 ConnectivityManager.TETHERING_INVALID);
-        final int subId = SubscriptionManager.getDefaultDataSubscriptionId();
-        final Resources res = Utils.getResourcesForSubId(this, subId);
-        final String[] provisionApp = res.getStringArray(
-                com.android.internal.R.array.config_mobile_hotspot_provision_app);
+        String[] provisionApp = getIntent().getStringArrayExtra(
+                EXTRA_TETHER_UI_PROVISIONING_APP_NAME);
+        if (provisionApp == null || provisionApp.length != 2) {
+            Log.e(TAG, "Unexpected provision app configuration");
+            return;
+        }
 
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.setClassName(provisionApp[0], provisionApp[1]);
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/CellInfoUtil.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/CellInfoUtil.java
index 0be8ff6..5650d10 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/CellInfoUtil.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/CellInfoUtil.java
@@ -33,6 +33,7 @@
 
 import com.android.internal.telephony.OperatorInfo;
 
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -149,7 +150,8 @@
                 mcc,
                 mnc,
                 operatorInfo.getOperatorAlphaLong(),
-                operatorInfo.getOperatorAlphaShort());
+                operatorInfo.getOperatorAlphaShort(),
+                Collections.emptyList());
 
         CellInfoGsm ci = new CellInfoGsm();
         ci.setCellIdentity(cig);
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/DataServiceSetupPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/DataServiceSetupPreferenceController.java
index 9bd0480..d2aeb5f 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/DataServiceSetupPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/DataServiceSetupPreferenceController.java
@@ -28,8 +28,6 @@
 
 import androidx.preference.Preference;
 
-import com.android.internal.telephony.PhoneConstants;
-
 /**
  * Preference controller for "Data service setup"
  */
@@ -49,14 +47,12 @@
 
     @Override
     public int getAvailabilityStatus(int subId) {
-        final boolean isLteOnCdma = mTelephonyManager.getLteOnCdmaMode()
-                == PhoneConstants.LTE_ON_CDMA_TRUE;
         final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId);
         return subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID
                 && carrierConfig != null
                 && !carrierConfig.getBoolean(
                 CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL)
-                && isLteOnCdma && !TextUtils.isEmpty(mSetupUrl)
+                && mTelephonyManager.isLteCdmaEvdoGsmWcdmaEnabled() && !TextUtils.isEmpty(mSetupUrl)
                 ? AVAILABLE
                 : CONDITIONALLY_UNAVAILABLE;
     }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/EnabledNetworkModePreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/EnabledNetworkModePreferenceController.java
index 66e282a..41cfd02 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/EnabledNetworkModePreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/EnabledNetworkModePreferenceController.java
@@ -28,9 +28,9 @@
 import androidx.preference.ListPreference;
 import androidx.preference.Preference;
 
+import com.android.car.developeroptions.R;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
-import com.android.car.developeroptions.R;
 
 /**
  * Preference controller for "Enabled network mode"
@@ -107,9 +107,7 @@
         final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(mSubId);
         mTelephonyManager = TelephonyManager.from(mContext).createForSubscriptionId(mSubId);
 
-        final boolean isLteOnCdma =
-                mTelephonyManager.getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE;
-        mIsGlobalCdma = isLteOnCdma
+        mIsGlobalCdma = mTelephonyManager.isLteCdmaEvdoGsmWcdmaEnabled()
                 && carrierConfig.getBoolean(CarrierConfigManager.KEY_SHOW_CDMA_CHOICES_BOOL);
         mShow4GForLTE = carrierConfig != null
                 ? carrierConfig.getBoolean(
@@ -131,13 +129,11 @@
                     mContext.getContentResolver(),
                     android.provider.Settings.Global.LTE_SERVICE_FORCED + mSubId,
                     0);
-            final boolean isLteOnCdma = mTelephonyManager.getLteOnCdmaMode()
-                    == PhoneConstants.LTE_ON_CDMA_TRUE;
             final int settingsNetworkMode = android.provider.Settings.Global.getInt(
                     mContext.getContentResolver(),
                     android.provider.Settings.Global.PREFERRED_NETWORK_MODE + mSubId,
                     Phone.PREFERRED_NT_MODE);
-            if (isLteOnCdma) {
+            if (mTelephonyManager.isLteCdmaEvdoGsmWcdmaEnabled()) {
                 if (lteForced == 0) {
                     preference.setEntries(
                             R.array.enabled_networks_cdma_choices);
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/MobileNetworkSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/MobileNetworkSettings.java
index 184c607..69ee73f 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/MobileNetworkSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/MobileNetworkSettings.java
@@ -32,7 +32,9 @@
 import android.view.MenuInflater;
 import android.view.MenuItem;
 
-import com.android.internal.telephony.TelephonyIntents;
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.core.FeatureFlags;
 import com.android.car.developeroptions.dashboard.RestrictedDashboardFragment;
@@ -44,18 +46,16 @@
 import com.android.car.developeroptions.network.telephony.gsm.AutoSelectPreferenceController;
 import com.android.car.developeroptions.network.telephony.gsm.OpenNetworkSelectPagePreferenceController;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.widget.PreferenceCategoryController;
+import com.android.internal.telephony.TelephonyIntents;
 import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-
 @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
 public class MobileNetworkSettings extends RestrictedDashboardFragment {
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/NetworkScanHelper.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/NetworkScanHelper.java
index 31df45b..f560549 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/NetworkScanHelper.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/NetworkScanHelper.java
@@ -31,6 +31,7 @@
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
 import com.google.common.util.concurrent.SettableFuture;
 
 import java.lang.annotation.Retention;
@@ -180,7 +181,7 @@
                     int errCode = Integer.parseInt(t.getMessage());
                     onError(errCode);
                 }
-            });
+            }, MoreExecutors.directExecutor());
             mExecutor.execute(new NetworkScanSyncTask(
                     mTelephonyManager, (SettableFuture) mNetworkScanFuture));
         } else if (type == NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS) {
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/PreferredNetworkModePreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/PreferredNetworkModePreferenceController.java
index c81eb65..7910f89 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/PreferredNetworkModePreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/PreferredNetworkModePreferenceController.java
@@ -27,9 +27,9 @@
 import androidx.preference.ListPreference;
 import androidx.preference.Preference;
 
+import com.android.car.developeroptions.R;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
-import com.android.car.developeroptions.R;
 
 /**
  * Preference controller for "Preferred network mode"
@@ -103,9 +103,7 @@
         final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(mSubId);
         mTelephonyManager = TelephonyManager.from(mContext).createForSubscriptionId(mSubId);
 
-        final boolean isLteOnCdma =
-                mTelephonyManager.getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE;
-        mIsGlobalCdma = isLteOnCdma
+        mIsGlobalCdma = mTelephonyManager.isLteCdmaEvdoGsmWcdmaEnabled()
                 && carrierConfig.getBoolean(CarrierConfigManager.KEY_SHOW_CDMA_CHOICES_BOOL);
     }
 
@@ -132,12 +130,9 @@
             case TelephonyManager.NETWORK_MODE_GSM_UMTS:
                 return R.string.preferred_network_mode_gsm_wcdma_summary;
             case TelephonyManager.NETWORK_MODE_CDMA_EVDO:
-                switch (mTelephonyManager.getLteOnCdmaMode()) {
-                    case PhoneConstants.LTE_ON_CDMA_TRUE:
-                        return R.string.preferred_network_mode_cdma_summary;
-                    default:
-                        return R.string.preferred_network_mode_cdma_evdo_summary;
-                }
+                return mTelephonyManager.isLteCdmaEvdoGsmWcdmaEnabled()
+                        ? R.string.preferred_network_mode_cdma_summary
+                        : R.string.preferred_network_mode_cdma_evdo_summary;
             case TelephonyManager.NETWORK_MODE_CDMA_NO_EVDO:
                 return R.string.preferred_network_mode_cdma_only_summary;
             case TelephonyManager.NETWORK_MODE_EVDO_NO_CDMA:
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/AppBubbleNotificationSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/AppBubbleNotificationSettings.java
deleted file mode 100644
index f6fbced..0000000
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/AppBubbleNotificationSettings.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.developeroptions.notification;
-
-import android.app.settings.SettingsEnums;
-import android.content.Context;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.car.developeroptions.R;
-import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
-import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.search.SearchIndexable;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@SearchIndexable
-public class AppBubbleNotificationSettings extends NotificationSettingsBase implements
-        GlobalBubblePermissionObserverMixin.Listener {
-    private static final String TAG = "AppBubNotiSettings";
-    private GlobalBubblePermissionObserverMixin mObserverMixin;
-
-    @Override
-    public int getMetricsCategory() {
-        return SettingsEnums.APP_BUBBLE_SETTINGS;
-    }
-
-    @Override
-    protected String getLogTag() {
-        return TAG;
-    }
-
-    @Override
-    protected int getPreferenceScreenResId() {
-        return R.xml.app_bubble_notification_settings;
-    }
-
-    @Override
-    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
-        mControllers = getPreferenceControllers(context, this);
-        return new ArrayList<>(mControllers);
-    }
-
-    protected static List<NotificationPreferenceController> getPreferenceControllers(
-            Context context, AppBubbleNotificationSettings fragment) {
-        List<NotificationPreferenceController> controllers = new ArrayList<>();
-        controllers.add(new HeaderPreferenceController(context, fragment));
-        controllers.add(new BubblePreferenceController(context, new NotificationBackend()));
-        return controllers;
-    }
-
-    @Override
-    public void onGlobalBubblePermissionChanged() {
-        updatePreferenceStates();
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-
-        if (mUid < 0 || TextUtils.isEmpty(mPkg) || mPkgInfo == null) {
-            Log.w(TAG, "Missing package or uid or packageinfo");
-            finish();
-            return;
-        }
-
-        for (NotificationPreferenceController controller : mControllers) {
-            controller.onResume(mAppRow, mChannel, mChannelGroup, mSuspendedAppsAdmin);
-            controller.displayPreference(getPreferenceScreen());
-        }
-        updatePreferenceStates();
-
-        mObserverMixin = new GlobalBubblePermissionObserverMixin(getContext(), this);
-        mObserverMixin.onStart();
-    }
-
-    @Override
-    public void onPause() {
-        mObserverMixin.onStop();
-        super.onPause();
-    }
-
-    public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
-            new BaseSearchIndexProvider() {
-
-                @Override
-                protected boolean isPageSearchEnabled(Context context) {
-                    return false;
-                }
-
-                @Override
-                public List<AbstractPreferenceController> createPreferenceControllers(Context
-                        context) {
-                    return new ArrayList<>(AppBubbleNotificationSettings.getPreferenceControllers(
-                            context, null));
-                }
-            };
-}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/AppNotificationSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/AppNotificationSettings.java
index 4c20fa0..f5efab7 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/AppNotificationSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/AppNotificationSettings.java
@@ -152,7 +152,6 @@
         mControllers.add(new DescriptionPreferenceController(context));
         mControllers.add(new NotificationsOffPreferenceController(context));
         mControllers.add(new DeletedChannelsPreferenceController(context, mBackend));
-        mControllers.add(new BubbleSummaryPreferenceController(context, mBackend));
         return new ArrayList<>(mControllers);
     }
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleNotificationPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleNotificationPreferenceController.java
deleted file mode 100644
index 5a26bf2..0000000
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleNotificationPreferenceController.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.developeroptions.notification;
-
-import static android.provider.Settings.Secure.NOTIFICATION_BUBBLES;
-import static android.provider.Settings.Secure.NOTIFICATION_BUBBLES;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.provider.Settings;
-import android.text.TextUtils;
-
-import com.android.car.developeroptions.core.PreferenceControllerMixin;
-import com.android.car.developeroptions.core.TogglePreferenceController;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnPause;
-import com.android.settingslib.core.lifecycle.events.OnResume;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
-public class BubbleNotificationPreferenceController extends TogglePreferenceController
-        implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener,
-        LifecycleObserver, OnResume, OnPause {
-
-    private static final String TAG = "BubbleNotifPrefContr";
-    @VisibleForTesting
-    static final int ON = 1;
-    @VisibleForTesting
-    static final int OFF = 0;
-
-    private SettingObserver mSettingObserver;
-
-    public BubbleNotificationPreferenceController(Context context, String preferenceKey) {
-        super(context, preferenceKey);
-    }
-
-    @Override
-    public void displayPreference(PreferenceScreen screen) {
-        super.displayPreference(screen);
-        Preference preference = screen.findPreference(getPreferenceKey());
-        if (preference != null) {
-            mSettingObserver = new SettingObserver(preference);
-        }
-    }
-
-    @Override
-    public void onResume() {
-        if (mSettingObserver != null) {
-            mSettingObserver.register(mContext.getContentResolver(), true /* register */);
-        }
-    }
-
-    @Override
-    public void onPause() {
-        if (mSettingObserver != null) {
-            mSettingObserver.register(mContext.getContentResolver(), false /* register */);
-        }
-    }
-
-    @Override
-    public int getAvailabilityStatus() {
-        return AVAILABLE;
-    }
-
-    @Override
-    public boolean isChecked() {
-        return Settings.Secure.getInt(mContext.getContentResolver(),
-                NOTIFICATION_BUBBLES, ON) == ON;
-    }
-
-    @Override
-    public boolean setChecked(boolean isChecked) {
-        return Settings.Secure.putInt(mContext.getContentResolver(),
-                NOTIFICATION_BUBBLES, isChecked ? ON : OFF);
-    }
-
-    class SettingObserver extends ContentObserver {
-
-        private final Uri NOTIFICATION_BUBBLES_URI =
-                Settings.Secure.getUriFor(NOTIFICATION_BUBBLES);
-
-        private final Preference mPreference;
-
-        public SettingObserver(Preference preference) {
-            super(new Handler());
-            mPreference = preference;
-        }
-
-        public void register(ContentResolver cr, boolean register) {
-            if (register) {
-                cr.registerContentObserver(NOTIFICATION_BUBBLES_URI, false, this);
-            } else {
-                cr.unregisterContentObserver(this);
-            }
-        }
-
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            super.onChange(selfChange, uri);
-            if (NOTIFICATION_BUBBLES_URI.equals(uri)) {
-                updateState(mPreference);
-            }
-        }
-    }
-}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleNotificationSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleNotificationSettings.java
deleted file mode 100644
index f45d72f..0000000
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleNotificationSettings.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.developeroptions.notification;
-
-import android.app.settings.SettingsEnums;
-import android.content.Context;
-import android.provider.SearchIndexableResource;
-
-import com.android.car.developeroptions.R;
-import com.android.car.developeroptions.core.OnActivityResultListener;
-import com.android.car.developeroptions.dashboard.DashboardFragment;
-import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.settingslib.search.SearchIndexable;
-
-import java.util.Arrays;
-import java.util.List;
-
-@SearchIndexable
-public class BubbleNotificationSettings extends DashboardFragment implements
-        OnActivityResultListener {
-    private static final String TAG = "BubbleNotiSettings";
-
-    @Override
-    public int getMetricsCategory() {
-        return SettingsEnums.BUBBLE_SETTINGS;
-    }
-
-    @Override
-    protected String getLogTag() {
-        return TAG;
-    }
-
-    @Override
-    protected int getPreferenceScreenResId() {
-        return R.xml.bubble_notification_settings;
-    }
-
-    /**
-     * For Search.
-     */
-    public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
-            new BaseSearchIndexProvider() {
-                @Override
-                public List<SearchIndexableResource> getXmlResourcesToIndex(
-                        Context context, boolean enabled) {
-                    final SearchIndexableResource sir = new SearchIndexableResource(context);
-                    sir.xmlResId = R.xml.bubble_notification_settings;
-                    return Arrays.asList(sir);
-                }
-            };
-}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubblePreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubblePreferenceController.java
deleted file mode 100644
index 82495c0..0000000
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubblePreferenceController.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.developeroptions.notification;
-
-import static android.provider.Settings.Secure.NOTIFICATION_BUBBLES;
-
-import android.content.Context;
-import android.provider.Settings;
-
-import com.android.car.developeroptions.R;
-import com.android.car.developeroptions.core.PreferenceControllerMixin;
-import com.android.settingslib.RestrictedSwitchPreference;
-
-import androidx.fragment.app.FragmentManager;
-import androidx.preference.Preference;
-
-public class BubblePreferenceController extends NotificationPreferenceController
-        implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
-
-    private static final String TAG = "BubblePrefContr";
-    private static final String KEY = "bubble_pref";
-    private static final int SYSTEM_WIDE_ON = 1;
-    private static final int SYSTEM_WIDE_OFF = 0;
-
-    private FragmentManager mFragmentManager;
-
-    public BubblePreferenceController(Context context, NotificationBackend backend) {
-        super(context, backend);
-    }
-
-    public BubblePreferenceController(Context context, FragmentManager fragmentManager,
-            NotificationBackend backend) {
-        super(context, backend);
-        mFragmentManager = fragmentManager;
-    }
-
-    @Override
-    public String getPreferenceKey() {
-        return KEY;
-    }
-
-    @Override
-    public boolean isAvailable() {
-        if (!super.isAvailable()) {
-            return false;
-        }
-        if (mAppRow == null && mChannel == null) {
-            return false;
-        }
-        if (mChannel != null) {
-            if (Settings.Secure.getInt(mContext.getContentResolver(),
-                    NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON) == SYSTEM_WIDE_OFF) {
-                return false;
-            }
-            if (isDefaultChannel()) {
-                return true;
-            } else {
-                return mAppRow == null ? false : mAppRow.allowBubbles;
-            }
-        }
-        return true;
-    }
-
-    public void updateState(Preference preference) {
-        if (mAppRow != null) {
-            RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
-            pref.setDisabledByAdmin(mAdmin);
-            if (mChannel != null) {
-                pref.setChecked(mChannel.canBubble());
-                pref.setEnabled(isChannelConfigurable() && !pref.isDisabledByAdmin());
-            } else {
-                pref.setChecked(mAppRow.allowBubbles
-                        && Settings.Secure.getInt(mContext.getContentResolver(),
-                        NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON) == SYSTEM_WIDE_ON);
-                pref.setSummary(mContext.getString(
-                        R.string.bubbles_app_toggle_summary, mAppRow.label));
-            }
-        }
-    }
-
-    @Override
-    public boolean onPreferenceChange(Preference preference, Object newValue) {
-        final boolean value = (Boolean) newValue;
-        if (mChannel != null) {
-            mChannel.setAllowBubbles(value);
-            saveChannel();
-            return true;
-        } else if (mAppRow != null) {
-            RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
-            // if the global setting is off, toggling app level permission requires extra
-            // confirmation
-            if (Settings.Secure.getInt(mContext.getContentResolver(),
-                    NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON) == SYSTEM_WIDE_OFF
-                    && !pref.isChecked()) {
-                new BubbleWarningDialogFragment()
-                        .setPkgInfo(mAppRow.pkg, mAppRow.uid)
-                        .show(mFragmentManager, "dialog");
-                return false;
-            } else {
-                mAppRow.allowBubbles = value;
-                mBackend.setAllowBubbles(mAppRow.pkg, mAppRow.uid, value);
-            }
-        }
-        return true;
-    }
-
-    // Used in app level prompt that confirms the user is ok with turning on bubbles
-    // globally. If they aren't, undo what
-    public static void revertBubblesApproval(Context mContext, String pkg, int uid) {
-        NotificationBackend backend = new NotificationBackend();
-        backend.setAllowBubbles(pkg, uid, false);
-        // changing the global settings will cause the observer on the host page to reload
-        // correct preference state
-        Settings.Secure.putInt(mContext.getContentResolver(),
-                NOTIFICATION_BUBBLES, SYSTEM_WIDE_OFF);
-    }
-
-    // Apply global bubbles approval
-    public static void applyBubblesApproval(Context mContext, String pkg, int uid) {
-        NotificationBackend backend = new NotificationBackend();
-        backend.setAllowBubbles(pkg, uid, true);
-        // changing the global settings will cause the observer on the host page to reload
-        // correct preference state
-        Settings.Secure.putInt(mContext.getContentResolver(),
-                NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON);
-    }
-}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleSummaryNotificationPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleSummaryNotificationPreferenceController.java
deleted file mode 100644
index 78ab78a..0000000
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleSummaryNotificationPreferenceController.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.developeroptions.notification;
-
-import static android.provider.Settings.Secure.NOTIFICATION_BUBBLES;
-
-import android.content.Context;
-import android.provider.Settings;
-
-import com.android.car.developeroptions.R;
-import com.android.car.developeroptions.core.BasePreferenceController;
-
-import androidx.annotation.VisibleForTesting;
-
-public class BubbleSummaryNotificationPreferenceController extends BasePreferenceController {
-
-    @VisibleForTesting
-    static final int ON = 1;
-
-    public BubbleSummaryNotificationPreferenceController(Context context, String preferenceKey) {
-        super(context, preferenceKey);
-    }
-
-    @Override
-    public CharSequence getSummary() {
-        return mContext.getString(
-                areBubblesEnabled() ? R.string.switch_on_text : R.string.switch_off_text);
-    }
-
-    @Override
-    public int getAvailabilityStatus() {
-        return AVAILABLE;
-    }
-
-    private boolean areBubblesEnabled() {
-        return Settings.Secure.getInt(mContext.getContentResolver(),
-                NOTIFICATION_BUBBLES, ON) == ON;
-    }
-}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleSummaryPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleSummaryPreferenceController.java
deleted file mode 100644
index ac24781..0000000
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleSummaryPreferenceController.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.developeroptions.notification;
-
-import static android.provider.Settings.Secure.NOTIFICATION_BUBBLES;
-
-import android.app.settings.SettingsEnums;
-import android.content.Context;
-import android.os.Bundle;
-import android.provider.Settings;
-
-import com.android.car.developeroptions.R;
-import com.android.car.developeroptions.applications.AppInfoBase;
-import com.android.car.developeroptions.core.SubSettingLauncher;
-
-import androidx.preference.Preference;
-
-public class BubbleSummaryPreferenceController extends NotificationPreferenceController {
-
-    private static final String KEY = "bubble_link_pref";
-    private static final int SYSTEM_WIDE_ON = 1;
-    private static final int SYSTEM_WIDE_OFF = 0;
-
-    public BubbleSummaryPreferenceController(Context context, NotificationBackend backend) {
-        super(context, backend);
-    }
-
-    @Override
-    public String getPreferenceKey() {
-        return KEY;
-    }
-
-    @Override
-    public boolean isAvailable() {
-        if (!super.isAvailable()) {
-            return false;
-        }
-        if (mAppRow == null && mChannel == null) {
-            return false;
-        }
-        if (mChannel != null) {
-            if (Settings.Secure.getInt(mContext.getContentResolver(),
-                    NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON) == SYSTEM_WIDE_OFF) {
-                return false;
-            }
-            if (isDefaultChannel()) {
-                return true;
-            } else {
-                return mAppRow == null ? false : mAppRow.allowBubbles;
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public void updateState(Preference preference) {
-        super.updateState(preference);
-
-        if (mAppRow != null) {
-            Bundle args = new Bundle();
-            args.putString(AppInfoBase.ARG_PACKAGE_NAME, mAppRow.pkg);
-            args.putInt(AppInfoBase.ARG_PACKAGE_UID, mAppRow.uid);
-
-            preference.setIntent(new SubSettingLauncher(mContext)
-                    .setDestination(AppBubbleNotificationSettings.class.getName())
-                    .setArguments(args)
-                    .setSourceMetricsCategory(
-                            SettingsEnums.NOTIFICATION_APP_NOTIFICATION)
-                    .toIntent());
-        }
-    }
-
-    @Override
-    public CharSequence getSummary() {
-        boolean canBubble = false;
-        if (mAppRow != null) {
-            if (mChannel != null) {
-                canBubble |= mChannel.canBubble();
-            } else {
-               canBubble |= mAppRow.allowBubbles
-                       && (Settings.Secure.getInt(mContext.getContentResolver(),
-                       NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON) == SYSTEM_WIDE_ON);
-            }
-        }
-        return mContext.getString(canBubble ? R.string.switch_on_text : R.string.switch_off_text);
-    }
-}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleWarningDialogFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleWarningDialogFragment.java
deleted file mode 100644
index d5bb8a7..0000000
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/BubbleWarningDialogFragment.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.car.developeroptions.notification;
-
-import android.app.Dialog;
-import android.app.settings.SettingsEnums;
-import android.os.Bundle;
-
-import androidx.appcompat.app.AlertDialog;
-
-import com.android.car.developeroptions.R;
-import com.android.car.developeroptions.core.instrumentation.InstrumentedDialogFragment;
-
-public class BubbleWarningDialogFragment extends InstrumentedDialogFragment {
-    static final String KEY_PKG = "p";
-    static final String KEY_UID = "u";
-
-
-    @Override
-    public int getMetricsCategory() {
-        return SettingsEnums.DIALOG_APP_BUBBLE_SETTINGS;
-    }
-
-    public BubbleWarningDialogFragment setPkgInfo(String pkg, int uid) {
-        Bundle args = new Bundle();
-        args.putString(KEY_PKG, pkg);
-        args.putInt(KEY_UID, uid);
-        setArguments(args);
-        return this;
-    }
-
-    @Override
-    public Dialog onCreateDialog(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        final Bundle args = getArguments();
-        final String pkg = args.getString(KEY_PKG);
-        final int uid = args.getInt(KEY_UID);
-
-        final String title =
-                getResources().getString(R.string.bubbles_feature_disabled_dialog_title);
-        final String summary = getResources()
-                .getString(R.string.bubbles_feature_disabled_dialog_text);
-        return new AlertDialog.Builder(getContext())
-                .setMessage(summary)
-                .setTitle(title)
-                .setCancelable(true)
-                .setPositiveButton(R.string.bubbles_feature_disabled_button_approve,
-                        (dialog, id) ->
-                                BubblePreferenceController.applyBubblesApproval(
-                                        getContext(), pkg, uid))
-                .setNegativeButton(R.string.bubbles_feature_disabled_button_cancel,
-                        (dialog, id) ->
-                                BubblePreferenceController.revertBubblesApproval(
-                                        getContext(), pkg, uid))
-                .create();
-    }
-}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ChannelNotificationSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ChannelNotificationSettings.java
index b851ce9..3e3b073 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ChannelNotificationSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ChannelNotificationSettings.java
@@ -113,7 +113,6 @@
         mControllers.add(new BadgePreferenceController(context, mBackend));
         mControllers.add(new DndPreferenceController(context, mBackend));
         mControllers.add(new NotificationsOffPreferenceController(context));
-        mControllers.add(new BubblePreferenceController(context, mBackend));
         return new ArrayList<>(mControllers);
     }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/GlobalBubblePermissionObserverMixin.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/GlobalBubblePermissionObserverMixin.java
deleted file mode 100644
index 08d5a51..0000000
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/GlobalBubblePermissionObserverMixin.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.developeroptions.notification;
-
-import android.content.Context;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
-import android.provider.Settings;
-
-public class GlobalBubblePermissionObserverMixin extends ContentObserver {
-
-    public interface Listener {
-        void onGlobalBubblePermissionChanged();
-    }
-
-    private final Context mContext;
-    private final Listener mListener;
-
-    public GlobalBubblePermissionObserverMixin(Context context, Listener listener) {
-        super(new Handler(Looper.getMainLooper()));
-        mContext = context;
-        mListener = listener;
-    }
-
-    @Override
-    public void onChange(boolean selfChange, Uri uri) {
-        if (mListener != null) {
-            mListener.onGlobalBubblePermissionChanged();
-        }
-    }
-
-    public void onStart() {
-        mContext.getContentResolver().registerContentObserver(
-                Settings.Secure.getUriFor(
-                        Settings.Secure.NOTIFICATION_BUBBLES),
-                false /* notifyForDescendants */,
-                this /* observer */);
-    }
-
-    public void onStop() {
-        mContext.getContentResolver().unregisterContentObserver(this /* observer */);
-    }
-}
\ No newline at end of file
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationAccessSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationAccessSettings.java
index 18dd856..b6c57c3 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationAccessSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationAccessSettings.java
@@ -37,8 +37,8 @@
 import com.android.car.developeroptions.core.instrumentation.InstrumentedDialogFragment;
 import com.android.car.developeroptions.overlay.FeatureFactory;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.utils.ManagedServiceSettings;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationAssistantPicker.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationAssistantPicker.java
index 5b037e6..3696a03 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationAssistantPicker.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationAssistantPicker.java
@@ -23,20 +23,18 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
 import android.graphics.drawable.Drawable;
-import android.os.RemoteException;
 import android.provider.SearchIndexableResource;
 import android.provider.Settings;
 import android.service.notification.NotificationAssistantService;
 import android.text.TextUtils;
-import android.util.Log;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.applications.defaultapps.DefaultAppPickerFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.applications.DefaultAppInfo;
 import com.android.settingslib.applications.ServiceListing;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.widget.CandidateInfo;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationBackend.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationBackend.java
index c459efc..4e71f42 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationBackend.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationBackend.java
@@ -19,6 +19,7 @@
 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
 
 import android.app.INotificationManager;
+import android.app.NotificationManager;
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
 import android.app.usage.IUsageStatsManager;
@@ -71,7 +72,7 @@
         row.icon = IconDrawableFactory.newInstance(context).getBadgedIcon(app);
         row.banned = getNotificationsBanned(row.pkg, row.uid);
         row.showBadge = canShowBadge(row.pkg, row.uid);
-        row.allowBubbles = canBubble(row.pkg, row.uid);
+        row.bubblePreference = getBubblePreference(row.pkg, row.uid);
         row.userId = UserHandle.getUserId(row.uid);
         row.blockedChannelCount = getBlockedChannelCount(row.pkg, row.uid);
         row.channelCount = getChannelCount(row.pkg, row.uid);
@@ -145,7 +146,7 @@
         try {
             if (onlyHasDefaultChannel(pkg, uid)) {
                 NotificationChannel defaultChannel =
-                        getChannel(pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID);
+                        getChannel(pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, null);
                 defaultChannel.setImportance(enabled ? IMPORTANCE_UNSPECIFIED : IMPORTANCE_NONE);
                 updateChannel(pkg, uid, defaultChannel);
             }
@@ -176,18 +177,18 @@
         }
     }
 
-    public boolean canBubble(String pkg, int uid) {
+    public int getBubblePreference(String pkg, int uid) {
         try {
-            return sINM.areBubblesAllowedForPackage(pkg, uid);
+            return sINM.getBubblePreferenceForPackage(pkg, uid);
         } catch (Exception e) {
             Log.w(TAG, "Error calling NoMan", e);
-            return false;
+            return -1;
         }
     }
 
-    public boolean setAllowBubbles(String pkg, int uid, boolean allow) {
+    public boolean setAllowBubbles(String pkg, int uid, int pref) {
         try {
-            sINM.setBubblesAllowed(pkg, uid, allow);
+            sINM.setBubblesAllowed(pkg, uid, pref);
             return true;
         } catch (Exception e) {
             Log.w(TAG, "Error calling NoMan", e);
@@ -195,13 +196,26 @@
         }
     }
 
-
     public NotificationChannel getChannel(String pkg, int uid, String channelId) {
         if (channelId == null) {
             return null;
         }
         try {
-            return sINM.getNotificationChannelForPackage(pkg, uid, channelId, true);
+            return sINM.getNotificationChannelForPackage(pkg, uid, channelId, null, true);
+        } catch (Exception e) {
+            Log.w(TAG, "Error calling NoMan", e);
+            return null;
+        }
+    }
+
+
+    public NotificationChannel getChannel(String pkg, int uid, String channelId,
+            String conversationId) {
+        if (channelId == null) {
+            return null;
+        }
+        try {
+            return sINM.getNotificationChannelForPackage(pkg, uid, channelId, conversationId, true);
         } catch (Exception e) {
             Log.w(TAG, "Error calling NoMan", e);
             return null;
@@ -472,7 +486,7 @@
         public boolean lockedImportance;
         public String lockedChannelId;
         public boolean showBadge;
-        public boolean allowBubbles;
+        public int bubblePreference = NotificationManager.BUBBLE_PREFERENCE_NONE;
         public int userId;
         public int blockedChannelCount;
         public int channelCount;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationPreferenceController.java
index 6a3b3fd..4122b66 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationPreferenceController.java
@@ -131,7 +131,7 @@
                 return false;
             }
 
-            return mChannel.isBlockableSystem() || !mAppRow.systemApp
+            return mChannel.isBlockable() || !mAppRow.systemApp
                     || mChannel.getImportance() == IMPORTANCE_NONE;
         }
         return false;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationSettingsBase.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationSettingsBase.java
index b6fadcb..f8ba753 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationSettingsBase.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationSettingsBase.java
@@ -328,7 +328,7 @@
                 return true;
             }
 
-            return channel.isBlockableSystem()
+            return channel.isBlockable()
                     || channel.getImportance() == NotificationManager.IMPORTANCE_NONE;
         }
         return false;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationStation.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationStation.java
index 03b0159..e9a8081 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationStation.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/NotificationStation.java
@@ -271,7 +271,7 @@
             StatusBarNotification[] active = mNoMan.getActiveNotifications(
                     mContext.getPackageName());
             StatusBarNotification[] dismissed = mNoMan.getHistoricalNotifications(
-                    mContext.getPackageName(), 50);
+                    mContext.getPackageName(), 50, true);
 
             List<HistoricalNotificationInfo> list
                     = new ArrayList<HistoricalNotificationInfo>(active.length + dismissed.length);
@@ -368,7 +368,7 @@
         }
         try {
             NotificationChannel channel = mNoMan.getNotificationChannelForPackage(
-                    sbn.getPackageName(), sbn.getUid(), n.getChannelId(), false);
+                    sbn.getPackageName(), sbn.getUid(), n.getChannelId(), null, false);
             sb.append("\n")
                     .append(bold(getString(R.string.notification_log_details_sound)))
                     .append(delim);
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenAccessSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenAccessSettings.java
index a9e36ab..c01b073 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenAccessSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenAccessSettings.java
@@ -37,8 +37,8 @@
 import com.android.car.developeroptions.applications.specialaccess.zenaccess.ZenAccessDetails;
 import com.android.car.developeroptions.applications.specialaccess.zenaccess.ZenAccessSettingObserverMixin;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.widget.EmptyTextSettings;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 import com.android.settingslib.widget.apppreference.AppPreference;
 
@@ -86,11 +86,7 @@
     @Override
     public void onResume() {
         super.onResume();
-        if (!ActivityManager.isLowRamDeviceStatic()) {
-            reloadList();
-        } else {
-            setEmptyText(R.string.disabled_low_ram_device);
-        }
+        reloadList();
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenCustomRuleBlockedEffectsSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenCustomRuleBlockedEffectsSettings.java
index b856ecd..505b3ca 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenCustomRuleBlockedEffectsSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenCustomRuleBlockedEffectsSettings.java
@@ -32,8 +32,6 @@
     @Override
     public void onCreate(Bundle bundle) {
         super.onCreate(bundle);
-        mFooterPreferenceMixin.createFooterPreference().setTitle(
-                R.string.zen_mode_blocked_effects_footer);
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeAutomationSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeAutomationSettings.java
index 58008aa..f2fc762 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeAutomationSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeAutomationSettings.java
@@ -33,11 +33,11 @@
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.utils.ManagedServiceSettings;
 import com.android.car.developeroptions.utils.ZenServiceListing;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeBlockedEffectsSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeBlockedEffectsSettings.java
index 3148d1b..988e500 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeBlockedEffectsSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeBlockedEffectsSettings.java
@@ -31,9 +31,9 @@
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
@@ -45,8 +45,6 @@
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
-        mFooterPreferenceMixin.createFooterPreference().setTitle(
-                R.string.zen_mode_blocked_effects_footer);
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeBypassingAppsSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeBypassingAppsSettings.java
index 92add24..ca932ca 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeBypassingAppsSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeBypassingAppsSettings.java
@@ -26,8 +26,8 @@
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeCallsSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeCallsSettings.java
index c8889ba..7a13860 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeCallsSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeCallsSettings.java
@@ -24,9 +24,9 @@
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeMessagesSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeMessagesSettings.java
index ef004ef..b45f225 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeMessagesSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeMessagesSettings.java
@@ -24,9 +24,9 @@
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeRestrictNotificationsSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeRestrictNotificationsSettings.java
index b27f7c4..08f4953 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeRestrictNotificationsSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeRestrictNotificationsSettings.java
@@ -23,9 +23,9 @@
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 import com.android.settingslib.widget.FooterPreference;
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeSettings.java
index d5b78aa..8105e23 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeSettings.java
@@ -39,9 +39,9 @@
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeSoundVibrationSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeSoundVibrationSettings.java
index 6e3d2dc..b238cc7 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeSoundVibrationSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/notification/ZenModeSoundVibrationSettings.java
@@ -22,9 +22,9 @@
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/BiometricFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/BiometricFragment.java
index a6c43bf..9720013 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/BiometricFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/BiometricFragment.java
@@ -16,23 +16,17 @@
 
 package com.android.car.developeroptions.password;
 
-import android.app.Activity;
 import android.app.settings.SettingsEnums;
 import android.content.DialogInterface;
 import android.hardware.biometrics.BiometricConstants;
 import android.hardware.biometrics.BiometricPrompt;
 import android.hardware.biometrics.BiometricPrompt.AuthenticationCallback;
 import android.hardware.biometrics.BiometricPrompt.AuthenticationResult;
-import android.hardware.biometrics.IBiometricConfirmDeviceCredentialCallback;
 import android.os.Bundle;
 import android.os.CancellationSignal;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Log;
 
 import androidx.annotation.NonNull;
 
-import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.core.InstrumentedFragment;
 
 import java.util.concurrent.Executor;
@@ -85,20 +79,6 @@
         }
     };
 
-    // TODO(b/123378871): Remove when moved.
-    private final IBiometricConfirmDeviceCredentialCallback mCancelCallback
-        = new IBiometricConfirmDeviceCredentialCallback.Stub() {
-        @Override
-        public void cancel() {
-            final Activity activity = getActivity();
-            if (activity != null) {
-                activity.finish();
-            } else {
-                Log.e(TAG, "Activity null!");
-            }
-        }
-    };
-
     /**
      * @param bundle Bundle passed from {@link BiometricPrompt.Builder#buildIntent()}
      * @return
@@ -140,20 +120,17 @@
         mBiometricPrompt = new BiometricPrompt.Builder(getContext())
             .setTitle(mBundle.getString(BiometricPrompt.KEY_TITLE))
             .setUseDefaultTitle() // use default title if title is null/empty
-            .setFromConfirmDeviceCredential()
+            .setDeviceCredentialAllowed(true)
             .setSubtitle(mBundle.getString(BiometricPrompt.KEY_SUBTITLE))
             .setDescription(mBundle.getString(BiometricPrompt.KEY_DESCRIPTION))
             .setConfirmationRequired(
                     mBundle.getBoolean(BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true))
-            .setNegativeButton(getResources().getString(
-                    R.string.confirm_device_credential_use_alternate_method),
-                    mClientExecutor, mNegativeButtonListener)
             .build();
         mCancellationSignal = new CancellationSignal();
 
         // TODO: CC doesn't use crypto for now
         mBiometricPrompt.authenticateUser(mCancellationSignal, mClientExecutor,
-                mAuthenticationCallback, mUserId, mCancelCallback);
+                mAuthenticationCallback, mUserId);
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ChooseLockGeneric.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ChooseLockGeneric.java
index 8e44e0b..8e3379b 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ChooseLockGeneric.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ChooseLockGeneric.java
@@ -59,7 +59,6 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
-import com.android.internal.widget.LockPatternUtils;
 import com.android.car.developeroptions.EncryptionInterstitial;
 import com.android.car.developeroptions.EventLogTags;
 import com.android.car.developeroptions.R;
@@ -70,13 +69,12 @@
 import com.android.car.developeroptions.biometrics.fingerprint.FingerprintEnrollFindSensor;
 import com.android.car.developeroptions.core.instrumentation.InstrumentedDialogFragment;
 import com.android.car.developeroptions.search.SearchFeatureProvider;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockscreenCredential;
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 import com.android.settingslib.RestrictedLockUtilsInternal;
 import com.android.settingslib.RestrictedPreference;
-import com.android.settingslib.widget.FooterPreference;
-import com.android.settingslib.widget.FooterPreferenceMixinCompat;
 
-import java.util.Arrays;
 import java.util.List;
 
 public class ChooseLockGeneric extends SettingsActivity {
@@ -112,6 +110,7 @@
         public static final String MINIMUM_QUALITY_KEY = "minimum_quality";
         public static final String HIDE_DISABLED_PREFS = "hide_disabled_prefs";
         public static final String TAG_FRP_WARNING_DIALOG = "frp_warning_dialog";
+        public static final String KEY_LOCK_SETTINGS_FOOTER = "lock_settings_footer";
 
         /**
          * Boolean extra determining whether a "screen lock options" button should be shown. This
@@ -152,7 +151,7 @@
         private boolean mPasswordConfirmed = false;
         private boolean mWaitingForConfirmation = false;
         private boolean mForChangeCredRequiredForBoot = false;
-        private byte[] mUserPassword;
+        private LockscreenCredential mUserPassword;
         private LockPatternUtils mLockPatternUtils;
         private FingerprintManager mFingerprintManager;
         private FaceManager mFaceManager;
@@ -202,7 +201,7 @@
                 .getBooleanExtra(CONFIRM_CREDENTIALS, true);
             if (getActivity() instanceof ChooseLockGeneric.InternalActivity) {
                 mPasswordConfirmed = !confirmCredentials;
-                mUserPassword = getActivity().getIntent().getByteArrayExtra(
+                mUserPassword = getActivity().getIntent().getParcelableExtra(
                         ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
             }
 
@@ -226,7 +225,7 @@
                 mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED);
                 mWaitingForConfirmation = savedInstanceState.getBoolean(WAITING_FOR_CONFIRMATION);
                 if (mUserPassword == null) {
-                    mUserPassword = savedInstanceState.getByteArray(
+                    mUserPassword = savedInstanceState.getParcelable(
                             ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
                 }
             }
@@ -385,11 +384,11 @@
             if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == Activity.RESULT_OK) {
                 mPasswordConfirmed = true;
                 mUserPassword = data != null
-                    ? data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD)
+                    ? data.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD)
                     : null;
                 updatePreferencesOrFinish(false /* isRecreatingActivity */);
                 if (mForChangeCredRequiredForBoot) {
-                    if (!(mUserPassword == null || mUserPassword.length == 0)) {
+                    if (mUserPassword != null && !mUserPassword.isNone()) {
                         maybeEnableEncryption(
                                 mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId), false);
                     } else {
@@ -449,7 +448,7 @@
             outState.putBoolean(PASSWORD_CONFIRMED, mPasswordConfirmed);
             outState.putBoolean(WAITING_FOR_CONFIRMATION, mWaitingForConfirmation);
             if (mUserPassword != null) {
-                outState.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, mUserPassword);
+                outState.putParcelable(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, mUserPassword);
             }
         }
 
@@ -487,12 +486,12 @@
 
         protected void addPreferences() {
             addPreferencesFromResource(R.xml.security_settings_picker);
-
+            final Preference footer = findPreference(KEY_LOCK_SETTINGS_FOOTER);
             if (!TextUtils.isEmpty(mCallerAppName)) {
-                FooterPreferenceMixinCompat footerMixin =
-                        new FooterPreferenceMixinCompat(this, getSettingsLifecycle());
-                FooterPreference footer = footerMixin.createFooterPreference();
+                footer.setVisible(true);
                 footer.setTitle(getFooterString());
+            } else {
+                footer.setVisible(false);
             }
 
             // Used for testing purposes
@@ -671,7 +670,7 @@
             setPreferenceSummary(ScreenLockType.MANAGED, R.string.secure_lock_encryption_warning);
         }
 
-        protected Intent getLockManagedPasswordIntent(byte[] password) {
+        protected Intent getLockManagedPasswordIntent(LockscreenCredential password) {
             return mManagedPasswordProvider.createIntent(false, password);
         }
 
@@ -770,7 +769,8 @@
             }
 
             if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
-                mChooseLockSettingsHelper.utils().clearLock(mUserPassword, mUserId);
+                mChooseLockSettingsHelper.utils().setLockCredential(
+                        LockscreenCredential.createNone(), mUserPassword, mUserId);
                 mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled, mUserId);
                 getActivity().setResult(Activity.RESULT_OK);
                 removeAllBiometricsForUserAndFinish(mUserId);
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ChooseLockPassword.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ChooseLockPassword.java
index d567a40..6bc66fb 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ChooseLockPassword.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ChooseLockPassword.java
@@ -17,13 +17,20 @@
 package com.android.car.developeroptions.password;
 
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
 
 import static com.android.car.developeroptions.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
+import static com.android.internal.widget.PasswordValidationError.CONTAINS_INVALID_CHARACTERS;
+import static com.android.internal.widget.PasswordValidationError.CONTAINS_SEQUENCE;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_DIGITS;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_LETTERS;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_LOWER_CASE;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_NON_DIGITS;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_NON_LETTER;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_SYMBOLS;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_UPPER_CASE;
+import static com.android.internal.widget.PasswordValidationError.TOO_LONG;
+import static com.android.internal.widget.PasswordValidationError.TOO_SHORT;
 
 import android.app.Activity;
 import android.app.admin.DevicePolicyManager;
@@ -60,10 +67,6 @@
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
-import com.android.internal.widget.TextViewInputDisabler;
 import com.android.car.developeroptions.EncryptionInterstitial;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.SettingsActivity;
@@ -72,13 +75,18 @@
 import com.android.car.developeroptions.core.InstrumentedFragment;
 import com.android.car.developeroptions.notification.RedactionInterstitial;
 import com.android.car.developeroptions.widget.ImeAwareEditText;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
+import com.android.internal.widget.LockscreenCredential;
+import com.android.internal.widget.PasswordValidationError;
+import com.android.internal.widget.TextViewInputDisabler;
 
 import com.google.android.setupcompat.template.FooterBarMixin;
 import com.google.android.setupcompat.template.FooterButton;
 import com.google.android.setupdesign.GlifLayout;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 
 public class ChooseLockPassword extends SettingsActivity {
@@ -124,7 +132,7 @@
             return this;
         }
 
-        public IntentBuilder setPassword(byte[] password) {
+        public IntentBuilder setPassword(LockscreenCredential password) {
             mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, password);
             return this;
         }
@@ -181,28 +189,24 @@
 
     public static class ChooseLockPasswordFragment extends InstrumentedFragment
             implements OnEditorActionListener, TextWatcher, SaveAndFinishWorker.Listener {
-        private static final String KEY_FIRST_PIN = "first_pin";
+        private static final String KEY_FIRST_PASSWORD = "first_password";
         private static final String KEY_UI_STAGE = "ui_stage";
-        private static final String KEY_CURRENT_PASSWORD = "current_password";
+        private static final String KEY_CURRENT_CREDENTIAL = "current_credential";
         private static final String FRAGMENT_TAG_SAVE_AND_FINISH = "save_and_finish_worker";
 
-        private byte[] mCurrentPassword;
-        private byte[] mChosenPassword;
+        private LockscreenCredential mCurrentCredential;
+        private LockscreenCredential mChosenPassword;
         private boolean mHasChallenge;
         private long mChallenge;
         private ImeAwareEditText mPasswordEntry;
         private TextViewInputDisabler mPasswordEntryInputDisabler;
-        private int mPasswordMinLength = LockPatternUtils.MIN_LOCK_PASSWORD_SIZE;
-        private int mPasswordMaxLength = 16;
-        private int mPasswordMinLetters = 0;
-        private int mPasswordMinUpperCase = 0;
-        private int mPasswordMinLowerCase = 0;
-        private int mPasswordMinSymbols = 0;
-        private int mPasswordMinNumeric = 0;
-        private int mPasswordMinNonLetter = 0;
-        private int mPasswordMinLengthToFulfillAllPolicies = 0;
-        private boolean mPasswordNumSequenceAllowed = true;
-        @PasswordComplexity private int mRequestedMinComplexity = PASSWORD_COMPLEXITY_NONE;
+
+        // Minimum password metrics enforced by admins.
+        private PasswordMetrics mMinMetrics;
+        private List<PasswordValidationError> mValidationErrors;
+        private boolean mPasswordReused;
+
+        @PasswordComplexity private int mMinComplexity = PASSWORD_COMPLEXITY_NONE;
         protected int mUserId;
         private byte[] mPasswordHistoryHashFactor;
 
@@ -216,7 +220,7 @@
         protected boolean mForFingerprint;
         protected boolean mForFace;
 
-        private byte[] mFirstPin;
+        private LockscreenCredential mFirstPassword;
         private RecyclerView mPasswordRestrictionView;
         protected boolean mIsAlphaMode;
         protected FooterButton mSkipOrClearButton;
@@ -228,28 +232,6 @@
         private static final int CONFIRM_EXISTING_REQUEST = 58;
         static final int RESULT_FINISHED = RESULT_FIRST_USER;
 
-        private static final int MIN_LETTER_IN_PASSWORD = 0;
-        private static final int MIN_UPPER_LETTERS_IN_PASSWORD = 1;
-        private static final int MIN_LOWER_LETTERS_IN_PASSWORD = 2;
-        private static final int MIN_SYMBOLS_IN_PASSWORD = 3;
-        private static final int MIN_NUMBER_IN_PASSWORD = 4;
-        private static final int MIN_NON_LETTER_IN_PASSWORD = 5;
-
-        // Error code returned from {@link #validatePassword(byte[])}.
-        static final int NO_ERROR = 0;
-        static final int CONTAIN_INVALID_CHARACTERS = 1 << 0;
-        static final int TOO_SHORT = 1 << 1;
-        static final int TOO_LONG = 1 << 2;
-        static final int CONTAIN_NON_DIGITS = 1 << 3;
-        static final int CONTAIN_SEQUENTIAL_DIGITS = 1 << 4;
-        static final int RECENTLY_USED = 1 << 5;
-        static final int NOT_ENOUGH_LETTER = 1 << 6;
-        static final int NOT_ENOUGH_UPPER_CASE = 1 << 7;
-        static final int NOT_ENOUGH_LOWER_CASE = 1 << 8;
-        static final int NOT_ENOUGH_DIGITS = 1 << 9;
-        static final int NOT_ENOUGH_SYMBOLS = 1 << 10;
-        static final int NOT_ENOUGH_NON_LETTER = 1 << 11;
-
         /**
          * Keep track internally of where the user is in choosing a pattern.
          */
@@ -381,13 +363,12 @@
             mForFingerprint = intent.getBooleanExtra(
                     ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
             mForFace = intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
-            mRequestedMinComplexity = intent.getIntExtra(
+            mMinComplexity = intent.getIntExtra(
                     EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
-            mRequestedQuality = Math.max(
-                    intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, mRequestedQuality),
-                    mLockPatternUtils.getRequestedPasswordQuality(mUserId));
+            mRequestedQuality = intent.getIntExtra(
+                    LockPatternUtils.PASSWORD_TYPE_KEY, PASSWORD_QUALITY_NUMERIC);
 
-            loadDpmPasswordRequirements();
+            mMinMetrics = mLockPatternUtils.getRequestedPasswordMetrics(mUserId);
             mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());
 
             if (intent.getBooleanExtra(
@@ -395,13 +376,13 @@
                 SaveAndFinishWorker w = new SaveAndFinishWorker();
                 final boolean required = getActivity().getIntent().getBooleanExtra(
                         EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
-                byte[] currentBytes = intent.getByteArrayExtra(
+                LockscreenCredential currentCredential = intent.getParcelableExtra(
                         ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
 
                 w.setBlocking(true);
                 w.setListener(this);
                 w.start(mChooseLockSettingsHelper.utils(), required, false, 0,
-                        currentBytes, currentBytes, mRequestedQuality, mUserId);
+                        currentCredential, currentCredential, mUserId);
             }
             mTextChangedHandler = new TextChangedHandler();
         }
@@ -476,7 +457,7 @@
             Intent intent = getActivity().getIntent();
             final boolean confirmCredentials = intent.getBooleanExtra(
                     ChooseLockGeneric.CONFIRM_CREDENTIALS, true);
-            mCurrentPassword = intent.getByteArrayExtra(
+            mCurrentCredential = intent.getParcelableExtra(
                     ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
             mHasChallenge = intent.getBooleanExtra(
                     ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
@@ -491,15 +472,15 @@
             } else {
 
                 // restore from previous state
-                mFirstPin = savedInstanceState.getByteArray(KEY_FIRST_PIN);
+                mFirstPassword = savedInstanceState.getParcelable(KEY_FIRST_PASSWORD);
                 final String state = savedInstanceState.getString(KEY_UI_STAGE);
                 if (state != null) {
                     mUiStage = Stage.valueOf(state);
                     updateStage(mUiStage);
                 }
 
-                if (mCurrentPassword == null) {
-                    mCurrentPassword = savedInstanceState.getByteArray(KEY_CURRENT_PASSWORD);
+                if (mCurrentCredential == null) {
+                    mCurrentCredential = savedInstanceState.getParcelable(KEY_CURRENT_CREDENTIAL);
                 }
 
                 // Re-attach to the exiting worker if there is one.
@@ -557,8 +538,8 @@
         public void onSaveInstanceState(Bundle outState) {
             super.onSaveInstanceState(outState);
             outState.putString(KEY_UI_STAGE, mUiStage.name());
-            outState.putByteArray(KEY_FIRST_PIN, mFirstPin);
-            outState.putByteArray(KEY_CURRENT_PASSWORD, mCurrentPassword);
+            outState.putParcelable(KEY_FIRST_PASSWORD, mFirstPassword);
+            outState.putParcelable(KEY_CURRENT_CREDENTIAL, mCurrentCredential);
         }
 
         @Override
@@ -571,7 +552,7 @@
                         getActivity().setResult(RESULT_FINISHED);
                         getActivity().finish();
                     } else {
-                        mCurrentPassword = data.getByteArrayExtra(
+                        mCurrentCredential = data.getParcelableExtra(
                                 ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
                     }
                     break;
@@ -595,210 +576,27 @@
         }
 
         /**
-         * Read the requirements from {@link DevicePolicyManager} and intent and aggregate them.
-         */
-        private void loadDpmPasswordRequirements() {
-            final int dpmPasswordQuality = mLockPatternUtils.getRequestedPasswordQuality(mUserId);
-            if (dpmPasswordQuality == PASSWORD_QUALITY_NUMERIC_COMPLEX) {
-                mPasswordNumSequenceAllowed = false;
-            }
-            mPasswordMinLength = Math.max(LockPatternUtils.MIN_LOCK_PASSWORD_SIZE,
-                    mLockPatternUtils.getRequestedMinimumPasswordLength(mUserId));
-            mPasswordMaxLength = mLockPatternUtils.getMaximumPasswordLength(mRequestedQuality);
-            mPasswordMinLetters = mLockPatternUtils.getRequestedPasswordMinimumLetters(mUserId);
-            mPasswordMinUpperCase = mLockPatternUtils.getRequestedPasswordMinimumUpperCase(mUserId);
-            mPasswordMinLowerCase = mLockPatternUtils.getRequestedPasswordMinimumLowerCase(mUserId);
-            mPasswordMinNumeric = mLockPatternUtils.getRequestedPasswordMinimumNumeric(mUserId);
-            mPasswordMinSymbols = mLockPatternUtils.getRequestedPasswordMinimumSymbols(mUserId);
-            mPasswordMinNonLetter = mLockPatternUtils.getRequestedPasswordMinimumNonLetter(mUserId);
-
-            // Modify the value based on dpm policy
-            switch (dpmPasswordQuality) {
-                case PASSWORD_QUALITY_ALPHABETIC:
-                    if (mPasswordMinLetters == 0) {
-                        mPasswordMinLetters = 1;
-                    }
-                    break;
-                case PASSWORD_QUALITY_ALPHANUMERIC:
-                    if (mPasswordMinLetters == 0) {
-                        mPasswordMinLetters = 1;
-                    }
-                    if (mPasswordMinNumeric == 0) {
-                        mPasswordMinNumeric = 1;
-                    }
-                    break;
-                case PASSWORD_QUALITY_COMPLEX:
-                    // Reserve all the requirements.
-                    break;
-                default:
-                    mPasswordMinNumeric = 0;
-                    mPasswordMinLetters = 0;
-                    mPasswordMinUpperCase = 0;
-                    mPasswordMinLowerCase = 0;
-                    mPasswordMinSymbols = 0;
-                    mPasswordMinNonLetter = 0;
-            }
-
-            mPasswordMinLengthToFulfillAllPolicies = getMinLengthToFulfillAllPolicies();
-        }
-
-        /**
-         * Merges the dpm requirements and the min complexity requirements.
+         * Validates PIN/Password and returns the validation result and updates mValidationErrors
+         * and mPasswordReused to reflect validation results.
          *
-         * <p>Since there are more than one set of metrics to meet the min complexity requirement,
-         * and we are not hard-coding any one of them to be the requirements the user must fulfil,
-         * we are taking what the user has already entered into account when compiling the list of
-         * requirements from min complexity. Then we merge this list with the DPM requirements, and
-         * present the merged set as validation results to the user on the UI.
-         *
-         * <p>For example, suppose min complexity requires either ALPHABETIC(8+), or
-         * ALPHANUMERIC(6+). If the user has entered "a", the length requirement displayed on the UI
-         * would be 8. Then the user appends "1" to make it "a1". We now know the user is entering
-         * an alphanumeric password so we would update the min complexity required min length to 6.
-         * This might result in a little confusion for the user but the UI does not support showing
-         * multiple sets of requirements / validation results as options to users, this is the best
-         * we can do now.
-         */
-        private void mergeMinComplexityAndDpmRequirements(int userEnteredPasswordQuality) {
-            if (mRequestedMinComplexity == PASSWORD_COMPLEXITY_NONE) {
-                // dpm requirements are dominant if min complexity is none
-                return;
-            }
-
-            // reset dpm requirements
-            loadDpmPasswordRequirements();
-
-            PasswordMetrics minMetrics = PasswordMetrics.getMinimumMetrics(
-                    mRequestedMinComplexity, userEnteredPasswordQuality, mRequestedQuality,
-                    requiresNumeric(), requiresLettersOrSymbols());
-            mPasswordNumSequenceAllowed = mPasswordNumSequenceAllowed
-                    && minMetrics.quality != PASSWORD_QUALITY_NUMERIC_COMPLEX;
-            mPasswordMinLength = Math.max(mPasswordMinLength, minMetrics.length);
-            mPasswordMinLetters = Math.max(mPasswordMinLetters, minMetrics.letters);
-            mPasswordMinUpperCase = Math.max(mPasswordMinUpperCase, minMetrics.upperCase);
-            mPasswordMinLowerCase = Math.max(mPasswordMinLowerCase, minMetrics.lowerCase);
-            mPasswordMinNumeric = Math.max(mPasswordMinNumeric, minMetrics.numeric);
-            mPasswordMinSymbols = Math.max(mPasswordMinSymbols, minMetrics.symbols);
-            mPasswordMinNonLetter = Math.max(mPasswordMinNonLetter, minMetrics.nonLetter);
-
-            if (minMetrics.quality == PASSWORD_QUALITY_ALPHABETIC) {
-                if (!requiresLettersOrSymbols()) {
-                    mPasswordMinLetters = 1;
-                }
-            }
-            if (minMetrics.quality == PASSWORD_QUALITY_ALPHANUMERIC) {
-                if (!requiresLettersOrSymbols()) {
-                    mPasswordMinLetters = 1;
-                }
-                if (!requiresNumeric()) {
-                    mPasswordMinNumeric = 1;
-                }
-            }
-
-            mPasswordMinLengthToFulfillAllPolicies = getMinLengthToFulfillAllPolicies();
-        }
-
-        private boolean requiresLettersOrSymbols() {
-            // This is the condition for the password to be considered ALPHABETIC according to
-            // PasswordMetrics.computeForPassword()
-            return mPasswordMinLetters + mPasswordMinUpperCase
-                    + mPasswordMinLowerCase + mPasswordMinSymbols + mPasswordMinNonLetter > 0;
-        }
-
-        private boolean requiresNumeric() {
-            return mPasswordMinNumeric > 0;
-        }
-
-        /**
-         * Validates PIN/Password and returns the validation result.
-         *
-         * @param password the raw password the user typed in
-         * @return the validation result.
+         * @param credential credential the user typed in.
+         * @return whether password satisfies all the requirements.
          */
         @VisibleForTesting
-        int validatePassword(byte[] password) {
-            int errorCode = NO_ERROR;
-            final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password);
-            mergeMinComplexityAndDpmRequirements(metrics.quality);
-
-            if (password == null || password.length < mPasswordMinLength) {
-                if (mPasswordMinLength > mPasswordMinLengthToFulfillAllPolicies) {
-                    errorCode |= TOO_SHORT;
-                }
-            } else if (password.length > mPasswordMaxLength) {
-                errorCode |= TOO_LONG;
+        boolean validatePassword(LockscreenCredential credential) {
+            final byte[] password = credential.getCredential();
+            mValidationErrors = PasswordMetrics.validatePassword(
+                    mMinMetrics, mMinComplexity, !mIsAlphaMode, password);
+            if (mValidationErrors.isEmpty()) {
+                mPasswordReused = mLockPatternUtils.checkPasswordHistory(
+                        password, getPasswordHistoryHashFactor(), mUserId);
             } else {
-                // The length requirements are fulfilled.
-                if (!mPasswordNumSequenceAllowed
-                        && !requiresLettersOrSymbols()
-                        && metrics.numeric == password.length) {
-                    // Check for repeated characters or sequences (e.g. '1234', '0000', '2468')
-                    // if DevicePolicyManager or min password complexity requires a complex numeric
-                    // password. There can be two cases in the UI: 1. User chooses to enroll a
-                    // PIN, 2. User chooses to enroll a password but enters a numeric-only pin. We
-                    // should carry out the sequence check in both cases.
-                    //
-                    // Conditions for the !requiresLettersOrSymbols() to be necessary:
-                    // - DPM requires NUMERIC_COMPLEX
-                    // - min complexity not NONE, user picks PASSWORD type so ALPHABETIC or
-                    // ALPHANUMERIC is required
-                    // Imagine user has entered "12345678", if we don't skip the sequence check, the
-                    // validation result would show both "requires a letter" and "sequence not
-                    // allowed", while the only requirement the user needs to know is "requires a
-                    // letter" because once the user has fulfilled the alphabetic requirement, the
-                    // password would not be containing only digits so this check would not be
-                    // performed anyway.
-                    final int sequence = PasswordMetrics.maxLengthSequence(password);
-                    if (sequence > PasswordMetrics.MAX_ALLOWED_SEQUENCE) {
-                        errorCode |= CONTAIN_SEQUENTIAL_DIGITS;
-                    }
-                }
-                // Is the password recently used?
-                if (mLockPatternUtils.checkPasswordHistory(password, getPasswordHistoryHashFactor(),
-                        mUserId)) {
-                    errorCode |= RECENTLY_USED;
-                }
+                mPasswordReused = false;
             }
-
-            // Allow non-control Latin-1 characters only.
-            for (int i = 0; i < password.length; i++) {
-                char c = (char) password[i];
-                if (c < 32 || c > 127) {
-                    errorCode |= CONTAIN_INVALID_CHARACTERS;
-                    break;
-                }
-            }
-
-            // Ensure no non-digits if we are requesting numbers. This shouldn't be possible unless
-            // user finds some way to bring up soft keyboard.
-            if (mRequestedQuality == PASSWORD_QUALITY_NUMERIC
-                    || mRequestedQuality == PASSWORD_QUALITY_NUMERIC_COMPLEX) {
-                if (metrics.letters > 0 || metrics.symbols > 0) {
-                    errorCode |= CONTAIN_NON_DIGITS;
-                }
-            }
-
-            if (metrics.letters < mPasswordMinLetters) {
-                errorCode |= NOT_ENOUGH_LETTER;
-            }
-            if (metrics.upperCase < mPasswordMinUpperCase) {
-                errorCode |= NOT_ENOUGH_UPPER_CASE;
-            }
-            if (metrics.lowerCase < mPasswordMinLowerCase) {
-                errorCode |= NOT_ENOUGH_LOWER_CASE;
-            }
-            if (metrics.symbols < mPasswordMinSymbols) {
-                errorCode |= NOT_ENOUGH_SYMBOLS;
-            }
-            if (metrics.numeric < mPasswordMinNumeric) {
-                errorCode |= NOT_ENOUGH_DIGITS;
-            }
-            if (metrics.nonLetter < mPasswordMinNonLetter) {
-                errorCode |= NOT_ENOUGH_NON_LETTER;
-            }
-            return errorCode;
+            return mValidationErrors.isEmpty() && !mPasswordReused;
         }
 
+
         /**
          * Lazily compute and return the history hash factor of the current user (mUserId), used for
          * password history check.
@@ -806,7 +604,8 @@
         private byte[] getPasswordHistoryHashFactor() {
             if (mPasswordHistoryHashFactor == null) {
                 mPasswordHistoryHashFactor = mLockPatternUtils.getPasswordHistoryHashFactor(
-                        mCurrentPassword, mUserId);
+                        mCurrentCredential != null ? mCurrentCredential
+                                : LockscreenCredential.createNone(), mUserId);
             }
             return mPasswordHistoryHashFactor;
         }
@@ -814,20 +613,22 @@
         public void handleNext() {
             if (mSaveAndFinishWorker != null) return;
             // TODO(b/120484642): This is a point of entry for passwords from the UI
-            mChosenPassword = LockPatternUtils.charSequenceToByteArray(mPasswordEntry.getText());
-            if (mChosenPassword == null || mChosenPassword.length == 0) {
+            final Editable passwordText = mPasswordEntry.getText();
+            if (TextUtils.isEmpty(passwordText)) {
                 return;
             }
+            mChosenPassword = mIsAlphaMode ? LockscreenCredential.createPassword(passwordText)
+                    : LockscreenCredential.createPin(passwordText);
             if (mUiStage == Stage.Introduction) {
-                if (validatePassword(mChosenPassword) == NO_ERROR) {
-                    mFirstPin = mChosenPassword;
+                if (validatePassword(mChosenPassword)) {
+                    mFirstPassword = mChosenPassword;
                     mPasswordEntry.setText("");
                     updateStage(Stage.NeedToConfirm);
                 } else {
-                    Arrays.fill(mChosenPassword, (byte) 0);
+                    mChosenPassword.zeroize();
                 }
             } else if (mUiStage == Stage.NeedToConfirm) {
-                if (Arrays.equals(mFirstPin, mChosenPassword)) {
+                if (mChosenPassword.equals(mFirstPassword)) {
                     startSaveAndFinish();
                 } else {
                     CharSequence tmp = mPasswordEntry.getText();
@@ -835,7 +636,7 @@
                         Selection.setSelection((Spannable) tmp, 0, tmp.length());
                     }
                     updateStage(Stage.ConfirmWrong);
-                    Arrays.fill(mChosenPassword, (byte) 0);
+                    mChosenPassword.zeroize();
                 }
             }
         }
@@ -868,79 +669,79 @@
         }
 
         /**
-         * @param errorCode error code returned from {@link #validatePassword(String)}.
+         * @param errorCode error code returned from password validation.
          * @return an array of messages describing the error, important messages come first.
          */
-        String[] convertErrorCodeToMessages(int errorCode) {
+        String[] convertErrorCodeToMessages() {
             List<String> messages = new ArrayList<>();
-            if ((errorCode & CONTAIN_INVALID_CHARACTERS) > 0) {
-                messages.add(getString(R.string.lockpassword_illegal_character));
+            for (PasswordValidationError error : mValidationErrors) {
+                switch (error.errorCode) {
+                    case CONTAINS_INVALID_CHARACTERS:
+                        messages.add(getString(R.string.lockpassword_illegal_character));
+                        break;
+                    case NOT_ENOUGH_UPPER_CASE:
+                        messages.add(getResources().getQuantityString(
+                                R.plurals.lockpassword_password_requires_uppercase,
+                                error.requirement, error.requirement));
+                        break;
+                    case NOT_ENOUGH_LOWER_CASE:
+                        messages.add(getResources().getQuantityString(
+                                R.plurals.lockpassword_password_requires_lowercase,
+                                error.requirement, error.requirement));
+                        break;
+                    case NOT_ENOUGH_LETTERS:
+                        messages.add(getResources().getQuantityString(
+                                R.plurals.lockpassword_password_requires_letters,
+                                error.requirement, error.requirement));
+                        break;
+                    case NOT_ENOUGH_DIGITS:
+                        messages.add(getResources().getQuantityString(
+                                R.plurals.lockpassword_password_requires_numeric,
+                                error.requirement, error.requirement));
+                        break;
+                    case NOT_ENOUGH_SYMBOLS:
+                        messages.add(getResources().getQuantityString(
+                                R.plurals.lockpassword_password_requires_symbols,
+                                error.requirement, error.requirement));
+                        break;
+                    case NOT_ENOUGH_NON_LETTER:
+                        messages.add(getResources().getQuantityString(
+                                R.plurals.lockpassword_password_requires_nonletter,
+                                error.requirement, error.requirement));
+                        break;
+                    case NOT_ENOUGH_NON_DIGITS:
+                        messages.add(getResources().getQuantityString(
+                                R.plurals.lockpassword_password_requires_nonnumerical,
+                                error.requirement, error.requirement));
+                        break;
+                    case TOO_SHORT:
+                        messages.add(getResources().getQuantityString(
+                                mIsAlphaMode
+                                        ? R.plurals.lockpassword_password_too_short
+                                        : R.plurals.lockpassword_pin_too_short,
+                                error.requirement, error.requirement));
+                        break;
+                    case TOO_LONG:
+                        messages.add(getResources().getQuantityString(
+                                mIsAlphaMode
+                                        ? R.plurals.lockpassword_password_too_long
+                                        : R.plurals.lockpassword_pin_too_long,
+                                error.requirement + 1, error.requirement + 1));
+                        break;
+                    case CONTAINS_SEQUENCE:
+                        messages.add(getString(R.string.lockpassword_pin_no_sequential_digits));
+                        break;
+                    default:
+                        Log.wtf(TAG, "unknown error validating password: " + error);
+                }
             }
-            if ((errorCode & CONTAIN_NON_DIGITS) > 0) {
-                messages.add(getString(R.string.lockpassword_pin_contains_non_digits));
-            }
-            if ((errorCode & NOT_ENOUGH_UPPER_CASE) > 0) {
-                messages.add(getResources().getQuantityString(
-                        R.plurals.lockpassword_password_requires_uppercase, mPasswordMinUpperCase,
-                        mPasswordMinUpperCase));
-            }
-            if ((errorCode & NOT_ENOUGH_LOWER_CASE) > 0) {
-                messages.add(getResources().getQuantityString(
-                        R.plurals.lockpassword_password_requires_lowercase, mPasswordMinLowerCase,
-                        mPasswordMinLowerCase));
-            }
-            if ((errorCode & NOT_ENOUGH_LETTER) > 0) {
-                messages.add(getResources().getQuantityString(
-                        R.plurals.lockpassword_password_requires_letters, mPasswordMinLetters,
-                        mPasswordMinLetters));
-            }
-            if ((errorCode & NOT_ENOUGH_DIGITS) > 0) {
-                messages.add(getResources().getQuantityString(
-                        R.plurals.lockpassword_password_requires_numeric, mPasswordMinNumeric,
-                        mPasswordMinNumeric));
-            }
-            if ((errorCode & NOT_ENOUGH_SYMBOLS) > 0) {
-                messages.add(getResources().getQuantityString(
-                        R.plurals.lockpassword_password_requires_symbols, mPasswordMinSymbols,
-                        mPasswordMinSymbols));
-            }
-            if ((errorCode & NOT_ENOUGH_NON_LETTER) > 0) {
-                messages.add(getResources().getQuantityString(
-                        R.plurals.lockpassword_password_requires_nonletter, mPasswordMinNonLetter,
-                        mPasswordMinNonLetter));
-            }
-            if ((errorCode & TOO_SHORT) > 0) {
-                messages.add(getResources().getQuantityString(
-                        mIsAlphaMode
-                                ? R.plurals.lockpassword_password_too_short
-                                : R.plurals.lockpassword_pin_too_short,
-                        mPasswordMinLength,
-                        mPasswordMinLength));
-            }
-            if ((errorCode & TOO_LONG) > 0) {
-                messages.add(getResources().getQuantityString(
-                        mIsAlphaMode
-                                ? R.plurals.lockpassword_password_too_long
-                                : R.plurals.lockpassword_pin_too_long,
-                        mPasswordMaxLength + 1,
-                        mPasswordMaxLength + 1));
-            }
-            if ((errorCode & CONTAIN_SEQUENTIAL_DIGITS) > 0) {
-                messages.add(getString(R.string.lockpassword_pin_no_sequential_digits));
-            }
-            if ((errorCode & RECENTLY_USED) > 0) {
+
+            if (mPasswordReused) {
                 messages.add(getString((mIsAlphaMode) ? R.string.lockpassword_password_recently_used
                         : R.string.lockpassword_pin_recently_used));
             }
-            return messages.toArray(new String[0]);
-        }
 
-        private int getMinLengthToFulfillAllPolicies() {
-            final int minLengthForLetters = Math.max(mPasswordMinLetters,
-                    mPasswordMinUpperCase + mPasswordMinLowerCase);
-            final int minLengthForNonLetters = Math.max(mPasswordMinNonLetter,
-                    mPasswordMinSymbols + mPasswordMinNumeric);
-            return minLengthForLetters + minLengthForNonLetters;
+            return messages.toArray(new String[0]);
         }
 
         /**
@@ -948,21 +749,24 @@
          */
         protected void updateUi() {
             final boolean canInput = mSaveAndFinishWorker == null;
-            byte[] password = LockPatternUtils.charSequenceToByteArray(mPasswordEntry.getText());
-            final int length = password.length;
+
+            LockscreenCredential password = mIsAlphaMode
+                    ? LockscreenCredential.createPasswordOrNone(mPasswordEntry.getText())
+                    : LockscreenCredential.createPinOrNone(mPasswordEntry.getText());
+            final int length = password.size();
             if (mUiStage == Stage.Introduction) {
                 mPasswordRestrictionView.setVisibility(View.VISIBLE);
-                final int errorCode = validatePassword(password);
-                String[] messages = convertErrorCodeToMessages(errorCode);
+                final boolean passwordCompliant = validatePassword(password);
+                String[] messages = convertErrorCodeToMessages();
                 // Update the fulfillment of requirements.
                 mPasswordRequirementAdapter.setRequirements(messages);
                 // Enable/Disable the next button accordingly.
-                setNextEnabled(errorCode == NO_ERROR);
+                setNextEnabled(passwordCompliant);
             } else {
                 // Hide password requirement view when we are just asking user to confirm the pw.
                 mPasswordRestrictionView.setVisibility(View.GONE);
                 setHeaderText(getString(mUiStage.getHint(mIsAlphaMode, getStageType())));
-                setNextEnabled(canInput && length >= mPasswordMinLength);
+                setNextEnabled(canInput && length >= LockPatternUtils.MIN_LOCK_PASSWORD_SIZE);
                 mSkipOrClearButton.setVisibility(toVisibility(canInput && length > 0));
             }
             int message = mUiStage.getMessage(mIsAlphaMode, getStageType());
@@ -975,7 +779,7 @@
 
             setNextText(mUiStage.buttonText);
             mPasswordEntryInputDisabler.setInputEnabled(canInput);
-            Arrays.fill(password, (byte) 0);
+            password.zeroize();
         }
 
         protected int toVisibility(boolean visibleOrGone) {
@@ -1027,7 +831,7 @@
             final boolean required = getActivity().getIntent().getBooleanExtra(
                     EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
             mSaveAndFinishWorker.start(mLockPatternUtils, required, mHasChallenge, mChallenge,
-                    mChosenPassword, mCurrentPassword, mRequestedQuality, mUserId);
+                    mChosenPassword, mCurrentCredential, mUserId);
         }
 
         @Override
@@ -1035,13 +839,13 @@
             getActivity().setResult(RESULT_FINISHED, resultData);
 
             if (mChosenPassword != null) {
-                Arrays.fill(mChosenPassword, (byte) 0);
+                mChosenPassword.zeroize();
             }
-            if (mCurrentPassword != null) {
-                Arrays.fill(mCurrentPassword, (byte) 0);
+            if (mCurrentCredential != null) {
+                mCurrentCredential.zeroize();
             }
-            if (mFirstPin != null) {
-                Arrays.fill(mFirstPin, (byte) 0);
+            if (mFirstPassword != null) {
+                mFirstPassword.zeroize();
             }
 
             mPasswordEntry.setText("");
@@ -1082,18 +886,18 @@
 
     public static class SaveAndFinishWorker extends SaveChosenLockWorkerBase {
 
-        private byte[] mChosenPassword;
-        private byte[] mCurrentPassword;
-        private int mRequestedQuality;
+        private LockscreenCredential mChosenPassword;
+        private LockscreenCredential mCurrentCredential;
 
         public void start(LockPatternUtils utils, boolean required,
                 boolean hasChallenge, long challenge,
-                byte[] chosenPassword, byte[] currentPassword, int requestedQuality, int userId) {
+                LockscreenCredential chosenPassword, LockscreenCredential currentCredential,
+                int userId) {
             prepare(utils, required, hasChallenge, challenge, userId);
 
             mChosenPassword = chosenPassword;
-            mCurrentPassword = currentPassword;
-            mRequestedQuality = requestedQuality;
+            mCurrentCredential = currentCredential != null ? currentCredential
+                    : LockscreenCredential.createNone();
             mUserId = userId;
 
             start();
@@ -1101,13 +905,13 @@
 
         @Override
         protected Pair<Boolean, Intent> saveAndVerifyInBackground() {
-            final boolean success = mUtils.saveLockPassword(
-                    mChosenPassword, mCurrentPassword, mRequestedQuality, mUserId);
+            final boolean success = mUtils.setLockCredential(
+                    mChosenPassword, mCurrentCredential, mUserId);
             Intent result = null;
             if (success && mHasChallenge) {
                 byte[] token;
                 try {
-                    token = mUtils.verifyPassword(mChosenPassword, mChallenge, mUserId);
+                    token = mUtils.verifyCredential(mChosenPassword, mChallenge, mUserId);
                 } catch (RequestThrottledException e) {
                     token = null;
                 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ChooseLockPattern.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ChooseLockPattern.java
index 66a4803..7bc4bcc 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ChooseLockPattern.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ChooseLockPattern.java
@@ -36,12 +36,6 @@
 
 import androidx.fragment.app.Fragment;
 
-import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
-import com.android.internal.widget.LockPatternView;
-import com.android.internal.widget.LockPatternView.Cell;
-import com.android.internal.widget.LockPatternView.DisplayMode;
 import com.android.car.developeroptions.EncryptionInterstitial;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.SettingsActivity;
@@ -49,14 +43,20 @@
 import com.android.car.developeroptions.Utils;
 import com.android.car.developeroptions.core.InstrumentedFragment;
 import com.android.car.developeroptions.notification.RedactionInterstitial;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
+import com.android.internal.widget.LockPatternView;
+import com.android.internal.widget.LockPatternView.Cell;
+import com.android.internal.widget.LockPatternView.DisplayMode;
+import com.android.internal.widget.LockscreenCredential;
 
 import com.google.android.collect.Lists;
 import com.google.android.setupcompat.template.FooterBarMixin;
 import com.google.android.setupcompat.template.FooterButton;
 import com.google.android.setupdesign.GlifLayout;
 
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
@@ -116,7 +116,7 @@
             return this;
         }
 
-        public IntentBuilder setPattern(byte[] pattern) {
+        public IntentBuilder setPattern(LockscreenCredential pattern) {
             mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, pattern);
             return this;
         }
@@ -189,7 +189,7 @@
 
         private static final String FRAGMENT_TAG_SAVE_AND_FINISH = "save_and_finish_worker";
 
-        private byte[] mCurrentPattern;
+        private LockscreenCredential mCurrentCredential;
         private boolean mHasChallenge;
         private long mChallenge;
         protected TextView mTitleText;
@@ -199,7 +199,7 @@
         protected TextView mFooterText;
         protected FooterButton mSkipOrClearButton;
         private FooterButton mNextButton;
-        protected List<LockPatternView.Cell> mChosenPattern = null;
+        @VisibleForTesting protected LockscreenCredential mChosenPattern;
         private ColorStateList mDefaultHeaderColorList;
 
         // ScrollView that contains title and header, only exist in land mode
@@ -226,7 +226,7 @@
                         getActivity().setResult(RESULT_FINISHED);
                         getActivity().finish();
                     } else {
-                        mCurrentPattern = data.getByteArrayExtra(
+                        mCurrentCredential = data.getParcelableExtra(
                                 ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
                     }
 
@@ -263,16 +263,19 @@
                     if (mUiStage == Stage.NeedToConfirm || mUiStage == Stage.ConfirmWrong) {
                         if (mChosenPattern == null) throw new IllegalStateException(
                                 "null chosen pattern in stage 'need to confirm");
-                        if (mChosenPattern.equals(pattern)) {
-                            updateStage(Stage.ChoiceConfirmed);
-                        } else {
-                            updateStage(Stage.ConfirmWrong);
+                        try (LockscreenCredential confirmPattern =
+                                LockscreenCredential.createPattern(pattern)) {
+                            if (mChosenPattern.equals(confirmPattern)) {
+                                updateStage(Stage.ChoiceConfirmed);
+                            } else {
+                                updateStage(Stage.ConfirmWrong);
+                            }
                         }
                     } else if (mUiStage == Stage.Introduction || mUiStage == Stage.ChoiceTooShort){
                         if (pattern.size() < LockPatternUtils.MIN_LOCK_PATTERN_SIZE) {
                             updateStage(Stage.ChoiceTooShort);
                         } else {
-                            mChosenPattern = new ArrayList<LockPatternView.Cell>(pattern);
+                            mChosenPattern = LockscreenCredential.createPattern(pattern);
                             updateStage(Stage.FirstChoiceValid);
                         }
                     } else {
@@ -459,12 +462,12 @@
                 SaveAndFinishWorker w = new SaveAndFinishWorker();
                 final boolean required = getActivity().getIntent().getBooleanExtra(
                         EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
-                byte[] current = intent.getByteArrayExtra(
+                LockscreenCredential current = intent.getParcelableExtra(
                         ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
                 w.setBlocking(true);
                 w.setListener(this);
                 w.start(mChooseLockSettingsHelper.utils(), required,
-                        false, 0, LockPatternUtils.byteArrayToPattern(current), current, mUserId);
+                        false, 0, current, current, mUserId);
             }
             mForFingerprint = intent.getBooleanExtra(
                     ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
@@ -542,8 +545,8 @@
             final boolean confirmCredentials = getActivity().getIntent()
                     .getBooleanExtra(ChooseLockGeneric.CONFIRM_CREDENTIALS, true);
             Intent intent = getActivity().getIntent();
-            mCurrentPattern =
-                    intent.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
+            mCurrentCredential =
+                    intent.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
             mHasChallenge = intent.getBooleanExtra(
                     ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
             mChallenge = intent.getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
@@ -566,13 +569,10 @@
                 }
             } else {
                 // restore from previous state
-                final byte[] pattern = savedInstanceState.getByteArray(KEY_PATTERN_CHOICE);
-                if (pattern != null) {
-                    mChosenPattern = LockPatternUtils.byteArrayToPattern(pattern);
-                }
+                mChosenPattern = savedInstanceState.getParcelable(KEY_PATTERN_CHOICE);
 
-                if (mCurrentPattern == null) {
-                    mCurrentPattern = savedInstanceState.getByteArray(KEY_CURRENT_PATTERN);
+                if (mCurrentCredential == null) {
+                    mCurrentCredential = savedInstanceState.getParcelable(KEY_CURRENT_PATTERN);
                 }
                 updateStage(Stage.values()[savedInstanceState.getInt(KEY_UI_STAGE)]);
 
@@ -607,6 +607,7 @@
 
         public void handleLeftButton() {
             if (mUiStage.leftMode == LeftButtonMode.Retry) {
+                mChosenPattern.zeroize();
                 mChosenPattern = null;
                 mLockPatternView.clearPattern();
                 updateStage(Stage.Introduction);
@@ -668,12 +669,11 @@
 
             outState.putInt(KEY_UI_STAGE, mUiStage.ordinal());
             if (mChosenPattern != null) {
-                outState.putByteArray(KEY_PATTERN_CHOICE,
-                        LockPatternUtils.patternToByteArray(mChosenPattern));
+                outState.putParcelable(KEY_PATTERN_CHOICE, mChosenPattern);
             }
 
-            if (mCurrentPattern != null) {
-                outState.putByteArray(KEY_CURRENT_PATTERN, mCurrentPattern);
+            if (mCurrentCredential != null) {
+                outState.putParcelable(KEY_CURRENT_PATTERN, mCurrentCredential);
             }
         }
 
@@ -813,15 +813,15 @@
             final boolean required = getActivity().getIntent().getBooleanExtra(
                     EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
             mSaveAndFinishWorker.start(mChooseLockSettingsHelper.utils(), required,
-                    mHasChallenge, mChallenge, mChosenPattern, mCurrentPattern, mUserId);
+                    mHasChallenge, mChallenge, mChosenPattern, mCurrentCredential, mUserId);
         }
 
         @Override
         public void onChosenLockSaveFinished(boolean wasSecureBefore, Intent resultData) {
             getActivity().setResult(RESULT_FINISHED, resultData);
 
-            if (mCurrentPattern != null) {
-                Arrays.fill(mCurrentPattern, (byte) 0);
+            if (mCurrentCredential != null) {
+                mCurrentCredential.zeroize();
             }
 
             if (!wasSecureBefore) {
@@ -836,16 +836,17 @@
 
     public static class SaveAndFinishWorker extends SaveChosenLockWorkerBase {
 
-        private List<LockPatternView.Cell> mChosenPattern;
-        private byte[] mCurrentPattern;
+        private LockscreenCredential mChosenPattern;
+        private LockscreenCredential mCurrentCredential;
         private boolean mLockVirgin;
 
         public void start(LockPatternUtils utils, boolean credentialRequired,
-                boolean hasChallenge, long challenge,
-                List<LockPatternView.Cell> chosenPattern, byte[] currentPattern, int userId) {
+                boolean hasChallenge, long challenge, LockscreenCredential chosenPattern,
+                LockscreenCredential currentCredential, int userId) {
             prepare(utils, credentialRequired, hasChallenge, challenge, userId);
 
-            mCurrentPattern = currentPattern;
+            mCurrentCredential = currentCredential != null ? currentCredential
+                    : LockscreenCredential.createNone();
             mChosenPattern = chosenPattern;
             mUserId = userId;
 
@@ -857,12 +858,13 @@
         @Override
         protected Pair<Boolean, Intent> saveAndVerifyInBackground() {
             final int userId = mUserId;
-            final boolean success = mUtils.saveLockPattern(mChosenPattern, mCurrentPattern, userId);
+            final boolean success = mUtils.setLockCredential(mChosenPattern, mCurrentCredential,
+                    userId);
             Intent result = null;
             if (success && mHasChallenge) {
                 byte[] token;
                 try {
-                    token = mUtils.verifyPattern(mChosenPattern, mChallenge, userId);
+                    token = mUtils.verifyCredential(mChosenPattern, mChallenge, userId);
                 } catch (RequestThrottledException e) {
                     token = null;
                 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ConfirmDeviceCredentialActivity.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ConfirmDeviceCredentialActivity.java
index 12afab1..6eef486 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ConfirmDeviceCredentialActivity.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ConfirmDeviceCredentialActivity.java
@@ -39,9 +39,9 @@
 import androidx.annotation.NonNull;
 import androidx.fragment.app.FragmentActivity;
 
-import com.android.internal.widget.LockPatternUtils;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.Utils;
+import com.android.internal.widget.LockPatternUtils;
 
 import java.util.concurrent.Executor;
 
@@ -108,10 +108,6 @@
             if (!mGoingToBackground) {
                 if (errorCode == BiometricPrompt.BIOMETRIC_ERROR_USER_CANCELED
                         || errorCode == BiometricPrompt.BIOMETRIC_ERROR_CANCELED) {
-                    if (mIsFallback) {
-                        mBiometricManager.onConfirmDeviceCredentialError(
-                                errorCode, getStringForError(errorCode));
-                    }
                     finish();
                 } else {
                     // All other errors go to some version of CC
@@ -128,10 +124,6 @@
             ConfirmDeviceCredentialUtils.checkForPendingIntent(
                     ConfirmDeviceCredentialActivity.this);
 
-            if (mIsFallback) {
-                mBiometricManager.onConfirmDeviceCredentialSuccess();
-            }
-
             setResult(Activity.RESULT_OK);
             finish();
         }
@@ -183,17 +175,11 @@
         mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this);
         final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
 
-        Bundle bpBundle =
-                intent.getBundleExtra(KeyguardManager.EXTRA_BIOMETRIC_PROMPT_BUNDLE);
-        if (bpBundle != null) {
-            mIsFallback = true;
-            mTitle = bpBundle.getString(BiometricPrompt.KEY_TITLE);
-            mDetails = bpBundle.getString(BiometricPrompt.KEY_SUBTITLE);
-        } else {
-            bpBundle = new Bundle();
-            bpBundle.putString(BiometricPrompt.KEY_TITLE, mTitle);
-            bpBundle.putString(BiometricPrompt.KEY_DESCRIPTION, mDetails);
-        }
+        final Bundle bpBundle = new Bundle();
+        mTitle = bpBundle.getString(BiometricPrompt.KEY_TITLE);
+        mDetails = bpBundle.getString(BiometricPrompt.KEY_SUBTITLE);
+        bpBundle.putString(BiometricPrompt.KEY_TITLE, mTitle);
+        bpBundle.putString(BiometricPrompt.KEY_DESCRIPTION, mDetails);
 
         boolean launchedBiometric = false;
         boolean launchedCDC = false;
@@ -254,12 +240,6 @@
                 mBiometricFragment.cancel();
             }
 
-            if (mIsFallback && !mCCLaunched) {
-                mBiometricManager.onConfirmDeviceCredentialError(
-                        BiometricConstants.BIOMETRIC_ERROR_CANCELED,
-                        getString(com.android.internal.R.string.biometric_error_user_canceled));
-            }
-
             finish();
         } else {
             mGoingToBackground = false;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ConfirmDeviceCredentialBaseActivity.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ConfirmDeviceCredentialBaseActivity.java
index 29fefa8..e5faa5f 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ConfirmDeviceCredentialBaseActivity.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ConfirmDeviceCredentialBaseActivity.java
@@ -17,9 +17,6 @@
 package com.android.car.developeroptions.password;
 
 import android.app.KeyguardManager;
-import android.hardware.biometrics.BiometricConstants;
-import android.hardware.biometrics.BiometricManager;
-import android.hardware.biometrics.IBiometricConfirmDeviceCredentialCallback;
 import android.os.Bundle;
 import android.os.UserManager;
 import android.util.Log;
@@ -50,16 +47,6 @@
     private boolean mFirstTimeVisible = true;
     private boolean mIsKeyguardLocked = false;
     private ConfirmCredentialTheme mConfirmCredentialTheme;
-    private BiometricManager mBiometricManager;
-
-    // TODO(b/123378871): Remove when moved.
-    private final IBiometricConfirmDeviceCredentialCallback mCancelCallback
-            = new IBiometricConfirmDeviceCredentialCallback.Stub() {
-        @Override
-        public void cancel() {
-            finish();
-        }
-    };
 
     private boolean isInternalActivity() {
         return (this instanceof ConfirmLockPassword.InternalActivity)
@@ -90,9 +77,6 @@
         }
         super.onCreate(savedState);
 
-        mBiometricManager = getSystemService(BiometricManager.class);
-        mBiometricManager.registerCancellationCallback(mCancelCallback);
-
         if (mConfirmCredentialTheme == ConfirmCredentialTheme.NORMAL) {
             // Prevent the content parent from consuming the window insets because GlifLayout uses
             // it to show the status bar background.
@@ -168,12 +152,6 @@
     @Override
     public void onStop() {
         super.onStop();
-        // TODO(b/123378871): Remove when moved.
-        if (!isChangingConfigurations()) {
-            mBiometricManager.onConfirmDeviceCredentialError(
-                    BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED,
-                    getString(com.android.internal.R.string.biometric_error_user_canceled));
-        }
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ConfirmLockPassword.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ConfirmLockPassword.java
index f5e3dce..068094b 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ConfirmLockPassword.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ConfirmLockPassword.java
@@ -27,6 +27,7 @@
 import android.os.SystemClock;
 import android.os.UserManager;
 import android.os.storage.StorageManager;
+import android.text.Editable;
 import android.text.InputType;
 import android.text.TextUtils;
 import android.view.KeyEvent;
@@ -42,11 +43,12 @@
 
 import androidx.fragment.app.Fragment;
 
-import com.android.internal.widget.LockPatternChecker;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.TextViewInputDisabler;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.widget.ImeAwareEditText;
+import com.android.internal.widget.LockPatternChecker;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockscreenCredential;
+import com.android.internal.widget.TextViewInputDisabler;
 import com.android.settingslib.animation.AppearAnimationUtils;
 import com.android.settingslib.animation.DisappearAnimationUtils;
 
@@ -324,10 +326,13 @@
             }
 
             // TODO(b/120484642): This is a point of entry for passwords from the UI
-            final byte[] pin = LockPatternUtils.charSequenceToByteArray(mPasswordEntry.getText());
-            if (pin == null || pin.length == 0) {
+            final Editable passwordText = mPasswordEntry.getText();
+            if (TextUtils.isEmpty(passwordText)) {
                 return;
             }
+            final LockscreenCredential credential = mIsAlpha
+                    ? LockscreenCredential.createPassword(passwordText)
+                    : LockscreenCredential.createPin(passwordText);
 
             mPasswordEntryInputDisabler.setInputEnabled(false);
             final boolean verifyChallenge = getActivity().getIntent().getBooleanExtra(
@@ -336,11 +341,11 @@
             Intent intent = new Intent();
             if (verifyChallenge)  {
                 if (isInternalActivity()) {
-                    startVerifyPassword(pin, intent);
+                    startVerifyPassword(credential, intent);
                     return;
                 }
             } else {
-                startCheckPassword(pin, intent);
+                startCheckPassword(credential, intent);
                 return;
             }
 
@@ -351,7 +356,7 @@
             return getActivity() instanceof ConfirmLockPassword.InternalActivity;
         }
 
-        private void startVerifyPassword(final byte[] pin, final Intent intent) {
+        private void startVerifyPassword(LockscreenCredential credential, final Intent intent) {
             long challenge = getActivity().getIntent().getLongExtra(
                     ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
             final int localEffectiveUserId = mEffectiveUserId;
@@ -375,18 +380,19 @@
                         }
             };
             mPendingLockCheck = (localEffectiveUserId == localUserId)
-                    ? LockPatternChecker.verifyPassword(
-                            mLockPatternUtils, pin, challenge, localUserId, onVerifyCallback)
+                    ? LockPatternChecker.verifyCredential(
+                            mLockPatternUtils, credential, challenge, localUserId, onVerifyCallback)
                     : LockPatternChecker.verifyTiedProfileChallenge(
-                            mLockPatternUtils, pin, false, challenge, localUserId,
+                            mLockPatternUtils, credential, challenge, localUserId,
                             onVerifyCallback);
         }
 
-        private void startCheckPassword(final byte[] pin, final Intent intent) {
+        private void startCheckPassword(final LockscreenCredential credential,
+                final Intent intent) {
             final int localEffectiveUserId = mEffectiveUserId;
-            mPendingLockCheck = LockPatternChecker.checkPassword(
+            mPendingLockCheck = LockPatternChecker.checkCredential(
                     mLockPatternUtils,
-                    pin,
+                    credential,
                     localEffectiveUserId,
                     new LockPatternChecker.OnCheckCallback() {
                         @Override
@@ -397,7 +403,7 @@
                                                 mIsAlpha ? StorageManager.CRYPT_TYPE_PASSWORD
                                                          : StorageManager.CRYPT_TYPE_PIN);
                                 intent.putExtra(
-                                        ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, pin);
+                                        ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, credential);
                             }
                             mCredentialCheckResultTracker.setResult(matched, intent, timeoutMs,
                                     localEffectiveUserId);
@@ -438,7 +444,6 @@
                     ConfirmDeviceCredentialUtils.reportSuccessfulAttempt(mLockPatternUtils,
                             mUserManager, mEffectiveUserId);
                 }
-                mBiometricManager.onConfirmDeviceCredentialSuccess();
                 startDisappearAnimation(intent);
                 ConfirmDeviceCredentialUtils.checkForPendingIntent(getActivity());
             } else {
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ConfirmLockPattern.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ConfirmLockPattern.java
index fedd126..96458eb 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ConfirmLockPattern.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ConfirmLockPattern.java
@@ -32,12 +32,13 @@
 import android.view.animation.Interpolator;
 import android.widget.TextView;
 
+import com.android.car.developeroptions.R;
 import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient;
 import com.android.internal.widget.LockPatternChecker;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockPatternView;
 import com.android.internal.widget.LockPatternView.Cell;
-import com.android.car.developeroptions.R;
+import com.android.internal.widget.LockscreenCredential;
 import com.android.settingslib.animation.AppearAnimationCreator;
 import com.android.settingslib.animation.AppearAnimationUtils;
 import com.android.settingslib.animation.DisappearAnimationUtils;
@@ -401,14 +402,15 @@
 
                 final boolean verifyChallenge = getActivity().getIntent().getBooleanExtra(
                         ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
+                final LockscreenCredential credential = LockscreenCredential.createPattern(pattern);
                 Intent intent = new Intent();
                 if (verifyChallenge) {
                     if (isInternalActivity()) {
-                        startVerifyPattern(pattern, intent);
+                        startVerifyPattern(credential, intent);
                         return;
                     }
                 } else {
-                    startCheckPattern(pattern, intent);
+                    startCheckPattern(credential, intent);
                     return;
                 }
 
@@ -419,7 +421,7 @@
                 return getActivity() instanceof ConfirmLockPattern.InternalActivity;
             }
 
-            private void startVerifyPattern(final List<LockPatternView.Cell> pattern,
+            private void startVerifyPattern(final LockscreenCredential pattern,
                     final Intent intent) {
                 final int localEffectiveUserId = mEffectiveUserId;
                 final int localUserId = mUserId;
@@ -444,15 +446,15 @@
                         }
                     };
                 mPendingLockCheck = (localEffectiveUserId == localUserId)
-                        ? LockPatternChecker.verifyPattern(
+                        ? LockPatternChecker.verifyCredential(
                                 mLockPatternUtils, pattern, challenge, localUserId,
                                 onVerifyCallback)
                         : LockPatternChecker.verifyTiedProfileChallenge(
-                                mLockPatternUtils, LockPatternUtils.patternToByteArray(pattern),
-                                true, challenge, localUserId, onVerifyCallback);
+                                mLockPatternUtils, pattern,
+                                challenge, localUserId, onVerifyCallback);
             }
 
-            private void startCheckPattern(final List<LockPatternView.Cell> pattern,
+            private void startCheckPattern(final LockscreenCredential pattern,
                     final Intent intent) {
                 if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
                     // Pattern size is less than the minimum, do not count it as an fail attempt.
@@ -461,7 +463,7 @@
                 }
 
                 final int localEffectiveUserId = mEffectiveUserId;
-                mPendingLockCheck = LockPatternChecker.checkPattern(
+                mPendingLockCheck = LockPatternChecker.checkCredential(
                         mLockPatternUtils,
                         pattern,
                         localEffectiveUserId,
@@ -473,7 +475,7 @@
                                     intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_TYPE,
                                                     StorageManager.CRYPT_TYPE_PATTERN);
                                     intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD,
-                                                    LockPatternUtils.patternToByteArray(pattern));
+                                                    pattern);
                                 }
                                 mCredentialCheckResultTracker.setResult(matched, intent, timeoutMs,
                                         localEffectiveUserId);
@@ -490,7 +492,6 @@
                     ConfirmDeviceCredentialUtils.reportSuccessfulAttempt(mLockPatternUtils,
                             mUserManager, mEffectiveUserId);
                 }
-                mBiometricManager.onConfirmDeviceCredentialSuccess();
                 startDisappearAnimation(intent);
                 ConfirmDeviceCredentialUtils.checkForPendingIntent(getActivity());
             } else {
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ManagedLockPasswordProvider.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ManagedLockPasswordProvider.java
index 5b01e65..334c055 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ManagedLockPasswordProvider.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/ManagedLockPasswordProvider.java
@@ -19,6 +19,8 @@
 import android.content.Context;
 import android.content.Intent;
 
+import com.android.internal.widget.LockscreenCredential;
+
 /**
  * Helper for handling managed passwords in security settings UI.
  * It provides resources that should be shown in settings UI when lock password quality is set to
@@ -59,7 +61,7 @@
      * @param password Current lock password.
      * @return Intent that should update lock password to a managed password.
      */
-    Intent createIntent(boolean requirePasswordToDecrypt, byte[] password) {
+    Intent createIntent(boolean requirePasswordToDecrypt, LockscreenCredential password) {
         return null;
     }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/SetNewPasswordController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/SetNewPasswordController.java
index 7689334..b213152 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/SetNewPasswordController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/password/SetNewPasswordController.java
@@ -21,8 +21,6 @@
 import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.admin.DevicePolicyManager;
@@ -40,6 +38,8 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.car.developeroptions.Utils;
 
+import java.util.Objects;
+
 /**
  * Business logic for {@link SetNewPasswordActivity}.
  *
@@ -99,11 +99,11 @@
             DevicePolicyManager devicePolicyManager,
             Ui ui) {
         mTargetUserId = targetUserId;
-        mPackageManager = checkNotNull(packageManager);
+        mPackageManager = Objects.requireNonNull(packageManager);
         mFingerprintManager = fingerprintManager;
         mFaceManager = faceManager;
-        mDevicePolicyManager = checkNotNull(devicePolicyManager);
-        mUi = checkNotNull(ui);
+        mDevicePolicyManager = Objects.requireNonNull(devicePolicyManager);
+        mUi = Objects.requireNonNull(ui);
     }
 
     /**
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/print/PrintSettingsFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/print/PrintSettingsFragment.java
index e73798c..83b7a63 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/print/PrintSettingsFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/print/PrintSettingsFragment.java
@@ -54,7 +54,7 @@
 
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 import com.android.settingslib.widget.apppreference.AppPreference;
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/print/SettingsPrintServicesLoader.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/print/SettingsPrintServicesLoader.java
index bf383b5..91ae5da 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/print/SettingsPrintServicesLoader.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/print/SettingsPrintServicesLoader.java
@@ -24,9 +24,8 @@
 
 import androidx.loader.content.Loader;
 
-import com.android.internal.util.Preconditions;
-
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Loader for the list of print services. Can be parametrized to select a subset.
@@ -37,7 +36,7 @@
 
     public SettingsPrintServicesLoader(@NonNull PrintManager printManager, @NonNull Context context,
             int selectionFlags) {
-        super(Preconditions.checkNotNull(context));
+        super(Objects.requireNonNull(context));
 
         mLoader = new PrintServicesLoader(printManager, context, selectionFlags) {
             @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/search/BaseSearchIndexProvider.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/search/BaseSearchIndexProvider.java
index 606d551..d6b060e 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/search/BaseSearchIndexProvider.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/search/BaseSearchIndexProvider.java
@@ -36,6 +36,8 @@
 import com.android.car.developeroptions.core.PreferenceControllerMixin;
 import com.android.car.developeroptions.core.PreferenceXmlParserUtils;
 import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.search.Indexable;
+import com.android.settingslib.search.SearchIndexableRaw;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -64,6 +66,11 @@
     }
 
     @Override
+    public List<SearchIndexableRaw> getDynamicRawDataToIndex(Context context, boolean enabled) {
+        return null;
+    }
+
+    @Override
     @CallSuper
     public List<String> getNonIndexableKeys(Context context) {
         if (!isPageSearchEnabled(context)) {
@@ -92,7 +99,6 @@
         return nonIndexableKeys;
     }
 
-    @Override
     public List<AbstractPreferenceController> getPreferenceControllers(Context context) {
         final List<AbstractPreferenceController> controllersFromCode =
                 createPreferenceControllers(context);
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/search/DatabaseIndexingUtils.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/search/DatabaseIndexingUtils.java
deleted file mode 100644
index 8477fc7..0000000
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/search/DatabaseIndexingUtils.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.car.developeroptions.search;
-
-import android.util.Log;
-
-import java.lang.reflect.Field;
-
-/**
- * Utility class for {@like DatabaseIndexingManager} to handle the mapping between Payloads
- * and Preference controllers, and managing indexable classes.
- */
-public class DatabaseIndexingUtils {
-
-    private static final String TAG = "IndexingUtil";
-
-    public static final String FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER =
-            "SEARCH_INDEX_DATA_PROVIDER";
-
-    public static Indexable.SearchIndexProvider getSearchIndexProvider(final Class<?> clazz) {
-        try {
-            final Field f = clazz.getField(FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER);
-            return (Indexable.SearchIndexProvider) f.get(null);
-        } catch (NoSuchFieldException e) {
-            Log.d(TAG, "Cannot find field '" + FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER + "'");
-        } catch (SecurityException se) {
-            Log.d(TAG, "Security exception for field '" +
-                    FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER + "'");
-        } catch (IllegalAccessException e) {
-            Log.d(TAG, "Illegal access to field '" + FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER + "'");
-        } catch (IllegalArgumentException e) {
-            Log.d(TAG, "Illegal argument when accessing field '" +
-                    FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER + "'");
-        }
-        return null;
-    }
-}
\ No newline at end of file
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/search/Indexable.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/search/Indexable.java
deleted file mode 100644
index fc191ff..0000000
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/search/Indexable.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.developeroptions.search;
-
-import android.content.Context;
-import android.provider.SearchIndexableResource;
-
-import androidx.annotation.Keep;
-
-import com.android.settingslib.core.AbstractPreferenceController;
-
-import java.util.List;
-
-/**
- * Interface for classes whose instances can provide data for indexing.
- *
- * Classes implementing the Indexable interface must have a static field called
- * <code>SEARCH_INDEX_DATA_PROVIDER</code>, which is an object implementing the
- * {@link Indexable.SearchIndexProvider} interface.
- *
- * See {@link android.provider.SearchIndexableResource} and {@link SearchIndexableRaw}.
- */
-public interface Indexable {
-
-    interface SearchIndexProvider {
-        /**
-         * Return a list of references for indexing.
-         *
-         * See {@link android.provider.SearchIndexableResource}
-         *
-         * @param context the context.
-         * @param enabled hint telling if the data needs to be considered into the search results
-         *                or not.
-         * @return a list of {@link android.provider.SearchIndexableResource} references.
-         * Can be null.
-         */
-        @Keep
-        List<SearchIndexableResource> getXmlResourcesToIndex(Context context, boolean enabled);
-
-        /**
-         * Return a list of raw data for indexing. See {@link SearchIndexableRaw}
-         *
-         * @param context the context.
-         * @param enabled hint telling if the data needs to be considered into the search results
-         *                or not.
-         * @return a list of {@link SearchIndexableRaw} references. Can be null.
-         */
-        @Keep
-        List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled);
-
-        /**
-         * Return a list of data keys that cannot be indexed. See {@link SearchIndexableRaw}
-         *
-         * @param context the context.
-         * @return a list of {@link SearchIndexableRaw} references. Can be null.
-         */
-        @Keep
-        List<String> getNonIndexableKeys(Context context);
-
-        /**
-         * @return a list of {@link AbstractPreferenceController} for ResultPayload data during
-         * Indexing.
-         */
-        @Keep
-        List<AbstractPreferenceController> getPreferenceControllers(Context context);
-    }
-}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/search/SearchIndexableRaw.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/search/SearchIndexableRaw.java
deleted file mode 100644
index a91a920..0000000
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/search/SearchIndexableRaw.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.developeroptions.search;
-
-import android.content.Context;
-import android.provider.SearchIndexableData;
-
-/**
- * Indexable raw data for Search.
- *
- * This is the raw data used by the Indexer and should match its data model.
- *
- * See {@link Indexable} and {@link android.provider.SearchIndexableResource}.
- */
-public class SearchIndexableRaw extends SearchIndexableData {
-
-    /**
-     * Title's raw data.
-     */
-    public String title;
-
-    /**
-     * Summary's raw data when the data is "ON".
-     */
-    public String summaryOn;
-
-    /**
-     * Summary's raw data when the data is "OFF".
-     */
-    public String summaryOff;
-
-    /**
-     * Entries associated with the raw data (when the data can have several values).
-     */
-    public String entries;
-
-    /**
-     * Keywords' raw data.
-     */
-    public String keywords;
-
-    /**
-     * Fragment's or Activity's title associated with the raw data.
-     */
-    public String screenTitle;
-
-    public SearchIndexableRaw(Context context) {
-        super(context);
-    }
-}
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/search/SettingsSearchIndexablesProvider.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/search/SettingsSearchIndexablesProvider.java
index c29cb54..78dce4a 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/search/SettingsSearchIndexablesProvider.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/search/SettingsSearchIndexablesProvider.java
@@ -65,6 +65,9 @@
 import com.android.car.developeroptions.slices.SettingsSliceProvider;
 import com.android.settingslib.drawer.DashboardCategory;
 import com.android.settingslib.drawer.Tile;
+import com.android.settingslib.search.Indexable;
+import com.android.settingslib.search.SearchIndexableData;
+import com.android.settingslib.search.SearchIndexableRaw;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -219,14 +222,12 @@
     }
 
     private List<String> getNonIndexableKeysFromProvider(Context context) {
-        final Collection<Class> values = FeatureFactory.getFactory(context)
+        final Collection<SearchIndexableData> bundles = FeatureFactory.getFactory(context)
                 .getSearchFeatureProvider().getSearchIndexableResources().getProviderValues();
         final List<String> nonIndexableKeys = new ArrayList<>();
-
-        for (Class<?> clazz : values) {
+        for (SearchIndexableData bundle : bundles) {
             final long startTime = System.currentTimeMillis();
-            Indexable.SearchIndexProvider provider = DatabaseIndexingUtils.getSearchIndexProvider(
-                    clazz);
+            Indexable.SearchIndexProvider provider = bundle.getSearchIndexProvider();
 
             List<String> providerNonIndexableKeys;
             try {
@@ -241,7 +242,8 @@
                 if (System.getProperty(SYSPROP_CRASH_ON_ERROR) != null) {
                     throw new RuntimeException(e);
                 }
-                Log.e(TAG, "Error trying to get non-indexable keys from: " + clazz.getName(), e);
+                Log.e(TAG, "Error trying to get non-indexable keys from: "
+                        + bundle.getTargetClass().getName(), e);
                 continue;
             }
 
@@ -270,13 +272,11 @@
     }
 
     private List<SearchIndexableResource> getSearchIndexableResourcesFromProvider(Context context) {
-        Collection<Class> values = FeatureFactory.getFactory(context)
+        final Collection<SearchIndexableData> bundles = FeatureFactory.getFactory(context)
                 .getSearchFeatureProvider().getSearchIndexableResources().getProviderValues();
         List<SearchIndexableResource> resourceList = new ArrayList<>();
-
-        for (Class<?> clazz : values) {
-            Indexable.SearchIndexProvider provider = DatabaseIndexingUtils.getSearchIndexProvider(
-                    clazz);
+        for (SearchIndexableData bundle : bundles) {
+            Indexable.SearchIndexProvider provider = bundle.getSearchIndexProvider();
 
             final List<SearchIndexableResource> resList =
                     provider.getXmlResourcesToIndex(context, true);
@@ -287,7 +287,7 @@
 
             for (SearchIndexableResource item : resList) {
                 item.className = TextUtils.isEmpty(item.className)
-                        ? clazz.getName()
+                        ? bundle.getTargetClass().getName()
                         : item.className;
             }
 
@@ -298,13 +298,11 @@
     }
 
     private List<SearchIndexableRaw> getSearchIndexableRawFromProvider(Context context) {
-        final Collection<Class> values = FeatureFactory.getFactory(context)
+        final Collection<SearchIndexableData> bundles = FeatureFactory.getFactory(context)
                 .getSearchFeatureProvider().getSearchIndexableResources().getProviderValues();
         final List<SearchIndexableRaw> rawList = new ArrayList<>();
-
-        for (Class<?> clazz : values) {
-            Indexable.SearchIndexProvider provider = DatabaseIndexingUtils.getSearchIndexProvider(
-                    clazz);
+        for (SearchIndexableData bundle : bundles) {
+            Indexable.SearchIndexProvider provider = bundle.getSearchIndexProvider();
             final List<SearchIndexableRaw> providerRaws = provider.getRawDataToIndex(context,
                     true /* enabled */);
 
@@ -315,7 +313,7 @@
             for (SearchIndexableRaw raw : providerRaws) {
                 // The classname and intent information comes from the PreIndexData
                 // This will be more clear when provider conversion is done at PreIndex time.
-                raw.className = clazz.getName();
+                raw.className = bundle.getTargetClass().getName();
 
             }
             rawList.addAll(providerRaws);
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/CredentialStorage.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/CredentialStorage.java
index 18abac7..268a710 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/CredentialStorage.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/CredentialStorage.java
@@ -41,18 +41,10 @@
 import androidx.appcompat.app.AlertDialog;
 import androidx.fragment.app.FragmentActivity;
 
-import com.android.internal.widget.LockPatternUtils;
-import com.android.org.bouncycastle.asn1.ASN1InputStream;
-import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.password.ChooseLockSettingsHelper;
 import com.android.car.developeroptions.vpn2.VpnUtils;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-
-import sun.security.util.ObjectIdentifier;
-import sun.security.x509.AlgorithmId;
+import com.android.internal.widget.LockPatternUtils;
 
 /**
  * CredentialStorage handles resetting and installing keys into KeyStore.
@@ -118,20 +110,6 @@
         }
     }
 
-    private boolean isHardwareBackedKey(byte[] keyData) {
-        try {
-            final ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData));
-            final PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
-            final String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
-            final String algName = new AlgorithmId(new ObjectIdentifier(algOid)).getName();
-
-            return KeyChain.isBoundKeyAlgorithm(algName);
-        } catch (IOException e) {
-            Log.e(TAG, "Failed to parse key data");
-            return false;
-        }
-    }
-
     /**
      * Install credentials if available, otherwise do nothing.
      *
@@ -165,56 +143,18 @@
             return true;
         }
 
-        boolean shouldFinish = true;
-        if (bundle.containsKey(Credentials.EXTRA_USER_PRIVATE_KEY_NAME)) {
-            final String key = bundle.getString(Credentials.EXTRA_USER_PRIVATE_KEY_NAME);
-            final byte[] value = bundle.getByteArray(Credentials.EXTRA_USER_PRIVATE_KEY_DATA);
-
-            if (!mKeyStore.importKey(key, value, uid, KeyStore.FLAG_NONE)) {
-                Log.e(TAG, "Failed to install " + key + " as uid " + uid);
-                return true;
-            }
-            // The key was prepended USER_PRIVATE_KEY by the CredentialHelper. However,
-            // KeyChain internally uses the raw alias name and only prepends USER_PRIVATE_KEY
-            // to the key name when interfacing with KeyStore.
-            // This is generally a symptom of CredentialStorage and CredentialHelper relying
-            // on internal implementation details of KeyChain and imitating its functionality
-            // rather than delegating to KeyChain for the certificate installation.
-            if (uid == Process.SYSTEM_UID || uid == KeyStore.UID_SELF) {
-                new MarkKeyAsUserSelectable(
-                        key.replaceFirst("^" + Credentials.USER_PRIVATE_KEY, "")).execute();
-                shouldFinish = false;
-            }
+        String alias = bundle.getString(Credentials.EXTRA_USER_KEY_ALIAS, null);
+        if (TextUtils.isEmpty(alias)) {
+            Log.e(TAG, "Cannot install key without an alias");
+            return true;
         }
 
-        final int flags = KeyStore.FLAG_NONE;
+        final byte[] privateKeyData = bundle.getByteArray(Credentials.EXTRA_USER_PRIVATE_KEY_DATA);
+        final byte[] certData = bundle.getByteArray(Credentials.EXTRA_USER_CERTIFICATE_DATA);
+        final byte[] caListData = bundle.getByteArray(Credentials.EXTRA_CA_CERTIFICATES_DATA);
+        new InstallKeyInKeyChain(alias, privateKeyData, certData, caListData, uid).execute();
 
-        if (bundle.containsKey(Credentials.EXTRA_USER_CERTIFICATE_NAME)) {
-            final String certName = bundle.getString(Credentials.EXTRA_USER_CERTIFICATE_NAME);
-            final byte[] certData = bundle.getByteArray(Credentials.EXTRA_USER_CERTIFICATE_DATA);
-
-            if (!mKeyStore.put(certName, certData, uid, flags)) {
-                Log.e(TAG, "Failed to install " + certName + " as uid " + uid);
-                return shouldFinish;
-            }
-        }
-
-        if (bundle.containsKey(Credentials.EXTRA_CA_CERTIFICATES_NAME)) {
-            final String caListName = bundle.getString(Credentials.EXTRA_CA_CERTIFICATES_NAME);
-            final byte[] caListData = bundle.getByteArray(Credentials.EXTRA_CA_CERTIFICATES_DATA);
-
-            if (!mKeyStore.put(caListName, caListData, uid, flags)) {
-                Log.e(TAG, "Failed to install " + caListName + " as uid " + uid);
-                return shouldFinish;
-            }
-        }
-
-        // Send the broadcast.
-        final Intent broadcast = new Intent(KeyChain.ACTION_KEYCHAIN_CHANGED);
-        sendBroadcast(broadcast);
-
-        setResult(RESULT_OK);
-        return shouldFinish;
+        return false;
     }
 
     /**
@@ -308,6 +248,67 @@
     }
 
     /**
+     * Background task to install a certificate into KeyChain.
+     */
+    private class InstallKeyInKeyChain extends AsyncTask<Void, Void, Boolean> {
+        final String mAlias;
+        private final byte[] mKeyData;
+        private final byte[] mCertData;
+        private final byte[] mCaListData;
+        private final int mUid;
+
+        InstallKeyInKeyChain(String alias, byte[] keyData, byte[] certData, byte[] caListData,
+                int uid) {
+            mAlias = alias;
+            mKeyData = keyData;
+            mCertData = certData;
+            mCaListData = caListData;
+            mUid = uid;
+        }
+
+        @Override
+        protected Boolean doInBackground(Void... unused) {
+            try (KeyChainConnection keyChainConnection = KeyChain.bind(CredentialStorage.this)) {
+                return keyChainConnection.getService()
+                        .installKeyPair(mKeyData, mCertData, mCaListData, mAlias, mUid);
+            } catch (RemoteException e) {
+                Log.w(TAG, String.format("Failed to install key %s to uid %d", mAlias, mUid), e);
+                return false;
+            } catch (InterruptedException e) {
+                Log.w(TAG, String.format("Interrupted while installing key %s", mAlias), e);
+                Thread.currentThread().interrupt();
+                return false;
+            }
+        }
+
+        @Override
+        protected void onPostExecute(Boolean result) {
+            Log.i(TAG, String.format("Marked alias %s as selectable, success? %s",
+                    mAlias, result));
+            CredentialStorage.this.onKeyInstalled(mAlias, mUid, result);
+        }
+    }
+
+    private void onKeyInstalled(String alias, int uid, boolean result) {
+        if (!result) {
+            Log.w(TAG, String.format("Error installing alias %s for uid %d", alias, uid));
+            finish();
+            return;
+        }
+
+        // Send the broadcast.
+        final Intent broadcast = new Intent(KeyChain.ACTION_KEYCHAIN_CHANGED);
+        sendBroadcast(broadcast);
+        setResult(RESULT_OK);
+
+        if (uid == Process.SYSTEM_UID || uid == KeyStore.UID_SELF) {
+            new MarkKeyAsUserSelectable(alias).execute();
+        } else {
+            finish();
+        }
+    }
+
+    /**
      * Background task to mark a given key alias as user-selectable, so that
      * it can be selected by users from the Certificate Selection prompt.
      */
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/CryptKeeperSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/CryptKeeperSettings.java
index f580692..7d83f4c 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/CryptKeeperSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/CryptKeeperSettings.java
@@ -28,7 +28,6 @@
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
-import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -43,6 +42,7 @@
 import com.android.car.developeroptions.core.InstrumentedPreferenceFragment;
 import com.android.car.developeroptions.password.ChooseLockSettingsHelper;
 import com.android.car.developeroptions.password.ConfirmLockPattern;
+import com.android.internal.widget.LockscreenCredential;
 
 public class CryptKeeperSettings extends InstrumentedPreferenceFragment {
     private static final String TAG = "CryptKeeper";
@@ -193,9 +193,10 @@
         // confirmation prompt; otherwise, go back to the initial state.
         if (resultCode == Activity.RESULT_OK && data != null) {
             int type = data.getIntExtra(ChooseLockSettingsHelper.EXTRA_KEY_TYPE, -1);
-            byte[] password = data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
-            if (!(password == null || password.length == 0)) {
-                showFinalConfirmation(type, password);
+            LockscreenCredential password = data.getParcelableExtra(
+                    ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
+            if (password != null && !password.isNone()) {
+                showFinalConfirmation(type, password.getCredential());
             }
         }
     }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/LockUnificationPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/LockUnificationPreferenceController.java
index 451b01e..4619dab 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/LockUnificationPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/LockUnificationPreferenceController.java
@@ -31,7 +31,6 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
-import com.android.internal.widget.LockPatternUtils;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.Utils;
 import com.android.car.developeroptions.core.PreferenceControllerMixin;
@@ -39,6 +38,8 @@
 import com.android.car.developeroptions.overlay.FeatureFactory;
 import com.android.car.developeroptions.password.ChooseLockGeneric;
 import com.android.car.developeroptions.password.ChooseLockSettingsHelper;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockscreenCredential;
 import com.android.settingslib.RestrictedLockUtilsInternal;
 import com.android.settingslib.RestrictedSwitchPreference;
 import com.android.settingslib.core.AbstractPreferenceController;
@@ -70,8 +71,8 @@
     private RestrictedSwitchPreference mUnifyProfile;
 
 
-    private byte[] mCurrentDevicePassword;
-    private byte[] mCurrentProfilePassword;
+    private LockscreenCredential mCurrentDevicePassword;
+    private LockscreenCredential mCurrentProfilePassword;
     private boolean mKeepDeviceLock;
 
     @Override
@@ -89,6 +90,8 @@
                 .getSecurityFeatureProvider()
                 .getLockPatternUtils(context);
         mProfileUserId = Utils.getManagedProfileId(mUm, MY_USER_ID);
+        mCurrentDevicePassword = LockscreenCredential.createNone();
+        mCurrentProfilePassword = LockscreenCredential.createNone();
     }
 
     @Override
@@ -151,13 +154,13 @@
         } else if (requestCode == UNIFY_LOCK_CONFIRM_DEVICE_REQUEST
                 && resultCode == Activity.RESULT_OK) {
             mCurrentDevicePassword =
-                    data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
+                    data.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
             launchConfirmProfileLock();
             return true;
         } else if (requestCode == UNIFY_LOCK_CONFIRM_PROFILE_REQUEST
                 && resultCode == Activity.RESULT_OK) {
             mCurrentProfilePassword =
-                    data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
+                    data.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
             unifyLocks();
             return true;
         }
@@ -221,17 +224,8 @@
     }
 
     private void unifyKeepingWorkLock() {
-        final int profileQuality =
-                mLockPatternUtils.getKeyguardStoredPasswordQuality(mProfileUserId);
-        // PASSWORD_QUALITY_SOMETHING means pattern, everything above means PIN/password.
-        if (profileQuality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
-            mLockPatternUtils.saveLockPattern(
-                    LockPatternUtils.byteArrayToPattern(mCurrentProfilePassword),
-                    mCurrentDevicePassword, MY_USER_ID);
-        } else {
-            mLockPatternUtils.saveLockPassword(
-                    mCurrentProfilePassword, mCurrentDevicePassword, profileQuality, MY_USER_ID);
-        }
+        mLockPatternUtils.setLockCredential(
+                mCurrentProfilePassword, mCurrentDevicePassword, MY_USER_ID);
         mLockPatternUtils.setSeparateProfileChallengeEnabled(mProfileUserId, false,
                 mCurrentProfilePassword);
         final boolean profilePatternVisibility =
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/screenlock/ScreenLockSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/screenlock/ScreenLockSettings.java
index 90b55c1..0a2524a 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/screenlock/ScreenLockSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/security/screenlock/ScreenLockSettings.java
@@ -23,14 +23,14 @@
 
 import androidx.fragment.app.Fragment;
 
-import com.android.internal.widget.LockPatternUtils;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.security.OwnerInfoPreferenceController;
+import com.android.internal.widget.LockPatternUtils;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/sim/SimSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/sim/SimSettings.java
index aff0bd9..d3727f8 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/sim/SimSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/sim/SimSettings.java
@@ -22,8 +22,8 @@
 import android.content.res.Resources;
 import android.graphics.drawable.BitmapDrawable;
 import android.os.Bundle;
-import android.os.SystemProperties;
 import android.provider.SearchIndexableResource;
+import android.sysprop.TelephonyProperties;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.telephony.PhoneNumberUtils;
@@ -37,12 +37,11 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
-import com.android.internal.telephony.TelephonyProperties;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.RestrictedSettingsFragment;
 import com.android.car.developeroptions.Utils;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
@@ -181,8 +180,7 @@
         if (DBG) log("[updateCellularDataValues] mSubInfoList=" + mSubInfoList);
 
         boolean callStateIdle = isCallStateIdle();
-        final boolean ecbMode = SystemProperties.getBoolean(
-                TelephonyProperties.PROPERTY_INECM_MODE, false);
+        final boolean ecbMode = TelephonyProperties.in_ecm_mode().orElse(false);
         if (sir != null) {
             simPref.setSummary(sir.getDisplayName());
             // Enable data preference in msim mode and call state idle
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/slices/SliceDataConverter.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/slices/SliceDataConverter.java
index 51cd411..1330a93 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/slices/SliceDataConverter.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/slices/SliceDataConverter.java
@@ -50,8 +50,8 @@
 import com.android.car.developeroptions.core.PreferenceXmlParserUtils.MetadataFlag;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.overlay.FeatureFactory;
-import com.android.car.developeroptions.search.DatabaseIndexingUtils;
-import com.android.car.developeroptions.search.Indexable.SearchIndexProvider;
+import com.android.settingslib.search.Indexable.SearchIndexProvider;
+import com.android.settingslib.search.SearchIndexableData;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -95,14 +95,13 @@
     public List<SliceData> getSliceData() {
         List<SliceData> sliceData = new ArrayList<>();
 
-        final Collection<Class> indexableClasses = FeatureFactory.getFactory(mContext)
+        final Collection<SearchIndexableData> bundles = FeatureFactory.getFactory(mContext)
                 .getSearchFeatureProvider().getSearchIndexableResources().getProviderValues();
 
-        for (Class clazz : indexableClasses) {
-            final String fragmentName = clazz.getName();
+        for (SearchIndexableData bundle : bundles) {
+            final String fragmentName = bundle.getTargetClass().getName();
 
-            final SearchIndexProvider provider = DatabaseIndexingUtils.getSearchIndexProvider(
-                    clazz);
+            final SearchIndexProvider provider = bundle.getSearchIndexProvider();
 
             // CodeInspection test guards against the null check. Keep check in case of bad actors.
             if (provider == null) {
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/sound/HandsFreeProfileOutputPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/sound/HandsFreeProfileOutputPreferenceController.java
index 7aada43..f3702f7 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/sound/HandsFreeProfileOutputPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/sound/HandsFreeProfileOutputPreferenceController.java
@@ -66,7 +66,7 @@
             final BluetoothDevice btDevice = mConnectedDevices.get(connectedDeviceIndex);
             mSelectedIndex = connectedDeviceIndex;
             setActiveBluetoothDevice(btDevice);
-            listPreference.setSummary(btDevice.getAliasName());
+            listPreference.setSummary(btDevice.getAlias());
         }
         return true;
     }
@@ -143,7 +143,7 @@
         mediaValues[mSelectedIndex] = defaultSummary;
         for (int i = 0, size = mConnectedDevices.size(); i < size; i++) {
             final BluetoothDevice btDevice = mConnectedDevices.get(i);
-            mediaOutputs[i] = btDevice.getAliasName();
+            mediaOutputs[i] = btDevice.getAlias();
             mediaValues[i] = btDevice.getAddress();
             if (btDevice.equals(activeDevice)) {
                 // select the active connected device.
@@ -171,7 +171,8 @@
         if (hapProfile != null && hfpProfile != null && device == null) {
             hfpProfile.setActiveDevice(null);
             hapProfile.setActiveDevice(null);
-        } else if (hapProfile != null && hapProfile.getHiSyncId(device) != HI_SYNC_ID_INVALID) {
+        } else if (hapProfile != null && device != null
+                && hapProfile.getHiSyncId(device) != HI_SYNC_ID_INVALID) {
             hapProfile.setActiveDevice(device);
         } else if (hfpProfile != null) {
             hfpProfile.setActiveDevice(device);
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/sound/MediaOutputPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/sound/MediaOutputPreferenceController.java
index 64126c9..9229507 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/sound/MediaOutputPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/sound/MediaOutputPreferenceController.java
@@ -86,7 +86,7 @@
         mPreference.setVisible(deviceConnectable);
         mPreference.setSummary((activeDevice == null) ?
                 mContext.getText(R.string.media_output_default_summary) :
-                activeDevice.getAliasName());
+                activeDevice.getAlias());
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/support/SupportDashboardActivity.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/support/SupportDashboardActivity.java
index 677b5fc..bffb551 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/support/SupportDashboardActivity.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/support/SupportDashboardActivity.java
@@ -24,9 +24,9 @@
 import com.android.car.developeroptions.overlay.FeatureFactory;
 import com.android.car.developeroptions.overlay.SupportFeatureProvider;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
-import com.android.car.developeroptions.search.SearchIndexableRaw;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
+import com.android.settingslib.search.SearchIndexableRaw;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/system/ResetDashboardFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/system/ResetDashboardFragment.java
index 7c6ad97..bf49cfd 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/system/ResetDashboardFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/system/ResetDashboardFragment.java
@@ -25,9 +25,9 @@
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.network.NetworkResetPreferenceController;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/system/SystemDashboardFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/system/SystemDashboardFragment.java
index d94d914..ba51aee 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/system/SystemDashboardFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/system/SystemDashboardFragment.java
@@ -29,7 +29,7 @@
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.overlay.FeatureFactory;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.Arrays;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/system/SystemUpdatePreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/system/SystemUpdatePreferenceController.java
index 9209d3f..efa06ea 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/system/SystemUpdatePreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/system/SystemUpdatePreferenceController.java
@@ -89,7 +89,7 @@
     @Override
     public CharSequence getSummary() {
         CharSequence summary = mContext.getString(R.string.android_version_summary,
-                Build.VERSION.RELEASE);
+                Build.VERSION.RELEASE_OR_CODENAME);
         final FutureTask<Bundle> bundleFutureTask = new FutureTask<>(
                 // Put the API call in a future to avoid StrictMode violation.
                 () -> mUpdateManager.retrieveSystemUpdateInfo());
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/tts/TextToSpeechSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/tts/TextToSpeechSettings.java
index 5b8d88e..73493a8 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/tts/TextToSpeechSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/tts/TextToSpeechSettings.java
@@ -43,9 +43,9 @@
 import com.android.car.developeroptions.SettingsActivity;
 import com.android.car.developeroptions.SettingsPreferenceFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.widget.GearPreference;
 import com.android.car.developeroptions.widget.SeekBarPreference;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 import com.android.settingslib.widget.ActionButtonsPreference;
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/tts/TtsEnginePreferenceFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/tts/TtsEnginePreferenceFragment.java
index 25d8021..d76635b 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/tts/TtsEnginePreferenceFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/tts/TtsEnginePreferenceFragment.java
@@ -17,8 +17,8 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.SettingsPreferenceFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.tts.TtsEnginePreference.RadioButtonGroupState;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.Arrays;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/users/MultiUserFooterPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/users/MultiUserFooterPreferenceController.java
index e1d8aef..c3c5f83 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/users/MultiUserFooterPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/users/MultiUserFooterPreferenceController.java
@@ -21,29 +21,18 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.Preference;
 
-import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.core.BasePreferenceController;
-import com.android.settingslib.widget.FooterPreference;
-import com.android.settingslib.widget.FooterPreferenceMixinCompat;
 
 public class MultiUserFooterPreferenceController extends BasePreferenceController {
 
     @VisibleForTesting
     final UserCapabilities mUserCaps;
 
-    private FooterPreferenceMixinCompat mFooterMixin;
-
-    public MultiUserFooterPreferenceController(Context context) {
-        super(context, "dummy_key");
+    public MultiUserFooterPreferenceController(Context context, String key) {
+        super(context, key);
         mUserCaps = UserCapabilities.create(context);
     }
 
-    public MultiUserFooterPreferenceController setFooterMixin(
-            FooterPreferenceMixinCompat footerMixin) {
-        mFooterMixin = footerMixin;
-        return this;
-    }
-
     @Override
     public int getAvailabilityStatus() {
         return (mUserCaps.mEnabled && !mUserCaps.mUserSwitcherEnabled)
@@ -54,8 +43,6 @@
     @Override
     public void updateState(Preference preference) {
         mUserCaps.updateAddUserCapabilities(mContext);
-        final FooterPreference pref = mFooterMixin.createFooterPreference();
-        pref.setTitle(R.string.user_settings_footer_text);
-        pref.setVisible(isAvailable());
+        preference.setVisible(isAvailable());
     }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/users/MultiUserSwitchBarController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/users/MultiUserSwitchBarController.java
index 82e7f36..63a20e7 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/users/MultiUserSwitchBarController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/users/MultiUserSwitchBarController.java
@@ -52,8 +52,6 @@
         mListener = listener;
         mUserCapabilities = UserCapabilities.create(context);
         mSwitchBar.setChecked(mUserCapabilities.mUserSwitcherEnabled);
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Settings.Global.USER_SWITCHER_ENABLED, mSwitchBar.isChecked() ? 1 : 0);
 
         if (mUserCapabilities.mDisallowSwitchUser) {
             mSwitchBar.setDisabledByAdmin(RestrictedLockUtilsInternal
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/users/UserSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/users/UserSettings.java
index 415ce36..1913222 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/users/UserSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/users/UserSettings.java
@@ -57,8 +57,6 @@
 import androidx.preference.PreferenceGroup;
 import androidx.preference.PreferenceScreen;
 
-import com.android.internal.util.UserIcons;
-import com.android.internal.widget.LockPatternUtils;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.SettingsActivity;
 import com.android.car.developeroptions.SettingsPreferenceFragment;
@@ -67,14 +65,16 @@
 import com.android.car.developeroptions.dashboard.SummaryLoader;
 import com.android.car.developeroptions.password.ChooseLockGeneric;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.widget.SwitchBar;
 import com.android.car.developeroptions.widget.SwitchBarController;
+import com.android.internal.util.UserIcons;
+import com.android.internal.widget.LockPatternUtils;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 import com.android.settingslib.RestrictedLockUtilsInternal;
 import com.android.settingslib.RestrictedPreference;
 import com.android.settingslib.drawable.CircleFramedDrawable;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.io.IOException;
@@ -111,6 +111,7 @@
     private static final String KEY_USER_GUEST = "user_guest";
     private static final String KEY_ADD_USER = "user_add";
     private static final String KEY_ADD_USER_WHEN_LOCKED = "user_settings_add_users_when_locked";
+    private static final String KEY_MULTIUSER_FOOTER = "multiuser_footer";
 
     private static final int MENU_REMOVE_USER = Menu.FIRST;
 
@@ -233,8 +234,8 @@
 
         mAddUserWhenLockedPreferenceController = new AddUserWhenLockedPreferenceController(
                 activity, KEY_ADD_USER_WHEN_LOCKED);
-        mMultiUserFooterPreferenceController = new MultiUserFooterPreferenceController(activity)
-                .setFooterMixin(mFooterPreferenceMixin);
+        mMultiUserFooterPreferenceController = new MultiUserFooterPreferenceController(activity,
+                KEY_MULTIUSER_FOOTER);
 
         final PreferenceScreen screen = getPreferenceScreen();
         mAddUserWhenLockedPreferenceController.displayPreference(screen);
@@ -954,7 +955,10 @@
         final Preference addUserOnLockScreen = getPreferenceScreen().findPreference(
                 mAddUserWhenLockedPreferenceController.getPreferenceKey());
         mAddUserWhenLockedPreferenceController.updateState(addUserOnLockScreen);
-        mMultiUserFooterPreferenceController.updateState(null /* preference */);
+
+        final Preference multiUserFooterPrefence = getPreferenceScreen().findPreference(
+                mMultiUserFooterPreferenceController.getPreferenceKey());
+        mMultiUserFooterPreferenceController.updateState(multiUserFooterPrefence);
         mUserListCategory.setVisible(mUserCaps.mUserSwitcherEnabled);
 
         updateAddUser(context);
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/utils/ManagedServiceSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/utils/ManagedServiceSettings.java
index c266613..2f14cab 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/utils/ManagedServiceSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/utils/ManagedServiceSettings.java
@@ -17,7 +17,6 @@
 package com.android.car.developeroptions.utils;
 
 import android.annotation.Nullable;
-import android.app.ActivityManager;
 import android.app.Dialog;
 import android.app.admin.DevicePolicyManager;
 import android.app.settings.SettingsEnums;
@@ -91,12 +90,8 @@
     @Override
     public void onResume() {
         super.onResume();
-        if (!ActivityManager.isLowRamDeviceStatic()) {
-            mServiceListing.reload();
-            mServiceListing.setListening(true);
-        } else {
-            setEmptyText(R.string.disabled_low_ram_device);
-        }
+        mServiceListing.reload();
+        mServiceListing.setListening(true);
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/vpn2/AppDialogFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/vpn2/AppDialogFragment.java
index 011760e..472ea18 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/vpn2/AppDialogFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/vpn2/AppDialogFragment.java
@@ -22,6 +22,7 @@
 import android.content.DialogInterface;
 import android.content.pm.PackageInfo;
 import android.net.IConnectivityManager;
+import android.net.VpnManager;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -145,7 +146,8 @@
         }
         final int userId = getUserId();
         try {
-            mService.setVpnPackageAuthorization(mPackageInfo.packageName, userId, false);
+            mService.setVpnPackageAuthorization(
+                    mPackageInfo.packageName, userId, VpnManager.TYPE_VPN_NONE);
             onDisconnect(dialog);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to forget authorization of " + mPackageInfo.packageName +
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/vpn2/AppVpnInfo.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/vpn2/AppVpnInfo.java
index 87991ac..1c405fe 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/vpn2/AppVpnInfo.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/vpn2/AppVpnInfo.java
@@ -2,8 +2,6 @@
 
 import android.annotation.NonNull;
 
-import com.android.internal.util.Preconditions;
-
 import java.util.Objects;
 
 /**
@@ -16,7 +14,7 @@
 
     public AppVpnInfo(int userId, @NonNull String packageName) {
         this.userId = userId;
-        this.packageName = Preconditions.checkNotNull(packageName);
+        this.packageName = Objects.requireNonNull(packageName);
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wallpaper/WallpaperSuggestionActivity.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wallpaper/WallpaperSuggestionActivity.java
index e6bcf32..aed64f2 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wallpaper/WallpaperSuggestionActivity.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wallpaper/WallpaperSuggestionActivity.java
@@ -29,9 +29,9 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.core.SubSettingLauncher;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
-import com.android.car.developeroptions.search.SearchIndexableRaw;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
+import com.android.settingslib.search.SearchIndexableRaw;
 
 import com.google.android.setupcompat.util.WizardManagerHelper;
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wfd/WifiDisplaySettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wfd/WifiDisplaySettings.java
index e2205d3..04616f5 100755
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wfd/WifiDisplaySettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wfd/WifiDisplaySettings.java
@@ -61,12 +61,12 @@
 import androidx.preference.PreferenceViewHolder;
 import androidx.preference.SwitchPreference;
 
-import com.android.internal.app.MediaRouteDialogPresenter;
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.SettingsPreferenceFragment;
 import com.android.car.developeroptions.dashboard.SummaryLoader;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
+import com.android.internal.app.MediaRouteDialogPresenter;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
@@ -523,7 +523,7 @@
         if (DEBUG) {
             Slog.d(TAG, "Setting listen mode to: " + enable);
         }
-        mWifiP2pManager.listen(mWifiP2pChannel, enable, new ActionListener() {
+        final ActionListener listener = new ActionListener() {
             @Override
             public void onSuccess() {
                 if (DEBUG) {
@@ -537,7 +537,12 @@
                 Slog.e(TAG, "Failed to " + (enable ? "entered" : "exited")
                         + " listen mode with reason " + reason + ".");
             }
-        });
+        };
+        if (enable) {
+            mWifiP2pManager.startListening(mWifiP2pChannel, listener);
+        } else {
+            mWifiP2pManager.stopListening(mWifiP2pChannel, listener);
+        }
     }
 
     private void setWifiP2pChannels(final int lc, final int oc) {
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/widget/ChartGridView.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/widget/ChartGridView.java
index b608544..457e71e 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/widget/ChartGridView.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/widget/ChartGridView.java
@@ -31,9 +31,10 @@
 import android.util.AttributeSet;
 import android.view.View;
 
-import com.android.internal.util.Preconditions;
 import com.android.car.developeroptions.R;
 
+import java.util.Objects;
+
 /**
  * Background of {@link ChartView} that renders grid lines as requested by
  * {@link ChartAxis#getTickPoints()}.
@@ -89,8 +90,8 @@
     }
 
     void init(ChartAxis horiz, ChartAxis vert) {
-        mHoriz = Preconditions.checkNotNull(horiz, "missing horiz");
-        mVert = Preconditions.checkNotNull(vert, "missing vert");
+        mHoriz = Objects.requireNonNull(horiz, "missing horiz");
+        mVert = Objects.requireNonNull(vert, "missing vert");
     }
 
     void setBounds(long start, long end) {
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/widget/ChartSweepView.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/widget/ChartSweepView.java
index e61938b..fcea0de 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/widget/ChartSweepView.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/widget/ChartSweepView.java
@@ -35,9 +35,10 @@
 import android.view.MotionEvent;
 import android.view.View;
 
-import com.android.internal.util.Preconditions;
 import com.android.car.developeroptions.R;
 
+import java.util.Objects;
+
 /**
  * Sweep across a {@link ChartView} at a specific {@link ChartAxis} value, which
  * a user can drag.
@@ -155,7 +156,7 @@
     };
 
     void init(ChartAxis axis) {
-        mAxis = Preconditions.checkNotNull(axis, "missing axis");
+        mAxis = Objects.requireNonNull(axis, "missing axis");
     }
 
     public void setNeighbors(ChartSweepView... neighbors) {
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/widget/ChartView.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/widget/ChartView.java
index ff5293d..b04f408 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/widget/ChartView.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/widget/ChartView.java
@@ -25,9 +25,10 @@
 import android.view.ViewDebug;
 import android.widget.FrameLayout;
 
-import com.android.internal.util.Preconditions;
 import com.android.car.developeroptions.R;
 
+import java.util.Objects;
+
 /**
  * Container for two-dimensional chart, drawn with a combination of
  * {@link ChartGridView} and {@link ChartSweepView} children. The entire chart uses
@@ -70,8 +71,8 @@
     }
 
     void init(ChartAxis horiz, ChartAxis vert) {
-        mHoriz = Preconditions.checkNotNull(horiz, "missing horiz");
-        mVert = Preconditions.checkNotNull(vert, "missing vert");
+        mHoriz = Objects.requireNonNull(horiz, "missing horiz");
+        mVert = Objects.requireNonNull(vert, "missing vert");
     }
 
     public void setOptimalWidth(int optimalWidth, float optimalWidthWeight) {
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/CaptivePortalNetworkCallback.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/CaptivePortalNetworkCallback.java
index 2b3955b..d9e94d6 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/CaptivePortalNetworkCallback.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/CaptivePortalNetworkCallback.java
@@ -19,7 +19,7 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
 
 /** Listens for changes to NetworkCapabilities to update the ConnectedAccessPointPreference. */
 final class CaptivePortalNetworkCallback extends NetworkCallback {
@@ -31,8 +31,8 @@
 
     CaptivePortalNetworkCallback(
             Network network, ConnectedAccessPointPreference connectedApPreference) {
-        mNetwork = Preconditions.checkNotNull(network);
-        mConnectedApPreference = Preconditions.checkNotNull(connectedApPreference);
+        mNetwork = Objects.requireNonNull(network);
+        mConnectedApPreference = Objects.requireNonNull(connectedApPreference);
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/ConfigureWifiSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/ConfigureWifiSettings.java
index 4f5ea7e..8753614 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/ConfigureWifiSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/ConfigureWifiSettings.java
@@ -28,9 +28,9 @@
 import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.dashboard.DashboardFragment;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
 import com.android.car.developeroptions.wifi.p2p.WifiP2pPreferenceController;
 import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/NetworkRequestDialogFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/NetworkRequestDialogFragment.java
index 6c32f5c..bf213bb 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/NetworkRequestDialogFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/NetworkRequestDialogFragment.java
@@ -30,6 +30,7 @@
 import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.Message;
 import android.text.TextUtils;
 import android.view.LayoutInflater;
@@ -304,7 +305,7 @@
         final WifiManager wifiManager = getContext().getApplicationContext()
                 .getSystemService(WifiManager.class);
         if (wifiManager != null) {
-            wifiManager.registerNetworkRequestMatchCallback(this, mHandler);
+            wifiManager.registerNetworkRequestMatchCallback(new HandlerExecutor(mHandler), this);
         }
         // Sets time-out to stop scanning.
         mHandler.sendEmptyMessageDelayed(MESSAGE_STOP_SCAN_WIFI_LIST, DELAY_TIME_STOP_SCAN_MS);
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/NetworkRequestErrorDialogFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/NetworkRequestErrorDialogFragment.java
index 59f1b02..5d3bd74 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/NetworkRequestErrorDialogFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/NetworkRequestErrorDialogFragment.java
@@ -41,10 +41,6 @@
         return new NetworkRequestErrorDialogFragment();
     }
 
-    private NetworkRequestErrorDialogFragment() {
-        super();
-    }
-
     @Override
     public void onCancel(@NonNull DialogInterface dialog) {
         super.onCancel(dialog);
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/RequestToggleWiFiActivity.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/RequestToggleWiFiActivity.java
index 5e24362..4c86e04 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/RequestToggleWiFiActivity.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/RequestToggleWiFiActivity.java
@@ -29,12 +29,11 @@
 import android.os.Bundle;
 import android.text.TextUtils;
 import android.util.Log;
-import android.widget.Toast;
 
 import androidx.annotation.NonNull;
 
-import com.android.internal.app.AlertActivity;
 import com.android.car.developeroptions.R;
+import com.android.internal.app.AlertActivity;
 
 /**
  * This activity handles requests to toggle WiFi by collecting user
@@ -313,11 +312,6 @@
                         finish();
                     }
                 } break;
-
-                case WifiManager.ERROR: {
-                    Toast.makeText(activity, R.string.wifi_error, Toast.LENGTH_SHORT).show();
-                    finish();
-                } break;
             }
         }
     }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiConfigController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiConfigController.java
index faba3c7..aac5b88 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiConfigController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiConfigController.java
@@ -42,7 +42,6 @@
 import android.text.InputType;
 import android.text.TextUtils;
 import android.text.TextWatcher;
-import android.util.FeatureFlagUtils;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.View;
@@ -254,8 +253,7 @@
         mMeteredSettingsSpinner = mView.findViewById(R.id.metered_settings);
         mHiddenSettingsSpinner = mView.findViewById(R.id.hidden_settings);
         mPrivacySettingsSpinner = mView.findViewById(R.id.privacy_settings);
-        if (mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_wifi_connected_mac_randomization_supported)) {
+        if (mWifiManager.isConnectedMacRandomizationSupported()) {
             View privacySettingsLayout = mView.findViewById(R.id.privacy_settings_fields);
             privacySettingsLayout.setVisibility(View.VISIBLE);
         }
@@ -289,11 +287,12 @@
                                 config.macRandomizationSetting);
                 mPrivacySettingsSpinner.setSelection(prefMacValue);
 
-                if (config.getIpAssignment() == IpAssignment.STATIC) {
+                if (config.getIpConfiguration().getIpAssignment() == IpAssignment.STATIC) {
                     mIpSettingsSpinner.setSelection(STATIC_IP);
                     showAdvancedFields = true;
                     // Display IP address.
-                    StaticIpConfiguration staticConfig = config.getStaticIpConfiguration();
+                    StaticIpConfiguration staticConfig = config.getIpConfiguration()
+                            .getStaticIpConfiguration();
                     if (staticConfig != null && staticConfig.ipAddress != null) {
                         addRow(group, R.string.wifi_ip_address,
                                 staticConfig.ipAddress.getAddress().getHostAddress());
@@ -307,10 +306,11 @@
                     showAdvancedFields = true;
                 }
 
-                if (config.getProxySettings() == ProxySettings.STATIC) {
+                ProxySettings proxySettings = config.getIpConfiguration().getProxySettings();
+                if (proxySettings == ProxySettings.STATIC) {
                     mProxySettingsSpinner.setSelection(PROXY_STATIC);
                     showAdvancedFields = true;
-                } else if (config.getProxySettings() == ProxySettings.PAC) {
+                } else if (proxySettings == ProxySettings.PAC) {
                     mProxySettingsSpinner.setSelection(PROXY_PAC);
                     showAdvancedFields = true;
                 } else {
@@ -331,17 +331,10 @@
                 showProxyFields();
                 final CheckBox advancedTogglebox =
                         (CheckBox) mView.findViewById(R.id.wifi_advanced_togglebox);
-                mView.findViewById(R.id.wifi_advanced_toggle).setVisibility(
-                        mAccessPoint.isCarrierAp() ? View.GONE : View.VISIBLE);
                 advancedTogglebox.setOnCheckedChangeListener(this);
                 advancedTogglebox.setChecked(showAdvancedFields);
                 mView.findViewById(R.id.wifi_advanced_fields)
                         .setVisibility(showAdvancedFields ? View.VISIBLE : View.GONE);
-                if (mAccessPoint.isCarrierAp()) {
-                    addRow(group, R.string.wifi_carrier_connect,
-                            String.format(mContext.getString(R.string.wifi_carrier_content),
-                            mAccessPoint.getCarrierName()));
-                }
             }
 
             if (mMode == WifiConfigUiBase.MODE_MODIFY) {
@@ -644,7 +637,7 @@
                 config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
                 if (mAccessPointSecurity == AccessPoint.SECURITY_EAP_SUITE_B) {
                     config.allowedKeyManagement.set(KeyMgmt.SUITE_B_192);
-                    config.requirePMF = true;
+                    config.requirePmf = true;
                     config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
                     config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
                     config.allowedGroupManagementCiphers.set(WifiConfiguration.GroupMgmtCipher
@@ -761,7 +754,7 @@
                 break;
             case AccessPoint.SECURITY_SAE:
                 config.allowedKeyManagement.set(KeyMgmt.SAE);
-                config.requirePMF = true;
+                config.requirePmf = true;
                 if (mPasswordView.length() != 0) {
                     String password = mPasswordView.getText().toString();
                     config.preSharedKey = '"' + password + '"';
@@ -770,7 +763,7 @@
 
             case AccessPoint.SECURITY_OWE:
                 config.allowedKeyManagement.set(KeyMgmt.OWE);
-                config.requirePMF = true;
+                config.requirePmf = true;
                 break;
 
             default:
@@ -978,10 +971,6 @@
             mEapIdentityView = (TextView) mView.findViewById(R.id.identity);
             mEapAnonymousView = (TextView) mView.findViewById(R.id.anonymous);
 
-            if (mAccessPoint != null && mAccessPoint.isCarrierAp()) {
-                mEapMethodSpinner.setSelection(mAccessPoint.getCarrierApEapType());
-            }
-
             loadCertificates(
                     mEapCaCertSpinner,
                     Credentials.CA_CERTIFICATE,
@@ -1149,9 +1138,6 @@
                 setUserCertInvisible();
                 setPasswordInvisible();
                 setIdentityInvisible();
-                if (mAccessPoint != null && mAccessPoint.isCarrierAp()) {
-                    setEapMethodInvisible();
-                }
                 break;
         }
 
@@ -1246,13 +1232,14 @@
                 mDns2View.addTextChangedListener(this);
             }
             if (config != null) {
-                StaticIpConfiguration staticConfig = config.getStaticIpConfiguration();
+                StaticIpConfiguration staticConfig = config.getIpConfiguration()
+                        .getStaticIpConfiguration();
                 if (staticConfig != null) {
                     if (staticConfig.ipAddress != null) {
                         mIpAddressView.setText(
                                 staticConfig.ipAddress.getAddress().getHostAddress());
                         mNetworkPrefixLengthView.setText(Integer.toString(staticConfig.ipAddress
-                                .getNetworkPrefixLength()));
+                                .getPrefixLength()));
                     }
 
                     if (staticConfig.gateway != null) {
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiInfoPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiInfoPreferenceController.java
index 301037b..9e6663a 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiInfoPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiInfoPreferenceController.java
@@ -22,7 +22,6 @@
 import android.content.IntentFilter;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
-import android.provider.Settings;
 import android.text.TextUtils;
 
 import androidx.core.text.BidiFormatter;
@@ -58,7 +57,7 @@
         super(context);
         mWifiManager = wifiManager;
         mFilter = new IntentFilter();
-        mFilter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
+        mFilter.addAction(WifiManager.ACTION_LINK_CONFIGURATION_CHANGED);
         mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
 
         lifecycle.addObserver(this);
@@ -98,8 +97,8 @@
     public void updateWifiInfo() {
         if (mWifiMacAddressPref != null) {
             final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
-            final boolean macRandomizationSupported = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_wifi_connected_mac_randomization_supported);
+            final boolean macRandomizationSupported =
+                    mWifiManager.isConnectedMacRandomizationSupported();
             final String macAddress = wifiInfo == null ? null : wifiInfo.getMacAddress();
 
             if (macRandomizationSupported && WifiInfo.DEFAULT_MAC_ADDRESS.equals(macAddress)) {
@@ -123,8 +122,8 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            if (action.equals(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION) ||
-                    action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+            if (action.equals(WifiManager.ACTION_LINK_CONFIGURATION_CHANGED)
+                    || action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
                 updateWifiInfo();
             }
         }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiNoInternetDialog.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiNoInternetDialog.java
index e13aee1..7279460 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiNoInternetDialog.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiNoInternetDialog.java
@@ -38,9 +38,9 @@
 import android.view.View;
 import android.widget.CheckBox;
 
+import com.android.car.developeroptions.R;
 import com.android.internal.app.AlertActivity;
 import com.android.internal.app.AlertController;
-import com.android.car.developeroptions.R;
 
 public final class WifiNoInternetDialog extends AlertActivity implements
         DialogInterface.OnClickListener {
@@ -116,9 +116,9 @@
             finish();
             return;
         }
-        mNetworkName = nc.getSSID();
+        mNetworkName = nc.getSsid();
         if (mNetworkName != null) {
-            mNetworkName = WifiInfo.removeDoubleQuotes(mNetworkName);
+            mNetworkName = WifiInfo.sanitizeSsid(mNetworkName);
         }
 
         createDialog();
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiScanModeActivity.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiScanModeActivity.java
index 7a75cbd..cb2861a 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiScanModeActivity.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiScanModeActivity.java
@@ -24,7 +24,6 @@
 import android.content.pm.PackageManager;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
-import android.provider.Settings;
 
 import androidx.appcompat.app.AlertDialog;
 import androidx.fragment.app.DialogFragment;
@@ -79,8 +78,7 @@
     }
 
     private void doPositiveClick() {
-        Settings.Global.putInt(getContentResolver(),
-                Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 1);
+        getApplicationContext().getSystemService(WifiManager.class).setScanAlwaysAvailable(true);
         setResult(RESULT_OK);
         finish();
     }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiScanningRequiredFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiScanningRequiredFragment.java
index d5aa87f..505aceb 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiScanningRequiredFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiScanningRequiredFragment.java
@@ -23,8 +23,8 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.net.wifi.WifiManager;
 import android.os.Bundle;
-import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
 import android.widget.Toast;
@@ -69,8 +69,7 @@
         ContentResolver contentResolver = context.getContentResolver();
         switch(which) {
             case DialogInterface.BUTTON_POSITIVE:
-                Settings.Global.putInt(contentResolver,
-                        Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 1);
+                context.getSystemService(WifiManager.class).setScanAlwaysAvailable(true);
                 Toast.makeText(
                         context,
                         context.getString(R.string.wifi_settings_scanning_required_enabled),
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiSettings.java
index 5807647..963806b 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiSettings.java
@@ -17,6 +17,7 @@
 package com.android.car.developeroptions.wifi;
 
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED;
 import static android.os.UserManager.DISALLOW_CONFIG_WIFI;
 
 import android.annotation.NonNull;
@@ -61,20 +62,19 @@
 import com.android.car.developeroptions.core.FeatureFlags;
 import com.android.car.developeroptions.core.SubSettingLauncher;
 import com.android.car.developeroptions.dashboard.SummaryLoader;
-import com.android.car.developeroptions.datausage.DataUsageUtils;
 import com.android.car.developeroptions.datausage.DataUsagePreference;
+import com.android.car.developeroptions.datausage.DataUsageUtils;
 import com.android.car.developeroptions.location.ScanningSettings;
 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
-import com.android.car.developeroptions.search.Indexable;
-import com.android.car.developeroptions.search.SearchIndexableRaw;
 import com.android.car.developeroptions.widget.SummaryUpdater.OnSummaryChangeListener;
 import com.android.car.developeroptions.widget.SwitchBarController;
 import com.android.car.developeroptions.wifi.details.WifiNetworkDetailsFragment;
 import com.android.car.developeroptions.wifi.dpp.WifiDppUtils;
-import com.android.car.developeroptions.wifi.savedaccesspoints.SavedAccessPointsWifiSettings;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedLockUtilsInternal;
+import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
+import com.android.settingslib.search.SearchIndexableRaw;
 import com.android.settingslib.wifi.AccessPoint;
 import com.android.settingslib.wifi.AccessPoint.AccessPointListener;
 import com.android.settingslib.wifi.AccessPointPreference;
@@ -699,7 +699,8 @@
         }
         WifiConfiguration.NetworkSelectionStatus networkStatus =
                 config.getNetworkSelectionStatus();
-        if (networkStatus == null || networkStatus.isNetworkEnabled()) {
+        if (networkStatus == null
+                || networkStatus.getNetworkSelectionStatus() == NETWORK_SELECTION_ENABLED) {
             return false;
         }
         int reason = networkStatus.getNetworkSelectionDisableReason();
@@ -965,10 +966,8 @@
         final Context context = getContext();
         final PowerManager powerManager = context.getSystemService(PowerManager.class);
         final ContentResolver contentResolver = context.getContentResolver();
-        return Settings.Global.getInt(contentResolver,
-                Settings.Global.WIFI_WAKEUP_ENABLED, 0) == 1
-                && Settings.Global.getInt(contentResolver,
-                Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1
+        return mWifiManager.isAutoWakeupEnabled()
+                && mWifiManager.isScanAlwaysAvailable()
                 && Settings.Global.getInt(contentResolver,
                 Settings.Global.AIRPLANE_MODE_ON, 0) == 0
                 && !powerManager.isPowerSaveMode();
@@ -979,8 +978,8 @@
         // Don't use WifiManager.isScanAlwaysAvailable() to check the Wi-Fi scanning mode. Instead,
         // read the system settings directly. Because when the device is in Airplane mode, even if
         // Wi-Fi scanning mode is on, WifiManager.isScanAlwaysAvailable() still returns "off".
-        final boolean wifiScanningMode = Settings.Global.getInt(getActivity().getContentResolver(),
-                Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1;
+        // TODO(b/149421497): Fix this?
+        final boolean wifiScanningMode = mWifiManager.isScanAlwaysAvailable();
         final CharSequence description = wifiScanningMode ? getText(R.string.wifi_scan_notify_text)
                 : getText(R.string.wifi_scan_notify_text_scanning_off);
         final LinkifyUtils.OnClickListener clickListener =
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiSummaryUpdater.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiSummaryUpdater.java
index 40fd848..5683c90 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiSummaryUpdater.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiSummaryUpdater.java
@@ -90,7 +90,7 @@
         if (!mWifiTracker.connected) {
             return mContext.getString(R.string.disconnected);
         }
-        String ssid = WifiInfo.removeDoubleQuotes(mWifiTracker.ssid);
+        String ssid = WifiInfo.sanitizeSsid(mWifiTracker.ssid);
         if (TextUtils.isEmpty(mWifiTracker.statusLabel)) {
             return ssid;
         }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiUtils.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiUtils.java
index 16db4f0..bbf8284 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiUtils.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiUtils.java
@@ -193,7 +193,7 @@
                 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
                 if (security == AccessPoint.SECURITY_EAP_SUITE_B) {
                     config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
-                    config.requirePMF = true;
+                    config.requirePmf = true;
                     config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
                     config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
                     config.allowedGroupManagementCiphers.set(WifiConfiguration.GroupMgmtCipher
@@ -207,7 +207,7 @@
                 break;
             case AccessPoint.SECURITY_SAE:
                 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
-                config.requirePMF = true;
+                config.requirePmf = true;
                 if (!TextUtils.isEmpty(password)) {
                     config.preSharedKey = '"' + password + '"';
                 }
@@ -215,7 +215,7 @@
 
             case AccessPoint.SECURITY_OWE:
                 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
-                config.requirePMF = true;
+                config.requirePmf = true;
                 break;
 
             default:
@@ -272,7 +272,7 @@
             return CONNECT_TYPE_OPEN_NETWORK;
         } else if (accessPoint.isSaved() && config != null
                 && config.getNetworkSelectionStatus() != null
-                && config.getNetworkSelectionStatus().getHasEverConnected()) {
+                && config.getNetworkSelectionStatus().hasEverConnected()) {
             return CONNECT_TYPE_SAVED_NETWORK;
         } else if (accessPoint.isPasspoint()) {
             // Access point provided by an installed Passpoint provider, connect using
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiWakeupPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiWakeupPreferenceController.java
index 2661f4d..182dc5a 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiWakeupPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiWakeupPreferenceController.java
@@ -24,6 +24,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.location.LocationManager;
+import android.net.wifi.WifiManager;
 import android.provider.Settings;
 import android.text.TextUtils;
 
@@ -59,6 +60,9 @@
     SwitchPreference mPreference;
     @VisibleForTesting
     LocationManager mLocationManager;
+
+    @VisibleForTesting
+    WifiManager mWifiManager;
     private final BroadcastReceiver mLocationReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -73,6 +77,7 @@
         super(context);
         mFragment = fragment;
         mLocationManager = (LocationManager) context.getSystemService(Service.LOCATION_SERVICE);
+        mWifiManager = context.getSystemService(WifiManager.class);
         lifecycle.addObserver(this);
     }
 
@@ -152,8 +157,7 @@
     }
 
     private boolean getWifiScanningEnabled() {
-        return Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1;
+        return mWifiManager.isScanAlwaysAvailable();
     }
 
     private void showScanningDialog() {
@@ -164,13 +168,11 @@
     }
 
     private boolean getWifiWakeupEnabled() {
-        return Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.WIFI_WAKEUP_ENABLED, 0) == 1;
+        return mWifiManager.isAutoWakeupEnabled();
     }
 
     private void setWifiWakeupEnabled(boolean enabled) {
-        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.WIFI_WAKEUP_ENABLED,
-                enabled ? 1 : 0);
+        mWifiManager.setAutoWakeupEnabled(enabled);
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/details/WifiDetailPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/details/WifiDetailPreferenceController.java
index cb80cb3..cd484a7 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/details/WifiDetailPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/details/WifiDetailPreferenceController.java
@@ -197,15 +197,7 @@
         public void onReceive(Context context, Intent intent) {
             switch (intent.getAction()) {
                 case WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION:
-                    if (!intent.getBooleanExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED,
-                            false /* defaultValue */)) {
-                        // only one network changed
-                        WifiConfiguration wifiConfiguration = intent
-                                .getParcelableExtra(WifiManager.EXTRA_WIFI_CONFIGURATION);
-                        if (mAccessPoint.matches(wifiConfiguration)) {
-                            mWifiConfig = wifiConfiguration;
-                        }
-                    }
+                    updateMatchingWifiConfig();
                     // fall through
                 case WifiManager.NETWORK_STATE_CHANGED_ACTION:
                 case WifiManager.RSSI_CHANGED_ACTION:
@@ -213,6 +205,17 @@
                     break;
             }
         }
+
+        private void updateMatchingWifiConfig() {
+            // use getPrivilegedConfiguredNetworks() to get Passpoint & other ephemeral networks
+            for (WifiConfiguration wifiConfiguration :
+                    mWifiManager.getPrivilegedConfiguredNetworks()) {
+                if (mAccessPoint.matches(wifiConfiguration)) {
+                    mWifiConfig = wifiConfiguration;
+                    break;
+                }
+            }
+        }
     };
 
     private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder()
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/details/WifiPrivacyPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/details/WifiPrivacyPreferenceController.java
index 2b5ba22..308f6bb 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/details/WifiPrivacyPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/details/WifiPrivacyPreferenceController.java
@@ -63,9 +63,8 @@
 
     @Override
     public int getAvailabilityStatus() {
-        return mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_wifi_connected_mac_randomization_supported) ?
-                AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+        return mWifiManager.isConnectedMacRandomizationSupported()
+                ?  AVAILABLE : CONDITIONALLY_UNAVAILABLE;
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/dpp/WifiDppUtils.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/dpp/WifiDppUtils.java
index 882dcf7..ee7a3e2 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/dpp/WifiDppUtils.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/dpp/WifiDppUtils.java
@@ -20,8 +20,9 @@
 import android.content.Context;
 import android.content.Intent;
 import android.hardware.biometrics.BiometricPrompt;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.wifi.SoftApConfiguration;
 import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiManager;
 import android.os.CancellationSignal;
 import android.os.Handler;
@@ -29,15 +30,12 @@
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.text.TextUtils;
-import android.util.FeatureFlagUtils;
 
 import com.android.car.developeroptions.R;
-
 import com.android.settingslib.wifi.AccessPoint;
 
-import java.util.List;
-
 import java.time.Duration;
+import java.util.List;
 
 /**
  * Here are the items shared by both WifiDppConfiguratorActivity & WifiDppEnrolleeActivity
@@ -173,6 +171,19 @@
                 WifiQrCode.SECURITY_NO_PASSWORD : WifiQrCode.SECURITY_WEP;
     }
 
+    private static String getSecurityString(SoftApConfiguration config) {
+        switch (config.getSecurityType()) {
+            case SoftApConfiguration.SECURITY_TYPE_WPA3_SAE:
+            // TODO: add support for SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION
+                return WifiQrCode.SECURITY_SAE;
+            case SoftApConfiguration.SECURITY_TYPE_WPA2_PSK:
+                return WifiQrCode.SECURITY_WPA_PSK;
+            case SoftApConfiguration.SECURITY_TYPE_OPEN:
+            default:
+                return WifiQrCode.SECURITY_NO_PASSWORD;
+        }
+    }
+
     /**
      * Returns an intent to launch QR code generator. It may return null if the security is not
      * supported by QR code generator.
@@ -235,20 +246,19 @@
      * the security is not supported by QR code generator.
      *
      * @param context The context to use for the content resolver
-     * @param wifiManager An instance of {@link WifiManager}
-     * @param wifiConfiguration {@link WifiConfiguration} of the Wi-Fi hotspot
+     * @param softApConfiguration {@link WifiConfiguration} of the Wi-Fi hotspot
      * @return Intent for launching QR code generator
      */
     public static Intent getHotspotConfiguratorIntentOrNull(Context context,
-            WifiManager wifiManager, WifiConfiguration wifiConfiguration) {
+            SoftApConfiguration softApConfiguration) {
         final Intent intent = new Intent(context, WifiDppConfiguratorActivity.class);
-        if (isSupportHotspotConfiguratorQrCodeGenerator(wifiConfiguration)) {
+        if (isSupportHotspotConfiguratorQrCodeGenerator(softApConfiguration)) {
             intent.setAction(WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR);
         } else {
             return null;
         }
 
-        setConfiguratorIntentExtra(intent, wifiManager, wifiConfiguration);
+        setConfiguratorIntentExtra(intent, softApConfiguration);
 
         intent.putExtra(EXTRA_WIFI_NETWORK_ID, WifiConfiguration.INVALID_NETWORK_ID);
         intent.putExtra(EXTRA_IS_HOTSPOT, true);
@@ -289,6 +299,30 @@
     }
 
     /**
+     * Set all extra except {@code EXTRA_WIFI_NETWORK_ID} for the intent to
+     * launch configurator activity later.
+     *
+     * @param intent the target to set extra
+     * @param softApConfig the Wi-Fi network for launching configurator activity
+     */
+    private static void setConfiguratorIntentExtra(
+            Intent intent, SoftApConfiguration softApConfig) {
+        final String ssid = softApConfig.getSsid();
+        final String security = getSecurityString(softApConfig);
+        String preSharedKey = softApConfig.getPassphrase();
+
+        if (!TextUtils.isEmpty(ssid)) {
+            intent.putExtra(EXTRA_WIFI_SSID, ssid);
+        }
+        if (!TextUtils.isEmpty(security)) {
+            intent.putExtra(EXTRA_WIFI_SECURITY, security);
+        }
+        if (!TextUtils.isEmpty(preSharedKey)) {
+            intent.putExtra(EXTRA_WIFI_PRE_SHARED_KEY, preSharedKey);
+        }
+    }
+
+    /**
      * Shows authentication screen to confirm credentials (pin, pattern or password) for the current
      * user of the device.
      *
@@ -367,12 +401,13 @@
     }
 
     private static boolean isSupportHotspotConfiguratorQrCodeGenerator(
-            WifiConfiguration wifiConfiguration) {
+            SoftApConfiguration softApConfiguration) {
         // QR code generator produces QR code with ZXing's Wi-Fi network config format,
         // it supports PSK and WEP and non security
         // KeyMgmt.NONE is for WEP or non security
-        return wifiConfiguration.allowedKeyManagement.get(KeyMgmt.WPA2_PSK) ||
-                wifiConfiguration.allowedKeyManagement.get(KeyMgmt.NONE);
+        int securityType = softApConfiguration.getSecurityType();
+        return securityType == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK
+                || securityType == SoftApConfiguration.SECURITY_TYPE_OPEN;
     }
 
     private static boolean isSupportWifiDpp(Context context, int accesspointSecurity) {
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/dpp/WifiNetworkConfig.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/dpp/WifiNetworkConfig.java
index c70cd2d..58091cd 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/dpp/WifiNetworkConfig.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/dpp/WifiNetworkConfig.java
@@ -257,7 +257,7 @@
             final WifiConfiguration enhancedOpenNetworkWifiConfiguration =
                     getBasicWifiConfiguration();
             enhancedOpenNetworkWifiConfiguration.allowedKeyManagement.set(KeyMgmt.OWE);
-            enhancedOpenNetworkWifiConfiguration.requirePMF = true;
+            enhancedOpenNetworkWifiConfiguration.requirePmf = true;
             wifiConfigurations.add(enhancedOpenNetworkWifiConfiguration);
             return wifiConfigurations;
         }
@@ -286,7 +286,7 @@
             }
         } else if (mSecurity.startsWith(SECURITY_SAE)) {
             wifiConfiguration.allowedKeyManagement.set(KeyMgmt.SAE);
-            wifiConfiguration.requirePMF = true;
+            wifiConfiguration.requirePmf = true;
             if (mPreSharedKey.length() != 0) {
                 wifiConfiguration.preSharedKey = addQuotationIfNeeded(mPreSharedKey);
             }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/p2p/WifiP2pSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/p2p/WifiP2pSettings.java
index a9f1ff5..bc60bec 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/p2p/WifiP2pSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/p2p/WifiP2pSettings.java
@@ -147,7 +147,7 @@
                 } else {
                     updateSearchMenu(false);
                 }
-            } else if (WifiP2pManager.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION.equals(action)) {
+            } else if (WifiP2pManager.ACTION_WIFI_P2P_PERSISTENT_GROUPS_CHANGED.equals(action)) {
                 if (mWifiP2pManager != null) {
                     mWifiP2pManager.requestPersistentGroupInfo(mChannel, WifiP2pSettings.this);
                 }
@@ -334,7 +334,7 @@
         mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
         mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
         mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION);
-        mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION);
+        mIntentFilter.addAction(WifiP2pManager.ACTION_WIFI_P2P_PERSISTENT_GROUPS_CHANGED);
         final PreferenceScreen preferenceScreen = getPreferenceScreen();
 
         getActivity().registerReceiver(mReceiver, mIntentFilter);
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/slice/ContextualWifiSlice.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/slice/ContextualWifiSlice.java
index d0f490d..ae2a211 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/slice/ContextualWifiSlice.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/slice/ContextualWifiSlice.java
@@ -18,7 +18,7 @@
 
 import android.content.Context;
 import android.net.Uri;
-import android.net.wifi.WifiSsid;
+import android.net.wifi.WifiManager;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -69,6 +69,6 @@
     }
 
     private boolean hasWorkingNetwork() {
-        return !TextUtils.equals(getActiveSSID(), WifiSsid.NONE) && !isCaptivePortal();
+        return !TextUtils.equals(getActiveSSID(), WifiManager.UNKNOWN_SSID) && !isCaptivePortal();
     }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/slice/WifiScanWorker.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/slice/WifiScanWorker.java
index d10821c..c880f80 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/slice/WifiScanWorker.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/slice/WifiScanWorker.java
@@ -34,7 +34,6 @@
 
 import androidx.annotation.VisibleForTesting;
 
-import com.android.internal.util.Preconditions;
 import com.android.car.developeroptions.slices.SliceBackgroundWorker;
 import com.android.car.developeroptions.wifi.WifiUtils;
 import com.android.settingslib.wifi.AccessPoint;
@@ -42,6 +41,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * {@link SliceBackgroundWorker} for Wi-Fi, used by WifiSlice.
@@ -185,7 +185,7 @@
         private boolean mIsCaptivePortal;
 
         CaptivePortalNetworkCallback(Network network) {
-            mNetwork = Preconditions.checkNotNull(network);
+            mNetwork = Objects.requireNonNull(network);
         }
 
         @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/slice/WifiSlice.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/slice/WifiSlice.java
index 5563add..e30716a 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/slice/WifiSlice.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/slice/WifiSlice.java
@@ -34,12 +34,11 @@
 import android.net.ConnectivityManager;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
-import android.net.NetworkInfo.State;
 import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkInfo.State;
 import android.net.Uri;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
-import android.net.wifi.WifiSsid;
 import android.os.Bundle;
 import android.text.Spannable;
 import android.text.SpannableString;
@@ -321,9 +320,9 @@
 
     protected String getActiveSSID() {
         if (mWifiManager.getWifiState() != WifiManager.WIFI_STATE_ENABLED) {
-            return WifiSsid.NONE;
+            return WifiManager.UNKNOWN_SSID;
         }
-        return WifiInfo.removeDoubleQuotes(mWifiManager.getConnectionInfo().getSSID());
+        return WifiInfo.sanitizeSsid(mWifiManager.getConnectionInfo().getSSID());
     }
 
     private boolean isWifiEnabled() {
@@ -340,7 +339,7 @@
         switch (mWifiManager.getWifiState()) {
             case WifiManager.WIFI_STATE_ENABLED:
                 final String ssid = getActiveSSID();
-                if (TextUtils.equals(ssid, WifiSsid.NONE)) {
+                if (TextUtils.equals(ssid, WifiManager.UNKNOWN_SSID)) {
                     return mContext.getText(R.string.disconnected);
                 }
                 return ssid;
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/TetherService.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/TetherService.java
index dbedb4c..9b7d4b4 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/TetherService.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/TetherService.java
@@ -32,7 +32,6 @@
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
 import android.net.ConnectivityManager;
 import android.os.IBinder;
 import android.os.ResultReceiver;
@@ -44,10 +43,9 @@
 
 import androidx.annotation.VisibleForTesting;
 
-import com.android.car.developeroptions.Utils;
-
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 public class TetherService extends Service {
     private static final String TAG = "TetherService";
@@ -55,6 +53,12 @@
 
     @VisibleForTesting
     public static final String EXTRA_RESULT = "EntitlementResult";
+    @VisibleForTesting
+    public static final String EXTRA_TETHER_PROVISIONING_RESPONSE =
+            "android.net.extra.TETHER_PROVISIONING_RESPONSE";
+    @VisibleForTesting
+    public static final String EXTRA_TETHER_SILENT_PROVISIONING_ACTION =
+            "android.net.extra.TETHER_SILENT_PROVISIONING_ACTION";
 
     // Activity results to match the activity provision protocol.
     // Default to something not ok.
@@ -69,6 +73,10 @@
 
     private int mCurrentTypeIndex;
     private boolean mInProvisionCheck;
+    /** Intent action received from the provisioning app when entitlement check completes. */
+    private String mExpectedProvisionResponseAction = null;
+    /** Intent action sent to the provisioning app to request an entitlement check. */
+    private String mProvisionAction;
     private TetherServiceWrapper mWrapper;
     private ArrayList<Integer> mCurrentTethers;
     private ArrayMap<Integer, List<ResultReceiver>> mPendingCallbacks;
@@ -83,10 +91,6 @@
     public void onCreate() {
         super.onCreate();
         if (DEBUG) Log.d(TAG, "Creating TetherService");
-        String provisionResponse = getResourceForDefaultDataSubId().getString(
-                com.android.internal.R.string.config_mobile_hotspot_provision_response);
-        registerReceiver(mReceiver, new IntentFilter(provisionResponse),
-                android.Manifest.permission.CONNECTIVITY_INTERNAL, null);
         SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
         mCurrentTethers = stringToTethers(prefs.getString(KEY_TETHERS, ""));
         mCurrentTypeIndex = 0;
@@ -98,6 +102,24 @@
         mHotspotReceiver = new HotspotOffReceiver(this);
     }
 
+    // Registers the broadcast receiver for the specified response action, first unregistering
+    // the receiver if it was registered for a different response action.
+    private void maybeRegisterReceiver(final String responseAction) {
+        if (Objects.equals(responseAction, mExpectedProvisionResponseAction)) return;
+
+        if (mExpectedProvisionResponseAction != null) unregisterReceiver(mReceiver);
+
+        registerReceiver(mReceiver, new IntentFilter(responseAction),
+                android.Manifest.permission.TETHER_PRIVILEGED, null /* handler */);
+        mExpectedProvisionResponseAction = responseAction;
+        if (DEBUG) Log.d(TAG, "registerReceiver " + responseAction);
+    }
+
+    private int stopSelfAndStartNotSticky() {
+        stopSelf();
+        return START_NOT_STICKY;
+    }
+
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
         if (intent.hasExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE)) {
@@ -111,9 +133,9 @@
                     callbacksForType.add(callback);
                 } else {
                     // Invalid tether type. Just ignore this request and report failure.
+                    Log.e(TAG, "Invalid tethering type " + type + ", stopping");
                     callback.send(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE, null);
-                    stopSelf();
-                    return START_NOT_STICKY;
+                    return stopSelfAndStartNotSticky();
                 }
             }
 
@@ -123,6 +145,19 @@
             }
         }
 
+        mProvisionAction = intent.getStringExtra(EXTRA_TETHER_SILENT_PROVISIONING_ACTION);
+        if (mProvisionAction == null) {
+            Log.e(TAG, "null provisioning action, stop ");
+            return stopSelfAndStartNotSticky();
+        }
+
+        final String response = intent.getStringExtra(EXTRA_TETHER_PROVISIONING_RESPONSE);
+        if (response == null) {
+            Log.e(TAG, "null provisioning response, stop ");
+            return stopSelfAndStartNotSticky();
+        }
+        maybeRegisterReceiver(response);
+
         if (intent.hasExtra(ConnectivityManager.EXTRA_REM_TETHER_TYPE)) {
             if (!mInProvisionCheck) {
                 int type = intent.getIntExtra(ConnectivityManager.EXTRA_REM_TETHER_TYPE,
@@ -132,27 +167,17 @@
                 if (index >= 0) {
                     removeTypeAtIndex(index);
                 }
-                cancelAlarmIfNecessary();
             } else {
                 if (DEBUG) Log.d(TAG, "Don't cancel alarm during provisioning");
             }
         }
 
-        // Only set the alarm if we have one tether, meaning the one just added,
-        // to avoid setting it when it was already set previously for another
-        // type.
-        if (intent.getBooleanExtra(ConnectivityManager.EXTRA_SET_ALARM, false)
-                && mCurrentTethers.size() == 1) {
-            scheduleAlarm();
-        }
-
         if (intent.getBooleanExtra(ConnectivityManager.EXTRA_RUN_PROVISION, false)) {
             startProvisioning(mCurrentTypeIndex);
         } else if (!mInProvisionCheck) {
             // If we aren't running any provisioning, no reason to stay alive.
             if (DEBUG) Log.d(TAG, "Stopping self.  startid: " + startId);
-            stopSelf();
-            return START_NOT_STICKY;
+            return stopSelfAndStartNotSticky();
         }
         // We want to be started if we are killed accidently, so that we can be sure we finish
         // the check.
@@ -168,16 +193,15 @@
         SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
         prefs.edit().putString(KEY_TETHERS, tethersToString(mCurrentTethers)).commit();
 
-        unregisterReceivers();
+        if (mExpectedProvisionResponseAction != null) {
+            unregisterReceiver(mReceiver);
+            mExpectedProvisionResponseAction = null;
+        }
+        mHotspotReceiver.unregister();
         if (DEBUG) Log.d(TAG, "Destroying TetherService");
         super.onDestroy();
     }
 
-    private void unregisterReceivers() {
-        unregisterReceiver(mReceiver);
-        mHotspotReceiver.unregister();
-    }
-
     private void removeTypeAtIndex(int index) {
         mCurrentTethers.remove(index);
         // If we are currently in the middle of a check, we may need to adjust the
@@ -246,22 +270,22 @@
     }
 
     private void startProvisioning(int index) {
-        if (index < mCurrentTethers.size()) {
-            Intent intent = getProvisionBroadcastIntent(index);
-            setEntitlementAppActive(index);
+        if (index >= mCurrentTethers.size()) return;
+        Intent intent = getProvisionBroadcastIntent(index);
+        setEntitlementAppActive(index);
 
-            if (DEBUG) Log.d(TAG, "Sending provisioning broadcast: " + intent.getAction()
+        if (DEBUG) {
+            Log.d(TAG, "Sending provisioning broadcast: " + intent.getAction()
                     + " type: " + mCurrentTethers.get(index));
-
-            sendBroadcast(intent);
-            mInProvisionCheck = true;
         }
+
+        sendBroadcast(intent);
+        mInProvisionCheck = true;
     }
 
     private Intent getProvisionBroadcastIntent(int index) {
-        String provisionAction = getResourceForDefaultDataSubId().getString(
-                com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui);
-        Intent intent = new Intent(provisionAction);
+        if (mProvisionAction == null) Log.wtf(TAG, "null provisioning action");
+        Intent intent = new Intent(mProvisionAction);
         int type = mCurrentTethers.get(index);
         intent.putExtra(TETHER_CHOICE, type);
         intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND
@@ -295,9 +319,7 @@
 
         PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0);
         AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
-        int period = getResourceForDefaultDataSubId().getInteger(
-                com.android.internal.R.integer.config_mobile_hotspot_provision_check_period);
-        long periodMs = period * MS_PER_HOUR;
+        long periodMs = 24 * MS_PER_HOUR;
         long firstTime = SystemClock.elapsedRealtime() + periodMs;
         if (DEBUG) Log.d(TAG, "Scheduling alarm at interval " + periodMs);
         alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, firstTime, periodMs,
@@ -348,40 +370,48 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (DEBUG) Log.d(TAG, "Got provision result " + intent);
-            String provisionResponse = getResourceForDefaultDataSubId().getString(
-                    com.android.internal.R.string.config_mobile_hotspot_provision_response);
+            if (!intent.getAction().equals(mExpectedProvisionResponseAction)) {
+                Log.e(TAG, "Received provisioning response for unexpected action="
+                        + intent.getAction() + ", expected=" + mExpectedProvisionResponseAction);
+                return;
+            }
 
-            if (provisionResponse.equals(intent.getAction())) {
-                if (!mInProvisionCheck) {
-                    Log.e(TAG, "Unexpected provision response " + intent);
-                    return;
-                }
-                int checkType = mCurrentTethers.get(mCurrentTypeIndex);
-                mInProvisionCheck = false;
-                int result = intent.getIntExtra(EXTRA_RESULT, RESULT_DEFAULT);
-                if (result != RESULT_OK) {
-                    switch (checkType) {
-                        case ConnectivityManager.TETHERING_WIFI:
-                            disableWifiTethering();
-                            break;
-                        case ConnectivityManager.TETHERING_BLUETOOTH:
-                            disableBtTethering();
-                            break;
-                        case ConnectivityManager.TETHERING_USB:
-                            disableUsbTethering();
-                            break;
-                    }
-                }
-                fireCallbacksForType(checkType, result);
+            if (!mInProvisionCheck) {
+                Log.e(TAG, "Unexpected provisioning response when not in provisioning check"
+                        + intent);
+                return;
+            }
 
-                if (++mCurrentTypeIndex >= mCurrentTethers.size()) {
-                    // We are done with all checks, time to die.
-                    stopSelf();
-                } else {
-                    // Start the next check in our list.
-                    startProvisioning(mCurrentTypeIndex);
+
+            if (!mInProvisionCheck) {
+                Log.e(TAG, "Unexpected provision response " + intent);
+                return;
+            }
+            int checkType = mCurrentTethers.get(mCurrentTypeIndex);
+            mInProvisionCheck = false;
+            int result = intent.getIntExtra(EXTRA_RESULT, RESULT_DEFAULT);
+            if (result != RESULT_OK) {
+                switch (checkType) {
+                    case ConnectivityManager.TETHERING_WIFI:
+                        disableWifiTethering();
+                        break;
+                    case ConnectivityManager.TETHERING_BLUETOOTH:
+                        disableBtTethering();
+                        break;
+                    case ConnectivityManager.TETHERING_USB:
+                        disableUsbTethering();
+                        break;
                 }
             }
+            fireCallbacksForType(checkType, result);
+
+            if (++mCurrentTypeIndex >= mCurrentTethers.size()) {
+                // We are done with all checks, time to die.
+                stopSelf();
+            } else {
+                // Start the next check in our list.
+                startProvisioning(mCurrentTypeIndex);
+            }
         }
     };
 
@@ -399,8 +429,7 @@
 
     /**
      * A static helper class used for tests. UsageStatsManager cannot be mocked out because
-     * it's marked final. Static method SubscriptionManager#getResourcesForSubId also cannot
-     * be mocked. This class can be mocked out instead.
+     * it's marked final. This class can be mocked out instead.
      */
     @VisibleForTesting
     public static class TetherServiceWrapper {
@@ -419,10 +448,4 @@
             return SubscriptionManager.getDefaultDataSubscriptionId();
         }
     }
-
-    @VisibleForTesting
-    Resources getResourceForDefaultDataSubId() {
-        final int subId = getTetherServiceWrapper().getDefaultDataSubscriptionId();
-        return Utils.getResourcesForSubId(this, subId);
-    }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherApBandPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherApBandPreferenceController.java
index a03e822..3e4bde0 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherApBandPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherApBandPreferenceController.java
@@ -18,7 +18,7 @@
 
 import android.content.Context;
 import android.content.res.Resources;
-import android.net.wifi.WifiConfiguration;
+import android.net.wifi.SoftApConfiguration;
 import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
@@ -34,33 +34,32 @@
 
     private String[] mBandEntries;
     private String[] mBandSummaries;
-    private int mBandIndex;
-    private boolean isDualMode;
+    private int mBand;
 
     public WifiTetherApBandPreferenceController(Context context,
             OnTetherConfigUpdateListener listener) {
         super(context, listener);
-        isDualMode = mWifiManager.isDualModeSupported();
         updatePreferenceEntries();
     }
 
     @Override
     public void updateDisplay() {
-        final WifiConfiguration config = mWifiManager.getWifiApConfiguration();
+        final SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
         if (config == null) {
-            mBandIndex = 0;
-            Log.d(TAG, "Updating band index to 0 because no config");
+            mBand = SoftApConfiguration.BAND_2GHZ;
+            Log.d(TAG, "Updating band to 2GHz because no config");
         } else if (is5GhzBandSupported()) {
-            mBandIndex = validateSelection(config.apBand);
-            Log.d(TAG, "Updating band index to " + mBandIndex);
+            mBand = validateSelection(config.getBand());
+            Log.d(TAG, "Updating band to " + mBand);
         } else {
-            config.apBand = 0;
-            mWifiManager.setWifiApConfiguration(config);
-            mBandIndex = config.apBand;
-            Log.d(TAG, "5Ghz not supported, updating band index to " + mBandIndex);
+            SoftApConfiguration newConfig = new SoftApConfiguration.Builder(config)
+                    .setBand(SoftApConfiguration.BAND_2GHZ)
+                    .build();
+            mWifiManager.setSoftApConfiguration(newConfig);
+            mBand = newConfig.getBand();
+            Log.d(TAG, "5Ghz not supported, updating band to " + mBand);
         }
-        ListPreference preference =
-                (ListPreference) mPreference;
+        ListPreference preference = (ListPreference) mPreference;
         preference.setEntries(mBandSummaries);
         preference.setEntryValues(mBandEntries);
 
@@ -68,16 +67,23 @@
             preference.setEnabled(false);
             preference.setSummary(R.string.wifi_ap_choose_2G);
         } else {
-            preference.setValue(Integer.toString(config.apBand));
+            preference.setValue(Integer.toString(config.getBand()));
             preference.setSummary(getConfigSummary());
         }
     }
 
     String getConfigSummary() {
-        if (mBandIndex == WifiConfiguration.AP_BAND_ANY) {
-           return mContext.getString(R.string.wifi_ap_prefer_5G);
+        switch (mBand) {
+            case SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ:
+                return mContext.getString(R.string.wifi_ap_prefer_5G);
+            case SoftApConfiguration.BAND_2GHZ:
+                return mBandSummaries[0];
+            case SoftApConfiguration.BAND_5GHZ:
+                return mBandSummaries[1];
+            default:
+                Log.e(TAG, "Unknown band: " + mBand);
+                return mContext.getString(R.string.wifi_ap_prefer_5G);
         }
-        return mBandSummaries[mBandIndex];
     }
 
     @Override
@@ -87,27 +93,22 @@
 
     @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
-        mBandIndex = validateSelection(Integer.parseInt((String) newValue));
-        Log.d(TAG, "Band preference changed, updating band index to " + mBandIndex);
+        mBand = validateSelection(Integer.parseInt((String) newValue));
+        Log.d(TAG, "Band preference changed, updating band to " + mBand);
         preference.setSummary(getConfigSummary());
         mListener.onTetherConfigUpdated();
         return true;
     }
 
     private int validateSelection(int band) {
-        // Reset the band to 2.4 GHz if we get a weird config back to avoid a crash.
-        final boolean isDualMode = mWifiManager.isDualModeSupported();
-
         // unsupported states:
-        // 1: no dual mode means we can't have AP_BAND_ANY - default to 5GHZ
-        // 2: no 5 GHZ support means we can't have AP_BAND_5GHZ - default to 2GHZ
-        // 3: With Dual mode support we can't have AP_BAND_5GHZ - default to ANY
-        if (!isDualMode && WifiConfiguration.AP_BAND_ANY == band) {
-            return WifiConfiguration.AP_BAND_5GHZ;
-        } else if (!is5GhzBandSupported() && WifiConfiguration.AP_BAND_5GHZ == band) {
-            return WifiConfiguration.AP_BAND_2GHZ;
-        } else if (isDualMode && WifiConfiguration.AP_BAND_5GHZ == band) {
-            return WifiConfiguration.AP_BAND_ANY;
+        // 1: BAND_5GHZ only - include 2GHZ since some of countries doesn't support 5G hotspot
+        // 2: no 5 GHZ support means we can't have BAND_5GHZ - default to 2GHZ
+        if (SoftApConfiguration.BAND_5GHZ == band) {
+            if (!is5GhzBandSupported()) {
+                return SoftApConfiguration.BAND_2GHZ;
+            }
+            return SoftApConfiguration.BAND_5GHZ | SoftApConfiguration.BAND_2GHZ;
         }
 
         return band;
@@ -116,26 +117,18 @@
     @VisibleForTesting
     void updatePreferenceEntries() {
         Resources res = mContext.getResources();
-        int entriesRes = R.array.wifi_ap_band_config_full;
-        int summariesRes = R.array.wifi_ap_band_summary_full;
-        // change the list options if this is a dual mode device
-        if (isDualMode) {
-            entriesRes = R.array.wifi_ap_band_dual_mode;
-            summariesRes = R.array.wifi_ap_band_dual_mode_summary;
-        }
+        int entriesRes = R.array.wifi_ap_band;
+        int summariesRes = R.array.wifi_ap_band_summary;
         mBandEntries = res.getStringArray(entriesRes);
         mBandSummaries = res.getStringArray(summariesRes);
     }
 
     private boolean is5GhzBandSupported() {
         final String countryCode = mWifiManager.getCountryCode();
-        if (!mWifiManager.isDualBandSupported() || countryCode == null) {
-            return false;
-        }
-        return true;
+        return mWifiManager.is5GHzBandSupported() && countryCode != null;
     }
 
-    public int getBandIndex() {
-        return mBandIndex;
+    public int getBand() {
+        return mBand;
     }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherPasswordPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherPasswordPreferenceController.java
index 82d7e51..7ffda79 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherPasswordPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherPasswordPreferenceController.java
@@ -17,7 +17,7 @@
 package com.android.car.developeroptions.wifi.tether;
 
 import android.content.Context;
-import android.net.wifi.WifiConfiguration;
+import android.net.wifi.SoftApConfiguration;
 import android.text.TextUtils;
 
 import androidx.preference.EditTextPreference;
@@ -48,12 +48,13 @@
 
     @Override
     public void updateDisplay() {
-        final WifiConfiguration config = mWifiManager.getWifiApConfiguration();
-        if (config == null || (config.getAuthType() == WifiConfiguration.KeyMgmt.WPA2_PSK
-                && TextUtils.isEmpty(config.preSharedKey))) {
+        final SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
+        if (config == null || (
+                config.getSecurityType() == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK
+                && TextUtils.isEmpty(config.getPassphrase()))) {
             mPassword = generateRandomPassword();
         } else {
-            mPassword = config.preSharedKey;
+            mPassword = config.getPassphrase();
         }
         ((ValidatedEditTextPreference) mPreference).setValidator(this);
         ((ValidatedEditTextPreference) mPreference).setIsPassword(true);
@@ -79,8 +80,8 @@
      */
     public String getPasswordValidated(int securityType) {
         // don't actually overwrite unless we get a new config in case it was accidentally toggled.
-        if (securityType == WifiConfiguration.KeyMgmt.NONE) {
-            return "";
+        if (securityType == SoftApConfiguration.SECURITY_TYPE_OPEN) {
+            return null;
         } else if (!isTextValid(mPassword)) {
             mPassword = generateRandomPassword();
             updatePasswordDisplay((EditTextPreference) mPreference);
@@ -89,7 +90,7 @@
     }
 
     public void updateVisibility(int securityType) {
-        mPreference.setVisible(securityType != WifiConfiguration.KeyMgmt.NONE);
+        mPreference.setVisible(securityType != SoftApConfiguration.SECURITY_TYPE_OPEN);
     }
 
     @Override
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherPreferenceController.java
index 3ce80a5..66ee41a 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherPreferenceController.java
@@ -16,15 +16,14 @@
 
 package com.android.car.developeroptions.wifi.tether;
 
-import android.content.BroadcastReceiver;
+import android.annotation.NonNull;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.net.ConnectivityManager;
-import android.net.wifi.WifiConfiguration;
+import android.net.wifi.SoftApConfiguration;
+import android.net.wifi.WifiClient;
 import android.net.wifi.WifiManager;
-import android.provider.Settings;
 import android.text.BidiFormatter;
+import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.Preference;
@@ -39,9 +38,12 @@
 import com.android.settingslib.core.lifecycle.events.OnStart;
 import com.android.settingslib.core.lifecycle.events.OnStop;
 
+import java.util.List;
+
 public class WifiTetherPreferenceController extends AbstractPreferenceController
         implements PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop {
 
+    private static final String TAG = "WifiTetherPreferenceController";
     private static final String WIFI_TETHER_SETTINGS = "wifi_tether";
 
     private final ConnectivityManager mConnectivityManager;
@@ -128,13 +130,14 @@
                     }
 
                     @Override
-                    public void onNumClientsChanged(int numClients) {
+                    public void onConnectedClientsChanged(List<WifiClient> clients) {
                         if (mPreference != null
                                 && mSoftApState == WifiManager.WIFI_AP_STATE_ENABLED) {
                             // Only show the number of clients when state is on
+                            int numberOfClients = clients.size();
                             mPreference.setSummary(mContext.getResources().getQuantityString(
-                                    R.plurals.wifi_tether_connected_summary, numClients,
-                                    numClients));
+                                    R.plurals.wifi_tether_connected_summary, numberOfClients,
+                                    numberOfClients));
                         }
                     }
                 });
@@ -147,8 +150,7 @@
                 mPreference.setSummary(R.string.wifi_tether_starting);
                 break;
             case WifiManager.WIFI_AP_STATE_ENABLED:
-                WifiConfiguration wifiConfig = mWifiManager.getWifiApConfiguration();
-                updateConfigSummary(wifiConfig);
+                updateConfigSummary(mWifiManager.getSoftApConfiguration());
                 break;
             case WifiManager.WIFI_AP_STATE_DISABLING:
                 mPreference.setSummary(R.string.wifi_tether_stopping);
@@ -165,12 +167,13 @@
         }
     }
 
-    private void updateConfigSummary(WifiConfiguration wifiConfig) {
-        final String s = mContext.getString(
-                com.android.internal.R.string.wifi_tether_configure_ssid_default);
-
+    private void updateConfigSummary(@NonNull SoftApConfiguration softApConfig) {
+        if (softApConfig == null) {
+            // should never happen.
+            Log.e(TAG, "Ap config null unexpectedly");
+            return;
+        }
         mPreference.setSummary(mContext.getString(R.string.wifi_tether_enabled_subtext,
-                BidiFormatter.getInstance().unicodeWrap(
-                        (wifiConfig == null) ? s : wifiConfig.SSID)));
+                BidiFormatter.getInstance().unicodeWrap(softApConfig.getSsid())));
     }
 }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherSSIDPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherSSIDPreferenceController.java
index 14b637c..d64f646 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherSSIDPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherSSIDPreferenceController.java
@@ -18,15 +18,13 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.net.wifi.WifiConfiguration;
+import android.net.wifi.SoftApConfiguration;
 import android.util.Log;
-import android.view.View;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.EditTextPreference;
 import androidx.preference.Preference;
 
-import com.android.car.developeroptions.R;
 import com.android.car.developeroptions.widget.ValidatedEditTextPreference;
 import com.android.car.developeroptions.wifi.dpp.WifiDppUtils;
 
@@ -54,17 +52,16 @@
 
     @Override
     public void updateDisplay() {
-        final WifiConfiguration config = mWifiManager.getWifiApConfiguration();
+        final SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
         if (config != null) {
-            mSSID = config.SSID;
+            mSSID = config.getSsid();
         } else {
             mSSID = DEFAULT_SSID;
         }
         ((ValidatedEditTextPreference) mPreference).setValidator(this);
 
         if (mWifiManager.isWifiApEnabled() && config != null) {
-            final Intent intent = WifiDppUtils.getHotspotConfiguratorIntentOrNull(mContext,
-                    mWifiManager, config);
+            final Intent intent = WifiDppUtils.getHotspotConfiguratorIntentOrNull(mContext, config);
 
             if (intent == null) {
                 Log.e(TAG, "Invalid security to share hotspot");
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherSecurityPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherSecurityPreferenceController.java
index 4ac12d2..6b20d52 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherSecurityPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherSecurityPreferenceController.java
@@ -1,7 +1,7 @@
 package com.android.car.developeroptions.wifi.tether;
 
 import android.content.Context;
-import android.net.wifi.WifiConfiguration;
+import android.net.wifi.SoftApConfiguration;
 
 import androidx.preference.ListPreference;
 import androidx.preference.Preference;
@@ -28,12 +28,11 @@
 
     @Override
     public void updateDisplay() {
-        final WifiConfiguration config = mWifiManager.getWifiApConfiguration();
-        if (config != null && config.getAuthType() == WifiConfiguration.KeyMgmt.NONE) {
-            mSecurityValue = WifiConfiguration.KeyMgmt.NONE;
-
+        final SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
+        if (config != null && config.getSecurityType() == SoftApConfiguration.SECURITY_TYPE_OPEN) {
+            mSecurityValue = SoftApConfiguration.SECURITY_TYPE_OPEN;
         } else {
-            mSecurityValue = WifiConfiguration.KeyMgmt.WPA2_PSK;
+            mSecurityValue = SoftApConfiguration.SECURITY_TYPE_WPA2_PSK;
         }
 
         final ListPreference preference = (ListPreference) mPreference;
@@ -54,7 +53,7 @@
     }
 
     private String getSummaryForSecurityType(int securityType) {
-        if (securityType == WifiConfiguration.KeyMgmt.NONE) {
+        if (securityType == SoftApConfiguration.SECURITY_TYPE_OPEN) {
             return mSecurityEntries[1];
         }
         // WPA2 PSK
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherSettings.java
index 1071563..5bbcd8d 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherSettings.java
@@ -24,7 +24,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.net.wifi.WifiConfiguration;
+import android.net.wifi.SoftApConfiguration;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
 import android.os.UserManager;
@@ -186,10 +186,10 @@
 
     @Override
     public void onTetherConfigUpdated() {
-        final WifiConfiguration config = buildNewConfig();
-        mPasswordPreferenceController.updateVisibility(config.getAuthType());
+        final SoftApConfiguration config = buildNewConfig();
+        mPasswordPreferenceController.updateVisibility(config.getSecurityType());
 
-        /**
+        /*
          * if soft AP is stopped, bring up
          * else restart with new config
          * TODO: update config on a running access point when framework support is added
@@ -200,19 +200,18 @@
             mRestartWifiApAfterConfigChange = true;
             mSwitchBarController.stopTether();
         }
-        mWifiManager.setWifiApConfiguration(config);
+        mWifiManager.setSoftApConfiguration(config);
     }
 
-    private WifiConfiguration buildNewConfig() {
-        final WifiConfiguration config = new WifiConfiguration();
+    private SoftApConfiguration buildNewConfig() {
         final int securityType = mSecurityPreferenceController.getSecurityType();
 
-        config.SSID = mSSIDPreferenceController.getSSID();
-        config.allowedKeyManagement.set(securityType);
-        config.preSharedKey = mPasswordPreferenceController.getPasswordValidated(securityType);
-        config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
-        config.apBand = mApBandPreferenceController.getBandIndex();
-        return config;
+        return new SoftApConfiguration.Builder()
+                .setSsid(mSSIDPreferenceController.getSSID())
+                .setPassphrase(mPasswordPreferenceController.getPasswordValidated(securityType),
+                        securityType)
+                .setBand(mApBandPreferenceController.getBand())
+                .build();
     }
 
     private void startTether() {
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherSoftApManager.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherSoftApManager.java
index f31a64f..fa4fc0b 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherSoftApManager.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherSoftApManager.java
@@ -1,7 +1,11 @@
 package com.android.car.developeroptions.wifi.tether;
 
+import android.net.wifi.WifiClient;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
+import android.os.HandlerExecutor;
+
+import java.util.List;
 
 /**
  * Wrapper for {@link android.net.wifi.WifiManager.SoftApCallback} to pass the robo test
@@ -18,8 +22,8 @@
         }
 
         @Override
-        public void onNumClientsChanged(int numClients) {
-            mWifiTetherSoftApCallback.onNumClientsChanged(numClients);
+        public void onConnectedClientsChanged(List<WifiClient> clients) {
+            mWifiTetherSoftApCallback.onConnectedClientsChanged(clients);
         }
     };
     private Handler mHandler;
@@ -32,7 +36,7 @@
     }
 
     public void registerSoftApCallback() {
-        mWifiManager.registerSoftApCallback(mSoftApCallback, mHandler);
+        mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
     }
 
     public void unRegisterSoftApCallback() {
@@ -42,6 +46,11 @@
     public interface WifiTetherSoftApCallback {
         void onStateChanged(int state, int failureReason);
 
-        void onNumClientsChanged(int numClients);
+        /**
+         * Called when the connected clients to soft AP changes.
+         *
+         * @param clients the currently connected clients
+         */
+        void onConnectedClientsChanged(List<WifiClient> clients);
     }
 }
diff --git a/tests/CarLibTests/Android.bp b/tests/CarLibTests/Android.bp
new file mode 100644
index 0000000..242ae83
--- /dev/null
+++ b/tests/CarLibTests/Android.bp
@@ -0,0 +1,44 @@
+// 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.
+
+android_app {
+    name: "CarLibTestApp",
+    platform_apis: true,
+}
+
+//###########################################################
+// Robolectric test target for testing car test lib classes #
+//###########################################################
+android_robolectric_test {
+    enabled: true,
+
+    name: "CarLibTests",
+
+    srcs: ["src/**/*.java"],
+
+    java_resource_dirs: ["config"],
+
+    libs: [
+        "Robolectric_all-target",
+        "robolectric_android-all-stub",
+        "mockito-robolectric-prebuilt",
+        "truth-prebuilt",
+        "androidx.test.core",
+        "android.car.testapi",
+        "androidx.test.rules",
+    ],
+
+    instrumentation_for: "CarLibTestApp",
+
+}
diff --git a/tests/CarLibTests/Android.mk b/tests/CarLibTests/Android.mk
deleted file mode 100644
index bf86890..0000000
--- a/tests/CarLibTests/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (C) 2019 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CarLibTests
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_JAVA_LIBRARIES := \
-    android.car \
-    android.test.runner \
-    android.test.base \
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    junit \
-    android.car.testapi \
-    androidx.test.rules \
-    androidx.test.core \
-    mockito-target-minus-junit4 \
-    com.android.car.test.utils \
-    truth-prebuilt \
-
-include $(BUILD_PACKAGE)
diff --git a/tests/CarLibTests/AndroidManifest.xml b/tests/CarLibTests/AndroidManifest.xml
index 03379c7..df64d87 100644
--- a/tests/CarLibTests/AndroidManifest.xml
+++ b/tests/CarLibTests/AndroidManifest.xml
@@ -16,13 +16,5 @@
   -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="android.car.testapi.tests">
-
-  <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-                   android:targetPackage="android.car.testapi.tests"
-                   android:label="Unit Tests for Car APIs"/>
-
-  <application>
-      <uses-library android:name="android.test.runner" />
-  </application>
-
+    <application/>
 </manifest>
diff --git a/tests/CarLibTests/config/robolectric.properties b/tests/CarLibTests/config/robolectric.properties
new file mode 100644
index 0000000..c0a0ca2
--- /dev/null
+++ b/tests/CarLibTests/config/robolectric.properties
@@ -0,0 +1,15 @@
+# Copyright (C) 2019 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+sdk=NEWEST_SDK
diff --git a/tests/CarLibTests/src/android/car/CarAppFocusManagerTest.java b/tests/CarLibTests/src/android/car/CarAppFocusManagerTest.java
new file mode 100644
index 0000000..b3c794e
--- /dev/null
+++ b/tests/CarLibTests/src/android/car/CarAppFocusManagerTest.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.robolectric.Shadows.shadowOf;
+
+import android.app.Application;
+import android.car.CarAppFocusManager.OnAppFocusChangedListener;
+import android.car.CarAppFocusManager.OnAppFocusOwnershipCallback;
+import android.car.testapi.CarAppFocusController;
+import android.car.testapi.FakeCar;
+import android.os.Looper;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.internal.DoNotInstrument;
+import org.robolectric.shadows.ShadowBinder;
+
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
+public class CarAppFocusManagerTest {
+    @Rule
+    public MockitoRule rule = MockitoJUnit.rule();
+
+    private Application mContext;
+
+    private FakeCar mFakeCar;
+    private CarAppFocusManager mCarAppFocusManager;
+    private CarAppFocusController mCarAppFocusController;
+    private Looper mAppFocusServiceLooper;
+
+    private static final int APP1_UID = 1041;
+    private static final int APP1_PID = 1043;
+    private static final int APP2_UID = 1072;
+    private static final int APP2_PID = 1074;
+    private static final int APP3_UID = 1111;
+    private static final int APP3_PID = 2222;
+
+    @Mock OnAppFocusOwnershipCallback mApp1Callback;
+    @Mock OnAppFocusChangedListener mApp1Listener;
+    @Mock OnAppFocusOwnershipCallback mApp2Callback;
+    @Mock OnAppFocusChangedListener mApp2Listener;
+    @Mock OnAppFocusOwnershipCallback mApp3Callback;
+    @Mock OnAppFocusChangedListener mApp3Listener;
+
+    @Before
+    public void setUp() {
+        ShadowBinder.reset();
+        mContext = ApplicationProvider.getApplicationContext();
+        mFakeCar = FakeCar.createFakeCar(mContext);
+        mCarAppFocusManager =
+                (CarAppFocusManager) mFakeCar.getCar().getCarManager(Car.APP_FOCUS_SERVICE);
+        mCarAppFocusController = mFakeCar.getAppFocusController();
+        mAppFocusServiceLooper = mCarAppFocusController.getLooper();
+    }
+
+    @Test
+    public void defaultState_noFocusesHeld() {
+        assertThat(mCarAppFocusManager.getActiveAppTypes()).isEmpty();
+    }
+
+    @Test
+    public void requestNavFocus_noCurrentFocus_requestShouldSucceed() {
+        int result = mCarAppFocusManager.requestAppFocus(
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, mApp1Callback);
+        assertThat(result).isEqualTo(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED);
+    }
+
+    @Test
+    public void requestNavFocus_noCurrentFocus_callbackIsRun() {
+        mCarAppFocusManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION,
+                mApp1Callback);
+        shadowOf(mAppFocusServiceLooper).runToEndOfTasks();
+
+        verify(mApp1Callback)
+                .onAppFocusOwnershipGranted(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+    }
+
+    @Test
+    public void requestNavFocus_noCurrentFocus_holdsOwnership() {
+        mCarAppFocusManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION,
+                mApp1Callback);
+
+        assertThat(
+                mCarAppFocusManager
+                        .isOwningFocus(mApp1Callback, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION))
+                .isTrue();
+    }
+
+    @Test
+    public void requestNavFocus_noCurrentFocus_onlyNavActive() {
+        mCarAppFocusManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION,
+                mApp1Callback);
+
+        assertThat(mCarAppFocusManager.getActiveAppTypes())
+                .isEqualTo(new int[] {CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION});
+    }
+
+    private void setCallingApp(int uid, int pid) {
+        ShadowBinder.setCallingUid(uid);
+        ShadowBinder.setCallingPid(pid);
+    }
+
+    private void app2GainsFocus_app1BroughtToForeground() {
+        setCallingApp(APP2_UID, APP2_PID);
+        mCarAppFocusManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION,
+                mApp2Callback);
+        mCarAppFocusController.setForegroundUid(APP1_UID);
+        mCarAppFocusController.setForegroundPid(APP1_PID);
+        setCallingApp(APP2_UID, APP1_PID);
+    }
+
+    @Test
+    public void requestNavFocus_currentOwnerInBackground_requestShouldSucceed() {
+        app2GainsFocus_app1BroughtToForeground();
+
+        assertThat(
+                mCarAppFocusManager
+                        .requestAppFocus(
+                                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, mApp1Callback))
+                .isEqualTo(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED);
+    }
+
+    @Test
+    public void requestNavFocus_currentOwnerInBackground_callbackIsRun() {
+        app2GainsFocus_app1BroughtToForeground();
+        mCarAppFocusManager
+                .requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, mApp1Callback);
+        shadowOf(mAppFocusServiceLooper).runToEndOfTasks();
+
+        verify(mApp1Callback)
+                .onAppFocusOwnershipGranted(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+    }
+
+    @Test
+    public void requestNavFocus_currentOwnerInBackground_holdsOwnership() {
+        app2GainsFocus_app1BroughtToForeground();
+        mCarAppFocusManager
+                .requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, mApp1Callback);
+
+        assertThat(
+                mCarAppFocusManager
+                        .isOwningFocus(mApp1Callback, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION))
+                .isTrue();
+    }
+
+    @Test
+    public void requestNavFocus_currentOwnerInForeground_requestFails() {
+        setCallingApp(APP2_UID, APP2_PID);
+        mCarAppFocusController.setForegroundUid(APP2_UID);
+        mCarAppFocusController.setForegroundPid(APP2_PID);
+        mCarAppFocusManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION,
+                mApp2Callback);
+        setCallingApp(APP1_UID, APP1_PID);
+
+        assertThat(
+                mCarAppFocusManager
+                        .requestAppFocus(
+                                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, mApp1Callback))
+                .isEqualTo(CarAppFocusManager.APP_FOCUS_REQUEST_FAILED);
+    }
+
+    @Test
+    public void requestAppFocus_callingAppNotified() {
+        setCallingApp(APP1_UID, APP1_PID);
+        mCarAppFocusManager
+                .addFocusListener(mApp1Listener, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        mCarAppFocusManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION,
+                mApp1Callback);
+        shadowOf(mAppFocusServiceLooper).runToEndOfTasks();
+
+        verify(mApp1Listener)
+                .onAppFocusChanged(eq(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION), anyBoolean());
+    }
+
+    @Test
+    public void requestAppFocus_otherAppNotified() {
+        setCallingApp(APP2_UID, APP2_PID);
+        mCarAppFocusManager
+                .addFocusListener(mApp2Listener, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        setCallingApp(APP1_UID, APP1_PID);
+        mCarAppFocusManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION,
+                mApp1Callback);
+        shadowOf(mAppFocusServiceLooper).runToEndOfTasks();
+
+        verify(mApp2Listener)
+                .onAppFocusChanged(eq(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION), eq(true));
+    }
+
+    @Test
+    public void requestAppFocus_focusLost_otherAppRequest_callbackRun() {
+        setCallingApp(APP2_UID, APP2_PID);
+        mCarAppFocusManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION,
+                mApp2Callback);
+        setCallingApp(APP1_UID, APP1_PID);
+        mCarAppFocusManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION,
+                mApp1Callback);
+        shadowOf(mAppFocusServiceLooper).runToEndOfTasks();
+
+        verify(mApp2Callback)
+                .onAppFocusOwnershipLost(eq(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION));
+    }
+
+    @Test
+    public void abandonAppFocus_callingAppNotified() {
+        setCallingApp(APP1_UID, APP1_PID);
+        mCarAppFocusManager
+                .addFocusListener(mApp1Listener, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        mCarAppFocusManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION,
+                mApp1Callback);
+        mCarAppFocusManager
+                .abandonAppFocus(mApp1Callback, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        shadowOf(mAppFocusServiceLooper).runToEndOfTasks();
+
+        verify(mApp1Listener)
+                .onAppFocusChanged(eq(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION), eq(false));
+    }
+
+    @Test
+    public void abandonAppFocus_otherAppNotified() {
+        setCallingApp(APP2_UID, APP2_PID);
+        mCarAppFocusManager
+                .addFocusListener(mApp2Listener, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        setCallingApp(APP1_UID, APP1_PID);
+        mCarAppFocusManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION,
+                mApp1Callback);
+        mCarAppFocusManager
+                .abandonAppFocus(mApp1Callback, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        shadowOf(mAppFocusServiceLooper).runToEndOfTasks();
+
+        verify(mApp2Listener)
+                .onAppFocusChanged(eq(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION), eq(false));
+    }
+
+    @Test
+    public void gainAppFocus_multipleListenersRegistered_bothUnownedTrigger() {
+        setCallingApp(APP1_UID, APP1_PID);
+        mCarAppFocusManager
+                .addFocusListener(mApp1Listener, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        setCallingApp(APP2_UID, APP2_PID);
+        mCarAppFocusManager
+                .addFocusListener(mApp2Listener, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        setCallingApp(APP3_UID, APP3_PID);
+        mCarAppFocusManager
+                .addFocusListener(mApp3Listener, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        mCarAppFocusManager
+                .requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, mApp3Callback);
+        shadowOf(mAppFocusServiceLooper).runToEndOfTasks();
+
+        verify(mApp1Listener)
+                .onAppFocusChanged(eq(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION), eq(true));
+        verify(mApp2Listener)
+                .onAppFocusChanged(eq(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION), eq(true));
+        verify(mApp3Listener)
+                .onAppFocusChanged(eq(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION), eq(true));
+    }
+}
diff --git a/tests/CarLibTests/src/android/car/CarNavigationStatusManagerTest.java b/tests/CarLibTests/src/android/car/CarNavigationStatusManagerTest.java
new file mode 100644
index 0000000..a4cb5fb
--- /dev/null
+++ b/tests/CarLibTests/src/android/car/CarNavigationStatusManagerTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.navigation.CarNavigationInstrumentCluster;
+import android.car.navigation.CarNavigationStatusManager;
+import android.car.testapi.CarNavigationStatusController;
+import android.car.testapi.FakeCar;
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.internal.DoNotInstrument;
+
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
+public class CarNavigationStatusManagerTest {
+    private Context mContext;
+    private FakeCar mFakeCar;
+    private Car mCar;
+    private CarNavigationStatusManager mCarNavigationStatusManager;
+    private CarNavigationStatusController mCarNavigationStatusController;
+
+    @Before
+    public void setUp() {
+        mContext = ApplicationProvider.getApplicationContext();
+        mFakeCar = FakeCar.createFakeCar(mContext);
+        mCar = mFakeCar.getCar();
+        mCarNavigationStatusManager =
+                (CarNavigationStatusManager) mCar.getCarManager(Car.CAR_NAVIGATION_SERVICE);
+        mCarNavigationStatusController = mFakeCar.getCarNavigationStatusController();
+
+        // There should be no value after set up of the service.
+        assertThat(mCarNavigationStatusController.getCurrentNavState()).isNull();
+    }
+
+    @Test
+    public void onNavigationStateChanged_bundleIsReceived() {
+        Bundle bundle = new Bundle();
+        mCarNavigationStatusManager.sendNavigationStateChange(bundle);
+
+        assertThat(mCarNavigationStatusController.getCurrentNavState()).isEqualTo(bundle);
+    }
+
+    @Test
+    public void getInstrumentClusterInfo_returnsImageCodeCluster() {
+        // default cluster should be an image code cluster (no custom images)
+        assertThat(mCarNavigationStatusManager.getInstrumentClusterInfo().getType()).isEqualTo(
+                CarNavigationInstrumentCluster.CLUSTER_TYPE_IMAGE_CODES_ONLY);
+    }
+
+    @Test
+    public void setImageCodeClusterInfo_returnsImageCodeCluster() {
+        mCarNavigationStatusController.setImageCodeClusterInfo(42);
+
+        CarNavigationInstrumentCluster instrumentCluster =
+                mCarNavigationStatusManager.getInstrumentClusterInfo();
+
+        assertThat(instrumentCluster.getType())
+                .isEqualTo(CarNavigationInstrumentCluster.CLUSTER_TYPE_IMAGE_CODES_ONLY);
+        assertThat(instrumentCluster.getMinIntervalMillis()).isEqualTo(42);
+    }
+
+    @Test
+    public void setCustomImageClusterInfo_returnsCustomImageCluster() {
+        mCarNavigationStatusController.setCustomImageClusterInfo(
+                100,
+                1024,
+                768,
+                32);
+
+        CarNavigationInstrumentCluster instrumentCluster =
+                mCarNavigationStatusManager.getInstrumentClusterInfo();
+
+        assertThat(instrumentCluster.getType())
+                .isEqualTo(CarNavigationInstrumentCluster.CLUSTER_TYPE_CUSTOM_IMAGES_SUPPORTED);
+        assertThat(instrumentCluster.getMinIntervalMillis()).isEqualTo(100);
+        assertThat(instrumentCluster.getImageWidth()).isEqualTo(1024);
+        assertThat(instrumentCluster.getImageHeight()).isEqualTo(768);
+        assertThat(instrumentCluster.getImageColorDepthBits()).isEqualTo(32);
+    }
+}
diff --git a/tests/CarLibTests/src/android/car/CarProjectionManagerTest.java b/tests/CarLibTests/src/android/car/CarProjectionManagerTest.java
index 970cac9..c822fba 100644
--- a/tests/CarLibTests/src/android/car/CarProjectionManagerTest.java
+++ b/tests/CarLibTests/src/android/car/CarProjectionManagerTest.java
@@ -34,11 +34,11 @@
 import android.car.testapi.FakeCar;
 import android.content.Context;
 import android.content.Intent;
-import android.net.wifi.WifiConfiguration;
+import android.net.MacAddress;
+import android.net.wifi.SoftApConfiguration;
 import android.util.ArraySet;
 
 import androidx.test.core.app.ApplicationProvider;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -50,6 +50,8 @@
 import org.mockito.Spy;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.internal.DoNotInstrument;
 
 import java.util.Arrays;
 import java.util.Collections;
@@ -58,7 +60,8 @@
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 
-@RunWith(AndroidJUnit4.class)
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
 public class CarProjectionManagerTest {
     @Rule
     public MockitoRule rule = MockitoJUnit.rule();
@@ -91,7 +94,7 @@
 
     @Test
     public void startAp_fail() throws InterruptedException {
-        mController.setWifiConfiguration(null);
+        mController.setSoftApConfiguration(null);
 
         mProjectionManager.startProjectionAccessPoint(mApCallback);
         mApCallback.mFailed.await(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
@@ -100,16 +103,16 @@
 
     @Test
     public void startAp_success() throws InterruptedException {
-        WifiConfiguration wifiConfiguration = new WifiConfiguration();
-        wifiConfiguration.SSID = "Hello";
-        wifiConfiguration.BSSID = "AA:BB:CC:CC:DD:EE";
-        wifiConfiguration.preSharedKey = "password";
-
-        mController.setWifiConfiguration(wifiConfiguration);
+        SoftApConfiguration config = new SoftApConfiguration.Builder()
+                .setSsid("Hello")
+                .setBssid(MacAddress.fromString("AA:BB:CC:CC:DD:EE"))
+                .setPassphrase("password", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
+                .build();
+        mController.setSoftApConfiguration(config);
 
         mProjectionManager.startProjectionAccessPoint(mApCallback);
         mApCallback.mStarted.await(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        assertThat(mApCallback.mWifiConfiguration).isEqualTo(wifiConfiguration);
+        assertThat(mApCallback.mSoftApConfiguration).isEqualTo(config);
     }
 
     @Test
@@ -256,11 +259,11 @@
         CountDownLatch mStarted = new CountDownLatch(1);
         CountDownLatch mFailed = new CountDownLatch(1);
         int mFailureReason = -1;
-        WifiConfiguration mWifiConfiguration;
+        SoftApConfiguration mSoftApConfiguration;
 
         @Override
-        public void onStarted(WifiConfiguration wifiConfiguration) {
-            mWifiConfiguration = wifiConfiguration;
+        public void onStarted(SoftApConfiguration softApConfiguration) {
+            mSoftApConfiguration = softApConfiguration;
             mStarted.countDown();
         }
 
diff --git a/tests/CarLibTests/src/android/car/CarPropertyManagerTest.java b/tests/CarLibTests/src/android/car/CarPropertyManagerTest.java
index bc322c3..4d87c05 100644
--- a/tests/CarLibTests/src/android/car/CarPropertyManagerTest.java
+++ b/tests/CarLibTests/src/android/car/CarPropertyManagerTest.java
@@ -26,7 +26,6 @@
 import android.car.testapi.FakeCar;
 
 import androidx.test.core.app.ApplicationProvider;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -34,8 +33,11 @@
 import org.junit.runner.RunWith;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.internal.DoNotInstrument;
 
-@RunWith(AndroidJUnit4.class)
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
 public class CarPropertyManagerTest {
     private static final int FAN_SPEED_VALUE = 42;
     private static final float TEMPERATURE_VALUE = 42.24f;
diff --git a/tests/CarLibTests/src/android/car/CarUxRestrictionsManagerTest.java b/tests/CarLibTests/src/android/car/CarUxRestrictionsManagerTest.java
new file mode 100644
index 0000000..9e67e4b
--- /dev/null
+++ b/tests/CarLibTests/src/android/car/CarUxRestrictionsManagerTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+
+import android.app.Application;
+import android.car.drivingstate.CarUxRestrictions;
+import android.car.drivingstate.CarUxRestrictionsManager;
+import android.car.drivingstate.CarUxRestrictionsManager.OnUxRestrictionsChangedListener;
+import android.car.testapi.CarUxRestrictionsController;
+import android.car.testapi.FakeCar;
+import android.os.RemoteException;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.internal.DoNotInstrument;
+
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
+public class CarUxRestrictionsManagerTest {
+    @Rule
+    public MockitoRule rule = MockitoJUnit.rule();
+
+    CarUxRestrictionsManager mCarUxRestrictionsManager;
+    CarUxRestrictionsController mCarUxRestrictionsController;
+
+    @Mock
+    OnUxRestrictionsChangedListener mListener;
+
+    @Before
+    public void setUp() {
+        Application context = ApplicationProvider.getApplicationContext();
+        FakeCar fakeCar = FakeCar.createFakeCar(context);
+        Car carApi = fakeCar.getCar();
+
+        mCarUxRestrictionsManager =
+                (CarUxRestrictionsManager) carApi.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);
+        mCarUxRestrictionsController = fakeCar.getCarUxRestrictionController();
+    }
+
+    @Test
+    public void getRestrictions_noRestrictionsSet_noRestrictionsPresent() {
+        assertThat(mCarUxRestrictionsManager.getCurrentCarUxRestrictions().getActiveRestrictions())
+                .isEqualTo(CarUxRestrictions.UX_RESTRICTIONS_BASELINE);
+    }
+
+    @Test
+    public void setUxRestrictions_restrictionsRegistered() throws RemoteException {
+        mCarUxRestrictionsController.setUxRestrictions(CarUxRestrictions.UX_RESTRICTIONS_NO_VIDEO);
+
+        assertThat(mCarUxRestrictionsManager.getCurrentCarUxRestrictions().getActiveRestrictions())
+                .isEqualTo(CarUxRestrictions.UX_RESTRICTIONS_NO_VIDEO);
+    }
+
+    @Test
+    public void clearUxRestrictions_restrictionsCleared() throws RemoteException {
+        mCarUxRestrictionsController
+                .setUxRestrictions(CarUxRestrictions.UX_RESTRICTIONS_FULLY_RESTRICTED);
+        mCarUxRestrictionsController.clearUxRestrictions();
+
+        assertThat(mCarUxRestrictionsManager.getCurrentCarUxRestrictions().getActiveRestrictions())
+                .isEqualTo(CarUxRestrictions.UX_RESTRICTIONS_BASELINE);
+    }
+
+    @Test
+    public void isListenerRegistered_noListenerSet_returnsFalse() {
+        assertThat(mCarUxRestrictionsController.isListenerRegistered()).isFalse();
+    }
+
+    @Test
+    public void isListenerRegistered_listenerSet_returnsTrue() {
+        mCarUxRestrictionsManager.registerListener(mListener);
+
+        assertThat(mCarUxRestrictionsController.isListenerRegistered()).isTrue();
+    }
+
+    @Test
+    public void setUxRestrictions_listenerRegistered_listenerTriggered() throws RemoteException {
+        mCarUxRestrictionsManager.registerListener(mListener);
+        mCarUxRestrictionsController
+                .setUxRestrictions(CarUxRestrictions.UX_RESTRICTIONS_NO_TEXT_MESSAGE);
+
+        verify(mListener).onUxRestrictionsChanged(any());
+    }
+}
+
diff --git a/tests/CarSecurityPermissionTest/Android.bp b/tests/CarSecurityPermissionTest/Android.bp
new file mode 100644
index 0000000..066ecc8
--- /dev/null
+++ b/tests/CarSecurityPermissionTest/Android.bp
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+android_test {
+    name: "CarSecurityPermissionTest",
+
+    srcs: ["src/**/*.java"],
+
+    libs: [
+        "android.car",
+        "android.test.runner",
+        "android.test.base",
+        "android.test.mock",
+    ],
+
+    static_libs: [
+        "androidx.test.core",
+        "androidx.test.ext.junit",
+        "androidx.test.rules",
+        "car-frameworks-service",
+        "compatibility-device-util-axt",
+        "mockito-target-minus-junit4",
+        "testng",
+        "truth-prebuilt",
+    ],
+
+    platform_apis: true,
+
+    certificate: "platform",
+}
\ No newline at end of file
diff --git a/tests/CarSecurityPermissionTest/AndroidManifest.xml b/tests/CarSecurityPermissionTest/AndroidManifest.xml
new file mode 100644
index 0000000..bb4d6cc
--- /dev/null
+++ b/tests/CarSecurityPermissionTest/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.car.securitypermissiontest">
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.car.securitypermissiontest"
+                     android:label="Security permission tests for Car APIs"/>
+    <application android:label="CarSecurityPermissionTest"
+                 android:debuggable="true">
+        <uses-library android:name="android.test.runner" />
+    </application>
+</manifest>
\ No newline at end of file
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/CarPermisisonTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/CarPermisisonTest.java
new file mode 100644
index 0000000..07f4310
--- /dev/null
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/CarPermisisonTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car;
+
+import static org.testng.Assert.assertThrows;
+
+import android.car.Car;
+import android.os.Handler;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * This class contains security permission tests for the {@link Car}'s system APIs.
+ */
+@RunWith(AndroidJUnit4.class)
+public class CarPermisisonTest {
+    private Car mCar = null;
+
+    @Before
+    public void setUp() throws Exception {
+        mCar = Car.createCar(
+                InstrumentationRegistry.getInstrumentation().getTargetContext(), (Handler) null);
+    }
+
+    @After
+    public void tearDown() {
+        mCar.disconnect();
+    }
+
+    @Test
+    public void testEnableFeaturePermission() throws Exception {
+        assertThrows(SecurityException.class, () -> mCar.enableFeature("some feature"));
+    }
+
+    @Test
+    public void testDisableFeaturePermission() throws Exception {
+        assertThrows(SecurityException.class, () -> mCar.disableFeature("some feature"));
+    }
+
+    @Test
+    public void testGetAllEnabledFeaturesPermission() throws Exception {
+        assertThrows(SecurityException.class, () -> mCar.getAllEnabledFeatures());
+    }
+
+    @Test
+    public void testGetAllPendingDisabledFeaturesPermission() throws Exception {
+        assertThrows(SecurityException.class, () -> mCar.getAllPendingDisabledFeatures());
+    }
+
+    @Test
+    public void testGetAllPendingEnabledFeaturesPermission() throws Exception {
+        assertThrows(SecurityException.class, () -> mCar.getAllPendingEnabledFeatures());
+    }
+}
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/CarPropertyManagerPublicPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/CarPropertyManagerPublicPermissionTest.java
new file mode 100644
index 0000000..975bc74
--- /dev/null
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/CarPropertyManagerPublicPermissionTest.java
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.car.Car;
+import android.car.VehicleAreaType;
+import android.car.VehiclePropertyIds;
+import android.car.VehiclePropertyType;
+import android.car.hardware.property.CarPropertyManager;
+import android.os.Handler;
+import android.util.Log;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashSet;
+
+/**
+ * This class contains security permission tests for the {@link CarPropertyManager}'s public APIs.
+ */
+@RunWith(AndroidJUnit4.class)
+public class CarPropertyManagerPublicPermissionTest {
+    private Car mCar = null;
+    private CarPropertyManager mPropertyManager;
+    private HashSet<Integer> mProps = new HashSet<>();
+    private static final String TAG = CarPropertyManagerPublicPermissionTest.class.getSimpleName();
+    private static final Integer DUMMY_AREA_ID = VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
+    // Dummy values for setter test.
+    private static final int DUMMY_PROPERTY_VALUE_INTEGER = 1;
+    private static final Integer[] DUMMY_PROPERTY_VALUE_INTEGER_ARRAY = new Integer[]{1};
+    private static final float DUMMY_PROPERTY_VALUE_FLOAT = 1.0f;
+    private static final Float[] DUMMY_PROPERTY_VALUE_FLOAT_ARRAY = new Float[]{1.0f};
+    private static final Long DUMMY_PROPERTY_VALUE_LONG = 1L;
+    private static final Long[] DUMMY_PROPERTY_VALUE_LONG_ARRAY = new Long[]{1L};
+    private static final boolean DUMMY_PROPERTY_VALUE_BOOLEAN = true;
+    private static final String DUMMY_PROPERTY_VALUE_STRING = "test";
+    private static final byte[] DUMMY_PROPERTY_VALUE_BYTE_ARRAY = "test".getBytes();
+    private static final Object[] DUMMY_PROPERTY_VALUE_OBJECT_ARRAY = new Object[]{1, "test"};
+
+    @Before
+    public void setUp() throws Exception  {
+        initAllPropertyIds();
+        mCar = Car.createCar(
+                InstrumentationRegistry.getInstrumentation().getTargetContext(), (Handler) null);
+        mPropertyManager = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
+        assertThat(mPropertyManager).isNotNull();
+    }
+
+    private synchronized void initAllPropertyIds() {
+        mProps.add(VehiclePropertyIds.DOOR_POS);
+        mProps.add(VehiclePropertyIds.DOOR_MOVE);
+        mProps.add(VehiclePropertyIds.DOOR_LOCK);
+        mProps.add(VehiclePropertyIds.MIRROR_Z_POS);
+        mProps.add(VehiclePropertyIds.MIRROR_Z_MOVE);
+        mProps.add(VehiclePropertyIds.MIRROR_Y_POS);
+        mProps.add(VehiclePropertyIds.MIRROR_Y_MOVE);
+        mProps.add(VehiclePropertyIds.MIRROR_LOCK);
+        mProps.add(VehiclePropertyIds.MIRROR_FOLD);
+        mProps.add(VehiclePropertyIds.SEAT_MEMORY_SELECT);
+        mProps.add(VehiclePropertyIds.SEAT_MEMORY_SET);
+        mProps.add(VehiclePropertyIds.SEAT_BELT_BUCKLED);
+        mProps.add(VehiclePropertyIds.SEAT_BELT_HEIGHT_POS);
+        mProps.add(VehiclePropertyIds.SEAT_BELT_HEIGHT_MOVE);
+        mProps.add(VehiclePropertyIds.SEAT_FORE_AFT_POS);
+        mProps.add(VehiclePropertyIds.SEAT_FORE_AFT_MOVE);
+        mProps.add(VehiclePropertyIds.SEAT_BACKREST_ANGLE_1_POS);
+        mProps.add(VehiclePropertyIds.SEAT_BACKREST_ANGLE_1_MOVE);
+        mProps.add(VehiclePropertyIds.SEAT_BACKREST_ANGLE_2_POS);
+        mProps.add(VehiclePropertyIds.SEAT_BACKREST_ANGLE_2_MOVE);
+        mProps.add(VehiclePropertyIds.SEAT_HEIGHT_POS);
+        mProps.add(VehiclePropertyIds.SEAT_HEIGHT_MOVE);
+        mProps.add(VehiclePropertyIds.SEAT_DEPTH_POS);
+        mProps.add(VehiclePropertyIds.SEAT_DEPTH_MOVE);
+        mProps.add(VehiclePropertyIds.SEAT_TILT_POS);
+        mProps.add(VehiclePropertyIds.SEAT_TILT_MOVE);
+        mProps.add(VehiclePropertyIds.SEAT_LUMBAR_FORE_AFT_POS);
+        mProps.add(VehiclePropertyIds.SEAT_LUMBAR_FORE_AFT_MOVE);
+        mProps.add(VehiclePropertyIds.SEAT_LUMBAR_SIDE_SUPPORT_POS);
+        mProps.add(VehiclePropertyIds.SEAT_LUMBAR_SIDE_SUPPORT_MOVE);
+        mProps.add(VehiclePropertyIds.SEAT_HEADREST_HEIGHT_POS);
+        mProps.add(VehiclePropertyIds.SEAT_HEADREST_HEIGHT_MOVE);
+        mProps.add(VehiclePropertyIds.SEAT_HEADREST_ANGLE_POS);
+        mProps.add(VehiclePropertyIds.SEAT_HEADREST_ANGLE_MOVE);
+        mProps.add(VehiclePropertyIds.SEAT_HEADREST_FORE_AFT_POS);
+        mProps.add(VehiclePropertyIds.SEAT_HEADREST_FORE_AFT_MOVE);
+        mProps.add(VehiclePropertyIds.SEAT_OCCUPANCY);
+        mProps.add(VehiclePropertyIds.WINDOW_POS);
+        mProps.add(VehiclePropertyIds.WINDOW_MOVE);
+        mProps.add(VehiclePropertyIds.WINDOW_LOCK);
+
+        // HVAC properties
+        mProps.add(VehiclePropertyIds.HVAC_FAN_SPEED);
+        mProps.add(VehiclePropertyIds.HVAC_FAN_DIRECTION);
+        mProps.add(VehiclePropertyIds.HVAC_TEMPERATURE_CURRENT);
+        mProps.add(VehiclePropertyIds.HVAC_TEMPERATURE_SET);
+        mProps.add(VehiclePropertyIds.HVAC_DEFROSTER);
+        mProps.add(VehiclePropertyIds.HVAC_ELECTRIC_DEFROSTER_ON);
+        mProps.add(VehiclePropertyIds.HVAC_AC_ON);
+        mProps.add(VehiclePropertyIds.HVAC_MAX_AC_ON);
+        mProps.add(VehiclePropertyIds.HVAC_MAX_DEFROST_ON);
+        mProps.add(VehiclePropertyIds.HVAC_RECIRC_ON);
+        mProps.add(VehiclePropertyIds.HVAC_DUAL_ON);
+        mProps.add(VehiclePropertyIds.HVAC_AUTO_ON);
+        mProps.add(VehiclePropertyIds.HVAC_SEAT_TEMPERATURE);
+        mProps.add(VehiclePropertyIds.HVAC_SIDE_MIRROR_HEAT);
+        mProps.add(VehiclePropertyIds.HVAC_STEERING_WHEEL_HEAT);
+        mProps.add(VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS);
+        mProps.add(VehiclePropertyIds.HVAC_ACTUAL_FAN_SPEED_RPM);
+        mProps.add(VehiclePropertyIds.HVAC_POWER_ON);
+        mProps.add(VehiclePropertyIds.HVAC_FAN_DIRECTION_AVAILABLE);
+        mProps.add(VehiclePropertyIds.HVAC_AUTO_RECIRC_ON);
+        mProps.add(VehiclePropertyIds.HVAC_SEAT_VENTILATION);
+
+        // Info properties
+        mProps.add(VehiclePropertyIds.INFO_VIN);
+        mProps.add(VehiclePropertyIds.INFO_MAKE);
+        mProps.add(VehiclePropertyIds.INFO_MODEL);
+        mProps.add(VehiclePropertyIds.INFO_MODEL_YEAR);
+        mProps.add(VehiclePropertyIds.INFO_FUEL_CAPACITY);
+        mProps.add(VehiclePropertyIds.INFO_FUEL_TYPE);
+        mProps.add(VehiclePropertyIds.INFO_EV_BATTERY_CAPACITY);
+        mProps.add(VehiclePropertyIds.INFO_EV_CONNECTOR_TYPE);
+        mProps.add(VehiclePropertyIds.INFO_FUEL_DOOR_LOCATION);
+        mProps.add(VehiclePropertyIds.INFO_MULTI_EV_PORT_LOCATIONS);
+        mProps.add(VehiclePropertyIds.INFO_EV_PORT_LOCATION);
+        mProps.add(VehiclePropertyIds.INFO_DRIVER_SEAT);
+        mProps.add(VehiclePropertyIds.INFO_EXTERIOR_DIMENSIONS);
+
+        // Sensor properties
+        mProps.add(VehiclePropertyIds.PERF_ODOMETER);
+        mProps.add(VehiclePropertyIds.PERF_VEHICLE_SPEED);
+        mProps.add(VehiclePropertyIds.PERF_VEHICLE_SPEED_DISPLAY);
+        mProps.add(VehiclePropertyIds.ENGINE_COOLANT_TEMP);
+        mProps.add(VehiclePropertyIds.ENGINE_OIL_LEVEL);
+        mProps.add(VehiclePropertyIds.ENGINE_OIL_TEMP);
+        mProps.add(VehiclePropertyIds.ENGINE_RPM);
+        mProps.add(VehiclePropertyIds.WHEEL_TICK);
+        mProps.add(VehiclePropertyIds.FUEL_LEVEL);
+        mProps.add(VehiclePropertyIds.FUEL_DOOR_OPEN);
+        mProps.add(VehiclePropertyIds.EV_BATTERY_LEVEL);
+        mProps.add(VehiclePropertyIds.EV_CHARGE_PORT_OPEN);
+        mProps.add(VehiclePropertyIds.EV_CHARGE_PORT_CONNECTED);
+        mProps.add(VehiclePropertyIds.EV_BATTERY_INSTANTANEOUS_CHARGE_RATE);
+        mProps.add(VehiclePropertyIds.RANGE_REMAINING);
+        mProps.add(VehiclePropertyIds.TIRE_PRESSURE);
+        mProps.add(VehiclePropertyIds.PERF_STEERING_ANGLE);
+        mProps.add(VehiclePropertyIds.PERF_REAR_STEERING_ANGLE);
+        mProps.add(VehiclePropertyIds.GEAR_SELECTION);
+        mProps.add(VehiclePropertyIds.CURRENT_GEAR);
+        mProps.add(VehiclePropertyIds.PARKING_BRAKE_ON);
+        mProps.add(VehiclePropertyIds.PARKING_BRAKE_AUTO_APPLY);
+        mProps.add(VehiclePropertyIds.FUEL_LEVEL_LOW);
+        mProps.add(VehiclePropertyIds.NIGHT_MODE);
+        mProps.add(VehiclePropertyIds.TURN_SIGNAL_STATE);
+        mProps.add(VehiclePropertyIds.IGNITION_STATE);
+        mProps.add(VehiclePropertyIds.ABS_ACTIVE);
+        mProps.add(VehiclePropertyIds.TRACTION_CONTROL_ACTIVE);
+        mProps.add(VehiclePropertyIds.ENV_OUTSIDE_TEMPERATURE);
+        mProps.add(VehiclePropertyIds.HEADLIGHTS_STATE);
+        mProps.add(VehiclePropertyIds.HIGH_BEAM_LIGHTS_STATE);
+        mProps.add(VehiclePropertyIds.FOG_LIGHTS_STATE);
+        mProps.add(VehiclePropertyIds.HAZARD_LIGHTS_STATE);
+        mProps.add(VehiclePropertyIds.HEADLIGHTS_SWITCH);
+        mProps.add(VehiclePropertyIds.HIGH_BEAM_LIGHTS_SWITCH);
+        mProps.add(VehiclePropertyIds.FOG_LIGHTS_SWITCH);
+        mProps.add(VehiclePropertyIds.HAZARD_LIGHTS_SWITCH);
+        mProps.add(VehiclePropertyIds.READING_LIGHTS_STATE);
+        mProps.add(VehiclePropertyIds.CABIN_LIGHTS_STATE);
+        mProps.add(VehiclePropertyIds.READING_LIGHTS_SWITCH);
+        mProps.add(VehiclePropertyIds.CABIN_LIGHTS_SWITCH);
+        // Display_Units
+        mProps.add(VehiclePropertyIds.DISTANCE_DISPLAY_UNITS);
+        mProps.add(VehiclePropertyIds.FUEL_VOLUME_DISPLAY_UNITS);
+        mProps.add(VehiclePropertyIds.TIRE_PRESSURE_DISPLAY_UNITS);
+        mProps.add(VehiclePropertyIds.EV_BATTERY_DISPLAY_UNITS);
+        mProps.add(VehiclePropertyIds.FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME);
+        mProps.add(VehiclePropertyIds.VEHICLE_SPEED_DISPLAY_UNITS);
+    }
+
+    @After
+    public void tearDown() {
+        if (mCar != null) {
+            mCar.disconnect();
+        }
+    }
+
+    @Test
+    public void testCarPropertyManagerGetter() {
+        for (int propertyId : mProps) {
+            try {
+                switch (propertyId & VehiclePropertyType.MASK) {
+                    case VehiclePropertyType.BOOLEAN:
+                        // The areaId may not match with it in propertyConfig. CarService
+                        // check the permission before checking valid areaId.
+                        mPropertyManager.getBooleanProperty(propertyId, DUMMY_AREA_ID);
+                        break;
+                    case VehiclePropertyType.FLOAT:
+                        mPropertyManager.getFloatProperty(propertyId, DUMMY_AREA_ID);
+                        break;
+                    case VehiclePropertyType.INT32_VEC:
+                        mPropertyManager.getIntArrayProperty(propertyId, DUMMY_AREA_ID);
+                        break;
+                    case VehiclePropertyType.INT32:
+                        mPropertyManager.getIntProperty(propertyId, DUMMY_AREA_ID);
+                        break;
+                    default:
+                        mPropertyManager.getProperty(propertyId, DUMMY_AREA_ID);
+                }
+            } catch (Exception e) {
+                assertWithMessage("Get property: 0x" + Integer.toHexString(propertyId)
+                        + " cause an unexpected exception: " + e)
+                        .that(e).isInstanceOf(SecurityException.class);
+                continue;
+            }
+            assertPropertyNotImplementedInVhal(propertyId);
+        }
+    }
+
+    private void assertPropertyNotImplementedInVhal(int propertyId) {
+        assertWithMessage("Get property : 0x " + Integer.toHexString(propertyId)
+                + " without permission.")
+                .that(mPropertyManager.getProperty(propertyId, DUMMY_AREA_ID)).isNull();
+        Log.w(TAG, "Property id: 0x" + Integer.toHexString(propertyId)
+                + " does not exist in the VHAL implementation.");
+    }
+
+    @Test
+    public void testCarPropertyManagerSetter() {
+        for (int propertyId : mProps) {
+            try {
+                // Dummy value may not in the valid range. CarService checks permission
+                // and sends request to VHAL. VHAL checks specific property range.
+                switch (propertyId & VehiclePropertyType.MASK) {
+                    case VehiclePropertyType.BOOLEAN:
+                        mPropertyManager.setBooleanProperty(propertyId, DUMMY_AREA_ID,
+                                DUMMY_PROPERTY_VALUE_BOOLEAN);
+                        break;
+                    case VehiclePropertyType.FLOAT:
+                        mPropertyManager.setFloatProperty(propertyId, DUMMY_AREA_ID,
+                                DUMMY_PROPERTY_VALUE_FLOAT);
+                        break;
+                    case VehiclePropertyType.FLOAT_VEC:
+                        mPropertyManager.setProperty(Float[].class, propertyId, DUMMY_AREA_ID,
+                                DUMMY_PROPERTY_VALUE_FLOAT_ARRAY);
+                        break;
+                    case VehiclePropertyType.INT32:
+                        mPropertyManager.setIntProperty(propertyId, DUMMY_AREA_ID,
+                                DUMMY_PROPERTY_VALUE_INTEGER);
+                        break;
+                    case VehiclePropertyType.INT32_VEC:
+                        mPropertyManager.setProperty(Integer[].class, propertyId, DUMMY_AREA_ID,
+                                DUMMY_PROPERTY_VALUE_INTEGER_ARRAY);
+                        break;
+                    case VehiclePropertyType.INT64:
+                        mPropertyManager.setProperty(Long.class, propertyId, DUMMY_AREA_ID,
+                                DUMMY_PROPERTY_VALUE_LONG);
+                        break;
+                    case VehiclePropertyType.INT64_VEC:
+                        mPropertyManager.setProperty(Long[].class, propertyId, DUMMY_AREA_ID,
+                                DUMMY_PROPERTY_VALUE_LONG_ARRAY);
+                        break;
+                    case VehiclePropertyType.BYTES:
+                        mPropertyManager.setProperty(byte[].class, propertyId, DUMMY_AREA_ID,
+                                DUMMY_PROPERTY_VALUE_BYTE_ARRAY);
+                        break;
+                    case VehiclePropertyType.MIXED:
+                        mPropertyManager.setProperty(Object[].class, propertyId, DUMMY_AREA_ID,
+                                DUMMY_PROPERTY_VALUE_OBJECT_ARRAY);
+                        break;
+                    case VehiclePropertyType.STRING:
+                        mPropertyManager.setProperty(String.class, propertyId, DUMMY_AREA_ID,
+                                DUMMY_PROPERTY_VALUE_STRING);
+                        break;
+                    default:
+                        throw new IllegalArgumentException("Invalid value type for property: 0x"
+                                + Integer.toHexString(propertyId));
+                }
+            } catch (IllegalArgumentException e) {
+                assertWithMessage("Set property: 0x" + Integer.toHexString(propertyId)
+                        + " cause an unexpected exception: " + e)
+                        .that(e.getMessage()).contains("does not exist in the vehicle");
+            } catch (Exception e) {
+                assertWithMessage("Get property: 0x" + Integer.toHexString(propertyId)
+                        + " cause an unexpected exception: " + e)
+                        .that(e).isInstanceOf(SecurityException.class);
+            }
+        }
+    }
+}
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/CarPublicPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/CarPublicPermissionTest.java
new file mode 100644
index 0000000..16aef37
--- /dev/null
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/CarPublicPermissionTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car;
+
+import static org.testng.Assert.assertThrows;
+
+import android.car.Car;
+import android.os.Handler;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * This class contains security permission tests for the {@link CarPermisisonTest}'s public APIs.
+ */
+@RunWith(AndroidJUnit4.class)
+public class CarPublicPermissionTest {
+    private Car mCar = null;
+
+    @Before
+    public void setUp() throws Exception {
+        mCar = Car.createCar(
+                InstrumentationRegistry.getInstrumentation().getTargetContext(), (Handler) null);
+    }
+
+    @After
+    public void tearDown() {
+        mCar.disconnect();
+    }
+
+    @Test
+    public void testGetCarManagerPermissions() throws Exception {
+        assertThrows(SecurityException.class, () -> mCar.getCarManager(
+                Car.CAR_DRIVING_STATE_SERVICE));
+        assertThrows(SecurityException.class, () -> mCar.getCarManager(
+                Car.CAR_INSTRUMENT_CLUSTER_SERVICE));
+        assertThrows(SecurityException.class, () -> mCar.getCarManager(Car.CAR_NAVIGATION_SERVICE));
+        assertThrows(SecurityException.class, () -> mCar.getCarManager(
+                Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE));
+        if (mCar.isFeatureEnabled(Car.DIAGNOSTIC_SERVICE)) {
+            assertThrows(SecurityException.class, () -> mCar.getCarManager(Car.DIAGNOSTIC_SERVICE));
+        }
+        assertThrows(SecurityException.class, () -> mCar.getCarManager(Car.POWER_SERVICE));
+        if (mCar.isFeatureEnabled(Car.VMS_SUBSCRIBER_SERVICE)) {
+            assertThrows(SecurityException.class, () -> mCar.getCarManager(
+                    Car.VMS_SUBSCRIBER_SERVICE));
+        }
+        assertThrows(SecurityException.class, () -> mCar.getCarManager(Car.TEST_SERVICE));
+        if (mCar.isFeatureEnabled(Car.STORAGE_MONITORING_SERVICE)) {
+            assertThrows(SecurityException.class, () -> mCar.getCarManager(
+                    Car.STORAGE_MONITORING_SERVICE));
+        }
+    }
+}
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/content/pm/CarPackageManagerPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/content/pm/CarPackageManagerPermissionTest.java
new file mode 100644
index 0000000..f1e23ba
--- /dev/null
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/content/pm/CarPackageManagerPermissionTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car;
+
+import static org.testng.Assert.assertThrows;
+
+import android.car.Car;
+import android.car.content.pm.CarAppBlockingPolicy;
+import android.car.content.pm.CarPackageManager;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * This class contains security permission tests for {@link CarPackageManager}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class CarPackageManagerPermissionTest {
+    private Car mCar;
+    private CarPackageManager mPm;
+
+    @Before
+    public void setUp() throws Exception {
+        mCar = Car.createCar(InstrumentationRegistry.getInstrumentation().getTargetContext());
+        mPm = (CarPackageManager) mCar.getCarManager(Car.PACKAGE_SERVICE);
+    }
+
+    @After
+    public void tearDown() {
+        mCar.disconnect();
+    }
+
+    @Test
+    public void testRestartTask() {
+        assertThrows(SecurityException.class, () -> mPm.restartTask(0));
+    }
+
+    @Test
+    public void testSetAppBlockingPolicy() {
+        String packageName = "com.android";
+        CarAppBlockingPolicy policy = new CarAppBlockingPolicy(null, null);
+        assertThrows(SecurityException.class, () -> mPm.setAppBlockingPolicy(packageName, policy,
+                0));
+    }
+
+}
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/input/CarInputManagerPermisisonTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/input/CarInputManagerPermisisonTest.java
new file mode 100644
index 0000000..9730d13
--- /dev/null
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/input/CarInputManagerPermisisonTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.input;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.car.Car;
+import android.car.input.CarInputManager;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+/**
+ * This class contains security permission tests for the {@link CarInputManager}'s system APIs.
+ */
+@RunWith(AndroidJUnit4.class)
+public class CarInputManagerPermisisonTest {
+    private Car mCar;
+
+    private CarInputManager mCarInputManager;
+
+    @Mock
+    private CarInputManager.CarInputCaptureCallback mMockedCallback;
+
+    @Before
+    public void setUp() throws Exception {
+        mCar = Car.createCar(
+                InstrumentationRegistry.getInstrumentation().getTargetContext());
+        assertThat(mCar).isNotNull();
+        mCarInputManager = (CarInputManager) mCar.getCarManager(Car.CAR_INPUT_SERVICE);
+        assertThat(mCarInputManager).isNotNull();
+    }
+
+    @After
+    public void tearDown() {
+        mCar.disconnect();
+    }
+
+    @Test
+    public void testEnableFeaturePermission() throws Exception {
+        assertThrows(SecurityException.class, () -> mCarInputManager.requestInputEventCapture(
+                mMockedCallback,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0));
+    }
+}
+
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/media/CarAudioManagerPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/media/CarAudioManagerPermissionTest.java
new file mode 100644
index 0000000..1e4391b
--- /dev/null
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/media/CarAudioManagerPermissionTest.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.media;
+
+import static android.car.Car.AUDIO_SERVICE;
+import static android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS;
+import static android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME;
+import static android.car.Car.createCar;
+import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE;
+import static android.media.AudioAttributes.USAGE_MEDIA;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.expectThrows;
+
+import android.car.Car;
+import android.car.media.CarAudioManager;
+import android.content.Context;
+import android.os.Handler;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Objects;
+
+/**
+ * This class contains security permission tests for the {@link CarAudioManager}'s system APIs.
+ */
+@RunWith(AndroidJUnit4.class)
+public final class CarAudioManagerPermissionTest {
+    private static final int GROUP_ID = 0;
+    private static final int UID = 10;
+
+    private CarAudioManager mCarAudioManager;
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        Car car = Objects.requireNonNull(createCar(mContext, (Handler) null));
+        mCarAudioManager = (CarAudioManager) car.getCarManager(AUDIO_SERVICE);
+    }
+
+    @Test
+    public void setGroupVolumePermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.setGroupVolume(GROUP_ID, 0, 0));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+    }
+
+    @Test
+    public void setGroupVolumeWithZonePermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.setGroupVolume(PRIMARY_AUDIO_ZONE, GROUP_ID, 0, 0));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+    }
+
+    @Test
+    public void getGroupMaxVolumePermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.getGroupMaxVolume(GROUP_ID));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+    }
+
+    @Test
+    public void getGroupMaxVolumeWithZonePermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.getGroupMaxVolume(PRIMARY_AUDIO_ZONE, GROUP_ID));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+    }
+
+    @Test
+    public void getGroupMinVolumePermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.getGroupMinVolume(GROUP_ID));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+    }
+
+    @Test
+    public void getGroupMinVolumeWithZonePermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.getGroupMinVolume(PRIMARY_AUDIO_ZONE, GROUP_ID));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+    }
+
+    @Test
+    public void getGroupVolumePermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.getGroupVolume(GROUP_ID));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+    }
+
+    @Test
+    public void getGroupVolumeWithZonePermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.getGroupVolume(PRIMARY_AUDIO_ZONE, GROUP_ID));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+    }
+
+    @Test
+    public void setFadeTowardFrontPermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.setFadeTowardFront(0));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+    }
+
+    @Test
+    public void setBalanceTowardRightPermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.setBalanceTowardRight(0));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+    }
+
+    @Test
+    public void getExternalSourcesPermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.getExternalSources());
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
+    }
+
+    @Test
+    public void createAudioPatchPermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.createAudioPatch("address", USAGE_MEDIA, 0));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
+    }
+
+    @Test
+    public void releaseAudioPatchPermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.releaseAudioPatch(null));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
+    }
+
+    @Test
+    public void getVolumeGroupCountPermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.getVolumeGroupCount());
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+    }
+
+    @Test
+    public void getVolumeGroupCountWithZonePermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.getVolumeGroupCount(PRIMARY_AUDIO_ZONE));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+    }
+
+    @Test
+    public void getVolumeGroupIdForUsagePermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.getVolumeGroupIdForUsage(USAGE_MEDIA));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+    }
+
+    @Test
+    public void getVolumeGroupIdForUsageWithZonePermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, USAGE_MEDIA));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+    }
+
+    @Test
+    public void getUsagesForVolumeGroupIdPermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.getUsagesForVolumeGroupId(GROUP_ID));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+    }
+
+    @Test
+    public void getAudioZoneIdsPermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.getAudioZoneIds());
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
+    }
+
+    @Test
+    public void getZoneIdForUidPermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.getZoneIdForUid(UID));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
+    }
+
+    @Test
+    public void setZoneIdForUidPermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.setZoneIdForUid(PRIMARY_AUDIO_ZONE, UID));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
+    }
+
+    @Test
+    public void clearZoneIdForUidPermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.clearZoneIdForUid(UID));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
+    }
+
+    @Test
+    public void getOutputDeviceForUsagePermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.getOutputDeviceForUsage(PRIMARY_AUDIO_ZONE, USAGE_MEDIA));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
+    }
+
+    @Test
+    public void onCarDisconnectedPermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.onCarDisconnected());
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+    }
+
+    @Test
+    public void onCarDisconnected() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.onCarDisconnected());
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+    }
+}
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/media/CarAudioManagerPublicPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/media/CarAudioManagerPublicPermissionTest.java
new file mode 100644
index 0000000..b9cafc4
--- /dev/null
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/media/CarAudioManagerPublicPermissionTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.media;
+
+import static android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.expectThrows;
+
+import android.car.Car;
+import android.car.media.CarAudioManager;
+import android.car.media.CarAudioManager.CarVolumeCallback;
+import android.content.Context;
+import android.os.Handler;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * This class contains security permission tests for the {@link CarAudioManager}'s public APIs.
+ */
+@RunWith(AndroidJUnit4.class)
+public final class CarAudioManagerPublicPermissionTest {
+    private CarAudioManager mCarAudioManager;
+
+    @Before
+    public void setUp() throws Exception {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        Car car = Car.createCar(context, (Handler) null);
+        mCarAudioManager = (CarAudioManager) car.getCarManager(Car.AUDIO_SERVICE);
+    }
+
+    @Test
+    public void registerCarVolumeCallbackPermission() {
+        CarVolumeCallback callback = new CarVolumeCallback() {};
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarAudioManager.registerCarVolumeCallback(callback));
+        assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+    }
+}
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/user/CarUserManagerPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/user/CarUserManagerPermissionTest.java
new file mode 100644
index 0000000..3a5ea1b
--- /dev/null
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/user/CarUserManagerPermissionTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.user;
+
+import static android.Manifest.permission.CREATE_USERS;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.MANAGE_USERS;
+import static android.car.Car.CAR_USER_SERVICE;
+import static android.car.Car.createCar;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.CUSTOM_1;
+
+import static com.android.compatibility.common.util.ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.expectThrows;
+
+import android.app.Instrumentation;
+import android.car.Car;
+import android.car.user.CarUserManager;
+import android.car.user.CarUserManager.UserLifecycleListener;
+import android.content.Context;
+import android.os.Handler;
+import android.os.UserManager;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Objects;
+
+/**
+ * This class contains security permission tests for the {@link CarUserManager}'s system APIs.
+ */
+@RunWith(AndroidJUnit4.class)
+public final class CarUserManagerPermissionTest {
+    private static final int USRE_TYPE = 1;
+
+    private CarUserManager mCarUserManager;
+    private Context mContext;
+    private Instrumentation mInstrumentation;
+
+    @Before
+    public void setUp() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mContext = mInstrumentation.getTargetContext();
+        Car car = Objects.requireNonNull(createCar(mContext, (Handler) null));
+        mCarUserManager = (CarUserManager) car.getCarManager(CAR_USER_SERVICE);
+
+    }
+
+    @Test
+    public void testSwitchUserPermission() throws Exception {
+        Exception e = expectThrows(SecurityException.class, () -> mCarUserManager.switchUser(100));
+        assertThat(e.getMessage()).contains(MANAGE_USERS);
+    }
+
+    @Test
+    public void testCreateUserPermission() throws Exception {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarUserManager.createUser(null, UserManager.USER_TYPE_FULL_SECONDARY, 0));
+        assertThat(e.getMessage()).contains(MANAGE_USERS);
+        assertThat(e.getMessage()).contains(CREATE_USERS);
+    }
+
+    @Test
+    public void testRemoveUserPermission() throws Exception {
+        Exception e = expectThrows(SecurityException.class, () -> mCarUserManager.removeUser(100));
+        assertThat(e.getMessage()).contains(MANAGE_USERS);
+    }
+
+    @Test
+    public void testAddListenerPermission() {
+        UserLifecycleListener listener = (e) -> { };
+
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarUserManager.addListener(Runnable::run, listener));
+
+        assertThat(e.getMessage()).contains(INTERACT_ACROSS_USERS);
+        assertThat(e.getMessage()).contains(INTERACT_ACROSS_USERS_FULL);
+    }
+
+    @Test
+    public void testRemoveListenerPermission() throws Exception {
+        UserLifecycleListener listener = (e) -> { };
+        invokeMethodWithShellPermissionsNoReturn(mCarUserManager,
+                (um) -> um.addListener(Runnable::run, listener));
+
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarUserManager.removeListener(listener));
+
+        assertThat(e.getMessage()).contains(INTERACT_ACROSS_USERS);
+        assertThat(e.getMessage()).contains(INTERACT_ACROSS_USERS_FULL);
+    }
+
+    @Test
+    public void testGetUserIdentificationAssociationPermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarUserManager.getUserIdentificationAssociation(CUSTOM_1));
+        assertThat(e.getMessage()).contains(MANAGE_USERS);
+    }
+
+    @Test
+    public void testSetUserIdentificationAssociationPermission() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarUserManager.setUserIdentificationAssociation(
+                        new int[] {CUSTOM_1}, new int[] {42}));
+        assertThat(e.getMessage()).contains(MANAGE_USERS);
+    }
+
+    @Test
+    public void testSetUserSwitchUiCallback() {
+        Exception e = expectThrows(SecurityException.class,
+                () -> mCarUserManager.getUserIdentificationAssociation(CUSTOM_1));
+        assertThat(e.getMessage()).contains(MANAGE_USERS);
+    }
+}
diff --git a/tests/DefaultStorageMonitoringCompanionApp/Android.mk b/tests/DefaultStorageMonitoringCompanionApp/Android.mk
index 66c04c3..ff28cf6 100644
--- a/tests/DefaultStorageMonitoringCompanionApp/Android.mk
+++ b/tests/DefaultStorageMonitoringCompanionApp/Android.mk
@@ -23,8 +23,7 @@
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 
 LOCAL_PACKAGE_NAME := DefaultStorageMonitoringCompanionApp
-
-LOCAL_SDK_VERSION := system_current
+LOCAL_PRIVATE_PLATFORM_APIS := true
 
 LOCAL_AAPT_FLAGS := --auto-add-overlay
 
@@ -36,6 +35,6 @@
 
 LOCAL_DEX_PREOPT := false
 
-LOCAL_JAVA_LIBRARIES += android.car-system-stubs
+LOCAL_JAVA_LIBRARIES += android.car
 
 include $(BUILD_PACKAGE)
diff --git a/tests/DefaultStorageMonitoringCompanionApp/src/com/google/android/car/defaultstoragemonitoringcompanionapp/MainActivity.java b/tests/DefaultStorageMonitoringCompanionApp/src/com/google/android/car/defaultstoragemonitoringcompanionapp/MainActivity.java
index b76388e..02adca2 100644
--- a/tests/DefaultStorageMonitoringCompanionApp/src/com/google/android/car/defaultstoragemonitoringcompanionapp/MainActivity.java
+++ b/tests/DefaultStorageMonitoringCompanionApp/src/com/google/android/car/defaultstoragemonitoringcompanionapp/MainActivity.java
@@ -111,7 +111,11 @@
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
             Log.d(TAG, "Connected to " + name.flattenToString());
-
+            if (!mCar.isFeatureEnabled(Car.STORAGE_MONITORING_SERVICE)) {
+                Log.e(TAG, "Car.STORAGE_MONITORING_SERVICE feature not supported, will finish");
+                finish();
+                return;
+            }
             CarStorageMonitoringManager storageMonitoringManager =
                     (CarStorageMonitoringManager) mCar.getCarManager(
                             Car.STORAGE_MONITORING_SERVICE);
@@ -120,6 +124,7 @@
                     storageMonitoringManager.getWearEstimateHistory();
             if (wearEstimateChanges.isEmpty()) {
                 finish();
+                return;
             }
 
             WearEstimateChange currentChange =
@@ -127,6 +132,7 @@
 
             if (!DEBUG && currentChange.isAcceptableDegradation) {
                 finish();
+                return;
             }
 
             mNotificationTextView.setText(wearChangeToString(currentChange));
diff --git a/tests/DiagnosticTools/Android.mk b/tests/DiagnosticTools/Android.mk
new file mode 100644
index 0000000..c2453ae
--- /dev/null
+++ b/tests/DiagnosticTools/Android.mk
@@ -0,0 +1,48 @@
+#
+# 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.
+#
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := DiagnosticTools
+LOCAL_PRIVATE_PLATFORM_APIS := true
+
+LOCAL_CERTIFICATE := platform
+
+#LOCAL_SDK_VERSION := current
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_STATIC_ANDROID_LIBRARIES := androidx.recyclerview_recyclerview \
+    com.google.android.material_material \
+    androidx-constraintlayout_constraintlayout \
+    androidx.appcompat_appcompat \
+    androidx-constraintlayout_constraintlayout-solver
+
+LOCAL_JAVA_LIBRARIES := android.car
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/DiagnosticTools/AndroidManifest.xml b/tests/DiagnosticTools/AndroidManifest.xml
new file mode 100644
index 0000000..55ee4bc
--- /dev/null
+++ b/tests/DiagnosticTools/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?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
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.google.android.car.diagnostictools">
+    <uses-permission android:name="android.car.permission.CAR_DIAGNOSTICS"/>
+    <uses-permission android:name="android.car.permission.CLEAR_CAR_DIAGNOSTICS"/>
+    <application android:label="OBD-II Diagnostic Tools" android:theme="@style/AppTheme">
+        <activity android:name=".ECUListActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+        <activity android:name=".DTCListActivity"/>
+        <activity android:name=".DTCDetailActivity"/>
+        <activity android:name=".LiveDataActivity"/>
+    </application>
+</manifest>
diff --git a/tests/DiagnosticTools/res/drawable/ic_arrow_back_black_24dp.xml b/tests/DiagnosticTools/res/drawable/ic_arrow_back_black_24dp.xml
new file mode 100644
index 0000000..75ae95c
--- /dev/null
+++ b/tests/DiagnosticTools/res/drawable/ic_arrow_back_black_24dp.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+  android:height="24dp"
+  android:tint="#FFFFFF"
+  android:viewportHeight="24.0"
+  android:viewportWidth="24.0"
+  android:width="24dp">
+  <path
+    android:fillColor="#FF000000"
+    android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
+</vector>
diff --git a/tests/DiagnosticTools/res/drawable/ic_delete_sweep_black_24dp.xml b/tests/DiagnosticTools/res/drawable/ic_delete_sweep_black_24dp.xml
new file mode 100644
index 0000000..6c933bf
--- /dev/null
+++ b/tests/DiagnosticTools/res/drawable/ic_delete_sweep_black_24dp.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+  android:height="24dp"
+  android:tint="#FFFFFF"
+  android:viewportHeight="24.0"
+  android:viewportWidth="24.0"
+  android:width="24dp">
+  <path
+    android:fillColor="#FF000000"
+    android:pathData="M15,16h4v2h-4zM15,8h7v2h-7zM15,12h6v2h-6zM3,18c0,1.1 0.9,2 2,2h6c1.1,0 2,-0.9 2,-2L13,8L3,8v10zM14,5h-3l-1,-1L6,4L5,5L2,5v2h12z"/>
+</vector>
diff --git a/tests/DiagnosticTools/res/drawable/ic_select_all_black_24dp.xml b/tests/DiagnosticTools/res/drawable/ic_select_all_black_24dp.xml
new file mode 100644
index 0000000..5729483
--- /dev/null
+++ b/tests/DiagnosticTools/res/drawable/ic_select_all_black_24dp.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+  android:height="24dp"
+  android:tint="#FFFFFF"
+  android:viewportHeight="24.0"
+  android:viewportWidth="24.0"
+  android:width="24dp">
+  <path
+    android:fillColor="#FF000000"
+    android:pathData="M3,5h2L5,3c-1.1,0 -2,0.9 -2,2zM3,13h2v-2L3,11v2zM7,21h2v-2L7,19v2zM3,9h2L5,7L3,7v2zM13,3h-2v2h2L13,3zM19,3v2h2c0,-1.1 -0.9,-2 -2,-2zM5,21v-2L3,19c0,1.1 0.9,2 2,2zM3,17h2v-2L3,15v2zM9,3L7,3v2h2L9,3zM11,21h2v-2h-2v2zM19,13h2v-2h-2v2zM19,21c1.1,0 2,-0.9 2,-2h-2v2zM19,9h2L21,7h-2v2zM19,17h2v-2h-2v2zM15,21h2v-2h-2v2zM15,5h2L17,3h-2v2zM7,17h10L17,7L7,7v10zM9,9h6v6L9,15L9,9z"/>
+</vector>
diff --git a/tests/DiagnosticTools/res/drawable/ic_show_chart_black_24dp.xml b/tests/DiagnosticTools/res/drawable/ic_show_chart_black_24dp.xml
new file mode 100644
index 0000000..210ede0
--- /dev/null
+++ b/tests/DiagnosticTools/res/drawable/ic_show_chart_black_24dp.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+  android:height="24dp"
+  android:tint="#FFFFFF"
+  android:viewportHeight="24.0"
+  android:viewportWidth="24.0"
+  android:width="24dp">
+  <path
+    android:fillColor="#FF000000"
+    android:pathData="M3.5,18.49l6,-6.01 4,4L22,6.92l-1.41,-1.41 -7.09,7.97 -4,-4L2,16.99z"/>
+</vector>
diff --git a/tests/DiagnosticTools/res/layout/activity_dtc_details.xml b/tests/DiagnosticTools/res/layout/activity_dtc_details.xml
new file mode 100644
index 0000000..4feb8c4
--- /dev/null
+++ b/tests/DiagnosticTools/res/layout/activity_dtc_details.xml
@@ -0,0 +1,89 @@
+<?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
+  -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+  xmlns:app="http://schemas.android.com/apk/res-auto"
+  xmlns:tools="http://schemas.android.com/tools"
+  android:layout_width="match_parent"
+  android:layout_height="wrap_content">
+  <androidx.constraintlayout.widget.ConstraintLayout
+    android:id="@+id/linearLayout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <Button
+      android:id="@+id/freeze_frame_clear"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:layout_marginEnd="16dp"
+      android:onClick="clearFreezeFrameButtonPress"
+      android:text="Clear Freeze Frame Data"
+      app:layout_constraintBottom_toTopOf="@+id/freeze_frame_data"
+      app:layout_constraintEnd_toEndOf="parent"
+      app:layout_constraintTop_toBottomOf="@+id/dtc_details"/>
+    <ProgressBar
+      android:id="@+id/freeze_frame_loading"
+      style="?android:attr/progressBarStyle"
+      android:layout_width="0dp"
+      android:layout_height="128dp"
+      android:visibility="invisible"
+      app:layout_constraintBottom_toBottomOf="parent"
+      app:layout_constraintEnd_toEndOf="parent"
+      app:layout_constraintHorizontal_bias="0.0"
+      app:layout_constraintStart_toStartOf="parent"
+      app:layout_constraintTop_toBottomOf="@+id/freeze_frame_title"/>
+    <TextView
+      android:id="@+id/dtc_details"
+      android:layout_width="0dp"
+      android:layout_height="wrap_content"
+      android:text="TextView"
+      android:textSize="24sp"
+      app:layout_constraintEnd_toEndOf="parent"
+      app:layout_constraintStart_toStartOf="parent"
+      app:layout_constraintTop_toBottomOf="@+id/toolbar"/>
+    <TextView
+      android:id="@+id/freeze_frame_title"
+      android:layout_width="0dp"
+      android:layout_height="wrap_content"
+      android:layout_marginTop="8dp"
+      android:text="Freeze Frame:"
+      android:textSize="36sp"
+      app:layout_constraintStart_toStartOf="parent"
+      app:layout_constraintTop_toBottomOf="@+id/dtc_details"/>
+    <Toolbar
+      android:id="@+id/toolbar"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:background="?android:attr/colorPrimary"
+      android:elevation="4dp"
+      android:theme="@android:attr/actionBarTheme"/>
+    <androidx.recyclerview.widget.RecyclerView
+      android:id="@+id/freeze_frame_data"
+      android:layout_width="match_parent"
+      android:layout_height="0dp"
+      android:layout_marginTop="8dp"
+      android:background="#00FF0000"
+      android:minHeight="72dp"
+      android:visibility="visible"
+      app:layout_constraintBottom_toBottomOf="parent"
+      app:layout_constraintEnd_toEndOf="@+id/freeze_frame_loading"
+      app:layout_constraintHeight_default="spread"
+      app:layout_constraintHeight_min="300dp"
+      app:layout_constraintStart_toStartOf="@+id/freeze_frame_loading"
+      app:layout_constraintTop_toBottomOf="@+id/freeze_frame_title"/>
+  </androidx.constraintlayout.widget.ConstraintLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/tests/DiagnosticTools/res/layout/activity_dtc_list.xml b/tests/DiagnosticTools/res/layout/activity_dtc_list.xml
new file mode 100644
index 0000000..e5f92a5
--- /dev/null
+++ b/tests/DiagnosticTools/res/layout/activity_dtc_list.xml
@@ -0,0 +1,50 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+  xmlns:app="http://schemas.android.com/apk/res-auto"
+  xmlns:tools="http://schemas.android.com/tools"
+  android:id="@+id/relativeLayout2"
+  android:layout_width="match_parent"
+  android:layout_height="match_parent"
+  android:orientation="vertical">
+  <Toolbar
+    android:id="@+id/toolbar"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?android:attr/colorPrimary"
+    android:elevation="4dp"
+    android:theme="@android:attr/actionBarTheme"/>
+  <FrameLayout
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <androidx.recyclerview.widget.RecyclerView
+      android:id="@+id/dtc_list"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:scrollbars="vertical"/>
+    <com.google.android.material.floatingactionbutton.FloatingActionButton
+      android:id="@+id/floatingActionButton"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:layout_margin="16dp"
+      android:layout_gravity="bottom|end"
+      android:clickable="true"
+      android:onClick="onClickActionButton"
+      android:src="@drawable/ic_delete_sweep_black_24dp"/>
+  </FrameLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/DiagnosticTools/res/layout/activity_live_data.xml b/tests/DiagnosticTools/res/layout/activity_live_data.xml
new file mode 100644
index 0000000..dc085a6
--- /dev/null
+++ b/tests/DiagnosticTools/res/layout/activity_live_data.xml
@@ -0,0 +1,38 @@
+<?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
+  -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+  android:layout_width="match_parent"
+  android:layout_height="match_parent">
+  <LinearLayout
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+    <Toolbar
+      android:id="@+id/toolbar"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:background="?android:attr/colorPrimary"
+      android:elevation="4dp"
+      android:theme="@android:attr/actionBarTheme"/>
+    <androidx.recyclerview.widget.RecyclerView
+      android:id="@+id/live_data_list"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:scrollbars="vertical"/>
+  </LinearLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/tests/DiagnosticTools/res/layout/diagnostic_tools.xml b/tests/DiagnosticTools/res/layout/diagnostic_tools.xml
new file mode 100644
index 0000000..44c6f64
--- /dev/null
+++ b/tests/DiagnosticTools/res/layout/diagnostic_tools.xml
@@ -0,0 +1,56 @@
+<?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
+  xmlns:android="http://schemas.android.com/apk/res/android"
+  xmlns:app="http://schemas.android.com/apk/res-auto"
+  xmlns:tools="http://schemas.android.com/tools"
+  android:layout_width="match_parent"
+  android:layout_height="match_parent"
+  android:orientation="vertical">
+
+  <Toolbar
+    android:id="@+id/toolbar"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?android:attr/colorPrimary"
+    android:elevation="4dp"
+    android:theme="@android:attr/actionBarTheme"/>
+
+  <FrameLayout
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <androidx.recyclerview.widget.RecyclerView
+      android:id="@+id/my_recycler_view"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:scrollbars="vertical"/>
+    <com.google.android.material.floatingactionbutton.FloatingActionButton
+      android:id="@+id/floatingActionButton"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:clickable="true"
+      android:layout_gravity="bottom|end"
+      android:layout_margin="16dp"
+      android:src="@drawable/ic_delete_sweep_black_24dp"
+      android:onClick="onClickActionButton"/>
+  </FrameLayout>
+
+
+</LinearLayout>
+
+
diff --git a/tests/DiagnosticTools/res/layout/row_layout.xml b/tests/DiagnosticTools/res/layout/row_layout.xml
new file mode 100644
index 0000000..62728da
--- /dev/null
+++ b/tests/DiagnosticTools/res/layout/row_layout.xml
@@ -0,0 +1,75 @@
+<?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
+  -->
+
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+  xmlns:app="http://schemas.android.com/apk/res-auto"
+  xmlns:tools="http://schemas.android.com/tools"
+  android:id="@+id/relativeLayout"
+  android:layout_width="match_parent"
+  android:layout_height="wrap_content"
+  android:padding="12dp">
+
+  <CheckBox
+    android:id="@+id/checkBox"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_marginTop="8dp"
+    android:layout_marginBottom="8dp"
+    android:layout_marginEnd="8dp"
+    app:layout_constraintBottom_toBottomOf="parent"
+    app:layout_constraintEnd_toEndOf="parent"
+    app:layout_constraintTop_toTopOf="parent"/>
+
+  <TextView
+    android:id="@+id/firstLine"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:layout_alignWithParentIfMissing="true"
+    android:gravity="center_vertical"
+    android:text="Example application"
+    android:textSize="32sp"
+    app:layout_constraintBottom_toTopOf="@id/secondLine"
+    app:layout_constraintRight_toRightOf="parent"
+    app:layout_constraintTop_toTopOf="parent"/>
+  <TextView
+    android:id="@+id/dtc_number"
+    android:layout_width="wrap_content"
+    android:layout_height="0dp"
+    android:layout_marginEnd="8dp"
+    android:layout_centerHorizontal="true"
+    android:layout_centerVertical="true"
+    android:gravity="center"
+    android:text="TextView"
+    android:textSize="32sp"
+    app:layout_constraintBottom_toBottomOf="parent"
+    app:layout_constraintEnd_toStartOf="@+id/checkBox"
+    app:layout_constraintTop_toTopOf="parent"
+    app:layout_constraintVertical_bias="0.0"/>
+  <TextView
+    android:id="@+id/secondLine"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:ellipsize="marquee"
+    android:singleLine="true"
+    android:text="Description"
+    android:textSize="24sp"
+    android:visibility="visible"
+    app:layout_constraintBottom_toBottomOf="parent"
+    app:layout_constraintRight_toRightOf="parent"
+    app:layout_constraintStart_toStartOf="parent"/>
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/tests/DiagnosticTools/res/raw/system_dtcs.json b/tests/DiagnosticTools/res/raw/system_dtcs.json
new file mode 100644
index 0000000..c41bd28
--- /dev/null
+++ b/tests/DiagnosticTools/res/raw/system_dtcs.json
@@ -0,0 +1,149 @@
+{
+    "P0008": { "short_description":"Engine Position System Performance - Bank 1",  "long_description":"<strong>1. Meaning:<\/strong><br> Bank 1 camshaft and the crankshaft have a variation in mechanical timing. Basically the engine control module (ECM) is experiencing timing issues.<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tDecreased power<br> •\tRough acceleration<br> •\tLower fuel economy<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tTiming chain is experiencing tension<br> •\tTiming chain is stretched<br> •\tCrankshaft reluctor wheel is not referenced to TDC (top dead center)<br> •\tWiring damage<br> •\tWorn out timing components<br> •\tInternal damage to ECM<br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUse an advanced diagnostic tool to pull engine codes<br> •\tVisually inspect the VCT/VVT circuit for open/damaged wires."},
+    "P0010": { "short_description":"Intake Camshaft Position Actuator Circuit / Open (Bank 1)",  "long_description":"<strong>1. Meaning:<\/strong><br> Bank 1 camshaft and the crankshaft have a variation in mechanical timing. The problem occurs when the engine experiences high RPM. The ECM doesn’t properly adjust valve lift at high RPM.<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine performs poorly at high RPM<br> •\tCar runs roughly<br> •\tLower fuel economy<br> •\tCar fails emission test<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tSludge in engine oil<br> •\tFaulty OVC (oil control valve)<br> •\tInternal damage to ECM<br> •\tECM timing is out of sync<br> •\tWiring damage<br> •\tMalfunction of crankshaft or camshaft sensor<br> •\tA short in VCT/VVT circuit, or the circuit is open<br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUse an advanced diagnostic tool to pull engine codes<br> •\tInspect the VVT/VCT solenoid system for dirty oil<br> •\tInspect the circuit for wiring problems"},
+    "P0011": { "short_description":"Intake Camshaft Position Timing - Over-Advanced (Bank 1)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe camshaft timing for bank 1 is above and beyond the limit set by the ECM. This causes an over-advanced condition that occurs either during retarding or advancing of the camshaft timing<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tHard starting<br> •\tPoor idle<br> •\tCar may run rough or stall<br> •\tPoor fuel economy<br> •\tCar may fail emission test<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tCamshaft remains advanced despite ECM commanding it to retard<br> •\tBank 1 oil control solenoid may be clogged or stuck<br> •\tOil may be too thick and is thus blocking passages in bank 1<br> •\tWiring problems in VCT/VVT<br> •\tOil continuously flows to VCT piston chamber<br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck that engine oil is clean and has the recommended viscosity<br> •\tVisually inspect wiring in the CVT system<br> •\tPull engine codes and live data using advanced diagnostic tool"},
+    "P0012": { "short_description":"Intake Camshaft Position Timing - Over-Retarded (Bank 1)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tBank 1 is having an over-retarded timing condition that occurs either during retarding or advancing<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tHard starting<br> •\tPoor fuel economy<br> •\tCar may run rough or stall<br> •\tCar may fail emission test<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tCamshaft timing is incorrect<br> •\tWiring problems in VCT/VVT<br> •\tOil continuously flows to VCT piston chamber<br> •\tTiming valve solenoid control has failed and is stuck in open position<br> •\tOil may be too thick and is thus blocking passages in bank 1<br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck that engine oil is clean<br> •\tVisually inspect wiring in the CVT system<br> •\tPull engine codes and live data using advanced diagnostic tool<br> •\tUsing bidirectional scanner, command the timing valve solenoid control valve to open and close then see if camshaft timings change. If they change it means the valve is not the problem"},
+    "P0014": { "short_description":"Exhaust Camshaft Position Timing - Over-Advanced (Bank 1)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tBank 1 camshaft is having an over-advanced timing condition that occurs either during retarding or advancing<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tHard starting<br> •\tPoor fuel economy<br> •\tCar may run rough or stall<br> •\tCar may fail emission test<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tCamshaft timing is incorrect<br> •\tWiring problems in VCT/VVT<br> •\tOil continuously flows to VCT piston chamber<br> •\tTiming valve solenoid control has failed and is stuck in open position<br> •\tOil may be too thick and is thus blocking passages in bank 1<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck that engine oil is clean and full in the tank<br> •\tVisually inspect wiring in the CVT system<br> •\tPull engine codes and live data using advanced diagnostic tool<br> •\tUsing bidirectional scanner, command the timing valve solenoid control valve to open and close then see if camshaft timings change. If they change it means the valve is not the problem"},
+    "P0016": { "short_description":"Crankshaft Position Camshaft Position Correlation Bank 1 Sensor A",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe crankshaft and camshaft signals are out of time. Meaning the ECM can detect that the timing of the crankshaft and that of the camshaft do not correlate <br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine may crank but fail to start<br> •\tEngine may continue to run but will record poor performance<br> •\tRattling sound in the harmonic balancer<br> •\tPoor fuel economy<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tTiming chain is overstretched<br> •\tTone ring on camshaft and/or crankshaft is has slipped or broken<br> •\tTiming chain has jumped teeth and put camshaft timing out of position<br> •\tProblems with camshaft phaser and putting the phaser out of position<br> •\tWiring to crank/cam sensor is damaged<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tInspect oil control valve (OCV) for connection or wiring problems<br> •\tCheck that engine oil is clean, full and has correct viscosity<br> •\tPull engine codes and live data using advanced diagnostic tool<br> •\tUsing bidirectional scanner, command the OVC on and off then see if camshaft timings change. If they change it means the valve is not the problem"},
+    "P0021": { "short_description":"Intake Camshaft Position Timing - Over-Advanced (Bank 2)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe camshaft timing for bank 2 is above and beyond the limit set by the ECM. This causes an over-advanced condition that occurs either during retarding or advancing of the camshaft timing<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tHard starting<br> •\tPoor idle<br> •\tCar may run rough or stall<br> •\tPoor fuel economy<br> •\tCar may fail emission test<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tCamshaft remains advanced despite ECM commanding it to retard<br> •\tBank 2 oil control solenoid may be clogged or stuck<br> •\tOil may be too thick and is thus blocking passages in bank 2<br> •\tWiring problems in VCT/VVT<br> •\tOil continuously flows to VCT piston chamber<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck that engine oil is clean and has the recommended viscosity<br> •\tVisually inspect wiring in the CVT system<br> •\tPull engine codes and live data using advanced diagnostic tool"},
+    "P0022": { "short_description":"“A” camshaft position – timing over-retarded (Bank 2)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe camshaft timing for bank 2 is over-retarded<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tCar stalls<br> •\tCar hard starts<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tCamshaft remains retarded despite ECM commanding it to advance<br> •\tWiring problems in VCT/VVT<br> •\tOil continuously flows to VCT piston chamber<br> •\tTiming valve controlled solenoid has failed and remains open<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect wiring in the CVT system<br> •\tPull engine codes and live data using advanced diagnostic tool<br> •\tReset the codes. If P0022 returns use a bidirectional tool to check whether VCT solenoid is working"},
+    "P0030": { "short_description":"Heated Oxygen Sensor (H02S) Heater Control Circuit Bank 1 Sensor 1",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tBank 1, sensor 1 of the O2 sensor heater circuit is faulty. As such, the engine isn’t achieving closed loop and therefore the car has increased emissions<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tLonger time needed to achieve closed loop<br> •\tDecreased fuel economy<br> •\tEngine may go into fixed fuel mix<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tH02S sensor in bank 1, circuit 1 is not sending the correct signal to ECM<br> •\tDamaged or failed element in heater circuit<br> •\tOpen in O2 sensor heater’s circuit<br> •\tOpen/short in O2 sensor heater’s battery<br> •\tDefective ECM (this is the least likely cause)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tInspect wiring and power to the O2 sensor and ensure there’s no damage/open/short<br> •\tUse code reader to pull engine codes<br> •\tCheck voltage of O2 sensor and ensure it matches manufacturer’s specs<br> •\tReplace O2 sensor if necessary"},
+    "P0031": { "short_description":"Heated Oxygen Sensor (HO2S) Heater Circuit Low Voltage Bank 1 Sensor 1",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe resistance of the heater circuit in bank 1 is too low to heat fuel until it achieves air to fuel ratio of 14:7. The problem is coming from the 1st sensor of bank 1. This code is usually triggered when resistance level is below 0.8A<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tAlthough not always, ECM may enter failsafe mode<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tShort or open in the O2 heater circuit<br> •\tDefective O2 sensor heater<br> •\tThere’s a wiring problem in the circuit leading to the heater. It may be broken or frayed<br> •\tDefective ECM (this is the least likely cause)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tInspect wiring and power to the O2 sensor and ensure there’s no damage/open/short<br> •\tUse code reader to pull engine codes"},
+    "P0037": { "short_description":"Heated Oxygen Sensor (H02S) Heater Control Circuit Bank 1 Sensor 2",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tBank 1, sensor 2 of the O2 sensor heater circuit is faulty. As such, the engine isn’t achieving closed loop and therefore the car has increased emissions<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tLonger time needed to achieve closed loop<br> •\tDecreased fuel economy<br> •\tEngine may go into fixed fuel mix<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tH02S sensor in bank 1, circuit 2 is not sending the correct signal to ECM<br> •\tDamaged or failed element in heater circuit<br> •\tOpen in O2 sensor heater’s circuit<br> •\tOpen/short in O2 sensor heater’s battery<br> •\tDefective ECM (this is the least likely cause)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tInspect wiring and power to the O2 sensor and ensure there’s no damage/open/short<br> •\tUse code reader to pull engine codes<br> •\tCheck voltage of O2 sensor and ensure it matches manufacturer’s specs<br> •\tReplace O2 sensor if necessary"},
+    "P0087": { "short_description":"Fuel Rail/System Pressure - Too Low",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe ECM has determined that the pressure of fuel going to the fuel pump module is below the pressure that was commanded by the ECM<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tVehicle may have a rich fuel condition<br> •\tIt may also misfire<br> •\tVehicle may run poorly<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tClogged fuel filter or fuel screen<br> •\tDefective fuel pressure sensor<br> •\tDefective fuel pump<br> •\tFault in fuel line that’s causing a restriction<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUse code reader to pull engine codes<br> •\tVisually inspect fuel tank, fuel filter and fuel lines<br> •\tTake manual readings of fuel pressure and compare with specifications<br> •\tRun a fuel pump test"},
+    "P0102": { "short_description":"Mass or Volume Air Flow Circuit low Input",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe mass airflow (MAF) sensor is not performing within the normal expectation and is therefore sending a lower signal than normal (due to low voltage)<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tExtremely low fuel consumption and thus internal engine problems<br> •\tEngine runs roughly<br> •\tCar idles and stalls frequently<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective MAF sensor<br> •\tPresence of dirt and debris in MAF (restricts airflow)<br> •\tLeaks in air intake system<br> •\tImproper wiring of the circuit to MAF sensor<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUse code reader to pull engine codes <br> •\tVisually inspect MAF sensor wiring and circuit<br> •\tCheck for air leaks in air intake system<br> •\tInspect MAF to see if there’s dirt and debris"},
+    "P0106": { "short_description":"Manifold Absolute Pressure/Barometric Pressure Circuit Range/Performance Problem",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe Powertrain Control Module (PCM) has not detected a change in engine speed, throttle angle and/or exhaust gas recirculation (EGR) despite an increase in manifold absolute pressure (MAP). Increase in MAP indicates increase in engine load<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tPoor fuel economy<br> •\tEngine fails to idle<br> •\tEngine produces black smoke (visible at tailpipe)<br> •\tErratic acceleration<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tFaulty MAP sensor<br> •\tAir intake component is loose, cracked or doesn’t have its plastic fitting<br> •\tWater or dirt affecting connector to MAP sensor<br> •\tCorrosion may be causing poor signal to and from MAP sensor<br> •\tPCM is defective (least likely but not unlikely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUse an advanced scanner to pull engine codes <br> •\tWith that scanner, take the reading of MAP sensor when engine is off but key is on. It should be similar or close to barometric pressure (BARO) reading<br> •\tStart the engine and see if MAP sensor readings drop significantly. If they do the sensor is working properly "},
+    "P0107": { "short_description":"Manifold Absolute Pressure/Barometric Pressure Circuit Low Input",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected that the voltage in the MAP sensor is less than .25 volts, which is too low to send a reliable signal<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tVehicle is hard to start<br> •\tPoor fuel economy<br> •\tEngine fails to idle<br> •\tEngine produces black smoke (visible at tailpipe)<br> •\tEngine cranks for long<br> •\tErratic acceleration<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tFaulty MAP sensor<br> •\tOpen or short in signal circuit, 5volt reference circuit or ground circuit<br> •\tPCM is defective (least likely but not unlikely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUse an advanced scanner to pull engine codes <br> •\tWith that scanner, take the voltage of MAP sensor when engine is on and key is on. If it’s less than .5V turn the engine off, remove the MAP sensor and use a volt/ohm meter to check for 5 volts on the 5 volt reference circuit"},
+    "P0108": { "short_description":"Manifold Absolute Pressure/Barometric Pressure Circuit High Input",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected that the voltage in the MAP sensor is more than 5 volts or generally more than commanded under the prevailing circumstance<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tPoor fuel economy<br> •\tEngine fails to idle and may not start completely<br> •\tEngine produces black smoke (visible at tailpipe)<br> •\tEngine cranks for long<br> •\tErratic acceleration<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tFaulty MAP sensor<br> •\tOpen or short in signal circuit, 5volt reference circuit or ground circuit<br> •\tLeak in vacuum system, especially in the engine or supply line to MAP sensor<br> •\tPCM is defective (least likely but not unlikely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUse an advanced scanner to pull engine codes <br> •\tWith that scanner, take the reading of MAP sensor when engine is off but key is on. It should be similar or close to barometric pressure (BARO) reading<br> •\tIf the difference between the two readings is more than .5 then you’re looking at a faulty MAP sensor"},
+    "P0113": { "short_description":"Intake Air Temperature Circuit High Input",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe PCM has detected that the signal voltage from the intake air temperature (IAT) is above 5V, which is more than the expected range<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine may run extra lean<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective IAT sensor<br> •\tLoose or faulty wiring at IAT sensor<br> •\tOpen or short in IAT ground circuit, signal circuit or reference circuit<br> •\tPCM is defective (least likely but not unlikely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUse an advanced scanner to pull engine codes.<br> •\tView live data from the IAT sensor. If the reading is less than -30 degrees then the sensor is likely to be faulty. If otherwise then it’s probably an intermittent problem<br> •\tCheck the wiring for opens and loose connections"},
+    "P0116": { "short_description":"Engine Coolant Temperature Circuit Range/Performance Problem",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe PCM has seen a sudden and quick change in engine coolant temperature (ECT) at a time when there shouldn’t be such a change<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tPoor fuel economy<br> •\tEngine fails to idle and may not start completely<br> •\tEngine produces black smoke (visible at tailpipe)<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tThermostat is either missing or open<br> •\tDefective ECT sensor<br> •\tOpen or short in ECT signal or ground circuit<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUsing an OBD2 scanner, start by diagnosing and resetting any other ECT codes<br> •\tNow, check the ECT reading. When the engine is cold the reading should match ambient temperature reading. If it doesn’t then there’s a problem with the ECT sensor"},
+    "P0118": { "short_description":"Engine Coolant Temperature Circuit High Input",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe PCM has determined that ECT is less than freezing temp yet the engine has been running for several minutes, which shouldn’t happen<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tPoor fuel economy<br> •\tEngine fails to idle and may not start completely<br> •\tEngine produces black smoke (visible at tailpipe)<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective ECT sensor<br> •\tOpen or short in ECT signal or ground circuit<br> •\tPCM is defective (least likely but not unlikely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUsing an OBD2 scanner, check the reading of ECT. If it’s a logical reading then the problem is intermittent<br> •\tPerform a wiggle test while looking out for drop-outs. If there are any then there’s a bad connection to or from the ECT sensor"},
+    "P0121": { "short_description":"Throttle/Pedal Position Sensor/Switch A Circuit Range/Performance Problem",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe PCM has detected that the throttle position sensor (TPS) voltage is more or less than it should be for the current RPM<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tCar produces black smoke (visible at tailpipe)<br> •\tCar stumbles when you accelerate or decelerate<br> •\tEngine may fail to start completely<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective TPS<br> •\tOpen or short in TPS circuit<br> •\tLoose or bad connection to TPS<br> •\tPCM is defective (least likely but not unlikely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to TPS for loose, open or short connections <br> •\tUsing an OBD2 scanner, check for live and freeze frame data from TPS. If it doesn’t read .5 at idle and 4.5 at full throttle the TPS is faulty"},
+    "P0122": { "short_description":"Throttle/Pedal Position Sensor/Switch A Circuit Low Input",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM is reporting that the TPS has recorded a voltage that is lower than the normal minimum limit. The value varies from one car to another but the code may come when the voltage hits .20V or less<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tExtremely high idle<br> •\tRough or low idle<br> •\tCar stalls<br> •\tAcceleration is low or completely lacking<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective TPS<br> •\tOpen or short in TPS circuit<br> •\tImproper mounting of TPS after replacement<br> •\tTPS has loosened<br> •\tPCM is defective (least likely but not unlikely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to TPS for loose, open or short connections<br> •\tCheck that TPS is tightly in position, especially if you recently replaced it"},
+    "P0123": { "short_description":"Throttle/Pedal Position Sensor/Switch A Circuit High Input",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM is reporting that the TPS has recorded a voltage that is higher than the normal maximum limit, usually around 5 volts<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tExtremely high idle<br> •\tRough or low idle<br> •\tFrequent surges<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective TPS<br> •\tOpen or short in TPS circuit<br> •\tImproper mounting of TPS after replacement<br> •\tPCM is defective (least likely but not unlikely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to TPS for loose, open or short connections<br> •\tCheck that TPS is tightly in position, especially if you recently replaced it"},
+    "P0128": { "short_description":"Coolant Thermostat (Coolant Temp Below Thermostat Regulating Temperature)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected that the engine has not attained the required temperature despite being on for enough time to attain that temperature<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light MAY come on<br> •\tEngine temp drops when the vehicle is in high speed<br> •\tEngine takes abnormally long to warm<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tMost likely cause is that thermostat is leaking or stuck in open position<br> •\tEngine coolant level is too low<br> •\tDefective IAT sensor<br> •\tDefective ECT sensor<br> •\tDefective cooling fan<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck whether coolant strength and level are in the recommended range<br> •\tCheck whether IAT sensor, ECT sensor and coolant fan are working<br> •\tIf all the above are okay then the thermostat is the problem"},
+    "P0130": { "short_description":"O2 Sensor Circuit Malfunction (Bank 1 Sensor 1)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tECM has determined that the O2 sensor voltage remained lower than normal (below .4v) for too long (20 seconds or more)<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tCar produces black smoke (visible at tailpipe)<br> •\tPoor fuel economy<br> •\tEngine may fail to start completely<br> •\tIf it starts it may run rough and/or stumble<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tMostly a problem related to corrosion, loose terminal or burnt wire in the O2 sensor connector<br> •\tDefective O2 sensor<br> •\tOpen or short in wiring to O2 sensor<br> •\tUnmetered oxygen is getting back into exhaust system, most likely from holes in the system<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to O2 sensor for loose, open or short connections<br> •\tUse a wiggle test to determine where the voltage drops out<br> •\tUsing an OBD2 scanner, check whether sensor 1 of bank 1 is switching properly. Normally it should switch evenly between rich and lean in rapid successions"},
+    "P0131": { "short_description":"O2 Sensor Circuit Low Voltage (Bank 1 Sensor 1)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tECM has determined that there’s a low voltage condition in bank 1 sensor 1; i.e. O2 sensor voltage remained too low for longer than 2 minutes<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tCar produces black smoke (visible at tailpipe)<br> •\tPoor fuel economy<br> •\tEngine may fail to start completely<br> •\tIf it starts it may run rough and/or stumble<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tMostly a problem related to corrosion, loose terminal or burnt wire in the O2 sensor 1 connector<br> •\tDefective O2 sensor<br> •\tOpen or short in wiring to O2 sensor<br> •\tO2 circuit is experiencing high resistance<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to O2 sensor 1 for loose, open or short connections<br> •\tUse a wiggle test to determine where the voltage drops out<br> •\tUsing an OBD2 scanner, check whether sensor 1 of bank 1 is switching properly."},
+    "P0132": { "short_description":"O2 Sensor Circuit High Voltage (Bank 1 Sensor 1)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe heated O2 sensor in bank 1 sensor 1 is giving a higher voltage reading than it should. For most vehicles the code comes when voltage exceeds 1.5V<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tGenerally doesn’t come with symptoms. However, in some cases the Check Engine Light may come on and fuel economy may reduce<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tFuel temp is excessively high<br> •\tShort, open or broken wire in O2 sensor circuit<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to O2 sensor for loose, open or short connections<br> •\tUse a wiggle test to determine where the voltage drops out<br> •\tUsing an OBD2 scanner, check whether sensor 1 of bank 1 is switching properly."},
+    "P0133": { "short_description":"O2 Sensor Circuit Slow Response (Bank 1 Sensor 1)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tO2 sensor or ECM can’t adjust air to fuel ratio as it’s supposed to even when the engine is running<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tGenerally doesn’t come with symptoms. However, in some cases the Check Engine Light may come on and fuel economy may reduce<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tFirst O2 sensor in bank 1 is faulty<br> •\tShort, open or broken wire in O2 sensor circuit<br> •\tExhaust leak<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to first O2 sensor for loose, open or short connections<br> •\tUse a wiggle test to determine where the voltage drops out<br> •\tVisually check for exhaust leaks or air inlet leaks<br> •\tUsing an OBD2 scanner, check whether sensor 1 of bank 1 is switching properly."},
+    "P0134": { "short_description":"O2 Sensor Circuit No Activity Detected (Bank 1 Sensor 1)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has perceived that first O2 sensor in bank 1 is inactive or open because it has not warmed up after more than 1 minute of the engine running<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tCar produces black smoke (visible at tailpipe)<br> •\tPoor fuel economy<br> •\tEngine may run rough and/or stumble<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tFaulty O2 sensor<br> •\tShort, open or broken wire in O2 sensor circuit<br> •\tExhaust leak<br> •\tDefective heater circuit in O2 sensor<br> •\tHeater circuit has blown fuse<br> •\tPCM is defective (least likely but not unlikely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to first O2 sensor (bank 1) for loose, open or short connections<br> •\tUse a wiggle test to determine where the voltage drops out<br> •\tVisually check for exhaust leaks or air inlet leaks"},
+    "P0135": { "short_description":"O2 Sensor Heater Circuit Malfunction (Bank 1 Sensor 1)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tUsually, when O2 heater attains operating temperature, O2 sensor switches based on ambient temp. If ECM determines that the O2 sensor took too long to switch this code is set. It applies to the first sensor of bank 1<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tPoor fuel economy<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tShort, open or broken wire in O2 heating system<br> •\tHigh resistance in O2 heater element or circuit<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to first O2 sensor (bank 1) for loose, open or short connections<br> •\tUse a wiggle test to determine where the voltage drops out<br> •\tIf the code is persistent replace O2 sensor<br> "},
+    "P0136": { "short_description":"O2 Sensor Circuit Malfunction (Bank 1 Sensor 2)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tECM has determined that the there’s a low voltage condition in bank 1 sensor 2; i.e. O2 sensor voltage remained too low for longer than 2 minutes<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tCar produces black smoke (visible at tailpipe)<br> •\tPoor fuel economy<br> •\tEngine may fail to start completely<br> •\tIf it starts it may run rough and/or stumble<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tMostly a problem related to corrosion, loose terminal or burnt wire in the O2 sensor 2 connector<br> •\tDefective O2 sensor<br> •\tOpen or short in wiring to O2 sensor<br> •\tO2 circuit is experiencing high resistance<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to O2 sensor 2 for loose, open or short connections<br> •\tUse a wiggle test to determine where the voltage drops out<br> •\tUsing an OBD2 scanner, check whether sensor 2 of bank 1 is switching properly."},
+    "P0137": { "short_description":"O2 Sensor Circuit Low Voltage (Bank 1 Sensor 2)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tBasically same as P0136. The PCM has detected that the O2 sensor may be inactive<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tGenerally doesn’t come with symptoms. However, in some cases the Check Engine Light may come on and fuel economy may reduce<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tFaulty O2 sensor<br> •\tShort, open or broken wire in O2 sensor circuit<br> •\tDefective heater circuit in O2 sensor<br> •\tHigh resistance in O2 heater element or circuit<br> •\tFaulty fuel pump regulator resulting in very high or very low fuel pressure<br> •\tExhaust leak<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to O2 sensor for loose, open or short connections<br> •\tUse a wiggle test to determine where the voltage drops out<br> •\tVisually check for exhaust leaks or air inlet leaks<br> •\tIf the code is persistent replace O2 sensor"},
+    "P0138": { "short_description":"O2 Sensor Circuit High Voltage (Bank 1 Sensor 2)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe heated O2 sensor in bank 1 sensor 2 is giving a higher voltage reading than it should. For most vehicles the code comes when voltage exceeds 1.5V<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tGenerally doesn’t come with symptoms. However, in some cases the Check Engine Light may come on and fuel economy may reduce<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tFuel temp is excessively high<br> •\tShort, open or broken wire in O2 sensor circuit<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to O2 sensor for loose, open or short connections<br> •\tUse a wiggle test to determine where the voltage drops out<br> •\tUsing an OBD2 scanner, check whether sensor 1 of bank 2 is switching properly."},
+    "P0139": { "short_description":"O2 Sensor Circuit Slow Response (Bank 1 Sensor 2)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tO2 sensor or ECM can’t adjust air to fuel ratio as it’s supposed to even when the engine is running<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tGenerally doesn’t come with symptoms. However, in some cases the Check Engine Light may come on and fuel economy may reduce<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tSecond O2 sensor in bank 1 is faulty<br> •\tShort, open or broken wire in O2 sensor circuit<br> •\tExhaust leak<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to second O2 sensor for loose, open or short connections<br> •\tUse a wiggle test to determine where the voltage drops out<br> •\tVisually check for exhaust leaks or air inlet leaks<br> •\tUsing an OBD2 scanner, check whether sensor 2 of bank 1 is switching properly."},
+    "P0140": { "short_description":"O2 Sensor Circuit No Activity Detected (Bank 2 Sensor 2)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has perceived that second O2 sensor in bank 2 is inactive or open because it has not warmed up after more than 1 minute of the engine running<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tCar produces black smoke (visible at tailpipe)<br> •\tPoor fuel economy<br> •\tEngine may run rough and/or stumble<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tFaulty O2 sensor<br> •\tShort, open or broken wire in O2 sensor circuit<br> •\tExhaust leak<br> •\tDefective heater circuit in O2 sensor<br> •\tHeater circuit has blown fuse<br> •\tPCM is defective (least likely but not unlikely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to second O2 sensor (in bank 2) for loose, open or short connections<br> •\tUse a wiggle test to determine where the voltage drops out<br> •\tVisually check for exhaust leaks or air inlet leaks"},
+    "P0141": { "short_description":"O2 Sensor Heater Circuit Malfunction (Bank 1 Sensor 2)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tWhen O2 heater attains operating temperature, O2 sensor switches based on ambient temp. If ECM determines that the O2 sensor took too long to switch this code is set. It applies to the second sensor of bank 1<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tPoor fuel economy<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tShort, open or broken wire in O2 heating system<br> •\tHigh resistance in O2 heater element or circuit<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to second O2 sensor (bank 1) for loose, open or short connections<br> •\tUse a wiggle test to determine where the voltage drops out<br> •\tIf the code is persistent replace O2 sensor"},
+    "P0151": { "short_description":"O2 Sensor Circuit Low Voltage (Bank 2 Sensor 1)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tECM has determined that there’s a low voltage condition in bank 2 sensor 1; i.e. O2 sensor voltage remained too low for longer than 2 minutes<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tCar produces black smoke (visible at tailpipe)<br> •\tPoor fuel economy<br> •\tEngine may fail to start completely<br> •\tIf it starts it may run rough and/or stumble<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tMostly a problem related to corrosion, loose terminal or burnt wire in the O2 sensor 2 connector<br> •\tDefective O2 sensor<br> •\tOpen or short in wiring to O2 sensor<br> •\tO2 circuit is experiencing high resistance<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to O2 sensor 1 for loose, open or short connections<br> •\tUse a wiggle test to determine where the voltage drops out<br> •\tUsing an OBD2 scanner, check whether sensor 1 of bank 2 is switching properly."},
+    "P0153": { "short_description":"O2 Sensor Circuit Slow Response (Bank 2 Sensor 1)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tO2 sensor or ECM can’t adjust air to fuel ratio as it’s supposed to even when the engine is runningc<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tGenerally doesn’t come with symptoms. However, in some cases the Check Engine Light may come on and fuel economy may reduce<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tFirst O2 sensor in bank 2 is faulty<br> •\tShort, open or broken wire in O2 sensor circuit<br> •\tExhaust leak<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to second O2 sensor for loose, open or short connections<br> •\tUse a wiggle test to determine where the voltage drops out<br> •\tVisually check for exhaust leaks or air inlet leaks<br> •\tUsing an OBD2 scanner, check whether sensor 1 of bank 2 is switching properly."},
+    "P0154": { "short_description":"O2 Sensor Circuit No Activity Detected (Bank 2 Sensor 1)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has perceived that first O2 sensor in bank 2 is inactive or open because it has not warmed up after more than 1 minute of the engine running<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tCar produces black smoke (visible at tailpipe)<br> •\tPoor fuel economy<br> •\tEngine may run rough and/or stumble<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tFaulty O2 sensor<br> •\tShort, open or broken wire in O2 sensor circuit<br> •\tExhaust leak<br> •\tDefective heater circuit in O2 sensor<br> •\tHeater circuit has blown fuse<br> •\tPCM is defective (least likely but not unlikely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to first O2 sensor (bank 2) for loose, open or short connections<br> •\tUse a wiggle test to determine where the voltage drops out<br> •\tVisually check for exhaust leaks or air inlet leaks"},
+    "P0157": { "short_description":"O2 Sensor Circuit Low Voltage (Bank 2 Sensor 2)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tECM has determined that there’s a low voltage condition in bank 2 sensor 2; i.e. O2 sensor voltage remained too low for longer than 2 minutes<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tCar produces black smoke (visible at tailpipe)<br> •\tPoor fuel economy<br> •\tEngine may fail to start completely<br> •\tIf it starts it may run rough and/or stumble<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tMostly a problem related to corrosion, loose terminal or burnt wire in the O2 sensor 2 connector<br> •\tDefective O2 sensor<br> •\tOpen or short in wiring to O2 sensor<br> •\tO2 circuit is experiencing high resistance<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to O2 sensor 2 for loose, open or short connections<br> •\tUse a wiggle test to determine where the voltage drops out<br> •\tUsing an OBD2 scanner, check whether sensor 2 of bank 2 is switching properly."},
+    "P0161": { "short_description":"O2 Sensor Heater Circuit Malfunction (Bank 2 Sensor 2)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tWhen O2 heater attains operating temperature, O2 sensor switches based on ambient temp. If ECM determines that the O2 sensor took too long to switch this code is set. It applies to the second sensor of bank 2<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tPoor fuel economy<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tShort, open or broken wire in O2 heating system<br> •\tHigh resistance in O2 heater element or circuit<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to second O2 sensor (bank 2) for loose, open or short connections<br> •\tUse a wiggle test to determine where the voltage drops out<br> •\tIf the code is persistent replace O2 sensor"},
+    "P0171": { "short_description":"System Too Lean (Bank 1)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThere’s a lean condition in bank 1; i.e. there’s excess oxygen in the exhaust<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tSignificant decrease in engine power<br> •\tCar hesitates then surges upon acceleration<br> •\tRough idle<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDirty or defective MAF sensor<br> •\tMAF sensor has a vacuum leak<br> •\tPositive Crankcase Ventilation (PCV) valve is stuck in open position<br> •\tLeak either in PCV or vacuum system<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tInspect MAF sensor in bank 1 for dirt and debris<br> •\tCheck whether fuel pressure is correct<br> •\tCheck vacuum and PCV for leaks<br> •\tRun a smog test using OBD2 scanner"},
+    "P0172": { "short_description":"System Too Rich (Bank 1)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThere’s a rich condition in bank 1; i.e. there’s too little oxygen in the exhaust<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tGenerally doesn’t come with symptoms but the Check Engine Light may come on and engine may misfire<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDirty or defective MAF sensor<br> •\tMAF sensor has a vacuum leak<br> •\tProblem relating to fuel pressure or delivery<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tInspect MAF sensor in bank 1 for dirt and debris<br> •\tCheck whether fuel pressure is correct<br> •\tInspect fuel lines and injectors for any leaks/openings and dirt<br> •\tCheck vacuum, PCV and exhaust for leaks<br> •\tRun a smog test using OBD2 scanner"},
+    "P0174": { "short_description":"System Too Lean (Bank 2)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThere’s a lean condition in bank 2; i.e. there’s excess oxygen in the exhaust<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tSignificant decrease in engine power<br> •\tCar hesitates then surges upon acceleration<br> •\tRough idle<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDirty or defective MAF sensor<br> •\tMAF sensor has a vacuum leak<br> •\tPositive Crankcase Ventilation (PCV) valve is stuck in open position<br> •\tLeak either in PCV or vacuum system<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tInspect MAF sensor in bank 2 for dirt and debris<br> •\tCheck whether fuel pressure is correct<br> •\tCheck vacuum and PCV for leaks<br> •\tRun a smog test using OBD2 scanner"},
+    "P0175": { "short_description":"System Too Rich (Bank 2)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThere’s a rich condition in bank 2; i.e. there’s too little oxygen in the exhaust<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tGenerally doesn’t come with symptoms but the Check Engine Light may come on and engine may misfire<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDirty or defective MAF sensor<br> •\tMAF sensor has a vacuum leak<br> •\tProblem relating to fuel pressure or delivery<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tInspect MAF sensor in bank 2 for dirt and debris<br> •\tCheck whether fuel pressure is correct<br> •\tInspect fuel lines and injectors for any leaks/openings and dirt<br> •\tCheck vacuum, PCV and exhaust for leaks<br> •\tRun a smog test using OBD2 scanner"},
+    "P0193": { "short_description":"Fuel Rail Pressure Sensor Circuit High Input",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe PCM has detected that the pressure of fuel is not within the range that’s predetermined by the car manufacturer <br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine cranks but doesn’t start<br> •\tCar hesitates upon acceleration<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective fuel rail pressure (FRP) sensor<br> •\tDefective fuel pump<br> •\tOpen or short in FRP circuit<br> •\tLow or no fuel in tank<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tInspect all wiring and connections in FRP circuit and check for shorts, opens, broken and melted wires<br> •\tCheck for corroded or burnt terminals in connectors<br> •\tUse a scan tool to pull codes and freeze frame data"},
+    "P0300": { "short_description":"Random/Multiple Cylinder Misfire Detected",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected that there’s an engine cylinder that’s not firing properly. It could be one or more cylinders. PCM hasn’t specified the exact cylinder<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tCheck Engine Light may flash<br> •\tEngine lacks power<br> •\tEngine may be hard to start<br> •\tEngine may stumble and hesitate frequently<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective or worn out spark plugs<br> •\tLow fuel pressure<br> •\tVacuum leak<br> •\tDefective catalytic converter<br> •\tDefective fuel injector<br> •\tDefective coil<br> •\tDefective camshaft position sensor<br> •\tDefective crankshaft sensor<br> •\tProblem with distributor<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUsing a scan tool, pull codes and see if there are any other besides P0300. Address the others first<br> •\tInspect whether there are loose, open or short wires in ignition coils<br> •\tInspect whether spark plugs and their wires are in good condition<br> •\tCheck that fuel pressure is within the recommended range<br> •\tInspect fuel injectors to see whether they are in good condition"},
+    "P0301": { "short_description":"Cylinder 1 Misfire Detected",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected that cylinder #1 is not firing properly<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tCheck Engine Light may flash<br> •\tEngine lacks power<br> •\tEngine may be hard to start<br> •\tEngine may stumble and hesitate frequently<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective or worn out spark plugs in cylinder 1<br> •\tLow fuel pressure<br> •\tVacuum leak<br> •\tDefective catalytic converter<br> •\tDefective fuel injector<br> •\tDefective coil<br> •\tDefective camshaft position sensor<br> •\tDefective crankshaft sensor<br> •\tProblem with distributor<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUsing a scan tool, pull codes and see if there are any other besides P0301. Address the others first<br> •\tInspect whether there are loose, open or short wires in ignition coils in cylinder 1<br> •\tInspect whether cylinder 1 spark plugs and their wires are in good condition<br> •\tCheck that fuel pressure is within the recommended range<br> •\tInspect fuel injectors to see whether they are in good condition"},
+    "P0302": { "short_description":"Cylinder 2 Misfire Detected",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected that cylinder #2 is not firing properly<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tCheck Engine Light may flash<br> •\tEngine lacks power<br> •\tEngine may be hard to start<br> •\tEngine may stumble and hesitate frequently<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective or worn out spark plugs in cylinder 2<br> •\tLow fuel pressure<br> •\tVacuum leak<br> •\tDefective catalytic converter<br> •\tDefective fuel injector<br> •\tDefective coil<br> •\tDefective camshaft position sensor<br> •\tDefective crankshaft sensor<br> •\tProblem with distributor<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUsing a scan tool, pull codes and see if there are any other besides P0302. Address the others first<br> •\tInspect whether there are loose, open or short wires in ignition coils in cylinder 2<br> •\tInspect whether cylinder 2 spark plugs and their wires are in good condition<br> •\tCheck that fuel pressure is within the recommended range<br> •\tInspect fuel injectors to see whether they are in good condition"},
+    "P0303": { "short_description":"Cylinder 3 Misfire Detected",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected that cylinder #3 is not firing properly<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tCheck Engine Light may flash<br> •\tEngine lacks power<br> •\tEngine may be hard to start<br> •\tEngine may stumble and hesitate frequently<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective or worn out spark plugs in cylinder 3<br> •\tLow fuel pressure<br> •\tVacuum leak<br> •\tDefective catalytic converter<br> •\tDefective fuel injector<br> •\tDefective coil<br> •\tDefective camshaft position sensor<br> •\tDefective crankshaft sensor<br> •\tProblem with distributor<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUsing a scan tool, pull codes and see if there are any other besides P0303. Address the others first<br> •\tInspect whether there are loose, open or short wires in ignition coils in cylinder 3<br> •\tInspect whether cylinder 3 spark plugs and their wires are in good condition<br> •\tCheck that fuel pressure is within the recommended range<br> •\tInspect fuel injectors to see whether they are in good condition"},
+    "P0304": { "short_description":"Cylinder 4 Misfire Detected",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected that cylinder #4 is not firing properly<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tCheck Engine Light may flash<br> •\tEngine lacks power<br> •\tEngine may be hard to start<br> •\tEngine may stumble and hesitate frequently<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective or worn out spark plugs in cylinder 4<br> •\tLow fuel pressure<br> •\tVacuum leak<br> •\tDefective catalytic converter<br> •\tDefective fuel injector<br> •\tDefective coil<br> •\tDefective camshaft position sensor<br> •\tDefective crankshaft sensor<br> •\tProblem with distributor<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUsing a scan tool, pull codes and see if there are any other besides P0304. Address the others first<br> •\tInspect whether there are loose, open or short wires in ignition coils in cylinder 4<br> •\tInspect whether cylinder 4 spark plugs and their wires are in good condition<br> •\tCheck that fuel pressure is within the recommended range<br> •\tInspect fuel injectors to see whether they are in good condition"},
+    "P0305": { "short_description":"Cylinder 5 Misfire Detected",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected that cylinder #5 is not firing properly<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tCheck Engine Light may flash<br> •\tEngine lacks power<br> •\tEngine may be hard to start<br> •\tEngine may stumble and hesitate frequently<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective or worn out spark plugs in cylinder 5<br> •\tLow fuel pressure<br> •\tVacuum leak<br> •\tDefective catalytic converter<br> •\tDefective fuel injector<br> •\tDefective coil<br> •\tDefective camshaft position sensor<br> •\tDefective crankshaft sensor<br> •\tProblem with distributor<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUsing a scan tool, pull codes and see if there are any other besides P0305. Address the others first<br> •\tInspect whether there are loose, open or short wires in ignition coils in cylinder 5<br> •\tInspect whether cylinder 5 spark plugs and their wires are in good condition<br> •\tCheck that fuel pressure is within the recommended range<br> •\tInspect fuel injectors to see whether they are in good condition"},
+    "P0306": { "short_description":"Cylinder 6 Misfire Detected",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected that cylinder #6 is not firing properly<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tCheck Engine Light may flash<br> •\tEngine lacks power<br> •\tEngine may be hard to start<br> •\tEngine may stumble and hesitate frequently<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective or worn out spark plugs in cylinder 6<br> •\tLow fuel pressure<br> •\tVacuum leak<br> •\tDefective catalytic converter<br> •\tDefective fuel injector<br> •\tDefective coil<br> •\tDefective camshaft position sensor<br> •\tDefective crankshaft sensor<br> •\tProblem with distributor<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUsing a scan tool, pull codes and see if there are any other besides P0306. Address the others first<br> •\tInspect whether there are loose, open or short wires in ignition coils in cylinder 6<br> •\tInspect whether cylinder 6 spark plugs and their wires are in good condition<br> •\tCheck that fuel pressure is within the recommended range<br> •\tInspect fuel injectors to see whether they are in good condition"},
+    "P0316": { "short_description":"Misfire Detected On Startup (First 1000 Revolutions)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected a misfire less than 1,000 revolutions after startup<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine lacks power<br> •\tRough idle<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective or worn out spark plugs<br> •\tNo fuel<br> •\tLow fuel pressure<br> •\tVacuum leak<br> •\tDefective catalytic converter<br> •\tDefective fuel injector<br> •\tDefective coil<br> •\tDefective crankshaft sensor<br> •\tWiring fault in crankshaft position sensor<br> •\tProblem with PCM<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tPull all codes then address other misfire codes first<br> •\tCheck all wiring and connectors in crankshaft and camshaft position sensors<br> •\tReview freeze frame data to narrow down the problem further"},
+    "P0320": { "short_description":"Ignition/Distributor Engine Speed Input Circuit Malfunction",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThere’s an electrical circuit fault in either the crankshaft position (CKP) sensor or camshaft position (CMP) sensor<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine cranks but doesn’t start<br> •\tEngine lacks power<br> •\tEngine misfires, hesitates and stumbles<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tOpen or short in power supply circuit and/or control circuit between PCM and ignition/distributor/engine speed sensor<br> •\tDefective ignition/distributor/engine speed sensor<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck that all the connectors and wiring to ignition/distributor/engine speed sensors are in good condition<br> •\tRemove connectors and see if their terminals are burnt/corroded<br> •\tPull and reset P0320 code, drive the car for several minutes and see if the code returns. If it does then probably a sensor needs replacing"},
+    "P0325": { "short_description":"Knock Sensor 1 Circuit Malfunction (Bank 1 or Single Sensor)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected that the engine’s knock sensor 1 in circuit bank 1 is not working properly<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tGenerally doesn’t come with symptoms but Check Engine Light may come on.<br> •\tEngine may also lose power<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tFirst sensor in circuit bank 1 may be faulty<br> •\tOpen or short in wiring to the sensor<br> •\tProblem with engine coolant<br> •\tEngine is excessively lean<br> •\tPCM has failed (least likely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to knock sensor 1 in circuit bank 1. Ensure there are no shorts or open wires<br> •\tView coolant temp data to check for issues<br> •\tIf there are none, clear the code and test drive the car. If it comes back the sensor is defective"},
+    "P0327": { "short_description":"Knock Sensor 1 Circuit low Input (Bank 1 or Single Sensor)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tKnock sensor on bank 1 is has low output voltage than normal; usually .5V or less<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tGenerally doesn’t come with symptoms but Check Engine Light may come on<br> •\tYou may also notice fluctuating RPM and loss of engine power<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tSensor in circuit bank 1 may be faulty<br> •\tOpen or short in wiring to the sensor<br> •\tPCM has failed (least likely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck the resistance of the knock sensor and ensure it matches manufacturer’s specifications<br> •\tVisually inspect all wiring to knock sensor 1 in circuit bank 1. Ensure there are no shorts or open wires<br> •\tIf the above don’t work replace knock sensor"},
+    "P0328": { "short_description":"Knock Sensor 1 Circuit high Input (Bank 1 or Single Sensor)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tKnock sensor on bank 1 is has high output voltage than normal; usually .5V or less<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tLoss of power<br> •\tIrregular RPM<br> •\tEngine pings when accelerating<br> •\tKnocking sound coming from engine compartment<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tKnock sensor 1 in circuit 1 may be faulty<br> •\tOpen or short in wiring to the sensor<br> •\tLow fuel pressure<br> •\tLoose knock sensor<br> •\tUsing incorrect type of fuel<br> •\tPCM has failed (least likely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tEnsure the correct fuel was used<br> •\tVisually inspect all wiring to knock sensor 1 in circuit bank 1. Ensure there are no shorts or open wires<br> •\tMeasure resistance of the sensor. If it doesn’t match manufacturer specs replace the sensor"},
+    "P0332": { "short_description":"Knock Sensor 2 Circuit Low Input (Bank 2)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tKnock sensor on bank 2 is has low output voltage than normal; usually .5V or less<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tGenerally doesn’t come with symptoms but Check Engine Light may come on<br> •\tYou may also notice fluctuating RPM and loss of engine power<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tSensor in circuit bank 2 may be faulty<br> •\tOpen or short in wiring to the sensor<br> •\tPCM has failed (least likely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck the resistance of the knock sensor and ensure it matches manufacturer’s specifications<br> •\tVisually inspect all wiring to knock sensor 2 in circuit bank 2. Ensure there are no shorts or open wires<br> •\tIf the above don’t work replace knock sensor"},
+    "P0335": { "short_description":"Crankshaft Position Sensor A Circuit Malfunction",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected that crankshaft position (CKP) sensor is not producing pulses or the pulses are not normal. It uses these pulses to determine the position of the crankshaft<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine may fail to start<br> •\tVehicle may run rough<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective CKP sensor<br> •\tOpen or short in CKP sensor wiring<br> •\tTiming belt is broken<br> •\tPCM has failed (least likely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tStart by checking if there’s an RPM signal (using a scanner)<br> •\tIf it’s not there check all the wires and connectors to the sensor. Repair as necessary<br> •\tCheck the sensor’s resistance and compare with manufacturer’s recommendation. If they don’t match replace sensor"},
+    "P0336": { "short_description":"Crankshaft Position Sensor A Circuit Range/Performance",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has not received proper information from CKP sensor and therefore cannot adjust ignition timing and fuel injection accordingly<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine may fail to start<br> •\tIntermittent stalling<br> •\tIntermittent misfire<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective CKP sensor<br> •\tProblem with CKP sensor wiring<br> •\tReluctor ring is dislodged from its stationary location<br> •\tReluctor ring is broken<br> •\tPCM has failed (least likely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect CKP sensor for wiring issues<br> •\tInspect reluctor ring if it has broken/damaged teeth or dirt lodged in the teeth<br> •\tCheck sensor resistance and compare with manufacturer specs. If they don’t match replace sensor"},
+    "P0340": { "short_description":"Camshaft Position Sensor Circuit Malfunction",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThere’s a problem in the camshaft position sensor (CPS) circuit. As such, PCM can’t perform ignition spark and fuel injector timing properly<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine may fail to start<br> •\tVehicle may run rough<br> •\tRough idle<br> •\tMisfire <br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective CPS<br> •\tOpen or short in CPS wiring<br> •\tDefective CKP sensor<br> •\tPCM has failed (least likely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tInspect wiring to CPS and ensure there are no open or broken wires<br> •\tCheck CPS voltage if it’s within the manufacturer’s specs. If it’s not replace sensor<br> •\tCheck CKP sensor as well to determine whether it’s the source of the problem"},
+    "P0341": { "short_description":"Camshaft Position Sensor Circuit Range/Performance",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe signal that the PCM is receiving from the camshaft position sensor (CPS ) is inconsistent with what it should be<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tGenerally doesn’t come with symptoms but Check Engine Light may come on<br> •\tPossible poor fuel economy<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective CPS<br> •\tOpen or short in CPS wiring<br> •\tDefective reluctor wheel<br> •\tInterference in CPS wiring (from spark plug)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tInspect wiring to CPS and ensure there are no open or broken wires<br> •\tInspect reluctor wheel and check for damage or missing teeth<br> •\tReplace the CPS"},
+    "P0345": { "short_description":"Camshaft Position Sensor A Circuit Malfunction (Bank 2)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected a problem in the CPS circuit of bank 2. The problem could be anywhere in the circuit; sensor, wring or PC<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tLow engine power<br> •\tHard starting or no starting completely<br> •\tVehicle runs rough and/or misfires<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tOpen, grounded or short wiring in CPS circuit of bank 2<br> •\tDefective CPS<br> •\tDefective CKP sensor<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tInspect wiring to CPS in bank 2 and ensure there are no open or broken wires<br> •\tCheck CPS voltage to ensure it’s within the range specified by manufacturer<br> •\tCheck circuit connectors for corrosion and burns<br> •\tCheck that CKP sensor is operating as it should<br> •\tReplace CPS if all the above check out"},
+    "P0351": { "short_description":"Ignition Coil A Primary/Secondary Circuit Malfunction",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThere’s a short in the driver circuit for the engine’s coil #1 (the coil for cylinder #1)<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine misfire<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tShort or open in the coil on plug (COP) driver circuit<br> •\tLoose or broken connection at coil<br> •\tDefective COP<br> •\tDefective PCM (least likely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tIf the engine is not currently misfiring then it’s an intermittent problem. Start by checking coil #1 wires visually as well as using wiggle test<br> •\tCheck for loose connections and broken connector locks<br> •\tIf all the above check out replace coil #1"},
+    "P0354": { "short_description":"Ignition Coil D Primary/Secondary Circuit Malfunction",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThere’s a short in the driver circuit for the engine’s coil #4 (the coil for cylinder #4)<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine misfire<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tShort or open in the coil on plug (COP) driver circuit<br> •\tLoose or broken connection at coil<br> •\tDefective COP<br> •\tDefective PCM (least likely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tIf the engine is not currently misfiring then it’s an intermittent problem. Start by checking coil #4 wires visually as well as using wiggle test<br> •\tCheck for loose connections and broken connector locks<br> •\tIf all the above check out replace coil #4"},
+    "P0400": { "short_description":"Exhaust Gas Recirculation Flow Malfunction",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThere’s either an insufficient or non-existent amount of exhaust gases entering the cylinders<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tIncreased NOx emissions<br> •\tIncreased combustion temperatures <br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tExhaust gas recirculation (EGR) passage is plugged<br> •\tEGR solenoid is faulty<br> •\tWiring or harness to EGR solenoid is faulty<br> •\tEGR valve is faulty<br> •\tEither vacuum lines are damaged or disconnected from EGR valve or EGR valve solenoid<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tWith a bidirectional scan tool, open and close EGR valve while the engine is running. If the engine stumbles then there’s a wiring problem<br> •\tIf the engine doesn’t stumble but it dies then the ports are plugged<br> •\tAfter the above visually inspect all hoses, vacuum lines, solenoid and solenoid harnesses for damage<br> •\tUsing the scanner, check solenoid voltage to ensure its within normal range<br> •\tIf all the above check out replace EGR valve"},
+    "P0401": { "short_description":"Exhaust Gas Recirculation Flow Insufficient Detected",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected an insufficient amount of EGR<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tMost notable symptom is engine pinging when the vehicle is in high speed or under load<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective differential pressure feedback EGR (DPFE) sensor<br> •\tDefective EGR valve<br> •\tEGR valve can’t open because of lack of vacuum<br> •\tBlockage in EGR tube<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck EGR valve and its tubing for deposits<br> •\tCheck DPFE sensor voltage to ensure its within specified range<br> •\tIf not replace the sensor. If it is replace the EGR valve"},
+    "P0402": { "short_description":"Exhaust Gas Recirculation Flow Excessive Detected",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected an excessive amount of EGR<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tMost notable symptom is engine surging off idle<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective differential pressure feedback EGR (DPFE) sensor<br> •\tDefective EGR valve<br> •\tEGR valve can’t open because of lack of vacuum<br> •\tBlockage in EGR tube<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck DPFE sensor voltage to ensure its within specified range<br> •\tIf not replace the sensor."},
+    "P0403": { "short_description":"Exhaust Gas Recirculation Circuit Malfunction",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected that the EGR circuit has malfunctioned and isn’t sending the proper voltage at the proper time<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine may misfire under acceleration<br> •\tRough idle<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tShort or open in circuit leading to EGR solenoid<br> •\tPins connecting EGR solenoid are worn out or loose<br> •\tPresence of water in EGR solenoid harness<br> •\tEGR solenoid isn’t getting voltage supply<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tPull codes and freeze frame data to confirm P0403 code<br> •\tCheck all wiring and connections to EGR solenoid<br> •\tDisconnect and check EGR valve circuit for a short or open<br> •\tClear code and do test drive. If it comes back replace solenoid"},
+    "P0404": { "short_description":"Exhaust Gas Recirculation Circuit Range/Performance",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has determined that EGR valve is open when it should be closed or its closed when it should be open<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine may idle rough<br> •\tEngine may fail to idle<br> •\tVehicle may fail emissions<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tOpen or short in reference, ground or PCM controlled circuit<br> •\tDefective PCM (least likely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to EGR to ensure there are no shorts or opens<br> •\tUsing a bidirectional scanner, open and close EGR valve as you watch the EGR position. If it’s not close to the “desired” position then it’s likely a bad valve"},
+    "P0405": { "short_description":"Exhaust Gas Recirculation Sensor A Circuit Low",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tEGR valve pintle is not moving as it should either because of unusually low voltage or its position is lower than the PCM has commanded<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tOpen or short in reference or ground circuit<br> •\tDefective EGR valve<br> •\tDefective PCM (least likely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to EGR to ensure there are no shorts or opens<br> •\tUsing a bidirectional scanner, open and close EGR valve and watch how it responds. If its moving properly then it’s an intermittent problem"},
+    "P0406": { "short_description":"Exhaust Gas Recirculation Sensor A Circuit High",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tEGR sensor has had abnormally high voltage reading for too long<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tMay surge when you drive<br> •\tMay stall intermittently<br> •\tVehicle may fail emissions<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective EGR valve<br> •\tShort or open in EGR wiring circuit<br> •\tDebris build up in EGR valve and is holding it open<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tPull codes and freeze frame data<br> •\tVisually inspect all wiring to EGR to ensure there are no shorts or opens<br> •\tUsing a scan tool, view EGR position during startup and while running to ensure its correct<br> •\tClear code and do test drive"},
+    "P0411": { "short_description":"Secondary Air Injection System Incorrect Flow Detected",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe flow coming from the secondary air injection system is out of the range specified by PCM<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine may hesitate when you accelerate<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective air injection pump<br> •\tCheck valve is damaged or missing<br> •\tDamage or leak in exhaust component<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect air injection system and check for broken components, damaged hoses and excess carbon<br> •\tReset the code and do a test drive"},
+    "P0420": { "short_description":"Catalyst System Efficiency Below Threshold (Bank 1)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tCatalytic converter is not working as efficiently as it should and the vehicle is therefore emitting more harmful substances<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine lacks power<br> •\tReduced fuel economy<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective O2 sensor<br> •\tDefective engine coolant temp<br> •\tWiring to downstream O2 sensor is damaged or improperly done<br> •\tLeaking fuel injector<br> •\tOil is contaminated<br> •\tUsing leaded fuel where unleaded fuel was required<br> •\tDefective catalytic converter, exhaust pipe, muffler or exhaust manifold<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tInspect exhaust system for damage and leaks.<br> •\tCheck voltage of downstream O2 sensor while the engine is running. If its not steady (jumpy between .1 and .9 V) then the catalytic converter needs replacing"},
+    "P0421": { "short_description":"Warm Up Catalyst Efficiency Below Threshold (Bank 1)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tDownstream O2 sensor on bank 1 has detected that the converter is not working according to specification<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine may lack power<br> •\tEngine may hesitate when accelerating <br> <br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective catalytic converter<br> •\tDefective O2 sensor, particularly downstream O2 sensor<br> •\tFouled up spark plug<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tMeasure voltage of O2 sensor (both) and ensure they match the specs. If not replace as necessary<br> •\tVisually inspect catalytic converters and check for red fumes (when car is running)<br> •\tSmell fumes and try to find traces of excessive fuel<br> •\tIf the latter two are present replace catalytic converter"},
+    "P0430": { "short_description":"Catalyst System Efficiency Below Threshold (Bank 2)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tCatalytic converter is not working as efficiently as it should. Its therefore releasing more harmful pollutants<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine may lack power<br> •\tReduced fuel economy<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective O2 sensor<br> •\tLeak in exhaust system<br> •\tDefective catalytic converter<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck exhaust system for any damages and leaks<br> •\tWith the car running, check the voltage of downstream O2 sensor. If it’s not steady then the catalytic converter is at fault"},
+    "P0440": { "short_description":"Evaporative Emission Control System Malfunction",  "long_description":"<strong>1. Meaning:<\/strong><br> • A component in the EVAP system is not working properly<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light may come on<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tGas cap is not working or has not been installed properly<br> •\tCanister is plugged and defective<br> •\tPurge solenoid has failed<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tInspect gas cap to see if its installed tightly<br> •\tCheck for disconnected or cracked EVAP hoses<br> •\tInspect charcoal canister and fuel tank for leaks and damages<br> •\tCheck that purge valve (solenoid) has no leaks"},
+    "P0441": { "short_description":"Evaporative Emission Control System Incorrect Purge flow",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected that there’s no purge flow (i.e. purge control valve is still closed) despite commanding a purge<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light may come on<br> •\tRough or erratic idle<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tLoose or damaged EVAP hoses<br> •\tDefective purge valve<br> •\tGas cap is loose, missing or damaged<br> •\tCharcoal canister is damaged or defective<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tInspect gas cap to see if its installed tightly<br> •\tCheck for disconnected or cracked EVAP hoses<br> •\tInspect charcoal canister and fuel tank for leaks and damages<br> •\tCheck that purge valve (solenoid) has no leaks"},
+    "P0442": { "short_description":"Evaporative Emission Control System leak Detected (small leak)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected a very small vapor leak somewhere in the EVAP control system <br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light may come on<br> •\tReduced fuel economy<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tLoose or damaged EVAP hoses<br> •\tDefective purge valve<br> •\tGas cap is loose, missing or damaged<br> •\tCharcoal canister is leaking<br> •\tFuel tank is leaking<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tInspect gas cap to see if its installed tightly<br> •\tCheck for disconnected or cracked EVAP hoses<br> •\tInspect charcoal canister and fuel tank for leaks and damages<br> •\tCheck that purge valve (solenoid) has no leaks<br> •\tIf the above don’t narrow down the problem perform a smoke test"},
+    "P0443": { "short_description":"Evaporative Emission Control System Purge Control Valve circuit Malfunction",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tEither there’s an open in the purge control valve circuit or the circuit has abnormal voltage (too high or too low)<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light may come on<br> •\tCar may have lean condition<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tPurge solenoid has short or open<br> •\tShort or open somewhere in the wiring harness to purge valve<br> •\tDriver circuit in PCM has an open or short<br> •\tWater intrusion has caused connector to break or wear out<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUsing a scan tool, command purge valve to open. Listen for a clicking sound (one or many times)<br> •\tIf it doesn’t click examine solenoid and connectors for breakages and signs of extreme wearing out<br> •\tCheck all the circuits for wiring problems"},
+    "P0446": { "short_description":"Evaporative Emission Control System Vent Control Circuit Malfunction",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected an open or short in EVAP control circuit or a short to ground circuit<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective EVAP vent valve<br> •\tBlockage in vent valve<br> •\tVent valve control circuit has an open or short<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tExamine all wiring to vent valve<br> •\tIf the above checks out replace vent valve"},
+    "P0449": { "short_description":"Evaporative Emission Control System Vent Valve/Solenoid Circuit Malfunction",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected a problem in the circuit that controls the EVAP system vent<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective EVAP vent valve<br> •\tWiring issue in the EVAP vent valve<br> •\tCircuit issue in the EVAP vent valve<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck all wires leading to the vent valve for shorts and opens<br> •\tCheck fuses that power the vent solenoid (in case there are any)<br> •\tExamine if vent valve has cracks or openings<br> •\tUsing a bidirectional scanner, actuate the valve to see if its working"},
+    "P0452": { "short_description":"Evaporative Emission System Pressure Sensor/Switch Low",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected that the fuel tank pressure is abnormally low<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective fuel tank pressure (FTP) sensor<br> •\tWiring problem in the circuits that lead to FTP sensor<br> •\tBroken or cracked vapor line (either to the tank or vacuum canister)<br> •\tLoose gas cap leading to loss of vacuum<br> •\tLeaking gasket in fuel pump module<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck vapor hoses for any breakages and opens<br> •\tSince diagnosing this problem is extremely hard (due to the location of the FTP sensor), its recommended that you get a professional to do the job"},
+    "P0455": { "short_description":"Evaporative Emission Control System Leak Detected (large leak)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected a large vapor leak somewhere in the EVAP control system <br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light may come on<br> •\tReduced fuel economy<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tLoose or damaged EVAP hoses<br> •\tGas cap is loose, missing or damaged<br> •\tNon-compatible gas cap<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tInspect gas cap to see if its installed tightly<br> •\tCheck for disconnected or cracked EVAP hoses<br> •\tInspect charcoal canister and fuel tank for leaks and damages<br> •\tIf the above don’t work replace the gas cap"},
+    "P0456": { "short_description":"Evaporative Emissions System - Small leak detected",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tFTP sensor has indicated a small leak in EVAP system<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tFaulty gas cap<br> •\tLeak in fuel tank hoses or EVAP hoses<br> •\tLeak in vent valve or purge valve<br> •\tLeak in EVAP canister<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUse a bidirectional tool to activate vent solenoid as you monitor FTP sensor. It will tell you if the system is sealing properly or not<br> •\tIf it is then use a smoke test to determine the leak"},
+    "P0457": { "short_description":"Evaporative Emission Control System (EVAP) Leak Detected",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThere’s a vacuum leak and the EVAP system can’t draw fuel vapors into the system for efficient burning<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tSmell of fuel in exhaust<br> •\tReduced fuel economy<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tGas cap is either loose, cracked or missing<br> •\tLoose, disconnected or cracked hose in EVAP system<br> •\tCracked vacuum canister<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tInspect gas cap and check if its loose or has debris that’s preventing it from fitting tightly<br> •\tInspect vacuum hoses for cracks and breaks<br> •\tInspect charcoal canister for leaks"},
+    "P0463": { "short_description":"Evaporative Emission Control System Pressure Sensor High Input",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe signal from the fuel level sensor is above 5 volts for a prolonged period of time<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tFuel light may come on and sound alarm<br> •\tFluctuating fuel level gauge<br> •\tFuel level gauge may erroneously read empty or full<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective fuel level sensor<br> •\tProblem with fuel level sensor circuit<br> •\tDefective instrument cluster<br> •\tDamaged fuel tank<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect fuel tank for damage or leaks<br> •\tInspect wiring harness<br> •\tDo voltage test on fuel level sensor circuit<br> •\tIf all those check out you may have to replace fuel tank"},
+    "P0500": { "short_description":"Vehicle Speed Sensor Malfunction",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe vehicle speed, as given by the vehicle speed sensor (VSS) is not within the expected range<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tSpeedometer may fail to work<br> •\tLoss of ABS (anti-lock brakes)<br> •\tABS light may come on<br> •\tTransmission may not work properly<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective VSS<br> •\tWiring problem in VSS circuit<br> •\tPCM is not configured properly for the tire size of the vehicle<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to VSS and check for open, short, broken and chaffed wires<br> •\tCheck the voltage of the speed sensor"},
+    "P0506": { "short_description":"Idle Control System RPM lower Than Expected",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected that the engine idle speed is lower than the pre-programmed RPM<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tRough idle due to lower idle speed<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tVacuum leak<br> •\tAir is restricted in the exhaust or intake air path<br> •\tDefective positive crankcase ventilation valve<br> •\tProblem with throttle body<br> •\tFailed PCM<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck for vacuum leaks, damages and restriction<br> •\tNote that this code is informational more than anything, so look out for other codes that it comes with and address them first"},
+    "P0507": { "short_description":"Idle Control System RPM higher Than Expected",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected that the engine idle speed is higher than the pre-programmed RPM (typically over 200 RPM)<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tVacuum leak<br> •\tDefective positive crankcase ventilation valve<br> •\tLeaking air intake<br> •\tProblem with throttle body<br> •\tDefective EVAP system<br> •\tDefective idle air controller (IAC) or a problem with IAC circuit<br> •\tFailed PCM<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck for vacuum leaks, damages and restriction<br> •\tNote that this code is informational more than anything, so look out for other codes that it comes with and address those first"},
+    "P0521": { "short_description":"Engine Oil Pressure Sensor/Switch Range/Performance",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has seen an unexpected value in engine oil pressure sensor. The value could be fixed when it should fluctuate or simply out of the normal range<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tOil pressure gauge may read too low or too high<br> •\tOil pressure light may come on<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tOil level in the engine is too low<br> •\tOil pressure is too low<br> •\tDirty oil<br> •\tFaulty wiring to oil pressure sensor<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck that oil level is not too low<br> •\tCheck that the right oil was used<br> •\tVisually inspect all wiring to oil pressure sensor and check for open, short or broken wires<br> •\tIf you can, take the oil pressure reading and compare with the reading shown by the vehicle’s PCM. That should tell you if the problem is with oil pressure"},
+    "P0522": { "short_description":"Engine Oil Pressure Sensor/Switch Low Voltage",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected a very low value in engine oil pressure sensor<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tOil pressure light comes on<br> •\tOil pressure gauge reads zero or low value<br> •\tEngine may fail to start<br> •\tEngine may stall when you’re driving<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tWiring problem in oil pressure sensor circuit<br> •\tDefective oil pressure sensor<br> •\tLow oil level or blockage in oil passage<br> •\tUsing wrong type of oil<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck oil level and condition<br> •\tVisually inspect all wiring to oil pressure sensor<br> •\tCheck the sensor’s voltage to ensure it meets manufacturer’s specs<br> •\tIf you can, take the oil pressure reading and compare with the reading shown by the vehicle’s PCM. That should tell you if the problem is with oil pressure"},
+    "P0562": { "short_description":"System Voltage Low",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected that the ignition feed circuit has very low voltage. Meaning the charging system might not be working<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tRed battery light on<br> •\tReduced fuel economy<br> •\tTransmission may fail<br> •\tEngine may fail to start<br> •\tEngine may start then stall and die<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective alternator<br> •\tHigh resistance either in alternator-battery circuit, alternator-PCM circuit or both<br> •\tDefective PCM<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck whether battery voltage is sufficient<br> •\tEnsure battery is properly connected then check alternator belt<br> •\tUsing a digital volt ohm meter (DVOM), check whether the charging system is working<br> •\tReset the code then do a test drive. If the code returns check PCM voltage"},
+    "P0606": { "short_description":"ECM/PCM Processor Fault",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected an integrity fault in its own system<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tFailed PCM<br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tRe-flash PCM with updated software. If that doesn’t work replace the PCM"},
+    "P0700": { "short_description":"Transmission Control System Malfunction",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tIf the transmission control module (TCM) detects a fault in the transmission system and sets a code, this code is also stored in the PCM<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tTransmission may exhibit problems<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tAny transmission-related problem can trigger this code<br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tThis is only an informational code, so pull all transmission codes, address them and do a test drive to fix this code"},
+    "P0705": { "short_description":"Transmission Range Sensor Circuit Malfunction (PRNDL Input)",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected a malfunction in the transmission range sensor (TRS)<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tActuating starter may be impossible<br> •\tBack up lights may fail<br> •\tEngine may only start at neutral<br> •\tIrregular shift RPMs<br> •\tDelayed transmission engagement<br> •\tReduced fuel economy<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective TRS<br> •\tLoose TRS<br> •\tShorted wire in TRS circuit<br> •\tLoose or corroded connector at the external TRS. Pins may also be bent<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tMore often than not this code means replacing the TRS"},
+    "P0715": { "short_description":"Input/Turbine Speed Sensor Circuit Malfunction",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe actual transmission input speed does not match the desired input speed <br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tTransmission shifts erratically<br> •\tTransmission may fail to shift<br> •\tFailure in speedometer<br> •\tLower fuel economy<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective input speed sensor<br> •\tDefective output speed sensor<br> •\tA wiring problem in input/output speed sensor circuit<br> •\tLoose or burnt connector in transmission circuit<br> •\tDefective or improperly programmed PCM<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring and connectors for loose, burnt, open or broken connections<br> •\tUsing a scanner, pull all codes and freeze frame data to see which sensor is malfunctioning (input/output)<br> •\tReplace sensor if necessary"},
+    "P0720": { "short_description":"Output Speed Sensor Circuit Malfunction",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has determined that there’s a malfunction in the Output Shaft Speed Sensor (OSS) of the transmission system<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tDelayed shifts<br> •\tFailed speedometer<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective OSS<br> •\tDefective transmission fluid temperature sensor<br> •\tWiring problem in the OSS circuit<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck that all wiring to OSS is properly done and there are no open, broken or shorted wires<br> •\tMeasure OSS voltage and compare with manufacturer’s specs. If they don’t match replace OSS<br> •\tMeasure transmission fluid temperature sensor voltage and compare with manufacturer’s specs. If they don’t match replace the sensor"},
+    "P0741": { "short_description":"Torque Converter Clutch Circuit Performance or Stuck Off",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tTCM has detected a problem within the circuit that controls the torque converter clutch (TCC) solenoid<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tSlightly reduced fuel economy<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tShorted wire in transmission’s ground circuit<br> •\tInternal short in TCC solenoid<br> •\tDefective TCM<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck that all wiring in the transmission circuit is properly done and there are no open, broken or shorted wires<br> •\tCheck the resistance of the TCC solenoid and compare with manufacturer’s specs<br> •\tMonitor TCM using an advanced scan tool and see if its performance parameters are within normal range"},
+    "P1101": { "short_description":"MAF Sensor Out Of Self-Test Range./KOER Not Able To Complete KOER Aborted",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe PCM has detected an irregular (or abnormal) voltage from the Mass Air Flow (MAF) sensor<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine performs erratically upon startup<br> •\tReduced vehicle power<br> •\tRough idling<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective MAF sensor<br> •\tWiring problem in MAF sensor circuit<br> •\tFaulty connector(s) in MAF system<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck that all wiring in the MAF sensor circuit is properly done and there are no open, broken or shorted wires<br> •\tCheck air filters for dirt and debris that might be obstructing air flow<br> •\tPerform smoke test in vacuum system to check for leaks before and after MAF sensor<br> •\tCheck the voltage in MAF sensor and compare with manufacturer’s specs. If they don’t match replace the sensor<br> •\tCheck continuity between PCM and MAF sensor"},
+    "P1133": { "short_description":"HO2S Insufficient Switching Sensor 1",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has determined that the front heated O2 sensor (HO2S) is not functioning properly <br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tHard starting<br> •\tReduced fuel economy<br> •\tRough or erratic idling<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective O2 sensor<br> •\tDamaged, broken, shorted or corroded wires/connectors in front HO2S<br> •\tEGR valve is stuck open<br> •\tMisfires on at least one cylinder<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck that all O2 sensor wires and connectors are not damaged, open, broken, shorted or burnt<br> •\tUsing a scanner, determine whether oxygen sensors are switching enough times<br> •\tIf not, measure their voltage to determine which sensor is faulty. Replace as necessary"},
+    "P1135": { "short_description":"Air/Fuel Ratio Sensor Heater Circuit Malfunction Bank 1 Sensor 1",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThis Toyota code means the PCM has detected an oxygen sensor heater circuit malfunction<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tLonger time needed to achieve closed loop<br> •\tDecreased fuel economy<br> •\tEngine may go into fixed fuel mix<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tH02S sensor in bank 1, circuit 1 is not sending the correct signal to ECM<br> •\tDamaged or failed element in heater circuit<br> •\tOpen in O2 sensor heater’s circuit<br> •\tOpen/short in O2 sensor heater’s battery<br> •\tDefective ECM (this is the least likely cause)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tInspect wiring and power to the O2 sensor and ensure there’s no damage/open/short<br> •\tUse code reader to pull engine codes<br> •\tCheck voltage of O2 sensor and ensure it matches manufacturer’s specs<br> •\tReplace O2 sensor if necessary"},
+    "P1399": { "short_description":"Random Cylinder Misfire Detected",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThis Honda code means the PCM has detected that there’s an engine cylinder that’s not firing properly. It could be one or more cylinders. PCM hasn’t specified the exact cylinder<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tCheck Engine Light may flash<br> •\tEngine lacks power<br> •\tEngine may be hard to start<br> •\tEngine may stumble and hesitate frequently<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective or worn out spark plugs<br> •\tLow fuel pressure<br> •\tVacuum leak<br> •\tDefective catalytic converter<br> •\tDefective fuel injector<br> •\tDefective coil<br> •\tDefective camshaft position sensor<br> •\tDefective crankshaft sensor<br> •\tProblem with distributor<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUsing a scan tool, pull codes and see if there are any other besides P0300. Address the others first<br> •\tInspect whether there are loose, open or short wires in ignition coils<br> •\tInspect whether spark plugs and their wires are in good condition<br> •\tCheck that fuel pressure is within the recommended range<br> •\tInspect fuel injectors to see whether they are in good condition"},
+    "P1443": { "short_description":"Evaporative Emission Control System Control Valve",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThis is a predominantly Ford, Nissan and Range Rover code that means the same thing as P0443. Please refer to that code (#79 on this list)"},
+    "P1450": { "short_description":"Unable To Bleed Up Fuel Tank Vacuum",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThis is a Ford, Jaguar, Lincoln, Mercedes, Mercury and Oldsmobile code that means that the Evaporative Emission Control System has failed to bleed up the fuel tank<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine may fail to start<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective vent valve<br> •\tBlockage in vacuum lines<br> •\tDamaged charcoal canister<br> •\tOverfilling fuel tank<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck that all vent valve wires and connectors are not damaged, open, broken, shorted or burnt<br> •\tRemove any blockage in vacuum lines. Refer to your application manual for this procedure<br> •\tVisually inspect charcoal canister for any damages<br> •\tCheck that the fuel amount is within the recommended range"},
+    "P1456": { "short_description":"Fuel Tank Temperature Sensor Circuit Malfunction",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThis Honda code means the same thing as P0442. Please refer to that code (#78 on this list)"},
+    "P1457": { "short_description":"This is a manufacturer-specific code that means different things in different cars<br> •\tIn Honda it means Evaporative emission (EVAP) canister purge system (canister system) - leak detected<br> •\tIn Acura it means Evaporative emission (EVAP) canister purge system (canister system) - leak detected<br> •\tIn Audi it means Exhaust gas recirculation temperature (EGRT) sensor 2/Bank 2 - open circuit/short to positive<br> •\tIn Isuzu it means Evaporative emission (EVAP) canister purge system (canister system) - leak detected<br> •\tIn Kia it means Evaporative emission (EVAP) canister purge valve (low)<br> •\tIn Volkswagen it means Exhaust gas recirculation temperature (EGRT) open circuit/short to positive"},
+    "P1491": { "short_description":"This is a manufacturer-specific code that means different things in different cars<br> •\tIn Acura it means Exhaust gas recirculation (EGR) system - valve lift insufficient<br> •\tIn Chrysler it means Radiator Fan Relay Circuit Conditions<br> •\tIn Honda it means Exhaust gas recirculation (EGR) system - valve lift insufficient<br> •\tIn Infiniti it means Evaporative emission (EVAP) canister purge control system – malfunction<br> •\tIn Isuzu it means Exhaust gas recirculation (EGR) system - valve lift insufficient<br> •\tIn Mercedes it means AC system - pressure too high<br> •\tIn Nissan it means Evaporative emission (EVAP) canister purge system - bypass vacuum valve malfunction"},
+    "P1494": { "short_description":"EVAP Leak Detection Pump Pressure Switch Condition",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tA Chrysler code, this code means the same as P0442, i.e. PCM has detected a very small vapor leak somewhere in the EVAP control system <br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light may come on<br> •\tReduced fuel economy<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tLoose or damaged EVAP hoses<br> •\tDefective purge valve<br> •\tGas cap is loose, missing or damaged<br> •\tCharcoal canister is leaking<br> •\tFuel tank is leaking<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tInspect gas cap to see if its installed tightly<br> •\tCheck for disconnected or cracked EVAP hoses<br> •\tInspect charcoal canister and fuel tank for leaks and damages<br> •\tCheck that purge valve (solenoid) has no leaks<br> •\tIf the above don’t narrow down the problem perform a smoke test"},
+    "P1516": { "short_description":"Throttle actuator control module / throttle actuator position performance",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tA GM code, this DTC means that the voltage being sent by the throttle actuator position sensor (TAPS) doesn’t match the voltage being received by the actual throttle position sensor<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tVehicle may fail to accelerate<br> •\tIntermittent surging<br> •\tReduced fuel economy<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective pedal position sensor<br> •\tOpen or short in circuit supplying power to pedal position sensor<br> •\tDefective PCM<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to pedal position sensor and ensure there are no open, broken or shorted wires<br> •\tRun a resistance test on sensor. If it fails replace it<br> •\tDo a test drive, if the code returns run a test on PCM"},
+    "P1684": { "short_description":"Battery Power to Module Disconnected",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThis code appears on Dodge and Chrysler vehicles. It means the transmission control module (TCM) is disconnected from the battery’s power B+ or ground<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tRecently disconnected battery<br> •\tTCM was either replaced or disconnected<br> •\tShort in TCM harness<br> •\tDefective TCM<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck all wiring to TCM and ensure there are no shorted, broken or open wires<br> •\tUse a scan tool to reset the code<br> •\tDo a voltage test on TCM to determine if its defective"},
+    "P2096": { "short_description":"Post Catalyst Fuel Trim System Too Lean Bank 1",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThere’s a lean condition (i.e. too much air and too little fuel) in cylinder #1 on a V6 or V8 engine.<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tReduced fuel economy<br> •\tErratic acceleration<br> •\tEngine misfires<br> •\tRough idle<br> •\tMay produce spark knock<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tLarge vacuum leak<br> •\tLarge air leak somewhere around the 1st cylinder<br> •\tLow fuel pressure<br> •\tMisfiring plugs that cause the engine to run rough<br> •\tDefective O2 sensor<br> •\tDefective exhaust system<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUsing a scan tool, pull all the codes and address all the others first<br> •\tVisually inspect exhaust system for any damaged or worn out components<br> •\tCheck for vacuum leaks in the engine, particularly between the intake manifold and MAF sensor<br> •\tCheck that plug wires are not burning<br> •\tIf the vehicle has very little acceleration power, check for clogged converter<br> •\tIf none of the above work replace MAF sensor then downstream O2 sensor (in that order)"},
+    "P2097": { "short_description":"Post Catalyst Fuel Trim System Too Rich Bank 1",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThere’s a rich condition (i.e. too little oxygen content) in cylinder #1<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine lacks power<br> •\tReduced fuel economy<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective catalytic converter<br> •\tDefective O2 sensor(s)<br> •\tDefective MAF sensor or manifold air pressure sensor<br> •\tLeak in exhaust system<br> •\tWiring problem e.g. burnt, open, broken or disconnected wire<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect wiring harnesses for broken, open, burnt or disconnected wires<br> •\tCheck the exhaust for leaks and damages<br> •\tPull all codes and freeze frame data. Reset the codes and do a test drive<br> •\tIf code P2097 returns check resistance of MAF sensor and O2 sensors. Replace as necessary"},
+    "P2101": { "short_description":"Throttle Actuator \"A\" Control Motor Circuit Range/Performance",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThis code is set when there’s an electrical or mechanical problem in the throttle actuator A (TA-A)<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine fails to accelerate<br> •\tFixed idle speed<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective TA-A<br> •\tOpen or short in TA-A circuit<br> •\tDefective PCM (least likely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tLocate TA-A and check all its wiring harnesses. Ensure there are no open, broken, disconnected, shorted or burnt wires and connectors<br> •\tReset the code and do a test drive. If it returns test the actuator"},
+    "P2138": { "short_description":"Throttle/Pedal Pos Sensor/Switch D / E Voltage Correlation",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected a fault in either the D or E (or both) circuit of the throttle position sensor<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tVehicle may fail to start<br> •\tVehicle may stall<br> •\tPoor acceleration<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective throttle position sensor<br> •\tDefective throttle body motor<br> •\tWiring or connector problem in throttle body motor circuit<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect throttle body motor circuit for loose, broken, burnt or open wires and connectors<br> •\tTest resistance of throttle motor and throttle position sensor. Replace as necessary"},
+    "P2181": { "short_description":"Cooling System Performance",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tA vague OBD2 code, the P2181 suggests that there’s somewhere in the engine where the temperature is out of range (either too hot or too cold)<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tTemperature gauge indicates too high or too low temp<br> •\tIf the temp is too cold the engine will have a rich condition<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective engine coolant temperature (ECT) sensor<br> •\tWiring or connector problem in ECT circuit<br> •\tThermostat is stuck open or closed<br> •\tPresence of air in cooling system<br> •\tLow engine coolant level<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tIf the engine is running too cold replace thermostat<br> •\tCheck to ensure there are no open, broken, disconnected, shorted or burnt wires and connectors in ECT circuit<br> •\tCheck whether fan is working. If it’s wobbling or has a leak tighten or replace the fan. Remember to check its fuse as well<br> •\tTest the resistance of ECT sensor. If it’s off the recommended reading replace the sensor"},
+    "P2195": { "short_description":"O2 Sensor Signal Stuck Lean Bank 1 Sensor 1",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tO2 sensor 1 on cylinder 1 (bank 1) is reading an air/fuel ratio that has strayed so far from the normal 14.7:1 that the PCM is no longer able to correct the ratio<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective O2 sensor or A/F (air/fuel) ratio sensor<br> •\tOpen or short in O2 sensor circuit<br> •\tDefective fuel pressure system leading to too high or too low fuel pressure<br> •\tFuel leak<br> •\tLeak in engine vacuum or intake air<br> •\tLeak in PCV system<br> •\tLeak in fuel system (tank or hoses)<br> •\tDefective MAF sensor<br> •\tDefective PCM<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring harnesses to O2 sensor circuits, especially sensor 1<br> •\tCheck vacuum, fuel tank and PCV systems for leaks<br> •\tUsing a scan tool, monitor short and long term fuel trim values and compare with manufacturer specs<br> •\tAlso take readings for MAF and O2 sensor 1 and compare with specs<br> •\tCheck the resistance of those sensors to ensure they work properly. Replace as necessary"},
+    "P2196": { "short_description":"O2 Sensor Signal Stuck Rich Bank 1 Sensor 1",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThis code is similar to P2195; i.e. O2 sensor 1 on cylinder 1 (bank 1) is reading an air/fuel ratio that has strayed so far from the normal 14.7:1 that the PCM is no longer able to correct the ratio<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective O2 sensor or A/F (air/fuel) ratio sensor<br> •\tOpen or short in O2 sensor circuit<br> •\tDefective fuel pressure system leading to too high or too low fuel pressure<br> •\tFuel leak<br> •\tLeak in engine vacuum or intake air<br> •\tLeak in PCV system<br> •\tLeak in fuel system (tank or hoses)<br> •\tDefective MAF sensor<br> •\tDefective PCM<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring harnesses to O2 sensor circuits, especially sensor 1<br> •\tCheck vacuum, fuel tank and PCV systems for leaks<br> •\tUsing a scan tool, monitor short and long term fuel trim values and compare with manufacturer specs<br> •\tAlso take readings for MAF and O2 sensor 1 and compare with specs<br> •\tCheck the resistance of those sensors to ensure they work properly. Replace as necessary"},
+    "P2270": { "short_description":"O2 Sensor Signal Biased/Stuck Lean Bank 1 Sensor 2",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe signal being put out by sensor 2 on bank 1 is stuck lean (the sensor has detected too much air)<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine may run rough<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tProblem with fuel injector<br> •\tExhaust leak near sensor 2 of bank 1<br> •\tDefective sensor 2 of bank 1<br> •\tIncorrect fuel pressure<br> •\tLeak in engine coolant<br> •\tDefective purge solenoid valve<br> •\tDefective PCM (least likely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring harnesses to O2 sensor circuits, especially sensor 1 of bank 1<br> •\tCheck for exhaust leaks<br> •\tUsing a scan tool, monitor sensor readings and compare with manufacturer specs<br> •\tProceed to test resistance of sensors and replace as necessary"},
+    "P2646": { "short_description":"“A” Rocker Arm Actuator System Performance/Stuck Off Bank 1",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe “A” rocker arm actuator control circuit is either stuck in the off position or not working as it should<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tEngine may lack power<br> •\tEngine valve train may be excessively noisy<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tLow oil pressure<br> •\tClogged oil passages<br> •\tRocker arm actuator has built-up slug<br> •\tOil used is too thick<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVerify that the oil used is of the right viscosity<br> •\tCheck A” rocker arm actuator hoses and passages for blockage<br> •\tClear code and do test drive. If it returns perform manufacturer pinpoint test for A” rocker arm actuator"},
+    "P2A00": { "short_description":"O2 Sensor Circuit Range/Performance Bank 1 Sensor 1",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe upstream O2 sensor circuit has failed to cycle as expected by the PCM over a period of time predetermined by the PCM<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tReduced fuel economy<br> •\tPoor engine performance<br> •\tEngine misfires<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective O2 sensor 1 in bank 1<br> •\tBurnt, open, broken, shorted or disconnected wire/connector in the sensor circuit<br> •\tVacuum leak<br> •\tDefective MAF sensor<br> •\tLeak in engine exhaust<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring harnesses to O2 sensor circuits, especially sensor 1 of bank 1<br> •\tCheck for leaks in engine and vacuum system<br> •\tAddress other codes, reset all codes and do test drive. If the code returns check resistance of MAF sensor and O2 sensor. Replace as necessary"},
+    "U0001": { "short_description":"Controller Area Network (CAN) Data Bus: High Speed Bus/Communication Control Module",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe high speed bus is a communication line between the totally integrated power module (TIPM) and other vehicle modules. When this code sets it means there’s a module (especially ABS module) that has failed to communicate with TIPM<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tVehicle may fail to start on one or few attempts<br> •\tKey alarm may activate intermittently<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tOpen in either positive or negative CAN bus circuit<br> •\tOpen in power or ground supply circuit to the module that set the code<br> •\tShort to ground on CAN bus circuit<br> •\tLow voltage<br> •\tProblem with TIPM<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUsing a bidirectional scan tool, operate each module independently to find out which one is not working<br> •\tOnce you’ve pinpointed the module check that its circuits have no loose, open, broken or disconnected wires and connectors<br> •\tDo the same for TIPM<br> •\tUse an ohmmeter to check continuity on wire terminals in the module and TIPM<br> •\tIf all the above don’t work replace the TIPM"},
+    "U0073": { "short_description":"Control Module Communication Bus “A” Off",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tProblem with CAN bus making it hard for modules to exchange information and to communicate with scan tool<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tInstrument cluster indicator “light” on<br> •\tReduced fuel economy<br> •\tEngine lacks power<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tOpen in the “A” CAN bus + or – circuit <br> •\tShort to power or ground in “A” CAN bus circuit<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tPull all communication codes and address them first then this one last<br> •\tVisually inspect all bus communication connections (connectors and wires) for breaks, shorts, opens, chafing, burns and melted spots<br> •\tReset all codes and do a test drive. If this code returns disconnect one control module at a time and see if the scanner can finally communicate with PCM"},
+    "U0101": { "short_description":"Lost Communication With Transmission Control Module",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThere’s no communication between the transmission control module (TCM) and other control modules<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tCar doesn’t shift gears<br> •\tStays in one gear, usually 2nd or 3rd gear<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tOpen in CAN bus + or – circuit<br> •\tShort to power or ground in either + or – CAN bus circuit<br> •\tDefective TCM (least likely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUsing a bidirectional scan tool, control TCM and see if it responds. If it doesn’t probe it further<br> •\tIf it responds then check all the wires, connectors and fuses that make the circuit<br> •\tWith key on engine off, check the voltage of CAN C+ and C-. If the readings don’t match manufacturer’s specs then the communication circuits are bad"},
+    "U0107": { "short_description":"Lost Communication With Throttle Actuator Control Module",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThere’s no communication between the throttle actuator control (TAC) module and other control modules<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tElectronic throttle control light comes on or flashes<br> •\tNo throttle response<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tOpen in CAN bus + or – circuit<br> •\tShort to power or ground in either + or – CAN bus circuit<br> •\tDefective TAC module (least likely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUsing a bidirectional scan tool, control TAC module and see if it responds. If it doesn’t probe it further<br> •\tIf it responds then check all the wires, connectors and fuses that make the circuit<br> •\tWith key on engine off, check the voltage of CAN C+ and C-. If the readings don’t match manufacturer’s specs then the communication circuits are bad"},
+    "U0121": { "short_description":"Lost Communication With Anti-Lock Brake System Control Module",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThere’s no communication between the anti-lock brake system (ABS) control module and other control modules<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tABS warning light comes on<br> •\tTRAC or ESP/ESC (or both) warning light comes on<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tOpen in CAN bus + or – circuit<br> •\tShort to power or ground in either + or – CAN bus circuit<br> •\tDefective ABS control module (least likely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUsing a bidirectional scan tool, control ABS control module and see if it responds. If it doesn’t probe it further<br> •\tIf it responds then check all the wires, connectors and fuses that make the circuit<br> •\tWith key on engine off, check the voltage of CAN C+ and C-. If the readings don’t match manufacturer’s specs then the communication circuits are bad"},
+    "U0155": { "short_description":"Lost Communication With Instrument Panel Control Module",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThere’s no communication between the instrument panel control (IPC) module and other control modules<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tAll indicator lights in instrument panel/cluster come on, or<br> •\tNo indicator lights in instrument panel/cluster come on<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> <br> •\tOpen in CAN bus + or – circuit<br> •\tShort to power or ground in either + or – CAN bus circuit<br> •\tDefective IPC module (least likely)<br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUsing a bidirectional scan tool, control IPC module and see if it responds. If it doesn’t probe it further<br> •\tIf it responds then check all the wires, connectors and fuses that make the circuit<br> •\tWith key on engine off, check the voltage of CAN C+ and C-. If the readings don’t match manufacturer’s specs then the communication circuits are bad"},
+    "U1120": { "short_description":"Lost Wheel Distance",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPrimarily a Chrysler code, the U1120 means the ABS module is not able to communicate with speed sensors<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tABS warning light may come on<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tOpen in CAN bus + or – circuit<br> •\tShort to power or ground in either + or – CAN bus circuit<br> •\tDefective ABS control module (least likely)<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUsing a bidirectional scan tool, control ABS control module and see if it responds. If it doesn’t probe it further<br> •\tIf it responds then check all the wires, connectors and fuses that make the circuit<br> •\tWith key on engine off, check the voltage of CAN C+ and C-. If the readings don’t match manufacturer’s specs then the communication circuits are bad"},
+    "U1900": { "short_description":"CAN Communication Bus Fault",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPrimarily a Ford code, the U1900 means the same as U0001 <br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tVehicle may fail to start on one or few attempts<br> •\tKey alarm may activate intermittently<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tOpen in either positive or negative CAN bus circuit<br> •\tOpen in power or ground supply circuit to the module that set the code<br> •\tShort to ground on CAN bus circuit<br> •\tLow voltage<br> •\tProblem with TIPM<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tUsing a bidirectional scan tool, operate each module independently to find out which one is not working<br> •\tOnce you’ve pinpointed the module check that its circuits have no loose, open, broken or disconnected wires and connectors<br> •\tDo the same for TIPM<br> •\tUse an ohmmeter to check continuity on wire terminals in the module and TIPM<br> •\tIf all the above don’t work replace the TIPM"},
+    "B0092": { "short_description":"Left Side Restraints Sensor 2",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tA Ford code, the B0092 means that the left side airbag sensor has detected a problem with the airbag system<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tAirbag warning lights may come on<br> •\tAbnormal illumination of airbag warning lights<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tOpen, short or broken wire in left side restraint sensor 2 harness<br> •\tDefective left side restraint sensor 2<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to left side restraint sensor 2 for loose, open or short connections<br> •\tCheck resistance of left side restraint sensor 2 and compare with specs. If they don’t match replace sensor"},
+    "B1015": { "short_description":"This Is A Manufacturer-Specific Code That Means Different Things In Different Cars<br> •\tIn GM It Means Passenger Deploy. Loop Resistance High<br> •\tIn Chrysler It Means Rear Defrost Switch Request Input Circuit/Performance<br> •\tIn Ford It Means Electronic Instrument Cluster Unconfigured<br> •\tIn Mazda It Means Electronic Instrument Cluster Unconfigured<br> •\tIn Mitsubishi It Means Heater Water Temperature Sensor Performance"},
+    "B1047": { "short_description":"Driver-Side Side Air Bag Module And Other Air Bag Module Circuits Short",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThere’s a short in the side airbag on the driver’s side<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tAirbag warning lights may come on<br> •\tAbnormal illumination of airbag warning lights<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tOpen or short in the circuit leading to driver-side side air bag module<br> •\tDefective driver-side side air bag module<br> •\tDefective SRS (airbag) module<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to the driver-side side air bag module for loose, open or short connections<br> •\tPerform resistance test on driver-side side air bag module<br> •\tPerform resistance test on airbag control module"},
+    "B1057": { "short_description":"Driver Airbag Module Short",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe airbag diagnosis sensor on the driver’s side has detected a short in the circuit<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tAirbag warning light comes on<br> <br> <strong>4. Possible Causes:<\/strong><br> •\tShort in driver airbag’s harness<br> •\tProblem with spiral cable<br> •\tDefective driver airbag<br> •\tProblem with electrical connection in driver airbag<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect the wiring harness to driver’s airbag<br> •\tPerform resistance test on driver’s airbag module<br> •\tCheck resistance of spiral cable and airbag diagnosis sensor and replace as necessary"},
+    "B1318": { "short_description":"Battery Voltage Low",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThis is a Ford and Jaguar code that is set when the PCM detects that battery voltage has fallen below a predetermined level <br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tRed battery light on<br> •\tReduced fuel economy<br> •\tTransmission may fail<br> •\tEngine may fail to start<br> •\tEngine may start then stall and die<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective alternator<br> •\tUsing an incorrect battery<br> •\tUnmaintained battery<br> •\tHigh resistance either in alternator-battery circuit, alternator-PCM circuit or both<br> •\tDefective PCM<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck whether battery voltage is sufficient<br> •\tEnsure battery is properly connected then check alternator belt<br> •\tUsing a digital volt ohm meter (DVOM), check whether the charging system is working<br> •\tReset the code then do a test drive. If the code returns check PCM voltage"},
+    "B1342": { "short_description":"ECU Is Defective",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe Electronic Control Unit (ECU) has failed<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tOther warning lights may come on depending on which module is affected<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective ECU<br> •\tDamaged controller(s) due to abnormal system voltages<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tDiagnose and address all other codes first before replacing ECU<br> •\tCheck whether system voltage is within manufacturer’s recommendation<br> •\tInspect wiring to ECU and ensure that there are no open, shorted or broken wires<br> •\tReset all codes and do test drive. If the code returns you may have to replace ECU"},
+    "B1650": { "short_description":"Occupant Classification System Fault",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM or airbag control module has detected a malfunction in the occupant classification system<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tAirbag warning light comes on<br> •\tCheck Engine Light may come on<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tProblem in the occupant classification system<br> •\tWiring problem in the right front seat<br> •\tProblem with airbag sensor assembly center<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring in the occupant classification system for loose, open or short connections<br> •\tPerform resistance test on occupant classification system and airbag sensor assembly center and replace as necessary<br> •\tPerform resistance test on airbag control module. If it doesn’t pass the test replace the module"},
+    "B1676": { "short_description":"Battery Pack Voltage Out Of Range",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThis anti-lock brake system (ABS) code is set when the ABS module detects a voltage signal that’s less than 9v or more than 19v for more than 8 seconds<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tABS warning light comes on<br> •\tCheck Engine Light may come on<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tBlown fuse in ABS<br> •\tProblem in the charging system<br> •\tWiring problem in ABS module connector<br> •\tDefective ABS module<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring and connectors in ABS module as well as charging system for loose, open or short connections<br> •\tCheck that all fuses in ABS are not blown. If any is blown replace<br> •\tTest resistance of ABS module and compare with manufacturer’s specs<br> •\tReset code and do test drive. If it returns consider replacing the module"},
+    "C0265": { "short_description":"EBCM Motor Relay Circuit Low When On ",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe Electronic Brake Control Module (EBCM) is sending an abnormally low voltage signal<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tABS warning light comes on<br> •\tCheck Engine Light may come on<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tShorted or open wire in EBCM harness<br> •\tPoor electrical connection in EBCM circuit<br> •\tDefective EBCM<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring and connectors in EBCM for loose, open or shorted connections<br> •\tTest EBCM for resistance and compare readings with manufacturer’s specs. If they are out of range consider replacing"},
+    "C1130": { "short_description":"Engine Signal 1",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe ABS control module has detected that there’s a problem with the engine control unit (ECU) or PCM<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tABS warning light comes on<br> •\tCheck Engine Light comes on<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective ECU<br> •\tDefective ABS actuator and/or ABS control module<br> •\tProblem with CAN communication line<br> •\tDamaged controller(s) due to abnormal system voltages<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tDiagnose and address all other codes first before replacing ECU<br> •\tCheck whether system voltage is within manufacturer’s recommendation<br> •\tInspect wiring to ECU and ensure that there are no open, shorted or broken wires<br> •\tCheck all fuses and replace as necessary<br> •\tRun tests on ABS module<br> •\tRun tests on CAN line<br> •\tReset all codes and do test drive. If the code returns you may have to replace ECU"},
+    "C1145": { "short_description":"Right Front Wheel Speed Sensor Input Circuit Failure",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe right front wheel speed, as given by the wheel’s speed sensor is not within the expected range<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tABS warning light comes on<br> •\tCheck Engine Light comes on<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective right front wheel speed sensor<br> •\tWiring problem in that speed sensor’s circuit<br> •\tPCM is not configured properly for the size of the right front wheel<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring to the right front wheel speed sensor and check for open, short, broken and chaffed wires<br> •\tCheck the voltage of the speed sensor and match with manufacturer specs. If they don’t match replace the sensor"},
+    "C1201": { "short_description":"Engine Control System Malfunction",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThe Electronic Control Unit (ECU) has failed<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tOther warning lights may come on depending on which module is affected<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective ECU<br> •\tDamaged controller(s) due to abnormal system voltages<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tDiagnose and address all other codes first before replacing ECU<br> •\tCheck whether system voltage is within manufacturer’s recommendation<br> •\tInspect wiring to ECU and ensure that there are no open, shorted or broken wires<br> •\tReset all codes and do test drive. If the code returns you may have to replace ECU"},
+    "C121C": { "short_description":"Torque Request Signal Denied",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThis camshaft-related code is an informational. It comes with codes P0344, P0345 or P0365. Addressing those codes will get rid of this one"},
+    "C1223": { "short_description":"ABS Control System Malfunction",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThis code is set when the car’s vehicle stability control (VSC) system detects any malfunction in the ABS<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tABS warning light comes on<br> •\tCheck Engine Light comes on<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tOpen or short in the ABS circuit<br> •\tDefective ABS sensor<br> •\tDefective ABS control module<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring in the ABS circuit for loose, open or short connections<br> •\tPerform resistance test on ABS sensors and module. Replace as necessary<br> •\tReset code and do drive cycle, if it returns probe other systems, including PCM"},
+    "C1233": { "short_description":"Left Front Wheel Speed Sensor Input Signal Missing",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM or vehicle speed sensor (VSS) has failed to receive signals from the Left Front Wheel Speed Sensor<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tABS warning light comes on<br> •\tCheck Engine Light comes on<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tPoor connection in Left Front Wheel Speed Sensor<br> •\tOpen, shorted or broken wire in Left Front Wheel Speed Sensor harness<br> •\tDefective Left Front Wheel Speed Sensor<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring in the Left Front Wheel Speed Sensor circuit for loose, open or short connections<br> •\tPerform resistance test on Left Front Wheel Speed Sensor. Replace if necessary<br> •\tReset code and do drive cycle, if it returns probe ABS system entirely"},
+    "C1234": { "short_description":"Right Front Wheel Speed Sensor Input Signal Missing",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM or vehicle speed sensor (VSS) has failed to receive signals from the Right Front Wheel Speed Sensor<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tABS warning light comes on<br> •\tCheck Engine Light comes on<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tPoor connection in Right Front Wheel Speed Sensor<br> •\tOpen, shorted or broken wire in Right Front Wheel Speed Sensor harness<br> •\tDefective Right Front Wheel Speed Sensor<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring in the Right Front Wheel Speed Sensor circuit for loose, open or short connections<br> •\tPerform resistance test on Right Front Wheel Speed Sensor. Replace if necessary<br> •\tReset code and do drive cycle, if it returns probe ABS system entirely"},
+    "C1241": { "short_description":"Low Battery Positive Voltage",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tThis code is set when there’s a problem with the skid control ECU (master cylinder solenoid)<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tABS warning light comes on<br> •\tCheck Engine Light comes on<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tLow battery voltage<br> •\tUsing an incorrect battery<br> •\tUnmaintained battery<br> •\tHigh resistance either in alternator-battery circuit, alternator-PCM circuit or both<br> •\tDefective charging system<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tCheck whether battery voltage is sufficient<br> •\tEnsure battery is properly connected then check alternator belt<br> •\tUsing a digital volt ohm meter (DVOM), check whether the charging system is working<br> •\tReset the code then do a test drive. If the code returns check PCM voltage"},
+    "C1713": { "short_description":"Right Rear Height Control Sensor<br> Circuit<br> ",  "long_description":"<strong>1. Meaning:<\/strong><br> •\tPCM has detected that after switching ignition ON, a voltage of .3V or less, or 4.7V or more was achieved for more than 1 second at each height control sensor sub−assy rear<br> <br> <strong>3. Main Symptoms:<\/strong><br> •\tCheck Engine Light comes on<br> •\tHeight control indicator lamp (N) comes on or blinks<br> •\tVehicle won’t be able to perform height control function<br> <br> <br> <strong>4. Possible Causes:<\/strong><br> •\tDefective Right Rear Height Control Sensor<br> •\tWiring issue in Right Rear Height Control Sensor<br> •\tWorn out suspension and ride control parts<br> •\tProblem with shocks and/or struts<br> <br> <br> <strong>5. Diagnostic Steps:<\/strong><br> •\tVisually inspect all wiring in the RIGHT Rear Height Control Sensor circuit for loose, open or short connections<br> •\tPerform resistance test on Right Rear Height Control Sensor. Replace if necessary<br> •\tEnsure that all parts, including ball joints, springs (for ride height), shocks and struts are well maintained"}
+ }
\ No newline at end of file
diff --git a/tests/DiagnosticTools/res/raw/system_float_sensors.json b/tests/DiagnosticTools/res/raw/system_float_sensors.json
new file mode 100644
index 0000000..4311e10
--- /dev/null
+++ b/tests/DiagnosticTools/res/raw/system_float_sensors.json
@@ -0,0 +1,36 @@
+{
+  "FUEL_TANK_LEVEL_INPUT": {
+    "units": "%",
+    "translation": "x/2.55",
+    "name": "Fuel Tank Level Input"
+  },
+  "ENGINE_RPM": {
+    "units": "RPM",
+    "translation": "x/4",
+    "name": "Engine RPM"
+  },
+  "CALCULATED_ENGINE_LOAD": {
+    "units": "%",
+    "translation": "x/2.55",
+    "name": "Calculated Engine Load"
+  },
+  "SHORT_TERM_FUEL_TRIM_BANK1": {
+    "units": "%",
+    "conversion": {
+      "scale": 0.78125,
+      "offset": -100
+    },
+    "translation": "x/1.28 - 100",
+    "name": "Short Term Fuel Trim: Bank 1"
+  },
+  "VEHICLE_SPEED": {
+    "units": "KMH",
+    "translation": "",
+    "name": "Vehicle Speed"
+  },
+  "ENGINE_COOLANT_TEMPERATURE": {
+    "units": "C",
+    "translation": "x-40",
+    "name": "Engine Coolant Temperature"
+  }
+}
\ No newline at end of file
diff --git a/tests/DiagnosticTools/res/raw/system_integer_sensors.json b/tests/DiagnosticTools/res/raw/system_integer_sensors.json
new file mode 100644
index 0000000..a9f2775
--- /dev/null
+++ b/tests/DiagnosticTools/res/raw/system_integer_sensors.json
@@ -0,0 +1,23 @@
+{
+  "AMBIENT_AIR_TEMPERATURE": {
+    "units": "C",
+    "translation": "x-40",
+    "name": "Ambient Air Temperature"
+  },
+  "RUNTIME_SINCE_ENGINE_START": {
+    "units": "seconds",
+    "translation": "x-40",
+    "name": "Runtime Since Engine Start"
+  },
+  "FUEL_SYSTEM_STATUS": {
+    "units": "",
+    "mapping": {
+      "1": "Open loop due to insufficient engine temperature",
+      "2": "Closed loop, using oxygen sensor feedback to determine fuel mix",
+      "4": "Open loop due to engine load OR fuel cut due to deceleration",
+      "8": "Open loop due to system failure",
+      "16": "Closed loop, using at least one oxygen sensor but there is a fault in the feedback system"
+    },
+    "name": "Fuel System Status"
+  }
+}
\ No newline at end of file
diff --git a/tests/DiagnosticTools/res/raw/vendor_dtcs.json b/tests/DiagnosticTools/res/raw/vendor_dtcs.json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/tests/DiagnosticTools/res/raw/vendor_dtcs.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/tests/DiagnosticTools/res/raw/vendor_ecus.json b/tests/DiagnosticTools/res/raw/vendor_ecus.json
new file mode 100644
index 0000000..973e627
--- /dev/null
+++ b/tests/DiagnosticTools/res/raw/vendor_ecus.json
@@ -0,0 +1,7 @@
+{
+  "123": "Door Control Unit",
+  "124": "Engine Control Unit",
+  "125": "Engine Power Steering Control Unit",
+  "222": "Seat Control Unit",
+  "221": "Telematic Control Unit"
+}
\ No newline at end of file
diff --git a/tests/DiagnosticTools/res/raw/vendor_float_sensors.json b/tests/DiagnosticTools/res/raw/vendor_float_sensors.json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/tests/DiagnosticTools/res/raw/vendor_float_sensors.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/tests/DiagnosticTools/res/raw/vendor_integer_sensors.json b/tests/DiagnosticTools/res/raw/vendor_integer_sensors.json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/tests/DiagnosticTools/res/raw/vendor_integer_sensors.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/tests/DiagnosticTools/res/values-af/strings.xml b/tests/DiagnosticTools/res/values-af/strings.xml
new file mode 100644
index 0000000..57424bd
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-af/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Wys Vries Raam-inligting"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-am/strings.xml b/tests/DiagnosticTools/res/values-am/strings.xml
new file mode 100644
index 0000000..44fa319
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-am/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"የክፈፍ እሰር መረጃን አሳይ"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-ar/strings.xml b/tests/DiagnosticTools/res/values-ar/strings.xml
new file mode 100644
index 0000000..d2e46ff
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-ar/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"عرض معلومات عن الإطار الثابت"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-as/strings.xml b/tests/DiagnosticTools/res/values-as/strings.xml
new file mode 100644
index 0000000..98fc05f
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-as/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"ফ্ৰীজ ফ্ৰে’মৰ তথ্য দেখুৱাওক"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-az/strings.xml b/tests/DiagnosticTools/res/values-az/strings.xml
new file mode 100644
index 0000000..95f4ea9
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-az/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Stop-kadr məlumatını göstərin"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-b+sr+Latn/strings.xml b/tests/DiagnosticTools/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..fa16fed
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Prikaži informacije o zamrznutom okviru"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-be/strings.xml b/tests/DiagnosticTools/res/values-be/strings.xml
new file mode 100644
index 0000000..e73e14c
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-be/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Інфармацыя пра замарожаны кадр экрана"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-bg/strings.xml b/tests/DiagnosticTools/res/values-bg/strings.xml
new file mode 100644
index 0000000..71b4550
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-bg/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Показване на информацията за фиксиране на рамката"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-bn/strings.xml b/tests/DiagnosticTools/res/values-bn/strings.xml
new file mode 100644
index 0000000..56ce8c7
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-bn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"ফ্রিজ ফ্রেমের তথ্য দেখাও"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-bs/strings.xml b/tests/DiagnosticTools/res/values-bs/strings.xml
new file mode 100644
index 0000000..f049f27
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-bs/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Prikaz informacija o zamrznutom okviru"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-ca/strings.xml b/tests/DiagnosticTools/res/values-ca/strings.xml
new file mode 100644
index 0000000..9bcaa94
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-ca/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Mostra informació sobre el bloqueig del marc"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-cs/strings.xml b/tests/DiagnosticTools/res/values-cs/strings.xml
new file mode 100644
index 0000000..b769c80
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-cs/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Zobrazit informace o ukotveném rámci"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-da/strings.xml b/tests/DiagnosticTools/res/values-da/strings.xml
new file mode 100644
index 0000000..5472fde
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-da/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Vis oplysninger om stillbillede"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-de/strings.xml b/tests/DiagnosticTools/res/values-de/strings.xml
new file mode 100644
index 0000000..9aabaf5
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-de/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Informationen zum Freeze Frame anzeigen"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-el/strings.xml b/tests/DiagnosticTools/res/values-el/strings.xml
new file mode 100644
index 0000000..ec201ec
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-el/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Εμφάνιση πληροφοριών σταθεροποίησης πλαισίου"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-en-rAU/strings.xml b/tests/DiagnosticTools/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..bd4ccb9
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-en-rAU/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Display freeze frame Info"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-en-rCA/strings.xml b/tests/DiagnosticTools/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..bd4ccb9
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-en-rCA/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Display freeze frame Info"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-en-rGB/strings.xml b/tests/DiagnosticTools/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..bd4ccb9
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-en-rGB/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Display freeze frame Info"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-en-rIN/strings.xml b/tests/DiagnosticTools/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..bd4ccb9
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-en-rIN/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Display freeze frame Info"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-en-rXC/strings.xml b/tests/DiagnosticTools/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..6203c22
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-en-rXC/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‎‎‏‎‎‎‏‎‏‎‎‏‏‏‎‏‏‎‏‏‎‎‏‎‏‎‏‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‏‏‏‎‎‎‎‏‏‎Display Freeze Frame Info‎‏‎‎‏‎"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-es-rUS/strings.xml b/tests/DiagnosticTools/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..437c8df
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-es-rUS/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Mostrar información del fotograma bloqueado"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-es/strings.xml b/tests/DiagnosticTools/res/values-es/strings.xml
new file mode 100644
index 0000000..e1c0523
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-es/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Mostrar información del marco inmovilizado"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-et/strings.xml b/tests/DiagnosticTools/res/values-et/strings.xml
new file mode 100644
index 0000000..cdeb1c6
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-et/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Kuva hangunud kaadri teave"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-eu/strings.xml b/tests/DiagnosticTools/res/values-eu/strings.xml
new file mode 100644
index 0000000..5adc732
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-eu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Bistaratu fotogramaren informazioa"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-fa/strings.xml b/tests/DiagnosticTools/res/values-fa/strings.xml
new file mode 100644
index 0000000..9785166
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-fa/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"نمایش اطلاعات Freeze Frame"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-fi/strings.xml b/tests/DiagnosticTools/res/values-fi/strings.xml
new file mode 100644
index 0000000..e19f9f9
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-fi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Näytä pysäytetyn kehyksen tiedot"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-fr-rCA/strings.xml b/tests/DiagnosticTools/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..c67b69e
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-fr-rCA/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Afficher les renseignements de l\'arrêt sur image"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-fr/strings.xml b/tests/DiagnosticTools/res/values-fr/strings.xml
new file mode 100644
index 0000000..f7b39e9
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-fr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Afficher les informations sur l\'image fixe"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-gl/strings.xml b/tests/DiagnosticTools/res/values-gl/strings.xml
new file mode 100644
index 0000000..6f9c271
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-gl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Mostrar información de marco fixo"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-gu/strings.xml b/tests/DiagnosticTools/res/values-gu/strings.xml
new file mode 100644
index 0000000..bf3308f
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-gu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"ફ્રેમને સ્થિર કરવા માટેની માહિતી બતાવો"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-hi/strings.xml b/tests/DiagnosticTools/res/values-hi/strings.xml
new file mode 100644
index 0000000..0975220
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-hi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"फ़्रेम को फ़्रीज़ करने की जानकारी दिखाएं"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-hr/strings.xml b/tests/DiagnosticTools/res/values-hr/strings.xml
new file mode 100644
index 0000000..f049f27
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-hr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Prikaz informacija o zamrznutom okviru"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-hu/strings.xml b/tests/DiagnosticTools/res/values-hu/strings.xml
new file mode 100644
index 0000000..3f6c0db
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-hu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Freeze Frame-adat megjelenítése"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-hy/strings.xml b/tests/DiagnosticTools/res/values-hy/strings.xml
new file mode 100644
index 0000000..f121ac9
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-hy/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Ցուցադրել սառեցված կադրի տվյալները"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-in/strings.xml b/tests/DiagnosticTools/res/values-in/strings.xml
new file mode 100644
index 0000000..cf97c3c
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-in/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Tampilkan Info Freeze Frame"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-is/strings.xml b/tests/DiagnosticTools/res/values-is/strings.xml
new file mode 100644
index 0000000..e6b6ae9
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-is/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Birta upplýsingar um frystan ramma"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-it/strings.xml b/tests/DiagnosticTools/res/values-it/strings.xml
new file mode 100644
index 0000000..d35ff17
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-it/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Mostra informazioni sul fotogramma di blocco"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-iw/strings.xml b/tests/DiagnosticTools/res/values-iw/strings.xml
new file mode 100644
index 0000000..e0065b7
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-iw/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"הצגת פרטים על הקפאת מסגרת"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-ja/strings.xml b/tests/DiagnosticTools/res/values-ja/strings.xml
new file mode 100644
index 0000000..4c75450
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-ja/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"ディスプレイ フリーズ フレーム情報"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-ka/strings.xml b/tests/DiagnosticTools/res/values-ka/strings.xml
new file mode 100644
index 0000000..cf35524
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-ka/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"სტოპ-კადრის ინფორმაციის ჩვენება"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-kk/strings.xml b/tests/DiagnosticTools/res/values-kk/strings.xml
new file mode 100644
index 0000000..04626ed
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-kk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Стоп-кадр ақпаратын көрсету"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-km/strings.xml b/tests/DiagnosticTools/res/values-km/strings.xml
new file mode 100644
index 0000000..37f54f4
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-km/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"បង្ហាញ​ព័ត៌មាន​អំពីស៊ុម​គាំង"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-kn/strings.xml b/tests/DiagnosticTools/res/values-kn/strings.xml
new file mode 100644
index 0000000..cf4e172
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-kn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"ಫ್ರೀಜ್ ಫ್ರೇಮ್ ಮಾಹಿತಿಯನ್ನು ಡಿಸ್‌ಪ್ಲೇ ಮಾಡಿ"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-ko/strings.xml b/tests/DiagnosticTools/res/values-ko/strings.xml
new file mode 100644
index 0000000..26fea08
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-ko/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"정지 화면 정보 표시"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-ky/strings.xml b/tests/DiagnosticTools/res/values-ky/strings.xml
new file mode 100644
index 0000000..c74ecfc
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-ky/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Freeze Frame\'дин маалыматын чагылдыруу"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-lo/strings.xml b/tests/DiagnosticTools/res/values-lo/strings.xml
new file mode 100644
index 0000000..34a5849
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-lo/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"ສະແດງຂໍ້ມູນເຟຣມຄ້າງ"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-lt/strings.xml b/tests/DiagnosticTools/res/values-lt/strings.xml
new file mode 100644
index 0000000..1f83787
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-lt/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Rodyti užfiksuoto kadro informaciją"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-lv/strings.xml b/tests/DiagnosticTools/res/values-lv/strings.xml
new file mode 100644
index 0000000..a835124
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-lv/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Rādīt fiksētā kadra informāciju"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-mk/strings.xml b/tests/DiagnosticTools/res/values-mk/strings.xml
new file mode 100644
index 0000000..804ab83
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-mk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Информации за замрзната рамка на екранот"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-ml/strings.xml b/tests/DiagnosticTools/res/values-ml/strings.xml
new file mode 100644
index 0000000..dc612dd
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-ml/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"ഫ്രീസ് ഫ്രെയിമിനെക്കുറിച്ചുള്ള വിവരം കാണിക്കുക"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-mn/strings.xml b/tests/DiagnosticTools/res/values-mn/strings.xml
new file mode 100644
index 0000000..ded1e9a
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-mn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Freeze Frame-н мэдээлэл харуулах"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-mr/strings.xml b/tests/DiagnosticTools/res/values-mr/strings.xml
new file mode 100644
index 0000000..94eea43
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-mr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"फ्रीझ फ्रेम माहिती प्रदर्शित करा"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-ms/strings.xml b/tests/DiagnosticTools/res/values-ms/strings.xml
new file mode 100644
index 0000000..67d2ba0
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-ms/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Paparkan Maklumat Bingkai Pegun"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-my/strings.xml b/tests/DiagnosticTools/res/values-my/strings.xml
new file mode 100644
index 0000000..98c8d16
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-my/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"ရပ်နေသည့်ဖရိမ် အချက်အလက်များကို ပြရန်"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-nb/strings.xml b/tests/DiagnosticTools/res/values-nb/strings.xml
new file mode 100644
index 0000000..51af902
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-nb/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Vis informasjon om øyeblikksbildet"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-ne/strings.xml b/tests/DiagnosticTools/res/values-ne/strings.xml
new file mode 100644
index 0000000..c227447
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-ne/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"डिस्प्ले फ्रिज गर्ने फ्रेमसम्बन्धी जानकारी"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-nl/strings.xml b/tests/DiagnosticTools/res/values-nl/strings.xml
new file mode 100644
index 0000000..a808fd2
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-nl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Informatie over freeze frame weergeven"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-or/strings.xml b/tests/DiagnosticTools/res/values-or/strings.xml
new file mode 100644
index 0000000..22df718
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-or/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"ଫ୍ରିଜ୍ ଫ୍ରେମ୍ ସୂଚନା ପ୍ରଦର୍ଶନ କରନ୍ତୁ"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-pa/strings.xml b/tests/DiagnosticTools/res/values-pa/strings.xml
new file mode 100644
index 0000000..a2277c6
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-pa/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"ਫ੍ਰੀਜ਼ ਫ੍ਰੇਮ ਜਾਣਕਾਰੀ ਦਿਖਾਓ"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-pl/strings.xml b/tests/DiagnosticTools/res/values-pl/strings.xml
new file mode 100644
index 0000000..4828319
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-pl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Wyświetl informacje o zatrzymanej klatce"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-pt-rPT/strings.xml b/tests/DiagnosticTools/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..d768d53
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-pt-rPT/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Apresentar informações de frame fixo"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-pt/strings.xml b/tests/DiagnosticTools/res/values-pt/strings.xml
new file mode 100644
index 0000000..968bfe1
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-pt/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Mostrar informação do congelamento do frame"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-ro/strings.xml b/tests/DiagnosticTools/res/values-ro/strings.xml
new file mode 100644
index 0000000..d06e299
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-ro/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Afișați informații despre cadrul blocat"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-ru/strings.xml b/tests/DiagnosticTools/res/values-ru/strings.xml
new file mode 100644
index 0000000..482ee1b
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-ru/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Показывать информацию на стоп-кадре"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-si/strings.xml b/tests/DiagnosticTools/res/values-si/strings.xml
new file mode 100644
index 0000000..3304298
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-si/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"ඇවුරුම් රාමු තතු සංදර්ශනය"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-sk/strings.xml b/tests/DiagnosticTools/res/values-sk/strings.xml
new file mode 100644
index 0000000..967abff
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-sk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Zobraziť informácie o ukotvenom rámci"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-sl/strings.xml b/tests/DiagnosticTools/res/values-sl/strings.xml
new file mode 100644
index 0000000..c856e68
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-sl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Prikaz podatkov o zamrznjenem okviru"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-sq/strings.xml b/tests/DiagnosticTools/res/values-sq/strings.xml
new file mode 100644
index 0000000..a129f8d
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-sq/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Shfaq informacionin e ngrirjes së kuadrit"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-sr/strings.xml b/tests/DiagnosticTools/res/values-sr/strings.xml
new file mode 100644
index 0000000..abae266
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-sr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Прикажи информације о замрзнутом оквиру"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-sv/strings.xml b/tests/DiagnosticTools/res/values-sv/strings.xml
new file mode 100644
index 0000000..ab70663
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-sv/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Visa information om fryst bildruta"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-sw/strings.xml b/tests/DiagnosticTools/res/values-sw/strings.xml
new file mode 100644
index 0000000..c3f839e
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-sw/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Onyesha Maelezo kuhusu Fremu ya Kufanya Skrini Isisonge"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-ta/strings.xml b/tests/DiagnosticTools/res/values-ta/strings.xml
new file mode 100644
index 0000000..09e74cc
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-ta/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"ஃப்ரீஸ் ஃப்ரேம் தகவலைக் காட்டு"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-te/strings.xml b/tests/DiagnosticTools/res/values-te/strings.xml
new file mode 100644
index 0000000..dfad13b
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-te/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"స్తంభించిన ఫ్రేమ్ సమాచారాన్ని ప్రదర్శించు"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-th/strings.xml b/tests/DiagnosticTools/res/values-th/strings.xml
new file mode 100644
index 0000000..098229f
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-th/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"แสดงข้อมูลเฟรมค้าง"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-tl/strings.xml b/tests/DiagnosticTools/res/values-tl/strings.xml
new file mode 100644
index 0000000..561b1e8
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-tl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Ipakita ang Impormasyon ng Freeze Frame"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-tr/strings.xml b/tests/DiagnosticTools/res/values-tr/strings.xml
new file mode 100644
index 0000000..e7c5340
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-tr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Kare Dondurma Bilgilerini Göster"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-uk/strings.xml b/tests/DiagnosticTools/res/values-uk/strings.xml
new file mode 100644
index 0000000..073f940
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-uk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Інформація про показ стоп-кадру"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-ur/strings.xml b/tests/DiagnosticTools/res/values-ur/strings.xml
new file mode 100644
index 0000000..07254b9
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-ur/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"فریز کو فریم کرنے کی معلومات دکھائیں"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-uz/strings.xml b/tests/DiagnosticTools/res/values-uz/strings.xml
new file mode 100644
index 0000000..40b606e
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-uz/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Stop-kadrni chiqarish axboroti"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-vi/strings.xml b/tests/DiagnosticTools/res/values-vi/strings.xml
new file mode 100644
index 0000000..a2b79b0
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-vi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Hiển thị thông tin về khung cố định"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-zh-rCN/strings.xml b/tests/DiagnosticTools/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..f7bdfea
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-zh-rCN/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"显示冻结帧信息"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-zh-rHK/strings.xml b/tests/DiagnosticTools/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..4733dbb
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-zh-rHK/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"顯示頁框凍結資訊"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-zh-rTW/strings.xml b/tests/DiagnosticTools/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..103d099
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-zh-rTW/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"顯示凍結頁框資訊"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values-zu/strings.xml b/tests/DiagnosticTools/res/values-zu/strings.xml
new file mode 100644
index 0000000..94ff953
--- /dev/null
+++ b/tests/DiagnosticTools/res/values-zu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_freeze_frame_info" msgid="1425573367248263107">"Bonisa ulwazi lokumisa uzimele"</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values/strings.xml b/tests/DiagnosticTools/res/values/strings.xml
new file mode 100644
index 0000000..fa8fb51
--- /dev/null
+++ b/tests/DiagnosticTools/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+    <string name="display_freeze_frame_info">Display Freeze Frame Info</string>
+</resources>
diff --git a/tests/DiagnosticTools/res/values/styles.xml b/tests/DiagnosticTools/res/values/styles.xml
new file mode 100644
index 0000000..66e44ff
--- /dev/null
+++ b/tests/DiagnosticTools/res/values/styles.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+    <style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
+        <item name="android:colorPrimary">#008577</item>
+        <item name="android:colorPrimaryDark">#00574B</item>
+        <item name="android:colorAccent">#D81B60</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowActionBar">false</item>
+    </style>
+
+</resources>
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/DTC.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/DTC.java
new file mode 100644
index 0000000..ca75157
--- /dev/null
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/DTC.java
@@ -0,0 +1,183 @@
+/*
+ * 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.diagnostictools;
+
+import android.content.Context;
+import android.os.Parcel;
+import android.text.Html;
+import android.text.Spanned;
+import android.text.SpannedString;
+
+import com.google.android.car.diagnostictools.utils.DTCMetadata;
+import com.google.android.car.diagnostictools.utils.MetadataProcessing;
+import com.google.android.car.diagnostictools.utils.SelectableRowModel;
+
+import java.util.Random;
+
+/**
+ * Model which wraps DTC code and metadata information for display through DTCAdapter. Extends
+ * SelectableRowModel to allow for selection and use with SelectableAdapter
+ */
+public class DTC extends SelectableRowModel implements android.os.Parcelable {
+
+    public static final Creator<DTC> CREATOR =
+            new Creator<DTC>() {
+                @Override
+                public DTC createFromParcel(Parcel source) {
+                    return new DTC(source);
+                }
+
+                @Override
+                public DTC[] newArray(int size) {
+                    return new DTC[size];
+                }
+            };
+    private static final String TAG = "DTC";
+    private static Random sRandomGen;
+    private String mCode;
+    private String mDescription;
+    private long mTimestamp;
+    private Spanned mLongDescription;
+    private String mStringLongDescription; // Used for Parcelable compatibility
+
+    /**
+     * Full constructor for DTC.
+     *
+     * @param code DTC code associated with the DTC
+     * @param description Short description associated with the DTC
+     * @param timestamp Timestamp associated with the DTC
+     * @param longDescription Long descriptions associated with the DTC
+     * @param stringLongDescription String version of longDescription for Parcelable support
+     */
+    private DTC(
+            String code,
+            String description,
+            long timestamp,
+            Spanned longDescription,
+            String stringLongDescription) {
+        this.mCode = code;
+        this.mDescription = description;
+        this.mTimestamp = timestamp;
+        this.mLongDescription = longDescription;
+        this.mStringLongDescription = stringLongDescription;
+    }
+
+    /**
+     * Paired down constructor that utilizes DTC metadata that is preloaded.
+     *
+     * @param code DTC code associated with the DTC
+     * @param timestamp Timestamp associated with the DTC
+     * @param context Context from which this is called. Required to allow MetadataProcessing to be
+     *     loaded if the singleton has not been instantiated
+     */
+    DTC(String code, long timestamp, Context context) {
+        this.mCode = code;
+        this.mTimestamp = timestamp;
+        DTCMetadata dtcMetadata = getDTCMetadata(code, context);
+        if (dtcMetadata != null) {
+            this.mDescription = dtcMetadata.getShortDescription();
+            this.mLongDescription = dtcMetadata.getSpannedLongDescription();
+            this.mStringLongDescription = dtcMetadata.getStringLongDescription();
+        } else {
+            this.mDescription = "No Description Available";
+            this.mLongDescription = SpannedString.valueOf("No Details Available");
+            this.mStringLongDescription = "No Details Available";
+        }
+    }
+
+    protected DTC(Parcel in) {
+        this.mCode = in.readString();
+        this.mDescription = in.readString();
+        this.mTimestamp = in.readLong();
+        this.mStringLongDescription = in.readString();
+        this.mLongDescription = Html.fromHtml(this.mStringLongDescription, 0);
+    }
+
+    public String getCode() {
+        return mCode;
+    }
+
+    public String getDescription() {
+        return mDescription;
+    }
+
+    public long getTimestamp() {
+        return mTimestamp;
+    }
+
+    //Delete when DTCs are implemented
+    public void setTimestamp(long timestamp) {
+        mTimestamp = timestamp;
+    }
+
+    public Spanned getLongDescription() {
+        return mLongDescription;
+    }
+
+
+    /**
+     * Create sample DTC using MetadataProcessing for values. Some numbers will not return actual
+     * values and will be replaced with placeholder information that would be presented if metadata
+     * wasn't found.
+     *
+     * @param number Used to generate the DTC code which will be "P(008+number)"
+     * @param context Context from which this is called. Required to allow MetadataProcessing to be
+     *     loaded if the singleton has not been instantiated
+     * @return New sample DTC based on number and metadata
+     */
+    static DTC createSampleDTC(int number, Context context) {
+        String code = String.format("P%04d", 8 + number);
+        if (sRandomGen == null) {
+            sRandomGen = new Random();
+        }
+        long timestamp = sRandomGen.nextLong();
+        return new DTC(code, timestamp, context);
+    }
+
+    private DTCMetadata getDTCMetadata(String code, Context context) {
+        return MetadataProcessing.getInstance(context).getDTCMetadata(code);
+    }
+
+    /**
+     * Implement method of SelectableRowModel. One element is selected as the DTC is the base child
+     *
+     * @return Returns 1 (as DTC is the based element)
+     */
+    @Override
+    public int numSelected() {
+        return 1;
+    }
+
+    /** TODO: Calls VHAL DTC delete method to allow this DTC to be cleared */
+    @Override
+    public void delete() {
+        // TODO clear DTC
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(this.mCode);
+        dest.writeString(this.mDescription);
+        dest.writeLong(this.mTimestamp);
+        dest.writeString(this.mStringLongDescription);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/DTCAdapter.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/DTCAdapter.java
new file mode 100644
index 0000000..f837666
--- /dev/null
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/DTCAdapter.java
@@ -0,0 +1,98 @@
+/*
+ * 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.diagnostictools;
+
+import android.content.Context;
+import android.content.Intent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+
+import com.google.android.car.diagnostictools.utils.SelectableAdapter;
+
+import java.util.List;
+
+/** Adapter for RecyclerView in DTCListActivity which displays DTCs */
+public class DTCAdapter extends SelectableAdapter<DTC, RowViewHolder> {
+
+    private List<DTC> mDtcs;
+    private Context mContext;
+
+    DTCAdapter(List<DTC> inputDTCs, Context context) {
+        mDtcs = inputDTCs;
+        mContext = context;
+    }
+
+    @NonNull
+    @Override
+    public RowViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+
+        View v = inflater.inflate(R.layout.row_layout, parent, false);
+
+        return new RowViewHolder(v, true, false, false);
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull RowViewHolder holder, int position) {
+        final DTC refDTC = mDtcs.get(position);
+        final RowViewHolder finalHolder = holder;
+        holder.setFields(refDTC.getCode(), refDTC.getDescription(), "", false);
+        refDTC.setColor(finalHolder);
+        holder.layout.setOnClickListener(
+                new OnClickListener() {
+                    @Override
+                    public void onClick(View view) {
+                        if (hasSelected()) {
+                            toggleSelect(refDTC);
+                            refDTC.setColor(finalHolder);
+                        } else {
+                            Intent intent = new Intent(mContext, DTCDetailActivity.class);
+                            intent.putExtra("dtc", refDTC);
+                            mContext.startActivity(intent);
+                        }
+                    }
+                });
+        holder.layout.setOnLongClickListener(
+                new View.OnLongClickListener() {
+                    @Override
+                    public boolean onLongClick(View view) {
+                        toggleSelect(refDTC);
+                        refDTC.setColor(finalHolder);
+                        return true;
+                    }
+                });
+    }
+
+    @Override
+    public int getItemCount() {
+        return mDtcs.size();
+    }
+
+    /**
+     * Overrides method getBaseList of SelectableAdapter to allow selection of elements
+     *
+     * @return base list of DTCs
+     */
+    @Override
+    protected List<DTC> getBaseList() {
+        return mDtcs;
+    }
+}
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/DTCDetailActivity.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/DTCDetailActivity.java
new file mode 100644
index 0000000..e532b3d
--- /dev/null
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/DTCDetailActivity.java
@@ -0,0 +1,223 @@
+/*
+ * 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.diagnostictools;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.car.Car;
+import android.car.diagnostic.CarDiagnosticEvent;
+import android.car.diagnostic.CarDiagnosticManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.Toolbar;
+
+import androidx.recyclerview.widget.DividerItemDecoration;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.android.car.diagnostictools.utils.MetadataProcessing;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Displays detailed information about a specific DTC. Opened through clicking a DTC in
+ * DTCListActivity
+ */
+public class DTCDetailActivity extends Activity {
+
+    private static final String TAG = "DTCDetailActivity";
+    private final Handler mHandler = new Handler();
+    private Car mCar;
+    private Toolbar mDTCTitle;
+    private TextView mDTCDetails;
+    private DTC mDTC;
+    private ProgressBar mFreezeFrameLoading;
+    private TextView mFreezeFrameTitle;
+    private Button mFreezeFrameClear;
+    private RecyclerView mFreezeFrameData;
+    private CarDiagnosticManager mCarDiagnosticManager;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_dtc_details);
+
+        mDTCTitle = findViewById(R.id.toolbar);
+        mDTCTitle.setNavigationIcon(R.drawable.ic_arrow_back_black_24dp);
+        mDTCTitle.setNavigationOnClickListener(
+                view -> {
+                    finish();
+                    mHandler.removeCallbacksAndMessages(null);
+                });
+        mDTCDetails = findViewById(R.id.dtc_details);
+        mFreezeFrameLoading = findViewById(R.id.freeze_frame_loading);
+        mFreezeFrameTitle = findViewById(R.id.freeze_frame_title);
+        mFreezeFrameClear = findViewById(R.id.freeze_frame_clear);
+        mFreezeFrameData = findViewById(R.id.freeze_frame_data);
+
+        hideFreezeFrameFields();
+
+        // Set up RecyclerView
+        mFreezeFrameData.setHasFixedSize(false);
+        mFreezeFrameData.setLayoutManager(new LinearLayoutManager(DTCDetailActivity.this));
+        final List<LiveDataAdapter.SensorDataWrapper> input = new ArrayList<>();
+        // Add test data
+        for (int i = 0; i < 100; i++) {
+            input.add(new LiveDataAdapter.SensorDataWrapper("Test " + i, "%", i));
+        }
+        LiveDataAdapter adapter = new LiveDataAdapter(input);
+        mFreezeFrameData.setAdapter(adapter);
+        mFreezeFrameData.addItemDecoration(
+                new DividerItemDecoration(
+                        mFreezeFrameData.getContext(), DividerItemDecoration.VERTICAL));
+
+        loadingFreezeFrame();
+
+        mCar = Car.createCar(this);
+        mCarDiagnosticManager = (CarDiagnosticManager) mCar.getCarManager(Car.DIAGNOSTIC_SERVICE);
+
+        // Runnable function that checks to see if there is a Freeze Frame available or not.
+        // Repeats
+        // until there is a Freeze Frame available
+        mHandler.postDelayed(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        long[] timestamps = mCarDiagnosticManager.getFreezeFrameTimestamps();
+                        Log.e(TAG, "onCreate: Number of timestamps" + timestamps.length);
+                        if (timestamps.length > 0) {
+                            CarDiagnosticEvent freezeFrame =
+                                    mCarDiagnosticManager.getFreezeFrame(
+                                            timestamps[timestamps.length - 1]);
+                            adapter.update(
+                                    LiveDataActivity.processSensorInfoIntoWrapper(
+                                            freezeFrame,
+                                            MetadataProcessing.getInstance(
+                                                    DTCDetailActivity.this)));
+                            loadedFreezeFrame();
+                            mDTC.setTimestamp(timestamps[timestamps.length - 1]);
+                        } else {
+                            hideFreezeFrameFields();
+                            mHandler.postDelayed(this, 2000);
+                        }
+                    }
+                },
+                0);
+
+        getIncomingIntent();
+    }
+
+    /** Removes all callbacks from mHandler when DTCDetailActivity is destroyed */
+    @Override
+    protected void onDestroy() {
+        if (mHandler != null) {
+            mHandler.removeCallbacksAndMessages(null);
+        }
+        if (mCar != null && mCar.isConnected()) {
+            mCar.disconnect();
+            mCar = null;
+        }
+        super.onDestroy();
+    }
+
+    /** Handle incoming intent to extract extras. */
+    private void getIncomingIntent() {
+        Log.d(TAG, "getIncomingIntent: extras: " + getIntent().toString());
+        if (getIntent().hasExtra("dtc")) {
+            mDTC = getIntent().getParcelableExtra("dtc");
+            setUpDetailPage();
+        }
+    }
+
+    /** Assuming dtc has been set to a DTC. */
+    private void setUpDetailPage() {
+        if (mDTC != null) {
+            mDTCTitle.setTitle(mDTC.getCode() + ": " + mDTC.getDescription());
+            mDTCDetails.setText(mDTC.getLongDescription());
+        } else {
+            mDTCTitle.setTitle("No DTC input");
+            mDTCDetails.setText("No DTC long description");
+        }
+    }
+
+    /** Hide all Freeze Frame associated elements. */
+    private void hideFreezeFrameFields() {
+        mFreezeFrameData.setVisibility(View.INVISIBLE);
+        mFreezeFrameClear.setVisibility(View.INVISIBLE);
+        mFreezeFrameTitle.setVisibility(View.INVISIBLE);
+        mFreezeFrameLoading.setVisibility(View.INVISIBLE);
+    }
+
+    /** Hide most Freeze Frame associated elements and tell user that there isn't one available. */
+    private void noFreezeFrameAvailable() {
+        hideFreezeFrameFields();
+        mFreezeFrameTitle.setVisibility(View.VISIBLE);
+        mFreezeFrameTitle.setText(
+                "No Freeze Frame Data Available Right Now. Data will appear if becomes available");
+    }
+
+    /** Indicate to the user that a freeze frame is being loaded with a spinning progress bar */
+    private void loadingFreezeFrame() {
+        mFreezeFrameTitle.setVisibility(View.VISIBLE);
+        mFreezeFrameTitle.setText("Freeze Frame Loading...");
+        mFreezeFrameLoading.setVisibility(View.VISIBLE);
+    }
+
+    /**
+     * Displays freeze frame and conditionally displays button to clear it based on if functionality
+     * is supported
+     */
+    private void loadedFreezeFrame() {
+        mFreezeFrameLoading.setVisibility(View.INVISIBLE);
+        if (mCarDiagnosticManager.isClearFreezeFramesSupported()
+                && mCarDiagnosticManager.isSelectiveClearFreezeFramesSupported()) {
+            mFreezeFrameClear.setVisibility(View.VISIBLE);
+        }
+        mFreezeFrameData.setVisibility(View.VISIBLE);
+        mFreezeFrameTitle.setText("Freeze Frame");
+    }
+
+    /**
+     * Handles button press of the clear Freeze Frame button. Confirms that the user would like to
+     * do this action and then clears Frames with Manager methods
+     *
+     * @param v View that triggered the function
+     */
+    public void clearFreezeFrameButtonPress(View v) {
+        new AlertDialog.Builder(this)
+                .setTitle("Confirm Freeze Frame Clear")
+                .setMessage(
+                        String.format(
+                                "Do you really want to clear the freeze frame for DTC %s?",
+                                mDTC.getCode()))
+                .setIcon(android.R.drawable.ic_dialog_alert)
+                .setPositiveButton(
+                        android.R.string.yes,
+                        (dialog, whichButton) -> {
+                            mCarDiagnosticManager.clearFreezeFrames(mDTC.getTimestamp());
+                            hideFreezeFrameFields();
+                        })
+                .setNegativeButton(android.R.string.no, null)
+                .show();
+    }
+}
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/DTCListActivity.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/DTCListActivity.java
new file mode 100644
index 0000000..4d7220b
--- /dev/null
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/DTCListActivity.java
@@ -0,0 +1,89 @@
+/*
+ * 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.diagnostictools;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.Toolbar;
+
+import androidx.recyclerview.widget.DividerItemDecoration;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.List;
+
+/** Displays a list of DTCs associated with an ECU */
+public class DTCListActivity extends Activity {
+
+    private static final String TAG = "DTCListActivity";
+    private String mEcuName;
+    private List<DTC> mDtcs;
+    private Toolbar mEcuTitle;
+    private RecyclerView mDTCList;
+    private DTCAdapter mAdapter;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_dtc_list);
+        mEcuTitle = findViewById(R.id.toolbar);
+        mEcuTitle.setNavigationIcon(R.drawable.ic_arrow_back_black_24dp);
+        mEcuTitle.setNavigationOnClickListener(view -> finish());
+
+        mDTCList = findViewById(R.id.dtc_list);
+        mDTCList.setHasFixedSize(true);
+        mDTCList.setLayoutManager(new LinearLayoutManager(this));
+        getIncomingIntent();
+    }
+
+    /** Handle incoming intent and extras. Extract ECU name and DTC list */
+    private void getIncomingIntent() {
+        Log.d(TAG, "getIncomingIntent: extras: " + getIntent().toString());
+        if (getIntent().hasExtra("name")) {
+            mEcuName = getIntent().getStringExtra("name");
+            mEcuTitle.setTitle(mEcuName);
+        }
+        if (getIntent().hasExtra("dtcs")) {
+            mDtcs = getIntent().getParcelableArrayListExtra("dtcs");
+            mAdapter = new DTCAdapter(mDtcs, this);
+            mDTCList.setAdapter(mAdapter);
+            mDTCList.addItemDecoration(
+                    new DividerItemDecoration(
+                            mDTCList.getContext(), DividerItemDecoration.VERTICAL));
+        }
+    }
+
+    /**
+     * Handle clicks from the ActionButton. Confirms that the user wants to clear selected DTCs and
+     * then deletes them on confirmation.
+     */
+    public void onClickActionButton(View view) {
+        new AlertDialog.Builder(this)
+                .setTitle("Clear DTCs")
+                .setMessage(
+                        String.format(
+                                "Do you really want to clear %d mDtcs?", mAdapter.numSelected()))
+                .setIcon(android.R.drawable.ic_dialog_alert)
+                .setPositiveButton(
+                        android.R.string.yes, (dialog, whichButton) -> mAdapter.deleteSelected())
+                .setNegativeButton(android.R.string.no, null)
+                .show();
+    }
+}
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/ECU.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/ECU.java
new file mode 100644
index 0000000..ca8fe3c
--- /dev/null
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/ECU.java
@@ -0,0 +1,131 @@
+/*
+ * 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.diagnostictools;
+
+import android.content.Context;
+
+import com.google.android.car.diagnostictools.utils.MetadataProcessing;
+import com.google.android.car.diagnostictools.utils.SelectableRowModel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Model which wraps ECU data (address, name, and associated DTCs) and extends SelectableRowModel to
+ * enable the selection of ECU elements.
+ */
+public class ECU extends SelectableRowModel {
+
+    private String mAddress;
+    private String mName;
+    /**
+     * MUST be locked when integrating DTC properties to prevent issues with parallel adding and
+     * deleting.
+     */
+    private List<DTC> mDtcs;
+
+    /**
+     * Full constructor that creates an ECU model with its address, name, and list of associated
+     * DTCs.
+     *
+     * @param address Address for ECU
+     * @param name Human readable name for ECU
+     * @param dtcs List of DTCs that are raised by the ECU
+     */
+    private ECU(String address, String name, List<DTC> dtcs) {
+        mAddress = address;
+        mName = name;
+        this.mDtcs = dtcs;
+    }
+
+    /**
+     * Paired down constructor that creates an ECU based on its address, list of associated DTCs,
+     * and metadata.
+     *
+     * @param address Address for ECU
+     * @param dtcs List of DTCs that are raised by the ECU
+     * @param context Context from which this is called. Required to allow MetadataProcessing to be
+     *     loaded if the singleton has not been instantiated
+     */
+    public ECU(String address, List<DTC> dtcs, Context context) {
+        mAddress = address;
+        this.mDtcs = dtcs;
+        String metadata = MetadataProcessing.getInstance(context).getECUMetadata(address);
+        if (metadata != null) {
+            this.mName = metadata;
+        } else {
+            this.mName = "No Name Available";
+        }
+    }
+
+    public String getAddress() {
+        return mAddress;
+    }
+
+    public String getName() {
+        return mName;
+    }
+
+    public List<DTC> getDtcs() {
+        return mDtcs;
+    }
+
+    /**
+     * Create sample DTC using MetadataProcessing for values. Some numbers will not return actual
+     * values and will be replaced with placeholder information that would be presented if metadata
+     * wasn't found.
+     *
+     * @param number Used to generate the DTC code which will be "P(008+number)"
+     * @param context Context from which this is called. Required to allow MetadataProcessing to be
+     *     loaded if the singleton has not been instantiated
+     * @return New sample DTC based on number and metadata
+     */
+    static ECU createSampleECU(int number, Context context) {
+        List<DTC> dtcs = new ArrayList<>();
+        String address = (number + 123) + "";
+
+        ECU rtrECU = new ECU(address, dtcs, context);
+
+        for (int i = 0; i < number; i++) {
+            dtcs.add(DTC.createSampleDTC(i, context));
+        }
+        return rtrECU;
+    }
+
+    /**
+     * Implement method of SelectableRowModel. The number of elements selected is based on the
+     * number of elements in its children
+     *
+     * @return Returns the number of DTCs that are its children (as DTC is the based element)
+     */
+    @Override
+    public int numSelected() {
+        int count = 0;
+        for (DTC dtc : mDtcs) {
+            count += dtc.numSelected();
+        }
+        return count;
+    }
+
+    /** Runs the implemented delete method in the DTC model to delete records on a VHAL level */
+    @Override
+    public void delete() {
+        for (DTC dtc : mDtcs) {
+            dtc.delete();
+        }
+    }
+}
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/ECUAdapter.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/ECUAdapter.java
new file mode 100644
index 0000000..e8eda50
--- /dev/null
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/ECUAdapter.java
@@ -0,0 +1,99 @@
+/*
+ * 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.diagnostictools;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Parcelable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+
+import com.google.android.car.diagnostictools.utils.SelectableAdapter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Adapter for RecyclerView in ECUListActivity which displays ECUs */
+public class ECUAdapter extends SelectableAdapter<ECU, RowViewHolder> {
+
+    private List<ECU> mEcuOrderedList;
+    private Context mContext;
+
+    public ECUAdapter(List<ECU> ecusIn, Context context) {
+        mEcuOrderedList = ecusIn;
+        mContext = context;
+        mEcuOrderedList.sort((ecu, t1) -> t1.getDtcs().size() - ecu.getDtcs().size());
+    }
+
+    @NonNull
+    @Override
+    public RowViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+
+        View v = inflater.inflate(R.layout.row_layout, parent, false);
+
+        return new RowViewHolder(v, true, false, true);
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull RowViewHolder holder, final int position) {
+        final ECU refECU = mEcuOrderedList.get(position);
+        final RowViewHolder finalHolder = holder;
+        final String name = refECU.getName();
+        refECU.setColor(finalHolder);
+        holder.setFields(
+                refECU.getAddress(), name, String.format("%d DTCs", refECU.getDtcs().size()),
+                false);
+        holder.layout.setOnClickListener(
+                view -> {
+                    if (hasSelected()) {
+                        toggleSelect(refECU);
+                        refECU.setColor(finalHolder);
+                    } else {
+                        Intent intent = new Intent(mContext, DTCListActivity.class);
+                        intent.putExtra("name", name);
+                        intent.putParcelableArrayListExtra(
+                                "dtcs", (ArrayList<? extends Parcelable>) refECU.getDtcs());
+                        mContext.startActivity(intent);
+                    }
+                });
+        holder.layout.setOnLongClickListener(
+                view -> {
+                    toggleSelect(refECU);
+                    refECU.setColor(finalHolder);
+                    return true;
+                });
+    }
+
+    @Override
+    public int getItemCount() {
+        return mEcuOrderedList.size();
+    }
+
+    /**
+     * Overrides method getBaseList of SelectableAdapter to allow selection of elements
+     *
+     * @return base list of DTCs
+     */
+    @Override
+    protected List<ECU> getBaseList() {
+        return mEcuOrderedList;
+    }
+}
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/ECUListActivity.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/ECUListActivity.java
new file mode 100644
index 0000000..a2ee70b
--- /dev/null
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/ECUListActivity.java
@@ -0,0 +1,94 @@
+/*
+ * 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.diagnostictools;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Toolbar;
+
+import androidx.recyclerview.widget.DividerItemDecoration;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Displays a list of ECUs */
+public class ECUListActivity extends Activity {
+
+    private RecyclerView mRecyclerView;
+    private ECUAdapter mAdapter;
+    private RecyclerView.LayoutManager mLayoutManager;
+    private Toolbar mToolbar;
+
+    /** Called with the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        View view = getLayoutInflater().inflate(R.layout.diagnostic_tools, null);
+        setContentView(view);
+
+        mRecyclerView = findViewById(R.id.my_recycler_view);
+
+        mRecyclerView.setHasFixedSize(true);
+
+        mLayoutManager = new LinearLayoutManager(this);
+        mRecyclerView.setLayoutManager(mLayoutManager);
+        List<ECU> input = new ArrayList<>();
+        for (int i = 0; i < 100; i++) {
+            input.add(ECU.createSampleECU(i, this));
+        }
+        mAdapter = new ECUAdapter(input, this);
+        mRecyclerView.setAdapter(mAdapter);
+        mRecyclerView.addItemDecoration(
+                new DividerItemDecoration(
+                        mRecyclerView.getContext(), DividerItemDecoration.VERTICAL));
+
+        mToolbar = findViewById(R.id.toolbar);
+        setActionBar(mToolbar);
+        mToolbar.setNavigationIcon(R.drawable.ic_show_chart_black_24dp);
+        mToolbar.setTitle("ECU Overview");
+        final Context mContext = this;
+        mToolbar.setNavigationOnClickListener(
+                view1 -> {
+                    Intent intent = new Intent(mContext, LiveDataActivity.class);
+                    mContext.startActivity(intent);
+                });
+    }
+
+    /**
+     * Handle clicks from the ActionButton. Confirms that the user wants to clear selected DTCs and
+     * then deletes them on confirmation.
+     */
+    public void onClickActionButton(View view) {
+        new AlertDialog.Builder(this)
+                .setTitle("Clear DTCs")
+                .setMessage(
+                        String.format(
+                                "Do you really want to clear %d mDtcs?", mAdapter.numSelected()))
+                .setIcon(android.R.drawable.ic_dialog_alert)
+                .setPositiveButton(
+                        android.R.string.yes, (dialog, whichButton) -> mAdapter.deleteSelected())
+                .setNegativeButton(android.R.string.no, null)
+                .show();
+    }
+}
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/LiveDataActivity.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/LiveDataActivity.java
new file mode 100644
index 0000000..7e7c585
--- /dev/null
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/LiveDataActivity.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.car.diagnostictools;
+
+import android.app.Activity;
+import android.car.Car;
+import android.car.diagnostic.CarDiagnosticEvent;
+import android.car.diagnostic.CarDiagnosticManager;
+import android.car.diagnostic.FloatSensorIndex;
+import android.car.diagnostic.IntegerSensorIndex;
+import android.car.hardware.property.CarPropertyManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.Toast;
+import android.widget.Toolbar;
+
+import androidx.recyclerview.widget.DividerItemDecoration;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.LayoutManager;
+
+import com.google.android.car.diagnostictools.utils.MetadataProcessing;
+import com.google.android.car.diagnostictools.utils.SensorMetadata;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LiveDataActivity extends Activity {
+    private static final String TAG = "LiveDataActivity";
+
+    private Car mCar;
+    private MetadataProcessing mMetadataProcessing;
+    private RecyclerView mRecyclerView;
+    private LayoutManager mLayoutManager;
+    private LiveDataAdapter mAdapter;
+
+    /**
+     * Convert CarDiagnosticEvent into a list of SensorDataWrapper objects to be displayed
+     *
+     * @param event CarDiagnosticEvent with live(freeze) frame data in it.
+     * @param mMetadataProcessing MetadataProcessing object to associate sensor data with
+     * @return List of LiveDataWrappers to be displayed
+     */
+    static List<LiveDataAdapter.SensorDataWrapper> processSensorInfoIntoWrapper(
+            CarDiagnosticEvent event, MetadataProcessing mMetadataProcessing) {
+        List<LiveDataAdapter.SensorDataWrapper> sensorData = new ArrayList<>();
+        for (int i = 0; i <= FloatSensorIndex.LAST_SYSTEM; i++) {
+            Float sensor_value = event.getSystemFloatSensor(i);
+            if (sensor_value != null) {
+                SensorMetadata metadata = mMetadataProcessing.getFloatMetadata(i);
+                if (metadata != null) {
+                    Log.d(TAG, "Float metadata" + metadata.toString());
+                    sensorData.add(metadata.toLiveDataWrapper(sensor_value));
+                } else {
+                    sensorData.add(
+                            new LiveDataAdapter.SensorDataWrapper(
+                                    "Float Sensor " + i, "", sensor_value));
+                }
+            }
+        }
+        for (int i = 0; i <= IntegerSensorIndex.LAST_SYSTEM; i++) {
+            Integer sensor_value = event.getSystemIntegerSensor(i);
+            if (sensor_value != null) {
+                SensorMetadata metadata = mMetadataProcessing.getIntegerMetadata(i);
+                if (metadata != null) {
+                    Log.d(TAG, "Sensor metadata" + metadata.toString());
+                    sensorData.add(metadata.toLiveDataWrapper(sensor_value));
+                } else {
+                    sensorData.add(
+                            new LiveDataAdapter.SensorDataWrapper(
+                                    "Integer Sensor " + i, "", sensor_value));
+                }
+            }
+        }
+        return sensorData;
+    }
+
+    /**
+     * Overloaded version of processSensorInfoIntoWrapper that uses the metadata member variable
+     *
+     * @param event CarDiagnosticEvent with live(freeze) frame data in it.
+     * @return List of LiveDataWrappers to be displayed
+     */
+    private List<LiveDataAdapter.SensorDataWrapper> processSensorInfoIntoWrapper(
+            CarDiagnosticEvent event) {
+        return processSensorInfoIntoWrapper(event, mMetadataProcessing);
+    }
+
+    /** Called with the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        View view = getLayoutInflater().inflate(R.layout.activity_live_data, null);
+        setContentView(view);
+
+        mCar = Car.createCar(this);
+        mMetadataProcessing = MetadataProcessing.getInstance(this);
+
+        CarDiagnosticManager diagnosticManager =
+                (CarDiagnosticManager) mCar.getCarManager(Car.DIAGNOSTIC_SERVICE);
+
+        CarDiagnosticListener listener = new CarDiagnosticListener(diagnosticManager);
+
+        if (diagnosticManager != null && diagnosticManager.isLiveFrameSupported()) {
+            diagnosticManager.registerListener(
+                    listener,
+                    CarDiagnosticManager.FRAME_TYPE_LIVE,
+                    (int) CarPropertyManager.SENSOR_RATE_NORMAL);
+        } else if (diagnosticManager == null) {
+            Toast.makeText(this, "Error reading manager, please reload", Toast.LENGTH_LONG).show();
+        } else if (!diagnosticManager.isLiveFrameSupported()) {
+            Toast.makeText(this, "Live Frame data not supported", Toast.LENGTH_LONG).show();
+        }
+
+        Toolbar toolbar = findViewById(R.id.toolbar);
+        setActionBar(toolbar);
+        toolbar.setNavigationIcon(R.drawable.ic_arrow_back_black_24dp);
+        toolbar.setNavigationOnClickListener(view1 -> finish());
+
+        mRecyclerView = findViewById(R.id.live_data_list);
+
+        mRecyclerView.setHasFixedSize(false);
+
+        mLayoutManager = new LinearLayoutManager(this);
+        mRecyclerView.setLayoutManager(mLayoutManager);
+        mAdapter = new LiveDataAdapter();
+        mRecyclerView.setAdapter(mAdapter);
+        mRecyclerView.addItemDecoration(
+                new DividerItemDecoration(
+                        mRecyclerView.getContext(), DividerItemDecoration.VERTICAL));
+    }
+
+    @Override
+    public void onDestroy() {
+        if (mCar != null && mCar.isConnected()) {
+            mCar.disconnect();
+            mCar = null;
+        }
+        super.onDestroy();
+    }
+
+    /** Listener which updates live frame data when it is available */
+    private class CarDiagnosticListener implements CarDiagnosticManager.OnDiagnosticEventListener {
+
+        private final CarDiagnosticManager mManager;
+
+        CarDiagnosticListener(CarDiagnosticManager manager) {
+            this.mManager = manager;
+        }
+
+        @Override
+        public void onDiagnosticEvent(CarDiagnosticEvent event) {
+            if (mManager.isLiveFrameSupported()) {
+                mAdapter.update(processSensorInfoIntoWrapper(event));
+            }
+        }
+    }
+}
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/LiveDataAdapter.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/LiveDataAdapter.java
new file mode 100644
index 0000000..7127052
--- /dev/null
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/LiveDataAdapter.java
@@ -0,0 +1,93 @@
+/*
+ * 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.diagnostictools;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Adapter which displays live data */
+public class LiveDataAdapter extends RecyclerView.Adapter<RowViewHolder> {
+
+    private List<SensorDataWrapper> mLiveData;
+
+    public LiveDataAdapter(List<SensorDataWrapper> initialData) {
+        mLiveData = initialData;
+    }
+
+    public LiveDataAdapter() {
+        mLiveData = new ArrayList<>();
+    }
+
+    @NonNull
+    @Override
+    public RowViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+
+        View v = inflater.inflate(R.layout.row_layout, parent, false);
+
+        return new RowViewHolder(v, false, false, true);
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull RowViewHolder holder, int position) {
+        SensorDataWrapper wrapper = mLiveData.get(position);
+        holder.setFields(wrapper.mName, "", "" + wrapper.mNumber + " " + wrapper.mUnit, false);
+    }
+
+    @Override
+    public int getItemCount() {
+        return mLiveData.size();
+    }
+
+    /**
+     * Takes in new data to update the RecyclerView with
+     *
+     * @param data New list of LiveDataWrappers to display
+     */
+    public void update(List<SensorDataWrapper> data) {
+        mLiveData.clear();
+        mLiveData.addAll(data);
+        notifyDataSetChanged();
+    }
+
+    /** Wrapper which holds data about a DataFrame */
+    public static class SensorDataWrapper {
+
+        private String mName;
+        private String mUnit;
+        private String mNumber;
+
+        public SensorDataWrapper(String name, String unit, float number) {
+            this.mName = name;
+            this.mUnit = unit;
+            this.mNumber = String.valueOf(number);
+        }
+
+        public SensorDataWrapper(String name, String unit, String number) {
+            this.mName = name;
+            this.mUnit = unit;
+            this.mNumber = number;
+        }
+    }
+}
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/RowViewHolder.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/RowViewHolder.java
new file mode 100644
index 0000000..3e83f06
--- /dev/null
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/RowViewHolder.java
@@ -0,0 +1,78 @@
+/*
+ * 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.diagnostictools;
+
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+/** Generic ViewHolder which is used to represent data in rows. */
+public class RowViewHolder extends RecyclerView.ViewHolder {
+
+    public TextView textHeader;
+    public TextView textDescription;
+    public TextView textValueField;
+    public CheckBox checkBox;
+    public View layout;
+
+    public RowViewHolder(@NonNull View itemView) {
+        super(itemView);
+        layout = itemView;
+        textHeader = itemView.findViewById(R.id.firstLine);
+        textDescription = itemView.findViewById(R.id.secondLine);
+        textValueField = itemView.findViewById(R.id.dtc_number);
+        checkBox = itemView.findViewById(R.id.checkBox);
+    }
+
+    /**
+     * Full constructor which allows selective displaying of description, checkbox, and value
+     * fields.
+     *
+     * @param itemView View to construct on
+     * @param showDescription Display description if true, remove from view (View.GONE) if false
+     * @param showCheckBox Display checkBox if true, remove from view (View.GONE) if false
+     * @param showValue Display value if true, remove from view (View.GONE) if false
+     */
+    public RowViewHolder(
+            @NonNull View itemView,
+            boolean showDescription,
+            boolean showCheckBox,
+            boolean showValue) {
+        this(itemView);
+        checkBox.setVisibility(showCheckBox ? View.VISIBLE : View.GONE);
+        textValueField.setVisibility(showValue ? View.VISIBLE : View.GONE);
+        textDescription.setVisibility(showDescription ? View.VISIBLE : View.GONE);
+    }
+
+    /**
+     * Set values of elements inside the view.
+     *
+     * @param header Header value to display
+     * @param description Description value to display
+     * @param valueField Value to display on the right side
+     * @param chbx Whether or not the checkbox is checked
+     */
+    public void setFields(String header, String description, String valueField, boolean chbx) {
+        textHeader.setText(header);
+        textDescription.setText(description);
+        textValueField.setText(valueField);
+        checkBox.setChecked(chbx);
+    }
+}
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/DTCMetadata.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/DTCMetadata.java
new file mode 100644
index 0000000..8071365
--- /dev/null
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/DTCMetadata.java
@@ -0,0 +1,86 @@
+/*
+ * 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.diagnostictools.utils;
+
+import android.text.Html;
+import android.text.Spanned;
+import android.util.Log;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/** Holds metadata for a DTC. The intended use case is to map this to a DTC code. */
+public class DTCMetadata {
+
+    private static final String TAG = "DTCMetadata";
+    private static final String SHORT_DESCRIPTION_KEY = "short_description";
+    private static final String LONG_DESCRIPTION_KEY = "long_description";
+
+    private String mShortDescription;
+    private String mStringLongDescription;
+    private Spanned mSpannedLongDescription;
+
+    /**
+     * Creates new DTCMeta data object. Both the String and Spanned version of the longDescription
+     * are stored to allow for the object to be parcelable (String is used) and allow only one call
+     * to Html.fromHTML (Spanned is used)
+     *
+     * @param shortDescription Main description of 50 characters or less
+     * @param longDescription Longer description that can be in HTML format to allow for more
+     *     complex formatting.
+     */
+    private DTCMetadata(String shortDescription, String longDescription) {
+        this.mShortDescription = shortDescription;
+        this.mStringLongDescription = longDescription;
+        this.mSpannedLongDescription = Html.fromHtml(longDescription, 0);
+    }
+
+    /**
+     * Build a DTCmeta object from a JSON object. Used by JsonMetadataReader
+     *
+     * @param jsonObject JSONObject that contains both a "short_description" key and a
+     *     "long_description" key
+     * @return New DTCMetadata object if successful or null if not
+     */
+    static DTCMetadata buildFromJson(JSONObject jsonObject) {
+        try {
+            return new DTCMetadata(
+                    jsonObject.getString(SHORT_DESCRIPTION_KEY),
+                    jsonObject.getString(LONG_DESCRIPTION_KEY));
+        } catch (JSONException e) {
+            Log.d(
+                    TAG,
+                    "DTC JSON Object doesn't match expected format: "
+                            + jsonObject.toString()
+                            + " Error: "
+                            + e.toString());
+            return null;
+        }
+    }
+
+    public String getShortDescription() {
+        return mShortDescription;
+    }
+
+    public Spanned getSpannedLongDescription() {
+        return mSpannedLongDescription;
+    }
+
+    public String getStringLongDescription() {
+        return mStringLongDescription;
+    }
+}
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/JsonMetadataReader.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/JsonMetadataReader.java
new file mode 100644
index 0000000..3ce3e66
--- /dev/null
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/JsonMetadataReader.java
@@ -0,0 +1,191 @@
+/*
+ * 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.diagnostictools.utils;
+
+import android.car.diagnostic.FloatSensorIndex;
+import android.car.diagnostic.IntegerSensorIndex;
+import android.util.Log;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.reflect.Field;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Takes in an InputStream of a JSON file and converts it into a mapping from Integer (SensorIndex
+ * IntDef) to a SensorMetadata object
+ *
+ * <p>Two similar methods used are read(Float|Integer)SensorIndexFromJson. These utilize the
+ * (Float|Integer)SensorIndex.class objects to allow the JSON object to utilize @IntDef variable
+ * names.
+ *
+ * <p>Additionally two similar methods are read(DTCs|ECUs)FromJson which take in an input stream and
+ * return a mapping between DTCs/ECUs and their respective metadata (DTCMetadata or String
+ * respectively)
+ */
+class JsonMetadataReader {
+
+    private static final String TAG = "JsonMetadataReader";
+
+    /**
+     * Converts a JSON file with DTC -> DTCMetadata formatting into the corresponding mapping
+     *
+     * @param in InputStream for JSON file
+     * @return Mapping from String to SensorMetadata
+     * @throws IOException Thrown if there is an issue with reading the file from the InputStream
+     * @throws JSONException Thrown if the JSON object is malformed
+     */
+    static Map<String, DTCMetadata> readDTCsFromJson(InputStream in)
+            throws IOException, JSONException {
+        JSONObject metadataMapping = new JSONObject(inputStreamToString(in));
+        Map<String, DTCMetadata> metadata = new HashMap<>();
+        for (String dtc : metadataMapping.keySet()) {
+            try {
+                metadata.put(dtc, DTCMetadata.buildFromJson(metadataMapping.getJSONObject(dtc)));
+            } catch (JSONException e) {
+                Log.d(TAG, "Invalid JSON for DTC: " + dtc);
+            }
+        }
+        return metadata;
+    }
+
+    /**
+     * Converts a JSON file with ECU -> String formatting into the corresponding mapping
+     *
+     * @param in InputStream for JSON file
+     * @return Mapping from String to SensorMetadata
+     * @throws IOException Thrown if there is an issue with reading the file from the InputStream
+     * @throws JSONException Thrown if the JSON object is malformed
+     */
+    static Map<String, String> readECUsFromJson(InputStream in) throws IOException, JSONException {
+        JSONObject metadataMapping = new JSONObject(inputStreamToString(in));
+        Map<String, String> metadata = new HashMap<>();
+        for (String address : metadataMapping.keySet()) {
+            try {
+                metadata.put(address, metadataMapping.getString(address));
+            } catch (JSONException e) {
+                Log.d(TAG, "Invalid JSON for ECU: " + address);
+            }
+        }
+
+        return metadata;
+    }
+
+    /**
+     * Takes an InputStream of JSON and converts it to a mapping from FloatSensorIndex field value
+     * to Sensor Metadata objects
+     *
+     * @param in InputStream of JSON
+     * @return Mapping from FloatSensorIndex field values to SensorMetadata objects
+     * @throws IOException Thrown if there is an issue with reading the file from the InputStream
+     * @throws JSONException Thrown if the JSON object is malformed
+     */
+    static Map<Integer, SensorMetadata> readFloatSensorIndexFromJson(InputStream in)
+            throws IOException, JSONException {
+        return readSensorIndexFromJson(in, FloatSensorIndex.class);
+    }
+
+    /**
+     * Takes an InputStream of JSON and converts it to a mapping from IntegerSensorIndex field value
+     * to Sensor Metadata objects
+     *
+     * @param in InputStream of JSON
+     * @return Mapping from IntegerSensorIndex field values to SensorMetadata objects
+     * @throws IOException Thrown if there is an issue with reading the file from the InputStream
+     * @throws JSONException Thrown if the JSON object is malformed
+     */
+    static Map<Integer, SensorMetadata> readIntegerSensorIndexFromJson(InputStream in)
+            throws IOException, JSONException {
+        return readSensorIndexFromJson(in, IntegerSensorIndex.class);
+    }
+
+    /**
+     * Takes an InputStream and Class to read in as a SensorIndex. The Class is used to connect with
+     * reflections and assert that key names are consistent with the SensorIndex class input
+     *
+     * @param in InputStream of JSON file
+     * @param sensorIndexClass Defines which of the (Float|Integer)SensorIndex classes does the key
+     *     for the output mapping link to
+     * @return Mapping from sensorIndexClass field values to SensorMetadata objects
+     * @throws IOException Thrown if there is an issue with reading the file from the InputStream
+     * @throws JSONException Thrown if the JSON object is malformed
+     */
+    private static Map<Integer, SensorMetadata> readSensorIndexFromJson(
+            InputStream in, Class sensorIndexClass) throws IOException, JSONException {
+        Map<String, SensorMetadata> metadata = JsonMetadataReader.readSensorsFromJson(in);
+        Map<Integer, SensorMetadata> metadataMap = new HashMap<>();
+        // Use Reflection to get all fields of the specified sensorIndexClass
+        Field[] sensorIndexFields = sensorIndexClass.getFields();
+        // For all fields, if the JSON object contains the field then put it into the map
+        for (Field f : sensorIndexFields) {
+            if (metadata.containsKey(f.getName())) {
+                try {
+                    metadataMap.put((Integer) f.get(sensorIndexClass), metadata.get(f.getName()));
+                } catch (IllegalAccessException e) { // Added for safety though should never
+                    // trigger
+                    Log.e(TAG, "Illegal Access Exception throws but should not be thrown");
+                }
+            }
+        }
+        return metadataMap;
+    }
+
+    /**
+     * Helper method that creates an unchecked String to SensorMetadata mapping from an InputStream
+     *
+     * @param in InputStream for JSON file
+     * @return Mapping from String to SensorMetadata
+     * @throws IOException Thrown if there is an issue with reading the file from the InputStream
+     * @throws JSONException Thrown if the JSON object is malformed
+     */
+    private static Map<String, SensorMetadata> readSensorsFromJson(InputStream in)
+            throws IOException, JSONException {
+        JSONObject metadataMapping = new JSONObject(inputStreamToString(in));
+        Map<String, SensorMetadata> metadata = new HashMap<>();
+        for (String sensorIndex : metadataMapping.keySet()) {
+            // Use a static method from SensorMetadata to handle the conversion from
+            // JSON->SensorMetadata
+            metadata.put(
+                    sensorIndex,
+                    SensorMetadata.buildFromJson(metadataMapping.getJSONObject(sensorIndex)));
+        }
+        return metadata;
+    }
+
+    /**
+     * Converts an InputStream into a String
+     *
+     * @param in InputStream
+     * @return InputStream converted to a String
+     * @throws IOException Thrown if there are issues in reading the file
+     */
+    private static String inputStreamToString(InputStream in) throws IOException {
+        StringBuilder builder = new StringBuilder();
+        try (BufferedReader reader =
+                new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
+            reader.lines().forEach(builder::append);
+        }
+        return builder.toString();
+    }
+}
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/MathEval.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/MathEval.java
new file mode 100644
index 0000000..11910df
--- /dev/null
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/MathEval.java
@@ -0,0 +1,201 @@
+/*
+ * 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.diagnostictools.utils;
+
+/**
+ * This class allows for custom formulas to translate input live/freeze frame data into the
+ * appropriate values. Ideally a `conversion` object should be used in the JSON but this allows for
+ * more flexibility if needed.
+ */
+class MathEval {
+
+    /**
+     * This is a sanity check for user generated strings to catch errors once instead of everytime
+     * the data is translated
+     *
+     * @param str Translation string to test
+     * @return True if the string doesn't or won't fail when processing simple inputs
+     */
+    static boolean testTranslation(final String str) {
+        if (str == null || str.length() == 0) {
+            return true;
+        } else if (str.length() > 50) {
+            return false;
+        }
+
+        try {
+            eval(str, (float) 100.0);
+            eval(str, (float) 10.0);
+            eval(str, (float) 1);
+            eval(str, (float) .1);
+            eval(str, (float) 0);
+            eval(str, (float) -100.0);
+            eval(str, (float) -10.0);
+            eval(str, (float) -1);
+            eval(str, (float) -.1);
+        } catch (Exception e) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Uses a translation string and applies the formula to a variable From
+     * https://stackoverflow.com/a/26227947 with modifications. String must only use +,-,*,/,^,(,)
+     * or "sqrt", "sin", "cos", "tan" (as a function ie sqrt(4)) and the variable x
+     *
+     * @param translationString Translation string which uses x as the variable
+     * @param variableIn Float that the translation is operating on
+     * @return New Float that has gone through operations defined in "translationString". If
+     *     translationString is non-operable then the variableIn will be returned
+     * @throws TranslationTooLongException Thrown if the translation string is longer than 50 chars
+     *     to prevent long execution times
+     */
+    static double eval(final String translationString, Float variableIn)
+            throws TranslationTooLongException {
+
+        if (translationString == null || translationString.length() == 0) {
+            return variableIn;
+        } else if (translationString.length() > 50) {
+            throw new TranslationTooLongException(
+                    "Translation function " + translationString + " is too long");
+        }
+
+        return new Object() {
+            int mPos = -1, mCh;
+
+            void nextChar() {
+                mCh = (++mPos < translationString.length()) ? translationString.charAt(mPos) : -1;
+            }
+
+            boolean eat(int charToEat) {
+                while (mCh == ' ') {
+                    nextChar();
+                }
+                if (mCh == charToEat) {
+                    nextChar();
+                    return true;
+                }
+                return false;
+            }
+
+            double parse() {
+                nextChar();
+                double x = parseExpression();
+                if (mPos < translationString.length()) {
+                    throw new RuntimeException("Unexpected: " + (char) mCh);
+                }
+                return x;
+            }
+
+            // Grammar:
+            // expression = term | expression `+` term | expression `-` term
+            // term = factor | term `*` factor | term `/` factor
+            // factor = `+` factor | `-` factor | `(` expression `)`
+            //        | number | functionName factor | factor `^` factor
+
+            double parseExpression() {
+                double x = parseTerm();
+                for (;; ) {
+                    if (eat('+')) {
+                        x += parseTerm(); // addition
+                    } else if (eat('-')) {
+                        x -= parseTerm(); // subtraction
+                    } else {
+                        return x;
+                    }
+                }
+            }
+
+            double parseTerm() {
+                double x = parseFactor();
+                for (;; ) {
+                    if (eat('*')) {
+                        x *= parseFactor(); // multiplication
+                    } else if (eat('/')) {
+                        x /= parseFactor(); // division
+                    } else {
+                        return x;
+                    }
+                }
+            }
+
+            double parseFactor() {
+                if (eat('+')) {
+                    return parseFactor(); // unary plus
+                }
+                if (eat('-')) {
+                    return -parseFactor(); // unary minus
+                }
+
+                double x;
+                int startPos = this.mPos;
+                if (eat('(')) { // parentheses
+                    x = parseExpression();
+                    eat(')');
+                } else if ((mCh >= '0' && mCh <= '9') || mCh == '.') { // numbers
+                    while ((mCh >= '0' && mCh <= '9') || mCh == '.') {
+                        nextChar();
+                    }
+                    x = Double.parseDouble(translationString.substring(startPos, this.mPos));
+                } else if (mCh == 'x') {
+                    x = variableIn;
+                    nextChar();
+                    // System.out.println(x);
+                } else if (mCh >= 'a' && mCh <= 'z') { // functions
+                    while (mCh >= 'a' && mCh <= 'z') {
+                        nextChar();
+                    }
+                    String func = translationString.substring(startPos, this.mPos);
+                    x = parseFactor();
+                    switch (func) {
+                        case "sqrt":
+                            x = Math.sqrt(x);
+                            break;
+                        case "sin":
+                            x = Math.sin(Math.toRadians(x));
+                            break;
+                        case "cos":
+                            x = Math.cos(Math.toRadians(x));
+                            break;
+                        case "tan":
+                            x = Math.tan(Math.toRadians(x));
+                            break;
+                        default:
+                            throw new RuntimeException("Unknown function: " + func);
+                    }
+                } else {
+                    throw new RuntimeException("Unexpected: " + (char) mCh);
+                }
+
+                if (eat('^')) {
+                    x = Math.pow(x, parseFactor()); // exponentiation
+                }
+
+                return x;
+            }
+        }.parse();
+    }
+
+    /** Exception thrown if the translation string is too long */
+    static class TranslationTooLongException extends Exception {
+
+        TranslationTooLongException(String errorMsg) {
+            super(errorMsg);
+        }
+    }
+}
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/MetadataProcessing.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/MetadataProcessing.java
new file mode 100644
index 0000000..9f36002
--- /dev/null
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/MetadataProcessing.java
@@ -0,0 +1,151 @@
+/*
+ * 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.diagnostictools.utils;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.google.android.car.diagnostictools.R;
+
+import org.json.JSONException;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+
+/** Singleton class that contains all available metadata information */
+public class MetadataProcessing {
+
+    private static final String TAG = "MetadataProcessing";
+    private static MetadataProcessing sInstance = null;
+
+    private Map<Integer, SensorMetadata> mFloatMetadata = new HashMap<>();
+    private Map<Integer, SensorMetadata> mIntegerMetadata = new HashMap<>();
+    private Map<String, DTCMetadata> mDTCMetadataMap = new HashMap<>();
+    private Map<String, String> mECUMetadataMap = new HashMap<>();
+
+    /**
+     * Creates a MetadataProcessing object using a context to access files in res/raw
+     *
+     * @param context Any context object. Used to access files in res/raw
+     */
+    private MetadataProcessing(Context context) {
+        // DTC Metadata
+        try {
+            mDTCMetadataMap =
+                    JsonMetadataReader.readDTCsFromJson(
+                            context.getResources().openRawResource(R.raw.system_dtcs));
+        } catch (IOException | JSONException e) {
+            Log.d(
+                    TAG,
+                    "Error reading in JSON Metadata for system DTCs. More info: " + e.toString());
+        }
+        try {
+            mDTCMetadataMap.putAll(
+                    JsonMetadataReader.readDTCsFromJson(
+                            context.getResources().openRawResource(R.raw.vendor_dtcs)));
+        } catch (IOException | JSONException e) {
+            Log.d(
+                    TAG,
+                    "Error reading in JSON Metadata for vendor DTCs. More info: " + e.toString());
+        }
+
+        // Float Metadata
+        try {
+            mFloatMetadata =
+                    JsonMetadataReader.readFloatSensorIndexFromJson(
+                            context.getResources().openRawResource(R.raw.system_float_sensors));
+        } catch (IOException | JSONException e) {
+            Log.e(
+                    TAG,
+                    "Error reading in JSON Metadata for system float sensors. More info: "
+                            + e.toString());
+        }
+        try {
+            mFloatMetadata.putAll(
+                    JsonMetadataReader.readFloatSensorIndexFromJson(
+                            context.getResources().openRawResource(R.raw.vendor_float_sensors)));
+        } catch (IOException | JSONException e) {
+            Log.e(
+                    TAG,
+                    "Error reading in JSON Metadata for vendor float sensors. More info: "
+                            + e.toString());
+        }
+
+        // Integer Metadata
+        try {
+            mIntegerMetadata =
+                    JsonMetadataReader.readIntegerSensorIndexFromJson(
+                            context.getResources().openRawResource(R.raw.system_integer_sensors));
+        } catch (IOException | JSONException e) {
+            Log.e(
+                    TAG,
+                    "Error reading in JSON Metadata for system integer sensors. More info: "
+                            + e.toString());
+        }
+        try {
+            mIntegerMetadata.putAll(
+                    JsonMetadataReader.readIntegerSensorIndexFromJson(
+                            context.getResources().openRawResource(R.raw.vendor_integer_sensors)));
+        } catch (IOException | JSONException e) {
+            Log.e(
+                    TAG,
+                    "Error reading in JSON Metadata for vendor integer sensors. More info: "
+                            + e.toString());
+        }
+
+        // ECU Metadata
+        try {
+            mECUMetadataMap =
+                    JsonMetadataReader.readECUsFromJson(
+                            context.getResources().openRawResource(R.raw.vendor_ecus));
+        } catch (IOException | JSONException e) {
+            Log.e(TAG, "Error reading in JSON Metadata for ECUs. More info: " + e.toString());
+        }
+    }
+
+    /**
+     * Maintains a singleton object and allows access to it. If no singleton object is created the
+     * method will create one based on passed in context
+     *
+     * @param context Any context that allows access to res/raw
+     * @return Singleton MetadataProcessing object
+     */
+    public static synchronized MetadataProcessing getInstance(Context context) {
+        if (sInstance == null) {
+            sInstance = new MetadataProcessing(context);
+        }
+        return sInstance;
+    }
+
+    public SensorMetadata getFloatMetadata(Integer floatSensorIndex) {
+        return mFloatMetadata.getOrDefault(floatSensorIndex, null);
+    }
+
+    public SensorMetadata getIntegerMetadata(Integer integerSensorIndex) {
+        return mIntegerMetadata.getOrDefault(integerSensorIndex, null);
+    }
+
+    public DTCMetadata getDTCMetadata(String dtcCode) {
+        return mDTCMetadataMap.getOrDefault(dtcCode, null);
+    }
+
+    public String getECUMetadata(String ecuAddress) {
+        return mECUMetadataMap.getOrDefault(ecuAddress, null);
+    }
+}
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/SelectableAdapter.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/SelectableAdapter.java
new file mode 100644
index 0000000..77deca9
--- /dev/null
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/SelectableAdapter.java
@@ -0,0 +1,110 @@
+/*
+ * 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.diagnostictools.utils;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Used to enable a RecyclerView Adapter to select and delete row elements. Designed to be self
+ * contained so that implementing the abstract function will enable selecting behavior.
+ *
+ * @param <M> Base row model used. For example, the `DTC` class is used for the DTCAdapter
+ * @param <VH> Base view holder used. Included so that SelectableAdapter can use
+ *     notifyDataSetChanged
+ */
+public abstract class SelectableAdapter<
+                M extends SelectableRowModel, VH extends RecyclerView.ViewHolder>
+        extends RecyclerView.Adapter<VH> {
+
+    private List<M> mSelected = new ArrayList<>();
+
+    /**
+     * Toggle if an element is selected or not.
+     *
+     * @param model The model object that is related to the row selected
+     */
+    public void toggleSelect(M model) {
+        if (model.isSelected()) {
+            model.setSelected(false);
+            mSelected.remove(model);
+        } else {
+            model.setSelected(true);
+            mSelected.add(model);
+        }
+    }
+
+    /**
+     * Returns the number of elements selected. Uses the model's numSelected method to allow for one
+     * model object to represent multiple element (one ECU holds multiple DTCs). If no elements are
+     * explicitly selected, it is assumed that all elements are selected.
+     *
+     * @return number of elements selected
+     */
+    public int numSelected() {
+        int count = 0;
+        for (M model : mSelected) {
+            count += model.numSelected();
+        }
+        if (count == 0) {
+            for (M model : getBaseList()) {
+                count += model.numSelected();
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Deletes all selected element or all elements if no elements are selected. Additionally, calls
+     * the delete methods for all related models.
+     */
+    public void deleteSelected() {
+        if (mSelected.size() == 0) {
+            for (M model : getBaseList()) {
+                model.delete();
+            }
+            getBaseList().clear();
+        } else {
+            for (M model : mSelected) {
+                model.delete();
+            }
+            getBaseList().removeAll(mSelected);
+            mSelected.clear();
+        }
+        notifyDataSetChanged();
+    }
+
+    /**
+     * If there are any models explicitly selected. Does not take into account there are any
+     * elements in that model (an ECU with 0 DTCs).
+     *
+     * @return if there are any models selected
+     */
+    public boolean hasSelected() {
+        return mSelected.size() > 0;
+    }
+
+    /**
+     * Gets base list that the adapter is built off of. This must be one list which the adapter uses
+     * for both order and elements.
+     *
+     * @return base list that adapter is built off of
+     */
+    protected abstract List<M> getBaseList();
+}
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/SelectableRowModel.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/SelectableRowModel.java
new file mode 100644
index 0000000..e2675bf
--- /dev/null
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/SelectableRowModel.java
@@ -0,0 +1,65 @@
+/*
+ * 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.diagnostictools.utils;
+
+import android.graphics.Color;
+
+import com.google.android.car.diagnostictools.RowViewHolder;
+
+/**
+ * Data model class which ECUs and DTCs extend. Allows those classes to be connected with a
+ * SelectableAdapter to enable a RecyclerView with elements getting selected
+ */
+public abstract class SelectableRowModel {
+
+    /** If model is selected */
+    private boolean mIsSelected;
+
+    boolean isSelected() {
+        return mIsSelected;
+    }
+
+    void setSelected(boolean selected) {
+        mIsSelected = selected;
+    }
+
+    /**
+     * Takes in a RowViewHolder object and sets its layout background to its appropriate color based
+     * on if it is selected or not. Uses hardcoded values for the selected and default backgrounds.
+     *
+     * @param holder RowViewHolder object associated with the model object
+     */
+    public void setColor(RowViewHolder holder) {
+        int color = mIsSelected ? Color.GRAY : Color.parseColor("#303030");
+        holder.layout.setBackgroundColor(color);
+    }
+
+    /**
+     * Get the number of elements selected when this model is selected. If the object has children
+     * which are also selected as a result of this select, then those should be counted in that
+     * number.
+     *
+     * @return number of elements selected
+     */
+    public abstract int numSelected();
+
+    /**
+     * Delete this model and all of its children. This allows the model to run special functions to
+     * delete itself in any other representation (DTCs can be deleted from the VHAL).
+     */
+    public abstract void delete();
+}
diff --git a/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/SensorMetadata.java b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/SensorMetadata.java
new file mode 100644
index 0000000..91425d1
--- /dev/null
+++ b/tests/DiagnosticTools/src/com/google/android/car/diagnostictools/utils/SensorMetadata.java
@@ -0,0 +1,295 @@
+/*
+ * 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.diagnostictools.utils;
+
+import android.util.Log;
+
+import com.google.android.car.diagnostictools.LiveDataAdapter;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Stores metadata about a sensor and provides methods to better understand the sensor data.
+ * Provides support for arbitrary translation, scaling (conversion) following the format [Scaled
+ * Data Value] = [Offset] + [Scale] x [Raw Decimal Data Value], and mapping from integer to String.
+ */
+public class SensorMetadata {
+
+    private static final String TRANSLATION_KEY = "translation";
+    private static final String NAME_KEY = "name";
+    private static final String UNITS_KEY = "units";
+    private static final String CONVERSION_KEY = "conversion";
+    private static final String MAPPING_KEY = "mapping";
+    private static final String TAG = "SensorMetadata";
+
+    private String mTranslationString;
+    private float mScale;
+    private float mOffset;
+    private String mName;
+    private String mUnits;
+    private Map<Integer, String> mMapping;
+    private boolean mHasConversion;
+    private boolean mHasMapping;
+
+    /**
+     * Takes in arbitrary translation string that should have x in it as a variable, sensor name,
+     * and the sensor data units. For more information view MathEval.eval.
+     *
+     * @param translationString translation string with a 50 character limit. More information on
+     *     usage in MathEval.eval.
+     * @param name Name of sensor.
+     * @param units Units of the sensor's data.
+     */
+    private SensorMetadata(String translationString, String name, String units) {
+        if (MathEval.testTranslation(translationString)) {
+            this.mTranslationString = translationString;
+        } else {
+            Log.e(
+                    "ServiceCenterTools",
+                    String.format(
+                            "Invalid translation string %s for sensor %s because tests failed",
+                            translationString, name));
+            this.mTranslationString = "";
+        }
+        this.mName = name;
+        this.mUnits = units;
+        this.mHasConversion = false;
+        this.mHasMapping = false;
+    }
+
+    /**
+     * Takes in float scale and offset values, sensor name, and the sensor data units. Scaling and
+     * mOffset are used in the following format: [Scaled Data Value] = [Offset] + [Scale] x [Raw
+     * Decimal Data Value].
+     *
+     * @param scale Value to mScale sensor data by.
+     * @param offset Value to shift sensor data by.
+     * @param name Name of sensor.
+     * @param units Units of the sensor's data.
+     */
+    private SensorMetadata(float scale, float offset, String name, String units) {
+        this.mScale = scale;
+        this.mOffset = offset;
+        this.mName = name;
+        this.mUnits = units;
+        this.mHasConversion = true;
+        this.mHasMapping = false;
+    }
+
+    /**
+     * Takes in a Integer -> String mapping and sensor mName.
+     *
+     * @param mapping Mapping between Integer sensor values to their String values
+     * @param name Name of sensor.
+     */
+    private SensorMetadata(Map<Integer, String> mapping, String name) {
+        this.mMapping = mapping;
+        this.mName = name;
+        this.mUnits = "";
+        this.mHasMapping = true;
+        this.mHasConversion = false;
+    }
+
+    /**
+     * Takes in json object which represents the metadata for a single sensor and converts it to a
+     * SensorMetadata object. Supports mappings, structured conversions (mScale and mOffset), and
+     * arbitrary translations. Mappings and conversions are preferred and translation read in if
+     * neither are present.
+     *
+     * @param json JSON object for metadata
+     * @return returns a new SensorMeta data object with the data from the JSON object
+     */
+    static SensorMetadata buildFromJson(JSONObject json) {
+        String name = readStringFromJSON(NAME_KEY, json);
+        String units = readStringFromJSON(UNITS_KEY, json);
+
+        if (json.has(CONVERSION_KEY)) {
+            try {
+                JSONObject conversionObject = json.getJSONObject(CONVERSION_KEY);
+                float scale = readFloatFromJSON("scale", conversionObject);
+                float offset = readFloatFromJSON("offset", conversionObject);
+
+                return new SensorMetadata(scale, offset, name, units);
+            } catch (JSONException e) {
+                Log.d(TAG, "buildFromJson: Error reading conversion for " + name + ": " + e);
+            }
+        } else if (json.has(MAPPING_KEY)) {
+            try {
+                Map<Integer, String> mapping = readMappingFromJSON(MAPPING_KEY, json);
+                return new SensorMetadata(mapping, name);
+            } catch (JSONException e) {
+                Log.d(TAG, "buildFromJson: Error reading mapping: " + e);
+            }
+        }
+        String translationString = readStringFromJSON(TRANSLATION_KEY, json);
+
+        return new SensorMetadata(translationString, name, units);
+    }
+
+    /**
+     * Helper function that reads a string at a certain key from a JSONObject. Function wraps the
+     * JSON functions with appropriate exception handling.
+     *
+     * @param key key at which the desired string value is located
+     * @param json JSONObject that has the string value at the key
+     * @return value at key or null if error or not found
+     */
+    private static String readStringFromJSON(String key, JSONObject json) {
+        try {
+            if (json.has(key)) {
+                return json.getString(key);
+            }
+        } catch (JSONException e) {
+            Log.e(TAG, "Error reading " + key + " for String SensorMetadata");
+        }
+        return "";
+    }
+
+    /**
+     * Helper function that reads a float at a certain key from a JSONObject. Function wraps the
+     * JSON functions with appropriate exception handling.
+     *
+     * @param key key at which the desired float value is located
+     * @param json JSONObject that has the float value at the key
+     * @return value at key or null if error or not found
+     * @throws JSONException Throws JSONException if there is any
+     */
+    private static float readFloatFromJSON(String key, JSONObject json) throws JSONException {
+        try {
+            if (json.has(key)) {
+                return (float) json.getDouble(key);
+            } else {
+                Log.e(TAG, "No tag for " + key + " is found");
+                throw new JSONException(String.format("%s missing from object", key));
+            }
+        } catch (JSONException e) {
+            Log.e(TAG, "Error reading " + key + " for float SensorMetadata");
+            throw e;
+        }
+    }
+
+    /**
+     * Helper function that reads a mapping at a certain key from a JSONObject. Function wraps the
+     * JSON functions with appropriate exception handling.
+     *
+     * @param key key at which the desired float value is located
+     * @param json JSONObject that has the float value at the key
+     * @return value at key or null if error or not found
+     * @throws JSONException Throws JSONException if there is any
+     */
+    private static Map<Integer, String> readMappingFromJSON(String key, JSONObject json)
+            throws JSONException {
+        try {
+            if (json.has(key)) {
+                json = json.getJSONObject(key);
+                Map<Integer, String> map = new HashMap<>();
+                Iterator<String> keys = json.keys();
+
+                while (keys.hasNext()) {
+                    String integer = keys.next();
+                    if (json.get(integer) instanceof String && isInteger(integer)) {
+                        map.put(Integer.parseInt(integer), json.getString(integer));
+                    }
+                }
+                return map;
+            } else {
+                Log.e(TAG, "No tag for " + key + " is found");
+                throw new JSONException(String.format("%s missing from object", key));
+            }
+        } catch (JSONException e) {
+            Log.e(TAG, "Error reading " + key + " for mapping SensorMetadata");
+            throw e;
+        }
+    }
+
+    /**
+     * Helper function to quickly check if a String can be converted to an int. From
+     * https://stackoverflow.com/a/237204
+     *
+     * @param str String to check.
+     * @return true if String can be converted to an int, false if not.
+     */
+    private static boolean isInteger(String str) {
+        if (str == null) {
+            return false;
+        }
+        int length = str.length();
+        if (length == 0) {
+            return false;
+        }
+        int i = 0;
+        if (str.charAt(0) == '-') {
+            if (length == 1) {
+                return false;
+            }
+            i = 1;
+        }
+        for (; i < length; i++) {
+            char c = str.charAt(i);
+            if (c < '0' || c > '9') {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Uses appropriate translation method (mapping, conversion, translation string) to convert
+     * float sensor data into true value
+     *
+     * @param data Float of data to translate
+     * @return Processed data
+     */
+    private String translateData(Float data) {
+        if (mHasConversion) {
+            return String.valueOf(data * mScale + mOffset);
+        } else if (mHasMapping) {
+            return mMapping.getOrDefault(Math.round(data), "No mapping available");
+        }
+        try {
+            return String.valueOf((float) MathEval.eval(mTranslationString, data));
+        } catch (MathEval.TranslationTooLongException e) {
+            Log.e("ServiceCenterTools", "Translation: " + mTranslationString + " too long");
+            return String.valueOf(data);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "Metadata for "
+                + mName
+                + " with units: "
+                + mUnits
+                + " and translation: "
+                + mTranslationString;
+    }
+
+    /**
+     * Translates and wraps data in a SensorDataWrapper object to allow for it to be displayed
+     *
+     * @param data Sensor data to translate and wrapp
+     * @return SensorDataWrapper that can be displayed in the LiveDataAdapter
+     */
+    public LiveDataAdapter.SensorDataWrapper toLiveDataWrapper(float data) {
+        return new LiveDataAdapter.SensorDataWrapper(mName, mUnits, this.translateData(data));
+    }
+}
diff --git a/tests/DiagnosticTools/tests/Android.mk b/tests/DiagnosticTools/tests/Android.mk
new file mode 100644
index 0000000..8c21035
--- /dev/null
+++ b/tests/DiagnosticTools/tests/Android.mk
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
+
+LOCAL_STATIC_JAVA_LIBRARIES := junit
+
+LOCAL_PACKAGE_NAME := DiagnosticToolsTests
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_INSTRUMENTATION_FOR := DiagnosticTools
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/tests/DiagnosticTools/tests/AndroidManifest.xml b/tests/DiagnosticTools/tests/AndroidManifest.xml
new file mode 100644
index 0000000..ad451f4
--- /dev/null
+++ b/tests/DiagnosticTools/tests/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
+      package="com.google.android.car.diagnostictools.tests">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+  <instrumentation android:name="android.test.InstrumentationTestRunner"
+      android:targetPackage="com.example.android.diagnostictools"
+      android:label="DiagnosticTools sample tests">
+  </instrumentation>  
+  
+</manifest>
diff --git a/tests/DiagnosticTools/tests/build.properties b/tests/DiagnosticTools/tests/build.properties
new file mode 100644
index 0000000..e0c39de
--- /dev/null
+++ b/tests/DiagnosticTools/tests/build.properties
@@ -0,0 +1 @@
+tested.project.dir=..
diff --git a/tests/DiagnosticTools/tests/src/com/google/android/car/diagnostictools/DiagnosticToolsTest.java b/tests/DiagnosticTools/tests/src/com/google/android/car/diagnostictools/DiagnosticToolsTest.java
new file mode 100644
index 0000000..ca26a8f
--- /dev/null
+++ b/tests/DiagnosticTools/tests/src/com/google/android/car/diagnostictools/DiagnosticToolsTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.diagnostictools;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+ * Make sure that the main launcher activity opens up properly, which will be
+ * verified by {@link #testActivityTestCaseSetUpProperly}.
+ */
+public class DiagnosticToolsTest extends ActivityInstrumentationTestCase2<ECUListActivity> {
+
+    /**
+     * Creates an {@link ActivityInstrumentationTestCase2} for the {@link ECUListActivity} activity.
+     */
+    public DiagnosticToolsTest() {
+        super(ECUListActivity.class);
+    }
+
+    /**
+     * Verifies that the activity under test can be launched.
+     */
+    public void testActivityTestCaseSetUpProperly() {
+        assertNotNull("activity should be launched successfully", getActivity());
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/Android.mk b/tests/EmbeddedKitchenSinkApp/Android.mk
index f00a14b..f9526ce 100644
--- a/tests/EmbeddedKitchenSinkApp/Android.mk
+++ b/tests/EmbeddedKitchenSinkApp/Android.mk
@@ -41,17 +41,19 @@
 LOCAL_DEX_PREOPT := false
 
 LOCAL_STATIC_ANDROID_LIBRARIES += \
-    car-service-lib-for-test \
-    androidx.car_car-cluster
+    car-service-test-static-lib \
+    com.google.android.material_material \
+    androidx.appcompat_appcompat \
+    car-ui-lib
 
 LOCAL_STATIC_JAVA_LIBRARIES += \
     android.hidl.base-V1.0-java \
     android.hardware.automotive.vehicle-V2.0-java \
-    vehicle-hal-support-lib \
+    vehicle-hal-support-lib-for-test \
     com.android.car.keventreader-client \
     guava \
-    kitchensink-gson \
-    android.car.cluster.navigation
+    android.car.cluster.navigation \
+    car-experimental-api-static-lib
 
 LOCAL_JAVA_LIBRARIES += android.car
 
@@ -61,9 +63,6 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
-    kitchensink-gson:libs/gson-2.1.jar
-
 include $(BUILD_MULTI_PREBUILT)
 
 include $(CLEAR_VARS)
diff --git a/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml b/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
index 5612807..ec480c4 100644
--- a/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
+++ b/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
@@ -15,64 +15,118 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.google.android.car.kitchensink"
-        android:sharedUserId="android.uid.system">
-    <uses-sdk
-        android:minSdkVersion="24"
-        android:targetSdkVersion='25'/>
-    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+        android:sharedUserId="com.google.android.car.uid.kitchensink"
+        package="com.google.android.car.kitchensink">
+    <uses-permission android:name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/>
+    <uses-permission android:name="android.car.permission.CAR_CAMERA"/>
+    <uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_SETTINGS"/>
+    <uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"/>
+    <uses-permission android:name="android.car.permission.CAR_DIAGNOSTICS"/>
+    <uses-permission android:name="android.car.permission.CAR_DISPLAY_IN_CLUSTER"/>
+    <!-- use for CarServiceTest -->
+    <uses-permission android:name="android.car.permission.CAR_DRIVING_STATE"/>
+    <uses-permission android:name="android.car.permission.CAR_ENERGY"/>
+    <!-- use for AndroidCarApiTest -->
+    <uses-permission android:name="android.car.permission.CAR_INFO"/>
+    <!-- use for AndroidCarApiTest -->
+    <uses-permission android:name="android.car.permission.CAR_PROJECTION"/>
+    <uses-permission android:name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"/>
+    <uses-permission android:name="android.car.permission.CAR_MILEAGE"/>
+    <uses-permission android:name="android.car.permission.CAR_MOCK_VEHICLE_HAL"/>
+    <uses-permission android:name="android.car.permission.CAR_NAVIGATION_MANAGER"/>
+    <!-- use for CarServiceTest -->
+    <uses-permission android:name="android.car.permission.CAR_EXTERIOR_ENVIRONMENT"/>
+    <uses-permission android:name="android.car.permission.CAR_POWER"/>
+    <!-- use for CarServiceTest -->
+    <uses-permission android:name="android.car.permission.CAR_POWERTRAIN"/>
+    <uses-permission android:name="android.car.permission.CAR_SPEED"/>
+     <!-- use for CarServiceTest -->
+    <uses-permission android:name="android.car.permission.CAR_TEST_SERVICE"/>
+    <!-- use for CarServiceTest -->
+    <uses-permission android:name="android.car.permission.CAR_VENDOR_EXTENSION"/>
+    <!-- use for CarServiceTest -->
+    <uses-permission android:name="android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION"/>
+    <uses-permission android:name="android.car.permission.CONTROL_CAR_CLIMATE"/>
+    <uses-permission android:name="android.car.permission.READ_CAR_STEERING"/>
+    <uses-permission android:name="android.car.permission.STORAGE_MONITORING"/>
+    <uses-permission android:name="android.car.permission.CAR_DYNAMICS_STATE"/>
+    <!-- use for CarServiceTest -->
+    <uses-permission android:name="android.car.permission.VMS_PUBLISHER"/>
+    <!-- use for CarServiceTest -->
+    <uses-permission android:name="android.car.permission.VMS_SUBSCRIBER"/>
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
-    <uses-permission android:name="android.car.permission.CAR_SPEED" />
-    <uses-permission android:name="android.car.permission.CAR_MILEAGE" />
-    <uses-permission android:name="android.car.permission.CAR_ENERGY" />
-    <uses-permission android:name="android.car.permission.CONTROL_CAR_CLIMATE" />
-    <uses-permission android:name="android.car.permission.CAR_MOCK_VEHICLE_HAL" />
-    <uses-permission android:name="android.car.permission.CAR_CAMERA" />
-    <uses-permission android:name="android.car.permission.CAR_NAVIGATION_MANAGER"/>
-    <uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"/>
-    <uses-permission android:name="android.car.permission.VEHICLE_DYNAMICS_STATE"/>
-    <uses-permission android:name="android.car.permission.CAR_DISPLAY_IN_CLUSTER"/>
-    <uses-permission android:name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"/>
-    <uses-permission android:name="android.car.permission.STORAGE_MONITORING" />
-    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
-    <uses-permission android:name="android.permission.MANAGE_USB" />
-    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
-    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
-    <uses-permission android:name="android.permission.SEND_SMS" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+    <uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE"/>
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
+    <uses-permission android:name="android.permission.ACTIVITY_EMBEDDING"/>
+    <uses-permission android:name="android.permission.BLUETOOTH"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED"/>
+    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
+    <uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
+    <uses-permission android:name="android.permission.INJECT_EVENTS"/>
+    <!-- use for CarServiceUnitTest and CarServiceTest -->
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+    <!-- use for CarServiceUnitTest -->
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+    <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
+    <uses-permission android:name="android.permission.LOCATION_HARDWARE"/>
+    <uses-permission android:name="android.permission.MANAGE_USB"/>
+    <uses-permission android:name="android.permission.MANAGE_USERS"/>
+    <!-- use for CarServiceTest -->
+    <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>
+    <uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING"/>
+    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
+    <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
+    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE"/>
+    <uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG"/>
+    <uses-permission android:name="android.permission.PROVIDE_TRUST_AGENT"/>
+    <!-- Allow query of any normal app on the device in R+ -->
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+    <uses-permission android:name="android.permission.READ_LOGS"/>
     <uses-permission android:name="android.permission.READ_SMS"/>
-    <uses-permission android:name="android.permission.BLUETOOTH" />
-    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
-    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
-    <uses-permission android:name="android.permission.INJECT_EVENTS" />
-    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+    <uses-permission android:name="android.permission.REAL_GET_TASKS"/>
+    <uses-permission android:name="android.permission.REBOOT"/>
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
+    <uses-permission android:name="android.permission.SEND_SMS"/>
+    <!-- use for CarServiceTest -->
+    <uses-permission android:name="android.permission.MONITOR_INPUT"/>
+    <uses-permission android:name="android.permission.SET_ACTIVITY_WATCHER"/>
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
+    <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
+    <!-- use for vendor properties -->
+    <uses-permission android:name="android.car.permission.CAR_VENDOR_EXTENSION" />
+    <uses-permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_SEAT" />
+    <uses-permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_INFO" />
+    <uses-permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_INFO" />
+
+    <uses-permission android:name="android.car.permission.CONTROL_CAR_FEATURES"/>
 
     <application android:label="@string/app_title"
         android:icon="@drawable/ic_launcher">
-        <uses-library android:name="android.test.runner" />
-
-
+        <uses-library android:name="android.test.runner"/>
         <!-- This is for embedded mode. -->
         <activity android:name=".KitchenSinkActivity"
             android:theme="@style/KitchenSinkActivityTheme"
             android:label="@string/app_title"
             android:launchMode="singleTask">
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
 
         <meta-data
             android:name="android.car.application"
-            android:resource="@xml/automotive_app_desc" />
+            android:resource="@xml/automotive_app_desc"/>
 
         <activity android:name=".orientation.LandscapeActivity"
                   android:label="@string/landscpae_activity"
                   android:screenOrientation="landscape">
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
+                <action android:name="android.intent.action.MAIN"/>
             </intent-filter>
         </activity>
 
@@ -80,7 +134,7 @@
             android:label="@string/portrait_activity"
             android:screenOrientation="portrait">
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
+                <action android:name="android.intent.action.MAIN"/>
             </intent-filter>
         </activity>
 
@@ -97,24 +151,17 @@
 
         <activity android:name=".activityview.ActivityViewTestFragment"/>
 
-        <!-- temporary solution until b/68882625 is fixed. -->
-        <receiver android:name=".touchsound.DisableTouchSoundOnBoot" android:exported="true">
-            <intent-filter>
-                <action android:name="android.intent.action.BOOT_COMPLETED"/>
-            </intent-filter>
-        </receiver>
-
         <service android:name=".vendorservice.LogLifecycleService"
                  android:exported="false" android:directBootAware="true">
         </service>
 
-        <service android:name=".UserNoiticeDemoUiService" android:directBootAware="true" />
+        <service android:name=".UserNoiticeDemoUiService" android:directBootAware="true"/>
 
         <!-- Content provider for images -->
         <provider android:name=".cluster.ClusterContentProvider"
                   android:authorities="com.google.android.car.kitchensink.cluster.clustercontentprovider"
                   android:grantUriPermissions="true"
-                  android:exported="true" />
+                  android:exported="true"/>
 
         <activity android:name=".AlwaysCrashingActivity"
                   android:label="@string/always_crashing_activity">
@@ -139,3 +186,4 @@
 
     </application>
 </manifest>
+
diff --git a/tests/EmbeddedKitchenSinkApp/libs/gson-2.1-sources.jar b/tests/EmbeddedKitchenSinkApp/libs/gson-2.1-sources.jar
deleted file mode 100644
index 09396a0..0000000
--- a/tests/EmbeddedKitchenSinkApp/libs/gson-2.1-sources.jar
+++ /dev/null
Binary files differ
diff --git a/tests/EmbeddedKitchenSinkApp/libs/gson-2.1.jar b/tests/EmbeddedKitchenSinkApp/libs/gson-2.1.jar
deleted file mode 100644
index 83c5c99..0000000
--- a/tests/EmbeddedKitchenSinkApp/libs/gson-2.1.jar
+++ /dev/null
Binary files differ
diff --git a/tests/EmbeddedKitchenSinkApp/res/drawable/ic_check_box_checked.xml b/tests/EmbeddedKitchenSinkApp/res/drawable/ic_check_box_checked.xml
index b1e9707..d14f423 100644
--- a/tests/EmbeddedKitchenSinkApp/res/drawable/ic_check_box_checked.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/drawable/ic_check_box_checked.xml
@@ -15,9 +15,9 @@
   -->
 
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="@dimen/car_primary_icon_size"
-        android:height="@dimen/car_primary_icon_size"
-        android:tint="@color/car_accent"
+        android:width="@dimen/car_ui_primary_icon_size"
+        android:height="@dimen/car_ui_primary_icon_size"
+        android:tint="?android:attr/colorAccent"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
diff --git a/tests/EmbeddedKitchenSinkApp/res/drawable/ic_check_box_unchecked.xml b/tests/EmbeddedKitchenSinkApp/res/drawable/ic_check_box_unchecked.xml
index b05cb48..b6b82f9 100644
--- a/tests/EmbeddedKitchenSinkApp/res/drawable/ic_check_box_unchecked.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/drawable/ic_check_box_unchecked.xml
@@ -15,9 +15,9 @@
   -->
 
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="@dimen/car_primary_icon_size"
-        android:height="@dimen/car_primary_icon_size"
-        android:tint="@color/car_tint"
+        android:width="@dimen/car_ui_primary_icon_size"
+        android:height="@dimen/car_ui_primary_icon_size"
+        android:tint="#fff8f9fa"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/activity_view_test_fragment.xml b/tests/EmbeddedKitchenSinkApp/res/layout/activity_view_test_fragment.xml
index bd74423..568bad5 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/activity_view_test_fragment.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/activity_view_test_fragment.xml
@@ -19,7 +19,7 @@
     <RelativeLayout android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:padding="20dp">
-        <ActivityView android:id="@+id/av_activityview"
+        <android.car.app.CarActivityView android:id="@+id/av_activityview"
                       android:layout_width="match_parent"
                       android:layout_height="match_parent"/>
     </RelativeLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/alert_dialog_bluetooth_pin_confirm.xml b/tests/EmbeddedKitchenSinkApp/res/layout/alert_dialog_bluetooth_pin_confirm.xml
index d613e4a..a54d135 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/alert_dialog_bluetooth_pin_confirm.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/alert_dialog_bluetooth_pin_confirm.xml
@@ -30,7 +30,7 @@
         android:orientation="vertical">
 
         <RelativeLayout
-            android:layout_height="@dimen/car_double_line_list_item_height"
+            android:layout_height="@dimen/car_ui_list_item_height"
             android:layout_width="match_parent" >
             <LinearLayout
                 android:layout_width="match_parent"
@@ -45,13 +45,13 @@
                     android:layout_height="wrap_content"
                     android:text="@string/bluetooth_pairing_key_msg"
                     android:visibility="gone"
-                    style="@style/TextAppearance.Car.Body2.SingleLine" />
+                    style="@style/TextAppearance.CarUi.Body2.SingleLine" />
                 <TextView
                     android:id="@+id/pairing_subhead"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:visibility="gone"
-                    style="@style/TextAppearance.Car.Body1.SingleLine"
+                    style="@style/TextAppearance.CarUi.Body1.SingleLine"
                     android:layout_marginTop="@dimen/car_padding_1" />
             </LinearLayout>
         </RelativeLayout>
@@ -59,14 +59,14 @@
         <TextView
             android:id="@+id/pairing_code_message"
             android:layout_width="wrap_content"
-            android:layout_height="@dimen/car_single_line_list_item_height"
+            android:layout_height="@dimen/car_ui_list_item_height"
             android:gravity="center_vertical"
             android:text="@string/bluetooth_enter_passkey_msg"
-            style="@style/TextAppearance.Car.Body2"
+            style="@style/TextAppearance.CarUi.Body2"
             android:visibility="gone" />
 
         <RelativeLayout
-            android:layout_height="@dimen/car_double_line_list_item_height"
+            android:layout_height="@dimen/car_ui_list_item_height"
             android:layout_width="match_parent" >
             <CheckBox
                 android:id="@+id/phonebook_sharing_message_confirm_pin"
@@ -83,7 +83,7 @@
                 android:layout_centerVertical="true"
                 android:layout_marginStart="@dimen/car_keyline_3"
                 android:layout_marginEnd="@dimen/car_keyline_3"
-                style="@style/TextAppearance.Car.Body2.SingleLine"
+                style="@style/TextAppearance.CarUi.Body2.SingleLine"
                 android:gravity="center_vertical"/>
         </RelativeLayout>
 
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/alert_dialog_bluetooth_pin_entry.xml b/tests/EmbeddedKitchenSinkApp/res/layout/alert_dialog_bluetooth_pin_entry.xml
index 898cf4d..6d2dffb 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/alert_dialog_bluetooth_pin_entry.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/alert_dialog_bluetooth_pin_entry.xml
@@ -32,12 +32,12 @@
         <TextView
             android:id="@+id/message_below_pin"
             android:layout_width="wrap_content"
-            android:layout_height="@dimen/car_single_line_list_item_height"
+            android:layout_height="@dimen/car_ui_list_item_height"
             android:gravity="center_vertical"
-            style="@style/TextAppearance.Car.Body2"/>
+            style="@style/TextAppearance.CarUi.Body2"/>
 
         <FrameLayout
-            android:layout_height="@dimen/car_double_line_list_item_height"
+            android:layout_height="@dimen/car_ui_list_item_height"
             android:layout_width="match_parent" >
             <LinearLayout
                 android:layout_width="match_parent"
@@ -48,7 +48,7 @@
                     android:id="@+id/text"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    style="@style/TextAppearance.Car.Body1"
+                    style="@style/TextAppearance.CarUi.Body1"
                     android:inputType="textPassword"
                     android:maxLines="1" />
                 <TextView
@@ -57,17 +57,17 @@
                     android:layout_height="wrap_content"
                     android:layout_marginTop="@dimen/car_padding_2"
                     android:text="@string/bluetooth_pin_values_hint"
-                    style="@style/TextAppearance.Car.Body2.SingleLine" />
+                    style="@style/TextAppearance.CarUi.Body2.SingleLine" />
             </LinearLayout>
         </FrameLayout>
 
         <RelativeLayout
-            android:layout_height="@dimen/car_double_line_list_item_height"
+            android:layout_height="@dimen/car_ui_list_item_height"
             android:layout_width="match_parent" >
             <CheckBox
                 android:id="@+id/alphanumeric_pin"
-                android:layout_width="@dimen/car_primary_icon_size"
-                android:layout_height="@dimen/car_primary_icon_size"
+                android:layout_width="@dimen/car_ui_primary_icon_size"
+                android:layout_height="@dimen/car_ui_primary_icon_size"
                 android:button="@drawable/ic_check_box"
                 android:layout_alignParentStart="true"
                 android:layout_centerVertical="true" />
@@ -79,17 +79,17 @@
                 android:layout_centerVertical="true"
                 android:layout_marginStart="@dimen/car_keyline_3"
                 android:layout_marginEnd="@dimen/car_keyline_3"
-                style="@style/TextAppearance.Car.Body2.SingleLine"
+                style="@style/TextAppearance.CarUi.Body2.SingleLine"
                 android:gravity="center_vertical"/>
         </RelativeLayout>
 
         <RelativeLayout
-            android:layout_height="@dimen/car_double_line_list_item_height"
+            android:layout_height="@dimen/car_ui_list_item_height"
             android:layout_width="match_parent">
             <CheckBox
                 android:id="@+id/phonebook_sharing_message_entry_pin"
-                android:layout_width="@dimen/car_primary_icon_size"
-                android:layout_height="@dimen/car_primary_icon_size"
+                android:layout_width="@dimen/car_ui_primary_icon_size"
+                android:layout_height="@dimen/car_ui_primary_icon_size"
                 android:button="@drawable/ic_check_box"
                 android:layout_alignParentStart="true"
                 android:layout_centerVertical="true" />
@@ -101,7 +101,7 @@
                 android:layout_centerVertical="true"
                 android:layout_marginStart="@dimen/car_keyline_3"
                 android:layout_marginEnd="@dimen/car_keyline_3"
-                style="@style/TextAppearance.Car.Body2.SingleLine"
+                style="@style/TextAppearance.CarUi.Body2.SingleLine"
                 android:gravity="center_vertical"/>
         </RelativeLayout>
     </LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/audio.xml b/tests/EmbeddedKitchenSinkApp/res/layout/audio.xml
index cd5decc..cfc3515 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/audio.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/audio.xml
@@ -28,13 +28,45 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:orientation="horizontal"
-                android:layout_weight="1" >
-                <ToggleButton
-                    android:id="@+id/button_mock_audio"
+                android:layout_weight="1"
+                android:visibility="gone"
+                android:id="@+id/audio_select_device_address_layout">
+                <TextView
+                    android:id="@+id/select_device_title"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:textOn="@string/mock_audio_on"
-                    android:textOff="@string/mock_audio_off" />
+                    android:text="@string/select_device" />
+                <Space
+                    android:layout_width="3dp"
+                    android:layout_height="match_parent" />
+                <Spinner
+                    android:id="@+id/device_address_spinner"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content" />
+                <Space
+                    android:layout_width="3dp"
+                    android:layout_height="match_parent" />
+                <Button
+                    android:id="@+id/button_device_media_play_start"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/play" />
+                <Space
+                    android:layout_width="3dp"
+                    android:layout_height="match_parent" />
+                <Button
+                    android:id="@+id/button_device_media_play_once"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/play_pcm_once" />
+                <Space
+                    android:layout_width="3dp"
+                    android:layout_height="match_parent" />
+                <Button
+                    android:id="@+id/button_device_media_play_stop"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/stop" />
             </LinearLayout>
             <LinearLayout
                 android:layout_width="match_parent"
@@ -45,7 +77,7 @@
                     android:id="@+id/zone_selection_title"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:text="@string/select_zone" />
+                    android:text="@string/select_zone_to_hear_on_speaker" />
                 <Spinner
                     android:id="@+id/zone_spinner"
                     android:layout_width="fill_parent"
@@ -56,45 +88,30 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:orientation="horizontal"
-                android:layout_weight="1"
-                android:visibility="gone"
-                android:id="@+id/audio_display_layout">
+                android:layout_weight="1" >
                 <TextView
-                    android:id="@+id/select_display_title"
+                    android:id="@+id/activity_current_zone_id_title"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:text="@string/select_display" />
-                <Space
-                    android:layout_width="3dp"
-                    android:layout_height="match_parent" />
-                <Spinner
-                    android:id="@+id/display_spinner"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content" />
-                <Space
-                    android:layout_width="3dp"
-                    android:layout_height="match_parent" />
-                <Button
-                    android:id="@+id/button_display_media_play_start"
+                    android:text="@string/activity_current_zone_id" />
+                <TextView
+                    android:id="@+id/activity_current_zone"
+                    android:paddingLeft="8dp"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:text="@string/play" />
-                <Space
-                    android:layout_width="3dp"
-                    android:layout_height="match_parent" />
-                <Button
-                    android:id="@+id/button_display_media_play_once"
+                    android:text="@string/no_zone" />
+            </LinearLayout>
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                android:layout_weight="1" >
+                <ToggleButton
+                    android:id="@+id/button_mock_audio"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:text="@string/play_pcm_once" />
-                <Space
-                    android:layout_width="3dp"
-                    android:layout_height="match_parent" />
-                <Button
-                    android:id="@+id/button_display_media_play_stop"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="@string/stop" />
+                    android:textOn="@string/mock_audio_on"
+                    android:textOff="@string/mock_audio_off" />
             </LinearLayout>
             <LinearLayout
                 android:layout_width="match_parent"
@@ -256,6 +273,52 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:orientation="horizontal"
+                android:layout_weight="1" >
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/media_with_delayed_focus" />
+                <Button
+                    android:id="@+id/media_delayed_focus_start"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/play" />
+                <Button
+                    android:id="@+id/media_delayed_focus_stop"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/stop" />
+                <TextView
+                    android:id="@+id/media_delayed_player_status"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:paddingLeft="8dp"
+                    android:text="@string/player_not_started" />
+            </LinearLayout>
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                android:layout_weight="1" >
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/phone_audio_player" />
+                <Button
+                    android:id="@+id/phone_audio_focus_start"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/play" />
+                <Button
+                    android:id="@+id/phone_audio_focus_stop"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/stop" />
+            </LinearLayout>
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
                 android:layout_weight="1">
                 <Button
                     android:id="@+id/button_microphone_on"
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/audio_input.xml b/tests/EmbeddedKitchenSinkApp/res/layout/audio_input.xml
new file mode 100644
index 0000000..3e2dd0c
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/audio_input.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<LinearLayout
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical"
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <com.google.android.material.tabs.TabLayout
+        android:id="@+id/zones_input_tab"
+        android:layout_width="match_parent"
+        android:layout_height="50dp">
+    </com.google.android.material.tabs.TabLayout>
+    <androidx.viewpager.widget.ViewPager
+        android:id="@+id/zones_input_view_pager"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+    </androidx.viewpager.widget.ViewPager>
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/audio_input_item.xml b/tests/EmbeddedKitchenSinkApp/res/layout/audio_input_item.xml
new file mode 100644
index 0000000..ac87a74
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/audio_input_item.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <TextView
+        android:id="@+id/input_device_address"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:textSize="20sp"
+        android:layout_weight="1">
+    </TextView>
+    <Button
+        android:id="@+id/play_audio_input"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="20dp"
+        android:text="@string/play_audio_input" />
+    <Button
+        android:id="@+id/stop_audio_input"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/stop_audio_input"/>
+    <TextView
+        android:id="@+id/input_device_state"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:textSize="20sp"
+        android:layout_weight="1"
+        android:text="@string/player_not_started">
+    </TextView>
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/connectivity_fragment.xml b/tests/EmbeddedKitchenSinkApp/res/layout/connectivity_fragment.xml
index c6e75fe..3d8f94a 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/connectivity_fragment.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/connectivity_fragment.xml
@@ -14,122 +14,168 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:orientation="vertical"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent">
+<androidx.viewpager.widget.ViewPager
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/connectivity_pager"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <com.google.android.material.tabs.TabLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="top" />
 
     <LinearLayout
+        android:tag="WiFi Control"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <LinearLayout
             android:orientation="horizontal"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_margin="4dp">
 
-        <TextView
+            <TextView
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginRight="20dp"
                 android:text="Wifi:" />
 
-        <Button android:id="@+id/startWifi"
+            <Button android:id="@+id/startWifi"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginRight="5dp"
                 android:text="Start" />
 
-        <Button android:id="@+id/stopWifi"
+            <Button android:id="@+id/stopWifi"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginRight="20dp"
                 android:text="Stop" />
 
-        <TextView
+            <TextView
                 android:id="@+id/wifiStatusPolled"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content" />
-    </LinearLayout>
+        </LinearLayout>
 
-    <LinearLayout
+        <LinearLayout
             android:orientation="horizontal"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_margin="4dp">
 
-        <TextView
+            <TextView
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginRight="20dp"
                 android:text="Tethering:" />
 
-        <Button android:id="@+id/startTethering"
+            <Button android:id="@+id/startTethering"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginRight="5dp"
                 android:text="Start" />
 
-        <Button android:id="@+id/stopTethering"
+            <Button android:id="@+id/stopTethering"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginRight="20dp"
                 android:text="Stop" />
 
-        <TextView
+            <TextView
                 android:id="@+id/tetheringStatus"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginRight="5dp" />
 
-        <TextView
+            <TextView
                 android:id="@+id/tetheringStatusPolled"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content" />
-    </LinearLayout>
+        </LinearLayout>
 
-    <LinearLayout
+        <LinearLayout
             android:orientation="horizontal"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_margin="4dp">
 
-        <TextView
+            <TextView
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginRight="20dp"
                 android:text="LocalOnly:" />
 
-        <Button android:id="@+id/startLocalOnly"
+            <Button android:id="@+id/startLocalOnly"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginRight="5dp"
                 android:text="Start" />
 
-        <Button android:id="@+id/stopLocalOnly"
+            <Button android:id="@+id/stopLocalOnly"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginRight="20dp"
                 android:text="Stop" />
 
-        <TextView
+            <TextView
                 android:id="@+id/localOnlyStatus"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_margin="4dp">
+            <Button android:id="@+id/networkEnableWifiIntent"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="Enable Wifi Intent"/>
+            <Button android:id="@+id/networkDisableWifiIntent"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="Disable Wifi Intent"/>
+        </LinearLayout>
+
+        <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_margin="4dp">
+            <Button android:id="@+id/networkEnableBluetoothIntent"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="Enable Bluetooth Intent"/>
+            <Button android:id="@+id/networkDisableBluetoothIntent"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="Disable Bluetooth Intent"/>
+            <Button android:id="@+id/networkDiscoverableBluetoothIntent"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="Discoverable Bluetooth Intent"/>
+        </LinearLayout>
     </LinearLayout>
 
-    <!-- List(s) of networks (right now only have view all, may do a search UI)
-    -->
     <LinearLayout
-            android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent">
+        android:tag="Network list"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
 
         <!-- Header for table -->
         <LinearLayout
-                android:orientation="horizontal"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:paddingLeft="4dp"
-                android:background="#3C3F41"
-                android:weightSum="12">
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingLeft="4dp"
+            android:background="#3C3F41"
+            android:weightSum="12">
 
             <TextView
                 android:layout_width="0dp"
@@ -138,8 +184,7 @@
                 android:textSize="32sp"
                 android:textColor="#d4d4d4"
                 android:textStyle="bold"
-                android:text="Net ID">
-            </TextView>
+                android:text="Net ID" />
 
             <TextView
                 android:layout_width="0dp"
@@ -148,8 +193,7 @@
                 android:textSize="32sp"
                 android:textColor="#d4d4d4"
                 android:textStyle="bold"
-                android:text="Details">
-            </TextView>
+                android:text="Details" />
 
             <TextView
                 android:layout_width="0dp"
@@ -158,8 +202,7 @@
                 android:textSize="32sp"
                 android:textColor="#d4d4d4"
                 android:textStyle="bold"
-                android:text="Functions">
-            </TextView>
+                android:text="Functions" />
 
         </LinearLayout>
 
@@ -171,47 +214,12 @@
 
             <!-- Filled in code with network_item.xml -->
             <ListView
-                    android:id="@+id/networks"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content">
-            </ListView>
+                android:id="@+id/networks"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" />
 
         </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
 
     </LinearLayout>
 
-    <LinearLayout
-        android:orientation="horizontal"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_margin="4dp">
-        <Button android:id="@+id/networkEnableWifiIntent"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="Enable Wifi Intent"/>
-        <Button android:id="@+id/networkDisableWifiIntent"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="Disable Wifi Intent"/>
-    </LinearLayout>
-
-    <LinearLayout
-        android:orientation="horizontal"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_margin="4dp">
-        <Button android:id="@+id/networkEnableBluetoothIntent"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="Enable Bluetooth Intent"/>
-        <Button android:id="@+id/networkDisableBluetoothIntent"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="Disable Bluetooth Intent"/>
-        <Button android:id="@+id/networkDiscoverableBluetoothIntent"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="Discoverable Bluetooth Intent"/>
-    </LinearLayout>
-
-</LinearLayout>
+</androidx.viewpager.widget.ViewPager>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/dialer_test.xml b/tests/EmbeddedKitchenSinkApp/res/layout/dialer_test.xml
deleted file mode 100644
index ef8ecee..0000000
--- a/tests/EmbeddedKitchenSinkApp/res/layout/dialer_test.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2020 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical">
-
-    <ScrollView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:fillViewport="true">
-
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="vertical">
-
-            <Button
-                android:id="@+id/bind_btn"
-                android:layout_width="400dp"
-                android:layout_height="80dp"
-                android:text="BIND">
-            </Button>
-
-            <Button
-                android:id="@+id/bring_to_front_btn"
-                android:layout_width="400dp"
-                android:layout_height="80dp"
-                android:text="onBringToFront">
-            </Button>
-        </LinearLayout>
-    </ScrollView>
-</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/experimental_feature_test.xml b/tests/EmbeddedKitchenSinkApp/res/layout/experimental_feature_test.xml
new file mode 100644
index 0000000..6119157
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/experimental_feature_test.xml
@@ -0,0 +1,45 @@
+<?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_experimental_ping"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/experimental_ping" />
+                <TextView
+                    android:id="@+id/experimental_ping_msg"
+                    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/layout/kitchen_activity.xml b/tests/EmbeddedKitchenSinkApp/res/layout/kitchen_activity.xml
index f0439c4..e6de221 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/kitchen_activity.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/kitchen_activity.xml
@@ -26,7 +26,6 @@
         android:layout_height="wrap_content"
         android:layout_centerHorizontal="true"
         android:layout_marginBottom="10dp"
-        android:background="@android:color/background_light"
         android:text="Hide KitchenSink Menu"
         android:textSize="30sp"
         android:padding="15dp"/>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/notification_fragment.xml b/tests/EmbeddedKitchenSinkApp/res/layout/notification_fragment.xml
index 088aa68..4610f4c 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/notification_fragment.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/notification_fragment.xml
@@ -55,13 +55,23 @@
                 android:textSize="30sp"/>
 
             <Button
-                android:id="@+id/category_message_button"
+                android:id="@+id/category_message_diff_person_button"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_margin="10dp"
                 android:background="#ffa9a8"
                 android:foreground="?android:attr/selectableItemBackground"
-                android:text="Message"
+                android:text="Message from diff person"
+                android:textSize="30sp"/>
+
+            <Button
+                android:id="@+id/category_message_same_person_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dp"
+                android:background="#ffa9a8"
+                android:foreground="?android:attr/selectableItemBackground"
+                android:text="Message from same person"
                 android:textSize="30sp"/>
 
             <Button
@@ -109,6 +119,22 @@
                 android:layout_margin="10dp"
                 android:text="Progress (Can't dismiss)"
                 android:textSize="30sp"/>
+
+            <Button
+                android:id="@+id/custom_group_summary_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dp"
+                android:text="Custom Group Summary of 6 (Inbox Style, Should behave the same as phone)"
+                android:textSize="30sp"/>
+
+            <Button
+                android:id="@+id/group_without_summary_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dp"
+                android:text="Custom Group Without Summary of 6 (Should not group)"
+                android:textSize="30sp"/>
         </LinearLayout>
 
         <LinearLayout
@@ -173,6 +199,7 @@
                 android:background="#ffa9a8"
                 android:foreground="?android:attr/selectableItemBackground"
                 android:text="Car Emergency"
+                android:enabled="false"
                 android:textSize="30sp"/>
 
             <Button
@@ -183,6 +210,7 @@
                 android:background="#ffa9a8"
                 android:foreground="?android:attr/selectableItemBackground"
                 android:text="Car Warning"
+                android:enabled="false"
                 android:textSize="30sp"/>
 
             <Button
@@ -191,6 +219,7 @@
                 android:layout_height="wrap_content"
                 android:layout_margin="10dp"
                 android:text="Car Information"
+                android:enabled="false"
                 android:textSize="30sp"/>
         </LinearLayout>
     </LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/package_info_test.xml b/tests/EmbeddedKitchenSinkApp/res/layout/package_info_test.xml
new file mode 100644
index 0000000..23a5765
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/package_info_test.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+          http://www.apache.org/licenses/LICENSE-2.0
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout
+    android:layout_width="fill_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <LinearLayout
+        android:id="@+id/header"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="@dimen/header_margin"
+        android:orientation="horizontal">
+        <Spinner
+            android:id = "@+id/spinner"
+            android:layout_width = "wrap_content"
+            android:layout_height = "wrap_content"
+            android:layout_weight = "1"
+            android:paddingLeft="@dimen/header_padding"
+            android:prompt = "@string/select_user"
+            android:textSize = "@dimen/spinner_text_size"
+            />
+        <CheckBox
+            android:id = "@+id/checkbox_activities"
+            android:layout_width = "wrap_content"
+            android:layout_height = "wrap_content"
+            android:layout_weight = "1"
+            android:paddingLeft="@dimen/header_padding"
+            android:text = "@string/checkbox_activities"
+            android:textSize = "@dimen/checkbox_text_size"
+            />
+        <CheckBox
+            android:id = "@+id/checkbox_services"
+            android:layout_width = "wrap_content"
+            android:layout_height = "wrap_content"
+            android:layout_weight = "1"
+            android:text = "@string/checkbox_services"
+            android:textSize = "@dimen/checkbox_text_size"
+            />
+        <CheckBox
+            android:id = "@+id/checkbox_permissions"
+            android:layout_width = "wrap_content"
+            android:layout_height = "wrap_content"
+            android:layout_weight = "1"
+            android:text = "@string/checkbox_permissions"
+            android:textSize = "@dimen/checkbox_text_size"
+            />
+        <CheckBox
+            android:id = "@+id/checkbox_shareduid"
+            android:layout_width = "wrap_content"
+            android:layout_height = "wrap_content"
+            android:layout_weight = "1"
+            android:text = "@string/checkbox_shareduid"
+            android:textSize = "@dimen/checkbox_text_size"
+            />
+        <Button
+            android:id = "@+id/button_show"
+            android:layout_width = "wrap_content"
+            android:layout_height = "wrap_content"
+            android:layout_weight = "1"
+            android:text = "@string/button_show"
+            android:textSize = "@dimen/checkbox_text_size"
+            />
+    </LinearLayout>
+    <ScrollView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:id="@+id/packages"/>
+     </ScrollView>
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/profile_user.xml b/tests/EmbeddedKitchenSinkApp/res/layout/profile_user.xml
new file mode 100644
index 0000000..9a2d78a
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/profile_user.xml
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical" >
+    <TextView
+        android:id="@+id/profile_textView_state"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" android:text=""/>
+    <TextView
+        android:id="@+id/profile_textView_zoneinfo"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" android:text=""/>
+    <TextView
+        android:id="@+id/profile_textView_userstate"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" android:text=""/>
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal" >
+        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                      android:layout_width="wrap_content"
+                      android:layout_height="wrap_content"
+                      android:orientation="vertical" >
+            <TextView
+                android:id="@+id/profile_textView_users"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" android:text="Users"/>
+            <Spinner
+                android:id="@+id/profile_spinner_users"
+                android:layout_width="wrap_content" android:layout_height="wrap_content"/>
+        </LinearLayout>
+        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                      android:layout_width="wrap_content"
+                      android:layout_height="wrap_content"
+                      android:orientation="vertical" >
+            <TextView
+                android:id="@+id/profile_textView_zones"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" android:text="Zones"/>
+            <Spinner
+                android:id="@+id/profile_spinner_zones"
+                android:layout_width="wrap_content" android:layout_height="wrap_content"/>
+        </LinearLayout>
+        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                      android:layout_width="wrap_content"
+                      android:layout_height="wrap_content"
+                      android:orientation="vertical" >
+            <TextView
+                android:id="@+id/profile_textView_displays"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" android:text="Displays"/>
+            <Spinner
+                android:id="@+id/profile_spinner_displays"
+                android:layout_width="wrap_content" android:layout_height="wrap_content"/>
+        </LinearLayout>
+        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                      android:layout_width="wrap_content"
+                      android:layout_height="wrap_content"
+                      android:orientation="vertical" >
+            <TextView
+                android:id="@+id/profile_textView_apps"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" android:text="Apps"/>
+            <Spinner
+                android:id="@+id/profile_spinner_apps"
+                android:layout_width="wrap_content" android:layout_height="wrap_content"/>
+        </LinearLayout>
+    </LinearLayout>
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="horizontal" >
+        <Button
+            android:id="@+id/profile_button_create_managed_user"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:text="Create Managed User"/>
+        <Button
+            android:id="@+id/profile_button_create_restricted_user"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:text="Create Restricted User"/>
+        <Button
+            android:id="@+id/profile_button_remove_user"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:text="Remove User"/>
+    </LinearLayout>
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="horizontal" >
+        <Button
+            android:id="@+id/profile_button_start_user"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:text="Start User"/>
+        <Button
+            android:id="@+id/profile_button_stop_user"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:text="Stop User"/>
+        <Button
+            android:id="@+id/profile_button_assign_user_to_zone"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:text="Assign User To Zone"/>
+    </LinearLayout>
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="horizontal" >
+        <Button
+            android:id="@+id/profile_button_launch_app_for_zone"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:text="Start App For Zone"/>
+        <Button
+            android:id="@+id/profile_button_launch_app_for_display"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:text="Start App For Display And User"/>
+    </LinearLayout>
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="horizontal" >
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/status_message_title"/>
+        <TextView
+            android:id="@+id/status_message_text_view"
+            android:paddingLeft="10dp"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text=""/>
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/sensors.xml b/tests/EmbeddedKitchenSinkApp/res/layout/sensors.xml
index 6c4d945..3d7f320 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/sensors.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/sensors.xml
@@ -23,7 +23,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:orientation="vertical"
-            android:layout_centerHorizontal="true">
+            android:layout_marginLeft="30dp">
         <TextView
             android:id="@+id/location_title"
             android:layout_width="wrap_content"
@@ -59,9 +59,8 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:orientation="vertical"
-            android:layout_centerHorizontal="true"
-            android:layout_below="@+id/location_layout"
-            android:layout_alignStart="@+id/location_layout">
+            android:layout_marginLeft="30dp"
+            android:layout_below="@+id/location_layout">
         <TextView
             android:id="@+id/sensor_title"
             android:layout_width="wrap_content"
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/sms_received.xml b/tests/EmbeddedKitchenSinkApp/res/layout/sms_received.xml
index 0a329af..5c3bd12 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/sms_received.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/sms_received.xml
@@ -79,14 +79,30 @@
             android:id="@+id/sms_tel_num"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:text="+1-650-000-0000                    "
-            android:inputType="text" />
+            android:text="+1-650-000-0000, comma separated"
+            android:inputType="text"/>
+    </LinearLayout>
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
         <Button
             android:id="@+id/sms_new_message"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center"
             android:text="@string/sms_new_message_button"/>
+        <Button
+            android:id="@+id/mms_new_message"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:text="@string/mms_new_message_button"/>
+        <Button
+            android:id="@+id/reset_message_counter"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:text="@string/reset_message_counter_button"/>
     </LinearLayout>
 
     <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content"
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/system_feature_fragment.xml b/tests/EmbeddedKitchenSinkApp/res/layout/system_feature_fragment.xml
new file mode 100644
index 0000000..45d1dbb
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/system_feature_fragment.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<ListView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/sys_features_list"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+</ListView>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/vehicle_ctrl_fragment.xml b/tests/EmbeddedKitchenSinkApp/res/layout/vehicle_ctrl_fragment.xml
new file mode 100644
index 0000000..0b3ade4
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/vehicle_ctrl_fragment.xml
@@ -0,0 +1,169 @@
+<?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.
+-->
+
+<androidx.viewpager.widget.ViewPager
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/vehicle_ctrl_pager"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <com.google.android.material.tabs.TabLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="top" />
+
+    <LinearLayout
+        android:tag="Doors/windows"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <TextView
+                android:layout_width="300dp"
+                android:layout_height="wrap_content"
+                android:text="Front left window:" />
+
+            <Button android:id="@+id/winFLOpen"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Open" />
+
+            <Button android:id="@+id/winFLClose"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Close" />
+
+            <TextView android:id="@+id/winFLPos"
+                android:layout_marginLeft="20dp"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <TextView
+                android:layout_width="300dp"
+                android:layout_height="wrap_content"
+                android:text="Front right window:" />
+
+            <Button android:id="@+id/winFROpen"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Open" />
+
+            <Button android:id="@+id/winFRClose"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Close" />
+
+            <TextView android:id="@+id/winFRPos"
+                android:layout_marginLeft="20dp"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <TextView
+                android:layout_width="300dp"
+                android:layout_height="wrap_content"
+                android:text="Rear left window:" />
+
+            <Button android:id="@+id/winRLOpen"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Open" />
+
+            <Button android:id="@+id/winRLClose"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Close" />
+
+            <TextView android:id="@+id/winRLPos"
+                android:layout_marginLeft="20dp"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <TextView
+                android:layout_width="300dp"
+                android:layout_height="wrap_content"
+                android:text="Rear right window:" />
+
+            <Button android:id="@+id/winRROpen"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Open" />
+
+            <Button android:id="@+id/winRRClose"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Close" />
+
+            <TextView android:id="@+id/winRRPos"
+                android:layout_marginLeft="20dp"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" />
+        </LinearLayout>
+    </LinearLayout>
+
+    <LinearLayout
+        android:tag="Prop test"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <TextView
+                android:layout_width="300dp"
+                android:layout_height="wrap_content"
+                android:text="PROTOCAN_TEST" />
+
+            <Button android:id="@+id/protocan_test_on"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="ON" />
+
+            <Button android:id="@+id/protocan_test_off"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="OFF" />
+
+        </LinearLayout>
+    </LinearLayout>
+
+
+</androidx.viewpager.widget.ViewPager>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/volume_test.xml b/tests/EmbeddedKitchenSinkApp/res/layout/volume_test.xml
index db48680..7cd5c95 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/volume_test.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/volume_test.xml
@@ -16,12 +16,25 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="horizontal" android:layout_width="match_parent"
     android:layout_height="match_parent">
-    <ListView
-        android:id="@+id/volume_list"
+
+    <LinearLayout
         android:layout_width="0dp"
         android:layout_height="match_parent"
+        android:layout_marginLeft="20dp"
+        android:orientation="vertical"
         android:layout_weight="3">
-    </ListView>
+        <com.google.android.material.tabs.TabLayout
+            android:id="@+id/zones_tab"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content">
+        </com.google.android.material.tabs.TabLayout>
+        <androidx.viewpager.widget.ViewPager
+            android:id="@+id/zone_view_pager"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1">
+        </androidx.viewpager.widget.ViewPager>
+    </LinearLayout>
 
     <LinearLayout
         android:layout_width="0dp"
@@ -31,12 +44,6 @@
         android:layout_weight="1">
 
         <Button
-            android:id="@+id/refresh"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/refresh_volume"/>
-
-        <Button
             android:id="@+id/volume_up"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/zone_input_tab.xml b/tests/EmbeddedKitchenSinkApp/res/layout/zone_input_tab.xml
new file mode 100644
index 0000000..f552265
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/zone_input_tab.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <ListView
+        android:id="@+id/input_list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_weight="3">
+    </ListView>
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/zone_volume_tab.xml b/tests/EmbeddedKitchenSinkApp/res/layout/zone_volume_tab.xml
new file mode 100644
index 0000000..bb38d5a
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/zone_volume_tab.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <ListView
+        android:id="@+id/volume_list"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="3">
+    </ListView>
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/values/dimens.xml b/tests/EmbeddedKitchenSinkApp/res/values/dimens.xml
index 437d69d..a649f9c 100644
--- a/tests/EmbeddedKitchenSinkApp/res/values/dimens.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/values/dimens.xml
@@ -45,6 +45,12 @@
     <dimen name="car_card_header_height">96dp</dimen>
     <dimen name="car_card_action_bar_height">96dp</dimen>
 
+    <!-- Package info -->
+    <dimen name="spinner_text_size">16sp</dimen>
+    <dimen name="checkbox_text_size">16sp</dimen>
+    <dimen name="header_margin">8dp</dimen>
+    <dimen name="header_padding">8dp</dimen>
+
     <!-- Paddings -->
     <dimen name="car_padding_1">4dp</dimen>
     <dimen name="car_padding_2">10dp</dimen>
diff --git a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
index 0d56369..e64c094 100644
--- a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
@@ -113,6 +113,12 @@
     <string name="media_play" translatable="false">Media Play</string>
     <string name="hw_audio_source_title" translatable="false">HwAudioSource</string>
     <string name="hw_audio_source_not_found" translatable="false">Not found</string>
+    <string name="media_with_delayed_focus" translatable="false">Media With Delayed Focus</string>
+    <string name="player_not_started" translatable="false">Player Not Started</string>
+    <string name="player_paused" translatable="false">Player Paused</string>
+    <string name="player_started" translatable="false">Player Started</string>
+    <string name="player_delayed" translatable="false">Player Delayed</string>
+    <string name="player_stopped" translatable="false">Player Stopped</string>
     <string name="nav_play" translatable="false">Nav Play</string>
     <string name="vr_play" translatable="false">VR Play</string>
     <string name="system_play" translatable="false">System Play</string>
@@ -131,8 +137,15 @@
     <string name="microphone_off" translatable="false">Mic Off</string>
     <string name="mock_audio_on" translatable="false">Audio Mocking On</string>
     <string name="mock_audio_off" translatable="false">Audio Mocking Off</string>
-    <string name="select_zone" translatable="false">Select Zone</string>
-    <string name="select_display" translatable="false">Select Display</string>
+    <string name="select_zone_to_hear_on_speaker" translatable="false">Select Zone to hear on speaker</string>
+    <string name="select_device" translatable="false">Select Device</string>
+    <string name="activity_current_zone_id" translatable="false">Activity\'s current audio zone id</string>
+    <string name="no_zone" translatable="false">none</string>
+    <string name="phone_audio_player" translatable="false">Phone Player</string>
+
+    <!-- Audio Input-->
+    <string name="play_audio_input" translatable="false">Play</string>
+    <string name="stop_audio_input" translatable="false">Stop</string>
 
     <!-- keyboard test fragment -->
     <string name="keyboard_test_title" translatable="false">Keyboard Test</string>
@@ -178,6 +191,14 @@
     <string name="sw_center" translatable="false">Center</string>
     <string name="sw_back" translatable="false">Back</string>
 
+    <!-- package info test -->
+    <string name="select_user" translatable="false">Select user</string>
+    <string name="checkbox_activities" translatable="false">contains only activities</string>
+    <string name="checkbox_services" translatable="false">services are not exported</string>
+    <string name="checkbox_permissions" translatable="false"> does not require selected permissions</string>
+    <string name="checkbox_shareduid" translatable="false">sharedUserId is not system</string>
+    <string name="button_show" translatable="false">Show</string>
+
     <!-- power test -->
     <string name="power_request_shutdown" translatable="false">Request Shutdown</string>
     <string name="power_shutdown" translatable="false">Shutdown</string>
@@ -249,7 +270,9 @@
     <string name="sms_connect" translatable="false">Connect</string>
     <string name="sms_disconnect" translatable="false">Disconnect</string>
     <string name="sms_send_message" translatable="false">Send</string>
-    <string name="sms_new_message_button" translatable="false">Send new message</string>
+    <string name="sms_new_message_button" translatable="false">Send new message (Short)</string>
+    <string name="mms_new_message_button" translatable="false">Send new message (Long)</string>
+    <string name="reset_message_counter_button" translatable="false">Reset message counter</string>
     <string name="sms_notifications" translatable="false">Toggle Notifications</string>
     <string name="sms_listing_button" translatable="false">List SMS</string>
     <string name="sms_listing_label_folder" translatable="false">Folder</string>
@@ -337,4 +360,10 @@
     <string name="always_crashing_activity" translatable="false">Always Crash Activity</string>
     <string name="no_crash_activity" translatable="false">No Crash Activity</string>
     <string name="empty_activity" translatable="false">Empty Activity</string>
+
+    <!-- ExperimentalFeatureTest -->
+    <string name="experimental_ping" translatable="false">Ping Service</string>
+
+    <!-- User Profile -->
+    <string name="status_message_title">Status Message</string>
 </resources>
diff --git a/tests/EmbeddedKitchenSinkApp/res/values/styles.xml b/tests/EmbeddedKitchenSinkApp/res/values/styles.xml
index 908c051..5d74613 100644
--- a/tests/EmbeddedKitchenSinkApp/res/values/styles.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/values/styles.xml
@@ -16,12 +16,12 @@
 */
 -->
 <resources>
-    <style name="TextAppearance.Car.Body1.SingleLine" parent="TextAppearance.Car.Body1">
+    <style name="TextAppearance.CarUi.Body1.SingleLine" parent="TextAppearance.CarUi.Body1">
         <item name="android:maxLines">1</item>
         <item name="android:ellipsize">marquee</item>
     </style>
 
-    <style name="TextAppearance.Car.Body2.SingleLine" parent="TextAppearance.Car.Body2">
+    <style name="TextAppearance.CarUi.Body2.SingleLine" parent="TextAppearance.CarUi.Body2">
         <item name="android:maxLines">1</item>
         <item name="android:ellipsize">end</item>
     </style>
@@ -34,6 +34,7 @@
         <item name="android:clickable">true</item>
     </style>
 
-    <style name="KitchenSinkActivityTheme" parent="android:Theme.DeviceDefault.NoActionBar">
+    <style name="KitchenSinkActivityTheme" parent="Theme.AppCompat.NoActionBar">
+        <item name="android:textSize">24sp</item>
     </style>
 </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
index 3e594f5..9f6b907 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/CarApiTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/CarApiTestFragment.java
@@ -71,17 +71,20 @@
                 R.id.carapi_createcar_with_status_change);
         view.findViewById(R.id.button_carapi_createandconnect).setOnClickListener(
                 (View v) -> {
+                    disconnectCar(mCarForCreateAndConnect);
                     mCarForCreateAndConnect = Car.createCar(getContext(),
                             mServiceConnectionForCreateAndConnect);
                     mCarForCreateAndConnect.connect();
                 });
         view.findViewById(R.id.button_carapi_createcar).setOnClickListener(
                 (View v) -> {
+                    disconnectCar(mCarForCreateCar);
                     mCarForCreateCar = Car.createCar(getContext());
                     mTextForCreateCar.setText("isConnected:" + mCarForCreateCar.isConnected());
                 });
         view.findViewById(R.id.button_carapi_createcar_with_status_change).setOnClickListener(
                 (View v) -> {
+                    disconnectCar(mCarForStatusChange);
                     mCarForStatusChange = Car.createCar(getContext(), null,
                             Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER,
                             (Car car, boolean ready) -> {
@@ -101,4 +104,21 @@
                 });
         return view;
     }
+
+    @Override
+    public void onDestroyView() {
+        disconnectCar(mCarForCreateAndConnect);
+        mCarForCreateAndConnect = null;
+        disconnectCar(mCarForCreateCar);
+        mCarForCreateCar = null;
+        disconnectCar(mCarForStatusChange);
+        mCarForStatusChange = null;
+        super.onDestroyView();
+    }
+
+    private void disconnectCar(Car car) {
+        if (car != null && car.isConnected()) {
+            car.disconnect();
+        }
+    }
 }
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/CarWatchdogClient.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/CarWatchdogClient.java
new file mode 100644
index 0000000..3f696f7
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/CarWatchdogClient.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.car.kitchensink;
+
+import android.annotation.NonNull;
+import android.car.Car;
+import android.car.watchdog.CarWatchdogManager;
+import android.car.watchdog.CarWatchdogManager.CarWatchdogClientCallback;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.util.Log;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public final class CarWatchdogClient {
+    private static final String TAG = CarWatchdogClient.class.getSimpleName();
+    private static final String TIMEOUT_CRITICAL = "critical";
+    private static final String TIMEOUT_MODERATE = "moderate";
+    private static final String TIMEOUT_NORMAL = "normal";
+    private static CarWatchdogClient sCarWatchdogClient;
+
+    private final CarWatchdogManager mCarWatchdogManager;
+    private final CarWatchdogClientCallback mClientCallback = new CarWatchdogClientCallback() {
+        @Override
+        public boolean onCheckHealthStatus(int sessionId, int timeout) {
+            if (mClientConfig.verbose) {
+                Log.i(TAG, "onCheckHealthStatus: session id =  " + sessionId);
+            }
+            long currentUptime = SystemClock.uptimeMillis();
+            return mClientConfig.notRespondAfterInMs < 0
+                    || mClientConfig.notRespondAfterInMs > currentUptime - mClientStartTime;
+        }
+
+        @Override
+        public void onPrepareProcessTermination() {
+            Log.w(TAG, "This process is being terminated by car watchdog");
+        }
+    };
+    private final ExecutorService mCallbackExecutor = Executors.newFixedThreadPool(1);
+    private ClientConfig mClientConfig;
+    private long mClientStartTime;
+
+    // This method is not intended for multi-threaded calls.
+    public static void start(Car car, @NonNull String command) {
+        if (sCarWatchdogClient != null) {
+            Log.w(TAG, "Car watchdog client already started");
+            return;
+        }
+        ClientConfig config;
+        try {
+            config = parseCommand(command);
+        } catch (IllegalArgumentException e) {
+            Log.w(TAG, "Watchdog command error: " + e);
+            return;
+        }
+        sCarWatchdogClient = new CarWatchdogClient(car, config);
+        sCarWatchdogClient.registerAndGo();
+    }
+
+    private static ClientConfig parseCommand(String command) {
+        String[] tokens = command.split("[ ]+");
+        int paramCount = tokens.length;
+        if (paramCount != 3 && paramCount != 4) {
+            throw new IllegalArgumentException("invalid command syntax");
+        }
+        int timeout;
+        int inactiveMainAfterInSec;
+        int notRespondAfterInSec;
+        switch (tokens[0]) {
+            case TIMEOUT_CRITICAL:
+                timeout = CarWatchdogManager.TIMEOUT_CRITICAL;
+                break;
+            case TIMEOUT_MODERATE:
+                timeout = CarWatchdogManager.TIMEOUT_MODERATE;
+                break;
+            case TIMEOUT_NORMAL:
+                timeout = CarWatchdogManager.TIMEOUT_NORMAL;
+                break;
+            default:
+                throw new IllegalArgumentException("invalid timeout value");
+        }
+        try {
+            notRespondAfterInSec = Integer.parseInt(tokens[1]);
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException("time for \"not responding after\" is not number");
+        }
+        try {
+            inactiveMainAfterInSec = Integer.parseInt(tokens[2]);
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException("time for \"inactive main after\" is not number");
+        }
+        boolean verbose = false;
+        if (paramCount == 4) {
+            switch (tokens[3]) {
+                case "true":
+                    verbose = true;
+                    break;
+                case "false":
+                    verbose = false;
+                    break;
+                default:
+                    throw new IllegalArgumentException("invalid verbose value: " + tokens[3]);
+            }
+        }
+        Log.i(TAG, "CarWatchdogClient command: timeout = " + tokens[0] + ", notRespondingAfter = "
+                + notRespondAfterInSec + ", inactiveMainAfter = " + inactiveMainAfterInSec
+                + ", verbose = " + verbose);
+        return new ClientConfig(timeout, inactiveMainAfterInSec, notRespondAfterInSec, verbose);
+    }
+
+    private CarWatchdogClient(Car car, ClientConfig config) {
+        mClientConfig = config;
+        mCarWatchdogManager = (CarWatchdogManager) car.getCarManager(Car.CAR_WATCHDOG_SERVICE);
+    }
+
+    private void registerAndGo() {
+        mClientStartTime = SystemClock.uptimeMillis();
+        mCarWatchdogManager.registerClient(mCallbackExecutor, mClientCallback,
+                mClientConfig.timeout);
+        // Post a runnable which takes long time to finish to the main thread if inactive_main_after
+        // is no less than 0
+        if (mClientConfig.inactiveMainAfterInMs >= 0) {
+            Handler handler = new Handler(Looper.getMainLooper());
+            handler.postDelayed(() -> {
+                try {
+                    if (mClientConfig.verbose) {
+                        Log.i(TAG, "Main thread gets inactive");
+                    }
+                    Thread.sleep(getTimeForInactiveMain(mClientConfig.timeout));
+                } catch (InterruptedException e) {
+                    // Ignore
+                }
+            }, mClientConfig.inactiveMainAfterInMs);
+        }
+    }
+
+    // The waiting time = (timeout * 2) + 50 milliseconds.
+    private long getTimeForInactiveMain(int timeout) {
+        switch (timeout) {
+            case CarWatchdogManager.TIMEOUT_CRITICAL:
+                return 6050L;
+            case CarWatchdogManager.TIMEOUT_MODERATE:
+                return 10050L;
+            case CarWatchdogManager.TIMEOUT_NORMAL:
+                return 20050L;
+            default:
+                Log.w(TAG, "Invalid timeout");
+                return 20050L;
+        }
+    }
+
+    private static final class ClientConfig {
+        public int timeout;
+        public long inactiveMainAfterInMs;
+        public long notRespondAfterInMs;
+        public boolean verbose;
+
+        ClientConfig(int timeout, int inactiveMainAfterInSec, int notRespondAfterInSec,
+                boolean verbose) {
+            this.timeout = timeout;
+            inactiveMainAfterInMs = inactiveMainAfterInSec * 1000L;
+            notRespondAfterInMs = notRespondAfterInSec * 1000L;
+            this.verbose = verbose;
+        }
+    }
+}
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 e667964..20dd9fc 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
@@ -45,6 +45,7 @@
 import com.google.android.car.kitchensink.alertdialog.AlertDialogTestFragment;
 import com.google.android.car.kitchensink.assistant.CarAssistantFragment;
 import com.google.android.car.kitchensink.audio.AudioTestFragment;
+import com.google.android.car.kitchensink.audio.CarAudioInputTestFragment;
 import com.google.android.car.kitchensink.bluetooth.BluetoothHeadsetFragment;
 import com.google.android.car.kitchensink.bluetooth.MapMceTestFragment;
 import com.google.android.car.kitchensink.carboard.KeyboardTestFragment;
@@ -52,25 +53,29 @@
 import com.google.android.car.kitchensink.connectivity.ConnectivityFragment;
 import com.google.android.car.kitchensink.cube.CubesTestFragment;
 import com.google.android.car.kitchensink.diagnostic.DiagnosticTestFragment;
-import com.google.android.car.kitchensink.dialer.DialerTestFragment;
 import com.google.android.car.kitchensink.displayinfo.DisplayInfoFragment;
+import com.google.android.car.kitchensink.experimental.ExperimentalFeatureTestFragment;
 import com.google.android.car.kitchensink.hvac.HvacTestFragment;
-import com.google.android.car.kitchensink.input.InputTestFragment;
 import com.google.android.car.kitchensink.notification.NotificationFragment;
 import com.google.android.car.kitchensink.orientation.OrientationTestFragment;
+import com.google.android.car.kitchensink.packageinfo.PackageInfoFragment;
 import com.google.android.car.kitchensink.power.PowerTestFragment;
 import com.google.android.car.kitchensink.projection.ProjectionFragment;
 import com.google.android.car.kitchensink.property.PropertyTestFragment;
 import com.google.android.car.kitchensink.sensor.SensorsTestFragment;
 import com.google.android.car.kitchensink.storagelifetime.StorageLifetimeFragment;
 import com.google.android.car.kitchensink.storagevolumes.StorageVolumesFragment;
+import com.google.android.car.kitchensink.systemfeatures.SystemFeaturesFragment;
 import com.google.android.car.kitchensink.touch.TouchTestFragment;
+import com.google.android.car.kitchensink.users.ProfileUserFragment;
 import com.google.android.car.kitchensink.users.UsersFragment;
+import com.google.android.car.kitchensink.vehiclectrl.VehicleCtrlFragment;
 import com.google.android.car.kitchensink.vhal.VehicleHalFragment;
 import com.google.android.car.kitchensink.volume.VolumeTestFragment;
 import com.google.android.car.kitchensink.weblinks.WebLinksTestFragment;
 
 import java.util.Arrays;
+import java.util.Comparator;
 import java.util.List;
 
 public class KitchenSinkActivity extends FragmentActivity {
@@ -163,32 +168,37 @@
             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("Audio Input", CarAudioInputTestFragment.class),
+            new FragmentMenuEntry("BT headset", BluetoothHeadsetFragment.class),
+            new FragmentMenuEntry("BT messaging", MapMceTestFragment.class),
             new FragmentMenuEntry("carapi", CarApiTestFragment.class),
             new FragmentMenuEntry("carboard", KeyboardTestFragment.class),
             new FragmentMenuEntry("connectivity", ConnectivityFragment.class),
             new FragmentMenuEntry("cubes test", CubesTestFragment.class),
             new FragmentMenuEntry("diagnostic", DiagnosticTestFragment.class),
-            new FragmentMenuEntry("dialer incallservice", DialerTestFragment.class),
             new FragmentMenuEntry("display info", DisplayInfoFragment.class),
+            new FragmentMenuEntry("experimental feature", ExperimentalFeatureTestFragment.class),
             new FragmentMenuEntry("hvac", HvacTestFragment.class),
             new FragmentMenuEntry("inst cluster", InstrumentClusterFragment.class),
-            new FragmentMenuEntry("input test", InputTestFragment.class),
+            // TODO (b/141774865) Enable after b/141635607 is fixed
+            // new FragmentMenuEntry("input test", InputTestFragment.class),
             new FragmentMenuEntry("notification", NotificationFragment.class),
             new FragmentMenuEntry("orientation test", OrientationTestFragment.class),
+            new FragmentMenuEntry("package info", PackageInfoFragment.class),
             new FragmentMenuEntry("power test", PowerTestFragment.class),
+            new FragmentMenuEntry("profile_user", ProfileUserFragment.class),
             new FragmentMenuEntry("projection", ProjectionFragment.class),
             new FragmentMenuEntry("property test", PropertyTestFragment.class),
             new FragmentMenuEntry("sensors", SensorsTestFragment.class),
             new FragmentMenuEntry("storage lifetime", StorageLifetimeFragment.class),
             new FragmentMenuEntry("storage volumes", StorageVolumesFragment.class),
+            new FragmentMenuEntry("system features", SystemFeaturesFragment.class),
             new FragmentMenuEntry("touch test", TouchTestFragment.class),
             new FragmentMenuEntry("users", UsersFragment.class),
-            new FragmentMenuEntry("volume test", VolumeTestFragment.class),
+            new FragmentMenuEntry("vehicle ctrl", VehicleCtrlFragment.class),
             new FragmentMenuEntry("vehicle hal", VehicleHalFragment.class),
-            new FragmentMenuEntry("web links", WebLinksTestFragment.class)
-    );
+            new FragmentMenuEntry("volume test", VolumeTestFragment.class),
+            new FragmentMenuEntry("web links", WebLinksTestFragment.class));
 
     private Car mCarApi;
     private CarHvacManager mHvacManager;
@@ -199,6 +209,10 @@
     private CarProjectionManager mCarProjectionManager;
     private Object mPropertyManagerReady = new Object();
 
+    public KitchenSinkActivity() {
+        mMenuEntries.sort(Comparator.comparing(MenuEntry::getText));
+    }
+
     public CarHvacManager getHvacManager() {
         return mHvacManager;
     }
@@ -223,13 +237,31 @@
      * adb shell am force-stop com.google.android.car.kitchensink
      * adb shell am start -n com.google.android.car.kitchensink/.KitchenSinkActivity \
      *     --es "select" "connectivity"
+     *
+     * Test car watchdog:
+     * adb shell am force-stop com.google.android.car.kitchensink
+     * adb shell am start -n com.google.android.car.kitchensink/.KitchenSinkActivity \
+     *     --es "watchdog" "[timeout] [not_respond_after] [inactive_main_after] [verbose]"
+     * - timeout: critical | moderate | normal
+     * - not_respond_after: after the given seconds, the client will not respond to car watchdog
+     *                      (-1 for making the client respond always)
+     * - inactive_main_after: after the given seconds, the main thread will not be responsive
+     *                        (-1 for making the main thread responsive always)
+     * - verbose: whether to output verbose logs (default: false)
      */
     @Override
     protected void onNewIntent(Intent intent) {
         super.onNewIntent(intent);
         Log.i(TAG, "onNewIntent");
         Bundle extras = intent.getExtras();
-        String select = (extras == null) ? null : extras.getString("select");
+        if (extras == null) {
+            return;
+        }
+        String watchdog = extras.getString("watchdog");
+        if (watchdog != null) {
+            CarWatchdogClient.start(getCar(), watchdog);
+        }
+        String select = extras.getString("select");
         if (select != null) {
             mMenuEntries.stream().filter(me -> select.equals(me.getText()))
                     .findAny().ifPresent(me -> me.onClick());
@@ -250,7 +282,7 @@
 
         mMenu = findViewById(R.id.menu);
         mMenu.setAdapter(new MenuAdapter(this));
-        mMenu.setLayoutManager(new GridLayoutManager(this, 3));
+        mMenu.setLayoutManager(new GridLayoutManager(this, 4));
 
         mMenuButton = findViewById(R.id.menu_button);
         mMenuButton.setOnClickListener(view -> toggleMenuVisibility());
@@ -331,11 +363,11 @@
 
     @Override
     protected void onDestroy() {
-        super.onDestroy();
         if (mCarApi != null) {
             mCarApi.disconnect();
         }
         Log.i(TAG, "onDestroy");
+        super.onDestroy();
     }
 
     private void showFragment(Fragment fragment) {
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/SimplePagerAdapter.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/SimplePagerAdapter.java
new file mode 100644
index 0000000..aedd3dd
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/SimplePagerAdapter.java
@@ -0,0 +1,59 @@
+/*
+ * 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.util.Pair;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.viewpager.widget.PagerAdapter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SimplePagerAdapter extends PagerAdapter {
+    private final List<Pair<View, String>> mPages = new ArrayList<>();
+
+    public SimplePagerAdapter(ViewGroup container) {
+        for (int i = 0; i < container.getChildCount(); i++) {
+            final View child = container.getChildAt(i);
+            final Object tag = child.getTag();
+            if (!(tag instanceof String)) continue;
+            mPages.add(new Pair<>(child, (String) tag));
+        }
+    }
+
+    @Override
+    public Object instantiateItem(ViewGroup container, int position) {
+        return mPages.get(position).first;
+    }
+
+    @Override
+    public int getCount() {
+        return mPages.size();
+    }
+
+    @Override
+    public CharSequence getPageTitle(int position) {
+        return mPages.get(position).second;
+    }
+
+    @Override
+    public boolean isViewFromObject(View view, Object object) {
+        return view == object;
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/activityview/ActivityViewTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/activityview/ActivityViewTestFragment.java
index a41427d..40c470d 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/activityview/ActivityViewTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/activityview/ActivityViewTestFragment.java
@@ -16,7 +16,7 @@
 
 package com.google.android.car.kitchensink.activityview;
 
-import android.app.ActivityView;
+import android.car.app.CarActivityView;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.os.Bundle;
@@ -36,7 +36,7 @@
  * This fragment exercises the capabilities of virtual display.
  */
 public class ActivityViewTestFragment extends Fragment {
-    private ActivityView mActivityView;
+    private CarActivityView mActivityView;
     private ViewGroup mActivityViewParent;
 
     @Override
@@ -62,7 +62,7 @@
 
     private void onLaunchActivityClicked(View v) {
         Intent intent = new Intent();
-        intent.setComponent(ComponentName.createRelative("com.android.settings", ".Settings"));
+        intent.setComponent(ComponentName.createRelative("com.android.car.settings", ".Settings"));
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         mActivityView.startActivity(intent);
     }
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/AudioPlayer.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/AudioPlayer.java
index a16160f..909c44c 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/AudioPlayer.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/AudioPlayer.java
@@ -93,6 +93,7 @@
     private final Context mContext;
     private final int mResourceId;
     private final AudioAttributes mAttrib;
+    private final AudioDeviceInfo mPreferredDeviceInfo;
 
     private final AtomicBoolean mPlaying = new AtomicBoolean(false);
 
@@ -101,15 +102,17 @@
 
     private PlayStateListener mListener;
 
+
     public AudioPlayer(Context context, int resourceId, AudioAttributes attrib) {
+        this(context, resourceId, attrib, /* deviceInfo= */ null);
+    }
+
+    public AudioPlayer(Context context, int resourceId, AudioAttributes attrib,
+            @Nullable AudioDeviceInfo preferredDeviceInfo) {
         mContext = context;
         mResourceId = resourceId;
         mAttrib = attrib;
-    }
-
-    public void start(boolean handleFocus, boolean repeat, int focusRequest) {
-        String nullDeviceAddress = null;
-        start(handleFocus, repeat, focusRequest, nullDeviceAddress);
+        mPreferredDeviceInfo = preferredDeviceInfo;
     }
 
     /**
@@ -117,10 +120,8 @@
      * @param handleFocus true to handle focus
      * @param repeat true to repeat track
      * @param focusRequest type of focus to request
-     * @param deviceAddress preferred device to attached to audio
      */
-    public void start(boolean handleFocus, boolean repeat, int focusRequest,
-            @Nullable String deviceAddress) {
+    public void start(boolean handleFocus, boolean repeat, int focusRequest) {
         mHandleFocus = handleFocus;
         mRepeat = repeat;
         mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
@@ -130,12 +131,11 @@
             // exercise the framework's focus logic when faced with a (sloppy) application which
             // might do this.
             Log.i(TAG, "Asking for focus for usage " + mAttrib.getUsage());
-            ret = mAudioManager.requestAudioFocus(mFocusListener, mAttrib,
-                    focusRequest, 0);
+            ret = mAudioManager.requestAudioFocus(mFocusListener, mAttrib, focusRequest, 0);
         }
         if (ret == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
             Log.i(TAG, "MediaPlayer got focus for usage " + mAttrib.getUsage());
-            doStart(deviceAddress);
+            doStart();
         } else {
             Log.i(TAG, "MediaPlayer denied focus for usage " + mAttrib.getUsage());
         }
@@ -147,7 +147,7 @@
         start(handleFocus, repeat, focusRequest);
     }
 
-    private void doStart(String deviceAddress) {
+    private void doStart() {
         if (mPlaying.getAndSet(true)) {
             Log.i(TAG, "already playing");
             return;
@@ -203,14 +203,10 @@
         }
 
         // Search for preferred device
-        if (deviceAddress != null) {
-            AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
-            for (AudioDeviceInfo deviceInfo : devices) {
-                if (deviceInfo.getAddress().equals(deviceAddress)) {
-                    mPlayer.setPreferredDevice(deviceInfo);
-                    break;
-                }
-            }
+        if (mPreferredDeviceInfo != null) {
+            mPlayer.setPreferredDevice(mPreferredDeviceInfo);
+            Log.d(TAG, "doStart preferred device address: " + mPreferredDeviceInfo.getAddress());
+
         }
 
         mPlayer.start();
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/AudioTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/AudioTestFragment.java
index 84b6bcf..bf5865a 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/AudioTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/AudioTestFragment.java
@@ -24,18 +24,17 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.hardware.display.DisplayManager;
 import android.media.AudioAttributes;
 import android.media.AudioDeviceInfo;
 import android.media.AudioFocusRequest;
 import android.media.AudioManager;
+import android.media.AudioManager.OnAudioFocusChangeListener;
 import android.media.HwAudioSource;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.util.Log;
-import android.view.Display;
-import android.view.DisplayAddress;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -55,24 +54,32 @@
 import com.google.android.car.kitchensink.R;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 
+import javax.annotation.concurrent.GuardedBy;
+
 public class AudioTestFragment extends Fragment {
     private static final String TAG = "CAR.AUDIO.KS";
     private static final boolean DBG = true;
 
+    // Key for communicating to hall which audio zone has been selected to play
+    private static final String AAE_PARAMETER_KEY_FOR_SELECTED_ZONE =
+            "com.android.car.emulator.selected_zone";
+
     private AudioManager mAudioManager;
     private FocusHandler mAudioFocusHandler;
     private ToggleButton mEnableMocking;
 
     private AudioPlayer mMusicPlayer;
+    @GuardedBy("mLock")
+    private AudioPlayer mMusicPlayerWithDelayedFocus;
     private AudioPlayer mMusicPlayerShort;
     private AudioPlayer mNavGuidancePlayer;
+    private AudioPlayer mPhoneAudioPlayer;
     private AudioPlayer mVrPlayer;
     private AudioPlayer mSystemPlayer;
     private AudioPlayer mWavPlayer;
-    private AudioPlayer mMusicPlayerForSelectedDisplay;
+    private AudioPlayer mMusicPlayerForSelectedDeviceAddress;
     private HwAudioSource mHwAudioSource;
     private AudioPlayer[] mAllPlayers;
 
@@ -83,28 +90,33 @@
     private CarAppFocusManager mAppFocusManager;
     private AudioAttributes mMusicAudioAttrib;
     private AudioAttributes mNavAudioAttrib;
+    private AudioAttributes mPhoneAudioAttrib;
     private AudioAttributes mVrAudioAttrib;
     private AudioAttributes mRadioAudioAttrib;
     private AudioAttributes mSystemSoundAudioAttrib;
-    private AudioAttributes mMusicAudioAttribForDisplay;
+    private AudioAttributes mMusicAudioAttribForDeviceAddress;
     private CarEmulator mCarEmulator;
     private CarAudioManager mCarAudioManager;
     private Spinner mZoneSpinner;
     ArrayAdapter<Integer> mZoneAdapter;
-    private Spinner mDisplaySpinner;
-    ArrayAdapter<Integer> mDisplayAdapter;
-    private LinearLayout mDisplayLayout;
-    private int mOldZonePosition;
+    private Spinner mDeviceAddressSpinner;
+    ArrayAdapter<CarAudioZoneDeviceInfo> mDeviceAddressAdapter;
+    private LinearLayout mDeviceAddressLayout;
 
-    private static int sDefaultExtraTestScreenPortId = 1;
+    private final Object mLock = new Object();
 
-    private final AudioManager.OnAudioFocusChangeListener mNavFocusListener = (focusChange) -> {
+    @GuardedBy("mLock")
+    private AudioFocusRequest mDelayedFocusRequest;
+    private OnAudioFocusChangeListener mMediaWithDelayedFocusListener;
+    private TextView mDelayedStatusText;
+
+    private final OnAudioFocusChangeListener mNavFocusListener = (focusChange) -> {
         Log.i(TAG, "Nav focus change:" + focusChange);
     };
-    private final AudioManager.OnAudioFocusChangeListener mVrFocusListener = (focusChange) -> {
+    private final OnAudioFocusChangeListener mVrFocusListener = (focusChange) -> {
         Log.i(TAG, "VR focus change:" + focusChange);
     };
-    private final AudioManager.OnAudioFocusChangeListener mRadioFocusListener = (focusChange) -> {
+    private final OnAudioFocusChangeListener mRadioFocusListener = (focusChange) -> {
         Log.i(TAG, "Radio focus change:" + focusChange);
     };
 
@@ -140,75 +152,12 @@
 
                     mCarAudioManager = (CarAudioManager) car.getCarManager(Car.AUDIO_SERVICE);
 
-                    //take care of zone selection
-                    int[] zoneList = mCarAudioManager.getAudioZoneIds();
-                    Integer[] zoneArray = Arrays.stream(zoneList).boxed().toArray(Integer[]::new);
-                    mZoneAdapter = new ArrayAdapter<>(mContext,
-                            android.R.layout.simple_spinner_item, zoneArray);
-                    mZoneAdapter.setDropDownViewResource(
-                            android.R.layout.simple_spinner_dropdown_item);
-                    mZoneSpinner.setAdapter(mZoneAdapter);
-                    mZoneSpinner.setEnabled(true);
+                    handleSetUpZoneSelection();
 
-                    if (mCarAudioManager.isDynamicRoutingEnabled()) {
-                        setUpDisplayPlayer();
-                    }
+                    setUpDeviceAddressPlayer();
                 });
     }
 
-    private void initializePlayers() {
-        mMusicAudioAttrib = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_MEDIA)
-            .build();
-        mNavAudioAttrib = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
-            .build();
-        mVrAudioAttrib = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_ASSISTANT)
-            .build();
-        mRadioAudioAttrib = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_MEDIA)
-            .build();
-        mSystemSoundAudioAttrib = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
-            .build();
-        // Create a display audio attribute
-        mMusicAudioAttribForDisplay = new AudioAttributes.Builder()
-                .setUsage(AudioAttributes.USAGE_MEDIA)
-                .build();
-
-
-        mMusicPlayerForSelectedDisplay = new AudioPlayer(mContext, R.raw.well_worth_the_wait,
-                mMusicAudioAttribForDisplay);
-        mMusicPlayer = new AudioPlayer(mContext, R.raw.well_worth_the_wait,
-            mMusicAudioAttrib);
-        mMusicPlayerShort = new AudioPlayer(mContext, R.raw.ring_classic_01,
-            mMusicAudioAttrib);
-        mNavGuidancePlayer = new AudioPlayer(mContext, R.raw.turnright,
-            mNavAudioAttrib);
-        mVrPlayer = new AudioPlayer(mContext, R.raw.one2six,
-            mVrAudioAttrib);
-        mSystemPlayer = new AudioPlayer(mContext, R.raw.ring_classic_01,
-            mSystemSoundAudioAttrib);
-        mWavPlayer = new AudioPlayer(mContext, R.raw.free_flight,
-            mMusicAudioAttrib);
-        final AudioDeviceInfo tuner = findTunerDevice(mContext);
-        if (tuner != null) {
-            mHwAudioSource = new HwAudioSource.Builder()
-                .setAudioAttributes(mMusicAudioAttrib)
-                .setAudioDeviceInfo(findTunerDevice(mContext))
-                .build();
-        }
-        mAllPlayers = new AudioPlayer[] {
-            mMusicPlayer,
-            mMusicPlayerShort,
-            mNavGuidancePlayer,
-            mVrPlayer,
-            mSystemPlayer,
-            mWavPlayer
-        };
-    }
-
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
         Log.i(TAG, "onCreateView");
@@ -216,12 +165,15 @@
         //Zone Spinner
         setUpZoneSpinnerView(view);
 
-        //Display layout
-        setUpDisplayLayoutView(view);
+        // Device Address layout
+        setUpDeviceAddressLayoutView(view);
 
         connectCar();
         initializePlayers();
 
+        TextView currentZoneIdTextView = view.findViewById(R.id.activity_current_zone);
+        setActivityCurrentZoneId(currentZoneIdTextView);
+
         mAudioManager = (AudioManager) mContext.getSystemService(
                 Context.AUDIO_SERVICE);
         mAudioFocusHandler = new FocusHandler(
@@ -333,29 +285,216 @@
             }
         });
 
-        // Manage buttons for audio player for displays
-        view.findViewById(R.id.button_display_media_play_start).setOnClickListener(v -> {
-            startDisplayAudio();
+        // Manage buttons for audio player for device address
+        view.findViewById(R.id.button_device_media_play_start).setOnClickListener(v -> {
+            startDeviceAudio();
         });
-        view.findViewById(R.id.button_display_media_play_once).setOnClickListener(v -> {
-            startDisplayAudio();
+        view.findViewById(R.id.button_device_media_play_once).setOnClickListener(v -> {
+            startDeviceAudio();
             // play only for 1 sec and stop
-            mHandler.postDelayed(() -> mMusicPlayerForSelectedDisplay.stop(), 1000);
+            mHandler.postDelayed(() -> mMusicPlayerForSelectedDeviceAddress.stop(), 1000);
         });
-        view.findViewById(R.id.button_display_media_play_stop)
-                .setOnClickListener(v -> mMusicPlayerForSelectedDisplay.stop());
+        view.findViewById(R.id.button_device_media_play_stop)
+                .setOnClickListener(v -> mMusicPlayerForSelectedDeviceAddress.stop());
+
+        view.findViewById(R.id.media_delayed_focus_start)
+                .setOnClickListener(v -> handleDelayedMediaStart());
+        view.findViewById(R.id.media_delayed_focus_stop)
+                .setOnClickListener(v -> handleDelayedMediaStop());
+
+        view.findViewById(R.id.phone_audio_focus_start)
+                .setOnClickListener(v -> mPhoneAudioPlayer.start(true, true,
+                        AudioManager.AUDIOFOCUS_GAIN_TRANSIENT));
+        view.findViewById(R.id.phone_audio_focus_stop)
+                .setOnClickListener(v -> mPhoneAudioPlayer.stop());
+
+        mDelayedStatusText = view.findViewById(R.id.media_delayed_player_status);
 
         return view;
     }
 
-    private void setUpDisplayLayoutView(View view) {
-        mDisplayLayout = view.findViewById(R.id.audio_display_layout);
+    @Override
+    public void onDestroyView() {
+        Log.i(TAG, "onDestroyView");
+        if (mCarEmulator != null) {
+            mCarEmulator.stop();
+        }
+        for (AudioPlayer p : mAllPlayers) {
+            p.stop();
+        }
+        handleHwAudioSourceStop();
+        if (mAudioFocusHandler != null) {
+            mAudioFocusHandler.release();
+            mAudioFocusHandler = null;
+        }
+        if (mAppFocusManager != null) {
+            mAppFocusManager.abandonAppFocus(mOwnershipCallbacks);
+        }
+        if (mCar != null && mCar.isConnected()) {
+            mCar.disconnect();
+            mCar = null;
+        }
+        super.onDestroyView();
+    }
 
-        mDisplaySpinner = view.findViewById(R.id.display_spinner);
-        mDisplaySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+    private void initializePlayers() {
+        mMusicAudioAttrib = new AudioAttributes.Builder()
+                .setUsage(AudioAttributes.USAGE_MEDIA)
+                .build();
+        mNavAudioAttrib = new AudioAttributes.Builder()
+                .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
+                .build();
+        mPhoneAudioAttrib = new AudioAttributes.Builder()
+                .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
+                .build();
+        mVrAudioAttrib = new AudioAttributes.Builder()
+                .setUsage(AudioAttributes.USAGE_ASSISTANT)
+                .build();
+        mRadioAudioAttrib = new AudioAttributes.Builder()
+                .setUsage(AudioAttributes.USAGE_MEDIA)
+                .build();
+        mSystemSoundAudioAttrib = new AudioAttributes.Builder()
+                .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+                .build();
+        // Create an audio device address audio attribute
+        mMusicAudioAttribForDeviceAddress = new AudioAttributes.Builder()
+                .setUsage(AudioAttributes.USAGE_MEDIA)
+                .build();
+
+
+        mMusicPlayerForSelectedDeviceAddress = new AudioPlayer(mContext, R.raw.well_worth_the_wait,
+                mMusicAudioAttribForDeviceAddress);
+        mMusicPlayer = new AudioPlayer(mContext, R.raw.well_worth_the_wait,
+                mMusicAudioAttrib);
+        mMusicPlayerWithDelayedFocus = new AudioPlayer(mContext, R.raw.well_worth_the_wait,
+                mMusicAudioAttrib);
+        mMusicPlayerShort = new AudioPlayer(mContext, R.raw.ring_classic_01,
+                mMusicAudioAttrib);
+        mNavGuidancePlayer = new AudioPlayer(mContext, R.raw.turnright,
+                mNavAudioAttrib);
+        mPhoneAudioPlayer = new AudioPlayer(mContext, R.raw.free_flight,
+                mPhoneAudioAttrib);
+        mVrPlayer = new AudioPlayer(mContext, R.raw.one2six,
+                mVrAudioAttrib);
+        mSystemPlayer = new AudioPlayer(mContext, R.raw.ring_classic_01,
+                mSystemSoundAudioAttrib);
+        mWavPlayer = new AudioPlayer(mContext, R.raw.free_flight,
+                mMusicAudioAttrib);
+        final AudioDeviceInfo tuner = findTunerDevice(mContext);
+        if (tuner != null) {
+            mHwAudioSource = new HwAudioSource.Builder()
+                    .setAudioAttributes(mMusicAudioAttrib)
+                    .setAudioDeviceInfo(findTunerDevice(mContext))
+                    .build();
+        }
+        mAllPlayers = new AudioPlayer[] {
+                mMusicPlayer,
+                mMusicPlayerShort,
+                mNavGuidancePlayer,
+                mVrPlayer,
+                mSystemPlayer,
+                mWavPlayer,
+                mMusicPlayerWithDelayedFocus
+        };
+    }
+
+    private void setActivityCurrentZoneId(TextView currentZoneIdTextView) {
+        if (mCarAudioManager.isDynamicRoutingEnabled()) {
+            try {
+                ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
+                        mContext.getPackageName(), 0);
+                int audioZoneId = mCarAudioManager.getZoneIdForUid(info.uid);
+                currentZoneIdTextView.setText(Integer.toString(audioZoneId));
+            } catch (PackageManager.NameNotFoundException e) {
+                Log.e(TAG, "setActivityCurrentZoneId Failed to find name: " , e);
+            }
+        }
+    }
+
+    private void handleDelayedMediaStart() {
+        synchronized (mLock) {
+            if (mDelayedFocusRequest != null) {
+                return;
+            }
+            mMediaWithDelayedFocusListener = new MediaWithDelayedFocusListener();
+            mDelayedFocusRequest = new AudioFocusRequest
+                    .Builder(AudioManager.AUDIOFOCUS_GAIN)
+                    .setAudioAttributes(mMusicAudioAttrib)
+                    .setOnAudioFocusChangeListener(mMediaWithDelayedFocusListener)
+                    .setForceDucking(false)
+                    .setWillPauseWhenDucked(false)
+                    .setAcceptsDelayedFocusGain(true)
+                    .build();
+            int delayedFocusRequestResults = mAudioManager.requestAudioFocus(mDelayedFocusRequest);
+            if (delayedFocusRequestResults == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+                startDelayedMediaPlayerLocked();
+                return;
+            }
+            if (delayedFocusRequestResults == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
+                if (DBG) Log.d(TAG, "Media With Delayed Focus delayed focus granted");
+                mDelayedStatusText.setText(R.string.player_delayed);
+                return;
+            }
+            mMediaWithDelayedFocusListener = null;
+            mDelayedFocusRequest = null;
+            mDelayedStatusText.setText(R.string.player_not_started);
+        }
+        if (DBG) Log.d(TAG, "Media With Delayed Focus focus rejected");
+    }
+
+    private void startDelayedMediaPlayerLocked() {
+        if (!mMusicPlayerWithDelayedFocus.isPlaying()) {
+            if (DBG) Log.d(TAG, "Media With Delayed Focus starting player");
+            mMusicPlayerWithDelayedFocus.start(false, true,
+                    AudioManager.AUDIOFOCUS_GAIN);
+            mDelayedStatusText.setText(R.string.player_started);
+            return;
+        }
+        if (DBG) Log.d(TAG, "Media With Delayed Focus player already started");
+    }
+
+    private void handleDelayedMediaStop() {
+        synchronized (mLock) {
+            if (mDelayedFocusRequest != null)  {
+                int requestResults = mAudioManager.abandonAudioFocusRequest(mDelayedFocusRequest);
+                if (DBG) {
+                    Log.d(TAG, "Media With Delayed Focus abandon focus " + requestResults);
+                }
+                mDelayedFocusRequest = null;
+                mMediaWithDelayedFocusListener = null;
+                stopDelayedMediaPlayerLocked();
+            }
+        }
+    }
+
+    private void stopDelayedMediaPlayerLocked() {
+        mDelayedStatusText.setText(R.string.player_not_started);
+        if (mMusicPlayerWithDelayedFocus.isPlaying()) {
+            if (DBG) Log.d(TAG, "Media With Delayed Focus stopping player");
+            mMusicPlayerWithDelayedFocus.stop();
+            return;
+        }
+        if (DBG) Log.d(TAG, "Media With Delayed Focus already stopped");
+    }
+
+    private void pauseDelayedMediaPlayerLocked() {
+        mDelayedStatusText.setText(R.string.player_paused);
+        if (mMusicPlayerWithDelayedFocus.isPlaying()) {
+            if (DBG) Log.d(TAG, "Media With Delayed Focus pausing player");
+            mMusicPlayerWithDelayedFocus.stop();
+            return;
+        }
+        if (DBG) Log.d(TAG, "Media With Delayed Focus already stopped");
+    }
+
+    private void setUpDeviceAddressLayoutView(View view) {
+        mDeviceAddressLayout = view.findViewById(R.id.audio_select_device_address_layout);
+
+        mDeviceAddressSpinner = view.findViewById(R.id.device_address_spinner);
+        mDeviceAddressSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
             @Override
             public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
-                handleDisplaySelection();
+                handleDeviceAddressSelection();
             }
 
             @Override
@@ -383,42 +522,25 @@
         int position = mZoneSpinner.getSelectedItemPosition();
         int zone = mZoneAdapter.getItem(position);
         Log.d(TAG, "Zone Selected: " + zone);
-        try {
-            ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
-                    mContext.getPackageName(), 0);
-            int uid = info.uid;
-            Log.d(TAG, "handleZoneSelection App uid: " + uid);
-            if (mCarAudioManager.setZoneIdForUid(zone, uid)) {
-                Log.d(TAG, "Changed uid " + uid + " sound to zone " + zone);
-                mOldZonePosition = position;
-            } else {
-                Log.d(TAG, "Filed to changed uid " + uid + " sound to zone " + zone);
-                mZoneSpinner.setSelection(mOldZonePosition);
-            }
-
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.e(TAG, "handleZoneSelection Failed to find name: " , e);
+        if (Build.IS_EMULATOR && zone != CarAudioManager.PRIMARY_AUDIO_ZONE) {
+            setZoneToPlayOnSpeaker(zone);
         }
     }
 
-    @Override
-    public void onDestroyView() {
-        super.onDestroyView();
-        Log.i(TAG, "onDestroyView");
-        if (mCarEmulator != null) {
-            mCarEmulator.stop();
+    private void handleSetUpZoneSelection() {
+        if (!Build.IS_EMULATOR || !mCarAudioManager.isDynamicRoutingEnabled()) {
+            return;
         }
-        for (AudioPlayer p : mAllPlayers) {
-            p.stop();
-        }
-        handleHwAudioSourceStop();
-        if (mAudioFocusHandler != null) {
-            mAudioFocusHandler.release();
-            mAudioFocusHandler = null;
-        }
-        if (mAppFocusManager != null) {
-            mAppFocusManager.abandonAppFocus(mOwnershipCallbacks);
-        }
+        //take care of zone selection
+        List<Integer> zoneList = mCarAudioManager.getAudioZoneIds();
+        Integer[] zoneArray = zoneList.stream()
+                .filter(i -> i != CarAudioManager.PRIMARY_AUDIO_ZONE).toArray(Integer[]::new);
+        mZoneAdapter = new ArrayAdapter<>(mContext,
+                android.R.layout.simple_spinner_item, zoneArray);
+        mZoneAdapter.setDropDownViewResource(
+                android.R.layout.simple_spinner_dropdown_item);
+        mZoneSpinner.setAdapter(mZoneAdapter);
+        mZoneSpinner.setEnabled(true);
     }
 
     private void handleNavStart() {
@@ -513,81 +635,81 @@
         mAudioManager.abandonAudioFocus(mRadioFocusListener, mRadioAudioAttrib);
     }
 
-    private void setUpDisplayPlayer() {
-        DisplayManager displayManager =  (DisplayManager) mContext.getSystemService(
-                Context.DISPLAY_SERVICE);
-        Display[] displays = displayManager.getDisplays();
-        List<Integer> displayList = new ArrayList<>();
-        for (Display display : displays) {
-            DisplayAddress.Physical physical = (DisplayAddress.Physical) display.getAddress();
-            if (physical != null) {
-                displayList.add((int) physical.getPort());
-                Log.d(TAG, "Found Display Port " + physical.getPort());
-            } else {
-                Log.d(TAG, "Found Display with no physical " + display.getDisplayId());
-            }
+    private void setUpDeviceAddressPlayer() {
+        if (!mCarAudioManager.isDynamicRoutingEnabled()) {
+            mDeviceAddressLayout.setVisibility(View.GONE);
+            return;
         }
-        // If only one display is available add another display for testing
-        if (displayList.size() == 1) {
-            displayList.add(sDefaultExtraTestScreenPortId);
+        mDeviceAddressLayout.setVisibility(View.VISIBLE);
+        List<CarAudioZoneDeviceInfo> deviceList = new ArrayList<>();
+        for (int audioZoneId: mCarAudioManager.getAudioZoneIds()) {
+            AudioDeviceInfo deviceInfo = mCarAudioManager
+                    .getOutputDeviceForUsage(audioZoneId, AudioAttributes.USAGE_MEDIA);
+            CarAudioZoneDeviceInfo carAudioZoneDeviceInfo = new CarAudioZoneDeviceInfo();
+            carAudioZoneDeviceInfo.mDeviceInfo = deviceInfo;
+            carAudioZoneDeviceInfo.mAudioZoneId = audioZoneId;
+            deviceList.add(carAudioZoneDeviceInfo);
+            if (DBG) {
+                Log.d(TAG, "Found device address"
+                        + carAudioZoneDeviceInfo.mDeviceInfo.getAddress()
+                        + " for audio zone id " + audioZoneId);
+            }
+
         }
 
-        //take care of display selection
-        Integer[] displayArray = displayList.stream().toArray(Integer[]::new);
-        mDisplayAdapter = new ArrayAdapter<>(mContext,
-                android.R.layout.simple_spinner_item, displayArray);
-        mDisplayAdapter.setDropDownViewResource(
+        CarAudioZoneDeviceInfo[] deviceArray =
+                deviceList.stream().toArray(CarAudioZoneDeviceInfo[]::new);
+        mDeviceAddressAdapter = new ArrayAdapter<>(mContext,
+                android.R.layout.simple_spinner_item, deviceArray);
+        mDeviceAddressAdapter.setDropDownViewResource(
                 android.R.layout.simple_spinner_dropdown_item);
-        mDisplaySpinner.setAdapter(mDisplayAdapter);
-        createDisplayAudioPlayer();
+        mDeviceAddressSpinner.setAdapter(mDeviceAddressAdapter);
+        createDeviceAddressAudioPlayer();
     }
 
-    private void createDisplayAudioPlayer() {
-        byte selectedDisplayPortId = mDisplayAdapter.getItem(
-                mDisplaySpinner.getSelectedItemPosition()).byteValue();
-        int zoneIdForDisplayId = mCarAudioManager.getZoneIdForDisplayPortId(selectedDisplayPortId);
-        Log.d(TAG, "Setting Bundle to zone " + zoneIdForDisplayId);
+    private void createDeviceAddressAudioPlayer() {
+        CarAudioZoneDeviceInfo carAudioZoneDeviceInfo = mDeviceAddressAdapter.getItem(
+                mDeviceAddressSpinner.getSelectedItemPosition());
+        Log.d(TAG, "Setting Bundle to zone " + carAudioZoneDeviceInfo.mAudioZoneId);
         Bundle bundle = new Bundle();
         bundle.putInt(CarAudioManager.AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID,
-                zoneIdForDisplayId);
-        mMusicAudioAttribForDisplay = new AudioAttributes.Builder()
+                carAudioZoneDeviceInfo.mAudioZoneId);
+        mMusicAudioAttribForDeviceAddress = new AudioAttributes.Builder()
                 .setUsage(AudioAttributes.USAGE_MEDIA)
                 .addBundle(bundle)
                 .build();
 
-        mMusicPlayerForSelectedDisplay = new AudioPlayer(mContext,
+        mMusicPlayerForSelectedDeviceAddress = new AudioPlayer(mContext,
                 R.raw.well_worth_the_wait,
-                mMusicAudioAttribForDisplay);
-
-        mDisplayLayout.findViewById(R.id.audio_display_layout)
-                .setVisibility(View.VISIBLE);
+                mMusicAudioAttribForDeviceAddress,
+                carAudioZoneDeviceInfo.mDeviceInfo);
     }
 
-    private void startDisplayAudio() {
-        byte selectedDisplayPortId = mDisplayAdapter.getItem(
-                mDisplaySpinner.getSelectedItemPosition()).byteValue();
-        int zoneIdForDisplayId = mCarAudioManager.getZoneIdForDisplayPortId(selectedDisplayPortId);
-        Log.d(TAG, "Starting display audio in zone " + zoneIdForDisplayId);
-        // Direct audio to the correct source
-        // TODO: Figure out a way to facilitate this for the user
-        // Currently there is no way of distinguishing apps from the same package to different zones
-        // One suggested way would be to create a unique id for each focus requester that is also
-        // share with the audio router
-        if (zoneIdForDisplayId == CarAudioManager.PRIMARY_AUDIO_ZONE) {
-            mMusicPlayerForSelectedDisplay.start(true, false,
-                    AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
-        } else {
-            // Route everything else to rear seat
-            mMusicPlayerForSelectedDisplay.start(true, false,
-                    AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, "bus100_rear_seat");
-        }
+    private void startDeviceAudio() {
+        Log.d(TAG, "Starting device address audio");
+        mMusicPlayerForSelectedDeviceAddress.start(true, false,
+                AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
     }
 
-    public void handleDisplaySelection() {
-        if (mMusicPlayerForSelectedDisplay != null && mMusicPlayerForSelectedDisplay.isPlaying()) {
-            mMusicPlayerForSelectedDisplay.stop();
+    public void handleDeviceAddressSelection() {
+        if (mMusicPlayerForSelectedDeviceAddress != null
+                && mMusicPlayerForSelectedDeviceAddress.isPlaying()) {
+            mMusicPlayerForSelectedDeviceAddress.stop();
         }
-        createDisplayAudioPlayer();
+        createDeviceAddressAudioPlayer();
+    }
+
+    /**
+     * Sets the left speaker to output sound from zoneId
+     * @param zoneId zone id to set left speakers output
+     * @Note this should only be used with emulator where the zones are separated into right
+     * and left speaker, other platforms would have real devices where audio is routed.
+     */
+    private void setZoneToPlayOnSpeaker(int zoneId) {
+        String selectedZoneKeyValueString = AAE_PARAMETER_KEY_FOR_SELECTED_ZONE + "=" + zoneId;
+        // send key value  parameter list to audio HAL
+        mAudioManager.setParameters(selectedZoneKeyValueString);
+        Log.d(TAG, "setZoneToPlayOnSpeaker : " + zoneId);
     }
 
 
@@ -649,8 +771,12 @@
             if (DBG) {
                 Log.i(TAG, "abandonAudioFocus");
             }
-            mAudioManager.abandonAudioFocusRequest(mFocusRequest);
-            mFocusRequest = null;
+            if (mFocusRequest != null) {
+                mAudioManager.abandonAudioFocusRequest(mFocusRequest);
+                mFocusRequest = null;
+            } else {
+                Log.i(TAG, "mFocusRequest is already null");
+            }
             setFocusText(AUDIO_FOCUS_STATE_RELEASED_UNKNOWN);
         }
 
@@ -658,7 +784,7 @@
             mText.setText("focus state:" + msg);
         }
 
-        private class AudioFocusListener implements AudioManager.OnAudioFocusChangeListener {
+        private class AudioFocusListener implements OnAudioFocusChangeListener {
             @Override
             public void onAudioFocusChange(int focusChange) {
                 Log.i(TAG, "onAudioFocusChange " + focusChange);
@@ -674,4 +800,46 @@
             }
         }
     }
+
+    private final class MediaWithDelayedFocusListener implements OnAudioFocusChangeListener {
+        @Override
+        public void onAudioFocusChange(int focusChange) {
+            if (DBG) Log.d(TAG, "Media With Delayed Focus focus change:" + focusChange);
+            synchronized (mLock) {
+                switch (focusChange) {
+                    case AudioManager.AUDIOFOCUS_GAIN:
+                    case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
+                    case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
+                    case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
+                        startDelayedMediaPlayerLocked();
+                        break;
+                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+                        pauseDelayedMediaPlayerLocked();
+                        break;
+                    case AudioManager.AUDIOFOCUS_LOSS:
+                    default:
+                        stopDelayedMediaPlayerLocked();
+                        mDelayedFocusRequest = null;
+                        mMediaWithDelayedFocusListener = null;
+                        break;
+                }
+            }
+        }
+    }
+
+    private class CarAudioZoneDeviceInfo {
+        AudioDeviceInfo mDeviceInfo;
+        int mAudioZoneId;
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            builder.append("Device Address : ");
+            builder.append(mDeviceInfo.getAddress());
+            builder.append(", Audio Zone Id: ");
+            builder.append(mAudioZoneId);
+            return builder.toString();
+        }
+    }
 }
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioInputAdapter.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioInputAdapter.java
new file mode 100644
index 0000000..fd680fd
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioInputAdapter.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.car.kitchensink.audio;
+
+import android.content.Context;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.google.android.car.kitchensink.R;
+
+public final class CarAudioInputAdapter
+        extends ArrayAdapter<CarAudioZoneInputFragment.CarAudioAudioInputInfo> {
+
+    private static final String TAG = "AUDIO.INPUT."
+            + CarAudioInputAdapter.class.getSimpleName();
+    private static final boolean DEBUG = true;
+    private final Context mContext;
+    private CarAudioZoneInputFragment.CarAudioAudioInputInfo[] mAudioDeviceInfos;
+    private final int mLayoutResourceId;
+    private CarAudioZoneInputFragment mFragment;
+
+    public CarAudioInputAdapter(Context context,
+            int layoutResourceId, CarAudioZoneInputFragment.CarAudioAudioInputInfo[]
+            carInputDevicesInfos, CarAudioZoneInputFragment fragment) {
+        super(context, layoutResourceId, carInputDevicesInfos);
+        mFragment = fragment;
+        mContext = context;
+        mLayoutResourceId = layoutResourceId;
+        mAudioDeviceInfos = carInputDevicesInfos;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        if (DEBUG) {
+            Log.d(TAG, "getView position " + position);
+        }
+        ViewHolder vh = new ViewHolder();
+        if (convertView == null) {
+            LayoutInflater inflater = LayoutInflater.from(mContext);
+            convertView = inflater.inflate(mLayoutResourceId, parent, false);
+            vh.mDeviceAddress = convertView.findViewById(R.id.input_device_address);
+            vh.mPlayButton = convertView.findViewById(R.id.play_audio_input);
+            vh.mStopButton = convertView.findViewById(R.id.stop_audio_input);
+            vh.mPlayerState = convertView.findViewById(R.id.input_device_state);
+            convertView.setTag(vh);
+        } else {
+            vh = (ViewHolder) convertView.getTag();
+        }
+        if (mAudioDeviceInfos[position] != null) {
+            String deviceAddress = mAudioDeviceInfos[position].mDeviceAddress;
+            vh.mDeviceAddress.setText(deviceAddress);
+            if (position == 0) {
+                vh.mPlayButton.setVisibility(View.INVISIBLE);
+                vh.mStopButton.setVisibility(View.INVISIBLE);
+                vh.mPlayerState.setVisibility(View.INVISIBLE);
+            } else {
+                vh.mPlayButton.setVisibility(View.VISIBLE);
+                vh.mPlayButton.setOnClickListener((View v) -> playAudio(mAudioDeviceInfos[position]
+                        .mDeviceAddress));
+                vh.mStopButton.setVisibility(View.VISIBLE);
+                vh.mStopButton.setOnClickListener((View v) -> stopAudio(mAudioDeviceInfos[position]
+                        .mDeviceAddress));
+                vh.mPlayerState.setVisibility(View.VISIBLE);
+                vh.mPlayerState.setText(getPlayerStateStringResource(mAudioDeviceInfos[position]
+                        .mPlayerState));
+            }
+        }
+        return convertView;
+    }
+
+    private void playAudio(String deviceAddress) {
+        mFragment.playAudio(deviceAddress);
+    }
+
+    private void stopAudio(String deviceAddress) {
+        mFragment.stopAudio(deviceAddress);
+    }
+
+    private int getPlayerStateStringResource(int state) {
+        switch (state) {
+            case CarAudioZoneInputFragment.PLAYING_STATE:
+                return R.string.player_started;
+            case CarAudioZoneInputFragment.PAUSED_STATE:
+                return R.string.player_paused;
+            case CarAudioZoneInputFragment.DELAYED_STATE:
+                return R.string.player_delayed;
+            case CarAudioZoneInputFragment.STOPPED_STATE:
+            default:
+                return R.string.player_stopped;
+        }
+    }
+
+    @Override
+    public int getCount() {
+        return mAudioDeviceInfos.length;
+    }
+
+    public void refreshAudioInputs(CarAudioZoneInputFragment.CarAudioAudioInputInfo[]
+            carInputDevicesInfos) {
+        mAudioDeviceInfos = carInputDevicesInfos;
+    }
+
+    private static final class ViewHolder {
+        public TextView mDeviceAddress;
+        public Button mPlayButton;
+        public Button mStopButton;
+        public TextView mPlayerState;
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioInputTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioInputTestFragment.java
new file mode 100644
index 0000000..0382cf6
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioInputTestFragment.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.car.kitchensink.audio;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.car.Car;
+import android.car.media.CarAudioManager;
+import android.content.Context;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.fragment.app.Fragment;
+import androidx.viewpager.widget.ViewPager;
+
+import com.google.android.car.kitchensink.R;
+import com.google.android.material.tabs.TabLayout;
+
+import java.util.List;
+
+public class CarAudioInputTestFragment extends Fragment {
+    private static final String TAG = "CAR.AUDIO.INPUT.KS";
+    private static final boolean DEBUG = true;
+
+
+    private Handler mHandler;
+    private Context mContext;
+
+    private Car mCar;
+    private AudioManager mAudioManager;
+    private CarAudioManager mCarAudioManager;
+    private TabLayout mZonesTabLayout;
+    private CarAudioZoneInputTabAdapter mInputAudioZoneAdapter;
+    private ViewPager mViewPager;
+
+    private void connectCar() {
+        mContext = getContext();
+        mHandler = new Handler(Looper.getMainLooper());
+        mCar = Car.createCar(mContext, /* handler= */ null,
+                Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, mCarServiceLifecycleListener);
+    }
+
+    private Car.CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> {
+        if (!ready) {
+            if (DEBUG) {
+                Log.d(TAG, "Disconnect from Car Service");
+            }
+            return;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "Connected to Car Service");
+        }
+        mCarAudioManager = (CarAudioManager) car.getCarManager(Car.AUDIO_SERVICE);
+
+        mAudioManager = mContext.getSystemService(AudioManager.class);
+    };
+
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
+        Log.i(TAG, "onCreateView");
+        View view = inflater.inflate(R.layout.audio_input, container, false);
+        connectCar();
+        return view;
+    }
+
+    @Override
+    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+        Log.i(TAG, "onViewCreated ");
+        mZonesTabLayout = view.findViewById(R.id.zones_input_tab);
+        mViewPager = (ViewPager) view.findViewById(R.id.zones_input_view_pager);
+
+        mInputAudioZoneAdapter = new CarAudioZoneInputTabAdapter(getChildFragmentManager());
+        mViewPager.setAdapter(mInputAudioZoneAdapter);
+        initInputInfo();
+        mZonesTabLayout.setupWithViewPager(mViewPager);
+    }
+
+    @Override
+    public void onDestroyView() {
+        Log.i(TAG, "onDestroyView");
+
+        if (mCar != null && mCar.isConnected()) {
+            mCar.disconnect();
+            mCar = null;
+        }
+        super.onDestroyView();
+    }
+
+    private void initInputInfo() {
+        if (!mCarAudioManager.isDynamicRoutingEnabled()) {
+            return;
+        }
+        List<Integer> audioZoneList = mCarAudioManager.getAudioZoneIds();
+        for (int audioZoneId : audioZoneList) {
+            if (mCarAudioManager.getInputDevicesForZoneId(audioZoneId).isEmpty()) {
+                if (DEBUG) {
+                    Log.d(TAG, "Audio Zone " + audioZoneId + " has no input devices");
+                }
+                continue;
+            }
+            addAudioZoneInputDevices(audioZoneId);
+        }
+        mInputAudioZoneAdapter.notifyDataSetChanged();
+    }
+
+    private void addAudioZoneInputDevices(int audioZoneId) {
+        String title = "Audio Zone " + audioZoneId;
+        if (DEBUG) {
+            Log.d(TAG, title + " adding devices");
+        }
+        CarAudioZoneInputFragment fragment = new CarAudioZoneInputFragment(audioZoneId,
+                mCarAudioManager, mAudioManager);
+
+        mZonesTabLayout.addTab(mZonesTabLayout.newTab().setText(title));
+        mInputAudioZoneAdapter.addFragment(fragment, title);
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioZoneInputFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioZoneInputFragment.java
new file mode 100644
index 0000000..9f2910f
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioZoneInputFragment.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.car.kitchensink.audio;
+
+import android.car.media.CarAudioManager;
+import android.car.media.CarAudioPatchHandle;
+import android.media.AudioAttributes;
+import android.media.AudioDeviceInfo;
+import android.media.AudioFocusRequest;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ListView;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+
+import com.google.android.car.kitchensink.R;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import javax.annotation.concurrent.GuardedBy;
+
+public final class CarAudioZoneInputFragment extends Fragment {
+    private static final String TAG = "CAR.AUDIO.INPUT."
+            + CarAudioZoneInputFragment.class.getSimpleName();
+    private static final boolean DEBUG = true;
+
+    static final int PLAYING_STATE = 0;
+    static final int PAUSED_STATE = 1;
+    static final int STOPPED_STATE = 2;
+    static final int DELAYED_STATE = 3;
+
+    private final Object mLock = new Object();
+    private final int mAudioZoneId;
+    private final CarAudioManager mCarAudioManager;
+    private final AudioManager mAudioManager;
+    @GuardedBy("mLock")
+    private final Map<String, CarAudioAudioInputInfo> mAudioDeviceInfoMap = new HashMap<>();
+    @GuardedBy("mLock")
+    private String mActiveInputAddress;
+    @GuardedBy("mLock")
+    private CarAudioPatchHandle mAudioPatch;
+    @GuardedBy("mLock")
+    private AudioFocusRequest mAudioFocusRequest;
+    @GuardedBy("mLock")
+    private InputAudioFocusListener mAudioFocusListener;
+
+    private CarAudioInputAdapter mCarAudioInputAdapter;
+    private CarAudioAudioInputInfo[] mCarInputDevicesInfos = new CarAudioAudioInputInfo[0];
+    private final AudioAttributes mAudioAttributes;
+
+    public CarAudioZoneInputFragment(int audioZoneId, CarAudioManager carAudioManager,
+            AudioManager audioManager) {
+        mAudioZoneId = audioZoneId;
+        mCarAudioManager = carAudioManager;
+        mAudioManager = audioManager;
+        mAudioAttributes = new AudioAttributes.Builder()
+                .setUsage(AudioAttributes.USAGE_MEDIA)
+                .build();
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        if (DEBUG) {
+            Log.d(TAG, "onCreateView " + mAudioZoneId);
+        }
+        View view = inflater.inflate(R.layout.zone_input_tab, container, false);
+        ListView audiInputListView = view.findViewById(R.id.input_list);
+        mCarAudioInputAdapter =
+                new CarAudioInputAdapter(getContext(), R.layout.audio_input_item,
+                        mCarInputDevicesInfos, this);
+        initAudioInputInfo(mAudioZoneId);
+        audiInputListView.setAdapter(mCarAudioInputAdapter);
+        return view;
+    }
+
+    @Override
+    public void onDestroyView() {
+        synchronized (mLock) {
+            if (mActiveInputAddress != null) {
+                stopAudio(mActiveInputAddress);
+            }
+        }
+        super.onDestroyView();
+    }
+
+    void initAudioInputInfo(int audioZoneId) {
+        List<AudioDeviceInfo> inputDevices =
+                mCarAudioManager.getInputDevicesForZoneId(audioZoneId);
+        mCarInputDevicesInfos = new CarAudioAudioInputInfo[inputDevices.size() + 1];
+        CarAudioAudioInputInfo titlesInfo = new CarAudioAudioInputInfo();
+        titlesInfo.mDeviceAddress = "Device Address";
+        titlesInfo.mPlayerState = STOPPED_STATE;
+        mCarInputDevicesInfos[0] = titlesInfo;
+
+        synchronized (mLock) {
+            for (int index = 0; index < inputDevices.size(); index++) {
+                AudioDeviceInfo info = inputDevices.get(index);
+                CarAudioAudioInputInfo audioInput = new CarAudioAudioInputInfo();
+                audioInput.mCarAudioZone = mAudioZoneId;
+                audioInput.mDeviceAddress = info.getAddress();
+                audioInput.mPlayerState = STOPPED_STATE;
+                mCarInputDevicesInfos[index + 1] = audioInput;
+
+                if (DEBUG) {
+                    Log.d(TAG, audioInput.toString());
+                }
+                mAudioDeviceInfoMap.put(info.getAddress(), audioInput);
+            }
+        }
+        mCarAudioInputAdapter.refreshAudioInputs(mCarInputDevicesInfos);
+    }
+
+    public void playAudio(@NonNull String deviceAddress) {
+        Objects.requireNonNull(deviceAddress);
+        synchronized (mLock) {
+            if (deviceAddress.equals(mActiveInputAddress)) {
+                if (DEBUG) {
+                    Log.d(TAG, "Audio already playing");
+                }
+                return;
+            }
+            if (mActiveInputAddress != null) {
+                mAudioManager.abandonAudioFocusRequest(mAudioFocusRequest);
+                stopAudioLocked();
+            }
+
+            mAudioFocusListener = new InputAudioFocusListener();
+            mAudioFocusRequest = new AudioFocusRequest
+                    .Builder(AudioManager.AUDIOFOCUS_GAIN)
+                    .setAudioAttributes(mAudioAttributes)
+                    .setOnAudioFocusChangeListener(mAudioFocusListener)
+                    .setForceDucking(false)
+                    .setWillPauseWhenDucked(false)
+                    .setAcceptsDelayedFocusGain(true)
+                    .build();
+
+            int audioFocusRequestResults = mAudioManager.requestAudioFocus(mAudioFocusRequest);
+            if (audioFocusRequestResults == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+                mActiveInputAddress = deviceAddress;
+                startAudioLocked();
+                return;
+            } else if (audioFocusRequestResults == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
+                // Keep the device but will start the audio once we get the focus gain
+                mActiveInputAddress = deviceAddress;
+                mAudioDeviceInfoMap.get(deviceAddress).mPlayerState = DELAYED_STATE;
+                mCarAudioInputAdapter.notifyDataSetChanged();
+                return;
+            }
+
+            // Focus was rejected
+            mAudioFocusRequest = null;
+            mAudioFocusListener = null;
+        }
+        mCarAudioInputAdapter.notifyDataSetChanged();
+    }
+
+    public void stopAudio(@NonNull String deviceAddress) {
+        Objects.requireNonNull(deviceAddress);
+        synchronized (mLock) {
+            if (deviceAddress.equals(mActiveInputAddress)) {
+                mAudioManager.abandonAudioFocusRequest(mAudioFocusRequest);
+                stopAudioLocked();
+            }
+        }
+    }
+
+    private void startAudioLocked() {
+        if (mAudioPatch != null) {
+            if (DEBUG) {
+                Log.d(TAG, "Audio already playing");
+            }
+            return;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "Starting audio input " + mActiveInputAddress);
+        }
+        mAudioPatch = mCarAudioManager.createAudioPatch(mActiveInputAddress,
+                AudioAttributes.USAGE_MEDIA, 0);
+        mAudioDeviceInfoMap.get(mActiveInputAddress).mPlayerState = PLAYING_STATE;
+        mCarAudioInputAdapter.notifyDataSetChanged();
+    }
+
+    private void pauseAudioLocked() {
+        if (mAudioPatch == null) {
+            if (DEBUG) {
+                Log.d(TAG, "Audio already paused");
+            }
+            return;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "Pausing audio input " + mActiveInputAddress);
+        }
+        mCarAudioManager.releaseAudioPatch(mAudioPatch);
+        mAudioPatch = null;
+        mAudioDeviceInfoMap.get(mActiveInputAddress).mPlayerState = PAUSED_STATE;
+        mCarAudioInputAdapter.notifyDataSetChanged();
+    }
+
+    private void stopAudioLocked() {
+        if (mAudioPatch == null) {
+            if (DEBUG) {
+                Log.d(TAG, "Audio already stopped");
+            }
+            return;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "Stopping audio input " + mActiveInputAddress);
+        }
+        mCarAudioManager.releaseAudioPatch(mAudioPatch);
+        mAudioDeviceInfoMap.get(mActiveInputAddress).mPlayerState = STOPPED_STATE;
+        mAudioPatch = null;
+        mAudioFocusRequest = null;
+        mAudioFocusListener = null;
+        mActiveInputAddress = null;
+
+        mCarAudioInputAdapter.notifyDataSetChanged();
+    }
+
+    private final class InputAudioFocusListener implements AudioManager.OnAudioFocusChangeListener {
+
+        @Override
+        public void onAudioFocusChange(int focusChange) {
+            if (DEBUG) {
+                Log.d(TAG, "InputAudioFocusListener focus change:" + focusChange);
+            }
+            synchronized (mLock) {
+                switch (focusChange) {
+                    case AudioManager.AUDIOFOCUS_GAIN:
+                    case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
+                    case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
+                    case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
+                        startAudioLocked();
+                        break;
+                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+                        pauseAudioLocked();
+                        break;
+                    case AudioManager.AUDIOFOCUS_LOSS:
+                    default:
+                        stopAudioLocked();
+                        break;
+                }
+            }
+        }
+    }
+
+    public static class CarAudioAudioInputInfo {
+        public int mCarAudioZone;
+        public String mDeviceAddress;
+        public int mPlayerState;
+
+        @Override
+        public String toString() {
+            return "Device address " + mDeviceAddress + ", Audio zone id " + mCarAudioZone;
+        }
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioZoneInputTabAdapter.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioZoneInputTabAdapter.java
new file mode 100644
index 0000000..65ec312
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioZoneInputTabAdapter.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.car.kitchensink.audio;
+
+import android.os.Parcelable;
+
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentStatePagerAdapter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class CarAudioZoneInputTabAdapter extends FragmentStatePagerAdapter {
+
+    private static final String TAG = "CAR.AUDIO.INPUT."
+            + CarAudioZoneInputTabAdapter.class.getSimpleName();
+    private final List<Fragment> mFragmentList = new ArrayList<>();
+    private final List<String> mFragmentTitleList = new ArrayList<>();
+    CarAudioZoneInputTabAdapter(FragmentManager fm) {
+        super(fm);
+    }
+
+    @Override
+    public Fragment getItem(int position) {
+        return mFragmentList.get(position);
+    }
+
+    public void addFragment(Fragment fragment, String title) {
+        mFragmentList.add(fragment);
+        mFragmentTitleList.add(title);
+    }
+
+    @Nullable
+    @Override
+    public CharSequence getPageTitle(int position) {
+        return mFragmentTitleList.get(position);
+    }
+
+    @Override
+    public int getCount() {
+        return mFragmentList.size();
+    }
+
+    @Override
+    public Parcelable saveState() {
+        return null;
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/MapMceTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/MapMceTestFragment.java
index 68d1c73..d73f6e3 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/MapMceTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/MapMceTestFragment.java
@@ -50,12 +50,53 @@
 import com.google.android.car.kitchensink.R;
 
 import java.util.Date;
+import java.util.HashSet;
 import java.util.List;
 
 @TargetApi(Build.VERSION_CODES.LOLLIPOP)
 public class MapMceTestFragment extends Fragment {
-    static final String MESSAGE_TO_SEND = "Im Busy Driving";
-    static final String NEW_MESSAGE_TO_SEND = "This is new msg";
+    static final String REPLY_MESSAGE_TO_SEND = "I am currently driving.";
+    static final String NEW_MESSAGE_TO_SEND_SHORT = "This is a new message.";
+    static final String NEW_MESSAGE_TO_SEND_LONG = "Lorem ipsum dolor sit amet, consectetur "
+            + "adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna "
+            + "aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi "
+            + "ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in "
+            + "voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
+            + "occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim "
+            + "id est laborum.\n\nCurabitur pretium tincidunt lacus. Nulla gravida orci a odio. "
+            + "Nullam varius, turpis et commodo pharetra, est eros bibendum elit, nec luctus "
+            + "magna felis sollicitudin mauris. Integer in mauris eu nibh euismod gravida. Duis "
+            + "ac tellus et risus vulputate vehicula. Donec lobortis risus a elit. Etiam tempor. "
+            + "Ut ullamcorper, ligula eu tempor congue, eros est euismod turpis, id tincidunt "
+            + "sapien risus a quam. Maecenas fermentum consequat mi. Donec fermentum. "
+            + "Pellentesque malesuada nulla a mi. Duis sapien sem, aliquet nec, commodo eget, "
+            + "consequat quis, neque. Aliquam faucibus, elit ut dictum aliquet, felis nisl "
+            + "adipiscing sapien, sed malesuada diam lacus eget erat. Cras mollis scelerisque "
+            + "nunc. Nullam arcu. Aliquam consequat. Curabitur augue lorem, dapibus quis, "
+            + "laoreet et, pretium ac, nisi. Aenean magna nisl, mollis quis, molestie eu, "
+            + "feugiat in, orci. In hac habitasse platea dictumst.\n\nLorem ipsum dolor sit "
+            + "amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et "
+            + "dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco "
+            + "laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
+            + "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. "
+            + "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia "
+            + "deserunt mollit anim id est laborum.\n\nCurabitur pretium tincidunt lacus. Nulla "
+            + "gravida orci a odio. Nullam varius, turpis et commodo pharetra, est eros bibendum "
+            + "elit, nec luctus magna felis sollicitudin mauris. Integer in mauris eu nibh "
+            + "euismod gravida. Duis ac tellus et risus vulputate vehicula. Donec lobortis risus "
+            + "a elit. Etiam tempor. Ut ullamcorper, ligula eu tempor congue, eros est euismod "
+            + "turpis, id tincidunt sapien risus a quam. Maecenas fermentum consequat mi. Donec "
+            + "fermentum. Pellentesque malesuada nulla a mi. Duis sapien sem, aliquet nec, "
+            + "commodo eget, consequat quis, neque. Aliquam faucibus, elit ut dictum aliquet, "
+            + "felis nisl adipiscing sapien, sed malesuada diam lacus eget erat. Cras mollis "
+            + "scelerisque nunc. Nullam arcu. Aliquam consequat. Curabitur augue lorem, dapibus "
+            + "quis, laoreet et, pretium ac, nisi. Aenean magna nisl, mollis quis, molestie eu, "
+            + "feugiat in, orci. In hac habitasse platea dictumst.";
+    private static final int SEND_NEW_SMS_SHORT = 1;
+    private static final int SEND_NEW_SMS_LONG = 2;
+    private static final int SEND_NEW_MMS_SHORT = 3;
+    private static final int SEND_NEW_MMS_LONG = 4;
+    private int mSendNewMsgCounter = 0;
     private static final String TAG = "CAR.BLUETOOTH.KS";
     private static final int SEND_SMS_PERMISSIONS_REQUEST = 1;
     BluetoothMapClient mMapProfile;
@@ -86,7 +127,9 @@
         Button reply = (Button) v.findViewById(R.id.reply);
         Button checkMessages = (Button) v.findViewById(R.id.check_messages);
         mBluetoothDevice = (TextView) v.findViewById(R.id.bluetoothDevice);
-        Button sendNewMsg = (Button) v.findViewById(R.id.sms_new_message);
+        Button sendNewMsgShort = (Button) v.findViewById(R.id.sms_new_message);
+        Button sendNewMsgLong = (Button) v.findViewById(R.id.mms_new_message);
+        Button resetSendNewMsgCounter = (Button) v.findViewById(R.id.reset_message_counter);
         mSmsTelNum = (EditText) v.findViewById(R.id.sms_tel_num);
         mOriginator = (EditText) v.findViewById(R.id.messageOriginator);
         mOriginatorDisplayName = (TextView) v.findViewById(R.id.messageOriginatorDisplayName);
@@ -114,18 +157,29 @@
             @Override
             public void onClick(View view) {
                 sendMessage(new Uri[]{Uri.parse(mOriginator.getText().toString())},
-                        MESSAGE_TO_SEND);
+                        REPLY_MESSAGE_TO_SEND);
             }
         });
 
-        sendNewMsg.setOnClickListener(new View.OnClickListener() {
+        sendNewMsgShort.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View view) {
-                String s = mSmsTelNum.getText().toString();
-                Toast.makeText(getContext(), "sending msg to " + s, Toast.LENGTH_SHORT).show();
-                Uri.Builder builder = new Uri.Builder();
-                Uri uri = builder.appendPath(s).scheme(PhoneAccount.SCHEME_TEL).build();
-                sendMessage(new Uri[]{uri}, NEW_MESSAGE_TO_SEND);
+                sendNewMsgOnClick(SEND_NEW_SMS_SHORT);
+            }
+        });
+
+        sendNewMsgLong.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                sendNewMsgOnClick(SEND_NEW_MMS_LONG);
+            }
+        });
+
+        resetSendNewMsgCounter.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                mSendNewMsgCounter = 0;
+                Toast.makeText(getContext(), "Counter reset to zero.", Toast.LENGTH_SHORT).show();
             }
         });
 
@@ -165,7 +219,11 @@
     }
 
     void disconnectDevice(String device) {
-        mMapProfile.disconnect(mBluetoothAdapter.getRemoteDevice((device)));
+        try {
+            mMapProfile.disconnect(mBluetoothAdapter.getRemoteDevice(device));
+        } catch (IllegalArgumentException e) {
+            Log.e(TAG, "Failed to disconnect from " + device, e);
+        }
     }
 
     @Override
@@ -208,6 +266,28 @@
         }
     }
 
+    private void sendNewMsgOnClick(int msgType) {
+        String messageToSend = "";
+        switch (msgType) {
+            case SEND_NEW_SMS_SHORT:
+                messageToSend = NEW_MESSAGE_TO_SEND_SHORT;
+                break;
+            case SEND_NEW_MMS_LONG:
+                messageToSend = NEW_MESSAGE_TO_SEND_LONG;
+                break;
+        }
+        String s = mSmsTelNum.getText().toString();
+        Toast.makeText(getContext(), "sending msg to " + s, Toast.LENGTH_SHORT).show();
+        HashSet<Uri> uris = new HashSet<Uri>();
+        Uri.Builder builder = new Uri.Builder();
+        for (String telNum : s.split(",")) {
+            uris.add(builder.path(telNum).scheme(PhoneAccount.SCHEME_TEL).build());
+        }
+        sendMessage(uris.toArray(new Uri[uris.size()]), Integer.toString(mSendNewMsgCounter)
+                + ":  " + messageToSend);
+        mSendNewMsgCounter += 1;
+    }
+
     private int getUploadingFeatureValue() {
         synchronized (mLock) {
             BluetoothDevice remoteDevice;
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/cluster/InstrumentClusterFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/cluster/InstrumentClusterFragment.java
index 8886913..ab4e2d9 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/cluster/InstrumentClusterFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/cluster/InstrumentClusterFragment.java
@@ -218,6 +218,15 @@
         super.onCreate(savedInstanceState);
     }
 
+    @Override
+    public void onDestroy() {
+        if (mCarApi != null && mCarApi.isConnected()) {
+            mCarApi.disconnect();
+            mCarApi = null;
+        }
+        super.onDestroy();
+    }
+
     /**
      * Enables/disables sending turn-by-turn data through the {@link CarNavigationStatusManager}
      */
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/connectivity/ConnectivityFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/connectivity/ConnectivityFragment.java
index 3bdfd22..7ec9f78 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/connectivity/ConnectivityFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/connectivity/ConnectivityFragment.java
@@ -47,8 +47,10 @@
 
 import androidx.fragment.app.Fragment;
 import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+import androidx.viewpager.widget.ViewPager;
 
 import com.google.android.car.kitchensink.R;
+import com.google.android.car.kitchensink.SimplePagerAdapter;
 
 import java.net.NetworkInterface;
 import java.net.SocketException;
@@ -470,6 +472,9 @@
             @Nullable Bundle savedInstanceState) {
         View view = inflater.inflate(R.layout.connectivity_fragment, container, false);
 
+        ViewPager pager = view.findViewById(R.id.connectivity_pager);
+        pager.setAdapter(new SimplePagerAdapter(pager));
+
         // Create the ListView of all networks
         ListView networksView = view.findViewById(R.id.networks);
         mNetworksAdapter = new NetworkListAdapter(getContext(), mNetworkItems, this);
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/diagnostic/DiagnosticTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/diagnostic/DiagnosticTestFragment.java
index 177d36c..99164df 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/diagnostic/DiagnosticTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/diagnostic/DiagnosticTestFragment.java
@@ -92,8 +92,15 @@
     }
 
     private void resumeDiagnosticManager() {
+        Car car = mActivity.getCar();
+        if (!car.isFeatureEnabled(Car.DIAGNOSTIC_SERVICE)) {
+            String notSupported = Car.DIAGNOSTIC_SERVICE + " not supported";
+            mLiveDiagnosticInfo.setText(notSupported);
+            mFreezeDiagnosticInfo.setText(notSupported);
+            return;
+        }
         mDiagnosticManager =
-                (CarDiagnosticManager) mActivity.getCar().getCarManager(Car.DIAGNOSTIC_SERVICE);
+                (CarDiagnosticManager) car.getCarManager(Car.DIAGNOSTIC_SERVICE);
         if (mLiveListener != null) {
             mDiagnosticManager.registerListener(mLiveListener,
                     CarDiagnosticManager.FRAME_TYPE_LIVE,
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/dialer/DialerTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/dialer/DialerTestFragment.java
deleted file mode 100644
index 8443c8a..0000000
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/dialer/DialerTestFragment.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.android.car.kitchensink.dialer;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.telecom.TelecomManager;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-
-import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-
-import com.android.internal.telecom.IInCallService;
-
-import com.google.android.car.kitchensink.R;
-
-/**
- * Test CarDialerApp and InCallService implementations
- */
-public class DialerTestFragment extends Fragment {
-    private static final String TAG = "DialerTestFragment";
-    private IInCallService mService;
-
-    private ServiceConnection mConnection = new ServiceConnection() {
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            Log.d(TAG, "connected");
-            mService = IInCallService.Stub.asInterface(service);
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            Log.d(TAG, "disconnected");
-            mService = null;
-        }
-    };
-
-    @Nullable
-    @Override
-    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
-            @Nullable Bundle savedInstanceState) {
-
-        View view = inflater.inflate(R.layout.dialer_test, container, false);
-
-        // OnClick: Binds kitchensink to InCallService
-        Button bindButton = view.findViewById(R.id.bind_btn);
-        bindButton.setOnClickListener((v) -> {
-            try {
-                Log.d(TAG, "bind");
-                Intent intent = new Intent("android.telecom.InCallService");
-                intent.setPackage("com.android.car.dialer");
-                getActivity().bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
-            } catch (Exception e) {
-                Log.e(TAG, e.toString());
-            }
-        });
-
-        // OnClick: Trigger InCallService#onBringToFront
-        Button bringToFrontButton = view.findViewById(R.id.bring_to_front_btn);
-        bringToFrontButton.setOnClickListener((v) -> {
-            Log.d(TAG, "bringToFront");
-            TelecomManager manager = (TelecomManager) getContext().getSystemService(
-                    Context.TELECOM_SERVICE);
-            manager.showInCallScreen(true);
-        });
-
-        return view;
-    }
-}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/displayinfo/DisplayInfoFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/displayinfo/DisplayInfoFragment.java
index e199821..f415e5b 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/displayinfo/DisplayInfoFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/displayinfo/DisplayInfoFragment.java
@@ -16,7 +16,9 @@
 package com.google.android.car.kitchensink.displayinfo;
 
 import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.content.Context;
+import android.content.pm.ConfigurationInfo;
 import android.content.res.Resources;
 import android.graphics.Point;
 import android.os.Bundle;
@@ -60,6 +62,13 @@
                 + getResources().getDisplayMetrics().DENSITY_DEFAULT);
 
         addTextView("======================================");
+
+        ActivityManager am =
+                (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
+        ConfigurationInfo ci = am.getDeviceConfigurationInfo();
+        addTextView("OpenGL ES version: " + ci.getGlEsVersion());
+
+        addTextView("======================================");
         addTextView("All size are in DP.");
         View rootView = getActivity().findViewById(android.R.id.content);
         addTextView("view size: "
@@ -111,7 +120,7 @@
 
     private void addTextView(String text) {
         TextView textView = new TextView(getContext());
-        textView.setTextAppearance(R.style.TextAppearance_Car_Body2);
+        textView.setTextAppearance(R.style.TextAppearance_CarUi_Body2);
         textView.setText(text);
         list.addView(textView);
     }
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/experimental/ExperimentalFeatureTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/experimental/ExperimentalFeatureTestFragment.java
new file mode 100644
index 0000000..9136a9d
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/experimental/ExperimentalFeatureTestFragment.java
@@ -0,0 +1,84 @@
+/*
+ * 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.experimental;
+
+import android.car.Car;
+import android.car.experimental.CarTestDemoExperimentalFeatureManager;
+import android.car.experimental.ExperimentalCar;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+import androidx.fragment.app.Fragment;
+
+import com.google.android.car.kitchensink.KitchenSinkActivity;
+import com.google.android.car.kitchensink.R;
+
+public class ExperimentalFeatureTestFragment extends Fragment {
+
+    private static final String TAG = "ExperimentalFeature";
+
+    private static final String[] PING_MSGS = {
+            "Hello, world",
+            "This is 1st experimental feature",
+    };
+
+    private int mCurrentMsgIndex = 0;
+    private TextView mPingMsgTextView;
+    private Button mPingButton;
+
+    private CarTestDemoExperimentalFeatureManager mDemoManager;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance) {
+        View view = inflater.inflate(R.layout.experimental_feature_test, container, false);
+        mPingMsgTextView = view.findViewById(R.id.experimental_ping_msg);
+        mPingButton = view.findViewById(R.id.button_experimental_ping);
+        Car car = ((KitchenSinkActivity) getHost()).getCar();
+        if (car.isFeatureEnabled(ExperimentalCar.TEST_EXPERIMENTAL_FEATURE_SERVICE)) {
+            mDemoManager = (CarTestDemoExperimentalFeatureManager) car.getCarManager(
+                    ExperimentalCar.TEST_EXPERIMENTAL_FEATURE_SERVICE);
+            mPingMsgTextView.setText("feature enabled");
+        } else {
+            Log.w(TAG, "ExperimentalCar.TEST_EXPERIMENTAL_FEATURE_SERVICE not enabled");
+            mPingButton.setActivated(false);
+            mPingMsgTextView.setText("feature disabled");
+        }
+        view.findViewById(R.id.button_experimental_ping).setOnClickListener(
+                (View v) -> {
+                    if (mDemoManager == null) {
+                        return;
+                    }
+                    String msg = pickMsg();
+                    mPingMsgTextView.setText(mDemoManager.ping(msg));
+                });
+        return view;
+    }
+
+    private String pickMsg() {
+        String msg = PING_MSGS[mCurrentMsgIndex];
+        mCurrentMsgIndex++;
+        if (mCurrentMsgIndex >= PING_MSGS.length) {
+            mCurrentMsgIndex = 0;
+        }
+        return msg;
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/notification/NotificationFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/notification/NotificationFragment.java
index a6d81c9..e14b25f 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/notification/NotificationFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/notification/NotificationFragment.java
@@ -42,6 +42,7 @@
     private NotificationManager mManager;
     private Context mContext;
     private Handler mHandler = new Handler();
+    private int mCount = 0;
     private HashMap<Integer, Runnable> mUpdateRunnables = new HashMap<>();
 
     @Override
@@ -89,12 +90,15 @@
         initImportanceMinButton(view);
 
         initOngoingButton(view);
-        initMessagingStyleButton(view);
+        initMessagingStyleButtonForDiffPerson(view);
+        initMessagingStyleButtonForSamePerson(view);
         initTestMessagesButton(view);
         initProgressButton(view);
         initNavigationButton(view);
         initMediaButton(view);
         initCallButton(view);
+        initCustomGroupSummaryButton(view);
+        initGroupWithoutSummaryButton(view);
 
         return view;
     }
@@ -238,8 +242,8 @@
         });
     }
 
-    private void initMessagingStyleButton(View view) {
-        view.findViewById(R.id.category_message_button).setOnClickListener(v -> {
+    private void initMessagingStyleButtonForDiffPerson(View view) {
+        view.findViewById(R.id.category_message_diff_person_button).setOnClickListener(v -> {
             int id = mCurrentNotificationId++;
 
             PendingIntent replyIntent = createServiceIntent(id, "reply");
@@ -307,6 +311,47 @@
         });
     }
 
+    private void initMessagingStyleButtonForSamePerson(View view) {
+        view.findViewById(R.id.category_message_same_person_button).setOnClickListener(v -> {
+            int id = mCurrentNotificationId++;
+
+            PendingIntent replyIntent = createServiceIntent(id, "reply");
+            PendingIntent markAsReadIntent = createServiceIntent(id, "read");
+
+            Person person = new Person.Builder().setName("John Doe").build();
+            MessagingStyle messagingStyle =
+                    new MessagingStyle(person).setConversationTitle("Hello!");
+            NotificationCompat.Builder builder = new NotificationCompat
+                    .Builder(mContext, IMPORTANCE_HIGH_ID)
+                    .setContentTitle("Message from someone")
+                    .setContentText("hi")
+                    .setShowWhen(true)
+                    .setCategory(Notification.CATEGORY_MESSAGE)
+                    .setSmallIcon(R.drawable.car_ic_mode)
+                    .setAutoCancel(true)
+                    .setColor(mContext.getColor(android.R.color.holo_green_light))
+                    .addAction(
+                            new Action.Builder(R.drawable.ic_check_box, "read", markAsReadIntent)
+                                    .setSemanticAction(Action.SEMANTIC_ACTION_MARK_AS_READ)
+                                    .setShowsUserInterface(false)
+                                    .build())
+                    .addAction(
+                            new Action.Builder(R.drawable.ic_check_box, "reply", replyIntent)
+                                    .setSemanticAction(Action.SEMANTIC_ACTION_REPLY)
+                                    .setShowsUserInterface(false)
+                                    .addRemoteInput(new RemoteInput.Builder("input").build())
+                                    .build());
+
+            NotificationCompat.Builder updateNotification =
+                    builder.setStyle(messagingStyle.addMessage(
+                            new MessagingStyle.Message(
+                                    "Message " + id,
+                                    System.currentTimeMillis(),
+                                    person)));
+            mManager.notify(12345, updateNotification.build());
+        });
+    }
+
     private void initTestMessagesButton(View view) {
         view.findViewById(R.id.test_message_button).setOnClickListener(v -> {
             int id = mCurrentNotificationId++;
@@ -314,7 +359,7 @@
             PendingIntent replyIntent = createServiceIntent(id, "reply");
             PendingIntent markAsReadIntent = createServiceIntent(id, "read");
 
-            Person person = new Person.Builder().setName("John Doe").build();
+            Person person = new Person.Builder().setName("John Doe " + id).build();
             MessagingStyle messagingStyle =
                     new MessagingStyle(person).setConversationTitle("Hello!");
             NotificationCompat.Builder builder = new NotificationCompat
@@ -515,4 +560,60 @@
             mManager.notify(mCurrentNotificationId++, notification);
         });
     }
+
+    private void initCustomGroupSummaryButton(View view) {
+        view.findViewById(R.id.custom_group_summary_button).setOnClickListener(v -> {
+            String groupKey = "GROUP_KEY" + mCurrentNotificationId++;
+            int delay = 500;
+
+            Notification summaryNotification = new Notification
+                    .Builder(mContext, IMPORTANCE_HIGH_ID)
+                    .setContentTitle("6 New mails")
+                    .setContentText("this is some summary")
+                    .setSmallIcon(R.drawable.thumb_up)
+                    .setLargeIcon(Icon.createWithResource(mContext, R.drawable.avatar1))
+                    .setGroup(groupKey)
+                    .setGroupSummary(true)
+                    .setStyle(new Notification.InboxStyle()
+                            .addLine("line 1")
+                            .addLine("line 2")
+                            .addLine("line 3")
+                            .addLine("line 4")
+                            .addLine("line 5")
+                            .setBigContentTitle("You've received 6 messages")
+                            .setSummaryText("From Alice, Bob, Claire, Douglas.."))
+                    .build();
+
+            mHandler.postDelayed(
+                    () -> mManager.notify(mCurrentNotificationId++, summaryNotification), delay);
+            for (int i = 1; i <= 6; i++) {
+                Notification notification = new Notification
+                        .Builder(mContext, IMPORTANCE_HIGH_ID)
+                        .setContentTitle("Group child " + i)
+                        .setSmallIcon(R.drawable.car_ic_mode)
+                        .setGroup(groupKey)
+                        .setSortKey(Integer.toString(6 - i))
+                        .build();
+                mHandler.postDelayed(() -> mManager.notify(mCurrentNotificationId++, notification),
+                        delay += 5000);
+            }
+        });
+    }
+
+    private void initGroupWithoutSummaryButton(View view) {
+        view.findViewById(R.id.group_without_summary_button).setOnClickListener(v -> {
+            String groupKey = "GROUP_KEY" + mCurrentNotificationId++;
+
+            for (int i = 1; i <= 6; i++) {
+                Notification notification = new Notification
+                        .Builder(mContext, IMPORTANCE_DEFAULT_ID)
+                        .setContentTitle("This notification should not group " + i)
+                        .setSmallIcon(R.drawable.car_ic_mode)
+                        .setGroup(groupKey)
+                        .setSortKey(Integer.toString(i))
+                        .build();
+                mHandler.post(() -> mManager.notify(mCurrentNotificationId++, notification));
+            }
+        });
+    }
 }
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/packageinfo/PackageInfoFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/packageinfo/PackageInfoFragment.java
new file mode 100644
index 0000000..039cc8c
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/packageinfo/PackageInfoFragment.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.car.kitchensink.packageinfo;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import androidx.fragment.app.Fragment;
+
+import com.google.android.car.kitchensink.R;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Test fragment to check packages installed for each user
+ * <p>
+ * Options to apply conditions to filter out packages, if package
+ * <ul>
+ * <li>only have activities.
+ * <li>have service but not exported or for single user.
+ * <li>does not require any key permission
+ * (INTERACT_ACROSS_USERS, INTERACT_ACROSS_USERS_FULL, WRITE_DEVICE_CONFIG).
+ * <li>does not have sharedUserId or shardUserId is not system uid.
+ * </ul>
+ */
+public final class PackageInfoFragment extends Fragment{
+    private static final String TAG = "PackageInfoTest";
+    private static final boolean DEBUG = true;
+    private static final int PACKAGE_FLAGS = PackageManager.GET_META_DATA
+            | PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES
+            | PackageManager.GET_PROVIDERS | PackageManager.GET_RECEIVERS
+            | PackageManager.GET_PERMISSIONS | PackageManager.GET_SIGNATURES;
+    private static final List<String> IMPORTANT_PERMISSIONS = Arrays.asList(
+            "android.permission.INTERACT_ACROSS_USERS",
+            "android.permission.INTERACT_ACROSS_USERS_FULL",
+            "android.permission.WRITE_DEVICE_CONFIG");
+    private static final String SYSTEM_UID = "android.uid.system";
+
+    private final List<PackageInfo> mPackagesToDisableForSystemUser = new ArrayList<>();
+
+    private UserManager mUserManager;
+    private PackageManager mPackageManager;
+    private UserInfo mUserToShow;
+    private int mShowFlags;
+    private TextView mPackageView;
+    private boolean mFilterActivities;
+    private boolean mFilterServices;
+    private boolean mFilterPermissions;
+    private boolean mFilterSharedUid;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
+        mPackageManager = getActivity().getPackageManager();
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance) {
+        View view = inflater.inflate(R.layout.package_info_test, container, false);
+        setListener(view);
+
+        return view;
+    }
+
+    private void refreshPackages() {
+        List<PackageInfo> packages = new ArrayList<PackageInfo>();
+        try {
+            packages = mPackageManager.getInstalledPackagesAsUser(PACKAGE_FLAGS, mUserToShow.id);
+            if (DEBUG) {
+                Log.d(TAG, "total packages found: " + packages.size());
+            }
+        } catch (Exception e) {
+            if (DEBUG) {
+                Log.e(TAG, "failed to get packages for given user: " + mUserToShow);
+            }
+            mPackageView.setText("Cannot retrieve packages for this user..");
+            return;
+        }
+
+        mPackagesToDisableForSystemUser.clear();
+
+        for (PackageInfo packageInfo : packages) {
+            Log.d(TAG, "checking package: " + packageInfo);
+            boolean toBlacklist = true;
+            // check share user id, show package does not have sharedUserId or not system uid
+            if (mFilterSharedUid) {
+                if (DEBUG) {
+                    Log.d(TAG, "sharedUid flagged: " + (packageInfo.sharedUserId == null
+                                || !packageInfo.sharedUserId.equals(SYSTEM_UID)));
+                }
+
+                toBlacklist &= (packageInfo.sharedUserId == null
+                        || !packageInfo.sharedUserId.equals(SYSTEM_UID));
+            }
+
+            // check permissions, show package does not require selected permissions
+            if (mFilterPermissions && packageInfo.requestedPermissions != null) {
+                if (DEBUG) {
+                    for (String info : Arrays.asList(packageInfo.requestedPermissions)) {
+                        Log.d(TAG, info + " flagged: " + (!IMPORTANT_PERMISSIONS.contains(info)));
+                    }
+                }
+
+                toBlacklist &= !(Arrays.asList(packageInfo.requestedPermissions).stream().anyMatch(
+                        info -> IMPORTANT_PERMISSIONS.contains(info)));
+            }
+            // check services, w/o service or service not exported and w/o single user flag
+            if (mFilterServices && packageInfo.services != null) {
+                if (DEBUG) {
+                    for (ServiceInfo info : Arrays.asList(packageInfo.services)) {
+                        Log.d(TAG, info + " flagged: " + (!info.exported
+                                && (info.flags & ServiceInfo.FLAG_SINGLE_USER) == 0));
+                    }
+                }
+
+                toBlacklist &= Arrays.asList(packageInfo.services).stream().anyMatch(info ->
+                    !info.exported && (info.flags & ServiceInfo.FLAG_SINGLE_USER) == 0);
+            }
+            // check activities
+            if (mFilterActivities) {
+                if (DEBUG) {
+                    Log.d(TAG, packageInfo + " contain activities only, flagged: " + (
+                            packageInfo.activities != null
+                            && packageInfo.services == null
+                            && packageInfo.providers == null));
+                }
+                toBlacklist &= (packageInfo.activities != null
+                    && packageInfo.services == null && packageInfo.providers == null);
+            }
+
+            if (toBlacklist) {
+                mPackagesToDisableForSystemUser.add(packageInfo);
+            }
+        }
+    }
+
+    private void showPackagesOnView(TextView tv) {
+        refreshPackages();
+
+        tv.setText(mPackagesToDisableForSystemUser.size() + " Packages found ...\n");
+
+        for (PackageInfo info : mPackagesToDisableForSystemUser) {
+            tv.append(info.packageName.toString() + "\n");
+        }
+    }
+
+    private void setListener(View v) {
+        List<UserInfo> users = mUserManager.getUsers();
+        mUserToShow = users.get(0);
+        Spinner spinner = v.findViewById(R.id.spinner);
+        ArrayAdapter<UserInfo> userArrayAdapter = new ArrayAdapter<UserInfo>(
+                    getContext(), android.R.layout.simple_spinner_item, users);
+        userArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        spinner.setAdapter(userArrayAdapter);
+        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+            @Override
+            public void onItemSelected(AdapterView<?> parent, View currentView,
+                    int position, long id) {
+                mUserToShow = (UserInfo) parent.getItemAtPosition(position);
+            }
+            @Override
+            public void onNothingSelected(AdapterView<?> parent) {
+            }
+        });
+
+        CheckBox activities = v.findViewById(R.id.checkbox_activities);
+        CheckBox services = v.findViewById(R.id.checkbox_services);
+        CheckBox permissions = v.findViewById(R.id.checkbox_permissions);
+        CheckBox shareduid = v.findViewById(R.id.checkbox_shareduid);
+        Button showButton = v.findViewById(R.id.button_show);
+        TextView packageView = v.findViewById(R.id.packages);
+
+        activities.setOnClickListener(view -> mFilterActivities = ((CheckBox) view).isChecked());
+        services.setOnClickListener(view -> mFilterServices = ((CheckBox) view).isChecked());
+        permissions.setOnClickListener(view -> mFilterPermissions = ((CheckBox) view).isChecked());
+        shareduid.setOnClickListener(view -> mFilterSharedUid = ((CheckBox) view).isChecked());
+        showButton.setOnClickListener(view -> showPackagesOnView(packageView));
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/LocationListeners.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/LocationListeners.java
index 0129085..0c4e5a6 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/LocationListeners.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/LocationListeners.java
@@ -27,6 +27,9 @@
 import android.os.Bundle;
 import android.util.Log;
 
+import java.util.ArrayList;
+import java.util.function.Consumer;
+
 
 public class LocationListeners {
 
@@ -37,7 +40,81 @@
     LocationManager mLocationMgr;
     SensorManager   mSensorMgr;
 
-    Sensor mAccelerometerSensor, mMagneticFieldSensor, mGyroscopeSensor;
+    private class SensorHelper implements SensorEventListener {
+        private static final String TAG = "CAR.SENSOR.KS";
+        private static final String LOC_SENSOR_FORMAT = "%12.8f, %12.8f, %12.8f";
+
+        private final SensorManager mSensorMgr;
+        private final int mSensorType;
+        private final String mSensorUnits;
+        private final String mSensorName;
+        private final Sensor mSensor;
+        private final Consumer<String> mUpdate;
+
+        SensorHelper(SensorManager mgr, int type, String unit,
+                String name, Consumer<String> update) {
+            mSensorMgr = mgr;
+            mSensorType = type;
+            mSensorUnits = unit;
+            mSensorName = name;
+            mSensor = (mSensorMgr != null) ? mSensorMgr.getDefaultSensor(type) : null;
+            mUpdate = update;
+
+            if (mSensor == null) {
+                Log.w(TAG, "sensor " + mSensorName + " is not available");
+            } else {
+                Log.d(TAG, "sensor " + mSensorName + " is available");
+            }
+        }
+
+        void startListening() {
+            if (mSensorMgr == null) {
+                mUpdate.accept(mSensorName + ": SensorManager not available");
+                return;
+            }
+
+            if (mSensor == null) {
+                mUpdate.accept(mSensorName + ": sensor not available");
+                return;
+            }
+            if (!mSensorMgr.registerListener(this, mSensor,
+                    SensorManager.SENSOR_DELAY_FASTEST)) {
+                mUpdate.accept(mSensorName + ": failed to register listener.");
+                Log.w(TAG, "sensor " + mSensorName + " cannot be listened to");
+            } else {
+                mUpdate.accept(mSensorName + ": waiting to hear from SensorManager.");
+                Log.d(TAG, "sensor " + mSensorName + " is being listened to");
+            }
+        }
+
+        void stopListening() {
+            if (mSensor != null) {
+                mSensorMgr.unregisterListener(this);
+                mUpdate.accept(mSensorName + ": SensorManager stopped");
+                Log.d(TAG, "sensor " + mSensorName + " is not being listened to anymore");
+            }
+        }
+
+        @Override
+        public void onSensorChanged(SensorEvent event) {
+            if (event.sensor.getType() != mSensorType) {
+                Log.w(TAG, "unexpected event: " + event);
+                return;
+            }
+
+            final String es = String.format("%s %s: (" + LOC_SENSOR_FORMAT + ")",
+                    mSensorName, mSensorUnits,
+                    event.values[0], event.values[1], event.values[2]);
+
+            mUpdate.accept(es);
+        }
+
+        @Override
+        public void onAccuracyChanged(Sensor sensor, int accuracy) {
+        }
+    }
+
+    ArrayList<SensorHelper> mSensors = new ArrayList<>();
 
     public LocationListeners(Context context,
                              SensorsTestFragment.LocationInfoTextUpdateListener listener) {
@@ -46,9 +123,12 @@
         mLocationMgr = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
         mSensorMgr = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
 
-        mAccelerometerSensor = mSensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
-        mMagneticFieldSensor = mSensorMgr.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
-        mGyroscopeSensor = mSensorMgr.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
+        mSensors.add(new SensorHelper(mSensorMgr, Sensor.TYPE_ACCELEROMETER,
+                "m/s2", "Accelerometer", mTextUpdateHandler::setAccelField));
+        mSensors.add(new SensorHelper(mSensorMgr, Sensor.TYPE_MAGNETIC_FIELD,
+                "uT", "Magnetometer", mTextUpdateHandler::setMagField));
+        mSensors.add(new SensorHelper(mSensorMgr, Sensor.TYPE_GYROSCOPE,
+                "Rad/s", "Gyroscope", mTextUpdateHandler::setGyroField));
     }
 
     public void startListening() {
@@ -64,53 +144,7 @@
             mTextUpdateHandler.setLocationField("LocationManager not available");
         }
 
-        if (mSensorMgr != null) {
-            // Accelerometer.
-            if (mAccelerometerSensor != null) {
-                if (!mSensorMgr.registerListener(mSensorListener, mAccelerometerSensor,
-                        SensorManager.SENSOR_DELAY_FASTEST)) {
-                    mTextUpdateHandler.setAccelField(
-                            "Accelerometer: failed to register listener.");
-                } else {
-                    mTextUpdateHandler.setAccelField(
-                            "Accelerometer: waiting to hear from SensorManager");
-                }
-            } else {
-                mTextUpdateHandler.setAccelField("Accelerometer: sensor not available.");
-            }
-
-            // Gyroscope.
-            if (mGyroscopeSensor != null) {
-                if (!mSensorMgr.registerListener(mSensorListener, mGyroscopeSensor,
-                        SensorManager.SENSOR_DELAY_FASTEST)) {
-                    mTextUpdateHandler.setGyroField(
-                            "Gyroscope: failed to register listener.");
-                } else {
-                    mTextUpdateHandler.setGyroField(
-                            "Gyroscope: waiting to hear from SensorManager");
-                }
-            } else {
-                mTextUpdateHandler.setGyroField("Gyroscope: sensor not available.");
-            }
-
-            // Magnetometer.
-            if (mMagneticFieldSensor != null) {
-                if (!mSensorMgr.registerListener(mSensorListener, mMagneticFieldSensor,
-                        SensorManager.SENSOR_DELAY_FASTEST)) {
-                    mTextUpdateHandler.setMagField(
-                            "Magnetometer: failed to register listener.");
-                } else {
-                    mTextUpdateHandler.setMagField(
-                            "Magnetometer: waiting to hear from SensorManager");
-                }
-            } else {
-                mTextUpdateHandler.setMagField("Magnetometer: sensor not available.");
-            }
-        } else {
-            mTextUpdateHandler.setAccelField("SensorManager not available");
-            mTextUpdateHandler.setGyroField("SensorManager not available");
-            mTextUpdateHandler.setMagField("SensorManager not available");
-        }
+        mSensors.forEach(SensorHelper::startListening);
     }
 
     public void stopListening() {
@@ -121,12 +155,7 @@
             }
         }
 
-        if (mSensorMgr != null) {
-            mSensorMgr.unregisterListener(mSensorListener);
-            mTextUpdateHandler.setAccelField("SensorManager stopped");
-            mTextUpdateHandler.setGyroField("SensorManager stopped");
-            mTextUpdateHandler.setMagField("SensorManager stopped");
-        }
+        mSensors.forEach(SensorHelper::stopListening);
     }
 
 
@@ -157,42 +186,4 @@
         public void onStatusChanged(String provider, int status, Bundle extras) {
         }
     };
-
-    private final SensorEventListener mSensorListener = new SensorEventListener() {
-        @Override
-        public void onSensorChanged(SensorEvent event) {
-            int type = event.sensor.getType();
-            switch (type) {
-                case Sensor.TYPE_GYROSCOPE:
-                    String gs = String.format("Gyroscope Rad/s: (%6.2f, %6.2f, %6.2f)",
-                            event.values[0], event.values[1], event.values[2]);
-                    mTextUpdateHandler.setGyroField(gs);
-                    break;
-                case Sensor.TYPE_MAGNETIC_FIELD:
-                    // NOTE:  If we wanted to report yaw/pitch/roll, we would use both
-                    //        accelerometer and magnetic data to compute R and I:
-                    // SensorManager.getRotationMatrix(R, I,
-                    //                                 mLastAccelerometerData
-                    //                                 mLastMagneticFieldData);
-                    // SensorManager.getOrientation(mR, orientation);
-                    String ms = String.format("Magnetic uT: (%6.2f, %6.2f, %6.2f)",
-                            event.values[0], event.values[1], event.values[2]);
-                    mTextUpdateHandler.setMagField(ms);
-                    break;
-                case Sensor.TYPE_ACCELEROMETER:
-                    String as = String.format("Accelerometer m/s2: (%6.2f, %6.2f, %6.2f)",
-                            event.values[0], event.values[1], event.values[2]);
-                    mTextUpdateHandler.setAccelField(as);
-                    break;
-                default:
-                    Log.w(TAG, "Unexpected sensor event type: " + type);
-                    // Should never happen.
-                    return;
-            }
-        }
-
-        @Override
-        public void onAccuracyChanged(Sensor sensor, int accuracy) {
-        }
-    };
 }
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/storagelifetime/StorageLifetimeFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/storagelifetime/StorageLifetimeFragment.java
index 481820b..b76cd24 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/storagelifetime/StorageLifetimeFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/storagelifetime/StorageLifetimeFragment.java
@@ -213,13 +213,19 @@
     @Override
     public void onResume() {
         super.onResume();
+        if (!mActivity.getCar().isFeatureEnabled(Car.STORAGE_MONITORING_SERVICE)) {
+            Log.w(TAG, "STORAGE_MONITORING_SERVICE not supported");
+            return;
+        }
         reloadInfo();
         registerListener();
     }
 
     @Override
     public void onPause() {
-        unregisterListener();
+        if (mActivity.getCar().isFeatureEnabled(Car.STORAGE_MONITORING_SERVICE)) {
+            unregisterListener();
+        }
         super.onPause();
     }
 }
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/systemfeatures/SystemFeaturesFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/systemfeatures/SystemFeaturesFragment.java
new file mode 100644
index 0000000..f3d51b2
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/systemfeatures/SystemFeaturesFragment.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.car.kitchensink.systemfeatures;
+
+import android.annotation.Nullable;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+
+import com.google.android.car.kitchensink.R;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Objects;
+
+/**
+ * Shows system features as available by PackageManager
+ */
+public class SystemFeaturesFragment extends Fragment {
+    private static final String TAG = "CAR.SYSFEATURES.KS";
+
+    private ListView mSysFeaturesList;
+    private PackageManager mPackageManager;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        mPackageManager = Objects.requireNonNull(
+                getContext().getPackageManager());
+
+        super.onCreate(savedInstanceState);
+    }
+
+    @Nullable
+    @Override
+    public View onCreateView(
+            @NonNull LayoutInflater inflater,
+            @Nullable ViewGroup container,
+            @Nullable Bundle savedInstanceState) {
+        mSysFeaturesList = (ListView) inflater.inflate(R.layout.system_feature_fragment,
+                container, false);
+        return mSysFeaturesList;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        refresh();
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+    }
+
+    private void refresh() {
+        final FeatureInfo[] features = mPackageManager.getSystemAvailableFeatures();
+        if (features != null) {
+            final String[] descriptions = Arrays.stream(features)
+                .filter(fi -> fi != null && fi.name != null)
+                .sorted(Comparator.<FeatureInfo, String>comparing(fi -> fi.name)
+                                  .thenComparing(fi -> fi.version))
+                .map(fi -> String.format("%s (v=%d)", fi.name, fi.version))
+                .toArray(String[]::new);
+            mSysFeaturesList.setAdapter(new ArrayAdapter<>(getContext(),
+                    android.R.layout.simple_list_item_1, descriptions));
+        } else {
+            Log.e(TAG, "no features available on this device!");
+        }
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/touchsound/DisableTouchSoundOnBoot.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/touchsound/DisableTouchSoundOnBoot.java
deleted file mode 100644
index 2c81bda..0000000
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/touchsound/DisableTouchSoundOnBoot.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.car.kitchensink.touchsound;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.provider.Settings;
-import android.util.Log;
-
-/**
- * Temp solution until b/68882625 is fixed
- */
-public class DisableTouchSoundOnBoot extends BroadcastReceiver {
-
-    private static final String KEY_TOUCH_SOUNDS = "sound_effects_enabled";
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        Log.w("DisableTouchSoundOnBoot", "disabling touch sound");
-        Settings.System.putInt(context.getContentResolver(), KEY_TOUCH_SOUNDS, 0);
-    }
-}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/ProfileUserFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/ProfileUserFragment.java
new file mode 100644
index 0000000..8ccb5b6
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/ProfileUserFragment.java
@@ -0,0 +1,537 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.car.kitchensink.users;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.IActivityManager;
+import android.car.Car;
+import android.car.CarOccupantZoneManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.UserInfo;
+import android.graphics.Color;
+import android.hardware.display.DisplayManager;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+import android.view.Display;
+import android.view.DisplayAddress;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import androidx.fragment.app.Fragment;
+
+import com.google.android.car.kitchensink.KitchenSinkActivity;
+import com.google.android.car.kitchensink.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ProfileUserFragment extends Fragment {
+
+    private static final String TAG = ProfileUserFragment.class.getSimpleName();
+
+    private static final int ERROR_MESSAGE = 0;
+    private static final int WARN_MESSAGE = 1;
+    private static final int INFO_MESSAGE = 2;
+
+    private SpinnerWrapper mUsersSpinner;
+    private SpinnerWrapper mZonesSpinner;
+    private SpinnerWrapper mDisplaysSpinner;
+    private SpinnerWrapper mAppsSpinner;
+
+    private Button mCreateRestrictedUserButton;
+    private Button mCreateManagedUserButton;
+    private Button mRemoveUserButton;
+    private Button mStartUserButton;
+    private Button mStopUserButton;
+    private Button mAssignUserToZoneButton;
+    private Button mLaunchAppForZoneButton;
+    private Button mLaunchAppForDisplayAndUserButton;
+
+    private TextView mUserIdText;
+    private TextView mZoneInfoText;
+    private TextView mUserStateText;
+    private TextView mErrorMessageText;
+
+    private UserManager mUserManager;
+    private DisplayManager mDisplayManager;
+    private CarOccupantZoneManager mZoneManager;
+
+
+    @Nullable
+    @Override
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+            @Nullable Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.profile_user, container, false);
+    }
+
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        mUserManager = getContext().getSystemService(UserManager.class);
+        mDisplayManager = getContext().getSystemService(DisplayManager.class);
+        Car car = ((KitchenSinkActivity) getHost()).getCar();
+        mZoneManager = (CarOccupantZoneManager) car.getCarManager(Car.CAR_OCCUPANT_ZONE_SERVICE);
+
+        mUserIdText = view.findViewById(R.id.profile_textView_state);
+        mZoneInfoText = view.findViewById(R.id.profile_textView_zoneinfo);
+        mUserStateText = view.findViewById(R.id.profile_textView_userstate);
+        updateTextInfo();
+
+        mUsersSpinner = SpinnerWrapper.create(getContext(),
+                view.findViewById(R.id.profile_spinner_users), getUsers());
+        mZonesSpinner = SpinnerWrapper.create(getContext(),
+                view.findViewById(R.id.profile_spinner_zones), getZones());
+        mDisplaysSpinner = SpinnerWrapper.create(getContext(),
+                view.findViewById(R.id.profile_spinner_displays), getDisplays());
+        mAppsSpinner = SpinnerWrapper.create(getContext(),
+                view.findViewById(R.id.profile_spinner_apps), getApps());
+
+        mCreateRestrictedUserButton = view.findViewById(R.id.profile_button_create_restricted_user);
+        mCreateRestrictedUserButton.setOnClickListener(v -> {
+            createUser(/* restricted= */ true);
+        });
+        mCreateManagedUserButton = view.findViewById(R.id.profile_button_create_managed_user);
+        mCreateManagedUserButton.setOnClickListener(v -> {
+            createUser(/* restricted= */ false);
+        });
+        mRemoveUserButton = view.findViewById(R.id.profile_button_remove_user);
+        mRemoveUserButton.setOnClickListener(v -> {
+            removeUser();
+        });
+        mStartUserButton = view.findViewById(R.id.profile_button_start_user);
+        mStartUserButton.setOnClickListener(v -> {
+            startUser();
+        });
+        mStopUserButton = view.findViewById(R.id.profile_button_stop_user);
+        mStopUserButton.setOnClickListener(v -> {
+            stopUser();
+        });
+        mAssignUserToZoneButton = view.findViewById(R.id.profile_button_assign_user_to_zone);
+        mAssignUserToZoneButton.setOnClickListener(v -> {
+            assignUserToZone();
+        });
+        mLaunchAppForZoneButton = view.findViewById(R.id.profile_button_launch_app_for_zone);
+        mLaunchAppForZoneButton.setOnClickListener(v -> {
+            launchAppForZone();
+        });
+        mLaunchAppForDisplayAndUserButton = view.findViewById(
+                R.id.profile_button_launch_app_for_display);
+        mLaunchAppForDisplayAndUserButton.setOnClickListener(v -> {
+            launchAppForDisplayAndUser();
+        });
+
+        mErrorMessageText = view.findViewById(R.id.status_message_text_view);
+    }
+
+    private void updateTextInfo() {
+        int currentUserId = ActivityManager.getCurrentUser();
+        int myUserId = UserHandle.myUserId();
+        mUserIdText.setText("Current userId:" + currentUserId + " myUserId:" + myUserId);
+        StringBuilder zoneStatebuilder = new StringBuilder();
+        zoneStatebuilder.append("Zone-User-Displays:");
+        List<CarOccupantZoneManager.OccupantZoneInfo> zonelist = mZoneManager.getAllOccupantZones();
+        for (CarOccupantZoneManager.OccupantZoneInfo zone : zonelist) {
+            zoneStatebuilder.append(zone.zoneId);
+            zoneStatebuilder.append("-");
+            zoneStatebuilder.append(mZoneManager.getUserForOccupant(zone));
+            zoneStatebuilder.append("-");
+            List<Display> displays = mZoneManager.getAllDisplaysForOccupant(zone);
+            for (Display display : displays) {
+                zoneStatebuilder.append(display.getDisplayId());
+                zoneStatebuilder.append(",");
+            }
+            zoneStatebuilder.append(":");
+        }
+        mZoneInfoText.setText(zoneStatebuilder.toString());
+        StringBuilder userStateBuilder = new StringBuilder();
+        userStateBuilder.append("UserId-state;");
+        int[] profileUsers = mUserManager.getEnabledProfileIds(currentUserId);
+        for (int profileUser : profileUsers) {
+            userStateBuilder.append(profileUser);
+            userStateBuilder.append("-");
+            if (mUserManager.isUserRunning(profileUser)) {
+                userStateBuilder.append("R:");
+            } else {
+                userStateBuilder.append("S:");
+            }
+        }
+        mUserStateText.setText(userStateBuilder.toString());
+    }
+
+    private void createUser(boolean restricted) {
+        try {
+            UserInfo user;
+            if (restricted) {
+                user = mUserManager.createRestrictedProfile("RestrictedProfile");
+            } else {
+                user = mUserManager.createProfileForUser("ManagedProfile",
+                        UserManager.USER_TYPE_PROFILE_MANAGED, /* flags= */ 0,
+                        ActivityManager.getCurrentUser());
+            }
+            setMessage(INFO_MESSAGE, "Created User " + user);
+            mUsersSpinner.updateEntries(getUsers());
+            updateTextInfo();
+        } catch (Exception e) {
+            setMessage(ERROR_MESSAGE, e);
+        }
+    }
+
+    private void removeUser() {
+        int userToRemove = getSelectedUser();
+        if (userToRemove == UserHandle.USER_NULL) {
+            setMessage(INFO_MESSAGE, "Cannot remove null user");
+            return;
+        }
+        int currentUser = ActivityManager.getCurrentUser();
+        if (userToRemove == currentUser) {
+            setMessage(WARN_MESSAGE, "Cannot remove current user");
+            return;
+        }
+        Log.i(TAG, "removing user:" + userToRemove);
+        try {
+            mUserManager.removeUser(userToRemove);
+            mUsersSpinner.updateEntries(getUsers());
+            updateTextInfo();
+            setMessage(INFO_MESSAGE, "Removed user " + userToRemove);
+        } catch (Exception e) {
+            setMessage(ERROR_MESSAGE, e);
+        }
+    }
+
+    private void stopUser() {
+        int userToUpdate = getSelectedUser();
+        if (!canChangeUser(userToUpdate)) {
+            return;
+        }
+
+        if (!mUserManager.isUserRunning(userToUpdate)) {
+            setMessage(WARN_MESSAGE, "User " + userToUpdate + " is already stopped");
+            return;
+        }
+        IActivityManager am = ActivityManager.getService();
+        Log.i(TAG, "stop user:" + userToUpdate);
+        try {
+            am.stopUser(userToUpdate, /* force= */ false, /* callback= */ null);
+        } catch (RemoteException e) {
+            setMessage(WARN_MESSAGE, "Cannot stop user", e);
+            return;
+        }
+        setMessage(INFO_MESSAGE, "Stopped user " + userToUpdate);
+        updateTextInfo();
+    }
+
+    private void startUser() {
+        int userToUpdate = getSelectedUser();
+        if (!canChangeUser(userToUpdate)) {
+            return;
+        }
+
+        if (mUserManager.isUserRunning(userToUpdate)) {
+            setMessage(WARN_MESSAGE, "User " + userToUpdate + " is already running");
+            return;
+        }
+        IActivityManager am = ActivityManager.getService();
+        Log.i(TAG, "start user:" + userToUpdate);
+        try {
+            am.startUserInBackground(userToUpdate);
+        } catch (RemoteException e) {
+            setMessage(WARN_MESSAGE, "Cannot start user", e);
+            return;
+        }
+        setMessage(INFO_MESSAGE, "Started user " + userToUpdate);
+        updateTextInfo();
+    }
+
+    private boolean canChangeUser(int userToUpdate) {
+        if (userToUpdate == UserHandle.USER_NULL) {
+            return false;
+        }
+        int currentUser = ActivityManager.getCurrentUser();
+        if (userToUpdate == currentUser) {
+            setMessage(WARN_MESSAGE, "Can not change current user");
+            return false;
+        }
+        return true;
+    }
+
+    private void assignUserToZone() {
+        int userId = getSelectedUser();
+        if (userId == UserHandle.USER_NULL) {
+            return;
+        }
+        Integer zoneId = getSelectedZone();
+        if (zoneId == null) {
+            return;
+        }
+        Log.i(TAG, "assigning user:" + userId + " to zone:" + zoneId);
+        boolean assignUserToZoneResults;
+        try {
+            assignUserToZoneResults =
+                    mZoneManager.assignProfileUserToOccupantZone(getZoneInfoForId(zoneId), userId);
+        } catch (IllegalArgumentException e) {
+            setMessage(ERROR_MESSAGE, e.getMessage());
+            return;
+        }
+        if (!assignUserToZoneResults) {
+            Log.e(TAG, "Assignment failed");
+            setMessage(ERROR_MESSAGE, "Failed to assign user " + userId + " to zone "
+                    + zoneId);
+            return;
+        }
+        setMessage(INFO_MESSAGE, "Assigned user " + userId + " to zone " + zoneId);
+        updateTextInfo();
+    }
+
+    private void setMessage(int messageType, String title, Exception e) {
+        StringBuilder messageTextBuilder = new StringBuilder();
+        messageTextBuilder.append(title);
+        messageTextBuilder.append(": ");
+        messageTextBuilder.append(e.getMessage());
+        setMessage(messageType, messageTextBuilder.toString());
+    }
+
+    private void setMessage(int messageType, Exception e) {
+        setMessage(messageType, e.getMessage());
+    }
+
+    private void setMessage(int messageType, String message) {
+        int textColor;
+        switch (messageType) {
+            case ERROR_MESSAGE:
+                Log.e(TAG, message);
+                textColor = Color.RED;
+                break;
+            case WARN_MESSAGE:
+                Log.w(TAG, message);
+                textColor = Color.GREEN;
+                break;
+            case INFO_MESSAGE:
+            default:
+                Log.i(TAG, message);
+                textColor = Color.WHITE;
+        }
+        mErrorMessageText.setTextColor(textColor);
+        mErrorMessageText.setText(message);
+    }
+
+    private void launchAppForZone() {
+        Intent intent = getSelectedApp();
+        if (intent == null) {
+            return;
+        }
+        Integer zoneId = getSelectedZone();
+        if (zoneId == null) {
+            return;
+        }
+        CarOccupantZoneManager.OccupantZoneInfo zoneInfo = getZoneInfoForId(zoneId);
+        if (zoneInfo == null) {
+            Log.e(TAG, "launchAppForZone, invalid zoneId:" + zoneId);
+            return;
+        }
+        int assignedUserId = mZoneManager.getUserForOccupant(zoneInfo);
+        if (assignedUserId == UserHandle.USER_NULL) {
+            Log.e(TAG, "launchAppForZone, invalid user for zone:" + zoneId);
+            return;
+        }
+        Log.i(TAG, "Launching Intent:" + intent + " for user:" + assignedUserId);
+        getContext().startActivityAsUser(intent, UserHandle.of(assignedUserId));
+    }
+
+    private void launchAppForDisplayAndUser() {
+        Intent intent = getSelectedApp();
+        if (intent == null) {
+            return;
+        }
+        int displayId = getSelectedDisplay();
+        if (displayId == Display.INVALID_DISPLAY) {
+            return;
+        }
+        int userId = getSelectedUser();
+        if (userId == UserHandle.USER_NULL) {
+            return;
+        }
+        Log.i(TAG, "Launching Intent:" + intent + " for user:" + userId
+                + " to display:" + displayId);
+        Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
+        getContext().startActivityAsUser(intent, bundle, UserHandle.of(userId));
+    }
+
+    @Nullable
+    private CarOccupantZoneManager.OccupantZoneInfo getZoneInfoForId(int zoneId) {
+        List<CarOccupantZoneManager.OccupantZoneInfo> zonelist = mZoneManager.getAllOccupantZones();
+        for (CarOccupantZoneManager.OccupantZoneInfo zone : zonelist) {
+            if (zone.zoneId == zoneId) {
+                return zone;
+            }
+        }
+        return null;
+    }
+
+    @Nullable
+    private Intent getSelectedApp() {
+        String appStr = (String) mAppsSpinner.getSelectedEntry();
+        if (appStr == null) {
+            Log.w(TAG, "getSelectedApp, no app selected", new RuntimeException());
+            return null;
+        }
+        Intent intent = new Intent();
+        intent.setComponent(ComponentName.unflattenFromString(appStr));
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        return intent;
+    }
+
+    @Nullable
+    private Integer getSelectedZone() {
+        String zoneStr = mZonesSpinner.getSelectedEntry();
+        if (zoneStr == null) {
+            Log.w(TAG, "getSelectedZone, no zone selected", new RuntimeException());
+            return null;
+        }
+        return Integer.valueOf(zoneStr.split(",")[0]);
+    }
+
+    @Nullable
+    private int getSelectedDisplay() {
+        String displayStr = mDisplaysSpinner.getSelectedEntry();
+        if (displayStr == null) {
+            Log.w(TAG, "getSelectedDisplay, no display selected", new RuntimeException());
+            return Display.INVALID_DISPLAY;
+        }
+        return Integer.parseInt(displayStr.split(",")[0]);
+    }
+
+    private int getSelectedUser() {
+        String userStr = mUsersSpinner.getSelectedEntry();
+        if (userStr == null) {
+            Log.w(TAG, "getSelectedUser, user not selected", new RuntimeException());
+            return UserHandle.USER_NULL;
+        }
+        return Integer.parseInt(userStr.split(",")[0]);
+    }
+
+    // format: id,[CURRENT|PROFILE]
+    private ArrayList<String> getUsers() {
+        ArrayList<String> users = new ArrayList<>();
+        int currentUser = ActivityManager.getCurrentUser();
+        users.add(Integer.toString(currentUser) + ",CURRENT");
+        int[] profileUsers = mUserManager.getEnabledProfileIds(currentUser);
+        for (int profileUser : profileUsers) {
+            if (profileUser == currentUser) {
+                continue;
+            }
+            users.add(Integer.toString(profileUser) + ",PROFILE");
+        }
+        return users;
+    }
+
+    // format: displayId,[P,]?,address]
+    private ArrayList<String> getDisplays() {
+        ArrayList<String> displays = new ArrayList<>();
+        Display[] disps = mDisplayManager.getDisplays();
+        int uidSelf = Process.myUid();
+        for (Display disp : disps) {
+            if (!disp.hasAccess(uidSelf)) {
+                continue;
+            }
+            StringBuilder builder = new StringBuilder();
+            int displayId = disp.getDisplayId();
+            builder.append(displayId);
+            builder.append(",");
+            DisplayAddress address = disp.getAddress();
+            if (address instanceof  DisplayAddress.Physical) {
+                builder.append("P,");
+            }
+            builder.append(address);
+            displays.add(builder.toString());
+        }
+        return displays;
+    }
+
+    // format: zoneId,[D|F|R]
+    private ArrayList<String> getZones() {
+        ArrayList<String> zones = new ArrayList<>();
+        List<CarOccupantZoneManager.OccupantZoneInfo> zonelist = mZoneManager.getAllOccupantZones();
+        for (CarOccupantZoneManager.OccupantZoneInfo zone : zonelist) {
+            StringBuilder builder = new StringBuilder();
+            builder.append(zone.zoneId);
+            builder.append(",");
+            if (zone.occupantType == CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER) {
+                builder.append("D");
+            } else if (zone.occupantType == CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER) {
+                builder.append("F");
+            } else {
+                builder.append("R");
+            }
+            zones.add(builder.toString());
+        }
+        return zones;
+    }
+
+    private ArrayList<String> getApps() {
+        ArrayList<String> apps = new ArrayList<>();
+        apps.add("com.google.android.car.kitchensink/.KitchenSinkActivity");
+        apps.add("com.android.car.multidisplay/.launcher.LauncherActivity");
+        apps.add("com.google.android.car.multidisplaytest/.MDTest");
+        return apps;
+    }
+
+    private static class SpinnerWrapper {
+        private final Spinner mSpinner;
+        private final ArrayList<String> mEntries;
+        private final ArrayAdapter<String> mAdapter;
+
+        private static SpinnerWrapper create(Context context, Spinner spinner,
+                ArrayList<String> entries) {
+            SpinnerWrapper wrapper = new SpinnerWrapper(context, spinner, entries);
+            wrapper.init();
+            return wrapper;
+        }
+
+        private SpinnerWrapper(Context context, Spinner spinner, ArrayList<String> entries) {
+            mSpinner = spinner;
+            mEntries = new ArrayList<>(entries);
+            mAdapter = new ArrayAdapter<String>(context, android.R.layout.simple_spinner_item,
+                    mEntries);
+        }
+
+        private void init() {
+            mAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+            mSpinner.setAdapter(mAdapter);
+        }
+
+        private void updateEntries(ArrayList<String> entries) {
+            mEntries.clear();
+            mEntries.addAll(entries);
+            mAdapter.notifyDataSetChanged();
+        }
+
+        @Nullable
+        private String getSelectedEntry() {
+            return (String) mSpinner.getSelectedItem();
+        }
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/vehiclectrl/VehicleCtrlFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/vehiclectrl/VehicleCtrlFragment.java
new file mode 100644
index 0000000..0040fe2
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/vehiclectrl/VehicleCtrlFragment.java
@@ -0,0 +1,149 @@
+/*
+ * 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.vehiclectrl;
+
+import android.annotation.IdRes;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.car.VehicleAreaWindow;
+import android.car.VehiclePropertyIds;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarPropertyManager;
+import android.hardware.automotive.vehicle.V2_0.VehicleArea;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropertyGroup;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.fragment.app.Fragment;
+import androidx.viewpager.widget.ViewPager;
+
+import com.google.android.car.kitchensink.KitchenSinkActivity;
+import com.google.android.car.kitchensink.R;
+import com.google.android.car.kitchensink.SimplePagerAdapter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@SuppressLint("SetTextI18n")
+public final class VehicleCtrlFragment extends Fragment {
+    private static final String TAG = VehicleCtrlFragment.class.getSimpleName();
+
+    public static final class CustomVehicleProperty {
+        public static final int PROTOCAN_TEST = (
+                0x0ABC
+                | VehiclePropertyGroup.VENDOR
+                | VehiclePropertyType.BOOLEAN
+                | VehicleArea.GLOBAL);
+
+        private CustomVehicleProperty() {}
+    };
+
+    private CarPropertyManager mPropMgr;
+    private final Map<Integer, TextView> mWindowPosWidgets = new HashMap<>();
+
+    private final CarPropertyManager.CarPropertyEventCallback mPropCb =
+            new CarPropertyManager.CarPropertyEventCallback() {
+        @Override
+        public void onChangeEvent(CarPropertyValue value) {
+            onPropertyEvent(value);
+        }
+
+        @Override
+        public void onErrorEvent(int propId, int zone) {}
+    };
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+            @Nullable Bundle savedInstanceState) {
+        View view = inflater.inflate(R.layout.vehicle_ctrl_fragment, container, false);
+
+        ViewPager pager = view.findViewById(R.id.vehicle_ctrl_pager);
+        pager.setAdapter(new SimplePagerAdapter(pager));
+
+        KitchenSinkActivity activity = (KitchenSinkActivity) getHost();
+        mPropMgr = activity.getPropertyManager();
+
+        subscribeProps();
+
+        initWindowBtns(view, VehicleAreaWindow.WINDOW_ROW_1_LEFT,
+                R.id.winFLOpen, R.id.winFLClose, R.id.winFLPos);
+        initWindowBtns(view, VehicleAreaWindow.WINDOW_ROW_1_RIGHT,
+                R.id.winFROpen, R.id.winFRClose, R.id.winFRPos);
+        initWindowBtns(view, VehicleAreaWindow.WINDOW_ROW_2_LEFT,
+                R.id.winRLOpen, R.id.winRLClose, R.id.winRLPos);
+        initWindowBtns(view, VehicleAreaWindow.WINDOW_ROW_2_RIGHT,
+                R.id.winRROpen, R.id.winRRClose, R.id.winRRPos);
+
+        initTestBtn(view, R.id.protocan_test_on, true);
+        initTestBtn(view, R.id.protocan_test_off, false);
+
+        return view;
+    }
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        unsubscribeProps();
+    }
+
+    private void subscribeProps() {
+        mPropMgr.registerCallback(mPropCb, VehiclePropertyIds.WINDOW_POS, 10);
+    }
+
+    private void unsubscribeProps() {
+        mPropMgr.unregisterCallback(mPropCb);
+    }
+
+    public void onPropertyEvent(CarPropertyValue prop) {
+        if (prop.getPropertyId() == VehiclePropertyIds.WINDOW_POS) {
+            Log.i(TAG, "Window pos: " + prop.getValue());
+            updateWindowPos(prop.getAreaId(), (int) prop.getValue());
+        }
+    }
+
+    private void initWindowBtns(View view, int winId, @IdRes int openId, @IdRes int closeId,
+            @IdRes int posId) {
+        // TODO(twasilczyk): fetch the actual min/max values
+        view.findViewById(openId).setOnClickListener(v -> moveWindow(winId, 1));
+        view.findViewById(closeId).setOnClickListener(v -> moveWindow(winId, -1));
+        mWindowPosWidgets.put(winId, view.findViewById(posId));
+    }
+
+    private void moveWindow(int windowId, int speed) {
+        Log.i(TAG, "Moving window " + windowId + " with speed " + speed);
+        mPropMgr.setIntProperty(VehiclePropertyIds.WINDOW_MOVE, windowId, speed);
+    }
+
+    private void updateWindowPos(int windowId, int pos) {
+        TextView view = mWindowPosWidgets.get(windowId);
+        view.post(() -> view.setText(pos + "%"));
+    }
+
+    private void initTestBtn(View view, @IdRes int btnId, boolean on) {
+        view.findViewById(btnId).setOnClickListener(v -> onTestBtnClicked(on));
+    }
+
+    private void onTestBtnClicked(boolean on) {
+        Log.i(TAG, "onTestBtnClicked " + on);
+        mPropMgr.setBooleanProperty(CustomVehicleProperty.PROTOCAN_TEST, VehicleArea.GLOBAL, on);
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/vhal/VehicleHalFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/vhal/VehicleHalFragment.java
index c5998c9..59af8c1 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/vhal/VehicleHalFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/vhal/VehicleHalFragment.java
@@ -33,8 +33,8 @@
 import android.widget.Button;
 import android.widget.LinearLayout;
 import android.widget.ListView;
-
 import android.widget.TextView;
+
 import androidx.fragment.app.Fragment;
 
 import com.google.android.car.kitchensink.KitchenSinkActivity;
@@ -66,11 +66,18 @@
     public void onResume() {
         super.onResume();
 
+        final boolean retry = true;
         final IVehicle vehicle;
         try {
-            vehicle = Objects.requireNonNull(IVehicle.getService());
-        } catch (NullPointerException | RemoteException e) {
+            vehicle = Objects.requireNonNull(IVehicle.getService(retry));
+        } catch (RemoteException | RuntimeException e) {
             Log.e(TAG, "unable to retrieve Vehicle HAL service", e);
+            AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+            builder.setTitle("Vehicle HAL not available")
+                   .setPositiveButton(android.R.string.ok, (x, y) -> { })
+                   .setMessage("In some cases (e.g. SELinux enforcing mode), this UI "
+                            + "is not available for use. Please use the car property UI")
+                   .show();
             return;
         }
 
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/AudioZoneVolumeTabAdapter.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/AudioZoneVolumeTabAdapter.java
new file mode 100644
index 0000000..3e94f28
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/AudioZoneVolumeTabAdapter.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.car.kitchensink.volume;
+
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentStatePagerAdapter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class AudioZoneVolumeTabAdapter extends FragmentStatePagerAdapter {
+
+    private final List<Fragment> mFragmentList = new ArrayList<>();
+    private final List<String> mFragmentTitleList = new ArrayList<>();
+    AudioZoneVolumeTabAdapter(FragmentManager fm) {
+        super(fm);
+    }
+
+    @Override
+    public Fragment getItem(int position) {
+        return mFragmentList.get(position);
+    }
+
+    public void addFragment(Fragment fragment, String title) {
+        mFragmentList.add(fragment);
+        mFragmentTitleList.add(title);
+        notifyDataSetChanged();
+    }
+
+    @Nullable
+    @Override
+    public CharSequence getPageTitle(int position) {
+        return mFragmentTitleList.get(position);
+    }
+
+    @Override
+    public int getCount() {
+        return mFragmentList.size();
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeAdapter.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeAdapter.java
new file mode 100644
index 0000000..eb0c111
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeAdapter.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.car.kitchensink.volume;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.google.android.car.kitchensink.R;
+import com.google.android.car.kitchensink.volume.VolumeTestFragment.CarAudioZoneVolumeInfo;
+
+public final class CarAudioZoneVolumeAdapter extends ArrayAdapter<CarAudioZoneVolumeInfo> {
+
+    private final Context mContext;
+    private CarAudioZoneVolumeInfo[] mVolumeList;
+    private final int mLayoutResourceId;
+    private CarAudioZoneVolumeFragment mFragment;
+
+    public CarAudioZoneVolumeAdapter(Context context,
+            int layoutResourceId, CarAudioZoneVolumeInfo[] volumeList,
+            CarAudioZoneVolumeFragment fragment) {
+        super(context, layoutResourceId, volumeList);
+        mFragment = fragment;
+        mContext = context;
+        this.mLayoutResourceId = layoutResourceId;
+        this.mVolumeList = volumeList;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        ViewHolder vh = new ViewHolder();
+        if (convertView == null) {
+            LayoutInflater inflater = LayoutInflater.from(mContext);
+            convertView = inflater.inflate(mLayoutResourceId, parent, false);
+            vh.id = convertView.findViewById(R.id.stream_id);
+            vh.maxVolume = convertView.findViewById(R.id.volume_limit);
+            vh.currentVolume = convertView.findViewById(R.id.current_volume);
+            vh.upButton = convertView.findViewById(R.id.volume_up);
+            vh.downButton = convertView.findViewById(R.id.volume_down);
+            vh.requestButton = convertView.findViewById(R.id.request);
+            convertView.setTag(vh);
+        } else {
+            vh = (ViewHolder) convertView.getTag();
+        }
+        if (mVolumeList[position] != null) {
+            vh.id.setText(mVolumeList[position].mId);
+            vh.maxVolume.setText(String.valueOf(mVolumeList[position].mMax));
+            vh.currentVolume.setText(String.valueOf(mVolumeList[position].mCurrent));
+            int color = mVolumeList[position].mHasFocus ? Color.GREEN : Color.GRAY;
+            vh.requestButton.setBackgroundColor(color);
+            if (position == 0) {
+                vh.upButton.setVisibility(View.INVISIBLE);
+                vh.downButton.setVisibility(View.INVISIBLE);
+                vh.requestButton.setVisibility(View.INVISIBLE);
+            } else {
+                vh.upButton.setVisibility(View.VISIBLE);
+                vh.downButton.setVisibility(View.VISIBLE);
+                vh.requestButton.setVisibility(View.VISIBLE);
+                vh.upButton.setOnClickListener((view) -> {
+                    mFragment.adjustVolumeByOne(mVolumeList[position].mGroupId, true);
+                });
+                vh.downButton.setOnClickListener((view) -> {
+                    mFragment.adjustVolumeByOne(mVolumeList[position].mGroupId, false);
+                });
+
+                vh.requestButton.setOnClickListener((view) -> {
+                    mFragment.requestFocus(mVolumeList[position].mGroupId);
+                });
+            }
+        }
+        return convertView;
+    }
+
+    @Override
+    public int getCount() {
+        return mVolumeList.length;
+    }
+
+    public void refreshVolumes(CarAudioZoneVolumeInfo[] volumes) {
+        mVolumeList = volumes;
+        notifyDataSetChanged();
+    }
+
+    private static final class ViewHolder {
+        public TextView id;
+        public TextView maxVolume;
+        public TextView currentVolume;
+        public Button upButton;
+        public Button downButton;
+        public Button requestButton;
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeFragment.java
new file mode 100644
index 0000000..c1a712d
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeFragment.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.car.kitchensink.volume;
+
+import android.car.media.CarAudioManager;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.util.SparseIntArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ListView;
+
+import androidx.fragment.app.Fragment;
+
+import com.google.android.car.kitchensink.R;
+import com.google.android.car.kitchensink.volume.VolumeTestFragment.CarAudioZoneVolumeInfo;
+
+public final class CarAudioZoneVolumeFragment extends Fragment {
+    private static final String TAG = "CarVolumeTest."
+            + CarAudioZoneVolumeFragment.class.getSimpleName();
+    private static final boolean DEBUG = true;
+
+    private static final int MSG_VOLUME_CHANGED = 0;
+    private static final int MSG_REQUEST_FOCUS = 1;
+    private static final int MSG_FOCUS_CHANGED = 2;
+
+    private final int mZoneId;
+    private final CarAudioManager mCarAudioManager;
+    private final AudioManager mAudioManager;
+    private CarAudioZoneVolumeInfo[] mVolumeInfos =
+            new CarAudioZoneVolumeInfo[0];
+    private final Handler mHandler = new VolumeHandler();
+
+    private CarAudioZoneVolumeAdapter mCarAudioZoneVolumeAdapter;
+    private final SparseIntArray mGroupIdIndexMap = new SparseIntArray();
+
+    public void sendChangeMessage() {
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_VOLUME_CHANGED));
+    }
+
+    private class VolumeHandler extends Handler {
+        private AudioFocusListener mFocusListener;
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (DEBUG) {
+                Log.d(TAG, "zone " + mZoneId + " handleMessage : " + getMessageName(msg));
+            }
+            switch (msg.what) {
+                case MSG_VOLUME_CHANGED:
+                    initVolumeInfo();
+                    break;
+                case MSG_REQUEST_FOCUS:
+                    int groupId = msg.arg1;
+                    if (mFocusListener != null) {
+                        mAudioManager.abandonAudioFocus(mFocusListener);
+                        mVolumeInfos[mGroupIdIndexMap.get(groupId)].mHasFocus = false;
+                        mCarAudioZoneVolumeAdapter.notifyDataSetChanged();
+                    }
+
+                    mFocusListener = new AudioFocusListener(groupId);
+                    mAudioManager.requestAudioFocus(mFocusListener, groupId,
+                            AudioManager.AUDIOFOCUS_GAIN);
+                    break;
+                case MSG_FOCUS_CHANGED:
+                    int focusGroupId = msg.arg1;
+                    mVolumeInfos[mGroupIdIndexMap.get(focusGroupId)].mHasFocus = true;
+                    mCarAudioZoneVolumeAdapter.refreshVolumes(mVolumeInfos);
+                    break;
+                default :
+                    Log.wtf(TAG,"VolumeHandler handleMessage called with unknown message"
+                            + msg.what);
+
+            }
+        }
+    }
+
+    public CarAudioZoneVolumeFragment(int zoneId, CarAudioManager carAudioManager,
+            AudioManager audioManager) {
+        mZoneId = zoneId;
+        mCarAudioManager = carAudioManager;
+        mAudioManager = audioManager;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        if (DEBUG) {
+            Log.d(TAG, "onCreateView " + mZoneId);
+        }
+        View v = inflater.inflate(R.layout.zone_volume_tab, container, false);
+        ListView volumeListView = v.findViewById(R.id.volume_list);
+        mCarAudioZoneVolumeAdapter =
+                new CarAudioZoneVolumeAdapter(getContext(), R.layout.volume_item, mVolumeInfos,
+                        this);
+        initVolumeInfo();
+        volumeListView.setAdapter(mCarAudioZoneVolumeAdapter);
+        return v;
+    }
+
+    void initVolumeInfo() {
+        int volumeGroupCount = mCarAudioManager.getVolumeGroupCount(mZoneId);
+        mVolumeInfos = new CarAudioZoneVolumeInfo[volumeGroupCount + 1];
+        mGroupIdIndexMap.clear();
+        CarAudioZoneVolumeInfo titlesInfo = new CarAudioZoneVolumeInfo();
+        titlesInfo.mId = "Group id";
+        titlesInfo.mCurrent = "Current";
+        titlesInfo.mMax = "Max";
+        mVolumeInfos[0] = titlesInfo;
+
+        int i = 1;
+        for (int groupId = 0; groupId < volumeGroupCount; groupId++) {
+            CarAudioZoneVolumeInfo volumeInfo = new CarAudioZoneVolumeInfo();
+            mGroupIdIndexMap.put(groupId, i);
+            volumeInfo.mGroupId = groupId;
+            volumeInfo.mId = String.valueOf(groupId);
+            int current = mCarAudioManager.getGroupVolume(mZoneId, groupId);
+            int max = mCarAudioManager.getGroupMaxVolume(mZoneId, groupId);
+            volumeInfo.mCurrent = String.valueOf(current);
+            volumeInfo.mMax = String.valueOf(max);
+
+            mVolumeInfos[i] = volumeInfo;
+            if (DEBUG)
+            {
+                Log.d(TAG, groupId + " max: " + volumeInfo.mMax + " current: "
+                        + volumeInfo.mCurrent);
+            }
+            i++;
+        }
+        mCarAudioZoneVolumeAdapter.refreshVolumes(mVolumeInfos);
+    }
+
+    public void adjustVolumeByOne(int groupId, boolean up) {
+        if (mCarAudioManager == null) {
+            Log.e(TAG, "CarAudioManager is null");
+            return;
+        }
+        int current = mCarAudioManager.getGroupVolume(mZoneId, groupId);
+        int volume = current + (up ? 1 : -1);
+        mCarAudioManager.setGroupVolume(mZoneId, groupId, volume,
+                AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_PLAY_SOUND);
+        if (DEBUG) {
+            Log.d(TAG, "Set group " + groupId + " volume " + volume + " in audio zone "
+                    + mZoneId);
+        }
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_VOLUME_CHANGED));
+    }
+
+    public void requestFocus(int groupId) {
+        // Automatic volume change only works for primary audio zone.
+        if (mZoneId == CarAudioManager.PRIMARY_AUDIO_ZONE) {
+            mHandler.sendMessage(mHandler.obtainMessage(MSG_REQUEST_FOCUS, groupId));
+        }
+    }
+
+    private class AudioFocusListener implements AudioManager.OnAudioFocusChangeListener {
+        private final int mGroupId;
+        AudioFocusListener(int groupId) {
+            mGroupId = groupId;
+        }
+        @Override
+        public void onAudioFocusChange(int focusChange) {
+            if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
+                mHandler.sendMessage(mHandler.obtainMessage(MSG_FOCUS_CHANGED, mGroupId, 0));
+            } else {
+                Log.e(TAG, "Audio focus request failed");
+            }
+        }
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/VolumeAdapter.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/VolumeAdapter.java
deleted file mode 100644
index ec071dc..0000000
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/VolumeAdapter.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.android.car.kitchensink.volume;
-
-import android.content.Context;
-import android.graphics.Color;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.TextView;
-
-import com.google.android.car.kitchensink.R;
-import com.google.android.car.kitchensink.volume.VolumeTestFragment.VolumeInfo;
-
-
-public class VolumeAdapter extends ArrayAdapter<VolumeInfo> {
-
-    private final Context mContext;
-    private VolumeInfo[] mVolumeList;
-    private final int mLayoutResourceId;
-    private VolumeTestFragment mFragment;
-
-
-    public VolumeAdapter(Context c, int layoutResourceId, VolumeInfo[] volumeList,
-            VolumeTestFragment fragment) {
-        super(c, layoutResourceId, volumeList);
-        mFragment = fragment;
-        mContext = c;
-        this.mLayoutResourceId = layoutResourceId;
-        this.mVolumeList = volumeList;
-    }
-
-    @Override
-    public View getView(int position, View convertView, ViewGroup parent) {
-        ViewHolder vh = new ViewHolder();
-        if (convertView == null) {
-            LayoutInflater inflater = LayoutInflater.from(mContext);
-            convertView = inflater.inflate(mLayoutResourceId, parent, false);
-            vh.id = convertView.findViewById(R.id.stream_id);
-            vh.maxVolume = convertView.findViewById(R.id.volume_limit);
-            vh.currentVolume = convertView.findViewById(R.id.current_volume);
-            vh.upButton = convertView.findViewById(R.id.volume_up);
-            vh.downButton = convertView.findViewById(R.id.volume_down);
-            vh.requestButton = convertView.findViewById(R.id.request);
-            convertView.setTag(vh);
-        } else {
-            vh = (ViewHolder) convertView.getTag();
-        }
-        if (mVolumeList[position] != null) {
-            vh.id.setText(mVolumeList[position].mId);
-            vh.maxVolume.setText(String.valueOf(mVolumeList[position].mMax));
-            vh.currentVolume.setText(String.valueOf(mVolumeList[position].mCurrent));
-            int color = mVolumeList[position].mHasFocus ? Color.GREEN : Color.GRAY;
-            vh.requestButton.setBackgroundColor(color);
-            if (position == 0) {
-                vh.upButton.setVisibility(View.INVISIBLE);
-                vh.downButton.setVisibility(View.INVISIBLE);
-                vh.requestButton.setVisibility(View.INVISIBLE);
-            } else {
-                vh.upButton.setVisibility(View.VISIBLE);
-                vh.downButton.setVisibility(View.VISIBLE);
-                vh.requestButton.setVisibility(View.VISIBLE);
-                vh.upButton.setOnClickListener((view) -> {
-                    mFragment.adjustVolumeByOne(mVolumeList[position].mGroupId, true);
-                });
-                vh.downButton.setOnClickListener((view) -> {
-                    mFragment.adjustVolumeByOne(mVolumeList[position].mGroupId, false);
-                });
-
-                vh.requestButton.setOnClickListener((view) -> {
-                    mFragment.requestFocus(mVolumeList[position].mGroupId);
-                });
-            }
-        }
-        return convertView;
-    }
-
-    @Override
-    public int getCount() {
-        return mVolumeList.length;
-    }
-
-
-    public void refreshVolumes(VolumeInfo[] volumes) {
-        mVolumeList = volumes;
-        notifyDataSetChanged();
-    }
-
-    static class ViewHolder {
-        TextView id;
-        TextView maxVolume;
-        TextView currentVolume;
-        Button upButton;
-        Button downButton;
-        Button requestButton;
-    }
-}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/VolumeTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/VolumeTestFragment.java
index f753efe..d0366e1 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/VolumeTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/VolumeTestFragment.java
@@ -18,32 +18,37 @@
 import android.car.Car;
 import android.car.Car.CarServiceLifecycleListener;
 import android.car.media.CarAudioManager;
+import android.car.media.CarAudioManager.CarVolumeCallback;
 import android.content.Context;
 import android.media.AudioManager;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
 import android.util.Log;
-import android.util.SparseIntArray;
+import android.util.SparseArray;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.ListView;
 import android.widget.SeekBar;
 
 import androidx.annotation.Nullable;
 import androidx.fragment.app.Fragment;
+import androidx.viewpager.widget.ViewPager;
 
 import com.google.android.car.kitchensink.R;
+import com.google.android.material.tabs.TabLayout;
 
-public class VolumeTestFragment extends Fragment {
+import java.util.List;
+
+import javax.annotation.concurrent.GuardedBy;
+
+public final class VolumeTestFragment extends Fragment {
     private static final String TAG = "CarVolumeTest";
-    private static final int MSG_VOLUME_CHANGED = 0;
-    private static final int MSG_REQUEST_FOCUS = 1;
-    private static final int MSG_FOCUS_CHANGED= 2;
+    private static final boolean DEBUG = true;
 
     private AudioManager mAudioManager;
-    private VolumeAdapter mAdapter;
+    private AudioZoneVolumeTabAdapter mAudioZoneAdapter;
+    @GuardedBy("mLock")
+    private final SparseArray<CarAudioZoneVolumeFragment> mZoneVolumeFragments =
+            new SparseArray<>();
 
     private CarAudioManager mCarAudioManager;
     private Car mCar;
@@ -51,58 +56,10 @@
     private SeekBar mFader;
     private SeekBar mBalance;
 
-    private final Handler mHandler = new VolumeHandler();
+    private TabLayout mZonesTabLayout;
+    private Object mLock = new Object();
 
-    private class VolumeHandler extends Handler {
-        private AudioFocusListener mFocusListener;
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_VOLUME_CHANGED:
-                    initVolumeInfo();
-                    break;
-                case MSG_REQUEST_FOCUS:
-                    int groupId = msg.arg1;
-                    if (mFocusListener != null) {
-                        mAudioManager.abandonAudioFocus(mFocusListener);
-                        mVolumeInfos[mGroupIdIndexMap.get(groupId)].mHasFocus = false;
-                        mAdapter.notifyDataSetChanged();
-                    }
-
-                    mFocusListener = new AudioFocusListener(groupId);
-                    mAudioManager.requestAudioFocus(mFocusListener, groupId,
-                            AudioManager.AUDIOFOCUS_GAIN);
-                    break;
-                case MSG_FOCUS_CHANGED:
-                    int focusGroupId = msg.arg1;
-                    mVolumeInfos[mGroupIdIndexMap.get(focusGroupId)].mHasFocus = true;
-                    mAdapter.refreshVolumes(mVolumeInfos);
-                    break;
-
-            }
-        }
-    }
-
-    private VolumeInfo[] mVolumeInfos = new VolumeInfo[0];
-    private SparseIntArray mGroupIdIndexMap = new SparseIntArray();
-
-    private class AudioFocusListener implements AudioManager.OnAudioFocusChangeListener {
-        private final int mGroupId;
-        public AudioFocusListener(int groupId) {
-            mGroupId = groupId;
-        }
-        @Override
-        public void onAudioFocusChange(int focusChange) {
-            if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
-                mHandler.sendMessage(mHandler.obtainMessage(MSG_FOCUS_CHANGED, mGroupId, 0));
-            } else {
-                Log.e(TAG, "Audio focus request failed");
-            }
-        }
-    }
-
-    public static class VolumeInfo {
+    public static class CarAudioZoneVolumeInfo {
         public int mGroupId;
         public String mId;
         public String mMax;
@@ -110,30 +67,63 @@
         public boolean mHasFocus;
     }
 
+    private final class CarVolumeChangeListener extends CarVolumeCallback {
+        @Override
+        public void onGroupVolumeChanged(int zoneId, int groupId, int flags) {
+            if (DEBUG) {
+                Log.d(TAG, "onGroupVolumeChanged volume changed for zone "
+                        + zoneId);
+            }
+            synchronized (mLock) {
+                CarAudioZoneVolumeFragment fragment = mZoneVolumeFragments.get(zoneId);
+                if (fragment != null) {
+                    fragment.sendChangeMessage();
+                }
+            }
+        }
+
+        @Override
+        public void onMasterMuteChanged(int zoneId, int flags) {
+            if (DEBUG) {
+                Log.d(TAG, "onMasterMuteChanged master mute "
+                        + mAudioManager.isMasterMute());
+            }
+        }
+    }
+
+    private final CarVolumeCallback mCarVolumeCallback = new CarVolumeChangeListener();
+
     private CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> {
         if (!ready) {
-            Log.d(TAG, "Disconnect from Car Service");
+            if (DEBUG) {
+                Log.d(TAG, "Disconnect from Car Service");
+            }
             return;
         }
-        Log.d(TAG, "Connected to Car Service");
+        if (DEBUG) {
+            Log.d(TAG, "Connected to Car Service");
+        }
         mCarAudioManager = (CarAudioManager) car.getCarManager(Car.AUDIO_SERVICE);
         initVolumeInfo();
+        mCarAudioManager.registerCarVolumeCallback(mCarVolumeCallback);
     };
 
     @Override
     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                              @Nullable Bundle savedInstanceState) {
-        View v = inflater.inflate(R.layout.volume_test, container, false);
-
-        ListView volumeListView = v.findViewById(R.id.volume_list);
         mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
 
-        mAdapter = new VolumeAdapter(getContext(), R.layout.volume_item, mVolumeInfos, this);
-        volumeListView.setAdapter(mAdapter);
+        View v = inflater.inflate(R.layout.volume_test, container, false);
 
-        v.findViewById(R.id.refresh).setOnClickListener((view) -> initVolumeInfo());
+        mZonesTabLayout = v.findViewById(R.id.zones_tab);
+        ViewPager viewPager = (ViewPager) v.findViewById(R.id.zone_view_pager);
 
-        final SeekBar.OnSeekBarChangeListener seekListener = new SeekBar.OnSeekBarChangeListener() {
+        mAudioZoneAdapter = new AudioZoneVolumeTabAdapter(getChildFragmentManager());
+        viewPager.setAdapter(mAudioZoneAdapter);
+        mZonesTabLayout.setupWithViewPager(viewPager);
+
+        SeekBar.OnSeekBarChangeListener seekListener =
+                new SeekBar.OnSeekBarChangeListener() {
             public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                 final float percent = (progress - 100) / 100.0f;
                 if (seekBar.getId() == R.id.fade_bar) {
@@ -159,48 +149,29 @@
         return v;
     }
 
-    public void adjustVolumeByOne(int groupId, boolean up) {
-        if (mCarAudioManager == null) {
-            Log.e(TAG, "CarAudioManager is null");
-            return;
+    @Override
+    public void onDestroyView() {
+        if (mCar != null && mCar.isConnected()) {
+            mCar.disconnect();
+            mCar = null;
         }
-        int current = mCarAudioManager.getGroupVolume(groupId);
-        int volume = current + (up ? 1 : -1);
-        mCarAudioManager.setGroupVolume(groupId, volume,
-                AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_PLAY_SOUND);
-        Log.d(TAG, "Set group " + groupId + " volume " + volume);
-    }
-
-    public void requestFocus(int groupId) {
-        mHandler.sendMessage(mHandler.obtainMessage(MSG_REQUEST_FOCUS, groupId));
+        super.onDestroyView();
     }
 
     private void initVolumeInfo() {
-        int volumeGroupCount = mCarAudioManager.getVolumeGroupCount();
-        mVolumeInfos = new VolumeInfo[volumeGroupCount + 1];
-        mGroupIdIndexMap.clear();
-        mVolumeInfos[0] = new VolumeInfo();
-        mVolumeInfos[0].mId = "Group id";
-        mVolumeInfos[0].mCurrent = "Current";
-        mVolumeInfos[0].mMax = "Max";
-
-        int i = 1;
-        for (int groupId = 0; groupId < volumeGroupCount; groupId++) {
-            mVolumeInfos[i] = new VolumeInfo();
-            mVolumeInfos[i].mGroupId = groupId;
-            mGroupIdIndexMap.put(groupId, i);
-            mVolumeInfos[i].mId = String.valueOf(groupId);
-
-
-            int current = mCarAudioManager.getGroupVolume(groupId);
-            int max = mCarAudioManager.getGroupMaxVolume(groupId);
-            mVolumeInfos[i].mCurrent = String.valueOf(current);
-            mVolumeInfos[i].mMax = String.valueOf(max);
-
-            Log.d(TAG, groupId + " max: " + mVolumeInfos[i].mMax + " current: "
-                    + mVolumeInfos[i].mCurrent);
-            i++;
+        synchronized (mLock) {
+            List<Integer> audioZoneIds = mCarAudioManager.getAudioZoneIds();
+            for (int index = 0; index < audioZoneIds.size(); index++) {
+                int zoneId = audioZoneIds.get(index);
+                CarAudioZoneVolumeFragment fragment =
+                        new CarAudioZoneVolumeFragment(zoneId, mCarAudioManager, mAudioManager);
+                mZonesTabLayout.addTab(mZonesTabLayout.newTab().setText("Audio Zone " + zoneId));
+                mAudioZoneAdapter.addFragment(fragment, "Audio Zone " + zoneId);
+                if (DEBUG) {
+                    Log.d(TAG, "Adding audio volume for zone " + zoneId);
+                }
+                mZoneVolumeFragments.put(zoneId, fragment);
+            }
         }
-        mAdapter.refreshVolumes(mVolumeInfos);
     }
 }
diff --git a/tests/GarageModeTestApp/res/layout/main_activity.xml b/tests/GarageModeTestApp/res/layout/main_activity.xml
index a71e3cc..d79089e 100644
--- a/tests/GarageModeTestApp/res/layout/main_activity.xml
+++ b/tests/GarageModeTestApp/res/layout/main_activity.xml
@@ -62,13 +62,6 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/off_car_testing"/>
-
-        <Button
-            style="@style/Button"
-            android:id="@+id/incar_test_btn"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/in_car_testing"/>
     </LinearLayout>
 
     <FrameLayout
diff --git a/tests/GarageModeTestApp/res/values/strings.xml b/tests/GarageModeTestApp/res/values/strings.xml
index 8bab7b1..8dbe34b 100644
--- a/tests/GarageModeTestApp/res/values/strings.xml
+++ b/tests/GarageModeTestApp/res/values/strings.xml
@@ -17,7 +17,6 @@
   <string name="app_name" translatable="false">GarageMode Test App</string>
 
   <string name="off_car_testing" translatable="false">Offcar Test</string>
-  <string name="in_car_testing" translatable="false">Incar Test</string>
   <string name="quit_app" translatable="false">Quit App</string>
 
   <string name="button_schedule_job" translatable="false">Schedule Job</string>
diff --git a/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/IncarTestingFragment.java b/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/IncarTestingFragment.java
deleted file mode 100644
index 22b460e..0000000
--- a/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/IncarTestingFragment.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.android.car.garagemode.testapp;
-
-import androidx.fragment.app.Fragment;
-
-public class IncarTestingFragment extends Fragment {
-
-}
diff --git a/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/MainActivity.java b/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/MainActivity.java
index dae859f..5af7019 100644
--- a/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/MainActivity.java
+++ b/tests/GarageModeTestApp/src/com/google/android/car/garagemode/testapp/MainActivity.java
@@ -17,6 +17,7 @@
 
 import android.content.res.Configuration;
 import android.os.Bundle;
+import android.view.View;
 
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentActivity;
@@ -30,7 +31,6 @@
     private final List<MenuEntry> mMenuEntries = new ArrayList<MenuEntry>() {
         {
             add("Offcar testing", OffcarTestingFragment.class);
-            add("Incar testing", IncarTestingFragment.class);
             add("Quit", MainActivity.this::finish);
         }
 
@@ -47,13 +47,14 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main_activity);
+        // Until we have more than one fragment, hide the selection button
+        findViewById(R.id.offcar_test_btn).setVisibility(View.INVISIBLE);
 
         mMenuEntries.get(0).onClick();
 
         findViewById(R.id.offcar_test_btn).setOnClickListener((v) -> mMenuEntries.get(0).onClick());
-        findViewById(R.id.incar_test_btn).setOnClickListener((v) -> mMenuEntries.get(1).onClick());
         findViewById(R.id.exit_button_container).setOnClickListener(
-                (v) -> mMenuEntries.get(2).onClick());
+                (v) -> mMenuEntries.get(1).onClick());
     }
 
     @Override
diff --git a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ne/strings.xml b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ne/strings.xml
index 6a68809..9055065 100644
--- a/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ne/strings.xml
+++ b/tests/MultiDisplaySecondaryHomeTestLauncher/res/values-ne/strings.xml
@@ -21,7 +21,7 @@
     <string name="md_launcher" msgid="327845696688732506">"MD लन्चर"</string>
     <string name="couldnt_launch" msgid="7815676424138012351">"उक्त क्रियाकलाप सुरु गर्न सकिएन"</string>
     <string name="select_display" msgid="1682700853391296117">"कुनै डिस्प्ले चयन गर्नुहोस्"</string>
-    <string name="add_app_shortcut" msgid="8873512136913188432">"अनुप्रयोगको सर्टकट थप्नुहोस्‌"</string>
+    <string name="add_app_shortcut" msgid="8873512136913188432">"एपको सर्टकट थप्नुहोस्‌"</string>
     <string name="set_wallpaper" msgid="3650915172749345197">"वालपेपर सेट गर्नुहोस्"</string>
     <string name="new_instance" msgid="1924479866055190730">"नयाँ सत्रमा लोकार्पण गर्ने अनुरोध गर्नुहोस्"</string>
     <string name="wallpaper_description" msgid="5885164573334720996">"मल्टिडिस्प्लेको नमूना वालपेपर"</string>
diff --git a/tests/MultiDisplayTest/Android.mk b/tests/MultiDisplayTest/Android.mk
index 779c646..dcee7b4 100644
--- a/tests/MultiDisplayTest/Android.mk
+++ b/tests/MultiDisplayTest/Android.mk
@@ -33,7 +33,7 @@
 LOCAL_STATIC_ANDROID_LIBRARIES += \
     androidx.lifecycle_lifecycle-livedata \
     androidx.lifecycle_lifecycle-viewmodel \
-    androidx.car_car-cluster
+    androidx.car_car
 
 include $(BUILD_PACKAGE)
 
diff --git a/tests/OWNERS b/tests/OWNERS
new file mode 100644
index 0000000..e515908
--- /dev/null
+++ b/tests/OWNERS
@@ -0,0 +1,6 @@
+# Test team
+vshah@google.com
+
+# AAE TLs
+pirozzoj@google.com
+twasilczyk@google.com
diff --git a/tests/OccupantAwareness/Android.bp b/tests/OccupantAwareness/Android.bp
new file mode 100644
index 0000000..2160572
--- /dev/null
+++ b/tests/OccupantAwareness/Android.bp
@@ -0,0 +1,51 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "OccupantAwarenessSystemTests",
+
+    srcs: ["src/**/*.java"],
+
+    instrumentation_for: "CarService",
+
+    optimize: {
+        enabled: false,
+    },
+
+    certificate: "platform",
+    platform_apis: true,
+    privileged: true,
+
+    libs: [
+        "android.car",
+        "android.test.base",
+        "android.test.mock",
+        "android.test.runner",
+        // After here
+        "android.car-test-stubs",
+        "android.car.testapi",
+    ],
+
+    static_libs: [
+        "android-support-test",
+        "truth-prebuilt",
+        "android.hardware.automotive.occupant_awareness-java",
+        "android.test.base.stubs",
+        "car-service-test-static-lib",
+        "androidx.test.core",
+        "androidx.test.ext.junit",
+        "androidx.test.rules",
+        "car-frameworks-service",
+    ],
+}
diff --git a/tests/OccupantAwareness/AndroidManifest.xml b/tests/OccupantAwareness/AndroidManifest.xml
new file mode 100644
index 0000000..72085ed
--- /dev/null
+++ b/tests/OccupantAwareness/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.car.tests">
+
+    <!--  Needed for OAS testing -->
+    <uses-permission android:name="android.car.permission.READ_CAR_OCCUPANT_AWARENESS_STATE" />
+    <uses-permission android:name="android.car.permission.CONTROL_CAR_OCCUPANT_AWARENESS_SYSTEM" />
+
+    <application
+                 android:debuggable="true">
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.car.tests"
+                     android:label="Occupant Awareness System Tests" />
+</manifest>
diff --git a/tests/OccupantAwareness/src/com/android/car/test/OccupantAwarenessServiceIntegrationTest.java b/tests/OccupantAwareness/src/com/android/car/test/OccupantAwarenessServiceIntegrationTest.java
new file mode 100644
index 0000000..14738c4
--- /dev/null
+++ b/tests/OccupantAwareness/src/com/android/car/test/OccupantAwarenessServiceIntegrationTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.Car;
+import android.car.occupantawareness.OccupantAwarenessDetection;
+import android.car.occupantawareness.OccupantAwarenessManager;
+import android.car.occupantawareness.SystemStatusEvent;
+import android.content.Context;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+/*
+ * IMPORTANT NOTE:
+ * The test assumes that mock hal for occupant awareness interface is running at the time of test.
+ * Depending on test target, mock hal for occupant awareness interface may need to be added to build
+ * targets. Instructions to add mock hal to build -
+ * PRODUCT_PACKAGES += android.hardware.automotive.occupant_awareness@1.0-service_mock
+ *
+ * Mock hal may need to be launched before running the test -
+ * /system/bin/android.hardware.automotive.occupant_awareness@1.0-service_mock
+ *
+ * The test will likely fail if mock hal is not running on the target.
+ */
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public final class OccupantAwarenessServiceIntegrationTest {
+    private CompletableFuture<SystemStatusEvent> mFutureStatus;
+    private CompletableFuture<OccupantAwarenessDetection> mFutureDriverDetection;
+    private CompletableFuture<OccupantAwarenessDetection> mFuturePassengerDetection;
+
+    private final Context mContext = ApplicationProvider.getApplicationContext();
+    private Car mCar = Car.createCar(mContext);
+    private final OccupantAwarenessManager mOasManager =
+            (OccupantAwarenessManager) mCar.getCarManager(Car.OCCUPANT_AWARENESS_SERVICE);
+
+    @Before
+    public void setUp() {
+        mOasManager.registerChangeCallback(new CallbackHandler());
+    }
+
+    @Test
+    public void testGetCapabilityForRole() throws Exception {
+        // Mock hal only supports driver monitoring and presence detection for only driver and
+        // front seat passengers.
+        // This test ensures that correct values are passed to clients of occupant awareness
+        // service.
+        assertThat(mOasManager.getCapabilityForRole(
+                OccupantAwarenessDetection.VEHICLE_OCCUPANT_DRIVER))
+                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_PRESENCE
+                    | SystemStatusEvent.DETECTION_TYPE_DRIVER_MONITORING);
+
+        assertThat(mOasManager.getCapabilityForRole(
+                OccupantAwarenessDetection.VEHICLE_OCCUPANT_FRONT_PASSENGER))
+                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_PRESENCE);
+
+        assertThat(mOasManager.getCapabilityForRole(
+                OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_2_PASSENGER_RIGHT))
+                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_NONE);
+
+        assertThat(mOasManager.getCapabilityForRole(
+                OccupantAwarenessDetection.VEHICLE_OCCUPANT_NONE))
+                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_NONE);
+    }
+
+    @Test
+    public void testDetectionEvents() throws Exception {
+        // Since the test assumes mock hal is the source of detections, the pattern of driver and
+        // passenger detection is pre-determined. The test verifies that detections from occupant
+        // awareness manager matches expected detections.
+        OccupantAwarenessDetection driverDetection =
+                mFutureDriverDetection.get(1, TimeUnit.SECONDS);
+        OccupantAwarenessDetection passengerDetection =
+                mFuturePassengerDetection.get(1, TimeUnit.SECONDS);
+
+        assertThat(driverDetection.driverMonitoringDetection.isLookingOnRoad).isFalse();
+        assertThat(passengerDetection.isPresent).isTrue();
+    }
+
+    @Test
+    public void testSystemTransitionsToReady() throws Exception {
+        // Since the test assumes mock hal is the source of detections, it is expected that mock hal
+        // is ready to serve requests from occupant awareness service. The test verifies that
+        // occupant awareness manager notifies that the system transitions to ready state.
+        SystemStatusEvent status;
+        status = mFutureStatus.get(1, TimeUnit.SECONDS);
+        assertThat(status.systemStatus).isEqualTo(SystemStatusEvent.SYSTEM_STATUS_READY);
+    }
+
+    private final class CallbackHandler extends OccupantAwarenessManager.ChangeCallback {
+        @Override
+        public void onDetectionEvent(OccupantAwarenessDetection event) {
+            switch(event.role) {
+                case OccupantAwarenessDetection.VEHICLE_OCCUPANT_DRIVER:
+                    mFutureDriverDetection.complete(event);
+                    break;
+                case OccupantAwarenessDetection.VEHICLE_OCCUPANT_FRONT_PASSENGER:
+                    mFuturePassengerDetection.complete(event);
+                    break;
+            }
+        }
+
+        @Override
+        public void onSystemStateChanged(SystemStatusEvent systemStatus) {
+            mFutureStatus.complete(systemStatus);
+        }
+    }
+}
diff --git a/tests/OccupantAwareness/src/com/android/car/test/OccupantAwarenessSystemServiceTest.java b/tests/OccupantAwareness/src/com/android/car/test/OccupantAwarenessSystemServiceTest.java
new file mode 100644
index 0000000..e9b7cdf
--- /dev/null
+++ b/tests/OccupantAwareness/src/com/android/car/test/OccupantAwarenessSystemServiceTest.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.occupantawareness.IOccupantAwarenessEventCallback;
+import android.car.occupantawareness.OccupantAwarenessDetection;
+import android.car.occupantawareness.SystemStatusEvent;
+import android.content.Context;
+import android.hardware.automotive.occupant_awareness.IOccupantAwareness;
+import android.hardware.automotive.occupant_awareness.IOccupantAwarenessClientCallback;
+import android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus;
+import android.hardware.automotive.occupant_awareness.OccupantDetection;
+import android.hardware.automotive.occupant_awareness.OccupantDetections;
+import android.hardware.automotive.occupant_awareness.Role;
+import android.os.RemoteException;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.runner.AndroidJUnit4;
+
+import junit.framework.TestCase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class OccupantAwarenessSystemServiceTest extends TestCase {
+    private static final int TIMESTAMP = 1234; // In milliseconds.
+
+    /**
+     * Mock implementation of {@link
+     * android.hardware.automotive.occupant_awareness.IOccupantAwareness} for testing the service
+     * and manager.
+     */
+    private class MockOasHal
+            extends android.hardware.automotive.occupant_awareness.IOccupantAwareness.Stub {
+        private IOccupantAwarenessClientCallback mCallback;
+        private boolean mGraphIsRunning;
+
+        MockOasHal() {}
+
+        /** Returns whether the mock graph is running. */
+        public boolean isGraphRunning() {
+            return mGraphIsRunning;
+        }
+
+        @Override
+        public void getLatestDetection(OccupantDetections detections) {}
+
+        @Override
+        public void setCallback(IOccupantAwarenessClientCallback callback) {
+            mCallback = callback;
+        }
+
+        @Override
+        public @OccupantAwarenessStatus byte getState(int occupantRole, int detectionCapability) {
+            return OccupantAwarenessStatus.READY;
+        }
+
+        @Override
+        public @OccupantAwarenessStatus byte startDetection() {
+            mGraphIsRunning = true;
+            return OccupantAwarenessStatus.READY;
+        }
+
+        @Override
+        public @OccupantAwarenessStatus byte stopDetection() {
+            mGraphIsRunning = false;
+            return OccupantAwarenessStatus.READY;
+        }
+
+        @Override
+        public int getCapabilityForRole(@Role int occupantRole) {
+            if (occupantRole == OccupantAwarenessDetection.VEHICLE_OCCUPANT_DRIVER) {
+                return SystemStatusEvent.DETECTION_TYPE_PRESENCE
+                        | SystemStatusEvent.DETECTION_TYPE_GAZE
+                        | SystemStatusEvent.DETECTION_TYPE_DRIVER_MONITORING;
+            } else if (occupantRole
+                    == OccupantAwarenessDetection.VEHICLE_OCCUPANT_FRONT_PASSENGER) {
+                return SystemStatusEvent.DETECTION_TYPE_PRESENCE;
+            } else {
+                return SystemStatusEvent.DETECTION_TYPE_NONE;
+            }
+        }
+
+        /** Causes a status event to be generated with the specified flags. */
+        public void fireStatusEvent(int detectionFlags, @OccupantAwarenessStatus byte status)
+                throws RemoteException {
+            if (mCallback != null) {
+                mCallback.onSystemStatusChanged(detectionFlags, status);
+            }
+        }
+
+        /** Causes a status event to be generated with the specified detection event data. */
+        public void fireDetectionEvent(OccupantAwarenessDetection detectionEvent)
+                throws RemoteException {
+            if (mCallback != null) {
+                OccupantDetection detection = new OccupantDetection();
+
+                OccupantDetections detections = new OccupantDetections();
+                detections.timeStampMillis = TIMESTAMP;
+                detections.detections = new OccupantDetection[] {detection};
+                mCallback.onDetectionEvent(detections);
+            }
+        }
+
+        @Override
+        public int getInterfaceVersion() {
+            return this.VERSION;
+        }
+
+        @Override
+        public String getInterfaceHash() {
+            return this.HASH;
+        }
+    }
+
+    private MockOasHal mMockHal;
+    private com.android.car.OccupantAwarenessService mOasService;
+
+    private CompletableFuture<SystemStatusEvent> mFutureStatus;
+    private CompletableFuture<OccupantAwarenessDetection> mFutureDetection;
+
+    @Before
+    public void setUp() {
+        Context context = ApplicationProvider.getApplicationContext();
+        mMockHal = new MockOasHal();
+        mOasService = new com.android.car.OccupantAwarenessService(context, mMockHal);
+        mOasService.init();
+
+        resetFutures();
+    }
+
+    @After
+    public void tearDown() {
+        mOasService.release();
+    }
+
+    @Test
+    public void testWithNoRegisteredListeners() throws Exception {
+        // Verify operation when no listeners are registered.
+        mMockHal.fireStatusEvent(IOccupantAwareness.CAP_NONE, OccupantAwarenessStatus.READY);
+
+        // Nothing should have been received.
+        assertThat(mFutureStatus.isDone()).isFalse();
+        assertThat(mFutureDetection.isDone()).isFalse();
+    }
+
+    @Test
+    public void testStatusEventsWithRegisteredListeners() throws Exception {
+        // Verify correct operation when a listener has been registered.
+        registerCallbackToService();
+        SystemStatusEvent result;
+
+        // Fire a status event and ensure it is received.
+        // "Presence status is ready"
+        resetFutures();
+        mMockHal.fireStatusEvent(
+                IOccupantAwareness.CAP_PRESENCE_DETECTION, OccupantAwarenessStatus.READY);
+
+        result = mFutureStatus.get(1, TimeUnit.SECONDS);
+        assertEquals(result.detectionType, SystemStatusEvent.DETECTION_TYPE_PRESENCE);
+        assertEquals(result.systemStatus, SystemStatusEvent.SYSTEM_STATUS_READY);
+
+        // "Gaze status is failed"
+        resetFutures();
+        mMockHal.fireStatusEvent(
+                IOccupantAwareness.CAP_GAZE_DETECTION, OccupantAwarenessStatus.FAILURE);
+
+        result = mFutureStatus.get(1, TimeUnit.SECONDS);
+        assertEquals(result.detectionType, SystemStatusEvent.DETECTION_TYPE_GAZE);
+        assertEquals(result.systemStatus, SystemStatusEvent.SYSTEM_STATUS_SYSTEM_FAILURE);
+
+        // "Driver monitoring status is not-ready"
+        resetFutures();
+        mMockHal.fireStatusEvent(
+                IOccupantAwareness.CAP_DRIVER_MONITORING_DETECTION,
+                OccupantAwarenessStatus.NOT_INITIALIZED);
+
+        result = mFutureStatus.get(1, TimeUnit.SECONDS);
+        assertEquals(result.detectionType, SystemStatusEvent.DETECTION_TYPE_DRIVER_MONITORING);
+        assertEquals(result.systemStatus, SystemStatusEvent.SYSTEM_STATUS_NOT_READY);
+
+        // "None is non-supported"
+        resetFutures();
+        mMockHal.fireStatusEvent(
+                IOccupantAwareness.CAP_NONE, OccupantAwarenessStatus.NOT_SUPPORTED);
+
+        result = mFutureStatus.get(1, TimeUnit.SECONDS);
+        assertEquals(result.detectionType, SystemStatusEvent.DETECTION_TYPE_NONE);
+        assertEquals(result.systemStatus, SystemStatusEvent.SYSTEM_STATUS_NOT_SUPPORTED);
+    }
+
+    @Test
+    public void test_unregisteredListeners() throws Exception {
+        // Verify that listeners are successfully unregistered.
+        IOccupantAwarenessEventCallback callback = registerCallbackToService();
+
+        // Unregister the registered listener.
+        mOasService.unregisterEventListener(callback);
+
+        // Fire some events.
+        mMockHal.fireStatusEvent(IOccupantAwareness.CAP_NONE, OccupantAwarenessStatus.READY);
+        mMockHal.fireStatusEvent(
+                IOccupantAwareness.CAP_GAZE_DETECTION, OccupantAwarenessStatus.READY);
+        mMockHal.fireStatusEvent(
+                IOccupantAwareness.CAP_DRIVER_MONITORING_DETECTION, OccupantAwarenessStatus.READY);
+
+        // Nothing should have been received.
+        assertThat(mFutureStatus.isDone()).isFalse();
+        assertThat(mFutureDetection.isDone()).isFalse();
+
+        // Unregister a second time should log an error, but otherwise not cause any action.
+        mOasService.unregisterEventListener(callback);
+    }
+
+    @Test
+    public void test_getCapabilityForRole() throws Exception {
+        assertThat(
+                        mOasService.getCapabilityForRole(
+                                OccupantAwarenessDetection.VEHICLE_OCCUPANT_DRIVER))
+                .isEqualTo(
+                        SystemStatusEvent.DETECTION_TYPE_PRESENCE
+                                | SystemStatusEvent.DETECTION_TYPE_GAZE
+                                | SystemStatusEvent.DETECTION_TYPE_DRIVER_MONITORING);
+
+        assertThat(
+                        mOasService.getCapabilityForRole(
+                                OccupantAwarenessDetection.VEHICLE_OCCUPANT_FRONT_PASSENGER))
+                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_PRESENCE);
+
+        assertThat(
+                        mOasService.getCapabilityForRole(
+                                OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_2_PASSENGER_RIGHT))
+                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_NONE);
+
+        assertThat(
+                        mOasService.getCapabilityForRole(
+                                OccupantAwarenessDetection.VEHICLE_OCCUPANT_NONE))
+                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_NONE);
+    }
+
+    @Test
+    public void test_serviceStartsAndStopGraphWithListeners() throws Exception {
+        // Verify that the service starts the detection graph when the first client connects, and
+        // stop when the last client disconnects.
+
+        // Should be not running on start (no clients are yet connected).
+        assertThat(mMockHal.isGraphRunning()).isFalse();
+
+        // Connect a client. Graph should be running.
+        IOccupantAwarenessEventCallback first_client = registerCallbackToService();
+        assertThat(mMockHal.isGraphRunning()).isTrue();
+
+        // Connect a second client. Graph should continue running.
+        IOccupantAwarenessEventCallback second_client = registerCallbackToService();
+        assertThat(mMockHal.isGraphRunning()).isTrue();
+
+        // Remove the first client. Graph should continue to run since a client still remains.
+        mOasService.unregisterEventListener(first_client);
+        assertThat(mMockHal.isGraphRunning()).isTrue();
+
+        // Remove the second client. Graph should now stop since all clients have now closed.
+        mOasService.unregisterEventListener(second_client);
+        assertThat(mMockHal.isGraphRunning()).isFalse();
+    }
+
+    /** Registers a listener to the service. */
+    private IOccupantAwarenessEventCallback registerCallbackToService() {
+        IOccupantAwarenessEventCallback callback =
+                new IOccupantAwarenessEventCallback.Stub() {
+                    @Override
+                    public void onStatusChanged(SystemStatusEvent systemStatusEvent) {
+                        mFutureStatus.complete(systemStatusEvent);
+                    }
+
+                    public void onDetectionEvent(OccupantAwarenessDetection detectionEvent) {
+                        mFutureDetection.complete(detectionEvent);
+                    }
+                };
+
+        mOasService.registerEventListener(callback);
+        return callback;
+    }
+
+    /** Resets futures for testing. */
+    private void resetFutures() {
+        mFutureStatus = new CompletableFuture<>();
+        mFutureDetection = new CompletableFuture<>();
+    }
+}
diff --git a/tests/OccupantAwareness/src/com/android/car/test/OccupantAwarenessUtilsTest.java b/tests/OccupantAwareness/src/com/android/car/test/OccupantAwarenessUtilsTest.java
new file mode 100644
index 0000000..fc6fa06
--- /dev/null
+++ b/tests/OccupantAwareness/src/com/android/car/test/OccupantAwarenessUtilsTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.occupantawareness.OccupantAwarenessDetection;
+import android.car.occupantawareness.SystemStatusEvent;
+import android.hardware.automotive.occupant_awareness.IOccupantAwareness;
+import android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import junit.framework.TestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class OccupantAwarenessUtilsTest extends TestCase {
+
+    @Test
+    public void test_convertToStatusEvent() {
+        SystemStatusEvent event;
+
+        event =
+                OccupantAwarenessUtils.convertToStatusEvent(
+                        IOccupantAwareness.CAP_NONE, OccupantAwarenessStatus.READY);
+        assertThat(event.systemStatus).isEqualTo(SystemStatusEvent.SYSTEM_STATUS_READY);
+        assertThat(event.detectionType).isEqualTo(SystemStatusEvent.DETECTION_TYPE_NONE);
+
+        event =
+                OccupantAwarenessUtils.convertToStatusEvent(
+                        IOccupantAwareness.CAP_PRESENCE_DETECTION,
+                        OccupantAwarenessStatus.NOT_SUPPORTED);
+        assertThat(event.systemStatus).isEqualTo(SystemStatusEvent.SYSTEM_STATUS_NOT_SUPPORTED);
+        assertThat(event.detectionType).isEqualTo(SystemStatusEvent.DETECTION_TYPE_PRESENCE);
+
+        event =
+                OccupantAwarenessUtils.convertToStatusEvent(
+                        IOccupantAwareness.CAP_GAZE_DETECTION,
+                        OccupantAwarenessStatus.NOT_INITIALIZED);
+        assertThat(event.systemStatus).isEqualTo(SystemStatusEvent.SYSTEM_STATUS_NOT_READY);
+        assertThat(event.detectionType).isEqualTo(SystemStatusEvent.DETECTION_TYPE_GAZE);
+
+        event =
+                OccupantAwarenessUtils.convertToStatusEvent(
+                        IOccupantAwareness.CAP_DRIVER_MONITORING_DETECTION,
+                        OccupantAwarenessStatus.FAILURE);
+        assertThat(event.systemStatus).isEqualTo(SystemStatusEvent.SYSTEM_STATUS_SYSTEM_FAILURE);
+        assertThat(event.detectionType)
+                .isEqualTo(SystemStatusEvent.DETECTION_TYPE_DRIVER_MONITORING);
+    }
+
+    @Test
+    public void test_convertToConfidenceScore() {
+        assertThat(
+                        OccupantAwarenessUtils.convertToConfidenceScore(
+                                android.hardware.automotive.occupant_awareness.ConfidenceLevel.MAX))
+                .isEqualTo(OccupantAwarenessDetection.CONFIDENCE_LEVEL_MAX);
+
+        assertThat(
+                        OccupantAwarenessUtils.convertToConfidenceScore(
+                                android.hardware.automotive.occupant_awareness.ConfidenceLevel
+                                        .HIGH))
+                .isEqualTo(OccupantAwarenessDetection.CONFIDENCE_LEVEL_HIGH);
+
+        assertThat(
+                        OccupantAwarenessUtils.convertToConfidenceScore(
+                                android.hardware.automotive.occupant_awareness.ConfidenceLevel.LOW))
+                .isEqualTo(OccupantAwarenessDetection.CONFIDENCE_LEVEL_LOW);
+
+        assertThat(
+                        OccupantAwarenessUtils.convertToConfidenceScore(
+                                android.hardware.automotive.occupant_awareness.ConfidenceLevel
+                                        .NONE))
+                .isEqualTo(OccupantAwarenessDetection.CONFIDENCE_LEVEL_NONE);
+    }
+
+    @Test
+    public void test_convertToPoint3D() {
+        assertThat(OccupantAwarenessUtils.convertToPoint3D(null)).isNull();
+        assertThat(OccupantAwarenessUtils.convertToPoint3D(new double[0])).isNull();
+        assertThat(OccupantAwarenessUtils.convertToPoint3D(new double[2])).isNull();
+        assertThat(OccupantAwarenessUtils.convertToPoint3D(new double[] {1, 2, 3})).isNotNull();
+    }
+
+    @Test
+    public void test_convertToRole() {
+        assertThat(
+                        OccupantAwarenessUtils.convertToRole(
+                                android.hardware.automotive.occupant_awareness.Role.INVALID))
+                .isEqualTo(OccupantAwarenessDetection.VEHICLE_OCCUPANT_NONE);
+
+        assertThat(
+                        OccupantAwarenessUtils.convertToRole(
+                                android.hardware.automotive.occupant_awareness.Role.UNKNOWN))
+                .isEqualTo(OccupantAwarenessDetection.VEHICLE_OCCUPANT_NONE);
+
+        assertThat(
+                        OccupantAwarenessUtils.convertToRole(
+                                android.hardware.automotive.occupant_awareness.Role.DRIVER
+                                        | android.hardware.automotive.occupant_awareness.Role
+                                                .FRONT_PASSENGER
+                                        | android.hardware.automotive.occupant_awareness.Role
+                                                .ROW_2_PASSENGER_CENTER))
+                .isEqualTo(
+                        OccupantAwarenessDetection.VEHICLE_OCCUPANT_DRIVER
+                                | OccupantAwarenessDetection.VEHICLE_OCCUPANT_FRONT_PASSENGER
+                                | OccupantAwarenessDetection
+                                        .VEHICLE_OCCUPANT_ROW_2_PASSENGER_CENTER);
+
+        assertThat(
+                        OccupantAwarenessUtils.convertToRole(
+                                android.hardware.automotive.occupant_awareness.Role.ALL_OCCUPANTS))
+                .isEqualTo(OccupantAwarenessDetection.VEHICLE_OCCUPANT_ALL_OCCUPANTS);
+    }
+}
diff --git a/tests/PowerTestService/Android.mk b/tests/PowerTestService/Android.mk
index 6ea33f2..aeca2e9 100644
--- a/tests/PowerTestService/Android.mk
+++ b/tests/PowerTestService/Android.mk
@@ -28,7 +28,6 @@
     -Wno-unused-parameter
 
 LOCAL_C_INCLUDES += \
-    frameworks/base/include \
     packages/services/Car/car-lib/native/include
 
 LOCAL_SHARED_LIBRARIES := \
diff --git a/tests/SecondaryHomeApp/Android.bp b/tests/SecondaryHomeApp/Android.bp
new file mode 100644
index 0000000..04da06b
--- /dev/null
+++ b/tests/SecondaryHomeApp/Android.bp
@@ -0,0 +1,45 @@
+//
+// 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.
+//
+android_app {
+    name: "SecondaryHomeApp",
+
+    srcs: [
+        "src/**/*.java",
+        "src/**/I*.aidl",
+    ],
+
+    static_libs: [
+        "androidx.appcompat_appcompat",
+        "androidx.lifecycle_lifecycle-extensions",
+        "com.google.android.material_material",
+        "CarNotificationLib",
+    ],
+
+    libs: [
+        "android.car",
+    ],
+
+    manifest: "AndroidManifest.xml",
+
+    platform_apis: true,
+    certificate: "platform",
+    privileged: true,
+    required: ["privapp_whitelist_com.android.car.secondaryhome"],
+
+    resource_dirs: [
+        "res",
+    ],
+}
diff --git a/tests/SecondaryHomeApp/AndroidManifest.xml b/tests/SecondaryHomeApp/AndroidManifest.xml
new file mode 100644
index 0000000..5d22b70
--- /dev/null
+++ b/tests/SecondaryHomeApp/AndroidManifest.xml
@@ -0,0 +1,61 @@
+<?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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.android.car.secondaryhome">
+    <!-- System permission to host maps activity -->
+    <uses-permission android:name="android.permission.ACTIVITY_EMBEDDING"/>
+    <!-- System permission to send events to hosted maps activity -->
+    <uses-permission android:name="android.permission.INJECT_EVENTS"/>
+    <!-- System permission to use internal system windows -->
+    <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
+    <!-- System permissions to bring hosted activity to front on current display -->
+    <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"/>
+    <uses-permission android:name="android.permission.REORDER_TASKS"/>
+    <!-- System permissions to querry user -->
+    <uses-permission android:name="android.permission.MANAGE_USERS"/>
+
+    <application
+        android:label="@string/app_name"
+        tools:replace="android:label">
+
+        <activity
+            android:name=".launcher.LauncherActivity"
+            android:label="@string/app_launcher"
+            android:theme="@style/LauncherTheme"
+            android:configChanges="orientation|screenSize|smallestScreenSize|
+                screenLayout|colorMode|density"
+            android:documentLaunchMode="always"
+            android:multiprocess="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.SECONDARY_HOME"/>
+            </intent-filter>
+        </activity>
+        <service android:name=".launcher.NotificationListener"
+              android:label="@string/notification_service_label"
+              android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
+              android:directBootAware="true">
+            <intent-filter>
+                <action android:name="android.service.notification.NotificationListenerService"/>
+            </intent-filter>
+        </service>
+    </application>
+</manifest>
+
diff --git a/tests/SecondaryHomeApp/CleanSpec.mk b/tests/SecondaryHomeApp/CleanSpec.mk
new file mode 100644
index 0000000..93662b6
--- /dev/null
+++ b/tests/SecondaryHomeApp/CleanSpec.mk
@@ -0,0 +1,52 @@
+# 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/priv-app/SecondaryHomeApp)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/priv-app/SecondaryHomeApp)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/tests/SecondaryHomeApp/res/drawable/ic_arrow_back.xml b/tests/SecondaryHomeApp/res/drawable/ic_arrow_back.xml
new file mode 100644
index 0000000..658a068
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/drawable/ic_arrow_back.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:width="48dp"
+    android:height="48dp">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M15.41 16.09l-4.58-4.59 4.58-4.59L14 5.5l-6 6 6 6z"/>
+</vector>
diff --git a/tests/SecondaryHomeApp/res/drawable/ic_home.xml b/tests/SecondaryHomeApp/res/drawable/ic_home.xml
new file mode 100644
index 0000000..18c26ad
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/drawable/ic_home.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:viewportWidth="48"
+    android:viewportHeight="48"
+    android:width="48dp"
+    android:height="48dp">
+    <path
+        android:pathData="M7.33333333 14.6666667L14.6666667 14.6666667L14.6666667 7.33333333L7.33333333 7.33333333L7.33333333 14.6666667ZM18.3333333 36.6666667L25.6666667 36.6666667L25.6666667 29.3333333L18.3333333 29.3333333L18.3333333 36.6666667ZM7.33333333 36.6666667L14.6666667 36.6666667L14.6666667 29.3333333L7.33333333 29.3333333L7.33333333 36.6666667ZM7.33333333 25.6666667L14.6666667 25.6666667L14.6666667 18.3333333L7.33333333 18.3333333L7.33333333 25.6666667ZM18.3333333 25.6666667L25.6666667 25.6666667L25.6666667 18.3333333L18.3333333 18.3333333L18.3333333 25.6666667ZM29.3333333 7.33333333L29.3333333 14.6666667L36.6666667 14.6666667L36.6666667 7.33333333L29.3333333 7.33333333ZM18.3333333 14.6666667L25.6666667 14.6666667L25.6666667 7.33333333L18.3333333 7.33333333L18.3333333 14.6666667ZM29.3333333 25.6666667L36.6666667 25.6666667L36.6666667 18.3333333L29.3333333 18.3333333L29.3333333 25.6666667ZM29.3333333 36.6666667L36.6666667 36.6666667L36.6666667 29.3333333L29.3333333 29.3333333L29.3333333 36.6666667Z"
+        android:fillColor="@color/nav_icon_fill_color" />
+</vector>
diff --git a/tests/SecondaryHomeApp/res/drawable/ic_notification.xml b/tests/SecondaryHomeApp/res/drawable/ic_notification.xml
new file mode 100644
index 0000000..ab55431
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/drawable/ic_notification.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:viewportWidth="48"
+    android:viewportHeight="48"
+    android:width="48dp"
+    android:height="48dp">
+    <path
+        android:pathData="M22 39.125C23.925 39.125 25.5 37.55 25.5 35.625L18.5 35.625C18.5 37.55 20.0575 39.125 22 39.125ZM32.5 28.625L32.5 19.875C32.5 14.5025 29.63 10.005 24.625 8.815L24.625 7.625C24.625 6.1725 23.4525 5 22 5C20.5475 5 19.375 6.1725 19.375 7.625L19.375 8.815C14.3525 10.005 11.5 14.485 11.5 19.875L11.5 28.625L8 32.125L8 33.875L36 33.875L36 32.125L32.5 28.625Z"
+        android:fillColor="@color/nav_icon_fill_color" />
+</vector>
diff --git a/tests/SecondaryHomeApp/res/drawable/ic_notification_unseen.xml b/tests/SecondaryHomeApp/res/drawable/ic_notification_unseen.xml
new file mode 100644
index 0000000..4b33825
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/drawable/ic_notification_unseen.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:viewportWidth="44"
+        android:viewportHeight="44"
+        android:width="44dp"
+        android:height="44dp">
+  <path
+      android:pathData="M22 39.125C23.925 39.125 25.5 37.55 25.5 35.625L18.5 35.625C18.5 37.55 20.0575 39.125 22 39.125ZM32.5 28.625L32.5 19.875C32.5 14.5025 29.63 10.005 24.625 8.815L24.625 7.625C24.625 6.1725 23.4525 5 22 5C20.5475 5 19.375 6.1725 19.375 7.625L19.375 8.815C14.3525 10.005 11.5 14.485 11.5 19.875L11.5 28.625L8 32.125L8 33.875L36 33.875L36 32.125L32.5 28.625Z"
+      android:fillColor="@color/nav_icon_fill_color" />
+  <group
+      android:translateX="30"
+      android:translateY="2">
+    <path
+        android:fillColor="@color/notification_unseen_color"
+        android:strokeWidth="1"
+        android:pathData="M 6 0 C 9.31370849898 0 12 2.68629150102 12 6 C 12 9.31370849898 9.31370849898 12 6 12 C 2.68629150102 12 0 9.31370849898 0 6 C 0 2.68629150102 2.68629150102 0 6 0 Z" />
+  </group>
+</vector>
diff --git a/tests/SecondaryHomeApp/res/drawable/nav_button_background.xml b/tests/SecondaryHomeApp/res/drawable/nav_button_background.xml
new file mode 100644
index 0000000..0c1bd93
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/drawable/nav_button_background.xml
@@ -0,0 +1,26 @@
+<?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
+  -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="@color/nav_bar_ripple_background_color">
+    <item android:id="@android:id/mask">
+        <shape android:shape="rectangle">
+            <solid android:color="?android:colorAccent"/>
+            <corners android:radius="6dp"/>
+        </shape>
+    </item>
+</ripple>
diff --git a/tests/SecondaryHomeApp/res/layout/activity_main.xml b/tests/SecondaryHomeApp/res/layout/activity_main.xml
new file mode 100644
index 0000000..1156f56
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/layout/activity_main.xml
@@ -0,0 +1,41 @@
+<?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
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/RootView"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/background_color"
+    android:fitsSystemWindows="true"
+    android:orientation="vertical" >
+
+    <FrameLayout
+        android:id="@+id/container"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1">
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/navigation_bar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom">
+      <include layout="@layout/car_navigation_bar"/>
+    </FrameLayout>
+</LinearLayout>
diff --git a/tests/SecondaryHomeApp/res/layout/app_fragment.xml b/tests/SecondaryHomeApp/res/layout/app_fragment.xml
new file mode 100644
index 0000000..3f778f5
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/layout/app_fragment.xml
@@ -0,0 +1,28 @@
+<?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.
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/app_fragment"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <ActivityView
+        android:id="@+id/app_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+</FrameLayout>
diff --git a/tests/SecondaryHomeApp/res/layout/app_grid_item.xml b/tests/SecondaryHomeApp/res/layout/app_grid_item.xml
new file mode 100644
index 0000000..df2b723
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/layout/app_grid_item.xml
@@ -0,0 +1,35 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center">
+
+    <ImageView
+        android:id="@+id/app_icon"
+        android:layout_width="@dimen/app_icon_width"
+        android:layout_height="@dimen/app_icon_height" />
+
+    <TextView
+        android:id="@+id/app_name"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:maxLines="1" />
+</LinearLayout>
diff --git a/tests/SecondaryHomeApp/res/layout/car_navigation_bar.xml b/tests/SecondaryHomeApp/res/layout/car_navigation_bar.xml
new file mode 100644
index 0000000..b494c3a
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/layout/car_navigation_bar.xml
@@ -0,0 +1,58 @@
+<?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
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:id="@+id/nav_bar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:gravity="center">
+
+        <ImageButton
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:id="@+id/nav_back"
+            android:src="@drawable/ic_arrow_back"
+            android:gravity="center"
+          />
+
+        <ImageButton
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:id="@+id/nav_home"
+            android:src="@drawable/ic_home"
+            android:gravity="center"
+          />
+
+          <ImageButton
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:id="@+id/nav_notification"
+            android:src="@drawable/ic_notification"
+            android:gravity="center"
+          />
+    </LinearLayout>
+</FrameLayout>
diff --git a/tests/SecondaryHomeApp/res/layout/home_fragment.xml b/tests/SecondaryHomeApp/res/layout/home_fragment.xml
new file mode 100644
index 0000000..6fe0c79
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/layout/home_fragment.xml
@@ -0,0 +1,35 @@
+<?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.
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/home_fragment"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/background_color"
+    android:layout_margin="@dimen/app_grid_margin_top">
+
+    <GridView
+        android:id="@+id/app_grid"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:columnWidth="@dimen/app_list_col_width"
+        android:verticalSpacing="@dimen/app_list_horizontal_spacing"
+        android:horizontalSpacing="@dimen/app_list_vertical_spacing"
+        android:numColumns="auto_fit"
+        android:name="app_grid" />
+</FrameLayout>
diff --git a/tests/SecondaryHomeApp/res/layout/notification_fragment.xml b/tests/SecondaryHomeApp/res/layout/notification_fragment.xml
new file mode 100644
index 0000000..217d6cc
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/layout/notification_fragment.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/notification_fragment"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <Button
+        android:id="@+id/clear_all_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/clear_all"
+        style="@style/ClearButton"/>
+
+    <ScrollView
+        android:id="@+id/debug_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginTop="50dp"
+        android:gravity="center_vertical">
+
+        <TextView
+            android:id="@+id/debug"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:textSize="32sp"
+            android:gravity="center_vertical"/>
+    </ScrollView>
+</FrameLayout>
diff --git a/tests/SecondaryHomeApp/res/values-af/strings.xml b/tests/SecondaryHomeApp/res/values-af/strings.xml
new file mode 100644
index 0000000..31ac308
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-af/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome-lanseerder"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Kon nie begin nie"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Vee alles uit"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-am/strings.xml b/tests/SecondaryHomeApp/res/values-am/strings.xml
new file mode 100644
index 0000000..e873c1e
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-am/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"የSecHome ማስጀመሪያ"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"ማስጀመር አልተቻለም"</string>
+    <string name="clear_all" msgid="7403807937179450743">"ሁሉንም አጽዳ"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-ar/strings.xml b/tests/SecondaryHomeApp/res/values-ar/strings.xml
new file mode 100644
index 0000000..9920b3c
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-ar/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"مشغّل التطبيقات SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"تعذّر فتح"</string>
+    <string name="clear_all" msgid="7403807937179450743">"محو الكل"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-as/strings.xml b/tests/SecondaryHomeApp/res/values-as/strings.xml
new file mode 100644
index 0000000..99bd16b
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-as/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome লঞ্চাৰ"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"লঞ্চ কৰিব পৰা নগ’ল"</string>
+    <string name="clear_all" msgid="7403807937179450743">"সকলো মচক"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-az/strings.xml b/tests/SecondaryHomeApp/res/values-az/strings.xml
new file mode 100644
index 0000000..78b6841
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-az/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Başladıcısı"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"İşə salmaq alınmadı"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Hamısını silin"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-b+sr+Latn/strings.xml b/tests/SecondaryHomeApp/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..f4db301
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Pokretač aplikacije SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Pokretanje nije uspelo"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Obriši sve"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-be/strings.xml b/tests/SecondaryHomeApp/res/values-be/strings.xml
new file mode 100644
index 0000000..526ae17
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-be/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Праграма запуску SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Не ўдалося запусціць"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Ачысціць усё"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-bg/strings.xml b/tests/SecondaryHomeApp/res/values-bg/strings.xml
new file mode 100644
index 0000000..e100da1
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-bg/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Стартов панел на SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Не можа да се стартира"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Изчистване на всичко"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-bn/strings.xml b/tests/SecondaryHomeApp/res/values-bn/strings.xml
new file mode 100644
index 0000000..7b0cc75
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-bn/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome লঞ্চার"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"শুরু করা যায়নি"</string>
+    <string name="clear_all" msgid="7403807937179450743">"সব মুছে দিন"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-bs/strings.xml b/tests/SecondaryHomeApp/res/values-bs/strings.xml
new file mode 100644
index 0000000..54b9ab3
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-bs/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Pokretač za SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Pokretanje nije uspjelo"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Obriši sve"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-ca/strings.xml b/tests/SecondaryHomeApp/res/values-ca/strings.xml
new file mode 100644
index 0000000..17f2514
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-ca/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"No s\'ha pogut iniciar"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Esborra-ho tot"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-cs/strings.xml b/tests/SecondaryHomeApp/res/values-cs/strings.xml
new file mode 100644
index 0000000..2a7a8bc
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-cs/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Nelze spustit"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Vymazat vše"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-da/strings.xml b/tests/SecondaryHomeApp/res/values-da/strings.xml
new file mode 100644
index 0000000..17df754
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-da/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome-starter"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Kunne ikke åbnes"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Ryd alt"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-de/strings.xml b/tests/SecondaryHomeApp/res/values-de/strings.xml
new file mode 100644
index 0000000..76c249f
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-de/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome-Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Konnte nicht gestartet werden"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Alle löschen"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-el/strings.xml b/tests/SecondaryHomeApp/res/values-el/strings.xml
new file mode 100644
index 0000000..8f9b5e9
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-el/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Εφαρμογή εκκίνησης SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Δεν ήταν δυνατή η εκκίνηση"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Διαγραφή όλων"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-en-rAU/strings.xml b/tests/SecondaryHomeApp/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..b4aaaf6
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-en-rAU/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Couldn\'t launch"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Clear all"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-en-rCA/strings.xml b/tests/SecondaryHomeApp/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..b4aaaf6
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-en-rCA/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Couldn\'t launch"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Clear all"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-en-rGB/strings.xml b/tests/SecondaryHomeApp/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..b4aaaf6
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-en-rGB/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Couldn\'t launch"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Clear all"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-en-rIN/strings.xml b/tests/SecondaryHomeApp/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..b4aaaf6
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-en-rIN/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Couldn\'t launch"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Clear all"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-en-rXC/strings.xml b/tests/SecondaryHomeApp/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..92ad83a
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-en-rXC/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‎‏‏‎‎‏‏‎‎‏‏‏‏‎‎‏‏‎‎‏‏‎‎‎‎‏‏‏‎‏‎‎‏‎‎‎‎‏‏‎‎‏‎‎‎‎‏‎‎‎‎‏‏‎‎SecondaryHomeApp‎‏‎‎‏‎"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‏‏‎‏‎‏‏‎‎‎‎‏‎‎‎‏‏‏‎‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‎‏‎‏‏‎‏‎‏‎‏‎‏‎‏‎‎‎SecHome Launcher‎‏‎‎‏‎"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‎‏‏‎‎‎‎‎Couldn\'t launch‎‏‎‎‏‎"</string>
+    <string name="clear_all" msgid="7403807937179450743">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‎‏‎‏‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‏‎‎‎‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‎Clear all‎‏‎‎‏‎"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-es-rUS/strings.xml b/tests/SecondaryHomeApp/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..fe9bd48
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-es-rUS/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"No se pudo iniciar"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Borrar todo"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-es/strings.xml b/tests/SecondaryHomeApp/res/values-es/strings.xml
new file mode 100644
index 0000000..450e6b1
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-es/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"No se ha podido iniciar"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Borrar todo"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-et/strings.xml b/tests/SecondaryHomeApp/res/values-et/strings.xml
new file mode 100644
index 0000000..2f2fa0e
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-et/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome\'i käivitusprogramm"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Ei õnnestunud käivitada"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Kustuta kõik"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-eu/strings.xml b/tests/SecondaryHomeApp/res/values-eu/strings.xml
new file mode 100644
index 0000000..c2039c3
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-eu/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Ezin izan da abiarazi"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Garbitu guztiak"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-fa/strings.xml b/tests/SecondaryHomeApp/res/values-fa/strings.xml
new file mode 100644
index 0000000..45ded85
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-fa/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"راه‌انداز SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"راه‌اندازی نشد"</string>
+    <string name="clear_all" msgid="7403807937179450743">"پاک کردن همه"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-fi/strings.xml b/tests/SecondaryHomeApp/res/values-fi/strings.xml
new file mode 100644
index 0000000..2868300
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-fi/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome-käynnistysohjelma"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Käynnistys epäonnistui"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Tyhjennä kaikki"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-fr-rCA/strings.xml b/tests/SecondaryHomeApp/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..e3dce12
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-fr-rCA/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Lanceur d\'applications SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Impossible d\'effectuer le lancement"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Tout effacer"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-fr/strings.xml b/tests/SecondaryHomeApp/res/values-fr/strings.xml
new file mode 100644
index 0000000..e3dce12
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-fr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Lanceur d\'applications SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Impossible d\'effectuer le lancement"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Tout effacer"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-gl/strings.xml b/tests/SecondaryHomeApp/res/values-gl/strings.xml
new file mode 100644
index 0000000..9dfbcb6
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-gl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Launcher de SecHom"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Non se puido iniciar"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Borrar todo"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-gu/strings.xml b/tests/SecondaryHomeApp/res/values-gu/strings.xml
new file mode 100644
index 0000000..9797bec
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-gu/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome લૉન્ચર"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"લૉન્ચ કરી શકાઈ નથી"</string>
+    <string name="clear_all" msgid="7403807937179450743">"બધું સાફ કરો"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-hi/strings.xml b/tests/SecondaryHomeApp/res/values-hi/strings.xml
new file mode 100644
index 0000000..ad89c0e
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-hi/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"सेकेंडरी होम ऐप्लिकेशन लॉन्चर"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"ऐप्लिकेशन नहीं खुल सका"</string>
+    <string name="clear_all" msgid="7403807937179450743">"सभी सूचनाएं हटाएं"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-hr/strings.xml b/tests/SecondaryHomeApp/res/values-hr/strings.xml
new file mode 100644
index 0000000..d1e736f
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-hr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Pokretač za SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Pokretanje nije uspjelo"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Izbriši sve"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-hu/strings.xml b/tests/SecondaryHomeApp/res/values-hu/strings.xml
new file mode 100644
index 0000000..654ca24
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-hu/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome-indító"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Nem sikerült elindítani"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Összes törlése"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-hy/strings.xml b/tests/SecondaryHomeApp/res/values-hy/strings.xml
new file mode 100644
index 0000000..bf7be1d
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-hy/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Չհաջողվեց գործարկել հավելվածը"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Ջնջել բոլորը"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-in/strings.xml b/tests/SecondaryHomeApp/res/values-in/strings.xml
new file mode 100644
index 0000000..1d1ed9b
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-in/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Peluncur SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Tidak dapat meluncurkan"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Hapus semua"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-is/strings.xml b/tests/SecondaryHomeApp/res/values-is/strings.xml
new file mode 100644
index 0000000..c077fe0
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-is/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Ekki tókst að ræsa"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Hreinsa allt"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-it/strings.xml b/tests/SecondaryHomeApp/res/values-it/strings.xml
new file mode 100644
index 0000000..c20aea8
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-it/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Avvio app SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Impossibile avviare"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Elimina tutto"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-iw/strings.xml b/tests/SecondaryHomeApp/res/values-iw/strings.xml
new file mode 100644
index 0000000..1ff23a1
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-iw/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"מרכז האפליקציות של SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"לא ניתן היה להפעיל"</string>
+    <string name="clear_all" msgid="7403807937179450743">"ניקוי הכול"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-ja/strings.xml b/tests/SecondaryHomeApp/res/values-ja/strings.xml
new file mode 100644
index 0000000..6b7c7bd
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-ja/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"起動できませんでした"</string>
+    <string name="clear_all" msgid="7403807937179450743">"すべて消去"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-ka/strings.xml b/tests/SecondaryHomeApp/res/values-ka/strings.xml
new file mode 100644
index 0000000..2dc6bcc
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-ka/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome-ის გამშვები"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"გაშვება ვერ მოხერხდა"</string>
+    <string name="clear_all" msgid="7403807937179450743">"ყველას გასუფთავება"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-kk/strings.xml b/tests/SecondaryHomeApp/res/values-kk/strings.xml
new file mode 100644
index 0000000..c85a83d
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-kk/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome іске қосқышы"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Іске қосылмады."</string>
+    <string name="clear_all" msgid="7403807937179450743">"Бәрін өшіру"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-km/strings.xml b/tests/SecondaryHomeApp/res/values-km/strings.xml
new file mode 100644
index 0000000..d7f4fc3
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-km/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"កម្មវិធីចាប់ផ្ដើម SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"មិនអាច​ចាប់ផ្ដើមបានទេ"</string>
+    <string name="clear_all" msgid="7403807937179450743">"សម្អាត​ទាំងអស់"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-kn/strings.xml b/tests/SecondaryHomeApp/res/values-kn/strings.xml
new file mode 100644
index 0000000..baa1b0b
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-kn/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome ಲಾಂಚರ್"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"ಪ್ರಾರಂಭಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
+    <string name="clear_all" msgid="7403807937179450743">"ಎಲ್ಲ ತೆಗೆ"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-ko/strings.xml b/tests/SecondaryHomeApp/res/values-ko/strings.xml
new file mode 100644
index 0000000..dd0ba23
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-ko/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"보조 Home 앱"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome 런처"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"실행할 수 없음"</string>
+    <string name="clear_all" msgid="7403807937179450743">"모두 삭제"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-ky/strings.xml b/tests/SecondaryHomeApp/res/values-ky/strings.xml
new file mode 100644
index 0000000..8c8b6f3
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-ky/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Жүргүзгүчү"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Иштетилген жок"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Баарын тазалоо"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-lo/strings.xml b/tests/SecondaryHomeApp/res/values-lo/strings.xml
new file mode 100644
index 0000000..771a7a7
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-lo/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"ຕົວເປີດໃຊ້ SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"ບໍ່ສາມາດເປີດໃຊ້ໄດ້"</string>
+    <string name="clear_all" msgid="7403807937179450743">"ລຶບລ້າງທັງໝົດ"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-lt/strings.xml b/tests/SecondaryHomeApp/res/values-lt/strings.xml
new file mode 100644
index 0000000..1313ab6
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-lt/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"„SecHome“ paleidimo priemonė"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Nepavyko paleisti"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Išvalyti viską"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-lv/strings.xml b/tests/SecondaryHomeApp/res/values-lv/strings.xml
new file mode 100644
index 0000000..be82a66
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-lv/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome palaišanas programma"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Nevarēja palaist"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Notīrīt visu"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-mk/strings.xml b/tests/SecondaryHomeApp/res/values-mk/strings.xml
new file mode 100644
index 0000000..645fed4
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-mk/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Стартер на SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Не можеше да се стартува"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Исчисти сѐ"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-ml/strings.xml b/tests/SecondaryHomeApp/res/values-ml/strings.xml
new file mode 100644
index 0000000..7642ab3
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-ml/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome ലോഞ്ചർ"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"ലോഞ്ച് ചെയ്യാനായില്ല"</string>
+    <string name="clear_all" msgid="7403807937179450743">"എല്ലാം മായ്‌ക്കുക"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-mn/strings.xml b/tests/SecondaryHomeApp/res/values-mn/strings.xml
new file mode 100644
index 0000000..dcf260e
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-mn/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome эхлүүлэгч"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Эхлүүлж чадсангүй"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Бүгдийг арилгах"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-mr/strings.xml b/tests/SecondaryHomeApp/res/values-mr/strings.xml
new file mode 100644
index 0000000..e4bcaab
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-mr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome लाँचर"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"लाँच करू शकलो नाही"</string>
+    <string name="clear_all" msgid="7403807937179450743">"सर्व साफ करा"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-ms/strings.xml b/tests/SecondaryHomeApp/res/values-ms/strings.xml
new file mode 100644
index 0000000..c90eeea
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-ms/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Pelancar SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Tidak dapat dilancarkan"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Kosongkan semua"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-my/strings.xml b/tests/SecondaryHomeApp/res/values-my/strings.xml
new file mode 100644
index 0000000..251d857
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-my/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"စတင်၍မရပါ"</string>
+    <string name="clear_all" msgid="7403807937179450743">"အားလုံးရှင်းရန်"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-nb/strings.xml b/tests/SecondaryHomeApp/res/values-nb/strings.xml
new file mode 100644
index 0000000..2476553
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-nb/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome-starter"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Kunne ikke starte"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Fjern alle"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-ne/strings.xml b/tests/SecondaryHomeApp/res/values-ne/strings.xml
new file mode 100644
index 0000000..73d5498
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-ne/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome लन्चर"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"सुरु गर्न सकिएन"</string>
+    <string name="clear_all" msgid="7403807937179450743">"सबै हटाउनुहोस्"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-nl/strings.xml b/tests/SecondaryHomeApp/res/values-nl/strings.xml
new file mode 100644
index 0000000..53776b7
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-nl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Kan niet starten"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Alles wissen"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-or/strings.xml b/tests/SecondaryHomeApp/res/values-or/strings.xml
new file mode 100644
index 0000000..4af4f6d
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-or/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome ଲଞ୍ଚର୍"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"ଲଞ୍ଚ କରାଯାଇପାରିଲା ନାହିଁ"</string>
+    <string name="clear_all" msgid="7403807937179450743">"ସବୁ ଖାଲି କରନ୍ତୁ"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-pa/strings.xml b/tests/SecondaryHomeApp/res/values-pa/strings.xml
new file mode 100644
index 0000000..e1f8b06
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-pa/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome ਲਾਂਚਰ"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"ਲਾਂਚ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string>
+    <string name="clear_all" msgid="7403807937179450743">"ਸਭ ਕਲੀਅਰ ਕਰੋ"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-pl/strings.xml b/tests/SecondaryHomeApp/res/values-pl/strings.xml
new file mode 100644
index 0000000..bcee38e
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-pl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Program uruchamiający aplikację SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Nie udało się uruchomić"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Wyczyść wszystko"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-pt-rPT/strings.xml b/tests/SecondaryHomeApp/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..1c071da
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-pt-rPT/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Launcher SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Não foi possível iniciar."</string>
+    <string name="clear_all" msgid="7403807937179450743">"Limpar tudo"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-pt/strings.xml b/tests/SecondaryHomeApp/res/values-pt/strings.xml
new file mode 100644
index 0000000..a6fc9f1
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-pt/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Tela de início do SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Não foi possível iniciar"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Limpar tudo"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-ro/strings.xml b/tests/SecondaryHomeApp/res/values-ro/strings.xml
new file mode 100644
index 0000000..abf6176
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-ro/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Lansator SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Nu s-a putut lansa"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Ștergeți tot"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-ru/strings.xml b/tests/SecondaryHomeApp/res/values-ru/strings.xml
new file mode 100644
index 0000000..b9ae187
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-ru/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Запуск SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Не удалось запустить приложение."</string>
+    <string name="clear_all" msgid="7403807937179450743">"Очистить"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-si/strings.xml b/tests/SecondaryHomeApp/res/values-si/strings.xml
new file mode 100644
index 0000000..8b43e23
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-si/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome දියත්කරණය"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"දියත් කිරීමට නොහැකි විය"</string>
+    <string name="clear_all" msgid="7403807937179450743">"සියල්ල හිස් කරන්න"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-sk/strings.xml b/tests/SecondaryHomeApp/res/values-sk/strings.xml
new file mode 100644
index 0000000..f92de0d
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-sk/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Nie je možné spustiť"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Vymazať všetko"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-sl/strings.xml b/tests/SecondaryHomeApp/res/values-sl/strings.xml
new file mode 100644
index 0000000..3688d59
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-sl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Zaganjalnik za SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Ni bilo mogoče zagnati"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Izbriši vse"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-sq/strings.xml b/tests/SecondaryHomeApp/res/values-sq/strings.xml
new file mode 100644
index 0000000..65f930b
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-sq/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Nisësi i SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Nuk mund të nisej"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Pastro të gjitha"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-sr/strings.xml b/tests/SecondaryHomeApp/res/values-sr/strings.xml
new file mode 100644
index 0000000..5841c55
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-sr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Покретач апликације SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Покретање није успело"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Обриши све"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-sv/strings.xml b/tests/SecondaryHomeApp/res/values-sv/strings.xml
new file mode 100644
index 0000000..dc94e44
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-sv/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Starten misslyckades"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Rensa alla"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-sw/strings.xml b/tests/SecondaryHomeApp/res/values-sw/strings.xml
new file mode 100644
index 0000000..3a55603
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-sw/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Kifungua Programu cha SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Imeshindwa kufungua programu"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Futa yote"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-ta/strings.xml b/tests/SecondaryHomeApp/res/values-ta/strings.xml
new file mode 100644
index 0000000..42b81d9
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-ta/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome தொடங்கி"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"தொடங்க முடியவில்லை"</string>
+    <string name="clear_all" msgid="7403807937179450743">"அனைத்தையும் அழி"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-te/strings.xml b/tests/SecondaryHomeApp/res/values-te/strings.xml
new file mode 100644
index 0000000..43e09f6
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-te/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome లాంచర్"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"ప్రారంభించడం సాధ్యపడలేదు"</string>
+    <string name="clear_all" msgid="7403807937179450743">"అన్నింటినీ క్లియర్ చేయి"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-th/strings.xml b/tests/SecondaryHomeApp/res/values-th/strings.xml
new file mode 100644
index 0000000..7f4f300
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-th/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Launcher ของ SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"เปิดไม่ได้"</string>
+    <string name="clear_all" msgid="7403807937179450743">"ล้างทั้งหมด"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-tl/strings.xml b/tests/SecondaryHomeApp/res/values-tl/strings.xml
new file mode 100644
index 0000000..3464112
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-tl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Hindi mailunsad"</string>
+    <string name="clear_all" msgid="7403807937179450743">"I-clear lahat"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-tr/strings.xml b/tests/SecondaryHomeApp/res/values-tr/strings.xml
new file mode 100644
index 0000000..8d60d4e
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-tr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Başlatıcı"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Başlatılamadı"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Tümünü temizle"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-uk/strings.xml b/tests/SecondaryHomeApp/res/values-uk/strings.xml
new file mode 100644
index 0000000..e0a65b5
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-uk/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Не вдалося запустити"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Очистити все"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-ur/strings.xml b/tests/SecondaryHomeApp/res/values-ur/strings.xml
new file mode 100644
index 0000000..1816a6a
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-ur/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome لانچر"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"لانچ نہیں ہو سکا"</string>
+    <string name="clear_all" msgid="7403807937179450743">"سبھی کو ہٹائیں"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-uz/strings.xml b/tests/SecondaryHomeApp/res/values-uz/strings.xml
new file mode 100644
index 0000000..4ace080
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-uz/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Ishga tushmadi"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Hammasini tozalash"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-vi/strings.xml b/tests/SecondaryHomeApp/res/values-vi/strings.xml
new file mode 100644
index 0000000..64cc1c1
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-vi/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"Trình khởi chạy SecHome"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Không thể khởi chạy"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Xóa tất cả"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-zh-rCN/strings.xml b/tests/SecondaryHomeApp/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..e91a39b
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-zh-rCN/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome 启动器"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"无法启动"</string>
+    <string name="clear_all" msgid="7403807937179450743">"全部清除"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-zh-rHK/strings.xml b/tests/SecondaryHomeApp/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..2aea956
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-zh-rHK/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome 啟動器"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"無法啟動"</string>
+    <string name="clear_all" msgid="7403807937179450743">"全部清除"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-zh-rTW/strings.xml b/tests/SecondaryHomeApp/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..2aea956
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-zh-rTW/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"SecHome 啟動器"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"無法啟動"</string>
+    <string name="clear_all" msgid="7403807937179450743">"全部清除"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values-zu/strings.xml b/tests/SecondaryHomeApp/res/values-zu/strings.xml
new file mode 100644
index 0000000..07af15e
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values-zu/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="1232190134475133062">"SecondaryHomeApp"</string>
+    <string name="app_launcher" msgid="3285007106222765396">"I-SecHome Launcher"</string>
+    <string name="launch_fail_msg" msgid="2935729218024647088">"Ayikwazanga ukuqalisa"</string>
+    <string name="clear_all" msgid="7403807937179450743">"Sula konke"</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values/colors.xml b/tests/SecondaryHomeApp/res/values/colors.xml
new file mode 100644
index 0000000..7d5b424
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values/colors.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <color name="background_color">#263238</color>
+    <color name="nav_icon_fill_color">#8Fffffff</color>
+    <color name="nav_bar_ripple_background_color">#40ffffff</color>
+    <color name="notification_unseen_color">#e25142</color>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values/dimens.xml b/tests/SecondaryHomeApp/res/values/dimens.xml
new file mode 100644
index 0000000..84ba801
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values/dimens.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <dimen name="app_list_col_width">72dp</dimen>
+    <dimen name="app_list_horizontal_spacing">24dp</dimen>
+    <dimen name="app_list_vertical_spacing">24dp</dimen>
+    <dimen name="app_icon_width">64dp</dimen>
+    <dimen name="app_icon_height">64dp</dimen>
+    <dimen name="app_grid_margin_top">24dp</dimen>
+    <dimen name="app_grid_margin_left">8dp</dimen>
+    <dimen name="app_grid_margin_right">8dp</dimen>
+    <dimen name="notification_title_bar_height">8dp</dimen>
+    <dimen name="notification_primary_icon_size">64dp</dimen>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values/strings.xml b/tests/SecondaryHomeApp/res/values/strings.xml
new file mode 100644
index 0000000..9fb8e87
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <string name="app_name">SecondaryHomeApp</string>
+    <string name="app_launcher">SecHome Launcher</string>
+    <string name="launch_fail_msg">Couldn\'t launch</string>
+    <string-array name="hidden_apps" translatable="false">
+        <item>com.android.car.secondaryhome</item>
+    </string-array>
+    <string name="clear_all">Clear all</string>
+</resources>
diff --git a/tests/SecondaryHomeApp/res/values/styles.xml b/tests/SecondaryHomeApp/res/values/styles.xml
new file mode 100644
index 0000000..03ef3dc
--- /dev/null
+++ b/tests/SecondaryHomeApp/res/values/styles.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <style name="LauncherTheme" parent="Theme.MaterialComponents.NoActionBar" >
+        <item name="android:windowShowWallpaper">true</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowTranslucentStatus">true</item>
+        <item name="android:windowTranslucentNavigation">true</item>
+        <item name="android:colorBackgroundCacheHint">@null</item>
+        <item name="android:windowBackground">@android:color/transparent</item>
+    </style>
+
+    <style name="NavigationBarButton">
+        <item name="android:layout_height">96dp</item>
+        <item name="android:layout_width">96dp</item>
+        <item name="android:background">@drawable/nav_button_background</item>
+    </style>
+        <style name="ClearButton">
+        <item name="android:layout_height">96dp</item>
+        <item name="android:layout_width">96dp</item>
+        <item name="android:background">@drawable/nav_button_background</item>
+    </style>
+</resources>
diff --git a/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/AppEntry.java b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/AppEntry.java
new file mode 100644
index 0000000..f77b6c9
--- /dev/null
+++ b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/AppEntry.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.secondaryhome.launcher;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.graphics.drawable.Drawable;
+
+import java.util.Comparator;
+
+/** An entry that represents a single activity that can be launched. */
+public final class AppEntry {
+    @NonNull
+    private final Intent mLaunchIntent;
+    @NonNull
+    private final String mLabel;
+    @Nullable
+    private final Drawable mIcon;
+
+    AppEntry(@NonNull ResolveInfo info, @NonNull PackageManager packageManager) {
+        mLabel = info.loadLabel(packageManager).toString();
+        mIcon = info.loadIcon(packageManager);
+        mLaunchIntent = new Intent().setComponent(new ComponentName(
+                info.activityInfo.packageName, info.activityInfo.name));
+    }
+
+    @NonNull String getLabel() {
+        return mLabel;
+    }
+
+    @Nullable Drawable getIcon() {
+        return mIcon;
+    }
+
+    @NonNull Intent getLaunchIntent() {
+        return mLaunchIntent;
+    }
+
+    @NonNull ComponentName getComponentName() {
+        return mLaunchIntent.getComponent();
+    }
+
+    @Override
+    public String toString() {
+        return mLabel;
+    }
+
+    public static final Comparator<AppEntry> AppNameComparator =
+            Comparator.comparing(AppEntry::getLabel, String::compareToIgnoreCase);
+}
diff --git a/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/AppFragment.java b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/AppFragment.java
new file mode 100644
index 0000000..a05beee
--- /dev/null
+++ b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/AppFragment.java
@@ -0,0 +1,262 @@
+/**
+ * Copyright (c) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.secondaryhome.launcher;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityManager.StackInfo;
+import android.app.ActivityView;
+import android.app.IActivityManager;
+import android.app.TaskStackBuilder;
+import android.app.TaskStackListener;
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.hardware.input.InputManager;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.Display;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.fragment.app.Fragment;
+
+import com.android.car.secondaryhome.R;
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * {@link Fragment} that contains an ActivityView to run embedded application
+ */
+public final class AppFragment extends Fragment {
+    public static final int INVALID_TASK_STACK_ID = -1;
+
+    private static final String TAG = "SecHome.AppFragment";
+
+    private final IActivityManager mAm;
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private int mVirtualDisplayId = Display.INVALID_DISPLAY;
+    @GuardedBy("mLock")
+    private int mTaskStackId = INVALID_TASK_STACK_ID;
+    private boolean mActivityViewReady;
+    private Intent mLaunchIntent;
+    private TaskListener mTaskListener;
+    private TaskStackBuilder mTaskStackBuilder;
+
+    private Activity mActivity;
+    private ActivityView mActivityView;
+    private int mHomeDisplayId = Display.INVALID_DISPLAY;
+
+    private final ActivityView.StateCallback mActivityViewCallback =
+            new ActivityView.StateCallback() {
+                @Override
+                public void onActivityViewReady(ActivityView view) {
+                    mActivityViewReady = true;
+                    view.startActivity(mLaunchIntent);
+                    synchronized (mLock) {
+                        try {
+                            mTaskStackId = mAm.getFocusedStackInfo().stackId;
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "cannot get new taskstackid in ActivityView.StateCallback");
+                        }
+                        mVirtualDisplayId = view.getVirtualDisplayId();
+                    }
+                }
+
+                @Override
+                public void onActivityViewDestroyed(ActivityView view) {
+                    mActivityViewReady = false;
+                }
+            };
+
+    public AppFragment() {
+        mAm = ActivityManager.getService();
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mActivity = getActivity();
+        mHomeDisplayId = mActivity.getWindowManager().getDefaultDisplay().getDisplayId();
+
+        mTaskListener = new TaskListener();
+        mTaskStackBuilder = TaskStackBuilder.create(mActivity);
+
+        try {
+            mAm.registerTaskStackListener(mTaskListener);
+        } catch (RemoteException e) {
+            mTaskListener = null;
+        }
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        View view = inflater.inflate(R.layout.app_fragment, container, false);
+        mActivityView = view.findViewById(R.id.app_view);
+        return view;
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (mActivityView != null && mActivityViewReady) {
+            try {
+                mActivityView.release();
+                mActivityView = null;
+                mActivityViewReady = false;
+            } catch (Exception e) {
+                Log.e(TAG, "Fail to release ActivityView");
+            }
+        }
+
+        if (mTaskListener != null) {
+            mLaunchIntent = null;
+            mTaskListener = null;
+            synchronized (mLock) {
+                mTaskStackId = INVALID_TASK_STACK_ID;
+                mVirtualDisplayId = Display.INVALID_DISPLAY;
+            }
+        }
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        // If task stack is not empty, launch the top intent
+        if (mTaskStackBuilder.getIntentCount() > 0) {
+            launchTopAppInActivityView();
+        }
+    }
+
+    private void launchTopAppInActivityView() {
+        try {
+            if (mTaskStackBuilder.getIntentCount() == 0) {
+                return;
+            }
+            mLaunchIntent = mTaskStackBuilder
+                    .editIntentAt(mTaskStackBuilder.getIntentCount() - 1);
+
+            if (mActivityView != null) {
+                // Set callback to launch the app when ActivityView is ready
+                mActivityView.setCallback(mActivityViewCallback);
+            } else if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "ActivityView is null ");
+            }
+        } catch (ActivityNotFoundException e) {
+            Log.e(TAG, "App activity not found ..", e);
+        }
+    }
+
+    public void addLaunchIntentToStack(Intent launchIntent) {
+        mTaskStackBuilder.addNextIntent(launchIntent);
+        launchTopAppInActivityView();
+    }
+
+    public void onBackButtonPressed() {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "onBackButtonPressed..");
+        }
+        if (mActivityView != null) {
+            performBackPress();
+        }
+    }
+
+    public int getTaskStackId() {
+        synchronized (mLock) {
+            return mTaskStackId;
+        }
+    }
+
+    private void performBackPress() {
+        InputManager im = mActivity.getSystemService(InputManager.class);
+        int displayId;
+        synchronized (mLock) {
+            displayId = mVirtualDisplayId;
+        }
+
+        im.injectInputEvent(createKeyEvent(KeyEvent.ACTION_DOWN,
+                KeyEvent.KEYCODE_BACK, displayId),
+                InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+        im.injectInputEvent(createKeyEvent(KeyEvent.ACTION_UP,
+                KeyEvent.KEYCODE_BACK, displayId),
+                InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+    }
+
+    private static KeyEvent createKeyEvent(int action, int code, int displayId) {
+        long when = SystemClock.uptimeMillis();
+        KeyEvent ev = new KeyEvent(when, when, action, code, /* repeat= */ 0,
+                /* metaState= */ 0, KeyCharacterMap.VIRTUAL_KEYBOARD, /* scancode= */ 0,
+                KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
+                InputDevice.SOURCE_KEYBOARD);
+        ev.setDisplayId(displayId);
+        return ev;
+    }
+
+    private boolean isTaskStackEmpty() {
+        synchronized (mLock) {
+            try {
+                return mAm.getAllStackInfos().stream().anyMatch(info
+                        -> (info.stackId == mTaskStackId && info.topActivity == null));
+            } catch (RemoteException e) {
+                Log.e(TAG, "cannot getFocusedStackInfos", e);
+                return true;
+            }
+        }
+    }
+
+    private final class TaskListener extends TaskStackListener {
+        @Override
+        public void onTaskStackChanged() {
+            StackInfo focusedStackInfo;
+            try {
+                focusedStackInfo = mAm.getFocusedStackInfo();
+            } catch (RemoteException e) {
+                Log.e(TAG, "cannot getFocusedStackInfo", e);
+                return;
+            }
+
+            // App could be exited in two ways, and HomeFragment should be shown
+            if (isTaskStackEmpty()) {
+                ((LauncherActivity) mActivity).navigateHome();
+                synchronized (mLock) {
+                    mTaskStackId = INVALID_TASK_STACK_ID;
+                }
+            }
+
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "OnTaskStackChanged: virtual display: "
+                        + mVirtualDisplayId + " homeDisplay: " + mHomeDisplayId
+                        + "\nFocused stack: " + focusedStackInfo);
+                try {
+                    for (StackInfo info: mAm.getAllStackInfos()) {
+                        Log.d(TAG, "    stackId: " + info.stackId + " displayId: "
+                                + info.displayId + " component: " + info.topActivity);
+                    }
+                } catch (RemoteException e) {
+                    Log.e(TAG, "cannot getFocusedStackInfos", e);
+                }
+            }
+        }
+    }
+}
diff --git a/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/AppListAdapter.java b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/AppListAdapter.java
new file mode 100644
index 0000000..a3f4ed3
--- /dev/null
+++ b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/AppListAdapter.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.secondaryhome.launcher;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.car.secondaryhome.R;
+
+import java.util.List;
+import java.util.Set;
+
+/** Adapter for available apps list. */
+public final class AppListAdapter extends ArrayAdapter<AppEntry> {
+    private final LayoutInflater mInflater;
+
+    AppListAdapter(@NonNull Context context) {
+        super(context, android.R.layout.simple_list_item_2);
+        mInflater = LayoutInflater.from(context);
+    }
+
+    /**
+     * Sets data for AppListAdaptor and exclude the app from  blackList
+     * @param data        List of {@link AppEntry}
+     * @param blackList   A (possibly empty but not null) list of apps (package names) to hide
+     */
+    void setData(@NonNull List<AppEntry> data, @NonNull Set<String> blackList) {
+        clear();
+
+        data.stream().filter(app -> !blackList.contains(app.getComponentName().getPackageName()))
+                .forEach(app -> add(app));
+
+        sort(AppEntry.AppNameComparator);
+    }
+
+    @Override
+    public View getView(@NonNull int position,
+            @Nullable View convertView,
+            @NonNull ViewGroup parent) {
+        View view;
+        if (convertView == null) {
+            view = mInflater.inflate(R.layout.app_grid_item, parent, false);
+        } else {
+            view = convertView;
+        }
+
+        AppEntry item = getItem(position);
+        if (item != null) {
+            ((ImageView) view.findViewById(R.id.app_icon)).setImageDrawable(item.getIcon());
+            ((TextView) view.findViewById(R.id.app_name)).setText(item.getLabel());
+        }
+        return view;
+    }
+}
diff --git a/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/AppListLiveData.java b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/AppListLiveData.java
new file mode 100644
index 0000000..e1540ae
--- /dev/null
+++ b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/AppListLiveData.java
@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.secondaryhome.launcher;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.AsyncTask;
+
+import androidx.lifecycle.LiveData;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public final class AppListLiveData extends LiveData<List<AppEntry>> {
+
+    private final PackageManager mPackageManager;
+    private int mCurrentDataVersion;
+
+    AppListLiveData(@NonNull Context context) {
+        mPackageManager = context.getPackageManager();
+        loadData();
+    }
+
+    protected void loadData() {
+        int loadDataVersion = ++mCurrentDataVersion;
+
+        new AsyncTask<Void, Void, List<AppEntry>>() {
+            @Override
+            protected List<AppEntry> doInBackground(Void... voids) {
+                Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+                mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+
+                List<ResolveInfo> apps = mPackageManager.queryIntentActivities(mainIntent,
+                        PackageManager.GET_META_DATA);
+
+                if (apps == null) return Collections.emptyList();
+
+                List<AppEntry> entries = new ArrayList(apps.size());
+                apps.stream().forEach(app -> entries.add(new AppEntry(app, mPackageManager)));
+
+                return entries;
+            }
+
+            @Override
+            protected void onPostExecute(List<AppEntry> data) {
+                if (mCurrentDataVersion == loadDataVersion) {
+                    setValue(data);
+                }
+            }
+        }.execute();
+    }
+}
+
diff --git a/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/AppListViewModel.java b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/AppListViewModel.java
new file mode 100644
index 0000000..f94b96d
--- /dev/null
+++ b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/AppListViewModel.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.secondaryhome.launcher;
+
+import android.annotation.NonNull;
+import android.app.Application;
+
+import androidx.lifecycle.AndroidViewModel;
+import androidx.lifecycle.LiveData;
+
+import java.util.List;
+
+/**
+ * A view model that provides a list of activities that can be launched.
+ */
+public final class AppListViewModel extends AndroidViewModel {
+
+    @NonNull
+    private final AppListLiveData mAppList;
+    @NonNull
+    private final PackageIntentReceiver mPackageIntentReceiver;
+
+    public AppListViewModel(Application application) {
+        super(application);
+        mAppList = new AppListLiveData(application);
+        mPackageIntentReceiver = new PackageIntentReceiver(mAppList, application);
+    }
+
+    public LiveData<List<AppEntry>> getAppList() {
+        return mAppList;
+    }
+
+    @Override
+    protected void onCleared() {
+        getApplication().unregisterReceiver(mPackageIntentReceiver);
+    }
+}
diff --git a/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/AppPickedCallback.java b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/AppPickedCallback.java
new file mode 100644
index 0000000..fb06350
--- /dev/null
+++ b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/AppPickedCallback.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.secondaryhome.launcher;
+
+import android.annotation.NonNull;
+
+/**
+ * Callback to be invoked when an app was picked.
+ */
+interface AppPickedCallback {
+    void onAppPicked(@NonNull AppEntry appEntry);
+}
+
diff --git a/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/HomeFragment.java b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/HomeFragment.java
new file mode 100644
index 0000000..1a8ef85
--- /dev/null
+++ b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/HomeFragment.java
@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.secondaryhome.launcher;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.GridView;
+
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.lifecycle.ViewModelProviders;
+
+import com.android.car.secondaryhome.R;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * {@link Fragment} that shows a grid of app installed.
+ * It will launch app into AppFragment.
+ * Note: a new task will be launched every time for app to run in multiple display.
+ */
+public final class HomeFragment extends Fragment {
+    private static final String TAG = "SecHome.HomeFragment";
+
+    private final Set<String> mHiddenApps = new HashSet<>();
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+
+        View view = inflater.inflate(R.layout.home_fragment, container, false);
+        GridView gridView = view.findViewById(R.id.app_grid);
+
+        FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
+        AppListAdapter appListAdapter = new AppListAdapter(getActivity());
+
+        gridView.setAdapter(appListAdapter);
+        gridView.setOnItemClickListener((adapterView, v, position, id) -> {
+            AppEntry entry = appListAdapter.getItem(position);
+            AppFragment mAppFragment = (AppFragment) fragmentManager
+                    .findFragmentByTag(((LauncherActivity) getActivity()).APP_FRAGMENT_TAG);
+
+            if (mAppFragment != null) {
+                // Equivalent to setting in AndroidManifest: documentLaunchMode="always"
+                Intent newIntent = entry.getLaunchIntent()
+                        .setFlags(~Intent.FLAG_ACTIVITY_SINGLE_TOP)
+                        .addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT
+                                | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+                mAppFragment.addLaunchIntentToStack(newIntent);
+                ((LauncherActivity) getActivity()).navigateApp();
+
+            } else if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "AppFragment is not found...");
+            }
+        });
+
+        AppListViewModel appListViewModel = ViewModelProviders.of(this)
+                .get(AppListViewModel.class);
+
+        mHiddenApps.addAll(Arrays.asList(getResources().getStringArray(R.array.hidden_apps)));
+        appListViewModel.getAppList().observe(this, data ->
+                appListAdapter.setData(data, mHiddenApps));
+        return view;
+    }
+}
diff --git a/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/LauncherActivity.java b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/LauncherActivity.java
new file mode 100644
index 0000000..89f013f
--- /dev/null
+++ b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/LauncherActivity.java
@@ -0,0 +1,140 @@
+/**
+ * Copyright (c) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.secondaryhome.launcher;
+
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.ImageButton;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+import com.android.car.secondaryhome.R;
+
+/**
+ * Main launcher activity.
+ * It contains a navigation bar with BACK and HOME buttons.
+ */
+public final class LauncherActivity extends AppCompatActivity {
+    public static final String APP_FRAGMENT_TAG = "app";
+    public static final String HOME_FRAGMENT_TAG = "home";
+    public static final String NOTIFICATION_FRAGMENT_TAG = "notification";
+    private static final String TAG = "SecHome.LauncherActivity";
+
+    private final AppFragment mAppFragment = new AppFragment();
+    private final HomeFragment mHomeFragment = new HomeFragment();
+    private final NotificationFragment mNotificationFragment =
+            new NotificationFragment();
+
+    private String mLastFragment = HOME_FRAGMENT_TAG;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.activity_main);
+
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "Secondary home activity created...");
+        }
+
+        getSupportFragmentManager().beginTransaction()
+            .add(R.id.container, mAppFragment, APP_FRAGMENT_TAG)
+            .commit();
+
+        getSupportFragmentManager().beginTransaction()
+            .add(R.id.container, mHomeFragment, HOME_FRAGMENT_TAG)
+            .commit();
+
+        getSupportFragmentManager().beginTransaction()
+            .add(R.id.container, mNotificationFragment, NOTIFICATION_FRAGMENT_TAG)
+            .commit();
+
+        ImageButton backButton = findViewById(R.id.nav_back);
+        backButton.setOnClickListener(view -> onBackButtonPressed());
+        ImageButton homeButton = findViewById(R.id.nav_home);
+        homeButton.setOnClickListener(view -> navigateHome());
+        ImageButton notificationButton = findViewById(R.id.nav_notification);
+        notificationButton.setOnClickListener(view -> toggleNotification());
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        navigateHome();
+    }
+
+    private void onBackButtonPressed() {
+        // When BACK is pressed, if HomeFragment is shown
+        // and AppFragment's has valid and non-empty task stack, navigate to AppFragment;
+        // if AppFragment is shown, pop from stack on AppFragment;
+        // if NotificationFragment is shown, navigate to previous fragment.
+        if (mHomeFragment.isVisible()
+                && mAppFragment.getTaskStackId() != AppFragment.INVALID_TASK_STACK_ID) {
+            navigateApp();
+        } else if (mAppFragment.isVisible()) {
+            mAppFragment.onBackButtonPressed();
+        } else if (mNotificationFragment.isVisible()) {
+            toggleNotification();
+        }
+    }
+
+    public void navigateHome() {
+        getSupportFragmentManager().beginTransaction()
+            .show(mHomeFragment)
+            .commit();
+        getSupportFragmentManager().beginTransaction()
+            .hide(mAppFragment)
+            .commit();
+        getSupportFragmentManager().beginTransaction()
+            .hide(mNotificationFragment)
+            .commit();
+
+        mLastFragment = HOME_FRAGMENT_TAG;
+    }
+
+    public void navigateApp() {
+        getSupportFragmentManager().beginTransaction()
+            .hide(mHomeFragment)
+            .commit();
+        getSupportFragmentManager().beginTransaction()
+            .show(mAppFragment)
+            .commit();
+        getSupportFragmentManager().beginTransaction()
+            .hide(mNotificationFragment)
+            .commit();
+
+        mLastFragment = APP_FRAGMENT_TAG;
+    }
+
+    public void toggleNotification() {
+        if (!mNotificationFragment.isVisible()) {
+            getSupportFragmentManager().beginTransaction()
+                .hide(mHomeFragment)
+                .commit();
+            getSupportFragmentManager().beginTransaction()
+                .hide(mAppFragment)
+                .commit();
+            getSupportFragmentManager().beginTransaction()
+                .show(mNotificationFragment)
+                .commit();
+        } else if (mLastFragment.equals(HOME_FRAGMENT_TAG)) {
+            navigateHome();
+        } else {
+            navigateApp();
+        }
+    }
+}
diff --git a/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/NotificationFragment.java b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/NotificationFragment.java
new file mode 100644
index 0000000..64c20d2
--- /dev/null
+++ b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/NotificationFragment.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.secondaryhome.launcher;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+import androidx.fragment.app.Fragment;
+
+import com.android.car.notification.PreprocessingManager;
+import com.android.car.secondaryhome.R;
+
+/**
+ * {@link Fragment} that shows list of notifications.
+ */
+public final class NotificationFragment extends Fragment {
+
+    private static final String TAG = "SecHome.NotificationFragment";
+
+    private NotificationListener mNotificationListener;
+    private PreprocessingManager mPreprocessingManager;
+    private NotificationViewController mNotificationViewController;
+    private Context mContext;
+    private View mNotificationView;
+    private Button mClearAllButton;
+
+    private final ServiceConnection mNotificationListenerConnection = new ServiceConnection() {
+        public void onServiceConnected(ComponentName className, IBinder binder) {
+            Log.d(TAG, "onServiceConnected");
+            mNotificationListener = ((NotificationListener.LocalBinder) binder).getService();
+            mNotificationListener.registerAsSystemService(mContext);
+            mNotificationViewController =
+                    new NotificationViewController(mNotificationView,
+                            mPreprocessingManager,
+                            mNotificationListener);
+            mNotificationViewController.enable();
+        }
+
+        public void onServiceDisconnected(ComponentName className) {
+            Log.d(TAG, "onServiceDisconnected");
+            mNotificationViewController.disable();
+            mNotificationViewController = null;
+            mNotificationListener = null;
+        }
+    };
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mContext = getActivity().getApplicationContext();
+        mPreprocessingManager = PreprocessingManager.getInstance(mContext);
+        Intent intent = new Intent(mContext, NotificationListener.class);
+        intent.setAction(NotificationListener.ACTION_LOCAL_BINDING);
+
+        mContext.bindService(intent, mNotificationListenerConnection,
+                Context.BIND_AUTO_CREATE);
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        View view = inflater.inflate(R.layout.notification_fragment, container, false);
+        mNotificationView = view.findViewById(R.id.notification_fragment);
+        mClearAllButton = view.findViewById(R.id.clear_all_button);
+        mClearAllButton.setOnClickListener(v -> mNotificationViewController.resetNotifications());
+
+        return view;
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        // Unbind notification listener
+        mNotificationViewController.disable();
+        mNotificationViewController = null;
+        mNotificationListener = null;
+        mContext.unbindService(mNotificationListenerConnection);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        Log.d(TAG, "Resuming notification fragment");
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        Log.d(TAG, "Pausing notification fragment");
+    }
+}
diff --git a/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/NotificationListener.java b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/NotificationListener.java
new file mode 100644
index 0000000..fb106e1
--- /dev/null
+++ b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/NotificationListener.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.secondaryhome.launcher;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+
+import com.android.car.notification.AlertEntry;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * NotificationListenerService that fetches all notifications from system.
+ * Copied from {@link CarNotificationListener} since {@link CarNotificationListener}
+ * cannot be used outside that package.
+*/
+public class NotificationListener extends NotificationListenerService {
+    private static final String TAG = "SecHome.NotificationListener";
+    public static final String ACTION_LOCAL_BINDING = "local_binding";
+    public static final int NOTIFY_NOTIFICATION_POSTED = 1;
+    public static final int NOTIFY_NOTIFICATION_REMOVED = 2;
+
+    private final int mUserId = Process.myUserHandle().getIdentifier();
+
+    private Handler mHandler;
+
+    /**
+     * Map that contains all the active notifications. They will be removed from the map
+     * when the {@link NotificationListenerService} calls the onNotificationRemoved method.
+     */
+    private Map<String, AlertEntry> mActiveNotifications = new HashMap<>();
+
+    /**
+     * Call this to register this service as a system service.
+     *
+     * @param context Context required for registering the service.
+     */
+
+    public void registerAsSystemService(Context context) {
+        try {
+            Log.d(TAG, "register as system service for: " + mUserId);
+            registerAsSystemService(context,
+                    new ComponentName(context.getPackageName(),
+                    getClass().getCanonicalName()),
+                    Process.myUid());
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to register notification listener", e);
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        Log.d("TAG", "onBind");
+        return ACTION_LOCAL_BINDING.equals(intent.getAction())
+                ? new LocalBinder() : super.onBind(intent);
+    }
+
+    @Override
+    public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
+        Log.d(TAG, "onNotificationPosted: " + sbn);
+        if (!isNotificationForCurrentUser(sbn)) {
+            return;
+        }
+        AlertEntry alertEntry = new AlertEntry(sbn);
+        notifyNotificationPosted(alertEntry);
+    }
+
+    @Override
+    public void onNotificationRemoved(StatusBarNotification sbn) {
+        Log.d(TAG, "onNotificationRemoved: " + sbn);
+        AlertEntry alertEntry = mActiveNotifications.get(sbn.getKey());
+        if (alertEntry != null) {
+            removeNotification(alertEntry);
+        }
+    }
+
+    /**
+     * Get all active notifications
+     *
+     * @return a map of all active notifications with key being the notification key.
+     */
+    Map<String, AlertEntry> getNotifications() {
+        return mActiveNotifications.entrySet().stream()
+                .filter(x -> (isNotificationForCurrentUser(
+                        x.getValue().getStatusBarNotification())))
+                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+    }
+
+    @Override
+    public void onListenerConnected() {
+        mActiveNotifications = Stream.of(getActiveNotifications()).collect(
+                Collectors.toMap(StatusBarNotification::getKey, sbn -> new AlertEntry(sbn)));
+    }
+
+    @Override
+    public void onListenerDisconnected() {
+    }
+
+    public void setHandler(Handler handler) {
+        mHandler = handler;
+    }
+
+    private void notifyNotificationPosted(AlertEntry alertEntry) {
+        postNewNotification(alertEntry);
+    }
+
+    private boolean isNotificationForCurrentUser(StatusBarNotification sbn) {
+        return (sbn.getUser().getIdentifier() == mUserId
+                || sbn.getUser().getIdentifier() == UserHandle.USER_ALL);
+    }
+
+    class LocalBinder extends Binder {
+        public NotificationListener getService() {
+            return NotificationListener.this;
+        }
+    }
+
+    private void postNewNotification(AlertEntry alertEntry) {
+        mActiveNotifications.put(alertEntry.getKey(), alertEntry);
+        sendNotificationEventToHandler(alertEntry, NOTIFY_NOTIFICATION_POSTED);
+    }
+
+    private void removeNotification(AlertEntry alertEntry) {
+        mActiveNotifications.remove(alertEntry.getKey());
+        sendNotificationEventToHandler(alertEntry, NOTIFY_NOTIFICATION_REMOVED);
+    }
+
+    private void sendNotificationEventToHandler(AlertEntry alertEntry, int eventType) {
+        if (mHandler == null) {
+            return;
+        }
+        Message msg = Message.obtain(mHandler);
+        msg.what = eventType;
+        msg.obj = alertEntry;
+        mHandler.sendMessage(msg);
+    }
+}
diff --git a/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/NotificationViewController.java b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/NotificationViewController.java
new file mode 100644
index 0000000..ad096a6
--- /dev/null
+++ b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/NotificationViewController.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.secondaryhome.launcher;
+
+import android.app.Notification;
+import android.os.Handler;
+import android.os.Message;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.car.notification.AlertEntry;
+import com.android.car.notification.PreprocessingManager;
+import com.android.car.secondaryhome.R;
+
+/**
+ * This object will handle updating notification view.
+ * Each Notification should be shown on CarUiRecyclerView.
+ */
+public class NotificationViewController {
+    private static final String TAG = "NotificationViewControl";
+    private final View mCarNotificationView;
+    private final NotificationListener mCarNotificationListener;
+    private final NotificationUpdateHandler mNotificationUpdateHandler =
+            new NotificationUpdateHandler();
+    private final PreprocessingManager mPreprocessingManager;
+    private final TextView mTextBox;
+
+    public NotificationViewController(View carNotificationView,
+            PreprocessingManager preprocessingManager,
+            NotificationListener carNotificationListener) {
+        mCarNotificationView = carNotificationView;
+        mCarNotificationListener = carNotificationListener;
+        mPreprocessingManager = preprocessingManager;
+        mTextBox = mCarNotificationView.findViewById(R.id.debug);
+        resetNotifications();
+    }
+
+    /**
+     * Set handler to NotificationListener
+     */
+    public void enable() {
+        if (mCarNotificationListener != null) {
+            mCarNotificationListener.setHandler(mNotificationUpdateHandler);
+        }
+    }
+
+    /**
+     * Remove handler
+     */
+    public void disable() {
+        if (mCarNotificationListener != null) {
+            mCarNotificationListener.setHandler(null);
+        }
+    }
+
+    /**
+     * Update notifications: print to text box
+     */
+    private void updateNotifications(int what, AlertEntry alertEntry) {
+        // filter out navigation notification, otherwise it will spam
+        if (Notification.CATEGORY_NAVIGATION.equals(
+                    alertEntry.getNotification().category)) {
+            return;
+        }
+
+        mTextBox.append("New: " + alertEntry.getStatusBarNotification() + "\n");
+    }
+
+    /**
+    * Reset notifications to the latest state.
+    */
+    public void resetNotifications() {
+        mPreprocessingManager.init(
+                mCarNotificationListener.getNotifications(),
+                mCarNotificationListener.getCurrentRanking());
+
+        mPreprocessingManager.process(
+                true /* showLessImportantNotifications */,
+                mCarNotificationListener.getNotifications(),
+                mCarNotificationListener.getCurrentRanking());
+        mTextBox.setText("");
+    }
+
+    private class NotificationUpdateHandler extends Handler {
+        @Override
+        public void handleMessage(Message message) {
+            updateNotifications(message.what, (AlertEntry) message.obj);
+        }
+    }
+}
diff --git a/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/PackageIntentReceiver.java b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/PackageIntentReceiver.java
new file mode 100644
index 0000000..cca2fec
--- /dev/null
+++ b/tests/SecondaryHomeApp/src/com/android/car/secondaryhome/launcher/PackageIntentReceiver.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.secondaryhome.launcher;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+/**
+ * Receiver used to notify live data about app list changes.
+ */
+public final class PackageIntentReceiver extends BroadcastReceiver {
+
+    private final AppListLiveData mLiveData;
+
+    PackageIntentReceiver(AppListLiveData liveData, Context context) {
+        mLiveData = liveData;
+        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        filter.addDataScheme("package");
+        context.registerReceiver(this, filter);
+
+        // Register for events related to sdcard installation.
+        IntentFilter sdFilter = new IntentFilter();
+        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+        context.registerReceiver(this, sdFilter);
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        mLiveData.loadData();
+    }
+}
diff --git a/tests/ThemePlayground/Android.bp b/tests/ThemePlayground/Android.bp
new file mode 100644
index 0000000..78ef6ea
--- /dev/null
+++ b/tests/ThemePlayground/Android.bp
@@ -0,0 +1,47 @@
+//
+// 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.
+//
+
+android_app {
+    name: "ThemePlayground",
+
+    aaptflags: ["--auto-add-overlay"],
+
+    srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
+
+    static_libs: [
+        "androidx.recyclerview_recyclerview",
+        "androidx.transition_transition",
+        "androidx.legacy_legacy-support-v4",
+        "androidx-constraintlayout_constraintlayout",
+        "androidx-constraintlayout_constraintlayout-solver",
+        "car-apps-common",
+        "car-ui-lib",
+    ],
+
+    owner: "google",
+    platform_apis: true,
+    certificate: "platform",
+    privileged: true,
+
+    optimize: {
+        enabled: false,
+    },
+
+    libs: ["android.car"],
+
+    required: ["privapp_whitelist_com.android.car.themeplayground"],
+}
diff --git a/tests/ThemePlayground/Android.mk b/tests/ThemePlayground/Android.mk
deleted file mode 100644
index 1247765..0000000
--- a/tests/ThemePlayground/Android.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_AAPT_FLAGS := --auto-add-overlay
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_STATIC_ANDROID_LIBRARIES += \
-    androidx.recyclerview_recyclerview \
-    androidx.transition_transition \
-    androidx.legacy_legacy-support-v4 \
-    androidx-constraintlayout_constraintlayout
-
-LOCAL_MODULE_OWNER := google
-LOCAL_PACKAGE_NAME := ThemePlayground
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
-LOCAL_STATIC_JAVA_LIBRARIES := \
-         androidx-constraintlayout_constraintlayout-solver
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_JAVA_LIBRARIES += android.car
-
-LOCAL_REQUIRED_MODULES := privapp_whitelist_com.android.car.themeplayground
-
-include $(BUILD_PACKAGE)
diff --git a/tests/ThemePlayground/AndroidManifest.xml b/tests/ThemePlayground/AndroidManifest.xml
index efaf6e9..d009859 100644
--- a/tests/ThemePlayground/AndroidManifest.xml
+++ b/tests/ThemePlayground/AndroidManifest.xml
@@ -58,6 +58,10 @@
                   android:label="@string/recycler_view"
                   android:parentActivityName="com.android.car.themeplayground.TextSamples">
         </activity>
+        <activity android:name=".CarUiRecyclerViewSamples"
+            android:label="@string/car_ui_recycler_view"
+            android:parentActivityName="com.android.car.themeplayground.TextSamples">
+        </activity>
         <activity android:name=".DefaultThemeSamples"
                   android:label="@string/default_themes"
                   android:parentActivityName="com.android.car.themeplayground.TextSamples">
diff --git a/tests/ThemePlayground/res/layout/paged_recycler_view_samples.xml b/tests/ThemePlayground/res/layout/paged_recycler_view_samples.xml
new file mode 100644
index 0000000..c59f237
--- /dev/null
+++ b/tests/ThemePlayground/res/layout/paged_recycler_view_samples.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+  <com.android.car.ui.recyclerview.CarUiRecyclerView
+      android:id="@+id/list"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"/>
+  <include layout="@layout/menu_button"/>
+</LinearLayout>
diff --git a/tests/ThemePlayground/res/menu/menu_main.xml b/tests/ThemePlayground/res/menu/menu_main.xml
index 08168c0..bd175e4 100644
--- a/tests/ThemePlayground/res/menu/menu_main.xml
+++ b/tests/ThemePlayground/res/menu/menu_main.xml
@@ -42,6 +42,10 @@
         android:orderInCategory="100"
         android:title="@string/recycler_view"/>
     <item
+        android:id="@+id/car_ui_recycler_view"
+        android:orderInCategory="100"
+        android:title="@string/car_ui_recycler_view"/>
+    <item
         android:id="@+id/default_themes"
         android:orderInCategory="100"
         android:title="@string/default_themes"/>
diff --git a/tests/ThemePlayground/res/values/strings.xml b/tests/ThemePlayground/res/values/strings.xml
index 0a329b5..39d1b68 100644
--- a/tests/ThemePlayground/res/values/strings.xml
+++ b/tests/ThemePlayground/res/values/strings.xml
@@ -22,7 +22,8 @@
     <string name="toggle_theme" translatable="false">Change configuration(Day/Night)</string>
     <string name="apply" translatable="false">Apply</string>
     <string name="widgets" translatable="false">Widgets</string>
-    <string name="recycler_view" translatable="false">Recycler List View</string>
+    <string name="recycler_view" translatable="false">Recycler View</string>
+    <string name="car_ui_recycler_view" translatable="false">Car UI Recycler View</string>
     <string name="widget_checkbox" translatable="false">Checkbox</string>
     <string name="toggle_switch" translatable="false">Toggle Switch</string>
     <string name="reset" translatable="false">Reset</string>
diff --git a/tests/ThemePlayground/src/com/android/car/themeplayground/AbstractSampleActivity.java b/tests/ThemePlayground/src/com/android/car/themeplayground/AbstractSampleActivity.java
index a55bbbf..7ed53b8 100644
--- a/tests/ThemePlayground/src/com/android/car/themeplayground/AbstractSampleActivity.java
+++ b/tests/ThemePlayground/src/com/android/car/themeplayground/AbstractSampleActivity.java
@@ -62,6 +62,8 @@
                 return startSampleActivity(WidgetsSamples.class);
             case R.id.recycler_view:
                 return startSampleActivity(RecyclerViewSamples.class);
+            case R.id.car_ui_recycler_view:
+                return startSampleActivity(CarUiRecyclerViewSamples.class);
             case R.id.default_themes:
                 return startSampleActivity(DefaultThemeSamples.class);
             case R.id.multiple_intent:
diff --git a/tests/ThemePlayground/src/com/android/car/themeplayground/CarUiRecyclerViewSamples.java b/tests/ThemePlayground/src/com/android/car/themeplayground/CarUiRecyclerViewSamples.java
new file mode 100644
index 0000000..09b58be
--- /dev/null
+++ b/tests/ThemePlayground/src/com/android/car/themeplayground/CarUiRecyclerViewSamples.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.themeplayground;
+
+import android.os.Bundle;
+
+import com.android.car.ui.recyclerview.CarUiRecyclerView;
+
+import java.util.ArrayList;
+
+/**
+ * Activity that shows PagedRecyclerView example with dummy data.
+ */
+public class CarUiRecyclerViewSamples extends AbstractSampleActivity {
+
+    private final ArrayList<String> mData = new ArrayList<>();
+    private final int mDataToGenerate = 15;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Utils.onActivityCreateSetTheme(this);
+        setContentView(R.layout.paged_recycler_view_samples);
+        CarUiRecyclerView recyclerView = findViewById(R.id.list);
+        RecyclerViewAdapter adapter = new RecyclerViewAdapter(generateDummyData());
+        recyclerView.setAdapter(adapter);
+    }
+
+    private ArrayList<String> generateDummyData() {
+        for (int i = 0; i <= mDataToGenerate; i++) {
+            mData.add("data" + i);
+        }
+        return mData;
+    }
+}
diff --git a/tests/UserSwitchMonitorApp/Android.bp b/tests/UserSwitchMonitorApp/Android.bp
new file mode 100644
index 0000000..354eb55
--- /dev/null
+++ b/tests/UserSwitchMonitorApp/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_app {
+    name: "UserSwitchMonitorApp",
+
+    libs: [
+        "android.car-system-stubs",
+    ],
+
+    srcs: ["src/**/*.java"],
+
+    sdk_version: "system_current",
+}
diff --git a/tests/UserSwitchMonitorApp/AndroidManifest.xml b/tests/UserSwitchMonitorApp/AndroidManifest.xml
new file mode 100644
index 0000000..e78d690
--- /dev/null
+++ b/tests/UserSwitchMonitorApp/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.google.android.car.userswitchmonitor">
+
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
+
+    <application android:label="User Switch Monitor">
+        <service android:name=".UserSwitchMonitorService"/>
+        <receiver android:name=".BootCompletedReceiver" android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.BOOT_COMPLETED"/>
+            </intent-filter>
+        </receiver>
+    </application>
+</manifest>
diff --git a/tests/UserSwitchMonitorApp/res/drawable-hdpi/ic_launcher.png b/tests/UserSwitchMonitorApp/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..96a442e
--- /dev/null
+++ b/tests/UserSwitchMonitorApp/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/tests/UserSwitchMonitorApp/res/drawable-ldpi/ic_launcher.png b/tests/UserSwitchMonitorApp/res/drawable-ldpi/ic_launcher.png
new file mode 100644
index 0000000..9923872
--- /dev/null
+++ b/tests/UserSwitchMonitorApp/res/drawable-ldpi/ic_launcher.png
Binary files differ
diff --git a/tests/UserSwitchMonitorApp/res/drawable-mdpi/ic_launcher.png b/tests/UserSwitchMonitorApp/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..359047d
--- /dev/null
+++ b/tests/UserSwitchMonitorApp/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/tests/UserSwitchMonitorApp/res/drawable-xhdpi/ic_launcher.png b/tests/UserSwitchMonitorApp/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..71c6d76
--- /dev/null
+++ b/tests/UserSwitchMonitorApp/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/UserSwitchMonitorApp/src/com/google/android/car/userswitchmonitor/BootCompletedReceiver.java b/tests/UserSwitchMonitorApp/src/com/google/android/car/userswitchmonitor/BootCompletedReceiver.java
new file mode 100644
index 0000000..812fab6
--- /dev/null
+++ b/tests/UserSwitchMonitorApp/src/com/google/android/car/userswitchmonitor/BootCompletedReceiver.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.car.userswitchmonitor;
+
+import static com.google.android.car.userswitchmonitor.UserSwitchMonitorService.TAG;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+public final class BootCompletedReceiver extends BroadcastReceiver {
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Log.d(TAG, "onReceive(): " + intent);
+        Context appContext = context.getApplicationContext();
+        Intent service = new Intent(appContext, UserSwitchMonitorService.class);
+        appContext.startForegroundService(service);
+    }
+}
diff --git a/tests/UserSwitchMonitorApp/src/com/google/android/car/userswitchmonitor/UserSwitchMonitorService.java b/tests/UserSwitchMonitorApp/src/com/google/android/car/userswitchmonitor/UserSwitchMonitorService.java
new file mode 100644
index 0000000..f76b0d6
--- /dev/null
+++ b/tests/UserSwitchMonitorApp/src/com/google/android/car/userswitchmonitor/UserSwitchMonitorService.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.car.userswitchmonitor;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.Service;
+import android.car.Car;
+import android.car.user.CarUserManager;
+import android.car.user.CarUserManager.UserLifecycleEvent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Service that users {@link CarUserManager.UserLifecycleEvent UserLifecycleEvents} to monitor
+ * user switches.
+ *
+ */
+public final class UserSwitchMonitorService extends Service {
+
+    static final String TAG = "UserSwitchMonitor";
+
+    private final Object mLock = new Object();
+
+    private final int mUserId = android.os.Process.myUserHandle().getIdentifier();
+
+    private final List<UserLifecycleEvent> mEvents = new ArrayList<>();
+
+    private final CarUserManager.UserLifecycleListener mListener = (e) -> {
+        Log.d(TAG, "onEvent(" + mUserId + "): " + e);
+        synchronized (mLock) {
+            mEvents.add(e);
+        }
+    };
+
+    private Context mContext;
+    private Car mCar;
+    private CarUserManager mCarUserManager;
+    private NotificationManager mNotificationManager;
+
+    @Override
+    public void onCreate() {
+        mContext = getApplicationContext();
+        mCar = Car.createCar(mContext);
+        mCarUserManager = (CarUserManager) mCar.getCarManager(Car.CAR_USER_SERVICE);
+        mCarUserManager.addListener((r)-> r.run(), mListener);
+
+        mNotificationManager = mContext.getSystemService(NotificationManager.class);
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Log.d(TAG, "onStartCommand(" + mUserId + "): " + intent);
+
+        String channelId = "4815162342";
+        String name = "UserSwitchMonitor";
+        NotificationChannel channel = new NotificationChannel(channelId, name,
+                NotificationManager.IMPORTANCE_MIN);
+        mNotificationManager.createNotificationChannel(channel);
+
+        startForeground(startId,
+                new Notification.Builder(mContext, channelId)
+                        .setContentText(name)
+                        .setContentTitle(name)
+                        .setSmallIcon(R.drawable.ic_launcher)
+                        .build());
+
+        return super.onStartCommand(intent, flags, startId);
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.d(TAG, "onDestroy(" + mUserId + ")");
+
+        if (mCarUserManager != null) {
+            mCarUserManager.removeListener(mListener);
+        } else {
+            Log.w(TAG, "Cannot remove listener because manager is null");
+        }
+        if (mCar != null && mCar.isConnected()) {
+            mCar.disconnect();
+        }
+        super.onDestroy();
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.printf("User id: %d\n", mUserId);
+        synchronized (mLock) {
+            if (mEvents.isEmpty()) {
+                pw.println("Did not receive any event yet");
+                return;
+            }
+            int size = mEvents.size();
+            String indent = "  ";
+            pw.printf("Received %d events:\n", size);
+            for (int i = 0; i < size; i++) {
+                pw.printf("%s%d: %s\n", indent, (i + 1), mEvents.get(i));
+            }
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        Log.d(TAG, "onBind(): " + intent);
+        return null;
+    }
+
+}
diff --git a/tests/UxRestrictionsSample/Android.mk b/tests/UxRestrictionsSample/Android.mk
index 3092876..b763290 100644
--- a/tests/UxRestrictionsSample/Android.mk
+++ b/tests/UxRestrictionsSample/Android.mk
@@ -39,7 +39,9 @@
 
 LOCAL_CERTIFICATE := platform
 
-LOCAL_STATIC_JAVA_LIBRARIES += vehicle-hal-support-lib
+LOCAL_STATIC_JAVA_LIBRARIES += \
+    vehicle-hal-support-lib \
+    car-experimental-api-static-lib
 
 LOCAL_STATIC_ANDROID_LIBRARIES += \
     com.google.android.material_material \
diff --git a/tests/UxRestrictionsSample/res/layout/main_activity.xml b/tests/UxRestrictionsSample/res/layout/main_activity.xml
index e8634ee..66a3ea2 100644
--- a/tests/UxRestrictionsSample/res/layout/main_activity.xml
+++ b/tests/UxRestrictionsSample/res/layout/main_activity.xml
@@ -65,6 +65,15 @@
         android:textSize="@dimen/info_text_size"
         android:textAppearance="?android:textAppearanceLarge"/>
 
+    <TextView
+        android:id="@+id/current_driver_distraction"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/current_driver_distraction"
+        android:padding="@dimen/section_padding"
+        android:textSize="@dimen/info_text_size"
+        android:textAppearance="?android:textAppearanceLarge"/>
+
     <!-- Section: Available Actions -->
     <View
         android:layout_width="match_parent"
diff --git a/tests/UxRestrictionsSample/res/values/strings.xml b/tests/UxRestrictionsSample/res/values/strings.xml
index c789067..ec97bb7 100644
--- a/tests/UxRestrictionsSample/res/values/strings.xml
+++ b/tests/UxRestrictionsSample/res/values/strings.xml
@@ -38,4 +38,5 @@
     <string name="prod_config_title" translatable="false">Production Config</string>
     <string name="tab_baseline" translatable="false">Baseline</string>
     <string name="tab_passenger" translatable="false">Passenger</string>
+    <string name="current_driver_distraction" translatable="false">Driver Awareness Percentage: %1$s</string>
 </resources>
diff --git a/tests/UxRestrictionsSample/src/com/google/android/car/uxr/sample/MainActivity.java b/tests/UxRestrictionsSample/src/com/google/android/car/uxr/sample/MainActivity.java
index f4eff56..7393673 100644
--- a/tests/UxRestrictionsSample/src/com/google/android/car/uxr/sample/MainActivity.java
+++ b/tests/UxRestrictionsSample/src/com/google/android/car/uxr/sample/MainActivity.java
@@ -29,10 +29,14 @@
 import android.car.drivingstate.CarUxRestrictionsConfiguration;
 import android.car.drivingstate.CarUxRestrictionsConfiguration.DrivingStateRestrictions;
 import android.car.drivingstate.CarUxRestrictionsManager;
+import android.car.experimental.CarDriverDistractionManager;
+import android.car.experimental.DriverDistractionChangeEvent;
+import android.car.experimental.ExperimentalCar;
 import android.os.Bundle;
 import android.util.JsonWriter;
 import android.widget.Button;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.fragment.app.DialogFragment;
@@ -55,15 +59,19 @@
     private CarDrivingStateManager mCarDrivingStateManager;
     private CarUxRestrictionsManager mCarUxRestrictionsManager;
     private CarPackageManager mCarPackageManager;
+    private CarDriverDistractionManager mDistractionManager;
 
     private CarUxRestrictionsManager.OnUxRestrictionsChangedListener mUxRChangeListener =
             this::updateUxRText;
     private CarDrivingStateManager.CarDrivingStateEventListener mDrvStateChangeListener =
             this::updateDrivingStateText;
+    private CarDriverDistractionManager.OnDriverDistractionChangeListener
+            mDistractionChangedListener = this::onDriverDistractionChange;
 
     private TextView mDrvStatus;
     private TextView mDistractionOptStatus;
     private TextView mUxrStatus;
+    private TextView mDistractionStatus;
     private Button mToggleButton;
     private Button mSaveUxrConfigButton;
     private Button mShowStagedConfig;
@@ -81,6 +89,7 @@
         mDrvStatus = findViewById(R.id.driving_state);
         mDistractionOptStatus = findViewById(R.id.do_status);
         mUxrStatus = findViewById(R.id.uxr_status);
+        mDistractionStatus = findViewById(R.id.current_driver_distraction);
 
         mToggleButton = findViewById(R.id.toggle_status);
         mToggleButton.setOnClickListener(v -> updateToggleUxREnable());
@@ -114,6 +123,18 @@
             mCarUxRestrictionsManager.registerListener(mUxRChangeListener);
             updateUxRText(mCarUxRestrictionsManager.getCurrentCarUxRestrictions());
         }
+
+        if (mCar.isFeatureEnabled(
+                ExperimentalCar.DRIVER_DISTRACTION_EXPERIMENTAL_FEATURE_SERVICE)) {
+            mDistractionManager = (CarDriverDistractionManager) mCar.getCarManager(
+                    ExperimentalCar.DRIVER_DISTRACTION_EXPERIMENTAL_FEATURE_SERVICE);
+            if (mDistractionManager != null) {
+                mDistractionManager.addDriverDistractionChangeListener(mDistractionChangedListener);
+            }
+        } else {
+            mDistractionStatus.setText(
+                    getString(R.string.current_driver_distraction, "feature disabled"));
+        }
     }
 
     @Override
@@ -125,6 +146,9 @@
         if (mCarDrivingStateManager != null) {
             mCarDrivingStateManager.unregisterListener();
         }
+        if (mDistractionManager != null) {
+            mDistractionManager.removeDriverDistractionChangeListener(mDistractionChangedListener);
+        }
         if (mCar != null) {
             mCar.disconnect();
         }
@@ -145,6 +169,11 @@
         mUxrStatus.requestLayout();
     }
 
+    private void onDriverDistractionChange(DriverDistractionChangeEvent event) {
+        mDistractionStatus.setText(
+                getString(R.string.current_driver_distraction, event.getAwarenessPercentage()));
+    }
+
     private void updateToggleUxREnable() {
         if (mCarPackageManager == null) {
             return;
@@ -232,7 +261,11 @@
                                 .setRestrictions(passenger))
                 .build();
 
-        mCarUxRestrictionsManager.saveUxRestrictionsConfigurationForNextBoot(config);
+        if (mCarUxRestrictionsManager.saveUxRestrictionsConfigurationForNextBoot(config)) {
+            Toast.makeText(this, "Config saved successfully", Toast.LENGTH_SHORT).show();
+        } else {
+            Toast.makeText(this, "Config failed to save", Toast.LENGTH_SHORT).show();
+        }
     }
 
     private void showStagedUxRestrictionsConfig() {
diff --git a/tests/VmsPublisherClientSample/Android.mk b/tests/VmsPublisherClientSample/Android.mk
deleted file mode 100644
index 8c5ada8..0000000
--- a/tests/VmsPublisherClientSample/Android.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_PACKAGE_NAME := VmsPublisherClientSample
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_CERTIFICATE := testkey
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_JAVA_LIBRARIES += android.car
-
-include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/tests/VmsPublisherClientSample/AndroidManifest.xml b/tests/VmsPublisherClientSample/AndroidManifest.xml
deleted file mode 100644
index fdc1a31..0000000
--- a/tests/VmsPublisherClientSample/AndroidManifest.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.google.android.car.vms.publisher">
-
-    <uses-permission android:name="android.car.permission.VMS_PUBLISHER" />
-    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
-    <uses-permission android:name="android.permission.CAMERA"/>
-
-    <uses-sdk android:minSdkVersion="25" android:targetSdkVersion='25'/>
-
-    <application android:label="@string/app_name"
-                 android:icon="@mipmap/ic_launcher"
-                 android:directBootAware="true">
-        <service android:name=".VmsPublisherClientSampleService"
-                 android:exported="true"
-                 android:singleUser="true">
-        </service>
-    </application>
-</manifest>
diff --git a/tests/VmsPublisherClientSample/res/mipmap-hdpi/ic_launcher.png b/tests/VmsPublisherClientSample/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index cde69bc..0000000
--- a/tests/VmsPublisherClientSample/res/mipmap-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/VmsPublisherClientSample/res/mipmap-mdpi/ic_launcher.png b/tests/VmsPublisherClientSample/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index c133a0c..0000000
--- a/tests/VmsPublisherClientSample/res/mipmap-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/VmsPublisherClientSample/res/mipmap-xhdpi/ic_launcher.png b/tests/VmsPublisherClientSample/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index bfa42f0..0000000
--- a/tests/VmsPublisherClientSample/res/mipmap-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/VmsPublisherClientSample/res/mipmap-xxhdpi/ic_launcher.png b/tests/VmsPublisherClientSample/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 324e72c..0000000
--- a/tests/VmsPublisherClientSample/res/mipmap-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/VmsPublisherClientSample/res/mipmap-xxxhdpi/ic_launcher.png b/tests/VmsPublisherClientSample/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index aee44e1..0000000
--- a/tests/VmsPublisherClientSample/res/mipmap-xxxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/VmsPublisherClientSample/res/values/strings.xml b/tests/VmsPublisherClientSample/res/values/strings.xml
deleted file mode 100644
index 9d548e4..0000000
--- a/tests/VmsPublisherClientSample/res/values/strings.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-  <string name="app_name" translatable="false">VmsPublisherClientSample</string>
-</resources>
diff --git a/tests/VmsPublisherClientSample/src/com/google/android/car/vms/publisher/VmsPublisherClientSampleService.java b/tests/VmsPublisherClientSample/src/com/google/android/car/vms/publisher/VmsPublisherClientSampleService.java
deleted file mode 100644
index e235f1e..0000000
--- a/tests/VmsPublisherClientSample/src/com/google/android/car/vms/publisher/VmsPublisherClientSampleService.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.car.vms.publisher;
-
-import android.car.vms.VmsLayer;
-import android.car.vms.VmsPublisherClientService;
-import android.car.vms.VmsSubscriptionState;
-import android.os.Handler;
-import android.os.Message;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * This service is launched during the initialization of the VMS publisher service.
- * Once onVmsPublisherServiceReady is invoked, it starts publishing a single byte every second.
- */
-public class VmsPublisherClientSampleService extends VmsPublisherClientService {
-    public static final int PUBLISH_EVENT = 0;
-    public static final VmsLayer TEST_LAYER = new VmsLayer(0, 0, 0);
-    public static final int PUBLISHER_ID = 1;
-
-    private byte mCounter = 0;
-    private AtomicBoolean mInitialized = new AtomicBoolean(false);
-
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            if (msg.what == PUBLISH_EVENT && mInitialized.get()) {
-                periodicPublish();
-            }
-        }
-    };
-
-    /**
-     * Notifies that the publisher services are ready to be used: {@link #publish(VmsLayer, byte[])}
-     * and {@link #getSubscriptions()}.
-     */
-    @Override
-    public void onVmsPublisherServiceReady() {
-        VmsSubscriptionState subscriptionState = getSubscriptions();
-        onVmsSubscriptionChange(subscriptionState);
-    }
-
-    @Override
-    public void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState) {
-        if (mInitialized.compareAndSet(false, true)) {
-            for (VmsLayer layer : subscriptionState.getLayers()) {
-                if (layer.equals(TEST_LAYER)) {
-                    mHandler.sendEmptyMessage(PUBLISH_EVENT);
-                }
-            }
-        }
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        mInitialized.set(false);
-        mHandler.removeMessages(PUBLISH_EVENT);
-    }
-
-    private void periodicPublish() {
-        publish(TEST_LAYER, PUBLISHER_ID, new byte[]{mCounter});
-        ++mCounter;
-        mHandler.sendEmptyMessageDelayed(PUBLISH_EVENT, 1000);
-    }
-}
diff --git a/tests/VmsSubscriberClientSample/Android.mk b/tests/VmsSubscriberClientSample/Android.mk
deleted file mode 100644
index 2568ffc..0000000
--- a/tests/VmsSubscriberClientSample/Android.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_PACKAGE_NAME := VmsSubscriberClientSample
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_CERTIFICATE := platform
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_JAVA_LIBRARIES += android.car
-
-include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/tests/VmsSubscriberClientSample/AndroidManifest.xml b/tests/VmsSubscriberClientSample/AndroidManifest.xml
deleted file mode 100644
index a035d05..0000000
--- a/tests/VmsSubscriberClientSample/AndroidManifest.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-          package="com.google.android.car.vms.subscriber">
-          <!--android:sharedUserId="android.uid.system">-->
-    <uses-sdk android:minSdkVersion="25" android:targetSdkVersion='25'/>
-
-    <uses-permission android:name="android.car.permission.VMS_SUBSCRIBER"/>
-
-    <application android:label="@string/app_name"
-                 android:icon="@mipmap/ic_launcher">
-        <meta-data
-            android:name="android.car.application"
-            android:resource="@xml/automotive_app_desc"/>
-        <activity android:name=".VmsSubscriberClientSampleActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER"/>
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
\ No newline at end of file
diff --git a/tests/VmsSubscriberClientSample/res/layout/activity_main.xml b/tests/VmsSubscriberClientSample/res/layout/activity_main.xml
deleted file mode 100644
index ce05a4d..0000000
--- a/tests/VmsSubscriberClientSample/res/layout/activity_main.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/activity_main"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:paddingTop="@dimen/activity_vertical_margin"
-    android:paddingBottom="@dimen/activity_vertical_margin"
-    android:paddingLeft="@dimen/activity_horizontal_margin"
-    android:paddingRight="@dimen/activity_horizontal_margin"
-    tools:context="vms.apps.android.google.com.java.myapplication.MainActivity">
-
-    <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:textAppearance="?android:attr/textAppearanceLarge"
-        android:text=""
-        android:id="@+id/textview"/>
-</RelativeLayout>
diff --git a/tests/VmsSubscriberClientSample/res/mipmap-hdpi/ic_launcher.png b/tests/VmsSubscriberClientSample/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index cde69bc..0000000
--- a/tests/VmsSubscriberClientSample/res/mipmap-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/VmsSubscriberClientSample/res/mipmap-mdpi/ic_launcher.png b/tests/VmsSubscriberClientSample/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index c133a0c..0000000
--- a/tests/VmsSubscriberClientSample/res/mipmap-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/VmsSubscriberClientSample/res/mipmap-xhdpi/ic_launcher.png b/tests/VmsSubscriberClientSample/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index bfa42f0..0000000
--- a/tests/VmsSubscriberClientSample/res/mipmap-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/VmsSubscriberClientSample/res/mipmap-xxhdpi/ic_launcher.png b/tests/VmsSubscriberClientSample/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 324e72c..0000000
--- a/tests/VmsSubscriberClientSample/res/mipmap-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/VmsSubscriberClientSample/res/mipmap-xxxhdpi/ic_launcher.png b/tests/VmsSubscriberClientSample/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index aee44e1..0000000
--- a/tests/VmsSubscriberClientSample/res/mipmap-xxxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/VmsSubscriberClientSample/res/values-w820dp/dimens.xml b/tests/VmsSubscriberClientSample/res/values-w820dp/dimens.xml
deleted file mode 100644
index 308a194..0000000
--- a/tests/VmsSubscriberClientSample/res/values-w820dp/dimens.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<resources>
-  <!-- Example customization of dimensions originally defined in res/values/dimens.xml
-         (such as screen margins) for screens with more than 820dp of available width. This
-         would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
-  <dimen name="activity_horizontal_margin">64dp</dimen>
-</resources>
diff --git a/tests/VmsSubscriberClientSample/res/values/colors.xml b/tests/VmsSubscriberClientSample/res/values/colors.xml
deleted file mode 100644
index 5a077b3..0000000
--- a/tests/VmsSubscriberClientSample/res/values/colors.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-  <color name="colorPrimary">#3F51B5</color>
-  <color name="colorPrimaryDark">#303F9F</color>
-  <color name="colorAccent">#FF4081</color>
-</resources>
diff --git a/tests/VmsSubscriberClientSample/res/values/dimens.xml b/tests/VmsSubscriberClientSample/res/values/dimens.xml
deleted file mode 100644
index acf94cc..0000000
--- a/tests/VmsSubscriberClientSample/res/values/dimens.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<resources>
-  <!-- Default screen margins, per the Android Design guidelines. -->
-  <dimen name="activity_horizontal_margin">16dp</dimen>
-  <dimen name="activity_vertical_margin">16dp</dimen>
-</resources>
diff --git a/tests/VmsSubscriberClientSample/res/values/strings.xml b/tests/VmsSubscriberClientSample/res/values/strings.xml
deleted file mode 100644
index 64b8482..0000000
--- a/tests/VmsSubscriberClientSample/res/values/strings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-<resources>
-  <string name="app_name" translatable="false">VmsSubscriberClientSample</string>
-</resources>
diff --git a/tests/VmsSubscriberClientSample/res/values/styles.xml b/tests/VmsSubscriberClientSample/res/values/styles.xml
deleted file mode 100644
index a7a0615..0000000
--- a/tests/VmsSubscriberClientSample/res/values/styles.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<resources>
-
-  <!-- Base application theme. -->
-  <style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar">
-    <!-- Customize your theme here. -->
-  </style>
-
-</resources>
diff --git a/tests/VmsSubscriberClientSample/res/xml/automotive_app_desc.xml b/tests/VmsSubscriberClientSample/res/xml/automotive_app_desc.xml
deleted file mode 100644
index b10ddd0..0000000
--- a/tests/VmsSubscriberClientSample/res/xml/automotive_app_desc.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<automotiveApp>
-    <uses name="service" />
-    <uses name="projection" />
-    <uses name="activity" class="com.google.android.car.vms.subscriber.VmsSubscriberClientSampleActivity" />
-</automotiveApp>
diff --git a/tests/VmsSubscriberClientSample/src/com/google/android/car/vms/subscriber/VmsSubscriberClientSampleActivity.java b/tests/VmsSubscriberClientSample/src/com/google/android/car/vms/subscriber/VmsSubscriberClientSampleActivity.java
deleted file mode 100644
index 3730104..0000000
--- a/tests/VmsSubscriberClientSample/src/com/google/android/car/vms/subscriber/VmsSubscriberClientSampleActivity.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.car.vms.subscriber;
-
-import android.app.Activity;
-import android.car.Car;
-import android.car.vms.VmsAvailableLayers;
-import android.car.vms.VmsLayer;
-import android.car.vms.VmsSubscriberManager;
-import android.content.ComponentName;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.util.Log;
-import android.widget.TextView;
-
-import java.util.concurrent.Executor;
-
-/**
- * Connects to the Car service during onCreate. CarConnectionCallback.onConnected is invoked when
- * the connection is ready. Then, it subscribes to a VMS layer/version and updates the TextView when
- * a message is received.
- */
-public class VmsSubscriberClientSampleActivity extends Activity {
-    private static final String TAG = "VmsSampleActivity";
-    // The layer id and version should match the ones defined in
-    // com.google.android.car.vms.publisher.VmsPublisherClientSampleService
-    public static final VmsLayer TEST_LAYER = new VmsLayer(0, 0, 0);
-
-    private Car mCarApi;
-    private TextView mTextView;
-    private VmsSubscriberManager mVmsSubscriberManager;
-    private Executor mExecutor;
-
-    private class ThreadPerTaskExecutor implements Executor {
-        public void execute(Runnable r) {
-            new Thread(r).start();
-        }
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        mExecutor = new ThreadPerTaskExecutor();
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.activity_main);
-        mTextView = (TextView) findViewById(R.id.textview);
-        if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
-            mCarApi = Car.createCar(this, mCarServiceConnection);
-            mCarApi.connect();
-        } else {
-            Log.d(TAG, "No automotive feature.");
-        }
-    }
-
-    @Override
-    protected void onDestroy() {
-        super.onDestroy();
-        if (mCarApi != null) {
-            mCarApi.disconnect();
-        }
-        Log.i(TAG, "onDestroy");
-    }
-
-    private final ServiceConnection mCarServiceConnection = new ServiceConnection() {
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            Log.d(TAG, "Connected to Car Service");
-            mVmsSubscriberManager = getVmsSubscriberManager();
-            configureSubscriptions(mVmsSubscriberManager);
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            Log.d(TAG, "Disconnect from Car Service");
-            if (mVmsSubscriberManager != null) {
-                mVmsSubscriberManager.clearVmsSubscriberClientCallback();
-                mVmsSubscriberManager.unsubscribe(TEST_LAYER);
-            }
-        }
-
-        private VmsSubscriberManager getVmsSubscriberManager() {
-            return (VmsSubscriberManager) mCarApi.getCarManager(
-                    Car.VMS_SUBSCRIBER_SERVICE);
-        }
-
-        private void configureSubscriptions(VmsSubscriberManager vmsSubscriberManager) {
-            vmsSubscriberManager.setVmsSubscriberClientCallback(mExecutor, mClientCallback);
-            vmsSubscriberManager.subscribe(TEST_LAYER);
-        }
-
-    };
-
-    private final VmsSubscriberManager.VmsSubscriberClientCallback mClientCallback =
-        new VmsSubscriberManager.VmsSubscriberClientCallback() {
-            @Override
-            public void onVmsMessageReceived(VmsLayer layer, byte[] payload) {
-                mTextView.setText(String.valueOf(payload[0]));
-            }
-
-            @Override
-            public void onLayersAvailabilityChanged(VmsAvailableLayers availableLayers) {
-                mTextView.setText(String.valueOf(availableLayers));
-            }
-        };
-}
diff --git a/tests/android_car_api_test/Android.mk b/tests/android_car_api_test/Android.mk
index b88ca78..102a584 100644
--- a/tests/android_car_api_test/Android.mk
+++ b/tests/android_car_api_test/Android.mk
@@ -39,7 +39,17 @@
         android.hidl.base-V1.0-java \
         android.hardware.automotive.vehicle-V2.0-java \
         android.car.cluster.navigation \
+        android.car.cluster.navigation \
+        android.car.testapi \
+        android.car.test.utils \
+        androidx.test.runner \
+        compatibility-device-util-axt \
+        platform-test-annotations \
+        testng \
+        truth-prebuilt
 
 LOCAL_JAVA_LIBRARIES := android.car android.test.runner android.test.base
 
+LOCAL_COMPATIBILITY_SUITE := general-tests
+
 include $(BUILD_PACKAGE)
diff --git a/tests/android_car_api_test/AndroidManifest.xml b/tests/android_car_api_test/AndroidManifest.xml
index e4c5bbb..bd8fb8c 100644
--- a/tests/android_car_api_test/AndroidManifest.xml
+++ b/tests/android_car_api_test/AndroidManifest.xml
@@ -17,11 +17,10 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
         package="android.car.apitest"
-        android:sharedUserId="android.uid.system"
-        coreApp="true"
+        android:sharedUserId="com.google.android.car.uid.kitchensink"
         android:debuggable="true" >
 
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
             android:targetPackage="android.car.apitest"
             android:label="Tests for Car APIs"
             android:debuggable="true" />
@@ -36,5 +35,9 @@
         </activity>
         <service android:name=".CarProjectionManagerTest$TestService"
                  android:exported="true" />
+        <activity android:name=".CarActivityViewDisplayIdTestBase$ActivityInActivityView"/>
+        <activity android:name=".CarActivityViewDisplayIdTestBase$ActivityViewTestActivity"/>
+        <activity android:name=".CarActivityViewDisplayIdTestBase$MultiProcessActivityViewTestActivity"
+                  android:exported="true" android:process=":activity_view_test"/>
     </application>
 </manifest>
diff --git a/tests/android_car_api_test/src/android/car/apitest/AppBlockingPackageInfoTest.java b/tests/android_car_api_test/src/android/car/apitest/AppBlockingPackageInfoTest.java
index c260c0e..68ed348 100644
--- a/tests/android_car_api_test/src/android/car/apitest/AppBlockingPackageInfoTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/AppBlockingPackageInfoTest.java
@@ -18,35 +18,45 @@
 import android.car.content.pm.AppBlockingPackageInfo;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.content.pm.Signature;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.Signature;
 import android.os.Parcel;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+
 @SmallTest
-public class AppBlockingPackageInfoTest extends AndroidTestCase {
+public class AppBlockingPackageInfoTest {
     private static final String TAG = AppBlockingPackageInfoTest.class.getSimpleName();
 
+    private final Context mContext = InstrumentationRegistry.getInstrumentation()
+            .getTargetContext();
+
+    @Test
     public void testParcellingSystemInfo() throws Exception {
-        AppBlockingPackageInfo carServiceInfo = createInfoCarService(getContext());
+        AppBlockingPackageInfo carServiceInfo = createInfoCarService(mContext);
         Parcel dest = Parcel.obtain();
         carServiceInfo.writeToParcel(dest, 0);
         dest.setDataPosition(0);
         AppBlockingPackageInfo carServiceInfoRead = new AppBlockingPackageInfo(dest);
         Log.i(TAG, "expected:" + carServiceInfo + ",read:" + carServiceInfoRead);
-        assertEquals(carServiceInfo, carServiceInfoRead);
+        assertThat(carServiceInfoRead).isEqualTo(carServiceInfo);
     }
 
+    @Test
     public void testParcellingNonSystemInfo() throws Exception {
-        AppBlockingPackageInfo selfInfo = createInfoSelf(getContext());
+        AppBlockingPackageInfo selfInfo = createInfoSelf(mContext);
         Parcel dest = Parcel.obtain();
         selfInfo.writeToParcel(dest, 0);
         dest.setDataPosition(0);
         AppBlockingPackageInfo selfInfoRead = new AppBlockingPackageInfo(dest);
         Log.i(TAG, "expected:" + selfInfo + ",read:" + selfInfoRead);
-        assertEquals(selfInfo, selfInfoRead);
+        assertThat(selfInfoRead).isEqualTo(selfInfo);
     }
 
     public static AppBlockingPackageInfo createInfoCarService(Context context) {
@@ -60,8 +70,7 @@
         PackageManager pm = context.getPackageManager();
         Signature[] signatures;
         try {
-            signatures = pm.getPackageInfo(packageName,
-                    PackageManager.GET_SIGNATURES).signatures;
+            signatures = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures;
         } catch (NameNotFoundException e) {
             return null;
         }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarActivityViewDisplayIdCrashTest.java b/tests/android_car_api_test/src/android/car/apitest/CarActivityViewDisplayIdCrashTest.java
new file mode 100644
index 0000000..f275fe6
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/CarActivityViewDisplayIdCrashTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.apitest;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.ActivityManager;
+import android.content.Intent;
+import android.os.Process;
+import android.os.SystemClock;
+
+import androidx.test.filters.MediumTest;
+
+import org.junit.Test;
+
+import java.util.List;
+
+/**
+ * The test contained in this class kills a test activity, making the system unstable for a while.
+ * That said, this class must have only one test method.
+ */
+@MediumTest
+public final class CarActivityViewDisplayIdCrashTest extends CarActivityViewDisplayIdTestBase {
+
+    private static final int INVALID_PID = -1;
+
+    @Test
+    public void testCleanUpAfterClientIsCrashed() throws Exception {
+        Intent intent = new Intent(getContext(),
+                CarActivityViewDisplayIdTest.MultiProcessActivityViewTestActivity.class);
+        getContext().startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+        int pidOfTestActivity = waitForTestActivityReady();
+        int displayIdOfTestActivity = waitForActivityViewDisplayReady(ACTIVITY_VIEW_TEST_PKG_NAME);
+
+        assertThat(getMappedPhysicalDisplayOfVirtualDisplay(displayIdOfTestActivity))
+            .isEqualTo(DEFAULT_DISPLAY);
+
+        Process.killProcess(pidOfTestActivity);
+
+        assertThat(waitForMappedPhysicalDisplayOfVirtualDisplayCleared(displayIdOfTestActivity))
+            .isEqualTo(INVALID_DISPLAY);
+    }
+
+    private int waitForMappedPhysicalDisplayOfVirtualDisplayCleared(int displayId) {
+        // Initialized with a random number which is not DEFAULT_DISPLAY nor INVALID_DISPLAY.
+        int physicalDisplayId = 999;
+        for (int i = 0; i < TEST_TIMEOUT_MS / TEST_POLL_MS; ++i) {
+            physicalDisplayId = getMappedPhysicalDisplayOfVirtualDisplay(displayId);
+            if (physicalDisplayId == INVALID_DISPLAY) {
+                return physicalDisplayId;
+            }
+            SystemClock.sleep(TEST_POLL_MS);
+        }
+        return physicalDisplayId;
+    }
+
+    private int waitForTestActivityReady() {
+        for (int i = 0; i < TEST_TIMEOUT_MS / TEST_POLL_MS; ++i) {
+            List<ActivityManager.RunningAppProcessInfo> appProcesses =
+                    mActivityManager.getRunningAppProcesses();
+            for (ActivityManager.RunningAppProcessInfo info : appProcesses) {
+                if (info.processName.equals(ACTIVITY_VIEW_TEST_PROCESS_NAME) && info.importance
+                        == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
+                    return info.pid;
+                }
+            }
+            SystemClock.sleep(TEST_POLL_MS);
+        }
+        return INVALID_PID;
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarActivityViewDisplayIdTest.java b/tests/android_car_api_test/src/android/car/apitest/CarActivityViewDisplayIdTest.java
new file mode 100644
index 0000000..ee6dbbb
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/CarActivityViewDisplayIdTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.apitest;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+import static org.testng.Assert.assertThrows;
+
+import androidx.test.filters.MediumTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Build/Install/Run:
+ *  atest AndroidCarApiTest:CarActivityViewDisplayIdTest
+ */
+@RunWith(JUnit4.class)
+@MediumTest
+public class CarActivityViewDisplayIdTest extends CarActivityViewDisplayIdTestBase {
+    private static final String CAR_LAUNCHER_PKG_NAME = "com.android.car.carlauncher";
+    private static final int NONEXISTENT_DISPLAY_ID = Integer.MAX_VALUE;
+
+    @Test
+    public void testSingleActivityView() throws Exception {
+        ActivityViewTestActivity activity = startActivityViewTestActivity(DEFAULT_DISPLAY);
+        activity.waitForActivityViewReady();
+        int virtualDisplayId = activity.getActivityView().getVirtualDisplayId();
+
+        startTestActivity(ActivityInActivityView.class, virtualDisplayId);
+
+        assertThat(getMappedPhysicalDisplayOfVirtualDisplay(virtualDisplayId))
+                .isEqualTo(DEFAULT_DISPLAY);
+        assertThat(getMappedPhysicalDisplayOfVirtualDisplay(DEFAULT_DISPLAY))
+                .isEqualTo(INVALID_DISPLAY);
+
+        activity.finish();
+        activity.waitForActivityViewDestroyed();
+
+        assertThat(getMappedPhysicalDisplayOfVirtualDisplay(virtualDisplayId))
+                .isEqualTo(INVALID_DISPLAY);
+        assertThat(getMappedPhysicalDisplayOfVirtualDisplay(DEFAULT_DISPLAY))
+                .isEqualTo(INVALID_DISPLAY);
+    }
+
+    @Test
+    public void testDoubleActivityView() throws Exception {
+        ActivityViewTestActivity activity1 = startActivityViewTestActivity(DEFAULT_DISPLAY);
+        activity1.waitForActivityViewReady();
+        int virtualDisplayId1 = activity1.getActivityView().getVirtualDisplayId();
+
+        ActivityViewTestActivity activity2 = startActivityViewTestActivity(virtualDisplayId1);
+        activity2.waitForActivityViewReady();
+        int virtualDisplayId2 = activity2.getActivityView().getVirtualDisplayId();
+
+        startTestActivity(ActivityInActivityView.class, virtualDisplayId2);
+
+        assertThat(virtualDisplayId1).isNotEqualTo(virtualDisplayId2);
+        assertThat(getMappedPhysicalDisplayOfVirtualDisplay(virtualDisplayId1))
+                .isEqualTo(DEFAULT_DISPLAY);
+        assertThat(getMappedPhysicalDisplayOfVirtualDisplay(virtualDisplayId2))
+                .isEqualTo(DEFAULT_DISPLAY);
+        assertThat(getMappedPhysicalDisplayOfVirtualDisplay(DEFAULT_DISPLAY))
+                .isEqualTo(INVALID_DISPLAY);
+
+        activity2.finish();
+        activity1.finish();
+
+        activity2.waitForActivityViewDestroyed();
+        activity1.waitForActivityViewDestroyed();
+
+        assertThat(getMappedPhysicalDisplayOfVirtualDisplay(virtualDisplayId1))
+                .isEqualTo(INVALID_DISPLAY);
+        assertThat(getMappedPhysicalDisplayOfVirtualDisplay(virtualDisplayId2))
+                .isEqualTo(INVALID_DISPLAY);
+        assertThat(getMappedPhysicalDisplayOfVirtualDisplay(DEFAULT_DISPLAY))
+                .isEqualTo(INVALID_DISPLAY);
+    }
+
+    @Test
+    public void testThrowsExceptionOnReportingNonExistingDisplay() throws Exception {
+        ActivityViewTestActivity activity = startActivityViewTestActivity(DEFAULT_DISPLAY);
+        activity.waitForActivityViewReady();
+        int virtualDisplayId = activity.getActivityView().getVirtualDisplayId();
+
+        // This will pass since the test owns the display.
+        mCarUxRestrictionsManager.reportVirtualDisplayToPhysicalDisplay(virtualDisplayId,
+                NONEXISTENT_DISPLAY_ID);
+
+        assertThat(getMappedPhysicalDisplayOfVirtualDisplay(virtualDisplayId))
+                .isEqualTo(NONEXISTENT_DISPLAY_ID);
+
+        activity.finish();
+        activity.waitForActivityViewDestroyed();
+
+        // Now the display was released, so expect to throw an Exception.
+        assertThrows(
+                java.lang.IllegalArgumentException.class,
+                () -> mCarUxRestrictionsManager.reportVirtualDisplayToPhysicalDisplay(
+                        virtualDisplayId, NONEXISTENT_DISPLAY_ID));
+    }
+
+    // TODO(b/143353546): Make the following tests not to rely on CarLauncher.
+    @Test
+    public void testThrowsExceptionOnReportingNonOwningDisplay() throws Exception {
+        int displayIdOfCarLauncher = waitForActivityViewDisplayReady(CAR_LAUNCHER_PKG_NAME);
+        assumeTrue(INVALID_DISPLAY != displayIdOfCarLauncher);
+
+        // CarLauncher owns the display, so expect to throw an Exception.
+        assertThrows(
+                java.lang.SecurityException.class,
+                () -> mCarUxRestrictionsManager.reportVirtualDisplayToPhysicalDisplay(
+                        displayIdOfCarLauncher, DEFAULT_DISPLAY + 1));
+
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarActivityViewDisplayIdTestBase.java b/tests/android_car_api_test/src/android/car/apitest/CarActivityViewDisplayIdTestBase.java
new file mode 100644
index 0000000..e1782cb
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/CarActivityViewDisplayIdTestBase.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.apitest;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.ActivityView;
+import android.app.Instrumentation;
+import android.car.Car;
+import android.car.app.CarActivityView;
+import android.car.drivingstate.CarUxRestrictionsManager;
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.display.DisplayManager;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.view.Display;
+import android.view.ViewGroup;
+
+import org.junit.Before;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Base class for all CarActivityViewDisplayId tests.
+ */
+abstract class CarActivityViewDisplayIdTestBase extends CarApiTestBase {
+    protected static final String ACTIVITY_VIEW_TEST_PKG_NAME = "android.car.apitest";
+
+    protected static final String ACTIVITY_VIEW_TEST_PROCESS_NAME =
+            ACTIVITY_VIEW_TEST_PKG_NAME + ":activity_view_test";
+
+    protected static final String ACTIVITY_VIEW_DISPLAY_NAME = "TaskVirtualDisplay";
+
+    protected static final int TEST_POLL_MS = 50;
+    protected static final int TEST_TIMEOUT_SEC = 5;
+    protected static final int TEST_TIMEOUT_MS = TEST_TIMEOUT_SEC * 1000;
+
+    protected DisplayManager mDisplayManager;
+    protected ActivityManager mActivityManager;
+    protected CarUxRestrictionsManager mCarUxRestrictionsManager;
+
+    @Before
+    public void setUp() throws Exception {
+        mDisplayManager = getContext().getSystemService(DisplayManager.class);
+        mActivityManager = getContext().getSystemService(ActivityManager.class);
+        mCarUxRestrictionsManager = (CarUxRestrictionsManager)
+                getCar().getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);
+    }
+
+    protected int waitForActivityViewDisplayReady(String packageName) {
+        for (int i = 0; i < TEST_TIMEOUT_MS / TEST_POLL_MS; ++i) {
+            for (Display display : mDisplayManager.getDisplays()) {
+                if (display.getName().contains(ACTIVITY_VIEW_DISPLAY_NAME)
+                        && display.getOwnerPackageName().equals(packageName)
+                        && display.getState() == Display.STATE_ON) {
+                    return display.getDisplayId();
+                }
+            }
+            SystemClock.sleep(TEST_POLL_MS);
+        }
+        return INVALID_DISPLAY;
+    }
+
+    protected int getMappedPhysicalDisplayOfVirtualDisplay(int displayId) {
+        return mCarUxRestrictionsManager.getMappedPhysicalDisplayOfVirtualDisplay(displayId);
+    }
+
+    public static class ActivityViewTestActivity extends CarActivityViewDisplayIdTest.TestActivity {
+        private static final class ActivityViewStateCallback extends ActivityView.StateCallback {
+            private final CountDownLatch mActivityViewReadyLatch = new CountDownLatch(1);
+            private final CountDownLatch mActivityViewDestroyedLatch = new CountDownLatch(1);
+
+            @Override
+            public void onActivityViewReady(ActivityView view) {
+                mActivityViewReadyLatch.countDown();
+            }
+
+            @Override
+            public void onActivityViewDestroyed(ActivityView view) {
+                mActivityViewDestroyedLatch.countDown();
+            }
+        }
+
+        private CarActivityView mActivityView;
+        private final ActivityViewStateCallback mCallback = new ActivityViewStateCallback();
+
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+
+            mActivityView = new CarActivityView(this, /*attrs=*/null , /*defStyle=*/0 ,
+                    /*singleTaskInstance=*/true);
+            mActivityView.setCallback(mCallback);
+            setContentView(mActivityView);
+
+            ViewGroup.LayoutParams layoutParams = mActivityView.getLayoutParams();
+            layoutParams.width = MATCH_PARENT;
+            layoutParams.height = MATCH_PARENT;
+            mActivityView.requestLayout();
+        }
+
+        @Override
+        protected void onStop() {
+            super.onStop();
+            // Moved the release of the view from onDestroy to onStop since onDestroy was called
+            // in non-deterministic timing.
+            mActivityView.release();
+        }
+
+        ActivityView getActivityView() {
+            return mActivityView;
+        }
+
+        void waitForActivityViewReady() throws Exception {
+            waitForLatch(mCallback.mActivityViewReadyLatch);
+        }
+
+        void waitForActivityViewDestroyed() throws Exception {
+            waitForLatch(mCallback.mActivityViewDestroyedLatch);
+        }
+    }
+
+    protected ActivityViewTestActivity startActivityViewTestActivity(int displayId)
+            throws Exception {
+        return (ActivityViewTestActivity) startTestActivity(ActivityViewTestActivity.class,
+                displayId);
+    }
+
+    /** Test activity representing a multi-process activity. */
+    public static final class MultiProcessActivityViewTestActivity extends
+            ActivityViewTestActivity {
+    }
+
+    /**
+     * Test activity that has {@link android.R.attr#resizeableActivity} attribute set to
+     * {@code true}.
+     */
+    public static final class ActivityInActivityView extends TestActivity {}
+
+    /**
+     * Starts the provided activity and returns the started instance.
+     */
+    protected TestActivity startTestActivity(Class<?> activityClass, int displayId)
+            throws Exception {
+        Instrumentation.ActivityMonitor monitor = new Instrumentation.ActivityMonitor(
+                activityClass.getName(), null, false);
+        getInstrumentation().addMonitor(monitor);
+
+        Context context = getContext();
+        Intent intent = new Intent(context, activityClass).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        ActivityOptions options = ActivityOptions.makeBasic();
+        if (displayId != DEFAULT_DISPLAY) {
+            intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+            options.setLaunchDisplayId(displayId);
+        }
+        context.startActivity(intent, options.toBundle());
+
+        TestActivity activity = (TestActivity) monitor.waitForActivityWithTimeout(TEST_TIMEOUT_MS);
+        if (activity == null) {
+            throw new TimeoutException("Timed out waiting " + TEST_TIMEOUT_MS + " milliseconds "
+                    + " waiting for Activity");
+        }
+
+        activity.waitForResumeStateChange();
+        return activity;
+    }
+
+    private static void waitForLatch(CountDownLatch latch) throws Exception {
+        boolean result = latch.await(TEST_TIMEOUT_SEC, TimeUnit.SECONDS);
+        if (!result) {
+            throw new TimeoutException("Timed out waiting " + TEST_TIMEOUT_SEC + " seconds waiting"
+                    + " for task stack change notification");
+        }
+    }
+
+    protected static class TestActivity extends Activity {
+        private final CountDownLatch mResumed = new CountDownLatch(1);
+
+        @Override
+        protected void onPostResume() {
+            super.onPostResume();
+            mResumed.countDown();
+        }
+
+        void waitForResumeStateChange() throws Exception {
+            waitForLatch(mResumed);
+        }
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarApiTestBase.java b/tests/android_car_api_test/src/android/car/apitest/CarApiTestBase.java
index dc167b1..b3bf492 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarApiTestBase.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarApiTestBase.java
@@ -16,47 +16,79 @@
 
 package android.car.apitest;
 
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+import static com.android.compatibility.common.util.TestUtils.BooleanSupplierWithThrow;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+
+import android.car.Car;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.ServiceConnection;
 import android.os.IBinder;
 import android.os.Looper;
-import android.car.Car;
-import android.test.AndroidTestCase;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
 
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
-public class CarApiTestBase extends AndroidTestCase {
-    protected static final long DEFAULT_WAIT_TIMEOUT_MS = 1000;
+abstract class CarApiTestBase {
+
+    private static final String TAG = CarApiTestBase.class.getSimpleName();
+
+    protected static final long DEFAULT_WAIT_TIMEOUT_MS = 1_000;
+
+    /**
+     * Constant used to wait blindly, when there is no condition that can be checked.
+     */
+    private static final int SUSPEND_TIMEOUT_MS = 5_000;
+    /**
+     * How long to sleep (multiple times) while waiting for a condition.
+     */
+    private static final int SMALL_NAP_MS = 100;
+
+    protected static final Context sContext = InstrumentationRegistry.getInstrumentation()
+            .getTargetContext();
 
     private Car mCar;
 
-    private final DefaultServiceConnectionListener mConnectionListener =
+    protected final DefaultServiceConnectionListener mConnectionListener =
             new DefaultServiceConnectionListener();
 
-    protected static void assertMainThread() {
-        assertTrue(Looper.getMainLooper().isCurrentThread());
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public final void connectToCar() throws Exception {
         mCar = Car.createCar(getContext(), mConnectionListener);
         mCar.connect();
         mConnectionListener.waitForConnection(DEFAULT_WAIT_TIMEOUT_MS);
     }
 
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
+    @After
+    public final void disconnectFromCar() throws Exception {
         mCar.disconnect();
     }
 
-    protected synchronized Car getCar() {
+    protected Car getCar() {
         return mCar;
     }
 
-    protected static class DefaultServiceConnectionListener implements ServiceConnection {
+    protected final Context getContext() {
+        return sContext;
+    }
+
+    protected static void assertMainThread() {
+        assertThat(Looper.getMainLooper().isCurrentThread()).isTrue();
+    }
+
+    protected static final class DefaultServiceConnectionListener implements ServiceConnection {
         private final Semaphore mConnectionWait = new Semaphore(0);
 
         public void waitForConnection(long timeoutMs) throws InterruptedException {
@@ -74,4 +106,36 @@
             assertMainThread();
         }
     }
+
+    protected static void suspendToRamAndResume() throws Exception {
+        Log.d(TAG, "Emulate suspend to RAM and resume");
+        PowerManager powerManager = sContext.getSystemService(PowerManager.class);
+        runShellCommand("cmd car_service suspend");
+        // Check for suspend success
+        waitUntil("Suspsend is not successful",
+                SUSPEND_TIMEOUT_MS, () -> !powerManager.isScreenOn());
+
+        // Force turn off garage mode
+        runShellCommand("cmd car_service garage-mode off");
+        runShellCommand("cmd car_service resume");
+    }
+
+    protected static boolean waitUntil(String msg, long timeoutMs,
+            BooleanSupplierWithThrow condition) {
+        long deadline = SystemClock.elapsedRealtime() + timeoutMs;
+        do {
+            try {
+                if (condition.getAsBoolean()) {
+                    return true;
+                }
+            } catch (Exception e) {
+                Log.e(TAG, "Exception in waitUntil: " + msg);
+                throw new RuntimeException(e);
+            }
+            SystemClock.sleep(SMALL_NAP_MS);
+        } while (SystemClock.elapsedRealtime() < deadline);
+
+        fail(msg + " after: " + timeoutMs + "ms");
+        return false;
+    }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarAppBlockingPolicyTest.java b/tests/android_car_api_test/src/android/car/apitest/CarAppBlockingPolicyTest.java
index c8690e0..51cb1e3 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarAppBlockingPolicyTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarAppBlockingPolicyTest.java
@@ -17,20 +17,30 @@
 
 import android.car.content.pm.AppBlockingPackageInfo;
 import android.car.content.pm.CarAppBlockingPolicy;
+import android.content.Context;
 import android.os.Parcel;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+
 @SmallTest
-public class CarAppBlockingPolicyTest extends AndroidTestCase {
+public class CarAppBlockingPolicyTest {
     private static final String TAG = AppBlockingPackageInfoTest.class.getSimpleName();
 
+    private final Context mContext = InstrumentationRegistry.getInstrumentation()
+            .getTargetContext();
+
+    @Test
     public void testParcelling() throws Exception {
         AppBlockingPackageInfo carServiceInfo =
-                AppBlockingPackageInfoTest.createInfoCarService(getContext());
+                AppBlockingPackageInfoTest.createInfoCarService(mContext);
         AppBlockingPackageInfo selfInfo =
-                AppBlockingPackageInfoTest.createInfoSelf(getContext());
+                AppBlockingPackageInfoTest.createInfoSelf(mContext);
         // this is only for testing parcelling. contents has nothing to do with actual app blocking.
         AppBlockingPackageInfo[] whitelists = new AppBlockingPackageInfo[] { carServiceInfo,
                 selfInfo };
@@ -41,6 +51,6 @@
         dest.setDataPosition(0);
         CarAppBlockingPolicy policyRead = new CarAppBlockingPolicy(dest);
         Log.i(TAG, "expected:" + policyExpected + ",read:" + policyRead);
-        assertEquals(policyExpected, policyRead);
+        assertThat(policyRead).isEqualTo(policyExpected);
     }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarAppFocusManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarAppFocusManagerTest.java
index f1a25a5..8b64620 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarAppFocusManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarAppFocusManagerTest.java
@@ -18,6 +18,10 @@
 import static android.car.CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED;
 import static android.car.CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
 import android.car.Car;
 import android.car.CarAppFocusManager;
 import android.content.Context;
@@ -26,7 +30,11 @@
 import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
 
-import org.junit.Assert;
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.RequiresDevice;
+
+import org.junit.Before;
+import org.junit.Test;
 
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
@@ -38,16 +46,15 @@
 
     private final LooperThread mEventThread = new LooperThread();
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mManager = (CarAppFocusManager) getCar().getCarManager(Car.APP_FOCUS_SERVICE);
-        assertNotNull(mManager);
+        assertThat(mManager).isNotNull();
 
         // Request all application focuses and abandon them to ensure no active context is present
         // when test starts.
         int[] activeTypes =  mManager.getActiveAppTypes();
-        FocusOwnershipCallback owner = new FocusOwnershipCallback();
+        FocusOwnershipCallback owner = new FocusOwnershipCallback(/* assertEventThread= */ false);
         for (int i = 0; i < activeTypes.length; i++) {
             mManager.requestAppFocus(activeTypes[i], owner);
             owner.waitForOwnershipGrantAndAssert(DEFAULT_WAIT_TIMEOUT_MS, activeTypes[i]);
@@ -59,24 +66,18 @@
         mEventThread.waitForReadyState();
     }
 
+    @Test
     public void testSetActiveNullListener() throws Exception {
-        try {
-            mManager.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, null);
-            fail();
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
+        assertThrows(IllegalArgumentException.class,
+                () -> mManager.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, null));
     }
 
+    @Test
     public void testRegisterNull() throws Exception {
-        try {
-            mManager.addFocusListener(null, 0);
-            fail();
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
+        assertThrows(IllegalArgumentException.class, () -> mManager.addFocusListener(null, 0));
     }
 
+    @Test
     public void testRegisterUnregister() throws Exception {
         FocusChangedListener listener = new FocusChangedListener();
         FocusChangedListener listener2 = new FocusChangedListener();
@@ -87,6 +88,7 @@
         mManager.removeFocusListener(listener2);  // Double-unregister is OK
     }
 
+    @Test
     public void testRegisterUnregisterSpecificApp() throws Exception {
         FocusChangedListener listener1 = new FocusChangedListener();
         FocusChangedListener listener2 = new FocusChangedListener();
@@ -97,32 +99,33 @@
 
         manager.removeFocusListener(listener1, APP_FOCUS_TYPE_NAVIGATION);
 
-        assertEquals(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED,
-                manager.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, new FocusOwnershipCallback()));
+        assertThat(manager.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, new FocusOwnershipCallback()))
+                .isEqualTo(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED);
 
         // Unregistred from nav app, no events expected.
-        assertFalse(listener1.waitForFocusChangeAndAssert(
-                DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION, true));
-        assertTrue(listener2.waitForFocusChangeAndAssert(
-                DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION, true));
+        assertThat(listener1.waitForFocusChangeAndAssert(
+                DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION, true)).isFalse();
+        assertThat(listener2.waitForFocusChangeAndAssert(
+                DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION, true)).isTrue();
 
         manager.removeFocusListener(listener2, APP_FOCUS_TYPE_NAVIGATION);
-        assertEquals(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED,
-                manager.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, new FocusOwnershipCallback()));
-        assertFalse(listener2.waitForFocusChangeAndAssert(
-                DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION, true));
+        assertThat(manager.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, new FocusOwnershipCallback()))
+                .isEqualTo(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED);
+        assertThat(listener2.waitForFocusChangeAndAssert(
+                DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION, true)).isFalse();
 
         manager.removeFocusListener(listener2, 2);
         manager.removeFocusListener(listener2, 2);    // Double-unregister is OK
     }
 
+    @Test
+    @FlakyTest
     public void testFocusChange() throws Exception {
         CarAppFocusManager manager1 = createManager();
         CarAppFocusManager manager2 = createManager();
-        assertNotNull(manager2);
-        final int[] emptyFocus = new int[0];
+        assertThat(manager2).isNotNull();
 
-        Assert.assertArrayEquals(emptyFocus, manager1.getActiveAppTypes());
+        assertThat(manager1.getActiveAppTypes()).asList().isEmpty();
         FocusChangedListener change1 = new FocusChangedListener();
         FocusChangedListener change2 = new FocusChangedListener();
         FocusOwnershipCallback owner1 = new FocusOwnershipCallback();
@@ -131,93 +134,92 @@
         manager2.addFocusListener(change2, APP_FOCUS_TYPE_NAVIGATION);
 
 
-        assertEquals(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED,
-                manager1.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, owner1));
-        assertTrue(owner1.waitForOwnershipGrantAndAssert(
-                DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION));
-        int[] expectedFocuses = new int[] {APP_FOCUS_TYPE_NAVIGATION};
-        Assert.assertArrayEquals(expectedFocuses, manager1.getActiveAppTypes());
-        Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes());
-        assertTrue(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_NAVIGATION));
-        assertFalse(manager2.isOwningFocus(owner2, APP_FOCUS_TYPE_NAVIGATION));
-        assertTrue(change2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
-                APP_FOCUS_TYPE_NAVIGATION, true));
-        assertTrue(change1.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
-                APP_FOCUS_TYPE_NAVIGATION, true));
+        assertThat(manager1.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, owner1))
+                .isEqualTo(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED);
+        assertThat(owner1.waitForOwnershipGrantAndAssert(
+        DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION)).isTrue();
+        int expectedFocus  = APP_FOCUS_TYPE_NAVIGATION;
+        assertThat(manager1.getActiveAppTypes()).asList().containsExactly(expectedFocus).inOrder();
+        assertThat(manager2.getActiveAppTypes()).asList().containsExactly(expectedFocus).inOrder();
+        assertThat(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_NAVIGATION)).isTrue();
+        assertThat(manager2.isOwningFocus(owner2, APP_FOCUS_TYPE_NAVIGATION)).isFalse();
+        assertThat(change2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+        APP_FOCUS_TYPE_NAVIGATION, true)).isTrue();
+        assertThat(change1.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+        APP_FOCUS_TYPE_NAVIGATION, true)).isTrue();
 
-        expectedFocuses = new int[] {
-                APP_FOCUS_TYPE_NAVIGATION,
-        };
-        assertTrue(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_NAVIGATION));
-        assertFalse(manager2.isOwningFocus(owner2, APP_FOCUS_TYPE_NAVIGATION));
-        Assert.assertArrayEquals(expectedFocuses, manager1.getActiveAppTypes());
-        Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes());
+        expectedFocus = APP_FOCUS_TYPE_NAVIGATION;
+        assertThat(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_NAVIGATION)).isTrue();
+        assertThat(manager2.isOwningFocus(owner2, APP_FOCUS_TYPE_NAVIGATION)).isFalse();
+        assertThat(manager1.getActiveAppTypes()).asList().containsExactly(expectedFocus).inOrder();
+        assertThat(manager2.getActiveAppTypes()).asList().containsExactly(expectedFocus).inOrder();
 
         // this should be no-op
         change1.reset();
         change2.reset();
-        assertEquals(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED,
-                manager1.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, owner1));
-        assertTrue(owner1.waitForOwnershipGrantAndAssert(
-                DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION));
+        assertThat(manager1.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, owner1))
+                .isEqualTo(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED);
+        assertThat(owner1.waitForOwnershipGrantAndAssert(
+                DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION)).isTrue();
 
-        Assert.assertArrayEquals(expectedFocuses, manager1.getActiveAppTypes());
-        Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes());
-        assertFalse(change2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
-                APP_FOCUS_TYPE_NAVIGATION, true));
-        assertFalse(change1.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
-                APP_FOCUS_TYPE_NAVIGATION, true));
+        assertThat(manager1.getActiveAppTypes()).asList().containsExactly(expectedFocus).inOrder();
+        assertThat(manager2.getActiveAppTypes()).asList().containsExactly(expectedFocus).inOrder();
+        assertThat(change2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                APP_FOCUS_TYPE_NAVIGATION, true)).isTrue();
+        assertThat(change1.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                APP_FOCUS_TYPE_NAVIGATION, true)).isTrue();
 
-        assertEquals(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED,
-                manager2.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, owner2));
-        assertTrue(owner2.waitForOwnershipGrantAndAssert(
-                DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION));
+        assertThat(manager2.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, owner2))
+                .isEqualTo(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED);
+        assertThat(owner2.waitForOwnershipGrantAndAssert(
+                DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION)).isTrue();
 
-        assertFalse(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_NAVIGATION));
-        assertTrue(manager2.isOwningFocus(owner2, APP_FOCUS_TYPE_NAVIGATION));
-        Assert.assertArrayEquals(expectedFocuses, manager1.getActiveAppTypes());
-        Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes());
-        assertTrue(owner1.waitForOwnershipLossAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
-                APP_FOCUS_TYPE_NAVIGATION));
+        assertThat(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_NAVIGATION)).isFalse();
+        assertThat(manager2.isOwningFocus(owner2, APP_FOCUS_TYPE_NAVIGATION)).isTrue();
+        assertThat(manager1.getActiveAppTypes()).asList().containsExactly(expectedFocus).inOrder();
+        assertThat(manager2.getActiveAppTypes()).asList().containsExactly(expectedFocus).inOrder();
+        assertThat(owner1.waitForOwnershipLossAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                APP_FOCUS_TYPE_NAVIGATION)).isTrue();
 
         // no-op as it is not owning it
         change1.reset();
         change2.reset();
         manager1.abandonAppFocus(owner1, APP_FOCUS_TYPE_NAVIGATION);
-        assertFalse(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_NAVIGATION));
-        assertTrue(manager2.isOwningFocus(owner2, APP_FOCUS_TYPE_NAVIGATION));
-        Assert.assertArrayEquals(expectedFocuses, manager1.getActiveAppTypes());
-        Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes());
+        assertThat(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_NAVIGATION)).isFalse();
+        assertThat(manager2.isOwningFocus(owner2, APP_FOCUS_TYPE_NAVIGATION)).isTrue();
+        assertThat(manager1.getActiveAppTypes()).asList().containsExactly(expectedFocus).inOrder();
+        assertThat(manager2.getActiveAppTypes()).asList().containsExactly(expectedFocus).inOrder();
 
         change1.reset();
         change2.reset();
-        assertFalse(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_NAVIGATION));
-        assertTrue(manager2.isOwningFocus(owner2, APP_FOCUS_TYPE_NAVIGATION));
-        expectedFocuses = new int[] {APP_FOCUS_TYPE_NAVIGATION};
-        Assert.assertArrayEquals(expectedFocuses, manager1.getActiveAppTypes());
-        Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes());
+        assertThat(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_NAVIGATION)).isFalse();
+        assertThat(manager2.isOwningFocus(owner2, APP_FOCUS_TYPE_NAVIGATION)).isTrue();
+        expectedFocus = APP_FOCUS_TYPE_NAVIGATION;
+        assertThat(manager1.getActiveAppTypes()).asList().containsExactly(expectedFocus).inOrder();
+        assertThat(manager2.getActiveAppTypes()).asList().containsExactly(expectedFocus).inOrder();
 
         change1.reset();
         change2.reset();
         manager2.abandonAppFocus(owner2, APP_FOCUS_TYPE_NAVIGATION);
-        assertFalse(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_NAVIGATION));
-        assertFalse(manager2.isOwningFocus(owner2, APP_FOCUS_TYPE_NAVIGATION));
-        expectedFocuses = emptyFocus;
-        Assert.assertArrayEquals(expectedFocuses, manager1.getActiveAppTypes());
-        Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes());
-        assertTrue(change1.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
-                APP_FOCUS_TYPE_NAVIGATION, false));
+        assertThat(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_NAVIGATION)).isFalse();
+        assertThat(manager2.isOwningFocus(owner2, APP_FOCUS_TYPE_NAVIGATION)).isFalse();
+        assertThat(manager1.getActiveAppTypes()).asList().isEmpty();
+        assertThat(manager2.getActiveAppTypes()).asList().isEmpty();
+        assertThat(change1.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                APP_FOCUS_TYPE_NAVIGATION, false)).isTrue();
 
         manager1.removeFocusListener(change1);
         manager2.removeFocusListener(change2);
     }
 
+    @RequiresDevice
+    @Test
     public void testFilter() throws Exception {
         CarAppFocusManager manager1 = createManager(getContext(), mEventThread);
         CarAppFocusManager manager2 = createManager(getContext(), mEventThread);
 
-        Assert.assertArrayEquals(new int[0], manager1.getActiveAppTypes());
-        Assert.assertArrayEquals(new int[0], manager2.getActiveAppTypes());
+        assertThat(manager1.getActiveAppTypes()).asList().isEmpty();
+        assertThat(manager2.getActiveAppTypes()).asList().isEmpty();
 
         FocusChangedListener listener1 = new FocusChangedListener();
         FocusChangedListener listener2 = new FocusChangedListener();
@@ -225,23 +227,23 @@
         manager1.addFocusListener(listener1, APP_FOCUS_TYPE_NAVIGATION);
         manager2.addFocusListener(listener2, APP_FOCUS_TYPE_NAVIGATION);
 
-        assertEquals(APP_FOCUS_REQUEST_SUCCEEDED,
-                manager1.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, owner));
-        assertTrue(owner.waitForOwnershipGrantAndAssert(
-                DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION));
+        assertThat(manager1.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, owner))
+                .isEqualTo(APP_FOCUS_REQUEST_SUCCEEDED);
+        assertThat(owner.waitForOwnershipGrantAndAssert(
+                DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION)).isTrue();
 
-        assertTrue(listener1.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
-                APP_FOCUS_TYPE_NAVIGATION, true));
-        assertTrue(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
-                APP_FOCUS_TYPE_NAVIGATION, true));
+        assertThat(listener1.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                APP_FOCUS_TYPE_NAVIGATION, true)).isTrue();
+        assertThat(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                APP_FOCUS_TYPE_NAVIGATION, true)).isTrue();
 
         listener1.reset();
         listener2.reset();
         manager1.abandonAppFocus(owner, APP_FOCUS_TYPE_NAVIGATION);
-        assertTrue(listener1.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
-                APP_FOCUS_TYPE_NAVIGATION, false));
-        assertTrue(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
-                APP_FOCUS_TYPE_NAVIGATION, false));
+        assertThat(listener1.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+        APP_FOCUS_TYPE_NAVIGATION, false)).isTrue();
+        assertThat(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+        APP_FOCUS_TYPE_NAVIGATION, false)).isTrue();
     }
 
     private CarAppFocusManager createManager() throws InterruptedException {
@@ -252,7 +254,7 @@
             LooperThread eventThread) throws InterruptedException {
         Car car = createCar(context, eventThread);
         CarAppFocusManager manager = (CarAppFocusManager) car.getCarManager(Car.APP_FOCUS_SERVICE);
-        assertNotNull(manager);
+        assertThat(manager).isNotNull();
         return manager;
     }
 
@@ -261,12 +263,14 @@
         DefaultServiceConnectionListener connectionListener =
                 new DefaultServiceConnectionListener();
         Car car = Car.createCar(context, connectionListener, eventThread.mHandler);
-        assertNotNull(car);
+        assertThat(car).isNotNull();
         car.connect();
         connectionListener.waitForConnection(DEFAULT_WAIT_TIMEOUT_MS);
         return car;
     }
 
+    @RequiresDevice
+    @Test
     public void testMultipleChangeListenersPerManager() throws Exception {
         CarAppFocusManager manager = createManager();
         FocusChangedListener listener = new FocusChangedListener();
@@ -275,26 +279,27 @@
         manager.addFocusListener(listener, APP_FOCUS_TYPE_NAVIGATION);
         manager.addFocusListener(listener2, APP_FOCUS_TYPE_NAVIGATION);
 
-        assertEquals(APP_FOCUS_REQUEST_SUCCEEDED,
-                manager.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, owner));
-        assertTrue(owner.waitForOwnershipGrantAndAssert(
-                DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION));
+        assertThat(manager.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, owner))
+                .isEqualTo(APP_FOCUS_REQUEST_SUCCEEDED);
+        assertThat(owner.waitForOwnershipGrantAndAssert(
+                DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION)).isTrue();
 
-        assertTrue(listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
-                APP_FOCUS_TYPE_NAVIGATION, true));
-        assertTrue(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
-                APP_FOCUS_TYPE_NAVIGATION, true));
+        assertThat(listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                APP_FOCUS_TYPE_NAVIGATION, true)).isTrue();
+        assertThat(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                APP_FOCUS_TYPE_NAVIGATION, true)).isTrue();
 
         listener.reset();
         listener2.reset();
         manager.abandonAppFocus(owner, APP_FOCUS_TYPE_NAVIGATION);
-        assertTrue(listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
-                APP_FOCUS_TYPE_NAVIGATION, false));
-        assertTrue(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
-                APP_FOCUS_TYPE_NAVIGATION, false));
+        assertThat(listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                APP_FOCUS_TYPE_NAVIGATION, false)).isTrue();
+        assertThat(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                APP_FOCUS_TYPE_NAVIGATION, false)).isTrue();
     }
 
-    private class FocusChangedListener implements CarAppFocusManager.OnAppFocusChangedListener {
+    private final class FocusChangedListener
+            implements CarAppFocusManager.OnAppFocusChangedListener {
         private volatile int mLastChangeAppType;
         private volatile boolean mLastChangeAppActive;
         private volatile Semaphore mChangeWait = new Semaphore(0);
@@ -306,8 +311,8 @@
                 return false;
             }
 
-            assertEquals(expectedAppType, mLastChangeAppType);
-            assertEquals(expectedAppActive, mLastChangeAppActive);
+            assertThat(mLastChangeAppType).isEqualTo(expectedAppType);
+            assertThat(mLastChangeAppActive).isEqualTo(expectedAppActive);
             return true;
         }
 
@@ -326,19 +331,28 @@
         }
     }
 
-    private class FocusOwnershipCallback
+    private final class FocusOwnershipCallback
             implements CarAppFocusManager.OnAppFocusOwnershipCallback {
         private int mLastLossEvent;
         private final Semaphore mLossEventWait = new Semaphore(0);
         private int mLastGrantEvent;
         private final Semaphore mGrantEventWait = new Semaphore(0);
+        private final boolean mAssertEventThread;
+
+        private FocusOwnershipCallback(boolean assertEventThread) {
+            mAssertEventThread = assertEventThread;
+        }
+
+        private FocusOwnershipCallback() {
+            this(true);
+        }
 
         boolean waitForOwnershipLossAndAssert(long timeoutMs, int expectedAppType)
                 throws Exception {
             if (!mLossEventWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
                 return false;
             }
-            assertEquals(expectedAppType, mLastLossEvent);
+            assertThat(mLastLossEvent).isEqualTo(expectedAppType);
             return true;
         }
 
@@ -347,14 +361,16 @@
             if (!mGrantEventWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
                 return false;
             }
-            assertEquals(expectedAppType, mLastGrantEvent);
+            assertThat(mLastGrantEvent).isEqualTo(expectedAppType);
             return true;
         }
 
         @Override
         public void onAppFocusOwnershipLost(int appType) {
             Log.i(TAG, "onAppFocusOwnershipLost " + appType);
-            assertEventThread();
+            if (mAssertEventThread) {
+                assertEventThread();
+            }
             mLastLossEvent = appType;
             mLossEventWait.release();
         }
@@ -368,10 +384,10 @@
     }
 
     private void assertEventThread() {
-        assertEquals(mEventThread, Thread.currentThread());
+        assertThat(Thread.currentThread()).isSameAs(mEventThread);
     }
 
-    private static class LooperThread extends Thread {
+    private static final class LooperThread extends Thread {
 
         private final Object mReadySync = new Object();
 
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarBugreportManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarBugreportManagerTest.java
new file mode 100644
index 0000000..42406ca
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/CarBugreportManagerTest.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.apitest;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+import static org.testng.Assert.expectThrows;
+
+import android.Manifest;
+import android.annotation.FloatRange;
+import android.car.Car;
+import android.car.CarBugreportManager;
+import android.car.CarBugreportManager.CarBugreportManagerCallback;
+import android.os.ParcelFileDescriptor;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class CarBugreportManagerTest extends CarApiTestBase {
+    // TODO: Use "dumpstate.dry_run" to make dumpstate faster.
+    // dumpstate runs around 3 minutes on emulator on a pretty fast computer.
+    private static final int BUGREPORT_TIMEOUT_MILLIS = 360_000;
+    private static final int NO_ERROR = -1;
+
+    @Rule public TestName testName = new TestName();
+
+    private CarBugreportManager mManager;
+    private FakeCarBugreportCallback mFakeCallback;
+    private ParcelFileDescriptor mOutput;
+    private ParcelFileDescriptor mExtraOutput;
+
+    @Before
+    public void setUp() throws Exception {
+        mManager = (CarBugreportManager) getCar().getCarManager(Car.CAR_BUGREPORT_SERVICE);
+        mFakeCallback = new FakeCarBugreportCallback();
+        mOutput = createParcelFdInCache("bugreport", "zip");
+        mExtraOutput = createParcelFdInCache("screenshot", "png");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        getPermissions();  // For cancelBugreport()
+        mManager.cancelBugreport();
+        dropPermissions();
+    }
+
+    @Test
+    public void test_requestBugreport_failsWhenNoPermission() throws Exception {
+        dropPermissions();
+
+        SecurityException expected =
+                expectThrows(SecurityException.class,
+                        () -> mManager.requestBugreport(mOutput, mExtraOutput, mFakeCallback));
+        assertThat(expected).hasMessageThat().contains(
+                "nor current process has android.permission.DUMP.");
+    }
+
+    @Test
+    @LargeTest
+    public void test_requestBugreport_works() throws Exception {
+        getPermissions();
+
+        mManager.requestBugreport(mOutput, mExtraOutput, mFakeCallback);
+
+        // The FDs are duped and closed in requestBugreport().
+        assertFdIsClosed(mOutput);
+        assertFdIsClosed(mExtraOutput);
+
+        mFakeCallback.waitTillDoneOrTimeout(BUGREPORT_TIMEOUT_MILLIS);
+        assertThat(mFakeCallback.isFinishedSuccessfully()).isEqualTo(true);
+        assertThat(mFakeCallback.getReceivedProgress()).isTrue();
+        // TODO: Check the contents of the zip file and the extra output.
+    }
+
+    @Test
+    public void test_requestBugreport_cannotRunMultipleBugreports() throws Exception {
+        getPermissions();
+        FakeCarBugreportCallback callback2 = new FakeCarBugreportCallback();
+        ParcelFileDescriptor output2 = createParcelFdInCache("bugreport2", "zip");
+        ParcelFileDescriptor extraOutput2 = createParcelFdInCache("screenshot2", "png");
+
+        // 1st bugreport.
+        mManager.requestBugreport(mOutput, mExtraOutput, mFakeCallback);
+
+        // 2nd bugreport.
+        mManager.requestBugreport(output2, extraOutput2, callback2);
+
+        callback2.waitTillDoneOrTimeout(BUGREPORT_TIMEOUT_MILLIS);
+        assertThat(callback2.getErrorCode()).isEqualTo(
+                CarBugreportManagerCallback.CAR_BUGREPORT_IN_PROGRESS);
+    }
+
+    @Test
+    @LargeTest
+    public void test_cancelBugreport_works() throws Exception {
+        getPermissions();
+        FakeCarBugreportCallback callback2 = new FakeCarBugreportCallback();
+        ParcelFileDescriptor output2 = createParcelFdInCache("bugreport2", "zip");
+        ParcelFileDescriptor extraOutput2 = createParcelFdInCache("screenshot2", "png");
+
+        // 1st bugreport.
+        mManager.requestBugreport(mOutput, mExtraOutput, mFakeCallback);
+        mManager.cancelBugreport();
+
+        // Allow the system to finish the bugreport cancellation, 0.5 seconds is enough.
+        Thread.sleep(500);
+
+        // 2nd bugreport must work, because 1st bugreport was cancelled.
+        mManager.requestBugreport(output2, extraOutput2, callback2);
+
+        callback2.waitTillProgressOrTimeout(BUGREPORT_TIMEOUT_MILLIS);
+        assertThat(callback2.getErrorCode()).isEqualTo(NO_ERROR);
+        assertThat(callback2.getReceivedProgress()).isEqualTo(true);
+    }
+
+    private static void getPermissions() {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .adoptShellPermissionIdentity(Manifest.permission.DUMP);
+    }
+
+    private static void dropPermissions() {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .dropShellPermissionIdentity();
+    }
+
+    /** Creates a temp file in cache dir and returns file descriptor. */
+    private ParcelFileDescriptor createParcelFdInCache(String prefix, String extension)
+            throws Exception {
+        File f = File.createTempFile(
+                prefix + "_" + testName.getMethodName(), extension, getContext().getCacheDir());
+        f.setReadable(true, true);
+        f.setWritable(true, true);
+
+        return ParcelFileDescriptor.open(f,
+                ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_APPEND);
+    }
+
+    private static void assertFdIsClosed(ParcelFileDescriptor pfd) {
+        try {
+            int fd = pfd.getFd();
+            fail("Expected ParcelFileDescriptor argument to be closed, but got: " + fd);
+        } catch (IllegalStateException expected) {
+        }
+    }
+
+    private static class FakeCarBugreportCallback extends CarBugreportManagerCallback {
+        private final Object mLock = new Object();
+        private final CountDownLatch mEndedLatch = new CountDownLatch(1);
+        private final CountDownLatch mProgressLatch = new CountDownLatch(1);
+        private boolean mReceivedProgress = false;
+        private int mErrorCode = NO_ERROR;
+
+        @Override
+        public void onProgress(@FloatRange(from = 0f, to = 100f) float progress) {
+            synchronized (mLock) {
+                mReceivedProgress = true;
+            }
+            mProgressLatch.countDown();
+        }
+
+        @Override
+        public void onError(
+                @CarBugreportManagerCallback.CarBugreportErrorCode int errorCode) {
+            synchronized (mLock) {
+                mErrorCode = errorCode;
+            }
+            mEndedLatch.countDown();
+            mProgressLatch.countDown();
+        }
+
+        @Override
+        public void onFinished() {
+            mEndedLatch.countDown();
+            mProgressLatch.countDown();
+        }
+
+        int getErrorCode() {
+            synchronized (mLock) {
+                return mErrorCode;
+            }
+        }
+
+        boolean getReceivedProgress() {
+            synchronized (mLock) {
+                return mReceivedProgress;
+            }
+        }
+
+        boolean isFinishedSuccessfully() {
+            return mEndedLatch.getCount() == 0 && getErrorCode() == NO_ERROR;
+        }
+
+        void waitTillDoneOrTimeout(long timeoutMillis) throws InterruptedException {
+            mEndedLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
+        }
+
+        void waitTillProgressOrTimeout(long timeoutMillis) throws InterruptedException {
+            mProgressLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
+        }
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarCabinManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarCabinManagerTest.java
index 2526ecf..cc258c2 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarCabinManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarCabinManagerTest.java
@@ -15,12 +15,19 @@
  */
 package android.car.apitest;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+
 import android.car.Car;
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.cabin.CarCabinManager;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
 
+import org.junit.Before;
+import org.junit.Test;
+
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
@@ -32,13 +39,13 @@
 
     private CarCabinManager mCabinManager;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mCabinManager = (CarCabinManager) getCar().getCarManager(Car.CABIN_SERVICE);
-        assertNotNull(mCabinManager);
+        assertThat(mCabinManager).isNotNull();
     }
 
+    @Test
     public void testAllCabinProperties() throws Exception {
         List<CarPropertyConfig> properties = mCabinManager.getPropertyList();
         Set<Class> supportedTypes = new HashSet<>(Arrays.asList(
@@ -62,8 +69,8 @@
             case CarCabinManager.ID_MIRROR_FOLD:
             case CarCabinManager.ID_SEAT_BELT_BUCKLED:
             case CarCabinManager.ID_WINDOW_LOCK:
-                assertEquals(Boolean.class, property.getPropertyType());
-                assertFalse(property.isGlobalProperty());
+                assertThat(property.getPropertyType()).isAssignableTo(Boolean.class);
+                assertThat(property.isGlobalProperty()).isFalse();
                 break;
 
             // Zoned integer properties
@@ -101,13 +108,13 @@
             case CarCabinManager.ID_SEAT_HEADREST_FORE_AFT_MOVE:
             case CarCabinManager.ID_WINDOW_POS:
             case CarCabinManager.ID_WINDOW_MOVE:
-                assertEquals(Integer.class, property.getPropertyType());
-                assertFalse(property.isGlobalProperty());
+                assertThat(property.getPropertyType()).isAssignableTo(Integer.class);
+                assertThat(property.isGlobalProperty()).isFalse();
                 checkIntMinMax(property);
                 break;
             default:
                 Log.e(TAG, "Property ID not handled: " + propId);
-                assertTrue(false);
+                assertThat(false).isTrue();
                 break;
         }
     }
@@ -116,23 +123,23 @@
         Log.i(TAG, "checkIntMinMax property:" + property);
         if (!property.isGlobalProperty()) {
             int[] areaIds = property.getAreaIds();
-            assertTrue(areaIds.length > 0);
-            assertEquals(areaIds.length, property.getAreaCount());
+            assertThat(areaIds.length).isGreaterThan(0);
+            assertThat(property.getAreaCount()).isEqualTo(areaIds.length);
 
             for (int areId : areaIds) {
-                assertTrue(property.hasArea(areId));
+                assertThat(property.hasArea(areId)).isTrue();
                 int min = property.getMinValue(areId);
                 int max = property.getMaxValue(areId);
-                assertTrue(min <= max);
+                assertThat(min).isAtMost(max);
             }
         } else {
             int min = property.getMinValue();
             int max = property.getMaxValue();
-            assertTrue(min <= max);
+            assertThat(min).isAtMost(max);
             for (int i = 0; i < 32; i++) {
-                assertFalse(property.hasArea(0x1 << i));
-                assertNull(property.getMinValue(0x1 << i));
-                assertNull(property.getMaxValue(0x1 << i));
+                assertThat(property.hasArea(0x1 << i)).isFalse();
+                assertThat(property.getMinValue(0x1 << i)).isNull();
+                assertThat(property.getMaxValue(0x1 << i)).isNull();
             }
         }
     }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarDiagnosticManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarDiagnosticManagerTest.java
index 8783341..c038320 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarDiagnosticManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarDiagnosticManagerTest.java
@@ -16,64 +16,29 @@
 
 package android.car.apitest;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
 import android.car.Car;
 import android.car.diagnostic.CarDiagnosticEvent;
 import android.car.diagnostic.CarDiagnosticManager;
-import android.content.ComponentName;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-import android.os.Looper;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
+
+import org.junit.Before;
+import org.junit.Test;
 
 @MediumTest
-public class CarDiagnosticManagerTest extends AndroidTestCase {
-    private static final long DEFAULT_WAIT_TIMEOUT_MS = 5000;
+public class CarDiagnosticManagerTest extends CarApiTestBase {
 
-    private final Semaphore mConnectionWait = new Semaphore(0);
-
-    private Car mCar;
     private CarDiagnosticManager mCarDiagnosticManager;
 
-    private final ServiceConnection mConnectionListener =
-            new ServiceConnection() {
-
-                @Override
-                public void onServiceDisconnected(ComponentName name) {
-                    assertMainThread();
-                }
-
-                @Override
-                public void onServiceConnected(ComponentName name, IBinder service) {
-                    assertMainThread();
-                    mConnectionWait.release();
-                }
-            };
-
-    private void assertMainThread() {
-        assertTrue(Looper.getMainLooper().isCurrentThread());
-    }
-
-    private void waitForConnection(long timeoutMs) throws InterruptedException {
-        mConnectionWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mCar = Car.createCar(getContext(), mConnectionListener);
-        mCar.connect();
-        waitForConnection(DEFAULT_WAIT_TIMEOUT_MS);
-        mCarDiagnosticManager = (CarDiagnosticManager) mCar.getCarManager(Car.DIAGNOSTIC_SERVICE);
-        assertNotNull(mCarDiagnosticManager);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-        mCar.disconnect();
+    @Before
+    public void setUp() throws Exception {
+        Car car = getCar();
+        assumeTrue(car.isFeatureEnabled(Car.DIAGNOSTIC_SERVICE));
+        mCarDiagnosticManager = (CarDiagnosticManager) car.getCarManager(Car.DIAGNOSTIC_SERVICE);
+        assertThat(mCarDiagnosticManager).isNotNull();
     }
 
     /**
@@ -81,11 +46,12 @@
      *
      * @throws Exception
      */
+    @Test
     public void testLiveFrame() throws Exception {
         CarDiagnosticEvent liveFrame = mCarDiagnosticManager.getLatestLiveFrame();
         if (null != liveFrame) {
-            assertTrue(liveFrame.isLiveFrame());
-            assertFalse(liveFrame.isEmptyFrame());
+            assertThat(liveFrame.isLiveFrame()).isTrue();
+            assertThat(liveFrame.isEmptyFrame()).isFalse();
         }
     }
 
@@ -94,16 +60,17 @@
      *
      * @throws Exception
      */
+    @Test
     public void testFreezeFrames() throws Exception {
         long[] timestamps = mCarDiagnosticManager.getFreezeFrameTimestamps();
         if (null != timestamps) {
             for (long timestamp : timestamps) {
                 CarDiagnosticEvent freezeFrame = mCarDiagnosticManager.getFreezeFrame(timestamp);
-                assertNotNull(freezeFrame);
-                assertEquals(timestamp, freezeFrame.timestamp);
-                assertTrue(freezeFrame.isFreezeFrame());
-                assertFalse(freezeFrame.isEmptyFrame());
-                assertNotSame("", freezeFrame.dtc);
+                assertThat(freezeFrame).isNotNull();
+                assertThat(freezeFrame.timestamp).isEqualTo(timestamp);
+                assertThat(freezeFrame.isFreezeFrame()).isTrue();
+                assertThat(freezeFrame.isEmptyFrame()).isFalse();
+                assertThat(freezeFrame.dtc).isNotEmpty();
             }
         }
     }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarFeatureTest.java b/tests/android_car_api_test/src/android/car/apitest/CarFeatureTest.java
new file mode 100644
index 0000000..5d8fa6a
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/CarFeatureTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.apitest;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.Car;
+import android.car.CarFeatures;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+@SmallTest
+public class CarFeatureTest extends CarApiTestBase  {
+    // List in CarFeatureController should be inline with this.
+    private static final List<String> MANDATORY_FEATURES = Arrays.asList(
+            Car.APP_FOCUS_SERVICE,
+            Car.AUDIO_SERVICE,
+            Car.BLUETOOTH_SERVICE,
+            Car.CAR_BUGREPORT_SERVICE,
+            Car.CAR_CONFIGURATION_SERVICE,
+            Car.CAR_DRIVING_STATE_SERVICE,
+            Car.CAR_MEDIA_SERVICE,
+            Car.CAR_OCCUPANT_ZONE_SERVICE,
+            Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE,
+            Car.CAR_USER_SERVICE,
+            Car.CAR_UX_RESTRICTION_SERVICE,
+            Car.INFO_SERVICE,
+            Car.PACKAGE_SERVICE,
+            Car.POWER_SERVICE,
+            Car.PROJECTION_SERVICE,
+            Car.PROPERTY_SERVICE,
+            Car.TEST_SERVICE,
+            // All items below here are deprecated, but still should be supported
+            Car.CAR_INSTRUMENT_CLUSTER_SERVICE,
+            Car.CABIN_SERVICE,
+            Car.HVAC_SERVICE,
+            Car.SENSOR_SERVICE,
+            Car.VENDOR_EXTENSION_SERVICE
+    );
+
+    private static final List<String> OPTIONAL_FEATURES = Arrays.asList(
+            CarFeatures.FEATURE_CAR_USER_NOTICE_SERVICE,
+            Car.CAR_NAVIGATION_SERVICE,
+            Car.DIAGNOSTIC_SERVICE,
+            Car.STORAGE_MONITORING_SERVICE,
+            Car.VEHICLE_MAP_SERVICE
+    );
+
+    private static final String NON_EXISTING_FEATURE = "ThisFeatureDoesNotExist";
+
+    @Test
+    public void checkMandatoryFeatures() {
+        Car car = getCar();
+        assertThat(car).isNotNull();
+        for (String feature : MANDATORY_FEATURES) {
+            assertThat(car.isFeatureEnabled(feature)).isTrue();
+        }
+    }
+
+    @Test
+    public void toggleOptionalFeature() {
+        Car car = getCar();
+        assertThat(car).isNotNull();
+        for (String feature : OPTIONAL_FEATURES) {
+            boolean enabled = getCar().isFeatureEnabled(feature);
+            toggleOptionalFeature(feature, !enabled, enabled);
+            toggleOptionalFeature(feature, enabled, enabled);
+        }
+    }
+
+    @Test
+    public void testGetAllEnabledFeatures() {
+        Car car = getCar();
+        assertThat(car).isNotNull();
+        List<String> allEnabledFeatures = car.getAllEnabledFeatures();
+        assertThat(allEnabledFeatures).isNotEmpty();
+        for (String feature : MANDATORY_FEATURES) {
+            assertThat(allEnabledFeatures).contains(feature);
+        }
+    }
+
+    @Test
+    public void testEnableDisableForMandatoryFeatures() {
+        for (String feature : MANDATORY_FEATURES) {
+            assertThat(getCar().enableFeature(feature)).isEqualTo(Car.FEATURE_REQUEST_MANDATORY);
+            assertThat(getCar().disableFeature(feature)).isEqualTo(Car.FEATURE_REQUEST_MANDATORY);
+        }
+    }
+
+    @Test
+    public void testEnableDisableForNonExistingFeature() {
+        assertThat(getCar().enableFeature(NON_EXISTING_FEATURE)).isEqualTo(
+                Car.FEATURE_REQUEST_NOT_EXISTING);
+        assertThat(getCar().disableFeature(NON_EXISTING_FEATURE)).isEqualTo(
+                Car.FEATURE_REQUEST_NOT_EXISTING);
+    }
+
+    private void toggleOptionalFeature(String feature, boolean enable, boolean originallyEnabled) {
+        if (enable) {
+            if (originallyEnabled) {
+                assertThat(getCar().enableFeature(feature)).isEqualTo(
+                        Car.FEATURE_REQUEST_ALREADY_IN_THE_STATE);
+            } else {
+                assertThat(getCar().enableFeature(feature)).isEqualTo(Car.FEATURE_REQUEST_SUCCESS);
+                assertThat(getCar().getAllPendingEnabledFeatures()).contains(feature);
+            }
+            assertThat(getCar().getAllPendingDisabledFeatures()).doesNotContain(feature);
+        } else {
+            if (originallyEnabled) {
+                assertThat(getCar().disableFeature(feature)).isEqualTo(Car.FEATURE_REQUEST_SUCCESS);
+                assertThat(getCar().getAllPendingDisabledFeatures()).contains(feature);
+            } else {
+                assertThat(getCar().disableFeature(feature)).isEqualTo(
+                        Car.FEATURE_REQUEST_ALREADY_IN_THE_STATE);
+            }
+            assertThat(getCar().getAllPendingEnabledFeatures()).doesNotContain(feature);
+        }
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarHvacManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarHvacManagerTest.java
index 7a3b7b5..6bea3e3 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarHvacManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarHvacManagerTest.java
@@ -15,6 +15,11 @@
  */
 package android.car.apitest;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.fail;
+
 import android.car.Car;
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.hvac.CarHvacManager;
@@ -22,6 +27,9 @@
 import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
 
+import org.junit.Before;
+import org.junit.Test;
+
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
@@ -33,13 +41,13 @@
 
     private CarHvacManager mHvacManager;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mHvacManager = (CarHvacManager) getCar().getCarManager(Car.HVAC_SERVICE);
-        assertNotNull(mHvacManager);
+        assertThat(mHvacManager).isNotNull();
     }
 
+    @Test
     public void testAllHvacProperties() throws Exception {
         List<CarPropertyConfig> properties = mHvacManager.getPropertyList();
         Set<Class> supportedTypes = new HashSet<>(Arrays.asList(
@@ -54,10 +62,11 @@
         }
     }
 
+    @Test
     public void testHvacPosition() {
-        assertEquals(CarHvacManager.FAN_DIRECTION_FACE, VehicleHvacFanDirection.FACE);
-        assertEquals(CarHvacManager.FAN_DIRECTION_FLOOR, VehicleHvacFanDirection.FLOOR);
-        assertEquals(CarHvacManager.FAN_DIRECTION_DEFROST, VehicleHvacFanDirection.DEFROST);
+        assertThat(VehicleHvacFanDirection.FACE).isEqualTo(CarHvacManager.FAN_DIRECTION_FACE);
+        assertThat(VehicleHvacFanDirection.FLOOR).isEqualTo(CarHvacManager.FAN_DIRECTION_FLOOR);
+        assertThat(VehicleHvacFanDirection.DEFROST).isEqualTo(CarHvacManager.FAN_DIRECTION_DEFROST);
     }
 
     private void assertTypeAndZone(CarPropertyConfig property) {
@@ -103,35 +112,37 @@
         }
     }
 
-    private void checkTypeAndGlobal(Class clazz, boolean global, CarPropertyConfig<Integer> property) {
-        assertEquals("Wrong type, expecting " + clazz + " type for id:" + property.getPropertyId(),
-                clazz, property.getPropertyType());
-        assertEquals("Wrong zone, should " + (global ? "" : "not ") + "be global for id: " +
-                        property.getPropertyId() + ", area type:" + property.getAreaType(),
-                global, property.isGlobalProperty());
+    private void checkTypeAndGlobal(Class<?> clazz, boolean global,
+            CarPropertyConfig<Integer> property) {
+        assertWithMessage("Wrong type, expecting %s type for id %s", clazz,
+                property.getPropertyId()).that(property.getPropertyType()).isEqualTo(clazz);
+        assertWithMessage(
+                "Wrong zone, should %s be global for id:%s, area type: %s" + property.getAreaType(),
+                property.getPropertyId(), property.getAreaType(), (global ? "" : "not "))
+                        .that(property.isGlobalProperty()).isEqualTo(global);
     }
 
     private void checkIntMinMax(CarPropertyConfig<Integer> property) {
         Log.i(TAG, "checkIntMinMax property:" + property);
         if (!property.isGlobalProperty()) {
             int[] areaIds = property.getAreaIds();
-            assertTrue(areaIds.length > 0);
-            assertEquals(areaIds.length, property.getAreaCount());
+            assertThat(areaIds.length).isGreaterThan(0);
+            assertThat(property.getAreaCount()).isEqualTo(areaIds.length);
 
             for (int areaId : areaIds) {
-                assertTrue(property.hasArea(areaId));
+                assertThat(property.hasArea(areaId)).isTrue();
                 int min = property.getMinValue(areaId) == null ? 0 : property.getMinValue(areaId);
                 int max = property.getMaxValue(areaId) == null ? 0 : property.getMaxValue(areaId);
-                assertTrue(min <= max);
+                assertThat(min).isAtMost(max);
             }
         } else {
             int min = property.getMinValue() == null ? 0 : property.getMinValue();
             int max = property.getMaxValue() == null ? 0 : property.getMinValue();
-            assertTrue(min <= max);
+            assertThat(min).isAtMost(max);
             for (int i = 0; i < 32; i++) {
-                assertFalse(property.hasArea(0x1 << i));
-                assertNull(property.getMinValue(0x1 << i));
-                assertNull(property.getMaxValue(0x1 << i));
+                assertThat(property.hasArea(0x1 << i)).isFalse();
+                assertThat(property.getMinValue(0x1 << i)).isNull();
+                assertThat(property.getMaxValue(0x1 << i)).isNull();
             }
         }
     }
@@ -140,25 +151,25 @@
         Log.i(TAG, "checkFloatMinMax property:" + property);
         if (!property.isGlobalProperty()) {
             int[] areaIds = property.getAreaIds();
-            assertTrue(areaIds.length > 0);
-            assertEquals(areaIds.length, property.getAreaCount());
+            assertThat(areaIds.length).isGreaterThan(0);
+            assertThat(property.getAreaCount()).isEqualTo(areaIds.length);
 
             for (int areaId : areaIds) {
-                assertTrue(property.hasArea(areaId));
+                assertThat(property.hasArea(areaId)).isTrue();
                 float min =
                         property.getMinValue(areaId) == null ? 0f : property.getMinValue(areaId);
                 float max =
                         property.getMaxValue(areaId) == null ? 0f : property.getMinValue(areaId);
-                assertTrue(min <= max);
+                assertThat(min).isAtMost(max);
             }
         } else {
             float min = property.getMinValue() == null ? 0f : property.getMinValue();
             float max = property.getMaxValue() == null ? 0f : property.getMinValue();
-            assertTrue(min <= max);
+            assertThat(min).isAtMost(max);
             for (int i = 0; i < 32; i++) {
-                assertFalse(property.hasArea(0x1 << i));
-                assertNull(property.getMinValue(0x1 << i));
-                assertNull(property.getMaxValue(0x1 << i));
+                assertThat(property.hasArea(0x1 << i)).isFalse();
+                assertThat(property.getMinValue(0x1 << i)).isNull();
+                assertThat(property.getMaxValue(0x1 << i)).isNull();
             }
         }
     }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarInfoManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarInfoManagerTest.java
index eb2e9b3..298b28d 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarInfoManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarInfoManagerTest.java
@@ -20,26 +20,32 @@
 import android.car.CarInfoManager;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+
 @SmallTest
 public class CarInfoManagerTest extends CarApiTestBase {
 
     private CarInfoManager mInfoManager;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mInfoManager = (CarInfoManager) getCar().getCarManager(Car.INFO_SERVICE);
-        assertNotNull(mInfoManager);
+        assertThat(mInfoManager).isNotNull();
     }
 
+    @Test
     public void testVehicleId() throws Exception {
-        assertNotNull(mInfoManager.getVehicleId());
+        assertThat(mInfoManager.getVehicleId()).isNotNull();
     }
 
+    @Test
     public void testNotNullItems() throws Exception {
         // call and check if it throws exception.
-        assertNotNull(mInfoManager.getManufacturer());
-        assertNotNull(mInfoManager.getModel());
-        assertNotNull(mInfoManager.getModelYear());
+        assertThat(mInfoManager.getManufacturer()).isNotNull();
+        assertThat(mInfoManager.getModel()).isNotNull();
+        assertThat(mInfoManager.getModelYear()).isNotNull();
     }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarNavigationManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarNavigationManagerTest.java
index 193886e..6732c3d 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarNavigationManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarNavigationManagerTest.java
@@ -15,6 +15,10 @@
  */
 package android.car.apitest;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
 import android.car.Car;
 import android.car.CarAppFocusManager;
 import android.car.CarAppFocusManager.OnAppFocusOwnershipCallback;
@@ -38,6 +42,9 @@
 
 import com.google.android.collect.Lists;
 
+import org.junit.Before;
+import org.junit.Test;
+
 /**
  * Unit tests for {@link CarNavigationStatusManager}
  */
@@ -49,16 +56,16 @@
     private CarNavigationStatusManager mCarNavigationManager;
     private CarAppFocusManager mCarAppFocusManager;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mCarNavigationManager =
                 (CarNavigationStatusManager) getCar().getCarManager(Car.CAR_NAVIGATION_SERVICE);
         mCarAppFocusManager =
                 (CarAppFocusManager) getCar().getCarManager(Car.APP_FOCUS_SERVICE);
-        assertNotNull(mCarAppFocusManager);
+        assertThat(mCarAppFocusManager).isNotNull();
     }
 
+    @Test
     public void testSerializeAndDeserializeProto() throws Exception {
         ImageReference imageReference = ImageReference.newBuilder().build();
         Distance distance = Distance.newBuilder().build();
@@ -74,35 +81,37 @@
         Timestamp timestamp = Timestamp.newBuilder().build();
         NavigationStateProto navigationStateProto = NavigationStateProto.newBuilder().build();
 
-        assertNotNull(imageReference);
-        assertNotNull(distance);
-        assertNotNull(maneuver);
-        assertNotNull(lane);
-        assertNotNull(laneDirection);
-        assertNotNull(cue);
-        assertNotNull(cueElement);
-        assertNotNull(step);
-        assertNotNull(latLng);
-        assertNotNull(destination);
-        assertNotNull(road);
-        assertNotNull(timestamp);
-        assertNotNull(navigationStateProto);
+        assertThat(imageReference).isNotNull();
+        assertThat(distance).isNotNull();
+        assertThat(maneuver).isNotNull();
+        assertThat(lane).isNotNull();
+        assertThat(laneDirection).isNotNull();
+        assertThat(cue).isNotNull();
+        assertThat(cueElement).isNotNull();
+        assertThat(step).isNotNull();
+        assertThat(latLng).isNotNull();
+        assertThat(destination).isNotNull();
+        assertThat(road).isNotNull();
+        assertThat(timestamp).isNotNull();
+        assertThat(navigationStateProto).isNotNull();
 
-        assertNotNull(ImageReference.parseFrom(imageReference.toByteArray()));
-        assertNotNull(Distance.parseFrom(distance.toByteArray()));
-        assertNotNull(Maneuver.parseFrom(maneuver.toByteArray()));
-        assertNotNull(Lane.parseFrom(lane.toByteArray()));
-        assertNotNull(LaneDirection.parseFrom(laneDirection.toByteArray()));
-        assertNotNull(Cue.parseFrom(cue.toByteArray()));
-        assertNotNull(CueElement.parseFrom(cueElement.toByteArray()));
-        assertNotNull(Step.parseFrom(step.toByteArray()));
-        assertNotNull(LatLng.parseFrom(latLng.toByteArray()));
-        assertNotNull(Destination.parseFrom(destination.toByteArray()));
-        assertNotNull(Road.parseFrom(road.toByteArray()));
-        assertNotNull(Timestamp.parseFrom(timestamp.toByteArray()));
-        assertNotNull(NavigationStateProto.parseFrom(navigationStateProto.toByteArray()));
+
+        assertThat(ImageReference.parseFrom(imageReference.toByteArray())).isNotNull();
+        assertThat(Distance.parseFrom(distance.toByteArray())).isNotNull();
+        assertThat(Maneuver.parseFrom(maneuver.toByteArray())).isNotNull();
+        assertThat(Lane.parseFrom(lane.toByteArray())).isNotNull();
+        assertThat(LaneDirection.parseFrom(laneDirection.toByteArray())).isNotNull();
+        assertThat(Cue.parseFrom(cue.toByteArray())).isNotNull();
+        assertThat(CueElement.parseFrom(cueElement.toByteArray())).isNotNull();
+        assertThat(Step.parseFrom(step.toByteArray())).isNotNull();
+        assertThat(LatLng.parseFrom(latLng.toByteArray())).isNotNull();
+        assertThat(Destination.parseFrom(destination.toByteArray())).isNotNull();
+        assertThat(Road.parseFrom(road.toByteArray())).isNotNull();
+        assertThat(Timestamp.parseFrom(timestamp.toByteArray())).isNotNull();
+        assertThat(NavigationStateProto.parseFrom(navigationStateProto.toByteArray())).isNotNull();
     }
 
+    @Test
     public void testSendEvent() throws Exception {
         if (mCarNavigationManager == null) {
             Log.w(TAG, "Unable to run the test: "
@@ -116,12 +125,7 @@
         bundle.putStringArrayList("BUNDLE_ARRAY_OF_STRINGS",
                 Lists.newArrayList("Value A", "Value B", "Value Z"));
 
-        try {
-            mCarNavigationManager.sendEvent(1, bundle);
-            fail();
-        } catch (IllegalStateException expected) {
-            // Expected. Client should acquire focus ownership for APP_FOCUS_TYPE_NAVIGATION.
-        }
+        assertThrows(IllegalStateException.class, () -> mCarNavigationManager.sendEvent(1, bundle));
 
         mCarAppFocusManager.addFocusListener(new CarAppFocusManager.OnAppFocusChangedListener() {
             @Override
@@ -142,8 +146,8 @@
         };
         mCarAppFocusManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION,
                 ownershipCallback);
-        assertTrue(mCarAppFocusManager.isOwningFocus(ownershipCallback,
-                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION));
+        assertThat(mCarAppFocusManager.isOwningFocus(ownershipCallback,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION)).isTrue();
 
         Log.i(TAG, "Instrument cluster: " + mCarNavigationManager.getInstrumentClusterInfo());
 
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarPackageManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarPackageManagerTest.java
index 622a2af..b1b177d 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarPackageManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarPackageManagerTest.java
@@ -16,66 +16,21 @@
 
 package android.car.apitest;
 
-import android.content.ComponentName;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-import android.os.Looper;
 import android.car.Car;
 import android.car.content.pm.CarPackageManager;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
 
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
 
 @MediumTest
-public class CarPackageManagerTest extends AndroidTestCase {
-    private static final long DEFAULT_WAIT_TIMEOUT_MS = 3000;
+public class CarPackageManagerTest extends CarApiTestBase {
 
-    private final Semaphore mConnectionWait = new Semaphore(0);
-
-    private Car mCar;
-    private CarPackageManager mCarPackageManager;
-
-    private final ServiceConnection mConnectionListener = new ServiceConnection() {
-
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            assertMainThread();
-            mConnectionWait.release();
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            assertMainThread();
-        }
-
-    };
-
-    private void assertMainThread() {
-        assertTrue(Looper.getMainLooper().isCurrentThread());
-    }
-    private void waitForConnection(long timeoutMs) throws InterruptedException {
-        mConnectionWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mCar = Car.createCar(getContext(), mConnectionListener);
-        mCar.connect();
-        waitForConnection(DEFAULT_WAIT_TIMEOUT_MS);
-        mCarPackageManager = (CarPackageManager) mCar.getCarManager(Car.PACKAGE_SERVICE);
-        assertNotNull(mCarPackageManager);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-        mCar.disconnect();
-    }
-
+    @Test
     public void testCreate() throws Exception {
-        //nothing to do for now
+        CarPackageManager carPackageManager = (CarPackageManager) getCar()
+                .getCarManager(Car.PACKAGE_SERVICE);
+        assertThat(carPackageManager).isNotNull();
     }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarProjectionManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarProjectionManagerTest.java
index db04c24..0d4d64b 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarProjectionManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarProjectionManagerTest.java
@@ -15,18 +15,26 @@
  */
 package android.car.apitest;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
 import android.app.Service;
 import android.car.Car;
 import android.car.CarProjectionManager;
 import android.car.CarProjectionManager.ProjectionAccessPointCallback;
 import android.content.Intent;
-import android.net.wifi.WifiConfiguration;
+import android.net.wifi.SoftApConfiguration;
 import android.os.Binder;
 import android.os.IBinder;
 import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.Suppress;
 
 import androidx.test.filters.RequiresDevice;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -35,17 +43,11 @@
 public class CarProjectionManagerTest extends CarApiTestBase {
     private static final String TAG = CarProjectionManagerTest.class.getSimpleName();
 
-    private final CarProjectionManager.CarProjectionListener mListener =
-            new CarProjectionManager.CarProjectionListener() {
-                @Override
-                public void onVoiceAssistantRequest(boolean fromLongPress) {
-                    //void
-                }
-            };
+    private final CarProjectionManager.CarProjectionListener mListener = (fromLongPress) -> { };
 
     private CarProjectionManager mManager;
 
-    public static class TestService extends Service {
+    public static final class TestService extends Service {
         public static Object mLock = new Object();
         private static boolean sBound;
         private final Binder mBinder = new Binder() {};
@@ -68,31 +70,30 @@
         }
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mManager = (CarProjectionManager) getCar().getCarManager(Car.PROJECTION_SERVICE);
-        assertNotNull(mManager);
+        assertThat(mManager).isNotNull();
     }
 
+    @Test
     public void testSetUnsetListeners() throws Exception {
         mManager.registerProjectionListener(
                 mListener, CarProjectionManager.PROJECTION_VOICE_SEARCH);
         mManager.unregisterProjectionListener();
     }
 
+    @Test
     public void testRegisterListenersHandleBadInput() throws Exception {
-        try {
-            mManager.registerProjectionListener(null, CarProjectionManager.PROJECTION_VOICE_SEARCH);
-            fail();
-        } catch (NullPointerException e) {
-            // expected.
-        }
+        assertThrows(NullPointerException.class, () -> mManager.registerProjectionListener(null,
+                CarProjectionManager.PROJECTION_VOICE_SEARCH));
     }
 
+    @Test
     public void testRegisterProjectionRunner() throws Exception {
-        Intent intent = new Intent(getContext(), TestService.class);
-        assertFalse(TestService.getBound());
+        Intent intent = new Intent(
+                InstrumentationRegistry.getInstrumentation().getContext(), TestService.class);
+        assertThat(TestService.getBound()).isFalse();
         mManager.registerProjectionRunner(intent);
         synchronized (TestService.mLock) {
             try {
@@ -101,24 +102,25 @@
                 // Do nothing
             }
         }
-        assertTrue(TestService.getBound());
+        assertThat(TestService.getBound()).isTrue();
         mManager.unregisterProjectionRunner(intent);
     }
 
-    //TODO(b/120081013): move this test to CTS
-    @Suppress
+
+    @Ignore("//TODO(b/120081013): move this test to CTS")
     @RequiresDevice
+    @Test
     public void testAccessPoint() throws Exception {
         CountDownLatch startedLatch = new CountDownLatch(1);
 
         mManager.startProjectionAccessPoint(new ProjectionAccessPointCallback() {
             @Override
-            public void onStarted(WifiConfiguration wifiConfiguration) {
+            public void onStarted(SoftApConfiguration softApConfiguration) {
                 startedLatch.countDown();
             }
         });
 
-        assertTrue(startedLatch.await(30, TimeUnit.SECONDS));
+        assertThat(startedLatch.await(30, TimeUnit.SECONDS)).isTrue();
 
         mManager.stopProjectionAccessPoint();
     }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarPropertyConfigTest.java b/tests/android_car_api_test/src/android/car/apitest/CarPropertyConfigTest.java
index b869191..ed0200f 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarPropertyConfigTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarPropertyConfigTest.java
@@ -16,15 +16,27 @@
 
 package android.car.apitest;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.car.VehicleAreaType;
 import android.car.hardware.CarPropertyConfig;
 import android.test.suitebuilder.annotation.MediumTest;
 
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
 /**
  * Unit tests for {@link CarPropertyConfig}
  */
 @MediumTest
 public class CarPropertyConfigTest extends CarPropertyTestBase {
 
+    @Test
     public void testCarPropertyConfigBuilder() {
         createFloatPropertyConfig();
     }
@@ -36,40 +48,42 @@
                 .addAreaConfig(WINDOW_PASSENGER, 10f, 20f)
                 .build();
 
-        assertEquals(FLOAT_PROPERTY_ID, config.getPropertyId());
-        assertEquals(CAR_AREA_TYPE, config.getAreaType());
-        assertEquals(Float.class, config.getPropertyType());
-        assertEquals(2, config.getAreaCount());
+        assertThat(config.getPropertyId()).isEqualTo(FLOAT_PROPERTY_ID);
+        assertThat(config.getAreaType()).isEqualTo(CAR_AREA_TYPE);
+        assertThat(config.getPropertyType()).isEqualTo(Float.class);
+        assertThat(config.getAreaCount()).isEqualTo(2);
 
         // We didn't assign any restrictions to WINDOW_DRIVER area.
-        assertNull(config.getMinValue(WINDOW_DRIVER));
-        assertNull(config.getMaxValue(WINDOW_DRIVER));
+        assertThat(config.getMinValue(WINDOW_DRIVER)).isNull();
+        assertThat(config.getMaxValue(WINDOW_DRIVER)).isNull();
 
-        assertEquals(10f, config.getMinValue(WINDOW_PASSENGER));
-        assertEquals(20f, config.getMaxValue(WINDOW_PASSENGER));
+        assertThat(config.getMinValue(WINDOW_PASSENGER)).isEqualTo(10f);
+        assertThat(config.getMaxValue(WINDOW_PASSENGER)).isEqualTo(20f);
 
         return config;
     }
 
+    @Test
     public void testWriteReadFloat() {
         CarPropertyConfig<Float> config = createFloatPropertyConfig();
 
         writeToParcel(config);
         CarPropertyConfig<Float> configRead = readFromParcel();
 
-        assertEquals(FLOAT_PROPERTY_ID, configRead.getPropertyId());
-        assertEquals(CAR_AREA_TYPE, configRead.getAreaType());
-        assertEquals(Float.class, configRead.getPropertyType());
-        assertEquals(2, configRead.getAreaCount());
+        assertThat(configRead.getPropertyId()).isEqualTo(FLOAT_PROPERTY_ID);
+        assertThat(configRead.getAreaType()).isEqualTo(CAR_AREA_TYPE);
+        assertThat(configRead.getPropertyType()).isEqualTo(Float.class);
+        assertThat(configRead.getAreaCount()).isEqualTo(2);
 
         // We didn't assign any restrictions to WINDOW_DRIVER area.
-        assertNull(configRead.getMinValue(WINDOW_DRIVER));
-        assertNull(configRead.getMaxValue(WINDOW_DRIVER));
+        assertThat(configRead.getMinValue(WINDOW_DRIVER)).isNull();
+        assertThat(configRead.getMaxValue(WINDOW_DRIVER)).isNull();
 
-        assertEquals(10f, configRead.getMinValue(WINDOW_PASSENGER));
-        assertEquals(20f, configRead.getMaxValue(WINDOW_PASSENGER));
+        assertThat(configRead.getMinValue(WINDOW_PASSENGER)).isEqualTo(10f);
+        assertThat(configRead.getMaxValue(WINDOW_PASSENGER)).isEqualTo(20f);
     }
 
+    @Test
     public void testWriteReadIntegerValue() {
         Integer expectedMinValue = 1;
         Integer expectedMaxValue = 20;
@@ -81,18 +95,19 @@
         writeToParcel(config);
         CarPropertyConfig<Integer> configRead = readFromParcel();
 
-        assertEquals(INT_PROPERTY_ID, configRead.getPropertyId());
-        assertEquals(CAR_AREA_TYPE, configRead.getAreaType());
-        assertEquals(Integer.class, configRead.getPropertyType());
-        assertEquals(2, configRead.getAreaCount());
+        assertThat(configRead.getPropertyId()).isEqualTo(INT_PROPERTY_ID);
+        assertThat(configRead.getAreaType()).isEqualTo(CAR_AREA_TYPE);
+        assertThat(configRead.getPropertyType()).isEqualTo(Integer.class);
+        assertThat(configRead.getAreaCount()).isEqualTo(2);
 
-        assertNull(configRead.getMinValue(WINDOW_DRIVER));
-        assertNull(configRead.getMaxValue(WINDOW_DRIVER));
+        assertThat(configRead.getMinValue(WINDOW_DRIVER)).isNull();
+        assertThat(configRead.getMaxValue(WINDOW_DRIVER)).isNull();
 
-        assertEquals(expectedMinValue, configRead.getMinValue(WINDOW_PASSENGER));
-        assertEquals(expectedMaxValue, configRead.getMaxValue(WINDOW_PASSENGER));
+        assertThat(configRead.getMinValue(WINDOW_PASSENGER)).isEqualTo(expectedMinValue);
+        assertThat(configRead.getMaxValue(WINDOW_PASSENGER)).isEqualTo(expectedMaxValue);
     }
 
+    @Test
     public void testWriteReadLongValue() {
         Long expectedMinValue = 0L;
         Long expectedMaxValue = 100L;
@@ -104,18 +119,19 @@
         writeToParcel(config);
         CarPropertyConfig<Long> configRead = readFromParcel();
 
-        assertEquals(LONG_PROPERTY_ID, configRead.getPropertyId());
-        assertEquals(CAR_AREA_TYPE, configRead.getAreaType());
-        assertEquals(Long.class, configRead.getPropertyType());
-        assertEquals(2, configRead.getAreaCount());
+        assertThat(configRead.getPropertyId()).isEqualTo(LONG_PROPERTY_ID);
+        assertThat(configRead.getAreaType()).isEqualTo(CAR_AREA_TYPE);
+        assertThat(configRead.getPropertyType()).isEqualTo(Long.class);
+        assertThat(configRead.getAreaCount()).isEqualTo(2);
 
-        assertNull(configRead.getMinValue(WINDOW_DRIVER));
-        assertNull(configRead.getMaxValue(WINDOW_DRIVER));
+        assertThat(configRead.getMinValue(WINDOW_DRIVER)).isNull();
+        assertThat(configRead.getMaxValue(WINDOW_DRIVER)).isNull();
 
-        assertEquals(expectedMinValue, configRead.getMinValue(WINDOW_PASSENGER));
-        assertEquals(expectedMaxValue, configRead.getMaxValue(WINDOW_PASSENGER));
+        assertThat(configRead.getMinValue(WINDOW_PASSENGER)).isEqualTo(expectedMinValue);
+        assertThat(configRead.getMaxValue(WINDOW_PASSENGER)).isEqualTo(expectedMaxValue);
     }
 
+    @Test
     public void testWriteReadIntegerArray() {
         CarPropertyConfig<Integer[]> config = CarPropertyConfig
                 .newBuilder(Integer[].class, INT_ARRAY_PROPERTY_ID, CAR_AREA_TYPE)
@@ -127,40 +143,58 @@
         writeToParcel(config);
         CarPropertyConfig<Integer[]> configRead = readFromParcel();
 
-        assertEquals(INT_ARRAY_PROPERTY_ID, configRead.getPropertyId());
-        assertEquals(CAR_AREA_TYPE, configRead.getAreaType());
-        assertEquals(Integer[].class, configRead.getPropertyType());
-        assertEquals(2, configRead.getAreaCount());
+        assertThat(configRead.getPropertyId()).isEqualTo(INT_ARRAY_PROPERTY_ID);
+        assertThat(configRead.getAreaType()).isEqualTo(CAR_AREA_TYPE);
+        assertThat(configRead.getPropertyType()).isEqualTo(Integer[].class);
+        assertThat(configRead.getAreaCount()).isEqualTo(2);
 
         // We didn't assign any restrictions to WINDOW_DRIVER area.
-        assertNull(configRead.getMinValue(WINDOW_PASSENGER));
-        assertNull(configRead.getMaxValue(WINDOW_PASSENGER));
-        assertNull(configRead.getMinValue(WINDOW_DRIVER));
-        assertNull(configRead.getMaxValue(WINDOW_DRIVER));
+        assertThat(configRead.getMinValue(WINDOW_PASSENGER)).isNull();
+        assertThat(configRead.getMaxValue(WINDOW_PASSENGER)).isNull();
+        assertThat(configRead.getMinValue(WINDOW_DRIVER)).isNull();
+        assertThat(configRead.getMaxValue(WINDOW_DRIVER)).isNull();
     }
 
+    @Test
     public void testWriteReadUnexpectedType() {
         CarPropertyConfig<Float> config = createFloatPropertyConfig();
-
         writeToParcel(config);
 
-        try {
-            CarPropertyConfig<Integer> integerConfig = readFromParcel();
+        CarPropertyConfig<Integer> integerConfig = readFromParcel();
+
+        // Wrote float, attempted to read integer.
+        assertThrows(ClassCastException.class, () -> {
             Integer value = integerConfig.getMinValue(WINDOW_PASSENGER);
-            fail(String.valueOf(value));
-        } catch (ClassCastException expected) {
-            // Expected. Wrote float, attempted to read integer.
-        }
+        });
 
         // Type casting from raw CarPropertyConfig should be fine, just sanity check.
-        CarPropertyConfig rawTypeConfig = readFromParcel();
-        assertEquals(10f, rawTypeConfig.getMinValue(WINDOW_PASSENGER));
+        CarPropertyConfig<?> rawTypeConfig = readFromParcel();
+        assertThat(rawTypeConfig.getMinValue(WINDOW_PASSENGER)).isEqualTo(10f);
 
-        try {
-            int intValue = (Integer) rawTypeConfig.getMinValue(WINDOW_PASSENGER);
-            fail(String.valueOf(intValue));
-        } catch (ClassCastException expected) {
-            // Expected. Wrote float, attempted to read integer.
-        }
+        // Wrote float, attempted to read integer.
+        assertThrows(ClassCastException.class, () -> {
+            int value = (Integer) rawTypeConfig.getMinValue(WINDOW_PASSENGER);
+        });
+    }
+
+    @Test
+    public void testWriteReadMixedType() {
+        List<Integer> configArray = Arrays.asList(1, 0, 1, 0, 1, 0, 0, 0, 0);
+
+        CarPropertyConfig<Object> mixedTypePropertyConfig = CarPropertyConfig
+                .newBuilder(Object.class, MIXED_TYPE_PROPERTY_ID,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
+                .addArea(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
+                .setConfigArray(new ArrayList<Integer>(configArray))
+                .build();
+        writeToParcel(mixedTypePropertyConfig);
+
+        CarPropertyConfig<Object> configRead = readFromParcel();
+
+        assertThat(configRead.getPropertyId()).isEqualTo(MIXED_TYPE_PROPERTY_ID);
+        assertThat(configRead.getAreaType()).isEqualTo(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL);
+        assertThat(configRead.getPropertyType()).isEqualTo(Object.class);
+        assertThat(configRead.getAreaCount()).isEqualTo(1);
+        assertThat(configRead.getConfigArray()).containsExactlyElementsIn(configArray).inOrder();
     }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarPropertyTestBase.java b/tests/android_car_api_test/src/android/car/apitest/CarPropertyTestBase.java
index 266a386..9649dc7 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarPropertyTestBase.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarPropertyTestBase.java
@@ -20,34 +20,29 @@
 import android.car.hardware.CarPropertyValue;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.test.AndroidTestCase;
+
+import org.junit.After;
 
 /**
  * Base class to test {@link CarPropertyConfig} and {@link CarPropertyValue}.
  */
-public class CarPropertyTestBase extends AndroidTestCase {
+public class CarPropertyTestBase {
 
     protected static final int FLOAT_PROPERTY_ID        = 0x1160BEEF;
     protected static final int INT_ARRAY_PROPERTY_ID    = 0x0041BEEF;
-    protected static final int INT_PROPERTY_ID          = 0x0040BEFF;
-    protected static final int LONG_PROPERTY_ID         = 0x0050BEFF;
+    protected static final int INT_PROPERTY_ID          = 0x0040BEEF;
+    protected static final int LONG_PROPERTY_ID         = 0x0050BEEF;
+    protected static final int MIXED_TYPE_PROPERTY_ID   = 0x01e0BEEF;
 
     protected static final int CAR_AREA_TYPE    = 0xDEADBEEF;
     protected static final int WINDOW_DRIVER    = 0x00000001;
     protected static final int WINDOW_PASSENGER = 0x00000002;
 
-    private Parcel mParcel;
+    private final Parcel mParcel = Parcel.obtain();
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mParcel = Parcel.obtain();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void recycleParcel() throws Exception {
         mParcel.recycle();
-        super.tearDown();
     }
 
     protected  <T extends Parcelable> T readFromParcel() {
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarPropertyValueTest.java b/tests/android_car_api_test/src/android/car/apitest/CarPropertyValueTest.java
index 5dd41de..97fe7ba 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarPropertyValueTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarPropertyValueTest.java
@@ -16,15 +16,21 @@
 
 package android.car.apitest;
 
+import android.car.VehicleAreaType;
 import android.car.hardware.CarPropertyValue;
 import android.test.suitebuilder.annotation.MediumTest;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+
 /**
  * Unit tests for {@link CarPropertyValue}
  */
 @MediumTest
-public class CarPropertyValueTest extends CarPropertyConfigTest {
+public class CarPropertyValueTest extends CarPropertyTestBase {
 
+    @Test
     public void testSimpleFloatValue() {
         CarPropertyValue<Float> floatValue =
                 new CarPropertyValue<>(FLOAT_PROPERTY_ID, WINDOW_DRIVER, 10f);
@@ -32,7 +38,19 @@
         writeToParcel(floatValue);
 
         CarPropertyValue<Float> valueRead = readFromParcel();
-        assertEquals(10f, valueRead.getValue());
+        assertThat(valueRead.getValue()).isEqualTo((Object) 10f);
     }
 
+    @Test
+    public void testMixedValue() {
+        CarPropertyValue<Object> mixedValue =
+                new CarPropertyValue<>(MIXED_TYPE_PROPERTY_ID,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+                        new Object[] { "android", 1, 2.0 });
+        writeToParcel(mixedValue);
+        CarPropertyValue<Object[]> valueRead = readFromParcel();
+        assertThat(valueRead.getValue()).asList().containsExactly("android", 1, 2.0).inOrder();
+        assertThat(valueRead.getPropertyId()).isEqualTo(MIXED_TYPE_PROPERTY_ID);
+        assertThat(valueRead.getAreaId()).isEqualTo(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL);
+    }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarSensorManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarSensorManagerTest.java
index f19f33d..95bc181 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarSensorManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarSensorManagerTest.java
@@ -18,59 +18,20 @@
 
 import android.car.Car;
 import android.car.hardware.CarSensorManager;
-import android.content.ComponentName;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-import android.os.Looper;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
 
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
 
 @MediumTest
-public class CarSensorManagerTest extends AndroidTestCase {
-    private static final long DEFAULT_WAIT_TIMEOUT_MS = 3000;
+public class CarSensorManagerTest extends CarApiTestBase {
 
-    private final Semaphore mConnectionWait = new Semaphore(0);
-
-    private Car mCar;
-    private CarSensorManager mCarSensorManager;
-
-    private final ServiceConnection mConnectionListener = new ServiceConnection() {
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            assertMainThread();
-        }
-
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            assertMainThread();
-            mConnectionWait.release();
-        }
-    };
-
-    private void assertMainThread() {
-        assertTrue(Looper.getMainLooper().isCurrentThread());
-    }
-    private void waitForConnection(long timeoutMs) throws InterruptedException {
-        mConnectionWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
+    @Test
+    public void testCreate() throws Exception {
+        CarSensorManager carSensorManager = (CarSensorManager) getCar()
+                .getCarManager(Car.SENSOR_SERVICE);
+        assertThat(carSensorManager).isNotNull();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mCar = Car.createCar(getContext(), mConnectionListener);
-        mCar.connect();
-        waitForConnection(DEFAULT_WAIT_TIMEOUT_MS);
-        mCarSensorManager =
-                (CarSensorManager) mCar.getCarManager(Car.SENSOR_SERVICE);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-        mCar.disconnect();
-    }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarTest.java b/tests/android_car_api_test/src/android/car/apitest/CarTest.java
index 38e566a..d1532d4 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarTest.java
@@ -16,23 +16,33 @@
 
 package android.car.apitest;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
 import android.car.Car;
 import android.car.ICar;
 import android.car.hardware.CarSensorManager;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.ServiceConnection;
 import android.os.IBinder;
-import android.os.Looper;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Test;
+
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
 @SmallTest
-public class CarTest extends AndroidTestCase {
+public class CarTest {
     private static final long DEFAULT_WAIT_TIMEOUT_MS = 3000;
 
+    private final Context mContext = InstrumentationRegistry.getInstrumentation()
+            .getTargetContext();
+
     private final Semaphore mConnectionWait = new Semaphore(0);
 
     private ICar mICar;
@@ -41,70 +51,64 @@
 
         @Override
         public void onServiceDisconnected(ComponentName name) {
-            assertMainThread();
+            CarApiTestBase.assertMainThread();
         }
 
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
-            assertMainThread();
+            CarApiTestBase.assertMainThread();
             mICar = ICar.Stub.asInterface(service);
             mConnectionWait.release();
         }
     };
 
-    private void assertMainThread() {
-        assertTrue(Looper.getMainLooper().isCurrentThread());
-    }
-
     private void waitForConnection(long timeoutMs) throws InterruptedException {
         mConnectionWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
     }
 
+    @Test
     public void testCarConnection() throws Exception {
-        Car car = Car.createCar(getContext(), mConnectionListener);
-        assertFalse(car.isConnected());
-        assertFalse(car.isConnecting());
+        Car car = Car.createCar(mContext, mConnectionListener);
+        assertThat(car.isConnected()).isFalse();
+        assertThat(car.isConnecting()).isFalse();
         car.connect();
         // TODO fix race here
         // assertTrue(car.isConnecting()); // This makes test flaky.
         waitForConnection(DEFAULT_WAIT_TIMEOUT_MS);
-        assertTrue(car.isConnected());
-        assertFalse(car.isConnecting());
+        assertThat(car.isConnected()).isTrue();
+        assertThat(car.isConnecting()).isFalse();
         CarSensorManager carSensorManager =
                 (CarSensorManager) car.getCarManager(Car.SENSOR_SERVICE);
-        assertNotNull(carSensorManager);
+        assertThat(carSensorManager).isNotNull();
         CarSensorManager carSensorManager2 =
                 (CarSensorManager) car.getCarManager(Car.SENSOR_SERVICE);
-        assertEquals(carSensorManager, carSensorManager2);
+        assertThat(carSensorManager2).isSameAs(carSensorManager);
         Object noSuchService = car.getCarManager("No such service");
-        assertNull(noSuchService);
+        assertThat(noSuchService).isNull();
         // double disconnect should be safe.
         car.disconnect();
         car.disconnect();
-        assertFalse(car.isConnected());
-        assertFalse(car.isConnecting());
+        assertThat(car.isConnected()).isFalse();
+        assertThat(car.isConnecting()).isFalse();
     }
 
+    @Test
     public void testDoubleConnect() throws Exception {
-        Car car = Car.createCar(getContext(), mConnectionListener);
-        assertFalse(car.isConnected());
-        assertFalse(car.isConnecting());
+        Car car = Car.createCar(mContext, mConnectionListener);
+        assertThat(car.isConnected()).isFalse();
+        assertThat(car.isConnecting()).isFalse();
         car.connect();
-        try {
-            car.connect();
-            fail("dobule connect should throw");
-        } catch (IllegalStateException e) {
-            // expected
-        }
+        assertThrows(IllegalStateException.class, () -> car.connect());
         car.disconnect();
     }
 
+    @Test
     public void testConstructorWithICar() throws Exception {
-        Car car = Car.createCar(getContext(), mConnectionListener);
+        Car car = Car.createCar(mContext, mConnectionListener);
         car.connect();
         waitForConnection(DEFAULT_WAIT_TIMEOUT_MS);
-        assertNotNull(mICar);
-        Car car2 = new Car(getContext(), mICar, null);
-        assertTrue(car2.isConnected());
+        assertThat(mICar).isNotNull();
+        Car car2 = new Car(mContext, mICar, null);
+        assertThat(car2.isConnected()).isTrue();
     }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java
new file mode 100644
index 0000000..421dd44
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.apitest;
+
+import static android.car.test.util.UserTestingHelper.clearUserLockCredentials;
+import static android.car.test.util.UserTestingHelper.setMaxSupportedUsers;
+import static android.car.test.util.UserTestingHelper.setUserLockCredentials;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.fail;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.car.Car;
+import android.car.testapi.BlockingUserLifecycleListener;
+import android.car.user.CarUserManager;
+import android.car.user.CarUserManager.UserLifecycleEvent;
+import android.car.user.UserSwitchResult;
+import android.content.pm.UserInfo;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+
+import androidx.test.filters.FlakyTest;
+
+import com.android.internal.infra.AndroidFuture;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public final class CarUserManagerTest extends CarApiTestBase {
+
+    private static final String TAG = CarUserManagerTest.class.getSimpleName();
+
+    private static final int PIN = 2345;
+
+    private static final int SWITCH_TIMEOUT_MS = 70_000;
+    private static final int STOP_TIMEOUT_MS = 300_000;
+
+    /**
+     * Stopping the user takes a while, even when calling force stop - change it to false if this
+     * test becomes flaky.
+     */
+    private static final boolean TEST_STOP = false;
+
+    private static final UserManager sUserManager = UserManager.get(sContext);
+
+    private static final int sMaxNumberUsersBefore = UserManager.getMaxSupportedUsers();
+
+    private static final List<Integer> sCreatedUsers = new ArrayList<>();
+
+    private static int sInitialUserId = UserHandle.USER_NULL;
+
+    private CarUserManager mCarUserManager;
+
+    @BeforeClass
+    public static void setupUsers() {
+        sInitialUserId = ActivityManager.getCurrentUser();
+        Log.i(TAG, "Running test as user " + sInitialUserId);
+        setMaxSupportedUsers(8); // Total 6 users will be created for all tests
+    }
+
+    @AfterClass
+    public static void cleanupUsers() {
+        setMaxSupportedUsers(sMaxNumberUsersBefore);
+        switchUserDirectly(sInitialUserId);
+
+        for (int i = 0; i < sCreatedUsers.size(); i++) {
+            int id = sCreatedUsers.get(i);
+            Log.d(TAG, "removeCreatedUsers: " + id);
+            if (!sUserManager.removeUser(id)) {
+                Log.wtf(TAG, "Failed to remove user " + id);
+            }
+        }
+    }
+
+    @Before
+    public void setManager() throws Exception {
+        mCarUserManager = (CarUserManager) getCar().getCarManager(Car.CAR_USER_SERVICE);
+    }
+
+    @Test
+    public void testLifecycleListener() throws Exception {
+        int oldUserId = ActivityManager.getCurrentUser();
+        int newUserId = createNewUser("Test", /* isGuest= */ false).id;
+
+        BlockingUserLifecycleListener startListener = BlockingUserLifecycleListener
+                .forSpecificEvents()
+                .forUser(newUserId)
+                .setTimeout(SWITCH_TIMEOUT_MS)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
+                .build();
+
+        Log.d(TAG, "registering start listener: " + startListener);
+        AtomicBoolean executedRef = new AtomicBoolean();
+
+        Executor mExecutor = (r) -> {
+            executedRef.set(true);
+            r.run();
+        };
+        mCarUserManager.addListener(mExecutor, startListener);
+
+        // Switch while listener is registered
+        switchUser(newUserId);
+
+        List<UserLifecycleEvent> startEvents  = startListener.waitForEvents();
+        Log.d(TAG, "Received start events: " + startEvents);
+
+        // Make sure listener callback was executed in the proper threaqd
+        assertWithMessage("not executed on executor").that(executedRef.get()).isTrue();
+
+        // Assert user ids
+        List<UserLifecycleEvent> expectedEvents = startListener.waitForEvents();
+        Log.d(TAG, "Received expected events: " + expectedEvents);
+        for (UserLifecycleEvent event : expectedEvents) {
+            assertWithMessage("wrong userId on %s", event)
+                .that(event.getUserId()).isEqualTo(newUserId);
+            assertWithMessage("wrong userHandle on %s", event)
+                .that(event.getUserHandle().getIdentifier()).isEqualTo(newUserId);
+            if (event.getEventType() == USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
+                assertWithMessage("wrong previousUserId on %s", event)
+                    .that(event.getPreviousUserId()).isEqualTo(oldUserId);
+                assertWithMessage("wrong previousUserHandle on %s", event)
+                    .that(event.getPreviousUserHandle().getIdentifier()).isEqualTo(oldUserId);
+            }
+        }
+
+        Log.d(TAG, "unregistering start listener: " + startListener);
+        mCarUserManager.removeListener(startListener);
+
+        BlockingUserLifecycleListener stopListener = BlockingUserLifecycleListener
+                .forSpecificEvents()
+                .forUser(newUserId)
+                .setTimeout(STOP_TIMEOUT_MS)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPING)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED)
+                .build();
+
+        Log.d(TAG, "registering stop listener: " + stopListener);
+        mCarUserManager.addListener(mExecutor, stopListener);
+
+        // Switch back to the initial user
+        switchUser(sInitialUserId);
+
+        if (TEST_STOP) {
+            // Must force stop the user, otherwise it can take minutes for its process to finish
+            forceStopUser(newUserId);
+
+            List<UserLifecycleEvent> stopEvents = stopListener.waitForEvents();
+            Log.d(TAG, "stopEvents: " + stopEvents + "; all events on stop listener: "
+                    + stopListener.getAllReceivedEvents());
+
+            // Assert user ids
+            for (UserLifecycleEvent event : stopEvents) {
+                assertWithMessage("wrong userId on %s", event)
+                    .that(event.getUserId()).isEqualTo(newUserId);
+                assertWithMessage("wrong userHandle on %s", event)
+                    .that(event.getUserHandle().getIdentifier()).isEqualTo(newUserId);
+            }
+        } else {
+            Log.w(TAG, "NOT testing user stop events");
+        }
+
+        // Make sure unregistered listener didn't receive any more events
+        List<UserLifecycleEvent> allStartEvents = startListener.getAllReceivedEvents();
+        Log.d(TAG, "All start events: " + startEvents);
+        assertThat(allStartEvents).containsAllIn(startEvents).inOrder();
+
+        Log.d(TAG, "unregistering stop listener: " + stopListener);
+        mCarUserManager.removeListener(stopListener);
+    }
+
+    /**
+     * Tests resume behavior when current user is ephemeral guest, a new guest user should be
+     * created and switched to.
+     */
+    @Test
+    @FlakyTest // TODO(b/158050171) remove once process is stable on user switching.
+    public void testGuestUserResumeToNewGuestUser() throws Exception {
+        // Create new guest user
+        UserInfo guestUser = createNewUser("Guest", /* isGuestUser= */ true);
+        int guestUserId = guestUser.id;
+
+        // Wait for this user to be active
+        BlockingUserLifecycleListener listener1 = BlockingUserLifecycleListener
+                .forSpecificEvents()
+                .forUser(guestUserId)
+                .setTimeout(SWITCH_TIMEOUT_MS)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
+                .build();
+        mCarUserManager.addListener(Runnable::run, listener1);
+        switchUser(guestUserId);
+        listener1.waitForEvents();
+        mCarUserManager.removeListener(listener1);
+
+        BlockingUserLifecycleListener listener2 = BlockingUserLifecycleListener
+                .forSpecificEvents()
+                .forPreviousUser(guestUserId)
+                .setTimeout(SWITCH_TIMEOUT_MS)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING)
+                .build();
+        // Make sure listener callback was executed in the proper threaqd
+        mCarUserManager.addListener(Runnable::run, listener2);
+
+        // Emulate suspend to RAM
+        suspendToRamAndResume();
+        UserLifecycleEvent event = listener2.waitForEvents().get(0);
+
+        int newGuestId = event.getUserId();
+        sCreatedUsers.add(newGuestId);
+
+        assertWithMessage("wrong user on event %s", event).that(newGuestId)
+                .isNotEqualTo(guestUserId);
+        assertWithMessage("wrong current user").that(newGuestId)
+                .isEqualTo(ActivityManager.getCurrentUser());
+        UserInfo newGuest = sUserManager.getUserInfo(newGuestId);
+        assertWithMessage("new user (%s) is not a guest", newGuest.toFullString())
+                .that(newGuest.isGuest()).isTrue();
+        assertWithMessage("wrong name on new guest(%s)", newGuest.toFullString())
+                .that(newGuest.name).isNotEqualTo(guestUser.name);
+        mCarUserManager.removeListener(listener2);
+    }
+
+    /**
+     * Tests resume behavior when current user is guest guest but with secured lock screen,
+     * resume to same guest user.
+     */
+    @Test
+    @FlakyTest // TODO(b/158050171) remove once process is stable on user switching.
+    public void testSecuredGuestUserResumeToSameUser() throws Exception {
+        // Create new guest user
+        UserInfo guestUser = createNewUser("Guest", /* isGuestUser= */ true);
+        int guestUserId = guestUser.id;
+
+        // Wait for this user to be active
+        BlockingUserLifecycleListener listener = BlockingUserLifecycleListener
+                .forSpecificEvents()
+                .forUser(guestUserId)
+                .setTimeout(SWITCH_TIMEOUT_MS)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
+                .build();
+        mCarUserManager.addListener(Runnable::run, listener);
+
+        switchUser(guestUserId);
+
+        listener.waitForEvents();
+        mCarUserManager.removeListener(listener);
+
+        setUserLockCredentials(guestUserId, PIN);
+        try {
+            // Emulate suspend to RAM
+            suspendToRamAndResume();
+
+            assertWithMessage("not resumed to previous user: %s", guestUser)
+                    .that(ActivityManager.getCurrentUser()).isEqualTo(guestUserId);
+        } finally {
+            clearUserLockCredentials(guestUserId, PIN);
+        }
+
+    }
+
+    /**
+     * Tests resume behavior when current user is persistent user.
+     */
+    @Test
+    @FlakyTest // TODO(b/158050171) remove once process is stable on user switching.
+    public void testPersistentUserResumeToUser() throws Exception {
+        int newUserId = createNewUser("Test", /* isGuest= */ false).id;
+        BlockingUserLifecycleListener listener = BlockingUserLifecycleListener
+                .forSpecificEvents()
+                .forUser(newUserId)
+                .setTimeout(SWITCH_TIMEOUT_MS)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
+                .build();
+        mCarUserManager.addListener(Runnable::run, listener);
+        switchUser(newUserId);
+        listener.waitForEvents();
+
+        // Emulate suspend to RAM
+        suspendToRamAndResume();
+
+        listener.waitForEvents();
+        assertWithMessage("not resumed to previous user: %s", newUserId)
+                .that(ActivityManager.getCurrentUser()).isEqualTo(newUserId);
+
+        mCarUserManager.removeListener(listener);
+    }
+
+    @NonNull
+    private static UserInfo createNewUser(String name, boolean isGuest) {
+        name = "CarUserManagerTest." + name;
+        Log.i(TAG, "Creating new user " + name);
+        UserInfo newUser = isGuest ? sUserManager.createGuest(sContext, name)
+                : sUserManager.createUser(name, /* flags= */ 0);
+        sCreatedUsers.add(newUser.id);
+        Log.i(TAG, "Created new user: " + newUser.toFullString());
+        return newUser;
+    }
+
+    private void switchUser(@UserIdInt int userId) throws Exception {
+        Log.i(TAG, "Switching to user " + userId + " using CarUserManager");
+
+        AndroidFuture<UserSwitchResult> future = mCarUserManager.switchUser(userId);
+        UserSwitchResult result = future.get(SWITCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        Log.d(TAG, "Result: " + result);
+
+        // TODO(b/155326051): use result.isSuccess()
+        if (result.getStatus() != UserSwitchResult.STATUS_SUCCESSFUL) {
+            fail("Could not switch to user " + userId + ": " + result);
+        }
+    }
+
+    // TODO: ideally should use switchUser(), but that requires CarUserManager, which is not static.
+    private static void switchUserDirectly(@UserIdInt int userId) {
+        ActivityManager am = sContext.getSystemService(ActivityManager.class);
+        int currentUserId = am.getCurrentUser();
+        Log.i(TAG, "Switching to user " + userId + " using AM, when current is " + currentUserId);
+
+        if (currentUserId == userId) {
+            Log.v(TAG, "current user is already " + userId);
+            return;
+        }
+        if (!am.switchUser(userId)) {
+            fail("Could not switch to user " + userId + " using ActivityManager (current user is "
+                    + currentUserId + ")");
+        }
+    }
+
+    private static void forceStopUser(@UserIdInt int userId) throws RemoteException {
+        Log.i(TAG, "Force-stopping user " + userId);
+        IActivityManager am = ActivityManager.getService();
+        am.stopUser(userId, /* force=*/ true, /* listener= */ null);
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarUxRestrictionsConfigurationTest.java b/tests/android_car_api_test/src/android/car/apitest/CarUxRestrictionsConfigurationTest.java
index 030b133..6f74074 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarUxRestrictionsConfigurationTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarUxRestrictionsConfigurationTest.java
@@ -26,6 +26,10 @@
 import static android.car.drivingstate.CarUxRestrictionsConfiguration.Builder.SpeedRange.MAX_SPEED;
 import static android.car.drivingstate.CarUxRestrictionsManager.UX_RESTRICTION_MODE_BASELINE;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
 import android.car.drivingstate.CarUxRestrictions;
 import android.car.drivingstate.CarUxRestrictionsConfiguration;
 import android.car.drivingstate.CarUxRestrictionsConfiguration.Builder;
@@ -36,8 +40,6 @@
 
 import androidx.test.filters.SmallTest;
 
-import junit.framework.TestCase;
-
 import org.junit.Test;
 
 import java.io.ByteArrayInputStream;
@@ -51,12 +53,12 @@
  * Unit test for UXR config and its subclasses.
  */
 @SmallTest
-public class CarUxRestrictionsConfigurationTest extends TestCase {
+public class CarUxRestrictionsConfigurationTest {
 
     private static final String UX_RESTRICTION_MODE_PASSENGER = "passenger";
 
-    @Test
     // This test verifies the expected way to build config would succeed.
+    @Test
     public void testConstruction() {
         new Builder().build();
 
@@ -91,42 +93,44 @@
                 .build();
     }
 
+    @Test
     public void testUnspecifiedDrivingStateUsesDefaultRestriction() {
         CarUxRestrictionsConfiguration config = new Builder().build();
 
         CarUxRestrictions parkedRestrictions = config.getUxRestrictions(DRIVING_STATE_PARKED, 0f);
-        assertTrue(parkedRestrictions.isRequiresDistractionOptimization());
-        assertEquals(parkedRestrictions.getActiveRestrictions(), UX_RESTRICTIONS_FULLY_RESTRICTED);
+        assertThat(parkedRestrictions.isRequiresDistractionOptimization()).isTrue();
+        assertThat(parkedRestrictions.getActiveRestrictions())
+                .isEqualTo(UX_RESTRICTIONS_FULLY_RESTRICTED);
 
         CarUxRestrictions movingRestrictions = config.getUxRestrictions(DRIVING_STATE_MOVING, 1f);
-        assertTrue(movingRestrictions.isRequiresDistractionOptimization());
-        assertEquals(movingRestrictions.getActiveRestrictions(), UX_RESTRICTIONS_FULLY_RESTRICTED);
+        assertThat(movingRestrictions.isRequiresDistractionOptimization()).isTrue();
+        assertThat(movingRestrictions.getActiveRestrictions())
+                .isEqualTo(UX_RESTRICTIONS_FULLY_RESTRICTED);
     }
 
+    @Test
     public void testBuilderValidation_UnspecifiedStateUsesRestrictiveDefault() {
         CarUxRestrictionsConfiguration config = new Builder()
                 .setUxRestrictions(DRIVING_STATE_MOVING, true, UX_RESTRICTIONS_FULLY_RESTRICTED)
                 .build();
-        assertTrue(config.getUxRestrictions(DRIVING_STATE_PARKED, 0f)
-                .isRequiresDistractionOptimization());
-        assertTrue(config.getUxRestrictions(DRIVING_STATE_IDLING, 0f)
-                .isRequiresDistractionOptimization());
+        assertThat(config.getUxRestrictions(DRIVING_STATE_PARKED, 0f)
+        .isRequiresDistractionOptimization()).isTrue();
+        assertThat(config.getUxRestrictions(DRIVING_STATE_IDLING, 0f)
+        .isRequiresDistractionOptimization()).isTrue();
     }
 
+    @Test
     public void testBuilderValidation_NonMovingStateHasOneRestriction() {
         Builder builder = new Builder();
         builder.setUxRestrictions(DRIVING_STATE_IDLING,
                 true, UX_RESTRICTIONS_NO_VIDEO);
         builder.setUxRestrictions(DRIVING_STATE_IDLING,
                 false, UX_RESTRICTIONS_BASELINE);
-        try {
-            builder.build();
-            fail();
-        } catch (Exception e) {
-            // Expected exception.
-        }
+
+        assertThrows(Exception.class, () -> builder.build());
     }
 
+    @Test
     public void testBuilderValidation_PassengerModeNoSpeedRangeOverlap() {
         Builder builder = new Builder();
         builder.setUxRestrictions(DRIVING_STATE_MOVING, new DrivingStateRestrictions()
@@ -137,14 +141,10 @@
                 .setDistractionOptimizationRequired(true)
                 .setRestrictions(UX_RESTRICTIONS_FULLY_RESTRICTED)
                 .setSpeedRange(new Builder.SpeedRange(1f)));
-        try {
-            builder.build();
-            fail();
-        } catch (Exception e) {
-            // Expected exception.
-        }
+        assertThrows(Exception.class, () -> builder.build());
     }
 
+    @Test
     public void testBuilderValidation_PassengerModeCanSpecifySubsetOfSpeedRange() {
         CarUxRestrictionsConfiguration config = new Builder()
                 .setUxRestrictions(DRIVING_STATE_MOVING, new DrivingStateRestrictions()
@@ -154,10 +154,11 @@
                         .setSpeedRange(new Builder.SpeedRange(1f, 2f)))
                 .build();
 
-        assertTrue(config.getUxRestrictions(DRIVING_STATE_MOVING, 1f, UX_RESTRICTION_MODE_PASSENGER)
-                .isRequiresDistractionOptimization());
+        assertThat(config.getUxRestrictions(DRIVING_STATE_MOVING, 1f, UX_RESTRICTION_MODE_PASSENGER)
+                .isRequiresDistractionOptimization()).isTrue();
     }
 
+    @Test
     public void testBuilderValidation_MultipleSpeedRange_NonZeroStart() {
         Builder builder = new Builder();
         builder.setUxRestrictions(DRIVING_STATE_MOVING,
@@ -166,27 +167,19 @@
         builder.setUxRestrictions(DRIVING_STATE_MOVING,
                 new Builder.SpeedRange(2, MAX_SPEED),
                 true, UX_RESTRICTIONS_FULLY_RESTRICTED);
-        try {
-            builder.build();
-            fail();
-        } catch (Exception e) {
-            // Expected exception.
-        }
+        assertThrows(Exception.class, () -> builder.build());
     }
 
+    @Test
     public void testBuilderValidation_SpeedRange_NonZeroStart() {
         Builder builder = new Builder();
         builder.setUxRestrictions(DRIVING_STATE_MOVING,
                 new Builder.SpeedRange(1, MAX_SPEED),
                 true, UX_RESTRICTIONS_FULLY_RESTRICTED);
-        try {
-            builder.build();
-            fail();
-        } catch (Exception e) {
-            // Expected exception.
-        }
+        assertThrows(Exception.class, () -> builder.build());
     }
 
+    @Test
     public void testBuilderValidation_SpeedRange_Overlap() {
         Builder builder = new Builder();
         builder.setUxRestrictions(DRIVING_STATE_MOVING,
@@ -195,14 +188,10 @@
         builder.setUxRestrictions(DRIVING_STATE_MOVING,
                 new Builder.SpeedRange(4), true,
                 UX_RESTRICTIONS_FULLY_RESTRICTED);
-        try {
-            builder.build();
-            fail();
-        } catch (Exception e) {
-            // Expected exception.
-        }
+        assertThrows(Exception.class, () -> builder.build());
     }
 
+    @Test
     public void testBuilderValidation_SpeedRange_Gap() {
         Builder builder = new Builder();
         builder.setUxRestrictions(DRIVING_STATE_MOVING,
@@ -211,26 +200,17 @@
         builder.setUxRestrictions(DRIVING_STATE_MOVING,
                 new Builder.SpeedRange(8), true,
                 UX_RESTRICTIONS_FULLY_RESTRICTED);
-        try {
-            builder.build();
-            fail();
-        } catch (Exception e) {
-            // Expected exception.
-        }
+        assertThrows(Exception.class, () -> builder.build());
     }
 
+    @Test
     public void testBuilderValidation_NonMovingStateCannotUseSpeedRange() {
         Builder builder = new Builder();
-        try {
-            builder.setUxRestrictions(DRIVING_STATE_PARKED,
-                    new Builder.SpeedRange(0, 5), true,
-                    UX_RESTRICTIONS_FULLY_RESTRICTED);
-            fail();
-        } catch (Exception e) {
-            // Expected exception.
-        }
+        assertThrows(Exception.class, () -> builder.setUxRestrictions(DRIVING_STATE_PARKED,
+                new Builder.SpeedRange(0, 5), true, UX_RESTRICTIONS_FULLY_RESTRICTED));
     }
 
+    @Test
     public void testBuilderValidation_MultipleMovingRestrictionsShouldAllContainSpeedRange() {
         Builder builder = new Builder();
         builder.setUxRestrictions(DRIVING_STATE_MOVING, new DrivingStateRestrictions()
@@ -240,123 +220,115 @@
                 .setDistractionOptimizationRequired(true)
                 .setRestrictions(UX_RESTRICTIONS_FULLY_RESTRICTED)
                 .setSpeedRange(new Builder.SpeedRange(1f)));
-        try {
-            builder.build();
-            fail();
-        } catch (Exception e) {
-            // Expected exception.
-        }
+        assertThrows(Exception.class, () -> builder.build());
     }
 
+    @Test
     public void testSpeedRange_Construction() {
         new Builder.SpeedRange(0f);
         new Builder.SpeedRange(0f, 1f);
         new Builder.SpeedRange(0f, MAX_SPEED);
     }
 
+    @Test
     public void testSpeedRange_NoNegativeMin() {
-        try {
-            new Builder.SpeedRange(-2f, 1f);
-        } catch (Exception e) {
-            // Expected exception.
-        }
+        assertThrows(Exception.class, () -> new Builder.SpeedRange(-2f, 1f));
     }
 
+    @Test
     public void testSpeedRange_NoNegativeMax() {
-        try {
-            new Builder.SpeedRange(2f, -1f);
-        } catch (Exception e) {
-            // Expected exception.
-        }
+        assertThrows(Exception.class, () -> new Builder.SpeedRange(2f, -1f));
     }
 
+    @Test
     public void testSpeedRange_MinCannotBeMaxSpeed() {
-        try {
-            new Builder.SpeedRange(MAX_SPEED, 1f);
-        } catch (Exception e) {
-            // Expected exception.
-        }
+        assertThrows(Exception.class, () -> new Builder.SpeedRange(MAX_SPEED, 1f));
     }
 
+    @Test
     public void testSpeedRange_MinGreaterThanMax() {
-        try {
-            new Builder.SpeedRange(5f, 2f);
-        } catch (Exception e) {
-            // Expected exception.
-        }
+        assertThrows(Exception.class, () -> new Builder.SpeedRange(5f, 2f));
     }
 
+    @Test
     public void testSpeedRangeComparison_DifferentMin() {
         Builder.SpeedRange s1 =
                 new Builder.SpeedRange(1f);
         Builder.SpeedRange s2 =
                 new Builder.SpeedRange(2f);
-        assertTrue(s1.compareTo(s2) < 0);
-        assertTrue(s2.compareTo(s1) > 0);
+        assertThat(s1.compareTo(s2)).isLessThan(0);
+        assertThat(s2.compareTo(s1)).isGreaterThan(0);
     }
 
+    @Test
     public void testSpeedRangeComparison_SameMin() {
         Builder.SpeedRange s1 =
                 new Builder.SpeedRange(1f);
         Builder.SpeedRange s2 =
                 new Builder.SpeedRange(1f);
-        assertEquals(0, s1.compareTo(s2));
+        assertThat(s1.compareTo(s2)).isEqualTo(0);
     }
 
+    @Test
     public void testSpeedRangeComparison_SameMinDifferentMax() {
         Builder.SpeedRange s1 =
                 new Builder.SpeedRange(0f, 1f);
         Builder.SpeedRange s2 =
                 new Builder.SpeedRange(0f, 2f);
-        assertTrue(s1.compareTo(s2) < 0);
-        assertTrue(s2.compareTo(s1) > 0);
+        assertThat(s1.compareTo(s2)).isLessThan(0);
+        assertThat(s2.compareTo(s1)).isGreaterThan(0);
     }
 
+    @Test
     public void testSpeedRangeComparison_MaxSpeed() {
         Builder.SpeedRange s1 =
                 new Builder.SpeedRange(0f, 1f);
         Builder.SpeedRange s2 =
                 new Builder.SpeedRange(0f);
-        assertTrue(s1.compareTo(s2) < 0);
-        assertTrue(s2.compareTo(s1) > 0);
+        assertThat(s1.compareTo(s2)).isLessThan(0);
+        assertThat(s2.compareTo(s1)).isGreaterThan(0);
     }
 
+    @Test
+    @SuppressWarnings("TruthSelfEquals")
     public void testSpeedRangeEquals() {
         Builder.SpeedRange s1, s2;
 
         s1 = new Builder.SpeedRange(0f);
-        assertEquals(s1, s1);
+        assertThat(s1).isEqualTo(s1);
 
         s1 = new Builder.SpeedRange(1f);
         s2 = new Builder.SpeedRange(1f);
-        assertEquals(0, s1.compareTo(s2));
-        assertEquals(s1, s2);
+        assertThat(s1.compareTo(s2)).isEqualTo(0);
+        assertThat(s2).isEqualTo(s1);
 
         s1 = new Builder.SpeedRange(0f, 1f);
         s2 = new Builder.SpeedRange(0f, 1f);
-        assertEquals(s1, s2);
+        assertThat(s2).isEqualTo(s1);
 
         s1 = new Builder.SpeedRange(0f, MAX_SPEED);
         s2 = new Builder.SpeedRange(0f, MAX_SPEED);
-        assertEquals(s1, s2);
+        assertThat(s2).isEqualTo(s1);
 
         s1 = new Builder.SpeedRange(0f);
         s2 = new Builder.SpeedRange(1f);
-        assertFalse(s1.equals(s2));
+        assertThat(s1).isNotEqualTo(s2);
 
         s1 = new Builder.SpeedRange(0f, 1f);
         s2 = new Builder.SpeedRange(0f, 2f);
-        assertFalse(s1.equals(s2));
+        assertThat(s1).isNotEqualTo(s2);
     }
 
-    public void testJsonSerialization_DefaultConstructor() {
+    @Test
+    public void testJsonSerialization_DefaultConstructor() throws Exception {
         CarUxRestrictionsConfiguration config =
                 new Builder().build();
 
         verifyConfigThroughJsonSerialization(config, /* schemaVersion= */ 2);
     }
 
-    public void testJsonSerialization_RestrictionParameters() {
+    @Test
+    public void testJsonSerialization_RestrictionParameters() throws Exception {
         CarUxRestrictionsConfiguration config = new Builder()
                 .setMaxStringLength(1)
                 .setMaxCumulativeContentItems(1)
@@ -366,7 +338,8 @@
         verifyConfigThroughJsonSerialization(config, /* schemaVersion= */ 2);
     }
 
-    public void testJsonSerialization_NonMovingStateRestrictions() {
+    @Test
+    public void testJsonSerialization_NonMovingStateRestrictions() throws Exception {
         CarUxRestrictionsConfiguration config = new Builder()
                 .setUxRestrictions(DRIVING_STATE_PARKED, false, UX_RESTRICTIONS_BASELINE)
                 .build();
@@ -374,7 +347,8 @@
         verifyConfigThroughJsonSerialization(config, /* schemaVersion= */ 2);
     }
 
-    public void testJsonSerialization_MovingStateNoSpeedRange() {
+    @Test
+    public void testJsonSerialization_MovingStateNoSpeedRange() throws Exception {
         CarUxRestrictionsConfiguration config = new Builder()
                 .setUxRestrictions(DRIVING_STATE_MOVING, true, UX_RESTRICTIONS_FULLY_RESTRICTED)
                 .build();
@@ -382,7 +356,8 @@
         verifyConfigThroughJsonSerialization(config, /* schemaVersion= */ 2);
     }
 
-    public void testJsonSerialization_MovingStateWithSpeedRange() {
+    @Test
+    public void testJsonSerialization_MovingStateWithSpeedRange() throws Exception {
         CarUxRestrictionsConfiguration config = new Builder()
                 .setUxRestrictions(DRIVING_STATE_MOVING, new DrivingStateRestrictions()
                         .setDistractionOptimizationRequired(true)
@@ -397,7 +372,8 @@
         verifyConfigThroughJsonSerialization(config, /* schemaVersion= */ 2);
     }
 
-    public void testJsonSerialization_UxRestrictionMode() {
+    @Test
+    public void testJsonSerialization_UxRestrictionMode() throws Exception {
         CarUxRestrictionsConfiguration config = new Builder()
                 // Passenger mode
                 .setUxRestrictions(DRIVING_STATE_MOVING, new DrivingStateRestrictions()
@@ -471,21 +447,18 @@
 
         CarUxRestrictionsConfiguration deserialized = CarUxRestrictionsConfiguration.readJson(
                 new JsonReader(new StringReader(v1LegacyJsonFormat)), /* schemaVersion= */ 1);
-        assertEquals(expectedConfig, deserialized);
+        assertThat(deserialized).isEqualTo(expectedConfig);
     }
 
 
     @Test
     public void testJsonSerialization_ReadUnsupportedVersion_ThrowsException() throws Exception {
         int unsupportedVersion = -1;
-        try {
-            CarUxRestrictionsConfiguration deserialized = CarUxRestrictionsConfiguration.readJson(
-                    new JsonReader(new StringReader("")), unsupportedVersion);
-        } catch (IllegalArgumentException e) {
-            // expected exception
-        }
+        assertThrows(IllegalArgumentException.class, () -> CarUxRestrictionsConfiguration.readJson(
+                new JsonReader(new StringReader("")), unsupportedVersion));
     }
 
+    @Test
     public void testDump() {
         CarUxRestrictionsConfiguration[] configs = new CarUxRestrictionsConfiguration[]{
                 // Driving state with no speed range
@@ -536,6 +509,7 @@
         }
     }
 
+    @Test
     public void testDumpContainsNecessaryInfo() {
         CarUxRestrictionsConfiguration config = new Builder()
                 .setUxRestrictions(DRIVING_STATE_MOVING, new DrivingStateRestrictions()
@@ -557,17 +531,18 @@
         }
 
         String dump = new String(output.toByteArray());
-        assertTrue(dump.contains("Max String length"));
-        assertTrue(dump.contains("Max Cumulative Content Items"));
-        assertTrue(dump.contains("Max Content depth"));
-        assertTrue(dump.contains("State:moving"));
-        assertTrue(dump.contains("Speed Range"));
-        assertTrue(dump.contains("Requires DO?"));
-        assertTrue(dump.contains("Restrictions"));
-        assertTrue(dump.contains("passenger mode"));
-        assertTrue(dump.contains("baseline mode"));
+        assertThat(dump).contains("Max String length");
+        assertThat(dump).contains("Max Cumulative Content Items");
+        assertThat(dump).contains("Max Content depth");
+        assertThat(dump).contains("State:moving");
+        assertThat(dump).contains("Speed Range");
+        assertThat(dump).contains("Requires DO?");
+        assertThat(dump).contains("Restrictions");
+        assertThat(dump).contains("passenger mode");
+        assertThat(dump).contains("baseline mode");
     }
 
+    @Test
     public void testSetUxRestrictions_UnspecifiedModeDefaultsToBaseline() {
         CarUxRestrictionsConfiguration config = new Builder()
                 .setUxRestrictions(DRIVING_STATE_PARKED, new DrivingStateRestrictions()
@@ -576,13 +551,14 @@
                 .build();
 
         CarUxRestrictions restrictions = config.getUxRestrictions(DRIVING_STATE_PARKED, 0f);
-        assertTrue(restrictions.isRequiresDistractionOptimization());
-        assertEquals(UX_RESTRICTIONS_NO_VIDEO, restrictions.getActiveRestrictions());
+        assertThat(restrictions.isRequiresDistractionOptimization()).isTrue();
+        assertThat(restrictions.getActiveRestrictions()).isEqualTo(UX_RESTRICTIONS_NO_VIDEO);
 
-        assertTrue(restrictions.isSameRestrictions(
-                config.getUxRestrictions(DRIVING_STATE_PARKED, 0f, UX_RESTRICTION_MODE_BASELINE)));
+        assertThat(restrictions.isSameRestrictions(
+        config.getUxRestrictions(DRIVING_STATE_PARKED, 0f, UX_RESTRICTION_MODE_BASELINE))).isTrue();
     }
 
+    @Test
     public void testSetUxRestrictions_PassengerMode() {
         CarUxRestrictionsConfiguration config = new Builder()
                 .setUxRestrictions(DRIVING_STATE_PARKED, new DrivingStateRestrictions()
@@ -596,12 +572,12 @@
 
         CarUxRestrictions passenger = config.getUxRestrictions(
                 DRIVING_STATE_PARKED, 0f, UX_RESTRICTION_MODE_PASSENGER);
-        assertFalse(passenger.isRequiresDistractionOptimization());
+        assertThat(passenger.isRequiresDistractionOptimization()).isFalse();
 
         CarUxRestrictions baseline = config.getUxRestrictions(
                 DRIVING_STATE_PARKED, 0f, UX_RESTRICTION_MODE_BASELINE);
-        assertTrue(baseline.isRequiresDistractionOptimization());
-        assertEquals(UX_RESTRICTIONS_NO_VIDEO, baseline.getActiveRestrictions());
+        assertThat(baseline.isRequiresDistractionOptimization()).isTrue();
+        assertThat(baseline.getActiveRestrictions()).isEqualTo(UX_RESTRICTIONS_NO_VIDEO);
     }
 
     @Test
@@ -614,8 +590,8 @@
 
         CarUxRestrictions passenger = config.getUxRestrictions(
                 DRIVING_STATE_PARKED, 0f, UX_RESTRICTION_MODE_PASSENGER);
-        assertTrue(passenger.isRequiresDistractionOptimization());
-        assertEquals(UX_RESTRICTIONS_NO_VIDEO, passenger.getActiveRestrictions());
+        assertThat(passenger.isRequiresDistractionOptimization()).isTrue();
+        assertThat(passenger.getActiveRestrictions()).isEqualTo(UX_RESTRICTIONS_NO_VIDEO);
     }
 
     @Test
@@ -633,8 +609,8 @@
         // Retrieve with passenger mode for a moving state
         CarUxRestrictions passenger = config.getUxRestrictions(
                 DRIVING_STATE_MOVING, 1f, UX_RESTRICTION_MODE_PASSENGER);
-        assertTrue(passenger.isRequiresDistractionOptimization());
-        assertEquals(UX_RESTRICTIONS_NO_VIDEO, passenger.getActiveRestrictions());
+        assertThat(passenger.isRequiresDistractionOptimization()).isTrue();
+        assertThat(passenger.getActiveRestrictions()).isEqualTo(UX_RESTRICTIONS_NO_VIDEO);
     }
 
     @Test
@@ -653,15 +629,16 @@
         // Retrieve at speed within passenger mode range.
         CarUxRestrictions passenger = config.getUxRestrictions(
                 DRIVING_STATE_MOVING, 5f, UX_RESTRICTION_MODE_PASSENGER);
-        assertFalse(passenger.isRequiresDistractionOptimization());
+        assertThat(passenger.isRequiresDistractionOptimization()).isFalse();
 
         // Retrieve with passenger mode but outside speed range
         CarUxRestrictions baseline = config.getUxRestrictions(
                 DRIVING_STATE_MOVING, 1f, UX_RESTRICTION_MODE_PASSENGER);
-        assertTrue(baseline.isRequiresDistractionOptimization());
-        assertEquals(UX_RESTRICTIONS_NO_VIDEO, baseline.getActiveRestrictions());
+        assertThat(baseline.isRequiresDistractionOptimization()).isTrue();
+        assertThat(baseline.getActiveRestrictions()).isEqualTo(UX_RESTRICTIONS_NO_VIDEO);
     }
 
+    @Test
     public void testHasSameParameters_SameParameters() {
         CarUxRestrictionsConfiguration one = new CarUxRestrictionsConfiguration.Builder()
                 .setMaxStringLength(1)
@@ -675,9 +652,10 @@
                 .setMaxContentDepth(1)
                 .build();
 
-        assertTrue(one.hasSameParameters(other));
+        assertThat(one.hasSameParameters(other)).isTrue();
     }
 
+    @Test
     public void testHasSameParameters_DifferentParameters() {
         CarUxRestrictionsConfiguration one = new CarUxRestrictionsConfiguration.Builder()
                 .setMaxStringLength(2)
@@ -691,9 +669,10 @@
                 .setMaxContentDepth(1)
                 .build();
 
-        assertFalse(one.hasSameParameters(other));
+        assertThat(one.hasSameParameters(other)).isFalse();
     }
 
+    @Test
     public void testConfigurationEquals() {
         CarUxRestrictionsConfiguration one = new CarUxRestrictionsConfiguration.Builder()
                 .setMaxStringLength(2)
@@ -713,10 +692,11 @@
                         new DrivingStateRestrictions().setRestrictions(UX_RESTRICTIONS_NO_VIDEO))
                 .build();
 
-        assertEquals(one, other);
-        assertEquals(one.hashCode(), other.hashCode());
+        assertThat(other).isEqualTo(one);
+        assertThat(other.hashCode()).isEqualTo(one.hashCode());
     }
 
+    @Test
     public void testConfigurationEquals_DifferentRestrictions() {
         CarUxRestrictionsConfiguration one = new CarUxRestrictionsConfiguration.Builder()
                 .setMaxStringLength(2)
@@ -737,9 +717,10 @@
                         new DrivingStateRestrictions().setRestrictions(UX_RESTRICTIONS_BASELINE))
                 .build();
 
-        assertFalse(one.equals(other));
+        assertThat(one.equals(other)).isFalse();
     }
 
+    @Test
     public void testParcelableConfiguration() {
         CarUxRestrictionsConfiguration config = new CarUxRestrictionsConfiguration.Builder()
                 .setPhysicalPort((byte) 1)
@@ -766,9 +747,10 @@
 
         CarUxRestrictionsConfiguration deserialized =
                 CarUxRestrictionsConfiguration.CREATOR.createFromParcel(parcel);
-        assertEquals(deserialized, config);
+        assertThat(config).isEqualTo(deserialized);
     }
 
+    @Test
     public void testParcelableConfiguration_serializeNullPhysicalPort() {
         // Not setting physical port leaves it null.
         CarUxRestrictionsConfiguration config = new CarUxRestrictionsConfiguration.Builder()
@@ -788,8 +770,8 @@
 
         CarUxRestrictionsConfiguration deserialized =
                 CarUxRestrictionsConfiguration.CREATOR.createFromParcel(parcel);
-        assertEquals(deserialized, config);
-        assertNull(deserialized.getPhysicalPort());
+        assertThat(config).isEqualTo(deserialized);
+        assertThat(deserialized.getPhysicalPort()).isNull();
     }
 
     /**
@@ -797,23 +779,17 @@
      * Asserts the deserialized config is the same as input.
      */
     private void verifyConfigThroughJsonSerialization(CarUxRestrictionsConfiguration config,
-            int schemaVersion) {
+            int schemaVersion) throws Exception {
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         try (JsonWriter writer = new JsonWriter(new OutputStreamWriter(out))) {
             config.writeJson(writer);
-        } catch (Exception e) {
-            e.printStackTrace();
-            fail();
         }
 
         ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
         try (JsonReader reader = new JsonReader(new InputStreamReader(in))) {
             CarUxRestrictionsConfiguration deserialized = CarUxRestrictionsConfiguration.readJson(
                     reader, schemaVersion);
-            assertEquals(config, deserialized);
-        } catch (Exception e) {
-            e.printStackTrace();
-            fail();
+            assertThat(deserialized).isEqualTo(config);
         }
     }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/FuelTypeTest.java b/tests/android_car_api_test/src/android/car/apitest/FuelTypeTest.java
new file mode 100644
index 0000000..2a9481d
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/FuelTypeTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.apitest;
+
+import android.car.FuelType;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+
+@SmallTest
+public final class FuelTypeTest {
+    @Test
+    public void testMatchWithVehicleHal() {
+        assertThat(FuelType.UNKNOWN)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.FuelType.FUEL_TYPE_UNKNOWN);
+
+        assertThat(FuelType.UNLEADED)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.FuelType.FUEL_TYPE_UNLEADED);
+
+        assertThat(FuelType.LEADED)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.FuelType.FUEL_TYPE_LEADED);
+
+        assertThat(FuelType.DIESEL_1)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.FuelType.FUEL_TYPE_DIESEL_1);
+
+        assertThat(FuelType.DIESEL_2)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.FuelType.FUEL_TYPE_DIESEL_2);
+
+        assertThat(FuelType.BIODIESEL)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.FuelType.FUEL_TYPE_BIODIESEL);
+
+        assertThat(FuelType.E85)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.FuelType.FUEL_TYPE_E85);
+
+        assertThat(FuelType.LPG)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.FuelType.FUEL_TYPE_LPG);
+
+        assertThat(FuelType.CNG)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.FuelType.FUEL_TYPE_CNG);
+
+        assertThat(FuelType.LNG)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.FuelType.FUEL_TYPE_LNG);
+
+        assertThat(FuelType.ELECTRIC)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.FuelType.FUEL_TYPE_ELECTRIC);
+
+        assertThat(FuelType.HYDROGEN)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.FuelType.FUEL_TYPE_HYDROGEN);
+
+        assertThat(FuelType.OTHER)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.FuelType.FUEL_TYPE_OTHER);
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/PortLocationTypeTest.java b/tests/android_car_api_test/src/android/car/apitest/PortLocationTypeTest.java
new file mode 100644
index 0000000..c00889f
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/PortLocationTypeTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.apitest;
+
+import android.car.PortLocationType;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+
+@SmallTest
+public final class PortLocationTypeTest {
+    @Test
+    public void testMatchWithVehicleHal() {
+        assertThat(PortLocationType.UNKNOWN)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.PortLocationType.UNKNOWN);
+
+        assertThat(PortLocationType.FRONT_LEFT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.PortLocationType.FRONT_LEFT);
+
+        assertThat(PortLocationType.FRONT_RIGHT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.PortLocationType.FRONT_RIGHT);
+
+        assertThat(PortLocationType.REAR_RIGHT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.PortLocationType.REAR_RIGHT);
+
+        assertThat(PortLocationType.REAR_LEFT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.PortLocationType.REAR_LEFT);
+
+        assertThat(PortLocationType.FRONT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.PortLocationType.FRONT);
+
+        assertThat(PortLocationType.REAR)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.PortLocationType.REAR);
+
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/PreInstalledPackagesTest.java b/tests/android_car_api_test/src/android/car/apitest/PreInstalledPackagesTest.java
new file mode 100644
index 0000000..791f5d1
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/PreInstalledPackagesTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.apitest;
+
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+
+import static org.junit.Assert.fail;
+
+import android.platform.test.annotations.Presubmit;
+import android.text.TextUtils;
+
+import androidx.test.filters.FlakyTest;
+
+import org.junit.Test;
+
+@Presubmit
+public final class PreInstalledPackagesTest {
+
+    @Test
+    public void testNoCriticalErrors_currentMode() {
+        assertNoCriticalErrors(/* enforceMode= */ false);
+    }
+
+    @FlakyTest // TODO(b/157263778): still failing on cuttlefish
+    @Test
+    public void testNoCriticalErrors_enforceMode() {
+        assertNoCriticalErrors(/* enforceMode= */ true);
+    }
+
+    private static void assertNoCriticalErrors(boolean enforceMode) {
+        String cmd = "cmd user report-system-user-package-whitelist-problems --critical-only%s";
+        String mode =  enforceMode ? " --mode 1" : "";
+        String result = runShellCommand(cmd, mode);
+        if (!TextUtils.isEmpty(result)) {
+            fail("Command '" + String.format(cmd, mode) + "' reported errors:\n" + result);
+        }
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/VehicleAreaMirrorTest.java b/tests/android_car_api_test/src/android/car/apitest/VehicleAreaMirrorTest.java
index 7eb7eb8..6886faf 100644
--- a/tests/android_car_api_test/src/android/car/apitest/VehicleAreaMirrorTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/VehicleAreaMirrorTest.java
@@ -16,18 +16,22 @@
 package android.car.apitest;
 
 import android.car.VehicleAreaMirror;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
-@SmallTest
-public class VehicleAreaMirrorTest extends AndroidTestCase{
+import static com.google.common.truth.Truth.assertThat;
 
+import org.junit.Test;
+
+@SmallTest
+public class VehicleAreaMirrorTest {
+
+    @Test
     public void testMatchWithVehicleHal() {
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaMirror.DRIVER_CENTER,
-                VehicleAreaMirror.MIRROR_DRIVER_CENTER);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaMirror.DRIVER_LEFT,
-                VehicleAreaMirror.MIRROR_DRIVER_LEFT);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaMirror.DRIVER_RIGHT,
-                VehicleAreaMirror.MIRROR_DRIVER_RIGHT);
+        assertThat(VehicleAreaMirror.MIRROR_DRIVER_CENTER).isEqualTo(
+                android.hardware.automotive.vehicle.V2_0.VehicleAreaMirror.DRIVER_CENTER);
+        assertThat(VehicleAreaMirror.MIRROR_DRIVER_LEFT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaMirror.DRIVER_LEFT);
+        assertThat(VehicleAreaMirror.MIRROR_DRIVER_RIGHT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaMirror.DRIVER_RIGHT);
     }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/VehicleDoorTest.java b/tests/android_car_api_test/src/android/car/apitest/VehicleDoorTest.java
index d1b35c0..6c15929 100644
--- a/tests/android_car_api_test/src/android/car/apitest/VehicleDoorTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/VehicleDoorTest.java
@@ -16,28 +16,32 @@
 package android.car.apitest;
 
 import android.car.VehicleAreaDoor;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
-@SmallTest
-public class VehicleDoorTest extends AndroidTestCase {
+import static com.google.common.truth.Truth.assertThat;
 
+import org.junit.Test;
+
+@SmallTest
+public class VehicleDoorTest {
+
+    @Test
     public void testMatchWithVehicleHal() {
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaDoor.HOOD,
-                VehicleAreaDoor.DOOR_HOOD);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaDoor.REAR,
-                VehicleAreaDoor.DOOR_REAR);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaDoor.ROW_1_LEFT,
-                VehicleAreaDoor.DOOR_ROW_1_LEFT);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaDoor.ROW_1_RIGHT,
-                VehicleAreaDoor.DOOR_ROW_1_RIGHT);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaDoor.ROW_2_LEFT,
-                VehicleAreaDoor.DOOR_ROW_2_LEFT);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaDoor.ROW_2_RIGHT,
-                VehicleAreaDoor.DOOR_ROW_2_RIGHT);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaDoor.ROW_3_LEFT,
-                VehicleAreaDoor.DOOR_ROW_3_LEFT);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaDoor.ROW_3_RIGHT,
-                VehicleAreaDoor.DOOR_ROW_3_RIGHT);
+        assertThat(VehicleAreaDoor.DOOR_HOOD)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaDoor.HOOD);
+        assertThat(VehicleAreaDoor.DOOR_REAR)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaDoor.REAR);
+        assertThat(VehicleAreaDoor.DOOR_ROW_1_LEFT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaDoor.ROW_1_LEFT);
+        assertThat(VehicleAreaDoor.DOOR_ROW_1_RIGHT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaDoor.ROW_1_RIGHT);
+        assertThat(VehicleAreaDoor.DOOR_ROW_2_LEFT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaDoor.ROW_2_LEFT);
+        assertThat(VehicleAreaDoor.DOOR_ROW_2_RIGHT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaDoor.ROW_2_RIGHT);
+        assertThat(VehicleAreaDoor.DOOR_ROW_3_LEFT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaDoor.ROW_3_LEFT);
+        assertThat(VehicleAreaDoor.DOOR_ROW_3_RIGHT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaDoor.ROW_3_RIGHT);
     }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/VehicleGearTest.java b/tests/android_car_api_test/src/android/car/apitest/VehicleGearTest.java
new file mode 100644
index 0000000..44ca0cd
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/VehicleGearTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.apitest;
+
+import android.car.VehicleGear;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+
+@SmallTest
+public class VehicleGearTest {
+
+    @Test
+    public void testMatchWithVehicleHal() {
+        assertThat(VehicleGear.GEAR_UNKNOWN)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleGear.GEAR_UNKNOWN);
+
+        assertThat(VehicleGear.GEAR_NEUTRAL)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleGear.GEAR_NEUTRAL);
+
+        assertThat(VehicleGear.GEAR_REVERSE)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleGear.GEAR_REVERSE);
+
+        assertThat(VehicleGear.GEAR_PARK)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleGear.GEAR_PARK);
+
+        assertThat(VehicleGear.GEAR_DRIVE)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleGear.GEAR_DRIVE);
+
+        assertThat(VehicleGear.GEAR_FIRST)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleGear.GEAR_1);
+
+        assertThat(VehicleGear.GEAR_SECOND)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleGear.GEAR_2);
+
+        assertThat(VehicleGear.GEAR_THIRD)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleGear.GEAR_3);
+
+        assertThat(VehicleGear.GEAR_FOURTH)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleGear.GEAR_4);
+
+        assertThat(VehicleGear.GEAR_FIFTH)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleGear.GEAR_5);
+
+        assertThat(VehicleGear.GEAR_SIXTH)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleGear.GEAR_6);
+
+        assertThat(VehicleGear.GEAR_SEVENTH)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleGear.GEAR_7);
+
+        assertThat(VehicleGear.GEAR_EIGHTH)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleGear.GEAR_8);
+
+        assertThat(VehicleGear.GEAR_NINTH)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleGear.GEAR_9);
+    }
+
+    @Test
+    public void testToString() {
+        assertThat(VehicleGear.toString(VehicleGear.GEAR_UNKNOWN)).isEqualTo("GEAR_UNKNOWN");
+
+        assertThat(VehicleGear.toString(VehicleGear.GEAR_NEUTRAL)).isEqualTo("GEAR_NEUTRAL");
+
+        assertThat(VehicleGear.toString(VehicleGear.GEAR_REVERSE)).isEqualTo("GEAR_REVERSE");
+
+        assertThat(VehicleGear.toString(VehicleGear.GEAR_PARK)).isEqualTo("GEAR_PARK");
+
+        assertThat(VehicleGear.toString(VehicleGear.GEAR_DRIVE)).isEqualTo("GEAR_DRIVE");
+
+        assertThat(VehicleGear.toString(VehicleGear.GEAR_FIRST)).isEqualTo("GEAR_FIRST");
+
+        assertThat(VehicleGear.toString(VehicleGear.GEAR_SECOND)).isEqualTo("GEAR_SECOND");
+
+        assertThat(VehicleGear.toString(VehicleGear.GEAR_THIRD)).isEqualTo("GEAR_THIRD");
+
+        assertThat(VehicleGear.toString(VehicleGear.GEAR_FOURTH)).isEqualTo("GEAR_FOURTH");
+
+        assertThat(VehicleGear.toString(VehicleGear.GEAR_FIFTH)).isEqualTo("GEAR_FIFTH");
+
+        assertThat(VehicleGear.toString(VehicleGear.GEAR_SIXTH)).isEqualTo("GEAR_SIXTH");
+
+        assertThat(VehicleGear.toString(VehicleGear.GEAR_SEVENTH)).isEqualTo("GEAR_SEVENTH");
+
+        assertThat(VehicleGear.toString(VehicleGear.GEAR_EIGHTH)).isEqualTo("GEAR_EIGHTH");
+
+        assertThat(VehicleGear.toString(VehicleGear.GEAR_NINTH)).isEqualTo("GEAR_NINTH");
+
+        assertThat(VehicleGear.toString(3)).isEqualTo("0x3");
+
+        assertThat(VehicleGear.toString(12)).isEqualTo("0xc");
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/VehiclePropertyIdsTest.java b/tests/android_car_api_test/src/android/car/apitest/VehiclePropertyIdsTest.java
new file mode 100644
index 0000000..98451fb
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/VehiclePropertyIdsTest.java
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.apitest;
+
+import android.car.VehiclePropertyIds;
+import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VehiclePropertyIdsTest extends AndroidTestCase {
+    private static final List<String> MISSING_VEHICLE_PROPERTY_IDS =
+            new ArrayList<>(
+                Arrays.asList(
+                    "DISABLED_OPTIONAL_FEATURES",
+                    "HW_ROTARY_INPUT",
+                    "SUPPORT_CUSTOMIZE_VENDOR_PERMISSION"));
+    private static final List<Integer> MISSING_VEHICLE_PROPERTY_ID_VALUES =
+            new ArrayList<>(
+                Arrays.asList(
+                    /*DISABLED_OPTIONAL_FEATURES=*/286265094,
+                    /*HW_ROTARY_INPUT=*/289475104,
+                    /*SUPPORT_CUSTOMIZE_VENDOR_PERMISSION=*/287313669));
+
+
+    @Test
+    public void testMatchingVehiclePropertyNamesInVehicleHal() {
+        List<String> vehiclePropertyIdNames = getListOfConstantNames(VehiclePropertyIds.class);
+        List<String> vehiclePropertyNames = getListOfConstantNames(VehicleProperty.class);
+        assertEquals(vehiclePropertyNames.size(),
+                vehiclePropertyIdNames.size() + MISSING_VEHICLE_PROPERTY_IDS.size());
+        for (String vehiclePropertyName: vehiclePropertyNames) {
+            if (MISSING_VEHICLE_PROPERTY_IDS.contains(vehiclePropertyName)) {
+                continue;
+            }
+            assertTrue(vehiclePropertyIdNames.contains(vehiclePropertyName));
+        }
+    }
+
+    @Test
+    public void testMatchingVehiclePropertyValuesInVehicleHal() {
+        List<Integer> vehiclePropertyIds = getListOfConstantValues(VehiclePropertyIds.class);
+        List<Integer> vehicleProperties = getListOfConstantValues(VehicleProperty.class);
+        assertEquals(vehicleProperties.size(),
+                vehiclePropertyIds.size() + MISSING_VEHICLE_PROPERTY_ID_VALUES.size());
+        for (int vehicleProperty: vehicleProperties) {
+            if (MISSING_VEHICLE_PROPERTY_ID_VALUES.contains(vehicleProperty)) {
+                continue;
+            }
+            // TODO(b/151168399): VEHICLE_SPEED_DISPLAY_UNITS mismatch between java and hal.
+            if (vehicleProperty == VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS) {
+                continue;
+            }
+            assertTrue(vehiclePropertyIds.contains(vehicleProperty));
+        }
+    }
+
+    @Test
+    public void testToString() {
+        assertEquals("INVALID", VehiclePropertyIds.toString(VehiclePropertyIds.INVALID));
+        assertEquals("INFO_VIN", VehiclePropertyIds.toString(VehiclePropertyIds.INFO_VIN));
+        assertEquals("INFO_MAKE", VehiclePropertyIds.toString(VehiclePropertyIds.INFO_MAKE));
+        assertEquals("INFO_MODEL", VehiclePropertyIds.toString(VehiclePropertyIds.INFO_MODEL));
+        assertEquals("INFO_MODEL_YEAR",
+                VehiclePropertyIds.toString(VehiclePropertyIds.INFO_MODEL_YEAR));
+        assertEquals("INFO_FUEL_CAPACITY",
+                VehiclePropertyIds.toString(VehiclePropertyIds.INFO_FUEL_CAPACITY));
+        assertEquals("INFO_FUEL_TYPE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.INFO_FUEL_TYPE));
+        assertEquals("INFO_EV_BATTERY_CAPACITY",
+                VehiclePropertyIds.toString(VehiclePropertyIds.INFO_EV_BATTERY_CAPACITY));
+        assertEquals("INFO_MULTI_EV_PORT_LOCATIONS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.INFO_MULTI_EV_PORT_LOCATIONS));
+        assertEquals("INFO_EV_CONNECTOR_TYPE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.INFO_EV_CONNECTOR_TYPE));
+        assertEquals("INFO_FUEL_DOOR_LOCATION",
+                VehiclePropertyIds.toString(VehiclePropertyIds.INFO_FUEL_DOOR_LOCATION));
+        assertEquals("INFO_EV_PORT_LOCATION",
+                VehiclePropertyIds.toString(VehiclePropertyIds.INFO_EV_PORT_LOCATION));
+        assertEquals("INFO_DRIVER_SEAT",
+                VehiclePropertyIds.toString(VehiclePropertyIds.INFO_DRIVER_SEAT));
+        assertEquals("INFO_EXTERIOR_DIMENSIONS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.INFO_EXTERIOR_DIMENSIONS));
+        assertEquals("PERF_ODOMETER",
+                VehiclePropertyIds.toString(VehiclePropertyIds.PERF_ODOMETER));
+        assertEquals("PERF_VEHICLE_SPEED",
+                VehiclePropertyIds.toString(VehiclePropertyIds.PERF_VEHICLE_SPEED));
+        assertEquals("PERF_VEHICLE_SPEED_DISPLAY",
+                VehiclePropertyIds.toString(VehiclePropertyIds.PERF_VEHICLE_SPEED_DISPLAY));
+        assertEquals("PERF_STEERING_ANGLE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.PERF_STEERING_ANGLE));
+        assertEquals("PERF_REAR_STEERING_ANGLE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.PERF_REAR_STEERING_ANGLE));
+        assertEquals("ENGINE_COOLANT_TEMP",
+                VehiclePropertyIds.toString(VehiclePropertyIds.ENGINE_COOLANT_TEMP));
+        assertEquals("ENGINE_OIL_LEVEL",
+                VehiclePropertyIds.toString(VehiclePropertyIds.ENGINE_OIL_LEVEL));
+        assertEquals("ENGINE_OIL_TEMP",
+                VehiclePropertyIds.toString(VehiclePropertyIds.ENGINE_OIL_TEMP));
+        assertEquals("ENGINE_RPM", VehiclePropertyIds.toString(VehiclePropertyIds.ENGINE_RPM));
+        assertEquals("WHEEL_TICK", VehiclePropertyIds.toString(VehiclePropertyIds.WHEEL_TICK));
+        assertEquals("FUEL_LEVEL", VehiclePropertyIds.toString(VehiclePropertyIds.FUEL_LEVEL));
+        assertEquals("FUEL_DOOR_OPEN",
+                VehiclePropertyIds.toString(VehiclePropertyIds.FUEL_DOOR_OPEN));
+        assertEquals("EV_BATTERY_LEVEL",
+                VehiclePropertyIds.toString(VehiclePropertyIds.EV_BATTERY_LEVEL));
+        assertEquals("EV_CHARGE_PORT_OPEN",
+                VehiclePropertyIds.toString(VehiclePropertyIds.EV_CHARGE_PORT_OPEN));
+        assertEquals("EV_CHARGE_PORT_CONNECTED",
+                VehiclePropertyIds.toString(VehiclePropertyIds.EV_CHARGE_PORT_CONNECTED));
+        assertEquals("EV_BATTERY_INSTANTANEOUS_CHARGE_RATE",
+                VehiclePropertyIds.toString(
+                        VehiclePropertyIds.EV_BATTERY_INSTANTANEOUS_CHARGE_RATE));
+        assertEquals("RANGE_REMAINING",
+                VehiclePropertyIds.toString(VehiclePropertyIds.RANGE_REMAINING));
+        assertEquals("TIRE_PRESSURE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.TIRE_PRESSURE));
+        assertEquals("GEAR_SELECTION",
+                VehiclePropertyIds.toString(VehiclePropertyIds.GEAR_SELECTION));
+        assertEquals("CURRENT_GEAR", VehiclePropertyIds.toString(VehiclePropertyIds.CURRENT_GEAR));
+        assertEquals("PARKING_BRAKE_ON",
+                VehiclePropertyIds.toString(VehiclePropertyIds.PARKING_BRAKE_ON));
+        assertEquals("PARKING_BRAKE_AUTO_APPLY",
+                VehiclePropertyIds.toString(VehiclePropertyIds.PARKING_BRAKE_AUTO_APPLY));
+        assertEquals("FUEL_LEVEL_LOW",
+                VehiclePropertyIds.toString(VehiclePropertyIds.FUEL_LEVEL_LOW));
+        assertEquals("NIGHT_MODE", VehiclePropertyIds.toString(VehiclePropertyIds.NIGHT_MODE));
+        assertEquals("TURN_SIGNAL_STATE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.TURN_SIGNAL_STATE));
+        assertEquals("IGNITION_STATE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.IGNITION_STATE));
+        assertEquals("ABS_ACTIVE", VehiclePropertyIds.toString(VehiclePropertyIds.ABS_ACTIVE));
+        assertEquals("TRACTION_CONTROL_ACTIVE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.TRACTION_CONTROL_ACTIVE));
+        assertEquals("HVAC_FAN_SPEED",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_FAN_SPEED));
+        assertEquals("HVAC_FAN_DIRECTION",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_FAN_DIRECTION));
+        assertEquals("HVAC_TEMPERATURE_CURRENT",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_TEMPERATURE_CURRENT));
+        assertEquals("HVAC_TEMPERATURE_SET",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_TEMPERATURE_SET));
+        assertEquals("HVAC_DEFROSTER",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_DEFROSTER));
+        assertEquals("HVAC_AC_ON", VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_AC_ON));
+        assertEquals("HVAC_MAX_AC_ON",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_MAX_AC_ON));
+        assertEquals("HVAC_MAX_DEFROST_ON",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_MAX_DEFROST_ON));
+        assertEquals("HVAC_RECIRC_ON",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_RECIRC_ON));
+        assertEquals("HVAC_DUAL_ON", VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_DUAL_ON));
+        assertEquals("HVAC_AUTO_ON", VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_AUTO_ON));
+        assertEquals("HVAC_SEAT_TEMPERATURE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_SEAT_TEMPERATURE));
+        assertEquals("HVAC_SIDE_MIRROR_HEAT",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_SIDE_MIRROR_HEAT));
+        assertEquals("HVAC_STEERING_WHEEL_HEAT",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_STEERING_WHEEL_HEAT));
+        assertEquals("HVAC_TEMPERATURE_DISPLAY_UNITS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS));
+        assertEquals("HVAC_ACTUAL_FAN_SPEED_RPM",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_ACTUAL_FAN_SPEED_RPM));
+        assertEquals("HVAC_POWER_ON",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_POWER_ON));
+        assertEquals("HVAC_FAN_DIRECTION_AVAILABLE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_FAN_DIRECTION_AVAILABLE));
+        assertEquals("HVAC_AUTO_RECIRC_ON",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_AUTO_RECIRC_ON));
+        assertEquals("HVAC_SEAT_VENTILATION",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_SEAT_VENTILATION));
+        assertEquals("HVAC_ELECTRIC_DEFROSTER_ON",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_ELECTRIC_DEFROSTER_ON));
+        assertEquals("DISTANCE_DISPLAY_UNITS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.DISTANCE_DISPLAY_UNITS));
+        assertEquals("FUEL_VOLUME_DISPLAY_UNITS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.FUEL_VOLUME_DISPLAY_UNITS));
+        assertEquals("TIRE_PRESSURE_DISPLAY_UNITS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.TIRE_PRESSURE_DISPLAY_UNITS));
+        assertEquals("EV_BATTERY_DISPLAY_UNITS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.EV_BATTERY_DISPLAY_UNITS));
+        assertEquals("FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME",
+                VehiclePropertyIds.toString(
+                        VehiclePropertyIds.FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME));
+        assertEquals("ENV_OUTSIDE_TEMPERATURE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.ENV_OUTSIDE_TEMPERATURE));
+        assertEquals("AP_POWER_STATE_REQ",
+                VehiclePropertyIds.toString(VehiclePropertyIds.AP_POWER_STATE_REQ));
+        assertEquals("AP_POWER_STATE_REPORT",
+                VehiclePropertyIds.toString(VehiclePropertyIds.AP_POWER_STATE_REPORT));
+        assertEquals("AP_POWER_BOOTUP_REASON",
+                VehiclePropertyIds.toString(VehiclePropertyIds.AP_POWER_BOOTUP_REASON));
+        assertEquals("DISPLAY_BRIGHTNESS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.DISPLAY_BRIGHTNESS));
+        assertEquals("HW_KEY_INPUT", VehiclePropertyIds.toString(VehiclePropertyIds.HW_KEY_INPUT));
+        assertEquals("DOOR_POS", VehiclePropertyIds.toString(VehiclePropertyIds.DOOR_POS));
+        assertEquals("DOOR_MOVE", VehiclePropertyIds.toString(VehiclePropertyIds.DOOR_MOVE));
+        assertEquals("DOOR_LOCK", VehiclePropertyIds.toString(VehiclePropertyIds.DOOR_LOCK));
+        assertEquals("MIRROR_Z_POS", VehiclePropertyIds.toString(VehiclePropertyIds.MIRROR_Z_POS));
+        assertEquals("MIRROR_Z_MOVE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.MIRROR_Z_MOVE));
+        assertEquals("MIRROR_Y_POS", VehiclePropertyIds.toString(VehiclePropertyIds.MIRROR_Y_POS));
+        assertEquals("MIRROR_Y_MOVE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.MIRROR_Y_MOVE));
+        assertEquals("MIRROR_LOCK", VehiclePropertyIds.toString(VehiclePropertyIds.MIRROR_LOCK));
+        assertEquals("MIRROR_FOLD", VehiclePropertyIds.toString(VehiclePropertyIds.MIRROR_FOLD));
+        assertEquals("SEAT_MEMORY_SELECT",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_MEMORY_SELECT));
+        assertEquals("SEAT_MEMORY_SET",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_MEMORY_SET));
+        assertEquals("SEAT_BELT_BUCKLED",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_BELT_BUCKLED));
+        assertEquals("SEAT_BELT_HEIGHT_POS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_BELT_HEIGHT_POS));
+        assertEquals("SEAT_BELT_HEIGHT_MOVE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_BELT_HEIGHT_MOVE));
+        assertEquals("SEAT_FORE_AFT_POS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_FORE_AFT_POS));
+        assertEquals("SEAT_FORE_AFT_MOVE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_FORE_AFT_MOVE));
+        assertEquals("SEAT_BACKREST_ANGLE_1_POS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_BACKREST_ANGLE_1_POS));
+        assertEquals("SEAT_BACKREST_ANGLE_1_MOVE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_BACKREST_ANGLE_1_MOVE));
+        assertEquals("SEAT_BACKREST_ANGLE_2_POS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_BACKREST_ANGLE_2_POS));
+        assertEquals("SEAT_BACKREST_ANGLE_2_MOVE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_BACKREST_ANGLE_2_MOVE));
+        assertEquals("SEAT_HEIGHT_POS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_HEIGHT_POS));
+        assertEquals("SEAT_HEIGHT_MOVE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_HEIGHT_MOVE));
+        assertEquals("SEAT_DEPTH_POS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_DEPTH_POS));
+        assertEquals("SEAT_DEPTH_MOVE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_DEPTH_MOVE));
+        assertEquals("SEAT_TILT_POS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_TILT_POS));
+        assertEquals("SEAT_TILT_MOVE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_TILT_MOVE));
+        assertEquals("SEAT_LUMBAR_FORE_AFT_POS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_LUMBAR_FORE_AFT_POS));
+        assertEquals("SEAT_LUMBAR_FORE_AFT_MOVE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_LUMBAR_FORE_AFT_MOVE));
+        assertEquals("SEAT_LUMBAR_SIDE_SUPPORT_POS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_LUMBAR_SIDE_SUPPORT_POS));
+        assertEquals("SEAT_LUMBAR_SIDE_SUPPORT_MOVE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_LUMBAR_SIDE_SUPPORT_MOVE));
+        assertEquals("SEAT_HEADREST_HEIGHT_POS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_HEADREST_HEIGHT_POS));
+        assertEquals("SEAT_HEADREST_HEIGHT_MOVE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_HEADREST_HEIGHT_MOVE));
+        assertEquals("SEAT_HEADREST_ANGLE_POS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_HEADREST_ANGLE_POS));
+        assertEquals("SEAT_HEADREST_ANGLE_MOVE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_HEADREST_ANGLE_MOVE));
+        assertEquals("SEAT_HEADREST_FORE_AFT_POS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_HEADREST_FORE_AFT_POS));
+        assertEquals("SEAT_HEADREST_FORE_AFT_MOVE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_HEADREST_FORE_AFT_MOVE));
+        assertEquals("SEAT_OCCUPANCY",
+                VehiclePropertyIds.toString(VehiclePropertyIds.SEAT_OCCUPANCY));
+        assertEquals("WINDOW_POS", VehiclePropertyIds.toString(VehiclePropertyIds.WINDOW_POS));
+        assertEquals("WINDOW_MOVE", VehiclePropertyIds.toString(VehiclePropertyIds.WINDOW_MOVE));
+        assertEquals("WINDOW_LOCK", VehiclePropertyIds.toString(VehiclePropertyIds.WINDOW_LOCK));
+        assertEquals("VEHICLE_MAP_SERVICE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.VEHICLE_MAP_SERVICE));
+        assertEquals("OBD2_LIVE_FRAME",
+                VehiclePropertyIds.toString(VehiclePropertyIds.OBD2_LIVE_FRAME));
+        assertEquals("OBD2_FREEZE_FRAME",
+                VehiclePropertyIds.toString(VehiclePropertyIds.OBD2_FREEZE_FRAME));
+        assertEquals("OBD2_FREEZE_FRAME_INFO",
+                VehiclePropertyIds.toString(VehiclePropertyIds.OBD2_FREEZE_FRAME_INFO));
+        assertEquals("OBD2_FREEZE_FRAME_CLEAR",
+                VehiclePropertyIds.toString(VehiclePropertyIds.OBD2_FREEZE_FRAME_CLEAR));
+        assertEquals("HEADLIGHTS_STATE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HEADLIGHTS_STATE));
+        assertEquals("HIGH_BEAM_LIGHTS_STATE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HIGH_BEAM_LIGHTS_STATE));
+        assertEquals("FOG_LIGHTS_STATE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.FOG_LIGHTS_STATE));
+        assertEquals("HAZARD_LIGHTS_STATE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HAZARD_LIGHTS_STATE));
+        assertEquals("HEADLIGHTS_SWITCH",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HEADLIGHTS_SWITCH));
+        assertEquals("HIGH_BEAM_LIGHTS_SWITCH",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HIGH_BEAM_LIGHTS_SWITCH));
+        assertEquals("FOG_LIGHTS_SWITCH",
+                VehiclePropertyIds.toString(VehiclePropertyIds.FOG_LIGHTS_SWITCH));
+        assertEquals("HAZARD_LIGHTS_SWITCH",
+                VehiclePropertyIds.toString(VehiclePropertyIds.HAZARD_LIGHTS_SWITCH));
+        assertEquals("CABIN_LIGHTS_STATE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.CABIN_LIGHTS_STATE));
+        assertEquals("CABIN_LIGHTS_SWITCH",
+                VehiclePropertyIds.toString(VehiclePropertyIds.CABIN_LIGHTS_SWITCH));
+        assertEquals("READING_LIGHTS_STATE",
+                VehiclePropertyIds.toString(VehiclePropertyIds.READING_LIGHTS_STATE));
+        assertEquals("READING_LIGHTS_SWITCH",
+                VehiclePropertyIds.toString(VehiclePropertyIds.READING_LIGHTS_SWITCH));
+        assertEquals("VEHICLE_SPEED_DISPLAY_UNITS",
+                VehiclePropertyIds.toString(VehiclePropertyIds.VEHICLE_SPEED_DISPLAY_UNITS));
+        assertEquals("INITIAL_USER_INFO",
+                VehiclePropertyIds.toString(VehiclePropertyIds.INITIAL_USER_INFO));
+        assertEquals("SWITCH_USER", VehiclePropertyIds.toString(VehiclePropertyIds.SWITCH_USER));
+        assertEquals("USER_IDENTIFICATION_ASSOCIATION",
+                VehiclePropertyIds.toString(VehiclePropertyIds.USER_IDENTIFICATION_ASSOCIATION));
+        assertEquals("0x3", VehiclePropertyIds.toString(3));
+    }
+
+    private static List<Integer> getListOfConstantValues(Class clazz) {
+        List<Integer> list = new ArrayList<Integer>();
+        for (Field field : clazz.getDeclaredFields()) {
+            int modifiers = field.getModifiers();
+            if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) {
+                try {
+                    list.add(field.getInt(null));
+                } catch (IllegalAccessException e) {
+                }
+            }
+        }
+        return list;
+    }
+
+    private static List<String> getListOfConstantNames(Class clazz) {
+        List<String> list = new ArrayList<String>();
+        for (Field field : clazz.getDeclaredFields()) {
+            int modifiers = field.getModifiers();
+            if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) {
+                list.add(field.getName());
+            }
+        }
+        return list;
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/VehicleSeatTest.java b/tests/android_car_api_test/src/android/car/apitest/VehicleSeatTest.java
index 841c66e..6ed1197 100644
--- a/tests/android_car_api_test/src/android/car/apitest/VehicleSeatTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/VehicleSeatTest.java
@@ -16,30 +16,79 @@
 package android.car.apitest;
 
 import android.car.VehicleAreaSeat;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
-@SmallTest
-public class VehicleSeatTest extends AndroidTestCase {
+import static com.google.common.truth.Truth.assertThat;
 
+import org.junit.Test;
+
+@SmallTest
+public class VehicleSeatTest {
+
+    @Test
     public void testMatchWithVehicleHal() {
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat.ROW_1_LEFT,
-                VehicleAreaSeat.SEAT_ROW_1_LEFT);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat.ROW_1_CENTER,
-                VehicleAreaSeat.SEAT_ROW_1_CENTER);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat.ROW_1_RIGHT,
-                VehicleAreaSeat.SEAT_ROW_1_RIGHT);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat.ROW_2_LEFT,
-                VehicleAreaSeat.SEAT_ROW_2_LEFT);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat.ROW_2_CENTER,
-                VehicleAreaSeat.SEAT_ROW_2_CENTER);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat.ROW_2_RIGHT,
-                VehicleAreaSeat.SEAT_ROW_2_RIGHT);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat.ROW_3_LEFT,
-                VehicleAreaSeat.SEAT_ROW_3_LEFT);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat.ROW_3_CENTER,
-                VehicleAreaSeat.SEAT_ROW_3_CENTER);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat.ROW_3_RIGHT,
-                VehicleAreaSeat.SEAT_ROW_3_RIGHT);
+        assertThat(VehicleAreaSeat.SEAT_ROW_1_LEFT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat.ROW_1_LEFT);
+        assertThat(VehicleAreaSeat.SEAT_ROW_1_CENTER)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat.ROW_1_CENTER);
+        assertThat(VehicleAreaSeat.SEAT_ROW_1_RIGHT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat.ROW_1_RIGHT);
+        assertThat(VehicleAreaSeat.SEAT_ROW_2_LEFT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat.ROW_2_LEFT);
+        assertThat(VehicleAreaSeat.SEAT_ROW_2_CENTER)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat.ROW_2_CENTER);
+        assertThat(VehicleAreaSeat.SEAT_ROW_2_RIGHT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat.ROW_2_RIGHT);
+        assertThat(VehicleAreaSeat.SEAT_ROW_3_LEFT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat.ROW_3_LEFT);
+        assertThat(VehicleAreaSeat.SEAT_ROW_3_CENTER)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat.ROW_3_CENTER);
+        assertThat(VehicleAreaSeat.SEAT_ROW_3_RIGHT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat.ROW_3_RIGHT);
+    }
+
+    @Test
+    public void testFromRowAndSide() {
+        assertThat(VehicleAreaSeat.SEAT_UNKNOWN)
+                .isEqualTo(VehicleAreaSeat.fromRowAndSide(-1, VehicleAreaSeat.SIDE_LEFT));
+        assertThat(VehicleAreaSeat.SEAT_UNKNOWN)
+                .isEqualTo(VehicleAreaSeat.fromRowAndSide(-1, VehicleAreaSeat.SIDE_CENTER));
+        assertThat(VehicleAreaSeat.SEAT_UNKNOWN)
+                .isEqualTo(VehicleAreaSeat.fromRowAndSide(-1, VehicleAreaSeat.SIDE_RIGHT));
+
+        assertThat(VehicleAreaSeat.SEAT_UNKNOWN)
+                .isEqualTo(VehicleAreaSeat.fromRowAndSide(0, VehicleAreaSeat.SIDE_LEFT));
+        assertThat(VehicleAreaSeat.SEAT_UNKNOWN)
+                .isEqualTo(VehicleAreaSeat.fromRowAndSide(0, VehicleAreaSeat.SIDE_CENTER));
+        assertThat(VehicleAreaSeat.SEAT_UNKNOWN)
+                .isEqualTo(VehicleAreaSeat.fromRowAndSide(0, VehicleAreaSeat.SIDE_RIGHT));
+
+        assertThat(VehicleAreaSeat.SEAT_ROW_1_LEFT)
+                .isEqualTo(VehicleAreaSeat.fromRowAndSide(1, VehicleAreaSeat.SIDE_LEFT));
+        assertThat(VehicleAreaSeat.SEAT_ROW_1_CENTER)
+                .isEqualTo(VehicleAreaSeat.fromRowAndSide(1, VehicleAreaSeat.SIDE_CENTER));
+        assertThat(VehicleAreaSeat.SEAT_ROW_1_RIGHT)
+                .isEqualTo(VehicleAreaSeat.fromRowAndSide(1, VehicleAreaSeat.SIDE_RIGHT));
+
+        assertThat(VehicleAreaSeat.SEAT_ROW_2_LEFT)
+                .isEqualTo(VehicleAreaSeat.fromRowAndSide(2, VehicleAreaSeat.SIDE_LEFT));
+        assertThat(VehicleAreaSeat.SEAT_ROW_2_CENTER)
+                .isEqualTo(VehicleAreaSeat.fromRowAndSide(2, VehicleAreaSeat.SIDE_CENTER));
+        assertThat(VehicleAreaSeat.SEAT_ROW_2_RIGHT)
+                .isEqualTo(VehicleAreaSeat.fromRowAndSide(2, VehicleAreaSeat.SIDE_RIGHT));
+
+        assertThat(VehicleAreaSeat.SEAT_ROW_3_LEFT)
+                .isEqualTo(VehicleAreaSeat.fromRowAndSide(3, VehicleAreaSeat.SIDE_LEFT));
+        assertThat(VehicleAreaSeat.SEAT_ROW_3_CENTER)
+                .isEqualTo(VehicleAreaSeat.fromRowAndSide(3, VehicleAreaSeat.SIDE_CENTER));
+        assertThat(VehicleAreaSeat.SEAT_ROW_3_RIGHT)
+                .isEqualTo(VehicleAreaSeat.fromRowAndSide(3, VehicleAreaSeat.SIDE_RIGHT));
+
+        assertThat(VehicleAreaSeat.SEAT_UNKNOWN)
+                .isEqualTo(VehicleAreaSeat.fromRowAndSide(4, VehicleAreaSeat.SIDE_LEFT));
+        assertThat(VehicleAreaSeat.SEAT_UNKNOWN)
+                .isEqualTo(VehicleAreaSeat.fromRowAndSide(4, VehicleAreaSeat.SIDE_CENTER));
+        assertThat(VehicleAreaSeat.SEAT_UNKNOWN)
+                .isEqualTo(VehicleAreaSeat.fromRowAndSide(4, VehicleAreaSeat.SIDE_RIGHT));
     }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/VehicleWindowTest.java b/tests/android_car_api_test/src/android/car/apitest/VehicleWindowTest.java
index 331d3ef..a0eb9d8 100644
--- a/tests/android_car_api_test/src/android/car/apitest/VehicleWindowTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/VehicleWindowTest.java
@@ -16,32 +16,36 @@
 package android.car.apitest;
 
 import android.car.VehicleAreaWindow;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
-@SmallTest
-public class VehicleWindowTest extends AndroidTestCase {
+import static com.google.common.truth.Truth.assertThat;
 
+import org.junit.Test;
+
+@SmallTest
+public class VehicleWindowTest {
+
+    @Test
     public void testMatchWithVehicleHal() {
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow.FRONT_WINDSHIELD,
-                VehicleAreaWindow.WINDOW_FRONT_WINDSHIELD);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow.REAR_WINDSHIELD,
-                VehicleAreaWindow.WINDOW_REAR_WINDSHIELD);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow.ROW_1_LEFT,
-                VehicleAreaWindow.WINDOW_ROW_1_LEFT);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow.ROW_1_RIGHT,
-                VehicleAreaWindow.WINDOW_ROW_1_RIGHT);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow.ROW_2_LEFT,
-                VehicleAreaWindow.WINDOW_ROW_2_LEFT);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow.ROW_2_RIGHT,
-                VehicleAreaWindow.WINDOW_ROW_2_RIGHT);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow.ROW_3_LEFT,
-                VehicleAreaWindow.WINDOW_ROW_3_LEFT);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow.ROW_3_RIGHT,
-                VehicleAreaWindow.WINDOW_ROW_3_RIGHT);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow.ROOF_TOP_1,
-                VehicleAreaWindow.WINDOW_ROOF_TOP_1);
-        assertEquals(android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow.ROOF_TOP_2,
-                VehicleAreaWindow.WINDOW_ROOF_TOP_2);
+        assertThat(VehicleAreaWindow.WINDOW_FRONT_WINDSHIELD).isEqualTo(
+                android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow.FRONT_WINDSHIELD);
+        assertThat(VehicleAreaWindow.WINDOW_REAR_WINDSHIELD).isEqualTo(
+                android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow.REAR_WINDSHIELD);
+        assertThat(VehicleAreaWindow.WINDOW_ROW_1_LEFT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow.ROW_1_LEFT);
+        assertThat(VehicleAreaWindow.WINDOW_ROW_1_RIGHT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow.ROW_1_RIGHT);
+        assertThat(VehicleAreaWindow.WINDOW_ROW_2_LEFT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow.ROW_2_LEFT);
+        assertThat(VehicleAreaWindow.WINDOW_ROW_2_RIGHT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow.ROW_2_RIGHT);
+        assertThat(VehicleAreaWindow.WINDOW_ROW_3_LEFT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow.ROW_3_LEFT);
+        assertThat(VehicleAreaWindow.WINDOW_ROW_3_RIGHT)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow.ROW_3_RIGHT);
+        assertThat(VehicleAreaWindow.WINDOW_ROOF_TOP_1)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow.ROOF_TOP_1);
+        assertThat(VehicleAreaWindow.WINDOW_ROOF_TOP_2)
+                .isEqualTo(android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow.ROOF_TOP_2);
     }
 }
diff --git a/tests/carservice_test/Android.mk b/tests/carservice_test/Android.mk
index 63f1a4e..b764df7 100644
--- a/tests/carservice_test/Android.mk
+++ b/tests/carservice_test/Android.mk
@@ -39,25 +39,34 @@
 LOCAL_PROGUARD_ENABLED := disabled
 
 LOCAL_STATIC_JAVA_LIBRARIES := junit
+# testng imported to use assertThrows, we can remove it once it's ported to JUnit's.
 LOCAL_STATIC_JAVA_LIBRARIES += \
+    android.car.test.utils \
     androidx.test.ext.junit \
     androidx.test.rules \
     android.hardware.automotive.vehicle-V2.0-java \
     car-frameworks-service \
-    car-service-lib-for-test \
+    car-service-test-static-lib \
     car-systemtest \
     com.android.car.test.utils \
     mockito-target-extended \
+    testng \
     truth-prebuilt \
-    vehicle-hal-support-lib
-
+    vehicle-hal-support-lib-for-test \
+    compatibility-device-util-axt
 
 LOCAL_JAVA_LIBRARIES := \
     android.car \
     android.car.userlib \
+    android.car.watchdoglib \
     android.test.runner \
     android.test.base
 
-LOCAL_JNI_SHARED_LIBRARIES := libdexmakerjvmtiagent
+# mockito-target-inline dependency
+LOCAL_JNI_SHARED_LIBRARIES := \
+    libdexmakerjvmtiagent \
+    libstaticjvmtiagent
+
+LOCAL_COMPATIBILITY_SUITE := general-tests
 
 include $(BUILD_PACKAGE)
diff --git a/tests/carservice_test/AndroidManifest.xml b/tests/carservice_test/AndroidManifest.xml
index 297754d..1b3acc0 100644
--- a/tests/carservice_test/AndroidManifest.xml
+++ b/tests/carservice_test/AndroidManifest.xml
@@ -15,7 +15,8 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.car.test" android:sharedUserId="android.uid.system">
+        package="com.android.car.test"
+        android:sharedUserId="com.google.android.car.uid.kitchensink">
 
     <uses-permission android:name="android.Manifest.permission.MODIFY_AUDIO_ROUTING" />
     <uses-permission android:name="android.car.permission.CONTROL_CAR_CLIMATE" />
@@ -28,6 +29,7 @@
     <uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME" />
     <uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_SETTINGS" />
     <uses-permission android:name="android.car.permission.STORAGE_MONITORING" />
+    <uses-permission android:name="android.car.permission.READ_CAR_OCCUPANT_AWARENESS_STATE" />
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
             android:targetPackage="com.android.car.test"
@@ -42,25 +44,15 @@
                 <action android:name="android.car.content.pm.CarAppBlockingPolicyService"/>
             </intent-filter>
         </service>
-        <service android:name="com.android.car.MockedVmsTestBase$MockPublisherClient"
-             android:exported="true"
-             android:permission="android.car.permission.BIND_VMS_CLIENT"/>
 
-        <service android:name="com.android.car.VmsPublisherClientPermissionTest$PublisherClientExpectedPermission"
-                 android:exported="true"
-                 android:permission="android.car.permission.BIND_VMS_CLIENT"/>
-        <service android:name="com.android.car.VmsPublisherClientPermissionTest$PublisherClientWrongPermission"
-                 android:exported="true"
-                 android:permission="android.car.permission.VMS_PUBLISHER"/>
-        <service android:name="com.android.car.VmsPublisherClientPermissionTest$PublisherClientMissingPermission"
-                 android:exported="true"/>
-
-        <activity android:name="com.android.car.SystemActivityMonitoringServiceTest$ActivityA"/>
-        <activity android:name="com.android.car.SystemActivityMonitoringServiceTest$ActivityB"/>
-        <activity android:name="com.android.car.SystemActivityMonitoringServiceTest$ActivityC"/>
-        <activity android:name="com.android.car.SystemActivityMonitoringServiceTest$ActivityThatFinishesImmediately"/>
-        <activity android:name="com.android.car.SystemActivityMonitoringServiceTest$BlockingActivity"
-                  android:taskAffinity="com.android.car.carservicetest.block"/>
+        <activity android:name="com.android.car.CarUxRestrictionsManagerServiceTest$ActivityViewTestActivity"/>
+        <activity android:name="com.android.car.pm.ActivityBlockingActivityTest$NonDoNoHistoryActivity"
+                  android:noHistory="true"/>
+        <activity android:name="com.android.car.pm.ActivityBlockingActivityTest$NonDoActivity"/>
+        <activity android:name="com.android.car.pm.ActivityBlockingActivityTest$DoActivity"
+            android:label="DoActivity">
+            <meta-data android:name="distractionOptimized" android:value="true"/>
+        </activity>
 
         <receiver android:name="com.android.car.CarStorageMonitoringBroadcastReceiver"
             android:exported="true"
diff --git a/tests/carservice_test/res/raw/car_audio_configuration.xml b/tests/carservice_test/res/raw/car_audio_configuration.xml
index 4ae5217..e1d75df 100644
--- a/tests/carservice_test/res/raw/car_audio_configuration.xml
+++ b/tests/carservice_test/res/raw/car_audio_configuration.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
-<carAudioConfiguration version="1">
+<carAudioConfiguration version="2">
     <zones>
-        <zone name="primary zone" isPrimary="true">
+        <zone name="primary zone" isPrimary="true" audioZoneId="0" occupantZoneId="1">
             <volumeGroups>
                 <group>
                     <device address="bus0_media_out">
@@ -14,15 +14,15 @@
                 <group>
                     <device address="bus1_navigation_out">
                         <context context="navigation"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
                     </device>
                 </group>
             </volumeGroups>
-            <displays>
-                <display port="1"/>
-                <display port="2"/>
-            </displays>
         </zone>
-        <zone name="rear seat zone">
+        <zone name="rear seat zone" audioZoneId="2">
             <volumeGroups>
                 <group>
                     <device address="bus100_rear_seat">
@@ -32,8 +32,12 @@
                         <context context="call_ring"/>
                         <context context="call"/>
                         <context context="alarm"/>
-                        <context context="notification"/>
                         <context context="system_sound"/>
+                        <context context="notification"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
                     </device>
                 </group>
             </volumeGroups>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_V1.xml b/tests/carservice_test/res/raw/car_audio_configuration_V1.xml
new file mode 100644
index 0000000..26b1c08
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_V1.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<carAudioConfiguration version="1">
+    <zones>
+        <zone name="primary zone" isPrimary="true">
+            <volumeGroups>
+                <group>
+                    <device address="bus0_media_out">
+                        <context context="music"/>
+                    </device>
+                    <device address="bus3_call_ring_out">
+                        <context context="call_ring"/>
+                    </device>
+                </group>
+                <group>
+                    <device address="bus1_navigation_out">
+                        <context context="navigation"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+        <zone name="rear seat zone">
+            <volumeGroups>
+                <group>
+                    <device address="bus100_rear_seat">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_V1_with_audio_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_V1_with_audio_zone_id.xml
new file mode 100644
index 0000000..5793ab7
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_V1_with_audio_zone_id.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<carAudioConfiguration version="1">
+    <zones>
+        <zone name="primary zone" isPrimary="true" audioZoneId="0">
+            <volumeGroups>
+                <group>
+                    <device address="bus0_media_out">
+                        <context context="music"/>
+                    </device>
+                    <device address="bus3_call_ring_out">
+                        <context context="call_ring"/>
+                    </device>
+                </group>
+                <group>
+                    <device address="bus1_navigation_out">
+                        <context context="navigation"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+        <zone name="rear seat zone">
+            <volumeGroups>
+                <group>
+                    <device address="bus100_rear_seat">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_V1_with_non_legacy_contexts.xml b/tests/carservice_test/res/raw/car_audio_configuration_V1_with_non_legacy_contexts.xml
new file mode 100644
index 0000000..5c39ceb
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_V1_with_non_legacy_contexts.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<carAudioConfiguration version="1">
+    <zones>
+        <zone name="primary zone" isPrimary="true">
+            <volumeGroups>
+                <group>
+                    <device address="bus0_media_out">
+                        <context context="music"/>
+                    </device>
+                    <device address="bus3_call_ring_out">
+                        <context context="call_ring"/>
+                    </device>
+                </group>
+                <group>
+                    <device address="bus1_navigation_out">
+                        <context context="navigation"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+        <zone name="rear seat zone">
+            <volumeGroups>
+                <group>
+                    <device address="bus100_rear_seat">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                        <!-- Non-legacy context in a V1 configuration -->
+                        <context context="emergency"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_V1_with_occupant_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_V1_with_occupant_zone_id.xml
new file mode 100644
index 0000000..564a13c
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_V1_with_occupant_zone_id.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<carAudioConfiguration version="1">
+    <zones>
+        <zone name="primary zone" isPrimary="true" occupantZoneId="1">
+            <volumeGroups>
+                <group>
+                    <device address="bus0_media_out">
+                        <context context="music"/>
+                    </device>
+                    <device address="bus3_call_ring_out">
+                        <context context="call_ring"/>
+                    </device>
+                </group>
+                <group>
+                    <device address="bus1_navigation_out">
+                        <context context="navigation"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+        <zone name="rear seat zone">
+            <volumeGroups>
+                <group>
+                    <device address="bus100_rear_seat">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_duplicate_audio_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_duplicate_audio_zone_id.xml
new file mode 100644
index 0000000..8561968
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_duplicate_audio_zone_id.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<carAudioConfiguration version="2">
+    <zones>
+        <zone name="primary zone" isPrimary="true" audioZoneId="0" occupantZoneId="1">
+            <volumeGroups>
+                <group>
+                    <device address="bus0_media_out">
+                        <context context="music"/>
+                    </device>
+                    <device address="bus3_call_ring_out">
+                        <context context="call_ring"/>
+                    </device>
+                </group>
+                <group>
+                    <device address="bus1_navigation_out">
+                        <context context="navigation"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+        <zone name="rear seat zone" audioZoneId="1" occupantZoneId="2">
+            <volumeGroups>
+                <group>
+                    <device address="bus100_rear_seat">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+        <zone name="rear seat zone 2" audioZoneId="1" occupantZoneId="3">
+            <volumeGroups>
+                <group>
+                    <device address="bus200_rear_seat">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_duplicate_occupant_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_duplicate_occupant_zone_id.xml
new file mode 100644
index 0000000..8c1d0e8
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_duplicate_occupant_zone_id.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<carAudioConfiguration version="2">
+    <zones>
+        <zone name="primary zone" isPrimary="true" audioZoneId="0" occupantZoneId="1">
+            <volumeGroups>
+                <group>
+                    <device address="bus0_media_out">
+                        <context context="music"/>
+                    </device>
+                    <device address="bus3_call_ring_out">
+                        <context context="call_ring"/>
+                    </device>
+                </group>
+                <group>
+                    <device address="bus1_navigation_out">
+                        <context context="navigation"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+        <zone name="rear seat zone" audioZoneId="2" occupantZoneId="1">
+            <volumeGroups>
+                <group>
+                    <device address="bus100_rear_seat">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_duplicate_ports.xml b/tests/carservice_test/res/raw/car_audio_configuration_duplicate_ports.xml
index 288e8fb..dba13a2 100644
--- a/tests/carservice_test/res/raw/car_audio_configuration_duplicate_ports.xml
+++ b/tests/carservice_test/res/raw/car_audio_configuration_duplicate_ports.xml
@@ -17,10 +17,6 @@
                     </device>
                 </group>
             </volumeGroups>
-            <displays>
-                <display port="1"/>
-                <display port="1"/>
-            </displays>
         </zone>
     </zones>
 </carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_empty_input_device.xml b/tests/carservice_test/res/raw/car_audio_configuration_empty_input_device.xml
new file mode 100644
index 0000000..9a7b2d6
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_empty_input_device.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<carAudioConfiguration version="2">
+    <zones>
+        <zone name="primary zone" isPrimary="true" audioZoneId="0">
+            <volumeGroups>
+                <group>
+                    <device address="bus0_media_out">
+                        <context context="music"/>
+                    </device>
+                    <device address="bus3_call_ring_out">
+                        <context context="call_ring"/>
+                    </device>
+                </group>
+                <group>
+                    <device address="bus1_navigation_out">
+                        <context context="navigation"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+            <inputDevices>
+                <inputDevice address=""/>
+                <inputDevice address="Built-In Mic"/>
+            </inputDevices>
+        </zone>
+        <zone name="rear seat zone" audioZoneId="1">
+            <volumeGroups>
+                <group>
+                    <device address="bus100_rear_seat">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+            <inputDevices>
+                <inputDevice address="bus_1000_input"/>
+                <inputDevice address="Built-In Back Mic"/>
+            </inputDevices>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_empty_occupant_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_empty_occupant_zone_id.xml
new file mode 100644
index 0000000..972da37
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_empty_occupant_zone_id.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<carAudioConfiguration version="2">
+    <zones>
+        <zone name="primary zone" isPrimary="true" audioZoneId="0" occupantZoneId="">
+            <volumeGroups>
+                <group>
+                    <device address="bus0_media_out">
+                        <context context="music"/>
+                    </device>
+                    <device address="bus3_call_ring_out">
+                        <context context="call_ring"/>
+                    </device>
+                </group>
+                <group>
+                    <device address="bus1_navigation_out">
+                        <context context="navigation"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+        <zone name="rear seat zone" audioZoneId="2">
+            <volumeGroups>
+                <group>
+                    <device address="bus100_rear_seat">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_missing_address.xml b/tests/carservice_test/res/raw/car_audio_configuration_missing_address.xml
new file mode 100644
index 0000000..a3ab43d
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_missing_address.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<carAudioConfiguration version="2">
+    <zones>
+        <zone name="primary zone" isPrimary="true" audioZoneId="0">
+            <volumeGroups>
+                <group>
+                    <device address="bus0_media_out">
+                        <context context="music"/>
+                    </device>
+                    <device address="bus3_call_ring_out">
+                        <context context="call_ring"/>
+                    </device>
+                </group>
+                <group>
+                    <device address="bus1_navigation_out">
+                        <context context="navigation"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+            <inputDevices>
+                <inputDevice address="fm_tuner"/>
+                <inputDevice/>
+            </inputDevices>
+        </zone>
+        <zone name="rear seat zone" audioZoneId="1">
+            <volumeGroups>
+                <group>
+                    <device address="bus100_rear_seat">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+            <inputDevices>
+                <inputDevice address="bus_1000_input"/>
+                <inputDevice address="Built-In Back Mic"/>
+            </inputDevices>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_negative_audio_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_negative_audio_zone_id.xml
new file mode 100644
index 0000000..060934b
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_negative_audio_zone_id.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<carAudioConfiguration version="2">
+    <zones>
+        <zone name="primary zone" isPrimary="true" audioZoneId="-1" occupantZoneId="1">
+            <volumeGroups>
+                <group>
+                    <device address="bus0_media_out">
+                        <context context="music"/>
+                    </device>
+                    <device address="bus3_call_ring_out">
+                        <context context="call_ring"/>
+                    </device>
+                </group>
+                <group>
+                    <device address="bus1_navigation_out">
+                        <context context="navigation"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+        <zone name="rear seat zone" audioZoneId="2">
+            <volumeGroups>
+                <group>
+                    <device address="bus100_rear_seat">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_negative_occupant_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_negative_occupant_zone_id.xml
new file mode 100644
index 0000000..cffad51
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_negative_occupant_zone_id.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<carAudioConfiguration version="2">
+    <zones>
+        <zone name="primary zone" isPrimary="true" audioZoneId="0" occupantZoneId="-1">
+            <volumeGroups>
+                <group>
+                    <device address="bus0_media_out">
+                        <context context="music"/>
+                    </device>
+                    <device address="bus3_call_ring_out">
+                        <context context="call_ring"/>
+                    </device>
+                </group>
+                <group>
+                    <device address="bus1_navigation_out">
+                        <context context="navigation"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+        <zone name="rear seat zone" audioZoneId="2">
+            <volumeGroups>
+                <group>
+                    <device address="bus100_rear_seat">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_no_audio_zone_id_for_primary_zone.xml b/tests/carservice_test/res/raw/car_audio_configuration_no_audio_zone_id_for_primary_zone.xml
new file mode 100644
index 0000000..8cf6c13
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_no_audio_zone_id_for_primary_zone.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<carAudioConfiguration version="2">
+    <zones>
+        <zone name="primary zone" isPrimary="true">
+            <volumeGroups>
+                <group>
+                    <device address="bus0_media_out">
+                        <context context="music"/>
+                    </device>
+                    <device address="bus3_call_ring_out">
+                        <context context="call_ring"/>
+                    </device>
+                </group>
+                <group>
+                    <device address="bus1_navigation_out">
+                        <context context="navigation"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+        <zone name="rear seat zone" audioZoneId="2"
+              occupantZoneId="1">
+            <volumeGroups>
+                <group>
+                    <device address="bus100_rear_seat">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_non_existent_input_device.xml b/tests/carservice_test/res/raw/car_audio_configuration_non_existent_input_device.xml
new file mode 100644
index 0000000..d4ddfbe
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_non_existent_input_device.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<carAudioConfiguration version="2">
+    <zones>
+        <zone name="primary zone" isPrimary="true">
+            <volumeGroups>
+                <group>
+                    <device address="bus0_media_out">
+                        <context context="music"/>
+                    </device>
+                    <device address="bus3_call_ring_out">
+                        <context context="call_ring"/>
+                    </device>
+                </group>
+                <group>
+                    <device address="bus1_navigation_out">
+                        <context context="navigation"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+            <inputDevices>
+                <inputDevice address="fm_tuner"/>
+                <inputDevice address="Built-In Mic"/>
+            </inputDevices>
+        </zone>
+        <zone name="rear seat zone" audioZoneId="1">
+            <volumeGroups>
+                <group>
+                    <device address="bus100_rear_seat">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+            <inputDevices>
+                <inputDevice address="MISSING_AUDIO_INPUT"/>
+                <inputDevice address="Built-In Back Mic"/>
+            </inputDevices>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_audio_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_audio_zone_id.xml
new file mode 100644
index 0000000..8e1c41b
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_audio_zone_id.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<carAudioConfiguration version="2">
+    <zones>
+        <zone name="primary zone" isPrimary="true" audioZoneId="primary" occupantZoneId="1">
+            <volumeGroups>
+                <group>
+                    <device address="bus0_media_out">
+                        <context context="music"/>
+                    </device>
+                    <device address="bus3_call_ring_out">
+                        <context context="call_ring"/>
+                    </device>
+                </group>
+                <group>
+                    <device address="bus1_navigation_out">
+                        <context context="navigation"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+        <zone name="rear seat zone" audioZoneId="2">
+            <volumeGroups>
+                <group>
+                    <device address="bus100_rear_seat">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_occupant_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_occupant_zone_id.xml
new file mode 100644
index 0000000..f00b169
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_occupant_zone_id.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<carAudioConfiguration version="2">
+    <zones>
+        <zone name="primary zone" isPrimary="true" audioZoneId="0" occupantZoneId="one">
+            <volumeGroups>
+                <group>
+                    <device address="bus0_media_out">
+                        <context context="music"/>
+                    </device>
+                    <device address="bus3_call_ring_out">
+                        <context context="call_ring"/>
+                    </device>
+                </group>
+                <group>
+                    <device address="bus1_navigation_out">
+                        <context context="navigation"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+        <zone name="rear seat zone" audioZoneId="2">
+            <volumeGroups>
+                <group>
+                    <device address="bus100_rear_seat">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_port.xml b/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_port.xml
index 6787be6..9adef24 100644
--- a/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_port.xml
+++ b/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_port.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<carAudioConfiguration version="1">
+<carAudioConfiguration version="2">
     <zones>
         <zone name="primary zone" isPrimary="true">
             <volumeGroups>
@@ -14,12 +14,13 @@
                 <group>
                     <device address="bus1_navigation_out">
                         <context context="navigation"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
                     </device>
                 </group>
             </volumeGroups>
-            <displays>
-                <display port="one"/>
-            </displays>
         </zone>
     </zones>
 </carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_non_primary_zone_with_primary_audio_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_non_primary_zone_with_primary_audio_zone_id.xml
new file mode 100644
index 0000000..4364a1d
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_non_primary_zone_with_primary_audio_zone_id.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<carAudioConfiguration version="2">
+    <zones>
+        <zone name="primary zone" isPrimary="true" occupantZoneId="1">
+            <volumeGroups>
+                <group>
+                    <device address="bus0_media_out">
+                        <context context="music"/>
+                    </device>
+                    <device address="bus3_call_ring_out">
+                        <context context="call_ring"/>
+                    </device>
+                </group>
+                <group>
+                    <device address="bus1_navigation_out">
+                        <context context="navigation"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+        <zone name="rear seat zone" audioZoneId="0">
+            <volumeGroups>
+                <group>
+                    <device address="bus100_rear_seat">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_output_address_does_not_exist.xml b/tests/carservice_test/res/raw/car_audio_configuration_output_address_does_not_exist.xml
new file mode 100644
index 0000000..a359d36
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_output_address_does_not_exist.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<carAudioConfiguration version="2">
+    <zones>
+        <zone name="primary zone" isPrimary="true" audioZoneId="0" occupantZoneId="1">
+            <volumeGroups>
+                <group>
+                    <device address="bus0_media_out">
+                        <context context="music"/>
+                    </device>
+                    <device address="bus3_call_ring_out">
+                        <context context="call_ring"/>
+                    </device>
+                </group>
+                <group>
+                    <device address="bus1_navigation_out">
+                        <context context="navigation"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+        <zone name="rear seat zone" audioZoneId="2">
+            <volumeGroups>
+                <group>
+                    <device address="bus1000_does_not_exist">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_primary_zone_with_non_zero_audio_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_primary_zone_with_non_zero_audio_zone_id.xml
new file mode 100644
index 0000000..2d25716
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_primary_zone_with_non_zero_audio_zone_id.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<carAudioConfiguration version="2">
+    <zones>
+        <zone name="primary zone" isPrimary="true" audioZoneId="1" occupantZoneId="1">
+            <volumeGroups>
+                <group>
+                    <device address="bus0_media_out">
+                        <context context="music"/>
+                    </device>
+                    <device address="bus3_call_ring_out">
+                        <context context="call_ring"/>
+                    </device>
+                </group>
+                <group>
+                    <device address="bus1_navigation_out">
+                        <context context="navigation"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+        <zone name="rear seat zone" audioZoneId="2">
+            <volumeGroups>
+                <group>
+                    <device address="bus100_rear_seat">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_repeat_input_device.xml b/tests/carservice_test/res/raw/car_audio_configuration_repeat_input_device.xml
new file mode 100644
index 0000000..efe1e5e
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_repeat_input_device.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<carAudioConfiguration version="2">
+    <zones>
+        <zone name="primary zone" isPrimary="true" audioZoneId="0">
+            <volumeGroups>
+                <group>
+                    <device address="bus0_media_out">
+                        <context context="music"/>
+                    </device>
+                    <device address="bus3_call_ring_out">
+                        <context context="call_ring"/>
+                    </device>
+                </group>
+                <group>
+                    <device address="bus1_navigation_out">
+                        <context context="navigation"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+            <inputDevices>
+                <inputDevice address="fm_tuner"/>
+                <inputDevice address="Built-In Mic"/>
+            </inputDevices>
+        </zone>
+        <zone name="rear seat zone" audioZoneId="1">
+            <volumeGroups>
+                <group>
+                    <device address="bus100_rear_seat">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+            <inputDevices>
+                <inputDevice address="fm_tuner"/>
+                <inputDevice address="Built-In Back Mic"/>
+            </inputDevices>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_with_input_devices.xml b/tests/carservice_test/res/raw/car_audio_configuration_with_input_devices.xml
new file mode 100644
index 0000000..f97d835
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_with_input_devices.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<carAudioConfiguration version="2">
+    <zones>
+        <zone name="primary zone" isPrimary="true" audioZoneId="0">
+            <volumeGroups>
+                <group>
+                    <device address="bus0_media_out">
+                        <context context="music"/>
+                    </device>
+                    <device address="bus3_call_ring_out">
+                        <context context="call_ring"/>
+                    </device>
+                </group>
+                <group>
+                    <device address="bus1_navigation_out">
+                        <context context="navigation"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+            <inputDevices>
+                <inputDevice address="fm_tuner"/>
+                <inputDevice address="Built-In Mic"/>
+            </inputDevices>
+        </zone>
+        <zone name="rear seat zone" audioZoneId="1">
+            <volumeGroups>
+                <group>
+                    <device address="bus100_rear_seat">
+                        <context context="music"/>
+                        <context context="navigation"/>
+                        <context context="voice_command"/>
+                        <context context="call_ring"/>
+                        <context context="call"/>
+                        <context context="alarm"/>
+                        <context context="notification"/>
+                        <context context="system_sound"/>
+                        <context context="emergency"/>
+                        <context context="safety"/>
+                        <context context="vehicle_status"/>
+                        <context context="announcement"/>
+                    </device>
+                </group>
+            </volumeGroups>
+            <inputDevices>
+                <inputDevice address="bus_1000_input"/>
+                <inputDevice address="Built-In Back Mic"/>
+            </inputDevices>
+        </zone>
+    </zones>
+</carAudioConfiguration>
diff --git a/tests/carservice_test/res/xml/test_car_volume_groups.xml b/tests/carservice_test/res/xml/test_car_volume_groups.xml
new file mode 100644
index 0000000..9d25cf8
--- /dev/null
+++ b/tests/carservice_test/res/xml/test_car_volume_groups.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<volumeGroups xmlns:car="http://schemas.android.com/apk/res-auto">
+    <group>
+        <context car:context="music"/>
+    </group>
+    <group>
+        <context car:context="call_ring"/>
+        <context car:context="notification"/>
+        <context car:context="system_sound"/>
+        <context car:context="navigation"/>
+        <context car:context="voice_command"/>
+        <context car:context="call"/>
+        <context car:context="alarm"/>
+    </group>
+</volumeGroups>
\ No newline at end of file
diff --git a/tests/carservice_test/src/android/media/tests/AudioPolicyTest.java b/tests/carservice_test/src/android/media/tests/AudioPolicyTest.java
index 9e0f311..4601432 100644
--- a/tests/carservice_test/src/android/media/tests/AudioPolicyTest.java
+++ b/tests/carservice_test/src/android/media/tests/AudioPolicyTest.java
@@ -32,9 +32,9 @@
 import android.os.Looper;
 import android.util.Log;
 
-import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -51,7 +51,7 @@
     private static final long WAIT_TIMEOUT_MS = 1000;
     private AudioManager mAudioManager;
     private Handler mHandler;
-    private Context mContext = InstrumentationRegistry.getContext();
+    private Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
 
     @Before
     public void setUp() throws Exception {
@@ -68,7 +68,8 @@
     public void testAudioPorts() throws Exception {
         AudioPortUpdateListener listener = new AudioPortUpdateListener();
         mAudioManager.registerAudioPortUpdateListener(listener);
-        ArrayList<AudioPort> initialPorts = dumpAudioPorts("initial state");
+        // TODO(b/142554800): assert ports
+        dumpAudioPorts("initial state");
         AudioMix mediaMix = createAudioMix(AudioAttributes.CONTENT_TYPE_UNKNOWN,
                 AudioAttributes.CONTENT_TYPE_MUSIC);
         AudioPolicy audioPolicy = new AudioPolicy.Builder(mContext)
@@ -78,7 +79,7 @@
         mAudioManager.registerAudioPolicy(audioPolicy);
         dumpAudioPorts("policy set");
         mAudioManager.unregisterAudioPolicyAsync(audioPolicy);
-        ArrayList<AudioPort> afterUnregisterPorts = dumpAudioPorts("policy unset");
+        dumpAudioPorts("policy unset");
         mAudioManager.unregisterAudioPortUpdateListener(listener);
     }
 
@@ -87,7 +88,7 @@
         ArrayList<AudioPort> ports = new ArrayList<>();
         assertEquals(AudioManager.SUCCESS, AudioManager.listAudioPorts(ports));
         for (AudioPort port : ports) {
-            Log.i(TAG, "port:" + port.toString() + " name:" + port.name());
+            Log.i(TAG, "port:" + port + " name:" + port.name());
         }
         return ports;
     }
diff --git a/tests/carservice_test/src/com/android/car/AppFocusTest.java b/tests/carservice_test/src/com/android/car/AppFocusTest.java
index 3474d88..390acf2 100644
--- a/tests/carservice_test/src/com/android/car/AppFocusTest.java
+++ b/tests/carservice_test/src/com/android/car/AppFocusTest.java
@@ -21,8 +21,8 @@
 import android.car.CarAppFocusManager;
 import android.util.Log;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -46,6 +46,7 @@
         manager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, ownershipListener);
         listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
                 CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, true);
+        listener.resetWait();
         manager.abandonAppFocus(ownershipListener, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
         listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
                 CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, false);
@@ -57,7 +58,7 @@
         private boolean mLastChangeAppActive;
         private final Semaphore mChangeWait = new Semaphore(0);
 
-        public boolean waitForFocusChangeAndAssert(long timeoutMs, int expectedAppType,
+        private boolean waitForFocusChangeAndAssert(long timeoutMs, int expectedAppType,
                 boolean expectedAppActive) throws Exception {
             if (!mChangeWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
                 return false;
@@ -67,6 +68,10 @@
             return true;
         }
 
+        private void resetWait() {
+            mChangeWait.drainPermits();
+        }
+
         @Override
         public void onAppFocusChanged(int appType, boolean active) {
             Log.i(TAG, "onAppFocusChanged appType=" + appType + " active=" + active);
diff --git a/tests/carservice_test/src/com/android/car/CarAudioManagerTest.java b/tests/carservice_test/src/com/android/car/CarAudioManagerTest.java
index d11159e..2e2cee9 100644
--- a/tests/carservice_test/src/com/android/car/CarAudioManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarAudioManagerTest.java
@@ -19,8 +19,8 @@
 import android.car.media.CarAudioManager;
 import android.util.Log;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/tests/carservice_test/src/com/android/car/CarCabinManagerTest.java b/tests/carservice_test/src/com/android/car/CarCabinManagerTest.java
index 46d54b7..378d587 100644
--- a/tests/carservice_test/src/com/android/car/CarCabinManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarCabinManagerTest.java
@@ -33,8 +33,9 @@
 import android.util.Log;
 import android.util.MutableInt;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.car.vehiclehal.VehiclePropValueBuilder;
 import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler;
@@ -131,7 +132,7 @@
                 errorLatch.countDown();
             }
         });
-
+        mCarCabinManager.setBooleanProperty(PROP, AREA, true);
         getMockedVehicleHal().injectError(ERR_CODE, PROP, AREA);
         assertTrue(errorLatch.await(DEFAULT_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertEquals(PROP, propertyIdReceived.value);
@@ -141,6 +142,7 @@
 
     // Test an event
     @Test
+    @FlakyTest
     public void testEvent() throws Exception {
         mCarCabinManager.registerCallback(new EventListener());
         // Wait for two events generated on registration
diff --git a/tests/carservice_test/src/com/android/car/CarDiagnosticConstantsTest.java b/tests/carservice_test/src/com/android/car/CarDiagnosticConstantsTest.java
index 2955345..7ce3b5f 100644
--- a/tests/carservice_test/src/com/android/car/CarDiagnosticConstantsTest.java
+++ b/tests/carservice_test/src/com/android/car/CarDiagnosticConstantsTest.java
@@ -18,8 +18,8 @@
 
 import android.util.Log;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import junit.framework.TestCase;
 
diff --git a/tests/carservice_test/src/com/android/car/CarDiagnosticManagerTest.java b/tests/carservice_test/src/com/android/car/CarDiagnosticManagerTest.java
index f73c401..fb7eee6 100644
--- a/tests/carservice_test/src/com/android/car/CarDiagnosticManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarDiagnosticManagerTest.java
@@ -40,8 +40,9 @@
 import android.util.JsonWriter;
 import android.util.Log;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.car.vehiclehal.DiagnosticEventBuilder;
 import com.android.car.vehiclehal.DiagnosticJson;
@@ -203,6 +204,13 @@
     }
 
     @Override
+    protected synchronized void configureResourceOverrides(MockResources resources) {
+        super.configureResourceOverrides(resources);
+        resources.overrideResource(com.android.car.R.array.config_allowed_optional_car_features,
+                new String[]{Car.DIAGNOSTIC_SERVICE});
+    }
+
+    @Override
     protected synchronized void configureMockedHal() {
         java.util.Collection<Integer> numVendorSensors = Arrays.asList(0, 0);
         java.util.Collection<Integer> selectiveClear = Collections.singletonList(1);
@@ -487,7 +495,9 @@
         assertFalse(compressionIgnitionMonitors.NMHCCatalyst.incomplete);
     }
 
-    @Test public void testFuelType() throws Exception {
+    @Test
+    @FlakyTest
+    public void testFuelType() throws Exception {
         Listener listener = new Listener();
         mCarDiagnosticManager.registerListener(
                 listener,
diff --git a/tests/carservice_test/src/com/android/car/CarDrivingRestrictionsTest.java b/tests/carservice_test/src/com/android/car/CarDrivingRestrictionsTest.java
index 162cd3e..890981a 100644
--- a/tests/carservice_test/src/com/android/car/CarDrivingRestrictionsTest.java
+++ b/tests/carservice_test/src/com/android/car/CarDrivingRestrictionsTest.java
@@ -29,11 +29,12 @@
 import android.car.drivingstate.CarUxRestrictionsManager;
 import android.hardware.automotive.vehicle.V2_0.VehicleGear;
 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
+import android.os.Build;
 import android.os.SystemClock;
 import android.util.Log;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.car.vehiclehal.VehiclePropValueBuilder;
 import com.android.internal.annotations.GuardedBy;
@@ -211,9 +212,14 @@
                         .setTimestamp(SystemClock.elapsedRealtimeNanos())
                         .build());
         drivingEvent = listener.waitForDrivingStateChange();
-        assertNotNull(drivingEvent);
-        assertThat(drivingEvent.eventValue).isEqualTo(CarDrivingStateEvent.DRIVING_STATE_IDLING);
-
+        if (Build.IS_DEBUGGABLE) {
+            // In userdebug build, payloadChecker in HAL drops the invalid event.
+            assertNull(drivingEvent);
+        } else {
+            assertNotNull(drivingEvent);
+            assertThat(drivingEvent.eventValue).isEqualTo(
+                    CarDrivingStateEvent.DRIVING_STATE_IDLING);
+        }
         // Now, send in an invalid speed value as well, now the driving state will be unknown and
         // the UX restrictions will change to fully restricted.
         listener.reset();
@@ -224,13 +230,19 @@
                         .setTimestamp(SystemClock.elapsedRealtimeNanos())
                         .build());
         drivingEvent = listener.waitForDrivingStateChange();
-        assertNotNull(drivingEvent);
-        assertThat(drivingEvent.eventValue).isEqualTo(CarDrivingStateEvent.DRIVING_STATE_UNKNOWN);
-        restrictions = listener.waitForUxRestrictionsChange();
-        assertNotNull(restrictions);
-        assertTrue(restrictions.isRequiresDistractionOptimization());
-        assertThat(restrictions.getActiveRestrictions())
-                .isEqualTo(CarUxRestrictions.UX_RESTRICTIONS_FULLY_RESTRICTED);
+        if (Build.IS_DEBUGGABLE) {
+            // In userdebug build, payloadChecker in HAL drops the invalid event.
+            assertNull(drivingEvent);
+        } else {
+            assertNotNull(drivingEvent);
+            assertThat(drivingEvent.eventValue).isEqualTo(
+                    CarDrivingStateEvent.DRIVING_STATE_UNKNOWN);
+            restrictions = listener.waitForUxRestrictionsChange();
+            assertNotNull(restrictions);
+            assertTrue(restrictions.isRequiresDistractionOptimization());
+            assertThat(restrictions.getActiveRestrictions())
+                    .isEqualTo(CarUxRestrictions.UX_RESTRICTIONS_FULLY_RESTRICTED);
+        }
         mCarDrivingStateManager.unregisterListener();
         mCarUxRManager.unregisterListener();
     }
diff --git a/tests/carservice_test/src/com/android/car/CarFeatureControllerTest.java b/tests/carservice_test/src/com/android/car/CarFeatureControllerTest.java
new file mode 100644
index 0000000..5d508ca
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/CarFeatureControllerTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.Car;
+import android.car.CarFeatures;
+import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
+import android.util.Log;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import com.android.car.vehiclehal.VehiclePropValueBuilder;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class CarFeatureControllerTest extends MockedCarTestBase {
+    private static final String TAG = CarFeatureControllerTest.class.getSimpleName();
+    private static final String[] ENABLED_OPTIONAL_FEATURES = {
+            CarFeatures.FEATURE_CAR_USER_NOTICE_SERVICE,
+            Car.STORAGE_MONITORING_SERVICE
+    };
+    private String mDisabledOptionalFeatures = "";
+
+    @Override
+    protected void configureMockedHal() {
+        Log.i(TAG, "mDisabledOptionalFeatures:" + mDisabledOptionalFeatures);
+        addProperty(VehicleProperty.DISABLED_OPTIONAL_FEATURES,
+                VehiclePropValueBuilder.newBuilder(VehicleProperty.DISABLED_OPTIONAL_FEATURES)
+                        .setStringValue(mDisabledOptionalFeatures)
+                        .build());
+    }
+
+    @Override
+    protected void configureResourceOverrides(MockResources resources) {
+        super.configureResourceOverrides(resources);
+        resources.overrideResource(com.android.car.R.array.config_allowed_optional_car_features,
+                ENABLED_OPTIONAL_FEATURES);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        // Do nothing so that we can call super.setUp in test itself.
+    }
+
+    @Test
+    @UiThreadTest
+    public void testParsingVhalEmptyList() throws Exception {
+        super.setUp();
+        CarFeatureController featureController = CarLocalServices.getService(
+                CarFeatureController.class);
+        assertThat(featureController).isNotNull();
+        List<String> disabledFeatures = featureController.getDisabledFeaturesFromVhal();
+        assertThat(disabledFeatures).isEmpty();
+    }
+
+    @Test
+    @UiThreadTest
+    public void testParsingVhalMultipleEntries() throws Exception {
+        String[] disabledFeaturesExpected = {"com.aaa", "com.bbb"};
+        mDisabledOptionalFeatures = String.join(",", disabledFeaturesExpected);
+        super.setUp();
+        CarFeatureController featureController = CarLocalServices.getService(
+                CarFeatureController.class);
+        assertThat(featureController).isNotNull();
+        List<String> disabledFeatures = featureController.getDisabledFeaturesFromVhal();
+        assertThat(disabledFeatures).hasSize(disabledFeaturesExpected.length);
+        for (String feature: disabledFeaturesExpected) {
+            assertThat(disabledFeatures).contains(feature);
+        }
+    }
+
+    @Test
+    @UiThreadTest
+    public void testUserNoticeDisabledFromVhal() throws Exception {
+        mDisabledOptionalFeatures = CarFeatures.FEATURE_CAR_USER_NOTICE_SERVICE;
+        super.setUp();
+        CarFeatureController featureController = CarLocalServices.getService(
+                CarFeatureController.class);
+        assertThat(featureController).isNotNull();
+        List<String> disabledFeatures = featureController.getDisabledFeaturesFromVhal();
+        assertThat(disabledFeatures).contains(CarFeatures.FEATURE_CAR_USER_NOTICE_SERVICE);
+        assertThat(featureController.isFeatureEnabled(CarFeatures.FEATURE_CAR_USER_NOTICE_SERVICE))
+                .isFalse();
+        assertThat(featureController.isFeatureEnabled(Car.STORAGE_MONITORING_SERVICE)).isTrue();
+    }
+}
diff --git a/tests/carservice_test/src/com/android/car/CarHvacManagerTest.java b/tests/carservice_test/src/com/android/car/CarHvacManagerTest.java
index a32cca5..df2ce60 100644
--- a/tests/carservice_test/src/com/android/car/CarHvacManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarHvacManagerTest.java
@@ -16,9 +16,12 @@
 
 package com.android.car;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.testng.Assert.assertThrows;
 
 import android.car.Car;
 import android.car.hardware.CarPropertyValue;
@@ -35,12 +38,14 @@
 import android.util.Log;
 import android.util.MutableInt;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.car.vehiclehal.VehiclePropValueBuilder;
 import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler;
 
+import junit.framework.AssertionFailedError;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -83,6 +88,8 @@
         super.setUp();
         mAvailable = new Semaphore(0);
         mCarHvacManager = (CarHvacManager) getCar().getCarManager(Car.HVAC_SERVICE);
+        mCarHvacManager.setIntProperty(VehicleProperty.HVAC_FAN_SPEED,
+                VehicleAreaSeat.ROW_1_LEFT, 0);
     }
 
     // Test a boolean property
@@ -101,6 +108,17 @@
         assertFalse(defrost);
     }
 
+    /**
+     * Test {@link CarHvacManager#isPropertyAvailable(int, int)}
+     */
+    @Test
+    public void testHvacPropertyAvailable() {
+        assertThat(mCarHvacManager.isPropertyAvailable(VehicleProperty.HVAC_AC_ON,
+                VehicleAreaSeat.ROW_1_CENTER)).isFalse();
+        assertThat(mCarHvacManager.isPropertyAvailable(VehicleProperty.HVAC_FAN_SPEED,
+                VehicleAreaSeat.ROW_1_LEFT)).isTrue();
+    }
+
     // Test an integer property
     @Test
     public void testHvacFanSpeed() throws Exception {
@@ -156,7 +174,7 @@
                 errorLatch.countDown();
             }
         });
-
+        mCarHvacManager.setBooleanProperty(PROP, AREA, true);
         getMockedVehicleHal().injectError(ERR_CODE, PROP, AREA);
         assertTrue(errorLatch.await(DEFAULT_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertEquals(PROP, propertyIdReceived.value);
@@ -213,6 +231,38 @@
         assertEquals(VehicleAreaSeat.ROW_1_LEFT, mEventZoneVal);
     }
 
+    /**
+     * Test {@link CarHvacManager#unregisterCallback(CarHvacEventCallback)}
+     */
+    @Test
+    public void testUnregisterCallback() throws Exception {
+        EventListener listener = new EventListener();
+        mCarHvacManager.registerCallback(listener);
+        // Wait for events generated on registration
+        assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
+        assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
+        assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
+        assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
+
+        // Inject a boolean event and wait for its callback in onPropertySet.
+        VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.HVAC_DEFROSTER)
+                .setAreaId(VehicleAreaWindow.FRONT_WINDSHIELD)
+                .setTimestamp(SystemClock.elapsedRealtimeNanos())
+                .addIntValue(1)
+                .build();
+        assertEquals(0, mAvailable.availablePermits());
+        getMockedVehicleHal().injectEvent(v);
+
+        // Verify client get the callback.
+        assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
+        assertTrue(mEventBoolVal);
+        assertEquals(mEventZoneVal, VehicleAreaWindow.FRONT_WINDSHIELD);
+
+        // test unregister callback
+        mCarHvacManager.unregisterCallback(listener);
+        assertThrows(AssertionFailedError.class, () -> getMockedVehicleHal().injectEvent(v));
+    }
+
     private class HvacPropertyHandler implements VehicleHalPropertyHandler {
         HashMap<Integer, VehiclePropValue> mMap = new HashMap<>();
 
diff --git a/tests/carservice_test/src/com/android/car/CarInfoManagerTest.java b/tests/carservice_test/src/com/android/car/CarInfoManagerTest.java
index 454295a..4c3cc6d 100644
--- a/tests/carservice_test/src/com/android/car/CarInfoManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarInfoManagerTest.java
@@ -15,26 +15,39 @@
  */
 package com.android.car;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static com.google.common.truth.Truth.assertThat;
 
 import android.car.Car;
 import android.car.CarInfoManager;
+import android.car.PortLocationType;
+import android.car.VehicleAreaSeat;
+import android.hardware.automotive.vehicle.V2_0.EvConnectorType;
+import android.hardware.automotive.vehicle.V2_0.FuelType;
 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.car.vehiclehal.VehiclePropValueBuilder;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Arrays;
+import java.util.List;
+
 @RunWith(AndroidJUnit4.class)
 @MediumTest
 public class CarInfoManagerTest extends MockedCarTestBase {
     private static final String MAKE_NAME = "ANDROID";
-
+    private static final String MODEL_NAME = "TEST";
+    private static final int MODEL_YEAR = 2020;
+    private static final String MODEL_YEAR_STRING = "2020";
+    private static final float FAKE_CAPACITY = 2.0f;
+    private static final List<Integer> FUEL_TYPES =
+            Arrays.asList(FuelType.FUEL_TYPE_CNG, FuelType.FUEL_TYPE_BIODIESEL);
+    private static final List<Integer> EV_CONNECTOR_TYPES =
+            Arrays.asList(android.car.EvConnectorType.GBT, android.car.EvConnectorType.GBT_DC);
     private CarInfoManager mCarInfoManager;
 
     @Override
@@ -43,7 +56,37 @@
                 VehiclePropValueBuilder.newBuilder(VehicleProperty.INFO_MAKE)
                         .setStringValue(MAKE_NAME)
                         .build());
-
+        addStaticProperty(VehicleProperty.INFO_MODEL_YEAR,
+                VehiclePropValueBuilder.newBuilder(VehicleProperty.INFO_MODEL_YEAR)
+                        .addIntValue(MODEL_YEAR).build());
+        addStaticProperty(VehicleProperty.INFO_FUEL_CAPACITY,
+                VehiclePropValueBuilder.newBuilder(VehicleProperty.INFO_FUEL_CAPACITY)
+                        .addFloatValue(FAKE_CAPACITY).build());
+        addStaticProperty(VehicleProperty.INFO_EV_BATTERY_CAPACITY,
+                VehiclePropValueBuilder.newBuilder(VehicleProperty.INFO_EV_BATTERY_CAPACITY)
+                        .addFloatValue(FAKE_CAPACITY).build());
+        addStaticProperty(VehicleProperty.INFO_MODEL,
+                VehiclePropValueBuilder.newBuilder(VehicleProperty.INFO_MODEL)
+                        .setStringValue(MODEL_NAME).build());
+        addStaticProperty(VehicleProperty.INFO_FUEL_TYPE,
+                VehiclePropValueBuilder.newBuilder(VehicleProperty.INFO_FUEL_TYPE)
+                        .addIntValue(FuelType.FUEL_TYPE_CNG)
+                        .addIntValue(FuelType.FUEL_TYPE_BIODIESEL)
+                        .build());
+        addStaticProperty(VehicleProperty.INFO_EV_CONNECTOR_TYPE,
+                VehiclePropValueBuilder.newBuilder(VehicleProperty.INFO_EV_CONNECTOR_TYPE)
+                        .addIntValue(EvConnectorType.GBT_AC)
+                        .addIntValue(EvConnectorType.GBT_DC)
+                        .build());
+        addStaticProperty(VehicleProperty.INFO_EV_PORT_LOCATION,
+                VehiclePropValueBuilder.newBuilder(VehicleProperty.INFO_EV_PORT_LOCATION)
+                        .addIntValue(PortLocationType.FRONT).build());
+        addStaticProperty(VehicleProperty.INFO_FUEL_DOOR_LOCATION,
+                VehiclePropValueBuilder.newBuilder(VehicleProperty.INFO_FUEL_DOOR_LOCATION)
+                        .addIntValue(PortLocationType.FRONT_LEFT).build());
+        addStaticProperty(VehicleProperty.INFO_DRIVER_SEAT,
+                VehiclePropValueBuilder.newBuilder(VehicleProperty.INFO_FUEL_DOOR_LOCATION)
+                        .addIntValue(VehicleAreaSeat.SEAT_ROW_1_LEFT).build());
     }
 
     @Override
@@ -54,17 +97,50 @@
 
     @Test
     public void testVehicleId() throws Exception {
-        assertNotNull(mCarInfoManager.getVehicleId());
+        assertThat(mCarInfoManager.getVehicleId()).isNotNull();
     }
 
     @Test
     public void testManufacturer() throws Exception {
-        assertEquals(MAKE_NAME, mCarInfoManager.getManufacturer());
+        assertThat(mCarInfoManager.getManufacturer()).isEqualTo(MAKE_NAME);
     }
 
     @Test
-    public void testNotNullItems() throws Exception {
-        assertNotNull(mCarInfoManager.getModel());
-        assertNotNull(mCarInfoManager.getModelYear());
+    public void testGetModel() throws Exception {
+        assertThat(mCarInfoManager.getModel()).isEqualTo(MODEL_NAME);
+    }
+
+    @Test
+    public void testGetFuelType() throws Exception {
+        assertThat(mCarInfoManager.getFuelTypes()).asList().containsAllIn(FUEL_TYPES).inOrder();
+    }
+
+    @Test
+    public void testGetEvConnectorTypes() throws Exception {
+        assertThat(mCarInfoManager.getEvConnectorTypes()).asList().containsAllIn(EV_CONNECTOR_TYPES)
+                .inOrder();
+    }
+
+    @Test
+    public void testGetModelYear() throws Exception {
+        assertThat(mCarInfoManager.getModelYear()).isEqualTo(MODEL_YEAR_STRING);
+        assertThat(mCarInfoManager.getModelYearInInteger()).isEqualTo(MODEL_YEAR);
+    }
+
+    @Test
+    public void testGetPortDoorLocation() throws Exception {
+        assertThat(mCarInfoManager.getEvPortLocation()).isEqualTo(PortLocationType.FRONT);
+        assertThat(mCarInfoManager.getFuelDoorLocation()).isEqualTo(PortLocationType.FRONT_LEFT);
+    }
+
+    @Test
+    public void testGetCapacity() throws Exception {
+        assertThat(mCarInfoManager.getEvBatteryCapacity()).isEqualTo(FAKE_CAPACITY);
+        assertThat(mCarInfoManager.getFuelCapacity()).isEqualTo(FAKE_CAPACITY);
+    }
+
+    @Test
+    public void testGetDriverSeat() throws Exception {
+        assertThat(mCarInfoManager.getDriverSeat()).isEqualTo(VehicleAreaSeat.SEAT_ROW_1_LEFT);
     }
 }
diff --git a/tests/carservice_test/src/com/android/car/CarPackageManagerTest.java b/tests/carservice_test/src/com/android/car/CarPackageManagerTest.java
index 302e827..93a7103 100644
--- a/tests/carservice_test/src/com/android/car/CarPackageManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarPackageManagerTest.java
@@ -25,9 +25,10 @@
 import android.car.content.pm.CarPackageManager;
 import android.util.Log;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 import androidx.test.filters.Suppress;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.car.pm.CarPackageManagerService;
 
@@ -81,6 +82,7 @@
     // if the test is necessary.
     @Suppress
     @Test
+    @FlakyTest
     public void testSettingWhitelist() throws Exception {
         init(false);
         final String carServicePackageName = "com.android.car";
diff --git a/tests/carservice_test/src/com/android/car/CarPowerManagementTest.java b/tests/carservice_test/src/com/android/car/CarPowerManagementTest.java
index 0ae1e1f..0abf3e5 100644
--- a/tests/carservice_test/src/com/android/car/CarPowerManagementTest.java
+++ b/tests/carservice_test/src/com/android/car/CarPowerManagementTest.java
@@ -30,8 +30,8 @@
 import android.os.SystemClock;
 
 import androidx.test.annotation.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.car.systeminterface.DisplayInterface;
 import com.android.car.systeminterface.SystemInterface;
@@ -44,6 +44,7 @@
 import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
@@ -52,6 +53,10 @@
 @MediumTest
 public class CarPowerManagementTest extends MockedCarTestBase {
 
+    private static final int STATE_POLLING_INTERVAL_MS = 1; // Milliseconds
+    private static final int STATE_TRANSITION_MAX_WAIT_MS = 5 * STATE_POLLING_INTERVAL_MS;
+    private static final int TEST_SHUTDOWN_TIMEOUT_MS = 100 * STATE_POLLING_INTERVAL_MS;
+
     private final PowerStatePropertyHandler mPowerStateHandler = new PowerStatePropertyHandler();
     private final MockDisplayInterface mMockDisplayInterface = new MockDisplayInterface();
 
@@ -134,12 +139,27 @@
                 VehicleApPowerStateReport.SHUTDOWN_CANCELLED);
     }
 
+    @Test
+    @UiThreadTest
+    public void testCancelShutdownFromWaitForFinish() throws Exception {
+        assertWaitForVhal();
+        mPowerStateHandler.sendStateAndCheckResponse(
+                VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+                VehicleApPowerStateShutdownParam.CAN_SLEEP,
+                VehicleApPowerStateReport.DEEP_SLEEP_ENTRY);
+        // After DEEP_SLEEP_ENTRY, we're in WAIT_FOR_FINISH
+        mPowerStateHandler.sendStateAndCheckResponse(
+                VehicleApPowerStateReq.CANCEL_SHUTDOWN,
+                0,
+                VehicleApPowerStateReport.SHUTDOWN_CANCELLED);
+    }
+
     /**********************************************************************************************
      * Test for invalid state transtions
      **********************************************************************************************/
     @Test
     @UiThreadTest
-    public void testInivalidTransitionsFromWaitForVhal() throws Exception {
+    public void testInvalidTransitionsFromWaitForVhal() throws Exception {
         assertWaitForVhal();
         mPowerStateHandler.sendStateAndExpectNoResponse(VehicleApPowerStateReq.CANCEL_SHUTDOWN, 0);
         mPowerStateHandler.sendStateAndExpectNoResponse(VehicleApPowerStateReq.FINISHED, 0);
@@ -162,8 +182,6 @@
     @UiThreadTest
     public void testInvalidTransitionsFromPrepareShutdown() throws Exception {
         assertWaitForVhal();
-        // Increase the timeout to handle all the test cases here
-        CarPowerManagementService.setShutdownPrepareTimeout(15 * 1000);
         // Transition to SHUTDOWN_PREPARE first
         mPowerStateHandler.sendStateAndCheckResponse(
                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
@@ -191,9 +209,6 @@
                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
                 VehicleApPowerStateShutdownParam.CAN_SLEEP,
                 VehicleApPowerStateReport.DEEP_SLEEP_ENTRY);
-        // Once the device has entered WAIT_FOR_FINISH, shutdown cannot be cancelled.
-        mPowerStateHandler.sendStateAndExpectNoResponse(VehicleApPowerStateReq.CANCEL_SHUTDOWN, 0);
-        mPowerStateHandler.sendStateAndExpectNoResponse(VehicleApPowerStateReq.ON, 0);
         mPowerStateHandler.sendStateAndExpectNoResponse(
                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
                 VehicleApPowerStateShutdownParam.CAN_SLEEP);
@@ -214,9 +229,6 @@
                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
                 VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY,
                 VehicleApPowerStateReport.SHUTDOWN_START);
-        // Once the device has entered WAIT_FOR_FINISH, shutdown cannot be cancelled.
-        mPowerStateHandler.sendStateAndExpectNoResponse(VehicleApPowerStateReq.CANCEL_SHUTDOWN, 0);
-        mPowerStateHandler.sendStateAndExpectNoResponse(VehicleApPowerStateReq.ON, 0);
         mPowerStateHandler.sendStateAndExpectNoResponse(
                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
                 VehicleApPowerStateShutdownParam.CAN_SLEEP);
@@ -259,6 +271,22 @@
         mMockDisplayInterface.waitForDisplayState(false);
     }
 
+    @Test
+    @UiThreadTest
+    public void testSleepImmediateEntry() throws Exception {
+        assertWaitForVhal();
+        mMockDisplayInterface.waitForDisplayState(false);
+        mPowerStateHandler.sendStateAndCheckResponse(
+                VehicleApPowerStateReq.ON,
+                0,
+                VehicleApPowerStateReport.ON);
+        mMockDisplayInterface.waitForDisplayState(true);
+        mPowerStateHandler.sendPowerState(
+                VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+                VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY);
+        assertResponseTransient(VehicleApPowerStateReport.DEEP_SLEEP_ENTRY, 0, true);
+    }
+
     // Check that 'expectedState' was reached and is the current state.
     private void assertResponse(int expectedState, int expectedParam, boolean checkParam)
             throws Exception {
@@ -293,7 +321,6 @@
         int[] first = setEvents.getFirst();
         assertEquals(VehicleApPowerStateReport.WAIT_FOR_VHAL, first[0]);
         assertEquals(0, first[1]);
-        CarPowerManagementService.setShutdownPrepareTimeout(0);
     }
 
     private final class MockDisplayInterface implements DisplayInterface {
@@ -320,16 +347,18 @@
         }
 
         @Override
-        public void startDisplayStateMonitoring(CarPowerManagementService service) {}
+        public void startDisplayStateMonitoring(CarPowerManagementService service) {
+            // To reduce test duration, decrease the polling interval and the
+            // time to wait for a shutdown
+            service.setShutdownTimersForTest(STATE_POLLING_INTERVAL_MS,
+                    TEST_SHUTDOWN_TIMEOUT_MS);
+        }
 
         @Override
         public void stopDisplayStateMonitoring() {}
 
         @Override
         public void refreshDisplayBrightness() {}
-
-        @Override
-        public void reconfigureSecondaryDisplays() {}
     }
 
     private class PowerStatePropertyHandler implements VehicleHalPropertyHandler {
@@ -382,7 +411,7 @@
             }
         }
 
-        private LinkedList<int[]> waitForStateSetAndGetAll(long timeoutMs, int expectedSet)
+        private LinkedList<int[]> waitForStateSetAndGetAll(long timeoutMs, int expectedState)
                 throws Exception {
             while (true) {
                 if (!mSetWaitSemaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
@@ -391,7 +420,7 @@
                 synchronized (this) {
                     boolean found = false;
                     for (int[] state : mSetStates) {
-                        if (state[0] == expectedSet) {
+                        if (state[0] == expectedState) {
                             found = true;
                             break;
                         }
@@ -399,36 +428,47 @@
                     if (found) {
                         LinkedList<int[]> res = mSetStates;
                         mSetStates = new LinkedList<>();
+                        mSetWaitSemaphore.drainPermits();
                         return res;
                     }
                 }
             }
         }
 
-        private void sendStateAndCheckResponse(int state, int param, int expectedSet)
+        private void sendStateAndCheckResponse(int state, int param, int expectedState)
                 throws Exception {
             sendPowerState(state, param);
-            waitForStateSetAndGetAll(DEFAULT_WAIT_TIMEOUT_MS, expectedSet);
+            waitForStateSetAndGetAll(DEFAULT_WAIT_TIMEOUT_MS, expectedState);
         }
 
         /**
-         * Checks that a power state transition does NOT occur.  If any state does occur during
-         * the timeout period, then the test fails.
+         * Checks that a power state transition does NOT occur. If any state does occur during
+         * the timeout period (other than a POSTPONE), then the test fails.
          */
         private void sendStateAndExpectNoResponse(int state, int param) throws Exception {
             sendPowerState(state, param);
             // Wait to see if a state transition occurs
-            if (!mSetWaitSemaphore.tryAcquire(DEFAULT_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
-                // No state transition, this is a success!
-                return;
-            } else {
+            long startTime = SystemClock.elapsedRealtime();
+            while (true) {
+                long timeWaitingMs = SystemClock.elapsedRealtime() - startTime;
+                if (timeWaitingMs > STATE_TRANSITION_MAX_WAIT_MS) {
+                    // No meaningful state transition: this is a success!
+                    return;
+                }
+                if (!mSetWaitSemaphore.tryAcquire(STATE_TRANSITION_MAX_WAIT_MS,
+                        TimeUnit.MILLISECONDS)) {
+                    // No state transition, this is a success!
+                    return;
+                }
                 synchronized (this) {
-                    int[] newState = mSetStates.pop();
-                    if (newState[0] != VehicleApPowerStateReport.SHUTDOWN_POSTPONE) {
-                        fail("Unexpected state change occured, state=" + newState[0]);
+                    while (!mSetStates.isEmpty()) {
+                        int[] newState = mSetStates.pop();
+                        if (newState[0] != VehicleApPowerStateReport.SHUTDOWN_POSTPONE) {
+                            fail("Unexpected state change occurred, state="
+                                    + Arrays.toString(newState));
+                        }
                     }
-                    // Reset the collected states
-                    mSetStates = new LinkedList<>();
+                    mSetWaitSemaphore.drainPermits();
                 }
             }
         }
diff --git a/tests/carservice_test/src/com/android/car/CarProjectionManagerTest.java b/tests/carservice_test/src/com/android/car/CarProjectionManagerTest.java
index 9fe3a84..ebc493f 100644
--- a/tests/carservice_test/src/com/android/car/CarProjectionManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarProjectionManagerTest.java
@@ -30,8 +30,8 @@
 import android.util.Log;
 import android.view.KeyEvent;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.car.vehiclehal.VehiclePropValueBuilder;
 import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler;
diff --git a/tests/carservice_test/src/com/android/car/CarPropertyEventTest.java b/tests/carservice_test/src/com/android/car/CarPropertyEventTest.java
new file mode 100644
index 0000000..cf3e482
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/CarPropertyEventTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarPropertyEvent;
+import android.car.hardware.property.CarPropertyManager;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+
+/** Unit tests for {@link android.car.hardware.property.CarPropertyEvent} */
+@RunWith(MockitoJUnitRunner.class)
+public final class CarPropertyEventTest {
+
+    private static final int FAKE_PROPERTY_ID = 0x1101111;
+    private static final int FAKE_AREA_ID = 0x1;
+    private static final int FAKE_PROPERTY_VALUE = 5;
+    private final Parcel mParcel = Parcel.obtain();
+
+    @After
+    public void tearDown() throws Exception {
+        mParcel.recycle();
+    }
+
+    private <T extends Parcelable> T readFromParcel() {
+        mParcel.setDataPosition(0);
+        return mParcel.readParcelable(null);
+    }
+
+    private void writeToParcel(Parcelable value) {
+        mParcel.writeParcelable(value, 0);
+    }
+
+    @Test
+    public void testCreateErrorEvent() {
+        CarPropertyEvent carPropertyEvent = CarPropertyEvent
+                .createErrorEventWithErrorCode(FAKE_PROPERTY_ID, FAKE_AREA_ID,
+                        CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN);
+
+        assertThat(carPropertyEvent.getErrorCode())
+                .isEqualTo(CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN);
+        assertThat(carPropertyEvent.getCarPropertyValue().getStatus()).isEqualTo(
+                CarPropertyValue.STATUS_ERROR);
+        assertThat(carPropertyEvent.getEventType()).isEqualTo(
+                CarPropertyEvent.PROPERTY_EVENT_ERROR);
+        assertThat(carPropertyEvent.describeContents()).isEqualTo(0);
+    }
+
+    @Test
+    public void testWriteAndReadEvent() {
+        CarPropertyValue<Integer> value = new CarPropertyValue<Integer>(FAKE_PROPERTY_ID,
+                FAKE_AREA_ID, FAKE_PROPERTY_VALUE);
+        CarPropertyEvent carPropertyEvent = new CarPropertyEvent(
+                CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, value);
+
+        writeToParcel(carPropertyEvent);
+        CarPropertyEvent eventReadFromParcel = readFromParcel();
+
+        assertThat(eventReadFromParcel.getCarPropertyValue().getAreaId())
+                .isEqualTo(FAKE_AREA_ID);
+        assertThat(eventReadFromParcel.getCarPropertyValue().getPropertyId())
+                .isEqualTo(FAKE_PROPERTY_ID);
+        assertThat(eventReadFromParcel.getCarPropertyValue().getValue())
+                .isEqualTo(FAKE_PROPERTY_VALUE);
+        assertThat(eventReadFromParcel.getEventType())
+                .isEqualTo(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE);
+    }
+}
diff --git a/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java b/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java
new file mode 100644
index 0000000..b620fdf
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java
@@ -0,0 +1,789 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+import static org.testng.Assert.assertThrows;
+
+import android.car.Car;
+import android.car.VehicleAreaType;
+import android.car.VehiclePropertyIds;
+import android.car.hardware.CarPropertyConfig;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarInternalErrorException;
+import android.car.hardware.property.CarPropertyManager;
+import android.car.hardware.property.PropertyAccessDeniedSecurityException;
+import android.car.hardware.property.PropertyNotAvailableAndRetryException;
+import android.car.hardware.property.PropertyNotAvailableException;
+import android.car.hardware.property.VehicleHalStatusCode;
+import android.car.test.util.Visitor;
+import android.hardware.automotive.vehicle.V2_0.VehicleArea;
+import android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropertyGroup;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType;
+import android.os.Build;
+import android.os.ServiceSpecificException;
+import android.os.SystemClock;
+import android.util.ArraySet;
+import android.util.Log;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler;
+
+import com.google.common.truth.Truth;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test for {@link android.car.hardware.property.CarPropertyManager}
+ */
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class CarPropertyManagerTest extends MockedCarTestBase {
+
+    private static final String TAG = CarPropertyManagerTest.class.getSimpleName();
+
+    /**
+     * configArray[0], 1 indicates the property has a String value
+     * configArray[1], 1 indicates the property has a Boolean value .
+     * configArray[2], 1 indicates the property has a Integer value
+     * configArray[3], the number indicates the size of Integer[]  in the property.
+     * configArray[4], 1 indicates the property has a Long value .
+     * configArray[5], the number indicates the size of Long[]  in the property.
+     * configArray[6], 1 indicates the property has a Float value .
+     * configArray[7], the number indicates the size of Float[] in the property.
+     * configArray[8], the number indicates the size of byte[] in the property.
+     */
+    private static final java.util.Collection<Integer> CONFIG_ARRAY_1 =
+            Arrays.asList(1, 0, 1, 0, 1, 0, 0, 0, 0);
+    private static final java.util.Collection<Integer> CONFIG_ARRAY_2 =
+            Arrays.asList(1, 1, 1, 0, 0, 0, 0, 2, 0);
+    private static final Object[] EXPECTED_VALUE_1 = {"android", 1, 1L};
+    private static final Object[] EXPECTED_VALUE_2 = {"android", true, 3, 1.1f, 2f};
+
+    private static final int CUSTOM_SEAT_INT_PROP_1 =
+            0x1201 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.SEAT;
+    private static final int CUSTOM_SEAT_INT_PROP_2 =
+            0x1202 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.SEAT;
+
+    private static final int CUSTOM_SEAT_MIXED_PROP_ID_1 =
+            0x1101 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.MIXED | VehicleArea.SEAT;
+    private static final int CUSTOM_GLOBAL_MIXED_PROP_ID_2 =
+            0x1102 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.MIXED | VehicleArea.GLOBAL;
+
+    private static final int CUSTOM_GLOBAL_INT_ARRAY_PROP =
+            0x1103 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32_VEC
+                    | VehicleArea.GLOBAL;
+    private static final Integer[] FAKE_INT_ARRAY_VALUE = {1, 2};
+
+    // Vendor properties for testing exceptions.
+    private static final int PROP_CAUSE_STATUS_CODE_TRY_AGAIN =
+            0x1201 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL;
+    private static final int PROP_CAUSE_STATUS_CODE_INVALID_ARG =
+            0x1202 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL;
+    private static final int PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE =
+            0x1203 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL;
+    private static final int PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR =
+            0x1204 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL;
+    private static final int PROP_CAUSE_STATUS_CODE_ACCESS_DENIED =
+            0x1205 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL;
+
+    // Use FAKE_PROPERTY_ID to test api return null or throw exception.
+    private static final int FAKE_PROPERTY_ID = 0x111;
+
+    private static final int DRIVER_SIDE_AREA_ID = VehicleAreaSeat.ROW_1_LEFT
+                                                    | VehicleAreaSeat.ROW_2_LEFT;
+    private static final int PASSENGER_SIDE_AREA_ID = VehicleAreaSeat.ROW_1_RIGHT
+                                                    | VehicleAreaSeat.ROW_2_CENTER
+                                                    | VehicleAreaSeat.ROW_2_RIGHT;
+    private static final float INIT_TEMP_VALUE = 16f;
+    private static final float CHANGED_TEMP_VALUE = 20f;
+    private static final int CALLBACK_SHORT_TIMEOUT_MS = 250; // ms
+    // Wait for CarPropertyManager register/unregister listener
+    private static final long WAIT_FOR_NO_EVENTS = 50;
+
+    private static final List<Integer> USER_HAL_PROPERTIES = Arrays.asList(
+            VehiclePropertyIds.INITIAL_USER_INFO,
+            VehiclePropertyIds.SWITCH_USER,
+            VehiclePropertyIds.CREATE_USER,
+            VehiclePropertyIds.REMOVE_USER,
+            VehiclePropertyIds.USER_IDENTIFICATION_ASSOCIATION
+            );
+
+    private CarPropertyManager mManager;
+
+    @Rule public TestName mTestName = new TestName();
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        setUpTargetSdk();
+        mManager = (CarPropertyManager) getCar().getCarManager(Car.PROPERTY_SERVICE);
+        assertThat(mManager).isNotNull();
+    }
+
+    private void setUpTargetSdk() {
+        if (mTestName.getMethodName().endsWith("InQ")) {
+            getContext().getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.Q;
+        } else if (mTestName.getMethodName().endsWith("InR")) {
+            getContext().getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.R;
+        }
+    }
+
+    @Test
+    public void testMixedPropertyConfigs() {
+        List<CarPropertyConfig> configs = mManager.getPropertyList();
+        for (CarPropertyConfig cfg : configs) {
+            switch (cfg.getPropertyId()) {
+                case CUSTOM_SEAT_MIXED_PROP_ID_1:
+                    assertThat(cfg.getConfigArray()).containsExactlyElementsIn(CONFIG_ARRAY_1)
+                            .inOrder();
+                    break;
+                case CUSTOM_GLOBAL_MIXED_PROP_ID_2:
+                    assertThat(cfg.getConfigArray()).containsExactlyElementsIn(CONFIG_ARRAY_2)
+                            .inOrder();
+                    break;
+                case VehiclePropertyIds.HVAC_TEMPERATURE_SET:
+                case PROP_CAUSE_STATUS_CODE_ACCESS_DENIED:
+                case PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR:
+                case PROP_CAUSE_STATUS_CODE_TRY_AGAIN:
+                case PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE:
+                case PROP_CAUSE_STATUS_CODE_INVALID_ARG:
+                case CUSTOM_SEAT_INT_PROP_1:
+                case CUSTOM_SEAT_INT_PROP_2:
+                case CUSTOM_GLOBAL_INT_ARRAY_PROP:
+                case VehiclePropertyIds.INFO_VIN:
+                    break;
+                default:
+                    Assert.fail("Unexpected CarPropertyConfig: " + cfg.toString());
+            }
+        }
+    }
+
+    @Test
+    public void testGetMixTypeProperty() {
+        mManager.setProperty(Object[].class, CUSTOM_SEAT_MIXED_PROP_ID_1,
+                0, EXPECTED_VALUE_1);
+        CarPropertyValue<Object[]> result = mManager.getProperty(
+                CUSTOM_SEAT_MIXED_PROP_ID_1, 0);
+        assertThat(result.getValue()).isEqualTo(EXPECTED_VALUE_1);
+        mManager.setProperty(Object[].class, CUSTOM_GLOBAL_MIXED_PROP_ID_2,
+                0, EXPECTED_VALUE_2);
+        result = mManager.getProperty(
+                CUSTOM_GLOBAL_MIXED_PROP_ID_2, 0);
+        assertThat(result.getValue()).isEqualTo(EXPECTED_VALUE_2);
+    }
+
+    /**
+     * Test {@link android.car.hardware.property.CarPropertyManager#getIntArrayProperty(int, int)}
+     */
+    @Test
+    public void testGetIntArrayProperty() {
+        mManager.setProperty(Integer[].class, CUSTOM_GLOBAL_INT_ARRAY_PROP, VehicleArea.GLOBAL,
+                FAKE_INT_ARRAY_VALUE);
+
+        int[] result = mManager.getIntArrayProperty(CUSTOM_GLOBAL_INT_ARRAY_PROP,
+                VehicleArea.GLOBAL);
+        assertThat(result).asList().containsExactlyElementsIn(FAKE_INT_ARRAY_VALUE);
+    }
+
+    /**
+     * Test {@link CarPropertyManager#getProperty(Class, int, int)}
+     */
+    @Test
+    public void testGetPropertyWithClass() {
+        mManager.setProperty(Integer[].class, CUSTOM_GLOBAL_INT_ARRAY_PROP, VehicleArea.GLOBAL,
+                FAKE_INT_ARRAY_VALUE);
+
+        CarPropertyValue<Integer[]> result = mManager.getProperty(Integer[].class,
+                CUSTOM_GLOBAL_INT_ARRAY_PROP, VehicleArea.GLOBAL);
+        assertThat(result.getValue()).asList().containsExactlyElementsIn(FAKE_INT_ARRAY_VALUE);
+    }
+
+    /**
+     * Test {@link CarPropertyManager#isPropertyAvailable(int, int)}
+     */
+    @Test
+    public void testIsPropertyAvailable() {
+        assertThat(mManager.isPropertyAvailable(FAKE_PROPERTY_ID, VehicleArea.GLOBAL)).isFalse();
+        assertThat(mManager.isPropertyAvailable(CUSTOM_GLOBAL_INT_ARRAY_PROP, VehicleArea.GLOBAL))
+                .isTrue();
+    }
+
+    /**
+     * Test {@link CarPropertyManager#getWritePermission(int)}
+     * and {@link CarPropertyManager#getWritePermission(int)}
+     */
+    @Test
+    public void testGetPermission() {
+        String hvacReadPermission = mManager.getReadPermission(
+                VehiclePropertyIds.HVAC_TEMPERATURE_SET);
+        assertThat(hvacReadPermission).isEqualTo(Car.PERMISSION_CONTROL_CAR_CLIMATE);
+        String hvacWritePermission = mManager.getWritePermission(
+                VehiclePropertyIds.HVAC_TEMPERATURE_SET);
+        assertThat(hvacWritePermission).isEqualTo(Car.PERMISSION_CONTROL_CAR_CLIMATE);
+
+        // For read-only property
+        String vinReadPermission = mManager.getReadPermission(VehiclePropertyIds.INFO_VIN);
+        assertThat(vinReadPermission).isEqualTo(Car.PERMISSION_IDENTIFICATION);
+        String vinWritePermission = mManager.getWritePermission(VehiclePropertyIds.INFO_VIN);
+        assertThat(vinWritePermission).isNull();
+    }
+
+    @Test
+    public void testGetPropertyConfig() {
+        CarPropertyConfig config = mManager.getCarPropertyConfig(CUSTOM_SEAT_MIXED_PROP_ID_1);
+        assertThat(config.getPropertyId()).isEqualTo(CUSTOM_SEAT_MIXED_PROP_ID_1);
+        // return null if can not find the propertyConfig for the property.
+        assertThat(mManager.getCarPropertyConfig(FAKE_PROPERTY_ID)).isNull();
+    }
+
+    @Test
+    public void testGetAreaId() {
+        int result = mManager.getAreaId(CUSTOM_SEAT_MIXED_PROP_ID_1, VehicleAreaSeat.ROW_1_LEFT);
+        assertThat(result).isEqualTo(DRIVER_SIDE_AREA_ID);
+        //test for the GLOBAL property
+        int globalAreaId =
+                mManager.getAreaId(CUSTOM_GLOBAL_MIXED_PROP_ID_2, VehicleAreaSeat.ROW_1_LEFT);
+        assertThat(globalAreaId).isEqualTo(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL);
+        //test exception
+        assertThrows(IllegalArgumentException.class, () -> mManager.getAreaId(
+                CUSTOM_SEAT_MIXED_PROP_ID_1, VehicleAreaSeat.ROW_3_CENTER));
+        assertThrows(IllegalArgumentException.class, () -> mManager.getAreaId(FAKE_PROPERTY_ID,
+                VehicleAreaSeat.ROW_1_LEFT));
+    }
+
+    @Test
+    public void testNotReceiveOnErrorEvent() throws Exception {
+        TestErrorCallback callback = new TestErrorCallback();
+        mManager.registerCallback(callback, VehiclePropertyIds.HVAC_TEMPERATURE_SET,
+                CarPropertyManager.SENSOR_RATE_ONCHANGE);
+        callback.assertRegisterCompleted();
+        injectErrorEvent(VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID,
+                CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN);
+        // app never change the value of HVAC_TEMPERATURE_SET, it won't get an error code.
+        callback.assertOnErrorEventNotCalled();
+    }
+
+    @Test
+    public void testReceiveOnErrorEvent() throws Exception {
+        TestErrorCallback callback = new TestErrorCallback();
+        mManager.registerCallback(callback, VehiclePropertyIds.HVAC_TEMPERATURE_SET,
+                CarPropertyManager.SENSOR_RATE_ONCHANGE);
+        callback.assertRegisterCompleted();
+        mManager.setFloatProperty(
+                VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID,
+                CHANGED_TEMP_VALUE);
+        injectErrorEvent(VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID,
+                CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN);
+        callback.assertOnErrorEventCalled();
+        assertThat(callback.mReceivedErrorEventWithErrorCode).isTrue();
+        assertThat(callback.mErrorCode).isEqualTo(
+                CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN);
+        assertThat(callback.mReceivedErrorEventWithOutErrorCode).isFalse();
+    }
+
+    @Test
+    public void testNotReceiveOnErrorEventAfterUnregister() throws Exception {
+        TestErrorCallback callback1 = new TestErrorCallback();
+        mManager.registerCallback(callback1, VehiclePropertyIds.HVAC_TEMPERATURE_SET,
+                CarPropertyManager.SENSOR_RATE_ONCHANGE);
+        callback1.assertRegisterCompleted();
+        TestErrorCallback callback2 = new TestErrorCallback();
+        mManager.registerCallback(callback2, VehiclePropertyIds.HVAC_TEMPERATURE_SET,
+                CarPropertyManager.SENSOR_RATE_ONCHANGE);
+        mManager.setFloatProperty(
+                VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID,
+                CHANGED_TEMP_VALUE);
+        mManager.unregisterCallback(callback1, VehiclePropertyIds.HVAC_TEMPERATURE_SET);
+        SystemClock.sleep(WAIT_FOR_NO_EVENTS);
+        injectErrorEvent(VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID,
+                CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN);
+        // callback1 is unregistered
+        callback1.assertOnErrorEventNotCalled();
+        callback2.assertOnErrorEventCalled();
+    }
+    @Test
+    public void testSetterExceptionsInQ() {
+        Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion)
+                .isEqualTo(Build.VERSION_CODES.Q);
+
+        assertThrows(IllegalStateException.class,
+                ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_ACCESS_DENIED,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
+        assertThrows(IllegalStateException.class,
+                ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
+        assertThrows(IllegalStateException.class,
+                ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
+        assertThrows(IllegalArgumentException.class,
+                ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_INVALID_ARG,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
+        assertThrows(RuntimeException.class,
+                ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_ACCESS_DENIED,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
+    }
+
+    @Test
+    public void testSetterExceptionsInR() {
+        Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion)
+                .isEqualTo(Build.VERSION_CODES.R);
+
+        assertThrows(PropertyAccessDeniedSecurityException.class,
+                ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_ACCESS_DENIED,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
+        assertThrows(PropertyNotAvailableAndRetryException.class,
+                ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_TRY_AGAIN,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
+        assertThrows(PropertyNotAvailableException.class,
+                ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
+        assertThrows(CarInternalErrorException.class,
+                ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
+        assertThrows(IllegalArgumentException.class,
+                ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_INVALID_ARG,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1));
+    }
+
+    @Test
+    public void testGetterExceptionsInQ() {
+        Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion)
+                .isEqualTo(Build.VERSION_CODES.Q);
+
+        assertThrows(IllegalStateException.class,
+                ()->mManager.getProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+        assertThrows(IllegalArgumentException.class,
+                ()->mManager.getProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+        assertThrows(IllegalStateException.class,
+                ()->mManager.getProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+        assertThrows(IllegalStateException.class,
+                ()->mManager.getProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+        Truth.assertThat(mManager.getProperty(PROP_CAUSE_STATUS_CODE_TRY_AGAIN,
+                VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)).isNull();
+    }
+
+    @Test
+    public void testGetterExceptionsInR() {
+        Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion)
+                .isEqualTo(Build.VERSION_CODES.R);
+
+        assertThrows(PropertyAccessDeniedSecurityException.class,
+                () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+        assertThrows(IllegalArgumentException.class,
+                () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+        assertThrows(PropertyNotAvailableAndRetryException.class,
+                () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_TRY_AGAIN,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+        assertThrows(PropertyNotAvailableException.class,
+                () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+        assertThrows(CarInternalErrorException.class,
+                () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR,
+                        VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+    }
+
+    @Test
+    public void testOnChangeEventWithSameAreaId() throws Exception {
+        // init
+        mManager.setProperty(Integer.class,
+                CUSTOM_SEAT_INT_PROP_1, DRIVER_SIDE_AREA_ID, 1);
+        TestSequenceCallback callback = new TestSequenceCallback(1);
+        mManager.registerCallback(callback, CUSTOM_SEAT_INT_PROP_1, 0);
+        callback.assertRegisterCompleted();
+
+        VehiclePropValue firstFakeValueDriveSide = new VehiclePropValue();
+        firstFakeValueDriveSide.prop = CUSTOM_SEAT_INT_PROP_1;
+        firstFakeValueDriveSide.areaId = DRIVER_SIDE_AREA_ID;
+        firstFakeValueDriveSide.value.int32Values.add(2);
+        firstFakeValueDriveSide.timestamp = SystemClock.elapsedRealtimeNanos();
+        VehiclePropValue secFakeValueDriveSide = new VehiclePropValue();
+        secFakeValueDriveSide.prop = CUSTOM_SEAT_INT_PROP_1;
+        secFakeValueDriveSide.areaId = DRIVER_SIDE_AREA_ID;
+        secFakeValueDriveSide.value.int32Values.add(3); // 0 in HAL indicate false;
+        secFakeValueDriveSide.timestamp = SystemClock.elapsedRealtimeNanos();
+        // inject the new event first
+        getMockedVehicleHal().injectEvent(secFakeValueDriveSide);
+        // inject the old event
+        getMockedVehicleHal().injectEvent(firstFakeValueDriveSide);
+        callback.assertOnChangeEventCalled();
+        // Client should only get the new event
+        assertThat((int) callback.getLastCarPropertyValue(CUSTOM_SEAT_INT_PROP_1).getValue())
+                .isEqualTo(3);
+        assertThat(callback.getEventCounter()).isEqualTo(1);
+
+    }
+
+    @Test
+    public void testOnChangeEventWithDifferentAreaId() throws Exception {
+        // init
+        mManager.setProperty(Integer.class,
+                CUSTOM_SEAT_INT_PROP_2, DRIVER_SIDE_AREA_ID, 1);
+        TestSequenceCallback callback = new TestSequenceCallback(2);
+        mManager.registerCallback(callback, CUSTOM_SEAT_INT_PROP_2, 0);
+        callback.assertRegisterCompleted();
+        VehiclePropValue fakeValueDriveSide = new VehiclePropValue();
+        fakeValueDriveSide.prop = CUSTOM_SEAT_INT_PROP_2;
+        fakeValueDriveSide.areaId = DRIVER_SIDE_AREA_ID;
+        fakeValueDriveSide.value.int32Values.add(4);
+        fakeValueDriveSide.timestamp = SystemClock.elapsedRealtimeNanos();
+
+        VehiclePropValue fakeValuePsgSide = new VehiclePropValue();
+        fakeValuePsgSide.prop = CUSTOM_SEAT_INT_PROP_2;
+        fakeValuePsgSide.areaId = PASSENGER_SIDE_AREA_ID;
+        fakeValuePsgSide.value.int32Values.add(5);
+        fakeValuePsgSide.timestamp = SystemClock.elapsedRealtimeNanos();
+
+        // inject passenger event before driver event
+        getMockedVehicleHal().injectEvent(fakeValuePsgSide);
+        getMockedVehicleHal().injectEvent(fakeValueDriveSide);
+        callback.assertOnChangeEventCalled();
+
+        // both events should be received by listener
+        assertThat((int) callback.getLastCarPropertyValue(CUSTOM_SEAT_INT_PROP_2).getValue())
+                .isEqualTo(4);
+        assertThat(callback.getEventCounter()).isEqualTo(2);
+    }
+
+    @Test
+    public void testUserHal_getProperty() {
+        userHalPropertiesTest("getProperty()", (prop) ->
+                mManager.getProperty(prop, /* areaId= */ 0));
+    }
+
+    @Test
+    public void testUserHal_getBooleanProperty() {
+        userHalPropertiesTest("getBooleanProperty()", (prop) ->
+                mManager.getBooleanProperty(prop, /* areaId= */ 0));
+    }
+
+    @Test
+    public void testUserHal_getIntProperty() {
+        userHalPropertiesTest("getIntProperty()", (prop) ->
+                mManager.getIntProperty(prop, /* areaId= */ 0));
+    }
+
+    @Test
+    public void testUserHal_getIntArrayProperty() {
+        userHalPropertiesTest("getIntArrayProperty()", (prop) ->
+                mManager.getIntArrayProperty(prop, /* areaId= */ 0));
+    }
+
+    @Test
+    public void testUserHal_getFloatProperty() {
+        userHalPropertiesTest("getFloatProperty()", (prop) ->
+                mManager.getFloatProperty(prop, /* areaId= */ 0));
+    }
+
+    @Test
+    public void testUserHal_getPropertyList() {
+        userHalPropertiesTest("getPropertyList()", (prop) -> {
+            ArraySet<Integer> list = new ArraySet<>();
+            list.add(prop);
+            mManager.getPropertyList(list);
+        });
+    }
+
+    @Test
+    public void testUserHal_getCarPropertyConfig() {
+        userHalPropertiesTest("getCarPropertyConfig()", (prop) ->
+                mManager.getCarPropertyConfig(prop));
+    }
+
+    @Test
+    public void testUserHal_getAreaId() {
+        userHalPropertiesTest("getAreaId()", (prop) ->
+                mManager.getAreaId(prop, /* areaId= */ 0));
+    }
+
+    @Test
+    public void testUserHal_getReadPermission() {
+        userHalPropertiesTest("getReadPermission()", (prop) ->
+                mManager.getReadPermission(prop));
+    }
+
+    @Test
+    public void testUserHal_getWritePermission() {
+        userHalPropertiesTest("getWritePermission()", (prop) ->
+                mManager.getWritePermission(prop));
+    }
+
+    @Test
+    public void testUserHal_isPropertyAvailable() {
+        userHalPropertiesTest("isPropertyAvailable()", (prop) ->
+                mManager.isPropertyAvailable(prop, /* area= */ 0));
+    }
+
+    @Test
+    public void testUserHal_setProperty() {
+        userHalPropertiesTest("setProperty()", (prop) ->
+                mManager.setProperty(Object.class, prop, /* areaId= */ 0, /* val= */ null));
+    }
+
+    @Test
+    public void testUserHal_setBooleanProperty() {
+        userHalPropertiesTest("setBooleanProperty()", (prop) ->
+                mManager.setBooleanProperty(prop, /* areaId= */ 0, /* val= */ true));
+    }
+
+    @Test
+    public void testUserHal_setFloatProperty() {
+        userHalPropertiesTest("setFloatProperty()", (prop) ->
+                mManager.setFloatProperty(prop, /* areaId= */ 0, /* val= */ 0.0F));
+    }
+
+    @Test
+    public void testUserHal_setIntProperty() {
+        userHalPropertiesTest("setIntProperty()", (prop) ->
+                mManager.setIntProperty(prop, /* areaId= */ 0, /* val= */ 0));
+    }
+
+    private void userHalPropertiesTest(String method, Visitor<Integer> visitor) {
+        List<String> failedProperties = new ArrayList<String>();
+        for (int propertyId : USER_HAL_PROPERTIES) {
+            try {
+                visitor.visit(propertyId);
+                failedProperties.add(propToString(propertyId));
+            } catch (IllegalArgumentException e) {
+                // expected
+            }
+        }
+        if (!failedProperties.isEmpty()) {
+            fail(method + " should not support these properties: " + failedProperties);
+        }
+    }
+
+    @Override
+    protected synchronized void configureMockedHal() {
+        PropertyHandler handler = new PropertyHandler();
+        addProperty(CUSTOM_SEAT_MIXED_PROP_ID_1, handler).setConfigArray(CONFIG_ARRAY_1)
+                .addAreaConfig(DRIVER_SIDE_AREA_ID).addAreaConfig(PASSENGER_SIDE_AREA_ID);
+        addProperty(CUSTOM_GLOBAL_MIXED_PROP_ID_2, handler).setConfigArray(CONFIG_ARRAY_2);
+        addProperty(CUSTOM_GLOBAL_INT_ARRAY_PROP, handler);
+
+        VehiclePropValue tempValue = new VehiclePropValue();
+        tempValue.value.floatValues.add(INIT_TEMP_VALUE);
+        tempValue.prop = VehiclePropertyIds.HVAC_TEMPERATURE_SET;
+        addProperty(VehiclePropertyIds.HVAC_TEMPERATURE_SET, tempValue)
+                .addAreaConfig(DRIVER_SIDE_AREA_ID).addAreaConfig(PASSENGER_SIDE_AREA_ID);
+        addProperty(VehiclePropertyIds.INFO_VIN);
+
+        addProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED, handler);
+        addProperty(PROP_CAUSE_STATUS_CODE_TRY_AGAIN, handler);
+        addProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR, handler);
+        addProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG, handler);
+        addProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE, handler);
+
+        addProperty(CUSTOM_SEAT_INT_PROP_1, handler).addAreaConfig(DRIVER_SIDE_AREA_ID)
+                                                        .addAreaConfig(PASSENGER_SIDE_AREA_ID);
+        addProperty(CUSTOM_SEAT_INT_PROP_2, handler).addAreaConfig(DRIVER_SIDE_AREA_ID)
+                                                        .addAreaConfig(PASSENGER_SIDE_AREA_ID);
+    }
+
+    private class PropertyHandler implements VehicleHalPropertyHandler {
+        HashMap<Integer, VehiclePropValue> mMap = new HashMap<>();
+        @Override
+        public synchronized void onPropertySet(VehiclePropValue value) {
+            // Simulate HalClient.set() behavior.
+            int statusCode = mapPropertyToStatusCode(value.prop);
+            if (statusCode == VehicleHalStatusCode.STATUS_INVALID_ARG) {
+                throw new IllegalArgumentException();
+            }
+
+            if (statusCode != VehicleHalStatusCode.STATUS_OK) {
+                throw new ServiceSpecificException(statusCode);
+            }
+
+            mMap.put(value.prop, value);
+        }
+
+        @Override
+        public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) {
+            // Simulate HalClient.get() behavior.
+            int statusCode = mapPropertyToStatusCode(value.prop);
+            if (statusCode == VehicleHalStatusCode.STATUS_INVALID_ARG) {
+                throw new IllegalArgumentException();
+            }
+
+            if (statusCode != VehicleHalStatusCode.STATUS_OK) {
+                throw new ServiceSpecificException(statusCode);
+            }
+
+            VehiclePropValue currentValue = mMap.get(value.prop);
+            return currentValue != null ? currentValue : value;
+        }
+
+        @Override
+        public synchronized void onPropertySubscribe(int property, float sampleRate) {
+            Log.d(TAG, "onPropertySubscribe property "
+                    + property + " sampleRate " + sampleRate);
+        }
+
+        @Override
+        public synchronized void onPropertyUnsubscribe(int property) {
+            Log.d(TAG, "onPropertyUnSubscribe property " + property);
+        }
+    }
+
+    private static String propToString(int propertyId) {
+        return VehiclePropertyIds.toString(propertyId) + " (" + propertyId + ")";
+    }
+
+    private static int mapPropertyToStatusCode(int propId) {
+        switch (propId) {
+            case PROP_CAUSE_STATUS_CODE_TRY_AGAIN:
+                return VehicleHalStatusCode.STATUS_TRY_AGAIN;
+            case PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE:
+                return VehicleHalStatusCode.STATUS_NOT_AVAILABLE;
+            case PROP_CAUSE_STATUS_CODE_ACCESS_DENIED:
+                return VehicleHalStatusCode.STATUS_ACCESS_DENIED;
+            case PROP_CAUSE_STATUS_CODE_INVALID_ARG:
+                return VehicleHalStatusCode.STATUS_INVALID_ARG;
+            case PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR:
+                return VehicleHalStatusCode.STATUS_INTERNAL_ERROR;
+            default:
+                return VehicleHalStatusCode.STATUS_OK;
+        }
+    }
+
+    private static class TestErrorCallback implements CarPropertyManager.CarPropertyEventCallback {
+
+        private static final String CALLBACK_TAG = "ErrorEventTest";
+        private boolean mReceivedErrorEventWithErrorCode = false;
+        private boolean mReceivedErrorEventWithOutErrorCode = false;
+        private int mErrorCode;
+        private final CountDownLatch mEventsCountDownLatch = new CountDownLatch(1);
+        private final CountDownLatch mRegisterCountDownLatch = new CountDownLatch(2);
+        @Override
+        public void onChangeEvent(CarPropertyValue value) {
+            Log.d(CALLBACK_TAG, "onChangeEvent: " + value);
+            mRegisterCountDownLatch.countDown();
+        }
+
+        @Override
+        public void onErrorEvent(int propId, int zone) {
+            mReceivedErrorEventWithOutErrorCode = true;
+            Log.d(CALLBACK_TAG, "onErrorEvent, propId: " + propId + " zone: " + zone);
+            mEventsCountDownLatch.countDown();
+        }
+
+        @Override
+        public void onErrorEvent(int propId, int areaId, int errorCode) {
+            mReceivedErrorEventWithErrorCode = true;
+            mErrorCode = errorCode;
+            Log.d(CALLBACK_TAG, "onErrorEvent, propId: " + propId + " areaId: " + areaId
+                    + "errorCode: " + errorCode);
+            mEventsCountDownLatch.countDown();
+        }
+
+        public void assertOnErrorEventCalled() throws InterruptedException {
+            if (!mEventsCountDownLatch.await(CALLBACK_SHORT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                throw new IllegalStateException("Callback is not called in "
+                        + CALLBACK_SHORT_TIMEOUT_MS + " ms.");
+            }
+        }
+
+        public void assertOnErrorEventNotCalled() throws InterruptedException {
+            if (mEventsCountDownLatch.await(CALLBACK_SHORT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                throw new IllegalStateException("Callback is called in " + CALLBACK_SHORT_TIMEOUT_MS
+                        + " ms.");
+            }
+        }
+
+        public void assertRegisterCompleted() throws InterruptedException {
+            if (!mRegisterCountDownLatch.await(CALLBACK_SHORT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                throw new IllegalStateException("Register failed in " + CALLBACK_SHORT_TIMEOUT_MS
+                        + " ms.");
+            }
+        }
+    }
+
+    private class TestSequenceCallback implements CarPropertyManager.CarPropertyEventCallback {
+
+        private ConcurrentHashMap<Integer, CarPropertyValue> mRecorder = new ConcurrentHashMap<>();
+        private int mCounter = 0;
+        private final CountDownLatch mEventsCountDownLatch;
+        private final CountDownLatch mRegisterCountDownLatch = new CountDownLatch(2);
+        @Override
+        public void onChangeEvent(CarPropertyValue value) {
+            Log.e(TAG, "onChanged get a event " + value);
+            mRecorder.put(value.getPropertyId(), value);
+            mRegisterCountDownLatch.countDown();
+            // Skip initial events
+            if (value.getTimestamp() != 0) {
+                mCounter++;
+                mEventsCountDownLatch.countDown();
+            }
+        }
+
+        TestSequenceCallback(int expectedTimes) {
+            mEventsCountDownLatch = new CountDownLatch(expectedTimes);
+        }
+
+        @Override
+        public void onErrorEvent(int properId, int zone) {
+            Log.e(TAG, "TestSequenceCallback get an onErrorEvent");
+        }
+
+        public CarPropertyValue getLastCarPropertyValue(int propId) {
+            return mRecorder.get(propId);
+        }
+
+        public int getEventCounter() {
+            return mCounter;
+        }
+
+        public void assertOnChangeEventCalled() throws InterruptedException {
+            if (!mEventsCountDownLatch.await(CALLBACK_SHORT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                throw new IllegalStateException("Callback is not called in "
+                        + CALLBACK_SHORT_TIMEOUT_MS + " ms.");
+            }
+        }
+
+        public void assertRegisterCompleted() throws InterruptedException {
+            if (!mRegisterCountDownLatch.await(CALLBACK_SHORT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                throw new IllegalStateException("Register failed in " + CALLBACK_SHORT_TIMEOUT_MS
+                        + " ms.");
+            }
+        }
+    }
+
+}
diff --git a/tests/carservice_test/src/com/android/car/CarPropertyServiceTest.java b/tests/carservice_test/src/com/android/car/CarPropertyServiceTest.java
new file mode 100644
index 0000000..0dbe369
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/CarPropertyServiceTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.verify;
+
+import static java.lang.Integer.toHexString;
+
+import android.hardware.automotive.vehicle.V2_0.VehicleGear;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
+import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
+import android.os.SystemClock;
+import android.util.Log;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import com.android.car.vehiclehal.VehiclePropValueBuilder;
+import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Test for {@link com.android.car.CarPropertyService}
+ */
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class CarPropertyServiceTest extends MockedCarTestBase {
+    private static final String TAG = CarPropertyServiceTest.class.getSimpleName();
+
+    private final Map<Integer, VehiclePropValue> mDefaultPropValues = new HashMap<>();
+
+    private CarPropertyService mService;
+
+    public CarPropertyServiceTest() {
+        // Unusual default values for the vehicle properties registered to listen via
+        // CarPropertyService.registerListener. Unusual default values like the car is in motion,
+        // night mode is on, or the car is low on fuel.
+        mDefaultPropValues.put(VehicleProperty.GEAR_SELECTION,
+                VehiclePropValueBuilder.newBuilder(VehicleProperty.GEAR_SELECTION)
+                .addIntValue(VehicleGear.GEAR_DRIVE)
+                .setTimestamp(SystemClock.elapsedRealtimeNanos()).build());
+        mDefaultPropValues.put(VehicleProperty.PARKING_BRAKE_ON,
+                VehiclePropValueBuilder.newBuilder(VehicleProperty.PARKING_BRAKE_ON)
+                .setBooleanValue(false)
+                .setTimestamp(SystemClock.elapsedRealtimeNanos()).build());
+        mDefaultPropValues.put(VehicleProperty.PERF_VEHICLE_SPEED,
+                VehiclePropValueBuilder.newBuilder(VehicleProperty.PERF_VEHICLE_SPEED)
+                .addFloatValue(30.0f)
+                .setTimestamp(SystemClock.elapsedRealtimeNanos()).build());
+        mDefaultPropValues.put(VehicleProperty.NIGHT_MODE,
+                VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE)
+                .setBooleanValue(true)
+                .setTimestamp(SystemClock.elapsedRealtimeNanos()).build());
+    }
+
+    @Override
+    protected synchronized void configureMockedHal() {
+        PropertyHandler handler = new PropertyHandler();
+        for (VehiclePropValue value : mDefaultPropValues.values()) {
+            handler.onPropertySet(value);
+            addProperty(value.prop, handler);
+        }
+    }
+
+    @Override
+    protected synchronized void spyOnBeforeCarImplInit() {
+        mService = getCarPropertyService();
+        assertThat(mService).isNotNull();
+        spyOn(mService);
+    }
+
+    @Test
+    public void testMatchesDefaultPropertyValues() {
+        Set<Integer> expectedPropIds = mDefaultPropValues.keySet();
+        ArgumentCaptor<Integer> propIdCaptor = ArgumentCaptor.forClass(Integer.class);
+        verify(mService, atLeast(expectedPropIds.size())).registerListener(
+                propIdCaptor.capture(), anyFloat(), any());
+
+        Set<Integer> actualPropIds = new HashSet<Integer>(propIdCaptor.getAllValues());
+        assertWithMessage("Should assign default values for missing property IDs")
+                .that(expectedPropIds).containsAllIn(actualPropIds.toArray());
+        assertWithMessage("Missing registerListener for property IDs")
+                .that(actualPropIds).containsAllIn(expectedPropIds.toArray());
+    }
+
+    private static final class PropertyHandler implements VehicleHalPropertyHandler {
+        private final Map<Integer, VehiclePropValue> mMap = new HashMap<>();
+
+        @Override
+        public synchronized void onPropertySet(VehiclePropValue value) {
+            mMap.put(value.prop, value);
+        }
+
+        @Override
+        public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) {
+            assertWithMessage("onPropertyGet missing property: %s", toHexString(value.prop))
+                    .that(mMap).containsKey(value.prop);
+            VehiclePropValue currentValue = mMap.get(value.prop);
+            return currentValue != null ? currentValue : value;
+        }
+
+        @Override
+        public synchronized void onPropertySubscribe(int property, float sampleRate) {
+            assertWithMessage("onPropertySubscribe missing property: %s", toHexString(property))
+                    .that(mMap).containsKey(property);
+            Log.d(TAG, "onPropertySubscribe property "
+                    + property + " sampleRate " + sampleRate);
+        }
+
+        @Override
+        public synchronized void onPropertyUnsubscribe(int property) {
+            assertWithMessage("onPropertyUnsubscribe missing property: %s", toHexString(property))
+                    .that(mMap).containsKey(property);
+            Log.d(TAG, "onPropertyUnSubscribe property " + property);
+        }
+    }
+}
diff --git a/tests/carservice_test/src/com/android/car/CarSensorManagerTest.java b/tests/carservice_test/src/com/android/car/CarSensorManagerTest.java
index 5bc2c28..11bd3a9 100644
--- a/tests/carservice_test/src/com/android/car/CarSensorManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarSensorManagerTest.java
@@ -29,16 +29,20 @@
 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
 import android.os.SystemClock;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
 import com.android.car.vehiclehal.VehiclePropValueBuilder;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test the public entry points for the CarSensorManager
  */
+@RunWith(AndroidJUnit4.class)
 @MediumTest
 public class CarSensorManagerTest extends MockedCarTestBase {
     private static final String TAG = CarSensorManagerTest.class.getSimpleName();
@@ -146,12 +150,12 @@
         // Set up our listener callback
         SensorListener listener = new SensorListener();
         mCarSensorManager.registerListener(listener,
-                CarSensorManager.SENSOR_TYPE_NIGHT,
+                CarSensorManager.SENSOR_TYPE_PARKING_BRAKE,
                 CarSensorManager.SENSOR_RATE_FASTEST);
 
         VehiclePropValue value;
         CarSensorEvent event;
-        CarSensorEvent.NightData data = null;
+        CarSensorEvent.ParkingBrakeData data = null;
 
         // Clear event generated by registerCallback()
         listener.waitForSensorChange();
@@ -159,56 +163,58 @@
 
         // Set the value TRUE and wait for the event to arrive
         getMockedVehicleHal().injectEvent(
-                VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE)
+                VehiclePropValueBuilder.newBuilder(VehicleProperty.PARKING_BRAKE_ON)
                         .setBooleanValue(true)
                         .setTimestamp(51L)
                         .build(), true);
         assertTrue(listener.waitForSensorChange(51L));
 
         // Ensure we got the expected event
-        assertEquals(listener.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT);
+        assertEquals(listener.getLastEvent().sensorType,
+                CarSensorManager.SENSOR_TYPE_PARKING_BRAKE);
 
         // Ensure we got the expected value in our callback
-        data = listener.getLastEvent().getNightData(data);
-        Log.d(TAG, "NightMode " + data.isNightMode + " at " + data.timestamp);
-        assertTrue(data.isNightMode);
+        data = listener.getLastEvent().getParkingBrakeData(data);
+        Log.d(TAG, "Parking: " + data.isEngaged + " at " + data.timestamp);
+        assertTrue(data.isEngaged);
 
         // Ensure we have the expected value in the sensor manager's cache
-        event = mCarSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT);
+        event = mCarSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_PARKING_BRAKE);
         assertNotNull(event);
-        data = event.getNightData(data);
+        data = event.getParkingBrakeData(data);
         assertEquals("Unexpected event timestamp", data.timestamp, 51);
-        assertTrue("Unexpected value", data.isNightMode);
+        assertTrue("Unexpected value", data.isEngaged);
 
         listener.reset();
         // Set the value FALSE
         getMockedVehicleHal().injectEvent(
-                VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE)
+                VehiclePropValueBuilder.newBuilder(VehicleProperty.PARKING_BRAKE_ON)
                         .setTimestamp(1001)
                         .setBooleanValue(false)
                         .build(), true);
         assertTrue(listener.waitForSensorChange(1001));
 
         // Ensure we got the expected event
-        assertEquals(listener.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT);
+        assertEquals(listener.getLastEvent().sensorType,
+                CarSensorManager.SENSOR_TYPE_PARKING_BRAKE);
 
         // Ensure we got the expected value in our callback
-        data = listener.getLastEvent().getNightData(data);
+        data = listener.getLastEvent().getParkingBrakeData(data);
         assertEquals("Unexpected event timestamp", 1001, data.timestamp);
-        assertFalse("Unexpected value", data.isNightMode);
+        assertFalse("Unexpected value", data.isEngaged);
 
         // Ensure we have the expected value in the sensor manager's cache
-        event = mCarSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT);
+        event = mCarSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_PARKING_BRAKE);
         assertNotNull(event);
-        data = event.getNightData(data);
-        assertFalse(data.isNightMode);
+        data = event.getParkingBrakeData(data);
+        assertFalse(data.isEngaged);
 
         // Unregister our handler (from all sensor types)
         mCarSensorManager.unregisterListener(listener);
 
         listener.reset();
         // Set the value TRUE again
-        value = VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE)
+        value = VehiclePropValueBuilder.newBuilder(VehicleProperty.PARKING_BRAKE_ON)
                 .setTimestamp(2001)
                 .setBooleanValue(true)
                 .build();
@@ -219,11 +225,11 @@
         assertFalse(listener.waitForSensorChange(2001));
 
         // Despite us not having a callback registered, the Sensor Manager should see the update
-        event = mCarSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT);
+        event = mCarSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_PARKING_BRAKE);
         assertNotNull(event);
-        data = event.getNightData(data);
+        data = event.getParkingBrakeData(data);
         assertEquals("Unexpected event timestamp", data.timestamp, 2001);
-        assertTrue("Unexpected value", data.isNightMode);
+        assertTrue("Unexpected value", data.isEngaged);
     }
 
     @Test
@@ -335,18 +341,18 @@
         SensorListener listener3 = new SensorListener();
 
         mCarSensorManager.registerListener(listener1,
-                CarSensorManager.SENSOR_TYPE_NIGHT,
+                CarSensorManager.SENSOR_TYPE_PARKING_BRAKE,
                 CarSensorManager.SENSOR_RATE_NORMAL);
 
         mCarSensorManager.registerListener(listener2,
-                CarSensorManager.SENSOR_TYPE_NIGHT,
+                CarSensorManager.SENSOR_TYPE_PARKING_BRAKE,
                 CarSensorManager.SENSOR_RATE_NORMAL);
 
         mCarSensorManager.registerListener(listener3,
-                CarSensorManager.SENSOR_TYPE_NIGHT,
+                CarSensorManager.SENSOR_TYPE_PARKING_BRAKE,
                 CarSensorManager.SENSOR_RATE_FASTEST);
 
-        CarSensorEvent.NightData data = null;
+        CarSensorEvent.ParkingBrakeData data = null;
         VehiclePropValue value;
         CarSensorEvent event;
 
@@ -359,7 +365,7 @@
         listener3.reset();
 
         // Set the value TRUE and wait for the event to arrive
-        value = VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE)
+        value = VehiclePropValueBuilder.newBuilder(VehicleProperty.PARKING_BRAKE_ON)
                 .setTimestamp(1001L)
                 .setBooleanValue(true)
                 .build();
@@ -370,34 +376,37 @@
         assertTrue(listener3.waitForSensorChange(1001L));
 
         // Ensure we got the expected event
-        assertEquals(listener1.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT);
-        assertEquals(listener2.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT);
-        assertEquals(listener3.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT);
+        assertEquals(listener1.getLastEvent().sensorType,
+                CarSensorManager.SENSOR_TYPE_PARKING_BRAKE);
+        assertEquals(listener2.getLastEvent().sensorType,
+                CarSensorManager.SENSOR_TYPE_PARKING_BRAKE);
+        assertEquals(listener3.getLastEvent().sensorType,
+                CarSensorManager.SENSOR_TYPE_PARKING_BRAKE);
 
         // Ensure we got the expected value in our callback
-        data = listener1.getLastEvent().getNightData(data);
-        Log.d(TAG, "NightMode " + data.isNightMode + " at " + data.timestamp);
-        assertTrue(data.isNightMode);
+        data = listener1.getLastEvent().getParkingBrakeData(data);
+        Log.d(TAG, "Parking brake is " + data.isEngaged + " at " + data.timestamp);
+        assertTrue(data.isEngaged);
 
-        data = listener2.getLastEvent().getNightData(data);
-        Log.d(TAG, "NightMode " + data.isNightMode + " at " + data.timestamp);
-        assertTrue(data.isNightMode);
+        data = listener2.getLastEvent().getParkingBrakeData(data);
+        Log.d(TAG, "Parking brake is " + data.isEngaged + " at " + data.timestamp);
+        assertTrue(data.isEngaged);
 
-        data = listener3.getLastEvent().getNightData(data);
-        Log.d(TAG, "NightMode " + data.isNightMode + " at " + data.timestamp);
-        assertTrue(data.isNightMode);
+        data = listener3.getLastEvent().getParkingBrakeData(data);
+        Log.d(TAG, "Parking brake is" + data.isEngaged + " at " + data.timestamp);
+        assertTrue(data.isEngaged);
 
         // Ensure we have the expected value in the sensor manager's cache
-        event = mCarSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT);
-        data = event.getNightData(data);
+        event = mCarSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_PARKING_BRAKE);
+        data = event.getParkingBrakeData(data);
         assertEquals("Unexpected event timestamp", 1001, data.timestamp);
-        assertTrue("Unexpected value", data.isNightMode);
+        assertTrue("Unexpected value", data.isEngaged);
 
         listener1.reset();
         listener2.reset();
         listener3.reset();
         // Set the value FALSE
-        value = VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE)
+        value = VehiclePropValueBuilder.newBuilder(VehicleProperty.PARKING_BRAKE_ON)
                 .setTimestamp(2001)
                 .setBooleanValue(false)
                 .build();
@@ -407,27 +416,30 @@
         assertTrue(listener3.waitForSensorChange(2001));
 
         // Ensure we got the expected event
-        assertEquals(listener1.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT);
-        assertEquals(listener2.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT);
-        assertEquals(listener3.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT);
+        assertEquals(listener1.getLastEvent().sensorType,
+                CarSensorManager.SENSOR_TYPE_PARKING_BRAKE);
+        assertEquals(listener2.getLastEvent().sensorType,
+                CarSensorManager.SENSOR_TYPE_PARKING_BRAKE);
+        assertEquals(listener3.getLastEvent().sensorType,
+                CarSensorManager.SENSOR_TYPE_PARKING_BRAKE);
 
         // Ensure we got the expected value in our callback
-        data = listener1.getLastEvent().getNightData(data);
+        data = listener1.getLastEvent().getParkingBrakeData(data);
         assertEquals("Unexpected event timestamp", 2001, data.timestamp);
-        assertFalse("Unexpected value", data.isNightMode);
+        assertFalse("Unexpected value", data.isEngaged);
 
-        data = listener2.getLastEvent().getNightData(data);
+        data = listener2.getLastEvent().getParkingBrakeData(data);
         assertEquals("Unexpected event timestamp", 2001, data.timestamp);
-        assertFalse("Unexpected value", data.isNightMode);
+        assertFalse("Unexpected value", data.isEngaged);
 
-        data = listener3.getLastEvent().getNightData(data);
+        data = listener3.getLastEvent().getParkingBrakeData(data);
         assertEquals("Unexpected event timestamp", 2001, data.timestamp);
-        assertFalse("Unexpected value", data.isNightMode);
+        assertFalse("Unexpected value", data.isEngaged);
 
         // Ensure we have the expected value in the sensor manager's cache
-        event = mCarSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT);
-        data = event.getNightData(data);
-        assertFalse(data.isNightMode);
+        event = mCarSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_PARKING_BRAKE);
+        data = event.getParkingBrakeData(data);
+        assertFalse(data.isEngaged);
 
         Log.d(TAG, "Unregistering listener3");
         listener1.reset();
@@ -435,7 +447,7 @@
         listener3.reset();
         mCarSensorManager.unregisterListener(listener3);
         Log.d(TAG, "Rate changed - expect sensor restart and change event sent.");
-        value = VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE)
+        value = VehiclePropValueBuilder.newBuilder(VehicleProperty.PARKING_BRAKE_ON)
                 .setTimestamp(3002)
                 .setBooleanValue(false)
                 .build();
@@ -447,7 +459,7 @@
         listener2.reset();
         listener3.reset();
         // Set the value TRUE again
-        value = VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE)
+        value = VehiclePropValueBuilder.newBuilder(VehicleProperty.PARKING_BRAKE_ON)
                 .setTimestamp()
                 .setBooleanValue(true)
                 .build();
diff --git a/tests/carservice_test/src/com/android/car/CarStorageMonitoringTest.java b/tests/carservice_test/src/com/android/car/CarStorageMonitoringTest.java
index 61c23a0..7fb9066 100644
--- a/tests/carservice_test/src/com/android/car/CarStorageMonitoringTest.java
+++ b/tests/carservice_test/src/com/android/car/CarStorageMonitoringTest.java
@@ -21,10 +21,10 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
-import static org.mockito.Mockito.doNothing;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.car.Car;
 import android.car.storagemonitoring.CarStorageMonitoringManager;
 import android.car.storagemonitoring.IoStats;
@@ -33,6 +33,7 @@
 import android.car.storagemonitoring.UidIoRecord;
 import android.car.storagemonitoring.WearEstimate;
 import android.car.storagemonitoring.WearEstimateChange;
+import android.content.Context;
 import android.content.Intent;
 import android.os.SystemClock;
 import android.util.JsonWriter;
@@ -40,8 +41,8 @@
 import android.util.Pair;
 import android.util.SparseArray;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.car.storagemonitoring.LifetimeWriteInfoProvider;
 import com.android.car.storagemonitoring.UidIoStatsProvider;
@@ -58,7 +59,6 @@
 import org.junit.Test;
 import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
 
 import java.io.File;
 import java.io.FileWriter;
@@ -308,8 +308,10 @@
 
     private CarStorageMonitoringManager mCarStorageMonitoringManager;
 
-    private ArgumentCaptor<Intent> mBroadcastIntentArg = ArgumentCaptor.forClass(Intent.class);
-    private ArgumentCaptor<String> mBroadcastStringArg = ArgumentCaptor.forClass(String.class);
+    @Override
+    protected MockedCarTestContext createMockedCarTestContext(Context context) {
+        return new CarStorageMonitoringTestContext(context);
+    }
 
     @Override
     protected synchronized SystemInterface.Builder getSystemInterfaceBuilder() {
@@ -371,6 +373,8 @@
     @Override
     protected synchronized void configureResourceOverrides(MockResources resources) {
         super.configureResourceOverrides(resources);
+        resources.overrideResource(com.android.car.R.array.config_allowed_optional_car_features,
+                new String[] {Car.STORAGE_MONITORING_SERVICE});
         final ResourceOverrides overrides = PER_TEST_RESOURCES.getOrDefault(getName(), null);
         if (overrides != null) {
             overrides.overrideResources(resources);
@@ -380,10 +384,7 @@
     @Override
     public void setUp() throws Exception {
         super.setUp();
-        doNothing().when(getCarServiceContext()).sendBroadcast(mBroadcastIntentArg.capture(),
-                mBroadcastStringArg.capture());
         mMockSystemStateInterface.executeBootCompletedActions();
-
         mCarStorageMonitoringManager =
             (CarStorageMonitoringManager) getCar().getCarManager(Car.STORAGE_MONITORING_SERVICE);
     }
@@ -654,7 +655,9 @@
         mMockStorageMonitoringInterface.addIoStatsRecord(record);
         mMockTimeInterface.setUptime(500).tick();
 
-        assertBroadcastArgs(mBroadcastIntentArg.getValue(), mBroadcastStringArg.getValue());
+        CarStorageMonitoringTestContext context = (CarStorageMonitoringTestContext) getContext();
+        assertBroadcastArgs(context.getLastBroadcastedIntent(),
+                context.getLastBroadcastedString());
     }
 
     @Test
@@ -676,7 +679,9 @@
         mMockStorageMonitoringInterface.addIoStatsRecord(record);
         mMockTimeInterface.setUptime(500).tick();
 
-        assertBroadcastArgs(mBroadcastIntentArg.getValue(), mBroadcastStringArg.getValue());
+        CarStorageMonitoringTestContext context = (CarStorageMonitoringTestContext) getContext();
+        assertBroadcastArgs(context.getLastBroadcastedIntent(),
+                context.getLastBroadcastedString());
     }
 
     @Test
@@ -771,6 +776,35 @@
 
     }
 
+    /**
+     * Special version of {@link MockedCarTestContext} that stores the last arguments used when
+     * invoking {@method sendBroadcast(Intent, String)} to be retrieved later by the test.
+     */
+    private class CarStorageMonitoringTestContext extends MockedCarTestContext {
+        private Intent mLastBroadcastedIntent;
+        private String mLastBroadcastedString;
+
+        CarStorageMonitoringTestContext(Context base) {
+            super(base);
+        }
+
+        @Override
+        public void sendBroadcast(@RequiresPermission Intent intent,
+                @Nullable String receiverPermission) {
+            mLastBroadcastedIntent = intent;
+            mLastBroadcastedString = receiverPermission;
+            super.sendBroadcast(intent, receiverPermission);
+        }
+
+        Intent getLastBroadcastedIntent() {
+            return mLastBroadcastedIntent;
+        }
+
+        String getLastBroadcastedString() {
+            return mLastBroadcastedString;
+        }
+    }
+
     static final class MockStorageMonitoringInterface implements StorageMonitoringInterface,
         WearInformationProvider {
         private WearInformation mWearInformation = null;
diff --git a/tests/carservice_test/src/com/android/car/CarUxRestrictionsConfigurationXmlParserTest.java b/tests/carservice_test/src/com/android/car/CarUxRestrictionsConfigurationXmlParserTest.java
index bb3c7bf..a6b3fe1 100644
--- a/tests/carservice_test/src/com/android/car/CarUxRestrictionsConfigurationXmlParserTest.java
+++ b/tests/carservice_test/src/com/android/car/CarUxRestrictionsConfigurationXmlParserTest.java
@@ -29,9 +29,9 @@
 import android.content.Context;
 import android.util.ArraySet;
 
-import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -48,7 +48,7 @@
     private static final String UX_RESTRICTION_MODE_PASSENGER = "passenger";
 
     private Context getContext() {
-        return InstrumentationRegistry.getTargetContext();
+        return InstrumentationRegistry.getInstrumentation().getTargetContext();
     }
 
     @Test
diff --git a/tests/carservice_test/src/com/android/car/CarUxRestrictionsManagerServiceTest.java b/tests/carservice_test/src/com/android/car/CarUxRestrictionsManagerServiceTest.java
index 0b77d8e..7890d5a 100644
--- a/tests/carservice_test/src/com/android/car/CarUxRestrictionsManagerServiceTest.java
+++ b/tests/carservice_test/src/com/android/car/CarUxRestrictionsManagerServiceTest.java
@@ -22,6 +22,9 @@
 import static android.car.drivingstate.CarUxRestrictions.UX_RESTRICTIONS_BASELINE;
 import static android.car.drivingstate.CarUxRestrictionsManager.UX_RESTRICTION_MODE_BASELINE;
 
+import static androidx.test.InstrumentationRegistry.getContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
 import static com.android.car.CarUxRestrictionsManagerService.CONFIG_FILENAME_PRODUCTION;
 import static com.android.car.CarUxRestrictionsManagerService.CONFIG_FILENAME_STAGED;
 
@@ -35,6 +38,7 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
+import android.car.Car;
 import android.car.VehiclePropertyIds;
 import android.car.drivingstate.CarDrivingStateEvent;
 import android.car.drivingstate.CarUxRestrictions;
@@ -44,13 +48,19 @@
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.property.CarPropertyEvent;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.os.IBinder;
+import android.os.IRemoteCallback;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.JsonWriter;
+import android.view.Display;
+import android.view.DisplayAddress;
 
-import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.MediumTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -59,10 +69,12 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.File;
@@ -72,24 +84,40 @@
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 @RunWith(AndroidJUnit4.class)
 @MediumTest
 public class CarUxRestrictionsManagerServiceTest {
 
     private static final String UX_RESTRICTION_MODE_PASSENGER = "passenger";
+    private static final long TEST_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5);
 
     private CarUxRestrictionsManagerService mService;
 
+    @Rule
+    public final MockitoRule rule = MockitoJUnit.rule();
+
     @Mock
     private CarDrivingStateService mMockDrivingStateService;
     @Mock
     private CarPropertyService mMockCarPropertyService;
     @Mock
     private SystemInterface mMockSystemInterface;
+    @Mock
+    private IBinder mIBinder;
+    @Mock
+    private IRemoteCallback mRemoteCallback;
+    @Mock
+    private DisplayManager mDisplayManager;
+    @Mock
+    private Display mDisplay0;
+    @Mock
+    private Display mDisplay1;
 
     private Context mSpyContext;
 
@@ -97,10 +125,9 @@
 
     @Before
     public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
+        when(mRemoteCallback.asBinder()).thenReturn(mIBinder);
         // Spy context because service needs to access xml resource during init.
-        mSpyContext = spy(InstrumentationRegistry.getTargetContext());
-
+        mSpyContext = spy(getInstrumentation().getTargetContext());
         CarLocalServices.removeServiceForTest(SystemInterface.class);
         CarLocalServices.addService(SystemInterface.class, mMockSystemInterface);
 
@@ -172,7 +199,7 @@
     @Test
     public void testLoadConfig_UseProdConfig() throws IOException {
         CarUxRestrictionsConfiguration expected = createEmptyConfig();
-        setupMockFile(CONFIG_FILENAME_PRODUCTION, expected);
+        setupMockFile(CONFIG_FILENAME_PRODUCTION, List.of(expected));
 
         CarUxRestrictionsConfiguration actual = mService.loadConfig().get(0);
 
@@ -248,7 +275,7 @@
     public void testLoadConfig_PromoteStagedFileWhenParked() throws Exception {
         CarUxRestrictionsConfiguration expected = createEmptyConfig();
         // Staged file contains actual config. Ignore prod since it should be overwritten by staged.
-        File staged = setupMockFile(CONFIG_FILENAME_STAGED, expected);
+        File staged = setupMockFile(CONFIG_FILENAME_STAGED, List.of(expected));
         // Set up temp file for prod to avoid polluting other tests.
         setupMockFile(CONFIG_FILENAME_PRODUCTION, null);
 
@@ -264,7 +291,7 @@
         CarUxRestrictionsConfiguration expected = createEmptyConfig();
         File staged = setupMockFile(CONFIG_FILENAME_STAGED, null);
         // Prod file contains actual config. Ignore staged since it should not be promoted.
-        setupMockFile(CONFIG_FILENAME_PRODUCTION, expected);
+        setupMockFile(CONFIG_FILENAME_PRODUCTION, List.of(expected));
 
         setUpMockDrivingState();
         CarUxRestrictionsConfiguration actual = mService.loadConfig().get(0);
@@ -301,7 +328,10 @@
     public void testGetCurrentUxRestrictions_UnknownDisplayId_ReturnsFullRestrictions()
             throws Exception {
         mService.init();
-        CarUxRestrictions restrictions = mService.getCurrentUxRestrictions(/* displayId= */ 10);
+        // there would never actually be a display id of 100,000 - this is just an example of an id
+        // that doesn't exist on the device
+        int unknownDisplayId = 100_000;
+        CarUxRestrictions restrictions = mService.getCurrentUxRestrictions(unknownDisplayId);
         CarUxRestrictions expected = new CarUxRestrictions.Builder(
                 /*reqOpt= */ true,
                 CarUxRestrictions.UX_RESTRICTIONS_FULLY_RESTRICTED,
@@ -309,6 +339,109 @@
         assertTrue(restrictions.toString(), expected.isSameRestrictions(restrictions));
     }
 
+    @Test
+    public void testGetCurrentUxRestrictions_UnreportedVirtualDisplay_UseDefaultDisplayRestriction()
+            throws Exception {
+        // Create a virtual display that will get registered with the DisplayManager used by UXRE
+        String virtualDisplayName = "virtual_display";
+        DisplayManager displayManager = getContext().getSystemService(DisplayManager.class);
+        VirtualDisplay virtualDisplay = displayManager.createVirtualDisplay(
+                virtualDisplayName, 10, 10, 10, null, 0);
+        int virtualDisplayId = virtualDisplay.getDisplay().getDisplayId();
+
+        // Setup restrictions on the default display only
+        int defaultPortRestrictions = CarUxRestrictions.UX_RESTRICTIONS_NO_KEYBOARD;
+        byte defaultPort = CarUxRestrictionsManagerService.getDefaultDisplayPhysicalPort(
+                displayManager);
+        CarUxRestrictionsConfiguration defaultPortConfig = createMovingConfig(defaultPort,
+                defaultPortRestrictions);
+        setupMockFile(CONFIG_FILENAME_PRODUCTION, List.of(defaultPortConfig));
+
+        // Trigger restrictions by entering driving state
+        mService.init();
+        mService.handleDrivingStateEventLocked(
+                new CarDrivingStateEvent(CarDrivingStateEvent.DRIVING_STATE_MOVING,
+                        SystemClock.elapsedRealtime()));
+
+        // Virtual display should have restrictions for default display
+        CarUxRestrictions restrictions = mService.getCurrentUxRestrictions(virtualDisplayId);
+        CarUxRestrictions expected = new CarUxRestrictions.Builder(
+                /*reqOpt= */ true,
+                defaultPortRestrictions,
+                SystemClock.elapsedRealtimeNanos()).build();
+        assertTrue(restrictions.toString(), expected.isSameRestrictions(restrictions));
+
+        virtualDisplay.release();
+    }
+
+    @Test
+    public void testGetCurrentUxRestrictions_ReportedVirtualDisplay_ReturnsRestrictionsForPort()
+            throws Exception {
+        // Create a virtual display that we own in this process
+        String virtualDisplayName = "virtual_display";
+        DisplayManager displayManager = getContext().getSystemService(DisplayManager.class);
+        VirtualDisplay virtualDisplay = displayManager.createVirtualDisplay(
+                virtualDisplayName, 10, 10, 10, null, 0);
+
+        // Mock displays on two different physical ports, where the virtual display is on the
+        // second port. Don't use the virtual displayId since we are mocking out all the id logic.
+        int displayIdForPhysicalPort1 = 0;
+        int displayIdForPhysicalPort2 = 1;
+        int virtualDisplayId = 2;
+        int physicalDisplayIdForVirtualDisplayId2 = displayIdForPhysicalPort2;
+        int physicalPortForFirstDisplay = 10;
+        int physicalPortForSecondDisplay = 11;
+        when(mSpyContext.getSystemService(DisplayManager.class)).thenReturn(mDisplayManager);
+        mockDisplay(mDisplayManager, mDisplay0, displayIdForPhysicalPort1,
+                physicalPortForFirstDisplay);
+        mockDisplay(mDisplayManager, mDisplay1, displayIdForPhysicalPort2,
+                physicalPortForSecondDisplay);
+        when(mDisplayManager.getDisplay(virtualDisplayId)).thenReturn(virtualDisplay.getDisplay());
+        when(mDisplayManager.getDisplays()).thenReturn(new Display[]{
+                mDisplay0,
+                mDisplay1,
+                virtualDisplay.getDisplay(),
+        });
+
+        // Setup different restrictions for each physical port
+        int port2Restrictions = CarUxRestrictions.UX_RESTRICTIONS_NO_KEYBOARD;
+        CarUxRestrictionsConfiguration defaultPortConfig = createMovingConfig(
+                (byte) physicalPortForFirstDisplay,
+                CarUxRestrictions.UX_RESTRICTIONS_NO_DIALPAD);
+        CarUxRestrictionsConfiguration port2Config = createMovingConfig(
+                (byte) physicalPortForSecondDisplay,
+                port2Restrictions);
+        setupMockFile(CONFIG_FILENAME_PRODUCTION, List.of(defaultPortConfig, port2Config));
+
+        // Enter driving state to trigger restrictions
+        mService = new CarUxRestrictionsManagerService(mSpyContext,
+                mMockDrivingStateService, mMockCarPropertyService);
+        mService.init();
+        // A CarActivityView would report this itself, but we fake the report here
+        mService.reportVirtualDisplayToPhysicalDisplay(mRemoteCallback, virtualDisplayId,
+                physicalDisplayIdForVirtualDisplayId2);
+        mService.handleDrivingStateEventLocked(
+                new CarDrivingStateEvent(CarDrivingStateEvent.DRIVING_STATE_MOVING,
+                        SystemClock.elapsedRealtime()));
+
+        // Virtual display should have restrictions for port2
+        CarUxRestrictions restrictions = mService.getCurrentUxRestrictions(virtualDisplayId);
+        CarUxRestrictions expected = new CarUxRestrictions.Builder(
+                /*reqOpt= */ true,
+                port2Restrictions,
+                SystemClock.elapsedRealtimeNanos()).build();
+        assertTrue(restrictions.toString(), expected.isSameRestrictions(restrictions));
+
+        virtualDisplay.release();
+    }
+
+    private void mockDisplay(DisplayManager displayManager, Display display, int displayId,
+            int portAddress) {
+        when(displayManager.getDisplay(displayId)).thenReturn(display);
+        when(display.getDisplayId()).thenReturn(displayId);
+        when(display.getAddress()).thenReturn(DisplayAddress.fromPhysicalDisplayId(portAddress));
+    }
+
     // This test only involves calling a few methods and should finish very quickly. If it doesn't
     // finish in 20s, we probably encountered a deadlock.
     @Test(timeout = 20000)
@@ -382,7 +515,7 @@
         // we manually trigger the event. This event is what eventually triggers the dispatch to
         // ICarDrivingStateChangeListener that was defined above.
         Runnable propertyChangeEventRunnable =
-                () -> drivingStateService.handlePropertyEvent(
+                () -> drivingStateService.handlePropertyEventLocked(
                         new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
                                 new CarPropertyValue<>(
                                         VehiclePropertyIds.PERF_VEHICLE_SPEED, 0, 100f)));
@@ -471,7 +604,7 @@
         // that CarUxRestrictionsManagerService internally made to CarDrivingStateService in
         // CarUxRestrictionsManagerService#init().
         Runnable propertyChangeEventRunnable =
-                () -> drivingStateService.handlePropertyEvent(
+                () -> drivingStateService.handlePropertyEventLocked(
                         new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
                                 new CarPropertyValue<>(
                                         VehiclePropertyIds.PERF_VEHICLE_SPEED, 0, 100f)));
@@ -500,6 +633,30 @@
         }
     }
 
+    @Test(expected = SecurityException.class)
+    public void testSetRestrictionMode_missingPermission_throwsException() throws Exception {
+        when(mSpyContext.checkCallingOrSelfPermission(
+                Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
+        mService.setRestrictionMode(UX_RESTRICTION_MODE_BASELINE);
+    }
+
+    @Test(expected = SecurityException.class)
+    public void testGetRestrictionMode_missingPermission_throwsException() throws Exception {
+        when(mSpyContext.checkCallingOrSelfPermission(
+                Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
+        mService.getRestrictionMode();
+    }
+
+    @Test(expected = SecurityException.class)
+    public void testSaveUxRestrictionsConfigurationForNextBoot_missingPermission_throwsException()
+            throws Exception {
+        when(mSpyContext.checkCallingOrSelfPermission(
+                Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
+        mService.saveUxRestrictionsConfigurationForNextBoot(new ArrayList<>());
+    }
 
     private CarUxRestrictionsConfiguration createEmptyConfig() {
         return createEmptyConfig(null);
@@ -513,6 +670,20 @@
         return builder.build();
     }
 
+    private CarUxRestrictionsConfiguration createMovingConfig(Byte port, int restrictions) {
+        Builder builder = new Builder();
+        if (port != null) {
+            builder.setPhysicalPort(port);
+        }
+        CarUxRestrictionsConfiguration.DrivingStateRestrictions drivingStateRestrictions =
+                new CarUxRestrictionsConfiguration.DrivingStateRestrictions();
+        drivingStateRestrictions.setDistractionOptimizationRequired(restrictions != 0);
+        drivingStateRestrictions.setRestrictions(restrictions);
+        builder.setUxRestrictions(CarDrivingStateEvent.DRIVING_STATE_MOVING,
+                drivingStateRestrictions);
+        return builder.build();
+    }
+
     private void setUpMockParkedState() {
         when(mMockDrivingStateService.getCurrentDrivingState()).thenReturn(
                 new CarDrivingStateEvent(CarDrivingStateEvent.DRIVING_STATE_PARKED, 0));
@@ -533,17 +704,15 @@
                 .thenReturn(speed);
     }
 
-    private File setupMockFile(String filename, CarUxRestrictionsConfiguration config)
+    private File setupMockFile(String filename, List<CarUxRestrictionsConfiguration> configs)
             throws IOException {
         File f = new File(mTempSystemCarDir, filename);
         assertTrue(f.createNewFile());
 
-        if (config != null) {
+        if (configs != null) {
             try (JsonWriter writer = new JsonWriter(
                     new OutputStreamWriter(new FileOutputStream(f), "UTF-8"))) {
-                writer.beginArray();
-                config.writeJson(writer);
-                writer.endArray();
+                mService.writeJson(writer, configs);
             }
         }
         return f;
diff --git a/tests/carservice_test/src/com/android/car/CarVendorExtensionManagerTest.java b/tests/carservice_test/src/com/android/car/CarVendorExtensionManagerTest.java
index 4848fa2..47ccb28 100644
--- a/tests/carservice_test/src/com/android/car/CarVendorExtensionManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarVendorExtensionManagerTest.java
@@ -35,8 +35,8 @@
 import android.util.Log;
 import android.util.SparseArray;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.car.vehiclehal.test.MockedVehicleHal;
 import com.android.car.vehiclehal.test.VehiclePropConfigBuilder;
diff --git a/tests/carservice_test/src/com/android/car/FastPairProviderTest.java b/tests/carservice_test/src/com/android/car/FastPairProviderTest.java
index 6aee11d..546f352 100644
--- a/tests/carservice_test/src/com/android/car/FastPairProviderTest.java
+++ b/tests/carservice_test/src/com/android/car/FastPairProviderTest.java
@@ -29,22 +29,27 @@
 import android.content.res.Resources;
 import android.os.ParcelUuid;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 
 import java.util.Arrays;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class FastPairProviderTest {
+    @Rule
+    public final MockitoRule rule = MockitoJUnit.rule();
+
     // Service ID assigned for FastPair.
     private static final ParcelUuid FastPairServiceUuid = ParcelUuid
             .fromString("0000FE2C-0000-1000-8000-00805f9b34fb");
@@ -62,7 +67,6 @@
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
         when(mMockContext.getSystemService(Context.BLUETOOTH_SERVICE)).thenReturn(
                 mMockBluetoothManager);
         when(mMockBluetoothManager.getAdapter()).thenReturn(mMockBluetoothAdapter);
diff --git a/tests/carservice_test/src/com/android/car/ICarImplTest.java b/tests/carservice_test/src/com/android/car/ICarImplTest.java
new file mode 100644
index 0000000..7b8691f
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/ICarImplTest.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow;
+
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.car.Car;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.automotive.vehicle.V2_0.IVehicle;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.car.systeminterface.ActivityManagerInterface;
+import com.android.car.systeminterface.DisplayInterface;
+import com.android.car.systeminterface.IOInterface;
+import com.android.car.systeminterface.StorageMonitoringInterface;
+import com.android.car.systeminterface.SystemInterface;
+import com.android.car.systeminterface.SystemInterface.Builder;
+import com.android.car.systeminterface.SystemStateInterface;
+import com.android.car.systeminterface.TimeInterface;
+import com.android.car.systeminterface.WakeLockInterface;
+import com.android.car.test.utils.TemporaryDirectory;
+import com.android.car.watchdog.CarWatchdogService;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * This class contains unit tests for the {@link ICarImpl}.
+ * It tests that services started with {@link ICarImpl} are initialized properly.
+ *
+ * The following mocks are used:
+ * 1. {@link ActivityManagerInterface} broadcasts intent for a user.
+ * 2. {@link DisplayInterface} provides access to display operations.
+ * 3. {@link IVehicle} provides access to vehicle properties.
+ * 4. {@link StorageMonitoringInterface} provides access to storage monitoring operations.
+ * 5. {@link SystemStateInterface} provides system statuses (booting, sleeping, ...).
+ * 6. {@link TimeInterface} provides access to time operations.
+ * 7. {@link TimeInterface} provides access to wake lock operations.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class ICarImplTest extends AbstractExtendedMockitoTestCase {
+    private static final String TAG = ICarImplTest.class.getSimpleName();
+
+    @Mock private ActivityManagerInterface mMockActivityManagerInterface;
+    @Mock private DisplayInterface mMockDisplayInterface;
+    @Mock private IVehicle mMockVehicle;
+    @Mock private StorageMonitoringInterface mMockStorageMonitoringInterface;
+    @Mock private SystemStateInterface mMockSystemStateInterface;
+    @Mock private TimeInterface mMockTimeInterface;
+    @Mock private WakeLockInterface mMockWakeLockInterface;
+    @Mock private CarWatchdogService mCarWatchdogService;
+
+    private Context mContext;
+    private SystemInterface mFakeSystemInterface;
+    private UserManager mUserManager;
+
+    private final MockIOInterface mMockIOInterface = new MockIOInterface();
+
+    /**
+     * Initialize all of the objects with the @Mock annotation.
+     */
+    @Before
+    public void setUp() throws Exception {
+        // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
+        // http://b/25897652.
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+
+        mContext = spy(InstrumentationRegistry.getInstrumentation().getTargetContext());
+
+        mUserManager = spy(mContext.getSystemService(UserManager.class));
+        doReturn(mUserManager).when(mContext).getSystemService(eq(UserManager.class));
+        doReturn(mUserManager).when(mContext).getSystemService(eq(Context.USER_SERVICE));
+
+        Resources resources = spy(mContext.getResources());
+        doReturn("").when(resources).getString(
+                eq(com.android.car.R.string.instrumentClusterRendererService));
+        doReturn(false).when(resources).getBoolean(
+                eq(com.android.car.R.bool.audioUseDynamicRouting));
+        doReturn(new String[0]).when(resources).getStringArray(
+                eq(com.android.car.R.array.config_earlyStartupServices));
+        doReturn(resources).when(mContext).getResources();
+
+        mFakeSystemInterface = Builder.newSystemInterface()
+                .withSystemStateInterface(mMockSystemStateInterface)
+                .withActivityManagerInterface(mMockActivityManagerInterface)
+                .withDisplayInterface(mMockDisplayInterface)
+                .withIOInterface(mMockIOInterface)
+                .withStorageMonitoringInterface(mMockStorageMonitoringInterface)
+                .withTimeInterface(mMockTimeInterface)
+                .withWakeLockInterface(mMockWakeLockInterface).build();
+        // ICarImpl will register new CarLocalServices services.
+        // This prevents one test failure in tearDown from triggering assertion failure for single
+        // CarLocalServices service.
+        CarLocalServices.removeAllServices();
+    }
+
+    /**
+     *  Clean up before running the next test.
+     */
+    @After
+    public void tearDown() {
+        try {
+            if (mMockIOInterface != null) {
+                mMockIOInterface.tearDown();
+            }
+        } finally {
+            CarLocalServices.removeAllServices();
+        }
+    }
+
+    @Test
+    public void testNoShardedPreferencesAccessedBeforeUserZeroUnlock() {
+        doReturn(true).when(mContext).isCredentialProtectedStorage();
+        doReturn(false).when(mUserManager).isUserUnlockingOrUnlocked(anyInt());
+        doReturn(false).when(mUserManager).isUserUnlocked();
+        doReturn(false).when(mUserManager).isUserUnlocked(anyInt());
+        doReturn(false).when(mUserManager).isUserUnlocked(any(UserHandle.class));
+        doReturn(false).when(mUserManager).isUserUnlockingOrUnlocked(any(UserHandle.class));
+
+        doThrow(new NullPointerException()).when(mContext).getSharedPrefsFile(anyString());
+        doThrow(new NullPointerException()).when(mContext).getSharedPreferencesPath(any());
+        doThrow(new NullPointerException()).when(mContext).getSharedPreferences(
+                anyString(), anyInt());
+        doThrow(new NullPointerException()).when(mContext).getSharedPreferences(
+                any(File.class), anyInt());
+        doThrow(new NullPointerException()).when(mContext).getDataDir();
+
+        ICarImpl carImpl = new ICarImpl(mContext, mMockVehicle, mFakeSystemInterface,
+                /* errorNotifier= */ null, "MockedCar", /* carUserService= */ null,
+                mCarWatchdogService);
+        carImpl.init();
+        Car mCar = new Car(mContext, carImpl, /* handler= */ null);
+
+        // Post tasks for Handler Threads to ensure all the tasks that will be queued inside init
+        // will be done.
+        for (Thread t : Thread.getAllStackTraces().keySet()) {
+            if (!HandlerThread.class.isInstance(t)) {
+                continue;
+            }
+            HandlerThread ht = (HandlerThread) t;
+            CarServiceUtils.runOnLooperSync(ht.getLooper(), () -> {
+                // Do nothing, just need to make sure looper finishes current task.
+            });
+        }
+
+        mCar.disconnect();
+        carImpl.release();
+    }
+
+    static final class MockIOInterface implements IOInterface {
+        private TemporaryDirectory mFilesDir = null;
+
+        @Override
+        public File getSystemCarDir() {
+            if (mFilesDir == null) {
+                try {
+                    mFilesDir = new TemporaryDirectory(TAG);
+                } catch (IOException e) {
+                    Log.e(TAG, "failed to create temporary directory", e);
+                    fail("failed to create temporary directory. exception was: " + e);
+                }
+            }
+            return mFilesDir.getDirectory();
+        }
+
+        public void tearDown() {
+            if (mFilesDir != null) {
+                try {
+                    mFilesDir.close();
+                } catch (Exception e) {
+                    Log.w(TAG, "could not remove temporary directory", e);
+                }
+            }
+        }
+    }
+}
diff --git a/tests/carservice_test/src/com/android/car/MockedCarTestBase.java b/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
index 69eba19..04c9504 100644
--- a/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
+++ b/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
@@ -15,17 +15,22 @@
  */
 package com.android.car;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
-import static org.mockito.Mockito.doReturn;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
 
 import android.car.Car;
 import android.car.test.CarTestManager;
 import android.car.test.CarTestManagerBinderWrapper;
+import android.car.user.CarUserManager.UserLifecycleListener;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
 import android.content.ServiceConnection;
 import android.content.res.Resources;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
@@ -35,13 +40,15 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.UserHandle;
 import android.util.Log;
 import android.util.SparseArray;
 
-import androidx.test.InstrumentationRegistry;
 import androidx.test.annotation.UiThreadTest;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.car.pm.CarPackageManagerService;
+import com.android.car.systeminterface.ActivityManagerInterface;
 import com.android.car.systeminterface.DisplayInterface;
 import com.android.car.systeminterface.IOInterface;
 import com.android.car.systeminterface.StorageMonitoringInterface;
@@ -51,20 +58,25 @@
 import com.android.car.systeminterface.TimeInterface;
 import com.android.car.systeminterface.WakeLockInterface;
 import com.android.car.test.utils.TemporaryDirectory;
+import com.android.car.user.CarUserService;
 import com.android.car.vehiclehal.test.MockedVehicleHal;
 import com.android.car.vehiclehal.test.MockedVehicleHal.DefaultPropertyHandler;
 import com.android.car.vehiclehal.test.MockedVehicleHal.StaticPropertyHandler;
 import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler;
 import com.android.car.vehiclehal.test.VehiclePropConfigBuilder;
-import com.android.car.vms.VmsClientManager;
+import com.android.car.watchdog.CarWatchdogService;
 
 import org.junit.After;
 import org.junit.Before;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
 
 import java.io.File;
 import java.io.IOException;
 import java.time.Duration;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -73,25 +85,29 @@
  * per test set up that should be done before starting.
  */
 public class MockedCarTestBase {
-    private static final String TAG = MockedCarTestBase.class.getSimpleName();
     static final long DEFAULT_WAIT_TIMEOUT_MS = 3000;
     static final long SHORT_WAIT_TIMEOUT_MS = 500;
+    private static final String TAG = MockedCarTestBase.class.getSimpleName();
+    private static final IBinder sCarServiceToken = new Binder();
+    private static boolean sRealCarServiceReleased;
 
     private Car mCar;
     private ICarImpl mCarImpl;
     private MockedVehicleHal mMockedVehicleHal;
     private SystemInterface mFakeSystemInterface;
     private MockResources mResources;
+    private MockedCarTestContext mMockedCarTestContext;
+
+    private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
+    private final CarUserService mCarUserService = mock(CarUserService.class);
     private final MockIOInterface mMockIOInterface = new MockIOInterface();
-
     private final Handler mMainHandler = new Handler(Looper.getMainLooper());
-
     private final Map<VehiclePropConfigBuilder, VehicleHalPropertyHandler> mHalConfig =
             new HashMap<>();
     private final SparseArray<VehiclePropConfigBuilder> mPropToConfigBuilder = new SparseArray<>();
+    private final CarWatchdogService mCarWatchdogService = mock(CarWatchdogService.class);
 
-    private static final IBinder mCarServiceToken = new Binder();
-    private static boolean mRealCarServiceReleased = false;
+    private MockitoSession mSession;
 
     protected synchronized MockedVehicleHal createMockedVehicleHal() {
         return new MockedVehicleHal();
@@ -108,9 +124,13 @@
     protected synchronized void configureMockedHal() {
     }
 
+    protected synchronized void spyOnBeforeCarImplInit() {
+    }
+
     protected synchronized SystemInterface.Builder getSystemInterfaceBuilder() {
         return Builder.newSystemInterface()
                 .withSystemStateInterface(new MockSystemStateInterface())
+                .withActivityManagerInterface(new MockActivityManagerInterface())
                 .withDisplayInterface(new MockDisplayInterface())
                 .withIOInterface(mMockIOInterface)
                 .withStorageMonitoringInterface(new MockStorageMonitoringInterface())
@@ -123,14 +143,24 @@
     protected synchronized void configureResourceOverrides(MockResources resources) {
         resources.overrideResource(com.android.car.R.string.instrumentClusterRendererService, "");
         resources.overrideResource(com.android.car.R.bool.audioUseDynamicRouting, false);
+        resources.overrideResource(com.android.car.R.array.config_earlyStartupServices,
+                new String[0]);
     }
 
-    protected Context getContext() {
-        return InstrumentationRegistry.getTargetContext();
+    protected synchronized Context getContext() {
+        if (mMockedCarTestContext == null) {
+            mMockedCarTestContext = createMockedCarTestContext(
+                    InstrumentationRegistry.getInstrumentation().getTargetContext());
+        }
+        return mMockedCarTestContext;
+    }
+
+    protected MockedCarTestContext createMockedCarTestContext(Context context) {
+        return new MockedCarTestContext(context);
     }
 
     protected Context getTestContext() {
-        return InstrumentationRegistry.getContext();
+        return InstrumentationRegistry.getInstrumentation().getContext();
     }
 
     protected String getFlattenComponent(Class cls) {
@@ -138,10 +168,21 @@
         return cn.flattenToString();
     }
 
+    /** Child class should override this to configure mocking in different way */
+    protected MockitoSession createMockingSession() {
+        return mockitoSession()
+                .initMocks(this)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+    }
+
     @Before
     @UiThreadTest
     public void setUp() throws Exception {
         Log.i(TAG, "setUp");
+
+        mSession = createMockingSession();
+
         releaseRealCarService(getContext());
 
         mMockedVehicleHal = createMockedVehicleHal();
@@ -150,65 +191,94 @@
         mFakeSystemInterface = getSystemInterfaceBuilder().build();
         configureFakeSystemInterface();
 
-        Context context = getCarServiceContext();
-        spyOn(context);
-        mResources = new MockResources(context.getResources());
-        configureResourceOverrides(mResources);
-        doReturn(mResources).when(context).getResources();
+        mMockedCarTestContext = (MockedCarTestContext) getContext();
+        configureResourceOverrides((MockResources) mMockedCarTestContext.getResources());
+
+        doAnswer((invocation) -> {
+            UserLifecycleListener listener = invocation.getArgument(0);
+            Log.d(TAG, "Adding UserLifecycleListener: " + listener);
+            mUserLifecycleListeners.add(listener);
+            return null;
+        }).when(mCarUserService).addUserLifecycleListener(any());
+
+        doAnswer((invocation) -> {
+            UserLifecycleListener listener = invocation.getArgument(0);
+            Log.d(TAG, "Removing UserLifecycleListener: " + listener);
+            mUserLifecycleListeners.remove(listener);
+            return null;
+        }).when(mCarUserService).removeUserLifecycleListener(any());
 
         // ICarImpl will register new CarLocalServices services.
         // This prevents one test failure in tearDown from triggering assertion failure for single
         // CarLocalServices service.
         CarLocalServices.removeAllServices();
-        ICarImpl carImpl = new ICarImpl(context, mMockedVehicleHal, mFakeSystemInterface,
-                null /* error notifier */, "MockedCar");
 
-        initMockedHal(carImpl, false /* no need to release */);
-        mCarImpl = carImpl;
+        // This should be done here as feature property is accessed inside the constructor.
+        initMockedHal();
+        mCarImpl = new ICarImpl(mMockedCarTestContext, mMockedVehicleHal, mFakeSystemInterface,
+                /* errorNotifier= */ null , "MockedCar", mCarUserService, mCarWatchdogService);
 
-        mCar = new Car(context, mCarImpl, null /* handler */);
+        spyOnBeforeCarImplInit();
+        mCarImpl.init();
+        mCar = new Car(mMockedCarTestContext, mCarImpl, null /* handler */);
     }
 
     @After
+    @UiThreadTest
     public void tearDown() throws Exception {
-        if (mCar != null) {
-            mCar.disconnect();
+        Log.i(TAG, "tearDown");
+
+        try {
+            if (mCar != null) {
+                mCar.disconnect();
+                mCar = null;
+            }
+            if (mCarImpl != null) {
+                mCarImpl.release();
+                mCarImpl = null;
+            }
+            CarServiceUtils.finishAllHandlerTasks();
+            if (mMockIOInterface != null) {
+                mMockIOInterface.tearDown();
+            }
+            mMockedVehicleHal = null;
+        } finally {
+            if (mSession != null) {
+                mSession.finishMocking();
+            }
         }
-        if (mCarImpl != null) {
-            mCarImpl.release();
-        }
-        if (mMockIOInterface != null) {
-            mMockIOInterface.tearDown();
-        }
+    }
+
+    public CarPropertyService getCarPropertyService() {
+        return (CarPropertyService) mCarImpl.getCarService(Car.PROPERTY_SERVICE);
+    }
+
+    public void injectErrorEvent(int propId, int areaId, int errorCode) {
+        mMockedVehicleHal.injectError(errorCode, propId, areaId);
+    }
+
+    /**
+     * Creates new Car instance for testing.
+     */
+    public Car createNewCar() {
+        return new Car(mMockedCarTestContext, mCarImpl, null /* handler */);
     }
 
     public CarPackageManagerService getPackageManagerService() {
         return (CarPackageManagerService) mCarImpl.getCarService(Car.PACKAGE_SERVICE);
     }
 
-    public VmsClientManager getVmsClientManager() {
-        return (VmsClientManager) mCarImpl.getCarInternalService(ICarImpl.INTERNAL_VMS_MANAGER);
-    }
-
-    protected Context getCarServiceContext() {
-        return getContext();
-    }
-
     protected synchronized void reinitializeMockedHal() throws Exception {
-        initMockedHal(mCarImpl, true /* release */);
+        mCarImpl.release();
+        initMockedHal();
     }
 
-    private synchronized void initMockedHal(ICarImpl carImpl, boolean release) throws Exception {
-        if (release) {
-            carImpl.release();
-        }
-
+    private synchronized void initMockedHal() throws Exception {
         for (Map.Entry<VehiclePropConfigBuilder, VehicleHalPropertyHandler> entry
                 : mHalConfig.entrySet()) {
             mMockedVehicleHal.addProperty(entry.getKey().build(), entry.getValue());
         }
         mHalConfig.clear();
-        carImpl.init();
     }
 
     protected synchronized VehiclePropConfigBuilder addProperty(int propertyId,
@@ -260,13 +330,13 @@
 
     /*
      * In order to eliminate interfering with real car service we will disable it. It will be
-     * enabled back in CarTestService when mCarServiceToken will go away (tests finish).
+     * enabled back in CarTestService when sCarServiceToken will go away (tests finish).
      */
     private synchronized static void releaseRealCarService(Context context) throws Exception {
-        if (mRealCarServiceReleased) {
+        if (sRealCarServiceReleased) {
             return;  // We just want to release it once.
         }
-        mRealCarServiceReleased = true;  // To make sure it was called once.
+        sRealCarServiceReleased = true;  // To make sure it was called once.
 
         Object waitForConnection = new Object();
         Car car = android.car.Car.createCar(context, new ServiceConnection() {
@@ -295,7 +365,14 @@
             assertNotNull(binderWrapper);
 
             CarTestManager mgr = new CarTestManager(car, binderWrapper.binder);
-            mgr.stopCarService(mCarServiceToken);
+            mgr.stopCarService(sCarServiceToken);
+        }
+    }
+
+    static final class MockActivityManagerInterface implements ActivityManagerInterface {
+        @Override
+        public void sendBroadcastAsUser(Intent intent, UserHandle user) {
+            Log.d(TAG, "Broadcast intent: " + intent.getAction() + " as user: " + user);
         }
     }
 
@@ -315,9 +392,6 @@
 
         @Override
         public void refreshDisplayBrightness() {}
-
-        @Override
-        public void reconfigureSecondaryDisplays() {}
     }
 
     static final class MockIOInterface implements IOInterface {
@@ -347,6 +421,29 @@
         }
     }
 
+    /**
+     * Special version of {@link ContextWrapper} that overrides {@method getResources} by returning
+     * a {@link MockResources}, so tests are free to set resources. This class represents an
+     * alternative of using Mockito spy (see b/148240178).
+     *
+     * Tests may specialize this class. If they decide so, then they are required to override
+     * {@method newMockedCarContext} to provide their own context.
+     */
+    protected static class MockedCarTestContext extends ContextWrapper {
+
+        private final Resources mMockedResources;
+
+        MockedCarTestContext(Context base) {
+            super(base);
+            mMockedResources = new MockResources(base.getResources());
+        }
+
+        @Override
+        public Resources getResources() {
+            return mMockedResources;
+        }
+    }
+
     static final class MockResources extends Resources {
         private final HashMap<Integer, Boolean> mBooleanOverrides = new HashMap<>();
         private final HashMap<Integer, Integer> mIntegerOverrides = new HashMap<>();
@@ -439,5 +536,4 @@
         @Override
         public void switchToFullWakeLock() {}
     }
-
 }
diff --git a/tests/carservice_test/src/com/android/car/MockedVmsTestBase.java b/tests/carservice_test/src/com/android/car/MockedVmsTestBase.java
index ccc2e6c..ff649de 100644
--- a/tests/carservice_test/src/com/android/car/MockedVmsTestBase.java
+++ b/tests/carservice_test/src/com/android/car/MockedVmsTestBase.java
@@ -18,7 +18,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import android.app.ActivityManager;
 import android.car.Car;
 import android.car.VehicleAreaType;
 import android.car.vms.VmsAvailableLayers;
@@ -50,27 +49,17 @@
 import java.util.concurrent.TimeUnit;
 
 public class MockedVmsTestBase extends MockedCarTestBase {
-    public static final long PUBLISHER_BIND_TIMEOUT_SECS = 2L;
-
+    public static final long PUBLISHER_CLIENT_TIMEOUT = 500L;
+    public static final long MESSAGE_RECEIVE_TIMEOUT = 500L;
     private static final String TAG = "MockedVmsTestBase";
-    private static CountDownLatch sPublisherIsReady = new CountDownLatch(1);
-    private static MockPublisherClient sPublisherClient;
+
+    private MockPublisherClient mPublisherClient;
+    private CountDownLatch mPublisherIsReady = new CountDownLatch(1);
     private VmsSubscriberManager mVmsSubscriberManager;
     private MockSubscriberClient mSubscriberClient;
     private MockHalClient mHalClient;
 
     @Override
-    protected synchronized void configureResourceOverrides(MockResources resources) {
-        super.configureResourceOverrides(resources);
-        // Override publisher client endpoint configurations
-        // Both lists must be set, but only one will be used (see setUp)
-        resources.overrideResource(com.android.car.R.array.vmsPublisherSystemClients,
-                new String[]{getFlattenComponent(MockPublisherClient.class)});
-        resources.overrideResource(com.android.car.R.array.vmsPublisherUserClients,
-                new String[]{getFlattenComponent(MockPublisherClient.class)});
-    }
-
-    @Override
     protected synchronized void configureMockedHal() {
         mHalClient = new MockHalClient();
         addProperty(VehicleProperty.VEHICLE_MAP_SERVICE, mHalClient)
@@ -81,14 +70,18 @@
 
     @Before
     public void setUpVms() throws Exception {
-        // Trigger VmsClientManager to bind to the MockPublisherClient
-        getVmsClientManager().mUserCallback.onSwitchUser(ActivityManager.getCurrentUser());
+        mPublisherClient = new MockPublisherClient();
+        mPublisherClient.setMockCar(getCar());
         mVmsSubscriberManager = (VmsSubscriberManager) getCar().getCarManager(
                 Car.VMS_SUBSCRIBER_SERVICE);
         mSubscriberClient = new MockSubscriberClient();
         mVmsSubscriberManager.setVmsSubscriberClientCallback(Executors.newSingleThreadExecutor(),
                 mSubscriberClient);
 
+        assertTrue(
+                "Timeout while waiting for publisher client to be ready",
+                mPublisherIsReady.await(PUBLISHER_CLIENT_TIMEOUT, TimeUnit.MILLISECONDS));
+
         // Validate session handshake
         List<Integer> v = mHalClient.receiveMessage().value.int32Values;
         assertEquals(VmsMessageType.START_SESSION,
@@ -114,26 +107,12 @@
                 (int) v.get(VmsAvailabilityStateIntegerValuesIndex.NUMBER_OF_ASSOCIATED_LAYERS));
     }
 
-    @Override
-    public void tearDown() throws Exception {
-        super.tearDown();
-        sPublisherIsReady = new CountDownLatch(1);
-        sPublisherClient = null;
-    }
-
     VmsSubscriberManager getSubscriberManager() {
         return mVmsSubscriberManager;
     }
 
     MockPublisherClient getMockPublisherClient() {
-        try {
-            assertTrue(
-                    "Timeout while waiting for publisher client to be ready",
-                    sPublisherIsReady.await(PUBLISHER_BIND_TIMEOUT_SECS, TimeUnit.SECONDS));
-        } catch (InterruptedException e) {
-            throw new RuntimeException(e);
-        }
-        return sPublisherClient;
+        return mPublisherClient;
     }
 
     MockSubscriberClient getMockSubscriberClient() {
@@ -144,20 +123,24 @@
         return mHalClient;
     }
 
-    public static class MockPublisherClient extends VmsPublisherClientService {
+    class MockPublisherClient extends VmsPublisherClientService {
         private BlockingQueue<VmsSubscriptionState> mSubscriptionState =
                 new LinkedBlockingQueue<>();
 
+        void setMockCar(Car car) {
+            onCarLifecycleChanged(car, true);
+        }
+
         @Override
         protected void onVmsPublisherServiceReady() {
             Log.d(TAG, "MockPublisherClient.onVmsPublisherServiceReady");
-            sPublisherClient = this;
-            sPublisherIsReady.countDown();
+            mPublisherIsReady.countDown();
         }
 
         @Override
         public void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState) {
-            Log.d(TAG, "MockPublisherClient.onVmsSubscriptionChange");
+            Log.d(TAG, "MockPublisherClient.onVmsSubscriptionChange: "
+                    + subscriptionState.getSequenceNumber());
             mSubscriptionState.add(subscriptionState);
         }
 
@@ -224,7 +207,7 @@
 
     private static <T> T receiveWithTimeout(BlockingQueue<T> queue) {
         try {
-            return queue.poll(2L, TimeUnit.SECONDS);
+            return queue.poll(MESSAGE_RECEIVE_TIMEOUT, TimeUnit.MILLISECONDS);
         } catch (InterruptedException e) {
             throw new RuntimeException(e);
         }
diff --git a/tests/carservice_test/src/com/android/car/SystemActivityMonitoringServiceTest.java b/tests/carservice_test/src/com/android/car/SystemActivityMonitoringServiceTest.java
deleted file mode 100644
index 4595f9e..0000000
--- a/tests/carservice_test/src/com/android/car/SystemActivityMonitoringServiceTest.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.car;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.annotation.Nullable;
-import android.app.Activity;
-import android.app.ActivityOptions;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.VirtualDisplay;
-import android.util.Log;
-import android.view.Display;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.car.SystemActivityMonitoringService.TopTaskInfoContainer;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-import java.util.function.BooleanSupplier;
-
-@RunWith(AndroidJUnit4.class)
-@MediumTest
-public class SystemActivityMonitoringServiceTest {
-    private static final String TAG = "SystemActivityMonitoringServiceTest";
-
-    private static final long ACTIVITY_TIMEOUT_MS = 5000;
-    private static final long DEFAULT_TIMEOUT_SECONDS = 2;
-
-    private SystemActivityMonitoringService mService;
-    private Semaphore mActivityLaunchSemaphore = new Semaphore(0);
-
-    private final TopTaskInfoContainer[] mTopTaskInfo = new TopTaskInfoContainer[1];
-
-    @Before
-    public void setUp() throws Exception {
-        mService = new SystemActivityMonitoringService(getContext());
-        mService.registerActivityLaunchListener(
-                new FilteredLaunchListener(/* desiredComponent= */ null));
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        mService.registerActivityLaunchListener(null);
-        mService = null;
-    }
-
-    @Test
-    public void testActivityLaunch() throws Exception {
-        ComponentName activityA = toComponentName(getTestContext(), ActivityA.class);
-        mService.registerActivityLaunchListener(new FilteredLaunchListener(activityA));
-        startActivity(getContext(), activityA);
-        assertTopTaskActivity(activityA);
-
-        ComponentName activityB = toComponentName(getTestContext(), ActivityB.class);
-        mService.registerActivityLaunchListener(new FilteredLaunchListener(activityB));
-        startActivity(getContext(), activityB);
-        assertTopTaskActivity(activityB);
-    }
-
-    @Test
-    public void testActivityBlocking() throws Exception {
-        ComponentName blackListedActivity = toComponentName(getTestContext(), ActivityC.class);
-        ComponentName blockingActivity = toComponentName(getTestContext(), BlockingActivity.class);
-        Intent blockingIntent = new Intent();
-        blockingIntent.setComponent(blockingActivity);
-
-        // start a black listed activity
-        mService.registerActivityLaunchListener(new FilteredLaunchListener(blackListedActivity));
-        startActivity(getContext(), blackListedActivity);
-        assertTopTaskActivity(blackListedActivity);
-
-        // Instead of start activity, invoke blockActivity.
-        mService.registerActivityLaunchListener(new FilteredLaunchListener(blockingActivity));
-        mService.blockActivity(mTopTaskInfo[0], blockingIntent);
-        assertTopTaskActivity(blockingActivity);
-    }
-
-    @Test
-    public void testRemovesFromTopTasks() throws Exception {
-        ComponentName activityThatFinishesImmediately =
-                toComponentName(getTestContext(), ActivityThatFinishesImmediately.class);
-        startActivity(getContext(), activityThatFinishesImmediately);
-        waitUntil(() -> topTasksHasComponent(activityThatFinishesImmediately));
-        waitUntil(() -> !topTasksHasComponent(activityThatFinishesImmediately));
-    }
-
-    @Test
-    public void testGetTopTasksOnMultiDisplay() throws Exception {
-        String virtualDisplayName = "virtual_display";
-        DisplayManager displayManager = getContext().getSystemService(DisplayManager.class);
-        VirtualDisplay virtualDisplay = displayManager.createVirtualDisplay(
-                virtualDisplayName, 10, 10, 10, null, 0);
-
-        ComponentName activityA = toComponentName(getTestContext(), ActivityA.class);
-        startActivity(getContext(), activityA, Display.DEFAULT_DISPLAY);
-        waitUntil(() -> topTasksHasComponent(activityA));
-
-        ComponentName activityB = toComponentName(getTestContext(), ActivityB.class);
-        startActivity(getContext(), activityB, virtualDisplay.getDisplay().getDisplayId());
-        waitUntil(() -> topTasksHasComponent(activityB));
-
-        virtualDisplay.release();
-    }
-
-    private void waitUntil(BooleanSupplier condition) throws Exception {
-        while (!condition.getAsBoolean()) {
-            boolean didAquire =
-                    mActivityLaunchSemaphore.tryAcquire(DEFAULT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
-            if (!didAquire && !condition.getAsBoolean()) {
-                throw new RuntimeException("failed while waiting for condition to become true");
-            }
-        }
-    }
-
-    private boolean topTasksHasComponent(ComponentName component) {
-        for (TopTaskInfoContainer topTaskInfoContainer : mService.getTopTasks()) {
-            if (topTaskInfoContainer.topActivity.equals(component)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /** Activity that closes itself after some timeout to clean up the screen. */
-    public static class TempActivity extends Activity {
-        @Override
-        protected void onResume() {
-            super.onResume();
-            getMainThreadHandler().postDelayed(this::finish, ACTIVITY_TIMEOUT_MS);
-        }
-    }
-
-    public static class ActivityA extends TempActivity {}
-
-    public static class ActivityB extends TempActivity {}
-
-    public static class ActivityC extends TempActivity {}
-
-    public static class ActivityThatFinishesImmediately extends Activity {
-
-        @Override
-        protected void onResume() {
-            super.onResume();
-            finish();
-        }
-    }
-
-    public static class BlockingActivity extends TempActivity {}
-
-    private void assertTopTaskActivity(ComponentName activity) throws Exception {
-        assertTrue(mActivityLaunchSemaphore.tryAcquire(DEFAULT_TIMEOUT_SECONDS, TimeUnit.SECONDS));
-        synchronized (mTopTaskInfo) {
-            assertEquals(activity, mTopTaskInfo[0].topActivity);
-        }
-    }
-
-    private Context getContext() {
-        return InstrumentationRegistry.getTargetContext();
-    }
-
-    private Context getTestContext() {
-        return InstrumentationRegistry.getContext();
-    }
-
-    private static ComponentName toComponentName(Context ctx, Class<?> cls) {
-        return ComponentName.createRelative(ctx, cls.getName());
-    }
-
-    private static void startActivity(Context ctx, ComponentName name) {
-        startActivity(ctx, name, Display.DEFAULT_DISPLAY);
-    }
-
-    private static void startActivity(Context ctx, ComponentName name, int displayId) {
-        Intent intent = new Intent();
-        intent.setComponent(name);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        ActivityOptions options = ActivityOptions.makeBasic();
-        options.setLaunchDisplayId(displayId);
-
-        ctx.startActivity(intent, options.toBundle());
-    }
-
-    private class FilteredLaunchListener
-            implements SystemActivityMonitoringService.ActivityLaunchListener {
-
-        @Nullable
-        private final ComponentName mDesiredComponent;
-
-        /**
-         * Creates an instance of an
-         * {@link com.android.car.SystemActivityMonitoringService.ActivityLaunchListener}
-         * that filters based on the component name or does not filter if component name is null.
-         */
-        FilteredLaunchListener(@Nullable ComponentName desiredComponent) {
-            mDesiredComponent = desiredComponent;
-        }
-
-        @Override
-        public void onActivityLaunch(TopTaskInfoContainer topTask) {
-            // Ignore activities outside of this test case
-            if (!getTestContext().getPackageName().equals(topTask.topActivity.getPackageName())) {
-                Log.d(TAG, "Component launched from other package: "
-                        + topTask.topActivity.getClassName());
-                return;
-            }
-            if (mDesiredComponent != null && !topTask.topActivity.equals(mDesiredComponent)) {
-                Log.d(TAG, String.format("Unexpected component: %s. Expected: %s",
-                        topTask.topActivity.getClassName(), mDesiredComponent));
-                return;
-            }
-
-            synchronized (mTopTaskInfo) {
-                mTopTaskInfo[0] = topTask;
-            }
-            mActivityLaunchSemaphore.release();
-        }
-    }
-}
diff --git a/tests/carservice_test/src/com/android/car/VmsHalServiceSubscriptionEventTest.java b/tests/carservice_test/src/com/android/car/VmsHalServiceSubscriptionEventTest.java
index cc32231..4260ee0 100644
--- a/tests/carservice_test/src/com/android/car/VmsHalServiceSubscriptionEventTest.java
+++ b/tests/carservice_test/src/com/android/car/VmsHalServiceSubscriptionEventTest.java
@@ -23,9 +23,11 @@
 import android.hardware.automotive.vehicle.V2_0.VmsMessageType;
 import android.hardware.automotive.vehicle.V2_0.VmsSubscriptionsStateIntegerValuesIndex;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -33,6 +35,7 @@
 import java.util.HashSet;
 import java.util.List;
 
+@RunWith(AndroidJUnit4.class)
 @MediumTest
 public class VmsHalServiceSubscriptionEventTest extends MockedVmsTestBase {
     @Test
diff --git a/tests/carservice_test/src/com/android/car/VmsOperationRecorderTest.java b/tests/carservice_test/src/com/android/car/VmsOperationRecorderTest.java
index 2c41f32..cd44e43 100644
--- a/tests/carservice_test/src/com/android/car/VmsOperationRecorderTest.java
+++ b/tests/carservice_test/src/com/android/car/VmsOperationRecorderTest.java
@@ -24,8 +24,8 @@
 import android.car.vms.VmsOperationRecorder;
 import android.util.Log;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.json.JSONArray;
 import org.json.JSONException;
diff --git a/tests/carservice_test/src/com/android/car/VmsPublisherClientPermissionTest.java b/tests/carservice_test/src/com/android/car/VmsPublisherClientPermissionTest.java
deleted file mode 100644
index 0bb9d4f..0000000
--- a/tests/carservice_test/src/com/android/car/VmsPublisherClientPermissionTest.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import static com.android.car.MockedVmsTestBase.PUBLISHER_BIND_TIMEOUT_SECS;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.app.ActivityManager;
-import android.car.vms.VmsPublisherClientService;
-import android.car.vms.VmsSubscriptionState;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-public class VmsPublisherClientPermissionTest extends MockedCarTestBase {
-    private static CountDownLatch sPublisherExpectedPermission = new CountDownLatch(1);
-    private static CountDownLatch sPublisherWrongPermission = new CountDownLatch(1);
-    private static CountDownLatch sPublisherMissingPermission = new CountDownLatch(1);
-
-    private static class MockPublisherClient extends VmsPublisherClientService {
-        private CountDownLatch mReadyLatch;
-        MockPublisherClient(CountDownLatch readyLatch) {
-            mReadyLatch = readyLatch;
-        }
-        @Override
-        protected void onVmsPublisherServiceReady() {
-            mReadyLatch.countDown();
-        }
-
-        @Override
-        public void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState) {}
-    }
-
-
-    // AndroidManifest.xml:
-    // <service android:name="com.android.car.VmsPublisherClientPermissionTest$PublisherClientExpectedPermission"
-    //         android:exported="true"
-    //         android:permission="android.car.permission.BIND_VMS_CLIENT"/>
-    public static class PublisherClientExpectedPermission extends MockPublisherClient {
-        public PublisherClientExpectedPermission() {
-            super(sPublisherExpectedPermission);
-        }
-    }
-
-    // AndroidManifest.xml:
-    // <service android:name="com.android.car.VmsPublisherClientPermissionTest$PublisherClientWrongPermission"
-    //         android:exported="true"
-    //         android:permission="android.car.permission.VMS_PUBLISHER"/>
-    public static class PublisherClientWrongPermission extends MockPublisherClient {
-        public PublisherClientWrongPermission() {
-            super(sPublisherWrongPermission);
-        }
-    }
-
-    // AndroidManifest.xml:
-    // <service android:name="com.android.car.VmsPublisherClientPermissionTest$PublisherClientMissingPermission"
-    //         android:exported="true"/>
-    public static class PublisherClientMissingPermission extends MockPublisherClient {
-        public PublisherClientMissingPermission() {
-            super(sPublisherMissingPermission);
-        }
-    }
-
-    @Override
-    protected synchronized void configureResourceOverrides(MockResources resources) {
-        super.configureResourceOverrides(resources);
-        resources.overrideResource(com.android.car.R.array.vmsPublisherSystemClients, new String[]{
-                getFlattenComponent(PublisherClientExpectedPermission.class),
-                getFlattenComponent(PublisherClientWrongPermission.class),
-                getFlattenComponent(PublisherClientMissingPermission.class)
-        });
-        resources.overrideResource(com.android.car.R.array.vmsPublisherUserClients, new String[]{
-                getFlattenComponent(PublisherClientExpectedPermission.class),
-                getFlattenComponent(PublisherClientWrongPermission.class),
-                getFlattenComponent(PublisherClientMissingPermission.class)
-        });
-    }
-
-    @Before
-    public void triggerClientBinding() {
-        getVmsClientManager().mUserCallback.onSwitchUser(ActivityManager.getCurrentUser());
-    }
-
-    @Test
-    public void testExpectedPermission() throws Exception {
-        assertTrue(
-                "Timeout while waiting for publisher client to be ready",
-                sPublisherExpectedPermission.await(PUBLISHER_BIND_TIMEOUT_SECS, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testWrongPermission() throws Exception {
-        assertFalse(
-                "Publisher with wrong android:permission was bound unexpectedly",
-                sPublisherWrongPermission.await(PUBLISHER_BIND_TIMEOUT_SECS, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testMissingPermission() throws Exception {
-        assertFalse(
-                "Publisher with missing android:permission was bound unexpectedly",
-                sPublisherMissingPermission.await(PUBLISHER_BIND_TIMEOUT_SECS, TimeUnit.SECONDS));
-    }
-}
diff --git a/tests/carservice_test/src/com/android/car/VmsPublisherClientServiceTest.java b/tests/carservice_test/src/com/android/car/VmsPublisherClientServiceTest.java
deleted file mode 100644
index 2f79019..0000000
--- a/tests/carservice_test/src/com/android/car/VmsPublisherClientServiceTest.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import android.car.vms.VmsLayer;
-import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
-import android.hardware.automotive.vehicle.V2_0.VmsBaseMessageIntegerValuesIndex;
-import android.hardware.automotive.vehicle.V2_0.VmsMessageType;
-import android.hardware.automotive.vehicle.V2_0.VmsMessageWithLayerIntegerValuesIndex;
-
-import androidx.test.filters.MediumTest;
-
-import org.junit.Test;
-
-@MediumTest
-public class VmsPublisherClientServiceTest extends MockedVmsTestBase {
-    private static final int MOCK_PUBLISHER_LAYER_ID = 12;
-    private static final int MOCK_PUBLISHER_LAYER_VERSION = 34;
-    private static final int MOCK_PUBLISHER_LAYER_SUBTYPE = 56;
-    public static final int MOCK_PUBLISHER_ID = 1234;
-    public static final VmsLayer MOCK_PUBLISHER_LAYER =
-            new VmsLayer(MOCK_PUBLISHER_LAYER_ID,
-                    MOCK_PUBLISHER_LAYER_SUBTYPE,
-                    MOCK_PUBLISHER_LAYER_VERSION);
-    public static final byte[] PAYLOAD = new byte[]{1, 1, 2, 3, 5, 8, 13};
-
-    @Test
-    public void testPublish() throws Exception {
-        MockHalClient client = getMockHalClient();
-        client.sendMessage(
-                VmsMessageType.SUBSCRIBE,
-                MOCK_PUBLISHER_LAYER_ID,
-                MOCK_PUBLISHER_LAYER_SUBTYPE,
-                MOCK_PUBLISHER_LAYER_VERSION);
-
-        getMockPublisherClient().publish(MOCK_PUBLISHER_LAYER, MOCK_PUBLISHER_ID, PAYLOAD);
-
-        VehiclePropValue message;
-        do {
-            message = client.receiveMessage();
-        } while (message != null && message.value.int32Values.get(
-                VmsBaseMessageIntegerValuesIndex.MESSAGE_TYPE) != VmsMessageType.DATA);
-        assertNotNull("No data message received", message);
-
-        VehiclePropValue.RawValue rawValue = message.value;
-        int messageType = rawValue.int32Values.get(
-                VmsMessageWithLayerIntegerValuesIndex.MESSAGE_TYPE);
-        int layerId = rawValue.int32Values.get(
-                VmsMessageWithLayerIntegerValuesIndex.LAYER_TYPE);
-        int layerVersion = rawValue.int32Values.get(
-                VmsMessageWithLayerIntegerValuesIndex.LAYER_VERSION);
-        byte[] payload = new byte[rawValue.bytes.size()];
-        for (int i = 0; i < rawValue.bytes.size(); ++i) {
-            payload[i] = rawValue.bytes.get(i);
-        }
-        assertEquals(VmsMessageType.DATA, messageType);
-        assertEquals(MOCK_PUBLISHER_LAYER_ID, layerId);
-        assertEquals(MOCK_PUBLISHER_LAYER_VERSION, layerVersion);
-        assertArrayEquals(PAYLOAD, payload);
-    }
-}
diff --git a/tests/carservice_test/src/com/android/car/VmsPublisherSubscriberTest.java b/tests/carservice_test/src/com/android/car/VmsPublisherSubscriberTest.java
index 87cf1b8..a95a45a 100644
--- a/tests/carservice_test/src/com/android/car/VmsPublisherSubscriberTest.java
+++ b/tests/carservice_test/src/com/android/car/VmsPublisherSubscriberTest.java
@@ -31,10 +31,14 @@
 import android.car.vms.VmsSubscriptionState;
 import android.util.Pair;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.MediumTest;
+import androidx.test.filters.RequiresDevice;
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.Arrays;
 import java.util.Collections;
@@ -43,6 +47,7 @@
 import java.util.function.Supplier;
 import java.util.function.ToIntFunction;
 
+@RunWith(AndroidJUnit4.class)
 @MediumTest
 public class VmsPublisherSubscriberTest extends MockedVmsTestBase {
     private static final VmsLayer SUBSCRIPTION_LAYER = new VmsLayer(1, 1, 1);
@@ -245,6 +250,7 @@
     }
 
     @Test
+    @RequiresDevice
     public void testSubscribe() {
         mSubscriber.subscribe(SUBSCRIPTION_LAYER);
         assertSubscriptionState(1, SUBSCRIPTION_LAYER);
@@ -514,6 +520,7 @@
     }
 
     @Test
+    @FlakyTest
     public void testUnsubscribeToPublisher_MultiplePublishers() {
         int publisherId = mPublisher.getPublisherId(PUBLISHER_INFO);
         int publisherId2 = mPublisher.getPublisherId(PUBLISHER_INFO_OTHER);
diff --git a/tests/carservice_test/src/com/android/car/VmsSubscriberManagerTest.java b/tests/carservice_test/src/com/android/car/VmsSubscriberManagerTest.java
index 19f9ec0..423718c 100644
--- a/tests/carservice_test/src/com/android/car/VmsSubscriberManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/VmsSubscriberManagerTest.java
@@ -27,9 +27,11 @@
 import android.hardware.automotive.vehicle.V2_0.VmsMessageType;
 import android.util.Pair;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -37,6 +39,7 @@
 import java.util.HashSet;
 import java.util.Set;
 
+@RunWith(AndroidJUnit4.class)
 @MediumTest
 public class VmsSubscriberManagerTest extends MockedVmsTestBase {
     private static final int PUBLISHER_ID = 17;
@@ -420,13 +423,36 @@
         assertEquals(1, sequenceNumber);
         assertEquals(1, numberLayers);
 
+        int[] offeringMessage2 = {
+                VmsMessageType.OFFERING, // MessageType
+                PUBLISHER_ID,
+                2, // Number of offered layers
+
+                SUBSCRIPTION_LAYER_ID,
+                MOCK_PUBLISHER_LAYER_SUBTYPE,
+                SUBSCRIPTION_LAYER_VERSION,
+                0, // number of dependencies for layer
+
+                SUBSCRIPTION_DEPENDANT_LAYER_ID_1,
+                MOCK_PUBLISHER_LAYER_SUBTYPE,
+                SUBSCRIPTION_DEPENDANT_LAYER_VERSION_1,
+                1, // number of dependencies for layer
+                SUBSCRIPTION_LAYER_ID,
+                MOCK_PUBLISHER_LAYER_SUBTYPE,
+                SUBSCRIPTION_LAYER_VERSION,
+        };
+
+
         // Inject second offer.
-        getMockHalClient().sendMessage(offeringMessage);
+        getMockHalClient().sendMessage(offeringMessage2);
 
         // Verify applications API.
         availableLayers = getMockSubscriberClient().receiveLayerAvailability();
         assertEquals(
-                Collections.singleton(SUBSCRIPTION_ASSOCIATED_LAYER),
+                new HashSet<>(Arrays.asList(
+                        SUBSCRIPTION_ASSOCIATED_LAYER,
+                        SUBSCRIPTION_DEPENDANT_ASSOCIATED_LAYER_1
+                )),
                 availableLayers.getAssociatedLayers());
         assertEquals(2, availableLayers.getSequence());
 
@@ -439,7 +465,7 @@
 
         assertEquals(messageType, VmsMessageType.AVAILABILITY_CHANGE);
         assertEquals(2, sequenceNumber);
-        assertEquals(1, numberLayers);
+        assertEquals(2, numberLayers);
 
     }
 
diff --git a/tests/carservice_test/src/com/android/car/audio/AudioFocusTest.java b/tests/carservice_test/src/com/android/car/audio/AudioFocusTest.java
deleted file mode 100644
index ff4c517..0000000
--- a/tests/carservice_test/src/com/android/car/audio/AudioFocusTest.java
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.audio;
-
-import static org.junit.Assert.assertEquals;
-
-import android.media.AudioAttributes;
-import android.media.AudioFocusRequest;
-import android.media.AudioManager;
-
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class AudioFocusTest {
-
-    private static final String TAG = "AudioFocusTest";
-
-    private static final int TEST_TIMING_TOLERANCE_MS = 100;
-
-    // ContextNumber.INVALID
-    private static final AudioAttributes ATTR_VIRTUAL_SOURCE = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_VIRTUAL_SOURCE)
-            .setContentType(AudioAttributes.USAGE_VIRTUAL_SOURCE)
-            .build();
-    // ContextNumber.MUSIC
-    private static final AudioAttributes ATTR_MEDIA = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_MEDIA)
-            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
-            .build();
-    // ContextNumber.NAVIGATION
-    private static final AudioAttributes ATTR_DRIVE_DIR = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
-            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
-            .build();
-    // ContextNumber.VOICE_COMMAND
-    private static final AudioAttributes ATTR_A11Y = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY)
-            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
-            .build();
-    // ContextNumber.CALL_RING
-    private static final AudioAttributes ATTR_RINGTONE = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .build();
-    // ContextNumber.CALL
-    private static final AudioAttributes ATTR_VOICE_COM = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
-            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
-            .build();
-    // ContextNumber.ALARM
-    private static final AudioAttributes ATTR_ALARM = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_ALARM)
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .build();
-    // ContextNumber.NOTIFICATION
-    private static final AudioAttributes ATTR_NOTIFICATION = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_NOTIFICATION)
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .build();
-    // ContextNumber.SYSTEM_SOUND
-    private static final AudioAttributes ATTR_A11Y_NOTIFICATION = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
-            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
-            .build();
-
-    private AudioManager mAudioManager;
-
-    @Before
-    public void setUp() {
-        mAudioManager = new AudioManager(ApplicationProvider.getApplicationContext());
-    }
-
-    @Test
-    public void individualAttributeFocusRequest_focusRequestGranted() throws Exception {
-        // Make sure each usage is able to request and release audio focus individually
-        requestAndLoseFocusForAttribute(ATTR_VIRTUAL_SOURCE);
-        requestAndLoseFocusForAttribute(ATTR_MEDIA);
-        requestAndLoseFocusForAttribute(ATTR_DRIVE_DIR);
-        requestAndLoseFocusForAttribute(ATTR_A11Y);
-        requestAndLoseFocusForAttribute(ATTR_RINGTONE);
-        requestAndLoseFocusForAttribute(ATTR_VOICE_COM);
-        requestAndLoseFocusForAttribute(ATTR_ALARM);
-        requestAndLoseFocusForAttribute(ATTR_NOTIFICATION);
-        requestAndLoseFocusForAttribute(ATTR_A11Y_NOTIFICATION);
-    }
-
-    @Test
-    public void exclusiveInteractionsForFocusGain_requestGrantedAndFocusLossSent()
-            throws Exception {
-        // For each interaction the focus request is granted and on the second request
-        // focus lost is dispatched to the first focus listener
-
-        // Test Exclusive interactions with audio focus gain request without pause
-        // instead of ducking
-        testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN, false);
-        // Test Exclusive interactions with audio focus gain request with pause instead of ducking
-        testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN, true);
-    }
-
-    @Test
-    public void exclusiveInteractionsTransient_requestGrantedAndFocusLossSent()
-            throws Exception {
-        // For each interaction the focus request is granted and on the second request
-        // focus lost transient is dispatched to the first focus listener
-
-        // Test Exclusive interactions with audio focus gain transient request
-        // without pause instead of ducking
-        testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, false);
-        // Test Exclusive interactions with audio focus gain transient request
-        // with pause instead of ducking
-        testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, true);
-    }
-
-    @Test
-    public void exclusiveInteractionsTransientMayDuck_requestGrantedAndFocusLossSent()
-            throws Exception {
-        // For each interaction the focus request is granted and on the second request
-        // focus lost transient is dispatched to the first focus listener
-
-        // Test exclusive interactions with audio focus transient may duck focus request
-        // without pause instead of ducking
-        testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
-                false);
-        // Test exclusive interactions with audio focus transient may duck focus request
-        // with pause instead of ducking
-        testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
-                true);
-    }
-
-    @Test
-    public void rejectedInteractions_focusRequestRejected() throws Exception {
-        // Test different paired interaction between different usages
-        // for each interaction pair the first focus request will be granted but the second
-        // will be rejected
-        int interaction = CarAudioFocus.INTERACTION_REJECT;
-        int gain = AudioManager.AUDIOFOCUS_GAIN;
-        testInteraction(ATTR_VIRTUAL_SOURCE, ATTR_VIRTUAL_SOURCE, interaction, gain, false);
-        testInteraction(ATTR_VIRTUAL_SOURCE, ATTR_MEDIA, interaction, gain, false);
-        testInteraction(ATTR_VIRTUAL_SOURCE, ATTR_DRIVE_DIR, interaction, gain, false);
-        testInteraction(ATTR_VIRTUAL_SOURCE, ATTR_A11Y, interaction, gain, false);
-        testInteraction(ATTR_VIRTUAL_SOURCE, ATTR_RINGTONE, interaction, gain, false);
-        testInteraction(ATTR_VIRTUAL_SOURCE, ATTR_VOICE_COM, interaction, gain, false);
-        testInteraction(ATTR_VIRTUAL_SOURCE, ATTR_ALARM, interaction, gain, false);
-        testInteraction(ATTR_VIRTUAL_SOURCE, ATTR_NOTIFICATION, interaction, gain, false);
-        testInteraction(ATTR_VIRTUAL_SOURCE, ATTR_A11Y_NOTIFICATION, interaction, gain, false);
-
-        testInteraction(ATTR_MEDIA, ATTR_VIRTUAL_SOURCE, interaction, gain, false);
-
-        testInteraction(ATTR_DRIVE_DIR, ATTR_VIRTUAL_SOURCE, interaction, gain, false);
-
-        testInteraction(ATTR_A11Y, ATTR_VIRTUAL_SOURCE, interaction, gain, false);
-        testInteraction(ATTR_A11Y, ATTR_DRIVE_DIR, interaction, gain, false);
-        testInteraction(ATTR_A11Y, ATTR_NOTIFICATION, interaction, gain, false);
-        testInteraction(ATTR_A11Y, ATTR_A11Y_NOTIFICATION, interaction, gain, false);
-
-        testInteraction(ATTR_RINGTONE, ATTR_VIRTUAL_SOURCE, interaction, gain, false);
-        testInteraction(ATTR_RINGTONE, ATTR_MEDIA, interaction, gain, false);
-        testInteraction(ATTR_RINGTONE, ATTR_ALARM, interaction, gain, false);
-        testInteraction(ATTR_RINGTONE, ATTR_NOTIFICATION, interaction, gain, false);
-
-        testInteraction(ATTR_VOICE_COM, ATTR_VIRTUAL_SOURCE, interaction, gain, false);
-        testInteraction(ATTR_VOICE_COM, ATTR_MEDIA, interaction, gain, false);
-        testInteraction(ATTR_VOICE_COM, ATTR_A11Y, interaction, gain, false);
-
-        testInteraction(ATTR_ALARM, ATTR_VIRTUAL_SOURCE, interaction, gain, false);
-
-        testInteraction(ATTR_NOTIFICATION, ATTR_VIRTUAL_SOURCE, interaction, gain, false);
-
-        testInteraction(ATTR_A11Y_NOTIFICATION, ATTR_VIRTUAL_SOURCE, interaction, gain, false);
-    }
-
-    @Test
-    public void concurrentInteractionsFocusGain_requestGrantedAndFocusLossSent() throws Exception {
-        // Test concurrent interactions i.e. interactions that can
-        // potentially gain focus at the same time.
-        // For this test permanent focus gain is requested by two usages.
-        // The focus request will be granted for both and on the second focus request focus
-        // lost will dispatched to the first focus listener listener.
-        testConcurrentInteractions(AudioManager.AUDIOFOCUS_GAIN, false);
-    }
-
-    @Test
-    public void concurrentInteractionsTransientGain_requestGrantedAndFocusLossTransientSent()
-            throws Exception {
-        // Test concurrent interactions i.e. interactions that can
-        // potentially gain focus at the same time.
-        // For this test permanent focus gain is requested by first usage and focus gain transient
-        // is requested by second usage.
-        // The focus request will be granted for both and on the second focus request focus
-        // lost transient will dispatched to the first focus listener listener.
-        testConcurrentInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, false);
-        // Repeat the test this time with pause for ducking on first listener
-        testConcurrentInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, true);
-    }
-
-    @Test
-    public void concurrentInteractionsTransientGainMayDuck_requestGrantedAndNoFocusLossSent()
-            throws Exception {
-        // Test concurrent interactions i.e. interactions that can
-        // potentially gain focus at the same time.
-        // For this test permanent focus gain is requested by first usage and focus gain transient
-        // may duck is requested by second usage.
-        // The focus request will be granted for both but no focus lost is sent to the first focus
-        // listener, as each usage actually has shared focus and  should play at the same time.
-        testConcurrentInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, false);
-        // Test the same behaviour but this time with pause for ducking on the first focus listener
-        testConcurrentInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, true);
-    }
-
-    private void testConcurrentInteractions(int gain, boolean pauseForDucking)
-            throws Exception {
-        // Test paired concurrent interactions i.e. interactions that can
-        // potentially gain focus at the same time.
-        int interaction = CarAudioFocus.INTERACTION_CONCURRENT;
-        testInteraction(ATTR_MEDIA, ATTR_DRIVE_DIR, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_MEDIA, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_MEDIA, ATTR_A11Y_NOTIFICATION, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_DRIVE_DIR, ATTR_MEDIA, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_DRIVE_DIR, ATTR_DRIVE_DIR, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_DRIVE_DIR, ATTR_RINGTONE, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_DRIVE_DIR, ATTR_ALARM, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_DRIVE_DIR, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_DRIVE_DIR, ATTR_A11Y_NOTIFICATION, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_A11Y, ATTR_MEDIA, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_A11Y, ATTR_A11Y, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_RINGTONE, ATTR_DRIVE_DIR, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_RINGTONE, ATTR_A11Y, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_RINGTONE, ATTR_RINGTONE, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_RINGTONE, ATTR_VOICE_COM, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_VOICE_COM, ATTR_DRIVE_DIR, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_VOICE_COM, ATTR_RINGTONE, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_VOICE_COM, ATTR_VOICE_COM, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_VOICE_COM, ATTR_ALARM, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_VOICE_COM, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_ALARM, ATTR_MEDIA, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ALARM, ATTR_DRIVE_DIR, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ALARM, ATTR_ALARM, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ALARM, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ALARM, ATTR_A11Y_NOTIFICATION, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_NOTIFICATION, ATTR_MEDIA, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NOTIFICATION, ATTR_DRIVE_DIR, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NOTIFICATION, ATTR_ALARM, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NOTIFICATION, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NOTIFICATION, ATTR_A11Y_NOTIFICATION, interaction, gain,
-                pauseForDucking);
-
-
-        testInteraction(ATTR_A11Y_NOTIFICATION, ATTR_MEDIA, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_A11Y_NOTIFICATION, ATTR_DRIVE_DIR, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_A11Y_NOTIFICATION, ATTR_ALARM, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_A11Y_NOTIFICATION, ATTR_NOTIFICATION, interaction, gain,
-                pauseForDucking);
-        testInteraction(ATTR_A11Y_NOTIFICATION, ATTR_A11Y_NOTIFICATION, interaction, gain,
-                pauseForDucking);
-    }
-
-    private void testExclusiveInteractions(int gain, boolean pauseForDucking)
-            throws Exception {
-
-        // Test exclusive interaction, interaction where each usage will not share focus with other
-        // another usage. As a result once focus is gained any current focus listener
-        // in this interaction will lose focus.
-        int interaction = CarAudioFocus.INTERACTION_EXCLUSIVE;
-        testInteraction(ATTR_MEDIA, ATTR_MEDIA, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_MEDIA, ATTR_A11Y, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_MEDIA, ATTR_RINGTONE, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_MEDIA, ATTR_VOICE_COM, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_MEDIA, ATTR_ALARM, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_DRIVE_DIR, ATTR_A11Y, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_DRIVE_DIR, ATTR_VOICE_COM, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_A11Y, ATTR_RINGTONE, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_A11Y, ATTR_VOICE_COM, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_ALARM, ATTR_A11Y, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ALARM, ATTR_RINGTONE, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_ALARM, ATTR_VOICE_COM, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_NOTIFICATION, ATTR_A11Y, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NOTIFICATION, ATTR_RINGTONE, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_NOTIFICATION, ATTR_VOICE_COM, interaction, gain, pauseForDucking);
-
-        testInteraction(ATTR_A11Y_NOTIFICATION, ATTR_A11Y, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_A11Y_NOTIFICATION, ATTR_RINGTONE, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_A11Y_NOTIFICATION, ATTR_VOICE_COM, interaction, gain, pauseForDucking);
-    }
-
-
-    /**
-     * Test paired usage interactions with gainType and pause instead ducking
-     * @param attributes1 Attributes of the first usage (first focus requester) in the interaction
-     * @param attributes2 Attributes of the second usage (second focus requester) in the interaction
-     * @param interaction type of interaction {@link CarAudioFocus.INTERACTION_REJECT},
-     * {@link CarAudioFocus.INTERACTION_EXCLUSIVE}, {@link CarAudioFocus.INTERACTION_CONCURRENT}
-     * @param gainType Type of gain {@link AudioManager.AUDIOFOCUS_GAIN} ,
-     * {@link CarAudioFocus.AUDIOFOCUS_GAIN_TRANSIENT},
-     * {@link CarAudioFocus.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}
-     * @param pauseForDucking flag to indicate if the first focus listener should pause
-     *                        instead of ducking
-     * @throws Exception
-     */
-    private void testInteraction(AudioAttributes attributes1,
-            AudioAttributes attributes2,
-            int interaction,
-            int gainType,
-            boolean pauseForDucking) throws Exception {
-
-        final FocusChangeListener focusChangeListener1 = new FocusChangeListener();
-        final AudioFocusRequest audioFocusRequest1 = new AudioFocusRequest
-                .Builder(AudioManager.AUDIOFOCUS_GAIN)
-                .setAudioAttributes(attributes1)
-                .setOnAudioFocusChangeListener(focusChangeListener1)
-                .setForceDucking(false)
-                .setWillPauseWhenDucked(pauseForDucking)
-                .build();
-
-        final FocusChangeListener focusChangeListener2 = new FocusChangeListener();
-        final AudioFocusRequest audioFocusRequest2 = new AudioFocusRequest
-                .Builder(gainType)
-                .setAudioAttributes(attributes2)
-                .setOnAudioFocusChangeListener(focusChangeListener2)
-                .setForceDucking(false)
-                .build();
-
-        int expectedLoss = 0;
-
-        // Each focus gain type will return a different focus lost type
-        switch (gainType) {
-            case AudioManager.AUDIOFOCUS_GAIN:
-                expectedLoss = AudioManager.AUDIOFOCUS_LOSS;
-                break;
-            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
-                expectedLoss = AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
-                break;
-            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
-                expectedLoss = AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
-                // Note loss or gain will not be sent as both can live concurrently
-                if (interaction == CarAudioFocus.INTERACTION_CONCURRENT && !pauseForDucking) {
-                    expectedLoss = AudioManager.AUDIOFOCUS_NONE;
-                }
-                break;
-        }
-
-        int secondRequestResultsExpected = AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
-
-        if (interaction == CarAudioFocus.INTERACTION_REJECT) {
-            secondRequestResultsExpected = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
-        }
-
-        int requestResult = mAudioManager.requestAudioFocus(audioFocusRequest1);
-        String message = "Focus gain request failed  for 1st "
-                + AudioAttributes.usageToString(attributes1.getUsage());
-        assertEquals(message, AudioManager.AUDIOFOCUS_REQUEST_GRANTED, requestResult);
-
-
-        requestResult = mAudioManager.requestAudioFocus(audioFocusRequest2);
-        message = "Focus gain request failed for 2nd "
-                + AudioAttributes.usageToString(attributes2.getUsage());
-        assertEquals(message, secondRequestResultsExpected, requestResult);
-
-        // If the results is rejected for second one we only have to clean up first
-        // as the second focus request is rejected
-        if (interaction == CarAudioFocus.INTERACTION_REJECT) {
-            requestResult = mAudioManager.abandonAudioFocusRequest(audioFocusRequest1);
-            message = "Focus loss request failed for 1st "
-                    + AudioAttributes.usageToString(attributes1.getUsage());
-            assertEquals(message, AudioManager.AUDIOFOCUS_REQUEST_GRANTED, requestResult);
-        }
-
-        // If exclusive we expect to lose focus on 1st one
-        // unless we have a concurrent interaction
-        if (interaction == CarAudioFocus.INTERACTION_EXCLUSIVE
-                || interaction == CarAudioFocus.INTERACTION_CONCURRENT) {
-            Thread.sleep(TEST_TIMING_TOLERANCE_MS);
-            message = "Focus change was not dispatched for 1st "
-                    + AudioAttributes.usageToString(ATTR_MEDIA.getUsage());
-            assertEquals(message, expectedLoss,
-                    focusChangeListener1.getFocusChangeAndReset());
-
-            requestResult = mAudioManager.abandonAudioFocusRequest(audioFocusRequest2);
-            message = "Focus loss request failed  for 2nd "
-                    + AudioAttributes.usageToString(ATTR_MEDIA.getUsage());
-            assertEquals(message, AudioManager.AUDIOFOCUS_REQUEST_GRANTED, requestResult);
-
-            // If the loss was transient then we should have received back on 1st
-            if ((gainType == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT
-                    || gainType == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)) {
-
-                // Since ducking and concurrent can exist together
-                // this needs to be skipped as the focus lost is not sent
-                if (!(interaction == CarAudioFocus.INTERACTION_CONCURRENT
-                        && gainType == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)) {
-                    Thread.sleep(TEST_TIMING_TOLERANCE_MS);
-                    message = "Focus change was not dispatched for 1st "
-                            + AudioAttributes.usageToString(ATTR_MEDIA.getUsage());
-                    assertEquals(message, AudioManager.AUDIOFOCUS_GAIN,
-                            focusChangeListener1.getFocusChangeAndReset());
-                }
-                // For concurrent focus interactions still needs to be released
-                message = "Focus loss request failed  for 1st  "
-                        + AudioAttributes.usageToString(attributes1.getUsage());
-                requestResult = mAudioManager.abandonAudioFocusRequest(audioFocusRequest1);
-                assertEquals(message, AudioManager.AUDIOFOCUS_REQUEST_GRANTED,
-                        requestResult);
-            }
-        }
-    }
-
-    /**
-     * Verifies usage can request audio focus and release it
-     * @param attribute usage attribute to request focus
-     * @throws Exception
-     */
-    private void requestAndLoseFocusForAttribute(AudioAttributes attribute)  throws Exception {
-        final FocusChangeListener focusChangeListener = new FocusChangeListener();
-        final AudioFocusRequest audioFocusRequest = new AudioFocusRequest
-                .Builder(AudioManager.AUDIOFOCUS_GAIN)
-                .setAudioAttributes(attribute)
-                .setOnAudioFocusChangeListener(focusChangeListener)
-                .setForceDucking(false)
-                .build();
-
-
-        int requestResult = mAudioManager.requestAudioFocus(audioFocusRequest);
-        String message = "Focus gain request failed  for "
-                + AudioAttributes.usageToString(attribute.getUsage());
-        assertEquals(message, AudioManager.AUDIOFOCUS_REQUEST_GRANTED, requestResult);
-
-        Thread.sleep(TEST_TIMING_TOLERANCE_MS);
-        // Verify no focus changed dispatched
-        message = "Focus change was dispatched for "
-                + AudioAttributes.usageToString(attribute.getUsage());
-        assertEquals(message, AudioManager.AUDIOFOCUS_NONE,
-                focusChangeListener.getFocusChangeAndReset());
-
-        requestResult = mAudioManager.abandonAudioFocusRequest(audioFocusRequest);
-        message = "Focus loss request failed  for "
-                + AudioAttributes.usageToString(attribute.getUsage());
-        assertEquals(message, AudioManager.AUDIOFOCUS_REQUEST_GRANTED, requestResult);
-    }
-
-    private static class FocusChangeListener implements AudioManager.OnAudioFocusChangeListener {
-        private final Object mLock = new Object();
-        private int mFocusChange = AudioManager.AUDIOFOCUS_NONE;
-
-        int getFocusChangeAndReset() {
-            final int change;
-            synchronized (mLock) {
-                change = mFocusChange;
-                mFocusChange = AudioManager.AUDIOFOCUS_NONE;
-            }
-            return change;
-        }
-
-        @Override
-        public void onAudioFocusChange(int focusChange) {
-            synchronized (mLock) {
-                mFocusChange = focusChange;
-            }
-        }
-    }
-}
diff --git a/tests/carservice_test/src/com/android/car/audio/CarAudioFocusTest.java b/tests/carservice_test/src/com/android/car/audio/CarAudioFocusTest.java
new file mode 100644
index 0000000..9b374c2
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/audio/CarAudioFocusTest.java
@@ -0,0 +1,842 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.audio;
+
+import static android.media.AudioManager.AUDIOFOCUS_GAIN;
+import static android.media.AudioManager.AUDIOFOCUS_LOSS;
+import static android.media.AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
+import static android.media.AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+import static android.media.AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.media.AudioAttributes;
+import android.media.AudioFocusRequest;
+import android.media.AudioManager;
+import android.os.Looper;
+import android.util.Log;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.RequiresDevice;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.car.R;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class CarAudioFocusTest {
+
+    private static final String TAG = CarAudioFocusTest.class.getSimpleName();
+    private static final boolean DEBUG = false;
+    private static final long TEST_TIMING_TOLERANCE_MS = 100;
+    private static final int TEST_TORELANCE_MAX_ITERATIONS = 5;
+    private static final int INTERACTION_REJECT = 0;  // Focus not granted
+    private static final int INTERACTION_EXCLUSIVE = 1;  // Focus granted, others loose focus
+    private static final int INTERACTION_CONCURRENT = 2;  // Focus granted, others keep focus
+
+    // CarAudioContext.INVALID
+    private static final AudioAttributes ATTR_INVALID = new AudioAttributes.Builder()
+            .setUsage(AudioAttributes.USAGE_VIRTUAL_SOURCE)
+            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
+            .build();
+    // CarAudioContext.MUSIC
+    private static final AudioAttributes ATTR_MEDIA = new AudioAttributes.Builder()
+            .setUsage(AudioAttributes.USAGE_MEDIA)
+            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
+            .build();
+    // CarAudioContext.NAVIGATION
+    private static final AudioAttributes ATTR_NAVIGATION = new AudioAttributes.Builder()
+            .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
+            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
+            .build();
+    // CarAudioContext.VOICE_COMMAND
+    private static final AudioAttributes ATTR_VOICE_COMMAND = new AudioAttributes.Builder()
+            .setUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY)
+            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
+            .build();
+    // CarAudioContext.CALL_RING
+    private static final AudioAttributes ATTR_CALL_RING = new AudioAttributes.Builder()
+            .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
+            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+            .build();
+    // CarAudioContext.CALL
+    private static final AudioAttributes ATTR_CALL = new AudioAttributes.Builder()
+            .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
+            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
+            .build();
+    // CarAudioContext.ALARM
+    private static final AudioAttributes ATTR_ALARM = new AudioAttributes.Builder()
+            .setUsage(AudioAttributes.USAGE_ALARM)
+            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+            .build();
+    // CarAudioContext.NOTIFICATION
+    private static final AudioAttributes ATTR_NOTIFICATION = new AudioAttributes.Builder()
+            .setUsage(AudioAttributes.USAGE_NOTIFICATION)
+            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+            .build();
+    // CarAudioContext.SYSTEM_SOUND
+    private static final AudioAttributes ATTR_SYSTEM_SOUND = new AudioAttributes.Builder()
+            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
+            .build();
+    // CarAudioContext.EMERGENCY
+    private static final AudioAttributes ATTR_EMERGENCY = new AudioAttributes.Builder()
+            .setSystemUsage(AudioAttributes.USAGE_EMERGENCY)
+            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+            .build();
+    // CarAudioContext.SAFETY
+    private static final AudioAttributes ATTR_SAFETY = new AudioAttributes.Builder()
+            .setSystemUsage(AudioAttributes.USAGE_SAFETY)
+            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+            .build();
+    // CarAudioContext.VEHICLE_STATUS
+    private static final AudioAttributes ATTR_VEHICLE_STATUS = new AudioAttributes.Builder()
+            .setSystemUsage(AudioAttributes.USAGE_VEHICLE_STATUS)
+            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+            .build();
+    // CarAudioContext.ANNOUNCEMENT
+    private static final AudioAttributes ATTR_ANNOUNCEMENT = new AudioAttributes.Builder()
+            .setSystemUsage(AudioAttributes.USAGE_ANNOUNCEMENT)
+            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
+            .build();
+
+    private final Set<AudioFocusRequest> mAudioFocusRequestsSet = new HashSet<>();
+
+    private AudioManager mAudioManager;
+
+    @Before
+    public void setUp() {
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        mAudioManager = (AudioManager) context.getSystemService(AudioManager.class);
+
+        boolean isDynamicRoutingEnabled = context.getResources().getBoolean(
+                R.bool.audioUseDynamicRouting);
+        assumeTrue("Dynamic routing must be enabled to run CarAudioFocusTests",
+                isDynamicRoutingEnabled);
+    }
+
+    @After
+    public void cleanUp() {
+        Iterator<AudioFocusRequest> iterator = mAudioFocusRequestsSet.iterator();
+        while (iterator.hasNext()) {
+            AudioFocusRequest request = iterator.next();
+            mAudioManager.abandonAudioFocusRequest(request);
+            if (DEBUG) {
+                Log.d(TAG, "cleanUp Removing: "
+                        + request.getAudioAttributes().usageToString());
+            }
+        }
+    }
+
+    @Test
+    public void requestAudioFocus_forRequestWithDelayedFocus_requestGranted() {
+        AudioFocusRequest mediaAudioFocusRequest = delayedFocusRequestBuilder().build();
+
+        mAudioFocusRequestsSet.add(mediaAudioFocusRequest);
+        assertThat(mAudioManager.requestAudioFocus(mediaAudioFocusRequest))
+                .isEqualTo(AUDIOFOCUS_REQUEST_GRANTED);
+    }
+
+    @Test
+    public void requestAudioFocus_forRequestWithDelayedFocus_whileOneCall_requestDelayed() {
+        AudioFocusRequest phoneAudioFocusRequest = phoneFocusRequestBuilder().build();
+
+        mAudioFocusRequestsSet.add(phoneAudioFocusRequest);
+        mAudioManager.requestAudioFocus(phoneAudioFocusRequest);
+
+        AudioFocusRequest mediaAudioFocusRequest = delayedFocusRequestBuilder().build();
+
+        mAudioFocusRequestsSet.add(mediaAudioFocusRequest);
+        assertThat(mAudioManager.requestAudioFocus(mediaAudioFocusRequest))
+                .isEqualTo(AUDIOFOCUS_REQUEST_DELAYED);
+    }
+
+    @Test
+    public void abandonAudioFocusRequest_forCall_whileFocusDelayed_focusGained() {
+        AudioFocusRequest phoneAudioFocusRequest = phoneFocusRequestBuilder().build();
+
+        mAudioManager.requestAudioFocus(phoneAudioFocusRequest);
+        mAudioFocusRequestsSet.add(phoneAudioFocusRequest);
+
+        FocusChangeListener mediaFocusChangeListener = new FocusChangeListener();
+        AudioFocusRequest mediaAudioFocusRequest = delayedFocusRequestBuilder()
+                .setOnAudioFocusChangeListener(mediaFocusChangeListener).build();
+
+        mAudioManager.requestAudioFocus(mediaAudioFocusRequest);
+        mAudioFocusRequestsSet.add(mediaAudioFocusRequest);
+
+        mAudioManager.abandonAudioFocusRequest(phoneAudioFocusRequest);
+        mAudioFocusRequestsSet.remove(phoneAudioFocusRequest);
+
+        assertThat(mediaFocusChangeListener
+                .waitForFocusChangeAndAssertFocus(TEST_TIMING_TOLERANCE_MS, AUDIOFOCUS_GAIN,
+                        "Could not gain focus for delayed focus after call ended"))
+                .isTrue();
+    }
+
+    @Test
+    public void abandonAudioFocusRequest_forDelayedRequest_whileOnCall_requestGranted() {
+        AudioFocusRequest phoneAudioFocusRequest = phoneFocusRequestBuilder().build();
+
+        mAudioManager.requestAudioFocus(phoneAudioFocusRequest);
+        mAudioFocusRequestsSet.add(phoneAudioFocusRequest);
+
+        AudioFocusRequest mediaAudioFocusRequest = delayedFocusRequestBuilder().build();
+
+        mAudioManager.requestAudioFocus(mediaAudioFocusRequest);
+        mAudioFocusRequestsSet.add(mediaAudioFocusRequest);
+
+        assertThat(mAudioManager.abandonAudioFocusRequest(mediaAudioFocusRequest))
+                .isEqualTo(AUDIOFOCUS_REQUEST_GRANTED);
+        mAudioFocusRequestsSet.remove(mediaAudioFocusRequest);
+    }
+
+    @Test
+    public void
+            abandonAudioFocusRequest_forCall_afterDelayedAbandon_delayedRequestDoesNotGainsFocus() {
+        AudioFocusRequest phoneAudioFocusRequest = phoneFocusRequestBuilder().build();
+
+        mAudioManager.requestAudioFocus(phoneAudioFocusRequest);
+        mAudioFocusRequestsSet.add(phoneAudioFocusRequest);
+
+        FocusChangeListener mediaFocusChangeListener = new FocusChangeListener();
+        AudioFocusRequest mediaAudioFocusRequest = delayedFocusRequestBuilder()
+                .setOnAudioFocusChangeListener(mediaFocusChangeListener).build();
+
+        mAudioManager.requestAudioFocus(mediaAudioFocusRequest);
+        mAudioFocusRequestsSet.add(mediaAudioFocusRequest);
+
+        mAudioManager.abandonAudioFocusRequest(mediaAudioFocusRequest);
+
+        mAudioManager.abandonAudioFocusRequest(phoneAudioFocusRequest);
+        mAudioFocusRequestsSet.remove(phoneAudioFocusRequest);
+
+        assertThat(mediaFocusChangeListener
+                .waitForFocusChangeAndAssertFocus(TEST_TIMING_TOLERANCE_MS, AUDIOFOCUS_GAIN,
+                        "Focus gained for abandoned delayed request after call"))
+                .isFalse();
+        mAudioFocusRequestsSet.remove(mediaAudioFocusRequest);
+    }
+
+    @Test
+    public void
+            requestAudioFocus_multipleTimesForSameDelayedRequest_delayedRequestDoesNotGainsFocus() {
+        AudioFocusRequest phoneAudioFocusRequest = phoneFocusRequestBuilder().build();
+
+        mAudioManager.requestAudioFocus(phoneAudioFocusRequest);
+        mAudioFocusRequestsSet.add(phoneAudioFocusRequest);
+
+        FocusChangeListener mediaFocusChangeListener = new FocusChangeListener();
+        AudioFocusRequest mediaAudioFocusRequest = delayedFocusRequestBuilder()
+                .setOnAudioFocusChangeListener(mediaFocusChangeListener).build();
+
+        mAudioManager.requestAudioFocus(mediaAudioFocusRequest);
+        mAudioFocusRequestsSet.add(mediaAudioFocusRequest);
+
+        mAudioManager.requestAudioFocus(mediaAudioFocusRequest);
+
+        assertThat(mediaFocusChangeListener
+                .waitForFocusChangeAndAssertFocus(TEST_TIMING_TOLERANCE_MS,
+                        AUDIOFOCUS_LOSS,
+                        "Focus gained for delayed request after same request"))
+                .isFalse();
+    }
+
+    @Test
+    public void requestAudioFocus_multipleTimesForSameFocusListener_requestFailed() {
+        AudioFocusRequest phoneAudioFocusRequest = phoneFocusRequestBuilder().build();
+
+        mAudioManager.requestAudioFocus(phoneAudioFocusRequest);
+        mAudioFocusRequestsSet.add(phoneAudioFocusRequest);
+
+        FocusChangeListener focusChangeLister = new FocusChangeListener();
+        AudioFocusRequest mediaAudioFocusRequest = delayedFocusRequestBuilder()
+                .setOnAudioFocusChangeListener(focusChangeLister).build();
+
+        mAudioManager.requestAudioFocus(mediaAudioFocusRequest);
+        mAudioFocusRequestsSet.add(mediaAudioFocusRequest);
+
+        AudioFocusRequest systemSoundRequest = delayedFocusRequestBuilder()
+                .setOnAudioFocusChangeListener(focusChangeLister)
+                .setAudioAttributes(ATTR_SYSTEM_SOUND).build();
+
+        mAudioFocusRequestsSet.add(systemSoundRequest);
+        assertThat(mAudioManager.requestAudioFocus(systemSoundRequest))
+                .isEqualTo(AUDIOFOCUS_REQUEST_FAILED);
+        mAudioFocusRequestsSet.remove(systemSoundRequest);
+    }
+
+    @Test
+    public void individualAttributeFocusRequest_focusRequestGranted() {
+        // Make sure each usage is able to request and release audio focus individually
+        requestAndLoseFocusForAttribute(ATTR_INVALID);
+        requestAndLoseFocusForAttribute(ATTR_MEDIA);
+        requestAndLoseFocusForAttribute(ATTR_NAVIGATION);
+        requestAndLoseFocusForAttribute(ATTR_VOICE_COMMAND);
+        requestAndLoseFocusForAttribute(ATTR_CALL_RING);
+        requestAndLoseFocusForAttribute(ATTR_CALL);
+        requestAndLoseFocusForAttribute(ATTR_ALARM);
+        requestAndLoseFocusForAttribute(ATTR_NOTIFICATION);
+        requestAndLoseFocusForAttribute(ATTR_SYSTEM_SOUND);
+        requestAndLoseFocusForAttribute(ATTR_EMERGENCY);
+        requestAndLoseFocusForAttribute(ATTR_SAFETY);
+        requestAndLoseFocusForAttribute(ATTR_VEHICLE_STATUS);
+        requestAndLoseFocusForAttribute(ATTR_ANNOUNCEMENT);
+    }
+
+    @Test
+    @FlakyTest
+    public void exclusiveInteractionsForFocusGain_requestGrantedAndFocusLossSent() {
+        // For each interaction the focus request is granted and on the second request
+        // focus lost is dispatched to the first focus listener
+
+        // Test Exclusive interactions with audio focus gain request without pause
+        // instead of ducking
+        testExclusiveInteractions(AUDIOFOCUS_GAIN, false);
+        // Test Exclusive interactions with audio focus gain request with pause instead of ducking
+        testExclusiveInteractions(AUDIOFOCUS_GAIN, true);
+    }
+
+    @Test
+    public void exclusiveInteractionsTransient_requestGrantedAndFocusLossSent() {
+        // For each interaction the focus request is granted and on the second request
+        // focus lost transient is dispatched to the first focus listener
+
+        // Test Exclusive interactions with audio focus gain transient request
+        // without pause instead of ducking
+        testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, false);
+        // Test Exclusive interactions with audio focus gain transient request
+        // with pause instead of ducking
+        testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, true);
+    }
+
+    @RequiresDevice
+    @Test
+    public void exclusiveInteractionsTransientMayDuck_requestGrantedAndFocusLossSent() {
+        // For each interaction the focus request is granted and on the second request
+        // focus lost transient is dispatched to the first focus listener
+
+        // Test exclusive interactions with audio focus transient may duck focus request
+        // without pause instead of ducking
+        testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, false);
+        // Test exclusive interactions with audio focus transient may duck focus request
+        // with pause instead of ducking
+        testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, true);
+    }
+
+    @RequiresDevice
+    @Test
+    public void rejectedInteractions_focusRequestRejected() {
+        // Test different paired interaction between different usages
+        // for each interaction pair the first focus request will be granted but the second
+        // will be rejected
+        int interaction = INTERACTION_REJECT;
+        int gain = AUDIOFOCUS_GAIN;
+        testInteraction(ATTR_INVALID, ATTR_INVALID, interaction, gain, false);
+        testInteraction(ATTR_INVALID, ATTR_MEDIA, interaction, gain, false);
+        testInteraction(ATTR_INVALID, ATTR_NAVIGATION, interaction, gain, false);
+        testInteraction(ATTR_INVALID, ATTR_VOICE_COMMAND, interaction, gain, false);
+        testInteraction(ATTR_INVALID, ATTR_CALL_RING, interaction, gain, false);
+        testInteraction(ATTR_INVALID, ATTR_CALL, interaction, gain, false);
+        testInteraction(ATTR_INVALID, ATTR_ALARM, interaction, gain, false);
+        testInteraction(ATTR_INVALID, ATTR_NOTIFICATION, interaction, gain, false);
+        testInteraction(ATTR_INVALID, ATTR_SYSTEM_SOUND, interaction, gain, false);
+        testInteraction(ATTR_INVALID, ATTR_VEHICLE_STATUS, interaction, gain, false);
+        testInteraction(ATTR_INVALID, ATTR_ANNOUNCEMENT, interaction, gain, false);
+
+        testInteraction(ATTR_MEDIA, ATTR_INVALID, interaction, gain, false);
+
+        testInteraction(ATTR_NAVIGATION, ATTR_INVALID, interaction, gain, false);
+
+        testInteraction(ATTR_VOICE_COMMAND, ATTR_INVALID, interaction, gain, false);
+        testInteraction(ATTR_VOICE_COMMAND, ATTR_NAVIGATION, interaction, gain, false);
+        testInteraction(ATTR_VOICE_COMMAND, ATTR_NOTIFICATION, interaction, gain, false);
+        testInteraction(ATTR_VOICE_COMMAND, ATTR_SYSTEM_SOUND, interaction, gain, false);
+        testInteraction(ATTR_VOICE_COMMAND, ATTR_ANNOUNCEMENT, interaction, gain, false);
+
+        testInteraction(ATTR_CALL_RING, ATTR_INVALID, interaction, gain, false);
+        testInteraction(ATTR_CALL_RING, ATTR_MEDIA, interaction, gain, false);
+        testInteraction(ATTR_CALL_RING, ATTR_ALARM, interaction, gain, false);
+        testInteraction(ATTR_CALL_RING, ATTR_NOTIFICATION, interaction, gain, false);
+        testInteraction(ATTR_CALL_RING, ATTR_ANNOUNCEMENT, interaction, gain, false);
+
+        testInteraction(ATTR_CALL, ATTR_INVALID, interaction, gain, false);
+        testInteraction(ATTR_CALL, ATTR_MEDIA, interaction, gain, false);
+        testInteraction(ATTR_CALL, ATTR_VOICE_COMMAND, interaction, gain, false);
+        testInteraction(ATTR_CALL, ATTR_SYSTEM_SOUND, interaction, gain, false);
+        testInteraction(ATTR_CALL, ATTR_ANNOUNCEMENT, interaction, gain, false);
+
+        testInteraction(ATTR_ALARM, ATTR_INVALID, interaction, gain, false);
+        testInteraction(ATTR_ALARM, ATTR_ANNOUNCEMENT, interaction, gain, false);
+
+        testInteraction(ATTR_NOTIFICATION, ATTR_INVALID, interaction, gain, false);
+
+        testInteraction(ATTR_SYSTEM_SOUND, ATTR_INVALID, interaction, gain, false);
+
+        testInteraction(ATTR_EMERGENCY, ATTR_INVALID, interaction, gain, false);
+        testInteraction(ATTR_EMERGENCY, ATTR_MEDIA, interaction, gain, false);
+        testInteraction(ATTR_EMERGENCY, ATTR_NAVIGATION, interaction, gain, false);
+        testInteraction(ATTR_EMERGENCY, ATTR_VOICE_COMMAND, interaction, gain, false);
+        testInteraction(ATTR_EMERGENCY, ATTR_CALL_RING, interaction, gain, false);
+        testInteraction(ATTR_EMERGENCY, ATTR_ALARM, interaction, gain, false);
+        testInteraction(ATTR_EMERGENCY, ATTR_NOTIFICATION, interaction, gain, false);
+        testInteraction(ATTR_EMERGENCY, ATTR_SYSTEM_SOUND, interaction, gain, false);
+        testInteraction(ATTR_EMERGENCY, ATTR_VEHICLE_STATUS, interaction, gain, false);
+        testInteraction(ATTR_EMERGENCY, ATTR_ANNOUNCEMENT, interaction, gain, false);
+
+        testInteraction(ATTR_SAFETY, ATTR_INVALID, interaction, gain, false);
+
+        testInteraction(ATTR_VEHICLE_STATUS, ATTR_INVALID, interaction, gain, false);
+
+        testInteraction(ATTR_ANNOUNCEMENT, ATTR_INVALID, interaction, gain, false);
+    }
+
+    @Test
+    public void concurrentInteractionsFocusGain_requestGrantedAndFocusLossSent() {
+        // Test concurrent interactions i.e. interactions that can
+        // potentially gain focus at the same time.
+        // For this test permanent focus gain is requested by two usages.
+        // The focus request will be granted for both and on the second focus request focus
+        // lost will dispatched to the first focus listener listener.
+        testConcurrentInteractions(AUDIOFOCUS_GAIN, false);
+    }
+
+    @Test
+    @FlakyTest
+    public void concurrentInteractionsTransientGain_requestGrantedAndFocusLossTransientSent() {
+        // Test concurrent interactions i.e. interactions that can
+        // potentially gain focus at the same time.
+        // For this test permanent focus gain is requested by first usage and focus gain transient
+        // is requested by second usage.
+        // The focus request will be granted for both and on the second focus request focus
+        // lost transient will dispatched to the first focus listener listener.
+        testConcurrentInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, false);
+        // Repeat the test this time with pause for ducking on first listener
+        testConcurrentInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, true);
+    }
+
+    @RequiresDevice
+    @Test
+    public void concurrentInteractionsTransientGainMayDuck_requestGrantedAndNoFocusLossSent() {
+        // Test concurrent interactions i.e. interactions that can
+        // potentially gain focus at the same time.
+        // For this test permanent focus gain is requested by first usage and focus gain transient
+        // may duck is requested by second usage.
+        // The focus request will be granted for both but no focus lost is sent to the first focus
+        // listener, as each usage actually has shared focus and  should play at the same time.
+        testConcurrentInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, false);
+        // Test the same behaviour but this time with pause for ducking on the first focus listener
+        testConcurrentInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, true);
+    }
+
+    private void testConcurrentInteractions(int gain, boolean pauseForDucking) {
+        // Test paired concurrent interactions i.e. interactions that can
+        // potentially gain focus at the same time.
+        int interaction = INTERACTION_CONCURRENT;
+        testInteraction(ATTR_MEDIA, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_MEDIA, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_MEDIA, ATTR_SYSTEM_SOUND, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_MEDIA, ATTR_SAFETY, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_MEDIA, ATTR_VEHICLE_STATUS, interaction, gain, pauseForDucking);
+
+        testInteraction(ATTR_NAVIGATION, ATTR_MEDIA, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_NAVIGATION, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_NAVIGATION, ATTR_CALL_RING, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_NAVIGATION, ATTR_ALARM, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_NAVIGATION, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_NAVIGATION, ATTR_SYSTEM_SOUND, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_NAVIGATION, ATTR_SAFETY, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_NAVIGATION, ATTR_VEHICLE_STATUS, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_NAVIGATION, ATTR_ANNOUNCEMENT, interaction, gain, pauseForDucking);
+
+        testInteraction(ATTR_VOICE_COMMAND, ATTR_MEDIA, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_VOICE_COMMAND, ATTR_VOICE_COMMAND, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_VOICE_COMMAND, ATTR_SAFETY, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_VOICE_COMMAND, ATTR_VEHICLE_STATUS, interaction, gain,
+                pauseForDucking);
+
+        testInteraction(ATTR_CALL_RING, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_CALL_RING, ATTR_VOICE_COMMAND, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_CALL_RING, ATTR_CALL_RING, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_CALL_RING, ATTR_CALL, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_CALL_RING, ATTR_SAFETY, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_CALL_RING, ATTR_VEHICLE_STATUS, interaction, gain, pauseForDucking);
+
+        testInteraction(ATTR_CALL, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_CALL, ATTR_CALL_RING, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_CALL, ATTR_CALL, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_CALL, ATTR_ALARM, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_CALL, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_CALL, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_CALL, ATTR_SAFETY, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_CALL, ATTR_VEHICLE_STATUS, interaction, gain, pauseForDucking);
+
+        testInteraction(ATTR_ALARM, ATTR_MEDIA, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_ALARM, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_ALARM, ATTR_ALARM, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_ALARM, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_ALARM, ATTR_SYSTEM_SOUND, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_ALARM, ATTR_SAFETY, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_ALARM, ATTR_VEHICLE_STATUS, interaction, gain, pauseForDucking);
+
+        testInteraction(ATTR_NOTIFICATION, ATTR_MEDIA, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_NOTIFICATION, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_NOTIFICATION, ATTR_ALARM, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_NOTIFICATION, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_NOTIFICATION, ATTR_SYSTEM_SOUND, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_NOTIFICATION, ATTR_SAFETY, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_NOTIFICATION, ATTR_VEHICLE_STATUS, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_NOTIFICATION, ATTR_ANNOUNCEMENT, interaction, gain, pauseForDucking);
+
+        testInteraction(ATTR_SYSTEM_SOUND, ATTR_MEDIA, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_SYSTEM_SOUND, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_SYSTEM_SOUND, ATTR_ALARM, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_SYSTEM_SOUND, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_SYSTEM_SOUND, ATTR_SYSTEM_SOUND, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_SYSTEM_SOUND, ATTR_SAFETY, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_SYSTEM_SOUND, ATTR_VEHICLE_STATUS, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_SYSTEM_SOUND, ATTR_ANNOUNCEMENT, interaction, gain, pauseForDucking);
+
+        testInteraction(ATTR_EMERGENCY, ATTR_CALL, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_EMERGENCY, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_EMERGENCY, ATTR_SAFETY, interaction, gain, pauseForDucking);
+
+        testInteraction(ATTR_SAFETY, ATTR_MEDIA, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_SAFETY, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_SAFETY, ATTR_CALL_RING, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_SAFETY, ATTR_CALL, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_SAFETY, ATTR_ALARM, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_SAFETY, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_SAFETY, ATTR_SYSTEM_SOUND, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_SAFETY, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_SAFETY, ATTR_SAFETY, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_SAFETY, ATTR_VEHICLE_STATUS, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_SAFETY, ATTR_ANNOUNCEMENT, interaction, gain, pauseForDucking);
+
+        testInteraction(ATTR_VEHICLE_STATUS, ATTR_MEDIA, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_VEHICLE_STATUS, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_VEHICLE_STATUS, ATTR_CALL_RING, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_VEHICLE_STATUS, ATTR_CALL, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_VEHICLE_STATUS, ATTR_ALARM, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_VEHICLE_STATUS, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_VEHICLE_STATUS, ATTR_SYSTEM_SOUND, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_VEHICLE_STATUS, ATTR_SAFETY, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_VEHICLE_STATUS, ATTR_VEHICLE_STATUS, interaction, gain,
+                pauseForDucking);
+        testInteraction(ATTR_VEHICLE_STATUS, ATTR_ANNOUNCEMENT, interaction, gain, pauseForDucking);
+
+        testInteraction(ATTR_ANNOUNCEMENT, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_ANNOUNCEMENT, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_ANNOUNCEMENT, ATTR_SYSTEM_SOUND, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_ANNOUNCEMENT, ATTR_SAFETY, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_ANNOUNCEMENT, ATTR_VEHICLE_STATUS, interaction, gain, pauseForDucking);
+    }
+
+    private void testExclusiveInteractions(int gain, boolean pauseForDucking) {
+        // Test exclusive interaction, interaction where each usage will not share focus with other
+        // another usage. As a result once focus is gained any current focus listener
+        // in this interaction will lose focus.
+        int interaction = INTERACTION_EXCLUSIVE;
+
+        testInteraction(ATTR_INVALID, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_INVALID, ATTR_SAFETY, interaction, gain, pauseForDucking);
+
+        testInteraction(ATTR_MEDIA, ATTR_MEDIA, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_MEDIA, ATTR_VOICE_COMMAND, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_MEDIA, ATTR_CALL_RING, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_MEDIA, ATTR_CALL, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_MEDIA, ATTR_ALARM, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_MEDIA, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_MEDIA, ATTR_ANNOUNCEMENT, interaction, gain, pauseForDucking);
+
+        testInteraction(ATTR_NAVIGATION, ATTR_VOICE_COMMAND, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_NAVIGATION, ATTR_CALL, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_NAVIGATION, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
+
+        testInteraction(ATTR_VOICE_COMMAND, ATTR_CALL_RING, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_VOICE_COMMAND, ATTR_CALL, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_VOICE_COMMAND, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
+
+        testInteraction(ATTR_CALL_RING, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
+
+        testInteraction(ATTR_ALARM, ATTR_VOICE_COMMAND, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_ALARM, ATTR_CALL_RING, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_ALARM, ATTR_CALL, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_ALARM, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
+
+        testInteraction(ATTR_NOTIFICATION, ATTR_VOICE_COMMAND, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_NOTIFICATION, ATTR_CALL_RING, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_NOTIFICATION, ATTR_CALL, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_NOTIFICATION, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
+
+        testInteraction(ATTR_SYSTEM_SOUND, ATTR_VOICE_COMMAND, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_SYSTEM_SOUND, ATTR_CALL_RING, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_SYSTEM_SOUND, ATTR_CALL, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_SYSTEM_SOUND, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
+
+        testInteraction(ATTR_VEHICLE_STATUS, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
+
+        testInteraction(ATTR_ANNOUNCEMENT, ATTR_MEDIA, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_ANNOUNCEMENT, ATTR_VOICE_COMMAND, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_ANNOUNCEMENT, ATTR_CALL_RING, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_ANNOUNCEMENT, ATTR_CALL, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_ANNOUNCEMENT, ATTR_ALARM, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_ANNOUNCEMENT, ATTR_EMERGENCY, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_ANNOUNCEMENT, ATTR_ANNOUNCEMENT, interaction, gain, pauseForDucking);
+    }
+
+
+    /**
+     * Test paired usage interactions with gainType and pause instead ducking
+     *
+     * @param attributes1     Attributes of the first usage (first focus requester) in the
+     *                        interaction
+     * @param attributes2     Attributes of the second usage (second focus requester) in the
+     *                        interaction
+     * @param interaction     type of interaction {@link INTERACTION_REJECT}, {@link
+     *                        INTERACTION_EXCLUSIVE}, {@link INTERACTION_CONCURRENT}
+     * @param gainType        Type of gain {@link AUDIOFOCUS_GAIN} , {@link
+     *                        CarAudioFocus.AUDIOFOCUS_GAIN_TRANSIENT}, {@link
+     *                        CarAudioFocus.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}
+     * @param pauseForDucking flag to indicate if the first focus listener should pause instead of
+     *                        ducking
+     * @throws Exception
+     */
+    private void testInteraction(AudioAttributes attributes1,
+            AudioAttributes attributes2,
+            int interaction,
+            int gainType,
+            boolean pauseForDucking) {
+        final FocusChangeListener focusChangeListener1 = new FocusChangeListener();
+        final AudioFocusRequest audioFocusRequest1 = new AudioFocusRequest
+                .Builder(AUDIOFOCUS_GAIN)
+                .setAudioAttributes(attributes1)
+                .setOnAudioFocusChangeListener(focusChangeListener1)
+                .setForceDucking(false)
+                .setWillPauseWhenDucked(pauseForDucking)
+                .build();
+
+        final FocusChangeListener focusChangeListener2 = new FocusChangeListener();
+        final AudioFocusRequest audioFocusRequest2 = new AudioFocusRequest
+                .Builder(gainType)
+                .setAudioAttributes(attributes2)
+                .setOnAudioFocusChangeListener(focusChangeListener2)
+                .setForceDucking(false)
+                .build();
+
+        int expectedLoss = 0;
+
+        // Each focus gain type will return a different focus lost type
+        switch (gainType) {
+            case AUDIOFOCUS_GAIN:
+                expectedLoss = AUDIOFOCUS_LOSS;
+                break;
+            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
+                expectedLoss = AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
+                break;
+            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
+                expectedLoss = AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
+                // Note loss or gain will not be sent as both can live concurrently
+                if (interaction == INTERACTION_CONCURRENT && !pauseForDucking) {
+                    expectedLoss = AudioManager.AUDIOFOCUS_NONE;
+                }
+                break;
+        }
+
+        int secondRequestResultsExpected = AUDIOFOCUS_REQUEST_GRANTED;
+
+        if (interaction == INTERACTION_REJECT) {
+            secondRequestResultsExpected = AUDIOFOCUS_REQUEST_FAILED;
+        }
+
+        int requestResult = mAudioManager.requestAudioFocus(audioFocusRequest1);
+        String message = "Focus gain request failed  for 1st "
+                + AudioAttributes.usageToString(attributes1.getSystemUsage());
+        assertEquals(message, AUDIOFOCUS_REQUEST_GRANTED, requestResult);
+        mAudioFocusRequestsSet.add(audioFocusRequest1);
+
+        requestResult = mAudioManager.requestAudioFocus(audioFocusRequest2);
+        message = "Focus gain request failed for 2nd "
+                + AudioAttributes.usageToString(attributes2.getSystemUsage());
+        assertEquals(message, secondRequestResultsExpected, requestResult);
+        mAudioFocusRequestsSet.add(audioFocusRequest2);
+
+        // If the results is rejected for second one we only have to clean up first
+        // as the second focus request is rejected
+        if (interaction == INTERACTION_REJECT) {
+            requestResult = mAudioManager.abandonAudioFocusRequest(audioFocusRequest1);
+            mAudioFocusRequestsSet.clear();
+            message = "Focus loss request failed for 1st "
+                    + AudioAttributes.usageToString(attributes1.getSystemUsage());
+            assertEquals(message, AUDIOFOCUS_REQUEST_GRANTED, requestResult);
+        }
+
+        // If exclusive we expect to lose focus on 1st one
+        // unless we have a concurrent interaction
+        if (interaction == INTERACTION_EXCLUSIVE || interaction == INTERACTION_CONCURRENT) {
+            message = "Focus change was not dispatched for 1st "
+                    + AudioAttributes.usageToString(attributes1.getSystemUsage());
+            boolean shouldStop = false;
+            int counter = 0;
+            while (!shouldStop && counter++ < TEST_TORELANCE_MAX_ITERATIONS) {
+                boolean gainedFocusLoss = focusChangeListener1.waitForFocusChangeAndAssertFocus(
+                        TEST_TIMING_TOLERANCE_MS, expectedLoss, message);
+                shouldStop = gainedFocusLoss
+                        || (expectedLoss == AudioManager.AUDIOFOCUS_NONE);
+            }
+            assertThat(shouldStop).isTrue();
+            focusChangeListener1.resetFocusChangeAndWait();
+
+            if (expectedLoss == AUDIOFOCUS_LOSS) {
+                mAudioFocusRequestsSet.remove(audioFocusRequest1);
+            }
+            requestResult = mAudioManager.abandonAudioFocusRequest(audioFocusRequest2);
+            mAudioFocusRequestsSet.remove(audioFocusRequest2);
+            message = "Focus loss request failed  for 2nd "
+                    + AudioAttributes.usageToString(attributes2.getSystemUsage());
+            assertEquals(message, AUDIOFOCUS_REQUEST_GRANTED, requestResult);
+
+
+            // If the loss was transient then we should have received back on 1st
+            if ((gainType == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT
+                    || gainType == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)) {
+
+                // Since ducking and concurrent can exist together
+                // this needs to be skipped as the focus lost is not sent
+                if (!(interaction == INTERACTION_CONCURRENT
+                        && gainType == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)) {
+                    message = "Focus change was not dispatched for 1st "
+                            + AudioAttributes.usageToString(attributes1.getSystemUsage());
+
+                    boolean focusGained = false;
+                    int count = 0;
+                    while (!focusGained && count++ < TEST_TORELANCE_MAX_ITERATIONS) {
+                        focusGained = focusChangeListener1.waitForFocusChangeAndAssertFocus(
+                                TEST_TIMING_TOLERANCE_MS,
+                                AUDIOFOCUS_GAIN, message);
+                    }
+                    assertThat(focusGained).isTrue();
+                    focusChangeListener1.resetFocusChangeAndWait();
+                }
+                // For concurrent focus interactions still needs to be released
+                message = "Focus loss request failed  for 1st  "
+                        + AudioAttributes.usageToString(attributes1.getSystemUsage());
+                requestResult = mAudioManager.abandonAudioFocusRequest(audioFocusRequest1);
+                mAudioFocusRequestsSet.remove(audioFocusRequest1);
+                assertEquals(message, AUDIOFOCUS_REQUEST_GRANTED,
+                        requestResult);
+            }
+        }
+    }
+
+    /**
+     * Verifies usage can request audio focus and release it
+     *
+     * @param attribute usage attribute to request focus
+     */
+    private void requestAndLoseFocusForAttribute(AudioAttributes attribute) {
+        FocusChangeListener focusChangeListener = new FocusChangeListener();
+        AudioFocusRequest audioFocusRequest = new AudioFocusRequest
+                .Builder(AUDIOFOCUS_GAIN)
+                .setAudioAttributes(attribute)
+                .setOnAudioFocusChangeListener(focusChangeListener)
+                .setForceDucking(false)
+                .build();
+
+
+        int requestResult = mAudioManager.requestAudioFocus(audioFocusRequest);
+        String message = "Focus gain request failed  for "
+                + AudioAttributes.usageToString(attribute.getSystemUsage());
+        assertEquals(message, AUDIOFOCUS_REQUEST_GRANTED, requestResult);
+        mAudioFocusRequestsSet.add(audioFocusRequest);
+
+        // Verify no focus changed dispatched
+        message = "Focus change was dispatched for "
+                + AudioAttributes.usageToString(attribute.getSystemUsage());
+
+        assertThat(focusChangeListener.waitForFocusChangeAndAssertFocus(
+                TEST_TIMING_TOLERANCE_MS, AudioManager.AUDIOFOCUS_NONE, message)).isFalse();
+        focusChangeListener.resetFocusChangeAndWait();
+
+        requestResult = mAudioManager.abandonAudioFocusRequest(audioFocusRequest);
+        message = "Focus loss request failed  for "
+                + AudioAttributes.usageToString(attribute.getSystemUsage());
+        assertEquals(message, AUDIOFOCUS_REQUEST_GRANTED, requestResult);
+        mAudioFocusRequestsSet.remove(audioFocusRequest);
+    }
+
+    private static AudioFocusRequest.Builder delayedFocusRequestBuilder() {
+        AudioManager.OnAudioFocusChangeListener listener = new FocusChangeListener();
+        return new AudioFocusRequest.Builder(AUDIOFOCUS_GAIN)
+                .setAcceptsDelayedFocusGain(true).setAudioAttributes(ATTR_MEDIA)
+                .setOnAudioFocusChangeListener(listener);
+    }
+
+    private static AudioFocusRequest.Builder phoneFocusRequestBuilder() {
+        AudioManager.OnAudioFocusChangeListener listener = new FocusChangeListener();
+        return new AudioFocusRequest.Builder(AUDIOFOCUS_GAIN)
+                .setAudioAttributes(ATTR_CALL)
+                .setOnAudioFocusChangeListener(listener);
+    }
+
+    private static class FocusChangeListener implements AudioManager.OnAudioFocusChangeListener {
+        private final Semaphore mChangeEventSignal = new Semaphore(0);
+        private int mFocusChange = AudioManager.AUDIOFOCUS_NONE;
+
+        private boolean waitForFocusChangeAndAssertFocus(long timeoutMs, int expectedFocus,
+                String message) {
+            boolean acquired = false;
+            try {
+                acquired = mChangeEventSignal.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
+            } catch (Exception ignored) {
+
+            }
+            if (acquired) {
+                assertEquals(message, expectedFocus, mFocusChange);
+            }
+            return acquired;
+        }
+
+        private void resetFocusChangeAndWait() {
+            mFocusChange = AudioManager.AUDIOFOCUS_NONE;
+            mChangeEventSignal.drainPermits();
+        }
+
+        @Override
+        public void onAudioFocusChange(int focusChange) {
+            // should be dispatched to main thread.
+            assertThat(Looper.getMainLooper()).isEqualTo(Looper.myLooper());
+            mFocusChange = focusChange;
+            mChangeEventSignal.release();
+        }
+    }
+}
diff --git a/tests/carservice_test/src/com/android/car/audio/CarAudioZoneTest.java b/tests/carservice_test/src/com/android/car/audio/CarAudioZoneTest.java
new file mode 100644
index 0000000..74d9781
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/audio/CarAudioZoneTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.audio;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.expectThrows;
+
+import android.car.media.CarAudioManager;
+import android.hardware.automotive.audiocontrol.V1_0.ContextNumber;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CarAudioZoneTest {
+    private static final String MUSIC_ADDRESS = "bus0_music";
+    private static final String NAV_ADDRESS = "bus1_nav";
+
+    @Mock
+    private CarVolumeGroup mMockMusicGroup;
+    @Mock
+    private CarVolumeGroup mMockNavGroup;
+    private CarAudioZone mTestAudioZone =
+            new CarAudioZone(CarAudioManager.PRIMARY_AUDIO_ZONE, "Primary zone");
+    @Before
+    public void setUp() {
+        when(mMockMusicGroup.getAddressForContext(ContextNumber.MUSIC)).thenReturn(MUSIC_ADDRESS);
+        when(mMockMusicGroup.getContexts()).thenReturn(new int[]{ContextNumber.MUSIC});
+
+        when(mMockNavGroup.getAddressForContext(ContextNumber.NAVIGATION)).thenReturn(NAV_ADDRESS);
+        when(mMockNavGroup.getContexts()).thenReturn(new int[]{ContextNumber.NAVIGATION});
+    }
+
+    @Test
+    public void getAddressForContext_returnsExpectedDeviceAddress() {
+        mTestAudioZone.addVolumeGroup(mMockMusicGroup);
+        mTestAudioZone.addVolumeGroup(mMockNavGroup);
+
+        String musicAddress = mTestAudioZone.getAddressForContext(ContextNumber.MUSIC);
+        assertThat(musicAddress).isEqualTo(MUSIC_ADDRESS);
+
+        String navAddress = mTestAudioZone.getAddressForContext(ContextNumber.NAVIGATION);
+        assertThat(navAddress).matches(NAV_ADDRESS);
+    }
+
+    @Test
+    public void getAddressForContext_throwsOnInvalidContext() {
+        IllegalArgumentException thrown =
+                expectThrows(IllegalArgumentException.class,
+                        () -> mTestAudioZone.getAddressForContext(ContextNumber.INVALID));
+
+        assertThat(thrown).hasMessageThat().contains("audioContext 0 is invalid");
+    }
+
+    @Test
+    public void getAddressForContext_throwsOnNonExistentContext() {
+        IllegalStateException thrown =
+                expectThrows(IllegalStateException.class,
+                        () -> mTestAudioZone.getAddressForContext(ContextNumber.MUSIC));
+
+        assertThat(thrown).hasMessageThat().contains("Could not find output device in zone");
+    }
+}
diff --git a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperLegacyTest.java b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperLegacyTest.java
new file mode 100644
index 0000000..170ae8c
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperLegacyTest.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.audio;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.expectThrows;
+
+import android.annotation.XmlRes;
+import android.content.Context;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.car.R;
+import com.android.car.audio.hal.AudioControlWrapperV1;
+
+import com.google.common.collect.Lists;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+@RunWith(AndroidJUnit4.class)
+public class CarAudioZonesHelperLegacyTest {
+    @Rule
+    public final MockitoRule rule = MockitoJUnit.rule();
+
+    @Mock
+    private AudioControlWrapperV1 mMockAudioControlWrapper;
+    @Mock
+    private CarAudioSettings mMockCarAudioSettings;
+
+    private static final int INVALID_BUS = -1;
+    private final Context mContext = ApplicationProvider.getApplicationContext();
+    private final @XmlRes int mCarVolumeGroups = R.xml.test_car_volume_groups;
+
+    @Test
+    public void constructor_checksForNoDuplicateBusNumbers() {
+        List<CarAudioDeviceInfo> carAudioDeviceInfos = getCarAudioDeviceInfoWithDuplicateBuses();
+
+        RuntimeException exception = expectThrows(RuntimeException.class,
+                () -> new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
+                        carAudioDeviceInfos, mMockAudioControlWrapper, mMockCarAudioSettings));
+
+        assertThat(exception.getMessage()).contains("Two addresses map to same bus number:");
+    }
+
+    @Test
+    public void constructor_throwsIfLegacyContextNotAssignedToBus() throws Exception {
+        List<CarAudioDeviceInfo> carAudioDeviceInfos = getValidCarAudioDeviceInfos();
+
+        when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(INVALID_BUS);
+
+        RuntimeException exception = expectThrows(RuntimeException.class,
+                () -> new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
+                carAudioDeviceInfos, mMockAudioControlWrapper, mMockCarAudioSettings));
+
+        assertThat(exception.getMessage()).contains("Invalid bus -1 was associated with context");
+    }
+
+    @Test
+    public void loadAudioZones_succeeds() throws Exception {
+        List<CarAudioDeviceInfo> carAudioDeviceInfos = getValidCarAudioDeviceInfos();
+        when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(1);
+
+        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
+                carAudioDeviceInfos, mMockAudioControlWrapper, mMockCarAudioSettings);
+
+        CarAudioZone[] zones = helper.loadAudioZones();
+
+        assertThat(zones).hasLength(1);
+    }
+
+    @Test
+    public void loadAudioZones_parsesAllVolumeGroups() throws Exception {
+        List<CarAudioDeviceInfo> carAudioDeviceInfos = getValidCarAudioDeviceInfos();
+
+        when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(1);
+
+        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
+                carAudioDeviceInfos, mMockAudioControlWrapper, mMockCarAudioSettings);
+
+        CarAudioZone[] zones = helper.loadAudioZones();
+        CarVolumeGroup[] volumeGroups = zones[0].getVolumeGroups();
+        assertThat(volumeGroups).hasLength(2);
+    }
+
+    @Test
+    public void loadAudioZones_associatesLegacyContextsWithCorrectBuses() throws Exception {
+        List<CarAudioDeviceInfo> carAudioDeviceInfos = getValidCarAudioDeviceInfos();
+
+        when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(2);
+        when(mMockAudioControlWrapper.getBusForContext(CarAudioContext.MUSIC)).thenReturn(1);
+
+        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
+                carAudioDeviceInfos, mMockAudioControlWrapper, mMockCarAudioSettings);
+
+        CarAudioZone[] zones = helper.loadAudioZones();
+
+        CarVolumeGroup[] volumeGroups = zones[0].getVolumeGroups();
+        CarVolumeGroup mediaVolumeGroup = volumeGroups[0];
+        List<Integer> contexts = IntStream.of(mediaVolumeGroup.getContexts()).boxed().collect(
+                Collectors.toList());
+        assertThat(contexts).contains(CarAudioContext.MUSIC);
+
+        CarVolumeGroup secondVolumeGroup = volumeGroups[1];
+        List<Integer> secondContexts = IntStream.of(secondVolumeGroup.getContexts()).boxed()
+                .collect(Collectors.toList());
+        assertThat(secondContexts).containsAllOf(CarAudioContext.NAVIGATION,
+                CarAudioContext.VOICE_COMMAND, CarAudioContext.CALL_RING, CarAudioContext.CALL,
+                CarAudioContext.ALARM, CarAudioContext.NOTIFICATION, CarAudioContext.SYSTEM_SOUND);
+
+    }
+
+    @Test
+    public void loadAudioZones_associatesNonLegacyContextsWithMediaBus() throws Exception {
+        List<CarAudioDeviceInfo> carAudioDeviceInfos = getValidCarAudioDeviceInfos();
+        when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(2);
+        when(mMockAudioControlWrapper.getBusForContext(CarAudioService.DEFAULT_AUDIO_CONTEXT))
+                .thenReturn(1);
+
+        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
+                carAudioDeviceInfos, mMockAudioControlWrapper, mMockCarAudioSettings);
+
+        CarAudioZone[] zones = helper.loadAudioZones();
+
+        CarVolumeGroup[] volumeGroups = zones[0].getVolumeGroups();
+        CarVolumeGroup mediaVolumeGroup = volumeGroups[0];
+        List<Integer> contexts = IntStream.of(mediaVolumeGroup.getContexts()).boxed().collect(
+                Collectors.toList());
+        assertThat(contexts).containsAllOf(CarAudioService.DEFAULT_AUDIO_CONTEXT,
+                CarAudioContext.EMERGENCY, CarAudioContext.VEHICLE_STATUS,
+                CarAudioContext.ANNOUNCEMENT);
+    }
+
+    private List<CarAudioDeviceInfo> getCarAudioDeviceInfoWithDuplicateBuses() {
+        CarAudioDeviceInfo deviceInfo1 = Mockito.mock(CarAudioDeviceInfo.class);
+        when(deviceInfo1.getAddress()).thenReturn("bus001_media");
+        CarAudioDeviceInfo deviceInfo2 = Mockito.mock(CarAudioDeviceInfo.class);
+        when(deviceInfo2.getAddress()).thenReturn("bus001_notifications");
+        return Lists.newArrayList(deviceInfo1, deviceInfo2);
+    }
+
+    private List<CarAudioDeviceInfo> getValidCarAudioDeviceInfos() {
+        CarAudioDeviceInfo deviceInfo1 = Mockito.mock(CarAudioDeviceInfo.class);
+        when(deviceInfo1.getAddress()).thenReturn("bus001_media");
+        when(deviceInfo1.getStepValue()).thenReturn(10);
+        CarAudioDeviceInfo deviceInfo2 = Mockito.mock(CarAudioDeviceInfo.class);
+        when(deviceInfo2.getAddress()).thenReturn("bus002_notifications");
+        when(deviceInfo2.getStepValue()).thenReturn(10);
+        return Lists.newArrayList(deviceInfo1, deviceInfo2);
+    }
+}
diff --git a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperTest.java b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperTest.java
index bd8862d..fce0a78 100644
--- a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperTest.java
+++ b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperTest.java
@@ -15,47 +15,69 @@
  */
 package com.android.car.audio;
 
-import static junit.framework.TestCase.fail;
+import static com.android.car.audio.CarAudioService.DEFAULT_AUDIO_CONTEXT;
 
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
+import static org.testng.Assert.expectThrows;
 
+import android.car.media.CarAudioManager;
 import android.content.Context;
-import android.hardware.automotive.audiocontrol.V1_0.ContextNumber;
-import android.media.AudioGain;
-import android.util.SparseArray;
-import android.view.DisplayAddress;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
+import android.util.SparseIntArray;
 
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import com.android.car.R;
 
+import com.google.common.collect.ImmutableList;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Arrays;
 import java.util.List;
+import java.util.stream.Collectors;
 
 @RunWith(AndroidJUnit4.class)
 public class CarAudioZonesHelperTest {
-    private SparseArray<CarAudioDeviceInfo> mBusToMockCarAudioDeviceInfo;
-    private Context mContext;
+    private List<CarAudioDeviceInfo> mCarAudioOutputDeviceInfos;
+    private AudioDeviceInfo[] mInputAudioDeviceInfos;
     private InputStream mInputStream;
+    private Context mContext;
+    private CarAudioSettings mCarAudioSettings;
+
+    private static final String PRIMARY_ZONE_NAME = "primary zone";
+
+    private static final String BUS_0_ADDRESS = "bus0_media_out";
+    private static final String BUS_1_ADDRESS = "bus1_navigation_out";
+    private static final String BUS_3_ADDRESS = "bus3_call_ring_out";
+    private static final String BUS_100_ADDRESS = "bus100_rear_seat";
+    private static final String BUS_1000_ADDRESS_DOES_NOT_EXIST = "bus1000_does_not_exist";
+
+    private static final String PRIMARY_ZONE_MICROPHONE_ADDRESS = "Built-In Mic";
+    private static final String PRIMARY_ZONE_FM_TUNER_ADDRESS = "fm_tuner";
+    private static final String SECONDARY_ZONE_BACK_MICROPHONE_ADDRESS = "Built-In Back Mic";
+    private static final String SECONDARY_ZONE_BUS_1000_INPUT_ADDRESS = "bus_1000_input";
+
+    private static final int PRIMARY_OCCUPANT_ID = 1;
+    private static final int SECONDARY_ZONE_ID = 2;
 
     @Before
     public void setUp() {
-        mBusToMockCarAudioDeviceInfo = generateBusToCarDeviceInfo();
+        mCarAudioOutputDeviceInfos = generateCarDeviceInfos();
+        mInputAudioDeviceInfos = generateInputDeviceInfos();
         mContext = ApplicationProvider.getApplicationContext();
         mInputStream = mContext.getResources().openRawResource(R.raw.car_audio_configuration);
+        mCarAudioSettings = mock(CarAudioSettings.class);
     }
 
     @After
@@ -65,162 +87,490 @@
         }
     }
 
-    private SparseArray<CarAudioDeviceInfo> generateBusToCarDeviceInfo() {
-        SparseArray<CarAudioDeviceInfo> busToCarAudioDeviceInfo = new SparseArray<>();
-        busToCarAudioDeviceInfo.put(0, generateCarAudioDeviceInfo());
-        busToCarAudioDeviceInfo.put(1, generateCarAudioDeviceInfo());
-        busToCarAudioDeviceInfo.put(3, generateCarAudioDeviceInfo());
-        busToCarAudioDeviceInfo.put(100, generateCarAudioDeviceInfo());
-
-        return busToCarAudioDeviceInfo;
+    private List<CarAudioDeviceInfo> generateCarDeviceInfos() {
+        return ImmutableList.of(
+                generateCarAudioDeviceInfo(BUS_0_ADDRESS),
+                generateCarAudioDeviceInfo(BUS_1_ADDRESS),
+                generateCarAudioDeviceInfo(BUS_3_ADDRESS),
+                generateCarAudioDeviceInfo(BUS_100_ADDRESS),
+                generateCarAudioDeviceInfo(""),
+                generateCarAudioDeviceInfo(""),
+                generateCarAudioDeviceInfo(null),
+                generateCarAudioDeviceInfo(null)
+        );
     }
 
-    private CarAudioDeviceInfo generateCarAudioDeviceInfo() {
-        CarAudioDeviceInfo cadiMock = Mockito.mock(CarAudioDeviceInfo.class);
-        AudioGain audioGainMock = Mockito.mock(AudioGain.class);
-        when(audioGainMock.stepValue()).thenReturn(1);
-        when(cadiMock.getAudioGain()).thenReturn(audioGainMock);
+    private AudioDeviceInfo[] generateInputDeviceInfos() {
+        return new AudioDeviceInfo[]{
+                generateInputAudioDeviceInfo(PRIMARY_ZONE_MICROPHONE_ADDRESS,
+                        AudioDeviceInfo.TYPE_BUILTIN_MIC),
+                generateInputAudioDeviceInfo(PRIMARY_ZONE_FM_TUNER_ADDRESS,
+                        AudioDeviceInfo.TYPE_FM_TUNER),
+                generateInputAudioDeviceInfo(SECONDARY_ZONE_BACK_MICROPHONE_ADDRESS,
+                        AudioDeviceInfo.TYPE_BUS),
+                generateInputAudioDeviceInfo(SECONDARY_ZONE_BUS_1000_INPUT_ADDRESS,
+                        AudioDeviceInfo.TYPE_BUILTIN_MIC)
+        };
+    }
+
+    private CarAudioDeviceInfo generateCarAudioDeviceInfo(String address) {
+        CarAudioDeviceInfo cadiMock = mock(CarAudioDeviceInfo.class);
+        when(cadiMock.getStepValue()).thenReturn(1);
         when(cadiMock.getDefaultGain()).thenReturn(2);
         when(cadiMock.getMaxGain()).thenReturn(5);
         when(cadiMock.getMinGain()).thenReturn(0);
+        when(cadiMock.getAddress()).thenReturn(address);
         return cadiMock;
     }
 
-    @Test
-    public void loadAudioZones_parsesAllZones() throws IOException, XmlPullParserException {
-        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, mInputStream,
-                mBusToMockCarAudioDeviceInfo);
-
-        CarAudioZone[] zones = cazh.loadAudioZones();
-
-        assertEquals(2, zones.length);
+    private AudioDeviceInfo generateInputAudioDeviceInfo(String address, int type) {
+        AudioDeviceInfo inputMock = mock(AudioDeviceInfo.class);
+        when(inputMock.getAddress()).thenReturn(address);
+        when(inputMock.getType()).thenReturn(type);
+        when(inputMock.isSource()).thenReturn(true);
+        when(inputMock.isSink()).thenReturn(false);
+        return inputMock;
     }
 
     @Test
-    public void loadAudioZones_parsesZoneName() throws IOException, XmlPullParserException {
-        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, mInputStream,
-                mBusToMockCarAudioDeviceInfo);
+    public void loadAudioZones_parsesAllZones() throws Exception {
+        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mCarAudioSettings, mInputStream,
+                mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
+
+        List<CarAudioZone> zoneList = Arrays.asList(cazh.loadAudioZones());
+
+        assertThat(zoneList).hasSize(2);
+    }
+
+    @Test
+    public void loadAudioZones_versionOneParsesAllZones() throws Exception {
+        try (InputStream versionOneStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_V1)) {
+            CarAudioZonesHelper cazh = new CarAudioZonesHelper(mCarAudioSettings, versionOneStream,
+                    mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
+
+            CarAudioZone[] zones = cazh.loadAudioZones();
+
+            assertThat(zones.length).isEqualTo(2);
+        }
+    }
+
+    @Test
+    public void loadAudioZones_parsesAudioZoneId() throws Exception {
+        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mCarAudioSettings, mInputStream,
+                mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
+
+        CarAudioZone[] zones = cazh.loadAudioZones();
+
+        List<Integer> zoneIds = getListOfZoneIds(zones);
+        assertThat(zoneIds.size()).isEqualTo(2);
+        assertThat(zoneIds)
+                .containsExactly(CarAudioManager.PRIMARY_AUDIO_ZONE, SECONDARY_ZONE_ID).inOrder();
+    }
+
+    @Test
+    public void loadAudioZones_parsesOccupantZoneId() throws Exception {
+        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mCarAudioSettings, mInputStream,
+                mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
+
+        CarAudioZone[] zones = cazh.loadAudioZones();
+
+        assertThat(zones.length).isEqualTo(2);
+
+        SparseIntArray audioZoneIdToOccupantZoneIdMapping =
+                cazh.getCarAudioZoneIdToOccupantZoneIdMapping();
+        assertThat(audioZoneIdToOccupantZoneIdMapping.get(CarAudioManager.PRIMARY_AUDIO_ZONE))
+                .isEqualTo(PRIMARY_OCCUPANT_ID);
+        assertThat(audioZoneIdToOccupantZoneIdMapping.get(SECONDARY_ZONE_ID, -1))
+                .isEqualTo(-1);
+    }
+
+    @Test
+    public void loadAudioZones_parsesZoneName() throws Exception {
+        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mCarAudioSettings, mInputStream,
+                mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
 
         CarAudioZone[] zones = cazh.loadAudioZones();
 
         CarAudioZone primaryZone = zones[0];
-        assertEquals("primary zone", primaryZone.getName());
+        assertThat(primaryZone.getName()).isEqualTo(PRIMARY_ZONE_NAME);
     }
 
     @Test
-    public void loadAudioZones_parsesIsPrimary() throws IOException, XmlPullParserException {
-        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, mInputStream,
-                mBusToMockCarAudioDeviceInfo);
+    public void loadAudioZones_parsesIsPrimary() throws Exception {
+        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mCarAudioSettings, mInputStream,
+                mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
 
         CarAudioZone[] zones = cazh.loadAudioZones();
 
         CarAudioZone primaryZone = zones[0];
-        assertTrue(primaryZone.isPrimaryZone());
+        assertThat(primaryZone.isPrimaryZone()).isTrue();
 
         CarAudioZone rseZone = zones[1];
-        assertFalse(rseZone.isPrimaryZone());
+        assertThat(rseZone.isPrimaryZone()).isFalse();
     }
 
     @Test
-    public void loadAudioZones_parsesVolumeGroups() throws IOException, XmlPullParserException {
-        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, mInputStream,
-                mBusToMockCarAudioDeviceInfo);
+    public void loadAudioZones_parsesVolumeGroups() throws Exception {
+        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mCarAudioSettings, mInputStream,
+                mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
 
         CarAudioZone[] zones = cazh.loadAudioZones();
 
         CarAudioZone primaryZone = zones[0];
-        assertEquals(2, primaryZone.getVolumeGroupCount());
+        assertThat(primaryZone.getVolumeGroupCount()).isEqualTo(2);
     }
 
     @Test
-    public void loadAudioZones_parsesBuses() throws IOException, XmlPullParserException {
-        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, mInputStream,
-                mBusToMockCarAudioDeviceInfo);
+    public void loadAudioZones_parsesAddresses() throws Exception {
+        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mCarAudioSettings, mInputStream,
+                mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
 
         CarAudioZone[] zones = cazh.loadAudioZones();
 
         CarAudioZone primaryZone = zones[0];
         CarVolumeGroup volumeGroup = primaryZone.getVolumeGroups()[0];
-        int[] busNumbers = volumeGroup.getBusNumbers();
-        assertEquals(2, busNumbers.length);
-        assertEquals(0, busNumbers[0]);
-        assertEquals(3, busNumbers[1]);
+        List<String> addresses = volumeGroup.getAddresses();
+        assertThat(addresses).containsExactly(BUS_0_ADDRESS, BUS_3_ADDRESS);
     }
 
     @Test
-    public void loadAudioZones_parsesContexts() throws IOException, XmlPullParserException {
-        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, mInputStream,
-                mBusToMockCarAudioDeviceInfo);
+    public void loadAudioZones_parsesContexts() throws Exception {
+        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mCarAudioSettings, mInputStream,
+                mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
 
         CarAudioZone[] zones = cazh.loadAudioZones();
 
         CarAudioZone primaryZone = zones[0];
         CarVolumeGroup volumeGroup = primaryZone.getVolumeGroups()[0];
-        int[] expectedContextForBus0 = {ContextNumber.MUSIC};
-        assertArrayEquals(expectedContextForBus0, volumeGroup.getContextsForBus(0));
+        assertThat(volumeGroup.getContextsForAddress(BUS_0_ADDRESS)).asList()
+                .containsExactly(CarAudioContext.MUSIC);
 
-        int[] expectedContextForBus100 = new int[]{ContextNumber.MUSIC, ContextNumber.NAVIGATION,
-                ContextNumber.VOICE_COMMAND, ContextNumber.CALL_RING, ContextNumber.CALL,
-                ContextNumber.ALARM, ContextNumber.NOTIFICATION, ContextNumber.SYSTEM_SOUND};
         CarAudioZone rearSeatEntertainmentZone = zones[1];
         CarVolumeGroup rseVolumeGroup = rearSeatEntertainmentZone.getVolumeGroups()[0];
-        int[] contextForBus100 = rseVolumeGroup.getContextsForBus(100);
-        assertArrayEquals(expectedContextForBus100, contextForBus100);
+        List<Integer> contextForBus100List =
+                Arrays.stream(rseVolumeGroup.getContextsForAddress(BUS_100_ADDRESS))
+                        .boxed().collect(Collectors.toList());
+        List<Integer> contextsList =
+                Arrays.stream(CarAudioContext.CONTEXTS).boxed().collect(Collectors.toList());
+        assertThat(contextForBus100List).containsExactlyElementsIn(contextsList);
     }
 
     @Test
-    public void loadAudioZones_parsesPhysicalDisplayAddresses()
-            throws IOException, XmlPullParserException {
-        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, mInputStream,
-                mBusToMockCarAudioDeviceInfo);
+    public void loadAudioZones_forVersionOne_bindsNonLegacyContextsToDefault() throws Exception {
+        InputStream versionOneStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_V1);
+
+        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mCarAudioSettings, versionOneStream,
+                mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
 
         CarAudioZone[] zones = cazh.loadAudioZones();
 
-        CarAudioZone primaryZone = zones[0];
-        List<DisplayAddress.Physical> primaryPhysicals = primaryZone.getPhysicalDisplayAddresses();
-        assertEquals(2, primaryPhysicals.size());
-        assertEquals(1, (long) primaryPhysicals.get(0).getPort());
-        assertEquals(2, (long) primaryPhysicals.get(1).getPort());
+        CarAudioZone defaultZone = zones[0];
+        CarVolumeGroup volumeGroup = defaultZone.getVolumeGroups()[0];
+        List<Integer> audioContexts = Arrays.stream(volumeGroup.getContexts()).boxed()
+                .collect(Collectors.toList());
+
+        assertThat(audioContexts).containsAllOf(DEFAULT_AUDIO_CONTEXT, CarAudioContext.EMERGENCY,
+                CarAudioContext.SAFETY, CarAudioContext.VEHICLE_STATUS,
+                CarAudioContext.ANNOUNCEMENT);
     }
 
     @Test
-    public void loadAudioZones_defaultsDisplayAddressesToEmptyList()
-            throws IOException, XmlPullParserException {
-        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, mInputStream,
-                mBusToMockCarAudioDeviceInfo);
+    public void loadAudioZones_forVersionOneWithNonLegacyContexts_throws() {
+        InputStream v1NonLegacyContextStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_V1_with_non_legacy_contexts);
 
-        CarAudioZone[] zones = cazh.loadAudioZones();
+        CarAudioZonesHelper cazh =
+                new CarAudioZonesHelper(mCarAudioSettings, v1NonLegacyContextStream,
+                        mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
 
-        CarAudioZone rseZone = zones[1];
-        List<DisplayAddress.Physical> rsePhysicals = rseZone.getPhysicalDisplayAddresses();
-        assertTrue(rsePhysicals.isEmpty());
+        IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,
+                cazh::loadAudioZones);
+
+        assertThat(exception).hasMessageThat().contains("Non-legacy audio contexts such as");
     }
 
-    @Test(expected = RuntimeException.class)
-    public void loadAudioZones_throwsOnDuplicatePorts() throws IOException, XmlPullParserException {
-        try (InputStream duplicatePortStream = mContext.getResources().openRawResource(
-                R.raw.car_audio_configuration_duplicate_ports)) {
-            CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, duplicatePortStream,
-                    mBusToMockCarAudioDeviceInfo);
+    @Test
+    public void loadAudioZones_passesOnMissingAudioZoneIdForPrimary() throws Exception {
+        try (InputStream missingAudioZoneIdStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_no_audio_zone_id_for_primary_zone)) {
+            CarAudioZonesHelper cazh =
+                    new CarAudioZonesHelper(mCarAudioSettings, missingAudioZoneIdStream,
+                            mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
 
-            cazh.loadAudioZones();
+            CarAudioZone[] zones = cazh.loadAudioZones();
+
+            List<Integer> zoneIds = getListOfZoneIds(zones);
+            assertThat(zoneIds.size()).isEqualTo(2);
+            assertThat(zoneIds).contains(CarAudioManager.PRIMARY_AUDIO_ZONE);
+            assertThat(zoneIds).contains(SECONDARY_ZONE_ID);
         }
     }
 
     @Test
-    public void loadAudioZones_throwsOnNonNumericalPort()
-            throws IOException, XmlPullParserException {
-        try (InputStream duplicatePortStream = mContext.getResources().openRawResource(
-                R.raw.car_audio_configuration_non_numerical_port)) {
-            CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, duplicatePortStream,
-                    mBusToMockCarAudioDeviceInfo);
-
-            try {
-                cazh.loadAudioZones();
-                fail();
-            } catch (RuntimeException e) {
-                assertEquals(NumberFormatException.class, e.getCause().getClass());
-            }
+    public void loadAudioZones_versionOneFailsOnAudioZoneId() throws Exception {
+        try (InputStream versionOneAudioZoneIdStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_V1_with_audio_zone_id)) {
+            CarAudioZonesHelper cazh = new CarAudioZonesHelper(mCarAudioSettings,
+                    versionOneAudioZoneIdStream, mCarAudioOutputDeviceInfos,
+                    mInputAudioDeviceInfos);
+            IllegalArgumentException thrown =
+                    expectThrows(IllegalArgumentException.class,
+                            () -> cazh.loadAudioZones());
+            assertThat(thrown).hasMessageThat().contains("Invalid audio attribute audioZoneId");
         }
     }
+
+    @Test
+    public void loadAudioZones_versionOneFailsOnOccupantZoneId() throws Exception {
+        try (InputStream versionOneOccupantIdStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_V1_with_occupant_zone_id)) {
+            CarAudioZonesHelper cazh =
+                    new CarAudioZonesHelper(mCarAudioSettings, versionOneOccupantIdStream,
+                            mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
+            IllegalArgumentException thrown =
+                    expectThrows(IllegalArgumentException.class,
+                            () -> cazh.loadAudioZones());
+            assertThat(thrown).hasMessageThat().contains("Invalid audio attribute occupantZoneId");
+        }
+    }
+
+    @Test
+    public void loadAudioZones_parsesInputDevices() throws Exception {
+        try (InputStream inputDevicesStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_with_input_devices)) {
+            CarAudioZonesHelper cazh =
+                    new CarAudioZonesHelper(mCarAudioSettings, inputDevicesStream,
+                            mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
+
+            CarAudioZone[] zones = cazh.loadAudioZones();
+
+            CarAudioZone primaryZone = zones[0];
+            List<AudioDeviceAttributes> primaryZoneInputDevices =
+                    primaryZone.getInputAudioDevices();
+            assertThat(primaryZoneInputDevices).hasSize(2);
+
+            List<String> primaryZoneInputAddresses =
+                    primaryZoneInputDevices.stream().map(a -> a.getAddress()).collect(
+                            Collectors.toList());
+            assertThat(primaryZoneInputAddresses).containsExactly(PRIMARY_ZONE_FM_TUNER_ADDRESS,
+                    PRIMARY_ZONE_MICROPHONE_ADDRESS).inOrder();
+
+            CarAudioZone secondaryZone = zones[1];
+            List<AudioDeviceAttributes> secondaryZoneInputDevices =
+                    secondaryZone.getInputAudioDevices();
+            List<String> secondaryZoneInputAddresses =
+                    secondaryZoneInputDevices.stream().map(a -> a.getAddress()).collect(
+                            Collectors.toList());
+            assertThat(secondaryZoneInputAddresses).containsExactly(
+                    SECONDARY_ZONE_BUS_1000_INPUT_ADDRESS,
+                    SECONDARY_ZONE_BACK_MICROPHONE_ADDRESS).inOrder();
+        }
+    }
+
+    @Test
+    public void loadAudioZones_failsOnDuplicateOccupantZoneId() throws Exception {
+        try (InputStream duplicateOccupantZoneIdStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_duplicate_occupant_zone_id)) {
+            CarAudioZonesHelper cazh = new CarAudioZonesHelper(mCarAudioSettings,
+                    duplicateOccupantZoneIdStream, mCarAudioOutputDeviceInfos,
+                    mInputAudioDeviceInfos);
+            IllegalArgumentException thrown =
+                    expectThrows(IllegalArgumentException.class,
+                            () -> cazh.loadAudioZones());
+            assertThat(thrown).hasMessageThat().contains("already associated with a zone");
+        }
+    }
+
+    @Test
+    public void loadAudioZones_failsOnDuplicateAudioZoneId() throws Exception {
+        try (InputStream duplicateAudioZoneIdStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_duplicate_audio_zone_id)) {
+            CarAudioZonesHelper cazh =
+                    new CarAudioZonesHelper(mCarAudioSettings, duplicateAudioZoneIdStream,
+                            mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
+            IllegalArgumentException thrown =
+                    expectThrows(IllegalArgumentException.class,
+                            () -> cazh.loadAudioZones());
+            assertThat(thrown).hasMessageThat().contains("already associated with a zone");
+        }
+    }
+
+    @Test
+    public void loadAudioZones_failsOnEmptyInputDeviceAddress() throws Exception {
+        try (InputStream inputDevicesStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_empty_input_device)) {
+            CarAudioZonesHelper cazh =
+                    new CarAudioZonesHelper(mCarAudioSettings, inputDevicesStream,
+                            mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
+
+            IllegalArgumentException thrown =
+                    expectThrows(IllegalArgumentException.class,
+                            () -> cazh.loadAudioZones());
+            assertThat(thrown).hasMessageThat().contains("empty.");
+        }
+    }
+
+    @Test
+    public void loadAudioZones_failsOnNonNumericalAudioZoneId() throws Exception {
+        try (InputStream nonNumericalStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_non_numerical_audio_zone_id)) {
+            CarAudioZonesHelper cazh =
+                    new CarAudioZonesHelper(mCarAudioSettings, nonNumericalStream,
+                            mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
+            IllegalArgumentException thrown =
+                    expectThrows(IllegalArgumentException.class,
+                            () -> cazh.loadAudioZones());
+            assertThat(thrown).hasMessageThat().contains("was \"primary\" instead.");
+        }
+    }
+
+    @Test
+    public void loadAudioZones_failsOnNegativeAudioZoneId() throws Exception {
+        try (InputStream negativeAudioZoneIdStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_negative_audio_zone_id)) {
+            CarAudioZonesHelper cazh =
+                    new CarAudioZonesHelper(mCarAudioSettings, negativeAudioZoneIdStream,
+                            mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
+            IllegalArgumentException thrown =
+                    expectThrows(IllegalArgumentException.class,
+                            () -> cazh.loadAudioZones());
+            assertThat(thrown).hasMessageThat().contains("but was \"-1\" instead.");
+        }
+    }
+
+    @Test
+    public void loadAudioZones_failsOnMissingInputDevice() throws Exception {
+        try (InputStream inputDevicesStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_missing_address)) {
+            CarAudioZonesHelper cazh =
+                    new CarAudioZonesHelper(mCarAudioSettings, inputDevicesStream,
+                            mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
+
+            NullPointerException thrown =
+                    expectThrows(NullPointerException.class,
+                            () -> cazh.loadAudioZones());
+            assertThat(thrown).hasMessageThat().contains("present.");
+        }
+    }
+
+    @Test
+    public void loadAudioZones_failsOnNonNumericalOccupantZoneId() throws Exception {
+        try (InputStream nonNumericalStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_non_numerical_occupant_zone_id)) {
+            CarAudioZonesHelper cazh =
+                    new CarAudioZonesHelper(mCarAudioSettings, nonNumericalStream,
+                            mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
+            IllegalArgumentException thrown =
+                    expectThrows(IllegalArgumentException.class,
+                            () -> cazh.loadAudioZones());
+            assertThat(thrown).hasMessageThat().contains("was \"one\" instead.");
+        }
+    }
+
+    @Test
+    public void loadAudioZones_failsOnNegativeOccupantZoneId() throws Exception {
+        try (InputStream negativeOccupantZoneIdStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_negative_occupant_zone_id)) {
+            CarAudioZonesHelper cazh = new CarAudioZonesHelper(mCarAudioSettings,
+                    negativeOccupantZoneIdStream, mCarAudioOutputDeviceInfos,
+                    mInputAudioDeviceInfos);
+            IllegalArgumentException thrown =
+                    expectThrows(IllegalArgumentException.class,
+                            () -> cazh.loadAudioZones());
+            assertThat(thrown).hasMessageThat().contains("was \"-1\" instead.");
+        }
+    }
+
+    @Test
+    public void loadAudioZones_failsOnNonExistentInputDevice() throws Exception {
+        try (InputStream inputDevicesStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_non_existent_input_device)) {
+            CarAudioZonesHelper cazh =
+                    new CarAudioZonesHelper(mCarAudioSettings, inputDevicesStream,
+                            mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
+
+            IllegalArgumentException thrown =
+                    expectThrows(IllegalArgumentException.class,
+                            () -> cazh.loadAudioZones());
+            assertThat(thrown).hasMessageThat().contains("does not exist");
+        }
+    }
+
+    @Test
+    public void loadAudioZones_failsOnEmptyOccupantZoneId() throws Exception {
+        try (InputStream emptyOccupantZoneIdStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_empty_occupant_zone_id)) {
+            CarAudioZonesHelper cazh =
+                    new CarAudioZonesHelper(mCarAudioSettings, emptyOccupantZoneIdStream,
+                            mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
+            IllegalArgumentException thrown =
+                    expectThrows(IllegalArgumentException.class,
+                            () -> cazh.loadAudioZones());
+            assertThat(thrown).hasMessageThat().contains("but was \"\" instead.");
+        }
+    }
+
+    @Test
+    public void loadAudioZones_failsOnNonZeroAudioZoneIdForPrimary() throws Exception {
+        try (InputStream nonZeroForPrimaryStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_primary_zone_with_non_zero_audio_zone_id)) {
+            CarAudioZonesHelper cazh =
+                    new CarAudioZonesHelper(mCarAudioSettings, nonZeroForPrimaryStream,
+                            mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
+            IllegalArgumentException thrown =
+                    expectThrows(IllegalArgumentException.class,
+                            () -> cazh.loadAudioZones());
+            assertThat(thrown).hasMessageThat().contains("it can be left empty.");
+        }
+    }
+
+    @Test
+    public void loadAudioZones_failsOnZeroAudioZoneIdForSecondary() throws Exception {
+        try (InputStream zeroZoneIdForSecondaryStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_non_primary_zone_with_primary_audio_zone_id)) {
+            CarAudioZonesHelper cazh = new CarAudioZonesHelper(mCarAudioSettings,
+                    zeroZoneIdForSecondaryStream, mCarAudioOutputDeviceInfos,
+                    mInputAudioDeviceInfos);
+            IllegalArgumentException thrown =
+                    expectThrows(IllegalArgumentException.class,
+                            () -> cazh.loadAudioZones());
+            assertThat(thrown).hasMessageThat().contains(PRIMARY_ZONE_NAME);
+        }
+    }
+
+    @Test
+    public void loadAudioZones_failsOnRepeatedInputDevice() throws Exception {
+        try (InputStream inputDevicesStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_repeat_input_device)) {
+            CarAudioZonesHelper cazh =
+                    new CarAudioZonesHelper(mCarAudioSettings, inputDevicesStream,
+                            mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
+
+            IllegalArgumentException thrown =
+                    expectThrows(IllegalArgumentException.class,
+                            () -> cazh.loadAudioZones());
+            assertThat(thrown).hasMessageThat().contains("can not repeat.");
+        }
+    }
+
+    @Test
+    public void loadAudioZones_failsOnMissingOutputDevice() throws Exception {
+        try (InputStream outputDevicesStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_output_address_does_not_exist)) {
+            CarAudioZonesHelper cazh =
+                    new CarAudioZonesHelper(mCarAudioSettings, outputDevicesStream,
+                            mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
+
+            IllegalStateException thrown =
+                    expectThrows(IllegalStateException.class,
+                            () -> cazh.loadAudioZones());
+            assertThat(thrown).hasMessageThat().contains(BUS_1000_ADDRESS_DOES_NOT_EXIST);
+        }
+    }
+
+    private List<Integer> getListOfZoneIds(CarAudioZone[] zones) {
+        return Arrays.stream(zones).map(CarAudioZone::getId).collect(Collectors.toList());
+    }
 }
diff --git a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesValidatorTest.java b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesValidatorTest.java
new file mode 100644
index 0000000..c171321
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesValidatorTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.audio;
+
+import static org.mockito.Mockito.when;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.google.common.collect.Lists;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+@RunWith(AndroidJUnit4.class)
+public class CarAudioZonesValidatorTest {
+    @Rule
+    public final ExpectedException thrown = ExpectedException.none();
+
+    @Test
+    public void validate_thereIsAtLeastOneZone() {
+        thrown.expect(RuntimeException.class);
+        thrown.expectMessage("At least one zone should be defined");
+
+        CarAudioZonesValidator.validate(new CarAudioZone[0]);
+    }
+
+    @Test
+    public void validate_volumeGroupsForEachZone() {
+        CarAudioZone primaryZone = Mockito.mock(CarAudioZone.class);
+        when(primaryZone.validateVolumeGroups()).thenReturn(true);
+        CarAudioZone zoneOne = Mockito.mock(CarAudioZone.class);
+        when(zoneOne.validateVolumeGroups()).thenReturn(false);
+        when(zoneOne.getId()).thenReturn(1);
+
+        thrown.expect(RuntimeException.class);
+        thrown.expectMessage("Invalid volume groups configuration for zone " + 1);
+
+        CarAudioZonesValidator.validate(new CarAudioZone[]{primaryZone, zoneOne});
+    }
+
+    @Test
+    public void validate_eachAddressAppearsInOnlyOneZone() {
+        CarAudioZone primaryZone = Mockito.mock(CarAudioZone.class);
+        CarVolumeGroup mockVolumeGroup = Mockito.mock(CarVolumeGroup.class);
+        when(mockVolumeGroup.getAddresses()).thenReturn(Lists.newArrayList("one", "two", "three"));
+        when(primaryZone.getVolumeGroups()).thenReturn(new CarVolumeGroup[]{mockVolumeGroup});
+        when(primaryZone.validateVolumeGroups()).thenReturn(true);
+
+        CarAudioZone secondaryZone = Mockito.mock(CarAudioZone.class);
+        CarVolumeGroup mockSecondaryVolmeGroup = Mockito.mock(CarVolumeGroup.class);
+        when(mockSecondaryVolmeGroup.getAddresses()).thenReturn(
+                Lists.newArrayList("three", "four", "five"));
+        when(secondaryZone.getVolumeGroups()).thenReturn(
+                new CarVolumeGroup[]{mockSecondaryVolmeGroup});
+        when(secondaryZone.validateVolumeGroups()).thenReturn(true);
+
+        thrown.expect(RuntimeException.class);
+        thrown.expectMessage(
+                "Device with address three appears in multiple volume groups or audio zones");
+
+        CarAudioZonesValidator.validate(new CarAudioZone[]{primaryZone, secondaryZone});
+    }
+
+    @Test
+    public void validate_passesWithoutExceptionForValidZoneConfiguration() {
+        CarAudioZone primaryZone = Mockito.mock(CarAudioZone.class);
+        when(primaryZone.validateVolumeGroups()).thenReturn(true);
+        when(primaryZone.getVolumeGroups()).thenReturn(new CarVolumeGroup[0]);
+
+        CarAudioZonesValidator.validate(new CarAudioZone[]{primaryZone});
+    }
+}
diff --git a/tests/carservice_test/src/com/android/car/audio/CarVolumeGroupTest.java b/tests/carservice_test/src/com/android/car/audio/CarVolumeGroupTest.java
new file mode 100644
index 0000000..cc9ecd3
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/audio/CarVolumeGroupTest.java
@@ -0,0 +1,476 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.audio;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.expectThrows;
+
+import android.app.ActivityManager;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.os.UserHandle;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.google.common.primitives.Ints;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RunWith(AndroidJUnit4.class)
+public class CarVolumeGroupTest extends AbstractExtendedMockitoTestCase{
+    private static final int STEP_VALUE = 2;
+    private static final int MIN_GAIN = 0;
+    private static final int MAX_GAIN = 5;
+    private static final int DEFAULT_GAIN = 0;
+    private static final int TEST_USER_10 = 10;
+    private static final int TEST_USER_11 = 11;
+    private static final String OTHER_ADDRESS = "other_address";
+    private static final String MEDIA_DEVICE_ADDRESS = "music";
+    private static final String NAVIGATION_DEVICE_ADDRESS = "navigation";
+
+
+    private CarAudioDeviceInfo mMediaDevice;
+    private CarAudioDeviceInfo mNavigationDevice;
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+        session.spyStatic(ActivityManager.class);
+    }
+
+    @Before
+    public void setUp() {
+        mMediaDevice = generateCarAudioDeviceInfo(MEDIA_DEVICE_ADDRESS);
+        mNavigationDevice = generateCarAudioDeviceInfo(NAVIGATION_DEVICE_ADDRESS);
+    }
+
+    @Test
+    public void bind_associatesDeviceAddresses() {
+        CarAudioSettings settings =
+                generateCarAudioSettings(0 , 0, 2);
+        CarVolumeGroup carVolumeGroup = new CarVolumeGroup(settings, 0, 0);
+
+        carVolumeGroup.bind(CarAudioContext.MUSIC, mMediaDevice);
+        assertEquals(1, carVolumeGroup.getAddresses().size());
+
+        carVolumeGroup.bind(CarAudioContext.NAVIGATION, mNavigationDevice);
+
+        List<String> addresses = carVolumeGroup.getAddresses();
+        assertEquals(2, addresses.size());
+        assertTrue(addresses.contains(MEDIA_DEVICE_ADDRESS));
+        assertTrue(addresses.contains(NAVIGATION_DEVICE_ADDRESS));
+    }
+
+    @Test
+    public void bind_checksForSameStepSize() {
+        CarAudioSettings settings =
+                generateCarAudioSettings(0 , 0, 2);
+        CarVolumeGroup carVolumeGroup = new CarVolumeGroup(settings, 0, 0);
+
+        carVolumeGroup.bind(CarAudioContext.MUSIC, mMediaDevice);
+        CarAudioDeviceInfo differentStepValueDevice = generateCarAudioDeviceInfo(
+                NAVIGATION_DEVICE_ADDRESS, STEP_VALUE + 1,
+                MIN_GAIN, MAX_GAIN);
+
+        IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
+                () -> carVolumeGroup.bind(CarAudioContext.NAVIGATION, differentStepValueDevice));
+        assertThat(thrown).hasMessageThat()
+                .contains("Gain controls within one group must have same step value");
+    }
+
+    @Test
+    public void bind_updatesMinGainToSmallestValue() {
+        CarAudioSettings settings =
+                generateCarAudioSettings(0 , 0, 2);
+        CarVolumeGroup carVolumeGroup = new CarVolumeGroup(settings, 0, 0);
+
+        CarAudioDeviceInfo largestMinGain = generateCarAudioDeviceInfo(
+                NAVIGATION_DEVICE_ADDRESS, 1, 10, 10);
+        carVolumeGroup.bind(CarAudioContext.NAVIGATION, largestMinGain);
+
+        assertEquals(0, carVolumeGroup.getMaxGainIndex());
+
+        CarAudioDeviceInfo smallestMinGain = generateCarAudioDeviceInfo(
+                NAVIGATION_DEVICE_ADDRESS, 1, 2, 10);
+        carVolumeGroup.bind(CarAudioContext.NOTIFICATION, smallestMinGain);
+
+        assertEquals(8, carVolumeGroup.getMaxGainIndex());
+
+        CarAudioDeviceInfo middleMinGain = generateCarAudioDeviceInfo(
+                NAVIGATION_DEVICE_ADDRESS, 1, 7, 10);
+        carVolumeGroup.bind(CarAudioContext.VOICE_COMMAND, middleMinGain);
+
+        assertEquals(8, carVolumeGroup.getMaxGainIndex());
+    }
+
+    @Test
+    public void bind_updatesMaxGainToLargestValue() {
+        CarAudioSettings settings =
+                generateCarAudioSettings(0 , 0, 2);
+        CarVolumeGroup carVolumeGroup = new CarVolumeGroup(settings, 0, 0);
+
+        CarAudioDeviceInfo smallestMaxGain = generateCarAudioDeviceInfo(
+                NAVIGATION_DEVICE_ADDRESS, 1, 1, 5);
+        carVolumeGroup.bind(CarAudioContext.NAVIGATION, smallestMaxGain);
+
+        assertEquals(4, carVolumeGroup.getMaxGainIndex());
+
+        CarAudioDeviceInfo largestMaxGain = generateCarAudioDeviceInfo(
+                NAVIGATION_DEVICE_ADDRESS, 1, 1, 10);
+        carVolumeGroup.bind(CarAudioContext.NOTIFICATION, largestMaxGain);
+
+        assertEquals(9, carVolumeGroup.getMaxGainIndex());
+
+        CarAudioDeviceInfo middleMaxGain = generateCarAudioDeviceInfo(
+                NAVIGATION_DEVICE_ADDRESS, 1, 1, 7);
+        carVolumeGroup.bind(CarAudioContext.VOICE_COMMAND, middleMaxGain);
+
+        assertEquals(9, carVolumeGroup.getMaxGainIndex());
+    }
+
+    @Test
+    public void bind_checksThatTheSameContextIsNotBoundTwice() {
+        CarAudioSettings settings =
+                generateCarAudioSettings(0 , 0, 2);
+        CarVolumeGroup carVolumeGroup = new CarVolumeGroup(settings, 0, 0);
+
+        carVolumeGroup.bind(CarAudioContext.NAVIGATION, mMediaDevice);
+
+        IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
+                () -> carVolumeGroup.bind(CarAudioContext.NAVIGATION, mMediaDevice));
+        assertThat(thrown).hasMessageThat()
+                .contains("Context NAVIGATION has already been bound to " + MEDIA_DEVICE_ADDRESS);
+    }
+
+    @Test
+    public void getContexts_returnsAllContextsBoundToVolumeGroup() {
+        CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+
+        int[] contexts = carVolumeGroup.getContexts();
+
+        assertEquals(6, contexts.length);
+
+        List<Integer> contextsList = Ints.asList(contexts);
+        assertTrue(contextsList.contains(CarAudioContext.MUSIC));
+        assertTrue(contextsList.contains(CarAudioContext.CALL));
+        assertTrue(contextsList.contains(CarAudioContext.CALL_RING));
+        assertTrue(contextsList.contains(CarAudioContext.NAVIGATION));
+        assertTrue(contextsList.contains(CarAudioContext.ALARM));
+        assertTrue(contextsList.contains(CarAudioContext.NOTIFICATION));
+    }
+
+    @Test
+    public void getContextsForAddress_returnsContextsBoundToThatAddress() {
+        CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+
+        int[] contexts = carVolumeGroup.getContextsForAddress(MEDIA_DEVICE_ADDRESS);
+
+        assertEquals(3, contexts.length);
+        List<Integer> contextsList = Ints.asList(contexts);
+        assertTrue(contextsList.contains(CarAudioContext.MUSIC));
+        assertTrue(contextsList.contains(CarAudioContext.CALL));
+        assertTrue(contextsList.contains(CarAudioContext.CALL_RING));
+    }
+
+    @Test
+    public void getContextsForAddress_returnsEmptyArrayIfAddressNotBound() {
+        CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+
+        int[] contexts = carVolumeGroup.getContextsForAddress(OTHER_ADDRESS);
+
+        assertEquals(0, contexts.length);
+    }
+
+    @Test
+    public void getCarAudioDeviceInfoForAddress_returnsExpectedDevice() {
+        CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+
+        CarAudioDeviceInfo actualDevice = carVolumeGroup.getCarAudioDeviceInfoForAddress(
+                MEDIA_DEVICE_ADDRESS);
+
+        assertEquals(mMediaDevice, actualDevice);
+    }
+
+    @Test
+    public void getCarAudioDeviceInfoForAddress_returnsNullIfAddressNotBound() {
+        CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+
+        CarAudioDeviceInfo actualDevice = carVolumeGroup.getCarAudioDeviceInfoForAddress(
+                OTHER_ADDRESS);
+
+        assertNull(actualDevice);
+    }
+
+    @Test
+    public void setCurrentGainIndex_setsGainOnAllBoundDevices() {
+        CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+
+        carVolumeGroup.setCurrentGainIndex(2);
+        verify(mMediaDevice).setCurrentGain(4);
+        verify(mNavigationDevice).setCurrentGain(4);
+    }
+
+    @Test
+    public void setCurrentGainIndex_updatesCurrentGainIndex() {
+        CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+
+        carVolumeGroup.setCurrentGainIndex(2);
+
+        assertEquals(2, carVolumeGroup.getCurrentGainIndex());
+    }
+
+    @Test
+    public void setCurrentGainIndex_checksNewGainIsAboveMin() {
+        CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+
+        IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
+                () -> carVolumeGroup.setCurrentGainIndex(-1));
+        assertThat(thrown).hasMessageThat().contains("Gain out of range (0:5) -2index -1");
+    }
+
+    @Test
+    public void setCurrentGainIndex_checksNewGainIsBelowMax() {
+        CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+
+        IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
+                () -> carVolumeGroup.setCurrentGainIndex(3));
+        assertThat(thrown).hasMessageThat().contains("Gain out of range (0:5) 6index 3");
+    }
+
+    @Test
+    public void getMinGainIndex_alwaysReturnsZero() {
+
+        CarAudioSettings settings =
+                generateCarAudioSettings(0 , 0, 2);
+        CarVolumeGroup carVolumeGroup = new CarVolumeGroup(settings, 0, 0);
+        CarAudioDeviceInfo minGainPlusOneDevice = generateCarAudioDeviceInfo(
+                NAVIGATION_DEVICE_ADDRESS, STEP_VALUE, 10, MAX_GAIN);
+        carVolumeGroup.bind(CarAudioContext.NAVIGATION, minGainPlusOneDevice);
+
+        assertEquals(0, carVolumeGroup.getMinGainIndex());
+
+        CarAudioDeviceInfo minGainDevice = generateCarAudioDeviceInfo(
+                NAVIGATION_DEVICE_ADDRESS, STEP_VALUE, 1, MAX_GAIN);
+        carVolumeGroup.bind(CarAudioContext.NOTIFICATION, minGainDevice);
+
+        assertEquals(0, carVolumeGroup.getMinGainIndex());
+    }
+
+    @Test
+    public void loadVolumesForUser_setsCurrentGainIndexForUser() {
+
+        List<Integer> users = new ArrayList<>();
+        users.add(TEST_USER_10);
+        users.add(TEST_USER_11);
+
+        Map<Integer, Integer> storedGainIndex = new HashMap<>();
+        storedGainIndex.put(TEST_USER_10, 2);
+        storedGainIndex.put(TEST_USER_11, 0);
+
+        CarAudioSettings settings =
+                generateCarAudioSettings(users, 0 , 0, storedGainIndex);
+        CarVolumeGroup carVolumeGroup = new CarVolumeGroup(settings, 0, 0);
+
+        CarAudioDeviceInfo deviceInfo = generateCarAudioDeviceInfo(
+                NAVIGATION_DEVICE_ADDRESS, STEP_VALUE, MIN_GAIN, MAX_GAIN);
+        carVolumeGroup.bind(CarAudioContext.NAVIGATION, deviceInfo);
+        carVolumeGroup.loadVolumesForUser(TEST_USER_10);
+
+        assertEquals(2, carVolumeGroup.getCurrentGainIndex());
+
+        carVolumeGroup.loadVolumesForUser(TEST_USER_11);
+
+        assertEquals(0, carVolumeGroup.getCurrentGainIndex());
+    }
+
+    @Test
+    public void loadUserStoredGainIndex_setsCurrentGainIndexToDefault() {
+        CarAudioSettings settings =
+                generateCarAudioSettings(TEST_USER_10, 0, 0, 10);
+        CarVolumeGroup carVolumeGroup = new CarVolumeGroup(settings, 0, 0);
+
+        CarAudioDeviceInfo deviceInfo = generateCarAudioDeviceInfo(
+                NAVIGATION_DEVICE_ADDRESS, STEP_VALUE, MIN_GAIN, MAX_GAIN);
+        carVolumeGroup.bind(CarAudioContext.NAVIGATION, deviceInfo);
+
+        carVolumeGroup.setCurrentGainIndex(2);
+
+        assertEquals(2, carVolumeGroup.getCurrentGainIndex());
+
+        carVolumeGroup.loadVolumesForUser(0);
+
+        assertEquals(0, carVolumeGroup.getCurrentGainIndex());
+    }
+
+    @Test
+    public void setCurrentGainIndex_setsCurrentGainIndexForUser() {
+        List<Integer> users = new ArrayList<>();
+        users.add(TEST_USER_11);
+
+        Map<Integer, Integer> storedGainIndex = new HashMap<>();
+        storedGainIndex.put(TEST_USER_11, 2);
+
+        CarAudioSettings settings =
+                generateCarAudioSettings(users, 0 , 0, storedGainIndex);
+        CarVolumeGroup carVolumeGroup = new CarVolumeGroup(settings, 0, 0);
+
+        CarAudioDeviceInfo deviceInfo = generateCarAudioDeviceInfo(
+                NAVIGATION_DEVICE_ADDRESS, STEP_VALUE, MIN_GAIN, MAX_GAIN);
+        carVolumeGroup.bind(CarAudioContext.NAVIGATION, deviceInfo);
+        carVolumeGroup.loadVolumesForUser(TEST_USER_11);
+
+        carVolumeGroup.setCurrentGainIndex(MIN_GAIN);
+
+        verify(settings).storeVolumeGainIndexForUser(TEST_USER_11, 0, 0, MIN_GAIN);
+    }
+
+    @Test
+    public void setCurrentGainIndex_setsCurrentGainIndexForDefaultUser() {
+        List<Integer> users = new ArrayList<>();
+        users.add(UserHandle.USER_CURRENT);
+
+        Map<Integer, Integer> storedGainIndex = new HashMap<>();
+        storedGainIndex.put(UserHandle.USER_CURRENT, 2);
+
+        CarAudioSettings settings =
+                generateCarAudioSettings(users, 0 , 0, storedGainIndex);
+        CarVolumeGroup carVolumeGroup = new CarVolumeGroup(settings, 0, 0);
+
+        CarAudioDeviceInfo deviceInfo = generateCarAudioDeviceInfo(
+                NAVIGATION_DEVICE_ADDRESS, STEP_VALUE, MIN_GAIN, MAX_GAIN);
+        carVolumeGroup.bind(CarAudioContext.NAVIGATION, deviceInfo);
+
+        carVolumeGroup.setCurrentGainIndex(MIN_GAIN);
+
+        verify(settings)
+                .storeVolumeGainIndexForUser(UserHandle.USER_CURRENT, 0, 0, MIN_GAIN);
+    }
+
+    @Test
+    public void bind_setsCurrentGainIndexToStoredGainIndex() {
+        CarAudioSettings settings =
+                generateCarAudioSettings(0 , 0, 2);
+        CarVolumeGroup carVolumeGroup = new CarVolumeGroup(settings, 0, 0);
+
+        CarAudioDeviceInfo deviceInfo = generateCarAudioDeviceInfo(
+                NAVIGATION_DEVICE_ADDRESS, STEP_VALUE, MIN_GAIN, MAX_GAIN);
+        carVolumeGroup.bind(CarAudioContext.NAVIGATION, deviceInfo);
+
+
+        assertEquals(2, carVolumeGroup.getCurrentGainIndex());
+    }
+
+    @Test
+    public void getAddressForContext_returnsExpectedDeviceAddress() {
+        CarAudioSettings settings =
+                generateCarAudioSettings(0 , 0, 2);
+        CarVolumeGroup carVolumeGroup = new CarVolumeGroup(settings, 0, 0);
+
+
+        carVolumeGroup.bind(CarAudioContext.MUSIC, mMediaDevice);
+
+        String mediaAddress = carVolumeGroup.getAddressForContext(CarAudioContext.MUSIC);
+
+        assertEquals(mMediaDevice.getAddress(), mediaAddress);
+    }
+
+    @Test
+    public void getAddressForContext_returnsNull() {
+        CarAudioSettings settings =
+                generateCarAudioSettings(0 , 0, 2);
+        CarVolumeGroup carVolumeGroup = new CarVolumeGroup(settings, 0, 0);
+
+        String nullAddress = carVolumeGroup.getAddressForContext(CarAudioContext.MUSIC);
+
+        assertNull(nullAddress);
+    }
+
+    private CarVolumeGroup testVolumeGroupSetup() {
+        CarAudioSettings settings =
+                generateCarAudioSettings(0 , 0, 2);
+        CarVolumeGroup carVolumeGroup = new CarVolumeGroup(settings, 0, 0);
+
+
+        carVolumeGroup.bind(CarAudioContext.MUSIC, mMediaDevice);
+        carVolumeGroup.bind(CarAudioContext.CALL, mMediaDevice);
+        carVolumeGroup.bind(CarAudioContext.CALL_RING, mMediaDevice);
+
+        carVolumeGroup.bind(CarAudioContext.NAVIGATION, mNavigationDevice);
+        carVolumeGroup.bind(CarAudioContext.ALARM, mNavigationDevice);
+        carVolumeGroup.bind(CarAudioContext.NOTIFICATION, mNavigationDevice);
+
+        return carVolumeGroup;
+    }
+
+    private CarAudioDeviceInfo generateCarAudioDeviceInfo(String address) {
+        return generateCarAudioDeviceInfo(address, STEP_VALUE, MIN_GAIN, MAX_GAIN);
+    }
+
+    private CarAudioDeviceInfo generateCarAudioDeviceInfo(String address, int stepValue,
+            int minGain, int maxGain) {
+        CarAudioDeviceInfo cadiMock = Mockito.mock(CarAudioDeviceInfo.class);
+        when(cadiMock.getStepValue()).thenReturn(stepValue);
+        when(cadiMock.getDefaultGain()).thenReturn(DEFAULT_GAIN);
+        when(cadiMock.getMaxGain()).thenReturn(maxGain);
+        when(cadiMock.getMinGain()).thenReturn(minGain);
+        when(cadiMock.getAddress()).thenReturn(address);
+        return cadiMock;
+    }
+
+    private CarAudioSettings generateCarAudioSettings(int userId,
+            int zoneId, int id, int storedGainIndex) {
+        CarAudioSettings settingsMock = Mockito.mock(CarAudioSettings.class);
+        when(settingsMock.getStoredVolumeGainIndexForUser(userId, zoneId, id))
+                .thenReturn(storedGainIndex);
+
+        return settingsMock;
+    }
+
+    private CarAudioSettings generateCarAudioSettings(
+            int zoneId, int id, int storedGainIndex) {
+        CarAudioSettings settingsMock = Mockito.mock(CarAudioSettings.class);
+
+        when(settingsMock.getStoredVolumeGainIndexForUser(anyInt(), eq(zoneId),
+                eq(id))).thenReturn(storedGainIndex);
+
+        return settingsMock;
+    }
+
+    private CarAudioSettings generateCarAudioSettings(List<Integer> users,
+            int zoneId, int id, Map<Integer, Integer> storedGainIndex) {
+        CarAudioSettings settingsMock = Mockito.mock(CarAudioSettings.class);
+        for (Integer user : users) {
+            when(settingsMock.getStoredVolumeGainIndexForUser(user, zoneId,
+                    id)).thenReturn(storedGainIndex.get(user));
+        }
+        return settingsMock;
+    }
+
+}
diff --git a/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusTest.java b/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusTest.java
new file mode 100644
index 0000000..7a3f813
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/audio/CarZonesAudioFocusTest.java
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.audio;
+
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+import static android.media.AudioAttributes.USAGE_MEDIA;
+import static android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION;
+import static android.media.AudioManager.AUDIOFOCUS_GAIN;
+import static android.media.AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
+import static android.media.AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
+import static android.media.AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+import static android.media.AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.car.media.CarAudioManager;
+import android.content.ContentResolver;
+import android.content.pm.PackageManager;
+import android.media.AudioAttributes;
+import android.media.AudioFocusInfo;
+import android.media.AudioManager;
+import android.media.audiopolicy.AudioPolicy;
+import android.os.Build;
+import android.os.Bundle;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(AndroidJUnit4.class)
+public class CarZonesAudioFocusTest {
+    private static final String MEDIA_CLIENT_ID = "media-client-id";
+    private static final String NAVIGATION_CLIENT_ID = "nav-client-id";
+    private static final String CALL_CLIENT_ID = "call-client-id";
+    private static final String PACKAGE_NAME = "com.android.car.audio";
+    private static final int AUDIOFOCUS_FLAG = 0;
+    private static final int PRIMARY_ZONE_ID = CarAudioManager.PRIMARY_AUDIO_ZONE;
+    private static final int SECONDARY_ZONE_ID = CarAudioManager.PRIMARY_AUDIO_ZONE + 1;
+    private static final int MEDIA_CLIENT_UID_1 = 1086753;
+    private static final int MEDIA_CLIENT_UID_2 = 1000009;
+    private static final int NAVIGATION_CLIENT_UID = 1010101;
+    private static final int TEST_USER_ID = 10;
+    private static final int CALL_CLIENT_UID = 1086753;
+
+    @Rule
+    public MockitoRule rule = MockitoJUnit.rule();
+    @Mock
+    private AudioManager mMockAudioManager;
+    @Mock
+    private PackageManager mMockPackageManager;
+    @Mock
+    private AudioPolicy mAudioPolicy;
+    @Mock
+    private CarAudioZone mPrimaryAudioZone;
+    @Mock
+    private CarAudioZone mSecondaryAudioZone;
+    @Mock
+    private CarAudioService mCarAudioService;
+    @Mock
+    private ContentResolver mContentResolver;
+    @Mock
+    private CarAudioSettings mCarAudioSettings;
+
+    private CarAudioZone[] mMockAudioZones;
+
+    @Before
+    public void setUp() {
+        mMockAudioZones = generateAudioZones();
+    }
+
+    @Test
+    public void onAudioFocusRequest_withNoCurrentFocusHolder_requestGranted() {
+        CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus(false);
+        when(mCarAudioService.getZoneIdForUid(MEDIA_CLIENT_UID_1)).thenReturn(PRIMARY_ZONE_ID);
+        AudioFocusInfo audioFocusInfo = new AudioFocusInfoBuilder().setUsage(USAGE_MEDIA)
+                .setClientId(MEDIA_CLIENT_ID).setGainRequest(AUDIOFOCUS_GAIN)
+                .setClientUid(MEDIA_CLIENT_UID_1).createAudioFocusInfo();
+
+        requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfo);
+
+        verify(mMockAudioManager, never())
+                .dispatchAudioFocusChange(eq(audioFocusInfo), anyInt(), eq(mAudioPolicy));
+    }
+
+    @Test
+    public void onAudioFocusRequest_forTwoDifferentZones_requestGranted() {
+        CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus(false);
+        when(mCarAudioService.getZoneIdForUid(MEDIA_CLIENT_UID_1)).thenReturn(PRIMARY_ZONE_ID);
+        AudioFocusInfo audioFocusInfoClient1 = new AudioFocusInfoBuilder().setUsage(USAGE_MEDIA)
+                .setClientId(MEDIA_CLIENT_ID).setGainRequest(AUDIOFOCUS_GAIN)
+                .setClientUid(MEDIA_CLIENT_UID_1).createAudioFocusInfo();
+
+        requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfoClient1);
+
+        when(mCarAudioService.getZoneIdForUid(MEDIA_CLIENT_UID_2)).thenReturn(SECONDARY_ZONE_ID);
+        AudioFocusInfo audioFocusInfoClient2 = new AudioFocusInfoBuilder().setUsage(USAGE_MEDIA)
+                .setClientId(MEDIA_CLIENT_ID).setGainRequest(AUDIOFOCUS_GAIN)
+                .setClientUid(MEDIA_CLIENT_UID_2).createAudioFocusInfo();
+
+        requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfoClient2);
+
+        verify(mMockAudioManager, never())
+                .dispatchAudioFocusChange(eq(audioFocusInfoClient1), anyInt(), eq(mAudioPolicy));
+
+        verify(mMockAudioManager, never())
+                .dispatchAudioFocusChange(eq(audioFocusInfoClient2), anyInt(), eq(mAudioPolicy));
+    }
+
+    @Test
+    public void onAudioFocusRequest_forTwoDifferentZones_abandonInOne_requestGranted() {
+        CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus(false);
+        when(mCarAudioService.getZoneIdForUid(MEDIA_CLIENT_UID_1)).thenReturn(PRIMARY_ZONE_ID);
+        AudioFocusInfo audioFocusInfoClient1 = new AudioFocusInfoBuilder().setUsage(USAGE_MEDIA)
+                .setClientId(MEDIA_CLIENT_ID).setGainRequest(AUDIOFOCUS_GAIN)
+                .setClientUid(MEDIA_CLIENT_UID_1).createAudioFocusInfo();
+
+        requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfoClient1);
+
+        when(mCarAudioService.getZoneIdForUid(MEDIA_CLIENT_UID_2)).thenReturn(SECONDARY_ZONE_ID);
+        AudioFocusInfo audioFocusInfoClient2 = new AudioFocusInfoBuilder().setUsage(USAGE_MEDIA)
+                .setClientId(MEDIA_CLIENT_ID).setGainRequest(AUDIOFOCUS_GAIN)
+                .setClientUid(MEDIA_CLIENT_UID_2).createAudioFocusInfo();
+
+        requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfoClient2);
+
+        carZonesAudioFocus.onAudioFocusAbandon(audioFocusInfoClient2);
+
+        verify(mMockAudioManager, never())
+                .dispatchAudioFocusChange(eq(audioFocusInfoClient1), anyInt(), eq(mAudioPolicy));
+
+        verify(mMockAudioManager, never())
+                .dispatchAudioFocusChange(eq(audioFocusInfoClient2), anyInt(), eq(mAudioPolicy));
+    }
+
+    @Test
+    public void onAudioFocusRequest_withBundleFocusRequest_requestGranted() {
+        CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus(false);
+        when(mCarAudioService.isAudioZoneIdValid(PRIMARY_ZONE_ID)).thenReturn(true);
+
+        when(mCarAudioService.getZoneIdForUid(MEDIA_CLIENT_UID_1)).thenReturn(PRIMARY_ZONE_ID);
+        Bundle bundle = new Bundle();
+        bundle.putInt(CarAudioManager.AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID,
+                PRIMARY_ZONE_ID);
+        AudioFocusInfo audioFocusInfoClient = new AudioFocusInfoBuilder().setUsage(USAGE_MEDIA)
+                .setClientId(MEDIA_CLIENT_ID).setGainRequest(AUDIOFOCUS_GAIN)
+                .setClientUid(MEDIA_CLIENT_UID_1).setBundle(bundle).createAudioFocusInfo();
+
+        requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfoClient);
+
+        verify(mMockAudioManager, never())
+                .dispatchAudioFocusChange(eq(audioFocusInfoClient), anyInt(), eq(mAudioPolicy));
+    }
+
+    @Test
+    public void onAudioFocusRequest_repeatForSameZone_requestGranted() {
+        CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus(false);
+        when(mCarAudioService.getZoneIdForUid(MEDIA_CLIENT_UID_1)).thenReturn(PRIMARY_ZONE_ID);
+        AudioFocusInfo audioFocusInfoMediaClient = new AudioFocusInfoBuilder().setUsage(USAGE_MEDIA)
+                        .setClientId(MEDIA_CLIENT_ID).setGainRequest(AUDIOFOCUS_GAIN)
+                        .setClientUid(MEDIA_CLIENT_UID_1).createAudioFocusInfo();
+
+        requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfoMediaClient);
+
+        when(mCarAudioService.getZoneIdForUid(NAVIGATION_CLIENT_UID)).thenReturn(PRIMARY_ZONE_ID);
+        AudioFocusInfo audioFocusInfoNavClient =
+                new AudioFocusInfoBuilder().setUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
+                .setClientId(NAVIGATION_CLIENT_ID).setGainRequest(AUDIOFOCUS_GAIN)
+                .setClientUid(NAVIGATION_CLIENT_UID).createAudioFocusInfo();
+
+        requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfoNavClient);
+
+        verify(mMockAudioManager)
+                .dispatchAudioFocusChange(eq(audioFocusInfoMediaClient),
+                        anyInt(), eq(mAudioPolicy));
+
+        verify(mMockAudioManager, never())
+                .dispatchAudioFocusChange(eq(audioFocusInfoNavClient),
+                        anyInt(), eq(mAudioPolicy));
+    }
+
+    @Test
+    public void onAudioFocusRequest_forNavigationWhileOnCall_rejectNavOnCall_requestFailed() {
+        CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus(false);
+        when(mCarAudioService.isAudioZoneIdValid(PRIMARY_ZONE_ID)).thenReturn(true);
+        setUpRejectNavigationOnCallValue(true);
+        carZonesAudioFocus.updateUserForZoneId(PRIMARY_ZONE_ID, TEST_USER_ID);
+
+        when(mCarAudioService.getZoneIdForUid(CALL_CLIENT_UID)).thenReturn(PRIMARY_ZONE_ID);
+        AudioFocusInfo audioFocusInfoCallClient = new AudioFocusInfoBuilder()
+                .setUsage(USAGE_VOICE_COMMUNICATION)
+                .setGainRequest(AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)
+                .setClientId(CALL_CLIENT_ID)
+                .setClientUid(CALL_CLIENT_UID).createAudioFocusInfo();
+
+        requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfoCallClient);
+
+        when(mCarAudioService.getZoneIdForUid(NAVIGATION_CLIENT_UID)).thenReturn(PRIMARY_ZONE_ID);
+        AudioFocusInfo audioFocusInfoNavClient =
+                new AudioFocusInfoBuilder().setUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
+                        .setGainRequest(AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)
+                        .setClientId(NAVIGATION_CLIENT_ID)
+                        .setClientUid(NAVIGATION_CLIENT_UID).createAudioFocusInfo();
+
+        carZonesAudioFocus
+                .onAudioFocusRequest(audioFocusInfoNavClient, AUDIOFOCUS_REQUEST_GRANTED);
+        verify(mMockAudioManager).setFocusRequestResult(audioFocusInfoNavClient,
+                AUDIOFOCUS_REQUEST_FAILED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocusRequest_forNavigationWhileOnCall_noRejectNavOnCall_requestSucceeds() {
+        CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus(false);
+        when(mCarAudioService.isAudioZoneIdValid(PRIMARY_ZONE_ID)).thenReturn(true);
+        setUpRejectNavigationOnCallValue(false);
+        carZonesAudioFocus.updateUserForZoneId(PRIMARY_ZONE_ID, TEST_USER_ID);
+
+        when(mCarAudioService.getZoneIdForUid(CALL_CLIENT_UID)).thenReturn(PRIMARY_ZONE_ID);
+        AudioFocusInfo audioFocusInfoCallClient = new AudioFocusInfoBuilder()
+                .setUsage(USAGE_VOICE_COMMUNICATION)
+                .setGainRequest(AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)
+                .setClientId(CALL_CLIENT_ID)
+                .setClientUid(CALL_CLIENT_UID).createAudioFocusInfo();
+
+        requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfoCallClient);
+
+        when(mCarAudioService.getZoneIdForUid(NAVIGATION_CLIENT_UID)).thenReturn(PRIMARY_ZONE_ID);
+        AudioFocusInfo audioFocusInfoNavClient =
+                new AudioFocusInfoBuilder().setUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
+                        .setGainRequest(AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)
+                        .setClientId(NAVIGATION_CLIENT_ID)
+                        .setClientUid(NAVIGATION_CLIENT_UID).createAudioFocusInfo();
+
+
+        carZonesAudioFocus
+                .onAudioFocusRequest(audioFocusInfoNavClient, AUDIOFOCUS_REQUEST_GRANTED);
+        verify(mMockAudioManager).setFocusRequestResult(audioFocusInfoNavClient,
+                AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocusRequest_forMediaWhileOnCall_withDelayedEnable_delayedSucceeds() {
+        CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus(true);
+        when(mCarAudioService.isAudioZoneIdValid(PRIMARY_ZONE_ID)).thenReturn(true);
+
+        when(mCarAudioService.getZoneIdForUid(CALL_CLIENT_UID)).thenReturn(PRIMARY_ZONE_ID);
+        AudioFocusInfo audioFocusInfoCallClient = new AudioFocusInfoBuilder()
+                .setUsage(USAGE_VOICE_COMMUNICATION)
+                .setGainRequest(AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)
+                .setClientId(CALL_CLIENT_ID)
+                .setClientUid(CALL_CLIENT_UID).createAudioFocusInfo();
+
+        requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfoCallClient);
+
+        when(mCarAudioService.getZoneIdForUid(MEDIA_CLIENT_UID_1)).thenReturn(PRIMARY_ZONE_ID);
+        AudioFocusInfo audioFocusMediaClient =
+                new AudioFocusInfoBuilder().setUsage(USAGE_MEDIA)
+                        .setGainRequest(AUDIOFOCUS_GAIN)
+                        .setClientId(MEDIA_CLIENT_ID)
+                        .setDelayedFocusRequestEnable(true)
+                        .setClientUid(MEDIA_CLIENT_UID_1).createAudioFocusInfo();
+
+
+        carZonesAudioFocus
+                .onAudioFocusRequest(audioFocusMediaClient, AUDIOFOCUS_REQUEST_GRANTED);
+        verify(mMockAudioManager).setFocusRequestResult(audioFocusMediaClient,
+                AUDIOFOCUS_REQUEST_DELAYED, mAudioPolicy);
+    }
+
+    private void requestFocusAndAssertIfRequestNotGranted(CarZonesAudioFocus carZonesAudioFocus,
+            AudioFocusInfo audioFocusClient) {
+        requestFocusAndAssertIfRequestDiffers(carZonesAudioFocus, audioFocusClient,
+                AUDIOFOCUS_REQUEST_GRANTED);
+    }
+
+    private void requestFocusAndAssertIfRequestDiffers(CarZonesAudioFocus carZonesAudioFocus,
+            AudioFocusInfo audioFocusClient, int expectedAudioFocusResults) {
+        carZonesAudioFocus.onAudioFocusRequest(audioFocusClient, expectedAudioFocusResults);
+        verify(mMockAudioManager)
+                .setFocusRequestResult(audioFocusClient, expectedAudioFocusResults, mAudioPolicy);
+    }
+
+    private CarAudioZone[] generateAudioZones() {
+        mPrimaryAudioZone = new CarAudioZone(PRIMARY_ZONE_ID, "Primary zone");
+        mSecondaryAudioZone = new CarAudioZone(SECONDARY_ZONE_ID, "Secondary zone");
+        CarAudioZone[] zones = {mPrimaryAudioZone, mSecondaryAudioZone};
+        return zones;
+    }
+
+    private CarZonesAudioFocus getCarZonesAudioFocus(boolean enableDelayedFocus) {
+        CarZonesAudioFocus carZonesAudioFocus =
+                new CarZonesAudioFocus(mMockAudioManager, mMockPackageManager,
+                        mMockAudioZones, mCarAudioSettings, enableDelayedFocus);
+        carZonesAudioFocus.setOwningPolicy(mCarAudioService, mAudioPolicy);
+        return carZonesAudioFocus;
+    }
+
+    private void setUpRejectNavigationOnCallValue(boolean rejectNavigationOnCall) {
+        when(mCarAudioSettings.getContentResolver()).thenReturn(mContentResolver);
+        when(mCarAudioSettings.isRejectNavigationOnCallEnabledInSettings(TEST_USER_ID))
+                .thenReturn(rejectNavigationOnCall);
+    }
+
+    public class AudioFocusInfoBuilder {
+        private int mUsage;
+        private int mClientUid;
+        private String mClientId;
+        private int mGainRequest;
+        private String mPackageName = PACKAGE_NAME;
+        private Bundle mBundle = null;
+        private int mLossReceived = AudioManager.AUDIOFOCUS_NONE;
+        private int mFlags = AUDIOFOCUS_FLAG;
+        private int mSdk = Build.VERSION.SDK_INT;
+        private boolean mDelayedFocusRequestEnabled = false;
+
+        public AudioFocusInfoBuilder setUsage(int usage) {
+            mUsage = usage;
+            return this;
+        }
+
+        public AudioFocusInfoBuilder setClientUid(int clientUid) {
+            mClientUid = clientUid;
+            return this;
+        }
+
+        public AudioFocusInfoBuilder setClientId(String clientId) {
+            mClientId = clientId;
+            return this;
+        }
+
+        public AudioFocusInfoBuilder setPackageName(String packageName) {
+            mPackageName = packageName;
+            return this;
+        }
+
+        public AudioFocusInfoBuilder setGainRequest(int gainRequest) {
+            mGainRequest = gainRequest;
+            return this;
+        }
+
+        public AudioFocusInfoBuilder setLossReceived(int lossReceived) {
+            mLossReceived = lossReceived;
+            return this;
+        }
+
+        public AudioFocusInfoBuilder setSdk(int sdk) {
+            mSdk = sdk;
+            return this;
+        }
+
+        public AudioFocusInfoBuilder setBundle(Bundle bundle) {
+            mBundle = bundle;
+            return this;
+        }
+
+        public AudioFocusInfoBuilder setDelayedFocusRequestEnable(boolean b) {
+            mDelayedFocusRequestEnabled = b;
+            return this;
+        }
+
+        public AudioFocusInfo createAudioFocusInfo() {
+            AudioAttributes.Builder builder = new AudioAttributes.Builder().setUsage(mUsage);
+            if (mBundle != null) {
+                builder = builder.addBundle(mBundle);
+            }
+            if (mDelayedFocusRequestEnabled) {
+                mFlags = mFlags | AudioManager.AUDIOFOCUS_FLAG_DELAY_OK;
+            }
+            AudioAttributes audioAttributes = builder.build();
+            return new AudioFocusInfo(audioAttributes, mClientUid, mClientId,
+                    mPackageName, mGainRequest, mLossReceived, mFlags, mSdk);
+        }
+    }
+}
diff --git a/tests/carservice_test/src/com/android/car/audio/OWNERS b/tests/carservice_test/src/com/android/car/audio/OWNERS
new file mode 100644
index 0000000..8d34cdd
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/audio/OWNERS
@@ -0,0 +1,3 @@
+# Audio owners
+haydengomes@google.com
+oscarazu@google.com
\ No newline at end of file
diff --git a/tests/carservice_test/src/com/android/car/garagemode/ControllerTest.java b/tests/carservice_test/src/com/android/car/garagemode/ControllerTest.java
index 88881d7..d013d28 100644
--- a/tests/carservice_test/src/com/android/car/garagemode/ControllerTest.java
+++ b/tests/carservice_test/src/com/android/car/garagemode/ControllerTest.java
@@ -24,6 +24,7 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -35,22 +36,26 @@
 import android.content.Intent;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.UserHandle;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.car.CarLocalServices;
+import com.android.car.systeminterface.SystemInterface;
 import com.android.car.user.CarUserService;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -61,13 +66,17 @@
 public class ControllerTest {
     private static final Logger LOG = new Logger("ControllerTest");
 
+    @Rule public final MockitoRule rule = MockitoJUnit.rule();
+
     @Mock private Context mContextMock;
     @Mock private Looper mLooperMock;
     @Mock private Handler mHandlerMock;
     @Mock private Car mCarMock;
     @Mock private CarPowerManager mCarPowerManagerMock;
     @Mock private CarUserService mCarUserServiceMock;
+    @Mock private SystemInterface mSystemInterfaceMock;
     private CarUserService mCarUserServiceOriginal;
+    private SystemInterface mSystemInterfaceOriginal;
     @Captor private ArgumentCaptor<Intent> mIntentCaptor;
     @Captor private ArgumentCaptor<Integer> mIntegerCaptor;
 
@@ -88,7 +97,6 @@
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
         mWakeupPolicy = new WakeupPolicy(sTemplateWakeupSchedule);
         mController = new Controller(
                 mContextMock,
@@ -101,19 +109,26 @@
         mCarUserServiceOriginal = CarLocalServices.getService(CarUserService.class);
         CarLocalServices.removeServiceForTest(CarUserService.class);
         CarLocalServices.addService(CarUserService.class, mCarUserServiceMock);
+        CarLocalServices.removeServiceForTest(SystemInterface.class);
+        CarLocalServices.addService(SystemInterface.class, mSystemInterfaceMock);
         doReturn(new ArrayList<Integer>()).when(mCarUserServiceMock).startAllBackgroundUsers();
+        doNothing().when(mSystemInterfaceMock)
+                .sendBroadcastAsUser(any(Intent.class), any(UserHandle.class));
     }
 
     @After
     public void tearDown() {
         CarLocalServices.removeServiceForTest(CarUserService.class);
         CarLocalServices.addService(CarUserService.class, mCarUserServiceOriginal);
+        CarLocalServices.removeServiceForTest(SystemInterface.class);
+        CarLocalServices.addService(SystemInterface.class, mSystemInterfaceOriginal);
     }
 
     @Test
     public void testOnShutdownPrepare_shouldInitiateGarageMode() {
         startAndAssertGarageModeWithSignal(CarPowerStateListener.SHUTDOWN_PREPARE);
-        verify(mContextMock).sendBroadcast(mIntentCaptor.capture());
+        verify(mSystemInterfaceMock)
+                .sendBroadcastAsUser(mIntentCaptor.capture(), eq(UserHandle.ALL));
         verifyGarageModeBroadcast(mIntentCaptor.getAllValues(), 1, ACTION_GARAGE_MODE_ON);
     }
 
@@ -132,7 +147,8 @@
         verify(mHandlerMock, Mockito.atLeastOnce()).removeCallbacks(any(Runnable.class));
 
         // Verify that OFF signal broadcasted to JobScheduler
-        verify(mContextMock, times(2)).sendBroadcast(mIntentCaptor.capture());
+        verify(mSystemInterfaceMock, times(2))
+                .sendBroadcastAsUser(mIntentCaptor.capture(), eq(UserHandle.ALL));
         verifyGarageModeBroadcast(mIntentCaptor.getAllValues(), 1, ACTION_GARAGE_MODE_ON);
         verifyGarageModeBroadcast(mIntentCaptor.getAllValues(), 2, ACTION_GARAGE_MODE_OFF);
 
diff --git a/tests/carservice_test/src/com/android/car/garagemode/GarageModeServiceTest.java b/tests/carservice_test/src/com/android/car/garagemode/GarageModeServiceTest.java
index 83f2c87..89e41cf 100644
--- a/tests/carservice_test/src/com/android/car/garagemode/GarageModeServiceTest.java
+++ b/tests/carservice_test/src/com/android/car/garagemode/GarageModeServiceTest.java
@@ -25,16 +25,18 @@
 import android.content.ContentResolver;
 import android.content.Context;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 
 import java.io.PrintWriter;
 import java.util.List;
@@ -42,6 +44,7 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class GarageModeServiceTest {
+    @Rule public final MockitoRule rule = MockitoJUnit.rule();
     @Mock private Context mMockContext;
     @Mock private Controller mMockController;
     @Mock private ContentResolver mMockContentResolver;
@@ -52,7 +55,6 @@
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
         when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
         mService = new GarageModeService(mMockContext, mMockController);
     }
diff --git a/tests/carservice_test/src/com/android/car/garagemode/WakeupPolicyTest.java b/tests/carservice_test/src/com/android/car/garagemode/WakeupPolicyTest.java
index 921434b..092724f 100644
--- a/tests/carservice_test/src/com/android/car/garagemode/WakeupPolicyTest.java
+++ b/tests/carservice_test/src/com/android/car/garagemode/WakeupPolicyTest.java
@@ -20,9 +20,9 @@
 
 import android.content.Context;
 
-import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.car.R;
 
@@ -82,6 +82,6 @@
     }
 
     private Context getContext() {
-        return InstrumentationRegistry.getTargetContext();
+        return InstrumentationRegistry.getInstrumentation().getTargetContext();
     }
 }
diff --git a/tests/carservice_test/src/com/android/car/input/CarInputManagerTest.java b/tests/carservice_test/src/com/android/car/input/CarInputManagerTest.java
new file mode 100644
index 0000000..907bdc2
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/input/CarInputManagerTest.java
@@ -0,0 +1,605 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.input;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.annotation.NonNull;
+import android.car.Car;
+import android.car.input.CarInputManager;
+import android.car.input.RotaryEvent;
+import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
+import android.util.Log;
+import android.util.Pair;
+import android.view.KeyEvent;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import com.android.car.CarServiceUtils;
+import com.android.car.MockedCarTestBase;
+import com.android.car.vehiclehal.VehiclePropValueBuilder;
+import com.android.internal.annotations.GuardedBy;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public final class CarInputManagerTest extends MockedCarTestBase {
+    private static final String TAG = CarInputManagerTest.class.getSimpleName();
+
+    private static final int INVALID_DISPLAY_TYPE = -1;
+    private static final int INVALID_INPUT_TYPE = -1;
+
+    private CarInputManager mCarInputManager;
+
+    private final class CaptureCallback implements CarInputManager.CarInputCaptureCallback {
+
+        private static final long EVENT_WAIT_TIME = 500;
+
+        private final Object mLock = new Object();
+
+        // Stores passed events. Last one in front
+        @GuardedBy("mLock")
+        private final LinkedList<Pair<Integer, List<KeyEvent>>> mKeyEvents = new LinkedList<>();
+
+        // Stores passed events. Last one in front
+        @GuardedBy("mLock")
+        private final LinkedList<Pair<Integer, List<RotaryEvent>>> mRotaryEvents =
+                new LinkedList<>();
+
+        // Stores passed state changes. Last one in front
+        @GuardedBy("mLock")
+        private final LinkedList<Pair<Integer, int[]>> mStateChanges = new LinkedList<>();
+
+        private final Semaphore mKeyEventWait = new Semaphore(0);
+        private final Semaphore mRotaryEventWait = new Semaphore(0);
+        private final Semaphore mStateChangeWait = new Semaphore(0);
+
+        @Override
+        public void onKeyEvents(int targetDisplayId, List<KeyEvent> keyEvents) {
+            Log.i(TAG, "onKeyEvents event:" + keyEvents.get(0) + " this:" + this);
+            synchronized (mLock) {
+                mKeyEvents.addFirst(new Pair<Integer, List<KeyEvent>>(targetDisplayId, keyEvents));
+            }
+            mKeyEventWait.release();
+        }
+
+        @Override
+        public void onRotaryEvents(int targetDisplayId, List<RotaryEvent> events) {
+            Log.i(TAG, "onRotaryEvents event:" + events.get(0) + " this:" + this);
+            synchronized (mLock) {
+                mRotaryEvents.addFirst(new Pair<Integer, List<RotaryEvent>>(targetDisplayId,
+                        events));
+            }
+            mRotaryEventWait.release();
+        }
+
+        @Override
+        public void onCaptureStateChanged(int targetDisplayId,
+                @NonNull @CarInputManager.InputTypeEnum int[] activeInputTypes) {
+            Log.i(TAG, "onCaptureStateChanged types:" + Arrays.toString(activeInputTypes)
+                    + " this:" + this);
+            synchronized (mLock) {
+                mStateChanges.addFirst(new Pair<Integer, int[]>(targetDisplayId, activeInputTypes));
+            }
+            mStateChangeWait.release();
+        }
+
+        private void resetAllEventsWaiting() {
+            mStateChangeWait.drainPermits();
+            mKeyEventWait.drainPermits();
+            mRotaryEventWait.drainPermits();
+        }
+
+        private void waitForStateChange() throws Exception {
+            mStateChangeWait.tryAcquire(EVENT_WAIT_TIME, TimeUnit.MILLISECONDS);
+        }
+
+        private void waitForKeyEvent() throws Exception  {
+            mKeyEventWait.tryAcquire(EVENT_WAIT_TIME, TimeUnit.MILLISECONDS);
+        }
+
+        private void waitForRotaryEvent() throws Exception {
+            mRotaryEventWait.tryAcquire(EVENT_WAIT_TIME, TimeUnit.MILLISECONDS);
+        }
+
+        private LinkedList<Pair<Integer, List<KeyEvent>>> getkeyEvents() {
+            synchronized (mLock) {
+                LinkedList<Pair<Integer, List<KeyEvent>>> r =
+                        new LinkedList<Pair<Integer, List<KeyEvent>>>(mKeyEvents);
+                Log.i(TAG, "getKeyEvents size:" + r.size() + ",this:" + this);
+                return r;
+            }
+        }
+
+        private LinkedList<Pair<Integer, List<RotaryEvent>>> getRotaryEvents() {
+            synchronized (mLock) {
+                LinkedList<Pair<Integer, List<RotaryEvent>>> r =
+                        new LinkedList<Pair<Integer, List<RotaryEvent>>>(mRotaryEvents);
+                Log.i(TAG, "getRotaryEvents size:" + r.size() + ",this:" + this);
+                return r;
+            }
+        }
+
+        private LinkedList<Pair<Integer, int[]>> getStateChanges() {
+            synchronized (mLock) {
+                return new LinkedList<Pair<Integer, int[]>>(mStateChanges);
+            }
+        }
+    }
+
+    private final CaptureCallback mCallback0 = new CaptureCallback();
+    private final CaptureCallback mCallback1 = new CaptureCallback();
+
+    @Override
+    protected synchronized void configureMockedHal() {
+        addProperty(VehicleProperty.HW_KEY_INPUT,
+                VehiclePropValueBuilder.newBuilder(VehicleProperty.HW_KEY_INPUT)
+                        .addIntValue(0, 0, 0)
+                        .build());
+        addProperty(VehicleProperty.HW_ROTARY_INPUT,
+                VehiclePropValueBuilder.newBuilder(VehicleProperty.HW_ROTARY_INPUT)
+                        .addIntValue(0, 1, 0)
+                        .build());
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mCarInputManager = (CarInputManager) getCar().getCarManager(Car.CAR_INPUT_SERVICE);
+        assertThat(mCarInputManager).isNotNull();
+    }
+
+    @Test
+    public void testInvalidArgs() {
+        // TODO(b/150818155) Need to migrate cluster code to use this to enable it.
+        assertThrows(IllegalArgumentException.class,
+                () -> mCarInputManager.requestInputEventCapture(mCallback0,
+                        CarInputManager.TARGET_DISPLAY_TYPE_CLUSTER,
+                        new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0));
+
+        // Invalid display
+        assertThrows(IllegalArgumentException.class,
+                () -> mCarInputManager.requestInputEventCapture(mCallback0, INVALID_DISPLAY_TYPE,
+                        new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0));
+
+        // Invalid input types
+        assertThrows(IllegalArgumentException.class,
+                () -> mCarInputManager.requestInputEventCapture(mCallback0,
+                        CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                        new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION, INVALID_INPUT_TYPE},
+                        0));
+        assertThrows(IllegalArgumentException.class,
+                () -> mCarInputManager.requestInputEventCapture(mCallback0,
+                        CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                        new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION},
+                        CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY));
+        assertThrows(IllegalArgumentException.class,
+                () -> mCarInputManager.requestInputEventCapture(mCallback0,
+                        CarInputManager.TARGET_DISPLAY_TYPE_MAIN, new int[]{INVALID_INPUT_TYPE},
+                        0));
+        assertThrows(IllegalArgumentException.class,
+                () -> mCarInputManager.requestInputEventCapture(mCallback0,
+                        CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                        new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION, INVALID_INPUT_TYPE},
+                        0));
+    }
+
+    private CarInputManager createAnotherCarInputManager() {
+        return (CarInputManager) createNewCar().getCarManager(Car.CAR_INPUT_SERVICE);
+    }
+
+    @Test
+    public void testFailWithFullCaptureHigherPriority() throws Exception {
+        CarInputManager carInputManager0 = createAnotherCarInputManager();
+        int r = carInputManager0.requestInputEventCapture(mCallback0,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{CarInputManager.INPUT_TYPE_ALL_INPUTS},
+                CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
+
+        //TODO test event
+
+        r = mCarInputManager.requestInputEventCapture(mCallback1,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_FAILED);
+
+        carInputManager0.releaseInputEventCapture(CarInputManager.TARGET_DISPLAY_TYPE_MAIN);
+
+        r = mCarInputManager.requestInputEventCapture(mCallback1,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
+
+        //TODO test event
+    }
+
+    @Test
+    public void testDelayedGrantWithFullCapture() throws Exception {
+        mCallback1.resetAllEventsWaiting();
+        CarInputManager carInputManager0 = createAnotherCarInputManager();
+        int r = carInputManager0.requestInputEventCapture(mCallback0,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{CarInputManager.INPUT_TYPE_ALL_INPUTS},
+                CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
+
+        injectKeyEvent(true, KeyEvent.KEYCODE_NAVIGATE_NEXT);
+        mCallback0.waitForKeyEvent();
+        assertLastKeyEvent(CarInputManager.TARGET_DISPLAY_TYPE_MAIN, true,
+                KeyEvent.KEYCODE_NAVIGATE_NEXT, mCallback0);
+
+        injectKeyEvent(true, KeyEvent.KEYCODE_DPAD_CENTER);
+        mCallback0.waitForKeyEvent();
+        assertLastKeyEvent(CarInputManager.TARGET_DISPLAY_TYPE_MAIN, true,
+                KeyEvent.KEYCODE_DPAD_CENTER, mCallback0);
+
+        int numClicks = 3;
+        injectRotaryEvent(CarInputManager.TARGET_DISPLAY_TYPE_MAIN, numClicks);
+        mCallback0.waitForRotaryEvent();
+        assertLastRotaryEvent(CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION, numClicks, mCallback0);
+
+        r = mCarInputManager.requestInputEventCapture(mCallback1,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION},
+                CarInputManager.CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_DELAYED);
+
+        injectRotaryEvent(CarInputManager.TARGET_DISPLAY_TYPE_MAIN, numClicks);
+        waitForDispatchToMain();
+        assertNumberOfOnRotaryEvents(0, mCallback1);
+
+        carInputManager0.releaseInputEventCapture(CarInputManager.TARGET_DISPLAY_TYPE_MAIN);
+
+        // Now capture should be granted back
+        mCallback1.waitForStateChange();
+        assertLastStateChange(CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{
+                        CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION},
+                mCallback1);
+        assertNoStateChange(mCallback0);
+
+        injectRotaryEvent(CarInputManager.TARGET_DISPLAY_TYPE_MAIN, numClicks);
+        mCallback1.waitForRotaryEvent();
+        assertLastRotaryEvent(CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION, numClicks, mCallback1);
+    }
+
+    @Test
+    public void testOneClientTransitionFromFullToNonFull() throws Exception {
+        CarInputManager carInputManager0 = createAnotherCarInputManager();
+        CarInputManager carInputManager1 = createAnotherCarInputManager();
+
+        int r = carInputManager0.requestInputEventCapture(mCallback0,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{CarInputManager.INPUT_TYPE_ALL_INPUTS},
+                CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
+
+        r = mCarInputManager.requestInputEventCapture(mCallback1,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{
+                        CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION,
+                        CarInputManager.INPUT_TYPE_NAVIGATE_KEYS},
+                CarInputManager.CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_DELAYED);
+
+        r = carInputManager0.requestInputEventCapture(mCallback0,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{
+                        CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION,
+                        CarInputManager.INPUT_TYPE_DPAD_KEYS}, 0);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
+
+        waitForDispatchToMain();
+        assertLastStateChange(CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{CarInputManager.INPUT_TYPE_NAVIGATE_KEYS},
+                mCallback1);
+        assertNoStateChange(mCallback0);
+    }
+
+    @Test
+    public void testSwitchFromFullCaptureToPerTypeCapture() throws Exception {
+        int r = mCarInputManager.requestInputEventCapture(mCallback0,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{CarInputManager.INPUT_TYPE_ALL_INPUTS},
+                CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
+
+        r = mCarInputManager.requestInputEventCapture(mCallback1,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
+    }
+
+    @Test
+    public void testIndependentTwoCaptures() throws Exception {
+        int r = createAnotherCarInputManager().requestInputEventCapture(mCallback0,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
+
+        int numClicks = 3;
+        injectRotaryEvent(CarInputManager.TARGET_DISPLAY_TYPE_MAIN, numClicks);
+        mCallback0.waitForRotaryEvent();
+        assertLastRotaryEvent(CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION, numClicks, mCallback0);
+
+        r = mCarInputManager.requestInputEventCapture(mCallback1,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{CarInputManager.INPUT_TYPE_NAVIGATE_KEYS}, 0);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
+
+        injectKeyEvent(true, KeyEvent.KEYCODE_NAVIGATE_NEXT);
+        mCallback1.waitForKeyEvent();
+        assertLastKeyEvent(CarInputManager.TARGET_DISPLAY_TYPE_MAIN, true,
+                KeyEvent.KEYCODE_NAVIGATE_NEXT, mCallback1);
+    }
+
+    @Test
+    public void testTwoClientsOverwrap() throws Exception {
+        CarInputManager carInputManager0 = createAnotherCarInputManager();
+        CarInputManager carInputManager1 = createAnotherCarInputManager();
+
+        mCallback0.resetAllEventsWaiting();
+        int r = carInputManager0.requestInputEventCapture(mCallback0,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{
+                        CarInputManager.INPUT_TYPE_DPAD_KEYS,
+                        CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
+
+        injectKeyEvent(true, KeyEvent.KEYCODE_DPAD_CENTER);
+        mCallback0.waitForKeyEvent();
+        assertLastKeyEvent(CarInputManager.TARGET_DISPLAY_TYPE_MAIN, true,
+                KeyEvent.KEYCODE_DPAD_CENTER, mCallback0);
+
+        int numClicks = 3;
+        injectRotaryEvent(CarInputManager.TARGET_DISPLAY_TYPE_MAIN, numClicks);
+        mCallback0.waitForRotaryEvent();
+        assertLastRotaryEvent(CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION, numClicks, mCallback0);
+
+        r = carInputManager1.requestInputEventCapture(mCallback1,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{
+                        CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION,
+                        CarInputManager.INPUT_TYPE_NAVIGATE_KEYS}, 0);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
+
+        mCallback1.waitForStateChange();
+        assertLastStateChange(CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{CarInputManager.INPUT_TYPE_DPAD_KEYS},
+                mCallback0);
+        assertNoStateChange(mCallback1);
+
+        injectKeyEvent(true, KeyEvent.KEYCODE_NAVIGATE_NEXT);
+        mCallback1.waitForKeyEvent();
+        assertLastKeyEvent(CarInputManager.TARGET_DISPLAY_TYPE_MAIN, true,
+                KeyEvent.KEYCODE_NAVIGATE_NEXT, mCallback1);
+        assertNumberOfOnKeyEvents(1, mCallback0);
+
+        injectKeyEvent(true, KeyEvent.KEYCODE_DPAD_CENTER);
+        mCallback0.waitForKeyEvent();
+        assertLastKeyEvent(CarInputManager.TARGET_DISPLAY_TYPE_MAIN, true,
+                KeyEvent.KEYCODE_DPAD_CENTER, mCallback0);
+        assertNumberOfOnKeyEvents(2, mCallback0);
+
+        injectRotaryEvent(CarInputManager.TARGET_DISPLAY_TYPE_MAIN, numClicks);
+        mCallback1.waitForRotaryEvent();
+        assertLastRotaryEvent(CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION, numClicks, mCallback1);
+        assertNumberOfOnRotaryEvents(1, mCallback0);
+
+
+
+        mCallback0.resetAllEventsWaiting();
+        carInputManager1.releaseInputEventCapture(CarInputManager.TARGET_DISPLAY_TYPE_MAIN);
+
+        mCallback0.waitForStateChange();
+        assertLastStateChange(CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{CarInputManager.INPUT_TYPE_DPAD_KEYS,
+                        CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION},
+                mCallback0);
+        assertNoStateChange(mCallback1);
+
+        injectRotaryEvent(CarInputManager.TARGET_DISPLAY_TYPE_MAIN, numClicks);
+        mCallback0.waitForRotaryEvent();
+        assertLastRotaryEvent(CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION, numClicks, mCallback0);
+    }
+
+    @Test
+    public void testInteractionWithFullCapturer() throws Exception {
+        CarInputManager carInputManager0 = createAnotherCarInputManager();
+        CarInputManager carInputManager1 = createAnotherCarInputManager();
+
+        Log.i(TAG, "requestInputEventCapture callback 0");
+
+        int r = carInputManager0.requestInputEventCapture(mCallback0,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{
+                        CarInputManager.INPUT_TYPE_DPAD_KEYS,
+                        CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
+
+        Log.i(TAG, "requestInputEventCapture callback 1");
+        r = carInputManager1.requestInputEventCapture(mCallback1,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{CarInputManager.INPUT_TYPE_ALL_INPUTS},
+                CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
+
+        waitForDispatchToMain();
+        assertLastStateChange(CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[0], mCallback0);
+        assertNoStateChange(mCallback1);
+
+        Log.i(TAG, "releaseInputEventCapture callback 1");
+        carInputManager1.releaseInputEventCapture(CarInputManager.TARGET_DISPLAY_TYPE_MAIN);
+
+        waitForDispatchToMain();
+        assertLastStateChange(CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{CarInputManager.INPUT_TYPE_DPAD_KEYS,
+                        CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION},
+                mCallback0);
+        assertNoStateChange(mCallback1);
+    }
+
+    @Test
+    public void testSingleClientUpdates() throws Exception {
+        int r = mCarInputManager.requestInputEventCapture(mCallback0,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{
+                        CarInputManager.INPUT_TYPE_DPAD_KEYS,
+                        CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
+
+        r = mCarInputManager.requestInputEventCapture(mCallback0,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{
+                        CarInputManager.INPUT_TYPE_DPAD_KEYS,
+                        CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
+
+        waitForDispatchToMain();
+        assertNoStateChange(mCallback0);
+
+        r = mCarInputManager.requestInputEventCapture(mCallback0,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{
+                        CarInputManager.INPUT_TYPE_DPAD_KEYS,
+                        CarInputManager.INPUT_TYPE_NAVIGATE_KEYS}, 0);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
+
+        waitForDispatchToMain();
+        assertNoStateChange(mCallback0);
+
+        r = mCarInputManager.requestInputEventCapture(mCallback0,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{CarInputManager.INPUT_TYPE_ALL_INPUTS},
+                CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
+
+        waitForDispatchToMain();
+        assertNoStateChange(mCallback0);
+
+        r = mCarInputManager.requestInputEventCapture(mCallback0,
+                CarInputManager.TARGET_DISPLAY_TYPE_MAIN,
+                new int[]{CarInputManager.INPUT_TYPE_ALL_INPUTS},
+                CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY);
+        assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
+
+        waitForDispatchToMain();
+        assertNoStateChange(mCallback0);
+    }
+
+    /**
+     * Events dispatched to main, so this should guarantee that all event dispatched are completed.
+     */
+    private void waitForDispatchToMain() {
+        // Needs to twice as it is dispatched to main inside car service once and it is
+        // dispatched to main inside CarInputManager once.
+        CarServiceUtils.runOnMainSync(() -> { });
+        CarServiceUtils.runOnMainSync(() -> { });
+    }
+
+    private void assertLastKeyEvent(int displayId, boolean down, int keyCode,
+            CaptureCallback callback) {
+        LinkedList<Pair<Integer, List<KeyEvent>>> events = callback.getkeyEvents();
+        assertThat(events).isNotEmpty();
+        Pair<Integer, List<KeyEvent>> lastEvent = events.getFirst();
+        assertThat(lastEvent.first).isEqualTo(displayId);
+        assertThat(lastEvent.second).hasSize(1);
+        KeyEvent keyEvent = lastEvent.second.get(0);
+        assertThat(keyEvent.getAction()).isEqualTo(
+                down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP);
+        assertThat(keyEvent.getKeyCode()).isEqualTo(keyCode);
+    }
+
+    private void assertNumberOfOnKeyEvents(int expectedNumber, CaptureCallback callback) {
+        LinkedList<Pair<Integer, List<KeyEvent>>> events = callback.getkeyEvents();
+        assertThat(events).hasSize(expectedNumber);
+    }
+
+    private void assertLastRotaryEvent(int displayId, int rotaryType, int numberOfClicks,
+            CaptureCallback callback) {
+        LinkedList<Pair<Integer, List<RotaryEvent>>> rotaryEvents = callback.getRotaryEvents();
+        assertThat(rotaryEvents).isNotEmpty();
+        Pair<Integer, List<RotaryEvent>> lastEvent = rotaryEvents.getFirst();
+        assertThat(lastEvent.first).isEqualTo(displayId);
+        assertThat(lastEvent.second).hasSize(1);
+        RotaryEvent rotaryEvent = lastEvent.second.get(0);
+        assertThat(rotaryEvent.getInputType()).isEqualTo(rotaryType);
+        assertThat(rotaryEvent.getNumberOfClicks()).isEqualTo(numberOfClicks);
+        // TODO(b/151225008) Test timestamp
+    }
+
+    private void assertNumberOfOnRotaryEvents(int expectedNumber, CaptureCallback callback) {
+        LinkedList<Pair<Integer, List<RotaryEvent>>> rotaryEvents = callback.getRotaryEvents();
+        assertThat(rotaryEvents).hasSize(expectedNumber);
+    }
+
+    private void assertLastStateChange(int expectedTargetDisplayId, int[] expectedInputTypes,
+            CaptureCallback callback) {
+        LinkedList<Pair<Integer, int[]>> changes = callback.getStateChanges();
+        assertThat(changes).isNotEmpty();
+        Pair<Integer, int[]> lastChange = changes.getFirst();
+        assertStateChange(expectedTargetDisplayId, expectedInputTypes, lastChange);
+    }
+
+    private void assertNoStateChange(CaptureCallback callback) {
+        assertThat(callback.getStateChanges()).isEmpty();
+    }
+
+    private void assertStateChange(int expectedTargetDisplayId, int[] expectedInputTypes,
+            Pair<Integer, int[]> actual) {
+        Arrays.sort(expectedInputTypes);
+        assertThat(actual.first).isEqualTo(expectedTargetDisplayId);
+        assertThat(actual.second).isEqualTo(expectedInputTypes);
+    }
+
+    private void injectKeyEvent(boolean down, int keyCode) {
+        getMockedVehicleHal().injectEvent(
+                VehiclePropValueBuilder.newBuilder(VehicleProperty.HW_KEY_INPUT)
+                .addIntValue(down ? 0 : 1, keyCode, 0)
+                .build());
+    }
+
+    private void injectRotaryEvent(int displayId, int numClicks) {
+        VehiclePropValueBuilder builder = VehiclePropValueBuilder.newBuilder(
+                VehicleProperty.HW_ROTARY_INPUT)
+                .addIntValue(0 /* navigation oly for now */, numClicks, displayId);
+        for (int i = 0; i < numClicks - 1; i++) {
+            builder.addIntValue(0);
+        }
+        getMockedVehicleHal().injectEvent(builder.build());
+    }
+}
diff --git a/tests/carservice_test/src/com/android/car/pm/ActivityBlockingActivityTest.java b/tests/carservice_test/src/com/android/car/pm/ActivityBlockingActivityTest.java
new file mode 100644
index 0000000..69632f0
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/pm/ActivityBlockingActivityTest.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.pm;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertNotNull;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.car.Car;
+import android.car.drivingstate.CarDrivingStateEvent;
+import android.car.drivingstate.CarDrivingStateManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.Until;
+import android.view.Display;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class ActivityBlockingActivityTest {
+    private static final String ACTIVITY_BLOCKING_ACTIVITY_TEXTVIEW_ID =
+            "com.android.car:id/blocking_text";
+
+    // cf_x86_auto is very slow, so uses very long timeout.
+    private static final int UI_TIMEOUT_MS = 20_000;
+    private static final int NOT_FOUND_UI_TIMEOUT_MS = 10_000;
+    private static final long ACTIVITY_TIMEOUT_MS = 5000;
+
+    private CarDrivingStateManager mCarDrivingStateManager;
+
+    private UiDevice mDevice;
+
+    // NOTE: Assume there is only one testing Activity.
+    private static final AtomicReference<TempActivity> sTestingActivity = new AtomicReference<>();
+
+    @Before
+    public void setUp() throws Exception {
+        Car car = Car.createCar(getContext());
+        mCarDrivingStateManager = (CarDrivingStateManager)
+                car.getCarManager(Car.CAR_DRIVING_STATE_SERVICE);
+        assertNotNull(mCarDrivingStateManager);
+
+        mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+
+        setDrivingStateMoving();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        setDrivingStateParked();
+
+        TempActivity testingActivity = sTestingActivity.get();
+        if (testingActivity != null) {
+            testingActivity.finishCompletely();
+        }
+    }
+
+    @Test
+    public void testBlockingActivity_doActivity_isNotBlocked() throws Exception {
+        startActivity(toComponentName(getTestContext(), DoActivity.class));
+
+        assertThat(mDevice.wait(Until.findObject(By.text(
+                DoActivity.class.getSimpleName())),
+                UI_TIMEOUT_MS)).isNotNull();
+        assertBlockingActivityNotFound();
+    }
+
+    @Test
+    public void testBlockingActivity_nonDoActivity_isBlocked() throws Exception {
+        startNonDoActivity(NonDoActivity.EXTRA_DO_NOTHING);
+
+        assertThat(mDevice.wait(Until.findObject(By.res(ACTIVITY_BLOCKING_ACTIVITY_TEXTVIEW_ID)),
+                UI_TIMEOUT_MS)).isNotNull();
+    }
+
+    @Test
+    public void testBlockingActivity_nonDoFinishesOnCreate_noBlockingActivity()
+            throws Exception {
+        startNonDoActivity(NonDoActivity.EXTRA_ONCREATE_FINISH_IMMEDIATELY);
+
+        assertBlockingActivityNotFound();
+    }
+
+    @Test
+    public void testBlockingActivity_nonDoLaunchesDoOnCreate_noBlockingActivity()
+            throws Exception {
+        startNonDoActivity(NonDoActivity.EXTRA_ONCREATE_LAUNCH_DO_IMMEDIATELY);
+
+        assertBlockingActivityNotFound();
+    }
+
+    @Test
+    public void testBlockingActivity_nonDoFinishesOnResume_noBlockingActivity()
+            throws Exception {
+        startNonDoActivity(NonDoActivity.EXTRA_ONRESUME_FINISH_IMMEDIATELY);
+
+        assertBlockingActivityNotFound();
+    }
+
+    @Test
+    public void testBlockingActivity_nonDoLaunchesDoOnResume_noBlockingActivity()
+            throws Exception {
+        startNonDoActivity(NonDoActivity.EXTRA_ONRESUME_LAUNCH_DO_IMMEDIATELY);
+
+        assertBlockingActivityNotFound();
+    }
+
+    @Test
+    public void testBlockingActivity_nonDoNoHistory_isBlocked() throws Exception {
+        startActivity(toComponentName(getTestContext(), NonDoNoHistoryActivity.class));
+
+        assertThat(mDevice.wait(Until.findObject(By.res(ACTIVITY_BLOCKING_ACTIVITY_TEXTVIEW_ID)),
+                UI_TIMEOUT_MS)).isNotNull();
+    }
+
+    private void assertBlockingActivityNotFound() {
+        assertThat(mDevice.wait(Until.gone(By.res(ACTIVITY_BLOCKING_ACTIVITY_TEXTVIEW_ID)),
+                NOT_FOUND_UI_TIMEOUT_MS)).isNotNull();
+    }
+
+    private void startActivity(ComponentName name) {
+        Intent intent = new Intent();
+        intent.setComponent(name);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(Display.DEFAULT_DISPLAY);
+
+        getContext().startActivity(intent, options.toBundle());
+    }
+
+    private void startNonDoActivity(int firstActionFlag) {
+        ComponentName activity = toComponentName(getTestContext(), NonDoActivity.class);
+        Intent intent = new Intent();
+        intent.setComponent(activity);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(NonDoActivity.EXTRA_FIRST_ACTION, firstActionFlag);
+
+        ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(Display.DEFAULT_DISPLAY);
+
+        getContext().startActivity(intent, options.toBundle());
+    }
+
+
+    private void setDrivingStateMoving() {
+        mCarDrivingStateManager.injectDrivingState(CarDrivingStateEvent.DRIVING_STATE_MOVING);
+    }
+
+    private void setDrivingStateParked() {
+        mCarDrivingStateManager.injectDrivingState(CarDrivingStateEvent.DRIVING_STATE_PARKED);
+    }
+
+    private static ComponentName toComponentName(Context ctx, Class<?> cls) {
+        return ComponentName.createRelative(ctx, cls.getName());
+    }
+
+    public static class NonDoActivity extends TempActivity {
+
+        static final String EXTRA_FIRST_ACTION = "first_action";
+
+        static final int EXTRA_DO_NOTHING = 0;
+        static final int EXTRA_ONCREATE_FINISH_IMMEDIATELY = 1;
+        static final int EXTRA_ONCREATE_LAUNCH_DO_IMMEDIATELY = 2;
+        static final int EXTRA_ONRESUME_FINISH_IMMEDIATELY = 3;
+        static final int EXTRA_ONRESUME_LAUNCH_DO_IMMEDIATELY = 4;
+
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            Bundle extras = getIntent().getExtras();
+            if (extras != null) {
+                switch (extras.getInt(EXTRA_FIRST_ACTION, EXTRA_DO_NOTHING)) {
+                    case EXTRA_ONCREATE_LAUNCH_DO_IMMEDIATELY:
+                        startActivity(new Intent(this, DoActivity.class));
+                        finish();
+                        break;
+                    case EXTRA_ONCREATE_FINISH_IMMEDIATELY:
+                        finish();
+                        break;
+                    default:
+                        // do nothing
+                }
+            }
+        }
+
+        @Override
+        protected void onResume() {
+            super.onResume();
+            Bundle extras = getIntent().getExtras();
+            if (extras != null) {
+                switch (extras.getInt(EXTRA_FIRST_ACTION, EXTRA_DO_NOTHING)) {
+                    case EXTRA_ONRESUME_LAUNCH_DO_IMMEDIATELY:
+                        startActivity(new Intent(this, DoActivity.class));
+                        finish();
+                        break;
+                    case EXTRA_ONRESUME_FINISH_IMMEDIATELY:
+                        finish();
+                        break;
+                    default:
+                        // do nothing
+                }
+            }
+        }
+    }
+
+    public static class NonDoNoHistoryActivity extends TempActivity {
+    }
+
+    public static class DoActivity extends TempActivity {
+    }
+
+    /** Activity that closes itself after some timeout to clean up the screen. */
+    public static class TempActivity extends Activity {
+        private final CountDownLatch mDestroyed = new CountDownLatch(1);
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            sTestingActivity.set(this);
+        }
+
+        @Override
+        protected void onDestroy() {
+            sTestingActivity.set(null);
+            super.onDestroy();
+            mDestroyed.countDown();
+        }
+
+        void finishCompletely() throws InterruptedException {
+            finish();
+            mDestroyed.await(ACTIVITY_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        }
+    }
+
+    private Context getContext() {
+        return InstrumentationRegistry.getInstrumentation().getTargetContext();
+    }
+
+    private Context getTestContext() {
+        return InstrumentationRegistry.getInstrumentation().getContext();
+    }
+}
diff --git a/tests/carservice_test/src/com/android/car/pm/CarPackageManagerServiceTest.java b/tests/carservice_test/src/com/android/car/pm/CarPackageManagerServiceTest.java
index 9745a1e..8a29b1a 100644
--- a/tests/carservice_test/src/com/android/car/pm/CarPackageManagerServiceTest.java
+++ b/tests/carservice_test/src/com/android/car/pm/CarPackageManagerServiceTest.java
@@ -19,20 +19,22 @@
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertTrue;
 
-import android.car.userlib.CarUserManagerHelper;
 import android.content.Context;
 
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.car.CarUxRestrictionsManagerService;
 import com.android.car.SystemActivityMonitoringService;
+import com.android.car.user.CarUserService;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -45,19 +47,23 @@
 public class CarPackageManagerServiceTest {
     CarPackageManagerService mService;
 
+    @Rule
+    public final MockitoRule rule = MockitoJUnit.rule();
+
     private Context mContext;
     @Mock
     private CarUxRestrictionsManagerService mMockUxrService;
     @Mock
     private SystemActivityMonitoringService mMockSamService;
+    @Mock
+    private CarUserService mMockUserService;
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = InstrumentationRegistry.getTargetContext();
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
 
         mService = new CarPackageManagerService(mContext, mMockUxrService, mMockSamService,
-                new CarUserManagerHelper(mContext));
+                mMockUserService);
     }
 
     @Test
diff --git a/tests/carservice_test/src/com/android/car/vms/VmsClientTest.java b/tests/carservice_test/src/com/android/car/vms/VmsClientTest.java
new file mode 100644
index 0000000..d08195b
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/vms/VmsClientTest.java
@@ -0,0 +1,2610 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.vms;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.testng.Assert.assertThrows;
+
+import static java.util.Collections.emptySet;
+
+import android.car.Car;
+import android.car.vms.VmsAssociatedLayer;
+import android.car.vms.VmsAvailableLayers;
+import android.car.vms.VmsClient;
+import android.car.vms.VmsClientManager;
+import android.car.vms.VmsClientManager.VmsClientCallback;
+import android.car.vms.VmsLayer;
+import android.car.vms.VmsLayerDependency;
+import android.car.vms.VmsSubscriptionState;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import com.android.car.MockedCarTestBase;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class VmsClientTest extends MockedCarTestBase {
+    private static final long CONNECT_TIMEOUT = 10_000;
+
+    private static final byte[] PROVIDER_DESC1 = {1, 2, 3, 4, 5};
+    private static final byte[] PROVIDER_DESC2 = {5, 4, 3, 2, 1};
+
+    private static final VmsAvailableLayers DEFAULT_AVAILABLE_LAYERS =
+            new VmsAvailableLayers(0, emptySet());
+    private static final VmsSubscriptionState DEFAULT_SUBSCRIPTION_STATE =
+            new VmsSubscriptionState(0, emptySet(), emptySet());
+
+    private static final VmsLayer LAYER1 = new VmsLayer(1, 1, 1);
+    private static final VmsLayer LAYER2 = new VmsLayer(2, 1, 1);
+    private static final VmsLayer LAYER3 = new VmsLayer(3, 1, 1);
+
+    private static final byte[] PAYLOAD = {1, 2, 3, 4, 5, 6, 7, 8};
+    private static final byte[] LARGE_PAYLOAD = new byte[16 * 1024]; // 16KB
+
+    @Rule
+    public MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Mock
+    private VmsClientCallback mClientCallback1;
+    @Captor
+    private ArgumentCaptor<VmsClient> mClientCaptor;
+    @Mock
+    private VmsClientCallback mClientCallback2;
+
+    private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
+
+    private VmsClientManager mClientManager;
+
+    @Before
+    public void setUpTest() {
+        mClientManager = (VmsClientManager) getCar().getCarManager(Car.VEHICLE_MAP_SERVICE);
+        LARGE_PAYLOAD[0] = 123;
+    }
+
+    @Test
+    public void testRegister() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        awaitTaskCompletion();
+        assertThat(client.getAvailableLayers()).isEqualTo(DEFAULT_AVAILABLE_LAYERS);
+        assertThat(client.getSubscriptionState()).isEqualTo(DEFAULT_SUBSCRIPTION_STATE);
+        verifyLayerAvailability(mClientCallback1, DEFAULT_AVAILABLE_LAYERS);
+        verifySubscriptionState(mClientCallback1, DEFAULT_SUBSCRIPTION_STATE);
+    }
+
+    @Test
+    public void testRegister_ReceivesCurrentLayerAvailabilityAndSubscriptions() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)));
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1,
+                        asSet(providerId)))
+        );
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                asSet(LAYER1),
+                asSet(new VmsAssociatedLayer(LAYER2, asSet(12345)))
+        );
+        assertThat(client2.getAvailableLayers()).isEqualTo(expectedLayers);
+        assertThat(client2.getSubscriptionState()).isEqualTo(expectedSubscriptions);
+        verify(mClientCallback2).onLayerAvailabilityChanged(expectedLayers);
+        verify(mClientCallback2).onSubscriptionStateChanged(expectedSubscriptions);
+    }
+
+    @Test
+    public void testRegisterProvider_SameIdForSameInfo() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        int providerId2 = client.registerProvider(PROVIDER_DESC1);
+
+        assertThat(providerId).isEqualTo(providerId2);
+    }
+
+    @Test
+    public void testRegisterProvider_SameIdForSameInfo_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        int providerId2 = client2.registerProvider(PROVIDER_DESC1);
+
+        assertThat(providerId).isEqualTo(providerId2);
+    }
+
+    @Test
+    public void testRegisterProvider_DifferentIdForDifferentInfo() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        int providerId2 = client.registerProvider(PROVIDER_DESC2);
+
+        assertThat(providerId).isNotEqualTo(providerId2);
+    }
+
+    @Test
+    public void testUnregisterProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+
+        client.unregisterProvider(providerId);
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testUnregisterProvider_UnknownId() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        client.unregisterProvider(12345);
+    }
+
+    @Test
+    public void testGetProviderDescription_UnknownId() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        assertThat(client.getProviderDescription(12345)).isNull();
+    }
+
+    @Test
+    public void testGetProviderDescription_RegisteredProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        assertThat(client.getProviderDescription(providerId)).isEqualTo(PROVIDER_DESC1);
+    }
+
+    @Test
+    public void testSetSubscriptions() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                asSet(LAYER1),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                asSet(LAYER1),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_OverwriteSubscription() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER2, emptySet())
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                asSet(LAYER2),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_OverwriteSubscription_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER2, emptySet())
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER3, emptySet())
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                asSet(LAYER1, LAYER3),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_RemoveSubscription() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        client.setSubscriptions(emptySet());
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                emptySet(),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_RemoveSubscription_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER2, emptySet())
+        ));
+        client2.setSubscriptions(emptySet());
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                asSet(LAYER1),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_RemoveSubscription_MultipleClients_SameLayer() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        client2.setSubscriptions(emptySet());
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                asSet(LAYER1),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_RemoveSubscription_OnUnregister_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER2, emptySet())
+        ));
+        mClientManager.unregisterVmsClientCallback(mClientCallback2);
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                asSet(LAYER1),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_RemoveSubscription_OnUnregister_MultipleClients_SameLayer() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mClientManager.unregisterVmsClientCallback(mClientCallback2);
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                asSet(LAYER1),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayers() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER2, emptySet())
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                asSet(LAYER1, LAYER2),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayers_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER2, emptySet()),
+                new VmsAssociatedLayer(LAYER3, emptySet())
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                asSet(LAYER1, LAYER2, LAYER3),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(54321))
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345, 54321))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_OverwriteSubscription() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER2, asSet(54321))
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER2, asSet(54321))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_OverwriteSubscription_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER2, asSet(54321))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER3, asSet(98765))
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                emptySet(),
+                asSet(
+                        new VmsAssociatedLayer(LAYER1, asSet(12345)),
+                        new VmsAssociatedLayer(LAYER3, asSet(98765))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_OverwriteSubscription_MultipleClients_SameLayer() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER2, asSet(54321))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(98765))
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345, 98765))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_OverwriteSubscription_MultipleClients_SameLayerAndProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER2, asSet(54321))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_RemoveSubscription() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        client.setSubscriptions(emptySet());
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                emptySet(),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_RemoveSubscription_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER2, asSet(54321))
+        ));
+        client2.setSubscriptions(emptySet());
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_RemoveSubscription_MultipleClients_SameLayer() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(54321))
+        ));
+        client2.setSubscriptions(emptySet());
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_RemoveSubscription_MultipleClients_SameLayerAndProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        client2.setSubscriptions(emptySet());
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_RemoveSubscription_OnUnregister_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER2, asSet(54321))
+        ));
+        mClientManager.unregisterVmsClientCallback(mClientCallback2);
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_RemoveSubscription_OnUnregister_MultipleClients_SameLayer() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(54321))
+        ));
+        mClientManager.unregisterVmsClientCallback(mClientCallback2);
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_RemoveSubscription_OnUnregister_MultipleClients_SameLayerAndProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        mClientManager.unregisterVmsClientCallback(mClientCallback2);
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndMultipleProviders() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345, 54321))
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345, 54321))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndMultipleProviders_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(54321))
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345, 54321))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayersAndProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                asSet(LAYER1),
+                asSet(new VmsAssociatedLayer(LAYER2, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayersAndProvider_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER3, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(54321))
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                asSet(LAYER1, LAYER3),
+                asSet(new VmsAssociatedLayer(LAYER2, asSet(12345, 54321))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayersAndProvider_OverwriteSubscription() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER2, emptySet()),
+                new VmsAssociatedLayer(LAYER1, asSet(54321))
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                asSet(LAYER2),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(54321))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayersAndProvider_OverwriteSubscription_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER2, emptySet()),
+                new VmsAssociatedLayer(LAYER1, asSet(54321))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER3, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(54321))
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                asSet(LAYER1, LAYER3),
+                asSet(new VmsAssociatedLayer(LAYER2, asSet(12345, 54321))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayersAndProvider_RemoveSubscription() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+        client.setSubscriptions(emptySet());
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                emptySet(),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayersAndProvider_RemoveSubscription_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER2, emptySet()),
+                new VmsAssociatedLayer(LAYER1, asSet(54321))
+        ));
+        client2.setSubscriptions(emptySet());
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                asSet(LAYER1),
+                asSet(new VmsAssociatedLayer(LAYER2, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayersAndProvider_RemoveSubscription_OnUnregister_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER2, emptySet()),
+                new VmsAssociatedLayer(LAYER1, asSet(54321))
+        ));
+        mClientManager.unregisterVmsClientCallback(mClientCallback2);
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                asSet(LAYER1),
+                asSet(new VmsAssociatedLayer(LAYER2, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayersAndMultipleProviders() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(54321)),
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                emptySet(),
+                asSet(
+                        new VmsAssociatedLayer(LAYER1, asSet(54321)),
+                        new VmsAssociatedLayer(LAYER2, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayersAndMultipleProviders_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(54321))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                emptySet(),
+                asSet(
+                        new VmsAssociatedLayer(LAYER1, asSet(54321)),
+                        new VmsAssociatedLayer(LAYER2, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerOnlySupersedesLayerAndProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                asSet(LAYER1),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerOnlySupersedesLayerAndProvider_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                asSet(LAYER1),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerOnlySupersedesLayerAndProvider_RemoveLayerSubscription() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerOnlySupersedesLayerAndProvider_RemoveLayerSubscription_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        client2.setSubscriptions(emptySet());
+
+        awaitTaskCompletion();
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetMonitoringEnabled_Enable_NoSubscriptionChange() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        client.setMonitoringEnabled(true);
+
+        awaitTaskCompletion();
+        verifySubscriptionState(mClientCallback1, DEFAULT_SUBSCRIPTION_STATE);
+    }
+
+    @Test
+    public void testSetMonitoringEnabled_Disable_NoSubscriptionChange() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        client.setMonitoringEnabled(false);
+
+        awaitTaskCompletion();
+        verifySubscriptionState(mClientCallback1, DEFAULT_SUBSCRIPTION_STATE);
+    }
+
+    @Test
+    public void testSetProviderOfferings_UnknownProviderId() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> client.setProviderOfferings(12345, emptySet()));
+    }
+
+    @Test
+    public void testSetProviderOfferings_OtherClientsProviderId() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> client2.setProviderOfferings(providerId, emptySet()));
+    }
+
+    @Test
+    public void testSetProviderOfferings_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_MultipleProviders() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        int providerId2 = client.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId, providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        int providerId2 = client2.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client2.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId, providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_MultipleClients_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        client2.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client2.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_MultipleLayers_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1),
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_MultipleLayers_MultipleProviders() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        int providerId2 = client.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_MultipleLayers_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        int providerId2 = client2.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client2.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_MultipleLayers_MultipleClients_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        client2.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client2.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_OverwriteOffering_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_OverwriteOffering_MultipleProviders() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        int providerId2 = client.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(3, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_OverwriteOffering_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        int providerId2 = client2.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client2.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client2.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(3, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_OverwriteOffering_MultipleClients_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        client2.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client2.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client2.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_RemoveOfferings_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client.setProviderOfferings(providerId, emptySet());
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_RemoveOfferings_MultipleProviders() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        int providerId2 = client.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client.setProviderOfferings(providerId2, emptySet());
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(3, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_RemoveOfferings_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        int providerId2 = client2.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client2.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client2.setProviderOfferings(providerId2, emptySet());
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(3, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_RemoveOfferings_MultipleClients_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        client2.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client2.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client2.setProviderOfferings(providerId, emptySet());
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_RemoveOfferings_OnUnregister_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        // Register second client to verify layer availability after first client disconnects
+        connectVmsClient(mClientCallback2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mClientManager.unregisterVmsClientCallback(mClientCallback1);
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers1 = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)))
+        );
+        VmsAvailableLayers expectedLayers2 = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers1);
+        verifyLayerAvailability(mClientCallback2, expectedLayers2);
+    }
+
+    @Test
+    public void testSetProviderOfferings_RemoveOfferings_OnUnregister_MultipleProviders() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        int providerId2 = client.registerProvider(PROVIDER_DESC2);
+
+        // Register second client to verify layer availability after first client disconnects
+        connectVmsClient(mClientCallback2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mClientManager.unregisterVmsClientCallback(mClientCallback1);
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers1 = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId, providerId2)))
+        );
+        VmsAvailableLayers expectedLayers2 = new VmsAvailableLayers(3, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers1);
+        verifyLayerAvailability(mClientCallback2, expectedLayers2);
+    }
+
+    @Test
+    public void testSetProviderOfferings_RemoveOfferings_OnUnregister_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        int providerId2 = client2.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client2.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mClientManager.unregisterVmsClientCallback(mClientCallback1);
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers1 = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId, providerId2)))
+        );
+        VmsAvailableLayers expectedLayers2 = new VmsAvailableLayers(3, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers1);
+        verifyLayerAvailability(mClientCallback2, expectedLayers2);
+    }
+
+    @Test
+    public void testSetProviderOfferings_RemoveOfferings_OnUnregister_MultipleClients_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        client2.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        client2.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mClientManager.unregisterVmsClientCallback(mClientCallback1);
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers1 = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)))
+        );
+        VmsAvailableLayers expectedLayers2 = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers1);
+        verifyLayerAvailability(mClientCallback2, expectedLayers2);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_MultipleProviders() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        int providerId2 = client.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2))
+        ));
+        client.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        int providerId2 = client2.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2))
+        ));
+        client2.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_MultipleClients_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        client2.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2))
+        ));
+        client2.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_MultipleDependencies_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3)),
+                new VmsLayerDependency(LAYER2),
+                new VmsLayerDependency(LAYER3)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER3, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_MultipleDependencies_MultipleProviders() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        int providerId2 = client.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3)),
+                new VmsLayerDependency(LAYER2)
+        ));
+        client.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER3)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER3, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_MultipleDependencies_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        int providerId2 = client2.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3)),
+                new VmsLayerDependency(LAYER2)
+        ));
+        client2.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER3)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER3, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_MultipleDependencies_MultipleClients_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        client2.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3)),
+                new VmsLayerDependency(LAYER2)
+        ));
+        client2.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER3)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER3, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_ChainedDependencies_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER2, asSet(LAYER3)),
+                new VmsLayerDependency(LAYER3)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER3, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_ChainedDependencies_MultipleProviders() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        int providerId2 = client.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER3)
+        ));
+        client.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER2, asSet(LAYER3))
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId2)),
+                new VmsAssociatedLayer(LAYER3, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_ChainedDependencies_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        int providerId2 = client2.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER3)
+        ));
+        client2.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER2, asSet(LAYER3))
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId2)),
+                new VmsAssociatedLayer(LAYER3, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_ChainedDependencies_MultipleClients_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        client2.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER3)
+        ));
+        client2.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER2, asSet(LAYER3))
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER3, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER2, asSet(LAYER1))
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_MultipleProviders() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        int providerId2 = client.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2))
+        ));
+        client.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER2, asSet(LAYER1))
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        int providerId2 = client2.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2))
+        ));
+        client2.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER2, asSet(LAYER1))
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_MultipleClients_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        client2.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2))
+        ));
+        client2.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER2, asSet(LAYER1))
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_MultipleDependencies_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3)),
+                new VmsLayerDependency(LAYER2),
+                new VmsLayerDependency(LAYER3, asSet(LAYER1))
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_MultipleDependencies_MultipleProviders() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        int providerId2 = client.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3)),
+                new VmsLayerDependency(LAYER2)
+        ));
+        client.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER3, asSet(LAYER1))
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_MultipleDependencies_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        int providerId2 = client2.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3)),
+                new VmsLayerDependency(LAYER2)
+        ));
+        client2.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER3, asSet(LAYER1))
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_MultipleDependencies_MultipleClients_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        client2.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3)),
+                new VmsLayerDependency(LAYER2)
+        ));
+        client2.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER3, asSet(LAYER1))
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_ChainedDependencies_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER2, asSet(LAYER3)),
+                new VmsLayerDependency(LAYER3, asSet(LAYER1))
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_ChainedDependencies_MultipleProviders() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        int providerId2 = client.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER3, asSet(LAYER1))
+        ));
+        client.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER2, asSet(LAYER3))
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_ChainedDependencies_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        int providerId2 = client2.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER3, asSet(LAYER1))
+        ));
+        client2.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER2, asSet(LAYER3))
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_ChainedDependencies_MultipleClients_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        client2.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER3, asSet(LAYER1))
+        ));
+        client2.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER2, asSet(LAYER3))
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyUnmet_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2))
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyUnmet_MultipleDependencies_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3)),
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyUnmet_MultipleDependencies_MultipleProviders() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        int providerId2 = client.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3))
+        ));
+        client.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER3)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER3, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyUnmet_MultipleDependencies_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        int providerId2 = client2.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3))
+        ));
+        client2.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER3)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER3, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyUnmet_MultipleDependencies_MultipleClients_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        client2.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3))
+        ));
+        client2.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER3)
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER3, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyUnmet_ChainedDependencies_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER2, asSet(LAYER3))
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyUnmet_ChainedDependencies_MultipleProviders() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        int providerId2 = client.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2))
+        ));
+        client.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER2, asSet(LAYER3))
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyUnmet_ChainedDependencies_MultipleClients() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        int providerId2 = client2.registerProvider(PROVIDER_DESC2);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2))
+        ));
+        client2.setProviderOfferings(providerId2, asSet(
+                new VmsLayerDependency(LAYER2, asSet(LAYER3))
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyUnmet_ChainedDependencies_MultipleClients_SingleProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+        client2.registerProvider(PROVIDER_DESC1);
+
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2))
+        ));
+        client2.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER2, asSet(LAYER3))
+        ));
+
+        awaitTaskCompletion();
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testPublishPacket_UnknownOffering() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> client.publishPacket(providerId, LAYER1, PAYLOAD));
+    }
+
+    @Test
+    public void testPublishPacket_NoSubscribers() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        connectVmsClient(mClientCallback2);
+
+        client.publishPacket(providerId, LAYER1, PAYLOAD);
+
+        awaitTaskCompletion();
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_MonitorSubscriber_Enabled() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        connectVmsClient(mClientCallback2);
+
+        client.setMonitoringEnabled(true);
+        client.publishPacket(providerId, LAYER1, PAYLOAD);
+
+        awaitTaskCompletion();
+        verifyPacketReceived(mClientCallback1, providerId, LAYER1, PAYLOAD);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_MonitorSubscriber_EnabledAndDisabled() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        connectVmsClient(mClientCallback2);
+
+        client.setMonitoringEnabled(true);
+        client.setMonitoringEnabled(false);
+        client.publishPacket(providerId, LAYER1, PAYLOAD);
+
+        awaitTaskCompletion();
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_LayerSubscriber() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        client.publishPacket(providerId, LAYER1, PAYLOAD);
+
+        awaitTaskCompletion();
+        verifyPacketReceived(mClientCallback1, providerId, LAYER1, PAYLOAD);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_LayerSubscriber_Unsubscribe() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        client.setSubscriptions(emptySet());
+        client.publishPacket(providerId, LAYER1, PAYLOAD);
+
+        awaitTaskCompletion();
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_LayerSubscriber_DifferentLayer() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER2, emptySet())
+        ));
+        client.publishPacket(providerId, LAYER1, PAYLOAD);
+
+        awaitTaskCompletion();
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_MultipleLayerSubscribers() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        client.publishPacket(providerId, LAYER1, PAYLOAD);
+
+        awaitTaskCompletion();
+        verifyPacketReceived(mClientCallback1, providerId, LAYER1, PAYLOAD);
+        verifyPacketReceived(mClientCallback2, providerId, LAYER1, PAYLOAD);
+    }
+
+    @Test
+    public void testPublishPacket_LayerAndProviderSubscriber() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId))
+        ));
+        client.publishPacket(providerId, LAYER1, PAYLOAD);
+
+        awaitTaskCompletion();
+        verifyPacketReceived(mClientCallback1, providerId, LAYER1, PAYLOAD);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_LayerAndProviderSubscriber_Unsubscribe() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId))
+        ));
+        client.setSubscriptions(emptySet());
+        client.publishPacket(providerId, LAYER1, PAYLOAD);
+
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_LayerAndProviderSubscriber_DifferentProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        int providerId2 = client.registerProvider(PROVIDER_DESC2);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId2))
+        ));
+        client.publishPacket(providerId, LAYER1, PAYLOAD);
+
+        awaitTaskCompletion();
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_MultipleLayerAndProviderSubscribers() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        VmsClient client2 = connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId))
+        ));
+        client2.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId))
+        ));
+        client.publishPacket(providerId, LAYER1, PAYLOAD);
+
+        awaitTaskCompletion();
+        verifyPacketReceived(mClientCallback1, providerId, LAYER1, PAYLOAD);
+        verifyPacketReceived(mClientCallback2, providerId, LAYER1, PAYLOAD);
+    }
+
+    @Test
+    public void testPublishPacket_Large_UnknownOffering() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> client.publishPacket(providerId, LAYER1, LARGE_PAYLOAD));
+    }
+
+    @Test
+    public void testPublishPacket_Large_NoSubscribers() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        connectVmsClient(mClientCallback2);
+
+        client.publishPacket(providerId, LAYER1, LARGE_PAYLOAD);
+
+        awaitTaskCompletion();
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_Large_MonitorSubscriber_Enabled() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        connectVmsClient(mClientCallback2);
+
+        client.setMonitoringEnabled(true);
+        client.publishPacket(providerId, LAYER1, LARGE_PAYLOAD);
+
+        awaitTaskCompletion();
+        verifyPacketReceived(mClientCallback1, providerId, LAYER1, LARGE_PAYLOAD);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_Large_MonitorSubscriber_EnabledAndDisabled() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        connectVmsClient(mClientCallback2);
+
+        client.setMonitoringEnabled(true);
+        client.setMonitoringEnabled(false);
+        client.publishPacket(providerId, LAYER1, LARGE_PAYLOAD);
+
+        awaitTaskCompletion();
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_Large_LayerSubscriber() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        client.publishPacket(providerId, LAYER1, LARGE_PAYLOAD);
+
+        awaitTaskCompletion();
+        verifyPacketReceived(mClientCallback1, providerId, LAYER1, LARGE_PAYLOAD);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_Large_LayerSubscriber_Unsubscribe() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        client.setSubscriptions(emptySet());
+        client.publishPacket(providerId, LAYER1, LARGE_PAYLOAD);
+
+        awaitTaskCompletion();
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_Large_LayerSubscriber_DifferentLayer() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER2, emptySet())
+        ));
+        client.publishPacket(providerId, LAYER1, LARGE_PAYLOAD);
+
+        awaitTaskCompletion();
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_Large_LayerAndProviderSubscriber() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId))
+        ));
+        client.publishPacket(providerId, LAYER1, LARGE_PAYLOAD);
+
+        awaitTaskCompletion();
+        verifyPacketReceived(mClientCallback1, providerId, LAYER1, LARGE_PAYLOAD);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_Large_LayerAndProviderSubscriber_Unsubscribe() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId))
+        ));
+        client.setSubscriptions(emptySet());
+        client.publishPacket(providerId, LAYER1, LARGE_PAYLOAD);
+
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_Large_LayerAndProviderSubscriber_DifferentProvider() {
+        VmsClient client = connectVmsClient(mClientCallback1);
+        int providerId = client.registerProvider(PROVIDER_DESC1);
+        int providerId2 = client.registerProvider(PROVIDER_DESC2);
+        client.setProviderOfferings(providerId, asSet(
+                new VmsLayerDependency(LAYER1)
+        ));
+        connectVmsClient(mClientCallback2);
+
+        client.setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId2))
+        ));
+        client.publishPacket(providerId, LAYER1, LARGE_PAYLOAD);
+
+        awaitTaskCompletion();
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    private VmsClient connectVmsClient(VmsClientCallback callback) {
+        mClientManager.registerVmsClientCallback(mExecutor, callback);
+        verify(callback, timeout(CONNECT_TIMEOUT)).onClientConnected(mClientCaptor.capture());
+        return mClientCaptor.getValue();
+    }
+
+    private void awaitTaskCompletion() {
+        mExecutor.shutdown();
+        try {
+            mExecutor.awaitTermination(2L, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            fail("Executor termination interrupted");
+        }
+    }
+
+    private static void verifyLayerAvailability(
+            VmsClientCallback callback,
+            VmsAvailableLayers availableLayers) {
+        ArgumentCaptor<VmsAvailableLayers> availableLayersCaptor =
+                ArgumentCaptor.forClass(VmsAvailableLayers.class);
+        verify(callback, times(availableLayers.getSequenceNumber() + 1))
+                .onLayerAvailabilityChanged(availableLayersCaptor.capture());
+        assertThat(availableLayersCaptor.getValue()).isEqualTo(availableLayers);
+    }
+
+    private static void verifySubscriptionState(
+            VmsClientCallback callback,
+            VmsSubscriptionState subscriptionState) {
+        ArgumentCaptor<VmsSubscriptionState> subscriptionStateCaptor =
+                ArgumentCaptor.forClass(VmsSubscriptionState.class);
+        verify(callback, times(subscriptionState.getSequenceNumber() + 1))
+                .onSubscriptionStateChanged(subscriptionStateCaptor.capture());
+        assertThat(subscriptionStateCaptor.getValue()).isEqualTo(subscriptionState);
+    }
+
+    private static void verifyNoPacketsReceived(
+            VmsClientCallback callback,
+            int providerId, VmsLayer layer) {
+        verify(callback, never()).onPacketReceived(eq(providerId), eq(layer), any());
+    }
+
+    private static void verifyPacketReceived(
+            VmsClientCallback callback,
+            int providerId, VmsLayer layer, byte[] payload) {
+        verify(callback).onPacketReceived(providerId, layer, payload);
+    }
+
+    private static <T> Set<T> asSet(T... values) {
+        return new HashSet<T>(Arrays.asList(values));
+    }
+}
diff --git a/tests/carservice_test/src/com/android/car/watchdog/CarWatchdogServiceTest.java b/tests/carservice_test/src/com/android/car/watchdog/CarWatchdogServiceTest.java
new file mode 100644
index 0000000..28d70e6
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/watchdog/CarWatchdogServiceTest.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.watchdog;
+
+import static android.car.test.mocks.AndroidMockitoHelper.mockQueryService;
+import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetAllUsers;
+import static android.car.test.mocks.AndroidMockitoHelper.mockUmIsUserRunning;
+import static android.car.test.util.UserTestingHelper.UserInfoBuilder;
+import static android.car.watchdog.CarWatchdogManager.TIMEOUT_CRITICAL;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.automotive.watchdog.ICarWatchdog;
+import android.automotive.watchdog.ICarWatchdogClient;
+import android.car.Car;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.watchdog.CarWatchdogManager;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * <p>This class contains unit tests for the {@link CarWatchdogService}.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class CarWatchdogServiceTest extends AbstractExtendedMockitoTestCase {
+
+    private static final String CAR_WATCHDOG_DAEMON_INTERFACE =
+            "android.automotive.watchdog.ICarWatchdog/default";
+    private static final int MAX_WAIT_TIME_MS = 3000;
+    private static final int INVALID_SESSION_ID = -1;
+
+    private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+    private final Executor mExecutor =
+            InstrumentationRegistry.getInstrumentation().getTargetContext().getMainExecutor();
+    private final ArrayList<UserInfo> mUserInfos = new ArrayList<>(Arrays.asList(
+            new UserInfoBuilder(10).setName("user 1").build(),
+            new UserInfoBuilder(11).setName("user 2").build()
+    ));
+
+    @Mock private Context mMockContext;
+    @Mock private Car mCar;
+    @Mock private UserManager mUserManager;
+    @Mock private IBinder mDaemonBinder;
+    @Mock private IBinder mServiceBinder;
+    @Mock private ICarWatchdog mCarWatchdogDaemon;
+
+    private CarWatchdogService mCarWatchdogService;
+    private ICarWatchdogClient mWatchdogServiceClientImpl;
+
+    @Before
+    public void setUpMocks() throws Exception {
+        mCarWatchdogService = new CarWatchdogService(mMockContext);
+
+        mockQueryService(CAR_WATCHDOG_DAEMON_INTERFACE, mDaemonBinder, mCarWatchdogDaemon);
+        when(mCar.getEventHandler()).thenReturn(mMainHandler);
+        when(mServiceBinder.queryLocalInterface(anyString())).thenReturn(mCarWatchdogService);
+        when(mMockContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+        mockUmGetAllUsers(mUserManager, mUserInfos);
+        mockUmIsUserRunning(mUserManager, 10, true);
+        mockUmIsUserRunning(mUserManager, 11, false);
+
+        mCarWatchdogService.init();
+        mWatchdogServiceClientImpl = registerMediator();
+    }
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder builder) {
+        builder
+            .spyStatic(ServiceManager.class)
+            .spyStatic(UserHandle.class);
+    }
+
+    @Test
+    public void testRegisterUnregisterClient() throws Exception {
+        TestClient client = new TestClient(new SelfCheckGoodClient());
+        client.registerClient();
+        assertThat(mCarWatchdogService.getClientCount(TIMEOUT_CRITICAL)).isEqualTo(1);
+        client.unregisterClient();
+        assertThat(mCarWatchdogService.getClientCount(TIMEOUT_CRITICAL)).isEqualTo(0);
+    }
+
+    @Test
+    public void testNoSelfCheckGoodClient() throws Exception {
+        testClientResponse(new NoSelfCheckGoodClient(), 0);
+    }
+
+    @Test
+    public void testSelfCheckGoodClient() throws Exception {
+        testClientResponse(new SelfCheckGoodClient(), 0);
+    }
+
+    @Test
+    public void testBadClient() throws Exception {
+        BadTestClient client = new BadTestClient();
+        testClientResponse(client, 1);
+        assertThat(client.makeSureProcessTerminationNotified()).isEqualTo(true);
+    }
+
+    @Test
+    public void testClientUnderStoppedUser() throws Exception {
+        expectStoppedUser();
+        TestClient client = new TestClient(new BadTestClient());
+        client.registerClient();
+        mWatchdogServiceClientImpl.checkIfAlive(123456, TIMEOUT_CRITICAL);
+        ArgumentCaptor<int[]> notRespondingClients = ArgumentCaptor.forClass(int[].class);
+        verify(mCarWatchdogDaemon, timeout(MAX_WAIT_TIME_MS)).tellMediatorAlive(
+                eq(mWatchdogServiceClientImpl), notRespondingClients.capture(), eq(123456));
+        assertThat(notRespondingClients.getValue().length).isEqualTo(0);
+        mWatchdogServiceClientImpl.checkIfAlive(987654, TIMEOUT_CRITICAL);
+        verify(mCarWatchdogDaemon, timeout(MAX_WAIT_TIME_MS)).tellMediatorAlive(
+                eq(mWatchdogServiceClientImpl), notRespondingClients.capture(), eq(987654));
+        assertThat(notRespondingClients.getValue().length).isEqualTo(0);
+    }
+
+    @Test
+    public void testMultipleClients() throws Exception {
+        expectRunningUser();
+        ArgumentCaptor<int[]> pidsCaptor = ArgumentCaptor.forClass(int[].class);
+        ArrayList<TestClient> clients = new ArrayList<>(Arrays.asList(
+                new TestClient(new NoSelfCheckGoodClient()),
+                new TestClient(new SelfCheckGoodClient()),
+                new TestClient(new BadTestClient()),
+                new TestClient(new BadTestClient())
+        ));
+        for (int i = 0; i < clients.size(); i++) {
+            clients.get(i).registerClient();
+        }
+
+        mWatchdogServiceClientImpl.checkIfAlive(123456, TIMEOUT_CRITICAL);
+        for (int i = 0; i < clients.size(); i++) {
+            assertThat(clients.get(i).mAndroidClient.makeSureHealthCheckDone()).isEqualTo(true);
+        }
+        verify(mCarWatchdogDaemon, timeout(MAX_WAIT_TIME_MS)).tellMediatorAlive(
+                eq(mWatchdogServiceClientImpl), pidsCaptor.capture(), eq(123456));
+        assertThat(pidsCaptor.getValue().length).isEqualTo(0);
+
+        mWatchdogServiceClientImpl.checkIfAlive(987654, TIMEOUT_CRITICAL);
+        verify(mCarWatchdogDaemon, timeout(MAX_WAIT_TIME_MS)).tellMediatorAlive(
+                eq(mWatchdogServiceClientImpl), pidsCaptor.capture(), eq(987654));
+        assertThat(pidsCaptor.getValue().length).isEqualTo(2);
+    }
+
+    private ICarWatchdogClient registerMediator() throws Exception {
+        ArgumentCaptor<ICarWatchdogClient> clientImplCaptor =
+                ArgumentCaptor.forClass(ICarWatchdogClient.class);
+        verify(mCarWatchdogDaemon).registerMediator(clientImplCaptor.capture());
+        return clientImplCaptor.getValue();
+    }
+
+    private void testClientResponse(BaseAndroidClient androidClient, int badClientCount)
+            throws Exception {
+        expectRunningUser();
+        TestClient client = new TestClient(androidClient);
+        client.registerClient();
+        mWatchdogServiceClientImpl.checkIfAlive(123456, TIMEOUT_CRITICAL);
+        ArgumentCaptor<int[]> notRespondingClients = ArgumentCaptor.forClass(int[].class);
+        verify(mCarWatchdogDaemon, timeout(MAX_WAIT_TIME_MS)).tellMediatorAlive(
+                eq(mWatchdogServiceClientImpl), notRespondingClients.capture(), eq(123456));
+        // Checking Android client health is asynchronous, so wait at most 1 second.
+        int repeat = 10;
+        while (repeat > 0) {
+            int sessionId = androidClient.getLastSessionId();
+            if (sessionId != INVALID_SESSION_ID) {
+                break;
+            }
+            SystemClock.sleep(100L);
+            repeat--;
+        }
+        assertThat(androidClient.getLastSessionId()).isNotEqualTo(INVALID_SESSION_ID);
+        assertThat(notRespondingClients.getValue().length).isEqualTo(0);
+        assertThat(androidClient.makeSureHealthCheckDone()).isEqualTo(true);
+        mWatchdogServiceClientImpl.checkIfAlive(987654, TIMEOUT_CRITICAL);
+        verify(mCarWatchdogDaemon, timeout(MAX_WAIT_TIME_MS)).tellMediatorAlive(
+                eq(mWatchdogServiceClientImpl), notRespondingClients.capture(), eq(987654));
+        assertThat(notRespondingClients.getValue().length).isEqualTo(badClientCount);
+    }
+
+    private void expectRunningUser() {
+        doReturn(10).when(() -> UserHandle.getUserId(Binder.getCallingUid()));
+    }
+
+    private void expectStoppedUser() {
+        doReturn(11).when(() -> UserHandle.getUserId(Binder.getCallingUid()));
+    }
+
+    private final class TestClient {
+        final CarWatchdogManager mCarWatchdogManager;
+        BaseAndroidClient mAndroidClient;
+
+        TestClient(BaseAndroidClient actualClient) {
+            mCarWatchdogManager = new CarWatchdogManager(mCar, mServiceBinder);
+            mAndroidClient = actualClient;
+            actualClient.setManager(mCarWatchdogManager);
+        }
+
+        public void registerClient() {
+            mCarWatchdogManager.registerClient(mExecutor, mAndroidClient, TIMEOUT_CRITICAL);
+        }
+
+        public void unregisterClient() {
+            mCarWatchdogManager.unregisterClient(mAndroidClient);
+        }
+    }
+
+    private abstract class BaseAndroidClient extends CarWatchdogManager.CarWatchdogClientCallback {
+        protected final CountDownLatch mLatchHealthCheckDone = new CountDownLatch(1);
+        protected final CountDownLatch mLatchProcessTermination = new CountDownLatch(1);
+        protected CarWatchdogManager mManager;
+        protected int mLastSessionId = INVALID_SESSION_ID;
+
+        @Override
+        public boolean onCheckHealthStatus(int sessionId, int timeout) {
+            mLastSessionId = sessionId;
+            return false;
+        }
+
+        @Override
+        public void onPrepareProcessTermination() {
+            mLatchProcessTermination.countDown();
+        }
+
+        public int getLastSessionId() {
+            return mLastSessionId;
+        }
+
+        public boolean makeSureProcessTerminationNotified() {
+            try {
+                return mLatchProcessTermination.await(1000, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException ignore) {
+            }
+            return false;
+        }
+
+        public boolean makeSureHealthCheckDone() {
+            try {
+                return mLatchHealthCheckDone.await(1000, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException ignore) {
+            }
+            return false;
+        }
+
+        public void setManager(CarWatchdogManager manager) {
+            mManager = manager;
+        }
+    }
+
+    private final class SelfCheckGoodClient extends BaseAndroidClient {
+        @Override
+        public boolean onCheckHealthStatus(int sessionId, int timeout) {
+            super.onCheckHealthStatus(sessionId, timeout);
+            mMainHandler.post(() -> {
+                mManager.tellClientAlive(this, sessionId);
+                mLatchHealthCheckDone.countDown();
+            });
+            return false;
+        }
+    }
+
+    private final class NoSelfCheckGoodClient extends BaseAndroidClient {
+        @Override
+        public boolean onCheckHealthStatus(int sessionId, int timeout) {
+            super.onCheckHealthStatus(sessionId, timeout);
+            mLatchHealthCheckDone.countDown();
+            return true;
+        }
+    }
+
+    private final class BadTestClient extends BaseAndroidClient {
+        @Override
+        public boolean onCheckHealthStatus(int sessionId, int timeout) {
+            super.onCheckHealthStatus(sessionId, timeout);
+            mLatchHealthCheckDone.countDown();
+            return false;
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/Android.mk b/tests/carservice_unit_test/Android.mk
index f172a61..1033f41 100644
--- a/tests/carservice_unit_test/Android.mk
+++ b/tests/carservice_unit_test/Android.mk
@@ -44,22 +44,28 @@
 LOCAL_JAVA_LIBRARIES := \
     android.car \
     android.car.userlib \
+    android.car.watchdoglib \
     android.test.runner \
     android.test.base \
-    android.test.mock
+    android.test.mock \
+    EncryptionRunner
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
+    android.car.testapi \
+    android.car.test.utils \
     androidx.test.core \
     androidx.test.ext.junit \
     androidx.test.rules \
     car-frameworks-service \
-    car-service-lib-for-test \
+    car-service-test-static-lib \
     com.android.car.test.utils \
     frameworks-base-testutils \
     mockito-target-extended \
     testng \
     truth-prebuilt
 
+LOCAL_COMPATIBILITY_SUITE := general-tests
+
 # mockito-target-inline dependency
 LOCAL_JNI_SHARED_LIBRARIES := \
     libdexmakerjvmtiagent \
diff --git a/tests/carservice_unit_test/AndroidManifest.xml b/tests/carservice_unit_test/AndroidManifest.xml
index 5ed59ef..87fd276 100644
--- a/tests/carservice_unit_test/AndroidManifest.xml
+++ b/tests/carservice_unit_test/AndroidManifest.xml
@@ -16,8 +16,8 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-        package="com.android.car.carservice_unittest"
-        android:sharedUserId="android.uid.system" >
+        android:sharedUserId="com.google.android.car.uid.kitchensink"
+        package="com.android.car.carservice_unittest">
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
             android:targetPackage="com.android.car.carservice_unittest"
             android:label="Unit Tests for Car APIs"/>
@@ -26,5 +26,10 @@
     <application android:label="CarServiceUnitTest"
             android:debuggable="true">
         <uses-library android:name="android.test.runner" />
+        <activity android:name="com.android.car.SystemActivityMonitoringServiceTest$ActivityA"/>
+        <activity android:name="com.android.car.SystemActivityMonitoringServiceTest$ActivityB"/>
+        <activity android:name="com.android.car.SystemActivityMonitoringServiceTest$ActivityC"/>
+        <activity android:name="com.android.car.SystemActivityMonitoringServiceTest$BlockingActivity"
+                  android:taskAffinity="com.android.car.carservice_unittest.block"/>
     </application>
 </manifest>
diff --git a/tests/carservice_unit_test/src/android/car/AbstractExtendedMockitoCarServiceTestCase.java b/tests/carservice_unit_test/src/android/car/AbstractExtendedMockitoCarServiceTestCase.java
new file mode 100644
index 0000000..258e49e
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/AbstractExtendedMockitoCarServiceTestCase.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import android.annotation.NonNull;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.util.Log;
+
+import com.android.car.CarLocalServices;
+
+/**
+ * Specialized {@link AbstractExtendedMockitoTestCase} implementation that provides
+ * CarService-related helpers.
+ */
+public abstract class AbstractExtendedMockitoCarServiceTestCase
+        extends AbstractExtendedMockitoTestCase {
+
+    private static final String TAG = AbstractExtendedMockitoCarServiceTestCase.class
+            .getSimpleName();
+
+    private static final boolean VERBOSE = false;
+
+    /**
+     * Mocks a call to {@link CarLocalServices#getService(Class)}.
+     *
+     * @throws IllegalStateException if class didn't override {@link #newSessionBuilder()} and
+     * called {@code spyStatic(CarLocalServices.class)} on the session passed to it.
+     */
+    protected final <T> void mockGetCarLocalService(@NonNull Class<T> type, @NonNull T service) {
+        if (VERBOSE) Log.v(TAG, getLogPrefix() + "mockGetLocalService(" + type.getName() + ")");
+        assertSpied(CarLocalServices.class);
+
+        beginTrace("mockGetLocalService");
+        doReturn(service).when(() -> CarLocalServices.getService(type));
+        endTrace();
+    }
+}
diff --git a/tests/carservice_unit_test/src/android/car/CarTest.java b/tests/carservice_unit_test/src/android/car/CarTest.java
index d1f5ac6..d1c7098 100644
--- a/tests/carservice_unit_test/src/android/car/CarTest.java
+++ b/tests/carservice_unit_test/src/android/car/CarTest.java
@@ -36,25 +36,26 @@
 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;
 import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 import org.mockito.Mock;
 import org.mockito.MockitoSession;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.quality.Strictness;
 
+import java.util.Collections;
+import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * Unit test for Car API.
  */
-@RunWith(AndroidJUnit4.class)
+@RunWith(JUnit4.class)
 public class CarTest {
     private static final String TAG = CarTest.class.getSimpleName();
 
@@ -72,11 +73,56 @@
         }
 
         @Override
-        public void setUserLockStatus(int userHandle, int unlocked) {
+        public void onUserLifecycleEvent(int eventType, long timestampMs, int fromUserId,
+                int toUserId) {
         }
 
         @Override
-        public void onSwitchUser(int userHandle) {
+        public void onFirstUserUnlocked(int userId, long timestampMs, long duration,
+                int halResponseTime) {
+        }
+
+        @Override
+        public void getInitialUserInfo(int requestType, int timeoutMs, IBinder binder) {
+        }
+
+        @Override
+        public void setInitialUser(int userId) {
+        }
+
+        @Override
+        public boolean isFeatureEnabled(String featureName) {
+            return false;
+        }
+
+        @Override
+        public int enableFeature(String featureName) {
+            return Car.FEATURE_REQUEST_SUCCESS;
+        }
+
+        @Override
+        public int disableFeature(String featureName) {
+            return Car.FEATURE_REQUEST_SUCCESS;
+        }
+
+        @Override
+        public List<String> getAllEnabledFeatures() {
+            return Collections.EMPTY_LIST;
+        }
+
+        @Override
+        public List<String> getAllPendingDisabledFeatures() {
+            return Collections.EMPTY_LIST;
+        }
+
+        @Override
+        public List<String> getAllPendingEnabledFeatures() {
+            return Collections.EMPTY_LIST;
+        }
+
+        @Override
+        public String getCarManagerClassForFeature(String featureName) {
+            return null;
         }
 
         @Override
diff --git a/tests/carservice_unit_test/src/android/car/encryptionrunner/EncryptionRunnerTest.java b/tests/carservice_unit_test/src/android/car/encryptionrunner/EncryptionRunnerTest.java
new file mode 100644
index 0000000..38802e4
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/encryptionrunner/EncryptionRunnerTest.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.encryptionrunner;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.util.Log;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class EncryptionRunnerTest {
+
+    private Key mClientKey;
+    private Key mServerKey;
+    private byte[] mData = "testData".getBytes();
+
+    private interface RunnerFactory {
+        EncryptionRunner newRunner();
+    }
+
+    private interface HandshakeVerifier {
+        void verifyHandshake(EncryptionRunner clientRunner, EncryptionRunner serverRunner)
+                throws Exception;
+    }
+
+    @Test
+    public void happyFlow_dummyRunner() throws Exception {
+        verifyRunners(EncryptionRunnerFactory::newDummyRunner,
+                EncryptionRunnerTest::verifyHandshake);
+    }
+
+    @Test
+    public void happyFlow_ukey2Runner() throws Exception {
+        verifyRunners(EncryptionRunnerTest::newRunner, EncryptionRunnerTest::verifyHandshake);
+    }
+
+    @Test
+    public void happyFlow_oobUkey2Runner() throws Exception {
+        verifyRunners(EncryptionRunnerTest::newOobRunner, EncryptionRunnerTest::verifyOobHandshake);
+    }
+
+    @Test
+    public void happyFlow_dummyRunner_reconnect() throws Exception {
+        setUpFirstConnection(EncryptionRunnerFactory::newDummyRunner,
+                EncryptionRunnerTest::verifyHandshake);
+        verifyRunnersReconnect(EncryptionRunnerFactory::newDummyRunner);
+    }
+
+    @Test
+    public void happyFlow_uKey2Runner_reconnect() throws Exception {
+        setUpFirstConnection(EncryptionRunnerTest::newRunner,
+                EncryptionRunnerTest::verifyHandshake);
+        verifyRunnersReconnect(EncryptionRunnerTest::newRunner);
+    }
+
+    @Test
+    public void happyFlow_oobUey2Runner_reconnect() throws Exception {
+        setUpFirstConnection(EncryptionRunnerTest::newOobRunner,
+                EncryptionRunnerTest::verifyOobHandshake);
+        verifyRunnersReconnect(EncryptionRunnerTest::newOobRunner);
+    }
+
+    @Test
+    public void uKey2Runner_reconnect_encrypt_and_decrypt() throws Exception {
+        setUpFirstConnection(EncryptionRunnerTest::newRunner,
+                EncryptionRunnerTest::verifyHandshake);
+        setUpReconnection(EncryptionRunnerTest::newRunner, EncryptionRunnerTest::verifyHandshake);
+        assertThat(mClientKey.decryptData(mServerKey.encryptData(mData))).isEqualTo(mData);
+    }
+
+    @Test
+    public void dummyRunner_reconnect_encrypt_and_decrypt() throws Exception {
+        setUpFirstConnection(EncryptionRunnerFactory::newDummyRunner,
+                EncryptionRunnerTest::verifyHandshake);
+        setUpReconnection(EncryptionRunnerFactory::newDummyRunner,
+                EncryptionRunnerTest::verifyHandshake);
+        assertThat(mClientKey.decryptData(mServerKey.encryptData(mData))).isEqualTo(mData);
+    }
+
+    @Test
+    public void oobUkey2Runner_reconnect_encrypt_and_decrypt() throws Exception {
+        setUpFirstConnection(EncryptionRunnerTest::newOobRunner,
+                EncryptionRunnerTest::verifyOobHandshake);
+        setUpReconnection(EncryptionRunnerTest::newOobRunner,
+                EncryptionRunnerTest::verifyOobHandshake);
+        assertThat(mClientKey.decryptData(mServerKey.encryptData(mData))).isEqualTo(mData);
+    }
+
+    private static EncryptionRunner newRunner() {
+        return EncryptionRunnerFactory.newRunner(
+                EncryptionRunnerFactory.EncryptionRunnerType.UKEY2);
+    }
+
+    private static EncryptionRunner newOobRunner() {
+        return EncryptionRunnerFactory.newRunner(
+                EncryptionRunnerFactory.EncryptionRunnerType.OOB_UKEY2);
+    }
+
+    private void setUpFirstConnection(RunnerFactory runnerFactory,
+            HandshakeVerifier handshakeVerifier) throws Exception {
+        EncryptionRunner clientRunner = runnerFactory.newRunner();
+        EncryptionRunner serverRunner = runnerFactory.newRunner();
+        handshakeVerifier.verifyHandshake(clientRunner, serverRunner);
+        HandshakeMessage finalServerMessage = serverRunner.verifyPin();
+        HandshakeMessage finalClientMessage = clientRunner.verifyPin();
+        mServerKey = finalServerMessage.getKey();
+        mClientKey = finalClientMessage.getKey();
+    }
+
+    private void setUpReconnection(RunnerFactory runnerFactory, HandshakeVerifier handshakeVerifier)
+            throws Exception {
+        setUpFirstConnection(runnerFactory, handshakeVerifier);
+        EncryptionRunner clientRunner = runnerFactory.newRunner();
+        EncryptionRunner serverRunner = runnerFactory.newRunner();
+        verifyHandshakeReconnect(clientRunner, serverRunner);
+        HandshakeMessage nextClientMessage =
+                clientRunner.initReconnectAuthentication(mClientKey.asBytes());
+        HandshakeMessage finalServerMessage = serverRunner.authenticateReconnection(
+                nextClientMessage.getNextMessage(), mServerKey.asBytes());
+        HandshakeMessage finalClientMessage = clientRunner.authenticateReconnection(
+                finalServerMessage.getNextMessage(), mServerKey.asBytes());
+        mServerKey = finalServerMessage.getKey();
+        mClientKey = finalClientMessage.getKey();
+    }
+
+    /**
+     * Runs through a happy flow of encryption runners and verifies that they behave as expected.
+     * Some * of the test is implementation specific because the interface doesn't specify how many
+     * round * trips may be needed but this test makes assumptions( i.e. white box testing).
+     */
+    private void verifyRunners(RunnerFactory runnerFactory, HandshakeVerifier handshakeVerifier)
+            throws Exception {
+        EncryptionRunner clientRunner = runnerFactory.newRunner();
+        EncryptionRunner serverRunner = runnerFactory.newRunner();
+
+        handshakeVerifier.verifyHandshake(clientRunner, serverRunner);
+
+        HandshakeMessage finalServerMessage = serverRunner.verifyPin();
+        assertThat(finalServerMessage.getHandshakeState())
+                .isEqualTo(HandshakeMessage.HandshakeState.FINISHED);
+        assertThat(finalServerMessage.getKey()).isNotNull();
+        assertThat(finalServerMessage.getNextMessage()).isNull();
+
+        HandshakeMessage finalClientMessage = clientRunner.verifyPin();
+        assertThat(finalClientMessage.getHandshakeState())
+                .isEqualTo(HandshakeMessage.HandshakeState.FINISHED);
+        assertThat(finalClientMessage.getKey()).isNotNull();
+        assertThat(finalClientMessage.getNextMessage()).isNull();
+
+        assertThat(finalServerMessage.getKey()
+                .decryptData(finalClientMessage.getKey().encryptData(mData)))
+                .isEqualTo(mData);
+        assertThat(finalClientMessage.getKey()
+                .decryptData(finalServerMessage.getKey().encryptData(mData)))
+                .isEqualTo(mData);
+    }
+
+    private void verifyRunnersReconnect(RunnerFactory runnerFactory) throws Exception {
+        EncryptionRunner clientRunner = runnerFactory.newRunner();
+        EncryptionRunner serverRunner = runnerFactory.newRunner();
+        verifyHandshakeReconnect(clientRunner, serverRunner);
+
+        HandshakeMessage nextClientMessage =
+                clientRunner.initReconnectAuthentication(mClientKey.asBytes());
+        assertThat(nextClientMessage.getHandshakeState())
+                .isEqualTo(HandshakeMessage.HandshakeState.RESUMING_SESSION);
+        assertThat(nextClientMessage.getKey()).isNull();
+        assertThat(nextClientMessage.getNextMessage()).isNotNull();
+
+        HandshakeMessage finalServerMessage = serverRunner.authenticateReconnection(
+                nextClientMessage.getNextMessage(), mServerKey.asBytes());
+        assertThat(finalServerMessage.getHandshakeState())
+                .isEqualTo(HandshakeMessage.HandshakeState.FINISHED);
+        assertThat(finalServerMessage.getKey()).isNotNull();
+        assertThat(finalServerMessage.getNextMessage()).isNotNull();
+
+        HandshakeMessage finalClientMessage = clientRunner.authenticateReconnection(
+                finalServerMessage.getNextMessage(), mServerKey.asBytes());
+        assertThat(finalClientMessage.getHandshakeState())
+                .isEqualTo(HandshakeMessage.HandshakeState.FINISHED);
+        assertThat(finalClientMessage.getKey()).isNotNull();
+        assertThat(finalClientMessage.getNextMessage()).isNull();
+    }
+
+    private static void verifyHandshake(EncryptionRunner clientRunner,
+            EncryptionRunner serverRunner)
+            throws Exception {
+        HandshakeMessage initialClientMessage = clientRunner.initHandshake();
+
+        assertThat(initialClientMessage.getHandshakeState())
+                .isEqualTo(HandshakeMessage.HandshakeState.IN_PROGRESS);
+        assertThat(initialClientMessage.getKey()).isNull();
+        assertThat(initialClientMessage.getNextMessage()).isNotNull();
+
+        // This and the following similar log statements are useful when running this test to
+        // find the payload sizes.
+        Log.i(EncryptionRunner.TAG,
+                "initial client size:" + initialClientMessage.getNextMessage().length);
+
+        HandshakeMessage initialServerMessage =
+                serverRunner.respondToInitRequest(initialClientMessage.getNextMessage());
+
+        assertThat(initialServerMessage.getHandshakeState())
+                .isEqualTo(HandshakeMessage.HandshakeState.IN_PROGRESS);
+        assertThat(initialServerMessage.getKey()).isNull();
+        assertThat(initialServerMessage.getNextMessage()).isNotNull();
+
+        Log.i(EncryptionRunner.TAG,
+                "initial server message size:" + initialServerMessage.getNextMessage().length);
+
+        HandshakeMessage clientMessage =
+                clientRunner.continueHandshake(initialServerMessage.getNextMessage());
+
+        assertThat(clientMessage.getHandshakeState())
+                .isEqualTo(HandshakeMessage.HandshakeState.VERIFICATION_NEEDED);
+        assertThat(clientMessage.getKey()).isNull();
+        assertThat(clientMessage.getVerificationCode()).isNotEmpty();
+        assertThat(clientMessage.getNextMessage()).isNotNull();
+
+        Log.i(EncryptionRunner.TAG,
+                "second client message size:" + clientMessage.getNextMessage().length);
+
+        HandshakeMessage serverMessage =
+                serverRunner.continueHandshake(clientMessage.getNextMessage());
+        assertThat(serverMessage.getHandshakeState())
+                .isEqualTo(HandshakeMessage.HandshakeState.VERIFICATION_NEEDED);
+        assertThat(serverMessage.getKey()).isNull();
+        assertThat(serverMessage.getNextMessage()).isNull();
+
+        Log.i(EncryptionRunner.TAG,
+                "last server message size:" + clientMessage.getNextMessage().length);
+    }
+
+    private static void verifyOobHandshake(
+            EncryptionRunner clientRunner, EncryptionRunner serverRunner) throws Exception {
+        HandshakeMessage initialClientMessage = clientRunner.initHandshake();
+
+        assertThat(initialClientMessage.getHandshakeState())
+                .isEqualTo(HandshakeMessage.HandshakeState.IN_PROGRESS);
+        assertThat(initialClientMessage.getKey()).isNull();
+        assertThat(initialClientMessage.getNextMessage()).isNotNull();
+
+        HandshakeMessage initialServerMessage =
+                serverRunner.respondToInitRequest(initialClientMessage.getNextMessage());
+
+        assertThat(initialServerMessage.getHandshakeState())
+                .isEqualTo(HandshakeMessage.HandshakeState.IN_PROGRESS);
+        assertThat(initialServerMessage.getKey()).isNull();
+        assertThat(initialServerMessage.getNextMessage()).isNotNull();
+
+        HandshakeMessage clientMessage =
+                clientRunner.continueHandshake(initialServerMessage.getNextMessage());
+
+        assertThat(clientMessage.getHandshakeState())
+                .isEqualTo(HandshakeMessage.HandshakeState.OOB_VERIFICATION_NEEDED);
+        assertThat(clientMessage.getKey()).isNull();
+        assertThat(clientMessage.getOobVerificationCode()).isNotEmpty();
+        assertThat(clientMessage.getNextMessage()).isNotNull();
+
+        HandshakeMessage serverMessage = serverRunner.continueHandshake(
+                clientMessage.getNextMessage());
+        assertThat(serverMessage.getHandshakeState())
+                .isEqualTo(HandshakeMessage.HandshakeState.OOB_VERIFICATION_NEEDED);
+        assertThat(serverMessage.getKey()).isNull();
+        assertThat(serverMessage.getNextMessage()).isNull();
+    }
+
+    private void verifyHandshakeReconnect(
+            EncryptionRunner clientRunner, EncryptionRunner serverRunner)
+            throws HandshakeException {
+        clientRunner.setIsReconnect(true);
+        serverRunner.setIsReconnect(true);
+
+        HandshakeMessage initialClientMessage = clientRunner.initHandshake();
+        assertThat(initialClientMessage.getHandshakeState())
+                .isEqualTo(HandshakeMessage.HandshakeState.IN_PROGRESS);
+        assertThat(initialClientMessage.getKey()).isNull();
+        assertThat(initialClientMessage.getNextMessage()).isNotNull();
+
+        // This and the following similar log statements are useful when running this test to
+        // find the payload sizes.
+        Log.i(EncryptionRunner.TAG,
+                "initial client size:" + initialClientMessage.getNextMessage().length);
+
+        HandshakeMessage initialServerMessage =
+                serverRunner.respondToInitRequest(initialClientMessage.getNextMessage());
+
+        assertThat(initialServerMessage.getHandshakeState())
+                .isEqualTo(HandshakeMessage.HandshakeState.IN_PROGRESS);
+        assertThat(initialServerMessage.getKey()).isNull();
+        assertThat(initialServerMessage.getNextMessage()).isNotNull();
+
+        Log.i(EncryptionRunner.TAG,
+                "initial server message size:" + initialServerMessage.getNextMessage().length);
+
+        HandshakeMessage clientMessage =
+                clientRunner.continueHandshake(initialServerMessage.getNextMessage());
+
+        assertThat(clientMessage.getHandshakeState())
+                .isEqualTo(HandshakeMessage.HandshakeState.RESUMING_SESSION);
+        assertThat(clientMessage.getKey()).isNull();
+        assertThat(clientMessage.getNextMessage()).isNotNull();
+
+        HandshakeMessage serverMessage =
+                serverRunner.continueHandshake(clientMessage.getNextMessage());
+        assertThat(serverMessage.getHandshakeState())
+                .isEqualTo(HandshakeMessage.HandshakeState.RESUMING_SESSION);
+        assertThat(serverMessage.getKey()).isNull();
+    }
+
+    @Test
+    public void invalidPin_ukey2() throws Exception {
+        invalidPinTest(EncryptionRunnerTest::newRunner, EncryptionRunnerTest::verifyHandshake);
+    }
+
+    @Test
+    public void invalidPin_dummy() throws Exception {
+        invalidPinTest(EncryptionRunnerFactory::newDummyRunner,
+                EncryptionRunnerTest::verifyHandshake);
+    }
+
+    @Test
+    public void invalidPin_oobUkey2() throws Exception {
+        invalidPinTest(EncryptionRunnerTest::newOobRunner,
+                EncryptionRunnerTest::verifyOobHandshake);
+    }
+
+    private void invalidPinTest(RunnerFactory runnerFactory, HandshakeVerifier handshakeVerifier)
+            throws Exception {
+        EncryptionRunner clientRunner = runnerFactory.newRunner();
+        EncryptionRunner serverRunner = runnerFactory.newRunner();
+
+        handshakeVerifier.verifyHandshake(clientRunner, serverRunner);
+        clientRunner.invalidPin();
+        serverRunner.invalidPin();
+
+        try {
+            clientRunner.verifyPin();
+            Assert.fail();
+        } catch (Exception ignored) {
+            // pass
+        }
+
+        try {
+            serverRunner.verifyPin();
+            Assert.fail();
+        } catch (Exception ignored) {
+            // pass
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/android/car/encryptionrunner/Ukey2EncryptionRunnerTest.java b/tests/carservice_unit_test/src/android/car/encryptionrunner/Ukey2EncryptionRunnerTest.java
new file mode 100644
index 0000000..71dbb4c
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/encryptionrunner/Ukey2EncryptionRunnerTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.encryptionrunner;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class Ukey2EncryptionRunnerTest {
+
+    private Ukey2EncryptionRunner mRunner;
+
+    @Before
+    public void setup() {
+        mRunner = new Ukey2EncryptionRunner();
+    }
+
+    @Test
+    public void generateReadablePairingCode_modsBytesAcrossRange() throws Exception {
+        // 194 is an example of a value that would fail if using signed instead of unsigned ints
+        // 194 -> 11000010
+        // 11000010 -> 194 (unsigned 8-bit int)
+        // 11000010 -> -62 (signed 8-bit int)
+        byte[] bytes = new byte[]{0, 7, (byte) 161, (byte) 194, (byte) 196, (byte) 255};
+        String pairingCode = mRunner.generateReadablePairingCode(bytes);
+
+        assertThat(pairingCode).isEqualTo("071465");
+    }
+}
diff --git a/tests/carservice_unit_test/src/android/car/userlib/CarUserManagerHelperTest.java b/tests/carservice_unit_test/src/android/car/userlib/CarUserManagerHelperTest.java
index 02a3f13..62cf6d4 100644
--- a/tests/carservice_unit_test/src/android/car/userlib/CarUserManagerHelperTest.java
+++ b/tests/carservice_unit_test/src/android/car/userlib/CarUserManagerHelperTest.java
@@ -16,44 +16,41 @@
 
 package android.car.userlib;
 
+import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetSystemUser;
+import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetUserInfo;
+import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetUsers;
+import static android.car.test.util.UserTestingHelper.newUser;
+import static android.os.UserHandle.USER_SYSTEM;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
-import android.content.BroadcastReceiver;
+import android.car.settings.CarSettings;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.UserInfo;
-import android.graphics.Bitmap;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.Handler;
+import android.content.res.Resources;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.provider.Settings;
+import android.sysprop.CarProperties;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
 
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Optional;
 
 /**
  * This class contains unit tests for the {@link CarUserManagerHelper}.
@@ -63,502 +60,59 @@
  * 1. {@link Context} provides system services and resources.
  * 2. {@link UserManager} provides dummy users and user info.
  * 3. {@link ActivityManager} to verify user switch is invoked.
- * 4. {@link CarUserManagerHelper.OnUsersUpdateListener} registers a listener for user updates.
  */
-@RunWith(AndroidJUnit4.class)
 @SmallTest
-public class CarUserManagerHelperTest {
-    @Mock
-    private Context mContext;
-    @Mock
-    private UserManager mUserManager;
-    @Mock
-    private ActivityManager mActivityManager;
-    @Mock
-    private CarUserManagerHelper.OnUsersUpdateListener mTestListener;
-    @Mock
-    private TestableFrameworkWrapper mTestableFrameworkWrapper;
+public class CarUserManagerHelperTest extends AbstractExtendedMockitoTestCase {
+    @Mock private Context mContext;
+    @Mock private UserManager mUserManager;
+    @Mock private ActivityManager mActivityManager;
+    @Mock private ContentResolver mContentResolver;
 
-    private static final String GUEST_USER_NAME = "testGuest";
+    // Not worth to mock because it would need to mock a Drawable used by UserIcons.
+    private final Resources mResources = InstrumentationRegistry.getTargetContext().getResources();
+
     private static final String TEST_USER_NAME = "testUser";
-    private static final String DEFAULT_ADMIN_NAME = "defaultAdminName";
+    private static final int NO_FLAGS = 0;
 
     private CarUserManagerHelper mCarUserManagerHelper;
-    private UserInfo mCurrentProcessUser;
-    private UserInfo mSystemUser;
-    private int mForegroundUserId;
-    private UserInfo mForegroundUser;
+    private final int mForegroundUserId = 42;
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+        session
+            .spyStatic(ActivityManager.class)
+            .spyStatic(CarProperties.class)
+            .spyStatic(UserManager.class);
+    }
 
     @Before
-    public void setUpMocksAndVariables() throws Exception {
-        MockitoAnnotations.initMocks(this);
+    public void setUpMocksAndVariables() {
         doReturn(mUserManager).when(mContext).getSystemService(Context.USER_SERVICE);
         doReturn(mActivityManager).when(mContext).getSystemService(Context.ACTIVITY_SERVICE);
-        doReturn(InstrumentationRegistry.getTargetContext().getResources())
-                .when(mContext).getResources();
-        doReturn(InstrumentationRegistry.getTargetContext().getContentResolver())
-                .when(mContext).getContentResolver();
+        doReturn(mResources).when(mContext).getResources();
+        doReturn(mContentResolver).when(mContext).getContentResolver();
         doReturn(mContext).when(mContext).getApplicationContext();
-        mCarUserManagerHelper = new CarUserManagerHelper(mContext, mTestableFrameworkWrapper);
-        mCarUserManagerHelper.setDefaultAdminName(DEFAULT_ADMIN_NAME);
+        mCarUserManagerHelper = new CarUserManagerHelper(mContext);
 
-        mCurrentProcessUser = createUserInfoForId(UserHandle.myUserId());
-        mSystemUser = createUserInfoForId(UserHandle.USER_SYSTEM);
-        doReturn(mCurrentProcessUser).when(mUserManager).getUserInfo(UserHandle.myUserId());
-
-        // Get the ID of the foreground user running this test.
-        // We cannot mock the foreground user since getCurrentUser is static.
-        // We cannot rely on foreground_id != system_id, they could be the same user.
-        mForegroundUserId = ActivityManager.getCurrentUser();
-        mForegroundUser = createUserInfoForId(mForegroundUserId);
-
-        // Clear boot override for every test by returning the default value passed to the method
-        when(mTestableFrameworkWrapper.getBootUserOverrideId(anyInt()))
-                .thenAnswer(stub -> stub.getArguments()[0]);
-    }
-
-    @Test
-    public void checkHeadlessSystemUserFlag() {
-        // Make sure the headless system user flag is on.
-        assertThat(mCarUserManagerHelper.isHeadlessSystemUser()).isTrue();
-    }
-
-    @Test
-    public void checkIsSystemUser() {
-        UserInfo testInfo = new UserInfo();
-
-        testInfo.id = UserHandle.USER_SYSTEM;
-        assertThat(mCarUserManagerHelper.isSystemUser(testInfo)).isTrue();
-
-        testInfo.id = UserHandle.USER_SYSTEM + 2; // Make it different than system id.
-        assertThat(mCarUserManagerHelper.isSystemUser(testInfo)).isFalse();
-    }
-
-    // System user will not be returned when calling get all users.
-    @Test
-    public void testHeadlessUser0GetAllUsers_NotReturnSystemUser() {
-        UserInfo otherUser1 = createUserInfoForId(10);
-        UserInfo otherUser2 = createUserInfoForId(11);
-        UserInfo otherUser3 = createUserInfoForId(12);
-
-        mockGetUsers(mSystemUser, otherUser1, otherUser2, otherUser3);
-
-        assertThat(mCarUserManagerHelper.getAllUsers())
-                .containsExactly(otherUser1, otherUser2, otherUser3);
-    }
-
-    @Test
-    public void testGetAllSwitchableUsers() {
-        // Create two non-foreground users.
-        UserInfo user1 = createUserInfoForId(mForegroundUserId + 1);
-        UserInfo user2 = createUserInfoForId(mForegroundUserId + 2);
-
-        mockGetUsers(mForegroundUser, user1, user2);
-
-        // Should return all non-foreground users.
-        assertThat(mCarUserManagerHelper.getAllSwitchableUsers()).containsExactly(user1, user2);
-    }
-
-    @Test
-    public void testGetAllPersistentUsers() {
-        // Create two non-ephemeral users.
-        UserInfo user1 = createUserInfoForId(mForegroundUserId);
-        UserInfo user2 = createUserInfoForId(mForegroundUserId + 1);
-        // Create two ephemeral users.
-        UserInfo user3 = new UserInfo(
-                /* id= */mForegroundUserId + 2, /* name = */ "user3", UserInfo.FLAG_EPHEMERAL);
-        UserInfo user4 = new UserInfo(
-                /* id= */mForegroundUserId + 3, /* name = */ "user4", UserInfo.FLAG_EPHEMERAL);
-
-        mockGetUsers(user1, user2, user3, user4);
-
-        // Should return all non-ephemeral users.
-        assertThat(mCarUserManagerHelper.getAllPersistentUsers()).containsExactly(user1, user2);
-    }
-
-    @Test
-    public void testGetAllAdminUsers() {
-        // Create two admin, and two non-admin users.
-        UserInfo user1 = new UserInfo(/* id= */ 10, /* name = */ "user10", UserInfo.FLAG_ADMIN);
-        UserInfo user2 = createUserInfoForId(11);
-        UserInfo user3 = createUserInfoForId(12);
-        UserInfo user4 = new UserInfo(/* id= */ 13, /* name = */ "user13", UserInfo.FLAG_ADMIN);
-
-        mockGetUsers(user1, user2, user3, user4);
-
-        // Should return only admin users.
-        assertThat(mCarUserManagerHelper.getAllAdminUsers()).containsExactly(user1, user4);
-    }
-
-    @Test
-    public void testGetAllUsersExceptGuests() {
-        // Create two users and a guest user.
-        UserInfo user1 = createUserInfoForId(10);
-        UserInfo user2 = createUserInfoForId(12);
-        UserInfo user3 = new UserInfo(/* id= */ 13, /* name = */ "user13", UserInfo.FLAG_GUEST);
-
-        mockGetUsers(user1, user2, user3);
-
-        // Should not return guests.
-        assertThat(mCarUserManagerHelper.getAllUsersExceptGuests())
-                .containsExactly(user1, user2);
-    }
-
-    @Test
-    public void testUserCanBeRemoved() {
-        UserInfo testInfo = new UserInfo();
-
-        // System user cannot be removed.
-        testInfo.id = UserHandle.USER_SYSTEM;
-        assertThat(mCarUserManagerHelper.canUserBeRemoved(testInfo)).isFalse();
-
-        testInfo.id = UserHandle.USER_SYSTEM + 2; // Make it different than system id.
-        assertThat(mCarUserManagerHelper.canUserBeRemoved(testInfo)).isTrue();
-    }
-
-    @Test
-    public void testCurrentProcessCanAddUsers() {
-        doReturn(false).when(mUserManager)
-                .hasUserRestriction(UserManager.DISALLOW_ADD_USER);
-        assertThat(mCarUserManagerHelper.canCurrentProcessAddUsers()).isTrue();
-
-        doReturn(true).when(mUserManager)
-                .hasUserRestriction(UserManager.DISALLOW_ADD_USER);
-        assertThat(mCarUserManagerHelper.canCurrentProcessAddUsers()).isFalse();
-    }
-
-    @Test
-    public void testCurrentProcessCanRemoveUsers() {
-        doReturn(false).when(mUserManager)
-                .hasUserRestriction(UserManager.DISALLOW_REMOVE_USER);
-        assertThat(mCarUserManagerHelper.canCurrentProcessRemoveUsers()).isTrue();
-
-        doReturn(true).when(mUserManager)
-                .hasUserRestriction(UserManager.DISALLOW_REMOVE_USER);
-        assertThat(mCarUserManagerHelper.canCurrentProcessRemoveUsers()).isFalse();
-    }
-
-    @Test
-    public void testCurrentProcessCanSwitchUsers() {
-        doReturn(false).when(mUserManager)
-                .hasUserRestriction(UserManager.DISALLOW_USER_SWITCH);
-        assertThat(mCarUserManagerHelper.canCurrentProcessSwitchUsers()).isTrue();
-
-        doReturn(true).when(mUserManager)
-                .hasUserRestriction(UserManager.DISALLOW_USER_SWITCH);
-        assertThat(mCarUserManagerHelper.canCurrentProcessSwitchUsers()).isFalse();
-    }
-
-    @Test
-    public void testCurrentGuestProcessCannotModifyAccounts() {
-        assertThat(mCarUserManagerHelper.canCurrentProcessModifyAccounts()).isTrue();
-
-        doReturn(true).when(mUserManager).isGuestUser();
-
-        assertThat(mCarUserManagerHelper.canCurrentProcessModifyAccounts()).isFalse();
-    }
-
-    @Test
-    public void testCurrentDemoProcessCannotModifyAccounts() {
-        assertThat(mCarUserManagerHelper.canCurrentProcessModifyAccounts()).isTrue();
-
-        doReturn(true).when(mUserManager).isDemoUser();
-
-        assertThat(mCarUserManagerHelper.canCurrentProcessModifyAccounts()).isFalse();
-    }
-
-    @Test
-    public void testCurrentDisallowModifyAccountsProcessIsEnforced() {
-        assertThat(mCarUserManagerHelper.canCurrentProcessModifyAccounts()).isTrue();
-
-        doReturn(true).when(mUserManager)
-                .hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS);
-
-        assertThat(mCarUserManagerHelper.canCurrentProcessModifyAccounts()).isFalse();
-    }
-
-    @Test
-    public void testGetMaxSupportedUsers() {
-        setMaxSupportedUsers(11);
-
-        // Max users - headless system user.
-        assertThat(mCarUserManagerHelper.getMaxSupportedUsers()).isEqualTo(10);
-    }
-
-    @Test
-    public void testGetMaxSupportedRealUsers() {
-        setMaxSupportedUsers(7);
-
-        // Create three managed profiles, and two normal users.
-        UserInfo user1 = createUserInfoForId(10);
-        UserInfo user2 =
-                new UserInfo(/* id= */ 11, /* name = */ "user11", UserInfo.FLAG_MANAGED_PROFILE);
-        UserInfo user3 =
-                new UserInfo(/* id= */ 12, /* name = */ "user12", UserInfo.FLAG_MANAGED_PROFILE);
-        UserInfo user4 = createUserInfoForId(13);
-        UserInfo user5 =
-                new UserInfo(/* id= */ 14, /* name = */ "user14", UserInfo.FLAG_MANAGED_PROFILE);
-
-        mockGetUsers(user1, user2, user3, user4, user5);
-
-        // Max users - # managed profiles - headless system user.
-        assertThat(mCarUserManagerHelper.getMaxSupportedRealUsers()).isEqualTo(3);
-    }
-
-    @Test
-    public void testHeadlessSystemUser_IsUserLimitReached() {
-        UserInfo user1 = createUserInfoForId(10);
-        UserInfo user2 =
-                new UserInfo(/* id= */ 11, /* name = */ "user11", UserInfo.FLAG_MANAGED_PROFILE);
-        UserInfo user3 =
-                new UserInfo(/* id= */ 12, /* name = */ "user12", UserInfo.FLAG_MANAGED_PROFILE);
-        UserInfo user4 = createUserInfoForId(13);
-
-        mockGetUsers(mSystemUser, user1, user2, user3, user4);
-
-        setMaxSupportedUsers(6);
-        assertThat(mCarUserManagerHelper.isUserLimitReached()).isFalse();
-
-        setMaxSupportedUsers(5);
-        assertThat(mCarUserManagerHelper.isUserLimitReached()).isTrue();
-    }
-
-    @Test
-    public void testIsUserLimitReachedIgnoresGuests() {
-        setMaxSupportedUsers(6);
-
-        UserInfo user1 = createUserInfoForId(10);
-        UserInfo user2 =
-                new UserInfo(/* id= */ 11, /* name = */ "user11", UserInfo.FLAG_MANAGED_PROFILE);
-        UserInfo user3 =
-                new UserInfo(/* id= */ 12, /* name = */ "user12", UserInfo.FLAG_MANAGED_PROFILE);
-        UserInfo user4 = createUserInfoForId(13);
-        UserInfo user5 = new UserInfo(/* id= */ 14, /* name = */ "user14", UserInfo.FLAG_GUEST);
-        UserInfo user6 = createUserInfoForId(15);
-
-        mockGetUsers(user1, user2, user3, user4);
-        assertThat(mCarUserManagerHelper.isUserLimitReached()).isFalse();
-
-        // Add guest user. Verify it doesn't affect the limit.
-        mockGetUsers(user1, user2, user3, user4, user5);
-        assertThat(mCarUserManagerHelper.isUserLimitReached()).isFalse();
-
-        // Add normal user. Limit is reached
-        mockGetUsers(user1, user2, user3, user4, user5, user6);
-        assertThat(mCarUserManagerHelper.isUserLimitReached()).isTrue();
-    }
-
-    @Test
-    public void testCreateNewAdminUserCallsCreateUser() {
-        // Make sure current user is admin, since only admins can create other admins.
-        doReturn(true).when(mUserManager).isAdminUser();
-
-        mCarUserManagerHelper.createNewAdminUser(TEST_USER_NAME);
-        verify(mUserManager).createUser(TEST_USER_NAME, UserInfo.FLAG_ADMIN);
-    }
-
-    @Test
-    public void testCreateNewAdminUserReturnsNullUsers() {
-        // Make sure current user is admin, since only admins can create other admins.
-        doReturn(true).when(mUserManager).isAdminUser();
-
-        doReturn(null).when(mUserManager).createUser(TEST_USER_NAME, UserInfo.FLAG_ADMIN);
-        assertThat(mCarUserManagerHelper.createNewAdminUser(TEST_USER_NAME)).isNull();
-    }
-
-    @Test
-    public void testCreateNewAdminUserReturnsCreatedUser() {
-        // Make sure current user is admin, since only admins can create other admins.
-        doReturn(true).when(mUserManager).isAdminUser();
-
-        UserInfo newUser = new UserInfo();
-        newUser.name = TEST_USER_NAME;
-        doReturn(newUser).when(mUserManager).createUser(TEST_USER_NAME, UserInfo.FLAG_ADMIN);
-        assertThat(mCarUserManagerHelper.createNewAdminUser(TEST_USER_NAME)).isEqualTo(newUser);
-    }
-
-    @Test
-    public void testCreateNewAdminUserWithDefaultUserNameCallsCreateUser() {
-        // Make sure current user is admin, since only admins can create other admins.
-        doReturn(true).when(mUserManager).isAdminUser();
-
-        mCarUserManagerHelper.createNewAdminUser();
-        verify(mUserManager).createUser(DEFAULT_ADMIN_NAME, UserInfo.FLAG_ADMIN);
-    }
-
-    @Test
-    public void testCreateNewAdminUserWithDefaultUserNameReturnsNullUsers() {
-        // Make sure current user is admin, since only admins can create other admins.
-        doReturn(true).when(mUserManager).isAdminUser();
-
-        doReturn(null).when(mUserManager).createUser(DEFAULT_ADMIN_NAME, UserInfo.FLAG_ADMIN);
-        assertThat(mCarUserManagerHelper.createNewAdminUser(DEFAULT_ADMIN_NAME)).isNull();
-    }
-
-    @Test
-    public void testCreateNewAdminUserWithDefaultUserNameReturnsCreatedUser() {
-        // Make sure current user is admin, since only admins can create other admins.
-        doReturn(true).when(mUserManager).isAdminUser();
-
-        UserInfo newUser = new UserInfo();
-        newUser.name = DEFAULT_ADMIN_NAME;
-        doReturn(newUser).when(mUserManager).createUser(DEFAULT_ADMIN_NAME, UserInfo.FLAG_ADMIN);
-        assertThat(mCarUserManagerHelper.createNewAdminUser()).isEqualTo(newUser);
-    }
-
-    @Test
-    public void testAdminsCanCreateAdmins() {
-        String newAdminName = "Test new admin";
-        UserInfo expectedAdmin = new UserInfo();
-        expectedAdmin.name = newAdminName;
-        doReturn(expectedAdmin).when(mUserManager).createUser(newAdminName, UserInfo.FLAG_ADMIN);
-
-        // Admins can create other admins.
-        doReturn(true).when(mUserManager).isAdminUser();
-        UserInfo actualAdmin = mCarUserManagerHelper.createNewAdminUser(newAdminName);
-        assertThat(actualAdmin).isEqualTo(expectedAdmin);
-    }
-
-    @Test
-    public void testNonAdminsCanNotCreateAdmins() {
-        String newAdminName = "Test new admin";
-        UserInfo expectedAdmin = new UserInfo();
-        expectedAdmin.name = newAdminName;
-        doReturn(expectedAdmin).when(mUserManager).createUser(newAdminName, UserInfo.FLAG_ADMIN);
-
-        // Test that non-admins cannot create new admins.
-        doReturn(false).when(mUserManager).isAdminUser(); // Current user non-admin.
-        assertThat(mCarUserManagerHelper.createNewAdminUser(newAdminName)).isNull();
-    }
-
-    @Test
-    public void testSystemUserCanCreateAdmins() {
-        String newAdminName = "Test new admin";
-        UserInfo expectedAdmin = new UserInfo();
-        expectedAdmin.name = newAdminName;
-
-        doReturn(expectedAdmin).when(mUserManager).createUser(newAdminName, UserInfo.FLAG_ADMIN);
-
-        // System user can create admins.
-        doReturn(true).when(mUserManager).isSystemUser();
-        UserInfo actualAdmin = mCarUserManagerHelper.createNewAdminUser(newAdminName);
-        assertThat(actualAdmin).isEqualTo(expectedAdmin);
+        mockGetCurrentUser(mForegroundUserId);
     }
 
     @Test
     public void testCreateNewNonAdminUser() {
         // Verify createUser on UserManager gets called.
         mCarUserManagerHelper.createNewNonAdminUser(TEST_USER_NAME);
-        verify(mUserManager).createUser(TEST_USER_NAME, 0);
+        verify(mUserManager).createUser(TEST_USER_NAME, NO_FLAGS);
 
-        doReturn(null).when(mUserManager).createUser(TEST_USER_NAME, 0);
+        doReturn(null).when(mUserManager).createUser(TEST_USER_NAME, NO_FLAGS);
         assertThat(mCarUserManagerHelper.createNewNonAdminUser(TEST_USER_NAME)).isNull();
 
         UserInfo newUser = new UserInfo();
         newUser.name = TEST_USER_NAME;
-        doReturn(newUser).when(mUserManager).createUser(TEST_USER_NAME, 0);
+        doReturn(newUser).when(mUserManager).createUser(TEST_USER_NAME, NO_FLAGS);
         assertThat(mCarUserManagerHelper.createNewNonAdminUser(TEST_USER_NAME)).isEqualTo(newUser);
     }
 
     @Test
-    public void testCannotRemoveSystemUser() {
-        assertThat(mCarUserManagerHelper.removeUser(mSystemUser, GUEST_USER_NAME)).isFalse();
-    }
-
-    @Test
-    public void testAdminsCanRemoveOtherUsers() {
-        int idToRemove = mCurrentProcessUser.id + 2;
-        UserInfo userToRemove = createUserInfoForId(idToRemove);
-
-        doReturn(true).when(mUserManager).removeUser(idToRemove);
-
-        // If Admin is removing non-current, non-system user, simply calls removeUser.
-        doReturn(true).when(mUserManager).isAdminUser();
-        assertThat(mCarUserManagerHelper.removeUser(userToRemove, GUEST_USER_NAME)).isTrue();
-        verify(mUserManager).removeUser(idToRemove);
-    }
-
-    @Test
-    public void testNonAdminsCanNotRemoveOtherUsers() {
-        UserInfo otherUser = createUserInfoForId(mCurrentProcessUser.id + 2);
-
-        // Make current user non-admin.
-        doReturn(false).when(mUserManager).isAdminUser();
-
-        // Mock so that removeUser always pretends it's successful.
-        doReturn(true).when(mUserManager).removeUser(anyInt());
-
-        // If Non-Admin is trying to remove someone other than themselves, they should fail.
-        assertThat(mCarUserManagerHelper.removeUser(otherUser, GUEST_USER_NAME)).isFalse();
-        verify(mUserManager, never()).removeUser(otherUser.id);
-    }
-
-    @Test
-    public void testRemoveLastActiveUser() {
-        // Cannot remove system user.
-        assertThat(mCarUserManagerHelper.removeUser(mSystemUser, GUEST_USER_NAME)).isFalse();
-
-        UserInfo adminInfo = new UserInfo(/* id= */10, "admin", UserInfo.FLAG_ADMIN);
-        mockGetUsers(adminInfo);
-
-        assertThat(mCarUserManagerHelper.removeUser(adminInfo, GUEST_USER_NAME))
-                .isEqualTo(false);
-    }
-
-    @Test
-    public void testRemoveLastAdminUser() {
-        // Make current user admin.
-        doReturn(true).when(mUserManager).isAdminUser();
-
-        UserInfo adminInfo = new UserInfo(/* id= */10, "admin", UserInfo.FLAG_ADMIN);
-        UserInfo nonAdminInfo = new UserInfo(/* id= */11, "non-admin", 0);
-        mockGetUsers(adminInfo, nonAdminInfo);
-
-        UserInfo newAdminInfo = new UserInfo(/* id= */12, DEFAULT_ADMIN_NAME, UserInfo.FLAG_ADMIN);
-        doReturn(newAdminInfo)
-                .when(mUserManager).createUser(DEFAULT_ADMIN_NAME, UserInfo.FLAG_ADMIN);
-
-        mCarUserManagerHelper.removeUser(adminInfo, GUEST_USER_NAME);
-        verify(mUserManager).createUser(DEFAULT_ADMIN_NAME, UserInfo.FLAG_ADMIN);
-        verify(mActivityManager).switchUser(newAdminInfo.id);
-        verify(mUserManager).removeUser(adminInfo.id);
-    }
-
-    @Test
-    public void testRemoveLastAdminUserFailsToCreateNewUser() {
-        // Make current user admin.
-        doReturn(true).when(mUserManager).isAdminUser();
-
-        UserInfo adminInfo = new UserInfo(/* id= */10, "admin", UserInfo.FLAG_ADMIN);
-        UserInfo nonAdminInfo = new UserInfo(/* id= */11, "non-admin", 0);
-        mockGetUsers(adminInfo, nonAdminInfo);
-
-        UserInfo newAdminInfo = new UserInfo(/* id= */12, DEFAULT_ADMIN_NAME, UserInfo.FLAG_ADMIN);
-        doReturn(newAdminInfo)
-                .when(mUserManager).createUser(DEFAULT_ADMIN_NAME, UserInfo.FLAG_ADMIN);
-
-        // Fail to create a new user to force a failure case
-        doReturn(null)
-                .when(mUserManager).createUser(DEFAULT_ADMIN_NAME, UserInfo.FLAG_ADMIN);
-
-        mCarUserManagerHelper.removeUser(adminInfo, GUEST_USER_NAME);
-        verify(mUserManager).createUser(DEFAULT_ADMIN_NAME, UserInfo.FLAG_ADMIN);
-        verify(mActivityManager, never()).switchUser(anyInt());
-        verify(mUserManager, never()).removeUser(adminInfo.id);
-    }
-
-    @Test
-    public void testSwitchToGuest() {
-        mCarUserManagerHelper.startGuestSession(GUEST_USER_NAME);
-        verify(mUserManager).createGuest(mContext, GUEST_USER_NAME);
-
-        UserInfo guestInfo = new UserInfo(/* id= */21, GUEST_USER_NAME, UserInfo.FLAG_GUEST);
-        doReturn(guestInfo).when(mUserManager).createGuest(mContext, GUEST_USER_NAME);
-        mCarUserManagerHelper.startGuestSession(GUEST_USER_NAME);
-        verify(mActivityManager).switchUser(21);
-    }
-
-    @Test
     public void testSwitchToId() {
         int userIdToSwitchTo = mForegroundUserId + 2;
         doReturn(true).when(mActivityManager).switchUser(userIdToSwitchTo);
@@ -579,46 +133,16 @@
     public void testCannotSwitchIfSwitchingNotAllowed() {
         int userIdToSwitchTo = mForegroundUserId + 2;
         doReturn(true).when(mActivityManager).switchUser(userIdToSwitchTo);
-        doReturn(true).when(mUserManager).hasUserRestriction(UserManager.DISALLOW_USER_SWITCH);
+        doReturn(UserManager.SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED)
+                .when(mUserManager).getUserSwitchability();
         assertThat(mCarUserManagerHelper.switchToUserId(userIdToSwitchTo)).isFalse();
         verify(mActivityManager, never()).switchUser(userIdToSwitchTo);
     }
 
     @Test
-    public void testGetUserIcon() {
-        mCarUserManagerHelper.getUserIcon(mCurrentProcessUser);
-        verify(mUserManager).getUserIcon(mCurrentProcessUser.id);
-    }
-
-    @Test
-    public void testScaleUserIcon() {
-        Bitmap fakeIcon = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
-        Drawable scaledIcon = mCarUserManagerHelper.scaleUserIcon(fakeIcon, 300);
-        assertThat(scaledIcon.getIntrinsicWidth()).isEqualTo(300);
-        assertThat(scaledIcon.getIntrinsicHeight()).isEqualTo(300);
-    }
-
-    @Test
-    public void testSetUserName() {
-        UserInfo testInfo = createUserInfoForId(mCurrentProcessUser.id + 3);
-        String newName = "New Test Name";
-        mCarUserManagerHelper.setUserName(testInfo, newName);
-        verify(mUserManager).setUserName(mCurrentProcessUser.id + 3, newName);
-    }
-
-    @Test
-    public void testIsCurrentProcessSystemUser() {
-        doReturn(true).when(mUserManager).isAdminUser();
-        assertThat(mCarUserManagerHelper.isCurrentProcessAdminUser()).isTrue();
-
-        doReturn(false).when(mUserManager).isAdminUser();
-        assertThat(mCarUserManagerHelper.isCurrentProcessAdminUser()).isFalse();
-    }
-
-    @Test
     public void testGrantAdminPermissions() {
         int userId = 30;
-        UserInfo testInfo = createUserInfoForId(userId);
+        UserInfo testInfo = newUser(userId);
 
         // Test that non-admins cannot grant admin permissions.
         doReturn(false).when(mUserManager).isAdminUser(); // Current user non-admin.
@@ -632,64 +156,24 @@
     }
 
     @Test
-    public void testSetUserRestriction() {
-        int userId = 20;
-        UserInfo testInfo = createUserInfoForId(userId);
-
-        mCarUserManagerHelper.setUserRestriction(
-                testInfo, UserManager.DISALLOW_ADD_USER, /* enable= */ true);
-        verify(mUserManager).setUserRestriction(
-                UserManager.DISALLOW_ADD_USER, true, UserHandle.of(userId));
-
-        mCarUserManagerHelper.setUserRestriction(
-                testInfo, UserManager.DISALLOW_REMOVE_USER, /* enable= */ false);
-        verify(mUserManager).setUserRestriction(
-                UserManager.DISALLOW_REMOVE_USER, false, UserHandle.of(userId));
-    }
-
-    @Test
     public void testDefaultNonAdminRestrictions() {
         String testUserName = "Test User";
         int userId = 20;
-        UserInfo newNonAdmin = createUserInfoForId(userId);
+        UserInfo newNonAdmin = newUser(userId);
 
-        doReturn(newNonAdmin).when(mUserManager).createUser(testUserName, /* flags= */ 0);
+        doReturn(newNonAdmin).when(mUserManager).createUser(testUserName, NO_FLAGS);
 
         mCarUserManagerHelper.createNewNonAdminUser(testUserName);
 
         verify(mUserManager).setUserRestriction(
                 UserManager.DISALLOW_FACTORY_RESET, /* enable= */ true, UserHandle.of(userId));
-        verify(mUserManager).setUserRestriction(
-                UserManager.DISALLOW_SMS, /* enable= */ false, UserHandle.of(userId));
-        verify(mUserManager).setUserRestriction(
-                UserManager.DISALLOW_OUTGOING_CALLS, /* enable= */ false, UserHandle.of(userId));
-    }
-
-    @Test
-    public void testDefaultGuestRestrictions() {
-        int guestRestrictionsExpectedCount = 6;
-
-        ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
-        mCarUserManagerHelper.initDefaultGuestRestrictions();
-
-        verify(mUserManager).setDefaultGuestRestrictions(bundleCaptor.capture());
-        Bundle guestRestrictions = bundleCaptor.getValue();
-
-        assertThat(guestRestrictions.keySet()).hasSize(guestRestrictionsExpectedCount);
-        assertThat(guestRestrictions.getBoolean(UserManager.DISALLOW_FACTORY_RESET)).isTrue();
-        assertThat(guestRestrictions.getBoolean(UserManager.DISALLOW_REMOVE_USER)).isTrue();
-        assertThat(guestRestrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)).isTrue();
-        assertThat(guestRestrictions.getBoolean(UserManager.DISALLOW_INSTALL_APPS)).isTrue();
-        assertThat(guestRestrictions.getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES))
-                .isTrue();
-        assertThat(guestRestrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS)).isTrue();
     }
 
     @Test
     public void testGrantingAdminPermissionsRemovesNonAdminRestrictions() {
         int testUserId = 30;
         boolean restrictionEnabled = false;
-        UserInfo testInfo = createUserInfoForId(testUserId);
+        UserInfo testInfo = newUser(testUserId);
 
         // Only admins can grant permissions.
         doReturn(true).when(mUserManager).isAdminUser();
@@ -701,278 +185,207 @@
     }
 
     @Test
-    public void testRegisterUserChangeReceiver() {
-        mCarUserManagerHelper.registerOnUsersUpdateListener(mTestListener);
+    public void testGetInitialUser_WithValidLastActiveUser_ReturnsLastActiveUser() {
+        setLastActiveUser(12);
+        mockGetUsers(USER_SYSTEM, 10, 11, 12);
 
-        ArgumentCaptor<BroadcastReceiver> receiverCaptor =
-                ArgumentCaptor.forClass(BroadcastReceiver.class);
-        ArgumentCaptor<UserHandle> handleCaptor = ArgumentCaptor.forClass(UserHandle.class);
-        ArgumentCaptor<IntentFilter> filterCaptor = ArgumentCaptor.forClass(IntentFilter.class);
-        ArgumentCaptor<String> permissionCaptor = ArgumentCaptor.forClass(String.class);
-        ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
-
-        verify(mContext).registerReceiverAsUser(
-                receiverCaptor.capture(),
-                handleCaptor.capture(),
-                filterCaptor.capture(),
-                permissionCaptor.capture(),
-                handlerCaptor.capture());
-
-        // Verify we're listening to Intents from ALL users.
-        assertThat(handleCaptor.getValue()).isEqualTo(UserHandle.ALL);
-
-        // Verify the presence of each intent in the filter.
-        // Verify the exact number of filters. Every time a new intent is added, this test should
-        // get updated.
-        assertThat(filterCaptor.getValue().countActions()).isEqualTo(6);
-        assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_REMOVED)).isTrue();
-        assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_ADDED)).isTrue();
-        assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_INFO_CHANGED)).isTrue();
-        assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_SWITCHED)).isTrue();
-        assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_STOPPED)).isTrue();
-        assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_UNLOCKED)).isTrue();
-
-        // Verify that calling the receiver calls the listener.
-        receiverCaptor.getValue().onReceive(mContext, new Intent());
-        verify(mTestListener).onUsersUpdate();
-
-        assertThat(permissionCaptor.getValue()).isNull();
-        assertThat(handlerCaptor.getValue()).isNull();
-
-        // Unregister the receiver.
-        mCarUserManagerHelper.unregisterOnUsersUpdateListener(mTestListener);
-        verify(mContext).unregisterReceiver(receiverCaptor.getValue());
+        assertThat(mCarUserManagerHelper.getInitialUser(/* usesOverrideUserIdProperty= */ true))
+                .isEqualTo(12);
     }
 
     @Test
-    public void testMultipleRegistrationsOfSameListener() {
-        CarUserManagerHelper.OnUsersUpdateListener listener =
-                Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class);
+    public void testGetInitialUser_WithNonExistLastActiveUser_ReturnsLastPersistentUser() {
+        setLastActiveUser(120);
+        setLastPersistentActiveUser(110);
+        mockGetUsers(USER_SYSTEM, 100, 110);
 
-        ArgumentCaptor<BroadcastReceiver> receiverCaptor =
-                ArgumentCaptor.forClass(BroadcastReceiver.class);
-
-        mCarUserManagerHelper.registerOnUsersUpdateListener(listener);
-        mCarUserManagerHelper.registerOnUsersUpdateListener(listener);
-        // Even for multiple registrations of the same listener, broadcast receiver registered once.
-        verify(mContext, times(1))
-                .registerReceiverAsUser(receiverCaptor.capture(), any(), any(), any(), any());
-
-        // Verify that calling the receiver calls the listener.
-        receiverCaptor.getValue().onReceive(mContext, new Intent());
-        verify(listener).onUsersUpdate();
-
-        // Verify that a single removal unregisters the listener.
-        mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener);
-        verify(mContext).unregisterReceiver(any());
+        assertThat(mCarUserManagerHelper.getInitialUser(/* usesOverrideUserIdProperty= */ true))
+                .isEqualTo(110);
+        // should have reset last active user
+        assertThat(getSettingsInt(CarSettings.Global.LAST_ACTIVE_USER_ID))
+                .isEqualTo(UserHandle.USER_NULL);
     }
 
     @Test
-    public void testMultipleUnregistrationsOfTheSameListener() {
-        CarUserManagerHelper.OnUsersUpdateListener listener =
-                Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class);
-        mCarUserManagerHelper.registerOnUsersUpdateListener(listener);
+    public void testGetInitialUser_WithNonExistLastActiveAndPersistentUsers_ReturnsSmallestUser() {
+        setLastActiveUser(120);
+        setLastPersistentActiveUser(120);
+        mockGetUsers(USER_SYSTEM, 100, 110);
 
-        // Verify that a multiple unregistrations cause only one unregister for broadcast receiver.
-        mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener);
-        mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener);
-        mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener);
-        verify(mContext, times(1)).unregisterReceiver(any());
+        assertThat(mCarUserManagerHelper.getInitialUser(/* usesOverrideUserIdProperty= */ true))
+                .isEqualTo(100);
+        // should have reset both settions
+        assertThat(getSettingsInt(CarSettings.Global.LAST_ACTIVE_USER_ID))
+                .isEqualTo(UserHandle.USER_NULL);
+        assertThat(getSettingsInt(CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID))
+                .isEqualTo(UserHandle.USER_NULL);
     }
 
     @Test
-    public void testUnregisterReceiverCalledAfterAllListenersUnregister() {
-        CarUserManagerHelper.OnUsersUpdateListener listener1 =
-                Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class);
-        CarUserManagerHelper.OnUsersUpdateListener listener2 =
-                Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class);
+    public void testGetInitialUser_WithOverrideId_ReturnsOverrideId() {
+        setDefaultBootUserOverride(11);
+        setLastActiveUser(12);
+        mockGetUsers(USER_SYSTEM, 10, 11, 12);
 
-        mCarUserManagerHelper.registerOnUsersUpdateListener(listener1);
-        mCarUserManagerHelper.registerOnUsersUpdateListener(listener2);
-
-        mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener1);
-        verify(mContext, never()).unregisterReceiver(any());
-
-        mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener2);
-        verify(mContext, times(1)).unregisterReceiver(any());
+        assertThat(mCarUserManagerHelper.getInitialUser(/* usesOverrideUserIdProperty= */ true))
+                .isEqualTo(11);
     }
 
     @Test
-    public void testRegisteringMultipleListeners() {
-        CarUserManagerHelper.OnUsersUpdateListener listener1 =
-                Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class);
-        CarUserManagerHelper.OnUsersUpdateListener listener2 =
-                Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class);
-        ArgumentCaptor<BroadcastReceiver> receiverCaptor =
-                ArgumentCaptor.forClass(BroadcastReceiver.class);
+    public void testGetInitialUser_WithInvalidOverrideId_ReturnsLastActiveUserId() {
+        setDefaultBootUserOverride(15);
+        setLastActiveUser(12);
+        mockGetUsers(USER_SYSTEM, 10, 11, 12);
 
-        mCarUserManagerHelper.registerOnUsersUpdateListener(listener1);
-        mCarUserManagerHelper.registerOnUsersUpdateListener(listener2);
-        verify(mContext, times(1))
-                .registerReceiverAsUser(receiverCaptor.capture(), any(), any(), any(), any());
-
-        // Verify that calling the receiver calls both listeners.
-        receiverCaptor.getValue().onReceive(mContext, new Intent());
-        verify(listener1).onUsersUpdate();
-        verify(listener2).onUsersUpdate();
+        assertThat(mCarUserManagerHelper.getInitialUser(/* usesOverrideUserIdProperty= */ true))
+                .isEqualTo(12);
     }
 
     @Test
-    public void testUnregisteringListenerStopsUpdatesForListener() {
-        CarUserManagerHelper.OnUsersUpdateListener listener1 =
-                Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class);
-        CarUserManagerHelper.OnUsersUpdateListener listener2 =
-                Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class);
-        ArgumentCaptor<BroadcastReceiver> receiverCaptor =
-                ArgumentCaptor.forClass(BroadcastReceiver.class);
-
-        mCarUserManagerHelper.registerOnUsersUpdateListener(listener1);
-        mCarUserManagerHelper.registerOnUsersUpdateListener(listener2);
-        verify(mContext, times(1))
-                .registerReceiverAsUser(receiverCaptor.capture(), any(), any(), any(), any());
-
-        // Unregister listener2
-        mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener2);
-
-        // Verify that calling the receiver calls only one listener.
-        receiverCaptor.getValue().onReceive(mContext, new Intent());
-        verify(listener1).onUsersUpdate();
-        verify(listener2, never()).onUsersUpdate();
-    }
-
-    @Test
-    public void test_GetInitialUserWithValidLastActiveUser_ReturnsLastActiveUser() {
-        int lastActiveUserId = 12;
-
-        UserInfo user10 = createUserInfoForId(10);
-        UserInfo user11 = createUserInfoForId(11);
-        UserInfo user12 = createUserInfoForId(12);
-
-        setLastActiveUser(lastActiveUserId);
-        mockGetUsers(mSystemUser, user10, user11, user12);
-
-        assertThat(mCarUserManagerHelper.getInitialUser()).isEqualTo(lastActiveUserId);
-    }
-
-    @Test
-    public void test_GetInitialUserWithNonExistLastActiveUser_ReturnsSmallestUserId() {
-        int lastActiveUserId = 12;
-        int minimumUserId = 10;
-
-        UserInfo smallestUser = createUserInfoForId(minimumUserId);
-        UserInfo notSmallestUser = createUserInfoForId(minimumUserId + 1);
-
-        setLastActiveUser(lastActiveUserId);
-        mockGetUsers(mSystemUser, smallestUser, notSmallestUser);
-
-        assertThat(mCarUserManagerHelper.getInitialUser()).isEqualTo(minimumUserId);
-    }
-
-    @Test
-    public void test_GetInitialUserWithOverrideId_ReturnsOverrideId() {
-        int lastActiveUserId = 12;
-        int overrideUserId = 11;
-
-        UserInfo user10 = createUserInfoForId(10);
-        UserInfo user11 = createUserInfoForId(11);
-        UserInfo user12 = createUserInfoForId(12);
-
-        setDefaultBootUserOverride(overrideUserId);
-        setLastActiveUser(lastActiveUserId);
-        mockGetUsers(mSystemUser, user10, user11, user12);
-
-        assertThat(mCarUserManagerHelper.getInitialUser()).isEqualTo(overrideUserId);
-    }
-
-    @Test
-    public void test_GetInitialUserWithInvalidOverrideId_ReturnsLastActiveUserId() {
-        int lastActiveUserId = 12;
-        int overrideUserId = 15;
-
-        UserInfo user10 = createUserInfoForId(10);
-        UserInfo user11 = createUserInfoForId(11);
-        UserInfo user12 = createUserInfoForId(12);
-
-        setDefaultBootUserOverride(overrideUserId);
-        setLastActiveUser(lastActiveUserId);
-        mockGetUsers(mSystemUser, user10, user11, user12);
-
-        assertThat(mCarUserManagerHelper.getInitialUser()).isEqualTo(lastActiveUserId);
-    }
-
-    @Test
-    public void test_GetInitialUserWithInvalidOverrideAndLastActiveUserIds_ReturnsSmallestUserId() {
+    public void testGetInitialUser_WithInvalidOverrideAndLastActiveUserIds_ReturnsSmallestUserId() {
         int minimumUserId = 10;
         int invalidLastActiveUserId = 14;
         int invalidOverrideUserId = 15;
 
-        UserInfo minimumUser = createUserInfoForId(minimumUserId);
-        UserInfo user11 = createUserInfoForId(minimumUserId + 1);
-        UserInfo user12 = createUserInfoForId(minimumUserId + 2);
-
         setDefaultBootUserOverride(invalidOverrideUserId);
         setLastActiveUser(invalidLastActiveUserId);
-        mockGetUsers(mSystemUser, minimumUser, user11, user12);
+        mockGetUsers(USER_SYSTEM, minimumUserId, minimumUserId + 1, minimumUserId + 2);
 
-        assertThat(mCarUserManagerHelper.getInitialUser()).isEqualTo(minimumUserId);
+        assertThat(mCarUserManagerHelper.getInitialUser(/* usesOverrideUserIdProperty= */ true))
+                .isEqualTo(minimumUserId);
     }
 
     @Test
-    public void test_CreateNewOrFindExistingGuest_ReturnsExistingGuest() {
-        // Create two users and a guest user.
-        UserInfo user1 = createUserInfoForId(10);
-        UserInfo user2 = createUserInfoForId(12);
-        UserInfo user3 = new UserInfo(/* id= */ 13, /* name = */ "user13", UserInfo.FLAG_GUEST);
+    public void testGetInitialUser_WhenOverrideIdIsIgnored() {
+        setDefaultBootUserOverride(11);
+        setLastActiveUser(12);
+        mockGetUsers(USER_SYSTEM, 10, 11, 12);
 
-        mockGetUsers(user1, user2, user3);
-        doReturn(null).when(mUserManager).createGuest(any(), any());
-
-        UserInfo guest = mCarUserManagerHelper.createNewOrFindExistingGuest(GUEST_USER_NAME);
-        assertThat(guest).isEqualTo(user3);
+        assertThat(mCarUserManagerHelper.getInitialUser(/* usesOverrideUserIdProperty= */ false))
+                .isEqualTo(12);
     }
 
     @Test
-    public void test_CreateNewOrFindExistingGuest_CreatesNewGuest_IfNoExisting() {
-        // Create two users.
-        UserInfo user1 = createUserInfoForId(10);
-        UserInfo user2 = createUserInfoForId(12);
-
-        mockGetUsers(user1, user2);
-
-        // Create a user for the "new guest" user.
-        UserInfo guestInfo = new UserInfo(/* id= */21, GUEST_USER_NAME, UserInfo.FLAG_GUEST);
-        doReturn(guestInfo).when(mUserManager).createGuest(mContext, GUEST_USER_NAME);
-
-        UserInfo guest = mCarUserManagerHelper.createNewOrFindExistingGuest(GUEST_USER_NAME);
-        verify(mUserManager).createGuest(mContext, GUEST_USER_NAME);
-        assertThat(guest).isEqualTo(guestInfo);
+    public void testGetInitialUser_WithEmptyReturnNull() {
+        assertThat(mCarUserManagerHelper.getInitialUser(/* usesOverrideUserIdProperty= */ true))
+                .isEqualTo(UserHandle.USER_NULL);
     }
 
-    private UserInfo createUserInfoForId(int id) {
-        UserInfo userInfo = new UserInfo();
-        userInfo.id = id;
-        return userInfo;
+    @Test
+    public void testHasInitialUser_onlyHeadlessSystemUser() {
+        mockIsHeadlessSystemUserMode(true);
+        mockGetUsers(USER_SYSTEM);
+
+        assertThat(mCarUserManagerHelper.hasInitialUser()).isFalse();
     }
 
-    private void mockGetUsers(UserInfo... users) {
-        List<UserInfo> testUsers = new ArrayList<>();
-        for (UserInfo user : users) {
-            testUsers.add(user);
-        }
-        doReturn(testUsers).when(mUserManager).getUsers(true);
+    @Test
+    public void testHasInitialUser_onlyNonHeadlessSystemUser() {
+        mockIsHeadlessSystemUserMode(false);
+        mockGetUsers(USER_SYSTEM);
+
+        assertThat(mCarUserManagerHelper.hasInitialUser()).isTrue();
     }
 
-    private void setLastActiveUser(int userId) {
-        Settings.Global.putInt(InstrumentationRegistry.getTargetContext().getContentResolver(),
-                Settings.Global.LAST_ACTIVE_USER_ID, userId);
+    @Test
+    public void testHasInitialUser_hasNormalUser() {
+        mockIsHeadlessSystemUserMode(true);
+        mockGetUsers(USER_SYSTEM, 10);
+
+        assertThat(mCarUserManagerHelper.hasInitialUser()).isTrue();
     }
 
-    private void setDefaultBootUserOverride(int userId) {
-        doReturn(userId).when(mTestableFrameworkWrapper)
-                .getBootUserOverrideId(anyInt());
+    @Test
+    public void testHasInitialUser_hasOnlyWorkProfile() {
+        mockIsHeadlessSystemUserMode(true);
+
+        UserInfo systemUser = newUser(UserHandle.USER_SYSTEM);
+
+        UserInfo workProfile = newUser(10);
+        workProfile.userType = UserManager.USER_TYPE_PROFILE_MANAGED;
+        assertThat(workProfile.isManagedProfile()).isTrue(); // Sanity check
+
+        mockGetUsers(systemUser, workProfile);
+
+        assertThat(mCarUserManagerHelper.hasInitialUser()).isFalse();
     }
 
-    private void setMaxSupportedUsers(int maxValue) {
-        doReturn(maxValue).when(mTestableFrameworkWrapper).userManagerGetMaxSupportedUsers();
+    @Test
+    public void testSetLastActiveUser_headlessSystem() {
+        mockIsHeadlessSystemUserMode(true);
+        mockUmGetSystemUser(mUserManager);
+
+        mCarUserManagerHelper.setLastActiveUser(UserHandle.USER_SYSTEM);
+
+        assertSettingsNotSet(CarSettings.Global.LAST_ACTIVE_USER_ID);
+        assertSettingsNotSet(CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID);
     }
-}
\ No newline at end of file
+
+    @Test
+    public void testSetLastActiveUser_nonHeadlessSystem() {
+        mockIsHeadlessSystemUserMode(false);
+        mockUmGetSystemUser(mUserManager);
+
+        mCarUserManagerHelper.setLastActiveUser(UserHandle.USER_SYSTEM);
+
+        assertThat(getSettingsInt(CarSettings.Global.LAST_ACTIVE_USER_ID))
+                .isEqualTo(UserHandle.USER_SYSTEM);
+        assertThat(getSettingsInt(CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID))
+                .isEqualTo(UserHandle.USER_SYSTEM);
+    }
+
+    @Test
+    public void testSetLastActiveUser_nonExistingUser() {
+        // Don't need to mock um.getUser(), it will return null by default
+        mCarUserManagerHelper.setLastActiveUser(42);
+
+        assertThat(getSettingsInt(CarSettings.Global.LAST_ACTIVE_USER_ID)).isEqualTo(42);
+        assertSettingsNotSet(CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID);
+    }
+
+    @Test
+    public void testSetLastActiveUser_ephemeralUser() {
+        int persistentUserId = 42;
+        int ephemeralUserid = 108;
+        mockUmGetUserInfo(mUserManager, persistentUserId, NO_FLAGS);
+        mockUmGetUserInfo(mUserManager, ephemeralUserid, UserInfo.FLAG_EPHEMERAL);
+
+        mCarUserManagerHelper.setLastActiveUser(persistentUserId);
+        mCarUserManagerHelper.setLastActiveUser(ephemeralUserid);
+
+        assertThat(getSettingsInt(CarSettings.Global.LAST_ACTIVE_USER_ID))
+                .isEqualTo(ephemeralUserid);
+        assertThat(getSettingsInt(CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID))
+                .isEqualTo(persistentUserId);
+    }
+
+    @Test
+    public void testSetLastActiveUser_nonEphemeralUser() {
+        mockUmGetUserInfo(mUserManager, 42, NO_FLAGS);
+
+        mCarUserManagerHelper.setLastActiveUser(42);
+
+        assertThat(getSettingsInt(CarSettings.Global.LAST_ACTIVE_USER_ID)).isEqualTo(42);
+        assertThat(getSettingsInt(CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID)).isEqualTo(42);
+    }
+
+    private void mockGetUsers(@NonNull @UserIdInt int... userIds) {
+        mockUmGetUsers(mUserManager, userIds);
+    }
+
+    private void mockGetUsers(@NonNull UserInfo... users) {
+        mockUmGetUsers(mUserManager, users);
+    }
+
+    private void setLastActiveUser(@UserIdInt int userId) {
+        putSettingsInt(CarSettings.Global.LAST_ACTIVE_USER_ID, userId);
+    }
+
+    private void setLastPersistentActiveUser(@UserIdInt int userId) {
+        putSettingsInt(CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID, userId);
+    }
+
+    private void setDefaultBootUserOverride(@UserIdInt int userId) {
+        doReturn(Optional.of(userId)).when(() -> CarProperties.boot_user_override_id());
+    }
+}
diff --git a/tests/carservice_unit_test/src/android/car/userlib/InitialUserSetterTest.java b/tests/carservice_unit_test/src/android/car/userlib/InitialUserSetterTest.java
new file mode 100644
index 0000000..785cbc4
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/userlib/InitialUserSetterTest.java
@@ -0,0 +1,910 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.userlib;
+
+import static android.car.test.mocks.CarArgumentMatchers.isUserInfo;
+import static android.car.test.util.UserTestingHelper.newGuestUser;
+import static android.car.test.util.UserTestingHelper.newSecondaryUser;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.userlib.InitialUserSetter.Builder;
+import android.car.userlib.InitialUserSetter.InitialUserInfo;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.content.pm.UserInfo.UserInfoFlag;
+import android.hardware.automotive.vehicle.V2_0.UserFlags;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+
+import com.android.internal.widget.LockPatternUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
+import java.util.function.Consumer;
+
+public final class InitialUserSetterTest extends AbstractExtendedMockitoTestCase {
+
+    @UserInfoFlag
+    private static final int NO_FLAGS = 0;
+
+    private static final String OWNER_NAME = "OwnerOfALonelyDevice";
+    private static final String GUEST_NAME = "GuessWhot";
+
+    private static final int USER_ID = 10;
+    private static final int NEW_USER_ID = 11;
+    private static final int CURRENT_USER_ID = 12;
+
+    @Mock
+    private Context mContext;
+
+    @Mock
+    private CarUserManagerHelper mHelper;
+
+    @Mock
+    private IActivityManager mIActivityManager;
+
+    @Mock
+    private UserManager mUm;
+
+    @Mock
+    private LockPatternUtils mLockPatternUtils;
+
+    // Spy used in tests that need to verify the default behavior as fallback
+    private InitialUserSetter mSetter;
+
+    private final MyListener mListener = new MyListener();
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+        session
+            .spyStatic(ActivityManager.class)
+            .spyStatic(UserManager.class);
+    }
+
+    @Before
+    public void setFixtures() {
+        mSetter = spy(new InitialUserSetter(mContext, mHelper, mUm, mListener,
+                mLockPatternUtils, OWNER_NAME, GUEST_NAME));
+
+        doReturn(mIActivityManager).when(() -> ActivityManager.getService());
+        mockGetCurrentUser(CURRENT_USER_ID);
+    }
+
+    @Test
+    public void testSet_null() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> mSetter.set(null));
+    }
+
+    @Test
+    public void testInitialUserInfoBuilder_invalidType() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> new InitialUserSetter.Builder(-1));
+    }
+
+    @Test
+    public void testInitialUserInfoBuilder_invalidSetSwitchUserId() throws Exception {
+        InitialUserSetter.Builder builder = new InitialUserSetter.Builder(
+                InitialUserSetter.TYPE_CREATE);
+        assertThrows(IllegalArgumentException.class, () -> builder.setSwitchUserId(USER_ID));
+    }
+
+    @Test
+    public void testInitialUserInfoBuilder_invalidSetNewUserName() throws Exception {
+        InitialUserSetter.Builder builder = new InitialUserSetter.Builder(
+                InitialUserSetter.TYPE_SWITCH);
+        assertThrows(IllegalArgumentException.class, () -> builder.setNewUserName(OWNER_NAME));
+    }
+
+    @Test
+    public void testInitialUserInfoBuilder_invalidSetNewUserFlags() throws Exception {
+        InitialUserSetter.Builder builder = new InitialUserSetter.Builder(
+                InitialUserSetter.TYPE_SWITCH);
+        assertThrows(IllegalArgumentException.class,
+                () -> builder.setNewUserFlags(UserFlags.ADMIN));
+    }
+
+    @Test
+    public void testSwitchUser_ok_nonGuest() throws Exception {
+        UserInfo user = expectUserExists(USER_ID);
+        expectSwitchUser(USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_SWITCH)
+                .setSwitchUserId(USER_ID)
+                .build());
+
+        verifyUserSwitched(USER_ID);
+        verifyFallbackDefaultBehaviorNeverCalled();
+        verifySystemUserUnlocked();
+        assertInitialUserSet(user);
+    }
+
+    @Test
+    public void testSwitchUser_ok_systemUser() throws Exception {
+        UserInfo user = expectUserExists(UserHandle.USER_SYSTEM);
+        expectSwitchUser(UserHandle.USER_SYSTEM);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_SWITCH)
+                .setSwitchUserId(UserHandle.USER_SYSTEM)
+                .build());
+
+        verifyUserSwitched(UserHandle.USER_SYSTEM);
+        verifyFallbackDefaultBehaviorNeverCalled();
+        verifySystemUserNeverUnlocked();
+        assertInitialUserSet(user);
+    }
+
+    @Test
+    public void testSwitchUser_ok_guestReplaced() throws Exception {
+        boolean ephemeral = true; // ephemeral doesn't really matter in this test
+        mockGetCurrentUser(CURRENT_USER_ID);
+        expectGuestExists(USER_ID, ephemeral); // ephemeral doesn't matter
+        UserInfo newGuest = newGuestUser(NEW_USER_ID, ephemeral);
+        expectGuestReplaced(USER_ID, newGuest);
+        expectSwitchUser(NEW_USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_SWITCH)
+                .setSwitchUserId(USER_ID)
+                .setReplaceGuest(true)
+                .build());
+
+        verifyUserSwitched(NEW_USER_ID);
+        verifyFallbackDefaultBehaviorNeverCalled();
+        verifySystemUserUnlocked();
+        verifyUserDeleted(USER_ID);
+        assertInitialUserSet(newGuest);
+    }
+
+    @Test
+    public void testSwitchUser_ok_guestDoesNotNeedToBeReplaced() throws Exception {
+        boolean ephemeral = true; // ephemeral doesn't really matter in this test
+        UserInfo existingGuest = expectGuestExists(USER_ID, ephemeral);
+        expectSwitchUser(USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_SWITCH)
+                .setSwitchUserId(USER_ID)
+                .setReplaceGuest(false)
+                .build());
+
+        verifyUserSwitched(USER_ID);
+        verifyGuestNeverMarkedForDeletion();
+        verifyFallbackDefaultBehaviorNeverCalled();
+        verifySystemUserUnlocked();
+        assertInitialUserSet(existingGuest);
+    }
+
+
+    @Test
+    public void testSwitchUser_fail_guestReplacementFailed() throws Exception {
+        expectGuestExists(USER_ID, /* isEphemeral= */ true); // ephemeral doesn't matter
+        expectGuestReplaced(USER_ID, /* newGuest= */ null);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_SWITCH)
+                .setSwitchUserId(USER_ID)
+                .setReplaceGuest(true)
+                .build());
+
+        verifyUserNeverSwitched();
+        verifyFallbackDefaultBehaviorCalledFromCreateOrSwitch();
+        verifySystemUserNeverUnlocked();
+    }
+
+    @Test
+    public void testSwitchUser_fail_switchFail() throws Exception {
+        expectUserExists(USER_ID);
+        expectSwitchUserFails(USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_SWITCH)
+                .setSwitchUserId(USER_ID)
+                .build());
+
+        verifyFallbackDefaultBehaviorCalledFromCreateOrSwitch();
+        verifySystemUserUnlocked();
+        verifyLastActiveUserNeverSet();
+    }
+
+    @Test
+    public void testSwitchUser_fail_userDoesntExist() throws Exception {
+        // No need to set user exists expectation / will return null by default
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_SWITCH)
+                .setSwitchUserId(USER_ID)
+                .build());
+
+        verifyUserNeverSwitched();
+        verifyFallbackDefaultBehaviorCalledFromCreateOrSwitch();
+        verifySystemUserNeverUnlocked();
+    }
+
+    @Test
+    public void testSwitchUser_fail_switchThrowsException() throws Exception {
+        expectUserExists(USER_ID);
+        expectSwitchUserThrowsException(USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_SWITCH)
+                .setSwitchUserId(USER_ID)
+                .build());
+
+        verifyFallbackDefaultBehaviorCalledFromCreateOrSwitch();
+        verifySystemUserUnlocked();
+        verifyLastActiveUserNeverSet();
+    }
+
+    @Test
+    public void testSwitchUser_ok_targetIsCurrentUser() throws Exception {
+        mockGetCurrentUser(CURRENT_USER_ID);
+        UserInfo currentUser = expectUserExists(CURRENT_USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_SWITCH)
+                .setSwitchUserId(CURRENT_USER_ID)
+                .build());
+
+        verifyUserNeverSwitched();
+        verifyFallbackDefaultBehaviorNeverCalled();
+        verifySystemUserUnlocked();
+        assertInitialUserSet(currentUser);
+    }
+
+    @Test
+    public void testReplaceGuestIfNeeded_null() {
+        assertThrows(IllegalArgumentException.class, () -> mSetter.replaceGuestIfNeeded(null));
+    }
+
+    @Test
+    public void testReplaceGuestIfNeeded_nonGuest() {
+        UserInfo user = newSecondaryUser(USER_ID);
+
+        assertThat(mSetter.replaceGuestIfNeeded(user)).isSameAs(user);
+
+        verifyGuestNeverMarkedForDeletion();
+        verifyUserNeverCreated();
+    }
+
+    @Test
+    public void testReplaceGuestIfNeeded_ok_nonEphemeralGuest() {
+        UserInfo newGuest = expectCreateGuestUser(NEW_USER_ID, GUEST_NAME, NO_FLAGS);
+        UserInfo user = newGuestUser(USER_ID, /* ephemeral= */ false);
+
+        assertThat(mSetter.replaceGuestIfNeeded(user)).isSameAs(newGuest);
+
+        verifyGuestMarkedForDeletion(USER_ID);
+    }
+
+    @Test
+    public void testReplaceGuestIfNeeded_lockScreen() throws Exception {
+        UserInfo user = newGuestUser(USER_ID, /* ephemeral= */ false);
+        expectUserIsSecure(USER_ID);
+        assertThat(mSetter.replaceGuestIfNeeded(user)).isSameAs(user);
+
+        verifyGuestNeverMarkedForDeletion();
+        verifyUserNeverCreated();
+    }
+
+    @Test
+    public void testReplaceGuestIfNeeded_ok_ephemeralGuest() {
+        UserInfo newGuest = expectCreateGuestUser(NEW_USER_ID, GUEST_NAME, UserInfo.FLAG_EPHEMERAL);
+        UserInfo user = newGuestUser(USER_ID, /* ephemeral= */ true);
+
+        assertThat(mSetter.replaceGuestIfNeeded(user)).isSameAs(newGuest);
+
+        verifyGuestMarkedForDeletion(USER_ID);
+    }
+
+    @Test
+    public void testReplaceGuestIfNeeded_fail_ephemeralGuest_createFailed() {
+        // don't set create guest expectation, so it returns null
+
+        UserInfo user = newGuestUser(USER_ID, /* ephemeral= */ true);
+        assertThat(mSetter.replaceGuestIfNeeded(user)).isEqualTo(null);
+
+        verifyGuestMarkedForDeletion(USER_ID);
+    }
+
+    @Test
+    public void testCreateUser_ok_noflags() throws Exception {
+        UserInfo newUser = expectCreateFullUser(USER_ID, "TheDude", NO_FLAGS);
+        expectSwitchUser(USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_CREATE)
+                .setNewUserName("TheDude")
+                .setNewUserFlags(UserFlags.NONE)
+                .build());
+
+        verifyUserSwitched(USER_ID);
+        verifyFallbackDefaultBehaviorNeverCalled();
+        verifySystemUserUnlocked();
+        assertInitialUserSet(newUser);
+    }
+
+    @Test
+    public void testCreateUser_ok_admin() throws Exception {
+        UserInfo newUser = expectCreateFullUser(USER_ID, "TheDude", UserInfo.FLAG_ADMIN);
+        expectSwitchUser(USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_CREATE)
+                .setNewUserName("TheDude")
+                .setNewUserFlags(UserFlags.ADMIN)
+                .build());
+
+        verifyUserSwitched(USER_ID);
+        verifyFallbackDefaultBehaviorNeverCalled();
+        verifySystemUserUnlocked();
+        assertInitialUserSet(newUser);
+    }
+
+    @Test
+    public void testCreateUser_ok_admin_setLocale() throws Exception {
+        UserInfo newUser = expectCreateFullUser(USER_ID, "TheDude", UserInfo.FLAG_ADMIN);
+        expectSwitchUser(USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_CREATE)
+                .setNewUserName("TheDude")
+                .setNewUserFlags(UserFlags.ADMIN)
+                .setUserLocales("LOL")
+                .build());
+
+        verifyUserSwitched(USER_ID);
+        verifyFallbackDefaultBehaviorNeverCalled();
+        verifySystemUserUnlocked();
+        assertInitialUserSet(newUser);
+        assertSystemLocales("LOL");
+    }
+
+
+    @Test
+    public void testCreateUser_ok_ephemeralGuest() throws Exception {
+        UserInfo newGuest = expectCreateGuestUser(USER_ID, "TheDude", UserInfo.FLAG_EPHEMERAL);
+        expectSwitchUser(USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_CREATE)
+                .setNewUserName("TheDude")
+                .setNewUserFlags(UserFlags.EPHEMERAL | UserFlags.GUEST)
+                .build());
+
+        verifyUserSwitched(USER_ID);
+        verifyFallbackDefaultBehaviorNeverCalled();
+        verifySystemUserUnlocked();
+        assertInitialUserSet(newGuest);
+    }
+
+    @Test
+    public void testCreateUser_fail_systemUser() throws Exception {
+        // No need to set mUm.createUser() expectation - it shouldn't be called
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_CREATE)
+                .setNewUserName("TheDude")
+                .setNewUserFlags(UserFlags.SYSTEM)
+                .build());
+
+        verifyUserNeverSwitched();
+        verifyFallbackDefaultBehaviorCalledFromCreateOrSwitch();
+        verifySystemUserNeverUnlocked();
+    }
+
+    @Test
+    public void testCreateUser_fail_guestAdmin() throws Exception {
+        // No need to set mUm.createUser() expectation - it shouldn't be called
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_CREATE)
+                .setNewUserName("TheDude")
+                .setNewUserFlags(UserFlags.GUEST | UserFlags.ADMIN)
+                .build());
+
+        verifyUserNeverSwitched();
+        verifyFallbackDefaultBehaviorCalledFromCreateOrSwitch();
+    }
+
+    @Test
+    public void testCreateUser_fail_ephemeralAdmin() throws Exception {
+        // No need to set mUm.createUser() expectation - it shouldn't be called
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_CREATE)
+                .setNewUserName("TheDude")
+                .setNewUserFlags(UserFlags.EPHEMERAL | UserFlags.ADMIN)
+                .build());
+
+        verifyUserNeverSwitched();
+        verifyFallbackDefaultBehaviorCalledFromCreateOrSwitch();
+    }
+
+    @Test
+    public void testCreateUser_fail_createFail() throws Exception {
+        // No need to set mUm.createUser() expectation - it will return false by default
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_CREATE)
+                .setNewUserName("TheDude")
+                .setNewUserFlags(UserFlags.NONE)
+                .build());
+
+        verifyUserNeverSwitched();
+        verifyFallbackDefaultBehaviorCalledFromCreateOrSwitch();
+    }
+
+    @Test
+    public void testCreateUser_fail_createThrowsException() throws Exception {
+        expectCreateUserThrowsException("TheDude", UserFlags.NONE);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_CREATE)
+                .setNewUserName("TheDude")
+                .setNewUserFlags(UserFlags.NONE)
+                .build());
+
+        verifyUserNeverSwitched();
+        verifyFallbackDefaultBehaviorCalledFromCreateOrSwitch();
+    }
+
+    @Test
+    public void testCreateUser_fail_switchFail() throws Exception {
+        expectCreateFullUser(USER_ID, "TheDude", NO_FLAGS);
+        expectSwitchUserFails(USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_CREATE)
+                .setNewUserName("TheDude")
+                .setNewUserFlags(UserFlags.NONE)
+                .build());
+
+        verifyFallbackDefaultBehaviorCalledFromCreateOrSwitch();
+        verifySystemUserUnlocked();
+        verifyLastActiveUserNeverSet();
+    }
+
+    @Test
+    public void testDefaultBehavior_firstBoot_ok() throws Exception {
+        // no need to mock hasInitialUser(), it will return false by default
+        UserInfo newUser = expectCreateFullUser(USER_ID, OWNER_NAME, UserInfo.FLAG_ADMIN);
+        expectSwitchUser(USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_DEFAULT_BEHAVIOR).build());
+
+        verifyUserSwitched(USER_ID);
+        verifyFallbackDefaultBehaviorNeverCalled();
+        verifySystemUserUnlocked();
+        assertInitialUserSet(newUser);
+    }
+
+    @Test
+    public void testDefaultBehavior_firstBoot_ok_setLocale() throws Exception {
+        // no need to mock hasInitialUser(), it will return false by default
+        UserInfo newUser = expectCreateFullUser(USER_ID, OWNER_NAME, UserInfo.FLAG_ADMIN);
+        expectSwitchUser(USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_DEFAULT_BEHAVIOR)
+                .setUserLocales("LOL")
+                .build());
+
+        verifyUserSwitched(USER_ID);
+        verifyFallbackDefaultBehaviorNeverCalled();
+        verifySystemUserUnlocked();
+        assertInitialUserSet(newUser);
+        assertSystemLocales("LOL");
+    }
+
+    @Test
+    public void testDefaultBehavior_firstBoot_fail_createUserFailed() throws Exception {
+        // no need to mock hasInitialUser(), it will return false by default
+        // no need to mock createUser(), it will return null by default
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_DEFAULT_BEHAVIOR).build());
+
+        verifyUserNeverSwitched();
+        verifyFallbackDefaultBehaviorCalledFromDefaultBehavior();
+        verifySystemUserNeverUnlocked();
+    }
+
+    @Test
+    public void testDefaultBehavior_firstBoot_fail_switchFailed() throws Exception {
+        // no need to mock hasInitialUser(), it will return false by default
+        expectCreateFullUser(USER_ID, OWNER_NAME, UserInfo.FLAG_ADMIN);
+        expectSwitchUserFails(USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_DEFAULT_BEHAVIOR).build());
+
+        verifyFallbackDefaultBehaviorCalledFromDefaultBehavior();
+        verifySystemUserUnlocked();
+        verifyLastActiveUserNeverSet();
+    }
+
+    @Test
+    public void testDefaultBehavior_firstBoot_fail_switchFailed_setLocale() throws Exception {
+        // no need to mock hasInitialUser(), it will return false by default
+        expectCreateFullUser(USER_ID, OWNER_NAME, UserInfo.FLAG_ADMIN);
+        expectSwitchUserFails(USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_DEFAULT_BEHAVIOR)
+                .setUserLocales("LOL")
+                .build());
+
+        verifyFallbackDefaultBehaviorCalledFromDefaultBehavior();
+        verifySystemUserUnlocked();
+        verifyLastActiveUserNeverSet();
+        assertSystemLocales("LOL");
+    }
+
+    @Test
+    public void testDefaultBehavior_nonFirstBoot_ok() throws Exception {
+        UserInfo existingUser = expectHasInitialUser(USER_ID);
+        expectSwitchUser(USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_DEFAULT_BEHAVIOR).build());
+
+        verifyUserSwitched(USER_ID);
+        verifyFallbackDefaultBehaviorNeverCalled();
+        verifyUserNeverCreated();
+        verifySystemUserUnlocked();
+        assertInitialUserSet(existingUser);
+    }
+
+    @Test
+    public void testDefaultBehavior_nonFirstBoot_ok_targetIsCurrentUser() throws Exception {
+        UserInfo currentUser = expectHasInitialUser(CURRENT_USER_ID);
+        expectSwitchUser(CURRENT_USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_DEFAULT_BEHAVIOR).build());
+
+        verifyUserNeverSwitched();
+        verifyFallbackDefaultBehaviorNeverCalled();
+        verifyUserNeverCreated();
+        verifySystemUserUnlocked();
+        assertInitialUserSet(currentUser);
+    }
+
+    @Test
+    public void testDefaultBehavior_nonFirstBoot_fail_switchFail() throws Exception {
+        expectHasInitialUser(USER_ID);
+        expectSwitchUserFails(USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_DEFAULT_BEHAVIOR).build());
+
+        verifyFallbackDefaultBehaviorCalledFromDefaultBehavior();
+        verifyUserNeverCreated();
+        verifySystemUserUnlocked();
+        verifyLastActiveUserNeverSet();
+    }
+
+    @Test
+    public void testDefaultBehavior_nonFirstBoot_ok_guestReplaced() throws Exception {
+        boolean ephemeral = true; // ephemeral doesn't really matter in this test
+        expectHasInitialUser(USER_ID);
+        expectGuestExists(USER_ID, ephemeral);
+        UserInfo newGuest = newGuestUser(NEW_USER_ID, ephemeral);
+        expectGuestReplaced(USER_ID, newGuest);
+        expectSwitchUser(NEW_USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_DEFAULT_BEHAVIOR)
+                .setReplaceGuest(true)
+                .build());
+
+        verifyUserSwitched(NEW_USER_ID);
+        verifyFallbackDefaultBehaviorNeverCalled();
+        verifyUserNeverCreated();
+        verifySystemUserUnlocked();
+        verifyUserDeleted(USER_ID);
+        assertInitialUserSet(newGuest);
+    }
+
+    @Test
+    public void testDefaultBehavior_nonFirstBoot_fail_guestReplacementFailed() throws Exception {
+        expectHasInitialUser(USER_ID);
+        expectGuestExists(USER_ID, /* isEphemeral= */ true); // ephemeral doesn't matter
+        expectGuestReplaced(USER_ID, /* newGuest= */ null);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_DEFAULT_BEHAVIOR)
+                .setReplaceGuest(true)
+                .build());
+
+        verifyUserNeverSwitched();
+        verifyFallbackDefaultBehaviorCalledFromDefaultBehavior();
+        verifyUserNeverCreated();
+        verifySystemUserNeverUnlocked();
+    }
+
+    @Test
+    public void testDefaultBehavior_nonFirstBoot_ok_withOverriddenProperty() throws Exception {
+        boolean supportsOverrideUserIdProperty = true;
+        UserInfo user = expectHasInitialUser(USER_ID, supportsOverrideUserIdProperty);
+        expectSwitchUser(USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_DEFAULT_BEHAVIOR)
+                .setSupportsOverrideUserIdProperty(true)
+                .build());
+
+        verifyUserSwitched(USER_ID);
+        verifyFallbackDefaultBehaviorNeverCalled(supportsOverrideUserIdProperty);
+        verifyUserNeverCreated();
+        verifySystemUserUnlocked();
+        assertInitialUserSet(user);
+    }
+
+    @Test
+    public void testDefaultBehavior_nonFirstBoot_ok_guestDoesNotNeedToBeReplaced()
+            throws Exception {
+        boolean ephemeral = true; // ephemeral doesn't really matter in this test
+        UserInfo existingGuest = expectHasInitialGuest(USER_ID);
+        expectSwitchUser(USER_ID);
+
+        mSetter.set(new Builder(InitialUserSetter.TYPE_DEFAULT_BEHAVIOR)
+                .setReplaceGuest(false)
+                .build());
+
+        verifyUserSwitched(USER_ID);
+        verifyGuestNeverMarkedForDeletion();
+        verifyFallbackDefaultBehaviorNeverCalled();
+        verifyUserNeverCreated();
+        verifySystemUserUnlocked();
+        assertInitialUserSet(existingGuest);
+    }
+
+    @Test
+    public void testUnlockSystemUser_startedOk() throws Exception {
+        when(mIActivityManager.startUserInBackground(UserHandle.USER_SYSTEM)).thenReturn(true);
+
+        mSetter.unlockSystemUser();
+
+        verify(mIActivityManager, never()).unlockUser(UserHandle.USER_SYSTEM, /* token= */ null,
+                /* secret= */ null, /* listener= */ null);
+    }
+
+    @Test
+    public void testUnlockSystemUser_startFailUnlockedInstead() throws Exception {
+        // No need to set startUserInBackground() expectation as it will return false by default
+
+        mSetter.unlockSystemUser();
+
+        verify(mIActivityManager).unlockUser(UserHandle.USER_SYSTEM, /* token= */ null,
+                /* secret= */ null, /* listener= */ null);
+    }
+
+    @Test
+    public void testStartForegroundUser_ok() throws Exception {
+        expectAmStartFgUser(10);
+
+        assertThat(mSetter.startForegroundUser(10)).isTrue();
+    }
+
+    @Test
+    public void testStartForegroundUser_fail() {
+        // startUserInForegroundWithListener will return false by default
+
+        assertThat(mSetter.startForegroundUser(10)).isFalse();
+    }
+
+    @Test
+    public void testStartForegroundUser_remoteException() throws Exception {
+        expectAmStartFgUserThrowsException(10);
+
+        assertThat(mSetter.startForegroundUser(10)).isFalse();
+    }
+
+    @Test
+    public void testStartForegroundUser_nonHeadlessSystemUser() throws Exception {
+        mockIsHeadlessSystemUserMode(false);
+        expectAmStartFgUser(UserHandle.USER_SYSTEM);
+
+        assertThat(mSetter.startForegroundUser(UserHandle.USER_SYSTEM)).isTrue();
+    }
+
+    @Test
+    public void testStartForegroundUser_headlessSystemUser() throws Exception {
+        mockIsHeadlessSystemUserMode(true);
+
+        assertThat(mSetter.startForegroundUser(UserHandle.USER_SYSTEM)).isFalse();
+
+        verify(mIActivityManager, never()).startUserInForegroundWithListener(UserHandle.USER_SYSTEM,
+                null);
+    }
+
+    private UserInfo expectHasInitialUser(@UserIdInt int userId) {
+        return expectHasInitialUser(userId, /* supportsOverrideUserIdProperty= */ false);
+    }
+
+    private UserInfo expectHasInitialUser(@UserIdInt int userId,
+            boolean supportsOverrideUserIdProperty) {
+        return expectHasInitialUser(userId, /* isGuest= */ false, supportsOverrideUserIdProperty);
+    }
+
+    private UserInfo expectHasInitialGuest(int userId) {
+        return expectHasInitialUser(userId, /* isGuest= */ true,
+                /* supportsOverrideUserIdProperty= */ false);
+    }
+    private UserInfo expectHasInitialUser(@UserIdInt int userId, boolean isGuest,
+            boolean supportsOverrideUserIdProperty) {
+        when(mHelper.hasInitialUser()).thenReturn(true);
+        when(mHelper.getInitialUser(supportsOverrideUserIdProperty)).thenReturn(userId);
+        return isGuest ? expectGuestExists(userId, /* isEphemeral= */ true)
+                : expectUserExists(userId);
+    }
+
+    private UserInfo expectUserExists(@UserIdInt int userId) {
+        UserInfo user = new UserInfo();
+        user.id = userId;
+        when(mUm.getUserInfo(userId)).thenReturn(user);
+        return user;
+    }
+
+    private void expectUserIsSecure(@UserIdInt int userId) {
+        when(mLockPatternUtils.isSecure(userId)).thenReturn(true);
+    }
+
+    private UserInfo expectGuestExists(@UserIdInt int userId, boolean isEphemeral) {
+        UserInfo user = new UserInfo();
+        user.id = userId;
+        user.userType = UserManager.USER_TYPE_FULL_GUEST;
+        if (isEphemeral) {
+            user.flags = UserInfo.FLAG_EPHEMERAL;
+        }
+        when(mUm.getUserInfo(userId)).thenReturn(user);
+        return user;
+    }
+
+    private void expectGuestReplaced(int existingGuestId, UserInfo newGuest) {
+        doReturn(newGuest).when(mSetter).replaceGuestIfNeeded(isUserInfo(existingGuestId));
+    }
+
+    private void expectSwitchUser(@UserIdInt int userId) throws Exception {
+        doReturn(true).when(mSetter).startForegroundUser(userId);
+    }
+    private void expectSwitchUserFails(@UserIdInt int userId) {
+        when(mSetter.startForegroundUser(userId)).thenReturn(false);
+    }
+
+    private void expectSwitchUserThrowsException(@UserIdInt int userId) {
+        when(mSetter.startForegroundUser(userId))
+                .thenThrow(new RuntimeException("D'OH! Cannot switch to " + userId));
+    }
+
+    private UserInfo expectCreateFullUser(@UserIdInt int userId, @Nullable String name,
+            @UserInfoFlag int flags) {
+        return expectCreateUserOfType(UserManager.USER_TYPE_FULL_SECONDARY, userId, name, flags);
+    }
+
+    private UserInfo expectCreateGuestUser(@UserIdInt int userId, @Nullable String name,
+            @UserInfoFlag int flags) {
+        return expectCreateUserOfType(UserManager.USER_TYPE_FULL_GUEST, userId, name, flags);
+    }
+
+    private UserInfo expectCreateUserOfType(@NonNull String type, @UserIdInt int userId,
+            @Nullable String name, @UserInfoFlag int flags) {
+        UserInfo userInfo = new UserInfo(userId, name, flags);
+        when(mUm.createUser(name, type, flags)).thenReturn(userInfo);
+        // Once user is created, it should exist...
+        when(mUm.getUserInfo(userId)).thenReturn(userInfo);
+        return userInfo;
+    }
+
+    private void expectCreateUserThrowsException(@NonNull String name, @UserIdInt int userId) {
+        when(mUm.createUser(eq(name), anyString(), eq(userId)))
+                .thenThrow(new RuntimeException("Cannot create user. D'OH!"));
+    }
+
+    private void expectAmStartFgUser(@UserIdInt int userId) throws Exception {
+        when(mIActivityManager.startUserInForegroundWithListener(userId, null)).thenReturn(true);
+    }
+
+    private void expectAmStartFgUserThrowsException(@UserIdInt int userId) throws Exception {
+        when(mIActivityManager.startUserInForegroundWithListener(userId, null))
+                .thenThrow(new RemoteException("D'OH! Cannot switch to " + userId));
+    }
+
+    private void verifyUserSwitched(@UserIdInt int userId) throws Exception {
+        verify(mSetter).startForegroundUser(userId);
+        verify(mHelper).setLastActiveUser(userId);
+    }
+
+    private void verifyUserNeverSwitched() throws Exception {
+        verify(mSetter, never()).startForegroundUser(anyInt());
+        verifyLastActiveUserNeverSet();
+    }
+
+    private void verifyUserNeverCreated() {
+        verify(mUm, never()).createUser(anyString(), anyString(), anyInt());
+    }
+
+    private void verifyGuestMarkedForDeletion(@UserIdInt int userId) {
+        verify(mUm).markGuestForDeletion(userId);
+    }
+
+    private void verifyGuestNeverMarkedForDeletion() {
+        verify(mUm, never()).markGuestForDeletion(anyInt());
+    }
+
+    private void verifyUserDeleted(@UserIdInt int userId) {
+        verify(mUm).removeUser(userId);
+    }
+
+    private void verifyFallbackDefaultBehaviorCalledFromCreateOrSwitch() {
+        verify(mSetter).fallbackDefaultBehavior(isInitialInfo(false), eq(true), anyString());
+        assertInitialUserSet(null);
+    }
+
+    private void verifyFallbackDefaultBehaviorCalledFromDefaultBehavior() {
+        verify(mSetter).fallbackDefaultBehavior(isInitialInfo(false), eq(false), anyString());
+        assertInitialUserSet(null);
+    }
+
+    private void verifyFallbackDefaultBehaviorNeverCalled() {
+        verifyFallbackDefaultBehaviorNeverCalled(/* supportsOverrideUserIdProperty= */ false);
+    }
+
+    private void verifyFallbackDefaultBehaviorNeverCalled(boolean supportsOverrideUserIdProperty) {
+        verify(mSetter, never()).fallbackDefaultBehavior(
+                isInitialInfo(supportsOverrideUserIdProperty), anyBoolean(), anyString());
+    }
+
+    private static InitialUserInfo isInitialInfo(boolean supportsOverrideUserIdProperty) {
+        return argThat((info) -> {
+            return info.supportsOverrideUserIdProperty == supportsOverrideUserIdProperty;
+        });
+    }
+
+    private void verifySystemUserUnlocked() {
+        verify(mSetter).unlockSystemUser();
+    }
+
+    private void verifySystemUserNeverUnlocked() {
+        verify(mSetter, never()).unlockSystemUser();
+    }
+
+    private void verifyLastActiveUserNeverSet() {
+        verify(mHelper, never()).setLastActiveUser(anyInt());
+    }
+
+    private void assertInitialUserSet(@NonNull UserInfo expectedUser) {
+        assertWithMessage("listener called wrong number of times").that(mListener.numberCalls)
+            .isEqualTo(1);
+        assertWithMessage("wrong initial user set on listener").that(mListener.initialUser)
+            .isSameAs(expectedUser);
+    }
+
+    private void assertSystemLocales(@NonNull String expected) {
+        // TODO(b/156033195): should test specific userId
+        assertThat(getSettingsString(Settings.System.SYSTEM_LOCALES)).isEqualTo(expected);
+    }
+
+    private final class MyListener implements Consumer<UserInfo> {
+        public int numberCalls;
+        public UserInfo initialUser;
+
+        @Override
+        public void accept(UserInfo initialUser) {
+            this.initialUser = initialUser;
+            numberCalls++;
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/android/car/userlib/OWNERS b/tests/carservice_unit_test/src/android/car/userlib/OWNERS
new file mode 100644
index 0000000..6c61804
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/userlib/OWNERS
@@ -0,0 +1,7 @@
+# Library owners
+ahugh@google.com
+jovanak@google.com
+yizheng@google.com
+felipeal@google.com
+keunyoung@google.com
+
diff --git a/tests/carservice_unit_test/src/android/car/userlib/UserHalHelperTest.java b/tests/carservice_unit_test/src/android/car/userlib/UserHalHelperTest.java
new file mode 100644
index 0000000..7bb7f9d
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/userlib/UserHalHelperTest.java
@@ -0,0 +1,1347 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.userlib;
+
+import static android.car.userlib.UserHalHelper.CREATE_USER_PROPERTY;
+import static android.car.userlib.UserHalHelper.REMOVE_USER_PROPERTY;
+import static android.car.userlib.UserHalHelper.SWITCH_USER_PROPERTY;
+import static android.car.userlib.UserHalHelper.USER_IDENTIFICATION_ASSOCIATION_PROPERTY;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue.ASSOCIATE_CURRENT_USER;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue.DISASSOCIATE_ALL_USERS;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue.DISASSOCIATE_CURRENT_USER;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.CUSTOM_1;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.CUSTOM_2;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.CUSTOM_3;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.CUSTOM_4;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.KEY_FOB;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationValue.ASSOCIATED_ANOTHER_USER;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationValue.ASSOCIATED_CURRENT_USER;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationValue.NOT_ASSOCIATED_ANY_USER;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationValue.UNKNOWN;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.annotation.NonNull;
+import android.app.ActivityManager;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase.CustomMockitoSessionBuilder;
+import android.car.test.mocks.AndroidMockitoHelper;
+import android.car.test.util.UserTestingHelper.UserInfoBuilder;
+import android.content.pm.UserInfo;
+import android.hardware.automotive.vehicle.V2_0.CreateUserRequest;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
+import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
+import android.hardware.automotive.vehicle.V2_0.SwitchUserMessageType;
+import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
+import android.hardware.automotive.vehicle.V2_0.UserFlags;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociation;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationValue;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetAssociation;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
+import android.hardware.automotive.vehicle.V2_0.UsersInfo;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import com.google.common.collect.Range;
+
+import org.junit.Test;
+import org.mockito.Mock;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class UserHalHelperTest extends AbstractExtendedMockitoTestCase {
+
+    @Mock
+    private UserManager mUm;
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+        session.spyStatic(ActivityManager.class);
+    }
+
+    @Test
+    public void testHalCallbackStatusToString() {
+        assertThat(UserHalHelper.halCallbackStatusToString(-666)).isNotNull();
+    }
+
+    @Test
+    public void testParseInitialUserInfoRequestType_valid() {
+        assertThat(UserHalHelper.parseInitialUserInfoRequestType("FIRST_BOOT"))
+                .isEqualTo(InitialUserInfoRequestType.FIRST_BOOT);
+        assertThat(UserHalHelper.parseInitialUserInfoRequestType("COLD_BOOT"))
+            .isEqualTo(InitialUserInfoRequestType.COLD_BOOT);
+        assertThat(UserHalHelper.parseInitialUserInfoRequestType("FIRST_BOOT_AFTER_OTA"))
+            .isEqualTo(InitialUserInfoRequestType.FIRST_BOOT_AFTER_OTA);
+        assertThat(UserHalHelper.parseInitialUserInfoRequestType("RESUME"))
+            .isEqualTo(InitialUserInfoRequestType.RESUME);
+    }
+
+    @Test
+    public void testParseInitialUserInfoRequestType_unknown() {
+        assertThat(UserHalHelper.parseInitialUserInfoRequestType("666")).isEqualTo(666);
+    }
+
+    @Test
+    public void testParseInitialUserInfoRequestType_invalid() {
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.parseInitialUserInfoRequestType("NumberNotIAm"));
+    }
+
+    @Test
+    public void testConvertFlags_nullUser() {
+        assertThrows(IllegalArgumentException.class, () -> UserHalHelper.convertFlags(null));
+    }
+
+    @Test
+    public void testConvertFlags() {
+        UserInfo user = new UserInfo();
+
+        user.id = UserHandle.USER_SYSTEM;
+        assertConvertFlags(UserFlags.SYSTEM, user);
+
+        user.id = 10;
+        assertConvertFlags(UserFlags.NONE, user);
+
+        user.flags = UserInfo.FLAG_ADMIN;
+        assertThat(user.isAdmin()).isTrue(); // sanity check
+        assertConvertFlags(UserFlags.ADMIN, user);
+
+        user.flags = UserInfo.FLAG_EPHEMERAL;
+        assertThat(user.isEphemeral()).isTrue(); // sanity check
+        assertConvertFlags(UserFlags.EPHEMERAL, user);
+
+        user.userType = UserManager.USER_TYPE_FULL_GUEST;
+        assertThat(user.isEphemeral()).isTrue(); // sanity check
+        assertThat(user.isGuest()).isTrue(); // sanity check
+        assertConvertFlags(UserFlags.GUEST | UserFlags.EPHEMERAL, user);
+    }
+
+    @Test
+    public void testGetFlags_nullUserManager() {
+        assertThrows(IllegalArgumentException.class, () -> UserHalHelper.getFlags(null, 10));
+    }
+
+    @Test
+    public void testGetFlags_noUser() {
+        // No need to set anythin as mUm call will return null
+        assertThrows(IllegalArgumentException.class, () -> UserHalHelper.getFlags(mUm, 10));
+    }
+
+    @Test
+    public void testGetFlags_ok() {
+        UserInfo user = new UserInfo();
+
+        user.id = UserHandle.USER_SYSTEM;
+        assertGetFlags(UserFlags.SYSTEM, user);
+
+        user.id = 10;
+        assertGetFlags(UserFlags.NONE, user);
+
+        user.flags = UserInfo.FLAG_ADMIN;
+        assertThat(user.isAdmin()).isTrue(); // sanity check
+        assertGetFlags(UserFlags.ADMIN, user);
+
+        user.flags = UserInfo.FLAG_EPHEMERAL;
+        assertThat(user.isEphemeral()).isTrue(); // sanity check
+        assertGetFlags(UserFlags.EPHEMERAL, user);
+
+        user.userType = UserManager.USER_TYPE_FULL_GUEST;
+        assertThat(user.isEphemeral()).isTrue(); // sanity check
+        assertThat(user.isGuest()).isTrue(); // sanity check
+        assertGetFlags(UserFlags.GUEST | UserFlags.EPHEMERAL, user);
+    }
+
+    @Test
+    public void testIsSystem() {
+        assertThat(UserHalHelper.isSystem(UserFlags.SYSTEM)).isTrue();
+        assertThat(UserHalHelper.isSystem(UserFlags.SYSTEM | 666)).isTrue();
+        assertThat(UserHalHelper.isSystem(UserFlags.GUEST)).isFalse();
+    }
+
+    @Test
+    public void testIsGuest() {
+        assertThat(UserHalHelper.isGuest(UserFlags.GUEST)).isTrue();
+        assertThat(UserHalHelper.isGuest(UserFlags.GUEST | 666)).isTrue();
+        assertThat(UserHalHelper.isGuest(UserFlags.SYSTEM)).isFalse();
+    }
+
+    @Test
+    public void testIsEphemeral() {
+        assertThat(UserHalHelper.isEphemeral(UserFlags.EPHEMERAL)).isTrue();
+        assertThat(UserHalHelper.isEphemeral(UserFlags.EPHEMERAL | 666)).isTrue();
+        assertThat(UserHalHelper.isEphemeral(UserFlags.GUEST)).isFalse();
+    }
+
+    @Test
+    public void testIsAdmin() {
+        assertThat(UserHalHelper.isAdmin(UserFlags.ADMIN)).isTrue();
+        assertThat(UserHalHelper.isAdmin(UserFlags.ADMIN | 666)).isTrue();
+        assertThat(UserHalHelper.isAdmin(UserFlags.GUEST)).isFalse();
+    }
+
+    @Test
+    public void testIsDisabled() {
+        assertThat(UserHalHelper.isDisabled(UserFlags.DISABLED)).isTrue();
+        assertThat(UserHalHelper.isDisabled(UserFlags.DISABLED | 666)).isTrue();
+        assertThat(UserHalHelper.isDisabled(UserFlags.GUEST)).isFalse();
+    }
+
+    @Test
+    public void testIsProfile() {
+        assertThat(UserHalHelper.isProfile(UserFlags.PROFILE)).isTrue();
+        assertThat(UserHalHelper.isProfile(UserFlags.PROFILE | 666)).isTrue();
+        assertThat(UserHalHelper.isProfile(UserFlags.GUEST)).isFalse();
+    }
+
+    @Test
+    public void testToUserInfoFlags() {
+        assertThat(UserHalHelper.toUserInfoFlags(UserFlags.NONE)).isEqualTo(0);
+        assertThat(UserHalHelper.toUserInfoFlags(UserFlags.EPHEMERAL))
+                .isEqualTo(UserInfo.FLAG_EPHEMERAL);
+        assertThat(UserHalHelper.toUserInfoFlags(UserFlags.ADMIN))
+                .isEqualTo(UserInfo.FLAG_ADMIN);
+        assertThat(UserHalHelper.toUserInfoFlags(UserFlags.EPHEMERAL | UserFlags.ADMIN))
+                .isEqualTo(UserInfo.FLAG_EPHEMERAL | UserInfo.FLAG_ADMIN);
+
+        // test flags that should be ignored
+        assertThat(UserHalHelper.toUserInfoFlags(UserFlags.SYSTEM)).isEqualTo(0);
+        assertThat(UserHalHelper.toUserInfoFlags(UserFlags.GUEST)).isEqualTo(0);
+        assertThat(UserHalHelper.toUserInfoFlags(1024)).isEqualTo(0);
+    }
+
+    private void assertConvertFlags(int expectedFlags, @NonNull UserInfo user) {
+        assertWithMessage("flags mismatch: user=%s, flags=%s",
+                user.toFullString(), UserHalHelper.userFlagsToString(expectedFlags))
+                        .that(UserHalHelper.convertFlags(user)).isEqualTo(expectedFlags);
+    }
+
+    private void assertGetFlags(int expectedFlags, @NonNull UserInfo user) {
+        when(mUm.getUserInfo(user.id)).thenReturn(user);
+        assertWithMessage("flags mismatch: user=%s, flags=%s",
+                user.toFullString(), UserHalHelper.userFlagsToString(expectedFlags))
+                        .that(UserHalHelper.getFlags(mUm, user.id)).isEqualTo(expectedFlags);
+    }
+
+    @Test
+    public void testUserFlagsToString() {
+        assertThat(UserHalHelper.userFlagsToString(-666)).isNotNull();
+    }
+
+    @Test
+    public void testCreatePropRequest_withType() {
+        int prop = 1;
+        int requestId = 2;
+        int requestType = 3;
+        long before = SystemClock.elapsedRealtime();
+        VehiclePropValue propRequest = UserHalHelper.createPropRequest(prop, requestId,
+                requestType);
+        long after = SystemClock.elapsedRealtime();
+
+        assertThat(propRequest.value.int32Values)
+                .containsExactly(requestId, requestType)
+                .inOrder();
+        assertThat(propRequest.prop).isEqualTo(prop);
+        assertThat(propRequest.timestamp).isIn(Range.closed(before, after));
+    }
+
+    @Test
+    public void testCreatePropRequest() {
+        int prop = 1;
+        int requestId = 2;
+        long before = SystemClock.elapsedRealtime();
+        VehiclePropValue propRequest = UserHalHelper.createPropRequest(prop, requestId);
+        long after = SystemClock.elapsedRealtime();
+
+        assertThat(propRequest.value.int32Values)
+                .containsExactly(requestId)
+                .inOrder();
+        assertThat(propRequest.prop).isEqualTo(prop);
+        assertThat(propRequest.timestamp).isIn(Range.closed(before, after));
+    }
+
+    @Test
+    public void testAddUsersInfo_nullProp() {
+        UsersInfo infos = new UsersInfo();
+
+        assertThrows(NullPointerException.class, () -> UserHalHelper.addUsersInfo(null, infos));
+    }
+
+    @Test
+    public void testAddUsersInfo_nullCurrentUser() {
+        VehiclePropValue propRequest = new VehiclePropValue();
+
+        UsersInfo infos = new UsersInfo();
+        infos.currentUser = null;
+        assertThrows(NullPointerException.class, () ->
+                UserHalHelper.addUsersInfo(propRequest, infos));
+    }
+
+    @Test
+    public void testAddUsersInfo_mismatchNumberUsers() {
+        VehiclePropValue propRequest = new VehiclePropValue();
+
+        UsersInfo infos = new UsersInfo();
+        infos.currentUser.userId = 42;
+        infos.currentUser.flags = 1;
+        infos.numberUsers = 1;
+        assertThat(infos.existingUsers).isEmpty();
+        assertThrows(IllegalArgumentException.class, () ->
+                UserHalHelper.addUsersInfo(propRequest, infos));
+    }
+
+    @Test
+    public void testAddUsersInfo_success() {
+        VehiclePropValue propRequest = new VehiclePropValue();
+        propRequest.value.int32Values.add(99);
+
+        UsersInfo infos = new UsersInfo();
+        infos.currentUser.userId = 42;
+        infos.currentUser.flags = 1;
+        infos.numberUsers = 1;
+
+        android.hardware.automotive.vehicle.V2_0.UserInfo userInfo =
+                new android.hardware.automotive.vehicle.V2_0.UserInfo();
+        userInfo.userId = 43;
+        userInfo.flags = 1;
+        infos.existingUsers.add(userInfo);
+        UserHalHelper.addUsersInfo(propRequest, infos);
+
+        assertThat(propRequest.value.int32Values)
+                .containsExactly(99, 42, 1, 1, 43, 1)
+                .inOrder();
+    }
+
+    @Test
+    public void testAddUserInfo_nullProp() {
+        android.hardware.automotive.vehicle.V2_0.UserInfo userInfo =
+                new android.hardware.automotive.vehicle.V2_0.UserInfo();
+
+        assertThrows(NullPointerException.class, () -> UserHalHelper.addUserInfo(null, userInfo));
+    }
+
+    @Test
+    public void testAddUserInfo_nullCurrentUser() {
+        VehiclePropValue prop = new VehiclePropValue();
+
+        assertThrows(NullPointerException.class, () -> UserHalHelper.addUserInfo(prop, null));
+    }
+
+    @Test
+    public void testAddUserInfo_success() {
+        VehiclePropValue propRequest = new VehiclePropValue();
+        propRequest.value.int32Values.add(99);
+
+        android.hardware.automotive.vehicle.V2_0.UserInfo userInfo =
+                new android.hardware.automotive.vehicle.V2_0.UserInfo();
+        userInfo.userId = 42;
+        userInfo.flags = 1;
+
+        UserHalHelper.addUserInfo(propRequest, userInfo);
+
+        assertThat(propRequest.value.int32Values)
+                .containsExactly(99, 42, 1)
+                .inOrder();
+    }
+
+    @Test
+    public void testIsValidUserIdentificationAssociationType_valid() {
+        assertThat(UserHalHelper.isValidUserIdentificationAssociationType(KEY_FOB)).isTrue();
+        assertThat(UserHalHelper.isValidUserIdentificationAssociationType(CUSTOM_1)).isTrue();
+        assertThat(UserHalHelper.isValidUserIdentificationAssociationType(CUSTOM_2)).isTrue();
+        assertThat(UserHalHelper.isValidUserIdentificationAssociationType(CUSTOM_3)).isTrue();
+        assertThat(UserHalHelper.isValidUserIdentificationAssociationType(CUSTOM_4)).isTrue();
+    }
+
+    @Test
+    public void testIsValidUserIdentificationAssociationType_invalid() {
+        assertThat(UserHalHelper.isValidUserIdentificationAssociationType(CUSTOM_4 + 1)).isFalse();
+    }
+
+    @Test
+    public void testIsValidUserIdentificationAssociationValue_valid() {
+        assertThat(UserHalHelper.isValidUserIdentificationAssociationValue(ASSOCIATED_ANOTHER_USER))
+                .isTrue();
+        assertThat(UserHalHelper.isValidUserIdentificationAssociationValue(ASSOCIATED_CURRENT_USER))
+                .isTrue();
+        assertThat(UserHalHelper.isValidUserIdentificationAssociationValue(NOT_ASSOCIATED_ANY_USER))
+                .isTrue();
+        assertThat(UserHalHelper.isValidUserIdentificationAssociationValue(UNKNOWN)).isTrue();
+    }
+
+    @Test
+    public void testIsValidUserIdentificationAssociationValue_invalid() {
+        assertThat(UserHalHelper.isValidUserIdentificationAssociationValue(0)).isFalse();
+    }
+
+    @Test
+    public void testIsValidUserIdentificationAssociationSetValue_valid() {
+        assertThat(UserHalHelper
+                .isValidUserIdentificationAssociationSetValue(ASSOCIATE_CURRENT_USER)).isTrue();
+        assertThat(UserHalHelper
+                .isValidUserIdentificationAssociationSetValue(DISASSOCIATE_CURRENT_USER)).isTrue();
+        assertThat(UserHalHelper
+                .isValidUserIdentificationAssociationSetValue(DISASSOCIATE_ALL_USERS)).isTrue();
+    }
+
+    @Test
+    public void testIsValidUserIdentificationAssociationSetValue_invalid() {
+        assertThat(UserHalHelper.isValidUserIdentificationAssociationSetValue(0)).isFalse();
+    }
+
+    @Test
+    public void testUserIdentificationGetRequestToVehiclePropValue_null() {
+        assertThrows(NullPointerException.class,
+                () -> UserHalHelper.toVehiclePropValue((UserIdentificationGetRequest) null));
+    }
+
+    @Test
+    public void testUserIdentificationGetRequestToVehiclePropValue_emptyRequest() {
+        UserIdentificationGetRequest request = new UserIdentificationGetRequest();
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toVehiclePropValue(request));
+    }
+
+    @Test
+    public void testUserIdentificationGetRequestToVehiclePropValue_wrongNumberOfAssociations() {
+        UserIdentificationGetRequest request = new UserIdentificationGetRequest();
+        request.numberAssociationTypes = 1;
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toVehiclePropValue(request));
+    }
+
+    @Test
+    public void testUserIdentificationGetRequestToVehiclePropValue_invalidType() {
+        UserIdentificationGetRequest request = new UserIdentificationGetRequest();
+        request.numberAssociationTypes = 1;
+        request.associationTypes.add(CUSTOM_4 + 1);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toVehiclePropValue(request));
+    }
+
+    @Test
+    public void testUserIdentificationGetRequestToVehiclePropValue_missingRequestId() {
+        UserIdentificationGetRequest request = new UserIdentificationGetRequest();
+        request.userInfo.userId = 42;
+        request.userInfo.flags = 108;
+        request.numberAssociationTypes = 1;
+        request.associationTypes.add(KEY_FOB);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toVehiclePropValue(request));
+    }
+
+    @Test
+    public void testUserIdentificationGetRequestToVehiclePropValue_ok() {
+        UserIdentificationGetRequest request = new UserIdentificationGetRequest();
+        request.requestId = 1;
+        request.userInfo.userId = 42;
+        request.userInfo.flags = 108;
+        request.numberAssociationTypes = 2;
+        request.associationTypes.add(KEY_FOB);
+        request.associationTypes.add(CUSTOM_1);
+
+        VehiclePropValue propValue = UserHalHelper.toVehiclePropValue(request);
+        assertWithMessage("wrong prop on %s", propValue).that(propValue.prop)
+                .isEqualTo(USER_IDENTIFICATION_ASSOCIATION_PROPERTY);
+        assertWithMessage("wrong int32values on %s", propValue).that(propValue.value.int32Values)
+                .containsExactly(1, 42, 108, 2, KEY_FOB, CUSTOM_1).inOrder();
+    }
+
+    @Test
+    public void testToUserIdentificationResponse_null() {
+        assertThrows(NullPointerException.class,
+                () -> UserHalHelper.toUserIdentificationResponse(null));
+    }
+
+    @Test
+    public void testToUserIdentificationResponse_invalidPropType() {
+        VehiclePropValue prop = new VehiclePropValue();
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toUserIdentificationResponse(prop));
+    }
+
+    @Test
+    public void testToUserIdentificationResponse_invalidSize() {
+        VehiclePropValue prop = new VehiclePropValue();
+        prop.prop = UserHalHelper.USER_IDENTIFICATION_ASSOCIATION_PROPERTY;
+        // need at least 4: request_id, number associations, type1, value1
+        prop.value.int32Values.add(1);
+        prop.value.int32Values.add(2);
+        prop.value.int32Values.add(3);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toUserIdentificationResponse(prop));
+    }
+
+    @Test
+    public void testToUserIdentificationResponse_invalidRequest() {
+        VehiclePropValue prop = new VehiclePropValue();
+        prop.prop = UserHalHelper.USER_IDENTIFICATION_ASSOCIATION_PROPERTY;
+        prop.value.int32Values.add(0);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toUserIdentificationResponse(prop));
+    }
+
+    @Test
+    public void testToUserIdentificationResponse_invalidType() {
+        VehiclePropValue prop = new VehiclePropValue();
+        prop.prop = UserHalHelper.USER_IDENTIFICATION_ASSOCIATION_PROPERTY;
+        prop.value.int32Values.add(42); // request id
+        prop.value.int32Values.add(1); // number of associations
+        prop.value.int32Values.add(CUSTOM_4 + 1);
+        prop.value.int32Values.add(ASSOCIATED_ANOTHER_USER);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toUserIdentificationResponse(prop));
+    }
+
+    @Test
+    public void testToUserIdentificationResponse_invalidValue() {
+        VehiclePropValue prop = new VehiclePropValue();
+        prop.prop = UserHalHelper.USER_IDENTIFICATION_ASSOCIATION_PROPERTY;
+        prop.value.int32Values.add(42); // request id
+        prop.value.int32Values.add(1); // number of associations
+        prop.value.int32Values.add(KEY_FOB);
+        prop.value.int32Values.add(0);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toUserIdentificationResponse(prop));
+    }
+
+    @Test
+    public void testToUserIdentificationResponse_ok() {
+        VehiclePropValue prop = new VehiclePropValue();
+        prop.prop = UserHalHelper.USER_IDENTIFICATION_ASSOCIATION_PROPERTY;
+        prop.value.int32Values.add(42); // request id
+        prop.value.int32Values.add(3); // number of associations
+        prop.value.int32Values.add(KEY_FOB);
+        prop.value.int32Values.add(ASSOCIATED_ANOTHER_USER);
+        prop.value.int32Values.add(CUSTOM_1);
+        prop.value.int32Values.add(ASSOCIATED_CURRENT_USER);
+        prop.value.int32Values.add(CUSTOM_2);
+        prop.value.int32Values.add(NOT_ASSOCIATED_ANY_USER);
+        prop.value.stringValue = "D'OH!";
+
+        UserIdentificationResponse response = UserHalHelper.toUserIdentificationResponse(prop);
+
+        assertWithMessage("Wrong request id on %s", response)
+            .that(response.requestId).isEqualTo(42);
+        assertWithMessage("Wrong number of associations on %s", response)
+            .that(response.numberAssociation).isEqualTo(3);
+        assertAssociation(response, 0, KEY_FOB, ASSOCIATED_ANOTHER_USER);
+        assertAssociation(response, 1, CUSTOM_1, ASSOCIATED_CURRENT_USER);
+        assertAssociation(response, 2, CUSTOM_2, NOT_ASSOCIATED_ANY_USER);
+        assertWithMessage("Wrong error message on %s", response)
+            .that(response.errorMessage).isEqualTo("D'OH!");
+    }
+
+    @Test
+    public void testToInitialUserInfoResponse_null() {
+        assertThrows(NullPointerException.class,
+                () -> UserHalHelper.toInitialUserInfoResponse(null));
+    }
+
+    @Test
+    public void testToInitialUserInfoResponse_invalidPropType() {
+        VehiclePropValue prop = new VehiclePropValue();
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toInitialUserInfoResponse(prop));
+    }
+
+    @Test
+    public void testToInitialUserInfoResponse_invalidSize() {
+        VehiclePropValue prop = new VehiclePropValue();
+        prop.prop = UserHalHelper.INITIAL_USER_INFO_PROPERTY;
+        //      need at least 2: request_id, action_type
+        prop.value.int32Values.add(42);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toInitialUserInfoResponse(prop));
+    }
+
+    @Test
+    public void testToInitialUserInfoResponse_invalidRequest() {
+        VehiclePropValue prop = new VehiclePropValue();
+        prop.prop = UserHalHelper.INITIAL_USER_INFO_PROPERTY;
+        prop.value.int32Values.add(0);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toInitialUserInfoResponse(prop));
+    }
+
+    @Test
+    public void testToInitialUserInfoResponse_invalidAction() {
+        VehiclePropValue prop = new VehiclePropValue();
+        prop.prop = UserHalHelper.INITIAL_USER_INFO_PROPERTY;
+        prop.value.int32Values.add(42); // request id
+        prop.value.int32Values.add(-1); // InitialUserInfoResponseAction
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toInitialUserInfoResponse(prop));
+    }
+
+    @Test
+    public void testToInitialUserInfoResponse_default_ok_noStringValue() {
+        VehiclePropValue prop = new VehiclePropValue();
+        prop.prop = UserHalHelper.INITIAL_USER_INFO_PROPERTY;
+        prop.value.int32Values.add(42); // request id
+        prop.value.int32Values.add(InitialUserInfoResponseAction.DEFAULT);
+
+        InitialUserInfoResponse response = UserHalHelper.toInitialUserInfoResponse(prop);
+
+        assertThat(response).isNotNull();
+        assertThat(response.requestId).isEqualTo(42);
+        assertThat(response.action).isEqualTo(InitialUserInfoResponseAction.DEFAULT);
+        assertThat(response.userNameToCreate).isEmpty();
+        assertThat(response.userToSwitchOrCreate.userId).isEqualTo(UserHandle.USER_NULL);
+        assertThat(response.userToSwitchOrCreate.flags).isEqualTo(UserFlags.NONE);
+        assertThat(response.userLocales).isEmpty();
+    }
+
+    @Test
+    public void testToInitialUserInfoResponse_default_ok_stringValueWithJustSeparator() {
+        VehiclePropValue prop = new VehiclePropValue();
+        prop.prop = UserHalHelper.INITIAL_USER_INFO_PROPERTY;
+        prop.value.int32Values.add(42); // request id
+        prop.value.int32Values.add(InitialUserInfoResponseAction.DEFAULT);
+        prop.value.stringValue = "||";
+
+        InitialUserInfoResponse response = UserHalHelper.toInitialUserInfoResponse(prop);
+
+        assertThat(response).isNotNull();
+        assertThat(response.requestId).isEqualTo(42);
+        assertThat(response.action).isEqualTo(InitialUserInfoResponseAction.DEFAULT);
+        assertThat(response.userNameToCreate).isEmpty();
+        assertThat(response.userToSwitchOrCreate.userId).isEqualTo(UserHandle.USER_NULL);
+        assertThat(response.userToSwitchOrCreate.flags).isEqualTo(UserFlags.NONE);
+        assertThat(response.userLocales).isEmpty();
+    }
+
+    @Test
+    public void testToInitialUserInfoResponse_default_ok_stringValueWithLocale() {
+        VehiclePropValue prop = new VehiclePropValue();
+        prop.prop = UserHalHelper.INITIAL_USER_INFO_PROPERTY;
+        prop.value.int32Values.add(42); // request id
+        prop.value.int32Values.add(InitialUserInfoResponseAction.DEFAULT);
+        prop.value.stringValue = "esperanto,klingon";
+
+        InitialUserInfoResponse response = UserHalHelper.toInitialUserInfoResponse(prop);
+
+        assertThat(response).isNotNull();
+        assertThat(response.requestId).isEqualTo(42);
+        assertThat(response.action).isEqualTo(InitialUserInfoResponseAction.DEFAULT);
+        assertThat(response.userNameToCreate).isEmpty();
+        assertThat(response.userToSwitchOrCreate.userId).isEqualTo(UserHandle.USER_NULL);
+        assertThat(response.userToSwitchOrCreate.flags).isEqualTo(UserFlags.NONE);
+        assertThat(response.userLocales).isEqualTo("esperanto,klingon");
+    }
+
+    @Test
+    public void testToInitialUserInfoResponse_default_ok_stringValueWithLocaleWithHalfSeparator() {
+        VehiclePropValue prop = new VehiclePropValue();
+        prop.prop = UserHalHelper.INITIAL_USER_INFO_PROPERTY;
+        prop.value.int32Values.add(42); // request id
+        prop.value.int32Values.add(InitialUserInfoResponseAction.DEFAULT);
+        prop.value.stringValue = "esperanto|klingon";
+
+        InitialUserInfoResponse response = UserHalHelper.toInitialUserInfoResponse(prop);
+
+        assertThat(response).isNotNull();
+        assertThat(response.requestId).isEqualTo(42);
+        assertThat(response.action).isEqualTo(InitialUserInfoResponseAction.DEFAULT);
+        assertThat(response.userNameToCreate).isEmpty();
+        assertThat(response.userToSwitchOrCreate.userId).isEqualTo(UserHandle.USER_NULL);
+        assertThat(response.userToSwitchOrCreate.flags).isEqualTo(UserFlags.NONE);
+        assertThat(response.userLocales).isEqualTo("esperanto|klingon");
+    }
+
+    @Test
+    public void testToInitialUserInfoResponse_switch_missingUserId() {
+        VehiclePropValue prop = new VehiclePropValue();
+        prop.prop = UserHalHelper.INITIAL_USER_INFO_PROPERTY;
+        prop.value.int32Values.add(42); // request id
+        prop.value.int32Values.add(InitialUserInfoResponseAction.SWITCH);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toInitialUserInfoResponse(prop));
+    }
+
+    @Test
+    public void testToInitialUserInfoResponse_switch_ok_noLocale() {
+        VehiclePropValue prop = new VehiclePropValue();
+        prop.prop = UserHalHelper.INITIAL_USER_INFO_PROPERTY;
+        prop.value.int32Values.add(42); // request id
+        prop.value.int32Values.add(InitialUserInfoResponseAction.SWITCH);
+        prop.value.int32Values.add(108); // user id
+        prop.value.int32Values.add(666); // flags - should be ignored
+
+        InitialUserInfoResponse response = UserHalHelper.toInitialUserInfoResponse(prop);
+
+        assertThat(response).isNotNull();
+        assertThat(response.requestId).isEqualTo(42);
+        assertThat(response.action).isEqualTo(InitialUserInfoResponseAction.SWITCH);
+        assertThat(response.userNameToCreate).isEmpty();
+        assertThat(response.userToSwitchOrCreate.userId).isEqualTo(108);
+        assertThat(response.userToSwitchOrCreate.flags).isEqualTo(UserFlags.NONE);
+        assertThat(response.userLocales).isEmpty();
+    }
+
+    @Test
+    public void testToInitialUserInfoResponse_switch_ok_withLocale() {
+        VehiclePropValue prop = new VehiclePropValue();
+        prop.prop = UserHalHelper.INITIAL_USER_INFO_PROPERTY;
+        prop.value.int32Values.add(42); // request id
+        prop.value.int32Values.add(InitialUserInfoResponseAction.SWITCH);
+        prop.value.int32Values.add(108); // user id
+        prop.value.int32Values.add(666); // flags - should be ignored
+        // add some extra | to make sure they're ignored
+        prop.value.stringValue = "esperanto,klingon|||";
+        InitialUserInfoResponse response = UserHalHelper.toInitialUserInfoResponse(prop);
+
+        assertThat(response).isNotNull();
+        assertThat(response.requestId).isEqualTo(42);
+        assertThat(response.action).isEqualTo(InitialUserInfoResponseAction.SWITCH);
+        assertThat(response.userNameToCreate).isEmpty();
+        assertThat(response.userToSwitchOrCreate.userId).isEqualTo(108);
+        assertThat(response.userToSwitchOrCreate.flags).isEqualTo(UserFlags.NONE);
+        assertThat(response.userLocales).isEqualTo("esperanto,klingon");
+    }
+
+    @Test
+    public void testToInitialUserInfoResponse_create_missingUserId() {
+        VehiclePropValue prop = new VehiclePropValue();
+        prop.prop = UserHalHelper.INITIAL_USER_INFO_PROPERTY;
+        prop.value.int32Values.add(42); // request id
+        prop.value.int32Values.add(InitialUserInfoResponseAction.CREATE);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toInitialUserInfoResponse(prop));
+    }
+
+    @Test
+    public void testToInitialUserInfoResponse_create_missingFlags() {
+        VehiclePropValue prop = new VehiclePropValue();
+        prop.prop = UserHalHelper.INITIAL_USER_INFO_PROPERTY;
+        prop.value.int32Values.add(42); // request id
+        prop.value.int32Values.add(InitialUserInfoResponseAction.CREATE);
+        prop.value.int32Values.add(108); // user id
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toInitialUserInfoResponse(prop));
+    }
+
+    @Test
+    public void testToInitialUserInfoResponse_create_ok_noLocale() {
+        VehiclePropValue prop = new VehiclePropValue();
+        prop.prop = UserHalHelper.INITIAL_USER_INFO_PROPERTY;
+        prop.value.int32Values.add(42); // request id
+        prop.value.int32Values.add(InitialUserInfoResponseAction.CREATE);
+        prop.value.int32Values.add(666); // user id - not used
+        prop.value.int32Values.add(UserFlags.GUEST);
+        prop.value.stringValue = "||ElGuesto";
+
+        InitialUserInfoResponse response = UserHalHelper.toInitialUserInfoResponse(prop);
+
+        assertThat(response).isNotNull();
+        assertThat(response.requestId).isEqualTo(42);
+        assertThat(response.action).isEqualTo(InitialUserInfoResponseAction.CREATE);
+        assertThat(response.userNameToCreate).isEqualTo("ElGuesto");
+        assertThat(response.userToSwitchOrCreate.userId).isEqualTo(UserHandle.USER_NULL);
+        assertThat(response.userToSwitchOrCreate.flags).isEqualTo(UserFlags.GUEST);
+        assertThat(response.userLocales).isEmpty();
+    }
+
+    @Test
+    public void testToInitialUserInfoResponse_create_ok_withLocale() {
+        VehiclePropValue prop = new VehiclePropValue();
+        prop.prop = UserHalHelper.INITIAL_USER_INFO_PROPERTY;
+        prop.value.int32Values.add(42); // request id
+        prop.value.int32Values.add(InitialUserInfoResponseAction.CREATE);
+        prop.value.int32Values.add(666); // user id - not used
+        prop.value.int32Values.add(UserFlags.GUEST);
+        prop.value.stringValue = "esperanto,klingon||ElGuesto";
+
+        InitialUserInfoResponse response = UserHalHelper.toInitialUserInfoResponse(prop);
+
+        assertThat(response).isNotNull();
+        assertThat(response.requestId).isEqualTo(42);
+        assertThat(response.action).isEqualTo(InitialUserInfoResponseAction.CREATE);
+        assertThat(response.userNameToCreate).isEqualTo("ElGuesto");
+        assertThat(response.userToSwitchOrCreate.userId).isEqualTo(UserHandle.USER_NULL);
+        assertThat(response.userToSwitchOrCreate.flags).isEqualTo(UserFlags.GUEST);
+        assertThat(response.userLocales).isEqualTo("esperanto,klingon");
+    }
+
+    @Test
+    public void testToInitialUserInfoResponse_create_ok_nameAndLocaleWithHalfDelimiter() {
+        VehiclePropValue prop = new VehiclePropValue();
+        prop.prop = UserHalHelper.INITIAL_USER_INFO_PROPERTY;
+        prop.value.int32Values.add(42); // request id
+        prop.value.int32Values.add(InitialUserInfoResponseAction.CREATE);
+        prop.value.int32Values.add(666); // user id - not used
+        prop.value.int32Values.add(UserFlags.GUEST);
+        prop.value.stringValue = "esperanto|klingon||El|Guesto";
+
+        InitialUserInfoResponse response = UserHalHelper.toInitialUserInfoResponse(prop);
+
+        assertThat(response).isNotNull();
+        assertThat(response.requestId).isEqualTo(42);
+        assertThat(response.action).isEqualTo(InitialUserInfoResponseAction.CREATE);
+        assertThat(response.userNameToCreate).isEqualTo("El|Guesto");
+        assertThat(response.userToSwitchOrCreate.userId).isEqualTo(UserHandle.USER_NULL);
+        assertThat(response.userToSwitchOrCreate.flags).isEqualTo(UserFlags.GUEST);
+        assertThat(response.userLocales).isEqualTo("esperanto|klingon");
+    }
+
+    @Test
+    public void testUserIdentificationSetRequestToVehiclePropValue_null() {
+        assertThrows(NullPointerException.class,
+                () -> UserHalHelper.toVehiclePropValue((UserIdentificationSetRequest) null));
+    }
+
+    @Test
+    public void testUserIdentificationSetRequestToVehiclePropValue_emptyRequest() {
+        UserIdentificationSetRequest request = new UserIdentificationSetRequest();
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toVehiclePropValue(request));
+    }
+
+    @Test
+    public void testUserIdentificationSetRequestToVehiclePropValue_wrongNumberOfAssociations() {
+        UserIdentificationSetRequest request = new UserIdentificationSetRequest();
+        request.numberAssociations = 1;
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toVehiclePropValue(request));
+    }
+
+    @Test
+    public void testUserIdentificationSetRequestToVehiclePropValue_invalidType() {
+        UserIdentificationSetRequest request = new UserIdentificationSetRequest();
+        request.numberAssociations = 1;
+        UserIdentificationSetAssociation association1 = new UserIdentificationSetAssociation();
+        request.associations.add(association1);
+        association1.type = CUSTOM_4 + 1;
+        association1.value = ASSOCIATE_CURRENT_USER;
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toVehiclePropValue(request));
+    }
+
+    @Test
+    public void testUserIdentificationSetRequestToVehiclePropValue_invalidValue() {
+        UserIdentificationSetRequest request = new UserIdentificationSetRequest();
+        request.numberAssociations = 1;
+        UserIdentificationSetAssociation association1 = new UserIdentificationSetAssociation();
+        request.associations.add(association1);
+        association1.type = KEY_FOB;
+        association1.value = -1;
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toVehiclePropValue(request));
+    }
+
+    @Test
+    public void testUserIdentificationSetRequestToVehiclePropValue_missingRequestId() {
+        UserIdentificationSetRequest request = new UserIdentificationSetRequest();
+        request.userInfo.userId = 42;
+        request.userInfo.flags = 108;
+        request.numberAssociations = 1;
+        UserIdentificationSetAssociation association1 = new UserIdentificationSetAssociation();
+        association1.type = KEY_FOB;
+        association1.value = ASSOCIATE_CURRENT_USER;
+        request.associations.add(association1);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toVehiclePropValue(request));
+    }
+
+    @Test
+    public void testUserIdentificationSetRequestToVehiclePropValue_ok() {
+        UserIdentificationSetRequest request = new UserIdentificationSetRequest();
+        request.requestId = 1;
+        request.userInfo.userId = 42;
+        request.userInfo.flags = 108;
+        request.numberAssociations = 2;
+        UserIdentificationSetAssociation association1 = new UserIdentificationSetAssociation();
+        association1.type = KEY_FOB;
+        association1.value = ASSOCIATE_CURRENT_USER;
+        request.associations.add(association1);
+        UserIdentificationSetAssociation association2 = new UserIdentificationSetAssociation();
+        association2.type = CUSTOM_1;
+        association2.value = DISASSOCIATE_CURRENT_USER;
+        request.associations.add(association2);
+
+        VehiclePropValue propValue = UserHalHelper.toVehiclePropValue(request);
+        assertWithMessage("wrong prop on %s", propValue).that(propValue.prop)
+                .isEqualTo(USER_IDENTIFICATION_ASSOCIATION_PROPERTY);
+        assertWithMessage("wrong int32values on %s", propValue).that(propValue.value.int32Values)
+                .containsExactly(1, 42, 108, 2,
+                        KEY_FOB, ASSOCIATE_CURRENT_USER,
+                        CUSTOM_1, DISASSOCIATE_CURRENT_USER)
+                .inOrder();
+    }
+
+    @Test
+    public void testRemoveUserRequestToVehiclePropValue_null() {
+        assertThrows(NullPointerException.class,
+                () -> UserHalHelper.toVehiclePropValue((RemoveUserRequest) null));
+    }
+
+    @Test
+    public void testRemoveUserRequestToVehiclePropValue_emptyRequest() {
+        RemoveUserRequest request = new RemoveUserRequest();
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toVehiclePropValue(request));
+    }
+
+    @Test
+    public void testRemoveUserRequestToVehiclePropValue_missingRequestId() {
+        RemoveUserRequest request = new RemoveUserRequest();
+        request.removedUserInfo.userId = 11;
+        request.usersInfo.existingUsers.add(request.removedUserInfo);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toVehiclePropValue(request));
+    }
+
+    @Test
+    public void testRemoveUserRequestToVehiclePropValue_ok() {
+        RemoveUserRequest request = new RemoveUserRequest();
+        request.requestId = 42;
+
+        android.hardware.automotive.vehicle.V2_0.UserInfo user10 =
+                new android.hardware.automotive.vehicle.V2_0.UserInfo();
+        user10.userId = 10;
+        user10.flags = UserFlags.ADMIN;
+
+        // existing users
+        request.usersInfo.numberUsers = 1;
+        request.usersInfo.existingUsers.add(user10);
+
+        // current user
+        request.usersInfo.currentUser = user10;
+        // user to remove
+        request.removedUserInfo = user10;
+
+        VehiclePropValue propValue = UserHalHelper.toVehiclePropValue(request);
+
+        assertWithMessage("wrong prop on %s", propValue).that(propValue.prop)
+                .isEqualTo(REMOVE_USER_PROPERTY);
+        assertWithMessage("wrong int32values on %s", propValue).that(propValue.value.int32Values)
+                .containsExactly(42, // request id
+                        10, UserFlags.ADMIN, // user to remove
+                        10, UserFlags.ADMIN, // current user
+                        1, // number of users
+                        10, UserFlags.ADMIN  // existing user 1
+                        ).inOrder();
+    }
+
+    @Test
+    public void testCreateUserRequestToVehiclePropValue_null() {
+        assertThrows(NullPointerException.class,
+                () -> UserHalHelper.toVehiclePropValue((CreateUserRequest) null));
+    }
+
+    @Test
+    public void testCreateUserRequestToVehiclePropValue_emptyRequest() {
+        CreateUserRequest request = new CreateUserRequest();
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toVehiclePropValue(request));
+    }
+
+    @Test
+    public void testCreateUserRequestToVehiclePropValue_missingRequestId() {
+        CreateUserRequest request = new CreateUserRequest();
+        request.newUserInfo.userId = 10;
+        request.usersInfo.existingUsers.add(request.newUserInfo);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toVehiclePropValue(request));
+    }
+
+    @Test
+    public void testCreateUserRequestToVehiclePropValue_nullNewUserName() {
+        CreateUserRequest request = new CreateUserRequest();
+        request.requestId = 42;
+
+        request.newUserInfo.userId = 10;
+        request.newUserInfo.flags = UserFlags.ADMIN;
+        request.newUserName = null;
+
+        request.usersInfo.numberUsers = 1;
+        request.usersInfo.currentUser.userId = request.newUserInfo.userId;
+        request.usersInfo.currentUser.flags = request.newUserInfo.flags;
+        request.usersInfo.existingUsers.add(request.usersInfo.currentUser);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toVehiclePropValue(request));
+    }
+
+    @Test
+    public void testCreateUserRequestToVehiclePropValue_usersInfoDoesNotContainNewUser() {
+        CreateUserRequest request = new CreateUserRequest();
+        request.requestId = 42;
+        request.newUserInfo.userId = 10;
+        android.hardware.automotive.vehicle.V2_0.UserInfo user =
+                new android.hardware.automotive.vehicle.V2_0.UserInfo();
+        user.userId = 11;
+        request.usersInfo.existingUsers.add(user);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toVehiclePropValue(request));
+    }
+
+    @Test
+    public void testCreateUserRequestToVehiclePropValue_newUserFlagsMismatch() {
+        CreateUserRequest request = new CreateUserRequest();
+        request.requestId = 42;
+        request.newUserInfo.userId = 10;
+        request.newUserInfo.flags = UserFlags.ADMIN;
+        android.hardware.automotive.vehicle.V2_0.UserInfo user =
+                new android.hardware.automotive.vehicle.V2_0.UserInfo();
+        user.userId = 10;
+        request.newUserInfo.flags = UserFlags.SYSTEM;
+        request.usersInfo.existingUsers.add(user);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toVehiclePropValue(request));
+    }
+
+    @Test
+    public void testCreateUserRequestToVehiclePropValue_ok() {
+        CreateUserRequest request = new CreateUserRequest();
+        request.requestId = 42;
+
+        android.hardware.automotive.vehicle.V2_0.UserInfo user10 =
+                new android.hardware.automotive.vehicle.V2_0.UserInfo();
+        user10.userId = 10;
+        user10.flags = UserFlags.ADMIN;
+        android.hardware.automotive.vehicle.V2_0.UserInfo user11 =
+                new android.hardware.automotive.vehicle.V2_0.UserInfo();
+        user11.userId = 11;
+        user11.flags = UserFlags.SYSTEM;
+        android.hardware.automotive.vehicle.V2_0.UserInfo user12 =
+                new android.hardware.automotive.vehicle.V2_0.UserInfo();
+        user12.userId = 12;
+        user12.flags = UserFlags.GUEST;
+
+        // existing users
+        request.usersInfo.numberUsers = 3;
+        request.usersInfo.existingUsers.add(user10);
+        request.usersInfo.existingUsers.add(user11);
+        request.usersInfo.existingUsers.add(user12);
+
+        // current user
+        request.usersInfo.currentUser.userId = 12;
+        request.usersInfo.currentUser.flags = UserFlags.GUEST;
+
+        // new user
+        request.newUserInfo.userId = 10;
+        request.newUserInfo.flags = UserFlags.ADMIN;
+        request.newUserName = "Dude";
+
+
+        VehiclePropValue propValue = UserHalHelper.toVehiclePropValue(request);
+
+        assertWithMessage("wrong prop on %s", propValue).that(propValue.prop)
+                .isEqualTo(CREATE_USER_PROPERTY);
+        assertWithMessage("wrong int32values on %s", propValue).that(propValue.value.int32Values)
+                .containsExactly(42, // request id
+                        10, UserFlags.ADMIN, // new user
+                        12, UserFlags.GUEST, // current user
+                        3, // number of users
+                        10, UserFlags.ADMIN,  // existing user 1
+                        11, UserFlags.SYSTEM, // existing user 2
+                        12, UserFlags.GUEST   // existing user 3
+                        ).inOrder();
+        assertWithMessage("wrong name %s", propValue).that(propValue.value.stringValue)
+                .isEqualTo("Dude");
+    }
+
+    @Test
+    public void testSwitchUserRequestToVehiclePropValue_null() {
+        assertThrows(NullPointerException.class,
+                () -> UserHalHelper.toVehiclePropValue((SwitchUserRequest) null));
+    }
+
+    @Test
+    public void testSwitchUserRequestToVehiclePropValue_emptyRequest() {
+        SwitchUserRequest request = new SwitchUserRequest();
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toVehiclePropValue(request));
+    }
+
+    @Test
+    public void testSwitchUserRequestToVehiclePropValue_missingMessageType() {
+        SwitchUserRequest request = new SwitchUserRequest();
+        request.requestId = 42;
+        android.hardware.automotive.vehicle.V2_0.UserInfo user10 =
+                new android.hardware.automotive.vehicle.V2_0.UserInfo();
+        user10.userId = 10;
+        request.usersInfo.numberUsers = 1;
+        request.usersInfo.existingUsers.add(user10);
+        request.usersInfo.currentUser = user10;
+        request.targetUser = user10;
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toVehiclePropValue(request));
+    }
+
+    @Test
+    public void testSwitchUserRequestToVehiclePropValue_incorrectMessageType() {
+        SwitchUserRequest request = new SwitchUserRequest();
+        request.requestId = 42;
+        request.messageType = -1;
+        android.hardware.automotive.vehicle.V2_0.UserInfo user10 =
+                new android.hardware.automotive.vehicle.V2_0.UserInfo();
+        user10.userId = 10;
+        request.usersInfo.numberUsers = 1;
+        request.usersInfo.existingUsers.add(user10);
+        request.usersInfo.currentUser = user10;
+        request.targetUser = user10;
+
+        assertThrows(IllegalArgumentException.class,
+                () -> UserHalHelper.toVehiclePropValue(request));
+    }
+
+    @Test
+    public void tesSwitchUserRequestToVehiclePropValue_ok() {
+        SwitchUserRequest request = new SwitchUserRequest();
+        request.requestId = 42;
+        android.hardware.automotive.vehicle.V2_0.UserInfo user10 =
+                new android.hardware.automotive.vehicle.V2_0.UserInfo();
+        user10.userId = 10;
+        user10.flags = UserFlags.ADMIN;
+        // existing users
+        request.usersInfo.numberUsers = 1;
+        request.usersInfo.existingUsers.add(user10);
+        // current user
+        request.usersInfo.currentUser = user10;
+        // user to remove
+        request.targetUser = user10;
+        request.messageType = SwitchUserMessageType.ANDROID_SWITCH;
+
+        VehiclePropValue propValue = UserHalHelper.toVehiclePropValue(request);
+
+        assertWithMessage("wrong prop on %s", propValue).that(propValue.prop)
+                .isEqualTo(SWITCH_USER_PROPERTY);
+        assertWithMessage("wrong int32values on %s", propValue).that(propValue.value.int32Values)
+                .containsExactly(42, // request id
+                        SwitchUserMessageType.ANDROID_SWITCH, // message type
+                        10, UserFlags.ADMIN, // target user
+                        10, UserFlags.ADMIN, // current user
+                        1, // number of users
+                        10, UserFlags.ADMIN  // existing user 1
+                        ).inOrder();
+    }
+
+    @Test
+    public void testNewUsersInfo_nullUm() {
+        assertThrows(IllegalArgumentException.class, () -> UserHalHelper.newUsersInfo(null, 100));
+    }
+
+    @Test
+    public void testNewUsersInfo_nullUsers() {
+        UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUm, 100);
+
+        assertEmptyUsersInfo(usersInfo);
+    }
+
+    @Test
+    public void testNewUsersInfo_noUsers() {
+        List<UserInfo> users = new ArrayList<>();
+        AndroidMockitoHelper.mockUmGetUsers(mUm, users);
+
+        UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUm, 100);
+
+        assertEmptyUsersInfo(usersInfo);
+    }
+
+    @Test
+    public void testNewUsersInfo_ok() {
+        UserInfo user100 = new UserInfoBuilder(100).setFlags(UserInfo.FLAG_ADMIN).build();
+        UserInfo user200 = new UserInfoBuilder(200).build();
+
+        AndroidMockitoHelper.mockUmGetUsers(mUm, user100, user200);
+        AndroidMockitoHelper.mockAmGetCurrentUser(300); // just to make sure it's not used
+
+        UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUm, 100);
+
+        assertThat(usersInfo).isNotNull();
+        assertThat(usersInfo.currentUser.userId).isEqualTo(100);
+        assertThat(usersInfo.currentUser.flags).isEqualTo(UserFlags.ADMIN);
+
+        assertThat(usersInfo.numberUsers).isEqualTo(2);
+        assertThat(usersInfo.existingUsers).hasSize(2);
+
+        assertThat(usersInfo.existingUsers.get(0).userId).isEqualTo(100);
+        assertThat(usersInfo.existingUsers.get(0).flags).isEqualTo(UserFlags.ADMIN);
+        assertThat(usersInfo.existingUsers.get(1).userId).isEqualTo(200);
+        assertThat(usersInfo.existingUsers.get(1).flags).isEqualTo(UserFlags.NONE);
+    }
+
+    @Test
+    public void testNewUsersInfo_currentUser_ok() {
+        UserInfo user100 = new UserInfoBuilder(100).setFlags(UserInfo.FLAG_ADMIN).build();
+        UserInfo user200 = new UserInfoBuilder(200).build();
+
+        AndroidMockitoHelper.mockUmGetUsers(mUm, user100, user200);
+        AndroidMockitoHelper.mockAmGetCurrentUser(100);
+
+        UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUm);
+
+        assertThat(usersInfo).isNotNull();
+        assertThat(usersInfo.currentUser.userId).isEqualTo(100);
+        assertThat(usersInfo.currentUser.flags).isEqualTo(UserFlags.ADMIN);
+
+        assertThat(usersInfo.numberUsers).isEqualTo(2);
+        assertThat(usersInfo.existingUsers).hasSize(2);
+
+        assertThat(usersInfo.existingUsers.get(0).userId).isEqualTo(100);
+        assertThat(usersInfo.existingUsers.get(0).flags).isEqualTo(UserFlags.ADMIN);
+        assertThat(usersInfo.existingUsers.get(1).userId).isEqualTo(200);
+        assertThat(usersInfo.existingUsers.get(1).flags).isEqualTo(UserFlags.NONE);
+    }
+
+    @Test
+    @ExpectWtf
+    public void testNewUsersInfo_noCurrentUser() {
+        UserInfo user100 = new UserInfoBuilder(100).setFlags(UserInfo.FLAG_ADMIN).build();
+        UserInfo user200 = new UserInfoBuilder(200).build();
+
+        AndroidMockitoHelper.mockUmGetUsers(mUm, user100, user200);
+        AndroidMockitoHelper.mockAmGetCurrentUser(300);
+
+        UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUm);
+
+        assertThat(usersInfo).isNotNull();
+        assertThat(usersInfo.currentUser.userId).isEqualTo(300);
+        assertThat(usersInfo.currentUser.flags).isEqualTo(UserFlags.NONE);
+
+        assertThat(usersInfo.numberUsers).isEqualTo(2);
+        assertThat(usersInfo.existingUsers).hasSize(2);
+
+        assertThat(usersInfo.existingUsers.get(0).userId).isEqualTo(100);
+        assertThat(usersInfo.existingUsers.get(0).flags).isEqualTo(UserFlags.ADMIN);
+        assertThat(usersInfo.existingUsers.get(1).userId).isEqualTo(200);
+        assertThat(usersInfo.existingUsers.get(1).flags).isEqualTo(UserFlags.NONE);
+    }
+
+    @Test
+    public void testCheckValidUsersInfo_null() {
+        assertThrows(IllegalArgumentException.class, () -> UserHalHelper.checkValid(null));
+    }
+
+    @Test
+    public void testCheckValidUsersInfo_empty() {
+        UsersInfo usersInfo = new UsersInfo();
+        assertThrows(IllegalArgumentException.class, () -> UserHalHelper.checkValid(usersInfo));
+    }
+
+    @Test
+    public void testCheckValidUsersInfo_sizeMismatch() {
+        UsersInfo usersInfo = new UsersInfo();
+        usersInfo.numberUsers = 1;
+        assertThrows(IllegalArgumentException.class, () -> UserHalHelper.checkValid(usersInfo));
+    }
+
+    @Test
+    public void testCheckValidUsersInfo_currentUserMissing() {
+        UsersInfo usersInfo = new UsersInfo();
+        usersInfo.numberUsers = 1;
+        usersInfo.currentUser.userId = 10;
+        usersInfo.existingUsers.add(new android.hardware.automotive.vehicle.V2_0.UserInfo());
+
+        assertThrows(IllegalArgumentException.class, () -> UserHalHelper.checkValid(usersInfo));
+    }
+
+    @Test
+    public void testCheckValidUsersInfo_currentUserFlagsMismatch() {
+        UsersInfo usersInfo = new UsersInfo();
+        usersInfo.numberUsers = 1;
+        usersInfo.currentUser.userId = 10;
+        usersInfo.currentUser.flags = UserFlags.ADMIN;
+        android.hardware.automotive.vehicle.V2_0.UserInfo currentUser =
+                new android.hardware.automotive.vehicle.V2_0.UserInfo();
+        currentUser.userId = 10;
+        currentUser.flags = UserFlags.SYSTEM;
+        usersInfo.existingUsers.add(currentUser);
+
+        assertThrows(IllegalArgumentException.class, () -> UserHalHelper.checkValid(usersInfo));
+    }
+
+    @Test
+    public void testCheckValidUsersInfo_ok() {
+        UsersInfo usersInfo = new UsersInfo();
+        usersInfo.numberUsers = 1;
+        usersInfo.currentUser.userId = 10;
+
+        android.hardware.automotive.vehicle.V2_0.UserInfo currentUser =
+                new android.hardware.automotive.vehicle.V2_0.UserInfo();
+        currentUser.userId = 10;
+        usersInfo.existingUsers.add(currentUser);
+
+        UserHalHelper.checkValid(usersInfo);
+    }
+
+    private static void assertEmptyUsersInfo(UsersInfo usersInfo) {
+        assertThat(usersInfo).isNotNull();
+        assertThat(usersInfo.currentUser.userId).isEqualTo(UserHandle.USER_NULL);
+        assertThat(usersInfo.currentUser.flags).isEqualTo(UserFlags.NONE);
+        assertThat(usersInfo.numberUsers).isEqualTo(0);
+        assertThat(usersInfo.existingUsers).isEmpty();
+    }
+
+    private static void assertAssociation(@NonNull UserIdentificationResponse response, int index,
+            int expectedType, int expectedValue) {
+        UserIdentificationAssociation actualAssociation = response.associations.get(index);
+        if (actualAssociation.type != expectedType) {
+            fail("Wrong type for association at index " + index + " on " + response + "; expected "
+                    + UserIdentificationAssociationType.toString(expectedType) + ", got "
+                    + UserIdentificationAssociationType.toString(actualAssociation.type));
+        }
+        if (actualAssociation.type != expectedType) {
+            fail("Wrong value for association at index " + index + " on " + response + "; expected "
+                    + UserIdentificationAssociationValue.toString(expectedValue) + ", got "
+                    + UserIdentificationAssociationValue.toString(actualAssociation.value));
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/android/car/userlib/UserHelperTest.java b/tests/carservice_unit_test/src/android/car/userlib/UserHelperTest.java
new file mode 100644
index 0000000..c372a28
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/userlib/UserHelperTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.userlib;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import org.junit.Test;
+
+public final class UserHelperTest extends AbstractExtendedMockitoTestCase {
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+        session.spyStatic(UserManager.class);
+    }
+
+    @Test
+    public void testSafeName() {
+        assertThat(UserHelper.safeName(null)).isNull();
+
+        String safe = UserHelper.safeName("UnsafeIam");
+        assertThat(safe).isNotNull();
+        assertThat(safe).doesNotContain("UnsafeIAm");
+    }
+
+    @Test
+    public void testIsHeadlessSystemUser_system_headlessMode() {
+        mockIsHeadlessSystemUserMode(true);
+        assertThat(UserHelper.isHeadlessSystemUser(UserHandle.USER_SYSTEM)).isTrue();
+    }
+
+    @Test
+    public void testIsHeadlessSystemUser_system_nonHeadlessMode() {
+        mockIsHeadlessSystemUserMode(false);
+        assertThat(UserHelper.isHeadlessSystemUser(UserHandle.USER_SYSTEM)).isFalse();
+    }
+
+    @Test
+    public void testIsHeadlessSystemUser_nonSystem_headlessMode() {
+        mockIsHeadlessSystemUserMode(true);
+        assertThat(UserHelper.isHeadlessSystemUser(10)).isFalse();
+    }
+
+    @Test
+    public void testIsHeadlessSystemUser_nonSystem_nonHeadlessMode() {
+        mockIsHeadlessSystemUserMode(false);
+        assertThat(UserHelper.isHeadlessSystemUser(10)).isFalse();
+    }
+}
diff --git a/tests/carservice_unit_test/src/android/car/vms/VmsSubscriptionHelperTest.java b/tests/carservice_unit_test/src/android/car/vms/VmsSubscriptionHelperTest.java
new file mode 100644
index 0000000..d12447c
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/vms/VmsSubscriptionHelperTest.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.vms;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import static java.util.Collections.emptySet;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VmsSubscriptionHelperTest {
+    private static final VmsLayer LAYER1 = new VmsLayer(1, 1, 1);
+    private static final VmsLayer LAYER2 = new VmsLayer(2, 1, 1);
+    private static final VmsLayer LAYER3 = new VmsLayer(3, 1, 1);
+
+    private static final int PROVIDER_ID1 = 12345;
+    private static final int PROVIDER_ID2 = 54321;
+    private static final int PROVIDER_ID3 = 99999;
+
+    private final VmsSubscriptionHelper mSubscriptionHelper =
+            new VmsSubscriptionHelper(this::handleUpdate);
+
+    private Set<VmsAssociatedLayer> mSubscriptionUpdate;
+    private int mSubscriptionUpdateCount;
+    private boolean mUpdateThrowsException;
+
+    @Test
+    public void testSubscribe_SingleLayer() {
+        mSubscriptionHelper.subscribe(LAYER1);
+
+        assertThat(mSubscriptionUpdateCount).isEqualTo(1);
+        assertSubscriptions(new VmsAssociatedLayer(LAYER1, emptySet()));
+    }
+
+    @Test
+    public void testSubscribe_SingleLayer_IgnoreDuplicates() {
+        mSubscriptionHelper.subscribe(LAYER1);
+        mSubscriptionHelper.subscribe(LAYER1);
+
+        assertThat(mSubscriptionUpdateCount).isEqualTo(1);
+        assertSubscriptions(new VmsAssociatedLayer(LAYER1, emptySet()));
+    }
+
+    @Test
+    public void testSubscribe_SingleLayer_RetryAfterException() {
+        mUpdateThrowsException = true;
+        assertThrows(
+                UpdateHandlerException.class,
+                () -> mSubscriptionHelper.subscribe(LAYER1));
+
+        mUpdateThrowsException = false;
+        mSubscriptionHelper.subscribe(LAYER1);
+
+        assertThat(mSubscriptionUpdateCount).isEqualTo(2);
+        assertSubscriptions(new VmsAssociatedLayer(LAYER1, emptySet()));
+    }
+
+    @Test
+    public void testUnsubscribe_SingleLayer() {
+        mSubscriptionHelper.subscribe(LAYER1);
+        mSubscriptionHelper.unsubscribe(LAYER1);
+
+        assertThat(mSubscriptionUpdateCount).isEqualTo(2);
+        assertEmptySubscriptions();
+    }
+
+    @Test
+    public void testUnsubscribe_SingleLayer_IgnoreUnknown() {
+        mSubscriptionHelper.subscribe(LAYER1);
+        mSubscriptionHelper.unsubscribe(LAYER2);
+
+        assertThat(mSubscriptionUpdateCount).isEqualTo(1);
+        assertSubscriptions(new VmsAssociatedLayer(LAYER1, emptySet()));
+    }
+
+    @Test
+    public void testUnsubscribe_SingleLayer_RetryAfterException() {
+        mSubscriptionHelper.subscribe(LAYER1);
+        mUpdateThrowsException = true;
+        assertThrows(
+                UpdateHandlerException.class,
+                () -> mSubscriptionHelper.unsubscribe(LAYER1));
+
+        mUpdateThrowsException = false;
+        mSubscriptionHelper.unsubscribe(LAYER1);
+
+        assertThat(mSubscriptionUpdateCount).isEqualTo(3);
+        assertEmptySubscriptions();
+    }
+
+    @Test
+    public void testSubscribe_MultipleLayers() {
+        mSubscriptionHelper.subscribe(LAYER1);
+        mSubscriptionHelper.subscribe(LAYER2);
+        mSubscriptionHelper.subscribe(LAYER3);
+
+        assertThat(mSubscriptionUpdateCount).isEqualTo(3);
+        assertSubscriptions(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER2, emptySet()),
+                new VmsAssociatedLayer(LAYER3, emptySet()));
+    }
+
+    @Test
+    public void testUnsubscribe_MultipleLayers() {
+        mSubscriptionHelper.subscribe(LAYER1);
+        mSubscriptionHelper.subscribe(LAYER2);
+        mSubscriptionHelper.subscribe(LAYER3);
+        mSubscriptionHelper.unsubscribe(LAYER2);
+
+        assertThat(mSubscriptionUpdateCount).isEqualTo(4);
+        assertSubscriptions(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER3, emptySet()));
+    }
+
+    @Test
+    public void testSubscribe_SingleLayerAndProvider() {
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID1);
+
+        assertThat(mSubscriptionUpdateCount).isEqualTo(1);
+        assertSubscriptions(new VmsAssociatedLayer(LAYER1, asSet(PROVIDER_ID1)));
+    }
+
+    @Test
+    public void testSubscribe_SingleLayerAndProvider_IgnoreDuplicates() {
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID1);
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID1);
+
+        assertThat(mSubscriptionUpdateCount).isEqualTo(1);
+        assertSubscriptions(new VmsAssociatedLayer(LAYER1, asSet(PROVIDER_ID1)));
+    }
+
+    @Test
+    public void testSubscribe_SingleLayerAndProvider_RetryAfterException() {
+        mUpdateThrowsException = true;
+        assertThrows(
+                UpdateHandlerException.class,
+                () -> mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID1));
+
+        mUpdateThrowsException = false;
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID1);
+
+        assertThat(mSubscriptionUpdateCount).isEqualTo(2);
+        assertSubscriptions(new VmsAssociatedLayer(LAYER1, asSet(PROVIDER_ID1)));
+    }
+
+    @Test
+    public void testUnsubscribe_SingleLayerAndProvider() {
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID1);
+        mSubscriptionHelper.unsubscribe(LAYER1, PROVIDER_ID1);
+
+        assertThat(mSubscriptionUpdateCount).isEqualTo(2);
+        assertEmptySubscriptions();
+    }
+
+    @Test
+    public void testUnsubscribe_SingleLayerAndProvider_IgnoreUnknown() {
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID1);
+        mSubscriptionHelper.unsubscribe(LAYER1, PROVIDER_ID2);
+
+        assertThat(mSubscriptionUpdateCount).isEqualTo(1);
+        assertSubscriptions(new VmsAssociatedLayer(LAYER1, asSet(PROVIDER_ID1)));
+    }
+
+    @Test
+    public void testUnubscribe_SingleLayerAndProvider_RetryAfterException() {
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID1);
+        mUpdateThrowsException = true;
+        assertThrows(
+                UpdateHandlerException.class,
+                () -> mSubscriptionHelper.unsubscribe(LAYER1, PROVIDER_ID1));
+
+        mUpdateThrowsException = false;
+        mSubscriptionHelper.unsubscribe(LAYER1, PROVIDER_ID1);
+
+        assertThat(mSubscriptionUpdateCount).isEqualTo(3);
+        assertEmptySubscriptions();
+    }
+
+    @Test
+    public void testSubscribe_SingleLayerAndMultipleProviders() {
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID1);
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID2);
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID3);
+
+        assertThat(mSubscriptionUpdateCount).isEqualTo(3);
+        assertSubscriptions(
+                new VmsAssociatedLayer(LAYER1, asSet(PROVIDER_ID1, PROVIDER_ID2, PROVIDER_ID3)));
+    }
+
+    @Test
+    public void testUnsubscribe_SingleLayerAndMultipleProviders() {
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID1);
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID2);
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID3);
+        mSubscriptionHelper.unsubscribe(LAYER1, PROVIDER_ID2);
+
+        assertThat(mSubscriptionUpdateCount).isEqualTo(4);
+        assertSubscriptions(new VmsAssociatedLayer(LAYER1, asSet(PROVIDER_ID1, PROVIDER_ID3)));
+    }
+
+    @Test
+    public void testSubscribe_MultipleLayersAndProvider() {
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID1);
+        mSubscriptionHelper.subscribe(LAYER2, PROVIDER_ID1);
+        mSubscriptionHelper.subscribe(LAYER3, PROVIDER_ID1);
+
+        assertThat(mSubscriptionUpdateCount).isEqualTo(3);
+        assertSubscriptions(
+                new VmsAssociatedLayer(LAYER1, asSet(PROVIDER_ID1)),
+                new VmsAssociatedLayer(LAYER2, asSet(PROVIDER_ID1)),
+                new VmsAssociatedLayer(LAYER3, asSet(PROVIDER_ID1)));
+    }
+
+    @Test
+    public void testUnsubscribe_MultipleLayersAndProvider() {
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID1);
+        mSubscriptionHelper.subscribe(LAYER2, PROVIDER_ID1);
+        mSubscriptionHelper.subscribe(LAYER3, PROVIDER_ID1);
+        mSubscriptionHelper.unsubscribe(LAYER2, PROVIDER_ID1);
+
+        assertThat(mSubscriptionUpdateCount).isEqualTo(4);
+        assertSubscriptions(
+                new VmsAssociatedLayer(LAYER1, asSet(PROVIDER_ID1)),
+                new VmsAssociatedLayer(LAYER3, asSet(PROVIDER_ID1)));
+    }
+
+    @Test
+    public void testSubscribe_MultipleLayersAndMultipleProviders() {
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID1);
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID2);
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID3);
+        mSubscriptionHelper.subscribe(LAYER2, PROVIDER_ID2);
+        mSubscriptionHelper.subscribe(LAYER3, PROVIDER_ID3);
+
+        assertThat(mSubscriptionUpdateCount).isEqualTo(5);
+        assertSubscriptions(
+                new VmsAssociatedLayer(LAYER1, asSet(PROVIDER_ID1, PROVIDER_ID2, PROVIDER_ID3)),
+                new VmsAssociatedLayer(LAYER2, asSet(PROVIDER_ID2)),
+                new VmsAssociatedLayer(LAYER3, asSet(PROVIDER_ID3))
+        );
+    }
+
+    @Test
+    public void testUnsubscribe_MultipleLayersAndMultipleProviders() {
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID1);
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID2);
+        mSubscriptionHelper.subscribe(LAYER1, PROVIDER_ID3);
+        mSubscriptionHelper.subscribe(LAYER2, PROVIDER_ID2);
+        mSubscriptionHelper.subscribe(LAYER3, PROVIDER_ID3);
+        mSubscriptionHelper.unsubscribe(LAYER1, PROVIDER_ID2);
+        mSubscriptionHelper.unsubscribe(LAYER3, PROVIDER_ID3);
+
+        assertThat(mSubscriptionUpdateCount).isEqualTo(7);
+        assertSubscriptions(
+                new VmsAssociatedLayer(LAYER1, asSet(PROVIDER_ID1, PROVIDER_ID3)),
+                new VmsAssociatedLayer(LAYER2, asSet(PROVIDER_ID2)));
+    }
+
+    private void handleUpdate(Set<VmsAssociatedLayer> subscriptionUpdate) {
+        mSubscriptionUpdate = subscriptionUpdate;
+        mSubscriptionUpdateCount++;
+        if (mUpdateThrowsException) {
+            throw new UpdateHandlerException();
+        }
+    }
+
+    private void assertEmptySubscriptions() {
+        assertSubscriptions();
+    }
+
+    private void assertSubscriptions(VmsAssociatedLayer... associatedLayers) {
+        Set<VmsAssociatedLayer> subscriptions = asSet(associatedLayers);
+        assertThat(mSubscriptionUpdate).isEqualTo(subscriptions);
+        assertThat(mSubscriptionHelper.getSubscriptions()).isEqualTo(subscriptions);
+    }
+
+    @SafeVarargs
+    private static <T> Set<T> asSet(T... values) {
+        return new HashSet<>(Arrays.asList(values));
+    }
+
+    private static class UpdateHandlerException extends RuntimeException {}
+}
diff --git a/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java b/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java
new file mode 100644
index 0000000..223e3e1
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.watchdoglib;
+
+import static android.car.test.mocks.AndroidMockitoHelper.mockQueryService;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.testng.Assert.assertThrows;
+
+import android.automotive.watchdog.ICarWatchdog;
+import android.automotive.watchdog.ICarWatchdogClient;
+import android.automotive.watchdog.ICarWatchdogMonitor;
+import android.automotive.watchdog.PowerCycle;
+import android.automotive.watchdog.StateType;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.Spy;
+import org.mockito.quality.Strictness;
+
+import java.util.ArrayList;
+
+/**
+ * <p>This class contains unit tests for the {@link CarWatchdogDaemonHelper}.
+ */
+public class CarWatchdogDaemonHelperTest {
+
+    private static final String CAR_WATCHDOG_DAEMON_INTERFACE =
+            "android.automotive.watchdog.ICarWatchdog/default";
+
+    @Mock CarWatchdogDaemonHelper.OnConnectionChangeListener mListener;
+    @Mock private IBinder mBinder = new Binder();
+    @Spy private ICarWatchdog mFakeCarWatchdog = new FakeCarWatchdog();
+    private CarWatchdogDaemonHelper mCarWatchdogDaemonHelper;
+    private MockitoSession mMockSession;
+
+    @Before
+    public void setUp() {
+        mMockSession = mockitoSession()
+                .initMocks(this)
+                .strictness(Strictness.LENIENT)
+                .spyStatic(ServiceManager.class)
+                .startMocking();
+        mockQueryService(CAR_WATCHDOG_DAEMON_INTERFACE, mBinder, mFakeCarWatchdog);
+        mCarWatchdogDaemonHelper = new CarWatchdogDaemonHelper();
+        mCarWatchdogDaemonHelper.connect();
+    }
+
+    @After
+    public void tearDown() {
+        mMockSession.finishMocking();
+    }
+
+    @Test
+    public void testConnection() {
+        CarWatchdogDaemonHelper carWatchdogDaemonHelper = new CarWatchdogDaemonHelper();
+        carWatchdogDaemonHelper.addOnConnectionChangeListener(mListener);
+        carWatchdogDaemonHelper.connect();
+        verify(mListener).onConnectionChange(true);
+    }
+
+    @Test
+    public void testRemoveConnectionChangeListener() {
+        CarWatchdogDaemonHelper carWatchdogDaemonHelper = new CarWatchdogDaemonHelper();
+        carWatchdogDaemonHelper.addOnConnectionChangeListener(mListener);
+        carWatchdogDaemonHelper.removeOnConnectionChangeListener(mListener);
+        carWatchdogDaemonHelper.connect();
+        verify(mListener, never()).onConnectionChange(true);
+    }
+
+    @Test
+    public void testIndirectCall_RegisterUnregisterClient() throws Exception {
+        ICarWatchdogClient client = new ICarWatchdogClient.Default();
+        mCarWatchdogDaemonHelper.registerClient(client, 0);
+        verify(mFakeCarWatchdog).registerClient(client, 0);
+        mCarWatchdogDaemonHelper.unregisterClient(client);
+        verify(mFakeCarWatchdog).unregisterClient(client);
+    }
+
+    @Test
+    public void testIndirectCall_RegisterUnregisterMediator() throws Exception {
+        ICarWatchdogClient mediator = new ICarWatchdogClient.Default();
+        mCarWatchdogDaemonHelper.registerMediator(mediator);
+        verify(mFakeCarWatchdog).registerMediator(mediator);
+        mCarWatchdogDaemonHelper.unregisterMediator(mediator);
+        verify(mFakeCarWatchdog).unregisterMediator(mediator);
+    }
+
+    @Test
+    public void testIndirectCall_RegisterUnregisterMonitor() throws Exception {
+        ICarWatchdogMonitor monitor = new ICarWatchdogMonitor.Default();
+        mCarWatchdogDaemonHelper.registerMonitor(monitor);
+        verify(mFakeCarWatchdog).registerMonitor(monitor);
+        mCarWatchdogDaemonHelper.unregisterMonitor(monitor);
+        verify(mFakeCarWatchdog).unregisterMonitor(monitor);
+    }
+
+    @Test
+    public void testIndirectCall_TellClientAlive() throws Exception {
+        ICarWatchdogClient client = new ICarWatchdogClient.Default();
+        mCarWatchdogDaemonHelper.tellClientAlive(client, 123456);
+        verify(mFakeCarWatchdog).tellClientAlive(client, 123456);
+    }
+
+    @Test
+    public void testIndirectCall_TellMediatorAlive() throws Exception {
+        ICarWatchdogClient mediator = new ICarWatchdogClient.Default();
+        int[] pids = new int[]{111};
+        mCarWatchdogDaemonHelper.tellMediatorAlive(mediator, pids, 123456);
+        verify(mFakeCarWatchdog).tellMediatorAlive(mediator, pids, 123456);
+    }
+
+    @Test
+    public void testIndirectCall_TellDumpFinished() throws Exception {
+        ICarWatchdogMonitor monitor = new ICarWatchdogMonitor.Default();
+        mCarWatchdogDaemonHelper.tellDumpFinished(monitor, 123456);
+        verify(mFakeCarWatchdog).tellDumpFinished(monitor, 123456);
+    }
+
+    @Test
+    public void testIndirectCall_NotifySystemStateChange() throws Exception {
+        mCarWatchdogDaemonHelper.notifySystemStateChange(StateType.POWER_CYCLE,
+                PowerCycle.POWER_CYCLE_SUSPEND, -1);
+        verify(mFakeCarWatchdog).notifySystemStateChange(StateType.POWER_CYCLE,
+                PowerCycle.POWER_CYCLE_SUSPEND, -1);
+    }
+
+    /*
+     * Test that the {@link CarWatchdogDaemonHelper} throws {@code IllegalArgumentException} when
+     * trying to register already-registered client again.
+     */
+    @Test
+    public void testMultipleRegistration() throws Exception {
+        ICarWatchdogClient client = new ICarWatchdogClientImpl();
+        mCarWatchdogDaemonHelper.registerMediator(client);
+        assertThrows(IllegalArgumentException.class,
+                () -> mCarWatchdogDaemonHelper.registerMediator(client));
+    }
+
+    /*
+     * Test that the {@link CarWatchdogDaemonHelper} throws {@code IllegalArgumentException} when
+     * trying to unregister not-registered client.
+     */
+    @Test
+    public void testInvalidUnregistration() throws Exception {
+        ICarWatchdogClient client = new ICarWatchdogClientImpl();
+        assertThrows(IllegalArgumentException.class,
+                () -> mCarWatchdogDaemonHelper.unregisterMediator(client));
+    }
+
+    // FakeCarWatchdog mimics ICarWatchdog daemon in local process.
+    private final class FakeCarWatchdog extends ICarWatchdog.Default {
+
+        private final ArrayList<ICarWatchdogClient> mClients = new ArrayList<>();
+
+        @Override
+        public void registerMediator(ICarWatchdogClient mediator) throws RemoteException {
+            for (ICarWatchdogClient client : mClients) {
+                if (client == mediator) {
+                    throw new IllegalArgumentException("Already registered mediator");
+                }
+            }
+            mClients.add(mediator);
+        }
+
+        @Override
+        public void unregisterMediator(ICarWatchdogClient mediator) throws RemoteException {
+            for (ICarWatchdogClient client : mClients) {
+                if (client == mediator) {
+                    mClients.remove(mediator);
+                    return;
+                }
+            }
+            throw new IllegalArgumentException("Not registered mediator");
+        }
+
+    }
+
+    private final class ICarWatchdogClientImpl extends ICarWatchdogClient.Stub {
+        @Override
+        public void checkIfAlive(int sessionId, int timeout) {}
+
+        @Override
+        public void prepareProcessTermination() {}
+
+        @Override
+        public int getInterfaceVersion() {
+            return this.VERSION;
+        }
+
+        @Override
+        public String getInterfaceHash() {
+            return this.HASH;
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/AppFocusServiceTest.java b/tests/carservice_unit_test/src/com/android/car/AppFocusServiceTest.java
new file mode 100644
index 0000000..0e7731b
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/AppFocusServiceTest.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+
+import android.car.Car;
+import android.car.CarAppFocusManager;
+import android.car.IAppFocusListener;
+import android.car.IAppFocusOwnershipCallback;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(MockitoJUnitRunner.class)
+public class AppFocusServiceTest {
+
+    private static final long WAIT_TIMEOUT_MS = 500;
+
+    private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private SystemActivityMonitoringService mSystemActivityMonitoringService;
+    @Mock
+    private Car mCar;
+
+    private AppFocusService mService;
+    private CarAppFocusManager mCarAppFocusManager1;
+    private CarAppFocusManager mCarAppFocusManager2;
+
+    private AppFocusChangedListener mAppFocusChangedListener1 = new AppFocusChangedListener();
+
+    private AppFocusOwnershipCallback mAppFocusOwnershipCallback1 = new AppFocusOwnershipCallback();
+
+    @Before
+    public void setUp() {
+        mService = new AppFocusService(mContext, mSystemActivityMonitoringService);
+        mService.init();
+        doReturn(mMainHandler).when(mCar).getEventHandler();
+        mCarAppFocusManager1 = new CarAppFocusManager(mCar, mService.asBinder());
+        mCarAppFocusManager2 = new CarAppFocusManager(mCar, mService.asBinder());
+    }
+
+    @Test
+    public void testSingleOwner() throws Exception {
+        mCarAppFocusManager2.addFocusListener(mAppFocusChangedListener1,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+
+        int r = mCarAppFocusManager1.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION,
+                mAppFocusOwnershipCallback1);
+        assertThat(r).isEqualTo(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED);
+        assertThat(mCarAppFocusManager1.isOwningFocus(mAppFocusOwnershipCallback1,
+                CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED)).isTrue();
+        waitForNavFocusChangeAndAssert(mAppFocusChangedListener1, true);
+
+        mAppFocusChangedListener1.resetWait();
+        mCarAppFocusManager1.abandonAppFocus(mAppFocusOwnershipCallback1,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        assertThat(mCarAppFocusManager1.isOwningFocus(mAppFocusOwnershipCallback1,
+                CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED)).isFalse();
+        waitForNavFocusChangeAndAssert(mAppFocusChangedListener1, false);
+    }
+
+    private void waitForNavFocusChangeAndAssert(AppFocusChangedListener listener, boolean isActive)
+            throws Exception {
+        listener.waitForEvent();
+        if (isActive) {
+            assertThat(listener.mLastActive).isTrue();
+        } else {
+            assertThat(listener.mLastActive).isFalse();
+        }
+        assertThat(listener.mLastAppType).isEqualTo(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+    }
+
+    @Test
+    public void testOwnerBinderDeath() throws Exception {
+        mCarAppFocusManager2.addFocusListener(mAppFocusChangedListener1,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+
+        int r = mCarAppFocusManager1.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION,
+                mAppFocusOwnershipCallback1);
+        assertThat(r).isEqualTo(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED);
+        assertThat(mCarAppFocusManager1.isOwningFocus(mAppFocusOwnershipCallback1,
+                CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED)).isTrue();
+        waitForNavFocusChangeAndAssert(mAppFocusChangedListener1, true);
+
+        assertThat(mService.mAllOwnershipClients.getInterfaces()).hasSize(1);
+        BinderInterfaceContainer.BinderInterface<IAppFocusOwnershipCallback> binder =
+                mService.mAllOwnershipClients.getInterfaces().iterator().next();
+        // Now fake binder death
+        mAppFocusChangedListener1.resetWait();
+        binder.binderDied();
+        assertThat(mService.mAllOwnershipClients.getInterfaces()).isEmpty();
+        waitForNavFocusChangeAndAssert(mAppFocusChangedListener1, false);
+    }
+
+    @Test
+    public void testListenerBinderDeath() throws Exception {
+
+        mCarAppFocusManager1.addFocusListener(mAppFocusChangedListener1,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        assertThat(mService.mAllChangeClients.getInterfaces()).hasSize(1);
+        BinderInterfaceContainer.BinderInterface<IAppFocusListener> binder =
+                mService.mAllChangeClients.getInterfaces().iterator().next();
+        binder.binderDied();
+        assertThat(mService.mAllChangeClients.getInterfaces()).isEmpty();
+    }
+
+    private class AppFocusChangedListener implements CarAppFocusManager.OnAppFocusChangedListener {
+
+        private final Semaphore mSemaphore = new Semaphore(0);
+        private int mLastAppType;
+        private boolean mLastActive;
+
+        @Override
+        public void onAppFocusChanged(int appType, boolean active) {
+            mLastAppType = appType;
+            mLastActive = active;
+            mSemaphore.release();
+        }
+
+        public void waitForEvent() throws Exception {
+            assertThat(mSemaphore.tryAcquire(WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
+        }
+
+        public void resetWait() {
+            mSemaphore.drainPermits();
+        }
+    }
+
+    private class AppFocusOwnershipCallback implements
+            CarAppFocusManager.OnAppFocusOwnershipCallback {
+
+        private final Semaphore mSemaphore = new Semaphore(0);
+        private int mGrantedAppTypes;
+
+        @Override
+        public void onAppFocusOwnershipLost(int appType) {
+            mGrantedAppTypes = mGrantedAppTypes & ~appType;
+            mSemaphore.release();
+        }
+
+        @Override
+        public void onAppFocusOwnershipGranted(int appType) {
+            mGrantedAppTypes = mGrantedAppTypes | appType;
+            mSemaphore.release();
+        }
+
+        public void waitForEvent() throws Exception {
+            mSemaphore.tryAcquire(WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        }
+
+        public void resetWait() {
+            mSemaphore.drainPermits();
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/BluetoothDeviceConnectionPolicyTest.java b/tests/carservice_unit_test/src/com/android/car/BluetoothDeviceConnectionPolicyTest.java
index f84d5f4..52b6e36 100644
--- a/tests/carservice_unit_test/src/com/android/car/BluetoothDeviceConnectionPolicyTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/BluetoothDeviceConnectionPolicyTest.java
@@ -16,7 +16,12 @@
 
 package com.android.car;
 
-import static org.mockito.Mockito.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.bluetooth.BluetoothAdapter;
 import android.car.hardware.power.CarPowerManager;
@@ -31,7 +36,7 @@
 import android.test.mock.MockContentProvider;
 import android.test.mock.MockContentResolver;
 
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.filters.RequiresDevice;
 
 import org.junit.After;
 import org.junit.Assert;
@@ -39,8 +44,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 import org.mockito.invocation.InvocationOnMock;
+import org.mockito.junit.MockitoJUnitRunner;
 import org.mockito.stubbing.Answer;
 
 /**
@@ -49,7 +54,8 @@
  * Run:
  * atest BluetoothDeviceConnectionPolicyTest
  */
-@RunWith(AndroidJUnit4.class)
+@RequiresDevice
+@RunWith(MockitoJUnitRunner.class)
 public class BluetoothDeviceConnectionPolicyTest {
     private BluetoothDeviceConnectionPolicy mPolicy;
 
@@ -71,7 +77,7 @@
 
     @Before
     public void setUp() {
-        mMockContentResolver = new MockContentResolver(mMockContext);
+        mMockContentResolver = new MockContentResolver(null);
         mMockContentProvider = new MockContentProvider() {
             @Override
             public Bundle call(String method, String request, Bundle args) {
@@ -80,7 +86,6 @@
         };
         mMockContentResolver.addProvider(Settings.AUTHORITY, mMockContentProvider);
 
-        MockitoAnnotations.initMocks(this);
         when(mMockContext.getResources()).thenReturn(mMockResources);
         when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
         when(mMockContext.getApplicationContext()).thenReturn(mMockContext);
@@ -109,17 +114,8 @@
 
     @After
     public void tearDown() {
-        mPowerStateListener = null;
         mPolicy.release();
-        mPolicy = null;
         mBluetoothAdapterHelper.release();
-        mBluetoothAdapterHelper = null;
-        mReceiver = null;
-        mMockBluetoothService = null;
-        mMockResources = null;
-        mMockContext = null;
-        mMockContentProvider = null;
-        mMockContentResolver = null;
     }
 
     //--------------------------------------------------------------------------------------------//
diff --git a/tests/carservice_unit_test/src/com/android/car/BluetoothProfileDeviceManagerTest.java b/tests/carservice_unit_test/src/com/android/car/BluetoothProfileDeviceManagerTest.java
index b5837fe..be8f8f3 100644
--- a/tests/carservice_unit_test/src/com/android/car/BluetoothProfileDeviceManagerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/BluetoothProfileDeviceManagerTest.java
@@ -41,7 +41,7 @@
 import android.text.TextUtils;
 
 import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.filters.RequiresDevice;
 
 import com.android.internal.util.test.BroadcastInterceptingContext;
 import com.android.internal.util.test.FakeSettingsProvider;
@@ -53,8 +53,8 @@
 import org.junit.runner.RunWith;
 import org.mockito.InOrder;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 import org.mockito.invocation.InvocationOnMock;
+import org.mockito.junit.MockitoJUnitRunner;
 import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
@@ -68,7 +68,8 @@
  * Run:
  * atest BluetoothProfileDeviceManagerTest
  */
-@RunWith(AndroidJUnit4.class)
+@RequiresDevice
+@RunWith(MockitoJUnitRunner.class)
 public class BluetoothProfileDeviceManagerTest {
     private static final int CONNECT_LATENCY_MS = 100;
     private static final int CONNECT_TIMEOUT_MS = 8000;
@@ -105,7 +106,7 @@
     private final String mSettingsKey = KEY_BLUETOOTH_HFP_CLIENT_DEVICES;
     private final String mConnectionAction = BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED;
     private ParcelUuid[] mUuids = new ParcelUuid[] {
-            BluetoothUuid.Handsfree_AG,
+            BluetoothUuid.HFP_AG,
             BluetoothUuid.HSP_AG};
     private ParcelUuid[] mBadUuids = new ParcelUuid[] {
             BluetoothUuid.PANU};
@@ -158,9 +159,6 @@
 
     @Before
     public void setUp() {
-
-        MockitoAnnotations.initMocks(this);
-
         mMockContext = new MockContext(InstrumentationRegistry.getTargetContext());
         setSettingsDeviceList("");
         assertSettingsContains("");
@@ -1178,6 +1176,30 @@
      * - The device manager is initialized, there are no devices in the list.
      *
      * Actions:
+     * - A Bonding state change with state == BOND_BONDING is received
+     * - A Uuid set is received for a device that has PRIORITY_UNDEFINED
+     *
+     * Outcome:
+     * - The device has its priority updated to PRIORITY_ON.
+     */
+    @Test
+    public void testReceiveUuidDevicePriorityUndefinedBonding_setPriorityOn() throws Exception {
+        setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST);
+        BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SINGLE_DEVICE_LIST.get(0));
+        mockDevicePriority(device, BluetoothProfile.PRIORITY_UNDEFINED);
+        sendBondStateChanged(device, BluetoothDevice.BOND_BONDING);
+        sendDeviceUuids(device, mUuids);
+        assertDeviceList(EMPTY_DEVICE_LIST);
+        verify(mMockProxies, times(1)).setProfilePriority(mProfileId, device,
+                BluetoothProfile.PRIORITY_ON);
+    }
+
+        /**
+     * Preconditions:
+     * - The device manager is initialized, there are no devices in the list.
+     * - The designated device is not in a bonding state.
+     *
+     * Actions:
      * - A Uuid set is received for a device that has PRIORITY_UNDEFINED
      *
      * Outcome:
@@ -1190,7 +1212,7 @@
         mockDevicePriority(device, BluetoothProfile.PRIORITY_UNDEFINED);
         sendDeviceUuids(device, mUuids);
         assertDeviceList(EMPTY_DEVICE_LIST);
-        verify(mMockProxies, times(1)).setProfilePriority(mProfileId, device,
+        verify(mMockProxies, times(0)).setProfilePriority(mProfileId, device,
                 BluetoothProfile.PRIORITY_ON);
     }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/CarBluetoothServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarBluetoothServiceTest.java
index 4b5f9bb..3d95204 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarBluetoothServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarBluetoothServiceTest.java
@@ -16,9 +16,11 @@
 
 package com.android.car;
 
-import static org.mockito.Mockito.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
 
-import android.car.ICarUserService;
+import android.car.IPerUserCarService;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
@@ -28,16 +30,14 @@
 import android.test.mock.MockContentProvider;
 import android.test.mock.MockContentResolver;
 
-import androidx.test.runner.AndroidJUnit4;
-
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 import org.mockito.invocation.InvocationOnMock;
+import org.mockito.junit.MockitoJUnitRunner;
 import org.mockito.stubbing.Answer;
 
 /**
@@ -52,9 +52,8 @@
  * 2) Verify that, when the useDefaultConnectionPolicy resource overlay flag is false, we do not
  *    create and use the default connection policy.
  */
-@RunWith(AndroidJUnit4.class)
+@RunWith(MockitoJUnitRunner.class)
 public class CarBluetoothServiceTest {
-
     private CarBluetoothService mCarBluetoothService;
 
     @Mock private Context mMockContext;
@@ -64,7 +63,7 @@
     @Mock private PackageManager mMockPackageManager;
 
     @Mock private PerUserCarServiceHelper mMockUserSwitchService;
-    @Mock private ICarUserService mMockCarUserService;
+    @Mock private IPerUserCarService mMockPerUserCarService;
     @Mock private CarBluetoothUserService mMockBluetoothUserService;
     private PerUserCarServiceHelper.ServiceCallback mUserSwitchCallback;
 
@@ -74,7 +73,7 @@
 
     @Before
     public void setUp() {
-        mMockContentResolver = new MockContentResolver(mMockContext);
+        mMockContentResolver = new MockContentResolver(null);
         mMockContentProvider = new MockContentProvider() {
             @Override
             public Bundle call(String method, String request, Bundle args) {
@@ -83,7 +82,6 @@
         };
         mMockContentResolver.addProvider(Settings.AUTHORITY, mMockContentProvider);
 
-        MockitoAnnotations.initMocks(this);
         when(mMockContext.getResources()).thenReturn(mMockResources);
         when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
         when(mMockContext.getApplicationContext()).thenReturn(mMockContext);
@@ -105,7 +103,7 @@
                 PerUserCarServiceHelper.ServiceCallback.class));
 
         try {
-            when(mMockCarUserService.getBluetoothUserService()).thenReturn(
+            when(mMockPerUserCarService.getBluetoothUserService()).thenReturn(
                     mMockBluetoothUserService);
         } catch (RemoteException e) {
             Assert.fail();
@@ -140,7 +138,7 @@
                 R.bool.useDefaultBluetoothConnectionPolicy)).thenReturn(true);
         mCarBluetoothService = new CarBluetoothService(mMockContext, mMockUserSwitchService);
         mCarBluetoothService.init();
-        mUserSwitchCallback.onServiceConnected(mMockCarUserService);
+        mUserSwitchCallback.onServiceConnected(mMockPerUserCarService);
         Assert.assertTrue(mCarBluetoothService.isUsingDefaultConnectionPolicy());
     }
 
@@ -160,7 +158,7 @@
                 R.bool.useDefaultBluetoothConnectionPolicy)).thenReturn(false);
         mCarBluetoothService = new CarBluetoothService(mMockContext, mMockUserSwitchService);
         mCarBluetoothService.init();
-        mUserSwitchCallback.onServiceConnected(mMockCarUserService);
+        mUserSwitchCallback.onServiceConnected(mMockPerUserCarService);
         Assert.assertFalse(mCarBluetoothService.isUsingDefaultConnectionPolicy());
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/CarConfigurationServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarConfigurationServiceTest.java
index 9254a56..e39f5c8 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarConfigurationServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarConfigurationServiceTest.java
@@ -29,25 +29,18 @@
 import android.car.settings.SpeedBumpConfiguration;
 
 import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.json.JSONException;
 import org.json.JSONObject;
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnitRunner;
 
 /**
  * Tests for {@link CarConfigurationService}.
  */
-@RunWith(AndroidJUnit4.class)
+@RunWith(MockitoJUnitRunner.class)
 public class CarConfigurationServiceTest {
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-    }
-
     @Test
     public void testJsonResourceSuccessfullyRead() {
         // Use the default JsonReader to check that the resource JSON can be retrieved.
diff --git a/tests/carservice_unit_test/src/com/android/car/CarInputServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarInputServiceTest.java
index b32df7f..cabab88 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarInputServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarInputServiceTest.java
@@ -30,16 +30,25 @@
 import static org.mockito.Mockito.ignoreStubs;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import android.annotation.UserIdInt;
+import android.app.IActivityManager;
 import android.car.CarProjectionManager;
 import android.car.input.CarInputHandlingService.InputFilter;
 import android.car.input.ICarInputListener;
+import android.car.testapi.BlockingUserLifecycleListener;
+import android.car.user.CarUserManager;
+import android.car.userlib.CarUserManagerHelper;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -48,35 +57,42 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
 import android.service.voice.VoiceInteractionSession;
 import android.telecom.TelecomManager;
+import android.test.mock.MockContentResolver;
 import android.view.KeyEvent;
 
 import androidx.test.core.app.ApplicationProvider;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.car.hal.InputHalService;
+import com.android.car.hal.UserHalService;
+import com.android.car.user.CarUserService;
 import com.android.internal.app.AssistUtils;
+import com.android.internal.util.test.BroadcastInterceptingContext;
+import com.android.internal.util.test.FakeSettingsProvider;
 
 import com.google.common.collect.Range;
 
+import org.junit.After;
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.Spy;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import java.util.BitSet;
 import java.util.function.IntSupplier;
 import java.util.function.Supplier;
 
-@RunWith(AndroidJUnit4.class)
+@RunWith(MockitoJUnitRunner.class)
 public class CarInputServiceTest {
-    @Rule public MockitoRule rule = MockitoJUnit.rule();
+    // TODO(b/152069895): decrease value once refactored. In fact, it should not even use
+    // runWithScissors(), but only rely on CountdownLatches
+    private static final long DEFAULT_TIMEOUT_MS = 5_000;
 
     @Mock InputHalService mInputHalService;
     @Mock TelecomManager mTelecomManager;
@@ -88,12 +104,54 @@
     @Spy Context mContext = ApplicationProvider.getApplicationContext();
     @Spy Handler mHandler = new Handler(Looper.getMainLooper());
 
+    private MockContext mMockContext;
+    private CarUserService mCarUserService;
     private CarInputService mCarInputService;
 
+    /**
+     * A mock {@link Context}.
+     * This class uses a mock {@link ContentResolver} and {@link android.content.ContentProvider} to
+     * avoid changing real system settings. Besides, to emulate the case where the OEM changes
+     * {@link R.string.rotaryService} to empty in the resource file (e.g., the OEM doesn't want to
+     * start RotaryService), this class allows to return a given String when retrieving {@link
+     * R.string.rotaryService}.
+     */
+    private static class MockContext extends BroadcastInterceptingContext {
+        private final MockContentResolver mContentResolver;
+        private final FakeSettingsProvider mContentProvider;
+        private final Resources mResources;
+
+        MockContext(Context base, String rotaryService) {
+            super(base);
+            FakeSettingsProvider.clearSettingsProvider();
+            mContentResolver = new MockContentResolver(this);
+            mContentProvider = new FakeSettingsProvider();
+            mContentResolver.addProvider(Settings.AUTHORITY, mContentProvider);
+
+            mResources = spy(base.getResources());
+            doReturn(rotaryService).when(mResources).getString(R.string.rotaryService);
+        }
+
+        void release() {
+            FakeSettingsProvider.clearSettingsProvider();
+        }
+
+        @Override
+        public ContentResolver getContentResolver() {
+            return mContentResolver;
+        }
+
+        @Override
+        public Resources getResources() {
+            return mResources;
+        }
+    }
+
     @Before
     public void setUp() {
-        mCarInputService = new CarInputService(mContext, mInputHalService, mHandler,
-                mTelecomManager, mAssistUtils, mDefaultMainListener, mLastCallSupplier,
+        mCarUserService = mock(CarUserService.class);
+        mCarInputService = new CarInputService(mContext, mInputHalService, mCarUserService,
+                mHandler, mTelecomManager, mAssistUtils, mDefaultMainListener, mLastCallSupplier,
                 /* customInputServiceComponent= */ null, mLongPressDelaySupplier);
 
         when(mInputHalService.isKeyInputSupported()).thenReturn(true);
@@ -104,6 +162,69 @@
     }
 
     @Test
+    public void rotaryServiceSettingsUpdated_whenRotaryServiceIsNotEmpty() throws Exception {
+        final String rotaryService = "com.android.car.rotary/com.android.car.rotary.RotaryService";
+        init(rotaryService);
+        assertThat(mMockContext.getString(R.string.rotaryService)).isEqualTo(rotaryService);
+
+        final int userId = 11;
+
+        // By default RotaryService is not enabled.
+        String enabledServices = Settings.Secure.getStringForUser(
+                mMockContext.getContentResolver(),
+                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                userId);
+        assertThat(enabledServices == null ? "" : enabledServices).doesNotContain(rotaryService);
+
+        String enabled = Settings.Secure.getStringForUser(
+                mMockContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_ENABLED,
+                userId);
+        assertThat(enabled).isNull();
+
+        // Enable RotaryService by sending user switch event.
+        sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, userId);
+
+        enabledServices = Settings.Secure.getStringForUser(
+                mMockContext.getContentResolver(),
+                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                userId);
+        assertThat(enabledServices).contains(rotaryService);
+
+        enabled = Settings.Secure.getStringForUser(
+                mMockContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_ENABLED,
+                userId);
+        assertThat(enabled).isEqualTo("1");
+    }
+
+    @Test
+    public void rotaryServiceSettingsNotUpdated_whenRotaryServiceIsEmpty() throws Exception {
+        final String rotaryService = "";
+        init(rotaryService);
+        assertThat(mMockContext.getString(R.string.rotaryService)).isEqualTo(rotaryService);
+
+        final int userId = 11;
+
+        // By default the Accessibility is disabled.
+        String enabled = Settings.Secure.getStringForUser(
+                mMockContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_ENABLED,
+                userId);
+        assertThat(enabled).isNull();
+
+        sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, userId);
+
+        // Sending user switch event shouldn't enable the Accessibility because RotaryService is
+        // empty.
+        enabled = Settings.Secure.getStringForUser(
+                mMockContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_ENABLED,
+                userId);
+        assertThat(enabled).isNull();
+    }
+
+    @Test
     public void ordinaryEvents_onMainDisplay_routedToInputManager() {
         KeyEvent event = send(Key.DOWN, KeyEvent.KEYCODE_ENTER, Display.MAIN);
 
@@ -462,6 +583,54 @@
         assertThat(timeCaptor.getValue()).isIn(Range.closed(then + systemDelay, now + systemDelay));
     }
 
+    @After
+    public void tearDown() {
+        if (mMockContext != null) {
+            mMockContext.release();
+            mMockContext = null;
+        }
+    }
+
+    /**
+     * Initializes {@link #mMockContext}, {@link #mCarUserService}, and {@link #mCarInputService}.
+     */
+    private void init(String rotaryService) {
+        mMockContext = new MockContext(mContext, rotaryService);
+
+        UserManager userManager = mock(UserManager.class);
+        UserInfo userInfo = mock(UserInfo.class);
+        doReturn(userInfo).when(userManager).getUserInfo(anyInt());
+        UserHalService userHal = mock(UserHalService.class);
+        CarUserManagerHelper carUserManagerHelper = mock(CarUserManagerHelper.class);
+        IActivityManager iActivityManager = mock(IActivityManager.class);
+        mCarUserService = new CarUserService(mMockContext, userHal, carUserManagerHelper,
+                userManager, iActivityManager, /* maxRunningUsers= */ 2);
+
+        mCarInputService = new CarInputService(mMockContext, mInputHalService, mCarUserService,
+                mHandler, mTelecomManager, mAssistUtils, mDefaultMainListener, mLastCallSupplier,
+                /* customInputServiceComponent= */ null, mLongPressDelaySupplier);
+        mCarInputService.init();
+    }
+
+    private void sendUserLifecycleEvent(@CarUserManager.UserLifecycleEventType int eventType,
+            @UserIdInt int userId) throws InterruptedException {
+        // Add a blocking listener to ensure CarUserService event notification is completed
+        // before proceeding with test execution.
+        BlockingUserLifecycleListener blockingListener =
+                BlockingUserLifecycleListener.forAnyEvent().build();
+        mCarUserService.addUserLifecycleListener(blockingListener);
+
+        runOnMainThreadAndWaitForIdle(() -> mCarUserService.onUserLifecycleEvent(eventType,
+                /* timestampMs= */ 0, /* fromUserId= */ UserHandle.USER_NULL, userId));
+        blockingListener.waitForAnyEvent();
+    }
+
+    private static void runOnMainThreadAndWaitForIdle(Runnable r) {
+        Handler.getMain().runWithScissors(r, DEFAULT_TIMEOUT_MS);
+        // Run empty runnable to make sure that all posted handlers are done.
+        Handler.getMain().runWithScissors(() -> { }, DEFAULT_TIMEOUT_MS);
+    }
+
     private enum Key {DOWN, UP}
 
     private enum Display {MAIN, INSTRUMENT_CLUSTER}
diff --git a/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java
index 5384005..8063d61 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java
@@ -31,11 +31,10 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.car.ICarUserService;
+import android.car.IPerUserCarService;
 import android.car.drivingstate.CarDrivingStateEvent;
 import android.car.drivingstate.ICarDrivingStateChangeListener;
 import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
-import android.car.userlib.CarUserManagerHelper;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -43,9 +42,9 @@
 import android.location.Location;
 import android.location.LocationManager;
 import android.os.SystemClock;
+import android.os.UserManager;
 
 import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.car.systeminterface.SystemInterface;
 import com.android.car.test.utils.TemporaryDirectory;
@@ -56,7 +55,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -75,14 +74,13 @@
  *
  * The following mocks are used:
  * 1. {@link Context} registers intent receivers.
- * 2. {@link CarUserManagerHelper} tells whether or not the system user is headless.
- * 3. {@link SystemInterface} tells where to store system files.
- * 4. {@link CarDrivingStateService} tells about driving state changes.
- * 5. {@link PerUserCarServiceHelper} provides a mocked {@link ICarUserService}.
- * 6. {@link ICarUserService} provides a mocked {@link LocationManagerProxy}.
- * 7. {@link LocationManagerProxy} provides dummy {@link Location}s.
+ * 2. {@link SystemInterface} tells where to store system files.
+ * 3. {@link CarDrivingStateService} tells about driving state changes.
+ * 4. {@link PerUserCarServiceHelper} provides a mocked {@link IPerUserCarService}.
+ * 5. {@link IPerUserCarService} provides a mocked {@link LocationManagerProxy}.
+ * 6. {@link LocationManagerProxy} provides dummy {@link Location}s.
  */
-@RunWith(AndroidJUnit4.class)
+@RunWith(MockitoJUnitRunner.class)
 public class CarLocationServiceTest {
     private static final String TAG = "CarLocationServiceTest";
     private static final String TEST_FILENAME = "location_cache.json";
@@ -96,26 +94,23 @@
     @Mock
     private LocationManagerProxy mMockLocationManagerProxy;
     @Mock
-    private CarUserManagerHelper mMockCarUserManagerHelper;
-    @Mock
     private SystemInterface mMockSystemInterface;
     @Mock
     private CarDrivingStateService mMockCarDrivingStateService;
     @Mock
     private PerUserCarServiceHelper mMockPerUserCarServiceHelper;
     @Mock
-    private ICarUserService mMockICarUserService;
+    private IPerUserCarService mMockIPerUserCarService;
 
     /**
      * Initialize all of the objects with the @Mock annotation.
      */
     @Before
     public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
         mContext = InstrumentationRegistry.getTargetContext();
         mTempDirectory = new TemporaryDirectory(TAG).getDirectory();
         mLatch = new CountDownLatch(1);
-        mCarLocationService = new CarLocationService(mMockContext, mMockCarUserManagerHelper) {
+        mCarLocationService = new CarLocationService(mMockContext) {
             @Override
             void asyncOperation(Runnable operation) {
                 super.asyncOperation(() -> {
@@ -131,10 +126,13 @@
         CarLocalServices.removeServiceForTest(PerUserCarServiceHelper.class);
         CarLocalServices.addService(PerUserCarServiceHelper.class, mMockPerUserCarServiceHelper);
         when(mMockSystemInterface.getSystemCarDir()).thenReturn(mTempDirectory);
-        when(mMockICarUserService.getLocationManagerProxy()).thenReturn(mMockLocationManagerProxy);
+        when(mMockIPerUserCarService.getLocationManagerProxy())
+                .thenReturn(mMockLocationManagerProxy);
 
-        // We only support and test the headless system user case.
-        when(mMockCarUserManagerHelper.isHeadlessSystemUser()).thenReturn(true);
+        if (!UserManager.isHeadlessSystemUserMode()) {
+            fail("We only support and test the headless system user case. Ensure the system has "
+                    + "the system property 'ro.fw.mu.headless_system_user' set to true.");
+        }
 
         // Store CarLocationService's user switch callback so we can invoke it in the tests.
         doAnswer((invocation) -> {
@@ -217,7 +215,7 @@
         ArgumentCaptor<Location> argument = ArgumentCaptor.forClass(Location.class);
         when(mMockLocationManagerProxy.injectLocation(argument.capture())).thenReturn(true);
 
-        mUserServiceCallback.onServiceConnected(mMockICarUserService);
+        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
         mLatch.await();
 
         Location location = argument.getValue();
@@ -239,7 +237,7 @@
         assertThat(mUserServiceCallback).isNotNull();
         assertThat(getLocationCacheFile().exists()).isFalse();
 
-        mUserServiceCallback.onServiceConnected(mMockICarUserService);
+        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
         mLatch.await();
 
         verify(mMockLocationManagerProxy, never()).injectLocation(any());
@@ -254,7 +252,7 @@
         assertThat(mUserServiceCallback).isNotNull();
         writeCacheFile("{\"provider\": \"gps\", \"latitude\": 16.7666, \"longitude\": 3.0026,");
 
-        mUserServiceCallback.onServiceConnected(mMockICarUserService);
+        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
         mLatch.await();
 
         verify(mMockLocationManagerProxy, never()).injectLocation(any());
@@ -269,7 +267,7 @@
         assertThat(mUserServiceCallback).isNotNull();
         writeCacheFile("{\"provider\":\"latitude\":16.7666,\"longitude\": \"accuracy\":1.0}");
 
-        mUserServiceCallback.onServiceConnected(mMockICarUserService);
+        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
         mLatch.await();
 
         verify(mMockLocationManagerProxy, never()).injectLocation(any());
@@ -285,7 +283,7 @@
         assertThat(mUserServiceCallback).isNotNull();
         writeCacheFile("{\"provider\": \"gps\", \"latitude\": 16.7666, \"longitude\": 3.0026}");
 
-        mUserServiceCallback.onServiceConnected(mMockICarUserService);
+        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
         mLatch.await();
 
         verify(mMockLocationManagerProxy, never()).injectLocation(any());
@@ -304,7 +302,7 @@
         writeCacheFile("{\"provider\": \"gps\", \"latitude\": 16.7666, \"longitude\": 3.0026,"
                 + "\"accuracy\":12.3, \"captureTime\": " + oldTime + "}");
 
-        mUserServiceCallback.onServiceConnected(mMockICarUserService);
+        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
         mLatch.await();
 
         verify(mMockLocationManagerProxy, never()).injectLocation(any());
@@ -319,7 +317,7 @@
         // We must have a LocationManagerProxy for the current user in order to get a location
         // during shutdown-prepare.
         mCarLocationService.init();
-        mUserServiceCallback.onServiceConnected(mMockICarUserService);
+        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
         mLatch.await();
         mLatch = new CountDownLatch(1);
 
@@ -373,7 +371,7 @@
         // We must have a LocationManagerProxy for the current user in order to get a location
         // during shutdown-prepare.
         mCarLocationService.init();
-        mUserServiceCallback.onServiceConnected(mMockICarUserService);
+        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
         mLatch.await();
         mLatch = new CountDownLatch(1);
 
@@ -398,7 +396,7 @@
         // We must have a LocationManagerProxy for the current user in order to check whether or
         // not location is enabled.
         mCarLocationService.init();
-        mUserServiceCallback.onServiceConnected(mMockICarUserService);
+        mUserServiceCallback.onServiceConnected(mMockIPerUserCarService);
         mLatch.await();
         mLatch = new CountDownLatch(1);
 
diff --git a/tests/carservice_unit_test/src/com/android/car/CarOccupantZoneServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarOccupantZoneServiceTest.java
new file mode 100644
index 0000000..e1c36db
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/CarOccupantZoneServiceTest.java
@@ -0,0 +1,931 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+import static org.testng.Assert.expectThrows;
+
+import android.annotation.UserIdInt;
+import android.car.Car;
+import android.car.CarOccupantZoneManager;
+import android.car.CarOccupantZoneManager.OccupantZoneInfo;
+import android.car.VehicleAreaSeat;
+import android.car.media.CarAudioManager;
+import android.car.user.CarUserManager;
+import android.car.user.CarUserManager.UserLifecycleEvent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.hardware.display.DisplayManager;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.SparseIntArray;
+import android.view.Display;
+import android.view.DisplayAddress;
+
+import com.android.car.CarOccupantZoneService.DisplayConfig;
+import com.android.car.CarOccupantZoneService.DisplayInfo;
+import com.android.car.CarOccupantZoneService.OccupantConfig;
+import com.android.car.user.CarUserService;
+import com.android.internal.car.ICarServiceHelper;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CarOccupantZoneServiceTest {
+
+    private static final String TAG = CarOccupantZoneServiceTest.class.getSimpleName();
+
+    private CarOccupantZoneService mService;
+    private CarOccupantZoneManager mManager;
+
+    @Mock
+    private CarPropertyService mCarPropertyService;
+
+    @Mock
+    private CarUserService mCarUserService;
+
+    @Mock
+    private Context mContext;
+
+    @Mock
+    private DisplayManager mDisplayManager;
+
+    @Mock
+    private UserManager mUserManager;
+
+    @Mock
+    private Resources mResources;
+
+    @Mock
+    private Display mDisplay0;
+
+    @Mock
+    private Display mDisplay1;
+
+    @Mock
+    private Display mDisplay2;
+
+    @Mock
+    private Display mDisplay3; // not listed by default
+
+    @Mock
+    private Display mDisplay4;
+
+    @Mock
+    private Display mDisplay5; // outside display config and become unknown display
+
+    private static final int CURRENT_USER = 100;
+    private static final int PROFILE_USER1 = 1001;
+    private static final int PROFILE_USER2 = 1002;
+
+    private static final String[] DEFAULT_OCCUPANT_ZONES = {
+            "occupantZoneId=0,occupantType=DRIVER,seatRow=1,seatSide=driver",
+            "occupantZoneId=1,occupantType=FRONT_PASSENGER,seatRow=1,seatSide=oppositeDriver",
+            "occupantZoneId=2,occupantType=REAR_PASSENGER,seatRow=2,seatSide=left",
+            "occupantZoneId=3,occupantType=REAR_PASSENGER,seatRow=2,seatSide=right"
+    };
+
+    private static final int PRIMARY_AUDIO_ZONE_ID = 0;
+    private static final int PRIMARY_AUDIO_ZONE_ID_OCCUPANT = 0;
+    private static final int SECONDARY_AUDIO_ZONE_ID = 1;
+    private static final int SECONDARY_AUDIO_ZONE_ID_OCCUPANT = 3;
+    private static final int UNMAPPED_AUDIO_ZONE_ID_OCCUPANT = 2;
+    private static final int INVALID_AUDIO_ZONE_ID_OCCUPANT = 100;
+
+    // LHD : Left Hand Drive
+    private final OccupantZoneInfo mZoneDriverLHD = new OccupantZoneInfo(0,
+            CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER,
+            VehicleAreaSeat.SEAT_ROW_1_LEFT);
+    private final OccupantZoneInfo mZoneFrontPassengerLHD = new OccupantZoneInfo(1,
+            CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
+            VehicleAreaSeat.SEAT_ROW_1_RIGHT);
+    private final OccupantZoneInfo mZoneRearLeft = new OccupantZoneInfo(2,
+            CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER,
+            VehicleAreaSeat.SEAT_ROW_2_LEFT);
+    private final OccupantZoneInfo mZoneRearRight = new OccupantZoneInfo(3,
+            CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER,
+            VehicleAreaSeat.SEAT_ROW_2_RIGHT);
+
+    // port address set to mocked displayid + 10 so that any possible mix of port address and
+    // display id can be detected.
+    private static final String[] DEFAULT_OCCUPANT_DISPLAY_MAPPING = {
+            "displayPort=10,displayType=MAIN,occupantZoneId=0",
+            "displayPort=11,displayType=INSTRUMENT_CLUSTER,occupantZoneId=0",
+            "displayPort=12,displayType=MAIN,occupantZoneId=1",
+            "displayPort=13,displayType=MAIN,occupantZoneId=2",
+            "displayPort=14,displayType=MAIN,occupantZoneId=3"
+    };
+
+    // Stores last changeFlags from onOccupantZoneConfigChanged call.
+    private int mLastChangeFlags;
+    private final Semaphore mChangeEventSignal = new Semaphore(0);
+
+    private final ICarServiceHelperImpl mICarServiceHelper = new ICarServiceHelperImpl();
+
+    private final CarOccupantZoneManager.OccupantZoneConfigChangeListener mChangeListener =
+            new CarOccupantZoneManager.OccupantZoneConfigChangeListener() {
+                @Override
+                public void onOccupantZoneConfigChanged(int changeFlags) {
+                    // should be dispatched to main thread.
+                    assertThat(Looper.getMainLooper()).isEqualTo(Looper.myLooper());
+                    mLastChangeFlags = changeFlags;
+                    mChangeEventSignal.release();
+                }
+            };
+
+    private void resetConfigChangeEventWait() {
+        mLastChangeFlags = 0;
+        mChangeEventSignal.drainPermits();
+    }
+
+    private boolean waitForConfigChangeEventAndAssertFlag(long timeoutMs, int expectedFlag) {
+        boolean acquired = false;
+        try {
+            acquired = mChangeEventSignal.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
+        } catch (Exception ignored) {
+
+        }
+        if (acquired) {
+            assertThat(expectedFlag).isEqualTo(mLastChangeFlags);
+        }
+        return acquired;
+    }
+
+    private void mockDisplay(DisplayManager displayManager, Display display, int displayId,
+            int portAddress) {
+        when(displayManager.getDisplay(displayId)).thenReturn(display);
+        when(display.getDisplayId()).thenReturn(displayId);
+        when(display.getAddress()).thenReturn(DisplayAddress.fromPhysicalDisplayId(portAddress));
+    }
+
+    @Before
+    public void setUp() {
+        when(mContext.getResources()).thenReturn(mResources);
+        when(mContext.getSystemService(DisplayManager.class)).thenReturn(mDisplayManager);
+        when(mResources.getStringArray(R.array.config_occupant_zones))
+                .thenReturn(DEFAULT_OCCUPANT_ZONES);
+        when(mResources.getStringArray(R.array.config_occupant_display_mapping))
+                .thenReturn(DEFAULT_OCCUPANT_DISPLAY_MAPPING);
+        when(mContext.getApplicationInfo()).thenReturn(new ApplicationInfo());
+        // Stored as static: Other tests can leave things behind and fail this test in add call.
+        // So just remove as safety guard.
+        CarLocalServices.removeServiceForTest(CarPropertyService.class);
+        CarLocalServices.addService(CarPropertyService.class, mCarPropertyService);
+        CarLocalServices.removeServiceForTest(CarUserService.class);
+        CarLocalServices.addService(CarUserService.class, mCarUserService);
+        mockDisplay(mDisplayManager, mDisplay0, 0, 10);
+        mockDisplay(mDisplayManager, mDisplay1, 1, 11);
+        mockDisplay(mDisplayManager, mDisplay2, 2, 12);
+        mockDisplay(mDisplayManager, mDisplay4, 4, 14);
+        mockDisplay(mDisplayManager, mDisplay5, 5, 15);
+        when(mDisplayManager.getDisplays()).thenReturn(new Display[]{
+                mDisplay0,
+                mDisplay1,
+                mDisplay2,
+                mDisplay4,
+                mDisplay5
+        });
+
+        mService = new CarOccupantZoneService(mContext, mDisplayManager, mUserManager,
+                /* enableProfileUserAssignmentForMultiDisplay= */ false);
+        spyOn(mService);
+        doReturn(VehicleAreaSeat.SEAT_ROW_1_LEFT).when(mService).getDriverSeat();
+        doReturn(CURRENT_USER).when(mService).getCurrentUser();
+
+        Car car = new Car(mContext, /* service= */ null, /* handler= */ null);
+        mManager = new CarOccupantZoneManager(car, mService);
+    }
+
+    @After
+    public void tearDown() {
+        CarLocalServices.removeServiceForTest(CarUserService.class);
+        CarLocalServices.removeServiceForTest(CarPropertyService.class);
+    }
+
+    @Test
+    public void testDefaultOccupantConfig() {
+        mService.init();
+
+        // key : zone id
+        HashMap<Integer, OccupantZoneInfo> configs = mService.getOccupantsConfig();
+        assertThat(configs).hasSize(DEFAULT_OCCUPANT_ZONES.length);
+        assertThat(mZoneDriverLHD).isEqualTo(configs.get(0));
+        assertThat(mZoneFrontPassengerLHD).isEqualTo(configs.get(1));
+        assertThat(mZoneRearLeft).isEqualTo(configs.get(2));
+        assertThat(mZoneRearRight).isEqualTo(configs.get(3));
+    }
+
+    @Test
+    public void testDefaultAudioZoneConfig() {
+        mService.init();
+        SparseIntArray audioConfigs = mService.getAudioConfigs();
+        assertThat(audioConfigs.size()).isEqualTo(0);
+    }
+
+    /** RHD: Right Hand Drive */
+    @Test
+    public void testDefaultOccupantConfigForRHD() {
+        // driver is right side and opposite should be left.
+        doReturn(VehicleAreaSeat.SEAT_ROW_1_RIGHT).when(mService).getDriverSeat();
+
+        mService.init();
+
+        // key : zone id
+        HashMap<Integer, OccupantZoneInfo> configs = mService.getOccupantsConfig();
+        assertThat(configs).hasSize(DEFAULT_OCCUPANT_ZONES.length);
+        assertThat(new OccupantZoneInfo(0, CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER,
+                VehicleAreaSeat.SEAT_ROW_1_RIGHT)).isEqualTo(configs.get(0));
+        assertThat(new OccupantZoneInfo(1, CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
+                VehicleAreaSeat.SEAT_ROW_1_LEFT)).isEqualTo(configs.get(1));
+        assertThat(mZoneRearLeft).isEqualTo(configs.get(2));
+        assertThat(mZoneRearRight).isEqualTo(configs.get(3));
+    }
+
+    private void assertDisplayConfig(DisplayConfig c, int displayType, int occupantZoneId) {
+        assertThat(displayType).isEqualTo(c.displayType);
+        assertThat(occupantZoneId).isEqualTo(c.occupantZoneId);
+    }
+
+    @Test
+    public void testDefaultOccupantDisplayMapping() {
+        mService.init();
+
+        // key: display port address
+        HashMap<Integer, DisplayConfig> configs = mService.getDisplayConfigs();
+        assertThat(configs).hasSize(DEFAULT_OCCUPANT_DISPLAY_MAPPING.length);
+        assertDisplayConfig(configs.get(10), CarOccupantZoneManager.DISPLAY_TYPE_MAIN, 0);
+        assertDisplayConfig(configs.get(11), CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER,
+                0);
+        assertDisplayConfig(configs.get(12), CarOccupantZoneManager.DISPLAY_TYPE_MAIN, 1);
+        assertDisplayConfig(configs.get(13), CarOccupantZoneManager.DISPLAY_TYPE_MAIN, 2);
+        assertDisplayConfig(configs.get(14), CarOccupantZoneManager.DISPLAY_TYPE_MAIN, 3);
+    }
+
+    private void setUpServiceWithProfileSupportEnabled() {
+        mService = new CarOccupantZoneService(mContext, mDisplayManager, mUserManager,
+                /* enableProfileUserAssignmentForMultiDisplay= */ true);
+        spyOn(mService);
+        doReturn(VehicleAreaSeat.SEAT_ROW_1_LEFT).when(mService).getDriverSeat();
+        doReturn(CURRENT_USER).when(mService).getCurrentUser();
+        LinkedList<UserInfo> profileUsers = new LinkedList<>();
+        profileUsers.add(new UserInfo(PROFILE_USER1, "1", 0));
+        profileUsers.add(new UserInfo(PROFILE_USER2, "1", 0));
+        doReturn(profileUsers).when(mUserManager).getEnabledProfiles(CURRENT_USER);
+        doReturn(true).when(mUserManager).isUserRunning(anyInt());
+
+        Car car = new Car(mContext, /* service= */ null, /* handler= */ null);
+        mManager = new CarOccupantZoneManager(car, mService);
+    }
+
+    @Test
+    public void testAssignProfileUserFailForNonProfileUser() throws Exception {
+        setUpServiceWithProfileSupportEnabled();
+        mService.init();
+
+        int invalidProfileUser = 2000;
+        assertThat(mManager.assignProfileUserToOccupantZone(mZoneFrontPassengerLHD,
+                invalidProfileUser)).isFalse();
+    }
+
+    private void assertDisplayWhitelist(int userId, int[] displays) {
+        assertThat(mICarServiceHelper.mWhitelists).containsKey(userId);
+        assertThat(mICarServiceHelper.mWhitelists.get(userId)).hasSize(displays.length);
+        for (int display : displays) {
+            assertThat(mICarServiceHelper.mWhitelists.get(userId)).contains(display);
+        }
+    }
+
+    private void assertPassengerDisplaysFromDefaultConfig() throws Exception {
+        assertThat(mICarServiceHelper.mPassengerDisplayIds).hasSize(2);
+        assertThat(mICarServiceHelper.mPassengerDisplayIds).contains(
+                mDisplay2.getDisplayId());
+        assertThat(mICarServiceHelper.mPassengerDisplayIds).contains(
+                mDisplay4.getDisplayId());
+    }
+
+    @Test
+    public void testAssignProfileUserOnce() throws Exception {
+        setUpServiceWithProfileSupportEnabled();
+        mService.init();
+        mService.setCarServiceHelper(mICarServiceHelper);
+
+        assertPassengerDisplaysFromDefaultConfig();
+
+        mICarServiceHelper.mWhitelists.clear();
+        assertThat(mManager.assignProfileUserToOccupantZone(mZoneFrontPassengerLHD,
+                PROFILE_USER1)).isTrue();
+        assertPassengerDisplaysFromDefaultConfig();
+        assertDisplayWhitelist(CURRENT_USER, new int[] {mDisplay4.getDisplayId()});
+        assertDisplayWhitelist(PROFILE_USER1, new int[] {mDisplay2.getDisplayId()});
+    }
+
+    @Test
+    public void testAssignProfileUserFailForStoppedUser() throws Exception {
+        setUpServiceWithProfileSupportEnabled();
+        mService.init();
+        mService.setCarServiceHelper(mICarServiceHelper);
+
+        assertPassengerDisplaysFromDefaultConfig();
+
+        mICarServiceHelper.mWhitelists.clear();
+        doReturn(false).when(mUserManager).isUserRunning(PROFILE_USER1);
+        assertThat(mManager.assignProfileUserToOccupantZone(mZoneFrontPassengerLHD,
+                PROFILE_USER1)).isFalse();
+    }
+
+    @Test
+    public void testAssignProfileUserSwitch() throws Exception {
+        setUpServiceWithProfileSupportEnabled();
+        mService.init();
+        mService.setCarServiceHelper(mICarServiceHelper);
+
+        assertThat(mManager.assignProfileUserToOccupantZone(mZoneFrontPassengerLHD,
+                PROFILE_USER1)).isTrue();
+
+        assertPassengerDisplaysFromDefaultConfig();
+        assertDisplayWhitelist(CURRENT_USER, new int[] {mDisplay4.getDisplayId()});
+        assertDisplayWhitelist(PROFILE_USER1, new int[] {mDisplay2.getDisplayId()});
+
+        mICarServiceHelper.mWhitelists.clear();
+        assertThat(mManager.assignProfileUserToOccupantZone(mZoneFrontPassengerLHD,
+                PROFILE_USER2)).isTrue();
+        assertPassengerDisplaysFromDefaultConfig();
+        assertDisplayWhitelist(CURRENT_USER, new int[] {mDisplay4.getDisplayId()});
+        assertDisplayWhitelist(PROFILE_USER2, new int[] {mDisplay2.getDisplayId()});
+    }
+
+    @Test
+    public void testAssignProfileFollowedByUserSwitch() throws Exception {
+        setUpServiceWithProfileSupportEnabled();
+        mService.init();
+        mService.setCarServiceHelper(mICarServiceHelper);
+
+        assertThat(mManager.assignProfileUserToOccupantZone(mZoneFrontPassengerLHD,
+                PROFILE_USER1)).isTrue();
+
+        assertPassengerDisplaysFromDefaultConfig();
+        assertDisplayWhitelist(CURRENT_USER, new int[] {mDisplay4.getDisplayId()});
+        assertDisplayWhitelist(PROFILE_USER1, new int[] {mDisplay2.getDisplayId()});
+
+        mICarServiceHelper.mWhitelists.clear();
+        int newUserId = 200;
+        doReturn(newUserId).when(mService).getCurrentUser();
+        mService.mUserLifecycleListener.onEvent(new UserLifecycleEvent(
+                CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, newUserId));
+
+        assertPassengerDisplaysFromDefaultConfig();
+        assertDisplayWhitelist(newUserId, new int[] {mDisplay2.getDisplayId(),
+                mDisplay4.getDisplayId()});
+        assertThat(mICarServiceHelper.mWhitelists).hasSize(1);
+    }
+
+    @Test
+    public void testAssignProfileFollowedByNullUserAssignment() throws Exception {
+        setUpServiceWithProfileSupportEnabled();
+        mService.init();
+        mService.setCarServiceHelper(mICarServiceHelper);
+
+        assertThat(mManager.assignProfileUserToOccupantZone(mZoneFrontPassengerLHD,
+                PROFILE_USER1)).isTrue();
+
+        assertPassengerDisplaysFromDefaultConfig();
+        assertDisplayWhitelist(CURRENT_USER, new int[] {mDisplay4.getDisplayId()});
+        assertDisplayWhitelist(PROFILE_USER1, new int[] {mDisplay2.getDisplayId()});
+
+        mICarServiceHelper.mWhitelists.clear();
+        assertThat(mManager.assignProfileUserToOccupantZone(mZoneFrontPassengerLHD,
+                UserHandle.USER_NULL)).isTrue();
+        assertPassengerDisplaysFromDefaultConfig();
+        assertDisplayWhitelist(CURRENT_USER, new int[] {mDisplay2.getDisplayId(),
+                mDisplay4.getDisplayId()});
+        assertThat(mICarServiceHelper.mWhitelists).hasSize(1);
+    }
+
+    @Test
+    public void testCarServiceHelperInitialUpdate() throws Exception {
+        setUpServiceWithProfileSupportEnabled();
+        mService.init();
+        mService.setCarServiceHelper(mICarServiceHelper);
+
+        assertPassengerDisplaysFromDefaultConfig();
+        assertDisplayWhitelist(CURRENT_USER, new int[] {mDisplay2.getDisplayId(),
+                mDisplay4.getDisplayId()});
+        assertThat(mICarServiceHelper.mWhitelists).hasSize(1);
+    }
+
+    private void assertDisplayInfoIncluded(
+            ArrayList<DisplayInfo> displayInfos, Display display, int displayType) {
+        for (DisplayInfo info : displayInfos) {
+            if (info.display == display && info.displayType == displayType) {
+                return;
+            }
+        }
+        fail("Cannot find display:" + display + " type:" + displayType);
+    }
+
+    private void assertOccupantConfig(OccupantConfig c, int userId, Display[] displays,
+            int[] displayTypes) {
+        assertThat(userId).isEqualTo(c.userId);
+        assertThat(c.displayInfos).hasSize(displays.length);
+        assertThat(c.displayInfos).hasSize(displayTypes.length);
+        for (int i = 0; i < displays.length; i++) {
+            assertDisplayInfoIncluded(c.displayInfos, displays[i], displayTypes[i]);
+        }
+    }
+
+    @Test
+    public void testSetAudioConfigMapping() {
+        mService.init();
+
+        SparseIntArray audioZoneIdToOccupantZoneMapping =
+                getDefaultAudioZoneToOccupantZoneMapping();
+
+        mService.setAudioZoneIdsForOccupantZoneIds(audioZoneIdToOccupantZoneMapping);
+
+        assertThat(mService.getAudioZoneIdForOccupant(PRIMARY_AUDIO_ZONE_ID_OCCUPANT))
+                .isEqualTo(PRIMARY_AUDIO_ZONE_ID);
+
+        assertThat(mService.getAudioZoneIdForOccupant(SECONDARY_AUDIO_ZONE_ID_OCCUPANT))
+                .isEqualTo(SECONDARY_AUDIO_ZONE_ID);
+    }
+
+    private SparseIntArray getDefaultAudioZoneToOccupantZoneMapping() {
+        SparseIntArray audioZoneIdToOccupantZoneMapping = new SparseIntArray(2);
+        audioZoneIdToOccupantZoneMapping.put(PRIMARY_AUDIO_ZONE_ID,
+                PRIMARY_AUDIO_ZONE_ID_OCCUPANT);
+        audioZoneIdToOccupantZoneMapping.put(SECONDARY_AUDIO_ZONE_ID,
+                SECONDARY_AUDIO_ZONE_ID_OCCUPANT);
+        return audioZoneIdToOccupantZoneMapping;
+    }
+
+    @Test
+    public void testOccupantZoneConfigInfoForAudio() {
+        mService.init();
+        SparseIntArray audioZoneIdToOccupantZoneMapping =
+                getDefaultAudioZoneToOccupantZoneMapping();
+
+        HashMap<Integer, CarOccupantZoneManager.OccupantZoneInfo> occupantZoneConfigs =
+                mService.getOccupantsConfig();
+
+        mService.setAudioZoneIdsForOccupantZoneIds(audioZoneIdToOccupantZoneMapping);
+
+        CarOccupantZoneManager.OccupantZoneInfo primaryOccupantInfo =
+                mService.getOccupantForAudioZoneId(PRIMARY_AUDIO_ZONE_ID);
+        assertThat(primaryOccupantInfo).isEqualTo(
+                occupantZoneConfigs.get(PRIMARY_AUDIO_ZONE_ID_OCCUPANT));
+
+        CarOccupantZoneManager.OccupantZoneInfo secondaryOccupantInfo =
+                mService.getOccupantForAudioZoneId(SECONDARY_AUDIO_ZONE_ID);
+        assertThat(secondaryOccupantInfo).isEqualTo(
+                occupantZoneConfigs.get(SECONDARY_AUDIO_ZONE_ID_OCCUPANT));
+
+        CarOccupantZoneManager.OccupantZoneInfo nullOccupantInfo =
+                mService.getOccupantForAudioZoneId(UNMAPPED_AUDIO_ZONE_ID_OCCUPANT);
+        assertThat(nullOccupantInfo).isNull();
+    }
+
+    @Test
+    public void testMissingAudioConfigMapping() {
+        mService.init();
+        SparseIntArray audioZoneIdToOccupantZoneMapping =
+                getDefaultAudioZoneToOccupantZoneMapping();
+
+        mService.setAudioZoneIdsForOccupantZoneIds(audioZoneIdToOccupantZoneMapping);
+
+        assertThat(mService.getAudioZoneIdForOccupant(UNMAPPED_AUDIO_ZONE_ID_OCCUPANT))
+                .isEqualTo(CarAudioManager.INVALID_AUDIO_ZONE);
+    }
+
+    @Test
+    public void testSetInvalidAudioConfigMapping() {
+        mService.init();
+        SparseIntArray audioZoneIdToOccupantZoneMapping = new SparseIntArray(2);
+        audioZoneIdToOccupantZoneMapping.put(PRIMARY_AUDIO_ZONE_ID,
+                PRIMARY_AUDIO_ZONE_ID_OCCUPANT);
+        audioZoneIdToOccupantZoneMapping.put(SECONDARY_AUDIO_ZONE_ID,
+                INVALID_AUDIO_ZONE_ID_OCCUPANT);
+        IllegalArgumentException thrown =
+                expectThrows(IllegalArgumentException.class,
+                        () -> mService.setAudioZoneIdsForOccupantZoneIds(
+                                audioZoneIdToOccupantZoneMapping));
+        thrown.getMessage().contains("does not exist");
+    }
+
+    @Test
+    public void testActiveOccupantConfigs() {
+        mService.init();
+
+        // key : zone id
+        HashMap<Integer, OccupantConfig> configs = mService.getActiveOccupantConfigs();
+        assertThat(configs).hasSize(3); // driver, front passenger, one rear
+        assertOccupantConfig(configs.get(0), CURRENT_USER, new Display[]{mDisplay0, mDisplay1},
+                new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
+                        CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER});
+        assertOccupantConfig(configs.get(1), CURRENT_USER, new Display[]{mDisplay2},
+                new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN});
+        assertOccupantConfig(configs.get(3), CURRENT_USER, new Display[]{mDisplay4},
+                new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN});
+    }
+
+    @Test
+    public void testActiveOccupantConfigsAfterDisplayAdd() {
+        mService.init();
+
+        mockDisplay(mDisplayManager, mDisplay3, 3, 13);
+        when(mDisplayManager.getDisplays()).thenReturn(new Display[]{
+                mDisplay0,
+                mDisplay1,
+                mDisplay2,
+                mDisplay3,
+                mDisplay4,
+                mDisplay5
+        });
+        mService.mDisplayListener.onDisplayAdded(3);
+
+        // key : zone id
+        HashMap<Integer, OccupantConfig> configs = mService.getActiveOccupantConfigs();
+        assertThat(configs).hasSize(4); // driver, front passenger, two rear
+        assertOccupantConfig(configs.get(0), CURRENT_USER, new Display[]{mDisplay0, mDisplay1},
+                new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
+                        CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER});
+        assertOccupantConfig(configs.get(1), CURRENT_USER, new Display[]{mDisplay2},
+                new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN});
+        assertOccupantConfig(configs.get(2), CURRENT_USER, new Display[]{mDisplay3},
+                new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN});
+        assertOccupantConfig(configs.get(3), CURRENT_USER, new Display[]{mDisplay4},
+                new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN});
+    }
+
+    @Test
+    public void testActiveOccupantConfigsAfterDisplayRemoval() {
+        mService.init();
+
+        when(mDisplayManager.getDisplays()).thenReturn(new Display[]{
+                mDisplay0,
+                mDisplay1,
+                mDisplay2,
+        });
+        mService.mDisplayListener.onDisplayRemoved(4);
+
+        // key : zone id
+        HashMap<Integer, OccupantConfig> configs = mService.getActiveOccupantConfigs();
+        assertThat(configs).hasSize(2); // driver, front passenger
+        assertOccupantConfig(configs.get(0), CURRENT_USER, new Display[]{mDisplay0, mDisplay1},
+                new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
+                        CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER});
+        assertOccupantConfig(configs.get(1), CURRENT_USER, new Display[]{mDisplay2},
+                new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN});
+    }
+
+    @Test
+    public void testActiveUserAfterUserSwitching() {
+        mService.init();
+
+        final int newUserId = 200;
+        doReturn(newUserId).when(mService).getCurrentUser();
+        mService.mUserLifecycleListener.onEvent(new UserLifecycleEvent(
+                CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, newUserId));
+
+        // key : zone id
+        HashMap<Integer, OccupantConfig> configs = mService.getActiveOccupantConfigs();
+        assertThat(configs).hasSize(3); // driver, front passenger, one rear
+        assertOccupantConfig(configs.get(0), newUserId, new Display[]{mDisplay0, mDisplay1},
+                new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
+                        CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER});
+        assertOccupantConfig(configs.get(1), newUserId, new Display[]{mDisplay2},
+                new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN});
+        assertOccupantConfig(configs.get(3), newUserId, new Display[]{mDisplay4},
+                new int[]{CarOccupantZoneManager.DISPLAY_TYPE_MAIN});
+    }
+
+    private void assertParsingFailure() {
+        assertThrows(Exception.class, () -> mService.init());
+        // call release to return it to clean state.
+        mService.release();
+    }
+
+    @Test
+    public void testWrongZoneConfigs() {
+        final String[] wrongZoneConfigs = {
+                "unknownKeyword",
+                "unknownKey=0",
+                "occupantZoneId=0,occupantType=Unknown,seatRow=1,seatSide=driver",
+                "occupantZoneId=0,occupantType=DRIVER,seatRow=0,seatSide=driver", // wrong row
+                "occupantZoneId=0,occupantType=DRIVER,seatRow=1,seatSide=wrongSide"
+        };
+
+        String[] zoneConfig = new String[1];
+        when(mResources.getStringArray(R.array.config_occupant_zones))
+                .thenReturn(zoneConfig);
+        for (int i = 0; i < wrongZoneConfigs.length; i++) {
+            zoneConfig[0] = wrongZoneConfigs[i];
+            assertParsingFailure();
+        }
+    }
+
+    @Test
+    public void testWrongDisplayConfigs() {
+        final String[] wrongDisplayConfigs = {
+                "unknownKeyword",
+                "unknownKey=0",
+                "displayPort=10,displayType=Unknown,occupantZoneId=0",
+                "displayPort=10,displayType=MAIN,occupantZoneId=100" // wrong zone id
+        };
+
+        String[] displayConfig = new String[1];
+        when(mResources.getStringArray(R.array.config_occupant_display_mapping))
+                .thenReturn(displayConfig);
+        for (int i = 0; i < wrongDisplayConfigs.length; i++) {
+            displayConfig[0] = wrongDisplayConfigs[i];
+            assertParsingFailure();
+        }
+    }
+
+    @Test
+    public void testManagerGetAllOccupantZones() {
+        mService.init();
+
+        List<OccupantZoneInfo> infos = mManager.getAllOccupantZones();
+        assertThat(infos).hasSize(3);
+        assertThat(infos).contains(mZoneDriverLHD);
+        assertThat(infos).contains(mZoneFrontPassengerLHD);
+        assertThat(infos).contains(mZoneRearRight);
+    }
+
+    @Test
+    public void testManagerGetAllDisplaysForOccupant() {
+        mService.init();
+
+        List<Display> displaysForDriver = mManager.getAllDisplaysForOccupant(mZoneDriverLHD);
+        assertThat(displaysForDriver).hasSize(2);
+        assertThat(displaysForDriver).contains(mDisplay0);
+        assertThat(displaysForDriver).contains(mDisplay1);
+
+        List<Display> displaysForFrontPassenger = mManager.getAllDisplaysForOccupant(
+                mZoneFrontPassengerLHD);
+        assertThat(displaysForFrontPassenger).hasSize(1);
+        assertThat(displaysForFrontPassenger).contains(mDisplay2);
+
+        List<Display> displaysForRearLeft = mManager.getAllDisplaysForOccupant(
+                mZoneRearLeft);
+        assertThat(displaysForRearLeft).hasSize(0);
+
+        List<Display> displaysForRearRight = mManager.getAllDisplaysForOccupant(
+                mZoneRearRight);
+        assertThat(displaysForRearRight).hasSize(1);
+        assertThat(displaysForRearRight).contains(mDisplay4);
+    }
+
+    @Test
+    public void testManagerGetAllDisplaysForOccupantAfterDisplayAdd() {
+        mService.init();
+
+        mockDisplay(mDisplayManager, mDisplay3, 3, 13);
+        when(mDisplayManager.getDisplays()).thenReturn(new Display[]{
+                mDisplay0,
+                mDisplay1,
+                mDisplay2,
+                mDisplay3,
+                mDisplay4,
+                mDisplay5
+        });
+        mService.mDisplayListener.onDisplayAdded(3);
+
+        List<Display> displaysForDriver = mManager.getAllDisplaysForOccupant(mZoneDriverLHD);
+        assertThat(displaysForDriver).hasSize(2);
+        assertThat(displaysForDriver).contains(mDisplay0);
+        assertThat(displaysForDriver).contains(mDisplay1);
+
+        List<Display> displaysForFrontPassenger = mManager.getAllDisplaysForOccupant(
+                mZoneFrontPassengerLHD);
+        assertThat(displaysForFrontPassenger).hasSize(1);
+        assertThat(displaysForFrontPassenger).contains(mDisplay2);
+
+        List<Display> displaysForRearLeft = mManager.getAllDisplaysForOccupant(
+                mZoneRearLeft);
+        assertThat(displaysForRearLeft).hasSize(1);
+        assertThat(displaysForRearLeft).contains(mDisplay3);
+
+        List<Display> displaysForRearRight = mManager.getAllDisplaysForOccupant(
+                mZoneRearRight);
+        assertThat(displaysForRearRight).hasSize(1);
+        assertThat(displaysForRearRight).contains(mDisplay4);
+    }
+
+    @Test
+    public void testManagerGetAllDisplaysForOccupantAfterDisplayRemoval() {
+        mService.init();
+
+        when(mDisplayManager.getDisplays()).thenReturn(new Display[]{
+                mDisplay0,
+                mDisplay1,
+                mDisplay2,
+        });
+        mService.mDisplayListener.onDisplayRemoved(4);
+
+        List<Display> displaysForDriver = mManager.getAllDisplaysForOccupant(mZoneDriverLHD);
+        assertThat(displaysForDriver).hasSize(2);
+        assertThat(displaysForDriver).contains(mDisplay0);
+        assertThat(displaysForDriver).contains(mDisplay1);
+
+        List<Display> displaysForFrontPassenger = mManager.getAllDisplaysForOccupant(
+                mZoneFrontPassengerLHD);
+        assertThat(displaysForFrontPassenger).hasSize(1);
+        assertThat(displaysForFrontPassenger).contains(mDisplay2);
+
+        List<Display> displaysForRearLeft = mManager.getAllDisplaysForOccupant(
+                mZoneRearLeft);
+        assertThat(displaysForRearLeft).hasSize(0);
+
+        List<Display> displaysForRearRight = mManager.getAllDisplaysForOccupant(
+                mZoneRearRight);
+        assertThat(displaysForRearRight).hasSize(0);
+    }
+
+    @Test
+    public void testManagerGetDisplayForOccupant() {
+        mService.init();
+
+        assertThat(mDisplay0).isEqualTo(mManager.getDisplayForOccupant(mZoneDriverLHD,
+                CarOccupantZoneManager.DISPLAY_TYPE_MAIN));
+        assertThat(mDisplay1).isEqualTo(mManager.getDisplayForOccupant(mZoneDriverLHD,
+                CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER));
+        assertThat(mManager.getDisplayForOccupant(mZoneDriverLHD,
+                CarOccupantZoneManager.DISPLAY_TYPE_HUD)).isNull();
+
+        assertThat(mDisplay2).isEqualTo(mManager.getDisplayForOccupant(mZoneFrontPassengerLHD,
+                CarOccupantZoneManager.DISPLAY_TYPE_MAIN));
+
+        assertThat(mManager.getDisplayForOccupant(mZoneRearLeft,
+                CarOccupantZoneManager.DISPLAY_TYPE_MAIN)).isNull();
+
+        assertThat(mDisplay4).isEqualTo(mManager.getDisplayForOccupant(mZoneRearRight,
+                CarOccupantZoneManager.DISPLAY_TYPE_MAIN));
+    }
+
+    @Test
+    public void testManagerGetDisplayType() {
+        mService.init();
+
+        assertThat(mManager.getDisplayType(mDisplay0)).isEqualTo(
+                CarOccupantZoneManager.DISPLAY_TYPE_MAIN);
+        assertThat(mManager.getDisplayType(mDisplay1)).isEqualTo(
+                CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER);
+        assertThat(mManager.getDisplayType(mDisplay2)).isEqualTo(
+                CarOccupantZoneManager.DISPLAY_TYPE_MAIN);
+        assertThat(mManager.getDisplayType(mDisplay4)).isEqualTo(
+                CarOccupantZoneManager.DISPLAY_TYPE_MAIN);
+        assertThat(mManager.getDisplayType(mDisplay5)).isEqualTo(
+                CarOccupantZoneManager.DISPLAY_TYPE_UNKNOWN);
+    }
+
+    @Test
+    public void testManagerGetUserForOccupant() {
+        mService.init();
+
+        int driverUser = mManager.getUserForOccupant(mZoneDriverLHD);
+        assertThat(CURRENT_USER).isEqualTo(driverUser);
+
+        //TODO update this after secondary user handling
+        assertThat(mManager.getUserForOccupant(mZoneFrontPassengerLHD)).isEqualTo(driverUser);
+        assertThat(mManager.getUserForOccupant(mZoneRearLeft)).isEqualTo(UserHandle.USER_NULL);
+        assertThat(mManager.getUserForOccupant(mZoneRearRight)).isEqualTo(driverUser);
+    }
+
+    @Test
+    public void testManagerGetUserForOccupantAfterUserSwitch() {
+        mService.init();
+
+        final int newUserId = 200;
+        doReturn(newUserId).when(mService).getCurrentUser();
+        mService.mUserLifecycleListener.onEvent(new UserLifecycleEvent(
+                CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, newUserId));
+
+        assertThat(newUserId).isEqualTo(mManager.getUserForOccupant(mZoneDriverLHD));
+        //TODO update this after secondary user handling
+        assertThat(mManager.getUserForOccupant(mZoneFrontPassengerLHD)).isEqualTo(newUserId);
+        assertThat(mManager.getUserForOccupant(mZoneRearLeft)).isEqualTo(UserHandle.USER_NULL);
+        assertThat(mManager.getUserForOccupant(mZoneRearRight)).isEqualTo(newUserId);
+    }
+
+    @Test
+    public void testManagerRegisterUnregister() {
+        mService.init();
+
+        final long eventWaitTimeMs = 300;
+
+        mManager.registerOccupantZoneConfigChangeListener(mChangeListener);
+
+        resetConfigChangeEventWait();
+        mService.mUserLifecycleListener.onEvent(new UserLifecycleEvent(
+                CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, 0)); // user id does not matter.
+
+        assertThat(waitForConfigChangeEventAndAssertFlag(eventWaitTimeMs,
+                CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER)).isTrue();
+
+        resetConfigChangeEventWait();
+        mService.mDisplayListener.onDisplayAdded(0); // displayid ignored
+        assertThat(waitForConfigChangeEventAndAssertFlag(eventWaitTimeMs,
+                CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_DISPLAY)).isTrue();
+
+        resetConfigChangeEventWait();
+        mManager.unregisterOccupantZoneConfigChangeListener(mChangeListener);
+        mService.mUserLifecycleListener.onEvent(new UserLifecycleEvent(
+                CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, 0));
+        assertThat(waitForConfigChangeEventAndAssertFlag(eventWaitTimeMs, 0)).isFalse();
+    }
+
+    @Test
+    public void testManagerRegisterUnregisterForAudioConfigs() {
+        mService.init();
+
+        long eventWaitTimeMs = 300;
+
+        mManager.registerOccupantZoneConfigChangeListener(mChangeListener);
+
+        resetConfigChangeEventWait();
+
+        SparseIntArray audioZoneIdToOccupantZoneMapping =
+                getDefaultAudioZoneToOccupantZoneMapping();
+
+        mService.setAudioZoneIdsForOccupantZoneIds(audioZoneIdToOccupantZoneMapping);
+
+        assertThat(waitForConfigChangeEventAndAssertFlag(eventWaitTimeMs,
+                CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_AUDIO)).isTrue();
+
+        resetConfigChangeEventWait();
+        mManager.unregisterOccupantZoneConfigChangeListener(mChangeListener);
+        mService.setAudioZoneIdsForOccupantZoneIds(audioZoneIdToOccupantZoneMapping);
+        assertThat(waitForConfigChangeEventAndAssertFlag(eventWaitTimeMs,
+                CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_AUDIO)).isFalse();
+    }
+
+    private static class ICarServiceHelperImpl extends ICarServiceHelper.Stub {
+        private List<Integer> mPassengerDisplayIds;
+
+        /** key: user id, value: display whitelistis */
+        private HashMap<Integer, List<Integer>> mWhitelists = new HashMap<>();
+
+        @Override
+        public int forceSuspend(int timeoutMs) {
+            return 0;
+        }
+
+        @Override
+        public void setDisplayWhitelistForUser(@UserIdInt int userId, int[] displayIds) {
+            mWhitelists.put(userId, Arrays.stream(displayIds).boxed().collect(Collectors.toList()));
+        }
+
+        @Override
+        public void setPassengerDisplays(int[] displayIdsForPassenger) {
+            mPassengerDisplayIds = Arrays.stream(displayIdsForPassenger).boxed().collect(
+                    Collectors.toList());
+        }
+
+        @Override
+        public void setSourcePreferredComponents(boolean enableSourcePreferred,
+                List<ComponentName> sourcePreferredComponents) throws RemoteException {
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
index 6baf12a..3cbfffc 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
@@ -16,39 +16,38 @@
 
 package com.android.car;
 
-import static android.content.pm.UserInfo.FLAG_EPHEMERAL;
-import static android.content.pm.UserInfo.FLAG_GUEST;
-import static android.os.UserHandle.USER_SYSTEM;
+import static android.car.test.mocks.CarArgumentMatchers.isUserInfo;
+import static android.car.test.util.UserTestingHelper.newGuestUser;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.notNull;
 import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import android.annotation.Nullable;
 import android.app.ActivityManager;
-import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
-import android.car.hardware.power.ICarPowerStateListener;
-import android.car.userlib.CarUserManagerHelper;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.test.util.Visitor;
+import android.car.userlib.HalCallback;
+import android.car.userlib.InitialUserSetter;
 import android.content.Context;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
 import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateReq;
 import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateShutdownParam;
-import android.os.RemoteException;
 import android.os.UserManager;
+import android.sysprop.CarProperties;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
@@ -62,38 +61,32 @@
 import com.android.car.systeminterface.SystemStateInterface;
 import com.android.car.systeminterface.WakeLockInterface;
 import com.android.car.test.utils.TemporaryDirectory;
+import com.android.car.user.CarUserService;
+import com.android.internal.app.IVoiceInteractionManagerService;
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.TestRule;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.MockitoSession;
-import org.mockito.junit.MockitoJUnitRunner;
-import org.mockito.quality.Strictness;
 
 import java.io.File;
 import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-import java.lang.reflect.Method;
 import java.time.Duration;
+import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
 @SmallTest
-@RunWith(MockitoJUnitRunner.class)
-public class CarPowerManagementServiceTest {
+public class CarPowerManagementServiceTest extends AbstractExtendedMockitoTestCase {
     private static final String TAG = CarPowerManagementServiceTest.class.getSimpleName();
     private static final long WAIT_TIMEOUT_MS = 2000;
     private static final long WAIT_TIMEOUT_LONG_MS = 5000;
-    private static final int NO_USER_INFO_FLAGS = 0;
-    private static final String NEW_GUEST_NAME = "NewestGuestInTheBlock";
+    private static final int WAKE_UP_DELAY = 100;
+
+    private static final int CURRENT_USER_ID = 42;
+    private static final int CURRENT_GUEST_ID = 108; // must be different than CURRENT_USER_ID;
+    private static final int NEW_GUEST_ID = 666;
 
     private final MockDisplayInterface mDisplayInterface = new MockDisplayInterface();
     private final MockSystemStateInterface mSystemStateInterface = new MockSystemStateInterface();
@@ -102,49 +95,32 @@
     private final PowerSignalListener mPowerSignalListener = new PowerSignalListener();
     private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
 
-    private MockitoSession mSession;
-
     private MockedPowerHalService mPowerHal;
     private SystemInterface mSystemInterface;
     private CarPowerManagementService mService;
     private CompletableFuture<Void> mFuture;
 
     @Mock
-    private CarUserManagerHelper mCarUserManagerHelper;
-    @Mock
     private UserManager mUserManager;
     @Mock
     private Resources mResources;
+    @Mock
+    private CarUserService mUserService;
+    @Mock
+    private InitialUserSetter mInitialUserSetter;
+    @Mock
+    private IVoiceInteractionManagerService mVoiceInteractionManagerService;
 
-    // Wakeup time for the test; it's automatically set based on @WakeupTime annotation
-    private int mWakeupTime;
 
-    // Value used to set config_disableUserSwitchDuringResume - must be defined before initTest();
-    private boolean mDisableUserSwitchDuringResume;
-
-    @Rule
-    public final TestRule setWakeupTimeRule = new TestWatcher() {
-        protected void starting(Description description) {
-            final String testName = description.getMethodName();
-            try {
-                Method testMethod = CarPowerManagementServiceTest.class.getMethod(testName);
-                WakeupTime wakeupAnnotation = testMethod.getAnnotation(WakeupTime.class);
-                if (wakeupAnnotation != null) {
-                    mWakeupTime = wakeupAnnotation.value();
-                    Log.d(TAG, "Using annotated wakeup time: " + mWakeupTime);
-                }
-            } catch (Exception e) {
-                Log.e(TAG, "Could not infer wakeupTime for " + testName, e);
-            }
-        }
-    };
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+        session
+            .spyStatic(ActivityManager.class)
+            .spyStatic(CarProperties.class);
+    }
 
     @Before
     public void setUp() throws Exception {
-        mSession = mockitoSession()
-                .strictness(Strictness.LENIENT)
-                .spyStatic(ActivityManager.class)
-                .startMocking();
         mPowerHal = new MockedPowerHalService(true /*isPowerStateSupported*/,
                 true /*isDeepSleepAllowed*/, true /*isTimedWakeupAllowed*/);
         mSystemInterface = SystemInterface.Builder.defaultSystemInterface(mContext)
@@ -152,6 +128,9 @@
             .withSystemStateInterface(mSystemStateInterface)
             .withWakeLockInterface(mWakeLockInterface)
             .withIOInterface(mIOInterface).build();
+
+        setCurrentUser(CURRENT_USER_ID, /* isGuest= */ false);
+        setService();
     }
 
     @After
@@ -159,47 +138,36 @@
         if (mService != null) {
             mService.release();
         }
+        CarServiceUtils.finishAllHandlerTasks();
         mIOInterface.tearDown();
-        mSession.finishMocking();
     }
 
     /**
      * Helper method to create mService and initialize a test case
      */
-    private void initTest() throws Exception {
+    private void setService() throws Exception {
         when(mResources.getInteger(R.integer.maxGarageModeRunningDurationInSecs))
                 .thenReturn(900);
-        when(mResources.getBoolean(R.bool.config_disableUserSwitchDuringResume))
-                .thenReturn(mDisableUserSwitchDuringResume);
-
-        Log.i(TAG, "initTest(): overridden overlay properties: "
+        Log.i(TAG, "setService(): overridden overlay properties: "
                 + "config_disableUserSwitchDuringResume="
                 + mResources.getBoolean(R.bool.config_disableUserSwitchDuringResume)
                 + ", maxGarageModeRunningDurationInSecs="
                 + mResources.getInteger(R.integer.maxGarageModeRunningDurationInSecs));
         mService = new CarPowerManagementService(mContext, mResources, mPowerHal,
-                mSystemInterface, mCarUserManagerHelper, mUserManager, NEW_GUEST_NAME);
+                mSystemInterface, mUserManager, mUserService, mInitialUserSetter,
+                mVoiceInteractionManagerService);
         mService.init();
-        CarPowerManagementService.setShutdownPrepareTimeout(0);
+        mService.setShutdownTimersForTest(0, 0);
         mPowerHal.setSignalListener(mPowerSignalListener);
-        if (mWakeupTime > 0) {
-            registerListenerToService();
-            mService.scheduleNextWakeupTime(mWakeupTime);
-        }
+        mService.scheduleNextWakeupTime(WAKE_UP_DELAY);
         assertStateReceived(MockedPowerHalService.SET_WAIT_FOR_VHAL, 0);
     }
 
     @Test
-    public void testBootComplete() throws Exception {
-        initTest();
-    }
-
-    @Test
     public void testDisplayOn() throws Exception {
         // start with display off
         mSystemInterface.setDisplayState(false);
         mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS);
-        initTest();
         // Transition to ON state
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
 
@@ -209,8 +177,25 @@
 
     @Test
     public void testShutdown() throws Exception {
-        initTest();
+        // Transition to ON state
+        mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
+        assertThat(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)).isTrue();
 
+        mPowerHal.setCurrentPowerState(
+                new PowerState(
+                        VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+                        VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY));
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_START);
+        assertThat(mService.garageModeShouldExitImmediately()).isFalse();
+        assertThat(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)).isFalse();
+        mPowerSignalListener.waitForShutdown(WAIT_TIMEOUT_MS);
+        // Send the finished signal
+        mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
+        mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
+    }
+
+    @Test
+    public void testShutdownImmediately() throws Exception {
         // Transition to ON state
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
         assertThat(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)).isTrue();
@@ -221,16 +206,17 @@
                         VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY));
         // Since modules have to manually schedule next wakeup, we should not schedule next wakeup
         // To test module behavior, we need to actually implement mock listener module.
-        assertStateReceived(PowerHalService.SET_SHUTDOWN_START, 0);
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_START, 0);
+        assertThat(mService.garageModeShouldExitImmediately()).isTrue();
         assertThat(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)).isFalse();
         mPowerSignalListener.waitForShutdown(WAIT_TIMEOUT_MS);
+        // Send the finished signal
+        mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
         mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
     }
 
     @Test
     public void testSuspend() throws Exception {
-        initTest();
-
         // Start in the ON state
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
         assertThat(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)).isTrue();
@@ -240,14 +226,12 @@
                         VehicleApPowerStateReq.SHUTDOWN_PREPARE,
                         VehicleApPowerStateShutdownParam.CAN_SLEEP));
         // Verify suspend
-        assertStateReceivedForShutdownOrSleepWithPostpone(
-                PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_LONG_MS, mWakeupTime);
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY);
+        assertThat(mService.garageModeShouldExitImmediately()).isFalse();
     }
 
     @Test
     public void testShutdownOnSuspend() throws Exception {
-        initTest();
-
         // Start in the ON state
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
         assertThat(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)).isTrue();
@@ -259,16 +243,14 @@
                         VehicleApPowerStateReq.SHUTDOWN_PREPARE,
                         VehicleApPowerStateShutdownParam.CAN_SLEEP));
         // Verify shutdown
-        assertStateReceivedForShutdownOrSleepWithPostpone(
-                PowerHalService.SET_SHUTDOWN_START, WAIT_TIMEOUT_LONG_MS, mWakeupTime);
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_START);
         mPowerSignalListener.waitForShutdown(WAIT_TIMEOUT_MS);
         // Send the finished signal
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
         mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
         // Cancel the shutdown
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.CANCEL_SHUTDOWN, 0));
-        assertStateReceivedForShutdownOrSleepWithPostpone(
-                PowerHalService.SET_SHUTDOWN_CANCELLED, WAIT_TIMEOUT_LONG_MS, 0);
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_CANCELLED);
 
         // Request suspend again
         mPowerHal.setCurrentPowerState(
@@ -276,14 +258,11 @@
                         VehicleApPowerStateReq.SHUTDOWN_PREPARE,
                         VehicleApPowerStateShutdownParam.CAN_SLEEP));
         // Verify suspend
-        assertStateReceivedForShutdownOrSleepWithPostpone(
-                PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_LONG_MS, mWakeupTime);
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY);
     }
 
     @Test
     public void testShutdownCancel() throws Exception {
-        initTest();
-
         // Start in the ON state
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
         assertThat(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)).isTrue();
@@ -292,43 +271,32 @@
                 new PowerState(
                         VehicleApPowerStateReq.SHUTDOWN_PREPARE,
                         VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY));
-        assertStateReceivedForShutdownOrSleepWithPostpone(
-                PowerHalService.SET_SHUTDOWN_START, WAIT_TIMEOUT_LONG_MS, 0);
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_START, 0);
         // Cancel the shutdown
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.CANCEL_SHUTDOWN, 0));
-        assertStateReceivedForShutdownOrSleepWithPostpone(
-                PowerHalService.SET_SHUTDOWN_CANCELLED, WAIT_TIMEOUT_LONG_MS, 0);
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_CANCELLED);
         // Go to suspend
         mPowerHal.setCurrentPowerState(
                 new PowerState(
                         VehicleApPowerStateReq.SHUTDOWN_PREPARE,
                         VehicleApPowerStateShutdownParam.CAN_SLEEP));
-        assertStateReceivedForShutdownOrSleepWithPostpone(
-                PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_LONG_MS, mWakeupTime);
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY);
     }
 
     @Test
-    @WakeupTime(100)
-    public void testShutdownWithProcessing() throws Exception {
-        initTest();
-        mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE, 0));
-        assertStateReceivedForShutdownOrSleepWithPostpone(
-                PowerHalService.SET_SHUTDOWN_START, WAIT_TIMEOUT_LONG_MS, mWakeupTime);
-        mPowerSignalListener.waitForShutdown(WAIT_TIMEOUT_MS);
-        // Send the finished signal
-        mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
-        mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
-    }
+    public void testSleepImmediately() throws Exception {
+        // Transition to ON state
+        mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
+        assertThat(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)).isTrue();
 
-    @Test
-    @WakeupTime(100)
-    public void testSleepEntryAndWakeup() throws Exception {
-        initTest();
-        mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
-                VehicleApPowerStateShutdownParam.CAN_SLEEP));
-        assertStateReceivedForShutdownOrSleepWithPostpone(
-                PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_LONG_MS, mWakeupTime);
+        mPowerHal.setCurrentPowerState(
+                new PowerState(
+                        VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+                        VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY));
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, 0);
+        assertThat(mService.garageModeShouldExitImmediately()).isTrue();
         mPowerSignalListener.waitForSleepEntry(WAIT_TIMEOUT_MS);
+
         // Send the finished signal from HAL to CPMS
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
         mSystemStateInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS);
@@ -337,270 +305,208 @@
     }
 
     @Test
-    public void testUserSwitchingOnResume_differentUser() throws Exception {
-        initTest();
-        setUserInfo(10, NO_USER_INFO_FLAGS);
-        setUserInfo(11, NO_USER_INFO_FLAGS);
-        setCurrentUser(10);
-        setInitialUser(11);
-
-        suspendAndResumeForUserSwitchingTests();
-
-        verifyUserSwitched(11);
+    public void testShutdownWithProcessing() throws Exception {
+        mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE, 0));
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_START);
+        mPowerSignalListener.waitForShutdown(WAIT_TIMEOUT_MS);
+        // Send the finished signal
+        mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
+        mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
     }
 
     @Test
-    public void testUserSwitchingOnResume_sameUser() throws Exception {
-        initTest();
-        setUserInfo(10, NO_USER_INFO_FLAGS);
-        setInitialUser(10);
-        setCurrentUser(10);
+    public void testSleepEntryAndWakeup() throws Exception {
+        mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+                VehicleApPowerStateShutdownParam.CAN_SLEEP));
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY);
+        mPowerSignalListener.waitForSleepEntry(WAIT_TIMEOUT_MS);
+        // Send the finished signal from HAL to CPMS
+        mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
+        mSystemStateInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS);
+        assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0);
+        mPowerSignalListener.waitForSleepExit(WAIT_TIMEOUT_MS);
+    }
 
+    /**
+     * This test case tests the same scenario as {@link #testUserSwitchingOnResume_differentUser()},
+     * but indirectly triggering {@code switchUserOnResumeIfNecessary()} through HAL events.
+     */
+    @Test
+    public void testSleepEntryAndWakeUpForProcessing() throws Exception {
+
+        // Speed up the polling for power state transitions
+        mService.setShutdownTimersForTest(10, 40);
+
+        suspendAndResume();
+
+        verifyDefaultInitialUserBehaviorCalled();
+    }
+
+    @Test
+    public void testUserSwitchingOnResume_noHal() throws Exception {
         suspendAndResumeForUserSwitchingTests();
 
+        verifyDefaultInitialUserBehaviorCalled();
+    }
+
+    @Test
+    public void testUserSwitchingOnResume_disabledByOEM_nonGuest() throws Exception {
+        UserInfo currentUser = setCurrentUser(CURRENT_USER_ID, /* isGuest= */ false);
+        expectNewGuestCreated(CURRENT_USER_ID, currentUser);
+
+        suspendAndResumeForUserSwitchingTestsWhileDisabledByOem();
+
         verifyUserNotSwitched();
     }
 
     @Test
-    public void testUserSwitchingOnResume_differentEphemeralUser() throws Exception {
-        initTest();
-        setUserInfo(10, NO_USER_INFO_FLAGS);
-        setUserInfo(11, FLAG_EPHEMERAL);
-        setCurrentUser(10);
-        setInitialUser(11);
+    public void testUserSwitchingOnResume_disabledByOEM_guest() throws Exception {
+        setCurrentUser(CURRENT_GUEST_ID, /* isGuest= */ true);
+        UserInfo newGuest = newGuestUser(NEW_GUEST_ID, /* ephemeral= */ true);
+        expectNewGuestCreated(CURRENT_GUEST_ID, newGuest);
 
-        suspendAndResumeForUserSwitchingTests();
+        suspendAndResumeForUserSwitchingTestsWhileDisabledByOem();
 
-        verifyUserSwitched(11);
+        verifyUserSwitched(NEW_GUEST_ID);
     }
 
     @Test
-    public void testUserSwitchingOnResume_sameGuest() throws Exception {
-        initTest();
-        setUserInfo(10, "ElGuesto", FLAG_GUEST | FLAG_EPHEMERAL);
-        setInitialUser(10);
-        setCurrentUser(10);
-        expectGuestMarkedForDeletionOk(10);
-        expectNewGuestCreated(11);
+    public void testUserSwitchingOnResume_disabledByOEM_guestReplacementFails() throws Exception {
+        setCurrentUser(CURRENT_GUEST_ID, /* isGuest= */ true);
+        expectNewGuestCreated(CURRENT_GUEST_ID, /* newGuest= */ null);
 
-        suspendAndResumeForUserSwitchingTests();
-
-        verifyUserRemoved(10);
-        verifyUserSwitched(11);
-    }
-
-    @Test
-    public void testUserSwitchingOnResume_differentGuest() throws Exception {
-        initTest();
-        setUserInfo(11, "ElGuesto", FLAG_GUEST | FLAG_EPHEMERAL);
-        setInitialUser(11);
-        setCurrentUser(10);
-        expectGuestMarkedForDeletionOk(11);
-        expectNewGuestCreated(12);
-
-        suspendAndResumeForUserSwitchingTests();
-
-        verifyUserRemoved(11);
-        verifyUserSwitched(12);
-    }
-
-    @Test
-    public void testUserSwitchingOnResume_guestCreationFailed() throws Exception {
-        initTest();
-        setUserInfo(10, "ElGuesto", FLAG_GUEST | FLAG_EPHEMERAL);
-        setInitialUser(10);
-        setCurrentUser(10);
-        expectGuestMarkedForDeletionOk(10);
-        expectNewGuestCreationFailed("ElGuesto");
-
-        suspendAndResumeForUserSwitchingTests();
+        suspendAndResumeForUserSwitchingTestsWhileDisabledByOem();
 
         verifyUserNotSwitched();
-        verifyUserNotRemoved(10);
+        verifyDefaultInitialUserBehaviorCalled();
     }
 
     @Test
-    public void testUserSwitchingOnResume_differentPersistentGuest() throws Exception {
-        initTest();
-        setUserInfo(11, "ElGuesto", FLAG_GUEST);
-        setInitialUser(11);
-        setCurrentUser(10);
-        expectGuestMarkedForDeletionOk(11);
-        expectNewGuestCreated(12);
-
-        suspendAndResumeForUserSwitchingTests();
-
-        verifyUserRemoved(11);
-        verifyUserSwitched(12);
+    public void testUserSwitchingUsingHal_failure_setTimeout() throws Exception {
+        userSwitchingWhenHalFailsTest(HalCallback.STATUS_HAL_SET_TIMEOUT);
     }
 
     @Test
-    public void testUserSwitchingOnResume_preDeleteGuestFail() throws Exception {
-        initTest();
-        setUserInfo(10, "ElGuesto", FLAG_GUEST | FLAG_EPHEMERAL);
-        setInitialUser(10);
-        setCurrentUser(10);
-        expectGuestMarkedForDeletionFail(10);
-
-        suspendAndResumeForUserSwitchingTests();
-
-        verifyUserNotSwitched();
-        verifyNoGuestCreated();
+    public void testUserSwitchingUsingHal_failure_responseTimeout() throws Exception {
+        userSwitchingWhenHalFailsTest(HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
     }
 
     @Test
-    public void testUserSwitchingOnResume_systemUser() throws Exception {
-        initTest();
-        setInitialUser(USER_SYSTEM);
-        setCurrentUser(10);
-
-        suspendAndResumeForUserSwitchingTests();
-
-        verifyUserNotSwitched();
+    public void testUserSwitchingUsingHal_failure_concurrentOperation() throws Exception {
+        userSwitchingWhenHalFailsTest(HalCallback.STATUS_CONCURRENT_OPERATION);
     }
 
     @Test
-    public void testUserSwitchingOnResume_disabledByOEM_differentUser() throws Exception {
-        disableUserSwitchingDuringResume();
-        initTest();
-        setUserInfo(10, NO_USER_INFO_FLAGS);
-        setUserInfo(11, NO_USER_INFO_FLAGS);
-        setCurrentUser(10);
-        setInitialUser(11);
-
-        suspendAndResumeForUserSwitchingTests();
-
-        verifyUserNotSwitched();
+    public void testUserSwitchingUsingHal_failure_wrongResponse() throws Exception {
+        userSwitchingWhenHalFailsTest(HalCallback.STATUS_WRONG_HAL_RESPONSE);
     }
 
     @Test
-    public void testUserSwitchingOnResume_disabledByOEM_sameUser() throws Exception {
-        disableUserSwitchingDuringResume();
-        initTest();
-        setUserInfo(10, NO_USER_INFO_FLAGS);
-        setInitialUser(10);
-        setCurrentUser(10);
+    public void testUserSwitchingUsingHal_failure_invalidResponse() throws Exception {
+        userSwitchingWhenHalFailsTest(-666);
+    }
+
+    /**
+     * Tests all scenarios where the HAL.getInitialUserInfo() call failed - the outcome is the
+     * same, it should use the default behavior.
+     */
+    private void userSwitchingWhenHalFailsTest(int status) throws Exception {
+        enableUserHal();
+
+        setGetUserInfoResponse((c) -> c.onResponse(status, /* response= */ null));
 
         suspendAndResumeForUserSwitchingTests();
 
-        verifyUserNotSwitched();
+        verifyDefaultInitialUserBehaviorCalled();
     }
 
     @Test
-    public void testUserSwitchingOnResume_disabledByOEM_differentEphemeralUser() throws Exception {
-        disableUserSwitchingDuringResume();
-        initTest();
-        setUserInfo(10, NO_USER_INFO_FLAGS);
-        setUserInfo(11, FLAG_EPHEMERAL);
-        setCurrentUser(10);
-        setInitialUser(11);
+    public void testUserSwitchingUsingHal_invalidAction() throws Exception {
+        enableUserHal();
+
+        InitialUserInfoResponse response = new InitialUserInfoResponse();
+        response.action = -666;
+        setGetUserInfoResponse((c) -> c.onResponse(HalCallback.STATUS_OK, response));
 
         suspendAndResumeForUserSwitchingTests();
 
-        verifyUserNotSwitched();
+        verifyDefaultInitialUserBehaviorCalled();
     }
 
     @Test
-    public void testUserSwitchingOnResume_disabledByOEM_sameGuest() throws Exception {
-        disableUserSwitchingDuringResume();
-        initTest();
-        setUserInfo(10, "ElGuesto", FLAG_GUEST | FLAG_EPHEMERAL);
-        setInitialUser(10);
-        setCurrentUser(10);
-        expectGuestMarkedForDeletionOk(10);
-        expectNewGuestCreated(11);
+    public void testUserSwitchingUsingHal_default_nullResponse() throws Exception {
+        enableUserHal();
 
+        setGetUserInfoResponse((c) -> c.onResponse(HalCallback.STATUS_OK, /* response= */ null));
         suspendAndResumeForUserSwitchingTests();
 
-        verifyUserRemoved(10);
-        verifyUserSwitched(11);
-
+        verifyDefaultInitialUserBehaviorCalled();
     }
 
     @Test
-    public void testUserSwitchingOnResume_disabledByOEM_differentGuest() throws Exception {
-        disableUserSwitchingDuringResume();
-        initTest();
-        setUserInfo(11, "ElGuesto", FLAG_GUEST | FLAG_EPHEMERAL);
-        setInitialUser(11);
-        setCurrentUser(10);
-        expectGuestMarkedForDeletionOk(11);
-        expectNewGuestCreated(12);
+    public void testUserSwitchingUsingHal_default_ok() throws Exception {
+        enableUserHal();
+
+        InitialUserInfoResponse response = new InitialUserInfoResponse();
+        response.action = InitialUserInfoResponseAction.DEFAULT;
+        setGetUserInfoResponse((c) -> c.onResponse(HalCallback.STATUS_OK, response));
 
         suspendAndResumeForUserSwitchingTests();
 
-        verifyUserRemoved(11);
-        verifyUserSwitched(12);
+        verifyDefaultInitialUserBehaviorCalled();
     }
 
     @Test
-    public void testUserSwitchingOnResume_disabledByOEM_guestCreationFailed() throws Exception {
-        disableUserSwitchingDuringResume();
-        initTest();
-        initTest();
-        setUserInfo(10, "ElGuesto", FLAG_GUEST | FLAG_EPHEMERAL);
-        setInitialUser(10);
-        setCurrentUser(10);
-        expectGuestMarkedForDeletionOk(10);
-        expectNewGuestCreationFailed("ElGuesto");
+    public void testUserSwitchingUsingHal_switch() throws Exception {
+        enableUserHal();
+
+        InitialUserInfoResponse response = new InitialUserInfoResponse();
+        response.action = InitialUserInfoResponseAction.SWITCH;
+        response.userToSwitchOrCreate.userId = 10;
+        setGetUserInfoResponse((c) -> c.onResponse(HalCallback.STATUS_OK, response));
 
         suspendAndResumeForUserSwitchingTests();
 
-        verifyUserNotSwitched();
-        verifyUserNotRemoved(10);
+        verifyUserSwitched(10);
+        verifyDefaultInitilUserBehaviorNeverCalled();
     }
 
     @Test
-    public void testUserSwitchingOnResume_disabledByOEM_differentPersistentGuest()
-            throws Exception {
-        disableUserSwitchingDuringResume();
-        initTest();
-        setUserInfo(11, "ElGuesto", FLAG_GUEST);
-        setInitialUser(11);
-        setCurrentUser(10);
-        expectGuestMarkedForDeletionOk(11);
-        expectNewGuestCreated(12);
+    public void testUserSwitchingUsingHal_create() throws Exception {
+        enableUserHal();
+
+        InitialUserInfoResponse response = new InitialUserInfoResponse();
+        response.action = InitialUserInfoResponseAction.CREATE;
+        response.userToSwitchOrCreate.flags = 42;
+        response.userNameToCreate = "Duffman";
+        setGetUserInfoResponse((c) -> c.onResponse(HalCallback.STATUS_OK, response));
 
         suspendAndResumeForUserSwitchingTests();
 
-        verifyUserRemoved(11);
-        verifyUserSwitched(12);
+        verifyUserCreated("Duffman", 42);
+        verifyDefaultInitilUserBehaviorNeverCalled();
     }
 
-    @Test
-    public void testUserSwitchingOnResume_disabledByOEM_preDeleteGuestFail() throws Exception {
-        disableUserSwitchingDuringResume();
-        initTest();
-        setUserInfo(10, "ElGuesto", FLAG_GUEST | FLAG_EPHEMERAL);
-        setInitialUser(10);
-        setCurrentUser(10);
-        expectGuestMarkedForDeletionFail(10);
-
-        suspendAndResumeForUserSwitchingTests();
-
-        verifyUserNotSwitched();
-        verifyNoGuestCreated();
+    private void setGetUserInfoResponse(Visitor<HalCallback<InitialUserInfoResponse>> visitor) {
+        doAnswer((invocation) -> {
+            HalCallback<InitialUserInfoResponse> callback = invocation.getArgument(1);
+            visitor.visit(callback);
+            return null;
+        }).when(mUserService).getInitialUserInfo(eq(InitialUserInfoRequestType.RESUME), notNull());
     }
 
-    @Test
-    public void testUserSwitchingOnResume_disabledByOEM_systemUser() throws Exception {
-        disableUserSwitchingDuringResume();
-        initTest();
-        setInitialUser(USER_SYSTEM);
-        setCurrentUser(10);
-
-        suspendAndResumeForUserSwitchingTests();
-
-        verifyUserNotSwitched();
+    private void enableUserHal() {
+        doReturn(Optional.of(true)).when(() -> CarProperties.user_hal_enabled());
+        when(mUserService.isUserHalSupported()).thenReturn(true);
     }
 
-    private void suspendAndResumeForUserSwitchingTests() throws Exception {
+    private void suspendAndResume() throws Exception {
         Log.d(TAG, "suspend()");
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
                 VehicleApPowerStateShutdownParam.CAN_SLEEP));
         assertThat(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)).isFalse();
-        assertStateReceivedForShutdownOrSleepWithPostpone(
-                PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_LONG_MS, mWakeupTime);
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY);
+        assertVoiceInteractionDisabled();
         mPowerSignalListener.waitForSleepEntry(WAIT_TIMEOUT_MS);
 
         // Send the finished signal
@@ -610,7 +516,7 @@
         mSystemStateInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS);
         assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0);
         mPowerSignalListener.waitForSleepExit(WAIT_TIMEOUT_MS);
-        mService.scheduleNextWakeupTime(mWakeupTime);
+        mService.scheduleNextWakeupTime(WAKE_UP_DELAY);
         // second processing after wakeup
         assertThat(mDisplayInterface.getDisplayState()).isFalse();
 
@@ -622,8 +528,7 @@
         CarServiceUtils.runOnLooperSync(mService.getHandlerThread().getLooper(), () -> { });
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
                 VehicleApPowerStateShutdownParam.CAN_SLEEP));
-        assertStateReceivedForShutdownOrSleepWithPostpone(
-                PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_LONG_MS, mWakeupTime);
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY);
         mPowerSignalListener.waitForSleepEntry(WAIT_TIMEOUT_MS);
         mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
         // PM will shutdown system as it was not woken-up due timer and it is not power on.
@@ -631,27 +536,16 @@
         mSystemStateInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS);
         // Since we just woke up from shutdown, wake up time will be 0
         assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0);
+        assertVoiceInteractionEnabled();
         assertThat(mDisplayInterface.getDisplayState()).isFalse();
     }
 
-    private void registerListenerToService() {
-        ICarPowerStateListener listenerToService = new ICarPowerStateListener.Stub() {
-            @Override
-            public void onStateChanged(int state) throws RemoteException {
-                if (state == CarPowerStateListener.SHUTDOWN_ENTER
-                        || state == CarPowerStateListener.SUSPEND_ENTER) {
-                    mFuture = new CompletableFuture<>();
-                    mFuture.whenComplete((res, ex) -> {
-                        if (ex == null) {
-                            mService.finished(this);
-                        }
-                    });
-                } else {
-                    mFuture = null;
-                }
-            }
-        };
-        mService.registerListener(listenerToService);
+    private void suspendAndResumeForUserSwitchingTests() throws Exception {
+        mService.switchUserOnResumeIfNecessary(/* allowSwitching= */ true);
+    }
+
+    private void suspendAndResumeForUserSwitchingTestsWhileDisabledByOem() throws Exception {
+        mService.switchUserOnResumeIfNecessary(/* allowSwitching= */ false);
     }
 
     private void assertStateReceived(int expectedState, int expectedParam) throws Exception {
@@ -660,23 +554,40 @@
         assertThat(state[1]).isEqualTo(expectedParam);
     }
 
-    private void assertStateReceivedForShutdownOrSleepWithPostpone(
-            int lastState, long timeoutMs, int expectedParamForShutdownOrSuspend) throws Exception {
+    private void assertStateReceivedForShutdownOrSleepWithPostpone(int lastState,
+            int expectedSecondParameter)
+            throws Exception {
         while (true) {
             if (mFuture != null && !mFuture.isDone()) {
                 mFuture.complete(null);
             }
-            int[] state = mPowerHal.waitForSend(timeoutMs);
+            int[] state = mPowerHal.waitForSend(WAIT_TIMEOUT_LONG_MS);
             if (state[0] == PowerHalService.SET_SHUTDOWN_POSTPONE) {
                 continue;
             }
             if (state[0] == lastState) {
-                assertThat(state[1]).isEqualTo(expectedParamForShutdownOrSuspend);
+                assertThat(state[1]).isEqualTo(expectedSecondParameter);
                 return;
             }
         }
     }
 
+    private void assertStateReceivedForShutdownOrSleepWithPostpone(int lastState) throws Exception {
+        int expectedSecondParameter =
+                (lastState == MockedPowerHalService.SET_DEEP_SLEEP_ENTRY
+                        || lastState == MockedPowerHalService.SET_SHUTDOWN_START)
+                        ? WAKE_UP_DELAY : 0;
+        assertStateReceivedForShutdownOrSleepWithPostpone(lastState, expectedSecondParameter);
+    }
+
+    private void assertVoiceInteractionEnabled() throws Exception {
+        verify(mVoiceInteractionManagerService).setDisabled(false);
+    }
+
+    private void assertVoiceInteractionDisabled() throws Exception {
+        verify(mVoiceInteractionManagerService).setDisabled(true);
+    }
+
     private static void waitForSemaphore(Semaphore semaphore, long timeoutMs)
             throws InterruptedException {
         if (!semaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
@@ -684,68 +595,58 @@
         }
     }
 
-    private void setInitialUser(int userId) {
-        when(mCarUserManagerHelper.getInitialUser()).thenReturn(userId);
-    }
-
-    private void setCurrentUser(int userId) {
-        when(ActivityManager.getCurrentUser()).thenReturn(userId);
-    }
-
-    private void setUserInfo(int userId, int flags) {
-        setUserInfo(userId, /* name= */ null, flags);
-    }
-
-    private void setUserInfo(int userId, @Nullable String name, int flags) {
+    private UserInfo setCurrentUser(int userId, boolean isGuest) {
+        mockGetCurrentUser(userId);
         final UserInfo userInfo = new UserInfo();
         userInfo.id = userId;
-        userInfo.name = name;
-        userInfo.flags = flags;
+        userInfo.userType = isGuest
+                ? UserManager.USER_TYPE_FULL_GUEST
+                : UserManager.USER_TYPE_FULL_SECONDARY;
         Log.v(TAG, "UM.getUserInfo("  + userId + ") will return " + userInfo.toFullString());
         when(mUserManager.getUserInfo(userId)).thenReturn(userInfo);
+        return userInfo;
     }
 
     private void verifyUserNotSwitched() {
-        verify(mCarUserManagerHelper, never()).switchToUserId(anyInt());
+        verify(mInitialUserSetter, never()).set(argThat((info) -> {
+            return info.type == InitialUserSetter.TYPE_SWITCH;
+        }));
     }
 
     private void verifyUserSwitched(int userId) {
-        verify(mCarUserManagerHelper, times(1)).switchToUserId(userId);
+        // TODO(b/153679319): pass proper value for replaceGuest
+        verify(mInitialUserSetter).set(argThat((info) -> {
+            return info.type == InitialUserSetter.TYPE_SWITCH
+                    && info.switchUserId == userId
+                    && info.replaceGuest;
+        }));
     }
 
-    private void verifyNoGuestCreated() {
-        verify(mUserManager, never()).createGuest(notNull(), anyString());
+    private void expectNewGuestCreated(int existingGuestId, UserInfo newGuest) {
+        when(mInitialUserSetter.replaceGuestIfNeeded(isUserInfo(existingGuestId)))
+                .thenReturn(newGuest);
     }
 
-    private void expectGuestMarkedForDeletionOk(int userId) {
-        when(mUserManager.markGuestForDeletion(userId)).thenReturn(true);
+    private void verifyDefaultInitialUserBehaviorCalled() {
+        // TODO(b/153679319): pass proper value for replaceGuest
+        verify(mInitialUserSetter).set(argThat((info) -> {
+            return info.type == InitialUserSetter.TYPE_DEFAULT_BEHAVIOR
+                    && info.replaceGuest;
+        }));
     }
 
-    private void expectGuestMarkedForDeletionFail(int userId) {
-        when(mUserManager.markGuestForDeletion(userId)).thenReturn(false);
+    private void verifyDefaultInitilUserBehaviorNeverCalled() {
+        verify(mInitialUserSetter, never()).set(argThat((info) -> {
+            return info.type == InitialUserSetter.TYPE_DEFAULT_BEHAVIOR;
+        }));
     }
 
-    private void expectNewGuestCreated(int userId) {
-        final UserInfo userInfo = new UserInfo();
-        userInfo.id = userId;
-        userInfo.name = NEW_GUEST_NAME;
-        when(mUserManager.createGuest(notNull(), eq(NEW_GUEST_NAME))).thenReturn(userInfo);
-    }
-
-    private void expectNewGuestCreationFailed(String name) {
-        when(mUserManager.createGuest(notNull(), eq(name))).thenReturn(null);
-    }
-
-    private void verifyUserRemoved(int userId) {
-        verify(mUserManager, times(1)).removeUser(userId);
-    }
-
-    private void verifyUserNotRemoved(int userId) {
-        verify(mUserManager, never()).removeUser(userId);
-    }
-
-    private void disableUserSwitchingDuringResume() {
-        mDisableUserSwitchDuringResume = true;
+    private void verifyUserCreated(String name, int halFlags) {
+        verify(mInitialUserSetter).set(argThat((info) -> {
+            return info.type == InitialUserSetter.TYPE_CREATE
+                    && info.newUserName == name
+                    && info.newUserFlags == halFlags;
+        }));
     }
 
     private static final class MockDisplayInterface implements DisplayInterface {
@@ -778,9 +679,6 @@
 
         @Override
         public void refreshDisplayBrightness() {}
-
-        @Override
-        public void reconfigureSecondaryDisplays() {}
     }
 
     private static final class MockSystemStateInterface implements SystemStateInterface {
@@ -904,10 +802,4 @@
             }
         }
     }
-
-    @Retention(RUNTIME)
-    @Target({METHOD})
-    public static @interface WakeupTime {
-        int value();
-    }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/CarProjectionServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarProjectionServiceTest.java
index 2866d11..3a2ad2e 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarProjectionServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarProjectionServiceTest.java
@@ -51,18 +51,15 @@
 import android.os.RemoteException;
 
 import androidx.test.core.app.ApplicationProvider;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.Spy;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import java.util.Arrays;
 import java.util.BitSet;
@@ -70,7 +67,7 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-@RunWith(AndroidJUnit4.class)
+@RunWith(MockitoJUnitRunner.class)
 public class CarProjectionServiceTest {
     private static final int MD_ID1 = 1;
     private static final int MD_ID2 = 2;
@@ -84,9 +81,6 @@
 
     private final IBinder mToken = new Binder();
 
-    @Rule
-    public MockitoRule rule = MockitoJUnit.rule();
-
     private CarProjectionService mService;
 
     @Spy
diff --git a/tests/carservice_unit_test/src/com/android/car/LocationManagerProxyTest.java b/tests/carservice_unit_test/src/com/android/car/LocationManagerProxyTest.java
index 6fa4e3b..d298564 100644
--- a/tests/carservice_unit_test/src/com/android/car/LocationManagerProxyTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/LocationManagerProxyTest.java
@@ -27,14 +27,16 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnitRunner;
 
 /**
  * This class contains unit tests for {@link LocationManagerProxy}.
  *
  * Mocks are used for {@link Context} and {@link LocationManager}.
  */
+@RunWith(MockitoJUnitRunner.class)
 public class LocationManagerProxyTest {
     private static final String TAG = "LocationManagerProxyTest";
     private LocationManagerProxy mLocationManagerProxy;
@@ -46,7 +48,6 @@
     /** Initialize all of the objects with the @Mock annotation. */
     @Before
     public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
         when(mMockContext.getSystemService(Context.LOCATION_SERVICE))
                 .thenReturn(mMockLocationManager);
         mLocationManagerProxy = new LocationManagerProxy(mMockContext);
diff --git a/tests/carservice_unit_test/src/com/android/car/SystemActivityMonitoringServiceTest.java b/tests/carservice_unit_test/src/com/android/car/SystemActivityMonitoringServiceTest.java
new file mode 100644
index 0000000..66a522e
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/SystemActivityMonitoringServiceTest.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.NonNull;
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.app.Instrumentation.ActivityMonitor;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.Display;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import com.android.car.SystemActivityMonitoringService.TopTaskInfoContainer;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.BooleanSupplier;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class SystemActivityMonitoringServiceTest {
+    private static final String TAG = "SystemActivityMonitoringServiceTest";
+
+    private static final long ACTIVITY_TIMEOUT_MS = 5000;
+    private static final long DEFAULT_TIMEOUT_MS = 10_000;
+    private static final int SLEEP_MS = 50;
+
+    private SystemActivityMonitoringService mService;
+
+    @Before
+    public void setUp() throws Exception {
+        mService = new SystemActivityMonitoringService(getContext());
+        mService.init();
+    }
+
+    @After
+    public void tearDown() {
+        mService.registerActivityLaunchListener(null);
+        mService.release();
+        mService = null;
+    }
+
+    @Test
+    public void testActivityLaunch() throws Exception {
+        ComponentName activityA = toComponentName(getTestContext(), ActivityA.class);
+        FilteredLaunchListener listenerA = new FilteredLaunchListener(activityA);
+        mService.registerActivityLaunchListener(listenerA);
+        startActivity(activityA);
+        listenerA.assertTopTaskActivityLaunched();
+
+        ComponentName activityB = toComponentName(getTestContext(), ActivityB.class);
+        FilteredLaunchListener listenerB = new FilteredLaunchListener(activityB);
+        mService.registerActivityLaunchListener(listenerB);
+        startActivity(activityB);
+        listenerB.assertTopTaskActivityLaunched();
+    }
+
+    @Test
+    public void testActivityBlocking() throws Exception {
+        ComponentName blackListedActivity = toComponentName(getTestContext(), ActivityC.class);
+        ComponentName blockingActivity = toComponentName(getTestContext(), BlockingActivity.class);
+        Intent blockingIntent = new Intent();
+        blockingIntent.setComponent(blockingActivity);
+
+        // start a black listed activity
+        FilteredLaunchListener listenerBlackListed =
+                new FilteredLaunchListener(blackListedActivity);
+        mService.registerActivityLaunchListener(listenerBlackListed);
+        startActivity(blackListedActivity);
+        listenerBlackListed.assertTopTaskActivityLaunched();
+
+        // Instead of start activity, invoke blockActivity.
+        FilteredLaunchListener listenerBlocking = new FilteredLaunchListener(blockingActivity);
+        mService.registerActivityLaunchListener(listenerBlocking);
+        mService.blockActivity(listenerBlackListed.mTopTask, blockingIntent);
+        listenerBlocking.assertTopTaskActivityLaunched();
+    }
+
+    @Test
+    public void testRemovesFromTopTasks() throws Exception {
+        ComponentName activityA = toComponentName(getTestContext(), ActivityA.class);
+        FilteredLaunchListener listenerA = new FilteredLaunchListener(activityA);
+        mService.registerActivityLaunchListener(listenerA);
+        Activity launchedActivity = startActivity(activityA);
+        listenerA.assertTopTaskActivityLaunched();
+        assertTrue(topTasksHasComponent(activityA));
+
+        getInstrumentation().runOnMainSync(launchedActivity::finish);
+        waitUntil(() -> !topTasksHasComponent(activityA));
+    }
+
+    @Test
+    public void testGetTopTasksOnMultiDisplay() throws Exception {
+        String virtualDisplayName = "virtual_display";
+        DisplayManager displayManager = getContext().getSystemService(DisplayManager.class);
+        VirtualDisplay virtualDisplay = displayManager.createVirtualDisplay(
+                virtualDisplayName, 10, 10, 10, null, 0);
+
+        ComponentName activityA = toComponentName(getTestContext(), ActivityA.class);
+        FilteredLaunchListener listenerA = new FilteredLaunchListener(activityA);
+        mService.registerActivityLaunchListener(listenerA);
+        startActivity(activityA, Display.DEFAULT_DISPLAY);
+        listenerA.assertTopTaskActivityLaunched();
+        assertTrue(topTasksHasComponent(activityA));
+
+        ComponentName activityB = toComponentName(getTestContext(), ActivityB.class);
+        FilteredLaunchListener listenerB = new FilteredLaunchListener(activityB);
+        mService.registerActivityLaunchListener(listenerB);
+        startActivity(activityB, virtualDisplay.getDisplay().getDisplayId());
+        listenerB.assertTopTaskActivityLaunched();
+        assertTrue(topTasksHasComponent(activityB));
+
+        virtualDisplay.release();
+    }
+
+    private void waitUntil(BooleanSupplier condition) {
+        for (long i = DEFAULT_TIMEOUT_MS / SLEEP_MS; !condition.getAsBoolean() && i > 0; --i) {
+            SystemClock.sleep(SLEEP_MS);
+        }
+        if (!condition.getAsBoolean()) {
+            throw new RuntimeException("failed while waiting for condition to become true");
+        }
+    }
+
+    private boolean topTasksHasComponent(ComponentName component) {
+        for (TopTaskInfoContainer topTaskInfoContainer : mService.getTopTasks()) {
+            if (topTaskInfoContainer.topActivity.equals(component)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /** Activity that closes itself after some timeout to clean up the screen. */
+    public static class TempActivity extends Activity {
+        @Override
+        protected void onResume() {
+            super.onResume();
+            getMainThreadHandler().postDelayed(this::finish, ACTIVITY_TIMEOUT_MS);
+        }
+    }
+
+    public static class ActivityA extends TempActivity {}
+
+    public static class ActivityB extends TempActivity {}
+
+    public static class ActivityC extends TempActivity {}
+
+    public static class BlockingActivity extends TempActivity {}
+
+    private Context getContext() {
+        return getInstrumentation().getTargetContext();
+    }
+
+    private Context getTestContext() {
+        return getInstrumentation().getContext();
+    }
+
+    private static ComponentName toComponentName(Context ctx, Class<?> cls) {
+        return ComponentName.createRelative(ctx, cls.getName());
+    }
+
+    private Activity startActivity(ComponentName name) {
+        return startActivity(name, Display.DEFAULT_DISPLAY);
+    }
+
+    private Activity startActivity(ComponentName name, int displayId) {
+        ActivityMonitor monitor = new ActivityMonitor(name.getClassName(), null, false);
+        getInstrumentation().addMonitor(monitor);
+
+        Intent intent = new Intent();
+        intent.setComponent(name);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(displayId);
+
+        getContext().startActivity(intent, options.toBundle());
+        return monitor.waitForActivityWithTimeout(ACTIVITY_TIMEOUT_MS);
+    }
+
+    private class FilteredLaunchListener
+            implements SystemActivityMonitoringService.ActivityLaunchListener {
+
+        private final ComponentName mDesiredComponent;
+        private final CountDownLatch mActivityLaunched = new CountDownLatch(1);
+        private TopTaskInfoContainer mTopTask;
+
+        /**
+         * Creates an instance of an
+         * {@link com.android.car.SystemActivityMonitoringService.ActivityLaunchListener}
+         * that filters based on the component name or does not filter if component name is null.
+         */
+        FilteredLaunchListener(@NonNull ComponentName desiredComponent) {
+            mDesiredComponent = desiredComponent;
+        }
+
+        @Override
+        public void onActivityLaunch(TopTaskInfoContainer topTask) {
+            // Ignore activities outside of this test case
+            if (!getTestContext().getPackageName().equals(topTask.topActivity.getPackageName())) {
+                Log.d(TAG, "Component launched from other package: "
+                        + topTask.topActivity.getClassName());
+                return;
+            }
+            if (!topTask.topActivity.equals(mDesiredComponent)) {
+                Log.d(TAG, String.format("Unexpected component: %s. Expected: %s",
+                        topTask.topActivity.getClassName(), mDesiredComponent));
+                return;
+            }
+            if (mTopTask == null) {  // We are interested in the first one only.
+                mTopTask = topTask;
+            }
+            mActivityLaunched.countDown();
+        }
+
+        void assertTopTaskActivityLaunched() throws InterruptedException {
+            assertTrue(mActivityLaunched.await(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/SystemStateInterfaceTest.java b/tests/carservice_unit_test/src/com/android/car/SystemStateInterfaceTest.java
index 5f8ac00..838d066 100644
--- a/tests/carservice_unit_test/src/com/android/car/SystemStateInterfaceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/SystemStateInterfaceTest.java
@@ -18,7 +18,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.content.ComponentName;
 import android.content.Context;
+import android.os.RemoteException;
 
 import com.android.car.systeminterface.SystemStateInterface;
 import com.android.internal.car.ICarServiceHelper;
@@ -29,6 +31,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.List;
+
 /**
  * Unit tests for {@link SystemStateInterface}
  *
@@ -87,12 +91,32 @@
         public int forceSuspend(int timeoutMs) {
             return 0; // Success
         }
+        @Override
+        public void setDisplayWhitelistForUser(int userId, int[] displayIds) {
+        }
+        @Override
+        public void setPassengerDisplays(int[] displayIdsForPassenger) {
+        }
+        @Override
+        public void setSourcePreferredComponents(boolean enableSourcePreferred,
+                List<ComponentName> sourcePreferredComponents) throws RemoteException {
+        }
     }
     private static class TestServiceHelperFails extends ICarServiceHelper.Stub {
         @Override
         public int forceSuspend(int timeoutMs) {
             return 1; // Failure
         }
+        @Override
+        public void setDisplayWhitelistForUser(int userId, int[] displayIds) {
+        }
+        @Override
+        public void setPassengerDisplays(int[] displayIdsForPassenger) {
+        }
+        @Override
+        public void setSourcePreferredComponents(boolean enableSourcePreferred,
+                List<ComponentName> sourcePreferredComponents) throws RemoteException {
+        }
     }
     // Invoke enterDeepSleep() before setting the helper.
     // Return the result from enterDeepSleep().
diff --git a/tests/carservice_unit_test/src/com/android/car/VmsAssociatedLayerTest.java b/tests/carservice_unit_test/src/com/android/car/VmsAssociatedLayerTest.java
deleted file mode 100644
index 1d384cc..0000000
--- a/tests/carservice_unit_test/src/com/android/car/VmsAssociatedLayerTest.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import static org.junit.Assert.assertNotEquals;
-
-import android.car.vms.VmsAssociatedLayer;
-import android.car.vms.VmsLayer;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import android.os.Parcel;
-
-import java.util.Arrays;
-import java.util.HashSet;
-
-
-/*
- * A class to test the VmsAssociatedLayer parcelability.
- */
-@SmallTest
-public class VmsAssociatedLayerTest extends AndroidTestCase {
-    private static final int LAYER_ID = 12;
-    private static final int LAYER_VERSION = 34;
-    private static final int LAYER_SUBTYPE = 56;
-
-    private static final int PUBLISHER_ID_1 = 111;
-    private static final int PUBLISHER_ID_2 = 222;
-
-    private static final int DIFFERENT_LAYER_ID = 99;
-
-    private static final VmsLayer VMS_LAYER = new VmsLayer(
-            LAYER_ID,
-            LAYER_SUBTYPE,
-            LAYER_VERSION);
-
-    private static final VmsLayer ANOTHER_VMS_LAYER = new VmsLayer(
-            DIFFERENT_LAYER_ID,
-            LAYER_SUBTYPE,
-            LAYER_VERSION);
-
-
-    public void testNoPublishersAssociatedLayerParcel() throws Exception {
-        VmsAssociatedLayer vmsAssociatedLayer =
-                new VmsAssociatedLayer(
-                        VMS_LAYER,
-                        new HashSet<>(Arrays.asList()));
-        Parcel parcel = Parcel.obtain();
-        vmsAssociatedLayer.writeToParcel(parcel, vmsAssociatedLayer.describeContents());
-        parcel.setDataPosition(0);
-        VmsAssociatedLayer createdFromParcel = VmsAssociatedLayer.CREATOR.createFromParcel(parcel);
-        assertEquals(vmsAssociatedLayer, createdFromParcel);
-    }
-
-    public void testLayerWithMultiplePublishersParcel() throws Exception {
-        VmsAssociatedLayer vmsAssociatedLayer =
-                new VmsAssociatedLayer(
-                        VMS_LAYER,
-                        new HashSet<>(Arrays.asList(PUBLISHER_ID_1, PUBLISHER_ID_2)));
-        Parcel parcel = Parcel.obtain();
-        vmsAssociatedLayer.writeToParcel(parcel, vmsAssociatedLayer.describeContents());
-        parcel.setDataPosition(0);
-        VmsAssociatedLayer createdFromParcel = VmsAssociatedLayer.CREATOR.createFromParcel(parcel);
-        assertEquals(vmsAssociatedLayer, createdFromParcel);
-    }
-
-    public void testNoPublishersAssociatedLayerEquality() throws Exception {
-        VmsAssociatedLayer original =
-                new VmsAssociatedLayer(
-                        VMS_LAYER,
-                        new HashSet<>(Arrays.asList()));
-
-        VmsAssociatedLayer similar =
-                new VmsAssociatedLayer(
-                        VMS_LAYER,
-                        new HashSet<>(Arrays.asList()));
-
-        assertEquals(original.getVmsLayer(), similar.getVmsLayer());
-        assertEquals(original.getPublisherIds(), similar.getPublisherIds());
-        assertEquals(original, similar);
-    }
-
-    public void testLayerWithMultiplePublishersEquality() throws Exception {
-        VmsAssociatedLayer original =
-                new VmsAssociatedLayer(
-                        VMS_LAYER,
-                        new HashSet<>(Arrays.asList(PUBLISHER_ID_1, PUBLISHER_ID_2)));
-
-        VmsAssociatedLayer similar =
-                new VmsAssociatedLayer(
-                        VMS_LAYER,
-                        new HashSet<>(Arrays.asList(PUBLISHER_ID_1, PUBLISHER_ID_2)));
-
-        assertEquals(original.getVmsLayer(), similar.getVmsLayer());
-        assertEquals(original.getPublisherIds(), similar.getPublisherIds());
-        assertEquals(original, similar);
-    }
-
-    public void testVerifyNonEqualOnLayer() throws Exception {
-        VmsAssociatedLayer original =
-                new VmsAssociatedLayer(
-                        ANOTHER_VMS_LAYER,
-                        new HashSet<>(Arrays.asList()));
-
-        VmsAssociatedLayer similar =
-                new VmsAssociatedLayer(
-                        VMS_LAYER,
-                        new HashSet<>(Arrays.asList()));
-
-        assertNotEquals(original, similar);
-    }
-
-    public void testVerifyNonEqualOnPublisherIds() throws Exception {
-        VmsAssociatedLayer original =
-                new VmsAssociatedLayer(
-                        VMS_LAYER,
-                        new HashSet<>(Arrays.asList(PUBLISHER_ID_1)));
-
-        VmsAssociatedLayer similar =
-                new VmsAssociatedLayer(
-                        VMS_LAYER,
-                        new HashSet<>(Arrays.asList(PUBLISHER_ID_2)));
-
-        assertNotEquals(original, similar);
-    }
-}
\ No newline at end of file
diff --git a/tests/carservice_unit_test/src/com/android/car/VmsAvailableLayersTest.java b/tests/carservice_unit_test/src/com/android/car/VmsAvailableLayersTest.java
deleted file mode 100644
index 63ac1a3..0000000
--- a/tests/carservice_unit_test/src/com/android/car/VmsAvailableLayersTest.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import static org.junit.Assert.assertNotEquals;
-
-import android.car.vms.VmsAssociatedLayer;
-import android.car.vms.VmsAvailableLayers;
-import android.car.vms.VmsLayer;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import android.os.Parcel;
-
-import java.util.Arrays;
-import java.util.HashSet;
-
-
-/*
- * A class to test the VmsAvailableLayers parcelability.
- */
-@SmallTest
-public class VmsAvailableLayersTest extends AndroidTestCase {
-    private static final int LAYER_ID = 12;
-    private static final int LAYER_VERSION = 34;
-    private static final int LAYER_SUBTYPE = 56;
-    private static final int PUBLISHER_ID = 999;
-    private static final int SEQUENCE_NUMBER = 17;
-
-    private static final int DIFFERENT_SEQUENCE_NUMBER = 71;
-    private static final int DIFFERENT_LAYER_ID = 21;
-
-    private static final VmsLayer VMS_LAYER = new VmsLayer(
-            LAYER_ID,
-            LAYER_SUBTYPE,
-            LAYER_VERSION);
-
-    private static final VmsLayer ANOTHER_VMS_LAYER = new VmsLayer(
-            DIFFERENT_LAYER_ID,
-            LAYER_SUBTYPE,
-            LAYER_VERSION);
-
-    private static final VmsAssociatedLayer VMS_ASSOCIATED_LAYER = new VmsAssociatedLayer(
-            VMS_LAYER,
-            new HashSet<>(Arrays.asList(PUBLISHER_ID)));
-
-    private static final VmsAssociatedLayer ANOTHER_VMS_ASSOCIATED_LAYER = new VmsAssociatedLayer(
-            ANOTHER_VMS_LAYER,
-            new HashSet<>(Arrays.asList(PUBLISHER_ID)));
-
-    public void testNoAvailableLayersParcel() throws Exception {
-        VmsAvailableLayers vmsAvailableLayers =
-                new VmsAvailableLayers(new HashSet<>(Arrays.asList()), SEQUENCE_NUMBER);
-
-        Parcel parcel = Parcel.obtain();
-
-        vmsAvailableLayers.writeToParcel(parcel, vmsAvailableLayers.describeContents());
-        parcel.setDataPosition(0);
-        VmsAvailableLayers createdFromParcel = VmsAvailableLayers.CREATOR.createFromParcel(parcel);
-        assertEquals(vmsAvailableLayers, createdFromParcel);
-    }
-
-    public void testMultipleAvailableLayersParcel() throws Exception {
-        VmsAvailableLayers vmsAvailableLayers =
-                new VmsAvailableLayers(
-                        new HashSet<>(Arrays.asList(
-                                VMS_ASSOCIATED_LAYER,
-                                ANOTHER_VMS_ASSOCIATED_LAYER)),
-                        SEQUENCE_NUMBER);
-
-        Parcel parcel = Parcel.obtain();
-
-        vmsAvailableLayers.writeToParcel(parcel, vmsAvailableLayers.describeContents());
-        parcel.setDataPosition(0);
-        VmsAvailableLayers createdFromParcel = VmsAvailableLayers.CREATOR.createFromParcel(parcel);
-        assertEquals(vmsAvailableLayers, createdFromParcel);
-    }
-
-    public void testNoAvailableLayerEquality() throws Exception {
-        VmsAvailableLayers original =
-                new VmsAvailableLayers(
-                        new HashSet<>(Arrays.asList()),
-                        SEQUENCE_NUMBER);
-
-        VmsAvailableLayers similar =
-                new VmsAvailableLayers(
-                        new HashSet<>(Arrays.asList()),
-                        SEQUENCE_NUMBER);
-
-        assertEquals(original.getAssociatedLayers(), similar.getAssociatedLayers());
-        assertEquals(original.getSequence(), similar.getSequence());
-        assertEquals(original, similar);
-    }
-
-    public void testMultipleAvailableLayerEquality() throws Exception {
-        VmsAvailableLayers original =
-                new VmsAvailableLayers(
-                        new HashSet<>(Arrays.asList(
-                                VMS_ASSOCIATED_LAYER,
-                                ANOTHER_VMS_ASSOCIATED_LAYER)),
-                        SEQUENCE_NUMBER);
-
-        VmsAvailableLayers similar =
-                new VmsAvailableLayers(
-                        new HashSet<>(Arrays.asList(
-                                VMS_ASSOCIATED_LAYER,
-                                ANOTHER_VMS_ASSOCIATED_LAYER)),
-                        SEQUENCE_NUMBER);
-
-        assertEquals(original.getAssociatedLayers(), similar.getAssociatedLayers());
-        assertEquals(original.getSequence(), similar.getSequence());
-        assertEquals(original, similar);
-    }
-
-    public void testVerifyNonEqualOnAssociatedLayer() throws Exception {
-        VmsAvailableLayers original =
-                new VmsAvailableLayers(
-                        new HashSet<>(Arrays.asList(VMS_ASSOCIATED_LAYER)),
-                        SEQUENCE_NUMBER);
-
-        VmsAvailableLayers similar =
-                new VmsAvailableLayers(
-                        new HashSet<>(Arrays.asList(ANOTHER_VMS_ASSOCIATED_LAYER)),
-                        SEQUENCE_NUMBER);
-
-        assertNotEquals(original, similar);
-    }
-
-    public void testVerifyNonEqualOnSequence() throws Exception {
-        VmsAvailableLayers original =
-                new VmsAvailableLayers(
-                        new HashSet<>(Arrays.asList(VMS_ASSOCIATED_LAYER)),
-                        SEQUENCE_NUMBER);
-
-        VmsAvailableLayers similar =
-                new VmsAvailableLayers(
-                        new HashSet<>(Arrays.asList(VMS_ASSOCIATED_LAYER)),
-                        DIFFERENT_SEQUENCE_NUMBER);
-
-        assertNotEquals(original, similar);
-    }
-}
\ No newline at end of file
diff --git a/tests/carservice_unit_test/src/com/android/car/VmsLayerDependencyTest.java b/tests/carservice_unit_test/src/com/android/car/VmsLayerDependencyTest.java
deleted file mode 100644
index 4c659cd..0000000
--- a/tests/carservice_unit_test/src/com/android/car/VmsLayerDependencyTest.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import static org.junit.Assert.assertNotEquals;
-
-import android.car.vms.VmsLayer;
-import android.car.vms.VmsLayerDependency;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import android.os.Parcel;
-
-import java.util.Arrays;
-import java.util.HashSet;
-
-
-/*
- * A class to test the VmsLayerDependency parcelability.
- */
-@SmallTest
-public class VmsLayerDependencyTest extends AndroidTestCase {
-    private static final int LAYER_ID = 112;
-    private static final int LAYER_VERSION = 134;
-    private static final int LAYER_SUBTYPE = 156;
-
-    private static final int DEPENDENT_LAYER_ID = 212;
-    private static final int DEPENDENT_LAYER_VERSION = 234;
-    private static final int DEPENDENT_LAYER_SUBTYPE = 256;
-
-    private static final int DIFFERENT_LAYER_ID = 99;
-
-    private static final VmsLayer VMS_LAYER = new VmsLayer(
-            LAYER_ID,
-            LAYER_SUBTYPE,
-            LAYER_VERSION);
-
-    private static final VmsLayer ANOTHER_VMS_LAYER = new VmsLayer(
-            DIFFERENT_LAYER_ID,
-            LAYER_SUBTYPE,
-            LAYER_VERSION);
-
-    private static final VmsLayer DEPENDENT_VMS_LAYER = new VmsLayer(
-            DEPENDENT_LAYER_ID,
-            DEPENDENT_LAYER_SUBTYPE,
-            DEPENDENT_LAYER_VERSION);
-
-    private static final VmsLayer ANOTHER_DEPENDENT_VMS_LAYER = new VmsLayer(
-            DIFFERENT_LAYER_ID,
-            DEPENDENT_LAYER_SUBTYPE,
-            DEPENDENT_LAYER_VERSION);
-
-    public void testNoDependendtLayerParcel() throws Exception {
-        VmsLayerDependency vmsLayerDependency =
-                new VmsLayerDependency(
-                        VMS_LAYER,
-                        new HashSet<>(Arrays.asList()));
-
-        Parcel parcel = Parcel.obtain();
-        vmsLayerDependency.writeToParcel(parcel, vmsLayerDependency.describeContents());
-        parcel.setDataPosition(0);
-        VmsLayerDependency createdFromParcel = VmsLayerDependency.CREATOR.createFromParcel(parcel);
-        assertEquals(vmsLayerDependency, createdFromParcel);
-    }
-
-    public void testMultipleDependendtLayerParcel() throws Exception {
-        VmsLayerDependency vmsLayerDependency =
-                new VmsLayerDependency(
-                        VMS_LAYER,
-                        new HashSet<>(Arrays.asList(DEPENDENT_VMS_LAYER, ANOTHER_DEPENDENT_VMS_LAYER)));
-
-        Parcel parcel = Parcel.obtain();
-        vmsLayerDependency.writeToParcel(parcel, vmsLayerDependency.describeContents());
-        parcel.setDataPosition(0);
-        VmsLayerDependency createdFromParcel = VmsLayerDependency.CREATOR.createFromParcel(parcel);
-        assertEquals(vmsLayerDependency, createdFromParcel);
-    }
-
-    public void testNoDependendtLayerEquality() throws Exception {
-        VmsLayerDependency original =
-                new VmsLayerDependency(
-                        VMS_LAYER,
-                        new HashSet<>(Arrays.asList()));
-
-        VmsLayerDependency similar =
-                new VmsLayerDependency(VMS_LAYER);
-
-        assertEquals(original.getLayer(), similar.getLayer());
-        assertEquals(original.getDependencies(), similar.getDependencies());
-        assertEquals(original, similar);
-    }
-
-    public void testMultipleDependendtLayerEquality() throws Exception {
-        VmsLayerDependency original =
-                new VmsLayerDependency(
-                        VMS_LAYER,
-                        new HashSet<>(Arrays.asList(DEPENDENT_VMS_LAYER, ANOTHER_DEPENDENT_VMS_LAYER)));
-
-        VmsLayerDependency similar =
-                new VmsLayerDependency(
-                        VMS_LAYER,
-                        new HashSet<>(Arrays.asList(DEPENDENT_VMS_LAYER, ANOTHER_DEPENDENT_VMS_LAYER)));
-        assertEquals(original.getLayer(), similar.getLayer());
-        assertEquals(original.getDependencies(), similar.getDependencies());
-        assertEquals(original, similar);
-    }
-
-    public void testVerifyNonEqualOnLayer() throws Exception {
-        VmsLayerDependency original =
-                new VmsLayerDependency(
-                        VMS_LAYER,
-                        new HashSet<>(Arrays.asList(DEPENDENT_VMS_LAYER)));
-
-        VmsLayerDependency similar =
-                new VmsLayerDependency(
-                        ANOTHER_DEPENDENT_VMS_LAYER,
-                        new HashSet<>(Arrays.asList(DEPENDENT_VMS_LAYER)));
-
-        assertNotEquals(original, similar);
-    }
-
-    public void testVerifyNonEqualOnDependentLayer() throws Exception {
-        VmsLayerDependency original =
-                new VmsLayerDependency(
-                        VMS_LAYER,
-                        new HashSet<>(Arrays.asList(DEPENDENT_VMS_LAYER)));
-
-        VmsLayerDependency similar =
-                new VmsLayerDependency(
-                        VMS_LAYER,
-                        new HashSet<>(Arrays.asList(ANOTHER_DEPENDENT_VMS_LAYER)));
-
-        assertNotEquals(original, similar);
-    }
-}
diff --git a/tests/carservice_unit_test/src/com/android/car/VmsLayerTest.java b/tests/carservice_unit_test/src/com/android/car/VmsLayerTest.java
deleted file mode 100644
index 56fb129..0000000
--- a/tests/carservice_unit_test/src/com/android/car/VmsLayerTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import static org.junit.Assert.assertNotEquals;
-
-import android.car.vms.VmsLayer;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import android.os.Parcel;
-
-import java.util.Arrays;
-import java.util.HashSet;
-
-/*
- * A class to test the VmsLayer parcelability.
- */
-@SmallTest
-public class VmsLayerTest extends AndroidTestCase {
-    private static final int LAYER_ID = 12;
-    private static final int LAYER_VERSION = 34;
-    private static final int LAYER_SUBTYPE = 56;
-
-    private static final int DIFFERENT_LAYER_ID = 99;
-
-    public void testLayerParcel() throws Exception {
-        VmsLayer vmsLayer =
-                new VmsLayer(
-                        LAYER_ID,
-                        LAYER_SUBTYPE,
-                        LAYER_VERSION);
-
-        Parcel parcel = Parcel.obtain();
-        vmsLayer.writeToParcel(parcel, vmsLayer.describeContents());
-        parcel.setDataPosition(0);
-        VmsLayer createdFromParcel = VmsLayer.CREATOR.createFromParcel(parcel);
-        assertEquals(vmsLayer, createdFromParcel);
-    }
-
-    public void testLayerEquality() throws Exception {
-        VmsLayer original =
-                new VmsLayer(
-                        LAYER_ID,
-                        LAYER_SUBTYPE,
-                        LAYER_VERSION);
-
-        VmsLayer similar =
-                new VmsLayer(
-                        LAYER_ID,
-                        LAYER_SUBTYPE,
-                        LAYER_VERSION);
-
-        assertEquals(original.getType(), similar.getType());
-        assertEquals(original.getSubtype(), similar.getSubtype());
-        assertEquals(original.getVersion(), similar.getVersion());
-        assertEquals(original, similar);
-    }
-
-    public void testVerifyNonEqual() throws Exception {
-        VmsLayer original =
-                new VmsLayer(
-                        LAYER_ID,
-                        LAYER_SUBTYPE,
-                        LAYER_VERSION);
-
-        VmsLayer similar =
-                new VmsLayer(
-                        DIFFERENT_LAYER_ID,
-                        LAYER_SUBTYPE,
-                        LAYER_VERSION);
-
-        assertNotEquals(original, similar);
-    }
-}
\ No newline at end of file
diff --git a/tests/carservice_unit_test/src/com/android/car/VmsLayersAvailabilityTest.java b/tests/carservice_unit_test/src/com/android/car/VmsLayersAvailabilityTest.java
deleted file mode 100644
index ebf50d8..0000000
--- a/tests/carservice_unit_test/src/com/android/car/VmsLayersAvailabilityTest.java
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import android.car.vms.VmsAssociatedLayer;
-import android.car.vms.VmsLayer;
-import android.car.vms.VmsLayerDependency;
-import android.car.vms.VmsLayersOffering;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-@SmallTest
-public class VmsLayersAvailabilityTest extends AndroidTestCase {
-
-    private static final VmsLayer LAYER_X = new VmsLayer(1, 1, 2);
-    private static final VmsLayer LAYER_Y = new VmsLayer(3, 2, 4);
-    private static final VmsLayer LAYER_Z = new VmsLayer(5, 3, 6);
-
-    private static final int PUBLISHER_ID_1 = 19;
-    private static final int PUBLISHER_ID_2 = 28;
-
-    private static final Set<Integer> PUBLISHERS_1 = new HashSet<>(Arrays.asList(PUBLISHER_ID_1));
-    private static final Set<Integer> PUBLISHERS_2 = new HashSet<>(Arrays.asList(PUBLISHER_ID_2));
-    private static final Set<Integer> PUBLISHERS_1_AND_2 =
-            new HashSet<>(Arrays.asList(PUBLISHER_ID_1, PUBLISHER_ID_2));
-
-    private static final VmsLayerDependency X_DEPENDS_ON_Y =
-            new VmsLayerDependency(LAYER_X, new HashSet<VmsLayer>(Arrays.asList(LAYER_Y)));
-
-    private static final VmsLayerDependency X_DEPENDS_ON_Z =
-            new VmsLayerDependency(LAYER_X, new HashSet<VmsLayer>(Arrays.asList(LAYER_Z)));
-
-    private static final VmsLayerDependency Y_DEPENDS_ON_Z =
-            new VmsLayerDependency(LAYER_Y, new HashSet<VmsLayer>(Arrays.asList(LAYER_Z)));
-
-    private static final VmsLayerDependency Y_DEPENDS_ON_X =
-            new VmsLayerDependency(LAYER_Y, new HashSet<VmsLayer>(Arrays.asList(LAYER_X)));
-
-    private static final VmsLayerDependency Z_DEPENDS_ON_X =
-            new VmsLayerDependency(LAYER_Z, new HashSet<VmsLayer>(Arrays.asList(LAYER_X)));
-
-    private static final VmsLayerDependency Z_DEPENDS_ON_NOTHING =
-            new VmsLayerDependency(LAYER_Z);
-
-    private static final VmsLayerDependency X_DEPENDS_ON_SELF =
-            new VmsLayerDependency(LAYER_X, new HashSet<VmsLayer>(Arrays.asList(LAYER_X)));
-
-    private Set<VmsLayersOffering> mOfferings;
-    private VmsLayersAvailability mLayersAvailability;
-
-    @Override
-    protected void setUp() throws Exception {
-        mLayersAvailability = new VmsLayersAvailability();
-        mOfferings = new HashSet<>();
-        super.setUp();
-    }
-
-    public void testNoOffering() {
-        assertTrue(mLayersAvailability.getAvailableLayers().getAssociatedLayers().isEmpty());
-    }
-
-    public void testEmptyOffering() {
-        mLayersAvailability.setPublishersOffering(Collections.EMPTY_LIST);
-        assertTrue(mLayersAvailability.getAvailableLayers().getAssociatedLayers().isEmpty());
-    }
-
-    public void testSingleLayerNoDeps() throws Exception {
-        Set<VmsAssociatedLayer> expectedAvailableAssociatedLayers = new HashSet<>();
-        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_X, PUBLISHERS_2));
-
-        VmsLayersOffering offering =
-                new VmsLayersOffering(new HashSet<>(Arrays.asList(new VmsLayerDependency(LAYER_X))),
-                        PUBLISHER_ID_2);
-
-        mOfferings.add(offering);
-        mLayersAvailability.setPublishersOffering(mOfferings);
-
-        assertEquals(expectedAvailableAssociatedLayers,
-                mLayersAvailability.getAvailableLayers().getAssociatedLayers());
-    }
-
-    public void testChainOfDependenciesSatisfied() throws Exception {
-        Set<VmsAssociatedLayer> expectedAvailableAssociatedLayers = new HashSet<>();
-        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_X, PUBLISHERS_1));
-        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_Y, PUBLISHERS_1));
-        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_Z, PUBLISHERS_1));
-
-        VmsLayersOffering offering =
-                new VmsLayersOffering(
-                        new HashSet<>(Arrays.asList(
-                                X_DEPENDS_ON_Y, Y_DEPENDS_ON_Z, Z_DEPENDS_ON_NOTHING)),
-                        PUBLISHER_ID_1);
-
-        mOfferings.add(offering);
-        mLayersAvailability.setPublishersOffering(mOfferings);
-
-        assertEquals(expectedAvailableAssociatedLayers,
-                new HashSet<VmsAssociatedLayer>(
-                        mLayersAvailability.getAvailableLayers().getAssociatedLayers()));
-    }
-
-    public void testChainOfDependenciesSatisfiedTwoOfferings() throws Exception {
-        Set<VmsAssociatedLayer> expectedAvailableAssociatedLayers = new HashSet<>();
-        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_X, PUBLISHERS_1));
-        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_Y, PUBLISHERS_1));
-        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_Z, PUBLISHERS_1));
-
-        VmsLayersOffering offering1 =
-                new VmsLayersOffering(
-                        new HashSet<>(Arrays.asList(X_DEPENDS_ON_Y, Y_DEPENDS_ON_Z)),
-                        PUBLISHER_ID_1);
-
-        VmsLayersOffering offering2 =
-                new VmsLayersOffering(new HashSet<>(Arrays.asList(Z_DEPENDS_ON_NOTHING)),
-                        PUBLISHER_ID_1);
-
-        mOfferings.add(offering1);
-        mOfferings.add(offering2);
-        mLayersAvailability.setPublishersOffering(mOfferings);
-
-        assertEquals(expectedAvailableAssociatedLayers,
-                new HashSet<VmsAssociatedLayer>(
-                        mLayersAvailability.getAvailableLayers().getAssociatedLayers()));
-    }
-
-    public void testChainOfDependencieNotSatisfied() throws Exception {
-        Set<VmsAssociatedLayer> expectedAvailableAssociatedLayers = new HashSet<>();
-        VmsLayersOffering offering =
-                new VmsLayersOffering(new HashSet<>(Arrays.asList(X_DEPENDS_ON_Y, Y_DEPENDS_ON_Z)),
-                        PUBLISHER_ID_1);
-
-        mOfferings.add(offering);
-        mLayersAvailability.setPublishersOffering(mOfferings);
-
-        assertEquals(expectedAvailableAssociatedLayers,
-                new HashSet<VmsAssociatedLayer>(
-                        mLayersAvailability.getAvailableLayers().getAssociatedLayers()));
-    }
-
-    public void testOneOfMultipleDependencySatisfied() throws Exception {
-        Set<VmsAssociatedLayer> expectedAvailableAssociatedLayers = new HashSet<>();
-        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_X, PUBLISHERS_1));
-        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_Z, PUBLISHERS_1));
-
-
-        VmsLayersOffering offering =
-                new VmsLayersOffering(
-                        new HashSet<>(Arrays.asList(
-                                X_DEPENDS_ON_Y, X_DEPENDS_ON_Z, Z_DEPENDS_ON_NOTHING)),
-                        PUBLISHER_ID_1);
-
-        mOfferings.add(offering);
-        mLayersAvailability.setPublishersOffering(mOfferings);
-
-        assertEquals(expectedAvailableAssociatedLayers,
-                new HashSet<VmsAssociatedLayer>(
-                        mLayersAvailability.getAvailableLayers().getAssociatedLayers()));
-    }
-
-    public void testCyclicDependency() throws Exception {
-        Set<VmsAssociatedLayer> expectedAvailableAssociatedLayers = new HashSet<>();
-
-        VmsLayersOffering offering =
-                new VmsLayersOffering(
-                        new HashSet<>(
-                                Arrays.asList(X_DEPENDS_ON_Y, Y_DEPENDS_ON_Z, Z_DEPENDS_ON_X)),
-                        PUBLISHER_ID_1);
-
-        mOfferings.add(offering);
-        mLayersAvailability.setPublishersOffering(mOfferings);
-
-        assertEquals(expectedAvailableAssociatedLayers,
-                new HashSet<VmsAssociatedLayer>(
-                        mLayersAvailability.getAvailableLayers().getAssociatedLayers()));
-    }
-
-    public void testAlmostCyclicDependency() throws Exception {
-        Set<VmsAssociatedLayer> expectedAvailableAssociatedLayers = new HashSet<>();
-        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_Z, PUBLISHERS_1_AND_2));
-        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_X, PUBLISHERS_1));
-        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_Y, PUBLISHERS_2));
-
-        VmsLayersOffering offering1 =
-                new VmsLayersOffering(
-                        new HashSet<>(Arrays.asList(X_DEPENDS_ON_Y, Z_DEPENDS_ON_NOTHING)),
-                        PUBLISHER_ID_1);
-
-        VmsLayersOffering offering2 =
-                new VmsLayersOffering(new HashSet<>(Arrays.asList(Y_DEPENDS_ON_Z, Z_DEPENDS_ON_X)),
-                        PUBLISHER_ID_2);
-
-        mOfferings.add(offering1);
-        mOfferings.add(offering2);
-        mLayersAvailability.setPublishersOffering(mOfferings);
-
-        assertEquals(expectedAvailableAssociatedLayers,
-                mLayersAvailability.getAvailableLayers().getAssociatedLayers());
-    }
-
-    public void testCyclicDependencyAndLayerWithoutDependency() throws Exception {
-        Set<VmsAssociatedLayer> expectedAvailableAssociatedLayers = new HashSet<>();
-        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_Z, PUBLISHERS_1));
-
-        VmsLayersOffering offering1 =
-                new VmsLayersOffering(
-                        new HashSet<>(
-                                Arrays.asList(X_DEPENDS_ON_Y, Z_DEPENDS_ON_NOTHING)),
-                        PUBLISHER_ID_1);
-
-        VmsLayersOffering offering2 =
-                new VmsLayersOffering(new HashSet<>(Arrays.asList(Y_DEPENDS_ON_X)), PUBLISHER_ID_2);
-
-        mOfferings.add(offering1);
-        mOfferings.add(offering2);
-        mLayersAvailability.setPublishersOffering(mOfferings);
-
-        assertEquals(expectedAvailableAssociatedLayers,
-                new HashSet<VmsAssociatedLayer>(
-                        mLayersAvailability.getAvailableLayers().getAssociatedLayers()));
-    }
-
-    public void testSelfDependency() throws Exception {
-        Set<VmsAssociatedLayer> expectedAvailableAssociatedLayers = new HashSet<>();
-
-        VmsLayersOffering offering =
-                new VmsLayersOffering(new HashSet<>(Arrays.asList(X_DEPENDS_ON_SELF)),
-                        PUBLISHER_ID_1);
-
-        mOfferings.add(offering);
-        mLayersAvailability.setPublishersOffering(mOfferings);
-
-        assertEquals(expectedAvailableAssociatedLayers,
-                new HashSet<VmsAssociatedLayer>(
-                        mLayersAvailability.getAvailableLayers().getAssociatedLayers()));
-    }
-}
\ No newline at end of file
diff --git a/tests/carservice_unit_test/src/com/android/car/VmsLayersOfferingTest.java b/tests/carservice_unit_test/src/com/android/car/VmsLayersOfferingTest.java
deleted file mode 100644
index c2111a9..0000000
--- a/tests/carservice_unit_test/src/com/android/car/VmsLayersOfferingTest.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import static org.junit.Assert.assertNotEquals;
-
-import android.car.vms.VmsLayer;
-import android.car.vms.VmsLayerDependency;
-import android.car.vms.VmsLayersOffering;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.os.Parcel;
-
-import java.util.Arrays;
-import java.util.HashSet;
-
-import android.util.Log;
-
-/*
- * A class to test the VmsLayersOffering parcelability.
- */
-@SmallTest
-public class VmsLayersOfferingTest extends AndroidTestCase {
-    private static final int PUBLISHER_ID = 1;
-
-    private static final int LAYER_ID = 112;
-    private static final int LAYER_VERSION = 134;
-    private static final int LAYER_SUBTYPE = 156;
-
-    private static final int DEPENDENT_LAYER_ID = 212;
-    private static final int DEPENDENT_LAYER_VERSION = 234;
-    private static final int DEPENDENT_LAYER_SUBTYPE = 256;
-
-    private static final int DIFFERENT_LAYER_ID = 99;
-    private static final int DIFFERENT_PUBLISHER_ID = 2;
-
-    private static final VmsLayer VMS_LAYER = new VmsLayer(
-            LAYER_ID,
-            LAYER_SUBTYPE,
-            LAYER_VERSION);
-
-    private static final VmsLayer DEPENDENT_VMS_LAYER = new VmsLayer(
-            DEPENDENT_LAYER_ID,
-            DEPENDENT_LAYER_SUBTYPE,
-            DEPENDENT_LAYER_VERSION);
-
-    private static final VmsLayer ANOTHER_DEPENDENT_VMS_LAYER = new VmsLayer(
-            DIFFERENT_LAYER_ID,
-            DEPENDENT_LAYER_SUBTYPE,
-            DEPENDENT_LAYER_VERSION);
-
-    private static final VmsLayerDependency VMS_LAYER_DEPENDENCY =
-            new VmsLayerDependency(
-                    VMS_LAYER,
-                    new HashSet<>(Arrays.asList(DEPENDENT_VMS_LAYER)));
-
-    private static final VmsLayerDependency ANOTHER_VMS_LAYER_DEPENDENCY =
-            new VmsLayerDependency(
-                    VMS_LAYER,
-                    new HashSet<>(Arrays.asList(ANOTHER_DEPENDENT_VMS_LAYER)));
-
-    public void testNoOfferingParcel() throws Exception {
-        VmsLayersOffering vmsLayersOffering =
-                new VmsLayersOffering(new HashSet<>(Arrays.asList()), PUBLISHER_ID);
-
-        Parcel parcel = Parcel.obtain();
-        vmsLayersOffering.writeToParcel(parcel, vmsLayersOffering.describeContents());
-        parcel.setDataPosition(0);
-        VmsLayersOffering createdFromParcel = VmsLayersOffering.CREATOR.createFromParcel(parcel);
-        assertEquals(vmsLayersOffering, createdFromParcel);
-    }
-
-    public void testMultipleOfferingParcel() throws Exception {
-        VmsLayersOffering vmsLayersOffering =
-                new VmsLayersOffering(
-                        new HashSet<>(Arrays.asList(
-                                VMS_LAYER_DEPENDENCY,
-                                ANOTHER_VMS_LAYER_DEPENDENCY)),
-                        PUBLISHER_ID);
-
-        Parcel parcel = Parcel.obtain();
-        vmsLayersOffering.writeToParcel(parcel, vmsLayersOffering.describeContents());
-        parcel.setDataPosition(0);
-        VmsLayersOffering createdFromParcel = VmsLayersOffering.CREATOR.createFromParcel(parcel);
-
-        assertEquals(vmsLayersOffering, createdFromParcel);
-    }
-
-    public void testNoOfferingEquality() throws Exception {
-        VmsLayersOffering original =
-                new VmsLayersOffering(
-                        new HashSet<>(Arrays.asList()), PUBLISHER_ID);
-
-        VmsLayersOffering similar =
-                new VmsLayersOffering(
-                        new HashSet<>(Arrays.asList()), PUBLISHER_ID);
-
-        assertEquals(original.getDependencies(), similar.getDependencies());
-        assertEquals(original.getPublisherId(), similar.getPublisherId());
-        assertEquals(original, similar);
-    }
-
-    public void testMultipleOfferingEquality() throws Exception {
-        VmsLayersOffering original =
-                new VmsLayersOffering(
-                        new HashSet<>(Arrays.asList(VMS_LAYER_DEPENDENCY, ANOTHER_VMS_LAYER_DEPENDENCY)), PUBLISHER_ID);
-
-        VmsLayersOffering similar =
-                new VmsLayersOffering(
-                        new HashSet<>(Arrays.asList(VMS_LAYER_DEPENDENCY, ANOTHER_VMS_LAYER_DEPENDENCY)), PUBLISHER_ID);
-
-        assertEquals(original.getDependencies(), similar.getDependencies());
-        assertEquals(original.getPublisherId(), similar.getPublisherId());
-        assertEquals(original, similar);
-    }
-
-    public void testVerifyNonEqualOnPublisherId() throws Exception {
-        VmsLayersOffering original =
-                new VmsLayersOffering(
-                        new HashSet<>(Arrays.asList(VMS_LAYER_DEPENDENCY)), PUBLISHER_ID);
-
-        VmsLayersOffering similar =
-                new VmsLayersOffering(
-                        new HashSet<>(Arrays.asList(VMS_LAYER_DEPENDENCY)), DIFFERENT_PUBLISHER_ID);
-
-        assertNotEquals(original, similar);
-    }
-
-    public void testVerifyNonEqualOnDependency() throws Exception {
-        VmsLayersOffering original =
-                new VmsLayersOffering(
-                        new HashSet<>(Arrays.asList(VMS_LAYER_DEPENDENCY)), PUBLISHER_ID);
-
-        VmsLayersOffering similar =
-                new VmsLayersOffering(
-                        new HashSet<>(Arrays.asList(ANOTHER_VMS_LAYER_DEPENDENCY)), PUBLISHER_ID);
-
-        assertNotEquals(original, similar);
-    }
-}
diff --git a/tests/carservice_unit_test/src/com/android/car/VmsPublisherServiceTest.java b/tests/carservice_unit_test/src/com/android/car/VmsPublisherServiceTest.java
deleted file mode 100644
index 2bd09df..0000000
--- a/tests/carservice_unit_test/src/com/android/car/VmsPublisherServiceTest.java
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.car.Car;
-import android.car.vms.IVmsPublisherClient;
-import android.car.vms.IVmsPublisherService;
-import android.car.vms.IVmsSubscriberClient;
-import android.car.vms.VmsLayer;
-import android.car.vms.VmsLayersOffering;
-import android.car.vms.VmsSubscriptionState;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.RemoteException;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.car.stats.CarStatsService;
-import com.android.car.stats.VmsClientLogger;
-import com.android.car.vms.VmsBrokerService;
-import com.android.car.vms.VmsClientManager;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-
-@SmallTest
-public class VmsPublisherServiceTest {
-    private static final VmsSubscriptionState SUBSCRIPTION_STATE = new VmsSubscriptionState(12345,
-            Collections.emptySet(), Collections.emptySet());
-    private static final VmsLayersOffering OFFERING = new VmsLayersOffering(Collections.emptySet(),
-            54321);
-    private static final VmsLayer LAYER = new VmsLayer(1, 2, 3);
-
-    private static final int PUBLISHER_ID = 54321;
-    private static final byte[] PAYLOAD = new byte[]{1, 2, 3, 4};
-
-    private static final int PUBLISHER_UID = 10100;
-    private static final int SUBSCRIBER_UID = 10101;
-    private static final int SUBSCRIBER_UID2 = 10102;
-    private static final int NO_SUBSCRIBERS_UID = -1;
-
-    @Rule
-    public MockitoRule mMockitoRule = MockitoJUnit.rule();
-    @Mock
-    private Context mContext;
-    @Mock
-    private CarStatsService mStatsService;
-    @Mock
-    private VmsBrokerService mBrokerService;
-    @Captor
-    private ArgumentCaptor<VmsBrokerService.PublisherListener> mProxyCaptor;
-    @Mock
-    private VmsClientManager mClientManager;
-
-    @Mock
-    private VmsClientLogger mPublisherLog;
-    @Mock
-    private VmsClientLogger mSubscriberLog;
-    @Mock
-    private VmsClientLogger mSubscriberLog2;
-    @Mock
-    private VmsClientLogger mNoSubscribersLog;
-
-    @Mock
-    private IVmsSubscriberClient mSubscriberClient;
-    @Mock
-    private IVmsSubscriberClient mSubscriberClient2;
-
-    private VmsPublisherService mPublisherService;
-    private MockPublisherClient mPublisherClient;
-    private MockPublisherClient mPublisherClient2;
-
-    @Before
-    public void setUp() {
-        mPublisherService = new VmsPublisherService(mContext, mStatsService, mBrokerService,
-                mClientManager, () -> PUBLISHER_UID);
-        verify(mClientManager).setPublisherService(mPublisherService);
-
-        when(mClientManager.getSubscriberUid(mSubscriberClient)).thenReturn(SUBSCRIBER_UID);
-        when(mClientManager.getSubscriberUid(mSubscriberClient2)).thenReturn(SUBSCRIBER_UID2);
-
-        when(mStatsService.getVmsClientLogger(PUBLISHER_UID)).thenReturn(mPublisherLog);
-        when(mStatsService.getVmsClientLogger(SUBSCRIBER_UID)).thenReturn(mSubscriberLog);
-        when(mStatsService.getVmsClientLogger(SUBSCRIBER_UID2)).thenReturn(mSubscriberLog2);
-        when(mStatsService.getVmsClientLogger(NO_SUBSCRIBERS_UID)).thenReturn(mNoSubscribersLog);
-
-        mPublisherClient = new MockPublisherClient();
-        mPublisherClient2 = new MockPublisherClient();
-        when(mBrokerService.getSubscribersForLayerFromPublisher(LAYER, PUBLISHER_ID))
-                .thenReturn(new HashSet<>(Arrays.asList(mSubscriberClient, mSubscriberClient2)));
-    }
-
-    @After
-    public void tearDown() {
-        verifyNoMoreInteractions(mPublisherLog, mSubscriberLog, mSubscriberLog2, mNoSubscribersLog);
-    }
-
-    @Test
-    public void testInit() {
-        mPublisherService.init();
-    }
-
-    @Test
-    public void testOnClientConnected() {
-        mPublisherService.onClientConnected("SomeClient", mPublisherClient);
-        mPublisherService.onClientConnected("SomeOtherClient", mPublisherClient2);
-        verify(mBrokerService, times(2)).addPublisherListener(mProxyCaptor.capture());
-
-        assertNotNull(mPublisherClient.mPublisherService);
-        assertSame(mPublisherClient.mPublisherService, mProxyCaptor.getAllValues().get(0));
-
-        assertNotNull(mPublisherClient2.mPublisherService);
-        assertSame(mPublisherClient2.mPublisherService, mProxyCaptor.getAllValues().get(1));
-        assertNotSame(mPublisherClient2.mPublisherService, mPublisherClient.mPublisherService);
-    }
-
-    @Test
-    public void testOnClientDisconnected() {
-        mPublisherService.onClientConnected("SomeClient", mPublisherClient);
-        mPublisherService.onClientConnected("SomeOtherClient", mPublisherClient2);
-        verify(mBrokerService, times(2)).addPublisherListener(mProxyCaptor.capture());
-
-        reset(mClientManager, mBrokerService);
-        mPublisherService.onClientDisconnected("SomeClient");
-
-        verify(mBrokerService).removeDeadPublisher(mPublisherClient.mToken);
-        verify(mBrokerService).removePublisherListener(mProxyCaptor.getAllValues().get(0));
-        verifyNoMoreInteractions(mBrokerService);
-    }
-
-    @Test
-    public void testSetLayersOffering() throws Exception {
-        mPublisherService.onClientConnected("SomeClient", mPublisherClient);
-
-        mPublisherClient.mPublisherService.setLayersOffering(mPublisherClient.mToken, OFFERING);
-        verify(mBrokerService).setPublisherLayersOffering(mPublisherClient.mToken, OFFERING);
-    }
-
-    @Test(expected = SecurityException.class)
-    public void testSetLayersOffering_InvalidToken() throws Exception {
-        mPublisherService.onClientConnected("SomeClient", mPublisherClient);
-
-        mPublisherClient.mPublisherService.setLayersOffering(new Binder(), OFFERING);
-    }
-
-    @Test(expected = SecurityException.class)
-    public void testSetLayersOffering_Disconnected() throws Exception {
-        mPublisherService.onClientConnected("SomeClient", mPublisherClient);
-        mPublisherService.onClientDisconnected("SomeClient");
-
-        mPublisherClient.mPublisherService.setLayersOffering(mPublisherClient.mToken, OFFERING);
-    }
-
-    @Test(expected = SecurityException.class)
-    public void testSetLayersOffering_PermissionDenied() throws Exception {
-        mPublisherService.onClientConnected("SomeClient", mPublisherClient);
-        when(mContext.checkCallingOrSelfPermission(Car.PERMISSION_VMS_PUBLISHER)).thenReturn(
-                PackageManager.PERMISSION_DENIED);
-
-        mPublisherClient.mPublisherService.setLayersOffering(mPublisherClient.mToken, OFFERING);
-    }
-
-    @Test
-    public void testPublish() throws Exception {
-        mPublisherService.onClientConnected("SomeClient", mPublisherClient);
-
-        mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID,
-                PAYLOAD);
-        verify(mSubscriberClient).onVmsMessageReceived(LAYER, PAYLOAD);
-        verify(mSubscriberClient2).onVmsMessageReceived(LAYER, PAYLOAD);
-
-        verify(mPublisherLog).logPacketSent(LAYER, PAYLOAD.length);
-        verify(mSubscriberLog).logPacketReceived(LAYER, PAYLOAD.length);
-        verify(mSubscriberLog2).logPacketReceived(LAYER, PAYLOAD.length);
-    }
-
-    @Test
-    public void testPublishNullLayerAndNullPayload() throws Exception {
-        mPublisherService.onClientConnected("SomeClient", mPublisherClient);
-
-        // We just want to ensure that no exceptions are thrown here.
-        mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, null, PUBLISHER_ID,
-                null);
-    }
-
-    @Test
-    public void testPublish_NoSubscribers() throws Exception {
-        mPublisherService.onClientConnected("SomeClient", mPublisherClient);
-        when(mBrokerService.getSubscribersForLayerFromPublisher(LAYER, PUBLISHER_ID))
-                .thenReturn(Collections.emptySet());
-
-        mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID,
-                PAYLOAD);
-
-        verify(mPublisherLog).logPacketSent(LAYER, PAYLOAD.length);
-        verify(mNoSubscribersLog).logPacketDropped(LAYER, PAYLOAD.length);
-    }
-
-    @Test
-    public void testPublish_ClientError() throws Exception {
-        mPublisherService.onClientConnected("SomeClient", mPublisherClient);
-        doThrow(new RemoteException()).when(mSubscriberClient).onVmsMessageReceived(LAYER, PAYLOAD);
-
-        mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID,
-                PAYLOAD);
-        verify(mSubscriberClient).onVmsMessageReceived(LAYER, PAYLOAD);
-        verify(mSubscriberClient2).onVmsMessageReceived(LAYER, PAYLOAD);
-
-        verify(mPublisherLog).logPacketSent(LAYER, PAYLOAD.length);
-        verify(mSubscriberLog).logPacketDropped(LAYER, PAYLOAD.length);
-        verify(mSubscriberLog2).logPacketReceived(LAYER, PAYLOAD.length);
-    }
-
-    @Test(expected = SecurityException.class)
-    public void testPublish_InvalidToken() throws Exception {
-        mPublisherService.onClientConnected("SomeClient", mPublisherClient);
-
-        mPublisherClient.mPublisherService.publish(new Binder(), LAYER, PUBLISHER_ID, PAYLOAD);
-    }
-
-    @Test(expected = SecurityException.class)
-    public void testPublish_Disconnected() throws Exception {
-        mPublisherService.onClientConnected("SomeClient", mPublisherClient);
-        mPublisherService.onClientDisconnected("SomeClient");
-
-        mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID,
-                PAYLOAD);
-    }
-
-    @Test(expected = SecurityException.class)
-    public void testPublish_PermissionDenied() throws Exception {
-        mPublisherService.onClientConnected("SomeClient", mPublisherClient);
-        when(mContext.checkCallingOrSelfPermission(Car.PERMISSION_VMS_PUBLISHER)).thenReturn(
-                PackageManager.PERMISSION_DENIED);
-
-        mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID,
-                PAYLOAD);
-    }
-
-    @Test
-    public void testGetSubscriptions() throws Exception {
-        mPublisherService.onClientConnected("SomeClient", mPublisherClient);
-        when(mBrokerService.getSubscriptionState()).thenReturn(SUBSCRIPTION_STATE);
-
-        assertEquals(SUBSCRIPTION_STATE, mPublisherClient.mPublisherService.getSubscriptions());
-    }
-
-    @Test(expected = SecurityException.class)
-    public void testGetSubscriptions_Disconnected() throws Exception {
-        mPublisherService.onClientConnected("SomeClient", mPublisherClient);
-        mPublisherService.onClientDisconnected("SomeClient");
-
-        mPublisherClient.mPublisherService.getSubscriptions();
-    }
-
-    @Test(expected = SecurityException.class)
-    public void testGetSubscriptions_PermissionDenied() throws Exception {
-        mPublisherService.onClientConnected("SomeClient", mPublisherClient);
-        when(mContext.checkCallingOrSelfPermission(Car.PERMISSION_VMS_PUBLISHER)).thenReturn(
-                PackageManager.PERMISSION_DENIED);
-
-        mPublisherClient.mPublisherService.getSubscriptions();
-    }
-
-    @Test
-    public void testGetPublisherId() throws Exception {
-        mPublisherService.onClientConnected("SomeClient", mPublisherClient);
-        when(mBrokerService.getPublisherId(PAYLOAD)).thenReturn(PUBLISHER_ID);
-
-        assertEquals(PUBLISHER_ID, mPublisherClient.mPublisherService.getPublisherId(PAYLOAD));
-    }
-
-    @Test(expected = SecurityException.class)
-    public void testGetPublisherId_Disconnected() throws Exception {
-        mPublisherService.onClientConnected("SomeClient", mPublisherClient);
-        mPublisherService.onClientDisconnected("SomeClient");
-
-        mPublisherClient.mPublisherService.getPublisherId(PAYLOAD);
-    }
-
-    @Test(expected = SecurityException.class)
-    public void testGetPublisherId_PermissionDenied() throws Exception {
-        mPublisherService.onClientConnected("SomeClient", mPublisherClient);
-        when(mContext.checkCallingOrSelfPermission(Car.PERMISSION_VMS_PUBLISHER)).thenReturn(
-                PackageManager.PERMISSION_DENIED);
-
-        mPublisherClient.mPublisherService.getPublisherId(PAYLOAD);
-    }
-
-    @Test
-    public void testOnSubscriptionChange() {
-        mPublisherService.onClientConnected("SomeClient", mPublisherClient);
-        mPublisherService.onClientConnected("SomeOtherClient", mPublisherClient2);
-        verify(mBrokerService, times(2)).addPublisherListener(mProxyCaptor.capture());
-
-        mProxyCaptor.getAllValues().get(0).onSubscriptionChange(SUBSCRIPTION_STATE);
-
-        assertEquals(SUBSCRIPTION_STATE, mPublisherClient.mSubscriptionState);
-        assertNull(mPublisherClient2.mSubscriptionState);
-    }
-
-    @Test
-    public void testRelease() {
-        mPublisherService.release();
-    }
-
-    private class MockPublisherClient extends IVmsPublisherClient.Stub {
-        private IBinder mToken;
-        private IVmsPublisherService mPublisherService;
-        private VmsSubscriptionState mSubscriptionState;
-
-        @Override
-        public void setVmsPublisherService(IBinder token, IVmsPublisherService service) {
-            assertNotNull(token);
-            assertNotNull(service);
-            if (mToken != null) {
-                throw new IllegalArgumentException("Publisher service set multiple times");
-            }
-            this.mToken = token;
-            this.mPublisherService = service;
-        }
-
-        @Override
-        public void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState) {
-            assertNotNull(subscriptionState);
-            this.mSubscriptionState = subscriptionState;
-        }
-    }
-}
diff --git a/tests/carservice_unit_test/src/com/android/car/VmsPublishersInfoTest.java b/tests/carservice_unit_test/src/com/android/car/VmsPublishersInfoTest.java
deleted file mode 100644
index 1938a19..0000000
--- a/tests/carservice_unit_test/src/com/android/car/VmsPublishersInfoTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class VmsPublishersInfoTest {
-    public static final byte[] MOCK_INFO_1 = new byte[]{2, 3, 5, 7, 11, 13, 17};
-    public static final byte[] SAME_MOCK_INFO_1 = new byte[]{2, 3, 5, 7, 11, 13, 17};
-    public static final byte[] MOCK_INFO_2 = new byte[]{2, 3, 5, 7, 11, 13, 17, 19};
-
-    private VmsPublishersInfo mVmsPublishersInfo;
-
-    @Before
-    public void setUp() throws Exception {
-        mVmsPublishersInfo = new VmsPublishersInfo();
-    }
-
-    @Test
-    public void testSingleInfo() throws Exception {
-        int id = mVmsPublishersInfo.getIdForInfo(MOCK_INFO_1);
-        assertEquals(1, id);
-        assertArrayEquals(MOCK_INFO_1, mVmsPublishersInfo.getPublisherInfo(id));
-    }
-
-    @Test
-    public void testSingleInfo_NoSuchId() throws Exception {
-        assertEquals(0, mVmsPublishersInfo.getPublisherInfo(12345).length);
-    }
-
-    @Test
-    public void testTwoInfos() throws Exception {
-        int id1 = mVmsPublishersInfo.getIdForInfo(MOCK_INFO_1);
-        int id2 = mVmsPublishersInfo.getIdForInfo(MOCK_INFO_2);
-        assertEquals(1, id1);
-        assertEquals(2, id2);
-        assertArrayEquals(MOCK_INFO_1, mVmsPublishersInfo.getPublisherInfo(id1));
-        assertArrayEquals(MOCK_INFO_2, mVmsPublishersInfo.getPublisherInfo(id2));
-    }
-
-    @Test
-    public void testSingleInfoInsertedTwice() throws Exception {
-        int id = mVmsPublishersInfo.getIdForInfo(MOCK_INFO_1);
-        assertEquals(1, id);
-
-        int sameId = mVmsPublishersInfo.getIdForInfo(SAME_MOCK_INFO_1);
-        assertEquals(sameId, id);
-    }
-}
diff --git a/tests/carservice_unit_test/src/com/android/car/VmsRoutingTest.java b/tests/carservice_unit_test/src/com/android/car/VmsRoutingTest.java
deleted file mode 100644
index 9e516a8..0000000
--- a/tests/carservice_unit_test/src/com/android/car/VmsRoutingTest.java
+++ /dev/null
@@ -1,892 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.car.vms.IVmsSubscriberClient;
-import android.car.vms.VmsAssociatedLayer;
-import android.car.vms.VmsAvailableLayers;
-import android.car.vms.VmsLayer;
-import android.car.vms.VmsSubscriptionState;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-
-@SmallTest
-public class VmsRoutingTest {
-    private static final VmsLayer LAYER_1 = new VmsLayer(1, 1, 2);
-    private static final VmsLayer LAYER_2 = new VmsLayer(1, 3, 3);
-    private static final VmsLayer[] LAYERS = {LAYER_1, LAYER_2};
-    private static final int PUBLISHER_ID_1 = 123;
-    private static final int PUBLISHER_ID_2 = 456;
-    private static final int[] PUBLISHER_IDS = {PUBLISHER_ID_1, PUBLISHER_ID_2};
-
-    private VmsRouting mRouting;
-    private IVmsSubscriberClient mSubscriber;
-    private IVmsSubscriberClient mSubscriberRewrapped;
-    private IVmsSubscriberClient mSubscriber2;
-
-    @Before
-    public void setUp() throws Exception {
-        mRouting = new VmsRouting();
-        mSubscriber = new MockVmsSubscriber();
-        mSubscriberRewrapped = IVmsSubscriberClient.Stub.asInterface(mSubscriber.asBinder());
-        mSubscriber2 = new MockVmsSubscriber();
-    }
-
-    @Test
-    public void testDefaultSubscriptionState() {
-        assertNoSubscribers();
-
-        assertEquals(
-                new VmsSubscriptionState(0, Collections.emptySet(), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testAddPassiveSubscriber() {
-        mRouting.addSubscription(mSubscriber);
-
-        // Receives messages for all layers and publishers
-        assertSubscribers(LAYER_1, mSubscriber);
-        assertSubscribers(LAYER_2, mSubscriber);
-
-        assertEquals(
-                new VmsSubscriptionState(0, Collections.emptySet(), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testAddPassiveSubscriber_MultipleTimes() {
-        mRouting.addSubscription(mSubscriber);
-        mRouting.addSubscription(mSubscriber);
-
-        assertSubscribers(LAYER_1, mSubscriber);
-        assertSubscribers(LAYER_2, mSubscriber);
-
-        assertEquals(
-                new VmsSubscriptionState(0, Collections.emptySet(), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testAddPassiveSubscriber_MultipleTimes_Rewrapped() {
-        mRouting.addSubscription(mSubscriber);
-        mRouting.addSubscription(mSubscriberRewrapped);
-
-        assertSubscribers(LAYER_1, mSubscriber);
-        assertSubscribers(LAYER_2, mSubscriber);
-
-        assertEquals(
-                new VmsSubscriptionState(0, Collections.emptySet(), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testAddPassiveSubscriber_MultipleSubscribers() {
-        mRouting.addSubscription(mSubscriber);
-        mRouting.addSubscription(mSubscriber2);
-
-        assertSubscribers(LAYER_1, mSubscriber, mSubscriber2);
-        assertSubscribers(LAYER_2, mSubscriber, mSubscriber2);
-
-        assertEquals(
-                new VmsSubscriptionState(0, Collections.emptySet(), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemovePassiveSubscriber() {
-        mRouting.addSubscription(mSubscriber);
-        mRouting.removeSubscription(mSubscriber);
-
-        assertNoSubscribers();
-
-        assertEquals(
-                new VmsSubscriptionState(0, Collections.emptySet(), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemovePassiveSubscriber_NoSubscriptions() {
-        mRouting.removeSubscription(mSubscriber);
-
-        assertNoSubscribers();
-
-        assertEquals(
-                new VmsSubscriptionState(0, Collections.emptySet(), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemovePassiveSubscriber_MultipleTimes() {
-        mRouting.addSubscription(mSubscriber);
-        mRouting.removeSubscription(mSubscriber);
-        mRouting.removeSubscription(mSubscriber);
-
-        assertNoSubscribers();
-
-        assertEquals(
-                new VmsSubscriptionState(0, Collections.emptySet(), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemovePassiveSubscriber_Rewrapped() {
-        mRouting.addSubscription(mSubscriber);
-        mRouting.removeSubscription(mSubscriberRewrapped);
-
-        assertNoSubscribers();
-
-        assertEquals(
-                new VmsSubscriptionState(0, Collections.emptySet(), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemovePassiveSubscriber_UnknownSubscriber() {
-        mRouting.addSubscription(mSubscriber);
-        mRouting.removeSubscription(mSubscriber2);
-
-        assertSubscribers(mSubscriber);
-
-        assertEquals(
-                new VmsSubscriptionState(0, Collections.emptySet(), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemovePassiveSubscriber_MultipleSubscribers() {
-        mRouting.addSubscription(mSubscriber);
-        mRouting.addSubscription(mSubscriber2);
-        mRouting.removeSubscription(mSubscriber2);
-
-        assertSubscribers(mSubscriber);
-
-        assertEquals(
-                new VmsSubscriptionState(0, Collections.emptySet(), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testAddLayerSubscriber() {
-        mRouting.addSubscription(mSubscriber, LAYER_1);
-
-        assertSubscribers(LAYER_1, mSubscriber);
-        assertNoSubscribers(LAYER_2);
-
-        assertEquals(
-                new VmsSubscriptionState(1, Collections.singleton(LAYER_1), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testAddLayerSubscriber_MultipleTimes() {
-        mRouting.addSubscription(mSubscriber, LAYER_1);
-        mRouting.addSubscription(mSubscriber, LAYER_1);
-
-        assertSubscribers(LAYER_1, mSubscriber);
-        assertNoSubscribers(LAYER_2);
-
-        assertEquals(
-                new VmsSubscriptionState(1, Collections.singleton(LAYER_1), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testAddLayerSubscriber_MultipleTimes_Rewrapped() {
-        mRouting.addSubscription(mSubscriber, LAYER_1);
-        mRouting.addSubscription(mSubscriberRewrapped, LAYER_1);
-
-        assertSubscribers(LAYER_1, mSubscriber);
-        assertNoSubscribers(LAYER_2);
-
-        assertEquals(
-                new VmsSubscriptionState(1, Collections.singleton(LAYER_1), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testAddLayerSubscriber_MultipleLayers() {
-        mRouting.addSubscription(mSubscriber, LAYER_1);
-        mRouting.addSubscription(mSubscriber, LAYER_2);
-
-        assertSubscribers(LAYER_1, mSubscriber);
-        assertSubscribers(LAYER_2, mSubscriber);
-
-        assertEquals(
-                new VmsSubscriptionState(2,
-                        new HashSet<>(Arrays.asList(LAYER_1, LAYER_2)), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testAddLayerSubscriber_MultipleSubscribers() {
-        mRouting.addSubscription(mSubscriber, LAYER_1);
-        mRouting.addSubscription(mSubscriber2, LAYER_1);
-
-        assertSubscribers(LAYER_1, mSubscriber, mSubscriber2);
-        assertNoSubscribers(LAYER_2);
-
-        assertEquals(
-                new VmsSubscriptionState(2, Collections.singleton(LAYER_1), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testAddLayerSubscriber_MultipleSubscribers_MultipleLayers() {
-        mRouting.addSubscription(mSubscriber, LAYER_1);
-        mRouting.addSubscription(mSubscriber2, LAYER_2);
-
-        assertSubscribers(LAYER_1, mSubscriber);
-        assertSubscribers(LAYER_2, mSubscriber2);
-
-        assertEquals(
-                new VmsSubscriptionState(2,
-                        new HashSet<>(Arrays.asList(LAYER_1, LAYER_2)), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemoveLayerSubscriber() {
-        mRouting.addSubscription(mSubscriber, LAYER_1);
-        mRouting.removeSubscription(mSubscriber, LAYER_1);
-
-        assertNoSubscribers();
-
-        assertEquals(
-                new VmsSubscriptionState(2, Collections.emptySet(), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemoveLayerSubscriber_NoSubscriptions() {
-        mRouting.removeSubscription(mSubscriber, LAYER_1);
-
-        assertNoSubscribers();
-
-        assertEquals(
-                new VmsSubscriptionState(0, Collections.emptySet(), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemoveLayerSubscriber_MultipleTimes() {
-        mRouting.addSubscription(mSubscriber, LAYER_1);
-        mRouting.removeSubscription(mSubscriber, LAYER_1);
-        mRouting.removeSubscription(mSubscriber, LAYER_1);
-
-        assertNoSubscribers();
-
-        assertEquals(
-                new VmsSubscriptionState(2, Collections.emptySet(), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemoveLayerSubscriber_Rewrapped() {
-        mRouting.addSubscription(mSubscriber, LAYER_1);
-        mRouting.removeSubscription(mSubscriberRewrapped, LAYER_1);
-
-        assertNoSubscribers();
-
-        assertEquals(
-                new VmsSubscriptionState(2, Collections.emptySet(), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemoveLayerSubscriber_UnknownSubscriber() {
-        mRouting.addSubscription(mSubscriber, LAYER_1);
-        mRouting.removeSubscription(mSubscriber2, LAYER_1);
-
-        assertSubscribers(LAYER_1, mSubscriber);
-        assertNoSubscribers(LAYER_2);
-
-        assertEquals(
-                new VmsSubscriptionState(1, Collections.singleton(LAYER_1), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemoveLayerSubscriber_MultipleLayers() {
-        mRouting.addSubscription(mSubscriber, LAYER_1);
-        mRouting.addSubscription(mSubscriber, LAYER_2);
-        mRouting.removeSubscription(mSubscriber, LAYER_2);
-
-        assertSubscribers(LAYER_1, mSubscriber);
-        assertNoSubscribers(LAYER_2);
-
-        assertEquals(
-                new VmsSubscriptionState(3, Collections.singleton(LAYER_1), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemoveLayerSubscriber_MultipleSubscribers() {
-        mRouting.addSubscription(mSubscriber, LAYER_1);
-        mRouting.addSubscription(mSubscriber2, LAYER_1);
-        mRouting.removeSubscription(mSubscriber2, LAYER_1);
-
-        assertSubscribers(LAYER_1, mSubscriber);
-        assertNoSubscribers(LAYER_2);
-
-        assertEquals(
-                new VmsSubscriptionState(3, Collections.singleton(LAYER_1), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemoveLayerSubscriber_MultipleSubscribers_MultipleLayers() {
-        mRouting.addSubscription(mSubscriber, LAYER_1);
-        mRouting.addSubscription(mSubscriber2, LAYER_2);
-        mRouting.removeSubscription(mSubscriber2, LAYER_2);
-
-        assertSubscribers(LAYER_1, mSubscriber);
-        assertNoSubscribers(LAYER_2);
-
-        assertEquals(
-                new VmsSubscriptionState(3, Collections.singleton(LAYER_1), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testAddPublisherSubscriber() {
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-
-        assertSubscribers(LAYER_1, PUBLISHER_ID_1, mSubscriber);
-        assertNoSubscribers(LAYER_1, PUBLISHER_ID_2);
-        assertNoSubscribers(LAYER_2);
-
-        assertEquals(
-                new VmsSubscriptionState(1, Collections.emptySet(),
-                        Collections.singleton(new VmsAssociatedLayer(
-                                LAYER_1, Collections.singleton(PUBLISHER_ID_1)))),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testAddPublisherSubscriber_MultipleTimes() {
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-
-        assertSubscribers(LAYER_1, PUBLISHER_ID_1, mSubscriber);
-        assertNoSubscribers(LAYER_1, PUBLISHER_ID_2);
-        assertNoSubscribers(LAYER_2);
-
-        assertEquals(
-                new VmsSubscriptionState(1, Collections.emptySet(),
-                        Collections.singleton(new VmsAssociatedLayer(
-                                LAYER_1, Collections.singleton(PUBLISHER_ID_1)))),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testAddPublisherSubscriber_MultipleTimes_Rewrapped() {
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.addSubscription(mSubscriberRewrapped, LAYER_1, PUBLISHER_ID_1);
-
-        assertSubscribers(LAYER_1, PUBLISHER_ID_1, mSubscriber);
-        assertNoSubscribers(LAYER_1, PUBLISHER_ID_2);
-        assertNoSubscribers(LAYER_2);
-
-        assertEquals(
-                new VmsSubscriptionState(1, Collections.emptySet(),
-                        Collections.singleton(new VmsAssociatedLayer(
-                                LAYER_1, Collections.singleton(PUBLISHER_ID_1)))),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testAddPublisherSubscriber_MultipleSubscribers() {
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.addSubscription(mSubscriber2, LAYER_1, PUBLISHER_ID_1);
-
-        assertSubscribers(LAYER_1, PUBLISHER_ID_1, mSubscriber, mSubscriber2);
-        assertNoSubscribers(LAYER_1, PUBLISHER_ID_2);
-        assertNoSubscribers(LAYER_2);
-
-        assertEquals(
-                new VmsSubscriptionState(2, Collections.emptySet(),
-                        Collections.singleton(new VmsAssociatedLayer(
-                                LAYER_1, Collections.singleton(PUBLISHER_ID_1)))),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testAddPublisherSubscriber_MultipleLayers() {
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.addSubscription(mSubscriber, LAYER_2, PUBLISHER_ID_1);
-
-        assertSubscribers(LAYER_1, PUBLISHER_ID_1, mSubscriber);
-        assertSubscribers(LAYER_2, PUBLISHER_ID_1, mSubscriber);
-        assertNoSubscribers(LAYER_1, PUBLISHER_ID_2);
-        assertNoSubscribers(LAYER_2, PUBLISHER_ID_2);
-
-        assertEquals(
-                new VmsSubscriptionState(2, Collections.emptySet(),
-                        new HashSet<>(Arrays.asList(
-                                new VmsAssociatedLayer(
-                                        LAYER_1, Collections.singleton(PUBLISHER_ID_1)),
-                                new VmsAssociatedLayer(
-                                        LAYER_2, Collections.singleton(PUBLISHER_ID_1))
-                        ))),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testAddPublisherSubscriber_MultiplePublishers() {
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_2);
-
-        assertSubscribers(LAYER_1, PUBLISHER_ID_1, mSubscriber);
-        assertSubscribers(LAYER_1, PUBLISHER_ID_2, mSubscriber);
-        assertNoSubscribers(LAYER_2);
-
-        assertEquals(
-                new VmsSubscriptionState(2, Collections.emptySet(),
-                        Collections.singleton(new VmsAssociatedLayer(
-                                LAYER_1,
-                                new HashSet<>(Arrays.asList(PUBLISHER_ID_1, PUBLISHER_ID_2))
-                        ))),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testAddPublisherSubscriber_MultipleSubscribers_MultipleLayers() {
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.addSubscription(mSubscriber2, LAYER_2, PUBLISHER_ID_1);
-
-        assertSubscribers(LAYER_1, PUBLISHER_ID_1, mSubscriber);
-        assertSubscribers(LAYER_2, PUBLISHER_ID_1, mSubscriber2);
-        assertNoSubscribers(LAYER_1, PUBLISHER_ID_2);
-        assertNoSubscribers(LAYER_2, PUBLISHER_ID_2);
-
-        assertEquals(
-                new VmsSubscriptionState(2, Collections.emptySet(),
-                        new HashSet<>(Arrays.asList(
-                                new VmsAssociatedLayer(
-                                        LAYER_1, Collections.singleton(PUBLISHER_ID_1)),
-                                new VmsAssociatedLayer(
-                                        LAYER_2, Collections.singleton(PUBLISHER_ID_1))
-                        ))),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testAddPublisherSubscriber_MultipleSubscribers_MultiplePublishers() {
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.addSubscription(mSubscriber2, LAYER_1, PUBLISHER_ID_2);
-
-        assertSubscribers(LAYER_1, PUBLISHER_ID_1, mSubscriber);
-        assertSubscribers(LAYER_1, PUBLISHER_ID_2, mSubscriber2);
-        assertNoSubscribers(LAYER_2);
-
-        assertEquals(
-                new VmsSubscriptionState(2, Collections.emptySet(),
-                        Collections.singleton(new VmsAssociatedLayer(
-                                LAYER_1,
-                                new HashSet<>(Arrays.asList(PUBLISHER_ID_1, PUBLISHER_ID_2))
-                        ))),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemovePublisherSubscriber() {
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.removeSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-
-        assertNoSubscribers();
-
-        assertEquals(
-                new VmsSubscriptionState(2, Collections.emptySet(), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemovePublisherSubscriber_NoSubscribers() {
-        mRouting.removeSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-
-        assertNoSubscribers();
-
-        assertEquals(
-                new VmsSubscriptionState(0, Collections.emptySet(), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemovePublisherSubscriber_MultipleTimes() {
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.removeSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.removeSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-
-        assertNoSubscribers();
-
-        assertEquals(
-                new VmsSubscriptionState(2, Collections.emptySet(), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemovePublisherSubscriber_Rewrapped() {
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.removeSubscription(mSubscriberRewrapped, LAYER_1, PUBLISHER_ID_1);
-
-        assertNoSubscribers();
-
-        assertEquals(
-                new VmsSubscriptionState(2, Collections.emptySet(), Collections.emptySet()),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemovePublisherSubscriber_UnknownSubscriber() {
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.removeSubscription(mSubscriber2, LAYER_1, PUBLISHER_ID_1);
-
-        assertSubscribers(LAYER_1, PUBLISHER_ID_1, mSubscriber);
-        assertNoSubscribers(LAYER_1, PUBLISHER_ID_2);
-        assertNoSubscribers(LAYER_2);
-
-        assertEquals(
-                new VmsSubscriptionState(1, Collections.emptySet(),
-                        Collections.singleton(new VmsAssociatedLayer(
-                                LAYER_1, Collections.singleton(PUBLISHER_ID_1)))),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemovePublisherSubscriber_MultipleLayers() {
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.addSubscription(mSubscriber2, LAYER_2, PUBLISHER_ID_1);
-        mRouting.removeSubscription(mSubscriber2, LAYER_2, PUBLISHER_ID_1);
-
-        assertSubscribers(LAYER_1, PUBLISHER_ID_1, mSubscriber);
-        assertNoSubscribers(LAYER_1, PUBLISHER_ID_2);
-        assertNoSubscribers(LAYER_2);
-
-        assertEquals(
-                new VmsSubscriptionState(3, Collections.emptySet(),
-                        Collections.singleton(new VmsAssociatedLayer(
-                                LAYER_1, Collections.singleton(PUBLISHER_ID_1)))),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemovePublisherSubscriber_MultiplePublishers() {
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.addSubscription(mSubscriber2, LAYER_1, PUBLISHER_ID_2);
-        mRouting.removeSubscription(mSubscriber2, LAYER_1, PUBLISHER_ID_2);
-
-        assertSubscribers(LAYER_1, PUBLISHER_ID_1, mSubscriber);
-        assertNoSubscribers(LAYER_1, PUBLISHER_ID_2);
-        assertNoSubscribers(LAYER_2);
-
-        assertEquals(
-                new VmsSubscriptionState(3, Collections.emptySet(),
-                        Collections.singleton(new VmsAssociatedLayer(
-                                LAYER_1, Collections.singleton(PUBLISHER_ID_1)))),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemovePublisherSubscriber_MultipleSubscribers() {
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.addSubscription(mSubscriber2, LAYER_1, PUBLISHER_ID_1);
-        mRouting.removeSubscription(mSubscriber2, LAYER_1, PUBLISHER_ID_1);
-
-        assertSubscribers(LAYER_1, PUBLISHER_ID_1, mSubscriber);
-        assertNoSubscribers(LAYER_1, PUBLISHER_ID_2);
-        assertNoSubscribers(LAYER_2);
-
-        assertEquals(
-                new VmsSubscriptionState(3, Collections.emptySet(),
-                        Collections.singleton(new VmsAssociatedLayer(
-                                LAYER_1, Collections.singleton(PUBLISHER_ID_1)))),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemovePublisherSubscriber_MultipleSubscribers_MultipleLayers() {
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.addSubscription(mSubscriber2, LAYER_2, PUBLISHER_ID_1);
-        mRouting.removeSubscription(mSubscriber2, LAYER_2, PUBLISHER_ID_1);
-
-        assertSubscribers(LAYER_1, PUBLISHER_ID_1, mSubscriber);
-        assertNoSubscribers(LAYER_2);
-
-        assertEquals(
-                new VmsSubscriptionState(3, Collections.emptySet(),
-                        Collections.singleton(new VmsAssociatedLayer(
-                                LAYER_1, Collections.singleton(PUBLISHER_ID_1)))),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemovePublisherSubscriber_MultipleSubscribers_MultiplePublishers() {
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.addSubscription(mSubscriber2, LAYER_1, PUBLISHER_ID_2);
-        mRouting.removeSubscription(mSubscriber2, LAYER_1, PUBLISHER_ID_2);
-
-        assertSubscribers(LAYER_1, PUBLISHER_ID_1, mSubscriber);
-        assertNoSubscribers(LAYER_1, PUBLISHER_ID_2);
-        assertNoSubscribers(LAYER_2);
-
-        assertEquals(
-                new VmsSubscriptionState(3, Collections.emptySet(),
-                        Collections.singleton(new VmsAssociatedLayer(
-                                LAYER_1, Collections.singleton(PUBLISHER_ID_1)))),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testAddingAllTypesOfSubscribers() {
-        IVmsSubscriberClient passiveSubscriber = new MockVmsSubscriber();
-        mRouting.addSubscription(passiveSubscriber);
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.addSubscription(mSubscriber2, LAYER_1);
-        mRouting.addSubscription(mSubscriber, LAYER_2);
-        mRouting.addSubscription(mSubscriber2, LAYER_2, PUBLISHER_ID_2);
-
-        assertSubscribers(LAYER_1, PUBLISHER_ID_1, passiveSubscriber, mSubscriber, mSubscriber2);
-        assertSubscribers(LAYER_1, PUBLISHER_ID_2, passiveSubscriber, mSubscriber2);
-        assertSubscribers(LAYER_2, PUBLISHER_ID_1, passiveSubscriber, mSubscriber);
-        assertSubscribers(LAYER_2, PUBLISHER_ID_2, passiveSubscriber, mSubscriber, mSubscriber2);
-
-        assertEquals(
-                new VmsSubscriptionState(4,
-                        new HashSet<>(Arrays.asList(LAYER_1, LAYER_2)),
-                        new HashSet<>(Arrays.asList(
-                                new VmsAssociatedLayer(
-                                        LAYER_1, Collections.singleton(PUBLISHER_ID_1)),
-                                new VmsAssociatedLayer(
-                                        LAYER_2, Collections.singleton(PUBLISHER_ID_2))
-                        ))),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testAddingAndRemovingAllTypesOfSubscribers() {
-        IVmsSubscriberClient passiveSubscriber = new MockVmsSubscriber();
-        mRouting.addSubscription(passiveSubscriber);
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.addSubscription(mSubscriber2, LAYER_1);
-        mRouting.addSubscription(mSubscriber, LAYER_2);
-        mRouting.addSubscription(mSubscriber2, LAYER_2, PUBLISHER_ID_2);
-        mRouting.removeSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.removeSubscription(mSubscriber, LAYER_2);
-
-        assertSubscribers(LAYER_1, PUBLISHER_ID_1, passiveSubscriber, mSubscriber2);
-        assertSubscribers(LAYER_1, PUBLISHER_ID_2, passiveSubscriber, mSubscriber2);
-        assertSubscribers(LAYER_2, PUBLISHER_ID_1, passiveSubscriber);
-        assertSubscribers(LAYER_2, PUBLISHER_ID_2, passiveSubscriber, mSubscriber2);
-
-        assertEquals(
-                new VmsSubscriptionState(6,
-                        Collections.singleton(LAYER_1),
-                        Collections.singleton(
-                                new VmsAssociatedLayer(
-                                        LAYER_2, Collections.singleton(PUBLISHER_ID_2))
-                        )),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemoveDeadSubscriber() {
-        IVmsSubscriberClient passiveSubscriber = new MockVmsSubscriber();
-        mRouting.addSubscription(passiveSubscriber);
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.addSubscription(mSubscriber2, LAYER_1);
-        mRouting.addSubscription(mSubscriber, LAYER_2);
-        mRouting.addSubscription(mSubscriber2, LAYER_2, PUBLISHER_ID_2);
-        assertTrue(mRouting.removeDeadSubscriber(mSubscriber));
-
-        assertSubscribers(LAYER_1, PUBLISHER_ID_1, passiveSubscriber, mSubscriber2);
-        assertSubscribers(LAYER_1, PUBLISHER_ID_2, passiveSubscriber, mSubscriber2);
-        assertSubscribers(LAYER_2, PUBLISHER_ID_1, passiveSubscriber);
-        assertSubscribers(LAYER_2, PUBLISHER_ID_2, passiveSubscriber, mSubscriber2);
-
-        assertEquals(
-                new VmsSubscriptionState(6,
-                        Collections.singleton(LAYER_1),
-                        Collections.singleton(
-                                new VmsAssociatedLayer(
-                                        LAYER_2, Collections.singleton(PUBLISHER_ID_2))
-                        )),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemoveDeadSubscriber_NoSubscriptions() {
-        IVmsSubscriberClient passiveSubscriber = new MockVmsSubscriber();
-        mRouting.addSubscription(passiveSubscriber);
-        mRouting.addSubscription(mSubscriber2, LAYER_1);
-        mRouting.addSubscription(mSubscriber2, LAYER_2, PUBLISHER_ID_2);
-        assertFalse(mRouting.removeDeadSubscriber(mSubscriber));
-
-        assertSubscribers(LAYER_1, PUBLISHER_ID_1, passiveSubscriber, mSubscriber2);
-        assertSubscribers(LAYER_1, PUBLISHER_ID_2, passiveSubscriber, mSubscriber2);
-        assertSubscribers(LAYER_2, PUBLISHER_ID_1, passiveSubscriber);
-        assertSubscribers(LAYER_2, PUBLISHER_ID_2, passiveSubscriber, mSubscriber2);
-
-        assertEquals(
-                new VmsSubscriptionState(2,
-                        Collections.singleton(LAYER_1),
-                        Collections.singleton(
-                                new VmsAssociatedLayer(
-                                        LAYER_2, Collections.singleton(PUBLISHER_ID_2))
-                        )),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testRemoveDeadSubscriber_PassiveSubscriber() {
-        IVmsSubscriberClient passiveSubscriber = new MockVmsSubscriber();
-        mRouting.addSubscription(passiveSubscriber);
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.addSubscription(mSubscriber2, LAYER_1);
-        mRouting.addSubscription(mSubscriber, LAYER_2);
-        mRouting.addSubscription(mSubscriber2, LAYER_2, PUBLISHER_ID_2);
-        assertFalse(mRouting.removeDeadSubscriber(passiveSubscriber));
-
-        assertSubscribers(LAYER_1, PUBLISHER_ID_1, mSubscriber, mSubscriber2);
-        assertSubscribers(LAYER_1, PUBLISHER_ID_2, mSubscriber2);
-        assertSubscribers(LAYER_2, PUBLISHER_ID_1, mSubscriber);
-        assertSubscribers(LAYER_2, PUBLISHER_ID_2, mSubscriber, mSubscriber2);
-
-        assertEquals(
-                new VmsSubscriptionState(4,
-                        new HashSet<>(Arrays.asList(LAYER_1, LAYER_2)),
-                        new HashSet<>(Arrays.asList(
-                                new VmsAssociatedLayer(
-                                        LAYER_1, Collections.singleton(PUBLISHER_ID_1)),
-                                new VmsAssociatedLayer(
-                                        LAYER_2, Collections.singleton(PUBLISHER_ID_2))
-                        ))),
-                mRouting.getSubscriptionState());
-    }
-
-    @Test
-    public void testHasSubscriptions_Default() {
-        assertFalse(mRouting.hasLayerSubscriptions(LAYER_1));
-        assertFalse(mRouting.hasLayerSubscriptions(LAYER_2));
-        assertFalse(mRouting.hasLayerFromPublisherSubscriptions(LAYER_1, PUBLISHER_ID_1));
-        assertFalse(mRouting.hasLayerFromPublisherSubscriptions(LAYER_1, PUBLISHER_ID_2));
-        assertFalse(mRouting.hasLayerFromPublisherSubscriptions(LAYER_2, PUBLISHER_ID_1));
-        assertFalse(mRouting.hasLayerFromPublisherSubscriptions(LAYER_2, PUBLISHER_ID_2));
-    }
-
-    @Test
-    public void testHasSubscriptions_PassiveSubscriber() {
-        mRouting.addSubscription(mSubscriber);
-
-        testHasSubscriptions_Default();
-    }
-
-    @Test
-    public void testHasSubscriptions_DeadSubscriber() {
-        mRouting.addSubscription(mSubscriber);
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-        mRouting.removeDeadSubscriber(mSubscriber);
-
-        testHasSubscriptions_Default();
-    }
-
-    @Test
-    public void testHasSubscriptions_Layer() {
-        mRouting.addSubscription(mSubscriber, LAYER_1);
-
-        assertTrue(mRouting.hasLayerSubscriptions(LAYER_1));
-        assertFalse(mRouting.hasLayerSubscriptions(LAYER_2));
-        assertFalse(mRouting.hasLayerFromPublisherSubscriptions(LAYER_1, PUBLISHER_ID_1));
-        assertFalse(mRouting.hasLayerFromPublisherSubscriptions(LAYER_1, PUBLISHER_ID_2));
-        assertFalse(mRouting.hasLayerFromPublisherSubscriptions(LAYER_2, PUBLISHER_ID_1));
-        assertFalse(mRouting.hasLayerFromPublisherSubscriptions(LAYER_2, PUBLISHER_ID_2));
-
-        mRouting.removeSubscription(mSubscriber, LAYER_1);
-
-        assertFalse(mRouting.hasLayerSubscriptions(LAYER_1));
-    }
-
-    @Test
-    public void testHasSubscriptions_LayerFromPublisher() {
-        mRouting.addSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-
-        assertFalse(mRouting.hasLayerSubscriptions(LAYER_1));
-        assertFalse(mRouting.hasLayerSubscriptions(LAYER_2));
-        assertTrue(mRouting.hasLayerFromPublisherSubscriptions(LAYER_1, PUBLISHER_ID_1));
-        assertFalse(mRouting.hasLayerFromPublisherSubscriptions(LAYER_1, PUBLISHER_ID_2));
-        assertFalse(mRouting.hasLayerFromPublisherSubscriptions(LAYER_2, PUBLISHER_ID_1));
-        assertFalse(mRouting.hasLayerFromPublisherSubscriptions(LAYER_2, PUBLISHER_ID_2));
-
-        mRouting.removeSubscription(mSubscriber, LAYER_1, PUBLISHER_ID_1);
-
-        assertFalse(mRouting.hasLayerFromPublisherSubscriptions(LAYER_1, PUBLISHER_ID_1));
-    }
-
-    class MockVmsSubscriber extends IVmsSubscriberClient.Stub {
-        @Override
-        public void onVmsMessageReceived(VmsLayer layer, byte[] payload) {
-            throw new RuntimeException("Should not be accessed");
-        }
-
-        @Override
-        public void onLayersAvailabilityChanged(VmsAvailableLayers availableLayers) {
-            throw new RuntimeException("Should not be accessed");
-        }
-    }
-
-    private void assertNoSubscribers() {
-        assertSubscribers(); /* subscribers is empty */
-    }
-
-    private void assertNoSubscribers(VmsLayer layer) {
-        assertSubscribers(layer); /* subscribers is empty */
-    }
-
-    private void assertNoSubscribers(VmsLayer layer, int publisherId) {
-        assertSubscribers(layer, publisherId); /* subscribers is empty */
-    }
-
-    private void assertSubscribers(IVmsSubscriberClient... subscribers) {
-        for (VmsLayer layer : LAYERS) {
-            assertSubscribers(layer, subscribers);
-        }
-    }
-
-    private void assertSubscribers(VmsLayer layer, IVmsSubscriberClient... subscribers) {
-        for (int publisherId : PUBLISHER_IDS) {
-            assertSubscribers(layer, publisherId, subscribers);
-        }
-    }
-
-    private void assertSubscribers(VmsLayer layer, int publisherId,
-            IVmsSubscriberClient... subscribers) {
-        assertEquals(
-                new HashSet<>(Arrays.asList(subscribers)),
-                mRouting.getSubscribersForLayerFromPublisher(layer, publisherId));
-    }
-}
\ No newline at end of file
diff --git a/tests/carservice_unit_test/src/com/android/car/VmsSubscriberServiceTest.java b/tests/carservice_unit_test/src/com/android/car/VmsSubscriberServiceTest.java
deleted file mode 100644
index 0208515..0000000
--- a/tests/carservice_unit_test/src/com/android/car/VmsSubscriberServiceTest.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.car.vms.IVmsSubscriberClient;
-import android.car.vms.VmsAvailableLayers;
-import android.car.vms.VmsLayer;
-import android.content.Context;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.car.hal.VmsHalService;
-import com.android.car.vms.VmsBrokerService;
-import com.android.car.vms.VmsClientManager;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import java.util.Arrays;
-import java.util.Collections;
-
-@SmallTest
-public class VmsSubscriberServiceTest {
-    private static final VmsLayer LAYER = new VmsLayer(1, 2, 3);
-    private static final int PUBLISHER_ID = 54321;
-    private static final byte[] PUBLISHER_INFO = new byte[]{1, 2, 3, 4};
-    private static final VmsAvailableLayers AVAILABLE_LAYERS =
-            new VmsAvailableLayers(Collections.emptySet(), 0);
-
-    @Rule
-    public MockitoRule mMockitoRule = MockitoJUnit.rule();
-    @Mock
-    private Context mContext;
-    @Mock
-    private VmsBrokerService mBrokerService;
-    @Mock
-    private VmsClientManager mClientManager;
-    @Mock
-    private VmsHalService mHal;
-
-    @Mock
-    private IVmsSubscriberClient mSubscriberClient;
-    @Mock
-    private IVmsSubscriberClient mSubscriberClient2;
-
-    private VmsSubscriberService mSubscriberService;
-
-    @Before
-    public void setUp() {
-        mSubscriberService = new VmsSubscriberService(mContext, mBrokerService, mClientManager,
-                mHal);
-        verify(mBrokerService).addSubscriberListener(eq(mSubscriberService));
-        verify(mHal).setVmsSubscriberService(eq(mSubscriberService));
-    }
-
-    @After
-    public void tearDown() {
-        verifyNoMoreInteractions(mBrokerService, mClientManager);
-    }
-
-    @Test
-    public void testAddVmsSubscriberToNotifications() {
-        mSubscriberService.addVmsSubscriberToNotifications(mSubscriberClient);
-        verify(mClientManager).addSubscriber(mSubscriberClient);
-    }
-
-    @Test
-    public void testRemoveVmsSubscriberToNotifications() {
-        mSubscriberService.removeVmsSubscriberToNotifications(mSubscriberClient);
-        verify(mClientManager).removeSubscriber(mSubscriberClient);
-    }
-
-    @Test
-    public void testAddVmsSubscriber() {
-        mSubscriberService.addVmsSubscriber(mSubscriberClient, LAYER);
-        verify(mClientManager).addSubscriber(mSubscriberClient);
-        verify(mBrokerService).addSubscription(mSubscriberClient, LAYER);
-    }
-
-    @Test
-    public void testRemoveVmsSubscriber() {
-        mSubscriberService.removeVmsSubscriber(mSubscriberClient, LAYER);
-        verify(mBrokerService).removeSubscription(mSubscriberClient, LAYER);
-    }
-
-
-    @Test
-    public void testAddVmsSubscriberToPublisher() {
-        mSubscriberService.addVmsSubscriberToPublisher(mSubscriberClient, LAYER, PUBLISHER_ID);
-        verify(mClientManager).addSubscriber(mSubscriberClient);
-        verify(mBrokerService).addSubscription(mSubscriberClient, LAYER, PUBLISHER_ID);
-    }
-
-    @Test
-    public void testRemoveVmsSubscriberToPublisher() {
-        testAddVmsSubscriberToPublisher();
-
-        mSubscriberService.removeVmsSubscriberToPublisher(mSubscriberClient, LAYER, PUBLISHER_ID);
-        verify(mBrokerService).removeSubscription(mSubscriberClient, LAYER, PUBLISHER_ID);
-    }
-
-    @Test
-    public void testAddVmsSubscriberPassive() {
-        mSubscriberService.addVmsSubscriberPassive(mSubscriberClient);
-        verify(mClientManager).addSubscriber(mSubscriberClient);
-        verify(mBrokerService).addSubscription(mSubscriberClient);
-    }
-
-    @Test
-    public void testRemoveVmsSubscriberPassive() {
-        mSubscriberService.removeVmsSubscriberPassive(mSubscriberClient);
-        verify(mBrokerService).removeSubscription(mSubscriberClient);
-    }
-
-    @Test
-    public void testGetPublisherInfo() {
-        when(mBrokerService.getPublisherInfo(PUBLISHER_ID)).thenReturn(PUBLISHER_INFO);
-        assertThat(mSubscriberService.getPublisherInfo(PUBLISHER_ID)).isSameAs(PUBLISHER_INFO);
-        verify(mBrokerService).getPublisherInfo(PUBLISHER_ID);
-    }
-
-    @Test
-    public void testGetAvailableLayers() {
-        when(mBrokerService.getAvailableLayers()).thenReturn(AVAILABLE_LAYERS);
-        assertThat(mSubscriberService.getAvailableLayers()).isSameAs(AVAILABLE_LAYERS);
-        verify(mBrokerService).getAvailableLayers();
-    }
-
-    @Test
-    public void testOnLayersAvailabilityChange() throws Exception {
-        when(mClientManager.getAllSubscribers())
-                .thenReturn(Arrays.asList(mSubscriberClient, mSubscriberClient2));
-        mSubscriberService.onLayersAvailabilityChange(AVAILABLE_LAYERS);
-        verify(mClientManager).getAllSubscribers();
-        verify(mSubscriberClient).onLayersAvailabilityChanged(AVAILABLE_LAYERS);
-        verify(mSubscriberClient2).onLayersAvailabilityChanged(AVAILABLE_LAYERS);
-    }
-}
diff --git a/tests/carservice_unit_test/src/com/android/car/VmsSubscriptionStateTest.java b/tests/carservice_unit_test/src/com/android/car/VmsSubscriptionStateTest.java
deleted file mode 100644
index ea41286..0000000
--- a/tests/carservice_unit_test/src/com/android/car/VmsSubscriptionStateTest.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import static org.junit.Assert.assertNotEquals;
-
-import android.car.vms.VmsAssociatedLayer;
-import android.car.vms.VmsLayer;
-import android.car.vms.VmsSubscriptionState;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import android.os.Parcel;
-
-import java.util.Arrays;
-import java.util.HashSet;
-
-/*
- * A class to test the VmsSubscriptionState parcelability.
- */
-@SmallTest
-public class VmsSubscriptionStateTest extends AndroidTestCase {
-    private static final int LAYER_ID = 12;
-    private static final int LAYER_VERSION = 34;
-    private static final int LAYER_SUBTYPE = 56;
-
-    private static final int PUBLISHER_ID_1= 111;
-    private static final int PUBLISHER_ID_2= 222;
-
-    private static final int DIFFERENT_LAYER_ID = 99;
-
-    private static final int SEQUENCE_NUMBER = 1;
-    private static final int DIFFERENT_SEQUENCE_NUMBER = 2;
-
-    private static final VmsLayer VMS_LAYER = new VmsLayer(
-            LAYER_ID,
-            LAYER_SUBTYPE,
-            LAYER_VERSION);
-
-    private static final VmsLayer ANOTHER_VMS_LAYER = new VmsLayer(
-            DIFFERENT_LAYER_ID,
-            LAYER_SUBTYPE,
-            LAYER_VERSION);
-
-    private static final VmsAssociatedLayer VMS_ASSOCIATED_LAYER =
-            new VmsAssociatedLayer(
-                    VMS_LAYER,
-                    new HashSet<>(Arrays.asList(PUBLISHER_ID_1)));
-
-    public void testNoSubscriptionsParcel() throws Exception {
-        VmsSubscriptionState vmsSubscriptionState =
-                new VmsSubscriptionState(
-                        SEQUENCE_NUMBER,
-                        new HashSet<>(Arrays.asList()),
-                        new HashSet<>(Arrays.asList()));
-
-        Parcel parcel = Parcel.obtain();
-        vmsSubscriptionState.writeToParcel(parcel, vmsSubscriptionState.describeContents());
-        parcel.setDataPosition(0);
-        VmsSubscriptionState createdFromParcel = VmsSubscriptionState.CREATOR.createFromParcel(parcel);
-        assertEquals(vmsSubscriptionState, createdFromParcel);
-    }
-
-    public void testMultipleSubscriptionsParcel() throws Exception {
-        VmsSubscriptionState vmsSubscriptionState =
-                new VmsSubscriptionState(
-                        SEQUENCE_NUMBER,
-                        new HashSet<>(Arrays.asList(VMS_LAYER)),
-                        new HashSet<>(Arrays.asList(VMS_ASSOCIATED_LAYER)));
-
-        Parcel parcel = Parcel.obtain();
-        vmsSubscriptionState.writeToParcel(parcel, vmsSubscriptionState.describeContents());
-        parcel.setDataPosition(0);
-        VmsSubscriptionState createdFromParcel = VmsSubscriptionState.CREATOR.createFromParcel(parcel);
-        assertEquals(vmsSubscriptionState, createdFromParcel);
-    }
-
-    public void testNoSubscriptionsEquality() throws Exception {
-        VmsSubscriptionState original =
-                new VmsSubscriptionState(
-                        SEQUENCE_NUMBER,
-                        new HashSet<>(Arrays.asList()),
-                        new HashSet<>(Arrays.asList()));
-
-        VmsSubscriptionState similar =
-                new VmsSubscriptionState(
-                        SEQUENCE_NUMBER,
-                        new HashSet<>(Arrays.asList()),
-                        new HashSet<>(Arrays.asList()));
-
-        assertEquals(original.getSequenceNumber(), similar.getSequenceNumber());
-        assertEquals(original.getLayers(), similar.getLayers());
-        assertEquals(original.getAssociatedLayers(), similar.getAssociatedLayers());
-        assertEquals(original, similar);
-    }
-
-    public void testMultipleSubscriptionsEquality() throws Exception {
-        VmsSubscriptionState original =
-                new VmsSubscriptionState(
-                        SEQUENCE_NUMBER,
-                        new HashSet<>(Arrays.asList(VMS_LAYER)),
-                        new HashSet<>(Arrays.asList(VMS_ASSOCIATED_LAYER)));
-
-        VmsSubscriptionState similar =
-                new VmsSubscriptionState(
-                        SEQUENCE_NUMBER,
-                        new HashSet<>(Arrays.asList(VMS_LAYER)),
-                        new HashSet<>(Arrays.asList(VMS_ASSOCIATED_LAYER)));
-
-        assertEquals(original.getSequenceNumber(), similar.getSequenceNumber());
-        assertEquals(original.getLayers(), similar.getLayers());
-        assertEquals(original.getAssociatedLayers(), similar.getAssociatedLayers());
-        assertEquals(original, similar);
-    }
-
-    public void testVerifyNonEqualOnSequenceNumber() throws Exception {
-        VmsSubscriptionState original =
-                new VmsSubscriptionState(
-                        SEQUENCE_NUMBER,
-                        new HashSet<>(Arrays.asList(VMS_LAYER)),
-                        new HashSet<>(Arrays.asList(VMS_ASSOCIATED_LAYER)));
-
-        VmsSubscriptionState similar =
-                new VmsSubscriptionState(
-                        DIFFERENT_SEQUENCE_NUMBER,
-                        new HashSet<>(Arrays.asList(VMS_LAYER)),
-                        new HashSet<>(Arrays.asList(VMS_ASSOCIATED_LAYER)));
-
-        if (!original.equals(similar)) {
-            return;
-        }
-        fail("VmsSubscriptionState with different sequence numbers appear to be equal. original: " +
-                original +
-                ", similar: " +
-                similar);
-    }
-
-    public void testVerifyNonEqualOnLayers() throws Exception {
-        VmsSubscriptionState original =
-                new VmsSubscriptionState(
-                        SEQUENCE_NUMBER,
-                        new HashSet<>(Arrays.asList(VMS_LAYER)),
-                        new HashSet<>(Arrays.asList(VMS_ASSOCIATED_LAYER)));
-
-        VmsSubscriptionState similar =
-                new VmsSubscriptionState(
-                        SEQUENCE_NUMBER,
-                        new HashSet<>(Arrays.asList()),
-                        new HashSet<>(Arrays.asList(VMS_ASSOCIATED_LAYER)));
-
-        assertNotEquals(original, similar);
-    }
-
-    public void testVerifyNonEqualOnAssociatedLayers() throws Exception {
-        VmsSubscriptionState original =
-                new VmsSubscriptionState(
-                        SEQUENCE_NUMBER,
-                        new HashSet<>(Arrays.asList(VMS_LAYER)),
-                        new HashSet<>(Arrays.asList(VMS_ASSOCIATED_LAYER)));
-
-        VmsSubscriptionState similar =
-                new VmsSubscriptionState(
-                        SEQUENCE_NUMBER,
-                        new HashSet<>(Arrays.asList(VMS_LAYER)),
-                        new HashSet<>(Arrays.asList()));
-
-        assertNotEquals(original, similar);
-    }
-}
\ No newline at end of file
diff --git a/tests/carservice_unit_test/src/com/android/car/am/FixedActivityServiceTest.java b/tests/carservice_unit_test/src/com/android/car/am/FixedActivityServiceTest.java
new file mode 100644
index 0000000..6d1cc76
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/am/FixedActivityServiceTest.java
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.am;
+
+import static android.car.test.mocks.AndroidMockitoHelper.mockAmGetCurrentUser;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.ActivityManager.StackInfo;
+import android.app.ActivityOptions;
+import android.app.IActivityManager;
+import android.app.TaskStackListener;
+import android.car.hardware.power.CarPowerManager;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.hardware.display.DisplayManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.view.Display;
+
+import com.android.car.CarLocalServices;
+import com.android.car.CarServiceUtils;
+import com.android.car.user.CarUserService;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.stubbing.OngoingStubbing;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public final class FixedActivityServiceTest extends AbstractExtendedMockitoTestCase {
+
+    private static final long RECHECK_INTERVAL_MARGIN_MS = 600;
+
+    private final int mValidDisplayId = 1;
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private IActivityManager mActivityManager;
+    @Mock
+    private UserManager mUserManager;
+    @Mock
+    private DisplayManager mDisplayManager;
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private CarUserService mCarUserService;
+    @Mock
+    private CarPowerManager mCarPowerManager;
+
+    private FixedActivityService mFixedActivityService;
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder builder) {
+        builder
+            .spyStatic(ActivityManager.class)
+            .spyStatic(CarLocalServices.class);
+    }
+
+    @Before
+    public void setUp() {
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        doReturn(mCarUserService).when(() -> CarLocalServices.getService(CarUserService.class));
+        doReturn(mCarPowerManager).when(() -> CarLocalServices.createCarPowerManager(mContext));
+        mFixedActivityService = new FixedActivityService(mContext, mActivityManager, mUserManager,
+                mDisplayManager);
+    }
+
+    @After
+    public void tearDown() {
+        if (mFixedActivityService != null) {
+            mFixedActivityService.release();
+        }
+        CarServiceUtils.finishAllHandlerTasks();
+    }
+
+    @Test
+    public void testStartFixedActivityModeForDisplayAndUser_noRunningActivity()
+            throws Exception {
+        int userId = 10;
+        ActivityOptions options = new ActivityOptions(new Bundle());
+        Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
+        mockAmGetCurrentUser(userId);
+        expectNoActivityStack();
+
+        // No running activities
+        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
+                options, mValidDisplayId, userId);
+        verify(mContext).startActivityAsUser(eq(intent), any(Bundle.class),
+                eq(UserHandle.of(userId)));
+        assertThat(ret).isTrue();
+    }
+
+    @Test
+    public void testStartFixedActivityModeForDisplayAndUser_alreadyRunningActivity()
+            throws Exception {
+        int userId = 10;
+        int[] userIds = new int[] { userId };
+        int[] taskIds = new int[] { 1234 };
+        ActivityOptions options = new ActivityOptions(new Bundle());
+        Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
+        mockAmGetCurrentUser(userId);
+        expectActivityStackInfo(
+                createEmptyStackInfo(),
+                createStackInfo(intent, userIds, mValidDisplayId, taskIds)
+        );
+
+        // No running activities
+        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
+                options, mValidDisplayId, userId);
+        verify(mContext).startActivityAsUser(eq(intent), any(Bundle.class),
+                eq(UserHandle.of(userId)));
+        assertThat(ret).isTrue();
+
+        ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
+                options, mValidDisplayId, userId);
+        // startActivityAsUser should not called at this time. So, total called count is 1.
+        verify(mContext).startActivityAsUser(eq(intent), any(Bundle.class),
+                eq(UserHandle.of(userId)));
+        assertThat(ret).isTrue();
+    }
+
+    @Test
+    public void testStartFixedActivityModeForDisplayAndUser_runNewActivity() throws Exception {
+        int userId = 10;
+        int[] userIds = new int[] { userId };
+        int[] taskIds = new int[] { 1234 };
+        ActivityOptions options = new ActivityOptions(new Bundle());
+        Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
+        Intent anotherIntent = expectComponentAvailable("test_package_II", "com.test.dude_II",
+                userId);
+        mockAmGetCurrentUser(userId);
+        expectActivityStackInfo(
+                createEmptyStackInfo(),
+                createStackInfo(intent, userIds, mValidDisplayId, taskIds)
+        );
+
+        // No running activities
+        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
+                options, mValidDisplayId, userId);
+        assertThat(ret).isTrue();
+
+        // Start activity with new package
+        ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(anotherIntent,
+                options, mValidDisplayId, userId);
+        verify(mContext).startActivityAsUser(eq(anotherIntent), any(Bundle.class),
+                eq(UserHandle.of(userId)));
+        assertThat(ret).isTrue();
+    }
+
+    @Test
+    public void testStartFixedActivityModeForDisplay_relaunchWithPackageUpdated() throws Exception {
+        int userId = 10;
+        int[] userIds = new int[] { userId };
+        int[] taskIds = new int[] { 1234 };
+        String packageName = "test_package";
+        String className = "com.test.dude";
+        ActivityOptions options = new ActivityOptions(new Bundle());
+        ArgumentCaptor<BroadcastReceiver> receiverCaptor =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
+        Intent intent = expectComponentAvailable(packageName, className, userId);
+        mockAmGetCurrentUser(userId);
+        expectActivityStackInfo(
+                createEmptyStackInfo(),
+                createStackInfo(intent, userIds, mValidDisplayId, taskIds)
+        );
+
+        // No running activities
+        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
+                options, mValidDisplayId, userId);
+        verify(mContext).registerReceiverAsUser(receiverCaptor.capture(), eq(UserHandle.ALL),
+                any(IntentFilter.class), eq(null), eq(null));
+        verify(mContext).startActivityAsUser(eq(intent), any(Bundle.class),
+                eq(UserHandle.of(userId)));
+        assertThat(ret).isTrue();
+
+        // Update package
+        SystemClock.sleep(RECHECK_INTERVAL_MARGIN_MS);
+        int appId = 987;
+        BroadcastReceiver receiver = receiverCaptor.getValue();
+        Intent packageIntent = new Intent(Intent.ACTION_PACKAGE_CHANGED);
+        packageIntent.setData(new Uri.Builder().path(packageName).build());
+        packageIntent.putExtra(Intent.EXTRA_UID, UserHandle.getUid(userId, appId));
+        receiver.onReceive(mContext, packageIntent);
+        verify(mContext).startActivityAsUser(eq(intent), any(Bundle.class),
+                eq(UserHandle.of(userId)));
+
+        SystemClock.sleep(RECHECK_INTERVAL_MARGIN_MS);
+        ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
+                options, mValidDisplayId, userId);
+        // Activity should not be launched.
+        verify(mContext).startActivityAsUser(eq(intent), any(Bundle.class),
+                eq(UserHandle.of(userId)));
+        assertThat(ret).isTrue();
+    }
+
+
+    @Test
+    public void testStartFixedActivityModeForDisplayAndUser_runOnDifferentDisplay()
+            throws Exception {
+        int userId = 10;
+        ActivityOptions options = new ActivityOptions(new Bundle());
+        Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
+        Intent anotherIntent = expectComponentAvailable("test_package_II", "com.test.dude_II",
+                userId);
+        mockAmGetCurrentUser(userId);
+        expectNoActivityStack();
+
+        // No running activities
+        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
+                options, mValidDisplayId, userId);
+        assertThat(ret).isTrue();
+
+        int anotherValidDisplayId = mValidDisplayId + 1;
+        ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(anotherIntent,
+                options, anotherValidDisplayId, userId);
+        verify(mContext).startActivityAsUser(eq(anotherIntent), any(Bundle.class),
+                eq(UserHandle.of(userId)));
+        assertThat(ret).isTrue();
+    }
+
+    @Test
+    public void testStartFixedActivityModeForDisplayAndUser_invalidDisplay() {
+        int userId = 10;
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        ActivityOptions options = new ActivityOptions(new Bundle());
+        int invalidDisplayId = Display.DEFAULT_DISPLAY;
+
+        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent, options,
+                invalidDisplayId, userId);
+        assertThat(ret).isFalse();
+    }
+
+    @Test
+    public void testStartFixedActivityModeForDisplayAndUser_notAllowedUser() {
+        int currentUserId = 10;
+        int notAllowedUserId = 11;
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        ActivityOptions options = new ActivityOptions(new Bundle());
+        int displayId = mValidDisplayId;
+        mockAmGetCurrentUser(currentUserId);
+        expectNoProfileUser(currentUserId);
+
+        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent, options,
+                displayId, notAllowedUserId);
+        assertThat(ret).isFalse();
+    }
+
+    @Test
+    public void testStartFixedActivityModeForDisplayAndUser_invalidComponent() throws Exception {
+        int userId = 10;
+        ActivityOptions options = new ActivityOptions(new Bundle());
+        Intent invalidIntent = expectComponentUnavailable("test_package", "com.test.dude", userId);
+        mockAmGetCurrentUser(userId);
+
+        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(invalidIntent,
+                options, mValidDisplayId, userId);
+        assertThat(ret).isFalse();
+    }
+
+    @Test
+    public void testStopFixedActivityMode() throws Exception {
+        int userId = 10;
+        ActivityOptions options = new ActivityOptions(new Bundle());
+        Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
+        mockAmGetCurrentUser(userId);
+        expectNoActivityStack();
+
+        // Start an activity
+        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
+                options, mValidDisplayId, userId);
+        // To check if monitoring is started.
+        verify(mActivityManager).registerTaskStackListener(any(TaskStackListener.class));
+        assertThat(ret).isTrue();
+
+        mFixedActivityService.stopFixedActivityMode(mValidDisplayId);
+        verify(mActivityManager).unregisterTaskStackListener(any(TaskStackListener.class));
+    }
+
+    @Test
+    public void testStopFixedActivityMode_invalidDisplayId() throws Exception {
+        mFixedActivityService.stopFixedActivityMode(Display.DEFAULT_DISPLAY);
+        verify(mActivityManager, never()).unregisterTaskStackListener(any(TaskStackListener.class));
+    }
+
+    private void expectNoProfileUser(@UserIdInt int userId) {
+        when(mUserManager.getEnabledProfileIds(userId)).thenReturn(new int[0]);
+    }
+
+    private Intent expectComponentUnavailable(String pkgName, String className,
+            @UserIdInt int userId) throws Exception {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        ComponentName component = new ComponentName(pkgName, className);
+        intent.setComponent(component);
+        ActivityInfo activityInfo = new ActivityInfo();
+        // To make sure there is no matched activity
+        activityInfo.name = component.getClassName() + ".unavailable";
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.activities = new ActivityInfo[] { activityInfo };
+        when(mPackageManager.getPackageInfoAsUser(component.getPackageName(),
+                PackageManager.GET_ACTIVITIES, userId)).thenReturn(packageInfo);
+        return intent;
+    }
+
+    private Intent expectComponentAvailable(String pkgName, String className, @UserIdInt int userId)
+            throws Exception {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        ComponentName component = new ComponentName(pkgName, className);
+        intent.setComponent(component);
+        ActivityInfo activityInfo = new ActivityInfo();
+        activityInfo.name = component.getClassName();
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.activities = new ActivityInfo[] { activityInfo };
+        when(mPackageManager.getPackageInfoAsUser(component.getPackageName(),
+                PackageManager.GET_ACTIVITIES, userId)).thenReturn(packageInfo);
+        return intent;
+    }
+
+    private void expectNoActivityStack() throws Exception {
+        when(mActivityManager.getAllStackInfos()).thenReturn(createEmptyStackInfo());
+    }
+
+    private void expectActivityStackInfo(List<StackInfo> ...stackInfos) throws Exception {
+        OngoingStubbing<List<StackInfo>> stub = when(mActivityManager.getAllStackInfos());
+        for (List<StackInfo> stackInfo : stackInfos) {
+            stub = stub.thenReturn(stackInfo);
+        }
+    }
+
+    private List<StackInfo> createEmptyStackInfo() {
+        return new ArrayList<StackInfo>();
+    }
+
+    private List<StackInfo> createStackInfo(Intent intent, @UserIdInt int[] userIds, int displayId,
+            int[] taskIds) {
+        StackInfo stackInfo = new StackInfo();
+        stackInfo.taskUserIds = userIds;
+        stackInfo.topActivity = intent.getComponent().clone();
+        stackInfo.visible = true;
+        stackInfo.displayId = displayId;
+        stackInfo.taskIds = taskIds;
+        return Arrays.asList(stackInfo);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioContextTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioContextTest.java
new file mode 100644
index 0000000..e886652
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioContextTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.audio;
+
+import static android.media.AudioAttributes.USAGE_GAME;
+import static android.media.AudioAttributes.USAGE_MEDIA;
+import static android.media.AudioAttributes.USAGE_UNKNOWN;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.media.AudioAttributes.AttributeUsage;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.car.audio.CarAudioContext.AudioContext;
+
+import com.google.common.primitives.Ints;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashSet;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+public class CarAudioContextTest {
+    private static final int INVALID_USAGE = -5;
+    private static final int INVALID_CONTEXT = -5;
+
+    @Test
+    public void getContextForUsage_forValidUsage_returnsContext() {
+        assertThat(CarAudioContext.getContextForUsage(USAGE_MEDIA))
+                .isEqualTo(CarAudioContext.MUSIC);
+    }
+
+    @Test
+    public void getContextForUsage_withInvalidUsage_returnsInvalidContext() {
+        assertThat(CarAudioContext.getContextForUsage(INVALID_USAGE)).isEqualTo(
+                CarAudioContext.INVALID);
+    }
+
+    @Test
+    public void getUsagesForContext_withValidContext_returnsUsages() {
+        int[] usages = CarAudioContext.getUsagesForContext(CarAudioContext.MUSIC);
+        assertThat(usages).asList().containsExactly(USAGE_UNKNOWN, USAGE_GAME, USAGE_MEDIA);
+    }
+
+    @Test
+    public void getUsagesForContext_withInvalidContext_throws() {
+        assertThrows(IllegalArgumentException.class, () -> {
+            CarAudioContext.getUsagesForContext(INVALID_CONTEXT);
+        });
+    }
+
+    @Test
+    public void getUsagesForContext_returnsUniqueValuesForAllContexts() {
+        Set<Integer> allUsages = new HashSet<>();
+        for (@AudioContext int audioContext : CarAudioContext.CONTEXTS) {
+            @AttributeUsage int[] usages = CarAudioContext.getUsagesForContext(audioContext);
+            assertThat(allUsages.addAll(Ints.asList(usages))).isTrue();
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioFocusUnitTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioFocusUnitTest.java
new file mode 100644
index 0000000..1d82004
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioFocusUnitTest.java
@@ -0,0 +1,690 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.audio;
+
+import static android.media.AudioAttributes.USAGE_ANNOUNCEMENT;
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+import static android.media.AudioAttributes.USAGE_ASSISTANT;
+import static android.media.AudioAttributes.USAGE_EMERGENCY;
+import static android.media.AudioAttributes.USAGE_MEDIA;
+import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
+import static android.media.AudioAttributes.USAGE_VEHICLE_STATUS;
+import static android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION;
+import static android.media.AudioManager.AUDIOFOCUS_GAIN;
+import static android.media.AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
+import static android.media.AudioManager.AUDIOFOCUS_LOSS;
+import static android.media.AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
+import static android.media.AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
+import static android.media.AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+import static android.media.AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.pm.PackageManager;
+import android.media.AudioAttributes;
+import android.media.AudioAttributes.AttributeUsage;
+import android.media.AudioFocusInfo;
+import android.media.AudioManager;
+import android.media.audiopolicy.AudioPolicy;
+import android.os.Build;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(AndroidJUnit4.class)
+public class CarAudioFocusUnitTest {
+    private static final int CLIENT_UID = 1;
+    private static final String FIRST_CLIENT_ID = "first-client-id";
+    private static final String SECOND_CLIENT_ID = "second-client-id";
+    private static final String THIRD_CLIENT_ID = "third-client-id";
+    private static final String PACKAGE_NAME = "com.android.car.audio";
+    private static final int AUDIOFOCUS_FLAG = 0;
+
+    @Rule
+    public MockitoRule rule = MockitoJUnit.rule();
+    @Mock
+    private AudioManager mMockAudioManager;
+    @Mock
+    private PackageManager mMockPackageManager;
+    @Mock
+    private AudioPolicy mAudioPolicy;
+    @Mock
+    private CarAudioSettings mCarAudioSettings;
+
+    private FocusInteraction mFocusInteraction;
+
+
+    @Before
+    public void setUp() {
+        mFocusInteraction = new FocusInteraction(mCarAudioSettings);
+    }
+
+    @Test
+    public void onAudioFocusRequest_withNoCurrentFocusHolder_requestGranted() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(false);
+        AudioFocusInfo audioFocusInfo = getInfoForFirstClientWithMedia();
+        carAudioFocus.onAudioFocusRequest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager).setFocusRequestResult(audioFocusInfo,
+                AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocusRequest_withSameClientIdSameUsage_requestGranted() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(false);
+        AudioFocusInfo audioFocusInfo = getInfoForFirstClientWithMedia();
+        carAudioFocus.onAudioFocusRequest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        AudioFocusInfo sameClientAndUsageFocusInfo = getInfoForFirstClientWithMedia();
+        carAudioFocus.onAudioFocusRequest(sameClientAndUsageFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(2)).setFocusRequestResult(sameClientAndUsageFocusInfo,
+                AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocusRequest_withSameClientIdDifferentUsage_requestFailed() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(false);
+        requestFocusForMediaWithFirstClient(carAudioFocus);
+
+        AudioFocusInfo sameClientFocusInfo = getInfo(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+                FIRST_CLIENT_ID, AUDIOFOCUS_GAIN, false);
+        carAudioFocus.onAudioFocusRequest(sameClientFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager).setFocusRequestResult(sameClientFocusInfo,
+                AUDIOFOCUS_REQUEST_FAILED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocusRequest_concurrentRequest_requestGranted() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(false);
+        requestFocusForMediaWithFirstClient(carAudioFocus);
+
+        AudioFocusInfo concurrentFocusInfo = getConcurrentInfo(AUDIOFOCUS_GAIN);
+        carAudioFocus.onAudioFocusRequest(concurrentFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager).setFocusRequestResult(concurrentFocusInfo,
+                AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocusRequest_concurrentRequestWithoutDucking_holderLosesFocus() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(false);
+        AudioFocusInfo initialFocusInfo = requestFocusForMediaWithFirstClient(carAudioFocus);
+
+        AudioFocusInfo concurrentFocusInfo = getConcurrentInfo(AUDIOFOCUS_GAIN);
+        carAudioFocus.onAudioFocusRequest(concurrentFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager).dispatchAudioFocusChange(initialFocusInfo,
+                AudioManager.AUDIOFOCUS_LOSS, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocusRequest_concurrentRequestMayDuck_holderRetainsFocus() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(false);
+        AudioFocusInfo initialFocusInfo = requestFocusForMediaWithFirstClient(carAudioFocus);
+
+        AudioFocusInfo concurrentFocusInfo = getConcurrentInfo(AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
+        carAudioFocus.onAudioFocusRequest(concurrentFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(0)).dispatchAudioFocusChange(eq(initialFocusInfo),
+                anyInt(), eq(mAudioPolicy));
+    }
+
+    @Test
+    public void onAudioFocusRequest_exclusiveRequest_requestGranted() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(false);
+        requestFocusForMediaWithFirstClient(carAudioFocus);
+
+        AudioFocusInfo exclusiveRequestInfo = getExclusiveInfo(AUDIOFOCUS_GAIN);
+        carAudioFocus.onAudioFocusRequest(exclusiveRequestInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager).setFocusRequestResult(exclusiveRequestInfo,
+                AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocusRequest_exclusiveRequest_holderLosesFocus() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(false);
+        AudioFocusInfo initialFocusInfo = requestFocusForMediaWithFirstClient(carAudioFocus);
+
+        AudioFocusInfo exclusiveRequestInfo = getExclusiveInfo(AUDIOFOCUS_GAIN);
+        carAudioFocus.onAudioFocusRequest(exclusiveRequestInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager).dispatchAudioFocusChange(initialFocusInfo,
+                AudioManager.AUDIOFOCUS_LOSS, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocusRequest_exclusiveRequestMayDuck_holderLosesFocusTransiently() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(false);
+        AudioFocusInfo initialFocusInfo = requestFocusForMediaWithFirstClient(carAudioFocus);
+
+        AudioFocusInfo exclusiveRequestInfo = getExclusiveInfo(AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
+        carAudioFocus.onAudioFocusRequest(exclusiveRequestInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager).dispatchAudioFocusChange(initialFocusInfo,
+                AudioManager.AUDIOFOCUS_LOSS_TRANSIENT, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocus_rejectRequest_requestFailed() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(false);
+        requestFocusForUsageWithFirstClient(USAGE_ASSISTANT, carAudioFocus);
+
+        AudioFocusInfo rejectRequestInfo = getRejectInfo();
+        carAudioFocus.onAudioFocusRequest(rejectRequestInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager).setFocusRequestResult(rejectRequestInfo,
+                AUDIOFOCUS_REQUEST_FAILED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocus_rejectRequest_holderRetainsFocus() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(false);
+        AudioFocusInfo initialFocusInfo = requestFocusForUsageWithFirstClient(USAGE_ASSISTANT,
+                carAudioFocus);
+
+        AudioFocusInfo rejectRequestInfo = getRejectInfo();
+        carAudioFocus.onAudioFocusRequest(rejectRequestInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(0)).dispatchAudioFocusChange(eq(initialFocusInfo),
+                anyInt(), eq(mAudioPolicy));
+    }
+
+    // System Usage tests
+
+    @Test
+    public void onAudioFocus_exclusiveWithSystemUsage_requestGranted() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(false);
+        requestFocusForMediaWithFirstClient(carAudioFocus);
+
+        AudioFocusInfo exclusiveSystemUsageInfo = getExclusiveWithSystemUsageInfo();
+        carAudioFocus.onAudioFocusRequest(exclusiveSystemUsageInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager).setFocusRequestResult(exclusiveSystemUsageInfo,
+                AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocus_exclusiveWithSystemUsage_holderLosesFocus() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(false);
+        AudioFocusInfo initialFocusInfo = requestFocusForMediaWithFirstClient(carAudioFocus);
+
+        AudioFocusInfo exclusiveSystemUsageInfo = getExclusiveWithSystemUsageInfo();
+        carAudioFocus.onAudioFocusRequest(exclusiveSystemUsageInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager).dispatchAudioFocusChange(initialFocusInfo,
+                AUDIOFOCUS_LOSS, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocus_concurrentWithSystemUsage_requestGranted() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(false);
+        requestFocusForMediaWithFirstClient(carAudioFocus);
+
+        AudioFocusInfo concurrentSystemUsageInfo = getConcurrentWithSystemUsageInfo();
+        carAudioFocus.onAudioFocusRequest(concurrentSystemUsageInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager).setFocusRequestResult(concurrentSystemUsageInfo,
+                AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocus_concurrentWithSystemUsageAndConcurrent_holderRetainsFocus() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(false);
+        AudioFocusInfo initialFocusInfo = requestFocusForMediaWithFirstClient(carAudioFocus);
+
+        AudioFocusInfo concurrentSystemUsageInfo = getConcurrentWithSystemUsageInfo();
+        carAudioFocus.onAudioFocusRequest(concurrentSystemUsageInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(0)).dispatchAudioFocusChange(eq(initialFocusInfo),
+                anyInt(), eq(mAudioPolicy));
+    }
+
+    @Test
+    public void onAudioFocus_rejectWithSystemUsage_requestFailed() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(false);
+        requestFocusForUsageWithFirstClient(USAGE_VOICE_COMMUNICATION, carAudioFocus);
+
+        AudioFocusInfo rejectWithSystemUsageInfo = getRejectWithSystemUsageInfo();
+        carAudioFocus.onAudioFocusRequest(rejectWithSystemUsageInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager).setFocusRequestResult(rejectWithSystemUsageInfo,
+                AUDIOFOCUS_REQUEST_FAILED, mAudioPolicy);
+    }
+
+    // Delayed Focus tests
+    @Test
+    public void onAudioFocus_requestWithDelayedFocus_requestGranted() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(true);
+
+        AudioFocusInfo delayedFocusInfo = getDelayedExclusiveInfo(AUDIOFOCUS_GAIN);
+        carAudioFocus.onAudioFocusRequest(delayedFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager)
+                .setFocusRequestResult(delayedFocusInfo,
+                        AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocus_delayedRequestAbandonedBeforeGettingFocus_abandonSucceeds() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(true);
+
+        AudioFocusInfo callFocusInfo = setupFocusInfoAndRequestFocusForCall(carAudioFocus);
+
+        AudioFocusInfo delayedFocusInfo = getDelayedExclusiveInfo(AUDIOFOCUS_GAIN);
+        carAudioFocus.onAudioFocusRequest(delayedFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        carAudioFocus.onAudioFocusAbandon(delayedFocusInfo);
+
+        verify(mMockAudioManager, never()).dispatchAudioFocusChange(
+                delayedFocusInfo, AUDIOFOCUS_LOSS, mAudioPolicy);
+
+        carAudioFocus.onAudioFocusAbandon(callFocusInfo);
+
+        verify(mMockAudioManager, never()).dispatchAudioFocusChange(
+                delayedFocusInfo, AUDIOFOCUS_GAIN, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocus_forRequestDelayed_requestDelayed() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(true);
+
+        setupFocusInfoAndRequestFocusForCall(carAudioFocus);
+
+        AudioFocusInfo delayedFocusInfo = getDelayedExclusiveInfo(AUDIOFOCUS_GAIN);
+        carAudioFocus.onAudioFocusRequest(delayedFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager)
+                .setFocusRequestResult(delayedFocusInfo,
+                        AUDIOFOCUS_REQUEST_DELAYED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocus_forRequestDelayed_delayedFocusGained() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(true);
+
+        AudioFocusInfo callFocusInfo = setupFocusInfoAndRequestFocusForCall(carAudioFocus);
+
+        AudioFocusInfo delayedFocusInfo = getDelayedExclusiveInfo(AUDIOFOCUS_GAIN);
+        carAudioFocus.onAudioFocusRequest(delayedFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager)
+                .setFocusRequestResult(delayedFocusInfo,
+                        AUDIOFOCUS_REQUEST_DELAYED, mAudioPolicy);
+
+        carAudioFocus.onAudioFocusAbandon(callFocusInfo);
+
+        verify(mMockAudioManager)
+                .dispatchAudioFocusChange(delayedFocusInfo, AUDIOFOCUS_GAIN, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocus_multipleRequestWithDelayedFocus_requestsDelayed() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(true);
+
+        AudioFocusInfo callFocusInfo = setupFocusInfoAndRequestFocusForCall(carAudioFocus);
+
+        AudioFocusInfo firstRequestWithDelayedFocus = getInfo(USAGE_MEDIA, SECOND_CLIENT_ID,
+                AUDIOFOCUS_GAIN, true);
+        carAudioFocus.onAudioFocusRequest(firstRequestWithDelayedFocus, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager)
+                .setFocusRequestResult(firstRequestWithDelayedFocus,
+                        AUDIOFOCUS_REQUEST_DELAYED, mAudioPolicy);
+
+        AudioFocusInfo secondRequestWithDelayedFocus = getInfo(USAGE_MEDIA, THIRD_CLIENT_ID,
+                AUDIOFOCUS_GAIN, true);
+        carAudioFocus.onAudioFocusRequest(secondRequestWithDelayedFocus,
+                AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager)
+                .setFocusRequestResult(secondRequestWithDelayedFocus,
+                        AUDIOFOCUS_REQUEST_DELAYED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocus_multipleRequestWithDelayedFocus_firstRequestReceivesFocusLoss() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(true);
+
+        AudioFocusInfo callFocusInfo = setupFocusInfoAndRequestFocusForCall(carAudioFocus);
+
+        AudioFocusInfo firstRequestWithDelayedFocus = getInfo(USAGE_MEDIA, SECOND_CLIENT_ID,
+                AUDIOFOCUS_GAIN, true);
+        carAudioFocus.onAudioFocusRequest(firstRequestWithDelayedFocus, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager)
+                .setFocusRequestResult(firstRequestWithDelayedFocus,
+                        AUDIOFOCUS_REQUEST_DELAYED, mAudioPolicy);
+
+        AudioFocusInfo secondRequestWithDelayedFocus = getInfo(USAGE_MEDIA, THIRD_CLIENT_ID,
+                AUDIOFOCUS_GAIN, true);
+
+        carAudioFocus.onAudioFocusRequest(secondRequestWithDelayedFocus,
+                AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager).dispatchAudioFocusChange(
+                firstRequestWithDelayedFocus, AUDIOFOCUS_LOSS, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocus_multipleRequestOnlyOneWithDelayedFocus_delayedFocusNotChanged() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(true);
+
+        AudioFocusInfo callFocusInfo = setupFocusInfoAndRequestFocusForCall(carAudioFocus);
+
+        AudioFocusInfo firstRequestWithDelayedFocus = getInfo(USAGE_MEDIA, SECOND_CLIENT_ID,
+                AUDIOFOCUS_GAIN, true);
+        carAudioFocus.onAudioFocusRequest(firstRequestWithDelayedFocus, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager)
+                .setFocusRequestResult(firstRequestWithDelayedFocus,
+                        AUDIOFOCUS_REQUEST_DELAYED, mAudioPolicy);
+
+        AudioFocusInfo secondRequestWithNoDelayedFocus = getInfo(USAGE_MEDIA, THIRD_CLIENT_ID,
+                AUDIOFOCUS_GAIN, false);
+
+        carAudioFocus.onAudioFocusRequest(secondRequestWithNoDelayedFocus,
+                AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager)
+                .setFocusRequestResult(secondRequestWithNoDelayedFocus,
+                        AUDIOFOCUS_REQUEST_FAILED, mAudioPolicy);
+
+        verify(mMockAudioManager, never()).dispatchAudioFocusChange(
+                firstRequestWithDelayedFocus, AUDIOFOCUS_LOSS, mAudioPolicy);
+    }
+
+    @Test
+    public void
+            onAudioFocus_multipleRequestOnlyOneWithDelayedFocus_nonTransientRequestReceivesLoss() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(true);
+
+        AudioFocusInfo mediaRequestWithOutDelayedFocus = getInfo(USAGE_MEDIA, SECOND_CLIENT_ID,
+                AUDIOFOCUS_GAIN, false);
+        carAudioFocus.onAudioFocusRequest(mediaRequestWithOutDelayedFocus,
+                AUDIOFOCUS_REQUEST_GRANTED);
+
+        AudioFocusInfo callFocusInfo = setupFocusInfoAndRequestFocusForCall(carAudioFocus);
+
+        AudioFocusInfo mediaRequestWithDelayedFocus = getInfo(USAGE_MEDIA, THIRD_CLIENT_ID,
+                AUDIOFOCUS_GAIN, true);
+
+        carAudioFocus.onAudioFocusRequest(mediaRequestWithDelayedFocus,
+                AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager)
+                .setFocusRequestResult(mediaRequestWithDelayedFocus,
+                        AUDIOFOCUS_REQUEST_DELAYED, mAudioPolicy);
+
+        verify(mMockAudioManager).dispatchAudioFocusChange(
+                mediaRequestWithOutDelayedFocus, AUDIOFOCUS_LOSS, mAudioPolicy);
+    }
+
+    @Test
+    public void
+            onAudioFocus_multipleRequestOnlyOneWithDelayedFocus_duckedRequestReceivesLoss() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(true);
+
+        AudioFocusInfo navRequestWithOutDelayedFocus =
+                getInfo(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, SECOND_CLIENT_ID,
+                        AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, false);
+        carAudioFocus.onAudioFocusRequest(navRequestWithOutDelayedFocus,
+                AUDIOFOCUS_REQUEST_GRANTED);
+
+        AudioFocusInfo callFocusInfo = setupFocusInfoAndRequestFocusForCall(carAudioFocus);
+
+        verify(mMockAudioManager).dispatchAudioFocusChange(
+                navRequestWithOutDelayedFocus, AUDIOFOCUS_LOSS_TRANSIENT, mAudioPolicy);
+
+        AudioFocusInfo mediaRequestWithDelayedFocus = getInfo(USAGE_MEDIA, THIRD_CLIENT_ID,
+                AUDIOFOCUS_GAIN, true);
+
+        carAudioFocus.onAudioFocusRequest(mediaRequestWithDelayedFocus,
+                AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager).dispatchAudioFocusChange(
+                navRequestWithOutDelayedFocus, AUDIOFOCUS_LOSS, mAudioPolicy);
+    }
+
+    @Test
+    public void
+            onAudioFocus_concurrentRequestAfterDelayedFocus_concurrentFocusGranted() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(true);
+
+        AudioFocusInfo callFocusInfo = setupFocusInfoAndRequestFocusForCall(carAudioFocus);
+
+        AudioFocusInfo delayedFocusRequest = getInfo(USAGE_MEDIA, SECOND_CLIENT_ID,
+                AUDIOFOCUS_GAIN, true);
+
+        carAudioFocus.onAudioFocusRequest(delayedFocusRequest,
+                AUDIOFOCUS_REQUEST_GRANTED);
+
+        AudioFocusInfo mapFocusInfo = getInfo(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, THIRD_CLIENT_ID,
+                AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, false);
+        carAudioFocus.onAudioFocusRequest(mapFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager)
+                .setFocusRequestResult(mapFocusInfo,
+                        AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+    }
+
+    @Test
+    public void
+            onAudioFocus_concurrentRequestsAndAbandonsAfterDelayedFocus_noDelayedFocusChange() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(true);
+
+        AudioFocusInfo callFocusInfo = setupFocusInfoAndRequestFocusForCall(carAudioFocus);
+
+        AudioFocusInfo delayedFocusRequest = getInfo(USAGE_MEDIA, SECOND_CLIENT_ID,
+                AUDIOFOCUS_GAIN, true);
+
+        carAudioFocus.onAudioFocusRequest(delayedFocusRequest,
+                AUDIOFOCUS_REQUEST_GRANTED);
+
+        AudioFocusInfo mapFocusInfo = getInfo(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, THIRD_CLIENT_ID,
+                AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, false);
+        carAudioFocus.onAudioFocusRequest(mapFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        carAudioFocus.onAudioFocusAbandon(mapFocusInfo);
+
+        verify(mMockAudioManager, never()).dispatchAudioFocusChange(
+                delayedFocusRequest, AUDIOFOCUS_LOSS, mAudioPolicy);
+
+        verify(mMockAudioManager, never()).dispatchAudioFocusChange(
+                delayedFocusRequest, AUDIOFOCUS_GAIN, mAudioPolicy);
+    }
+
+    @Test
+    public void
+            onAudioFocus_concurrentRequestAfterDelayedFocus_delayedGainesFocus() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(true);
+
+        AudioFocusInfo callFocusInfo = setupFocusInfoAndRequestFocusForCall(carAudioFocus);
+
+        AudioFocusInfo delayedFocusRequest = getInfo(USAGE_MEDIA, SECOND_CLIENT_ID,
+                AUDIOFOCUS_GAIN, true);
+
+        carAudioFocus.onAudioFocusRequest(delayedFocusRequest,
+                AUDIOFOCUS_REQUEST_GRANTED);
+
+        AudioFocusInfo mapFocusInfo = getInfo(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, THIRD_CLIENT_ID,
+                AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, false);
+        carAudioFocus.onAudioFocusRequest(mapFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        carAudioFocus.onAudioFocusAbandon(mapFocusInfo);
+
+        carAudioFocus.onAudioFocusAbandon(callFocusInfo);
+
+        verify(mMockAudioManager).dispatchAudioFocusChange(
+                delayedFocusRequest, AUDIOFOCUS_GAIN, mAudioPolicy);
+    }
+
+    @Test
+    public void
+            onAudioFocus_delayedFocusRequestAfterDoubleReject_delayedGainesFocus() {
+        CarAudioFocus carAudioFocus = getCarAudioFocus(true);
+
+        AudioFocusInfo callRingFocusInfo = getInfo(USAGE_NOTIFICATION_RINGTONE, FIRST_CLIENT_ID,
+                AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, false);
+        carAudioFocus.onAudioFocusRequest(callRingFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+        verify(mMockAudioManager)
+                .setFocusRequestResult(callRingFocusInfo,
+                        AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+
+        AudioAttributes audioAttributes = new AudioAttributes.Builder()
+                .setSystemUsage(USAGE_EMERGENCY)
+                .build();
+        AudioFocusInfo emergencyFocusInfo = getInfo(audioAttributes, SECOND_CLIENT_ID,
+                AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, false);
+        carAudioFocus.onAudioFocusRequest(emergencyFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+        verify(mMockAudioManager)
+                .setFocusRequestResult(emergencyFocusInfo,
+                        AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+
+        verify(mMockAudioManager).dispatchAudioFocusChange(
+                callRingFocusInfo, AUDIOFOCUS_LOSS_TRANSIENT, mAudioPolicy);
+
+        AudioFocusInfo delayedFocusRequest = getInfo(USAGE_MEDIA, THIRD_CLIENT_ID,
+                AUDIOFOCUS_GAIN, true);
+
+        carAudioFocus.onAudioFocusRequest(delayedFocusRequest,
+                AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager)
+                .setFocusRequestResult(delayedFocusRequest,
+                        AUDIOFOCUS_REQUEST_DELAYED, mAudioPolicy);
+
+        carAudioFocus.onAudioFocusAbandon(emergencyFocusInfo);
+
+        verify(mMockAudioManager, never()).dispatchAudioFocusChange(
+                delayedFocusRequest, AUDIOFOCUS_GAIN, mAudioPolicy);
+
+        verify(mMockAudioManager).dispatchAudioFocusChange(
+                callRingFocusInfo, AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, mAudioPolicy);
+
+        carAudioFocus.onAudioFocusAbandon(callRingFocusInfo);
+
+        verify(mMockAudioManager).dispatchAudioFocusChange(
+                delayedFocusRequest, AUDIOFOCUS_GAIN, mAudioPolicy);
+
+    }
+
+    private AudioFocusInfo setupFocusInfoAndRequestFocusForCall(CarAudioFocus carAudioFocus) {
+        AudioFocusInfo callFocusInfo = getInfo(USAGE_VOICE_COMMUNICATION, FIRST_CLIENT_ID,
+                AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, false);
+        carAudioFocus.onAudioFocusRequest(callFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+        verify(mMockAudioManager)
+                .setFocusRequestResult(callFocusInfo,
+                        AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+        return callFocusInfo;
+    }
+
+    // USAGE_ASSISTANCE_NAVIGATION_GUIDANCE is concurrent with USAGE_MEDIA
+    private AudioFocusInfo getConcurrentInfo(int gainType) {
+        return getInfo(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, SECOND_CLIENT_ID, gainType,
+                false);
+    }
+
+    // USAGE_VEHICLE_STATUS is concurrent with USAGE_MEDIA
+    private AudioFocusInfo getConcurrentWithSystemUsageInfo() {
+        return getSystemUsageInfo(USAGE_VEHICLE_STATUS, AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
+    }
+
+    // USAGE_MEDIA is exclusive with USAGE_MEDIA
+    private AudioFocusInfo getExclusiveInfo(int gainType) {
+        return getInfo(USAGE_MEDIA, SECOND_CLIENT_ID, gainType, false);
+    }
+
+    // USAGE_MEDIA is exclusive with USAGE_MEDIA
+    private AudioFocusInfo getDelayedExclusiveInfo(int gainType) {
+        return getInfo(USAGE_MEDIA, SECOND_CLIENT_ID, gainType, true);
+    }
+
+    // USAGE_EMERGENCY is exclusive with USAGE_MEDIA
+    private AudioFocusInfo getExclusiveWithSystemUsageInfo() {
+        return getSystemUsageInfo(USAGE_EMERGENCY, AUDIOFOCUS_GAIN);
+    }
+
+    // USAGE_ASSISTANCE_NAVIGATION_GUIDANCE is rejected with USAGE_ASSISTANT
+    private AudioFocusInfo getRejectInfo() {
+        return getInfo(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, SECOND_CLIENT_ID,
+                AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, false);
+    }
+
+    // USAGE_ANNOUNCEMENT is rejected with USAGE_VOICE_COMMUNICATION
+    private AudioFocusInfo getRejectWithSystemUsageInfo() {
+        return getSystemUsageInfo(USAGE_ANNOUNCEMENT, AUDIOFOCUS_GAIN);
+    }
+
+    private AudioFocusInfo requestFocusForUsageWithFirstClient(@AttributeUsage int usage,
+            CarAudioFocus carAudioFocus) {
+        AudioFocusInfo initialFocusInfo = getInfo(usage, FIRST_CLIENT_ID, AUDIOFOCUS_GAIN,
+                false);
+        carAudioFocus.onAudioFocusRequest(initialFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+        return initialFocusInfo;
+    }
+
+    private AudioFocusInfo requestFocusForMediaWithFirstClient(CarAudioFocus carAudioFocus) {
+        return requestFocusForUsageWithFirstClient(USAGE_MEDIA, carAudioFocus);
+    }
+
+    private AudioFocusInfo getInfoForFirstClientWithMedia() {
+        return getInfo(USAGE_MEDIA, FIRST_CLIENT_ID, AUDIOFOCUS_GAIN, false);
+    }
+
+    private AudioFocusInfo getInfo(@AttributeUsage int usage, String clientId, int gainType,
+            boolean acceptsDelayedFocus) {
+        AudioAttributes audioAttributes = new AudioAttributes.Builder()
+                .setUsage(usage)
+                .build();
+        return getInfo(audioAttributes, clientId, gainType, acceptsDelayedFocus);
+    }
+
+    private AudioFocusInfo getSystemUsageInfo(@AttributeUsage int systemUsage, int gainType) {
+        AudioAttributes audioAttributes = new AudioAttributes.Builder()
+                .setSystemUsage(systemUsage)
+                .build();
+        return getInfo(audioAttributes, SECOND_CLIENT_ID, gainType, false);
+    }
+
+    private AudioFocusInfo getInfo(AudioAttributes audioAttributes, String clientId, int gainType,
+            boolean acceptsDelayedFocus) {
+        int flags =  acceptsDelayedFocus ? AudioManager.AUDIOFOCUS_FLAG_DELAY_OK : AUDIOFOCUS_FLAG;
+        return new AudioFocusInfo(audioAttributes, CLIENT_UID, clientId, PACKAGE_NAME,
+                gainType, AudioManager.AUDIOFOCUS_NONE,
+                flags, Build.VERSION.SDK_INT);
+    }
+
+    private CarAudioFocus getCarAudioFocus(boolean enableDelayAudioFocus) {
+        CarAudioFocus carAudioFocus = new CarAudioFocus(mMockAudioManager, mMockPackageManager,
+                mFocusInteraction, enableDelayAudioFocus);
+        carAudioFocus.setOwningPolicy(mAudioPolicy);
+        return carAudioFocus;
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioSettingsUnitTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioSettingsUnitTest.java
new file mode 100644
index 0000000..cf1b7fd
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioSettingsUnitTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.audio;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.media.CarAudioManager;
+import android.car.settings.CarSettings;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.content.ContentResolver;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+@RunWith(AndroidJUnit4.class)
+public class CarAudioSettingsUnitTest extends AbstractExtendedMockitoTestCase {
+
+    private static final int TEST_USER_ID_1 = 11;
+    private static final int TEST_ZONE_ID = CarAudioManager.PRIMARY_AUDIO_ZONE;
+    private static final int TEST_GROUP_ID = 0;
+    private static final int TEST_GAIN_INDEX = 10;
+    private static final String TEST_GAIN_INDEX_KEY = "android.car.VOLUME_GROUP/0";
+
+
+    @Mock
+    private ContentResolver mMockContentResolver;
+
+    private CarAudioSettings mCarAudioSettings;
+
+    @Before
+    public void setUp() {
+        mCarAudioSettings = new CarAudioSettings(mMockContentResolver);
+    }
+
+    @Test
+    public void isRejectNavigationOnCallEnabledInSettings_whenSetToNotToReject_returnsFalse() {
+        setRejectNavigationOnCallSettingsValues(0);
+        assertThat(
+                mCarAudioSettings.isRejectNavigationOnCallEnabledInSettings(TEST_USER_ID_1))
+                .isFalse();
+    }
+
+    @Test
+    public void isRejectNavigationOnCallEnabledInSettings_whenSetToToReject_returnsTrue() {
+        setRejectNavigationOnCallSettingsValues(1);
+        assertThat(
+                mCarAudioSettings.isRejectNavigationOnCallEnabledInSettings(TEST_USER_ID_1))
+                .isTrue();
+    }
+
+    @Test
+    public void getStoredVolumeGainIndexForUser_returnsSavedValue() {
+        setStoredVolumeGainIndexForUser(TEST_GAIN_INDEX);
+
+        assertThat(mCarAudioSettings.getStoredVolumeGainIndexForUser(TEST_USER_ID_1, TEST_ZONE_ID,
+                        TEST_GROUP_ID)).isEqualTo(TEST_GAIN_INDEX);
+    }
+
+    @Test
+    public void storedVolumeGainIndexForUser_savesValue() {
+        mCarAudioSettings.storeVolumeGainIndexForUser(TEST_USER_ID_1, TEST_ZONE_ID,
+                TEST_GROUP_ID, TEST_GAIN_INDEX);
+        assertThat(getSettingsInt(TEST_GAIN_INDEX_KEY)).isEqualTo(TEST_GAIN_INDEX);
+    }
+
+    private void setStoredVolumeGainIndexForUser(int gainIndexForUser) {
+        putSettingsInt(TEST_GAIN_INDEX_KEY, gainIndexForUser);
+    }
+
+    private void setRejectNavigationOnCallSettingsValues(int settingsValue) {
+        putSettingsInt(CarSettings.Secure.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL,
+                settingsValue);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeCallbackHandlerTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeCallbackHandlerTest.java
new file mode 100644
index 0000000..54436af
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeCallbackHandlerTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.audio;
+
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.car.media.ICarVolumeCallback;
+import android.os.RemoteException;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class CarVolumeCallbackHandlerTest {
+    private static final int ZONE_ID = 2;
+    private static final int GROUP_ID = 5;
+    private static final int FLAGS = 0;
+
+    private CarVolumeCallbackHandler mHandler;
+    private TestCarVolumeCallback mCallback1;
+    private TestCarVolumeCallback mCallback2;
+
+    @Before
+    public void setUp() {
+        mHandler = new CarVolumeCallbackHandler();
+        mCallback1 = new TestCarVolumeCallback(spy(ICarVolumeCallback.class));
+        mHandler.registerCallback(mCallback1.asBinder());
+        mCallback2 = new TestCarVolumeCallback(spy(ICarVolumeCallback.class));
+        mHandler.registerCallback(mCallback2.asBinder());
+    }
+
+    @After
+    public void tearDown() {
+        mHandler.unregisterCallback(mCallback1.asBinder());
+        mHandler.unregisterCallback(mCallback2.asBinder());
+    }
+
+    @Test
+    public void onVolumeGroupChange_callsAllRegisteredCallbacks() throws RemoteException {
+        mHandler.onVolumeGroupChange(ZONE_ID, GROUP_ID, FLAGS);
+
+        verify(mCallback1.getSpy()).onGroupVolumeChanged(ZONE_ID, GROUP_ID, FLAGS);
+        verify(mCallback2.getSpy()).onGroupVolumeChanged(ZONE_ID, GROUP_ID, FLAGS);
+    }
+
+    @Test
+    public void onVolumeGroupChange_doesntCallUnregisteredCallbacks() throws RemoteException {
+        mHandler.unregisterCallback(mCallback1.asBinder());
+        mHandler.onVolumeGroupChange(ZONE_ID, GROUP_ID, FLAGS);
+
+        verify(mCallback1.getSpy(), never()).onGroupVolumeChanged(ZONE_ID, GROUP_ID, FLAGS);
+        verify(mCallback2.getSpy()).onGroupVolumeChanged(ZONE_ID, GROUP_ID, FLAGS);
+    }
+
+    @Test
+    public void onMasterMuteChanged_callsAllRegisteredCallbacks() throws RemoteException {
+        mHandler.onMasterMuteChanged(ZONE_ID, FLAGS);
+
+        verify(mCallback1.getSpy()).onMasterMuteChanged(ZONE_ID, FLAGS);
+        verify(mCallback2.getSpy()).onMasterMuteChanged(ZONE_ID, FLAGS);
+    }
+
+    // Because the binder logic uses transact, spying on the object directly doesn't work. So
+    // instead we pass a mSpy in and have the Test wrapper call it so we can test the behavior
+    private class TestCarVolumeCallback extends ICarVolumeCallback.Stub {
+        private final ICarVolumeCallback mSpy;
+
+        TestCarVolumeCallback(ICarVolumeCallback spy) {
+            this.mSpy = spy;
+        }
+
+        public ICarVolumeCallback getSpy() {
+            return mSpy;
+        }
+
+        @Override
+        public void onGroupVolumeChanged(int zoneId, int groupId, int flags)
+                throws RemoteException {
+            mSpy.onGroupVolumeChanged(zoneId, groupId, flags);
+        }
+
+        @Override
+        public void onMasterMuteChanged(int zoneId, int flags) throws RemoteException {
+            mSpy.onMasterMuteChanged(zoneId, flags);
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeTest.java
new file mode 100644
index 0000000..06d2299
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeTest.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.audio;
+
+import static android.media.AudioAttributes.USAGE_ALARM;
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+import static android.media.AudioAttributes.USAGE_MEDIA;
+import static android.media.AudioAttributes.USAGE_NOTIFICATION;
+import static android.media.AudioAttributes.USAGE_VIRTUAL_SOURCE;
+import static android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION;
+import static android.telephony.TelephonyManager.CALL_STATE_IDLE;
+import static android.telephony.TelephonyManager.CALL_STATE_OFFHOOK;
+import static android.telephony.TelephonyManager.CALL_STATE_RINGING;
+
+import static com.android.car.audio.CarAudioContext.ALARM;
+import static com.android.car.audio.CarAudioContext.CALL;
+import static com.android.car.audio.CarAudioContext.CALL_RING;
+import static com.android.car.audio.CarAudioContext.NAVIGATION;
+import static com.android.car.audio.CarAudioService.DEFAULT_AUDIO_CONTEXT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.media.AudioAttributes;
+import android.media.AudioAttributes.AttributeUsage;
+import android.media.AudioPlaybackConfiguration;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.car.audio.CarAudioContext.AudioContext;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class CarVolumeTest {
+    @Test
+    public void getSuggestedAudioContext_withNoConfigurationsAndIdleTelephony_returnsDefault() {
+        @AudioContext int suggestedContext = CarVolume.getSuggestedAudioContext(new ArrayList<>(),
+                CALL_STATE_IDLE);
+
+        assertThat(suggestedContext).isEqualTo(CarAudioService.DEFAULT_AUDIO_CONTEXT);
+    }
+
+    @Test
+    public void getSuggestedAudioContext_withOneConfiguration_returnsAssociatedContext() {
+        List<AudioPlaybackConfiguration> configurations = ImmutableList.of(
+                new Builder().setUsage(USAGE_ALARM).build()
+        );
+
+        @AudioContext int suggestedContext = CarVolume.getSuggestedAudioContext(configurations,
+                CALL_STATE_IDLE);
+
+        assertThat(suggestedContext).isEqualTo(ALARM);
+    }
+
+    @Test
+    public void getSuggestedAudioContext_withCallStateOffHook_returnsCallContext() {
+        @AudioContext int suggestedContext = CarVolume.getSuggestedAudioContext(new ArrayList<>(),
+                CALL_STATE_OFFHOOK);
+
+        assertThat(suggestedContext).isEqualTo(CALL);
+    }
+
+    @Test
+    public void getSuggestedAudioContext_withCallStateRinging_returnsCallRingContext() {
+        @AudioContext int suggestedContext = CarVolume.getSuggestedAudioContext(new ArrayList<>(),
+                CALL_STATE_RINGING);
+
+        assertThat(suggestedContext).isEqualTo(CALL_RING);
+    }
+
+    @Test
+    public void getSuggestedAudioContext_withConfigurations_returnsHighestPriorityContext() {
+        List<AudioPlaybackConfiguration> configurations = ImmutableList.of(
+                new Builder().setUsage(USAGE_ALARM).build(),
+                new Builder().setUsage(USAGE_VOICE_COMMUNICATION).build(),
+                new Builder().setUsage(USAGE_NOTIFICATION).build()
+        );
+
+        @AudioContext int suggestedContext = CarVolume.getSuggestedAudioContext(configurations,
+                CALL_STATE_IDLE);
+
+        assertThat(suggestedContext).isEqualTo(CALL);
+    }
+
+    @Test
+    public void getSuggestedAudioContext_ignoresInactiveConfigurations() {
+        List<AudioPlaybackConfiguration> configurations = ImmutableList.of(
+                new Builder().setUsage(USAGE_ALARM).build(),
+                new Builder().setUsage(USAGE_VOICE_COMMUNICATION).setInactive().build(),
+                new Builder().setUsage(USAGE_NOTIFICATION).build()
+        );
+
+        @AudioContext int suggestedContext = CarVolume.getSuggestedAudioContext(configurations,
+                CALL_STATE_IDLE);
+
+        assertThat(suggestedContext).isEqualTo(ALARM);
+    }
+
+    @Test
+    public void getSuggestedAudioContext_withLowerPriorityConfigurationsAndCall_returnsCall() {
+        List<AudioPlaybackConfiguration> configurations = ImmutableList.of(
+                new Builder().setUsage(USAGE_ALARM).build(),
+                new Builder().setUsage(USAGE_NOTIFICATION).build()
+        );
+
+        @AudioContext int suggestedContext = CarVolume.getSuggestedAudioContext(configurations,
+                CALL_STATE_OFFHOOK);
+
+        assertThat(suggestedContext).isEqualTo(CALL);
+    }
+
+    @Test
+    public void getSuggestedAudioContext_withNavigationConfigurationAndCall_returnsNavigation() {
+        List<AudioPlaybackConfiguration> configurations = ImmutableList.of(
+                new Builder().setUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE).build()
+        );
+
+        @AudioContext int suggestedContext = CarVolume.getSuggestedAudioContext(configurations,
+                CALL_STATE_OFFHOOK);
+
+        assertThat(suggestedContext).isEqualTo(NAVIGATION);
+    }
+
+    @Test
+    public void getSuggestedAudioContext_withUnprioritizedUsage_returnsDefault() {
+        List<AudioPlaybackConfiguration> configurations = ImmutableList.of(
+                new Builder().setUsage(USAGE_VIRTUAL_SOURCE).build()
+        );
+
+        @AudioContext int suggestedContext = CarVolume.getSuggestedAudioContext(configurations,
+                CALL_STATE_IDLE);
+
+        assertThat(suggestedContext).isEqualTo(DEFAULT_AUDIO_CONTEXT);
+    }
+
+    private static class Builder {
+        private @AttributeUsage int mUsage = USAGE_MEDIA;
+        private boolean mIsActive = true;
+
+        Builder setUsage(@AttributeUsage int usage) {
+            mUsage = usage;
+            return this;
+        }
+
+        Builder setInactive() {
+            mIsActive = false;
+            return this;
+        }
+
+        AudioPlaybackConfiguration build() {
+            AudioPlaybackConfiguration configuration = mock(AudioPlaybackConfiguration.class);
+            AudioAttributes attributes = new AudioAttributes.Builder().setUsage(mUsage).build();
+            when(configuration.getAudioAttributes()).thenReturn(attributes);
+            when(configuration.isActive()).thenReturn(mIsActive);
+            return configuration;
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/FocusEntryTest.java b/tests/carservice_unit_test/src/com/android/car/audio/FocusEntryTest.java
new file mode 100644
index 0000000..1698781
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/FocusEntryTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.audio;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.car.Car;
+import android.car.media.CarAudioManager;
+import android.content.pm.PackageManager;
+import android.media.AudioAttributes;
+import android.media.AudioFocusInfo;
+import android.media.AudioManager;
+import android.os.Bundle;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(AndroidJUnit4.class)
+public class FocusEntryTest {
+
+    private static final int CLIENT_UID = 0;
+    private static final String CLIENT_ID = "0";
+    private static final String PACKAGE_NAME = "PACKAGE_NAME";
+    private static final int LOSS_RECEIVED = 0;
+    private static final int DEFAULT_FLAGS = 0;
+    private static final int SDK = 0;
+
+    @Rule
+    public MockitoRule rule = MockitoJUnit.rule();
+
+    @Mock
+    private PackageManager mMockPM;
+
+    @Test
+    public void wantsPauseInsteadOfDucking_whenFlagIsSet_returnsTrue() {
+        AudioFocusInfo info = getInfoWithFlags(
+                AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS);
+
+        FocusEntry focusEntry = new FocusEntry(info, CarAudioContext.MUSIC, mMockPM);
+
+        assertThat(focusEntry.wantsPauseInsteadOfDucking()).isTrue();
+    }
+
+    @Test
+    public void wantsPauseInsteadOfDucking_whenFlagIsNotSet_returnsFalse() {
+        AudioFocusInfo info = getInfoWithFlags(0);
+
+        FocusEntry focusEntry = new FocusEntry(info, CarAudioContext.MUSIC, mMockPM);
+
+        assertThat(focusEntry.wantsPauseInsteadOfDucking()).isFalse();
+    }
+
+    @Test
+    public void receivesDuckEvents_whenBundleDoesNotReceiveDuckingEvents_returnsFalse() {
+        AudioFocusInfo info = getInfoThatReceivesDuckingEvents(false);
+        FocusEntry focusEntry = new FocusEntry(info, CarAudioContext.MUSIC, mMockPM);
+
+        assertThat(focusEntry.receivesDuckEvents()).isFalse();
+    }
+
+    @Test
+    public void receivesDuckEvents_withoutReceiveCarAudioDuckingEventsPermission_returnsFalse() {
+        withoutPermission();
+        AudioFocusInfo info = getInfoThatReceivesDuckingEvents(true);
+
+        FocusEntry focusEntry = new FocusEntry(info, CarAudioContext.MUSIC, mMockPM);
+
+        assertThat(focusEntry.receivesDuckEvents()).isFalse();
+    }
+
+    @Test
+    public void receivesDuckEvents_withReceiveCarAudioDuckingEventsPermission_returnsTrue() {
+        withPermission();
+        AudioFocusInfo info = getInfoThatReceivesDuckingEvents(true);
+
+        FocusEntry focusEntry = new FocusEntry(info, CarAudioContext.MUSIC, mMockPM);
+
+        assertThat(focusEntry.receivesDuckEvents()).isTrue();
+    }
+
+    private void withPermission() {
+        when(mMockPM.checkPermission(Car.PERMISSION_RECEIVE_CAR_AUDIO_DUCKING_EVENTS, PACKAGE_NAME))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+    }
+
+    private void withoutPermission() {
+        when(mMockPM.checkPermission(Car.PERMISSION_RECEIVE_CAR_AUDIO_DUCKING_EVENTS, PACKAGE_NAME))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
+    }
+
+    private AudioFocusInfo getInfoWithFlags(int flags) {
+        AudioAttributes attributes = new AudioAttributes.Builder().build();
+        return getInfo(attributes, flags);
+    }
+
+    private AudioFocusInfo getInfoThatReceivesDuckingEvents(boolean receivesDuckingEvents) {
+        Bundle bundle = new Bundle();
+        bundle.putBoolean(CarAudioManager.AUDIOFOCUS_EXTRA_RECEIVE_DUCKING_EVENTS,
+                receivesDuckingEvents);
+        AudioAttributes attributes = new AudioAttributes.Builder()
+                .addBundle(bundle)
+                .build();
+        return getInfo(attributes, DEFAULT_FLAGS);
+    }
+
+    private AudioFocusInfo getInfo(AudioAttributes attributes, int flags) {
+        return new AudioFocusInfo(attributes, CLIENT_UID, CLIENT_ID, PACKAGE_NAME,
+                AudioManager.AUDIOFOCUS_GAIN, LOSS_RECEIVED, flags, SDK);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/FocusInteractionTest.java b/tests/carservice_unit_test/src/com/android/car/audio/FocusInteractionTest.java
new file mode 100644
index 0000000..d1571a4
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/FocusInteractionTest.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.audio;
+
+import static com.android.car.audio.CarAudioContext.AudioContext;
+import static com.android.car.audio.FocusInteraction.INTERACTION_CONCURRENT;
+import static com.android.car.audio.FocusInteraction.INTERACTION_EXCLUSIVE;
+import static com.android.car.audio.FocusInteraction.INTERACTION_REJECT;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.content.ContentResolver;
+import android.media.AudioManager;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class FocusInteractionTest {
+    private static final int UNDEFINED_CONTEXT_VALUE = -10;
+    private static final int TEST_USER_ID = 10;
+
+    @Mock
+    private CarAudioSettings mMockCarAudioSettings;
+    @Mock
+    private ContentResolver mMockContentResolver;
+    @Rule
+    public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    private final List<FocusEntry> mLosers = new ArrayList<>();
+
+    private FocusInteraction mFocusInteraction;
+
+    @Before
+    public void setUp() {
+        doReturn(mMockContentResolver).when(mMockCarAudioSettings).getContentResolver();
+        mFocusInteraction = new FocusInteraction(mMockCarAudioSettings);
+    }
+
+    @Test
+    public void getInteractionMatrix_returnsNByNMatrix() {
+        int n = CarAudioContext.CONTEXTS.length + 1; // One extra for CarAudioContext.INVALID
+
+        int[][] interactionMatrix = mFocusInteraction.getInteractionMatrix();
+
+        assertThat(interactionMatrix.length).isEqualTo(n);
+        for (int i = 0; i < n; i++) {
+            assertWithMessage("Row %s is not of length %s", i, n)
+                    .that(interactionMatrix[i].length).isEqualTo(n);
+        }
+    }
+
+    @Test
+    public void getInteractionMatrix_hasValidInteractionValues() {
+        List<Integer> supportedInteractions = Arrays.asList(INTERACTION_REJECT,
+                INTERACTION_EXCLUSIVE, INTERACTION_CONCURRENT);
+
+        int[][] interactionMatrix = mFocusInteraction.getInteractionMatrix();
+
+        for (int i = 0; i < interactionMatrix.length; i++) {
+            for (int j = 0; j < interactionMatrix[i].length; j++) {
+                assertWithMessage("Row %s column %s has unexpected value %s", i, j,
+                        interactionMatrix[i][j]).that(
+                        interactionMatrix[i][j]).isIn(supportedInteractions);
+            }
+        }
+    }
+
+    @Test
+    public void evaluateResult_forRejectPair_returnsFailed() {
+        FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.INVALID);
+
+        int result = mFocusInteraction.evaluateRequest(CarAudioContext.INVALID, focusEntry, mLosers,
+                false, false);
+
+        assertThat(result).isEqualTo(AudioManager.AUDIOFOCUS_REQUEST_FAILED);
+    }
+
+    @Test
+    public void evaluateResult_forCallAndNavigation_withNavigationNotRejected_returnsConcurrent() {
+        doReturn(false)
+                .when(mMockCarAudioSettings)
+                .isRejectNavigationOnCallEnabledInSettings(TEST_USER_ID);
+
+        mFocusInteraction.setUserIdForSettings(TEST_USER_ID);
+        FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.CALL);
+
+        int result = mFocusInteraction.evaluateRequest(CarAudioContext.NAVIGATION, focusEntry,
+                mLosers, false, false);
+
+        assertThat(result).isEqualTo(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
+    }
+
+    @Test
+    public void evaluateResult_forCallAndNavigation_withNavigationRejected_returnsConcurrent() {
+        doReturn(true)
+                .when(mMockCarAudioSettings)
+                .isRejectNavigationOnCallEnabledInSettings(TEST_USER_ID);
+        mFocusInteraction.setUserIdForSettings(TEST_USER_ID);
+        FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.CALL);
+
+        int result = mFocusInteraction.evaluateRequest(CarAudioContext.NAVIGATION, focusEntry,
+                mLosers, false, false);
+
+        assertThat(result).isEqualTo(AudioManager.AUDIOFOCUS_REQUEST_FAILED);
+    }
+
+    @Test
+    public void evaluateResult_forRejectPair_doesNotAddToLosers() {
+        FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.INVALID);
+
+        mFocusInteraction
+                .evaluateRequest(CarAudioContext.INVALID, focusEntry, mLosers, false,
+                        false);
+
+        assertThat(mLosers).isEmpty();
+    }
+
+    @Test
+    public void evaluateRequest_forExclusivePair_returnsGranted() {
+        FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.MUSIC);
+
+        int result = mFocusInteraction.evaluateRequest(CarAudioContext.MUSIC, focusEntry, mLosers,
+                false, false);
+
+        assertThat(result).isEqualTo(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
+    }
+
+    @Test
+    public void evaluateRequest_forExclusivePair_addsEntryToLosers() {
+        FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.MUSIC);
+
+        mFocusInteraction
+                .evaluateRequest(CarAudioContext.MUSIC, focusEntry, mLosers, false,
+                        false);
+
+        assertThat(mLosers).containsExactly(focusEntry);
+    }
+
+    @Test
+    public void evaluateResult_forConcurrentPair_returnsGranted() {
+        FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.NAVIGATION);
+
+        int result = mFocusInteraction.evaluateRequest(CarAudioContext.MUSIC, focusEntry, mLosers,
+                false, false);
+
+        assertThat(result).isEqualTo(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
+    }
+
+    @Test
+    public void evaluateResult_forConcurrentPair_andNoDucking_addsToLosers() {
+        FocusEntry focusEntry =
+                newMockFocusEntryWithDuckingBehavior(false, false);
+
+        mFocusInteraction
+                .evaluateRequest(CarAudioContext.MUSIC, focusEntry, mLosers, false, false);
+
+        assertThat(mLosers).containsExactly(focusEntry);
+    }
+
+    @Test
+    public void evaluateResult_forConcurrentPair_andWantsPauseInsteadOfDucking_addsToLosers() {
+        FocusEntry focusEntry =
+                newMockFocusEntryWithDuckingBehavior(true, false);
+
+        mFocusInteraction
+                .evaluateRequest(CarAudioContext.MUSIC, focusEntry, mLosers, true, false);
+
+        assertThat(mLosers).containsExactly(focusEntry);
+    }
+
+    @Test
+    public void evaluateResult_forConcurrentPair_andReceivesDuckEvents_addsToLosers() {
+        FocusEntry focusEntry =
+                newMockFocusEntryWithDuckingBehavior(false, true);
+
+        mFocusInteraction
+                .evaluateRequest(CarAudioContext.MUSIC, focusEntry, mLosers, true, false);
+
+        assertThat(mLosers).containsExactly(focusEntry);
+    }
+
+    @Test
+    public void evaluateResult_forConcurrentPair_andDucking_doesAddsToLosers() {
+        FocusEntry focusEntry =
+                newMockFocusEntryWithDuckingBehavior(false, true);
+
+        mFocusInteraction
+                .evaluateRequest(CarAudioContext.MUSIC, focusEntry, mLosers, true,
+                        false);
+
+        assertThat(mLosers).containsExactly(focusEntry);
+    }
+
+    @Test
+    public void evaluateResult_forUndefinedContext_throws() {
+        FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.NAVIGATION);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> mFocusInteraction.evaluateRequest(UNDEFINED_CONTEXT_VALUE, focusEntry,
+                        mLosers, false, false));
+    }
+
+    @Test
+    public void evaluateResult_forUndefinedFocusHolderContext_throws() {
+        FocusEntry focusEntry = newMockFocusEntryWithContext(UNDEFINED_CONTEXT_VALUE);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> mFocusInteraction.evaluateRequest(CarAudioContext.MUSIC, focusEntry,
+                        mLosers, false, false));
+    }
+
+    @Test
+    public void evaluateRequest_forExclusivePair_withDelayedFocus_returnsGranted() {
+        FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.MUSIC);
+
+        int result = mFocusInteraction.evaluateRequest(CarAudioContext.MUSIC, focusEntry, mLosers,
+                false, true);
+
+        assertThat(result).isEqualTo(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
+    }
+
+    @Test
+    public void evaluateRequest_forRejectPair_withDelayedFocus_returnsDelayed() {
+        FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.CALL);
+
+        int result = mFocusInteraction.evaluateRequest(CarAudioContext.MUSIC, focusEntry, mLosers,
+                false, true);
+
+        assertThat(result).isEqualTo(AudioManager.AUDIOFOCUS_REQUEST_DELAYED);
+    }
+
+    @Test
+    public void evaluateRequest_forRejectPair_withoutDelayedFocus_returnsReject() {
+        FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.CALL);
+
+        int result = mFocusInteraction.evaluateRequest(CarAudioContext.MUSIC, focusEntry, mLosers,
+                false, false);
+
+        assertThat(result).isEqualTo(AudioManager.AUDIOFOCUS_REQUEST_FAILED);
+    }
+
+    private FocusEntry newMockFocusEntryWithContext(@AudioContext int audioContext) {
+        FocusEntry focusEntry = mock(FocusEntry.class);
+        when(focusEntry.getAudioContext()).thenReturn(audioContext);
+        return focusEntry;
+    }
+
+    private FocusEntry newMockFocusEntryWithDuckingBehavior(boolean pauseInsteadOfDucking,
+            boolean receivesDuckingEvents) {
+        FocusEntry focusEntry = newMockFocusEntryWithContext(CarAudioContext.NAVIGATION);
+        when(focusEntry.wantsPauseInsteadOfDucking()).thenReturn(pauseInsteadOfDucking);
+        when(focusEntry.receivesDuckEvents()).thenReturn(receivesDuckingEvents);
+        return focusEntry;
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/OWNERS b/tests/carservice_unit_test/src/com/android/car/audio/OWNERS
new file mode 100644
index 0000000..8d34cdd
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/OWNERS
@@ -0,0 +1,3 @@
+# Audio owners
+haydengomes@google.com
+oscarazu@google.com
\ No newline at end of file
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlFactoryUnitTest.java b/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlFactoryUnitTest.java
new file mode 100644
index 0000000..b47aa10
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlFactoryUnitTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package audio.hal;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.car.audio.hal.AudioControlFactory;
+import com.android.car.audio.hal.AudioControlWrapper;
+import com.android.car.audio.hal.AudioControlWrapperV1;
+import com.android.car.audio.hal.AudioControlWrapperV2;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+@RunWith(AndroidJUnit4.class)
+public class AudioControlFactoryUnitTest extends AbstractExtendedMockitoTestCase {
+    private static final String TAG = AudioControlFactoryUnitTest.class.getSimpleName();
+
+    @Mock
+    android.hardware.automotive.audiocontrol.V2_0.IAudioControl mIAudioControlV2;
+
+    @Mock
+    android.hardware.automotive.audiocontrol.V1_0.IAudioControl mIAudioControlV1;
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+        session.spyStatic(AudioControlWrapperV2.class).spyStatic(AudioControlWrapperV1.class);
+    }
+
+    @Test
+    public void newAudioControl_forAudioControlWrapperV2_returnsInstance() {
+        doReturn(null).when(() -> AudioControlWrapperV1.getService());
+        doReturn(mIAudioControlV2).when(() -> AudioControlWrapperV2.getService());
+
+        AudioControlWrapper wrapper = AudioControlFactory.newAudioControl();
+        assertThat(wrapper).isNotNull();
+    }
+
+    @Test
+    public void newAudioControl_forAudioControlWrapperV1_returnsInstance() {
+        doReturn(mIAudioControlV1).when(() -> AudioControlWrapperV1.getService());
+        doReturn(null).when(() -> AudioControlWrapperV2.getService());
+
+        AudioControlWrapper wrapper = AudioControlFactory.newAudioControl();
+        assertThat(wrapper).isNotNull();
+    }
+
+    @Test
+    public void newAudioControl_forNullAudioControlWrappers_fails() {
+        doReturn(null).when(() -> AudioControlWrapperV1.getService());
+        doReturn(null).when(() -> AudioControlWrapperV2.getService());
+
+        assertThrows(IllegalStateException.class, () -> AudioControlFactory.newAudioControl());
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperV1Test.java b/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperV1Test.java
new file mode 100644
index 0000000..c559d89
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperV1Test.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.audio.hal;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.hardware.automotive.audiocontrol.V1_0.IAudioControl;
+import android.hardware.automotive.audiocontrol.V2_0.IFocusListener;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(AndroidJUnit4.class)
+public class AudioControlWrapperV1Test {
+    private static final float FADE_VALUE = 5;
+    private static final float BALANCE_VALUE = 6;
+    private static final int CONTEXT_NUMBER = 3;
+    private static final int USAGE = AudioAttributes.USAGE_MEDIA;
+    private static final int ZONE_ID = 2;
+    private static final int FOCUS_GAIN = AudioManager.AUDIOFOCUS_GAIN;
+
+    @Rule
+    public MockitoRule rule = MockitoJUnit.rule();
+
+    @Mock
+    IAudioControl mAudioControlV1;
+
+    @Test
+    public void setFadeTowardFront_succeeds() throws Exception {
+        AudioControlWrapperV1 audioControlWrapperV1 = new AudioControlWrapperV1(mAudioControlV1);
+        audioControlWrapperV1.setFadeTowardFront(FADE_VALUE);
+
+        verify(mAudioControlV1).setFadeTowardFront(FADE_VALUE);
+    }
+
+    @Test
+    public void setBalanceTowardRight_succeeds() throws Exception {
+        AudioControlWrapperV1 audioControlWrapperV1 = new AudioControlWrapperV1(mAudioControlV1);
+        audioControlWrapperV1.setBalanceTowardRight(BALANCE_VALUE);
+
+        verify(mAudioControlV1).setBalanceTowardRight(BALANCE_VALUE);
+    }
+
+    @Test
+    public void getBusForContext_returnsBusNumber() throws Exception {
+        AudioControlWrapperV1 audioControlWrapperV1 = new AudioControlWrapperV1(mAudioControlV1);
+        int busNumber = 1;
+        when(mAudioControlV1.getBusForContext(CONTEXT_NUMBER)).thenReturn(busNumber);
+
+        int actualBus = audioControlWrapperV1.getBusForContext(CONTEXT_NUMBER);
+        assertThat(actualBus).isEqualTo(busNumber);
+    }
+
+    @Test
+    public void supportsHalAudioFocus_returnsFalse() {
+        AudioControlWrapperV1 audioControlWrapperV1 = new AudioControlWrapperV1(mAudioControlV1);
+
+        assertThat(audioControlWrapperV1.supportsHalAudioFocus()).isFalse();
+    }
+
+    @Test
+    public void registerFocusListener_throws() {
+        AudioControlWrapperV1 audioControlWrapperV1 = new AudioControlWrapperV1(mAudioControlV1);
+        IFocusListener mockListener = mock(IFocusListener.class);
+
+        assertThrows(UnsupportedOperationException.class,
+                () -> audioControlWrapperV1.registerFocusListener(mockListener));
+    }
+
+    @Test
+    public void unregisterFocusListener_throws() {
+        AudioControlWrapperV1 audioControlWrapperV1 = new AudioControlWrapperV1(mAudioControlV1);
+        IFocusListener mockListener = mock(IFocusListener.class);
+
+        assertThrows(UnsupportedOperationException.class,
+                () -> audioControlWrapperV1.unregisterFocusListener());
+    }
+
+    @Test
+    public void onAudioFocusChange_throws() {
+        AudioControlWrapperV1 audioControlWrapperV1 = new AudioControlWrapperV1(mAudioControlV1);
+
+        assertThrows(UnsupportedOperationException.class,
+                () -> audioControlWrapperV1.onAudioFocusChange(USAGE, ZONE_ID, FOCUS_GAIN));
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperV2Test.java b/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperV2Test.java
new file mode 100644
index 0000000..a57b68d
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperV2Test.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.audio.hal;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.hardware.automotive.audiocontrol.V2_0.IAudioControl;
+import android.hardware.automotive.audiocontrol.V2_0.ICloseHandle;
+import android.hardware.automotive.audiocontrol.V2_0.IFocusListener;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(AndroidJUnit4.class)
+public class AudioControlWrapperV2Test {
+    private static final float FADE_VALUE = 5;
+    private static final float BALANCE_VALUE = 6;
+    private static final int CONTEXT_NUMBER = 3;
+    private static final int USAGE = AudioAttributes.USAGE_MEDIA;
+    private static final int ZONE_ID = 2;
+    private static final int FOCUS_GAIN = AudioManager.AUDIOFOCUS_GAIN;
+
+    @Rule
+    public MockitoRule rule = MockitoJUnit.rule();
+
+    @Mock
+    IAudioControl mAudioControlV2;
+
+    @Test
+    public void setFadeTowardFront_succeeds() throws Exception {
+        AudioControlWrapperV2 audioControlWrapperV2 = new AudioControlWrapperV2(mAudioControlV2);
+        audioControlWrapperV2.setFadeTowardFront(FADE_VALUE);
+
+        verify(mAudioControlV2).setFadeTowardFront(FADE_VALUE);
+    }
+
+    @Test
+    public void setBalanceTowardRight_succeeds() throws Exception {
+        AudioControlWrapperV2 audioControlWrapperV2 = new AudioControlWrapperV2(mAudioControlV2);
+        audioControlWrapperV2.setBalanceTowardRight(BALANCE_VALUE);
+
+        verify(mAudioControlV2).setBalanceTowardRight(BALANCE_VALUE);
+    }
+
+    @Test
+    public void supportsHalAudioFocus_returnsTrue() {
+        AudioControlWrapperV2 audioControlWrapperV2 = new AudioControlWrapperV2(mAudioControlV2);
+
+        assertThat(audioControlWrapperV2.supportsHalAudioFocus()).isTrue();
+    }
+
+    @Test
+    public void registerFocusListener_succeeds() throws Exception {
+        AudioControlWrapperV2 audioControlWrapperV2 = new AudioControlWrapperV2(mAudioControlV2);
+        IFocusListener mockListener = mock(IFocusListener.class);
+        audioControlWrapperV2.registerFocusListener(mockListener);
+
+        verify(mAudioControlV2).registerFocusListener(mockListener);
+    }
+
+    @Test
+    public void unregisterFocusListener_closesHandle() throws Exception {
+        IFocusListener mockListener = mock(IFocusListener.class);
+        ICloseHandle mockCloseHandle = mock(ICloseHandle.class);
+        when(mAudioControlV2.registerFocusListener(mockListener)).thenReturn(mockCloseHandle);
+
+        AudioControlWrapperV2 audioControlWrapperV2 = new AudioControlWrapperV2(mAudioControlV2);
+        audioControlWrapperV2.registerFocusListener(mockListener);
+
+        audioControlWrapperV2.unregisterFocusListener();
+
+        verify(mockCloseHandle).close();
+    }
+
+    @Test
+    public void onAudioFocusChange_succeeds() throws Exception {
+        AudioControlWrapperV2 audioControlWrapperV2 = new AudioControlWrapperV2(mAudioControlV2);
+        audioControlWrapperV2.onAudioFocusChange(USAGE, ZONE_ID, FOCUS_GAIN);
+
+        verify(mAudioControlV2).onAudioFocusChange(USAGE, ZONE_ID, FOCUS_GAIN);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/hal/HalAudioFocusTest.java b/tests/carservice_unit_test/src/com/android/car/audio/hal/HalAudioFocusTest.java
new file mode 100644
index 0000000..310c984
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/hal/HalAudioFocusTest.java
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.audio.hal;
+
+import static android.media.AudioAttributes.USAGE_ALARM;
+import static android.media.AudioAttributes.USAGE_MEDIA;
+import static android.media.AudioManager.AUDIOFOCUS_GAIN;
+import static android.media.AudioManager.AUDIOFOCUS_LOSS;
+import static android.media.AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
+import static android.media.AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+import static android.media.AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.car.media.CarAudioManager;
+import android.media.AudioFocusRequest;
+import android.media.AudioManager;
+import android.media.AudioManager.OnAudioFocusChangeListener;
+import android.os.Bundle;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(AndroidJUnit4.class)
+public class HalAudioFocusTest {
+    private static final int[] AUDIO_ZONE_IDS = {0, 1, 2, 3};
+    private static final int ZONE_ID = 0;
+    private static final int SECOND_ZONE_ID = 1;
+    private static final int INVALID_ZONE_ID = 5;
+
+    @Rule
+    public MockitoRule rule = MockitoJUnit.rule();
+
+    @Mock
+    AudioManager mMockAudioManager;
+    @Mock
+    AudioControlWrapper mAudioControlWrapper;
+
+    private HalAudioFocus mHalAudioFocus;
+
+    @Before
+    public void setUp() {
+        mHalAudioFocus = new HalAudioFocus(mMockAudioManager, mAudioControlWrapper, AUDIO_ZONE_IDS);
+    }
+
+    @Test
+    public void registerFocusListener_succeeds() {
+        mHalAudioFocus.registerFocusListener();
+
+        verify(mAudioControlWrapper).registerFocusListener(mHalAudioFocus);
+    }
+
+    @Test
+    public void requestAudioFocus_notifiesHalOfFocusChange() {
+        whenAnyFocusRequestGranted();
+
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+
+        verify(mAudioControlWrapper).onAudioFocusChange(USAGE_MEDIA, ZONE_ID,
+                AUDIOFOCUS_REQUEST_GRANTED);
+    }
+
+    @Test
+    public void requestAudioFocus_specifiesUsage() {
+        whenAnyFocusRequestGranted();
+
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+
+        AudioFocusRequest actualRequest = getLastRequest();
+        assertThat(actualRequest.getAudioAttributes().getUsage()).isEqualTo(USAGE_MEDIA);
+    }
+
+    @Test
+    public void requestAudioFocus_specifiesFocusGain() {
+        whenAnyFocusRequestGranted();
+
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+
+        AudioFocusRequest actualRequest = getLastRequest();
+        assertThat(actualRequest.getFocusGain()).isEqualTo(AUDIOFOCUS_GAIN);
+    }
+
+    @Test
+    public void requestAudioFocus_specifiesZoneId() {
+        whenAnyFocusRequestGranted();
+
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+
+        AudioFocusRequest actualRequest = getLastRequest();
+        Bundle bundle = actualRequest.getAudioAttributes().getBundle();
+        assertThat(bundle.getInt(CarAudioManager.AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID)).isEqualTo(
+                ZONE_ID);
+    }
+
+    @Test
+    public void requestAudioFocus_providesFocusChangeListener() {
+        whenAnyFocusRequestGranted();
+
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+
+        AudioFocusRequest actualRequest = getLastRequest();
+        assertThat(actualRequest.getOnAudioFocusChangeListener()).isNotNull();
+    }
+
+    @Test
+    public void requestAudioFocus_withInvalidZone_throws() {
+        whenAnyFocusRequestGranted();
+
+        assertThrows(IllegalArgumentException.class,
+                () -> mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, INVALID_ZONE_ID,
+                        AUDIOFOCUS_GAIN));
+    }
+
+    @Test
+    public void requestAudioFocus_withSameZoneAndUsage_keepsExistingRequest() {
+        whenAnyFocusRequestGranted();
+
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+        AudioFocusRequest firstRequest = getLastRequest();
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+
+        verify(mMockAudioManager, never()).abandonAudioFocusRequest(firstRequest);
+    }
+
+    @Test
+    public void requestAudioFocus_withSameZoneAndUsage_notifiesHalOfExistingRequestStatus() {
+        whenAnyFocusRequestGranted();
+
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+        AudioFocusRequest firstRequest = getLastRequest();
+        OnAudioFocusChangeListener listener = firstRequest.getOnAudioFocusChangeListener();
+        listener.onAudioFocusChange(AUDIOFOCUS_LOSS_TRANSIENT);
+
+        verify(mAudioControlWrapper).onAudioFocusChange(USAGE_MEDIA, ZONE_ID,
+                AUDIOFOCUS_LOSS_TRANSIENT);
+
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+
+        verify(mAudioControlWrapper, times(2)).onAudioFocusChange(USAGE_MEDIA, ZONE_ID,
+                AUDIOFOCUS_LOSS_TRANSIENT);
+    }
+
+    @Test
+    public void requestAudioFocus_withDifferentZoneAndSameUsage_keepsExistingRequest() {
+        whenAnyFocusRequestGranted();
+
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+        AudioFocusRequest firstRequest = getLastRequest();
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, SECOND_ZONE_ID, AUDIOFOCUS_GAIN);
+
+        verify(mMockAudioManager, never()).abandonAudioFocusRequest(firstRequest);
+    }
+
+    @Test
+    public void requestAudioFocus_withSameZoneAndDifferentUsage_keepsExistingRequest() {
+        whenAnyFocusRequestGranted();
+
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+        AudioFocusRequest firstRequest = getLastRequest();
+        mHalAudioFocus.requestAudioFocus(USAGE_ALARM, ZONE_ID, AUDIOFOCUS_GAIN);
+
+        verify(mMockAudioManager, never()).abandonAudioFocusRequest(firstRequest);
+    }
+
+    @Test
+    public void requestAudioFocus_withPreviouslyFailedRequest_doesNothingForOldRequest() {
+        when(mMockAudioManager.requestAudioFocus(any())).thenReturn(AUDIOFOCUS_REQUEST_FAILED,
+                AUDIOFOCUS_REQUEST_GRANTED);
+
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+        AudioFocusRequest firstRequest = getLastRequest();
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+
+        verify(mMockAudioManager, never()).abandonAudioFocusRequest(firstRequest);
+    }
+
+    @Test
+    public void onAudioFocusChange_notifiesHalOfChange() {
+        whenAnyFocusRequestGranted();
+
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+        verify(mAudioControlWrapper, never()).onAudioFocusChange(USAGE_MEDIA, ZONE_ID,
+                AUDIOFOCUS_LOSS_TRANSIENT);
+
+        AudioFocusRequest actualRequest = getLastRequest();
+        OnAudioFocusChangeListener listener = actualRequest.getOnAudioFocusChangeListener();
+        listener.onAudioFocusChange(AUDIOFOCUS_LOSS_TRANSIENT);
+
+        verify(mAudioControlWrapper).onAudioFocusChange(USAGE_MEDIA, ZONE_ID,
+                AUDIOFOCUS_LOSS_TRANSIENT);
+    }
+
+    @Test
+    public void abandonAudioFocus_withNoCurrentRequest_doesNothing() throws Exception {
+        whenAnyFocusRequestGranted();
+
+        mHalAudioFocus.abandonAudioFocus(USAGE_MEDIA, ZONE_ID);
+
+        verify(mMockAudioManager, never()).abandonAudioFocusRequest(any());
+    }
+
+    @Test
+    public void abandonAudioFocus_withInvalidZone_throws() {
+        whenAnyFocusRequestGranted();
+
+        assertThrows(IllegalArgumentException.class,
+                () -> mHalAudioFocus.abandonAudioFocus(USAGE_MEDIA, INVALID_ZONE_ID));
+    }
+
+    @Test
+    public void abandonAudioFocus_withCurrentRequest_abandonsExistingFocus() throws Exception {
+        whenAnyFocusRequestGranted();
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+        AudioFocusRequest actualRequest = getLastRequest();
+
+        mHalAudioFocus.abandonAudioFocus(USAGE_MEDIA, ZONE_ID);
+
+        verify(mMockAudioManager).abandonAudioFocusRequest(actualRequest);
+    }
+
+    @Test
+    public void abandonAudioFocus_withCurrentRequest_notifiesHalOfFocusChange() throws Exception {
+        whenAnyFocusRequestGranted();
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+        AudioFocusRequest actualRequest = getLastRequest();
+        when(mMockAudioManager.abandonAudioFocusRequest(actualRequest)).thenReturn(
+                AUDIOFOCUS_REQUEST_GRANTED);
+
+        mHalAudioFocus.abandonAudioFocus(USAGE_MEDIA, ZONE_ID);
+
+        verify(mAudioControlWrapper).onAudioFocusChange(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_LOSS);
+    }
+
+    @Test
+    public void abandonAudioFocus_withFocusAlreadyLost_doesNothing() throws Exception {
+        whenAnyFocusRequestGranted();
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+        AudioFocusRequest actualRequest = getLastRequest();
+        OnAudioFocusChangeListener listener = actualRequest.getOnAudioFocusChangeListener();
+        listener.onAudioFocusChange(AUDIOFOCUS_LOSS);
+
+        mHalAudioFocus.abandonAudioFocus(USAGE_MEDIA, ZONE_ID);
+
+        verify(mMockAudioManager, never()).abandonAudioFocusRequest(actualRequest);
+    }
+
+    @Test
+    public void abandonAudioFocus_withFocusTransientlyLost_abandonsExistingFocus()
+            throws Exception {
+        whenAnyFocusRequestGranted();
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+        AudioFocusRequest actualRequest = getLastRequest();
+        OnAudioFocusChangeListener listener = actualRequest.getOnAudioFocusChangeListener();
+        listener.onAudioFocusChange(AUDIOFOCUS_LOSS_TRANSIENT);
+
+        mHalAudioFocus.abandonAudioFocus(USAGE_MEDIA, ZONE_ID);
+
+        verify(mMockAudioManager).abandonAudioFocusRequest(actualRequest);
+    }
+
+    @Test
+    public void abandonAudioFocus_withExistingRequestOfDifferentUsage_doesNothing()
+            throws Exception {
+        whenAnyFocusRequestGranted();
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+
+        mHalAudioFocus.abandonAudioFocus(USAGE_ALARM, ZONE_ID);
+
+        verify(mMockAudioManager, never()).abandonAudioFocusRequest(any());
+    }
+
+    @Test
+    public void abandonAudioFocus_withExistingRequestOfDifferentZoneId_doesNothing()
+            throws Exception {
+        whenAnyFocusRequestGranted();
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+
+        mHalAudioFocus.abandonAudioFocus(USAGE_MEDIA, SECOND_ZONE_ID);
+
+        verify(mMockAudioManager, never()).abandonAudioFocusRequest(any());
+    }
+
+    @Test
+    public void abandonAudioFocus_withFailedRequest_doesNotNotifyHal() throws Exception {
+        whenAnyFocusRequestGranted();
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+        AudioFocusRequest request = getLastRequest();
+
+        when(mMockAudioManager.abandonAudioFocusRequest(request))
+                .thenReturn(AUDIOFOCUS_REQUEST_FAILED);
+
+        mHalAudioFocus.abandonAudioFocus(USAGE_MEDIA, ZONE_ID);
+
+        verify(mAudioControlWrapper, never())
+                .onAudioFocusChange(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_LOSS);
+    }
+
+    @Test
+    public void reset_abandonsExistingRequests() {
+        whenAnyFocusRequestGranted();
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+        AudioFocusRequest mediaRequest = getLastRequest();
+        mHalAudioFocus.requestAudioFocus(USAGE_ALARM, ZONE_ID, AUDIOFOCUS_GAIN);
+        AudioFocusRequest alarmRequest = getLastRequest();
+
+        verify(mMockAudioManager, never()).abandonAudioFocusRequest(any());
+
+        mHalAudioFocus.reset();
+
+        verify(mMockAudioManager).abandonAudioFocusRequest(mediaRequest);
+        verify(mMockAudioManager).abandonAudioFocusRequest(alarmRequest);
+        verifyNoMoreInteractions(mMockAudioManager);
+    }
+
+    @Test
+    public void reset_notifiesHal() {
+        whenAnyFocusRequestGranted();
+        mHalAudioFocus.requestAudioFocus(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_GAIN);
+        mHalAudioFocus.requestAudioFocus(USAGE_ALARM, ZONE_ID, AUDIOFOCUS_GAIN);
+
+        verify(mAudioControlWrapper, never()).onAudioFocusChange(anyInt(), eq(ZONE_ID),
+                eq(AUDIOFOCUS_LOSS));
+        when(mMockAudioManager.abandonAudioFocusRequest(any())).thenReturn(
+                AUDIOFOCUS_REQUEST_GRANTED);
+
+        mHalAudioFocus.reset();
+
+        verify(mAudioControlWrapper).onAudioFocusChange(USAGE_MEDIA, ZONE_ID, AUDIOFOCUS_LOSS);
+        verify(mAudioControlWrapper).onAudioFocusChange(USAGE_ALARM, ZONE_ID, AUDIOFOCUS_LOSS);
+    }
+
+    private void whenAnyFocusRequestGranted() {
+        when(mMockAudioManager.requestAudioFocus(any())).thenReturn(AUDIOFOCUS_REQUEST_GRANTED);
+    }
+
+    private AudioFocusRequest getLastRequest() {
+        ArgumentCaptor<AudioFocusRequest> captor = ArgumentCaptor.forClass(AudioFocusRequest.class);
+        verify(mMockAudioManager, atLeastOnce()).requestAudioFocus(captor.capture());
+        return captor.getValue();
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/cluster/InstrumentClusterServiceTest.java b/tests/carservice_unit_test/src/com/android/car/cluster/InstrumentClusterServiceTest.java
new file mode 100644
index 0000000..79ebe4f
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/cluster/InstrumentClusterServiceTest.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.cluster;
+
+import static android.car.settings.CarSettings.Global.DISABLE_INSTRUMENTATION_SERVICE;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+
+import android.car.CarAppFocusManager;
+import android.car.cluster.renderer.IInstrumentCluster;
+import android.car.cluster.renderer.IInstrumentClusterNavigation;
+import android.car.navigation.CarNavigationInstrumentCluster;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Looper;
+import android.os.Process;
+import android.view.KeyEvent;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.car.AppFocusService;
+import com.android.car.CarInputService;
+import com.android.car.CarLocalServices;
+import com.android.car.CarServiceUtils;
+import com.android.car.R;
+import com.android.car.user.CarUserService;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.stubbing.Answer;
+
+public class InstrumentClusterServiceTest extends AbstractExtendedMockitoTestCase {
+
+    private static final String DEFAULT_RENDERER_SERVICE =
+            "com.android.car.carservice_unittest/.FakeService";
+
+    private InstrumentClusterService mService;
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private AppFocusService mAppFocusService;
+    @Mock
+    private CarInputService mCarInputService;
+    @Mock
+    private CarUserService mCarUserService;
+
+    private final IInstrumentClusterNavigationImpl mInstrumentClusterNavigation =
+            new IInstrumentClusterNavigationImpl();
+
+    private final IInstrumentCluster mInstrumentClusterRenderer = new IInstrumentCluster.Stub() {
+
+        @Override
+        public IInstrumentClusterNavigation getNavigationService() {
+            return mInstrumentClusterNavigation;
+        }
+
+        @Override
+        public void setNavigationContextOwner(int uid, int pid) {
+        }
+
+        @Override
+        public void onKeyEvent(KeyEvent keyEvent) {
+        }
+    };
+
+    @Before
+    public void setUp() {
+        doReturn(DEFAULT_RENDERER_SERVICE).when(mContext).getString(
+                R.string.instrumentClusterRendererService);
+        doReturn(true).when(mContext).bindServiceAsUser(any(), any(), anyInt(), any());
+        ContentResolver cr = InstrumentationRegistry.getTargetContext().getContentResolver();
+        doReturn(cr).when(mContext).getContentResolver();
+        putSettingsString(DISABLE_INSTRUMENTATION_SERVICE, "false");
+        doAnswer((Answer<Void>) invocationOnMock -> {
+                    Runnable r = invocationOnMock.getArgument(0);
+                    r.run();
+                    return null;
+                }
+        ).when(mCarUserService).runOnUser0Unlock(any());
+        CarLocalServices.removeServiceForTest(CarUserService.class);
+        CarLocalServices.addService(CarUserService.class, mCarUserService);
+
+        setNewService();
+    }
+
+    private void setNewService() {
+        // Must prepare Looper (once) otherwise InstrumentClusterService constructor will fail.
+        Looper looper = Looper.myLooper();
+        if (looper == null) {
+            Looper.prepare();
+        }
+        mService = new InstrumentClusterService(mContext, mAppFocusService, mCarInputService);
+    }
+
+    @After
+    public void tearDown() {
+        CarLocalServices.removeServiceForTest(CarUserService.class);
+    }
+
+    private void initService(boolean connect) {
+        mService.init();
+        if (connect) {
+            notifyRendererServiceConnection();
+        }
+        // Give nav focus to the test
+        mService.onFocusAcquired(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, Process.myUid(),
+                Process.myPid());
+    }
+
+    private void notifyRendererServiceConnection() {
+        mService.mRendererServiceConnection.onServiceConnected(null,
+                mInstrumentClusterRenderer.asBinder());
+    }
+
+    @Test
+    public void testNonNullManager() throws Exception {
+        initService(/* connect= */ true);
+        checkValidClusterNavigation();
+    }
+
+    @Test
+    public void testDelayedConnection() throws Exception {
+        initService(/* connect= */ false);
+        CarServiceUtils.runOnMain(() -> {
+            // need to delay notification
+            try {
+                Thread.sleep(50);
+            } catch (InterruptedException e) {
+            }
+            notifyRendererServiceConnection();
+        });
+        checkValidClusterNavigation();
+    }
+
+    @Test
+    public void testNoConfig() throws Exception {
+        doReturn("").when(mContext).getString(R.string.instrumentClusterRendererService);
+        setNewService();
+        initService(/* connect= */ false);
+        IInstrumentClusterNavigation navigationService = mService.getNavigationService();
+        assertThat(navigationService).isNull();
+    }
+
+    private void checkValidClusterNavigation() throws Exception {
+        IInstrumentClusterNavigation navigationService = mService.getNavigationService();
+        assertThat(navigationService).isNotNull();
+        // should pass wrapper from car service
+        assertThat(navigationService).isNotEqualTo(mInstrumentClusterNavigation);
+        assertThat(navigationService.getInstrumentClusterInfo()).isEqualTo(
+                mInstrumentClusterNavigation.mClusterInfo);
+        Bundle bundle = new Bundle();
+        navigationService.onNavigationStateChanged(bundle);
+        assertThat(bundle).isEqualTo(mInstrumentClusterNavigation.mLastBundle);
+    }
+
+    private static class IInstrumentClusterNavigationImpl
+            extends IInstrumentClusterNavigation.Stub {
+
+        private final CarNavigationInstrumentCluster mClusterInfo =
+                CarNavigationInstrumentCluster.createCustomImageCluster(/*minIntervalMs= */ 100,
+                        /* imageWidth= */ 800, /* imageHeight= */ 480,
+                        /* imageColorDepthBits= */ 32);
+
+        private Bundle mLastBundle;
+
+        @Override
+        public void onNavigationStateChanged(Bundle bundle) {
+            mLastBundle = bundle;
+        }
+
+        @Override
+        public CarNavigationInstrumentCluster getInstrumentClusterInfo() {
+            return mClusterInfo;
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/HalClientUnitTest.java b/tests/carservice_unit_test/src/com/android/car/hal/HalClientUnitTest.java
new file mode 100644
index 0000000..8b18119
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/hal/HalClientUnitTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.hal;
+
+import static android.car.test.mocks.CarArgumentMatchers.isProperty;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.expectThrows;
+
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.hardware.automotive.vehicle.V2_0.IVehicle;
+import android.hardware.automotive.vehicle.V2_0.IVehicleCallback;
+import android.hardware.automotive.vehicle.V2_0.StatusCode;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
+public final class HalClientUnitTest extends AbstractExtendedMockitoTestCase {
+
+    private static final int WAIT_CAP_FOR_RETRIABLE_RESULT_MS = 100;
+    private static final int SLEEP_BETWEEN_RETRIABLE_INVOKES_MS = 50;
+
+    private static final int PROP = 42;
+    private static final int AREA_ID = 108;
+
+    private final VehiclePropValue mProp = new VehiclePropValue();
+
+    @Mock IVehicle mIVehicle;
+    @Mock IVehicleCallback mIVehicleCallback;
+
+    private HalClient mClient;
+
+    @Before
+    public void setFixtures() {
+        mClient = new HalClient(mIVehicle, Looper.getMainLooper(), mIVehicleCallback,
+                WAIT_CAP_FOR_RETRIABLE_RESULT_MS, SLEEP_BETWEEN_RETRIABLE_INVOKES_MS);
+        mProp.prop = PROP;
+        mProp.areaId = AREA_ID;
+    }
+
+    @Test
+    public void testSet_remoteExceptionThenFail() throws Exception {
+        when(mIVehicle.set(isProperty(PROP)))
+            .thenThrow(new RemoteException("Never give up, never surrender!"))
+            .thenThrow(new RemoteException("D'OH!"));
+
+        Exception actualException = expectThrows(ServiceSpecificException.class,
+                () -> mClient.setValue(mProp));
+
+        assertThat(actualException).hasMessageThat().contains(Integer.toHexString(PROP));
+        assertThat(actualException).hasMessageThat().contains(Integer.toHexString(AREA_ID));
+    }
+
+    @Test
+    public void testSet_remoteExceptionThenOk() throws Exception {
+        when(mIVehicle.set(isProperty(PROP)))
+            .thenThrow(new RemoteException("Never give up, never surrender!"))
+            .thenReturn(StatusCode.OK);
+
+        mClient.setValue(mProp);
+    }
+
+    @Test
+    public void testSet_invalidArgument() throws Exception {
+        when(mIVehicle.set(isProperty(PROP))).thenReturn(StatusCode.INVALID_ARG);
+
+        Exception actualException = expectThrows(IllegalArgumentException.class,
+                () -> mClient.setValue(mProp));
+
+        assertThat(actualException).hasMessageThat().contains(Integer.toHexString(PROP));
+        assertThat(actualException).hasMessageThat().contains(Integer.toHexString(AREA_ID));
+    }
+
+    @Test
+    public void testSet_otherError() throws Exception {
+        when(mIVehicle.set(isProperty(PROP))).thenReturn(StatusCode.INTERNAL_ERROR);
+
+        Exception actualException = expectThrows(ServiceSpecificException.class,
+                () -> mClient.setValue(mProp));
+
+        assertThat(actualException).hasMessageThat().contains(Integer.toHexString(PROP));
+        assertThat(actualException).hasMessageThat().contains(Integer.toHexString(AREA_ID));
+    }
+
+    @Test
+    public void testSet_ok() throws Exception {
+        when(mIVehicle.set(isProperty(PROP))).thenReturn(StatusCode.OK);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/InputHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/InputHalServiceTest.java
index 5cce922..09c3d4a 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/InputHalServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/InputHalServiceTest.java
@@ -23,6 +23,7 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -32,7 +33,7 @@
 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
 import android.view.KeyEvent;
 
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.filters.RequiresDevice;
 
 import com.android.car.vehiclehal.test.VehiclePropConfigBuilder;
 
@@ -41,30 +42,27 @@
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 import java.util.function.LongSupplier;
 
-@RunWith(AndroidJUnit4.class)
+@RunWith(MockitoJUnitRunner.class)
 public class InputHalServiceTest {
-    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
-
     @Mock VehicleHal mVehicleHal;
     @Mock InputHalService.InputListener mInputListener;
     @Mock LongSupplier mUptimeSupplier;
 
     private static final VehiclePropConfig HW_KEY_INPUT_CONFIG =
             VehiclePropConfigBuilder.newBuilder(VehicleProperty.HW_KEY_INPUT).build();
+    private static final VehiclePropConfig HW_ROTARY_INPUT_CONFIG =
+            VehiclePropConfigBuilder.newBuilder(VehicleProperty.HW_ROTARY_INPUT).build();
     private static final int DISPLAY = 42;
 
     private enum Key { DOWN, UP }
@@ -90,7 +88,7 @@
 
         mInputHalService.setInputListener(mInputListener);
 
-        mInputHalService.handleHalEvents(
+        mInputHalService.onHalEvents(
                 ImmutableList.of(makeKeyPropValue(Key.DOWN, KeyEvent.KEYCODE_ENTER)));
         verify(mInputListener, never()).onKeyEvent(any(), anyInt());
     }
@@ -102,11 +100,37 @@
                 HW_KEY_INPUT_CONFIG,
                 VehiclePropConfigBuilder.newBuilder(VehicleProperty.CURRENT_GEAR).build());
 
-        Collection<VehiclePropConfig> takenProps =
-                mInputHalService.takeSupportedProperties(offeredProps);
+        mInputHalService.takeProperties(offeredProps);
 
-        assertThat(takenProps).containsExactly(HW_KEY_INPUT_CONFIG);
         assertThat(mInputHalService.isKeyInputSupported()).isTrue();
+        assertThat(mInputHalService.isRotaryInputSupported()).isFalse();
+    }
+
+    @Test
+    public void takesRotaryInputProperty() {
+        Set<VehiclePropConfig> offeredProps = ImmutableSet.of(
+                VehiclePropConfigBuilder.newBuilder(VehicleProperty.ABS_ACTIVE).build(),
+                HW_ROTARY_INPUT_CONFIG,
+                VehiclePropConfigBuilder.newBuilder(VehicleProperty.CURRENT_GEAR).build());
+
+        mInputHalService.takeProperties(offeredProps);
+
+        assertThat(mInputHalService.isRotaryInputSupported()).isTrue();
+        assertThat(mInputHalService.isKeyInputSupported()).isFalse();
+    }
+
+    @Test
+    public void takesKeyAndRotaryInputProperty() {
+        Set<VehiclePropConfig> offeredProps = ImmutableSet.of(
+                VehiclePropConfigBuilder.newBuilder(VehicleProperty.ABS_ACTIVE).build(),
+                HW_KEY_INPUT_CONFIG,
+                HW_ROTARY_INPUT_CONFIG,
+                VehiclePropConfigBuilder.newBuilder(VehicleProperty.CURRENT_GEAR).build());
+
+        mInputHalService.takeProperties(offeredProps);
+
+        assertThat(mInputHalService.isKeyInputSupported()).isTrue();
+        assertThat(mInputHalService.isRotaryInputSupported()).isTrue();
     }
 
     @Test
@@ -131,7 +155,7 @@
             return null;
         }).when(mInputListener).onKeyEvent(any(), eq(DISPLAY));
 
-        mInputHalService.handleHalEvents(
+        mInputHalService.onHalEvents(
                 ImmutableList.of(
                         makeKeyPropValue(Key.DOWN, KeyEvent.KEYCODE_ENTER),
                         makeKeyPropValue(Key.DOWN, KeyEvent.KEYCODE_MENU)));
@@ -184,6 +208,7 @@
     /**
      * Test for handling rotary knob event.
      */
+    @RequiresDevice
     @Test
     public void handlesRepeatedKeyWithIndents() {
         subscribeListener();
@@ -230,8 +255,78 @@
         assertThat(event.getRepeatCount()).isEqualTo(0);
     }
 
+    @Test
+    public void dispatchesRotaryEvent_singleVolumeUp_toListener() {
+        // TODO(b/151225008) Update this
+        /*
+        subscribeListener();
+
+        // KeyEvents get recycled, so we can't just use ArgumentCaptor#getAllValues here.
+        // We need to make a copy of the information we need at the time of the call.
+        List<KeyEvent> events = new ArrayList<>();
+        doAnswer(inv -> {
+            KeyEvent event = inv.getArgument(0);
+            events.add(event.copy());
+            return null;
+        }).when(mInputListener).onKeyEvent(any(), eq(DISPLAY));
+
+        long timestampNanos = 12345678901L;
+        mInputHalService.onHalEvents(ImmutableList.of(
+                makeRotaryPropValue(RotaryInputType.ROTARY_INPUT_TYPE_AUDIO_VOLUME, 1,
+                        timestampNanos, 0)));
+
+        long timestampMillis = timestampNanos / 1000000;
+        KeyEvent downEvent = events.get(0);
+        assertThat(downEvent.getKeyCode()).isEqualTo(KeyEvent.KEYCODE_VOLUME_UP);
+        assertThat(downEvent.getAction()).isEqualTo(KeyEvent.ACTION_DOWN);
+        assertThat(downEvent.getEventTime()).isEqualTo(timestampMillis);
+        KeyEvent upEvent = events.get(1);
+        assertThat(upEvent.getKeyCode()).isEqualTo(KeyEvent.KEYCODE_VOLUME_UP);
+        assertThat(upEvent.getAction()).isEqualTo(KeyEvent.ACTION_UP);
+        assertThat(upEvent.getEventTime()).isEqualTo(timestampMillis);
+
+        events.forEach(KeyEvent::recycle);*/
+    }
+
+    @Test
+    public void dispatchesRotaryEvent_multipleNavigatePrevious_toListener() {
+        // TODO(b/151225008) Update this
+        /*
+        subscribeListener();
+
+        // KeyEvents get recycled, so we can't just use ArgumentCaptor#getAllValues here.
+        // We need to make a copy of the information we need at the time of the call.
+        List<KeyEvent> events = new ArrayList<>();
+        doAnswer(inv -> {
+            KeyEvent event = inv.getArgument(0);
+            events.add(event.copy());
+            return null;
+        }).when(mInputListener).onKeyEvent(any(), eq(DISPLAY));
+
+        long timestampNanos = 12345678901L;
+        int deltaNanos = 876543210;
+        int numberOfDetents = 3;
+        mInputHalService.onHalEvents(ImmutableList.of(
+                makeRotaryPropValue(RotaryInputType.ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION,
+                        -numberOfDetents, timestampNanos, deltaNanos)));
+
+        for (int i = 0; i < numberOfDetents; i++) {
+            long timestampMillis = (timestampNanos + i * (long) deltaNanos) / 1000000;
+            KeyEvent downEvent = events.get(i * 2);
+            assertThat(downEvent.getKeyCode()).isEqualTo(KeyEvent.KEYCODE_NAVIGATE_PREVIOUS);
+            assertThat(downEvent.getAction()).isEqualTo(KeyEvent.ACTION_DOWN);
+            assertThat(downEvent.getEventTime()).isEqualTo(timestampMillis);
+            KeyEvent upEvent = events.get(i * 2 + 1);
+            assertThat(upEvent.getKeyCode()).isEqualTo(KeyEvent.KEYCODE_NAVIGATE_PREVIOUS);
+            assertThat(upEvent.getAction()).isEqualTo(KeyEvent.ACTION_UP);
+            assertThat(upEvent.getEventTime()).isEqualTo(timestampMillis);
+        }
+
+        events.forEach(KeyEvent::recycle);*/
+    }
+
     private void subscribeListener() {
-        mInputHalService.takeSupportedProperties(ImmutableSet.of(HW_KEY_INPUT_CONFIG));
+        mInputHalService.takeProperties(ImmutableSet.of(HW_KEY_INPUT_CONFIG));
         assertThat(mInputHalService.isKeyInputSupported()).isTrue();
 
         mInputHalService.setInputListener(mInputListener);
@@ -254,7 +349,7 @@
     private KeyEvent dispatchSingleEvent(Key action, int code) {
         ArgumentCaptor<KeyEvent> captor = ArgumentCaptor.forClass(KeyEvent.class);
         reset(mInputListener);
-        mInputHalService.handleHalEvents(ImmutableList.of(makeKeyPropValue(action, code)));
+        mInputHalService.onHalEvents(ImmutableList.of(makeKeyPropValue(action, code)));
         verify(mInputListener).onKeyEvent(captor.capture(), eq(DISPLAY));
         reset(mInputListener);
         return captor.getValue();
@@ -274,10 +369,24 @@
     private KeyEvent dispatchSingleEventWithIndents(int code, int indents) {
         ArgumentCaptor<KeyEvent> captor = ArgumentCaptor.forClass(KeyEvent.class);
         reset(mInputListener);
-        mInputHalService.handleHalEvents(
+        mInputHalService.onHalEvents(
                 ImmutableList.of(makeKeyPropValueWithIndents(code, indents)));
-        verify(mInputListener).onKeyEvent(captor.capture(), eq(DISPLAY));
+        verify(mInputListener, times(indents)).onKeyEvent(captor.capture(), eq(DISPLAY));
         reset(mInputListener);
         return captor.getValue();
     }
+
+    private VehiclePropValue makeRotaryPropValue(int rotaryInputType, int detents, long timestamp,
+            int delayBetweenDetents) {
+        VehiclePropValue v = new VehiclePropValue();
+        v.prop = VehicleProperty.HW_ROTARY_INPUT;
+        v.value.int32Values.add(rotaryInputType);
+        v.value.int32Values.add(detents);
+        v.value.int32Values.add(DISPLAY);
+        for (int i = 0; i < Math.abs(detents) - 1; i++) {
+            v.value.int32Values.add(delayBetweenDetents);
+        }
+        v.timestamp = timestamp;
+        return v;
+    }
 }
\ No newline at end of file
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/PropertyHalServiceIdsTest.java b/tests/carservice_unit_test/src/com/android/car/hal/PropertyHalServiceIdsTest.java
new file mode 100644
index 0000000..e128b19
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/hal/PropertyHalServiceIdsTest.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.hal;
+
+import android.car.Car;
+import android.car.VehicleHvacFanDirection;
+import android.car.VehiclePropertyIds;
+import android.hardware.automotive.vehicle.V2_0.VehicleGear;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
+import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
+import android.hardware.automotive.vehicle.V2_0.VehicleUnit;
+import android.hardware.automotive.vehicle.V2_0.VehicleVendorPermission;
+import android.os.SystemClock;
+import android.util.Log;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.car.vehiclehal.VehiclePropValueBuilder;
+
+import com.google.common.truth.Truth;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class PropertyHalServiceIdsTest {
+    @Rule
+    public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    private PropertyHalServiceIds mPropertyHalServiceIds;
+
+    private static final String TAG = PropertyHalServiceIdsTest.class.getSimpleName();
+    private static final int VENDOR_PROPERTY_1 = 0x21e01111;
+    private static final int VENDOR_PROPERTY_2 = 0x21e01112;
+    private static final int VENDOR_PROPERTY_3 = 0x21e01113;
+    private static final int VENDOR_PROPERTY_4 = 0x21e01114;
+    private static final int[] VENDOR_PROPERTY_IDS = {
+            VENDOR_PROPERTY_1, VENDOR_PROPERTY_2, VENDOR_PROPERTY_3, VENDOR_PROPERTY_4};
+    private static final int[] SYSTEM_PROPERTY_IDS = {VehiclePropertyIds.ENGINE_OIL_LEVEL,
+            VehiclePropertyIds.CURRENT_GEAR, VehiclePropertyIds.NIGHT_MODE,
+            VehiclePropertyIds.HVAC_FAN_SPEED, VehiclePropertyIds.DOOR_LOCK};
+    private static final List<Integer> CONFIG_ARRAY = new ArrayList<>();
+    private static final List<Integer> CONFIG_ARRAY_INVALID = new ArrayList<>();
+    //payload test
+    private static final VehiclePropValue GEAR_WITH_VALID_VALUE =
+            VehiclePropValueBuilder.newBuilder(VehicleProperty.GEAR_SELECTION)
+            .addIntValue(VehicleGear.GEAR_DRIVE)
+            .setTimestamp(SystemClock.elapsedRealtimeNanos()).build();
+    private static final VehiclePropValue GEAR_WITH_EXTRA_VALUE =
+            VehiclePropValueBuilder.newBuilder(VehicleProperty.GEAR_SELECTION)
+                    .addIntValue(VehicleGear.GEAR_DRIVE)
+                    .addIntValue(VehicleGear.GEAR_1)
+                    .setTimestamp(SystemClock.elapsedRealtimeNanos()).build();
+    private static final VehiclePropValue GEAR_WITH_INVALID_VALUE =
+            VehiclePropValueBuilder.newBuilder(VehicleProperty.GEAR_SELECTION)
+                    .addIntValue(VehicleUnit.KILOPASCAL)
+                    .setTimestamp(SystemClock.elapsedRealtimeNanos()).build();
+    private static final VehiclePropValue GEAR_WITH_INVALID_TYPE_VALUE =
+            VehiclePropValueBuilder.newBuilder(VehicleProperty.GEAR_SELECTION)
+                    .addFloatValue(1.0f)
+                    .setTimestamp(SystemClock.elapsedRealtimeNanos()).build();
+    private static final VehiclePropValue HVAC_FAN_DIRECTIONS_VALID =
+            VehiclePropValueBuilder.newBuilder(VehicleProperty.HVAC_FAN_DIRECTION)
+                    .addIntValue(VehicleHvacFanDirection.FACE | VehicleHvacFanDirection.FLOOR)
+                    .setTimestamp(SystemClock.elapsedRealtimeNanos()).build();
+    private static final VehiclePropValue HVAC_FAN_DIRECTIONS_INVALID =
+            VehiclePropValueBuilder.newBuilder(VehicleProperty.HVAC_FAN_DIRECTION)
+                    .addIntValue(VehicleHvacFanDirection.FACE | 0x100)
+                    .setTimestamp(SystemClock.elapsedRealtimeNanos()).build();
+    @Before
+    public void setUp() {
+        mPropertyHalServiceIds = new PropertyHalServiceIds();
+        // set up read permission and write permission to VENDOR_PROPERTY_1
+        CONFIG_ARRAY.add(VENDOR_PROPERTY_1);
+        CONFIG_ARRAY.add(VehicleVendorPermission.PERMISSION_DEFAULT);
+        CONFIG_ARRAY.add(VehicleVendorPermission.PERMISSION_NOT_ACCESSIBLE);
+        // set up read permission and write permission to VENDOR_PROPERTY_2
+        CONFIG_ARRAY.add(VENDOR_PROPERTY_2);
+        CONFIG_ARRAY.add(VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_ENGINE);
+        CONFIG_ARRAY.add(VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_ENGINE);
+        // set up read permission and write permission to VENDOR_PROPERTY_3
+        CONFIG_ARRAY.add(VENDOR_PROPERTY_3);
+        CONFIG_ARRAY.add(VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_INFO);
+        CONFIG_ARRAY.add(VehicleVendorPermission.PERMISSION_DEFAULT);
+
+        // set a invalid config
+        CONFIG_ARRAY_INVALID.add(VehiclePropertyIds.CURRENT_GEAR);
+        CONFIG_ARRAY_INVALID.add(VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_ENGINE);
+        CONFIG_ARRAY_INVALID.add(VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_ENGINE);
+    }
+
+    /**
+     * Test {@link PropertyHalServiceIds#getReadPermission(int)}
+     * and {@link PropertyHalServiceIds#getWritePermission(int)} for system properties
+     */
+    @Test
+    public void checkPermissionForSystemProperty() {
+        Assert.assertEquals(Car.PERMISSION_CAR_ENGINE_DETAILED,
+                mPropertyHalServiceIds.getReadPermission(VehiclePropertyIds.ENGINE_OIL_LEVEL));
+        Assert.assertNull(
+                mPropertyHalServiceIds.getWritePermission(VehiclePropertyIds.ENGINE_OIL_LEVEL));
+        Assert.assertEquals(Car.PERMISSION_CONTROL_CAR_CLIMATE,
+                mPropertyHalServiceIds.getReadPermission(VehiclePropertyIds.HVAC_FAN_SPEED));
+        Assert.assertEquals(Car.PERMISSION_CONTROL_CAR_CLIMATE,
+                mPropertyHalServiceIds.getWritePermission(VehiclePropertyIds.HVAC_FAN_SPEED));
+    }
+    /**
+     * Test {@link PropertyHalServiceIds#customizeVendorPermission(List)}
+     */
+    @Test
+    public void checkPermissionForVendorProperty() {
+        // test insert a valid config
+        mPropertyHalServiceIds.customizeVendorPermission(CONFIG_ARRAY);
+
+        Assert.assertEquals(Car.PERMISSION_VENDOR_EXTENSION,
+                mPropertyHalServiceIds.getReadPermission(VENDOR_PROPERTY_1));
+        Assert.assertNull(mPropertyHalServiceIds.getWritePermission(VENDOR_PROPERTY_1));
+
+        Assert.assertEquals(android.car.hardware.property
+                        .VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_ENGINE,
+                mPropertyHalServiceIds.getReadPermission(VENDOR_PROPERTY_2));
+        Assert.assertEquals(android.car.hardware.property
+                        .VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_ENGINE,
+                mPropertyHalServiceIds.getWritePermission(VENDOR_PROPERTY_2));
+
+        Assert.assertEquals(android.car.hardware.property
+                        .VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_INFO,
+                mPropertyHalServiceIds.getReadPermission(VENDOR_PROPERTY_3));
+        Assert.assertEquals(Car.PERMISSION_VENDOR_EXTENSION,
+                mPropertyHalServiceIds.getWritePermission(VENDOR_PROPERTY_3));
+
+        Assert.assertEquals(Car.PERMISSION_VENDOR_EXTENSION,
+                mPropertyHalServiceIds.getReadPermission(VENDOR_PROPERTY_4));
+        Assert.assertEquals(Car.PERMISSION_VENDOR_EXTENSION,
+                mPropertyHalServiceIds.getWritePermission(VENDOR_PROPERTY_4));
+
+        // test insert invalid config
+        try {
+            mPropertyHalServiceIds.customizeVendorPermission(CONFIG_ARRAY_INVALID);
+            Assert.fail("Insert system properties with vendor permissions");
+        } catch (IllegalArgumentException e) {
+            Log.v(TAG, e.getMessage());
+        }
+    }
+
+    /**
+     * Test {@link PropertyHalServiceIds#isSupportedProperty(int)}
+     */
+    @Test
+    public void checkVendorPropertyId() {
+        for (int vendorProp : VENDOR_PROPERTY_IDS) {
+            Assert.assertTrue(mPropertyHalServiceIds.isSupportedProperty(vendorProp));
+        }
+        for (int systemProp : SYSTEM_PROPERTY_IDS) {
+            Assert.assertTrue(mPropertyHalServiceIds.isSupportedProperty(systemProp));
+        }
+    }
+
+    /**
+     * Test {@link PropertyHalServiceIds#checkPayload(VehiclePropValue)}
+     */
+    @Test
+    public void testPayload() {
+        Truth.assertThat(mPropertyHalServiceIds.checkPayload(GEAR_WITH_VALID_VALUE)).isTrue();
+        Truth.assertThat(mPropertyHalServiceIds.checkPayload(GEAR_WITH_EXTRA_VALUE)).isFalse();
+        Truth.assertThat(mPropertyHalServiceIds.checkPayload(GEAR_WITH_INVALID_VALUE)).isFalse();
+        Truth.assertThat(mPropertyHalServiceIds.checkPayload(GEAR_WITH_INVALID_TYPE_VALUE))
+                .isFalse();
+
+        Truth.assertThat(mPropertyHalServiceIds.checkPayload(HVAC_FAN_DIRECTIONS_VALID)).isTrue();
+        Truth.assertThat(mPropertyHalServiceIds.checkPayload(HVAC_FAN_DIRECTIONS_INVALID))
+                .isFalse();
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java
new file mode 100644
index 0000000..1d1f9d0
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java
@@ -0,0 +1,1650 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.hal;
+
+import static android.car.VehiclePropertyIds.CREATE_USER;
+import static android.car.VehiclePropertyIds.CURRENT_GEAR;
+import static android.car.VehiclePropertyIds.INITIAL_USER_INFO;
+import static android.car.VehiclePropertyIds.REMOVE_USER;
+import static android.car.VehiclePropertyIds.SWITCH_USER;
+import static android.car.VehiclePropertyIds.USER_IDENTIFICATION_ASSOCIATION;
+import static android.car.test.mocks.CarArgumentMatchers.isProperty;
+import static android.car.test.mocks.CarArgumentMatchers.isPropertyWithValues;
+import static android.car.test.util.VehicleHalTestingHelper.newConfig;
+import static android.car.test.util.VehicleHalTestingHelper.newSubscribableConfig;
+import static android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType.COLD_BOOT;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue.ASSOCIATE_CURRENT_USER;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.CUSTOM_1;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.KEY_FOB;
+import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationValue.ASSOCIATED_CURRENT_USER;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.annotation.NonNull;
+import android.car.hardware.property.VehicleHalStatusCode;
+import android.car.userlib.HalCallback;
+import android.car.userlib.UserHalHelper;
+import android.hardware.automotive.vehicle.V2_0.CreateUserRequest;
+import android.hardware.automotive.vehicle.V2_0.CreateUserResponse;
+import android.hardware.automotive.vehicle.V2_0.CreateUserStatus;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
+import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
+import android.hardware.automotive.vehicle.V2_0.SwitchUserMessageType;
+import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
+import android.hardware.automotive.vehicle.V2_0.SwitchUserResponse;
+import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
+import android.hardware.automotive.vehicle.V2_0.UserFlags;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociation;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetAssociation;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
+import android.hardware.automotive.vehicle.V2_0.UserInfo;
+import android.hardware.automotive.vehicle.V2_0.UsersInfo;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.ServiceSpecificException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.car.CarLocalServices;
+import com.android.car.user.CarUserService;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+@RunWith(MockitoJUnitRunner.class)
+public final class UserHalServiceTest {
+
+    private static final String TAG = UserHalServiceTest.class.getSimpleName();
+
+    /**
+     * Timeout passed to {@link UserHalService} methods
+     */
+    private static final int TIMEOUT_MS = 50;
+
+    /**
+     * Timeout for {@link GenericHalCallback#assertCalled()} for tests where the HAL is supposed to
+     * return something - it's a short time so it doesn't impact the test duration.
+     */
+    private static final int CALLBACK_TIMEOUT_SUCCESS = TIMEOUT_MS + 50;
+
+    /**
+     * Timeout for {@link GenericHalCallback#assertCalled()} for tests where the HAL is not supposed
+     * to return anything - it's a slightly longer to make sure the test doesn't fail prematurely.
+     */
+    private static final int CALLBACK_TIMEOUT_TIMEOUT = TIMEOUT_MS + 450;
+
+    // Used when crafting a request property - the real value will be set by the mock.
+    private static final int REQUEST_ID_PLACE_HOLDER = 1111;
+
+    private static final int DEFAULT_REQUEST_ID = 2222;
+
+    private static final int DEFAULT_USER_ID = 333;
+    private static final int DEFAULT_USER_FLAGS = 444;
+
+    private static final int INITIAL_USER_INFO_RESPONSE_ACTION = 108;
+
+    @Mock
+    private VehicleHal mVehicleHal;
+    @Mock
+    private CarUserService mCarUserService;
+
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+    private final UserInfo mUser0 = new UserInfo();
+    private final UserInfo mUser10 = new UserInfo();
+
+    private final UsersInfo mUsersInfo = new UsersInfo();
+
+    // Must be a spy so we can mock getNextRequestId()
+    private UserHalService mUserHalService;
+
+    @Before
+    public void setFixtures() {
+        mUserHalService = spy(new UserHalService(mVehicleHal, mHandler));
+        // Needs at least one property, otherwise isSupported() and isUserAssociationSupported()
+        // will return false
+        mUserHalService.takeProperties(Arrays.asList(newSubscribableConfig(INITIAL_USER_INFO),
+                newSubscribableConfig(CREATE_USER), newSubscribableConfig(REMOVE_USER),
+                newSubscribableConfig(SWITCH_USER),
+                newSubscribableConfig(USER_IDENTIFICATION_ASSOCIATION)));
+
+        mUser0.userId = 0;
+        mUser0.flags = 100;
+        mUser10.userId = 10;
+        mUser10.flags = 110;
+
+        mUsersInfo.currentUser = mUser0;
+        mUsersInfo.numberUsers = 2;
+        mUsersInfo.existingUsers = new ArrayList<>(2);
+        mUsersInfo.existingUsers.add(mUser0);
+        mUsersInfo.existingUsers.add(mUser10);
+
+        CarLocalServices.addService(CarUserService.class, mCarUserService);
+    }
+
+    @After
+    public void clearFixtures() {
+        CarLocalServices.removeServiceForTest(CarUserService.class);
+    }
+
+    @Test
+    public void testTakeSupportedProperties_supportedNoProperties() {
+        // Cannot use mUserHalService because it's already set with supported properties
+        UserHalService myHalService = new UserHalService(mVehicleHal);
+
+        myHalService.takeProperties(Collections.emptyList());
+        assertThat(myHalService.isSupported()).isFalse();
+        assertThat(myHalService.isUserAssociationSupported()).isFalse();
+    }
+
+    @Test
+    public void testTakeSupportedProperties_supportedFewProperties() {
+        // Cannot use mUserHalService because it's already set with supported properties
+        UserHalService myHalService = new UserHalService(mVehicleHal);
+        myHalService.takeProperties(Arrays.asList(newSubscribableConfig(INITIAL_USER_INFO),
+                newSubscribableConfig(CREATE_USER), newSubscribableConfig(REMOVE_USER)));
+
+        assertThat(myHalService.isSupported()).isFalse();
+        assertThat(myHalService.isUserAssociationSupported()).isFalse();
+    }
+
+    @Test
+    public void testTakeSupportedProperties_supportedAllCoreProperties() {
+        // Cannot use mUserHalService because it's already set with supported properties
+        UserHalService myHalService = new UserHalService(mVehicleHal);
+        myHalService.takeProperties(Arrays.asList(newSubscribableConfig(INITIAL_USER_INFO),
+                newSubscribableConfig(CREATE_USER), newSubscribableConfig(REMOVE_USER),
+                newSubscribableConfig(SWITCH_USER)));
+
+        assertThat(myHalService.isSupported()).isTrue();
+        assertThat(myHalService.isUserAssociationSupported()).isFalse();
+    }
+
+    @Test
+    public void testTakeSupportedProperties_supportedAllProperties() {
+        // Cannot use mUserHalService because it's already set with supported properties
+        UserHalService myHalService = new UserHalService(mVehicleHal);
+        myHalService.takeProperties(Arrays.asList(newSubscribableConfig(INITIAL_USER_INFO),
+                newSubscribableConfig(CREATE_USER), newSubscribableConfig(REMOVE_USER),
+                newSubscribableConfig(SWITCH_USER),
+                newSubscribableConfig(USER_IDENTIFICATION_ASSOCIATION)));
+
+        assertThat(myHalService.isSupported()).isTrue();
+        assertThat(myHalService.isUserAssociationSupported()).isTrue();
+    }
+
+    @Test
+    public void testTakeSupportedPropertiesAndInit() {
+        // Cannot use mUserHalService because it's already set with supported properties
+        UserHalService myHalService = new UserHalService(mVehicleHal);
+        VehiclePropConfig unsupportedConfig = newConfig(CURRENT_GEAR);
+
+        myHalService.takeProperties(Arrays.asList(newSubscribableConfig(INITIAL_USER_INFO),
+                newSubscribableConfig(CREATE_USER), newSubscribableConfig(REMOVE_USER),
+                newSubscribableConfig(SWITCH_USER), unsupportedConfig,
+                newSubscribableConfig(USER_IDENTIFICATION_ASSOCIATION)));
+
+
+        // Ideally there should be 2 test methods (one for takeSupportedProperties() and one for
+        // init()), but on "real life" VehicleHal calls these 2 methods in sequence, and the latter
+        // depends on the properties set by the former, so it's ok to test both here...
+        myHalService.init();
+        verify(mVehicleHal).subscribeProperty(myHalService, INITIAL_USER_INFO);
+        verify(mVehicleHal).subscribeProperty(myHalService, CREATE_USER);
+        verify(mVehicleHal).subscribeProperty(myHalService, REMOVE_USER);
+        verify(mVehicleHal).subscribeProperty(myHalService, SWITCH_USER);
+        verify(mVehicleHal).subscribeProperty(myHalService, USER_IDENTIFICATION_ASSOCIATION);
+    }
+
+    @Test
+    public void testSupportedProperties() {
+        assertThat(mUserHalService.getAllSupportedProperties()).asList().containsExactly(
+                INITIAL_USER_INFO, CREATE_USER, REMOVE_USER, SWITCH_USER,
+                USER_IDENTIFICATION_ASSOCIATION);
+    }
+
+    @Test
+    public void testGetUserInfo_noHalSupported() {
+        // Cannot use mUserHalService because it's already set with supported properties
+        UserHalService myHalService = new UserHalService(mVehicleHal);
+
+        assertThrows(IllegalStateException.class, () -> myHalService.getInitialUserInfo(COLD_BOOT,
+                TIMEOUT_MS, mUsersInfo, noOpCallback()));
+    }
+
+    @Test
+    public void testGetUserInfo_invalidTimeout() {
+        assertThrows(IllegalArgumentException.class, () ->
+                mUserHalService.getInitialUserInfo(COLD_BOOT, 0, mUsersInfo, noOpCallback()));
+        assertThrows(IllegalArgumentException.class, () ->
+                mUserHalService.getInitialUserInfo(COLD_BOOT, -1, mUsersInfo, noOpCallback()));
+    }
+
+    @Test
+    public void testGetUserInfo_noUsersInfo() {
+        assertThrows(NullPointerException.class, () ->
+                mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, null, noOpCallback()));
+    }
+
+    @Test
+    public void testGetUserInfo_noCallback() {
+        assertThrows(NullPointerException.class,
+                () -> mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS,
+                        mUsersInfo, null));
+    }
+
+    @Test
+    public void testGetUserInfo_halSetTimedOut() throws Exception {
+        replySetPropertyWithTimeoutException(INITIAL_USER_INFO);
+
+        GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+        mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+                callback);
+
+        callback.assertCalled();
+        assertCallbackStatus(callback, HalCallback.STATUS_HAL_SET_TIMEOUT);
+        assertThat(callback.response).isNull();
+
+        // Make sure the pending request was removed
+        SystemClock.sleep(CALLBACK_TIMEOUT_TIMEOUT);
+        callback.assertNotCalledAgain();
+    }
+
+    @Test
+    public void testGetUserInfo_halDidNotReply() throws Exception {
+        GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+        mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+                callback);
+
+        callback.assertCalled();
+        assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
+        assertThat(callback.response).isNull();
+    }
+
+    @Test
+    public void testGetUserInfo_secondCallFailWhilePending() throws Exception {
+        GenericHalCallback<InitialUserInfoResponse> callback1 = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+        GenericHalCallback<InitialUserInfoResponse> callback2 = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+        mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+                callback1);
+        mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+                callback2);
+
+        callback1.assertCalled();
+        assertCallbackStatus(callback1, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
+        assertThat(callback1.response).isNull();
+
+        callback2.assertCalled();
+        assertCallbackStatus(callback2, HalCallback.STATUS_CONCURRENT_OPERATION);
+        assertThat(callback1.response).isNull();
+    }
+
+    @Test
+    public void testGetUserInfo_halReplyWithWrongRequestId() throws Exception {
+        VehiclePropValue propResponse = UserHalHelper.createPropRequest(INITIAL_USER_INFO,
+                    REQUEST_ID_PLACE_HOLDER, INITIAL_USER_INFO_RESPONSE_ACTION);
+
+        replySetPropertyWithOnChangeEvent(INITIAL_USER_INFO, propResponse,
+                /* rightRequestId= */ false);
+
+        GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+        mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+                callback);
+
+        callback.assertCalled();
+        assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
+        assertThat(callback.response).isNull();
+    }
+
+    @Test
+    public void testGetUserInfo_halReturnedInvalidAction() throws Exception {
+        VehiclePropValue propResponse = UserHalHelper.createPropRequest(INITIAL_USER_INFO,
+                    REQUEST_ID_PLACE_HOLDER, INITIAL_USER_INFO_RESPONSE_ACTION);
+
+        AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent(
+                INITIAL_USER_INFO, propResponse, /* rightRequestId= */ true);
+
+        GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_SUCCESS);
+        mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+                callback);
+
+        callback.assertCalled();
+
+        // Make sure the arguments were properly converted
+        assertInitialUserInfoSetRequest(reqCaptor.get(), COLD_BOOT);
+
+        // Assert response
+        assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE);
+        assertThat(callback.response).isNull();
+    }
+
+    @Test
+    public void testGetUserInfo_successDefault() throws Exception {
+        VehiclePropValue propResponse = UserHalHelper.createPropRequest(INITIAL_USER_INFO,
+                    REQUEST_ID_PLACE_HOLDER, InitialUserInfoResponseAction.DEFAULT);
+
+        AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent(
+                INITIAL_USER_INFO, propResponse, /* rightRequestId= */ true);
+
+        GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_SUCCESS);
+        mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+                callback);
+
+        callback.assertCalled();
+
+        // Make sure the arguments were properly converted
+        assertInitialUserInfoSetRequest(reqCaptor.get(), COLD_BOOT);
+
+        // Assert response
+        assertCallbackStatus(callback, HalCallback.STATUS_OK);
+        InitialUserInfoResponse actualResponse = callback.response;
+        assertThat(actualResponse.action).isEqualTo(InitialUserInfoResponseAction.DEFAULT);
+        assertThat(actualResponse.userNameToCreate).isEmpty();
+        assertThat(actualResponse.userToSwitchOrCreate).isNotNull();
+        assertThat(actualResponse.userToSwitchOrCreate.userId).isEqualTo(UserHandle.USER_NULL);
+        assertThat(actualResponse.userToSwitchOrCreate.flags).isEqualTo(UserFlags.NONE);
+    }
+
+    @Test
+    public void testGetUserInfo_successSwitchUser() throws Exception {
+        int userIdToSwitch = 42;
+        VehiclePropValue propResponse = UserHalHelper.createPropRequest(INITIAL_USER_INFO,
+                    REQUEST_ID_PLACE_HOLDER, InitialUserInfoResponseAction.SWITCH);
+        propResponse.value.int32Values.add(userIdToSwitch);
+
+        AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent(
+                INITIAL_USER_INFO, propResponse, /* rightRequestId= */ true);
+
+        GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_SUCCESS);
+        mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+                callback);
+
+        callback.assertCalled();
+
+        // Make sure the arguments were properly converted
+        assertInitialUserInfoSetRequest(reqCaptor.get(), COLD_BOOT);
+
+        assertCallbackStatus(callback, HalCallback.STATUS_OK);
+        InitialUserInfoResponse actualResponse = callback.response;
+        assertThat(actualResponse.action).isEqualTo(InitialUserInfoResponseAction.SWITCH);
+        assertThat(actualResponse.userNameToCreate).isEmpty();
+        UserInfo userToSwitch = actualResponse.userToSwitchOrCreate;
+        assertThat(userToSwitch).isNotNull();
+        assertThat(userToSwitch.userId).isEqualTo(userIdToSwitch);
+        assertThat(userToSwitch.flags).isEqualTo(UserFlags.NONE);
+    }
+
+    @Test
+    public void testGetUserInfo_successCreateUser() throws Exception {
+        int newUserFlags = 108;
+        String newUserName = "Groot";
+        VehiclePropValue propResponse = UserHalHelper.createPropRequest(INITIAL_USER_INFO,
+                    REQUEST_ID_PLACE_HOLDER, InitialUserInfoResponseAction.CREATE);
+        propResponse.value.int32Values.add(666); // userId (not used)
+        propResponse.value.int32Values.add(newUserFlags);
+        propResponse.value.stringValue = "||" + newUserName;
+
+        AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent(
+                INITIAL_USER_INFO, propResponse, /* rightRequestId= */ true);
+
+        GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_SUCCESS);
+        mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+                callback);
+
+        callback.assertCalled();
+
+        // Make sure the arguments were properly converted
+        assertInitialUserInfoSetRequest(reqCaptor.get(), COLD_BOOT);
+
+        assertCallbackStatus(callback, HalCallback.STATUS_OK);
+        assertThat(callback.status).isEqualTo(HalCallback.STATUS_OK);
+        InitialUserInfoResponse actualResponse = callback.response;
+        assertThat(actualResponse.action).isEqualTo(InitialUserInfoResponseAction.CREATE);
+        assertThat(actualResponse.userLocales).isEmpty();
+        assertThat(actualResponse.userNameToCreate).isEqualTo(newUserName);
+        UserInfo newUser = actualResponse.userToSwitchOrCreate;
+        assertThat(newUser).isNotNull();
+        assertThat(newUser.userId).isEqualTo(UserHandle.USER_NULL);
+        assertThat(newUser.flags).isEqualTo(newUserFlags);
+    }
+
+    @Test
+    public void testGetUserInfo_twoSuccessfulCalls() throws Exception {
+        testGetUserInfo_successDefault();
+        testGetUserInfo_successDefault();
+    }
+
+    @Test
+    public void testSwitchUser_noHalSupported() {
+        // Cannot use mUserHalService because it's already set with supported properties
+        UserHalService myHalService = new UserHalService(mVehicleHal);
+
+        assertThrows(IllegalStateException.class,
+                () -> myHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo),
+                        TIMEOUT_MS, noOpCallback()));
+    }
+
+    @Test
+    public void testSwitchUser_invalidTimeout() {
+        assertThrows(IllegalArgumentException.class, () -> mUserHalService
+                .switchUser(createUserSwitchRequest(mUser10, mUsersInfo), 0, noOpCallback()));
+        assertThrows(IllegalArgumentException.class, () -> mUserHalService
+                .switchUser(createUserSwitchRequest(mUser10, mUsersInfo), -1, noOpCallback()));
+    }
+
+    @Test
+    public void testSwitchUser_noUsersInfo() {
+        assertThrows(IllegalArgumentException.class, () -> mUserHalService
+                .switchUser(createUserSwitchRequest(mUser10, null), TIMEOUT_MS, noOpCallback()));
+    }
+
+    @Test
+    public void testSwitchUser_noCallback() {
+        assertThrows(NullPointerException.class, () -> mUserHalService
+                .switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS, null));
+    }
+
+    @Test
+    public void testSwitchUser_nullRequest() {
+        assertThrows(NullPointerException.class, () -> mUserHalService
+                .switchUser(null, TIMEOUT_MS, noOpCallback()));
+    }
+
+    @Test
+    public void testSwitchUser_noTarget() {
+        assertThrows(NullPointerException.class, () -> mUserHalService
+                .switchUser(createUserSwitchRequest(null, mUsersInfo), TIMEOUT_MS, noOpCallback()));
+    }
+
+    @Test
+    public void testSwitchUser_halSetTimedOut() throws Exception {
+        replySetPropertyWithTimeoutException(SWITCH_USER);
+
+        GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+                callback);
+
+        callback.assertCalled();
+        assertCallbackStatus(callback, HalCallback.STATUS_HAL_SET_TIMEOUT);
+        assertThat(callback.response).isNull();
+
+        // Make sure the pending request was removed
+        SystemClock.sleep(CALLBACK_TIMEOUT_TIMEOUT);
+        callback.assertNotCalledAgain();
+    }
+
+    @Test
+    public void testSwitchUser_halDidNotReply() throws Exception {
+        GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+                callback);
+
+        callback.assertCalled();
+        assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
+        assertThat(callback.response).isNull();
+    }
+
+    @Test
+    public void testSwitchUser_halReplyWithWrongRequestId() throws Exception {
+        VehiclePropValue propResponse = UserHalHelper.createPropRequest(SWITCH_USER,
+                    REQUEST_ID_PLACE_HOLDER, InitialUserInfoResponseAction.SWITCH);
+
+        replySetPropertyWithOnChangeEvent(SWITCH_USER, propResponse,
+                /* rightRequestId= */ false);
+
+        GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+                callback);
+
+        callback.assertCalled();
+        assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
+        assertThat(callback.response).isNull();
+    }
+
+    @Test
+    public void testSwitchUser_halReturnedInvalidMessageType() throws Exception {
+        VehiclePropValue propResponse = UserHalHelper.createPropRequest(SWITCH_USER,
+                REQUEST_ID_PLACE_HOLDER, SwitchUserMessageType.LEGACY_ANDROID_SWITCH);
+        propResponse.value.int32Values.add(SwitchUserStatus.SUCCESS);
+
+        AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent(
+                SWITCH_USER, propResponse, /* rightRequestId= */ true);
+
+        GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_SUCCESS);
+        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+                callback);
+
+        callback.assertCalled();
+
+        // Make sure the arguments were properly converted
+        assertHalSetSwitchUserRequest(reqCaptor.get(), SwitchUserMessageType.ANDROID_SWITCH,
+                mUser10);
+
+        // Assert response
+        assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE);
+        assertThat(callback.response).isNull();
+    }
+
+    @Test
+    public void testSwitchUser_success() throws Exception {
+        VehiclePropValue propResponse = UserHalHelper.createPropRequest(SWITCH_USER,
+                    REQUEST_ID_PLACE_HOLDER, SwitchUserMessageType.VEHICLE_RESPONSE);
+        propResponse.value.int32Values.add(SwitchUserStatus.SUCCESS);
+
+        AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent(
+                SWITCH_USER, propResponse, /* rightRequestId= */ true);
+
+        GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_SUCCESS);
+        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+                callback);
+
+        callback.assertCalled();
+
+        // Make sure the arguments were properly converted
+        assertHalSetSwitchUserRequest(reqCaptor.get(), SwitchUserMessageType.ANDROID_SWITCH,
+                mUser10);
+
+        // Assert response
+        assertCallbackStatus(callback, HalCallback.STATUS_OK);
+        SwitchUserResponse actualResponse = callback.response;
+        assertThat(actualResponse.status).isEqualTo(SwitchUserStatus.SUCCESS);
+        assertThat(actualResponse.messageType).isEqualTo(SwitchUserMessageType.VEHICLE_RESPONSE);
+        assertThat(actualResponse.errorMessage).isEmpty();
+    }
+
+    @Test
+    public void testSwitchUser_failure() throws Exception {
+        VehiclePropValue propResponse = UserHalHelper.createPropRequest(SWITCH_USER,
+                    REQUEST_ID_PLACE_HOLDER, SwitchUserMessageType.VEHICLE_RESPONSE);
+        propResponse.value.int32Values.add(SwitchUserStatus.FAILURE);
+        propResponse.value.stringValue = "D'OH!";
+
+        AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent(
+                SWITCH_USER, propResponse, /* rightRequestId= */ true);
+
+        GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_SUCCESS);
+        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+                callback);
+
+        callback.assertCalled();
+
+        // Make sure the arguments were properly converted
+        assertHalSetSwitchUserRequest(reqCaptor.get(), SwitchUserMessageType.ANDROID_SWITCH,
+                mUser10);
+
+        // Assert response
+        assertCallbackStatus(callback, HalCallback.STATUS_OK);
+        SwitchUserResponse actualResponse = callback.response;
+        assertThat(actualResponse.status).isEqualTo(SwitchUserStatus.FAILURE);
+        assertThat(actualResponse.messageType).isEqualTo(SwitchUserMessageType.VEHICLE_RESPONSE);
+        assertThat(actualResponse.errorMessage).isEqualTo("D'OH!");
+    }
+
+    @Test
+    public void testSwitchUser_secondCallFailWhilePending() throws Exception {
+        GenericHalCallback<SwitchUserResponse> callback1 = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+        GenericHalCallback<SwitchUserResponse> callback2 = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+                callback1);
+        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+                callback2);
+
+        callback1.assertCalled();
+        assertCallbackStatus(callback1, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
+        assertThat(callback1.response).isNull();
+
+        callback2.assertCalled();
+        assertCallbackStatus(callback2, HalCallback.STATUS_CONCURRENT_OPERATION);
+        assertThat(callback1.response).isNull();
+    }
+
+    @Test
+    public void testSwitchUser_halReturnedInvalidStatus() throws Exception {
+        VehiclePropValue propResponse = UserHalHelper.createPropRequest(SWITCH_USER,
+                    REQUEST_ID_PLACE_HOLDER, SwitchUserMessageType.VEHICLE_RESPONSE);
+        propResponse.value.int32Values.add(/*status =*/ 110); // an invalid status
+
+        AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent(
+                SWITCH_USER, propResponse, /* rightRequestId= */ true);
+
+        GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_SUCCESS);
+        mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+                callback);
+
+        callback.assertCalled();
+
+        // Make sure the arguments were properly converted
+        assertHalSetSwitchUserRequest(reqCaptor.get(), SwitchUserMessageType.ANDROID_SWITCH,
+                mUser10);
+
+        // Assert response
+        assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE);
+        assertThat(callback.response).isNull();
+    }
+
+    @Test
+    public void testUserSwitch_OEMRequest_success() throws Exception {
+        int requestId = -4;
+        int targetUserId = 11;
+        VehiclePropValue propResponse = UserHalHelper.createPropRequest(SWITCH_USER,
+                requestId, SwitchUserMessageType.VEHICLE_REQUEST);
+
+        propResponse.value.int32Values.add(targetUserId);
+
+        mUserHalService.onHalEvents(Arrays.asList(propResponse));
+        waitForHandler();
+
+        verify(mCarUserService).switchAndroidUserFromHal(requestId, targetUserId);
+    }
+
+    @Test
+    public void testUserSwitch_OEMRequest_failure_positiveRequestId() throws Exception {
+        int requestId = 4;
+        int targetUserId = 11;
+        VehiclePropValue propResponse = UserHalHelper.createPropRequest(SWITCH_USER,
+                requestId, SwitchUserMessageType.VEHICLE_REQUEST);
+        propResponse.value.int32Values.add(targetUserId);
+
+        mUserHalService.onHalEvents(Arrays.asList(propResponse));
+        waitForHandler();
+
+        verify(mCarUserService, never()).switchAndroidUserFromHal(anyInt(), anyInt());
+    }
+
+    @Test
+    public void testPostSwitchResponse_noHalSupported() {
+        // Cannot use mUserHalService because it's already set with supported properties
+        UserHalService myHalService = new UserHalService(mVehicleHal);
+
+        assertThrows(IllegalStateException.class,
+                () -> myHalService.postSwitchResponse(new SwitchUserRequest()));
+    }
+
+    @Test
+    public void testPostSwitchResponse_nullRequest() {
+        assertThrows(NullPointerException.class, () -> mUserHalService.postSwitchResponse(null));
+    }
+
+    @Test
+    public void testPostSwitchResponse_noUsersInfo() {
+        SwitchUserRequest request = createUserSwitchRequest(mUser10, null);
+        request.requestId = 42;
+        assertThrows(IllegalArgumentException.class,
+                () -> mUserHalService.postSwitchResponse(request));
+    }
+
+    @Test
+    public void testPostSwitchResponse_HalCalledWithCorrectProp() {
+        SwitchUserRequest request = createUserSwitchRequest(mUser10, mUsersInfo);
+        request.requestId = 42;
+        mUserHalService.postSwitchResponse(request);
+        ArgumentCaptor<VehiclePropValue> propCaptor =
+                ArgumentCaptor.forClass(VehiclePropValue.class);
+        verify(mVehicleHal).set(propCaptor.capture());
+        VehiclePropValue prop = propCaptor.getValue();
+        assertHalSetSwitchUserRequest(prop, SwitchUserMessageType.ANDROID_POST_SWITCH, mUser10);
+    }
+
+    @Test
+    public void testLegacyUserSwitch_nullRequest() {
+        assertThrows(NullPointerException.class, () -> mUserHalService.legacyUserSwitch(null));
+    }
+
+    @Test
+    public void testLegacyUserSwitch_noMessageType() {
+        SwitchUserRequest request = new SwitchUserRequest();
+
+        assertThrows(IllegalArgumentException.class,
+                () -> mUserHalService.legacyUserSwitch(request));
+    }
+
+    @Test
+    public void testLegacyUserSwitch_noTargetUserInfo() {
+        SwitchUserRequest request = new SwitchUserRequest();
+        request.messageType = SwitchUserMessageType.ANDROID_SWITCH;
+
+        assertThrows(IllegalArgumentException.class,
+                () -> mUserHalService.legacyUserSwitch(request));
+    }
+
+    @Test
+    public void testRemoveUser_noHalSupported() {
+        // Cannot use mUserHalService because it's already set with supported properties
+        UserHalService myHalService = new UserHalService(mVehicleHal);
+
+        assertThrows(IllegalStateException.class,
+                () -> myHalService.removeUser(new RemoveUserRequest()));
+    }
+
+    @Test
+    public void testRemoveUser_nullRequest() {
+        RemoveUserRequest request = null;
+
+        assertThrows(NullPointerException.class,
+                () -> mUserHalService.removeUser(request));
+    }
+
+    @Test
+    public void testRemoveUser_noRequestId() {
+        RemoveUserRequest request = new RemoveUserRequest();
+
+        assertThrows(IllegalArgumentException.class,
+                () -> mUserHalService.removeUser(request));
+    }
+
+    @Test
+    public void testRemoveUser_noRemovedUserInfo() {
+        RemoveUserRequest request = new RemoveUserRequest();
+        request.requestId = 1;
+
+        assertThrows(IllegalArgumentException.class,
+                () -> mUserHalService.removeUser(request));
+    }
+
+    @Test
+    public void testRemoveUser_noUsersInfo() {
+        RemoveUserRequest request = new RemoveUserRequest();
+        request.requestId = 1;
+        request.removedUserInfo = mUser10;
+
+        assertThrows(IllegalArgumentException.class,
+                () -> mUserHalService.removeUser(request));
+    }
+
+    @Test
+    public void testRemoveUser_HalCalledWithCorrectProp() {
+        RemoveUserRequest request = new RemoveUserRequest();
+        request.removedUserInfo = mUser10;
+        request.usersInfo = mUsersInfo;
+        ArgumentCaptor<VehiclePropValue> propCaptor =
+                ArgumentCaptor.forClass(VehiclePropValue.class);
+
+        mUserHalService.removeUser(request);
+
+        verify(mVehicleHal).set(propCaptor.capture());
+        assertHalSetRemoveUserRequest(propCaptor.getValue(), mUser10);
+    }
+
+    @Test
+    public void testLegacyUserSwitch_noHalSupported() {
+        // Cannot use mUserHalService because it's already set with supported properties
+        UserHalService myHalService = new UserHalService(mVehicleHal);
+
+        assertThrows(IllegalStateException.class,
+                () -> myHalService.legacyUserSwitch(new SwitchUserRequest()));
+    }
+
+    @Test
+    public void testLegacyUserSwitch_noUsersInfo() {
+        SwitchUserRequest request = new SwitchUserRequest();
+        request.messageType = SwitchUserMessageType.ANDROID_SWITCH;
+        request.targetUser = mUser10;
+
+        assertThrows(IllegalArgumentException.class,
+                () -> mUserHalService.legacyUserSwitch(request));
+    }
+
+    @Test
+    public void testLegacyUserSwitch_HalCalledWithCorrectProp() {
+        SwitchUserRequest request = new SwitchUserRequest();
+        request.messageType = SwitchUserMessageType.LEGACY_ANDROID_SWITCH;
+        request.targetUser = mUser10;
+        request.usersInfo = mUsersInfo;
+
+        mUserHalService.legacyUserSwitch(request);
+        ArgumentCaptor<VehiclePropValue> propCaptor =
+                ArgumentCaptor.forClass(VehiclePropValue.class);
+        verify(mVehicleHal).set(propCaptor.capture());
+        VehiclePropValue prop = propCaptor.getValue();
+        assertHalSetSwitchUserRequest(prop, SwitchUserMessageType.LEGACY_ANDROID_SWITCH,
+                mUser10);
+    }
+
+    @Test
+    public void testCreateUser_noHalSupported() {
+        // Cannot use mUserHalService because it's already set with supported properties
+        UserHalService myHalService = new UserHalService(mVehicleHal);
+
+        assertThrows(IllegalStateException.class,
+                () -> myHalService.createUser(new CreateUserRequest(), TIMEOUT_MS, noOpCallback()));
+    }
+
+    @Test
+    public void testCreateUser_noRequest() {
+        assertThrows(NullPointerException.class, () -> mUserHalService
+                .createUser(null, TIMEOUT_MS, noOpCallback()));
+    }
+
+    @Test
+    public void testCreateUser_invalidTimeout() {
+        assertThrows(IllegalArgumentException.class, () -> mUserHalService
+                .createUser(new CreateUserRequest(), 0, noOpCallback()));
+        assertThrows(IllegalArgumentException.class, () -> mUserHalService
+                .createUser(new CreateUserRequest(), -1, noOpCallback()));
+    }
+
+    @Test
+    public void testCreateUser_noCallback() {
+        CreateUserRequest request = new CreateUserRequest();
+        request.newUserInfo.userId = 10;
+        request.usersInfo.existingUsers.add(request.newUserInfo);
+
+        assertThrows(NullPointerException.class, () -> mUserHalService
+                .createUser(request, TIMEOUT_MS, null));
+    }
+
+    /**
+     * Creates a valid {@link CreateUserRequest} for tests that doesn't check its contents.
+     */
+    @NonNull
+    private CreateUserRequest newValidCreateUserRequest() {
+        CreateUserRequest request = new CreateUserRequest();
+        request.newUserInfo = mUser10;
+        request.usersInfo = mUsersInfo;
+        return request;
+    }
+
+    @Test
+    public void testCreateUser_halSetTimedOut() throws Exception {
+        replySetPropertyWithTimeoutException(CREATE_USER);
+
+        GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+        mUserHalService.createUser(newValidCreateUserRequest(), TIMEOUT_MS, callback);
+
+        callback.assertCalled();
+        assertCallbackStatus(callback, HalCallback.STATUS_HAL_SET_TIMEOUT);
+        assertThat(callback.response).isNull();
+
+        // Make sure the pending request was removed
+        SystemClock.sleep(CALLBACK_TIMEOUT_TIMEOUT);
+        callback.assertNotCalledAgain();
+    }
+
+    @Test
+    public void testCreateUser_halDidNotReply() throws Exception {
+        GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+        mUserHalService.createUser(newValidCreateUserRequest(), TIMEOUT_MS, callback);
+
+        callback.assertCalled();
+        assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
+        assertThat(callback.response).isNull();
+    }
+
+    @Test
+    public void testCreateUser_halReplyWithWrongRequestId() throws Exception {
+        VehiclePropValue propResponse =
+                UserHalHelper.createPropRequest(CREATE_USER, REQUEST_ID_PLACE_HOLDER);
+
+        replySetPropertyWithOnChangeEvent(CREATE_USER, propResponse,
+                /* rightRequestId= */ false);
+
+        GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+        mUserHalService.createUser(newValidCreateUserRequest(), TIMEOUT_MS, callback);
+
+        callback.assertCalled();
+        assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
+        assertThat(callback.response).isNull();
+    }
+
+    @Test
+    public void testCreateUser_success() throws Exception {
+        VehiclePropValue propResponse =
+                UserHalHelper.createPropRequest(CREATE_USER, REQUEST_ID_PLACE_HOLDER);
+        propResponse.value.int32Values.add(CreateUserStatus.SUCCESS);
+
+        AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent(
+                CREATE_USER, propResponse, /* rightRequestId= */ true);
+
+        CreateUserRequest request = new CreateUserRequest();
+        request.newUserInfo = mUser10;
+        request.usersInfo = mUsersInfo;
+        GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_SUCCESS);
+        mUserHalService.createUser(request, TIMEOUT_MS, callback);
+
+        callback.assertCalled();
+
+        // Make sure the arguments were properly converted
+        assertHalSetCreateUserRequest(reqCaptor.get(), request);
+
+        // Assert response
+        assertCallbackStatus(callback, HalCallback.STATUS_OK);
+        CreateUserResponse actualResponse = callback.response;
+        assertThat(actualResponse.status).isEqualTo(CreateUserStatus.SUCCESS);
+        assertThat(actualResponse.errorMessage).isEmpty();
+    }
+
+    @Test
+    public void testCreateUser_failure() throws Exception {
+        VehiclePropValue propResponse =
+                UserHalHelper.createPropRequest(CREATE_USER, REQUEST_ID_PLACE_HOLDER);
+        propResponse.value.int32Values.add(CreateUserStatus.FAILURE);
+        propResponse.value.stringValue = "D'OH!";
+
+        AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent(
+                CREATE_USER, propResponse, /* rightRequestId= */ true);
+
+        CreateUserRequest request = new CreateUserRequest();
+        request.newUserInfo = mUser10;
+        request.usersInfo = mUsersInfo;
+        GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_SUCCESS);
+        mUserHalService.createUser(request, TIMEOUT_MS, callback);
+
+        callback.assertCalled();
+
+        // Make sure the arguments were properly converted
+        assertHalSetCreateUserRequest(reqCaptor.get(), request);
+
+        // Assert response
+        assertCallbackStatus(callback, HalCallback.STATUS_OK);
+        CreateUserResponse actualResponse = callback.response;
+        assertThat(actualResponse.status).isEqualTo(CreateUserStatus.FAILURE);
+        assertThat(actualResponse.errorMessage).isEqualTo("D'OH!");
+    }
+
+    @Test
+    public void testCreateUser_secondCallFailWhilePending() throws Exception {
+        GenericHalCallback<CreateUserResponse> callback1 = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+        GenericHalCallback<CreateUserResponse> callback2 = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+        mUserHalService.createUser(newValidCreateUserRequest(), TIMEOUT_MS, callback1);
+        mUserHalService.createUser(newValidCreateUserRequest(), TIMEOUT_MS, callback2);
+
+        callback1.assertCalled();
+        assertCallbackStatus(callback1, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
+        assertThat(callback1.response).isNull();
+
+        callback2.assertCalled();
+        assertCallbackStatus(callback2, HalCallback.STATUS_CONCURRENT_OPERATION);
+        assertThat(callback1.response).isNull();
+    }
+
+    @Test
+    public void testCreateUser_halReturnedInvalidStatus() throws Exception {
+        VehiclePropValue propResponse =
+                UserHalHelper.createPropRequest(CREATE_USER, REQUEST_ID_PLACE_HOLDER);
+        propResponse.value.int32Values.add(/*status =*/ -1); // an invalid status
+
+        AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent(
+                CREATE_USER, propResponse, /* rightRequestId= */ true);
+
+        GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_SUCCESS);
+        mUserHalService.createUser(newValidCreateUserRequest(), TIMEOUT_MS, callback);
+
+        callback.assertCalled();
+
+        // Assert response
+        assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE);
+        assertThat(callback.response).isNull();
+    }
+
+    @Test
+    public void testGetUserAssociation_noHalSupported() {
+        // Cannot use mUserHalService because it's already set with supported properties
+        UserHalService myHalService = new UserHalService(mVehicleHal);
+
+        assertThrows(IllegalStateException.class,
+                () -> myHalService.getUserAssociation(new UserIdentificationGetRequest()));
+    }
+
+    @Test
+    public void testGetUserAssociation_nullRequest() {
+        assertThrows(NullPointerException.class, () -> mUserHalService.getUserAssociation(null));
+    }
+
+    @Test
+    public void testGetUserAssociation_requestWithDuplicatedTypes() {
+        UserIdentificationGetRequest request = new UserIdentificationGetRequest();
+        request.numberAssociationTypes = 2;
+        request.associationTypes.add(KEY_FOB);
+        request.associationTypes.add(KEY_FOB);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> mUserHalService.getUserAssociation(request));
+    }
+
+    @Test
+    public void testGetUserAssociation_invalidResponse() {
+        VehiclePropValue propResponse = new VehiclePropValue();
+        propResponse.prop = USER_IDENTIFICATION_ASSOCIATION;
+        propResponse.value.int32Values.add(DEFAULT_REQUEST_ID);
+        propResponse.value.int32Values.add(1); // 1 associations
+        propResponse.value.int32Values.add(KEY_FOB); // type only, it's missing value
+        UserIdentificationGetRequest request = replyToValidGetUserIdentificationRequest(
+                propResponse);
+
+        assertThat(mUserHalService.getUserAssociation(request)).isNull();
+    }
+
+    @Test
+    public void testGetUserAssociation_nullResponse() {
+        UserIdentificationGetRequest request = replyToValidGetUserIdentificationRequest(null);
+
+        assertThat(mUserHalService.getUserAssociation(request)).isNull();
+
+        verifyValidGetUserIdentificationRequestMade();
+    }
+
+    @Test
+    public void testGetUserAssociation_wrongNumberOfAssociationsOnResponse() {
+        VehiclePropValue propResponse = new VehiclePropValue();
+        propResponse.prop = USER_IDENTIFICATION_ASSOCIATION;
+        propResponse.value.int32Values.add(DEFAULT_REQUEST_ID);
+        propResponse.value.int32Values.add(2); // 2 associations
+        propResponse.value.int32Values.add(KEY_FOB);
+        propResponse.value.int32Values.add(ASSOCIATED_CURRENT_USER);
+        propResponse.value.int32Values.add(CUSTOM_1);
+        propResponse.value.int32Values.add(ASSOCIATED_CURRENT_USER);
+        UserIdentificationGetRequest request = replyToValidGetUserIdentificationRequest(
+                propResponse);
+
+        assertThat(mUserHalService.getUserAssociation(request)).isNull();
+
+        verifyValidGetUserIdentificationRequestMade();
+    }
+
+    @Test
+    public void testGetUserAssociation_typesOnResponseMismatchTypesOnRequest() {
+        VehiclePropValue propResponse = new VehiclePropValue();
+        propResponse.prop = USER_IDENTIFICATION_ASSOCIATION;
+        propResponse.value.int32Values.add(DEFAULT_REQUEST_ID);
+        propResponse.value.int32Values.add(1); // 1 association
+        propResponse.value.int32Values.add(CUSTOM_1);
+        propResponse.value.int32Values.add(ASSOCIATED_CURRENT_USER);
+        UserIdentificationGetRequest request = replyToValidGetUserIdentificationRequest(
+                propResponse);
+
+        assertThat(mUserHalService.getUserAssociation(request)).isNull();
+
+        verifyValidGetUserIdentificationRequestMade();
+    }
+
+    @Test
+    public void testGetUserAssociation_requestIdMismatch() {
+        VehiclePropValue propResponse = new VehiclePropValue();
+        propResponse.prop = USER_IDENTIFICATION_ASSOCIATION;
+        propResponse.value.int32Values.add(DEFAULT_REQUEST_ID + 1);
+        propResponse.value.int32Values.add(1); // 1 association
+        propResponse.value.int32Values.add(KEY_FOB);
+        propResponse.value.int32Values.add(ASSOCIATED_CURRENT_USER);
+        UserIdentificationGetRequest request = replyToValidGetUserIdentificationRequest(
+                propResponse);
+
+        assertThat(mUserHalService.getUserAssociation(request)).isNull();
+
+        verifyValidGetUserIdentificationRequestMade();
+    }
+
+    @Test
+    public void testGetUserAssociation_ok() {
+        VehiclePropValue propResponse = new VehiclePropValue();
+        propResponse.prop = USER_IDENTIFICATION_ASSOCIATION;
+        propResponse.value.int32Values.add(DEFAULT_REQUEST_ID);
+        propResponse.value.int32Values.add(1); // 1 association
+        propResponse.value.int32Values.add(KEY_FOB);
+        propResponse.value.int32Values.add(ASSOCIATED_CURRENT_USER);
+        UserIdentificationGetRequest request = replyToValidGetUserIdentificationRequest(
+                propResponse);
+
+        UserIdentificationResponse response = mUserHalService.getUserAssociation(request);
+
+        assertThat(response.requestId).isEqualTo(DEFAULT_REQUEST_ID);
+        assertThat(response.numberAssociation).isEqualTo(1);
+        assertThat(response.associations).hasSize(1);
+        UserIdentificationAssociation actualAssociation = response.associations.get(0);
+        assertThat(actualAssociation.type).isEqualTo(KEY_FOB);
+        assertThat(actualAssociation.value).isEqualTo(ASSOCIATED_CURRENT_USER);
+    }
+
+    @Test
+    public void testSetUserAssociation_noHalSupported() {
+        // Cannot use mUserHalService because it's already set with supported properties
+        UserHalService myHalService = new UserHalService(mVehicleHal);
+
+        assertThrows(IllegalStateException.class, () -> myHalService.setUserAssociation(TIMEOUT_MS,
+                new UserIdentificationSetRequest(), noOpCallback()));
+    }
+
+    @Test
+    public void testSetUserAssociation_invalidTimeout() {
+        UserIdentificationSetRequest request = new UserIdentificationSetRequest();
+        assertThrows(IllegalArgumentException.class, () ->
+                mUserHalService.setUserAssociation(0, request, noOpCallback()));
+        assertThrows(IllegalArgumentException.class, () ->
+                mUserHalService.setUserAssociation(-1, request, noOpCallback()));
+    }
+
+    @Test
+    public void testSetUserAssociation_nullRequest() {
+        assertThrows(NullPointerException.class, () ->
+                mUserHalService.setUserAssociation(TIMEOUT_MS, null, noOpCallback()));
+    }
+
+    @Test
+    public void testSetUserAssociation_nullCallback() {
+        UserIdentificationSetRequest request = new UserIdentificationSetRequest();
+        assertThrows(NullPointerException.class, () ->
+                mUserHalService.setUserAssociation(TIMEOUT_MS, request, null));
+    }
+
+    @Test
+    public void testSetUserAssociation_requestWithDuplicatedTypes() {
+        UserIdentificationSetRequest request = new UserIdentificationSetRequest();
+        request.numberAssociations = 2;
+        UserIdentificationSetAssociation association1 = new UserIdentificationSetAssociation();
+        association1.type = KEY_FOB;
+        association1.value = ASSOCIATE_CURRENT_USER;
+        request.associations.add(association1);
+        request.associations.add(association1);
+
+        assertThrows(IllegalArgumentException.class, () ->
+                mUserHalService.setUserAssociation(TIMEOUT_MS, request, noOpCallback()));
+    }
+
+    @Test
+    public void testSetUserAssociation_halSetTimedOut() throws Exception {
+        UserIdentificationSetRequest request = validUserIdentificationSetRequest();
+        GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+        replySetPropertyWithTimeoutException(USER_IDENTIFICATION_ASSOCIATION);
+
+        mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+
+        callback.assertCalled();
+        assertCallbackStatus(callback, HalCallback.STATUS_HAL_SET_TIMEOUT);
+        assertThat(callback.response).isNull();
+
+        // Make sure the pending request was removed
+        SystemClock.sleep(CALLBACK_TIMEOUT_TIMEOUT);
+        callback.assertNotCalledAgain();
+    }
+
+    @Test
+    public void testSetUserAssociation_halDidNotReply() throws Exception {
+        UserIdentificationSetRequest request = validUserIdentificationSetRequest();
+        GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+
+        mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+
+        callback.assertCalled();
+        assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
+        assertThat(callback.response).isNull();
+    }
+
+    @Test
+    public void testSetUserAssociation_secondCallFailWhilePending() throws Exception {
+        UserIdentificationSetRequest request = validUserIdentificationSetRequest();
+        GenericHalCallback<UserIdentificationResponse> callback1 = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+        GenericHalCallback<UserIdentificationResponse> callback2 = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+
+        mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback1);
+        mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback2);
+
+        callback1.assertCalled();
+        assertCallbackStatus(callback1, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
+        assertThat(callback1.response).isNull();
+
+        callback2.assertCalled();
+        assertCallbackStatus(callback2, HalCallback.STATUS_CONCURRENT_OPERATION);
+        assertThat(callback1.response).isNull();
+    }
+
+    @Test
+    public void testSetUserAssociation_responseWithWrongRequestId() throws Exception {
+        VehiclePropValue propResponse = new VehiclePropValue();
+        propResponse.prop = USER_IDENTIFICATION_ASSOCIATION;
+        propResponse.value.int32Values.add(DEFAULT_REQUEST_ID + 1);
+        AtomicReference<VehiclePropValue> propRequest = replySetPropertyWithOnChangeEvent(
+                USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true);
+        UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest();
+        GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+
+        mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+
+        // Assert request
+        verifyValidSetUserIdentificationRequestMade(propRequest.get());
+        // Assert response
+        callback.assertCalled();
+        assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE);
+        assertThat(callback.response).isNull();
+    }
+
+    @Test
+    public void testSetUserAssociation_notEnoughValuesOnResponse() throws Exception {
+        VehiclePropValue propResponse = new VehiclePropValue();
+        propResponse.prop = USER_IDENTIFICATION_ASSOCIATION;
+        // need at least 4: requestId, number associations, type1, value1
+        propResponse.value.int32Values.add(1);
+        propResponse.value.int32Values.add(2);
+        propResponse.value.int32Values.add(3);
+
+        AtomicReference<VehiclePropValue> propRequest = replySetPropertyWithOnChangeEvent(
+                USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true);
+        UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest();
+        GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+
+        mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+
+        // Assert request
+        verifyValidSetUserIdentificationRequestMade(propRequest.get());
+        // Assert response
+        callback.assertCalled();
+        assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE);
+        assertThat(callback.response).isNull();
+    }
+
+    @Test
+    public void testSetUserAssociation_wrongNumberOfAssociationsOnResponse() throws Exception {
+        VehiclePropValue propResponse = new VehiclePropValue();
+        propResponse.prop = USER_IDENTIFICATION_ASSOCIATION;
+        propResponse.value.int32Values.add(DEFAULT_REQUEST_ID);
+        propResponse.value.int32Values.add(2); // 2 associations; request is just 1
+        propResponse.value.int32Values.add(KEY_FOB);
+        propResponse.value.int32Values.add(ASSOCIATED_CURRENT_USER);
+        propResponse.value.int32Values.add(CUSTOM_1);
+        propResponse.value.int32Values.add(ASSOCIATED_CURRENT_USER);
+
+        AtomicReference<VehiclePropValue> propRequest = replySetPropertyWithOnChangeEvent(
+                USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true);
+        UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest();
+        GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+
+        mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+
+        // Assert request
+        verifyValidSetUserIdentificationRequestMade(propRequest.get());
+        // Assert response
+        callback.assertCalled();
+        assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE);
+        assertThat(callback.response).isNull();
+    }
+
+    @Test
+    public void testSetUserAssociation_typeMismatchOnResponse() throws Exception {
+        VehiclePropValue propResponse = new VehiclePropValue();
+        propResponse.prop = USER_IDENTIFICATION_ASSOCIATION;
+        propResponse.value.int32Values.add(DEFAULT_REQUEST_ID);
+        propResponse.value.int32Values.add(1); // 1 association
+        propResponse.value.int32Values.add(CUSTOM_1); // request is KEY_FOB
+        propResponse.value.int32Values.add(ASSOCIATED_CURRENT_USER);
+
+        AtomicReference<VehiclePropValue> propRequest = replySetPropertyWithOnChangeEvent(
+                USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true);
+        UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest();
+        GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+
+        mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+
+        // Assert request
+        verifyValidSetUserIdentificationRequestMade(propRequest.get());
+        // Assert response
+        callback.assertCalled();
+        assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE);
+        assertThat(callback.response).isNull();
+    }
+
+    @Test
+    public void testSetUserAssociation_ok() throws Exception {
+        VehiclePropValue propResponse = new VehiclePropValue();
+        propResponse.prop = USER_IDENTIFICATION_ASSOCIATION;
+        propResponse.value.int32Values.add(DEFAULT_REQUEST_ID);
+        propResponse.value.int32Values.add(1); // 1 association
+        propResponse.value.int32Values.add(KEY_FOB);
+        propResponse.value.int32Values.add(ASSOCIATED_CURRENT_USER);
+
+        AtomicReference<VehiclePropValue> propRequest = replySetPropertyWithOnChangeEvent(
+                USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true);
+        UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest();
+        GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
+                CALLBACK_TIMEOUT_TIMEOUT);
+
+        mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+
+        // Assert request
+        verifyValidSetUserIdentificationRequestMade(propRequest.get());
+        // Assert response
+        callback.assertCalled();
+        assertCallbackStatus(callback, HalCallback.STATUS_OK);
+
+        UserIdentificationResponse actualResponse = callback.response;
+
+        assertThat(actualResponse.requestId).isEqualTo(DEFAULT_REQUEST_ID);
+        assertThat(actualResponse.numberAssociation).isEqualTo(1);
+        assertThat(actualResponse.associations).hasSize(1);
+        UserIdentificationAssociation actualAssociation = actualResponse.associations.get(0);
+        assertThat(actualAssociation.type).isEqualTo(KEY_FOB);
+        assertThat(actualAssociation.value).isEqualTo(ASSOCIATED_CURRENT_USER);
+    }
+
+    /**
+     * Asserts the given {@link UsersInfo} is properly represented in the {@link VehiclePropValue}.
+     *
+     * @param value property containing the info
+     * @param info info to be checked
+     * @param initialIndex first index of the info values in the property's {@code int32Values}
+     */
+    private void assertUsersInfo(VehiclePropValue value, UsersInfo info, int initialIndex) {
+        // TODO: consider using UserHalHelper to convert the property into a specific request,
+        // and compare the request's UsersInfo.
+        // But such method is not needed in production code yet.
+        ArrayList<Integer> values = value.value.int32Values;
+        assertWithMessage("wrong values size").that(values)
+                .hasSize(initialIndex + 3 + info.numberUsers * 2);
+
+        int i = initialIndex;
+        assertWithMessage("currentUser.id mismatch at index %s", i).that(values.get(i))
+                .isEqualTo(info.currentUser.userId);
+        i++;
+        assertWithMessage("currentUser.flags mismatch at index %s", i).that(values.get(i))
+            .isEqualTo(info.currentUser.flags);
+        i++;
+        assertWithMessage("numberUsers mismatch at index %s", i).that(values.get(i))
+            .isEqualTo(info.numberUsers);
+        i++;
+
+        for (int j = 0; j < info.numberUsers; j++) {
+            int actualUserId = values.get(i++);
+            int actualUserFlags = values.get(i++);
+            UserInfo expectedUser = info.existingUsers.get(j);
+            assertWithMessage("wrong id for existing user#%s at index %s", j, i)
+                .that(actualUserId).isEqualTo(expectedUser.userId);
+            assertWithMessage("wrong flags for existing user#%s at index %s", j, i)
+                .that(actualUserFlags).isEqualTo(expectedUser.flags);
+        }
+    }
+
+    /**
+     * Sets the VHAL mock to emulate a property change event upon a call to set a property.
+     *
+     * @param prop prop to be set
+     * @param response response to be set on event
+     * @param rightRequestId whether the response id should match the request
+     * @return
+     *
+     * @return reference to the value passed to {@code set()}.
+     */
+    private AtomicReference<VehiclePropValue> replySetPropertyWithOnChangeEvent(int prop,
+            VehiclePropValue response, boolean rightRequestId) throws Exception {
+        AtomicReference<VehiclePropValue> ref = new AtomicReference<>();
+        doAnswer((inv) -> {
+            VehiclePropValue request = inv.getArgument(0);
+            ref.set(request);
+            int requestId = request.value.int32Values.get(0);
+            int responseId = rightRequestId ? requestId : requestId + 1000;
+            response.value.int32Values.set(0, responseId);
+            Log.d(TAG, "replySetPropertyWithOnChangeEvent(): resp=" + response + " for req="
+                    + request);
+            mUserHalService.onHalEvents(Arrays.asList(response));
+            return null;
+        }).when(mVehicleHal).set(isProperty(prop));
+        return ref;
+    }
+
+    /**
+     * Sets the VHAL mock to emulate a property timeout exception upon a call to set a property.
+     */
+    private void replySetPropertyWithTimeoutException(int prop) throws Exception {
+        doThrow(new ServiceSpecificException(VehicleHalStatusCode.STATUS_TRY_AGAIN,
+                "PropId: 0x" + Integer.toHexString(prop))).when(mVehicleHal).set(isProperty(prop));
+    }
+
+    @NonNull
+    private SwitchUserRequest createUserSwitchRequest(@NonNull UserInfo targetUser,
+            @NonNull UsersInfo usersInfo) {
+        SwitchUserRequest request = new SwitchUserRequest();
+        request.targetUser = targetUser;
+        request.usersInfo = usersInfo;
+        return request;
+    }
+
+    /**
+     * Creates and set expectations for a valid request.
+     */
+    private UserIdentificationGetRequest replyToValidGetUserIdentificationRequest(
+            @NonNull VehiclePropValue response) {
+        mockNextRequestId(DEFAULT_REQUEST_ID);
+
+        UserIdentificationGetRequest request = new UserIdentificationGetRequest();
+        request.userInfo.userId = DEFAULT_USER_ID;
+        request.userInfo.flags = DEFAULT_USER_FLAGS;
+        request.numberAssociationTypes = 1;
+        request.associationTypes.add(KEY_FOB);
+
+        when(mVehicleHal.get(isPropertyWithValues(USER_IDENTIFICATION_ASSOCIATION,
+                DEFAULT_REQUEST_ID, DEFAULT_USER_ID, DEFAULT_USER_FLAGS,
+                /* numberAssociations= */ 1, KEY_FOB)))
+            .thenReturn(response);
+
+        return request;
+    }
+
+    /**
+     * Creates and set expectations for a valid request.
+     */
+    private UserIdentificationSetRequest replyToValidSetUserIdentificationRequest() {
+        mockNextRequestId(DEFAULT_REQUEST_ID);
+        return validUserIdentificationSetRequest();
+    }
+
+    /**
+     * Creates a valid request that can be used in test cases where its content is not asserted.
+     */
+    private UserIdentificationSetRequest validUserIdentificationSetRequest() {
+        UserIdentificationSetRequest request = new UserIdentificationSetRequest();
+        request.userInfo.userId = DEFAULT_USER_ID;
+        request.userInfo.flags = DEFAULT_USER_FLAGS;
+        request.numberAssociations = 1;
+        UserIdentificationSetAssociation association1 = new UserIdentificationSetAssociation();
+        association1.type = KEY_FOB;
+        association1.value = ASSOCIATE_CURRENT_USER;
+        request.associations.add(association1);
+        return request;
+    }
+
+    /**
+     * Run empty runnable to make sure that all posted handlers are done.
+     */
+    private void waitForHandler() {
+        mHandler.runWithScissors(() -> { }, /* Default timeout */ CALLBACK_TIMEOUT_TIMEOUT);
+    }
+
+    private void mockNextRequestId(int requestId) {
+        doReturn(requestId).when(mUserHalService).getNextRequestId();
+    }
+
+    private void assertInitialUserInfoSetRequest(VehiclePropValue req, int requestType) {
+        assertThat(req.value.int32Values.get(1)).isEqualTo(requestType);
+        assertUsersInfo(req, mUsersInfo, 2);
+    }
+
+    private void assertHalSetSwitchUserRequest(VehiclePropValue req, int messageType,
+            UserInfo targetUserInfo) {
+        assertThat(req.prop).isEqualTo(SWITCH_USER);
+        assertWithMessage("wrong request Id on %s", req).that(req.value.int32Values.get(0))
+            .isAtLeast(1);
+        assertThat(req.value.int32Values.get(1)).isEqualTo(messageType);
+        assertWithMessage("targetuser.id mismatch on %s", req).that(req.value.int32Values.get(2))
+                .isEqualTo(targetUserInfo.userId);
+        assertWithMessage("targetuser.flags mismatch on %s", req).that(req.value.int32Values.get(3))
+                .isEqualTo(targetUserInfo.flags);
+        assertUsersInfo(req, mUsersInfo, 4);
+    }
+
+    private void assertHalSetRemoveUserRequest(VehiclePropValue req, UserInfo userInfo) {
+        assertThat(req.prop).isEqualTo(REMOVE_USER);
+        assertWithMessage("wrong request Id on %s", req).that(req.value.int32Values.get(0))
+                .isAtLeast(1);
+        assertWithMessage("user.id mismatch on %s", req).that(req.value.int32Values.get(1))
+                .isEqualTo(userInfo.userId);
+        assertWithMessage("user.flags mismatch on %s", req).that(req.value.int32Values.get(2))
+                .isEqualTo(userInfo.flags);
+        assertUsersInfo(req, mUsersInfo, 3);
+    }
+
+    private void assertHalSetCreateUserRequest(VehiclePropValue prop, CreateUserRequest request) {
+        assertThat(prop.prop).isEqualTo(CREATE_USER);
+        assertWithMessage("wrong request Id on %s", prop).that(prop.value.int32Values.get(0))
+                .isEqualTo(request.requestId);
+        assertWithMessage("newUser.userId mismatch on %s", prop).that(prop.value.int32Values.get(1))
+                .isEqualTo(request.newUserInfo.userId);
+        assertWithMessage("newUser.flags mismatch on %s", prop).that(prop.value.int32Values.get(2))
+                .isEqualTo(request.newUserInfo.flags);
+        assertUsersInfo(prop, request.usersInfo, 3);
+    }
+
+    private void assertCallbackStatus(GenericHalCallback<?> callback, int expectedStatus) {
+        int actualStatus = callback.status;
+        if (actualStatus == expectedStatus) return;
+
+        fail("Wrong callback status; expected "
+                + UserHalHelper.halCallbackStatusToString(expectedStatus) + ", got "
+                + UserHalHelper.halCallbackStatusToString(actualStatus));
+    }
+
+    /**
+     * Verifies {@code hal.get()} was called with the values used on
+     * {@link #replyToValidGetUserIdentificationRequest(VehiclePropValue)}.
+     */
+    private void verifyValidGetUserIdentificationRequestMade() {
+        verify(mVehicleHal).get(isPropertyWithValues(USER_IDENTIFICATION_ASSOCIATION,
+                DEFAULT_REQUEST_ID, DEFAULT_USER_ID, DEFAULT_USER_FLAGS,
+                /* numberAssociations= */ 1, KEY_FOB));
+    }
+
+    /**
+     * Verifies {@code hal.set()} was called with the values used on
+     * {@link #replyToValidSetUserIdentificationRequest(VehiclePropValue)}.
+     */
+    private void verifyValidSetUserIdentificationRequestMade(@NonNull VehiclePropValue request) {
+        assertThat(request.prop).isEqualTo(USER_IDENTIFICATION_ASSOCIATION);
+        assertThat(request.value.int32Values).containsExactly(DEFAULT_REQUEST_ID, DEFAULT_USER_ID,
+                DEFAULT_USER_FLAGS,
+                /* numberAssociations= */ 1, KEY_FOB, ASSOCIATE_CURRENT_USER);
+    }
+
+    private static <T> HalCallback<T> noOpCallback() {
+        return (i, r) -> { };
+    }
+
+    private final class GenericHalCallback<R> implements HalCallback<R> {
+
+        private final CountDownLatch mLatch = new CountDownLatch(1);
+        private final int mTimeout;
+        private final List<Pair<Integer, R>> mExtraCalls = new ArrayList<>();
+
+        public int status;
+        public R response;
+
+        GenericHalCallback(int timeout) {
+            this.mTimeout = timeout;
+        }
+
+        @Override
+        public void onResponse(int status, R response) {
+            Log.d(TAG, "onResponse(): status=" + status + ", response=" +  response);
+            this.status = status;
+            this.response = response;
+            if (mLatch.getCount() == 0) {
+                Log.e(TAG, "Already responded");
+                mExtraCalls.add(new Pair<>(status, response));
+                return;
+            }
+            mLatch.countDown();
+        }
+
+        /**
+         * Asserts that the callback was called, or fail if it timed out.
+         */
+        public void assertCalled() throws InterruptedException {
+            Log.d(TAG, "assertCalled(): waiting " + mTimeout + "ms");
+            if (!mLatch.await(mTimeout, TimeUnit.MILLISECONDS)) {
+                throw new AssertionError("callback not called in " + mTimeout + "ms");
+            }
+        }
+
+        /**
+         * Asserts that the callback was not called more than once.
+         */
+        public void assertNotCalledAgain() {
+            if (mExtraCalls.isEmpty()) return;
+            throw new AssertionError("Called " + mExtraCalls.size() + " times more than expected: "
+                    + mExtraCalls);
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/VmsHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/VmsHalServiceTest.java
index 093ab9b..dadcbad 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/VmsHalServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/VmsHalServiceTest.java
@@ -20,21 +20,18 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
-import android.car.vms.IVmsPublisherClient;
-import android.car.vms.IVmsPublisherService;
-import android.car.vms.IVmsSubscriberClient;
-import android.car.vms.IVmsSubscriberService;
+import android.car.hardware.property.VehicleHalStatusCode;
 import android.car.vms.VmsAssociatedLayer;
 import android.car.vms.VmsAvailableLayers;
+import android.car.vms.VmsClient;
+import android.car.vms.VmsClientManager.VmsClientCallback;
 import android.car.vms.VmsLayer;
 import android.car.vms.VmsLayerDependency;
-import android.car.vms.VmsLayersOffering;
 import android.car.vms.VmsSubscriptionState;
 import android.content.Context;
 import android.content.res.Resources;
@@ -43,33 +40,33 @@
 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyGroup;
 import android.hardware.automotive.vehicle.V2_0.VmsMessageType;
-import android.os.Binder;
-import android.os.IBinder;
+import android.os.Handler;
+import android.os.ServiceSpecificException;
 
 import com.android.car.R;
 import com.android.car.test.utils.TemporaryFile;
-import com.android.car.vms.VmsClientManager;
 
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
-import org.mockito.ArgumentCaptor;
+import org.junit.runner.RunWith;
 import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+@RunWith(MockitoJUnitRunner.class)
 public class VmsHalServiceTest {
     private static final int LAYER_TYPE = 1;
     private static final int LAYER_SUBTYPE = 2;
@@ -81,8 +78,6 @@
     private static final int CORE_ID = 54321;
     private static final int CLIENT_ID = 98765;
 
-    @Rule
-    public MockitoRule mockito = MockitoJUnit.rule();
     @Mock
     private Context mContext;
     @Mock
@@ -90,16 +85,11 @@
     @Mock
     private VehicleHal mVehicleHal;
     @Mock
-    private VmsClientManager mClientManager;
-    @Mock
-    private IVmsPublisherService mPublisherService;
-    @Mock
-    private IVmsSubscriberService mSubscriberService;
+    private VmsClient mVmsClient;
 
-    private IBinder mToken;
     private VmsHalService mHalService;
-    private IVmsPublisherClient mPublisherClient;
-    private IVmsSubscriberClient mSubscriberClient;
+    private VmsClientCallback mEventCallback;
+    private int mVmsInitCount;
 
     @Before
     public void setUp() throws Exception {
@@ -107,24 +97,22 @@
     }
 
     private void initHalService(boolean propagatePropertyException) throws Exception {
+        mVmsInitCount = 0;
         when(mContext.getResources()).thenReturn(mResources);
         mHalService = new VmsHalService(mContext, mVehicleHal, () -> (long) CORE_ID,
-            propagatePropertyException);
-        mHalService.setClientManager(mClientManager);
-        mHalService.setVmsSubscriberService(mSubscriberService);
+                this::initVmsClient, propagatePropertyException);
 
         VehiclePropConfig propConfig = new VehiclePropConfig();
         propConfig.prop = VehicleProperty.VEHICLE_MAP_SERVICE;
-        mHalService.takeSupportedProperties(Collections.singleton(propConfig));
+        mHalService.takeProperties(Collections.singleton(propConfig));
 
-        when(mSubscriberService.getAvailableLayers()).thenReturn(
+        when(mVmsClient.getAvailableLayers()).thenReturn(
                 new VmsAvailableLayers(Collections.emptySet(), 0));
         mHalService.init();
         waitForHandlerCompletion();
 
         // Verify START_SESSION message was sent
-        InOrder initOrder =
-                Mockito.inOrder(mClientManager, mSubscriberService, mVehicleHal);
+        InOrder initOrder = Mockito.inOrder(mVehicleHal);
         initOrder.verify(mVehicleHal).subscribeProperty(mHalService,
                 VehicleProperty.VEHICLE_MAP_SERVICE);
         initOrder.verify(mVehicleHal).set(createHalMessage(
@@ -143,21 +131,6 @@
         ));
         waitForHandlerCompletion();
 
-        // Verify client is marked as connected
-        ArgumentCaptor<IVmsPublisherClient> publisherCaptor =
-                ArgumentCaptor.forClass(IVmsPublisherClient.class);
-        ArgumentCaptor<IVmsSubscriberClient> subscriberCaptor =
-                ArgumentCaptor.forClass(IVmsSubscriberClient.class);
-        initOrder.verify(mClientManager, never()).onHalDisconnected();
-        initOrder.verify(mClientManager)
-                .onHalConnected(publisherCaptor.capture(), subscriberCaptor.capture());
-        mPublisherClient = publisherCaptor.getValue();
-        mSubscriberClient = subscriberCaptor.getValue();
-
-        mToken = new Binder();
-        mPublisherClient.setVmsPublisherService(mToken, mPublisherService);
-
-        initOrder.verify(mSubscriberService).getAvailableLayers();
         initOrder.verify(mVehicleHal).set(createHalMessage(
                 VmsMessageType.AVAILABILITY_CHANGE, // Message type
                 0,                                  // Sequence number
@@ -166,19 +139,26 @@
 
         waitForHandlerCompletion();
         initOrder.verifyNoMoreInteractions();
-        reset(mClientManager, mSubscriberService, mVehicleHal);
+        assertEquals(1, mVmsInitCount);
+        reset(mVmsClient, mVehicleHal);
+    }
+
+    private VmsClient initVmsClient(Handler handler, VmsClientCallback callback) {
+        mEventCallback = callback;
+        mVmsInitCount++;
+        return mVmsClient;
     }
 
     @Test
     public void testCoreId_IntegerOverflow() throws Exception {
         mHalService = new VmsHalService(mContext, mVehicleHal,
-                () -> (long) Integer.MAX_VALUE + CORE_ID, true);
+                () -> (long) Integer.MAX_VALUE + CORE_ID, this::initVmsClient, true);
 
         VehiclePropConfig propConfig = new VehiclePropConfig();
         propConfig.prop = VehicleProperty.VEHICLE_MAP_SERVICE;
-        mHalService.takeSupportedProperties(Collections.singleton(propConfig));
+        mHalService.takeProperties(Collections.singleton(propConfig));
 
-        when(mSubscriberService.getAvailableLayers()).thenReturn(
+        when(mVmsClient.getAvailableLayers()).thenReturn(
                 new VmsAvailableLayers(Collections.emptySet(), 0));
         mHalService.init();
         waitForHandlerCompletion();
@@ -196,9 +176,7 @@
 
         VehiclePropConfig otherPropConfig = new VehiclePropConfig();
         otherPropConfig.prop = VehicleProperty.CURRENT_GEAR;
-
-        assertEquals(Collections.singleton(vmsPropConfig),
-                mHalService.takeSupportedProperties(Arrays.asList(otherPropConfig, vmsPropConfig)));
+        mHalService.takeProperties(Arrays.asList(vmsPropConfig));
     }
 
     /**
@@ -213,7 +191,7 @@
      * </ul>
      */
     @Test
-    public void testHandleDataEvent() throws Exception {
+    public void testHandleDataEvent() {
         VehiclePropValue message = createHalMessage(
                 VmsMessageType.DATA,                       // Message type
                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION,  // VmsLayer
@@ -222,7 +200,20 @@
         message.value.bytes.addAll(PAYLOAD_AS_LIST);
 
         sendHalMessage(message);
-        verify(mPublisherService).publish(mToken, LAYER, PUBLISHER_ID, PAYLOAD);
+        verify(mVmsClient).publishPacket(PUBLISHER_ID, LAYER, PAYLOAD);
+    }
+
+    @Test
+    public void testOnPacketReceivedEvent() throws Exception {
+        VehiclePropValue message = createHalMessage(
+                VmsMessageType.DATA,                       // Message type
+                LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION,  // VmsLayer
+                PUBLISHER_ID                               // PublisherId
+        );
+        message.value.bytes.addAll(PAYLOAD_AS_LIST);
+
+        mEventCallback.onPacketReceived(PUBLISHER_ID, LAYER, PAYLOAD);
+        verify(mVehicleHal).set(message);
     }
 
     /**
@@ -235,14 +226,14 @@
      * </ul>
      */
     @Test
-    public void testHandleSubscribeEvent() throws Exception {
+    public void testHandleSubscribeEvent() {
         VehiclePropValue message = createHalMessage(
                 VmsMessageType.SUBSCRIBE,                 // Message type
                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION  // VmsLayer
         );
 
         sendHalMessage(message);
-        verify(mSubscriberService).addVmsSubscriber(mSubscriberClient, LAYER);
+        verify(mVmsClient).setSubscriptions(asSet(new VmsAssociatedLayer(LAYER, asSet())));
     }
 
     /**
@@ -256,7 +247,7 @@
      * </ul>
      */
     @Test
-    public void testHandleSubscribeToPublisherEvent() throws Exception {
+    public void testHandleSubscribeToPublisherEvent() {
         VehiclePropValue message = createHalMessage(
                 VmsMessageType.SUBSCRIBE_TO_PUBLISHER,     // Message type
                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION,  // VmsLayer
@@ -264,8 +255,8 @@
         );
 
         sendHalMessage(message);
-        verify(mSubscriberService).addVmsSubscriberToPublisher(mSubscriberClient, LAYER,
-                PUBLISHER_ID);
+        verify(mVmsClient).setSubscriptions(asSet(
+                new VmsAssociatedLayer(LAYER, asSet(PUBLISHER_ID))));
     }
 
     /**
@@ -278,14 +269,16 @@
      * </ul>
      */
     @Test
-    public void testHandleUnsubscribeEvent() throws Exception {
+    public void testHandleUnsubscribeEvent() {
+        testHandleSubscribeEvent();
+
         VehiclePropValue message = createHalMessage(
                 VmsMessageType.UNSUBSCRIBE,               // Message type
                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION  // VmsLayer
         );
 
         sendHalMessage(message);
-        verify(mSubscriberService).removeVmsSubscriber(mSubscriberClient, LAYER);
+        verify(mVmsClient).setSubscriptions(asSet());
     }
 
     /**
@@ -299,7 +292,9 @@
      * </ul>
      */
     @Test
-    public void testHandleUnsubscribeFromPublisherEvent() throws Exception {
+    public void testHandleUnsubscribeFromPublisherEvent() {
+        testHandleSubscribeToPublisherEvent();
+
         VehiclePropValue message = createHalMessage(
                 VmsMessageType.UNSUBSCRIBE_TO_PUBLISHER,   // Message type
                 LAYER_TYPE, LAYER_SUBTYPE, LAYER_VERSION,  // VmsLayer
@@ -307,8 +302,7 @@
         );
 
         sendHalMessage(message);
-        verify(mSubscriberService).removeVmsSubscriberToPublisher(mSubscriberClient, LAYER,
-                PUBLISHER_ID);
+        verify(mVmsClient).setSubscriptions(asSet());
     }
 
     /**
@@ -331,7 +325,7 @@
         );
         request.value.bytes.addAll(PAYLOAD_AS_LIST);
 
-        when(mPublisherService.getPublisherId(PAYLOAD)).thenReturn(PUBLISHER_ID);
+        when(mVmsClient.registerProvider(PAYLOAD)).thenReturn(PUBLISHER_ID);
 
         VehiclePropValue response = createHalMessage(
                 VmsMessageType.PUBLISHER_ID_RESPONSE,  // Message type
@@ -362,7 +356,7 @@
                 PUBLISHER_ID                                   // Publisher ID
         );
 
-        when(mSubscriberService.getPublisherInfo(PUBLISHER_ID)).thenReturn(PAYLOAD);
+        when(mVmsClient.getProviderDescription(PUBLISHER_ID)).thenReturn(PAYLOAD);
 
         VehiclePropValue response = createHalMessage(
                 VmsMessageType.PUBLISHER_INFORMATION_RESPONSE  // Message type
@@ -395,7 +389,7 @@
      * </ul>
      */
     @Test
-    public void testHandleOfferingEvent_ZeroOfferings() throws Exception {
+    public void testHandleOfferingEvent_ZeroOfferings() {
         VehiclePropValue message = createHalMessage(
                 VmsMessageType.OFFERING,  // Message type
                 PUBLISHER_ID,             // PublisherId
@@ -403,13 +397,11 @@
         );
 
         sendHalMessage(message);
-        verify(mPublisherService).setLayersOffering(
-                mToken,
-                new VmsLayersOffering(Collections.emptySet(), PUBLISHER_ID));
+        verify(mVmsClient).setProviderOfferings(PUBLISHER_ID, asSet());
     }
 
     @Test
-    public void testHandleOfferingEvent_LayerOnly() throws Exception {
+    public void testHandleOfferingEvent_LayerOnly() {
         VehiclePropValue message = createHalMessage(
                 VmsMessageType.OFFERING,                   // Message type
                 PUBLISHER_ID,                              // PublisherId
@@ -420,15 +412,13 @@
         );
 
         sendHalMessage(message);
-        verify(mPublisherService).setLayersOffering(
-                mToken,
-                new VmsLayersOffering(Collections.singleton(
-                        new VmsLayerDependency(LAYER)),
-                        PUBLISHER_ID));
+        verify(mVmsClient).setProviderOfferings(
+                PUBLISHER_ID,
+                asSet(new VmsLayerDependency(LAYER)));
     }
 
     @Test
-    public void testHandleOfferingEvent_LayerAndDependency() throws Exception {
+    public void testHandleOfferingEvent_LayerAndDependency() {
         VehiclePropValue message = createHalMessage(
                 VmsMessageType.OFFERING,                   // Message type
                 PUBLISHER_ID,                              // PublisherId
@@ -439,16 +429,15 @@
         );
 
         sendHalMessage(message);
-        verify(mPublisherService).setLayersOffering(
-                mToken,
-                new VmsLayersOffering(Collections.singleton(
+        verify(mVmsClient).setProviderOfferings(
+                PUBLISHER_ID,
+                asSet(
                         new VmsLayerDependency(LAYER, Collections.singleton(
-                                new VmsLayer(4, 5, 6)))),
-                        PUBLISHER_ID));
+                                new VmsLayer(4, 5, 6)))));
     }
 
     @Test
-    public void testHandleOfferingEvent_MultipleLayersAndDependencies() throws Exception {
+    public void testHandleOfferingEvent_MultipleLayersAndDependencies() {
         VehiclePropValue message = createHalMessage(
                 VmsMessageType.OFFERING,                   // Message type
                 PUBLISHER_ID,                              // PublisherId
@@ -468,9 +457,9 @@
         );
 
         sendHalMessage(message);
-        verify(mPublisherService).setLayersOffering(
-                mToken,
-                new VmsLayersOffering(new LinkedHashSet<>(Arrays.asList(
+        verify(mVmsClient).setProviderOfferings(
+                PUBLISHER_ID,
+                asSet(
                         new VmsLayerDependency(LAYER, new LinkedHashSet<>(Arrays.asList(
                                 new VmsLayer(4, 5, 6),
                                 new VmsLayer(7, 8, 9)
@@ -478,8 +467,7 @@
                         new VmsLayerDependency(new VmsLayer(3, 2, 1), Collections.emptySet()),
                         new VmsLayerDependency(new VmsLayer(6, 5, 4), Collections.singleton(
                                 new VmsLayer(7, 8, 9)
-                        )))),
-                        PUBLISHER_ID));
+                        ))));
     }
 
     /**
@@ -509,7 +497,7 @@
                 VmsMessageType.AVAILABILITY_REQUEST  // Message type
         );
 
-        when(mSubscriberService.getAvailableLayers()).thenReturn(
+        when(mVmsClient.getAvailableLayers()).thenReturn(
                 new VmsAvailableLayers(Collections.emptySet(), 123));
 
         VehiclePropValue response = createHalMessage(
@@ -528,7 +516,7 @@
                 VmsMessageType.AVAILABILITY_REQUEST  // Message type
         );
 
-        when(mSubscriberService.getAvailableLayers()).thenReturn(
+        when(mVmsClient.getAvailableLayers()).thenReturn(
                 new VmsAvailableLayers(Collections.singleton(
                         new VmsAssociatedLayer(LAYER, Collections.singleton(PUBLISHER_ID))), 123));
 
@@ -552,7 +540,7 @@
                 VmsMessageType.AVAILABILITY_REQUEST  // Message type
         );
 
-        when(mSubscriberService.getAvailableLayers()).thenReturn(
+        when(mVmsClient.getAvailableLayers()).thenReturn(
                 new VmsAvailableLayers(new LinkedHashSet<>(Arrays.asList(
                         new VmsAssociatedLayer(LAYER,
                                 new LinkedHashSet<>(Arrays.asList(PUBLISHER_ID, 54321))),
@@ -595,7 +583,7 @@
      */
     @Test
     public void testHandleStartSessionEvent() throws Exception {
-        when(mSubscriberService.getAvailableLayers()).thenReturn(
+        when(mVmsClient.getAvailableLayers()).thenReturn(
                 new VmsAvailableLayers(Collections.emptySet(), 5));
 
         VehiclePropValue request = createHalMessage(
@@ -612,10 +600,10 @@
 
         sendHalMessage(request);
 
-        InOrder inOrder = Mockito.inOrder(mClientManager, mVehicleHal);
-        inOrder.verify(mClientManager).onHalDisconnected();
+        InOrder inOrder = Mockito.inOrder(mVehicleHal, mVmsClient);
+        inOrder.verify(mVmsClient).unregister();
         inOrder.verify(mVehicleHal).set(response);
-        inOrder.verify(mClientManager).onHalConnected(mPublisherClient, mSubscriberClient);
+        assertEquals(2, mVmsInitCount);
 
         waitForHandlerCompletion();
         inOrder.verify(mVehicleHal).set(createHalMessage(
@@ -643,7 +631,7 @@
      */
     @Test
     public void testOnLayersAvailabilityChanged_ZeroLayers() throws Exception {
-        mSubscriberClient.onLayersAvailabilityChanged(
+        mEventCallback.onLayerAvailabilityChanged(
                 new VmsAvailableLayers(Collections.emptySet(), 123));
 
         VehiclePropValue message = createHalMessage(
@@ -658,7 +646,7 @@
 
     @Test
     public void testOnLayersAvailabilityChanged_OneLayer() throws Exception {
-        mSubscriberClient.onLayersAvailabilityChanged(
+        mEventCallback.onLayerAvailabilityChanged(
                 new VmsAvailableLayers(Collections.singleton(
                         new VmsAssociatedLayer(LAYER, Collections.singleton(PUBLISHER_ID))), 123));
 
@@ -678,7 +666,7 @@
 
     @Test
     public void testOnLayersAvailabilityChanged_MultipleLayers() throws Exception {
-        mSubscriberClient.onLayersAvailabilityChanged(
+        mEventCallback.onLayerAvailabilityChanged(
                 new VmsAvailableLayers(new LinkedHashSet<>(Arrays.asList(
                         new VmsAssociatedLayer(LAYER,
                                 new LinkedHashSet<>(Arrays.asList(PUBLISHER_ID, 54321))),
@@ -745,7 +733,7 @@
                 VmsMessageType.SUBSCRIPTIONS_REQUEST  // Message type
         );
 
-        when(mPublisherService.getSubscriptions()).thenReturn(
+        when(mVmsClient.getSubscriptionState()).thenReturn(
                 new VmsSubscriptionState(123, Collections.emptySet(), Collections.emptySet()));
 
         VehiclePropValue response = createHalMessage(
@@ -766,7 +754,7 @@
                 VmsMessageType.SUBSCRIPTIONS_REQUEST  // Message type
         );
 
-        when(mPublisherService.getSubscriptions()).thenReturn(
+        when(mVmsClient.getSubscriptionState()).thenReturn(
                 new VmsSubscriptionState(123, Collections.singleton(LAYER),
                         Collections.emptySet()));
 
@@ -789,7 +777,7 @@
                 VmsMessageType.SUBSCRIPTIONS_REQUEST  // Message type
         );
 
-        when(mPublisherService.getSubscriptions()).thenReturn(
+        when(mVmsClient.getSubscriptionState()).thenReturn(
                 new VmsSubscriptionState(123, Collections.emptySet(), Collections.singleton(
                         new VmsAssociatedLayer(LAYER, Collections.singleton(PUBLISHER_ID)))));
 
@@ -814,7 +802,7 @@
                 VmsMessageType.SUBSCRIPTIONS_REQUEST  // Message type
         );
 
-        when(mPublisherService.getSubscriptions()).thenReturn(
+        when(mVmsClient.getSubscriptionState()).thenReturn(
                 new VmsSubscriptionState(123,
                         new LinkedHashSet<>(Arrays.asList(
                                 LAYER,
@@ -877,7 +865,7 @@
      */
     @Test
     public void testOnVmsSubscriptionChange_ZeroLayers() throws Exception {
-        mPublisherClient.onVmsSubscriptionChange(
+        mEventCallback.onSubscriptionStateChanged(
                 new VmsSubscriptionState(123, Collections.emptySet(), Collections.emptySet()));
 
         VehiclePropValue response = createHalMessage(
@@ -894,7 +882,7 @@
     @Test
     public void testOnVmsSubscriptionChange_OneLayer_ZeroAssociatedLayers()
             throws Exception {
-        mPublisherClient.onVmsSubscriptionChange(
+        mEventCallback.onSubscriptionStateChanged(
                 new VmsSubscriptionState(123, Collections.singleton(LAYER),
                         Collections.emptySet()));
 
@@ -913,7 +901,7 @@
     @Test
     public void testOnVmsSubscriptionChange_ZeroLayers_OneAssociatedLayer()
             throws Exception {
-        mPublisherClient.onVmsSubscriptionChange(
+        mEventCallback.onSubscriptionStateChanged(
                 new VmsSubscriptionState(123, Collections.emptySet(), Collections.singleton(
                         new VmsAssociatedLayer(LAYER, Collections.singleton(PUBLISHER_ID)))));
 
@@ -934,7 +922,7 @@
     @Test
     public void testOnVmsSubscriptionChange_MultipleLayersAndAssociatedLayers()
             throws Exception {
-        mPublisherClient.onVmsSubscriptionChange(
+        mEventCallback.onSubscriptionStateChanged(
                 new VmsSubscriptionState(123,
                         new LinkedHashSet<>(Arrays.asList(
                                 LAYER,
@@ -977,7 +965,6 @@
         doThrow(new RuntimeException()).when(mVehicleHal).set(any());
         initHalService(false);
 
-        mHalService.init();
         waitForHandlerCompletion();
     }
 
@@ -985,7 +972,7 @@
     public void testPropertySetExceptionNotPropagated_ClientStartSession() throws Exception {
         initHalService(false);
 
-        when(mSubscriberService.getAvailableLayers()).thenReturn(
+        when(mVmsClient.getAvailableLayers()).thenReturn(
                 new VmsAvailableLayers(Collections.emptySet(), 0));
         doThrow(new RuntimeException()).when(mVehicleHal).set(any());
 
@@ -1053,7 +1040,8 @@
         setUp();
 
         when(mVehicleHal.get(metricsPropertyId))
-                .thenThrow(new PropertyTimeoutException(metricsPropertyId));
+                .thenThrow(new ServiceSpecificException(VehicleHalStatusCode.STATUS_TRY_AGAIN,
+                        "propertyId: 0x" + Integer.toHexString(metricsPropertyId)));
 
         mHalService.dumpMetrics(new FileDescriptor());
         verify(mVehicleHal).get(metricsPropertyId);
@@ -1081,7 +1069,7 @@
     }
 
     private void sendHalMessage(VehiclePropValue message) {
-        mHalService.handleHalEvents(Collections.singletonList(message));
+        mHalService.onHalEvents(Collections.singletonList(message));
     }
 
     private void waitForHandlerCompletion() throws Exception {
@@ -1089,4 +1077,9 @@
         mHalService.getHandler().post(latch::countDown);
         latch.await(5, TimeUnit.SECONDS);
     }
+
+    @SafeVarargs
+    private static <T> Set<T> asSet(T... values) {
+        return new HashSet<>(Arrays.asList(values));
+    }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java
new file mode 100644
index 0000000..ae86874
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.hardware.power;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.car.Car;
+import android.car.hardware.power.CarPowerManager;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.test.mocks.JavaMockitoHelper;
+import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateReq;
+import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateShutdownParam;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.car.CarPowerManagementService;
+import com.android.car.MockedPowerHalService;
+import com.android.car.R;
+import com.android.car.hal.PowerHalService;
+import com.android.car.hal.PowerHalService.PowerState;
+import com.android.car.systeminterface.DisplayInterface;
+import com.android.car.systeminterface.SystemInterface;
+import com.android.car.systeminterface.SystemStateInterface;
+import com.android.internal.app.IVoiceInteractionManagerService;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
+import java.time.Duration;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Semaphore;
+
+@SmallTest
+public class CarPowerManagerUnitTest extends AbstractExtendedMockitoTestCase {
+    private static final String TAG = CarPowerManagerUnitTest.class.getSimpleName();
+    private static final long WAIT_TIMEOUT_MS = 5_000;
+    private static final long WAIT_TIMEOUT_LONG_MS = 10_000;
+    // A shorter value for use when the test is expected to time out
+    private static final long WAIT_WHEN_TIMEOUT_EXPECTED_MS = 100;
+
+    private final MockDisplayInterface mDisplayInterface = new MockDisplayInterface();
+    private final MockSystemStateInterface mSystemStateInterface = new MockSystemStateInterface();
+    private final Context mContext =
+            InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+    private MockedPowerHalService mPowerHal;
+    private SystemInterface mSystemInterface;
+    private CarPowerManagementService mService;
+    private CarPowerManager mCarPowerManager;
+
+    @Mock
+    private Resources mResources;
+    @Mock
+    private Car mCar;
+    @Mock
+    private IVoiceInteractionManagerService mVoiceInteractionManagerService;
+
+    @Before
+    public void setUp() throws Exception {
+        mPowerHal = new MockedPowerHalService(true /*isPowerStateSupported*/,
+                true /*isDeepSleepAllowed*/, true /*isTimedWakeupAllowed*/);
+        mSystemInterface = SystemInterface.Builder.defaultSystemInterface(mContext)
+            .withDisplayInterface(mDisplayInterface)
+            .withSystemStateInterface(mSystemStateInterface)
+            .build();
+        setService();
+        mCarPowerManager = new CarPowerManager(mCar, mService);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (mService != null) {
+            mService.release();
+        }
+    }
+
+    @Test
+    public void testRequestShutdownOnNextSuspend_positive() throws Exception {
+        setPowerOn();
+        // Tell it to shutdown
+        mCarPowerManager.requestShutdownOnNextSuspend();
+        // Request suspend
+        setPowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+                VehicleApPowerStateShutdownParam.CAN_SLEEP);
+        // Verify shutdown
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_START, 0);
+    }
+
+    @Test
+    public void testRequestShutdownOnNextSuspend_negative() throws Exception {
+        setPowerOn();
+
+        // Do not tell it to shutdown
+
+        // Request suspend
+        setPowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+                VehicleApPowerStateShutdownParam.CAN_SLEEP);
+        // Verify suspend
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, 0);
+    }
+
+    @Test
+    public void testScheduleNextWakeupTime() throws Exception {
+        setPowerOn();
+
+        int wakeTime = 1234;
+        mCarPowerManager.scheduleNextWakeupTime(wakeTime);
+
+        setPowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+                VehicleApPowerStateShutdownParam.CAN_SLEEP);
+
+        // Verify that we suspended with the requested wake-up time
+        assertStateReceivedForShutdownOrSleepWithPostpone(
+                PowerHalService.SET_DEEP_SLEEP_ENTRY, wakeTime);
+    }
+
+    @Test
+    public void testSetListener() throws Exception {
+        setPowerOn();
+
+        WaitablePowerStateListener listener = new WaitablePowerStateListener(2);
+
+        setPowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+                VehicleApPowerStateShutdownParam.CAN_SLEEP);
+
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, 0);
+
+        int finalState = listener.await();
+        assertThat(finalState).isEqualTo(PowerHalService.SET_DEEP_SLEEP_ENTRY);
+    }
+
+    @Test
+    public void testSetListenerWithCompletion() throws Exception {
+        setPowerOn();
+
+        WaitablePowerStateListenerWithCompletion listener =
+                new WaitablePowerStateListenerWithCompletion(2);
+
+        setPowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+                VehicleApPowerStateShutdownParam.CAN_SLEEP);
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, 0);
+
+        int finalState = listener.await();
+        assertThat(finalState).isEqualTo(PowerHalService.SET_DEEP_SLEEP_ENTRY);
+    }
+
+    @Test
+    public void testClearListener() throws Exception {
+        setPowerOn();
+
+        // Set a listener with a short timeout, because we expect the timeout to happen
+        WaitablePowerStateListener listener =
+                new WaitablePowerStateListener(1, WAIT_WHEN_TIMEOUT_EXPECTED_MS);
+
+        mCarPowerManager.clearListener();
+
+        setPowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+                VehicleApPowerStateShutdownParam.CAN_SLEEP);
+
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, 0);
+        // Verify that the listener didn't run
+        assertThrows(IllegalStateException.class, () -> listener.await());
+    }
+
+    @Test
+    public void testGetPowerState() throws Exception {
+        setPowerOn();
+        assertThat(mCarPowerManager.getPowerState()).isEqualTo(PowerHalService.SET_ON);
+
+        // Request suspend
+        setPowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+                        VehicleApPowerStateShutdownParam.CAN_SLEEP);
+        assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, 0);
+        assertThat(mCarPowerManager.getPowerState())
+                .isEqualTo(PowerHalService.SET_DEEP_SLEEP_ENTRY);
+    }
+
+    /**
+     * Helper method to create mService and initialize a test case
+     */
+    private void setService() throws Exception {
+        Log.i(TAG, "setService(): overridden overlay properties: "
+                + "config_disableUserSwitchDuringResume="
+                + mResources.getBoolean(R.bool.config_disableUserSwitchDuringResume)
+                + ", maxGarageModeRunningDurationInSecs="
+                + mResources.getInteger(R.integer.maxGarageModeRunningDurationInSecs));
+        mService = new CarPowerManagementService(mContext, mResources, mPowerHal,
+                mSystemInterface, null, null, null, mVoiceInteractionManagerService);
+        mService.init();
+        mService.setShutdownTimersForTest(0, 0);
+        assertStateReceived(MockedPowerHalService.SET_WAIT_FOR_VHAL, 0);
+    }
+
+    private void assertStateReceived(int expectedState, int expectedParam) throws Exception {
+        int[] state = mPowerHal.waitForSend(WAIT_TIMEOUT_MS);
+        assertThat(state).asList().containsExactly(expectedState, expectedParam).inOrder();
+    }
+
+    /**
+     * Helper method to get the system into ON
+     */
+    private void setPowerOn() throws Exception {
+        setPowerState(VehicleApPowerStateReq.ON, 0);
+        assertThat(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)).isTrue();
+    }
+
+    /**
+     * Helper to set the PowerHal state
+     *
+     * @param stateEnum Requested state enum
+     * @param stateParam Addition state parameter
+     */
+    private void setPowerState(int stateEnum, int stateParam) {
+        mPowerHal.setCurrentPowerState(new PowerState(stateEnum, stateParam));
+    }
+
+    private void assertStateReceivedForShutdownOrSleepWithPostpone(
+            int lastState, int stateParameter) throws Exception {
+        long startTime = System.currentTimeMillis();
+        while (true) {
+            int[] state = mPowerHal.waitForSend(WAIT_TIMEOUT_LONG_MS);
+            if (state[0] == lastState) {
+                assertThat(state[1]).isEqualTo(stateParameter);
+                return;
+            }
+            assertThat(state[0]).isEqualTo(PowerHalService.SET_SHUTDOWN_POSTPONE);
+            assertThat(System.currentTimeMillis() - startTime).isLessThan(WAIT_TIMEOUT_LONG_MS);
+        }
+    }
+
+    private static final class MockDisplayInterface implements DisplayInterface {
+        private boolean mDisplayOn = true;
+        private final Semaphore mDisplayStateWait = new Semaphore(0);
+
+        @Override
+        public void setDisplayBrightness(int brightness) {}
+
+        @Override
+        public synchronized void setDisplayState(boolean on) {
+            mDisplayOn = on;
+            mDisplayStateWait.release();
+        }
+
+        public synchronized boolean getDisplayState() {
+            return mDisplayOn;
+        }
+
+        public boolean waitForDisplayStateChange(long timeoutMs) throws Exception {
+            JavaMockitoHelper.await(mDisplayStateWait, timeoutMs);
+            return mDisplayOn;
+        }
+
+        @Override
+        public void startDisplayStateMonitoring(CarPowerManagementService service) {}
+
+        @Override
+        public void stopDisplayStateMonitoring() {}
+
+        @Override
+        public void refreshDisplayBrightness() {}
+    }
+
+    /**
+     * Helper class to set a power-state listener,
+     * verify that the listener gets called the
+     * right number of times, and return the final
+     * power state.
+     */
+    private final class WaitablePowerStateListener {
+        private final CountDownLatch mLatch;
+        private int mListenedState = -1;
+        private long mTimeoutValue = WAIT_TIMEOUT_MS;
+
+        WaitablePowerStateListener(int initialCount, long customTimeout) {
+            this(initialCount);
+            mTimeoutValue = customTimeout;
+        }
+
+        WaitablePowerStateListener(int initialCount) {
+            mLatch = new CountDownLatch(initialCount);
+            mCarPowerManager.setListener(
+                    (state) -> {
+                        mListenedState = state;
+                        mLatch.countDown();
+                    });
+        }
+
+        int await() throws Exception {
+            JavaMockitoHelper.await(mLatch, WAIT_TIMEOUT_MS);
+            return mListenedState;
+        }
+    }
+
+    /**
+     * Helper class to set a power-state listener with completion,
+     * verify that the listener gets called the right number of times,
+     * verify that the CompletableFuture is provided, complete the
+     * CompletableFuture, and return the final power state.
+     */
+    private final class WaitablePowerStateListenerWithCompletion {
+        private final CountDownLatch mLatch;
+        private int mListenedState = -1;
+        WaitablePowerStateListenerWithCompletion(int initialCount) {
+            mLatch = new CountDownLatch(initialCount);
+            mCarPowerManager.setListenerWithCompletion(
+                    (state, future) -> {
+                        mListenedState = state;
+                        if (state == PowerHalService.SET_SHUTDOWN_PREPARE) {
+                            assertThat(future).isNotNull();
+                            future.complete(null);
+                        } else {
+                            assertThat(future).isNull();
+                        }
+                        mLatch.countDown();
+                    });
+        }
+
+        int await() throws Exception {
+            JavaMockitoHelper.await(mLatch, WAIT_TIMEOUT_MS);
+            return mListenedState;
+        }
+    }
+
+    private static final class MockSystemStateInterface implements SystemStateInterface {
+        private final Semaphore mShutdownWait = new Semaphore(0);
+        private final Semaphore mSleepWait = new Semaphore(0);
+        private final Semaphore mSleepExitWait = new Semaphore(0);
+        private boolean mWakeupCausedByTimer = false;
+
+        @Override
+        public void shutdown() {
+            mShutdownWait.release();
+        }
+
+        public void waitForShutdown(long timeoutMs) throws Exception {
+            JavaMockitoHelper.await(mShutdownWait, timeoutMs);
+        }
+
+        @Override
+        public boolean enterDeepSleep() {
+            mSleepWait.release();
+            try {
+                mSleepExitWait.acquire();
+            } catch (InterruptedException e) {
+            }
+            return true;
+        }
+
+        public void waitForSleepEntryAndWakeup(long timeoutMs) throws Exception {
+            JavaMockitoHelper.await(mSleepWait, timeoutMs);
+            mSleepExitWait.release();
+        }
+
+        @Override
+        public void scheduleActionForBootCompleted(Runnable action, Duration delay) {}
+
+        @Override
+        public boolean isWakeupCausedByTimer() {
+            Log.i(TAG, "isWakeupCausedByTimer:" + mWakeupCausedByTimer);
+            return mWakeupCausedByTimer;
+        }
+
+        public synchronized void setWakeupCausedByTimer(boolean set) {
+            mWakeupCausedByTimer = set;
+        }
+
+        @Override
+        public boolean isSystemSupportingDeepSleep() {
+            return true;
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/media/CarMediaServiceTest.java b/tests/carservice_unit_test/src/com/android/car/media/CarMediaServiceTest.java
new file mode 100644
index 0000000..fe45782
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/media/CarMediaServiceTest.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.media;
+
+import static android.car.media.CarMediaManager.MEDIA_SOURCE_MODE_BROWSE;
+import static android.car.media.CarMediaManager.MEDIA_SOURCE_MODE_PLAYBACK;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.car.Car;
+import android.car.media.ICarMediaSourceListener;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.test.mocks.AndroidMockitoHelper;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionManager;
+import android.media.session.PlaybackState;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.UserManager;
+
+import com.android.car.CarMediaService;
+import com.android.car.R;
+import com.android.car.user.CarUserService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CarMediaServiceTest extends AbstractExtendedMockitoTestCase {
+
+    private static final String MEDIA_PACKAGE = "test.package";
+    private static final String MEDIA_PACKAGE2 = "test.package2";
+    private static final String MEDIA_CLASS = "test_class";
+    private static final String MEDIA_CLASS2 = "test_class2";
+
+    private static final int TEST_USER_ID = 100;
+
+    private static final ComponentName MEDIA_COMPONENT =
+            new ComponentName(MEDIA_PACKAGE, MEDIA_CLASS);
+    private static final ComponentName MEDIA_COMPONENT2 =
+            new ComponentName(MEDIA_PACKAGE2, MEDIA_CLASS2);
+
+    @Mock private Context mContext;
+    @Mock private Resources mResources;
+    @Mock private CarUserService mUserService;
+    @Mock private UserManager mUserManager;
+    @Mock private PackageManager mPackageManager;
+    @Mock private MediaSessionManager mMediaSessionManager;
+
+    private CarMediaService mCarMediaService;
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder builder) {
+        builder.spyStatic(ActivityManager.class);
+    }
+
+    @Before
+    public void setUp() {
+        when(mContext.checkCallingOrSelfPermission(anyString()))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+
+        doReturn(mResources).when(mContext).getResources();
+        doReturn(mUserManager).when(mContext).getSystemService(Context.USER_SERVICE);
+        UserInfo userInfo = new UserInfo(TEST_USER_ID, "test_user", UserInfo.FLAG_PRIMARY);
+        AndroidMockitoHelper.mockAmGetCurrentUser(TEST_USER_ID);
+        AndroidMockitoHelper.mockUmGetUserInfo(mUserManager, userInfo);
+        doReturn(mMediaSessionManager).when(mContext).getSystemService(MediaSessionManager.class);
+
+        mCarMediaService = new CarMediaService(mContext, mUserService);
+    }
+
+    @Test
+    public void testSetMediaSource_ModePlaybackIndependent() {
+        mCarMediaService.setIndependentPlaybackConfig(true);
+
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK);
+
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
+                .isEqualTo(MEDIA_COMPONENT);
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
+                .isNotEqualTo(MEDIA_COMPONENT);
+    }
+
+    @Test
+    public void testSetMediaSource_ModeBrowseIndependent() {
+        mCarMediaService.setIndependentPlaybackConfig(true);
+
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_BROWSE);
+
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
+                .isEqualTo(MEDIA_COMPONENT);
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
+                .isNotEqualTo(MEDIA_COMPONENT);
+    }
+
+    @Test
+    public void testSetMediaSource_ModePlaybackAndBrowseIndependent() {
+        mCarMediaService.setIndependentPlaybackConfig(true);
+
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_BROWSE);
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT2, MEDIA_SOURCE_MODE_PLAYBACK);
+
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
+                .isEqualTo(MEDIA_COMPONENT);
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
+                .isEqualTo(MEDIA_COMPONENT2);
+    }
+
+    @Test
+    public void testSetMediaSource_Dependent() {
+        mCarMediaService.setIndependentPlaybackConfig(false);
+
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK);
+
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
+                .isEqualTo(MEDIA_COMPONENT);
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
+                .isEqualTo(MEDIA_COMPONENT);
+
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT2, MEDIA_SOURCE_MODE_BROWSE);
+
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
+                .isEqualTo(MEDIA_COMPONENT2);
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
+                .isEqualTo(MEDIA_COMPONENT2);
+    }
+
+    @Test
+    public void testMediaSourceListener_Independent() throws Exception {
+        mCarMediaService.setIndependentPlaybackConfig(true);
+        ICarMediaSourceListener listenerPlayback = mockMediaSourceListener();
+        ICarMediaSourceListener listenerBrowse = mockMediaSourceListener();
+
+        mCarMediaService.registerMediaSourceListener(listenerPlayback, MEDIA_SOURCE_MODE_PLAYBACK);
+        mCarMediaService.registerMediaSourceListener(listenerBrowse, MEDIA_SOURCE_MODE_BROWSE);
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK);
+
+        verify(listenerPlayback).onMediaSourceChanged(MEDIA_COMPONENT);
+        verify(listenerBrowse, never()).onMediaSourceChanged(any());
+    }
+
+    @Test
+    public void testMediaSourceListener_IndependentBrowse() throws Exception {
+        mCarMediaService.setIndependentPlaybackConfig(true);
+        ICarMediaSourceListener listenerPlayback = mockMediaSourceListener();
+        ICarMediaSourceListener listenerBrowse = mockMediaSourceListener();
+
+        mCarMediaService.registerMediaSourceListener(listenerPlayback, MEDIA_SOURCE_MODE_PLAYBACK);
+        mCarMediaService.registerMediaSourceListener(listenerBrowse, MEDIA_SOURCE_MODE_BROWSE);
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_BROWSE);
+
+        verify(listenerBrowse).onMediaSourceChanged(MEDIA_COMPONENT);
+        verify(listenerPlayback, never()).onMediaSourceChanged(any());
+    }
+
+    @Test
+    public void testMediaSourceListener_Dependent() throws Exception {
+        mCarMediaService.setIndependentPlaybackConfig(false);
+        ICarMediaSourceListener listenerPlayback = mockMediaSourceListener();
+        ICarMediaSourceListener listenerBrowse = mockMediaSourceListener();
+
+        mCarMediaService.registerMediaSourceListener(listenerPlayback, MEDIA_SOURCE_MODE_PLAYBACK);
+        mCarMediaService.registerMediaSourceListener(listenerBrowse, MEDIA_SOURCE_MODE_BROWSE);
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK);
+
+        verify(listenerPlayback).onMediaSourceChanged(MEDIA_COMPONENT);
+        verify(listenerBrowse).onMediaSourceChanged(MEDIA_COMPONENT);
+
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_BROWSE);
+
+        verify(listenerPlayback).onMediaSourceChanged(MEDIA_COMPONENT);
+        verify(listenerBrowse).onMediaSourceChanged(MEDIA_COMPONENT);
+    }
+
+    @Test
+    public void testMediaSourceListener_Unregister() throws Exception {
+        ICarMediaSourceListener listener = mockMediaSourceListener();
+
+        mCarMediaService.registerMediaSourceListener(listener, MEDIA_SOURCE_MODE_PLAYBACK);
+        mCarMediaService.unregisterMediaSourceListener(listener, MEDIA_SOURCE_MODE_PLAYBACK);
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK);
+
+        verify(listener, never()).onMediaSourceChanged(MEDIA_COMPONENT);
+    }
+
+    @Test
+    public void testDefaultMediaSource() {
+        initializeMockPackageManager(MEDIA_CLASS);
+        mockUserUnlocked(true);
+
+        mCarMediaService.init();
+
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
+                .isEqualTo(MEDIA_COMPONENT);
+    }
+
+    @Test
+    public void testUnresolvedMediaPackage() {
+        initializeMockPackageManager();
+
+        assertThat(mCarMediaService.isMediaService(MEDIA_COMPONENT)).isFalse();
+    }
+
+    // Tests that PlaybackState changing to STATE_PLAYING will result the media source changing
+    @Test
+    public void testActiveSessionListener_StatePlayingChangesSource() {
+        initializeMockPackageManager(MEDIA_CLASS, MEDIA_CLASS2);
+        mockUserUnlocked(true);
+        mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_PLAYING));
+
+        mCarMediaService.init();
+
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
+                .isEqualTo(MEDIA_COMPONENT2);
+    }
+
+    @Test
+    public void testActiveSessionListener_IndependentBrowseUnchanged() {
+        mCarMediaService.setIndependentPlaybackConfig(true);
+        initializeMockPackageManager(MEDIA_CLASS, MEDIA_CLASS2);
+        mockUserUnlocked(true);
+        mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_PLAYING));
+
+        mCarMediaService.init();
+
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
+                .isEqualTo(MEDIA_COMPONENT2);
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
+                .isEqualTo(MEDIA_COMPONENT);
+    }
+
+    @Test
+    public void testActiveSessionListener_DependentBrowseChanged() {
+        mCarMediaService.setIndependentPlaybackConfig(false);
+        initializeMockPackageManager(MEDIA_CLASS, MEDIA_CLASS2);
+        mockUserUnlocked(true);
+        mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_PLAYING));
+
+        mCarMediaService.init();
+
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
+                .isEqualTo(MEDIA_COMPONENT2);
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
+                .isEqualTo(MEDIA_COMPONENT2);
+    }
+
+    @Test
+    public void testActiveSessionListener_StatePaused() {
+        initializeMockPackageManager(MEDIA_CLASS, MEDIA_CLASS2);
+        mockUserUnlocked(true);
+        mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_PAUSED));
+
+        mCarMediaService.init();
+
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
+                .isEqualTo(MEDIA_COMPONENT);
+    }
+
+    private void mockUserUnlocked(boolean unlocked) {
+        when(mUserManager.isUserUnlocked(anyInt())).thenReturn(unlocked);
+    }
+
+    private ICarMediaSourceListener mockMediaSourceListener() {
+        ICarMediaSourceListener listener = mock(ICarMediaSourceListener.class);
+        when(listener.asBinder()).thenReturn(mock(IBinder.class));
+        return listener;
+    }
+
+    // This method invokes a playback state changed callback on a mock MediaController
+    private void mockPlaybackStateChange(PlaybackState newState) {
+        List<MediaController> controllers = new ArrayList<>();
+        MediaController mockController = mock(MediaController.class);
+        when(mockController.getPackageName()).thenReturn(MEDIA_PACKAGE2);
+        when(mockController.getSessionToken()).thenReturn(mock(MediaSession.Token.class));
+        Bundle sessionExtras = new Bundle();
+        sessionExtras.putString(Car.CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION, MEDIA_CLASS2);
+        when(mockController.getExtras()).thenReturn(sessionExtras);
+
+        doAnswer(invocation -> {
+            MediaController.Callback callback = invocation.getArgument(0);
+            callback.onPlaybackStateChanged(newState);
+            return null;
+        }).when(mockController).registerCallback(notNull());
+        controllers.add(mockController);
+
+        doAnswer(invocation -> {
+            MediaSessionManager.OnActiveSessionsChangedListener callback =
+                    invocation.getArgument(0);
+            callback.onActiveSessionsChanged(controllers);
+            return null;
+        }).when(mMediaSessionManager).addOnActiveSessionsChangedListener(any(
+                MediaSessionManager.OnActiveSessionsChangedListener.class), any(), anyInt(), any());
+    }
+
+    // This method sets up PackageManager queries to return mocked media components if specified
+    private void initializeMockPackageManager(String... classesToResolve) {
+        when(mContext.getString(R.string.config_defaultMediaSource))
+                .thenReturn(MEDIA_COMPONENT.flattenToShortString());
+        List<ResolveInfo> packageList = new ArrayList();
+        for (String className : classesToResolve) {
+            ResolveInfo info = new ResolveInfo();
+            ServiceInfo serviceInfo = new ServiceInfo();
+            serviceInfo.name = className;
+            info.serviceInfo = serviceInfo;
+            packageList.add(info);
+        }
+        when(mPackageManager.queryIntentServicesAsUser(any(), anyInt(), anyInt()))
+                .thenReturn(packageList);
+    }
+
+    private PlaybackState createPlaybackState(@PlaybackState.State int state) {
+        return new PlaybackState.Builder().setState(state, 0, 0).build();
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceControllerTest.java b/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceControllerTest.java
index 2be7db8..ddea0c0 100644
--- a/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceControllerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceControllerTest.java
@@ -16,54 +16,67 @@
 
 package com.android.car.pm;
 
-import static com.google.common.truth.Truth.assertThat;
+import static android.car.test.mocks.CarArgumentMatchers.isUserHandle;
 
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.fail;
 import static org.mockito.Mockito.when;
 
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.testapi.BlockingUserLifecycleListener;
+import android.car.user.CarUserManager;
+import android.car.user.CarUserManager.UserLifecycleEventType;
 import android.car.userlib.CarUserManagerHelper;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.Log;
 
 import androidx.test.core.app.ApplicationProvider;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.car.CarLocalServices;
+import com.android.car.hal.UserHalService;
 import com.android.car.user.CarUserService;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
-@RunWith(AndroidJUnit4.class)
-public class VendorServiceControllerTest {
-    private VendorServiceController mController;
-    private static final Long DEFAULT_TIMEOUT_MS = 1000L;
+public final class VendorServiceControllerTest extends AbstractExtendedMockitoTestCase {
+    private static final String TAG = VendorServiceControllerTest.class.getSimpleName();
+
+    // TODO(b/152069895): decrease value once refactored. In fact, it should not even use
+    // runWithScissors(), but only rely on CountdownLatches
+    private static final long DEFAULT_TIMEOUT_MS = 5_000;
 
     private static final int FG_USER_ID = 13;
 
-    private static final String SERVICE_BIND_ALL_USERS_ASAP = "com.andorid.car/.AllUsersService";
-    private static final String SERVICE_BIND_FG_USER_UNLOCKED = "com.andorid.car/.ForegroundUsers";
-    private static final String SERVICE_START_SYSTEM_UNLOCKED = "com.andorid.car/.SystemUser";
+    private static final String SERVICE_BIND_ALL_USERS_ASAP = "com.android.car/.AllUsersService";
+    private static final String SERVICE_BIND_FG_USER_UNLOCKED = "com.android.car/.ForegroundUsers";
+    private static final String SERVICE_START_SYSTEM_UNLOCKED = "com.android.car/.SystemUser";
 
     private static final String[] FAKE_SERVICES = new String[] {
             SERVICE_BIND_ALL_USERS_ASAP + "#bind=bind,user=all,trigger=asap",
@@ -71,36 +84,39 @@
             SERVICE_START_SYSTEM_UNLOCKED + "#bind=start,user=system,trigger=userUnlocked"
     };
 
-    @Rule
-    public MockitoRule rule = MockitoJUnit.rule();
-
     @Mock
     private Resources mResources;
 
     @Mock
     private UserManager mUserManager;
 
-    private ServiceLauncherContext mContext;
+    @Mock
+    private UserHalService mUserHal;
 
+    private ServiceLauncherContext mContext;
     private CarUserManagerHelper mUserManagerHelper;
     private CarUserService mCarUserService;
+    private VendorServiceController mController;
+
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+        session.spyStatic(ActivityManager.class);
+    }
 
     @Before
     public void setUp() {
         mContext = new ServiceLauncherContext(ApplicationProvider.getApplicationContext());
         mUserManagerHelper = Mockito.spy(new CarUserManagerHelper(mContext));
-        mCarUserService = new CarUserService(mContext, mUserManagerHelper,
+        mCarUserService = new CarUserService(mContext, mUserHal, mUserManagerHelper, mUserManager,
                 ActivityManager.getService(), 2 /* max running users */);
         CarLocalServices.addService(CarUserService.class, mCarUserService);
 
-        mController = new VendorServiceController(mContext,
-                Looper.getMainLooper(), mUserManagerHelper);
+        mController = new VendorServiceController(mContext, Looper.getMainLooper());
 
-        when(mUserManagerHelper.isPersistentUser(anyInt())).thenReturn(true);
-        // Let's pretend system is not fully loaded, current user is system.
-        when(mUserManagerHelper.getCurrentForegroundUserId()).thenReturn(UserHandle.USER_SYSTEM);
-        // ..and by default all users are locked
-        mockUserUnlock(UserHandle.USER_ALL, false /* unlock */);
+        UserInfo persistentFgUser = new UserInfo(FG_USER_ID, "persistent user", 0);
+        when(mUserManager.getUserInfo(FG_USER_ID)).thenReturn(persistentFgUser);
+
         when(mResources.getStringArray(com.android.car.R.array.config_earlyStartupServices))
                 .thenReturn(FAKE_SERVICES);
     }
@@ -121,83 +137,127 @@
     }
 
     @Test
-    public void init_systemUser() throws InterruptedException {
+    public void init_systemUser() throws Exception {
+        mContext.expectServices(SERVICE_BIND_ALL_USERS_ASAP);
+        mockGetCurrentUser(UserHandle.USER_SYSTEM);
         mController.init();
 
-        Thread.sleep(100);
-
         mContext.assertBoundService(SERVICE_BIND_ALL_USERS_ASAP);
         mContext.verifyNoMoreServiceLaunches();
     }
 
     @Test
-    public void systemUserUnlocked() {
+    public void systemUserUnlocked() throws Exception {
         mController.init();
         mContext.reset();
 
+        // TODO(b/152069895): must refactor this test because
+        // SERVICE_BIND_ALL_USERS_ASAP is bound twice (users 0 and 10)
+        mContext.expectServices(SERVICE_START_SYSTEM_UNLOCKED);
+
         // Unlock system user
-        mockUserUnlock(UserHandle.USER_SYSTEM, true);
-        runOnMainThread(() -> mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true));
+        mockUserUnlock(UserHandle.USER_SYSTEM);
+        sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING,
+                UserHandle.USER_SYSTEM);
 
         mContext.assertStartedService(SERVICE_START_SYSTEM_UNLOCKED);
         mContext.verifyNoMoreServiceLaunches();
     }
 
     @Test
-    public void fgUserUnlocked() {
+    public void fgUserUnlocked() throws Exception {
+        mockGetCurrentUser(UserHandle.USER_SYSTEM);
         mController.init();
         mContext.reset();
 
+        mContext.expectServices(SERVICE_BIND_ALL_USERS_ASAP, SERVICE_BIND_FG_USER_UNLOCKED);
+
         // Switch user to foreground
-        when(mUserManagerHelper.getCurrentForegroundUserId()).thenReturn(FG_USER_ID);
-        runOnMainThread(() -> mCarUserService.onSwitchUser(FG_USER_ID));
+        mockGetCurrentUser(FG_USER_ID);
+        // TODO(b/155918094): Update this test,
+        UserInfo nullUser = new UserInfo(UserHandle.USER_NULL, "null user", 0);
+        when(mUserManager.getUserInfo(UserHandle.USER_NULL)).thenReturn(nullUser);
+        sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, FG_USER_ID);
 
         // Expect only services with ASAP trigger to be started
         mContext.assertBoundService(SERVICE_BIND_ALL_USERS_ASAP);
         mContext.verifyNoMoreServiceLaunches();
 
         // Unlock foreground user
-        mockUserUnlock(FG_USER_ID, true);
-        runOnMainThread(() -> mCarUserService.setUserLockStatus(FG_USER_ID, true));
+        mockUserUnlock(FG_USER_ID);
+        sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING, FG_USER_ID);
 
         mContext.assertBoundService(SERVICE_BIND_FG_USER_UNLOCKED);
         mContext.verifyNoMoreServiceLaunches();
     }
 
-    private void runOnMainThread(Runnable r) {
+    private static void runOnMainThreadAndWaitForIdle(Runnable r) {
         Handler.getMain().runWithScissors(r, DEFAULT_TIMEOUT_MS);
+        // Run empty runnable to make sure that all posted handlers are done.
+        Handler.getMain().runWithScissors(() -> { }, DEFAULT_TIMEOUT_MS);
     }
 
-    private void mockUserUnlock(int userId, boolean unlock) {
-        if (UserHandle.USER_ALL == userId) {
-            when(mUserManager.isUserUnlockingOrUnlocked(any())).thenReturn(unlock);
-            when(mUserManager.isUserUnlockingOrUnlocked(anyInt())).thenReturn(unlock);
-        } else {
-            when(mUserManager.isUserUnlockingOrUnlocked(userId)).thenReturn(unlock);
-            when(mUserManager.isUserUnlockingOrUnlocked(UserHandle.of(userId))).thenReturn(unlock);
-        }
+    private void mockUserUnlock(@UserIdInt int userId) {
+        when(mUserManager.isUserUnlockingOrUnlocked(isUserHandle(userId))).thenReturn(true);
+        when(mUserManager.isUserUnlockingOrUnlocked(userId)).thenReturn(true);
+    }
+
+    private static void assertHasService(List<Intent> intents, String service, String action) {
+        assertWithMessage("Service %s not %s yet", service, action).that(intents)
+                .hasSize(1);
+        assertWithMessage("Wrong component %s", action).that(intents.get(0).getComponent())
+                .isEqualTo(ComponentName.unflattenFromString(service));
+        intents.clear();
+    }
+
+    private void sendUserLifecycleEvent(@UserLifecycleEventType int eventType,
+            @UserIdInt int userId) throws InterruptedException {
+        // Adding a blocking listener to ensure CarUserService event notification is completed
+        // before proceeding with test execution.
+        BlockingUserLifecycleListener blockingListener =
+                BlockingUserLifecycleListener.forAnyEvent().build();
+        mCarUserService.addUserLifecycleListener(blockingListener);
+
+        runOnMainThreadAndWaitForIdle(() -> mCarUserService.onUserLifecycleEvent(eventType,
+                /* timestampMs= */ 0, /* fromUserId= */ UserHandle.USER_NULL, userId));
+        blockingListener.waitForAnyEvent();
     }
 
     /** Overrides framework behavior to succeed on binding/starting processes. */
-    public class ServiceLauncherContext extends ContextWrapper {
+    public final class ServiceLauncherContext extends ContextWrapper {
+
+        private final Object mLock = new Object();
+
+        @GuardedBy("mLock")
         private List<Intent> mBoundIntents = new ArrayList<>();
+        @GuardedBy("mLock")
         private List<Intent> mStartedServicesIntents = new ArrayList<>();
 
+        private final Map<String, CountDownLatch> mBoundLatches = new HashMap<>();
+        private final Map<String, CountDownLatch> mStartedLatches = new HashMap<>();
+
         ServiceLauncherContext(Context base) {
             super(base);
         }
 
         @Override
         public ComponentName startServiceAsUser(Intent service, UserHandle user) {
-            mStartedServicesIntents.add(service);
+            synchronized (mLock) {
+                mStartedServicesIntents.add(service);
+            }
+            countdown(mStartedLatches, service, "started");
             return service.getComponent();
         }
 
         @Override
         public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
                 Handler handler, UserHandle user) {
-            mBoundIntents.add(service);
+            synchronized (mLock) {
+                mBoundIntents.add(service);
+                Log.v(TAG, "Added service (" + service + ") to bound intents");
+            }
             conn.onServiceConnected(service.getComponent(), null);
+            countdown(mBoundLatches, service, "bound");
             return true;
         }
 
@@ -212,38 +272,76 @@
             return mResources;
         }
 
-        void assertBoundService(String service) {
-            assertThat(mBoundIntents).hasSize(1);
-            assertThat(mBoundIntents.get(0).getComponent())
-                    .isEqualTo(ComponentName.unflattenFromString(service));
-            mBoundIntents.clear();
+        private void expectServices(String... services) {
+            for (String service : services) {
+                Log.v(TAG, "expecting service " + service);
+                mBoundLatches.put(service, new CountDownLatch(1));
+                mStartedLatches.put(service, new CountDownLatch(1));
+            }
         }
 
-        void assertStartedService(String service) {
-            assertThat(mStartedServicesIntents).hasSize(1);
-            assertThat(mStartedServicesIntents.get(0).getComponent())
-                    .isEqualTo(ComponentName.unflattenFromString(service));
-            mStartedServicesIntents.clear();
+        private void await(Map<String, CountDownLatch> latches, String service, String method)
+                throws InterruptedException {
+            CountDownLatch latch = latches.get(service);
+            Preconditions.checkArgument(latch != null,
+                    "no latch set for %s - did you call expectBoundServices()?", service);
+            Log.d(TAG, "waiting " + DEFAULT_TIMEOUT_MS + "ms for " + method);
+            if (!latch.await(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                String errorMessage = method + " not called in " + DEFAULT_TIMEOUT_MS + "ms";
+                Log.e(TAG, errorMessage);
+                fail(errorMessage);
+            }
+            Log.v(TAG, "latch.await for service (" + service + ") and method ("
+                    + method + ") called fine");
+        }
+
+        private void countdown(Map<String, CountDownLatch> latches, Intent service, String action) {
+            String serviceName = service.getComponent().flattenToShortString();
+            CountDownLatch latch = latches.get(serviceName);
+            if (latch == null) {
+                Log.e(TAG, "unexpected service (" + serviceName + ") " + action + ". Expected only "
+                        + mBoundLatches.keySet());
+            } else {
+                latch.countDown();
+                Log.v(TAG, "latch.countDown for service (" + service + ") and action ("
+                        + action + ") called fine");
+            }
+        }
+
+        void assertBoundService(String service) throws InterruptedException {
+            await(mBoundLatches, service, "bind()");
+            synchronized (mLock) {
+                assertHasService(mBoundIntents, service, "bound");
+            }
+        }
+
+        void assertStartedService(String service) throws InterruptedException {
+            await(mStartedLatches, service, "start()");
+            synchronized (mLock) {
+                assertHasService(mStartedServicesIntents, service, "started");
+            }
         }
 
         void verifyNoMoreServiceLaunches() {
-            assertThat(mStartedServicesIntents).isEmpty();
-            assertThat(mBoundIntents).isEmpty();
+            synchronized (mLock) {
+                assertThat(mStartedServicesIntents).isEmpty();
+                assertThat(mBoundIntents).isEmpty();
+            }
         }
 
         void reset() {
-            mStartedServicesIntents.clear();
-            mBoundIntents.clear();
-
+            synchronized (mLock) {
+                mStartedServicesIntents.clear();
+                mBoundIntents.clear();
+            }
         }
 
         @Override
         public Object getSystemService(String name) {
             if (Context.USER_SERVICE.equals(name)) {
                 return mUserManager;
-            } else {
-                return super.getSystemService(name);
             }
+            return super.getSystemService(name);
         }
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceInfoTest.java b/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceInfoTest.java
index 8174add..9f33ba4 100644
--- a/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceInfoTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceInfoTest.java
@@ -20,14 +20,13 @@
 
 import android.content.ComponentName;
 
-import androidx.test.runner.AndroidJUnit4;
-
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-@RunWith(AndroidJUnit4.class)
+@RunWith(JUnit4.class)
 public class VendorServiceInfoTest {
     private static final String SERVICE_NAME = "com.andorid.car/.MyService";
 
diff --git a/tests/carservice_unit_test/src/com/android/car/storagemonitoring/CarStorageMonitoringTest.java b/tests/carservice_unit_test/src/com/android/car/storagemonitoring/CarStorageMonitoringTest.java
index 50490e9..eb5c4ed 100644
--- a/tests/carservice_unit_test/src/com/android/car/storagemonitoring/CarStorageMonitoringTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/storagemonitoring/CarStorageMonitoringTest.java
@@ -16,7 +16,15 @@
 
 package com.android.car.storagemonitoring;
 
-import static org.mockito.Mockito.*;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
 
 import android.car.storagemonitoring.IoStats;
 import android.car.storagemonitoring.IoStatsEntry;
@@ -37,11 +45,11 @@
 import com.android.car.test.utils.TemporaryDirectory;
 import com.android.car.test.utils.TemporaryFile;
 
-import junit.framework.TestCase;
-
 import org.json.JSONObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import java.io.FileWriter;
 import java.io.StringReader;
@@ -53,22 +61,18 @@
 import java.util.Collections;
 import java.util.List;
 
-
 /**
  * Tests the storage monitoring API in CarService.
  */
+@RunWith(MockitoJUnitRunner.class)
 @MediumTest
-public class CarStorageMonitoringTest extends TestCase {
+public class CarStorageMonitoringTest {
     static final String TAG = CarStorageMonitoringTest.class.getSimpleName();
 
     @Mock private IHealth mMockedHal;
     @Mock private HealthServiceWearInfoProvider.IHealthSupplier mHealthServiceSupplier;
 
-    @Override
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-    }
-
+    @Test
     public void testEMmcWearInformationProvider() throws Exception {
         try (TemporaryFile lifetimeFile = new TemporaryFile(TAG)) {
             try (TemporaryFile eolFile = new TemporaryFile(TAG)) {
@@ -80,16 +84,17 @@
 
                 WearInformation wearInformation = wearInfoProvider.load();
 
-                assertNotNull(wearInformation);
-                assertEquals(40, wearInformation.lifetimeEstimateA);
-                assertEquals(WearInformation.UNKNOWN_LIFETIME_ESTIMATE,
-                        wearInformation.lifetimeEstimateB);
-
-                assertEquals(WearInformation.PRE_EOL_INFO_NORMAL, wearInformation.preEolInfo);
+                assertThat(wearInformation).isNotNull();
+                assertThat(wearInformation.lifetimeEstimateA).isEqualTo(40);
+                assertThat(wearInformation.lifetimeEstimateB)
+                    .isEqualTo(WearInformation.UNKNOWN_LIFETIME_ESTIMATE);
+                assertThat(wearInformation.preEolInfo)
+                    .isEqualTo(WearInformation.PRE_EOL_INFO_NORMAL);
             }
         }
     }
 
+    @Test
     public void testUfsWearInformationProvider() throws Exception {
         try (TemporaryFile lifetimeFile = new TemporaryFile(TAG)) {
             lifetimeFile.write("ufs version: 1.0\n" +
@@ -104,14 +109,15 @@
 
             WearInformation wearInformation = wearInfoProvider.load();
 
-            assertNotNull(wearInformation);
-            assertEquals(90, wearInformation.lifetimeEstimateB);
-            assertEquals(WearInformation.PRE_EOL_INFO_WARNING, wearInformation.preEolInfo);
-            assertEquals(WearInformation.UNKNOWN_LIFETIME_ESTIMATE,
-                    wearInformation.lifetimeEstimateA);
+            assertThat(wearInformation).isNotNull();
+            assertThat(wearInformation.lifetimeEstimateB).isEqualTo(90);
+            assertThat(wearInformation.preEolInfo).isEqualTo(WearInformation.PRE_EOL_INFO_WARNING);
+            assertThat(wearInformation.lifetimeEstimateA)
+                .isEqualTo(WearInformation.UNKNOWN_LIFETIME_ESTIMATE);
         }
     }
 
+    @Test
     public void testHealthServiceWearInformationProvider() throws Exception {
         StorageInfo storageInfo = new StorageInfo();
         storageInfo.eol = WearInformation.PRE_EOL_INFO_NORMAL;
@@ -132,31 +138,38 @@
         }).when(mMockedHal).getStorageInfo(any(getStorageInfoCallback.class));
         WearInformation wearInformation = wearInfoProvider.load();
 
-        assertNotNull(wearInformation);
-        assertEquals(storageInfo.lifetimeA, wearInformation.lifetimeEstimateA);
-        assertEquals(storageInfo.lifetimeB, wearInformation.lifetimeEstimateB);
-        assertEquals(storageInfo.eol, wearInformation.preEolInfo);
+        assertThat(wearInformation).isNotNull();
+        assertThat(wearInformation.lifetimeEstimateA).isEqualTo(storageInfo.lifetimeA);
+        assertThat(wearInformation.lifetimeEstimateB).isEqualTo(storageInfo.lifetimeB);
+        assertThat(wearInformation.preEolInfo).isEqualTo(storageInfo.eol);
     }
 
+    @Test
+    @SuppressWarnings("TruthSelfEquals")
+    // TODO: use EqualsTester to check equality with itself,
+    // Remove @SuppressWarnings("TruthSelfEquals") at other places too
     public void testWearEstimateEquality() {
         WearEstimate wearEstimate1 = new WearEstimate(10, 20);
         WearEstimate wearEstimate2 = new WearEstimate(10, 20);
         WearEstimate wearEstimate3 = new WearEstimate(20, 30);
-        assertEquals(wearEstimate1, wearEstimate1);
-        assertEquals(wearEstimate1, wearEstimate2);
-        assertNotSame(wearEstimate1, wearEstimate3);
+        assertThat(wearEstimate1).isEqualTo(wearEstimate1);
+        assertThat(wearEstimate2).isEqualTo(wearEstimate1);
+        assertThat(wearEstimate1).isNotSameAs(wearEstimate3);
     }
 
+    @Test
     public void testWearEstimateParcel() throws Exception {
         WearEstimate originalWearEstimate = new WearEstimate(10, 20);
         Parcel p = Parcel.obtain();
         originalWearEstimate.writeToParcel(p, 0);
         p.setDataPosition(0);
         WearEstimate newWearEstimate = new WearEstimate(p);
-        assertEquals(originalWearEstimate, newWearEstimate);
+        assertThat(newWearEstimate).isEqualTo(originalWearEstimate);
         p.recycle();
     }
 
+    @Test
+    @SuppressWarnings("TruthSelfEquals")
     public void testWearEstimateChangeEquality() {
         WearEstimateChange wearEstimateChange1 = new WearEstimateChange(
                 new WearEstimate(10, 20),
@@ -170,17 +183,18 @@
             5000L,
             wearEstimateChange1.dateAtChange,
             false);
-        assertEquals(wearEstimateChange1, wearEstimateChange1);
-        assertEquals(wearEstimateChange1, wearEstimateChange2);
+        assertThat(wearEstimateChange1).isEqualTo(wearEstimateChange1);
+        assertThat(wearEstimateChange2).isEqualTo(wearEstimateChange1);
         WearEstimateChange wearEstimateChange3 = new WearEstimateChange(
             new WearEstimate(10, 30),
             new WearEstimate(20, 30),
             3000L,
             Instant.now(),
             true);
-        assertNotSame(wearEstimateChange1, wearEstimateChange3);
+        assertThat(wearEstimateChange1).isNotSameAs(wearEstimateChange3);
     }
 
+    @Test
     public void testWearEstimateChangeParcel() throws Exception {
         WearEstimateChange originalWearEstimateChange = new WearEstimateChange(
                 new WearEstimate(10, 0),
@@ -192,10 +206,11 @@
         originalWearEstimateChange.writeToParcel(p, 0);
         p.setDataPosition(0);
         WearEstimateChange newWearEstimateChange = new WearEstimateChange(p);
-        assertEquals(originalWearEstimateChange, newWearEstimateChange);
+        assertThat(newWearEstimateChange).isEqualTo(originalWearEstimateChange);
         p.recycle();
     }
 
+    @Test
     public void testWearEstimateJson() throws Exception {
         WearEstimate originalWearEstimate = new WearEstimate(20, 0);
         StringWriter stringWriter = new StringWriter(1024);
@@ -204,9 +219,10 @@
         StringReader stringReader = new StringReader(stringWriter.toString());
         JsonReader jsonReader = new JsonReader(stringReader);
         WearEstimate newWearEstimate = new WearEstimate(jsonReader);
-        assertEquals(originalWearEstimate, newWearEstimate);
+        assertThat(newWearEstimate).isEqualTo(originalWearEstimate);
     }
 
+    @Test
     public void testWearEstimateRecordJson() throws Exception {
         try (TemporaryFile temporaryFile = new TemporaryFile(TAG)) {
             WearEstimateRecord originalWearEstimateRecord = new WearEstimateRecord(new WearEstimate(10, 20),
@@ -217,10 +233,12 @@
             JSONObject jsonObject = new JSONObject(
                     new String(Files.readAllBytes(temporaryFile.getPath())));
             WearEstimateRecord newWearEstimateRecord = new WearEstimateRecord(jsonObject);
-            assertEquals(originalWearEstimateRecord, newWearEstimateRecord);
+            assertThat(newWearEstimateRecord).isEqualTo(originalWearEstimateRecord);
         }
     }
 
+    @Test
+    @SuppressWarnings("TruthSelfEquals")
     public void testWearEstimateRecordEquality() throws Exception {
         WearEstimateRecord wearEstimateRecord1 = new WearEstimateRecord(WearEstimate.UNKNOWN_ESTIMATE,
                 new WearEstimate(10, 20), 5000, Instant.ofEpochMilli(2000));
@@ -229,11 +247,12 @@
         WearEstimateRecord wearEstimateRecord3 = new WearEstimateRecord(WearEstimate.UNKNOWN_ESTIMATE,
             new WearEstimate(10, 40), 5000, Instant.ofEpochMilli(1000));
 
-        assertEquals(wearEstimateRecord1, wearEstimateRecord1);
-        assertEquals(wearEstimateRecord1, wearEstimateRecord2);
-        assertNotSame(wearEstimateRecord1, wearEstimateRecord3);
+        assertThat(wearEstimateRecord1).isEqualTo(wearEstimateRecord1);
+        assertThat(wearEstimateRecord2).isEqualTo(wearEstimateRecord1);
+        assertThat(wearEstimateRecord1).isNotSameAs(wearEstimateRecord3);
     }
 
+    @Test
     public void testWearHistoryJson() throws Exception {
         try (TemporaryFile temporaryFile = new TemporaryFile(TAG)) {
             WearEstimateRecord wearEstimateRecord1 = new WearEstimateRecord(
@@ -253,10 +272,12 @@
             JSONObject jsonObject = new JSONObject(
                 new String(Files.readAllBytes(temporaryFile.getPath())));
             WearHistory newWearHistory = new WearHistory(jsonObject);
-            assertEquals(originalWearHistory, newWearHistory);
+            assertThat(newWearHistory).isEqualTo(originalWearHistory);
         }
     }
 
+    @Test
+    @SuppressWarnings("TruthSelfEquals")
     public void testWearHistoryEquality() throws Exception {
         WearEstimateRecord wearEstimateRecord1 = new WearEstimateRecord(
             WearEstimate.UNKNOWN_ESTIMATE,
@@ -281,11 +302,12 @@
         WearHistory wearHistory3 = WearHistory.fromRecords(wearEstimateRecord1,
             wearEstimateRecord2, wearEstimateRecord3, wearEstimateRecord5);
 
-        assertEquals(wearHistory1, wearHistory1);
-        assertEquals(wearHistory1, wearHistory2);
-        assertNotSame(wearHistory1, wearHistory3);
+        assertThat(wearHistory1).isEqualTo(wearHistory1);
+        assertThat(wearHistory2).isEqualTo(wearHistory1);
+        assertThat(wearHistory1).isNotSameAs(wearHistory3);
     }
 
+    @Test
     public void testWearHistoryToChanges() {
         WearEstimateRecord wearEstimateRecord1 = new WearEstimateRecord(
             WearEstimate.UNKNOWN_ESTIMATE,
@@ -302,30 +324,34 @@
 
         List<WearEstimateChange> wearEstimateChanges = wearHistory.toWearEstimateChanges(1);
 
-        assertEquals(3, wearEstimateChanges.size());
+        assertThat(wearEstimateChanges.size()).isEqualTo(3);
         WearEstimateChange unknownToOne = wearEstimateChanges.get(0);
         WearEstimateChange oneToTwo = wearEstimateChanges.get(1);
         WearEstimateChange twoToThree = wearEstimateChanges.get(2);
 
-        assertEquals(unknownToOne.oldEstimate, wearEstimateRecord1.getOldWearEstimate());
-        assertEquals(unknownToOne.newEstimate, wearEstimateRecord1.getNewWearEstimate());
-        assertEquals(unknownToOne.uptimeAtChange, wearEstimateRecord1.getTotalCarServiceUptime());
-        assertEquals(unknownToOne.dateAtChange, wearEstimateRecord1.getUnixTimestamp());
-        assertTrue(unknownToOne.isAcceptableDegradation);
+        assertThat(wearEstimateRecord1.getOldWearEstimate()).isEqualTo(unknownToOne.oldEstimate);
+        assertThat(wearEstimateRecord1.getNewWearEstimate()).isEqualTo(unknownToOne.newEstimate);
+        assertThat(wearEstimateRecord1.getTotalCarServiceUptime())
+            .isEqualTo(unknownToOne.uptimeAtChange);
+        assertThat(wearEstimateRecord1.getUnixTimestamp()).isEqualTo(unknownToOne.dateAtChange);
+        assertThat(unknownToOne.isAcceptableDegradation).isTrue();
 
-        assertEquals(oneToTwo.oldEstimate, wearEstimateRecord2.getOldWearEstimate());
-        assertEquals(oneToTwo.newEstimate, wearEstimateRecord2.getNewWearEstimate());
-        assertEquals(oneToTwo.uptimeAtChange, wearEstimateRecord2.getTotalCarServiceUptime());
-        assertEquals(oneToTwo.dateAtChange, wearEstimateRecord2.getUnixTimestamp());
-        assertTrue(oneToTwo.isAcceptableDegradation);
+        assertThat(wearEstimateRecord2.getOldWearEstimate()).isEqualTo(oneToTwo.oldEstimate);
+        assertThat(wearEstimateRecord2.getNewWearEstimate()).isEqualTo(oneToTwo.newEstimate);
+        assertThat(wearEstimateRecord2.getTotalCarServiceUptime())
+            .isEqualTo(oneToTwo.uptimeAtChange);
+        assertThat(wearEstimateRecord2.getUnixTimestamp()).isEqualTo(oneToTwo.dateAtChange);
+        assertThat(oneToTwo.isAcceptableDegradation).isTrue();
 
-        assertEquals(twoToThree.oldEstimate, wearEstimateRecord3.getOldWearEstimate());
-        assertEquals(twoToThree.newEstimate, wearEstimateRecord3.getNewWearEstimate());
-        assertEquals(twoToThree.uptimeAtChange, wearEstimateRecord3.getTotalCarServiceUptime());
-        assertEquals(twoToThree.dateAtChange, wearEstimateRecord3.getUnixTimestamp());
-        assertFalse(twoToThree.isAcceptableDegradation);
+        assertThat(wearEstimateRecord3.getOldWearEstimate()).isEqualTo(twoToThree.oldEstimate);
+        assertThat(wearEstimateRecord3.getNewWearEstimate()).isEqualTo(twoToThree.newEstimate);
+        assertThat(wearEstimateRecord3.getTotalCarServiceUptime())
+            .isEqualTo(twoToThree.uptimeAtChange);
+        assertThat(wearEstimateRecord3.getUnixTimestamp()).isEqualTo(twoToThree.dateAtChange);
+        assertThat(twoToThree.isAcceptableDegradation).isFalse();
     }
 
+    @Test
     public void testUidIoStatEntry() throws Exception {
         try (TemporaryFile statsFile = new TemporaryFile(TAG)) {
             statsFile.write("0 256797495 181736102 362132480 947167232 0 0 0 0 250 0\n"
@@ -336,41 +362,42 @@
 
             SparseArray<UidIoRecord> entries = statsProvider.load();
 
-            assertNotNull(entries);
-            assertEquals(2, entries.size());
+            assertThat(entries).isNotNull();
+            assertThat(entries.size()).isEqualTo(2);
 
             IoStatsEntry entry = new IoStatsEntry(entries.get(0), 1234);
-            assertNotNull(entry);
-            assertEquals(0, entry.uid);
-            assertEquals(1234, entry.runtimeMillis);
-            assertEquals(256797495, entry.foreground.bytesRead);
-            assertEquals(181736102, entry.foreground.bytesWritten);
-            assertEquals(362132480, entry.foreground.bytesReadFromStorage);
-            assertEquals(947167232, entry.foreground.bytesWrittenToStorage);
-            assertEquals(250, entry.foreground.fsyncCalls);
-            assertEquals(0, entry.background.bytesRead);
-            assertEquals(0, entry.background.bytesWritten);
-            assertEquals(0, entry.background.bytesReadFromStorage);
-            assertEquals(0, entry.background.bytesWrittenToStorage);
-            assertEquals(0, entry.background.fsyncCalls);
+            assertThat(entry).isNotNull();
+            assertThat(entry.uid).isEqualTo(0);
+            assertThat(entry.runtimeMillis).isEqualTo(1234);
+            assertThat(entry.foreground.bytesRead).isEqualTo(256797495);
+            assertThat(entry.foreground.bytesWritten).isEqualTo(181736102);
+            assertThat(entry.foreground.bytesReadFromStorage).isEqualTo(362132480);
+            assertThat(entry.foreground.bytesWrittenToStorage).isEqualTo(947167232);
+            assertThat(entry.foreground.fsyncCalls).isEqualTo(250);
+            assertThat(entry.background.bytesRead).isEqualTo(0);
+            assertThat(entry.background.bytesWritten).isEqualTo(0);
+            assertThat(entry.background.bytesReadFromStorage).isEqualTo(0);
+            assertThat(entry.background.bytesWrittenToStorage).isEqualTo(0);
+            assertThat(entry.background.fsyncCalls).isEqualTo(0);
 
             entry = new IoStatsEntry(entries.get(1006), 4321);
-            assertNotNull(entry);
-            assertEquals(1006, entry.uid);
-            assertEquals(4321, entry.runtimeMillis);
-            assertEquals(489007, entry.foreground.bytesRead);
-            assertEquals(196802, entry.foreground.bytesWritten);
-            assertEquals(0, entry.foreground.bytesReadFromStorage);
-            assertEquals(20480, entry.foreground.bytesWrittenToStorage);
-            assertEquals(1, entry.foreground.fsyncCalls);
-            assertEquals(51474, entry.background.bytesRead);
-            assertEquals(2048, entry.background.bytesWritten);
-            assertEquals(1024, entry.background.bytesReadFromStorage);
-            assertEquals(2048, entry.background.bytesWrittenToStorage);
-            assertEquals(1, entry.background.fsyncCalls);
+            assertThat(entry).isNotNull();
+            assertThat(entry.uid).isEqualTo(1006);
+            assertThat(entry.runtimeMillis).isEqualTo(4321);
+            assertThat(entry.foreground.bytesRead).isEqualTo(489007);
+            assertThat(entry.foreground.bytesWritten).isEqualTo(196802);
+            assertThat(entry.foreground.bytesReadFromStorage).isEqualTo(0);
+            assertThat(entry.foreground.bytesWrittenToStorage).isEqualTo(20480);
+            assertThat(entry.foreground.fsyncCalls).isEqualTo(1);
+            assertThat(entry.background.bytesRead).isEqualTo(51474);
+            assertThat(entry.background.bytesWritten).isEqualTo(2048);
+            assertThat(entry.background.bytesReadFromStorage).isEqualTo(1024);
+            assertThat(entry.background.bytesWrittenToStorage).isEqualTo(2048);
+            assertThat(entry.background.fsyncCalls).isEqualTo(1);
         }
     }
 
+    @Test
     public void testUidIoStatEntryMissingFields() throws Exception {
         try (TemporaryFile statsFile = new TemporaryFile(TAG)) {
             statsFile.write("0 256797495 181736102 362132480 947167232 0 0 0 0 250 0\n"
@@ -381,10 +408,11 @@
 
             SparseArray<UidIoRecord> entries = statsProvider.load();
 
-            assertNull(entries);
+            assertThat(entries).isNull();
         }
     }
 
+    @Test
     public void testUidIoStatEntryNonNumericFields() throws Exception {
         try (TemporaryFile statsFile = new TemporaryFile(TAG)) {
             statsFile.write("0 256797495 181736102 362132480 947167232 0 0 0 0 250 0\n"
@@ -395,10 +423,12 @@
 
             SparseArray<UidIoRecord> entries = statsProvider.load();
 
-            assertNull(entries);
+            assertThat(entries).isNull();
         }
     }
 
+    @Test
+    @SuppressWarnings("TruthSelfEquals")
     public void testUidIoStatEntryEquality() throws Exception {
         IoStatsEntry statEntry1 = new IoStatsEntry(10, 1234,
             new IoStatsEntry.Metrics(10, 20, 30, 40, 50),
@@ -416,13 +446,14 @@
             new IoStatsEntry.Metrics(10, 20, 30, 40, 0),
             new IoStatsEntry.Metrics(100, 200, 300, 400, 500));
 
-        assertEquals(statEntry1, statEntry1);
-        assertEquals(statEntry1, statEntry2);
-        assertNotSame(statEntry1, statEntry3);
-        assertNotSame(statEntry1, statEntry4);
-        assertNotSame(statEntry1, statEntry5);
+        assertThat(statEntry1).isEqualTo(statEntry1);
+        assertThat(statEntry2).isEqualTo(statEntry1);
+        assertThat(statEntry1).isNotSameAs(statEntry3);
+        assertThat(statEntry1).isNotSameAs(statEntry4);
+        assertThat(statEntry1).isNotSameAs(statEntry5);
     }
 
+    @Test
     public void testUidIoStatEntryParcel() throws Exception {
         IoStatsEntry statEntry = new IoStatsEntry(10, 5000,
             new IoStatsEntry.Metrics(10, 20, 30, 40, 50),
@@ -431,9 +462,10 @@
         statEntry.writeToParcel(p, 0);
         p.setDataPosition(0);
         IoStatsEntry other = new IoStatsEntry(p);
-        assertEquals(other, statEntry);
+        assertThat(statEntry).isEqualTo(other);
     }
 
+    @Test
     public void testUidIoStatEntryJson() throws Exception {
         try (TemporaryFile temporaryFile = new TemporaryFile(TAG)) {
             IoStatsEntry statEntry = new IoStatsEntry(10, 1200,
@@ -445,11 +477,12 @@
             JSONObject jsonObject = new JSONObject(
                 new String(Files.readAllBytes(temporaryFile.getPath())));
             IoStatsEntry other = new IoStatsEntry(jsonObject);
-            assertEquals(statEntry, other);
+            assertThat(other).isEqualTo(statEntry);
         }
     }
 
 
+    @Test
     public void testUidIoStatEntryDelta() throws Exception {
         IoStatsEntry statEntry1 = new IoStatsEntry(10, 1000,
             new IoStatsEntry.Metrics(10, 20, 30, 40, 50),
@@ -465,21 +498,21 @@
 
 
         IoStatsEntry delta21 = statEntry2.delta(statEntry1);
-        assertNotNull(delta21);
-        assertEquals(statEntry1.uid, delta21.uid);
+        assertThat(delta21).isNotNull();
+        assertThat(delta21.uid).isEqualTo(statEntry1.uid);
 
-        assertEquals(1000, delta21.runtimeMillis);
-        assertEquals(100, delta21.foreground.bytesRead);
-        assertEquals(100, delta21.foreground.bytesWritten);
-        assertEquals(100, delta21.foreground.bytesReadFromStorage);
-        assertEquals(100, delta21.foreground.bytesWrittenToStorage);
-        assertEquals(100, delta21.foreground.fsyncCalls);
+        assertThat(delta21.runtimeMillis).isEqualTo(1000);
+        assertThat(delta21.foreground.bytesRead).isEqualTo(100);
+        assertThat(delta21.foreground.bytesWritten).isEqualTo(100);
+        assertThat(delta21.foreground.bytesReadFromStorage).isEqualTo(100);
+        assertThat(delta21.foreground.bytesWrittenToStorage).isEqualTo(100);
+        assertThat(delta21.foreground.fsyncCalls).isEqualTo(100);
 
-        assertEquals(200, delta21.background.bytesRead);
-        assertEquals(300, delta21.background.bytesWritten);
-        assertEquals(400, delta21.background.bytesReadFromStorage);
-        assertEquals(410, delta21.background.bytesWrittenToStorage);
-        assertEquals(10, delta21.background.fsyncCalls);
+        assertThat(delta21.background.bytesRead).isEqualTo(200);
+        assertThat(delta21.background.bytesWritten).isEqualTo(300);
+        assertThat(delta21.background.bytesReadFromStorage).isEqualTo(400);
+        assertThat(delta21.background.bytesWrittenToStorage).isEqualTo(410);
+        assertThat(delta21.background.fsyncCalls).isEqualTo(10);
 
         try {
             IoStatsEntry delta31 = statEntry3.delta(statEntry1);
@@ -489,6 +522,7 @@
         }
     }
 
+    @Test
     public void testUidIoStatsRecordDelta() throws Exception {
         IoStatsEntry statEntry = new IoStatsEntry(10, 1000,
             new IoStatsEntry.Metrics(10, 20, 30, 40, 50),
@@ -500,20 +534,20 @@
 
         UidIoRecord delta = statRecord.delta(statEntry);
 
-        assertNotNull(delta);
-        assertEquals(statRecord.uid, delta.uid);
+        assertThat(delta).isNotNull();
+        assertThat(delta.uid).isEqualTo(statRecord.uid);
 
-        assertEquals(10, delta.foreground_rchar);
-        assertEquals(0, delta.foreground_wchar);
-        assertEquals(0, delta.foreground_read_bytes);
-        assertEquals(10, delta.foreground_write_bytes);
-        assertEquals(20, delta.foreground_fsync);
+        assertThat(delta.foreground_rchar).isEqualTo(10);
+        assertThat(delta.foreground_wchar).isEqualTo(0);
+        assertThat(delta.foreground_read_bytes).isEqualTo(0);
+        assertThat(delta.foreground_write_bytes).isEqualTo(10);
+        assertThat(delta.foreground_fsync).isEqualTo(20);
 
-        assertEquals(20, delta.background_rchar);
-        assertEquals(0, delta.background_wchar);
-        assertEquals(0, delta.background_read_bytes);
-        assertEquals(10, delta.background_write_bytes);
-        assertEquals(10, delta.background_fsync);
+        assertThat(delta.background_rchar).isEqualTo(20);
+        assertThat(delta.background_wchar).isEqualTo(0);
+        assertThat(delta.background_read_bytes).isEqualTo(0);
+        assertThat(delta.background_write_bytes).isEqualTo(10);
+        assertThat(delta.background_fsync).isEqualTo(10);
 
         statRecord = new UidIoRecord(30,
             20, 20, 30, 50, 70,
@@ -527,6 +561,8 @@
         }
     }
 
+    @Test
+    @SuppressWarnings("TruthSelfEquals")
     public void testUidIoStatsDelta() throws Exception {
         IoStatsEntry entry10 = new IoStatsEntry(10, 1000,
             new IoStatsEntry.Metrics(10, 20, 30, 40, 50),
@@ -555,12 +591,13 @@
         IoStats delta3 = new IoStats(statsEntries2, 3000);
         IoStats delta4 = new IoStats(statsEntries1, 5000);
 
-        assertEquals(delta1, delta1);
-        assertEquals(delta1, delta2);
-        assertNotSame(delta1, delta3);
-        assertNotSame(delta3, delta4);
+        assertThat(delta1).isEqualTo(delta1);
+        assertThat(delta2).isEqualTo(delta1);
+        assertThat(delta1).isNotSameAs(delta3);
+        assertThat(delta3).isNotSameAs(delta4);
     }
 
+    @Test
     public void testUidIoStatsTotals() throws Exception {
         IoStatsEntry entry10 = new IoStatsEntry(10, 1000,
             new IoStatsEntry.Metrics(20, 0, 10, 0, 0),
@@ -581,26 +618,27 @@
         IoStatsEntry.Metrics backgroundTotals = delta.getBackgroundTotals();
         IoStatsEntry.Metrics overallTotals = delta.getTotals();
 
-        assertEquals(120, foregroundTotals.bytesRead);
-        assertEquals(200, foregroundTotals.bytesWritten);
-        assertEquals(60, foregroundTotals.bytesReadFromStorage);
-        assertEquals(200, foregroundTotals.bytesWrittenToStorage);
-        assertEquals(1, foregroundTotals.fsyncCalls);
+        assertThat(foregroundTotals.bytesRead).isEqualTo(120);
+        assertThat(foregroundTotals.bytesWritten).isEqualTo(200);
+        assertThat(foregroundTotals.bytesReadFromStorage).isEqualTo(60);
+        assertThat(foregroundTotals.bytesWrittenToStorage).isEqualTo(200);
+        assertThat(foregroundTotals.fsyncCalls).isEqualTo(1);
 
 
-        assertEquals(10, backgroundTotals.bytesRead);
-        assertEquals(80, backgroundTotals.bytesWritten);
-        assertEquals(10, backgroundTotals.bytesReadFromStorage);
-        assertEquals(20, backgroundTotals.bytesWrittenToStorage);
-        assertEquals(3, backgroundTotals.fsyncCalls);
+        assertThat(backgroundTotals.bytesRead).isEqualTo(10);
+        assertThat(backgroundTotals.bytesWritten).isEqualTo(80);
+        assertThat(backgroundTotals.bytesReadFromStorage).isEqualTo(10);
+        assertThat(backgroundTotals.bytesWrittenToStorage).isEqualTo(20);
+        assertThat(backgroundTotals.fsyncCalls).isEqualTo(3);
 
-        assertEquals(130, overallTotals.bytesRead);
-        assertEquals(280, overallTotals.bytesWritten);
-        assertEquals(70, overallTotals.bytesReadFromStorage);
-        assertEquals(220, overallTotals.bytesWrittenToStorage);
-        assertEquals(4, overallTotals.fsyncCalls);
+        assertThat(overallTotals.bytesRead).isEqualTo(130);
+        assertThat(overallTotals.bytesWritten).isEqualTo(280);
+        assertThat(overallTotals.bytesReadFromStorage).isEqualTo(70);
+        assertThat(overallTotals.bytesWrittenToStorage).isEqualTo(220);
+        assertThat(overallTotals.fsyncCalls).isEqualTo(4);
     }
 
+    @Test
     public void testUidIoStatsDeltaParcel() throws Exception {
         IoStatsEntry entry10 = new IoStatsEntry(10, 1000,
             new IoStatsEntry.Metrics(10, 20, 30, 40, 50),
@@ -623,13 +661,14 @@
 
         IoStats parceledStatsDelta = new IoStats(p);
 
-        assertEquals(statsDelta.getTimestamp(), parceledStatsDelta.getTimestamp());
+        assertThat(parceledStatsDelta.getTimestamp()).isEqualTo(statsDelta.getTimestamp());
 
         assertEquals(2, parceledStatsDelta.getStats().stream()
                 .filter(e -> e.equals(entry10) || e.equals(entry20))
                 .count());
     }
 
+    @Test
     public void testUidIoStatsDeltaJson() throws Exception {
         try (TemporaryFile temporaryFile = new TemporaryFile(TAG)) {
             IoStatsEntry entry10 = new IoStatsEntry(10, 1000,
@@ -652,10 +691,11 @@
             JSONObject jsonObject = new JSONObject(
                 new String(Files.readAllBytes(temporaryFile.getPath())));
             IoStats other = new IoStats(jsonObject);
-            assertEquals(statsDelta, other);
+            assertThat(other).isEqualTo(statsDelta);
         }
     }
 
+    @Test
     public void testLifetimeWriteInfo() throws Exception {
         try (TemporaryDirectory temporaryDirectory = new TemporaryDirectory(TAG)) {
             try (TemporaryDirectory ext4 = temporaryDirectory.getSubdirectory("ext4");
@@ -683,8 +723,8 @@
 
                     LifetimeWriteInfo[] writeInfos = sysfsLifetimeWriteInfoProvider.load();
 
-                    assertNotNull(writeInfos);
-                    assertEquals(3, writeInfos.length);
+                    assertThat(writeInfos).isNotNull();
+                    assertThat(writeInfos.length).isEqualTo(3);
                     assertTrue(Arrays.stream(writeInfos).anyMatch(
                             li -> li.equals(expected_ext4_part1)));
                     assertTrue(Arrays.stream(writeInfos).anyMatch(
@@ -696,6 +736,8 @@
         }
     }
 
+    @Test
+    @SuppressWarnings("TruthSelfEquals")
     public void testLifetimeWriteInfoEquality() throws Exception {
         LifetimeWriteInfo writeInfo = new LifetimeWriteInfo("part1", "ext4", 123);
         LifetimeWriteInfo writeInfoEq = new LifetimeWriteInfo("part1", "ext4", 123);
@@ -704,13 +746,14 @@
         LifetimeWriteInfo writeInfoNeq2 = new LifetimeWriteInfo("part1", "f2fs", 123);
         LifetimeWriteInfo writeInfoNeq3 = new LifetimeWriteInfo("part1", "ext4", 100);
 
-        assertEquals(writeInfo, writeInfo);
-        assertEquals(writeInfo, writeInfoEq);
-        assertNotSame(writeInfo, writeInfoNeq1);
-        assertNotSame(writeInfo, writeInfoNeq2);
-        assertNotSame(writeInfo, writeInfoNeq3);
+        assertThat(writeInfo).isEqualTo(writeInfo);
+        assertThat(writeInfoEq).isEqualTo(writeInfo);
+        assertThat(writeInfo).isNotSameAs(writeInfoNeq1);
+        assertThat(writeInfo).isNotSameAs(writeInfoNeq2);
+        assertThat(writeInfo).isNotSameAs(writeInfoNeq3);
     }
 
+    @Test
     public void testLifetimeWriteInfoParcel() throws Exception {
         LifetimeWriteInfo lifetimeWriteInfo = new LifetimeWriteInfo("part1", "ext4", 1024);
 
@@ -720,9 +763,10 @@
 
         LifetimeWriteInfo parceled = new LifetimeWriteInfo(p);
 
-        assertEquals(lifetimeWriteInfo, parceled);
+        assertThat(parceled).isEqualTo(lifetimeWriteInfo);
     }
 
+    @Test
     public void testLifetimeWriteInfoJson() throws Exception {
         try (TemporaryFile temporaryFile = new TemporaryFile(TAG)) {
             LifetimeWriteInfo lifetimeWriteInfo = new LifetimeWriteInfo("part1", "ext4", 1024);
@@ -733,7 +777,7 @@
             JSONObject jsonObject = new JSONObject(
                 new String(Files.readAllBytes(temporaryFile.getPath())));
             LifetimeWriteInfo other = new LifetimeWriteInfo(jsonObject);
-            assertEquals(lifetimeWriteInfo, other);
+            assertThat(other).isEqualTo(lifetimeWriteInfo);
         }
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/testapi/BlockingUserLifecycleListenerTest.java b/tests/carservice_unit_test/src/com/android/car/testapi/BlockingUserLifecycleListenerTest.java
new file mode 100644
index 0000000..e94bb77
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/testapi/BlockingUserLifecycleListenerTest.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.testapi;
+
+import static android.car.test.mocks.JavaMockitoHelper.await;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.testng.Assert.assertThrows;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.car.testapi.BlockingUserLifecycleListener;
+import android.car.user.CarUserManager;
+import android.car.user.CarUserManager.UserLifecycleEvent;
+import android.car.user.CarUserManager.UserLifecycleEventType;
+import android.os.UserHandle;
+import android.util.Log;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.stream.Collectors;
+
+public final class BlockingUserLifecycleListenerTest {
+
+    private static final String TAG = BlockingUserLifecycleListenerTest.class.getSimpleName();
+    private static final long TIMEOUT_MS = 500;
+
+    @Test
+    public void testListener_forAnyEvent_invalidBuilderMethods() throws Exception {
+        BlockingUserLifecycleListener.Builder builder = BlockingUserLifecycleListener.forAnyEvent()
+                .setTimeout(666);
+
+        assertThrows(IllegalStateException.class, () -> builder.forUser(10));
+        assertThrows(IllegalStateException.class, () -> builder.forPreviousUser(10));
+        assertThrows(IllegalStateException.class,
+                () -> builder.addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED));
+    }
+
+    @Test
+    public void testForAnyEvent_invalidMethods() throws Exception {
+        BlockingUserLifecycleListener listener =  BlockingUserLifecycleListener.forAnyEvent()
+                .build();
+
+        assertThrows(IllegalStateException.class, () -> listener.waitForEvents());
+        assertThrows(IllegalStateException.class, () -> listener.getAllReceivedEvents());
+    }
+
+    @Test
+    public void testForAnyEvent_timesout() throws Exception {
+        BlockingUserLifecycleListener listener =  BlockingUserLifecycleListener.forAnyEvent()
+                .build();
+
+        assertThrows(IllegalStateException.class, () -> listener.waitForAnyEvent());
+    }
+
+    @Test
+    public void testForAnyEvent_ok() throws Exception {
+        BlockingUserLifecycleListener listener =  BlockingUserLifecycleListener.forAnyEvent()
+                .build();
+        sendAsyncEvents(listener, 10, USER_LIFECYCLE_EVENT_TYPE_UNLOCKED);
+
+        UserLifecycleEvent event = listener.waitForAnyEvent();
+        assertEvent(event, 10, USER_LIFECYCLE_EVENT_TYPE_UNLOCKED);
+    }
+
+    @Test
+    public void testForSpecificEvents_invalidMethods() throws Exception {
+        BlockingUserLifecycleListener listener =  BlockingUserLifecycleListener.forSpecificEvents()
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING).build();
+
+        assertThrows(IllegalStateException.class, () -> listener.waitForAnyEvent());
+    }
+
+    @Test
+    public void testForSpecificEvents_receivedOnlyExpected() throws Exception {
+        BlockingUserLifecycleListener listener =  BlockingUserLifecycleListener.forSpecificEvents()
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
+                .build();
+
+        sendAsyncEvents(listener, 10,
+                USER_LIFECYCLE_EVENT_TYPE_STARTING,
+                USER_LIFECYCLE_EVENT_TYPE_UNLOCKED);
+
+        List<UserLifecycleEvent> events = listener.waitForEvents();
+        assertEvents(events, 10,
+                USER_LIFECYCLE_EVENT_TYPE_STARTING,
+                USER_LIFECYCLE_EVENT_TYPE_UNLOCKED);
+
+        List<UserLifecycleEvent> allReceivedEvents = listener.getAllReceivedEvents();
+        assertThat(allReceivedEvents).containsAllIn(events).inOrder();
+    }
+
+    @Test
+    public void testForSpecificEvents_receivedExtraEvents() throws Exception {
+        BlockingUserLifecycleListener listener =  BlockingUserLifecycleListener.forSpecificEvents()
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING)
+                .build();
+
+        CountDownLatch latch = sendAsyncEvents(listener, 10,
+                USER_LIFECYCLE_EVENT_TYPE_STARTING,
+                USER_LIFECYCLE_EVENT_TYPE_SWITCHING,
+                USER_LIFECYCLE_EVENT_TYPE_UNLOCKING,
+                USER_LIFECYCLE_EVENT_TYPE_UNLOCKED);
+
+        List<UserLifecycleEvent> events = listener.waitForEvents();
+        assertEvents(events, 10,
+                USER_LIFECYCLE_EVENT_TYPE_STARTING,
+                USER_LIFECYCLE_EVENT_TYPE_UNLOCKING);
+
+        await(latch, TIMEOUT_MS);
+        List<UserLifecycleEvent> allReceivedEvents = listener.getAllReceivedEvents();
+        assertEvents(allReceivedEvents, 10,
+                USER_LIFECYCLE_EVENT_TYPE_STARTING,
+                USER_LIFECYCLE_EVENT_TYPE_SWITCHING,
+                USER_LIFECYCLE_EVENT_TYPE_UNLOCKING,
+                USER_LIFECYCLE_EVENT_TYPE_UNLOCKED);
+    }
+
+    @Test
+    public void testForSpecificEvents_filterByUser() throws Exception {
+        BlockingUserLifecycleListener listener =  BlockingUserLifecycleListener.forSpecificEvents()
+                .forUser(10)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
+                .build();
+        UserLifecycleEvent wrong1 = new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPING, 11);
+        UserLifecycleEvent wrong2 = new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED, 11);
+        UserLifecycleEvent right1 = new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING, 10);
+        UserLifecycleEvent right2 = new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, 10);
+
+        CountDownLatch latch = sendAsyncEvents(listener,
+                Arrays.asList(wrong1, right1, right2, wrong2));
+
+        List<UserLifecycleEvent> events = listener.waitForEvents();
+        assertThat(events).containsExactly(right1, right2).inOrder();
+
+        await(latch, TIMEOUT_MS);
+        List<UserLifecycleEvent> allReceivedEvents = listener.getAllReceivedEvents();
+        assertThat(allReceivedEvents)
+                .containsExactly(wrong1, right1, right2, wrong2)
+                .inOrder();
+    }
+
+    @Test
+    public void testForSpecificEvents_filterByUserDuplicatedEventTypes() throws Exception {
+        BlockingUserLifecycleListener listener =  BlockingUserLifecycleListener.forSpecificEvents()
+                .forUser(10)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
+                .build();
+        UserLifecycleEvent wrong1 = new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPING, 11);
+        UserLifecycleEvent wrong2 = new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED, 11);
+        UserLifecycleEvent wrong3 = new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING, 11);
+        UserLifecycleEvent right1 = new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING, 10);
+        UserLifecycleEvent right2 = new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, 10);
+        UserLifecycleEvent right3 = new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING, 10);
+
+        CountDownLatch latch = sendAsyncEvents(listener,
+                Arrays.asList(wrong1, right1, wrong2, right2, right3, wrong3));
+
+        List<UserLifecycleEvent> events = listener.waitForEvents();
+        assertThat(events).containsExactly(right1, right2, right3).inOrder();
+
+        await(latch, TIMEOUT_MS);
+        List<UserLifecycleEvent> allReceivedEvents = listener.getAllReceivedEvents();
+        assertThat(allReceivedEvents)
+                .containsExactly(wrong1, right1, wrong2, right2, right3, wrong3)
+                .inOrder();
+    }
+
+    @Test
+    public void testForSpecificEvents_filterByPreviousUser() throws Exception {
+        BlockingUserLifecycleListener listener = BlockingUserLifecycleListener.forSpecificEvents()
+                .forPreviousUser(10)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
+                .build();
+        UserLifecycleEvent wrong1 =
+                new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPING, 11);
+        UserLifecycleEvent wrong2 =
+                new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED, 10);
+        UserLifecycleEvent wrong3 =
+                new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING, 11, 10);
+        UserLifecycleEvent right1 =
+                new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING, 10, 11);
+        UserLifecycleEvent right2 =
+                new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, 10, 12);
+
+        CountDownLatch latch = sendAsyncEvents(listener,
+                Arrays.asList(wrong1, right1, wrong2, right2, wrong3));
+
+        List<UserLifecycleEvent> events = listener.waitForEvents();
+        assertThat(events).containsExactly(right1, right2).inOrder();
+
+        await(latch, TIMEOUT_MS);
+        List<UserLifecycleEvent> allReceivedEvents = listener.getAllReceivedEvents();
+        assertThat(allReceivedEvents)
+                .containsExactly(wrong1, right1, wrong2, right2, wrong3)
+                .inOrder();
+    }
+
+    @Test
+    public void testForSpecificEvents_filterByPreviousAndTargetUsers() throws Exception {
+        BlockingUserLifecycleListener listener = BlockingUserLifecycleListener.forSpecificEvents()
+                .forPreviousUser(10)
+                .forUser(11)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
+                .build();
+        UserLifecycleEvent wrong1 =
+                new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPING, 11);
+        UserLifecycleEvent wrong2 =
+                new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED, 10);
+        UserLifecycleEvent wrong3 =
+                new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING, 10, 12);
+        UserLifecycleEvent right1 =
+                new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING, 10, 11);
+        UserLifecycleEvent right2 =
+                new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, 10, 11);
+
+        CountDownLatch latch = sendAsyncEvents(listener,
+                Arrays.asList(wrong1, right1, wrong2, right2, wrong3));
+
+        List<UserLifecycleEvent> events = listener.waitForEvents();
+        assertThat(events).containsExactly(right1, right2).inOrder();
+
+        await(latch, TIMEOUT_MS);
+        List<UserLifecycleEvent> allReceivedEvents = listener.getAllReceivedEvents();
+        assertThat(allReceivedEvents)
+                .containsExactly(wrong1, right1, wrong2, right2, wrong3)
+                .inOrder();
+    }
+
+    @NonNull
+    private static CountDownLatch sendAsyncEvents(@NonNull BlockingUserLifecycleListener listener,
+            @UserIdInt int userId, @UserLifecycleEventType int... eventTypes) {
+        List<UserLifecycleEvent> events = Arrays.stream(eventTypes)
+                .mapToObj((type) -> new UserLifecycleEvent(type, userId))
+                .collect(Collectors.toList());
+        return sendAsyncEvents(listener, events);
+    }
+
+    @NonNull
+    private static CountDownLatch sendAsyncEvents(@NonNull BlockingUserLifecycleListener listener,
+            @NonNull List<UserLifecycleEvent> events) {
+        Log.d(TAG, "sendAsyncEvents(" + events + "): called on thread " + Thread.currentThread());
+        CountDownLatch latch = new CountDownLatch(1);
+        new Thread(() -> {
+            Log.d(TAG, "sending " + events.size() + " on thread " + Thread.currentThread());
+            events.forEach((e) -> listener.onEvent(e));
+            Log.d(TAG, "sent");
+            latch.countDown();
+        }, "AsyncEventsThread").start();
+        return latch;
+    }
+
+    private static void assertEvent(UserLifecycleEvent event, @UserIdInt int expectedUserId,
+            @UserLifecycleEventType int expectedType) {
+        assertThat(event).isNotNull();
+        assertWithMessage("wrong type on %s; expected %s", event,
+                CarUserManager.lifecycleEventTypeToString(expectedType)).that(event.getEventType())
+                        .isEqualTo(expectedType);
+        assertThat(event.getUserId()).isEqualTo(expectedUserId);
+        assertThat(event.getUserHandle().getIdentifier()).isEqualTo(expectedUserId);
+        assertThat(event.getPreviousUserId()).isEqualTo(UserHandle.USER_NULL);
+        assertThat(event.getPreviousUserHandle()).isNull();
+    }
+
+    private static void assertEvents(List<UserLifecycleEvent> events, @UserIdInt int expectedUserId,
+            @UserLifecycleEventType int... expectedTypes) {
+        assertThat(events).isNotNull();
+        assertThat(events).hasSize(expectedTypes.length);
+        for (int i = 0; i < expectedTypes.length; i++) {
+            int expectedType = expectedTypes[i];
+            UserLifecycleEvent event = events.get(i);
+            assertEvent(event, expectedUserId, expectedType);
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/trust/BLEMessagePayloadStreamTest.java b/tests/carservice_unit_test/src/com/android/car/trust/BLEMessagePayloadStreamTest.java
index a99b1d7..31e8ca2 100644
--- a/tests/carservice_unit_test/src/com/android/car/trust/BLEMessagePayloadStreamTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/trust/BLEMessagePayloadStreamTest.java
@@ -18,14 +18,13 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import androidx.test.runner.AndroidJUnit4;
-
 import com.android.car.BLEStreamProtos.BLEMessageProto.BLEMessage;
 import com.android.car.BLEStreamProtos.BLEOperationProto.OperationType;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 import java.io.IOException;
 import java.util.List;
@@ -36,7 +35,7 @@
  * <p>Run:
  * {@code atest BLEMessagePayloadStreamTest}
  */
-@RunWith(AndroidJUnit4.class)
+@RunWith(JUnit4.class)
 public class BLEMessagePayloadStreamTest {
     private static final boolean IS_MESSAGE_ENCRYPTED = false;
     private static final OperationType OPERATION_TYPE = OperationType.CLIENT_MESSAGE;
diff --git a/tests/carservice_unit_test/src/com/android/car/trust/BleMessageStreamV1Test.java b/tests/carservice_unit_test/src/com/android/car/trust/BleMessageStreamV1Test.java
new file mode 100644
index 0000000..0483616
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/trust/BleMessageStreamV1Test.java
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.trust;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.os.Handler;
+
+import com.android.car.BLEStreamProtos.BLEMessageProto.BLEMessage;
+import com.android.car.BLEStreamProtos.BLEOperationProto.OperationType;
+import com.android.car.protobuf.InvalidProtocolBufferException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import java.util.UUID;
+
+/**
+ * Unit test for the {@link BleMessageStreamV1}.
+ *
+ * <p>Run:
+ * {@code atest CarServiceUnitTest:BleMessageStreamV1Test}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class BleMessageStreamV1Test {
+    private static final String ADDRESS_MOCK = "00:11:22:33:AA:BB";
+
+    // The UUID values here are arbitrary.
+    private static final UUID WRITE_UUID = UUID.fromString("9a138a69-7c29-400f-9e71-fc29516f9f8b");
+    private static final UUID READ_UUID = UUID.fromString("3e344860-e688-4cce-8411-16161b61ad57");
+
+    private BleMessageStreamV1 mBleMessageStream;
+    private BluetoothDevice mBluetoothDevice;
+
+    @Mock BlePeripheralManager mBlePeripheralManager;
+    @Mock BleMessageStreamCallback mCallbackMock;
+    @Mock Handler mHandlerMock;
+    @Mock BluetoothGattCharacteristic mWriteCharacteristicMock;
+    @Mock BluetoothGattCharacteristic mReadCharacteristicMock;
+
+    @Before
+    public void setUp() {
+        // Mock so that handler will run anything that is posted to it.
+        when(mHandlerMock.post(any(Runnable.class))).thenAnswer(invocation -> {
+            invocation.<Runnable>getArgument(0).run();
+            return null;
+        });
+
+        // Ensure the mock characteristics return valid UUIDs.
+        when(mWriteCharacteristicMock.getUuid()).thenReturn(WRITE_UUID);
+        when(mReadCharacteristicMock.getUuid()).thenReturn(READ_UUID);
+
+        mBluetoothDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(ADDRESS_MOCK);
+        mBleMessageStream = new BleMessageStreamV1(
+                mHandlerMock, mBlePeripheralManager, mBluetoothDevice, mWriteCharacteristicMock,
+                mReadCharacteristicMock);
+        mBleMessageStream.registerCallback(mCallbackMock);
+    }
+
+    @Test
+    public void writeMessage_noChunkingRequired_sendsCorrectMessage() {
+        // Ensure that there is enough space to fit the message.
+        mBleMessageStream.setMaxWriteSize(512);
+
+        byte[] message = "message".getBytes();
+        boolean isPayloadEncrypted = true;
+        OperationType operationType = OperationType.CLIENT_MESSAGE;
+
+        mBleMessageStream.writeMessage(message, operationType, isPayloadEncrypted);
+
+        BLEMessage expectedMessage = BLEMessageV1Factory.makeBLEMessage(
+                message, operationType, isPayloadEncrypted);
+
+        // Verify that the message was written.
+        verify(mWriteCharacteristicMock).setValue(expectedMessage.toByteArray());
+
+        // Verify that there is also a notification of the characteristic change.
+        verify(mBlePeripheralManager).notifyCharacteristicChanged(mBluetoothDevice,
+                mWriteCharacteristicMock, false);
+    }
+
+    @Test
+    public void writeMessage_chunkingRequired_sendsCorrectMessage()
+            throws InvalidProtocolBufferException, IOException {
+        boolean isPayloadEncrypted = true;
+        OperationType operationType = OperationType.CLIENT_MESSAGE;
+
+        int maxSize = 20;
+        int requiredWrites = 9;
+        byte[] message = makeMessage(requiredWrites * maxSize);
+        int headerSize = BLEMessageV1Factory.getProtoHeaderSize(
+                operationType, message.length, isPayloadEncrypted);
+
+        // Make sure the payload can't fit into one chunk.
+        mBleMessageStream.setMaxWriteSize(maxSize + headerSize);
+        mBleMessageStream.writeMessage(message, operationType, isPayloadEncrypted);
+
+        // Each part of the message requires an ACK except the last one.
+        int numOfAcks = requiredWrites - 1;
+
+        for (int i = 0; i < numOfAcks; i++) {
+            mBleMessageStream.onCharacteristicWrite(
+                    mBluetoothDevice,
+                    mReadCharacteristicMock,
+                    BLEMessageV1Factory.makeAcknowledgementMessage().toByteArray());
+        }
+
+        // Each ACK should trigger a canceling of the retry runnable.
+        verify(mHandlerMock, times(numOfAcks)).removeCallbacks(any(Runnable.class));
+
+        ArgumentCaptor<byte[]> messageCaptor = ArgumentCaptor.forClass(byte[].class);
+
+        verify(mWriteCharacteristicMock, times(requiredWrites)).setValue(
+                messageCaptor.capture());
+        verify(mBlePeripheralManager, times(requiredWrites))
+                .notifyCharacteristicChanged(mBluetoothDevice,
+                        mWriteCharacteristicMock, false);
+
+        List<byte[]> writtenBytes = messageCaptor.getAllValues();
+        ByteArrayOutputStream reassembledMessageStream = new ByteArrayOutputStream();
+
+        // Verify the packet numbers.
+        for (int i = 0; i < writtenBytes.size(); i++) {
+            BLEMessage bleMessage = BLEMessage.parseFrom(writtenBytes.get(i));
+
+            assertThat(bleMessage.getPacketNumber()).isEqualTo(i + 1);
+            assertThat(bleMessage.getTotalPackets()).isEqualTo(writtenBytes.size());
+            assertThat(bleMessage.getIsPayloadEncrypted()).isTrue();
+
+            reassembledMessageStream.write(bleMessage.getPayload().toByteArray());
+        }
+
+        // Verify the reassembled message.
+        assertThat(reassembledMessageStream.toByteArray()).isEqualTo(message);
+    }
+
+    @Test
+    public void writeMessage_chunkingRequired_retriesSamePayloadIfNoAckReceived()
+            throws InvalidProtocolBufferException, IOException {
+        // Execute delayed runnables immediately to simulate an ACK timeout.
+        mockHandlerToExecuteDelayedRunnablesImmediately();
+
+        boolean isPayloadEncrypted = true;
+        OperationType operationType = OperationType.CLIENT_MESSAGE;
+
+        int maxSize = 20;
+        int requiredWrites = 9;
+        byte[] message = makeMessage(requiredWrites * maxSize);
+        int headerSize = BLEMessageV1Factory.getProtoHeaderSize(
+                operationType, message.length, isPayloadEncrypted);
+
+        // Make sure the payload can't fit into one chunk.
+        mBleMessageStream.setMaxWriteSize(maxSize + headerSize);
+        mBleMessageStream.writeMessage(message, operationType, isPayloadEncrypted);
+
+        ArgumentCaptor<byte[]> messageCaptor = ArgumentCaptor.forClass(byte[].class);
+
+        // Because there is no ACK, the write should be retried up to the limit.
+        verify(mWriteCharacteristicMock, times(BleMessageStreamV1.BLE_MESSAGE_RETRY_LIMIT))
+                .setValue(messageCaptor.capture());
+        verify(mBlePeripheralManager, times(BleMessageStreamV1.BLE_MESSAGE_RETRY_LIMIT))
+                .notifyCharacteristicChanged(mBluetoothDevice, mWriteCharacteristicMock, false);
+
+        List<byte[]> writtenBytes = messageCaptor.getAllValues();
+        List<byte[]> writtenPayloads = new ArrayList<>();
+
+        for (int i = 0; i < writtenBytes.size(); i++) {
+            BLEMessage bleMessage = BLEMessage.parseFrom(writtenBytes.get(i));
+
+            // The same packet should be written.
+            assertThat(bleMessage.getPacketNumber()).isEqualTo(1);
+            assertThat(bleMessage.getTotalPackets()).isEqualTo(requiredWrites);
+            assertThat(bleMessage.getIsPayloadEncrypted()).isTrue();
+
+            writtenPayloads.add(bleMessage.getPayload().toByteArray());
+        }
+
+        // Verify that the same payload is being written.
+        for (byte[] payload : writtenPayloads) {
+            assertThat(payload).isEqualTo(writtenPayloads.get(0));
+        }
+    }
+
+    @Test
+    public void writeMessage_chunkingRequired_notifiesCallbackIfNoAck()
+            throws InvalidProtocolBufferException, IOException {
+        // Execute delayed runnables immediately to simulate an ACK timeout.
+        mockHandlerToExecuteDelayedRunnablesImmediately();
+
+        boolean isPayloadEncrypted = true;
+        OperationType operationType = OperationType.CLIENT_MESSAGE;
+
+        int maxSize = 20;
+        int requiredWrites = 9;
+        byte[] message = makeMessage(requiredWrites * maxSize);
+        int headerSize = BLEMessageV1Factory.getProtoHeaderSize(
+                operationType, message.length, isPayloadEncrypted);
+
+        // Make sure the payload can't fit into one chunk.
+        mBleMessageStream.setMaxWriteSize(maxSize + headerSize);
+        mBleMessageStream.writeMessage(message, operationType, isPayloadEncrypted);
+
+        // Because there is no ACK, the write should be retried up to the limit.
+        verify(mWriteCharacteristicMock, times(BleMessageStreamV1.BLE_MESSAGE_RETRY_LIMIT))
+                .setValue(any(byte[].class));
+        verify(mBlePeripheralManager, times(BleMessageStreamV1.BLE_MESSAGE_RETRY_LIMIT))
+                .notifyCharacteristicChanged(mBluetoothDevice, mWriteCharacteristicMock, false);
+
+        // But the callback should only be notified once.
+        verify(mCallbackMock).onWriteMessageError();
+    }
+
+    @Test
+    public void processClientMessage_noChunking_notifiesCallbackForCompleteMessage() {
+        byte[] payload = "message".getBytes();
+
+        // This client message is a complete message, meaning it is part 1 of 1.
+        BLEMessage clientMessage = BLEMessageV1Factory.makeBLEMessage(
+                payload, OperationType.CLIENT_MESSAGE, /* isPayloadEncrypted= */ true);
+
+        mBleMessageStream.onCharacteristicWrite(
+                mBluetoothDevice,
+                mReadCharacteristicMock,
+                clientMessage.toByteArray());
+
+        // The callback should be notified with only the payload.
+        verify(mCallbackMock).onMessageReceived(payload, READ_UUID);
+
+        // And the callback should only be notified once.
+        verify(mCallbackMock).onMessageReceived(any(byte[].class), any(UUID.class));
+    }
+
+    @Test
+    public void processClientMessage_chunkingRequired_notifiesCallbackForCompleteMessage() {
+        // The length here is arbitrary.
+        int payloadLength = 1024;
+        byte[] payload = makeMessage(payloadLength);
+
+        // Ensure the max size is smaller than the payload length.
+        int maxSize = 50;
+        List<BLEMessage> clientMessages = BLEMessageV1Factory.makeBLEMessages(
+                payload, OperationType.CLIENT_MESSAGE, maxSize, /* isPayloadEncrypted= */ true);
+
+        for (BLEMessage message : clientMessages) {
+            mBleMessageStream.onCharacteristicWrite(
+                    mBluetoothDevice,
+                    mReadCharacteristicMock,
+                    message.toByteArray());
+        }
+
+        // The callback should be notified with only the payload.
+        verify(mCallbackMock).onMessageReceived(payload, READ_UUID);
+
+        // And the callback should only be notified once.
+        verify(mCallbackMock).onMessageReceived(any(byte[].class), any(UUID.class));
+    }
+
+    @Test
+    public void processClientMessage_chunkingRequired_sendsACKForEachMessagePart() {
+        // The length here is arbitrary.
+        int payloadLength = 1024;
+        byte[] payload = makeMessage(payloadLength);
+
+        // Ensure the max size is smaller than the payload length.
+        int maxSize = 50;
+        List<BLEMessage> clientMessages = BLEMessageV1Factory.makeBLEMessages(
+                payload, OperationType.CLIENT_MESSAGE, maxSize, /* isPayloadEncrypted= */ true);
+
+        for (BLEMessage message : clientMessages) {
+            mBleMessageStream.onCharacteristicWrite(
+                    mBluetoothDevice,
+                    mReadCharacteristicMock,
+                    message.toByteArray());
+        }
+
+        ArgumentCaptor<byte[]> messageCaptor = ArgumentCaptor.forClass(byte[].class);
+
+        // An ACK should be sent for each message received, except the last one.
+        verify(mWriteCharacteristicMock, times(clientMessages.size() - 1))
+                .setValue(messageCaptor.capture());
+        verify(mBlePeripheralManager, times(clientMessages.size() - 1))
+                .notifyCharacteristicChanged(mBluetoothDevice, mWriteCharacteristicMock, false);
+
+        List<byte[]> writtenValues = messageCaptor.getAllValues();
+        byte[] ackMessageBytes = BLEMessageV1Factory.makeAcknowledgementMessage().toByteArray();
+
+        // Now verify that each byte was an ACK message.
+        for (byte[] writtenValue : writtenValues) {
+            assertThat(writtenValue).isEqualTo(ackMessageBytes);
+        }
+    }
+
+    private void mockHandlerToExecuteDelayedRunnablesImmediately() {
+        when(mHandlerMock.postDelayed(any(Runnable.class), anyLong())).thenAnswer(invocation -> {
+            invocation.<Runnable>getArgument(0).run();
+            return null;
+        });
+    }
+
+    /** Returns a random message of the specified length. */
+    private byte[] makeMessage(int length) {
+        byte[] message = new byte[length];
+        new Random().nextBytes(message);
+
+        return message;
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/trust/CarTrustAgentEnrollmentServiceTest.java b/tests/carservice_unit_test/src/com/android/car/trust/CarTrustAgentEnrollmentServiceTest.java
index 3f21ca6..8a41e32 100644
--- a/tests/carservice_unit_test/src/com/android/car/trust/CarTrustAgentEnrollmentServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/trust/CarTrustAgentEnrollmentServiceTest.java
@@ -19,46 +19,50 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.le.AdvertiseCallback;
 import android.car.encryptionrunner.DummyEncryptionRunner;
 import android.car.encryptionrunner.EncryptionRunnerFactory;
 import android.car.encryptionrunner.HandshakeMessage;
 import android.car.trust.TrustedDeviceInfo;
-import android.car.userlib.CarUserManagerHelper;
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.os.RemoteException;
+import android.os.UserHandle;
 
 import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.filters.FlakyTest;
 
 import com.android.car.Utils;
+import com.android.car.trust.CarTrustAgentBleManager.SendMessageCallback;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import java.util.UUID;
 
 /**
  * Unit test for {@link CarTrustAgentEnrollmentService} and {@link CarTrustedDeviceService}.
  */
-@RunWith(AndroidJUnit4.class)
+@RunWith(MockitoJUnitRunner.class)
 public class CarTrustAgentEnrollmentServiceTest {
 
     private static final long TEST_HANDLE1 = 1L;
     private static final long TEST_HANDLE2 = 2L;
+    private static final String DEVICE_ID = "device_id";
+    private static final String KEY = "key";
     // Random uuid for test
     private static final UUID TEST_ID1 = UUID.fromString("9a138a69-7c29-400f-9e71-fc29516f9f8b");
-    private static final UUID TEST_ID2 = UUID.fromString("3e344860-e688-4cce-8411-16161b61ad57");
     private static final String TEST_TOKEN = "test_escrow_token";
     private static final String ADDRESS = "00:11:22:33:AA:BB";
     private static final String DEFAULT_NAME = "My Device";
@@ -70,6 +74,7 @@
     private Context mContext;
     private CarTrustedDeviceService mCarTrustedDeviceService;
     private CarTrustAgentEnrollmentService mCarTrustAgentEnrollmentService;
+    private CarCompanionDeviceStorage mCarCompanionDeviceStorage;
     private BluetoothDevice mBluetoothDevice;
     private int mUserId;
     @Mock
@@ -93,17 +98,16 @@
 
     @Before
     public void setUp() throws RemoteException {
-        MockitoAnnotations.initMocks(this);
-
         mBluetoothDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(ADDRESS);
         mContext = InstrumentationRegistry.getTargetContext();
         mCarTrustedDeviceService = new CarTrustedDeviceService(mContext);
         mCarTrustAgentEnrollmentService = new CarTrustAgentEnrollmentService(mContext,
                 mCarTrustedDeviceService, mMockCarTrustAgentBleManager);
+        mCarCompanionDeviceStorage = new CarCompanionDeviceStorage(mContext);
         mCarTrustedDeviceService.init();
         mCarTrustAgentEnrollmentService.init();
         mCarTrustAgentEnrollmentService.setEnrollmentRequestDelegate(mEnrollDelegate);
-        mUserId = new CarUserManagerHelper(mContext).getCurrentProcessUserId();
+        mUserId = UserHandle.myUserId();
         mCarTrustAgentEnrollmentService.onRemoteDeviceConnected(mBluetoothDevice);
     }
 
@@ -115,10 +119,12 @@
     }
 
     @Test
+    @FlakyTest
     public void testDisableEnrollment_startEnrollmentAdvertisingFail() {
         mCarTrustAgentEnrollmentService.setTrustedDeviceEnrollmentEnabled(false);
         mCarTrustAgentEnrollmentService.startEnrollmentAdvertising();
-        verify(mMockCarTrustAgentBleManager, never()).startEnrollmentAdvertising();
+        verify(mMockCarTrustAgentBleManager, never()).startEnrollmentAdvertising(anyString(),
+                any(AdvertiseCallback.class));
     }
 
     @Test
@@ -129,35 +135,39 @@
                 mCarTrustAgentEnrollmentService.ENROLLMENT_STATE_NONE);
         // Have received device unique id.
         UUID uuid = UUID.randomUUID();
-        mCarTrustAgentEnrollmentService.onEnrollmentDataReceived(Utils.uuidToBytes(uuid));
+        mCarTrustAgentEnrollmentService.onDataReceived(Utils.uuidToBytes(uuid));
         assertThat(mCarTrustAgentEnrollmentService.mEnrollmentState).isEqualTo(
                 mCarTrustAgentEnrollmentService.ENROLLMENT_STATE_UNIQUE_ID);
         assertThat(mCarTrustAgentEnrollmentService.mEncryptionState).isEqualTo(
                 HandshakeMessage.HandshakeState.UNKNOWN);
         // send device unique id
-        verify(mMockCarTrustAgentBleManager).sendEnrollmentMessage(eq(mBluetoothDevice),
-                eq(Utils.uuidToBytes(mCarTrustedDeviceService.getUniqueId())), any(), eq(false));
+        verify(mMockCarTrustAgentBleManager).sendMessage(
+                eq(Utils.uuidToBytes(mCarCompanionDeviceStorage.getUniqueId())), any(), eq(false),
+                any(SendMessageCallback.class));
 
         // Have received handshake request.
-        mCarTrustAgentEnrollmentService.onEnrollmentDataReceived(
+        mCarTrustAgentEnrollmentService.onDataReceived(
                 DummyEncryptionRunner.INIT.getBytes());
         assertThat(mCarTrustAgentEnrollmentService.mEncryptionState).isEqualTo(
                 HandshakeMessage.HandshakeState.IN_PROGRESS);
         // Send response to init handshake request
-        verify(mMockCarTrustAgentBleManager).sendEnrollmentMessage(eq(mBluetoothDevice),
-                eq(DummyEncryptionRunner.INIT_RESPONSE.getBytes()), any(), eq(false));
+        verify(mMockCarTrustAgentBleManager).sendMessage(
+                eq(DummyEncryptionRunner.INIT_RESPONSE.getBytes()), any(), eq(false),
+                any(SendMessageCallback.class));
 
-        mCarTrustAgentEnrollmentService.onEnrollmentDataReceived(
+        mCarTrustAgentEnrollmentService.onDataReceived(
                 DummyEncryptionRunner.CLIENT_RESPONSE.getBytes());
         assertThat(mCarTrustAgentEnrollmentService.mEncryptionState).isEqualTo(
                 HandshakeMessage.HandshakeState.VERIFICATION_NEEDED);
-        verify(mMockCarTrustAgentBleManager).sendEnrollmentMessage(eq(mBluetoothDevice),
-                eq(DummyEncryptionRunner.INIT_RESPONSE.getBytes()), any(), eq(false));
+        verify(mMockCarTrustAgentBleManager).sendMessage(
+                eq(DummyEncryptionRunner.INIT_RESPONSE.getBytes()), any(), eq(false),
+                any(SendMessageCallback.class));
 
         // Completed the handshake by confirming the verification code.
         mCarTrustAgentEnrollmentService.enrollmentHandshakeAccepted(mBluetoothDevice);
-        verify(mMockCarTrustAgentBleManager).sendEnrollmentMessage(eq(mBluetoothDevice),
-                eq(mCarTrustAgentEnrollmentService.CONFIRMATION_SIGNAL), any(), eq(false));
+        verify(mMockCarTrustAgentBleManager).sendMessage(
+                eq(mCarTrustAgentEnrollmentService.CONFIRMATION_SIGNAL), any(), eq(false),
+                any(SendMessageCallback.class));
         assertThat(mCarTrustAgentEnrollmentService.mEncryptionState).isEqualTo(
                 HandshakeMessage.HandshakeState.FINISHED);
         assertThat(mCarTrustAgentEnrollmentService.mEnrollmentState).isEqualTo(
@@ -185,8 +195,8 @@
         mCarTrustAgentEnrollmentService.onEscrowTokenActiveStateChanged(
                 TEST_HANDLE1, /* isTokenActive= */ true, mUserId);
 
-        verify(mMockCarTrustAgentBleManager).sendEnrollmentMessage(eq(mBluetoothDevice), any(),
-                any(), eq(true));
+        verify(mMockCarTrustAgentBleManager).sendMessage(any(),
+                any(), eq(true), any(SendMessageCallback.class));
         assertThat(mCarTrustAgentEnrollmentService.getEnrolledDeviceInfosForUser(
                 mUserId)).containsExactly(DEVICE_INFO1);
         assertThat(mCarTrustAgentEnrollmentService.isEscrowTokenActive(TEST_HANDLE1,
@@ -224,14 +234,14 @@
     @Test
     public void testOnEscrowTokenRemoved_removeOneTrustedDevice() {
         setupEncryptionHandshake(TEST_ID1);
-        SharedPreferences sharedPrefs = mCarTrustedDeviceService.getSharedPrefs();
+        SharedPreferences sharedPrefs = mCarCompanionDeviceStorage.getSharedPrefs();
         mCarTrustAgentEnrollmentService.onEscrowTokenActiveStateChanged(
                 TEST_HANDLE1, /* isTokenActive= */ true,
                 mUserId);
 
         assertThat(mCarTrustAgentEnrollmentService.getEnrolledDeviceInfosForUser(
                 mUserId)).containsExactly(DEVICE_INFO1);
-        assertThat(mCarTrustedDeviceService.getUserHandleByTokenHandle(TEST_HANDLE1)).isEqualTo(
+        assertThat(mCarCompanionDeviceStorage.getUserHandleByTokenHandle(TEST_HANDLE1)).isEqualTo(
                 mUserId);
         assertThat(sharedPrefs.getLong(TEST_ID1.toString(), -1)).isEqualTo(TEST_HANDLE1);
 
@@ -241,31 +251,39 @@
 
         assertThat(mCarTrustAgentEnrollmentService.getEnrolledDeviceInfosForUser(
                 mUserId)).containsExactly(DEVICE_INFO1, DEVICE_INFO2);
-        assertThat(mCarTrustedDeviceService.getUserHandleByTokenHandle(TEST_HANDLE2)).isEqualTo(
+        assertThat(mCarCompanionDeviceStorage.getUserHandleByTokenHandle(TEST_HANDLE2)).isEqualTo(
                 mUserId);
         assertThat(sharedPrefs.getLong(TEST_ID1.toString(), -1)).isEqualTo(TEST_HANDLE2);
 
-        // Remove all handles
+        // Remove one handle
         mCarTrustAgentEnrollmentService.onEscrowTokenRemoved(TEST_HANDLE1, mUserId);
 
         assertThat(mCarTrustAgentEnrollmentService.getEnrolledDeviceInfosForUser(
                 mUserId)).containsExactly(DEVICE_INFO2);
-        assertThat(mCarTrustedDeviceService.getUserHandleByTokenHandle(TEST_HANDLE1)).isEqualTo(-1);
-        assertThat(mCarTrustedDeviceService.getUserHandleByTokenHandle(TEST_HANDLE2)).isEqualTo(
+        assertThat(mCarCompanionDeviceStorage
+                .getUserHandleByTokenHandle(TEST_HANDLE1))
+                .isEqualTo(-1);
+        assertThat(mCarCompanionDeviceStorage.getUserHandleByTokenHandle(TEST_HANDLE2)).isEqualTo(
                 mUserId);
         assertThat(sharedPrefs.getLong(TEST_ID1.toString(), -1)).isEqualTo(TEST_HANDLE2);
-
-        mCarTrustAgentEnrollmentService.onEscrowTokenRemoved(TEST_HANDLE2, mUserId);
-
-        assertThat(mCarTrustAgentEnrollmentService.getEnrolledDeviceInfosForUser(
-            mUserId)).isEmpty();
-        assertThat(mCarTrustedDeviceService.getUserHandleByTokenHandle(TEST_HANDLE2)).isEqualTo(-1);
-        assertThat(sharedPrefs.getLong(TEST_ID1.toString(), -1)).isEqualTo(-1);
     }
 
     @Test
     public void testGetUserHandleByTokenHandle_nonExistentHandle() {
-        assertThat(mCarTrustedDeviceService.getUserHandleByTokenHandle(TEST_HANDLE1)).isEqualTo(-1);
+        assertThat(mCarCompanionDeviceStorage
+                .getUserHandleByTokenHandle(TEST_HANDLE1))
+                .isEqualTo(-1);
+    }
+
+    @Test
+    public void testEncryptionKeyStorage() {
+        byte[] encryptionKey = KEY.getBytes();
+        if (mCarCompanionDeviceStorage.saveEncryptionKey(DEVICE_ID, encryptionKey)) {
+            assertThat(mCarCompanionDeviceStorage.getEncryptionKey(DEVICE_ID))
+                .isEqualTo(encryptionKey);
+        }
+        mCarCompanionDeviceStorage.clearEncryptionKey(DEVICE_ID);
+        assertThat(mCarCompanionDeviceStorage.getEncryptionKey(DEVICE_ID) == null).isTrue();
     }
 
     @Test
@@ -273,17 +291,17 @@
         setupEncryptionHandshake(TEST_ID1);
         mCarTrustAgentEnrollmentService.onEscrowTokenActiveStateChanged(
                 TEST_HANDLE1, /* isTokenActive= */ true, mUserId);
-        assertThat(mCarTrustedDeviceService.getUserHandleByTokenHandle(TEST_HANDLE1)).isEqualTo(
+        assertThat(mCarCompanionDeviceStorage.getUserHandleByTokenHandle(TEST_HANDLE1)).isEqualTo(
                 mUserId);
     }
 
     private void setupEncryptionHandshake(UUID uuid) {
         mCarTrustAgentEnrollmentService.setEncryptionRunner(
                 EncryptionRunnerFactory.newDummyRunner());
-        mCarTrustAgentEnrollmentService.onEnrollmentDataReceived(Utils.uuidToBytes(uuid));
-        mCarTrustAgentEnrollmentService.onEnrollmentDataReceived(
+        mCarTrustAgentEnrollmentService.onDataReceived(Utils.uuidToBytes(uuid));
+        mCarTrustAgentEnrollmentService.onDataReceived(
                 DummyEncryptionRunner.INIT.getBytes());
-        mCarTrustAgentEnrollmentService.onEnrollmentDataReceived(
+        mCarTrustAgentEnrollmentService.onDataReceived(
                 DummyEncryptionRunner.CLIENT_RESPONSE.getBytes());
         mCarTrustAgentEnrollmentService.enrollmentHandshakeAccepted(mBluetoothDevice);
     }
diff --git a/tests/carservice_unit_test/src/com/android/car/user/CarUserManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/user/CarUserManagerUnitTest.java
new file mode 100644
index 0000000..8a024aa
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/user/CarUserManagerUnitTest.java
@@ -0,0 +1,519 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.user;
+
+import static android.car.test.mocks.AndroidMockitoHelper.getResult;
+import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetUsers;
+import static android.car.testapi.CarMockitoHelper.mockHandleRemoteExceptionFromCarServiceWithDefaultValue;
+import static android.os.UserHandle.USER_SYSTEM;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.car.Car;
+import android.car.ICarUserService;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.test.util.UserTestingHelper;
+import android.car.user.CarUserManager;
+import android.car.user.CarUserManager.UserLifecycleListener;
+import android.car.user.CarUserManager.UserSwitchUiCallback;
+import android.car.user.UserCreationResult;
+import android.car.user.UserIdentificationAssociationResponse;
+import android.car.user.UserRemovalResult;
+import android.car.user.UserSwitchResult;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.content.pm.UserInfo.UserInfoFlag;
+import android.os.RemoteException;
+import android.os.UserManager;
+import android.provider.Settings;
+
+import com.android.internal.infra.AndroidFuture;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
+public final class CarUserManagerUnitTest extends AbstractExtendedMockitoTestCase {
+
+    @Mock
+    private Car mCar;
+    @Mock
+    private UserManager mUserManager;
+    @Mock
+    private ICarUserService mService;
+    @Mock
+    private Context mMockContext;
+
+    private CarUserManager mMgr;
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+        session.spyStatic(UserManager.class);
+    }
+
+    @Before
+    public void setFixtures() {
+        mMgr = new CarUserManager(mCar, mService, mUserManager);
+        when(mCar.getContext()).thenReturn(mMockContext);
+    }
+
+    @Test
+    public void testIsValidUser_headlessSystemUser() {
+        mockIsHeadlessSystemUserMode(true);
+        setExistingUsers(USER_SYSTEM);
+
+        assertThat(mMgr.isValidUser(USER_SYSTEM)).isFalse();
+    }
+
+    @Test
+    public void testIsValidUser_nonHeadlessSystemUser() {
+        mockIsHeadlessSystemUserMode(false);
+        setExistingUsers(USER_SYSTEM);
+
+        assertThat(mMgr.isValidUser(USER_SYSTEM)).isTrue();
+    }
+
+    @Test
+    public void testIsValidUser_found() {
+        setExistingUsers(1, 2, 3);
+
+        assertThat(mMgr.isValidUser(1)).isTrue();
+        assertThat(mMgr.isValidUser(2)).isTrue();
+        assertThat(mMgr.isValidUser(3)).isTrue();
+    }
+
+    @Test
+    public void testIsValidUser_notFound() {
+        setExistingUsers(1, 2, 3);
+
+        assertThat(mMgr.isValidUser(4)).isFalse();
+    }
+
+    @Test
+    public void testIsValidUser_emptyUsers() {
+        assertThat(mMgr.isValidUser(666)).isFalse();
+    }
+
+    @Test
+    public void testAddListener_nullExecutor() {
+        assertThrows(NullPointerException.class, () -> mMgr.addListener(null, (e) -> { }));
+    }
+
+    @Test
+    public void testAddListener_nullListener() {
+        assertThrows(NullPointerException.class, () -> mMgr.addListener(Runnable::run, null));
+    }
+
+    @Test
+    public void testAddListener_sameListenerAddedTwice() {
+        UserLifecycleListener listener = (e) -> { };
+
+        mMgr.addListener(Runnable::run, listener);
+        assertThrows(IllegalStateException.class, () -> mMgr.addListener(Runnable::run, listener));
+    }
+
+    @Test
+    public void testAddListener_differentListenersAddedTwice() {
+        mMgr.addListener(Runnable::run, (e) -> { });
+        mMgr.addListener(Runnable::run, (e) -> { });
+    }
+
+    @Test
+    public void testRemoveListener_nullListener() {
+        assertThrows(NullPointerException.class, () -> mMgr.removeListener(null));
+    }
+
+    @Test
+    public void testRemoveListener_notAddedBefore() {
+        UserLifecycleListener listener = (e) -> { };
+
+        assertThrows(IllegalStateException.class, () -> mMgr.removeListener(listener));
+    }
+
+    @Test
+    public void testRemoveListener_addAndRemove() {
+        UserLifecycleListener listener = (e) -> { };
+
+        mMgr.addListener(Runnable::run, listener);
+        mMgr.removeListener(listener);
+
+        // Make sure it was removed
+        assertThrows(IllegalStateException.class, () -> mMgr.removeListener(listener));
+    }
+
+    @Test
+    public void testSwitchUser_success() throws Exception {
+        expectServiceSwitchUserSucceeds(11, UserSwitchResult.STATUS_SUCCESSFUL, "D'OH!");
+
+        AndroidFuture<UserSwitchResult> future = mMgr.switchUser(11);
+
+        assertThat(future).isNotNull();
+        UserSwitchResult result = getResult(future);
+        assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+        assertThat(result.getErrorMessage()).isEqualTo("D'OH!");
+    }
+
+    @Test
+    public void testSwitchUser_noUserSwitchability() throws Exception {
+        when(mUserManager.getUserSwitchability())
+                .thenReturn(UserManager.SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED);
+
+        AndroidFuture<UserSwitchResult> future = mMgr.switchUser(11);
+
+        assertThat(future).isNotNull();
+        UserSwitchResult result = getResult(future);
+        assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_NOT_SWITCHABLE);
+        assertThat(result.getErrorMessage()).isNull();
+    }
+
+    @Test
+    public void testSwitchUser_remoteException() throws Exception {
+        expectServiceSwitchUserFails(11);
+        mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
+
+        AndroidFuture<UserSwitchResult> future = mMgr.switchUser(11);
+
+        assertThat(future).isNotNull();
+        UserSwitchResult result = getResult(future);
+        assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
+        assertThat(result.getErrorMessage()).isNull();
+    }
+
+    @Test
+    public void testRemoveUser_success() throws Exception {
+        int userId = 11;
+        int status = UserRemovalResult.STATUS_SUCCESSFUL;
+        when(mService.removeUser(userId)).thenReturn(new UserRemovalResult(status));
+
+        UserRemovalResult result = mMgr.removeUser(11);
+
+        assertThat(result.getStatus()).isEqualTo(UserRemovalResult.STATUS_SUCCESSFUL);
+    }
+
+    @Test
+    public void testRemoveUser_remoteException() throws Exception {
+        int userId = 11;
+        doThrow(new RemoteException("D'OH!")).when(mService).removeUser(eq(userId));
+        mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
+
+        UserRemovalResult result = mMgr.removeUser(11);
+
+        assertThat(result.getStatus()).isEqualTo(UserRemovalResult.STATUS_HAL_INTERNAL_FAILURE);
+    }
+
+    @Test
+    public void testSetSwitchUserUICallback_success() throws Exception {
+        UserSwitchUiCallback callback = (u)-> { };
+
+        mMgr.setUserSwitchUiCallback(callback);
+
+        verify(mService).setUserSwitchUiCallback(any());
+    }
+
+    @Test
+    public void testSetSwitchUserUICallback_nullCallback() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> mMgr.setUserSwitchUiCallback(null));
+    }
+
+    @Test
+    public void testCreateUser_withType_success() throws Exception {
+        expectServiceCreateUserSucceeds("dude", "sweet", 42, UserCreationResult.STATUS_SUCCESSFUL,
+                108);
+
+        AndroidFuture<UserCreationResult> future = mMgr.createUser("dude", "sweet", 42);
+
+        assertThat(future).isNotNull();
+        UserCreationResult result = getResult(future);
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_SUCCESSFUL);
+        assertThat(result.isSuccess()).isTrue();
+        assertThat(result.getErrorMessage()).isNull();
+
+        UserInfo newUser = result.getUser();
+        assertThat(newUser).isNotNull();
+        assertThat(newUser.id).isEqualTo(108);
+        assertThat(newUser.name).isEqualTo("dude");
+        assertThat(newUser.userType).isEqualTo("sweet");
+        assertThat(newUser.flags).isEqualTo(42);
+    }
+
+    @Test
+    public void testCreateUser_withType_remoteException() throws Exception {
+        expectServiceCreateUserFails("dude", "sweet", 42);
+        mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
+
+        AndroidFuture<UserCreationResult> future = mMgr.createUser("dude", "sweet", 42);
+
+        assertThat(future).isNotNull();
+        UserCreationResult result = getResult(future);
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
+        assertThat(result.isSuccess()).isFalse();
+        assertThat(result.getErrorMessage()).isNull();
+        assertThat(result.getUser()).isNull();
+    }
+
+    @Test
+    public void testCreateUser_success() throws Exception {
+        expectServiceCreateUserSucceeds("dude", UserManager.USER_TYPE_FULL_SECONDARY, 42,
+                UserCreationResult.STATUS_SUCCESSFUL, 108);
+
+        AndroidFuture<UserCreationResult> future = mMgr.createUser("dude", 42);
+
+        assertThat(future).isNotNull();
+        UserCreationResult result = getResult(future);
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_SUCCESSFUL);
+        assertThat(result.isSuccess()).isTrue();
+        assertThat(result.getErrorMessage()).isNull();
+
+        UserInfo newUser = result.getUser();
+        assertThat(newUser).isNotNull();
+        assertThat(newUser.id).isEqualTo(108);
+        assertThat(newUser.name).isEqualTo("dude");
+        assertThat(newUser.userType).isEqualTo(UserManager.USER_TYPE_FULL_SECONDARY);
+        assertThat(newUser.flags).isEqualTo(42);
+    }
+
+    @Test
+    public void testCreateUser_remoteException() throws Exception {
+        expectServiceCreateUserFails("dude", UserManager.USER_TYPE_FULL_SECONDARY, 42);
+        mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
+
+        AndroidFuture<UserCreationResult> future = mMgr.createUser("dude", 42);
+
+        assertThat(future).isNotNull();
+        UserCreationResult result = getResult(future);
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
+        assertThat(result.isSuccess()).isFalse();
+        assertThat(result.getErrorMessage()).isNull();
+        assertThat(result.getUser()).isNull();
+    }
+
+    @Test
+    public void testCreateGuest_success() throws Exception {
+        expectServiceCreateUserSucceeds("dudeGuest", UserManager.USER_TYPE_FULL_GUEST, 0,
+                UserCreationResult.STATUS_SUCCESSFUL, 108);
+
+        AndroidFuture<UserCreationResult> future = mMgr.createGuest("dudeGuest");
+
+        assertThat(future).isNotNull();
+        UserCreationResult result = getResult(future);
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_SUCCESSFUL);
+        assertThat(result.isSuccess()).isTrue();
+        assertThat(result.getErrorMessage()).isNull();
+
+        UserInfo newUser = result.getUser();
+        assertThat(newUser).isNotNull();
+        assertThat(newUser.id).isEqualTo(108);
+        assertThat(newUser.name).isEqualTo("dudeGuest");
+        assertThat(newUser.userType).isEqualTo(UserManager.USER_TYPE_FULL_GUEST);
+        assertThat(newUser.flags).isEqualTo(0);
+        assertThat(getSettingsString(Settings.Secure.SKIP_FIRST_USE_HINTS)).isEqualTo("1");
+    }
+
+    @Test
+    public void testCreateGuest_remoteException() throws Exception {
+        expectServiceCreateUserFails("dudeGuest", UserManager.USER_TYPE_FULL_GUEST, 0);
+        mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
+
+        AndroidFuture<UserCreationResult> future = mMgr.createGuest("dudeGuest");
+
+        assertThat(future).isNotNull();
+        UserCreationResult result = getResult(future);
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
+        assertThat(result.isSuccess()).isFalse();
+        assertThat(result.getErrorMessage()).isNull();
+        assertThat(result.getUser()).isNull();
+    }
+
+    @Test
+    public void testGetUserIdentificationAssociation_nullTypes() throws Exception {
+        assertThrows(IllegalArgumentException.class,
+                () -> mMgr.getUserIdentificationAssociation(null));
+    }
+
+    @Test
+    public void testGetUserIdentificationAssociation_emptyTypes() throws Exception {
+        assertThrows(IllegalArgumentException.class,
+                () -> mMgr.getUserIdentificationAssociation(new int[] {}));
+    }
+
+    @Test
+    public void testGetUserIdentificationAssociation_remoteException() throws Exception {
+        int[] types = new int[] {1};
+        when(mService.getUserIdentificationAssociation(types))
+                .thenThrow(new RemoteException("D'OH!"));
+        mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
+
+        assertThat(mMgr.getUserIdentificationAssociation(types)).isNull();
+    }
+
+    @Test
+    public void testGetUserIdentificationAssociation_ok() throws Exception {
+        int[] types = new int[] { 4, 8, 15, 16, 23, 42 };
+        UserIdentificationAssociationResponse expectedResponse =
+                UserIdentificationAssociationResponse.forSuccess(types);
+        when(mService.getUserIdentificationAssociation(types)).thenReturn(expectedResponse);
+
+        UserIdentificationAssociationResponse actualResponse =
+                mMgr.getUserIdentificationAssociation(types);
+
+        assertThat(actualResponse).isSameAs(expectedResponse);
+    }
+
+    @Test
+    public void testSetUserIdentificationAssociation_nullTypes() throws Exception {
+        assertThrows(IllegalArgumentException.class,
+                () -> mMgr.setUserIdentificationAssociation(null, new int[] {42}));
+    }
+
+    @Test
+    public void testSetUserIdentificationAssociation_emptyTypes() throws Exception {
+        assertThrows(IllegalArgumentException.class,
+                () -> mMgr.setUserIdentificationAssociation(new int[0], new int[] {42}));
+    }
+
+    @Test
+    public void testSetUserIdentificationAssociation_nullValues() throws Exception {
+        assertThrows(IllegalArgumentException.class,
+                () -> mMgr.setUserIdentificationAssociation(new int[] {42}, null));
+    }
+
+    @Test
+    public void testSetUserIdentificationAssociation_emptyValues() throws Exception {
+        assertThrows(IllegalArgumentException.class,
+                () -> mMgr.setUserIdentificationAssociation(new int[] {42}, new int[0]));
+    }
+
+    @Test
+    public void testSetUserIdentificationAssociation_sizeMismatch() throws Exception {
+        assertThrows(IllegalArgumentException.class,
+                () -> mMgr.setUserIdentificationAssociation(new int[] {1}, new int[] {2, 3}));
+    }
+
+    @Test
+    public void testSetUserIdentificationAssociation_remoteException() throws Exception {
+        int[] types = new int[] {1};
+        int[] values = new int[] {2};
+        doThrow(new RemoteException("D'OH!")).when(mService)
+                .setUserIdentificationAssociation(anyInt(), same(types), same(values), notNull());
+        mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
+
+        AndroidFuture<UserIdentificationAssociationResponse> future =
+                mMgr.setUserIdentificationAssociation(types, values);
+
+        assertThat(future).isNotNull();
+        UserIdentificationAssociationResponse result = getResult(future);
+        assertThat(result.isSuccess()).isFalse();
+        assertThat(result.getValues()).isNull();
+        assertThat(result.getErrorMessage()).isNull();
+    }
+
+    @Test
+    public void testSetUserIdentificationAssociation_ok() throws Exception {
+        int[] types = new int[] { 1, 2, 3 };
+        int[] values = new int[] { 10, 20, 30 };
+        doAnswer((inv) -> {
+            @SuppressWarnings("unchecked")
+            AndroidFuture<UserIdentificationAssociationResponse> future =
+                    (AndroidFuture<UserIdentificationAssociationResponse>) inv.getArguments()[3];
+            UserIdentificationAssociationResponse response =
+                    UserIdentificationAssociationResponse.forSuccess(values, "D'OH!");
+            future.complete(response);
+            return null;
+        }).when(mService)
+                .setUserIdentificationAssociation(anyInt(), same(types), same(values), notNull());
+        mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
+
+        AndroidFuture<UserIdentificationAssociationResponse> future =
+                mMgr.setUserIdentificationAssociation(types, values);
+
+        assertThat(future).isNotNull();
+        UserIdentificationAssociationResponse result = getResult(future);
+        assertThat(result.isSuccess()).isTrue();
+        assertThat(result.getValues()).asList().containsAllOf(10, 20, 30).inOrder();
+        assertThat(result.getErrorMessage()).isEqualTo("D'OH!");
+    }
+
+    @Test
+    public void testIsUserHalUserAssociation() throws Exception {
+        when(mService.isUserHalUserAssociationSupported()).thenReturn(false).thenReturn(true);
+
+        assertThat(mMgr.isUserHalUserAssociationSupported()).isFalse();
+        assertThat(mMgr.isUserHalUserAssociationSupported()).isTrue();
+    }
+
+    @Test
+    public void testIsUserHalUserAssociation_remoteException() throws Exception {
+        doThrow(new RemoteException("D'OH!")).when(mService).isUserHalUserAssociationSupported();
+        mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
+
+        assertThat(mMgr.isUserHalUserAssociationSupported()).isFalse();
+    }
+
+    private void expectServiceSwitchUserSucceeds(@UserIdInt int userId,
+            @UserSwitchResult.Status int status, @Nullable String errorMessage)
+            throws RemoteException {
+        doAnswer((invocation) -> {
+            @SuppressWarnings("unchecked")
+            AndroidFuture<UserSwitchResult> future = (AndroidFuture<UserSwitchResult>) invocation
+                    .getArguments()[2];
+            future.complete(new UserSwitchResult(status, errorMessage));
+            return null;
+        }).when(mService).switchUser(eq(userId), anyInt(), notNull());
+    }
+
+    private void expectServiceSwitchUserFails(@UserIdInt int userId) throws RemoteException {
+        doThrow(new RemoteException("D'OH!")).when(mService)
+            .switchUser(eq(userId), anyInt(), notNull());
+    }
+
+    private void expectServiceCreateUserSucceeds(@Nullable String name,
+            @NonNull String userType, @UserInfoFlag int flags,
+            @UserCreationResult.Status int status, @UserIdInt int userId) throws RemoteException {
+        doAnswer((invocation) -> {
+            @SuppressWarnings("unchecked")
+            AndroidFuture<UserCreationResult> future =
+                    (AndroidFuture<UserCreationResult>) invocation.getArguments()[4];
+            UserInfo newUser = new UserTestingHelper.UserInfoBuilder(108)
+                    .setName(name).setType(userType).setFlags(flags).build();
+            future.complete(new UserCreationResult(status, newUser, /* errorMessage= */ null));
+            return null;
+        }).when(mService).createUser(eq(name), eq(userType), eq(flags), anyInt(), notNull());
+    }
+
+    private void expectServiceCreateUserFails(@Nullable String name,
+            @NonNull String userType, @UserInfoFlag int flags) throws RemoteException {
+        doThrow(new RemoteException("D'OH!")).when(mService)
+                .createUser(eq(name), eq(userType), eq(flags), anyInt(), notNull());
+    }
+
+    private void setExistingUsers(int... userIds) {
+        mockUmGetUsers(mUserManager, userIds);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/user/CarUserNoticeServiceTest.java b/tests/carservice_unit_test/src/com/android/car/user/CarUserNoticeServiceTest.java
new file mode 100644
index 0000000..f50ad32
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/user/CarUserNoticeServiceTest.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.user;
+
+import static android.car.test.mocks.AndroidMockitoHelper.mockContextGetService;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.AppOpsManager;
+import android.car.AbstractExtendedMockitoCarServiceTestCase;
+import android.car.hardware.power.CarPowerManager;
+import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
+import android.car.settings.CarSettings;
+import android.car.test.mocks.JavaMockitoHelper;
+import android.car.user.CarUserManager;
+import android.car.user.CarUserManager.UserLifecycleEvent;
+import android.car.user.CarUserManager.UserLifecycleListener;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.car.CarLocalServices;
+import com.android.car.CarPowerManagementService;
+import com.android.car.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+
+import java.util.concurrent.CountDownLatch;
+
+public class CarUserNoticeServiceTest extends AbstractExtendedMockitoCarServiceTestCase {
+
+    private static final long TIMEOUT_MS = 10_000;
+
+    @Mock
+    private Context mMockContext;
+    @Mock
+    private Context mOtherMockContext;
+    @Mock
+    private Resources mMockedResources;
+    @Mock
+    private CarPowerManagementService mMockCarPowerManagementService;
+    @Mock
+    private CarUserService mMockCarUserService;
+    @Mock
+    private PowerManager mMockPowerManager;
+    @Mock
+    private AppOpsManager mMockAppOpsManager;
+    @Mock
+    private PackageManager mMockPackageManager;
+    @Mock
+    private CarPowerManager mCarPowerManager;
+
+    @Captor
+    private ArgumentCaptor<BroadcastReceiver> mDisplayBroadcastReceiver;
+
+    @Captor
+    private ArgumentCaptor<UserLifecycleListener> mUserLifecycleListenerArgumentCaptor;
+
+    @Captor
+    private ArgumentCaptor<CarPowerStateListener> mPowerStateListener;
+
+    private CarUserNoticeService mCarUserNoticeService;
+
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+        session
+            .spyStatic(CarLocalServices.class);
+    }
+
+    /**
+     * Initialize all of the objects with the @Mock annotation.
+     */
+    @Before
+    public void setUpMocks() throws Exception {
+        doReturn(mCarPowerManager).when(() -> CarLocalServices.createCarPowerManager(mMockContext));
+        mockGetCarLocalService(CarPowerManagementService.class, mMockCarPowerManagementService);
+        mockGetCarLocalService(CarUserService.class, mMockCarUserService);
+
+        putSettingsInt(CarSettings.Secure.KEY_ENABLE_INITIAL_NOTICE_SCREEN_TO_USER, 1);
+
+        when(mMockContext.getResources()).thenReturn(mMockedResources);
+        when(mMockContext.getContentResolver())
+                .thenReturn(InstrumentationRegistry.getInstrumentation().getTargetContext()
+                        .getContentResolver());
+        when(mMockedResources.getString(anyInt())).thenReturn("com.foo/.Blah");
+
+        mockContextGetService(mMockContext, PowerManager.class, mMockPowerManager);
+        mockContextGetService(mMockContext, AppOpsManager.class, mMockAppOpsManager);
+        mockContextGetService(mMockContext, PackageManager.class, mMockPackageManager);
+        when(mMockPackageManager.getPackageUidAsUser(any(), anyInt())).thenReturn(1);
+        mCarUserNoticeService = new CarUserNoticeService(mMockContext, mHandler);
+        mCarUserNoticeService.init();
+        verify(mMockCarUserService).addUserLifecycleListener(
+                mUserLifecycleListenerArgumentCaptor.capture());
+        verify(mMockContext).registerReceiver(mDisplayBroadcastReceiver.capture(),
+                any(IntentFilter.class));
+        verify(mCarPowerManager).setListener(mPowerStateListener.capture());
+    }
+
+    @Test
+    public void featureDisabledTest() {
+        // Feature is disabled when the string is empty
+        when(mMockedResources.getString(R.string.config_userNoticeUiService)).thenReturn("");
+        when(mOtherMockContext.getResources()).thenReturn(mMockedResources);
+
+        CarUserNoticeService otherService = new CarUserNoticeService(mOtherMockContext);
+        otherService.init();
+
+        verify(mOtherMockContext, never()).registerReceiver(any(), any());
+    }
+
+    @Test
+    public void uiHiddenWhenBroadcastOffReceived() throws Exception {
+        setUser();
+        // reset UI
+        setDisplayOff();
+        CountDownLatch latch = mockUnbindService();
+        sendBroadcast(Intent.ACTION_SCREEN_OFF);
+        assertLatchCalled(latch);
+    }
+
+    @Test
+    public void uiShownWhenBroadcastOnReceived() throws Exception {
+        setUser();
+        // reset UI
+        setDisplayOff();
+        CountDownLatch latch = mockUnbindService();
+        sendBroadcast(Intent.ACTION_SCREEN_OFF);
+        assertLatchCalled(latch);
+
+        // send screen on broadcast
+        setDisplayOn();
+        latch = mockBindService();
+        sendBroadcast(Intent.ACTION_SCREEN_ON);
+        assertLatchCalled(latch);
+    }
+
+    @Test
+    public void uiHiddenWhenPowerShutDown() throws Exception {
+        setUser();
+        // reset UI
+        setDisplayOff();
+        CountDownLatch latch = mockUnbindService();
+        sendPowerStateChange(CarPowerManager.CarPowerStateListener.SHUTDOWN_PREPARE);
+        assertLatchCalled(latch);
+    }
+
+    @Test
+    public void uiShownWhenPowerOn() throws Exception {
+        setUser();
+        // reset UI
+        setDisplayOff();
+        CountDownLatch latch = mockUnbindService();
+        sendPowerStateChange(CarPowerManager.CarPowerStateListener.SHUTDOWN_PREPARE);
+        assertLatchCalled(latch);
+
+        // send Power On
+        setDisplayOn();
+        latch = mockBindService();
+        sendPowerStateChange(CarPowerManager.CarPowerStateListener.ON);
+        assertLatchCalled(latch);
+    }
+
+    @Test
+    public void uiNotShownIfKeyDisabled() throws Exception {
+        setUser();
+        // reset UI
+        setDisplayOff();
+        CountDownLatch latch = mockUnbindService();
+        sendBroadcast(Intent.ACTION_SCREEN_OFF);
+        assertLatchCalled(latch);
+
+        // UI not shown if key is disabled
+        setDisplayOn();
+        latch = mockKeySettings(
+                CarSettings.Secure.KEY_ENABLE_INITIAL_NOTICE_SCREEN_TO_USER, 0);
+        sendBroadcast(Intent.ACTION_SCREEN_ON);
+        assertLatchCalled(latch);
+        // invoked only once, when user switched
+        verify(mMockContext, times(1)).bindServiceAsUser(any(), any(), anyInt(), any());
+    }
+
+    private static void assertLatchCalled(CountDownLatch latch) throws Exception {
+        JavaMockitoHelper.await(latch, TIMEOUT_MS);
+    }
+
+    private void switchUser(int userId) throws Exception {
+        // Notify listeners about user switch.
+        mUserLifecycleListenerArgumentCaptor.getValue().onEvent(new UserLifecycleEvent(
+                CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, userId));
+    }
+
+    private CountDownLatch mockBindService() {
+        CountDownLatch latch = new CountDownLatch(1);
+        when(mMockContext.bindServiceAsUser(any(), any(), anyInt(), any()))
+                .thenAnswer(inv -> {
+                    latch.countDown();
+                    return true;
+                });
+        return latch;
+    }
+
+    private CountDownLatch mockUnbindService() {
+        CountDownLatch latch = new CountDownLatch(1);
+        doAnswer(inv -> {
+            latch.countDown();
+            return null;
+        }).when(mMockContext).unbindService(any());
+        return latch;
+    }
+
+    private static CountDownLatch mockKeySettings(String key, int value) {
+        CountDownLatch latch = new CountDownLatch(1);
+        when(Settings.Secure.getIntForUser(any(),
+                eq(key), anyInt(),
+                anyInt()))
+                        .thenAnswer(inv -> {
+                            latch.countDown();
+                            return value;
+                        });
+        return latch;
+    }
+
+    private void setDisplayOn() {
+        when(mMockPowerManager.isInteractive()).thenReturn(true);
+    }
+
+    private void setDisplayOff() {
+        when(mMockPowerManager.isInteractive()).thenReturn(false);
+    }
+
+    private void sendBroadcast(String action) {
+        Intent intent = new Intent();
+        intent.setAction(action);
+        mHandler.post(() -> mDisplayBroadcastReceiver.getValue().onReceive(mMockContext, intent));
+    }
+
+    private void sendPowerStateChange(int state) {
+        mPowerStateListener.getValue().onStateChanged(state);
+    }
+
+    private void setUser() throws Exception {
+        // switch user (required to set user)
+        setDisplayOn();
+        CountDownLatch latch = mockBindService();
+        switchUser(UserHandle.MIN_SECONDARY_USER_ID);
+        assertLatchCalled(latch);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
index c81f887..b339c9a 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
@@ -16,41 +16,115 @@
 
 package com.android.car.user;
 
+import static android.car.test.mocks.AndroidMockitoHelper.getResult;
+import static android.car.test.mocks.AndroidMockitoHelper.mockUmCreateUser;
+import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetUserInfo;
+import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetUsers;
+import static android.car.test.util.UserTestingHelper.UserInfoBuilder;
+import static android.content.pm.UserInfo.FLAG_ADMIN;
+import static android.content.pm.UserInfo.FLAG_EPHEMERAL;
+import static android.content.pm.UserInfo.FLAG_GUEST;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.doReturn;
+import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.IActivityManager;
+import android.car.CarOccupantZoneManager.OccupantTypeEnum;
+import android.car.CarOccupantZoneManager.OccupantZoneInfo;
 import android.car.settings.CarSettings;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.test.mocks.AndroidMockitoHelper;
+import android.car.test.mocks.BlockingAnswer;
+import android.car.test.util.BlockingResultReceiver;
+import android.car.testapi.BlockingUserLifecycleListener;
+import android.car.user.CarUserManager;
+import android.car.user.CarUserManager.UserLifecycleEvent;
+import android.car.user.CarUserManager.UserLifecycleEventType;
+import android.car.user.CarUserManager.UserLifecycleListener;
+import android.car.user.UserCreationResult;
+import android.car.user.UserIdentificationAssociationResponse;
+import android.car.user.UserRemovalResult;
+import android.car.user.UserSwitchResult;
 import android.car.userlib.CarUserManagerHelper;
+import android.car.userlib.HalCallback;
+import android.car.userlib.HalCallback.HalCallbackStatus;
+import android.car.userlib.UserHalHelper;
+import android.car.userlib.UserHelper;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.hardware.automotive.vehicle.V2_0.CreateUserRequest;
+import android.hardware.automotive.vehicle.V2_0.CreateUserResponse;
+import android.hardware.automotive.vehicle.V2_0.CreateUserStatus;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
+import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
+import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
+import android.hardware.automotive.vehicle.V2_0.SwitchUserResponse;
+import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
+import android.hardware.automotive.vehicle.V2_0.UserFlags;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociation;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
+import android.hardware.automotive.vehicle.V2_0.UsersInfo;
 import android.location.LocationManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.provider.Settings;
+import android.sysprop.CarProperties;
+import android.util.Log;
+import android.util.SparseArray;
 
 import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.car.hal.UserHalService;
+import com.android.internal.R;
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.Preconditions;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Captor;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
 
 /**
  * This class contains unit tests for the {@link CarUserService}.
@@ -58,133 +132,193 @@
  * The following mocks are used:
  * <ol>
  * <li> {@link Context} provides system services and resources.
- * <li> {@link CarUserManagerHelper} provides user info and actions.
+ * <li> {@link IActivityManager} provides current user.
+ * <li> {@link UserManager} provides user creation and user info.
+ * <li> {@link Resources} provides user icon.
+ * <li> {@link Drawable} provides bitmap of user icon.
  * <ol/>
  */
-@RunWith(AndroidJUnit4.class)
-public class CarUserServiceTest {
+public final class CarUserServiceTest extends AbstractExtendedMockitoTestCase {
+
+    private static final String TAG = CarUserServiceTest.class.getSimpleName();
+    private static final int NO_USER_INFO_FLAGS = 0;
+
+    private static final int NON_EXISTING_USER = 55; // must not be on mExistingUsers
+
+    private static final long DEFAULT_LIFECYCLE_TIMESTAMP = 1;
+
+    @Mock private Context mMockContext;
+    @Mock private Context mApplicationContext;
+    @Mock private LocationManager mLocationManager;
+    @Mock private UserHalService mUserHal;
+    @Mock private CarUserManagerHelper mMockedCarUserManagerHelper;
+    @Mock private IActivityManager mMockedIActivityManager;
+    @Mock private UserManager mMockedUserManager;
+    @Mock private Resources mMockedResources;
+    @Mock private Drawable mMockedDrawable;
+    @Mock private UserMetrics mUserMetrics;
+    @Mock IResultReceiver mSwitchUserUiReceiver;
+    @Mock PackageManager mPackageManager;
+
+    private final BlockingUserLifecycleListener mUserLifecycleListener =
+            BlockingUserLifecycleListener.forAnyEvent().build();
+
+    @Captor private ArgumentCaptor<UsersInfo> mUsersInfoCaptor;
+
     private CarUserService mCarUserService;
-
-    @Mock
-    private Context mMockContext;
-
-    @Mock
-    private Context mApplicationContext;
-
-    @Mock
-    private LocationManager mLocationManager;
-
-    @Mock
-    private CarUserManagerHelper mCarUserManagerHelper;
-
-    private static final String DEFAULT_ADMIN_NAME = "defaultName";
-
-    @Mock
-    private IActivityManager mMockedIActivityManager;
-
-    @Mock
-    private UserManager mMockedUserManager;
-
     private boolean mUser0TaskExecuted;
+    private FakeCarOccupantZoneService mFakeCarOccupantZoneService;
 
+    private final int mGetUserInfoRequestType = InitialUserInfoRequestType.COLD_BOOT;
+    private final AndroidFuture<UserSwitchResult> mUserSwitchFuture = new AndroidFuture<>();
+    private final AndroidFuture<UserCreationResult> mUserCreationFuture = new AndroidFuture<>();
+    private final AndroidFuture<UserIdentificationAssociationResponse> mUserAssociationRespFuture =
+            new AndroidFuture<>();
+    private final int mAsyncCallTimeoutMs = 100;
+    private final BlockingResultReceiver mReceiver =
+            new BlockingResultReceiver(mAsyncCallTimeoutMs);
+    private final InitialUserInfoResponse mGetUserInfoResponse = new InitialUserInfoResponse();
+    private final SwitchUserResponse mSwitchUserResponse = new SwitchUserResponse();
+
+    private final @NonNull UserInfo mAdminUser = new UserInfoBuilder(100)
+            .setAdmin(true)
+            .build();
+    private final @NonNull UserInfo mGuestUser = new UserInfoBuilder(111)
+            .setGuest(true)
+            .setEphemeral(true)
+            .build();
+    private final @NonNull UserInfo mRegularUser = new UserInfoBuilder(222)
+            .build();
+    private final List<UserInfo> mExistingUsers =
+            Arrays.asList(mAdminUser, mGuestUser, mRegularUser);
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder builder) {
+        builder
+            .spyStatic(ActivityManager.class)
+            // TODO(b/156299496): it cannot spy on UserManager, as it would slow down the tests
+            // considerably (more than 5 minutes total, instead of just a couple seconds). So, it's
+            // mocking UserHelper.isHeadlessSystemUser() (on mockIsHeadlessSystemUser()) instead...
+            .spyStatic(UserHelper.class)
+            .spyStatic(CarProperties.class);
+    }
 
     /**
      * Initialize all of the objects with the @Mock annotation.
      */
     @Before
-    public void setUpMocks() throws Exception {
-        MockitoAnnotations.initMocks(this);
+    public void setUpMocks() {
         doReturn(mApplicationContext).when(mMockContext).getApplicationContext();
         doReturn(mLocationManager).when(mMockContext).getSystemService(Context.LOCATION_SERVICE);
         doReturn(InstrumentationRegistry.getTargetContext().getContentResolver())
                 .when(mMockContext).getContentResolver();
-        doReturn(mMockedUserManager).when(mMockContext).getSystemService(Context.USER_SERVICE);
         doReturn(false).when(mMockedUserManager).isUserUnlockingOrUnlocked(anyInt());
-        mCarUserService = new CarUserService(mMockContext, mCarUserManagerHelper,
-                mMockedIActivityManager, 3);
+        doReturn(mMockedResources).when(mMockContext).getResources();
+        doReturn(mMockedDrawable).when(mMockedResources)
+                .getDrawable(eq(R.drawable.ic_account_circle), eq(null));
+        doReturn(mMockedDrawable).when(mMockedDrawable).mutate();
+        doReturn(1).when(mMockedDrawable).getIntrinsicWidth();
+        doReturn(1).when(mMockedDrawable).getIntrinsicHeight();
+        mockUserHalSupported(true);
+        mockUserHalUserAssociationSupported(true);
+        doReturn(Optional.of(mAsyncCallTimeoutMs)).when(() -> CarProperties.user_hal_timeout());
+        mCarUserService =
+                new CarUserService(
+                        mMockContext,
+                        mUserHal,
+                        mMockedCarUserManagerHelper,
+                        mMockedUserManager,
+                        mMockedIActivityManager,
+                        3, mUserMetrics);
 
-        doReturn(new ArrayList<>()).when(mCarUserManagerHelper).getAllUsers();
-
-        // Restore default value at the beginning of each test.
-        putSettingsInt(CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 0);
+        mFakeCarOccupantZoneService = new FakeCarOccupantZoneService(mCarUserService);
     }
 
-    /**
-     * Test that the {@link CarUserService} registers to receive the locked boot completed
-     * intent.
-     */
     @Test
-    public void testRegistersToReceiveEvents() {
-        ArgumentCaptor<IntentFilter> argument = ArgumentCaptor.forClass(IntentFilter.class);
-        mCarUserService.init();
-        verify(mMockContext).registerReceiver(eq(mCarUserService), argument.capture());
-        IntentFilter intentFilter = argument.getValue();
-        assertThat(intentFilter.countActions()).isEqualTo(1);
-
-        assertThat(intentFilter.getAction(0)).isEqualTo(Intent.ACTION_USER_SWITCHED);
+    public void testAddUserLifecycleListener_checkNullParameter() {
+        assertThrows(NullPointerException.class,
+                () -> mCarUserService.addUserLifecycleListener(null));
     }
 
-    /**
-     * Test that the {@link CarUserService} unregisters its event receivers.
-     */
     @Test
-    public void testUnregistersEventReceivers() {
-        mCarUserService.release();
-        verify(mMockContext).unregisterReceiver(mCarUserService);
+    public void testRemoveUserLifecycleListener_checkNullParameter() {
+        assertThrows(NullPointerException.class,
+                () -> mCarUserService.removeUserLifecycleListener(null));
     }
 
-    /**
-     * Test that the {@link CarUserService} does set the disable modify account permission for
-     * user 0 upon user 0 unlock when user 0 is headless.
-     */
     @Test
-    public void testDisableModifyAccountsForHeadlessSystemUserOnFirstRun() {
-        // Mock system user.
-        UserInfo systemUser = new UserInfo();
-        systemUser.id = UserHandle.USER_SYSTEM;
-        doReturn(systemUser).when(mCarUserManagerHelper).getSystemUserInfo();
-        doReturn(true).when(mCarUserManagerHelper).isHeadlessSystemUser();
+    public void testOnUserLifecycleEvent_legacyUserSwitch_halCalled() throws Exception {
+        // Arrange
+        mockExistingUsers(mExistingUsers);
 
-        mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true);
+        // Act
+        sendUserSwitchingEvent(mAdminUser.id, mRegularUser.id);
 
-        verify(mCarUserManagerHelper)
-                .setUserRestriction(systemUser, UserManager.DISALLOW_MODIFY_ACCOUNTS, true);
+        // Verify
+        verify(mUserHal).legacyUserSwitch(any());
     }
 
-    /**
-     * Test that the {@link CarUserService} does not set the disable modify account permission for
-     * user 0 upon user 0 unlock when user 0 is not headless.
-     */
     @Test
-    public void testDisableModifyAccountsForRegularSystemUserOnFirstRun() {
-        // Mock system user.
-        UserInfo systemUser = new UserInfo();
-        systemUser.id = UserHandle.USER_SYSTEM;
-        doReturn(systemUser).when(mCarUserManagerHelper).getSystemUserInfo();
-        doReturn(false).when(mCarUserManagerHelper).isHeadlessSystemUser();
+    public void testOnUserLifecycleEvent_legacyUserSwitch_halnotSupported() throws Exception {
+        // Arrange
+        mockExistingUsers(mExistingUsers);
+        mockUserHalSupported(false);
 
-        mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true);
+        // Act
+        sendUserSwitchingEvent(mAdminUser.id, mRegularUser.id);
 
-        verify(mCarUserManagerHelper, never())
-                .setUserRestriction(systemUser, UserManager.DISALLOW_MODIFY_ACCOUNTS, true);
+        // Verify
+        verify(mUserHal, never()).legacyUserSwitch(any());
     }
 
-    /**
-     * Test that the {@link CarUserService} does not set restrictions on user 0 if they have already
-     * been set.
-     */
     @Test
-    public void testDoesNotSetSystemUserRestrictions_IfRestrictionsAlreadySet() {
-        // Mock system user.
-        UserInfo systemUser = new UserInfo();
-        systemUser.id = UserHandle.USER_SYSTEM;
-        doReturn(systemUser).when(mCarUserManagerHelper).getSystemUserInfo();
+    public void testOnUserLifecycleEvent_notifyListener() throws Exception {
+        // Arrange
+        mCarUserService.addUserLifecycleListener(mUserLifecycleListener);
+        mockExistingUsers(mExistingUsers);
 
-        putSettingsInt(CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
-        mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true);
+        // Act
+        sendUserSwitchingEvent(mAdminUser.id, mRegularUser.id);
 
-        verify(mCarUserManagerHelper, never())
-                .setUserRestriction(systemUser, UserManager.DISALLOW_MODIFY_ACCOUNTS, true);
+        // Verify
+        verifyListenerOnEventInvoked(mRegularUser.id,
+                CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING);
+    }
+
+    @Test
+    public void testOnUserLifecycleEvent_ensureAllListenersAreNotified() throws Exception {
+        // Arrange: add two listeners, one to fail on onEvent
+        // Adding the failure listener first.
+        UserLifecycleListener failureListener = mock(UserLifecycleListener.class);
+        doThrow(new RuntimeException("Failed onEvent invocation")).when(
+                failureListener).onEvent(any(UserLifecycleEvent.class));
+        mCarUserService.addUserLifecycleListener(failureListener);
+        mockExistingUsers(mExistingUsers);
+
+        // Adding the non-failure listener later.
+        mCarUserService.addUserLifecycleListener(mUserLifecycleListener);
+
+        // Act
+        sendUserSwitchingEvent(mAdminUser.id, mRegularUser.id);
+
+        // Verify
+        verifyListenerOnEventInvoked(mRegularUser.id,
+                CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING);
+    }
+
+    private void verifyListenerOnEventInvoked(int expectedNewUserId, int expectedEventType)
+            throws Exception {
+        UserLifecycleEvent actualEvent = mUserLifecycleListener.waitForAnyEvent();
+        assertThat(actualEvent.getEventType()).isEqualTo(expectedEventType);
+        assertThat(actualEvent.getUserId()).isEqualTo(expectedNewUserId);
+    }
+
+    private void verifyLastActiveUserSet(@UserIdInt int userId) {
+        verify(mMockedCarUserManagerHelper).setLastActiveUser(userId);
+    }
+
+    private void verifyLastActiveUserNotSet() {
+        verify(mMockedCarUserManagerHelper, never()).setLastActiveUser(anyInt());
     }
 
     /**
@@ -193,41 +327,23 @@
      */
     @Test
     public void testDisableLocationForHeadlessSystemUserOnFirstRun() {
-        doReturn(true).when(mCarUserManagerHelper).isHeadlessSystemUser();
-        mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true);
-
+        sendUserUnlockedEvent(UserHandle.USER_SYSTEM);
         verify(mLocationManager).setLocationEnabledForUser(
                 /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
     }
 
     /**
-     * Test that the {@link CarUserService} does not disable the location service for regular user 0
-     * upon first run.
+     * Test that the {@link CarUserService} updates last active user on user switch in non-headless
+     * system user mode.
      */
     @Test
-    public void testDisableLocationForRegularSystemUserOnFirstRun() {
-        doReturn(false).when(mCarUserManagerHelper).isHeadlessSystemUser();
-        mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true);
+    public void testLastActiveUserUpdatedOnUserSwitch_nonHeadlessSystemUser() throws Exception {
+        mockIsHeadlessSystemUser(mRegularUser.id, false);
+        mockExistingUsers(mExistingUsers);
 
-        verify(mLocationManager, never()).setLocationEnabledForUser(
-                /* enabled= */ false, UserHandle.of(UserHandle.USER_SYSTEM));
-    }
+        sendUserSwitchingEvent(mAdminUser.id, mRegularUser.id);
 
-    /**
-     * Test that the {@link CarUserService} updates last active user on user switch intent.
-     */
-    @Test
-    public void testLastActiveUserUpdatedOnUserSwitch() {
-        int lastActiveUserId = 11;
-
-        Intent intent = new Intent(Intent.ACTION_USER_SWITCHED);
-        intent.putExtra(Intent.EXTRA_USER_HANDLE, lastActiveUserId);
-
-        doReturn(true).when(mCarUserManagerHelper).isPersistentUser(lastActiveUserId);
-
-        mCarUserService.onReceive(mMockContext, intent);
-
-        verify(mCarUserManagerHelper).setLastActiveUser(lastActiveUserId);
+        verifyLastActiveUserSet(mRegularUser.id);
     }
 
     /**
@@ -235,25 +351,14 @@
      */
     @Test
     public void testInitializeGuestRestrictions_IfNotAlreadySet() {
-        mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true);
-        verify(mCarUserManagerHelper).initDefaultGuestRestrictions();
+        sendUserUnlockedEvent(UserHandle.USER_SYSTEM);
         assertThat(getSettingsInt(CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET)).isEqualTo(1);
     }
 
-    /**
-     * Test that the {@link CarUserService} does not set restrictions after they have been set once.
-     */
-    @Test
-    public void test_DoesNotInitializeGuestRestrictions_IfAlreadySet() {
-        putSettingsInt(CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
-        mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true);
-        verify(mCarUserManagerHelper, never()).initDefaultGuestRestrictions();
-    }
-
     @Test
     public void testRunOnUser0UnlockImmediate() {
         mUser0TaskExecuted = false;
-        mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true);
+        sendUserUnlockedEvent(UserHandle.USER_SYSTEM);
         mCarUserService.runOnUser0Unlock(() -> {
             mUser0TaskExecuted = true;
         });
@@ -267,7 +372,7 @@
             mUser0TaskExecuted = true;
         });
         assertFalse(mUser0TaskExecuted);
-        mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true);
+        sendUserUnlockedEvent(UserHandle.USER_SYSTEM);
         assertTrue(mUser0TaskExecuted);
     }
 
@@ -275,47 +380,52 @@
      * Test is lengthy as it is testing LRU logic.
      */
     @Test
-    public void testBackgroundUserList() {
-        final int user1 = 101;
-        final int user2 = 102;
-        final int user3 = 103;
-        final int user4Guest = 104;
-        final int user5 = 105;
-        doReturn(true).when(mCarUserManagerHelper).isPersistentUser(user1);
-        doReturn(true).when(mCarUserManagerHelper).isPersistentUser(user2);
-        doReturn(true).when(mCarUserManagerHelper).isPersistentUser(user3);
-        doReturn(true).when(mCarUserManagerHelper).isPersistentUser(user5);
+    public void testBackgroundUserList() throws RemoteException {
+        int user1 = 101;
+        int user2 = 102;
+        int user3 = 103;
+        int user4Guest = 104;
+        int user5 = 105;
 
-        doReturn(user1).when(mCarUserManagerHelper).getCurrentForegroundUserId();
-        mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true);
+        UserInfo user1Info = new UserInfo(user1, "user1", NO_USER_INFO_FLAGS);
+        UserInfo user2Info = new UserInfo(user2, "user2", NO_USER_INFO_FLAGS);
+        UserInfo user3Info = new UserInfo(user3, "user3", NO_USER_INFO_FLAGS);
+        UserInfo user4GuestInfo = new UserInfo(
+                user4Guest, "user4Guest", FLAG_EPHEMERAL | FLAG_GUEST);
+        UserInfo user5Info = new UserInfo(user5, "user5", NO_USER_INFO_FLAGS);
+
+        doReturn(user1Info).when(mMockedUserManager).getUserInfo(user1);
+        doReturn(user2Info).when(mMockedUserManager).getUserInfo(user2);
+        doReturn(user3Info).when(mMockedUserManager).getUserInfo(user3);
+        doReturn(user4GuestInfo).when(mMockedUserManager).getUserInfo(user4Guest);
+        doReturn(user5Info).when(mMockedUserManager).getUserInfo(user5);
+
+        mockGetCurrentUser(user1);
+        sendUserUnlockedEvent(UserHandle.USER_SYSTEM);
         // user 0 should never go to that list.
         assertTrue(mCarUserService.getBackgroundUsersToRestart().isEmpty());
 
-        mCarUserService.setUserLockStatus(user1, true);
+        sendUserUnlockedEvent(user1);
         assertEquals(new Integer[]{user1},
                 mCarUserService.getBackgroundUsersToRestart().toArray());
 
         // user 2 background, ignore in restart list
-        mCarUserService.setUserLockStatus(user2, true);
-        mCarUserService.setUserLockStatus(user1, false);
+        sendUserUnlockedEvent(user2);
         assertEquals(new Integer[]{user1},
                 mCarUserService.getBackgroundUsersToRestart().toArray());
 
-        doReturn(user3).when(mCarUserManagerHelper).getCurrentForegroundUserId();
-        mCarUserService.setUserLockStatus(user3, true);
-        mCarUserService.setUserLockStatus(user2, false);
+        mockGetCurrentUser(user3);
+        sendUserUnlockedEvent(user3);
         assertEquals(new Integer[]{user3, user1},
                 mCarUserService.getBackgroundUsersToRestart().toArray());
 
-        doReturn(user4Guest).when(mCarUserManagerHelper).getCurrentForegroundUserId();
-        mCarUserService.setUserLockStatus(user4Guest, true);
-        mCarUserService.setUserLockStatus(user3, false);
+        mockGetCurrentUser(user4Guest);
+        sendUserUnlockedEvent(user4Guest);
         assertEquals(new Integer[]{user3, user1},
                 mCarUserService.getBackgroundUsersToRestart().toArray());
 
-        doReturn(user5).when(mCarUserManagerHelper).getCurrentForegroundUserId();
-        mCarUserService.setUserLockStatus(user5, true);
-        mCarUserService.setUserLockStatus(user4Guest, false);
+        mockGetCurrentUser(user5);
+        sendUserUnlockedEvent(user5);
         assertEquals(new Integer[]{user5, user3},
                 mCarUserService.getBackgroundUsersToRestart().toArray());
     }
@@ -325,22 +435,26 @@
      */
     @Test
     public void testBackgroundUsersStartStopKeepBackgroundUserList() throws Exception {
-        final int user1 = 101;
-        final int user2 = 102;
-        final int user3 = 103;
+        int user1 = 101;
+        int user2 = 102;
+        int user3 = 103;
 
-        doReturn(true).when(mCarUserManagerHelper).isPersistentUser(user1);
-        doReturn(true).when(mCarUserManagerHelper).isPersistentUser(user2);
-        doReturn(true).when(mCarUserManagerHelper).isPersistentUser(user3);
-        doReturn(user1).when(mCarUserManagerHelper).getCurrentForegroundUserId();
-        mCarUserService.setUserLockStatus(UserHandle.USER_SYSTEM, true);
-        mCarUserService.setUserLockStatus(user1, true);
-        doReturn(user2).when(mCarUserManagerHelper).getCurrentForegroundUserId();
-        mCarUserService.setUserLockStatus(user2, true);
-        mCarUserService.setUserLockStatus(user1, false);
-        doReturn(user3).when(mCarUserManagerHelper).getCurrentForegroundUserId();
-        mCarUserService.setUserLockStatus(user3, true);
-        mCarUserService.setUserLockStatus(user2, false);
+        UserInfo user1Info = new UserInfo(user1, "user1", NO_USER_INFO_FLAGS);
+        UserInfo user2Info = new UserInfo(user2, "user2", NO_USER_INFO_FLAGS);
+        UserInfo user3Info = new UserInfo(user3, "user3", NO_USER_INFO_FLAGS);
+
+        doReturn(user1Info).when(mMockedUserManager).getUserInfo(user1);
+        doReturn(user2Info).when(mMockedUserManager).getUserInfo(user2);
+        doReturn(user3Info).when(mMockedUserManager).getUserInfo(user3);
+
+        mockGetCurrentUser(user1);
+        sendUserUnlockedEvent(UserHandle.USER_SYSTEM);
+        sendUserUnlockedEvent(user1);
+        mockGetCurrentUser(user2);
+        sendUserUnlockedEvent(user2);
+        sendUserUnlockedEvent(user1);
+        mockGetCurrentUser(user3);
+        sendUserUnlockedEvent(user3);
 
         assertEquals(new Integer[]{user3, user2},
                 mCarUserService.getBackgroundUsersToRestart().toArray());
@@ -350,7 +464,7 @@
                 null, null, null);
         assertEquals(new Integer[]{user2},
                 mCarUserService.startAllBackgroundUsers().toArray());
-        mCarUserService.setUserLockStatus(user2, true);
+        sendUserUnlockedEvent(user2);
         assertEquals(new Integer[]{user3, user2},
                 mCarUserService.getBackgroundUsersToRestart().toArray());
 
@@ -361,7 +475,6 @@
         assertTrue(mCarUserService.stopBackgroundUser(user2));
         assertEquals(new Integer[]{user3, user2},
                 mCarUserService.getBackgroundUsersToRestart().toArray());
-        mCarUserService.setUserLockStatus(user2, false);
         assertEquals(new Integer[]{user3, user2},
                 mCarUserService.getBackgroundUsersToRestart().toArray());
     }
@@ -372,28 +485,1821 @@
     }
 
     @Test
-    public void testStopBackgroundUserForFgUser() {
-        final int user1 = 101;
-        doReturn(user1).when(mCarUserManagerHelper).getCurrentForegroundUserId();
+    public void testStopBackgroundUserForFgUser() throws RemoteException {
+        int user1 = 101;
+        mockGetCurrentUser(user1);
         assertFalse(mCarUserService.stopBackgroundUser(UserHandle.USER_SYSTEM));
     }
 
-    private void putSettingsInt(String key, int value) {
-        Settings.Global.putInt(InstrumentationRegistry.getTargetContext().getContentResolver(),
-                key, value);
+    @Test
+    public void testCreateAdminDriver_IfCurrentUserIsAdminUser() throws Exception {
+        when(mMockedUserManager.isSystemUser()).thenReturn(true);
+        mockUmCreateUser(mMockedUserManager, "testUser", UserManager.USER_TYPE_FULL_SECONDARY,
+                UserInfo.FLAG_ADMIN, 10);
+        mockHalCreateUser(HalCallback.STATUS_OK, CreateUserStatus.SUCCESS);
+
+        AndroidFuture<UserCreationResult> future = mCarUserService.createDriver("testUser", true);
+
+        assertThat(getResult(future).getUser().name).isEqualTo("testUser");
+        assertThat(getResult(future).getUser().id).isEqualTo(10);
     }
 
-    private int getSettingsInt(String key) {
-        return Settings.Global.getInt(
-                InstrumentationRegistry.getTargetContext().getContentResolver(),
-                key, /* default= */ 0);
+    @Test
+    public void testCreateAdminDriver_IfCurrentUserIsNotSystemUser() throws Exception {
+        when(mMockedUserManager.isSystemUser()).thenReturn(false);
+        AndroidFuture<UserCreationResult> future = mCarUserService.createDriver("testUser", true);
+        assertThat(getResult(future).getStatus())
+                .isEqualTo(UserCreationResult.STATUS_INVALID_REQUEST);
     }
 
-    private UserInfo mockAdmin(int adminId) {
-        UserInfo admin = new UserInfo(adminId, DEFAULT_ADMIN_NAME,
+    @Test
+    public void testCreateNonAdminDriver() throws Exception {
+        mockUmCreateUser(mMockedUserManager, "testUser", UserManager.USER_TYPE_FULL_SECONDARY,
+                NO_USER_INFO_FLAGS, 10);
+        mockHalCreateUser(HalCallback.STATUS_OK, CreateUserStatus.SUCCESS);
+
+        AndroidFuture<UserCreationResult> future = mCarUserService.createDriver("testUser", false);
+
+        UserInfo userInfo = getResult(future).getUser();
+        assertThat(userInfo.name).isEqualTo("testUser");
+        assertThat(userInfo.id).isEqualTo(10);
+    }
+
+    @Test
+    public void testCreatePassenger() {
+        int driverId = 90;
+        int passengerId = 99;
+        String userName = "testUser";
+        UserInfo userInfo = new UserInfo(passengerId, userName, NO_USER_INFO_FLAGS);
+        doReturn(userInfo).when(mMockedUserManager).createProfileForUser(eq(userName),
+                eq(UserManager.USER_TYPE_PROFILE_MANAGED), eq(0), eq(driverId));
+        UserInfo driverInfo = new UserInfo(driverId, "driver", NO_USER_INFO_FLAGS);
+        doReturn(driverInfo).when(mMockedUserManager).getUserInfo(driverId);
+        assertEquals(userInfo, mCarUserService.createPassenger(userName, driverId));
+    }
+
+    @Test
+    public void testCreatePassenger_IfMaximumProfileAlreadyCreated() {
+        int driverId = 90;
+        String userName = "testUser";
+        doReturn(null).when(mMockedUserManager).createProfileForUser(eq(userName),
+                eq(UserManager.USER_TYPE_PROFILE_MANAGED), anyInt(), anyInt());
+        UserInfo driverInfo = new UserInfo(driverId, "driver", NO_USER_INFO_FLAGS);
+        doReturn(driverInfo).when(mMockedUserManager).getUserInfo(driverId);
+        assertEquals(null, mCarUserService.createPassenger(userName, driverId));
+    }
+
+    @Test
+    public void testCreatePassenger_IfDriverIsGuest() {
+        int driverId = 90;
+        String userName = "testUser";
+        UserInfo driverInfo = new UserInfo(driverId, "driver", UserInfo.FLAG_GUEST);
+        doReturn(driverInfo).when(mMockedUserManager).getUserInfo(driverId);
+        assertEquals(null, mCarUserService.createPassenger(userName, driverId));
+    }
+
+    @Test
+    public void testSwitchDriver() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        int requestId = 42;
+        mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
+        mSwitchUserResponse.requestId = requestId;
+        mockHalSwitch(mAdminUser.id, mRegularUser, mSwitchUserResponse);
+        mockAmSwitchUser(mRegularUser, true);
+        when(mMockedUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH))
+                .thenReturn(false);
+        mCarUserService.switchDriver(mRegularUser.id, mUserSwitchFuture);
+        assertThat(getUserSwitchResult().getStatus())
+                .isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+    }
+
+    @Test
+    public void testSwitchDriver_IfUserSwitchIsNotAllowed() throws Exception {
+        when(mMockedUserManager.getUserSwitchability())
+                .thenReturn(UserManager.SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED);
+        mCarUserService.switchDriver(mRegularUser.id, mUserSwitchFuture);
+        assertThat(getUserSwitchResult().getStatus())
+                .isEqualTo(UserSwitchResult.STATUS_INVALID_REQUEST);
+    }
+
+    @Test
+    public void testSwitchDriver_IfSwitchedToCurrentUser() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        when(mMockedUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH))
+                .thenReturn(false);
+        mCarUserService.switchDriver(mAdminUser.id, mUserSwitchFuture);
+        assertThat(getUserSwitchResult().getStatus())
+                .isEqualTo(UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND);
+    }
+
+    @Test
+    public void testStartPassenger() throws RemoteException {
+        int passenger1Id = 91;
+        int passenger2Id = 92;
+        int passenger3Id = 93;
+        int zone1Id = 1;
+        int zone2Id = 2;
+        doReturn(true).when(mMockedIActivityManager)
+                .startUserInBackgroundWithListener(anyInt(), eq(null));
+        assertTrue(mCarUserService.startPassenger(passenger1Id, zone1Id));
+        assertTrue(mCarUserService.startPassenger(passenger2Id, zone2Id));
+        assertFalse(mCarUserService.startPassenger(passenger3Id, zone2Id));
+    }
+
+    @Test
+    public void testStopPassenger() throws RemoteException {
+        int user1Id = 11;
+        int passenger1Id = 91;
+        int passenger2Id = 92;
+        int zoneId = 1;
+        UserInfo user1Info = new UserInfo(user1Id, "user1", NO_USER_INFO_FLAGS);
+        UserInfo passenger1Info =
+                new UserInfo(passenger1Id, "passenger1", UserInfo.FLAG_MANAGED_PROFILE);
+        associateParentChild(user1Info, passenger1Info);
+        doReturn(passenger1Info).when(mMockedUserManager).getUserInfo(passenger1Id);
+        doReturn(null).when(mMockedUserManager).getUserInfo(passenger2Id);
+        mockGetCurrentUser(user1Id);
+        doReturn(true).when(mMockedIActivityManager)
+                .startUserInBackgroundWithListener(anyInt(), eq(null));
+        assertTrue(mCarUserService.startPassenger(passenger1Id, zoneId));
+        assertTrue(mCarUserService.stopPassenger(passenger1Id));
+        // Test of stopping an already stopped passenger.
+        assertTrue(mCarUserService.stopPassenger(passenger1Id));
+        // Test of stopping a non-existing passenger.
+        assertFalse(mCarUserService.stopPassenger(passenger2Id));
+    }
+
+    private static void associateParentChild(UserInfo parent, UserInfo child) {
+        parent.profileGroupId = parent.id;
+        child.profileGroupId = parent.id;
+    }
+
+    private static List<UserInfo> prepareUserList() {
+        List<UserInfo> users = new ArrayList<>(Arrays.asList(
+                new UserInfo(10, "test10", UserInfo.FLAG_PRIMARY | UserInfo.FLAG_ADMIN),
+                new UserInfo(11, "test11", NO_USER_INFO_FLAGS),
+                new UserInfo(12, "test12", UserInfo.FLAG_MANAGED_PROFILE),
+                new UserInfo(13, "test13", NO_USER_INFO_FLAGS),
+                new UserInfo(14, "test14", UserInfo.FLAG_GUEST),
+                new UserInfo(15, "test15", UserInfo.FLAG_EPHEMERAL),
+                new UserInfo(16, "test16", UserInfo.FLAG_DISABLED),
+                new UserInfo(17, "test17", UserInfo.FLAG_MANAGED_PROFILE),
+                new UserInfo(18, "test18", UserInfo.FLAG_MANAGED_PROFILE),
+                new UserInfo(19, "test19", NO_USER_INFO_FLAGS)
+        ));
+        // Parent: test10, child: test12
+        associateParentChild(users.get(0), users.get(2));
+        // Parent: test13, child: test17
+        associateParentChild(users.get(3), users.get(7));
+        // Parent: test13, child: test18
+        associateParentChild(users.get(3), users.get(8));
+        return users;
+    }
+
+    @Test
+    public void testGetAllPossibleDrivers() {
+        Set<Integer> expected = new HashSet<Integer>(Arrays.asList(10, 11, 13, 14));
+        when(mMockedUserManager.getUsers(true)).thenReturn(prepareUserList());
+        mockIsHeadlessSystemUser(19, true);
+        for (UserInfo user : mCarUserService.getAllDrivers()) {
+            assertThat(expected).contains(user.id);
+            expected.remove(user.id);
+        }
+        assertThat(expected).isEmpty();
+    }
+
+    @Test
+    public void testGetAllPassengers() {
+        SparseArray<HashSet<Integer>> testCases = new SparseArray<HashSet<Integer>>() {
+            {
+                put(0, new HashSet<Integer>());
+                put(10, new HashSet<Integer>(Arrays.asList(12)));
+                put(11, new HashSet<Integer>());
+                put(13, new HashSet<Integer>(Arrays.asList(17)));
+            }
+        };
+        mockIsHeadlessSystemUser(18, true);
+        for (int i = 0; i < testCases.size(); i++) {
+            when(mMockedUserManager.getUsers(true)).thenReturn(prepareUserList());
+            List<UserInfo> passengers = mCarUserService.getPassengers(testCases.keyAt(i));
+            HashSet<Integer> expected = testCases.valueAt(i);
+            for (UserInfo user : passengers) {
+                assertThat(expected).contains(user.id);
+                expected.remove(user.id);
+            }
+            assertThat(expected).isEmpty();
+        }
+    }
+
+    @Test
+    public void testRemoveUser_currentUserCannotBeRemoved() throws Exception {
+        mockCurrentUser(mAdminUser);
+
+        UserRemovalResult result = mCarUserService.removeUser(mAdminUser.id);
+
+        assertThat(result.getStatus())
+                .isEqualTo(UserRemovalResult.STATUS_TARGET_USER_IS_CURRENT_USER);
+    }
+
+    @Test
+    public void testRemoveUser_userNotExist() throws Exception {
+        UserRemovalResult result = mCarUserService.removeUser(15);
+
+        assertThat(result.getStatus())
+                .isEqualTo(UserRemovalResult.STATUS_USER_DOES_NOT_EXIST);
+    }
+
+    @Test
+    public void testRemoveUser_lastAdminUser() throws Exception {
+        mockCurrentUser(mRegularUser);
+        mockExistingUsers(mExistingUsers);
+
+        UserRemovalResult result = mCarUserService.removeUser(mAdminUser.id);
+
+        assertThat(result.getStatus())
+                .isEqualTo(UserRemovalResult.STATUS_TARGET_USER_IS_LAST_ADMIN_USER);
+    }
+
+    @Test
+    public void testRemoveUser_notLastAdminUser_success() throws Exception {
+        List<UserInfo> existingUsers =
+                new ArrayList<UserInfo>(Arrays.asList(mAdminUser, mGuestUser, mRegularUser));
+        UserInfo currentUser = mRegularUser;
+        // Give admin rights to current user.
+        currentUser.flags = currentUser.flags | FLAG_ADMIN;
+        mockExistingUsersAndCurrentUser(existingUsers, currentUser);
+
+        UserInfo removeUser = mAdminUser;
+        doAnswer((invocation) -> {
+            existingUsers.remove(removeUser);
+            return true;
+        }).when(mMockedUserManager).removeUser(eq(removeUser.id));
+
+        UserRemovalResult result = mCarUserService.removeUser(removeUser.id);
+
+        assertThat(result.getStatus()).isEqualTo(UserRemovalResult.STATUS_SUCCESSFUL);
+        assertHalRemove(currentUser, removeUser, existingUsers);
+    }
+
+    @Test
+    public void testRemoveUser_success() throws Exception {
+        List<UserInfo> existingUsers =
+                new ArrayList<UserInfo>(Arrays.asList(mAdminUser, mGuestUser, mRegularUser));
+        UserInfo currentUser = mAdminUser;
+        mockExistingUsersAndCurrentUser(existingUsers, currentUser);
+        UserInfo removeUser = mRegularUser;
+        doAnswer((invocation) -> {
+            existingUsers.remove(removeUser);
+            return true;
+        }).when(mMockedUserManager).removeUser(eq(removeUser.id));
+
+        UserRemovalResult result = mCarUserService.removeUser(removeUser.id);
+
+        assertThat(result.getStatus()).isEqualTo(UserRemovalResult.STATUS_SUCCESSFUL);
+        assertHalRemove(currentUser, removeUser, existingUsers);
+    }
+
+    @Test
+    public void testRemoveUser_halNotSupported() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        int removeUserId = mRegularUser.id;
+        mockUserHalSupported(false);
+        when(mMockedUserManager.removeUser(removeUserId)).thenReturn(true);
+
+        UserRemovalResult result = mCarUserService.removeUser(removeUserId);
+
+        assertThat(result.getStatus()).isEqualTo(UserRemovalResult.STATUS_SUCCESSFUL);
+        verify(mUserHal, never()).removeUser(any());
+    }
+
+    @Test
+    public void testRemoveUser_androidFailure() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        int targetUserId = mRegularUser.id;
+        when(mMockedUserManager.removeUser(targetUserId)).thenReturn(false);
+
+        UserRemovalResult result = mCarUserService.removeUser(targetUserId);
+
+        assertThat(result.getStatus()).isEqualTo(UserRemovalResult.STATUS_ANDROID_FAILURE);
+    }
+
+    @Test
+    public void testSwitchUser_nullReceiver() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+
+        assertThrows(NullPointerException.class, () -> mCarUserService
+                .switchUser(mAdminUser.id, mAsyncCallTimeoutMs, null));
+    }
+
+    @Test
+    public void testSwitchUser_nonExistingTarget() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> mCarUserService
+                .switchUser(NON_EXISTING_USER, mAsyncCallTimeoutMs, mUserSwitchFuture));
+    }
+
+    @Test
+    public void testSwitchUser_targetSameAsCurrentUser() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+
+        mCarUserService.switchUser(mAdminUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        assertThat(getUserSwitchResult().getStatus())
+                .isEqualTo(UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND);
+    }
+
+    @Test
+    public void testSwitchUser_halNotSupported_success() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        mockUserHalSupported(false);
+        mockAmSwitchUser(mRegularUser, true);
+
+        mCarUserService.switchUser(mRegularUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        assertThat(getUserSwitchResult().getStatus())
+                .isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+        verify(mUserHal, never()).switchUser(any(), anyInt(), any());
+
+        // update current user due to successful user switch
+        mockCurrentUser(mRegularUser);
+        sendUserUnlockedEvent(mRegularUser.id);
+        assertNoPostSwitch();
+    }
+
+    @Test
+    public void testSwitchUser_halNotSupported_failure() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        mockUserHalSupported(false);
+
+        mCarUserService.switchUser(mRegularUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        assertThat(getUserSwitchResult().getStatus())
+                .isEqualTo(UserSwitchResult.STATUS_ANDROID_FAILURE);
+        verify(mUserHal, never()).switchUser(any(), anyInt(), any());
+    }
+
+    @Test
+    public void testSwitchUser_HalSuccessAndroidSuccess() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        int requestId = 42;
+        mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
+        mSwitchUserResponse.requestId = requestId;
+        mockHalSwitch(mAdminUser.id, mGuestUser, mSwitchUserResponse);
+        mockAmSwitchUser(mGuestUser, true);
+
+        mCarUserService.switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        assertThat(getUserSwitchResult().getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+
+        // update current user due to successful user switch
+        mockCurrentUser(mGuestUser);
+        sendUserUnlockedEvent(mGuestUser.id);
+        assertPostSwitch(requestId, mGuestUser.id, mGuestUser.id);
+    }
+
+    @Test
+    public void testSwitchUser_HalSuccessAndroidFailure() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        int requestId = 42;
+        mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
+        mSwitchUserResponse.requestId = requestId;
+        mockHalSwitch(mAdminUser.id, mGuestUser, mSwitchUserResponse);
+        mockAmSwitchUser(mGuestUser, false);
+
+        mCarUserService.switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        assertThat(getUserSwitchResult().getStatus())
+                .isEqualTo(UserSwitchResult.STATUS_ANDROID_FAILURE);
+        assertPostSwitch(requestId, mAdminUser.id, mGuestUser.id);
+    }
+
+    @Test
+    public void testSwitchUser_HalFailure() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        mSwitchUserResponse.status = SwitchUserStatus.FAILURE;
+        mSwitchUserResponse.errorMessage = "Error Message";
+        mockHalSwitch(mAdminUser.id, mGuestUser, mSwitchUserResponse);
+
+        mCarUserService.switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        UserSwitchResult result = getUserSwitchResult();
+        assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_HAL_FAILURE);
+        assertThat(result.getErrorMessage()).isEqualTo(mSwitchUserResponse.errorMessage);
+    }
+
+    @Test
+    public void testSwitchUser_error_badCallbackStatus() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
+        mockHalSwitch(mAdminUser.id, HalCallback.STATUS_WRONG_HAL_RESPONSE, mSwitchUserResponse,
+                mGuestUser);
+
+        mCarUserService.switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        assertThat(getUserSwitchResult().getStatus())
+                .isEqualTo(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
+    }
+
+    @Test
+    public void testSwitchUser_multipleCallsDifferentUser_beforeFirstUserUnlocked()
+            throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        int requestId = 42;
+        mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
+        mSwitchUserResponse.requestId = requestId;
+        mockHalSwitch(mAdminUser.id, mGuestUser, mSwitchUserResponse);
+        mockAmSwitchUser(mGuestUser, true);
+        mCarUserService.switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        // calling another user switch before unlock
+        int newRequestId = 43;
+        SwitchUserResponse switchUserResponse = new SwitchUserResponse();
+        switchUserResponse.status = SwitchUserStatus.SUCCESS;
+        switchUserResponse.requestId = newRequestId;
+        mockHalSwitch(mAdminUser.id, mRegularUser, switchUserResponse);
+        mockAmSwitchUser(mRegularUser, true);
+        AndroidFuture<UserSwitchResult> futureNewRequest = new AndroidFuture<>();
+        mCarUserService.switchUser(mRegularUser.id, mAsyncCallTimeoutMs, futureNewRequest);
+
+        assertThat(getUserSwitchResult().getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+        assertThat(getResult(futureNewRequest).getStatus())
+                .isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+        assertNoPostSwitch();
+        assertHalSwitch(mAdminUser.id, mGuestUser.id);
+        assertHalSwitch(mAdminUser.id, mRegularUser.id);
+    }
+
+    @Test
+    public void testSwitchUser_multipleCallsDifferentUser_beforeFirstUserUnlock_abandonFirstCall()
+            throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        int requestId = 42;
+        mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
+        mSwitchUserResponse.requestId = requestId;
+        mockHalSwitch(mAdminUser.id, mGuestUser, mSwitchUserResponse);
+        mockAmSwitchUser(mGuestUser, true);
+        mCarUserService.switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        // calling another user switch before unlock
+        int newRequestId = 43;
+        SwitchUserResponse switchUserResponse = new SwitchUserResponse();
+        switchUserResponse.status = SwitchUserStatus.SUCCESS;
+        switchUserResponse.requestId = newRequestId;
+        mockHalSwitch(mAdminUser.id, mRegularUser, switchUserResponse);
+        mockAmSwitchUser(mRegularUser, true);
+        AndroidFuture<UserSwitchResult> futureNewRequest = new AndroidFuture<>();
+        mCarUserService.switchUser(mRegularUser.id, mAsyncCallTimeoutMs, futureNewRequest);
+        mockCurrentUser(mRegularUser);
+        sendUserUnlockedEvent(mRegularUser.id);
+
+        assertThat(getResult(futureNewRequest).getStatus())
+                .isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+        assertPostSwitch(newRequestId, mRegularUser.id, mRegularUser.id);
+        assertHalSwitch(mAdminUser.id, mGuestUser.id);
+        assertHalSwitch(mAdminUser.id, mRegularUser.id);
+    }
+
+    @Test
+    public void testSwitchUser_multipleCallsDifferentUser_beforeHALResponded()
+            throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        int requestId = 42;
+        mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
+        mSwitchUserResponse.requestId = requestId;
+        mCarUserService.switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        // calling another user switch before unlock
+        int newRequestId = 43;
+        SwitchUserResponse switchUserResponse = new SwitchUserResponse();
+        switchUserResponse.status = SwitchUserStatus.SUCCESS;
+        switchUserResponse.requestId = newRequestId;
+        mockHalSwitch(mAdminUser.id, mRegularUser, switchUserResponse);
+        mockAmSwitchUser(mRegularUser, true);
+        AndroidFuture<UserSwitchResult> futureNewRequest = new AndroidFuture<>();
+        mCarUserService.switchUser(mRegularUser.id, mAsyncCallTimeoutMs, futureNewRequest);
+
+        assertThat(getResult(futureNewRequest).getStatus())
+                .isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+        assertNoPostSwitch();
+        assertHalSwitch(mAdminUser.id, mGuestUser.id);
+        assertHalSwitch(mAdminUser.id, mRegularUser.id);
+    }
+
+    @Test
+    public void testSwitchUser_multipleCallsDifferentUser_beforeHALResponded_abandonFirstCall()
+            throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        int requestId = 42;
+        mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
+        mSwitchUserResponse.requestId = requestId;
+        mCarUserService.switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        // calling another user switch before unlock
+        int newRequestId = 43;
+        SwitchUserResponse switchUserResponse = new SwitchUserResponse();
+        switchUserResponse.status = SwitchUserStatus.SUCCESS;
+        switchUserResponse.requestId = newRequestId;
+        mockHalSwitch(mAdminUser.id, mRegularUser, switchUserResponse);
+        mockAmSwitchUser(mRegularUser, true);
+        AndroidFuture<UserSwitchResult> futureNewRequest = new AndroidFuture<>();
+        mCarUserService.switchUser(mRegularUser.id, mAsyncCallTimeoutMs, futureNewRequest);
+        mockCurrentUser(mRegularUser);
+        sendUserUnlockedEvent(mRegularUser.id);
+
+        assertThat(getResult(futureNewRequest).getStatus())
+                .isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+        assertPostSwitch(newRequestId, mRegularUser.id, mRegularUser.id);
+        assertHalSwitch(mAdminUser.id, mGuestUser.id);
+        assertHalSwitch(mAdminUser.id, mRegularUser.id);
+    }
+
+    @Test
+    public void testSwitchUser_multipleCallsDifferentUser_HALRespondedLate_abandonFirstCall()
+            throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        int requestId = 42;
+        mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
+        mSwitchUserResponse.requestId = requestId;
+        BlockingAnswer<Void> blockingAnswer = mockHalSwitchLateResponse(mAdminUser.id, mGuestUser,
+                mSwitchUserResponse);
+        mCarUserService.switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        // calling another user switch before unlock
+        int newRequestId = 43;
+        SwitchUserResponse switchUserResponse = new SwitchUserResponse();
+        switchUserResponse.status = SwitchUserStatus.SUCCESS;
+        switchUserResponse.requestId = newRequestId;
+        mockHalSwitch(mAdminUser.id, mRegularUser, switchUserResponse);
+        mockAmSwitchUser(mRegularUser, true);
+        AndroidFuture<UserSwitchResult> futureNewRequest = new AndroidFuture<>();
+        mCarUserService.switchUser(mRegularUser.id, mAsyncCallTimeoutMs, futureNewRequest);
+        mockCurrentUser(mRegularUser);
+        sendUserUnlockedEvent(mRegularUser.id);
+        blockingAnswer.unblock();
+
+        UserSwitchResult result = getUserSwitchResult();
+        assertThat(result.getStatus())
+                .isEqualTo(UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST);
+        assertThat(getResult(futureNewRequest).getStatus())
+                .isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+        assertPostSwitch(newRequestId, mRegularUser.id, mRegularUser.id);
+        assertHalSwitch(mAdminUser.id, mGuestUser.id);
+        assertHalSwitch(mAdminUser.id, mRegularUser.id);
+    }
+
+    @Test
+    public void testSwitchUser_multipleCallsSameUser_beforeHALResponded() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        int requestId = 42;
+        mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
+        mSwitchUserResponse.requestId = requestId;
+
+        mCarUserService.switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        // calling another user switch before unlock
+        AndroidFuture<UserSwitchResult> futureNewRequest = new AndroidFuture<>();
+        mCarUserService.switchUser(mGuestUser.id, mAsyncCallTimeoutMs, futureNewRequest);
+
+        assertThat(getResult(futureNewRequest).getStatus())
+                .isEqualTo(UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO);
+        assertNoPostSwitch();
+        assertHalSwitch(mAdminUser.id, mGuestUser.id);
+    }
+
+    @Test
+    public void testSwitchUser_multipleCallsSameUser_beforeFirstUserUnlocked() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        int requestId = 42;
+        mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
+        mSwitchUserResponse.requestId = requestId;
+        mockHalSwitch(mAdminUser.id, mGuestUser, mSwitchUserResponse);
+        mockAmSwitchUser(mGuestUser, true);
+
+        mCarUserService.switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        // calling another user switch before unlock
+        AndroidFuture<UserSwitchResult> futureNewRequest = new AndroidFuture<>();
+        mCarUserService.switchUser(mGuestUser.id, mAsyncCallTimeoutMs, futureNewRequest);
+
+        assertThat(getUserSwitchResult().getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+        assertThat(getResult(futureNewRequest).getStatus())
+                .isEqualTo(UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO);
+        assertNoPostSwitch();
+        assertHalSwitch(mAdminUser.id, mGuestUser.id);
+    }
+
+    @Test
+    public void testSwitchUser_multipleCallsSameUser_beforeFirstUserUnlocked_noAffectOnFirstCall()
+            throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        int requestId = 42;
+        mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
+        mSwitchUserResponse.requestId = requestId;
+        mockHalSwitch(mAdminUser.id, mGuestUser, mSwitchUserResponse);
+        mockAmSwitchUser(mGuestUser, true);
+
+        mCarUserService.switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        int newRequestId = 43;
+        mSwitchUserResponse.requestId = newRequestId;
+
+        // calling another user switch before unlock
+        AndroidFuture<UserSwitchResult> futureNewRequest = new AndroidFuture<>();
+        mCarUserService.switchUser(mGuestUser.id, mAsyncCallTimeoutMs, futureNewRequest);
+        mockCurrentUser(mGuestUser);
+        sendUserUnlockedEvent(mGuestUser.id);
+
+        assertThat(getUserSwitchResult().getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+        assertThat(getResult(futureNewRequest).getStatus())
+                .isEqualTo(UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO);
+        assertPostSwitch(requestId, mGuestUser.id, mGuestUser.id);
+        assertHalSwitch(mAdminUser.id, mGuestUser.id);
+    }
+
+    @Test
+    public void testSwitchUser_InvalidPermission() throws Exception {
+        mockManageUsersPermission(android.Manifest.permission.MANAGE_USERS, false);
+        assertThrows(SecurityException.class, () -> mCarUserService
+                .switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture));
+    }
+
+    @Test
+    public void testLegacyUserSwitch_ok() throws Exception {
+        mockExistingUsers(mExistingUsers);
+
+        sendUserSwitchingEvent(mAdminUser.id, mRegularUser.id);
+
+        verify(mUserHal).legacyUserSwitch(isSwitchUserRequest(0, mAdminUser.id, mRegularUser.id));
+    }
+
+    @Test
+    public void testLegacyUserSwitch_notCalledAfterNormalSwitch() throws Exception {
+        // Arrange - emulate normal switch
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        int requestId = 42;
+        mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
+        mSwitchUserResponse.requestId = requestId;
+        mockHalSwitch(mAdminUser.id, mGuestUser, mSwitchUserResponse);
+        mockAmSwitchUser(mGuestUser, true);
+        mCarUserService.switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        // Act - trigger legacy switch
+        sendUserSwitchingEvent(mAdminUser.id, mGuestUser.id);
+
+        // Assert
+        verify(mUserHal, never()).legacyUserSwitch(any());
+    }
+
+    @Test
+    public void testSetSwitchUserUI_receiverSetAndCalled() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        int callerId = Binder.getCallingUid();
+        mockCallerUid(callerId, true);
+        int requestId = 42;
+        mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
+        mSwitchUserResponse.requestId = requestId;
+        mockHalSwitch(mAdminUser.id, mGuestUser, mSwitchUserResponse);
+        mockAmSwitchUser(mGuestUser, true);
+
+        mCarUserService.setUserSwitchUiCallback(mSwitchUserUiReceiver);
+        mCarUserService.switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        // update current user due to successful user switch
+        verify(mSwitchUserUiReceiver).send(mGuestUser.id, null);
+    }
+
+    @Test
+    public void testSetSwitchUserUI_nonCarSysUiCaller() throws Exception {
+        int callerId = Binder.getCallingUid();
+        mockCallerUid(callerId, false);
+
+        assertThrows(SecurityException.class,
+                () -> mCarUserService.setUserSwitchUiCallback(mSwitchUserUiReceiver));
+    }
+
+    @Test
+    public void testSwitchUser_OEMRequest_success() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        mockAmSwitchUser(mRegularUser, true);
+        int requestId = -1;
+
+        mCarUserService.switchAndroidUserFromHal(requestId, mRegularUser.id);
+        mockCurrentUser(mRegularUser);
+        sendUserUnlockedEvent(mRegularUser.id);
+
+        assertPostSwitch(requestId, mRegularUser.id, mRegularUser.id);
+    }
+
+    @Test
+    public void testSwitchUser_OEMRequest_failure() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        mockAmSwitchUser(mRegularUser, false);
+        int requestId = -1;
+
+        mCarUserService.switchAndroidUserFromHal(requestId, mRegularUser.id);
+
+        assertPostSwitch(requestId, mAdminUser.id, mRegularUser.id);
+    }
+
+    @Test
+    public void testCreateUser_nullType() throws Exception {
+        assertThrows(NullPointerException.class, () -> mCarUserService
+                .createUser("dude", null, 108, mAsyncCallTimeoutMs, mUserCreationFuture));
+    }
+
+    @Test
+    public void testCreateUser_nullReceiver() throws Exception {
+        assertThrows(NullPointerException.class, () -> mCarUserService
+                .createUser("dude", "TypeONegative", 108, mAsyncCallTimeoutMs, null));
+    }
+
+    @Test
+    public void testCreateUser_umCreateReturnsNull() throws Exception {
+        // No need to mock um.createUser() to return null
+
+        mCarUserService.createUser("dude", "TypeONegative", 108, mAsyncCallTimeoutMs,
+                mUserCreationFuture);
+
+        UserCreationResult result = getUserCreationResult();
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_ANDROID_FAILURE);
+        assertThat(result.getUser()).isNull();
+        assertThat(result.getErrorMessage()).isNull();
+        assertNoHalUserCreation();
+        verifyNoUserRemoved();
+    }
+
+    @Test
+    public void testCreateUser_umCreateThrowsException() throws Exception {
+        mockUmCreateUser(mMockedUserManager, "dude", "TypeONegative", 108,
+                new RuntimeException("D'OH!"));
+
+        mCarUserService.createUser("dude", "TypeONegative", 108, mAsyncCallTimeoutMs,
+                mUserCreationFuture);
+
+        UserCreationResult result = getUserCreationResult();
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_ANDROID_FAILURE);
+        assertThat(result.getUser()).isNull();
+        assertThat(result.getErrorMessage()).isNull();
+        assertNoHalUserCreation();
+        verifyNoUserRemoved();
+    }
+
+    @Test
+    public void testCreateUser_internalHalFailure() throws Exception {
+        mockUmCreateUser(mMockedUserManager, "dude", "TypeONegative", 108, 42);
+        mockHalCreateUser(HalCallback.STATUS_INVALID, /* not_used_status= */ -1);
+
+        mCarUserService.createUser("dude", "TypeONegative", 108, mAsyncCallTimeoutMs,
+                mUserCreationFuture);
+
+        UserCreationResult result = getUserCreationResult();
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
+        assertThat(result.getUser()).isNull();
+        assertThat(result.getErrorMessage()).isNull();
+        verifyUserRemoved(42);
+    }
+
+    @Test
+    public void testCreateUser_halFailure() throws Exception {
+        mockUmCreateUser(mMockedUserManager, "dude", "TypeONegative", 108, 42);
+        mockHalCreateUser(HalCallback.STATUS_OK, CreateUserStatus.FAILURE);
+
+        mCarUserService.createUser("dude", "TypeONegative", 108, mAsyncCallTimeoutMs,
+                mUserCreationFuture);
+
+        UserCreationResult result = getUserCreationResult();
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_HAL_FAILURE);
+        assertThat(result.getUser()).isNull();
+        assertThat(result.getErrorMessage()).isNull();
+
+        verifyUserRemoved(42);
+    }
+
+    @Test
+    public void testCreateUser_halServiceThrowsRuntimeException() throws Exception {
+        mockUmCreateUser(mMockedUserManager, "dude", "TypeONegative", 108, 42);
+        mockHalCreateUserThrowsRuntimeException();
+
+        mCarUserService.createUser("dude", "TypeONegative", 108, mAsyncCallTimeoutMs,
+                mUserCreationFuture);
+
+        UserCreationResult result = getUserCreationResult();
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
+        assertThat(result.getUser()).isNull();
+        assertThat(result.getErrorMessage()).isNull();
+
+        verifyUserRemoved(42);
+    }
+
+    @Test
+    public void testCreateUser_halNotSupported_success() throws Exception {
+        mockUserHalSupported(false);
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        int userId = mGuestUser.id;
+        mockUmCreateUser(mMockedUserManager, "dude", UserManager.USER_TYPE_FULL_GUEST,
+                UserInfo.FLAG_EPHEMERAL, userId);
+
+        mCarUserService.createUser("dude", UserManager.USER_TYPE_FULL_GUEST,
+                UserInfo.FLAG_EPHEMERAL, mAsyncCallTimeoutMs, mUserCreationFuture);
+
+        UserCreationResult result = getUserCreationResult();
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_SUCCESSFUL);
+        verify(mUserHal, never()).createUser(any(), anyInt(), any());
+    }
+
+    @Test
+    public void testCreateUser_success() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        int userId = mGuestUser.id;
+        mockUmCreateUser(mMockedUserManager, "dude", UserManager.USER_TYPE_FULL_GUEST,
+                UserInfo.FLAG_EPHEMERAL, userId);
+        ArgumentCaptor<CreateUserRequest> requestCaptor =
+                mockHalCreateUser(HalCallback.STATUS_OK, CreateUserStatus.SUCCESS);
+
+        mCarUserService.createUser("dude", UserManager.USER_TYPE_FULL_GUEST,
+                UserInfo.FLAG_EPHEMERAL, mAsyncCallTimeoutMs, mUserCreationFuture);
+
+        // Assert request
+        CreateUserRequest request = requestCaptor.getValue();
+        Log.d(TAG, "createUser() request: " + request);
+        assertThat(request.newUserName).isEqualTo("dude");
+        assertThat(request.newUserInfo.userId).isEqualTo(userId);
+        assertThat(request.newUserInfo.flags).isEqualTo(UserFlags.GUEST | UserFlags.EPHEMERAL);
+        assertDefaultUsersInfo(request.usersInfo, mAdminUser);
+
+        UserCreationResult result = getUserCreationResult();
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_SUCCESSFUL);
+        assertThat(result.getErrorMessage()).isNull();
+        UserInfo newUser = result.getUser();
+        assertThat(newUser).isNotNull();
+        assertThat(newUser.id).isEqualTo(userId);
+        assertThat(newUser.name).isEqualTo("dude");
+        assertThat(newUser.userType).isEqualTo(UserManager.USER_TYPE_FULL_GUEST);
+        assertThat(newUser.flags).isEqualTo(UserInfo.FLAG_EPHEMERAL);
+
+        verifyNoUserRemoved();
+    }
+
+    @Test
+    public void testCreateUser_success_nullName() throws Exception {
+        String nullName = null;
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        int userId = mGuestUser.id;
+        mockUmCreateUser(mMockedUserManager, nullName, UserManager.USER_TYPE_FULL_GUEST,
+                UserInfo.FLAG_EPHEMERAL, userId);
+        ArgumentCaptor<CreateUserRequest> requestCaptor =
+                mockHalCreateUser(HalCallback.STATUS_OK, CreateUserStatus.SUCCESS);
+
+        mCarUserService.createUser(nullName, UserManager.USER_TYPE_FULL_GUEST,
+                UserInfo.FLAG_EPHEMERAL, mAsyncCallTimeoutMs, mUserCreationFuture);
+
+        // Assert request
+        CreateUserRequest request = requestCaptor.getValue();
+        Log.d(TAG, "createUser() request: " + request);
+        assertThat(request.newUserName).isEmpty();
+        assertThat(request.newUserInfo.userId).isEqualTo(userId);
+        assertThat(request.newUserInfo.flags).isEqualTo(UserFlags.GUEST | UserFlags.EPHEMERAL);
+        assertDefaultUsersInfo(request.usersInfo, mAdminUser);
+
+        UserCreationResult result = getUserCreationResult();
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_SUCCESSFUL);
+        assertThat(result.getErrorMessage()).isNull();
+
+        UserInfo newUser = result.getUser();
+        assertThat(newUser).isNotNull();
+        assertThat(newUser.id).isEqualTo(userId);
+        assertThat(newUser.name).isNull();
+        assertThat(newUser.userType).isEqualTo(UserManager.USER_TYPE_FULL_GUEST);
+        assertThat(newUser.flags).isEqualTo(UserInfo.FLAG_EPHEMERAL);
+
+        verifyNoUserRemoved();
+    }
+
+    @Test
+    public void testGetUserInfo_nullReceiver() throws Exception {
+        assertThrows(NullPointerException.class, () -> mCarUserService
+                .getInitialUserInfo(mGetUserInfoRequestType, mAsyncCallTimeoutMs, null));
+    }
+
+    @Test
+    public void testGetInitialUserInfo_validReceiver_invalidPermission() throws Exception {
+        mockManageUsersPermission(android.Manifest.permission.MANAGE_USERS, false);
+        assertThrows(SecurityException.class,
+                () -> mCarUserService.getInitialUserInfo(42, 108, mReceiver));
+    }
+
+    @Test
+    public void testGetUserInfo_defaultResponse() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+
+        mGetUserInfoResponse.action = InitialUserInfoResponseAction.DEFAULT;
+        mockGetInitialInfo(mAdminUser.id, mGetUserInfoResponse);
+
+        mCarUserService.getInitialUserInfo(mGetUserInfoRequestType, mAsyncCallTimeoutMs, mReceiver);
+
+        assertThat(mReceiver.getResultCode()).isEqualTo(HalCallback.STATUS_OK);
+        Bundle resultData = mReceiver.getResultData();
+        assertThat(resultData).isNotNull();
+        assertInitialInfoAction(resultData, mGetUserInfoResponse.action);
+        assertInitialInfoUserLocales(resultData, null);
+    }
+
+    @Test
+    public void testGetUserInfo_defaultResponse_withLocale() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+
+        mGetUserInfoResponse.action = InitialUserInfoResponseAction.DEFAULT;
+        mGetUserInfoResponse.userLocales = "LOL";
+        mockGetInitialInfo(mAdminUser.id, mGetUserInfoResponse);
+
+        mCarUserService.getInitialUserInfo(mGetUserInfoRequestType, mAsyncCallTimeoutMs, mReceiver);
+
+        assertThat(mReceiver.getResultCode()).isEqualTo(HalCallback.STATUS_OK);
+        Bundle resultData = mReceiver.getResultData();
+        assertThat(resultData).isNotNull();
+        assertInitialInfoAction(resultData, mGetUserInfoResponse.action);
+        assertInitialInfoUserLocales(resultData, "LOL");
+    }
+
+    @Test
+    public void testGetUserInfo_switchUserResponse() throws Exception {
+        int switchUserId = mGuestUser.id;
+        mockExistingUsersAndCurrentUser(mAdminUser);
+
+        mGetUserInfoResponse.action = InitialUserInfoResponseAction.SWITCH;
+        mGetUserInfoResponse.userToSwitchOrCreate.userId = switchUserId;
+        mockGetInitialInfo(mAdminUser.id, mGetUserInfoResponse);
+
+        mCarUserService.getInitialUserInfo(mGetUserInfoRequestType, mAsyncCallTimeoutMs, mReceiver);
+
+        assertThat(mReceiver.getResultCode()).isEqualTo(HalCallback.STATUS_OK);
+        Bundle resultData = mReceiver.getResultData();
+        assertThat(resultData).isNotNull();
+        assertInitialInfoAction(resultData, mGetUserInfoResponse.action);
+        assertUserId(resultData, switchUserId);
+        assertNoUserFlags(resultData);
+        assertNoUserName(resultData);
+    }
+
+    @Test
+    public void testGetUserInfo_createUserResponse() throws Exception {
+        int newUserFlags = 42;
+        String newUserName = "TheDude";
+
+        mockExistingUsersAndCurrentUser(mAdminUser);
+
+        mGetUserInfoResponse.action = InitialUserInfoResponseAction.CREATE;
+        mGetUserInfoResponse.userToSwitchOrCreate.flags = newUserFlags;
+        mGetUserInfoResponse.userNameToCreate = newUserName;
+        mockGetInitialInfo(mAdminUser.id, mGetUserInfoResponse);
+
+        mCarUserService.getInitialUserInfo(mGetUserInfoRequestType, mAsyncCallTimeoutMs, mReceiver);
+
+        assertThat(mReceiver.getResultCode()).isEqualTo(HalCallback.STATUS_OK);
+        Bundle resultData = mReceiver.getResultData();
+        assertThat(resultData).isNotNull();
+        assertInitialInfoAction(resultData, mGetUserInfoResponse.action);
+        assertNoUserId(resultData);
+        assertUserFlags(resultData, newUserFlags);
+        assertUserName(resultData, newUserName);
+    }
+
+    @Test
+    public void testGetUserInfo_halNotSupported() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        mockUserHalSupported(false);
+
+        mCarUserService.getInitialUserInfo(mGetUserInfoRequestType, mAsyncCallTimeoutMs, mReceiver);
+
+        verify(mUserHal, never()).getInitialUserInfo(anyInt(), anyInt(), any(), any());
+        assertThat(mReceiver.getResultCode()).isEqualTo(HalCallback.STATUS_HAL_NOT_SUPPORTED);
+    }
+
+    /**
+     * Tests the {@code getUserInfo()} that's used by other services.
+     */
+    @Test
+    public void testGetInitialUserInfo() throws Exception {
+        int requestType = 42;
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        HalCallback<InitialUserInfoResponse> callback = (s, r) -> { };
+        mCarUserService.getInitialUserInfo(requestType, callback);
+        verify(mUserHal).getInitialUserInfo(eq(requestType), anyInt(), mUsersInfoCaptor.capture(),
+                same(callback));
+        assertDefaultUsersInfo(mUsersInfoCaptor.getValue(), mAdminUser);
+    }
+
+    @Test
+    public void testGetInitialUserInfo_nullCallback() throws Exception {
+        assertThrows(NullPointerException.class,
+                () -> mCarUserService.getInitialUserInfo(42, null));
+    }
+
+    @Test
+    public void testGetInitialUserInfo_halNotSupported_callback() throws Exception {
+        int requestType = 42;
+        mockUserHalSupported(false);
+        HalCallback<InitialUserInfoResponse> callback = (s, r) -> { };
+
+        mCarUserService.getInitialUserInfo(requestType, callback);
+
+        verify(mUserHal, never()).getInitialUserInfo(anyInt(), anyInt(), any(), any());
+    }
+
+    @Test
+    public void testGetInitialUserInfo_invalidPermission() throws Exception {
+        mockManageUsersPermission(android.Manifest.permission.MANAGE_USERS, false);
+        assertThrows(SecurityException.class,
+                () -> mCarUserService.getInitialUserInfo(42, (s, r) -> { }));
+    }
+
+    @Test
+    public void testGetInitialUser_invalidPermission() throws Exception {
+        mockManageUsersPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, false);
+        mockManageUsersPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, false);
+        assertThrows(SecurityException.class, () -> mCarUserService.getInitialUser());
+    }
+
+    @Test
+    public void testGetInitialUser_ok() throws Exception {
+        assertThat(mCarUserService.getInitialUser()).isNull();
+        UserInfo user = new UserInfo();
+        mCarUserService.setInitialUser(user);
+        assertThat(mCarUserService.getInitialUser()).isSameAs(user);
+    }
+
+    @Test
+    public void testIsHalSupported() throws Exception {
+        when(mUserHal.isSupported()).thenReturn(true);
+        assertThat(mCarUserService.isUserHalSupported()).isTrue();
+    }
+
+    @Test
+    public void testGetUserIdentificationAssociation_nullTypes() throws Exception {
+        assertThrows(IllegalArgumentException.class,
+                () -> mCarUserService.getUserIdentificationAssociation(null));
+    }
+
+    @Test
+    public void testGetUserIdentificationAssociation_emptyTypes() throws Exception {
+        assertThrows(IllegalArgumentException.class,
+                () -> mCarUserService.getUserIdentificationAssociation(new int[] {}));
+    }
+
+    @Test
+    public void testGetUserIdentificationAssociation_noPermission() throws Exception {
+        mockManageUsersPermission(android.Manifest.permission.MANAGE_USERS, false);
+        assertThrows(SecurityException.class,
+                () -> mCarUserService.getUserIdentificationAssociation(new int[] { 42 }));
+    }
+
+    @Test
+    public void testGetUserIdentificationAssociation_noSuchUser() throws Exception {
+        // Should fail because we're not mocking UserManager.getUserInfo() to set the flag
+        assertThrows(IllegalArgumentException.class,
+                () -> mCarUserService.getUserIdentificationAssociation(new int[] { 42 }));
+    }
+
+    @Test
+    public void testGetUserIdentificationAssociation_service_returnNull() throws Exception {
+        mockCurrentUserForBinderCalls();
+
+        UserIdentificationAssociationResponse response = mCarUserService
+                .getUserIdentificationAssociation(new int[] { 108 });
+
+        assertThat(response.isSuccess()).isFalse();
+        assertThat(response.getValues()).isNull();
+        assertThat(response.getErrorMessage()).isNull();
+    }
+
+    @Test
+    public void testGetUserIdentificationAssociation_halNotSupported() throws Exception {
+        mockUserHalUserAssociationSupported(false);
+
+        UserIdentificationAssociationResponse response = mCarUserService
+                .getUserIdentificationAssociation(new int[] { });
+
+        assertThat(response.isSuccess()).isFalse();
+        assertThat(response.getValues()).isNull();
+        assertThat(response.getErrorMessage()).isEqualTo(CarUserService.VEHICLE_HAL_NOT_SUPPORTED);
+        verify(mUserHal, never()).getUserAssociation(any());
+    }
+
+    @Test
+    public void testGetUserIdentificationAssociation_ok() throws Exception {
+        UserInfo currentUser = mockCurrentUserForBinderCalls();
+
+        int[] types = new int[] { 1, 2, 3 };
+        int[] values = new int[] { 10, 20, 30 };
+        mockHalGetUserIdentificationAssociation(currentUser, types, values, "D'OH!");
+
+        UserIdentificationAssociationResponse response = mCarUserService
+                .getUserIdentificationAssociation(types);
+
+        assertThat(response.isSuccess()).isTrue();
+        assertThat(response.getValues()).asList().containsAllOf(10, 20, 30).inOrder();
+        assertThat(response.getErrorMessage()).isEqualTo("D'OH!");
+    }
+
+    @Test
+    public void testSetUserIdentificationAssociation_nullTypes() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> mCarUserService
+                .setUserIdentificationAssociation(mAsyncCallTimeoutMs,
+                        null, new int[] {42}, mUserAssociationRespFuture));
+    }
+
+    @Test
+    public void testSetUserIdentificationAssociation_emptyTypes() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> mCarUserService
+                .setUserIdentificationAssociation(mAsyncCallTimeoutMs,
+                        new int[0], new int[] {42}, mUserAssociationRespFuture));
+    }
+
+    @Test
+    public void testSetUserIdentificationAssociation_nullValues() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> mCarUserService
+                .setUserIdentificationAssociation(mAsyncCallTimeoutMs,
+                        new int[] {42}, null, mUserAssociationRespFuture));
+    }
+    @Test
+    public void testSetUserIdentificationAssociation_sizeMismatch() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> mCarUserService
+                .setUserIdentificationAssociation(mAsyncCallTimeoutMs,
+                        new int[] {1}, new int[] {2, 2}, mUserAssociationRespFuture));
+    }
+
+    @Test
+    public void testSetUserIdentificationAssociation_nullFuture() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> mCarUserService
+                .setUserIdentificationAssociation(mAsyncCallTimeoutMs,
+                        new int[] {42}, new int[] {42}, null));
+    }
+
+    @Test
+    public void testSetUserIdentificationAssociation_noPermission() throws Exception {
+        mockManageUsersPermission(android.Manifest.permission.MANAGE_USERS, false);
+        assertThrows(SecurityException.class, () -> mCarUserService
+                .setUserIdentificationAssociation(mAsyncCallTimeoutMs,
+                        new int[] {42}, new int[] {42}, mUserAssociationRespFuture));
+    }
+
+    @Test
+    public void testSetUserIdentificationAssociation_noCurrentUser() throws Exception {
+        // Should fail because we're not mocking UserManager.getUserInfo() to set the flag
+        assertThrows(IllegalArgumentException.class, () -> mCarUserService
+                .setUserIdentificationAssociation(mAsyncCallTimeoutMs,
+                        new int[] {42}, new int[] {42}, mUserAssociationRespFuture));
+    }
+
+    @Test
+    public void testSetUserIdentificationAssociation_halNotSupported() throws Exception {
+        int[] types = new int[] { 1, 2, 3 };
+        int[] values = new int[] { 10, 20, 30 };
+        mockUserHalUserAssociationSupported(false);
+
+        mCarUserService.setUserIdentificationAssociation(mAsyncCallTimeoutMs, types, values,
+                mUserAssociationRespFuture);
+        UserIdentificationAssociationResponse response = getUserAssociationRespResult();
+
+        assertThat(response.isSuccess()).isFalse();
+        assertThat(response.getValues()).isNull();
+        assertThat(response.getErrorMessage()).isEqualTo(CarUserService.VEHICLE_HAL_NOT_SUPPORTED);
+        verify(mUserHal, never()).setUserAssociation(anyInt(), any(), any());
+    }
+
+    @Test
+    public void testSetUserIdentificationAssociation_halFailedWithErrorMessage() throws Exception {
+        mockCurrentUserForBinderCalls();
+        mockHalSetUserIdentificationAssociationFailure("D'OH!");
+        int[] types = new int[] { 1, 2, 3 };
+        int[] values = new int[] { 10, 20, 30 };
+        mCarUserService.setUserIdentificationAssociation(mAsyncCallTimeoutMs, types, values,
+                mUserAssociationRespFuture);
+
+        UserIdentificationAssociationResponse response = getUserAssociationRespResult();
+
+        assertThat(response.isSuccess()).isFalse();
+        assertThat(response.getValues()).isNull();
+        assertThat(response.getErrorMessage()).isEqualTo("D'OH!");
+
+    }
+
+    @Test
+    public void testSetUserIdentificationAssociation_halFailedWithoutErrorMessage()
+            throws Exception {
+        mockCurrentUserForBinderCalls();
+        mockHalSetUserIdentificationAssociationFailure(/* errorMessage= */ null);
+        int[] types = new int[] { 1, 2, 3 };
+        int[] values = new int[] { 10, 20, 30 };
+        mCarUserService.setUserIdentificationAssociation(mAsyncCallTimeoutMs, types, values,
+                mUserAssociationRespFuture);
+
+        UserIdentificationAssociationResponse response = getUserAssociationRespResult();
+
+        assertThat(response.isSuccess()).isFalse();
+        assertThat(response.getValues()).isNull();
+        assertThat(response.getErrorMessage()).isNull();
+    }
+
+    @Test
+    public void testSetUserIdentificationAssociation_ok() throws Exception {
+        UserInfo currentUser = mockCurrentUserForBinderCalls();
+
+        int[] types = new int[] { 1, 2, 3 };
+        int[] values = new int[] { 10, 20, 30 };
+        mockHalSetUserIdentificationAssociationSuccess(currentUser, types, values, "D'OH!");
+
+        mCarUserService.setUserIdentificationAssociation(mAsyncCallTimeoutMs, types, values,
+                mUserAssociationRespFuture);
+
+        UserIdentificationAssociationResponse response = getUserAssociationRespResult();
+
+        assertThat(response.isSuccess()).isTrue();
+        assertThat(response.getValues()).asList().containsAllOf(10, 20, 30).inOrder();
+        assertThat(response.getErrorMessage()).isEqualTo("D'OH!");
+    }
+
+    @Test
+    public void testUserMetric_SendEvent() throws Exception {
+        mockExistingUsersAndCurrentUser(mAdminUser);
+        sendUserSwitchingEvent(mAdminUser.id, mRegularUser.id);
+
+        verify(mUserMetrics).onEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING,
+                DEFAULT_LIFECYCLE_TIMESTAMP, mAdminUser.id, mRegularUser.id);
+    }
+
+    @Test
+    public void testUserMetric_FirstUnlock() {
+        int userId = 99;
+        long timestampMs = 0;
+        long duration = 153;
+        int halResponseTime = 5;
+        mCarUserService.onFirstUserUnlocked(userId, timestampMs, duration, halResponseTime);
+
+        verify(mUserMetrics).logFirstUnlockedUser(userId, timestampMs, duration, halResponseTime);
+    }
+
+    @NonNull
+    private UserSwitchResult getUserSwitchResult() throws Exception {
+        return getResult(mUserSwitchFuture);
+    }
+
+    @NonNull
+    private UserCreationResult getUserCreationResult() throws Exception {
+        return getResult(mUserCreationFuture);
+    }
+
+    @NonNull
+    private UserIdentificationAssociationResponse getUserAssociationRespResult()
+            throws Exception {
+        return getResult(mUserAssociationRespFuture);
+    }
+
+    /**
+     * This method must be called for cases where the service infers the user id of the caller
+     * using Binder - it's not worth the effort of mocking such (native) calls.
+     */
+    @NonNull
+    private UserInfo mockCurrentUserForBinderCalls() {
+        int currentUserId = ActivityManager.getCurrentUser();
+        Log.d(TAG, "testetUserIdentificationAssociation_ok(): current user is " + currentUserId);
+        UserInfo currentUser = mockUmGetUserInfo(mMockedUserManager, currentUserId,
                 UserInfo.FLAG_ADMIN);
-        doReturn(admin).when(mCarUserManagerHelper).createNewAdminUser();
+        return currentUser;
+    }
 
-        return admin;
+    /**
+     * Mock calls that generate a {@code UsersInfo}.
+     */
+    private void mockExistingUsersAndCurrentUser(@NonNull UserInfo user)
+            throws Exception {
+        mockExistingUsers(mExistingUsers);
+        mockCurrentUser(user);
+    }
+
+    private void mockExistingUsersAndCurrentUser(@NonNull List<UserInfo> existingUsers,
+            @NonNull UserInfo currentUser) throws Exception {
+        mockExistingUsers(existingUsers);
+        mockCurrentUser(currentUser);
+    }
+
+    private void mockExistingUsers(@NonNull List<UserInfo> existingUsers) {
+        mockUmGetUsers(mMockedUserManager, existingUsers);
+        for (UserInfo user : existingUsers) {
+            AndroidMockitoHelper.mockUmGetUserInfo(mMockedUserManager, user);
+        }
+    }
+
+    private void mockCurrentUser(@NonNull UserInfo user) throws Exception {
+        when(mMockedIActivityManager.getCurrentUser()).thenReturn(user);
+        mockGetCurrentUser(user.id);
+    }
+
+    private void mockAmSwitchUser(@NonNull UserInfo user, boolean result) throws Exception {
+        when(mMockedIActivityManager.switchUser(user.id)).thenReturn(result);
+    }
+
+    private void mockGetInitialInfo(@UserIdInt int currentUserId,
+            @NonNull InitialUserInfoResponse response) {
+        UsersInfo usersInfo = newUsersInfo(currentUserId);
+        doAnswer((invocation) -> {
+            Log.d(TAG, "Answering " + invocation + " with " + response);
+            @SuppressWarnings("unchecked")
+            HalCallback<InitialUserInfoResponse> callback =
+                    (HalCallback<InitialUserInfoResponse>) invocation.getArguments()[3];
+            callback.onResponse(HalCallback.STATUS_OK, response);
+            return null;
+        }).when(mUserHal).getInitialUserInfo(eq(mGetUserInfoRequestType), eq(mAsyncCallTimeoutMs),
+                eq(usersInfo), notNull());
+    }
+
+    private void mockIsHeadlessSystemUser(@UserIdInt int userId, boolean mode) {
+        doReturn(mode).when(() -> UserHelper.isHeadlessSystemUser(userId));
+    }
+
+    private void mockHalSwitch(@UserIdInt int currentUserId, @NonNull UserInfo androidTargetUser,
+            @Nullable SwitchUserResponse response) {
+        mockHalSwitch(currentUserId, HalCallback.STATUS_OK, response, androidTargetUser);
+    }
+
+    @NonNull
+    private ArgumentCaptor<CreateUserRequest> mockHalCreateUser(
+            @HalCallbackStatus int callbackStatus, int responseStatus) {
+        CreateUserResponse response = new CreateUserResponse();
+        response.status = responseStatus;
+        ArgumentCaptor<CreateUserRequest> captor = ArgumentCaptor.forClass(CreateUserRequest.class);
+        doAnswer((invocation) -> {
+            Log.d(TAG, "Answering " + invocation + " with " + response);
+            @SuppressWarnings("unchecked")
+            HalCallback<CreateUserResponse> callback =
+                    (HalCallback<CreateUserResponse>) invocation.getArguments()[2];
+            callback.onResponse(callbackStatus, response);
+            return null;
+        }).when(mUserHal).createUser(captor.capture(), eq(mAsyncCallTimeoutMs), notNull());
+        return captor;
+    }
+
+    private void mockHalCreateUserThrowsRuntimeException() {
+        doThrow(new RuntimeException("D'OH!"))
+                .when(mUserHal).createUser(any(), eq(mAsyncCallTimeoutMs), notNull());
+    }
+
+    private void mockCallerUid(int uid, boolean returnCorrectUid) throws Exception {
+        String packageName = "packageName";
+        String className = "className";
+        when(mMockedResources.getString(anyInt())).thenReturn(packageName + "/" + className);
+        when(mMockContext.createContextAsUser(any(), anyInt())).thenReturn(mMockContext);
+        when(mMockContext.getPackageManager()).thenReturn(mPackageManager);
+
+        if (returnCorrectUid) {
+            when(mPackageManager.getPackageUid(any(), anyInt())).thenReturn(uid);
+        } else {
+            when(mPackageManager.getPackageUid(any(), anyInt())).thenReturn(uid + 1);
+        }
+    }
+
+    private BlockingAnswer<Void> mockHalSwitchLateResponse(@UserIdInt int currentUserId,
+            @NonNull UserInfo androidTargetUser, @Nullable SwitchUserResponse response) {
+        android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
+                new android.hardware.automotive.vehicle.V2_0.UserInfo();
+        halTargetUser.userId = androidTargetUser.id;
+        halTargetUser.flags = UserHalHelper.convertFlags(androidTargetUser);
+        UsersInfo usersInfo = newUsersInfo(currentUserId);
+        SwitchUserRequest request = new SwitchUserRequest();
+        request.targetUser = halTargetUser;
+        request.usersInfo = usersInfo;
+
+        BlockingAnswer<Void> blockingAnswer = BlockingAnswer.forVoidReturn(10_000, (invocation) -> {
+            Log.d(TAG, "Answering " + invocation + " with " + response);
+            @SuppressWarnings("unchecked")
+            HalCallback<SwitchUserResponse> callback = (HalCallback<SwitchUserResponse>) invocation
+                    .getArguments()[2];
+            callback.onResponse(HalCallback.STATUS_OK, response);
+        });
+        doAnswer(blockingAnswer).when(mUserHal).switchUser(eq(request), eq(mAsyncCallTimeoutMs),
+                notNull());
+        return blockingAnswer;
+    }
+
+    private void mockHalSwitch(@UserIdInt int currentUserId,
+            @HalCallback.HalCallbackStatus int callbackStatus,
+            @Nullable SwitchUserResponse response, @NonNull UserInfo androidTargetUser) {
+        android.hardware.automotive.vehicle.V2_0.UserInfo halTargetUser =
+                new android.hardware.automotive.vehicle.V2_0.UserInfo();
+        halTargetUser.userId = androidTargetUser.id;
+        halTargetUser.flags = UserHalHelper.convertFlags(androidTargetUser);
+        UsersInfo usersInfo = newUsersInfo(currentUserId);
+        SwitchUserRequest request = new SwitchUserRequest();
+        request.targetUser = halTargetUser;
+        request.usersInfo = usersInfo;
+
+        doAnswer((invocation) -> {
+            Log.d(TAG, "Answering " + invocation + " with " + response);
+            @SuppressWarnings("unchecked")
+            HalCallback<SwitchUserResponse> callback =
+                    (HalCallback<SwitchUserResponse>) invocation.getArguments()[2];
+            callback.onResponse(callbackStatus, response);
+            return null;
+        }).when(mUserHal).switchUser(eq(request), eq(mAsyncCallTimeoutMs), notNull());
+    }
+
+    private void mockHalGetUserIdentificationAssociation(@NonNull UserInfo user,
+            @NonNull int[] types, @NonNull int[] values,  @Nullable String errorMessage) {
+        assertWithMessage("mismatch on number of types and values").that(types.length)
+                .isEqualTo(values.length);
+
+        UserIdentificationResponse response = new UserIdentificationResponse();
+        response.numberAssociation = types.length;
+        response.errorMessage = errorMessage;
+        for (int i = 0; i < types.length; i++) {
+            UserIdentificationAssociation association = new UserIdentificationAssociation();
+            association.type = types[i];
+            association.value = values[i];
+            response.associations.add(association);
+        }
+
+        when(mUserHal.getUserAssociation(isUserIdentificationGetRequest(user, types)))
+                .thenReturn(response);
+    }
+
+    private void mockHalSetUserIdentificationAssociationSuccess(@NonNull UserInfo user,
+            @NonNull int[] types, @NonNull int[] values,  @Nullable String errorMessage) {
+        assertWithMessage("mismatch on number of types and values").that(types.length)
+                .isEqualTo(values.length);
+
+        UserIdentificationResponse response = new UserIdentificationResponse();
+        response.numberAssociation = types.length;
+        response.errorMessage = errorMessage;
+        for (int i = 0; i < types.length; i++) {
+            UserIdentificationAssociation association = new UserIdentificationAssociation();
+            association.type = types[i];
+            association.value = values[i];
+            response.associations.add(association);
+        }
+
+        doAnswer((invocation) -> {
+            Log.d(TAG, "Answering " + invocation + " with " + response);
+            @SuppressWarnings("unchecked")
+            UserIdentificationSetRequest request =
+                    (UserIdentificationSetRequest) invocation.getArguments()[1];
+            assertWithMessage("Wrong user on %s", request)
+                    .that(request.userInfo.userId)
+                    .isEqualTo(user.id);
+            assertWithMessage("Wrong flags on %s", request)
+                    .that(UserHalHelper.toUserInfoFlags(request.userInfo.flags))
+                    .isEqualTo(user.flags);
+            @SuppressWarnings("unchecked")
+            HalCallback<UserIdentificationResponse> callback =
+                    (HalCallback<UserIdentificationResponse>) invocation.getArguments()[2];
+            callback.onResponse(HalCallback.STATUS_OK, response);
+            return null;
+        }).when(mUserHal).setUserAssociation(eq(mAsyncCallTimeoutMs), notNull(), notNull());
+    }
+
+    private void mockHalSetUserIdentificationAssociationFailure(@NonNull String errorMessage) {
+        UserIdentificationResponse response = new UserIdentificationResponse();
+        response.errorMessage = errorMessage;
+        doAnswer((invocation) -> {
+            Log.d(TAG, "Answering " + invocation + " with " + response);
+            @SuppressWarnings("unchecked")
+            HalCallback<UserIdentificationResponse> callback =
+                    (HalCallback<UserIdentificationResponse>) invocation.getArguments()[2];
+            callback.onResponse(HalCallback.STATUS_WRONG_HAL_RESPONSE, response);
+            return null;
+        }).when(mUserHal).setUserAssociation(eq(mAsyncCallTimeoutMs), notNull(), notNull());
+    }
+
+    private void mockManageUsersPermission(String permission, boolean granted) {
+        int result;
+        if (granted) {
+            result = android.content.pm.PackageManager.PERMISSION_GRANTED;
+        } else {
+            result = android.content.pm.PackageManager.PERMISSION_DENIED;
+        }
+        doReturn(result).when(() -> ActivityManager.checkComponentPermission(eq(permission),
+                anyInt(), anyInt(), eq(true)));
+    }
+
+    private void mockUserHalSupported(boolean result) {
+        when(mUserHal.isSupported()).thenReturn(result);
+    }
+
+    private void mockUserHalUserAssociationSupported(boolean result) {
+        when(mUserHal.isUserAssociationSupported()).thenReturn(result);
+    }
+
+    /**
+     * Asserts a {@link UsersInfo} that was created based on {@link #mockCurrentUsers(UserInfo)}.
+     */
+    private void assertDefaultUsersInfo(UsersInfo actual, UserInfo currentUser) {
+        // TODO(b/150413515): figure out why this method is not called in other places
+        assertThat(actual).isNotNull();
+        assertSameUser(actual.currentUser, currentUser);
+        assertThat(actual.numberUsers).isEqualTo(mExistingUsers.size());
+        for (int i = 0; i < actual.numberUsers; i++) {
+            assertSameUser(actual.existingUsers.get(i), mExistingUsers.get(i));
+        }
+    }
+
+    private void assertSameUser(android.hardware.automotive.vehicle.V2_0.UserInfo halUser,
+            UserInfo androidUser) {
+        assertThat(halUser.userId).isEqualTo(androidUser.id);
+        assertWithMessage("flags mismatch: hal=%s, android=%s",
+                UserInfo.flagsToString(androidUser.flags),
+                UserHalHelper.userFlagsToString(halUser.flags))
+            .that(halUser.flags).isEqualTo(UserHalHelper.convertFlags(androidUser));
+    }
+
+    private void verifyUserRemoved(@UserIdInt int userId) {
+        verify(mMockedUserManager).removeUser(userId);
+    }
+
+    private void verifyNoUserRemoved() {
+        verify(mMockedUserManager, never()).removeUser(anyInt());
+    }
+
+    @NonNull
+    private UsersInfo newUsersInfo(@UserIdInt int currentUserId) {
+        UsersInfo infos = new UsersInfo();
+        infos.numberUsers = mExistingUsers.size();
+        boolean foundCurrentUser = false;
+        for (UserInfo info : mExistingUsers) {
+            android.hardware.automotive.vehicle.V2_0.UserInfo existingUser =
+                    new android.hardware.automotive.vehicle.V2_0.UserInfo();
+            int flags = UserFlags.NONE;
+            if (info.id == UserHandle.USER_SYSTEM) {
+                flags |= UserFlags.SYSTEM;
+            }
+            if (info.isAdmin()) {
+                flags |= UserFlags.ADMIN;
+            }
+            if (info.isGuest()) {
+                flags |= UserFlags.GUEST;
+            }
+            if (info.isEphemeral()) {
+                flags |= UserFlags.EPHEMERAL;
+            }
+            existingUser.userId = info.id;
+            existingUser.flags = flags;
+            if (info.id == currentUserId) {
+                foundCurrentUser = true;
+                infos.currentUser.userId = info.id;
+                infos.currentUser.flags = flags;
+            }
+            infos.existingUsers.add(existingUser);
+        }
+        Preconditions.checkArgument(foundCurrentUser,
+                "no user with id " + currentUserId + " on " + mExistingUsers);
+        return infos;
+    }
+
+    private void assertUserId(@NonNull Bundle resultData, int expectedUserId) {
+        int actualUserId = resultData.getInt(CarUserService.BUNDLE_USER_ID);
+        assertWithMessage("wrong user id on bundle extra %s", CarUserService.BUNDLE_USER_ID)
+                .that(actualUserId).isEqualTo(expectedUserId);
+    }
+
+    private void assertNoUserId(@NonNull Bundle resultData) {
+        assertNoExtra(resultData, CarUserService.BUNDLE_USER_ID);
+    }
+
+    private void assertUserFlags(@NonNull Bundle resultData, int expectedUserFlags) {
+        int actualUserFlags = resultData.getInt(CarUserService.BUNDLE_USER_FLAGS);
+        assertWithMessage("wrong user flags on bundle extra %s", CarUserService.BUNDLE_USER_FLAGS)
+                .that(actualUserFlags).isEqualTo(expectedUserFlags);
+    }
+
+    private void assertNoUserFlags(@NonNull Bundle resultData) {
+        assertNoExtra(resultData, CarUserService.BUNDLE_USER_FLAGS);
+    }
+
+    private void assertUserName(@NonNull Bundle resultData, @NonNull String expectedName) {
+        String actualName = resultData.getString(CarUserService.BUNDLE_USER_NAME);
+        assertWithMessage("wrong user name on bundle extra %s",
+                CarUserService.BUNDLE_USER_FLAGS).that(actualName).isEqualTo(expectedName);
+    }
+
+    private void assertNoUserName(@NonNull Bundle resultData) {
+        assertNoExtra(resultData, CarUserService.BUNDLE_USER_NAME);
+    }
+
+    private void assertNoExtra(@NonNull Bundle resultData, @NonNull String extra) {
+        Object value = resultData.get(extra);
+        assertWithMessage("should not have extra %s", extra).that(value).isNull();
+    }
+
+    private void assertInitialInfoAction(@NonNull Bundle resultData, int expectedAction) {
+        int actualAction = resultData.getInt(CarUserService.BUNDLE_INITIAL_INFO_ACTION);
+        assertWithMessage("wrong request type on bundle extra %s",
+                CarUserService.BUNDLE_INITIAL_INFO_ACTION).that(actualAction)
+                .isEqualTo(expectedAction);
+    }
+
+    private void assertInitialInfoUserLocales(Bundle resultData, String expectedLocales) {
+        String actualLocales = resultData.getString(CarUserService.BUNDLE_USER_LOCALES);
+        assertWithMessage("wrong locales on bundle extra %s",
+                CarUserService.BUNDLE_USER_LOCALES).that(actualLocales)
+                .isEqualTo(expectedLocales);
+    }
+
+    private void assertNoPostSwitch() {
+        verify(mUserHal, never()).postSwitchResponse(any());
+    }
+
+    private void assertPostSwitch(int requestId, int currentId, int targetId) {
+        verify(mUserHal).postSwitchResponse(isSwitchUserRequest(requestId, currentId, targetId));
+    }
+
+    private void assertHalSwitch(int currentId, int targetId) {
+        verify(mUserHal).switchUser(isSwitchUserRequest(0, currentId, targetId),
+                eq(mAsyncCallTimeoutMs), any());
+    }
+
+    private void assertNoHalUserCreation() {
+        verify(mUserHal, never()).createUser(any(), eq(mAsyncCallTimeoutMs), any());
+    }
+
+    private void assertHalRemove(@NonNull UserInfo currentUser, @NonNull UserInfo removeUser,
+            @NonNull List<UserInfo> existingUsers) {
+        ArgumentCaptor<RemoveUserRequest> request =
+                ArgumentCaptor.forClass(RemoveUserRequest.class);
+        verify(mUserHal).removeUser(request.capture());
+        assertThat(request.getValue().removedUserInfo.userId).isEqualTo(removeUser.id);
+        assertThat(request.getValue().usersInfo.currentUser.userId).isEqualTo(currentUser.id);
+        UsersInfo receivedExistingUsers = request.getValue().usersInfo;
+        assertThat(receivedExistingUsers.numberUsers).isEqualTo(existingUsers.size());
+        for (int i = 0; i < receivedExistingUsers.numberUsers; i++) {
+            assertSameUser(receivedExistingUsers.existingUsers.get(i), existingUsers.get(i));
+        }
+    }
+
+    @NonNull
+    private static SwitchUserRequest isSwitchUserRequest(int requestId,
+            @UserIdInt int currentUserId, @UserIdInt int targetUserId) {
+        return argThat(new SwitchUserRequestMatcher(requestId, currentUserId, targetUserId));
+    }
+
+    static final class FakeCarOccupantZoneService {
+        private final SparseArray<Integer> mZoneUserMap = new SparseArray<Integer>();
+        private final CarUserService.ZoneUserBindingHelper mZoneUserBindigHelper =
+                new CarUserService.ZoneUserBindingHelper() {
+                    @Override
+                    @NonNull
+                    public List<OccupantZoneInfo> getOccupantZones(
+                            @OccupantTypeEnum int occupantType) {
+                        return null;
+                    }
+
+                    @Override
+                    public boolean assignUserToOccupantZone(@UserIdInt int userId, int zoneId) {
+                        if (mZoneUserMap.get(zoneId) != null) {
+                            return false;
+                        }
+                        mZoneUserMap.put(zoneId, userId);
+                        return true;
+                    }
+
+                    @Override
+                    public boolean unassignUserFromOccupantZone(@UserIdInt int userId) {
+                        for (int index = 0; index < mZoneUserMap.size(); index++) {
+                            if (mZoneUserMap.valueAt(index) == userId) {
+                                mZoneUserMap.removeAt(index);
+                                break;
+                            }
+                        }
+                        return true;
+                    }
+
+                    @Override
+                    public boolean isPassengerDisplayAvailable() {
+                        return true;
+                    }
+                };
+
+        FakeCarOccupantZoneService(CarUserService carUserService) {
+            carUserService.setZoneUserBindingHelper(mZoneUserBindigHelper);
+        }
+    }
+
+    private void sendUserLifecycleEvent(@UserIdInt int fromUserId, @UserIdInt int toUserId,
+            @UserLifecycleEventType int eventType) {
+        mCarUserService.onUserLifecycleEvent(eventType, DEFAULT_LIFECYCLE_TIMESTAMP, fromUserId,
+                toUserId);
+    }
+
+    private void sendUserUnlockedEvent(@UserIdInt int userId) {
+        sendUserLifecycleEvent(/* fromUser */ 0, userId,
+                CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED);
+    }
+
+    private void sendUserSwitchingEvent(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
+        sendUserLifecycleEvent(fromUserId, toUserId,
+                CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING);
+    }
+
+    @NonNull
+    private static UserIdentificationGetRequest isUserIdentificationGetRequest(
+            @NonNull UserInfo user, @NonNull int[] types) {
+        return argThat(new UserIdentificationGetRequestMatcher(user, types));
+    }
+
+    private static class UserIdentificationGetRequestMatcher implements
+            ArgumentMatcher<UserIdentificationGetRequest> {
+
+        private static final String MY_TAG =
+                UserIdentificationGetRequestMatcher.class.getSimpleName();
+
+        private final @UserIdInt int mUserId;
+        private final int mHalFlags;
+        private final @NonNull int[] mTypes;
+
+        private UserIdentificationGetRequestMatcher(@NonNull UserInfo user, @NonNull int[] types) {
+            mUserId = user.id;
+            mHalFlags = UserHalHelper.convertFlags(user);
+            mTypes = types;
+        }
+
+        @Override
+        public boolean matches(UserIdentificationGetRequest argument) {
+            if (argument == null) {
+                Log.w(MY_TAG, "null argument");
+                return false;
+            }
+            if (argument.userInfo.userId != mUserId) {
+                Log.w(MY_TAG, "wrong user id on " + argument + "; expected " + mUserId);
+                return false;
+            }
+            if (argument.userInfo.flags != mHalFlags) {
+                Log.w(MY_TAG, "wrong flags on " + argument + "; expected " + mHalFlags);
+                return false;
+            }
+            if (argument.numberAssociationTypes != mTypes.length) {
+                Log.w(MY_TAG, "wrong numberAssociationTypes on " + argument + "; expected "
+                        + mTypes.length);
+                return false;
+            }
+            if (argument.associationTypes.size() != mTypes.length) {
+                Log.w(MY_TAG, "wrong associationTypes size on " + argument + "; expected "
+                        + mTypes.length);
+                return false;
+            }
+            for (int i = 0; i < mTypes.length; i++) {
+                if (argument.associationTypes.get(i) != mTypes[i]) {
+                    Log.w(MY_TAG, "wrong association type on index " + i + " on " + argument
+                            + "; expected types: " + Arrays.toString(mTypes));
+                    return false;
+                }
+            }
+            Log.d(MY_TAG, "Good News, Everyone! " + argument + " matches " + this);
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return "isUserIdentificationGetRequest(userId=" + mUserId + ", flags="
+                    + UserHalHelper.userFlagsToString(mHalFlags) + ", types="
+                    + Arrays.toString(mTypes) + ")";
+        }
+    }
+
+    private static final class SwitchUserRequestMatcher
+            implements ArgumentMatcher<SwitchUserRequest> {
+        private static final String MY_TAG = UsersInfo.class.getSimpleName();
+
+        private final int mRequestId;
+        private final @UserIdInt int mCurrentUserId;
+        private final @UserIdInt int mTargetUserId;
+
+
+        private SwitchUserRequestMatcher(int requestId, @UserIdInt int currentUserId,
+                @UserIdInt int targetUserId) {
+            mCurrentUserId = currentUserId;
+            mTargetUserId = targetUserId;
+            mRequestId = requestId;
+        }
+
+        @Override
+        public boolean matches(SwitchUserRequest argument) {
+            if (argument == null) {
+                Log.w(MY_TAG, "null argument");
+                return false;
+            }
+            if (argument.usersInfo.currentUser.userId != mCurrentUserId) {
+                Log.w(MY_TAG,
+                        "wrong current user id on " + argument + "; expected " + mCurrentUserId);
+                return false;
+            }
+
+            if (argument.targetUser.userId != mTargetUserId) {
+                Log.w(MY_TAG,
+                        "wrong target user id on " + argument + "; expected " + mTargetUserId);
+                return false;
+            }
+
+            if (argument.requestId != mRequestId) {
+                Log.w(MY_TAG,
+                        "wrong request Id on " + argument + "; expected " + mTargetUserId);
+                return false;
+            }
+
+            Log.d(MY_TAG, "Good News, Everyone! " + argument + " matches " + this);
+            return true;
+        }
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/user/ExperimentalCarUserManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/user/ExperimentalCarUserManagerUnitTest.java
new file mode 100644
index 0000000..2869d5d
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/user/ExperimentalCarUserManagerUnitTest.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.user;
+
+import static android.car.test.mocks.AndroidMockitoHelper.getResult;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.when;
+
+import android.annotation.UserIdInt;
+import android.car.Car;
+import android.car.ICarUserService;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.test.util.UserTestingHelper;
+import android.car.user.CarUserManager;
+import android.car.user.ExperimentalCarUserManager;
+import android.car.user.UserCreationResult;
+import android.car.user.UserSwitchResult;
+import android.content.pm.UserInfo;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import com.android.internal.infra.AndroidFuture;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
+import java.util.Arrays;
+import java.util.List;
+
+public final class ExperimentalCarUserManagerUnitTest extends AbstractExtendedMockitoTestCase {
+
+    @Mock
+    private Car mCar;
+    @Mock
+    private UserManager mUserManager;
+    @Mock
+    private ICarUserService mService;
+
+    private ExperimentalCarUserManager mManager;
+
+    @Before public void setFixtures() {
+        mManager =
+                ExperimentalCarUserManager.from(new CarUserManager(mCar, mService, mUserManager));
+    }
+
+    @Test
+    public void testCreateDriver_Success_Admin() throws Exception {
+        String name = "test driver";
+        int userId = 10;
+        expectCreateDriverSucceed(name, userId);
+
+        AndroidFuture<UserCreationResult> future = mManager.createDriver(name, true);
+
+        UserCreationResult result = getResult(future);
+        assertThat(result.getErrorMessage()).isNull();
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_SUCCESSFUL);
+        assertThat(result.getUser().id).isEqualTo(userId);
+    }
+
+    @Test
+    public void testCreateDriver_Success_NonAdmin() throws Exception {
+        String name = "test driver";
+        int userId = 10;
+        expectCreateDriverSucceed(name, userId);
+
+        AndroidFuture<UserCreationResult> future = mManager.createDriver(name, false);
+
+        UserCreationResult result = getResult(future);
+        assertThat(result.getErrorMessage()).isNull();
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_SUCCESSFUL);
+        assertThat(result.getUser().id).isEqualTo(userId);
+    }
+
+    @Test
+    public void testCreateDriver_Error() throws Exception {
+        expectCreateDriverFail();
+
+        AndroidFuture<UserCreationResult> future = mManager.createDriver("test driver", false);
+
+        assertThat(future).isNotNull();
+        UserCreationResult result = getResult(future);
+        assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
+    }
+
+    @Test
+    public void testCreatePassenger_Success() throws Exception {
+        expectCreatePassengerSucceed();
+        int userId = mManager.createPassenger("test passenger", 10);
+        assertThat(userId).isNotEqualTo(UserHandle.USER_NULL);
+    }
+
+    @Test
+    public void testCreatePassenger_Error() throws Exception {
+        expectCreatePassengerFail();
+        int userId = mManager.createPassenger("test passenger", 20);
+        assertThat(userId).isEqualTo(UserHandle.USER_NULL);
+    }
+
+    @Test
+    public void testSwitchDriver_Success() throws Exception {
+        expectSwitchDriverSucceed(10);
+        AndroidFuture<UserSwitchResult> future = mManager.switchDriver(10);
+        UserSwitchResult result = getResult(future);
+        assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+    }
+
+    @Test
+    public void testSwitchDriver_Error() throws Exception {
+        expectSwitchDriverFail(20);
+        AndroidFuture<UserSwitchResult> future = mManager.switchDriver(20);
+        assertThat(future).isNotNull();
+        UserSwitchResult result = getResult(future);
+        assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
+    }
+
+    @Test
+    public void testGetAllDrivers() throws Exception {
+        List<UserInfo> userInfos = UserTestingHelper.newUsers(10, 20, 30);
+        when(mService.getAllDrivers()).thenReturn(userInfos);
+        List<Integer> drivers = mManager.getAllDrivers();
+        assertThat(drivers).containsExactly(10, 20, 30);
+    }
+
+    @Test
+    public void testGetAllPassengers() throws Exception {
+        List<UserInfo> userInfos = UserTestingHelper.newUsers(100, 101, 102);
+        when(mService.getPassengers(10)).thenReturn(userInfos);
+        when(mService.getPassengers(20)).thenReturn(Arrays.asList());
+
+        List<Integer> passengers = mManager.getPassengers(10);
+        assertThat(passengers).containsExactly(100, 101, 102);
+
+        passengers = mManager.getPassengers(20);
+        assertThat(passengers).isEmpty();
+    }
+
+    @Test
+    public void testStartPassenger_Success() throws Exception {
+        expectStartPassengerSucceed();
+        boolean success = mManager.startPassenger(100, /* zoneId = */ 1);
+        assertThat(success).isTrue();
+    }
+
+    @Test
+    public void testStartPassenger_Error() throws Exception {
+        expectStartPassengerFail();
+        boolean success = mManager.startPassenger(200, /* zoneId = */ 1);
+        assertThat(success).isFalse();
+    }
+
+    @Test
+    public void testStopPassenger_Success() throws Exception {
+        expectStopPassengerSucceed();
+        boolean success = mManager.stopPassenger(100);
+        assertThat(success).isTrue();
+    }
+
+    @Test
+    public void testStopPassenger_Error() throws Exception {
+        expectStopPassengerFail();
+        boolean success = mManager.stopPassenger(200);
+        assertThat(success).isFalse();
+    }
+
+    private void expectCreateDriverSucceed(String name, @UserIdInt int userId) throws Exception {
+        AndroidFuture<UserCreationResult> future = new AndroidFuture<>();
+        future.complete(new UserCreationResult(UserCreationResult.STATUS_SUCCESSFUL,
+                UserTestingHelper.newUser(userId), null));
+        when(mService.createDriver(eq(name), anyBoolean())).thenReturn(future);
+    }
+
+    private void expectCreateDriverFail() throws Exception {
+        doThrow(new RemoteException("D'OH!")).when(mService)
+            .createDriver(anyString(), anyBoolean());
+    }
+
+    private void expectCreatePassengerSucceed() throws Exception {
+        UserInfo userInfo = UserTestingHelper.newUser(100);
+        when(mService.createPassenger("test passenger", /* driverId = */ 10)).thenReturn(userInfo);
+    }
+
+    private void expectCreatePassengerFail() throws Exception {
+        when(mService.createPassenger("test passenger", /* driverId = */ 10)).thenReturn(null);
+    }
+
+    private void expectSwitchDriverSucceed(@UserIdInt int userId) throws Exception {
+        doAnswer((invocation) -> {
+            @SuppressWarnings("unchecked")
+            AndroidFuture<UserSwitchResult> future = (AndroidFuture<UserSwitchResult>) invocation
+                    .getArguments()[1];
+            future.complete(new UserSwitchResult(UserSwitchResult.STATUS_SUCCESSFUL, null));
+            return null;
+        }).when(mService).switchDriver(eq(userId), notNull());
+    }
+
+    private void expectSwitchDriverFail(@UserIdInt int userId) throws Exception {
+        doThrow(new RemoteException("D'OH!")).when(mService)
+            .switchDriver(eq(userId), notNull());
+    }
+
+    private void expectStartPassengerSucceed() throws Exception {
+        when(mService.startPassenger(100, /* zoneId = */ 1)).thenReturn(true);
+    }
+
+    private void expectStartPassengerFail() throws Exception {
+        when(mService.startPassenger(200, /* zoneId = */ 1)).thenReturn(false);
+    }
+
+    private void expectStopPassengerSucceed() throws Exception {
+        when(mService.stopPassenger(100)).thenReturn(true);
+    }
+
+    private void expectStopPassengerFail() throws Exception {
+        when(mService.stopPassenger(200)).thenReturn(false);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/user/UserCreationResultTest.java b/tests/carservice_unit_test/src/com/android/car/user/UserCreationResultTest.java
new file mode 100644
index 0000000..7aba561
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/user/UserCreationResultTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.user;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.user.UserCreationResult;
+
+import org.junit.Test;
+
+public final class UserCreationResultTest {
+
+    @Test
+    public void testIsSuccess() {
+        assertThat(new UserCreationResult(UserCreationResult.STATUS_SUCCESSFUL, null, null)
+                .isSuccess()).isTrue();
+        assertThat(new UserCreationResult(UserCreationResult.STATUS_HAL_FAILURE, null, null)
+                .isSuccess()).isFalse();
+        assertThat(
+                new UserCreationResult(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE, null, null)
+                        .isSuccess()).isFalse();
+        assertThat(new UserCreationResult(UserCreationResult.STATUS_ANDROID_FAILURE, null, null)
+                .isSuccess()).isFalse();
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/user/UserIdentificationAssociationResponseTest.java b/tests/carservice_unit_test/src/com/android/car/user/UserIdentificationAssociationResponseTest.java
new file mode 100644
index 0000000..f9ca16d
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/user/UserIdentificationAssociationResponseTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.user;
+
+import static android.car.user.UserIdentificationAssociationResponse.forFailure;
+import static android.car.user.UserIdentificationAssociationResponse.forSuccess;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.car.user.UserIdentificationAssociationResponse;
+
+import org.junit.Test;
+
+public final class UserIdentificationAssociationResponseTest {
+
+    @Test
+    public void testFailure_noMessage() {
+        UserIdentificationAssociationResponse response = forFailure();
+
+        assertThat(response).isNotNull();
+        assertThat(response.isSuccess()).isFalse();
+        assertThat(response.getErrorMessage()).isNull();
+        assertThat(response.getValues()).isNull();
+    }
+
+    @Test
+    public void testFailure_withMessage() {
+        UserIdentificationAssociationResponse response = forFailure("D'OH!");
+
+        assertThat(response).isNotNull();
+        assertThat(response.isSuccess()).isFalse();
+        assertThat(response.getErrorMessage()).isEqualTo("D'OH!");
+        assertThat(response.getValues()).isNull();
+    }
+
+    @Test
+    public void testSuccess_nullValues() {
+        assertThrows(IllegalArgumentException.class, () -> forSuccess(null));
+    }
+
+    @Test
+    public void testSuccess_nullValuesWithMessage() {
+        assertThrows(IllegalArgumentException.class, () -> forSuccess(null, "D'OH!"));
+    }
+
+    @Test
+    public void testSuccess_emptyValues() {
+        assertThrows(IllegalArgumentException.class, () -> forSuccess(new int[0]));
+    }
+
+    @Test
+    public void testSuccess_emptyValuesWithMessage() {
+        assertThrows(IllegalArgumentException.class, () -> forSuccess(new int[0], "D'OH!"));
+    }
+
+    @Test
+    public void testSuccess_noMessage() {
+        UserIdentificationAssociationResponse response = forSuccess(new int[] {1, 2, 3});
+
+        assertThat(response).isNotNull();
+        assertThat(response.isSuccess()).isTrue();
+        assertThat(response.getErrorMessage()).isNull();
+        assertThat(response.getValues()).asList().containsAllOf(1, 2, 3).inOrder();
+    }
+
+    @Test
+    public void testSuccess_withMessage() {
+        UserIdentificationAssociationResponse response = forSuccess(new int[] {1, 2, 3}, "D'OH!");
+
+        assertThat(response).isNotNull();
+        assertThat(response.isSuccess()).isTrue();
+        assertThat(response.getErrorMessage()).isEqualTo("D'OH!");
+        assertThat(response.getValues()).asList().containsAllOf(1, 2, 3).inOrder();
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/user/UserLifecycleEventTest.java b/tests/carservice_unit_test/src/com/android/car/user/UserLifecycleEventTest.java
new file mode 100644
index 0000000..28bffde
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/user/UserLifecycleEventTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.user;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.user.CarUserManager.UserLifecycleEvent;
+import android.os.UserHandle;
+
+import org.junit.Test;
+
+public final class UserLifecycleEventTest {
+
+    @Test
+    public void testFullConstructor() {
+        int eventType = 42;
+        int from = 10;
+        int to = 20;
+        UserLifecycleEvent event = new UserLifecycleEvent(eventType, from, to);
+
+        assertThat(event.getEventType()).isEqualTo(eventType);
+        assertThat(event.getUserId()).isEqualTo(to);
+        assertThat(event.getUserHandle().getIdentifier()).isEqualTo(to);
+        assertThat(event.getPreviousUserId()).isEqualTo(from);
+        assertThat(event.getPreviousUserHandle().getIdentifier()).isEqualTo(from);
+    }
+
+    @Test
+    public void testAlternativeConstructor() {
+        int eventType = 42;
+        int to = 20;
+        UserLifecycleEvent event = new UserLifecycleEvent(eventType, to);
+
+        assertThat(event.getEventType()).isEqualTo(eventType);
+        assertThat(event.getUserId()).isEqualTo(to);
+        assertThat(event.getUserHandle().getIdentifier()).isEqualTo(to);
+        assertThat(event.getPreviousUserId()).isEqualTo(UserHandle.USER_NULL);
+        assertThat(event.getPreviousUserHandle()).isNull();
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/user/UserMetricsTest.java b/tests/carservice_unit_test/src/com/android/car/user/UserMetricsTest.java
new file mode 100644
index 0000000..5e97f3a
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/user/UserMetricsTest.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.user;
+
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+
+import android.annotation.UserIdInt;
+import android.os.SystemClock;
+import android.util.SparseArray;
+
+import com.android.car.user.UserMetrics.UserStartingMetric;
+import com.android.car.user.UserMetrics.UserStoppingMetric;
+
+import org.junit.Test;
+
+public final class UserMetricsTest {
+
+    private final UserMetrics mUserMetrics = new UserMetrics();
+    @UserIdInt private final int mFromUserId = 10;
+    @UserIdInt private final int mUserId = 11;
+
+    @Test
+    public void testStartingEvent_success() {
+        long timestamp = sendStartingEvent(mUserId);
+
+        assertStartTime(timestamp, mUserId);
+    }
+
+    @Test
+    public void testStartingEvent_multipleCallsDifferentUser() {
+        long timestamp1 = sendStartingEvent(mUserId);
+        int userId = 12;
+        long timestamp2 = sendStartingEvent(userId);
+
+        assertStartTime(timestamp1, mUserId);
+        assertStartTime(timestamp2, userId);
+    }
+
+    @Test
+    public void testStartingEvent_multipleCallsSameUser() {
+        long timestamp1 = sendStartingEvent(mUserId);
+        assertStartTime(timestamp1, mUserId);
+        long timestamp2 = sendStartingEvent(mUserId);
+
+        assertStartTime(timestamp2, mUserId);
+    }
+
+    @Test
+    public void testSwitchingEvent_failure() {
+        sendSwitchingEvent(mFromUserId, mUserId);
+
+        assertNoStartingMetric(mUserId);
+    }
+
+    @Test
+    public void testSwitchingEvent_success() {
+        sendStartingEvent(mUserId);
+        long timestamp = sendSwitchingEvent(mFromUserId, mUserId);
+
+        assertSwitchTime(timestamp, mFromUserId, mUserId);
+    }
+
+    @Test
+    public void testUnlockingEvent_failure() {
+        sendUnlockingEvent(mUserId);
+
+        assertNoStartingMetric(mUserId);
+    }
+
+    @Test
+    public void testUnlockingEvent_success() {
+        sendStartingEvent(mUserId);
+        long timestamp = sendUnlockingEvent(mUserId);
+
+        assertUnlockingTime(timestamp, mUserId);
+    }
+
+    @Test
+    public void testUnlockedEvent_failure() {
+        sendUnlockedEvent(mUserId);
+
+        assertNoStartingMetric(mUserId);
+    }
+
+    @Test
+    public void testUnlockedEvent_success() {
+        long timestamp = sendStartingEvent(mUserId);
+        assertStartTime(timestamp, mUserId);
+        sendUnlockedEvent(mUserId);
+
+        // a successful unlocked event would have removed the metric
+        assertNoStartingMetric(mUserId);
+    }
+
+    @Test
+    public void testStopingEvent_success() {
+        long timestamp = sendStopingEvent(mUserId);
+
+        assertStopingTime(timestamp, mUserId);
+    }
+
+    @Test
+    public void testStopingEvent_multipleCallsDifferentUser() {
+        long timestamp1 = sendStopingEvent(mUserId);
+        int userId = 12;
+        long timestamp2 = sendStopingEvent(userId);
+
+        assertStopingTime(timestamp1, mUserId);
+        assertStopingTime(timestamp2, userId);
+    }
+
+    @Test
+    public void testStopingEvent_multipleCallsSameUser() {
+        long timestamp1 = sendStopingEvent(mUserId);
+        assertStopingTime(timestamp1, mUserId);
+        long timestamp2 = sendStopingEvent(mUserId);
+
+        assertStopingTime(timestamp2, mUserId);
+    }
+
+    @Test
+    public void testStoppedEvent_failure() {
+        sendStoppedEvent(mUserId);
+
+        assertNoStoppingMetric(mUserId);
+    }
+
+    @Test
+    public void testStoppedEvent_success() {
+        long timestamp = sendStopingEvent(mUserId);
+        assertStopingTime(timestamp, mUserId);
+        sendStoppedEvent(mUserId);
+
+        // a successful stopped event would have removed the metric
+        assertNoStoppingMetric(mUserId);
+    }
+
+    private long sendStartingEvent(@UserIdInt int userId) {
+        long timestampMs = SystemClock.elapsedRealtimeNanos();
+        mUserMetrics.onEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING, timestampMs, /* fromUserId */ -1,
+                userId);
+        return timestampMs;
+    }
+
+    private long sendSwitchingEvent(@UserIdInt int fromUserId, @UserIdInt int userId) {
+        long timestampMs = SystemClock.elapsedRealtimeNanos();
+        mUserMetrics.onEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING, timestampMs, fromUserId, userId);
+        return timestampMs;
+    }
+
+    private long sendUnlockingEvent(@UserIdInt int userId) {
+        long timestampMs = SystemClock.elapsedRealtimeNanos();
+        mUserMetrics.onEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING, timestampMs, /* fromUserId */ -1,
+                userId);
+        return timestampMs;
+    }
+
+    private long sendUnlockedEvent(@UserIdInt int userId) {
+        long timestampMs = SystemClock.elapsedRealtimeNanos();
+        mUserMetrics.onEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, timestampMs, /* fromUserId */ -1,
+                userId);
+        return timestampMs;
+    }
+
+    private long sendStopingEvent(@UserIdInt int userId) {
+        long timestampMs = SystemClock.elapsedRealtimeNanos();
+        mUserMetrics.onEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPING, timestampMs, /* fromUserId */ -1,
+                userId);
+        return timestampMs;
+    }
+
+    private long sendStoppedEvent(@UserIdInt int userId) {
+        long timestampMs = SystemClock.elapsedRealtimeNanos();
+        mUserMetrics.onEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED, timestampMs, /* fromUserId */ -1,
+                userId);
+        return timestampMs;
+    }
+
+    private void assertStartTime(long timestamp, @UserIdInt int userId) {
+        SparseArray<UserStartingMetric> startArray = mUserMetrics.getUserStartMetrics();
+        UserStartingMetric metric = startArray.get(userId);
+        assertThat(metric.startTime).isEqualTo(timestamp);
+    }
+
+    private void assertSwitchTime(long timestamp, @UserIdInt int fromUserId,
+            @UserIdInt int userId) {
+        SparseArray<UserStartingMetric> startArray = mUserMetrics.getUserStartMetrics();
+        UserStartingMetric metric = startArray.get(userId);
+        assertThat(metric.switchFromUserId).isEqualTo(fromUserId);
+        assertThat(metric.switchTime).isEqualTo(timestamp);
+    }
+
+    private void assertUnlockingTime(long timestamp, int userId) {
+        SparseArray<UserStartingMetric> startArray = mUserMetrics.getUserStartMetrics();
+        UserStartingMetric metric = startArray.get(userId);
+        assertThat(metric.unlockingTime).isEqualTo(timestamp);
+    }
+
+    private void assertNoStartingMetric(@UserIdInt int userId) {
+        SparseArray<UserStartingMetric> startArray = mUserMetrics.getUserStartMetrics();
+        assertThrows(NullPointerException.class, () -> startArray.get(userId));
+    }
+
+    private void assertStopingTime(long timestamp, @UserIdInt int userId) {
+        SparseArray<UserStoppingMetric> stopArray = mUserMetrics.getUserStopMetrics();
+        UserStoppingMetric metric = stopArray.get(userId);
+        assertThat(metric.stopTime).isEqualTo(timestamp);
+    }
+
+    private void assertNoStoppingMetric(@UserIdInt int userId) {
+        SparseArray<UserStoppingMetric> stopArray = mUserMetrics.getUserStopMetrics();
+        assertThrows(NullPointerException.class, () -> stopArray.get(userId));
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/user/UserSwitchResultTest.java b/tests/carservice_unit_test/src/com/android/car/user/UserSwitchResultTest.java
new file mode 100644
index 0000000..41d37ef
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/user/UserSwitchResultTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.user;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.user.UserSwitchResult;
+
+import org.junit.Test;
+
+public final class UserSwitchResultTest {
+
+    @Test
+    public void testIUserSwitchResult_checkStatusAndMessage() {
+        String msg = "Test Message";
+        UserSwitchResult result =
+                new UserSwitchResult(UserSwitchResult.STATUS_SUCCESSFUL, msg);
+        assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+        assertThat(result.getErrorMessage()).isEqualTo(msg);
+    }
+
+    @Test
+    public void testIUserSwitchResult_isSuccess_failure() {
+        UserSwitchResult result =
+                new UserSwitchResult(UserSwitchResult.STATUS_ANDROID_FAILURE, null);
+        assertThat(result.isSuccess()).isFalse();
+    }
+
+    @Test
+    public void testIUserSwitchResult_isSuccess_success() {
+        UserSwitchResult result =
+                new UserSwitchResult(UserSwitchResult.STATUS_SUCCESSFUL, null);
+        assertThat(result.isSuccess()).isTrue();
+    }
+
+    @Test
+    public void testIUserSwitchResult_isSuccess_requestedState() {
+        UserSwitchResult result =
+                new UserSwitchResult(UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND, null);
+        assertThat(result.isSuccess()).isTrue();
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/vms/VmsBrokerServiceTest.java b/tests/carservice_unit_test/src/com/android/car/vms/VmsBrokerServiceTest.java
new file mode 100644
index 0000000..e85dece
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/vms/VmsBrokerServiceTest.java
@@ -0,0 +1,3336 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.vms;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptySet;
+
+import android.car.vms.IVmsClientCallback;
+import android.car.vms.VmsAssociatedLayer;
+import android.car.vms.VmsAvailableLayers;
+import android.car.vms.VmsLayer;
+import android.car.vms.VmsLayerDependency;
+import android.car.vms.VmsProviderInfo;
+import android.car.vms.VmsRegistrationInfo;
+import android.car.vms.VmsSubscriptionState;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SharedMemory;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.Pair;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.car.stats.CarStatsService;
+import com.android.car.stats.VmsClientLogger;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+@RunWith(MockitoJUnitRunner.class)
+@SmallTest
+public class VmsBrokerServiceTest {
+    private static final int USER_ID = 10;
+
+    private static final String TEST_PACKAGE1 = "test.package1";
+    private static final String TEST_PACKAGE2 = "test.package2";
+
+    private static final int TEST_APP_ID1 = 12345;
+    private static final int TEST_APP_ID2 = 54321;
+    private static final int TEST_APP_UID1 = UserHandle.getUid(USER_ID, TEST_APP_ID1);
+    private static final int TEST_APP_UID2 = UserHandle.getUid(USER_ID, TEST_APP_ID2);
+    private static final int NO_SUBSCRIBERS_UID = -1;
+
+    private static final VmsProviderInfo PROVIDER_INFO1 =
+            new VmsProviderInfo(new byte[]{1, 2, 3, 4, 5});
+    private static final VmsProviderInfo PROVIDER_INFO2 =
+            new VmsProviderInfo(new byte[]{5, 4, 3, 2, 1});
+
+    private static final VmsAvailableLayers DEFAULT_AVAILABLE_LAYERS =
+            new VmsAvailableLayers(0, emptySet());
+    private static final VmsSubscriptionState DEFAULT_SUBSCRIPTION_STATE =
+            new VmsSubscriptionState(0, emptySet(), emptySet());
+
+    private static final VmsLayer LAYER1 = new VmsLayer(1, 1, 1);
+    private static final VmsLayer LAYER2 = new VmsLayer(2, 1, 1);
+    private static final VmsLayer LAYER3 = new VmsLayer(3, 1, 1);
+
+    private static final byte[] PAYLOAD = {1, 2, 3, 4, 5, 6, 7, 8};
+    private static final int LARGE_PACKET_SIZE = 54321;
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private CarStatsService mStatsService;
+
+    @Mock
+    private IVmsClientCallback mClientCallback1;
+    @Mock
+    private IBinder mClientBinder1;
+    @Mock
+    private VmsClientLogger mClientLog1;
+
+    @Mock
+    private IVmsClientCallback mClientCallback2;
+    @Mock
+    private IBinder mClientBinder2;
+    @Mock
+    private VmsClientLogger mClientLog2;
+
+    @Mock
+    private VmsClientLogger mNoSubscribersLog;
+
+    private final IBinder mClientToken1 = new Binder();
+    private final IBinder mClientToken2 = new Binder();
+    private SharedMemory mLargePacket;
+
+    private VmsBrokerService mBrokerService;
+    private int mCallingAppUid;
+    private Map<IBinder /* token */, Pair<IBinder /* callback */, IBinder.DeathRecipient>>
+            mDeathRecipients = new ArrayMap<>();
+
+    @Before
+    public void setUp() throws Exception {
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        mBrokerService = new VmsBrokerService(mContext, mStatsService, () -> mCallingAppUid);
+
+        when(mPackageManager.getNameForUid(TEST_APP_UID1)).thenReturn(TEST_PACKAGE1);
+        when(mPackageManager.getNameForUid(TEST_APP_UID2)).thenReturn(TEST_PACKAGE2);
+
+        when(mStatsService.getVmsClientLogger(TEST_APP_UID1)).thenReturn(mClientLog1);
+        when(mStatsService.getVmsClientLogger(TEST_APP_UID2)).thenReturn(mClientLog2);
+        when(mStatsService.getVmsClientLogger(NO_SUBSCRIBERS_UID)).thenReturn(mNoSubscribersLog);
+
+        when(mClientCallback1.asBinder()).thenReturn(mClientBinder1);
+        when(mClientCallback2.asBinder()).thenReturn(mClientBinder2);
+
+        mCallingAppUid = TEST_APP_UID1;
+    }
+
+    // Used by PublishLargePacket tests
+    private void setupLargePacket() throws Exception {
+        mLargePacket = Mockito.spy(SharedMemory.create("VmsBrokerServiceTest", LARGE_PACKET_SIZE));
+    }
+
+    @After
+    public void tearDown() {
+        if (mLargePacket != null) {
+            mLargePacket.close();
+        }
+    }
+
+    @Test
+    public void testRegister() {
+        VmsRegistrationInfo registrationInfo =
+                registerClient(mClientToken1, mClientCallback1, false);
+
+        verify(mClientLog1).logConnectionState(VmsClientLogger.ConnectionState.CONNECTED);
+        assertThat(registrationInfo.getAvailableLayers()).isEqualTo(DEFAULT_AVAILABLE_LAYERS);
+        assertThat(registrationInfo.getSubscriptionState()).isEqualTo(DEFAULT_SUBSCRIPTION_STATE);
+    }
+
+    @Test
+    public void testRegister_DeadCallback() throws Exception {
+        doThrow(RemoteException.class).when(mClientBinder1).linkToDeath(any(), anyInt());
+        assertThrows(
+                IllegalStateException.class,
+                () -> registerClient(mClientToken1, mClientCallback1));
+
+        verify(mClientLog1).logConnectionState(VmsClientLogger.ConnectionState.CONNECTED);
+        verify(mClientLog1).logConnectionState(VmsClientLogger.ConnectionState.DISCONNECTED);
+    }
+
+    @Test
+    public void testRegister_LegacyClient() {
+        VmsRegistrationInfo registrationInfo =
+                registerClient(mClientToken1, mClientCallback1, true);
+
+        verify(mClientLog1).logConnectionState(VmsClientLogger.ConnectionState.CONNECTED);
+        assertThat(registrationInfo.getAvailableLayers()).isEqualTo(DEFAULT_AVAILABLE_LAYERS);
+        assertThat(registrationInfo.getSubscriptionState()).isEqualTo(DEFAULT_SUBSCRIPTION_STATE);
+    }
+
+    @Test
+    public void testRegister_LegacyClient_DeadCallback() throws Exception {
+        doThrow(RemoteException.class).when(mClientBinder1).linkToDeath(any(), anyInt());
+        assertThrows(
+                IllegalStateException.class,
+                () -> registerClient(mClientToken1, mClientCallback1, true));
+
+        verify(mClientLog1).logConnectionState(VmsClientLogger.ConnectionState.CONNECTED);
+        verify(mClientLog1).logConnectionState(VmsClientLogger.ConnectionState.DISCONNECTED);
+    }
+
+    @Test
+    public void testRegister_TwoClients_OneProcess() {
+        VmsRegistrationInfo registrationInfo =
+                registerClient(mClientToken1, mClientCallback1, false);
+        VmsRegistrationInfo registrationInfo2 =
+                registerClient(mClientToken2, mClientCallback2, false);
+
+        verify(mClientLog1, times(2))
+                .logConnectionState(VmsClientLogger.ConnectionState.CONNECTED);
+        assertThat(registrationInfo).isEqualTo(registrationInfo2);
+    }
+
+    @Test
+    public void testRegister_TwoClients_TwoProcesses() {
+        VmsRegistrationInfo registrationInfo =
+                registerClient(mClientToken1, mClientCallback1, false);
+        mCallingAppUid = TEST_APP_UID2;
+        VmsRegistrationInfo registrationInfo2 =
+                registerClient(mClientToken2, mClientCallback2, false);
+
+        verify(mClientLog1).logConnectionState(VmsClientLogger.ConnectionState.CONNECTED);
+        verify(mClientLog2).logConnectionState(VmsClientLogger.ConnectionState.CONNECTED);
+        assertThat(registrationInfo).isEqualTo(registrationInfo2);
+    }
+
+    @Test
+    public void testRegister_ReceivesCurrentLayerAvailabilityAndSubscriptions() {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)));
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+
+        VmsRegistrationInfo registrationInfo =
+                registerClient(mClientToken2, mClientCallback2, false);
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1,
+                        asSet(providerId)))
+        );
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                asSet(LAYER1),
+                asSet(new VmsAssociatedLayer(LAYER2, asSet(12345)))
+        );
+        VmsRegistrationInfo expectedRegistrationInfo =
+                new VmsRegistrationInfo(expectedLayers, expectedSubscriptions);
+        assertThat(registrationInfo).isEqualTo(expectedRegistrationInfo);
+    }
+
+    @Test
+    public void testUnregisterClient_UnknownClient() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        mBrokerService.unregisterClient(mClientToken2);
+
+        verify(mClientCallback1, never()).onLayerAvailabilityChanged(any());
+        verify(mClientCallback1, never()).onSubscriptionStateChanged(any());
+    }
+
+    @Test
+    public void testRegisterProvider_UnknownClient() {
+        assertThrows(
+                IllegalStateException.class,
+                () -> mBrokerService.registerProvider(new Binder(), PROVIDER_INFO1));
+    }
+
+    @Test
+    public void testRegisterProvider_SameIdForSameInfo() {
+        registerClient(mClientToken1, mClientCallback1);
+
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        int providerId2 = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        assertThat(providerId).isEqualTo(providerId2);
+    }
+
+    @Test
+    public void testRegisterProvider_SameIdForSameInfo_MultipleClients() {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        int providerId2 = mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO1);
+
+        assertThat(providerId).isEqualTo(providerId2);
+    }
+
+    @Test
+    public void testRegisterProvider_DifferentIdForDifferentInfo() {
+        registerClient(mClientToken1, mClientCallback1);
+
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        int providerId2 = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO2);
+
+        assertThat(providerId).isNotEqualTo(providerId2);
+    }
+
+    @Test
+    public void testGetProviderInfo_UnknownClient() {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        assertThrows(
+                IllegalStateException.class,
+                () -> mBrokerService.getProviderInfo(new Binder(), providerId));
+    }
+
+    @Test
+    public void testGetProviderInfo_UnknownId() {
+        registerClient(mClientToken1, mClientCallback1);
+
+        assertThat(mBrokerService.getProviderInfo(mClientToken1, 12345).getDescription()).isNull();
+    }
+
+    @Test
+    public void testGetProviderInfo_RegisteredProvider() {
+        registerClient(mClientToken1, mClientCallback1);
+
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        assertThat(mBrokerService.getProviderInfo(mClientToken1, providerId))
+                .isEqualTo(PROVIDER_INFO1);
+    }
+
+    @Test
+    public void testSetSubscriptions_UnknownClient() {
+        assertThrows(
+                IllegalStateException.class,
+                () -> mBrokerService.setSubscriptions(new Binder(), asList()));
+    }
+
+    @Test
+    public void testSetSubscriptions() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                asSet(LAYER1),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleClients() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                asSet(LAYER1),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_OverwriteSubscription() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER2, emptySet())
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                asSet(LAYER2),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_OverwriteSubscription_MultipleClients() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER2, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER3, emptySet())
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                asSet(LAYER1, LAYER3),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_RemoveSubscription() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken1, asList());
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                emptySet(),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_RemoveSubscription_MultipleClients() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER2, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList());
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                asSet(LAYER1),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_RemoveSubscription_MultipleClients_SameLayer()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList());
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                asSet(LAYER1),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_RemoveSubscription_OnUnregister_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER2, emptySet())
+        ));
+        unregisterClient(mClientToken2);
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                asSet(LAYER1),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_RemoveSubscription_OnUnregister_MultipleClients_SameLayer()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        unregisterClient(mClientToken2);
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                asSet(LAYER1),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_RemoveSubscription_OnDisconnect_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER2, emptySet())
+        ));
+        disconnectClient(mClientToken2);
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                asSet(LAYER1),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_RemoveSubscription_OnDisconnect_MultipleClients_SameLayer()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        disconnectClient(mClientToken2);
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                asSet(LAYER1),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+
+    @Test
+    public void testSetSubscriptions_MultipleLayers() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER2, emptySet())
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                asSet(LAYER1, LAYER2),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayers_MultipleClients() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER2, emptySet()),
+                new VmsAssociatedLayer(LAYER3, emptySet())
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                asSet(LAYER1, LAYER2, LAYER3),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_MultipleClients() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(54321))
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345, 54321))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_OverwriteSubscription() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER2, asSet(54321))
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER2, asSet(54321))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_OverwriteSubscription_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER2, asSet(54321))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER3, asSet(98765))
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                emptySet(),
+                asSet(
+                        new VmsAssociatedLayer(LAYER1, asSet(12345)),
+                        new VmsAssociatedLayer(LAYER3, asSet(98765))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_OverwriteSubscription_MultipleClients_SameLayer()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER2, asSet(54321))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(98765))
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345, 98765))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_OverwriteSubscription_MultipleClients_SameLayerAndProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER2, asSet(54321))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_RemoveSubscription() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken1, asList());
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                emptySet(),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_RemoveSubscription_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER2, asSet(54321))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList());
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_RemoveSubscription_MultipleClients_SameLayer()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(54321))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList());
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_RemoveSubscription_MultipleClients_SameLayerAndProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList());
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_RemoveSubscription_OnUnregister_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER2, asSet(54321))
+        ));
+        unregisterClient(mClientToken2);
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_RemoveSubscription_OnUnregister_MultipleClients_SameLayer()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(54321))
+        ));
+        unregisterClient(mClientToken2);
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_RemoveSubscription_OnUnregister_MultipleClients_SameLayerAndProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        unregisterClient(mClientToken2);
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_RemoveSubscription_OnDisconnect_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER2, asSet(54321))
+        ));
+        disconnectClient(mClientToken2);
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_RemoveSubscription_OnDisconnect_MultipleClients_SameLayer()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(54321))
+        ));
+        disconnectClient(mClientToken2);
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndProvider_RemoveSubscription_OnDisconnect_MultipleClients_SameLayerAndProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        disconnectClient(mClientToken2);
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndMultipleProviders() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345, 54321))
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345, 54321))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerAndMultipleProviders_MultipleClients() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(54321))
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345, 54321))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayersAndProvider() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                asSet(LAYER1),
+                asSet(new VmsAssociatedLayer(LAYER2, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayersAndProvider_MultipleClients() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER3, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(54321))
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                asSet(LAYER1, LAYER3),
+                asSet(new VmsAssociatedLayer(LAYER2, asSet(12345, 54321))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayersAndProvider_OverwriteSubscription()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER2, emptySet()),
+                new VmsAssociatedLayer(LAYER1, asSet(54321))
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                asSet(LAYER2),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(54321))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayersAndProvider_OverwriteSubscription_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER2, emptySet()),
+                new VmsAssociatedLayer(LAYER1, asSet(54321))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER3, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(54321))
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                asSet(LAYER1, LAYER3),
+                asSet(new VmsAssociatedLayer(LAYER2, asSet(12345, 54321))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayersAndProvider_RemoveSubscription()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken1, asList());
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                emptySet(),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayersAndProvider_RemoveSubscription_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER2, emptySet()),
+                new VmsAssociatedLayer(LAYER1, asSet(54321))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList());
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                asSet(LAYER1),
+                asSet(new VmsAssociatedLayer(LAYER2, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayersAndProvider_RemoveSubscription_OnUnregister_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER2, emptySet()),
+                new VmsAssociatedLayer(LAYER1, asSet(54321))
+        ));
+        unregisterClient(mClientToken2);
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                asSet(LAYER1),
+                asSet(new VmsAssociatedLayer(LAYER2, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayersAndProvider_RemoveSubscription_OnDisconnect_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER2, emptySet()),
+                new VmsAssociatedLayer(LAYER1, asSet(54321))
+        ));
+        disconnectClient(mClientToken2);
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                asSet(LAYER1),
+                asSet(new VmsAssociatedLayer(LAYER2, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayersAndMultipleProviders() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(54321)),
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                emptySet(),
+                asSet(
+                        new VmsAssociatedLayer(LAYER1, asSet(54321)),
+                        new VmsAssociatedLayer(LAYER2, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_MultipleLayersAndMultipleProviders_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(54321))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER2, asSet(12345))
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                emptySet(),
+                asSet(
+                        new VmsAssociatedLayer(LAYER1, asSet(54321)),
+                        new VmsAssociatedLayer(LAYER2, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerOnlySupersedesLayerAndProvider() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                asSet(LAYER1),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerOnlySupersedesLayerAndProvider_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(1,
+                asSet(LAYER1),
+                emptySet());
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerOnlySupersedesLayerAndProvider_RemoveLayerSubscription()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet()),
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(2,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetSubscriptions_LayerOnlySupersedesLayerAndProvider_RemoveLayerSubscription_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(12345))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList());
+
+        VmsSubscriptionState expectedSubscriptions = new VmsSubscriptionState(3,
+                emptySet(),
+                asSet(new VmsAssociatedLayer(LAYER1, asSet(12345))));
+        verifySubscriptionState(mClientCallback1, expectedSubscriptions);
+        verifySubscriptionState(mClientCallback2, expectedSubscriptions);
+    }
+
+    @Test
+    public void testSetMonitoringEnabled_UnknownClient() {
+        assertThrows(
+                IllegalStateException.class,
+                () -> mBrokerService.setMonitoringEnabled(new Binder(), true));
+    }
+
+    @Test
+    public void testSetMonitoringEnabled_Enable_NoSubscriptionChange() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+
+        mBrokerService.setMonitoringEnabled(mClientToken1, true);
+
+        verify(mClientCallback1, never()).onSubscriptionStateChanged(any());
+    }
+
+    @Test
+    public void testSetMonitoringEnabled_Disable_NoSubscriptionChange() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+
+        mBrokerService.setMonitoringEnabled(mClientToken1, false);
+
+        verify(mClientCallback1, never()).onSubscriptionStateChanged(any());
+    }
+
+    @Test
+    public void testSetProviderOfferings_UnknownClient() {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        assertThrows(
+                IllegalStateException.class,
+                () -> mBrokerService.setProviderOfferings(new Binder(), providerId, asList()));
+    }
+
+    @Test
+    public void testSetProviderOfferings_UnknownProviderId() {
+        registerClient(mClientToken1, mClientCallback1);
+
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> mBrokerService.setProviderOfferings(mClientToken1, 12345, asList()));
+    }
+
+    @Test
+    public void testSetProviderOfferings_UnknownProviderId_LegacyClient() throws Exception {
+        registerClient(mClientToken1, mClientCallback1, true);
+
+        mBrokerService.setProviderOfferings(mClientToken1, 12345, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(12345)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_OtherClientsProviderId() {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        registerClient(mClientToken2, mClientCallback2);
+
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> mBrokerService.setProviderOfferings(mClientToken2, providerId, asList()));
+    }
+
+    @Test
+    public void testSetProviderOfferings_OtherClientsProviderId_LegacyClient() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        registerClient(mClientToken2, mClientCallback2, true);
+
+        mBrokerService.setProviderOfferings(mClientToken2, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_SingleProvider() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_MultipleProviders() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        int providerId2 = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken1, providerId2, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId, providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_MultipleClients() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        int providerId2 = mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId2, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId, providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_MultipleClients_SingleProvider() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_MultipleLayers_SingleProvider() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1),
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_MultipleLayers_MultipleProviders() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        int providerId2 = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken1, providerId2, asList(
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_MultipleLayers_MultipleClients() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        int providerId2 = mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId2, asList(
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_MultipleLayers_MultipleClients_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId, asList(
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_OverwriteOffering_SingleProvider() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_OverwriteOffering_MultipleProviders() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        int providerId2 = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken1, providerId2, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken1, providerId2, asList(
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(3, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_OverwriteOffering_MultipleClients() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        int providerId2 = mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId2, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId2, asList(
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(3, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_OverwriteOffering_MultipleClients_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId, asList(
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_RemoveOfferings_SingleProvider() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList());
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_RemoveOfferings_MultipleProviders() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        int providerId2 = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken1, providerId2, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken1, providerId2, asList());
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(3, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_RemoveOfferings_MultipleClients() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        int providerId2 = mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId2, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId2, asList());
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(3, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_RemoveOfferings_MultipleClients_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId, asList());
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_RemoveOfferings_OnUnregister_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        // Register second client to verify layer availability after first client disconnects
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        unregisterClient(mClientToken1);
+
+        VmsAvailableLayers expectedLayers1 = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)))
+        );
+        VmsAvailableLayers expectedLayers2 = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers1);
+        verifyLayerAvailability(mClientCallback2, expectedLayers2);
+    }
+
+    @Test
+    public void testSetProviderOfferings_RemoveOfferings_OnUnregister_MultipleProviders()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        int providerId2 = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO2);
+
+        // Register second client to verify layer availability after first client disconnects
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken1, providerId2, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        unregisterClient(mClientToken1);
+
+        VmsAvailableLayers expectedLayers1 = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId, providerId2)))
+        );
+        VmsAvailableLayers expectedLayers2 = new VmsAvailableLayers(3, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers1);
+        verifyLayerAvailability(mClientCallback2, expectedLayers2);
+    }
+
+    @Test
+    public void testSetProviderOfferings_RemoveOfferings_OnUnregister_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        int providerId2 = mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId2, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        unregisterClient(mClientToken1);
+
+        VmsAvailableLayers expectedLayers1 = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId, providerId2)))
+        );
+        VmsAvailableLayers expectedLayers2 = new VmsAvailableLayers(3, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers1);
+        verifyLayerAvailability(mClientCallback2, expectedLayers2);
+    }
+
+    @Test
+    public void testSetProviderOfferings_RemoveOfferings_OnUnregister_MultipleClients_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        disconnectClient(mClientToken1);
+
+        VmsAvailableLayers expectedLayers1 = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)))
+        );
+        VmsAvailableLayers expectedLayers2 = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers1);
+        verifyLayerAvailability(mClientCallback2, expectedLayers2);
+    }
+
+    @Test
+    public void testSetProviderOfferings_RemoveOfferings_OnDisconnect_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        // Register second client to verify layer availability after first client disconnects
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        disconnectClient(mClientToken1);
+
+        VmsAvailableLayers expectedLayers1 = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)))
+        );
+        VmsAvailableLayers expectedLayers2 = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers1);
+        verifyLayerAvailability(mClientCallback2, expectedLayers2);
+    }
+
+    @Test
+    public void testSetProviderOfferings_RemoveOfferings_OnDisconnect_MultipleProviders()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        int providerId2 = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO2);
+
+        // Register second client to verify layer availability after first client disconnects
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken1, providerId2, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        disconnectClient(mClientToken1);
+
+        VmsAvailableLayers expectedLayers1 = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId, providerId2)))
+        );
+        VmsAvailableLayers expectedLayers2 = new VmsAvailableLayers(3, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers1);
+        verifyLayerAvailability(mClientCallback2, expectedLayers2);
+    }
+
+    @Test
+    public void testSetProviderOfferings_RemoveOfferings_OnDisconnect_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        int providerId2 = mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId2, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        disconnectClient(mClientToken1);
+
+        VmsAvailableLayers expectedLayers1 = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId, providerId2)))
+        );
+        VmsAvailableLayers expectedLayers2 = new VmsAvailableLayers(3, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers1);
+        verifyLayerAvailability(mClientCallback2, expectedLayers2);
+    }
+
+    @Test
+    public void testSetProviderOfferings_RemoveOfferings_OnDisconnect_MultipleClients_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        disconnectClient(mClientToken1);
+
+        VmsAvailableLayers expectedLayers1 = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)))
+        );
+        VmsAvailableLayers expectedLayers2 = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers1);
+        verifyLayerAvailability(mClientCallback2, expectedLayers2);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_SingleProvider() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_MultipleProviders() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        int providerId2 = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2))
+        ));
+        mBrokerService.setProviderOfferings(mClientToken1, providerId2, asList(
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_MultipleClients() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        int providerId2 = mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2))
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId2, asList(
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_MultipleClients_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2))
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId, asList(
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_MultipleDependencies_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3)),
+                new VmsLayerDependency(LAYER2),
+                new VmsLayerDependency(LAYER3)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER3, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_MultipleDependencies_MultipleProviders()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        int providerId2 = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3)),
+                new VmsLayerDependency(LAYER2)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken1, providerId2, asList(
+                new VmsLayerDependency(LAYER3)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER3, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_MultipleDependencies_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        int providerId2 = mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3)),
+                new VmsLayerDependency(LAYER2)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId2, asList(
+                new VmsLayerDependency(LAYER3)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER3, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_MultipleDependencies_MultipleClients_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3)),
+                new VmsLayerDependency(LAYER2)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId, asList(
+                new VmsLayerDependency(LAYER3)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER3, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_ChainedDependencies_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER2, asSet(LAYER3)),
+                new VmsLayerDependency(LAYER3)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER3, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_ChainedDependencies_MultipleProviders()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        int providerId2 = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER3)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken1, providerId2, asList(
+                new VmsLayerDependency(LAYER2, asSet(LAYER3))
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId2)),
+                new VmsAssociatedLayer(LAYER3, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_ChainedDependencies_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        int providerId2 = mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER3)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId2, asList(
+                new VmsLayerDependency(LAYER2, asSet(LAYER3))
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId2)),
+                new VmsAssociatedLayer(LAYER3, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyMet_ChainedDependencies_MultipleClients_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER3)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId, asList(
+                new VmsLayerDependency(LAYER2, asSet(LAYER3))
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)),
+                new VmsAssociatedLayer(LAYER3, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_SingleProvider() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER2, asSet(LAYER1))
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_MultipleProviders() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        int providerId2 = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2))
+        ));
+        mBrokerService.setProviderOfferings(mClientToken1, providerId2, asList(
+                new VmsLayerDependency(LAYER2, asSet(LAYER1))
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_MultipleClients() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        int providerId2 = mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2))
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId2, asList(
+                new VmsLayerDependency(LAYER2, asSet(LAYER1))
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_MultipleClients_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2))
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId, asList(
+                new VmsLayerDependency(LAYER2, asSet(LAYER1))
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_MultipleDependencies_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3)),
+                new VmsLayerDependency(LAYER2),
+                new VmsLayerDependency(LAYER3, asSet(LAYER1))
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_MultipleDependencies_MultipleProviders()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        int providerId2 = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3)),
+                new VmsLayerDependency(LAYER2)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken1, providerId2, asList(
+                new VmsLayerDependency(LAYER3, asSet(LAYER1))
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_MultipleDependencies_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        int providerId2 = mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3)),
+                new VmsLayerDependency(LAYER2)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId2, asList(
+                new VmsLayerDependency(LAYER3, asSet(LAYER1))
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_MultipleDependencies_MultipleClients_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3)),
+                new VmsLayerDependency(LAYER2)
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId, asList(
+                new VmsLayerDependency(LAYER3, asSet(LAYER1))
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_ChainedDependencies_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER2, asSet(LAYER3)),
+                new VmsLayerDependency(LAYER3, asSet(LAYER1))
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_ChainedDependencies_MultipleProviders()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        int providerId2 = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER3, asSet(LAYER1))
+        ));
+        mBrokerService.setProviderOfferings(mClientToken1, providerId2, asList(
+                new VmsLayerDependency(LAYER2, asSet(LAYER3))
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_ChainedDependencies_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        int providerId2 = mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER3, asSet(LAYER1))
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId2, asList(
+                new VmsLayerDependency(LAYER2, asSet(LAYER3))
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyCircular_ChainedDependencies_MultipleClients_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER3, asSet(LAYER1))
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId, asList(
+                new VmsLayerDependency(LAYER2, asSet(LAYER3))
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyUnmet_SingleProvider() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2))
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyUnmet_MultipleDependencies_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3)),
+                new VmsLayerDependency(LAYER2)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, asSet(
+                new VmsAssociatedLayer(LAYER2, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyUnmet_MultipleDependencies_MultipleProviders()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        int providerId2 = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3))
+        ));
+        mBrokerService.setProviderOfferings(mClientToken1, providerId2, asList(
+                new VmsLayerDependency(LAYER3)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER3, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyUnmet_MultipleDependencies_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        int providerId2 = mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3))
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId2, asList(
+                new VmsLayerDependency(LAYER3)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER3, asSet(providerId2)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyUnmet_MultipleDependencies_MultipleClients_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2, LAYER3))
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId, asList(
+                new VmsLayerDependency(LAYER3)
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, asSet(
+                new VmsAssociatedLayer(LAYER3, asSet(providerId)))
+        );
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyUnmet_ChainedDependencies_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2)),
+                new VmsLayerDependency(LAYER2, asSet(LAYER3))
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(1, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyUnmet_ChainedDependencies_MultipleProviders()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        int providerId2 = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2))
+        ));
+        mBrokerService.setProviderOfferings(mClientToken1, providerId2, asList(
+                new VmsLayerDependency(LAYER2, asSet(LAYER3))
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyUnmet_ChainedDependencies_MultipleClients()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        int providerId2 = mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2))
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId2, asList(
+                new VmsLayerDependency(LAYER2, asSet(LAYER3))
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testSetProviderOfferings_DependencyUnmet_ChainedDependencies_MultipleClients_SingleProvider()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        registerClient(mClientToken2, mClientCallback2);
+        mBrokerService.registerProvider(mClientToken2, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1, asSet(LAYER2))
+        ));
+        mBrokerService.setProviderOfferings(mClientToken2, providerId, asList(
+                new VmsLayerDependency(LAYER2, asSet(LAYER3))
+        ));
+
+        VmsAvailableLayers expectedLayers = new VmsAvailableLayers(2, emptySet());
+        verifyLayerAvailability(mClientCallback1, expectedLayers);
+        verifyLayerAvailability(mClientCallback2, expectedLayers);
+    }
+
+    @Test
+    public void testPublishPacket_UnknownClient() {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        assertThrows(
+                IllegalStateException.class,
+                () -> mBrokerService.publishPacket(new Binder(), providerId, LAYER1, PAYLOAD));
+    }
+
+    @Test
+    public void testPublishPacket_UnknownOffering() {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> mBrokerService.publishPacket(mClientToken1, providerId, LAYER1, PAYLOAD));
+    }
+
+    @Test
+    public void testPublishPacket_UnknownOffering_LegacyClient() throws Exception {
+        registerClient(mClientToken1, mClientCallback1, true);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.publishPacket(mClientToken1, 12345, LAYER1, PAYLOAD);
+
+        verify(mClientLog1).logPacketSent(LAYER1, PAYLOAD.length);
+        verify(mClientLog1).logPacketReceived(LAYER1, PAYLOAD.length);
+        verifyPacketReceived(mClientCallback1, 12345, LAYER1, PAYLOAD);
+    }
+
+
+    @Test
+    public void testPublishPacket_NoSubscribers() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.publishPacket(mClientToken1, providerId, LAYER1, PAYLOAD);
+
+        verify(mClientLog1).logPacketSent(LAYER1, PAYLOAD.length);
+        verify(mNoSubscribersLog).logPacketDropped(LAYER1, PAYLOAD.length);
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_MonitorSubscriber_Enabled() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setMonitoringEnabled(mClientToken1, true);
+        mBrokerService.publishPacket(mClientToken1, providerId, LAYER1, PAYLOAD);
+
+        verify(mClientLog1).logPacketSent(LAYER1, PAYLOAD.length);
+        verify(mClientLog1).logPacketReceived(LAYER1, PAYLOAD.length);
+        verifyPacketReceived(mClientCallback1, providerId, LAYER1, PAYLOAD);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_MonitorSubscriber_EnabledAndDisabled() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setMonitoringEnabled(mClientToken1, true);
+        mBrokerService.setMonitoringEnabled(mClientToken1, false);
+        mBrokerService.publishPacket(mClientToken1, providerId, LAYER1, PAYLOAD);
+
+        verify(mClientLog1).logPacketSent(LAYER1, PAYLOAD.length);
+        verify(mNoSubscribersLog).logPacketDropped(LAYER1, PAYLOAD.length);
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_LayerSubscriber() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.publishPacket(mClientToken1, providerId, LAYER1, PAYLOAD);
+
+        verify(mClientLog1).logPacketSent(LAYER1, PAYLOAD.length);
+        verify(mClientLog1).logPacketReceived(LAYER1, PAYLOAD.length);
+        verifyPacketReceived(mClientCallback1, providerId, LAYER1, PAYLOAD);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_LayerSubscriber_Unsubscribe() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken1, asList());
+        mBrokerService.publishPacket(mClientToken1, providerId, LAYER1, PAYLOAD);
+
+        verify(mClientLog1).logPacketSent(LAYER1, PAYLOAD.length);
+        verify(mNoSubscribersLog).logPacketDropped(LAYER1, PAYLOAD.length);
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_LayerSubscriber_DifferentLayer() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER2, emptySet())
+        ));
+        mBrokerService.publishPacket(mClientToken1, providerId, LAYER1, PAYLOAD);
+
+        verify(mClientLog1).logPacketSent(LAYER1, PAYLOAD.length);
+        verify(mNoSubscribersLog).logPacketDropped(LAYER1, PAYLOAD.length);
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_MultipleLayerSubscribers() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.publishPacket(mClientToken1, providerId, LAYER1, PAYLOAD);
+
+        verify(mClientLog1).logPacketSent(LAYER1, PAYLOAD.length);
+        verify(mClientLog1, times(2)).logPacketReceived(LAYER1, PAYLOAD.length);
+        verifyPacketReceived(mClientCallback1, providerId, LAYER1, PAYLOAD);
+        verifyPacketReceived(mClientCallback2, providerId, LAYER1, PAYLOAD);
+    }
+
+    @Test
+    public void testPublishPacket_MultipleLayerSubscribers_DifferentProcesses() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mCallingAppUid = TEST_APP_UID2;
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.publishPacket(mClientToken1, providerId, LAYER1, PAYLOAD);
+
+        verify(mClientLog1).logPacketSent(LAYER1, PAYLOAD.length);
+        verify(mClientLog1).logPacketReceived(LAYER1, PAYLOAD.length);
+        verify(mClientLog2).logPacketReceived(LAYER1, PAYLOAD.length);
+        verifyPacketReceived(mClientCallback1, providerId, LAYER1, PAYLOAD);
+        verifyPacketReceived(mClientCallback2, providerId, LAYER1, PAYLOAD);
+    }
+
+    @Test
+    public void testPublishPacket_LayerAndProviderSubscriber() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId))
+        ));
+        mBrokerService.publishPacket(mClientToken1, providerId, LAYER1, PAYLOAD);
+
+        verify(mClientLog1).logPacketSent(LAYER1, PAYLOAD.length);
+        verify(mClientLog1).logPacketReceived(LAYER1, PAYLOAD.length);
+        verifyPacketReceived(mClientCallback1, providerId, LAYER1, PAYLOAD);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_LayerAndProviderSubscriber_Unsubscribe() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId))
+        ));
+        mBrokerService.setSubscriptions(mClientToken1, asList());
+        mBrokerService.publishPacket(mClientToken1, providerId, LAYER1, PAYLOAD);
+
+        verify(mClientLog1).logPacketSent(LAYER1, PAYLOAD.length);
+        verify(mNoSubscribersLog).logPacketDropped(LAYER1, PAYLOAD.length);
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_LayerAndProviderSubscriber_DifferentProvider() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        int providerId2 = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId2))
+        ));
+        mBrokerService.publishPacket(mClientToken1, providerId, LAYER1, PAYLOAD);
+
+        verify(mClientLog1).logPacketSent(LAYER1, PAYLOAD.length);
+        verify(mNoSubscribersLog).logPacketDropped(LAYER1, PAYLOAD.length);
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+    }
+
+    @Test
+    public void testPublishPacket_MultipleLayerAndProviderSubscribers() throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId))
+        ));
+        mBrokerService.publishPacket(mClientToken1, providerId, LAYER1, PAYLOAD);
+
+        verify(mClientLog1).logPacketSent(LAYER1, PAYLOAD.length);
+        verify(mClientLog1, times(2)).logPacketReceived(LAYER1, PAYLOAD.length);
+        verifyPacketReceived(mClientCallback1, providerId, LAYER1, PAYLOAD);
+        verifyPacketReceived(mClientCallback2, providerId, LAYER1, PAYLOAD);
+    }
+
+    @Test
+    public void testPublishPacket_MultipleLayerAndProviderSubscribers_DifferentProcesses()
+            throws Exception {
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mCallingAppUid = TEST_APP_UID2;
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId))
+        ));
+        mBrokerService.publishPacket(mClientToken1, providerId, LAYER1, PAYLOAD);
+
+        verify(mClientLog1).logPacketSent(LAYER1, PAYLOAD.length);
+        verify(mClientLog1).logPacketReceived(LAYER1, PAYLOAD.length);
+        verify(mClientLog2).logPacketReceived(LAYER1, PAYLOAD.length);
+        verifyPacketReceived(mClientCallback1, providerId, LAYER1, PAYLOAD);
+        verifyPacketReceived(mClientCallback2, providerId, LAYER1, PAYLOAD);
+    }
+
+    @Test
+    public void testPublishLargePacket_UnknownClient() throws Exception {
+        setupLargePacket();
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        assertThrows(
+                IllegalStateException.class,
+                () -> mBrokerService.publishLargePacket(
+                        new Binder(), providerId, LAYER1, mLargePacket));
+
+        verify(mLargePacket, atLeastOnce()).getSize();
+        verify(mLargePacket).close();
+        verifyNoMoreInteractions(mLargePacket);
+    }
+
+    @Test
+    public void testPublishLargePacket_UnknownOffering() throws Exception {
+        setupLargePacket();
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> mBrokerService.publishLargePacket(
+                        mClientToken1, providerId, LAYER1, mLargePacket));
+
+        verify(mLargePacket, atLeastOnce()).getSize();
+        verify(mLargePacket).close();
+        verifyNoMoreInteractions(mLargePacket);
+    }
+
+    @Test
+    public void testPublishLargePacket_UnknownOffering_LegacyClient() throws Exception {
+        setupLargePacket();
+        registerClient(mClientToken1, mClientCallback1, true);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.publishLargePacket(mClientToken1, 12345, LAYER1, mLargePacket);
+
+        verify(mClientLog1).logPacketSent(LAYER1, LARGE_PACKET_SIZE);
+        verify(mClientLog1).logPacketReceived(LAYER1, LARGE_PACKET_SIZE);
+        verifyLargePacketReceived(mClientCallback1, 12345, LAYER1, mLargePacket);
+
+        verify(mLargePacket, atLeastOnce()).getSize();
+        verify(mLargePacket).close();
+        verifyNoMoreInteractions(mLargePacket);
+    }
+
+    @Test
+    public void testPublishLargePacket_NoSubscribers() throws Exception {
+        setupLargePacket();
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.publishLargePacket(mClientToken1, providerId, LAYER1, mLargePacket);
+
+        verify(mClientLog1).logPacketSent(LAYER1, LARGE_PACKET_SIZE);
+        verify(mNoSubscribersLog).logPacketDropped(LAYER1, LARGE_PACKET_SIZE);
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+
+        verify(mLargePacket, atLeastOnce()).getSize();
+        verify(mLargePacket).close();
+        verifyNoMoreInteractions(mLargePacket);
+    }
+
+    @Test
+    public void testPublishLargePacket_MonitorSubscriber_Enabled() throws Exception {
+        setupLargePacket();
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setMonitoringEnabled(mClientToken1, true);
+        mBrokerService.publishLargePacket(mClientToken1, providerId, LAYER1, mLargePacket);
+
+        verify(mClientLog1).logPacketSent(LAYER1, LARGE_PACKET_SIZE);
+        verify(mClientLog1).logPacketReceived(LAYER1, LARGE_PACKET_SIZE);
+        verifyLargePacketReceived(mClientCallback1, providerId, LAYER1, mLargePacket);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+
+        verify(mLargePacket, atLeastOnce()).getSize();
+        verify(mLargePacket).close();
+        verifyNoMoreInteractions(mLargePacket);
+    }
+
+    @Test
+    public void testPublishLargePacket_MonitorSubscriber_EnabledAndDisabled() throws Exception {
+        setupLargePacket();
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setMonitoringEnabled(mClientToken1, true);
+        mBrokerService.setMonitoringEnabled(mClientToken1, false);
+        mBrokerService.publishLargePacket(mClientToken1, providerId, LAYER1, mLargePacket);
+
+        verify(mClientLog1).logPacketSent(LAYER1, LARGE_PACKET_SIZE);
+        verify(mNoSubscribersLog).logPacketDropped(LAYER1, LARGE_PACKET_SIZE);
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+
+        verify(mLargePacket, atLeastOnce()).getSize();
+        verify(mLargePacket).close();
+        verifyNoMoreInteractions(mLargePacket);
+    }
+
+    @Test
+    public void testPublishLargePacket_LayerSubscriber() throws Exception {
+        setupLargePacket();
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.publishLargePacket(mClientToken1, providerId, LAYER1, mLargePacket);
+
+        verify(mClientLog1).logPacketSent(LAYER1, LARGE_PACKET_SIZE);
+        verify(mClientLog1).logPacketReceived(LAYER1, LARGE_PACKET_SIZE);
+        verifyLargePacketReceived(mClientCallback1, providerId, LAYER1, mLargePacket);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+
+        verify(mLargePacket, atLeastOnce()).getSize();
+        verify(mLargePacket).close();
+        verifyNoMoreInteractions(mLargePacket);
+    }
+
+    @Test
+    public void testPublishLargePacket_LayerSubscriber_Unsubscribe() throws Exception {
+        setupLargePacket();
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken1, asList());
+        mBrokerService.publishLargePacket(mClientToken1, providerId, LAYER1, mLargePacket);
+
+        verify(mClientLog1).logPacketSent(LAYER1, LARGE_PACKET_SIZE);
+        verify(mNoSubscribersLog).logPacketDropped(LAYER1, LARGE_PACKET_SIZE);
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+
+        verify(mLargePacket, atLeastOnce()).getSize();
+        verify(mLargePacket).close();
+        verifyNoMoreInteractions(mLargePacket);
+    }
+
+    @Test
+    public void testPublishLargePacket_LayerSubscriber_DifferentLayer() throws Exception {
+        setupLargePacket();
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER2, emptySet())
+        ));
+        mBrokerService.publishLargePacket(mClientToken1, providerId, LAYER1, mLargePacket);
+
+        verify(mClientLog1).logPacketSent(LAYER1, LARGE_PACKET_SIZE);
+        verify(mNoSubscribersLog).logPacketDropped(LAYER1, LARGE_PACKET_SIZE);
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+
+        verify(mLargePacket, atLeastOnce()).getSize();
+        verify(mLargePacket).close();
+        verifyNoMoreInteractions(mLargePacket);
+    }
+
+    @Test
+    public void testPublishLargePacket_MultipleLayerSubscribers() throws Exception {
+        setupLargePacket();
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.publishLargePacket(mClientToken1, providerId, LAYER1, mLargePacket);
+
+        verify(mClientLog1).logPacketSent(LAYER1, LARGE_PACKET_SIZE);
+        verify(mClientLog1, times(2)).logPacketReceived(LAYER1, LARGE_PACKET_SIZE);
+        verifyLargePacketReceived(mClientCallback1, providerId, LAYER1, mLargePacket);
+        verifyLargePacketReceived(mClientCallback2, providerId, LAYER1, mLargePacket);
+
+        verify(mLargePacket, atLeastOnce()).getSize();
+        verify(mLargePacket).close();
+        verifyNoMoreInteractions(mLargePacket);
+    }
+
+    @Test
+    public void testPublishLargePacket_MultipleLayerSubscribers_DifferentProcesses()
+            throws Exception {
+        setupLargePacket();
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mCallingAppUid = TEST_APP_UID2;
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, emptySet())
+        ));
+        mBrokerService.publishLargePacket(mClientToken1, providerId, LAYER1, mLargePacket);
+
+        verify(mClientLog1).logPacketSent(LAYER1, LARGE_PACKET_SIZE);
+        verify(mClientLog1).logPacketReceived(LAYER1, LARGE_PACKET_SIZE);
+        verify(mClientLog2).logPacketReceived(LAYER1, LARGE_PACKET_SIZE);
+        verifyLargePacketReceived(mClientCallback1, providerId, LAYER1, mLargePacket);
+        verifyLargePacketReceived(mClientCallback2, providerId, LAYER1, mLargePacket);
+
+        verify(mLargePacket, atLeastOnce()).getSize();
+        verify(mLargePacket).close();
+        verifyNoMoreInteractions(mLargePacket);
+    }
+
+    @Test
+    public void testPublishLargePacket_LayerAndProviderSubscriber() throws Exception {
+        setupLargePacket();
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId))
+        ));
+        mBrokerService.publishLargePacket(mClientToken1, providerId, LAYER1, mLargePacket);
+
+        verify(mClientLog1).logPacketSent(LAYER1, LARGE_PACKET_SIZE);
+        verify(mClientLog1).logPacketReceived(LAYER1, LARGE_PACKET_SIZE);
+        verifyLargePacketReceived(mClientCallback1, providerId, LAYER1, mLargePacket);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+
+        verify(mLargePacket, atLeastOnce()).getSize();
+        verify(mLargePacket).close();
+        verifyNoMoreInteractions(mLargePacket);
+    }
+
+    @Test
+    public void testPublishLargePacket_LayerAndProviderSubscriber_Unsubscribe() throws Exception {
+        setupLargePacket();
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId))
+        ));
+        mBrokerService.setSubscriptions(mClientToken1, asList());
+        mBrokerService.publishLargePacket(mClientToken1, providerId, LAYER1, mLargePacket);
+
+        verify(mClientLog1).logPacketSent(LAYER1, LARGE_PACKET_SIZE);
+        verify(mNoSubscribersLog).logPacketDropped(LAYER1, LARGE_PACKET_SIZE);
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+
+        verify(mLargePacket, atLeastOnce()).getSize();
+        verify(mLargePacket).close();
+        verifyNoMoreInteractions(mLargePacket);
+    }
+
+    @Test
+    public void testPublishLargePacket_LayerAndProviderSubscriber_DifferentProvider()
+            throws Exception {
+        setupLargePacket();
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+        int providerId2 = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO2);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId2))
+        ));
+        mBrokerService.publishLargePacket(mClientToken1, providerId, LAYER1, mLargePacket);
+
+        verify(mClientLog1).logPacketSent(LAYER1, LARGE_PACKET_SIZE);
+        verify(mNoSubscribersLog).logPacketDropped(LAYER1, LARGE_PACKET_SIZE);
+        verifyNoPacketsReceived(mClientCallback1, providerId, LAYER1);
+        verifyNoPacketsReceived(mClientCallback2, providerId, LAYER1);
+
+        verify(mLargePacket, atLeastOnce()).getSize();
+        verify(mLargePacket).close();
+        verifyNoMoreInteractions(mLargePacket);
+    }
+
+    @Test
+    public void testPublishLargePacket_MultipleLayerAndProviderSubscribers() throws Exception {
+        setupLargePacket();
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId))
+        ));
+        mBrokerService.publishLargePacket(mClientToken1, providerId, LAYER1, mLargePacket);
+
+        verify(mClientLog1).logPacketSent(LAYER1, LARGE_PACKET_SIZE);
+        verify(mClientLog1, times(2)).logPacketReceived(LAYER1, LARGE_PACKET_SIZE);
+        verifyLargePacketReceived(mClientCallback1, providerId, LAYER1, mLargePacket);
+        verifyLargePacketReceived(mClientCallback2, providerId, LAYER1, mLargePacket);
+
+        verify(mLargePacket, atLeastOnce()).getSize();
+        verify(mLargePacket).close();
+        verifyNoMoreInteractions(mLargePacket);
+    }
+
+    @Test
+    public void testPublishLargePacket_MultipleLayerAndProviderSubscribers_DifferentProcesses()
+            throws Exception {
+        setupLargePacket();
+        registerClient(mClientToken1, mClientCallback1);
+        int providerId = mBrokerService.registerProvider(mClientToken1, PROVIDER_INFO1);
+
+        mBrokerService.setProviderOfferings(mClientToken1, providerId, asList(
+                new VmsLayerDependency(LAYER1)
+        ));
+        mCallingAppUid = TEST_APP_UID2;
+        registerClient(mClientToken2, mClientCallback2);
+
+        mBrokerService.setSubscriptions(mClientToken1, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId))
+        ));
+        mBrokerService.setSubscriptions(mClientToken2, asList(
+                new VmsAssociatedLayer(LAYER1, asSet(providerId))
+        ));
+        mBrokerService.publishLargePacket(mClientToken1, providerId, LAYER1, mLargePacket);
+
+        verify(mClientLog1).logPacketSent(LAYER1, LARGE_PACKET_SIZE);
+        verify(mClientLog1).logPacketReceived(LAYER1, LARGE_PACKET_SIZE);
+        verify(mClientLog2).logPacketReceived(LAYER1, LARGE_PACKET_SIZE);
+        verifyLargePacketReceived(mClientCallback1, providerId, LAYER1, mLargePacket);
+        verifyLargePacketReceived(mClientCallback2, providerId, LAYER1, mLargePacket);
+
+        verify(mLargePacket, atLeastOnce()).getSize();
+        verify(mLargePacket).close();
+        verifyNoMoreInteractions(mLargePacket);
+    }
+
+    private void registerClient(IBinder token, IVmsClientCallback callback) {
+        registerClient(token, callback, false);
+    }
+
+    private VmsRegistrationInfo registerClient(IBinder token, IVmsClientCallback callback,
+            boolean legacyClient) {
+        VmsRegistrationInfo registrationInfo =
+                mBrokerService.registerClient(token, callback, legacyClient);
+
+        IBinder callbackBinder = callback.asBinder();
+        try {
+            if (!mDeathRecipients.containsKey(token)) {
+                ArgumentCaptor<IBinder.DeathRecipient> deathRecipientCaptor =
+                        ArgumentCaptor.forClass(IBinder.DeathRecipient.class);
+                verify(callbackBinder).linkToDeath(deathRecipientCaptor.capture(), eq(0));
+                mDeathRecipients.put(token,
+                        Pair.create(callbackBinder, deathRecipientCaptor.getValue()));
+            } else {
+                verify(callbackBinder, never()).linkToDeath(any(), anyInt());
+            }
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
+        }
+
+        return registrationInfo;
+    }
+
+    private void unregisterClient(IBinder token) {
+        mBrokerService.unregisterClient(token);
+
+        Pair<IBinder, IBinder.DeathRecipient> deathRecipientPair = mDeathRecipients.get(token);
+        assertThat(deathRecipientPair).isNotNull();
+        verify(deathRecipientPair.first).unlinkToDeath(same(deathRecipientPair.second), eq(0));
+    }
+
+    private void disconnectClient(IBinder token) {
+        Pair<IBinder, IBinder.DeathRecipient> deathRecipientPair = mDeathRecipients.get(token);
+        assertThat(deathRecipientPair).isNotNull();
+
+        deathRecipientPair.second.binderDied();
+        verify(deathRecipientPair.first).unlinkToDeath(same(deathRecipientPair.second), eq(0));
+    }
+
+    private static void verifyLayerAvailability(
+            IVmsClientCallback callback,
+            VmsAvailableLayers availableLayers) throws RemoteException {
+        ArgumentCaptor<VmsAvailableLayers> availableLayersCaptor =
+                ArgumentCaptor.forClass(VmsAvailableLayers.class);
+        verify(callback, times(availableLayers.getSequenceNumber()))
+                .onLayerAvailabilityChanged(availableLayersCaptor.capture());
+        assertThat(availableLayersCaptor.getValue()).isEqualTo(availableLayers);
+    }
+
+    private static void verifySubscriptionState(
+            IVmsClientCallback callback,
+            VmsSubscriptionState subscriptionState) throws RemoteException {
+        ArgumentCaptor<VmsSubscriptionState> subscriptionStateCaptor =
+                ArgumentCaptor.forClass(VmsSubscriptionState.class);
+        verify(callback, times(subscriptionState.getSequenceNumber()))
+                .onSubscriptionStateChanged(subscriptionStateCaptor.capture());
+        assertThat(subscriptionStateCaptor.getValue()).isEqualTo(subscriptionState);
+    }
+
+    private static void verifyNoPacketsReceived(
+            IVmsClientCallback callback,
+            int providerId, VmsLayer layer) throws RemoteException {
+        verify(callback, never()).onPacketReceived(eq(providerId), eq(layer), any());
+        verify(callback, never()).onLargePacketReceived(eq(providerId), eq(layer), any());
+    }
+
+    private static void verifyPacketReceived(
+            IVmsClientCallback callback,
+            int providerId, VmsLayer layer, byte[] payload) throws RemoteException {
+        verify(callback).onPacketReceived(providerId, layer, payload);
+    }
+
+    private static void verifyLargePacketReceived(
+            IVmsClientCallback callback,
+            int providerId, VmsLayer layer, SharedMemory packet) throws RemoteException {
+        verify(callback).onLargePacketReceived(providerId, layer, packet);
+    }
+
+    private static <T> Set<T> asSet(T... values) {
+        return new HashSet<T>(Arrays.asList(values));
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/vms/VmsClientManagerTest.java b/tests/carservice_unit_test/src/com/android/car/vms/VmsClientManagerTest.java
deleted file mode 100644
index e1c9d9a..0000000
--- a/tests/carservice_unit_test/src/com/android/car/vms/VmsClientManagerTest.java
+++ /dev/null
@@ -1,1116 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.vms;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.same;
-import static org.mockito.Mockito.atLeast;
-import static org.mockito.Mockito.atMost;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-import android.car.Car;
-import android.car.vms.IVmsPublisherClient;
-import android.car.vms.IVmsPublisherService;
-import android.car.vms.IVmsSubscriberClient;
-import android.car.vms.VmsAvailableLayers;
-import android.car.vms.VmsLayer;
-import android.car.vms.VmsSubscriptionState;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
-import android.content.res.Resources;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Process;
-import android.os.UserHandle;
-import android.os.UserManager;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.car.VmsPublisherService;
-import com.android.car.hal.VmsHalService;
-import com.android.car.stats.CarStatsService;
-import com.android.car.stats.VmsClientLogger;
-import com.android.car.stats.VmsClientLogger.ConnectionState;
-import com.android.car.user.CarUserService;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-@SmallTest
-public class VmsClientManagerTest {
-    private static final String SYSTEM_CLIENT = "com.google.android.apps.vms.test/.VmsSystemClient";
-    private static final ComponentName SYSTEM_CLIENT_COMPONENT =
-            ComponentName.unflattenFromString(SYSTEM_CLIENT);
-    private static final String SYSTEM_CLIENT_NAME =
-            "com.google.android.apps.vms.test/com.google.android.apps.vms.test.VmsSystemClient U=0";
-
-    private static final String USER_CLIENT = "com.google.android.apps.vms.test/.VmsUserClient";
-    private static final ComponentName USER_CLIENT_COMPONENT =
-            ComponentName.unflattenFromString(USER_CLIENT);
-    private static final int USER_ID = 10;
-    private static final String USER_CLIENT_NAME =
-            "com.google.android.apps.vms.test/com.google.android.apps.vms.test.VmsUserClient U=10";
-    private static final int USER_ID_U11 = 11;
-
-    private static final String TEST_PACKAGE = "test.package1";
-    private static final String HAL_CLIENT_NAME = "HalClient";
-    private static final String UNKNOWN_PACKAGE = "UnknownPackage";
-
-    private static final int TEST_APP_ID = 12345;
-    private static final int TEST_SYSTEM_UID = 12345;
-    private static final int TEST_USER_UID = 1012345;
-    private static final int TEST_USER_UID_U11 = 1112345;
-
-    private static final long MILLIS_BEFORE_REBIND = 100;
-
-    @Rule
-    public MockitoRule mMockitoRule = MockitoJUnit.rule();
-    @Mock
-    private Context mContext;
-    @Mock
-    private PackageManager mPackageManager;
-    @Mock
-    private Resources mResources;
-    @Mock
-    private CarStatsService mStatsService;
-    @Mock
-    private UserManager mUserManager;
-    @Mock
-    private CarUserService mUserService;
-
-    @Mock
-    private VmsBrokerService mBrokerService;
-
-    @Mock
-    private VmsHalService mHal;
-
-    @Mock
-    private Handler mHandler;
-
-    @Captor
-    private ArgumentCaptor<Runnable> mRebindCaptor;
-
-    @Mock
-    private VmsPublisherService mPublisherService;
-
-    @Mock
-    private IVmsSubscriberClient mSubscriberClient1;
-    @Mock
-    private Binder mSubscriberBinder1;
-
-    @Captor
-    private ArgumentCaptor<IBinder.DeathRecipient> mDeathRecipient;
-
-    @Mock
-    private IVmsSubscriberClient mSubscriberClient2;
-    @Mock
-    private Binder mSubscriberBinder2;
-
-    @Captor
-    private ArgumentCaptor<ServiceConnection> mConnectionCaptor;
-
-    @Mock
-    private VmsClientLogger mSystemClientLog;
-    @Mock
-    private VmsClientLogger mUserClientLog;
-    @Mock
-    private VmsClientLogger mUserClientLog2;
-    @Mock
-    private VmsClientLogger mHalClientLog;
-
-    private VmsClientManager mClientManager;
-
-    private int mForegroundUserId;
-    private int mCallingAppUid;
-
-    private ServiceInfo mSystemServiceInfo;
-    private ServiceInfo mUserServiceInfo;
-
-    @Before
-    public void setUp() throws Exception {
-        resetContext();
-        mSystemServiceInfo = new ServiceInfo();
-        mSystemServiceInfo.permission = Car.PERMISSION_BIND_VMS_CLIENT;
-        mSystemServiceInfo.applicationInfo = new ApplicationInfo();
-        mSystemServiceInfo.applicationInfo.uid = TEST_APP_ID;
-        when(mPackageManager.getServiceInfo(eq(SYSTEM_CLIENT_COMPONENT), anyInt()))
-                .thenReturn(mSystemServiceInfo);
-        when(mStatsService.getVmsClientLogger(TEST_SYSTEM_UID)).thenReturn(mSystemClientLog);
-
-        mUserServiceInfo = new ServiceInfo();
-        mUserServiceInfo.permission = Car.PERMISSION_BIND_VMS_CLIENT;
-        mUserServiceInfo.applicationInfo = new ApplicationInfo();
-        mUserServiceInfo.applicationInfo.uid = TEST_APP_ID;
-        when(mPackageManager.getServiceInfo(eq(USER_CLIENT_COMPONENT), anyInt()))
-                .thenReturn(mUserServiceInfo);
-        when(mStatsService.getVmsClientLogger(TEST_USER_UID)).thenReturn(mUserClientLog);
-        when(mStatsService.getVmsClientLogger(TEST_USER_UID_U11)).thenReturn(mUserClientLog2);
-
-        when(mStatsService.getVmsClientLogger(Process.myUid())).thenReturn(mHalClientLog);
-
-        when(mResources.getInteger(
-                com.android.car.R.integer.millisecondsBeforeRebindToVmsPublisher)).thenReturn(
-                (int) MILLIS_BEFORE_REBIND);
-        when(mResources.getStringArray(
-                com.android.car.R.array.vmsPublisherSystemClients)).thenReturn(
-                new String[]{ SYSTEM_CLIENT });
-        when(mResources.getStringArray(
-                com.android.car.R.array.vmsPublisherUserClients)).thenReturn(
-                new String[]{ USER_CLIENT });
-
-        when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
-
-        mClientManager = new VmsClientManager(mContext, mStatsService, mUserService,
-                mBrokerService, mHal, mHandler, () -> mCallingAppUid);
-        verify(mHal).setClientManager(mClientManager);
-        mClientManager.setPublisherService(mPublisherService);
-
-        notifyUserSwitched(USER_ID, false);
-        mCallingAppUid = UserHandle.getUid(USER_ID, 0);
-
-        when(mSubscriberClient1.asBinder()).thenReturn(mSubscriberBinder1);
-        when(mSubscriberClient2.asBinder()).thenReturn(mSubscriberBinder2);
-
-        when(mPackageManager.getNameForUid(mCallingAppUid)).thenReturn(TEST_PACKAGE);
-    }
-
-    @After
-    public void tearDown() {
-        verify(mContext, atLeast(0)).getSystemService(eq(Context.USER_SERVICE));
-        verify(mContext, atLeast(0)).getResources();
-        verify(mContext, atLeast(0)).getPackageManager();
-        verifyNoMoreInteractions(mContext, mBrokerService, mHal, mPublisherService, mHandler);
-        verifyNoMoreInteractions(mSystemClientLog, mUserClientLog, mUserClientLog2, mHalClientLog);
-    }
-
-    @Test
-    public void testInit() {
-        mClientManager.init();
-
-        // Verify registration of system user unlock listener
-        verify(mUserService).runOnUser0Unlock(mClientManager.mSystemUserUnlockedListener);
-        // Verify user callback is added
-        verify(mUserService).addUserCallback(eq(mClientManager.mUserCallback));
-    }
-
-    @Test
-    public void testRelease() {
-        mClientManager.release();
-
-        // Verify user switch receiver is unregistered
-        verify(mUserService).removeUserCallback(mClientManager.mUserCallback);
-    }
-
-    @Test
-    public void testSystemUserUnlocked() {
-        notifySystemUserUnlocked();
-        notifySystemUserUnlocked();
-
-        // Multiple events should only trigger a single bind, when successful
-        verifySystemBind(1);
-    }
-
-    @Test
-    public void testSystemUserUnlocked_ClientNotFound() throws Exception {
-        when(mPackageManager.getServiceInfo(eq(SYSTEM_CLIENT_COMPONENT), anyInt()))
-                .thenThrow(new PackageManager.NameNotFoundException());
-        notifySystemUserUnlocked();
-
-        // Process will not be bound
-        verifySystemBind(0);
-    }
-
-    @Test
-    public void testSystemUserUnlocked_WrongPermission() throws Exception {
-        mSystemServiceInfo.permission = Car.PERMISSION_VMS_PUBLISHER;
-        notifySystemUserUnlocked();
-
-        // Process will not be bound
-        verifySystemBind(0);
-        verify(mSystemClientLog).logConnectionState(ConnectionState.CONNECTION_ERROR);
-    }
-
-    @Test
-    public void testSystemUserUnlocked_BindFailed() {
-        when(mContext.bindServiceAsUser(any(), any(), anyInt(), any(), any())).thenReturn(false);
-        notifySystemUserUnlocked();
-        notifySystemUserUnlocked();
-
-        // Failure state will trigger another attempt on event
-        verifySystemBind(2);
-        verify(mSystemClientLog, times(2)).logConnectionState(ConnectionState.CONNECTION_ERROR);
-    }
-
-    @Test
-    public void testSystemUserUnlocked_BindException() {
-        when(mContext.bindServiceAsUser(any(), any(), anyInt(), any(), any())).thenThrow(
-                new SecurityException());
-        notifySystemUserUnlocked();
-        notifySystemUserUnlocked();
-
-        // Failure state will trigger another attempt on event
-        verifySystemBind(2);
-        verify(mSystemClientLog, times(2)).logConnectionState(ConnectionState.CONNECTION_ERROR);
-    }
-
-    @Test
-    public void testUserUnlocked() {
-        notifyUserUnlocked(USER_ID, true);
-        notifyUserUnlocked(USER_ID, true);
-
-        // Multiple events should only trigger a single bind, when successful
-        verifyUserBind(1);
-    }
-
-    @Test
-    public void testUserUnlocked_ForegroundUserNotUnlocked() {
-        notifyUserUnlocked(USER_ID, false);
-
-        // Process will not be bound
-        verifyUserBind(0);
-    }
-
-    @Test
-    public void testUserUnlocked_OtherUserUnlocked() {
-        notifyUserUnlocked(USER_ID_U11, true);
-
-        // Process will not be bound
-        verifyUserBind(0);
-    }
-
-    @Test
-    public void testUserUnlocked_ClientNotFound() throws Exception {
-        when(mPackageManager.getServiceInfo(eq(USER_CLIENT_COMPONENT), anyInt()))
-                .thenThrow(new PackageManager.NameNotFoundException());
-        notifyUserUnlocked(USER_ID, true);
-
-        // Process will not be bound
-        verifyUserBind(0);
-    }
-
-    @Test
-    public void testUserUnlocked_WrongPermission() throws Exception {
-        mUserServiceInfo.permission = Car.PERMISSION_VMS_PUBLISHER;
-        notifyUserUnlocked(USER_ID, true);
-
-        // Process will not be bound
-        verifyUserBind(0);
-        verify(mUserClientLog).logConnectionState(ConnectionState.CONNECTION_ERROR);
-    }
-
-    @Test
-    public void testUserUnlocked_BindFailed() {
-        when(mContext.bindServiceAsUser(any(), any(), anyInt(), any(), any()))
-                .thenReturn(false);
-        notifyUserUnlocked(USER_ID, true);
-        notifyUserUnlocked(USER_ID, true);
-
-        // Failure state will trigger another attempt
-        verifyUserBind(2);
-        verify(mUserClientLog, times(2)).logConnectionState(ConnectionState.CONNECTION_ERROR);
-    }
-
-    @Test
-    public void testUserUnlocked_UserBindFailed() {
-        when(mContext.bindServiceAsUser(any(), any(), anyInt(), any(), eq(UserHandle.of(USER_ID))))
-                .thenReturn(false);
-        notifyUserUnlocked(USER_ID, true);
-        notifyUserUnlocked(USER_ID, true);
-
-        // Failure state will trigger another attempt
-        verifyUserBind(2);
-        verify(mUserClientLog, times(2)).logConnectionState(ConnectionState.CONNECTION_ERROR);
-    }
-
-    @Test
-    public void testUserUnlocked_BindException() {
-        when(mContext.bindServiceAsUser(any(), any(), anyInt(), any(), any()))
-                .thenThrow(new SecurityException());
-        notifyUserUnlocked(USER_ID, true);
-        notifyUserUnlocked(USER_ID, true);
-
-        // Failure state will trigger another attempt
-        verifyUserBind(2);
-        verify(mUserClientLog, times(2)).logConnectionState(ConnectionState.CONNECTION_ERROR);
-    }
-
-    @Test
-    public void testUserUnlocked_SystemRebind() {
-        when(mContext.bindServiceAsUser(any(), any(), anyInt(), any(), eq(UserHandle.SYSTEM)))
-                .thenReturn(false);
-        notifySystemUserUnlocked();
-        verifySystemBind(1);
-        verify(mSystemClientLog).logConnectionState(ConnectionState.CONNECTION_ERROR);
-        resetContext();
-
-        when(mContext.bindServiceAsUser(any(), any(), anyInt(), any(), eq(UserHandle.SYSTEM)))
-                .thenReturn(true);
-        notifyUserUnlocked(USER_ID, true);
-        verifySystemBind(1);
-        verifyUserBind(1);
-    }
-
-    @Test
-    public void testUserUnlocked_SystemRebind_BindFailed() {
-        when(mContext.bindServiceAsUser(any(), any(), anyInt(), any(), eq(UserHandle.SYSTEM)))
-                .thenReturn(false);
-        notifySystemUserUnlocked();
-        verifySystemBind(1);
-        verify(mSystemClientLog).logConnectionState(ConnectionState.CONNECTION_ERROR);
-        resetContext();
-
-        when(mContext.bindServiceAsUser(any(), any(), anyInt(), any(), eq(UserHandle.SYSTEM)))
-                .thenReturn(false);
-        notifyUserUnlocked(USER_ID, true);
-        notifyUserUnlocked(USER_ID, true);
-
-        verifySystemBind(2); // Failure state will trigger another attempt
-        verify(mSystemClientLog, times(2)).logConnectionState(ConnectionState.CONNECTION_ERROR);
-        verifyUserBind(1);
-    }
-
-    @Test
-    public void testUserUnlocked_SystemRebind_BindException() {
-        when(mContext.bindServiceAsUser(any(), any(), anyInt(), any(), eq(UserHandle.SYSTEM)))
-                .thenThrow(new SecurityException());
-        notifySystemUserUnlocked();
-        verifySystemBind(1);
-        verify(mSystemClientLog).logConnectionState(ConnectionState.CONNECTION_ERROR);
-        resetContext();
-
-        when(mContext.bindServiceAsUser(any(), any(), anyInt(), any(), eq(UserHandle.SYSTEM)))
-                .thenThrow(new SecurityException());
-        notifyUserUnlocked(USER_ID, true);
-        notifyUserUnlocked(USER_ID, true);
-
-        verifySystemBind(2); // Failure state will trigger another attempt
-        verify(mSystemClientLog, times(2)).logConnectionState(ConnectionState.CONNECTION_ERROR);
-        verifyUserBind(1);
-    }
-
-    @Test
-    public void testUserSwitched() {
-        notifyUserSwitched(USER_ID, true);
-        notifyUserSwitched(USER_ID, true);
-
-        // Multiple events should only trigger a single bind, when successful
-        verifyUserBind(1);
-    }
-
-    @Test
-    public void testUserSwitchedAndUnlocked() {
-        notifyUserSwitched(USER_ID, true);
-        notifyUserUnlocked(USER_ID, true);
-
-        // Multiple events should only trigger a single bind, when successful
-        verifyUserBind(1);
-    }
-
-    @Test
-    public void testUserSwitched_ForegroundUserNotUnlocked() {
-        notifyUserSwitched(USER_ID, false);
-
-        // Process will not be bound
-        verifyUserBind(0);
-    }
-
-    @Test
-    public void testUserSwitchedToSystemUser() {
-        notifyUserSwitched(UserHandle.USER_SYSTEM, true);
-
-        // Neither user nor system processes will be bound for system user intent
-        verifySystemBind(0);
-        verifyUserBind(0);
-    }
-
-    @Test
-    public void testOnSystemServiceConnected() {
-        IBinder binder = bindSystemClient();
-        verifyOnClientConnected(SYSTEM_CLIENT_NAME, binder);
-        verify(mSystemClientLog).logConnectionState(ConnectionState.CONNECTED);
-    }
-
-    private IBinder bindSystemClient() {
-        notifySystemUserUnlocked();
-        verifySystemBind(1);
-        resetContext();
-
-        IBinder binder = createPublisherBinder();
-        ServiceConnection connection = mConnectionCaptor.getValue();
-        connection.onServiceConnected(null, binder);
-        return binder;
-    }
-
-    @Test
-    public void testOnUserServiceConnected() {
-        IBinder binder = bindUserClient();
-        verifyOnClientConnected(USER_CLIENT_NAME, binder);
-        verify(mUserClientLog).logConnectionState(ConnectionState.CONNECTED);
-    }
-
-    private IBinder bindUserClient() {
-        notifyUserUnlocked(USER_ID, true);
-        verifyUserBind(1);
-        resetContext();
-
-        IBinder binder = createPublisherBinder();
-        ServiceConnection connection = mConnectionCaptor.getValue();
-        connection.onServiceConnected(null, binder);
-        return binder;
-    }
-
-    @Test
-    public void testOnSystemServiceDisconnected() throws Exception {
-        notifySystemUserUnlocked();
-        verifySystemBind(1);
-        resetContext();
-
-        ServiceConnection connection = mConnectionCaptor.getValue();
-        connection.onServiceConnected(null, createPublisherBinder());
-        verify(mSystemClientLog).logConnectionState(ConnectionState.CONNECTED);
-        reset(mPublisherService);
-
-        connection.onServiceDisconnected(null);
-        verify(mPublisherService).onClientDisconnected(eq(SYSTEM_CLIENT_NAME));
-        verify(mSystemClientLog).logConnectionState(ConnectionState.DISCONNECTED);
-
-        verifyAndRunRebindTask();
-        verify(mContext).unbindService(connection);
-        verifySystemBind(1);
-    }
-
-    @Test
-    public void testOnSystemServiceDisconnected_ServiceReboundByAndroid() throws Exception {
-        notifySystemUserUnlocked();
-        verifySystemBind(1);
-        resetContext();
-
-        ServiceConnection connection = mConnectionCaptor.getValue();
-        IBinder binder = createPublisherBinder();
-        connection.onServiceConnected(null, binder);
-        verifyOnClientConnected(SYSTEM_CLIENT_NAME, binder);
-        verify(mSystemClientLog).logConnectionState(ConnectionState.CONNECTED);
-        reset(mPublisherService, mSystemClientLog);
-
-        connection.onServiceDisconnected(null);
-        verify(mPublisherService).onClientDisconnected(eq(SYSTEM_CLIENT_NAME));
-        verify(mSystemClientLog).logConnectionState(ConnectionState.DISCONNECTED);
-
-        binder = createPublisherBinder();
-        connection.onServiceConnected(null, binder);
-        verifyOnClientConnected(SYSTEM_CLIENT_NAME, binder);
-        verify(mSystemClientLog).logConnectionState(ConnectionState.CONNECTED);
-
-        verifyAndRunRebindTask();
-        // No more interactions (verified by tearDown)
-    }
-
-
-    @Test
-    public void testOnSystemServiceBindingDied() throws Exception {
-        notifySystemUserUnlocked();
-        verifySystemBind(1);
-        resetContext();
-
-        ServiceConnection connection = mConnectionCaptor.getValue();
-        connection.onServiceConnected(null, createPublisherBinder());
-        verify(mSystemClientLog).logConnectionState(ConnectionState.CONNECTED);
-        reset(mPublisherService);
-
-        connection.onBindingDied(null);
-        verify(mPublisherService).onClientDisconnected(eq(SYSTEM_CLIENT_NAME));
-        verify(mSystemClientLog).logConnectionState(ConnectionState.DISCONNECTED);
-
-        verifyAndRunRebindTask();
-        verify(mContext).unbindService(connection);
-        verifySystemBind(1);
-    }
-
-    @Test
-    public void testOnSystemServiceBindingDied_ServiceNotConnected() throws Exception {
-        notifySystemUserUnlocked();
-        verifySystemBind(1);
-        resetContext();
-
-        ServiceConnection connection = mConnectionCaptor.getValue();
-        connection.onBindingDied(null);
-
-        verifyZeroInteractions(mPublisherService);
-
-        verifyAndRunRebindTask();
-        verify(mContext).unbindService(connection);
-        verifySystemBind(1);
-    }
-
-    @Test
-    public void testOnUserServiceDisconnected() throws Exception {
-        notifyUserUnlocked(USER_ID, true);
-        verifyUserBind(1);
-        resetContext();
-
-        ServiceConnection connection = mConnectionCaptor.getValue();
-        connection.onServiceConnected(null, createPublisherBinder());
-        verify(mUserClientLog).logConnectionState(ConnectionState.CONNECTED);
-        reset(mPublisherService);
-
-        connection.onServiceDisconnected(null);
-        verify(mPublisherService).onClientDisconnected(eq(USER_CLIENT_NAME));
-        verify(mUserClientLog).logConnectionState(ConnectionState.DISCONNECTED);
-
-        verifyAndRunRebindTask();
-        verify(mContext).unbindService(connection);
-        verifyUserBind(1);
-    }
-
-    @Test
-    public void testOnUserServiceDisconnected_ServiceReboundByAndroid() throws Exception {
-        notifyUserUnlocked(USER_ID, true);
-        verifyUserBind(1);
-        resetContext();
-
-        ServiceConnection connection = mConnectionCaptor.getValue();
-        IBinder binder = createPublisherBinder();
-        connection.onServiceConnected(null, binder);
-        verifyOnClientConnected(USER_CLIENT_NAME, binder);
-        verify(mUserClientLog).logConnectionState(ConnectionState.CONNECTED);
-        reset(mPublisherService, mUserClientLog);
-
-        connection.onServiceDisconnected(null);
-        verify(mPublisherService).onClientDisconnected(eq(USER_CLIENT_NAME));
-        verify(mUserClientLog).logConnectionState(ConnectionState.DISCONNECTED);
-
-        binder = createPublisherBinder();
-        connection.onServiceConnected(null, binder);
-        verifyOnClientConnected(USER_CLIENT_NAME, binder);
-        verify(mUserClientLog).logConnectionState(ConnectionState.CONNECTED);
-
-        verifyAndRunRebindTask();
-        // No more interactions (verified by tearDown)
-    }
-
-    @Test
-    public void testOnUserServiceBindingDied() throws Exception {
-        notifyUserUnlocked(USER_ID, true);
-        verifyUserBind(1);
-        resetContext();
-
-        ServiceConnection connection = mConnectionCaptor.getValue();
-        connection.onServiceConnected(null, createPublisherBinder());
-        verify(mUserClientLog).logConnectionState(ConnectionState.CONNECTED);
-        reset(mPublisherService);
-
-        connection.onBindingDied(null);
-        verify(mPublisherService).onClientDisconnected(eq(USER_CLIENT_NAME));
-        verify(mUserClientLog).logConnectionState(ConnectionState.DISCONNECTED);
-
-        verifyAndRunRebindTask();
-        verify(mContext).unbindService(connection);
-        verifyUserBind(1);
-    }
-
-    @Test
-    public void testOnUserServiceBindingDied_ServiceNotConnected() throws Exception {
-        notifyUserUnlocked(USER_ID, true);
-        verifyUserBind(1);
-        resetContext();
-
-        ServiceConnection connection = mConnectionCaptor.getValue();
-        connection.onBindingDied(null);
-
-        verifyZeroInteractions(mPublisherService);
-
-        verifyAndRunRebindTask();
-        verify(mContext).unbindService(connection);
-        verifyUserBind(1);
-    }
-
-    @Test
-    public void testOnUserSwitched_UserChange() {
-        notifyUserUnlocked(USER_ID, true);
-        verifyUserBind(1);
-        resetContext();
-
-        ServiceConnection connection = mConnectionCaptor.getValue();
-        connection.onServiceConnected(null, createPublisherBinder());
-        verify(mUserClientLog).logConnectionState(ConnectionState.CONNECTED);
-        reset(mPublisherService);
-
-        notifyUserSwitched(USER_ID_U11, true);
-
-        verify(mContext).unbindService(connection);
-        verify(mPublisherService).onClientDisconnected(eq(USER_CLIENT_NAME));
-        verify(mUserClientLog).logConnectionState(ConnectionState.TERMINATED);
-        verifyUserBind(1);
-    }
-
-    @Test
-    public void testOnUserSwitched_UserChange_ForegroundUserNotUnlocked() {
-        notifyUserUnlocked(USER_ID, true);
-        verifyUserBind(1);
-        ServiceConnection connection = mConnectionCaptor.getValue();
-        connection.onServiceConnected(null, createPublisherBinder());
-        resetContext();
-        reset(mPublisherService);
-
-        notifyUserSwitched(USER_ID_U11, false);
-
-        verify(mContext).unbindService(connection);
-        verify(mPublisherService).onClientDisconnected(eq(USER_CLIENT_NAME));
-        verify(mUserClientLog).logConnectionState(ConnectionState.TERMINATED);
-        verifyUserBind(0);
-    }
-
-    @Test
-    public void testOnUserSwitched_UserChange_ToSystemUser() {
-        notifyUserUnlocked(USER_ID, true);
-        verifyUserBind(1);
-        ServiceConnection connection = mConnectionCaptor.getValue();
-        connection.onServiceConnected(null, createPublisherBinder());
-        resetContext();
-        reset(mPublisherService);
-
-        notifyUserSwitched(UserHandle.USER_SYSTEM, true);
-
-        verify(mContext).unbindService(connection);
-        verify(mPublisherService).onClientDisconnected(eq(USER_CLIENT_NAME));
-        verify(mUserClientLog).logConnectionState(ConnectionState.TERMINATED);
-        verifyUserBind(0);
-    }
-
-    @Test
-    public void testOnUserSwitched_UserChange_ServiceNotConnected() {
-        notifyUserUnlocked(USER_ID, true);
-        verifyUserBind(1);
-        ServiceConnection connection = mConnectionCaptor.getValue();
-        resetContext();
-
-        notifyUserSwitched(USER_ID_U11, true);
-
-        verify(mContext).unbindService(connection);
-        verifyUserBind(1);
-    }
-
-    @Test
-    public void testOnUserSwitched_UserChange_ServiceNotConnected_ForegroundUserNotUnlocked() {
-        notifyUserUnlocked(USER_ID, true);
-        verifyUserBind(1);
-        ServiceConnection connection = mConnectionCaptor.getValue();
-        resetContext();
-
-        notifyUserSwitched(USER_ID_U11, false);
-
-        verify(mContext).unbindService(connection);
-        verifyUserBind(0);
-    }
-
-    @Test
-    public void testOnUserUnlocked_UserChange() {
-        notifyUserUnlocked(USER_ID, true);
-        verifyUserBind(1);
-        ServiceConnection connection = mConnectionCaptor.getValue();
-        connection.onServiceConnected(null, createPublisherBinder());
-        resetContext();
-        reset(mPublisherService);
-
-        notifyUserSwitched(USER_ID_U11, false);
-        notifyUserUnlocked(USER_ID_U11, true);
-
-        verify(mContext).unbindService(connection);
-        verify(mPublisherService).onClientDisconnected(eq(USER_CLIENT_NAME));
-        verify(mUserClientLog).logConnectionState(ConnectionState.TERMINATED);
-        verifyUserBind(1);
-    }
-
-    @Test
-    public void testOnUserUnlocked_UserChange_ToSystemUser() {
-        notifySystemUserUnlocked();
-        verifySystemBind(1);
-        notifyUserUnlocked(USER_ID, true);
-        verifyUserBind(1);
-        ServiceConnection connection = mConnectionCaptor.getValue();
-        connection.onServiceConnected(null, createPublisherBinder());
-        resetContext();
-        reset(mPublisherService);
-
-        notifyUserSwitched(USER_ID_U11, false);
-        notifyUserUnlocked(UserHandle.USER_SYSTEM, true);
-
-        verify(mContext).unbindService(connection);
-        verify(mPublisherService).onClientDisconnected(eq(USER_CLIENT_NAME));
-        verify(mUserClientLog).logConnectionState(ConnectionState.TERMINATED);
-        // User processes will not be bound for system user
-        verifyUserBind(0);
-    }
-
-    @Test
-    public void testOnUserUnlocked_UserChange_ServiceNotConnected() {
-        notifyUserUnlocked(USER_ID, true);
-        verifyUserBind(1);
-        ServiceConnection connection = mConnectionCaptor.getValue();
-        resetContext();
-
-        notifyUserSwitched(USER_ID_U11, false);
-        notifyUserUnlocked(USER_ID_U11, true);
-
-        verify(mContext).unbindService(connection);
-        verifyUserBind(1);
-    }
-
-    @Test
-    public void testAddSubscriber() {
-        mClientManager.addSubscriber(mSubscriberClient1);
-        assertEquals(TEST_PACKAGE, mClientManager.getPackageName(mSubscriberClient1));
-        assertEquals(mCallingAppUid, mClientManager.getSubscriberUid(mSubscriberClient1));
-        assertEquals(UNKNOWN_PACKAGE, mClientManager.getPackageName(mSubscriberClient2));
-        assertEquals(-1, mClientManager.getSubscriberUid(mSubscriberClient2));
-    }
-
-    @Test
-    public void testAddSubscriber_SystemUser() {
-        mCallingAppUid = UserHandle.getUid(UserHandle.USER_SYSTEM, 0);
-        when(mPackageManager.getNameForUid(mCallingAppUid)).thenReturn(TEST_PACKAGE);
-
-        mClientManager.addSubscriber(mSubscriberClient1);
-        assertEquals(TEST_PACKAGE, mClientManager.getPackageName(mSubscriberClient1));
-        assertEquals(mCallingAppUid, mClientManager.getSubscriberUid(mSubscriberClient1));
-        assertEquals(UNKNOWN_PACKAGE, mClientManager.getPackageName(mSubscriberClient2));
-        assertEquals(-1, mClientManager.getSubscriberUid(mSubscriberClient2));
-    }
-
-    @Test
-    public void testAddSubscriber_NotForegroundUser() {
-        mCallingAppUid = UserHandle.getUid(USER_ID_U11, 0);
-
-        try {
-            mClientManager.addSubscriber(mSubscriberClient1);
-            fail("Expected client to be rejected");
-        } catch (SecurityException expected) {
-            // expected
-        }
-        assertEquals(UNKNOWN_PACKAGE, mClientManager.getPackageName(mSubscriberClient1));
-        assertEquals(-1, mClientManager.getSubscriberUid(mSubscriberClient1));
-    }
-
-    @Test
-    public void testAddSubscriber_MultipleCalls() {
-        mClientManager.addSubscriber(mSubscriberClient1);
-        mClientManager.addSubscriber(mSubscriberClient1);
-        verify(mPackageManager, atMost(1)).getNameForUid(anyInt());
-        assertEquals(TEST_PACKAGE, mClientManager.getPackageName(mSubscriberClient1));
-        assertEquals(mCallingAppUid, mClientManager.getSubscriberUid(mSubscriberClient1));
-        assertEquals(UNKNOWN_PACKAGE, mClientManager.getPackageName(mSubscriberClient2));
-        assertEquals(-1, mClientManager.getSubscriberUid(mSubscriberClient2));
-    }
-
-    @Test
-    public void testAddSubscriber_MultipleClients_SamePackage() {
-        mClientManager.addSubscriber(mSubscriberClient1);
-        mClientManager.addSubscriber(mSubscriberClient2);
-        verify(mPackageManager, atMost(2)).getNameForUid(anyInt());
-        assertEquals(TEST_PACKAGE, mClientManager.getPackageName(mSubscriberClient1));
-        assertEquals(mCallingAppUid, mClientManager.getSubscriberUid(mSubscriberClient1));
-        assertEquals(TEST_PACKAGE, mClientManager.getPackageName(mSubscriberClient2));
-        assertEquals(mCallingAppUid, mClientManager.getSubscriberUid(mSubscriberClient2));
-    }
-
-    @Test
-    public void testAddSubscriber_MultipleClients_ForegroundAndSystemUsers_SamePackage() {
-        int clientUid1 = mCallingAppUid;
-        mClientManager.addSubscriber(mSubscriberClient1);
-
-        mCallingAppUid = UserHandle.getUid(UserHandle.USER_SYSTEM, 0);
-        when(mPackageManager.getNameForUid(mCallingAppUid)).thenReturn(TEST_PACKAGE);
-        mClientManager.addSubscriber(mSubscriberClient2);
-
-        verify(mPackageManager, atMost(2)).getNameForUid(anyInt());
-        assertEquals(TEST_PACKAGE, mClientManager.getPackageName(mSubscriberClient1));
-        assertEquals(clientUid1, mClientManager.getSubscriberUid(mSubscriberClient1));
-        assertEquals(TEST_PACKAGE, mClientManager.getPackageName(mSubscriberClient2));
-        assertEquals(mCallingAppUid, mClientManager.getSubscriberUid(mSubscriberClient2));
-    }
-
-
-    @Test
-    public void testAddSubscriber_MultipleClients_MultiplePackages() {
-        int clientUid1 = mCallingAppUid;
-        mClientManager.addSubscriber(mSubscriberClient1);
-
-        mCallingAppUid = UserHandle.getUid(mForegroundUserId, 1);
-        when(mPackageManager.getNameForUid(mCallingAppUid)).thenReturn("test.package2");
-        mClientManager.addSubscriber(mSubscriberClient2);
-
-        verify(mPackageManager, times(2)).getNameForUid(anyInt());
-        assertEquals(TEST_PACKAGE, mClientManager.getPackageName(mSubscriberClient1));
-        assertEquals(clientUid1, mClientManager.getSubscriberUid(mSubscriberClient1));
-        assertEquals("test.package2", mClientManager.getPackageName(mSubscriberClient2));
-        assertEquals(mCallingAppUid, mClientManager.getSubscriberUid(mSubscriberClient2));
-    }
-
-    @Test
-    public void testRemoveSubscriber() {
-        mClientManager.addSubscriber(mSubscriberClient1);
-        mClientManager.removeSubscriber(mSubscriberClient1);
-        verify(mBrokerService).removeDeadSubscriber(mSubscriberClient1);
-        assertEquals(UNKNOWN_PACKAGE, mClientManager.getPackageName(mSubscriberClient1));
-        assertEquals(-1, mClientManager.getSubscriberUid(mSubscriberClient1));
-    }
-
-    @Test
-    public void testRemoveSubscriber_NotRegistered() {
-        mClientManager.removeSubscriber(mSubscriberClient1);
-        assertEquals(UNKNOWN_PACKAGE, mClientManager.getPackageName(mSubscriberClient1));
-        assertEquals(-1, mClientManager.getSubscriberUid(mSubscriberClient1));
-    }
-
-    @Test
-    public void testRemoveSubscriber_OnDeath() {
-        mClientManager.addSubscriber(mSubscriberClient1);
-
-        verify(mSubscriberBinder1).linkToDeath(mDeathRecipient.capture(), eq(0));
-        mDeathRecipient.getValue().binderDied();
-
-        verify(mBrokerService).removeDeadSubscriber(mSubscriberClient1);
-        assertEquals(UNKNOWN_PACKAGE, mClientManager.getPackageName(mSubscriberClient1));
-        assertEquals(-1, mClientManager.getSubscriberUid(mSubscriberClient1));
-    }
-
-    @Test
-    public void testOnUserSwitch_RemoveSubscriber() {
-        mClientManager.addSubscriber(mSubscriberClient1);
-
-        notifyUserSwitched(USER_ID_U11, false);
-        verify(mBrokerService).removeDeadSubscriber(mSubscriberClient1);
-        assertEquals(UNKNOWN_PACKAGE, mClientManager.getPackageName(mSubscriberClient1));
-        assertEquals(-1, mClientManager.getSubscriberUid(mSubscriberClient1));
-        assertTrue(mClientManager.getAllSubscribers().isEmpty());
-    }
-
-    @Test
-    public void testOnUserSwitch_RemoveSubscriber_AddNewSubscriber() {
-        mClientManager.addSubscriber(mSubscriberClient1);
-
-        notifyUserSwitched(USER_ID_U11, false);
-        verify(mBrokerService).removeDeadSubscriber(mSubscriberClient1);
-
-        mCallingAppUid = UserHandle.getUid(USER_ID_U11, 0);
-        when(mPackageManager.getNameForUid(mCallingAppUid)).thenReturn(TEST_PACKAGE);
-        mClientManager.addSubscriber(mSubscriberClient2);
-
-        assertEquals(UNKNOWN_PACKAGE, mClientManager.getPackageName(mSubscriberClient1));
-        assertEquals(-1, mClientManager.getSubscriberUid(mSubscriberClient1));
-        assertEquals(TEST_PACKAGE, mClientManager.getPackageName(mSubscriberClient2));
-        assertEquals(mCallingAppUid, mClientManager.getSubscriberUid(mSubscriberClient2));
-        assertFalse(mClientManager.getAllSubscribers().contains(mSubscriberClient1));
-        assertTrue(mClientManager.getAllSubscribers().contains(mSubscriberClient2));
-    }
-
-    @Test
-    public void testOnUserSwitch_RemoveSubscriber_RetainSystemClient() {
-        mClientManager.addSubscriber(mSubscriberClient1);
-
-        mCallingAppUid = UserHandle.getUid(UserHandle.USER_SYSTEM, 0);
-        when(mPackageManager.getNameForUid(mCallingAppUid)).thenReturn(TEST_PACKAGE);
-
-        mClientManager.addSubscriber(mSubscriberClient2);
-
-        notifyUserSwitched(USER_ID_U11, false);
-
-        verify(mBrokerService).removeDeadSubscriber(mSubscriberClient1);
-        verify(mBrokerService, never()).removeDeadSubscriber(mSubscriberClient2);
-        assertEquals(UNKNOWN_PACKAGE, mClientManager.getPackageName(mSubscriberClient1));
-        assertEquals(TEST_PACKAGE, mClientManager.getPackageName(mSubscriberClient2));
-    }
-
-    @Test
-    public void testOnUserSwitch_RemoveSubscriber_RetainHalClient() {
-        IVmsPublisherClient publisherClient = createPublisherClient();
-        IVmsSubscriberClient subscriberClient = createSubscriberClient();
-        mClientManager.onHalConnected(publisherClient, subscriberClient);
-        verify(mHalClientLog).logConnectionState(ConnectionState.CONNECTED);
-        reset(mPublisherService);
-
-        notifyUserSwitched(USER_ID_U11, false);
-
-        verify(mBrokerService, never()).removeDeadSubscriber(subscriberClient);
-        assertEquals(HAL_CLIENT_NAME, mClientManager.getPackageName(subscriberClient));
-    }
-
-    @Test
-    public void testHalClientConnected() {
-        IVmsPublisherClient publisherClient = createPublisherClient();
-        IVmsSubscriberClient subscriberClient = createSubscriberClient();
-        mClientManager.onHalConnected(publisherClient, subscriberClient);
-        verify(mPublisherService).onClientConnected(eq(HAL_CLIENT_NAME), same(publisherClient));
-        verify(mHalClientLog).logConnectionState(ConnectionState.CONNECTED);
-        assertTrue(mClientManager.getAllSubscribers().contains(subscriberClient));
-        assertEquals(HAL_CLIENT_NAME, mClientManager.getPackageName(subscriberClient));
-    }
-
-    @Test
-    public void testHalClientConnected_AfterAddSubscriber() {
-        IVmsPublisherClient publisherClient = createPublisherClient();
-        IVmsSubscriberClient subscriberClient = createSubscriberClient();
-        mClientManager.addSubscriber(subscriberClient);
-
-        mClientManager.onHalConnected(publisherClient, subscriberClient);
-        verify(mPublisherService).onClientConnected(eq(HAL_CLIENT_NAME), same(publisherClient));
-        verify(mHalClientLog).logConnectionState(ConnectionState.CONNECTED);
-        assertTrue(mClientManager.getAllSubscribers().contains(subscriberClient));
-        assertEquals(HAL_CLIENT_NAME, mClientManager.getPackageName(subscriberClient));
-    }
-
-    @Test
-    public void testOnHalClientDisconnected() {
-        IVmsPublisherClient publisherClient = createPublisherClient();
-        IVmsSubscriberClient subscriberClient = createSubscriberClient();
-        mClientManager.onHalConnected(publisherClient, subscriberClient);
-        verify(mHalClientLog).logConnectionState(ConnectionState.CONNECTED);
-        reset(mPublisherService);
-
-        mClientManager.onHalDisconnected();
-        verify(mPublisherService).onClientDisconnected(eq(HAL_CLIENT_NAME));
-        verify(mBrokerService).removeDeadSubscriber(eq(subscriberClient));
-        verify(mHalClientLog).logConnectionState(ConnectionState.DISCONNECTED);
-        assertFalse(mClientManager.getAllSubscribers().contains(subscriberClient));
-        assertEquals(UNKNOWN_PACKAGE, mClientManager.getPackageName(subscriberClient));
-    }
-
-    @Test
-    public void testOnHalClientDisconnected_NotConnected() {
-        mClientManager.onHalDisconnected();
-        verify(mPublisherService, never()).onClientDisconnected(eq(HAL_CLIENT_NAME));
-        assertTrue(mClientManager.getAllSubscribers().isEmpty());
-    }
-
-    private void resetContext() {
-        reset(mContext, mSystemClientLog, mUserClientLog);
-        when(mContext.getPackageManager()).thenReturn(mPackageManager);
-        when(mContext.bindServiceAsUser(any(), any(), anyInt(), any(), any())).thenReturn(true);
-        when(mContext.getResources()).thenReturn(mResources);
-    }
-
-    private void notifySystemUserUnlocked() {
-        mClientManager.mSystemUserUnlockedListener.run();
-    }
-
-    private void notifyUserSwitched(int foregroundUserId, boolean isForegroundUserUnlocked) {
-        when(mUserManager.isUserUnlockingOrUnlocked(foregroundUserId))
-                .thenReturn(isForegroundUserUnlocked);
-        mForegroundUserId = foregroundUserId; // Member variable used by verifyUserBind()
-        mClientManager.mUserCallback.onSwitchUser(foregroundUserId);
-    }
-
-    private void notifyUserUnlocked(int foregroundUserId, boolean isForegroundUserUnlocked) {
-        when(mUserManager.isUserUnlockingOrUnlocked(foregroundUserId))
-                .thenReturn(isForegroundUserUnlocked);
-        mClientManager.mUserCallback.onUserLockChanged(foregroundUserId, isForegroundUserUnlocked);
-    }
-
-    private void verifySystemBind(int times) {
-        verify(mSystemClientLog, times(times)).logConnectionState(ConnectionState.CONNECTING);
-        verifyBind(times, SYSTEM_CLIENT_COMPONENT, UserHandle.SYSTEM);
-    }
-
-    private void verifyUserBind(int times) {
-        if (mForegroundUserId == USER_ID) {
-            verify(mUserClientLog, times(times)).logConnectionState(ConnectionState.CONNECTING);
-        } else if (mForegroundUserId == USER_ID_U11) {
-            verify(mUserClientLog2, times(times)).logConnectionState(ConnectionState.CONNECTING);
-        }
-        verifyBind(times, USER_CLIENT_COMPONENT, UserHandle.of(mForegroundUserId));
-    }
-
-    private void verifyBind(int times, ComponentName componentName, UserHandle user) {
-        Intent expectedService = new Intent();
-        expectedService.setComponent(componentName);
-        verify(mContext, times(times)).bindServiceAsUser(
-                argThat((service) -> service.filterEquals(expectedService)),
-                mConnectionCaptor.capture(),
-                eq(Context.BIND_AUTO_CREATE), any(Handler.class), eq(user));
-    }
-
-    private void verifyAndRunRebindTask() {
-        verify(mHandler).postDelayed(mRebindCaptor.capture(), eq(MILLIS_BEFORE_REBIND));
-        mRebindCaptor.getValue().run();
-    }
-
-    private void verifyOnClientConnected(String publisherName, IBinder binder) {
-        ArgumentCaptor<IVmsPublisherClient> clientCaptor =
-                ArgumentCaptor.forClass(IVmsPublisherClient.class);
-        verify(mPublisherService).onClientConnected(eq(publisherName), clientCaptor.capture());
-        assertSame(binder, clientCaptor.getValue().asBinder());
-    }
-
-    private IBinder createPublisherBinder() {
-        return createPublisherClient().asBinder();
-    }
-
-    private IVmsPublisherClient createPublisherClient() {
-        return new IVmsPublisherClient.Stub() {
-            @Override
-            public void setVmsPublisherService(IBinder token, IVmsPublisherService service) {
-                throw new RuntimeException("Unexpected call");
-            }
-
-            @Override
-            public void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState) {
-                throw new RuntimeException("Unexpected call");
-            }
-        };
-    }
-
-    private IVmsSubscriberClient createSubscriberClient() {
-        return new IVmsSubscriberClient.Stub() {
-            @Override
-            public void onVmsMessageReceived(VmsLayer layer, byte[] payload) {
-                throw new RuntimeException("Unexpected call");
-            }
-
-            @Override
-            public void onLayersAvailabilityChanged(VmsAvailableLayers availableLayers) {
-                throw new RuntimeException("Unexpected call");
-            }
-        };
-    }
-}
diff --git a/tests/carservice_unit_test/src/com/android/car/vms/VmsLayerAvailabilityTest.java b/tests/carservice_unit_test/src/com/android/car/vms/VmsLayerAvailabilityTest.java
new file mode 100644
index 0000000..9010802
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/vms/VmsLayerAvailabilityTest.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.vms;
+
+import android.car.vms.VmsAssociatedLayer;
+import android.car.vms.VmsLayer;
+import android.car.vms.VmsLayerDependency;
+import android.car.vms.VmsLayersOffering;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+@SmallTest
+public class VmsLayerAvailabilityTest extends AndroidTestCase {
+
+    private static final VmsLayer LAYER_X = new VmsLayer(1, 1, 2);
+    private static final VmsLayer LAYER_Y = new VmsLayer(3, 2, 4);
+    private static final VmsLayer LAYER_Z = new VmsLayer(5, 3, 6);
+
+    private static final int PUBLISHER_ID_1 = 19;
+    private static final int PUBLISHER_ID_2 = 28;
+
+    private static final Set<Integer> PUBLISHERS_1 = Collections.singleton(PUBLISHER_ID_1);
+    private static final Set<Integer> PUBLISHERS_2 = Collections.singleton(PUBLISHER_ID_2);
+    private static final Set<Integer> PUBLISHERS_1_AND_2 =
+            new HashSet<>(Arrays.asList(PUBLISHER_ID_1, PUBLISHER_ID_2));
+
+    private static final VmsLayerDependency X_DEPENDS_ON_Y =
+            new VmsLayerDependency(LAYER_X, Collections.singleton(LAYER_Y));
+
+    private static final VmsLayerDependency X_DEPENDS_ON_Z =
+            new VmsLayerDependency(LAYER_X, Collections.singleton(LAYER_Z));
+
+    private static final VmsLayerDependency Y_DEPENDS_ON_Z =
+            new VmsLayerDependency(LAYER_Y, Collections.singleton(LAYER_Z));
+
+    private static final VmsLayerDependency Y_DEPENDS_ON_X =
+            new VmsLayerDependency(LAYER_Y, Collections.singleton(LAYER_X));
+
+    private static final VmsLayerDependency Z_DEPENDS_ON_X =
+            new VmsLayerDependency(LAYER_Z, Collections.singleton(LAYER_X));
+
+    private static final VmsLayerDependency Z_DEPENDS_ON_NOTHING =
+            new VmsLayerDependency(LAYER_Z);
+
+    private static final VmsLayerDependency X_DEPENDS_ON_SELF =
+            new VmsLayerDependency(LAYER_X, Collections.singleton(LAYER_X));
+
+    private Set<VmsLayersOffering> mOfferings;
+    private VmsLayerAvailability mLayersAvailability;
+
+    @Override
+    protected void setUp() throws Exception {
+        mLayersAvailability = new VmsLayerAvailability();
+        mOfferings = new HashSet<>();
+        super.setUp();
+    }
+
+    public void testNoOffering() {
+        assertTrue(mLayersAvailability.getAvailableLayers().getAssociatedLayers().isEmpty());
+    }
+
+    public void testEmptyOffering() {
+        mLayersAvailability.setPublishersOffering(Collections.emptyList());
+        assertTrue(mLayersAvailability.getAvailableLayers().getAssociatedLayers().isEmpty());
+    }
+
+    public void testSingleLayerNoDeps() {
+        Set<VmsAssociatedLayer> expectedAvailableAssociatedLayers = new HashSet<>();
+        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_X, PUBLISHERS_2));
+
+        VmsLayersOffering offering =
+                new VmsLayersOffering(Collections.singleton(new VmsLayerDependency(LAYER_X)),
+                        PUBLISHER_ID_2);
+
+        mOfferings.add(offering);
+        mLayersAvailability.setPublishersOffering(mOfferings);
+
+        assertEquals(expectedAvailableAssociatedLayers,
+                mLayersAvailability.getAvailableLayers().getAssociatedLayers());
+    }
+
+    public void testChainOfDependenciesSatisfied() {
+        Set<VmsAssociatedLayer> expectedAvailableAssociatedLayers = new HashSet<>();
+        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_X, PUBLISHERS_1));
+        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_Y, PUBLISHERS_1));
+        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_Z, PUBLISHERS_1));
+
+        VmsLayersOffering offering =
+                new VmsLayersOffering(
+                        new HashSet<>(Arrays.asList(
+                                X_DEPENDS_ON_Y, Y_DEPENDS_ON_Z, Z_DEPENDS_ON_NOTHING)),
+                        PUBLISHER_ID_1);
+
+        mOfferings.add(offering);
+        mLayersAvailability.setPublishersOffering(mOfferings);
+
+        assertEquals(expectedAvailableAssociatedLayers,
+                new HashSet<>(
+                        mLayersAvailability.getAvailableLayers().getAssociatedLayers()));
+    }
+
+    public void testChainOfDependenciesSatisfiedTwoOfferings() {
+        Set<VmsAssociatedLayer> expectedAvailableAssociatedLayers = new HashSet<>();
+        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_X, PUBLISHERS_1));
+        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_Y, PUBLISHERS_1));
+        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_Z, PUBLISHERS_1));
+
+        VmsLayersOffering offering1 =
+                new VmsLayersOffering(
+                        new HashSet<>(Arrays.asList(X_DEPENDS_ON_Y, Y_DEPENDS_ON_Z)),
+                        PUBLISHER_ID_1);
+
+        VmsLayersOffering offering2 =
+                new VmsLayersOffering(Collections.singleton(Z_DEPENDS_ON_NOTHING),
+                        PUBLISHER_ID_1);
+
+        mOfferings.add(offering1);
+        mOfferings.add(offering2);
+        mLayersAvailability.setPublishersOffering(mOfferings);
+
+        assertEquals(expectedAvailableAssociatedLayers,
+                new HashSet<>(
+                        mLayersAvailability.getAvailableLayers().getAssociatedLayers()));
+    }
+
+    public void testChainOfDependenciesNotSatisfied() {
+        Set<VmsAssociatedLayer> expectedAvailableAssociatedLayers = new HashSet<>();
+        VmsLayersOffering offering =
+                new VmsLayersOffering(new HashSet<>(Arrays.asList(X_DEPENDS_ON_Y, Y_DEPENDS_ON_Z)),
+                        PUBLISHER_ID_1);
+
+        mOfferings.add(offering);
+        mLayersAvailability.setPublishersOffering(mOfferings);
+
+        assertEquals(expectedAvailableAssociatedLayers,
+                new HashSet<>(
+                        mLayersAvailability.getAvailableLayers().getAssociatedLayers()));
+    }
+
+    public void testOneOfMultipleDependencySatisfied() {
+        Set<VmsAssociatedLayer> expectedAvailableAssociatedLayers = new HashSet<>();
+        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_X, PUBLISHERS_1));
+        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_Z, PUBLISHERS_1));
+
+
+        VmsLayersOffering offering =
+                new VmsLayersOffering(
+                        new HashSet<>(Arrays.asList(
+                                X_DEPENDS_ON_Y, X_DEPENDS_ON_Z, Z_DEPENDS_ON_NOTHING)),
+                        PUBLISHER_ID_1);
+
+        mOfferings.add(offering);
+        mLayersAvailability.setPublishersOffering(mOfferings);
+
+        assertEquals(expectedAvailableAssociatedLayers,
+                new HashSet<>(
+                        mLayersAvailability.getAvailableLayers().getAssociatedLayers()));
+    }
+
+    public void testCyclicDependency() {
+        Set<VmsAssociatedLayer> expectedAvailableAssociatedLayers = new HashSet<>();
+
+        VmsLayersOffering offering =
+                new VmsLayersOffering(
+                        new HashSet<>(
+                                Arrays.asList(X_DEPENDS_ON_Y, Y_DEPENDS_ON_Z, Z_DEPENDS_ON_X)),
+                        PUBLISHER_ID_1);
+
+        mOfferings.add(offering);
+        mLayersAvailability.setPublishersOffering(mOfferings);
+
+        assertEquals(expectedAvailableAssociatedLayers,
+                new HashSet<>(
+                        mLayersAvailability.getAvailableLayers().getAssociatedLayers()));
+    }
+
+    public void testAlmostCyclicDependency() {
+        Set<VmsAssociatedLayer> expectedAvailableAssociatedLayers = new HashSet<>();
+        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_Z, PUBLISHERS_1_AND_2));
+        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_X, PUBLISHERS_1));
+        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_Y, PUBLISHERS_2));
+
+        VmsLayersOffering offering1 =
+                new VmsLayersOffering(
+                        new HashSet<>(Arrays.asList(X_DEPENDS_ON_Y, Z_DEPENDS_ON_NOTHING)),
+                        PUBLISHER_ID_1);
+
+        VmsLayersOffering offering2 =
+                new VmsLayersOffering(new HashSet<>(Arrays.asList(Y_DEPENDS_ON_Z, Z_DEPENDS_ON_X)),
+                        PUBLISHER_ID_2);
+
+        mOfferings.add(offering1);
+        mOfferings.add(offering2);
+        mLayersAvailability.setPublishersOffering(mOfferings);
+
+        assertEquals(expectedAvailableAssociatedLayers,
+                mLayersAvailability.getAvailableLayers().getAssociatedLayers());
+    }
+
+    public void testCyclicDependencyAndLayerWithoutDependency() {
+        Set<VmsAssociatedLayer> expectedAvailableAssociatedLayers = new HashSet<>();
+        expectedAvailableAssociatedLayers.add(new VmsAssociatedLayer(LAYER_Z, PUBLISHERS_1));
+
+        VmsLayersOffering offering1 =
+                new VmsLayersOffering(
+                        new HashSet<>(
+                                Arrays.asList(X_DEPENDS_ON_Y, Z_DEPENDS_ON_NOTHING)),
+                        PUBLISHER_ID_1);
+
+        VmsLayersOffering offering2 =
+                new VmsLayersOffering(Collections.singleton(Y_DEPENDS_ON_X), PUBLISHER_ID_2);
+
+        mOfferings.add(offering1);
+        mOfferings.add(offering2);
+        mLayersAvailability.setPublishersOffering(mOfferings);
+
+        assertEquals(expectedAvailableAssociatedLayers,
+                new HashSet<>(
+                        mLayersAvailability.getAvailableLayers().getAssociatedLayers()));
+    }
+
+    public void testSelfDependency() {
+        Set<VmsAssociatedLayer> expectedAvailableAssociatedLayers = new HashSet<>();
+
+        VmsLayersOffering offering =
+                new VmsLayersOffering(Collections.singleton(X_DEPENDS_ON_SELF),
+                        PUBLISHER_ID_1);
+
+        mOfferings.add(offering);
+        mLayersAvailability.setPublishersOffering(mOfferings);
+
+        assertEquals(expectedAvailableAssociatedLayers,
+                new HashSet<>(
+                        mLayersAvailability.getAvailableLayers().getAssociatedLayers()));
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/vms/VmsProviderInfoStoreTest.java b/tests/carservice_unit_test/src/com/android/car/vms/VmsProviderInfoStoreTest.java
new file mode 100644
index 0000000..ae28fd1
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/vms/VmsProviderInfoStoreTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.vms;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class VmsProviderInfoStoreTest {
+    private static final byte[] MOCK_INFO_1 = new byte[]{2, 3, 5, 7, 11, 13, 17};
+    private static final byte[] SAME_MOCK_INFO_1 = new byte[]{2, 3, 5, 7, 11, 13, 17};
+    private static final byte[] MOCK_INFO_2 = new byte[]{2, 3, 5, 7, 11, 13, 17, 19};
+
+    private VmsProviderInfoStore mProviderInfoStore;
+
+    @Before
+    public void setUp() throws Exception {
+        mProviderInfoStore = new VmsProviderInfoStore();
+    }
+
+    @Test
+    public void testSingleInfo() {
+        int id = mProviderInfoStore.getProviderId(MOCK_INFO_1);
+        assertEquals(1, id);
+        assertArrayEquals(MOCK_INFO_1, mProviderInfoStore.getProviderInfo(id));
+    }
+
+    @Test
+    public void testSingleInfo_NoSuchId() {
+        assertNull(mProviderInfoStore.getProviderInfo(12345));
+    }
+
+    @Test
+    public void testTwoInfos() {
+        int id1 = mProviderInfoStore.getProviderId(MOCK_INFO_1);
+        int id2 = mProviderInfoStore.getProviderId(MOCK_INFO_2);
+        assertEquals(1, id1);
+        assertEquals(2, id2);
+        assertArrayEquals(MOCK_INFO_1, mProviderInfoStore.getProviderInfo(id1));
+        assertArrayEquals(MOCK_INFO_2, mProviderInfoStore.getProviderInfo(id2));
+    }
+
+    @Test
+    public void testSingleInfoInsertedTwice() {
+        int id = mProviderInfoStore.getProviderId(MOCK_INFO_1);
+        assertEquals(1, id);
+
+        int sameId = mProviderInfoStore.getProviderId(SAME_MOCK_INFO_1);
+        assertEquals(sameId, id);
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogManagerUnitTest.java
new file mode 100644
index 0000000..ce51364
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogManagerUnitTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.watchdog;
+
+import static android.car.watchdog.CarWatchdogManager.TIMEOUT_CRITICAL;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.automotive.watchdog.ICarWatchdogClient;
+import android.car.Car;
+import android.car.watchdog.CarWatchdogManager;
+import android.content.Context;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.concurrent.Executor;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CarWatchdogManagerUnitTest {
+
+    private static final int MAX_WAIT_TIME_MS = 3000;
+
+    private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+    private final Context mContext =
+            InstrumentationRegistry.getInstrumentation().getTargetContext();
+    private final Executor mExecutor = mContext.getMainExecutor();
+
+    @Mock private Car mCar;
+    @Mock private IBinder mBinder;
+    @Mock private CarWatchdogService mService;
+
+    private CarWatchdogManager mCarWatchdogManager;
+
+    @Before
+    public void setUp() {
+        when(mCar.getEventHandler()).thenReturn(mMainHandler);
+        when(mBinder.queryLocalInterface(anyString())).thenReturn(mService);
+        mCarWatchdogManager = new CarWatchdogManager(mCar, mBinder);
+    }
+
+    @Test
+    public void testRegisterClient() throws Exception {
+        TestClient client = new TestClient();
+        ICarWatchdogClient clientImpl = registerClient(client);
+        mCarWatchdogManager.unregisterClient(client);
+        verify(mService).unregisterClient(clientImpl);
+
+        clientImpl.checkIfAlive(123456, TIMEOUT_CRITICAL);
+        verify(mService, never()).tellClientAlive(clientImpl, 123456);
+    }
+
+    @Test
+    public void testUnregisterUnregisteredClient() throws Exception {
+        TestClient client = new TestClient();
+        mCarWatchdogManager.registerClient(mExecutor, client, TIMEOUT_CRITICAL);
+        mCarWatchdogManager.unregisterClient(client);
+        // The following call should not throw an exception.
+        mCarWatchdogManager.unregisterClient(client);
+    }
+
+    @Test
+    public void testRegisterMultipleClients() {
+        TestClient client1 = new TestClient();
+        TestClient client2 = new TestClient();
+        mCarWatchdogManager.registerClient(mExecutor, client1, TIMEOUT_CRITICAL);
+        assertThrows(IllegalStateException.class,
+                () -> mCarWatchdogManager.registerClient(mExecutor, client2, TIMEOUT_CRITICAL));
+    }
+
+    @Test
+    public void testHandlePongOnlyClient() throws Exception {
+        testClientResponse(new TestClient());
+    }
+
+    @Test
+    public void testHandleRedundantPongClient() throws Exception {
+        testClientResponse(new RedundantPongClient());
+    }
+
+    @Test
+    public void testHandleReturnAndPongClient() throws Exception {
+        testClientResponse(new ReturnAndPongClient());
+    }
+
+    private ICarWatchdogClient registerClient(CarWatchdogManager.CarWatchdogClientCallback client) {
+        mCarWatchdogManager.registerClient(mExecutor, client, TIMEOUT_CRITICAL);
+        ArgumentCaptor<ICarWatchdogClient> clientImplCaptor =
+                ArgumentCaptor.forClass(ICarWatchdogClient.class);
+
+        verify(mService).registerClient(clientImplCaptor.capture(), eq(TIMEOUT_CRITICAL));
+        return clientImplCaptor.getValue();
+    }
+
+    private void testClientResponse(CarWatchdogManager.CarWatchdogClientCallback client)
+            throws Exception {
+        ICarWatchdogClient clientImpl = registerClient(client);
+        clientImpl.checkIfAlive(123456, TIMEOUT_CRITICAL);
+        verify(mService, timeout(MAX_WAIT_TIME_MS)).tellClientAlive(clientImpl, 123456);
+    }
+
+    private final class TestClient extends CarWatchdogManager.CarWatchdogClientCallback {
+        @Override
+        public boolean onCheckHealthStatus(int sessionId, int timeout) {
+            mMainHandler.post(() -> mCarWatchdogManager.tellClientAlive(this, sessionId));
+            return false;
+        }
+    }
+
+    private final class RedundantPongClient extends CarWatchdogManager.CarWatchdogClientCallback {
+        @Override
+        public boolean onCheckHealthStatus(int sessionId, int timeout) {
+            mCarWatchdogManager.tellClientAlive(this, sessionId);
+            mCarWatchdogManager.tellClientAlive(this, sessionId);
+            return false;
+        }
+    }
+
+    private final class ReturnAndPongClient extends CarWatchdogManager.CarWatchdogClientCallback {
+        @Override
+        public boolean onCheckHealthStatus(int sessionId, int timeout) {
+            mMainHandler.post(() -> mCarWatchdogManager.tellClientAlive(this, sessionId));
+            return true;
+        }
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
new file mode 100644
index 0000000..99b6011
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.watchdog;
+
+import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetUsers;
+import static android.car.watchdog.CarWatchdogManager.TIMEOUT_CRITICAL;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.automotive.watchdog.ICarWatchdog;
+import android.automotive.watchdog.ICarWatchdogClient;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.UserManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.ArrayList;
+
+/**
+ * <p>This class contains unit tests for the {@link CarWatchdogService}.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class CarWatchdogServiceUnitTest extends AbstractExtendedMockitoTestCase {
+
+    private static final String CAR_WATCHDOG_DAEMON_INTERFACE =
+            "android.automotive.watchdog.ICarWatchdog/default";
+    private static final int MAX_WAIT_TIME_MS = 3000;
+    private static final int INVALID_SESSION_ID = -1;
+
+    @Mock private Context mMockContext;
+    @Mock private UserManager mUserManager;
+    @Mock private IBinder mBinder;
+    @Mock private ICarWatchdog mCarWatchdogDaemon;
+
+    private CarWatchdogService mCarWatchdogService;
+    private ICarWatchdogClient mClientImpl;
+
+    /**
+     * Initialize all of the objects with the @Mock annotation.
+     */
+    @Before
+    public void setUpMocks() throws Exception {
+        mCarWatchdogService = new CarWatchdogService(mMockContext);
+        mockWatchdogDaemon();
+        setupUsers();
+        mCarWatchdogService.init();
+        mClientImpl = registerMediator();
+    }
+
+    @Test
+    public void testMediatorHealthCheck() throws Exception {
+        mClientImpl.checkIfAlive(123456, TIMEOUT_CRITICAL);
+        verify(mCarWatchdogDaemon, timeout(MAX_WAIT_TIME_MS)).tellMediatorAlive(eq(mClientImpl),
+                any(int[].class), eq(123456));
+    }
+
+    @Test
+    public void testRegisterClient() throws Exception {
+        TestClient client = new TestClient();
+        mCarWatchdogService.registerClient(client, TIMEOUT_CRITICAL);
+        mClientImpl.checkIfAlive(123456, TIMEOUT_CRITICAL);
+        // Checking client health is asynchronous, so wait at most 1 second.
+        int repeat = 10;
+        while (repeat > 0) {
+            int sessionId = client.getLastSessionId();
+            if (sessionId != INVALID_SESSION_ID) {
+                return;
+            }
+            SystemClock.sleep(100L);
+            repeat--;
+        }
+        assertThat(client.getLastSessionId()).isNotEqualTo(INVALID_SESSION_ID);
+    }
+
+    @Test
+    public void testUnregisterUnregisteredClient() throws Exception {
+        TestClient client = new TestClient();
+        mCarWatchdogService.registerClient(client, TIMEOUT_CRITICAL);
+        mCarWatchdogService.unregisterClient(client);
+        mClientImpl.checkIfAlive(123456, TIMEOUT_CRITICAL);
+        assertThat(client.getLastSessionId()).isEqualTo(INVALID_SESSION_ID);
+    }
+
+    @Test
+    public void testGoodClientHealthCheck() throws Exception {
+        testClientHealthCheck(new TestClient(), 0);
+    }
+
+    @Test
+    public void testBadClientHealthCheck() throws Exception {
+        testClientHealthCheck(new BadTestClient(), 1);
+    }
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder builder) {
+        builder.spyStatic(ServiceManager.class);
+    }
+
+    private void mockWatchdogDaemon() {
+        doReturn(mBinder).when(() -> ServiceManager.getService(CAR_WATCHDOG_DAEMON_INTERFACE));
+        when(mBinder.queryLocalInterface(anyString())).thenReturn(mCarWatchdogDaemon);
+    }
+
+    private void setupUsers() {
+        when(mMockContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+        mockUmGetUsers(mUserManager, new ArrayList<UserInfo>());
+    }
+
+    private ICarWatchdogClient registerMediator() throws Exception {
+        ArgumentCaptor<ICarWatchdogClient> clientImplCaptor =
+                ArgumentCaptor.forClass(ICarWatchdogClient.class);
+        verify(mCarWatchdogDaemon).registerMediator(clientImplCaptor.capture());
+        return clientImplCaptor.getValue();
+    }
+
+    private void testClientHealthCheck(TestClient client, int badClientCount) throws Exception {
+        mCarWatchdogService.registerClient(client, TIMEOUT_CRITICAL);
+        mClientImpl.checkIfAlive(123456, TIMEOUT_CRITICAL);
+        ArgumentCaptor<int[]> notRespondingClients = ArgumentCaptor.forClass(int[].class);
+        verify(mCarWatchdogDaemon, timeout(MAX_WAIT_TIME_MS)).tellMediatorAlive(eq(mClientImpl),
+                notRespondingClients.capture(), eq(123456));
+        assertThat(notRespondingClients.getValue().length).isEqualTo(0);
+        mClientImpl.checkIfAlive(987654, TIMEOUT_CRITICAL);
+        verify(mCarWatchdogDaemon, timeout(MAX_WAIT_TIME_MS)).tellMediatorAlive(eq(mClientImpl),
+                notRespondingClients.capture(), eq(987654));
+        assertThat(notRespondingClients.getValue().length).isEqualTo(badClientCount);
+    }
+
+    private class TestClient extends ICarWatchdogClient.Stub {
+        protected int mLastSessionId = INVALID_SESSION_ID;
+
+        @Override
+        public void checkIfAlive(int sessionId, int timeout) {
+            mLastSessionId = sessionId;
+            mCarWatchdogService.tellClientAlive(this, sessionId);
+        }
+
+        @Override
+        public void prepareProcessTermination() {}
+
+        @Override
+        public int getInterfaceVersion() {
+            return this.VERSION;
+        }
+
+        @Override
+        public String getInterfaceHash() {
+            return this.HASH;
+        }
+
+        public int getLastSessionId() {
+            return mLastSessionId;
+        }
+    }
+
+    private final class BadTestClient extends TestClient {
+        @Override
+        public void checkIfAlive(int sessionId, int timeout) {
+            mLastSessionId = sessionId;
+            // This client doesn't respond to CarWatchdogService.
+        }
+    }
+}
diff --git a/tests/common_utils/Android.mk b/tests/common_utils/Android.mk
index 19302c6..57f40e5 100644
--- a/tests/common_utils/Android.mk
+++ b/tests/common_utils/Android.mk
@@ -23,4 +23,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    mockito-target-extended \
+
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/robotests/Android.mk b/tests/robotests/Android.mk
deleted file mode 100644
index 4ad36fa..0000000
--- a/tests/robotests/Android.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CarServiceRoboTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-
-LOCAL_MODULE_TAGS := tests
-
-# When built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_INSTRUMENTATION_FOR := CarService
-
-LOCAL_JAVA_LIBRARIES := \
-    android.car \
-    android.car.userlib \
-    robolectric_android-all-stub \
-    Robolectric_all-target \
-    mockito-robolectric-prebuilt \
-    truth-prebuilt
-
-include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/tests/robotests/AndroidManifest.xml b/tests/robotests/AndroidManifest.xml
deleted file mode 100644
index d160175..0000000
--- a/tests/robotests/AndroidManifest.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2018 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    coreApp="true"
-    package="com.android.car.robotests">
-
-  <application/>
-
-</manifest>
\ No newline at end of file
diff --git a/tests/robotests/config/robolectric.properties b/tests/robotests/config/robolectric.properties
deleted file mode 100644
index b4e3b78..0000000
--- a/tests/robotests/config/robolectric.properties
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-manifest=packages/services/Car/tests/robotests/AndroidManifest.xml
-sdk=NEWEST_SDK
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/car/CarServiceRobolectricTestRunner.java b/tests/robotests/src/com/android/car/CarServiceRobolectricTestRunner.java
deleted file mode 100644
index 92b3cd8..0000000
--- a/tests/robotests/src/com/android/car/CarServiceRobolectricTestRunner.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car;
-
-import android.annotation.NonNull;
-
-import org.junit.runners.model.InitializationError;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-import org.robolectric.manifest.AndroidManifest;
-import org.robolectric.res.Fs;
-import org.robolectric.res.ResourcePath;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.List;
-
-public class CarServiceRobolectricTestRunner extends RobolectricTestRunner {
-    public CarServiceRobolectricTestRunner(Class<?> testClass) throws InitializationError {
-        super(testClass);
-    }
-
-    /**
-     * We are going to create our own custom manifest so we can add multiple resource paths to it.
-     */
-    @Override
-    protected AndroidManifest getAppManifest(Config config) {
-        try {
-            // Using the manifest file's relative path, we can figure out the application directory.
-            final URL appRoot =
-                    new URL("file:packages/services/Car/tests/robotests");
-            final URL manifestPath = new URL(appRoot, "AndroidManifest.xml");
-            final URL resDir = new URL(appRoot, "res");
-            final URL assetsDir = new URL(appRoot, "assets");
-
-            return new AndroidManifest(Fs.fromURL(manifestPath), Fs.fromURL(resDir),
-                Fs.fromURL(assetsDir), "com.android.car") {
-                @Override
-                public List<ResourcePath> getIncludedResourcePaths() {
-                    final List<ResourcePath> paths = super.getIncludedResourcePaths();
-                    return paths;
-                }
-            };
-        } catch (MalformedURLException e) {
-            throw new RuntimeException("CarServiceRobolectricTestRunner failure", e);
-        }
-    }
-
-    private static ResourcePath resourcePath(@NonNull String spec) {
-        try {
-            return new ResourcePath(null, Fs.fromURL(new URL(spec)), null);
-        } catch (MalformedURLException e) {
-            throw new RuntimeException("CarServiceRobolectricTestRunner failure", e);
-        }
-    }
-}
diff --git a/tests/robotests/src/com/android/car/testutils/shadow/ShadowActivityManager.java b/tests/robotests/src/com/android/car/testutils/shadow/ShadowActivityManager.java
deleted file mode 100644
index e213c4e..0000000
--- a/tests/robotests/src/com/android/car/testutils/shadow/ShadowActivityManager.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.testutils.shadow;
-
-import android.app.ActivityManager;
-
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.annotation.Resetter;
-import org.robolectric.shadow.api.Shadow;
-
-@Implements(ActivityManager.class)
-public class ShadowActivityManager {
-    private static int sCurrentUserId = 0;
-    private int mUserSwitchedTo = -1;
-
-    @Resetter
-    public void reset() {
-        sCurrentUserId = 0;
-        mUserSwitchedTo = 0;
-    }
-
-    @Implementation
-    public static int getCurrentUser() {
-        return sCurrentUserId;
-    }
-
-    @Implementation
-    public boolean switchUser(int userId) {
-        mUserSwitchedTo = userId;
-        return true;
-    }
-
-    public boolean getSwitchUserCalled() {
-        return mUserSwitchedTo != -1;
-    }
-
-    public int getUserSwitchedTo() {
-        return mUserSwitchedTo;
-    }
-
-    public static void setCurrentUser(int userId) {
-        sCurrentUserId = userId;
-    }
-
-    public static ShadowActivityManager getShadow() {
-        return (ShadowActivityManager) Shadow.extract(
-            RuntimeEnvironment.application.getSystemService(ActivityManager.class));
-    }
-}
diff --git a/tests/robotests/src/com/android/car/testutils/shadow/ShadowUserHandle.java b/tests/robotests/src/com/android/car/testutils/shadow/ShadowUserHandle.java
deleted file mode 100644
index 656fa97..0000000
--- a/tests/robotests/src/com/android/car/testutils/shadow/ShadowUserHandle.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.testutils.shadow;
-
-import android.os.UserHandle;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-
-@Implements(UserHandle.class)
-public class ShadowUserHandle {
-    @Implementation
-    public static int myUserId() {
-        try {
-            return ShadowUserManager.getShadow().getCurrentUser();
-        } catch (Throwable t) {
-            // This method may be called before ShadowUserManager is properly initialized. Just
-            // return the default 0 in those cases.
-            return 0;
-        }
-    }
-}
diff --git a/tests/robotests/src/com/android/car/testutils/shadow/ShadowUserManager.java b/tests/robotests/src/com/android/car/testutils/shadow/ShadowUserManager.java
deleted file mode 100644
index bf9cf62..0000000
--- a/tests/robotests/src/com/android/car/testutils/shadow/ShadowUserManager.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.testutils.shadow;
-
-import android.content.Context;
-import android.content.pm.UserInfo;
-import android.os.UserHandle;
-import android.os.UserManager;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.HiddenApi;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.shadow.api.Shadow;
-
-@Implements(UserManager.class)
-public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager {
-    private final Map<Integer, UserInfo> mUserInfos = new HashMap<>();
-    private int mCurrentUser = UserHandle.USER_SYSTEM;
-    public boolean isSystemUser = true;
-    public boolean isPrimaryUser = true;
-    public boolean isLinkedUser = false;
-    public boolean isDemoUser = false;
-    public boolean isManagedProfile = false;
-    public boolean isGuestUser = false;
-    public boolean canSwitchUser = true;
-
-    {
-        addUserInfo(new UserInfo(UserHandle.USER_SYSTEM, "system_user", 0));
-    }
-
-    /**
-     * Used by BaseActivity when creating intents.
-     */
-    @Implementation
-    @HiddenApi
-    public List<UserInfo> getUsers() {
-        return new ArrayList<>(mUserInfos.values());
-    }
-
-    @Implementation
-    public boolean isSystemUser() {
-        return isSystemUser;
-    }
-
-    @Implementation
-    public boolean isPrimaryUser() {
-        return isPrimaryUser;
-    }
-
-    @Implementation
-    public boolean isLinkedUser() {
-        return isLinkedUser;
-    }
-
-    @Implementation
-    public boolean isDemoUser() {
-        return isDemoUser;
-    }
-
-    @Implementation
-    public boolean isGuestUser() {
-        return isGuestUser;
-    }
-
-    @Implementation
-    public boolean isManagedProfile(int userId) {
-        return isManagedProfile;
-    }
-
-    @Implementation
-    public static boolean isSplitSystemUser() {
-        return false;
-    }
-
-    @Implementation
-    public UserInfo getUserInfo(int id) {
-        return mUserInfos.get(id);
-    }
-
-    @Implementation
-    public boolean isUserUnlockingOrUnlocked(int userId) {
-        return isUserUnlocked();
-    }
-
-    @Implementation
-    public boolean canSwitchUsers() {
-        return canSwitchUser;
-    }
-
-    @Implementation
-    public boolean removeUser(int userId) {
-        mUserInfos.remove(userId);
-        return true;
-    }
-
-    @Implementation
-    public UserInfo createGuest(Context context, String name) {
-        UserInfo guest = new UserInfo(12, name, UserInfo.FLAG_GUEST);
-
-        addUserInfo(guest);
-        return guest;
-    }
-
-    public void switchUser(int userId) {
-        if (!mUserInfos.containsKey(userId)) {
-            throw new UnsupportedOperationException("Must add user before switching to it");
-        }
-        mCurrentUser = userId;
-    }
-
-    public int getCurrentUser() {
-        return mCurrentUser;
-    }
-
-    public void setCurrentUser(int userId) {
-        mCurrentUser = userId;
-    }
-
-    public void addUserInfo(UserInfo userInfo) {
-        mUserInfos.put(userInfo.id, userInfo);
-    }
-
-    public static ShadowUserManager getShadow() {
-        return (ShadowUserManager) Shadow.extract(
-                RuntimeEnvironment.application.getSystemService(UserManager.class));
-    }
-}
diff --git a/tests/robotests/src/com/android/car/users/CarUserManagerHelperRoboTest.java b/tests/robotests/src/com/android/car/users/CarUserManagerHelperRoboTest.java
deleted file mode 100644
index 6a90cdf..0000000
--- a/tests/robotests/src/com/android/car/users/CarUserManagerHelperRoboTest.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.users;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.app.ActivityManager;
-import android.car.userlib.CarUserManagerHelper;
-import android.content.Context;
-import android.content.pm.UserInfo;
-import android.os.UserManager;
-
-import com.android.car.CarServiceRobolectricTestRunner;
-import com.android.car.testutils.shadow.ShadowActivityManager;
-import com.android.car.testutils.shadow.ShadowUserHandle;
-import com.android.car.testutils.shadow.ShadowUserManager;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-@RunWith(CarServiceRobolectricTestRunner.class)
-@Config(shadows = { ShadowActivityManager.class,
-        ShadowUserHandle.class, ShadowUserManager.class})
-public class CarUserManagerHelperRoboTest {
-    @Mock
-    private Context mContext;
-
-    private CarUserManagerHelper mHelper;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(
-                RuntimeEnvironment.application.getSystemService(UserManager.class));
-        when(mContext.getSystemService(Context.ACTIVITY_SERVICE)).thenReturn(
-                RuntimeEnvironment.application.getSystemService(ActivityManager.class));
-        when(mContext.getApplicationContext()).thenReturn(mContext);
-        mHelper = new CarUserManagerHelper(mContext);
-    }
-
-    @After
-    public void tearDown() {
-        ShadowActivityManager.getShadow().reset();
-    }
-
-    @Test
-    public void testGetForegroundUserId() {
-        ShadowActivityManager.setCurrentUser(15);
-        assertThat(mHelper.getCurrentForegroundUserId()).isEqualTo(15);
-    }
-
-    @Test
-    public void testGetForegroundUserInfo() {
-        int currentForegroundUserId = 17;
-        ShadowActivityManager.setCurrentUser(currentForegroundUserId);
-
-        assertThat(mHelper.getCurrentForegroundUserInfo().id).isEqualTo(currentForegroundUserId);
-    }
-
-    @Test
-    public void testGetCurrentProcessUserId() {
-        int currentProcessUserId = 11;
-        ShadowUserManager.getShadow().setCurrentUser(currentProcessUserId);
-
-        assertThat(mHelper.getCurrentProcessUserId()).isEqualTo(currentProcessUserId);
-    }
-
-    @Test
-    public void testGetCurrentProcessUserInfo() {
-        int currentProcessUserId = 12;
-        ShadowUserManager.getShadow().setCurrentUser(currentProcessUserId);
-        assertThat(mHelper.getCurrentProcessUserInfo().id).isEqualTo(currentProcessUserId);
-    }
-
-    @Test
-    public void testGetAllUsers() {
-        int currentProcessUserId = 12;
-        ShadowUserManager userManager = ShadowUserManager.getShadow();
-        userManager.setCurrentUser(currentProcessUserId);
-
-        UserInfo currentProcessUser = createUserInfoForId(currentProcessUserId);
-        UserInfo systemUser = createUserInfoForId(0);
-
-        UserInfo otherUser1 = createUserInfoForId(13);
-        UserInfo otherUser2 = createUserInfoForId(14);
-
-        userManager.addUserInfo(systemUser);
-        userManager.addUserInfo(currentProcessUser);
-        userManager.addUserInfo(otherUser1);
-        userManager.addUserInfo(otherUser2);
-
-        if (mHelper.isHeadlessSystemUser()) {
-            // Should return 3 users that don't have system user id.
-            assertThat(mHelper.getAllUsers())
-                .containsExactly(currentProcessUser, otherUser1, otherUser2);
-        } else {
-            assertThat(mHelper.getAllUsers())
-                .containsExactly(systemUser, currentProcessUser, otherUser1, otherUser2);
-        }
-    }
-
-    @Test
-    public void testGetAllUsersExceptForegroundUser() {
-        ShadowActivityManager.setCurrentUser(11);
-        ShadowUserManager userManager = ShadowUserManager.getShadow();
-
-        UserInfo foregroundUser = createUserInfoForId(11);
-        UserInfo otherUser1 = createUserInfoForId(12);
-        UserInfo otherUser2 = createUserInfoForId(13);
-        UserInfo otherUser3 = createUserInfoForId(14);
-
-        userManager.addUserInfo(foregroundUser);
-        userManager.addUserInfo(otherUser1);
-        userManager.addUserInfo(otherUser2);
-        userManager.addUserInfo(otherUser3);
-
-        // Should return 3 users that don't have foregroundUser id.
-        assertThat(mHelper.getAllSwitchableUsers()).hasSize(3);
-        assertThat(mHelper.getAllSwitchableUsers())
-            .containsExactly(otherUser1, otherUser2, otherUser3);
-    }
-
-    @Test
-    public void testCheckForegroundUser() {
-        ShadowActivityManager.setCurrentUser(10);
-        assertThat(mHelper.isForegroundUser(createUserInfoForId(10))).isTrue();
-        assertThat(mHelper.isForegroundUser(createUserInfoForId(11))).isFalse();
-
-        ShadowActivityManager.setCurrentUser(11);
-        assertThat(mHelper.isForegroundUser(createUserInfoForId(11))).isTrue();
-    }
-
-    @Test
-    public void testIsUserRunningCurrentProcess() {
-        ShadowUserManager shadowUserManager = ShadowUserManager.getShadow();
-        UserInfo user1 = createUserInfoForId(10);
-        UserInfo user2 = createUserInfoForId(11);
-        shadowUserManager.addUserInfo(user1);
-        shadowUserManager.addUserInfo(user2);
-        shadowUserManager.setCurrentUser(10);
-
-        assertThat(mHelper.isCurrentProcessUser(user1)).isTrue();
-        assertThat(mHelper.isCurrentProcessUser(user2)).isFalse();
-
-        shadowUserManager.setCurrentUser(11);
-        assertThat(mHelper.isCurrentProcessUser(user2)).isTrue();
-        assertThat(mHelper.isCurrentProcessUser(user1)).isFalse();
-    }
-
-    @Test
-    public void testRemoveCurrentProcessUserSwitchesToGuestUser() {
-        // Set currentProcess user to be user 10.
-        ShadowUserManager shadowUserManager = ShadowUserManager.getShadow();
-        UserInfo user1 = createUserInfoForId(10);
-        UserInfo user2 = createUserInfoForId(11);
-        shadowUserManager.addUserInfo(user1);
-        shadowUserManager.addUserInfo(user2);
-        shadowUserManager.setCurrentUser(10);
-
-        // Removing a currentProcess user, calls "switch" to guest user
-        mHelper.removeUser(user1, "testGuest");
-        assertThat(ShadowActivityManager.getShadow().getSwitchUserCalled()).isTrue();
-        assertThat(ShadowActivityManager.getShadow().getUserSwitchedTo()).isEqualTo(0);
-
-        assertThat(shadowUserManager.removeUser(10)).isTrue();
-    }
-
-    @Test
-    public void testSwitchToUser() {
-        ShadowActivityManager.setCurrentUser(20);
-
-        // Switching to foreground user doesn't do anything.
-        mHelper.switchToUser(createUserInfoForId(20));
-        assertThat(ShadowActivityManager.getShadow().getSwitchUserCalled()).isFalse();
-
-        // Switching to non-current, non-guest user, simply calls switchUser.
-        UserInfo userToSwitchTo = new UserInfo(22, "Test User", 0);
-        mHelper.switchToUser(userToSwitchTo);
-        assertThat(ShadowActivityManager.getShadow().getSwitchUserCalled()).isTrue();
-        assertThat(ShadowActivityManager.getShadow().getUserSwitchedTo()).isEqualTo(22);
-    }
-
-    private UserInfo createUserInfoForId(int id) {
-        UserInfo userInfo = new UserInfo();
-        userInfo.id = id;
-        return userInfo;
-    }
-}
diff --git a/tests/vehiclehal_test/assets/car_hvac_set_test.json b/tests/vehiclehal_test/assets/car_hvac_set_test.json
new file mode 100644
index 0000000..e42875f
--- /dev/null
+++ b/tests/vehiclehal_test/assets/car_hvac_set_test.json
@@ -0,0 +1,26 @@
+[
+  {
+    "timestamp": 1526063903356950016,
+    "areaId": 117,
+    "value": 0,
+    "prop": 354419984
+  },
+  {
+    "timestamp": 1526063903357100032,
+    "areaId": 117,
+    "value": 1,
+    "prop": 354419984
+  },
+  {
+    "timestamp": 1526063903358950016,
+    "areaId": 117,
+    "value": 0,
+    "prop": 354419984
+  },
+  {
+    "timestamp": 1526063903359100032,
+    "areaId": 117,
+    "value": 1,
+    "prop": 354419984
+  }
+]
\ No newline at end of file
diff --git a/tests/vehiclehal_test/assets/car_hvac_test.json b/tests/vehiclehal_test/assets/car_hvac_test.json
index 7f6c0bb..bf51b8d 100644
--- a/tests/vehiclehal_test/assets/car_hvac_test.json
+++ b/tests/vehiclehal_test/assets/car_hvac_test.json
@@ -1,518 +1,506 @@
 [
     {
-        "timestamp": 1526063903356950016, 
-        "areaId": 1, 
-        "value": 1, 
-        "prop": 354419984
-    }, 
-    {
-        "timestamp": 1526063903357100032, 
-        "areaId": 4, 
-        "value": 1, 
-        "prop": 354419984
-    }, 
-    {
-        "timestamp": 1526063903757636096, 
-        "areaId": 0, 
-        "value": 1, 
+        "timestamp": 1526063903757636096,
+        "areaId": 117,
+        "value": 1,
         "prop": 356517121
-    }, 
+    },
     {
-        "timestamp": 1526063904959113984, 
-        "areaId": 0, 
-        "value": 28, 
+        "timestamp": 1526063904959113984,
+        "areaId": 49,
+        "value": 28,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063905159528960, 
-        "areaId": 0, 
-        "value": 27, 
+        "timestamp": 1526063905159528960,
+        "areaId": 49,
+        "value": 27,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063905359936000, 
-        "areaId": 0, 
-        "value": 26, 
+        "timestamp": 1526063905359936000,
+        "areaId": 49,
+        "value": 26,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063905560376832, 
-        "areaId": 0, 
-        "value": 25, 
+        "timestamp": 1526063905560376832,
+        "areaId": 49,
+        "value": 25,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063905760837120, 
-        "areaId": 0, 
-        "value": 24, 
+        "timestamp": 1526063905760837120,
+        "areaId": 49,
+        "value": 24,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063905961300992, 
-        "areaId": 0, 
-        "value": 23, 
+        "timestamp": 1526063905961300992,
+        "areaId": 49,
+        "value": 23,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063906362006016, 
-        "areaId": 0, 
-        "value": 1, 
+        "timestamp": 1526063906362006016,
+        "areaId": 117,
+        "value": 1,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063906562436096, 
-        "areaId": 0, 
-        "value": 2, 
+        "timestamp": 1526063906562436096,
+        "areaId": 117,
+        "value": 2,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063906762857984, 
-        "areaId": 0, 
-        "value": 3, 
+        "timestamp": 1526063906762857984,
+        "areaId": 117,
+        "value": 3,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063906963272960, 
-        "areaId": 0, 
-        "value": 4, 
+        "timestamp": 1526063906963272960,
+        "areaId": 117,
+        "value": 4,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063908364721920, 
-        "areaId": 0, 
-        "value": 1, 
+        "timestamp": 1526063908364721920,
+        "areaId": 117,
+        "value": 1,
         "prop": 356517121
-    }, 
+    },
     {
-        "timestamp": 1526063910066729984, 
-        "areaId": 0, 
-        "value": 4, 
+        "timestamp": 1526063910066729984,
+        "areaId": 117,
+        "value": 4,
         "prop": 356517121
-    }, 
+    },
     {
-        "timestamp": 1526063911268203008, 
-        "areaId": 0, 
-        "value": 22, 
+        "timestamp": 1526063911268203008,
+        "areaId": 49,
+        "value": 22,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063911468478976, 
-        "areaId": 0, 
-        "value": 23, 
+        "timestamp": 1526063911468478976,
+        "areaId": 49,
+        "value": 23,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063911668872192, 
-        "areaId": 0, 
-        "value": 24, 
+        "timestamp": 1526063911668872192,
+        "areaId": 49,
+        "value": 24,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063911869281024, 
-        "areaId": 0, 
-        "value": 25, 
+        "timestamp": 1526063911869281024,
+        "areaId": 49,
+        "value": 25,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063912069678080, 
-        "areaId": 0, 
-        "value": 26, 
+        "timestamp": 1526063912069678080,
+        "areaId": 49,
+        "value": 26,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063912270088960, 
-        "areaId": 0, 
-        "value": 27, 
+        "timestamp": 1526063912270088960,
+        "areaId": 49,
+        "value": 27,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063912670825984, 
-        "areaId": 0, 
-        "value": 5, 
+        "timestamp": 1526063912670825984,
+        "areaId": 117,
+        "value": 5,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063912871236096, 
-        "areaId": 0, 
-        "value": 4, 
+        "timestamp": 1526063912871236096,
+        "areaId": 117,
+        "value": 4,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063913071654912, 
-        "areaId": 0, 
-        "value": 3, 
+        "timestamp": 1526063913071654912,
+        "areaId": 117,
+        "value": 3,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063913272064000, 
-        "areaId": 0, 
-        "value": 2, 
+        "timestamp": 1526063913272064000,
+        "areaId": 117,
+        "value": 2,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063914373497856, 
-        "areaId": 0, 
-        "value": 1, 
+        "timestamp": 1526063914373497856,
+        "areaId": 117,
+        "value": 1,
         "prop": 356517121
-    }, 
+    },
     {
-        "timestamp": 1526063915574942976, 
-        "areaId": 0, 
-        "value": 28, 
+        "timestamp": 1526063915574942976,
+        "areaId": 49,
+        "value": 28,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063915775356928, 
-        "areaId": 0, 
-        "value": 27, 
+        "timestamp": 1526063915775356928,
+        "areaId": 49,
+        "value": 27,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063915975784960, 
-        "areaId": 0, 
-        "value": 26, 
+        "timestamp": 1526063915975784960,
+        "areaId": 49,
+        "value": 26,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063916176208128, 
-        "areaId": 0, 
-        "value": 25, 
+        "timestamp": 1526063916176208128,
+        "areaId": 49,
+        "value": 25,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063916376483840, 
-        "areaId": 0, 
-        "value": 24, 
+        "timestamp": 1526063916376483840,
+        "areaId": 49,
+        "value": 24,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063916576890880, 
-        "areaId": 0, 
-        "value": 23, 
+        "timestamp": 1526063916576890880,
+        "areaId": 49,
+        "value": 23,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063916977551872, 
-        "areaId": 0, 
-        "value": 1, 
+        "timestamp": 1526063916977551872,
+        "areaId": 117,
+        "value": 1,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063917177978112, 
-        "areaId": 0, 
-        "value": 2, 
+        "timestamp": 1526063917177978112,
+        "areaId": 117,
+        "value": 2,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063917378403072, 
-        "areaId": 0, 
-        "value": 3, 
+        "timestamp": 1526063917378403072,
+        "areaId": 117,
+        "value": 3,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063917578809856, 
-        "areaId": 0, 
-        "value": 4, 
+        "timestamp": 1526063917578809856,
+        "areaId": 117,
+        "value": 4,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063918980086016, 
-        "areaId": 0, 
-        "value": 1, 
+        "timestamp": 1526063918980086016,
+        "areaId": 117,
+        "value": 1,
         "prop": 356517121
-    }, 
+    },
     {
-        "timestamp": 1526063920681338112, 
-        "areaId": 0, 
-        "value": 4, 
+        "timestamp": 1526063920681338112,
+        "areaId": 117,
+        "value": 4,
         "prop": 356517121
-    }, 
+    },
     {
-        "timestamp": 1526063921882802944, 
-        "areaId": 0, 
-        "value": 22, 
+        "timestamp": 1526063921882802944,
+        "areaId": 49,
+        "value": 22,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063922083273984, 
-        "areaId": 0, 
-        "value": 23, 
+        "timestamp": 1526063922083273984,
+        "areaId": 49,
+        "value": 23,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063922283792896, 
-        "areaId": 0, 
-        "value": 24, 
+        "timestamp": 1526063922283792896,
+        "areaId": 49,
+        "value": 24,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063922484265984, 
-        "areaId": 0, 
-        "value": 25, 
+        "timestamp": 1526063922484265984,
+        "areaId": 49,
+        "value": 25,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063922684783872, 
-        "areaId": 0, 
-        "value": 26, 
+        "timestamp": 1526063922684783872,
+        "areaId": 49,
+        "value": 26,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063922885256960, 
-        "areaId": 0, 
-        "value": 27, 
+        "timestamp": 1526063922885256960,
+        "areaId": 49,
+        "value": 27,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063923285954048, 
-        "areaId": 0, 
-        "value": 5, 
+        "timestamp": 1526063923285954048,
+        "areaId": 117,
+        "value": 5,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063923486427136, 
-        "areaId": 0, 
-        "value": 4, 
+        "timestamp": 1526063923486427136,
+        "areaId": 117,
+        "value": 4,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063923686938880, 
-        "areaId": 0, 
-        "value": 3, 
+        "timestamp": 1526063923686938880,
+        "areaId": 117,
+        "value": 3,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063923887389952, 
-        "areaId": 0, 
-        "value": 2, 
+        "timestamp": 1526063923887389952,
+        "areaId": 117,
+        "value": 2,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063924988778240, 
-        "areaId": 0, 
-        "value": 1, 
+        "timestamp": 1526063924988778240,
+        "areaId": 117,
+        "value": 1,
         "prop": 356517121
-    }, 
+    },
     {
-        "timestamp": 1526063926190287104, 
-        "areaId": 0, 
-        "value": 28, 
+        "timestamp": 1526063926190287104,
+        "areaId": 49,
+        "value": 28,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063926390775040, 
-        "areaId": 0, 
-        "value": 27, 
+        "timestamp": 1526063926390775040,
+        "areaId": 49,
+        "value": 27,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063926591278080, 
-        "areaId": 0, 
-        "value": 26, 
+        "timestamp": 1526063926591278080,
+        "areaId": 49,
+        "value": 26,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063926791796992, 
-        "areaId": 0, 
-        "value": 25, 
+        "timestamp": 1526063926791796992,
+        "areaId": 49,
+        "value": 25,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063926992291840, 
-        "areaId": 0, 
-        "value": 24, 
+        "timestamp": 1526063926992291840,
+        "areaId": 49,
+        "value": 24,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063927192840960, 
-        "areaId": 0, 
-        "value": 23, 
+        "timestamp": 1526063927192840960,
+        "areaId": 49,
+        "value": 23,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063927593507072, 
-        "areaId": 0, 
-        "value": 1, 
+        "timestamp": 1526063927593507072,
+        "areaId": 117,
+        "value": 1,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063927793946112, 
-        "areaId": 0, 
-        "value": 2, 
+        "timestamp": 1526063927793946112,
+        "areaId": 117,
+        "value": 2,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063927994479872, 
-        "areaId": 0, 
-        "value": 3, 
+        "timestamp": 1526063927994479872,
+        "areaId": 117,
+        "value": 3,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063928194946048, 
-        "areaId": 0, 
-        "value": 4, 
+        "timestamp": 1526063928194946048,
+        "areaId": 117,
+        "value": 4,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063929596730112, 
-        "areaId": 0, 
-        "value": 1, 
+        "timestamp": 1526063929596730112,
+        "areaId": 117,
+        "value": 1,
         "prop": 356517121
-    }, 
+    },
     {
-        "timestamp": 1526063931298659072, 
-        "areaId": 0, 
-        "value": 4, 
+        "timestamp": 1526063931298659072,
+        "areaId": 117,
+        "value": 4,
         "prop": 356517121
-    }, 
+    },
     {
-        "timestamp": 1526063932500180992, 
-        "areaId": 0, 
-        "value": 22, 
+        "timestamp": 1526063932500180992,
+        "areaId": 49,
+        "value": 22,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063932700491008, 
-        "areaId": 0, 
-        "value": 23, 
+        "timestamp": 1526063932700491008,
+        "areaId": 49,
+        "value": 23,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063932900928000, 
-        "areaId": 0, 
-        "value": 24, 
+        "timestamp": 1526063932900928000,
+        "areaId": 49,
+        "value": 24,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063933101340928, 
-        "areaId": 0, 
-        "value": 25, 
+        "timestamp": 1526063933101340928,
+        "areaId": 49,
+        "value": 25,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063933301820160, 
-        "areaId": 0, 
-        "value": 26, 
+        "timestamp": 1526063933301820160,
+        "areaId": 49,
+        "value": 26,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063933502290944, 
-        "areaId": 0, 
-        "value": 27, 
+        "timestamp": 1526063933502290944,
+        "areaId": 49,
+        "value": 27,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063933903042048, 
-        "areaId": 0, 
-        "value": 5, 
+        "timestamp": 1526063933903042048,
+        "areaId": 117,
+        "value": 5,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063934103492864, 
-        "areaId": 0, 
-        "value": 4, 
+        "timestamp": 1526063934103492864,
+        "areaId": 117,
+        "value": 4,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063934303913984, 
-        "areaId": 0, 
-        "value": 3, 
+        "timestamp": 1526063934303913984,
+        "areaId": 117,
+        "value": 3,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063934504412928, 
-        "areaId": 0, 
-        "value": 2, 
+        "timestamp": 1526063934504412928,
+        "areaId": 117,
+        "value": 2,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063935606041856, 
-        "areaId": 0, 
-        "value": 1, 
+        "timestamp": 1526063935606041856,
+        "areaId": 117,
+        "value": 1,
         "prop": 356517121
-    }, 
+    },
     {
-        "timestamp": 1526063936807610880, 
-        "areaId": 0, 
-        "value": 28, 
+        "timestamp": 1526063936807610880,
+        "areaId": 49,
+        "value": 28,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063937008130048, 
-        "areaId": 0, 
-        "value": 27, 
+        "timestamp": 1526063937008130048,
+        "areaId": 49,
+        "value": 27,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063937208636160, 
-        "areaId": 0, 
-        "value": 26, 
+        "timestamp": 1526063937208636160,
+        "areaId": 49,
+        "value": 26,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063937409096960, 
-        "areaId": 0, 
-        "value": 25, 
+        "timestamp": 1526063937409096960,
+        "areaId": 49,
+        "value": 25,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063937609554176, 
-        "areaId": 0, 
-        "value": 24, 
+        "timestamp": 1526063937609554176,
+        "areaId": 49,
+        "value": 24,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063937810017024, 
-        "areaId": 0, 
-        "value": 23, 
+        "timestamp": 1526063937810017024,
+        "areaId": 49,
+        "value": 23,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063938210696960, 
-        "areaId": 0, 
-        "value": 1, 
+        "timestamp": 1526063938210696960,
+        "areaId": 117,
+        "value": 1,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063938411200000, 
-        "areaId": 0, 
-        "value": 2, 
+        "timestamp": 1526063938411200000,
+        "areaId": 117,
+        "value": 2,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063938611734016, 
-        "areaId": 0, 
-        "value": 3, 
+        "timestamp": 1526063938611734016,
+        "areaId": 117,
+        "value": 3,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063938812249856, 
-        "areaId": 0, 
-        "value": 4, 
+        "timestamp": 1526063938812249856,
+        "areaId": 117,
+        "value": 4,
         "prop": 356517120
-    }, 
+    },
     {
-        "timestamp": 1526063940214057984, 
-        "areaId": 0, 
-        "value": 1, 
+        "timestamp": 1526063940214057984,
+        "areaId": 117,
+        "value": 1,
         "prop": 356517121
-    }, 
+    },
     {
-        "timestamp": 1526063941916071936, 
-        "areaId": 0, 
-        "value": 4, 
+        "timestamp": 1526063941916071936,
+        "areaId": 117,
+        "value": 4,
         "prop": 356517121
-    }, 
+    },
     {
-        "timestamp": 1526063943123698944, 
-        "areaId": 0, 
-        "value": 22, 
+        "timestamp": 1526063943123698944,
+        "areaId": 49,
+        "value": 22,
         "prop": 358614275
-    }, 
+    },
     {
-        "timestamp": 1526063943323981056, 
-        "areaId": 0, 
-        "value": 23, 
+        "timestamp": 1526063943323981056,
+        "areaId": 49,
+        "value": 23,
         "prop": 358614275
     }
 ]
\ No newline at end of file
diff --git a/tests/vehiclehal_test/assets/car_info_test.json b/tests/vehiclehal_test/assets/car_info_test.json
index 90c9bdc..66aa87b 100644
--- a/tests/vehiclehal_test/assets/car_info_test.json
+++ b/tests/vehiclehal_test/assets/car_info_test.json
@@ -14,7 +14,7 @@
     {
         "timestamp": 1526063903360950016,
         "areaId": 0,
-        "value": "Test Car",
+        "value": "Toy Vehicle",
         "prop": 286261505
     }
 ]
diff --git a/tests/vehiclehal_test/assets/car_property_test.json b/tests/vehiclehal_test/assets/car_property_test.json
new file mode 100644
index 0000000..881ddf4
--- /dev/null
+++ b/tests/vehiclehal_test/assets/car_property_test.json
@@ -0,0 +1,26 @@
+[
+  {
+    "timestamp": 151111100000000,
+    "areaId": 0,
+    "value": 8,
+    "prop": 289408000
+  },
+  {
+    "timestamp": 101111100000000,
+    "areaId": 0,
+    "value": 4,
+    "prop": 289408000
+  },
+  {
+    "timestamp": 181111100000000,
+    "areaId": 0,
+    "value": 16,
+    "prop": 289408000
+  },
+  {
+    "timestamp": 101111100000000,
+    "areaId": 0,
+    "value": 4,
+    "prop": 289408000
+  }
+]
\ No newline at end of file
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarPropertyTest.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarPropertyTest.java
index f9d1fd8..8e41c19 100644
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarPropertyTest.java
+++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarPropertyTest.java
@@ -15,14 +15,22 @@
  */
 package com.android.car.vehiclehal.test;
 
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+import static java.lang.Integer.toHexString;
+
 import android.car.Car;
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.property.CarPropertyManager;
 import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback;
+import android.car.hardware.property.VehicleVendorPermission;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropertyGroup;
+import android.os.SystemClock;
 import android.util.ArraySet;
 import android.util.Log;
 
@@ -33,11 +41,11 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import static java.lang.Integer.toHexString;
-
-import java.io.File;
 import java.time.Duration;
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /**
  * The test suite will execute end-to-end Car Property API test by generating VHAL property data
@@ -51,88 +59,145 @@
     private static final String TAG = Utils.concatTag(CarPropertyTest.class);
 
     // Test should be completed within 10 minutes as it only covers a finite set of properties
-    private static final Duration TEST_TIME_OUT = Duration.ofMinutes(10);
+    private static final Duration TEST_TIME_OUT = Duration.ofMinutes(3);
 
     private static final String CAR_HVAC_TEST_JSON = "car_hvac_test.json";
+    private static final String CAR_HVAC_TEST_SET_JSON = "car_hvac_test.json";
     private static final String CAR_INFO_TEST_JSON = "car_info_test.json";
+    // kMixedTypePropertyForTest property ID
+    private static final int MIXED_TYPE_PROPERTY = 0x21e01111;
+    // kSetPropertyFromVehicleForTest
+    private static final int SET_INT_FROM_VEHICLE = 0x21e01112;
+    private static final int SET_FLOAT_FROM_VEHICLE = 0x21e01113;
+    private static final int SET_BOOLEAN_FROM_VEHICLE = 0x21e01114;
+    private static final int WAIT_FOR_CALLBACK = 200;
 
+    // kMixedTypePropertyForTest default value
+    private static final Object[] DEFAULT_VALUE = {"MIXED property", true, 2, 3, 4.5f};
+    private static final String CAR_PROPERTY_TEST_JSON = "car_property_test.json";
+    private static final int GEAR_PROPERTY_ID = 289408000;
+
+    private static final Set<String> VENDOR_PERMISSIONS = new HashSet<>(Arrays.asList(
+            Car.PERMISSION_VENDOR_EXTENSION,
+            VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_WINDOW,
+            VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_WINDOW,
+            // permissions for the property related with door
+            VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_DOOR,
+            VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_DOOR,
+            // permissions for the property related with seat
+            VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_SEAT,
+            VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_SEAT,
+            // permissions for the property related with mirror
+            VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_MIRROR,
+            VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_MIRROR,
+
+            // permissions for the property related with car's information
+            VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_INFO,
+            VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_INFO,
+            // permissions for the property related with car's engine
+            VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_ENGINE,
+            VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_ENGINE,
+            // permissions for the property related with car's HVAC
+            VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_HVAC,
+            VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_HVAC,
+            // permissions for the property related with car's light
+            VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_LIGHT,
+            VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_LIGHT,
+
+            // permissions reserved for other vendor permission
+            VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_1,
+            VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_1,
+            VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_2,
+            VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_2,
+            VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_3,
+            VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_3,
+            VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_4,
+            VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_4,
+            VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_5,
+            VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_5,
+            VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_6,
+            VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_6,
+            VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_7,
+            VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_7,
+            VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_8,
+            VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_8,
+            VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_9,
+            VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_9,
+            VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_10,
+            VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_10
+    ));
     private class CarPropertyEventReceiver implements CarPropertyEventCallback {
 
         private VhalEventVerifier mVerifier;
-        private Integer mNumOfEventToSkip;
+        private boolean mStartVerify = false;
 
-        CarPropertyEventReceiver(VhalEventVerifier verifier, int numOfEventToSkip) {
+        CarPropertyEventReceiver(VhalEventVerifier verifier) {
             mVerifier = verifier;
-            mNumOfEventToSkip = numOfEventToSkip;
         }
 
         @Override
         public void onChangeEvent(CarPropertyValue carPropertyValue) {
-            Log.d(TAG, "Received event: " + carPropertyValue);
-            synchronized (mNumOfEventToSkip) {
-                if (mNumOfEventToSkip > 0) {
-                    mNumOfEventToSkip--;
-                    return;
-                }
+            if (mStartVerify) {
+                mVerifier.verify(carPropertyValue);
             }
-            mVerifier.verify(carPropertyValue);
         }
 
         @Override
         public void onErrorEvent(final int propertyId, final int zone) {
             Assert.fail("Error: propertyId=" + toHexString(propertyId) + " zone=" + zone);
         }
-    }
 
-    private int countNumPropEventsToSkip(CarPropertyManager propMgr, ArraySet<Integer> props) {
-        int numToSkip = 0;
-        for (CarPropertyConfig c : propMgr.getPropertyList(props)) {
-            numToSkip += c.getAreaCount();
+        // Start verifying events
+        public void startVerifying() {
+            mStartVerify = true;
         }
-        return numToSkip;
     }
 
     /**
-     * This test will let Default VHAL to generate HVAC data and verify on-the-fly in the test. It
-     * is simulating the HVAC actions coming from hard buttons in a car.
+     * This test will use {@link CarPropertyManager#setProperty(Class, int, int, Object)} to turn
+     * on the HVAC_PROWER and then let Default VHAL to generate HVAC data and verify on-the-fly
+     * in the test. It is simulating the HVAC actions coming from hard buttons in a car.
      * @throws Exception
      */
     @Test
     public void testHvacHardButtonOperations() throws Exception {
+
         Log.d(TAG, "Prepare HVAC test data");
         List<CarPropertyValue> expectedEvents = getExpectedEvents(CAR_HVAC_TEST_JSON);
-        VhalEventVerifier verifier = new VhalEventVerifier(expectedEvents);
+        List<CarPropertyValue> expectedSetEvents = getExpectedEvents(CAR_HVAC_TEST_SET_JSON);
 
         CarPropertyManager propMgr = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
         assertNotNull("CarPropertyManager is null", propMgr);
 
-        ArraySet<Integer> props = new ArraySet<>();
-        for (CarPropertyValue event : expectedEvents) {
-            if (!props.contains(event.getPropertyId())) {
-                props.add(event.getPropertyId());
-            }
+        // test set method from android side
+        for (CarPropertyValue expectedEvent : expectedSetEvents) {
+            Class valueClass = expectedEvent.getValue().getClass();
+            propMgr.setProperty(valueClass,
+                    expectedEvent.getPropertyId(),
+                    expectedEvent.getAreaId(),
+                    expectedEvent.getValue());
+            Thread.sleep(WAIT_FOR_CALLBACK);
+            CarPropertyValue receivedEvent = propMgr.getProperty(valueClass,
+                    expectedEvent.getPropertyId(), expectedEvent.getAreaId());
+            assertTrue("Mismatched events, expected: " + expectedEvent + ", received: "
+                    + receivedEvent, Utils.areCarPropertyValuesEqual(expectedEvent, receivedEvent));
         }
 
-        int numToSkip = countNumPropEventsToSkip(propMgr, props);
-        Log.d(TAG, String.format("Start listening to the HAL."
-                                 + " Skipping %d events for listener registration", numToSkip));
-        CarPropertyEventCallback receiver =
-                new CarPropertyEventReceiver(verifier, numToSkip);
+        // test that set from vehicle side will trigger callback to android
+        VhalEventVerifier verifier = new VhalEventVerifier(expectedEvents);
+        ArraySet<Integer> props = new ArraySet<>();
+        for (CarPropertyValue event : expectedEvents) {
+                props.add(event.getPropertyId());
+        }
+        CarPropertyEventReceiver receiver =
+                new CarPropertyEventReceiver(verifier);
         for (Integer prop : props) {
             propMgr.registerCallback(receiver, prop, 0);
         }
-
-        File sharedJson = makeShareable(CAR_HVAC_TEST_JSON);
-        Log.d(TAG, "Send command to VHAL to start generation");
-        VhalEventGenerator hvacGenerator =
-                new JsonVhalEventGenerator(mVehicle).setJsonFile(sharedJson);
-        hvacGenerator.start();
-
-        Log.d(TAG, "Receiving and verifying VHAL events");
+        Thread.sleep(WAIT_FOR_CALLBACK);
+        receiver.startVerifying();
+        injectEventFromVehicleSide(expectedEvents, propMgr);
         verifier.waitForEnd(TEST_TIME_OUT.toMillis());
-
-        Log.d(TAG, "Send command to VHAL to stop generation");
-        hvacGenerator.stop();
         propMgr.unregisterCallback(receiver);
 
         assertTrue("Detected mismatched events: " + verifier.getResultString(),
@@ -140,38 +205,7 @@
     }
 
     /**
-     * This test will exercise on "set" calls to inject HVAC data in order to test the Car Property
-     * API end-to-end functionality.
-     * @throws Exception
-     */
-    @Test
-    @SuppressWarnings("unchecked")
-    public void testHvacSetGetOperations() throws Exception {
-        Log.d(TAG, "Prepare HVAC test data");
-        List<CarPropertyValue> expectedEvents = getExpectedEvents(CAR_HVAC_TEST_JSON);
-
-        CarPropertyManager propMgr = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
-        assertNotNull("CarPropertyManager is null", propMgr);
-
-        final long waitForSetMillisecond = 2;
-        for (CarPropertyValue expectedEvent : expectedEvents) {
-            Class valueClass = expectedEvent.getValue().getClass();
-            propMgr.setProperty(valueClass,
-                                expectedEvent.getPropertyId(),
-                                expectedEvent.getAreaId(),
-                                expectedEvent.getValue());
-
-            Thread.sleep(waitForSetMillisecond);
-            CarPropertyValue receivedEvent = propMgr.getProperty(valueClass,
-                    expectedEvent.getPropertyId(), expectedEvent.getAreaId());
-            assertTrue("Mismatched events, expected: " + expectedEvent + ", received: "
-                    + receivedEvent, Utils.areCarPropertyValuesEqual(expectedEvent, receivedEvent));
-        }
-    }
-
-    /**
-     * This test will load static vehicle information from test data file and verify them through
-     * get calls.
+     * Static properties' value should never be changed.
      * @throws Exception
      */
     @Test
@@ -181,20 +215,6 @@
         List<CarPropertyValue> expectedEvents = getExpectedEvents(CAR_INFO_TEST_JSON);
         CarPropertyManager propMgr = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
         assertNotNull("CarPropertyManager is null", propMgr);
-
-        File sharedJson = makeShareable(CAR_INFO_TEST_JSON);
-        Log.d(TAG, "Send command to VHAL to start generation");
-        VhalEventGenerator infoGenerator =
-                new JsonVhalEventGenerator(mVehicle).setJsonFile(sharedJson);
-        infoGenerator.start();
-
-        // Wait for some time to ensure information is all loaded
-        // It is assuming the test data is not very large
-        Thread.sleep(2000);
-
-        Log.d(TAG, "Send command to VHAL to stop generation");
-        infoGenerator.stop();
-
         for (CarPropertyValue expectedEvent : expectedEvents) {
             CarPropertyValue actualEvent = propMgr.getProperty(
                     expectedEvent.getPropertyId(), expectedEvent.getAreaId());
@@ -204,4 +224,138 @@
                     Utils.areCarPropertyValuesEqual(actualEvent, expectedEvent));
         }
     }
+
+    /**
+     * This test will test set/get on MIX type properties. It needs a vendor property in Google
+     * Vehicle HAL. See kMixedTypePropertyForTest in google defaultConfig.h for details.
+     * @throws Exception
+     */
+    @Test
+    public void testMixedTypeProperty() throws Exception {
+        CarPropertyManager propertyManager =
+                (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
+        ArraySet<Integer> propConfigSet = new ArraySet<>();
+        propConfigSet.add(MIXED_TYPE_PROPERTY);
+
+        List<CarPropertyConfig> configs = propertyManager.getPropertyList(propConfigSet);
+
+        // use google HAL in the test
+        assertNotEquals("Can not find MIXED type properties in HAL",
+                0, configs.size());
+
+        // test CarPropertyConfig
+        CarPropertyConfig<?> cfg = configs.get(0);
+        List<Integer> configArrayExpected = Arrays.asList(1, 1, 0, 2, 0, 0, 1, 0, 0);
+        assertArrayEquals(configArrayExpected.toArray(), cfg.getConfigArray().toArray());
+
+        // test SET/GET methods
+        CarPropertyValue<Object[]> propertyValue = propertyManager.getProperty(Object[].class,
+                MIXED_TYPE_PROPERTY, 0);
+        assertArrayEquals(DEFAULT_VALUE, propertyValue.getValue());
+
+        Object[] expectedValue = {"MIXED property", false, 5, 4, 3.2f};
+        propertyManager.setProperty(Object[].class, MIXED_TYPE_PROPERTY, 0, expectedValue);
+        // Wait for VHAL
+        Thread.sleep(WAIT_FOR_CALLBACK);
+        CarPropertyValue<Object[]> result = propertyManager.getProperty(Object[].class,
+                MIXED_TYPE_PROPERTY, 0);
+        assertArrayEquals(expectedValue, result.getValue());
+    }
+
+    /**
+     * This test will test the case: vehicle events comes to android out of order.
+     * See the events in car_property_test.json.
+     * @throws Exception
+     */
+    @Test
+    public void testPropertyEventOutOfOrder() throws Exception {
+        CarPropertyManager propMgr = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
+        assertNotNull("CarPropertyManager is null", propMgr);
+        List<CarPropertyValue> expectedEvents = getExpectedEvents(CAR_PROPERTY_TEST_JSON);
+
+        GearEventTestCallback cb = new GearEventTestCallback();
+        propMgr.registerCallback(cb, GEAR_PROPERTY_ID, CarPropertyManager.SENSOR_RATE_ONCHANGE);
+        injectEventFromVehicleSide(expectedEvents, propMgr);
+        // check VHAL ignored the last event in car_property_test, because it is out of order.
+        int currentGear = propMgr.getIntProperty(GEAR_PROPERTY_ID, 0);
+        assertEquals(16, currentGear);
+    }
+
+    /**
+     * Check only vendor properties have vendor permissions.
+     */
+    @Test
+    public void checkPropertyPermission() {
+        CarPropertyManager propMgr = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
+        List<CarPropertyConfig> configs = propMgr.getPropertyList();
+        for (CarPropertyConfig cfg : configs) {
+            String readPermission = propMgr.getReadPermission(cfg.getPropertyId());
+            String writePermission = propMgr.getWritePermission(cfg.getPropertyId());
+            if ((cfg.getPropertyId() & VehiclePropertyGroup.MASK) == VehiclePropertyGroup.VENDOR) {
+                Assert.assertTrue(readPermission == null
+                        || VENDOR_PERMISSIONS.contains(readPermission));
+                Assert.assertTrue(writePermission == null
+                        || VENDOR_PERMISSIONS.contains(writePermission));
+            } else {
+                Assert.assertTrue(readPermission == null
+                        || !VENDOR_PERMISSIONS.contains(readPermission));
+                Assert.assertTrue(writePermission == null
+                        || !VENDOR_PERMISSIONS.contains(writePermission));
+            }
+        }
+    }
+
+    private class GearEventTestCallback implements CarPropertyEventCallback {
+        private long mTimestamp = 0L;
+
+        @Override
+        public void onChangeEvent(CarPropertyValue carPropertyValue) {
+            if (carPropertyValue.getPropertyId() != GEAR_PROPERTY_ID) {
+                return;
+            }
+            if (carPropertyValue.getStatus() == CarPropertyValue.STATUS_AVAILABLE) {
+                Assert.assertTrue("Received events out of oder",
+                        mTimestamp <= carPropertyValue.getTimestamp());
+                mTimestamp = carPropertyValue.getTimestamp();
+            }
+        }
+
+        @Override
+        public void onErrorEvent(final int propertyId, final int zone) {
+            Assert.fail("Error: propertyId: x0" + toHexString(propertyId) + " areaId: " + zone);
+        }
+    }
+
+    /**
+     * Inject events from vehicle side. It change the value of property even the property is a
+     * read_only property such as GEAR_SELECTION. It only works with Google VHAL.
+     */
+    private void injectEventFromVehicleSide(List<CarPropertyValue> expectedEvents,
+            CarPropertyManager propMgr) {
+        for (CarPropertyValue propertyValue : expectedEvents) {
+            Object[] values = new Object[3];
+            int propId;
+            // The order of values is matter
+            if (propertyValue.getValue() instanceof Integer) {
+                propId = SET_INT_FROM_VEHICLE;
+                values[0] = propertyValue.getPropertyId();
+                values[1] = propertyValue.getValue();
+                values[2] = propertyValue.getTimestamp() + SystemClock.elapsedRealtimeNanos();
+            } else if (propertyValue.getValue() instanceof Float) {
+                values[0] = propertyValue.getPropertyId();
+                values[1] = propertyValue.getTimestamp() + SystemClock.elapsedRealtimeNanos();
+                values[2] = propertyValue.getValue();
+                propId = SET_FLOAT_FROM_VEHICLE;
+            } else if (propertyValue.getValue() instanceof Boolean) {
+                propId = SET_BOOLEAN_FROM_VEHICLE;
+                values[1] = propertyValue.getPropertyId();
+                values[0] = propertyValue.getValue();
+                values[2] = propertyValue.getTimestamp() + SystemClock.elapsedRealtimeNanos();
+            } else {
+                throw new IllegalArgumentException(
+                        "Unexpected property type for property " + propertyValue.getPropertyId());
+            }
+            propMgr.setProperty(Object[].class, propId, propertyValue.getAreaId(), values);
+        }
+    }
 }
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2ePerformanceTest.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2ePerformanceTest.java
index 6399549..edbd6d8 100644
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2ePerformanceTest.java
+++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/E2ePerformanceTest.java
@@ -79,9 +79,9 @@
                 CarSensorManager.SENSOR_TYPE_ODOMETER,
                 CarSensorManager.SENSOR_TYPE_CAR_SPEED
         };
-        // Expecting to receive at least 10 events within 150ms.
-        final int EVENT_INTERVAL_MS = 1; //
-        final int EXPECTED_EVENTS_PER_PROPERTY = 1000;
+        // CarPropertyManager supports highest rate is 100hz which means event interval is 10ms.
+        final int EVENT_INTERVAL_MS = 10; //
+        final int EXPECTED_EVENTS_PER_PROPERTY = 100;
         final int EXPECTED_EVENTS = EXPECTED_EVENTS_PER_PROPERTY * mgrProperties.length;
 
         CarSensorManager mgr = (CarSensorManager) mCar.getCarManager(Car.SENSOR_SERVICE);
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2FreezeFrameTest.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2FreezeFrameTest.java
index fb09ebd..1b2d575 100644
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2FreezeFrameTest.java
+++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/Obd2FreezeFrameTest.java
@@ -21,6 +21,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import android.hardware.automotive.vehicle.V2_0.IVehicle;
@@ -28,6 +29,7 @@
 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.util.Log;
 
 import com.android.car.vehiclehal.VehiclePropValueBuilder;
@@ -35,10 +37,13 @@
 import org.junit.Before;
 import org.junit.Test;
 
+import java.util.concurrent.TimeUnit;
+
 /** Test retrieving the OBD2_FREEZE_FRAME property from VHAL */
 public class Obd2FreezeFrameTest {
     private static final String TAG = Utils.concatTag(Obd2FreezeFrameTest.class);
     private static final int DEFAULT_WAIT_TIMEOUT_MS = 5000;
+    private static final long EPSILON = TimeUnit.MICROSECONDS.toNanos(2000);
     private IVehicle mVehicle = null;
 
     @Before
@@ -68,7 +73,9 @@
                                   assertNotNull("OBD2_FREEZE_FRAME read OK; should not be null",
                                           freezeFrame);
                                   Log.i(TAG, "dump of OBD2_FREEZE_FRAME:\n" + freezeFrame);
-                                  assertEquals(freezeFrame.timestamp, timestamp);
+                                  //Timestamp will be changed to real time.
+                                  assertTrue(SystemClock.elapsedRealtimeNanos()
+                                          - freezeFrame.timestamp < EPSILON);
                               }
                               return true;
                           });
diff --git a/tools/emulator/VehicleHalProto_pb2.py b/tools/emulator/VehicleHalProto_pb2.py
index 3278ed7..6e964f6 100644
--- a/tools/emulator/VehicleHalProto_pb2.py
+++ b/tools/emulator/VehicleHalProto_pb2.py
@@ -1,153 +1,164 @@
+# -*- coding: utf-8 -*-
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
 # source: VehicleHalProto.proto
 
+import sys
+_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
 from google.protobuf.internal import enum_type_wrapper
 from google.protobuf import descriptor as _descriptor
 from google.protobuf import message as _message
 from google.protobuf import reflection as _reflection
-from google.protobuf import descriptor_pb2
+from google.protobuf import symbol_database as _symbol_database
 # @@protoc_insertion_point(imports)
 
+_sym_db = _symbol_database.Default()
+
 
 
 
 DESCRIPTOR = _descriptor.FileDescriptor(
   name='VehicleHalProto.proto',
-  package='emulator',
-  serialized_pb='\n\x15VehicleHalProto.proto\x12\x08\x65mulator\"\xba\x01\n\x11VehicleAreaConfig\x12\x0f\n\x07\x61rea_id\x18\x01 \x02(\x05\x12\x17\n\x0fmin_int32_value\x18\x02 \x01(\x11\x12\x17\n\x0fmax_int32_value\x18\x03 \x01(\x11\x12\x17\n\x0fmin_int64_value\x18\x04 \x01(\x12\x12\x17\n\x0fmax_int64_value\x18\x05 \x01(\x12\x12\x17\n\x0fmin_float_value\x18\x06 \x01(\x02\x12\x17\n\x0fmax_float_value\x18\x07 \x01(\x02\"\x9b\x02\n\x11VehiclePropConfig\x12\x0c\n\x04prop\x18\x01 \x02(\x05\x12\x0e\n\x06\x61\x63\x63\x65ss\x18\x02 \x01(\x05\x12\x13\n\x0b\x63hange_mode\x18\x03 \x01(\x05\x12\x12\n\nvalue_type\x18\x04 \x01(\x05\x12\x17\n\x0fsupported_areas\x18\x05 \x01(\x05\x12\x31\n\x0c\x61rea_configs\x18\x06 \x03(\x0b\x32\x1b.emulator.VehicleAreaConfig\x12\x14\n\x0c\x63onfig_flags\x18\x07 \x01(\x05\x12\x14\n\x0c\x63onfig_array\x18\x08 \x03(\x05\x12\x15\n\rconfig_string\x18\t \x01(\t\x12\x17\n\x0fmin_sample_rate\x18\n \x01(\x02\x12\x17\n\x0fmax_sample_rate\x18\x0b \x01(\x02\"\xf2\x01\n\x10VehiclePropValue\x12\x0c\n\x04prop\x18\x01 \x02(\x05\x12\x12\n\nvalue_type\x18\x02 \x01(\x05\x12\x11\n\ttimestamp\x18\x03 \x01(\x03\x12+\n\x06status\x18\n \x01(\x0e\x32\x1b.emulator.VehiclePropStatus\x12\x0f\n\x07\x61rea_id\x18\x04 \x01(\x05\x12\x14\n\x0cint32_values\x18\x05 \x03(\x11\x12\x14\n\x0cint64_values\x18\x06 \x03(\x12\x12\x14\n\x0c\x66loat_values\x18\x07 \x03(\x02\x12\x14\n\x0cstring_value\x18\x08 \x01(\t\x12\x13\n\x0b\x62ytes_value\x18\t \x01(\x0c\"/\n\x0eVehiclePropGet\x12\x0c\n\x04prop\x18\x01 \x02(\x05\x12\x0f\n\x07\x61rea_id\x18\x02 \x01(\x05\"\xd8\x01\n\x0f\x45mulatorMessage\x12#\n\x08msg_type\x18\x01 \x02(\x0e\x32\x11.emulator.MsgType\x12 \n\x06status\x18\x02 \x01(\x0e\x32\x10.emulator.Status\x12&\n\x04prop\x18\x03 \x03(\x0b\x32\x18.emulator.VehiclePropGet\x12+\n\x06\x63onfig\x18\x04 \x03(\x0b\x32\x1b.emulator.VehiclePropConfig\x12)\n\x05value\x18\x05 \x03(\x0b\x32\x1a.emulator.VehiclePropValue*\x8a\x02\n\x07MsgType\x12\x12\n\x0eGET_CONFIG_CMD\x10\x00\x12\x13\n\x0fGET_CONFIG_RESP\x10\x01\x12\x16\n\x12GET_CONFIG_ALL_CMD\x10\x02\x12\x17\n\x13GET_CONFIG_ALL_RESP\x10\x03\x12\x14\n\x10GET_PROPERTY_CMD\x10\x04\x12\x15\n\x11GET_PROPERTY_RESP\x10\x05\x12\x18\n\x14GET_PROPERTY_ALL_CMD\x10\x06\x12\x19\n\x15GET_PROPERTY_ALL_RESP\x10\x07\x12\x14\n\x10SET_PROPERTY_CMD\x10\x08\x12\x15\n\x11SET_PROPERTY_RESP\x10\t\x12\x16\n\x12SET_PROPERTY_ASYNC\x10\n*\xfb\x01\n\x06Status\x12\r\n\tRESULT_OK\x10\x00\x12\x11\n\rERROR_UNKNOWN\x10\x01\x12\x1b\n\x17\x45RROR_UNIMPLEMENTED_CMD\x10\x02\x12\x1a\n\x16\x45RROR_INVALID_PROPERTY\x10\x03\x12\x19\n\x15\x45RROR_INVALID_AREA_ID\x10\x04\x12 \n\x1c\x45RROR_PROPERTY_UNINITIALIZED\x10\x05\x12\x1d\n\x19\x45RROR_WRITE_ONLY_PROPERTY\x10\x06\x12\x1d\n\x19\x45RROR_MEMORY_ALLOC_FAILED\x10\x07\x12\x1b\n\x17\x45RROR_INVALID_OPERATION\x10\x08*>\n\x11VehiclePropStatus\x12\r\n\tAVAILABLE\x10\x00\x12\x0f\n\x0bUNAVAILABLE\x10\x01\x12\t\n\x05\x45RROR\x10\x02\x42\x02H\x03')
+  package='vhal_proto',
+  syntax='proto2',
+  serialized_options=None,
+  serialized_pb=_b('\n\x15VehicleHalProto.proto\x12\nvhal_proto\"\xba\x01\n\x11VehicleAreaConfig\x12\x0f\n\x07\x61rea_id\x18\x01 \x02(\x05\x12\x17\n\x0fmin_int32_value\x18\x02 \x01(\x11\x12\x17\n\x0fmax_int32_value\x18\x03 \x01(\x11\x12\x17\n\x0fmin_int64_value\x18\x04 \x01(\x12\x12\x17\n\x0fmax_int64_value\x18\x05 \x01(\x12\x12\x17\n\x0fmin_float_value\x18\x06 \x01(\x02\x12\x17\n\x0fmax_float_value\x18\x07 \x01(\x02\"\x9d\x02\n\x11VehiclePropConfig\x12\x0c\n\x04prop\x18\x01 \x02(\x05\x12\x0e\n\x06\x61\x63\x63\x65ss\x18\x02 \x01(\x05\x12\x13\n\x0b\x63hange_mode\x18\x03 \x01(\x05\x12\x12\n\nvalue_type\x18\x04 \x01(\x05\x12\x17\n\x0fsupported_areas\x18\x05 \x01(\x05\x12\x33\n\x0c\x61rea_configs\x18\x06 \x03(\x0b\x32\x1d.vhal_proto.VehicleAreaConfig\x12\x14\n\x0c\x63onfig_flags\x18\x07 \x01(\x05\x12\x14\n\x0c\x63onfig_array\x18\x08 \x03(\x05\x12\x15\n\rconfig_string\x18\t \x01(\t\x12\x17\n\x0fmin_sample_rate\x18\n \x01(\x02\x12\x17\n\x0fmax_sample_rate\x18\x0b \x01(\x02\"\xf4\x01\n\x10VehiclePropValue\x12\x0c\n\x04prop\x18\x01 \x02(\x05\x12\x12\n\nvalue_type\x18\x02 \x01(\x05\x12\x11\n\ttimestamp\x18\x03 \x01(\x03\x12-\n\x06status\x18\n \x01(\x0e\x32\x1d.vhal_proto.VehiclePropStatus\x12\x0f\n\x07\x61rea_id\x18\x04 \x01(\x05\x12\x14\n\x0cint32_values\x18\x05 \x03(\x11\x12\x14\n\x0cint64_values\x18\x06 \x03(\x12\x12\x14\n\x0c\x66loat_values\x18\x07 \x03(\x02\x12\x14\n\x0cstring_value\x18\x08 \x01(\t\x12\x13\n\x0b\x62ytes_value\x18\t \x01(\x0c\"/\n\x0eVehiclePropGet\x12\x0c\n\x04prop\x18\x01 \x02(\x05\x12\x0f\n\x07\x61rea_id\x18\x02 \x01(\x05\"\xe2\x01\n\x0f\x45mulatorMessage\x12%\n\x08msg_type\x18\x01 \x02(\x0e\x32\x13.vhal_proto.MsgType\x12\"\n\x06status\x18\x02 \x01(\x0e\x32\x12.vhal_proto.Status\x12(\n\x04prop\x18\x03 \x03(\x0b\x32\x1a.vhal_proto.VehiclePropGet\x12-\n\x06\x63onfig\x18\x04 \x03(\x0b\x32\x1d.vhal_proto.VehiclePropConfig\x12+\n\x05value\x18\x05 \x03(\x0b\x32\x1c.vhal_proto.VehiclePropValue*\x8a\x02\n\x07MsgType\x12\x12\n\x0eGET_CONFIG_CMD\x10\x00\x12\x13\n\x0fGET_CONFIG_RESP\x10\x01\x12\x16\n\x12GET_CONFIG_ALL_CMD\x10\x02\x12\x17\n\x13GET_CONFIG_ALL_RESP\x10\x03\x12\x14\n\x10GET_PROPERTY_CMD\x10\x04\x12\x15\n\x11GET_PROPERTY_RESP\x10\x05\x12\x18\n\x14GET_PROPERTY_ALL_CMD\x10\x06\x12\x19\n\x15GET_PROPERTY_ALL_RESP\x10\x07\x12\x14\n\x10SET_PROPERTY_CMD\x10\x08\x12\x15\n\x11SET_PROPERTY_RESP\x10\t\x12\x16\n\x12SET_PROPERTY_ASYNC\x10\n*\xfb\x01\n\x06Status\x12\r\n\tRESULT_OK\x10\x00\x12\x11\n\rERROR_UNKNOWN\x10\x01\x12\x1b\n\x17\x45RROR_UNIMPLEMENTED_CMD\x10\x02\x12\x1a\n\x16\x45RROR_INVALID_PROPERTY\x10\x03\x12\x19\n\x15\x45RROR_INVALID_AREA_ID\x10\x04\x12 \n\x1c\x45RROR_PROPERTY_UNINITIALIZED\x10\x05\x12\x1d\n\x19\x45RROR_WRITE_ONLY_PROPERTY\x10\x06\x12\x1d\n\x19\x45RROR_MEMORY_ALLOC_FAILED\x10\x07\x12\x1b\n\x17\x45RROR_INVALID_OPERATION\x10\x08*>\n\x11VehiclePropStatus\x12\r\n\tAVAILABLE\x10\x00\x12\x0f\n\x0bUNAVAILABLE\x10\x01\x12\t\n\x05\x45RROR\x10\x02')
+)
 
 _MSGTYPE = _descriptor.EnumDescriptor(
   name='MsgType',
-  full_name='emulator.MsgType',
+  full_name='vhal_proto.MsgType',
   filename=None,
   file=DESCRIPTOR,
   values=[
     _descriptor.EnumValueDescriptor(
       name='GET_CONFIG_CMD', index=0, number=0,
-      options=None,
+      serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='GET_CONFIG_RESP', index=1, number=1,
-      options=None,
+      serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='GET_CONFIG_ALL_CMD', index=2, number=2,
-      options=None,
+      serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='GET_CONFIG_ALL_RESP', index=3, number=3,
-      options=None,
+      serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='GET_PROPERTY_CMD', index=4, number=4,
-      options=None,
+      serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='GET_PROPERTY_RESP', index=5, number=5,
-      options=None,
+      serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='GET_PROPERTY_ALL_CMD', index=6, number=6,
-      options=None,
+      serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='GET_PROPERTY_ALL_RESP', index=7, number=7,
-      options=None,
+      serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='SET_PROPERTY_CMD', index=8, number=8,
-      options=None,
+      serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='SET_PROPERTY_RESP', index=9, number=9,
-      options=None,
+      serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='SET_PROPERTY_ASYNC', index=10, number=10,
-      options=None,
+      serialized_options=None,
       type=None),
   ],
   containing_type=None,
-  options=None,
-  serialized_start=1024,
-  serialized_end=1290,
+  serialized_options=None,
+  serialized_start=1040,
+  serialized_end=1306,
 )
+_sym_db.RegisterEnumDescriptor(_MSGTYPE)
 
 MsgType = enum_type_wrapper.EnumTypeWrapper(_MSGTYPE)
 _STATUS = _descriptor.EnumDescriptor(
   name='Status',
-  full_name='emulator.Status',
+  full_name='vhal_proto.Status',
   filename=None,
   file=DESCRIPTOR,
   values=[
     _descriptor.EnumValueDescriptor(
       name='RESULT_OK', index=0, number=0,
-      options=None,
+      serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='ERROR_UNKNOWN', index=1, number=1,
-      options=None,
+      serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='ERROR_UNIMPLEMENTED_CMD', index=2, number=2,
-      options=None,
+      serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='ERROR_INVALID_PROPERTY', index=3, number=3,
-      options=None,
+      serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='ERROR_INVALID_AREA_ID', index=4, number=4,
-      options=None,
+      serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='ERROR_PROPERTY_UNINITIALIZED', index=5, number=5,
-      options=None,
+      serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='ERROR_WRITE_ONLY_PROPERTY', index=6, number=6,
-      options=None,
+      serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='ERROR_MEMORY_ALLOC_FAILED', index=7, number=7,
-      options=None,
+      serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='ERROR_INVALID_OPERATION', index=8, number=8,
-      options=None,
+      serialized_options=None,
       type=None),
   ],
   containing_type=None,
-  options=None,
-  serialized_start=1293,
-  serialized_end=1544,
+  serialized_options=None,
+  serialized_start=1309,
+  serialized_end=1560,
 )
+_sym_db.RegisterEnumDescriptor(_STATUS)
 
 Status = enum_type_wrapper.EnumTypeWrapper(_STATUS)
 _VEHICLEPROPSTATUS = _descriptor.EnumDescriptor(
   name='VehiclePropStatus',
-  full_name='emulator.VehiclePropStatus',
+  full_name='vhal_proto.VehiclePropStatus',
   filename=None,
   file=DESCRIPTOR,
   values=[
     _descriptor.EnumValueDescriptor(
       name='AVAILABLE', index=0, number=0,
-      options=None,
+      serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='UNAVAILABLE', index=1, number=1,
-      options=None,
+      serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='ERROR', index=2, number=2,
-      options=None,
+      serialized_options=None,
       type=None),
   ],
   containing_type=None,
-  options=None,
-  serialized_start=1546,
-  serialized_end=1608,
+  serialized_options=None,
+  serialized_start=1562,
+  serialized_end=1624,
 )
+_sym_db.RegisterEnumDescriptor(_VEHICLEPROPSTATUS)
 
 VehiclePropStatus = enum_type_wrapper.EnumTypeWrapper(_VEHICLEPROPSTATUS)
 GET_CONFIG_CMD = 0
@@ -178,351 +189,366 @@
 
 _VEHICLEAREACONFIG = _descriptor.Descriptor(
   name='VehicleAreaConfig',
-  full_name='emulator.VehicleAreaConfig',
+  full_name='vhal_proto.VehicleAreaConfig',
   filename=None,
   file=DESCRIPTOR,
   containing_type=None,
   fields=[
     _descriptor.FieldDescriptor(
-      name='area_id', full_name='emulator.VehicleAreaConfig.area_id', index=0,
+      name='area_id', full_name='vhal_proto.VehicleAreaConfig.area_id', index=0,
       number=1, type=5, cpp_type=1, label=2,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='min_int32_value', full_name='emulator.VehicleAreaConfig.min_int32_value', index=1,
+      name='min_int32_value', full_name='vhal_proto.VehicleAreaConfig.min_int32_value', index=1,
       number=2, type=17, cpp_type=1, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='max_int32_value', full_name='emulator.VehicleAreaConfig.max_int32_value', index=2,
+      name='max_int32_value', full_name='vhal_proto.VehicleAreaConfig.max_int32_value', index=2,
       number=3, type=17, cpp_type=1, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='min_int64_value', full_name='emulator.VehicleAreaConfig.min_int64_value', index=3,
+      name='min_int64_value', full_name='vhal_proto.VehicleAreaConfig.min_int64_value', index=3,
       number=4, type=18, cpp_type=2, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='max_int64_value', full_name='emulator.VehicleAreaConfig.max_int64_value', index=4,
+      name='max_int64_value', full_name='vhal_proto.VehicleAreaConfig.max_int64_value', index=4,
       number=5, type=18, cpp_type=2, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='min_float_value', full_name='emulator.VehicleAreaConfig.min_float_value', index=5,
+      name='min_float_value', full_name='vhal_proto.VehicleAreaConfig.min_float_value', index=5,
       number=6, type=2, cpp_type=6, label=1,
-      has_default_value=False, default_value=0,
+      has_default_value=False, default_value=float(0),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='max_float_value', full_name='emulator.VehicleAreaConfig.max_float_value', index=6,
+      name='max_float_value', full_name='vhal_proto.VehicleAreaConfig.max_float_value', index=6,
       number=7, type=2, cpp_type=6, label=1,
-      has_default_value=False, default_value=0,
+      has_default_value=False, default_value=float(0),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
   ],
-  options=None,
+  serialized_options=None,
   is_extendable=False,
+  syntax='proto2',
   extension_ranges=[],
-  serialized_start=36,
-  serialized_end=222,
+  oneofs=[
+  ],
+  serialized_start=38,
+  serialized_end=224,
 )
 
 
 _VEHICLEPROPCONFIG = _descriptor.Descriptor(
   name='VehiclePropConfig',
-  full_name='emulator.VehiclePropConfig',
+  full_name='vhal_proto.VehiclePropConfig',
   filename=None,
   file=DESCRIPTOR,
   containing_type=None,
   fields=[
     _descriptor.FieldDescriptor(
-      name='prop', full_name='emulator.VehiclePropConfig.prop', index=0,
+      name='prop', full_name='vhal_proto.VehiclePropConfig.prop', index=0,
       number=1, type=5, cpp_type=1, label=2,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='access', full_name='emulator.VehiclePropConfig.access', index=1,
+      name='access', full_name='vhal_proto.VehiclePropConfig.access', index=1,
       number=2, type=5, cpp_type=1, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='change_mode', full_name='emulator.VehiclePropConfig.change_mode', index=2,
+      name='change_mode', full_name='vhal_proto.VehiclePropConfig.change_mode', index=2,
       number=3, type=5, cpp_type=1, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='value_type', full_name='emulator.VehiclePropConfig.value_type', index=3,
+      name='value_type', full_name='vhal_proto.VehiclePropConfig.value_type', index=3,
       number=4, type=5, cpp_type=1, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='supported_areas', full_name='emulator.VehiclePropConfig.supported_areas', index=4,
+      name='supported_areas', full_name='vhal_proto.VehiclePropConfig.supported_areas', index=4,
       number=5, type=5, cpp_type=1, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='area_configs', full_name='emulator.VehiclePropConfig.area_configs', index=5,
+      name='area_configs', full_name='vhal_proto.VehiclePropConfig.area_configs', index=5,
       number=6, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='config_flags', full_name='emulator.VehiclePropConfig.config_flags', index=6,
+      name='config_flags', full_name='vhal_proto.VehiclePropConfig.config_flags', index=6,
       number=7, type=5, cpp_type=1, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='config_array', full_name='emulator.VehiclePropConfig.config_array', index=7,
+      name='config_array', full_name='vhal_proto.VehiclePropConfig.config_array', index=7,
       number=8, type=5, cpp_type=1, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='config_string', full_name='emulator.VehiclePropConfig.config_string', index=8,
+      name='config_string', full_name='vhal_proto.VehiclePropConfig.config_string', index=8,
       number=9, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=unicode("", "utf-8"),
+      has_default_value=False, default_value=_b("").decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='min_sample_rate', full_name='emulator.VehiclePropConfig.min_sample_rate', index=9,
+      name='min_sample_rate', full_name='vhal_proto.VehiclePropConfig.min_sample_rate', index=9,
       number=10, type=2, cpp_type=6, label=1,
-      has_default_value=False, default_value=0,
+      has_default_value=False, default_value=float(0),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='max_sample_rate', full_name='emulator.VehiclePropConfig.max_sample_rate', index=10,
+      name='max_sample_rate', full_name='vhal_proto.VehiclePropConfig.max_sample_rate', index=10,
       number=11, type=2, cpp_type=6, label=1,
-      has_default_value=False, default_value=0,
+      has_default_value=False, default_value=float(0),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
   ],
-  options=None,
+  serialized_options=None,
   is_extendable=False,
+  syntax='proto2',
   extension_ranges=[],
-  serialized_start=225,
-  serialized_end=508,
+  oneofs=[
+  ],
+  serialized_start=227,
+  serialized_end=512,
 )
 
 
 _VEHICLEPROPVALUE = _descriptor.Descriptor(
   name='VehiclePropValue',
-  full_name='emulator.VehiclePropValue',
+  full_name='vhal_proto.VehiclePropValue',
   filename=None,
   file=DESCRIPTOR,
   containing_type=None,
   fields=[
     _descriptor.FieldDescriptor(
-      name='prop', full_name='emulator.VehiclePropValue.prop', index=0,
+      name='prop', full_name='vhal_proto.VehiclePropValue.prop', index=0,
       number=1, type=5, cpp_type=1, label=2,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='value_type', full_name='emulator.VehiclePropValue.value_type', index=1,
+      name='value_type', full_name='vhal_proto.VehiclePropValue.value_type', index=1,
       number=2, type=5, cpp_type=1, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='timestamp', full_name='emulator.VehiclePropValue.timestamp', index=2,
+      name='timestamp', full_name='vhal_proto.VehiclePropValue.timestamp', index=2,
       number=3, type=3, cpp_type=2, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='status', full_name='emulator.VehiclePropValue.status', index=3,
+      name='status', full_name='vhal_proto.VehiclePropValue.status', index=3,
       number=10, type=14, cpp_type=8, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='area_id', full_name='emulator.VehiclePropValue.area_id', index=4,
+      name='area_id', full_name='vhal_proto.VehiclePropValue.area_id', index=4,
       number=4, type=5, cpp_type=1, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='int32_values', full_name='emulator.VehiclePropValue.int32_values', index=5,
+      name='int32_values', full_name='vhal_proto.VehiclePropValue.int32_values', index=5,
       number=5, type=17, cpp_type=1, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='int64_values', full_name='emulator.VehiclePropValue.int64_values', index=6,
+      name='int64_values', full_name='vhal_proto.VehiclePropValue.int64_values', index=6,
       number=6, type=18, cpp_type=2, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='float_values', full_name='emulator.VehiclePropValue.float_values', index=7,
+      name='float_values', full_name='vhal_proto.VehiclePropValue.float_values', index=7,
       number=7, type=2, cpp_type=6, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='string_value', full_name='emulator.VehiclePropValue.string_value', index=8,
+      name='string_value', full_name='vhal_proto.VehiclePropValue.string_value', index=8,
       number=8, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=unicode("", "utf-8"),
+      has_default_value=False, default_value=_b("").decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='bytes_value', full_name='emulator.VehiclePropValue.bytes_value', index=9,
+      name='bytes_value', full_name='vhal_proto.VehiclePropValue.bytes_value', index=9,
       number=9, type=12, cpp_type=9, label=1,
-      has_default_value=False, default_value="",
+      has_default_value=False, default_value=_b(""),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
   ],
-  options=None,
+  serialized_options=None,
   is_extendable=False,
+  syntax='proto2',
   extension_ranges=[],
-  serialized_start=511,
-  serialized_end=753,
+  oneofs=[
+  ],
+  serialized_start=515,
+  serialized_end=759,
 )
 
 
 _VEHICLEPROPGET = _descriptor.Descriptor(
   name='VehiclePropGet',
-  full_name='emulator.VehiclePropGet',
+  full_name='vhal_proto.VehiclePropGet',
   filename=None,
   file=DESCRIPTOR,
   containing_type=None,
   fields=[
     _descriptor.FieldDescriptor(
-      name='prop', full_name='emulator.VehiclePropGet.prop', index=0,
+      name='prop', full_name='vhal_proto.VehiclePropGet.prop', index=0,
       number=1, type=5, cpp_type=1, label=2,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='area_id', full_name='emulator.VehiclePropGet.area_id', index=1,
+      name='area_id', full_name='vhal_proto.VehiclePropGet.area_id', index=1,
       number=2, type=5, cpp_type=1, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
   ],
-  options=None,
+  serialized_options=None,
   is_extendable=False,
+  syntax='proto2',
   extension_ranges=[],
-  serialized_start=755,
-  serialized_end=802,
+  oneofs=[
+  ],
+  serialized_start=761,
+  serialized_end=808,
 )
 
 
 _EMULATORMESSAGE = _descriptor.Descriptor(
   name='EmulatorMessage',
-  full_name='emulator.EmulatorMessage',
+  full_name='vhal_proto.EmulatorMessage',
   filename=None,
   file=DESCRIPTOR,
   containing_type=None,
   fields=[
     _descriptor.FieldDescriptor(
-      name='msg_type', full_name='emulator.EmulatorMessage.msg_type', index=0,
+      name='msg_type', full_name='vhal_proto.EmulatorMessage.msg_type', index=0,
       number=1, type=14, cpp_type=8, label=2,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='status', full_name='emulator.EmulatorMessage.status', index=1,
+      name='status', full_name='vhal_proto.EmulatorMessage.status', index=1,
       number=2, type=14, cpp_type=8, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='prop', full_name='emulator.EmulatorMessage.prop', index=2,
+      name='prop', full_name='vhal_proto.EmulatorMessage.prop', index=2,
       number=3, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='config', full_name='emulator.EmulatorMessage.config', index=3,
+      name='config', full_name='vhal_proto.EmulatorMessage.config', index=3,
       number=4, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='value', full_name='emulator.EmulatorMessage.value', index=4,
+      name='value', full_name='vhal_proto.EmulatorMessage.value', index=4,
       number=5, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      options=None),
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
   ],
-  options=None,
+  serialized_options=None,
   is_extendable=False,
+  syntax='proto2',
   extension_ranges=[],
-  serialized_start=805,
-  serialized_end=1021,
+  oneofs=[
+  ],
+  serialized_start=811,
+  serialized_end=1037,
 )
 
 _VEHICLEPROPCONFIG.fields_by_name['area_configs'].message_type = _VEHICLEAREACONFIG
@@ -537,38 +563,45 @@
 DESCRIPTOR.message_types_by_name['VehiclePropValue'] = _VEHICLEPROPVALUE
 DESCRIPTOR.message_types_by_name['VehiclePropGet'] = _VEHICLEPROPGET
 DESCRIPTOR.message_types_by_name['EmulatorMessage'] = _EMULATORMESSAGE
+DESCRIPTOR.enum_types_by_name['MsgType'] = _MSGTYPE
+DESCRIPTOR.enum_types_by_name['Status'] = _STATUS
+DESCRIPTOR.enum_types_by_name['VehiclePropStatus'] = _VEHICLEPROPSTATUS
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
-class VehicleAreaConfig(_message.Message):
-  __metaclass__ = _reflection.GeneratedProtocolMessageType
-  DESCRIPTOR = _VEHICLEAREACONFIG
+VehicleAreaConfig = _reflection.GeneratedProtocolMessageType('VehicleAreaConfig', (_message.Message,), {
+  'DESCRIPTOR' : _VEHICLEAREACONFIG,
+  '__module__' : 'VehicleHalProto_pb2'
+  # @@protoc_insertion_point(class_scope:vhal_proto.VehicleAreaConfig)
+  })
+_sym_db.RegisterMessage(VehicleAreaConfig)
 
-  # @@protoc_insertion_point(class_scope:emulator.VehicleAreaConfig)
+VehiclePropConfig = _reflection.GeneratedProtocolMessageType('VehiclePropConfig', (_message.Message,), {
+  'DESCRIPTOR' : _VEHICLEPROPCONFIG,
+  '__module__' : 'VehicleHalProto_pb2'
+  # @@protoc_insertion_point(class_scope:vhal_proto.VehiclePropConfig)
+  })
+_sym_db.RegisterMessage(VehiclePropConfig)
 
-class VehiclePropConfig(_message.Message):
-  __metaclass__ = _reflection.GeneratedProtocolMessageType
-  DESCRIPTOR = _VEHICLEPROPCONFIG
+VehiclePropValue = _reflection.GeneratedProtocolMessageType('VehiclePropValue', (_message.Message,), {
+  'DESCRIPTOR' : _VEHICLEPROPVALUE,
+  '__module__' : 'VehicleHalProto_pb2'
+  # @@protoc_insertion_point(class_scope:vhal_proto.VehiclePropValue)
+  })
+_sym_db.RegisterMessage(VehiclePropValue)
 
-  # @@protoc_insertion_point(class_scope:emulator.VehiclePropConfig)
+VehiclePropGet = _reflection.GeneratedProtocolMessageType('VehiclePropGet', (_message.Message,), {
+  'DESCRIPTOR' : _VEHICLEPROPGET,
+  '__module__' : 'VehicleHalProto_pb2'
+  # @@protoc_insertion_point(class_scope:vhal_proto.VehiclePropGet)
+  })
+_sym_db.RegisterMessage(VehiclePropGet)
 
-class VehiclePropValue(_message.Message):
-  __metaclass__ = _reflection.GeneratedProtocolMessageType
-  DESCRIPTOR = _VEHICLEPROPVALUE
-
-  # @@protoc_insertion_point(class_scope:emulator.VehiclePropValue)
-
-class VehiclePropGet(_message.Message):
-  __metaclass__ = _reflection.GeneratedProtocolMessageType
-  DESCRIPTOR = _VEHICLEPROPGET
-
-  # @@protoc_insertion_point(class_scope:emulator.VehiclePropGet)
-
-class EmulatorMessage(_message.Message):
-  __metaclass__ = _reflection.GeneratedProtocolMessageType
-  DESCRIPTOR = _EMULATORMESSAGE
-
-  # @@protoc_insertion_point(class_scope:emulator.EmulatorMessage)
+EmulatorMessage = _reflection.GeneratedProtocolMessageType('EmulatorMessage', (_message.Message,), {
+  'DESCRIPTOR' : _EMULATORMESSAGE,
+  '__module__' : 'VehicleHalProto_pb2'
+  # @@protoc_insertion_point(class_scope:vhal_proto.EmulatorMessage)
+  })
+_sym_db.RegisterMessage(EmulatorMessage)
 
 
-DESCRIPTOR.has_options = True
-DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), 'H\003')
 # @@protoc_insertion_point(module_scope)
diff --git a/tools/emulator/gui.py b/tools/emulator/gui.py
index 3a0161d..6607ce4 100755
--- a/tools/emulator/gui.py
+++ b/tools/emulator/gui.py
@@ -17,6 +17,7 @@
 
 # A simple GUI to remotely actuate the Vehicle HAL via the eumalator
 
+import argparse
 import sys
 from threading import Thread
 from PyQt4.QtCore import *
@@ -125,8 +126,12 @@
 
 
 if __name__ == '__main__':
+    parser = argparse.ArgumentParser(description='Vehicle HAL Driver UI')
+    parser.add_argument("--serial", "-s", action='store', dest='serial',
+        default=None, required=False, help='Select which device to connect to')
+    args = parser.parse_args()
     print "Starting VHal driver GUI"
-    vhal = Vhal(c.vhal_types_2_0)
+    vhal = Vhal(c.vhal_types_2_0, device=args.serial)
 
     # Start a receive thread to consume any replies from the vhal
     print "Starting receiver thread"
diff --git a/tools/emulator/vhal_const_generate.py b/tools/emulator/vhal_const_generate.py
index 77bb74b..cc9a118 100755
--- a/tools/emulator/vhal_const_generate.py
+++ b/tools/emulator/vhal_const_generate.py
@@ -120,6 +120,7 @@
     print("    TYPE_INT64   = [VEHICLEPROPERTYTYPE_INT64]", file=vhal_20_file)
     print("    TYPE_FLOAT   = [VEHICLEPROPERTYTYPE_FLOAT]", file=vhal_20_file)
     print("    TYPE_INT32S  = [VEHICLEPROPERTYTYPE_INT32_VEC]", file=vhal_20_file)
+    print("    TYPE_INT64S  = [VEHICLEPROPERTYTYPE_INT64_VEC]", file=vhal_20_file)
     print("    TYPE_FLOATS  = [VEHICLEPROPERTYTYPE_FLOAT_VEC]", file=vhal_20_file)
     print("    TYPE_MIXED   = [VEHICLEPROPERTYTYPE_MIXED]", file=vhal_20_file)
 
diff --git a/tools/emulator/vhal_consts_2_0.py b/tools/emulator/vhal_consts_2_0.py
index 648de6d..d4e3b61 100644
--- a/tools/emulator/vhal_consts_2_0.py
+++ b/tools/emulator/vhal_consts_2_0.py
@@ -15,6 +15,283 @@
 # DO NOT EDIT MANUALLY
 # This file was autogenerated by vhal_const_generate.py
 
+# VehicleUnit
+VEHICLEUNIT_SHOULD_NOT_USE = 0x0
+VEHICLEUNIT_METER_PER_SEC = 0x1
+VEHICLEUNIT_RPM = 0x2
+VEHICLEUNIT_HERTZ = 0x3
+VEHICLEUNIT_PERCENTILE = 0x10
+VEHICLEUNIT_MILLIMETER = 0x20
+VEHICLEUNIT_METER = 0x21
+VEHICLEUNIT_KILOMETER = 0x23
+VEHICLEUNIT_MILE = 0x24
+VEHICLEUNIT_CELSIUS = 0x30
+VEHICLEUNIT_FAHRENHEIT = 0x31
+VEHICLEUNIT_KELVIN = 0x32
+VEHICLEUNIT_MILLILITER = 0x40
+VEHICLEUNIT_LITER = 0x41
+VEHICLEUNIT_GALLON = 0x42
+VEHICLEUNIT_US_GALLON = 0x42
+VEHICLEUNIT_IMPERIAL_GALLON = 0x43
+VEHICLEUNIT_NANO_SECS = 0x50
+VEHICLEUNIT_SECS = 0x53
+VEHICLEUNIT_YEAR = 0x59
+VEHICLEUNIT_WATT_HOUR = 0x60
+VEHICLEUNIT_MILLIAMPERE = 0x61
+VEHICLEUNIT_MILLIVOLT = 0x62
+VEHICLEUNIT_MILLIWATTS = 0x63
+VEHICLEUNIT_AMPERE_HOURS = 0x64
+VEHICLEUNIT_KILOWATT_HOUR = 0x65
+VEHICLEUNIT_KILOPASCAL = 0x70
+VEHICLEUNIT_PSI = 0x71
+VEHICLEUNIT_BAR = 0x72
+VEHICLEUNIT_DEGREES = 0x80
+VEHICLEUNIT_MILES_PER_HOUR = 0x90
+VEHICLEUNIT_KILOMETERS_PER_HOUR = 0x91
+
+# VehicleLightSwitch
+VEHICLELIGHTSWITCH_OFF = 0x0
+VEHICLELIGHTSWITCH_ON = 0x1
+VEHICLELIGHTSWITCH_DAYTIME_RUNNING = 0x2
+VEHICLELIGHTSWITCH_AUTOMATIC = 0x100
+
+# VmsMessageWithLayerIntegerValuesIndex
+VMSMESSAGEWITHLAYERINTEGERVALUESINDEX_LAYER_TYPE = 0x1
+VMSMESSAGEWITHLAYERINTEGERVALUESINDEX_LAYER_SUBTYPE = 0x2
+VMSMESSAGEWITHLAYERINTEGERVALUESINDEX_LAYER_VERSION = 0x3
+
+# VehiclePropertyGroup
+VEHICLEPROPERTYGROUP_SYSTEM = 0x10000000
+VEHICLEPROPERTYGROUP_VENDOR = 0x20000000
+VEHICLEPROPERTYGROUP_MASK = 0xf0000000
+
+# VehicleApPowerStateShutdownParam
+VEHICLEAPPOWERSTATESHUTDOWNPARAM_SHUTDOWN_IMMEDIATELY = 0x1
+VEHICLEAPPOWERSTATESHUTDOWNPARAM_CAN_SLEEP = 0x2
+VEHICLEAPPOWERSTATESHUTDOWNPARAM_SHUTDOWN_ONLY = 0x3
+
+# Obd2CommonIgnitionMonitors
+OBD2COMMONIGNITIONMONITORS_COMPONENTS_AVAILABLE = 0x1
+OBD2COMMONIGNITIONMONITORS_COMPONENTS_INCOMPLETE = 0x2
+OBD2COMMONIGNITIONMONITORS_FUEL_SYSTEM_AVAILABLE = 0x4
+OBD2COMMONIGNITIONMONITORS_FUEL_SYSTEM_INCOMPLETE = 0x8
+OBD2COMMONIGNITIONMONITORS_MISFIRE_AVAILABLE = 0x10
+OBD2COMMONIGNITIONMONITORS_MISFIRE_INCOMPLETE = 0x20
+
+# PortLocationType
+PORTLOCATIONTYPE_UNKNOWN = 0x0
+PORTLOCATIONTYPE_FRONT_LEFT = 0x1
+PORTLOCATIONTYPE_FRONT_RIGHT = 0x2
+PORTLOCATIONTYPE_REAR_RIGHT = 0x3
+PORTLOCATIONTYPE_REAR_LEFT = 0x4
+PORTLOCATIONTYPE_FRONT = 0x5
+PORTLOCATIONTYPE_REAR = 0x6
+
+# Obd2SparkIgnitionMonitors
+OBD2SPARKIGNITIONMONITORS_EGR_AVAILABLE = 0x40
+OBD2SPARKIGNITIONMONITORS_EGR_INCOMPLETE = 0x80
+OBD2SPARKIGNITIONMONITORS_OXYGEN_SENSOR_HEATER_AVAILABLE = 0x100
+OBD2SPARKIGNITIONMONITORS_OXYGEN_SENSOR_HEATER_INCOMPLETE = 0x200
+OBD2SPARKIGNITIONMONITORS_OXYGEN_SENSOR_AVAILABLE = 0x400
+OBD2SPARKIGNITIONMONITORS_OXYGEN_SENSOR_INCOMPLETE = 0x800
+OBD2SPARKIGNITIONMONITORS_AC_REFRIGERANT_AVAILABLE = 0x1000
+OBD2SPARKIGNITIONMONITORS_AC_REFRIGERANT_INCOMPLETE = 0x2000
+OBD2SPARKIGNITIONMONITORS_SECONDARY_AIR_SYSTEM_AVAILABLE = 0x4000
+OBD2SPARKIGNITIONMONITORS_SECONDARY_AIR_SYSTEM_INCOMPLETE = 0x8000
+OBD2SPARKIGNITIONMONITORS_EVAPORATIVE_SYSTEM_AVAILABLE = 0x10000
+OBD2SPARKIGNITIONMONITORS_EVAPORATIVE_SYSTEM_INCOMPLETE = 0x20000
+OBD2SPARKIGNITIONMONITORS_HEATED_CATALYST_AVAILABLE = 0x40000
+OBD2SPARKIGNITIONMONITORS_HEATED_CATALYST_INCOMPLETE = 0x80000
+OBD2SPARKIGNITIONMONITORS_CATALYST_AVAILABLE = 0x100000
+OBD2SPARKIGNITIONMONITORS_CATALYST_INCOMPLETE = 0x200000
+
+# VmsSubscriptionsStateIntegerValuesIndex
+VMSSUBSCRIPTIONSSTATEINTEGERVALUESINDEX_SEQUENCE_NUMBER = 0x1
+VMSSUBSCRIPTIONSSTATEINTEGERVALUESINDEX_NUMBER_OF_LAYERS = 0x2
+VMSSUBSCRIPTIONSSTATEINTEGERVALUESINDEX_NUMBER_OF_ASSOCIATED_LAYERS = 0x3
+VMSSUBSCRIPTIONSSTATEINTEGERVALUESINDEX_SUBSCRIPTIONS_START = 0x4
+
+# VehicleApPowerStateReq
+VEHICLEAPPOWERSTATEREQ_ON = 0x0
+VEHICLEAPPOWERSTATEREQ_SHUTDOWN_PREPARE = 0x1
+VEHICLEAPPOWERSTATEREQ_CANCEL_SHUTDOWN = 0x2
+VEHICLEAPPOWERSTATEREQ_FINISHED = 0x3
+
+# VehicleApPowerStateReqIndex
+VEHICLEAPPOWERSTATEREQINDEX_STATE = 0x0
+VEHICLEAPPOWERSTATEREQINDEX_ADDITIONAL = 0x1
+
+# Obd2IgnitionMonitorKind
+OBD2IGNITIONMONITORKIND_SPARK = 0x0
+OBD2IGNITIONMONITORKIND_COMPRESSION = 0x1
+
+# VehiclePropertyAccess
+VEHICLEPROPERTYACCESS_NONE = 0x0
+VEHICLEPROPERTYACCESS_READ = 0x1
+VEHICLEPROPERTYACCESS_WRITE = 0x2
+VEHICLEPROPERTYACCESS_READ_WRITE = 0x3
+
+# VehicleOilLevel
+VEHICLEOILLEVEL_CRITICALLY_LOW = 0x0
+VEHICLEOILLEVEL_LOW = 0x1
+VEHICLEOILLEVEL_NORMAL = 0x2
+VEHICLEOILLEVEL_HIGH = 0x3
+VEHICLEOILLEVEL_ERROR = 0x4
+
+# VmsBaseMessageIntegerValuesIndex
+VMSBASEMESSAGEINTEGERVALUESINDEX_MESSAGE_TYPE = 0x0
+
+# StatusCode
+STATUSCODE_OK = 0x0
+STATUSCODE_TRY_AGAIN = 0x1
+STATUSCODE_INVALID_ARG = 0x2
+STATUSCODE_NOT_AVAILABLE = 0x3
+STATUSCODE_ACCESS_DENIED = 0x4
+STATUSCODE_INTERNAL_ERROR = 0x5
+
+# VehicleLightState
+VEHICLELIGHTSTATE_OFF = 0x0
+VEHICLELIGHTSTATE_ON = 0x1
+VEHICLELIGHTSTATE_DAYTIME_RUNNING = 0x2
+
+# VmsStartSessionMessageIntegerValuesIndex
+VMSSTARTSESSIONMESSAGEINTEGERVALUESINDEX_SERVICE_ID = 0x1
+VMSSTARTSESSIONMESSAGEINTEGERVALUESINDEX_CLIENT_ID = 0x2
+
+# VmsPublisherInformationIntegerValuesIndex
+VMSPUBLISHERINFORMATIONINTEGERVALUESINDEX_PUBLISHER_ID = 0x1
+
+# VehiclePropertyChangeMode
+VEHICLEPROPERTYCHANGEMODE_STATIC = 0x0
+VEHICLEPROPERTYCHANGEMODE_ON_CHANGE = 0x1
+VEHICLEPROPERTYCHANGEMODE_CONTINUOUS = 0x2
+
+# VmsMessageType
+VMSMESSAGETYPE_SUBSCRIBE = 0x1
+VMSMESSAGETYPE_SUBSCRIBE_TO_PUBLISHER = 0x2
+VMSMESSAGETYPE_UNSUBSCRIBE = 0x3
+VMSMESSAGETYPE_UNSUBSCRIBE_TO_PUBLISHER = 0x4
+VMSMESSAGETYPE_OFFERING = 0x5
+VMSMESSAGETYPE_AVAILABILITY_REQUEST = 0x6
+VMSMESSAGETYPE_SUBSCRIPTIONS_REQUEST = 0x7
+VMSMESSAGETYPE_AVAILABILITY_RESPONSE = 0x8
+VMSMESSAGETYPE_AVAILABILITY_CHANGE = 0x9
+VMSMESSAGETYPE_SUBSCRIPTIONS_RESPONSE = 0xa
+VMSMESSAGETYPE_SUBSCRIPTIONS_CHANGE = 0xb
+VMSMESSAGETYPE_DATA = 0xc
+VMSMESSAGETYPE_PUBLISHER_ID_REQUEST = 0xd
+VMSMESSAGETYPE_PUBLISHER_ID_RESPONSE = 0xe
+VMSMESSAGETYPE_PUBLISHER_INFORMATION_REQUEST = 0xf
+VMSMESSAGETYPE_PUBLISHER_INFORMATION_RESPONSE = 0x10
+VMSMESSAGETYPE_START_SESSION = 0x11
+VMSMESSAGETYPE_LAST_VMS_MESSAGE_TYPE = 0x11
+
+# DiagnosticIntegerSensorIndex
+DIAGNOSTICINTEGERSENSORINDEX_FUEL_SYSTEM_STATUS = 0x0
+DIAGNOSTICINTEGERSENSORINDEX_MALFUNCTION_INDICATOR_LIGHT_ON = 0x1
+DIAGNOSTICINTEGERSENSORINDEX_IGNITION_MONITORS_SUPPORTED = 0x2
+DIAGNOSTICINTEGERSENSORINDEX_IGNITION_SPECIFIC_MONITORS = 0x3
+DIAGNOSTICINTEGERSENSORINDEX_INTAKE_AIR_TEMPERATURE = 0x4
+DIAGNOSTICINTEGERSENSORINDEX_COMMANDED_SECONDARY_AIR_STATUS = 0x5
+DIAGNOSTICINTEGERSENSORINDEX_NUM_OXYGEN_SENSORS_PRESENT = 0x6
+DIAGNOSTICINTEGERSENSORINDEX_RUNTIME_SINCE_ENGINE_START = 0x7
+DIAGNOSTICINTEGERSENSORINDEX_DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON = 0x8
+DIAGNOSTICINTEGERSENSORINDEX_WARMUPS_SINCE_CODES_CLEARED = 0x9
+DIAGNOSTICINTEGERSENSORINDEX_DISTANCE_TRAVELED_SINCE_CODES_CLEARED = 0xa
+DIAGNOSTICINTEGERSENSORINDEX_ABSOLUTE_BAROMETRIC_PRESSURE = 0xb
+DIAGNOSTICINTEGERSENSORINDEX_CONTROL_MODULE_VOLTAGE = 0xc
+DIAGNOSTICINTEGERSENSORINDEX_AMBIENT_AIR_TEMPERATURE = 0xd
+DIAGNOSTICINTEGERSENSORINDEX_TIME_WITH_MALFUNCTION_LIGHT_ON = 0xe
+DIAGNOSTICINTEGERSENSORINDEX_TIME_SINCE_TROUBLE_CODES_CLEARED = 0xf
+DIAGNOSTICINTEGERSENSORINDEX_MAX_FUEL_AIR_EQUIVALENCE_RATIO = 0x10
+DIAGNOSTICINTEGERSENSORINDEX_MAX_OXYGEN_SENSOR_VOLTAGE = 0x11
+DIAGNOSTICINTEGERSENSORINDEX_MAX_OXYGEN_SENSOR_CURRENT = 0x12
+DIAGNOSTICINTEGERSENSORINDEX_MAX_INTAKE_MANIFOLD_ABSOLUTE_PRESSURE = 0x13
+DIAGNOSTICINTEGERSENSORINDEX_MAX_AIR_FLOW_RATE_FROM_MASS_AIR_FLOW_SENSOR = 0x14
+DIAGNOSTICINTEGERSENSORINDEX_FUEL_TYPE = 0x15
+DIAGNOSTICINTEGERSENSORINDEX_FUEL_RAIL_ABSOLUTE_PRESSURE = 0x16
+DIAGNOSTICINTEGERSENSORINDEX_ENGINE_OIL_TEMPERATURE = 0x17
+DIAGNOSTICINTEGERSENSORINDEX_DRIVER_DEMAND_PERCENT_TORQUE = 0x18
+DIAGNOSTICINTEGERSENSORINDEX_ENGINE_ACTUAL_PERCENT_TORQUE = 0x19
+DIAGNOSTICINTEGERSENSORINDEX_ENGINE_REFERENCE_PERCENT_TORQUE = 0x1a
+DIAGNOSTICINTEGERSENSORINDEX_ENGINE_PERCENT_TORQUE_DATA_IDLE = 0x1b
+DIAGNOSTICINTEGERSENSORINDEX_ENGINE_PERCENT_TORQUE_DATA_POINT1 = 0x1c
+DIAGNOSTICINTEGERSENSORINDEX_ENGINE_PERCENT_TORQUE_DATA_POINT2 = 0x1d
+DIAGNOSTICINTEGERSENSORINDEX_ENGINE_PERCENT_TORQUE_DATA_POINT3 = 0x1e
+DIAGNOSTICINTEGERSENSORINDEX_ENGINE_PERCENT_TORQUE_DATA_POINT4 = 0x1f
+DIAGNOSTICINTEGERSENSORINDEX_LAST_SYSTEM_INDEX = 0x1f
+
+# VmsMessageWithLayerAndPublisherIdIntegerValuesIndex
+VMSMESSAGEWITHLAYERANDPUBLISHERIDINTEGERVALUESINDEX_PUBLISHER_ID = 0x4
+
+# VmsOfferingMessageIntegerValuesIndex
+VMSOFFERINGMESSAGEINTEGERVALUESINDEX_PUBLISHER_ID = 0x1
+VMSOFFERINGMESSAGEINTEGERVALUESINDEX_NUMBER_OF_OFFERS = 0x2
+VMSOFFERINGMESSAGEINTEGERVALUESINDEX_OFFERING_START = 0x3
+
+# VehicleApPowerStateConfigFlag
+VEHICLEAPPOWERSTATECONFIGFLAG_ENABLE_DEEP_SLEEP_FLAG = 0x1
+VEHICLEAPPOWERSTATECONFIGFLAG_CONFIG_SUPPORT_TIMER_POWER_ON_FLAG = 0x2
+
+# FuelType
+FUELTYPE_FUEL_TYPE_UNKNOWN = 0x0
+FUELTYPE_FUEL_TYPE_UNLEADED = 0x1
+FUELTYPE_FUEL_TYPE_LEADED = 0x2
+FUELTYPE_FUEL_TYPE_DIESEL_1 = 0x3
+FUELTYPE_FUEL_TYPE_DIESEL_2 = 0x4
+FUELTYPE_FUEL_TYPE_BIODIESEL = 0x5
+FUELTYPE_FUEL_TYPE_E85 = 0x6
+FUELTYPE_FUEL_TYPE_LPG = 0x7
+FUELTYPE_FUEL_TYPE_CNG = 0x8
+FUELTYPE_FUEL_TYPE_LNG = 0x9
+FUELTYPE_FUEL_TYPE_ELECTRIC = 0xa
+FUELTYPE_FUEL_TYPE_HYDROGEN = 0xb
+FUELTYPE_FUEL_TYPE_OTHER = 0xc
+
+# VehicleSeatOccupancyState
+VEHICLESEATOCCUPANCYSTATE_UNKNOWN = 0x0
+VEHICLESEATOCCUPANCYSTATE_VACANT = 0x1
+VEHICLESEATOCCUPANCYSTATE_OCCUPIED = 0x2
+
+# VehicleIgnitionState
+VEHICLEIGNITIONSTATE_UNDEFINED = 0x0
+VEHICLEIGNITIONSTATE_LOCK = 0x1
+VEHICLEIGNITIONSTATE_OFF = 0x2
+VEHICLEIGNITIONSTATE_ACC = 0x3
+VEHICLEIGNITIONSTATE_ON = 0x4
+VEHICLEIGNITIONSTATE_START = 0x5
+
+# VehicleAreaSeat
+VEHICLEAREASEAT_ROW_1_LEFT = 0x1
+VEHICLEAREASEAT_ROW_1_CENTER = 0x2
+VEHICLEAREASEAT_ROW_1_RIGHT = 0x4
+VEHICLEAREASEAT_ROW_2_LEFT = 0x10
+VEHICLEAREASEAT_ROW_2_CENTER = 0x20
+VEHICLEAREASEAT_ROW_2_RIGHT = 0x40
+VEHICLEAREASEAT_ROW_3_LEFT = 0x100
+VEHICLEAREASEAT_ROW_3_CENTER = 0x200
+VEHICLEAREASEAT_ROW_3_RIGHT = 0x400
+
+# VehicleTurnSignal
+VEHICLETURNSIGNAL_NONE = 0x0
+VEHICLETURNSIGNAL_RIGHT = 0x1
+VEHICLETURNSIGNAL_LEFT = 0x2
+
+# EvConnectorType
+EVCONNECTORTYPE_UNKNOWN = 0x0
+EVCONNECTORTYPE_IEC_TYPE_1_AC = 0x1
+EVCONNECTORTYPE_IEC_TYPE_2_AC = 0x2
+EVCONNECTORTYPE_IEC_TYPE_3_AC = 0x3
+EVCONNECTORTYPE_IEC_TYPE_4_DC = 0x4
+EVCONNECTORTYPE_IEC_TYPE_1_CCS_DC = 0x5
+EVCONNECTORTYPE_IEC_TYPE_2_CCS_DC = 0x6
+EVCONNECTORTYPE_TESLA_ROADSTER = 0x7
+EVCONNECTORTYPE_TESLA_HPWC = 0x8
+EVCONNECTORTYPE_TESLA_SUPERCHARGER = 0x9
+EVCONNECTORTYPE_GBT_AC = 0xa
+EVCONNECTORTYPE_GBT_DC = 0xb
+EVCONNECTORTYPE_OTHER = 0x65
+
 # VehiclePropertyType
 VEHICLEPROPERTYTYPE_STRING = 0x100000
 VEHICLEPROPERTYTYPE_BOOLEAN = 0x200000
@@ -28,19 +305,102 @@
 VEHICLEPROPERTYTYPE_MIXED = 0xe00000
 VEHICLEPROPERTYTYPE_MASK = 0xff0000
 
-# VehicleArea
-VEHICLEAREA_GLOBAL = 0x1000000
-VEHICLEAREA_WINDOW = 0x3000000
-VEHICLEAREA_MIRROR = 0x4000000
-VEHICLEAREA_SEAT = 0x5000000
-VEHICLEAREA_DOOR = 0x6000000
-VEHICLEAREA_WHEEL = 0x7000000
-VEHICLEAREA_MASK = 0xf000000
+# VehicleAreaMirror
+VEHICLEAREAMIRROR_DRIVER_LEFT = 0x1
+VEHICLEAREAMIRROR_DRIVER_RIGHT = 0x2
+VEHICLEAREAMIRROR_DRIVER_CENTER = 0x4
 
-# VehiclePropertyGroup
-VEHICLEPROPERTYGROUP_SYSTEM = 0x10000000
-VEHICLEPROPERTYGROUP_VENDOR = 0x20000000
-VEHICLEPROPERTYGROUP_MASK = 0xf0000000
+# Obd2FuelSystemStatus
+OBD2FUELSYSTEMSTATUS_OPEN_INSUFFICIENT_ENGINE_TEMPERATURE = 0x1
+OBD2FUELSYSTEMSTATUS_CLOSED_LOOP = 0x2
+OBD2FUELSYSTEMSTATUS_OPEN_ENGINE_LOAD_OR_DECELERATION = 0x4
+OBD2FUELSYSTEMSTATUS_OPEN_SYSTEM_FAILURE = 0x8
+OBD2FUELSYSTEMSTATUS_CLOSED_LOOP_BUT_FEEDBACK_FAULT = 0x10
+
+# Obd2SecondaryAirStatus
+OBD2SECONDARYAIRSTATUS_UPSTREAM = 0x1
+OBD2SECONDARYAIRSTATUS_DOWNSTREAM_OF_CATALYCIC_CONVERTER = 0x2
+OBD2SECONDARYAIRSTATUS_FROM_OUTSIDE_OR_OFF = 0x4
+OBD2SECONDARYAIRSTATUS_PUMP_ON_FOR_DIAGNOSTICS = 0x8
+
+# VehicleAreaWheel
+VEHICLEAREAWHEEL_UNKNOWN = 0x0
+VEHICLEAREAWHEEL_LEFT_FRONT = 0x1
+VEHICLEAREAWHEEL_RIGHT_FRONT = 0x2
+VEHICLEAREAWHEEL_LEFT_REAR = 0x4
+VEHICLEAREAWHEEL_RIGHT_REAR = 0x8
+
+# VehicleGear
+VEHICLEGEAR_GEAR_NEUTRAL = 0x1
+VEHICLEGEAR_GEAR_REVERSE = 0x2
+VEHICLEGEAR_GEAR_PARK = 0x4
+VEHICLEGEAR_GEAR_DRIVE = 0x8
+VEHICLEGEAR_GEAR_1 = 0x10
+VEHICLEGEAR_GEAR_2 = 0x20
+VEHICLEGEAR_GEAR_3 = 0x40
+VEHICLEGEAR_GEAR_4 = 0x80
+VEHICLEGEAR_GEAR_5 = 0x100
+VEHICLEGEAR_GEAR_6 = 0x200
+VEHICLEGEAR_GEAR_7 = 0x400
+VEHICLEGEAR_GEAR_8 = 0x800
+VEHICLEGEAR_GEAR_9 = 0x1000
+
+# VmsAvailabilityStateIntegerValuesIndex
+VMSAVAILABILITYSTATEINTEGERVALUESINDEX_SEQUENCE_NUMBER = 0x1
+VMSAVAILABILITYSTATEINTEGERVALUESINDEX_NUMBER_OF_ASSOCIATED_LAYERS = 0x2
+VMSAVAILABILITYSTATEINTEGERVALUESINDEX_LAYERS_START = 0x3
+
+# VehicleHwKeyInputAction
+VEHICLEHWKEYINPUTACTION_ACTION_DOWN = 0x0
+VEHICLEHWKEYINPUTACTION_ACTION_UP = 0x1
+
+# VehicleApPowerStateReport
+VEHICLEAPPOWERSTATEREPORT_WAIT_FOR_VHAL = 0x1
+VEHICLEAPPOWERSTATEREPORT_DEEP_SLEEP_ENTRY = 0x2
+VEHICLEAPPOWERSTATEREPORT_DEEP_SLEEP_EXIT = 0x3
+VEHICLEAPPOWERSTATEREPORT_SHUTDOWN_POSTPONE = 0x4
+VEHICLEAPPOWERSTATEREPORT_SHUTDOWN_START = 0x5
+VEHICLEAPPOWERSTATEREPORT_ON = 0x6
+VEHICLEAPPOWERSTATEREPORT_SHUTDOWN_PREPARE = 0x7
+VEHICLEAPPOWERSTATEREPORT_SHUTDOWN_CANCELLED = 0x8
+
+# VehicleDisplay
+VEHICLEDISPLAY_MAIN = 0x0
+VEHICLEDISPLAY_INSTRUMENT_CLUSTER = 0x1
+
+# Obd2CompressionIgnitionMonitors
+OBD2COMPRESSIONIGNITIONMONITORS_EGR_OR_VVT_AVAILABLE = 0x40
+OBD2COMPRESSIONIGNITIONMONITORS_EGR_OR_VVT_INCOMPLETE = 0x80
+OBD2COMPRESSIONIGNITIONMONITORS_PM_FILTER_AVAILABLE = 0x100
+OBD2COMPRESSIONIGNITIONMONITORS_PM_FILTER_INCOMPLETE = 0x200
+OBD2COMPRESSIONIGNITIONMONITORS_EXHAUST_GAS_SENSOR_AVAILABLE = 0x400
+OBD2COMPRESSIONIGNITIONMONITORS_EXHAUST_GAS_SENSOR_INCOMPLETE = 0x800
+OBD2COMPRESSIONIGNITIONMONITORS_BOOST_PRESSURE_AVAILABLE = 0x1000
+OBD2COMPRESSIONIGNITIONMONITORS_BOOST_PRESSURE_INCOMPLETE = 0x2000
+OBD2COMPRESSIONIGNITIONMONITORS_NOx_SCR_AVAILABLE = 0x4000
+OBD2COMPRESSIONIGNITIONMONITORS_NOx_SCR_INCOMPLETE = 0x8000
+OBD2COMPRESSIONIGNITIONMONITORS_NMHC_CATALYST_AVAILABLE = 0x10000
+OBD2COMPRESSIONIGNITIONMONITORS_NMHC_CATALYST_INCOMPLETE = 0x20000
+
+# VehicleHvacFanDirection
+VEHICLEHVACFANDIRECTION_FACE = 0x1
+VEHICLEHVACFANDIRECTION_FLOOR = 0x2
+VEHICLEHVACFANDIRECTION_DEFROST = 0x4
+
+# VehicleAreaDoor
+VEHICLEAREADOOR_ROW_1_LEFT = 0x1
+VEHICLEAREADOOR_ROW_1_RIGHT = 0x4
+VEHICLEAREADOOR_ROW_2_LEFT = 0x10
+VEHICLEAREADOOR_ROW_2_RIGHT = 0x40
+VEHICLEAREADOOR_ROW_3_LEFT = 0x100
+VEHICLEAREADOOR_ROW_3_RIGHT = 0x400
+VEHICLEAREADOOR_HOOD = 0x10000000
+VEHICLEAREADOOR_REAR = 0x20000000
+
+# SubscribeFlags
+SUBSCRIBEFLAGS_UNDEFINED = 0x0
+SUBSCRIBEFLAGS_EVENTS_FROM_CAR = 0x1
+SUBSCRIBEFLAGS_EVENTS_FROM_ANDROID = 0x2
 
 # VehicleProperty
 VEHICLEPROPERTY_INVALID = 0x0
@@ -172,303 +532,6 @@
 VEHICLEPROPERTY_READING_LIGHTS_STATE = 0x15400f03
 VEHICLEPROPERTY_READING_LIGHTS_SWITCH = 0x15400f04
 
-# VehicleSeatOccupancyState
-VEHICLESEATOCCUPANCYSTATE_UNKNOWN = 0x0
-VEHICLESEATOCCUPANCYSTATE_VACANT = 0x1
-VEHICLESEATOCCUPANCYSTATE_OCCUPIED = 0x2
-
-# VehicleLightState
-VEHICLELIGHTSTATE_OFF = 0x0
-VEHICLELIGHTSTATE_ON = 0x1
-VEHICLELIGHTSTATE_DAYTIME_RUNNING = 0x2
-
-# VehicleLightSwitch
-VEHICLELIGHTSWITCH_OFF = 0x0
-VEHICLELIGHTSWITCH_ON = 0x1
-VEHICLELIGHTSWITCH_DAYTIME_RUNNING = 0x2
-VEHICLELIGHTSWITCH_AUTOMATIC = 0x100
-
-# EvConnectorType
-EVCONNECTORTYPE_UNKNOWN = 0x0
-EVCONNECTORTYPE_IEC_TYPE_1_AC = 0x1
-EVCONNECTORTYPE_IEC_TYPE_2_AC = 0x2
-EVCONNECTORTYPE_IEC_TYPE_3_AC = 0x3
-EVCONNECTORTYPE_IEC_TYPE_4_DC = 0x4
-EVCONNECTORTYPE_IEC_TYPE_1_CCS_DC = 0x5
-EVCONNECTORTYPE_IEC_TYPE_2_CCS_DC = 0x6
-EVCONNECTORTYPE_TESLA_ROADSTER = 0x7
-EVCONNECTORTYPE_TESLA_HPWC = 0x8
-EVCONNECTORTYPE_TESLA_SUPERCHARGER = 0x9
-EVCONNECTORTYPE_GBT_AC = 0xa
-EVCONNECTORTYPE_GBT_DC = 0xb
-EVCONNECTORTYPE_OTHER = 0x65
-
-# PortLocationType
-PORTLOCATIONTYPE_UNKNOWN = 0x0
-PORTLOCATIONTYPE_FRONT_LEFT = 0x1
-PORTLOCATIONTYPE_FRONT_RIGHT = 0x2
-PORTLOCATIONTYPE_REAR_RIGHT = 0x3
-PORTLOCATIONTYPE_REAR_LEFT = 0x4
-PORTLOCATIONTYPE_FRONT = 0x5
-PORTLOCATIONTYPE_REAR = 0x6
-
-# FuelType
-FUELTYPE_FUEL_TYPE_UNKNOWN = 0x0
-FUELTYPE_FUEL_TYPE_UNLEADED = 0x1
-FUELTYPE_FUEL_TYPE_LEADED = 0x2
-FUELTYPE_FUEL_TYPE_DIESEL_1 = 0x3
-FUELTYPE_FUEL_TYPE_DIESEL_2 = 0x4
-FUELTYPE_FUEL_TYPE_BIODIESEL = 0x5
-FUELTYPE_FUEL_TYPE_E85 = 0x6
-FUELTYPE_FUEL_TYPE_LPG = 0x7
-FUELTYPE_FUEL_TYPE_CNG = 0x8
-FUELTYPE_FUEL_TYPE_LNG = 0x9
-FUELTYPE_FUEL_TYPE_ELECTRIC = 0xa
-FUELTYPE_FUEL_TYPE_HYDROGEN = 0xb
-FUELTYPE_FUEL_TYPE_OTHER = 0xc
-
-# VehicleHvacFanDirection
-VEHICLEHVACFANDIRECTION_FACE = 0x1
-VEHICLEHVACFANDIRECTION_FLOOR = 0x2
-VEHICLEHVACFANDIRECTION_DEFROST = 0x4
-
-# VehicleOilLevel
-VEHICLEOILLEVEL_CRITICALLY_LOW = 0x0
-VEHICLEOILLEVEL_LOW = 0x1
-VEHICLEOILLEVEL_NORMAL = 0x2
-VEHICLEOILLEVEL_HIGH = 0x3
-VEHICLEOILLEVEL_ERROR = 0x4
-
-# VehicleApPowerStateConfigFlag
-VEHICLEAPPOWERSTATECONFIGFLAG_ENABLE_DEEP_SLEEP_FLAG = 0x1
-VEHICLEAPPOWERSTATECONFIGFLAG_CONFIG_SUPPORT_TIMER_POWER_ON_FLAG = 0x2
-
-# VehicleApPowerStateReq
-VEHICLEAPPOWERSTATEREQ_ON = 0x0
-VEHICLEAPPOWERSTATEREQ_SHUTDOWN_PREPARE = 0x1
-VEHICLEAPPOWERSTATEREQ_CANCEL_SHUTDOWN = 0x2
-VEHICLEAPPOWERSTATEREQ_FINISHED = 0x3
-
-# VehicleApPowerStateReqIndex
-VEHICLEAPPOWERSTATEREQINDEX_STATE = 0x0
-VEHICLEAPPOWERSTATEREQINDEX_ADDITIONAL = 0x1
-
-# VehicleApPowerStateShutdownParam
-VEHICLEAPPOWERSTATESHUTDOWNPARAM_SHUTDOWN_IMMEDIATELY = 0x1
-VEHICLEAPPOWERSTATESHUTDOWNPARAM_CAN_SLEEP = 0x2
-VEHICLEAPPOWERSTATESHUTDOWNPARAM_SHUTDOWN_ONLY = 0x3
-
-# VehicleApPowerStateReport
-VEHICLEAPPOWERSTATEREPORT_WAIT_FOR_VHAL = 0x1
-VEHICLEAPPOWERSTATEREPORT_DEEP_SLEEP_ENTRY = 0x2
-VEHICLEAPPOWERSTATEREPORT_DEEP_SLEEP_EXIT = 0x3
-VEHICLEAPPOWERSTATEREPORT_SHUTDOWN_POSTPONE = 0x4
-VEHICLEAPPOWERSTATEREPORT_SHUTDOWN_START = 0x5
-VEHICLEAPPOWERSTATEREPORT_ON = 0x6
-VEHICLEAPPOWERSTATEREPORT_SHUTDOWN_PREPARE = 0x7
-VEHICLEAPPOWERSTATEREPORT_SHUTDOWN_CANCELLED = 0x8
-
-# VehicleHwKeyInputAction
-VEHICLEHWKEYINPUTACTION_ACTION_DOWN = 0x0
-VEHICLEHWKEYINPUTACTION_ACTION_UP = 0x1
-
-# VehicleDisplay
-VEHICLEDISPLAY_MAIN = 0x0
-VEHICLEDISPLAY_INSTRUMENT_CLUSTER = 0x1
-
-# VehicleUnit
-VEHICLEUNIT_SHOULD_NOT_USE = 0x0
-VEHICLEUNIT_METER_PER_SEC = 0x1
-VEHICLEUNIT_RPM = 0x2
-VEHICLEUNIT_HERTZ = 0x3
-VEHICLEUNIT_PERCENTILE = 0x10
-VEHICLEUNIT_MILLIMETER = 0x20
-VEHICLEUNIT_METER = 0x21
-VEHICLEUNIT_KILOMETER = 0x23
-VEHICLEUNIT_MILE = 0x24
-VEHICLEUNIT_CELSIUS = 0x30
-VEHICLEUNIT_FAHRENHEIT = 0x31
-VEHICLEUNIT_KELVIN = 0x32
-VEHICLEUNIT_MILLILITER = 0x40
-VEHICLEUNIT_LITER = 0x41
-VEHICLEUNIT_GALLON = 0x42
-VEHICLEUNIT_US_GALLON = 0x42
-VEHICLEUNIT_IMPERIAL_GALLON = 0x43
-VEHICLEUNIT_NANO_SECS = 0x50
-VEHICLEUNIT_SECS = 0x53
-VEHICLEUNIT_YEAR = 0x59
-VEHICLEUNIT_WATT_HOUR = 0x60
-VEHICLEUNIT_MILLIAMPERE = 0x61
-VEHICLEUNIT_MILLIVOLT = 0x62
-VEHICLEUNIT_MILLIWATTS = 0x63
-VEHICLEUNIT_AMPERE_HOURS = 0x64
-VEHICLEUNIT_KILOWATT_HOUR = 0x65
-VEHICLEUNIT_KILOPASCAL = 0x70
-VEHICLEUNIT_PSI = 0x71
-VEHICLEUNIT_BAR = 0x72
-VEHICLEUNIT_DEGREES = 0x80
-VEHICLEUNIT_MILES_PER_HOUR = 0x90
-VEHICLEUNIT_KILOMETERS_PER_HOUR = 0x91
-
-# VehiclePropertyChangeMode
-VEHICLEPROPERTYCHANGEMODE_STATIC = 0x0
-VEHICLEPROPERTYCHANGEMODE_ON_CHANGE = 0x1
-VEHICLEPROPERTYCHANGEMODE_CONTINUOUS = 0x2
-
-# VehiclePropertyAccess
-VEHICLEPROPERTYACCESS_NONE = 0x0
-VEHICLEPROPERTYACCESS_READ = 0x1
-VEHICLEPROPERTYACCESS_WRITE = 0x2
-VEHICLEPROPERTYACCESS_READ_WRITE = 0x3
-
-# VehiclePropertyStatus
-VEHICLEPROPERTYSTATUS_AVAILABLE = 0x0
-VEHICLEPROPERTYSTATUS_UNAVAILABLE = 0x1
-VEHICLEPROPERTYSTATUS_ERROR = 0x2
-
-# VehicleGear
-VEHICLEGEAR_GEAR_NEUTRAL = 0x1
-VEHICLEGEAR_GEAR_REVERSE = 0x2
-VEHICLEGEAR_GEAR_PARK = 0x4
-VEHICLEGEAR_GEAR_DRIVE = 0x8
-VEHICLEGEAR_GEAR_1 = 0x10
-VEHICLEGEAR_GEAR_2 = 0x20
-VEHICLEGEAR_GEAR_3 = 0x40
-VEHICLEGEAR_GEAR_4 = 0x80
-VEHICLEGEAR_GEAR_5 = 0x100
-VEHICLEGEAR_GEAR_6 = 0x200
-VEHICLEGEAR_GEAR_7 = 0x400
-VEHICLEGEAR_GEAR_8 = 0x800
-VEHICLEGEAR_GEAR_9 = 0x1000
-
-# VehicleAreaSeat
-VEHICLEAREASEAT_ROW_1_LEFT = 0x1
-VEHICLEAREASEAT_ROW_1_CENTER = 0x2
-VEHICLEAREASEAT_ROW_1_RIGHT = 0x4
-VEHICLEAREASEAT_ROW_2_LEFT = 0x10
-VEHICLEAREASEAT_ROW_2_CENTER = 0x20
-VEHICLEAREASEAT_ROW_2_RIGHT = 0x40
-VEHICLEAREASEAT_ROW_3_LEFT = 0x100
-VEHICLEAREASEAT_ROW_3_CENTER = 0x200
-VEHICLEAREASEAT_ROW_3_RIGHT = 0x400
-
-# VehicleAreaWindow
-VEHICLEAREAWINDOW_FRONT_WINDSHIELD = 0x1
-VEHICLEAREAWINDOW_REAR_WINDSHIELD = 0x2
-VEHICLEAREAWINDOW_ROW_1_LEFT = 0x10
-VEHICLEAREAWINDOW_ROW_1_RIGHT = 0x40
-VEHICLEAREAWINDOW_ROW_2_LEFT = 0x100
-VEHICLEAREAWINDOW_ROW_2_RIGHT = 0x400
-VEHICLEAREAWINDOW_ROW_3_LEFT = 0x1000
-VEHICLEAREAWINDOW_ROW_3_RIGHT = 0x4000
-VEHICLEAREAWINDOW_ROOF_TOP_1 = 0x10000
-VEHICLEAREAWINDOW_ROOF_TOP_2 = 0x20000
-
-# VehicleAreaDoor
-VEHICLEAREADOOR_ROW_1_LEFT = 0x1
-VEHICLEAREADOOR_ROW_1_RIGHT = 0x4
-VEHICLEAREADOOR_ROW_2_LEFT = 0x10
-VEHICLEAREADOOR_ROW_2_RIGHT = 0x40
-VEHICLEAREADOOR_ROW_3_LEFT = 0x100
-VEHICLEAREADOOR_ROW_3_RIGHT = 0x400
-VEHICLEAREADOOR_HOOD = 0x10000000
-VEHICLEAREADOOR_REAR = 0x20000000
-
-# VehicleAreaMirror
-VEHICLEAREAMIRROR_DRIVER_LEFT = 0x1
-VEHICLEAREAMIRROR_DRIVER_RIGHT = 0x2
-VEHICLEAREAMIRROR_DRIVER_CENTER = 0x4
-
-# VehicleTurnSignal
-VEHICLETURNSIGNAL_NONE = 0x0
-VEHICLETURNSIGNAL_RIGHT = 0x1
-VEHICLETURNSIGNAL_LEFT = 0x2
-
-# VehicleIgnitionState
-VEHICLEIGNITIONSTATE_UNDEFINED = 0x0
-VEHICLEIGNITIONSTATE_LOCK = 0x1
-VEHICLEIGNITIONSTATE_OFF = 0x2
-VEHICLEIGNITIONSTATE_ACC = 0x3
-VEHICLEIGNITIONSTATE_ON = 0x4
-VEHICLEIGNITIONSTATE_START = 0x5
-
-# SubscribeFlags
-SUBSCRIBEFLAGS_UNDEFINED = 0x0
-SUBSCRIBEFLAGS_EVENTS_FROM_CAR = 0x1
-SUBSCRIBEFLAGS_EVENTS_FROM_ANDROID = 0x2
-
-# StatusCode
-STATUSCODE_OK = 0x0
-STATUSCODE_TRY_AGAIN = 0x1
-STATUSCODE_INVALID_ARG = 0x2
-STATUSCODE_NOT_AVAILABLE = 0x3
-STATUSCODE_ACCESS_DENIED = 0x4
-STATUSCODE_INTERNAL_ERROR = 0x5
-
-# VehicleAreaWheel
-VEHICLEAREAWHEEL_UNKNOWN = 0x0
-VEHICLEAREAWHEEL_LEFT_FRONT = 0x1
-VEHICLEAREAWHEEL_RIGHT_FRONT = 0x2
-VEHICLEAREAWHEEL_LEFT_REAR = 0x4
-VEHICLEAREAWHEEL_RIGHT_REAR = 0x8
-
-# Obd2FuelSystemStatus
-OBD2FUELSYSTEMSTATUS_OPEN_INSUFFICIENT_ENGINE_TEMPERATURE = 0x1
-OBD2FUELSYSTEMSTATUS_CLOSED_LOOP = 0x2
-OBD2FUELSYSTEMSTATUS_OPEN_ENGINE_LOAD_OR_DECELERATION = 0x4
-OBD2FUELSYSTEMSTATUS_OPEN_SYSTEM_FAILURE = 0x8
-OBD2FUELSYSTEMSTATUS_CLOSED_LOOP_BUT_FEEDBACK_FAULT = 0x10
-
-# Obd2IgnitionMonitorKind
-OBD2IGNITIONMONITORKIND_SPARK = 0x0
-OBD2IGNITIONMONITORKIND_COMPRESSION = 0x1
-
-# Obd2CommonIgnitionMonitors
-OBD2COMMONIGNITIONMONITORS_COMPONENTS_AVAILABLE = 0x1
-OBD2COMMONIGNITIONMONITORS_COMPONENTS_INCOMPLETE = 0x2
-OBD2COMMONIGNITIONMONITORS_FUEL_SYSTEM_AVAILABLE = 0x4
-OBD2COMMONIGNITIONMONITORS_FUEL_SYSTEM_INCOMPLETE = 0x8
-OBD2COMMONIGNITIONMONITORS_MISFIRE_AVAILABLE = 0x10
-OBD2COMMONIGNITIONMONITORS_MISFIRE_INCOMPLETE = 0x20
-
-# Obd2SparkIgnitionMonitors
-OBD2SPARKIGNITIONMONITORS_EGR_AVAILABLE = 0x40
-OBD2SPARKIGNITIONMONITORS_EGR_INCOMPLETE = 0x80
-OBD2SPARKIGNITIONMONITORS_OXYGEN_SENSOR_HEATER_AVAILABLE = 0x100
-OBD2SPARKIGNITIONMONITORS_OXYGEN_SENSOR_HEATER_INCOMPLETE = 0x200
-OBD2SPARKIGNITIONMONITORS_OXYGEN_SENSOR_AVAILABLE = 0x400
-OBD2SPARKIGNITIONMONITORS_OXYGEN_SENSOR_INCOMPLETE = 0x800
-OBD2SPARKIGNITIONMONITORS_AC_REFRIGERANT_AVAILABLE = 0x1000
-OBD2SPARKIGNITIONMONITORS_AC_REFRIGERANT_INCOMPLETE = 0x2000
-OBD2SPARKIGNITIONMONITORS_SECONDARY_AIR_SYSTEM_AVAILABLE = 0x4000
-OBD2SPARKIGNITIONMONITORS_SECONDARY_AIR_SYSTEM_INCOMPLETE = 0x8000
-OBD2SPARKIGNITIONMONITORS_EVAPORATIVE_SYSTEM_AVAILABLE = 0x10000
-OBD2SPARKIGNITIONMONITORS_EVAPORATIVE_SYSTEM_INCOMPLETE = 0x20000
-OBD2SPARKIGNITIONMONITORS_HEATED_CATALYST_AVAILABLE = 0x40000
-OBD2SPARKIGNITIONMONITORS_HEATED_CATALYST_INCOMPLETE = 0x80000
-OBD2SPARKIGNITIONMONITORS_CATALYST_AVAILABLE = 0x100000
-OBD2SPARKIGNITIONMONITORS_CATALYST_INCOMPLETE = 0x200000
-
-# Obd2CompressionIgnitionMonitors
-OBD2COMPRESSIONIGNITIONMONITORS_EGR_OR_VVT_AVAILABLE = 0x40
-OBD2COMPRESSIONIGNITIONMONITORS_EGR_OR_VVT_INCOMPLETE = 0x80
-OBD2COMPRESSIONIGNITIONMONITORS_PM_FILTER_AVAILABLE = 0x100
-OBD2COMPRESSIONIGNITIONMONITORS_PM_FILTER_INCOMPLETE = 0x200
-OBD2COMPRESSIONIGNITIONMONITORS_EXHAUST_GAS_SENSOR_AVAILABLE = 0x400
-OBD2COMPRESSIONIGNITIONMONITORS_EXHAUST_GAS_SENSOR_INCOMPLETE = 0x800
-OBD2COMPRESSIONIGNITIONMONITORS_BOOST_PRESSURE_AVAILABLE = 0x1000
-OBD2COMPRESSIONIGNITIONMONITORS_BOOST_PRESSURE_INCOMPLETE = 0x2000
-OBD2COMPRESSIONIGNITIONMONITORS_NOx_SCR_AVAILABLE = 0x4000
-OBD2COMPRESSIONIGNITIONMONITORS_NOx_SCR_INCOMPLETE = 0x8000
-OBD2COMPRESSIONIGNITIONMONITORS_NMHC_CATALYST_AVAILABLE = 0x10000
-OBD2COMPRESSIONIGNITIONMONITORS_NMHC_CATALYST_INCOMPLETE = 0x20000
-
-# Obd2SecondaryAirStatus
-OBD2SECONDARYAIRSTATUS_UPSTREAM = 0x1
-OBD2SECONDARYAIRSTATUS_DOWNSTREAM_OF_CATALYCIC_CONVERTER = 0x2
-OBD2SECONDARYAIRSTATUS_FROM_OUTSIDE_OR_OFF = 0x4
-OBD2SECONDARYAIRSTATUS_PUMP_ON_FOR_DIAGNOSTICS = 0x8
-
 # Obd2FuelType
 OBD2FUELTYPE_NOT_AVAILABLE = 0x0
 OBD2FUELTYPE_GASOLINE = 0x1
@@ -495,40 +558,17 @@
 OBD2FUELTYPE_HYBRID_REGENERATIVE = 0x16
 OBD2FUELTYPE_BIFUEL_RUNNING_DIESEL = 0x17
 
-# DiagnosticIntegerSensorIndex
-DIAGNOSTICINTEGERSENSORINDEX_FUEL_SYSTEM_STATUS = 0x0
-DIAGNOSTICINTEGERSENSORINDEX_MALFUNCTION_INDICATOR_LIGHT_ON = 0x1
-DIAGNOSTICINTEGERSENSORINDEX_IGNITION_MONITORS_SUPPORTED = 0x2
-DIAGNOSTICINTEGERSENSORINDEX_IGNITION_SPECIFIC_MONITORS = 0x3
-DIAGNOSTICINTEGERSENSORINDEX_INTAKE_AIR_TEMPERATURE = 0x4
-DIAGNOSTICINTEGERSENSORINDEX_COMMANDED_SECONDARY_AIR_STATUS = 0x5
-DIAGNOSTICINTEGERSENSORINDEX_NUM_OXYGEN_SENSORS_PRESENT = 0x6
-DIAGNOSTICINTEGERSENSORINDEX_RUNTIME_SINCE_ENGINE_START = 0x7
-DIAGNOSTICINTEGERSENSORINDEX_DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON = 0x8
-DIAGNOSTICINTEGERSENSORINDEX_WARMUPS_SINCE_CODES_CLEARED = 0x9
-DIAGNOSTICINTEGERSENSORINDEX_DISTANCE_TRAVELED_SINCE_CODES_CLEARED = 0xa
-DIAGNOSTICINTEGERSENSORINDEX_ABSOLUTE_BAROMETRIC_PRESSURE = 0xb
-DIAGNOSTICINTEGERSENSORINDEX_CONTROL_MODULE_VOLTAGE = 0xc
-DIAGNOSTICINTEGERSENSORINDEX_AMBIENT_AIR_TEMPERATURE = 0xd
-DIAGNOSTICINTEGERSENSORINDEX_TIME_WITH_MALFUNCTION_LIGHT_ON = 0xe
-DIAGNOSTICINTEGERSENSORINDEX_TIME_SINCE_TROUBLE_CODES_CLEARED = 0xf
-DIAGNOSTICINTEGERSENSORINDEX_MAX_FUEL_AIR_EQUIVALENCE_RATIO = 0x10
-DIAGNOSTICINTEGERSENSORINDEX_MAX_OXYGEN_SENSOR_VOLTAGE = 0x11
-DIAGNOSTICINTEGERSENSORINDEX_MAX_OXYGEN_SENSOR_CURRENT = 0x12
-DIAGNOSTICINTEGERSENSORINDEX_MAX_INTAKE_MANIFOLD_ABSOLUTE_PRESSURE = 0x13
-DIAGNOSTICINTEGERSENSORINDEX_MAX_AIR_FLOW_RATE_FROM_MASS_AIR_FLOW_SENSOR = 0x14
-DIAGNOSTICINTEGERSENSORINDEX_FUEL_TYPE = 0x15
-DIAGNOSTICINTEGERSENSORINDEX_FUEL_RAIL_ABSOLUTE_PRESSURE = 0x16
-DIAGNOSTICINTEGERSENSORINDEX_ENGINE_OIL_TEMPERATURE = 0x17
-DIAGNOSTICINTEGERSENSORINDEX_DRIVER_DEMAND_PERCENT_TORQUE = 0x18
-DIAGNOSTICINTEGERSENSORINDEX_ENGINE_ACTUAL_PERCENT_TORQUE = 0x19
-DIAGNOSTICINTEGERSENSORINDEX_ENGINE_REFERENCE_PERCENT_TORQUE = 0x1a
-DIAGNOSTICINTEGERSENSORINDEX_ENGINE_PERCENT_TORQUE_DATA_IDLE = 0x1b
-DIAGNOSTICINTEGERSENSORINDEX_ENGINE_PERCENT_TORQUE_DATA_POINT1 = 0x1c
-DIAGNOSTICINTEGERSENSORINDEX_ENGINE_PERCENT_TORQUE_DATA_POINT2 = 0x1d
-DIAGNOSTICINTEGERSENSORINDEX_ENGINE_PERCENT_TORQUE_DATA_POINT3 = 0x1e
-DIAGNOSTICINTEGERSENSORINDEX_ENGINE_PERCENT_TORQUE_DATA_POINT4 = 0x1f
-DIAGNOSTICINTEGERSENSORINDEX_LAST_SYSTEM_INDEX = 0x1f
+# VehicleAreaWindow
+VEHICLEAREAWINDOW_FRONT_WINDSHIELD = 0x1
+VEHICLEAREAWINDOW_REAR_WINDSHIELD = 0x2
+VEHICLEAREAWINDOW_ROW_1_LEFT = 0x10
+VEHICLEAREAWINDOW_ROW_1_RIGHT = 0x40
+VEHICLEAREAWINDOW_ROW_2_LEFT = 0x100
+VEHICLEAREAWINDOW_ROW_2_RIGHT = 0x400
+VEHICLEAREAWINDOW_ROW_3_LEFT = 0x1000
+VEHICLEAREAWINDOW_ROW_3_RIGHT = 0x4000
+VEHICLEAREAWINDOW_ROOF_TOP_1 = 0x10000
+VEHICLEAREAWINDOW_ROOF_TOP_2 = 0x20000
 
 # DiagnosticFloatSensorIndex
 DIAGNOSTICFLOATSENSORINDEX_CALCULATED_ENGINE_LOAD = 0x0
@@ -604,59 +644,19 @@
 DIAGNOSTICFLOATSENSORINDEX_ENGINE_FUEL_RATE = 0x46
 DIAGNOSTICFLOATSENSORINDEX_LAST_SYSTEM_INDEX = 0x46
 
-# VmsMessageType
-VMSMESSAGETYPE_START_SESSION = 0x11
-VMSMESSAGETYPE_SUBSCRIBE = 0x1
-VMSMESSAGETYPE_SUBSCRIBE_TO_PUBLISHER = 0x2
-VMSMESSAGETYPE_UNSUBSCRIBE = 0x3
-VMSMESSAGETYPE_UNSUBSCRIBE_TO_PUBLISHER = 0x4
-VMSMESSAGETYPE_OFFERING = 0x5
-VMSMESSAGETYPE_AVAILABILITY_REQUEST = 0x6
-VMSMESSAGETYPE_SUBSCRIPTIONS_REQUEST = 0x7
-VMSMESSAGETYPE_AVAILABILITY_RESPONSE = 0x8
-VMSMESSAGETYPE_AVAILABILITY_CHANGE = 0x9
-VMSMESSAGETYPE_SUBSCRIPTIONS_RESPONSE = 0xa
-VMSMESSAGETYPE_SUBSCRIPTIONS_CHANGE = 0xb
-VMSMESSAGETYPE_DATA = 0xc
-VMSMESSAGETYPE_PUBLISHER_ID_REQUEST = 0xd
-VMSMESSAGETYPE_PUBLISHER_ID_RESPONSE = 0xe
-VMSMESSAGETYPE_PUBLISHER_INFORMATION_REQUEST = 0xf
-VMSMESSAGETYPE_PUBLISHER_INFORMATION_RESPONSE = 0x10
-VMSMESSAGETYPE_LAST_VMS_MESSAGE_TYPE = 0x11
+# VehicleArea
+VEHICLEAREA_GLOBAL = 0x1000000
+VEHICLEAREA_WINDOW = 0x3000000
+VEHICLEAREA_MIRROR = 0x4000000
+VEHICLEAREA_SEAT = 0x5000000
+VEHICLEAREA_DOOR = 0x6000000
+VEHICLEAREA_WHEEL = 0x7000000
+VEHICLEAREA_MASK = 0xf000000
 
-# VmsBaseMessageIntegerValuesIndex
-VMSBASEMESSAGEINTEGERVALUESINDEX_MESSAGE_TYPE = 0x0
-
-# VmsStartSessionMessageIntegerValuesIndex
-VMSSTARTSESSIONMESSAGEINTEGERVALUESINDEX_SERVICE_ID = 0x1
-VMSSTARTSESSIONMESSAGEINTEGERVALUESINDEX_CLIENT_ID = 0x2
-
-# VmsMessageWithLayerIntegerValuesIndex
-VMSMESSAGEWITHLAYERINTEGERVALUESINDEX_LAYER_TYPE = 0x1
-VMSMESSAGEWITHLAYERINTEGERVALUESINDEX_LAYER_SUBTYPE = 0x2
-VMSMESSAGEWITHLAYERINTEGERVALUESINDEX_LAYER_VERSION = 0x3
-
-# VmsMessageWithLayerAndPublisherIdIntegerValuesIndex
-VMSMESSAGEWITHLAYERANDPUBLISHERIDINTEGERVALUESINDEX_PUBLISHER_ID = 0x4
-
-# VmsOfferingMessageIntegerValuesIndex
-VMSOFFERINGMESSAGEINTEGERVALUESINDEX_PUBLISHER_ID = 0x1
-VMSOFFERINGMESSAGEINTEGERVALUESINDEX_NUMBER_OF_OFFERS = 0x2
-VMSOFFERINGMESSAGEINTEGERVALUESINDEX_OFFERING_START = 0x3
-
-# VmsSubscriptionsStateIntegerValuesIndex
-VMSSUBSCRIPTIONSSTATEINTEGERVALUESINDEX_SEQUENCE_NUMBER = 0x1
-VMSSUBSCRIPTIONSSTATEINTEGERVALUESINDEX_NUMBER_OF_LAYERS = 0x2
-VMSSUBSCRIPTIONSSTATEINTEGERVALUESINDEX_NUMBER_OF_ASSOCIATED_LAYERS = 0x3
-VMSSUBSCRIPTIONSSTATEINTEGERVALUESINDEX_SUBSCRIPTIONS_START = 0x4
-
-# VmsAvailabilityStateIntegerValuesIndex
-VMSAVAILABILITYSTATEINTEGERVALUESINDEX_SEQUENCE_NUMBER = 0x1
-VMSAVAILABILITYSTATEINTEGERVALUESINDEX_NUMBER_OF_ASSOCIATED_LAYERS = 0x2
-VMSAVAILABILITYSTATEINTEGERVALUESINDEX_LAYERS_START = 0x3
-
-# VmsPublisherInformationIntegerValuesIndex
-VMSPUBLISHERINFORMATIONINTEGERVALUESINDEX_PUBLISHER_ID = 0x1
+# VehiclePropertyStatus
+VEHICLEPROPERTYSTATUS_AVAILABLE = 0x0
+VEHICLEPROPERTYSTATUS_UNAVAILABLE = 0x1
+VEHICLEPROPERTYSTATUS_ERROR = 0x2
 
 # Create a container of value_type constants to be used by vhal_emulator
 class vhal_types_2_0:
@@ -667,5 +667,6 @@
     TYPE_INT64   = [VEHICLEPROPERTYTYPE_INT64]
     TYPE_FLOAT   = [VEHICLEPROPERTYTYPE_FLOAT]
     TYPE_INT32S  = [VEHICLEPROPERTYTYPE_INT32_VEC]
+    TYPE_INT64S  = [VEHICLEPROPERTYTYPE_INT64_VEC]
     TYPE_FLOATS  = [VEHICLEPROPERTYTYPE_FLOAT_VEC]
     TYPE_MIXED   = [VEHICLEPROPERTYTYPE_MIXED]
diff --git a/tools/keventreader/server/Android.mk b/tools/keventreader/server/Android.mk
index 3dd6bba..301f557 100644
--- a/tools/keventreader/server/Android.mk
+++ b/tools/keventreader/server/Android.mk
@@ -28,9 +28,6 @@
     ../common/com/android/car/keventreader/IEventCallback.aidl \
     ../common/com/android/car/keventreader/IEventProvider.aidl \
 
-LOCAL_C_INCLUDES += \
-    frameworks/base/include
-
 LOCAL_SHARED_LIBRARIES := \
     libbinder \
     liblog \
diff --git a/tools/keventreader/server/keymap.cpp b/tools/keventreader/server/keymap.cpp
index 2e7c06d..5a86ff1 100644
--- a/tools/keventreader/server/keymap.cpp
+++ b/tools/keventreader/server/keymap.cpp
@@ -28,7 +28,7 @@
     fillMap();
 }
 
-std::string_view Keymap::getDisplayName(int keycode) {
+std::string Keymap::getDisplayName(int keycode) {
     auto iter = mKeyMap.find(keycode), end = mKeyMap.end();
     if (iter == end) {
         std::stringstream ss;
diff --git a/tools/keventreader/server/keymap.h b/tools/keventreader/server/keymap.h
index 28f68d6..86ec4d5 100644
--- a/tools/keventreader/server/keymap.h
+++ b/tools/keventreader/server/keymap.h
@@ -25,7 +25,7 @@
     public:
         static Keymap& get();
 
-        std::string_view getDisplayName(int keycode);
+        std::string getDisplayName(int keycode);
 
     private:
         std::map<int, const char*> mKeyMap;
diff --git a/user/OWNERS b/user/OWNERS
new file mode 100644
index 0000000..d5e72a4
--- /dev/null
+++ b/user/OWNERS
@@ -0,0 +1,6 @@
+# Library owners
+ahugh@google.com
+jovanak@google.com
+yizheng@google.com
+felipeal@google.com
+keunyoung@google.com
diff --git a/user/car-user-lib/Android.bp b/user/car-user-lib/Android.bp
index c96d01f..12bc950 100644
--- a/user/car-user-lib/Android.bp
+++ b/user/car-user-lib/Android.bp
@@ -17,6 +17,10 @@
     srcs: [
         "src/**/*.java",
     ],
+    static_libs: [
+        "android.car.settings",
+        "android.hardware.automotive.vehicle-V2.0-java",
+    ],
     product_variables: {
         pdk: {
             enabled: false,
diff --git a/user/car-user-lib/src/android/car/userlib/CarUserManagerHelper.java b/user/car-user-lib/src/android/car/userlib/CarUserManagerHelper.java
index 2a992cf..15a7d1a 100644
--- a/user/car-user-lib/src/android/car/userlib/CarUserManagerHelper.java
+++ b/user/car-user-lib/src/android/car/userlib/CarUserManagerHelper.java
@@ -17,29 +17,21 @@
 package android.car.userlib;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
-import android.content.BroadcastReceiver;
+import android.car.settings.CarSettings;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.UserInfo;
 import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.sysprop.CarProperties;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
 import android.util.Log;
 
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.RoSystemProperties;
 import com.android.internal.util.UserIcons;
 
 import com.google.android.collect.Sets;
@@ -58,11 +50,15 @@
  * <p>This class provides method for user management, including creating, removing, adding
  * and switching users. Methods related to get users will exclude system user by default.
  *
+ * <p><b>Note: </b>this class is in the process of being removed.  Use {@link UserManager} APIs
+ * directly or {@link android.car.user.CarUserManager.CarUserManager} instead.
+ *
  * @hide
  */
 public final class CarUserManagerHelper {
     private static final String TAG = "CarUserManagerHelper";
 
+    private static final boolean DEBUG = false;
     private static final int BOOT_USER_NOT_FOUND = -1;
 
     /**
@@ -76,7 +72,7 @@
      * Additional optional set of restrictions for Non-Admin users. These are the restrictions
      * configurable via Settings.
      */
-    public static final Set<String> OPTIONAL_NON_ADMIN_RESTRICTIONS = Sets.newArraySet(
+    private static final Set<String> OPTIONAL_NON_ADMIN_RESTRICTIONS = Sets.newArraySet(
             UserManager.DISALLOW_ADD_USER,
             UserManager.DISALLOW_OUTGOING_CALLS,
             UserManager.DISALLOW_SMS,
@@ -84,38 +80,9 @@
             UserManager.DISALLOW_UNINSTALL_APPS
     );
 
-    /**
-     * Default set of restrictions for Guest users.
-     */
-    private static final Set<String> DEFAULT_GUEST_RESTRICTIONS = Sets.newArraySet(
-            UserManager.DISALLOW_FACTORY_RESET,
-            UserManager.DISALLOW_REMOVE_USER,
-            UserManager.DISALLOW_MODIFY_ACCOUNTS,
-            UserManager.DISALLOW_INSTALL_APPS,
-            UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
-            UserManager.DISALLOW_UNINSTALL_APPS
-    );
-
     private final Context mContext;
     private final UserManager mUserManager;
     private final ActivityManager mActivityManager;
-    private final TestableFrameworkWrapper mTestableFrameworkWrapper;
-    private String mDefaultAdminName;
-    private Bitmap mDefaultGuestUserIcon;
-    private ArrayList<OnUsersUpdateListener> mUpdateListeners;
-    private final BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            ArrayList<OnUsersUpdateListener> copyOfUpdateListeners;
-            synchronized (mUpdateListeners) {
-                copyOfUpdateListeners = new ArrayList(mUpdateListeners);
-            }
-
-            for (OnUsersUpdateListener listener : copyOfUpdateListeners) {
-                listener.onUsersUpdate();
-            }
-        }
-    };
 
     /**
      * Initializes with a default name for admin users.
@@ -123,93 +90,50 @@
      * @param context Application Context
      */
     public CarUserManagerHelper(Context context) {
-        this(context, new TestableFrameworkWrapper());
-    }
-
-    @VisibleForTesting
-    CarUserManagerHelper(Context context, TestableFrameworkWrapper testableFrameworkWrapper) {
-        mUpdateListeners = new ArrayList<>();
-        mContext = context.getApplicationContext();
-        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        mContext = context;
+        mUserManager = UserManager.get(mContext);
         mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
-        mTestableFrameworkWrapper = testableFrameworkWrapper;
     }
 
     /**
-     * Registers a listener for updates to all users - removing, adding users or changing user info.
-     *
-     * @param listener Instance of {@link OnUsersUpdateListener}.
+     * Sets the last active user.
      */
-    public void registerOnUsersUpdateListener(OnUsersUpdateListener listener) {
-        if (listener == null) {
+    public void setLastActiveUser(@UserIdInt int userId) {
+        if (UserHelper.isHeadlessSystemUser(userId)) {
+            if (DEBUG) Log.d(TAG, "setLastActiveUser(): ignoring headless system user " + userId);
             return;
         }
+        setUserIdGlobalProperty(CarSettings.Global.LAST_ACTIVE_USER_ID, userId);
 
-        synchronized (mUpdateListeners) {
-            if (mUpdateListeners.isEmpty()) {
-                // First listener being added, register receiver.
-                registerReceiver();
-            }
-
-            if (!mUpdateListeners.contains(listener)) {
-                mUpdateListeners.add(listener);
-            }
+        // TODO(b/155918094): change method to receive a UserInfo instead
+        UserInfo user = mUserManager.getUserInfo(userId);
+        if (user == null) {
+            Log.w(TAG, "setLastActiveUser(): user " + userId + " doesn't exist");
+            return;
+        }
+        if (!user.isEphemeral()) {
+            setUserIdGlobalProperty(CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID, userId);
         }
     }
 
-    /**
-     * Unregisters on user update listener.
-     * Unregisters {@code BroadcastReceiver} if no listeners remain.
-     *
-     * @param listener Instance of {@link OnUsersUpdateListener} to unregister.
-     */
-    public void unregisterOnUsersUpdateListener(OnUsersUpdateListener listener) {
-        synchronized (mUpdateListeners) {
-            if (mUpdateListeners.contains(listener)) {
-                mUpdateListeners.remove(listener);
+    private void setUserIdGlobalProperty(@NonNull String name, @UserIdInt int userId) {
+        if (DEBUG) Log.d(TAG, "setting global property " + name + " to " + userId);
 
-                if (mUpdateListeners.isEmpty()) {
-                    // No more listeners, unregister broadcast receiver.
-                    unregisterReceiver();
-                }
-            }
-        }
+        Settings.Global.putInt(mContext.getContentResolver(), name, userId);
     }
 
-    /**
-     * Set last active user.
-     *
-     * @param userId last active user id.
-     */
-    public void setLastActiveUser(int userId) {
-        Settings.Global.putInt(
-                mContext.getContentResolver(), Settings.Global.LAST_ACTIVE_USER_ID, userId);
+    private int getUserIdGlobalProperty(@NonNull String name) {
+        int userId = Settings.Global.getInt(mContext.getContentResolver(), name,
+                UserHandle.USER_NULL);
+        if (DEBUG) Log.d(TAG, "getting global property " + name + ": " + userId);
+
+        return userId;
     }
 
-    /**
-     * Set last active user.
-     *
-     * @param userId last active user id.
-     * @param skipGlobalSetting whether to skip set the global settings value.
-     * @deprecated Use {@link #setLastActiveUser(int)} instead.
-     */
-    @Deprecated
-    public void setLastActiveUser(int userId, boolean skipGlobalSetting) {
-        if (!skipGlobalSetting) {
-            Settings.Global.putInt(
-                    mContext.getContentResolver(), Settings.Global.LAST_ACTIVE_USER_ID, userId);
-        }
-    }
+    private void resetUserIdGlobalProperty(@NonNull String name) {
+        if (DEBUG) Log.d(TAG, "resetting global property " + name);
 
-    /**
-     * Get user id for the last active user.
-     *
-     * @return user id of the last active user.
-     */
-    public int getLastActiveUser() {
-        return Settings.Global.getInt(
-            mContext.getContentResolver(), Settings.Global.LAST_ACTIVE_USER_ID,
-            /* default user id= */ UserHandle.USER_SYSTEM);
+        Settings.Global.putInt(mContext.getContentResolver(), name, UserHandle.USER_NULL);
     }
 
     /**
@@ -227,39 +151,72 @@
      * If any step fails to retrieve the stored id or the retrieved id does not exist on device,
      * then it will move onto the next step.
      *
-     * @return user id of the initial user to boot into on the device.
+     * @return user id of the initial user to boot into on the device, or
+     * {@link UserHandle#USER_NULL} if there is no user available.
      */
-    @SystemApi
-    public int getInitialUser() {
+    int getInitialUser(boolean usesOverrideUserIdProperty) {
+
         List<Integer> allUsers = userInfoListToUserIdList(getAllUsers());
 
-        int bootUserOverride = mTestableFrameworkWrapper.getBootUserOverrideId(BOOT_USER_NOT_FOUND);
+        if (allUsers.isEmpty()) {
+            return UserHandle.USER_NULL;
+        }
 
-        // If an override user is present and a real user, return it
-        if (bootUserOverride != BOOT_USER_NOT_FOUND
-                && allUsers.contains(bootUserOverride)) {
-            Log.i(TAG, "Boot user id override found for initial user, user id: "
-                    + bootUserOverride);
-            return bootUserOverride;
+        if (usesOverrideUserIdProperty) {
+            int bootUserOverride = CarProperties.boot_user_override_id()
+                    .orElse(BOOT_USER_NOT_FOUND);
+
+            // If an override user is present and a real user, return it
+            if (bootUserOverride != BOOT_USER_NOT_FOUND
+                    && allUsers.contains(bootUserOverride)) {
+                Log.i(TAG, "Boot user id override found for initial user, user id: "
+                        + bootUserOverride);
+                return bootUserOverride;
+            }
         }
 
         // If the last active user is not the SYSTEM user and is a real user, return it
-        int lastActiveUser = getLastActiveUser();
-        if (lastActiveUser != UserHandle.USER_SYSTEM
-                && allUsers.contains(lastActiveUser)) {
-            Log.i(TAG, "Last active user loaded for initial user, user id: "
-                    + lastActiveUser);
+        int lastActiveUser = getUserIdGlobalProperty(CarSettings.Global.LAST_ACTIVE_USER_ID);
+        if (allUsers.contains(lastActiveUser)) {
+            Log.i(TAG, "Last active user loaded for initial user: " + lastActiveUser);
             return lastActiveUser;
         }
+        resetUserIdGlobalProperty(CarSettings.Global.LAST_ACTIVE_USER_ID);
+
+        int lastPersistentUser = getUserIdGlobalProperty(
+                CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID);
+        if (allUsers.contains(lastPersistentUser)) {
+            Log.i(TAG, "Last active, persistent user loaded for initial user: "
+                    + lastPersistentUser);
+            return lastPersistentUser;
+        }
+        resetUserIdGlobalProperty(CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID);
 
         // If all else fails, return the smallest user id
         int returnId = Collections.min(allUsers);
-        Log.i(TAG, "Saved ids were invalid. Returning smallest user id, user id: "
-                + returnId);
+        // TODO(b/158101909): the smallest user id is not always the initial user; a better approach
+        // would be looking for the first ADMIN user, or keep track of all last active users (not
+        // just the very last)
+        Log.w(TAG, "Last active user (" + lastActiveUser + ") not found. Returning smallest user id"
+                + " instead: " + returnId);
         return returnId;
     }
 
-    private List<Integer> userInfoListToUserIdList(List<UserInfo> allUsers) {
+    /**
+     * Checks whether the device has an initial user that can be switched to.
+     */
+    public boolean hasInitialUser() {
+        List<UserInfo> allUsers = getAllUsers();
+        for (int i = 0; i < allUsers.size(); i++) {
+            UserInfo user = allUsers.get(i);
+            if (user.isManagedProfile()) continue;
+
+            return true;
+        }
+        return false;
+    }
+
+    private static List<Integer> userInfoListToUserIdList(List<UserInfo> allUsers) {
         ArrayList<Integer> list = new ArrayList<>(allUsers.size());
         for (UserInfo userInfo : allUsers) {
             list.add(userInfo.id);
@@ -268,100 +225,12 @@
     }
 
     /**
-     * Sets default guest restrictions that will be applied every time a Guest user is created.
-     *
-     * <p> Restrictions are written to disk and persistent across boots.
-     */
-    public void initDefaultGuestRestrictions() {
-        Bundle defaultGuestRestrictions = new Bundle();
-        for (String restriction : DEFAULT_GUEST_RESTRICTIONS) {
-            defaultGuestRestrictions.putBoolean(restriction, true);
-        }
-        mUserManager.setDefaultGuestRestrictions(defaultGuestRestrictions);
-    }
-
-    /**
-     * Returns {@code true} if the system is in the headless user 0 model.
-     *
-     * @return {@boolean true} if headless system user.
-     */
-    public boolean isHeadlessSystemUser() {
-        return RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER;
-    }
-
-    /**
-     * Gets UserInfo for the system user.
-     *
-     * @return {@link UserInfo} for the system user.
-     */
-    public UserInfo getSystemUserInfo() {
-        return mUserManager.getUserInfo(UserHandle.USER_SYSTEM);
-    }
-
-    /**
-     * Gets UserInfo for the current foreground user.
-     *
-     * Concept of foreground user is relevant for the multi-user deployment. Foreground user
-     * corresponds to the currently "logged in" user.
-     *
-     * @return {@link UserInfo} for the foreground user.
-     */
-    public UserInfo getCurrentForegroundUserInfo() {
-        return mUserManager.getUserInfo(getCurrentForegroundUserId());
-    }
-
-    /**
-     * @return Id of the current foreground user.
-     */
-    public int getCurrentForegroundUserId() {
-        return mActivityManager.getCurrentUser();
-    }
-
-    /**
-     * Gets UserInfo for the user running the caller process.
-     *
-     * <p>Differentiation between foreground user and current process user is relevant for
-     * multi-user deployments.
-     *
-     * <p>Some multi-user aware components (like SystemUI) needs to run a singleton component
-     * in system user. Current process user is always the same for that component, even when
-     * the foreground user changes.
-     *
-     * @return {@link UserInfo} for the user running the current process.
-     */
-    public UserInfo getCurrentProcessUserInfo() {
-        return mUserManager.getUserInfo(getCurrentProcessUserId());
-    }
-
-    /**
-     * @return Id for the user running the current process.
-     */
-    public int getCurrentProcessUserId() {
-        return UserHandle.myUserId();
-    }
-
-    /**
-     * Gets all the existing users on the system that are not currently running as
-     * the foreground user.
-     * These are all the users that can be switched to from the foreground user.
-     *
-     * @return List of {@code UserInfo} for each user that is not the foreground user.
-     */
-    public List<UserInfo> getAllSwitchableUsers() {
-        if (isHeadlessSystemUser()) {
-            return getAllUsersExceptSystemUserAndSpecifiedUser(getCurrentForegroundUserId());
-        } else {
-            return getAllUsersExceptSpecifiedUser(getCurrentForegroundUserId());
-        }
-    }
-
-    /**
      * Gets all the users that can be brought to the foreground on the system.
      *
      * @return List of {@code UserInfo} for users that associated with a real person.
      */
-    public List<UserInfo> getAllUsers() {
-        if (isHeadlessSystemUser()) {
+    private List<UserInfo> getAllUsers() {
+        if (UserManager.isHeadlessSystemUserMode()) {
             return getAllUsersExceptSystemUserAndSpecifiedUser(UserHandle.USER_SYSTEM);
         } else {
             return mUserManager.getUsers(/* excludeDying= */ true);
@@ -369,78 +238,6 @@
     }
 
     /**
-     * Gets all the users that are non-ephemeral and can be brought to the foreground on the system.
-     *
-     * @return List of {@code UserInfo} for non-ephemeral users that associated with a real person.
-     */
-    public List<UserInfo> getAllPersistentUsers() {
-        List<UserInfo> users = getAllUsers();
-        for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
-            UserInfo userInfo = iterator.next();
-            if (userInfo.isEphemeral()) {
-                // Remove user that is ephemeral.
-                iterator.remove();
-            }
-        }
-        return users;
-    }
-
-    /**
-     * Gets all the users that can be brought to the foreground on the system that have admin roles.
-     *
-     * @return List of {@code UserInfo} for admin users that associated with a real person.
-     */
-    public List<UserInfo> getAllAdminUsers() {
-        List<UserInfo> users = getAllUsers();
-
-        for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
-            UserInfo userInfo = iterator.next();
-            if (!userInfo.isAdmin()) {
-                // Remove user that is not admin.
-                iterator.remove();
-            }
-        }
-        return users;
-    }
-
-    /**
-     * Gets all users that are not guests.
-     *
-     * @return List of {@code UserInfo} for all users who are not guest users.
-     */
-    public List<UserInfo> getAllUsersExceptGuests() {
-        List<UserInfo> users = getAllUsers();
-
-        for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
-            UserInfo userInfo = iterator.next();
-            if (userInfo.isGuest()) {
-                // Remove guests.
-                iterator.remove();
-            }
-        }
-        return users;
-    }
-
-    /**
-     * Get all the users except the one with userId passed in.
-     *
-     * @param userId of the user not to be returned.
-     * @return All users other than user with userId.
-     */
-    private List<UserInfo> getAllUsersExceptSpecifiedUser(int userId) {
-        List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */true);
-
-        for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
-            UserInfo userInfo = iterator.next();
-            if (userInfo.id == userId) {
-                // Remove user with userId from the list.
-                iterator.remove();
-            }
-        }
-        return users;
-    }
-
-    /**
      * Get all the users except system user and the one with userId passed in.
      *
      * @param userId of the user not to be returned.
@@ -460,287 +257,6 @@
     }
 
     /**
-     * Maximum number of users allowed on the device. This includes real users, managed profiles
-     * and restricted users, but excludes guests.
-     *
-     * <p> It excludes system user in headless system user model.
-     *
-     * @return Maximum number of users that can be present on the device.
-     */
-    public int getMaxSupportedUsers() {
-        if (isHeadlessSystemUser()) {
-            return mTestableFrameworkWrapper.userManagerGetMaxSupportedUsers() - 1;
-        }
-        return mTestableFrameworkWrapper.userManagerGetMaxSupportedUsers();
-    }
-
-    /**
-     * Get the maximum number of real (non-guest, non-managed profile) users that can be created on
-     * the device. This is a dynamic value and it decreases with the increase of the number of
-     * managed profiles on the device.
-     *
-     * <p> It excludes system user in headless system user model.
-     *
-     * @return Maximum number of real users that can be created.
-     */
-    public int getMaxSupportedRealUsers() {
-        return getMaxSupportedUsers() - getManagedProfilesCount();
-    }
-
-    /**
-     * Returns true if the maximum number of users on the device has been reached, false otherwise.
-     */
-    public boolean isUserLimitReached() {
-        int countNonGuestUsers = getAllUsersExceptGuests().size();
-        int maxSupportedUsers = getMaxSupportedUsers();
-
-        if (countNonGuestUsers > maxSupportedUsers) {
-            Log.e(TAG, "There are more users on the device than allowed.");
-            return true;
-        }
-
-        return getAllUsersExceptGuests().size() == maxSupportedUsers;
-    }
-
-    private int getManagedProfilesCount() {
-        List<UserInfo> users = getAllUsers();
-
-        // Count all users that are managed profiles of another user.
-        int managedProfilesCount = 0;
-        for (UserInfo user : users) {
-            if (user.isManagedProfile()) {
-                managedProfilesCount++;
-            }
-        }
-        return managedProfilesCount;
-    }
-
-    // User information accessors
-
-    /**
-     * Checks whether the user is system user.
-     *
-     * @param userInfo User to check against system user.
-     * @return {@code true} if system user, {@code false} otherwise.
-     */
-    public boolean isSystemUser(UserInfo userInfo) {
-        return userInfo.id == UserHandle.USER_SYSTEM;
-    }
-
-    /**
-     * Checks whether the user is last active user.
-     *
-     * @param userInfo User to check against last active user.
-     * @return {@code true} if is last active user, {@code false} otherwise.
-     */
-    public boolean isLastActiveUser(UserInfo userInfo) {
-        return userInfo.id == getLastActiveUser();
-    }
-
-    /**
-     * Checks whether passed in user is the foreground user.
-     *
-     * @param userInfo User to check.
-     * @return {@code true} if foreground user, {@code false} otherwise.
-     */
-    public boolean isForegroundUser(UserInfo userInfo) {
-        return getCurrentForegroundUserId() == userInfo.id;
-    }
-
-    /**
-     * Checks whether passed in user is the user that's running the current process.
-     *
-     * @param userInfo User to check.
-     * @return {@code true} if user running the process, {@code false} otherwise.
-     */
-    public boolean isCurrentProcessUser(UserInfo userInfo) {
-        return getCurrentProcessUserId() == userInfo.id;
-    }
-
-    // Foreground user information accessors.
-
-    /**
-     * Checks if the foreground user is a guest user.
-     */
-    public boolean isForegroundUserGuest() {
-        return getCurrentForegroundUserInfo().isGuest();
-    }
-
-    /**
-     * Checks if the foreground user is a demo user.
-     */
-    public boolean isForegroundUserDemo() {
-        return getCurrentForegroundUserInfo().isDemo();
-    }
-
-    /**
-     * Checks if the foreground user is ephemeral.
-     */
-    public boolean isForegroundUserEphemeral() {
-        return getCurrentForegroundUserInfo().isEphemeral();
-    }
-
-    /**
-     * Checks if the given user is non-ephemeral.
-     *
-     * @param userId User to check
-     * @return {@code true} if given user is persistent user.
-     */
-    public boolean isPersistentUser(int userId) {
-        UserInfo user = mUserManager.getUserInfo(userId);
-        return !user.isEphemeral();
-    }
-
-    /**
-     * Returns whether this user can be removed from the system.
-     *
-     * @param userInfo User to be removed
-     * @return {@code true} if they can be removed, {@code false} otherwise.
-     */
-    public boolean canUserBeRemoved(UserInfo userInfo) {
-        return !isSystemUser(userInfo);
-    }
-
-    /**
-     * Returns whether a user has a restriction.
-     *
-     * @param restriction Restriction to check. Should be a UserManager.* restriction.
-     * @param userInfo the user whose restriction is to be checked
-     */
-    public boolean hasUserRestriction(String restriction, UserInfo userInfo) {
-        return mUserManager.hasUserRestriction(restriction, userInfo.getUserHandle());
-    }
-
-    /**
-     * Return whether the foreground user has a restriction.
-     *
-     * @param restriction Restriction to check. Should be a UserManager.* restriction.
-     * @return Whether that restriction exists for the foreground user.
-     */
-    public boolean foregroundUserHasUserRestriction(String restriction) {
-        return hasUserRestriction(restriction, getCurrentForegroundUserInfo());
-    }
-
-    /**
-     * Checks if the foreground user can add new users.
-     */
-    public boolean canForegroundUserAddUsers() {
-        return !foregroundUserHasUserRestriction(UserManager.DISALLOW_ADD_USER);
-    }
-
-    /**
-     * Checks if the current process user can modify accounts. Demo and Guest users cannot modify
-     * accounts even if the DISALLOW_MODIFY_ACCOUNTS restriction is not applied.
-     */
-    public boolean canForegroundUserModifyAccounts() {
-        return !foregroundUserHasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)
-            && !isForegroundUserDemo()
-            && !isForegroundUserGuest();
-    }
-
-    /**
-     * Returns whether the foreground user can switch to other users.
-     *
-     * <p>For instance switching users is not allowed if the current user is in a phone call,
-     * or {@link #{UserManager.DISALLOW_USER_SWITCH} is set.
-     */
-    public boolean canForegroundUserSwitchUsers() {
-        boolean inIdleCallState = TelephonyManager.getDefault().getCallState()
-                == TelephonyManager.CALL_STATE_IDLE;
-        boolean disallowUserSwitching =
-                foregroundUserHasUserRestriction(UserManager.DISALLOW_USER_SWITCH);
-        return (inIdleCallState && !disallowUserSwitching);
-    }
-
-    // Current process user information accessors
-
-    /**
-     * Checks whether this process is running under the system user.
-     */
-    public boolean isCurrentProcessSystemUser() {
-        return mUserManager.isSystemUser();
-    }
-
-    /**
-     * Checks if the calling app is running in a demo user.
-     */
-    public boolean isCurrentProcessDemoUser() {
-        return mUserManager.isDemoUser();
-    }
-
-    /**
-     * Checks if the calling app is running as an admin user.
-     */
-    public boolean isCurrentProcessAdminUser() {
-        return mUserManager.isAdminUser();
-    }
-
-    /**
-     * Checks if the calling app is running as a guest user.
-     */
-    public boolean isCurrentProcessGuestUser() {
-        return mUserManager.isGuestUser();
-    }
-
-    /**
-     * Check is the calling app is running as a restricted profile user (ie. a LinkedUser).
-     * Restricted profiles are only available when {@link #isHeadlessSystemUser()} is false.
-     */
-    public boolean isCurrentProcessRestrictedProfileUser() {
-        return mUserManager.isRestrictedProfile();
-    }
-
-    // Current process user restriction accessors
-
-    /**
-     * Return whether the user running the current process has a restriction.
-     *
-     * @param restriction Restriction to check. Should be a UserManager.* restriction.
-     * @return Whether that restriction exists for the user running the process.
-     */
-    public boolean isCurrentProcessUserHasRestriction(String restriction) {
-        return mUserManager.hasUserRestriction(restriction);
-    }
-
-    /**
-     * Checks if the current process user can modify accounts. Demo and Guest users cannot modify
-     * accounts even if the DISALLOW_MODIFY_ACCOUNTS restriction is not applied.
-     */
-    public boolean canCurrentProcessModifyAccounts() {
-        return !isCurrentProcessUserHasRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)
-            && !isCurrentProcessDemoUser()
-            && !isCurrentProcessGuestUser();
-    }
-
-    /**
-     * Checks if the user running the current process can add new users.
-     */
-    public boolean canCurrentProcessAddUsers() {
-        return !isCurrentProcessUserHasRestriction(UserManager.DISALLOW_ADD_USER);
-    }
-
-    /**
-     * Checks if the user running the current process can remove users.
-     */
-    public boolean canCurrentProcessRemoveUsers() {
-        return !isCurrentProcessUserHasRestriction(UserManager.DISALLOW_REMOVE_USER);
-    }
-
-    /**
-     * Returns whether the current process user can switch to other users.
-     *
-     * <p>For instance switching users is not allowed if the user is in a phone call,
-     * or {@link #{UserManager.DISALLOW_USER_SWITCH} is set.
-     */
-    public boolean canCurrentProcessSwitchUsers() {
-        boolean inIdleCallState = TelephonyManager.getDefault().getCallState()
-                == TelephonyManager.CALL_STATE_IDLE;
-        boolean disallowUserSwitching =
-                isCurrentProcessUserHasRestriction(UserManager.DISALLOW_USER_SWITCH);
-        return (inIdleCallState && !disallowUserSwitching);
-    }
-
-    /**
      * Grants admin permissions to the user.
      *
      * @param user User to be upgraded to Admin status.
@@ -750,7 +266,7 @@
             Manifest.permission.MANAGE_USERS
     })
     public void grantAdminPermissions(UserInfo user) {
-        if (!isCurrentProcessAdminUser()) {
+        if (!mUserManager.isAdminUser()) {
             Log.w(TAG, "Only admin users can assign admin permissions.");
             return;
         }
@@ -763,49 +279,14 @@
     }
 
     /**
-     * Creates a new user on the system with a default user name. This user name is set during
-     * constrution. The created user would be granted admin role. Only admins can create other
-     * admins.
-     *
-     * @return Newly created admin user, null if failed to create a user.
-     */
-    @Nullable
-    public UserInfo createNewAdminUser() {
-        return createNewAdminUser(getDefaultAdminName());
-    }
-
-    /**
-     * Creates a new user on the system, the created user would be granted admin role.
-     * Only admins can create other admins.
-     *
-     * @param userName Name to give to the newly created user.
-     * @return Newly created admin user, null if failed to create a user.
-     */
-    @Nullable
-    public UserInfo createNewAdminUser(String userName) {
-        if (!(isCurrentProcessAdminUser() || isCurrentProcessSystemUser())) {
-            // Only Admins or System user can create other privileged users.
-            Log.e(TAG, "Only admin users and system user can create other admins.");
-            return null;
-        }
-
-        UserInfo user = mUserManager.createUser(userName, UserInfo.FLAG_ADMIN);
-        if (user == null) {
-            // Couldn't create user, most likely because there are too many.
-            Log.w(TAG, "can't create admin user.");
-            return null;
-        }
-        assignDefaultIcon(user);
-
-        return user;
-    }
-
-    /**
      * Creates a new non-admin user on the system.
      *
      * @param userName Name to give to the newly created user.
      * @return Newly created non-admin user, null if failed to create a user.
+     *
+     * @deprecated non-admin restrictions should be set by resources overlay
      */
+    @Deprecated
     @Nullable
     public UserInfo createNewNonAdminUser(String userName) {
         UserInfo user = mUserManager.createUser(userName, 0);
@@ -816,11 +297,6 @@
         }
         setDefaultNonAdminRestrictions(user, /* enable= */ true);
 
-        // Each non-admin has sms and outgoing call restrictions applied by the UserManager on
-        // creation. We want to enable these permissions by default in the car.
-        setUserRestriction(user, UserManager.DISALLOW_SMS, /* enable= */ false);
-        setUserRestriction(user, UserManager.DISALLOW_OUTGOING_CALLS, /* enable= */ false);
-
         assignDefaultIcon(user);
         return user;
     }
@@ -830,10 +306,13 @@
      *
      * @param userInfo User to set restrictions on.
      * @param enable If true, restriction is ON, If false, restriction is OFF.
+     *
+     * @deprecated non-admin restrictions should be set by resources overlay
      */
-    private void setDefaultNonAdminRestrictions(UserInfo userInfo, boolean enable) {
+    @Deprecated
+    public void setDefaultNonAdminRestrictions(UserInfo userInfo, boolean enable) {
         for (String restriction : DEFAULT_NON_ADMIN_RESTRICTIONS) {
-            setUserRestriction(userInfo, restriction, enable);
+            mUserManager.setUserRestriction(restriction, enable, userInfo.getUserHandle());
         }
     }
 
@@ -845,94 +324,28 @@
      */
     private void setOptionalNonAdminRestrictions(UserInfo userInfo, boolean enable) {
         for (String restriction : OPTIONAL_NON_ADMIN_RESTRICTIONS) {
-            setUserRestriction(userInfo, restriction, enable);
+            mUserManager.setUserRestriction(restriction, enable, userInfo.getUserHandle());
         }
     }
 
     /**
-     * Sets the value of the specified restriction for the specified user.
-     *
-     * @param userInfo the user whose restriction is to be changed
-     * @param restriction the key of the restriction
-     * @param enable the value for the restriction. if true, turns the restriction ON, if false,
-     *               turns the restriction OFF.
-     */
-    public void setUserRestriction(UserInfo userInfo, String restriction, boolean enable) {
-        UserHandle userHandle = UserHandle.of(userInfo.id);
-        mUserManager.setUserRestriction(restriction, enable, userHandle);
-    }
-
-    /**
-     * Tries to remove the user that's passed in. System user cannot be removed.
-     * If the user to be removed is user currently running the process,
-     * it switches to the guest user first, and then removes the user.
-     * If the user being removed is the last admin user, this will create a new admin user.
-     *
-     * @param userInfo User to be removed
-     * @param guestUserName User name to use for the guest user if we need to switch to it
-     * @return {@code true} if user is successfully removed, {@code false} otherwise.
-     */
-    public boolean removeUser(UserInfo userInfo, String guestUserName) {
-        if (isSystemUser(userInfo)) {
-            Log.w(TAG, "User " + userInfo.id + " is system user, could not be removed.");
-            return false;
-        }
-
-        // Try to create a new admin before deleting the current one.
-        if (userInfo.isAdmin() && getAllAdminUsers().size() <= 1) {
-            return removeLastAdmin(userInfo);
-        }
-
-        if (!isCurrentProcessAdminUser() && !isCurrentProcessUser(userInfo)) {
-            // If the caller is non-admin, they can only delete themselves.
-            Log.e(TAG, "Non-admins cannot remove other users.");
-            return false;
-        }
-
-        if (userInfo.id == getCurrentForegroundUserId()) {
-            if (!canCurrentProcessSwitchUsers()) {
-                // If we can't switch to a different user, we can't exit this one and therefore
-                // can't delete it.
-                Log.w(TAG, "User switching is not allowed. Current user cannot be deleted");
-                return false;
-            }
-            startGuestSession(guestUserName);
-        }
-
-        return mUserManager.removeUser(userInfo.id);
-    }
-
-    private boolean removeLastAdmin(UserInfo userInfo) {
-        if (Log.isLoggable(TAG, Log.INFO)) {
-            Log.i(TAG, "User " + userInfo.id
-                    + " is the last admin user on device. Creating a new admin.");
-        }
-
-        UserInfo newAdmin = createNewAdminUser(getDefaultAdminName());
-        if (newAdmin == null) {
-            Log.w(TAG, "Couldn't create another admin, cannot delete current user.");
-            return false;
-        }
-
-        switchToUser(newAdmin);
-        return mUserManager.removeUser(userInfo.id);
-    }
-
-    /**
      * Switches (logs in) to another user given user id.
      *
      * @param id User id to switch to.
      * @return {@code true} if user switching succeed.
+     *
+     * @deprecated should use {@link android.car.user.CarUserManager.CarUserManager} instead
      */
+    @Deprecated
     public boolean switchToUserId(int id) {
-        if (id == UserHandle.USER_SYSTEM && isHeadlessSystemUser()) {
+        if (UserHelper.isHeadlessSystemUser(id)) {
             // System User doesn't associate with real person, can not be switched to.
             return false;
         }
-        if (!canCurrentProcessSwitchUsers()) {
+        if (mUserManager.getUserSwitchability() != UserManager.SWITCHABILITY_STATUS_OK) {
             return false;
         }
-        if (id == getCurrentForegroundUserId()) {
+        if (id == ActivityManager.getCurrentUser()) {
             return false;
         }
         return mActivityManager.switchUser(id);
@@ -943,168 +356,25 @@
      *
      * @param userInfo User to switch to.
      * @return {@code true} if user switching succeed.
+     *
+     * @deprecated should use {@link android.car.user.CarUserManager.CarUserManager} instead
      */
+    @Deprecated
     public boolean switchToUser(UserInfo userInfo) {
         return switchToUserId(userInfo.id);
     }
 
     /**
-     * Creates a new guest or finds the existing one, and switches into it.
+     * Assigns a default icon to a user according to the user's id.
      *
-     * @param guestName Username for the guest user.
-     * @return {@code true} if switch to guest user succeed.
+     * @param userInfo User whose avatar is set to default icon.
+     * @return Bitmap of the user icon.
      */
-    public boolean startGuestSession(String guestName) {
-        UserInfo guest = createNewOrFindExistingGuest(guestName);
-        if (guest == null) {
-            return false;
-        }
-        return switchToUserId(guest.id);
-    }
-
-    /**
-     * Creates and returns a new guest user or returns the existing one.
-     * Returns null if it fails to create a new guest.
-     *
-     * @param guestName Username for guest if new guest is being created.
-     */
-    @Nullable
-    public UserInfo createNewOrFindExistingGuest(String guestName) {
-        // CreateGuest will return null if a guest already exists.
-        UserInfo newGuest = mUserManager.createGuest(mContext, guestName);
-        if (newGuest != null) {
-            assignDefaultIcon(newGuest);
-            return newGuest;
-        }
-
-        UserInfo existingGuest = findExistingGuestUser();
-        if (existingGuest == null) {
-            // Most likely a guest got removed just before we tried to look for it.
-            Log.w(TAG, "Couldn't create a new guest and couldn't find an existing one.");
-        }
-
-        return existingGuest;
-    }
-
-    /**
-     * Returns UserInfo for the existing guest user, or null if there are no guests on the device.
-     */
-    @Nullable
-    private UserInfo findExistingGuestUser() {
-        for (UserInfo userInfo : getAllUsers()) {
-            if (userInfo.isGuest() && !userInfo.guestToRemove) {
-                return userInfo;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Gets a bitmap representing the user's default avatar.
-     *
-     * @param userInfo User whose avatar should be returned.
-     * @return Default user icon
-     */
-    public Bitmap getUserDefaultIcon(UserInfo userInfo) {
-        return UserIcons.convertToBitmap(
-            UserIcons.getDefaultUserIcon(mContext.getResources(), userInfo.id, false));
-    }
-
-    /**
-     * Gets a bitmap representing the default icon for a Guest user.
-     *
-     * @return Default guest user icon
-     */
-    public Bitmap getGuestDefaultIcon() {
-        if (mDefaultGuestUserIcon == null) {
-            mDefaultGuestUserIcon = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(
-                mContext.getResources(), UserHandle.USER_NULL, false));
-        }
-        return mDefaultGuestUserIcon;
-    }
-
-    /**
-     * Gets an icon for the user.
-     *
-     * @param userInfo User for which we want to get the icon.
-     * @return a Bitmap for the icon
-     */
-    public Bitmap getUserIcon(UserInfo userInfo) {
-        Bitmap picture = mUserManager.getUserIcon(userInfo.id);
-
-        if (picture == null) {
-            return assignDefaultIcon(userInfo);
-        }
-
-        return picture;
-    }
-
-    /**
-     * Method for scaling a Bitmap icon to a desirable size.
-     *
-     * @param icon Bitmap to scale.
-     * @param desiredSize Wanted size for the icon.
-     * @return Drawable for the icon, scaled to the new size.
-     */
-    public Drawable scaleUserIcon(Bitmap icon, int desiredSize) {
-        Bitmap scaledIcon = Bitmap.createScaledBitmap(
-                icon, desiredSize, desiredSize, true /* filter */);
-        return new BitmapDrawable(mContext.getResources(), scaledIcon);
-    }
-
-    /**
-     * Sets new Username for the user.
-     *
-     * @param user User whose name should be changed.
-     * @param name New username.
-     */
-    public void setUserName(UserInfo user, String name) {
-        mUserManager.setUserName(user.id, name);
-    }
-
-    private void registerReceiver() {
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_USER_REMOVED);
-        filter.addAction(Intent.ACTION_USER_ADDED);
-        filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
-        filter.addAction(Intent.ACTION_USER_SWITCHED);
-        filter.addAction(Intent.ACTION_USER_STOPPED);
-        filter.addAction(Intent.ACTION_USER_UNLOCKED);
-        mContext.registerReceiverAsUser(mUserChangeReceiver, UserHandle.ALL, filter, null, null);
-    }
-
-    // Assigns a default icon to a user according to the user's id.
     private Bitmap assignDefaultIcon(UserInfo userInfo) {
-        Bitmap bitmap = userInfo.isGuest()
-                ? getGuestDefaultIcon() : getUserDefaultIcon(userInfo);
+        int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
+        Bitmap bitmap = UserIcons.convertToBitmap(
+                UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
         mUserManager.setUserIcon(userInfo.id, bitmap);
         return bitmap;
     }
-
-    private void unregisterReceiver() {
-        mContext.unregisterReceiver(mUserChangeReceiver);
-    }
-
-    private String getDefaultAdminName() {
-        if (TextUtils.isEmpty(mDefaultAdminName)) {
-            mDefaultAdminName = mContext.getString(com.android.internal.R.string.owner_name);
-        }
-        return mDefaultAdminName;
-    }
-
-    @VisibleForTesting
-    void setDefaultAdminName(String defaultAdminName) {
-        mDefaultAdminName = defaultAdminName;
-    }
-
-    /**
-     * Interface for listeners that want to register for receiving updates to changes to the users
-     * on the system including removing and adding users, and changing user info.
-     */
-    public interface OnUsersUpdateListener {
-        /**
-         * Method that will get called when users list has been changed.
-         */
-        void onUsersUpdate();
-    }
 }
diff --git a/user/car-user-lib/src/android/car/userlib/CommonConstants.java b/user/car-user-lib/src/android/car/userlib/CommonConstants.java
new file mode 100644
index 0000000..89c09c5
--- /dev/null
+++ b/user/car-user-lib/src/android/car/userlib/CommonConstants.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.userlib;
+
+/**
+ * Provides constants used by both CarService and CarServiceHelper packages.
+ */
+public final class CommonConstants {
+
+    private CommonConstants() {
+        throw new UnsupportedOperationException("contains only static constants");
+    }
+
+    /**
+     * Constants used on {@link android.os.Bundle bundles} sent by
+     * {@link com.android.car.user.CarUserService} on binder calls.
+     */
+    public static final class CarUserServiceConstants {
+
+        public static final String BUNDLE_USER_ID = "user.id";
+        public static final String BUNDLE_USER_FLAGS = "user.flags";
+        public static final String BUNDLE_USER_NAME = "user.name";
+        public static final String BUNDLE_USER_LOCALES = "user.locales";
+        public static final String BUNDLE_INITIAL_INFO_ACTION = "initial_info.action";
+
+        private CarUserServiceConstants() {
+            throw new UnsupportedOperationException("contains only static constants");
+        }
+    }
+}
diff --git a/user/car-user-lib/src/android/car/userlib/HalCallback.java b/user/car-user-lib/src/android/car/userlib/HalCallback.java
new file mode 100644
index 0000000..784d01e
--- /dev/null
+++ b/user/car-user-lib/src/android/car/userlib/HalCallback.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.userlib;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Callback used on async methods.
+ *
+ * @param <R> response type.
+ */
+public interface HalCallback<R> {
+
+    int STATUS_INVALID = -1; // Used for logging purposes only
+    int STATUS_OK = 1;
+    int STATUS_HAL_SET_TIMEOUT = 2;
+    int STATUS_HAL_RESPONSE_TIMEOUT = 3;
+    int STATUS_WRONG_HAL_RESPONSE = 4;
+    int STATUS_CONCURRENT_OPERATION = 5;
+    int STATUS_HAL_NOT_SUPPORTED = 6;
+
+    /** @hide */
+    @IntDef(prefix = { "STATUS_" }, value = {
+            STATUS_OK,
+            STATUS_HAL_SET_TIMEOUT,
+            STATUS_HAL_RESPONSE_TIMEOUT,
+            STATUS_WRONG_HAL_RESPONSE,
+            STATUS_CONCURRENT_OPERATION,
+            STATUS_HAL_NOT_SUPPORTED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface HalCallbackStatus{}
+
+    /**
+     * Called when the HAL generated an event responding to that callback (or when an error
+     * occurred).
+     *
+     * @param status status of the request.
+     * @param response HAL response (or {@code null} in case of error).
+     */
+    void onResponse(@HalCallbackStatus int status, @Nullable R response);
+}
diff --git a/user/car-user-lib/src/android/car/userlib/InitialUserSetter.java b/user/car-user-lib/src/android/car/userlib/InitialUserSetter.java
new file mode 100644
index 0000000..10b642b
--- /dev/null
+++ b/user/car-user-lib/src/android/car/userlib/InitialUserSetter.java
@@ -0,0 +1,582 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.userlib;
+
+import static android.car.userlib.UserHalHelper.userFlagsToString;
+import static android.car.userlib.UserHelper.safeName;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.hardware.automotive.vehicle.V2_0.UserFlags;
+import android.os.RemoteException;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.sysprop.CarProperties;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.TimingsTraceLog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+import com.android.internal.widget.LockPatternUtils;
+
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.function.Consumer;
+
+/**
+ * Helper used to set the initial Android user on boot or when resuming from RAM.
+ */
+public final class InitialUserSetter {
+
+    private static final String TAG = InitialUserSetter.class.getSimpleName();
+
+    private static final boolean DBG = false;
+
+    /**
+     * Sets the initial user using the default behavior.
+     *
+     * <p>The default behavior is:
+     *
+     * <ol>
+     *  <li>On first boot, it creates and switches to a new user.
+     *  <li>Otherwise, it will switch to either:
+     *  <ol>
+     *   <li>User defined by {@code android.car.systemuser.bootuseroverrideid} (when it was
+     * constructed with such option enabled).
+     *   <li>Last active user (as defined by
+     * {@link android.provider.Settings.Global.LAST_ACTIVE_USER_ID}.
+     *  </ol>
+     * </ol>
+     */
+    public static final int TYPE_DEFAULT_BEHAVIOR = 0;
+
+    /**
+     * Switches to the given user, falling back to {@link #fallbackDefaultBehavior(String)} if it
+     * fails.
+     */
+    public static final int TYPE_SWITCH = 1;
+
+    /**
+     * Creates a new user and switches to it, falling back to
+     * {@link #fallbackDefaultBehavior(String) if any of these steps fails.
+     *
+     * @param name (optional) name of the new user
+     * @param halFlags user flags as defined by Vehicle HAL ({@code UserFlags} enum).
+     */
+    public static final int TYPE_CREATE = 2;
+
+    @IntDef(prefix = { "TYPE_" }, value = {
+            TYPE_DEFAULT_BEHAVIOR,
+            TYPE_SWITCH,
+            TYPE_CREATE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface InitialUserInfoType { }
+
+    private final Context mContext;
+
+    // TODO(b/150413304): abstract AM / UM into interfaces, then provide local and remote
+    // implementation (where local is implemented by ActivityManagerInternal / UserManagerInternal)
+    private final CarUserManagerHelper mHelper;
+    private final UserManager mUm;
+    private final LockPatternUtils mLockPatternUtils;
+
+    private final String mNewUserName;
+    private final String mNewGuestName;
+
+    private final Consumer<UserInfo> mListener;
+
+    public InitialUserSetter(@NonNull Context context, @NonNull Consumer<UserInfo> listener) {
+        this(context, listener, /* newGuestName= */ null);
+    }
+
+    public InitialUserSetter(@NonNull Context context, @NonNull Consumer<UserInfo> listener,
+            @Nullable String newGuestName) {
+        this(context, new CarUserManagerHelper(context), UserManager.get(context), listener,
+                new LockPatternUtils(context),
+                context.getString(com.android.internal.R.string.owner_name), newGuestName);
+    }
+
+    @VisibleForTesting
+    public InitialUserSetter(@NonNull Context context, @NonNull CarUserManagerHelper helper,
+            @NonNull UserManager um, @NonNull Consumer<UserInfo> listener,
+            @NonNull LockPatternUtils lockPatternUtils,
+            @Nullable String newUserName, @Nullable String newGuestName) {
+        mContext = context;
+        mHelper = helper;
+        mUm = um;
+        mListener = listener;
+        mLockPatternUtils = lockPatternUtils;
+        mNewUserName = newUserName;
+        mNewGuestName = newGuestName;
+    }
+
+    /**
+     * Builder for {@link InitialUserInfo} objects.
+     *
+     */
+    public static final class Builder {
+
+        private final @InitialUserInfoType int mType;
+        private boolean mReplaceGuest;
+        private @UserIdInt int mSwitchUserId;
+        private @Nullable String mNewUserName;
+        private int mNewUserFlags;
+        private boolean mSupportsOverrideUserIdProperty;
+        private @Nullable String mUserLocales;
+
+        /**
+         * Constructor for the given type.
+         *
+         * @param type {@link #TYPE_DEFAULT_BEHAVIOR}, {@link #TYPE_SWITCH},
+         * or {@link #TYPE_CREATE}.
+         */
+        public Builder(@InitialUserInfoType int type) {
+            Preconditions.checkArgument(
+                    type == TYPE_DEFAULT_BEHAVIOR || type == TYPE_SWITCH || type == TYPE_CREATE,
+                    "invalid builder type");
+            mType = type;
+        }
+
+        /**
+         * Sets the id of the user to be switched to.
+         *
+         * @throws IllegalArgumentException if builder is not for {@link #TYPE_SWITCH}.
+         */
+        @NonNull
+        public Builder setSwitchUserId(@UserIdInt int userId) {
+            Preconditions.checkArgument(mType == TYPE_SWITCH, "invalid builder type: " + mType);
+            mSwitchUserId = userId;
+            return this;
+        }
+
+        /**
+         * Sets whether the current user should be replaced when it's a guest.
+         */
+        @NonNull
+        public Builder setReplaceGuest(boolean value) {
+            mReplaceGuest = value;
+            return this;
+        }
+
+        /**
+         * Sets the name of the new user being created.
+         *
+         * @throws IllegalArgumentException if builder is not for {@link #TYPE_CREATE}.
+         */
+        @NonNull
+        public Builder setNewUserName(@Nullable String name) {
+            Preconditions.checkArgument(mType == TYPE_CREATE, "invalid builder type: " + mType);
+            mNewUserName = name;
+            return this;
+        }
+
+        /**
+         * Sets the flags (as defined by {@link android.hardware.automotive.vehicle.V2_0.UserFlags})
+         * of the new user being created.
+         *
+         * @throws IllegalArgumentException if builder is not for {@link #TYPE_CREATE}.
+         */
+        @NonNull
+        public Builder setNewUserFlags(int flags) {
+            Preconditions.checkArgument(mType == TYPE_CREATE, "invalid builder type: " + mType);
+            mNewUserFlags = flags;
+            return this;
+        }
+
+        /**
+         * Sets whether the {@link CarProperties#boot_user_override_id()} should be taking in
+         * account when using the default behavior.
+         */
+        @NonNull
+        public Builder setSupportsOverrideUserIdProperty(boolean value) {
+            mSupportsOverrideUserIdProperty = value;
+            return this;
+        }
+
+        /**
+         * Sets the system locales for the initial user (when it's created).
+         */
+        @NonNull
+        public Builder setUserLocales(@Nullable String userLocales) {
+            mUserLocales = userLocales;
+            return this;
+        }
+
+        /**
+         * Builds the object.
+         */
+        @NonNull
+        public InitialUserInfo build() {
+            return new InitialUserInfo(this);
+        }
+    }
+
+    /**
+     * Object used to define the properties of the initial user (which can then be set by
+     * {@link InitialUserSetter#set(InitialUserInfo)});
+     */
+    public static final class InitialUserInfo {
+        public final @InitialUserInfoType int type;
+        public final boolean replaceGuest;
+        public final @UserIdInt int switchUserId;
+        public final @Nullable String newUserName;
+        public final int newUserFlags;
+        public final boolean supportsOverrideUserIdProperty;
+        public @Nullable String userLocales;
+
+        private InitialUserInfo(@NonNull Builder builder) {
+            type = builder.mType;
+            switchUserId = builder.mSwitchUserId;
+            replaceGuest = builder.mReplaceGuest;
+            newUserName = builder.mNewUserName;
+            newUserFlags = builder.mNewUserFlags;
+            supportsOverrideUserIdProperty = builder.mSupportsOverrideUserIdProperty;
+            userLocales = builder.mUserLocales;
+        }
+    }
+
+    /**
+     * Sets the initial user.
+     */
+    public void set(@NonNull InitialUserInfo info) {
+        Preconditions.checkArgument(info != null, "info cannot be null");
+
+        switch (info.type) {
+            case TYPE_DEFAULT_BEHAVIOR:
+                executeDefaultBehavior(info, /* fallback= */ false);
+                break;
+            case TYPE_SWITCH:
+                try {
+                    switchUser(info, /* fallback= */ true);
+                } catch (Exception e) {
+                    fallbackDefaultBehavior(info, /* fallback= */ true,
+                            "Exception switching user: " + e);
+                }
+                break;
+            case TYPE_CREATE:
+                try {
+                    createAndSwitchUser(info, /* fallback= */ true);
+                } catch (Exception e) {
+                    fallbackDefaultBehavior(info, /* fallback= */ true,
+                            "Exception createUser user with name "
+                                    + UserHelper.safeName(info.newUserName) + " and flags "
+                                    + UserHalHelper.userFlagsToString(info.newUserFlags) + ": "
+                                    + e);
+                }
+                break;
+            default:
+                throw new IllegalArgumentException("invalid InitialUserInfo type: " + info.type);
+        }
+    }
+
+    private void executeDefaultBehavior(@NonNull InitialUserInfo info, boolean fallback) {
+        if (!mHelper.hasInitialUser()) {
+            if (DBG) Log.d(TAG, "executeDefaultBehavior(): no initial user, creating it");
+            createAndSwitchUser(new Builder(TYPE_CREATE)
+                    .setNewUserName(mNewUserName)
+                    .setNewUserFlags(UserFlags.ADMIN)
+                    .setSupportsOverrideUserIdProperty(info.supportsOverrideUserIdProperty)
+                    .setUserLocales(info.userLocales)
+                    .build(), fallback);
+        } else {
+            if (DBG) Log.d(TAG, "executeDefaultBehavior(): switching to initial user");
+            int userId = mHelper.getInitialUser(info.supportsOverrideUserIdProperty);
+            switchUser(new Builder(TYPE_SWITCH)
+                    .setSwitchUserId(userId)
+                    .setSupportsOverrideUserIdProperty(info.supportsOverrideUserIdProperty)
+                    .setReplaceGuest(info.replaceGuest)
+                    .build(), fallback);
+        }
+    }
+
+    @VisibleForTesting
+    void fallbackDefaultBehavior(@NonNull InitialUserInfo info, boolean fallback,
+            @NonNull String reason) {
+        if (!fallback) {
+            // Only log the error
+            Log.w(TAG, reason);
+            // Must explicitly tell listener that initial user could not be determined
+            notifyListener(/*initialUser= */ null);
+            return;
+        }
+        Log.w(TAG, "Falling back to default behavior. Reason: " + reason);
+        executeDefaultBehavior(info, /* fallback= */ false);
+    }
+
+    private void switchUser(@NonNull InitialUserInfo info, boolean fallback) {
+        int userId = info.switchUserId;
+        boolean replaceGuest = info.replaceGuest;
+
+        if (DBG) {
+            Log.d(TAG, "switchUser(): userId=" + userId + ", replaceGuest=" + replaceGuest
+                    + ", fallback=" + fallback);
+        }
+
+        UserInfo user = mUm.getUserInfo(userId);
+        if (user == null) {
+            fallbackDefaultBehavior(info, fallback, "user with id " + userId + " doesn't exist");
+            return;
+        }
+
+        UserInfo actualUser = user;
+
+        if (user.isGuest() && replaceGuest) {
+            actualUser = replaceGuestIfNeeded(user);
+
+            if (actualUser == null) {
+                fallbackDefaultBehavior(info, fallback, "could not replace guest "
+                        + user.toFullString());
+                return;
+            }
+        }
+
+        int actualUserId = actualUser.id;
+
+        unlockSystemUserIfNecessary(actualUserId);
+
+        int currentUserId = ActivityManager.getCurrentUser();
+        if (actualUserId != currentUserId) {
+            if (!startForegroundUser(actualUserId)) {
+                fallbackDefaultBehavior(info, fallback,
+                        "am.switchUser(" + actualUserId + ") failed");
+                return;
+            }
+            mHelper.setLastActiveUser(actualUserId);
+        }
+        notifyListener(actualUser);
+
+        if (actualUserId != userId) {
+            Slog.i(TAG, "Removing old guest " + userId);
+            if (!mUm.removeUser(userId)) {
+                Slog.w(TAG, "Could not remove old guest " + userId);
+            }
+        }
+    }
+
+    private void unlockSystemUserIfNecessary(@UserIdInt int userId) {
+        // If system user is the only user to unlock, it will be handled when boot is complete.
+        if (userId != UserHandle.USER_SYSTEM) {
+            unlockSystemUser();
+        }
+    }
+
+    // TODO(b/151758646): move to CarUserManagerHelper
+    /**
+     * Replaces {@code user} by a new guest, if necessary.
+     *
+     * <p>If {@code user} is not a guest, it doesn't do anything and returns the same user.
+     *
+     * <p>Otherwise, it marks the current guest for deletion, creates a new one, and returns the
+     * new guest (or {@code null} if a new guest could not be created).
+     */
+    @Nullable
+    public UserInfo replaceGuestIfNeeded(@NonNull UserInfo user) {
+        Preconditions.checkArgument(user != null, "user cannot be null");
+
+        if (!user.isGuest()) return user;
+
+        if (mLockPatternUtils.isSecure(user.id)) {
+            if (DBG) {
+                Log.d(TAG, "replaceGuestIfNeeded(), skipped, since user "
+                        + user.id + " has secure lock pattern");
+            }
+            return user;
+        }
+
+        Log.i(TAG, "Replacing guest (" + user.toFullString() + ")");
+
+        int halFlags = UserFlags.GUEST;
+        if (user.isEphemeral()) {
+            halFlags |= UserFlags.EPHEMERAL;
+        } else {
+            // TODO(b/150413515): decide whether we should allow it or not. Right now we're
+            // just logging, as UserManagerService will automatically set it to ephemeral if
+            // platform is set to do so.
+            Log.w(TAG, "guest being replaced is not ephemeral: " + user.toFullString());
+        }
+
+        if (!mUm.markGuestForDeletion(user.id)) {
+            // Don't need to recover in case of failure - most likely create new user will fail
+            // because there is already a guest
+            Log.w(TAG, "failed to mark guest " + user.id + " for deletion");
+        }
+
+        Pair<UserInfo, String> result = createNewUser(new Builder(TYPE_CREATE)
+                .setNewUserName(mNewGuestName)
+                .setNewUserFlags(halFlags)
+                .build());
+
+        String errorMessage = result.second;
+        if (errorMessage != null) {
+            Log.w(TAG, "could not replace guest " + user.toFullString() + ": " + errorMessage);
+            return null;
+        }
+
+        return result.first;
+    }
+
+    private void createAndSwitchUser(@NonNull InitialUserInfo info, boolean fallback) {
+        Pair<UserInfo, String> result = createNewUser(info);
+        String reason = result.second;
+        if (reason != null) {
+            fallbackDefaultBehavior(info, fallback, reason);
+            return;
+        }
+
+        switchUser(new Builder(TYPE_SWITCH)
+                .setSwitchUserId(result.first.id)
+                .setSupportsOverrideUserIdProperty(info.supportsOverrideUserIdProperty)
+                .build(), fallback);
+    }
+
+    /**
+     * Creates a new user.
+     *
+     * @return on success, first element is the new user; on failure, second element contains the
+     * error message.
+     */
+    @NonNull
+    private Pair<UserInfo, String> createNewUser(@NonNull InitialUserInfo info) {
+        String name = info.newUserName;
+        int halFlags = info.newUserFlags;
+
+        if (DBG) {
+            Log.d(TAG, "createUser(name=" + safeName(name) + ", flags="
+                    + userFlagsToString(halFlags) + ")");
+        }
+
+        if (UserHalHelper.isSystem(halFlags)) {
+            return new Pair<>(null, "Cannot create system user");
+        }
+
+        if (UserHalHelper.isAdmin(halFlags)) {
+            boolean validAdmin = true;
+            if (UserHalHelper.isGuest(halFlags)) {
+                Log.w(TAG, "Cannot create guest admin");
+                validAdmin = false;
+            }
+            if (UserHalHelper.isEphemeral(halFlags)) {
+                Log.w(TAG, "Cannot create ephemeral admin");
+                validAdmin = false;
+            }
+            if (!validAdmin) {
+                return new Pair<>(null, "Invalid flags for admin user");
+            }
+        }
+        // TODO(b/150413515): decide what to if HAL requested a non-ephemeral guest but framework
+        // sets all guests as ephemeral - should it fail or just warn?
+
+        int flags = UserHalHelper.toUserInfoFlags(halFlags);
+        String type = UserHalHelper.isGuest(halFlags) ? UserManager.USER_TYPE_FULL_GUEST
+                : UserManager.USER_TYPE_FULL_SECONDARY;
+
+        if (DBG) {
+            Log.d(TAG, "calling am.createUser((name=" + safeName(name) + ", type=" + type
+                    + ", flags=" + UserInfo.flagsToString(flags) + ")");
+        }
+
+        UserInfo userInfo = mUm.createUser(name, type, flags);
+        if (userInfo == null) {
+            return new Pair<>(null, "createUser(name=" + safeName(name) + ", flags="
+                    + userFlagsToString(halFlags) + "): failed to create user");
+        }
+
+        if (DBG) Log.d(TAG, "user created: " + userInfo.id);
+
+        if (info.userLocales != null) {
+            if (DBG) {
+                Log.d(TAG, "setting locale for user " + userInfo.id + " to " + info.userLocales);
+            }
+            Settings.System.putStringForUser(mContext.getContentResolver(),
+                    Settings.System.SYSTEM_LOCALES, info.userLocales, userInfo.id);
+        }
+
+        return new Pair<>(userInfo, null);
+    }
+
+    @VisibleForTesting
+    void unlockSystemUser() {
+        Log.i(TAG, "unlocking system user");
+        IActivityManager am = ActivityManager.getService();
+
+        TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
+        t.traceBegin("UnlockSystemUser");
+        try {
+            // This is for force changing state into RUNNING_LOCKED. Otherwise unlock does not
+            // update the state and USER_SYSTEM unlock happens twice.
+            t.traceBegin("am.startUser");
+            boolean started = am.startUserInBackground(UserHandle.USER_SYSTEM);
+            t.traceEnd();
+            if (!started) {
+                Log.w(TAG, "could not restart system user in foreground; trying unlock instead");
+                t.traceBegin("am.unlockUser");
+                boolean unlocked = am.unlockUser(UserHandle.USER_SYSTEM, /* token= */ null,
+                        /* secret= */ null, /* listener= */ null);
+                t.traceEnd();
+                if (!unlocked) {
+                    Log.w(TAG, "could not unlock system user neither");
+                    return;
+                }
+            }
+        } catch (RemoteException e) {
+            // should not happen for local call.
+            Log.wtf("RemoteException from AMS", e);
+        } finally {
+            t.traceEnd();
+        }
+    }
+
+    @VisibleForTesting
+    boolean startForegroundUser(@UserIdInt int userId) {
+        if (UserHelper.isHeadlessSystemUser(userId)) {
+            // System User doesn't associate with real person, can not be switched to.
+            return false;
+        }
+        try {
+            return ActivityManager.getService().startUserInForegroundWithListener(userId, null);
+        } catch (RemoteException e) {
+            Log.w(TAG, "failed to start user " + userId, e);
+            return false;
+        }
+    }
+
+    private void notifyListener(@Nullable UserInfo initialUser) {
+        if (DBG) Log.d(TAG, "notifyListener(): " + initialUser);
+        mListener.accept(initialUser);
+    }
+
+    /**
+     * Dumps it state.
+     */
+    public void dump(@NonNull PrintWriter writer) {
+        writer.println("InitialUserSetter");
+        String indent = "  ";
+        writer.printf("%smNewUserName: %s\n", indent, mNewUserName);
+        writer.printf("%smNewGuestName: %s\n", indent, mNewGuestName);
+    }
+}
diff --git a/user/car-user-lib/src/android/car/userlib/TestableFrameworkWrapper.java b/user/car-user-lib/src/android/car/userlib/TestableFrameworkWrapper.java
deleted file mode 100644
index 472ccac..0000000
--- a/user/car-user-lib/src/android/car/userlib/TestableFrameworkWrapper.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.car.userlib;
-
-import android.os.UserManager;
-import android.sysprop.CarProperties;
-
-/**
- * Testable versions of APIs from the framework.  This helps test difficult areas of the framework
- * due to limitations like SELinux or hard to mock static methods.
- */
-public class TestableFrameworkWrapper {
-    /**
-     * Wrapper around {@link CarProperties#boot_user_override_id()}
-     */
-    public int getBootUserOverrideId(int defaultValue) {
-        return CarProperties.boot_user_override_id().orElse(defaultValue);
-    }
-
-    /**
-     * Wrapper around {@link UserManager#getMaxSupportedUsers()}
-     */
-    public int userManagerGetMaxSupportedUsers() {
-        return UserManager.getMaxSupportedUsers();
-    }
-}
diff --git a/user/car-user-lib/src/android/car/userlib/UserHalHelper.java b/user/car-user-lib/src/android/car/userlib/UserHalHelper.java
new file mode 100644
index 0000000..3876b12
--- /dev/null
+++ b/user/car-user-lib/src/android/car/userlib/UserHalHelper.java
@@ -0,0 +1,678 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.userlib;
+
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.car.userlib.HalCallback.HalCallbackStatus;
+import android.content.pm.UserInfo;
+import android.content.pm.UserInfo.UserInfoFlag;
+import android.hardware.automotive.vehicle.V2_0.CreateUserRequest;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
+import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
+import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
+import android.hardware.automotive.vehicle.V2_0.UserFlags;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociation;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationValue;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetAssociation;
+import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest;
+import android.hardware.automotive.vehicle.V2_0.UsersInfo;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.text.TextUtils;
+import android.util.DebugUtils;
+import android.util.Log;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Provides utility methods for User HAL related functionalities.
+ */
+public final class UserHalHelper {
+
+    private static final String TAG = UserHalHelper.class.getSimpleName();
+    private static final boolean DEBUG = false;
+
+    public static final int INITIAL_USER_INFO_PROPERTY = 299896583;
+    public static final int SWITCH_USER_PROPERTY = 299896584;
+    public static final int CREATE_USER_PROPERTY = 299896585;
+    public static final int REMOVE_USER_PROPERTY = 299896586;
+    public static final int USER_IDENTIFICATION_ASSOCIATION_PROPERTY = 299896587;
+
+
+    private static final String STRING_SEPARATOR = "\\|\\|";
+
+    /**
+     * Gets user-friendly representation of the status.
+     */
+    public static String halCallbackStatusToString(@HalCallbackStatus int status) {
+        switch (status) {
+            case HalCallback.STATUS_OK:
+                return "OK";
+            case HalCallback.STATUS_HAL_SET_TIMEOUT:
+                return "HAL_SET_TIMEOUT";
+            case HalCallback.STATUS_HAL_RESPONSE_TIMEOUT:
+                return "HAL_RESPONSE_TIMEOUT";
+            case HalCallback.STATUS_WRONG_HAL_RESPONSE:
+                return "WRONG_HAL_RESPONSE";
+            case HalCallback.STATUS_CONCURRENT_OPERATION:
+                return "CONCURRENT_OPERATION";
+            default:
+                return "UNKNOWN-" + status;
+        }
+    }
+
+    /**
+     * Converts a string to a {@link InitialUserInfoRequestType}.
+     *
+     * @return valid type or numeric value if passed "as is"
+     *
+     * @throws IllegalArgumentException if type is not valid neither a number
+     */
+    public static int parseInitialUserInfoRequestType(@NonNull String type) {
+        switch(type) {
+            case "FIRST_BOOT":
+                return InitialUserInfoRequestType.FIRST_BOOT;
+            case "FIRST_BOOT_AFTER_OTA":
+                return InitialUserInfoRequestType.FIRST_BOOT_AFTER_OTA;
+            case "COLD_BOOT":
+                return InitialUserInfoRequestType.COLD_BOOT;
+            case "RESUME":
+                return InitialUserInfoRequestType.RESUME;
+            default:
+                try {
+                    return Integer.parseInt(type);
+                } catch (NumberFormatException e) {
+                    throw new IllegalArgumentException("invalid type: " + type);
+                }
+        }
+    }
+
+    /**
+     * Converts Android user flags to HALs.
+     */
+    public static int convertFlags(@NonNull UserInfo user) {
+        checkArgument(user != null, "user cannot be null");
+
+        int flags = UserFlags.NONE;
+        if (user.id == UserHandle.USER_SYSTEM) {
+            flags |= UserFlags.SYSTEM;
+        }
+        if (user.isAdmin()) {
+            flags |= UserFlags.ADMIN;
+        }
+        if (user.isGuest()) {
+            flags |= UserFlags.GUEST;
+        }
+        if (user.isEphemeral()) {
+            flags |= UserFlags.EPHEMERAL;
+        }
+        if (!user.isEnabled()) {
+            flags |= UserFlags.DISABLED;
+        }
+        if (user.isProfile()) {
+            flags |= UserFlags.PROFILE;
+        }
+
+        return flags;
+    }
+
+    /**
+     * Converts Android user flags to HALs.
+     */
+    public static int getFlags(@NonNull UserManager um, @UserIdInt int userId) {
+        Preconditions.checkArgument(um != null, "UserManager cannot be null");
+        UserInfo user = um.getUserInfo(userId);
+        Preconditions.checkArgument(user != null, "No user with id %d", userId);
+        return convertFlags(user);
+    }
+
+    /**
+     * Checks if a HAL flag contains {@link UserFlags#SYSTEM}.
+     */
+    public static boolean isSystem(int flags) {
+        return (flags & UserFlags.SYSTEM) != 0;
+    }
+
+    /**
+     * Checks if a HAL flag contains {@link UserFlags#GUEST}.
+     */
+    public static boolean isGuest(int flags) {
+        return (flags & UserFlags.GUEST) != 0;
+    }
+
+    /**
+     * Checks if a HAL flag contains {@link UserFlags#EPHEMERAL}.
+     */
+    public static boolean isEphemeral(int flags) {
+        return (flags & UserFlags.EPHEMERAL) != 0;
+    }
+
+    /**
+     * Checks if a HAL flag contains {@link UserFlags#ADMIN}.
+     */
+    public static boolean isAdmin(int flags) {
+        return (flags & UserFlags.ADMIN) != 0;
+    }
+
+    /**
+     * Checks if a HAL flag contains {@link UserFlags#DISABLED}.
+     */
+    public static boolean isDisabled(int flags) {
+        return (flags & UserFlags.DISABLED) != 0;
+    }
+
+    /**
+     * Checks if a HAL flag contains {@link UserFlags#PROFILE}.
+     */
+    public static boolean isProfile(int flags) {
+        return (flags & UserFlags.PROFILE) != 0;
+    }
+
+    /**
+     * Converts HAL flags to Android's.
+     */
+    @UserInfoFlag
+    public static int toUserInfoFlags(int halFlags) {
+        int flags = 0;
+        if (isEphemeral(halFlags)) {
+            flags |= UserInfo.FLAG_EPHEMERAL;
+        }
+        if (isAdmin(halFlags)) {
+            flags |= UserInfo.FLAG_ADMIN;
+        }
+        return flags;
+    }
+
+    /**
+     * Gets a user-friendly representation of the user flags.
+     */
+    @NonNull
+    public static String userFlagsToString(int flags) {
+        return DebugUtils.flagsToString(UserFlags.class, "", flags);
+    }
+
+    /**
+     * Creates a {@link VehiclePropValue} with the given {@code prop}, {@code requestId},
+     * and {@code requestType}.
+     */
+    @NonNull
+    public static VehiclePropValue createPropRequest(int prop, int requestId, int requestType) {
+        VehiclePropValue propRequest = createPropRequest(prop, requestId);
+        propRequest.value.int32Values.add(requestType);
+
+        return propRequest;
+    }
+
+    /**
+     * Creates a {@link VehiclePropValue} with the given {@code prop} and {@code requestId}.
+     */
+    @NonNull
+    public static VehiclePropValue createPropRequest(int prop, int requestId) {
+        VehiclePropValue propRequest = new VehiclePropValue();
+        propRequest.prop = prop;
+        propRequest.timestamp = SystemClock.elapsedRealtime();
+        propRequest.value.int32Values.add(requestId);
+
+        return propRequest;
+    }
+
+    /**
+     * Adds users information to prop value.
+     *
+     * <p><b>NOTE: </b>it does not validate the semantics of {@link UsersInfo} content (for example,
+     * if the current user is present in the list of users or if the flags are valid), only the
+     * basic correctness (like number of users matching existing users list size). Use
+     * {@link #checkValid(UsersInfo)} for a full check.
+     */
+    public static void addUsersInfo(@NonNull VehiclePropValue propRequest,
+                @NonNull UsersInfo usersInfo) {
+        Objects.requireNonNull(propRequest, "VehiclePropValue cannot be null");
+        Objects.requireNonNull(usersInfo.currentUser, "Current user cannot be null");
+        checkArgument(usersInfo.numberUsers == usersInfo.existingUsers.size(),
+                "Number of existing users info does not match numberUsers");
+
+        addUserInfo(propRequest, usersInfo.currentUser);
+        propRequest.value.int32Values.add(usersInfo.numberUsers);
+        for (int i = 0; i < usersInfo.numberUsers; i++) {
+            android.hardware.automotive.vehicle.V2_0.UserInfo userInfo =
+                    usersInfo.existingUsers.get(i);
+            addUserInfo(propRequest, userInfo);
+        }
+    }
+
+    /**
+     * Adds user information to prop value.
+     */
+    public static void addUserInfo(@NonNull VehiclePropValue propRequest,
+            @NonNull android.hardware.automotive.vehicle.V2_0.UserInfo userInfo) {
+        Objects.requireNonNull(propRequest, "VehiclePropValue cannot be null");
+        Objects.requireNonNull(userInfo, "UserInfo cannot be null");
+
+        propRequest.value.int32Values.add(userInfo.userId);
+        propRequest.value.int32Values.add(userInfo.flags);
+    }
+
+    /**
+     * Checks if the given {@code value} is a valid {@link UserIdentificationAssociationType}.
+     */
+    public static boolean isValidUserIdentificationAssociationType(int type) {
+        switch(type) {
+            case UserIdentificationAssociationType.KEY_FOB:
+            case UserIdentificationAssociationType.CUSTOM_1:
+            case UserIdentificationAssociationType.CUSTOM_2:
+            case UserIdentificationAssociationType.CUSTOM_3:
+            case UserIdentificationAssociationType.CUSTOM_4:
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Checks if the given {@code value} is a valid {@link UserIdentificationAssociationValue}.
+     */
+    public static boolean isValidUserIdentificationAssociationValue(int value) {
+        switch(value) {
+            case UserIdentificationAssociationValue.ASSOCIATED_ANOTHER_USER:
+            case UserIdentificationAssociationValue.ASSOCIATED_CURRENT_USER:
+            case UserIdentificationAssociationValue.NOT_ASSOCIATED_ANY_USER:
+            case UserIdentificationAssociationValue.UNKNOWN:
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Checks if the given {@code value} is a valid {@link UserIdentificationAssociationSetValue}.
+     */
+    public static boolean isValidUserIdentificationAssociationSetValue(int value) {
+        switch(value) {
+            case UserIdentificationAssociationSetValue.ASSOCIATE_CURRENT_USER:
+            case UserIdentificationAssociationSetValue.DISASSOCIATE_CURRENT_USER:
+            case UserIdentificationAssociationSetValue.DISASSOCIATE_ALL_USERS:
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Creates a {@link UserIdentificationResponse} from a generic {@link VehiclePropValue} sent by
+     * HAL.
+     *
+     * @throws IllegalArgumentException if the HAL property doesn't have the proper format.
+     */
+    @NonNull
+    public static UserIdentificationResponse toUserIdentificationResponse(
+            @NonNull VehiclePropValue prop) {
+        Objects.requireNonNull(prop, "prop cannot be null");
+        checkArgument(prop.prop == USER_IDENTIFICATION_ASSOCIATION_PROPERTY,
+                "invalid prop on %s", prop);
+        // need at least 4: request_id, number associations, type1, value1
+        assertMinimumSize(prop, 4);
+
+        int requestId = prop.value.int32Values.get(0);
+        checkArgument(requestId > 0, "invalid request id (%d) on %s", requestId, prop);
+
+        int numberAssociations = prop.value.int32Values.get(1);
+        checkArgument(numberAssociations >= 1, "invalid number of items on %s", prop);
+        int numberOfNonItems = 2; // requestId and size
+        int numberItems = prop.value.int32Values.size() - numberOfNonItems;
+        checkArgument(numberItems == numberAssociations * 2, "number of items mismatch on %s",
+                prop);
+
+        UserIdentificationResponse response = new UserIdentificationResponse();
+        response.requestId = requestId;
+        response.errorMessage = prop.value.stringValue;
+
+        response.numberAssociation = numberAssociations;
+        int i = numberOfNonItems;
+        for (int a = 0; a < numberAssociations; a++) {
+            int index;
+            UserIdentificationAssociation association = new UserIdentificationAssociation();
+            index = i++;
+            association.type = prop.value.int32Values.get(index);
+            checkArgument(isValidUserIdentificationAssociationType(association.type),
+                    "invalid type at index %d on %s", index, prop);
+            index = i++;
+            association.value = prop.value.int32Values.get(index);
+            checkArgument(isValidUserIdentificationAssociationValue(association.value),
+                    "invalid value at index %d on %s", index, prop);
+            response.associations.add(association);
+        }
+
+        return response;
+    }
+
+    /**
+     * Creates a {@link InitialUserInfoResponse} from a generic {@link VehiclePropValue} sent by
+     * HAL.
+     *
+     * @throws IllegalArgumentException if the HAL property doesn't have the proper format.
+     */
+    @NonNull
+    public static InitialUserInfoResponse toInitialUserInfoResponse(
+            @NonNull VehiclePropValue prop) {
+        if (DEBUG) Log.d(TAG, "toInitialUserInfoResponse(): " + prop);
+        Objects.requireNonNull(prop, "prop cannot be null");
+        checkArgument(prop.prop == INITIAL_USER_INFO_PROPERTY, "invalid prop on %s", prop);
+
+        // need at least 2: request_id, action_type
+        assertMinimumSize(prop, 2);
+
+        int requestId = prop.value.int32Values.get(0);
+        checkArgument(requestId > 0, "invalid request id (%d) on %s", requestId, prop);
+
+        InitialUserInfoResponse response = new InitialUserInfoResponse();
+        response.requestId = requestId;
+        response.action = prop.value.int32Values.get(1);
+
+        String[] stringValues = null;
+        if (!TextUtils.isEmpty(prop.value.stringValue)) {
+            stringValues = TextUtils.split(prop.value.stringValue, STRING_SEPARATOR);
+            if (DEBUG) {
+                Log.d(TAG, "toInitialUserInfoResponse(): values=" + Arrays.toString(stringValues)
+                        + " length: " + stringValues.length);
+            }
+        }
+        if (stringValues != null && stringValues.length > 0) {
+            response.userLocales = stringValues[0];
+        }
+
+        switch (response.action) {
+            case InitialUserInfoResponseAction.DEFAULT:
+                response.userToSwitchOrCreate.userId = UserHandle.USER_NULL;
+                response.userToSwitchOrCreate.flags = UserFlags.NONE;
+                break;
+            case InitialUserInfoResponseAction.SWITCH:
+                assertMinimumSize(prop, 3); // request_id, action_type, user_id
+                response.userToSwitchOrCreate.userId = prop.value.int32Values.get(2);
+                response.userToSwitchOrCreate.flags = UserFlags.NONE;
+                break;
+            case InitialUserInfoResponseAction.CREATE:
+                assertMinimumSize(prop, 4); // request_id, action_type, user_id, user_flags
+                // user id is set at index 2, but it's ignored
+                response.userToSwitchOrCreate.userId = UserHandle.USER_NULL;
+                response.userToSwitchOrCreate.flags = prop.value.int32Values.get(3);
+                if (stringValues.length > 1) {
+                    response.userNameToCreate = stringValues[1];
+                }
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "Invalid response action (" + response.action + " on " + prop);
+        }
+
+        if (DEBUG) Log.d(TAG, "returning : " + response);
+
+        return response;
+    }
+
+    /**
+     * Creates a generic {@link VehiclePropValue} (that can be sent to HAL) from a
+     * {@link UserIdentificationGetRequest}.
+     *
+     * @throws IllegalArgumentException if the request doesn't have the proper format.
+     */
+    @NonNull
+    public static VehiclePropValue toVehiclePropValue(
+            @NonNull UserIdentificationGetRequest request) {
+        Objects.requireNonNull(request, "request cannot be null");
+        checkArgument(request.numberAssociationTypes > 0,
+                "invalid number of association types mismatch on %s", request);
+        checkArgument(request.numberAssociationTypes == request.associationTypes.size(),
+                "number of association types mismatch on %s", request);
+        checkArgument(request.requestId > 0, "invalid requestId on %s", request);
+
+        VehiclePropValue propValue = createPropRequest(USER_IDENTIFICATION_ASSOCIATION_PROPERTY,
+                request.requestId);
+        addUserInfo(propValue, request.userInfo);
+        propValue.value.int32Values.add(request.numberAssociationTypes);
+
+        for (int i = 0; i < request.numberAssociationTypes; i++) {
+            int type = request.associationTypes.get(i);
+            checkArgument(isValidUserIdentificationAssociationType(type),
+                    "invalid type at index %d on %s", i, request);
+            propValue.value.int32Values.add(type);
+        }
+
+        return propValue;
+    }
+
+    /**
+     * Creates a generic {@link VehiclePropValue} (that can be sent to HAL) from a
+     * {@link UserIdentificationSetRequest}.
+     *
+     * @throws IllegalArgumentException if the request doesn't have the proper format.
+     */
+    @NonNull
+    public static VehiclePropValue toVehiclePropValue(
+            @NonNull UserIdentificationSetRequest request) {
+        Objects.requireNonNull(request, "request cannot be null");
+        checkArgument(request.numberAssociations > 0,
+                "invalid number of associations  mismatch on %s", request);
+        checkArgument(request.numberAssociations == request.associations.size(),
+                "number of associations mismatch on %s", request);
+        checkArgument(request.requestId > 0, "invalid requestId on %s", request);
+
+        VehiclePropValue propValue = createPropRequest(USER_IDENTIFICATION_ASSOCIATION_PROPERTY,
+                request.requestId);
+        addUserInfo(propValue, request.userInfo);
+        propValue.value.int32Values.add(request.numberAssociations);
+
+        for (int i = 0; i < request.numberAssociations; i++) {
+            UserIdentificationSetAssociation association = request.associations.get(i);
+            checkArgument(isValidUserIdentificationAssociationType(association.type),
+                    "invalid type at index %d on %s", i, request);
+            propValue.value.int32Values.add(association.type);
+            checkArgument(isValidUserIdentificationAssociationSetValue(association.value),
+                    "invalid value at index %d on %s", i, request);
+            propValue.value.int32Values.add(association.value);
+        }
+
+        return propValue;
+    }
+
+    /**
+     * Creates a generic {@link VehiclePropValue} (that can be sent to HAL) from a
+     * {@link CreateUserRequest}.
+     *
+     * @throws IllegalArgumentException if the request doesn't have the proper format.
+     */
+    @NonNull
+    public static VehiclePropValue toVehiclePropValue(@NonNull CreateUserRequest request) {
+        Objects.requireNonNull(request, "request cannot be null");
+        checkArgument(request.requestId > 0, "invalid requestId on %s", request);
+        checkValid(request.usersInfo);
+        checkArgument(request.newUserName != null, "newUserName cannot be null (should be empty "
+                + "instead) on %s", request);
+
+        boolean hasNewUser = false;
+        int newUserFlags = UserFlags.NONE;
+        for (int i = 0; i < request.usersInfo.existingUsers.size(); i++) {
+            android.hardware.automotive.vehicle.V2_0.UserInfo user =
+                    request.usersInfo.existingUsers.get(i);
+            if (user.userId == request.newUserInfo.userId) {
+                hasNewUser = true;
+                newUserFlags = user.flags;
+                break;
+            }
+        }
+        Preconditions.checkArgument(hasNewUser,
+                "new user's id not present on existing users on request %s", request);
+        Preconditions.checkArgument(request.newUserInfo.flags == newUserFlags,
+                "new user flags mismatch on existing users on %s", request);
+
+        VehiclePropValue propValue = createPropRequest(CREATE_USER_PROPERTY,
+                request.requestId);
+        propValue.value.stringValue = request.newUserName;
+        addUserInfo(propValue, request.newUserInfo);
+        addUsersInfo(propValue, request.usersInfo);
+
+        return propValue;
+    }
+
+    /**
+     * Creates a generic {@link VehiclePropValue} (that can be sent to HAL) from a
+     * {@link SwitchUserRequest}.
+     *
+     * @throws IllegalArgumentException if the request doesn't have the proper format.
+     */
+    @NonNull
+    public static VehiclePropValue toVehiclePropValue(@NonNull SwitchUserRequest request) {
+        Objects.requireNonNull(request, "request cannot be null");
+        checkArgument(request.messageType > 0, "invalid messageType on %s", request);
+        android.hardware.automotive.vehicle.V2_0.UserInfo targetInfo = request.targetUser;
+        UsersInfo usersInfo = request.usersInfo;
+        Objects.requireNonNull(targetInfo);
+        checkValid(usersInfo);
+
+        VehiclePropValue propValue = createPropRequest(SWITCH_USER_PROPERTY, request.requestId,
+                request.messageType);
+        addUserInfo(propValue, targetInfo);
+        addUsersInfo(propValue, usersInfo);
+        return propValue;
+    }
+
+    /**
+     * Creates a generic {@link VehiclePropValue} (that can be sent to HAL) from a
+     * {@link RemoveUserRequest}.
+     *
+     * @throws IllegalArgumentException if the request doesn't have the proper format.
+     */
+    @NonNull
+    public static VehiclePropValue toVehiclePropValue(@NonNull RemoveUserRequest request) {
+        checkArgument(request.requestId > 0, "invalid requestId on %s", request);
+        android.hardware.automotive.vehicle.V2_0.UserInfo removedUserInfo = request.removedUserInfo;
+        Objects.requireNonNull(removedUserInfo);
+        UsersInfo usersInfo = request.usersInfo;
+        checkValid(usersInfo);
+
+        VehiclePropValue propValue = createPropRequest(REMOVE_USER_PROPERTY, request.requestId);
+        addUserInfo(propValue, removedUserInfo);
+        addUsersInfo(propValue, usersInfo);
+        return propValue;
+    }
+
+    /**
+     * Creates a {@link UsersInfo} instance populated with the current users, using
+     * {@link ActivityManager#getCurrentUser()} as the current user.
+     */
+    @NonNull
+    public static UsersInfo newUsersInfo(@NonNull UserManager um) {
+        return newUsersInfo(um, ActivityManager.getCurrentUser());
+    }
+
+    /**
+     * Creates a {@link UsersInfo} instance populated with the current users, using
+     * {@code userId} as the current user.
+     */
+    @NonNull
+    public static UsersInfo newUsersInfo(@NonNull UserManager um, @UserIdInt int userId) {
+        Preconditions.checkArgument(um != null, "UserManager cannot be null");
+
+        List<UserInfo> users = um.getUsers(/* excludePartial= */ false, /* excludeDying= */ false,
+                /* excludePreCreated= */ true);
+
+        if (users == null || users.isEmpty()) {
+            Log.w(TAG, "newUsersInfo(): no users");
+            return emptyUsersInfo();
+        }
+
+        UsersInfo usersInfo = new UsersInfo();
+        usersInfo.currentUser.userId = userId;
+        UserInfo currentUser = null;
+        usersInfo.numberUsers = users.size();
+
+        for (int i = 0; i < usersInfo.numberUsers; i++) {
+            UserInfo user = users.get(i);
+            if (user.id == usersInfo.currentUser.userId) {
+                currentUser = user;
+            }
+            android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
+                    new android.hardware.automotive.vehicle.V2_0.UserInfo();
+            halUser.userId = user.id;
+            halUser.flags = convertFlags(user);
+            usersInfo.existingUsers.add(halUser);
+        }
+
+        if (currentUser != null) {
+            usersInfo.currentUser.flags = convertFlags(currentUser);
+        } else {
+            // This should not happen.
+            Log.wtf(TAG, "Current user is not part of existing users. usersInfo: " + usersInfo);
+        }
+
+        return usersInfo;
+    }
+
+    /**
+     * Checks if the given {@code usersInfo} is valid.
+     *
+     * @throws IllegalArgumentException if it isn't.
+     */
+    public static void checkValid(@NonNull UsersInfo usersInfo) {
+        Preconditions.checkArgument(usersInfo != null);
+        Preconditions.checkArgument(usersInfo.numberUsers == usersInfo.existingUsers.size(),
+                "sizes mismatch: numberUsers=%d, existingUsers.size=%d", usersInfo.numberUsers,
+                usersInfo.existingUsers.size());
+        boolean hasCurrentUser = false;
+        int currentUserFlags = UserFlags.NONE;
+        for (int i = 0; i < usersInfo.numberUsers; i++) {
+            android.hardware.automotive.vehicle.V2_0.UserInfo user = usersInfo.existingUsers.get(i);
+            if (user.userId == usersInfo.currentUser.userId) {
+                hasCurrentUser = true;
+                currentUserFlags = user.flags;
+                break;
+            }
+        }
+        Preconditions.checkArgument(hasCurrentUser,
+                "current user not found on existing users on %s", usersInfo);
+        Preconditions.checkArgument(usersInfo.currentUser.flags == currentUserFlags,
+                "current user flags mismatch on existing users on %s", usersInfo);
+    }
+
+    @NonNull
+    private static UsersInfo emptyUsersInfo() {
+        UsersInfo usersInfo = new UsersInfo();
+        usersInfo.currentUser.userId = UserHandle.USER_NULL;
+        usersInfo.currentUser.flags = UserFlags.NONE;
+        return usersInfo;
+    }
+
+    private static void assertMinimumSize(@NonNull VehiclePropValue prop, int minSize) {
+        checkArgument(prop.value.int32Values.size() >= minSize,
+                "not enough int32Values (minimum is %d) on %s", minSize, prop);
+    }
+
+    private UserHalHelper() {
+        throw new UnsupportedOperationException("contains only static methods");
+    }
+}
diff --git a/user/car-user-lib/src/android/car/userlib/UserHelper.java b/user/car-user-lib/src/android/car/userlib/UserHelper.java
new file mode 100644
index 0000000..9535ffb
--- /dev/null
+++ b/user/car-user-lib/src/android/car/userlib/UserHelper.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.userlib;
+
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+/**
+ * Provides utility methods for generic user-related functionalities that don't require a manager.
+ */
+public final class UserHelper {
+
+    private UserHelper() {
+        throw new UnsupportedOperationException("contains only static methods");
+    }
+
+    /**
+     * Gets a PII-safe representation of the name.
+     */
+    @Nullable
+    public static String safeName(@Nullable String name) {
+        return name == null ? name : name.length() + "_chars";
+    }
+
+    /**
+     * Checks whether the given user is both {@code SYSTEM} and headless.
+     */
+    public static boolean isHeadlessSystemUser(@UserIdInt int userId) {
+        return userId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode();
+    }
+}
diff --git a/vehicle-hal-support-lib/Android.bp b/vehicle-hal-support-lib/Android.bp
new file mode 100644
index 0000000..ca685a4
--- /dev/null
+++ b/vehicle-hal-support-lib/Android.bp
@@ -0,0 +1,40 @@
+// 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.
+//
+
+java_library {
+
+    name: "vehicle-hal-support-lib",
+
+    srcs: ["src/**/*.java"],
+
+    static_libs: [
+        "android.hidl.base-V1.0-java",
+        "android.hardware.automotive.vehicle-V2.0-java"
+    ],
+
+}
+
+java_library {
+
+    name: "vehicle-hal-support-lib-for-test",
+
+    srcs: ["test/**/*.java"],
+
+    static_libs: [
+        "vehicle-hal-support-lib",
+        "junit",
+    ],
+
+}
diff --git a/vehicle-hal-support-lib/Android.mk b/vehicle-hal-support-lib/Android.mk
deleted file mode 100644
index 22e094c..0000000
--- a/vehicle-hal-support-lib/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := vehicle-hal-support-lib
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    android.hidl.base-V1.0-java \
-    android.hardware.automotive.vehicle-V2.0-java \
-    junit
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/vehicle-hal-support-lib/src/com/android/car/vehiclehal/test/VehiclePropConfigBuilder.java b/vehicle-hal-support-lib/src/com/android/car/vehiclehal/test/VehiclePropConfigBuilder.java
index 59868d5..c66ba14 100644
--- a/vehicle-hal-support-lib/src/com/android/car/vehiclehal/test/VehiclePropConfigBuilder.java
+++ b/vehicle-hal-support-lib/src/com/android/car/vehiclehal/test/VehiclePropConfigBuilder.java
@@ -95,6 +95,14 @@
     }
 
     @CheckResult
+    public  VehiclePropConfigBuilder addAreaConfig(int areaId) {
+        VehicleAreaConfig area = new VehicleAreaConfig();
+        area.areaId = areaId;
+        mConfig.areaConfigs.add(area);
+        return this;
+    }
+
+    @CheckResult
     public VehiclePropConfigBuilder addAreaConfig(int areaId, int minValue, int maxValue) {
         VehicleAreaConfig area = new VehicleAreaConfig();
         area.areaId = areaId;
diff --git a/vehicle-hal-support-lib/src/com/android/car/vehiclehal/test/MockedVehicleHal.java b/vehicle-hal-support-lib/test/com/android/car/vehiclehal/test/MockedVehicleHal.java
similarity index 100%
rename from vehicle-hal-support-lib/src/com/android/car/vehiclehal/test/MockedVehicleHal.java
rename to vehicle-hal-support-lib/test/com/android/car/vehiclehal/test/MockedVehicleHal.java
diff --git a/watchdog/Android.mk b/watchdog/Android.mk
new file mode 100644
index 0000000..f0724fc
--- /dev/null
+++ b/watchdog/Android.mk
@@ -0,0 +1,16 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/watchdog/aidl/Android.bp b/watchdog/aidl/Android.bp
new file mode 100644
index 0000000..e17c87b
--- /dev/null
+++ b/watchdog/aidl/Android.bp
@@ -0,0 +1,31 @@
+// 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.
+
+aidl_interface {
+    name: "carwatchdog_aidl_interface",
+    vendor_available: true,
+    srcs: [
+        "android/automotive/watchdog/*.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            platform_apis: true,
+            enabled: true,
+        },
+    },
+    versions: [
+        "2",
+    ],
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/.hash b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/.hash
new file mode 100644
index 0000000..957c8ce
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/.hash
@@ -0,0 +1 @@
+eace40adc2f2d373348fedeb29f5ddcb329ce4ee
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/BootPhase.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/BootPhase.aidl
new file mode 100644
index 0000000..f8570de
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/BootPhase.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@Backing(type="int") @VintfStability
+enum BootPhase {
+  BOOT_COMPLETED = 1000,
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/ICarWatchdog.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/ICarWatchdog.aidl
new file mode 100644
index 0000000..61d4f32
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/ICarWatchdog.aidl
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+interface ICarWatchdog {
+  void registerClient(in android.automotive.watchdog.ICarWatchdogClient client, in android.automotive.watchdog.TimeoutLength timeout);
+  void unregisterClient(in android.automotive.watchdog.ICarWatchdogClient client);
+  void registerMediator(in android.automotive.watchdog.ICarWatchdogClient mediator);
+  void unregisterMediator(in android.automotive.watchdog.ICarWatchdogClient mediator);
+  void registerMonitor(in android.automotive.watchdog.ICarWatchdogMonitor monitor);
+  void unregisterMonitor(in android.automotive.watchdog.ICarWatchdogMonitor monitor);
+  void tellClientAlive(in android.automotive.watchdog.ICarWatchdogClient client, in int sessionId);
+  void tellMediatorAlive(in android.automotive.watchdog.ICarWatchdogClient mediator, in int[] clientsNotResponding, in int sessionId);
+  void tellDumpFinished(in android.automotive.watchdog.ICarWatchdogMonitor monitor, in int pid);
+  void notifySystemStateChange(in android.automotive.watchdog.StateType type, in int arg1, in int arg2);
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/ICarWatchdogClient.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/ICarWatchdogClient.aidl
new file mode 100644
index 0000000..d934ad0
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/ICarWatchdogClient.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+interface ICarWatchdogClient {
+  oneway void checkIfAlive(in int sessionId, in android.automotive.watchdog.TimeoutLength timeout);
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/ICarWatchdogMonitor.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/ICarWatchdogMonitor.aidl
new file mode 100644
index 0000000..f13af14
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/ICarWatchdogMonitor.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+interface ICarWatchdogMonitor {
+  oneway void onClientsNotResponding(in int[] pids);
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/PowerCycle.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/PowerCycle.aidl
new file mode 100644
index 0000000..2cfd03e
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/PowerCycle.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@Backing(type="int") @VintfStability
+enum PowerCycle {
+  POWER_CYCLE_SHUTDOWN = 0,
+  POWER_CYCLE_SUSPEND = 1,
+  POWER_CYCLE_RESUME = 2,
+  NUM_POWER_CYLES = 3,
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/StateType.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/StateType.aidl
new file mode 100644
index 0000000..52cd08e
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/StateType.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@Backing(type="int") @VintfStability
+enum StateType {
+  POWER_CYCLE = 0,
+  USER_STATE = 1,
+  BOOT_PHASE = 2,
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/TimeoutLength.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/TimeoutLength.aidl
new file mode 100644
index 0000000..e4be851
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/TimeoutLength.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@Backing(type="int") @VintfStability
+enum TimeoutLength {
+  TIMEOUT_CRITICAL = 0,
+  TIMEOUT_MODERATE = 1,
+  TIMEOUT_NORMAL = 2,
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/UserState.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/UserState.aidl
new file mode 100644
index 0000000..39dcc84
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/1/android/automotive/watchdog/UserState.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@Backing(type="int") @VintfStability
+enum UserState {
+  USER_STATE_STARTED = 0,
+  USER_STATE_STOPPED = 1,
+  NUM_USER_STATES = 2,
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/.hash b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/.hash
new file mode 100644
index 0000000..f024209
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/.hash
@@ -0,0 +1 @@
+f7adf2ef96b380c7fde3919f565eb764986bdcdd
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/BootPhase.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/BootPhase.aidl
new file mode 100644
index 0000000..f8570de
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/BootPhase.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@Backing(type="int") @VintfStability
+enum BootPhase {
+  BOOT_COMPLETED = 1000,
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/ICarWatchdog.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/ICarWatchdog.aidl
new file mode 100644
index 0000000..61d4f32
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/ICarWatchdog.aidl
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+interface ICarWatchdog {
+  void registerClient(in android.automotive.watchdog.ICarWatchdogClient client, in android.automotive.watchdog.TimeoutLength timeout);
+  void unregisterClient(in android.automotive.watchdog.ICarWatchdogClient client);
+  void registerMediator(in android.automotive.watchdog.ICarWatchdogClient mediator);
+  void unregisterMediator(in android.automotive.watchdog.ICarWatchdogClient mediator);
+  void registerMonitor(in android.automotive.watchdog.ICarWatchdogMonitor monitor);
+  void unregisterMonitor(in android.automotive.watchdog.ICarWatchdogMonitor monitor);
+  void tellClientAlive(in android.automotive.watchdog.ICarWatchdogClient client, in int sessionId);
+  void tellMediatorAlive(in android.automotive.watchdog.ICarWatchdogClient mediator, in int[] clientsNotResponding, in int sessionId);
+  void tellDumpFinished(in android.automotive.watchdog.ICarWatchdogMonitor monitor, in int pid);
+  void notifySystemStateChange(in android.automotive.watchdog.StateType type, in int arg1, in int arg2);
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/ICarWatchdogClient.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/ICarWatchdogClient.aidl
new file mode 100644
index 0000000..9768565
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/ICarWatchdogClient.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+interface ICarWatchdogClient {
+  oneway void checkIfAlive(in int sessionId, in android.automotive.watchdog.TimeoutLength timeout);
+  oneway void prepareProcessTermination();
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/ICarWatchdogMonitor.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/ICarWatchdogMonitor.aidl
new file mode 100644
index 0000000..f13af14
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/ICarWatchdogMonitor.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+interface ICarWatchdogMonitor {
+  oneway void onClientsNotResponding(in int[] pids);
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/PowerCycle.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/PowerCycle.aidl
new file mode 100644
index 0000000..2cfd03e
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/PowerCycle.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@Backing(type="int") @VintfStability
+enum PowerCycle {
+  POWER_CYCLE_SHUTDOWN = 0,
+  POWER_CYCLE_SUSPEND = 1,
+  POWER_CYCLE_RESUME = 2,
+  NUM_POWER_CYLES = 3,
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/StateType.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/StateType.aidl
new file mode 100644
index 0000000..52cd08e
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/StateType.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@Backing(type="int") @VintfStability
+enum StateType {
+  POWER_CYCLE = 0,
+  USER_STATE = 1,
+  BOOT_PHASE = 2,
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/TimeoutLength.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/TimeoutLength.aidl
new file mode 100644
index 0000000..e4be851
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/TimeoutLength.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@Backing(type="int") @VintfStability
+enum TimeoutLength {
+  TIMEOUT_CRITICAL = 0,
+  TIMEOUT_MODERATE = 1,
+  TIMEOUT_NORMAL = 2,
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/UserState.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/UserState.aidl
new file mode 100644
index 0000000..39dcc84
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/2/android/automotive/watchdog/UserState.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@Backing(type="int") @VintfStability
+enum UserState {
+  USER_STATE_STARTED = 0,
+  USER_STATE_STOPPED = 1,
+  NUM_USER_STATES = 2,
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/BootPhase.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/BootPhase.aidl
new file mode 100644
index 0000000..f8570de
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/BootPhase.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@Backing(type="int") @VintfStability
+enum BootPhase {
+  BOOT_COMPLETED = 1000,
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/ICarWatchdog.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/ICarWatchdog.aidl
new file mode 100644
index 0000000..61d4f32
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/ICarWatchdog.aidl
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+interface ICarWatchdog {
+  void registerClient(in android.automotive.watchdog.ICarWatchdogClient client, in android.automotive.watchdog.TimeoutLength timeout);
+  void unregisterClient(in android.automotive.watchdog.ICarWatchdogClient client);
+  void registerMediator(in android.automotive.watchdog.ICarWatchdogClient mediator);
+  void unregisterMediator(in android.automotive.watchdog.ICarWatchdogClient mediator);
+  void registerMonitor(in android.automotive.watchdog.ICarWatchdogMonitor monitor);
+  void unregisterMonitor(in android.automotive.watchdog.ICarWatchdogMonitor monitor);
+  void tellClientAlive(in android.automotive.watchdog.ICarWatchdogClient client, in int sessionId);
+  void tellMediatorAlive(in android.automotive.watchdog.ICarWatchdogClient mediator, in int[] clientsNotResponding, in int sessionId);
+  void tellDumpFinished(in android.automotive.watchdog.ICarWatchdogMonitor monitor, in int pid);
+  void notifySystemStateChange(in android.automotive.watchdog.StateType type, in int arg1, in int arg2);
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/ICarWatchdogClient.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/ICarWatchdogClient.aidl
new file mode 100644
index 0000000..9768565
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/ICarWatchdogClient.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+interface ICarWatchdogClient {
+  oneway void checkIfAlive(in int sessionId, in android.automotive.watchdog.TimeoutLength timeout);
+  oneway void prepareProcessTermination();
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/ICarWatchdogMonitor.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/ICarWatchdogMonitor.aidl
new file mode 100644
index 0000000..f13af14
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/ICarWatchdogMonitor.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+interface ICarWatchdogMonitor {
+  oneway void onClientsNotResponding(in int[] pids);
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/PowerCycle.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/PowerCycle.aidl
new file mode 100644
index 0000000..2cfd03e
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/PowerCycle.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@Backing(type="int") @VintfStability
+enum PowerCycle {
+  POWER_CYCLE_SHUTDOWN = 0,
+  POWER_CYCLE_SUSPEND = 1,
+  POWER_CYCLE_RESUME = 2,
+  NUM_POWER_CYLES = 3,
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/StateType.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/StateType.aidl
new file mode 100644
index 0000000..52cd08e
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/StateType.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@Backing(type="int") @VintfStability
+enum StateType {
+  POWER_CYCLE = 0,
+  USER_STATE = 1,
+  BOOT_PHASE = 2,
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/TimeoutLength.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/TimeoutLength.aidl
new file mode 100644
index 0000000..e4be851
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/TimeoutLength.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@Backing(type="int") @VintfStability
+enum TimeoutLength {
+  TIMEOUT_CRITICAL = 0,
+  TIMEOUT_MODERATE = 1,
+  TIMEOUT_NORMAL = 2,
+}
diff --git a/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/UserState.aidl b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/UserState.aidl
new file mode 100644
index 0000000..39dcc84
--- /dev/null
+++ b/watchdog/aidl/aidl_api/carwatchdog_aidl_interface/current/android/automotive/watchdog/UserState.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@Backing(type="int") @VintfStability
+enum UserState {
+  USER_STATE_STARTED = 0,
+  USER_STATE_STOPPED = 1,
+  NUM_USER_STATES = 2,
+}
diff --git a/watchdog/aidl/android/automotive/watchdog/BootPhase.aidl b/watchdog/aidl/android/automotive/watchdog/BootPhase.aidl
new file mode 100644
index 0000000..e693325
--- /dev/null
+++ b/watchdog/aidl/android/automotive/watchdog/BootPhase.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.watchdog;
+
+/**
+ * Used by ICarWatchdog to describe the boot phase.
+ */
+
+@VintfStability
+@Backing(type="int")
+enum BootPhase {
+  /**
+   * Boot completed and the home application has started.
+   */
+  BOOT_COMPLETED = 1000,
+}
diff --git a/watchdog/aidl/android/automotive/watchdog/ICarWatchdog.aidl b/watchdog/aidl/android/automotive/watchdog/ICarWatchdog.aidl
new file mode 100644
index 0000000..8368a81
--- /dev/null
+++ b/watchdog/aidl/android/automotive/watchdog/ICarWatchdog.aidl
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.watchdog;
+
+import android.automotive.watchdog.ICarWatchdogClient;
+import android.automotive.watchdog.ICarWatchdogMonitor;
+import android.automotive.watchdog.StateType;
+import android.automotive.watchdog.TimeoutLength;
+
+/**
+ * ICarWatchdog is an interface implemented by watchdog server.
+ * For health check, 4 components are involved: watchdog server, watchdog mediator, watchdog
+ * client, and watchdog monitor.
+ *   - watchdog server: checks clients' health status by pinging and waiting for the response.
+ *   - watchdog mediator: is a watchdog client by reporting its health status to the server, and
+ *                        at the same time plays a role of watchdog server by checking its clients'
+ *                        health status.
+ *   - watchdog client: reports its health status by responding to server's ping within timeout.
+ *   - watchdog monitor: captures and reports the process state of watchdog clients.
+ */
+
+@VintfStability
+interface ICarWatchdog {
+  /**
+   * Register the client to the watchdog server.
+   *
+   * @param client              Watchdog client to register.
+   * @param timeout             Timeout length specified through enum.
+   */
+  void registerClient(in ICarWatchdogClient client, in TimeoutLength timeout);
+
+  /**
+   * Unregister the client from the watchdog server.
+   *
+   * @param client              Watchdog client to unregister.
+   */
+  void unregisterClient(in ICarWatchdogClient client);
+
+  /**
+   * Register the mediator to the watchdog server.
+   * Note that watchdog mediator is also a watchdog client.
+   * The caller should have system UID.
+   *
+   * @param mediator            Watchdog mediator to register.
+   */
+  void registerMediator(in ICarWatchdogClient mediator);
+
+  /**
+   * Unregister the mediator from the watchdog server.
+   * Note that watchdog mediator is also a watchdog client.
+   * The caller should have system UID.
+   *
+   * @param mediator            Watchdog mediator to unregister.
+   */
+  void unregisterMediator(in ICarWatchdogClient mediator);
+
+  /**
+   * Register the monitor to the watchdog server.
+   * The caller should have system UID.
+   *
+   * @param monitor             Watchdog monitor to register.
+   */
+  void registerMonitor(in ICarWatchdogMonitor monitor);
+
+  /**
+   * Unregister the monitor from the watchdog server.
+   * The caller should have system UID.
+   *
+   * @param monitor             Watchdog monitor to unregister.
+   */
+  void unregisterMonitor(in ICarWatchdogMonitor monitor);
+
+  /**
+   * Tell watchdog server that the client is alive.
+   *
+   * @param client              Watchdog client that is responding.
+   * @param sessionId           Session id given by watchdog server.
+   */
+  void tellClientAlive(in ICarWatchdogClient client, in int sessionId);
+
+  /**
+   * Tell watchdog server that the mediator is alive together with the status of clients under
+   * the mediator.
+   * The caller should have system UID.
+   *
+   * @param mediator             Watchdog mediator that is responding.
+   * @param clientsNotResponding Array of process id of clients which haven't responded to the
+   *                             mediator.
+   * @param sessionId            Session id given by watchdog server.
+   */
+  void tellMediatorAlive(
+          in ICarWatchdogClient mediator, in int[] clientsNotResponding, in int sessionId);
+
+  /**
+   * Tell watchdog server that the monitor has finished dumping process information.
+   * The caller should have system UID.
+   *
+   * @param monitor              Watchdog monitor that is registered to watchdog server.
+   * @param pid                  Process id that has been dumped.
+   */
+  void tellDumpFinished(in ICarWatchdogMonitor monitor, in int pid);
+
+  /**
+   * Notify watchdog server about the system state change.
+   * The caller should have system UID.
+   *
+   * @param type                 One of the change types defined in the StateType enum.
+   * @param arg1                 First state change information for the specified type.
+   * @param arg2                 Second state change information for the specified type.
+   *
+   * When type is POWER_CYCLE, arg1 should contain the current power cycle of the device.
+   * When type is USER_STATE, arg1 and arg2 should contain the user ID and the current user state.
+   * When type is BOOT_PHASE, arg1 should contain the current boot phase.
+   */
+  void notifySystemStateChange(in StateType type, in int arg1, in int arg2);
+}
diff --git a/watchdog/aidl/android/automotive/watchdog/ICarWatchdogClient.aidl b/watchdog/aidl/android/automotive/watchdog/ICarWatchdogClient.aidl
new file mode 100644
index 0000000..958b620
--- /dev/null
+++ b/watchdog/aidl/android/automotive/watchdog/ICarWatchdogClient.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.watchdog;
+
+import android.automotive.watchdog.TimeoutLength;
+
+@VintfStability
+oneway interface ICarWatchdogClient {
+  /**
+   * Check if the client is alive.
+   * Watchdog server or mediator calls this method, expecting the clients will respond within
+   * timeout. The final timeout is decided by the server, considering the requested timeout on
+   * client registration. If no response from the clients, watchdog server will dump process
+   * information and kill them.
+   *
+   * @param sessionId           Unique id to identify each health check session.
+   * @param timeout             Final timeout given by the server based on client request.
+   */
+  void checkIfAlive(in int sessionId, in TimeoutLength timeout);
+
+  /**
+   * Notify the client that it will be forcedly terminated in 1 second.
+   */
+  void prepareProcessTermination();
+}
diff --git a/watchdog/aidl/android/automotive/watchdog/ICarWatchdogMonitor.aidl b/watchdog/aidl/android/automotive/watchdog/ICarWatchdogMonitor.aidl
new file mode 100644
index 0000000..d2e1ad8
--- /dev/null
+++ b/watchdog/aidl/android/automotive/watchdog/ICarWatchdogMonitor.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.watchdog;
+
+import android.automotive.watchdog.ICarWatchdogClient;
+
+@VintfStability
+oneway interface ICarWatchdogMonitor {
+  /**
+   * Called when the client has not responded within the given timeout.
+   * Watchdog server calls this method, requesting the monitor to dump process information of the
+   * clients.
+   *
+   * @param pids                Array of process id of the clients.
+   */
+  void onClientsNotResponding(in int[] pids);
+}
diff --git a/watchdog/aidl/android/automotive/watchdog/PowerCycle.aidl b/watchdog/aidl/android/automotive/watchdog/PowerCycle.aidl
new file mode 100644
index 0000000..04adefe
--- /dev/null
+++ b/watchdog/aidl/android/automotive/watchdog/PowerCycle.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.watchdog;
+
+/**
+ * Used by ICarWatchdog to describe the device power status.
+ */
+
+@VintfStability
+@Backing(type="int")
+enum PowerCycle {
+  /**
+   * The system is about to shut down.
+   */
+  POWER_CYCLE_SHUTDOWN,
+
+  /**
+   * The system is being suspended.
+   */
+  POWER_CYCLE_SUSPEND,
+
+  /**
+   * The system resumes working.
+   */
+  POWER_CYCLE_RESUME,
+
+  /**
+   * Number of available power cycles.
+   */
+  NUM_POWER_CYLES,
+}
diff --git a/watchdog/aidl/android/automotive/watchdog/StateType.aidl b/watchdog/aidl/android/automotive/watchdog/StateType.aidl
new file mode 100644
index 0000000..c6ba112
--- /dev/null
+++ b/watchdog/aidl/android/automotive/watchdog/StateType.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.watchdog;
+
+/**
+ * Used by ICarWatchdog to describe the change type.
+ */
+
+@VintfStability
+@Backing(type="int")
+enum StateType {
+  /**
+   * Device power status change.
+   */
+  POWER_CYCLE,
+
+  /**
+   * User state change.
+   */
+  USER_STATE,
+
+  /**
+   * Boot phase change.
+   */
+  BOOT_PHASE,
+}
\ No newline at end of file
diff --git a/watchdog/aidl/android/automotive/watchdog/TimeoutLength.aidl b/watchdog/aidl/android/automotive/watchdog/TimeoutLength.aidl
new file mode 100644
index 0000000..20fa7d7
--- /dev/null
+++ b/watchdog/aidl/android/automotive/watchdog/TimeoutLength.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.watchdog;
+
+/**
+ * Used by ICarWatchdog and ICarWatchdogMediator to determine if the clients are in bad state.
+ * Watchdog server will decide that the clients are in bad state when they don't respond within
+ * the timeout. Different timeouts are used by different clients based on how responsive they
+ * should be.
+ */
+
+@VintfStability
+@Backing(type="int")
+enum TimeoutLength {
+  /**
+   * Timeout is 3 seconds.
+   * This is for services which should be responsive.
+   */
+  TIMEOUT_CRITICAL,
+
+  /**
+   * Timeout is 5 seconds.
+   * This is for services which are relatively responsive.
+   */
+  TIMEOUT_MODERATE,
+
+  /**
+   * Timeout is 10 seconds.
+   * This is for all other services.
+   */
+  TIMEOUT_NORMAL,
+}
diff --git a/watchdog/aidl/android/automotive/watchdog/UserState.aidl b/watchdog/aidl/android/automotive/watchdog/UserState.aidl
new file mode 100644
index 0000000..b07cce6
--- /dev/null
+++ b/watchdog/aidl/android/automotive/watchdog/UserState.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.watchdog;
+
+/**
+ * Used by ICarWatchdog to describe whether user is started or stopped.
+ */
+
+@VintfStability
+@Backing(type="int")
+enum UserState {
+  /**
+   * The user is started.
+   */
+  USER_STATE_STARTED,
+
+  /**
+   * The user is stopped.
+   */
+  USER_STATE_STOPPED,
+
+  /**
+   * Number of available user states.
+   */
+  NUM_USER_STATES,
+}
diff --git a/watchdog/car-watchdog-lib/Android.bp b/watchdog/car-watchdog-lib/Android.bp
new file mode 100644
index 0000000..1fc2cd7
--- /dev/null
+++ b/watchdog/car-watchdog-lib/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_library {
+    name: "android.car.watchdoglib",
+    srcs: [
+        "src/**/*.java",
+    ],
+    static_libs: [
+        "androidx.preference_preference",
+        "carwatchdog_aidl_interface-java",
+    ],
+    product_variables: {
+        pdk: {
+            enabled: false,
+        },
+    },
+    installable: true,
+}
diff --git a/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java b/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java
new file mode 100644
index 0000000..4dfbe20
--- /dev/null
+++ b/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.watchdoglib;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.automotive.watchdog.ICarWatchdog;
+import android.automotive.watchdog.ICarWatchdogClient;
+import android.automotive.watchdog.ICarWatchdogMonitor;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Helper class for car watchdog daemon.
+ *
+ * @hide
+ */
+public final class CarWatchdogDaemonHelper {
+
+    private static final String TAG = CarWatchdogDaemonHelper.class.getSimpleName();
+    // Carwatchdog daemon polls for the service manager status once every 250 milliseconds.
+    // CAR_WATCHDOG_DAEMON_BIND_RETRY_INTERVAL_MS value should be at least twice the poll interval
+    // used by the daemon.
+    private static final long CAR_WATCHDOG_DAEMON_BIND_RETRY_INTERVAL_MS = 500;
+    private static final long CAR_WATCHDOG_DAEMON_FIND_MARGINAL_TIME_MS = 300;
+    private static final int CAR_WATCHDOG_DAEMON_BIND_MAX_RETRY = 3;
+    private static final String CAR_WATCHDOG_DAEMON_INTERFACE =
+            "android.automotive.watchdog.ICarWatchdog/default";
+
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+    private final CopyOnWriteArrayList<OnConnectionChangeListener> mConnectionListeners =
+            new CopyOnWriteArrayList<>();
+    private final String mTag;
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private @Nullable ICarWatchdog mCarWatchdogDaemon;
+    @GuardedBy("mLock")
+    private boolean mConnectionInProgress;
+
+    private final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
+        @Override
+        public void binderDied() {
+            Log.w(mTag, "Car watchdog daemon died: reconnecting");
+            unlinkToDeath();
+            synchronized (mLock) {
+                mCarWatchdogDaemon = null;
+            }
+            for (OnConnectionChangeListener listener : mConnectionListeners) {
+                listener.onConnectionChange(false);
+            }
+            mHandler.sendMessageDelayed(obtainMessage(CarWatchdogDaemonHelper::connectToDaemon,
+                    CarWatchdogDaemonHelper.this, CAR_WATCHDOG_DAEMON_BIND_MAX_RETRY),
+                    CAR_WATCHDOG_DAEMON_BIND_RETRY_INTERVAL_MS);
+        }
+    };
+
+    private interface Invokable {
+        void invoke(ICarWatchdog daemon) throws RemoteException;
+    }
+
+    /**
+     * Listener to notify the state change of the connection to car watchdog daemon.
+     */
+    public interface OnConnectionChangeListener {
+        /** Gets called when car watchdog daemon is connected or disconnected. */
+        void onConnectionChange(boolean connected);
+    }
+
+    public CarWatchdogDaemonHelper() {
+        mTag = TAG;
+    }
+
+    public CarWatchdogDaemonHelper(@NonNull String requestor) {
+        mTag = TAG + "[" + requestor + "]";
+    }
+
+    /**
+     * Connects to car watchdog daemon.
+     *
+     * <p>When it's connected, {@link OnConnectionChangeListener} is called with
+     * {@code true}.
+     */
+    public void connect() {
+        synchronized (mLock) {
+            if (mCarWatchdogDaemon != null || mConnectionInProgress) {
+                return;
+            }
+            mConnectionInProgress = true;
+        }
+        connectToDaemon(CAR_WATCHDOG_DAEMON_BIND_MAX_RETRY);
+    }
+
+    /**
+     * Disconnects from car watchdog daemon.
+     *
+     * <p>When it's disconnected, {@link OnConnectionChangeListener} is called with
+     * {@code false}.
+     */
+    public void disconnect() {
+        unlinkToDeath();
+        synchronized (mLock) {
+            mCarWatchdogDaemon = null;
+        }
+    }
+
+    /**
+     * Adds {@link OnConnectionChangeListener}.
+     *
+     * @param listener Listener to be notified when connection state changes.
+     */
+    public void addOnConnectionChangeListener(
+            @NonNull OnConnectionChangeListener listener) {
+        Objects.requireNonNull(listener, "Listener cannot be null");
+        mConnectionListeners.add(listener);
+    }
+
+    /**
+     * Removes {@link OnConnectionChangeListener}.
+     *
+     * @param listener Listener to be removed.
+     */
+    public void removeOnConnectionChangeListener(
+            @NonNull OnConnectionChangeListener listener) {
+        Objects.requireNonNull(listener, "Listener cannot be null");
+        mConnectionListeners.remove(listener);
+    }
+
+    /**
+     * Registers car watchdog client.
+     *
+     * @param client Car watchdog client to be registered.
+     * @param timeout Time within which the client should respond.
+     * @throws IllegalArgumentException If the client is already registered.
+     * @throws IllegalStateException If car watchdog daemon is not connected.
+     * @throws RemoteException
+     */
+    public void registerClient(ICarWatchdogClient client, int timeout) throws RemoteException {
+        invokeDaemonMethod((daemon) -> daemon.registerClient(client, timeout));
+    }
+
+    /**
+     * Unregisters car watchdog client.
+     *
+     * @param client Car watchdog client to be unregistered.
+     * @throws IllegalArgumentException If the client is not registered.
+     * @throws IllegalStateException If car watchdog daemon is not connected.
+     * @throws RemoteException
+     */
+    public void unregisterClient(ICarWatchdogClient client) throws RemoteException {
+        invokeDaemonMethod((daemon) -> daemon.unregisterClient(client));
+    }
+
+    /**
+     * Registers car watchdog client as mediator.
+     *
+     * @param mediator Car watchdog client to be registered.
+     * @throws IllegalArgumentException If the mediator is already registered.
+     * @throws IllegalStateException If car watchdog daemon is not connected.
+     * @throws RemoteException
+     */
+    public void registerMediator(ICarWatchdogClient mediator) throws RemoteException {
+        invokeDaemonMethod((daemon) -> daemon.registerMediator(mediator));
+    }
+
+    /**
+     * Unregisters car watchdog client as mediator.
+     *
+     * @param mediator Car watchdog client to be unregistered.
+     * @throws IllegalArgumentException If the mediator is not registered.
+     * @throws IllegalStateException If car watchdog daemon is not connected.
+     * @throws RemoteException
+     */
+    public void unregisterMediator(ICarWatchdogClient mediator)  throws RemoteException {
+        invokeDaemonMethod((daemon) -> daemon.unregisterMediator(mediator));
+    }
+
+    /**
+     * Registers car watchdog monitor.
+     *
+     * @param monitor Car watchdog monitor to be registered.
+     * @throws IllegalArgumentException If there is another monitor registered.
+     * @throws IllegalStateException If car watchdog daemon is not connected.
+     * @throws RemoteException
+     */
+    public void registerMonitor(ICarWatchdogMonitor monitor)  throws RemoteException {
+        invokeDaemonMethod((daemon) -> daemon.registerMonitor(monitor));
+    }
+
+    /**
+     * Unregisters car watchdog monitor.
+     *
+     * @param monitor Car watchdog monitor to be unregistered.
+     * @throws IllegalArgumentException If the monitor is not registered.
+     * @throws IllegalStateException If car watchdog daemon is not connected.
+     * @throws RemoteException
+     */
+    public void unregisterMonitor(ICarWatchdogMonitor monitor) throws RemoteException {
+        invokeDaemonMethod((daemon) -> daemon.unregisterMonitor(monitor));
+    }
+
+    /**
+     * Tells car watchdog daemon that the client is alive.
+     *
+     * @param client Car watchdog client which has been pined by car watchdog daemon.
+     * @param sessionId Session ID that car watchdog daemon has given.
+     * @throws IllegalArgumentException If the client is not registered,
+     *                                  or session ID is not correct.
+     * @throws IllegalStateException If car watchdog daemon is not connected.
+     * @throws RemoteException
+     */
+    public void tellClientAlive(ICarWatchdogClient client, int sessionId) throws RemoteException {
+        invokeDaemonMethod((daemon) -> daemon.tellClientAlive(client, sessionId));
+    }
+
+    /**
+     * Tells car watchdog daemon that the mediator is alive.
+     *
+     * @param mediator Car watchdog client which has been pined by car watchdog daemon.
+     * @param clientsNotResponding Array of process ID that are not responding.
+     * @param sessionId Session ID that car watchdog daemon has given.
+     * @throws IllegalArgumentException If the client is not registered,
+     *                                  or session ID is not correct.
+     * @throws IllegalStateException If car watchdog daemon is not connected.
+     * @throws RemoteException
+     */
+    public void tellMediatorAlive(ICarWatchdogClient mediator, int[] clientsNotResponding,
+            int sessionId) throws RemoteException {
+        invokeDaemonMethod(
+                (daemon) -> daemon.tellMediatorAlive(mediator, clientsNotResponding, sessionId));
+    }
+
+    /**
+     * Tells car watchdog daemon that the monitor has dumped clients' process information.
+     *
+     * @param monitor Car watchdog monitor that dumped process information.
+     * @param pid ID of process that has been dumped.
+     * @throws IllegalArgumentException If the monitor is not registered.
+     * @throws IllegalStateException If car watchdog daemon is not connected.
+     * @throws RemoteException
+     */
+    public void tellDumpFinished(ICarWatchdogMonitor monitor, int pid) throws RemoteException {
+        invokeDaemonMethod((daemon) -> daemon.tellDumpFinished(monitor, pid));
+    }
+
+    /**
+     * Tells car watchdog daemon that system state has been changed for the specified StateType.
+     *
+     * @param type Either PowerCycle, UserState, or BootPhase
+     * @param arg1 First state change information for the specified state type.
+     * @param arg2 Second state change information for the specified state type.
+     * @throws IllegalArgumentException If the args don't match the state type. Refer to the aidl
+     *                                  interface for more information on the args.
+     * @throws IllegalStateException If car watchdog daemon is not connected.
+     * @throws RemoteException
+     */
+    public void notifySystemStateChange(int type, int arg1, int arg2) throws RemoteException {
+        invokeDaemonMethod((daemon) -> daemon.notifySystemStateChange(type, arg1, arg2));
+    }
+
+    private void invokeDaemonMethod(Invokable r) throws RemoteException {
+        ICarWatchdog daemon;
+        synchronized (mLock) {
+            if (mCarWatchdogDaemon == null) {
+                throw new IllegalStateException("Car watchdog daemon is not connected");
+            }
+            daemon = mCarWatchdogDaemon;
+        }
+        r.invoke(daemon);
+    }
+
+    private void connectToDaemon(int retryCount) {
+        if (retryCount <= 0) {
+            synchronized (mLock) {
+                mConnectionInProgress = false;
+            }
+            Log.e(mTag, "Cannot reconnect to car watchdog daemon after retrying "
+                    + CAR_WATCHDOG_DAEMON_BIND_MAX_RETRY + " times");
+            return;
+        }
+        if (makeBinderConnection()) {
+            Log.i(mTag, "Connected to car watchdog daemon");
+            return;
+        }
+        mHandler.sendMessageDelayed(obtainMessage(CarWatchdogDaemonHelper::connectToDaemon,
+                CarWatchdogDaemonHelper.this, retryCount - 1),
+                CAR_WATCHDOG_DAEMON_BIND_RETRY_INTERVAL_MS);
+    }
+
+    private boolean makeBinderConnection() {
+        long currentTimeMs = SystemClock.uptimeMillis();
+        IBinder binder = ServiceManager.getService(CAR_WATCHDOG_DAEMON_INTERFACE);
+        if (binder == null) {
+            Log.w(mTag, "Getting car watchdog daemon binder failed");
+            return false;
+        }
+        long elapsedTimeMs = SystemClock.uptimeMillis() - currentTimeMs;
+        if (elapsedTimeMs > CAR_WATCHDOG_DAEMON_FIND_MARGINAL_TIME_MS) {
+            Log.wtf(mTag, "Finding car watchdog daemon took too long(" + elapsedTimeMs + "ms)");
+        }
+
+        ICarWatchdog daemon = ICarWatchdog.Stub.asInterface(binder);
+        if (daemon == null) {
+            Log.w(mTag, "Getting car watchdog daemon interface failed");
+            return false;
+        }
+        synchronized (mLock) {
+            mCarWatchdogDaemon = daemon;
+            mConnectionInProgress = false;
+        }
+        linkToDeath();
+        for (OnConnectionChangeListener listener : mConnectionListeners) {
+            listener.onConnectionChange(true);
+        }
+        return true;
+    }
+
+    private void linkToDeath() {
+        IBinder binder;
+        synchronized (mLock) {
+            if (mCarWatchdogDaemon == null) {
+                return;
+            }
+            binder = mCarWatchdogDaemon.asBinder();
+        }
+        if (binder == null) {
+            Log.w(mTag, "Linking to binder death recipient skipped");
+            return;
+        }
+        try {
+            binder.linkToDeath(mDeathRecipient, 0);
+        } catch (RemoteException e) {
+            Log.w(mTag, "Linking to binder death recipient failed: " + e);
+        }
+    }
+
+    private void unlinkToDeath() {
+        IBinder binder;
+        synchronized (mLock) {
+            if (mCarWatchdogDaemon == null) {
+                return;
+            }
+            binder = mCarWatchdogDaemon.asBinder();
+        }
+        if (binder == null) {
+            Log.w(mTag, "Unlinking from binder death recipient skipped");
+            return;
+        }
+        binder.unlinkToDeath(mDeathRecipient, 0);
+    }
+}
diff --git a/watchdog/product/carwatchdog.mk b/watchdog/product/carwatchdog.mk
new file mode 100644
index 0000000..028f67b
--- /dev/null
+++ b/watchdog/product/carwatchdog.mk
@@ -0,0 +1,28 @@
+# Copyright (C) 2020 The Android Open Source Project
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Add carwatchdogd to product package
+PRODUCT_PACKAGES += carwatchdogd
+
+# SELinux public policies for car watchdog services
+PRODUCT_PUBLIC_SEPOLICY_DIRS += packages/services/Car/watchdog/sepolicy/public
+
+# SELinux private policies for car watchdog services
+PRODUCT_PRIVATE_SEPOLICY_DIRS += packages/services/Car/watchdog/sepolicy/private
+
+# Include carwatchdog testclient if the build is userdebug or eng
+ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
+    PRODUCT_PACKAGES += carwatchdog_testclient
+    BOARD_SEPOLICY_DIRS += packages/services/Car/watchdog/testclient/sepolicy
+endif
diff --git a/watchdog/sepolicy/private/carwatchdog.te b/watchdog/sepolicy/private/carwatchdog.te
new file mode 100644
index 0000000..28473b0
--- /dev/null
+++ b/watchdog/sepolicy/private/carwatchdog.te
@@ -0,0 +1,22 @@
+# Car watchdog server
+typeattribute carwatchdogd coredomain;
+typeattribute carwatchdogd mlstrustedsubject;
+
+type carwatchdogd_exec, exec_type, file_type, system_file_type;
+
+init_daemon_domain(carwatchdogd)
+add_service(carwatchdogd, carwatchdogd_service)
+binder_use(carwatchdogd)
+binder_service(carwatchdogd)
+
+# Scan through /proc/pid for all processes
+r_dir_file(carwatchdogd, domain)
+
+# Read /proc/uid_io/stats
+allow carwatchdogd proc_uid_io_stats:file r_file_perms;
+
+# Read /proc/stat file
+allow carwatchdogd proc_stat:file r_file_perms;
+
+# Find package_native to get uid to package name mapping.
+allow carwatchdogd package_native_service:service_manager find;
diff --git a/watchdog/sepolicy/private/carwatchdogclientdomain.te b/watchdog/sepolicy/private/carwatchdogclientdomain.te
new file mode 100644
index 0000000..10c4e52
--- /dev/null
+++ b/watchdog/sepolicy/private/carwatchdogclientdomain.te
@@ -0,0 +1,4 @@
+# Car watchdog client domain
+binder_use(carwatchdogclient_domain)
+
+allow carwatchdogclient_domain carwatchdogd_service:service_manager find;
diff --git a/watchdog/sepolicy/private/file_contexts b/watchdog/sepolicy/private/file_contexts
new file mode 100644
index 0000000..fe0bcb1
--- /dev/null
+++ b/watchdog/sepolicy/private/file_contexts
@@ -0,0 +1,2 @@
+# Car watchdog server
+/system/bin/carwatchdogd  u:object_r:carwatchdogd_exec:s0
diff --git a/watchdog/sepolicy/private/service_contexts b/watchdog/sepolicy/private/service_contexts
new file mode 100644
index 0000000..ea1ba15
--- /dev/null
+++ b/watchdog/sepolicy/private/service_contexts
@@ -0,0 +1,2 @@
+# Car watchdog server
+android.automotive.watchdog.ICarWatchdog/default  u:object_r:carwatchdogd_service:s0
diff --git a/watchdog/sepolicy/public/attributes b/watchdog/sepolicy/public/attributes
new file mode 100644
index 0000000..d4ae54f
--- /dev/null
+++ b/watchdog/sepolicy/public/attributes
@@ -0,0 +1,3 @@
+# All car watchdog clients
+attribute carwatchdogclient_domain;
+expandattribute carwatchdogclient_domain true;
diff --git a/watchdog/sepolicy/public/carwatchdog.te b/watchdog/sepolicy/public/carwatchdog.te
new file mode 100644
index 0000000..2cb9c5a
--- /dev/null
+++ b/watchdog/sepolicy/public/carwatchdog.te
@@ -0,0 +1,9 @@
+# Car watchdog server
+type carwatchdogd, domain;
+
+binder_call(carwatchdogd, carwatchdogclient_domain)
+binder_call(carwatchdogclient_domain, carwatchdogd)
+
+# Configuration for system_server
+allow system_server carwatchdogd_service:service_manager find;
+binder_call(carwatchdogd, system_server)
diff --git a/watchdog/sepolicy/public/service.te b/watchdog/sepolicy/public/service.te
new file mode 100644
index 0000000..eb41df4
--- /dev/null
+++ b/watchdog/sepolicy/public/service.te
@@ -0,0 +1,2 @@
+# Car watchdog server
+type carwatchdogd_service, service_manager_type;
diff --git a/watchdog/sepolicy/public/te_macros b/watchdog/sepolicy/public/te_macros
new file mode 100644
index 0000000..abda525
--- /dev/null
+++ b/watchdog/sepolicy/public/te_macros
@@ -0,0 +1,11 @@
+#####################################
+# carwatchdog_client_domain(domain)
+# Allow a base set of permissions required for a domain to be a
+# client of a carwatchdog.
+#
+# For example, make some_domain a car watchd client:
+#   carwatchdog_client_domain(some_domain)
+#
+define(`carwatchdog_client_domain', `
+typeattribute $1 carwatchdogclient_domain;
+')
diff --git a/watchdog/server/Android.bp b/watchdog/server/Android.bp
new file mode 100644
index 0000000..e50b24a
--- /dev/null
+++ b/watchdog/server/Android.bp
@@ -0,0 +1,150 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_defaults {
+    name: "carwatchdogd_defaults",
+    cflags: [
+        "-Wall",
+        "-Wno-missing-field-initializers",
+        "-Werror",
+        "-Wno-unused-variable",
+        "-Wunused-parameter",
+    ],
+    include_dirs: [
+        "system/core/base/include",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "liblog",
+        "libutils",
+    ],
+}
+
+cc_defaults {
+    name: "libwatchdog_ioperfcollection_defaults",
+    shared_libs: [
+        "libcutils",
+        "libprocessgroup",
+    ],
+    static_libs: [
+        "libgtest_prod",
+    ],
+}
+
+cc_library {
+    name: "libwatchdog_ioperfcollection",
+    defaults: [
+        "carwatchdogd_defaults",
+        "libwatchdog_ioperfcollection_defaults",
+    ],
+    srcs: [
+        "src/IoPerfCollection.cpp",
+        "src/LooperWrapper.cpp",
+        "src/ProcPidStat.cpp",
+        "src/ProcStat.cpp",
+        "src/UidIoStats.cpp",
+    ],
+    whole_static_libs: [
+        "libwatchdog_properties",
+    ],
+    export_include_dirs: [
+        "src",
+    ],
+}
+
+cc_test {
+    name: "libwatchdog_test",
+    defaults: [
+        "carwatchdogd_defaults",
+        "libwatchdog_ioperfcollection_defaults",
+        "libwatchdog_process_service_defaults",
+    ],
+    test_suites: ["general-tests"],
+    srcs: [
+        "tests/IoPerfCollectionTest.cpp",
+        "tests/LooperStub.cpp",
+        "tests/ProcPidDir.cpp",
+        "tests/ProcPidStatTest.cpp",
+        "tests/ProcStatTest.cpp",
+        "tests/UidIoStatsTest.cpp",
+        "tests/WatchdogBinderMediatorTest.cpp",
+        "tests/WatchdogProcessServiceTest.cpp",
+    ],
+    static_libs: [
+        "libgmock",
+        "libgtest",
+        "libwatchdog_binder_mediator",
+        "libwatchdog_ioperfcollection",
+    ],
+}
+
+cc_defaults {
+    name: "libwatchdog_process_service_defaults",
+    shared_libs: [
+        "carwatchdog_aidl_interface-cpp",
+    ],
+}
+
+cc_library {
+    name: "libwatchdog_process_service",
+    srcs: [
+        "src/WatchdogProcessService.cpp",
+    ],
+    defaults: [
+        "carwatchdogd_defaults",
+        "libwatchdog_process_service_defaults"
+    ],
+}
+
+cc_library {
+    name: "libwatchdog_binder_mediator",
+    defaults: [
+        "carwatchdogd_defaults",
+        "libwatchdog_ioperfcollection_defaults",
+        "libwatchdog_process_service_defaults",
+    ],
+    srcs: [
+        "src/WatchdogBinderMediator.cpp",
+        "src/WatchdogProcessService.cpp",
+        "src/IoPerfCollection.cpp",
+    ],
+    shared_libs: [
+        "libwatchdog_ioperfcollection",
+        "libwatchdog_process_service",
+    ],
+    export_include_dirs: [
+        "src",
+    ],
+}
+
+cc_binary {
+    name: "carwatchdogd",
+    defaults: [
+        "carwatchdogd_defaults",
+        "libwatchdog_ioperfcollection_defaults",
+        "libwatchdog_process_service_defaults",
+    ],
+    srcs: [
+        "src/main.cpp",
+        "src/ServiceManager.cpp",
+    ],
+    init_rc: ["carwatchdogd.rc"],
+    shared_libs: [
+      "libwatchdog_binder_mediator",
+      "libwatchdog_ioperfcollection",
+      "libwatchdog_process_service",
+    ],
+    vintf_fragments: ["carwatchdogd.xml"],
+}
diff --git a/watchdog/server/carwatchdogd.rc b/watchdog/server/carwatchdogd.rc
new file mode 100644
index 0000000..c2eb104
--- /dev/null
+++ b/watchdog/server/carwatchdogd.rc
@@ -0,0 +1,47 @@
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+service carwatchdogd /system/bin/carwatchdogd
+    class core
+    user system
+    group system readproc
+    disabled
+
+on early-init && property:ro.build.type=userdebug
+    # Below intervals are in seconds
+    setprop ro.carwatchdog.boottime_collection_interval 1
+    setprop ro.carwatchdog.periodic_collection_interval 10
+
+on early-init && property:ro.build.type=eng
+    # Below intervals are in seconds
+    setprop ro.carwatchdog.boottime_collection_interval 1
+    setprop ro.carwatchdog.periodic_collection_interval 10
+
+on early-init && property:ro.build.type=user
+    # Below intervals are in seconds
+    setprop ro.carwatchdog.boottime_collection_interval 20
+    setprop ro.carwatchdog.periodic_collection_interval 60
+
+on early-init
+    # Number of top stats per category
+    setprop ro.carwatchdog.top_n_stats_per_category 10
+
+    # Number of top stats per sub-category
+    setprop ro.carwatchdog.top_n_stats_per_subcategory 5
+
+    # Cache size for the periodically collected records
+    setprop ro.carwatchdog.periodic_collection_buffer_size 180
+
+    # Start the service only after initializing the properties.
+    start carwatchdogd
diff --git a/watchdog/server/carwatchdogd.xml b/watchdog/server/carwatchdogd.xml
new file mode 100644
index 0000000..c0c8933
--- /dev/null
+++ b/watchdog/server/carwatchdogd.xml
@@ -0,0 +1,24 @@
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest version="1.0" type="framework">
+    <hal format="aidl">
+        <name>android.automotive.watchdog</name>
+        <interface>
+            <name>ICarWatchdog</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/watchdog/server/src/IoPerfCollection.cpp b/watchdog/server/src/IoPerfCollection.cpp
new file mode 100644
index 0000000..2799417
--- /dev/null
+++ b/watchdog/server/src/IoPerfCollection.cpp
@@ -0,0 +1,1059 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "carwatchdogd"
+
+#include "IoPerfCollection.h"
+
+#include <WatchdogProperties.sysprop.h>
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <binder/IServiceManager.h>
+#include <cutils/android_filesystem_config.h>
+#include <inttypes.h>
+#include <log/log.h>
+#include <processgroup/sched_policy.h>
+#include <pthread.h>
+#include <pwd.h>
+
+#include <algorithm>
+#include <iomanip>
+#include <iterator>
+#include <limits>
+#include <string>
+#include <thread>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using android::defaultServiceManager;
+using android::IBinder;
+using android::IServiceManager;
+using android::sp;
+using android::String16;
+using android::base::Error;
+using android::base::ParseUint;
+using android::base::Result;
+using android::base::Split;
+using android::base::StringAppendF;
+using android::base::StringPrintf;
+using android::base::WriteStringToFd;
+using android::content::pm::IPackageManagerNative;
+
+namespace {
+
+const int32_t kDefaultTopNStatsPerCategory = 10;
+const int32_t kDefaultTopNStatsPerSubcategory = 5;
+const std::chrono::seconds kDefaultBoottimeCollectionInterval = 1s;
+const std::chrono::seconds kDefaultPeriodicCollectionInterval = 10s;
+// Number of periodic collection perf data snapshots to cache in memory.
+const int32_t kDefaultPeriodicCollectionBufferSize = 180;
+
+// Minimum collection interval between subsequent collections.
+const std::chrono::nanoseconds kMinCollectionInterval = 1s;
+
+// Default values for the custom collection interval and max_duration.
+const std::chrono::nanoseconds kCustomCollectionInterval = 10s;
+const std::chrono::nanoseconds kCustomCollectionDuration = 30min;
+
+const std::string kDumpMajorDelimiter = std::string(100, '-') + "\n";
+
+constexpr const char* kHelpText =
+        "\nCustom I/O performance data collection dump options:\n"
+        "%s: Starts custom I/O performance data collection. Customize the collection behavior with "
+        "the following optional arguments:\n"
+        "\t%s <seconds>: Modifies the collection interval. Default behavior is to collect once "
+        "every %lld seconds.\n"
+        "\t%s <seconds>: Modifies the maximum collection duration. Default behavior is to collect "
+        "until %ld minutes before automatically stopping the custom collection and discarding "
+        "the collected data.\n"
+        "\t%s <package name>,<package, name>,...: Comma-separated value containing package names. "
+        "When provided, the results are filtered only to the provided package names. Default "
+        "behavior is to list the results for the top %d packages.\n"
+        "%s: Stops custom I/O performance data collection and generates a dump of "
+        "the collection report.\n\n"
+        "When no options are specified, the carwatchdog report contains the I/O performance "
+        "data collected during boot-time and over the last %ld minutes before the report "
+        "generation.";
+
+double percentage(uint64_t numer, uint64_t denom) {
+    return denom == 0 ? 0.0 : (static_cast<double>(numer) / static_cast<double>(denom)) * 100.0;
+}
+
+struct UidProcessStats {
+    struct ProcessInfo {
+        std::string comm = "";
+        uint64_t count = 0;
+    };
+    uint64_t uid = 0;
+    uint32_t ioBlockedTasksCnt = 0;
+    uint32_t totalTasksCnt = 0;
+    uint64_t majorFaults = 0;
+    std::vector<ProcessInfo> topNIoBlockedProcesses = {};
+    std::vector<ProcessInfo> topNMajorFaultProcesses = {};
+};
+
+std::unique_ptr<std::unordered_map<uint32_t, UidProcessStats>> getUidProcessStats(
+        const std::vector<ProcessStats>& processStats, int topNStatsPerSubCategory) {
+    std::unique_ptr<std::unordered_map<uint32_t, UidProcessStats>> uidProcessStats(
+            new std::unordered_map<uint32_t, UidProcessStats>());
+    for (const auto& stats : processStats) {
+        if (stats.uid < 0) {
+            continue;
+        }
+        uint32_t uid = static_cast<uint32_t>(stats.uid);
+        if (uidProcessStats->find(uid) == uidProcessStats->end()) {
+            (*uidProcessStats)[uid] = UidProcessStats{
+                    .uid = uid,
+                    .topNIoBlockedProcesses = std::vector<
+                            UidProcessStats::ProcessInfo>(topNStatsPerSubCategory,
+                                                          UidProcessStats::ProcessInfo{}),
+                    .topNMajorFaultProcesses = std::vector<
+                            UidProcessStats::ProcessInfo>(topNStatsPerSubCategory,
+                                                          UidProcessStats::ProcessInfo{}),
+            };
+        }
+        auto& curUidProcessStats = (*uidProcessStats)[uid];
+        // Top-level process stats has the aggregated major page faults count and this should be
+        // persistent across thread creation/termination. Thus use the value from this field.
+        curUidProcessStats.majorFaults += stats.process.majorFaults;
+        curUidProcessStats.totalTasksCnt += stats.threads.size();
+        // The process state is the same as the main thread state. Thus to avoid double counting
+        // ignore the process state.
+        uint32_t ioBlockedTasksCnt = 0;
+        for (const auto& threadStat : stats.threads) {
+            ioBlockedTasksCnt += threadStat.second.state == "D" ? 1 : 0;
+        }
+        curUidProcessStats.ioBlockedTasksCnt += ioBlockedTasksCnt;
+        for (auto it = curUidProcessStats.topNIoBlockedProcesses.begin();
+             it != curUidProcessStats.topNIoBlockedProcesses.end(); ++it) {
+            if (it->count < ioBlockedTasksCnt) {
+                curUidProcessStats.topNIoBlockedProcesses
+                        .emplace(it,
+                                 UidProcessStats::ProcessInfo{
+                                         .comm = stats.process.comm,
+                                         .count = ioBlockedTasksCnt,
+                                 });
+                curUidProcessStats.topNIoBlockedProcesses.pop_back();
+                break;
+            }
+        }
+        for (auto it = curUidProcessStats.topNMajorFaultProcesses.begin();
+             it != curUidProcessStats.topNMajorFaultProcesses.end(); ++it) {
+            if (it->count < stats.process.majorFaults) {
+                curUidProcessStats.topNMajorFaultProcesses
+                        .emplace(it,
+                                 UidProcessStats::ProcessInfo{
+                                         .comm = stats.process.comm,
+                                         .count = stats.process.majorFaults,
+                                 });
+                curUidProcessStats.topNMajorFaultProcesses.pop_back();
+                break;
+            }
+        }
+    }
+    return uidProcessStats;
+}
+
+Result<std::chrono::seconds> parseSecondsFlag(Vector<String16> args, size_t pos) {
+    if (args.size() < pos) {
+        return Error() << "Value not provided";
+    }
+
+    uint64_t value;
+    std::string strValue = std::string(String8(args[pos]).string());
+    if (!ParseUint(strValue, &value)) {
+        return Error() << "Invalid value " << args[pos].string() << ", must be an integer";
+    }
+    return std::chrono::seconds(value);
+}
+
+}  // namespace
+
+std::string toString(const UidIoPerfData& data) {
+    std::string buffer;
+    if (data.topNReads.size() > 0) {
+        StringAppendF(&buffer, "\nTop N Reads:\n%s\n", std::string(12, '-').c_str());
+        StringAppendF(&buffer,
+                      "Android User ID, Package Name, Foreground Bytes, Foreground Bytes %%, "
+                      "Foreground Fsync, Foreground Fsync %%, Background Bytes, "
+                      "Background Bytes %%, Background Fsync, Background Fsync %%\n");
+    }
+    for (const auto& stat : data.topNReads) {
+        StringAppendF(&buffer, "%" PRIu32 ", %s", stat.userId, stat.packageName.c_str());
+        for (int i = 0; i < UID_STATES; ++i) {
+            StringAppendF(&buffer, ", %" PRIu64 ", %.2f%%, %" PRIu64 ", %.2f%%", stat.bytes[i],
+                          percentage(stat.bytes[i], data.total[READ_BYTES][i]), stat.fsync[i],
+                          percentage(stat.fsync[i], data.total[FSYNC_COUNT][i]));
+        }
+        StringAppendF(&buffer, "\n");
+    }
+    if (data.topNWrites.size() > 0) {
+        StringAppendF(&buffer, "\nTop N Writes:\n%s\n", std::string(13, '-').c_str());
+        StringAppendF(&buffer,
+                      "Android User ID, Package Name, Foreground Bytes, Foreground Bytes %%, "
+                      "Foreground Fsync, Foreground Fsync %%, Background Bytes, "
+                      "Background Bytes %%, Background Fsync, Background Fsync %%\n");
+    }
+    for (const auto& stat : data.topNWrites) {
+        StringAppendF(&buffer, "%" PRIu32 ", %s", stat.userId, stat.packageName.c_str());
+        for (int i = 0; i < UID_STATES; ++i) {
+            StringAppendF(&buffer, ", %" PRIu64 ", %.2f%%, %" PRIu64 ", %.2f%%", stat.bytes[i],
+                          percentage(stat.bytes[i], data.total[WRITE_BYTES][i]), stat.fsync[i],
+                          percentage(stat.fsync[i], data.total[FSYNC_COUNT][i]));
+        }
+        StringAppendF(&buffer, "\n");
+    }
+    return buffer;
+}
+
+std::string toString(const SystemIoPerfData& data) {
+    std::string buffer;
+    StringAppendF(&buffer, "CPU I/O wait time/percent: %" PRIu64 " / %.2f%%\n", data.cpuIoWaitTime,
+                  percentage(data.cpuIoWaitTime, data.totalCpuTime));
+    StringAppendF(&buffer, "Number of I/O blocked processes/percent: %" PRIu32 " / %.2f%%\n",
+                  data.ioBlockedProcessesCnt,
+                  percentage(data.ioBlockedProcessesCnt, data.totalProcessesCnt));
+    return buffer;
+}
+
+std::string toString(const ProcessIoPerfData& data) {
+    std::string buffer;
+    StringAppendF(&buffer, "Number of major page faults since last collection: %" PRIu64 "\n",
+                  data.totalMajorFaults);
+    StringAppendF(&buffer,
+                  "Percentage of change in major page faults since last collection: %.2f%%\n",
+                  data.majorFaultsPercentChange);
+    if (data.topNMajorFaultUids.size() > 0) {
+        StringAppendF(&buffer, "\nTop N major page faults:\n%s\n", std::string(24, '-').c_str());
+        StringAppendF(&buffer,
+                      "Android User ID, Package Name, Number of major page faults, "
+                      "Percentage of total major page faults\n");
+        StringAppendF(&buffer,
+                      "\tCommand, Number of major page faults, Percentage of UID's major page "
+                      "faults\n");
+    }
+    for (const auto& uidStats : data.topNMajorFaultUids) {
+        StringAppendF(&buffer, "%" PRIu32 ", %s, %" PRIu64 ", %.2f%%\n", uidStats.userId,
+                      uidStats.packageName.c_str(), uidStats.count,
+                      percentage(uidStats.count, data.totalMajorFaults));
+        for (const auto& procStats : uidStats.topNProcesses) {
+            StringAppendF(&buffer, "\t%s, %" PRIu64 ", %.2f%%\n", procStats.comm.c_str(),
+                          procStats.count, percentage(procStats.count, uidStats.count));
+        }
+    }
+    if (data.topNIoBlockedUids.size() > 0) {
+        StringAppendF(&buffer, "\nTop N I/O waiting UIDs:\n%s\n", std::string(23, '-').c_str());
+        StringAppendF(&buffer,
+                      "Android User ID, Package Name, Number of owned tasks waiting for I/O, "
+                      "Percentage of owned tasks waiting for I/O\n");
+        StringAppendF(&buffer,
+                      "\tCommand, Number of I/O waiting tasks, Percentage of UID's tasks waiting "
+                      "for I/O\n");
+    }
+    for (size_t i = 0; i < data.topNIoBlockedUids.size(); ++i) {
+        const auto& uidStats = data.topNIoBlockedUids[i];
+        StringAppendF(&buffer, "%" PRIu32 ", %s, %" PRIu64 ", %.2f%%\n", uidStats.userId,
+                      uidStats.packageName.c_str(), uidStats.count,
+                      percentage(uidStats.count, data.topNIoBlockedUidsTotalTaskCnt[i]));
+        for (const auto& procStats : uidStats.topNProcesses) {
+            StringAppendF(&buffer, "\t%s, %" PRIu64 ", %.2f%%\n", procStats.comm.c_str(),
+                          procStats.count, percentage(procStats.count, uidStats.count));
+        }
+    }
+    return buffer;
+}
+
+std::string toString(const IoPerfRecord& record) {
+    std::string buffer;
+    StringAppendF(&buffer, "%s%s%s", toString(record.systemIoPerfData).c_str(),
+                  toString(record.processIoPerfData).c_str(),
+                  toString(record.uidIoPerfData).c_str());
+    return buffer;
+}
+
+std::string toString(const CollectionInfo& collectionInfo) {
+    std::string buffer;
+    StringAppendF(&buffer, "Number of collections: %zu\n", collectionInfo.records.size());
+    auto interval =
+            std::chrono::duration_cast<std::chrono::seconds>(collectionInfo.interval).count();
+    StringAppendF(&buffer, "Collection interval: %lld second%s\n", interval,
+                  ((interval > 1) ? "s" : ""));
+    for (size_t i = 0; i < collectionInfo.records.size(); ++i) {
+        const auto& record = collectionInfo.records[i];
+        std::stringstream timestamp;
+        timestamp << std::put_time(std::localtime(&record.time), "%c %Z");
+        StringAppendF(&buffer, "Collection %zu: <%s>\n%s\n%s\n", i, timestamp.str().c_str(),
+                      std::string(45, '=').c_str(), toString(record).c_str());
+    }
+    return buffer;
+}
+
+Result<void> IoPerfCollection::start() {
+    {
+        Mutex::Autolock lock(mMutex);
+        if (mCurrCollectionEvent != CollectionEvent::INIT || mCollectionThread.joinable()) {
+            return Error(INVALID_OPERATION)
+                    << "Cannot start I/O performance collection more than once";
+        }
+        mTopNStatsPerCategory = static_cast<int>(
+                sysprop::topNStatsPerCategory().value_or(kDefaultTopNStatsPerCategory));
+        mTopNStatsPerSubcategory = static_cast<int>(
+                sysprop::topNStatsPerSubcategory().value_or(kDefaultTopNStatsPerSubcategory));
+        std::chrono::nanoseconds boottimeCollectionInterval =
+                std::chrono::duration_cast<std::chrono::nanoseconds>(
+                        std::chrono::seconds(sysprop::boottimeCollectionInterval().value_or(
+                                kDefaultBoottimeCollectionInterval.count())));
+        std::chrono::nanoseconds periodicCollectionInterval =
+                std::chrono::duration_cast<std::chrono::nanoseconds>(
+                        std::chrono::seconds(sysprop::periodicCollectionInterval().value_or(
+                                kDefaultPeriodicCollectionInterval.count())));
+        size_t periodicCollectionBufferSize =
+                static_cast<size_t>(sysprop::periodicCollectionBufferSize().value_or(
+                        kDefaultPeriodicCollectionBufferSize));
+        mBoottimeCollection = {
+                .interval = boottimeCollectionInterval,
+                .maxCacheSize = std::numeric_limits<std::size_t>::max(),
+                .lastCollectionUptime = 0,
+                .records = {},
+        };
+        mPeriodicCollection = {
+                .interval = periodicCollectionInterval,
+                .maxCacheSize = periodicCollectionBufferSize,
+                .lastCollectionUptime = 0,
+                .records = {},
+        };
+    }
+
+    mCollectionThread = std::thread([&]() {
+        {
+            Mutex::Autolock lock(mMutex);
+            if (mCurrCollectionEvent != CollectionEvent::INIT) {
+                ALOGE("Skipping I/O performance data collection as the current collection event "
+                      "%s != %s",
+                      toString(mCurrCollectionEvent).c_str(),
+                      toString(CollectionEvent::INIT).c_str());
+                return;
+            }
+            mCurrCollectionEvent = CollectionEvent::BOOT_TIME;
+            mBoottimeCollection.lastCollectionUptime = mHandlerLooper->now();
+            mHandlerLooper->setLooper(Looper::prepare(/*opts=*/0));
+            mHandlerLooper->sendMessage(this, CollectionEvent::BOOT_TIME);
+        }
+        if (set_sched_policy(0, SP_BACKGROUND) != 0) {
+            ALOGW("Failed to set background scheduling priority to I/O performance data collection "
+                  "thread");
+        }
+        int ret = pthread_setname_np(pthread_self(), "IoPerfCollect");
+        if (ret != 0) {
+            ALOGE("Failed to set I/O perf collection thread name: %d", ret);
+        }
+        bool isCollectionActive = true;
+        // Loop until the collection is not active -- I/O perf collection runs on this thread in a
+        // handler.
+        while (isCollectionActive) {
+            mHandlerLooper->pollAll(/*timeoutMillis=*/-1);
+            Mutex::Autolock lock(mMutex);
+            isCollectionActive = mCurrCollectionEvent != CollectionEvent::TERMINATED;
+        }
+    });
+    return {};
+}
+
+void IoPerfCollection::terminate() {
+    {
+        Mutex::Autolock lock(mMutex);
+        if (mCurrCollectionEvent == CollectionEvent::TERMINATED) {
+            ALOGE("I/O performance data collection was terminated already");
+            return;
+        }
+        ALOGE("Terminating I/O performance data collection");
+        mCurrCollectionEvent = CollectionEvent::TERMINATED;
+    }
+    if (mCollectionThread.joinable()) {
+        mHandlerLooper->removeMessages(this);
+        mHandlerLooper->wake();
+        mCollectionThread.join();
+    }
+}
+
+Result<void> IoPerfCollection::onBootFinished() {
+    Mutex::Autolock lock(mMutex);
+    if (mCurrCollectionEvent != CollectionEvent::BOOT_TIME) {
+        // This case happens when either the I/O perf collection has prematurely terminated before
+        // boot complete notification is received or multiple boot complete notifications are
+        // received. In either case don't return error as this will lead to runtime exception and
+        // cause system to boot loop.
+        ALOGE("Current I/O performance data collection event %s != %s",
+                toString(mCurrCollectionEvent).c_str(),
+                toString(CollectionEvent::BOOT_TIME).c_str());
+        return {};
+    }
+    mBoottimeCollection.lastCollectionUptime = mHandlerLooper->now();
+    mHandlerLooper->removeMessages(this);
+    mHandlerLooper->sendMessage(this, SwitchEvent::END_BOOTTIME_COLLECTION);
+    return {};
+}
+
+Result<void> IoPerfCollection::dump(int fd, const Vector<String16>& args) {
+    if (args.empty()) {
+        const auto& ret = dumpCollection(fd);
+        if (!ret) {
+            return ret;
+        }
+        return {};
+    }
+
+    if (args[0] == String16(kStartCustomCollectionFlag)) {
+        if (args.size() > 7) {
+            return Error(BAD_VALUE) << "Number of arguments to start custom I/O performance data "
+                                    << "collection cannot exceed 7";
+        }
+        std::chrono::nanoseconds interval = kCustomCollectionInterval;
+        std::chrono::nanoseconds maxDuration = kCustomCollectionDuration;
+        std::unordered_set<std::string> filterPackages;
+        for (size_t i = 1; i < args.size(); ++i) {
+            if (args[i] == String16(kIntervalFlag)) {
+                const auto& ret = parseSecondsFlag(args, i + 1);
+                if (!ret) {
+                    return Error(BAD_VALUE)
+                            << "Failed to parse " << kIntervalFlag << ": " << ret.error();
+                }
+                interval = std::chrono::duration_cast<std::chrono::nanoseconds>(*ret);
+                ++i;
+                continue;
+            }
+            if (args[i] == String16(kMaxDurationFlag)) {
+                const auto& ret = parseSecondsFlag(args, i + 1);
+                if (!ret) {
+                    return Error(BAD_VALUE)
+                            << "Failed to parse " << kMaxDurationFlag << ": " << ret.error();
+                }
+                maxDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(*ret);
+                ++i;
+                continue;
+            }
+            if (args[i] == String16(kFilterPackagesFlag)) {
+                if (args.size() < i + 1) {
+                    return Error(BAD_VALUE)
+                            << "Must provide value for '" << kFilterPackagesFlag << "' flag";
+                }
+                std::vector<std::string> packages =
+                        Split(std::string(String8(args[i + 1]).string()), ",");
+                std::copy(packages.begin(), packages.end(),
+                          std::inserter(filterPackages, filterPackages.end()));
+                ++i;
+                continue;
+            }
+            ALOGW("Unknown flag %s provided to start custom I/O performance data collection",
+                  String8(args[i]).string());
+            return Error(BAD_VALUE) << "Unknown flag " << String8(args[i]).string()
+                                    << " provided to start custom I/O performance data "
+                                    << "collection";
+        }
+        const auto& ret = startCustomCollection(interval, maxDuration, filterPackages);
+        if (!ret) {
+            WriteStringToFd(ret.error().message(), fd);
+            return ret;
+        }
+        return {};
+    }
+
+    if (args[0] == String16(kEndCustomCollectionFlag)) {
+        if (args.size() != 1) {
+            ALOGW("Number of arguments to stop custom I/O performance data collection cannot "
+                  "exceed 1. Stopping the data collection.");
+            WriteStringToFd("Number of arguments to stop custom I/O performance data collection "
+                            "cannot exceed 1. Stopping the data collection.",
+                            fd);
+        }
+        return endCustomCollection(fd);
+    }
+
+    return Error(BAD_VALUE) << "I/O perf collection dump arguments start neither with "
+                            << kStartCustomCollectionFlag << " nor with "
+                            << kEndCustomCollectionFlag << " flags";
+}
+
+bool IoPerfCollection::dumpHelpText(int fd) {
+    long periodicCacheMinutes =
+            (std::chrono::duration_cast<std::chrono::seconds>(mPeriodicCollection.interval)
+                     .count() *
+             mPeriodicCollection.maxCacheSize) /
+            60;
+    return WriteStringToFd(StringPrintf(kHelpText, kStartCustomCollectionFlag, kIntervalFlag,
+                                        std::chrono::duration_cast<std::chrono::seconds>(
+                                                kCustomCollectionInterval)
+                                                .count(),
+                                        kMaxDurationFlag,
+                                        std::chrono::duration_cast<std::chrono::minutes>(
+                                                kCustomCollectionDuration)
+                                                .count(),
+                                        kFilterPackagesFlag, mTopNStatsPerCategory,
+                                        kEndCustomCollectionFlag, periodicCacheMinutes),
+                           fd);
+}
+
+Result<void> IoPerfCollection::dumpCollection(int fd) {
+    Mutex::Autolock lock(mMutex);
+    if (mCurrCollectionEvent == CollectionEvent::TERMINATED) {
+        ALOGW("I/O performance data collection not active. Dumping cached data");
+        if (!WriteStringToFd("I/O performance data collection not active. Dumping cached data.",
+                             fd)) {
+            return Error(FAILED_TRANSACTION) << "Failed to write I/O performance collection status";
+        }
+    }
+
+    const auto& ret = dumpCollectorsStatusLocked(fd);
+    if (!ret) {
+        return Error(FAILED_TRANSACTION) << ret.error();
+    }
+
+    if (!WriteStringToFd(StringPrintf("%sI/O performance data reports:\n%sBoot-time collection "
+                                      "report:\n%s\n",
+                                      kDumpMajorDelimiter.c_str(), kDumpMajorDelimiter.c_str(),
+                                      std::string(28, '=').c_str()),
+                         fd) ||
+        !WriteStringToFd(toString(mBoottimeCollection), fd) ||
+        !WriteStringToFd(StringPrintf("%s\nPeriodic collection report:\n%s\n",
+                                      std::string(75, '-').c_str(), std::string(27, '=').c_str()),
+                         fd) ||
+        !WriteStringToFd(toString(mPeriodicCollection), fd) ||
+        !WriteStringToFd(kDumpMajorDelimiter, fd)) {
+        return Error(FAILED_TRANSACTION)
+                << "Failed to dump the boot-time and periodic collection reports.";
+    }
+    return {};
+}
+
+Result<void> IoPerfCollection::dumpCollectorsStatusLocked(int fd) {
+    if (!mUidIoStats->enabled() &&
+        !WriteStringToFd(StringPrintf("UidIoStats collector failed to access the file %s",
+                                      mUidIoStats->filePath().c_str()),
+                         fd)) {
+        return Error() << "Failed to write UidIoStats collector status";
+    }
+    if (!mProcStat->enabled() &&
+        !WriteStringToFd(StringPrintf("ProcStat collector failed to access the file %s",
+                                      mProcStat->filePath().c_str()),
+                         fd)) {
+        return Error() << "Failed to write ProcStat collector status";
+    }
+    if (!mProcPidStat->enabled() &&
+        !WriteStringToFd(StringPrintf("ProcPidStat collector failed to access the directory %s",
+                                      mProcPidStat->dirPath().c_str()),
+                         fd)) {
+        return Error() << "Failed to write ProcPidStat collector status";
+    }
+    return {};
+}
+
+Result<void> IoPerfCollection::startCustomCollection(
+        std::chrono::nanoseconds interval, std::chrono::nanoseconds maxDuration,
+        const std::unordered_set<std::string>& filterPackages) {
+    if (interval < kMinCollectionInterval || maxDuration < kMinCollectionInterval) {
+        return Error(INVALID_OPERATION)
+                << "Collection interval and maximum duration must be >= "
+                << std::chrono::duration_cast<std::chrono::milliseconds>(kMinCollectionInterval)
+                           .count()
+                << " milliseconds.";
+    }
+    Mutex::Autolock lock(mMutex);
+    if (mCurrCollectionEvent != CollectionEvent::PERIODIC) {
+        return Error(INVALID_OPERATION)
+                << "Cannot start a custom collection when "
+                << "the current collection event " << toString(mCurrCollectionEvent)
+                << " != " << toString(CollectionEvent::PERIODIC) << " collection event";
+    }
+
+    mCustomCollection = {
+            .interval = interval,
+            .maxCacheSize = std::numeric_limits<std::size_t>::max(),
+            .filterPackages = filterPackages,
+            .lastCollectionUptime = mHandlerLooper->now(),
+            .records = {},
+    };
+
+    mHandlerLooper->removeMessages(this);
+    nsecs_t uptime = mHandlerLooper->now() + maxDuration.count();
+    mHandlerLooper->sendMessageAtTime(uptime, this, SwitchEvent::END_CUSTOM_COLLECTION);
+    mCurrCollectionEvent = CollectionEvent::CUSTOM;
+    mHandlerLooper->sendMessage(this, CollectionEvent::CUSTOM);
+    return {};
+}
+
+Result<void> IoPerfCollection::endCustomCollection(int fd) {
+    Mutex::Autolock lock(mMutex);
+    if (mCurrCollectionEvent != CollectionEvent::CUSTOM) {
+        return Error(INVALID_OPERATION) << "No custom collection is running";
+    }
+
+    mHandlerLooper->removeMessages(this);
+    mHandlerLooper->sendMessage(this, SwitchEvent::END_CUSTOM_COLLECTION);
+
+    const auto& ret = dumpCollectorsStatusLocked(fd);
+    if (!ret) {
+        return Error(FAILED_TRANSACTION) << ret.error();
+    }
+
+    if (!WriteStringToFd(StringPrintf("%sI/O performance data report for custom collection:\n%s",
+                                      kDumpMajorDelimiter.c_str(), kDumpMajorDelimiter.c_str()),
+                         fd) ||
+        !WriteStringToFd(toString(mCustomCollection), fd) ||
+        !WriteStringToFd(kDumpMajorDelimiter, fd)) {
+        return Error(FAILED_TRANSACTION) << "Failed to write custom collection report.";
+    }
+
+    return {};
+}
+
+void IoPerfCollection::handleMessage(const Message& message) {
+    Result<void> result;
+
+    switch (message.what) {
+        case static_cast<int>(CollectionEvent::BOOT_TIME):
+            result = processCollectionEvent(CollectionEvent::BOOT_TIME, &mBoottimeCollection);
+            break;
+        case static_cast<int>(SwitchEvent::END_BOOTTIME_COLLECTION):
+            result = processCollectionEvent(CollectionEvent::BOOT_TIME, &mBoottimeCollection);
+            if (result.ok()) {
+                mHandlerLooper->removeMessages(this);
+                mCurrCollectionEvent = CollectionEvent::PERIODIC;
+                mPeriodicCollection.lastCollectionUptime =
+                        mHandlerLooper->now() + mPeriodicCollection.interval.count();
+                mHandlerLooper->sendMessageAtTime(mPeriodicCollection.lastCollectionUptime, this,
+                                                  CollectionEvent::PERIODIC);
+            }
+            break;
+        case static_cast<int>(CollectionEvent::PERIODIC):
+            result = processCollectionEvent(CollectionEvent::PERIODIC, &mPeriodicCollection);
+            break;
+        case static_cast<int>(CollectionEvent::CUSTOM):
+            result = processCollectionEvent(CollectionEvent::CUSTOM, &mCustomCollection);
+            break;
+        case static_cast<int>(SwitchEvent::END_CUSTOM_COLLECTION): {
+            Mutex::Autolock lock(mMutex);
+            if (mCurrCollectionEvent != CollectionEvent::CUSTOM) {
+                ALOGW("Skipping END_CUSTOM_COLLECTION message as the current collection %s != %s",
+                      toString(mCurrCollectionEvent).c_str(),
+                      toString(CollectionEvent::CUSTOM).c_str());
+                return;
+            }
+            mCustomCollection = {};
+            mHandlerLooper->removeMessages(this);
+            mCurrCollectionEvent = CollectionEvent::PERIODIC;
+            mPeriodicCollection.lastCollectionUptime = mHandlerLooper->now();
+            mHandlerLooper->sendMessage(this, CollectionEvent::PERIODIC);
+            return;
+        }
+        default:
+            result = Error() << "Unknown message: " << message.what;
+    }
+
+    if (!result.ok()) {
+        Mutex::Autolock lock(mMutex);
+        ALOGE("Terminating I/O performance data collection: %s", result.error().message().c_str());
+        // DO NOT CALL terminate() as it tries to join the collection thread but this code is
+        // executed on the collection thread. Thus it will result in a deadlock.
+        mCurrCollectionEvent = CollectionEvent::TERMINATED;
+        mHandlerLooper->removeMessages(this);
+        mHandlerLooper->wake();
+    }
+}
+
+Result<void> IoPerfCollection::processCollectionEvent(CollectionEvent event, CollectionInfo* info) {
+    Mutex::Autolock lock(mMutex);
+    // Messages sent to the looper are intrinsically racy such that a message from the previous
+    // collection event may land in the looper after the current collection has already begun. Thus
+    // verify the current collection event before starting the collection.
+    if (mCurrCollectionEvent != event) {
+        ALOGW("Skipping %s collection message on collection event %s", toString(event).c_str(),
+              toString(mCurrCollectionEvent).c_str());
+        return {};
+    }
+    if (info->maxCacheSize == 0) {
+        return Error() << "Maximum cache size for " << toString(event) << " collection cannot be 0";
+    }
+    if (info->interval < kMinCollectionInterval) {
+        return Error()
+                << "Collection interval of "
+                << std::chrono::duration_cast<std::chrono::seconds>(info->interval).count()
+                << " seconds for " << toString(event) << " collection cannot be less than "
+                << std::chrono::duration_cast<std::chrono::seconds>(kMinCollectionInterval).count()
+                << " seconds";
+    }
+    auto ret = collectLocked(info);
+    if (!ret) {
+        return Error() << toString(event) << " collection failed: " << ret.error();
+    }
+    info->lastCollectionUptime += info->interval.count();
+    mHandlerLooper->sendMessageAtTime(info->lastCollectionUptime, this, event);
+    return {};
+}
+
+Result<void> IoPerfCollection::collectLocked(CollectionInfo* collectionInfo) {
+    if (!mUidIoStats->enabled() && !mProcStat->enabled() && !mProcPidStat->enabled()) {
+        return Error() << "No collectors enabled";
+    }
+    IoPerfRecord record{
+            .time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()),
+    };
+    auto ret = collectSystemIoPerfDataLocked(&record.systemIoPerfData);
+    if (!ret) {
+        return ret;
+    }
+    ret = collectProcessIoPerfDataLocked(*collectionInfo, &record.processIoPerfData);
+    if (!ret) {
+        return ret;
+    }
+    ret = collectUidIoPerfDataLocked(*collectionInfo, &record.uidIoPerfData);
+    if (!ret) {
+        return ret;
+    }
+    if (collectionInfo->records.size() > collectionInfo->maxCacheSize) {
+        collectionInfo->records.erase(collectionInfo->records.begin());  // Erase the oldest record.
+    }
+    collectionInfo->records.emplace_back(record);
+    return {};
+}
+
+Result<void> IoPerfCollection::collectUidIoPerfDataLocked(const CollectionInfo& collectionInfo,
+                                                          UidIoPerfData* uidIoPerfData) {
+    if (!mUidIoStats->enabled()) {
+        // Don't return an error to avoid pre-mature termination. Instead, fetch data from other
+        // collectors.
+        return {};
+    }
+
+    const Result<std::unordered_map<uint32_t, UidIoUsage>>& usage = mUidIoStats->collect();
+    if (!usage) {
+        return Error() << "Failed to collect uid I/O usage: " << usage.error();
+    }
+
+    // Fetch only the top N reads and writes from the usage records.
+    UidIoUsage tempUsage = {};
+    std::vector<const UidIoUsage*> topNReads(mTopNStatsPerCategory, &tempUsage);
+    std::vector<const UidIoUsage*> topNWrites(mTopNStatsPerCategory, &tempUsage);
+    std::unordered_set<uint32_t> unmappedUids;
+
+    for (const auto& uIt : *usage) {
+        const UidIoUsage& curUsage = uIt.second;
+        if (curUsage.ios.isZero()) {
+            continue;
+        }
+        if (mUidToPackageNameMapping.find(curUsage.uid) == mUidToPackageNameMapping.end()) {
+            unmappedUids.insert(curUsage.uid);
+        }
+        uidIoPerfData->total[READ_BYTES][FOREGROUND] +=
+                curUsage.ios.metrics[READ_BYTES][FOREGROUND];
+        uidIoPerfData->total[READ_BYTES][BACKGROUND] +=
+                curUsage.ios.metrics[READ_BYTES][BACKGROUND];
+        uidIoPerfData->total[WRITE_BYTES][FOREGROUND] +=
+                curUsage.ios.metrics[WRITE_BYTES][FOREGROUND];
+        uidIoPerfData->total[WRITE_BYTES][BACKGROUND] +=
+                curUsage.ios.metrics[WRITE_BYTES][BACKGROUND];
+        uidIoPerfData->total[FSYNC_COUNT][FOREGROUND] +=
+                curUsage.ios.metrics[FSYNC_COUNT][FOREGROUND];
+        uidIoPerfData->total[FSYNC_COUNT][BACKGROUND] +=
+                curUsage.ios.metrics[FSYNC_COUNT][BACKGROUND];
+
+        for (auto it = topNReads.begin(); it != topNReads.end(); ++it) {
+            const UidIoUsage* curRead = *it;
+            if (curRead->ios.sumReadBytes() < curUsage.ios.sumReadBytes()) {
+                topNReads.emplace(it, &curUsage);
+                if (collectionInfo.filterPackages.empty()) {
+                    topNReads.pop_back();
+                }
+                break;
+            }
+        }
+        for (auto it = topNWrites.begin(); it != topNWrites.end(); ++it) {
+            const UidIoUsage* curWrite = *it;
+            if (curWrite->ios.sumWriteBytes() < curUsage.ios.sumWriteBytes()) {
+                topNWrites.emplace(it, &curUsage);
+                if (collectionInfo.filterPackages.empty()) {
+                    topNWrites.pop_back();
+                }
+                break;
+            }
+        }
+    }
+
+    const auto& ret = updateUidToPackageNameMapping(unmappedUids);
+    if (!ret) {
+        ALOGW("%s", ret.error().message().c_str());
+    }
+
+    // Convert the top N I/O usage to UidIoPerfData.
+    for (const auto& usage : topNReads) {
+        if (usage->ios.isZero()) {
+            // End of non-zero usage records. This case occurs when the number of UIDs with active
+            // I/O operations is < |ro.carwatchdog.top_n_stats_per_category|.
+            break;
+        }
+        UidIoPerfData::Stats stats = {
+                .userId = multiuser_get_user_id(usage->uid),
+                .packageName = std::to_string(usage->uid),
+                .bytes = {usage->ios.metrics[READ_BYTES][FOREGROUND],
+                          usage->ios.metrics[READ_BYTES][BACKGROUND]},
+                .fsync = {usage->ios.metrics[FSYNC_COUNT][FOREGROUND],
+                          usage->ios.metrics[FSYNC_COUNT][BACKGROUND]},
+        };
+        if (mUidToPackageNameMapping.find(usage->uid) != mUidToPackageNameMapping.end()) {
+            stats.packageName = mUidToPackageNameMapping[usage->uid];
+        }
+        if (!collectionInfo.filterPackages.empty() &&
+            collectionInfo.filterPackages.find(stats.packageName) ==
+                    collectionInfo.filterPackages.end()) {
+            continue;
+        }
+        uidIoPerfData->topNReads.emplace_back(stats);
+    }
+
+    for (const auto& usage : topNWrites) {
+        if (usage->ios.isZero()) {
+            // End of non-zero usage records. This case occurs when the number of UIDs with active
+            // I/O operations is < |ro.carwatchdog.top_n_stats_per_category|.
+            break;
+        }
+        UidIoPerfData::Stats stats = {
+                .userId = multiuser_get_user_id(usage->uid),
+                .packageName = std::to_string(usage->uid),
+                .bytes = {usage->ios.metrics[WRITE_BYTES][FOREGROUND],
+                          usage->ios.metrics[WRITE_BYTES][BACKGROUND]},
+                .fsync = {usage->ios.metrics[FSYNC_COUNT][FOREGROUND],
+                          usage->ios.metrics[FSYNC_COUNT][BACKGROUND]},
+        };
+        if (mUidToPackageNameMapping.find(usage->uid) != mUidToPackageNameMapping.end()) {
+            stats.packageName = mUidToPackageNameMapping[usage->uid];
+        }
+        if (!collectionInfo.filterPackages.empty() &&
+            collectionInfo.filterPackages.find(stats.packageName) ==
+                    collectionInfo.filterPackages.end()) {
+            continue;
+        }
+        uidIoPerfData->topNWrites.emplace_back(stats);
+    }
+    return {};
+}
+
+Result<void> IoPerfCollection::collectSystemIoPerfDataLocked(SystemIoPerfData* systemIoPerfData) {
+    if (!mProcStat->enabled()) {
+        // Don't return an error to avoid pre-mature termination. Instead, fetch data from other
+        // collectors.
+        return {};
+    }
+
+    const Result<ProcStatInfo>& procStatInfo = mProcStat->collect();
+    if (!procStatInfo) {
+        return Error() << "Failed to collect proc stats: " << procStatInfo.error();
+    }
+
+    systemIoPerfData->cpuIoWaitTime = procStatInfo->cpuStats.ioWaitTime;
+    systemIoPerfData->totalCpuTime = procStatInfo->totalCpuTime();
+    systemIoPerfData->ioBlockedProcessesCnt = procStatInfo->ioBlockedProcessesCnt;
+    systemIoPerfData->totalProcessesCnt = procStatInfo->totalProcessesCnt();
+    return {};
+}
+
+Result<void> IoPerfCollection::collectProcessIoPerfDataLocked(
+        const CollectionInfo& collectionInfo, ProcessIoPerfData* processIoPerfData) {
+    if (!mProcPidStat->enabled()) {
+        // Don't return an error to avoid pre-mature termination. Instead, fetch data from other
+        // collectors.
+        return {};
+    }
+
+    const Result<std::vector<ProcessStats>>& processStats = mProcPidStat->collect();
+    if (!processStats) {
+        return Error() << "Failed to collect process stats: " << processStats.error();
+    }
+
+    const auto& uidProcessStats = getUidProcessStats(*processStats, mTopNStatsPerSubcategory);
+    std::unordered_set<uint32_t> unmappedUids;
+    // Fetch only the top N I/O blocked UIDs and UIDs with most major page faults.
+    UidProcessStats temp = {};
+    std::vector<const UidProcessStats*> topNIoBlockedUids(mTopNStatsPerCategory, &temp);
+    std::vector<const UidProcessStats*> topNMajorFaultUids(mTopNStatsPerCategory, &temp);
+    processIoPerfData->totalMajorFaults = 0;
+    for (const auto& it : *uidProcessStats) {
+        const UidProcessStats& curStats = it.second;
+        if (mUidToPackageNameMapping.find(curStats.uid) == mUidToPackageNameMapping.end()) {
+            unmappedUids.insert(curStats.uid);
+        }
+        processIoPerfData->totalMajorFaults += curStats.majorFaults;
+        for (auto it = topNIoBlockedUids.begin(); it != topNIoBlockedUids.end(); ++it) {
+            const UidProcessStats* topStats = *it;
+            if (topStats->ioBlockedTasksCnt < curStats.ioBlockedTasksCnt) {
+                topNIoBlockedUids.emplace(it, &curStats);
+                if (collectionInfo.filterPackages.empty()) {
+                    topNIoBlockedUids.pop_back();
+                }
+                break;
+            }
+        }
+        for (auto it = topNMajorFaultUids.begin(); it != topNMajorFaultUids.end(); ++it) {
+            const UidProcessStats* topStats = *it;
+            if (topStats->majorFaults < curStats.majorFaults) {
+                topNMajorFaultUids.emplace(it, &curStats);
+                if (collectionInfo.filterPackages.empty()) {
+                    topNMajorFaultUids.pop_back();
+                }
+                break;
+            }
+        }
+    }
+
+    const auto& ret = updateUidToPackageNameMapping(unmappedUids);
+    if (!ret) {
+        ALOGW("%s", ret.error().message().c_str());
+    }
+
+    // Convert the top N uid process stats to ProcessIoPerfData.
+    for (const auto& it : topNIoBlockedUids) {
+        if (it->ioBlockedTasksCnt == 0) {
+            // End of non-zero elements. This case occurs when the number of UIDs with I/O blocked
+            // processes is < |ro.carwatchdog.top_n_stats_per_category|.
+            break;
+        }
+        ProcessIoPerfData::UidStats stats = {
+                .userId = multiuser_get_user_id(it->uid),
+                .packageName = std::to_string(it->uid),
+                .count = it->ioBlockedTasksCnt,
+        };
+        if (mUidToPackageNameMapping.find(it->uid) != mUidToPackageNameMapping.end()) {
+            stats.packageName = mUidToPackageNameMapping[it->uid];
+        }
+        if (!collectionInfo.filterPackages.empty() &&
+            collectionInfo.filterPackages.find(stats.packageName) ==
+                    collectionInfo.filterPackages.end()) {
+            continue;
+        }
+        for (const auto& pIt : it->topNIoBlockedProcesses) {
+            if (pIt.count == 0) {
+                break;
+            }
+            stats.topNProcesses.emplace_back(
+                    ProcessIoPerfData::UidStats::ProcessStats{pIt.comm, pIt.count});
+        }
+        processIoPerfData->topNIoBlockedUids.emplace_back(stats);
+        processIoPerfData->topNIoBlockedUidsTotalTaskCnt.emplace_back(it->totalTasksCnt);
+    }
+    for (const auto& it : topNMajorFaultUids) {
+        if (it->majorFaults == 0) {
+            // End of non-zero elements. This case occurs when the number of UIDs with major faults
+            // is < |ro.carwatchdog.top_n_stats_per_category|.
+            break;
+        }
+        ProcessIoPerfData::UidStats stats = {
+                .userId = multiuser_get_user_id(it->uid),
+                .packageName = std::to_string(it->uid),
+                .count = it->majorFaults,
+        };
+        if (mUidToPackageNameMapping.find(it->uid) != mUidToPackageNameMapping.end()) {
+            stats.packageName = mUidToPackageNameMapping[it->uid];
+        }
+        if (!collectionInfo.filterPackages.empty() &&
+            collectionInfo.filterPackages.find(stats.packageName) ==
+                    collectionInfo.filterPackages.end()) {
+            continue;
+        }
+        for (const auto& pIt : it->topNMajorFaultProcesses) {
+            if (pIt.count == 0) {
+                break;
+            }
+            stats.topNProcesses.emplace_back(
+                    ProcessIoPerfData::UidStats::ProcessStats{pIt.comm, pIt.count});
+        }
+        processIoPerfData->topNMajorFaultUids.emplace_back(stats);
+    }
+    if (mLastMajorFaults == 0) {
+        processIoPerfData->majorFaultsPercentChange = 0;
+    } else {
+        int64_t increase = processIoPerfData->totalMajorFaults - mLastMajorFaults;
+        processIoPerfData->majorFaultsPercentChange =
+                (static_cast<double>(increase) / static_cast<double>(mLastMajorFaults)) * 100.0;
+    }
+    mLastMajorFaults = processIoPerfData->totalMajorFaults;
+    return {};
+}
+
+Result<void> IoPerfCollection::updateUidToPackageNameMapping(
+    const std::unordered_set<uint32_t>& uids) {
+    std::vector<int32_t> appUids;
+
+    for (const auto& uid : uids) {
+        if (uid >= AID_APP_START) {
+            appUids.emplace_back(static_cast<int32_t>(uid));
+            continue;
+        }
+        // System/native UIDs.
+        passwd* usrpwd = getpwuid(uid);
+        if (!usrpwd) {
+            continue;
+        }
+        mUidToPackageNameMapping[uid] = std::string(usrpwd->pw_name);
+    }
+
+    if (appUids.empty()) {
+        return {};
+    }
+
+    if (mPackageManager == nullptr) {
+        auto ret = retrievePackageManager();
+        if (!ret) {
+            return Error() << "Failed to retrieve package manager: " << ret.error();
+        }
+    }
+
+    std::vector<std::string> packageNames;
+    const binder::Status& status = mPackageManager->getNamesForUids(appUids, &packageNames);
+    if (!status.isOk()) {
+        return Error() << "package_native::getNamesForUids failed: " << status.exceptionMessage();
+    }
+
+    for (uint32_t i = 0; i < appUids.size(); i++) {
+        if (!packageNames[i].empty()) {
+            mUidToPackageNameMapping[appUids[i]] = packageNames[i];
+        }
+    }
+
+    return {};
+}
+
+Result<void> IoPerfCollection::retrievePackageManager() {
+    const sp<IServiceManager> sm = defaultServiceManager();
+    if (sm == nullptr) {
+        return Error() << "Failed to retrieve defaultServiceManager";
+    }
+
+    sp<IBinder> binder = sm->getService(String16("package_native"));
+    if (binder == nullptr) {
+        return Error() << "Failed to get service package_native";
+    }
+    mPackageManager = interface_cast<IPackageManagerNative>(binder);
+    return {};
+}
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/watchdog/server/src/IoPerfCollection.h b/watchdog/server/src/IoPerfCollection.h
new file mode 100644
index 0000000..4cccb05
--- /dev/null
+++ b/watchdog/server/src/IoPerfCollection.h
@@ -0,0 +1,316 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WATCHDOG_SERVER_SRC_IOPERFCOLLECTION_H_
+#define WATCHDOG_SERVER_SRC_IOPERFCOLLECTION_H_
+
+#include <android-base/chrono_utils.h>
+#include <android-base/result.h>
+#include <android/content/pm/IPackageManagerNative.h>
+#include <cutils/multiuser.h>
+#include <gtest/gtest_prod.h>
+#include <time.h>
+#include <utils/Errors.h>
+#include <utils/Looper.h>
+#include <utils/Mutex.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+#include <utils/Vector.h>
+
+#include <string>
+#include <thread>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "LooperWrapper.h"
+#include "ProcPidStat.h"
+#include "ProcStat.h"
+#include "UidIoStats.h"
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+constexpr const char* kStartCustomCollectionFlag = "--start_io";
+constexpr const char* kEndCustomCollectionFlag = "--stop_io";
+constexpr const char* kIntervalFlag = "--interval";
+constexpr const char* kMaxDurationFlag = "--max_duration";
+constexpr const char* kFilterPackagesFlag = "--filter_packages";
+
+// Performance data collected from the `/proc/uid_io/stats` file.
+struct UidIoPerfData {
+    struct Stats {
+        userid_t userId = 0;
+        std::string packageName;
+        uint64_t bytes[UID_STATES];
+        uint64_t fsync[UID_STATES];
+    };
+    std::vector<Stats> topNReads = {};
+    std::vector<Stats> topNWrites = {};
+    uint64_t total[METRIC_TYPES][UID_STATES] = {{0}};
+};
+
+std::string toString(const UidIoPerfData& perfData);
+
+// Performance data collected from the `/proc/stats` file.
+struct SystemIoPerfData {
+    uint64_t cpuIoWaitTime = 0;
+    uint64_t totalCpuTime = 0;
+    uint32_t ioBlockedProcessesCnt = 0;
+    uint32_t totalProcessesCnt = 0;
+};
+
+std::string toString(const SystemIoPerfData& perfData);
+
+// Performance data collected from the `/proc/[pid]/stat` and `/proc/[pid]/task/[tid]/stat` files.
+struct ProcessIoPerfData {
+    struct UidStats {
+        userid_t userId = 0;
+        std::string packageName;
+        uint64_t count = 0;
+        struct ProcessStats {
+            std::string comm = "";
+            uint64_t count = 0;
+        };
+        std::vector<ProcessStats> topNProcesses = {};
+    };
+    std::vector<UidStats> topNIoBlockedUids = {};
+    // Total # of tasks owned by each UID in |topNIoBlockedUids|.
+    std::vector<uint64_t> topNIoBlockedUidsTotalTaskCnt = {};
+    std::vector<UidStats> topNMajorFaultUids = {};
+    uint64_t totalMajorFaults = 0;
+    // Percentage of increase/decrease in the major page faults since last collection.
+    double majorFaultsPercentChange = 0.0;
+};
+
+std::string toString(const ProcessIoPerfData& data);
+
+struct IoPerfRecord {
+    time_t time;  // Collection time.
+    UidIoPerfData uidIoPerfData;
+    SystemIoPerfData systemIoPerfData;
+    ProcessIoPerfData processIoPerfData;
+};
+
+std::string toString(const IoPerfRecord& record);
+
+struct CollectionInfo {
+    std::chrono::nanoseconds interval = 0ns;  // Collection interval between subsequent collections.
+    size_t maxCacheSize = 0;                  // Maximum cache size for the collection.
+    std::unordered_set<std::string> filterPackages;  // Filter the output only to the specified
+                                                     // packages.
+    nsecs_t lastCollectionUptime = 0;         // Used to calculate the uptime for next collection.
+    std::vector<IoPerfRecord> records;        // Cache of collected performance records.
+};
+
+std::string toString(const CollectionInfo& collectionInfo);
+
+enum CollectionEvent {
+    INIT = 0,
+    BOOT_TIME,
+    PERIODIC,
+    CUSTOM,
+    TERMINATED,
+    LAST_EVENT,
+};
+
+enum SwitchEvent {
+    // Ends boot-time collection by collecting the last boot-time record and switching the
+    // collection event to periodic collection.
+    END_BOOTTIME_COLLECTION = CollectionEvent::LAST_EVENT + 1,
+    // Ends custom collection, discards collected data and starts periodic collection.
+    END_CUSTOM_COLLECTION
+};
+
+static inline std::string toString(CollectionEvent event) {
+    switch (event) {
+        case CollectionEvent::INIT:
+            return "INIT";
+        case CollectionEvent::BOOT_TIME:
+            return "BOOT_TIME";
+        case CollectionEvent::PERIODIC:
+            return "PERIODIC";
+        case CollectionEvent::CUSTOM:
+            return "CUSTOM";
+        case CollectionEvent::TERMINATED:
+            return "TERMINATED";
+        default:
+            return "INVALID";
+    }
+}
+
+// IoPerfCollection implements the I/O performance data collection module of the CarWatchDog
+// service. It exposes APIs that the CarWatchDog main thread and binder service can call to start
+// a collection, update the collection type, and generate collection dumps.
+class IoPerfCollection : public MessageHandler {
+public:
+    IoPerfCollection() :
+          mHandlerLooper(new LooperWrapper()),
+          mBoottimeCollection({}),
+          mPeriodicCollection({}),
+          mCustomCollection({}),
+          mCurrCollectionEvent(CollectionEvent::INIT),
+          mUidToPackageNameMapping({}),
+          mUidIoStats(new UidIoStats()),
+          mProcStat(new ProcStat()),
+          mProcPidStat(new ProcPidStat()),
+          mLastMajorFaults(0) {}
+
+    ~IoPerfCollection() { terminate(); }
+
+    // Starts the boot-time collection in the looper handler on a collection thread and returns
+    // immediately. Must be called only once. Otherwise, returns an error.
+    android::base::Result<void> start();
+
+    // Terminates the collection thread and returns.
+    void terminate();
+
+    // Ends the boot-time collection, caches boot-time perf records, sends message to the looper to
+    // begin the periodic collection, and returns immediately.
+    virtual android::base::Result<void> onBootFinished();
+
+    // Depending the arguments, it either:
+    // 1. Generates a dump from the boot-time and periodic collection events.
+    // 2. Starts custom collection.
+    // 3. Ends custom collection and dumps the collected data.
+    // Returns any error observed during the dump generation.
+    virtual android::base::Result<void> dump(int fd, const Vector<String16>& args);
+
+    // Dumps the help text.
+    bool dumpHelpText(int fd);
+
+private:
+    // Generates a dump from the boot-time and periodic collection events.
+    android::base::Result<void> dumpCollection(int fd);
+
+    // Dumps the collectors' status when they are disabled.
+    android::base::Result<void> dumpCollectorsStatusLocked(int fd);
+
+    // Starts a custom collection on the looper handler, temporarily stops the periodic collection
+    // (won't discard the collected data), and returns immediately. Returns any error observed
+    // during this process. The custom collection happens once every |interval| seconds. When the
+    // |maxDuration| is reached, the looper receives a message to end the collection, discards the
+    // collected data, and starts the periodic collection. This is needed to ensure the custom
+    // collection doesn't run forever when a subsequent |endCustomCollection| call is not received.
+    // When |kFilterPackagesFlag| value is provided, the results are filtered only to the specified
+    // package names.
+    android::base::Result<void> startCustomCollection(
+            std::chrono::nanoseconds interval, std::chrono::nanoseconds maxDuration,
+            const std::unordered_set<std::string>& filterPackages);
+
+    // Ends the current custom collection, generates a dump, sends message to looper to start the
+    // periodic collection, and returns immediately. Returns an error when there is no custom
+    // collection running or when a dump couldn't be generated from the custom collection.
+    android::base::Result<void> endCustomCollection(int fd);
+
+    // Handles the messages received by the lopper.
+    void handleMessage(const Message& message) override;
+
+    // Processes the events received by |handleMessage|.
+    android::base::Result<void> processCollectionEvent(CollectionEvent event, CollectionInfo* info);
+
+    // Collects/stores the performance data for the current collection event.
+    android::base::Result<void> collectLocked(CollectionInfo* collectionInfo);
+
+    // Collects performance data from the `/proc/uid_io/stats` file.
+    android::base::Result<void> collectUidIoPerfDataLocked(const CollectionInfo& collectionInfo,
+                                                           UidIoPerfData* uidIoPerfData);
+
+    // Collects performance data from the `/proc/stats` file.
+    android::base::Result<void> collectSystemIoPerfDataLocked(SystemIoPerfData* systemIoPerfData);
+
+    // Collects performance data from the `/proc/[pid]/stat` and
+    // `/proc/[pid]/task/[tid]/stat` files.
+    android::base::Result<void> collectProcessIoPerfDataLocked(
+            const CollectionInfo& collectionInfo, ProcessIoPerfData* processIoPerfData);
+
+    // Updates the |mUidToPackageNameMapping| for the given |uids|.
+    android::base::Result<void> updateUidToPackageNameMapping(
+            const std::unordered_set<uint32_t>& uids);
+
+    // Retrieves package manager from the default service manager.
+    android::base::Result<void> retrievePackageManager();
+
+    // Top N per-UID stats per category.
+    int mTopNStatsPerCategory;
+
+    // Top N per-process stats per subcategory.
+    int mTopNStatsPerSubcategory;
+
+    // Thread on which the actual collection happens.
+    std::thread mCollectionThread;
+
+    // Makes sure only one collection is running at any given time.
+    Mutex mMutex;
+
+    // Handler lopper to execute different collection events on the collection thread.
+    android::sp<LooperWrapper> mHandlerLooper GUARDED_BY(mMutex);
+
+    // Info for the |CollectionEvent::BOOT_TIME| collection event. The cache is persisted until
+    // system shutdown/reboot.
+    CollectionInfo mBoottimeCollection GUARDED_BY(mMutex);
+
+    // Info for the |CollectionEvent::PERIODIC| collection event. The cache size is limited by
+    // |ro.carwatchdog.periodic_collection_buffer_size|.
+    CollectionInfo mPeriodicCollection GUARDED_BY(mMutex);
+
+    // Info for the |CollectionEvent::CUSTOM| collection event. The info is cleared at the end of
+    // every custom collection.
+    CollectionInfo mCustomCollection GUARDED_BY(mMutex);
+
+    // Tracks the current collection event. Updated on |start|, |onBootComplete|,
+    // |startCustomCollection| and |endCustomCollection|.
+    CollectionEvent mCurrCollectionEvent GUARDED_BY(mMutex);
+
+    // Cache of uid to package name mapping.
+    std::unordered_map<uint64_t, std::string> mUidToPackageNameMapping GUARDED_BY(mMutex);
+
+    // Collector/parser for `/proc/uid_io/stats`.
+    android::sp<UidIoStats> mUidIoStats GUARDED_BY(mMutex);
+
+    // Collector/parser for `/proc/stat`.
+    android::sp<ProcStat> mProcStat GUARDED_BY(mMutex);
+
+    // Collector/parser for `/proc/PID/*` stat files.
+    android::sp<ProcPidStat> mProcPidStat GUARDED_BY(mMutex);
+
+    // Major faults delta from last collection. Useful when calculating the percentage change in
+    // major faults since last collection.
+    uint64_t mLastMajorFaults GUARDED_BY(mMutex);
+
+    // To get the package names from app uids.
+    android::sp<android::content::pm::IPackageManagerNative> mPackageManager GUARDED_BY(mMutex);
+
+    FRIEND_TEST(IoPerfCollectionTest, TestCollectionStartAndTerminate);
+    FRIEND_TEST(IoPerfCollectionTest, TestValidCollectionSequence);
+    FRIEND_TEST(IoPerfCollectionTest, TestCollectionTerminatesOnZeroEnabledCollectors);
+    FRIEND_TEST(IoPerfCollectionTest, TestCollectionTerminatesOnError);
+    FRIEND_TEST(IoPerfCollectionTest, TestCustomCollectionTerminatesAfterMaxDuration);
+    FRIEND_TEST(IoPerfCollectionTest, TestValidUidIoStatFile);
+    FRIEND_TEST(IoPerfCollectionTest, TestUidIOStatsLessThanTopNStatsLimit);
+    FRIEND_TEST(IoPerfCollectionTest, TestProcUidIoStatsContentsFromDevice);
+    FRIEND_TEST(IoPerfCollectionTest, TestValidProcStatFile);
+    FRIEND_TEST(IoPerfCollectionTest, TestValidProcPidContents);
+    FRIEND_TEST(IoPerfCollectionTest, TestProcPidContentsLessThanTopNStatsLimit);
+    FRIEND_TEST(IoPerfCollectionTest, TestCustomCollectionFiltersPackageNames);
+};
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
+
+#endif  //  WATCHDOG_SERVER_SRC_IOPERFCOLLECTION_H_
diff --git a/watchdog/server/src/LooperWrapper.cpp b/watchdog/server/src/LooperWrapper.cpp
new file mode 100644
index 0000000..35912ff
--- /dev/null
+++ b/watchdog/server/src/LooperWrapper.cpp
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LooperWrapper.h"
+
+#include <utils/Looper.h>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using android::sp;
+
+void LooperWrapper::wake() {
+    if (mLooper == nullptr) {
+        ALOGW("No looper in LooperWrapper");
+        return;
+    }
+    return mLooper->wake();
+}
+
+int LooperWrapper::pollAll(int timeoutMillis) {
+    if (mLooper == nullptr) {
+        ALOGW("No looper in LooperWrapper");
+        return 0;
+    }
+    return mLooper->pollAll(timeoutMillis);
+}
+
+void LooperWrapper::sendMessage(const sp<MessageHandler>& handler, const Message& message) {
+    if (mLooper == nullptr) {
+        ALOGW("No looper in LooperWrapper");
+        return;
+    }
+    return mLooper->sendMessage(handler, message);
+}
+
+void LooperWrapper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
+                                      const Message& message) {
+    if (mLooper == nullptr) {
+        ALOGW("No looper in LooperWrapper");
+        return;
+    }
+    return mLooper->sendMessageAtTime(uptime, handler, message);
+}
+
+void LooperWrapper::removeMessages(const sp<MessageHandler>& handler) {
+    if (mLooper == nullptr) {
+        ALOGW("No looper in LooperWrapper");
+        return;
+    }
+    return mLooper->removeMessages(handler);
+}
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/watchdog/server/src/LooperWrapper.h b/watchdog/server/src/LooperWrapper.h
new file mode 100644
index 0000000..d6e31df
--- /dev/null
+++ b/watchdog/server/src/LooperWrapper.h
@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WATCHDOG_SERVER_SRC_LOOPERWRAPPER_H_
+#define WATCHDOG_SERVER_SRC_LOOPERWRAPPER_H_
+
+#include <utils/Looper.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+// LooperWrapper is a wrapper around the actual looper implementation so tests can stub this wrapper
+// to deterministically poll the underlying looper.
+// Refer to utils/Looper.h for the class and methods descriptions.
+class LooperWrapper : public RefBase {
+public:
+    LooperWrapper() : mLooper(nullptr) {}
+    virtual ~LooperWrapper() {}
+
+    void setLooper(sp<Looper> looper) { mLooper = looper; }
+    void wake();
+    virtual nsecs_t now() { return systemTime(SYSTEM_TIME_MONOTONIC); }
+    virtual int pollAll(int timeoutMillis);
+    virtual void sendMessage(const android::sp<MessageHandler>& handler, const Message& message);
+    virtual void sendMessageAtTime(nsecs_t uptime, const android::sp<MessageHandler>& handler,
+                                   const Message& message);
+    virtual void removeMessages(const android::sp<MessageHandler>& handler);
+
+protected:
+    android::sp<Looper> mLooper;
+};
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
+
+#endif  //  WATCHDOG_SERVER_SRC_LOOPERWRAPPER_H_
diff --git a/watchdog/server/src/ProcPidStat.cpp b/watchdog/server/src/ProcPidStat.cpp
new file mode 100644
index 0000000..b92c739
--- /dev/null
+++ b/watchdog/server/src/ProcPidStat.cpp
@@ -0,0 +1,315 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "carwatchdogd"
+
+#include "ProcPidStat.h"
+
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+#include <dirent.h>
+#include <log/log.h>
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using android::base::EndsWith;
+using android::base::Error;
+using android::base::ParseInt;
+using android::base::ParseUint;
+using android::base::ReadFileToString;
+using android::base::Result;
+using android::base::Split;
+
+namespace {
+
+enum ReadError {
+    ERR_INVALID_FILE = 0,
+    ERR_FILE_OPEN_READ = 1,
+    NUM_ERRORS = 2,
+};
+
+// /proc/PID/stat or /proc/PID/task/TID/stat format:
+// <pid> <comm> <state> <ppid> <pgrp ID> <session ID> <tty_nr> <tpgid> <flags> <minor faults>
+// <children minor faults> <major faults> <children major faults> <user mode time>
+// <system mode time> <children user mode time> <children kernel mode time> <priority> <nice value>
+// <num threads> <start time since boot> <virtual memory size> <resident set size> <rss soft limit>
+// <start code addr> <end code addr> <start stack addr> <ESP value> <EIP> <bitmap of pending sigs>
+// <bitmap of blocked sigs> <bitmap of ignored sigs> <waiting channel> <num pages swapped>
+// <cumulative pages swapped> <exit signal> <processor #> <real-time prio> <agg block I/O delays>
+// <guest time> <children guest time> <start data addr> <end data addr> <start break addr>
+// <cmd line args start addr> <amd line args end addr> <env start addr> <env end addr> <exit code>
+// Example line: 1 (init) S 0 0 0 0 0 0 0 0 220 0 0 0 0 0 0 0 2 0 0 ...etc...
+bool parsePidStatLine(const std::string& line, PidStat* pidStat) {
+    std::vector<std::string> fields = Split(line, " ");
+
+    // Note: Regex parsing for the below logic increased the time taken to run the
+    // ProcPidStatTest#TestProcPidStatContentsFromDevice from 151.7ms to 1.3 seconds.
+
+    // Comm string is enclosed with ( ) brackets and may contain space(s). Thus calculate the
+    // commEndOffset based on the field that contains the closing bracket.
+    size_t commEndOffset = 0;
+    for (size_t i = 1; i < fields.size(); ++i) {
+        pidStat->comm += fields[i];
+        if (EndsWith(fields[i], ")")) {
+            commEndOffset = i - 1;
+            break;
+        }
+        pidStat->comm += " ";
+    }
+
+    if (pidStat->comm.front() != '(' || pidStat->comm.back() != ')') {
+        ALOGW("Comm string `%s` not enclosed in brackets", pidStat->comm.c_str());
+        return false;
+    }
+    pidStat->comm.erase(pidStat->comm.begin());
+    pidStat->comm.erase(pidStat->comm.end() - 1);
+
+    // The required data is in the first 22 + |commEndOffset| fields so make sure there are at least
+    // these many fields in the file.
+    if (fields.size() < 22 + commEndOffset || !ParseUint(fields[0], &pidStat->pid) ||
+        !ParseUint(fields[3 + commEndOffset], &pidStat->ppid) ||
+        !ParseUint(fields[11 + commEndOffset], &pidStat->majorFaults) ||
+        !ParseUint(fields[19 + commEndOffset], &pidStat->numThreads) ||
+        !ParseUint(fields[21 + commEndOffset], &pidStat->startTime)) {
+        ALOGW("Invalid proc pid stat contents: \"%s\"", line.c_str());
+        return false;
+    }
+    pidStat->state = fields[2 + commEndOffset];
+    return true;
+}
+
+Result<void> readPidStatFile(const std::string& path, PidStat* pidStat) {
+    std::string buffer;
+    if (!ReadFileToString(path, &buffer)) {
+        return Error(ERR_FILE_OPEN_READ) << "ReadFileToString failed for " << path;
+    }
+    std::vector<std::string> lines = Split(std::move(buffer), "\n");
+    if (lines.size() != 1 && (lines.size() != 2 || !lines[1].empty())) {
+        return Error(ERR_INVALID_FILE) << path << " contains " << lines.size() << " lines != 1";
+    }
+    if (!parsePidStatLine(std::move(lines[0]), pidStat)) {
+        return Error(ERR_INVALID_FILE) << "Failed to parse the contents of " << path;
+    }
+    return {};
+}
+
+}  // namespace
+
+Result<std::vector<ProcessStats>> ProcPidStat::collect() {
+    if (!mEnabled) {
+        return Error() << "Can not access PID stat files under " << kProcDirPath;
+    }
+
+    Mutex::Autolock lock(mMutex);
+    const auto& processStats = getProcessStatsLocked();
+    if (!processStats) {
+        return Error() << processStats.error();
+    }
+
+    std::vector<ProcessStats> delta;
+    for (const auto& it : *processStats) {
+        const ProcessStats& curStats = it.second;
+        const auto& cachedIt = mLastProcessStats.find(it.first);
+        if (cachedIt == mLastProcessStats.end() ||
+            cachedIt->second.process.startTime != curStats.process.startTime) {
+            // New/reused PID so don't calculate the delta.
+            delta.emplace_back(curStats);
+            continue;
+        }
+
+        ProcessStats deltaStats = curStats;
+        const ProcessStats& cachedStats = cachedIt->second;
+        deltaStats.process.majorFaults -= cachedStats.process.majorFaults;
+        for (auto& deltaThread : deltaStats.threads) {
+            const auto& cachedThread = cachedStats.threads.find(deltaThread.first);
+            if (cachedThread == cachedStats.threads.end() ||
+                cachedThread->second.startTime != deltaThread.second.startTime) {
+                // New TID or TID reused by the same PID so don't calculate the delta.
+                continue;
+            }
+            deltaThread.second.majorFaults -= cachedThread->second.majorFaults;
+        }
+        delta.emplace_back(deltaStats);
+    }
+    mLastProcessStats = *processStats;
+    return delta;
+}
+
+Result<std::unordered_map<uint32_t, ProcessStats>> ProcPidStat::getProcessStatsLocked() const {
+    std::unordered_map<uint32_t, ProcessStats> processStats;
+    auto procDirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(mPath.c_str()), closedir);
+    if (!procDirp) {
+        return Error() << "Failed to open " << mPath << " directory";
+    }
+    dirent* pidDir = nullptr;
+    while ((pidDir = readdir(procDirp.get())) != nullptr) {
+        // 1. Read top-level pid stats.
+        uint32_t pid = 0;
+        if (pidDir->d_type != DT_DIR || !ParseUint(pidDir->d_name, &pid)) {
+            continue;
+        }
+        ProcessStats curStats;
+        std::string path = StringPrintf((mPath + kStatFileFormat).c_str(), pid);
+        const auto& ret = readPidStatFile(path, &curStats.process);
+        if (!ret) {
+            // PID may disappear between scanning the directory and parsing the stat file.
+            // Thus treat ERR_FILE_OPEN_READ errors as soft errors.
+            if (ret.error().code() != ERR_FILE_OPEN_READ) {
+                return Error() << "Failed to read top-level per-process stat file: "
+                               << ret.error().message().c_str();
+            }
+            ALOGW("Failed to read top-level per-process stat file %s: %s", path.c_str(),
+                  ret.error().message().c_str());
+            continue;
+        }
+
+        // 2. When not found in the cache, fetch tgid/UID as soon as possible because processes
+        // may terminate during scanning.
+        const auto& it = mLastProcessStats.find(curStats.process.pid);
+        if (it == mLastProcessStats.end() ||
+            it->second.process.startTime != curStats.process.startTime || it->second.tgid == -1 ||
+            it->second.uid == -1) {
+            const auto& ret = getPidStatusLocked(&curStats);
+            if (!ret) {
+                if (ret.error().code() != ERR_FILE_OPEN_READ) {
+                    return Error() << "Failed to read pid status for pid " << curStats.process.pid
+                                   << ": " << ret.error().message().c_str();
+                }
+                ALOGW("Failed to read pid status for pid %" PRIu32 ": %s", curStats.process.pid,
+                      ret.error().message().c_str());
+                // Default tgid and uid values are -1 (aka unknown).
+            }
+        } else {
+            // Fetch from cache.
+            curStats.tgid = it->second.tgid;
+            curStats.uid = it->second.uid;
+        }
+
+        if (curStats.tgid != -1 && curStats.tgid != curStats.process.pid) {
+            ALOGW("Skipping non-process (i.e., Tgid != PID) entry for PID %" PRIu32,
+                  curStats.process.pid);
+            continue;
+        }
+
+        // 3. Fetch per-thread stats.
+        std::string taskDir = StringPrintf((mPath + kTaskDirFormat).c_str(), pid);
+        auto taskDirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(taskDir.c_str()), closedir);
+        if (!taskDirp) {
+            // Treat this as a soft error so at least the process stats will be collected.
+            ALOGW("Failed to open %s directory", taskDir.c_str());
+        }
+        dirent* tidDir = nullptr;
+        bool didReadMainThread = false;
+        while (taskDirp != nullptr && (tidDir = readdir(taskDirp.get())) != nullptr) {
+            uint32_t tid = 0;
+            if (tidDir->d_type != DT_DIR || !ParseUint(tidDir->d_name, &tid)) {
+                continue;
+            }
+            if (processStats.find(tid) != processStats.end()) {
+                return Error() << "Process stats already exists for TID " << tid
+                               << ". Stats will be double counted";
+            }
+
+            PidStat curThreadStat = {};
+            path = StringPrintf((taskDir + kStatFileFormat).c_str(), tid);
+            const auto& ret = readPidStatFile(path, &curThreadStat);
+            if (!ret) {
+                if (ret.error().code() != ERR_FILE_OPEN_READ) {
+                    return Error() << "Failed to read per-thread stat file: "
+                                   << ret.error().message().c_str();
+                }
+                // Maybe the thread terminated before reading the file so skip this thread and
+                // continue with scanning the next thread's stat.
+                ALOGW("Failed to read per-thread stat file %s: %s", path.c_str(),
+                      ret.error().message().c_str());
+                continue;
+            }
+            if (curThreadStat.pid == curStats.process.pid) {
+                didReadMainThread = true;
+            }
+            curStats.threads[curThreadStat.pid] = curThreadStat;
+        }
+        if (!didReadMainThread) {
+            // In the event of failure to read main-thread info (mostly because the process
+            // terminated during scanning/parsing), fill out the stat that are common between main
+            // thread and the process.
+            curStats.threads[curStats.process.pid] = PidStat{
+                    .pid = curStats.process.pid,
+                    .comm = curStats.process.comm,
+                    .state = curStats.process.state,
+                    .ppid = curStats.process.ppid,
+                    .numThreads = curStats.process.numThreads,
+                    .startTime = curStats.process.startTime,
+            };
+        }
+        processStats[curStats.process.pid] = curStats;
+    }
+    return processStats;
+}
+
+Result<void> ProcPidStat::getPidStatusLocked(ProcessStats* processStats) const {
+    std::string buffer;
+    std::string path = StringPrintf((mPath + kStatusFileFormat).c_str(), processStats->process.pid);
+    if (!ReadFileToString(path, &buffer)) {
+        return Error(ERR_FILE_OPEN_READ) << "ReadFileToString failed for " << path;
+    }
+    std::vector<std::string> lines = Split(std::move(buffer), "\n");
+    bool didReadUid = false;
+    bool didReadTgid = false;
+    for (size_t i = 0; i < lines.size(); ++i) {
+        if (lines[i].empty()) {
+            continue;
+        }
+        if (!lines[i].compare(0, 4, "Uid:")) {
+            if (didReadUid) {
+                return Error(ERR_INVALID_FILE)
+                        << "Duplicate UID line: \"" << lines[i] << "\" in file " << path;
+            }
+            std::vector<std::string> fields = Split(lines[i], "\t");
+            if (fields.size() < 2 || !ParseInt(fields[1], &processStats->uid)) {
+                return Error(ERR_INVALID_FILE)
+                        << "Invalid UID line: \"" << lines[i] << "\" in file " << path;
+            }
+            didReadUid = true;
+        } else if (!lines[i].compare(0, 5, "Tgid:")) {
+            if (didReadTgid) {
+                return Error(ERR_INVALID_FILE)
+                        << "Duplicate Tgid line: \"" << lines[i] << "\" in file" << path;
+            }
+            std::vector<std::string> fields = Split(lines[i], "\t");
+            if (fields.size() != 2 || !ParseInt(fields[1], &processStats->tgid)) {
+                return Error(ERR_INVALID_FILE)
+                        << "Invalid tgid line: \"" << lines[i] << "\" in file" << path;
+            }
+            didReadTgid = true;
+        }
+    }
+    if (!didReadUid || !didReadTgid) {
+        return Error(ERR_INVALID_FILE) << "Incomplete file " << mPath + kStatusFileFormat;
+    }
+    return {};
+}
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/watchdog/server/src/ProcPidStat.h b/watchdog/server/src/ProcPidStat.h
new file mode 100644
index 0000000..c520cb6
--- /dev/null
+++ b/watchdog/server/src/ProcPidStat.h
@@ -0,0 +1,124 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WATCHDOG_SERVER_SRC_PROCPIDSTAT_H_
+#define WATCHDOG_SERVER_SRC_PROCPIDSTAT_H_
+
+#include <android-base/result.h>
+#include <android-base/stringprintf.h>
+#include <gtest/gtest_prod.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using android::base::StringPrintf;
+
+#define PID_FOR_INIT 1
+
+constexpr const char* kProcDirPath = "/proc";
+constexpr const char* kStatFileFormat = "/%" PRIu32 "/stat";
+constexpr const char* kTaskDirFormat = "/%" PRIu32 "/task";
+constexpr const char* kStatusFileFormat = "/%" PRIu32 "/status";
+
+struct PidStat {
+    uint32_t pid = 0;
+    std::string comm = "";
+    std::string state = "";
+    uint32_t ppid = 0;
+    uint64_t majorFaults = 0;
+    uint32_t numThreads = 0;
+    uint64_t startTime = 0;  // Useful when identifying PID/TID reuse
+};
+
+struct ProcessStats {
+    int64_t tgid = -1;                              // -1 indicates a failure to read this value
+    int64_t uid = -1;                               // -1 indicates a failure to read this value
+    PidStat process = {};                           // Aggregated stats across all the threads
+    std::unordered_map<uint32_t, PidStat> threads;  // Per-thread stat including the main thread
+};
+
+// Collector/parser for `/proc/[pid]/stat`, `/proc/[pid]/task/[tid]/stat` and /proc/[pid]/status`
+// files.
+class ProcPidStat : public RefBase {
+public:
+    explicit ProcPidStat(const std::string& path = kProcDirPath) :
+          mLastProcessStats({}), mPath(path) {
+        std::string pidStatPath = StringPrintf((mPath + kStatFileFormat).c_str(), PID_FOR_INIT);
+        std::string tidStatPath = StringPrintf((mPath + kTaskDirFormat + kStatFileFormat).c_str(),
+                                               PID_FOR_INIT, PID_FOR_INIT);
+        std::string pidStatusPath = StringPrintf((mPath + kStatusFileFormat).c_str(), PID_FOR_INIT);
+
+        mEnabled = !access(pidStatPath.c_str(), R_OK) && !access(tidStatPath.c_str(), R_OK) &&
+                !access(pidStatusPath.c_str(), R_OK);
+    }
+
+    virtual ~ProcPidStat() {}
+
+    // Collects pid info delta since the last collection.
+    virtual android::base::Result<std::vector<ProcessStats>> collect();
+
+    // Called by IoPerfCollection and tests.
+    virtual bool enabled() { return mEnabled; }
+
+    virtual std::string dirPath() { return mPath; }
+
+private:
+    // Reads the contents of the below files:
+    // 1. Pid stat file at |mPath| + |kStatFileFormat|
+    // 2. Tid stat file at |mPath| + |kTaskDirFormat| + |kStatFileFormat|
+    android::base::Result<std::unordered_map<uint32_t, ProcessStats>> getProcessStatsLocked() const;
+
+    // Reads the tgid and real UID for the given PID from |mPath| + |kStatusFileFormat|.
+    android::base::Result<void> getPidStatusLocked(ProcessStats* processStats) const;
+
+    // Makes sure only one collection is running at any given time.
+    Mutex mMutex;
+
+    // Last dump of per-process stats. Useful for calculating the delta and identifying PID/TID
+    // reuse.
+    std::unordered_map<uint32_t, ProcessStats> mLastProcessStats GUARDED_BY(mMutex);
+
+    // True if the below files are accessible:
+    // 1. Pid stat file at |mPath| + |kTaskStatFileFormat|
+    // 2. Tid stat file at |mPath| + |kTaskDirFormat| + |kStatFileFormat|
+    // 3. Pid status file at |mPath| + |kStatusFileFormat|
+    // Otherwise, set to false.
+    bool mEnabled;
+
+    // Proc directory path. Default value is |kProcDirPath|.
+    // Updated by tests to point to a different location when needed.
+    std::string mPath;
+
+    FRIEND_TEST(IoPerfCollectionTest, TestValidProcPidContents);
+    FRIEND_TEST(ProcPidStatTest, TestValidStatFiles);
+    FRIEND_TEST(ProcPidStatTest, TestHandlesProcessTerminationBetweenScanningAndParsing);
+    FRIEND_TEST(ProcPidStatTest, TestHandlesPidTidReuse);
+};
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
+
+#endif  //  WATCHDOG_SERVER_SRC_PROCPIDSTAT_H_
diff --git a/watchdog/server/src/ProcStat.cpp b/watchdog/server/src/ProcStat.cpp
new file mode 100644
index 0000000..34b847f
--- /dev/null
+++ b/watchdog/server/src/ProcStat.cpp
@@ -0,0 +1,159 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "carwatchdogd"
+
+#include "ProcStat.h"
+
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+#include <log/log.h>
+
+#include <string>
+#include <vector>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using android::base::Error;
+using android::base::ReadFileToString;
+using android::base::Result;
+using android::base::StartsWith;
+using base::ParseUint;
+using base::Split;
+
+namespace {
+
+bool parseCpuStats(const std::string& data, CpuStats* cpuStats) {
+    std::vector<std::string> fields = Split(data, " ");
+    if (fields.size() == 12 && fields[1].empty()) {
+        // The first cpu line will have an extra space after the first word. This will generate an
+        // empty element when the line is split on " ". Erase the extra element.
+        fields.erase(fields.begin() + 1);
+    }
+    if (fields.size() != 11 || fields[0] != "cpu" || !ParseUint(fields[1], &cpuStats->userTime) ||
+        !ParseUint(fields[2], &cpuStats->niceTime) || !ParseUint(fields[3], &cpuStats->sysTime) ||
+        !ParseUint(fields[4], &cpuStats->idleTime) ||
+        !ParseUint(fields[5], &cpuStats->ioWaitTime) || !ParseUint(fields[6], &cpuStats->irqTime) ||
+        !ParseUint(fields[7], &cpuStats->softIrqTime) ||
+        !ParseUint(fields[8], &cpuStats->stealTime) ||
+        !ParseUint(fields[9], &cpuStats->guestTime) ||
+        !ParseUint(fields[10], &cpuStats->guestNiceTime)) {
+        ALOGW("Invalid cpu line: \"%s\"", data.c_str());
+        return false;
+    }
+    return true;
+}
+
+bool parseProcsCount(const std::string& data, uint32_t* out) {
+    std::vector<std::string> fields = Split(data, " ");
+    if (fields.size() != 2 || !StartsWith(fields[0], "procs_") || !ParseUint(fields[1], out)) {
+        ALOGW("Invalid procs_ line: \"%s\"", data.c_str());
+        return false;
+    }
+    return true;
+}
+
+}  // namespace
+
+Result<ProcStatInfo> ProcStat::collect() {
+    if (!kEnabled) {
+        return Error() << "Can not access " << kPath;
+    }
+
+    Mutex::Autolock lock(mMutex);
+    const auto& info = getProcStatLocked();
+    if (!info) {
+        return Error() << "Failed to get proc stat contents: " << info.error();
+    }
+
+    ProcStatInfo delta;
+
+    delta.cpuStats.userTime = info->cpuStats.userTime - mLastCpuStats.userTime;
+    delta.cpuStats.niceTime = info->cpuStats.niceTime - mLastCpuStats.niceTime;
+    delta.cpuStats.sysTime = info->cpuStats.sysTime - mLastCpuStats.sysTime;
+    delta.cpuStats.idleTime = info->cpuStats.idleTime - mLastCpuStats.idleTime;
+    delta.cpuStats.ioWaitTime = info->cpuStats.ioWaitTime - mLastCpuStats.ioWaitTime;
+    delta.cpuStats.irqTime = info->cpuStats.irqTime - mLastCpuStats.irqTime;
+    delta.cpuStats.softIrqTime = info->cpuStats.softIrqTime - mLastCpuStats.softIrqTime;
+    delta.cpuStats.stealTime = info->cpuStats.stealTime - mLastCpuStats.stealTime;
+    delta.cpuStats.guestTime = info->cpuStats.guestTime - mLastCpuStats.guestTime;
+    delta.cpuStats.guestNiceTime = info->cpuStats.guestNiceTime - mLastCpuStats.guestNiceTime;
+
+    // Process counts are real-time values. Thus they should be reported as-is and not their deltas.
+    delta.runnableProcessesCnt = info->runnableProcessesCnt;
+    delta.ioBlockedProcessesCnt = info->ioBlockedProcessesCnt;
+
+    mLastCpuStats = info->cpuStats;
+
+    return delta;
+}
+
+Result<ProcStatInfo> ProcStat::getProcStatLocked() const {
+    std::string buffer;
+    if (!ReadFileToString(kPath, &buffer)) {
+        return Error() << "ReadFileToString failed for " << kPath;
+    }
+
+    std::vector<std::string> lines = Split(std::move(buffer), "\n");
+    ProcStatInfo info;
+    bool didReadProcsRunning = false;
+    bool didReadProcsBlocked = false;
+    for (size_t i = 0; i < lines.size(); i++) {
+        if (lines[i].empty()) {
+            continue;
+        }
+        if (!lines[i].compare(0, 4, "cpu ")) {
+            if (info.totalCpuTime() != 0) {
+                return Error() << "Duplicate `cpu .*` line in " << kPath;
+            }
+            if (!parseCpuStats(std::move(lines[i]), &info.cpuStats)) {
+                return Error() << "Failed to parse `cpu .*` line in " << kPath;
+            }
+        } else if (!lines[i].compare(0, 6, "procs_")) {
+            if (!lines[i].compare(0, 13, "procs_running")) {
+                if (didReadProcsRunning) {
+                    return Error() << "Duplicate `procs_running .*` line in " << kPath;
+                }
+                if (!parseProcsCount(std::move(lines[i]), &info.runnableProcessesCnt)) {
+                    return Error() << "Failed to parse `procs_running .*` line in " << kPath;
+                }
+                didReadProcsRunning = true;
+                continue;
+            } else if (!lines[i].compare(0, 13, "procs_blocked")) {
+                if (didReadProcsBlocked) {
+                    return Error() << "Duplicate `procs_blocked .*` line in " << kPath;
+                }
+                if (!parseProcsCount(std::move(lines[i]), &info.ioBlockedProcessesCnt)) {
+                    return Error() << "Failed to parse `procs_blocked .*` line in " << kPath;
+                }
+                didReadProcsBlocked = true;
+                continue;
+            }
+            return Error() << "Unknown procs_ line `" << lines[i] << "` in " << kPath;
+        }
+    }
+    if (info.totalCpuTime() == 0 || !didReadProcsRunning || !didReadProcsBlocked) {
+        return Error() << kPath << " is incomplete";
+    }
+    return info;
+}
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/watchdog/server/src/ProcStat.h b/watchdog/server/src/ProcStat.h
new file mode 100644
index 0000000..00df4c8
--- /dev/null
+++ b/watchdog/server/src/ProcStat.h
@@ -0,0 +1,104 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WATCHDOG_SERVER_SRC_PROCSTAT_H_
+#define WATCHDOG_SERVER_SRC_PROCSTAT_H_
+
+#include <android-base/result.h>
+#include <stdint.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+constexpr const char* kProcStatPath = "/proc/stat";
+
+struct CpuStats {
+    uint64_t userTime = 0;       // Time spent in user mode.
+    uint64_t niceTime = 0;       // Time spent in user mode with low priority (nice).
+    uint64_t sysTime = 0;        // Time spent in system mode.
+    uint64_t idleTime = 0;       // Time spent in the idle task.
+    uint64_t ioWaitTime = 0;     // Time spent on context switching/waiting due to I/O operations.
+    uint64_t irqTime = 0;        // Time servicing interrupts.
+    uint64_t softIrqTime = 0;    // Time servicing soft interrupts.
+    uint64_t stealTime = 0;      // Stolen time (Time spent in other OS in a virtualized env).
+    uint64_t guestTime = 0;      // Time spent running a virtual CPU for guest OS.
+    uint64_t guestNiceTime = 0;  // Time spent running a niced virtual CPU for guest OS.
+};
+
+class ProcStatInfo {
+public:
+    ProcStatInfo() : cpuStats({}), runnableProcessesCnt(0), ioBlockedProcessesCnt(0) {}
+    ProcStatInfo(CpuStats stats, uint32_t runnableCnt, uint32_t ioBlockedCnt) :
+          cpuStats(stats), runnableProcessesCnt(runnableCnt), ioBlockedProcessesCnt(ioBlockedCnt) {}
+    CpuStats cpuStats;
+    uint32_t runnableProcessesCnt;
+    uint32_t ioBlockedProcessesCnt;
+
+    uint64_t totalCpuTime() const {
+        return cpuStats.userTime + cpuStats.niceTime + cpuStats.sysTime + cpuStats.idleTime +
+                cpuStats.ioWaitTime + cpuStats.irqTime + cpuStats.softIrqTime + cpuStats.stealTime +
+                cpuStats.guestTime + cpuStats.guestNiceTime;
+    }
+    uint32_t totalProcessesCnt() const { return runnableProcessesCnt + ioBlockedProcessesCnt; }
+    bool operator==(const ProcStatInfo& info) const {
+        return memcmp(&cpuStats, &info.cpuStats, sizeof(cpuStats)) == 0 &&
+                runnableProcessesCnt == info.runnableProcessesCnt &&
+                ioBlockedProcessesCnt == info.ioBlockedProcessesCnt;
+    }
+};
+
+// Collector/parser for `/proc/stat` file.
+class ProcStat : public RefBase {
+public:
+    explicit ProcStat(const std::string& path = kProcStatPath) :
+          mLastCpuStats({}), kEnabled(!access(path.c_str(), R_OK)), kPath(path) {}
+
+    virtual ~ProcStat() {}
+
+    // Collects proc stat delta since the last collection.
+    virtual android::base::Result<ProcStatInfo> collect();
+
+    // Returns true when the proc stat file is accessible. Otherwise, returns false.
+    // Called by IoPerfCollection and tests.
+    virtual bool enabled() { return kEnabled; }
+
+    virtual std::string filePath() { return kProcStatPath; }
+
+private:
+    // Reads the contents of |kPath|.
+    android::base::Result<ProcStatInfo> getProcStatLocked() const;
+
+    // Makes sure only one collection is running at any given time.
+    Mutex mMutex;
+
+    // Last dump of cpu stats from the file at |kPath|.
+    CpuStats mLastCpuStats GUARDED_BY(mMutex);
+
+    // True if |kPath| is accessible.
+    const bool kEnabled;
+
+    // Path to proc stat file. Default path is |kProcStatPath|.
+    const std::string kPath;
+};
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
+
+#endif  //  WATCHDOG_SERVER_SRC_PROCSTAT_H_
diff --git a/watchdog/server/src/ServiceManager.cpp b/watchdog/server/src/ServiceManager.cpp
new file mode 100644
index 0000000..3535232
--- /dev/null
+++ b/watchdog/server/src/ServiceManager.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "carwatchdogd"
+
+#include "ServiceManager.h"
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using android::sp;
+using android::String16;
+using android::automotive::watchdog::WatchdogProcessService;
+using android::base::Error;
+using android::base::Result;
+
+sp<WatchdogProcessService> ServiceManager::sWatchdogProcessService = nullptr;
+sp<IoPerfCollection> ServiceManager::sIoPerfCollection = nullptr;
+sp<WatchdogBinderMediator> ServiceManager::sWatchdogBinderMediator = nullptr;
+
+Result<void> ServiceManager::startServices(const sp<Looper>& looper) {
+    if (sWatchdogProcessService != nullptr || sIoPerfCollection != nullptr ||
+        sWatchdogBinderMediator != nullptr) {
+        return Error(INVALID_OPERATION) << "Cannot start services more than once";
+    }
+    auto result = startProcessAnrMonitor(looper);
+    if (!result.ok()) {
+        return result;
+    }
+    result = startIoPerfCollection();
+    if (!result.ok()) {
+        return result;
+    }
+    return {};
+}
+
+void ServiceManager::terminateServices() {
+    if (sWatchdogProcessService != nullptr) {
+        sWatchdogProcessService->terminate();
+        sWatchdogProcessService = nullptr;
+    }
+    if (sIoPerfCollection != nullptr) {
+        sIoPerfCollection->terminate();
+        sIoPerfCollection = nullptr;
+    }
+    if (sWatchdogBinderMediator != nullptr) {
+        sWatchdogBinderMediator->terminate();
+        sWatchdogBinderMediator = nullptr;
+    }
+}
+
+Result<void> ServiceManager::startProcessAnrMonitor(const sp<Looper>& looper) {
+    sWatchdogProcessService = new WatchdogProcessService(looper);
+    return {};
+}
+
+Result<void> ServiceManager::startIoPerfCollection() {
+    sp<IoPerfCollection> service = new IoPerfCollection();
+    const auto& result = service->start();
+    if (!result.ok()) {
+        return Error(result.error().code())
+                << "Failed to start I/O performance collection: " << result.error();
+    }
+    sIoPerfCollection = service;
+    return {};
+}
+
+Result<void> ServiceManager::startBinderMediator() {
+    sWatchdogBinderMediator = new WatchdogBinderMediator();
+    const auto& result = sWatchdogBinderMediator->init(sWatchdogProcessService, sIoPerfCollection);
+    if (!result.ok()) {
+        return Error(result.error().code())
+                << "Failed to start binder mediator: " << result.error();
+    }
+    return {};
+}
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/watchdog/server/src/ServiceManager.h b/watchdog/server/src/ServiceManager.h
new file mode 100644
index 0000000..3abc660
--- /dev/null
+++ b/watchdog/server/src/ServiceManager.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WATCHDOG_SERVER_SRC_SERVICEMANAGER_H_
+#define WATCHDOG_SERVER_SRC_SERVICEMANAGER_H_
+
+#include <android-base/result.h>
+#include <utils/Looper.h>
+#include <utils/StrongPointer.h>
+
+#include "IoPerfCollection.h"
+#include "WatchdogBinderMediator.h"
+#include "WatchdogProcessService.h"
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+class ServiceManager {
+public:
+    static android::base::Result<void> startServices(const android::sp<Looper>& looper);
+    static android::base::Result<void> startBinderMediator();
+    static void terminateServices();
+
+private:
+    static android::base::Result<void> startProcessAnrMonitor(const android::sp<Looper>& looper);
+    static android::base::Result<void> startIoPerfCollection();
+
+    static android::sp<WatchdogProcessService> sWatchdogProcessService;
+    static android::sp<IoPerfCollection> sIoPerfCollection;
+    static android::sp<WatchdogBinderMediator> sWatchdogBinderMediator;
+};
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
+
+#endif  // WATCHDOG_SERVER_SRC_SERVICEMANAGER_H_
diff --git a/watchdog/server/src/UidIoStats.cpp b/watchdog/server/src/UidIoStats.cpp
new file mode 100644
index 0000000..6b9d109
--- /dev/null
+++ b/watchdog/server/src/UidIoStats.cpp
@@ -0,0 +1,154 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "carwatchdogd"
+#define DEBUG false
+
+#include "UidIoStats.h"
+
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <inttypes.h>
+#include <log/log.h>
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+#include <utility>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using android::base::Error;
+using android::base::ReadFileToString;
+using android::base::Result;
+using android::base::StringPrintf;
+using base::ParseUint;
+using base::Split;
+
+namespace {
+
+bool parseUidIoStats(const std::string& data, UidIoStat* uidIoStat) {
+    std::vector<std::string> fields = Split(data, " ");
+    if (fields.size() < 11 || !ParseUint(fields[0], &uidIoStat->uid) ||
+        !ParseUint(fields[1], &uidIoStat->io[FOREGROUND].rchar) ||
+        !ParseUint(fields[2], &uidIoStat->io[FOREGROUND].wchar) ||
+        !ParseUint(fields[3], &uidIoStat->io[FOREGROUND].readBytes) ||
+        !ParseUint(fields[4], &uidIoStat->io[FOREGROUND].writeBytes) ||
+        !ParseUint(fields[5], &uidIoStat->io[BACKGROUND].rchar) ||
+        !ParseUint(fields[6], &uidIoStat->io[BACKGROUND].wchar) ||
+        !ParseUint(fields[7], &uidIoStat->io[BACKGROUND].readBytes) ||
+        !ParseUint(fields[8], &uidIoStat->io[BACKGROUND].writeBytes) ||
+        !ParseUint(fields[9], &uidIoStat->io[FOREGROUND].fsync) ||
+        !ParseUint(fields[10], &uidIoStat->io[BACKGROUND].fsync)) {
+        ALOGW("Invalid uid I/O stats: \"%s\"", data.c_str());
+        return false;
+    }
+    return true;
+}
+
+}  // namespace
+
+bool IoUsage::isZero() const {
+    for (int i = 0; i < METRIC_TYPES; i++) {
+        for (int j = 0; j < UID_STATES; j++) {
+            if (metrics[i][j]) {
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+std::string IoUsage::toString() const {
+    return StringPrintf("FgRdBytes:%" PRIu64 " BgRdBytes:%" PRIu64 " FgWrBytes:%" PRIu64
+                        " BgWrBytes:%" PRIu64 " FgFsync:%" PRIu64 " BgFsync:%" PRIu64,
+                        metrics[READ_BYTES][FOREGROUND], metrics[READ_BYTES][BACKGROUND],
+                        metrics[WRITE_BYTES][FOREGROUND], metrics[WRITE_BYTES][BACKGROUND],
+                        metrics[FSYNC_COUNT][FOREGROUND], metrics[FSYNC_COUNT][BACKGROUND]);
+}
+
+Result<std::unordered_map<uint32_t, UidIoUsage>> UidIoStats::collect() {
+    if (!kEnabled) {
+        return Error() << "Can not access " << kPath;
+    }
+
+    Mutex::Autolock lock(mMutex);
+    const auto& uidIoStats = getUidIoStatsLocked();
+    if (!uidIoStats.ok() || uidIoStats->empty()) {
+        return Error() << "Failed to get UID IO stats: " << uidIoStats.error();
+    }
+
+    std::unordered_map<uint32_t, UidIoUsage> usage;
+    for (const auto& it : *uidIoStats) {
+        const UidIoStat& uidIoStat = it.second;
+        usage[uidIoStat.uid] = {};
+        struct UidIoUsage& uidUsage = usage[uidIoStat.uid];
+        uidUsage.uid = uidIoStat.uid;
+
+        int64_t fgRdDelta = uidIoStat.io[FOREGROUND].readBytes -
+                            mLastUidIoStats[uidIoStat.uid].io[FOREGROUND].readBytes;
+        int64_t bgRdDelta = uidIoStat.io[BACKGROUND].readBytes -
+                            mLastUidIoStats[uidIoStat.uid].io[BACKGROUND].readBytes;
+        int64_t fgWrDelta = uidIoStat.io[FOREGROUND].writeBytes -
+                            mLastUidIoStats[uidIoStat.uid].io[FOREGROUND].writeBytes;
+        int64_t bgWrDelta = uidIoStat.io[BACKGROUND].writeBytes -
+                            mLastUidIoStats[uidIoStat.uid].io[BACKGROUND].writeBytes;
+        int64_t fgFsDelta =
+            uidIoStat.io[FOREGROUND].fsync - mLastUidIoStats[uidIoStat.uid].io[FOREGROUND].fsync;
+        int64_t bgFsDelta =
+            uidIoStat.io[BACKGROUND].fsync - mLastUidIoStats[uidIoStat.uid].io[BACKGROUND].fsync;
+
+        uidUsage.ios.metrics[READ_BYTES][FOREGROUND] += (fgRdDelta < 0) ? 0 : fgRdDelta;
+        uidUsage.ios.metrics[READ_BYTES][BACKGROUND] += (bgRdDelta < 0) ? 0 : bgRdDelta;
+        uidUsage.ios.metrics[WRITE_BYTES][FOREGROUND] += (fgWrDelta < 0) ? 0 : fgWrDelta;
+        uidUsage.ios.metrics[WRITE_BYTES][BACKGROUND] += (bgWrDelta < 0) ? 0 : bgWrDelta;
+        uidUsage.ios.metrics[FSYNC_COUNT][FOREGROUND] += (fgFsDelta < 0) ? 0 : fgFsDelta;
+        uidUsage.ios.metrics[FSYNC_COUNT][BACKGROUND] += (bgFsDelta < 0) ? 0 : bgFsDelta;
+    }
+    mLastUidIoStats = *uidIoStats;
+    return usage;
+}
+
+Result<std::unordered_map<uint32_t, UidIoStat>> UidIoStats::getUidIoStatsLocked() const {
+    std::string buffer;
+    if (!ReadFileToString(kPath, &buffer)) {
+        return Error() << "ReadFileToString failed for " << kPath;
+    }
+
+    std::vector<std::string> ioStats = Split(std::move(buffer), "\n");
+    std::unordered_map<uint32_t, UidIoStat> uidIoStats;
+    UidIoStat uidIoStat;
+    for (size_t i = 0; i < ioStats.size(); i++) {
+        if (ioStats[i].empty() || !ioStats[i].compare(0, 4, "task")) {
+            // Skip per-task stats as CONFIG_UID_SYS_STATS_DEBUG is not set in the kernel and
+            // the collected data is aggregated only per-UID.
+            continue;
+        }
+        if (!parseUidIoStats(std::move(ioStats[i]), &uidIoStat)) {
+            return Error() << "Failed to parse the contents of " << kPath;
+        }
+        uidIoStats[uidIoStat.uid] = uidIoStat;
+    }
+    return uidIoStats;
+}
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/watchdog/server/src/UidIoStats.h b/watchdog/server/src/UidIoStats.h
new file mode 100644
index 0000000..20258ca
--- /dev/null
+++ b/watchdog/server/src/UidIoStats.h
@@ -0,0 +1,128 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WATCHDOG_SERVER_SRC_UIDIOSTATS_H_
+#define WATCHDOG_SERVER_SRC_UIDIOSTATS_H_
+
+#include <android-base/result.h>
+#include <stdint.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+
+#include <string>
+#include <unordered_map>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+constexpr const char* kUidIoStatsPath = "/proc/uid_io/stats";
+
+enum UidState {
+    FOREGROUND = 0,
+    BACKGROUND,
+    UID_STATES,
+};
+
+enum MetricType {
+    READ_BYTES = 0,
+    WRITE_BYTES,
+    FSYNC_COUNT,
+    METRIC_TYPES,
+};
+
+struct IoStat {
+    uint64_t rchar = 0;       // characters read
+    uint64_t wchar = 0;       // characters written
+    uint64_t readBytes = 0;   // bytes read (from storage layer)
+    uint64_t writeBytes = 0;  // bytes written (to storage layer)
+    uint64_t fsync = 0;       // number of fsync syscalls
+};
+
+struct UidIoStat {
+    uint32_t uid = 0;  // linux user id
+    IoStat io[UID_STATES] = {{}};
+};
+
+class IoUsage {
+  public:
+    IoUsage() : metrics{{0}} {};
+    IoUsage(uint64_t fgRdBytes, uint64_t bgRdBytes, uint64_t fgWrBytes, uint64_t bgWrBytes,
+            uint64_t fgFsync, uint64_t bgFsync) {
+        metrics[READ_BYTES][FOREGROUND] = fgRdBytes;
+        metrics[READ_BYTES][BACKGROUND] = bgRdBytes;
+        metrics[WRITE_BYTES][FOREGROUND] = fgWrBytes;
+        metrics[WRITE_BYTES][BACKGROUND] = bgWrBytes;
+        metrics[FSYNC_COUNT][FOREGROUND] = fgFsync;
+        metrics[FSYNC_COUNT][BACKGROUND] = bgFsync;
+    }
+    bool operator==(const IoUsage& usage) const {
+        return memcmp(&metrics, &usage.metrics, sizeof(metrics)) == 0;
+    }
+    uint64_t sumReadBytes() const {
+        return metrics[READ_BYTES][FOREGROUND] + metrics[READ_BYTES][BACKGROUND];
+    }
+    uint64_t sumWriteBytes() const {
+        return metrics[WRITE_BYTES][FOREGROUND] + metrics[WRITE_BYTES][BACKGROUND];
+    }
+    bool isZero() const;
+    std::string toString() const;
+    uint64_t metrics[METRIC_TYPES][UID_STATES];
+};
+
+struct UidIoUsage {
+    uint32_t uid = 0;
+    IoUsage ios = {};
+};
+
+class UidIoStats : public RefBase {
+public:
+    explicit UidIoStats(const std::string& path = kUidIoStatsPath) :
+          kEnabled(!access(path.c_str(), R_OK)), kPath(path) {}
+
+    virtual ~UidIoStats() {}
+
+    // Collects the I/O usage since the last collection.
+    virtual android::base::Result<std::unordered_map<uint32_t, UidIoUsage>> collect();
+
+    // Returns true when the uid_io stats file is accessible. Otherwise, returns false.
+    // Called by IoPerfCollection and tests.
+    virtual bool enabled() { return kEnabled; }
+
+    virtual std::string filePath() { return kPath; }
+
+private:
+    // Reads the contents of |kPath|.
+    android::base::Result<std::unordered_map<uint32_t, UidIoStat>> getUidIoStatsLocked() const;
+
+    // Makes sure only one collection is running at any given time.
+    Mutex mMutex;
+
+    // Last dump from the file at |kPath|.
+    std::unordered_map<uint32_t, UidIoStat> mLastUidIoStats GUARDED_BY(mMutex);
+
+    // True if kPath is accessible.
+    const bool kEnabled;
+
+    // Path to uid_io stats file. Default path is |kUidIoStatsPath|.
+    const std::string kPath;
+};
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
+
+#endif  //  WATCHDOG_SERVER_SRC_UIDIOSTATS_H_
diff --git a/watchdog/server/src/WatchdogBinderMediator.cpp b/watchdog/server/src/WatchdogBinderMediator.cpp
new file mode 100644
index 0000000..0a482fd
--- /dev/null
+++ b/watchdog/server/src/WatchdogBinderMediator.cpp
@@ -0,0 +1,219 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "carwatchdogd"
+
+#include "WatchdogBinderMediator.h"
+
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+#include <android/automotive/watchdog/BootPhase.h>
+#include <android/automotive/watchdog/PowerCycle.h>
+#include <android/automotive/watchdog/UserState.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <cutils/multiuser.h>
+#include <log/log.h>
+#include <private/android_filesystem_config.h>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using android::defaultServiceManager;
+using android::base::Error;
+using android::base::ParseUint;
+using android::base::Result;
+using android::base::StringPrintf;
+using android::base::WriteStringToFd;
+using android::binder::Status;
+
+namespace {
+
+constexpr const char* kHelpFlag = "--help";
+constexpr const char* kHelpShortFlag = "-h";
+constexpr const char* kHelpText =
+        "CarWatchdog daemon dumpsys help page:\n"
+        "Format: dumpsys android.automotive.watchdog.ICarWatchdog/default [options]\n\n"
+        "%s or %s: Displays this help text.\n"
+        "When no options are specified, carwatchdog report is generated.\n";
+
+Status checkSystemPermission() {
+    if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
+        return Status::fromExceptionCode(Status::EX_SECURITY,
+                                         "Calling process does not have proper privilege");
+    }
+    return Status::ok();
+}
+
+Status fromExceptionCode(int32_t exceptionCode, std::string message) {
+    ALOGW("%s", message.c_str());
+    return Status::fromExceptionCode(exceptionCode, message.c_str());
+}
+
+}  // namespace
+
+Result<void> WatchdogBinderMediator::init(sp<WatchdogProcessService> watchdogProcessService,
+                                          sp<IoPerfCollection> ioPerfCollection) {
+    if (watchdogProcessService == nullptr || ioPerfCollection == nullptr) {
+        return Error(INVALID_OPERATION)
+                << "Must initialize both process and I/O perf collection service before starting "
+                << "carwatchdog binder mediator";
+    }
+    if (mWatchdogProcessService != nullptr || mIoPerfCollection != nullptr) {
+        return Error(INVALID_OPERATION)
+                << "Cannot initialize carwatchdog binder mediator more than once";
+    }
+    mWatchdogProcessService = watchdogProcessService;
+    mIoPerfCollection = ioPerfCollection;
+    status_t status =
+            defaultServiceManager()
+                    ->addService(String16("android.automotive.watchdog.ICarWatchdog/default"),
+                                 this);
+    if (status != OK) {
+        return Error(status) << "Failed to start carwatchdog binder mediator";
+    }
+    return {};
+}
+
+status_t WatchdogBinderMediator::dump(int fd, const Vector<String16>& args) {
+    if (args.empty()) {
+        auto ret = mWatchdogProcessService->dump(fd, args);
+        if (!ret.ok()) {
+            ALOGW("Failed to dump carwatchdog process service: %s", ret.error().message().c_str());
+            return ret.error().code();
+        }
+        ret = mIoPerfCollection->dump(fd, args);
+        if (!ret.ok()) {
+            ALOGW("Failed to dump I/O perf collection: %s", ret.error().message().c_str());
+            return ret.error().code();
+        }
+        return OK;
+    }
+
+    if (args[0] == String16(kHelpFlag) || args[0] == String16(kHelpShortFlag)) {
+        if (!dumpHelpText(fd, "")) {
+            ALOGW("Failed to write help text to fd");
+            return FAILED_TRANSACTION;
+        }
+        return OK;
+    }
+
+    if (args[0] == String16(kStartCustomCollectionFlag) ||
+        args[0] == String16(kEndCustomCollectionFlag)) {
+        auto ret = mIoPerfCollection->dump(fd, args);
+        if (!ret.ok()) {
+            std::string mode = args[0] == String16(kStartCustomCollectionFlag) ? "start" : "end";
+            std::string errorMsg = StringPrintf("Failed to %s custom I/O perf collection: %s",
+                                                mode.c_str(), ret.error().message().c_str());
+            if (ret.error().code() == BAD_VALUE) {
+                dumpHelpText(fd, errorMsg);
+            } else {
+                ALOGW("%s", errorMsg.c_str());
+            }
+            return ret.error().code();
+        }
+        return OK;
+    }
+    dumpHelpText(fd, "Invalid dump arguments");
+    return INVALID_OPERATION;
+}
+
+bool WatchdogBinderMediator::dumpHelpText(int fd, std::string errorMsg) {
+    if (!errorMsg.empty()) {
+        ALOGW("Error: %s", errorMsg.c_str());
+        if (!WriteStringToFd(StringPrintf("Error: %s\n\n", errorMsg.c_str()), fd)) {
+            ALOGW("Failed to write error message to fd");
+            return false;
+        }
+    }
+
+    return WriteStringToFd(StringPrintf(kHelpText, kHelpFlag, kHelpShortFlag), fd) &&
+            mIoPerfCollection->dumpHelpText(fd);
+}
+
+Status WatchdogBinderMediator::registerMediator(const sp<ICarWatchdogClient>& mediator) {
+    Status status = checkSystemPermission();
+    if (!status.isOk()) {
+        return status;
+    }
+    return mWatchdogProcessService->registerMediator(mediator);
+}
+
+Status WatchdogBinderMediator::unregisterMediator(const sp<ICarWatchdogClient>& mediator) {
+    Status status = checkSystemPermission();
+    if (!status.isOk()) {
+        return status;
+    }
+    return mWatchdogProcessService->unregisterMediator(mediator);
+}
+Status WatchdogBinderMediator::registerMonitor(const sp<ICarWatchdogMonitor>& monitor) {
+    Status status = checkSystemPermission();
+    if (!status.isOk()) {
+        return status;
+    }
+    return mWatchdogProcessService->registerMonitor(monitor);
+}
+Status WatchdogBinderMediator::unregisterMonitor(const sp<ICarWatchdogMonitor>& monitor) {
+    Status status = checkSystemPermission();
+    if (!status.isOk()) {
+        return status;
+    }
+    return mWatchdogProcessService->unregisterMonitor(monitor);
+}
+
+Status WatchdogBinderMediator::notifySystemStateChange(StateType type, int32_t arg1, int32_t arg2) {
+    Status status = checkSystemPermission();
+    if (!status.isOk()) {
+        return status;
+    }
+    switch (type) {
+        case StateType::POWER_CYCLE: {
+            PowerCycle powerCycle = static_cast<PowerCycle>(static_cast<uint32_t>(arg1));
+            if (powerCycle >= PowerCycle::NUM_POWER_CYLES) {
+                return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
+                                         StringPrintf("Invalid power cycle %d", powerCycle));
+            }
+            return mWatchdogProcessService->notifyPowerCycleChange(powerCycle);
+        }
+        case StateType::USER_STATE: {
+            userid_t userId = static_cast<userid_t>(arg1);
+            UserState userState = static_cast<UserState>(static_cast<uint32_t>(arg2));
+            if (userState >= UserState::NUM_USER_STATES) {
+                return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
+                                         StringPrintf("Invalid user state %d", userState));
+            }
+            return mWatchdogProcessService->notifyUserStateChange(userId, userState);
+        }
+        case StateType::BOOT_PHASE: {
+            BootPhase phase = static_cast<BootPhase>(static_cast<uint32_t>(arg1));
+            if (phase >= BootPhase::BOOT_COMPLETED) {
+                auto ret = mIoPerfCollection->onBootFinished();
+                if (!ret.ok()) {
+                    return fromExceptionCode(ret.error().code(), ret.error().message());
+                }
+            }
+            return Status::ok();
+        }
+    }
+    return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
+                             StringPrintf("Invalid state change type %d", type));
+}
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/watchdog/server/src/WatchdogBinderMediator.h b/watchdog/server/src/WatchdogBinderMediator.h
new file mode 100644
index 0000000..530659b
--- /dev/null
+++ b/watchdog/server/src/WatchdogBinderMediator.h
@@ -0,0 +1,101 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WATCHDOG_SERVER_SRC_WATCHDOGBINDERMEDIATOR_H_
+#define WATCHDOG_SERVER_SRC_WATCHDOGBINDERMEDIATOR_H_
+
+#include <android-base/result.h>
+#include <android/automotive/watchdog/BnCarWatchdog.h>
+#include <android/automotive/watchdog/StateType.h>
+#include <binder/IBinder.h>
+#include <binder/Status.h>
+#include <gtest/gtest_prod.h>
+#include <utils/Errors.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+#include <utils/Vector.h>
+
+#include "IoPerfCollection.h"
+#include "WatchdogProcessService.h"
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+class ServiceManager;
+
+// WatchdogBinderMediator implements the carwatchdog binder APIs such that it forwards the calls
+// either to process ANR service or I/O performance data collection.
+class WatchdogBinderMediator : public BnCarWatchdog, public IBinder::DeathRecipient {
+public:
+    WatchdogBinderMediator() : mWatchdogProcessService(nullptr), mIoPerfCollection(nullptr) {}
+
+    status_t dump(int fd, const Vector<String16>& args) override;
+    binder::Status registerClient(const sp<ICarWatchdogClient>& client,
+                                  TimeoutLength timeout) override {
+        return mWatchdogProcessService->registerClient(client, timeout);
+    }
+    binder::Status unregisterClient(const sp<ICarWatchdogClient>& client) override {
+        return mWatchdogProcessService->unregisterClient(client);
+    }
+    binder::Status registerMediator(const sp<ICarWatchdogClient>& mediator) override;
+    binder::Status unregisterMediator(const sp<ICarWatchdogClient>& mediator) override;
+    binder::Status registerMonitor(const sp<ICarWatchdogMonitor>& monitor) override;
+    binder::Status unregisterMonitor(const sp<ICarWatchdogMonitor>& monitor) override;
+    binder::Status tellClientAlive(const sp<ICarWatchdogClient>& client,
+                                   int32_t sessionId) override {
+        return mWatchdogProcessService->tellClientAlive(client, sessionId);
+    }
+    binder::Status tellMediatorAlive(const sp<ICarWatchdogClient>& mediator,
+                                     const std::vector<int32_t>& clientsNotResponding,
+                                     int32_t sessionId) override {
+        return mWatchdogProcessService->tellMediatorAlive(mediator, clientsNotResponding,
+                                                          sessionId);
+    }
+    binder::Status tellDumpFinished(const android::sp<ICarWatchdogMonitor>& monitor,
+                                    int32_t pid) override {
+        return mWatchdogProcessService->tellDumpFinished(monitor, pid);
+    }
+    binder::Status notifySystemStateChange(StateType type, int32_t arg1, int32_t arg2) override;
+
+protected:
+    android::base::Result<void> init(android::sp<WatchdogProcessService> watchdogProcessService,
+                                     android::sp<IoPerfCollection> ioPerfCollection);
+    void terminate() {
+        mWatchdogProcessService = nullptr;
+        mIoPerfCollection = nullptr;
+    }
+
+private:
+    void binderDied(const android::wp<IBinder>& who) override {
+        return mWatchdogProcessService->binderDied(who);
+    }
+    bool dumpHelpText(int fd, std::string errorMsg);
+
+    android::sp<WatchdogProcessService> mWatchdogProcessService;
+    android::sp<IoPerfCollection> mIoPerfCollection;
+
+    friend class ServiceManager;
+    friend class WatchdogBinderMediatorTest;
+    FRIEND_TEST(WatchdogBinderMediatorTest, TestErrorOnNullptrDuringInit);
+    FRIEND_TEST(WatchdogBinderMediatorTest, TestHandlesEmptyDumpArgs);
+};
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
+
+#endif  // WATCHDOG_SERVER_SRC_WATCHDOGBINDERMEDIATOR_H_
diff --git a/watchdog/server/src/WatchdogProcessService.cpp b/watchdog/server/src/WatchdogProcessService.cpp
new file mode 100644
index 0000000..8d4ec06
--- /dev/null
+++ b/watchdog/server/src/WatchdogProcessService.cpp
@@ -0,0 +1,565 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "carwatchdogd"
+#define DEBUG false  // STOPSHIP if true.
+
+#include "WatchdogProcessService.h"
+
+#include <android-base/chrono_utils.h>
+#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <binder/IPCThreadState.h>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using std::literals::chrono_literals::operator""s;
+using android::base::Error;
+using android::base::GetProperty;
+using android::base::Result;
+using android::base::StringAppendF;
+using android::base::StringPrintf;
+using android::base::WriteStringToFd;
+using android::binder::Status;
+
+namespace {
+
+const std::vector<TimeoutLength> kTimeouts = {TimeoutLength::TIMEOUT_CRITICAL,
+                                              TimeoutLength::TIMEOUT_MODERATE,
+                                              TimeoutLength::TIMEOUT_NORMAL};
+
+std::chrono::nanoseconds timeoutToDurationNs(const TimeoutLength& timeout) {
+    switch (timeout) {
+        case TimeoutLength::TIMEOUT_CRITICAL:
+            return 3s;  // 3s and no buffer time.
+        case TimeoutLength::TIMEOUT_MODERATE:
+            return 6s;  // 5s + 1s as buffer time.
+        case TimeoutLength::TIMEOUT_NORMAL:
+            return 12s;  // 10s + 2s as buffer time.
+    }
+}
+
+std::string pidArrayToString(const std::vector<int32_t>& pids) {
+    size_t size = pids.size();
+    if (size == 0) {
+        return "";
+    }
+    std::string buffer;
+    StringAppendF(&buffer, "%d", pids[0]);
+    for (int i = 1; i < size; i++) {
+        int pid = pids[i];
+        StringAppendF(&buffer, ", %d", pid);
+    }
+    return buffer;
+}
+
+bool isSystemShuttingDown() {
+    std::string sysPowerCtl;
+    std::istringstream tokenStream(GetProperty("sys.powerctl", ""));
+    std::getline(tokenStream, sysPowerCtl, ',');
+    return sysPowerCtl == "reboot" || sysPowerCtl == "shutdown";
+}
+
+}  // namespace
+
+WatchdogProcessService::WatchdogProcessService(const sp<Looper>& handlerLooper) :
+      mHandlerLooper(handlerLooper), mLastSessionId(0) {
+    mMessageHandler = new MessageHandlerImpl(this);
+    mWatchdogEnabled = true;
+    for (const auto& timeout : kTimeouts) {
+        mClients.insert(std::make_pair(timeout, std::vector<ClientInfo>()));
+        mPingedClients.insert(std::make_pair(timeout, PingedClientMap()));
+    }
+}
+
+Status WatchdogProcessService::registerClient(const sp<ICarWatchdogClient>& client,
+                                              TimeoutLength timeout) {
+    Mutex::Autolock lock(mMutex);
+    return registerClientLocked(client, timeout, ClientType::Regular);
+}
+
+Status WatchdogProcessService::unregisterClient(const sp<ICarWatchdogClient>& client) {
+    Mutex::Autolock lock(mMutex);
+    sp<IBinder> binder = BnCarWatchdog::asBinder(client);
+    // kTimeouts is declared as global static constant to cover all kinds of timeout (CRITICAL,
+    // MODERATE, NORMAL).
+    return unregisterClientLocked(kTimeouts, binder, ClientType::Regular);
+}
+
+Status WatchdogProcessService::registerMediator(const sp<ICarWatchdogClient>& mediator) {
+    Mutex::Autolock lock(mMutex);
+    // Mediator's timeout is always TIMEOUT_CRITICAL.
+    return registerClientLocked(mediator, TimeoutLength::TIMEOUT_CRITICAL, ClientType::Mediator);
+}
+
+Status WatchdogProcessService::unregisterMediator(const sp<ICarWatchdogClient>& mediator) {
+    std::vector<TimeoutLength> timeouts = {TimeoutLength::TIMEOUT_CRITICAL};
+    sp<IBinder> binder = BnCarWatchdog::asBinder(mediator);
+    Mutex::Autolock lock(mMutex);
+    return unregisterClientLocked(timeouts, binder, ClientType::Mediator);
+}
+
+Status WatchdogProcessService::registerMonitor(const sp<ICarWatchdogMonitor>& monitor) {
+    Mutex::Autolock lock(mMutex);
+    sp<IBinder> binder = BnCarWatchdog::asBinder(monitor);
+    if (mMonitor != nullptr && binder == BnCarWatchdog::asBinder(mMonitor)) {
+        return Status::ok();
+    }
+    status_t ret = binder->linkToDeath(this);
+    if (ret != OK) {
+        ALOGW("Cannot register the monitor. The monitor is dead.");
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "The monitor is dead.");
+    }
+    mMonitor = monitor;
+    if (DEBUG) {
+        ALOGD("Car watchdog monitor is registered");
+    }
+    return Status::ok();
+}
+
+Status WatchdogProcessService::unregisterMonitor(const sp<ICarWatchdogMonitor>& monitor) {
+    Mutex::Autolock lock(mMutex);
+    if (mMonitor != monitor) {
+        ALOGW("Cannot unregister the monitor. The monitor has not been registered.");
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
+                                         "The monitor has not been registered.");
+    }
+    sp<IBinder> binder = BnCarWatchdog::asBinder(monitor);
+    binder->unlinkToDeath(this);
+    mMonitor = nullptr;
+    if (DEBUG) {
+        ALOGD("Car watchdog monitor is unregistered");
+    }
+    return Status::ok();
+}
+
+Status WatchdogProcessService::tellClientAlive(const sp<ICarWatchdogClient>& client,
+                                               int32_t sessionId) {
+    Mutex::Autolock lock(mMutex);
+    return tellClientAliveLocked(client, sessionId);
+}
+
+Status WatchdogProcessService::tellMediatorAlive(const sp<ICarWatchdogClient>& mediator,
+                                                 const std::vector<int32_t>& clientsNotResponding,
+                                                 int32_t sessionId) {
+    Status status;
+    {
+        Mutex::Autolock lock(mMutex);
+        if (DEBUG) {
+            std::string buffer;
+            int size = clientsNotResponding.size();
+            if (size != 0) {
+                StringAppendF(&buffer, "%d", clientsNotResponding[0]);
+                for (int i = 1; i < clientsNotResponding.size(); i++) {
+                    StringAppendF(&buffer, ", %d", clientsNotResponding[i]);
+                }
+                ALOGD("Mediator(session: %d) responded with non-responding clients: %s", sessionId,
+                      buffer.c_str());
+            }
+        }
+        status = tellClientAliveLocked(mediator, sessionId);
+    }
+    if (status.isOk()) {
+        dumpAndKillAllProcesses(clientsNotResponding);
+    }
+    return status;
+}
+
+Status WatchdogProcessService::tellDumpFinished(const sp<ICarWatchdogMonitor>& monitor,
+                                                int32_t pid) {
+    Mutex::Autolock lock(mMutex);
+    if (mMonitor == nullptr || monitor == nullptr ||
+        BnCarWatchdog::asBinder(monitor) != BnCarWatchdog::asBinder(mMonitor)) {
+        return Status::
+                fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
+                                  "The monitor is not registered or an invalid monitor is given");
+    }
+    ALOGI("Process(pid: %d) has been dumped and killed", pid);
+    return Status::ok();
+}
+
+Status WatchdogProcessService::notifyPowerCycleChange(PowerCycle cycle) {
+    std::string buffer;
+    Mutex::Autolock lock(mMutex);
+    bool oldStatus = mWatchdogEnabled;
+    switch (cycle) {
+        case PowerCycle::POWER_CYCLE_SHUTDOWN:
+            mWatchdogEnabled = false;
+            buffer = "SHUTDOWN power cycle";
+            break;
+        case PowerCycle::POWER_CYCLE_SUSPEND:
+            mWatchdogEnabled = false;
+            buffer = "SUSPEND power cycle";
+            break;
+        case PowerCycle::POWER_CYCLE_RESUME:
+            mWatchdogEnabled = true;
+            for (const auto& timeout : kTimeouts) {
+                startHealthCheckingLocked(timeout);
+            }
+            buffer = "RESUME power cycle";
+            break;
+        default:
+            ALOGW("Unsupported power cycle: %d", cycle);
+            return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
+                                             "Unsupported power cycle");
+    }
+    ALOGI("Received %s", buffer.c_str());
+    if (oldStatus != mWatchdogEnabled) {
+        ALOGI("Car watchdog is %s", mWatchdogEnabled ? "enabled" : "disabled");
+    }
+    return Status::ok();
+}
+
+Status WatchdogProcessService::notifyUserStateChange(userid_t userId, UserState state) {
+    std::string buffer;
+    Mutex::Autolock lock(mMutex);
+    switch (state) {
+        case UserState::USER_STATE_STARTED:
+            mStoppedUserId.erase(userId);
+            buffer = StringPrintf("user(%d) is started", userId);
+            break;
+        case UserState::USER_STATE_STOPPED:
+            mStoppedUserId.insert(userId);
+            buffer = StringPrintf("user(%d) is stopped", userId);
+            break;
+        default:
+            ALOGW("Unsupported user state: %d", state);
+            return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Unsupported user state");
+    }
+    ALOGI("Received user state change: %s", buffer.c_str());
+    return Status::ok();
+}
+
+Result<void> WatchdogProcessService::dump(int fd, const Vector<String16>& /*args*/) {
+    Mutex::Autolock lock(mMutex);
+    const char* indent = "  ";
+    const char* doubleIndent = "    ";
+    std::string buffer;
+    WriteStringToFd("CAR WATCHDOG PROCESS SERVICE\n", fd);
+    WriteStringToFd(StringPrintf("%sWatchdog enabled: %s\n", indent,
+                                 mWatchdogEnabled ? "true" : "false"),
+                    fd);
+    WriteStringToFd(StringPrintf("%sRegistered clients\n", indent), fd);
+    int count = 1;
+    for (const auto& timeout : kTimeouts) {
+        std::vector<ClientInfo>& clients = mClients[timeout];
+        for (auto it = clients.begin(); it != clients.end(); it++, count++) {
+            WriteStringToFd(StringPrintf("%sClient #%d: %s\n", doubleIndent, count,
+                                         it->toString().c_str()),
+                            fd);
+        }
+    }
+    WriteStringToFd(StringPrintf("%sMonitor registered: %s\n", indent,
+                                 mMonitor == nullptr ? "false" : "true"),
+                    fd);
+    WriteStringToFd(StringPrintf("%sisSystemShuttingDown: %s\n", indent,
+                                 isSystemShuttingDown() ? "true" : "false"),
+                    fd);
+    buffer = "none";
+    bool first = true;
+    for (const auto& userId : mStoppedUserId) {
+        if (first) {
+            buffer = StringPrintf("%d", userId);
+            first = false;
+        } else {
+            StringAppendF(&buffer, ", %d", userId);
+        }
+    }
+    WriteStringToFd(StringPrintf("%sStopped users: %s\n", indent, buffer.c_str()), fd);
+    return {};
+}
+
+void WatchdogProcessService::doHealthCheck(int what) {
+    mHandlerLooper->removeMessages(mMessageHandler, what);
+    if (!isWatchdogEnabled()) {
+        return;
+    }
+    const TimeoutLength timeout = static_cast<TimeoutLength>(what);
+    dumpAndKillClientsIfNotResponding(timeout);
+
+    /* Generates a temporary/local vector containing clients.
+     * Using a local copy may send unnecessary ping messages to clients after they are unregistered.
+     * Clients should be able to handle them.
+     */
+    std::vector<ClientInfo> clientsToCheck;
+    PingedClientMap& pingedClients = mPingedClients[timeout];
+    {
+        Mutex::Autolock lock(mMutex);
+        pingedClients.clear();
+        clientsToCheck = mClients[timeout];
+        for (auto& clientInfo : clientsToCheck) {
+            if (mStoppedUserId.count(clientInfo.userId) > 0) {
+                continue;
+            }
+            int sessionId = getNewSessionId();
+            clientInfo.sessionId = sessionId;
+            pingedClients.insert(std::make_pair(sessionId, clientInfo));
+        }
+    }
+
+    for (const auto& clientInfo : clientsToCheck) {
+        Status status = clientInfo.client->checkIfAlive(clientInfo.sessionId, timeout);
+        if (!status.isOk()) {
+            ALOGW("Sending a ping message to client(pid: %d) failed: %s", clientInfo.pid,
+                  status.exceptionMessage().c_str());
+            {
+                Mutex::Autolock lock(mMutex);
+                pingedClients.erase(clientInfo.sessionId);
+            }
+        }
+    }
+    // Though the size of pingedClients is a more specific measure, clientsToCheck is used as a
+    // conservative approach.
+    if (clientsToCheck.size() > 0) {
+        auto durationNs = timeoutToDurationNs(timeout);
+        mHandlerLooper->sendMessageDelayed(durationNs.count(), mMessageHandler, Message(what));
+    }
+}
+
+void WatchdogProcessService::terminate() {
+    Mutex::Autolock lock(mMutex);
+    for (const auto& timeout : kTimeouts) {
+        std::vector<ClientInfo>& clients = mClients[timeout];
+        for (auto it = clients.begin(); it != clients.end();) {
+            sp<IBinder> binder = BnCarWatchdog::asBinder((*it).client);
+            binder->unlinkToDeath(this);
+            it = clients.erase(it);
+        }
+    }
+}
+
+void WatchdogProcessService::binderDied(const wp<IBinder>& who) {
+    Mutex::Autolock lock(mMutex);
+    IBinder* binder = who.unsafe_get();
+    // Check if dead binder is monitor.
+    sp<IBinder> monitor = BnCarWatchdog::asBinder(mMonitor);
+    if (monitor == binder) {
+        mMonitor = nullptr;
+        ALOGW("The monitor has died.");
+        return;
+    }
+    findClientAndProcessLocked(kTimeouts, binder,
+                               [&](std::vector<ClientInfo>& clients,
+                                   std::vector<ClientInfo>::const_iterator it) {
+                                   ALOGW("Client(pid: %d) died", it->pid);
+                                   clients.erase(it);
+                               });
+}
+
+bool WatchdogProcessService::isRegisteredLocked(const sp<ICarWatchdogClient>& client) {
+    sp<IBinder> binder = BnCarWatchdog::asBinder(client);
+    return findClientAndProcessLocked(kTimeouts, binder, nullptr);
+}
+
+Status WatchdogProcessService::registerClientLocked(const sp<ICarWatchdogClient>& client,
+                                                    TimeoutLength timeout, ClientType clientType) {
+    const char* clientName = clientType == ClientType::Regular ? "client" : "mediator";
+    if (isRegisteredLocked(client)) {
+        ALOGW("Cannot register the %s: the %s is already registered.", clientName, clientName);
+        return Status::ok();
+    }
+    sp<IBinder> binder = BnCarWatchdog::asBinder(client);
+    status_t status = binder->linkToDeath(this);
+    if (status != OK) {
+        std::string errorStr = StringPrintf("The %s is dead", clientName);
+        const char* errorCause = errorStr.c_str();
+        ALOGW("Cannot register the %s: %s", clientName, errorCause);
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, errorCause);
+    }
+    std::vector<ClientInfo>& clients = mClients[timeout];
+    pid_t callingPid = IPCThreadState::self()->getCallingPid();
+    uid_t callingUid = IPCThreadState::self()->getCallingUid();
+    clients.push_back(ClientInfo(client, callingPid, callingUid, clientType));
+
+    // If the client array becomes non-empty, start health checking.
+    if (clients.size() == 1) {
+        startHealthCheckingLocked(timeout);
+    }
+    if (DEBUG) {
+        ALOGD("Car watchdog %s(pid: %d, timeout: %d) is registered", clientName, callingPid,
+              timeout);
+    }
+    return Status::ok();
+}
+
+Status WatchdogProcessService::unregisterClientLocked(const std::vector<TimeoutLength>& timeouts,
+                                                      sp<IBinder> binder, ClientType clientType) {
+    const char* clientName = clientType == ClientType::Regular ? "client" : "mediator";
+    bool result = findClientAndProcessLocked(timeouts, binder,
+                                             [&](std::vector<ClientInfo>& clients,
+                                                 std::vector<ClientInfo>::const_iterator it) {
+                                                 binder->unlinkToDeath(this);
+                                                 clients.erase(it);
+                                             });
+    if (!result) {
+        std::string errorStr = StringPrintf("The %s has not been registered", clientName);
+        const char* errorCause = errorStr.c_str();
+        ALOGW("Cannot unregister the %s: %s", clientName, errorCause);
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, errorCause);
+    }
+    if (DEBUG) {
+        ALOGD("Car watchdog %s is unregistered", clientName);
+    }
+    return Status::ok();
+}
+
+Status WatchdogProcessService::tellClientAliveLocked(const sp<ICarWatchdogClient>& client,
+                                                     int32_t sessionId) {
+    const sp<IBinder> binder = BnCarWatchdog::asBinder(client);
+    for (const auto& timeout : kTimeouts) {
+        PingedClientMap& clients = mPingedClients[timeout];
+        PingedClientMap::const_iterator it = clients.find(sessionId);
+        if (it == clients.cend() || binder != BnCarWatchdog::asBinder(it->second.client)) {
+            continue;
+        }
+        clients.erase(it);
+        return Status::ok();
+    }
+    return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
+                                     "The client is not registered or the session ID is not found");
+}
+
+bool WatchdogProcessService::findClientAndProcessLocked(const std::vector<TimeoutLength> timeouts,
+                                                        const sp<IBinder> binder,
+                                                        const Processor& processor) {
+    for (const auto& timeout : timeouts) {
+        std::vector<ClientInfo>& clients = mClients[timeout];
+        for (auto it = clients.begin(); it != clients.end(); it++) {
+            if (BnCarWatchdog::asBinder((*it).client) != binder) {
+                continue;
+            }
+            if (processor != nullptr) {
+                processor(clients, it);
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+Result<void> WatchdogProcessService::startHealthCheckingLocked(TimeoutLength timeout) {
+    PingedClientMap& clients = mPingedClients[timeout];
+    clients.clear();
+    int what = static_cast<int>(timeout);
+    auto durationNs = timeoutToDurationNs(timeout);
+    mHandlerLooper->sendMessageDelayed(durationNs.count(), mMessageHandler, Message(what));
+    return {};
+}
+
+Result<void> WatchdogProcessService::dumpAndKillClientsIfNotResponding(TimeoutLength timeout) {
+    std::vector<int32_t> processIds;
+    std::vector<sp<ICarWatchdogClient>> clientsToNotify;
+    {
+        Mutex::Autolock lock(mMutex);
+        PingedClientMap& clients = mPingedClients[timeout];
+        for (PingedClientMap::const_iterator it = clients.cbegin(); it != clients.cend(); it++) {
+            pid_t pid = -1;
+            userid_t userId = -1;
+            sp<ICarWatchdogClient> client = it->second.client;
+            sp<IBinder> binder = BnCarWatchdog::asBinder(client);
+            std::vector<TimeoutLength> timeouts = {timeout};
+            findClientAndProcessLocked(timeouts, binder,
+                                       [&](std::vector<ClientInfo>& clients,
+                                           std::vector<ClientInfo>::const_iterator it) {
+                                           pid = (*it).pid;
+                                           userId = (*it).userId;
+                                           clients.erase(it);
+                                       });
+            if (pid != -1 && mStoppedUserId.count(userId) == 0) {
+                clientsToNotify.push_back(client);
+                processIds.push_back(pid);
+            }
+        }
+    }
+    for (auto&& client : clientsToNotify) {
+        client->prepareProcessTermination();
+    }
+    return dumpAndKillAllProcesses(processIds);
+}
+
+Result<void> WatchdogProcessService::dumpAndKillAllProcesses(
+        const std::vector<int32_t>& processesNotResponding) {
+    size_t size = processesNotResponding.size();
+    if (size == 0) {
+        return {};
+    }
+    std::string pidString = pidArrayToString(processesNotResponding);
+    sp<ICarWatchdogMonitor> monitor;
+    {
+        Mutex::Autolock lock(mMutex);
+        if (mMonitor == nullptr) {
+            std::string errorMsg =
+                    StringPrintf("Cannot dump and kill processes(pid = %s): Monitor is not set",
+                                 pidString.c_str());
+            ALOGW("%s", errorMsg.c_str());
+            return Error() << errorMsg;
+        }
+        monitor = mMonitor;
+    }
+    if (isSystemShuttingDown()) {
+        ALOGI("Skip dumping and killing processes(%s): The system is shutting down",
+              pidString.c_str());
+        return {};
+    }
+    monitor->onClientsNotResponding(processesNotResponding);
+    if (DEBUG) {
+        ALOGD("Dumping and killing processes is requested: %s", pidString.c_str());
+    }
+    return {};
+}
+
+int32_t WatchdogProcessService::getNewSessionId() {
+    // Make sure that session id is always positive number.
+    if (++mLastSessionId <= 0) {
+        mLastSessionId = 1;
+    }
+    return mLastSessionId;
+}
+
+bool WatchdogProcessService::isWatchdogEnabled() {
+    Mutex::Autolock lock(mMutex);
+    return mWatchdogEnabled;
+}
+
+std::string WatchdogProcessService::ClientInfo::toString() {
+    std::string buffer;
+    StringAppendF(&buffer, "pid = %d, userId = %d, type = %s", pid, userId,
+                  type == Regular ? "Regular" : "Mediator");
+    return buffer;
+}
+
+WatchdogProcessService::MessageHandlerImpl::MessageHandlerImpl(
+        const sp<WatchdogProcessService>& service) :
+      mService(service) {}
+
+void WatchdogProcessService::MessageHandlerImpl::handleMessage(const Message& message) {
+    switch (message.what) {
+        case static_cast<int>(TimeoutLength::TIMEOUT_CRITICAL):
+        case static_cast<int>(TimeoutLength::TIMEOUT_MODERATE):
+        case static_cast<int>(TimeoutLength::TIMEOUT_NORMAL):
+            mService->doHealthCheck(message.what);
+            break;
+        default:
+            ALOGW("Unknown message: %d", message.what);
+    }
+}
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/watchdog/server/src/WatchdogProcessService.h b/watchdog/server/src/WatchdogProcessService.h
new file mode 100644
index 0000000..322b343
--- /dev/null
+++ b/watchdog/server/src/WatchdogProcessService.h
@@ -0,0 +1,137 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WATCHDOG_SERVER_SRC_WATCHDOGPROCESSSERVICE_H_
+#define WATCHDOG_SERVER_SRC_WATCHDOGPROCESSSERVICE_H_
+
+#include <android-base/result.h>
+#include <android/automotive/watchdog/BnCarWatchdog.h>
+#include <android/automotive/watchdog/PowerCycle.h>
+#include <android/automotive/watchdog/UserState.h>
+#include <binder/IBinder.h>
+#include <binder/Status.h>
+#include <cutils/multiuser.h>
+#include <utils/Looper.h>
+#include <utils/Mutex.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+#include <utils/Vector.h>
+
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+class WatchdogProcessService : public IBinder::DeathRecipient {
+public:
+    explicit WatchdogProcessService(const android::sp<Looper>& handlerLooper);
+
+    virtual android::base::Result<void> dump(int fd, const Vector<String16>& args);
+
+    virtual binder::Status registerClient(const sp<ICarWatchdogClient>& client,
+                                          TimeoutLength timeout);
+    virtual binder::Status unregisterClient(const sp<ICarWatchdogClient>& client);
+    virtual binder::Status registerMediator(const sp<ICarWatchdogClient>& mediator);
+    virtual binder::Status unregisterMediator(const sp<ICarWatchdogClient>& mediator);
+    virtual binder::Status registerMonitor(const sp<ICarWatchdogMonitor>& monitor);
+    virtual binder::Status unregisterMonitor(const sp<ICarWatchdogMonitor>& monitor);
+    virtual binder::Status tellClientAlive(const sp<ICarWatchdogClient>& client, int32_t sessionId);
+    virtual binder::Status tellMediatorAlive(const sp<ICarWatchdogClient>& mediator,
+                                             const std::vector<int32_t>& clientsNotResponding,
+                                             int32_t sessionId);
+    virtual binder::Status tellDumpFinished(const android::sp<ICarWatchdogMonitor>& monitor,
+                                            int32_t pid);
+    virtual binder::Status notifyPowerCycleChange(PowerCycle cycle);
+    virtual binder::Status notifyUserStateChange(userid_t userId, UserState state);
+    virtual void binderDied(const android::wp<IBinder>& who);
+
+    void doHealthCheck(int what);
+    void terminate();
+
+private:
+    enum ClientType {
+        Regular,
+        Mediator,
+    };
+
+    struct ClientInfo {
+        ClientInfo(const android::sp<ICarWatchdogClient>& client, pid_t pid, userid_t userId,
+                   ClientType type) :
+              client(client),
+              pid(pid),
+              userId(userId),
+              type(type) {}
+        std::string toString();
+
+        android::sp<ICarWatchdogClient> client;
+        pid_t pid;
+        userid_t userId;
+        int sessionId;
+        ClientType type;
+    };
+
+    typedef std::unordered_map<int, ClientInfo> PingedClientMap;
+
+    class MessageHandlerImpl : public MessageHandler {
+    public:
+        explicit MessageHandlerImpl(const android::sp<WatchdogProcessService>& service);
+
+        void handleMessage(const Message& message) override;
+
+    private:
+        android::sp<WatchdogProcessService> mService;
+    };
+
+private:
+    binder::Status registerClientLocked(const android::sp<ICarWatchdogClient>& client,
+                                        TimeoutLength timeout, ClientType clientType);
+    binder::Status unregisterClientLocked(const std::vector<TimeoutLength>& timeouts,
+                                          android::sp<IBinder> binder, ClientType clientType);
+    bool isRegisteredLocked(const android::sp<ICarWatchdogClient>& client);
+    binder::Status tellClientAliveLocked(const android::sp<ICarWatchdogClient>& client,
+                                         int32_t sessionId);
+    base::Result<void> startHealthCheckingLocked(TimeoutLength timeout);
+    base::Result<void> dumpAndKillClientsIfNotResponding(TimeoutLength timeout);
+    base::Result<void> dumpAndKillAllProcesses(const std::vector<int32_t>& processesNotResponding);
+    int32_t getNewSessionId();
+    bool isWatchdogEnabled();
+
+    using Processor =
+            std::function<void(std::vector<ClientInfo>&, std::vector<ClientInfo>::const_iterator)>;
+    bool findClientAndProcessLocked(const std::vector<TimeoutLength> timeouts,
+                                    const android::sp<IBinder> binder, const Processor& processor);
+
+private:
+    sp<Looper> mHandlerLooper;
+    android::sp<MessageHandlerImpl> mMessageHandler;
+    Mutex mMutex;
+    std::unordered_map<TimeoutLength, std::vector<ClientInfo>> mClients GUARDED_BY(mMutex);
+    std::unordered_map<TimeoutLength, PingedClientMap> mPingedClients GUARDED_BY(mMutex);
+    std::unordered_set<userid_t> mStoppedUserId GUARDED_BY(mMutex);
+    android::sp<ICarWatchdogMonitor> mMonitor GUARDED_BY(mMutex);
+    bool mWatchdogEnabled GUARDED_BY(mMutex);
+    // mLastSessionId is accessed only within main thread. No need for mutual-exclusion.
+    int32_t mLastSessionId;
+};
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
+
+#endif  // WATCHDOG_SERVER_SRC_WATCHDOGPROCESSSERVICE_H_
diff --git a/watchdog/server/src/main.cpp b/watchdog/server/src/main.cpp
new file mode 100644
index 0000000..1443b51
--- /dev/null
+++ b/watchdog/server/src/main.cpp
@@ -0,0 +1,105 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "carwatchdogd"
+
+#include "ServiceManager.h"
+
+#include <android-base/chrono_utils.h>
+#include <android-base/properties.h>
+#include <android-base/result.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <log/log.h>
+#include <signal.h>
+#include <utils/Looper.h>
+
+#include <thread>
+
+using android::IPCThreadState;
+using android::Looper;
+using android::ProcessState;
+using android::sp;
+using android::automotive::watchdog::ServiceManager;
+using android::base::Result;
+
+namespace {
+
+const size_t kMaxBinderThreadCount = 16;
+
+void sigHandler(int sig) {
+    IPCThreadState::self()->stopProcess();
+    ServiceManager::terminateServices();
+    ALOGW("car watchdog server terminated on receiving signal %d.", sig);
+    exit(1);
+}
+
+void registerSigHandler() {
+    struct sigaction sa;
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = sigHandler;
+    sigaction(SIGQUIT, &sa, nullptr);
+    sigaction(SIGTERM, &sa, nullptr);
+}
+
+}  // namespace
+
+int main(int /*argc*/, char** /*argv*/) {
+    // Set up the looper
+    sp<Looper> looper(Looper::prepare(/*opts=*/0));
+
+    // Start the services
+    auto result = ServiceManager::startServices(looper);
+    if (!result) {
+        ALOGE("Failed to start services: %s", result.error().message().c_str());
+        ServiceManager::terminateServices();
+        exit(result.error().code());
+    }
+
+    registerSigHandler();
+
+    // Wait for the service manager before starting binder mediator.
+    while (android::base::GetProperty("init.svc.servicemanager", "") != "running") {
+        // Poll frequent enough so the CarWatchdogDaemonHelper can connect to the daemon during
+        // system boot up.
+        std::this_thread::sleep_for(250ms);
+    }
+
+    // Set up the binder
+    sp<ProcessState> ps(ProcessState::self());
+    ps->setThreadPoolMaxThreadCount(kMaxBinderThreadCount);
+    ps->startThreadPool();
+    ps->giveThreadPoolName();
+    IPCThreadState::self()->disableBackgroundScheduling(true);
+
+    result = ServiceManager::startBinderMediator();
+    if (!result) {
+        ALOGE("Failed to start binder mediator: %s", result.error().message().c_str());
+        ServiceManager::terminateServices();
+        exit(result.error().code());
+    }
+
+    // Loop forever -- the health check runs on this thread in a handler, and the binder calls
+    // remain responsive in their pool of threads.
+    while (true) {
+        looper->pollAll(/*timeoutMillis=*/-1);
+    }
+    ALOGW("Car watchdog server escaped from its loop.");
+
+    return 0;
+}
diff --git a/watchdog/server/sysprop/Android.bp b/watchdog/server/sysprop/Android.bp
new file mode 100644
index 0000000..a3c507a
--- /dev/null
+++ b/watchdog/server/sysprop/Android.bp
@@ -0,0 +1,21 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+sysprop_library {
+  name: "libwatchdog_properties",
+  srcs: ["*.sysprop"],
+  property_owner: "Platform",
+  api_packages: ["android.sysprop"],
+  recovery_available: true,
+}
diff --git a/watchdog/server/sysprop/WatchdogProperties.sysprop b/watchdog/server/sysprop/WatchdogProperties.sysprop
new file mode 100644
index 0000000..740fe01
--- /dev/null
+++ b/watchdog/server/sysprop/WatchdogProperties.sysprop
@@ -0,0 +1,61 @@
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the License);
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an AS IS BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module: "android.automotive.watchdog.sysprop"
+owner: Platform
+
+# Interval in seconds between consecutive boot-time performance data collections.
+prop {
+    api_name: "boottimeCollectionInterval"
+    type: Integer
+    scope: Internal
+    access: Readonly
+    prop_name: "ro.carwatchdog.boottime_collection_interval"
+}
+
+# Maximum number of periodically collected records to be cached in memory.
+prop {
+    api_name: "periodicCollectionBufferSize"
+    type: Integer
+    scope: Internal
+    access: Readonly
+    prop_name: "ro.carwatchdog.periodic_collection_buffer_size"
+}
+
+# Interval in seconds between consecutive periodic performance data collections.
+prop {
+    api_name: "periodicCollectionInterval"
+    type: Integer
+    scope: Internal
+    access: Readonly
+    prop_name: "ro.carwatchdog.periodic_collection_interval"
+}
+
+# Top N per-UID statistics/category collected by the performance data collector.
+prop {
+    api_name: "topNStatsPerCategory"
+    type: Integer
+    scope: Internal
+    access: Readonly
+    prop_name: "ro.carwatchdog.top_n_stats_per_category"
+}
+
+# Top N per-process statistics/category collected by the performance data collector.
+prop {
+    api_name: "topNStatsPerSubcategory"
+    type: Integer
+    scope: Internal
+    access: Readonly
+    prop_name: "ro.carwatchdog.top_n_stats_per_subcategory"
+}
diff --git a/watchdog/server/sysprop/api/libwatchdog_properties-current.txt b/watchdog/server/sysprop/api/libwatchdog_properties-current.txt
new file mode 100644
index 0000000..ab59538
--- /dev/null
+++ b/watchdog/server/sysprop/api/libwatchdog_properties-current.txt
@@ -0,0 +1,33 @@
+props {
+  module: "android.automotive.watchdog.sysprop"
+  prop {
+    api_name: "boottimeCollectionInterval"
+    type: Integer
+    scope: Internal
+    prop_name: "ro.carwatchdog.boottime_collection_interval"
+  }
+  prop {
+    api_name: "periodicCollectionBufferSize"
+    type: Integer
+    scope: Internal
+    prop_name: "ro.carwatchdog.periodic_collection_buffer_size"
+  }
+  prop {
+    api_name: "periodicCollectionInterval"
+    type: Integer
+    scope: Internal
+    prop_name: "ro.carwatchdog.periodic_collection_interval"
+  }
+  prop {
+    api_name: "topNStatsPerCategory"
+    type: Integer
+    scope: Internal
+    prop_name: "ro.carwatchdog.top_n_stats_per_category"
+  }
+  prop {
+    api_name: "topNStatsPerSubcategory"
+    type: Integer
+    scope: Internal
+    prop_name: "ro.carwatchdog.top_n_stats_per_subcategory"
+  }
+}
diff --git a/watchdog/server/sysprop/api/libwatchdog_properties-latest.txt b/watchdog/server/sysprop/api/libwatchdog_properties-latest.txt
new file mode 100644
index 0000000..ab59538
--- /dev/null
+++ b/watchdog/server/sysprop/api/libwatchdog_properties-latest.txt
@@ -0,0 +1,33 @@
+props {
+  module: "android.automotive.watchdog.sysprop"
+  prop {
+    api_name: "boottimeCollectionInterval"
+    type: Integer
+    scope: Internal
+    prop_name: "ro.carwatchdog.boottime_collection_interval"
+  }
+  prop {
+    api_name: "periodicCollectionBufferSize"
+    type: Integer
+    scope: Internal
+    prop_name: "ro.carwatchdog.periodic_collection_buffer_size"
+  }
+  prop {
+    api_name: "periodicCollectionInterval"
+    type: Integer
+    scope: Internal
+    prop_name: "ro.carwatchdog.periodic_collection_interval"
+  }
+  prop {
+    api_name: "topNStatsPerCategory"
+    type: Integer
+    scope: Internal
+    prop_name: "ro.carwatchdog.top_n_stats_per_category"
+  }
+  prop {
+    api_name: "topNStatsPerSubcategory"
+    type: Integer
+    scope: Internal
+    prop_name: "ro.carwatchdog.top_n_stats_per_subcategory"
+  }
+}
diff --git a/watchdog/server/tests/IoPerfCollectionTest.cpp b/watchdog/server/tests/IoPerfCollectionTest.cpp
new file mode 100644
index 0000000..82287bf
--- /dev/null
+++ b/watchdog/server/tests/IoPerfCollectionTest.cpp
@@ -0,0 +1,1524 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "IoPerfCollection.h"
+
+#include <WatchdogProperties.sysprop.h>
+#include <android-base/file.h>
+#include <cutils/android_filesystem_config.h>
+
+#include <algorithm>
+#include <future>
+#include <queue>
+#include <string>
+#include <vector>
+
+#include "LooperStub.h"
+#include "ProcPidDir.h"
+#include "ProcPidStat.h"
+#include "ProcStat.h"
+#include "UidIoStats.h"
+#include "gmock/gmock.h"
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using android::base::Error;
+using android::base::Result;
+using android::base::WriteStringToFile;
+using testing::LooperStub;
+using testing::populateProcPidDir;
+
+namespace {
+
+const std::chrono::seconds kTestBootInterval = 1s;
+const std::chrono::seconds kTestPeriodicInterval = 2s;
+const std::chrono::seconds kTestCustomInterval = 3s;
+const std::chrono::seconds kTestCustomCollectionDuration = 11s;
+
+class UidIoStatsStub : public UidIoStats {
+public:
+    explicit UidIoStatsStub(bool enabled = false) : mEnabled(enabled) {}
+    Result<std::unordered_map<uint32_t, UidIoUsage>> collect() override {
+        if (mCache.empty()) {
+            return Error() << "Cache is empty";
+        }
+        const auto entry = mCache.front();
+        mCache.pop();
+        return entry;
+    }
+    bool enabled() override { return mEnabled; }
+    std::string filePath() override { return kUidIoStatsPath; }
+    void push(const std::unordered_map<uint32_t, UidIoUsage>& entry) { mCache.push(entry); }
+
+private:
+    bool mEnabled;
+    std::queue<std::unordered_map<uint32_t, UidIoUsage>> mCache;
+};
+
+class ProcStatStub : public ProcStat {
+public:
+    explicit ProcStatStub(bool enabled = false) : mEnabled(enabled) {}
+    Result<ProcStatInfo> collect() override {
+        if (mCache.empty()) {
+            return Error() << "Cache is empty";
+        }
+        const auto entry = mCache.front();
+        mCache.pop();
+        return entry;
+    }
+    bool enabled() override { return mEnabled; }
+    std::string filePath() override { return kProcStatPath; }
+    void push(const ProcStatInfo& entry) { mCache.push(entry); }
+
+private:
+    bool mEnabled;
+    std::queue<ProcStatInfo> mCache;
+};
+
+class ProcPidStatStub : public ProcPidStat {
+public:
+    explicit ProcPidStatStub(bool enabled = false) : mEnabled(enabled) {}
+    Result<std::vector<ProcessStats>> collect() override {
+        if (mCache.empty()) {
+            return Error() << "Cache is empty";
+        }
+        const auto entry = mCache.front();
+        mCache.pop();
+        return entry;
+    }
+    bool enabled() override { return mEnabled; }
+    std::string dirPath() override { return kProcDirPath; }
+    void push(const std::vector<ProcessStats>& entry) { mCache.push(entry); }
+
+private:
+    bool mEnabled;
+    std::queue<std::vector<ProcessStats>> mCache;
+};
+
+bool isEqual(const UidIoPerfData& lhs, const UidIoPerfData& rhs) {
+    if (lhs.topNReads.size() != rhs.topNReads.size() ||
+        lhs.topNWrites.size() != rhs.topNWrites.size()) {
+        return false;
+    }
+    for (int i = 0; i < METRIC_TYPES; ++i) {
+        for (int j = 0; j < UID_STATES; ++j) {
+            if (lhs.total[i][j] != rhs.total[i][j]) {
+                return false;
+            }
+        }
+    }
+    auto comp = [&](const UidIoPerfData::Stats& l, const UidIoPerfData::Stats& r) -> bool {
+        bool isEqual = l.userId == r.userId && l.packageName == r.packageName;
+        for (int i = 0; i < UID_STATES; ++i) {
+            isEqual &= l.bytes[i] == r.bytes[i] && l.fsync[i] == r.fsync[i];
+        }
+        return isEqual;
+    };
+    return lhs.topNReads.size() == rhs.topNReads.size() &&
+            std::equal(lhs.topNReads.begin(), lhs.topNReads.end(), rhs.topNReads.begin(), comp) &&
+            lhs.topNWrites.size() == rhs.topNWrites.size() &&
+            std::equal(lhs.topNWrites.begin(), lhs.topNWrites.end(), rhs.topNWrites.begin(), comp);
+}
+
+bool isEqual(const SystemIoPerfData& lhs, const SystemIoPerfData& rhs) {
+    return lhs.cpuIoWaitTime == rhs.cpuIoWaitTime && lhs.totalCpuTime == rhs.totalCpuTime &&
+            lhs.ioBlockedProcessesCnt == rhs.ioBlockedProcessesCnt &&
+            lhs.totalProcessesCnt == rhs.totalProcessesCnt;
+}
+
+bool isEqual(const ProcessIoPerfData& lhs, const ProcessIoPerfData& rhs) {
+    if (lhs.topNIoBlockedUids.size() != rhs.topNIoBlockedUids.size() ||
+        lhs.topNMajorFaultUids.size() != rhs.topNMajorFaultUids.size() ||
+        lhs.totalMajorFaults != rhs.totalMajorFaults ||
+        lhs.majorFaultsPercentChange != rhs.majorFaultsPercentChange) {
+        return false;
+    }
+    auto comp = [&](const ProcessIoPerfData::UidStats& l,
+                    const ProcessIoPerfData::UidStats& r) -> bool {
+        auto comp = [&](const ProcessIoPerfData::UidStats::ProcessStats& l,
+                        const ProcessIoPerfData::UidStats::ProcessStats& r) -> bool {
+            return l.comm == r.comm && l.count == r.count;
+        };
+        return l.userId == r.userId && l.packageName == r.packageName && l.count == r.count &&
+                l.topNProcesses.size() == r.topNProcesses.size() &&
+                std::equal(l.topNProcesses.begin(), l.topNProcesses.end(), r.topNProcesses.begin(),
+                           comp);
+    };
+    return lhs.topNIoBlockedUids.size() == lhs.topNIoBlockedUids.size() &&
+            std::equal(lhs.topNIoBlockedUids.begin(), lhs.topNIoBlockedUids.end(),
+                       rhs.topNIoBlockedUids.begin(), comp) &&
+            lhs.topNIoBlockedUidsTotalTaskCnt.size() == rhs.topNIoBlockedUidsTotalTaskCnt.size() &&
+            std::equal(lhs.topNIoBlockedUidsTotalTaskCnt.begin(),
+                       lhs.topNIoBlockedUidsTotalTaskCnt.end(),
+                       rhs.topNIoBlockedUidsTotalTaskCnt.begin()) &&
+            lhs.topNMajorFaultUids.size() == rhs.topNMajorFaultUids.size() &&
+            std::equal(lhs.topNMajorFaultUids.begin(), lhs.topNMajorFaultUids.end(),
+                       rhs.topNMajorFaultUids.begin(), comp);
+}
+
+bool isEqual(const IoPerfRecord& lhs, const IoPerfRecord& rhs) {
+    return isEqual(lhs.uidIoPerfData, rhs.uidIoPerfData) &&
+            isEqual(lhs.systemIoPerfData, rhs.systemIoPerfData) &&
+            isEqual(lhs.processIoPerfData, rhs.processIoPerfData);
+}
+
+}  // namespace
+
+TEST(IoPerfCollectionTest, TestCollectionStartAndTerminate) {
+    sp<IoPerfCollection> collector = new IoPerfCollection();
+    const auto& ret = collector->start();
+    ASSERT_TRUE(ret) << ret.error().message();
+    ASSERT_TRUE(collector->mCollectionThread.joinable()) << "Collection thread not created";
+    ASSERT_FALSE(collector->start())
+            << "No error returned when collector was started more than once";
+    ASSERT_TRUE(sysprop::topNStatsPerCategory().has_value());
+    ASSERT_EQ(collector->mTopNStatsPerCategory, sysprop::topNStatsPerCategory().value());
+
+    ASSERT_TRUE(sysprop::topNStatsPerSubcategory().has_value());
+    ASSERT_EQ(collector->mTopNStatsPerSubcategory, sysprop::topNStatsPerSubcategory().value());
+
+    ASSERT_TRUE(sysprop::boottimeCollectionInterval().has_value());
+    ASSERT_EQ(std::chrono::duration_cast<std::chrono::seconds>(
+                      collector->mBoottimeCollection.interval)
+                      .count(),
+              sysprop::boottimeCollectionInterval().value());
+
+    ASSERT_TRUE(sysprop::topNStatsPerCategory().has_value());
+    ASSERT_EQ(std::chrono::duration_cast<std::chrono::seconds>(
+                      collector->mPeriodicCollection.interval)
+                      .count(),
+              sysprop::periodicCollectionInterval().value());
+
+    ASSERT_TRUE(sysprop::periodicCollectionBufferSize().has_value());
+    ASSERT_EQ(collector->mPeriodicCollection.maxCacheSize,
+              sysprop::periodicCollectionBufferSize().value());
+
+    collector->terminate();
+    ASSERT_FALSE(collector->mCollectionThread.joinable()) << "Collection thread did not terminate";
+}
+
+TEST(IoPerfCollectionTest, TestValidCollectionSequence) {
+    sp<UidIoStatsStub> uidIoStatsStub = new UidIoStatsStub(true);
+    sp<ProcStatStub> procStatStub = new ProcStatStub(true);
+    sp<ProcPidStatStub> procPidStatStub = new ProcPidStatStub(true);
+    sp<LooperStub> looperStub = new LooperStub();
+
+    sp<IoPerfCollection> collector = new IoPerfCollection();
+    collector->mUidIoStats = uidIoStatsStub;
+    collector->mProcStat = procStatStub;
+    collector->mProcPidStat = procPidStatStub;
+    collector->mHandlerLooper = looperStub;
+
+    auto ret = collector->start();
+    ASSERT_TRUE(ret) << ret.error().message();
+
+    collector->mBoottimeCollection.interval = kTestBootInterval;
+    collector->mPeriodicCollection.interval = kTestPeriodicInterval;
+    collector->mPeriodicCollection.maxCacheSize = 1;
+
+    // #1 Boot-time collection
+    uidIoStatsStub->push({{1009, {.uid = 1009, .ios = {0, 20000, 0, 30000, 0, 300}}}});
+    procStatStub->push(ProcStatInfo{
+            /*stats=*/{6200, 5700, 1700, 3100, /*ioWaitTime=*/1100, 5200, 3900, 0, 0, 0},
+            /*runnableCnt=*/17,
+            /*ioBlockedCnt=*/5,
+    });
+    procPidStatStub->push({{.tgid = 100,
+                            .uid = 1009,
+                            .process = {.pid = 100,
+                                        .comm = "disk I/O",
+                                        .state = "D",
+                                        .ppid = 1,
+                                        .majorFaults = 5000,
+                                        .numThreads = 1,
+                                        .startTime = 234},
+                            .threads = {{100,
+                                         {.pid = 100,
+                                          .comm = "disk I/O",
+                                          .state = "D",
+                                          .ppid = 1,
+                                          .majorFaults = 5000,
+                                          .numThreads = 1,
+                                          .startTime = 234}}}}});
+    IoPerfRecord bootExpectedFirst = {
+            .uidIoPerfData = {.topNReads = {{.userId = 0,
+                                             .packageName = "mount",
+                                             .bytes = {0, 20000},
+                                             .fsync{0, 300}}},
+                              .topNWrites = {{.userId = 0,
+                                              .packageName = "mount",
+                                              .bytes = {0, 30000},
+                                              .fsync{0, 300}}},
+                              .total = {{0, 20000}, {0, 30000}, {0, 300}}},
+            .systemIoPerfData = {.cpuIoWaitTime = 1100,
+                                 .totalCpuTime = 26900,
+                                 .ioBlockedProcessesCnt = 5,
+                                 .totalProcessesCnt = 22},
+            .processIoPerfData = {.topNIoBlockedUids = {{0, "mount", 1, {{"disk I/O", 1}}}},
+                                  .topNIoBlockedUidsTotalTaskCnt = {1},
+                                  .topNMajorFaultUids = {{0, "mount", 5000, {{"disk I/O", 5000}}}},
+                                  .totalMajorFaults = 5000,
+                                  .majorFaultsPercentChange = 0.0},
+    };
+    ret = looperStub->pollCache();
+    ASSERT_TRUE(ret) << ret.error().message();
+    ASSERT_EQ(looperStub->numSecondsElapsed(), 0)
+            << "Boot-time collection didn't start immediately";
+
+    // #2 Boot-time collection
+    uidIoStatsStub->push({
+            {1009, {.uid = 1009, .ios = {0, 2000, 0, 3000, 0, 100}}},
+    });
+    procStatStub->push(ProcStatInfo{
+            /*stats=*/{1200, 1700, 2700, 7800, /*ioWaitTime=*/5500, 500, 300, 0, 0, 100},
+            /*runnableCnt=*/8,
+            /*ioBlockedCnt=*/6,
+    });
+    procPidStatStub->push({{.tgid = 100,
+                            .uid = 1009,
+                            .process = {.pid = 100,
+                                        .comm = "disk I/O",
+                                        .state = "D",
+                                        .ppid = 1,
+                                        .majorFaults = 11000,
+                                        .numThreads = 1,
+                                        .startTime = 234},
+                            .threads = {{100,
+                                         {.pid = 100,
+                                          .comm = "disk I/O",
+                                          .state = "D",
+                                          .ppid = 1,
+                                          .majorFaults = 10000,
+                                          .numThreads = 1,
+                                          .startTime = 234}},
+                                        {200,
+                                         {.pid = 200,
+                                          .comm = "disk I/O",
+                                          .state = "D",
+                                          .ppid = 1,
+                                          .majorFaults = 1000,
+                                          .numThreads = 1,
+                                          .startTime = 1234}}}}});
+    IoPerfRecord bootExpectedSecond = {
+            .uidIoPerfData = {.topNReads = {{.userId = 0,
+                                             .packageName = "mount",
+                                             .bytes = {0, 2000},
+                                             .fsync{0, 100}}},
+                              .topNWrites = {{.userId = 0,
+                                              .packageName = "mount",
+                                              .bytes = {0, 3000},
+                                              .fsync{0, 100}}},
+                              .total = {{0, 2000}, {0, 3000}, {0, 100}}},
+            .systemIoPerfData = {.cpuIoWaitTime = 5500,
+                                 .totalCpuTime = 19800,
+                                 .ioBlockedProcessesCnt = 6,
+                                 .totalProcessesCnt = 14},
+            .processIoPerfData =
+                    {.topNIoBlockedUids = {{0, "mount", 2, {{"disk I/O", 2}}}},
+                     .topNIoBlockedUidsTotalTaskCnt = {2},
+                     .topNMajorFaultUids = {{0, "mount", 11000, {{"disk I/O", 11000}}}},
+                     .totalMajorFaults = 11000,
+                     .majorFaultsPercentChange = ((11000.0 - 5000.0) / 5000.0) * 100},
+    };
+    ret = looperStub->pollCache();
+    ASSERT_TRUE(ret) << ret.error().message();
+    ASSERT_EQ(looperStub->numSecondsElapsed(), kTestBootInterval.count())
+            << "Subsequent boot-time collection didn't happen at " << kTestBootInterval.count()
+            << " seconds interval";
+
+    // #3 Last boot-time collection
+    ret = collector->onBootFinished();
+    ASSERT_TRUE(ret) << ret.error().message();
+    uidIoStatsStub->push({
+            {1009, {.uid = 1009, .ios = {0, 7000, 0, 8000, 0, 50}}},
+    });
+    procStatStub->push(ProcStatInfo{
+            /*stats=*/{1400, 1900, 2900, 8000, /*ioWaitTime=*/5700, 700, 500, 0, 0, 300},
+            /*runnableCnt=*/10,
+            /*ioBlockedCnt=*/8,
+    });
+    procPidStatStub->push({{.tgid = 100,
+                            .uid = 1009,
+                            .process = {.pid = 100,
+                                        .comm = "disk I/O",
+                                        .state = "D",
+                                        .ppid = 1,
+                                        .majorFaults = 5000,
+                                        .numThreads = 1,
+                                        .startTime = 234},
+                            .threads = {{100,
+                                         {.pid = 100,
+                                          .comm = "disk I/O",
+                                          .state = "D",
+                                          .ppid = 1,
+                                          .majorFaults = 3000,
+                                          .numThreads = 1,
+                                          .startTime = 234}},
+                                        {200,
+                                         {.pid = 200,
+                                          .comm = "disk I/O",
+                                          .state = "D",
+                                          .ppid = 1,
+                                          .majorFaults = 2000,
+                                          .numThreads = 1,
+                                          .startTime = 1234}}}}});
+    IoPerfRecord bootExpectedThird = {
+            .uidIoPerfData = {.topNReads = {{.userId = 0,
+                                             .packageName = "mount",
+                                             .bytes = {0, 7000},
+                                             .fsync{0, 50}}},
+                              .topNWrites = {{.userId = 0,
+                                              .packageName = "mount",
+                                              .bytes = {0, 8000},
+                                              .fsync{0, 50}}},
+                              .total = {{0, 7000}, {0, 8000}, {0, 50}}},
+            .systemIoPerfData = {.cpuIoWaitTime = 5700,
+                                 .totalCpuTime = 21400,
+                                 .ioBlockedProcessesCnt = 8,
+                                 .totalProcessesCnt = 18},
+            .processIoPerfData = {.topNIoBlockedUids = {{0, "mount", 2, {{"disk I/O", 2}}}},
+                                  .topNIoBlockedUidsTotalTaskCnt = {2},
+                                  .topNMajorFaultUids = {{0, "mount", 5000, {{"disk I/O", 5000}}}},
+                                  .totalMajorFaults = 5000,
+                                  .majorFaultsPercentChange = ((5000.0 - 11000.0) / 11000.0) * 100},
+    };
+    ret = looperStub->pollCache();
+    ASSERT_TRUE(ret) << ret.error().message();
+    ASSERT_EQ(looperStub->numSecondsElapsed(), 0)
+            << "Last boot-time collection didn't happen immediately after receiving boot complete "
+            << "notification";
+
+    ASSERT_EQ(collector->mBoottimeCollection.records.size(), 3);
+    ASSERT_TRUE(isEqual(collector->mBoottimeCollection.records[0], bootExpectedFirst))
+            << "Boot-time collection record 1 doesn't match.\nExpected:\n"
+            << toString(bootExpectedFirst) << "\nActual:\n"
+            << toString(collector->mBoottimeCollection.records[0]);
+    ASSERT_TRUE(isEqual(collector->mBoottimeCollection.records[1], bootExpectedSecond))
+            << "Boot-time collection record 2 doesn't match.\nExpected:\n"
+            << toString(bootExpectedSecond) << "\nActual:\n"
+            << toString(collector->mBoottimeCollection.records[1]);
+    ASSERT_TRUE(isEqual(collector->mBoottimeCollection.records[2], bootExpectedThird))
+            << "Boot-time collection record 3 doesn't match.\nExpected:\n"
+            << toString(bootExpectedSecond) << "\nActual:\n"
+            << toString(collector->mBoottimeCollection.records[2]);
+
+    // #4 Periodic collection
+    uidIoStatsStub->push({
+            {1009, {.uid = 1009, .ios = {0, 4000, 0, 6000, 0, 100}}},
+    });
+    procStatStub->push(ProcStatInfo{
+            /*stats=*/{200, 700, 400, 800, /*ioWaitTime=*/500, 666, 780, 0, 0, 230},
+            /*runnableCnt=*/12,
+            /*ioBlockedCnt=*/3,
+    });
+    procPidStatStub->push({{.tgid = 100,
+                            .uid = 1009,
+                            .process = {.pid = 100,
+                                        .comm = "disk I/O",
+                                        .state = "D",
+                                        .ppid = 1,
+                                        .majorFaults = 4100,
+                                        .numThreads = 1,
+                                        .startTime = 234},
+                            .threads = {{100,
+                                         {.pid = 100,
+                                          .comm = "disk I/O",
+                                          .state = "D",
+                                          .ppid = 1,
+                                          .majorFaults = 100,
+                                          .numThreads = 1,
+                                          .startTime = 234}},
+                                        {1200,
+                                         {.pid = 1200,
+                                          .comm = "disk I/O",
+                                          .state = "S",
+                                          .ppid = 1,
+                                          .majorFaults = 4000,
+                                          .numThreads = 1,
+                                          .startTime = 567890}}}}});
+    IoPerfRecord periodicExpectedFirst = {
+            .uidIoPerfData = {.topNReads = {{.userId = 0,
+                                             .packageName = "mount",
+                                             .bytes = {0, 4000},
+                                             .fsync{0, 100}}},
+                              .topNWrites = {{.userId = 0,
+                                              .packageName = "mount",
+                                              .bytes = {0, 6000},
+                                              .fsync{0, 100}}},
+                              .total = {{0, 4000}, {0, 6000}, {0, 100}}},
+            .systemIoPerfData = {.cpuIoWaitTime = 500,
+                                 .totalCpuTime = 4276,
+                                 .ioBlockedProcessesCnt = 3,
+                                 .totalProcessesCnt = 15},
+            .processIoPerfData = {.topNIoBlockedUids = {{0, "mount", 1, {{"disk I/O", 1}}}},
+                                  .topNIoBlockedUidsTotalTaskCnt = {2},
+                                  .topNMajorFaultUids = {{0, "mount", 4100, {{"disk I/O", 4100}}}},
+                                  .totalMajorFaults = 4100,
+                                  .majorFaultsPercentChange = ((4100.0 - 5000.0) / 5000.0) * 100},
+    };
+    ret = looperStub->pollCache();
+    ASSERT_TRUE(ret) << ret.error().message();
+    ASSERT_EQ(looperStub->numSecondsElapsed(), kTestPeriodicInterval.count())
+            << "First periodic collection didn't happen at " << kTestPeriodicInterval.count()
+            << " seconds interval";
+
+    // #5 Periodic collection
+    uidIoStatsStub->push({
+            {1009, {.uid = 1009, .ios = {0, 3000, 0, 5000, 0, 800}}},
+    });
+    procStatStub->push(ProcStatInfo{
+            /*stats=*/{2300, 7300, 4300, 8300, /*ioWaitTime=*/5300, 6366, 7380, 0, 0, 2330},
+            /*runnableCnt=*/2,
+            /*ioBlockedCnt=*/4,
+    });
+    procPidStatStub->push({{.tgid = 100,
+                            .uid = 1009,
+                            .process = {.pid = 100,
+                                        .comm = "disk I/O",
+                                        .state = "D",
+                                        .ppid = 1,
+                                        .majorFaults = 44300,
+                                        .numThreads = 1,
+                                        .startTime = 234},
+                            .threads = {{100,
+                                         {.pid = 100,
+                                          .comm = "disk I/O",
+                                          .state = "D",
+                                          .ppid = 1,
+                                          .majorFaults = 1300,
+                                          .numThreads = 1,
+                                          .startTime = 234}},
+                                        {1200,
+                                         {.pid = 1200,
+                                          .comm = "disk I/O",
+                                          .state = "D",
+                                          .ppid = 1,
+                                          .majorFaults = 43000,
+                                          .numThreads = 1,
+                                          .startTime = 567890}}}}});
+    IoPerfRecord periodicExpectedSecond = {
+            .uidIoPerfData = {.topNReads = {{.userId = 0,
+                                             .packageName = "mount",
+                                             .bytes = {0, 3000},
+                                             .fsync{0, 800}}},
+                              .topNWrites = {{.userId = 0,
+                                              .packageName = "mount",
+                                              .bytes = {0, 5000},
+                                              .fsync{0, 800}}},
+                              .total = {{0, 3000}, {0, 5000}, {0, 800}}},
+            .systemIoPerfData = {.cpuIoWaitTime = 5300,
+                                 .totalCpuTime = 43576,
+                                 .ioBlockedProcessesCnt = 4,
+                                 .totalProcessesCnt = 6},
+            .processIoPerfData =
+                    {.topNIoBlockedUids = {{0, "mount", 2, {{"disk I/O", 2}}}},
+                     .topNIoBlockedUidsTotalTaskCnt = {2},
+                     .topNMajorFaultUids = {{0, "mount", 44300, {{"disk I/O", 44300}}}},
+                     .totalMajorFaults = 44300,
+                     .majorFaultsPercentChange = ((44300.0 - 4100.0) / 4100.0) * 100},
+    };
+    ret = looperStub->pollCache();
+    ASSERT_TRUE(ret) << ret.error().message();
+    ASSERT_EQ(looperStub->numSecondsElapsed(), kTestPeriodicInterval.count())
+            << "Subsequent periodic collection didn't happen at " << kTestPeriodicInterval.count()
+            << " seconds interval";
+
+    ASSERT_EQ(collector->mPeriodicCollection.records.size(), 2);
+    ASSERT_TRUE(isEqual(collector->mPeriodicCollection.records[0], periodicExpectedFirst))
+            << "Periodic collection snapshot 1, record 1 doesn't match.\nExpected:\n"
+            << toString(periodicExpectedFirst) << "\nActual:\n"
+            << toString(collector->mPeriodicCollection.records[0]);
+    ASSERT_TRUE(isEqual(collector->mPeriodicCollection.records[1], periodicExpectedSecond))
+            << "Periodic collection snapshot 1, record 2 doesn't match.\nExpected:\n"
+            << toString(periodicExpectedSecond) << "\nActual:\n"
+            << toString(collector->mPeriodicCollection.records[1]);
+
+    // #6 Custom collection
+    Vector<String16> args;
+    args.push_back(String16(kStartCustomCollectionFlag));
+    args.push_back(String16(kIntervalFlag));
+    args.push_back(String16(std::to_string(kTestCustomInterval.count()).c_str()));
+    args.push_back(String16(kMaxDurationFlag));
+    args.push_back(String16(std::to_string(kTestCustomCollectionDuration.count()).c_str()));
+
+    ret = collector->dump(-1, args);
+    ASSERT_TRUE(ret.ok()) << ret.error().message();
+    uidIoStatsStub->push({
+            {1009, {.uid = 1009, .ios = {0, 13000, 0, 15000, 0, 100}}},
+    });
+    procStatStub->push(ProcStatInfo{
+            /*stats=*/{2800, 7800, 4800, 8800, /*ioWaitTime=*/5800, 6866, 7880, 0, 0, 2830},
+            /*runnableCnt=*/200,
+            /*ioBlockedCnt=*/13,
+    });
+    procPidStatStub->push({{.tgid = 100,
+                            .uid = 1009,
+                            .process = {.pid = 100,
+                                        .comm = "disk I/O",
+                                        .state = "D",
+                                        .ppid = 1,
+                                        .majorFaults = 49800,
+                                        .numThreads = 1,
+                                        .startTime = 234},
+                            .threads = {{100,
+                                         {.pid = 100,
+                                          .comm = "disk I/O",
+                                          .state = "D",
+                                          .ppid = 1,
+                                          .majorFaults = 1800,
+                                          .numThreads = 1,
+                                          .startTime = 234}},
+                                        {1200,
+                                         {.pid = 1200,
+                                          .comm = "disk I/O",
+                                          .state = "D",
+                                          .ppid = 1,
+                                          .majorFaults = 48000,
+                                          .numThreads = 1,
+                                          .startTime = 567890}}}}});
+    IoPerfRecord customExpectedFirst = {
+            .uidIoPerfData = {.topNReads = {{.userId = 0,
+                                             .packageName = "mount",
+                                             .bytes = {0, 13000},
+                                             .fsync{0, 100}}},
+                              .topNWrites = {{.userId = 0,
+                                              .packageName = "mount",
+                                              .bytes = {0, 15000},
+                                              .fsync{0, 100}}},
+                              .total = {{0, 13000}, {0, 15000}, {0, 100}}},
+            .systemIoPerfData = {.cpuIoWaitTime = 5800,
+                                 .totalCpuTime = 47576,
+                                 .ioBlockedProcessesCnt = 13,
+                                 .totalProcessesCnt = 213},
+            .processIoPerfData =
+                    {.topNIoBlockedUids = {{0, "mount", 2, {{"disk I/O", 2}}}},
+                     .topNIoBlockedUidsTotalTaskCnt = {2},
+                     .topNMajorFaultUids = {{0, "mount", 49800, {{"disk I/O", 49800}}}},
+                     .totalMajorFaults = 49800,
+                     .majorFaultsPercentChange = ((49800.0 - 44300.0) / 44300.0) * 100},
+    };
+    ret = looperStub->pollCache();
+    ASSERT_TRUE(ret) << ret.error().message();
+    ASSERT_EQ(looperStub->numSecondsElapsed(), 0) << "Custom collection didn't start immediately";
+
+    // #7 Custom collection
+    uidIoStatsStub->push({
+            {1009, {.uid = 1009, .ios = {0, 14000, 0, 16000, 0, 100}}},
+    });
+    procStatStub->push(ProcStatInfo{
+            /*stats=*/{2900, 7900, 4900, 8900, /*ioWaitTime=*/5900, 6966, 7980, 0, 0, 2930},
+            /*runnableCnt=*/100,
+            /*ioBlockedCnt=*/57,
+    });
+    procPidStatStub->push({{.tgid = 100,
+                            .uid = 1009,
+                            .process = {.pid = 100,
+                                        .comm = "disk I/O",
+                                        .state = "D",
+                                        .ppid = 1,
+                                        .majorFaults = 50900,
+                                        .numThreads = 1,
+                                        .startTime = 234},
+                            .threads = {{100,
+                                         {.pid = 100,
+                                          .comm = "disk I/O",
+                                          .state = "D",
+                                          .ppid = 1,
+                                          .majorFaults = 1900,
+                                          .numThreads = 1,
+                                          .startTime = 234}},
+                                        {1200,
+                                         {.pid = 1200,
+                                          .comm = "disk I/O",
+                                          .state = "D",
+                                          .ppid = 1,
+                                          .majorFaults = 49000,
+                                          .numThreads = 1,
+                                          .startTime = 567890}}}}});
+    IoPerfRecord customExpectedSecond = {
+            .uidIoPerfData = {.topNReads = {{.userId = 0,
+                                             .packageName = "mount",
+                                             .bytes = {0, 14000},
+                                             .fsync{0, 100}}},
+                              .topNWrites = {{.userId = 0,
+                                              .packageName = "mount",
+                                              .bytes = {0, 16000},
+                                              .fsync{0, 100}}},
+                              .total = {{0, 14000}, {0, 16000}, {0, 100}}},
+            .systemIoPerfData = {.cpuIoWaitTime = 5900,
+                                 .totalCpuTime = 48376,
+                                 .ioBlockedProcessesCnt = 57,
+                                 .totalProcessesCnt = 157},
+            .processIoPerfData =
+                    {.topNIoBlockedUids = {{0, "mount", 2, {{"disk I/O", 2}}}},
+                     .topNIoBlockedUidsTotalTaskCnt = {2},
+                     .topNMajorFaultUids = {{0, "mount", 50900, {{"disk I/O", 50900}}}},
+                     .totalMajorFaults = 50900,
+                     .majorFaultsPercentChange = ((50900.0 - 49800.0) / 49800.0) * 100},
+    };
+    ret = looperStub->pollCache();
+    ASSERT_TRUE(ret) << ret.error().message();
+    ASSERT_EQ(looperStub->numSecondsElapsed(), kTestCustomInterval.count())
+            << "Subsequent custom collection didn't happen at " << kTestCustomInterval.count()
+            << " seconds interval";
+
+    ASSERT_EQ(collector->mCustomCollection.records.size(), 2);
+    ASSERT_TRUE(isEqual(collector->mCustomCollection.records[0], customExpectedFirst))
+            << "Custom collection record 1 doesn't match.\nExpected:\n"
+            << toString(customExpectedFirst) << "\nActual:\n"
+            << toString(collector->mCustomCollection.records[0]);
+    ASSERT_TRUE(isEqual(collector->mCustomCollection.records[1], customExpectedSecond))
+            << "Custom collection record 2 doesn't match.\nExpected:\n"
+            << toString(customExpectedSecond) << "\nActual:\n"
+            << toString(collector->mCustomCollection.records[1]);
+
+    // #8 Switch to periodic collection
+    args.clear();
+    args.push_back(String16(kEndCustomCollectionFlag));
+    TemporaryFile customDump;
+    ret = collector->dump(customDump.fd, args);
+    ASSERT_TRUE(ret.ok()) << ret.error().message();
+    ret = looperStub->pollCache();
+    ASSERT_TRUE(ret) << ret.error().message();
+
+    // Custom collection cache should be emptied on ending the collection.
+    ASSERT_EQ(collector->mCustomCollection.records.size(), 0);
+
+    // #7 periodic collection
+    uidIoStatsStub->push({
+            {1009, {.uid = 1009, .ios = {0, 123, 0, 456, 0, 25}}},
+    });
+    procStatStub->push(ProcStatInfo{
+            /*stats=*/{3400, 2300, 5600, 7800, /*ioWaitTime=*/1100, 166, 180, 0, 0, 130},
+            /*runnableCnt=*/3,
+            /*ioBlockedCnt=*/1,
+    });
+    procPidStatStub->push({{.tgid = 100,
+                            .uid = 1009,
+                            .process = {.pid = 100,
+                                        .comm = "disk I/O",
+                                        .state = "D",
+                                        .ppid = 1,
+                                        .majorFaults = 5701,
+                                        .numThreads = 1,
+                                        .startTime = 234},
+                            .threads = {{100,
+                                         {.pid = 100,
+                                          .comm = "disk I/O",
+                                          .state = "D",
+                                          .ppid = 1,
+                                          .majorFaults = 23,
+                                          .numThreads = 1,
+                                          .startTime = 234}},
+                                        {1200,
+                                         {.pid = 1200,
+                                          .comm = "disk I/O",
+                                          .state = "D",
+                                          .ppid = 1,
+                                          .majorFaults = 5678,
+                                          .numThreads = 1,
+                                          .startTime = 567890}}}}});
+    IoPerfRecord periodicExpectedThird = {
+            .uidIoPerfData = {.topNReads = {{.userId = 0,
+                                             .packageName = "mount",
+                                             .bytes = {0, 123},
+                                             .fsync{0, 25}}},
+                              .topNWrites = {{.userId = 0,
+                                              .packageName = "mount",
+                                              .bytes = {0, 456},
+                                              .fsync{0, 25}}},
+                              .total = {{0, 123}, {0, 456}, {0, 25}}},
+            .systemIoPerfData = {.cpuIoWaitTime = 1100,
+                                 .totalCpuTime = 20676,
+                                 .ioBlockedProcessesCnt = 1,
+                                 .totalProcessesCnt = 4},
+            .processIoPerfData = {.topNIoBlockedUids = {{0, "mount", 2, {{"disk I/O", 2}}}},
+                                  .topNIoBlockedUidsTotalTaskCnt = {2},
+                                  .topNMajorFaultUids = {{0, "mount", 5701, {{"disk I/O", 5701}}}},
+                                  .totalMajorFaults = 5701,
+                                  .majorFaultsPercentChange = ((5701.0 - 50900.0) / 50900.0) * 100},
+    };
+    ret = looperStub->pollCache();
+    ASSERT_TRUE(ret) << ret.error().message();
+    ASSERT_EQ(looperStub->numSecondsElapsed(), 0)
+            << "Periodic collection didn't start immediately after ending custom collection";
+
+    // Maximum periodic collection buffer size is 2.
+    ASSERT_EQ(collector->mPeriodicCollection.records.size(), 2);
+    ASSERT_TRUE(isEqual(collector->mPeriodicCollection.records[0], periodicExpectedSecond))
+            << "Periodic collection snapshot 2, record 1 doesn't match.\nExpected:\n"
+            << toString(periodicExpectedSecond) << "\nActual:\n"
+            << toString(collector->mPeriodicCollection.records[0]);
+    ASSERT_TRUE(isEqual(collector->mPeriodicCollection.records[1], periodicExpectedThird))
+            << "Periodic collection snapshot 2, record 2 doesn't match.\nExpected:\n"
+            << toString(periodicExpectedThird) << "\nActual:\n"
+            << toString(collector->mPeriodicCollection.records[1]);
+
+    ASSERT_EQ(collector->mBoottimeCollection.records.size(), 3)
+            << "Boot-time records not persisted until collector termination";
+
+    TemporaryFile bugreportDump;
+    ret = collector->dump(bugreportDump.fd, {});
+    ASSERT_TRUE(ret.ok()) << ret.error().message();
+
+    collector->terminate();
+}
+
+TEST(IoPerfCollectionTest, TestCollectionTerminatesOnZeroEnabledCollectors) {
+    sp<IoPerfCollection> collector = new IoPerfCollection();
+    collector->mUidIoStats = new UidIoStatsStub();
+    collector->mProcStat = new ProcStatStub();
+    collector->mProcPidStat = new ProcPidStatStub();
+
+    const auto& ret = collector->start();
+    ASSERT_TRUE(ret) << ret.error().message();
+
+    ASSERT_EQ(std::async([&]() {
+                  if (collector->mCollectionThread.joinable()) {
+                      collector->mCollectionThread.join();
+                  }
+              }).wait_for(1s),
+              std::future_status::ready)
+            << "Collection thread didn't terminate within 1 second.";
+    ASSERT_EQ(collector->mCurrCollectionEvent, CollectionEvent::TERMINATED);
+
+    // When the collection doesn't auto-terminate on error, the test will hang if the collector is
+    // not terminated explicitly. Thus call terminate to avoid this.
+    collector->terminate();
+}
+
+TEST(IoPerfCollectionTest, TestCollectionTerminatesOnError) {
+    sp<IoPerfCollection> collector = new IoPerfCollection();
+    collector->mUidIoStats = new UidIoStatsStub(true);
+    collector->mProcStat = new ProcStatStub(true);
+    collector->mProcPidStat = new ProcPidStatStub(true);
+
+    // Stub caches are empty so polling them should trigger error.
+    const auto& ret = collector->start();
+    ASSERT_TRUE(ret) << ret.error().message();
+
+    ASSERT_EQ(std::async([&]() {
+                  if (collector->mCollectionThread.joinable()) {
+                      collector->mCollectionThread.join();
+                  }
+              }).wait_for(1s),
+              std::future_status::ready)
+            << "Collection thread didn't terminate within 1 second.";
+    ASSERT_EQ(collector->mCurrCollectionEvent, CollectionEvent::TERMINATED);
+
+    // When the collection doesn't auto-terminate on error, the test will hang if the collector is
+    // not terminated explicitly. Thus call terminate to avoid this.
+    collector->terminate();
+}
+
+TEST(IoPerfCollectionTest, TestCustomCollectionFiltersPackageNames) {
+    sp<UidIoStatsStub> uidIoStatsStub = new UidIoStatsStub(true);
+    sp<ProcStatStub> procStatStub = new ProcStatStub(true);
+    sp<ProcPidStatStub> procPidStatStub = new ProcPidStatStub(true);
+    sp<LooperStub> looperStub = new LooperStub();
+
+    sp<IoPerfCollection> collector = new IoPerfCollection();
+    collector->mUidIoStats = uidIoStatsStub;
+    collector->mProcStat = procStatStub;
+    collector->mProcPidStat = procPidStatStub;
+    collector->mHandlerLooper = looperStub;
+    // Filter by package name should ignore this limit.
+    collector->mTopNStatsPerCategory = 1;
+
+    auto ret = collector->start();
+    ASSERT_TRUE(ret) << ret.error().message();
+
+    // Dummy boot-time collection
+    uidIoStatsStub->push({});
+    procStatStub->push(ProcStatInfo{});
+    procPidStatStub->push({});
+    ret = looperStub->pollCache();
+    ASSERT_TRUE(ret) << ret.error().message();
+
+    // Dummy Periodic collection
+    ret = collector->onBootFinished();
+    ASSERT_TRUE(ret) << ret.error().message();
+    uidIoStatsStub->push({});
+    procStatStub->push(ProcStatInfo{});
+    procPidStatStub->push({});
+    ret = looperStub->pollCache();
+    ASSERT_TRUE(ret) << ret.error().message();
+
+    // Start custom Collection
+    Vector<String16> args;
+    args.push_back(String16(kStartCustomCollectionFlag));
+    args.push_back(String16(kIntervalFlag));
+    args.push_back(String16(std::to_string(kTestCustomInterval.count()).c_str()));
+    args.push_back(String16(kMaxDurationFlag));
+    args.push_back(String16(std::to_string(kTestCustomCollectionDuration.count()).c_str()));
+    args.push_back(String16(kFilterPackagesFlag));
+    args.push_back(String16("android.car.cts,system_server"));
+
+    ret = collector->dump(-1, args);
+    ASSERT_TRUE(ret.ok()) << ret.error().message();
+
+    // Custom collection
+    collector->mUidToPackageNameMapping[1009] = "android.car.cts";
+    collector->mUidToPackageNameMapping[2001] = "system_server";
+    collector->mUidToPackageNameMapping[3456] = "random_process";
+    uidIoStatsStub->push({
+            {1009, {.uid = 1009, .ios = {0, 14000, 0, 16000, 0, 100}}},
+            {2001, {.uid = 2001, .ios = {0, 3400, 0, 6700, 0, 200}}},
+            {3456, {.uid = 3456, .ios = {0, 4200, 0, 5600, 0, 300}}},
+    });
+    procStatStub->push(ProcStatInfo{
+            /*stats=*/{2900, 7900, 4900, 8900, /*ioWaitTime=*/5900, 6966, 7980, 0, 0, 2930},
+            /*runnableCnt=*/100,
+            /*ioBlockedCnt=*/57,
+    });
+    procPidStatStub->push({{.tgid = 100,
+                            .uid = 1009,
+                            .process = {.pid = 100,
+                                        .comm = "cts_test",
+                                        .state = "D",
+                                        .ppid = 1,
+                                        .majorFaults = 50900,
+                                        .numThreads = 2,
+                                        .startTime = 234},
+                            .threads = {{100,
+                                         {.pid = 100,
+                                          .comm = "cts_test",
+                                          .state = "D",
+                                          .ppid = 1,
+                                          .majorFaults = 50900,
+                                          .numThreads = 1,
+                                          .startTime = 234}},
+                                        {200,
+                                         {.pid = 200,
+                                          .comm = "cts_test_2",
+                                          .state = "D",
+                                          .ppid = 1,
+                                          .majorFaults = 0,
+                                          .numThreads = 1,
+                                          .startTime = 290}}}},
+                           {.tgid = 1000,
+                            .uid = 2001,
+                            .process = {.pid = 1000,
+                                        .comm = "system_server",
+                                        .state = "D",
+                                        .ppid = 1,
+                                        .majorFaults = 1234,
+                                        .numThreads = 1,
+                                        .startTime = 345},
+                            .threads = {{1000,
+                                         {.pid = 1000,
+                                          .comm = "system_server",
+                                          .state = "D",
+                                          .ppid = 1,
+                                          .majorFaults = 1234,
+                                          .numThreads = 1,
+                                          .startTime = 345}}}},
+                           {.tgid = 4000,
+                            .uid = 3456,
+                            .process = {.pid = 4000,
+                                        .comm = "random_process",
+                                        .state = "D",
+                                        .ppid = 1,
+                                        .majorFaults = 3456,
+                                        .numThreads = 1,
+                                        .startTime = 890},
+                            .threads = {{4000,
+                                         {.pid = 4000,
+                                          .comm = "random_process",
+                                          .state = "D",
+                                          .ppid = 1,
+                                          .majorFaults = 50900,
+                                          .numThreads = 1,
+                                          .startTime = 890}}}}});
+    IoPerfRecord expected = {
+            .uidIoPerfData = {.topNReads = {{.userId = 0,
+                                             .packageName = "android.car.cts",
+                                             .bytes = {0, 14000},
+                                             .fsync{0, 100}},
+                                            {.userId = 0,
+                                             .packageName = "system_server",
+                                             .bytes = {0, 3400},
+                                             .fsync{0, 200}}},
+                              .topNWrites = {{.userId = 0,
+                                              .packageName = "android.car.cts",
+                                              .bytes = {0, 16000},
+                                              .fsync{0, 100}},
+                                             {.userId = 0,
+                                              .packageName = "system_server",
+                                              .bytes = {0, 6700},
+                                              .fsync{0, 200}}},
+                              .total = {{0, 21600}, {0, 28300}, {0, 600}}},
+            .systemIoPerfData = {.cpuIoWaitTime = 5900,
+                                 .totalCpuTime = 48376,
+                                 .ioBlockedProcessesCnt = 57,
+                                 .totalProcessesCnt = 157},
+            .processIoPerfData =
+                    {.topNIoBlockedUids = {{0, "android.car.cts", 2, {{"cts_test", 2}}},
+                                           {0, "system_server", 1, {{"system_server", 1}}}},
+                     .topNIoBlockedUidsTotalTaskCnt = {2, 1},
+                     .topNMajorFaultUids = {{0, "android.car.cts", 50900, {{"cts_test", 50900}}},
+                                            {0, "system_server", 1234, {{"system_server", 1234}}}},
+                     .totalMajorFaults = 55590,
+                     .majorFaultsPercentChange = 0},
+    };
+    ret = looperStub->pollCache();
+    ASSERT_TRUE(ret) << ret.error().message();
+    ASSERT_EQ(looperStub->numSecondsElapsed(), 0) << "Custom collection didn't start immediately";
+
+    ASSERT_EQ(collector->mCurrCollectionEvent, CollectionEvent::CUSTOM);
+    ASSERT_EQ(collector->mCustomCollection.records.size(), 1);
+    ASSERT_TRUE(isEqual(collector->mCustomCollection.records[0], expected))
+            << "Custom collection record doesn't match.\nExpected:\n"
+            << toString(expected) << "\nActual:\n"
+            << toString(collector->mCustomCollection.records[0]);
+    collector->terminate();
+}
+
+TEST(IoPerfCollectionTest, TestCustomCollectionTerminatesAfterMaxDuration) {
+    sp<UidIoStatsStub> uidIoStatsStub = new UidIoStatsStub(true);
+    sp<ProcStatStub> procStatStub = new ProcStatStub(true);
+    sp<ProcPidStatStub> procPidStatStub = new ProcPidStatStub(true);
+    sp<LooperStub> looperStub = new LooperStub();
+
+    sp<IoPerfCollection> collector = new IoPerfCollection();
+    collector->mUidIoStats = uidIoStatsStub;
+    collector->mProcStat = procStatStub;
+    collector->mProcPidStat = procPidStatStub;
+    collector->mHandlerLooper = looperStub;
+
+    auto ret = collector->start();
+    ASSERT_TRUE(ret) << ret.error().message();
+
+    // Dummy boot-time collection
+    uidIoStatsStub->push({});
+    procStatStub->push(ProcStatInfo{});
+    procPidStatStub->push({});
+    ret = looperStub->pollCache();
+    ASSERT_TRUE(ret) << ret.error().message();
+
+    // Dummy Periodic collection
+    ret = collector->onBootFinished();
+    ASSERT_TRUE(ret) << ret.error().message();
+    uidIoStatsStub->push({});
+    procStatStub->push(ProcStatInfo{});
+    procPidStatStub->push({});
+    ret = looperStub->pollCache();
+    ASSERT_TRUE(ret) << ret.error().message();
+
+    // Start custom Collection
+    Vector<String16> args;
+    args.push_back(String16(kStartCustomCollectionFlag));
+    args.push_back(String16(kIntervalFlag));
+    args.push_back(String16(std::to_string(kTestCustomInterval.count()).c_str()));
+    args.push_back(String16(kMaxDurationFlag));
+    args.push_back(String16(std::to_string(kTestCustomCollectionDuration.count()).c_str()));
+
+    ret = collector->dump(-1, args);
+    ASSERT_TRUE(ret.ok()) << ret.error().message();
+    // Maximum custom collection iterations during |kTestCustomCollectionDuration|.
+    int maxIterations =
+            static_cast<int>(kTestCustomCollectionDuration.count() / kTestCustomInterval.count());
+    for (int i = 0; i < maxIterations; ++i) {
+        ASSERT_TRUE(ret) << ret.error().message();
+        uidIoStatsStub->push({});
+        procStatStub->push(ProcStatInfo{});
+        procPidStatStub->push({});
+        ret = looperStub->pollCache();
+        ASSERT_TRUE(ret) << ret.error().message();
+        int secondsElapsed = (i == 0 ? 0 : kTestCustomInterval.count());
+        ASSERT_EQ(looperStub->numSecondsElapsed(), secondsElapsed)
+                << "Custom collection didn't happen at " << secondsElapsed
+                << " seconds interval in iteration " << i;
+    }
+
+    ASSERT_EQ(collector->mCurrCollectionEvent, CollectionEvent::CUSTOM);
+    ASSERT_GT(collector->mCustomCollection.records.size(), 0);
+    // Next looper message was injected during startCustomCollection to end the custom collection
+    // after |kTestCustomCollectionDuration|. Thus on processing this message the custom collection
+    // should terminate.
+    ret = looperStub->pollCache();
+    ASSERT_TRUE(ret) << ret.error().message();
+    ASSERT_EQ(looperStub->numSecondsElapsed(),
+              kTestCustomCollectionDuration.count() % kTestCustomInterval.count())
+            << "Custom collection did't end after " << kTestCustomCollectionDuration.count()
+            << " seconds";
+    ASSERT_EQ(collector->mCurrCollectionEvent, CollectionEvent::PERIODIC);
+    ASSERT_EQ(collector->mCustomCollection.records.size(), 0)
+            << "Custom collection records not discarded at the end of the collection";
+    collector->terminate();
+}
+
+TEST(IoPerfCollectionTest, TestValidUidIoStatFile) {
+    // Format: uid fgRdChar fgWrChar fgRdBytes fgWrBytes bgRdChar bgWrChar bgRdBytes bgWrBytes
+    // fgFsync bgFsync
+    constexpr char firstSnapshot[] =
+        "1001234 5000 1000 3000 500 0 0 0 0 20 0\n"
+        "1005678 500 100 30 50 300 400 100 200 45 60\n"
+        "1009 0 0 0 0 40000 50000 20000 30000 0 300\n"
+        "1001000 4000 3000 2000 1000 400 300 200 100 50 10\n";
+
+    struct UidIoPerfData expectedUidIoPerfData = {};
+    expectedUidIoPerfData.total[READ_BYTES][FOREGROUND] = 5030;
+    expectedUidIoPerfData.total[READ_BYTES][BACKGROUND] = 20300;
+    expectedUidIoPerfData.total[WRITE_BYTES][FOREGROUND] = 1550;
+    expectedUidIoPerfData.total[WRITE_BYTES][BACKGROUND] = 30300;
+    expectedUidIoPerfData.total[FSYNC_COUNT][FOREGROUND] = 115;
+    expectedUidIoPerfData.total[FSYNC_COUNT][BACKGROUND] = 370;
+    expectedUidIoPerfData.topNReads.push_back({
+            // uid: 1009
+            .userId = 0,
+            .packageName = "mount",
+            .bytes = {0, 20000},
+            .fsync = {0, 300},
+    });
+    expectedUidIoPerfData.topNReads.push_back({
+            // uid: 1001234
+            .userId = 10,
+            .packageName = "1001234",
+            .bytes = {3000, 0},
+            .fsync = {20, 0},
+    });
+    expectedUidIoPerfData.topNWrites.push_back({
+            // uid: 1009
+            .userId = 0,
+            .packageName = "mount",
+            .bytes = {0, 30000},
+            .fsync = {0, 300},
+    });
+    expectedUidIoPerfData.topNWrites.push_back({
+            // uid: 1001000
+            .userId = 10,
+            .packageName = "shared:android.uid.system",
+            .bytes = {1000, 100},
+            .fsync = {50, 10},
+    });
+
+    TemporaryFile tf;
+    ASSERT_NE(tf.fd, -1);
+    ASSERT_TRUE(WriteStringToFile(firstSnapshot, tf.path));
+
+    IoPerfCollection collector;
+    collector.mUidIoStats = new UidIoStats(tf.path);
+    collector.mTopNStatsPerCategory = 2;
+    ASSERT_TRUE(collector.mUidIoStats->enabled()) << "Temporary file is inaccessible";
+
+    struct UidIoPerfData actualUidIoPerfData = {};
+    auto ret = collector.collectUidIoPerfDataLocked(CollectionInfo{}, &actualUidIoPerfData);
+    ASSERT_RESULT_OK(ret);
+    EXPECT_TRUE(isEqual(expectedUidIoPerfData, actualUidIoPerfData))
+        << "First snapshot doesn't match.\nExpected:\n"
+        << toString(expectedUidIoPerfData) << "\nActual:\n"
+        << toString(actualUidIoPerfData);
+
+    constexpr char secondSnapshot[] =
+        "1001234 10000 2000 7000 950 0 0 0 0 45 0\n"
+        "1005678 600 100 40 50 1000 1000 1000 600 50 70\n"
+        "1003456 300 500 200 300 0 0 0 0 50 0\n"
+        "1001000 400 300 200 100 40 30 20 10 5 1\n";
+
+    expectedUidIoPerfData = {};
+    expectedUidIoPerfData.total[READ_BYTES][FOREGROUND] = 4210;
+    expectedUidIoPerfData.total[READ_BYTES][BACKGROUND] = 900;
+    expectedUidIoPerfData.total[WRITE_BYTES][FOREGROUND] = 750;
+    expectedUidIoPerfData.total[WRITE_BYTES][BACKGROUND] = 400;
+    expectedUidIoPerfData.total[FSYNC_COUNT][FOREGROUND] = 80;
+    expectedUidIoPerfData.total[FSYNC_COUNT][BACKGROUND] = 10;
+    expectedUidIoPerfData.topNReads.push_back({
+            // uid: 1001234
+            .userId = 10,
+            .packageName = "1001234",
+            .bytes = {4000, 0},
+            .fsync = {25, 0},
+    });
+    expectedUidIoPerfData.topNReads.push_back({
+            // uid: 1005678
+            .userId = 10,
+            .packageName = "1005678",
+            .bytes = {10, 900},
+            .fsync = {5, 10},
+    });
+    expectedUidIoPerfData.topNWrites.push_back({
+            // uid: 1001234
+            .userId = 10,
+            .packageName = "1001234",
+            .bytes = {450, 0},
+            .fsync = {25, 0},
+    });
+    expectedUidIoPerfData.topNWrites.push_back({
+            // uid: 1005678
+            .userId = 10,
+            .packageName = "1005678",
+            .bytes = {0, 400},
+            .fsync = {5, 10},
+    });
+    ASSERT_TRUE(WriteStringToFile(secondSnapshot, tf.path));
+    actualUidIoPerfData = {};
+    ret = collector.collectUidIoPerfDataLocked(CollectionInfo{}, &actualUidIoPerfData);
+    ASSERT_RESULT_OK(ret);
+    EXPECT_TRUE(isEqual(expectedUidIoPerfData, actualUidIoPerfData))
+        << "Second snapshot doesn't match.\nExpected:\n"
+        << toString(expectedUidIoPerfData) << "\nActual:\n"
+        << toString(actualUidIoPerfData);
+}
+
+TEST(IoPerfCollectionTest, TestUidIOStatsLessThanTopNStatsLimit) {
+    // Format: uid fgRdChar fgWrChar fgRdBytes fgWrBytes bgRdChar bgWrChar bgRdBytes bgWrBytes
+    // fgFsync bgFsync
+    constexpr char contents[] = "1001234 5000 1000 3000 500 0 0 0 0 20 0\n";
+
+    struct UidIoPerfData expectedUidIoPerfData = {};
+    expectedUidIoPerfData.total[READ_BYTES][FOREGROUND] = 3000;
+    expectedUidIoPerfData.total[READ_BYTES][BACKGROUND] = 0;
+    expectedUidIoPerfData.total[WRITE_BYTES][FOREGROUND] = 500;
+    expectedUidIoPerfData.total[WRITE_BYTES][BACKGROUND] = 0;
+    expectedUidIoPerfData.total[FSYNC_COUNT][FOREGROUND] = 20;
+    expectedUidIoPerfData.total[FSYNC_COUNT][BACKGROUND] = 0;
+    expectedUidIoPerfData.topNReads.push_back({
+            // uid: 1001234
+            .userId = 10,
+            .packageName = "1001234",
+            .bytes = {3000, 0},
+            .fsync = {20, 0},
+    });
+    expectedUidIoPerfData.topNWrites.push_back({
+            // uid: 1001234
+            .userId = 10,
+            .packageName = "1001234",
+            .bytes = {500, 0},
+            .fsync = {20, 0},
+    });
+
+    TemporaryFile tf;
+    ASSERT_NE(tf.fd, -1);
+    ASSERT_TRUE(WriteStringToFile(contents, tf.path));
+
+    IoPerfCollection collector;
+    collector.mUidIoStats = new UidIoStats(tf.path);
+    collector.mTopNStatsPerCategory = 10;
+    ASSERT_TRUE(collector.mUidIoStats->enabled()) << "Temporary file is inaccessible";
+
+    struct UidIoPerfData actualUidIoPerfData = {};
+    const auto& ret = collector.collectUidIoPerfDataLocked(CollectionInfo{}, &actualUidIoPerfData);
+    ASSERT_RESULT_OK(ret);
+    EXPECT_TRUE(isEqual(expectedUidIoPerfData, actualUidIoPerfData))
+        << "Collected data doesn't match.\nExpected:\n"
+        << toString(expectedUidIoPerfData) << "\nActual:\n"
+        << toString(actualUidIoPerfData);
+}
+
+TEST(IoPerfCollectionTest, TestValidProcStatFile) {
+    constexpr char firstSnapshot[] =
+            "cpu  6200 5700 1700 3100 1100 5200 3900 0 0 0\n"
+            "cpu0 2400 2900 600 690 340 4300 2100 0 0 0\n"
+            "cpu1 1900 2380 510 760 51 370 1500 0 0 0\n"
+            "cpu2 900 400 400 1000 600 400 160 0 0 0\n"
+            "cpu3 1000 20 190 650 109 130 140 0 0 0\n"
+            "intr 694351583 0 0 0 297062868 0 5922464 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "
+            "0 0\n"
+            // Skipped most of the intr line as it is not important for testing the ProcStat parsing
+            // logic.
+            "ctxt 579020168\n"
+            "btime 1579718450\n"
+            "processes 113804\n"
+            "procs_running 17\n"
+            "procs_blocked 5\n"
+            "softirq 33275060 934664 11958403 5111 516325 200333 0 341482 10651335 0 8667407\n";
+    struct SystemIoPerfData expectedSystemIoPerfData = {
+            .cpuIoWaitTime = 1100,
+            .totalCpuTime = 26900,
+            .ioBlockedProcessesCnt = 5,
+            .totalProcessesCnt = 22,
+    };
+
+    TemporaryFile tf;
+    ASSERT_NE(tf.fd, -1);
+    ASSERT_TRUE(WriteStringToFile(firstSnapshot, tf.path));
+
+    IoPerfCollection collector;
+    collector.mProcStat = new ProcStat(tf.path);
+    ASSERT_TRUE(collector.mProcStat->enabled()) << "Temporary file is inaccessible";
+
+    struct SystemIoPerfData actualSystemIoPerfData = {};
+    auto ret = collector.collectSystemIoPerfDataLocked(&actualSystemIoPerfData);
+    ASSERT_RESULT_OK(ret);
+    EXPECT_TRUE(isEqual(expectedSystemIoPerfData, actualSystemIoPerfData))
+            << "First snapshot doesn't match.\nExpected:\n"
+            << toString(expectedSystemIoPerfData) << "\nActual:\n"
+            << toString(actualSystemIoPerfData);
+
+    constexpr char secondSnapshot[] =
+            "cpu  16200 8700 2000 4100 2200 6200 5900 0 0 0\n"
+            "cpu0 4400 3400 700 890 800 4500 3100 0 0 0\n"
+            "cpu1 5900 3380 610 960 100 670 2000 0 0 0\n"
+            "cpu2 2900 1000 450 1400 800 600 460 0 0 0\n"
+            "cpu3 3000 920 240 850 500 430 340 0 0 0\n"
+            "intr 694351583 0 0 0 297062868 0 5922464 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "
+            "0 0\n"
+            "ctxt 579020168\n"
+            "btime 1579718450\n"
+            "processes 113804\n"
+            "procs_running 10\n"
+            "procs_blocked 2\n"
+            "softirq 33275060 934664 11958403 5111 516325 200333 0 341482 10651335 0 8667407\n";
+    expectedSystemIoPerfData = {
+            .cpuIoWaitTime = 1100,
+            .totalCpuTime = 18400,
+            .ioBlockedProcessesCnt = 2,
+            .totalProcessesCnt = 12,
+    };
+
+    ASSERT_TRUE(WriteStringToFile(secondSnapshot, tf.path));
+    actualSystemIoPerfData = {};
+    ret = collector.collectSystemIoPerfDataLocked(&actualSystemIoPerfData);
+    ASSERT_RESULT_OK(ret);
+    EXPECT_TRUE(isEqual(expectedSystemIoPerfData, actualSystemIoPerfData))
+            << "Second snapshot doesn't match.\nExpected:\n"
+            << toString(expectedSystemIoPerfData) << "\nActual:\n"
+            << toString(actualSystemIoPerfData);
+}
+
+TEST(IoPerfCollectionTest, TestValidProcPidContents) {
+    std::unordered_map<uint32_t, std::vector<uint32_t>> pidToTids = {
+            {1, {1, 453}},
+            {2546, {2546, 3456, 4789}},
+            {7890, {7890, 8978, 12890}},
+            {18902, {18902, 21345, 32452}},
+            {28900, {28900}},
+    };
+    std::unordered_map<uint32_t, std::string> perProcessStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 220 0 0 0 0 0 0 0 2 0 0\n"},
+            {2546, "2546 (system_server) R 1 0 0 0 0 0 0 0 6000 0 0 0 0 0 0 0 3 0 1000\n"},
+            {7890, "7890 (logd) D 1 0 0 0 0 0 0 0 15000 0 0 0 0 0 0 0 3 0 2345\n"},
+            {18902, "18902 (disk I/O) D 1 0 0 0 0 0 0 0 45678 0 0 0 0 0 0 0 3 0 897654\n"},
+            {28900, "28900 (tombstoned) D 1 0 0 0 0 0 0 0 89765 0 0 0 0 0 0 0 3 0 2345671\n"},
+    };
+    std::unordered_map<uint32_t, std::string> perProcessStatus = {
+            {1, "Pid:\t1\nTgid:\t1\nUid:\t0\t0\t0\t0\n"},
+            {2546, "Pid:\t2546\nTgid:\t2546\nUid:\t1001000\t1001000\t1001000\t1001000\n"},
+            {7890, "Pid:\t7890\nTgid:\t7890\nUid:\t1001000\t1001000\t1001000\t1001000\n"},
+            {18902, "Pid:\t18902\nTgid:\t18902\nUid:\t1009\t1009\t1009\t1009\n"},
+            {28900, "Pid:\t28900\nTgid:\t28900\nUid:\t1001234\t1001234\t1001234\t1001234\n"},
+    };
+    std::unordered_map<uint32_t, std::string> perThreadStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 2 0 0\n"},
+            {453, "453 (init) S 0 0 0 0 0 0 0 0 20 0 0 0 0 0 0 0 2 0 275\n"},
+            {2546, "2546 (system_server) R 1 0 0 0 0 0 0 0 1000 0 0 0 0 0 0 0 3 0 1000\n"},
+            {3456, "3456 (system_server) S 1 0 0 0 0 0 0 0 3000 0 0 0 0 0 0 0 3 0 2300\n"},
+            {4789, "4789 (system_server) D 1 0 0 0 0 0 0 0 2000 0 0 0 0 0 0 0 3 0 4500\n"},
+            {7890, "7890 (logd) D 1 0 0 0 0 0 0 0 10000 0 0 0 0 0 0 0 3 0 2345\n"},
+            {8978, "8978 (logd) D 1 0 0 0 0 0 0 0 1000 0 0 0 0 0 0 0 3 0 2500\n"},
+            {12890, "12890 (logd) D 1 0 0 0 0 0 0 0 500 0 0 0 0 0 0 0 3 0 2900\n"},
+            {18902, "18902 (disk I/O) D 1 0 0 0 0 0 0 0 30000 0 0 0 0 0 0 0 3 0 897654\n"},
+            {21345, "21345 (disk I/O) D 1 0 0 0 0 0 0 0 15000 0 0 0 0 0 0 0 3 0 904000\n"},
+            {32452, "32452 (disk I/O) D 1 0 0 0 0 0 0 0 678 0 0 0 0 0 0 0 3 0 1007000\n"},
+            {28900, "28900 (tombstoned) D 1 0 0 0 0 0 0 0 89765 0 0 0 0 0 0 0 3 0 2345671\n"},
+    };
+    struct ProcessIoPerfData expectedProcessIoPerfData = {};
+    expectedProcessIoPerfData.topNIoBlockedUids.push_back({
+            // uid: 1001000
+            .userId = 10,
+            .packageName = "shared:android.uid.system",
+            .count = 4,
+            .topNProcesses = {{"logd", 3}, {"system_server", 1}},
+    });
+    expectedProcessIoPerfData.topNIoBlockedUidsTotalTaskCnt.push_back(6);
+    expectedProcessIoPerfData.topNIoBlockedUids.push_back({
+            // uid: 1009
+            .userId = 0,
+            .packageName = "mount",
+            .count = 3,
+            .topNProcesses = {{"disk I/O", 3}},
+    });
+    expectedProcessIoPerfData.topNIoBlockedUidsTotalTaskCnt.push_back(3);
+    expectedProcessIoPerfData.topNMajorFaultUids.push_back({
+            // uid: 1001234
+            .userId = 10,
+            .packageName = "1001234",
+            .count = 89765,
+            .topNProcesses = {{"tombstoned", 89765}},
+    });
+    expectedProcessIoPerfData.topNMajorFaultUids.push_back({
+            // uid: 1009
+            .userId = 0,
+            .packageName = "mount",
+            .count = 45678,
+            .topNProcesses = {{"disk I/O", 45678}},
+    });
+    expectedProcessIoPerfData.totalMajorFaults = 156663;
+    expectedProcessIoPerfData.majorFaultsPercentChange = 0;
+
+    TemporaryDir firstSnapshot;
+    auto ret = populateProcPidDir(firstSnapshot.path, pidToTids, perProcessStat, perProcessStatus,
+                                  perThreadStat);
+    ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
+
+    IoPerfCollection collector;
+    collector.mProcPidStat = new ProcPidStat(firstSnapshot.path);
+    collector.mTopNStatsPerCategory = 2;
+    collector.mTopNStatsPerSubcategory = 2;
+    ASSERT_TRUE(collector.mProcPidStat->enabled())
+            << "Files under the temporary proc directory are inaccessible";
+
+    struct ProcessIoPerfData actualProcessIoPerfData = {};
+    ret = collector.collectProcessIoPerfDataLocked(CollectionInfo{}, &actualProcessIoPerfData);
+    ASSERT_TRUE(ret) << "Failed to collect first snapshot: " << ret.error();
+    EXPECT_TRUE(isEqual(expectedProcessIoPerfData, actualProcessIoPerfData))
+            << "First snapshot doesn't match.\nExpected:\n"
+            << toString(expectedProcessIoPerfData) << "\nActual:\n"
+            << toString(actualProcessIoPerfData);
+
+    pidToTids = {
+            {1, {1, 453}},
+            {2546, {2546, 3456, 4789}},
+    };
+    perProcessStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 880 0 0 0 0 0 0 0 2 0 0\n"},
+            {2546, "2546 (system_server) R 1 0 0 0 0 0 0 0 18000 0 0 0 0 0 0 0 3 0 1000\n"},
+    };
+    perProcessStatus = {
+            {1, "Pid:\t1\nTgid:\t1\nUid:\t0\t0\t0\t0\n"},
+            {2546, "Pid:\t2546\nTgid:\t2546\nUid:\t1001000\t1001000\t1001000\t1001000\n"},
+    };
+    perThreadStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 800 0 0 0 0 0 0 0 2 0 0\n"},
+            {453, "453 (init) S 0 0 0 0 0 0 0 0 80 0 0 0 0 0 0 0 2 0 275\n"},
+            {2546, "2546 (system_server) R 1 0 0 0 0 0 0 0 3000 0 0 0 0 0 0 0 3 0 1000\n"},
+            {3456, "3456 (system_server) S 1 0 0 0 0 0 0 0 9000 0 0 0 0 0 0 0 3 0 2300\n"},
+            {4789, "4789 (system_server) D 1 0 0 0 0 0 0 0 6000 0 0 0 0 0 0 0 3 0 4500\n"},
+    };
+    expectedProcessIoPerfData = {};
+    expectedProcessIoPerfData.topNIoBlockedUids.push_back({
+            // uid: 1001000
+            .userId = 10,
+            .packageName = "shared:android.uid.system",
+            .count = 1,
+            .topNProcesses = {{"system_server", 1}},
+    });
+    expectedProcessIoPerfData.topNIoBlockedUidsTotalTaskCnt.push_back(3);
+    expectedProcessIoPerfData.topNMajorFaultUids.push_back({
+            // uid: 1001000
+            .userId = 10,
+            .packageName = "shared:android.uid.system",
+            .count = 12000,
+            .topNProcesses = {{"system_server", 12000}},
+    });
+    expectedProcessIoPerfData.topNMajorFaultUids.push_back({
+            // uid: 0
+            .userId = 0,
+            .packageName = "root",
+            .count = 660,
+            .topNProcesses = {{"init", 660}},
+    });
+    expectedProcessIoPerfData.totalMajorFaults = 12660;
+    expectedProcessIoPerfData.majorFaultsPercentChange = ((12660.0 - 156663.0) / 156663.0) * 100;
+
+    TemporaryDir secondSnapshot;
+    ret = populateProcPidDir(secondSnapshot.path, pidToTids, perProcessStat, perProcessStatus,
+                             perThreadStat);
+    ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
+
+    collector.mProcPidStat->mPath = secondSnapshot.path;
+
+    actualProcessIoPerfData = {};
+    ret = collector.collectProcessIoPerfDataLocked(CollectionInfo{}, &actualProcessIoPerfData);
+    ASSERT_TRUE(ret) << "Failed to collect second snapshot: " << ret.error();
+    EXPECT_TRUE(isEqual(expectedProcessIoPerfData, actualProcessIoPerfData))
+            << "Second snapshot doesn't match.\nExpected:\n"
+            << toString(expectedProcessIoPerfData) << "\nActual:\n"
+            << toString(actualProcessIoPerfData);
+}
+
+TEST(IoPerfCollectionTest, TestProcPidContentsLessThanTopNStatsLimit) {
+    std::unordered_map<uint32_t, std::vector<uint32_t>> pidToTids = {
+            {1, {1, 453}},
+    };
+    std::unordered_map<uint32_t, std::string> perProcessStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 880 0 0 0 0 0 0 0 2 0 0\n"},
+    };
+    std::unordered_map<uint32_t, std::string> perProcessStatus = {
+            {1, "Pid:\t1\nTgid:\t1\nUid:\t0\t0\t0\t0\n"},
+    };
+    std::unordered_map<uint32_t, std::string> perThreadStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 800 0 0 0 0 0 0 0 2 0 0\n"},
+            {453, "453 (init) S 0 0 0 0 0 0 0 0 80 0 0 0 0 0 0 0 2 0 275\n"},
+    };
+    struct ProcessIoPerfData expectedProcessIoPerfData = {};
+    expectedProcessIoPerfData.topNMajorFaultUids.push_back({
+            // uid: 0
+            .userId = 0,
+            .packageName = "root",
+            .count = 880,
+            .topNProcesses = {{"init", 880}},
+    });
+    expectedProcessIoPerfData.totalMajorFaults = 880;
+    expectedProcessIoPerfData.majorFaultsPercentChange = 0.0;
+
+    TemporaryDir prodDir;
+    auto ret = populateProcPidDir(prodDir.path, pidToTids, perProcessStat, perProcessStatus,
+                                  perThreadStat);
+    ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
+
+    IoPerfCollection collector;
+    collector.mTopNStatsPerCategory = 5;
+    collector.mTopNStatsPerSubcategory = 3;
+    collector.mProcPidStat = new ProcPidStat(prodDir.path);
+    struct ProcessIoPerfData actualProcessIoPerfData = {};
+    ret = collector.collectProcessIoPerfDataLocked(CollectionInfo{}, &actualProcessIoPerfData);
+    ASSERT_TRUE(ret) << "Failed to collect proc pid contents: " << ret.error();
+    EXPECT_TRUE(isEqual(expectedProcessIoPerfData, actualProcessIoPerfData))
+            << "proc pid contents don't match.\nExpected:\n"
+            << toString(expectedProcessIoPerfData) << "\nActual:\n"
+            << toString(actualProcessIoPerfData);
+}
+
+TEST(IoPerfCollectionTest, TestHandlesInvalidDumpArguments) {
+    sp<IoPerfCollection> collector = new IoPerfCollection();
+    collector->start();
+    Vector<String16> args;
+    args.push_back(String16(kStartCustomCollectionFlag));
+    args.push_back(String16("Invalid flag"));
+    args.push_back(String16("Invalid value"));
+    ASSERT_FALSE(collector->dump(-1, args).ok());
+
+    args.clear();
+    args.push_back(String16(kStartCustomCollectionFlag));
+    args.push_back(String16(kIntervalFlag));
+    args.push_back(String16("Invalid interval"));
+    ASSERT_FALSE(collector->dump(-1, args).ok());
+
+    args.clear();
+    args.push_back(String16(kStartCustomCollectionFlag));
+    args.push_back(String16(kMaxDurationFlag));
+    args.push_back(String16("Invalid duration"));
+    ASSERT_FALSE(collector->dump(-1, args).ok());
+
+    args.clear();
+    args.push_back(String16(kEndCustomCollectionFlag));
+    args.push_back(String16(kMaxDurationFlag));
+    args.push_back(String16(std::to_string(kTestCustomCollectionDuration.count()).c_str()));
+    ASSERT_FALSE(collector->dump(-1, args).ok());
+
+    args.clear();
+    args.push_back(String16("Invalid flag"));
+    ASSERT_FALSE(collector->dump(-1, args).ok());
+    collector->terminate();
+}
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/watchdog/server/tests/LooperStub.cpp b/watchdog/server/tests/LooperStub.cpp
new file mode 100644
index 0000000..bd3311b
--- /dev/null
+++ b/watchdog/server/tests/LooperStub.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "carwatchdogd_ioperf_test"
+
+#include "LooperStub.h"
+
+#include <android-base/chrono_utils.h>
+#include <utils/Looper.h>
+
+#include <future>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+namespace testing {
+
+using android::base::Error;
+using android::base::Result;
+
+// As the messages, which are to be polled immediately, are enqueued in the underlying looper
+// handler before calling its poll method, the looper handler doesn't have to wait for any new
+// messages.
+const std::chrono::milliseconds kLooperPollTimeout = 0ms;
+
+// Maximum timeout before giving up on the underlying looper handler. This doesn't block the test
+// as long as the underlying looper handler processes the enqueued messages quickly and updates
+// |mShouldPoll|.
+const std::chrono::milliseconds kStubPollCheckTimeout = 3min;
+
+int LooperStub::pollAll(int /*timeoutMillis*/) {
+    {
+        Mutex::Autolock lock(mMutex);
+        if (!mShouldPoll) {
+            return 0;
+        }
+        mElapsedTime = mTimer;
+        while (!mCache.empty() && mCache.front().empty()) {
+            mTimer += 1s;  // Each empty entry in the cache is a second elapsed.
+            mCache.erase(mCache.begin());
+        }
+        mElapsedTime = mTimer - mElapsedTime;
+        if (mCache.empty()) {
+            mShouldPoll = false;
+            return 0;
+        }
+        // Send messages from the top of the cache and poll them immediately.
+        const auto messages = mCache.front();
+        for (const auto& m : messages) {
+            mLooper->sendMessage(mHandler, m);
+        }
+        mCache.erase(mCache.begin());
+    }
+    int result = mLooper->pollAll(kLooperPollTimeout.count());
+    Mutex::Autolock lock(mMutex);
+    mShouldPoll = false;
+    return result;
+}
+
+void LooperStub::sendMessage(const android::sp<MessageHandler>& handler, const Message& message) {
+    sendMessageAtTime(now(), handler, message);
+}
+
+void LooperStub::sendMessageAtTime(nsecs_t uptime, const android::sp<MessageHandler>& handler,
+                                   const Message& message) {
+    Mutex::Autolock lock(mMutex);
+    mHandler = handler;
+    nsecs_t uptimeDelay = uptime - now();
+    size_t pos = static_cast<size_t>(ns2s(uptimeDelay));
+    while (mCache.size() < pos + 1) {
+        mCache.emplace_back(LooperStub::CacheEntry());
+    }
+    mCache[pos].emplace_back(message);
+}
+
+void LooperStub::removeMessages(const android::sp<MessageHandler>& handler) {
+    Mutex::Autolock lock(mMutex);
+    mCache.clear();
+    mLooper->removeMessages(handler);
+}
+
+Result<void> LooperStub::pollCache() {
+    {
+        Mutex::Autolock lock(mMutex);
+        mShouldPoll = true;
+    }
+    auto checkPollCompleted = std::async([&]() {
+        bool shouldPoll = true;
+        while (shouldPoll) {
+            Mutex::Autolock lock(mMutex);
+            shouldPoll = mShouldPoll;
+        }
+    });
+    if (checkPollCompleted.wait_for(kStubPollCheckTimeout) != std::future_status::ready) {
+        mShouldPoll = false;
+        return Error() << "Poll didn't complete before " << kStubPollCheckTimeout.count()
+                       << " milliseconds";
+    }
+    return {};
+}
+
+}  // namespace testing
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/watchdog/server/tests/LooperStub.h b/watchdog/server/tests/LooperStub.h
new file mode 100644
index 0000000..da50faf
--- /dev/null
+++ b/watchdog/server/tests/LooperStub.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WATCHDOG_SERVER_TESTS_LOOPERSTUB_H_
+#define WATCHDOG_SERVER_TESTS_LOOPERSTUB_H_
+
+#include <android-base/chrono_utils.h>
+#include <android-base/result.h>
+#include <time.h>
+#include <utils/Looper.h>
+#include <utils/Mutex.h>
+#include <utils/StrongPointer.h>
+
+#include <functional>
+#include <vector>
+
+#include "LooperWrapper.h"
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+namespace testing {
+
+// LooperStub allows polling the underlying looper deterministically.
+// NOTE: Current implementation only works for one handler.
+class LooperStub : public LooperWrapper {
+public:
+    LooperStub() : mHandler(nullptr), mShouldPoll(false), mTimer(0) {}
+
+    nsecs_t now() override { return mTimer.count(); }
+    // No-op when mShouldPoll is false. Otherwise, sends messages (in a non-empty CacheEntry from
+    // the front of |mCache|) to the underlying looper and polls the looper immediately.
+    int pollAll(int timeoutMillis) override;
+
+    // Updates the front of |mCache| with the given message so the next pollAll call to the
+    // underlying looper will poll this message.
+    void sendMessage(const android::sp<MessageHandler>& handler, const Message& message) override;
+
+    // Updates the seconds(uptimeDelay) position in |mCache| with the given message.
+    // Thus |uptimeDelay| should be convertible to seconds without any fractions. uptimeDelay is
+    // computed from (uptime - now).
+    void sendMessageAtTime(nsecs_t uptime, const android::sp<MessageHandler>& handler,
+                           const Message& message) override;
+
+    // Removes all the messages from the cache and looper for |mHandler|.
+    void removeMessages(const android::sp<MessageHandler>& handler) override;
+
+    // Sets |mShouldPoll| so that the subsequent |pollAll| call processes the next non-empty
+    // CacheEntry in |mCache|. Before returning, waits for the pollAll call sent to the underlying
+    // looper to complete. Thus the caller can be certain this message was processed.
+    android::base::Result<void> pollCache();
+
+    // Number of seconds elapsed since the last pollAll call to the underlying looper.
+    nsecs_t numSecondsElapsed() {
+        return std::chrono::duration_cast<std::chrono::seconds>(mElapsedTime).count();
+    }
+
+private:
+    Mutex mMutex;
+    android::sp<MessageHandler> mHandler;
+    using CacheEntry = std::vector<Message>;  // Messages to process on a given second.
+    std::vector<CacheEntry> mCache;           // Messages pending to be processed.
+    bool mShouldPoll;
+    std::chrono::nanoseconds mTimer;
+    std::chrono::nanoseconds mElapsedTime;
+};
+
+}  // namespace testing
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
+
+#endif  // WATCHDOG_SERVER_TESTS_LOOPERSTUB_H_
diff --git a/watchdog/server/tests/ProcPidDir.cpp b/watchdog/server/tests/ProcPidDir.cpp
new file mode 100644
index 0000000..ac00e9b
--- /dev/null
+++ b/watchdog/server/tests/ProcPidDir.cpp
@@ -0,0 +1,106 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ProcPidDir.h"
+
+#include <android-base/file.h>
+#include <android-base/result.h>
+#include <errno.h>
+
+#include "ProcPidStat.h"
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+namespace testing {
+
+using android::base::Error;
+using android::base::Result;
+using android::base::WriteStringToFile;
+
+namespace {
+
+Result<void> makeDir(std::string path) {
+    if (mkdir(path.c_str(), 0700) && errno != EEXIST) {
+        return Error() << "Could not mkdir " << path << ": " << strerror(errno);
+    }
+    return {};
+}
+
+}  // namespace
+
+Result<void> populateProcPidDir(
+        const std::string& procDirPath,
+        const std::unordered_map<uint32_t, std::vector<uint32_t>>& pidToTids,
+        const std::unordered_map<uint32_t, std::string>& processStat,
+        const std::unordered_map<uint32_t, std::string>& processStatus,
+        const std::unordered_map<uint32_t, std::string>& threadStat) {
+    for (const auto& it : pidToTids) {
+        // 1. Create /proc/PID dir.
+        const auto& pidDirRes = makeDir(StringPrintf("%s/%" PRIu32, procDirPath.c_str(), it.first));
+        if (!pidDirRes) {
+            return Error() << "Failed to create top-level per-process directory: "
+                           << pidDirRes.error();
+        }
+
+        // 2. Create /proc/PID/stat file.
+        uint32_t pid = it.first;
+        if (processStat.find(pid) != processStat.end()) {
+            std::string path = StringPrintf((procDirPath + kStatFileFormat).c_str(), pid);
+            if (!WriteStringToFile(processStat.at(pid), path)) {
+                return Error() << "Failed to write pid stat file " << path;
+            }
+        }
+
+        // 3. Create /proc/PID/status file.
+        if (processStatus.find(pid) != processStatus.end()) {
+            std::string path = StringPrintf((procDirPath + kStatusFileFormat).c_str(), pid);
+            if (!WriteStringToFile(processStatus.at(pid), path)) {
+                return Error() << "Failed to write pid status file " << path;
+            }
+        }
+
+        // 4. Create /proc/PID/task dir.
+        const auto& taskDirRes = makeDir(StringPrintf((procDirPath + kTaskDirFormat).c_str(), pid));
+        if (!taskDirRes) {
+            return Error() << "Failed to create task directory: " << taskDirRes.error();
+        }
+
+        // 5. Create /proc/PID/task/TID dirs and /proc/PID/task/TID/stat files.
+        for (const auto& tid : it.second) {
+            const auto& tidDirRes = makeDir(
+                    StringPrintf((procDirPath + kTaskDirFormat + "/%" PRIu32).c_str(), pid, tid));
+            if (!tidDirRes) {
+                return Error() << "Failed to create per-thread directory: " << tidDirRes.error();
+            }
+            if (threadStat.find(tid) != threadStat.end()) {
+                std::string path =
+                        StringPrintf((procDirPath + kTaskDirFormat + kStatFileFormat).c_str(), pid,
+                                     tid);
+                if (!WriteStringToFile(threadStat.at(tid), path)) {
+                    return Error() << "Failed to write thread stat file " << path;
+                }
+            }
+        }
+    }
+
+    return {};
+}
+
+}  // namespace testing
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/watchdog/server/tests/ProcPidDir.h b/watchdog/server/tests/ProcPidDir.h
new file mode 100644
index 0000000..7253203
--- /dev/null
+++ b/watchdog/server/tests/ProcPidDir.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WATCHDOG_SERVER_TESTS_PROCPIDDIR_H_
+#define WATCHDOG_SERVER_TESTS_PROCPIDDIR_H_
+
+#include <android-base/result.h>
+#include <stdint.h>
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+namespace testing {
+
+android::base::Result<void> populateProcPidDir(
+        const std::string& procDirPath,
+        const std::unordered_map<uint32_t, std::vector<uint32_t>>& pidToTids,
+        const std::unordered_map<uint32_t, std::string>& processStat,
+        const std::unordered_map<uint32_t, std::string>& processStatus,
+        const std::unordered_map<uint32_t, std::string>& threadStat);
+
+}  // namespace testing
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
+
+#endif  //  WATCHDOG_SERVER_TESTS_PROCPIDDIR_H_
diff --git a/watchdog/server/tests/ProcPidStatTest.cpp b/watchdog/server/tests/ProcPidStatTest.cpp
new file mode 100644
index 0000000..6c9c394
--- /dev/null
+++ b/watchdog/server/tests/ProcPidStatTest.cpp
@@ -0,0 +1,604 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ProcPidStat.h"
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <inttypes.h>
+
+#include <algorithm>
+#include <string>
+
+#include "ProcPidDir.h"
+#include "gmock/gmock.h"
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using android::base::StringAppendF;
+using android::base::StringPrintf;
+using testing::populateProcPidDir;
+
+namespace {
+
+std::string toString(const PidStat& stat) {
+    return StringPrintf("PID: %" PRIu32 ", PPID: %" PRIu32 ", Comm: %s, State: %s, "
+                        "Major page faults: %" PRIu64 ", Num threads: %" PRIu32
+                        ", Start time: %" PRIu64,
+                        stat.pid, stat.ppid, stat.comm.c_str(), stat.state.c_str(),
+                        stat.majorFaults, stat.numThreads, stat.startTime);
+}
+
+std::string toString(const ProcessStats& stats) {
+    std::string buffer;
+    StringAppendF(&buffer, "Tgid: %" PRIi64 ", UID: %" PRIi64 ", %s\n", stats.tgid, stats.uid,
+                  toString(stats.process).c_str());
+    StringAppendF(&buffer, "\tThread stats:\n");
+    for (const auto& it : stats.threads) {
+        StringAppendF(&buffer, "\t\t%s\n", toString(it.second).c_str());
+    }
+    StringAppendF(&buffer, "\n");
+    return buffer;
+}
+
+std::string toString(const std::vector<ProcessStats>& stats) {
+    std::string buffer;
+    StringAppendF(&buffer, "Number of processes: %d\n", static_cast<int>(stats.size()));
+    for (const auto& it : stats) {
+        StringAppendF(&buffer, "%s", toString(it).c_str());
+    }
+    return buffer;
+}
+
+bool isEqual(const PidStat& lhs, const PidStat& rhs) {
+    return lhs.pid == rhs.pid && lhs.comm == rhs.comm && lhs.state == rhs.state &&
+            lhs.ppid == rhs.ppid && lhs.majorFaults == rhs.majorFaults &&
+            lhs.numThreads == rhs.numThreads && lhs.startTime == rhs.startTime;
+}
+
+bool isEqual(std::vector<ProcessStats>* lhs, std::vector<ProcessStats>* rhs) {
+    if (lhs->size() != rhs->size()) {
+        return false;
+    }
+    std::sort(lhs->begin(), lhs->end(), [&](const ProcessStats& l, const ProcessStats& r) -> bool {
+        return l.process.pid < r.process.pid;
+    });
+    std::sort(rhs->begin(), rhs->end(), [&](const ProcessStats& l, const ProcessStats& r) -> bool {
+        return l.process.pid < r.process.pid;
+    });
+    return std::equal(lhs->begin(), lhs->end(), rhs->begin(),
+                      [&](const ProcessStats& l, const ProcessStats& r) -> bool {
+                          if (l.tgid != r.tgid || l.uid != r.uid ||
+                              !isEqual(l.process, r.process) ||
+                              l.threads.size() != r.threads.size()) {
+                              return false;
+                          }
+                          for (const auto& lIt : l.threads) {
+                              const auto& rIt = r.threads.find(lIt.first);
+                              if (rIt == r.threads.end()) {
+                                  return false;
+                              }
+                              if (!isEqual(lIt.second, rIt->second)) {
+                                  return false;
+                              }
+                          }
+                          return true;
+                      });
+}
+
+}  // namespace
+
+TEST(ProcPidStatTest, TestValidStatFiles) {
+    std::unordered_map<uint32_t, std::vector<uint32_t>> pidToTids = {
+            {1, {1, 453}},
+            {1000, {1000, 1100}},
+    };
+
+    std::unordered_map<uint32_t, std::string> perProcessStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 220 0 0 0 0 0 0 0 2 0 0\n"},
+            {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 600 0 0 0 0 0 0 0 2 0 1000\n"},
+    };
+
+    std::unordered_map<uint32_t, std::string> perProcessStatus = {
+            {1, "Pid:\t1\nTgid:\t1\nUid:\t0\t0\t0\t0\n"},
+            {1000, "Pid:\t1000\nTgid:\t1000\nUid:\t10001234\t10001234\t10001234\t10001234\n"},
+    };
+
+    std::unordered_map<uint32_t, std::string> perThreadStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 2 0 0\n"},
+            {453, "453 (init) S 0 0 0 0 0 0 0 0 20 0 0 0 0 0 0 0 2 0 275\n"},
+            {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 250 0 0 0 0 0 0 0 2 0 1000\n"},
+            {1100, "1100 (system_server) S 1 0 0 0 0 0 0 0 350 0 0 0 0 0 0 0 2 0 1200\n"},
+    };
+
+    std::vector<ProcessStats> expected = {
+            {
+                    .tgid = 1,
+                    .uid = 0,
+                    .process = {1, "init", "S", 0, 220, 2, 0},
+                    .threads =
+                            {
+                                    {1, {1, "init", "S", 0, 200, 2, 0}},
+                                    {453, {453, "init", "S", 0, 20, 2, 275}},
+                            },
+            },
+            {
+                    .tgid = 1000,
+                    .uid = 10001234,
+                    .process = {1000, "system_server", "R", 1, 600, 2, 1000},
+                    .threads =
+                            {
+                                    {1000, {1000, "system_server", "R", 1, 250, 2, 1000}},
+                                    {1100, {1100, "system_server", "S", 1, 350, 2, 1200}},
+                            },
+            },
+    };
+
+    TemporaryDir firstSnapshot;
+    auto ret = populateProcPidDir(firstSnapshot.path, pidToTids, perProcessStat, perProcessStatus,
+                                  perThreadStat);
+    ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
+
+    ProcPidStat procPidStat(firstSnapshot.path);
+    ASSERT_TRUE(procPidStat.enabled())
+            << "Files under the path `" << firstSnapshot.path << "` are inaccessible";
+
+    auto actual = procPidStat.collect();
+    ASSERT_TRUE(actual) << "Failed to collect proc pid stat: " << actual.error();
+
+    EXPECT_TRUE(isEqual(&expected, &actual.value())) << "First snapshot doesn't match.\nExpected:\n"
+                                                     << toString(expected) << "\nActual:\n"
+                                                     << toString(*actual);
+
+    pidToTids = {
+            {1, {1, 453}}, {1000, {1000, 1400}},  // TID 1100 terminated and 1400 instantiated.
+    };
+
+    perProcessStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 920 0 0 0 0 0 0 0 2 0 0\n"},
+            {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 1550 0 0 0 0 0 0 0 2 0 1000\n"},
+    };
+
+    perThreadStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 600 0 0 0 0 0 0 0 2 0 0\n"},
+            {453, "453 (init) S 0 0 0 0 0 0 0 0 320 0 0 0 0 0 0 0 2 0 275\n"},
+            {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 600 0 0 0 0 0 0 0 2 0 1000\n"},
+            // TID 1100 hits +400 major page faults before terminating. This is counted against
+            // PID 1000's perProcessStat.
+            {1400, "1400 (system_server) S 1 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 2 0 8977476\n"},
+    };
+
+    expected = {
+            {
+                    .tgid = 1,
+                    .uid = 0,
+                    .process = {1, "init", "S", 0, 700, 2, 0},
+                    .threads =
+                            {
+                                    {1, {1, "init", "S", 0, 400, 2, 0}},
+                                    {453, {453, "init", "S", 0, 300, 2, 275}},
+                            },
+            },
+            {
+                    .tgid = 1000,
+                    .uid = 10001234,
+                    .process = {1000, "system_server", "R", 1, 950, 2, 1000},
+                    .threads =
+                            {
+                                    {1000, {1000, "system_server", "R", 1, 350, 2, 1000}},
+                                    {1400, {1400, "system_server", "S", 1, 200, 2, 8977476}},
+                            },
+            },
+    };
+
+    TemporaryDir secondSnapshot;
+    ret = populateProcPidDir(secondSnapshot.path, pidToTids, perProcessStat, perProcessStatus,
+                             perThreadStat);
+    ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
+
+    procPidStat.mPath = secondSnapshot.path;
+    ASSERT_TRUE(procPidStat.enabled())
+            << "Files under the path `" << secondSnapshot.path << "` are inaccessible";
+
+    actual = procPidStat.collect();
+    ASSERT_TRUE(actual) << "Failed to collect proc pid stat: " << actual.error();
+
+    EXPECT_TRUE(isEqual(&expected, &actual.value()))
+            << "Second snapshot doesn't match.\nExpected:\n"
+            << toString(expected) << "\nActual:\n"
+            << toString(*actual);
+}
+
+TEST(ProcPidStatTest, TestHandlesProcessTerminationBetweenScanningAndParsing) {
+    std::unordered_map<uint32_t, std::vector<uint32_t>> pidToTids = {
+            {1, {1}},
+            {100, {100}},          // Process terminates after scanning PID directory.
+            {1000, {1000}},        // Process terminates after reading stat file.
+            {2000, {2000}},        // Process terminates after scanning task directory.
+            {3000, {3000, 3300}},  // TID 3300 terminates after scanning task directory.
+    };
+
+    std::unordered_map<uint32_t, std::string> perProcessStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 220 0 0 0 0 0 0 0 1 0 0\n"},
+            // Process 100 terminated.
+            {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 600 0 0 0 0 0 0 0 1 0 1000\n"},
+            {2000, "2000 (logd) R 1 0 0 0 0 0 0 0 1200 0 0 0 0 0 0 0 1 0 4567\n"},
+            {3000, "3000 (disk I/O) R 1 0 0 0 0 0 0 0 10300 0 0 0 0 0 0 0 2 0 67890\n"},
+    };
+
+    std::unordered_map<uint32_t, std::string> perProcessStatus = {
+            {1, "Pid:\t1\nTgid:\t1\nUid:\t0\t0\t0\t0\n"},
+            // Process 1000 terminated.
+            {2000, "Pid:\t2000\nTgid:\t2000\nUid:\t10001234\t10001234\t10001234\t10001234\n"},
+            {3000, "Pid:\t3000\nTgid:\t3000\nUid:\t10001234\t10001234\t10001234\t10001234\n"},
+    };
+
+    std::unordered_map<uint32_t, std::string> perThreadStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 0\n"},
+            // Process 2000 terminated.
+            {3000, "3000 (disk I/O) R 1 0 0 0 0 0 0 0 2400 0 0 0 0 0 0 0 2 0 67890\n"},
+            // TID 3300 terminated.
+    };
+
+    std::vector<ProcessStats> expected = {
+            {
+                    .tgid = 1,
+                    .uid = 0,
+                    .process = {1, "init", "S", 0, 220, 1, 0},
+                    .threads = {{1, {1, "init", "S", 0, 200, 1, 0}}},
+            },
+            {
+                    .tgid = -1,
+                    .uid = -1,
+                    .process = {1000, "system_server", "R", 1, 600, 1, 1000},
+                    // Stats common between process and main-thread are copied when
+                    // main-thread stats are not available.
+                    .threads = {{1000, {1000, "system_server", "R", 1, 0, 1, 1000}}},
+            },
+            {
+                    .tgid = 2000,
+                    .uid = 10001234,
+                    .process = {2000, "logd", "R", 1, 1200, 1, 4567},
+                    .threads = {{2000, {2000, "logd", "R", 1, 0, 1, 4567}}},
+            },
+            {
+                    .tgid = 3000,
+                    .uid = 10001234,
+                    .process = {3000, "disk I/O", "R", 1, 10300, 2, 67890},
+                    .threads = {{3000, {3000, "disk I/O", "R", 1, 2400, 2, 67890}}},
+            },
+    };
+
+    TemporaryDir procDir;
+    const auto& ret = populateProcPidDir(procDir.path, pidToTids, perProcessStat, perProcessStatus,
+                                         perThreadStat);
+    ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
+
+    ProcPidStat procPidStat(procDir.path);
+    ASSERT_TRUE(procPidStat.enabled())
+            << "Files under the path `" << procDir.path << "` are inaccessible";
+
+    auto actual = procPidStat.collect();
+    ASSERT_TRUE(actual) << "Failed to collect proc pid stat: " << actual.error();
+
+    EXPECT_TRUE(isEqual(&expected, &actual.value()))
+            << "Proc pid contents doesn't match.\nExpected:\n"
+            << toString(expected) << "\nActual:\n"
+            << toString(*actual);
+}
+
+TEST(ProcPidStatTest, TestHandlesPidTidReuse) {
+    std::unordered_map<uint32_t, std::vector<uint32_t>> pidToTids = {
+            {1, {1, 367, 453, 589}},
+            {1000, {1000}},
+            {2345, {2345}},
+    };
+
+    std::unordered_map<uint32_t, std::string> perProcessStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 1200 0 0 0 0 0 0 0 4 0 0\n"},
+            {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 250 0 0 0 0 0 0 0 1 0 1000\n"},
+            {2345, "2345 (logd) R 1 0 0 0 0 0 0 0 54354 0 0 0 0 0 0 0 1 0 456\n"},
+    };
+
+    std::unordered_map<uint32_t, std::string> perProcessStatus = {
+            {1, "Pid:\t1\nTgid:\t1\nUid:\t0\t0\t0\t0\n"},
+            {1000, "Pid:\t1000\nTgid:\t1000\nUid:\t10001234\t10001234\t10001234\t10001234\n"},
+            {2345, "Pid:\t2345\nTgid:\t2345\nUid:\t10001234\t10001234\t10001234\t10001234\n"},
+    };
+
+    std::unordered_map<uint32_t, std::string> perThreadStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 4 0 0\n"},
+            {367, "367 (init) S 0 0 0 0 0 0 0 0 400 0 0 0 0 0 0 0 4 0 100\n"},
+            {453, "453 (init) S 0 0 0 0 0 0 0 0 100 0 0 0 0 0 0 0 4 0 275\n"},
+            {589, "589 (init) S 0 0 0 0 0 0 0 0 500 0 0 0 0 0 0 0 4 0 600\n"},
+            {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 250 0 0 0 0 0 0 0 1 0 1000\n"},
+            {2345, "2345 (logd) R 1 0 0 0 0 0 0 0 54354 0 0 0 0 0 0 0 1 0 456\n"},
+    };
+
+    std::vector<ProcessStats> expected = {
+            {
+                    .tgid = 1,
+                    .uid = 0,
+                    .process = {1, "init", "S", 0, 1200, 4, 0},
+                    .threads =
+                            {
+                                    {1, {1, "init", "S", 0, 200, 4, 0}},
+                                    {367, {367, "init", "S", 0, 400, 4, 100}},
+                                    {453, {453, "init", "S", 0, 100, 4, 275}},
+                                    {589, {589, "init", "S", 0, 500, 4, 600}},
+                            },
+            },
+            {
+                    .tgid = 1000,
+                    .uid = 10001234,
+                    .process = {1000, "system_server", "R", 1, 250, 1, 1000},
+                    .threads = {{1000, {1000, "system_server", "R", 1, 250, 1, 1000}}},
+            },
+            {
+                    .tgid = 2345,
+                    .uid = 10001234,
+                    .process = {2345, "logd", "R", 1, 54354, 1, 456},
+                    .threads = {{2345, {2345, "logd", "R", 1, 54354, 1, 456}}},
+            },
+    };
+
+    TemporaryDir firstSnapshot;
+    auto ret = populateProcPidDir(firstSnapshot.path, pidToTids, perProcessStat, perProcessStatus,
+                                  perThreadStat);
+    ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
+
+    ProcPidStat procPidStat(firstSnapshot.path);
+    ASSERT_TRUE(procPidStat.enabled())
+            << "Files under the path `" << firstSnapshot.path << "` are inaccessible";
+
+    auto actual = procPidStat.collect();
+    ASSERT_TRUE(actual) << "Failed to collect proc pid stat: " << actual.error();
+
+    EXPECT_TRUE(isEqual(&expected, &actual.value())) << "First snapshot doesn't match.\nExpected:\n"
+                                                     << toString(expected) << "\nActual:\n"
+                                                     << toString(*actual);
+
+    pidToTids = {
+            {1, {1, 589}},       // TID 589 reused by the same process.
+            {367, {367, 2000}},  // TID 367 reused as a PID. PID 2000 reused as a TID.
+            // PID 1000 reused as a new PID. TID 453 reused by a different PID.
+            {1000, {1000, 453}},
+    };
+
+    perProcessStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 1800 0 0 0 0 0 0 0 2 0 0\n"},
+            {367, "367 (system_server) R 1 0 0 0 0 0 0 0 100 0 0 0 0 0 0 0 2 0 3450\n"},
+            {1000, "1000 (logd) R 1 0 0 0 0 0 0 0 2000 0 0 0 0 0 0 0 2 0 4650\n"},
+    };
+
+    perProcessStatus = {
+            {1, "Pid:\t1\nTgid:\t1\nUid:\t0\t0\t0\t0\n"},
+            {367, "Pid:\t367\nTgid:\t367\nUid:\t10001234\t10001234\t10001234\t10001234\n"},
+            {1000, "Pid:\t1000\nTgid:\t1000\nUid:\t10001234\t10001234\t10001234\t10001234\n"},
+    };
+
+    perThreadStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 500 0 0 0 0 0 0 0 2 0 0\n"},
+            {589, "589 (init) S 0 0 0 0 0 0 0 0 300 0 0 0 0 0 0 0 2 0 2345\n"},
+            {367, "367 (system_server) R 1 0 0 0 0 0 0 0 50 0 0 0 0 0 0 0 2 0 3450\n"},
+            {2000, "2000 (system_server) R 1 0 0 0 0 0 0 0 50 0 0 0 0 0 0 0 2 0 3670\n"},
+            {1000, "1000 (logd) R 1 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 2 0 4650\n"},
+            {453, "453 (logd) D 1 0 0 0 0 0 0 0 1800 0 0 0 0 0 0 0 2 0 4770\n"},
+    };
+
+    expected = {
+            {
+                    .tgid = 1,
+                    .uid = 0,
+                    .process = {1, "init", "S", 0, 600, 2, 0},
+                    .threads =
+                            {
+                                    {1, {1, "init", "S", 0, 300, 2, 0}},
+                                    {589, {589, "init", "S", 0, 300, 2, 2345}},
+                            },
+            },
+            {
+                    .tgid = 367,
+                    .uid = 10001234,
+                    .process = {367, "system_server", "R", 1, 100, 2, 3450},
+                    .threads =
+                            {
+                                    {367, {367, "system_server", "R", 1, 50, 2, 3450}},
+                                    {2000, {2000, "system_server", "R", 1, 50, 2, 3670}},
+                            },
+            },
+            {
+                    .tgid = 1000,
+                    .uid = 10001234,
+                    .process = {1000, "logd", "R", 1, 2000, 2, 4650},
+                    .threads =
+                            {
+                                    {1000, {1000, "logd", "R", 1, 200, 2, 4650}},
+                                    {453, {453, "logd", "D", 1, 1800, 2, 4770}},
+                            },
+            },
+    };
+
+    TemporaryDir secondSnapshot;
+    ret = populateProcPidDir(secondSnapshot.path, pidToTids, perProcessStat, perProcessStatus,
+                             perThreadStat);
+    ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
+
+    procPidStat.mPath = secondSnapshot.path;
+    ASSERT_TRUE(procPidStat.enabled())
+            << "Files under the path `" << secondSnapshot.path << "` are inaccessible";
+
+    actual = procPidStat.collect();
+    ASSERT_TRUE(actual) << "Failed to collect proc pid stat: " << actual.error();
+
+    EXPECT_TRUE(isEqual(&expected, &actual.value()))
+            << "Second snapshot doesn't match.\nExpected:\n"
+            << toString(expected) << "\nActual:\n"
+            << toString(*actual);
+}
+
+TEST(ProcPidStatTest, TestErrorOnCorruptedProcessStatFile) {
+    std::unordered_map<uint32_t, std::vector<uint32_t>> pidToTids = {
+            {1, {1}},
+    };
+
+    std::unordered_map<uint32_t, std::string> perProcessStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 CORRUPTED DATA\n"},
+    };
+
+    std::unordered_map<uint32_t, std::string> perProcessStatus = {
+            {1, "Pid:\t1\nTgid:\t1\nUid:\t0\t0\t0\t0\n"},
+    };
+
+    std::unordered_map<uint32_t, std::string> perThreadStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 0\n"},
+    };
+
+    TemporaryDir procDir;
+    const auto& ret = populateProcPidDir(procDir.path, pidToTids, perProcessStat, perProcessStatus,
+                                         perThreadStat);
+    ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
+
+    ProcPidStat procPidStat(procDir.path);
+    ASSERT_TRUE(procPidStat.enabled())
+            << "Files under the path `" << procDir.path << "` are inaccessible";
+
+    const auto& actual = procPidStat.collect();
+    ASSERT_FALSE(actual) << "No error returned for invalid process stat file";
+}
+
+TEST(ProcPidStatTest, TestErrorOnCorruptedProcessStatusFile) {
+    std::unordered_map<uint32_t, std::vector<uint32_t>> pidToTids = {
+            {1, {1}},
+    };
+
+    std::unordered_map<uint32_t, std::string> perProcessStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 0\n"},
+    };
+
+    std::unordered_map<uint32_t, std::string> perProcessStatus = {
+            {1, "Pid:\t1\nTgid:\t1\nCORRUPTED DATA\n"},
+    };
+
+    std::unordered_map<uint32_t, std::string> perThreadStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 0\n"},
+    };
+
+    TemporaryDir procDir;
+    const auto& ret = populateProcPidDir(procDir.path, pidToTids, perProcessStat, perProcessStatus,
+                                         perThreadStat);
+    ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
+
+    ProcPidStat procPidStat(procDir.path);
+    ASSERT_TRUE(procPidStat.enabled())
+            << "Files under the path `" << procDir.path << "` are inaccessible";
+
+    const auto& actual = procPidStat.collect();
+    ASSERT_FALSE(actual) << "No error returned for invalid process status file";
+}
+
+TEST(ProcPidStatTest, TestErrorOnCorruptedThreadStatFile) {
+    std::unordered_map<uint32_t, std::vector<uint32_t>> pidToTids = {
+            {1, {1}},
+    };
+
+    std::unordered_map<uint32_t, std::string> perProcessStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 0\n"},
+    };
+
+    std::unordered_map<uint32_t, std::string> perProcessStatus = {
+            {1, "Pid:\t1\nTgid:\t1\nUid:\t0\t0\t0\t0\n"},
+    };
+
+    std::unordered_map<uint32_t, std::string> perThreadStat = {
+            {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 CORRUPTED DATA\n"},
+    };
+
+    TemporaryDir procDir;
+    const auto& ret = populateProcPidDir(procDir.path, pidToTids, perProcessStat, perProcessStatus,
+                                         perThreadStat);
+    ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
+
+    ProcPidStat procPidStat(procDir.path);
+    ASSERT_TRUE(procPidStat.enabled())
+            << "Files under the path `" << procDir.path << "` are inaccessible";
+
+    const auto& actual = procPidStat.collect();
+    ASSERT_FALSE(actual) << "No error returned for invalid thread stat file";
+}
+
+TEST(ProcPidStatTest, TestHandlesSpaceInCommName) {
+    std::unordered_map<uint32_t, std::vector<uint32_t>> pidToTids = {
+            {1, {1}},
+    };
+
+    std::unordered_map<uint32_t, std::string> perProcessStat = {
+            {1, "1 (random process name with space) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 0\n"},
+    };
+
+    std::unordered_map<uint32_t, std::string> perProcessStatus = {
+            {1, "Pid:\t1\nTgid:\t1\nUid:\t0\t0\t0\t0\n"},
+    };
+
+    std::unordered_map<uint32_t, std::string> perThreadStat = {
+            {1, "1 (random process name with space) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 0\n"},
+    };
+
+    std::vector<ProcessStats> expected = {
+            {
+                    .tgid = 1,
+                    .uid = 0,
+                    .process = {1, "random process name with space", "S", 0, 200, 1, 0},
+                    .threads = {{1, {1, "random process name with space", "S", 0, 200, 1, 0}}},
+            },
+    };
+
+    TemporaryDir procDir;
+    const auto& ret = populateProcPidDir(procDir.path, pidToTids, perProcessStat, perProcessStatus,
+                                         perThreadStat);
+    ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
+
+    ProcPidStat procPidStat(procDir.path);
+    ASSERT_TRUE(procPidStat.enabled())
+            << "Files under the path `" << procDir.path << "` are inaccessible";
+
+    auto actual = procPidStat.collect();
+    ASSERT_TRUE(actual) << "Failed to collect proc pid stat: " << actual.error();
+
+    EXPECT_TRUE(isEqual(&expected, &actual.value()))
+            << "Proc pid contents doesn't match.\nExpected:\n"
+            << toString(expected) << "\nActual:\n"
+            << toString(*actual);
+}
+
+TEST(ProcPidStatTest, TestProcPidStatContentsFromDevice) {
+    // TODO(b/148486340): Enable the test after appropriate SELinux privileges are available to
+    // read the proc file.
+    /*ProcPidStat procPidStat;
+    ASSERT_TRUE(procPidStat.enabled()) << "/proc/[pid]/.* files are inaccessible";
+
+    const auto& processStats = procPidStat.collect();
+    ASSERT_TRUE(processStats) << "Failed to collect proc pid stat: " << processStats.error();
+
+    // The below check should pass because there should be at least one process.
+    EXPECT_GT(processStats->size(), 0);*/
+}
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/watchdog/server/tests/ProcStatTest.cpp b/watchdog/server/tests/ProcStatTest.cpp
new file mode 100644
index 0000000..ad37e66
--- /dev/null
+++ b/watchdog/server/tests/ProcStatTest.cpp
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ProcStat.h"
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <inttypes.h>
+
+#include <string>
+
+#include "gmock/gmock.h"
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using android::base::StringPrintf;
+using android::base::WriteStringToFile;
+
+namespace {
+
+std::string toString(const ProcStatInfo& info) {
+    const auto& cpuStats = info.cpuStats;
+    return StringPrintf("Cpu Stats:\nUserTime: %" PRIu64 " NiceTime: %" PRIu64 " SysTime: %" PRIu64
+                        " IdleTime: %" PRIu64 " IoWaitTime: %" PRIu64 " IrqTime: %" PRIu64
+                        " SoftIrqTime: %" PRIu64 " StealTime: %" PRIu64 " GuestTime: %" PRIu64
+                        " GuestNiceTime: %" PRIu64 "\nNumber of running processes: %" PRIu32
+                        "\nNumber of blocked processes: %" PRIu32,
+                        cpuStats.userTime, cpuStats.niceTime, cpuStats.sysTime, cpuStats.idleTime,
+                        cpuStats.ioWaitTime, cpuStats.irqTime, cpuStats.softIrqTime,
+                        cpuStats.stealTime, cpuStats.guestTime, cpuStats.guestNiceTime,
+                        info.runnableProcessesCnt, info.ioBlockedProcessesCnt);
+}
+
+}  // namespace
+
+TEST(ProcStatTest, TestValidStatFile) {
+    constexpr char firstSnapshot[] =
+            "cpu  6200 5700 1700 3100 1100 5200 3900 0 0 0\n"
+            "cpu0 2400 2900 600 690 340 4300 2100 0 0 0\n"
+            "cpu1 1900 2380 510 760 51 370 1500 0 0 0\n"
+            "cpu2 900 400 400 1000 600 400 160 0 0 0\n"
+            "cpu3 1000 20 190 650 109 130 140 0 0 0\n"
+            "intr 694351583 0 0 0 297062868 0 5922464 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "
+            "0 0\n"
+            // Skipped most of the intr line as it is not important for testing the ProcStat parsing
+            // logic.
+            "ctxt 579020168\n"
+            "btime 1579718450\n"
+            "processes 113804\n"
+            "procs_running 17\n"
+            "procs_blocked 5\n"
+            "softirq 33275060 934664 11958403 5111 516325 200333 0 341482 10651335 0 8667407\n";
+    ProcStatInfo expectedFirstDelta;
+    expectedFirstDelta.cpuStats = {
+            .userTime = 6200,
+            .niceTime = 5700,
+            .sysTime = 1700,
+            .idleTime = 3100,
+            .ioWaitTime = 1100,
+            .irqTime = 5200,
+            .softIrqTime = 3900,
+            .stealTime = 0,
+            .guestTime = 0,
+            .guestNiceTime = 0,
+    };
+    expectedFirstDelta.runnableProcessesCnt = 17;
+    expectedFirstDelta.ioBlockedProcessesCnt = 5;
+
+    TemporaryFile tf;
+    ASSERT_NE(tf.fd, -1);
+    ASSERT_TRUE(WriteStringToFile(firstSnapshot, tf.path));
+
+    ProcStat procStat(tf.path);
+    ASSERT_TRUE(procStat.enabled()) << "Temporary file is inaccessible";
+
+    const auto& actualFirstDelta = procStat.collect();
+    EXPECT_RESULT_OK(actualFirstDelta);
+    EXPECT_EQ(expectedFirstDelta, *actualFirstDelta)
+            << "First snapshot doesnt't match.\nExpected:\n"
+            << toString(expectedFirstDelta) << "\nActual:\n"
+            << toString(*actualFirstDelta);
+
+    constexpr char secondSnapshot[] =
+            "cpu  16200 8700 2000 4100 2200 6200 5900 0 0 0\n"
+            "cpu0 4400 3400 700 890 800 4500 3100 0 0 0\n"
+            "cpu1 5900 3380 610 960 100 670 2000 0 0 0\n"
+            "cpu2 2900 1000 450 1400 800 600 460 0 0 0\n"
+            "cpu3 3000 920 240 850 500 430 340 0 0 0\n"
+            "intr 694351583 0 0 0 297062868 0 5922464 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "
+            "0 0\n"
+            "ctxt 579020168\n"
+            "btime 1579718450\n"
+            "processes 113804\n"
+            "procs_running 10\n"
+            "procs_blocked 2\n"
+            "softirq 33275060 934664 11958403 5111 516325 200333 0 341482 10651335 0 8667407\n";
+    ProcStatInfo expectedSecondDelta;
+    expectedSecondDelta.cpuStats = {
+            .userTime = 10000,
+            .niceTime = 3000,
+            .sysTime = 300,
+            .idleTime = 1000,
+            .ioWaitTime = 1100,
+            .irqTime = 1000,
+            .softIrqTime = 2000,
+            .stealTime = 0,
+            .guestTime = 0,
+            .guestNiceTime = 0,
+    };
+    expectedSecondDelta.runnableProcessesCnt = 10;
+    expectedSecondDelta.ioBlockedProcessesCnt = 2;
+
+    ASSERT_TRUE(WriteStringToFile(secondSnapshot, tf.path));
+    const auto& actualSecondDelta = procStat.collect();
+    EXPECT_RESULT_OK(actualSecondDelta);
+    EXPECT_EQ(expectedSecondDelta, *actualSecondDelta)
+            << "Second snapshot doesnt't match.\nExpected:\n"
+            << toString(expectedSecondDelta) << "\nActual:\n"
+            << toString(*actualSecondDelta);
+}
+
+TEST(ProcStatTest, TestErrorOnCorruptedStatFile) {
+    constexpr char contents[] =
+            "cpu  6200 5700 1700 3100 CORRUPTED DATA\n"
+            "cpu0 2400 2900 600 690 340 4300 2100 0 0 0\n"
+            "cpu1 1900 2380 510 760 51 370 1500 0 0 0\n"
+            "cpu2 900 400 400 1000 600 400 160 0 0 0\n"
+            "cpu3 1000 20 190 650 109 130 140 0 0 0\n"
+            "intr 694351583 0 0 0 297062868 0 5922464 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "
+            "0 0\n"
+            "ctxt 579020168\n"
+            "btime 1579718450\n"
+            "processes 113804\n"
+            "procs_running 17\n"
+            "procs_blocked 5\n"
+            "softirq 33275060 934664 11958403 5111 516325 200333 0 341482 10651335 0 8667407\n";
+    TemporaryFile tf;
+    ASSERT_NE(tf.fd, -1);
+    ASSERT_TRUE(WriteStringToFile(contents, tf.path));
+
+    ProcStat procStat(tf.path);
+    ASSERT_TRUE(procStat.enabled()) << "Temporary file is inaccessible";
+    EXPECT_FALSE(procStat.collect().ok()) << "No error returned for corrupted file";
+}
+
+TEST(ProcStatTest, TestErrorOnMissingCpuLine) {
+    constexpr char contents[] =
+            "cpu0 2400 2900 600 690 340 4300 2100 0 0 0\n"
+            "cpu1 1900 2380 510 760 51 370 1500 0 0 0\n"
+            "cpu2 900 400 400 1000 600 400 160 0 0 0\n"
+            "cpu3 1000 20 190 650 109 130 140 0 0 0\n"
+            "intr 694351583 0 0 0 297062868 0 5922464 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "
+            "0 0\n"
+            "ctxt 579020168\n"
+            "btime 1579718450\n"
+            "processes 113804\n"
+            "procs_running 17\n"
+            "procs_blocked 5\n"
+            "softirq 33275060 934664 11958403 5111 516325 200333 0 341482 10651335 0 8667407\n";
+    TemporaryFile tf;
+    ASSERT_NE(tf.fd, -1);
+    ASSERT_TRUE(WriteStringToFile(contents, tf.path));
+
+    ProcStat procStat(tf.path);
+    ASSERT_TRUE(procStat.enabled()) << "Temporary file is inaccessible";
+    EXPECT_FALSE(procStat.collect().ok()) << "No error returned due to missing cpu line";
+}
+
+TEST(ProcStatTest, TestErrorOnMissingProcsRunningLine) {
+    constexpr char contents[] =
+            "cpu  16200 8700 2000 4100 1250 6200 5900 0 0 0\n"
+            "cpu0 2400 2900 600 690 340 4300 2100 0 0 0\n"
+            "cpu1 1900 2380 510 760 51 370 1500 0 0 0\n"
+            "cpu2 900 400 400 1000 600 400 160 0 0 0\n"
+            "cpu3 1000 20 190 650 109 130 140 0 0 0\n"
+            "intr 694351583 0 0 0 297062868 0 5922464 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "
+            "0 0\n"
+            "ctxt 579020168\n"
+            "btime 1579718450\n"
+            "processes 113804\n"
+            "procs_blocked 5\n"
+            "softirq 33275060 934664 11958403 5111 516325 200333 0 341482 10651335 0 8667407\n";
+    TemporaryFile tf;
+    ASSERT_NE(tf.fd, -1);
+    ASSERT_TRUE(WriteStringToFile(contents, tf.path));
+
+    ProcStat procStat(tf.path);
+    ASSERT_TRUE(procStat.enabled()) << "Temporary file is inaccessible";
+    EXPECT_FALSE(procStat.collect().ok()) << "No error returned due to missing procs_running line";
+}
+
+TEST(ProcStatTest, TestErrorOnMissingProcsBlockedLine) {
+    constexpr char contents[] =
+            "cpu  16200 8700 2000 4100 1250 6200 5900 0 0 0\n"
+            "cpu0 2400 2900 600 690 340 4300 2100 0 0 0\n"
+            "cpu1 1900 2380 510 760 51 370 1500 0 0 0\n"
+            "cpu2 900 400 400 1000 600 400 160 0 0 0\n"
+            "cpu3 1000 20 190 650 109 130 140 0 0 0\n"
+            "intr 694351583 0 0 0 297062868 0 5922464 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "
+            "0 0\n"
+            "ctxt 579020168\n"
+            "btime 1579718450\n"
+            "processes 113804\n"
+            "procs_running 17\n"
+            "softirq 33275060 934664 11958403 5111 516325 200333 0 341482 10651335 0 8667407\n";
+    TemporaryFile tf;
+    ASSERT_NE(tf.fd, -1);
+    ASSERT_TRUE(WriteStringToFile(contents, tf.path));
+
+    ProcStat procStat(tf.path);
+    ASSERT_TRUE(procStat.enabled()) << "Temporary file is inaccessible";
+    EXPECT_FALSE(procStat.collect().ok()) << "No error returned due to missing procs_blocked line";
+}
+
+TEST(ProcStatTest, TestErrorOnUnknownProcsLine) {
+    constexpr char contents[] =
+            "cpu  16200 8700 2000 4100 1250 6200 5900 0 0 0\n"
+            "cpu0 2400 2900 600 690 340 4300 2100 0 0 0\n"
+            "cpu1 1900 2380 510 760 51 370 1500 0 0 0\n"
+            "cpu2 900 400 400 1000 600 400 160 0 0 0\n"
+            "cpu3 1000 20 190 650 109 130 140 0 0 0\n"
+            "intr 694351583 0 0 0 297062868 0 5922464 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "
+            "0 0\n"
+            "ctxt 579020168\n"
+            "btime 1579718450\n"
+            "processes 113804\n"
+            "procs_running 17\n"
+            "procs_blocked 5\n"
+            "procs_sleeping 15\n"
+            "softirq 33275060 934664 11958403 5111 516325 200333 0 341482 10651335 0 8667407\n";
+    TemporaryFile tf;
+    ASSERT_NE(tf.fd, -1);
+    ASSERT_TRUE(WriteStringToFile(contents, tf.path));
+
+    ProcStat procStat(tf.path);
+    ASSERT_TRUE(procStat.enabled()) << "Temporary file is inaccessible";
+    EXPECT_FALSE(procStat.collect().ok()) << "No error returned due to unknown procs line";
+}
+
+TEST(ProcStatTest, TestProcStatContentsFromDevice) {
+    ProcStat procStat;
+    ASSERT_TRUE(procStat.enabled()) << kProcStatPath << " file is inaccessible";
+
+    const auto& info = procStat.collect();
+    ASSERT_RESULT_OK(info);
+
+    // The below checks should pass because the /proc/stats file should have the CPU time spent
+    // since bootup and there should be at least one running process.
+    EXPECT_GT(info->totalCpuTime(), 0);
+    EXPECT_GT(info->totalProcessesCnt(), 0);
+}
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/watchdog/server/tests/UidIoStatsTest.cpp b/watchdog/server/tests/UidIoStatsTest.cpp
new file mode 100644
index 0000000..f4f0dd9
--- /dev/null
+++ b/watchdog/server/tests/UidIoStatsTest.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "UidIoStats.h"
+
+#include <android-base/file.h>
+
+#include <unordered_map>
+
+#include "gmock/gmock.h"
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using ::android::base::WriteStringToFile;
+
+TEST(UidIoStatsTest, TestValidStatFile) {
+    // Format: uid fgRdChar fgWrChar fgRdBytes fgWrBytes bgRdChar bgWrChar bgRdBytes bgWrBytes
+    // fgFsync bgFsync
+    constexpr char firstSnapshot[] =
+        "1001234 5000 1000 3000 500 0 0 0 0 20 0\n"
+        "1005678 500 100 30 50 300 400 100 200 45 60\n"
+        "1009 0 0 0 0 40000 50000 20000 30000 0 300\n"
+        "1001000 4000 3000 2000 1000 400 300 200 100 50 10\n";
+    std::unordered_map<uint32_t, UidIoUsage> expectedFirstUsage = {
+        {1001234,
+         {.uid = 1001234,
+          .ios = {/*fgRdBytes=*/3000, /*bgRdBytes=*/0, /*fgWrBytes=*/500,
+                  /*bgWrBytes=*/0, /*fgFsync=*/20, /*bgFsync=*/0}}},
+        {1005678, {.uid = 1005678, .ios = {30, 100, 50, 200, 45, 60}}},
+        {1009, {.uid = 1009, .ios = {0, 20000, 0, 30000, 0, 300}}},
+        {1001000, {.uid = 1001000, .ios = {2000, 200, 1000, 100, 50, 10}}},
+    };
+    TemporaryFile tf;
+    ASSERT_NE(tf.fd, -1);
+    ASSERT_TRUE(WriteStringToFile(firstSnapshot, tf.path));
+
+    UidIoStats uidIoStats(tf.path);
+    ASSERT_TRUE(uidIoStats.enabled()) << "Temporary file is inaccessible";
+
+    const auto& actualFirstUsage = uidIoStats.collect();
+    EXPECT_TRUE(actualFirstUsage) << actualFirstUsage.error();
+    EXPECT_EQ(expectedFirstUsage.size(), actualFirstUsage->size());
+    for (const auto& it : expectedFirstUsage) {
+        if (actualFirstUsage->find(it.first) == actualFirstUsage->end()) {
+            ADD_FAILURE() << "Expected uid " << it.first << " not found in the first snapshot";
+        }
+        const UidIoUsage& expected = it.second;
+        const UidIoUsage& actual = actualFirstUsage->at(it.first);
+        EXPECT_EQ(expected.uid, actual.uid);
+        EXPECT_EQ(expected.ios, actual.ios)
+            << "Unexpected I/O usage for uid " << it.first << " in first snapshot.\nExpected:\n"
+            << expected.ios.toString() << "\nActual:\n"<< actual.ios.toString();
+    }
+
+    constexpr char secondSnapshot[] =
+        "1001234 10000 2000 7000 950 0 0 0 0 45 0\n"
+        "1005678 600 100 40 50 1000 1000 1000 600 50 70\n"
+        "1003456 300 500 200 300 0 0 0 0 50 0\n"
+        "1001000 400 300 200 100 40 30 20 10 5 1\n";
+    std::unordered_map<uint32_t, UidIoUsage> expectedSecondUsage = {
+        {1001234,
+         {.uid = 1001234,
+          .ios = {/*fgRdBytes=*/4000, /*bgRdBytes=*/0,
+                  /*fgWrBytes=*/450, /*bgWrBytes=*/0, /*fgFsync=*/25,
+                  /*bgFsync=*/0}}},
+        {1005678, {.uid = 1005678, .ios = {10, 900, 0, 400, 5, 10}}},
+        {1003456, {.uid = 1003456, .ios = {200, 0, 300, 0, 50, 0}}},
+        {1001000, {.uid = 1001000, .ios = {0, 0, 0, 0, 0, 0}}},
+    };
+    ASSERT_TRUE(WriteStringToFile(secondSnapshot, tf.path));
+    const auto& actualSecondUsage = uidIoStats.collect();
+    EXPECT_TRUE(actualSecondUsage) << actualSecondUsage.error();
+    EXPECT_EQ(expectedSecondUsage.size(), actualSecondUsage->size());
+    for (const auto& it : expectedSecondUsage) {
+        if (actualSecondUsage->find(it.first) == actualSecondUsage->end()) {
+            ADD_FAILURE() << "Expected uid " << it.first << " not found in the second snapshot";
+        }
+        const UidIoUsage& expected = it.second;
+        const UidIoUsage& actual = actualSecondUsage->at(it.first);
+        EXPECT_EQ(expected.uid, actual.uid);
+        EXPECT_EQ(expected.ios, actual.ios)
+            << "Unexpected I/O usage for uid " << it.first << " in second snapshot:.\nExpected:\n"
+            << expected.ios.toString() << "\nActual:\n"<< actual.ios.toString();
+    }
+}
+
+TEST(UidIoStatsTest, TestErrorOnInvalidStatFile) {
+    // Format: uid fgRdChar fgWrChar fgRdBytes fgWrBytes bgRdChar bgWrChar bgRdBytes bgWrBytes
+    // fgFsync bgFsync
+    constexpr char contents[] =
+        "1001234 5000 1000 3000 500 0 0 0 0 20 0\n"
+        "1005678 500 100 30 50 300 400 100 200 45 60\n"
+        "1009012 0 0 0 0 40000 50000 20000 30000 0 300\n"
+        "1001000 4000 3000 2000 1000 CORRUPTED DATA\n";
+    TemporaryFile tf;
+    ASSERT_NE(tf.fd, -1);
+    ASSERT_TRUE(WriteStringToFile(contents, tf.path));
+
+    UidIoStats uidIoStats(tf.path);
+    ASSERT_TRUE(uidIoStats.enabled()) << "Temporary file is inaccessible";
+    EXPECT_FALSE(uidIoStats.collect()) << "No error returned for invalid file";
+}
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/watchdog/server/tests/WatchdogBinderMediatorTest.cpp b/watchdog/server/tests/WatchdogBinderMediatorTest.cpp
new file mode 100644
index 0000000..0d1cf05
--- /dev/null
+++ b/watchdog/server/tests/WatchdogBinderMediatorTest.cpp
@@ -0,0 +1,369 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "WatchdogBinderMediator.h"
+
+#include <android/automotive/watchdog/BootPhase.h>
+#include <android/automotive/watchdog/PowerCycle.h>
+#include <android/automotive/watchdog/UserState.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <errno.h>
+#include <gtest/gtest.h>
+#include <private/android_filesystem_config.h>
+#include <utils/RefBase.h>
+
+#include "gmock/gmock.h"
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using android::sp;
+using android::base::Result;
+using binder::Status;
+using ::testing::_;
+using ::testing::Return;
+
+namespace {
+
+class MockWatchdogProcessService : public WatchdogProcessService {
+public:
+    MockWatchdogProcessService() : WatchdogProcessService(nullptr) {}
+    MOCK_METHOD(Result<void>, dump, (int fd, const Vector<String16>& args), (override));
+
+    MOCK_METHOD(Status, registerClient,
+                (const sp<ICarWatchdogClient>& client, TimeoutLength timeout), (override));
+    MOCK_METHOD(Status, unregisterClient, (const sp<ICarWatchdogClient>& client), (override));
+    MOCK_METHOD(Status, registerMediator, (const sp<ICarWatchdogClient>& mediator), (override));
+    MOCK_METHOD(Status, unregisterMediator, (const sp<ICarWatchdogClient>& mediator), (override));
+    MOCK_METHOD(Status, registerMonitor, (const sp<ICarWatchdogMonitor>& monitor), (override));
+    MOCK_METHOD(Status, unregisterMonitor, (const sp<ICarWatchdogMonitor>& monitor), (override));
+    MOCK_METHOD(Status, tellClientAlive, (const sp<ICarWatchdogClient>& client, int32_t sessionId),
+                (override));
+    MOCK_METHOD(Status, tellMediatorAlive,
+                (const sp<ICarWatchdogClient>& mediator,
+                 const std::vector<int32_t>& clientsNotResponding, int32_t sessionId),
+                (override));
+    MOCK_METHOD(Status, tellDumpFinished,
+                (const android::sp<ICarWatchdogMonitor>& monitor, int32_t pid), (override));
+    MOCK_METHOD(Status, notifyPowerCycleChange, (PowerCycle cycle), (override));
+    MOCK_METHOD(Status, notifyUserStateChange, (userid_t userId, UserState state), (override));
+    MOCK_METHOD(void, binderDied, (const android::wp<IBinder>& who), (override));
+};
+
+class MockIoPerfCollection : public IoPerfCollection {
+public:
+    MockIoPerfCollection() {}
+    MOCK_METHOD(Result<void>, onBootFinished, (), (override));
+    MOCK_METHOD(Result<void>, dump, (int fd, const Vector<String16>& args), (override));
+};
+
+class MockICarWatchdogClient : public ICarWatchdogClient {
+public:
+    MOCK_METHOD(Status, checkIfAlive, (int32_t sessionId, TimeoutLength timeout), (override));
+    MOCK_METHOD(Status, prepareProcessTermination, (), (override));
+    MOCK_METHOD(IBinder*, onAsBinder, (), (override));
+    MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
+    MOCK_METHOD(std::string, getInterfaceHash, (), (override));
+};
+
+class MockICarWatchdogMonitor : public ICarWatchdogMonitor {
+public:
+    MOCK_METHOD(Status, onClientsNotResponding, (const std::vector<int32_t>& pids), (override));
+    MOCK_METHOD(IBinder*, onAsBinder, (), (override));
+    MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
+    MOCK_METHOD(std::string, getInterfaceHash, (), (override));
+};
+
+class ScopedChangeCallingUid : public RefBase {
+public:
+    explicit ScopedChangeCallingUid(uid_t uid) {
+        mCallingUid = IPCThreadState::self()->getCallingUid();
+        mCallingPid = IPCThreadState::self()->getCallingPid();
+        if (mCallingUid == uid) {
+            return;
+        }
+        mChangedUid = uid;
+        int64_t token = ((int64_t)mChangedUid << 32) | mCallingPid;
+        IPCThreadState::self()->restoreCallingIdentity(token);
+    }
+    ~ScopedChangeCallingUid() {
+        if (mCallingUid == mChangedUid) {
+            return;
+        }
+        int64_t token = ((int64_t)mCallingUid << 32) | mCallingPid;
+        IPCThreadState::self()->restoreCallingIdentity(token);
+    }
+
+private:
+    uid_t mCallingUid;
+    uid_t mChangedUid;
+    pid_t mCallingPid;
+};
+
+}  // namespace
+
+class WatchdogBinderMediatorTest : public ::testing::Test {
+protected:
+    virtual void SetUp() {
+        mMockWatchdogProcessService = new MockWatchdogProcessService();
+        mMockIoPerfCollection = new MockIoPerfCollection();
+        mWatchdogBinderMediator = new WatchdogBinderMediator();
+        mWatchdogBinderMediator->init(mMockWatchdogProcessService, mMockIoPerfCollection);
+    }
+    virtual void TearDown() {
+        mWatchdogBinderMediator->terminate();
+        ASSERT_TRUE(mWatchdogBinderMediator->mWatchdogProcessService == nullptr);
+        ASSERT_TRUE(mWatchdogBinderMediator->mIoPerfCollection == nullptr);
+        mMockWatchdogProcessService = nullptr;
+        mMockIoPerfCollection = nullptr;
+        mWatchdogBinderMediator = nullptr;
+        mScopedChangeCallingUid = nullptr;
+    }
+    // Sets calling UID to imitate System's process.
+    void setSystemCallingUid() { mScopedChangeCallingUid = new ScopedChangeCallingUid(AID_SYSTEM); }
+    sp<MockWatchdogProcessService> mMockWatchdogProcessService;
+    sp<MockIoPerfCollection> mMockIoPerfCollection;
+    sp<WatchdogBinderMediator> mWatchdogBinderMediator;
+    sp<ScopedChangeCallingUid> mScopedChangeCallingUid;
+};
+
+TEST_F(WatchdogBinderMediatorTest, TestErrorOnNullptrDuringInit) {
+    sp<WatchdogBinderMediator> mediator = new WatchdogBinderMediator();
+    ASSERT_FALSE(mediator->init(nullptr, new MockIoPerfCollection()).ok())
+            << "No error returned on nullptr watchdog process service";
+    ASSERT_FALSE(mediator->init(new MockWatchdogProcessService(), nullptr).ok())
+            << "No error returned on nullptr I/O perf collection";
+    ASSERT_FALSE(mediator->init(nullptr, nullptr).ok()) << "No error returned on nullptr";
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestHandlesEmptyDumpArgs) {
+    EXPECT_CALL(*mMockWatchdogProcessService, dump(-1, _)).WillOnce(Return(Result<void>()));
+    EXPECT_CALL(*mMockIoPerfCollection, dump(-1, _)).WillOnce(Return(Result<void>()));
+    mWatchdogBinderMediator->dump(-1, Vector<String16>());
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestHandlesStartCustomIoPerfCollection) {
+    EXPECT_CALL(*mMockIoPerfCollection, dump(-1, _)).WillOnce(Return(Result<void>()));
+
+    Vector<String16> args;
+    args.push_back(String16(kStartCustomCollectionFlag));
+    ASSERT_EQ(mWatchdogBinderMediator->dump(-1, args), OK);
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestHandlesStopCustomIoPerfCollection) {
+    EXPECT_CALL(*mMockIoPerfCollection, dump(-1, _)).WillOnce(Return(Result<void>()));
+
+    Vector<String16> args;
+    args.push_back(String16(kEndCustomCollectionFlag));
+    ASSERT_EQ(mWatchdogBinderMediator->dump(-1, args), OK);
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestErrorOnInvalidDumpArgs) {
+    Vector<String16> args;
+    args.push_back(String16("--invalid_option"));
+    ASSERT_NE(mWatchdogBinderMediator->dump(-1, args), OK) << "No error on invalid args";
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestRegisterClient) {
+    sp<ICarWatchdogClient> client = new MockICarWatchdogClient();
+    TimeoutLength timeout = TimeoutLength::TIMEOUT_MODERATE;
+    EXPECT_CALL(*mMockWatchdogProcessService, registerClient(client, timeout))
+            .WillOnce(Return(Status::ok()));
+    Status status = mWatchdogBinderMediator->registerClient(client, timeout);
+    ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestUnregisterClient) {
+    sp<ICarWatchdogClient> client = new MockICarWatchdogClient();
+    EXPECT_CALL(*mMockWatchdogProcessService, unregisterClient(client))
+            .WillOnce(Return(Status::ok()));
+    Status status = mWatchdogBinderMediator->unregisterClient(client);
+    ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestRegisterMediator) {
+    setSystemCallingUid();
+    sp<ICarWatchdogClient> mediator = new MockICarWatchdogClient();
+    EXPECT_CALL(*mMockWatchdogProcessService, registerMediator(mediator))
+            .WillOnce(Return(Status::ok()));
+    Status status = mWatchdogBinderMediator->registerMediator(mediator);
+    ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestErrorOnRegisterMediatorWithNonSystemCallingUid) {
+    sp<ICarWatchdogClient> mediator = new MockICarWatchdogClient();
+    EXPECT_CALL(*mMockWatchdogProcessService, registerMediator(mediator)).Times(0);
+    Status status = mWatchdogBinderMediator->registerMediator(mediator);
+    ASSERT_FALSE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestUnregisterMediator) {
+    setSystemCallingUid();
+    sp<ICarWatchdogClient> mediator = new MockICarWatchdogClient();
+    EXPECT_CALL(*mMockWatchdogProcessService, unregisterMediator(mediator))
+            .WillOnce(Return(Status::ok()));
+    Status status = mWatchdogBinderMediator->unregisterMediator(mediator);
+    ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestErrorOnUnegisterMediatorWithNonSystemCallingUid) {
+    sp<ICarWatchdogClient> mediator = new MockICarWatchdogClient();
+    EXPECT_CALL(*mMockWatchdogProcessService, unregisterMediator(mediator)).Times(0);
+    Status status = mWatchdogBinderMediator->unregisterMediator(mediator);
+    ASSERT_FALSE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestRegisterMonitor) {
+    setSystemCallingUid();
+    sp<ICarWatchdogMonitor> monitor = new MockICarWatchdogMonitor();
+    EXPECT_CALL(*mMockWatchdogProcessService, registerMonitor(monitor))
+            .WillOnce(Return(Status::ok()));
+    Status status = mWatchdogBinderMediator->registerMonitor(monitor);
+    ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestErrorOnRegisterMonitorWithNonSystemCallingUid) {
+    sp<ICarWatchdogMonitor> monitor = new MockICarWatchdogMonitor();
+    EXPECT_CALL(*mMockWatchdogProcessService, registerMonitor(monitor)).Times(0);
+    Status status = mWatchdogBinderMediator->registerMonitor(monitor);
+    ASSERT_FALSE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestUnregisterMonitor) {
+    setSystemCallingUid();
+    sp<ICarWatchdogMonitor> monitor = new MockICarWatchdogMonitor();
+    EXPECT_CALL(*mMockWatchdogProcessService, unregisterMonitor(monitor))
+            .WillOnce(Return(Status::ok()));
+    Status status = mWatchdogBinderMediator->unregisterMonitor(monitor);
+    ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestErrorOnUnregisterMonitorWithNonSystemCallingUid) {
+    sp<ICarWatchdogMonitor> monitor = new MockICarWatchdogMonitor();
+    EXPECT_CALL(*mMockWatchdogProcessService, unregisterMonitor(monitor)).Times(0);
+    Status status = mWatchdogBinderMediator->unregisterMonitor(monitor);
+    ASSERT_FALSE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestTellClientAlive) {
+    sp<ICarWatchdogClient> client = new MockICarWatchdogClient();
+    EXPECT_CALL(*mMockWatchdogProcessService, tellClientAlive(client, 456))
+            .WillOnce(Return(Status::ok()));
+    Status status = mWatchdogBinderMediator->tellClientAlive(client, 456);
+    ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestTellMediatorAlive) {
+    sp<ICarWatchdogClient> mediator = new MockICarWatchdogClient();
+    std::vector clientsNotResponding = {123};
+    EXPECT_CALL(*mMockWatchdogProcessService,
+                tellMediatorAlive(mediator, clientsNotResponding, 456))
+            .WillOnce(Return(Status::ok()));
+    Status status = mWatchdogBinderMediator->tellMediatorAlive(mediator, clientsNotResponding, 456);
+    ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestTellDumpFinished) {
+    sp<ICarWatchdogMonitor> monitor = new MockICarWatchdogMonitor();
+    EXPECT_CALL(*mMockWatchdogProcessService, tellDumpFinished(monitor, 456))
+            .WillOnce(Return(Status::ok()));
+    Status status = mWatchdogBinderMediator->tellDumpFinished(monitor, 456);
+    ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestErrorOnNotifyStateChangeWithNonSystemCallingUid) {
+    StateType type = StateType::POWER_CYCLE;
+    EXPECT_CALL(*mMockWatchdogProcessService, notifyPowerCycleChange(_)).Times(0);
+    Status status =
+            mWatchdogBinderMediator
+                    ->notifySystemStateChange(type,
+                                              static_cast<int32_t>(PowerCycle::POWER_CYCLE_SUSPEND),
+                                              -1);
+    ASSERT_FALSE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestNotifyPowerCycleChange) {
+    setSystemCallingUid();
+    StateType type = StateType::POWER_CYCLE;
+    EXPECT_CALL(*mMockWatchdogProcessService,
+                notifyPowerCycleChange(PowerCycle::POWER_CYCLE_SUSPEND))
+            .WillOnce(Return(Status::ok()));
+    Status status =
+            mWatchdogBinderMediator
+                    ->notifySystemStateChange(type,
+                                              static_cast<int32_t>(PowerCycle::POWER_CYCLE_SUSPEND),
+                                              -1);
+    ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestErrorOnNotifyPowerCycleChangeWithInvalidArgs) {
+    EXPECT_CALL(*mMockWatchdogProcessService, notifyPowerCycleChange(_)).Times(0);
+    StateType type = StateType::POWER_CYCLE;
+
+    Status status = mWatchdogBinderMediator->notifySystemStateChange(type, -1, -1);
+    ASSERT_FALSE(status.isOk()) << status;
+
+    status = mWatchdogBinderMediator->notifySystemStateChange(type, 3000, -1);
+    ASSERT_FALSE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestNotifyUserStateChange) {
+    setSystemCallingUid();
+    StateType type = StateType::USER_STATE;
+    EXPECT_CALL(*mMockWatchdogProcessService,
+                notifyUserStateChange(234567, UserState::USER_STATE_STOPPED))
+            .WillOnce(Return(Status::ok()));
+    Status status =
+            mWatchdogBinderMediator
+                    ->notifySystemStateChange(type, 234567,
+                                              static_cast<int32_t>(UserState::USER_STATE_STOPPED));
+    ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestErrorOnNotifyUserStateChangeWithInvalidArgs) {
+    EXPECT_CALL(*mMockWatchdogProcessService, notifyUserStateChange(_, _)).Times(0);
+    StateType type = StateType::USER_STATE;
+
+    Status status = mWatchdogBinderMediator->notifySystemStateChange(type, 234567, -1);
+    ASSERT_FALSE(status.isOk()) << status;
+
+    status = mWatchdogBinderMediator->notifySystemStateChange(type, 234567, 3000);
+    ASSERT_FALSE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogBinderMediatorTest, TestNotifyBootPhaseChange) {
+    setSystemCallingUid();
+    StateType type = StateType::BOOT_PHASE;
+    EXPECT_CALL(*mMockIoPerfCollection, onBootFinished()).WillOnce(Return(Result<void>()));
+    Status status = mWatchdogBinderMediator->notifySystemStateChange(
+        type, static_cast<int32_t>(BootPhase::BOOT_COMPLETED), -1);
+    ASSERT_TRUE(status.isOk()) << status;
+}
+
+
+TEST_F(WatchdogBinderMediatorTest, TestNotifyBootPhaseChangeWithNonBootCompletedPhase) {
+    setSystemCallingUid();
+    StateType type = StateType::BOOT_PHASE;
+    EXPECT_CALL(*mMockIoPerfCollection, onBootFinished()).Times(0);
+    Status status = mWatchdogBinderMediator->notifySystemStateChange(type, 0, -1);
+    ASSERT_TRUE(status.isOk()) << status;
+}
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/watchdog/server/tests/WatchdogProcessServiceTest.cpp b/watchdog/server/tests/WatchdogProcessServiceTest.cpp
new file mode 100644
index 0000000..38598ec
--- /dev/null
+++ b/watchdog/server/tests/WatchdogProcessServiceTest.cpp
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "WatchdogProcessService.h"
+
+#include "gmock/gmock.h"
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using android::sp;
+using binder::Status;
+using ::testing::_;
+using ::testing::Return;
+
+namespace {
+
+class MockBinder : public BBinder {
+public:
+    MOCK_METHOD(status_t, linkToDeath,
+                (const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags), (override));
+    MOCK_METHOD(status_t, unlinkToDeath,
+                (const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
+                 wp<DeathRecipient>* outRecipient),
+                (override));
+};
+
+class MockCarWatchdogClient : public ICarWatchdogClientDefault {
+public:
+    MockCarWatchdogClient() { mBinder = new MockBinder(); }
+    sp<MockBinder> getBinder() const { return mBinder; }
+
+    MOCK_METHOD(IBinder*, onAsBinder, (), (override));
+
+private:
+    sp<MockBinder> mBinder;
+};
+
+class MockCarWatchdogMonitor : public ICarWatchdogMonitorDefault {
+public:
+    MockCarWatchdogMonitor() { mBinder = new MockBinder(); }
+    sp<MockBinder> getBinder() const { return mBinder; }
+
+    MOCK_METHOD(IBinder*, onAsBinder, (), (override));
+
+private:
+    sp<MockBinder> mBinder;
+};
+
+}  // namespace
+
+class WatchdogProcessServiceTest : public ::testing::Test {
+protected:
+    void SetUp() override {
+        sp<Looper> looper(Looper::prepare(/*opts=*/0));
+        mWatchdogProcessService = new WatchdogProcessService(looper);
+    }
+
+    void TearDown() override { mWatchdogProcessService = nullptr; }
+
+    sp<WatchdogProcessService> mWatchdogProcessService;
+};
+
+sp<MockCarWatchdogClient> createMockCarWatchdogClient(status_t linkToDeathResult) {
+    sp<MockCarWatchdogClient> client = new MockCarWatchdogClient;
+    sp<MockBinder> binder = client->getBinder();
+    EXPECT_CALL(*binder, linkToDeath(_, nullptr, 0)).WillRepeatedly(Return(linkToDeathResult));
+    EXPECT_CALL(*binder, unlinkToDeath(_, nullptr, 0, nullptr)).WillRepeatedly(Return(OK));
+    EXPECT_CALL(*client, onAsBinder()).WillRepeatedly(Return(binder.get()));
+    return client;
+}
+
+sp<MockCarWatchdogMonitor> createMockCarWatchdogMonitor(status_t linkToDeathResult) {
+    sp<MockCarWatchdogMonitor> monitor = new MockCarWatchdogMonitor;
+    sp<MockBinder> binder = monitor->getBinder();
+    EXPECT_CALL(*binder, linkToDeath(_, nullptr, 0)).WillRepeatedly(Return(linkToDeathResult));
+    EXPECT_CALL(*binder, unlinkToDeath(_, nullptr, 0, nullptr)).WillRepeatedly(Return(OK));
+    EXPECT_CALL(*monitor, onAsBinder()).WillRepeatedly(Return(binder.get()));
+    return monitor;
+}
+
+sp<MockCarWatchdogClient> expectNormalCarWatchdogClient() {
+    return createMockCarWatchdogClient(OK);
+}
+
+sp<MockCarWatchdogClient> expectCarWatchdogClientBinderDied() {
+    return createMockCarWatchdogClient(DEAD_OBJECT);
+}
+
+sp<MockCarWatchdogMonitor> expectNormalCarWatchdogMonitor() {
+    return createMockCarWatchdogMonitor(OK);
+}
+
+sp<MockCarWatchdogMonitor> expectCarWatchdogMonitorBinderDied() {
+    return createMockCarWatchdogMonitor(DEAD_OBJECT);
+}
+
+TEST_F(WatchdogProcessServiceTest, TestRegisterClient) {
+    sp<MockCarWatchdogClient> client = expectNormalCarWatchdogClient();
+    Status status =
+            mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL);
+    ASSERT_TRUE(status.isOk()) << status;
+    status = mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL);
+    ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogProcessServiceTest, TestUnregisterClient) {
+    sp<MockCarWatchdogClient> client = expectNormalCarWatchdogClient();
+    mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL);
+    Status status = mWatchdogProcessService->unregisterClient(client);
+    ASSERT_TRUE(status.isOk()) << status;
+    ASSERT_FALSE(mWatchdogProcessService->unregisterClient(client).isOk())
+            << "Unregistering an unregistered client shoud return an error";
+}
+
+TEST_F(WatchdogProcessServiceTest, TestRegisterClient_BinderDied) {
+    sp<MockCarWatchdogClient> client = expectCarWatchdogClientBinderDied();
+    ASSERT_FALSE(
+            mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL).isOk())
+            << "When linkToDeath fails, registerClient should return an error";
+}
+
+TEST_F(WatchdogProcessServiceTest, TestRegisterMediator) {
+    sp<ICarWatchdogClient> mediator = expectNormalCarWatchdogClient();
+    Status status = mWatchdogProcessService->registerMediator(mediator);
+    ASSERT_TRUE(status.isOk()) << status;
+    status = mWatchdogProcessService->registerMediator(mediator);
+    ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogProcessServiceTest, TestRegisterMediator_BinderDied) {
+    sp<MockCarWatchdogClient> mediator = expectCarWatchdogClientBinderDied();
+    ASSERT_FALSE(mWatchdogProcessService->registerMediator(mediator).isOk())
+            << "When linkToDeath fails, registerMediator should return an error";
+}
+
+TEST_F(WatchdogProcessServiceTest, TestUnregisterMediator) {
+    sp<ICarWatchdogClient> mediator = expectNormalCarWatchdogClient();
+    mWatchdogProcessService->registerMediator(mediator);
+    Status status = mWatchdogProcessService->unregisterMediator(mediator);
+    ASSERT_TRUE(status.isOk()) << status;
+    ASSERT_FALSE(mWatchdogProcessService->unregisterMediator(mediator).isOk())
+            << "Unregistering an unregistered mediator shoud return an error";
+}
+
+TEST_F(WatchdogProcessServiceTest, TestRegisterMonitor) {
+    sp<ICarWatchdogMonitor> monitorOne = expectNormalCarWatchdogMonitor();
+    sp<ICarWatchdogMonitor> monitorTwo = expectNormalCarWatchdogMonitor();
+    Status status = mWatchdogProcessService->registerMonitor(monitorOne);
+    ASSERT_TRUE(status.isOk()) << status;
+    status = mWatchdogProcessService->registerMonitor(monitorOne);
+    ASSERT_TRUE(status.isOk()) << status;
+    status = mWatchdogProcessService->registerMonitor(monitorTwo);
+    ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogProcessServiceTest, TestRegisterMonitor_BinderDied) {
+    sp<MockCarWatchdogMonitor> monitor = expectCarWatchdogMonitorBinderDied();
+    ASSERT_FALSE(mWatchdogProcessService->registerMonitor(monitor).isOk())
+            << "When linkToDeath fails, registerMonitor should return an error";
+}
+
+TEST_F(WatchdogProcessServiceTest, TestUnregisterMonitor) {
+    sp<ICarWatchdogMonitor> monitor = expectNormalCarWatchdogMonitor();
+    mWatchdogProcessService->registerMonitor(monitor);
+    Status status = mWatchdogProcessService->unregisterMonitor(monitor);
+    ASSERT_TRUE(status.isOk()) << status;
+    ASSERT_FALSE(mWatchdogProcessService->unregisterMonitor(monitor).isOk())
+            << "Unregistering an unregistered monitor should return an error";
+}
+
+TEST_F(WatchdogProcessServiceTest, TestTellClientAlive) {
+    sp<ICarWatchdogClient> client = expectNormalCarWatchdogClient();
+    mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL);
+    ASSERT_FALSE(mWatchdogProcessService->tellClientAlive(client, 1234).isOk())
+            << "tellClientAlive not synced with checkIfAlive should return an error";
+}
+
+TEST_F(WatchdogProcessServiceTest, TestTellMediatorAlive) {
+    sp<ICarWatchdogClient> mediator = expectNormalCarWatchdogClient();
+    mWatchdogProcessService->registerMediator(mediator);
+    std::vector<int32_t> pids = {111, 222};
+    ASSERT_FALSE(mWatchdogProcessService->tellMediatorAlive(mediator, pids, 1234).isOk())
+            << "tellMediatorAlive not synced with checkIfAlive should return an error";
+}
+
+TEST_F(WatchdogProcessServiceTest, TestTellDumpFinished) {
+    sp<ICarWatchdogMonitor> monitor = expectNormalCarWatchdogMonitor();
+    ASSERT_FALSE(mWatchdogProcessService->tellDumpFinished(monitor, 1234).isOk())
+            << "Unregistered monitor cannot call tellDumpFinished";
+    mWatchdogProcessService->registerMonitor(monitor);
+    Status status = mWatchdogProcessService->tellDumpFinished(monitor, 1234);
+    ASSERT_TRUE(status.isOk()) << status;
+}
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
diff --git a/watchdog/testclient/Android.bp b/watchdog/testclient/Android.bp
new file mode 100644
index 0000000..f9e6642
--- /dev/null
+++ b/watchdog/testclient/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_binary {
+    name: "carwatchdog_testclient",
+    srcs: [
+        "src/*.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wno-missing-field-initializers",
+        "-Werror",
+        "-Wno-unused-variable",
+        "-Wunused-parameter",
+    ],
+    shared_libs: [
+        "carwatchdog_aidl_interface-ndk_platform",
+        "libbase",
+        "libbinder_ndk",
+        "liblog",
+        "libutils",
+    ],
+    vendor: true,
+}
diff --git a/watchdog/testclient/sepolicy/carwatchdog_testclient.te b/watchdog/testclient/sepolicy/carwatchdog_testclient.te
new file mode 100644
index 0000000..377bdc6
--- /dev/null
+++ b/watchdog/testclient/sepolicy/carwatchdog_testclient.te
@@ -0,0 +1,8 @@
+# Car watchdog client
+type carwatchdog_testclient, domain;
+type carwatchdog_testclient_exec, exec_type, file_type, vendor_file_type;
+
+carwatchdog_client_domain(carwatchdog_testclient)
+
+init_daemon_domain(carwatchdog_testclient)
+binder_use(carwatchdog_testclient)
diff --git a/watchdog/testclient/sepolicy/file_contexts b/watchdog/testclient/sepolicy/file_contexts
new file mode 100644
index 0000000..32c41de
--- /dev/null
+++ b/watchdog/testclient/sepolicy/file_contexts
@@ -0,0 +1,2 @@
+# Car watchdog test client
+/vendor/bin/carwatchdog_testclient  u:object_r:carwatchdog_testclient_exec:s0
diff --git a/watchdog/testclient/src/WatchdogClient.cpp b/watchdog/testclient/src/WatchdogClient.cpp
new file mode 100644
index 0000000..4c381c6
--- /dev/null
+++ b/watchdog/testclient/src/WatchdogClient.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "carwatchdog_testclient"
+
+#include "WatchdogClient.h"
+
+#include <android-base/file.h>
+#include <android/binder_manager.h>
+
+#include <unordered_map>
+
+namespace aidl {
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using ::android::Looper;
+using ::android::Message;
+using ::android::Mutex;
+using ::android::sp;
+
+namespace {
+
+enum { WHAT_CHECK_ALIVE = 1, WHAT_BECOME_INACTIVE = 2, WHAT_TERMINATE = 3 };
+
+const std::unordered_map<std::string, TimeoutLength> kTimeoutMap =
+        {{"critical", TimeoutLength::TIMEOUT_CRITICAL},
+         {"moderate", TimeoutLength::TIMEOUT_MODERATE},
+         {"normal", TimeoutLength::TIMEOUT_NORMAL}};
+
+}  // namespace
+
+WatchdogClient::WatchdogClient(const sp<Looper>& handlerLooper) : mHandlerLooper(handlerLooper) {
+    mMessageHandler = new MessageHandlerImpl(this);
+}
+
+ndk::ScopedAStatus WatchdogClient::checkIfAlive(int32_t sessionId, TimeoutLength timeout) {
+    if (mVerbose) {
+        ALOGI("Pinged by car watchdog daemon: session id = %d", sessionId);
+    }
+    Mutex::Autolock lock(mMutex);
+    mHandlerLooper->removeMessages(mMessageHandler, WHAT_CHECK_ALIVE);
+    mSession = HealthCheckSession(sessionId, timeout);
+    mHandlerLooper->sendMessage(mMessageHandler, Message(WHAT_CHECK_ALIVE));
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus WatchdogClient::prepareProcessTermination() {
+    ALOGI("This process is being terminated by car watchdog");
+    return ndk::ScopedAStatus::ok();
+}
+
+bool WatchdogClient::initialize(const CommandParam& param) {
+    ndk::SpAIBinder binder(
+            AServiceManager_getService("android.automotive.watchdog.ICarWatchdog/default"));
+    if (binder.get() == nullptr) {
+        ALOGE("Getting carwatchdog daemon failed");
+        return false;
+    }
+    std::shared_ptr<ICarWatchdog> server = ICarWatchdog::fromBinder(binder);
+    if (server == nullptr) {
+        ALOGE("Failed to connect to carwatchdog daemon");
+        return false;
+    }
+    {
+        Mutex::Autolock lock(mMutex);
+        mWatchdogServer = server;
+        mIsClientActive = true;
+    }
+    mForcedKill = param.forcedKill;
+    mVerbose = param.verbose;
+    registerClient(param.timeout);
+
+    if (param.inactiveAfterInSec >= 0) {
+        mHandlerLooper->sendMessageDelayed(seconds_to_nanoseconds(param.inactiveAfterInSec),
+                                           mMessageHandler, Message(WHAT_BECOME_INACTIVE));
+    }
+    if (param.terminateAfterInSec >= 0) {
+        mHandlerLooper->sendMessageDelayed(seconds_to_nanoseconds(param.terminateAfterInSec),
+                                           mMessageHandler, Message(WHAT_TERMINATE));
+    }
+    return true;
+}
+
+void WatchdogClient::finalize() {
+    {
+        Mutex::Autolock lock(mMutex);
+        if (!mWatchdogServer) {
+            return;
+        }
+    }
+    unregisterClient();
+}
+
+void WatchdogClient::respondToWatchdog() {
+    int sessionId;
+    std::shared_ptr<ICarWatchdog> watchdogServer;
+    std::shared_ptr<ICarWatchdogClient> testClient;
+    {
+        Mutex::Autolock lock(mMutex);
+        if (!mIsClientActive || mTestClient == nullptr || mWatchdogServer == nullptr) {
+            return;
+        }
+        watchdogServer = mWatchdogServer;
+        testClient = mTestClient;
+        sessionId = mSession.id;
+    }
+    ndk::ScopedAStatus status = watchdogServer->tellClientAlive(testClient, sessionId);
+    if (!status.isOk()) {
+        ALOGE("Failed to call binder interface: %d", status.getStatus());
+        return;
+    }
+    if (mVerbose) {
+        ALOGI("Sent response to car watchdog daemon: session id = %d", sessionId);
+    }
+}
+
+void WatchdogClient::becomeInactive() {
+    Mutex::Autolock lock(mMutex);
+    mIsClientActive = false;
+    if (mVerbose) {
+        ALOGI("Became inactive");
+    }
+}
+
+void WatchdogClient::terminateProcess() {
+    if (!mForcedKill) {
+        unregisterClient();
+    }
+    raise(SIGKILL);
+}
+
+void WatchdogClient::registerClient(const std::string& timeout) {
+    ndk::SpAIBinder binder = this->asBinder();
+    if (binder.get() == nullptr) {
+        ALOGW("Failed to get car watchdog client binder object");
+        return;
+    }
+    std::shared_ptr<ICarWatchdogClient> client = ICarWatchdogClient::fromBinder(binder);
+    if (client == nullptr) {
+        ALOGW("Failed to get ICarWatchdogClient from binder");
+        return;
+    }
+    std::shared_ptr<ICarWatchdog> watchdogServer;
+    {
+        Mutex::Autolock lock(mMutex);
+        if (mWatchdogServer == nullptr) {
+            return;
+        }
+        watchdogServer = mWatchdogServer;
+        mTestClient = client;
+    }
+    watchdogServer->registerClient(client, kTimeoutMap.at(timeout));
+    ALOGI("Successfully registered the client to car watchdog server");
+}
+
+void WatchdogClient::unregisterClient() {
+    std::shared_ptr<ICarWatchdog> watchdogServer;
+    std::shared_ptr<ICarWatchdogClient> testClient;
+    {
+        Mutex::Autolock lock(mMutex);
+        if (mWatchdogServer == nullptr || mTestClient == nullptr) {
+            return;
+        }
+        watchdogServer = mWatchdogServer;
+        testClient = mTestClient;
+        mTestClient = nullptr;
+    }
+    watchdogServer->unregisterClient(testClient);
+    ALOGI("Successfully unregistered the client from car watchdog server");
+}
+
+WatchdogClient::MessageHandlerImpl::MessageHandlerImpl(WatchdogClient* client) : mClient(client) {}
+
+void WatchdogClient::MessageHandlerImpl::handleMessage(const Message& message) {
+    switch (message.what) {
+        case WHAT_CHECK_ALIVE:
+            mClient->respondToWatchdog();
+            break;
+        case WHAT_BECOME_INACTIVE:
+            mClient->becomeInactive();
+            break;
+        case WHAT_TERMINATE:
+            mClient->terminateProcess();
+            break;
+        default:
+            ALOGW("Unknown message: %d", message.what);
+    }
+}
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
+}  // namespace aidl
diff --git a/watchdog/testclient/src/WatchdogClient.h b/watchdog/testclient/src/WatchdogClient.h
new file mode 100644
index 0000000..3174f98
--- /dev/null
+++ b/watchdog/testclient/src/WatchdogClient.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WATCHDOG_TESTCLIENT_SRC_WATCHDOGCLIENT_H_
+#define WATCHDOG_TESTCLIENT_SRC_WATCHDOGCLIENT_H_
+
+#include <aidl/android/automotive/watchdog/BnCarWatchdog.h>
+#include <aidl/android/automotive/watchdog/BnCarWatchdogClient.h>
+#include <utils/Looper.h>
+#include <utils/Mutex.h>
+#include <utils/String16.h>
+
+namespace aidl {
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+struct CommandParam {
+    std::string timeout;
+    int inactiveAfterInSec;
+    int terminateAfterInSec;
+    bool forcedKill;
+    bool verbose;
+};
+
+struct HealthCheckSession {
+    HealthCheckSession(int32_t sessionId = -1,
+                       TimeoutLength sessionTimeout = TimeoutLength::TIMEOUT_NORMAL) :
+          id(sessionId),
+          timeout(sessionTimeout) {}
+
+    int32_t id;
+    TimeoutLength timeout;
+};
+
+class WatchdogClient : public BnCarWatchdogClient {
+public:
+    explicit WatchdogClient(const ::android::sp<::android::Looper>& handlerLooper);
+
+    ndk::ScopedAStatus checkIfAlive(int32_t sessionId, TimeoutLength timeout) override;
+    ndk::ScopedAStatus prepareProcessTermination() override;
+
+    bool initialize(const CommandParam& param);
+    void finalize();
+
+private:
+    class MessageHandlerImpl : public ::android::MessageHandler {
+    public:
+        explicit MessageHandlerImpl(WatchdogClient* client);
+        void handleMessage(const ::android::Message& message) override;
+
+    private:
+        WatchdogClient* mClient;
+    };
+
+private:
+    void respondToWatchdog();
+    void becomeInactive();
+    void terminateProcess();
+    void registerClient(const std::string& timeout);
+    void unregisterClient();
+
+private:
+    ::android::sp<::android::Looper> mHandlerLooper;
+    ::android::sp<MessageHandlerImpl> mMessageHandler;
+    bool mForcedKill;
+    bool mVerbose;
+    ::android::Mutex mMutex;
+    std::shared_ptr<ICarWatchdog> mWatchdogServer GUARDED_BY(mMutex);
+    std::shared_ptr<ICarWatchdogClient> mTestClient GUARDED_BY(mMutex);
+    bool mIsClientActive GUARDED_BY(mMutex);
+    HealthCheckSession mSession GUARDED_BY(mMutex);
+};
+
+}  // namespace watchdog
+}  // namespace automotive
+}  // namespace android
+}  // namespace aidl
+
+#endif  // WATCHDOG_TESTCLIENT_SRC_WATCHDOGCLIENT_H_
diff --git a/watchdog/testclient/src/main.cpp b/watchdog/testclient/src/main.cpp
new file mode 100644
index 0000000..440069d
--- /dev/null
+++ b/watchdog/testclient/src/main.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "carwatchdog_testclient"
+
+#include "WatchdogClient.h"
+
+#include <android-base/parseint.h>
+#include <android-base/result.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <utils/Looper.h>
+
+using aidl::android::automotive::watchdog::CommandParam;
+using aidl::android::automotive::watchdog::WatchdogClient;
+using android::Looper;
+using android::sp;
+using android::base::Error;
+using android::base::ParseInt;
+using android::base::Result;
+
+Result<CommandParam> checkArgument(int argc, char** argv) {
+    CommandParam param;
+    if (argc < 4) {
+        return Error() << "Invalid syntax";
+    }
+    if (strcmp(argv[1], "critical") && strcmp(argv[1], "moderate") && strcmp(argv[1], "normal")) {
+        return Error() << "Invalid timeout";
+    }
+    param.timeout = argv[1];
+    std::string strValue = argv[2];
+    if (!ParseInt(strValue, &param.inactiveAfterInSec)) {
+        return Error() << "Invalid inactive after time";
+    }
+    strValue = argv[3];
+    if (!ParseInt(strValue, &param.terminateAfterInSec)) {
+        return Error() << "Invalid terminate after time";
+    }
+    param.forcedKill = false;
+    param.verbose = false;
+    for (int i = 4; i < argc; i++) {
+        if (!strcmp(argv[i], "--forcedkill")) {
+            param.forcedKill = true;
+        } else if (!strcmp(argv[i], "--verbose")) {
+            param.verbose = true;
+        } else {
+            return Error() << "Invalid option";
+        }
+    }
+    return param;
+}
+/**
+ * Usage: carwatchdog_testclient [timeout] [inactive_after] [terminate_after] [--forcedkill]
+ *                               [--verbose]
+ * timeout: critical|moderate|normal
+ * inactive_after: number in seconds. -1 for never being inactive.
+ * terminate_after: number in seconds. -1 for running forever.
+ * --forcedkill: terminate without unregistering from car watchdog daemon.
+ * --verbose: output verbose logs.
+ */
+int main(int argc, char** argv) {
+    sp<Looper> looper(Looper::prepare(/*opts=*/0));
+
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    std::shared_ptr<WatchdogClient> service = ndk::SharedRefBase::make<WatchdogClient>(looper);
+
+    auto param = checkArgument(argc, argv);
+    if (!param.ok()) {
+        ALOGE("%s: use \"carwatchdog_testclient timeout inactive_after terminate_after "
+              "[--forcedkill]\"",
+              param.error().message().c_str());
+        ALOGE("timeout: critical|moderate|normal");
+        ALOGE("inactive_after: number in seconds (-1 for never being inactive)");
+        ALOGE("terminate_after: number in seconds (-1 for running forever)");
+        ALOGE("--forcedkill: terminate without unregistering from car watchdog daemon");
+        ALOGE("--verbose: output verbose logs");
+        return 1;
+    }
+    if (!service->initialize(*param)) {
+        ALOGE("Failed to initialize watchdog client");
+        return 1;
+    }
+
+    while (true) {
+        looper->pollAll(/*timeoutMillis=*/-1);
+    }
+
+    return 0;
+}